diff options
author | Matt Ranostay <mranostay@gmail.com> | 2016-10-28 21:20:42 -0400 |
---|---|---|
committer | Jacek Anaszewski <j.anaszewski@samsung.com> | 2016-11-22 06:07:04 -0500 |
commit | a8c170b015ff6695641bdfbdb74729411ba1e9e5 (patch) | |
tree | 05c4f0b053eae8a9613d829673b400882f307a24 | |
parent | 90a5537bd83b461180120c926b7795c7dd44093a (diff) |
leds: pca963x: enable low-power state
Allow chip to enter low power state when no LEDs are being lit or in
blink mode.
Cc: Peter Meerwald <p.meerwald@bct-electronic.com>,
Cc: Ricardo Ribalda <ricardo.ribalda@gmail.com>
Cc: Tony Lindgren <tony@atomide.com>
Signed-off-by: Matt Ranostay <matt@ranostay.consulting>
Signed-off-by: Jacek Anaszewski <j.anaszewski@samsung.com>
-rw-r--r-- | drivers/leds/leds-pca963x.c | 40 |
1 files changed, 33 insertions, 7 deletions
diff --git a/drivers/leds/leds-pca963x.c b/drivers/leds/leds-pca963x.c index b6ce1f2ec33e..46fbf935944a 100644 --- a/drivers/leds/leds-pca963x.c +++ b/drivers/leds/leds-pca963x.c | |||
@@ -103,6 +103,7 @@ struct pca963x { | |||
103 | struct mutex mutex; | 103 | struct mutex mutex; |
104 | struct i2c_client *client; | 104 | struct i2c_client *client; |
105 | struct pca963x_led *leds; | 105 | struct pca963x_led *leds; |
106 | unsigned long leds_on; | ||
106 | }; | 107 | }; |
107 | 108 | ||
108 | struct pca963x_led { | 109 | struct pca963x_led { |
@@ -124,7 +125,6 @@ static int pca963x_brightness(struct pca963x_led *pca963x, | |||
124 | u8 mask = 0x3 << shift; | 125 | u8 mask = 0x3 << shift; |
125 | int ret; | 126 | int ret; |
126 | 127 | ||
127 | mutex_lock(&pca963x->chip->mutex); | ||
128 | ledout = i2c_smbus_read_byte_data(pca963x->chip->client, ledout_addr); | 128 | ledout = i2c_smbus_read_byte_data(pca963x->chip->client, ledout_addr); |
129 | switch (brightness) { | 129 | switch (brightness) { |
130 | case LED_FULL: | 130 | case LED_FULL: |
@@ -141,14 +141,13 @@ static int pca963x_brightness(struct pca963x_led *pca963x, | |||
141 | PCA963X_PWM_BASE + pca963x->led_num, | 141 | PCA963X_PWM_BASE + pca963x->led_num, |
142 | brightness); | 142 | brightness); |
143 | if (ret < 0) | 143 | if (ret < 0) |
144 | goto unlock; | 144 | return ret; |
145 | ret = i2c_smbus_write_byte_data(pca963x->chip->client, | 145 | ret = i2c_smbus_write_byte_data(pca963x->chip->client, |
146 | ledout_addr, | 146 | ledout_addr, |
147 | (ledout & ~mask) | (PCA963X_LED_PWM << shift)); | 147 | (ledout & ~mask) | (PCA963X_LED_PWM << shift)); |
148 | break; | 148 | break; |
149 | } | 149 | } |
150 | unlock: | 150 | |
151 | mutex_unlock(&pca963x->chip->mutex); | ||
152 | return ret; | 151 | return ret; |
153 | } | 152 | } |
154 | 153 | ||
@@ -180,14 +179,41 @@ static void pca963x_blink(struct pca963x_led *pca963x) | |||
180 | mutex_unlock(&pca963x->chip->mutex); | 179 | mutex_unlock(&pca963x->chip->mutex); |
181 | } | 180 | } |
182 | 181 | ||
182 | static int pca963x_power_state(struct pca963x_led *pca963x) | ||
183 | { | ||
184 | unsigned long *leds_on = &pca963x->chip->leds_on; | ||
185 | unsigned long cached_leds = pca963x->chip->leds_on; | ||
186 | |||
187 | if (pca963x->led_cdev.brightness) | ||
188 | set_bit(pca963x->led_num, leds_on); | ||
189 | else | ||
190 | clear_bit(pca963x->led_num, leds_on); | ||
191 | |||
192 | if (!(*leds_on) != !cached_leds) | ||
193 | return i2c_smbus_write_byte_data(pca963x->chip->client, | ||
194 | PCA963X_MODE1, *leds_on ? 0 : BIT(4)); | ||
195 | |||
196 | return 0; | ||
197 | } | ||
198 | |||
183 | static int pca963x_led_set(struct led_classdev *led_cdev, | 199 | static int pca963x_led_set(struct led_classdev *led_cdev, |
184 | enum led_brightness value) | 200 | enum led_brightness value) |
185 | { | 201 | { |
186 | struct pca963x_led *pca963x; | 202 | struct pca963x_led *pca963x; |
203 | int ret; | ||
187 | 204 | ||
188 | pca963x = container_of(led_cdev, struct pca963x_led, led_cdev); | 205 | pca963x = container_of(led_cdev, struct pca963x_led, led_cdev); |
189 | 206 | ||
190 | return pca963x_brightness(pca963x, value); | 207 | mutex_lock(&pca963x->chip->mutex); |
208 | |||
209 | ret = pca963x_brightness(pca963x, value); | ||
210 | if (ret < 0) | ||
211 | goto unlock; | ||
212 | ret = pca963x_power_state(pca963x); | ||
213 | |||
214 | unlock: | ||
215 | mutex_unlock(&pca963x->chip->mutex); | ||
216 | return ret; | ||
191 | } | 217 | } |
192 | 218 | ||
193 | static unsigned int pca963x_period_scale(struct pca963x_led *pca963x, | 219 | static unsigned int pca963x_period_scale(struct pca963x_led *pca963x, |
@@ -403,8 +429,8 @@ static int pca963x_probe(struct i2c_client *client, | |||
403 | goto exit; | 429 | goto exit; |
404 | } | 430 | } |
405 | 431 | ||
406 | /* Disable LED all-call address and set normal mode */ | 432 | /* Disable LED all-call address, and power down initially */ |
407 | i2c_smbus_write_byte_data(client, PCA963X_MODE1, 0x00); | 433 | i2c_smbus_write_byte_data(client, PCA963X_MODE1, BIT(4)); |
408 | 434 | ||
409 | if (pdata) { | 435 | if (pdata) { |
410 | /* Configure output: open-drain or totem pole (push-pull) */ | 436 | /* Configure output: open-drain or totem pole (push-pull) */ |