2 * Copyright 2014 Belkin Inc.
3 * Copyright 2015 Andrew Lunn <andrew@lunn.ch>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; version 2 of the License.
10 #include <linux/i2c.h>
11 #include <linux/leds.h>
12 #include <linux/module.h>
14 #include <linux/of_device.h>
15 #include <linux/regmap.h>
16 #include <linux/slab.h>
17 #include <linux/workqueue.h>
19 #define TLC591XX_MAX_LEDS 16
21 #define TLC591XX_REG_MODE1 0x00
22 #define MODE1_RESPON_ADDR_MASK 0xF0
23 #define MODE1_NORMAL_MODE (0 << 4)
24 #define MODE1_SPEED_MODE (1 << 4)
26 #define TLC591XX_REG_MODE2 0x01
27 #define MODE2_DIM (0 << 5)
28 #define MODE2_BLINK (1 << 5)
29 #define MODE2_OCH_STOP (0 << 3)
30 #define MODE2_OCH_ACK (1 << 3)
32 #define TLC591XX_REG_PWM(x) (0x02 + (x))
34 #define TLC591XX_REG_GRPPWM 0x12
35 #define TLC591XX_REG_GRPFREQ 0x13
37 /* LED Driver Output State, determine the source that drives LED outputs */
38 #define LEDOUT_OFF 0x0 /* Output LOW */
39 #define LEDOUT_ON 0x1 /* Output HI-Z */
40 #define LEDOUT_DIM 0x2 /* Dimming */
41 #define LEDOUT_BLINK 0x3 /* Blinking */
42 #define LEDOUT_MASK 0x3
44 #define ldev_to_led(c) container_of(c, struct tlc591xx_led, ldev)
45 #define work_to_led(work) container_of(work, struct tlc591xx_led, work)
50 struct led_classdev ldev
;
51 struct work_struct work
;
52 struct tlc591xx_priv
*priv
;
55 struct tlc591xx_priv
{
56 struct tlc591xx_led leds
[TLC591XX_MAX_LEDS
];
57 struct regmap
*regmap
;
58 unsigned int reg_ledout_offset
;
62 unsigned int max_leds
;
63 unsigned int reg_ledout_offset
;
66 static const struct tlc591xx tlc59116
= {
68 .reg_ledout_offset
= 0x14,
71 static const struct tlc591xx tlc59108
= {
73 .reg_ledout_offset
= 0x0c,
77 tlc591xx_set_mode(struct regmap
*regmap
, u8 mode
)
82 err
= regmap_write(regmap
, TLC591XX_REG_MODE1
, MODE1_NORMAL_MODE
);
86 val
= MODE2_OCH_STOP
| mode
;
88 return regmap_write(regmap
, TLC591XX_REG_MODE2
, val
);
92 tlc591xx_set_ledout(struct tlc591xx_priv
*priv
, struct tlc591xx_led
*led
,
95 unsigned int i
= (led
->led_no
% 4) * 2;
96 unsigned int mask
= LEDOUT_MASK
<< i
;
97 unsigned int addr
= priv
->reg_ledout_offset
+ (led
->led_no
>> 2);
101 return regmap_update_bits(priv
->regmap
, addr
, mask
, val
);
105 tlc591xx_set_pwm(struct tlc591xx_priv
*priv
, struct tlc591xx_led
*led
,
108 u8 pwm
= TLC591XX_REG_PWM(led
->led_no
);
110 return regmap_write(priv
->regmap
, pwm
, brightness
);
114 tlc591xx_led_work(struct work_struct
*work
)
116 struct tlc591xx_led
*led
= work_to_led(work
);
117 struct tlc591xx_priv
*priv
= led
->priv
;
118 enum led_brightness brightness
= led
->ldev
.brightness
;
121 switch (brightness
) {
123 err
= tlc591xx_set_ledout(priv
, led
, LEDOUT_OFF
);
126 err
= tlc591xx_set_ledout(priv
, led
, LEDOUT_ON
);
129 err
= tlc591xx_set_ledout(priv
, led
, LEDOUT_DIM
);
131 err
= tlc591xx_set_pwm(priv
, led
, brightness
);
135 dev_err(led
->ldev
.dev
, "Failed setting brightness\n");
139 tlc591xx_brightness_set(struct led_classdev
*led_cdev
,
140 enum led_brightness brightness
)
142 struct tlc591xx_led
*led
= ldev_to_led(led_cdev
);
144 led
->ldev
.brightness
= brightness
;
145 schedule_work(&led
->work
);
149 tlc591xx_destroy_devices(struct tlc591xx_priv
*priv
, unsigned int j
)
154 if (priv
->leds
[i
].active
) {
155 led_classdev_unregister(&priv
->leds
[i
].ldev
);
156 cancel_work_sync(&priv
->leds
[i
].work
);
162 tlc591xx_configure(struct device
*dev
,
163 struct tlc591xx_priv
*priv
,
164 const struct tlc591xx
*tlc591xx
)
169 tlc591xx_set_mode(priv
->regmap
, MODE2_DIM
);
170 for (i
= 0; i
< TLC591XX_MAX_LEDS
; i
++) {
171 struct tlc591xx_led
*led
= &priv
->leds
[i
];
178 led
->ldev
.brightness_set
= tlc591xx_brightness_set
;
179 led
->ldev
.max_brightness
= LED_FULL
;
180 INIT_WORK(&led
->work
, tlc591xx_led_work
);
181 err
= led_classdev_register(dev
, &led
->ldev
);
183 dev_err(dev
, "couldn't register LED %s\n",
192 tlc591xx_destroy_devices(priv
, i
);
196 static const struct regmap_config tlc591xx_regmap
= {
199 .max_register
= 0x1e,
202 static const struct of_device_id of_tlc591xx_leds_match
[] = {
203 { .compatible
= "ti,tlc59116",
205 { .compatible
= "ti,tlc59108",
209 MODULE_DEVICE_TABLE(of
, of_tlc591xx_leds_match
);
212 tlc591xx_probe(struct i2c_client
*client
,
213 const struct i2c_device_id
*id
)
215 struct device_node
*np
= client
->dev
.of_node
, *child
;
216 struct device
*dev
= &client
->dev
;
217 const struct of_device_id
*match
;
218 const struct tlc591xx
*tlc591xx
;
219 struct tlc591xx_priv
*priv
;
222 match
= of_match_device(of_tlc591xx_leds_match
, dev
);
226 tlc591xx
= match
->data
;
230 count
= of_get_child_count(np
);
231 if (!count
|| count
> tlc591xx
->max_leds
)
234 if (!i2c_check_functionality(client
->adapter
,
235 I2C_FUNC_SMBUS_BYTE_DATA
))
238 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
242 priv
->regmap
= devm_regmap_init_i2c(client
, &tlc591xx_regmap
);
243 if (IS_ERR(priv
->regmap
)) {
244 err
= PTR_ERR(priv
->regmap
);
245 dev_err(dev
, "Failed to allocate register map: %d\n", err
);
248 priv
->reg_ledout_offset
= tlc591xx
->reg_ledout_offset
;
250 i2c_set_clientdata(client
, priv
);
252 for_each_child_of_node(np
, child
) {
253 err
= of_property_read_u32(child
, "reg", ®
);
256 if (reg
< 0 || reg
>= tlc591xx
->max_leds
)
258 if (priv
->leds
[reg
].active
)
260 priv
->leds
[reg
].active
= true;
261 priv
->leds
[reg
].ldev
.name
=
262 of_get_property(child
, "label", NULL
) ? : child
->name
;
263 priv
->leds
[reg
].ldev
.default_trigger
=
264 of_get_property(child
, "linux,default-trigger", NULL
);
266 return tlc591xx_configure(dev
, priv
, tlc591xx
);
270 tlc591xx_remove(struct i2c_client
*client
)
272 struct tlc591xx_priv
*priv
= i2c_get_clientdata(client
);
274 tlc591xx_destroy_devices(priv
, TLC591XX_MAX_LEDS
);
279 static const struct i2c_device_id tlc591xx_id
[] = {
284 MODULE_DEVICE_TABLE(i2c
, tlc591xx_id
);
286 static struct i2c_driver tlc591xx_driver
= {
289 .of_match_table
= of_match_ptr(of_tlc591xx_leds_match
),
291 .probe
= tlc591xx_probe
,
292 .remove
= tlc591xx_remove
,
293 .id_table
= tlc591xx_id
,
296 module_i2c_driver(tlc591xx_driver
);
298 MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>");
299 MODULE_LICENSE("GPL");
300 MODULE_DESCRIPTION("TLC591XX LED driver");