aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/leds/Kconfig10
-rw-r--r--drivers/leds/leds-pca9532.c113
-rw-r--r--include/linux/leds-pca9532.h3
3 files changed, 122 insertions, 4 deletions
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 9bec8699b8a3..09de8dac8a73 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -162,6 +162,16 @@ config LEDS_PCA9532
162 LED controller. It is generally only useful 162 LED controller. It is generally only useful
163 as a platform driver 163 as a platform driver
164 164
165config LEDS_PCA9532_GPIO
166 bool "Enable GPIO support for PCA9532"
167 depends on LEDS_PCA9532
168 depends on GPIOLIB
169 help
170 Allow unused pins on PCA9532 to be used as gpio.
171
172 To use a pin as gpio pca9532_type in pca9532_platform data needs to
173 set to PCA9532_TYPE_GPIO.
174
165config LEDS_GPIO 175config LEDS_GPIO
166 tristate "LED Support for GPIO connected LEDs" 176 tristate "LED Support for GPIO connected LEDs"
167 depends on LEDS_CLASS 177 depends on LEDS_CLASS
diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c
index 5bf63af09ddf..ebea85603f43 100644
--- a/drivers/leds/leds-pca9532.c
+++ b/drivers/leds/leds-pca9532.c
@@ -19,7 +19,9 @@
19#include <linux/mutex.h> 19#include <linux/mutex.h>
20#include <linux/workqueue.h> 20#include <linux/workqueue.h>
21#include <linux/leds-pca9532.h> 21#include <linux/leds-pca9532.h>
22#include <linux/gpio.h>
22 23
24#define PCA9532_REG_INPUT(i) ((i)/8)
23#define PCA9532_REG_PSC(i) (0x2+(i)*2) 25#define PCA9532_REG_PSC(i) (0x2+(i)*2)
24#define PCA9532_REG_PWM(i) (0x3+(i)*2) 26#define PCA9532_REG_PWM(i) (0x3+(i)*2)
25#define PCA9532_REG_LS0 0x6 27#define PCA9532_REG_LS0 0x6
@@ -34,6 +36,9 @@ struct pca9532_data {
34 struct mutex update_lock; 36 struct mutex update_lock;
35 struct input_dev *idev; 37 struct input_dev *idev;
36 struct work_struct work; 38 struct work_struct work;
39#ifdef CONFIG_LEDS_PCA9532_GPIO
40 struct gpio_chip gpio;
41#endif
37 u8 pwm[2]; 42 u8 pwm[2];
38 u8 psc[2]; 43 u8 psc[2];
39}; 44};
@@ -200,16 +205,68 @@ static void pca9532_led_work(struct work_struct *work)
200 pca9532_setled(led); 205 pca9532_setled(led);
201} 206}
202 207
203static void pca9532_destroy_devices(struct pca9532_data *data, int n_devs) 208#ifdef CONFIG_LEDS_PCA9532_GPIO
209static int pca9532_gpio_request_pin(struct gpio_chip *gc, unsigned offset)
210{
211 struct pca9532_data *data = container_of(gc, struct pca9532_data, gpio);
212 struct pca9532_led *led = &data->leds[offset];
213
214 if (led->type == PCA9532_TYPE_GPIO)
215 return 0;
216
217 return -EBUSY;
218}
219
220static void pca9532_gpio_set_value(struct gpio_chip *gc, unsigned offset, int val)
221{
222 struct pca9532_data *data = container_of(gc, struct pca9532_data, gpio);
223 struct pca9532_led *led = &data->leds[offset];
224
225 if (val)
226 led->state = PCA9532_ON;
227 else
228 led->state = PCA9532_OFF;
229
230 pca9532_setled(led);
231}
232
233static int pca9532_gpio_get_value(struct gpio_chip *gc, unsigned offset)
234{
235 struct pca9532_data *data = container_of(gc, struct pca9532_data, gpio);
236 unsigned char reg;
237
238 reg = i2c_smbus_read_byte_data(data->client, PCA9532_REG_INPUT(offset));
239
240 return !!(reg & (1 << (offset % 8)));
241}
242
243static int pca9532_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
244{
245 /* To use as input ensure pin is not driven */
246 pca9532_gpio_set_value(gc, offset, 0);
247
248 return 0;
249}
250
251static int pca9532_gpio_direction_output(struct gpio_chip *gc, unsigned offset, int val)
252{
253 pca9532_gpio_set_value(gc, offset, val);
254
255 return 0;
256}
257#endif /* CONFIG_LEDS_PCA9532_GPIO */
258
259static int pca9532_destroy_devices(struct pca9532_data *data, int n_devs)
204{ 260{
205 int i = n_devs; 261 int i = n_devs;
206 262
207 if (!data) 263 if (!data)
208 return; 264 return -EINVAL;
209 265
210 while (--i >= 0) { 266 while (--i >= 0) {
211 switch (data->leds[i].type) { 267 switch (data->leds[i].type) {
212 case PCA9532_TYPE_NONE: 268 case PCA9532_TYPE_NONE:
269 case PCA9532_TYPE_GPIO:
213 break; 270 break;
214 case PCA9532_TYPE_LED: 271 case PCA9532_TYPE_LED:
215 led_classdev_unregister(&data->leds[i].ldev); 272 led_classdev_unregister(&data->leds[i].ldev);
@@ -224,12 +281,26 @@ static void pca9532_destroy_devices(struct pca9532_data *data, int n_devs)
224 break; 281 break;
225 } 282 }
226 } 283 }
284
285#ifdef CONFIG_LEDS_PCA9532_GPIO
286 if (data->gpio.dev) {
287 int err = gpiochip_remove(&data->gpio);
288 if (err) {
289 dev_err(&data->client->dev, "%s failed, %d\n",
290 "gpiochip_remove()", err);
291 return err;
292 }
293 }
294#endif
295
296 return 0;
227} 297}
228 298
229static int pca9532_configure(struct i2c_client *client, 299static int pca9532_configure(struct i2c_client *client,
230 struct pca9532_data *data, struct pca9532_platform_data *pdata) 300 struct pca9532_data *data, struct pca9532_platform_data *pdata)
231{ 301{
232 int i, err = 0; 302 int i, err = 0;
303 int gpios = 0;
233 304
234 for (i = 0; i < 2; i++) { 305 for (i = 0; i < 2; i++) {
235 data->pwm[i] = pdata->pwm[i]; 306 data->pwm[i] = pdata->pwm[i];
@@ -249,6 +320,9 @@ static int pca9532_configure(struct i2c_client *client,
249 switch (led->type) { 320 switch (led->type) {
250 case PCA9532_TYPE_NONE: 321 case PCA9532_TYPE_NONE:
251 break; 322 break;
323 case PCA9532_TYPE_GPIO:
324 gpios++;
325 break;
252 case PCA9532_TYPE_LED: 326 case PCA9532_TYPE_LED:
253 led->state = pled->state; 327 led->state = pled->state;
254 led->name = pled->name; 328 led->name = pled->name;
@@ -297,6 +371,34 @@ static int pca9532_configure(struct i2c_client *client,
297 break; 371 break;
298 } 372 }
299 } 373 }
374
375#ifdef CONFIG_LEDS_PCA9532_GPIO
376 if (gpios) {
377 data->gpio.label = "gpio-pca9532";
378 data->gpio.direction_input = pca9532_gpio_direction_input;
379 data->gpio.direction_output = pca9532_gpio_direction_output;
380 data->gpio.set = pca9532_gpio_set_value;
381 data->gpio.get = pca9532_gpio_get_value;
382 data->gpio.request = pca9532_gpio_request_pin;
383 data->gpio.can_sleep = 1;
384 data->gpio.base = pdata->gpio_base;
385 data->gpio.ngpio = 16;
386 data->gpio.dev = &client->dev;
387 data->gpio.owner = THIS_MODULE;
388
389 err = gpiochip_add(&data->gpio);
390 if (err) {
391 /* Use data->gpio.dev as a flag for freeing gpiochip */
392 data->gpio.dev = NULL;
393 dev_warn(&client->dev, "could not add gpiochip\n");
394 } else {
395 dev_info(&client->dev, "gpios %i...%i\n",
396 data->gpio.base, data->gpio.base +
397 data->gpio.ngpio - 1);
398 }
399 }
400#endif
401
300 return 0; 402 return 0;
301 403
302exit: 404exit:
@@ -337,7 +439,12 @@ static int pca9532_probe(struct i2c_client *client,
337static int pca9532_remove(struct i2c_client *client) 439static int pca9532_remove(struct i2c_client *client)
338{ 440{
339 struct pca9532_data *data = i2c_get_clientdata(client); 441 struct pca9532_data *data = i2c_get_clientdata(client);
340 pca9532_destroy_devices(data, 16); 442 int err;
443
444 err = pca9532_destroy_devices(data, 16);
445 if (err)
446 return err;
447
341 kfree(data); 448 kfree(data);
342 return 0; 449 return 0;
343} 450}
diff --git a/include/linux/leds-pca9532.h b/include/linux/leds-pca9532.h
index f158eb1149aa..b8d6fffed4d8 100644
--- a/include/linux/leds-pca9532.h
+++ b/include/linux/leds-pca9532.h
@@ -25,7 +25,7 @@ enum pca9532_state {
25}; 25};
26 26
27enum pca9532_type { PCA9532_TYPE_NONE, PCA9532_TYPE_LED, 27enum pca9532_type { PCA9532_TYPE_NONE, PCA9532_TYPE_LED,
28 PCA9532_TYPE_N2100_BEEP }; 28 PCA9532_TYPE_N2100_BEEP, PCA9532_TYPE_GPIO };
29 29
30struct pca9532_led { 30struct pca9532_led {
31 u8 id; 31 u8 id;
@@ -41,6 +41,7 @@ struct pca9532_platform_data {
41 struct pca9532_led leds[16]; 41 struct pca9532_led leds[16];
42 u8 pwm[2]; 42 u8 pwm[2];
43 u8 psc[2]; 43 u8 psc[2];
44 int gpio_base;
44}; 45};
45 46
46#endif /* __LINUX_PCA9532_H */ 47#endif /* __LINUX_PCA9532_H */