aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRicardo Ribalda Delgado <ricardo.ribalda@gmail.com>2013-08-14 17:23:49 -0400
committerBryan Wu <cooloney@gmail.com>2013-08-26 20:22:14 -0400
commita7d0e9884fd7594d4de5066add5135ac6bb55bd4 (patch)
tree8090e4f54ecbde5fa2b5aa6afeb07f2e25b4cbca /drivers
parenta5cd98b796b6891edc324415034a7f89531c754f (diff)
leds-pca9633: Add mutex to the ledout register
To update an LED a register has to be read, updated and writen. If another LED whas been updated at the same time, this could lead into wrong updates. This patch adds a common mutex to all the leds of the same chip to protect the ledout register. Signed-off-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com> Signed-off-by: Bryan Wu <cooloney@gmail.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/leds/leds-pca9633.c86
1 files changed, 55 insertions, 31 deletions
diff --git a/drivers/leds/leds-pca9633.c b/drivers/leds/leds-pca9633.c
index 7dd48f896d4e..aaa1c4a0dbc5 100644
--- a/drivers/leds/leds-pca9633.c
+++ b/drivers/leds/leds-pca9633.c
@@ -93,9 +93,17 @@ enum pca9633_cmd {
93 BLINK_SET, 93 BLINK_SET,
94}; 94};
95 95
96struct pca9633_led { 96struct pca9633_led;
97 struct i2c_client *client; 97
98struct pca9633 {
98 struct pca9633_chipdef *chipdef; 99 struct pca9633_chipdef *chipdef;
100 struct mutex mutex;
101 struct i2c_client *client;
102 struct pca9633_led *leds;
103};
104
105struct pca9633_led {
106 struct pca9633 *chip;
99 struct work_struct work; 107 struct work_struct work;
100 enum led_brightness brightness; 108 enum led_brightness brightness;
101 struct led_classdev led_cdev; 109 struct led_classdev led_cdev;
@@ -108,52 +116,60 @@ struct pca9633_led {
108 116
109static void pca9633_brightness_work(struct pca9633_led *pca9633) 117static void pca9633_brightness_work(struct pca9633_led *pca9633)
110{ 118{
111 u8 ledout_addr = pca9633->chipdef->ledout_base + (pca9633->led_num / 4); 119 u8 ledout_addr = pca9633->chip->chipdef->ledout_base
120 + (pca9633->led_num / 4);
112 u8 ledout; 121 u8 ledout;
113 int shift = 2 * (pca9633->led_num % 4); 122 int shift = 2 * (pca9633->led_num % 4);
114 u8 mask = 0x3 << shift; 123 u8 mask = 0x3 << shift;
115 124
116 ledout = i2c_smbus_read_byte_data(pca9633->client, ledout_addr); 125 mutex_lock(&pca9633->chip->mutex);
126 ledout = i2c_smbus_read_byte_data(pca9633->chip->client, ledout_addr);
117 switch (pca9633->brightness) { 127 switch (pca9633->brightness) {
118 case LED_FULL: 128 case LED_FULL:
119 i2c_smbus_write_byte_data(pca9633->client, ledout_addr, 129 i2c_smbus_write_byte_data(pca9633->chip->client, ledout_addr,
120 (ledout & ~mask) | (PCA9633_LED_ON << shift)); 130 (ledout & ~mask) | (PCA9633_LED_ON << shift));
121 break; 131 break;
122 case LED_OFF: 132 case LED_OFF:
123 i2c_smbus_write_byte_data(pca9633->client, ledout_addr, 133 i2c_smbus_write_byte_data(pca9633->chip->client, ledout_addr,
124 ledout & ~mask); 134 ledout & ~mask);
125 break; 135 break;
126 default: 136 default:
127 i2c_smbus_write_byte_data(pca9633->client, 137 i2c_smbus_write_byte_data(pca9633->chip->client,
128 PCA9633_PWM_BASE + pca9633->led_num, 138 PCA9633_PWM_BASE + pca9633->led_num,
129 pca9633->brightness); 139 pca9633->brightness);
130 i2c_smbus_write_byte_data(pca9633->client, ledout_addr, 140 i2c_smbus_write_byte_data(pca9633->chip->client, ledout_addr,
131 (ledout & ~mask) | (PCA9633_LED_PWM << shift)); 141 (ledout & ~mask) | (PCA9633_LED_PWM << shift));
132 break; 142 break;
133 } 143 }
144 mutex_unlock(&pca9633->chip->mutex);
134} 145}
135 146
136static void pca9633_blink_work(struct pca9633_led *pca9633) 147static void pca9633_blink_work(struct pca9633_led *pca9633)
137{ 148{
138 u8 ledout_addr = pca9633->chipdef->ledout_base + (pca9633->led_num / 4); 149 u8 ledout_addr = pca9633->chip->chipdef->ledout_base +
139 u8 ledout = i2c_smbus_read_byte_data(pca9633->client, ledout_addr); 150 (pca9633->led_num / 4);
140 u8 mode2 = i2c_smbus_read_byte_data(pca9633->client, PCA9633_MODE2); 151 u8 ledout;
152 u8 mode2 = i2c_smbus_read_byte_data(pca9633->chip->client,
153 PCA9633_MODE2);
141 int shift = 2 * (pca9633->led_num % 4); 154 int shift = 2 * (pca9633->led_num % 4);
142 u8 mask = 0x3 << shift; 155 u8 mask = 0x3 << shift;
143 156
144 i2c_smbus_write_byte_data(pca9633->client, pca9633->chipdef->grppwm, 157 i2c_smbus_write_byte_data(pca9633->chip->client,
145 pca9633->gdc); 158 pca9633->chip->chipdef->grppwm, pca9633->gdc);
146 159
147 i2c_smbus_write_byte_data(pca9633->client, pca9633->chipdef->grpfreq, 160 i2c_smbus_write_byte_data(pca9633->chip->client,
148 pca9633->gfrq); 161 pca9633->chip->chipdef->grpfreq, pca9633->gfrq);
149 162
150 if (!(mode2 & PCA9633_MODE2_DMBLNK)) 163 if (!(mode2 & PCA9633_MODE2_DMBLNK))
151 i2c_smbus_write_byte_data(pca9633->client, PCA9633_MODE2, 164 i2c_smbus_write_byte_data(pca9633->chip->client, PCA9633_MODE2,
152 mode2 | PCA9633_MODE2_DMBLNK); 165 mode2 | PCA9633_MODE2_DMBLNK);
153 166
167 mutex_lock(&pca9633->chip->mutex);
168 ledout = i2c_smbus_read_byte_data(pca9633->chip->client, ledout_addr);
154 if ((ledout & mask) != (PCA9633_LED_GRP_PWM << shift)) 169 if ((ledout & mask) != (PCA9633_LED_GRP_PWM << shift))
155 i2c_smbus_write_byte_data(pca9633->client, ledout_addr, 170 i2c_smbus_write_byte_data(pca9633->chip->client, ledout_addr,
156 (ledout & ~mask) | (PCA9633_LED_GRP_PWM << shift)); 171 (ledout & ~mask) | (PCA9633_LED_GRP_PWM << shift));
172 mutex_unlock(&pca9633->chip->mutex);
157} 173}
158 174
159static void pca9633_work(struct work_struct *work) 175static void pca9633_work(struct work_struct *work)
@@ -318,6 +334,7 @@ pca9633_dt_init(struct i2c_client *client, struct pca9633_chipdef *chip)
318static int pca9633_probe(struct i2c_client *client, 334static int pca9633_probe(struct i2c_client *client,
319 const struct i2c_device_id *id) 335 const struct i2c_device_id *id)
320{ 336{
337 struct pca9633 *pca9633_chip;
321 struct pca9633_led *pca9633; 338 struct pca9633_led *pca9633;
322 struct pca9633_platform_data *pdata; 339 struct pca9633_platform_data *pdata;
323 struct pca9633_chipdef *chip; 340 struct pca9633_chipdef *chip;
@@ -341,17 +358,30 @@ static int pca9633_probe(struct i2c_client *client,
341 return -EINVAL; 358 return -EINVAL;
342 } 359 }
343 360
361 pca9633_chip = devm_kzalloc(&client->dev, sizeof(*pca9633_chip),
362 GFP_KERNEL);
363 if (!pca9633_chip)
364 return -ENOMEM;
344 pca9633 = devm_kzalloc(&client->dev, chip->n_leds * sizeof(*pca9633), 365 pca9633 = devm_kzalloc(&client->dev, chip->n_leds * sizeof(*pca9633),
345 GFP_KERNEL); 366 GFP_KERNEL);
346 if (!pca9633) 367 if (!pca9633)
347 return -ENOMEM; 368 return -ENOMEM;
348 369
349 i2c_set_clientdata(client, pca9633); 370 i2c_set_clientdata(client, pca9633_chip);
371
372 mutex_init(&pca9633_chip->mutex);
373 pca9633_chip->chipdef = chip;
374 pca9633_chip->client = client;
375 pca9633_chip->leds = pca9633;
376
377 /* Turn off LEDs by default*/
378 i2c_smbus_write_byte_data(client, chip->ledout_base, 0x00);
379 if (chip->n_leds > 4)
380 i2c_smbus_write_byte_data(client, chip->ledout_base + 1, 0x00);
350 381
351 for (i = 0; i < chip->n_leds; i++) { 382 for (i = 0; i < chip->n_leds; i++) {
352 pca9633[i].client = client;
353 pca9633[i].led_num = i; 383 pca9633[i].led_num = i;
354 pca9633[i].chipdef = chip; 384 pca9633[i].chip = pca9633_chip;
355 385
356 /* Platform data can specify LED names and default triggers */ 386 /* Platform data can specify LED names and default triggers */
357 if (pdata && i < pdata->leds.num_leds) { 387 if (pdata && i < pdata->leds.num_leds) {
@@ -389,11 +419,6 @@ static int pca9633_probe(struct i2c_client *client,
389 if (pdata && pdata->outdrv == PCA9633_OPEN_DRAIN) 419 if (pdata && pdata->outdrv == PCA9633_OPEN_DRAIN)
390 i2c_smbus_write_byte_data(client, PCA9633_MODE2, 0x01); 420 i2c_smbus_write_byte_data(client, PCA9633_MODE2, 0x01);
391 421
392 /* Turn off LEDs */
393 i2c_smbus_write_byte_data(client, chip->ledout_base, 0x00);
394 if (chip->n_leds > 4)
395 i2c_smbus_write_byte_data(client, chip->ledout_base + 1, 0x00);
396
397 return 0; 422 return 0;
398 423
399exit: 424exit:
@@ -407,14 +432,13 @@ exit:
407 432
408static int pca9633_remove(struct i2c_client *client) 433static int pca9633_remove(struct i2c_client *client)
409{ 434{
410 struct pca9633_led *pca9633 = i2c_get_clientdata(client); 435 struct pca9633 *pca9633 = i2c_get_clientdata(client);
411 int i; 436 int i;
412 437
413 for (i = 0; i < pca9633->chipdef->n_leds; i++) 438 for (i = 0; i < pca9633->chipdef->n_leds; i++) {
414 if (pca9633[i].client != NULL) { 439 led_classdev_unregister(&pca9633->leds[i].led_cdev);
415 led_classdev_unregister(&pca9633[i].led_cdev); 440 cancel_work_sync(&pca9633->leds[i].work);
416 cancel_work_sync(&pca9633[i].work); 441 }
417 }
418 442
419 return 0; 443 return 0;
420} 444}