diff options
author | Tomasz Figa <t.figa@samsung.com> | 2014-07-02 17:40:59 +0200 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2014-07-11 14:08:36 +0200 |
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 089abde35d4..5740f93d658 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, return 0; } -/* - * The calls to gpio_direction_output() and gpio_direction_input() - * leads to this function call (via the pinctrl_gpio_direction_{input|output}() - * function called from the gpiolib interface). - */ -static int samsung_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, - struct pinctrl_gpio_range *range, unsigned offset, bool input) -{ - struct samsung_pin_bank_type *type; - struct samsung_pin_bank *bank; - struct samsung_pinctrl_drv_data *drvdata; - void __iomem *reg; - u32 data, pin_offset, mask, shift; - unsigned long flags; - - bank = gc_to_pin_bank(range->gc); - type = bank->type; - drvdata = pinctrl_dev_get_drvdata(pctldev); - - pin_offset = offset - bank->pin_base; - reg = drvdata->virt_base + bank->pctl_offset + - type->reg_offset[PINCFG_TYPE_FUNC]; - - mask = (1 << type->fld_width[PINCFG_TYPE_FUNC]) - 1; - shift = pin_offset * type->fld_width[PINCFG_TYPE_FUNC]; - if (shift >= 32) { - /* Some banks have two config registers */ - shift -= 32; - reg += 4; - } - - spin_lock_irqsave(&bank->slock, flags); - - data = readl(reg); - data &= ~(mask << shift); - if (!input) - data |= FUNC_OUTPUT << shift; - writel(data, reg); - - spin_unlock_irqrestore(&bank->slock, flags); - - return 0; -} - /* list of pinmux callbacks for the pinmux vertical in pinctrl core */ static const struct pinmux_ops samsung_pinmux_ops = { .get_functions_count = samsung_get_functions_count, .get_function_name = samsung_pinmux_get_fname, .get_function_groups = samsung_pinmux_get_groups, .enable = samsung_pinmux_enable, - .gpio_set_direction = samsung_pinmux_gpio_set_direction, }; /* 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) } /* - * gpiolib gpio_direction_input callback function. The setting of the pin - * mux function as 'gpio input' will be handled by the pinctrl susbsystem - * interface. + * The calls to gpio_direction_output() and gpio_direction_input() + * leads to this function call. */ +static int samsung_gpio_set_direction(struct gpio_chip *gc, + unsigned offset, bool input) +{ + struct samsung_pin_bank_type *type; + struct samsung_pin_bank *bank; + struct samsung_pinctrl_drv_data *drvdata; + void __iomem *reg; + u32 data, mask, shift; + unsigned long flags; + + bank = gc_to_pin_bank(gc); + type = bank->type; + drvdata = bank->drvdata; + + reg = drvdata->virt_base + bank->pctl_offset + + type->reg_offset[PINCFG_TYPE_FUNC]; + + mask = (1 << type->fld_width[PINCFG_TYPE_FUNC]) - 1; + shift = offset * type->fld_width[PINCFG_TYPE_FUNC]; + if (shift >= 32) { + /* Some banks have two config registers */ + shift -= 32; + reg += 4; + } + + spin_lock_irqsave(&bank->slock, flags); + + data = readl(reg); + data &= ~(mask << shift); + if (!input) + data |= FUNC_OUTPUT << shift; + writel(data, reg); + + spin_unlock_irqrestore(&bank->slock, flags); + + return 0; +} + +/* gpiolib gpio_direction_input callback function. */ static int samsung_gpio_direction_input(struct gpio_chip *gc, unsigned offset) { - return pinctrl_gpio_direction_input(gc->base + offset); + return samsung_gpio_set_direction(gc, offset, true); } -/* - * gpiolib gpio_direction_output callback function. The setting of the pin - * mux function as 'gpio output' will be handled by the pinctrl susbsystem - * interface. - */ +/* gpiolib gpio_direction_output callback function. */ static int samsung_gpio_direction_output(struct gpio_chip *gc, unsigned offset, int value) { samsung_gpio_set(gc, offset, value); - return pinctrl_gpio_direction_output(gc->base + offset); + return samsung_gpio_set_direction(gc, offset, false); } /* |