diff options
-rw-r--r-- | drivers/pinctrl/pinctrl-samsung.c | 117 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-samsung.h | 11 |
2 files changed, 79 insertions, 49 deletions
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c index e1ef5d28094d..0a38368edcd3 100644 --- a/drivers/pinctrl/pinctrl-samsung.c +++ b/drivers/pinctrl/pinctrl-samsung.c | |||
@@ -48,6 +48,11 @@ struct pin_config { | |||
48 | 48 | ||
49 | static unsigned int pin_base = 0; | 49 | static unsigned int pin_base = 0; |
50 | 50 | ||
51 | static inline struct samsung_pin_bank *gc_to_pin_bank(struct gpio_chip *gc) | ||
52 | { | ||
53 | return container_of(gc, struct samsung_pin_bank, gpio_chip); | ||
54 | } | ||
55 | |||
51 | /* check if the selector is a valid pin group selector */ | 56 | /* check if the selector is a valid pin group selector */ |
52 | static int samsung_get_group_count(struct pinctrl_dev *pctldev) | 57 | static int samsung_get_group_count(struct pinctrl_dev *pctldev) |
53 | { | 58 | { |
@@ -333,9 +338,12 @@ static int samsung_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, | |||
333 | void __iomem *reg; | 338 | void __iomem *reg; |
334 | u32 data, pin_offset, mask, shift; | 339 | u32 data, pin_offset, mask, shift; |
335 | 340 | ||
341 | bank = gc_to_pin_bank(range->gc); | ||
336 | drvdata = pinctrl_dev_get_drvdata(pctldev); | 342 | drvdata = pinctrl_dev_get_drvdata(pctldev); |
337 | 343 | ||
338 | pin_to_reg_bank(drvdata, offset, ®, &pin_offset, &bank); | 344 | pin_offset = offset - bank->pin_base; |
345 | reg = drvdata->virt_base + bank->pctl_offset; | ||
346 | |||
339 | mask = (1 << bank->func_width) - 1; | 347 | mask = (1 << bank->func_width) - 1; |
340 | shift = pin_offset * bank->func_width; | 348 | shift = pin_offset * bank->func_width; |
341 | 349 | ||
@@ -469,17 +477,16 @@ static struct pinconf_ops samsung_pinconf_ops = { | |||
469 | /* gpiolib gpio_set callback function */ | 477 | /* gpiolib gpio_set callback function */ |
470 | static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value) | 478 | static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value) |
471 | { | 479 | { |
480 | struct samsung_pin_bank *bank = gc_to_pin_bank(gc); | ||
472 | void __iomem *reg; | 481 | void __iomem *reg; |
473 | u32 pin_offset, data; | 482 | u32 data; |
474 | struct samsung_pinctrl_drv_data *drvdata; | ||
475 | 483 | ||
476 | drvdata = dev_get_drvdata(gc->dev); | 484 | reg = bank->drvdata->virt_base + bank->pctl_offset; |
477 | 485 | ||
478 | pin_to_reg_bank(drvdata, offset, ®, &pin_offset, NULL); | ||
479 | data = readl(reg + DAT_REG); | 486 | data = readl(reg + DAT_REG); |
480 | data &= ~(1 << pin_offset); | 487 | data &= ~(1 << offset); |
481 | if (value) | 488 | if (value) |
482 | data |= 1 << pin_offset; | 489 | data |= 1 << offset; |
483 | writel(data, reg + DAT_REG); | 490 | writel(data, reg + DAT_REG); |
484 | } | 491 | } |
485 | 492 | ||
@@ -487,14 +494,13 @@ static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value) | |||
487 | static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset) | 494 | static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset) |
488 | { | 495 | { |
489 | void __iomem *reg; | 496 | void __iomem *reg; |
490 | u32 pin_offset, data; | 497 | u32 data; |
491 | struct samsung_pinctrl_drv_data *drvdata; | 498 | struct samsung_pin_bank *bank = gc_to_pin_bank(gc); |
492 | 499 | ||
493 | drvdata = dev_get_drvdata(gc->dev); | 500 | reg = bank->drvdata->virt_base + bank->pctl_offset; |
494 | 501 | ||
495 | pin_to_reg_bank(drvdata, offset, ®, &pin_offset, NULL); | ||
496 | data = readl(reg + DAT_REG); | 502 | data = readl(reg + DAT_REG); |
497 | data >>= pin_offset; | 503 | data >>= offset; |
498 | data &= 1; | 504 | data &= 1; |
499 | return data; | 505 | return data; |
500 | } | 506 | } |
@@ -724,12 +730,16 @@ static int __init samsung_pinctrl_register(struct platform_device *pdev, | |||
724 | return -EINVAL; | 730 | return -EINVAL; |
725 | } | 731 | } |
726 | 732 | ||
727 | drvdata->grange.name = "samsung-pctrl-gpio-range"; | 733 | for (bank = 0; bank < drvdata->ctrl->nr_banks; ++bank) { |
728 | drvdata->grange.id = 0; | 734 | pin_bank = &drvdata->ctrl->pin_banks[bank]; |
729 | drvdata->grange.base = drvdata->ctrl->base; | 735 | pin_bank->grange.name = pin_bank->name; |
730 | drvdata->grange.npins = drvdata->ctrl->nr_pins; | 736 | pin_bank->grange.id = bank; |
731 | drvdata->grange.gc = drvdata->gc; | 737 | pin_bank->grange.pin_base = pin_bank->pin_base; |
732 | pinctrl_add_gpio_range(drvdata->pctl_dev, &drvdata->grange); | 738 | pin_bank->grange.base = pin_bank->gpio_chip.base; |
739 | pin_bank->grange.npins = pin_bank->gpio_chip.ngpio; | ||
740 | pin_bank->grange.gc = &pin_bank->gpio_chip; | ||
741 | pinctrl_add_gpio_range(drvdata->pctl_dev, &pin_bank->grange); | ||
742 | } | ||
733 | 743 | ||
734 | ret = samsung_pinctrl_parse_dt(pdev, drvdata); | 744 | ret = samsung_pinctrl_parse_dt(pdev, drvdata); |
735 | if (ret) { | 745 | if (ret) { |
@@ -740,49 +750,68 @@ static int __init samsung_pinctrl_register(struct platform_device *pdev, | |||
740 | return 0; | 750 | return 0; |
741 | } | 751 | } |
742 | 752 | ||
753 | static const struct gpio_chip samsung_gpiolib_chip = { | ||
754 | .set = samsung_gpio_set, | ||
755 | .get = samsung_gpio_get, | ||
756 | .direction_input = samsung_gpio_direction_input, | ||
757 | .direction_output = samsung_gpio_direction_output, | ||
758 | .owner = THIS_MODULE, | ||
759 | }; | ||
760 | |||
743 | /* register the gpiolib interface with the gpiolib subsystem */ | 761 | /* register the gpiolib interface with the gpiolib subsystem */ |
744 | static int __init samsung_gpiolib_register(struct platform_device *pdev, | 762 | static int __init samsung_gpiolib_register(struct platform_device *pdev, |
745 | struct samsung_pinctrl_drv_data *drvdata) | 763 | struct samsung_pinctrl_drv_data *drvdata) |
746 | { | 764 | { |
765 | struct samsung_pin_ctrl *ctrl = drvdata->ctrl; | ||
766 | struct samsung_pin_bank *bank = ctrl->pin_banks; | ||
747 | struct gpio_chip *gc; | 767 | struct gpio_chip *gc; |
748 | int ret; | 768 | int ret; |
769 | int i; | ||
749 | 770 | ||
750 | gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL); | 771 | for (i = 0; i < ctrl->nr_banks; ++i, ++bank) { |
751 | if (!gc) { | 772 | bank->gpio_chip = samsung_gpiolib_chip; |
752 | dev_err(&pdev->dev, "mem alloc for gpio_chip failed\n"); | 773 | |
753 | return -ENOMEM; | 774 | gc = &bank->gpio_chip; |
754 | } | 775 | gc->base = ctrl->base + bank->pin_base; |
755 | 776 | gc->ngpio = bank->nr_pins; | |
756 | drvdata->gc = gc; | 777 | gc->dev = &pdev->dev; |
757 | gc->base = drvdata->ctrl->base; | 778 | gc->of_node = bank->of_node; |
758 | gc->ngpio = drvdata->ctrl->nr_pins; | 779 | gc->label = bank->name; |
759 | gc->dev = &pdev->dev; | 780 | |
760 | gc->set = samsung_gpio_set; | 781 | ret = gpiochip_add(gc); |
761 | gc->get = samsung_gpio_get; | 782 | if (ret) { |
762 | gc->direction_input = samsung_gpio_direction_input; | 783 | dev_err(&pdev->dev, "failed to register gpio_chip %s, error code: %d\n", |
763 | gc->direction_output = samsung_gpio_direction_output; | 784 | gc->label, ret); |
764 | gc->label = drvdata->ctrl->label; | 785 | goto fail; |
765 | gc->owner = THIS_MODULE; | 786 | } |
766 | ret = gpiochip_add(gc); | ||
767 | if (ret) { | ||
768 | dev_err(&pdev->dev, "failed to register gpio_chip %s, error " | ||
769 | "code: %d\n", gc->label, ret); | ||
770 | return ret; | ||
771 | } | 787 | } |
772 | 788 | ||
773 | return 0; | 789 | return 0; |
790 | |||
791 | fail: | ||
792 | for (--i, --bank; i >= 0; --i, --bank) | ||
793 | if (gpiochip_remove(&bank->gpio_chip)) | ||
794 | dev_err(&pdev->dev, "gpio chip %s remove failed\n", | ||
795 | bank->gpio_chip.label); | ||
796 | return ret; | ||
774 | } | 797 | } |
775 | 798 | ||
776 | /* unregister the gpiolib interface with the gpiolib subsystem */ | 799 | /* unregister the gpiolib interface with the gpiolib subsystem */ |
777 | static int __init samsung_gpiolib_unregister(struct platform_device *pdev, | 800 | static int __init samsung_gpiolib_unregister(struct platform_device *pdev, |
778 | struct samsung_pinctrl_drv_data *drvdata) | 801 | struct samsung_pinctrl_drv_data *drvdata) |
779 | { | 802 | { |
780 | int ret = gpiochip_remove(drvdata->gc); | 803 | struct samsung_pin_ctrl *ctrl = drvdata->ctrl; |
781 | if (ret) { | 804 | struct samsung_pin_bank *bank = ctrl->pin_banks; |
805 | int ret = 0; | ||
806 | int i; | ||
807 | |||
808 | for (i = 0; !ret && i < ctrl->nr_banks; ++i, ++bank) | ||
809 | ret = gpiochip_remove(&bank->gpio_chip); | ||
810 | |||
811 | if (ret) | ||
782 | dev_err(&pdev->dev, "gpio chip remove failed\n"); | 812 | dev_err(&pdev->dev, "gpio chip remove failed\n"); |
783 | return ret; | 813 | |
784 | } | 814 | return ret; |
785 | return 0; | ||
786 | } | 815 | } |
787 | 816 | ||
788 | static const struct of_device_id samsung_pinctrl_dt_match[]; | 817 | static const struct of_device_id samsung_pinctrl_dt_match[]; |
diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h index e56be22302cd..dac40ffd5e67 100644 --- a/drivers/pinctrl/pinctrl-samsung.h +++ b/drivers/pinctrl/pinctrl-samsung.h | |||
@@ -23,6 +23,8 @@ | |||
23 | #include <linux/pinctrl/consumer.h> | 23 | #include <linux/pinctrl/consumer.h> |
24 | #include <linux/pinctrl/machine.h> | 24 | #include <linux/pinctrl/machine.h> |
25 | 25 | ||
26 | #include <linux/gpio.h> | ||
27 | |||
26 | /* register offsets within a pin bank */ | 28 | /* register offsets within a pin bank */ |
27 | #define DAT_REG 0x4 | 29 | #define DAT_REG 0x4 |
28 | #define PUD_REG 0x8 | 30 | #define PUD_REG 0x8 |
@@ -113,6 +115,8 @@ struct samsung_pinctrl_drv_data; | |||
113 | * @of_node: OF node of the bank. | 115 | * @of_node: OF node of the bank. |
114 | * @drvdata: link to controller driver data | 116 | * @drvdata: link to controller driver data |
115 | * @irq_domain: IRQ domain of the bank. | 117 | * @irq_domain: IRQ domain of the bank. |
118 | * @gpio_chip: GPIO chip of the bank. | ||
119 | * @grange: linux gpio pin range supported by this bank. | ||
116 | */ | 120 | */ |
117 | struct samsung_pin_bank { | 121 | struct samsung_pin_bank { |
118 | u32 pctl_offset; | 122 | u32 pctl_offset; |
@@ -129,6 +133,8 @@ struct samsung_pin_bank { | |||
129 | struct device_node *of_node; | 133 | struct device_node *of_node; |
130 | struct samsung_pinctrl_drv_data *drvdata; | 134 | struct samsung_pinctrl_drv_data *drvdata; |
131 | struct irq_domain *irq_domain; | 135 | struct irq_domain *irq_domain; |
136 | struct gpio_chip gpio_chip; | ||
137 | struct pinctrl_gpio_range grange; | ||
132 | }; | 138 | }; |
133 | 139 | ||
134 | /** | 140 | /** |
@@ -186,8 +192,6 @@ struct samsung_pin_ctrl { | |||
186 | * @nr_groups: number of such pin groups. | 192 | * @nr_groups: number of such pin groups. |
187 | * @pmx_functions: list of pin functions available to the driver. | 193 | * @pmx_functions: list of pin functions available to the driver. |
188 | * @nr_function: number of such pin functions. | 194 | * @nr_function: number of such pin functions. |
189 | * @gc: gpio_chip instance registered with gpiolib. | ||
190 | * @grange: linux gpio pin range supported by this controller. | ||
191 | */ | 195 | */ |
192 | struct samsung_pinctrl_drv_data { | 196 | struct samsung_pinctrl_drv_data { |
193 | void __iomem *virt_base; | 197 | void __iomem *virt_base; |
@@ -204,9 +208,6 @@ struct samsung_pinctrl_drv_data { | |||
204 | unsigned int nr_functions; | 208 | unsigned int nr_functions; |
205 | 209 | ||
206 | struct irq_domain *wkup_irqd; | 210 | struct irq_domain *wkup_irqd; |
207 | |||
208 | struct gpio_chip *gc; | ||
209 | struct pinctrl_gpio_range grange; | ||
210 | }; | 211 | }; |
211 | 212 | ||
212 | /** | 213 | /** |