diff options
author | Christian Ruppert <christian.ruppert@abilis.com> | 2013-10-15 09:39:38 -0400 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2013-10-16 09:33:51 -0400 |
commit | 5aad0db1c1ebb0f5be79f0adbecc16a2f0259b21 (patch) | |
tree | 032eccc167a0eea6844aae31bcf5f45e98674e54 /drivers/pinctrl | |
parent | 586a87e6edc936d6d3c3585af504b33b9c3f0a06 (diff) |
pinctrl: add TB10x pin control driver
The pinmux driver of the Abilis Systems TB10x platform based on ARC700 CPUs.
Used to control the pinmux and is a prerequisite for the GPIO driver.
Signed-off-by: Christian Ruppert <christian.ruppert@abilis.com>
Signed-off-by: Pierrick Hascoet <pierrick.hascoet@abilis.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/pinctrl')
-rw-r--r-- | drivers/pinctrl/Kconfig | 4 | ||||
-rw-r--r-- | drivers/pinctrl/Makefile | 1 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-tb10x.c | 886 |
3 files changed, 891 insertions, 0 deletions
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 85f5462460aa..e283c4970d1d 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig | |||
@@ -321,6 +321,10 @@ config PINCTRL_XWAY | |||
321 | depends on SOC_TYPE_XWAY | 321 | depends on SOC_TYPE_XWAY |
322 | depends on PINCTRL_LANTIQ | 322 | depends on PINCTRL_LANTIQ |
323 | 323 | ||
324 | config PINCTRL_TB10X | ||
325 | bool | ||
326 | depends on ARC_PLAT_TB10X | ||
327 | |||
324 | endmenu | 328 | endmenu |
325 | 329 | ||
326 | endif | 330 | endif |
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 3d14cb855b2c..8476cd902069 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile | |||
@@ -56,6 +56,7 @@ obj-$(CONFIG_PINCTRL_S3C24XX) += pinctrl-s3c24xx.o | |||
56 | obj-$(CONFIG_PINCTRL_S3C64XX) += pinctrl-s3c64xx.o | 56 | obj-$(CONFIG_PINCTRL_S3C64XX) += pinctrl-s3c64xx.o |
57 | obj-$(CONFIG_PINCTRL_XWAY) += pinctrl-xway.o | 57 | obj-$(CONFIG_PINCTRL_XWAY) += pinctrl-xway.o |
58 | obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o | 58 | obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o |
59 | obj-$(CONFIG_PINCTRL_TB10X) += pinctrl-tb10x.o | ||
59 | obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o | 60 | obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o |
60 | obj-$(CONFIG_PINCTRL_VF610) += pinctrl-vf610.o | 61 | obj-$(CONFIG_PINCTRL_VF610) += pinctrl-vf610.o |
61 | 62 | ||
diff --git a/drivers/pinctrl/pinctrl-tb10x.c b/drivers/pinctrl/pinctrl-tb10x.c new file mode 100644 index 000000000000..2e1ea568c9a2 --- /dev/null +++ b/drivers/pinctrl/pinctrl-tb10x.c | |||
@@ -0,0 +1,886 @@ | |||
1 | /* | ||
2 | * Abilis Systems TB10x pin control driver | ||
3 | * | ||
4 | * Copyright (C) Abilis Systems 2012 | ||
5 | * | ||
6 | * Author: Christian Ruppert <christian.ruppert@abilis.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | #include <linux/stringify.h> | ||
23 | #include <linux/pinctrl/pinctrl.h> | ||
24 | #include <linux/pinctrl/pinmux.h> | ||
25 | #include <linux/pinctrl/machine.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/mutex.h> | ||
29 | #include <linux/err.h> | ||
30 | #include <linux/io.h> | ||
31 | #include <linux/of.h> | ||
32 | #include <linux/slab.h> | ||
33 | |||
34 | #include "pinctrl-utils.h" | ||
35 | |||
36 | #define TB10X_PORT1 (0) | ||
37 | #define TB10X_PORT2 (16) | ||
38 | #define TB10X_PORT3 (32) | ||
39 | #define TB10X_PORT4 (48) | ||
40 | #define TB10X_PORT5 (128) | ||
41 | #define TB10X_PORT6 (64) | ||
42 | #define TB10X_PORT7 (80) | ||
43 | #define TB10X_PORT8 (96) | ||
44 | #define TB10X_PORT9 (112) | ||
45 | #define TB10X_GPIOS (256) | ||
46 | |||
47 | #define PCFG_PORT_BITWIDTH (2) | ||
48 | #define PCFG_PORT_MASK(PORT) \ | ||
49 | (((1 << PCFG_PORT_BITWIDTH) - 1) << (PCFG_PORT_BITWIDTH * (PORT))) | ||
50 | |||
51 | static const struct pinctrl_pin_desc tb10x_pins[] = { | ||
52 | /* Port 1 */ | ||
53 | PINCTRL_PIN(TB10X_PORT1 + 0, "MICLK_S0"), | ||
54 | PINCTRL_PIN(TB10X_PORT1 + 1, "MISTRT_S0"), | ||
55 | PINCTRL_PIN(TB10X_PORT1 + 2, "MIVAL_S0"), | ||
56 | PINCTRL_PIN(TB10X_PORT1 + 3, "MDI_S0"), | ||
57 | PINCTRL_PIN(TB10X_PORT1 + 4, "GPIOA0"), | ||
58 | PINCTRL_PIN(TB10X_PORT1 + 5, "GPIOA1"), | ||
59 | PINCTRL_PIN(TB10X_PORT1 + 6, "GPIOA2"), | ||
60 | PINCTRL_PIN(TB10X_PORT1 + 7, "MDI_S1"), | ||
61 | PINCTRL_PIN(TB10X_PORT1 + 8, "MIVAL_S1"), | ||
62 | PINCTRL_PIN(TB10X_PORT1 + 9, "MISTRT_S1"), | ||
63 | PINCTRL_PIN(TB10X_PORT1 + 10, "MICLK_S1"), | ||
64 | /* Port 2 */ | ||
65 | PINCTRL_PIN(TB10X_PORT2 + 0, "MICLK_S2"), | ||
66 | PINCTRL_PIN(TB10X_PORT2 + 1, "MISTRT_S2"), | ||
67 | PINCTRL_PIN(TB10X_PORT2 + 2, "MIVAL_S2"), | ||
68 | PINCTRL_PIN(TB10X_PORT2 + 3, "MDI_S2"), | ||
69 | PINCTRL_PIN(TB10X_PORT2 + 4, "GPIOC0"), | ||
70 | PINCTRL_PIN(TB10X_PORT2 + 5, "GPIOC1"), | ||
71 | PINCTRL_PIN(TB10X_PORT2 + 6, "GPIOC2"), | ||
72 | PINCTRL_PIN(TB10X_PORT2 + 7, "MDI_S3"), | ||
73 | PINCTRL_PIN(TB10X_PORT2 + 8, "MIVAL_S3"), | ||
74 | PINCTRL_PIN(TB10X_PORT2 + 9, "MISTRT_S3"), | ||
75 | PINCTRL_PIN(TB10X_PORT2 + 10, "MICLK_S3"), | ||
76 | /* Port 3 */ | ||
77 | PINCTRL_PIN(TB10X_PORT3 + 0, "MICLK_S4"), | ||
78 | PINCTRL_PIN(TB10X_PORT3 + 1, "MISTRT_S4"), | ||
79 | PINCTRL_PIN(TB10X_PORT3 + 2, "MIVAL_S4"), | ||
80 | PINCTRL_PIN(TB10X_PORT3 + 3, "MDI_S4"), | ||
81 | PINCTRL_PIN(TB10X_PORT3 + 4, "GPIOE0"), | ||
82 | PINCTRL_PIN(TB10X_PORT3 + 5, "GPIOE1"), | ||
83 | PINCTRL_PIN(TB10X_PORT3 + 6, "GPIOE2"), | ||
84 | PINCTRL_PIN(TB10X_PORT3 + 7, "MDI_S5"), | ||
85 | PINCTRL_PIN(TB10X_PORT3 + 8, "MIVAL_S5"), | ||
86 | PINCTRL_PIN(TB10X_PORT3 + 9, "MISTRT_S5"), | ||
87 | PINCTRL_PIN(TB10X_PORT3 + 10, "MICLK_S5"), | ||
88 | /* Port 4 */ | ||
89 | PINCTRL_PIN(TB10X_PORT4 + 0, "MICLK_S6"), | ||
90 | PINCTRL_PIN(TB10X_PORT4 + 1, "MISTRT_S6"), | ||
91 | PINCTRL_PIN(TB10X_PORT4 + 2, "MIVAL_S6"), | ||
92 | PINCTRL_PIN(TB10X_PORT4 + 3, "MDI_S6"), | ||
93 | PINCTRL_PIN(TB10X_PORT4 + 4, "GPIOG0"), | ||
94 | PINCTRL_PIN(TB10X_PORT4 + 5, "GPIOG1"), | ||
95 | PINCTRL_PIN(TB10X_PORT4 + 6, "GPIOG2"), | ||
96 | PINCTRL_PIN(TB10X_PORT4 + 7, "MDI_S7"), | ||
97 | PINCTRL_PIN(TB10X_PORT4 + 8, "MIVAL_S7"), | ||
98 | PINCTRL_PIN(TB10X_PORT4 + 9, "MISTRT_S7"), | ||
99 | PINCTRL_PIN(TB10X_PORT4 + 10, "MICLK_S7"), | ||
100 | /* Port 5 */ | ||
101 | PINCTRL_PIN(TB10X_PORT5 + 0, "PC_CE1N"), | ||
102 | PINCTRL_PIN(TB10X_PORT5 + 1, "PC_CE2N"), | ||
103 | PINCTRL_PIN(TB10X_PORT5 + 2, "PC_REGN"), | ||
104 | PINCTRL_PIN(TB10X_PORT5 + 3, "PC_INPACKN"), | ||
105 | PINCTRL_PIN(TB10X_PORT5 + 4, "PC_OEN"), | ||
106 | PINCTRL_PIN(TB10X_PORT5 + 5, "PC_WEN"), | ||
107 | PINCTRL_PIN(TB10X_PORT5 + 6, "PC_IORDN"), | ||
108 | PINCTRL_PIN(TB10X_PORT5 + 7, "PC_IOWRN"), | ||
109 | PINCTRL_PIN(TB10X_PORT5 + 8, "PC_RDYIRQN"), | ||
110 | PINCTRL_PIN(TB10X_PORT5 + 9, "PC_WAITN"), | ||
111 | PINCTRL_PIN(TB10X_PORT5 + 10, "PC_A0"), | ||
112 | PINCTRL_PIN(TB10X_PORT5 + 11, "PC_A1"), | ||
113 | PINCTRL_PIN(TB10X_PORT5 + 12, "PC_A2"), | ||
114 | PINCTRL_PIN(TB10X_PORT5 + 13, "PC_A3"), | ||
115 | PINCTRL_PIN(TB10X_PORT5 + 14, "PC_A4"), | ||
116 | PINCTRL_PIN(TB10X_PORT5 + 15, "PC_A5"), | ||
117 | PINCTRL_PIN(TB10X_PORT5 + 16, "PC_A6"), | ||
118 | PINCTRL_PIN(TB10X_PORT5 + 17, "PC_A7"), | ||
119 | PINCTRL_PIN(TB10X_PORT5 + 18, "PC_A8"), | ||
120 | PINCTRL_PIN(TB10X_PORT5 + 19, "PC_A9"), | ||
121 | PINCTRL_PIN(TB10X_PORT5 + 20, "PC_A10"), | ||
122 | PINCTRL_PIN(TB10X_PORT5 + 21, "PC_A11"), | ||
123 | PINCTRL_PIN(TB10X_PORT5 + 22, "PC_A12"), | ||
124 | PINCTRL_PIN(TB10X_PORT5 + 23, "PC_A13"), | ||
125 | PINCTRL_PIN(TB10X_PORT5 + 24, "PC_A14"), | ||
126 | PINCTRL_PIN(TB10X_PORT5 + 25, "PC_D0"), | ||
127 | PINCTRL_PIN(TB10X_PORT5 + 26, "PC_D1"), | ||
128 | PINCTRL_PIN(TB10X_PORT5 + 27, "PC_D2"), | ||
129 | PINCTRL_PIN(TB10X_PORT5 + 28, "PC_D3"), | ||
130 | PINCTRL_PIN(TB10X_PORT5 + 29, "PC_D4"), | ||
131 | PINCTRL_PIN(TB10X_PORT5 + 30, "PC_D5"), | ||
132 | PINCTRL_PIN(TB10X_PORT5 + 31, "PC_D6"), | ||
133 | PINCTRL_PIN(TB10X_PORT5 + 32, "PC_D7"), | ||
134 | PINCTRL_PIN(TB10X_PORT5 + 33, "PC_MOSTRT"), | ||
135 | PINCTRL_PIN(TB10X_PORT5 + 34, "PC_MOVAL"), | ||
136 | PINCTRL_PIN(TB10X_PORT5 + 35, "PC_MDO0"), | ||
137 | PINCTRL_PIN(TB10X_PORT5 + 36, "PC_MDO1"), | ||
138 | PINCTRL_PIN(TB10X_PORT5 + 37, "PC_MDO2"), | ||
139 | PINCTRL_PIN(TB10X_PORT5 + 38, "PC_MDO3"), | ||
140 | PINCTRL_PIN(TB10X_PORT5 + 39, "PC_MDO4"), | ||
141 | PINCTRL_PIN(TB10X_PORT5 + 40, "PC_MDO5"), | ||
142 | PINCTRL_PIN(TB10X_PORT5 + 41, "PC_MDO6"), | ||
143 | PINCTRL_PIN(TB10X_PORT5 + 42, "PC_MDO7"), | ||
144 | PINCTRL_PIN(TB10X_PORT5 + 43, "PC_MISTRT"), | ||
145 | PINCTRL_PIN(TB10X_PORT5 + 44, "PC_MIVAL"), | ||
146 | PINCTRL_PIN(TB10X_PORT5 + 45, "PC_MDI0"), | ||
147 | PINCTRL_PIN(TB10X_PORT5 + 46, "PC_MDI1"), | ||
148 | PINCTRL_PIN(TB10X_PORT5 + 47, "PC_MDI2"), | ||
149 | PINCTRL_PIN(TB10X_PORT5 + 48, "PC_MDI3"), | ||
150 | PINCTRL_PIN(TB10X_PORT5 + 49, "PC_MDI4"), | ||
151 | PINCTRL_PIN(TB10X_PORT5 + 50, "PC_MDI5"), | ||
152 | PINCTRL_PIN(TB10X_PORT5 + 51, "PC_MDI6"), | ||
153 | PINCTRL_PIN(TB10X_PORT5 + 52, "PC_MDI7"), | ||
154 | PINCTRL_PIN(TB10X_PORT5 + 53, "PC_MICLK"), | ||
155 | /* Port 6 */ | ||
156 | PINCTRL_PIN(TB10X_PORT6 + 0, "T_MOSTRT_S0"), | ||
157 | PINCTRL_PIN(TB10X_PORT6 + 1, "T_MOVAL_S0"), | ||
158 | PINCTRL_PIN(TB10X_PORT6 + 2, "T_MDO_S0"), | ||
159 | PINCTRL_PIN(TB10X_PORT6 + 3, "T_MOSTRT_S1"), | ||
160 | PINCTRL_PIN(TB10X_PORT6 + 4, "T_MOVAL_S1"), | ||
161 | PINCTRL_PIN(TB10X_PORT6 + 5, "T_MDO_S1"), | ||
162 | PINCTRL_PIN(TB10X_PORT6 + 6, "T_MOSTRT_S2"), | ||
163 | PINCTRL_PIN(TB10X_PORT6 + 7, "T_MOVAL_S2"), | ||
164 | PINCTRL_PIN(TB10X_PORT6 + 8, "T_MDO_S2"), | ||
165 | PINCTRL_PIN(TB10X_PORT6 + 9, "T_MOSTRT_S3"), | ||
166 | /* Port 7 */ | ||
167 | PINCTRL_PIN(TB10X_PORT7 + 0, "UART0_TXD"), | ||
168 | PINCTRL_PIN(TB10X_PORT7 + 1, "UART0_RXD"), | ||
169 | PINCTRL_PIN(TB10X_PORT7 + 2, "UART0_CTS"), | ||
170 | PINCTRL_PIN(TB10X_PORT7 + 3, "UART0_RTS"), | ||
171 | PINCTRL_PIN(TB10X_PORT7 + 4, "UART1_TXD"), | ||
172 | PINCTRL_PIN(TB10X_PORT7 + 5, "UART1_RXD"), | ||
173 | PINCTRL_PIN(TB10X_PORT7 + 6, "UART1_CTS"), | ||
174 | PINCTRL_PIN(TB10X_PORT7 + 7, "UART1_RTS"), | ||
175 | /* Port 8 */ | ||
176 | PINCTRL_PIN(TB10X_PORT8 + 0, "SPI3_CLK"), | ||
177 | PINCTRL_PIN(TB10X_PORT8 + 1, "SPI3_MISO"), | ||
178 | PINCTRL_PIN(TB10X_PORT8 + 2, "SPI3_MOSI"), | ||
179 | PINCTRL_PIN(TB10X_PORT8 + 3, "SPI3_SSN"), | ||
180 | /* Port 9 */ | ||
181 | PINCTRL_PIN(TB10X_PORT9 + 0, "SPI1_CLK"), | ||
182 | PINCTRL_PIN(TB10X_PORT9 + 1, "SPI1_MISO"), | ||
183 | PINCTRL_PIN(TB10X_PORT9 + 2, "SPI1_MOSI"), | ||
184 | PINCTRL_PIN(TB10X_PORT9 + 3, "SPI1_SSN0"), | ||
185 | PINCTRL_PIN(TB10X_PORT9 + 4, "SPI1_SSN1"), | ||
186 | /* Unmuxed GPIOs */ | ||
187 | PINCTRL_PIN(TB10X_GPIOS + 0, "GPIOB0"), | ||
188 | PINCTRL_PIN(TB10X_GPIOS + 1, "GPIOB1"), | ||
189 | |||
190 | PINCTRL_PIN(TB10X_GPIOS + 2, "GPIOD0"), | ||
191 | PINCTRL_PIN(TB10X_GPIOS + 3, "GPIOD1"), | ||
192 | |||
193 | PINCTRL_PIN(TB10X_GPIOS + 4, "GPIOF0"), | ||
194 | PINCTRL_PIN(TB10X_GPIOS + 5, "GPIOF1"), | ||
195 | |||
196 | PINCTRL_PIN(TB10X_GPIOS + 6, "GPIOH0"), | ||
197 | PINCTRL_PIN(TB10X_GPIOS + 7, "GPIOH1"), | ||
198 | |||
199 | PINCTRL_PIN(TB10X_GPIOS + 8, "GPIOI0"), | ||
200 | PINCTRL_PIN(TB10X_GPIOS + 9, "GPIOI1"), | ||
201 | PINCTRL_PIN(TB10X_GPIOS + 10, "GPIOI2"), | ||
202 | PINCTRL_PIN(TB10X_GPIOS + 11, "GPIOI3"), | ||
203 | PINCTRL_PIN(TB10X_GPIOS + 12, "GPIOI4"), | ||
204 | PINCTRL_PIN(TB10X_GPIOS + 13, "GPIOI5"), | ||
205 | PINCTRL_PIN(TB10X_GPIOS + 14, "GPIOI6"), | ||
206 | PINCTRL_PIN(TB10X_GPIOS + 15, "GPIOI7"), | ||
207 | PINCTRL_PIN(TB10X_GPIOS + 16, "GPIOI8"), | ||
208 | PINCTRL_PIN(TB10X_GPIOS + 17, "GPIOI9"), | ||
209 | PINCTRL_PIN(TB10X_GPIOS + 18, "GPIOI10"), | ||
210 | PINCTRL_PIN(TB10X_GPIOS + 19, "GPIOI11"), | ||
211 | |||
212 | PINCTRL_PIN(TB10X_GPIOS + 20, "GPION0"), | ||
213 | PINCTRL_PIN(TB10X_GPIOS + 21, "GPION1"), | ||
214 | PINCTRL_PIN(TB10X_GPIOS + 22, "GPION2"), | ||
215 | PINCTRL_PIN(TB10X_GPIOS + 23, "GPION3"), | ||
216 | #define MAX_PIN (TB10X_GPIOS + 24) | ||
217 | PINCTRL_PIN(MAX_PIN, "GPION4"), | ||
218 | }; | ||
219 | |||
220 | |||
221 | /* Port 1 */ | ||
222 | static const unsigned mis0_pins[] = { TB10X_PORT1 + 0, TB10X_PORT1 + 1, | ||
223 | TB10X_PORT1 + 2, TB10X_PORT1 + 3}; | ||
224 | static const unsigned gpioa_pins[] = { TB10X_PORT1 + 4, TB10X_PORT1 + 5, | ||
225 | TB10X_PORT1 + 6}; | ||
226 | static const unsigned mis1_pins[] = { TB10X_PORT1 + 7, TB10X_PORT1 + 8, | ||
227 | TB10X_PORT1 + 9, TB10X_PORT1 + 10}; | ||
228 | static const unsigned mip1_pins[] = { TB10X_PORT1 + 0, TB10X_PORT1 + 1, | ||
229 | TB10X_PORT1 + 2, TB10X_PORT1 + 3, | ||
230 | TB10X_PORT1 + 4, TB10X_PORT1 + 5, | ||
231 | TB10X_PORT1 + 6, TB10X_PORT1 + 7, | ||
232 | TB10X_PORT1 + 8, TB10X_PORT1 + 9, | ||
233 | TB10X_PORT1 + 10}; | ||
234 | |||
235 | /* Port 2 */ | ||
236 | static const unsigned mis2_pins[] = { TB10X_PORT2 + 0, TB10X_PORT2 + 1, | ||
237 | TB10X_PORT2 + 2, TB10X_PORT2 + 3}; | ||
238 | static const unsigned gpioc_pins[] = { TB10X_PORT2 + 4, TB10X_PORT2 + 5, | ||
239 | TB10X_PORT2 + 6}; | ||
240 | static const unsigned mis3_pins[] = { TB10X_PORT2 + 7, TB10X_PORT2 + 8, | ||
241 | TB10X_PORT2 + 9, TB10X_PORT2 + 10}; | ||
242 | static const unsigned mip3_pins[] = { TB10X_PORT2 + 0, TB10X_PORT2 + 1, | ||
243 | TB10X_PORT2 + 2, TB10X_PORT2 + 3, | ||
244 | TB10X_PORT2 + 4, TB10X_PORT2 + 5, | ||
245 | TB10X_PORT2 + 6, TB10X_PORT2 + 7, | ||
246 | TB10X_PORT2 + 8, TB10X_PORT2 + 9, | ||
247 | TB10X_PORT2 + 10}; | ||
248 | |||
249 | /* Port 3 */ | ||
250 | static const unsigned mis4_pins[] = { TB10X_PORT3 + 0, TB10X_PORT3 + 1, | ||
251 | TB10X_PORT3 + 2, TB10X_PORT3 + 3}; | ||
252 | static const unsigned gpioe_pins[] = { TB10X_PORT3 + 4, TB10X_PORT3 + 5, | ||
253 | TB10X_PORT3 + 6}; | ||
254 | static const unsigned mis5_pins[] = { TB10X_PORT3 + 7, TB10X_PORT3 + 8, | ||
255 | TB10X_PORT3 + 9, TB10X_PORT3 + 10}; | ||
256 | static const unsigned mip5_pins[] = { TB10X_PORT3 + 0, TB10X_PORT3 + 1, | ||
257 | TB10X_PORT3 + 2, TB10X_PORT3 + 3, | ||
258 | TB10X_PORT3 + 4, TB10X_PORT3 + 5, | ||
259 | TB10X_PORT3 + 6, TB10X_PORT3 + 7, | ||
260 | TB10X_PORT3 + 8, TB10X_PORT3 + 9, | ||
261 | TB10X_PORT3 + 10}; | ||
262 | |||
263 | /* Port 4 */ | ||
264 | static const unsigned mis6_pins[] = { TB10X_PORT4 + 0, TB10X_PORT4 + 1, | ||
265 | TB10X_PORT4 + 2, TB10X_PORT4 + 3}; | ||
266 | static const unsigned gpiog_pins[] = { TB10X_PORT4 + 4, TB10X_PORT4 + 5, | ||
267 | TB10X_PORT4 + 6}; | ||
268 | static const unsigned mis7_pins[] = { TB10X_PORT4 + 7, TB10X_PORT4 + 8, | ||
269 | TB10X_PORT4 + 9, TB10X_PORT4 + 10}; | ||
270 | static const unsigned mip7_pins[] = { TB10X_PORT4 + 0, TB10X_PORT4 + 1, | ||
271 | TB10X_PORT4 + 2, TB10X_PORT4 + 3, | ||
272 | TB10X_PORT4 + 4, TB10X_PORT4 + 5, | ||
273 | TB10X_PORT4 + 6, TB10X_PORT4 + 7, | ||
274 | TB10X_PORT4 + 8, TB10X_PORT4 + 9, | ||
275 | TB10X_PORT4 + 10}; | ||
276 | |||
277 | /* Port 6 */ | ||
278 | static const unsigned mop_pins[] = { TB10X_PORT6 + 0, TB10X_PORT6 + 1, | ||
279 | TB10X_PORT6 + 2, TB10X_PORT6 + 3, | ||
280 | TB10X_PORT6 + 4, TB10X_PORT6 + 5, | ||
281 | TB10X_PORT6 + 6, TB10X_PORT6 + 7, | ||
282 | TB10X_PORT6 + 8, TB10X_PORT6 + 9}; | ||
283 | static const unsigned mos0_pins[] = { TB10X_PORT6 + 0, TB10X_PORT6 + 1, | ||
284 | TB10X_PORT6 + 2}; | ||
285 | static const unsigned mos1_pins[] = { TB10X_PORT6 + 3, TB10X_PORT6 + 4, | ||
286 | TB10X_PORT6 + 5}; | ||
287 | static const unsigned mos2_pins[] = { TB10X_PORT6 + 6, TB10X_PORT6 + 7, | ||
288 | TB10X_PORT6 + 8}; | ||
289 | static const unsigned mos3_pins[] = { TB10X_PORT6 + 9}; | ||
290 | |||
291 | /* Port 7 */ | ||
292 | static const unsigned uart0_pins[] = { TB10X_PORT7 + 0, TB10X_PORT7 + 1, | ||
293 | TB10X_PORT7 + 2, TB10X_PORT7 + 3}; | ||
294 | static const unsigned uart1_pins[] = { TB10X_PORT7 + 4, TB10X_PORT7 + 5, | ||
295 | TB10X_PORT7 + 6, TB10X_PORT7 + 7}; | ||
296 | static const unsigned gpiol_pins[] = { TB10X_PORT7 + 0, TB10X_PORT7 + 1, | ||
297 | TB10X_PORT7 + 2, TB10X_PORT7 + 3}; | ||
298 | static const unsigned gpiom_pins[] = { TB10X_PORT7 + 4, TB10X_PORT7 + 5, | ||
299 | TB10X_PORT7 + 6, TB10X_PORT7 + 7}; | ||
300 | |||
301 | /* Port 8 */ | ||
302 | static const unsigned spi3_pins[] = { TB10X_PORT8 + 0, TB10X_PORT8 + 1, | ||
303 | TB10X_PORT8 + 2, TB10X_PORT8 + 3}; | ||
304 | static const unsigned jtag_pins[] = { TB10X_PORT8 + 0, TB10X_PORT8 + 1, | ||
305 | TB10X_PORT8 + 2, TB10X_PORT8 + 3}; | ||
306 | |||
307 | /* Port 9 */ | ||
308 | static const unsigned spi1_pins[] = { TB10X_PORT9 + 0, TB10X_PORT9 + 1, | ||
309 | TB10X_PORT9 + 2, TB10X_PORT9 + 3, | ||
310 | TB10X_PORT9 + 4}; | ||
311 | static const unsigned gpion_pins[] = { TB10X_PORT9 + 0, TB10X_PORT9 + 1, | ||
312 | TB10X_PORT9 + 2, TB10X_PORT9 + 3, | ||
313 | TB10X_PORT9 + 4}; | ||
314 | |||
315 | /* Port 5 */ | ||
316 | static const unsigned gpioj_pins[] = { TB10X_PORT5 + 0, TB10X_PORT5 + 1, | ||
317 | TB10X_PORT5 + 2, TB10X_PORT5 + 3, | ||
318 | TB10X_PORT5 + 4, TB10X_PORT5 + 5, | ||
319 | TB10X_PORT5 + 6, TB10X_PORT5 + 7, | ||
320 | TB10X_PORT5 + 8, TB10X_PORT5 + 9, | ||
321 | TB10X_PORT5 + 10, TB10X_PORT5 + 11, | ||
322 | TB10X_PORT5 + 12, TB10X_PORT5 + 13, | ||
323 | TB10X_PORT5 + 14, TB10X_PORT5 + 15, | ||
324 | TB10X_PORT5 + 16, TB10X_PORT5 + 17, | ||
325 | TB10X_PORT5 + 18, TB10X_PORT5 + 19, | ||
326 | TB10X_PORT5 + 20, TB10X_PORT5 + 21, | ||
327 | TB10X_PORT5 + 22, TB10X_PORT5 + 23, | ||
328 | TB10X_PORT5 + 24, TB10X_PORT5 + 25, | ||
329 | TB10X_PORT5 + 26, TB10X_PORT5 + 27, | ||
330 | TB10X_PORT5 + 28, TB10X_PORT5 + 29, | ||
331 | TB10X_PORT5 + 30, TB10X_PORT5 + 31}; | ||
332 | static const unsigned gpiok_pins[] = { TB10X_PORT5 + 32, TB10X_PORT5 + 33, | ||
333 | TB10X_PORT5 + 34, TB10X_PORT5 + 35, | ||
334 | TB10X_PORT5 + 36, TB10X_PORT5 + 37, | ||
335 | TB10X_PORT5 + 38, TB10X_PORT5 + 39, | ||
336 | TB10X_PORT5 + 40, TB10X_PORT5 + 41, | ||
337 | TB10X_PORT5 + 42, TB10X_PORT5 + 43, | ||
338 | TB10X_PORT5 + 44, TB10X_PORT5 + 45, | ||
339 | TB10X_PORT5 + 46, TB10X_PORT5 + 47, | ||
340 | TB10X_PORT5 + 48, TB10X_PORT5 + 49, | ||
341 | TB10X_PORT5 + 50, TB10X_PORT5 + 51, | ||
342 | TB10X_PORT5 + 52, TB10X_PORT5 + 53}; | ||
343 | static const unsigned ciplus_pins[] = { TB10X_PORT5 + 0, TB10X_PORT5 + 1, | ||
344 | TB10X_PORT5 + 2, TB10X_PORT5 + 3, | ||
345 | TB10X_PORT5 + 4, TB10X_PORT5 + 5, | ||
346 | TB10X_PORT5 + 6, TB10X_PORT5 + 7, | ||
347 | TB10X_PORT5 + 8, TB10X_PORT5 + 9, | ||
348 | TB10X_PORT5 + 10, TB10X_PORT5 + 11, | ||
349 | TB10X_PORT5 + 12, TB10X_PORT5 + 13, | ||
350 | TB10X_PORT5 + 14, TB10X_PORT5 + 15, | ||
351 | TB10X_PORT5 + 16, TB10X_PORT5 + 17, | ||
352 | TB10X_PORT5 + 18, TB10X_PORT5 + 19, | ||
353 | TB10X_PORT5 + 20, TB10X_PORT5 + 21, | ||
354 | TB10X_PORT5 + 22, TB10X_PORT5 + 23, | ||
355 | TB10X_PORT5 + 24, TB10X_PORT5 + 25, | ||
356 | TB10X_PORT5 + 26, TB10X_PORT5 + 27, | ||
357 | TB10X_PORT5 + 28, TB10X_PORT5 + 29, | ||
358 | TB10X_PORT5 + 30, TB10X_PORT5 + 31, | ||
359 | TB10X_PORT5 + 32, TB10X_PORT5 + 33, | ||
360 | TB10X_PORT5 + 34, TB10X_PORT5 + 35, | ||
361 | TB10X_PORT5 + 36, TB10X_PORT5 + 37, | ||
362 | TB10X_PORT5 + 38, TB10X_PORT5 + 39, | ||
363 | TB10X_PORT5 + 40, TB10X_PORT5 + 41, | ||
364 | TB10X_PORT5 + 42, TB10X_PORT5 + 43, | ||
365 | TB10X_PORT5 + 44, TB10X_PORT5 + 45, | ||
366 | TB10X_PORT5 + 46, TB10X_PORT5 + 47, | ||
367 | TB10X_PORT5 + 48, TB10X_PORT5 + 49, | ||
368 | TB10X_PORT5 + 50, TB10X_PORT5 + 51, | ||
369 | TB10X_PORT5 + 52, TB10X_PORT5 + 53}; | ||
370 | static const unsigned mcard_pins[] = { TB10X_PORT5 + 3, TB10X_PORT5 + 10, | ||
371 | TB10X_PORT5 + 11, TB10X_PORT5 + 12, | ||
372 | TB10X_PORT5 + 22, TB10X_PORT5 + 23, | ||
373 | TB10X_PORT5 + 33, TB10X_PORT5 + 35, | ||
374 | TB10X_PORT5 + 36, TB10X_PORT5 + 37, | ||
375 | TB10X_PORT5 + 38, TB10X_PORT5 + 39, | ||
376 | TB10X_PORT5 + 40, TB10X_PORT5 + 41, | ||
377 | TB10X_PORT5 + 42, TB10X_PORT5 + 43, | ||
378 | TB10X_PORT5 + 45, TB10X_PORT5 + 46, | ||
379 | TB10X_PORT5 + 47, TB10X_PORT5 + 48, | ||
380 | TB10X_PORT5 + 49, TB10X_PORT5 + 50, | ||
381 | TB10X_PORT5 + 51, TB10X_PORT5 + 52, | ||
382 | TB10X_PORT5 + 53}; | ||
383 | static const unsigned stc0_pins[] = { TB10X_PORT5 + 34, TB10X_PORT5 + 35, | ||
384 | TB10X_PORT5 + 36, TB10X_PORT5 + 37, | ||
385 | TB10X_PORT5 + 38, TB10X_PORT5 + 39, | ||
386 | TB10X_PORT5 + 40}; | ||
387 | static const unsigned stc1_pins[] = { TB10X_PORT5 + 25, TB10X_PORT5 + 26, | ||
388 | TB10X_PORT5 + 27, TB10X_PORT5 + 28, | ||
389 | TB10X_PORT5 + 29, TB10X_PORT5 + 30, | ||
390 | TB10X_PORT5 + 44}; | ||
391 | |||
392 | /* Unmuxed GPIOs */ | ||
393 | static const unsigned gpiob_pins[] = { TB10X_GPIOS + 0, TB10X_GPIOS + 1}; | ||
394 | static const unsigned gpiod_pins[] = { TB10X_GPIOS + 2, TB10X_GPIOS + 3}; | ||
395 | static const unsigned gpiof_pins[] = { TB10X_GPIOS + 4, TB10X_GPIOS + 5}; | ||
396 | static const unsigned gpioh_pins[] = { TB10X_GPIOS + 6, TB10X_GPIOS + 7}; | ||
397 | static const unsigned gpioi_pins[] = { TB10X_GPIOS + 8, TB10X_GPIOS + 9, | ||
398 | TB10X_GPIOS + 10, TB10X_GPIOS + 11, | ||
399 | TB10X_GPIOS + 12, TB10X_GPIOS + 13, | ||
400 | TB10X_GPIOS + 14, TB10X_GPIOS + 15, | ||
401 | TB10X_GPIOS + 16, TB10X_GPIOS + 17, | ||
402 | TB10X_GPIOS + 18, TB10X_GPIOS + 19}; | ||
403 | |||
404 | struct tb10x_pinfuncgrp { | ||
405 | const char *name; | ||
406 | const unsigned int *pins; | ||
407 | const unsigned int pincnt; | ||
408 | const int port; | ||
409 | const unsigned int mode; | ||
410 | const int isgpio; | ||
411 | }; | ||
412 | #define DEFPINFUNCGRP(NAME, PORT, MODE, ISGPIO) { \ | ||
413 | .name = __stringify(NAME), \ | ||
414 | .pins = NAME##_pins, .pincnt = ARRAY_SIZE(NAME##_pins), \ | ||
415 | .port = (PORT), .mode = (MODE), \ | ||
416 | .isgpio = (ISGPIO), \ | ||
417 | } | ||
418 | static const struct tb10x_pinfuncgrp tb10x_pingroups[] = { | ||
419 | DEFPINFUNCGRP(mis0, 0, 0, 0), | ||
420 | DEFPINFUNCGRP(gpioa, 0, 0, 1), | ||
421 | DEFPINFUNCGRP(mis1, 0, 0, 0), | ||
422 | DEFPINFUNCGRP(mip1, 0, 1, 0), | ||
423 | DEFPINFUNCGRP(mis2, 1, 0, 0), | ||
424 | DEFPINFUNCGRP(gpioc, 1, 0, 1), | ||
425 | DEFPINFUNCGRP(mis3, 1, 0, 0), | ||
426 | DEFPINFUNCGRP(mip3, 1, 1, 0), | ||
427 | DEFPINFUNCGRP(mis4, 2, 0, 0), | ||
428 | DEFPINFUNCGRP(gpioe, 2, 0, 1), | ||
429 | DEFPINFUNCGRP(mis5, 2, 0, 0), | ||
430 | DEFPINFUNCGRP(mip5, 2, 1, 0), | ||
431 | DEFPINFUNCGRP(mis6, 3, 0, 0), | ||
432 | DEFPINFUNCGRP(gpiog, 3, 0, 1), | ||
433 | DEFPINFUNCGRP(mis7, 3, 0, 0), | ||
434 | DEFPINFUNCGRP(mip7, 3, 1, 0), | ||
435 | DEFPINFUNCGRP(gpioj, 4, 0, 1), | ||
436 | DEFPINFUNCGRP(gpiok, 4, 0, 1), | ||
437 | DEFPINFUNCGRP(ciplus, 4, 1, 0), | ||
438 | DEFPINFUNCGRP(mcard, 4, 2, 0), | ||
439 | DEFPINFUNCGRP(stc0, 4, 3, 0), | ||
440 | DEFPINFUNCGRP(stc1, 4, 3, 0), | ||
441 | DEFPINFUNCGRP(mop, 5, 0, 0), | ||
442 | DEFPINFUNCGRP(mos0, 5, 1, 0), | ||
443 | DEFPINFUNCGRP(mos1, 5, 1, 0), | ||
444 | DEFPINFUNCGRP(mos2, 5, 1, 0), | ||
445 | DEFPINFUNCGRP(mos3, 5, 1, 0), | ||
446 | DEFPINFUNCGRP(uart0, 6, 0, 0), | ||
447 | DEFPINFUNCGRP(uart1, 6, 0, 0), | ||
448 | DEFPINFUNCGRP(gpiol, 6, 1, 1), | ||
449 | DEFPINFUNCGRP(gpiom, 6, 1, 1), | ||
450 | DEFPINFUNCGRP(spi3, 7, 0, 0), | ||
451 | DEFPINFUNCGRP(jtag, 7, 1, 0), | ||
452 | DEFPINFUNCGRP(spi1, 8, 0, 0), | ||
453 | DEFPINFUNCGRP(gpion, 8, 1, 1), | ||
454 | DEFPINFUNCGRP(gpiob, -1, 0, 1), | ||
455 | DEFPINFUNCGRP(gpiod, -1, 0, 1), | ||
456 | DEFPINFUNCGRP(gpiof, -1, 0, 1), | ||
457 | DEFPINFUNCGRP(gpioh, -1, 0, 1), | ||
458 | DEFPINFUNCGRP(gpioi, -1, 0, 1), | ||
459 | }; | ||
460 | #undef DEFPINFUNCGRP | ||
461 | |||
462 | struct tb10x_of_pinfunc { | ||
463 | const char *name; | ||
464 | const char *group; | ||
465 | }; | ||
466 | |||
467 | #define TB10X_PORTS (9) | ||
468 | |||
469 | /** | ||
470 | * struct tb10x_port - state of an I/O port | ||
471 | * @mode: Node this port is currently in. | ||
472 | * @count: Number of enabled functions which require this port to be | ||
473 | * configured in @mode. | ||
474 | */ | ||
475 | struct tb10x_port { | ||
476 | unsigned int mode; | ||
477 | unsigned int count; | ||
478 | }; | ||
479 | |||
480 | /** | ||
481 | * struct tb10x_pinctrl - TB10x pin controller internal state | ||
482 | * @pctl: pointer to the pinctrl_dev structure of this pin controller. | ||
483 | * @base: register set base address. | ||
484 | * @pingroups: pointer to an array of the pin groups this driver manages. | ||
485 | * @pinfuncgrpcnt: number of pingroups in @pingroups. | ||
486 | * @pinfuncs: pointer to an array of pin functions this driver manages. | ||
487 | * @pinfuncnt: number of pin functions in @pinfuncs. | ||
488 | * @mutex: mutex for exclusive access to a pin controller's state. | ||
489 | * @ports: current state of each port. | ||
490 | * @gpios: Indicates if a given pin is currently used as GPIO (1) or not (0). | ||
491 | */ | ||
492 | struct tb10x_pinctrl { | ||
493 | struct pinctrl_dev *pctl; | ||
494 | void *base; | ||
495 | const struct tb10x_pinfuncgrp *pingroups; | ||
496 | unsigned int pinfuncgrpcnt; | ||
497 | struct tb10x_of_pinfunc *pinfuncs; | ||
498 | unsigned int pinfuncnt; | ||
499 | struct mutex mutex; | ||
500 | struct tb10x_port ports[TB10X_PORTS]; | ||
501 | DECLARE_BITMAP(gpios, MAX_PIN + 1); | ||
502 | }; | ||
503 | |||
504 | static inline void tb10x_pinctrl_set_config(struct tb10x_pinctrl *state, | ||
505 | unsigned int port, unsigned int mode) | ||
506 | { | ||
507 | u32 pcfg; | ||
508 | |||
509 | if (state->ports[port].count) | ||
510 | return; | ||
511 | |||
512 | state->ports[port].mode = mode; | ||
513 | |||
514 | pcfg = ioread32(state->base) & ~(PCFG_PORT_MASK(port)); | ||
515 | pcfg |= (mode << (PCFG_PORT_BITWIDTH * port)) & PCFG_PORT_MASK(port); | ||
516 | iowrite32(pcfg, state->base); | ||
517 | } | ||
518 | |||
519 | static inline unsigned int tb10x_pinctrl_get_config( | ||
520 | struct tb10x_pinctrl *state, | ||
521 | unsigned int port) | ||
522 | { | ||
523 | return (ioread32(state->base) & PCFG_PORT_MASK(port)) | ||
524 | >> (PCFG_PORT_BITWIDTH * port); | ||
525 | } | ||
526 | |||
527 | static int tb10x_get_groups_count(struct pinctrl_dev *pctl) | ||
528 | { | ||
529 | struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctl); | ||
530 | return state->pinfuncgrpcnt; | ||
531 | } | ||
532 | |||
533 | static const char *tb10x_get_group_name(struct pinctrl_dev *pctl, unsigned n) | ||
534 | { | ||
535 | struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctl); | ||
536 | return state->pingroups[n].name; | ||
537 | } | ||
538 | |||
539 | static int tb10x_get_group_pins(struct pinctrl_dev *pctl, unsigned n, | ||
540 | unsigned const **pins, | ||
541 | unsigned * const num_pins) | ||
542 | { | ||
543 | struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctl); | ||
544 | |||
545 | *pins = state->pingroups[n].pins; | ||
546 | *num_pins = state->pingroups[n].pincnt; | ||
547 | |||
548 | return 0; | ||
549 | } | ||
550 | |||
551 | static int tb10x_dt_node_to_map(struct pinctrl_dev *pctl, | ||
552 | struct device_node *np_config, | ||
553 | struct pinctrl_map **map, unsigned *num_maps) | ||
554 | { | ||
555 | const char *string; | ||
556 | unsigned reserved_maps = 0; | ||
557 | int ret = 0; | ||
558 | |||
559 | if (of_property_read_string(np_config, "abilis,function", &string)) { | ||
560 | pr_err("%s: No abilis,function property in device tree.\n", | ||
561 | np_config->full_name); | ||
562 | return -EINVAL; | ||
563 | } | ||
564 | |||
565 | *map = NULL; | ||
566 | *num_maps = 0; | ||
567 | |||
568 | ret = pinctrl_utils_reserve_map(pctl, map, &reserved_maps, | ||
569 | num_maps, 1); | ||
570 | if (ret) | ||
571 | goto out; | ||
572 | |||
573 | ret = pinctrl_utils_add_map_mux(pctl, map, &reserved_maps, | ||
574 | num_maps, string, np_config->name); | ||
575 | |||
576 | out: | ||
577 | return ret; | ||
578 | } | ||
579 | |||
580 | static struct pinctrl_ops tb10x_pinctrl_ops = { | ||
581 | .get_groups_count = tb10x_get_groups_count, | ||
582 | .get_group_name = tb10x_get_group_name, | ||
583 | .get_group_pins = tb10x_get_group_pins, | ||
584 | .dt_node_to_map = tb10x_dt_node_to_map, | ||
585 | .dt_free_map = pinctrl_utils_dt_free_map, | ||
586 | }; | ||
587 | |||
588 | static int tb10x_get_functions_count(struct pinctrl_dev *pctl) | ||
589 | { | ||
590 | struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctl); | ||
591 | return state->pinfuncnt; | ||
592 | } | ||
593 | |||
594 | static const char *tb10x_get_function_name(struct pinctrl_dev *pctl, | ||
595 | unsigned n) | ||
596 | { | ||
597 | struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctl); | ||
598 | return state->pinfuncs[n].name; | ||
599 | } | ||
600 | |||
601 | static int tb10x_get_function_groups(struct pinctrl_dev *pctl, | ||
602 | unsigned n, const char * const **groups, | ||
603 | unsigned * const num_groups) | ||
604 | { | ||
605 | struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctl); | ||
606 | |||
607 | *groups = &state->pinfuncs[n].group; | ||
608 | *num_groups = 1; | ||
609 | |||
610 | return 0; | ||
611 | } | ||
612 | |||
613 | static int tb10x_gpio_request_enable(struct pinctrl_dev *pctl, | ||
614 | struct pinctrl_gpio_range *range, | ||
615 | unsigned pin) | ||
616 | { | ||
617 | struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctl); | ||
618 | int muxport = -1; | ||
619 | int muxmode = -1; | ||
620 | int i; | ||
621 | |||
622 | mutex_lock(&state->mutex); | ||
623 | |||
624 | /* | ||
625 | * Figure out to which port the requested GPIO belongs and how to | ||
626 | * configure that port. | ||
627 | * This loop also checks for pin conflicts between GPIOs and other | ||
628 | * functions. | ||
629 | */ | ||
630 | for (i = 0; i < state->pinfuncgrpcnt; i++) { | ||
631 | const struct tb10x_pinfuncgrp *pfg = &state->pingroups[i]; | ||
632 | unsigned int port = pfg->port; | ||
633 | unsigned int mode = pfg->mode; | ||
634 | int j; | ||
635 | |||
636 | /* | ||
637 | * Skip pin groups which are always mapped and don't need | ||
638 | * to be configured. | ||
639 | */ | ||
640 | if (port < 0) | ||
641 | continue; | ||
642 | |||
643 | for (j = 0; j < pfg->pincnt; j++) { | ||
644 | if (pin == pfg->pins[j]) { | ||
645 | if (pfg->isgpio) { | ||
646 | /* | ||
647 | * Remember the GPIO-only setting of | ||
648 | * the port this pin belongs to. | ||
649 | */ | ||
650 | muxport = port; | ||
651 | muxmode = mode; | ||
652 | } else if (state->ports[port].count | ||
653 | && (state->ports[port].mode == mode)) { | ||
654 | /* | ||
655 | * Error: The requested pin is already | ||
656 | * used for something else. | ||
657 | */ | ||
658 | mutex_unlock(&state->mutex); | ||
659 | return -EBUSY; | ||
660 | } | ||
661 | break; | ||
662 | } | ||
663 | } | ||
664 | } | ||
665 | |||
666 | /* | ||
667 | * If we haven't returned an error at this point, the GPIO pin is not | ||
668 | * used by another function and the GPIO request can be granted: | ||
669 | * Register pin as being used as GPIO so we don't allocate it to | ||
670 | * another function later. | ||
671 | */ | ||
672 | set_bit(pin, state->gpios); | ||
673 | |||
674 | /* | ||
675 | * Potential conflicts between GPIOs and pin functions were caught | ||
676 | * earlier in this function and tb10x_pinctrl_set_config will do the | ||
677 | * Right Thing, either configure the port in GPIO only mode or leave | ||
678 | * another mode compatible with this GPIO request untouched. | ||
679 | */ | ||
680 | if (muxport >= 0) | ||
681 | tb10x_pinctrl_set_config(state, muxport, muxmode); | ||
682 | |||
683 | mutex_unlock(&state->mutex); | ||
684 | |||
685 | return 0; | ||
686 | } | ||
687 | |||
688 | static void tb10x_gpio_disable_free(struct pinctrl_dev *pctl, | ||
689 | struct pinctrl_gpio_range *range, | ||
690 | unsigned pin) | ||
691 | { | ||
692 | struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctl); | ||
693 | |||
694 | mutex_lock(&state->mutex); | ||
695 | |||
696 | clear_bit(pin, state->gpios); | ||
697 | |||
698 | mutex_unlock(&state->mutex); | ||
699 | } | ||
700 | |||
701 | static int tb10x_pctl_enable(struct pinctrl_dev *pctl, | ||
702 | unsigned func_selector, unsigned group_selector) | ||
703 | { | ||
704 | struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctl); | ||
705 | const struct tb10x_pinfuncgrp *grp = &state->pingroups[group_selector]; | ||
706 | int i; | ||
707 | |||
708 | if (grp->port < 0) | ||
709 | return 0; | ||
710 | |||
711 | mutex_lock(&state->mutex); | ||
712 | |||
713 | /* | ||
714 | * Check if the requested function is compatible with previously | ||
715 | * requested functions. | ||
716 | */ | ||
717 | if (state->ports[grp->port].count | ||
718 | && (state->ports[grp->port].mode != grp->mode)) { | ||
719 | mutex_unlock(&state->mutex); | ||
720 | return -EBUSY; | ||
721 | } | ||
722 | |||
723 | /* | ||
724 | * Check if the requested function is compatible with previously | ||
725 | * requested GPIOs. | ||
726 | */ | ||
727 | for (i = 0; i < grp->pincnt; i++) | ||
728 | if (test_bit(grp->pins[i], state->gpios)) { | ||
729 | mutex_unlock(&state->mutex); | ||
730 | return -EBUSY; | ||
731 | } | ||
732 | |||
733 | tb10x_pinctrl_set_config(state, grp->port, grp->mode); | ||
734 | |||
735 | state->ports[grp->port].count++; | ||
736 | |||
737 | mutex_unlock(&state->mutex); | ||
738 | |||
739 | return 0; | ||
740 | } | ||
741 | |||
742 | static void tb10x_pctl_disable(struct pinctrl_dev *pctl, | ||
743 | unsigned func_selector, unsigned group_selector) | ||
744 | { | ||
745 | struct tb10x_pinctrl *state = pinctrl_dev_get_drvdata(pctl); | ||
746 | const struct tb10x_pinfuncgrp *grp = &state->pingroups[group_selector]; | ||
747 | |||
748 | if (grp->port < 0) | ||
749 | return; | ||
750 | |||
751 | mutex_lock(&state->mutex); | ||
752 | |||
753 | state->ports[grp->port].count--; | ||
754 | |||
755 | mutex_unlock(&state->mutex); | ||
756 | } | ||
757 | |||
758 | static struct pinmux_ops tb10x_pinmux_ops = { | ||
759 | .get_functions_count = tb10x_get_functions_count, | ||
760 | .get_function_name = tb10x_get_function_name, | ||
761 | .get_function_groups = tb10x_get_function_groups, | ||
762 | .gpio_request_enable = tb10x_gpio_request_enable, | ||
763 | .gpio_disable_free = tb10x_gpio_disable_free, | ||
764 | .enable = tb10x_pctl_enable, | ||
765 | .disable = tb10x_pctl_disable, | ||
766 | }; | ||
767 | |||
768 | static struct pinctrl_desc tb10x_pindesc = { | ||
769 | .name = "TB10x", | ||
770 | .pins = tb10x_pins, | ||
771 | .npins = ARRAY_SIZE(tb10x_pins), | ||
772 | .owner = THIS_MODULE, | ||
773 | .pctlops = &tb10x_pinctrl_ops, | ||
774 | .pmxops = &tb10x_pinmux_ops, | ||
775 | }; | ||
776 | |||
777 | static int tb10x_pinctrl_probe(struct platform_device *pdev) | ||
778 | { | ||
779 | int ret = -EINVAL; | ||
780 | struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
781 | struct device *dev = &pdev->dev; | ||
782 | struct device_node *of_node = dev->of_node; | ||
783 | struct device_node *child; | ||
784 | struct tb10x_pinctrl *state; | ||
785 | int i; | ||
786 | |||
787 | if (!of_node) { | ||
788 | dev_err(dev, "No device tree node found.\n"); | ||
789 | return -EINVAL; | ||
790 | } | ||
791 | |||
792 | if (!mem) { | ||
793 | dev_err(dev, "No memory resource defined.\n"); | ||
794 | return -EINVAL; | ||
795 | } | ||
796 | |||
797 | state = devm_kzalloc(dev, sizeof(struct tb10x_pinctrl) + | ||
798 | of_get_child_count(of_node) | ||
799 | * sizeof(struct tb10x_of_pinfunc), | ||
800 | GFP_KERNEL); | ||
801 | if (!state) | ||
802 | return -ENOMEM; | ||
803 | |||
804 | platform_set_drvdata(pdev, state); | ||
805 | state->pinfuncs = (struct tb10x_of_pinfunc *)(state + 1); | ||
806 | mutex_init(&state->mutex); | ||
807 | |||
808 | state->base = devm_ioremap_resource(dev, mem); | ||
809 | if (!state->base) { | ||
810 | dev_err(dev, "Request register region failed.\n"); | ||
811 | ret = -EBUSY; | ||
812 | goto fail; | ||
813 | } | ||
814 | |||
815 | state->pingroups = tb10x_pingroups; | ||
816 | state->pinfuncgrpcnt = ARRAY_SIZE(tb10x_pingroups); | ||
817 | |||
818 | for (i = 0; i < TB10X_PORTS; i++) | ||
819 | state->ports[i].mode = tb10x_pinctrl_get_config(state, i); | ||
820 | |||
821 | for_each_child_of_node(of_node, child) { | ||
822 | const char *name; | ||
823 | |||
824 | if (!of_property_read_string(child, "abilis,function", | ||
825 | &name)) { | ||
826 | state->pinfuncs[state->pinfuncnt].name = child->name; | ||
827 | state->pinfuncs[state->pinfuncnt].group = name; | ||
828 | state->pinfuncnt++; | ||
829 | } | ||
830 | } | ||
831 | |||
832 | state->pctl = pinctrl_register(&tb10x_pindesc, dev, state); | ||
833 | if (IS_ERR(state->pctl)) { | ||
834 | dev_err(dev, "could not register TB10x pin driver\n"); | ||
835 | ret = PTR_ERR(state->pctl); | ||
836 | goto fail; | ||
837 | } | ||
838 | |||
839 | return 0; | ||
840 | |||
841 | fail: | ||
842 | mutex_destroy(&state->mutex); | ||
843 | return ret; | ||
844 | } | ||
845 | |||
846 | static int tb10x_pinctrl_remove(struct platform_device *pdev) | ||
847 | { | ||
848 | struct tb10x_pinctrl *state = platform_get_drvdata(pdev); | ||
849 | |||
850 | pinctrl_unregister(state->pctl); | ||
851 | mutex_destroy(&state->mutex); | ||
852 | |||
853 | return 0; | ||
854 | } | ||
855 | |||
856 | |||
857 | static const struct of_device_id tb10x_pinctrl_dt_ids[] = { | ||
858 | { .compatible = "abilis,tb10x-iomux" }, | ||
859 | { } | ||
860 | }; | ||
861 | MODULE_DEVICE_TABLE(of, tb10x_pinctrl_dt_ids); | ||
862 | |||
863 | static struct platform_driver tb10x_pinctrl_pdrv = { | ||
864 | .probe = tb10x_pinctrl_probe, | ||
865 | .remove = tb10x_pinctrl_remove, | ||
866 | .driver = { | ||
867 | .name = "tb10x_pinctrl", | ||
868 | .of_match_table = of_match_ptr(tb10x_pinctrl_dt_ids), | ||
869 | .owner = THIS_MODULE | ||
870 | } | ||
871 | }; | ||
872 | |||
873 | static int __init tb10x_iopinctrl_init(void) | ||
874 | { | ||
875 | return platform_driver_register(&tb10x_pinctrl_pdrv); | ||
876 | } | ||
877 | |||
878 | static void __exit tb10x_iopinctrl_exit(void) | ||
879 | { | ||
880 | platform_driver_unregister(&tb10x_pinctrl_pdrv); | ||
881 | } | ||
882 | |||
883 | MODULE_AUTHOR("Christian Ruppert <christian.ruppert@abilis.com>"); | ||
884 | MODULE_LICENSE("GPL"); | ||
885 | module_init(tb10x_iopinctrl_init); | ||
886 | module_exit(tb10x_iopinctrl_exit); | ||