diff options
author | Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com> | 2013-08-14 17:23:47 -0400 |
---|---|---|
committer | Bryan Wu <cooloney@gmail.com> | 2013-08-26 20:22:14 -0400 |
commit | af67384f011e81ea86aef8aec51e62e775432ea8 (patch) | |
tree | 13272f7651922ed504162fd281e1c094b411c4ff | |
parent | daa124b1fe992f27f96d89cde5923bb929e28c1c (diff) |
leds-pca9633: Add support for PCA9634
Add support for PCA9634 chip, which belongs to the same family as the
9633 but with support for 8 outputs instead of 4.
Signed-off-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com>
Signed-off-by: Bryan Wu <cooloney@gmail.com>
-rw-r--r-- | Documentation/devicetree/bindings/leds/pca9633.txt | 11 | ||||
-rw-r--r-- | drivers/leds/Kconfig | 7 | ||||
-rw-r--r-- | drivers/leds/leds-pca9633.c | 108 |
3 files changed, 85 insertions, 41 deletions
diff --git a/Documentation/devicetree/bindings/leds/pca9633.txt b/Documentation/devicetree/bindings/leds/pca9633.txt index 6d9e1a9e7e9f..aece3eac1b63 100644 --- a/Documentation/devicetree/bindings/leds/pca9633.txt +++ b/Documentation/devicetree/bindings/leds/pca9633.txt | |||
@@ -1,24 +1,25 @@ | |||
1 | LEDs connected to pca9633 or pca9632 | 1 | LEDs connected to pca9632, pca9633 or pca9634 |
2 | 2 | ||
3 | Required properties: | 3 | Required properties: |
4 | - compatible : should be : "nxp,pca963x" | 4 | - compatible : should be : "nxp,pca9632", "nxp,pca9633" or "nxp,pca9634" |
5 | 5 | ||
6 | Optional properties: | 6 | Optional properties: |
7 | - nxp,totem-pole : use totem pole (push-pull) instead of default open-drain | 7 | - nxp,totem-pole : use totem pole (push-pull) instead of default open-drain |
8 | - nxp,hw-blink : use hardware blinking instead of software blinking | 8 | - nxp,hw-blink : use hardware blinking instead of software blinking |
9 | 9 | ||
10 | Each led is represented as a sub-node of the nxp,pca9633 device. | 10 | Each led is represented as a sub-node of the nxp,pca963x device. |
11 | 11 | ||
12 | LED sub-node properties: | 12 | LED sub-node properties: |
13 | - label : (optional) see Documentation/devicetree/bindings/leds/common.txt | 13 | - label : (optional) see Documentation/devicetree/bindings/leds/common.txt |
14 | - reg : number of LED line (could be from 0 to 4) | 14 | - reg : number of LED line (could be from 0 to 3 in pca9632 or pca9633 |
15 | or 0 to 7 in pca9634) | ||
15 | - linux,default-trigger : (optional) | 16 | - linux,default-trigger : (optional) |
16 | see Documentation/devicetree/bindings/leds/common.txt | 17 | see Documentation/devicetree/bindings/leds/common.txt |
17 | 18 | ||
18 | Examples: | 19 | Examples: |
19 | 20 | ||
20 | pca9632: pca9632 { | 21 | pca9632: pca9632 { |
21 | compatible = "nxp,pca9632", "nxp,pca963x"; | 22 | compatible = "nxp,pca9632"; |
22 | #address-cells = <1>; | 23 | #address-cells = <1>; |
23 | #size-cells = <0>; | 24 | #size-cells = <0>; |
24 | reg = <0x62>; | 25 | reg = <0x62>; |
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index f2c738d02872..e7977aa3ee59 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig | |||
@@ -292,12 +292,13 @@ config LEDS_PCA955X | |||
292 | devices include PCA9550, PCA9551, PCA9552, and PCA9553. | 292 | devices include PCA9550, PCA9551, PCA9552, and PCA9553. |
293 | 293 | ||
294 | config LEDS_PCA9633 | 294 | config LEDS_PCA9633 |
295 | tristate "LED support for PCA9633 I2C chip" | 295 | tristate "LED support for PCA963x I2C chip" |
296 | depends on LEDS_CLASS | 296 | depends on LEDS_CLASS |
297 | depends on I2C | 297 | depends on I2C |
298 | help | 298 | help |
299 | This option enables support for LEDs connected to the PCA9633 | 299 | This option enables support for LEDs connected to the PCA963x |
300 | LED driver chip accessed via the I2C bus. | 300 | LED driver chip accessed via the I2C bus. Supported |
301 | devices include PCA9633 and PCA9634 | ||
301 | 302 | ||
302 | config LEDS_WM831X_STATUS | 303 | config LEDS_WM831X_STATUS |
303 | tristate "LED support for status LEDs on WM831x PMICs" | 304 | tristate "LED support for status LEDs on WM831x PMICs" |
diff --git a/drivers/leds/leds-pca9633.c b/drivers/leds/leds-pca9633.c index ecd1449b1eb6..e59ca0a1d189 100644 --- a/drivers/leds/leds-pca9633.c +++ b/drivers/leds/leds-pca9633.c | |||
@@ -1,7 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright 2011 bct electronic GmbH | 2 | * Copyright 2011 bct electronic GmbH |
3 | * Copyright 2013 Qtechnology/AS | ||
3 | * | 4 | * |
4 | * Author: Peter Meerwald <p.meerwald@bct-electronic.com> | 5 | * Author: Peter Meerwald <p.meerwald@bct-electronic.com> |
6 | * Author: Ricardo Ribalda <ricardo.ribalda@gmail.com> | ||
5 | * | 7 | * |
6 | * Based on leds-pca955x.c | 8 | * Based on leds-pca955x.c |
7 | * | 9 | * |
@@ -10,6 +12,7 @@ | |||
10 | * directory of this archive for more details. | 12 | * directory of this archive for more details. |
11 | * | 13 | * |
12 | * LED driver for the PCA9633 I2C LED driver (7-bit slave address 0x62) | 14 | * LED driver for the PCA9633 I2C LED driver (7-bit slave address 0x62) |
15 | * LED driver for the PCA9634 I2C LED driver (7-bit slave address set by hw.) | ||
13 | * | 16 | * |
14 | * Note that hardware blinking violates the leds infrastructure driver | 17 | * Note that hardware blinking violates the leds infrastructure driver |
15 | * interface since the hardware only supports blinking all LEDs with the | 18 | * interface since the hardware only supports blinking all LEDs with the |
@@ -45,16 +48,42 @@ | |||
45 | #define PCA9633_MODE1 0x00 | 48 | #define PCA9633_MODE1 0x00 |
46 | #define PCA9633_MODE2 0x01 | 49 | #define PCA9633_MODE2 0x01 |
47 | #define PCA9633_PWM_BASE 0x02 | 50 | #define PCA9633_PWM_BASE 0x02 |
48 | #define PCA9633_GRPPWM 0x06 | 51 | |
49 | #define PCA9633_GRPFREQ 0x07 | 52 | enum pca9633_type { |
50 | #define PCA9633_LEDOUT 0x08 | 53 | pca9633, |
54 | pca9634, | ||
55 | }; | ||
56 | |||
57 | struct pca9633_chipdef { | ||
58 | u8 grppwm; | ||
59 | u8 grpfreq; | ||
60 | u8 ledout_base; | ||
61 | int n_leds; | ||
62 | }; | ||
63 | |||
64 | static struct pca9633_chipdef pca9633_chipdefs[] = { | ||
65 | [pca9633] = { | ||
66 | .grppwm = 0x6, | ||
67 | .grpfreq = 0x7, | ||
68 | .ledout_base = 0x8, | ||
69 | .n_leds = 4, | ||
70 | }, | ||
71 | [pca9634] = { | ||
72 | .grppwm = 0xa, | ||
73 | .grpfreq = 0xb, | ||
74 | .ledout_base = 0xc, | ||
75 | .n_leds = 8, | ||
76 | }, | ||
77 | }; | ||
51 | 78 | ||
52 | /* Total blink period in milliseconds */ | 79 | /* Total blink period in milliseconds */ |
53 | #define PCA9632_BLINK_PERIOD_MIN 42 | 80 | #define PCA9632_BLINK_PERIOD_MIN 42 |
54 | #define PCA9632_BLINK_PERIOD_MAX 10667 | 81 | #define PCA9632_BLINK_PERIOD_MAX 10667 |
55 | 82 | ||
56 | static const struct i2c_device_id pca9633_id[] = { | 83 | static const struct i2c_device_id pca9633_id[] = { |
57 | { "pca9633", 0 }, | 84 | { "pca9632", pca9633 }, |
85 | { "pca9633", pca9633 }, | ||
86 | { "pca9634", pca9634 }, | ||
58 | { } | 87 | { } |
59 | }; | 88 | }; |
60 | MODULE_DEVICE_TABLE(i2c, pca9633_id); | 89 | MODULE_DEVICE_TABLE(i2c, pca9633_id); |
@@ -66,10 +95,11 @@ enum pca9633_cmd { | |||
66 | 95 | ||
67 | struct pca9633_led { | 96 | struct pca9633_led { |
68 | struct i2c_client *client; | 97 | struct i2c_client *client; |
98 | struct pca9633_chipdef *chipdef; | ||
69 | struct work_struct work; | 99 | struct work_struct work; |
70 | enum led_brightness brightness; | 100 | enum led_brightness brightness; |
71 | struct led_classdev led_cdev; | 101 | struct led_classdev led_cdev; |
72 | int led_num; /* 0 .. 3 potentially */ | 102 | int led_num; /* 0 .. 7 potentially */ |
73 | enum pca9633_cmd cmd; | 103 | enum pca9633_cmd cmd; |
74 | char name[32]; | 104 | char name[32]; |
75 | u8 gdc; | 105 | u8 gdc; |
@@ -78,24 +108,26 @@ struct pca9633_led { | |||
78 | 108 | ||
79 | static void pca9633_brightness_work(struct pca9633_led *pca9633) | 109 | static void pca9633_brightness_work(struct pca9633_led *pca9633) |
80 | { | 110 | { |
81 | u8 ledout = i2c_smbus_read_byte_data(pca9633->client, PCA9633_LEDOUT); | 111 | u8 ledout_addr = pca9633->chipdef->ledout_base + (pca9633->led_num / 4); |
82 | int shift = 2 * pca9633->led_num; | 112 | u8 ledout; |
113 | int shift = 2 * (pca9633->led_num % 4); | ||
83 | u8 mask = 0x3 << shift; | 114 | u8 mask = 0x3 << shift; |
84 | 115 | ||
116 | ledout = i2c_smbus_read_byte_data(pca9633->client, ledout_addr); | ||
85 | switch (pca9633->brightness) { | 117 | switch (pca9633->brightness) { |
86 | case LED_FULL: | 118 | case LED_FULL: |
87 | i2c_smbus_write_byte_data(pca9633->client, PCA9633_LEDOUT, | 119 | i2c_smbus_write_byte_data(pca9633->client, ledout_addr, |
88 | (ledout & ~mask) | (PCA9633_LED_ON << shift)); | 120 | (ledout & ~mask) | (PCA9633_LED_ON << shift)); |
89 | break; | 121 | break; |
90 | case LED_OFF: | 122 | case LED_OFF: |
91 | i2c_smbus_write_byte_data(pca9633->client, PCA9633_LEDOUT, | 123 | i2c_smbus_write_byte_data(pca9633->client, ledout_addr, |
92 | ledout & ~mask); | 124 | ledout & ~mask); |
93 | break; | 125 | break; |
94 | default: | 126 | default: |
95 | i2c_smbus_write_byte_data(pca9633->client, | 127 | i2c_smbus_write_byte_data(pca9633->client, |
96 | PCA9633_PWM_BASE + pca9633->led_num, | 128 | PCA9633_PWM_BASE + pca9633->led_num, |
97 | pca9633->brightness); | 129 | pca9633->brightness); |
98 | i2c_smbus_write_byte_data(pca9633->client, PCA9633_LEDOUT, | 130 | i2c_smbus_write_byte_data(pca9633->client, ledout_addr, |
99 | (ledout & ~mask) | (PCA9633_LED_PWM << shift)); | 131 | (ledout & ~mask) | (PCA9633_LED_PWM << shift)); |
100 | break; | 132 | break; |
101 | } | 133 | } |
@@ -103,15 +135,16 @@ static void pca9633_brightness_work(struct pca9633_led *pca9633) | |||
103 | 135 | ||
104 | static void pca9633_blink_work(struct pca9633_led *pca9633) | 136 | static void pca9633_blink_work(struct pca9633_led *pca9633) |
105 | { | 137 | { |
106 | u8 ledout = i2c_smbus_read_byte_data(pca9633->client, PCA9633_LEDOUT); | 138 | u8 ledout_addr = pca9633->chipdef->ledout_base + (pca9633->led_num / 4); |
139 | u8 ledout = i2c_smbus_read_byte_data(pca9633->client, ledout_addr); | ||
107 | u8 mode2 = i2c_smbus_read_byte_data(pca9633->client, PCA9633_MODE2); | 140 | u8 mode2 = i2c_smbus_read_byte_data(pca9633->client, PCA9633_MODE2); |
108 | int shift = 2 * pca9633->led_num; | 141 | int shift = 2 * (pca9633->led_num % 4); |
109 | u8 mask = 0x3 << shift; | 142 | u8 mask = 0x3 << shift; |
110 | 143 | ||
111 | i2c_smbus_write_byte_data(pca9633->client, PCA9633_GRPPWM, | 144 | i2c_smbus_write_byte_data(pca9633->client, pca9633->chipdef->grppwm, |
112 | pca9633->gdc); | 145 | pca9633->gdc); |
113 | 146 | ||
114 | i2c_smbus_write_byte_data(pca9633->client, PCA9633_GRPFREQ, | 147 | i2c_smbus_write_byte_data(pca9633->client, pca9633->chipdef->grpfreq, |
115 | pca9633->gfrq); | 148 | pca9633->gfrq); |
116 | 149 | ||
117 | if (!(mode2 & PCA9633_MODE2_DMBLNK)) | 150 | if (!(mode2 & PCA9633_MODE2_DMBLNK)) |
@@ -119,7 +152,7 @@ static void pca9633_blink_work(struct pca9633_led *pca9633) | |||
119 | mode2 | PCA9633_MODE2_DMBLNK); | 152 | mode2 | PCA9633_MODE2_DMBLNK); |
120 | 153 | ||
121 | if ((ledout & mask) != (PCA9633_LED_GRP_PWM << shift)) | 154 | if ((ledout & mask) != (PCA9633_LED_GRP_PWM << shift)) |
122 | i2c_smbus_write_byte_data(pca9633->client, PCA9633_LEDOUT, | 155 | i2c_smbus_write_byte_data(pca9633->client, ledout_addr, |
123 | (ledout & ~mask) | (PCA9633_LED_GRP_PWM << shift)); | 156 | (ledout & ~mask) | (PCA9633_LED_GRP_PWM << shift)); |
124 | } | 157 | } |
125 | 158 | ||
@@ -215,7 +248,7 @@ static int pca9633_blink_set(struct led_classdev *led_cdev, | |||
215 | 248 | ||
216 | #if IS_ENABLED(CONFIG_OF) | 249 | #if IS_ENABLED(CONFIG_OF) |
217 | static struct pca9633_platform_data * | 250 | static struct pca9633_platform_data * |
218 | pca9633_dt_init(struct i2c_client *client) | 251 | pca9633_dt_init(struct i2c_client *client, struct pca9633_chipdef *chip) |
219 | { | 252 | { |
220 | struct device_node *np = client->dev.of_node, *child; | 253 | struct device_node *np = client->dev.of_node, *child; |
221 | struct pca9633_platform_data *pdata; | 254 | struct pca9633_platform_data *pdata; |
@@ -223,11 +256,11 @@ pca9633_dt_init(struct i2c_client *client) | |||
223 | int count; | 256 | int count; |
224 | 257 | ||
225 | count = of_get_child_count(np); | 258 | count = of_get_child_count(np); |
226 | if (!count || count > 4) | 259 | if (!count || count > chip->n_leds) |
227 | return ERR_PTR(-ENODEV); | 260 | return ERR_PTR(-ENODEV); |
228 | 261 | ||
229 | pca9633_leds = devm_kzalloc(&client->dev, | 262 | pca9633_leds = devm_kzalloc(&client->dev, |
230 | sizeof(struct led_info) * count, GFP_KERNEL); | 263 | sizeof(struct led_info) * chip->n_leds, GFP_KERNEL); |
231 | if (!pca9633_leds) | 264 | if (!pca9633_leds) |
232 | return ERR_PTR(-ENOMEM); | 265 | return ERR_PTR(-ENOMEM); |
233 | 266 | ||
@@ -269,12 +302,14 @@ pca9633_dt_init(struct i2c_client *client) | |||
269 | } | 302 | } |
270 | 303 | ||
271 | static const struct of_device_id of_pca9633_match[] = { | 304 | static const struct of_device_id of_pca9633_match[] = { |
272 | { .compatible = "nxp,pca963x", }, | 305 | { .compatible = "nxp,pca9632", }, |
306 | { .compatible = "nxp,pca9633", }, | ||
307 | { .compatible = "nxp,pca9634", }, | ||
273 | {}, | 308 | {}, |
274 | }; | 309 | }; |
275 | #else | 310 | #else |
276 | static struct pca9633_platform_data * | 311 | static struct pca9633_platform_data * |
277 | pca9633_dt_init(struct i2c_client *client) | 312 | pca9633_dt_init(struct i2c_client *client, struct pca9633_chipdef *chip) |
278 | { | 313 | { |
279 | return ERR_PTR(-ENODEV); | 314 | return ERR_PTR(-ENODEV); |
280 | } | 315 | } |
@@ -285,34 +320,38 @@ static int pca9633_probe(struct i2c_client *client, | |||
285 | { | 320 | { |
286 | struct pca9633_led *pca9633; | 321 | struct pca9633_led *pca9633; |
287 | struct pca9633_platform_data *pdata; | 322 | struct pca9633_platform_data *pdata; |
323 | struct pca9633_chipdef *chip; | ||
288 | int i, err; | 324 | int i, err; |
289 | 325 | ||
326 | chip = &pca9633_chipdefs[id->driver_data]; | ||
290 | pdata = dev_get_platdata(&client->dev); | 327 | pdata = dev_get_platdata(&client->dev); |
291 | 328 | ||
292 | if (!pdata) { | 329 | if (!pdata) { |
293 | pdata = pca9633_dt_init(client); | 330 | pdata = pca9633_dt_init(client, chip); |
294 | if (IS_ERR(pdata)) { | 331 | if (IS_ERR(pdata)) { |
295 | dev_warn(&client->dev, "could not parse configuration\n"); | 332 | dev_warn(&client->dev, "could not parse configuration\n"); |
296 | pdata = NULL; | 333 | pdata = NULL; |
297 | } | 334 | } |
298 | } | 335 | } |
299 | 336 | ||
300 | if (pdata) { | 337 | if (pdata && (pdata->leds.num_leds < 1 || |
301 | if (pdata->leds.num_leds <= 0 || pdata->leds.num_leds > 4) { | 338 | pdata->leds.num_leds > chip->n_leds)) { |
302 | dev_err(&client->dev, "board info must claim at most 4 LEDs"); | 339 | dev_err(&client->dev, "board info must claim 1-%d LEDs", |
303 | return -EINVAL; | 340 | chip->n_leds); |
304 | } | 341 | return -EINVAL; |
305 | } | 342 | } |
306 | 343 | ||
307 | pca9633 = devm_kzalloc(&client->dev, 4 * sizeof(*pca9633), GFP_KERNEL); | 344 | pca9633 = devm_kzalloc(&client->dev, chip->n_leds * sizeof(*pca9633), |
345 | GFP_KERNEL); | ||
308 | if (!pca9633) | 346 | if (!pca9633) |
309 | return -ENOMEM; | 347 | return -ENOMEM; |
310 | 348 | ||
311 | i2c_set_clientdata(client, pca9633); | 349 | i2c_set_clientdata(client, pca9633); |
312 | 350 | ||
313 | for (i = 0; i < 4; i++) { | 351 | for (i = 0; i < chip->n_leds; i++) { |
314 | pca9633[i].client = client; | 352 | pca9633[i].client = client; |
315 | pca9633[i].led_num = i; | 353 | pca9633[i].led_num = i; |
354 | pca9633[i].chipdef = chip; | ||
316 | 355 | ||
317 | /* Platform data can specify LED names and default triggers */ | 356 | /* Platform data can specify LED names and default triggers */ |
318 | if (pdata && i < pdata->leds.num_leds) { | 357 | if (pdata && i < pdata->leds.num_leds) { |
@@ -349,7 +388,9 @@ static int pca9633_probe(struct i2c_client *client, | |||
349 | i2c_smbus_write_byte_data(client, PCA9633_MODE2, 0x01); | 388 | i2c_smbus_write_byte_data(client, PCA9633_MODE2, 0x01); |
350 | 389 | ||
351 | /* Turn off LEDs */ | 390 | /* Turn off LEDs */ |
352 | i2c_smbus_write_byte_data(client, PCA9633_LEDOUT, 0x00); | 391 | i2c_smbus_write_byte_data(client, chip->ledout_base, 0x00); |
392 | if (chip->n_leds > 4) | ||
393 | i2c_smbus_write_byte_data(client, chip->ledout_base + 1, 0x00); | ||
353 | 394 | ||
354 | return 0; | 395 | return 0; |
355 | 396 | ||
@@ -367,10 +408,11 @@ static int pca9633_remove(struct i2c_client *client) | |||
367 | struct pca9633_led *pca9633 = i2c_get_clientdata(client); | 408 | struct pca9633_led *pca9633 = i2c_get_clientdata(client); |
368 | int i; | 409 | int i; |
369 | 410 | ||
370 | for (i = 0; i < 4; i++) { | 411 | for (i = 0; i < pca9633->chipdef->n_leds; i++) |
371 | led_classdev_unregister(&pca9633[i].led_cdev); | 412 | if (pca9633[i].client != NULL) { |
372 | cancel_work_sync(&pca9633[i].work); | 413 | led_classdev_unregister(&pca9633[i].led_cdev); |
373 | } | 414 | cancel_work_sync(&pca9633[i].work); |
415 | } | ||
374 | 416 | ||
375 | return 0; | 417 | return 0; |
376 | } | 418 | } |