aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Ranostay <mranostay@gmail.com>2016-10-28 21:20:42 -0400
committerJacek Anaszewski <j.anaszewski@samsung.com>2016-11-22 06:07:04 -0500
commita8c170b015ff6695641bdfbdb74729411ba1e9e5 (patch)
tree05c4f0b053eae8a9613d829673b400882f307a24
parent90a5537bd83b461180120c926b7795c7dd44093a (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.c40
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
108struct pca963x_led { 109struct 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 }
150unlock: 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
182static 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
183static int pca963x_led_set(struct led_classdev *led_cdev, 199static 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
214unlock:
215 mutex_unlock(&pca963x->chip->mutex);
216 return ret;
191} 217}
192 218
193static unsigned int pca963x_period_scale(struct pca963x_led *pca963x, 219static 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) */