diff options
author | Jesper Nilsson <jesper.nilsson@axis.com> | 2017-04-03 08:47:04 -0400 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2017-04-07 05:48:33 -0400 |
commit | 00df0582eab1294d10ca615a8ef645e0bb57a6e3 (patch) | |
tree | 95377862fb395181c05918e30d7c49c20e150d1d | |
parent | 9c6c149be390e02a5ac6ace4efb9f03716431bbe (diff) |
pinctrl: Add pincontrol driver for ARTPEC-6 SoC
Add pinctrl driver support for the Axis ARTPEC-6 SoC.
There are only some pins that actually have different
functions available, but all can control bias (pull-up/-down)
and drive strength.
Code originally written by Chris Paterson.
Signed-off-by: Jesper Nilsson <jesper.nilsson@axis.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
-rw-r--r-- | MAINTAINERS | 1 | ||||
-rw-r--r-- | drivers/pinctrl/Kconfig | 11 | ||||
-rw-r--r-- | drivers/pinctrl/Makefile | 1 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-artpec6.c | 992 |
4 files changed, 1005 insertions, 0 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index ed5731a8f5b8..1d5bc9757dc1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -1088,6 +1088,7 @@ L: linux-arm-kernel@axis.com | |||
1088 | F: arch/arm/mach-artpec | 1088 | F: arch/arm/mach-artpec |
1089 | F: arch/arm/boot/dts/artpec6* | 1089 | F: arch/arm/boot/dts/artpec6* |
1090 | F: drivers/clk/axis | 1090 | F: drivers/clk/axis |
1091 | F: drivers/pinctrl/pinctrl-artpec* | ||
1091 | F: Documentation/devicetree/bindings/pinctrl/axis,artpec6-pinctrl.txt | 1092 | F: Documentation/devicetree/bindings/pinctrl/axis,artpec6-pinctrl.txt |
1092 | 1093 | ||
1093 | ARM/ASPEED MACHINE SUPPORT | 1094 | ARM/ASPEED MACHINE SUPPORT |
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 8f8c2af45781..37af5e3029d5 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig | |||
@@ -41,6 +41,17 @@ config PINCTRL_ADI2 | |||
41 | future processors. This option is selected automatically when specific | 41 | future processors. This option is selected automatically when specific |
42 | machine and arch are selected to build. | 42 | machine and arch are selected to build. |
43 | 43 | ||
44 | config PINCTRL_ARTPEC6 | ||
45 | bool "Axis ARTPEC-6 pin controller driver" | ||
46 | depends on MACH_ARTPEC6 | ||
47 | select PINMUX | ||
48 | select GENERIC_PINCONF | ||
49 | help | ||
50 | This is the driver for the Axis ARTPEC-6 pin controller. This driver | ||
51 | supports pin function multiplexing as well as pin bias and drive | ||
52 | strength configuration. Device tree integration instructions can be | ||
53 | found in Documentation/devicetree/bindings/pinctrl/axis,artpec6-pinctrl.txt | ||
54 | |||
44 | config PINCTRL_AS3722 | 55 | config PINCTRL_AS3722 |
45 | tristate "Pinctrl and GPIO driver for ams AS3722 PMIC" | 56 | tristate "Pinctrl and GPIO driver for ams AS3722 PMIC" |
46 | depends on MFD_AS3722 && GPIOLIB | 57 | depends on MFD_AS3722 && GPIOLIB |
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index a251f439626f..5fc3c1ddd86f 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile | |||
@@ -8,6 +8,7 @@ obj-$(CONFIG_PINCONF) += pinconf.o | |||
8 | obj-$(CONFIG_OF) += devicetree.o | 8 | obj-$(CONFIG_OF) += devicetree.o |
9 | obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o | 9 | obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o |
10 | obj-$(CONFIG_PINCTRL_ADI2) += pinctrl-adi2.o | 10 | obj-$(CONFIG_PINCTRL_ADI2) += pinctrl-adi2.o |
11 | obj-$(CONFIG_PINCTRL_ARTPEC6) += pinctrl-artpec6.o | ||
11 | obj-$(CONFIG_PINCTRL_AS3722) += pinctrl-as3722.o | 12 | obj-$(CONFIG_PINCTRL_AS3722) += pinctrl-as3722.o |
12 | obj-$(CONFIG_PINCTRL_BF54x) += pinctrl-adi2-bf54x.o | 13 | obj-$(CONFIG_PINCTRL_BF54x) += pinctrl-adi2-bf54x.o |
13 | obj-$(CONFIG_PINCTRL_BF60x) += pinctrl-adi2-bf60x.o | 14 | obj-$(CONFIG_PINCTRL_BF60x) += pinctrl-adi2-bf60x.o |
diff --git a/drivers/pinctrl/pinctrl-artpec6.c b/drivers/pinctrl/pinctrl-artpec6.c new file mode 100644 index 000000000000..b5a2eff7ae3d --- /dev/null +++ b/drivers/pinctrl/pinctrl-artpec6.c | |||
@@ -0,0 +1,992 @@ | |||
1 | /* | ||
2 | * Driver for the Axis ARTPEC-6 pin controller | ||
3 | * | ||
4 | * Author: Chris Paterson <chris.paterson@linux.pieboy.co.uk> | ||
5 | * | ||
6 | * This file is licensed under the terms of the GNU General Public | ||
7 | * License version 2. This program is licensed "as is" without any | ||
8 | * warranty of any kind, whether express or implied. | ||
9 | */ | ||
10 | |||
11 | #include <linux/device.h> | ||
12 | #include <linux/err.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/io.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/of.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/pinctrl/pinctrl.h> | ||
19 | #include <linux/pinctrl/pinconf-generic.h> | ||
20 | #include <linux/pinctrl/pinconf.h> | ||
21 | #include <linux/pinctrl/pinmux.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include "core.h" | ||
24 | #include "pinconf.h" | ||
25 | #include "pinctrl-utils.h" | ||
26 | |||
27 | #define ARTPEC6_LAST_PIN 97 /* 97 pins in pinmux */ | ||
28 | #define ARTPEC6_MAX_MUXABLE 35 /* Last pin with muxable function */ | ||
29 | |||
30 | /* Pinmux control register bit definitions */ | ||
31 | #define ARTPEC6_PINMUX_UDC0_MASK 0x00000001 | ||
32 | #define ARTPEC6_PINMUX_UDC0_SHIFT 0 | ||
33 | #define ARTPEC6_PINMUX_UDC1_MASK 0x00000002 | ||
34 | #define ARTPEC6_PINMUX_UDC1_SHIFT 1 | ||
35 | #define ARTPEC6_PINMUX_DRV_MASK 0x00000060 | ||
36 | #define ARTPEC6_PINMUX_DRV_SHIFT 5 | ||
37 | #define ARTPEC6_PINMUX_SEL_MASK 0x00003000 | ||
38 | #define ARTPEC6_PINMUX_SEL_SHIFT 12 | ||
39 | |||
40 | /* Pinmux configurations */ | ||
41 | #define ARTPEC6_CONFIG_0 0 | ||
42 | #define ARTPEC6_CONFIG_1 1 | ||
43 | #define ARTPEC6_CONFIG_2 2 | ||
44 | #define ARTPEC6_CONFIG_3 3 | ||
45 | |||
46 | /* Pin drive strength options */ | ||
47 | #define ARTPEC6_DRIVE_4mA 4 | ||
48 | #define ARTPEC6_DRIVE_4mA_SET 0 | ||
49 | #define ARTPEC6_DRIVE_6mA 6 | ||
50 | #define ARTPEC6_DRIVE_6mA_SET 1 | ||
51 | #define ARTPEC6_DRIVE_8mA 8 | ||
52 | #define ARTPEC6_DRIVE_8mA_SET 2 | ||
53 | #define ARTPEC6_DRIVE_9mA 9 | ||
54 | #define ARTPEC6_DRIVE_9mA_SET 3 | ||
55 | |||
56 | struct artpec6_pmx { | ||
57 | struct device *dev; | ||
58 | struct pinctrl_dev *pctl; | ||
59 | void __iomem *base; | ||
60 | struct pinctrl_pin_desc *pins; | ||
61 | unsigned int num_pins; | ||
62 | const struct artpec6_pin_group *pin_groups; | ||
63 | unsigned int num_pin_groups; | ||
64 | const struct artpec6_pmx_func *functions; | ||
65 | unsigned int num_functions; | ||
66 | }; | ||
67 | |||
68 | struct artpec6_pin_group { | ||
69 | const char *name; | ||
70 | const unsigned int *pins; | ||
71 | const unsigned int num_pins; | ||
72 | unsigned char config; | ||
73 | }; | ||
74 | |||
75 | struct artpec6_pmx_func { | ||
76 | const char *name; | ||
77 | const char * const *groups; | ||
78 | const unsigned int num_groups; | ||
79 | }; | ||
80 | |||
81 | /* pins */ | ||
82 | static struct pinctrl_pin_desc artpec6_pins[] = { | ||
83 | PINCTRL_PIN(0, "GPIO0"), | ||
84 | PINCTRL_PIN(1, "GPIO1"), | ||
85 | PINCTRL_PIN(2, "GPIO2"), | ||
86 | PINCTRL_PIN(3, "GPIO3"), | ||
87 | PINCTRL_PIN(4, "GPIO4"), | ||
88 | PINCTRL_PIN(5, "GPIO5"), | ||
89 | PINCTRL_PIN(6, "GPIO6"), | ||
90 | PINCTRL_PIN(7, "GPIO7"), | ||
91 | PINCTRL_PIN(8, "GPIO8"), | ||
92 | PINCTRL_PIN(9, "GPIO9"), | ||
93 | PINCTRL_PIN(10, "GPIO10"), | ||
94 | PINCTRL_PIN(11, "GPIO11"), | ||
95 | PINCTRL_PIN(12, "GPIO12"), | ||
96 | PINCTRL_PIN(13, "GPIO13"), | ||
97 | PINCTRL_PIN(14, "GPIO14"), | ||
98 | PINCTRL_PIN(15, "GPIO15"), | ||
99 | PINCTRL_PIN(16, "GPIO16"), | ||
100 | PINCTRL_PIN(17, "GPIO17"), | ||
101 | PINCTRL_PIN(18, "GPIO18"), | ||
102 | PINCTRL_PIN(19, "GPIO19"), | ||
103 | PINCTRL_PIN(20, "GPIO20"), | ||
104 | PINCTRL_PIN(21, "GPIO21"), | ||
105 | PINCTRL_PIN(22, "GPIO22"), | ||
106 | PINCTRL_PIN(23, "GPIO23"), | ||
107 | PINCTRL_PIN(24, "GPIO24"), | ||
108 | PINCTRL_PIN(25, "GPIO25"), | ||
109 | PINCTRL_PIN(26, "GPIO26"), | ||
110 | PINCTRL_PIN(27, "GPIO27"), | ||
111 | PINCTRL_PIN(28, "GPIO28"), | ||
112 | PINCTRL_PIN(29, "GPIO29"), | ||
113 | PINCTRL_PIN(30, "GPIO30"), | ||
114 | PINCTRL_PIN(31, "GPIO31"), | ||
115 | PINCTRL_PIN(32, "UART3_TXD"), | ||
116 | PINCTRL_PIN(33, "UART3_RXD"), | ||
117 | PINCTRL_PIN(34, "UART3_RTS"), | ||
118 | PINCTRL_PIN(35, "UART3_CTS"), | ||
119 | PINCTRL_PIN(36, "NF_ALE"), | ||
120 | PINCTRL_PIN(37, "NF_CE0_N"), | ||
121 | PINCTRL_PIN(38, "NF_CE1_N"), | ||
122 | PINCTRL_PIN(39, "NF_CLE"), | ||
123 | PINCTRL_PIN(40, "NF_RE_N"), | ||
124 | PINCTRL_PIN(41, "NF_WE_N"), | ||
125 | PINCTRL_PIN(42, "NF_WP0_N"), | ||
126 | PINCTRL_PIN(43, "NF_WP1_N"), | ||
127 | PINCTRL_PIN(44, "NF_IO0"), | ||
128 | PINCTRL_PIN(45, "NF_IO1"), | ||
129 | PINCTRL_PIN(46, "NF_IO2"), | ||
130 | PINCTRL_PIN(47, "NF_IO3"), | ||
131 | PINCTRL_PIN(48, "NF_IO4"), | ||
132 | PINCTRL_PIN(49, "NF_IO5"), | ||
133 | PINCTRL_PIN(50, "NF_IO6"), | ||
134 | PINCTRL_PIN(51, "NF_IO7"), | ||
135 | PINCTRL_PIN(52, "NF_RB0_N"), | ||
136 | PINCTRL_PIN(53, "SDIO0_CLK"), | ||
137 | PINCTRL_PIN(54, "SDIO0_CMD"), | ||
138 | PINCTRL_PIN(55, "SDIO0_DAT0"), | ||
139 | PINCTRL_PIN(56, "SDIO0_DAT1"), | ||
140 | PINCTRL_PIN(57, "SDIO0_DAT2"), | ||
141 | PINCTRL_PIN(58, "SDIO0_DAT3"), | ||
142 | PINCTRL_PIN(59, "SDI0_CD"), | ||
143 | PINCTRL_PIN(60, "SDI0_WP"), | ||
144 | PINCTRL_PIN(61, "SDIO1_CLK"), | ||
145 | PINCTRL_PIN(62, "SDIO1_CMD"), | ||
146 | PINCTRL_PIN(63, "SDIO1_DAT0"), | ||
147 | PINCTRL_PIN(64, "SDIO1_DAT1"), | ||
148 | PINCTRL_PIN(65, "SDIO1_DAT2"), | ||
149 | PINCTRL_PIN(66, "SDIO1_DAT3"), | ||
150 | PINCTRL_PIN(67, "SDIO1_CD"), | ||
151 | PINCTRL_PIN(68, "SDIO1_WP"), | ||
152 | PINCTRL_PIN(69, "GBE_REFCLk"), | ||
153 | PINCTRL_PIN(70, "GBE_GTX_CLK"), | ||
154 | PINCTRL_PIN(71, "GBE_TX_CLK"), | ||
155 | PINCTRL_PIN(72, "GBE_TX_EN"), | ||
156 | PINCTRL_PIN(73, "GBE_TX_ER"), | ||
157 | PINCTRL_PIN(74, "GBE_TXD0"), | ||
158 | PINCTRL_PIN(75, "GBE_TXD1"), | ||
159 | PINCTRL_PIN(76, "GBE_TXD2"), | ||
160 | PINCTRL_PIN(77, "GBE_TXD3"), | ||
161 | PINCTRL_PIN(78, "GBE_TXD4"), | ||
162 | PINCTRL_PIN(79, "GBE_TXD5"), | ||
163 | PINCTRL_PIN(80, "GBE_TXD6"), | ||
164 | PINCTRL_PIN(81, "GBE_TXD7"), | ||
165 | PINCTRL_PIN(82, "GBE_RX_CLK"), | ||
166 | PINCTRL_PIN(83, "GBE_RX_DV"), | ||
167 | PINCTRL_PIN(84, "GBE_RX_ER"), | ||
168 | PINCTRL_PIN(85, "GBE_RXD0"), | ||
169 | PINCTRL_PIN(86, "GBE_RXD1"), | ||
170 | PINCTRL_PIN(87, "GBE_RXD2"), | ||
171 | PINCTRL_PIN(88, "GBE_RXD3"), | ||
172 | PINCTRL_PIN(89, "GBE_RXD4"), | ||
173 | PINCTRL_PIN(90, "GBE_RXD5"), | ||
174 | PINCTRL_PIN(91, "GBE_RXD6"), | ||
175 | PINCTRL_PIN(92, "GBE_RXD7"), | ||
176 | PINCTRL_PIN(93, "GBE_CRS"), | ||
177 | PINCTRL_PIN(94, "GBE_COL"), | ||
178 | PINCTRL_PIN(95, "GBE_MDC"), | ||
179 | PINCTRL_PIN(96, "GBE_MDIO"), | ||
180 | }; | ||
181 | |||
182 | static const unsigned int cpuclkout_pins0[] = { 0 }; | ||
183 | static const unsigned int udlclkout_pins0[] = { 1 }; | ||
184 | static const unsigned int i2c1_pins0[] = { 2, 3 }; | ||
185 | static const unsigned int i2c2_pins0[] = { 4, 5 }; | ||
186 | static const unsigned int i2c3_pins0[] = { 6, 7 }; | ||
187 | static const unsigned int i2s0_pins0[] = { 8, 9, 10, 11 }; | ||
188 | static const unsigned int i2s1_pins0[] = { 12, 13, 14, 15 }; | ||
189 | static const unsigned int i2srefclk_pins0[] = { 19 }; | ||
190 | static const unsigned int spi0_pins0[] = { 12, 13, 14, 15 }; | ||
191 | static const unsigned int spi1_pins0[] = { 16, 17, 18, 19 }; | ||
192 | static const unsigned int pciedebug_pins0[] = { 12, 13, 14, 15 }; | ||
193 | static const unsigned int uart0_pins0[] = { 16, 17, 18, 19, 20, | ||
194 | 21, 22, 23, 24, 25 }; | ||
195 | static const unsigned int uart0_pins1[] = { 20, 21, 22, 23 }; | ||
196 | static const unsigned int uart1_pins0[] = { 24, 25, 26, 27 }; | ||
197 | static const unsigned int uart2_pins0[] = { 26, 27, 28, 29, 30, | ||
198 | 31, 32, 33, 34, 35 }; | ||
199 | static const unsigned int uart2_pins1[] = { 28, 29, 30, 31 }; | ||
200 | static const unsigned int uart3_pins0[] = { 32, 33, 34, 35 }; | ||
201 | static const unsigned int uart4_pins0[] = { 20, 21, 22, 23 }; | ||
202 | static const unsigned int uart5_pins0[] = { 28, 29, 30, 31 }; | ||
203 | static const unsigned int nand_pins0[] = { 36, 37, 38, 39, 40, 41, | ||
204 | 42, 43, 44, 45, 46, 47, | ||
205 | 48, 49, 50, 51, 52 }; | ||
206 | static const unsigned int sdio0_pins0[] = { 53, 54, 55, 56, 57, 58, 59, 60 }; | ||
207 | static const unsigned int sdio1_pins0[] = { 61, 62, 63, 64, 65, 66, 67, 68 }; | ||
208 | static const unsigned int ethernet_pins0[] = { 69, 70, 71, 72, 73, 74, 75, | ||
209 | 76, 77, 78, 79, 80, 81, 82, | ||
210 | 83, 84, 85, 86, 87, 88, 89, | ||
211 | 90, 91, 92, 93, 94, 95, 96 }; | ||
212 | |||
213 | static const struct artpec6_pin_group artpec6_pin_groups[] = { | ||
214 | { | ||
215 | .name = "cpuclkoutgrp0", | ||
216 | .pins = cpuclkout_pins0, | ||
217 | .num_pins = ARRAY_SIZE(cpuclkout_pins0), | ||
218 | .config = ARTPEC6_CONFIG_1, | ||
219 | }, | ||
220 | { | ||
221 | .name = "udlclkoutgrp0", | ||
222 | .pins = udlclkout_pins0, | ||
223 | .num_pins = ARRAY_SIZE(udlclkout_pins0), | ||
224 | .config = ARTPEC6_CONFIG_1, | ||
225 | }, | ||
226 | { | ||
227 | .name = "i2c1grp0", | ||
228 | .pins = i2c1_pins0, | ||
229 | .num_pins = ARRAY_SIZE(i2c1_pins0), | ||
230 | .config = ARTPEC6_CONFIG_1, | ||
231 | }, | ||
232 | { | ||
233 | .name = "i2c2grp0", | ||
234 | .pins = i2c2_pins0, | ||
235 | .num_pins = ARRAY_SIZE(i2c2_pins0), | ||
236 | .config = ARTPEC6_CONFIG_1, | ||
237 | }, | ||
238 | { | ||
239 | .name = "i2c3grp0", | ||
240 | .pins = i2c3_pins0, | ||
241 | .num_pins = ARRAY_SIZE(i2c3_pins0), | ||
242 | .config = ARTPEC6_CONFIG_1, | ||
243 | }, | ||
244 | { | ||
245 | .name = "i2s0grp0", | ||
246 | .pins = i2s0_pins0, | ||
247 | .num_pins = ARRAY_SIZE(i2s0_pins0), | ||
248 | .config = ARTPEC6_CONFIG_1, | ||
249 | }, | ||
250 | { | ||
251 | .name = "i2s1grp0", | ||
252 | .pins = i2s1_pins0, | ||
253 | .num_pins = ARRAY_SIZE(i2s1_pins0), | ||
254 | .config = ARTPEC6_CONFIG_1, | ||
255 | }, | ||
256 | { | ||
257 | .name = "i2srefclkgrp0", | ||
258 | .pins = i2srefclk_pins0, | ||
259 | .num_pins = ARRAY_SIZE(i2srefclk_pins0), | ||
260 | .config = ARTPEC6_CONFIG_3, | ||
261 | }, | ||
262 | { | ||
263 | .name = "spi0grp0", | ||
264 | .pins = spi0_pins0, | ||
265 | .num_pins = ARRAY_SIZE(spi0_pins0), | ||
266 | .config = ARTPEC6_CONFIG_2, | ||
267 | }, | ||
268 | { | ||
269 | .name = "spi1grp0", | ||
270 | .pins = spi1_pins0, | ||
271 | .num_pins = ARRAY_SIZE(spi1_pins0), | ||
272 | .config = ARTPEC6_CONFIG_2, | ||
273 | }, | ||
274 | { | ||
275 | .name = "pciedebuggrp0", | ||
276 | .pins = pciedebug_pins0, | ||
277 | .num_pins = ARRAY_SIZE(pciedebug_pins0), | ||
278 | .config = ARTPEC6_CONFIG_3, | ||
279 | }, | ||
280 | { | ||
281 | .name = "uart0grp0", | ||
282 | .pins = uart0_pins0, | ||
283 | .num_pins = ARRAY_SIZE(uart0_pins0), | ||
284 | .config = ARTPEC6_CONFIG_1, | ||
285 | }, | ||
286 | { | ||
287 | .name = "uart0grp1", | ||
288 | .pins = uart0_pins1, | ||
289 | .num_pins = ARRAY_SIZE(uart0_pins1), | ||
290 | .config = ARTPEC6_CONFIG_1, | ||
291 | }, | ||
292 | { | ||
293 | .name = "uart1grp0", | ||
294 | .pins = uart1_pins0, | ||
295 | .num_pins = ARRAY_SIZE(uart1_pins0), | ||
296 | .config = ARTPEC6_CONFIG_2, | ||
297 | }, | ||
298 | { | ||
299 | .name = "uart2grp0", | ||
300 | .pins = uart2_pins0, | ||
301 | .num_pins = ARRAY_SIZE(uart2_pins0), | ||
302 | .config = ARTPEC6_CONFIG_1, | ||
303 | }, | ||
304 | { | ||
305 | .name = "uart2grp1", | ||
306 | .pins = uart2_pins1, | ||
307 | .num_pins = ARRAY_SIZE(uart2_pins1), | ||
308 | .config = ARTPEC6_CONFIG_1, | ||
309 | }, | ||
310 | { | ||
311 | .name = "uart3grp0", | ||
312 | .pins = uart3_pins0, | ||
313 | .num_pins = ARRAY_SIZE(uart3_pins0), | ||
314 | .config = ARTPEC6_CONFIG_0, | ||
315 | }, | ||
316 | { | ||
317 | .name = "uart4grp0", | ||
318 | .pins = uart4_pins0, | ||
319 | .num_pins = ARRAY_SIZE(uart4_pins0), | ||
320 | .config = ARTPEC6_CONFIG_2, | ||
321 | }, | ||
322 | { | ||
323 | .name = "uart5grp0", | ||
324 | .pins = uart5_pins0, | ||
325 | .num_pins = ARRAY_SIZE(uart5_pins0), | ||
326 | .config = ARTPEC6_CONFIG_2, | ||
327 | }, | ||
328 | { | ||
329 | .name = "uart5nocts", | ||
330 | .pins = uart5_pins0, | ||
331 | .num_pins = ARRAY_SIZE(uart5_pins0) - 1, | ||
332 | .config = ARTPEC6_CONFIG_2, | ||
333 | }, | ||
334 | { | ||
335 | .name = "nandgrp0", | ||
336 | .pins = nand_pins0, | ||
337 | .num_pins = ARRAY_SIZE(nand_pins0), | ||
338 | .config = ARTPEC6_CONFIG_0, | ||
339 | }, | ||
340 | { | ||
341 | .name = "sdio0grp0", | ||
342 | .pins = sdio0_pins0, | ||
343 | .num_pins = ARRAY_SIZE(sdio0_pins0), | ||
344 | .config = ARTPEC6_CONFIG_0, | ||
345 | }, | ||
346 | { | ||
347 | .name = "sdio1grp0", | ||
348 | .pins = sdio1_pins0, | ||
349 | .num_pins = ARRAY_SIZE(sdio1_pins0), | ||
350 | .config = ARTPEC6_CONFIG_0, | ||
351 | }, | ||
352 | { | ||
353 | .name = "ethernetgrp0", | ||
354 | .pins = ethernet_pins0, | ||
355 | .num_pins = ARRAY_SIZE(ethernet_pins0), | ||
356 | .config = ARTPEC6_CONFIG_0, | ||
357 | }, | ||
358 | }; | ||
359 | |||
360 | struct pin_register { | ||
361 | unsigned int start; | ||
362 | unsigned int end; | ||
363 | unsigned int reg_base; | ||
364 | }; | ||
365 | |||
366 | /* | ||
367 | * The register map has two holes where the pin number | ||
368 | * no longer fits directly with the register offset. | ||
369 | * This table allows us to map this easily. | ||
370 | */ | ||
371 | static const struct pin_register pin_register[] = { | ||
372 | { 0, 35, 0x0 }, /* 0x0 - 0x8c */ | ||
373 | { 36, 52, 0x100 }, /* 0x100 - 0x140 */ | ||
374 | { 53, 96, 0x180 }, /* 0x180 - 0x22c */ | ||
375 | }; | ||
376 | |||
377 | static unsigned int artpec6_pmx_reg_offset(unsigned int pin) | ||
378 | { | ||
379 | int i; | ||
380 | |||
381 | for (i = 0; i < ARRAY_SIZE(pin_register); i++) { | ||
382 | if (pin <= pin_register[i].end) { | ||
383 | return (pin - pin_register[i].start) * 4 + | ||
384 | pin_register[i].reg_base; | ||
385 | } | ||
386 | } | ||
387 | /* | ||
388 | * Anything we return here is wrong, but we can only | ||
389 | * get here if pin is outside registered range. | ||
390 | */ | ||
391 | pr_err("%s: Impossible pin %d\n", __func__, pin); | ||
392 | return 0; | ||
393 | } | ||
394 | |||
395 | static int artpec6_get_groups_count(struct pinctrl_dev *pctldev) | ||
396 | { | ||
397 | return ARRAY_SIZE(artpec6_pin_groups); | ||
398 | } | ||
399 | |||
400 | static const char *artpec6_get_group_name(struct pinctrl_dev *pctldev, | ||
401 | unsigned int group) | ||
402 | { | ||
403 | return artpec6_pin_groups[group].name; | ||
404 | } | ||
405 | |||
406 | static int artpec6_get_group_pins(struct pinctrl_dev *pctldev, | ||
407 | unsigned int group, | ||
408 | const unsigned int **pins, | ||
409 | unsigned int *num_pins) | ||
410 | { | ||
411 | *pins = (unsigned int *)artpec6_pin_groups[group].pins; | ||
412 | *num_pins = artpec6_pin_groups[group].num_pins; | ||
413 | return 0; | ||
414 | } | ||
415 | |||
416 | static int artpec6_pconf_drive_mA_to_field(unsigned int mA) | ||
417 | { | ||
418 | switch (mA) { | ||
419 | case ARTPEC6_DRIVE_4mA: | ||
420 | return ARTPEC6_DRIVE_4mA_SET; | ||
421 | case ARTPEC6_DRIVE_6mA: | ||
422 | return ARTPEC6_DRIVE_6mA_SET; | ||
423 | case ARTPEC6_DRIVE_8mA: | ||
424 | return ARTPEC6_DRIVE_8mA_SET; | ||
425 | case ARTPEC6_DRIVE_9mA: | ||
426 | return ARTPEC6_DRIVE_9mA_SET; | ||
427 | default: | ||
428 | return -EINVAL; | ||
429 | } | ||
430 | } | ||
431 | |||
432 | static unsigned int artpec6_pconf_drive_field_to_mA(int field) | ||
433 | { | ||
434 | switch (field) { | ||
435 | case ARTPEC6_DRIVE_4mA_SET: | ||
436 | return ARTPEC6_DRIVE_4mA; | ||
437 | case ARTPEC6_DRIVE_6mA_SET: | ||
438 | return ARTPEC6_DRIVE_6mA; | ||
439 | case ARTPEC6_DRIVE_8mA_SET: | ||
440 | return ARTPEC6_DRIVE_8mA; | ||
441 | case ARTPEC6_DRIVE_9mA_SET: | ||
442 | return ARTPEC6_DRIVE_9mA; | ||
443 | default: | ||
444 | /* Shouldn't happen */ | ||
445 | return 0; | ||
446 | } | ||
447 | } | ||
448 | |||
449 | static struct pinctrl_ops artpec6_pctrl_ops = { | ||
450 | .get_group_pins = artpec6_get_group_pins, | ||
451 | .get_groups_count = artpec6_get_groups_count, | ||
452 | .get_group_name = artpec6_get_group_name, | ||
453 | .dt_node_to_map = pinconf_generic_dt_node_to_map_all, | ||
454 | .dt_free_map = pinctrl_utils_free_map, | ||
455 | }; | ||
456 | |||
457 | static const char * const gpiogrps[] = { | ||
458 | "cpuclkoutgrp0", "udlclkoutgrp0", "i2c1grp0", "i2c2grp0", | ||
459 | "i2c3grp0", "i2s0grp0", "i2s1grp0", "i2srefclkgrp0", | ||
460 | "spi0grp0", "spi1grp0", "pciedebuggrp0", "uart0grp0", | ||
461 | "uart0grp1", "uart1grp0", "uart2grp0", "uart2grp1", | ||
462 | "uart4grp0", "uart5grp0", | ||
463 | }; | ||
464 | static const char * const cpuclkoutgrps[] = { "cpuclkoutgrp0" }; | ||
465 | static const char * const udlclkoutgrps[] = { "udlclkoutgrp0" }; | ||
466 | static const char * const i2c1grps[] = { "i2c1grp0" }; | ||
467 | static const char * const i2c2grps[] = { "i2c2grp0" }; | ||
468 | static const char * const i2c3grps[] = { "i2c3grp0" }; | ||
469 | static const char * const i2s0grps[] = { "i2s0grp0" }; | ||
470 | static const char * const i2s1grps[] = { "i2s1grp0" }; | ||
471 | static const char * const i2srefclkgrps[] = { "i2srefclkgrp0" }; | ||
472 | static const char * const spi0grps[] = { "spi0grp0" }; | ||
473 | static const char * const spi1grps[] = { "spi1grp0" }; | ||
474 | static const char * const pciedebuggrps[] = { "pciedebuggrp0" }; | ||
475 | static const char * const uart0grps[] = { "uart0grp0", "uart0grp1" }; | ||
476 | static const char * const uart1grps[] = { "uart1grp0" }; | ||
477 | static const char * const uart2grps[] = { "uart2grp0", "uart2grp1" }; | ||
478 | static const char * const uart3grps[] = { "uart3grp0" }; | ||
479 | static const char * const uart4grps[] = { "uart4grp0" }; | ||
480 | static const char * const uart5grps[] = { "uart5grp0", "uart5nocts" }; | ||
481 | static const char * const nandgrps[] = { "nandgrp0" }; | ||
482 | static const char * const sdio0grps[] = { "sdio0grp0" }; | ||
483 | static const char * const sdio1grps[] = { "sdio1grp0" }; | ||
484 | static const char * const ethernetgrps[] = { "ethernetgrp0" }; | ||
485 | |||
486 | static const struct artpec6_pmx_func artpec6_pmx_functions[] = { | ||
487 | { | ||
488 | .name = "gpio", | ||
489 | .groups = gpiogrps, | ||
490 | .num_groups = ARRAY_SIZE(gpiogrps), | ||
491 | }, | ||
492 | { | ||
493 | .name = "cpuclkout", | ||
494 | .groups = cpuclkoutgrps, | ||
495 | .num_groups = ARRAY_SIZE(cpuclkoutgrps), | ||
496 | }, | ||
497 | { | ||
498 | .name = "udlclkout", | ||
499 | .groups = udlclkoutgrps, | ||
500 | .num_groups = ARRAY_SIZE(udlclkoutgrps), | ||
501 | }, | ||
502 | { | ||
503 | .name = "i2c1", | ||
504 | .groups = i2c1grps, | ||
505 | .num_groups = ARRAY_SIZE(i2c1grps), | ||
506 | }, | ||
507 | { | ||
508 | .name = "i2c2", | ||
509 | .groups = i2c2grps, | ||
510 | .num_groups = ARRAY_SIZE(i2c2grps), | ||
511 | }, | ||
512 | { | ||
513 | .name = "i2c3", | ||
514 | .groups = i2c3grps, | ||
515 | .num_groups = ARRAY_SIZE(i2c3grps), | ||
516 | }, | ||
517 | { | ||
518 | .name = "i2s0", | ||
519 | .groups = i2s0grps, | ||
520 | .num_groups = ARRAY_SIZE(i2s0grps), | ||
521 | }, | ||
522 | { | ||
523 | .name = "i2s1", | ||
524 | .groups = i2s1grps, | ||
525 | .num_groups = ARRAY_SIZE(i2s1grps), | ||
526 | }, | ||
527 | { | ||
528 | .name = "i2srefclk", | ||
529 | .groups = i2srefclkgrps, | ||
530 | .num_groups = ARRAY_SIZE(i2srefclkgrps), | ||
531 | }, | ||
532 | { | ||
533 | .name = "spi0", | ||
534 | .groups = spi0grps, | ||
535 | .num_groups = ARRAY_SIZE(spi0grps), | ||
536 | }, | ||
537 | { | ||
538 | .name = "spi1", | ||
539 | .groups = spi1grps, | ||
540 | .num_groups = ARRAY_SIZE(spi1grps), | ||
541 | }, | ||
542 | { | ||
543 | .name = "pciedebug", | ||
544 | .groups = pciedebuggrps, | ||
545 | .num_groups = ARRAY_SIZE(pciedebuggrps), | ||
546 | }, | ||
547 | { | ||
548 | .name = "uart0", | ||
549 | .groups = uart0grps, | ||
550 | .num_groups = ARRAY_SIZE(uart0grps), | ||
551 | }, | ||
552 | { | ||
553 | .name = "uart1", | ||
554 | .groups = uart1grps, | ||
555 | .num_groups = ARRAY_SIZE(uart1grps), | ||
556 | }, | ||
557 | { | ||
558 | .name = "uart2", | ||
559 | .groups = uart2grps, | ||
560 | .num_groups = ARRAY_SIZE(uart2grps), | ||
561 | }, | ||
562 | { | ||
563 | .name = "uart3", | ||
564 | .groups = uart3grps, | ||
565 | .num_groups = ARRAY_SIZE(uart3grps), | ||
566 | }, | ||
567 | { | ||
568 | .name = "uart4", | ||
569 | .groups = uart4grps, | ||
570 | .num_groups = ARRAY_SIZE(uart4grps), | ||
571 | }, | ||
572 | { | ||
573 | .name = "uart5", | ||
574 | .groups = uart5grps, | ||
575 | .num_groups = ARRAY_SIZE(uart5grps), | ||
576 | }, | ||
577 | { | ||
578 | .name = "nand", | ||
579 | .groups = nandgrps, | ||
580 | .num_groups = ARRAY_SIZE(nandgrps), | ||
581 | }, | ||
582 | { | ||
583 | .name = "sdio0", | ||
584 | .groups = sdio0grps, | ||
585 | .num_groups = ARRAY_SIZE(sdio0grps), | ||
586 | }, | ||
587 | { | ||
588 | .name = "sdio1", | ||
589 | .groups = sdio1grps, | ||
590 | .num_groups = ARRAY_SIZE(sdio1grps), | ||
591 | }, | ||
592 | { | ||
593 | .name = "ethernet", | ||
594 | .groups = ethernetgrps, | ||
595 | .num_groups = ARRAY_SIZE(ethernetgrps), | ||
596 | }, | ||
597 | }; | ||
598 | |||
599 | static int artpec6_pmx_get_functions_count(struct pinctrl_dev *pctldev) | ||
600 | { | ||
601 | return ARRAY_SIZE(artpec6_pmx_functions); | ||
602 | } | ||
603 | |||
604 | static const char *artpec6_pmx_get_fname(struct pinctrl_dev *pctldev, | ||
605 | unsigned int function) | ||
606 | { | ||
607 | return artpec6_pmx_functions[function].name; | ||
608 | } | ||
609 | |||
610 | static int artpec6_pmx_get_fgroups(struct pinctrl_dev *pctldev, | ||
611 | unsigned int function, | ||
612 | const char * const **groups, | ||
613 | unsigned int * const num_groups) | ||
614 | { | ||
615 | *groups = artpec6_pmx_functions[function].groups; | ||
616 | *num_groups = artpec6_pmx_functions[function].num_groups; | ||
617 | return 0; | ||
618 | } | ||
619 | |||
620 | static void artpec6_pmx_select_func(struct pinctrl_dev *pctldev, | ||
621 | unsigned int function, unsigned int group, | ||
622 | bool enable) | ||
623 | { | ||
624 | unsigned int regval, val; | ||
625 | unsigned int reg; | ||
626 | int i; | ||
627 | struct artpec6_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); | ||
628 | |||
629 | for (i = 0; i < artpec6_pin_groups[group].num_pins; i++) { | ||
630 | /* | ||
631 | * Registers for pins above a ARTPEC6_MAX_MUXABLE | ||
632 | * do not have a SEL field and are always selected. | ||
633 | */ | ||
634 | if (artpec6_pin_groups[group].pins[i] > ARTPEC6_MAX_MUXABLE) | ||
635 | continue; | ||
636 | |||
637 | if (!strcmp(artpec6_pmx_get_fname(pctldev, function), "gpio")) { | ||
638 | /* GPIO is always config 0 */ | ||
639 | val = ARTPEC6_CONFIG_0 << ARTPEC6_PINMUX_SEL_SHIFT; | ||
640 | } else { | ||
641 | if (enable) | ||
642 | val = artpec6_pin_groups[group].config | ||
643 | << ARTPEC6_PINMUX_SEL_SHIFT; | ||
644 | else | ||
645 | val = ARTPEC6_CONFIG_0 | ||
646 | << ARTPEC6_PINMUX_SEL_SHIFT; | ||
647 | } | ||
648 | |||
649 | reg = artpec6_pmx_reg_offset(artpec6_pin_groups[group].pins[i]); | ||
650 | |||
651 | regval = readl(pmx->base + reg); | ||
652 | regval &= ~ARTPEC6_PINMUX_SEL_MASK; | ||
653 | regval |= val; | ||
654 | writel(regval, pmx->base + reg); | ||
655 | } | ||
656 | } | ||
657 | |||
658 | int artpec6_pmx_enable(struct pinctrl_dev *pctldev, unsigned int function, | ||
659 | unsigned int group) | ||
660 | { | ||
661 | struct artpec6_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); | ||
662 | |||
663 | dev_dbg(pmx->dev, "enabling %s function for pin group %s\n", | ||
664 | artpec6_pmx_get_fname(pctldev, function), | ||
665 | artpec6_get_group_name(pctldev, group)); | ||
666 | |||
667 | artpec6_pmx_select_func(pctldev, function, group, true); | ||
668 | |||
669 | return 0; | ||
670 | } | ||
671 | |||
672 | void artpec6_pmx_disable(struct pinctrl_dev *pctldev, unsigned int function, | ||
673 | unsigned int group) | ||
674 | { | ||
675 | struct artpec6_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); | ||
676 | |||
677 | dev_dbg(pmx->dev, "disabling %s function for pin group %s\n", | ||
678 | artpec6_pmx_get_fname(pctldev, function), | ||
679 | artpec6_get_group_name(pctldev, group)); | ||
680 | |||
681 | artpec6_pmx_select_func(pctldev, function, group, false); | ||
682 | } | ||
683 | |||
684 | static int artpec6_pmx_request_gpio(struct pinctrl_dev *pctldev, | ||
685 | struct pinctrl_gpio_range *range, | ||
686 | unsigned int pin) | ||
687 | { | ||
688 | struct artpec6_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); | ||
689 | unsigned int reg = artpec6_pmx_reg_offset(pin); | ||
690 | u32 val; | ||
691 | |||
692 | if (pin >= 32) | ||
693 | return -EINVAL; | ||
694 | |||
695 | val = readl_relaxed(pmx->base + reg); | ||
696 | val &= ~ARTPEC6_PINMUX_SEL_MASK; | ||
697 | val |= ARTPEC6_CONFIG_0 << ARTPEC6_PINMUX_SEL_SHIFT; | ||
698 | writel_relaxed(val, pmx->base + reg); | ||
699 | |||
700 | return 0; | ||
701 | } | ||
702 | |||
703 | static const struct pinmux_ops artpec6_pmx_ops = { | ||
704 | .get_functions_count = artpec6_pmx_get_functions_count, | ||
705 | .get_function_name = artpec6_pmx_get_fname, | ||
706 | .get_function_groups = artpec6_pmx_get_fgroups, | ||
707 | .set_mux = artpec6_pmx_enable, | ||
708 | .gpio_request_enable = artpec6_pmx_request_gpio, | ||
709 | }; | ||
710 | |||
711 | static int artpec6_pconf_get(struct pinctrl_dev *pctldev, unsigned int pin, | ||
712 | unsigned long *config) | ||
713 | { | ||
714 | struct artpec6_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); | ||
715 | enum pin_config_param param = pinconf_to_config_param(*config); | ||
716 | unsigned int regval; | ||
717 | |||
718 | /* Check for valid pin */ | ||
719 | if (pin >= pmx->num_pins) { | ||
720 | dev_dbg(pmx->dev, "pinconf is not supported for pin %s\n", | ||
721 | pmx->pins[pin].name); | ||
722 | return -ENOTSUPP; | ||
723 | } | ||
724 | |||
725 | dev_dbg(pmx->dev, "getting configuration for pin %s\n", | ||
726 | pmx->pins[pin].name); | ||
727 | |||
728 | /* Read pin register values */ | ||
729 | regval = readl(pmx->base + artpec6_pmx_reg_offset(pin)); | ||
730 | |||
731 | /* If valid, get configuration for parameter */ | ||
732 | switch (param) { | ||
733 | case PIN_CONFIG_BIAS_DISABLE: | ||
734 | if (!(regval & ARTPEC6_PINMUX_UDC1_MASK)) | ||
735 | return -EINVAL; | ||
736 | break; | ||
737 | |||
738 | case PIN_CONFIG_BIAS_PULL_UP: | ||
739 | case PIN_CONFIG_BIAS_PULL_DOWN: | ||
740 | if (regval & ARTPEC6_PINMUX_UDC1_MASK) | ||
741 | return -EINVAL; | ||
742 | |||
743 | regval = regval & ARTPEC6_PINMUX_UDC0_MASK; | ||
744 | if ((param == PIN_CONFIG_BIAS_PULL_UP && !regval) || | ||
745 | (param == PIN_CONFIG_BIAS_PULL_DOWN && regval)) | ||
746 | return -EINVAL; | ||
747 | break; | ||
748 | case PIN_CONFIG_DRIVE_STRENGTH: | ||
749 | regval = (regval & ARTPEC6_PINMUX_DRV_MASK) | ||
750 | >> ARTPEC6_PINMUX_DRV_SHIFT; | ||
751 | regval = artpec6_pconf_drive_field_to_mA(regval); | ||
752 | *config = pinconf_to_config_packed(param, regval); | ||
753 | break; | ||
754 | default: | ||
755 | return -ENOTSUPP; | ||
756 | } | ||
757 | |||
758 | return 0; | ||
759 | } | ||
760 | |||
761 | /* | ||
762 | * Valid combinations of param and arg: | ||
763 | * | ||
764 | * param arg | ||
765 | * PIN_CONFIG_BIAS_DISABLE: x (disable bias) | ||
766 | * PIN_CONFIG_BIAS_PULL_UP: 1 (pull up bias + enable) | ||
767 | * PIN_CONFIG_BIAS_PULL_DOWN: 1 (pull down bias + enable) | ||
768 | * PIN_CONFIG_DRIVE_STRENGTH: x (4mA, 6mA, 8mA, 9mA) | ||
769 | * | ||
770 | * All other args are invalid. All other params are not supported. | ||
771 | */ | ||
772 | static int artpec6_pconf_set(struct pinctrl_dev *pctldev, unsigned int pin, | ||
773 | unsigned long *configs, unsigned int num_configs) | ||
774 | { | ||
775 | struct artpec6_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); | ||
776 | enum pin_config_param param; | ||
777 | unsigned int arg; | ||
778 | unsigned int regval; | ||
779 | unsigned int *reg; | ||
780 | int i; | ||
781 | |||
782 | /* Check for valid pin */ | ||
783 | if (pin >= pmx->num_pins) { | ||
784 | dev_dbg(pmx->dev, "pinconf is not supported for pin %s\n", | ||
785 | pmx->pins[pin].name); | ||
786 | return -ENOTSUPP; | ||
787 | } | ||
788 | |||
789 | dev_dbg(pmx->dev, "setting configuration for pin %s\n", | ||
790 | pmx->pins[pin].name); | ||
791 | |||
792 | reg = pmx->base + artpec6_pmx_reg_offset(pin); | ||
793 | |||
794 | /* For each config */ | ||
795 | for (i = 0; i < num_configs; i++) { | ||
796 | int drive; | ||
797 | |||
798 | param = pinconf_to_config_param(configs[i]); | ||
799 | arg = pinconf_to_config_argument(configs[i]); | ||
800 | |||
801 | switch (param) { | ||
802 | case PIN_CONFIG_BIAS_DISABLE: | ||
803 | regval = readl(reg); | ||
804 | regval |= (1 << ARTPEC6_PINMUX_UDC1_SHIFT); | ||
805 | writel(regval, reg); | ||
806 | break; | ||
807 | |||
808 | case PIN_CONFIG_BIAS_PULL_UP: | ||
809 | if (arg != 1) { | ||
810 | dev_dbg(pctldev->dev, "%s: arg %u out of range\n", | ||
811 | __func__, arg); | ||
812 | return -EINVAL; | ||
813 | } | ||
814 | |||
815 | regval = readl(reg); | ||
816 | regval |= (arg << ARTPEC6_PINMUX_UDC0_SHIFT); | ||
817 | regval &= ~ARTPEC6_PINMUX_UDC1_MASK; /* Enable */ | ||
818 | writel(regval, reg); | ||
819 | break; | ||
820 | |||
821 | case PIN_CONFIG_BIAS_PULL_DOWN: | ||
822 | if (arg != 1) { | ||
823 | dev_dbg(pctldev->dev, "%s: arg %u out of range\n", | ||
824 | __func__, arg); | ||
825 | return -EINVAL; | ||
826 | } | ||
827 | |||
828 | regval = readl(reg); | ||
829 | regval &= ~(arg << ARTPEC6_PINMUX_UDC0_SHIFT); | ||
830 | regval &= ~ARTPEC6_PINMUX_UDC1_MASK; /* Enable */ | ||
831 | writel(regval, reg); | ||
832 | break; | ||
833 | |||
834 | case PIN_CONFIG_DRIVE_STRENGTH: | ||
835 | drive = artpec6_pconf_drive_mA_to_field(arg); | ||
836 | if (drive < 0) { | ||
837 | dev_dbg(pctldev->dev, "%s: arg %u out of range\n", | ||
838 | __func__, arg); | ||
839 | return -EINVAL; | ||
840 | } | ||
841 | |||
842 | regval = readl(reg); | ||
843 | regval &= ~ARTPEC6_PINMUX_DRV_MASK; | ||
844 | regval |= (drive << ARTPEC6_PINMUX_DRV_SHIFT); | ||
845 | writel(regval, reg); | ||
846 | break; | ||
847 | |||
848 | default: | ||
849 | dev_dbg(pmx->dev, "parameter not supported\n"); | ||
850 | return -ENOTSUPP; | ||
851 | } | ||
852 | } | ||
853 | |||
854 | return 0; | ||
855 | } | ||
856 | |||
857 | static int artpec6_pconf_group_set(struct pinctrl_dev *pctldev, | ||
858 | unsigned int group, unsigned long *configs, | ||
859 | unsigned int num_configs) | ||
860 | { | ||
861 | unsigned int num_pins, current_pin; | ||
862 | int ret; | ||
863 | |||
864 | dev_dbg(pctldev->dev, "setting group %s configuration\n", | ||
865 | artpec6_get_group_name(pctldev, group)); | ||
866 | |||
867 | num_pins = artpec6_pin_groups[group].num_pins; | ||
868 | |||
869 | for (current_pin = 0; current_pin < num_pins; current_pin++) { | ||
870 | ret = artpec6_pconf_set(pctldev, | ||
871 | artpec6_pin_groups[group].pins[current_pin], | ||
872 | configs, num_configs); | ||
873 | |||
874 | if (ret < 0) | ||
875 | return ret; | ||
876 | } | ||
877 | |||
878 | return 0; | ||
879 | } | ||
880 | |||
881 | static const struct pinconf_ops artpec6_pconf_ops = { | ||
882 | .is_generic = true, | ||
883 | .pin_config_get = artpec6_pconf_get, | ||
884 | .pin_config_set = artpec6_pconf_set, | ||
885 | .pin_config_group_set = artpec6_pconf_group_set, | ||
886 | }; | ||
887 | |||
888 | static struct pinctrl_desc artpec6_desc = { | ||
889 | .name = "artpec6-pinctrl", | ||
890 | .owner = THIS_MODULE, | ||
891 | .pins = artpec6_pins, | ||
892 | .npins = ARRAY_SIZE(artpec6_pins), | ||
893 | .pctlops = &artpec6_pctrl_ops, | ||
894 | .pmxops = &artpec6_pmx_ops, | ||
895 | .confops = &artpec6_pconf_ops, | ||
896 | }; | ||
897 | |||
898 | /* The reset values say 4mA, but we want 8mA as default. */ | ||
899 | static void artpec6_pmx_reset(struct artpec6_pmx *pmx) | ||
900 | { | ||
901 | void __iomem *base = pmx->base; | ||
902 | int i; | ||
903 | |||
904 | for (i = 0; i < ARTPEC6_LAST_PIN; i++) { | ||
905 | u32 val; | ||
906 | |||
907 | val = readl_relaxed(base + artpec6_pmx_reg_offset(i)); | ||
908 | val &= ~ARTPEC6_PINMUX_DRV_MASK; | ||
909 | val |= ARTPEC6_DRIVE_8mA_SET << ARTPEC6_PINMUX_DRV_SHIFT; | ||
910 | writel_relaxed(val, base + artpec6_pmx_reg_offset(i)); | ||
911 | } | ||
912 | } | ||
913 | |||
914 | static int artpec6_pmx_probe(struct platform_device *pdev) | ||
915 | { | ||
916 | struct artpec6_pmx *pmx; | ||
917 | struct resource *res; | ||
918 | |||
919 | pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL); | ||
920 | if (!pmx) | ||
921 | return -ENOMEM; | ||
922 | |||
923 | pmx->dev = &pdev->dev; | ||
924 | |||
925 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
926 | pmx->base = devm_ioremap_resource(&pdev->dev, res); | ||
927 | |||
928 | if (IS_ERR(pmx->base)) | ||
929 | return PTR_ERR(pmx->base); | ||
930 | |||
931 | artpec6_pmx_reset(pmx); | ||
932 | |||
933 | pmx->pins = artpec6_pins; | ||
934 | pmx->num_pins = ARRAY_SIZE(artpec6_pins); | ||
935 | pmx->functions = artpec6_pmx_functions; | ||
936 | pmx->num_functions = ARRAY_SIZE(artpec6_pmx_functions); | ||
937 | pmx->pin_groups = artpec6_pin_groups; | ||
938 | pmx->num_pin_groups = ARRAY_SIZE(artpec6_pin_groups); | ||
939 | pmx->pctl = pinctrl_register(&artpec6_desc, &pdev->dev, pmx); | ||
940 | |||
941 | if (!pmx->pctl) { | ||
942 | dev_err(&pdev->dev, "could not register pinctrl driver\n"); | ||
943 | return -EINVAL; | ||
944 | } | ||
945 | |||
946 | platform_set_drvdata(pdev, pmx); | ||
947 | |||
948 | dev_info(&pdev->dev, "initialised Axis ARTPEC-6 pinctrl driver\n"); | ||
949 | |||
950 | return 0; | ||
951 | } | ||
952 | |||
953 | static int artpec6_pmx_remove(struct platform_device *pdev) | ||
954 | { | ||
955 | struct artpec6_pmx *pmx = platform_get_drvdata(pdev); | ||
956 | |||
957 | pinctrl_unregister(pmx->pctl); | ||
958 | |||
959 | return 0; | ||
960 | } | ||
961 | |||
962 | static const struct of_device_id artpec6_pinctrl_match[] = { | ||
963 | { .compatible = "axis,artpec6-pinctrl" }, | ||
964 | {}, | ||
965 | }; | ||
966 | |||
967 | static struct platform_driver artpec6_pmx_driver = { | ||
968 | .driver = { | ||
969 | .name = "artpec6-pinctrl", | ||
970 | .owner = THIS_MODULE, | ||
971 | .of_match_table = artpec6_pinctrl_match, | ||
972 | }, | ||
973 | .probe = artpec6_pmx_probe, | ||
974 | .remove = artpec6_pmx_remove, | ||
975 | }; | ||
976 | |||
977 | static int __init artpec6_pmx_init(void) | ||
978 | { | ||
979 | return platform_driver_register(&artpec6_pmx_driver); | ||
980 | } | ||
981 | arch_initcall(artpec6_pmx_init); | ||
982 | |||
983 | static void __exit artpec6_pmx_exit(void) | ||
984 | { | ||
985 | platform_driver_unregister(&artpec6_pmx_driver); | ||
986 | } | ||
987 | module_exit(artpec6_pmx_exit); | ||
988 | |||
989 | MODULE_AUTHOR("Chris Paterson <chris.paterson@linux.pieboy.co.uk>"); | ||
990 | MODULE_DESCRIPTION("Axis ARTPEC-6 pin control driver"); | ||
991 | MODULE_LICENSE("GPL v2"); | ||
992 | MODULE_DEVICE_TABLE(of, artpec6_pinctrl_match); | ||