aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/sh/pfc/pinctrl.c
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2012-07-09 23:08:14 -0400
committerPaul Mundt <lethal@linux-sh.org>2012-07-09 23:08:14 -0400
commitca5481c68e9fbcea62bb3c78ae6cccf99ca8fb73 (patch)
tree977e9adb0bc0b8588b111c851e7d9230d72cd3b3 /drivers/sh/pfc/pinctrl.c
parent72c7afa10f272710028f244da65d35e571144085 (diff)
sh: pfc: Rudimentary pinctrl-backed GPIO support.
This begins the migration of the PFC core to the pinctrl subsystem. Initial support is very basic, with the bulk of the implementation simply being nopped out in such a way to allow registration with the pinctrl core to succeed. The gpio chip driver is stripped down considerably now relying purely on pinctrl API calls to manage the bulk of its operations. This provides a basis for further PFC refactoring, including decoupling pin functions from the GPIO API, establishing pin groups, and so forth. These will all be dealt with incrementally so as to introduce as few growing and migratory pains to tree-wide PFC pinmux users today. When the interfaces have been well established and in-tree users have been migrated off of the legacy interfaces it will be possible to strip down the core considerably, leading to eventual drivers/pinctrl rehoming. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'drivers/sh/pfc/pinctrl.c')
-rw-r--r--drivers/sh/pfc/pinctrl.c371
1 files changed, 371 insertions, 0 deletions
diff --git a/drivers/sh/pfc/pinctrl.c b/drivers/sh/pfc/pinctrl.c
new file mode 100644
index 000000000000..6008328594ff
--- /dev/null
+++ b/drivers/sh/pfc/pinctrl.c
@@ -0,0 +1,371 @@
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 */
10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/sh_pfc.h>
15#include <linux/err.h>
16#include <linux/slab.h>
17#include <linux/platform_device.h>
18#include <linux/pinctrl/consumer.h>
19#include <linux/pinctrl/pinctrl.h>
20#include <linux/pinctrl/pinconf.h>
21#include <linux/pinctrl/pinmux.h>
22#include <linux/pinctrl/pinconf-generic.h>
23
24struct sh_pfc_pinctrl {
25 struct pinctrl_dev *pctl;
26 struct sh_pfc *pfc;
27
28 struct pinctrl_pin_desc *pads;
29 unsigned int nr_pads;
30};
31
32static struct sh_pfc_pinctrl *sh_pfc_pmx;
33
34/*
35 * No group support yet
36 */
37static int sh_pfc_get_noop_count(struct pinctrl_dev *pctldev)
38{
39 return 0;
40}
41
42static const char *sh_pfc_get_noop_name(struct pinctrl_dev *pctldev,
43 unsigned selector)
44{
45 return NULL;
46}
47
48static int sh_pfc_get_group_pins(struct pinctrl_dev *pctldev, unsigned group,
49 const unsigned **pins, unsigned *num_pins)
50{
51 return -ENOTSUPP;
52}
53
54static struct pinctrl_ops sh_pfc_pinctrl_ops = {
55 .get_groups_count = sh_pfc_get_noop_count,
56 .get_group_name = sh_pfc_get_noop_name,
57 .get_group_pins = sh_pfc_get_group_pins,
58};
59
60
61/*
62 * No function support yet
63 */
64static int sh_pfc_get_function_groups(struct pinctrl_dev *pctldev, unsigned func,
65 const char * const **groups,
66 unsigned * const num_groups)
67{
68 return 0;
69}
70
71static int sh_pfc_noop_enable(struct pinctrl_dev *pctldev, unsigned func,
72 unsigned group)
73{
74 return 0;
75}
76
77static void sh_pfc_noop_disable(struct pinctrl_dev *pctldev, unsigned func,
78 unsigned group)
79{
80}
81
82static int sh_pfc_gpio_request_enable(struct pinctrl_dev *pctldev,
83 struct pinctrl_gpio_range *range,
84 unsigned offset)
85{
86 struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev);
87 struct sh_pfc *pfc = pmx->pfc;
88 struct pinmux_data_reg *dummy;
89 unsigned long flags;
90 int i, ret, pinmux_type;
91
92 ret = -EINVAL;
93
94 spin_lock_irqsave(&pfc->lock, flags);
95
96 if ((pfc->gpios[offset].flags & PINMUX_FLAG_TYPE) != PINMUX_TYPE_NONE)
97 goto err;
98
99 /* setup pin function here if no data is associated with pin */
100 if (sh_pfc_get_data_reg(pfc, offset, &dummy, &i) != 0) {
101 pinmux_type = PINMUX_TYPE_FUNCTION;
102
103 if (sh_pfc_config_gpio(pfc, offset,
104 pinmux_type,
105 GPIO_CFG_DRYRUN) != 0)
106 goto err;
107
108 if (sh_pfc_config_gpio(pfc, offset,
109 pinmux_type,
110 GPIO_CFG_REQ) != 0)
111 goto err;
112 } else
113 pinmux_type = PINMUX_TYPE_GPIO;
114
115 pfc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE;
116 pfc->gpios[offset].flags |= pinmux_type;
117
118 ret = 0;
119
120err:
121 spin_unlock_irqrestore(&pfc->lock, flags);
122
123 return ret;
124}
125
126static void sh_pfc_gpio_disable_free(struct pinctrl_dev *pctldev,
127 struct pinctrl_gpio_range *range,
128 unsigned offset)
129{
130 struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev);
131 struct sh_pfc *pfc = pmx->pfc;
132 unsigned long flags;
133 int pinmux_type;
134
135 spin_lock_irqsave(&pfc->lock, flags);
136
137 pinmux_type = pfc->gpios[offset].flags & PINMUX_FLAG_TYPE;
138
139 sh_pfc_config_gpio(pfc, offset, pinmux_type, GPIO_CFG_FREE);
140
141 pfc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE;
142 pfc->gpios[offset].flags |= PINMUX_TYPE_NONE;
143
144 spin_unlock_irqrestore(&pfc->lock, flags);
145}
146
147static int sh_pfc_gpio_set_direction(struct pinctrl_dev *pctldev,
148 struct pinctrl_gpio_range *range,
149 unsigned offset, bool input)
150{
151 struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev);
152 struct sh_pfc *pfc = pmx->pfc;
153 unsigned long flags;
154 int pinmux_type, new_pinmux_type;
155 int ret = -EINVAL;
156
157 new_pinmux_type = input ? PINMUX_TYPE_INPUT : PINMUX_TYPE_OUTPUT;
158
159 spin_lock_irqsave(&pfc->lock, flags);
160
161 pinmux_type = pfc->gpios[offset].flags & PINMUX_FLAG_TYPE;
162
163 switch (pinmux_type) {
164 case PINMUX_TYPE_GPIO:
165 break;
166 case PINMUX_TYPE_OUTPUT:
167 case PINMUX_TYPE_INPUT:
168 case PINMUX_TYPE_INPUT_PULLUP:
169 case PINMUX_TYPE_INPUT_PULLDOWN:
170 sh_pfc_config_gpio(pfc, offset, pinmux_type, GPIO_CFG_FREE);
171 break;
172 default:
173 goto err;
174 }
175
176 if (sh_pfc_config_gpio(pfc, offset,
177 new_pinmux_type,
178 GPIO_CFG_DRYRUN) != 0)
179 goto err;
180
181 if (sh_pfc_config_gpio(pfc, offset,
182 new_pinmux_type,
183 GPIO_CFG_REQ) != 0)
184 BUG();
185
186 pfc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE;
187 pfc->gpios[offset].flags |= new_pinmux_type;
188
189 ret = 0;
190
191err:
192 spin_unlock_irqrestore(&pfc->lock, flags);
193
194 return ret;
195}
196
197static struct pinmux_ops sh_pfc_pinmux_ops = {
198 .get_functions_count = sh_pfc_get_noop_count,
199 .get_function_name = sh_pfc_get_noop_name,
200 .get_function_groups = sh_pfc_get_function_groups,
201 .enable = sh_pfc_noop_enable,
202 .disable = sh_pfc_noop_disable,
203 .gpio_request_enable = sh_pfc_gpio_request_enable,
204 .gpio_disable_free = sh_pfc_gpio_disable_free,
205 .gpio_set_direction = sh_pfc_gpio_set_direction,
206};
207
208static int sh_pfc_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin,
209 unsigned long *config)
210{
211 return -ENOTSUPP;
212}
213
214static int sh_pfc_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin,
215 unsigned long config)
216{
217 return -EINVAL;
218}
219
220static struct pinconf_ops sh_pfc_pinconf_ops = {
221 .is_generic = true,
222 .pin_config_get = sh_pfc_pinconf_get,
223 .pin_config_set = sh_pfc_pinconf_set,
224};
225
226static struct pinctrl_gpio_range sh_pfc_gpio_range = {
227 .name = KBUILD_MODNAME,
228 .id = 0,
229};
230
231static struct pinctrl_desc sh_pfc_pinctrl_desc = {
232 .name = KBUILD_MODNAME,
233 .owner = THIS_MODULE,
234 .pctlops = &sh_pfc_pinctrl_ops,
235 .pmxops = &sh_pfc_pinmux_ops,
236 .confops = &sh_pfc_pinconf_ops,
237};
238
239int sh_pfc_register_pinctrl(struct sh_pfc *pfc)
240{
241 sh_pfc_pmx = kmalloc(sizeof(struct sh_pfc_pinctrl), GFP_KERNEL);
242 if (unlikely(!sh_pfc_pmx))
243 return -ENOMEM;
244
245 sh_pfc_pmx->pfc = pfc;
246
247 return 0;
248}
249
250/* pinmux ranges -> pinctrl pin descs */
251static int __devinit sh_pfc_map_gpios(struct sh_pfc *pfc,
252 struct sh_pfc_pinctrl *pmx)
253{
254 int i;
255
256 pmx->nr_pads = pfc->last_gpio - pfc->first_gpio + 1;
257
258 pmx->pads = kmalloc(sizeof(struct pinctrl_pin_desc) * pmx->nr_pads,
259 GFP_KERNEL);
260 if (unlikely(!pmx->pads)) {
261 pmx->nr_pads = 0;
262 return -ENOMEM;
263 }
264
265 /*
266 * We don't necessarily have a 1:1 mapping between pin and linux
267 * GPIO number, as the latter maps to the associated enum_id.
268 * Care needs to be taken to translate back to pin space when
269 * dealing with any pin configurations.
270 */
271 for (i = 0; i < pmx->nr_pads; i++) {
272 struct pinctrl_pin_desc *pin = pmx->pads + i;
273 struct pinmux_gpio *gpio = pfc->gpios + i;
274
275 pin->number = pfc->first_gpio + i;
276 pin->name = gpio->name;
277 }
278
279 sh_pfc_pinctrl_desc.pins = pmx->pads;
280 sh_pfc_pinctrl_desc.npins = pmx->nr_pads;
281
282 return 0;
283}
284
285static int __devinit sh_pfc_pinctrl_probe(struct platform_device *pdev)
286{
287 struct sh_pfc *pfc;
288 int ret;
289
290 if (unlikely(!sh_pfc_pmx))
291 return -ENODEV;
292
293 pfc = sh_pfc_pmx->pfc;
294
295 ret = sh_pfc_map_gpios(pfc, sh_pfc_pmx);
296 if (unlikely(ret != 0))
297 return ret;
298
299 sh_pfc_pmx->pctl = pinctrl_register(&sh_pfc_pinctrl_desc, &pdev->dev,
300 sh_pfc_pmx);
301 if (IS_ERR(sh_pfc_pmx->pctl)) {
302 ret = PTR_ERR(sh_pfc_pmx->pctl);
303 goto out;
304 }
305
306 sh_pfc_gpio_range.npins = pfc->last_gpio - pfc->first_gpio + 1;
307 sh_pfc_gpio_range.base = pfc->first_gpio;
308 sh_pfc_gpio_range.pin_base = pfc->first_gpio;
309
310 pinctrl_add_gpio_range(sh_pfc_pmx->pctl, &sh_pfc_gpio_range);
311
312 platform_set_drvdata(pdev, sh_pfc_pmx);
313
314 return 0;
315
316out:
317 kfree(sh_pfc_pmx->pads);
318 kfree(sh_pfc_pmx);
319 return ret;
320}
321
322static int __devexit sh_pfc_pinctrl_remove(struct platform_device *pdev)
323{
324 struct sh_pfc_pinctrl *pmx = platform_get_drvdata(pdev);
325
326 pinctrl_remove_gpio_range(pmx->pctl, &sh_pfc_gpio_range);
327 pinctrl_unregister(pmx->pctl);
328
329 platform_set_drvdata(pdev, NULL);
330
331 kfree(sh_pfc_pmx->pads);
332 kfree(sh_pfc_pmx);
333
334 return 0;
335}
336
337static struct platform_driver sh_pfc_pinctrl_driver = {
338 .probe = sh_pfc_pinctrl_probe,
339 .remove = __devexit_p(sh_pfc_pinctrl_remove),
340 .driver = {
341 .name = KBUILD_MODNAME,
342 .owner = THIS_MODULE,
343 },
344};
345
346static struct platform_device sh_pfc_pinctrl_device = {
347 .name = KBUILD_MODNAME,
348 .id = -1,
349};
350
351static int __init sh_pfc_pinctrl_init(void)
352{
353 int rc;
354
355 rc = platform_driver_register(&sh_pfc_pinctrl_driver);
356 if (likely(!rc)) {
357 rc = platform_device_register(&sh_pfc_pinctrl_device);
358 if (unlikely(rc))
359 platform_driver_unregister(&sh_pfc_pinctrl_driver);
360 }
361
362 return rc;
363}
364
365static void __exit sh_pfc_pinctrl_exit(void)
366{
367 platform_driver_unregister(&sh_pfc_pinctrl_driver);
368}
369
370subsys_initcall(sh_pfc_pinctrl_init);
371module_exit(sh_pfc_pinctrl_exit);