leds: Add driver for the ISSI IS31FL32xx family of LED controllers
[deliverable/linux.git] / drivers / leds / leds-is31fl32xx.c
CommitLineData
9d7cffaf
DR
1/*
2 * Driver for ISSI IS31FL32xx family of I2C LED controllers
3 *
4 * Copyright 2015 Allworx Corp.
5 *
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * Datasheets: http://www.issi.com/US/product-analog-fxled-driver.shtml
12 */
13
14#include <linux/device.h>
15#include <linux/i2c.h>
16#include <linux/kernel.h>
17#include <linux/leds.h>
18#include <linux/module.h>
19#include <linux/of.h>
20#include <linux/of_device.h>
21
22/* Used to indicate a device has no such register */
23#define IS31FL32XX_REG_NONE 0xFF
24
25/* Software Shutdown bit in Shutdown Register */
26#define IS31FL32XX_SHUTDOWN_SSD_ENABLE 0
27#define IS31FL32XX_SHUTDOWN_SSD_DISABLE BIT(0)
28
29/* IS31FL3216 has a number of unique registers */
30#define IS31FL3216_CONFIG_REG 0x00
31#define IS31FL3216_LIGHTING_EFFECT_REG 0x03
32#define IS31FL3216_CHANNEL_CONFIG_REG 0x04
33
34/* Software Shutdown bit in 3216 Config Register */
35#define IS31FL3216_CONFIG_SSD_ENABLE BIT(7)
36#define IS31FL3216_CONFIG_SSD_DISABLE 0
37
38struct is31fl32xx_priv;
39struct is31fl32xx_led_data {
40 struct led_classdev cdev;
41 u8 channel; /* 1-based, max priv->cdef->channels */
42 struct is31fl32xx_priv *priv;
43};
44
45struct is31fl32xx_priv {
46 const struct is31fl32xx_chipdef *cdef;
47 struct i2c_client *client;
48 unsigned int num_leds;
49 struct is31fl32xx_led_data leds[0];
50};
51
52/**
53 * struct is31fl32xx_chipdef - chip-specific attributes
54 * @channels : Number of LED channels
55 * @shutdown_reg : address of Shutdown register (optional)
56 * @pwm_update_reg : address of PWM Update register
57 * @global_control_reg : address of Global Control register (optional)
58 * @reset_reg : address of Reset register (optional)
59 * @pwm_register_base : address of first PWM register
60 * @pwm_registers_reversed: : true if PWM registers count down instead of up
61 * @led_control_register_base : address of first LED control register (optional)
62 * @enable_bits_per_led_control_register: number of LEDs enable bits in each
63 * @reset_func: : pointer to reset function
64 *
65 * For all optional register addresses, the sentinel value %IS31FL32XX_REG_NONE
66 * indicates that this chip has no such register.
67 *
68 * If non-NULL, @reset_func will be called during probing to set all
69 * necessary registers to a known initialization state. This is needed
70 * for chips that do not have a @reset_reg.
71 *
72 * @enable_bits_per_led_control_register must be >=1 if
73 * @led_control_register_base != %IS31FL32XX_REG_NONE.
74 */
75struct is31fl32xx_chipdef {
76 u8 channels;
77 u8 shutdown_reg;
78 u8 pwm_update_reg;
79 u8 global_control_reg;
80 u8 reset_reg;
81 u8 pwm_register_base;
82 bool pwm_registers_reversed;
83 u8 led_control_register_base;
84 u8 enable_bits_per_led_control_register;
85 int (*reset_func)(struct is31fl32xx_priv *priv);
86 int (*sw_shutdown_func)(struct is31fl32xx_priv *priv, bool enable);
87};
88
89static const struct is31fl32xx_chipdef is31fl3236_cdef = {
90 .channels = 36,
91 .shutdown_reg = 0x00,
92 .pwm_update_reg = 0x25,
93 .global_control_reg = 0x4a,
94 .reset_reg = 0x4f,
95 .pwm_register_base = 0x01,
96 .led_control_register_base = 0x26,
97 .enable_bits_per_led_control_register = 1,
98};
99
100static const struct is31fl32xx_chipdef is31fl3235_cdef = {
101 .channels = 28,
102 .shutdown_reg = 0x00,
103 .pwm_update_reg = 0x25,
104 .global_control_reg = 0x4a,
105 .reset_reg = 0x4f,
106 .pwm_register_base = 0x05,
107 .led_control_register_base = 0x2a,
108 .enable_bits_per_led_control_register = 1,
109};
110
111static const struct is31fl32xx_chipdef is31fl3218_cdef = {
112 .channels = 18,
113 .shutdown_reg = 0x00,
114 .pwm_update_reg = 0x16,
115 .global_control_reg = IS31FL32XX_REG_NONE,
116 .reset_reg = 0x17,
117 .pwm_register_base = 0x01,
118 .led_control_register_base = 0x13,
119 .enable_bits_per_led_control_register = 6,
120};
121
122static int is31fl3216_reset(struct is31fl32xx_priv *priv);
123static int is31fl3216_software_shutdown(struct is31fl32xx_priv *priv,
124 bool enable);
125static const struct is31fl32xx_chipdef is31fl3216_cdef = {
126 .channels = 16,
127 .shutdown_reg = IS31FL32XX_REG_NONE,
128 .pwm_update_reg = 0xB0,
129 .global_control_reg = IS31FL32XX_REG_NONE,
130 .reset_reg = IS31FL32XX_REG_NONE,
131 .pwm_register_base = 0x10,
132 .pwm_registers_reversed = true,
133 .led_control_register_base = 0x01,
134 .enable_bits_per_led_control_register = 8,
135 .reset_func = is31fl3216_reset,
136 .sw_shutdown_func = is31fl3216_software_shutdown,
137};
138
139static int is31fl32xx_write(struct is31fl32xx_priv *priv, u8 reg, u8 val)
140{
141 int ret;
142
143 dev_dbg(&priv->client->dev, "writing register 0x%02X=0x%02X", reg, val);
144
145 ret = i2c_smbus_write_byte_data(priv->client, reg, val);
146 if (ret) {
147 dev_err(&priv->client->dev,
148 "register write to 0x%02X failed (error %d)",
149 reg, ret);
150 }
151 return ret;
152}
153
154/*
155 * Custom reset function for IS31FL3216 because it does not have a RESET
156 * register the way that the other IS31FL32xx chips do. We don't bother
157 * writing the GPIO and animation registers, because the registers we
158 * do write ensure those will have no effect.
159 */
160static int is31fl3216_reset(struct is31fl32xx_priv *priv)
161{
162 unsigned int i;
163 int ret;
164
165 ret = is31fl32xx_write(priv, IS31FL3216_CONFIG_REG,
166 IS31FL3216_CONFIG_SSD_ENABLE);
167 if (ret)
168 return ret;
169 for (i = 0; i < priv->cdef->channels; i++) {
170 ret = is31fl32xx_write(priv, priv->cdef->pwm_register_base+i,
171 0x00);
172 if (ret)
173 return ret;
174 }
175 ret = is31fl32xx_write(priv, priv->cdef->pwm_update_reg, 0);
176 if (ret)
177 return ret;
178 ret = is31fl32xx_write(priv, IS31FL3216_LIGHTING_EFFECT_REG, 0x00);
179 if (ret)
180 return ret;
181 ret = is31fl32xx_write(priv, IS31FL3216_CHANNEL_CONFIG_REG, 0x00);
182 if (ret)
183 return ret;
184
185 return 0;
186}
187
188/*
189 * Custom Software-Shutdown function for IS31FL3216 because it does not have
190 * a SHUTDOWN register the way that the other IS31FL32xx chips do.
191 * We don't bother doing a read/modify/write on the CONFIG register because
192 * we only ever use a value of '0' for the other fields in that register.
193 */
194static int is31fl3216_software_shutdown(struct is31fl32xx_priv *priv,
195 bool enable)
196{
197 u8 value = enable ? IS31FL3216_CONFIG_SSD_ENABLE :
198 IS31FL3216_CONFIG_SSD_DISABLE;
199
200 return is31fl32xx_write(priv, IS31FL3216_CONFIG_REG, value);
201}
202
203/*
204 * NOTE: A mutex is not needed in this function because:
205 * - All referenced data is read-only after probe()
206 * - The I2C core has a mutex on to protect the bus
207 * - There are no read/modify/write operations
208 * - Intervening operations between the write of the PWM register
209 * and the Update register are harmless.
210 *
211 * Example:
212 * PWM_REG_1 write 16
213 * UPDATE_REG write 0
214 * PWM_REG_2 write 128
215 * UPDATE_REG write 0
216 * vs:
217 * PWM_REG_1 write 16
218 * PWM_REG_2 write 128
219 * UPDATE_REG write 0
220 * UPDATE_REG write 0
221 * are equivalent. Poking the Update register merely applies all PWM
222 * register writes up to that point.
223 */
224static int is31fl32xx_brightness_set(struct led_classdev *led_cdev,
225 enum led_brightness brightness)
226{
227 const struct is31fl32xx_led_data *led_data =
228 container_of(led_cdev, struct is31fl32xx_led_data, cdev);
229 const struct is31fl32xx_chipdef *cdef = led_data->priv->cdef;
230 u8 pwm_register_offset;
231 int ret;
232
233 dev_dbg(led_cdev->dev, "%s: %d\n", __func__, brightness);
234
235 /* NOTE: led_data->channel is 1-based */
236 if (cdef->pwm_registers_reversed)
237 pwm_register_offset = cdef->channels - led_data->channel;
238 else
239 pwm_register_offset = led_data->channel - 1;
240
241 ret = is31fl32xx_write(led_data->priv,
242 cdef->pwm_register_base + pwm_register_offset,
243 brightness);
244 if (ret)
245 return ret;
246
247 return is31fl32xx_write(led_data->priv, cdef->pwm_update_reg, 0);
248}
249
250static int is31fl32xx_reset_regs(struct is31fl32xx_priv *priv)
251{
252 const struct is31fl32xx_chipdef *cdef = priv->cdef;
253 int ret;
254
255 if (cdef->reset_reg != IS31FL32XX_REG_NONE) {
256 ret = is31fl32xx_write(priv, cdef->reset_reg, 0);
257 if (ret)
258 return ret;
259 }
260
261 if (cdef->reset_func)
262 return cdef->reset_func(priv);
263
264 return 0;
265}
266
267static int is31fl32xx_software_shutdown(struct is31fl32xx_priv *priv,
268 bool enable)
269{
270 const struct is31fl32xx_chipdef *cdef = priv->cdef;
271 int ret;
272
273 if (cdef->shutdown_reg != IS31FL32XX_REG_NONE) {
274 u8 value = enable ? IS31FL32XX_SHUTDOWN_SSD_ENABLE :
275 IS31FL32XX_SHUTDOWN_SSD_DISABLE;
276 ret = is31fl32xx_write(priv, cdef->shutdown_reg, value);
277 if (ret)
278 return ret;
279 }
280
281 if (cdef->sw_shutdown_func)
282 return cdef->sw_shutdown_func(priv, enable);
283
284 return 0;
285}
286
287static int is31fl32xx_init_regs(struct is31fl32xx_priv *priv)
288{
289 const struct is31fl32xx_chipdef *cdef = priv->cdef;
290 int ret;
291
292 ret = is31fl32xx_reset_regs(priv);
293 if (ret)
294 return ret;
295
296 /*
297 * Set enable bit for all channels.
298 * We will control state with PWM registers alone.
299 */
300 if (cdef->led_control_register_base != IS31FL32XX_REG_NONE) {
301 u8 value =
302 GENMASK(cdef->enable_bits_per_led_control_register-1, 0);
303 u8 num_regs = cdef->channels /
304 cdef->enable_bits_per_led_control_register;
305 int i;
306
307 for (i = 0; i < num_regs; i++) {
308 ret = is31fl32xx_write(priv,
309 cdef->led_control_register_base+i,
310 value);
311 if (ret)
312 return ret;
313 }
314 }
315
316 ret = is31fl32xx_software_shutdown(priv, false);
317 if (ret)
318 return ret;
319
320 if (cdef->global_control_reg != IS31FL32XX_REG_NONE) {
321 ret = is31fl32xx_write(priv, cdef->global_control_reg, 0x00);
322 if (ret)
323 return ret;
324 }
325
326 return 0;
327}
328
329static inline size_t sizeof_is31fl32xx_priv(int num_leds)
330{
331 return sizeof(struct is31fl32xx_priv) +
332 (sizeof(struct is31fl32xx_led_data) * num_leds);
333}
334
335static int is31fl32xx_parse_child_dt(const struct device *dev,
336 const struct device_node *child,
337 struct is31fl32xx_led_data *led_data)
338{
339 struct led_classdev *cdev = &led_data->cdev;
340 int ret = 0;
341 u32 reg;
342
343 if (of_property_read_string(child, "label", &cdev->name))
344 cdev->name = child->name;
345
346 ret = of_property_read_u32(child, "reg", &reg);
347 if (ret || reg < 1 || reg > led_data->priv->cdef->channels) {
348 dev_err(dev,
349 "Child node %s does not have a valid reg property\n",
350 child->full_name);
351 return -EINVAL;
352 }
353 led_data->channel = reg;
354
355 of_property_read_string(child, "linux,default-trigger",
356 &cdev->default_trigger);
357
358 cdev->brightness_set_blocking = is31fl32xx_brightness_set;
359
360 return 0;
361}
362
363static struct is31fl32xx_led_data *is31fl32xx_find_led_data(
364 struct is31fl32xx_priv *priv,
365 u8 channel)
366{
367 size_t i;
368
369 for (i = 0; i < priv->num_leds; i++) {
370 if (priv->leds[i].channel == channel)
371 return &priv->leds[i];
372 }
373
374 return NULL;
375}
376
377static int is31fl32xx_parse_dt(struct device *dev,
378 struct is31fl32xx_priv *priv)
379{
380 struct device_node *child;
381 int ret = 0;
382
383 for_each_child_of_node(dev->of_node, child) {
384 struct is31fl32xx_led_data *led_data =
385 &priv->leds[priv->num_leds];
386 const struct is31fl32xx_led_data *other_led_data;
387
388 led_data->priv = priv;
389
390 ret = is31fl32xx_parse_child_dt(dev, child, led_data);
391 if (ret)
392 goto err;
393
394 /* Detect if channel is already in use by another child */
395 other_led_data = is31fl32xx_find_led_data(priv,
396 led_data->channel);
397 if (other_led_data) {
398 dev_err(dev,
399 "%s and %s both attempting to use channel %d\n",
400 led_data->cdev.name,
401 other_led_data->cdev.name,
402 led_data->channel);
403 goto err;
404 }
405
406 ret = devm_led_classdev_register(dev, &led_data->cdev);
407 if (ret) {
408 dev_err(dev, "failed to register PWM led for %s: %d\n",
409 led_data->cdev.name, ret);
410 goto err;
411 }
412
413 priv->num_leds++;
414 }
415
416 return 0;
417
418err:
419 of_node_put(child);
420 return ret;
421}
422
423static const struct of_device_id of_is31fl31xx_match[] = {
424 { .compatible = "issi,is31fl3236", .data = &is31fl3236_cdef, },
425 { .compatible = "issi,is31fl3235", .data = &is31fl3235_cdef, },
426 { .compatible = "issi,is31fl3218", .data = &is31fl3218_cdef, },
427 { .compatible = "issi,is31fl3216", .data = &is31fl3216_cdef, },
428 {},
429};
430
431MODULE_DEVICE_TABLE(of, of_is31fl31xx_match);
432
433static int is31fl32xx_probe(struct i2c_client *client,
434 const struct i2c_device_id *id)
435{
436 const struct is31fl32xx_chipdef *cdef;
437 const struct of_device_id *of_dev_id;
438 struct device *dev = &client->dev;
439 struct is31fl32xx_priv *priv;
440 int count;
441 int ret = 0;
442
443 of_dev_id = of_match_device(of_is31fl31xx_match, dev);
444 if (!of_dev_id)
445 return -EINVAL;
446
447 cdef = of_dev_id->data;
448
449 count = of_get_child_count(dev->of_node);
450 if (!count)
451 return -EINVAL;
452
453 priv = devm_kzalloc(dev, sizeof_is31fl32xx_priv(count),
454 GFP_KERNEL);
455 if (!priv)
456 return -ENOMEM;
457
458 priv->client = client;
459 priv->cdef = cdef;
460 i2c_set_clientdata(client, priv);
461
462 ret = is31fl32xx_init_regs(priv);
463 if (ret)
464 return ret;
465
466 ret = is31fl32xx_parse_dt(dev, priv);
467 if (ret)
468 return ret;
469
470 return 0;
471}
472
473static int is31fl32xx_remove(struct i2c_client *client)
474{
475 struct is31fl32xx_priv *priv = i2c_get_clientdata(client);
476
477 return is31fl32xx_reset_regs(priv);
478}
479
480/*
481 * i2c-core requires that id_table be non-NULL, even though
482 * it is not used for DeviceTree based instantiation.
483 */
484static const struct i2c_device_id is31fl31xx_id[] = {
485 {},
486};
487
488MODULE_DEVICE_TABLE(i2c, is31fl31xx_id);
489
490static struct i2c_driver is31fl32xx_driver = {
491 .driver = {
492 .name = "is31fl32xx",
493 .of_match_table = of_is31fl31xx_match,
494 },
495 .probe = is31fl32xx_probe,
496 .remove = is31fl32xx_remove,
497 .id_table = is31fl31xx_id,
498};
499
500module_i2c_driver(is31fl32xx_driver);
501
502MODULE_AUTHOR("David Rivshin <drivshin@allworx.com>");
503MODULE_DESCRIPTION("ISSI IS31FL32xx LED driver");
504MODULE_LICENSE("GPL v2");
This page took 0.055945 seconds and 5 git commands to generate.