Skip to content

Commit fd6dd95

Browse files
bernardocrodriguespavelmachek
authored andcommitted
leds: pca963x: fix blink with hw acceleration
LEDs would behave differently depending on the blink hardware acceleration configuration. This commit will make LEDs respond exactly the same independently of the hardware acceleration status. In other words, if you had two pca963x, side by side, one with blink hardware acceleration "ON" and the other "OFF; and performed some arbitrary sequence of API calls (e.g. turn on/off, change brightness, change blink mode, etc.) you probably would end with not matching LED states. 'pca963x software blink' and 'leds-gpio' behavior were used as reference. Actual chip used to validate this change: pca9634 Some of the unmatched behaviors being fixed are (when hw blink was "ON") - Leds would stop blinking when the brightness was changed. - Leds would persist their blinking mode even after being turned off (brightness = 0). - Leds would only blink if another led was solid (pca963x will be forced out of low power) Signed-off-by: Bernardo Rodrigues <[email protected]> Signed-off-by: Pavel Machek <[email protected]>
1 parent 568035b commit fd6dd95

File tree

1 file changed

+20
-2
lines changed

1 file changed

+20
-2
lines changed

drivers/leds/leds-pca963x.c

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ struct pca963x_led {
101101
struct pca963x *chip;
102102
struct led_classdev led_cdev;
103103
int led_num; /* 0 .. 15 potentially */
104+
bool blinking;
104105
u8 gdc;
105106
u8 gfrq;
106107
};
@@ -129,12 +130,21 @@ static int pca963x_brightness(struct pca963x_led *led,
129130

130131
switch (brightness) {
131132
case LED_FULL:
132-
val = (ledout & ~mask) | (PCA963X_LED_ON << shift);
133+
if (led->blinking) {
134+
val = (ledout & ~mask) | (PCA963X_LED_GRP_PWM << shift);
135+
ret = i2c_smbus_write_byte_data(client,
136+
PCA963X_PWM_BASE +
137+
led->led_num,
138+
LED_FULL);
139+
} else {
140+
val = (ledout & ~mask) | (PCA963X_LED_ON << shift);
141+
}
133142
ret = i2c_smbus_write_byte_data(client, ledout_addr, val);
134143
break;
135144
case LED_OFF:
136145
val = ledout & ~mask;
137146
ret = i2c_smbus_write_byte_data(client, ledout_addr, val);
147+
led->blinking = false;
138148
break;
139149
default:
140150
ret = i2c_smbus_write_byte_data(client,
@@ -144,7 +154,11 @@ static int pca963x_brightness(struct pca963x_led *led,
144154
if (ret < 0)
145155
return ret;
146156

147-
val = (ledout & ~mask) | (PCA963X_LED_PWM << shift);
157+
if (led->blinking)
158+
val = (ledout & ~mask) | (PCA963X_LED_GRP_PWM << shift);
159+
else
160+
val = (ledout & ~mask) | (PCA963X_LED_PWM << shift);
161+
148162
ret = i2c_smbus_write_byte_data(client, ledout_addr, val);
149163
break;
150164
}
@@ -181,6 +195,7 @@ static void pca963x_blink(struct pca963x_led *led)
181195
}
182196

183197
mutex_unlock(&led->chip->mutex);
198+
led->blinking = true;
184199
}
185200

186201
static int pca963x_power_state(struct pca963x_led *led)
@@ -275,6 +290,8 @@ static int pca963x_blink_set(struct led_classdev *led_cdev,
275290
led->gfrq = gfrq;
276291

277292
pca963x_blink(led);
293+
led->led_cdev.brightness = LED_FULL;
294+
pca963x_led_set(led_cdev, LED_FULL);
278295

279296
*delay_on = time_on;
280297
*delay_off = time_off;
@@ -337,6 +354,7 @@ static int pca963x_register_leds(struct i2c_client *client,
337354
led->led_cdev.brightness_set_blocking = pca963x_led_set;
338355
if (hw_blink)
339356
led->led_cdev.blink_set = pca963x_blink_set;
357+
led->blinking = false;
340358

341359
init_data.fwnode = child;
342360
/* for backwards compatibility */

0 commit comments

Comments
 (0)