diff options
author | Peter Ujfalusi <peter.ujfalusi@ti.com> | 2012-12-06 05:52:05 -0500 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2013-01-17 05:48:12 -0500 |
commit | 72c7901ef00925c6d0cc7ab69183a684908303bc (patch) | |
tree | d99f93adf4a49c754343c1a47dc0e41f14e68567 /drivers/gpio/gpio-twl4030.c | |
parent | ebe5a0596f2ee4182dc42b39583be71e81aa0443 (diff) |
gpio: twl4030: Introduce private structure to store variables needed runtime
Move most of the global variables inside a private structure and allocate
it dynamically.
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio/gpio-twl4030.c')
-rw-r--r-- | drivers/gpio/gpio-twl4030.c | 82 |
1 files changed, 50 insertions, 32 deletions
diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index 9572aa137e6f..4643f9cd0cae 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c | |||
@@ -49,11 +49,6 @@ | |||
49 | * There are also two LED pins used sometimes as output-only GPIOs. | 49 | * There are also two LED pins used sometimes as output-only GPIOs. |
50 | */ | 50 | */ |
51 | 51 | ||
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 */ | 52 | /* genirq interfaces are not available to modules */ |
58 | #ifdef MODULE | 53 | #ifdef MODULE |
59 | #define is_module() true | 54 | #define is_module() true |
@@ -72,11 +67,20 @@ static int twl4030_gpio_irq_base; | |||
72 | /* Data structures */ | 67 | /* Data structures */ |
73 | static DEFINE_MUTEX(gpio_lock); | 68 | static DEFINE_MUTEX(gpio_lock); |
74 | 69 | ||
75 | /* store usage of each GPIO. - each bit represents one GPIO */ | 70 | struct gpio_twl4030_priv { |
76 | static unsigned int gpio_usage_count; | 71 | struct gpio_chip gpio_chip; |
72 | int irq_base; | ||
73 | |||
74 | unsigned int usage_count; | ||
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 | */ |
@@ -193,10 +197,6 @@ static int twl4030_get_gpio_datain(int gpio) | |||
193 | u8 base = 0; | 197 | u8 base = 0; |
194 | int ret = 0; | 198 | int ret = 0; |
195 | 199 | ||
196 | if (unlikely((gpio >= TWL4030_GPIO_MAX) | ||
197 | || !(gpio_usage_count & BIT(gpio)))) | ||
198 | return -EPERM; | ||
199 | |||
200 | base = REG_GPIODATAIN1 + d_bnk; | 200 | base = REG_GPIODATAIN1 + d_bnk; |
201 | ret = gpio_twl4030_read(base); | 201 | ret = gpio_twl4030_read(base); |
202 | if (ret > 0) | 202 | if (ret > 0) |
@@ -209,6 +209,7 @@ static int twl4030_get_gpio_datain(int gpio) | |||
209 | 209 | ||
210 | static int twl_request(struct gpio_chip *chip, unsigned offset) | 210 | static int twl_request(struct gpio_chip *chip, unsigned offset) |
211 | { | 211 | { |
212 | struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); | ||
212 | int status = 0; | 213 | int status = 0; |
213 | 214 | ||
214 | mutex_lock(&gpio_lock); | 215 | mutex_lock(&gpio_lock); |
@@ -252,7 +253,7 @@ static int twl_request(struct gpio_chip *chip, unsigned offset) | |||
252 | } | 253 | } |
253 | 254 | ||
254 | /* on first use, turn GPIO module "on" */ | 255 | /* on first use, turn GPIO module "on" */ |
255 | if (!gpio_usage_count) { | 256 | if (!priv->usage_count) { |
256 | struct twl4030_gpio_platform_data *pdata; | 257 | struct twl4030_gpio_platform_data *pdata; |
257 | u8 value = MASK_GPIO_CTRL_GPIO_ON; | 258 | u8 value = MASK_GPIO_CTRL_GPIO_ON; |
258 | 259 | ||
@@ -266,16 +267,18 @@ static int twl_request(struct gpio_chip *chip, unsigned offset) | |||
266 | status = gpio_twl4030_write(REG_GPIO_CTRL, value); | 267 | status = gpio_twl4030_write(REG_GPIO_CTRL, value); |
267 | } | 268 | } |
268 | 269 | ||
270 | done: | ||
269 | if (!status) | 271 | if (!status) |
270 | gpio_usage_count |= (0x1 << offset); | 272 | priv->usage_count |= BIT(offset); |
271 | 273 | ||
272 | done: | ||
273 | mutex_unlock(&gpio_lock); | 274 | mutex_unlock(&gpio_lock); |
274 | return status; | 275 | return status; |
275 | } | 276 | } |
276 | 277 | ||
277 | static void twl_free(struct gpio_chip *chip, unsigned offset) | 278 | static void twl_free(struct gpio_chip *chip, unsigned offset) |
278 | { | 279 | { |
280 | struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); | ||
281 | |||
279 | if (offset >= TWL4030_GPIO_MAX) { | 282 | if (offset >= TWL4030_GPIO_MAX) { |
280 | twl4030_led_set_value(offset - TWL4030_GPIO_MAX, 1); | 283 | twl4030_led_set_value(offset - TWL4030_GPIO_MAX, 1); |
281 | return; | 284 | return; |
@@ -283,10 +286,10 @@ static void twl_free(struct gpio_chip *chip, unsigned offset) | |||
283 | 286 | ||
284 | mutex_lock(&gpio_lock); | 287 | mutex_lock(&gpio_lock); |
285 | 288 | ||
286 | gpio_usage_count &= ~BIT(offset); | 289 | priv->usage_count &= ~BIT(offset); |
287 | 290 | ||
288 | /* on last use, switch off GPIO module */ | 291 | /* on last use, switch off GPIO module */ |
289 | if (!gpio_usage_count) | 292 | if (!priv->usage_count) |
290 | gpio_twl4030_write(REG_GPIO_CTRL, 0x0); | 293 | gpio_twl4030_write(REG_GPIO_CTRL, 0x0); |
291 | 294 | ||
292 | mutex_unlock(&gpio_lock); | 295 | mutex_unlock(&gpio_lock); |
@@ -301,14 +304,19 @@ static int twl_direction_in(struct gpio_chip *chip, unsigned offset) | |||
301 | 304 | ||
302 | static int twl_get(struct gpio_chip *chip, unsigned offset) | 305 | static int twl_get(struct gpio_chip *chip, unsigned offset) |
303 | { | 306 | { |
307 | struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); | ||
304 | int status = 0; | 308 | int status = 0; |
305 | 309 | ||
310 | if (!(priv->usage_count & BIT(offset))) | ||
311 | return -EPERM; | ||
312 | |||
306 | if (offset < TWL4030_GPIO_MAX) | 313 | if (offset < TWL4030_GPIO_MAX) |
307 | status = twl4030_get_gpio_datain(offset); | 314 | status = twl4030_get_gpio_datain(offset); |
308 | else if (offset == TWL4030_GPIO_MAX) | 315 | else if (offset == TWL4030_GPIO_MAX) |
309 | status = cached_leden & LEDEN_LEDAON; | 316 | status = cached_leden & LEDEN_LEDAON; |
310 | else | 317 | else |
311 | status = cached_leden & LEDEN_LEDBON; | 318 | status = cached_leden & LEDEN_LEDBON; |
319 | |||
312 | return (status < 0) ? 0 : status; | 320 | return (status < 0) ? 0 : status; |
313 | } | 321 | } |
314 | 322 | ||
@@ -333,12 +341,14 @@ static void twl_set(struct gpio_chip *chip, unsigned offset, int value) | |||
333 | 341 | ||
334 | static int twl_to_irq(struct gpio_chip *chip, unsigned offset) | 342 | static int twl_to_irq(struct gpio_chip *chip, unsigned offset) |
335 | { | 343 | { |
336 | return (twl4030_gpio_irq_base && (offset < TWL4030_GPIO_MAX)) | 344 | struct gpio_twl4030_priv *priv = to_gpio_twl4030(chip); |
337 | ? (twl4030_gpio_irq_base + offset) | 345 | |
346 | return (priv->irq_base && (offset < TWL4030_GPIO_MAX)) | ||
347 | ? (priv->irq_base + offset) | ||
338 | : -EINVAL; | 348 | : -EINVAL; |
339 | } | 349 | } |
340 | 350 | ||
341 | static struct gpio_chip twl_gpiochip = { | 351 | static struct gpio_chip template_chip = { |
342 | .label = "twl4030", | 352 | .label = "twl4030", |
343 | .owner = THIS_MODULE, | 353 | .owner = THIS_MODULE, |
344 | .request = twl_request, | 354 | .request = twl_request, |
@@ -424,8 +434,14 @@ static int gpio_twl4030_probe(struct platform_device *pdev) | |||
424 | { | 434 | { |
425 | struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; | 435 | struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; |
426 | struct device_node *node = pdev->dev.of_node; | 436 | struct device_node *node = pdev->dev.of_node; |
437 | struct gpio_twl4030_priv *priv; | ||
427 | int ret, irq_base; | 438 | int ret, irq_base; |
428 | 439 | ||
440 | priv = devm_kzalloc(&pdev->dev, sizeof(struct gpio_twl4030_priv), | ||
441 | GFP_KERNEL); | ||
442 | if (!priv) | ||
443 | return -ENOMEM; | ||
444 | |||
429 | /* maybe setup IRQs */ | 445 | /* maybe setup IRQs */ |
430 | if (is_module()) { | 446 | if (is_module()) { |
431 | dev_err(&pdev->dev, "can't dispatch IRQs from modules\n"); | 447 | dev_err(&pdev->dev, "can't dispatch IRQs from modules\n"); |
@@ -445,12 +461,13 @@ static int gpio_twl4030_probe(struct platform_device *pdev) | |||
445 | if (ret < 0) | 461 | if (ret < 0) |
446 | return ret; | 462 | return ret; |
447 | 463 | ||
448 | twl4030_gpio_irq_base = irq_base; | 464 | priv->irq_base = irq_base; |
449 | 465 | ||
450 | no_irqs: | 466 | no_irqs: |
451 | twl_gpiochip.base = -1; | 467 | priv->gpio_chip = template_chip; |
452 | twl_gpiochip.ngpio = TWL4030_GPIO_MAX; | 468 | priv->gpio_chip.base = -1; |
453 | twl_gpiochip.dev = &pdev->dev; | 469 | priv->gpio_chip.ngpio = TWL4030_GPIO_MAX; |
470 | priv->gpio_chip.dev = &pdev->dev; | ||
454 | 471 | ||
455 | if (node) | 472 | if (node) |
456 | pdata = of_gpio_twl4030(&pdev->dev); | 473 | pdata = of_gpio_twl4030(&pdev->dev); |
@@ -481,23 +498,23 @@ no_irqs: | |||
481 | * is (still) clear if use_leds is set. | 498 | * is (still) clear if use_leds is set. |
482 | */ | 499 | */ |
483 | if (pdata->use_leds) | 500 | if (pdata->use_leds) |
484 | twl_gpiochip.ngpio += 2; | 501 | priv->gpio_chip.ngpio += 2; |
485 | 502 | ||
486 | ret = gpiochip_add(&twl_gpiochip); | 503 | ret = gpiochip_add(&priv->gpio_chip); |
487 | if (ret < 0) { | 504 | if (ret < 0) { |
488 | dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret); | 505 | dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret); |
489 | twl_gpiochip.ngpio = 0; | 506 | priv->gpio_chip.ngpio = 0; |
490 | gpio_twl4030_remove(pdev); | 507 | gpio_twl4030_remove(pdev); |
491 | goto out; | 508 | goto out; |
492 | } | 509 | } |
493 | 510 | ||
494 | twl4030_gpio_base = twl_gpiochip.base; | 511 | platform_set_drvdata(pdev, priv); |
495 | 512 | ||
496 | if (pdata && pdata->setup) { | 513 | if (pdata && pdata->setup) { |
497 | int status; | 514 | int status; |
498 | 515 | ||
499 | status = pdata->setup(&pdev->dev, | 516 | status = pdata->setup(&pdev->dev, priv->gpio_chip.base, |
500 | twl4030_gpio_base, TWL4030_GPIO_MAX); | 517 | TWL4030_GPIO_MAX); |
501 | if (status) | 518 | if (status) |
502 | dev_dbg(&pdev->dev, "setup --> %d\n", status); | 519 | dev_dbg(&pdev->dev, "setup --> %d\n", status); |
503 | } | 520 | } |
@@ -510,18 +527,19 @@ out: | |||
510 | static int gpio_twl4030_remove(struct platform_device *pdev) | 527 | static int gpio_twl4030_remove(struct platform_device *pdev) |
511 | { | 528 | { |
512 | struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; | 529 | struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; |
530 | struct gpio_twl4030_priv *priv = platform_get_drvdata(pdev); | ||
513 | int status; | 531 | int status; |
514 | 532 | ||
515 | if (pdata && pdata->teardown) { | 533 | if (pdata && pdata->teardown) { |
516 | status = pdata->teardown(&pdev->dev, | 534 | status = pdata->teardown(&pdev->dev, priv->gpio_chip.base, |
517 | twl4030_gpio_base, TWL4030_GPIO_MAX); | 535 | TWL4030_GPIO_MAX); |
518 | if (status) { | 536 | if (status) { |
519 | dev_dbg(&pdev->dev, "teardown --> %d\n", status); | 537 | dev_dbg(&pdev->dev, "teardown --> %d\n", status); |
520 | return status; | 538 | return status; |
521 | } | 539 | } |
522 | } | 540 | } |
523 | 541 | ||
524 | status = gpiochip_remove(&twl_gpiochip); | 542 | status = gpiochip_remove(&priv->gpio_chip); |
525 | if (status < 0) | 543 | if (status < 0) |
526 | return status; | 544 | return status; |
527 | 545 | ||