]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - drivers/leds/leds-pca9633.c
leds: support new LP8501 device - another LP55xx common
[mirror_ubuntu-zesty-kernel.git] / drivers / leds / leds-pca9633.c
CommitLineData
75cb2e1d
PM
1/*
2 * Copyright 2011 bct electronic GmbH
3 *
4 * Author: Peter Meerwald <p.meerwald@bct-electronic.com>
5 *
6 * Based on leds-pca955x.c
7 *
8 * This file is subject to the terms and conditions of version 2 of
9 * the GNU General Public License. See the file COPYING in the main
10 * directory of this archive for more details.
11 *
12 * LED driver for the PCA9633 I2C LED driver (7-bit slave address 0x62)
13 *
14 */
15
16#include <linux/module.h>
17#include <linux/delay.h>
18#include <linux/string.h>
19#include <linux/ctype.h>
20#include <linux/leds.h>
21#include <linux/err.h>
22#include <linux/i2c.h>
23#include <linux/workqueue.h>
24#include <linux/slab.h>
81d22878 25#include <linux/of.h>
2f73c392 26#include <linux/platform_data/leds-pca9633.h>
75cb2e1d
PM
27
28/* LED select registers determine the source that drives LED outputs */
29#define PCA9633_LED_OFF 0x0 /* LED driver off */
30#define PCA9633_LED_ON 0x1 /* LED driver on */
31#define PCA9633_LED_PWM 0x2 /* Controlled through PWM */
32#define PCA9633_LED_GRP_PWM 0x3 /* Controlled through PWM/GRPPWM */
33
34#define PCA9633_MODE1 0x00
35#define PCA9633_MODE2 0x01
36#define PCA9633_PWM_BASE 0x02
37#define PCA9633_LEDOUT 0x08
38
39static const struct i2c_device_id pca9633_id[] = {
40 { "pca9633", 0 },
41 { }
42};
43MODULE_DEVICE_TABLE(i2c, pca9633_id);
44
45struct pca9633_led {
46 struct i2c_client *client;
47 struct work_struct work;
48 enum led_brightness brightness;
49 struct led_classdev led_cdev;
50 int led_num; /* 0 .. 3 potentially */
51 char name[32];
52};
53
54static void pca9633_led_work(struct work_struct *work)
55{
56 struct pca9633_led *pca9633 = container_of(work,
57 struct pca9633_led, work);
58 u8 ledout = i2c_smbus_read_byte_data(pca9633->client, PCA9633_LEDOUT);
59 int shift = 2 * pca9633->led_num;
60 u8 mask = 0x3 << shift;
61
62 switch (pca9633->brightness) {
63 case LED_FULL:
64 i2c_smbus_write_byte_data(pca9633->client, PCA9633_LEDOUT,
65 (ledout & ~mask) | (PCA9633_LED_ON << shift));
66 break;
67 case LED_OFF:
68 i2c_smbus_write_byte_data(pca9633->client, PCA9633_LEDOUT,
69 ledout & ~mask);
70 break;
71 default:
72 i2c_smbus_write_byte_data(pca9633->client,
73 PCA9633_PWM_BASE + pca9633->led_num,
74 pca9633->brightness);
75 i2c_smbus_write_byte_data(pca9633->client, PCA9633_LEDOUT,
76 (ledout & ~mask) | (PCA9633_LED_PWM << shift));
77 break;
78 }
79}
80
81static void pca9633_led_set(struct led_classdev *led_cdev,
82 enum led_brightness value)
83{
84 struct pca9633_led *pca9633;
85
86 pca9633 = container_of(led_cdev, struct pca9633_led, led_cdev);
87
88 pca9633->brightness = value;
89
90 /*
91 * Must use workqueue for the actual I/O since I2C operations
92 * can sleep.
93 */
94 schedule_work(&pca9633->work);
95}
96
81d22878
TL
97#if IS_ENABLED(CONFIG_OF)
98static struct pca9633_platform_data *
99pca9633_dt_init(struct i2c_client *client)
100{
101 struct device_node *np = client->dev.of_node, *child;
102 struct pca9633_platform_data *pdata;
103 struct led_info *pca9633_leds;
104 int count;
105
106 count = of_get_child_count(np);
107 if (!count || count > 4)
108 return ERR_PTR(-ENODEV);
109
110 pca9633_leds = devm_kzalloc(&client->dev,
111 sizeof(struct led_info) * count, GFP_KERNEL);
112 if (!pca9633_leds)
113 return ERR_PTR(-ENOMEM);
114
115 for_each_child_of_node(np, child) {
116 struct led_info led;
117 u32 reg;
118 int res;
119
120 led.name =
121 of_get_property(child, "label", NULL) ? : child->name;
122 led.default_trigger =
123 of_get_property(child, "linux,default-trigger", NULL);
124 res = of_property_read_u32(child, "reg", &reg);
125 if (res != 0)
126 continue;
127 pca9633_leds[reg] = led;
128 }
129 pdata = devm_kzalloc(&client->dev,
130 sizeof(struct pca9633_platform_data), GFP_KERNEL);
131 if (!pdata)
132 return ERR_PTR(-ENOMEM);
133
134 pdata->leds.leds = pca9633_leds;
135 pdata->leds.num_leds = count;
136
137 /* default to open-drain unless totem pole (push-pull) is specified */
138 if (of_property_read_bool(np, "nxp,totem-pole"))
139 pdata->outdrv = PCA9633_TOTEM_POLE;
140 else
141 pdata->outdrv = PCA9633_OPEN_DRAIN;
142
143 return pdata;
144}
145
146static const struct of_device_id of_pca9633_match[] = {
147 { .compatible = "nxp,pca963x", },
148 {},
149};
150#else
151static struct pca9633_platform_data *
152pca9633_dt_init(struct i2c_client *client)
153{
154 return ERR_PTR(-ENODEV);
155}
156#endif
157
98ea1ea2 158static int pca9633_probe(struct i2c_client *client,
75cb2e1d
PM
159 const struct i2c_device_id *id)
160{
161 struct pca9633_led *pca9633;
2f73c392 162 struct pca9633_platform_data *pdata;
75cb2e1d
PM
163 int i, err;
164
75cb2e1d
PM
165 pdata = client->dev.platform_data;
166
81d22878
TL
167 if (!pdata) {
168 pdata = pca9633_dt_init(client);
169 if (IS_ERR(pdata)) {
170 dev_warn(&client->dev, "could not parse configuration\n");
171 pdata = NULL;
172 }
173 }
174
75cb2e1d 175 if (pdata) {
2f73c392 176 if (pdata->leds.num_leds <= 0 || pdata->leds.num_leds > 4) {
75cb2e1d
PM
177 dev_err(&client->dev, "board info must claim at most 4 LEDs");
178 return -EINVAL;
179 }
180 }
181
983ce884 182 pca9633 = devm_kzalloc(&client->dev, 4 * sizeof(*pca9633), GFP_KERNEL);
75cb2e1d
PM
183 if (!pca9633)
184 return -ENOMEM;
185
186 i2c_set_clientdata(client, pca9633);
187
188 for (i = 0; i < 4; i++) {
189 pca9633[i].client = client;
190 pca9633[i].led_num = i;
191
192 /* Platform data can specify LED names and default triggers */
2f73c392
PM
193 if (pdata && i < pdata->leds.num_leds) {
194 if (pdata->leds.leds[i].name)
75cb2e1d
PM
195 snprintf(pca9633[i].name,
196 sizeof(pca9633[i].name), "pca9633:%s",
2f73c392
PM
197 pdata->leds.leds[i].name);
198 if (pdata->leds.leds[i].default_trigger)
75cb2e1d 199 pca9633[i].led_cdev.default_trigger =
2f73c392 200 pdata->leds.leds[i].default_trigger;
75cb2e1d
PM
201 } else {
202 snprintf(pca9633[i].name, sizeof(pca9633[i].name),
203 "pca9633:%d", i);
204 }
205
206 pca9633[i].led_cdev.name = pca9633[i].name;
207 pca9633[i].led_cdev.brightness_set = pca9633_led_set;
208
209 INIT_WORK(&pca9633[i].work, pca9633_led_work);
210
211 err = led_classdev_register(&client->dev, &pca9633[i].led_cdev);
212 if (err < 0)
213 goto exit;
214 }
215
216 /* Disable LED all-call address and set normal mode */
217 i2c_smbus_write_byte_data(client, PCA9633_MODE1, 0x00);
218
2f73c392
PM
219 /* Configure output: open-drain or totem pole (push-pull) */
220 if (pdata && pdata->outdrv == PCA9633_OPEN_DRAIN)
221 i2c_smbus_write_byte_data(client, PCA9633_MODE2, 0x01);
222
75cb2e1d
PM
223 /* Turn off LEDs */
224 i2c_smbus_write_byte_data(client, PCA9633_LEDOUT, 0x00);
225
226 return 0;
227
228exit:
229 while (i--) {
230 led_classdev_unregister(&pca9633[i].led_cdev);
231 cancel_work_sync(&pca9633[i].work);
232 }
233
75cb2e1d
PM
234 return err;
235}
236
678e8a6b 237static int pca9633_remove(struct i2c_client *client)
75cb2e1d
PM
238{
239 struct pca9633_led *pca9633 = i2c_get_clientdata(client);
240 int i;
241
242 for (i = 0; i < 4; i++) {
243 led_classdev_unregister(&pca9633[i].led_cdev);
244 cancel_work_sync(&pca9633[i].work);
245 }
246
75cb2e1d
PM
247 return 0;
248}
249
250static struct i2c_driver pca9633_driver = {
251 .driver = {
252 .name = "leds-pca9633",
253 .owner = THIS_MODULE,
81d22878 254 .of_match_table = of_match_ptr(of_pca9633_match),
75cb2e1d
PM
255 },
256 .probe = pca9633_probe,
df07cf81 257 .remove = pca9633_remove,
75cb2e1d
PM
258 .id_table = pca9633_id,
259};
260
261module_i2c_driver(pca9633_driver);
262
263MODULE_AUTHOR("Peter Meerwald <p.meerwald@bct-electronic.com>");
264MODULE_DESCRIPTION("PCA9633 LED driver");
265MODULE_LICENSE("GPL v2");