diff options
author | Linus Walleij <linus.walleij@linaro.org> | 2017-12-07 04:09:55 -0500 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2017-12-07 04:09:55 -0500 |
commit | 110e2a38c8daabb6f33e164dab6083afeeb2dd5e (patch) | |
tree | 0d2aedaee023372319fa326ba5f44e645b0f45c3 | |
parent | 4070a53496ec0c94fda1da0773eee2e5a5bd0084 (diff) | |
parent | e1190083b89bd0d53c83b647ff313d9f004c6772 (diff) |
Merge branch 'ib-move-axp209' into devel
-rw-r--r-- | Documentation/devicetree/bindings/gpio/gpio-axp209.txt | 49 | ||||
-rw-r--r-- | drivers/gpio/Kconfig | 6 | ||||
-rw-r--r-- | drivers/gpio/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpio/gpio-axp209.c | 188 | ||||
-rw-r--r-- | drivers/pinctrl/Kconfig | 10 | ||||
-rw-r--r-- | drivers/pinctrl/Makefile | 1 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-axp209.c | 476 |
7 files changed, 534 insertions, 197 deletions
diff --git a/Documentation/devicetree/bindings/gpio/gpio-axp209.txt b/Documentation/devicetree/bindings/gpio/gpio-axp209.txt index a6611304dd3c..fc42b2caa06d 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-axp209.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-axp209.txt | |||
@@ -1,10 +1,17 @@ | |||
1 | AXP209 GPIO controller | 1 | AXP209 GPIO & pinctrl controller |
2 | 2 | ||
3 | This driver follows the usual GPIO bindings found in | 3 | This driver follows the usual GPIO bindings found in |
4 | Documentation/devicetree/bindings/gpio/gpio.txt | 4 | Documentation/devicetree/bindings/gpio/gpio.txt |
5 | 5 | ||
6 | This driver follows the usual pinctrl bindings found in | ||
7 | Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt | ||
8 | |||
9 | This driver employs the per-pin muxing pattern. | ||
10 | |||
6 | Required properties: | 11 | Required properties: |
7 | - compatible: Should be "x-powers,axp209-gpio" | 12 | - compatible: Should be one of: |
13 | - "x-powers,axp209-gpio" | ||
14 | - "x-powers,axp813-gpio" | ||
8 | - #gpio-cells: Should be two. The first cell is the pin number and the | 15 | - #gpio-cells: Should be two. The first cell is the pin number and the |
9 | second is the GPIO flags. | 16 | second is the GPIO flags. |
10 | - gpio-controller: Marks the device node as a GPIO controller. | 17 | - gpio-controller: Marks the device node as a GPIO controller. |
@@ -28,3 +35,41 @@ axp209: pmic@34 { | |||
28 | #gpio-cells = <2>; | 35 | #gpio-cells = <2>; |
29 | }; | 36 | }; |
30 | }; | 37 | }; |
38 | |||
39 | The GPIOs can be muxed to other functions and therefore, must be a subnode of | ||
40 | axp_gpio. | ||
41 | |||
42 | Example: | ||
43 | |||
44 | &axp_gpio { | ||
45 | gpio0_adc: gpio0-adc { | ||
46 | pins = "GPIO0"; | ||
47 | function = "adc"; | ||
48 | }; | ||
49 | }; | ||
50 | |||
51 | &example_node { | ||
52 | pinctrl-names = "default"; | ||
53 | pinctrl-0 = <&gpio0_adc>; | ||
54 | }; | ||
55 | |||
56 | GPIOs and their functions | ||
57 | ------------------------- | ||
58 | |||
59 | Each GPIO is independent from the other (i.e. GPIO0 in gpio_in function does | ||
60 | not force GPIO1 and GPIO2 to be in gpio_in function as well). | ||
61 | |||
62 | axp209 | ||
63 | ------ | ||
64 | GPIO | Functions | ||
65 | ------------------------ | ||
66 | GPIO0 | gpio_in, gpio_out, ldo, adc | ||
67 | GPIO1 | gpio_in, gpio_out, ldo, adc | ||
68 | GPIO2 | gpio_in, gpio_out | ||
69 | |||
70 | axp813 | ||
71 | ------ | ||
72 | GPIO | Functions | ||
73 | ------------------------ | ||
74 | GPIO0 | gpio_in, gpio_out, ldo, adc | ||
75 | GPIO1 | gpio_in, gpio_out, ldo | ||
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d6a8e851ad13..395669bfcc26 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig | |||
@@ -122,12 +122,6 @@ config GPIO_ATH79 | |||
122 | Select this option to enable GPIO driver for | 122 | Select this option to enable GPIO driver for |
123 | Atheros AR71XX/AR724X/AR913X SoC devices. | 123 | Atheros AR71XX/AR724X/AR913X SoC devices. |
124 | 124 | ||
125 | config GPIO_AXP209 | ||
126 | tristate "X-Powers AXP209 PMIC GPIO Support" | ||
127 | depends on MFD_AXP20X | ||
128 | help | ||
129 | Say yes to enable GPIO support for the AXP209 PMIC | ||
130 | |||
131 | config GPIO_BCM_KONA | 125 | config GPIO_BCM_KONA |
132 | bool "Broadcom Kona GPIO" | 126 | bool "Broadcom Kona GPIO" |
133 | depends on OF_GPIO && (ARCH_BCM_MOBILE || COMPILE_TEST) | 127 | depends on OF_GPIO && (ARCH_BCM_MOBILE || COMPILE_TEST) |
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 4bc24febb889..bc5dd673fa11 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile | |||
@@ -32,7 +32,6 @@ obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o | |||
32 | obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o | 32 | obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o |
33 | obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o | 33 | obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o |
34 | obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o | 34 | obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o |
35 | obj-$(CONFIG_GPIO_AXP209) += gpio-axp209.o | ||
36 | obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o | 35 | obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o |
37 | obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o | 36 | obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o |
38 | obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o | 37 | obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o |
diff --git a/drivers/gpio/gpio-axp209.c b/drivers/gpio/gpio-axp209.c deleted file mode 100644 index 4a346b7b4172..000000000000 --- a/drivers/gpio/gpio-axp209.c +++ /dev/null | |||
@@ -1,188 +0,0 @@ | |||
1 | /* | ||
2 | * AXP20x GPIO driver | ||
3 | * | ||
4 | * Copyright (C) 2016 Maxime Ripard <maxime.ripard@free-electrons.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
9 | * option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/bitops.h> | ||
13 | #include <linux/device.h> | ||
14 | #include <linux/gpio/driver.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/mfd/axp20x.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/of.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/regmap.h> | ||
23 | #include <linux/slab.h> | ||
24 | |||
25 | #define AXP20X_GPIO_FUNCTIONS 0x7 | ||
26 | #define AXP20X_GPIO_FUNCTION_OUT_LOW 0 | ||
27 | #define AXP20X_GPIO_FUNCTION_OUT_HIGH 1 | ||
28 | #define AXP20X_GPIO_FUNCTION_INPUT 2 | ||
29 | |||
30 | struct axp20x_gpio { | ||
31 | struct gpio_chip chip; | ||
32 | struct regmap *regmap; | ||
33 | }; | ||
34 | |||
35 | static int axp20x_gpio_get_reg(unsigned offset) | ||
36 | { | ||
37 | switch (offset) { | ||
38 | case 0: | ||
39 | return AXP20X_GPIO0_CTRL; | ||
40 | case 1: | ||
41 | return AXP20X_GPIO1_CTRL; | ||
42 | case 2: | ||
43 | return AXP20X_GPIO2_CTRL; | ||
44 | } | ||
45 | |||
46 | return -EINVAL; | ||
47 | } | ||
48 | |||
49 | static int axp20x_gpio_input(struct gpio_chip *chip, unsigned offset) | ||
50 | { | ||
51 | struct axp20x_gpio *gpio = gpiochip_get_data(chip); | ||
52 | int reg; | ||
53 | |||
54 | reg = axp20x_gpio_get_reg(offset); | ||
55 | if (reg < 0) | ||
56 | return reg; | ||
57 | |||
58 | return regmap_update_bits(gpio->regmap, reg, | ||
59 | AXP20X_GPIO_FUNCTIONS, | ||
60 | AXP20X_GPIO_FUNCTION_INPUT); | ||
61 | } | ||
62 | |||
63 | static int axp20x_gpio_get(struct gpio_chip *chip, unsigned offset) | ||
64 | { | ||
65 | struct axp20x_gpio *gpio = gpiochip_get_data(chip); | ||
66 | unsigned int val; | ||
67 | int ret; | ||
68 | |||
69 | ret = regmap_read(gpio->regmap, AXP20X_GPIO20_SS, &val); | ||
70 | if (ret) | ||
71 | return ret; | ||
72 | |||
73 | return !!(val & BIT(offset + 4)); | ||
74 | } | ||
75 | |||
76 | static int axp20x_gpio_get_direction(struct gpio_chip *chip, unsigned offset) | ||
77 | { | ||
78 | struct axp20x_gpio *gpio = gpiochip_get_data(chip); | ||
79 | unsigned int val; | ||
80 | int reg, ret; | ||
81 | |||
82 | reg = axp20x_gpio_get_reg(offset); | ||
83 | if (reg < 0) | ||
84 | return reg; | ||
85 | |||
86 | ret = regmap_read(gpio->regmap, reg, &val); | ||
87 | if (ret) | ||
88 | return ret; | ||
89 | |||
90 | /* | ||
91 | * This shouldn't really happen if the pin is in use already, | ||
92 | * or if it's not in use yet, it doesn't matter since we're | ||
93 | * going to change the value soon anyway. Default to output. | ||
94 | */ | ||
95 | if ((val & AXP20X_GPIO_FUNCTIONS) > 2) | ||
96 | return 0; | ||
97 | |||
98 | /* | ||
99 | * The GPIO directions are the three lowest values. | ||
100 | * 2 is input, 0 and 1 are output | ||
101 | */ | ||
102 | return val & 2; | ||
103 | } | ||
104 | |||
105 | static int axp20x_gpio_output(struct gpio_chip *chip, unsigned offset, | ||
106 | int value) | ||
107 | { | ||
108 | struct axp20x_gpio *gpio = gpiochip_get_data(chip); | ||
109 | int reg; | ||
110 | |||
111 | reg = axp20x_gpio_get_reg(offset); | ||
112 | if (reg < 0) | ||
113 | return reg; | ||
114 | |||
115 | return regmap_update_bits(gpio->regmap, reg, | ||
116 | AXP20X_GPIO_FUNCTIONS, | ||
117 | value ? AXP20X_GPIO_FUNCTION_OUT_HIGH | ||
118 | : AXP20X_GPIO_FUNCTION_OUT_LOW); | ||
119 | } | ||
120 | |||
121 | static void axp20x_gpio_set(struct gpio_chip *chip, unsigned offset, | ||
122 | int value) | ||
123 | { | ||
124 | axp20x_gpio_output(chip, offset, value); | ||
125 | } | ||
126 | |||
127 | static int axp20x_gpio_probe(struct platform_device *pdev) | ||
128 | { | ||
129 | struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); | ||
130 | struct axp20x_gpio *gpio; | ||
131 | int ret; | ||
132 | |||
133 | if (!of_device_is_available(pdev->dev.of_node)) | ||
134 | return -ENODEV; | ||
135 | |||
136 | if (!axp20x) { | ||
137 | dev_err(&pdev->dev, "Parent drvdata not set\n"); | ||
138 | return -EINVAL; | ||
139 | } | ||
140 | |||
141 | gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); | ||
142 | if (!gpio) | ||
143 | return -ENOMEM; | ||
144 | |||
145 | gpio->chip.base = -1; | ||
146 | gpio->chip.can_sleep = true; | ||
147 | gpio->chip.parent = &pdev->dev; | ||
148 | gpio->chip.label = dev_name(&pdev->dev); | ||
149 | gpio->chip.owner = THIS_MODULE; | ||
150 | gpio->chip.get = axp20x_gpio_get; | ||
151 | gpio->chip.get_direction = axp20x_gpio_get_direction; | ||
152 | gpio->chip.set = axp20x_gpio_set; | ||
153 | gpio->chip.direction_input = axp20x_gpio_input; | ||
154 | gpio->chip.direction_output = axp20x_gpio_output; | ||
155 | gpio->chip.ngpio = 3; | ||
156 | |||
157 | gpio->regmap = axp20x->regmap; | ||
158 | |||
159 | ret = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); | ||
160 | if (ret) { | ||
161 | dev_err(&pdev->dev, "Failed to register GPIO chip\n"); | ||
162 | return ret; | ||
163 | } | ||
164 | |||
165 | dev_info(&pdev->dev, "AXP209 GPIO driver loaded\n"); | ||
166 | |||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | static const struct of_device_id axp20x_gpio_match[] = { | ||
171 | { .compatible = "x-powers,axp209-gpio" }, | ||
172 | { } | ||
173 | }; | ||
174 | MODULE_DEVICE_TABLE(of, axp20x_gpio_match); | ||
175 | |||
176 | static struct platform_driver axp20x_gpio_driver = { | ||
177 | .probe = axp20x_gpio_probe, | ||
178 | .driver = { | ||
179 | .name = "axp20x-gpio", | ||
180 | .of_match_table = axp20x_gpio_match, | ||
181 | }, | ||
182 | }; | ||
183 | |||
184 | module_platform_driver(axp20x_gpio_driver); | ||
185 | |||
186 | MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); | ||
187 | MODULE_DESCRIPTION("AXP20x PMIC GPIO driver"); | ||
188 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 4571cc098b76..ce126955212c 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig | |||
@@ -63,6 +63,16 @@ config PINCTRL_AS3722 | |||
63 | open drain configuration for the GPIO pins of AS3722 devices. It also | 63 | open drain configuration for the GPIO pins of AS3722 devices. It also |
64 | supports the GPIO functionality through gpiolib. | 64 | supports the GPIO functionality through gpiolib. |
65 | 65 | ||
66 | config PINCTRL_AXP209 | ||
67 | tristate "X-Powers AXP209 PMIC pinctrl and GPIO Support" | ||
68 | depends on MFD_AXP20X | ||
69 | help | ||
70 | AXP PMICs provides multiple GPIOs that can be muxed for different | ||
71 | functions. This driver bundles a pinctrl driver to select the function | ||
72 | muxing and a GPIO driver to handle the GPIO when the GPIO function is | ||
73 | selected. | ||
74 | Say yes to enable pinctrl and GPIO support for the AXP209 PMIC | ||
75 | |||
66 | config PINCTRL_BF54x | 76 | config PINCTRL_BF54x |
67 | def_bool y if BF54x | 77 | def_bool y if BF54x |
68 | select PINCTRL_ADI2 | 78 | select PINCTRL_ADI2 |
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index d0d4844f8022..4777f1595ce2 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile | |||
@@ -11,6 +11,7 @@ obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o | |||
11 | obj-$(CONFIG_PINCTRL_ADI2) += pinctrl-adi2.o | 11 | obj-$(CONFIG_PINCTRL_ADI2) += pinctrl-adi2.o |
12 | obj-$(CONFIG_PINCTRL_ARTPEC6) += pinctrl-artpec6.o | 12 | obj-$(CONFIG_PINCTRL_ARTPEC6) += pinctrl-artpec6.o |
13 | obj-$(CONFIG_PINCTRL_AS3722) += pinctrl-as3722.o | 13 | obj-$(CONFIG_PINCTRL_AS3722) += pinctrl-as3722.o |
14 | obj-$(CONFIG_PINCTRL_AXP209) += pinctrl-axp209.o | ||
14 | obj-$(CONFIG_PINCTRL_BF54x) += pinctrl-adi2-bf54x.o | 15 | obj-$(CONFIG_PINCTRL_BF54x) += pinctrl-adi2-bf54x.o |
15 | obj-$(CONFIG_PINCTRL_BF60x) += pinctrl-adi2-bf60x.o | 16 | obj-$(CONFIG_PINCTRL_BF60x) += pinctrl-adi2-bf60x.o |
16 | obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o | 17 | obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o |
diff --git a/drivers/pinctrl/pinctrl-axp209.c b/drivers/pinctrl/pinctrl-axp209.c new file mode 100644 index 000000000000..22d3bb0bf927 --- /dev/null +++ b/drivers/pinctrl/pinctrl-axp209.c | |||
@@ -0,0 +1,476 @@ | |||
1 | /* | ||
2 | * AXP20x pinctrl and GPIO driver | ||
3 | * | ||
4 | * Copyright (C) 2016 Maxime Ripard <maxime.ripard@free-electrons.com> | ||
5 | * Copyright (C) 2017 Quentin Schulz <quentin.schulz@free-electrons.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/bitops.h> | ||
14 | #include <linux/device.h> | ||
15 | #include <linux/gpio/driver.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/mfd/axp20x.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/of.h> | ||
22 | #include <linux/of_device.h> | ||
23 | #include <linux/pinctrl/pinconf-generic.h> | ||
24 | #include <linux/pinctrl/pinctrl.h> | ||
25 | #include <linux/pinctrl/pinmux.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <linux/regmap.h> | ||
28 | #include <linux/slab.h> | ||
29 | |||
30 | #define AXP20X_GPIO_FUNCTIONS 0x7 | ||
31 | #define AXP20X_GPIO_FUNCTION_OUT_LOW 0 | ||
32 | #define AXP20X_GPIO_FUNCTION_OUT_HIGH 1 | ||
33 | #define AXP20X_GPIO_FUNCTION_INPUT 2 | ||
34 | |||
35 | #define AXP20X_FUNC_GPIO_OUT 0 | ||
36 | #define AXP20X_FUNC_GPIO_IN 1 | ||
37 | #define AXP20X_FUNC_LDO 2 | ||
38 | #define AXP20X_FUNC_ADC 3 | ||
39 | #define AXP20X_FUNCS_NB 4 | ||
40 | |||
41 | #define AXP20X_MUX_GPIO_OUT 0 | ||
42 | #define AXP20X_MUX_GPIO_IN BIT(1) | ||
43 | #define AXP20X_MUX_ADC BIT(2) | ||
44 | |||
45 | #define AXP813_MUX_ADC (BIT(2) | BIT(0)) | ||
46 | |||
47 | struct axp20x_pctrl_desc { | ||
48 | const struct pinctrl_pin_desc *pins; | ||
49 | unsigned int npins; | ||
50 | /* Stores the pins supporting LDO function. Bit offset is pin number. */ | ||
51 | u8 ldo_mask; | ||
52 | /* Stores the pins supporting ADC function. Bit offset is pin number. */ | ||
53 | u8 adc_mask; | ||
54 | u8 gpio_status_offset; | ||
55 | u8 adc_mux; | ||
56 | }; | ||
57 | |||
58 | struct axp20x_pinctrl_function { | ||
59 | const char *name; | ||
60 | unsigned int muxval; | ||
61 | const char **groups; | ||
62 | unsigned int ngroups; | ||
63 | }; | ||
64 | |||
65 | struct axp20x_pctl { | ||
66 | struct gpio_chip chip; | ||
67 | struct regmap *regmap; | ||
68 | struct pinctrl_dev *pctl_dev; | ||
69 | struct device *dev; | ||
70 | const struct axp20x_pctrl_desc *desc; | ||
71 | struct axp20x_pinctrl_function funcs[AXP20X_FUNCS_NB]; | ||
72 | }; | ||
73 | |||
74 | static const struct pinctrl_pin_desc axp209_pins[] = { | ||
75 | PINCTRL_PIN(0, "GPIO0"), | ||
76 | PINCTRL_PIN(1, "GPIO1"), | ||
77 | PINCTRL_PIN(2, "GPIO2"), | ||
78 | }; | ||
79 | |||
80 | static const struct pinctrl_pin_desc axp813_pins[] = { | ||
81 | PINCTRL_PIN(0, "GPIO0"), | ||
82 | PINCTRL_PIN(1, "GPIO1"), | ||
83 | }; | ||
84 | |||
85 | static const struct axp20x_pctrl_desc axp20x_data = { | ||
86 | .pins = axp209_pins, | ||
87 | .npins = ARRAY_SIZE(axp209_pins), | ||
88 | .ldo_mask = BIT(0) | BIT(1), | ||
89 | .adc_mask = BIT(0) | BIT(1), | ||
90 | .gpio_status_offset = 4, | ||
91 | .adc_mux = AXP20X_MUX_ADC, | ||
92 | }; | ||
93 | |||
94 | static const struct axp20x_pctrl_desc axp813_data = { | ||
95 | .pins = axp813_pins, | ||
96 | .npins = ARRAY_SIZE(axp813_pins), | ||
97 | .ldo_mask = BIT(0) | BIT(1), | ||
98 | .adc_mask = BIT(0), | ||
99 | .gpio_status_offset = 0, | ||
100 | .adc_mux = AXP813_MUX_ADC, | ||
101 | }; | ||
102 | |||
103 | static int axp20x_gpio_get_reg(unsigned int offset) | ||
104 | { | ||
105 | switch (offset) { | ||
106 | case 0: | ||
107 | return AXP20X_GPIO0_CTRL; | ||
108 | case 1: | ||
109 | return AXP20X_GPIO1_CTRL; | ||
110 | case 2: | ||
111 | return AXP20X_GPIO2_CTRL; | ||
112 | } | ||
113 | |||
114 | return -EINVAL; | ||
115 | } | ||
116 | |||
117 | static int axp20x_gpio_input(struct gpio_chip *chip, unsigned int offset) | ||
118 | { | ||
119 | return pinctrl_gpio_direction_input(chip->base + offset); | ||
120 | } | ||
121 | |||
122 | static int axp20x_gpio_get(struct gpio_chip *chip, unsigned int offset) | ||
123 | { | ||
124 | struct axp20x_pctl *pctl = gpiochip_get_data(chip); | ||
125 | unsigned int val; | ||
126 | int ret; | ||
127 | |||
128 | ret = regmap_read(pctl->regmap, AXP20X_GPIO20_SS, &val); | ||
129 | if (ret) | ||
130 | return ret; | ||
131 | |||
132 | return !!(val & BIT(offset + pctl->desc->gpio_status_offset)); | ||
133 | } | ||
134 | |||
135 | static int axp20x_gpio_get_direction(struct gpio_chip *chip, | ||
136 | unsigned int offset) | ||
137 | { | ||
138 | struct axp20x_pctl *pctl = gpiochip_get_data(chip); | ||
139 | unsigned int val; | ||
140 | int reg, ret; | ||
141 | |||
142 | reg = axp20x_gpio_get_reg(offset); | ||
143 | if (reg < 0) | ||
144 | return reg; | ||
145 | |||
146 | ret = regmap_read(pctl->regmap, reg, &val); | ||
147 | if (ret) | ||
148 | return ret; | ||
149 | |||
150 | /* | ||
151 | * This shouldn't really happen if the pin is in use already, | ||
152 | * or if it's not in use yet, it doesn't matter since we're | ||
153 | * going to change the value soon anyway. Default to output. | ||
154 | */ | ||
155 | if ((val & AXP20X_GPIO_FUNCTIONS) > 2) | ||
156 | return 0; | ||
157 | |||
158 | /* | ||
159 | * The GPIO directions are the three lowest values. | ||
160 | * 2 is input, 0 and 1 are output | ||
161 | */ | ||
162 | return val & 2; | ||
163 | } | ||
164 | |||
165 | static int axp20x_gpio_output(struct gpio_chip *chip, unsigned int offset, | ||
166 | int value) | ||
167 | { | ||
168 | chip->set(chip, offset, value); | ||
169 | |||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | static void axp20x_gpio_set(struct gpio_chip *chip, unsigned int offset, | ||
174 | int value) | ||
175 | { | ||
176 | struct axp20x_pctl *pctl = gpiochip_get_data(chip); | ||
177 | int reg; | ||
178 | |||
179 | reg = axp20x_gpio_get_reg(offset); | ||
180 | if (reg < 0) | ||
181 | return; | ||
182 | |||
183 | regmap_update_bits(pctl->regmap, reg, | ||
184 | AXP20X_GPIO_FUNCTIONS, | ||
185 | value ? AXP20X_GPIO_FUNCTION_OUT_HIGH : | ||
186 | AXP20X_GPIO_FUNCTION_OUT_LOW); | ||
187 | } | ||
188 | |||
189 | static int axp20x_pmx_set(struct pinctrl_dev *pctldev, unsigned int offset, | ||
190 | u8 config) | ||
191 | { | ||
192 | struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
193 | int reg; | ||
194 | |||
195 | reg = axp20x_gpio_get_reg(offset); | ||
196 | if (reg < 0) | ||
197 | return reg; | ||
198 | |||
199 | return regmap_update_bits(pctl->regmap, reg, AXP20X_GPIO_FUNCTIONS, | ||
200 | config); | ||
201 | } | ||
202 | |||
203 | static int axp20x_pmx_func_cnt(struct pinctrl_dev *pctldev) | ||
204 | { | ||
205 | struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
206 | |||
207 | return ARRAY_SIZE(pctl->funcs); | ||
208 | } | ||
209 | |||
210 | static const char *axp20x_pmx_func_name(struct pinctrl_dev *pctldev, | ||
211 | unsigned int selector) | ||
212 | { | ||
213 | struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
214 | |||
215 | return pctl->funcs[selector].name; | ||
216 | } | ||
217 | |||
218 | static int axp20x_pmx_func_groups(struct pinctrl_dev *pctldev, | ||
219 | unsigned int selector, | ||
220 | const char * const **groups, | ||
221 | unsigned int *num_groups) | ||
222 | { | ||
223 | struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
224 | |||
225 | *groups = pctl->funcs[selector].groups; | ||
226 | *num_groups = pctl->funcs[selector].ngroups; | ||
227 | |||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | static int axp20x_pmx_set_mux(struct pinctrl_dev *pctldev, | ||
232 | unsigned int function, unsigned int group) | ||
233 | { | ||
234 | struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
235 | unsigned int mask; | ||
236 | |||
237 | /* Every pin supports GPIO_OUT and GPIO_IN functions */ | ||
238 | if (function <= AXP20X_FUNC_GPIO_IN) | ||
239 | return axp20x_pmx_set(pctldev, group, | ||
240 | pctl->funcs[function].muxval); | ||
241 | |||
242 | if (function == AXP20X_FUNC_LDO) | ||
243 | mask = pctl->desc->ldo_mask; | ||
244 | else | ||
245 | mask = pctl->desc->adc_mask; | ||
246 | |||
247 | if (!(BIT(group) & mask)) | ||
248 | return -EINVAL; | ||
249 | |||
250 | /* | ||
251 | * We let the regulator framework handle the LDO muxing as muxing bits | ||
252 | * are basically also regulators on/off bits. It's better not to enforce | ||
253 | * any state of the regulator when selecting LDO mux so that we don't | ||
254 | * interfere with the regulator driver. | ||
255 | */ | ||
256 | if (function == AXP20X_FUNC_LDO) | ||
257 | return 0; | ||
258 | |||
259 | return axp20x_pmx_set(pctldev, group, pctl->funcs[function].muxval); | ||
260 | } | ||
261 | |||
262 | static int axp20x_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, | ||
263 | struct pinctrl_gpio_range *range, | ||
264 | unsigned int offset, bool input) | ||
265 | { | ||
266 | struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
267 | |||
268 | if (input) | ||
269 | return axp20x_pmx_set(pctldev, offset, | ||
270 | pctl->funcs[AXP20X_FUNC_GPIO_IN].muxval); | ||
271 | |||
272 | return axp20x_pmx_set(pctldev, offset, | ||
273 | pctl->funcs[AXP20X_FUNC_GPIO_OUT].muxval); | ||
274 | } | ||
275 | |||
276 | static const struct pinmux_ops axp20x_pmx_ops = { | ||
277 | .get_functions_count = axp20x_pmx_func_cnt, | ||
278 | .get_function_name = axp20x_pmx_func_name, | ||
279 | .get_function_groups = axp20x_pmx_func_groups, | ||
280 | .set_mux = axp20x_pmx_set_mux, | ||
281 | .gpio_set_direction = axp20x_pmx_gpio_set_direction, | ||
282 | .strict = true, | ||
283 | }; | ||
284 | |||
285 | static int axp20x_groups_cnt(struct pinctrl_dev *pctldev) | ||
286 | { | ||
287 | struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
288 | |||
289 | return pctl->desc->npins; | ||
290 | } | ||
291 | |||
292 | static int axp20x_group_pins(struct pinctrl_dev *pctldev, unsigned int selector, | ||
293 | const unsigned int **pins, unsigned int *num_pins) | ||
294 | { | ||
295 | struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
296 | |||
297 | *pins = (unsigned int *)&pctl->desc->pins[selector]; | ||
298 | *num_pins = 1; | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | static const char *axp20x_group_name(struct pinctrl_dev *pctldev, | ||
304 | unsigned int selector) | ||
305 | { | ||
306 | struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
307 | |||
308 | return pctl->desc->pins[selector].name; | ||
309 | } | ||
310 | |||
311 | static const struct pinctrl_ops axp20x_pctrl_ops = { | ||
312 | .dt_node_to_map = pinconf_generic_dt_node_to_map_group, | ||
313 | .dt_free_map = pinconf_generic_dt_free_map, | ||
314 | .get_groups_count = axp20x_groups_cnt, | ||
315 | .get_group_name = axp20x_group_name, | ||
316 | .get_group_pins = axp20x_group_pins, | ||
317 | }; | ||
318 | |||
319 | static void axp20x_funcs_groups_from_mask(struct device *dev, unsigned int mask, | ||
320 | unsigned int mask_len, | ||
321 | struct axp20x_pinctrl_function *func, | ||
322 | const struct pinctrl_pin_desc *pins) | ||
323 | { | ||
324 | unsigned long int mask_cpy = mask; | ||
325 | const char **group; | ||
326 | unsigned int ngroups = hweight8(mask); | ||
327 | int bit; | ||
328 | |||
329 | func->ngroups = ngroups; | ||
330 | if (func->ngroups > 0) { | ||
331 | func->groups = devm_kzalloc(dev, ngroups * sizeof(const char *), | ||
332 | GFP_KERNEL); | ||
333 | group = func->groups; | ||
334 | for_each_set_bit(bit, &mask_cpy, mask_len) { | ||
335 | *group = pins[bit].name; | ||
336 | group++; | ||
337 | } | ||
338 | } | ||
339 | } | ||
340 | |||
341 | static void axp20x_build_funcs_groups(struct platform_device *pdev) | ||
342 | { | ||
343 | struct axp20x_pctl *pctl = platform_get_drvdata(pdev); | ||
344 | int i, pin, npins = pctl->desc->npins; | ||
345 | |||
346 | pctl->funcs[AXP20X_FUNC_GPIO_OUT].name = "gpio_out"; | ||
347 | pctl->funcs[AXP20X_FUNC_GPIO_OUT].muxval = AXP20X_MUX_GPIO_OUT; | ||
348 | pctl->funcs[AXP20X_FUNC_GPIO_IN].name = "gpio_in"; | ||
349 | pctl->funcs[AXP20X_FUNC_GPIO_IN].muxval = AXP20X_MUX_GPIO_IN; | ||
350 | pctl->funcs[AXP20X_FUNC_LDO].name = "ldo"; | ||
351 | /* | ||
352 | * Muxval for LDO is useless as we won't use it. | ||
353 | * See comment in axp20x_pmx_set_mux. | ||
354 | */ | ||
355 | pctl->funcs[AXP20X_FUNC_ADC].name = "adc"; | ||
356 | pctl->funcs[AXP20X_FUNC_ADC].muxval = pctl->desc->adc_mux; | ||
357 | |||
358 | /* Every pin supports GPIO_OUT and GPIO_IN functions */ | ||
359 | for (i = 0; i <= AXP20X_FUNC_GPIO_IN; i++) { | ||
360 | pctl->funcs[i].ngroups = npins; | ||
361 | pctl->funcs[i].groups = devm_kzalloc(&pdev->dev, | ||
362 | npins * sizeof(char *), | ||
363 | GFP_KERNEL); | ||
364 | for (pin = 0; pin < npins; pin++) | ||
365 | pctl->funcs[i].groups[pin] = pctl->desc->pins[pin].name; | ||
366 | } | ||
367 | |||
368 | axp20x_funcs_groups_from_mask(&pdev->dev, pctl->desc->ldo_mask, | ||
369 | npins, &pctl->funcs[AXP20X_FUNC_LDO], | ||
370 | pctl->desc->pins); | ||
371 | |||
372 | axp20x_funcs_groups_from_mask(&pdev->dev, pctl->desc->adc_mask, | ||
373 | npins, &pctl->funcs[AXP20X_FUNC_ADC], | ||
374 | pctl->desc->pins); | ||
375 | } | ||
376 | |||
377 | static const struct of_device_id axp20x_pctl_match[] = { | ||
378 | { .compatible = "x-powers,axp209-gpio", .data = &axp20x_data, }, | ||
379 | { .compatible = "x-powers,axp813-gpio", .data = &axp813_data, }, | ||
380 | { } | ||
381 | }; | ||
382 | MODULE_DEVICE_TABLE(of, axp20x_pctl_match); | ||
383 | |||
384 | static int axp20x_pctl_probe(struct platform_device *pdev) | ||
385 | { | ||
386 | struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); | ||
387 | struct axp20x_pctl *pctl; | ||
388 | struct device *dev = &pdev->dev; | ||
389 | struct pinctrl_desc *pctrl_desc; | ||
390 | int ret; | ||
391 | |||
392 | if (!of_device_is_available(pdev->dev.of_node)) | ||
393 | return -ENODEV; | ||
394 | |||
395 | if (!axp20x) { | ||
396 | dev_err(&pdev->dev, "Parent drvdata not set\n"); | ||
397 | return -EINVAL; | ||
398 | } | ||
399 | |||
400 | pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL); | ||
401 | if (!pctl) | ||
402 | return -ENOMEM; | ||
403 | |||
404 | pctl->chip.base = -1; | ||
405 | pctl->chip.can_sleep = true; | ||
406 | pctl->chip.request = gpiochip_generic_request; | ||
407 | pctl->chip.free = gpiochip_generic_free; | ||
408 | pctl->chip.parent = &pdev->dev; | ||
409 | pctl->chip.label = dev_name(&pdev->dev); | ||
410 | pctl->chip.owner = THIS_MODULE; | ||
411 | pctl->chip.get = axp20x_gpio_get; | ||
412 | pctl->chip.get_direction = axp20x_gpio_get_direction; | ||
413 | pctl->chip.set = axp20x_gpio_set; | ||
414 | pctl->chip.direction_input = axp20x_gpio_input; | ||
415 | pctl->chip.direction_output = axp20x_gpio_output; | ||
416 | pctl->chip.ngpio = pctl->desc->npins; | ||
417 | |||
418 | pctl->desc = (struct axp20x_pctrl_desc *)of_device_get_match_data(dev); | ||
419 | pctl->regmap = axp20x->regmap; | ||
420 | pctl->dev = &pdev->dev; | ||
421 | |||
422 | platform_set_drvdata(pdev, pctl); | ||
423 | |||
424 | axp20x_build_funcs_groups(pdev); | ||
425 | |||
426 | pctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*pctrl_desc), GFP_KERNEL); | ||
427 | if (!pctrl_desc) | ||
428 | return -ENOMEM; | ||
429 | |||
430 | pctrl_desc->name = dev_name(&pdev->dev); | ||
431 | pctrl_desc->owner = THIS_MODULE; | ||
432 | pctrl_desc->pins = pctl->desc->pins; | ||
433 | pctrl_desc->npins = pctl->desc->npins; | ||
434 | pctrl_desc->pctlops = &axp20x_pctrl_ops; | ||
435 | pctrl_desc->pmxops = &axp20x_pmx_ops; | ||
436 | |||
437 | pctl->pctl_dev = devm_pinctrl_register(&pdev->dev, pctrl_desc, pctl); | ||
438 | if (IS_ERR(pctl->pctl_dev)) { | ||
439 | dev_err(&pdev->dev, "couldn't register pinctrl driver\n"); | ||
440 | return PTR_ERR(pctl->pctl_dev); | ||
441 | } | ||
442 | |||
443 | ret = devm_gpiochip_add_data(&pdev->dev, &pctl->chip, pctl); | ||
444 | if (ret) { | ||
445 | dev_err(&pdev->dev, "Failed to register GPIO chip\n"); | ||
446 | return ret; | ||
447 | } | ||
448 | |||
449 | ret = gpiochip_add_pin_range(&pctl->chip, dev_name(&pdev->dev), | ||
450 | pctl->desc->pins->number, | ||
451 | pctl->desc->pins->number, | ||
452 | pctl->desc->npins); | ||
453 | if (ret) { | ||
454 | dev_err(&pdev->dev, "failed to add pin range\n"); | ||
455 | return ret; | ||
456 | } | ||
457 | |||
458 | dev_info(&pdev->dev, "AXP209 pinctrl and GPIO driver loaded\n"); | ||
459 | |||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | static struct platform_driver axp20x_pctl_driver = { | ||
464 | .probe = axp20x_pctl_probe, | ||
465 | .driver = { | ||
466 | .name = "axp20x-gpio", | ||
467 | .of_match_table = axp20x_pctl_match, | ||
468 | }, | ||
469 | }; | ||
470 | |||
471 | module_platform_driver(axp20x_pctl_driver); | ||
472 | |||
473 | MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); | ||
474 | MODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>"); | ||
475 | MODULE_DESCRIPTION("AXP20x PMIC pinctrl and GPIO driver"); | ||
476 | MODULE_LICENSE("GPL"); | ||