diff options
| -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 | ||
