diff options
Diffstat (limited to 'drivers/gpio/gpio-twl4030.c')
-rw-r--r-- | drivers/gpio/gpio-twl4030.c | 176 |
1 files changed, 112 insertions, 64 deletions
diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index 9572aa137e6f..4d330e36da1d 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c | |||
@@ -37,7 +37,6 @@ | |||
37 | 37 | ||
38 | #include <linux/i2c/twl.h> | 38 | #include <linux/i2c/twl.h> |
39 | 39 | ||
40 | |||
41 | /* | 40 | /* |
42 | * The GPIO "subchip" supports 18 GPIOs which can be configured as | 41 | * The GPIO "subchip" supports 18 GPIOs which can be configured as |
43 | * inputs or outputs, with pullups or pulldowns on each pin. Each | 42 | * inputs or outputs, with pullups or pulldowns on each pin. Each |
@@ -49,11 +48,6 @@ | |||
49 | * There are also two LED pins used sometimes as output-only GPIOs. | 48 | * There are also two LED pins used sometimes as output-only GPIOs. |
50 | */ | 49 | */ |
51 | 50 | ||
52 | |||
53 | static struct gpio_chip twl_gpiochip; | ||
54 | static int twl4030_gpio_base; | ||
55 | static int twl4030_gpio_irq_base; | ||
56 | |||
57 | /* genirq interfaces are not available to modules */ | 51 | /* genirq interfaces are not available to modules */ |
58 | #ifdef MODULE | 52 | #ifdef MODULE |
59 | #define is_module() true | 53 | #define is_module() true |
@@ -69,14 +63,24 @@ static int twl4030_gpio_irq_base; | |||
69 | /* Mask for GPIO registers when aggregated into a 32-bit integer */ | 63 | /* Mask for GPIO registers when aggregated into a 32-bit integer */ |
70 | #define GPIO_32_MASK 0x0003ffff | 64 | #define GPIO_32_MASK 0x0003ffff |
71 | 65 | ||
72 | /* Data structures */ | 66 | struct gpio_twl4030_priv { |
73 | static DEFINE_MUTEX(gpio_lock); | 67 | struct gpio_chip gpio_chip; |
68 | struct mutex mutex; | ||
69 | int irq_base; | ||
74 | 70 | ||
75 | /* store usage of each GPIO. - each bit represents one GPIO */ | 71 | /* Bitfields for state caching */ |
76 | static unsigned int gpio_usage_count; | 72 | unsigned int usage_count; |
73 | unsigned int direction; | ||
74 | unsigned int out_state; | ||
75 | }; | ||
77 | 76 | ||
78 | /*----------------------------------------------------------------------*/ | 77 | /*----------------------------------------------------------------------*/ |
79 | 78 | ||
79 | static inline struct gpio_twl4030_priv *to_gpio_twl4030(struct gpio_chip *chip) | ||
80 | { | ||
81 | return container_of(chip, struct gpio_twl4030_priv, gpio_chip); | ||
82 | } | ||
83 | |||
80 | /* | 84 | /* |
81 | * To configure TWL4030 GPIO module registers | 85 | * To configure TWL4030 GPIO module registers |
82 | */ | 86 | */ |
@@ -126,7 +130,7 @@ static inline int gpio_twl4030_read(u8 address) | |||
126 | 130 | ||
127 | /*----------------------------------------------------------------------*/ | 131 | /*----------------------------------------------------------------------*/ |
128 | 132 | ||
129 | static u8 cached_leden; /* protected by gpio_lock */ | 133 | static u8 cached_leden; |
130 | 134 | ||
131 | /* The LED lines are open drain outputs ... a FET pulls to GND, so an | 135 | /* The LED lines are open drain outputs ... a FET pulls to GND, so an |
132 | * external pullup is needed. We could also expose the integrated PWM | 136 | * external pullup is needed. We could also expose the integrated PWM |
@@ -140,14 +144,12 @@ static void twl4030_led_set_value(int led, int value) | |||
140 | if (led) | 144 | if (led) |
141 | mask <<= 1; | 145 | mask <<= 1; |
142 | 146 | ||
143 | mutex_lock(&gpio_lock); | ||
144 | if (value) | 147 | if (value) |
145 | cached_leden &= ~mask; | 148 | cached_leden &= ~mask; |
146 | else | 149 | else |
147 | cached_leden |= mask; | 150 | cached_leden |= mask; |
148 | status = twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden, | 151 | status = twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden, |
149 | TWL4030_LED_LEDEN_REG); | 152 | TWL4030_LED_LEDEN_REG); |
150 | mutex_unlock(&gpio_lock); | ||
151 | } | 153 | } |
152 | 154 | ||
153 | static int twl4030_set_gpio_direction(int gpio, int is_input) | 155 | static int twl4030_set_gpio_direction(int gpio, int is_input) |
@@ -158,7 +160,6 @@ static int twl4030_set_gpio_direction(int gpio, int is_input) | |||
158 | u8 base = REG_GPIODATADIR1 + d_bnk; | 160 | u8 base = REG_GPIODATADIR1 + d_bnk; |
159 | int ret = 0; | 161 | int ret = 0; |
160 | 162 | ||
161 | mutex_lock(&gpio_lock); | ||
162 | ret = gpio_twl4030_read(base); | 163 | ret = gpio_twl4030_read(base); |
163 | if (ret >= 0) { | 164 | if (ret >= 0) { |
164 | if (is_input) | 165 | if (is_input) |
@@ -168,7 +169,6 @@ static int twl4030_set_gpio_direction(int gpio, int is_input) | |||
168 | 169 | ||
169 | ret = gpio_twl4030_write(base, reg); | 170 | ret = gpio_twl4030_write(base, reg); |
170 | } | 171 | } |
171 | mutex_unlock(&gpio_lock); | ||
172 | return ret; | 172 | return ret; |
173 | } | 173 | } |
174 | 174 | ||
@@ -193,10 +193,6 @@ static int twl4030_get_gpio_datain(int gpio) | |||
193 | u8 base = 0; | 193 | u8 base = 0; |
194 | int ret = 0; | 194 | int ret = 0; |
195 | 195 | ||
196 | if (unlikely((gpio >= TWL4030_GPIO_MAX) | ||
197 | || !(gpio_usage_count & BIT(gpio)))) | ||
198 | return -EPERM; | ||
199 | |||
200 | base = REG_GPIODATAIN1 + d_bnk; | 196 | base = REG_GPIODATAIN1 + d_bnk; |
201 | ret = gpio_twl4030_read(base); | 197 | ret = gpio_twl4030_read(base); |
202 | if (ret > 0) | 198 | if (ret > 0) |
@@ -209,9 +205,10 @@ static int twl4030_get_gpio_datain(int gpio) | |||
209 | 205 | ||
210 | static int twl_request(struct gpio_chip *chip, unsigned offset) | 206 | static int twl_request(struct gpio_chip *chip, unsigned offset) |
211 | { | 207 | { |
208 | struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); | ||
212 | int status = 0; | 209 | int status = 0; |
213 | 210 | ||
214 | mutex_lock(&gpio_lock); | 211 | mutex_lock(&priv->mutex); |
215 | 212 | ||
216 | /* Support the two LED outputs as output-only GPIOs. */ | 213 | /* Support the two LED outputs as output-only GPIOs. */ |
217 | if (offset >= TWL4030_GPIO_MAX) { | 214 | if (offset >= TWL4030_GPIO_MAX) { |
@@ -252,7 +249,7 @@ static int twl_request(struct gpio_chip *chip, unsigned offset) | |||
252 | } | 249 | } |
253 | 250 | ||
254 | /* on first use, turn GPIO module "on" */ | 251 | /* on first use, turn GPIO module "on" */ |
255 | if (!gpio_usage_count) { | 252 | if (!priv->usage_count) { |
256 | struct twl4030_gpio_platform_data *pdata; | 253 | struct twl4030_gpio_platform_data *pdata; |
257 | u8 value = MASK_GPIO_CTRL_GPIO_ON; | 254 | u8 value = MASK_GPIO_CTRL_GPIO_ON; |
258 | 255 | ||
@@ -266,79 +263,120 @@ static int twl_request(struct gpio_chip *chip, unsigned offset) | |||
266 | status = gpio_twl4030_write(REG_GPIO_CTRL, value); | 263 | status = gpio_twl4030_write(REG_GPIO_CTRL, value); |
267 | } | 264 | } |
268 | 265 | ||
266 | done: | ||
269 | if (!status) | 267 | if (!status) |
270 | gpio_usage_count |= (0x1 << offset); | 268 | priv->usage_count |= BIT(offset); |
271 | 269 | ||
272 | done: | 270 | mutex_unlock(&priv->mutex); |
273 | mutex_unlock(&gpio_lock); | ||
274 | return status; | 271 | return status; |
275 | } | 272 | } |
276 | 273 | ||
277 | static void twl_free(struct gpio_chip *chip, unsigned offset) | 274 | static void twl_free(struct gpio_chip *chip, unsigned offset) |
278 | { | 275 | { |
276 | struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); | ||
277 | |||
278 | mutex_lock(&priv->mutex); | ||
279 | if (offset >= TWL4030_GPIO_MAX) { | 279 | if (offset >= TWL4030_GPIO_MAX) { |
280 | twl4030_led_set_value(offset - TWL4030_GPIO_MAX, 1); | 280 | twl4030_led_set_value(offset - TWL4030_GPIO_MAX, 1); |
281 | return; | 281 | goto out; |
282 | } | 282 | } |
283 | 283 | ||
284 | mutex_lock(&gpio_lock); | 284 | priv->usage_count &= ~BIT(offset); |
285 | |||
286 | gpio_usage_count &= ~BIT(offset); | ||
287 | 285 | ||
288 | /* on last use, switch off GPIO module */ | 286 | /* on last use, switch off GPIO module */ |
289 | if (!gpio_usage_count) | 287 | if (!priv->usage_count) |
290 | gpio_twl4030_write(REG_GPIO_CTRL, 0x0); | 288 | gpio_twl4030_write(REG_GPIO_CTRL, 0x0); |
291 | 289 | ||
292 | mutex_unlock(&gpio_lock); | 290 | out: |
291 | mutex_unlock(&priv->mutex); | ||
293 | } | 292 | } |
294 | 293 | ||
295 | static int twl_direction_in(struct gpio_chip *chip, unsigned offset) | 294 | static int twl_direction_in(struct gpio_chip *chip, unsigned offset) |
296 | { | 295 | { |
297 | return (offset < TWL4030_GPIO_MAX) | 296 | struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); |
298 | ? twl4030_set_gpio_direction(offset, 1) | 297 | int ret; |
299 | : -EINVAL; | 298 | |
299 | mutex_lock(&priv->mutex); | ||
300 | if (offset < TWL4030_GPIO_MAX) | ||
301 | ret = twl4030_set_gpio_direction(offset, 1); | ||
302 | else | ||
303 | ret = -EINVAL; | ||
304 | |||
305 | if (!ret) | ||
306 | priv->direction &= ~BIT(offset); | ||
307 | |||
308 | mutex_unlock(&priv->mutex); | ||
309 | |||
310 | return ret; | ||
300 | } | 311 | } |
301 | 312 | ||
302 | static int twl_get(struct gpio_chip *chip, unsigned offset) | 313 | static int twl_get(struct gpio_chip *chip, unsigned offset) |
303 | { | 314 | { |
315 | struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); | ||
316 | int ret; | ||
304 | int status = 0; | 317 | int status = 0; |
305 | 318 | ||
306 | if (offset < TWL4030_GPIO_MAX) | 319 | mutex_lock(&priv->mutex); |
307 | status = twl4030_get_gpio_datain(offset); | 320 | if (!(priv->usage_count & BIT(offset))) { |
308 | else if (offset == TWL4030_GPIO_MAX) | 321 | ret = -EPERM; |
309 | status = cached_leden & LEDEN_LEDAON; | 322 | goto out; |
323 | } | ||
324 | |||
325 | if (priv->direction & BIT(offset)) | ||
326 | status = priv->out_state & BIT(offset); | ||
310 | else | 327 | else |
311 | status = cached_leden & LEDEN_LEDBON; | 328 | status = twl4030_get_gpio_datain(offset); |
312 | return (status < 0) ? 0 : status; | 329 | |
330 | ret = (status <= 0) ? 0 : 1; | ||
331 | out: | ||
332 | mutex_unlock(&priv->mutex); | ||
333 | return ret; | ||
313 | } | 334 | } |
314 | 335 | ||
315 | static int twl_direction_out(struct gpio_chip *chip, unsigned offset, int value) | 336 | static void twl_set(struct gpio_chip *chip, unsigned offset, int value) |
316 | { | 337 | { |
317 | if (offset < TWL4030_GPIO_MAX) { | 338 | struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); |
339 | |||
340 | mutex_lock(&priv->mutex); | ||
341 | if (offset < TWL4030_GPIO_MAX) | ||
318 | twl4030_set_gpio_dataout(offset, value); | 342 | twl4030_set_gpio_dataout(offset, value); |
319 | return twl4030_set_gpio_direction(offset, 0); | 343 | else |
320 | } else { | ||
321 | twl4030_led_set_value(offset - TWL4030_GPIO_MAX, value); | 344 | twl4030_led_set_value(offset - TWL4030_GPIO_MAX, value); |
322 | return 0; | 345 | |
323 | } | 346 | if (value) |
347 | priv->out_state |= BIT(offset); | ||
348 | else | ||
349 | priv->out_state &= ~BIT(offset); | ||
350 | |||
351 | mutex_unlock(&priv->mutex); | ||
324 | } | 352 | } |
325 | 353 | ||
326 | static void twl_set(struct gpio_chip *chip, unsigned offset, int value) | 354 | static int twl_direction_out(struct gpio_chip *chip, unsigned offset, int value) |
327 | { | 355 | { |
356 | struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); | ||
357 | |||
358 | mutex_lock(&priv->mutex); | ||
328 | if (offset < TWL4030_GPIO_MAX) | 359 | if (offset < TWL4030_GPIO_MAX) |
329 | twl4030_set_gpio_dataout(offset, value); | 360 | twl4030_set_gpio_dataout(offset, value); |
330 | else | 361 | |
331 | twl4030_led_set_value(offset - TWL4030_GPIO_MAX, value); | 362 | priv->direction |= BIT(offset); |
363 | mutex_unlock(&priv->mutex); | ||
364 | |||
365 | twl_set(chip, offset, value); | ||
366 | |||
367 | return 0; | ||
332 | } | 368 | } |
333 | 369 | ||
334 | static int twl_to_irq(struct gpio_chip *chip, unsigned offset) | 370 | static int twl_to_irq(struct gpio_chip *chip, unsigned offset) |
335 | { | 371 | { |
336 | return (twl4030_gpio_irq_base && (offset < TWL4030_GPIO_MAX)) | 372 | struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); |
337 | ? (twl4030_gpio_irq_base + offset) | 373 | |
374 | return (priv->irq_base && (offset < TWL4030_GPIO_MAX)) | ||
375 | ? (priv->irq_base + offset) | ||
338 | : -EINVAL; | 376 | : -EINVAL; |
339 | } | 377 | } |
340 | 378 | ||
341 | static struct gpio_chip twl_gpiochip = { | 379 | static struct gpio_chip template_chip = { |
342 | .label = "twl4030", | 380 | .label = "twl4030", |
343 | .owner = THIS_MODULE, | 381 | .owner = THIS_MODULE, |
344 | .request = twl_request, | 382 | .request = twl_request, |
@@ -424,8 +462,14 @@ static int gpio_twl4030_probe(struct platform_device *pdev) | |||
424 | { | 462 | { |
425 | struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; | 463 | struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; |
426 | struct device_node *node = pdev->dev.of_node; | 464 | struct device_node *node = pdev->dev.of_node; |
465 | struct gpio_twl4030_priv *priv; | ||
427 | int ret, irq_base; | 466 | int ret, irq_base; |
428 | 467 | ||
468 | priv = devm_kzalloc(&pdev->dev, sizeof(struct gpio_twl4030_priv), | ||
469 | GFP_KERNEL); | ||
470 | if (!priv) | ||
471 | return -ENOMEM; | ||
472 | |||
429 | /* maybe setup IRQs */ | 473 | /* maybe setup IRQs */ |
430 | if (is_module()) { | 474 | if (is_module()) { |
431 | dev_err(&pdev->dev, "can't dispatch IRQs from modules\n"); | 475 | dev_err(&pdev->dev, "can't dispatch IRQs from modules\n"); |
@@ -445,12 +489,15 @@ static int gpio_twl4030_probe(struct platform_device *pdev) | |||
445 | if (ret < 0) | 489 | if (ret < 0) |
446 | return ret; | 490 | return ret; |
447 | 491 | ||
448 | twl4030_gpio_irq_base = irq_base; | 492 | priv->irq_base = irq_base; |
449 | 493 | ||
450 | no_irqs: | 494 | no_irqs: |
451 | twl_gpiochip.base = -1; | 495 | priv->gpio_chip = template_chip; |
452 | twl_gpiochip.ngpio = TWL4030_GPIO_MAX; | 496 | priv->gpio_chip.base = -1; |
453 | twl_gpiochip.dev = &pdev->dev; | 497 | priv->gpio_chip.ngpio = TWL4030_GPIO_MAX; |
498 | priv->gpio_chip.dev = &pdev->dev; | ||
499 | |||
500 | mutex_init(&priv->mutex); | ||
454 | 501 | ||
455 | if (node) | 502 | if (node) |
456 | pdata = of_gpio_twl4030(&pdev->dev); | 503 | pdata = of_gpio_twl4030(&pdev->dev); |
@@ -481,23 +528,23 @@ no_irqs: | |||
481 | * is (still) clear if use_leds is set. | 528 | * is (still) clear if use_leds is set. |
482 | */ | 529 | */ |
483 | if (pdata->use_leds) | 530 | if (pdata->use_leds) |
484 | twl_gpiochip.ngpio += 2; | 531 | priv->gpio_chip.ngpio += 2; |
485 | 532 | ||
486 | ret = gpiochip_add(&twl_gpiochip); | 533 | ret = gpiochip_add(&priv->gpio_chip); |
487 | if (ret < 0) { | 534 | if (ret < 0) { |
488 | dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret); | 535 | dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret); |
489 | twl_gpiochip.ngpio = 0; | 536 | priv->gpio_chip.ngpio = 0; |
490 | gpio_twl4030_remove(pdev); | 537 | gpio_twl4030_remove(pdev); |
491 | goto out; | 538 | goto out; |
492 | } | 539 | } |
493 | 540 | ||
494 | twl4030_gpio_base = twl_gpiochip.base; | 541 | platform_set_drvdata(pdev, priv); |
495 | 542 | ||
496 | if (pdata && pdata->setup) { | 543 | if (pdata && pdata->setup) { |
497 | int status; | 544 | int status; |
498 | 545 | ||
499 | status = pdata->setup(&pdev->dev, | 546 | status = pdata->setup(&pdev->dev, priv->gpio_chip.base, |
500 | twl4030_gpio_base, TWL4030_GPIO_MAX); | 547 | TWL4030_GPIO_MAX); |
501 | if (status) | 548 | if (status) |
502 | dev_dbg(&pdev->dev, "setup --> %d\n", status); | 549 | dev_dbg(&pdev->dev, "setup --> %d\n", status); |
503 | } | 550 | } |
@@ -510,18 +557,19 @@ out: | |||
510 | static int gpio_twl4030_remove(struct platform_device *pdev) | 557 | static int gpio_twl4030_remove(struct platform_device *pdev) |
511 | { | 558 | { |
512 | struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; | 559 | struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; |
560 | struct gpio_twl4030_priv *priv = platform_get_drvdata(pdev); | ||
513 | int status; | 561 | int status; |
514 | 562 | ||
515 | if (pdata && pdata->teardown) { | 563 | if (pdata && pdata->teardown) { |
516 | status = pdata->teardown(&pdev->dev, | 564 | status = pdata->teardown(&pdev->dev, priv->gpio_chip.base, |
517 | twl4030_gpio_base, TWL4030_GPIO_MAX); | 565 | TWL4030_GPIO_MAX); |
518 | if (status) { | 566 | if (status) { |
519 | dev_dbg(&pdev->dev, "teardown --> %d\n", status); | 567 | dev_dbg(&pdev->dev, "teardown --> %d\n", status); |
520 | return status; | 568 | return status; |
521 | } | 569 | } |
522 | } | 570 | } |
523 | 571 | ||
524 | status = gpiochip_remove(&twl_gpiochip); | 572 | status = gpiochip_remove(&priv->gpio_chip); |
525 | if (status < 0) | 573 | if (status < 0) |
526 | return status; | 574 | return status; |
527 | 575 | ||