diff options
author | Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> | 2013-03-10 11:44:02 -0400 |
---|---|---|
committer | Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> | 2013-03-15 08:33:54 -0400 |
commit | c58d9c1b26e3ab2933abc7d5444e945ddad44809 (patch) | |
tree | e751a0f696141d30aac72ba518d9c0a1db309845 /drivers/pinctrl/sh-pfc/pinctrl.c | |
parent | b705c054255ae3264aa02d46347e9cfbcf26523a (diff) |
sh-pfc: Implement generic pinconf support
The existing PFC pinconf implementation, tied to the PFC-specific pin
types, isn't used by drivers or boards. Replace it with the generic
pinconf types to implement bias (pull-up/down) setup. Other pin
configuration options can be implemented later if needed.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/pinctrl/sh-pfc/pinctrl.c')
-rw-r--r-- | drivers/pinctrl/sh-pfc/pinctrl.c | 123 |
1 files changed, 93 insertions, 30 deletions
diff --git a/drivers/pinctrl/sh-pfc/pinctrl.c b/drivers/pinctrl/sh-pfc/pinctrl.c index c15091096f65..79fa170b4872 100644 --- a/drivers/pinctrl/sh-pfc/pinctrl.c +++ b/drivers/pinctrl/sh-pfc/pinctrl.c | |||
@@ -24,6 +24,8 @@ | |||
24 | #include <linux/spinlock.h> | 24 | #include <linux/spinlock.h> |
25 | 25 | ||
26 | #include "core.h" | 26 | #include "core.h" |
27 | #include "../core.h" | ||
28 | #include "../pinconf.h" | ||
27 | 29 | ||
28 | struct sh_pfc_pin_config { | 30 | struct sh_pfc_pin_config { |
29 | u32 type; | 31 | u32 type; |
@@ -230,57 +232,118 @@ static const struct pinmux_ops sh_pfc_pinmux_ops = { | |||
230 | .gpio_set_direction = sh_pfc_gpio_set_direction, | 232 | .gpio_set_direction = sh_pfc_gpio_set_direction, |
231 | }; | 233 | }; |
232 | 234 | ||
235 | /* Check whether the requested parameter is supported for a pin. */ | ||
236 | static bool sh_pfc_pinconf_validate(struct sh_pfc *pfc, unsigned int _pin, | ||
237 | enum pin_config_param param) | ||
238 | { | ||
239 | int idx = sh_pfc_get_pin_index(pfc, _pin); | ||
240 | const struct sh_pfc_pin *pin = &pfc->info->pins[idx]; | ||
241 | |||
242 | switch (param) { | ||
243 | case PIN_CONFIG_BIAS_DISABLE: | ||
244 | return true; | ||
245 | |||
246 | case PIN_CONFIG_BIAS_PULL_UP: | ||
247 | return pin->configs & SH_PFC_PIN_CFG_PULL_UP; | ||
248 | |||
249 | case PIN_CONFIG_BIAS_PULL_DOWN: | ||
250 | return pin->configs & SH_PFC_PIN_CFG_PULL_DOWN; | ||
251 | |||
252 | default: | ||
253 | return false; | ||
254 | } | ||
255 | } | ||
256 | |||
233 | static int sh_pfc_pinconf_get(struct pinctrl_dev *pctldev, unsigned _pin, | 257 | static int sh_pfc_pinconf_get(struct pinctrl_dev *pctldev, unsigned _pin, |
234 | unsigned long *config) | 258 | unsigned long *config) |
235 | { | 259 | { |
236 | struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); | 260 | struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); |
237 | struct sh_pfc *pfc = pmx->pfc; | 261 | struct sh_pfc *pfc = pmx->pfc; |
238 | int idx = sh_pfc_get_pin_index(pfc, _pin); | 262 | enum pin_config_param param = pinconf_to_config_param(*config); |
239 | struct sh_pfc_pin_config *cfg = &pmx->configs[idx]; | 263 | unsigned long flags; |
264 | unsigned int bias; | ||
265 | |||
266 | if (!sh_pfc_pinconf_validate(pfc, _pin, param)) | ||
267 | return -ENOTSUPP; | ||
240 | 268 | ||
241 | *config = cfg->type; | 269 | switch (param) { |
270 | case PIN_CONFIG_BIAS_DISABLE: | ||
271 | case PIN_CONFIG_BIAS_PULL_UP: | ||
272 | case PIN_CONFIG_BIAS_PULL_DOWN: | ||
273 | if (!pfc->info->ops || !pfc->info->ops->get_bias) | ||
274 | return -ENOTSUPP; | ||
275 | |||
276 | spin_lock_irqsave(&pfc->lock, flags); | ||
277 | bias = pfc->info->ops->get_bias(pfc, _pin); | ||
278 | spin_unlock_irqrestore(&pfc->lock, flags); | ||
279 | |||
280 | if (bias != param) | ||
281 | return -EINVAL; | ||
282 | |||
283 | *config = 0; | ||
284 | break; | ||
285 | |||
286 | default: | ||
287 | return -ENOTSUPP; | ||
288 | } | ||
242 | 289 | ||
243 | return 0; | 290 | return 0; |
244 | } | 291 | } |
245 | 292 | ||
246 | static int sh_pfc_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin, | 293 | static int sh_pfc_pinconf_set(struct pinctrl_dev *pctldev, unsigned _pin, |
247 | unsigned long config) | 294 | unsigned long config) |
248 | { | 295 | { |
249 | struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); | 296 | struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); |
297 | struct sh_pfc *pfc = pmx->pfc; | ||
298 | enum pin_config_param param = pinconf_to_config_param(config); | ||
299 | unsigned long flags; | ||
250 | 300 | ||
251 | /* Validate the new type */ | 301 | if (!sh_pfc_pinconf_validate(pfc, _pin, param)) |
252 | if (config >= PINMUX_FLAG_TYPE) | 302 | return -ENOTSUPP; |
253 | return -EINVAL; | ||
254 | 303 | ||
255 | return sh_pfc_reconfig_pin(pmx, pin, config); | 304 | switch (param) { |
305 | case PIN_CONFIG_BIAS_PULL_UP: | ||
306 | case PIN_CONFIG_BIAS_PULL_DOWN: | ||
307 | case PIN_CONFIG_BIAS_DISABLE: | ||
308 | if (!pfc->info->ops || !pfc->info->ops->set_bias) | ||
309 | return -ENOTSUPP; | ||
310 | |||
311 | spin_lock_irqsave(&pfc->lock, flags); | ||
312 | pfc->info->ops->set_bias(pfc, _pin, param); | ||
313 | spin_unlock_irqrestore(&pfc->lock, flags); | ||
314 | |||
315 | break; | ||
316 | |||
317 | default: | ||
318 | return -ENOTSUPP; | ||
319 | } | ||
320 | |||
321 | return 0; | ||
256 | } | 322 | } |
257 | 323 | ||
258 | static void sh_pfc_pinconf_dbg_show(struct pinctrl_dev *pctldev, | 324 | static int sh_pfc_pinconf_group_set(struct pinctrl_dev *pctldev, unsigned group, |
259 | struct seq_file *s, unsigned pin) | 325 | unsigned long config) |
260 | { | 326 | { |
261 | const char *pinmux_type_str[] = { | 327 | struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); |
262 | [PINMUX_TYPE_NONE] = "none", | 328 | const unsigned int *pins; |
263 | [PINMUX_TYPE_FUNCTION] = "function", | 329 | unsigned int num_pins; |
264 | [PINMUX_TYPE_GPIO] = "gpio", | 330 | unsigned int i; |
265 | [PINMUX_TYPE_OUTPUT] = "output", | 331 | |
266 | [PINMUX_TYPE_INPUT] = "input", | 332 | pins = pmx->pfc->info->groups[group].pins; |
267 | [PINMUX_TYPE_INPUT_PULLUP] = "input bias pull up", | 333 | num_pins = pmx->pfc->info->groups[group].nr_pins; |
268 | [PINMUX_TYPE_INPUT_PULLDOWN] = "input bias pull down", | 334 | |
269 | }; | 335 | for (i = 0; i < num_pins; ++i) |
270 | unsigned long config; | 336 | sh_pfc_pinconf_set(pctldev, pins[i], config); |
271 | int rc; | 337 | |
272 | 338 | return 0; | |
273 | rc = sh_pfc_pinconf_get(pctldev, pin, &config); | ||
274 | if (unlikely(rc != 0)) | ||
275 | return; | ||
276 | |||
277 | seq_printf(s, " %s", pinmux_type_str[config]); | ||
278 | } | 339 | } |
279 | 340 | ||
280 | static const struct pinconf_ops sh_pfc_pinconf_ops = { | 341 | static const struct pinconf_ops sh_pfc_pinconf_ops = { |
281 | .pin_config_get = sh_pfc_pinconf_get, | 342 | .is_generic = true, |
282 | .pin_config_set = sh_pfc_pinconf_set, | 343 | .pin_config_get = sh_pfc_pinconf_get, |
283 | .pin_config_dbg_show = sh_pfc_pinconf_dbg_show, | 344 | .pin_config_set = sh_pfc_pinconf_set, |
345 | .pin_config_group_set = sh_pfc_pinconf_group_set, | ||
346 | .pin_config_config_dbg_show = pinconf_generic_dump_config, | ||
284 | }; | 347 | }; |
285 | 348 | ||
286 | /* PFC ranges -> pinctrl pin descs */ | 349 | /* PFC ranges -> pinctrl pin descs */ |