Commit | Line | Data |
---|---|---|
ca5481c6 PM |
1 | /* |
2 | * SuperH Pin Function Controller pinmux support. | |
3 | * | |
4 | * Copyright (C) 2012 Paul Mundt | |
5 | * | |
6 | * This file is subject to the terms and conditions of the GNU General Public | |
7 | * License. See the file "COPYING" in the main directory of this archive | |
8 | * for more details. | |
9 | */ | |
54407110 | 10 | |
c6193eac | 11 | #define DRV_NAME "sh-pfc" |
f9492fda | 12 | #define pr_fmt(fmt) KBUILD_MODNAME " pinctrl: " fmt |
ca5481c6 | 13 | |
1724acfd | 14 | #include <linux/device.h> |
90efde22 | 15 | #include <linux/err.h> |
ca5481c6 PM |
16 | #include <linux/init.h> |
17 | #include <linux/module.h> | |
ca5481c6 | 18 | #include <linux/pinctrl/consumer.h> |
ca5481c6 | 19 | #include <linux/pinctrl/pinconf.h> |
ca5481c6 | 20 | #include <linux/pinctrl/pinconf-generic.h> |
90efde22 LP |
21 | #include <linux/pinctrl/pinctrl.h> |
22 | #include <linux/pinctrl/pinmux.h> | |
90efde22 LP |
23 | #include <linux/slab.h> |
24 | #include <linux/spinlock.h> | |
ca5481c6 | 25 | |
f9165132 LP |
26 | #include "core.h" |
27 | ||
ca5481c6 PM |
28 | struct sh_pfc_pinctrl { |
29 | struct pinctrl_dev *pctl; | |
dcc427e1 | 30 | struct pinctrl_desc pctl_desc; |
dcc427e1 | 31 | |
ca5481c6 PM |
32 | struct sh_pfc *pfc; |
33 | ||
3d8d9f1d | 34 | struct pinctrl_pin_desc *pins; |
ca5481c6 PM |
35 | }; |
36 | ||
e3f805e8 | 37 | static int sh_pfc_get_groups_count(struct pinctrl_dev *pctldev) |
ca5481c6 | 38 | { |
e3f805e8 PM |
39 | struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); |
40 | ||
3d8d9f1d | 41 | return pmx->pfc->info->nr_groups; |
ca5481c6 PM |
42 | } |
43 | ||
e3f805e8 | 44 | static const char *sh_pfc_get_group_name(struct pinctrl_dev *pctldev, |
ca5481c6 PM |
45 | unsigned selector) |
46 | { | |
e3f805e8 PM |
47 | struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); |
48 | ||
3d8d9f1d | 49 | return pmx->pfc->info->groups[selector].name; |
ca5481c6 PM |
50 | } |
51 | ||
3d8d9f1d | 52 | static int sh_pfc_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, |
ca5481c6 PM |
53 | const unsigned **pins, unsigned *num_pins) |
54 | { | |
e3f805e8 PM |
55 | struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); |
56 | ||
3d8d9f1d LP |
57 | *pins = pmx->pfc->info->groups[selector].pins; |
58 | *num_pins = pmx->pfc->info->groups[selector].nr_pins; | |
e3f805e8 PM |
59 | |
60 | return 0; | |
ca5481c6 PM |
61 | } |
62 | ||
fdd85ec3 PM |
63 | static void sh_pfc_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, |
64 | unsigned offset) | |
65 | { | |
66 | seq_printf(s, "%s", DRV_NAME); | |
67 | } | |
68 | ||
fe330ce8 | 69 | static const struct pinctrl_ops sh_pfc_pinctrl_ops = { |
e3f805e8 PM |
70 | .get_groups_count = sh_pfc_get_groups_count, |
71 | .get_group_name = sh_pfc_get_group_name, | |
ca5481c6 | 72 | .get_group_pins = sh_pfc_get_group_pins, |
fdd85ec3 | 73 | .pin_dbg_show = sh_pfc_pin_dbg_show, |
ca5481c6 PM |
74 | }; |
75 | ||
d93a891f PM |
76 | static int sh_pfc_get_functions_count(struct pinctrl_dev *pctldev) |
77 | { | |
78 | struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); | |
79 | ||
3d8d9f1d | 80 | return pmx->pfc->info->nr_functions; |
d93a891f PM |
81 | } |
82 | ||
83 | static const char *sh_pfc_get_function_name(struct pinctrl_dev *pctldev, | |
84 | unsigned selector) | |
85 | { | |
86 | struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); | |
87 | ||
3d8d9f1d | 88 | return pmx->pfc->info->functions[selector].name; |
d93a891f | 89 | } |
ca5481c6 | 90 | |
3d8d9f1d LP |
91 | static int sh_pfc_get_function_groups(struct pinctrl_dev *pctldev, |
92 | unsigned selector, | |
ca5481c6 PM |
93 | const char * const **groups, |
94 | unsigned * const num_groups) | |
95 | { | |
d93a891f PM |
96 | struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); |
97 | ||
3d8d9f1d LP |
98 | *groups = pmx->pfc->info->functions[selector].groups; |
99 | *num_groups = pmx->pfc->info->functions[selector].nr_groups; | |
d93a891f | 100 | |
ca5481c6 PM |
101 | return 0; |
102 | } | |
103 | ||
3d8d9f1d | 104 | static int sh_pfc_func_enable(struct pinctrl_dev *pctldev, unsigned selector, |
ca5481c6 PM |
105 | unsigned group) |
106 | { | |
3d8d9f1d LP |
107 | struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); |
108 | struct sh_pfc *pfc = pmx->pfc; | |
109 | const struct sh_pfc_pin_group *grp = &pfc->info->groups[group]; | |
110 | unsigned long flags; | |
111 | unsigned int i; | |
112 | int ret = -EINVAL; | |
113 | ||
114 | spin_lock_irqsave(&pfc->lock, flags); | |
115 | ||
116 | for (i = 0; i < grp->nr_pins; ++i) { | |
117 | if (sh_pfc_config_mux(pfc, grp->mux[i], PINMUX_TYPE_FUNCTION, | |
118 | GPIO_CFG_DRYRUN)) | |
119 | goto done; | |
120 | ||
121 | if (sh_pfc_config_mux(pfc, grp->mux[i], PINMUX_TYPE_FUNCTION, | |
122 | GPIO_CFG_REQ)) | |
123 | goto done; | |
124 | } | |
125 | ||
126 | ret = 0; | |
127 | ||
128 | done: | |
129 | spin_unlock_irqrestore(&pfc->lock, flags); | |
130 | return ret; | |
ca5481c6 PM |
131 | } |
132 | ||
3d8d9f1d | 133 | static void sh_pfc_func_disable(struct pinctrl_dev *pctldev, unsigned selector, |
ca5481c6 PM |
134 | unsigned group) |
135 | { | |
3d8d9f1d LP |
136 | struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); |
137 | struct sh_pfc *pfc = pmx->pfc; | |
138 | const struct sh_pfc_pin_group *grp = &pfc->info->groups[group]; | |
139 | unsigned long flags; | |
140 | unsigned int i; | |
141 | ||
142 | spin_lock_irqsave(&pfc->lock, flags); | |
143 | ||
144 | for (i = 0; i < grp->nr_pins; ++i) | |
145 | sh_pfc_config_mux(pfc, grp->mux[i], PINMUX_TYPE_FUNCTION, | |
146 | GPIO_CFG_FREE); | |
147 | ||
148 | spin_unlock_irqrestore(&pfc->lock, flags); | |
ca5481c6 PM |
149 | } |
150 | ||
fdd85ec3 PM |
151 | static int sh_pfc_reconfig_pin(struct sh_pfc *pfc, unsigned offset, |
152 | int new_type) | |
153 | { | |
934cb02b LP |
154 | struct sh_pfc_pin *pin = sh_pfc_get_pin(pfc, offset); |
155 | unsigned int mark = pin->enum_id; | |
fdd85ec3 PM |
156 | unsigned long flags; |
157 | int pinmux_type; | |
158 | int ret = -EINVAL; | |
159 | ||
160 | spin_lock_irqsave(&pfc->lock, flags); | |
161 | ||
934cb02b | 162 | pinmux_type = pin->flags & PINMUX_FLAG_TYPE; |
fdd85ec3 PM |
163 | |
164 | /* | |
165 | * See if the present config needs to first be de-configured. | |
166 | */ | |
167 | switch (pinmux_type) { | |
168 | case PINMUX_TYPE_GPIO: | |
169 | break; | |
170 | case PINMUX_TYPE_OUTPUT: | |
171 | case PINMUX_TYPE_INPUT: | |
172 | case PINMUX_TYPE_INPUT_PULLUP: | |
173 | case PINMUX_TYPE_INPUT_PULLDOWN: | |
a68fdca9 | 174 | sh_pfc_config_mux(pfc, mark, pinmux_type, GPIO_CFG_FREE); |
fdd85ec3 PM |
175 | break; |
176 | default: | |
177 | goto err; | |
178 | } | |
179 | ||
180 | /* | |
181 | * Dry run | |
182 | */ | |
a68fdca9 | 183 | if (sh_pfc_config_mux(pfc, mark, new_type, GPIO_CFG_DRYRUN) != 0) |
fdd85ec3 PM |
184 | goto err; |
185 | ||
186 | /* | |
187 | * Request | |
188 | */ | |
a68fdca9 | 189 | if (sh_pfc_config_mux(pfc, mark, new_type, GPIO_CFG_REQ) != 0) |
fdd85ec3 PM |
190 | goto err; |
191 | ||
934cb02b LP |
192 | pin->flags &= ~PINMUX_FLAG_TYPE; |
193 | pin->flags |= new_type; | |
fdd85ec3 PM |
194 | |
195 | ret = 0; | |
196 | ||
197 | err: | |
198 | spin_unlock_irqrestore(&pfc->lock, flags); | |
199 | ||
200 | return ret; | |
201 | } | |
202 | ||
ca5481c6 PM |
203 | static int sh_pfc_gpio_request_enable(struct pinctrl_dev *pctldev, |
204 | struct pinctrl_gpio_range *range, | |
205 | unsigned offset) | |
206 | { | |
207 | struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); | |
208 | struct sh_pfc *pfc = pmx->pfc; | |
934cb02b | 209 | struct sh_pfc_pin *pin = sh_pfc_get_pin(pfc, offset); |
ca5481c6 | 210 | unsigned long flags; |
d93a891f | 211 | int ret, pinmux_type; |
ca5481c6 PM |
212 | |
213 | spin_lock_irqsave(&pfc->lock, flags); | |
214 | ||
934cb02b | 215 | pinmux_type = pin->flags & PINMUX_FLAG_TYPE; |
ca5481c6 | 216 | |
d93a891f | 217 | switch (pinmux_type) { |
d93a891f | 218 | case PINMUX_TYPE_GPIO: |
16d74ebe PM |
219 | case PINMUX_TYPE_INPUT: |
220 | case PINMUX_TYPE_OUTPUT: | |
d93a891f | 221 | break; |
2119f7c9 | 222 | case PINMUX_TYPE_FUNCTION: |
d93a891f PM |
223 | default: |
224 | pr_err("Unsupported mux type (%d), bailing...\n", pinmux_type); | |
077664a2 LP |
225 | ret = -ENOTSUPP; |
226 | goto err; | |
d93a891f | 227 | } |
ca5481c6 PM |
228 | |
229 | ret = 0; | |
230 | ||
231 | err: | |
232 | spin_unlock_irqrestore(&pfc->lock, flags); | |
233 | ||
234 | return ret; | |
235 | } | |
236 | ||
237 | static void sh_pfc_gpio_disable_free(struct pinctrl_dev *pctldev, | |
238 | struct pinctrl_gpio_range *range, | |
239 | unsigned offset) | |
240 | { | |
241 | struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); | |
242 | struct sh_pfc *pfc = pmx->pfc; | |
934cb02b | 243 | struct sh_pfc_pin *pin = sh_pfc_get_pin(pfc, offset); |
ca5481c6 PM |
244 | unsigned long flags; |
245 | int pinmux_type; | |
246 | ||
247 | spin_lock_irqsave(&pfc->lock, flags); | |
248 | ||
934cb02b | 249 | pinmux_type = pin->flags & PINMUX_FLAG_TYPE; |
ca5481c6 | 250 | |
934cb02b | 251 | sh_pfc_config_mux(pfc, pin->enum_id, pinmux_type, GPIO_CFG_FREE); |
ca5481c6 | 252 | |
ca5481c6 PM |
253 | spin_unlock_irqrestore(&pfc->lock, flags); |
254 | } | |
255 | ||
256 | static int sh_pfc_gpio_set_direction(struct pinctrl_dev *pctldev, | |
257 | struct pinctrl_gpio_range *range, | |
258 | unsigned offset, bool input) | |
259 | { | |
260 | struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); | |
fdd85ec3 | 261 | int type = input ? PINMUX_TYPE_INPUT : PINMUX_TYPE_OUTPUT; |
ca5481c6 | 262 | |
fdd85ec3 | 263 | return sh_pfc_reconfig_pin(pmx->pfc, offset, type); |
ca5481c6 PM |
264 | } |
265 | ||
fe330ce8 | 266 | static const struct pinmux_ops sh_pfc_pinmux_ops = { |
d93a891f PM |
267 | .get_functions_count = sh_pfc_get_functions_count, |
268 | .get_function_name = sh_pfc_get_function_name, | |
ca5481c6 | 269 | .get_function_groups = sh_pfc_get_function_groups, |
3d8d9f1d LP |
270 | .enable = sh_pfc_func_enable, |
271 | .disable = sh_pfc_func_disable, | |
ca5481c6 PM |
272 | .gpio_request_enable = sh_pfc_gpio_request_enable, |
273 | .gpio_disable_free = sh_pfc_gpio_disable_free, | |
274 | .gpio_set_direction = sh_pfc_gpio_set_direction, | |
275 | }; | |
276 | ||
934cb02b | 277 | static int sh_pfc_pinconf_get(struct pinctrl_dev *pctldev, unsigned _pin, |
ca5481c6 PM |
278 | unsigned long *config) |
279 | { | |
fdd85ec3 PM |
280 | struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); |
281 | struct sh_pfc *pfc = pmx->pfc; | |
934cb02b | 282 | struct sh_pfc_pin *pin = sh_pfc_get_pin(pfc, _pin); |
d93a891f | 283 | |
934cb02b | 284 | *config = pin->flags & PINMUX_FLAG_TYPE; |
d93a891f | 285 | |
fdd85ec3 | 286 | return 0; |
ca5481c6 PM |
287 | } |
288 | ||
289 | static int sh_pfc_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin, | |
290 | unsigned long config) | |
291 | { | |
fdd85ec3 | 292 | struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); |
fdd85ec3 PM |
293 | |
294 | /* Validate the new type */ | |
295 | if (config >= PINMUX_FLAG_TYPE) | |
296 | return -EINVAL; | |
297 | ||
298 | return sh_pfc_reconfig_pin(pmx->pfc, pin, config); | |
299 | } | |
300 | ||
301 | static void sh_pfc_pinconf_dbg_show(struct pinctrl_dev *pctldev, | |
302 | struct seq_file *s, unsigned pin) | |
303 | { | |
304 | const char *pinmux_type_str[] = { | |
305 | [PINMUX_TYPE_NONE] = "none", | |
306 | [PINMUX_TYPE_FUNCTION] = "function", | |
307 | [PINMUX_TYPE_GPIO] = "gpio", | |
308 | [PINMUX_TYPE_OUTPUT] = "output", | |
309 | [PINMUX_TYPE_INPUT] = "input", | |
310 | [PINMUX_TYPE_INPUT_PULLUP] = "input bias pull up", | |
311 | [PINMUX_TYPE_INPUT_PULLDOWN] = "input bias pull down", | |
312 | }; | |
313 | unsigned long config; | |
314 | int rc; | |
315 | ||
316 | rc = sh_pfc_pinconf_get(pctldev, pin, &config); | |
317 | if (unlikely(rc != 0)) | |
318 | return; | |
319 | ||
320 | seq_printf(s, " %s", pinmux_type_str[config]); | |
ca5481c6 PM |
321 | } |
322 | ||
fe330ce8 | 323 | static const struct pinconf_ops sh_pfc_pinconf_ops = { |
ca5481c6 PM |
324 | .pin_config_get = sh_pfc_pinconf_get, |
325 | .pin_config_set = sh_pfc_pinconf_set, | |
fdd85ec3 | 326 | .pin_config_dbg_show = sh_pfc_pinconf_dbg_show, |
ca5481c6 PM |
327 | }; |
328 | ||
63d57383 LP |
329 | /* PFC ranges -> pinctrl pin descs */ |
330 | static int sh_pfc_map_pins(struct sh_pfc *pfc, struct sh_pfc_pinctrl *pmx) | |
ca5481c6 | 331 | { |
63d57383 LP |
332 | const struct pinmux_range *ranges; |
333 | struct pinmux_range def_range; | |
334 | unsigned int nr_ranges; | |
335 | unsigned int nr_pins; | |
336 | unsigned int i; | |
337 | ||
338 | if (pfc->info->ranges == NULL) { | |
339 | def_range.begin = 0; | |
340 | def_range.end = pfc->info->nr_pins - 1; | |
341 | ranges = &def_range; | |
342 | nr_ranges = 1; | |
343 | } else { | |
344 | ranges = pfc->info->ranges; | |
345 | nr_ranges = pfc->info->nr_ranges; | |
346 | } | |
ca5481c6 | 347 | |
3d8d9f1d LP |
348 | pmx->pins = devm_kzalloc(pfc->dev, |
349 | sizeof(*pmx->pins) * pfc->info->nr_pins, | |
1724acfd | 350 | GFP_KERNEL); |
3d8d9f1d | 351 | if (unlikely(!pmx->pins)) |
ca5481c6 | 352 | return -ENOMEM; |
ca5481c6 | 353 | |
63d57383 LP |
354 | for (i = 0, nr_pins = 0; i < nr_ranges; ++i) { |
355 | const struct pinmux_range *range = &ranges[i]; | |
356 | unsigned int number; | |
357 | ||
358 | for (number = range->begin; number <= range->end; | |
359 | number++, nr_pins++) { | |
3d8d9f1d | 360 | struct pinctrl_pin_desc *pin = &pmx->pins[nr_pins]; |
63d57383 | 361 | struct sh_pfc_pin *info = &pfc->info->pins[nr_pins]; |
ca5481c6 | 362 | |
63d57383 LP |
363 | pin->number = number; |
364 | pin->name = info->name; | |
365 | } | |
ca5481c6 PM |
366 | } |
367 | ||
63d57383 LP |
368 | pfc->nr_pins = ranges[nr_ranges-1].end + 1; |
369 | ||
370 | return nr_ranges; | |
ca5481c6 PM |
371 | } |
372 | ||
c6193eac | 373 | int sh_pfc_register_pinctrl(struct sh_pfc *pfc) |
ca5481c6 | 374 | { |
c6193eac | 375 | struct sh_pfc_pinctrl *pmx; |
63d57383 | 376 | int nr_ranges; |
ca5481c6 | 377 | |
1724acfd | 378 | pmx = devm_kzalloc(pfc->dev, sizeof(*pmx), GFP_KERNEL); |
c6193eac LP |
379 | if (unlikely(!pmx)) |
380 | return -ENOMEM; | |
381 | ||
c6193eac LP |
382 | pmx->pfc = pfc; |
383 | pfc->pinctrl = pmx; | |
ca5481c6 | 384 | |
63d57383 LP |
385 | nr_ranges = sh_pfc_map_pins(pfc, pmx); |
386 | if (unlikely(nr_ranges < 0)) | |
387 | return nr_ranges; | |
ca5481c6 | 388 | |
dcc427e1 LP |
389 | pmx->pctl_desc.name = DRV_NAME; |
390 | pmx->pctl_desc.owner = THIS_MODULE; | |
391 | pmx->pctl_desc.pctlops = &sh_pfc_pinctrl_ops; | |
392 | pmx->pctl_desc.pmxops = &sh_pfc_pinmux_ops; | |
393 | pmx->pctl_desc.confops = &sh_pfc_pinconf_ops; | |
3d8d9f1d | 394 | pmx->pctl_desc.pins = pmx->pins; |
63d57383 | 395 | pmx->pctl_desc.npins = pfc->info->nr_pins; |
dcc427e1 LP |
396 | |
397 | pmx->pctl = pinctrl_register(&pmx->pctl_desc, pfc->dev, pmx); | |
fd9d05b0 WY |
398 | if (pmx->pctl == NULL) |
399 | return -EINVAL; | |
ca5481c6 | 400 | |
ca5481c6 | 401 | return 0; |
ca5481c6 PM |
402 | } |
403 | ||
c6193eac | 404 | int sh_pfc_unregister_pinctrl(struct sh_pfc *pfc) |
ca5481c6 | 405 | { |
c6193eac | 406 | struct sh_pfc_pinctrl *pmx = pfc->pinctrl; |
ca5481c6 | 407 | |
ca5481c6 PM |
408 | pinctrl_unregister(pmx->pctl); |
409 | ||
c6193eac | 410 | pfc->pinctrl = NULL; |
ca5481c6 PM |
411 | return 0; |
412 | } |