diff options
author | Mika Westerberg <mika.westerberg@linux.intel.com> | 2018-09-18 11:36:21 -0400 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2018-09-20 11:21:52 -0400 |
commit | 96147db1e1dff83679e71ac92193cbcab761a14c (patch) | |
tree | fae535aee78745d578e851c541c611389c11a5cf /drivers | |
parent | 8e2aac333785f91ff74e219a1e78e6bdc1ef2c41 (diff) |
pinctrl: intel: Do pin translation in other GPIO operations as well
For some reason I thought GPIOLIB handles translation from GPIO ranges
to pinctrl pins but it turns out not to be the case. This means that
when GPIOs operations are performed for a pin controller having a custom
GPIO base such as Cannon Lake and Ice Lake incorrect pin number gets
used internally.
Fix this in the same way we did for lock/unlock IRQ operations and
translate the GPIO number to pin before using it.
Fixes: a60eac3239f0 ("pinctrl: intel: Allow custom GPIO base for pad groups")
Reported-by: Rajat Jain <rajatja@google.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Tested-by: Rajat Jain <rajatja@google.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/pinctrl/intel/pinctrl-intel.c | 111 |
1 files changed, 63 insertions, 48 deletions
diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c index 62b009b27eda..ec8dafc94694 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.c +++ b/drivers/pinctrl/intel/pinctrl-intel.c | |||
@@ -747,13 +747,63 @@ static const struct pinctrl_desc intel_pinctrl_desc = { | |||
747 | .owner = THIS_MODULE, | 747 | .owner = THIS_MODULE, |
748 | }; | 748 | }; |
749 | 749 | ||
750 | /** | ||
751 | * intel_gpio_to_pin() - Translate from GPIO offset to pin number | ||
752 | * @pctrl: Pinctrl structure | ||
753 | * @offset: GPIO offset from gpiolib | ||
754 | * @commmunity: Community is filled here if not %NULL | ||
755 | * @padgrp: Pad group is filled here if not %NULL | ||
756 | * | ||
757 | * When coming through gpiolib irqchip, the GPIO offset is not | ||
758 | * automatically translated to pinctrl pin number. This function can be | ||
759 | * used to find out the corresponding pinctrl pin. | ||
760 | */ | ||
761 | static int intel_gpio_to_pin(struct intel_pinctrl *pctrl, unsigned offset, | ||
762 | const struct intel_community **community, | ||
763 | const struct intel_padgroup **padgrp) | ||
764 | { | ||
765 | int i; | ||
766 | |||
767 | for (i = 0; i < pctrl->ncommunities; i++) { | ||
768 | const struct intel_community *comm = &pctrl->communities[i]; | ||
769 | int j; | ||
770 | |||
771 | for (j = 0; j < comm->ngpps; j++) { | ||
772 | const struct intel_padgroup *pgrp = &comm->gpps[j]; | ||
773 | |||
774 | if (pgrp->gpio_base < 0) | ||
775 | continue; | ||
776 | |||
777 | if (offset >= pgrp->gpio_base && | ||
778 | offset < pgrp->gpio_base + pgrp->size) { | ||
779 | int pin; | ||
780 | |||
781 | pin = pgrp->base + offset - pgrp->gpio_base; | ||
782 | if (community) | ||
783 | *community = comm; | ||
784 | if (padgrp) | ||
785 | *padgrp = pgrp; | ||
786 | |||
787 | return pin; | ||
788 | } | ||
789 | } | ||
790 | } | ||
791 | |||
792 | return -EINVAL; | ||
793 | } | ||
794 | |||
750 | static int intel_gpio_get(struct gpio_chip *chip, unsigned offset) | 795 | static int intel_gpio_get(struct gpio_chip *chip, unsigned offset) |
751 | { | 796 | { |
752 | struct intel_pinctrl *pctrl = gpiochip_get_data(chip); | 797 | struct intel_pinctrl *pctrl = gpiochip_get_data(chip); |
753 | void __iomem *reg; | 798 | void __iomem *reg; |
754 | u32 padcfg0; | 799 | u32 padcfg0; |
800 | int pin; | ||
801 | |||
802 | pin = intel_gpio_to_pin(pctrl, offset, NULL, NULL); | ||
803 | if (pin < 0) | ||
804 | return -EINVAL; | ||
755 | 805 | ||
756 | reg = intel_get_padcfg(pctrl, offset, PADCFG0); | 806 | reg = intel_get_padcfg(pctrl, pin, PADCFG0); |
757 | if (!reg) | 807 | if (!reg) |
758 | return -EINVAL; | 808 | return -EINVAL; |
759 | 809 | ||
@@ -770,8 +820,13 @@ static void intel_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | |||
770 | unsigned long flags; | 820 | unsigned long flags; |
771 | void __iomem *reg; | 821 | void __iomem *reg; |
772 | u32 padcfg0; | 822 | u32 padcfg0; |
823 | int pin; | ||
824 | |||
825 | pin = intel_gpio_to_pin(pctrl, offset, NULL, NULL); | ||
826 | if (pin < 0) | ||
827 | return; | ||
773 | 828 | ||
774 | reg = intel_get_padcfg(pctrl, offset, PADCFG0); | 829 | reg = intel_get_padcfg(pctrl, pin, PADCFG0); |
775 | if (!reg) | 830 | if (!reg) |
776 | return; | 831 | return; |
777 | 832 | ||
@@ -790,8 +845,13 @@ static int intel_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) | |||
790 | struct intel_pinctrl *pctrl = gpiochip_get_data(chip); | 845 | struct intel_pinctrl *pctrl = gpiochip_get_data(chip); |
791 | void __iomem *reg; | 846 | void __iomem *reg; |
792 | u32 padcfg0; | 847 | u32 padcfg0; |
848 | int pin; | ||
793 | 849 | ||
794 | reg = intel_get_padcfg(pctrl, offset, PADCFG0); | 850 | pin = intel_gpio_to_pin(pctrl, offset, NULL, NULL); |
851 | if (pin < 0) | ||
852 | return -EINVAL; | ||
853 | |||
854 | reg = intel_get_padcfg(pctrl, pin, PADCFG0); | ||
795 | if (!reg) | 855 | if (!reg) |
796 | return -EINVAL; | 856 | return -EINVAL; |
797 | 857 | ||
@@ -827,51 +887,6 @@ static const struct gpio_chip intel_gpio_chip = { | |||
827 | .set_config = gpiochip_generic_config, | 887 | .set_config = gpiochip_generic_config, |
828 | }; | 888 | }; |
829 | 889 | ||
830 | /** | ||
831 | * intel_gpio_to_pin() - Translate from GPIO offset to pin number | ||
832 | * @pctrl: Pinctrl structure | ||
833 | * @offset: GPIO offset from gpiolib | ||
834 | * @commmunity: Community is filled here if not %NULL | ||
835 | * @padgrp: Pad group is filled here if not %NULL | ||
836 | * | ||
837 | * When coming through gpiolib irqchip, the GPIO offset is not | ||
838 | * automatically translated to pinctrl pin number. This function can be | ||
839 | * used to find out the corresponding pinctrl pin. | ||
840 | */ | ||
841 | static int intel_gpio_to_pin(struct intel_pinctrl *pctrl, unsigned offset, | ||
842 | const struct intel_community **community, | ||
843 | const struct intel_padgroup **padgrp) | ||
844 | { | ||
845 | int i; | ||
846 | |||
847 | for (i = 0; i < pctrl->ncommunities; i++) { | ||
848 | const struct intel_community *comm = &pctrl->communities[i]; | ||
849 | int j; | ||
850 | |||
851 | for (j = 0; j < comm->ngpps; j++) { | ||
852 | const struct intel_padgroup *pgrp = &comm->gpps[j]; | ||
853 | |||
854 | if (pgrp->gpio_base < 0) | ||
855 | continue; | ||
856 | |||
857 | if (offset >= pgrp->gpio_base && | ||
858 | offset < pgrp->gpio_base + pgrp->size) { | ||
859 | int pin; | ||
860 | |||
861 | pin = pgrp->base + offset - pgrp->gpio_base; | ||
862 | if (community) | ||
863 | *community = comm; | ||
864 | if (padgrp) | ||
865 | *padgrp = pgrp; | ||
866 | |||
867 | return pin; | ||
868 | } | ||
869 | } | ||
870 | } | ||
871 | |||
872 | return -EINVAL; | ||
873 | } | ||
874 | |||
875 | static int intel_gpio_irq_reqres(struct irq_data *d) | 890 | static int intel_gpio_irq_reqres(struct irq_data *d) |
876 | { | 891 | { |
877 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); | 892 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |