diff options
author | Tomasz Figa <t.figa@samsung.com> | 2014-07-02 11:40:59 -0400 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2014-07-11 08:08:36 -0400 |
commit | 18c28caa17d7127e0391e100a919d9f6c156e974 (patch) | |
tree | 4d2eb472ace97dd088aef0624a5a42ba01aae11e /drivers/pinctrl | |
parent | 0e9386752758b74fd42fda7cbdd6ccb5cb31033c (diff) |
pinctrl: samsung: Decouple direction setting from pinctrl
This patch makes the pinctrl-samsung driver configure GPIO direction on
its own, without using the pinctrl_gpio_direction_*() "helpers". The
rationale behind this change is as follows:
- pinctrl-samsung does not need translation from GPIO namespace to
pinctrl namespace to handle GPIO operations - GPIO chip and offset
therein are enough to calculate necessary offsets and bit masks in
constant time,
- the pinctrl_gpio_direction_*() functions do not do anything useful
other than translating the pin into pinctrl namespace and calling the
.gpio_set_direction() from pinmux_ops of the controller,
- the undesirable side effect of using those helpers is losing the
ability to change GPIO direction in atomic context, because they
explicitly use a mutex for synchronization,
Results of this patch are:
- fixed warnings about scheduling while atomic in code that needs to
set GPIO direction in atomic context (e.g. interrupt handler),
- reduced overhead of bitbanging drivers that use gpio_direction_*(),
e.g. i2c-gpio.
Signed-off-by: Tomasz Figa <t.figa@samsung.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/pinctrl')
-rw-r--r-- | drivers/pinctrl/pinctrl-samsung.c | 99 |
1 files changed, 44 insertions, 55 deletions
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c index 089abde35d44..5740f93d658c 100644 --- a/drivers/pinctrl/pinctrl-samsung.c +++ b/drivers/pinctrl/pinctrl-samsung.c | |||
@@ -333,57 +333,12 @@ static int samsung_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector, | |||
333 | return 0; | 333 | return 0; |
334 | } | 334 | } |
335 | 335 | ||
336 | /* | ||
337 | * The calls to gpio_direction_output() and gpio_direction_input() | ||
338 | * leads to this function call (via the pinctrl_gpio_direction_{input|output}() | ||
339 | * function called from the gpiolib interface). | ||
340 | */ | ||
341 | static int samsung_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, | ||
342 | struct pinctrl_gpio_range *range, unsigned offset, bool input) | ||
343 | { | ||
344 | struct samsung_pin_bank_type *type; | ||
345 | struct samsung_pin_bank *bank; | ||
346 | struct samsung_pinctrl_drv_data *drvdata; | ||
347 | void __iomem *reg; | ||
348 | u32 data, pin_offset, mask, shift; | ||
349 | unsigned long flags; | ||
350 | |||
351 | bank = gc_to_pin_bank(range->gc); | ||
352 | type = bank->type; | ||
353 | drvdata = pinctrl_dev_get_drvdata(pctldev); | ||
354 | |||
355 | pin_offset = offset - bank->pin_base; | ||
356 | reg = drvdata->virt_base + bank->pctl_offset + | ||
357 | type->reg_offset[PINCFG_TYPE_FUNC]; | ||
358 | |||
359 | mask = (1 << type->fld_width[PINCFG_TYPE_FUNC]) - 1; | ||
360 | shift = pin_offset * type->fld_width[PINCFG_TYPE_FUNC]; | ||
361 | if (shift >= 32) { | ||
362 | /* Some banks have two config registers */ | ||
363 | shift -= 32; | ||
364 | reg += 4; | ||
365 | } | ||
366 | |||
367 | spin_lock_irqsave(&bank->slock, flags); | ||
368 | |||
369 | data = readl(reg); | ||
370 | data &= ~(mask << shift); | ||
371 | if (!input) | ||
372 | data |= FUNC_OUTPUT << shift; | ||
373 | writel(data, reg); | ||
374 | |||
375 | spin_unlock_irqrestore(&bank->slock, flags); | ||
376 | |||
377 | return 0; | ||
378 | } | ||
379 | |||
380 | /* list of pinmux callbacks for the pinmux vertical in pinctrl core */ | 336 | /* list of pinmux callbacks for the pinmux vertical in pinctrl core */ |
381 | static const struct pinmux_ops samsung_pinmux_ops = { | 337 | static const struct pinmux_ops samsung_pinmux_ops = { |
382 | .get_functions_count = samsung_get_functions_count, | 338 | .get_functions_count = samsung_get_functions_count, |
383 | .get_function_name = samsung_pinmux_get_fname, | 339 | .get_function_name = samsung_pinmux_get_fname, |
384 | .get_function_groups = samsung_pinmux_get_groups, | 340 | .get_function_groups = samsung_pinmux_get_groups, |
385 | .enable = samsung_pinmux_enable, | 341 | .enable = samsung_pinmux_enable, |
386 | .gpio_set_direction = samsung_pinmux_gpio_set_direction, | ||
387 | }; | 342 | }; |
388 | 343 | ||
389 | /* set or get the pin config settings for a specified pin */ | 344 | /* set or get the pin config settings for a specified pin */ |
@@ -532,25 +487,59 @@ static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset) | |||
532 | } | 487 | } |
533 | 488 | ||
534 | /* | 489 | /* |
535 | * gpiolib gpio_direction_input callback function. The setting of the pin | 490 | * The calls to gpio_direction_output() and gpio_direction_input() |
536 | * mux function as 'gpio input' will be handled by the pinctrl susbsystem | 491 | * leads to this function call. |
537 | * interface. | ||
538 | */ | 492 | */ |
493 | static int samsung_gpio_set_direction(struct gpio_chip *gc, | ||
494 | unsigned offset, bool input) | ||
495 | { | ||
496 | struct samsung_pin_bank_type *type; | ||
497 | struct samsung_pin_bank *bank; | ||
498 | struct samsung_pinctrl_drv_data *drvdata; | ||
499 | void __iomem *reg; | ||
500 | u32 data, mask, shift; | ||
501 | unsigned long flags; | ||
502 | |||
503 | bank = gc_to_pin_bank(gc); | ||
504 | type = bank->type; | ||
505 | drvdata = bank->drvdata; | ||
506 | |||
507 | reg = drvdata->virt_base + bank->pctl_offset + | ||
508 | type->reg_offset[PINCFG_TYPE_FUNC]; | ||
509 | |||
510 | mask = (1 << type->fld_width[PINCFG_TYPE_FUNC]) - 1; | ||
511 | shift = offset * type->fld_width[PINCFG_TYPE_FUNC]; | ||
512 | if (shift >= 32) { | ||
513 | /* Some banks have two config registers */ | ||
514 | shift -= 32; | ||
515 | reg += 4; | ||
516 | } | ||
517 | |||
518 | spin_lock_irqsave(&bank->slock, flags); | ||
519 | |||
520 | data = readl(reg); | ||
521 | data &= ~(mask << shift); | ||
522 | if (!input) | ||
523 | data |= FUNC_OUTPUT << shift; | ||
524 | writel(data, reg); | ||
525 | |||
526 | spin_unlock_irqrestore(&bank->slock, flags); | ||
527 | |||
528 | return 0; | ||
529 | } | ||
530 | |||
531 | /* gpiolib gpio_direction_input callback function. */ | ||
539 | static int samsung_gpio_direction_input(struct gpio_chip *gc, unsigned offset) | 532 | static int samsung_gpio_direction_input(struct gpio_chip *gc, unsigned offset) |
540 | { | 533 | { |
541 | return pinctrl_gpio_direction_input(gc->base + offset); | 534 | return samsung_gpio_set_direction(gc, offset, true); |
542 | } | 535 | } |
543 | 536 | ||
544 | /* | 537 | /* gpiolib gpio_direction_output callback function. */ |
545 | * gpiolib gpio_direction_output callback function. The setting of the pin | ||
546 | * mux function as 'gpio output' will be handled by the pinctrl susbsystem | ||
547 | * interface. | ||
548 | */ | ||
549 | static int samsung_gpio_direction_output(struct gpio_chip *gc, unsigned offset, | 538 | static int samsung_gpio_direction_output(struct gpio_chip *gc, unsigned offset, |
550 | int value) | 539 | int value) |
551 | { | 540 | { |
552 | samsung_gpio_set(gc, offset, value); | 541 | samsung_gpio_set(gc, offset, value); |
553 | return pinctrl_gpio_direction_output(gc->base + offset); | 542 | return samsung_gpio_set_direction(gc, offset, false); |
554 | } | 543 | } |
555 | 544 | ||
556 | /* | 545 | /* |