diff options
| -rw-r--r-- | drivers/pinctrl/samsung/pinctrl-samsung.c | 48 |
1 files changed, 35 insertions, 13 deletions
diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c index f67b1e958589..5cc97f85db02 100644 --- a/drivers/pinctrl/samsung/pinctrl-samsung.c +++ b/drivers/pinctrl/samsung/pinctrl-samsung.c | |||
| @@ -514,25 +514,35 @@ static const struct pinconf_ops samsung_pinconf_ops = { | |||
| 514 | .pin_config_group_set = samsung_pinconf_group_set, | 514 | .pin_config_group_set = samsung_pinconf_group_set, |
| 515 | }; | 515 | }; |
| 516 | 516 | ||
| 517 | /* gpiolib gpio_set callback function */ | 517 | /* |
| 518 | static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value) | 518 | * The samsung_gpio_set_vlaue() should be called with "bank->slock" held |
| 519 | * to avoid race condition. | ||
| 520 | */ | ||
| 521 | static void samsung_gpio_set_value(struct gpio_chip *gc, | ||
| 522 | unsigned offset, int value) | ||
| 519 | { | 523 | { |
| 520 | struct samsung_pin_bank *bank = gpiochip_get_data(gc); | 524 | struct samsung_pin_bank *bank = gpiochip_get_data(gc); |
| 521 | const struct samsung_pin_bank_type *type = bank->type; | 525 | const struct samsung_pin_bank_type *type = bank->type; |
| 522 | unsigned long flags; | ||
| 523 | void __iomem *reg; | 526 | void __iomem *reg; |
| 524 | u32 data; | 527 | u32 data; |
| 525 | 528 | ||
| 526 | reg = bank->drvdata->virt_base + bank->pctl_offset; | 529 | reg = bank->drvdata->virt_base + bank->pctl_offset; |
| 527 | 530 | ||
| 528 | spin_lock_irqsave(&bank->slock, flags); | ||
| 529 | |||
| 530 | data = readl(reg + type->reg_offset[PINCFG_TYPE_DAT]); | 531 | data = readl(reg + type->reg_offset[PINCFG_TYPE_DAT]); |
| 531 | data &= ~(1 << offset); | 532 | data &= ~(1 << offset); |
| 532 | if (value) | 533 | if (value) |
| 533 | data |= 1 << offset; | 534 | data |= 1 << offset; |
| 534 | writel(data, reg + type->reg_offset[PINCFG_TYPE_DAT]); | 535 | writel(data, reg + type->reg_offset[PINCFG_TYPE_DAT]); |
| 536 | } | ||
| 537 | |||
| 538 | /* gpiolib gpio_set callback function */ | ||
| 539 | static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value) | ||
| 540 | { | ||
| 541 | struct samsung_pin_bank *bank = gpiochip_get_data(gc); | ||
| 542 | unsigned long flags; | ||
| 535 | 543 | ||
| 544 | spin_lock_irqsave(&bank->slock, flags); | ||
| 545 | samsung_gpio_set_value(gc, offset, value); | ||
| 536 | spin_unlock_irqrestore(&bank->slock, flags); | 546 | spin_unlock_irqrestore(&bank->slock, flags); |
| 537 | } | 547 | } |
| 538 | 548 | ||
| @@ -553,6 +563,8 @@ static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset) | |||
| 553 | } | 563 | } |
| 554 | 564 | ||
| 555 | /* | 565 | /* |
| 566 | * The samsung_gpio_set_direction() should be called with "bank->slock" held | ||
| 567 | * to avoid race condition. | ||
| 556 | * The calls to gpio_direction_output() and gpio_direction_input() | 568 | * The calls to gpio_direction_output() and gpio_direction_input() |
| 557 | * leads to this function call. | 569 | * leads to this function call. |
| 558 | */ | 570 | */ |
| @@ -564,7 +576,6 @@ static int samsung_gpio_set_direction(struct gpio_chip *gc, | |||
| 564 | struct samsung_pinctrl_drv_data *drvdata; | 576 | struct samsung_pinctrl_drv_data *drvdata; |
| 565 | void __iomem *reg; | 577 | void __iomem *reg; |
| 566 | u32 data, mask, shift; | 578 | u32 data, mask, shift; |
| 567 | unsigned long flags; | ||
| 568 | 579 | ||
| 569 | bank = gpiochip_get_data(gc); | 580 | bank = gpiochip_get_data(gc); |
| 570 | type = bank->type; | 581 | type = bank->type; |
| @@ -581,31 +592,42 @@ static int samsung_gpio_set_direction(struct gpio_chip *gc, | |||
| 581 | reg += 4; | 592 | reg += 4; |
| 582 | } | 593 | } |
| 583 | 594 | ||
| 584 | spin_lock_irqsave(&bank->slock, flags); | ||
| 585 | |||
| 586 | data = readl(reg); | 595 | data = readl(reg); |
| 587 | data &= ~(mask << shift); | 596 | data &= ~(mask << shift); |
| 588 | if (!input) | 597 | if (!input) |
| 589 | data |= FUNC_OUTPUT << shift; | 598 | data |= FUNC_OUTPUT << shift; |
| 590 | writel(data, reg); | 599 | writel(data, reg); |
| 591 | 600 | ||
| 592 | spin_unlock_irqrestore(&bank->slock, flags); | ||
| 593 | |||
| 594 | return 0; | 601 | return 0; |
| 595 | } | 602 | } |
| 596 | 603 | ||
| 597 | /* gpiolib gpio_direction_input callback function. */ | 604 | /* gpiolib gpio_direction_input callback function. */ |
| 598 | static int samsung_gpio_direction_input(struct gpio_chip *gc, unsigned offset) | 605 | static int samsung_gpio_direction_input(struct gpio_chip *gc, unsigned offset) |
| 599 | { | 606 | { |
| 600 | return samsung_gpio_set_direction(gc, offset, true); | 607 | struct samsung_pin_bank *bank = gpiochip_get_data(gc); |
| 608 | unsigned long flags; | ||
| 609 | int ret; | ||
| 610 | |||
| 611 | spin_lock_irqsave(&bank->slock, flags); | ||
| 612 | ret = samsung_gpio_set_direction(gc, offset, true); | ||
| 613 | spin_unlock_irqrestore(&bank->slock, flags); | ||
| 614 | return ret; | ||
| 601 | } | 615 | } |
| 602 | 616 | ||
| 603 | /* gpiolib gpio_direction_output callback function. */ | 617 | /* gpiolib gpio_direction_output callback function. */ |
| 604 | static int samsung_gpio_direction_output(struct gpio_chip *gc, unsigned offset, | 618 | static int samsung_gpio_direction_output(struct gpio_chip *gc, unsigned offset, |
| 605 | int value) | 619 | int value) |
| 606 | { | 620 | { |
| 607 | samsung_gpio_set(gc, offset, value); | 621 | struct samsung_pin_bank *bank = gpiochip_get_data(gc); |
| 608 | return samsung_gpio_set_direction(gc, offset, false); | 622 | unsigned long flags; |
| 623 | int ret; | ||
| 624 | |||
| 625 | spin_lock_irqsave(&bank->slock, flags); | ||
| 626 | samsung_gpio_set_value(gc, offset, value); | ||
| 627 | ret = samsung_gpio_set_direction(gc, offset, false); | ||
| 628 | spin_unlock_irqrestore(&bank->slock, flags); | ||
| 629 | |||
| 630 | return ret; | ||
| 609 | } | 631 | } |
| 610 | 632 | ||
| 611 | /* | 633 | /* |
