diff options
author | Kukjin Kim <kgene.kim@samsung.com> | 2012-11-18 20:00:41 -0500 |
---|---|---|
committer | Kukjin Kim <kgene.kim@samsung.com> | 2012-11-18 20:00:41 -0500 |
commit | bab797f8e36a4dd0476eda5197182aeea44e23db (patch) | |
tree | 925ec0c9a0041c4b7b09a5d3a5869d57e45a5da7 /drivers/pinctrl/pinctrl-samsung.c | |
parent | 3d70f8c617a436c7146ecb81df2265b4626dfe89 (diff) | |
parent | b33ef91f4b799a5de5904c4b361df97a0c3ec7dd (diff) |
Merge remote-tracking branch 'pinctrl/samsung' into next/pinctrl-samsung
Diffstat (limited to 'drivers/pinctrl/pinctrl-samsung.c')
-rw-r--r-- | drivers/pinctrl/pinctrl-samsung.c | 203 |
1 files changed, 146 insertions, 57 deletions
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c index 861cd5f04d5e..fc34cac8a1b0 100644 --- a/drivers/pinctrl/pinctrl-samsung.c +++ b/drivers/pinctrl/pinctrl-samsung.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | #include <linux/err.h> | 27 | #include <linux/err.h> |
28 | #include <linux/gpio.h> | 28 | #include <linux/gpio.h> |
29 | #include <linux/irqdomain.h> | ||
29 | 30 | ||
30 | #include "core.h" | 31 | #include "core.h" |
31 | #include "pinctrl-samsung.h" | 32 | #include "pinctrl-samsung.h" |
@@ -46,6 +47,13 @@ struct pin_config { | |||
46 | { "samsung,pin-pud-pdn", PINCFG_TYPE_PUD_PDN }, | 47 | { "samsung,pin-pud-pdn", PINCFG_TYPE_PUD_PDN }, |
47 | }; | 48 | }; |
48 | 49 | ||
50 | static unsigned int pin_base = 0; | ||
51 | |||
52 | static inline struct samsung_pin_bank *gc_to_pin_bank(struct gpio_chip *gc) | ||
53 | { | ||
54 | return container_of(gc, struct samsung_pin_bank, gpio_chip); | ||
55 | } | ||
56 | |||
49 | /* check if the selector is a valid pin group selector */ | 57 | /* check if the selector is a valid pin group selector */ |
50 | static int samsung_get_group_count(struct pinctrl_dev *pctldev) | 58 | static int samsung_get_group_count(struct pinctrl_dev *pctldev) |
51 | { | 59 | { |
@@ -250,14 +258,12 @@ static int samsung_pinmux_get_groups(struct pinctrl_dev *pctldev, | |||
250 | * given a pin number that is local to a pin controller, find out the pin bank | 258 | * given a pin number that is local to a pin controller, find out the pin bank |
251 | * and the register base of the pin bank. | 259 | * and the register base of the pin bank. |
252 | */ | 260 | */ |
253 | static void pin_to_reg_bank(struct gpio_chip *gc, unsigned pin, | 261 | static void pin_to_reg_bank(struct samsung_pinctrl_drv_data *drvdata, |
254 | void __iomem **reg, u32 *offset, | 262 | unsigned pin, void __iomem **reg, u32 *offset, |
255 | struct samsung_pin_bank **bank) | 263 | struct samsung_pin_bank **bank) |
256 | { | 264 | { |
257 | struct samsung_pinctrl_drv_data *drvdata; | ||
258 | struct samsung_pin_bank *b; | 265 | struct samsung_pin_bank *b; |
259 | 266 | ||
260 | drvdata = dev_get_drvdata(gc->dev); | ||
261 | b = drvdata->ctrl->pin_banks; | 267 | b = drvdata->ctrl->pin_banks; |
262 | 268 | ||
263 | while ((pin >= b->pin_base) && | 269 | while ((pin >= b->pin_base) && |
@@ -292,7 +298,7 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector, | |||
292 | * pin function number in the config register. | 298 | * pin function number in the config register. |
293 | */ | 299 | */ |
294 | for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++) { | 300 | for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++) { |
295 | pin_to_reg_bank(drvdata->gc, pins[cnt] - drvdata->ctrl->base, | 301 | pin_to_reg_bank(drvdata, pins[cnt] - drvdata->ctrl->base, |
296 | ®, &pin_offset, &bank); | 302 | ®, &pin_offset, &bank); |
297 | mask = (1 << bank->func_width) - 1; | 303 | mask = (1 << bank->func_width) - 1; |
298 | shift = pin_offset * bank->func_width; | 304 | shift = pin_offset * bank->func_width; |
@@ -329,10 +335,16 @@ static int samsung_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, | |||
329 | struct pinctrl_gpio_range *range, unsigned offset, bool input) | 335 | struct pinctrl_gpio_range *range, unsigned offset, bool input) |
330 | { | 336 | { |
331 | struct samsung_pin_bank *bank; | 337 | struct samsung_pin_bank *bank; |
338 | struct samsung_pinctrl_drv_data *drvdata; | ||
332 | void __iomem *reg; | 339 | void __iomem *reg; |
333 | u32 data, pin_offset, mask, shift; | 340 | u32 data, pin_offset, mask, shift; |
334 | 341 | ||
335 | pin_to_reg_bank(range->gc, offset, ®, &pin_offset, &bank); | 342 | bank = gc_to_pin_bank(range->gc); |
343 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
344 | |||
345 | pin_offset = offset - bank->pin_base; | ||
346 | reg = drvdata->virt_base + bank->pctl_offset; | ||
347 | |||
336 | mask = (1 << bank->func_width) - 1; | 348 | mask = (1 << bank->func_width) - 1; |
337 | shift = pin_offset * bank->func_width; | 349 | shift = pin_offset * bank->func_width; |
338 | 350 | ||
@@ -366,7 +378,7 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin, | |||
366 | u32 cfg_value, cfg_reg; | 378 | u32 cfg_value, cfg_reg; |
367 | 379 | ||
368 | drvdata = pinctrl_dev_get_drvdata(pctldev); | 380 | drvdata = pinctrl_dev_get_drvdata(pctldev); |
369 | pin_to_reg_bank(drvdata->gc, pin - drvdata->ctrl->base, ®_base, | 381 | pin_to_reg_bank(drvdata, pin - drvdata->ctrl->base, ®_base, |
370 | &pin_offset, &bank); | 382 | &pin_offset, &bank); |
371 | 383 | ||
372 | switch (cfg_type) { | 384 | switch (cfg_type) { |
@@ -391,6 +403,9 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin, | |||
391 | return -EINVAL; | 403 | return -EINVAL; |
392 | } | 404 | } |
393 | 405 | ||
406 | if (!width) | ||
407 | return -EINVAL; | ||
408 | |||
394 | mask = (1 << width) - 1; | 409 | mask = (1 << width) - 1; |
395 | shift = pin_offset * width; | 410 | shift = pin_offset * width; |
396 | data = readl(reg_base + cfg_reg); | 411 | data = readl(reg_base + cfg_reg); |
@@ -463,14 +478,16 @@ static struct pinconf_ops samsung_pinconf_ops = { | |||
463 | /* gpiolib gpio_set callback function */ | 478 | /* gpiolib gpio_set callback function */ |
464 | static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value) | 479 | static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value) |
465 | { | 480 | { |
481 | struct samsung_pin_bank *bank = gc_to_pin_bank(gc); | ||
466 | void __iomem *reg; | 482 | void __iomem *reg; |
467 | u32 pin_offset, data; | 483 | u32 data; |
484 | |||
485 | reg = bank->drvdata->virt_base + bank->pctl_offset; | ||
468 | 486 | ||
469 | pin_to_reg_bank(gc, offset, ®, &pin_offset, NULL); | ||
470 | data = readl(reg + DAT_REG); | 487 | data = readl(reg + DAT_REG); |
471 | data &= ~(1 << pin_offset); | 488 | data &= ~(1 << offset); |
472 | if (value) | 489 | if (value) |
473 | data |= 1 << pin_offset; | 490 | data |= 1 << offset; |
474 | writel(data, reg + DAT_REG); | 491 | writel(data, reg + DAT_REG); |
475 | } | 492 | } |
476 | 493 | ||
@@ -478,11 +495,13 @@ static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value) | |||
478 | static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset) | 495 | static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset) |
479 | { | 496 | { |
480 | void __iomem *reg; | 497 | void __iomem *reg; |
481 | u32 pin_offset, data; | 498 | u32 data; |
499 | struct samsung_pin_bank *bank = gc_to_pin_bank(gc); | ||
500 | |||
501 | reg = bank->drvdata->virt_base + bank->pctl_offset; | ||
482 | 502 | ||
483 | pin_to_reg_bank(gc, offset, ®, &pin_offset, NULL); | ||
484 | data = readl(reg + DAT_REG); | 503 | data = readl(reg + DAT_REG); |
485 | data >>= pin_offset; | 504 | data >>= offset; |
486 | data &= 1; | 505 | data &= 1; |
487 | return data; | 506 | return data; |
488 | } | 507 | } |
@@ -510,6 +529,23 @@ static int samsung_gpio_direction_output(struct gpio_chip *gc, unsigned offset, | |||
510 | } | 529 | } |
511 | 530 | ||
512 | /* | 531 | /* |
532 | * gpiolib gpio_to_irq callback function. Creates a mapping between a GPIO pin | ||
533 | * and a virtual IRQ, if not already present. | ||
534 | */ | ||
535 | static int samsung_gpio_to_irq(struct gpio_chip *gc, unsigned offset) | ||
536 | { | ||
537 | struct samsung_pin_bank *bank = gc_to_pin_bank(gc); | ||
538 | unsigned int virq; | ||
539 | |||
540 | if (!bank->irq_domain) | ||
541 | return -ENXIO; | ||
542 | |||
543 | virq = irq_create_mapping(bank->irq_domain, offset); | ||
544 | |||
545 | return (virq) ? : -ENXIO; | ||
546 | } | ||
547 | |||
548 | /* | ||
513 | * Parse the pin names listed in the 'samsung,pins' property and convert it | 549 | * Parse the pin names listed in the 'samsung,pins' property and convert it |
514 | * into a list of gpio numbers are create a pin group from it. | 550 | * into a list of gpio numbers are create a pin group from it. |
515 | */ | 551 | */ |
@@ -597,7 +633,7 @@ static int __devinit samsung_pinctrl_parse_dt(struct platform_device *pdev, | |||
597 | */ | 633 | */ |
598 | for_each_child_of_node(dev_np, cfg_np) { | 634 | for_each_child_of_node(dev_np, cfg_np) { |
599 | u32 function; | 635 | u32 function; |
600 | if (of_find_property(cfg_np, "interrupt-controller", NULL)) | 636 | if (!of_find_property(cfg_np, "samsung,pins", NULL)) |
601 | continue; | 637 | continue; |
602 | 638 | ||
603 | ret = samsung_pinctrl_parse_dt_pins(pdev, cfg_np, | 639 | ret = samsung_pinctrl_parse_dt_pins(pdev, cfg_np, |
@@ -712,12 +748,16 @@ static int __devinit samsung_pinctrl_register(struct platform_device *pdev, | |||
712 | return -EINVAL; | 748 | return -EINVAL; |
713 | } | 749 | } |
714 | 750 | ||
715 | drvdata->grange.name = "samsung-pctrl-gpio-range"; | 751 | for (bank = 0; bank < drvdata->ctrl->nr_banks; ++bank) { |
716 | drvdata->grange.id = 0; | 752 | pin_bank = &drvdata->ctrl->pin_banks[bank]; |
717 | drvdata->grange.base = drvdata->ctrl->base; | 753 | pin_bank->grange.name = pin_bank->name; |
718 | drvdata->grange.npins = drvdata->ctrl->nr_pins; | 754 | pin_bank->grange.id = bank; |
719 | drvdata->grange.gc = drvdata->gc; | 755 | pin_bank->grange.pin_base = pin_bank->pin_base; |
720 | pinctrl_add_gpio_range(drvdata->pctl_dev, &drvdata->grange); | 756 | pin_bank->grange.base = pin_bank->gpio_chip.base; |
757 | pin_bank->grange.npins = pin_bank->gpio_chip.ngpio; | ||
758 | pin_bank->grange.gc = &pin_bank->gpio_chip; | ||
759 | pinctrl_add_gpio_range(drvdata->pctl_dev, &pin_bank->grange); | ||
760 | } | ||
721 | 761 | ||
722 | ret = samsung_pinctrl_parse_dt(pdev, drvdata); | 762 | ret = samsung_pinctrl_parse_dt(pdev, drvdata); |
723 | if (ret) { | 763 | if (ret) { |
@@ -728,68 +768,117 @@ static int __devinit samsung_pinctrl_register(struct platform_device *pdev, | |||
728 | return 0; | 768 | return 0; |
729 | } | 769 | } |
730 | 770 | ||
771 | static const struct gpio_chip samsung_gpiolib_chip = { | ||
772 | .set = samsung_gpio_set, | ||
773 | .get = samsung_gpio_get, | ||
774 | .direction_input = samsung_gpio_direction_input, | ||
775 | .direction_output = samsung_gpio_direction_output, | ||
776 | .to_irq = samsung_gpio_to_irq, | ||
777 | .owner = THIS_MODULE, | ||
778 | }; | ||
779 | |||
731 | /* register the gpiolib interface with the gpiolib subsystem */ | 780 | /* register the gpiolib interface with the gpiolib subsystem */ |
732 | static int __devinit samsung_gpiolib_register(struct platform_device *pdev, | 781 | static int __devinit samsung_gpiolib_register(struct platform_device *pdev, |
733 | struct samsung_pinctrl_drv_data *drvdata) | 782 | struct samsung_pinctrl_drv_data *drvdata) |
734 | { | 783 | { |
784 | struct samsung_pin_ctrl *ctrl = drvdata->ctrl; | ||
785 | struct samsung_pin_bank *bank = ctrl->pin_banks; | ||
735 | struct gpio_chip *gc; | 786 | struct gpio_chip *gc; |
736 | int ret; | 787 | int ret; |
737 | 788 | int i; | |
738 | gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL); | 789 | |
739 | if (!gc) { | 790 | for (i = 0; i < ctrl->nr_banks; ++i, ++bank) { |
740 | dev_err(&pdev->dev, "mem alloc for gpio_chip failed\n"); | 791 | bank->gpio_chip = samsung_gpiolib_chip; |
741 | return -ENOMEM; | 792 | |
742 | } | 793 | gc = &bank->gpio_chip; |
743 | 794 | gc->base = ctrl->base + bank->pin_base; | |
744 | drvdata->gc = gc; | 795 | gc->ngpio = bank->nr_pins; |
745 | gc->base = drvdata->ctrl->base; | 796 | gc->dev = &pdev->dev; |
746 | gc->ngpio = drvdata->ctrl->nr_pins; | 797 | gc->of_node = bank->of_node; |
747 | gc->dev = &pdev->dev; | 798 | gc->label = bank->name; |
748 | gc->set = samsung_gpio_set; | 799 | |
749 | gc->get = samsung_gpio_get; | 800 | ret = gpiochip_add(gc); |
750 | gc->direction_input = samsung_gpio_direction_input; | 801 | if (ret) { |
751 | gc->direction_output = samsung_gpio_direction_output; | 802 | dev_err(&pdev->dev, "failed to register gpio_chip %s, error code: %d\n", |
752 | gc->label = drvdata->ctrl->label; | 803 | gc->label, ret); |
753 | gc->owner = THIS_MODULE; | 804 | goto fail; |
754 | ret = gpiochip_add(gc); | 805 | } |
755 | if (ret) { | ||
756 | dev_err(&pdev->dev, "failed to register gpio_chip %s, error " | ||
757 | "code: %d\n", gc->label, ret); | ||
758 | return ret; | ||
759 | } | 806 | } |
760 | 807 | ||
761 | return 0; | 808 | return 0; |
809 | |||
810 | fail: | ||
811 | for (--i, --bank; i >= 0; --i, --bank) | ||
812 | if (gpiochip_remove(&bank->gpio_chip)) | ||
813 | dev_err(&pdev->dev, "gpio chip %s remove failed\n", | ||
814 | bank->gpio_chip.label); | ||
815 | return ret; | ||
762 | } | 816 | } |
763 | 817 | ||
764 | /* unregister the gpiolib interface with the gpiolib subsystem */ | 818 | /* unregister the gpiolib interface with the gpiolib subsystem */ |
765 | static int __devinit samsung_gpiolib_unregister(struct platform_device *pdev, | 819 | static int __devinit samsung_gpiolib_unregister(struct platform_device *pdev, |
766 | struct samsung_pinctrl_drv_data *drvdata) | 820 | struct samsung_pinctrl_drv_data *drvdata) |
767 | { | 821 | { |
768 | int ret = gpiochip_remove(drvdata->gc); | 822 | struct samsung_pin_ctrl *ctrl = drvdata->ctrl; |
769 | if (ret) { | 823 | struct samsung_pin_bank *bank = ctrl->pin_banks; |
824 | int ret = 0; | ||
825 | int i; | ||
826 | |||
827 | for (i = 0; !ret && i < ctrl->nr_banks; ++i, ++bank) | ||
828 | ret = gpiochip_remove(&bank->gpio_chip); | ||
829 | |||
830 | if (ret) | ||
770 | dev_err(&pdev->dev, "gpio chip remove failed\n"); | 831 | dev_err(&pdev->dev, "gpio chip remove failed\n"); |
771 | return ret; | 832 | |
772 | } | 833 | return ret; |
773 | return 0; | ||
774 | } | 834 | } |
775 | 835 | ||
776 | static const struct of_device_id samsung_pinctrl_dt_match[]; | 836 | static const struct of_device_id samsung_pinctrl_dt_match[]; |
777 | 837 | ||
778 | /* retrieve the soc specific data */ | 838 | /* retrieve the soc specific data */ |
779 | static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data( | 839 | static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data( |
840 | struct samsung_pinctrl_drv_data *d, | ||
780 | struct platform_device *pdev) | 841 | struct platform_device *pdev) |
781 | { | 842 | { |
782 | int id; | 843 | int id; |
783 | const struct of_device_id *match; | 844 | const struct of_device_id *match; |
784 | const struct device_node *node = pdev->dev.of_node; | 845 | struct device_node *node = pdev->dev.of_node; |
846 | struct device_node *np; | ||
847 | struct samsung_pin_ctrl *ctrl; | ||
848 | struct samsung_pin_bank *bank; | ||
849 | int i; | ||
785 | 850 | ||
786 | id = of_alias_get_id(pdev->dev.of_node, "pinctrl"); | 851 | id = of_alias_get_id(node, "pinctrl"); |
787 | if (id < 0) { | 852 | if (id < 0) { |
788 | dev_err(&pdev->dev, "failed to get alias id\n"); | 853 | dev_err(&pdev->dev, "failed to get alias id\n"); |
789 | return NULL; | 854 | return NULL; |
790 | } | 855 | } |
791 | match = of_match_node(samsung_pinctrl_dt_match, node); | 856 | match = of_match_node(samsung_pinctrl_dt_match, node); |
792 | return (struct samsung_pin_ctrl *)match->data + id; | 857 | ctrl = (struct samsung_pin_ctrl *)match->data + id; |
858 | |||
859 | bank = ctrl->pin_banks; | ||
860 | for (i = 0; i < ctrl->nr_banks; ++i, ++bank) { | ||
861 | bank->drvdata = d; | ||
862 | bank->pin_base = ctrl->nr_pins; | ||
863 | ctrl->nr_pins += bank->nr_pins; | ||
864 | } | ||
865 | |||
866 | for_each_child_of_node(node, np) { | ||
867 | if (!of_find_property(np, "gpio-controller", NULL)) | ||
868 | continue; | ||
869 | bank = ctrl->pin_banks; | ||
870 | for (i = 0; i < ctrl->nr_banks; ++i, ++bank) { | ||
871 | if (!strcmp(bank->name, np->name)) { | ||
872 | bank->of_node = np; | ||
873 | break; | ||
874 | } | ||
875 | } | ||
876 | } | ||
877 | |||
878 | ctrl->base = pin_base; | ||
879 | pin_base += ctrl->nr_pins; | ||
880 | |||
881 | return ctrl; | ||
793 | } | 882 | } |
794 | 883 | ||
795 | static int __devinit samsung_pinctrl_probe(struct platform_device *pdev) | 884 | static int __devinit samsung_pinctrl_probe(struct platform_device *pdev) |
@@ -805,18 +894,18 @@ static int __devinit samsung_pinctrl_probe(struct platform_device *pdev) | |||
805 | return -ENODEV; | 894 | return -ENODEV; |
806 | } | 895 | } |
807 | 896 | ||
808 | ctrl = samsung_pinctrl_get_soc_data(pdev); | ||
809 | if (!ctrl) { | ||
810 | dev_err(&pdev->dev, "driver data not available\n"); | ||
811 | return -EINVAL; | ||
812 | } | ||
813 | |||
814 | drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); | 897 | drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); |
815 | if (!drvdata) { | 898 | if (!drvdata) { |
816 | dev_err(dev, "failed to allocate memory for driver's " | 899 | dev_err(dev, "failed to allocate memory for driver's " |
817 | "private data\n"); | 900 | "private data\n"); |
818 | return -ENOMEM; | 901 | return -ENOMEM; |
819 | } | 902 | } |
903 | |||
904 | ctrl = samsung_pinctrl_get_soc_data(drvdata, pdev); | ||
905 | if (!ctrl) { | ||
906 | dev_err(&pdev->dev, "driver data not available\n"); | ||
907 | return -EINVAL; | ||
908 | } | ||
820 | drvdata->ctrl = ctrl; | 909 | drvdata->ctrl = ctrl; |
821 | drvdata->dev = dev; | 910 | drvdata->dev = dev; |
822 | 911 | ||