diff options
author | Joachim Eastwood <manabian@gmail.com> | 2011-05-24 20:13:23 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-25 11:39:50 -0400 |
commit | 3c1ab50d0a31b27bb4e55168f4901dd91e6e5ea4 (patch) | |
tree | a9ec955ad64bda0ff64f5654c1b16eeb79e0d895 | |
parent | fff26f8141145e01eae8f4d6e642ac8a0d500158 (diff) |
drivers/leds/leds-pca9532.c: add gpio capability
Allow unused leds on pca9532 to be used as gpio. The board I am working
on now has no less than 6 pca9532 chips. One chips is used for only leds,
one has 14 leds and 2 gpio and the rest of the chips are gpio only.
There is also one board in mainline which could use this capabilty;
arch/arm/mach-iop32x/n2100.c
232 { .type = PCA9532_TYPE_NONE }, /* power OFF gpio */
233 { .type = PCA9532_TYPE_NONE }, /* reset gpio */
This patch defines a new pin type, PCA9532_TYPE_GPIO, and registers a
gpiochip if any pin has this type set. The gpio will registers all chip
pins but will filter on gpio_request.
[randy.dunlap@oracle.com: fix build when GPIOLIB is not enabled]
Signed-off-by: Joachim Eastwood <joachim.eastwood@jotron.com>
Reviewed-by: Wolfram Sang <w.sang@pengutronix.de>
Reviewed-by: H Hartley Sweeten <hsweeten@visionengravers.com>
Cc: Richard Purdie <rpurdie@rpsys.net>
Cc: Grant Likely <grant.likely@secretlab.ca>
Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com>
Cc: Jan Weitzel <j.weitzel@phytec.de>
Cc: Juergen Kilb <j.kilb@phytec.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | drivers/leds/Kconfig | 10 | ||||
-rw-r--r-- | drivers/leds/leds-pca9532.c | 113 | ||||
-rw-r--r-- | include/linux/leds-pca9532.h | 3 |
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 | ||
165 | config 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 | |||
165 | config LEDS_GPIO | 175 | config 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 | ||
203 | static void pca9532_destroy_devices(struct pca9532_data *data, int n_devs) | 208 | #ifdef CONFIG_LEDS_PCA9532_GPIO |
209 | static 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 | |||
220 | static 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 | |||
233 | static 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 | |||
243 | static 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 | |||
251 | static 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 | |||
259 | static 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 | ||
229 | static int pca9532_configure(struct i2c_client *client, | 299 | static 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 | ||
302 | exit: | 404 | exit: |
@@ -337,7 +439,12 @@ static int pca9532_probe(struct i2c_client *client, | |||
337 | static int pca9532_remove(struct i2c_client *client) | 439 | static 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 | ||
27 | enum pca9532_type { PCA9532_TYPE_NONE, PCA9532_TYPE_LED, | 27 | enum pca9532_type { PCA9532_TYPE_NONE, PCA9532_TYPE_LED, |
28 | PCA9532_TYPE_N2100_BEEP }; | 28 | PCA9532_TYPE_N2100_BEEP, PCA9532_TYPE_GPIO }; |
29 | 29 | ||
30 | struct pca9532_led { | 30 | struct 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 */ |