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>
This commit is contained in:
parent
0e93867527
commit
18c28caa17
|
@ -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_direction_input(struct gpio_chip *gc, unsigned offset)
|
||||
static int samsung_gpio_set_direction(struct gpio_chip *gc,
|
||||
unsigned offset, bool input)
|
||||
{
|
||||
return pinctrl_gpio_direction_input(gc->base + offset);
|
||||
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_output callback function. The setting of the pin
|
||||
* mux function as 'gpio output' will be handled by the pinctrl susbsystem
|
||||
* interface.
|
||||
*/
|
||||
/* gpiolib gpio_direction_input callback function. */
|
||||
static int samsung_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
|
||||
{
|
||||
return samsung_gpio_set_direction(gc, offset, true);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue