Commit 03b054e9 authored by Sherman Yin's avatar Sherman Yin Committed by Linus Walleij

pinctrl: Pass all configs to driver on pin_config_set()

When setting pin configuration in the pinctrl framework, pin_config_set() or
pin_config_group_set() is called in a loop to set one configuration at a time
for the specified pin or group.

This patch 1) removes the loop and 2) changes the API to pass the whole pin
config array to the driver.  It is now up to the driver to loop through the
configs.  This allows the driver to potentially combine configs and reduce the
number of writes to pin config registers.

All c files changed have been build-tested to verify the change compiles and
that the corresponding .o is successfully generated.
Signed-off-by: default avatarSherman Yin <syin@broadcom.com>
Reviewed-by: default avatarChristian Daudt <csd@broadcom.com>
Reviewed-by: default avatarMatt Porter <matt.porter@linaro.org>
Tested-by: default avatarStephen Warren <swarren@nvidia.com>
Acked-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent f5ba9c52
...@@ -191,18 +191,27 @@ static int mvebu_pinconf_group_get(struct pinctrl_dev *pctldev, ...@@ -191,18 +191,27 @@ static int mvebu_pinconf_group_get(struct pinctrl_dev *pctldev,
} }
static int mvebu_pinconf_group_set(struct pinctrl_dev *pctldev, static int mvebu_pinconf_group_set(struct pinctrl_dev *pctldev,
unsigned gid, unsigned long config) unsigned gid, unsigned long *configs,
unsigned num_configs)
{ {
struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
struct mvebu_pinctrl_group *grp = &pctl->groups[gid]; struct mvebu_pinctrl_group *grp = &pctl->groups[gid];
int i, ret;
if (!grp->ctrl) if (!grp->ctrl)
return -EINVAL; return -EINVAL;
if (grp->ctrl->mpp_set) for (i = 0; i < num_configs; i++) {
return grp->ctrl->mpp_set(grp->ctrl, config); if (grp->ctrl->mpp_set)
ret = grp->ctrl->mpp_set(grp->ctrl, configs[i]);
else
ret = mvebu_common_mpp_set(pctl, grp, configs[i]);
return mvebu_common_mpp_set(pctl, grp, config); if (ret)
return ret;
} /* for each config */
return 0;
} }
static void mvebu_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, static void mvebu_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
...@@ -303,6 +312,7 @@ static int mvebu_pinmux_enable(struct pinctrl_dev *pctldev, unsigned fid, ...@@ -303,6 +312,7 @@ static int mvebu_pinmux_enable(struct pinctrl_dev *pctldev, unsigned fid,
struct mvebu_pinctrl_group *grp = &pctl->groups[gid]; struct mvebu_pinctrl_group *grp = &pctl->groups[gid];
struct mvebu_mpp_ctrl_setting *setting; struct mvebu_mpp_ctrl_setting *setting;
int ret; int ret;
unsigned long config;
setting = mvebu_pinctrl_find_setting_by_name(pctl, grp, setting = mvebu_pinctrl_find_setting_by_name(pctl, grp,
func->name); func->name);
...@@ -313,7 +323,8 @@ static int mvebu_pinmux_enable(struct pinctrl_dev *pctldev, unsigned fid, ...@@ -313,7 +323,8 @@ static int mvebu_pinmux_enable(struct pinctrl_dev *pctldev, unsigned fid,
return -EINVAL; return -EINVAL;
} }
ret = mvebu_pinconf_group_set(pctldev, grp->gid, setting->val); config = setting->val;
ret = mvebu_pinconf_group_set(pctldev, grp->gid, &config, 1);
if (ret) { if (ret) {
dev_err(pctl->dev, "cannot set group %s to %s\n", dev_err(pctl->dev, "cannot set group %s to %s\n",
func->groups[gid], func->name); func->groups[gid], func->name);
...@@ -329,6 +340,7 @@ static int mvebu_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev, ...@@ -329,6 +340,7 @@ static int mvebu_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev,
struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); struct mvebu_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
struct mvebu_pinctrl_group *grp; struct mvebu_pinctrl_group *grp;
struct mvebu_mpp_ctrl_setting *setting; struct mvebu_mpp_ctrl_setting *setting;
unsigned long config;
grp = mvebu_pinctrl_find_group_by_pid(pctl, offset); grp = mvebu_pinctrl_find_group_by_pid(pctl, offset);
if (!grp) if (!grp)
...@@ -341,7 +353,9 @@ static int mvebu_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev, ...@@ -341,7 +353,9 @@ static int mvebu_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev,
if (!setting) if (!setting)
return -ENOTSUPP; return -ENOTSUPP;
return mvebu_pinconf_group_set(pctldev, grp->gid, setting->val); config = setting->val;
return mvebu_pinconf_group_set(pctldev, grp->gid, &config, 1);
} }
static int mvebu_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev, static int mvebu_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
......
...@@ -158,7 +158,7 @@ int pinconf_apply_setting(struct pinctrl_setting const *setting) ...@@ -158,7 +158,7 @@ int pinconf_apply_setting(struct pinctrl_setting const *setting)
{ {
struct pinctrl_dev *pctldev = setting->pctldev; struct pinctrl_dev *pctldev = setting->pctldev;
const struct pinconf_ops *ops = pctldev->desc->confops; const struct pinconf_ops *ops = pctldev->desc->confops;
int i, ret; int ret;
if (!ops) { if (!ops) {
dev_err(pctldev->dev, "missing confops\n"); dev_err(pctldev->dev, "missing confops\n");
...@@ -171,17 +171,15 @@ int pinconf_apply_setting(struct pinctrl_setting const *setting) ...@@ -171,17 +171,15 @@ int pinconf_apply_setting(struct pinctrl_setting const *setting)
dev_err(pctldev->dev, "missing pin_config_set op\n"); dev_err(pctldev->dev, "missing pin_config_set op\n");
return -EINVAL; return -EINVAL;
} }
for (i = 0; i < setting->data.configs.num_configs; i++) { ret = ops->pin_config_set(pctldev,
ret = ops->pin_config_set(pctldev, setting->data.configs.group_or_pin,
setting->data.configs.group_or_pin, setting->data.configs.configs,
setting->data.configs.configs[i]); setting->data.configs.num_configs);
if (ret < 0) { if (ret < 0) {
dev_err(pctldev->dev, dev_err(pctldev->dev,
"pin_config_set op failed for pin %d config %08lx\n", "pin_config_set op failed for pin %d\n",
setting->data.configs.group_or_pin, setting->data.configs.group_or_pin);
setting->data.configs.configs[i]); return ret;
return ret;
}
} }
break; break;
case PIN_MAP_TYPE_CONFIGS_GROUP: case PIN_MAP_TYPE_CONFIGS_GROUP:
...@@ -190,17 +188,15 @@ int pinconf_apply_setting(struct pinctrl_setting const *setting) ...@@ -190,17 +188,15 @@ int pinconf_apply_setting(struct pinctrl_setting const *setting)
"missing pin_config_group_set op\n"); "missing pin_config_group_set op\n");
return -EINVAL; return -EINVAL;
} }
for (i = 0; i < setting->data.configs.num_configs; i++) { ret = ops->pin_config_group_set(pctldev,
ret = ops->pin_config_group_set(pctldev, setting->data.configs.group_or_pin,
setting->data.configs.group_or_pin, setting->data.configs.configs,
setting->data.configs.configs[i]); setting->data.configs.num_configs);
if (ret < 0) { if (ret < 0) {
dev_err(pctldev->dev, dev_err(pctldev->dev,
"pin_config_group_set op failed for group %d config %08lx\n", "pin_config_group_set op failed for group %d\n",
setting->data.configs.group_or_pin, setting->data.configs.group_or_pin);
setting->data.configs.configs[i]); return ret;
return ret;
}
} }
break; break;
default: default:
......
...@@ -1041,98 +1041,115 @@ static int abx500_pin_config_get(struct pinctrl_dev *pctldev, ...@@ -1041,98 +1041,115 @@ static int abx500_pin_config_get(struct pinctrl_dev *pctldev,
static int abx500_pin_config_set(struct pinctrl_dev *pctldev, static int abx500_pin_config_set(struct pinctrl_dev *pctldev,
unsigned pin, unsigned pin,
unsigned long config) unsigned long *configs,
unsigned num_configs)
{ {
struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev); struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
struct gpio_chip *chip = &pct->chip; struct gpio_chip *chip = &pct->chip;
unsigned offset; unsigned offset;
int ret = -EINVAL; int ret = -EINVAL;
enum pin_config_param param = pinconf_to_config_param(config); int i;
enum pin_config_param argument = pinconf_to_config_argument(config); enum pin_config_param param;
enum pin_config_param argument;
dev_dbg(chip->dev, "pin %d [%#lx]: %s %s\n",
pin, config, (param == PIN_CONFIG_OUTPUT) ? "output " : "input", for (i = 0; i < num_configs; i++) {
(param == PIN_CONFIG_OUTPUT) ? (argument ? "high" : "low") : param = pinconf_to_config_param(configs[i]);
(argument ? "pull up" : "pull down")); argument = pinconf_to_config_argument(configs[i]);
/* on ABx500, there is no GPIO0, so adjust the offset */ dev_dbg(chip->dev, "pin %d [%#lx]: %s %s\n",
offset = pin - 1; pin, configs[i],
(param == PIN_CONFIG_OUTPUT) ? "output " : "input",
switch (param) { (param == PIN_CONFIG_OUTPUT) ?
case PIN_CONFIG_BIAS_DISABLE: (argument ? "high" : "low") :
ret = abx500_gpio_direction_input(chip, offset); (argument ? "pull up" : "pull down"));
if (ret < 0)
goto out; /* on ABx500, there is no GPIO0, so adjust the offset */
/* offset = pin - 1;
* Some chips only support pull down, while some actually
* support both pull up and pull down. Such chips have switch (param) {
* a "pullud" range specified for the pins that support case PIN_CONFIG_BIAS_DISABLE:
* both features. If the pin is not within that range, we ret = abx500_gpio_direction_input(chip, offset);
* fall back to the old bit set that only support pull down. if (ret < 0)
*/ goto out;
if (abx500_pullud_supported(chip, pin)) /*
ret = abx500_set_pull_updown(pct, * Some chips only support pull down, while some
pin, * actually support both pull up and pull down. Such
ABX500_GPIO_PULL_NONE); * chips have a "pullud" range specified for the pins
else * that support both features. If the pin is not
/* Chip only supports pull down */ * within that range, we fall back to the old bit set
ret = abx500_gpio_set_bits(chip, AB8500_GPIO_PUD1_REG, * that only support pull down.
offset, ABX500_GPIO_PULL_NONE); */
break; if (abx500_pullud_supported(chip, pin))
ret = abx500_set_pull_updown(pct,
case PIN_CONFIG_BIAS_PULL_DOWN: pin,
ret = abx500_gpio_direction_input(chip, offset); ABX500_GPIO_PULL_NONE);
if (ret < 0) else
goto out; /* Chip only supports pull down */
/* ret = abx500_gpio_set_bits(chip,
* if argument = 1 set the pull down AB8500_GPIO_PUD1_REG, offset,
* else clear the pull down ABX500_GPIO_PULL_NONE);
* Some chips only support pull down, while some actually break;
* support both pull up and pull down. Such chips have
* a "pullud" range specified for the pins that support
* both features. If the pin is not within that range, we
* fall back to the old bit set that only support pull down.
*/
if (abx500_pullud_supported(chip, pin))
ret = abx500_set_pull_updown(pct,
pin,
argument ? ABX500_GPIO_PULL_DOWN : ABX500_GPIO_PULL_NONE);
else
/* Chip only supports pull down */
ret = abx500_gpio_set_bits(chip, AB8500_GPIO_PUD1_REG,
offset,
argument ? ABX500_GPIO_PULL_DOWN : ABX500_GPIO_PULL_NONE);
break;
case PIN_CONFIG_BIAS_PULL_UP:
ret = abx500_gpio_direction_input(chip, offset);
if (ret < 0)
goto out;
/*
* if argument = 1 set the pull up
* else clear the pull up
*/
ret = abx500_gpio_direction_input(chip, offset);
/*
* Some chips only support pull down, while some actually
* support both pull up and pull down. Such chips have
* a "pullud" range specified for the pins that support
* both features. If the pin is not within that range, do
* nothing
*/
if (abx500_pullud_supported(chip, pin))
ret = abx500_set_pull_updown(pct,
pin,
argument ? ABX500_GPIO_PULL_UP : ABX500_GPIO_PULL_NONE);
break;
case PIN_CONFIG_OUTPUT: case PIN_CONFIG_BIAS_PULL_DOWN:
ret = abx500_gpio_direction_output(chip, offset, argument); ret = abx500_gpio_direction_input(chip, offset);
break; if (ret < 0)
goto out;
/*
* if argument = 1 set the pull down
* else clear the pull down
* Some chips only support pull down, while some
* actually support both pull up and pull down. Such
* chips have a "pullud" range specified for the pins
* that support both features. If the pin is not
* within that range, we fall back to the old bit set
* that only support pull down.
*/
if (abx500_pullud_supported(chip, pin))
ret = abx500_set_pull_updown(pct,
pin,
argument ? ABX500_GPIO_PULL_DOWN :
ABX500_GPIO_PULL_NONE);
else
/* Chip only supports pull down */
ret = abx500_gpio_set_bits(chip,
AB8500_GPIO_PUD1_REG,
offset,
argument ? ABX500_GPIO_PULL_DOWN :
ABX500_GPIO_PULL_NONE);
break;
default: case PIN_CONFIG_BIAS_PULL_UP:
dev_err(chip->dev, "illegal configuration requested\n"); ret = abx500_gpio_direction_input(chip, offset);
} if (ret < 0)
goto out;
/*
* if argument = 1 set the pull up
* else clear the pull up
*/
ret = abx500_gpio_direction_input(chip, offset);
/*
* Some chips only support pull down, while some
* actually support both pull up and pull down. Such
* chips have a "pullud" range specified for the pins
* that support both features. If the pin is not
* within that range, do nothing
*/
if (abx500_pullud_supported(chip, pin))
ret = abx500_set_pull_updown(pct,
pin,
argument ? ABX500_GPIO_PULL_UP :
ABX500_GPIO_PULL_NONE);
break;
case PIN_CONFIG_OUTPUT:
ret = abx500_gpio_direction_output(chip, offset,
argument);
break;
default:
dev_err(chip->dev, "illegal configuration requested\n");
}
} /* for each config */
out: out:
if (ret < 0) if (ret < 0)
dev_err(pct->dev, "%s failed (%d)\n", __func__, ret); dev_err(pct->dev, "%s failed (%d)\n", __func__, ret);
......
...@@ -736,30 +736,40 @@ static int at91_pinconf_get(struct pinctrl_dev *pctldev, ...@@ -736,30 +736,40 @@ static int at91_pinconf_get(struct pinctrl_dev *pctldev,
} }
static int at91_pinconf_set(struct pinctrl_dev *pctldev, static int at91_pinconf_set(struct pinctrl_dev *pctldev,
unsigned pin_id, unsigned long config) unsigned pin_id, unsigned long *configs,
unsigned num_configs)
{ {
struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
unsigned mask; unsigned mask;
void __iomem *pio; void __iomem *pio;
int i;
dev_dbg(info->dev, "%s:%d, pin_id=%d, config=0x%lx", __func__, __LINE__, pin_id, config); unsigned long config;
pio = pin_to_controller(info, pin_to_bank(pin_id));
mask = pin_to_mask(pin_id % MAX_NB_GPIO_PER_BANK); for (i = 0; i < num_configs; i++) {
config = configs[i];
if (config & PULL_UP && config & PULL_DOWN)
return -EINVAL; dev_dbg(info->dev,
"%s:%d, pin_id=%d, config=0x%lx",
at91_mux_set_pullup(pio, mask, config & PULL_UP); __func__, __LINE__, pin_id, config);
at91_mux_set_multidrive(pio, mask, config & MULTI_DRIVE); pio = pin_to_controller(info, pin_to_bank(pin_id));
if (info->ops->set_deglitch) mask = pin_to_mask(pin_id % MAX_NB_GPIO_PER_BANK);
info->ops->set_deglitch(pio, mask, config & DEGLITCH);
if (info->ops->set_debounce) if (config & PULL_UP && config & PULL_DOWN)
info->ops->set_debounce(pio, mask, config & DEBOUNCE, return -EINVAL;
at91_mux_set_pullup(pio, mask, config & PULL_UP);
at91_mux_set_multidrive(pio, mask, config & MULTI_DRIVE);
if (info->ops->set_deglitch)
info->ops->set_deglitch(pio, mask, config & DEGLITCH);
if (info->ops->set_debounce)
info->ops->set_debounce(pio, mask, config & DEBOUNCE,
(config & DEBOUNCE_VAL) >> DEBOUNCE_VAL_SHIFT); (config & DEBOUNCE_VAL) >> DEBOUNCE_VAL_SHIFT);
if (info->ops->set_pulldown) if (info->ops->set_pulldown)
info->ops->set_pulldown(pio, mask, config & PULL_DOWN); info->ops->set_pulldown(pio, mask, config & PULL_DOWN);
if (info->ops->disable_schmitt_trig && config & DIS_SCHMIT) if (info->ops->disable_schmitt_trig && config & DIS_SCHMIT)
info->ops->disable_schmitt_trig(pio, mask); info->ops->disable_schmitt_trig(pio, mask);
} /* for each config */
return 0; return 0;
} }
......
...@@ -893,28 +893,35 @@ static int bcm2835_pinconf_get(struct pinctrl_dev *pctldev, ...@@ -893,28 +893,35 @@ static int bcm2835_pinconf_get(struct pinctrl_dev *pctldev,
} }
static int bcm2835_pinconf_set(struct pinctrl_dev *pctldev, static int bcm2835_pinconf_set(struct pinctrl_dev *pctldev,
unsigned pin, unsigned long config) unsigned pin, unsigned long *configs,
unsigned num_configs)
{ {
struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev); struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
enum bcm2835_pinconf_param param = BCM2835_PINCONF_UNPACK_PARAM(config); enum bcm2835_pinconf_param param;
u16 arg = BCM2835_PINCONF_UNPACK_ARG(config); u16 arg;
u32 off, bit; u32 off, bit;
int i;
if (param != BCM2835_PINCONF_PARAM_PULL) for (i = 0; i < num_configs; i++) {
return -EINVAL; param = BCM2835_PINCONF_UNPACK_PARAM(configs[i]);
arg = BCM2835_PINCONF_UNPACK_ARG(configs[i]);
off = GPIO_REG_OFFSET(pin);
bit = GPIO_REG_SHIFT(pin); if (param != BCM2835_PINCONF_PARAM_PULL)
return -EINVAL;
bcm2835_gpio_wr(pc, GPPUD, arg & 3);
/* off = GPIO_REG_OFFSET(pin);
* Docs say to wait 150 cycles, but not of what. We assume a bit = GPIO_REG_SHIFT(pin);
* 1 MHz clock here, which is pretty slow...
*/ bcm2835_gpio_wr(pc, GPPUD, arg & 3);
udelay(150); /*
bcm2835_gpio_wr(pc, GPPUDCLK0 + (off * 4), BIT(bit)); * Docs say to wait 150 cycles, but not of what. We assume a
udelay(150); * 1 MHz clock here, which is pretty slow...
bcm2835_gpio_wr(pc, GPPUDCLK0 + (off * 4), 0); */
udelay(150);
bcm2835_gpio_wr(pc, GPPUDCLK0 + (off * 4), BIT(bit));
udelay(150);
bcm2835_gpio_wr(pc, GPPUDCLK0 + (off * 4), 0);
} /* for each config */
return 0; return 0;
} }
......
...@@ -401,64 +401,71 @@ static const struct pinmux_ops exynos5440_pinmux_ops = { ...@@ -401,64 +401,71 @@ static const struct pinmux_ops exynos5440_pinmux_ops = {
/* set the pin config settings for a specified pin */ /* set the pin config settings for a specified pin */
static int exynos5440_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, static int exynos5440_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
unsigned long config) unsigned long *configs,
unsigned num_configs)
{ {
struct exynos5440_pinctrl_priv_data *priv; struct exynos5440_pinctrl_priv_data *priv;
void __iomem *base; void __iomem *base;
enum pincfg_type cfg_type = PINCFG_UNPACK_TYPE(config); enum pincfg_type cfg_type;
u32 cfg_value = PINCFG_UNPACK_VALUE(config); u32 cfg_value;
u32 data; u32 data;
int i;
priv = pinctrl_dev_get_drvdata(pctldev); priv = pinctrl_dev_get_drvdata(pctldev);
base = priv->reg_base; base = priv->reg_base;
switch (cfg_type) { for (i = 0; i < num_configs; i++) {
case PINCFG_TYPE_PUD: cfg_type = PINCFG_UNPACK_TYPE(configs[i]);
/* first set pull enable/disable bit */ cfg_value = PINCFG_UNPACK_VALUE(configs[i]);
data = readl(base + GPIO_PE);
data &= ~(1 << pin); switch (cfg_type) {
if (cfg_value) case PINCFG_TYPE_PUD:
data |= (1 << pin); /* first set pull enable/disable bit */
writel(data, base + GPIO_PE); data = readl(base + GPIO_PE);
data &= ~(1 << pin);
/* then set pull up/down bit */ if (cfg_value)
data = readl(base + GPIO_PS); data |= (1 << pin);
data &= ~(1 << pin); writel(data, base + GPIO_PE);
if (cfg_value == 2)
data |= (1 << pin); /* then set pull up/down bit */
writel(data, base + GPIO_PS); data = readl(base + GPIO_PS);
break; data &= ~(1 << pin);
if (cfg_value == 2)
case PINCFG_TYPE_DRV: data |= (1 << pin);
/* set the first bit of the drive strength */ writel(data, base + GPIO_PS);
data = readl(base + GPIO_DS0); break;
data &= ~(1 << pin);
data |= ((cfg_value & 1) << pin); case PINCFG_TYPE_DRV:
writel(data, base + GPIO_DS0); /* set the first bit of the drive strength */
cfg_value >>= 1; data = readl(base + GPIO_DS0);
data &= ~(1 << pin);
/* set the second bit of the driver strength */ data |= ((cfg_value & 1) << pin);
data = readl(base + GPIO_DS1); writel(data, base + GPIO_DS0);
data &= ~(1 << pin); cfg_value >>= 1;
data |= ((cfg_value & 1) << pin);
writel(data, base + GPIO_DS1); /* set the second bit of the driver strength */
break; data = readl(base + GPIO_DS1);
case PINCFG_TYPE_SKEW_RATE: data &= ~(1 << pin);
data = readl(base + GPIO_SR); data |= ((cfg_value & 1) << pin);
data &= ~(1 << pin); writel(data, base + GPIO_DS1);
data |= ((cfg_value & 1) << pin); break;
writel(data, base + GPIO_SR); case PINCFG_TYPE_SKEW_RATE:
break; data = readl(base + GPIO_SR);
case PINCFG_TYPE_INPUT_TYPE: data &= ~(1 << pin);
data = readl(base + GPIO_TYPE); data |= ((cfg_value & 1) << pin);
data &= ~(1 << pin); writel(data, base + GPIO_SR);
data |= ((cfg_value & 1) << pin); break;
writel(data, base + GPIO_TYPE); case PINCFG_TYPE_INPUT_TYPE:
break; data = readl(base + GPIO_TYPE);
default: data &= ~(1 << pin);
WARN_ON(1); data |= ((cfg_value & 1) << pin);
return -EINVAL; writel(data, base + GPIO_TYPE);
} break;
default:
WARN_ON(1);
return -EINVAL;
}
} /* for each config */
return 0; return 0;
} }
...@@ -510,7 +517,8 @@ static int exynos5440_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, ...@@ -510,7 +517,8 @@ static int exynos5440_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin,
/* set the pin config settings for a specified pin group */ /* set the pin config settings for a specified pin group */
static int exynos5440_pinconf_group_set(struct pinctrl_dev *pctldev, static int exynos5440_pinconf_group_set(struct pinctrl_dev *pctldev,
unsigned group, unsigned long config) unsigned group, unsigned long *configs,
unsigned num_configs)
{ {
struct exynos5440_pinctrl_priv_data *priv; struct exynos5440_pinctrl_priv_data *priv;
const unsigned int *pins; const unsigned int *pins;
...@@ -520,7 +528,8 @@ static int exynos5440_pinconf_group_set(struct pinctrl_dev *pctldev, ...@@ -520,7 +528,8 @@ static int exynos5440_pinconf_group_set(struct pinctrl_dev *pctldev,
pins = priv->pin_groups[group].pins; pins = priv->pin_groups[group].pins;
for (cnt = 0; cnt < priv->pin_groups[group].num_pins; cnt++) for (cnt = 0; cnt < priv->pin_groups[group].num_pins; cnt++)
exynos5440_pinconf_set(pctldev, pins[cnt], config); exynos5440_pinconf_set(pctldev, pins[cnt], configs,
num_configs);
return 0; return 0;
} }
......
...@@ -238,7 +238,8 @@ static int falcon_pinconf_group_get(struct pinctrl_dev *pctrldev, ...@@ -238,7 +238,8 @@ static int falcon_pinconf_group_get(struct pinctrl_dev *pctrldev,
} }
static int falcon_pinconf_group_set(struct pinctrl_dev *pctrldev, static int falcon_pinconf_group_set(struct pinctrl_dev *pctrldev,
unsigned group, unsigned long config) unsigned group, unsigned long *configs,
unsigned num_configs)
{ {
return -ENOTSUPP; return -ENOTSUPP;
} }
...@@ -279,39 +280,47 @@ static int falcon_pinconf_get(struct pinctrl_dev *pctrldev, ...@@ -279,39 +280,47 @@ static int falcon_pinconf_get(struct pinctrl_dev *pctrldev,
} }
static int falcon_pinconf_set(struct pinctrl_dev *pctrldev, static int falcon_pinconf_set(struct pinctrl_dev *pctrldev,
unsigned pin, unsigned long config) unsigned pin, unsigned long *configs,
unsigned num_configs)
{ {
enum ltq_pinconf_param param = LTQ_PINCONF_UNPACK_PARAM(config); enum ltq_pinconf_param param;
int arg = LTQ_PINCONF_UNPACK_ARG(config); int arg;
struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
void __iomem *mem = info->membase[PORT(pin)]; void __iomem *mem = info->membase[PORT(pin)];
u32 reg; u32 reg;
int i;
switch (param) { for (i = 0; i < num_configs; i++) {
case LTQ_PINCONF_PARAM_DRIVE_CURRENT: param = LTQ_PINCONF_UNPACK_PARAM(configs[i]);
reg = LTQ_PADC_DCC; arg = LTQ_PINCONF_UNPACK_ARG(configs[i]);
break;
switch (param) {
case LTQ_PINCONF_PARAM_SLEW_RATE: case LTQ_PINCONF_PARAM_DRIVE_CURRENT:
reg = LTQ_PADC_SRC; reg = LTQ_PADC_DCC;
break; break;
case LTQ_PINCONF_PARAM_PULL: case LTQ_PINCONF_PARAM_SLEW_RATE:
if (arg == 1) reg = LTQ_PADC_SRC;
reg = LTQ_PADC_PDEN; break;
else
reg = LTQ_PADC_PUEN; case LTQ_PINCONF_PARAM_PULL:
break; if (arg == 1)
reg = LTQ_PADC_PDEN;
else
reg = LTQ_PADC_PUEN;
break;
default:
pr_err("%s: Invalid config param %04x\n",
pinctrl_dev_get_name(pctrldev), param);
return -ENOTSUPP;
}
default: pad_w32(mem, BIT(PORT_PIN(pin)), reg);
pr_err("%s: Invalid config param %04x\n", if (!(pad_r32(mem, reg) & BIT(PORT_PIN(pin))))
pinctrl_dev_get_name(pctrldev), param); return -ENOTSUPP;
return -ENOTSUPP; } /* for each config */
}
pad_w32(mem, BIT(PORT_PIN(pin)), reg);
if (!(pad_r32(mem, reg) & BIT(PORT_PIN(pin))))
return -ENOTSUPP;
return 0; return 0;
} }
......
...@@ -323,11 +323,13 @@ static int imx_pinconf_get(struct pinctrl_dev *pctldev, ...@@ -323,11 +323,13 @@ static int imx_pinconf_get(struct pinctrl_dev *pctldev,
} }
static int imx_pinconf_set(struct pinctrl_dev *pctldev, static int imx_pinconf_set(struct pinctrl_dev *pctldev,
unsigned pin_id, unsigned long config) unsigned pin_id, unsigned long *configs,
unsigned num_configs)
{ {
struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
const struct imx_pinctrl_soc_info *info = ipctl->info; const struct imx_pinctrl_soc_info *info = ipctl->info;
const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id]; const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
int i;
if (!(info->flags & ZERO_OFFSET_VALID) && !pin_reg->conf_reg) { if (!(info->flags & ZERO_OFFSET_VALID) && !pin_reg->conf_reg) {
dev_err(info->dev, "Pin(%s) does not support config function\n", dev_err(info->dev, "Pin(%s) does not support config function\n",
...@@ -338,17 +340,19 @@ static int imx_pinconf_set(struct pinctrl_dev *pctldev, ...@@ -338,17 +340,19 @@ static int imx_pinconf_set(struct pinctrl_dev *pctldev,
dev_dbg(ipctl->dev, "pinconf set pin %s\n", dev_dbg(ipctl->dev, "pinconf set pin %s\n",
info->pins[pin_id].name); info->pins[pin_id].name);
if (info->flags & SHARE_MUX_CONF_REG) { for (i = 0; i < num_configs; i++) {
u32 reg; if (info->flags & SHARE_MUX_CONF_REG) {
reg = readl(ipctl->base + pin_reg->conf_reg); u32 reg;
reg &= ~0xffff; reg = readl(ipctl->base + pin_reg->conf_reg);
reg |= config; reg &= ~0xffff;
writel(reg, ipctl->base + pin_reg->conf_reg); reg |= configs[i];
} else { writel(reg, ipctl->base + pin_reg->conf_reg);
writel(config, ipctl->base + pin_reg->conf_reg); } else {
} writel(configs[i], ipctl->base + pin_reg->conf_reg);
dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%lx\n", }
pin_reg->conf_reg, config); dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%lx\n",
pin_reg->conf_reg, configs[i]);
} /* for each config */
return 0; return 0;
} }
......
...@@ -233,7 +233,8 @@ static int mxs_pinconf_get(struct pinctrl_dev *pctldev, ...@@ -233,7 +233,8 @@ static int mxs_pinconf_get(struct pinctrl_dev *pctldev,
} }
static int mxs_pinconf_set(struct pinctrl_dev *pctldev, static int mxs_pinconf_set(struct pinctrl_dev *pctldev,
unsigned pin, unsigned long config) unsigned pin, unsigned long *configs,
unsigned num_configs)
{ {
return -ENOTSUPP; return -ENOTSUPP;
} }
...@@ -249,7 +250,8 @@ static int mxs_pinconf_group_get(struct pinctrl_dev *pctldev, ...@@ -249,7 +250,8 @@ static int mxs_pinconf_group_get(struct pinctrl_dev *pctldev,
} }
static int mxs_pinconf_group_set(struct pinctrl_dev *pctldev, static int mxs_pinconf_group_set(struct pinctrl_dev *pctldev,
unsigned group, unsigned long config) unsigned group, unsigned long *configs,
unsigned num_configs)
{ {
struct mxs_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev); struct mxs_pinctrl_data *d = pinctrl_dev_get_drvdata(pctldev);
struct mxs_group *g = &d->soc->groups[group]; struct mxs_group *g = &d->soc->groups[group];
...@@ -257,49 +259,56 @@ static int mxs_pinconf_group_set(struct pinctrl_dev *pctldev, ...@@ -257,49 +259,56 @@ static int mxs_pinconf_group_set(struct pinctrl_dev *pctldev,
u8 ma, vol, pull, bank, shift; u8 ma, vol, pull, bank, shift;
u16 pin; u16 pin;
u32 i; u32 i;
int n;
unsigned long config;
ma = CONFIG_TO_MA(config); for (n = 0; n < num_configs; n++) {
vol = CONFIG_TO_VOL(config); config = configs[n];
pull = CONFIG_TO_PULL(config);
ma = CONFIG_TO_MA(config);
for (i = 0; i < g->npins; i++) { vol = CONFIG_TO_VOL(config);
bank = PINID_TO_BANK(g->pins[i]); pull = CONFIG_TO_PULL(config);
pin = PINID_TO_PIN(g->pins[i]);
for (i = 0; i < g->npins; i++) {
/* drive */ bank = PINID_TO_BANK(g->pins[i]);
reg = d->base + d->soc->regs->drive; pin = PINID_TO_PIN(g->pins[i]);
reg += bank * 0x40 + pin / 8 * 0x10;
/* drive */
/* mA */ reg = d->base + d->soc->regs->drive;
if (config & MA_PRESENT) { reg += bank * 0x40 + pin / 8 * 0x10;
shift = pin % 8 * 4;
writel(0x3 << shift, reg + CLR); /* mA */
writel(ma << shift, reg + SET); if (config & MA_PRESENT) {
} shift = pin % 8 * 4;
writel(0x3 << shift, reg + CLR);
/* vol */ writel(ma << shift, reg + SET);
if (config & VOL_PRESENT) { }
shift = pin % 8 * 4 + 2;
if (vol) /* vol */
writel(1 << shift, reg + SET); if (config & VOL_PRESENT) {
else shift = pin % 8 * 4 + 2;
writel(1 << shift, reg + CLR); if (vol)
writel(1 << shift, reg + SET);
else
writel(1 << shift, reg + CLR);
}
/* pull */
if (config & PULL_PRESENT) {
reg = d->base + d->soc->regs->pull;
reg += bank * 0x10;
shift = pin;
if (pull)
writel(1 << shift, reg + SET);
else
writel(1 << shift, reg + CLR);
}
} }
/* pull */ /* cache the config value for mxs_pinconf_group_get() */
if (config & PULL_PRESENT) { g->config = config;
reg = d->base + d->soc->regs->pull;
reg += bank * 0x10;
shift = pin;
if (pull)
writel(1 << shift, reg + SET);
else
writel(1 << shift, reg + CLR);
}
}
/* cache the config value for mxs_pinconf_group_get() */ } /* for each config */
g->config = config;
return 0; return 0;
} }
......
...@@ -1695,7 +1695,7 @@ static int nmk_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin, ...@@ -1695,7 +1695,7 @@ static int nmk_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin,
} }
static int nmk_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin, static int nmk_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
unsigned long config) unsigned long *configs, unsigned num_configs)
{ {
static const char *pullnames[] = { static const char *pullnames[] = {
[NMK_GPIO_PULL_NONE] = "none", [NMK_GPIO_PULL_NONE] = "none",
...@@ -1712,20 +1712,9 @@ static int nmk_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin, ...@@ -1712,20 +1712,9 @@ static int nmk_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
struct pinctrl_gpio_range *range; struct pinctrl_gpio_range *range;
struct gpio_chip *chip; struct gpio_chip *chip;
unsigned bit; unsigned bit;
pin_cfg_t cfg;
/* int pull, slpm, output, val, i;
* The pin config contains pin number and altfunction fields, here bool lowemi, gpiomode, sleep;
* we just ignore that part. It's being handled by the framework and
* pinmux callback respectively.
*/
pin_cfg_t cfg = (pin_cfg_t) config;
int pull = PIN_PULL(cfg);
int slpm = PIN_SLPM(cfg);
int output = PIN_DIR(cfg);
int val = PIN_VAL(cfg);
bool lowemi = PIN_LOWEMI(cfg);
bool gpiomode = PIN_GPIOMODE(cfg);
bool sleep = PIN_SLEEPMODE(cfg);
range = nmk_match_gpio_range(pctldev, pin); range = nmk_match_gpio_range(pctldev, pin);
if (!range) { if (!range) {
...@@ -1740,54 +1729,74 @@ static int nmk_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin, ...@@ -1740,54 +1729,74 @@ static int nmk_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
chip = range->gc; chip = range->gc;
nmk_chip = container_of(chip, struct nmk_gpio_chip, chip); nmk_chip = container_of(chip, struct nmk_gpio_chip, chip);
if (sleep) { for (i = 0; i < num_configs; i++) {
int slpm_pull = PIN_SLPM_PULL(cfg);
int slpm_output = PIN_SLPM_DIR(cfg);
int slpm_val = PIN_SLPM_VAL(cfg);
/* All pins go into GPIO mode at sleep */
gpiomode = true;
/* /*
* The SLPM_* values are normal values + 1 to allow zero to * The pin config contains pin number and altfunction fields,
* mean "same as normal". * here we just ignore that part. It's being handled by the
* framework and pinmux callback respectively.
*/ */
if (slpm_pull) cfg = (pin_cfg_t) configs[i];
pull = slpm_pull - 1; pull = PIN_PULL(cfg);
if (slpm_output) slpm = PIN_SLPM(cfg);
output = slpm_output - 1; output = PIN_DIR(cfg);
if (slpm_val) val = PIN_VAL(cfg);
val = slpm_val - 1; lowemi = PIN_LOWEMI(cfg);
gpiomode = PIN_GPIOMODE(cfg);
dev_dbg(nmk_chip->chip.dev, "pin %d: sleep pull %s, dir %s, val %s\n", sleep = PIN_SLEEPMODE(cfg);
pin,
slpm_pull ? pullnames[pull] : "same", if (sleep) {
slpm_output ? (output ? "output" : "input") : "same", int slpm_pull = PIN_SLPM_PULL(cfg);
slpm_val ? (val ? "high" : "low") : "same"); int slpm_output = PIN_SLPM_DIR(cfg);
} int slpm_val = PIN_SLPM_VAL(cfg);
/* All pins go into GPIO mode at sleep */
gpiomode = true;
/*
* The SLPM_* values are normal values + 1 to allow zero
* to mean "same as normal".
*/
if (slpm_pull)
pull = slpm_pull - 1;
if (slpm_output)
output = slpm_output - 1;
if (slpm_val)
val = slpm_val - 1;
dev_dbg(nmk_chip->chip.dev,
"pin %d: sleep pull %s, dir %s, val %s\n",
pin,
slpm_pull ? pullnames[pull] : "same",
slpm_output ? (output ? "output" : "input")
: "same",
slpm_val ? (val ? "high" : "low") : "same");
}
dev_dbg(nmk_chip->chip.dev, "pin %d [%#lx]: pull %s, slpm %s (%s%s), lowemi %s\n", dev_dbg(nmk_chip->chip.dev,
pin, cfg, pullnames[pull], slpmnames[slpm], "pin %d [%#lx]: pull %s, slpm %s (%s%s), lowemi %s\n",
output ? "output " : "input", pin, cfg, pullnames[pull], slpmnames[slpm],
output ? (val ? "high" : "low") : "", output ? "output " : "input",
lowemi ? "on" : "off"); output ? (val ? "high" : "low") : "",
lowemi ? "on" : "off");
clk_enable(nmk_chip->clk); clk_enable(nmk_chip->clk);
bit = pin % NMK_GPIO_PER_CHIP; bit = pin % NMK_GPIO_PER_CHIP;
if (gpiomode) if (gpiomode)
/* No glitch when going to GPIO mode */ /* No glitch when going to GPIO mode */
__nmk_gpio_set_mode(nmk_chip, bit, NMK_GPIO_ALT_GPIO); __nmk_gpio_set_mode(nmk_chip, bit, NMK_GPIO_ALT_GPIO);
if (output) if (output)
__nmk_gpio_make_output(nmk_chip, bit, val); __nmk_gpio_make_output(nmk_chip, bit, val);
else { else {
__nmk_gpio_make_input(nmk_chip, bit); __nmk_gpio_make_input(nmk_chip, bit);
__nmk_gpio_set_pull(nmk_chip, bit, pull); __nmk_gpio_set_pull(nmk_chip, bit, pull);
} }
/* TODO: isn't this only applicable on output pins? */ /* TODO: isn't this only applicable on output pins? */
__nmk_gpio_set_lowemi(nmk_chip, bit, lowemi); __nmk_gpio_set_lowemi(nmk_chip, bit, lowemi);
__nmk_gpio_set_slpm(nmk_chip, bit, slpm);
clk_disable(nmk_chip->clk);
} /* for each config */
__nmk_gpio_set_slpm(nmk_chip, bit, slpm);
clk_disable(nmk_chip->clk);
return 0; return 0;
} }
......
...@@ -854,17 +854,19 @@ static int palmas_pinconf_get(struct pinctrl_dev *pctldev, ...@@ -854,17 +854,19 @@ static int palmas_pinconf_get(struct pinctrl_dev *pctldev,
} }
static int palmas_pinconf_set(struct pinctrl_dev *pctldev, static int palmas_pinconf_set(struct pinctrl_dev *pctldev,
unsigned pin, unsigned long config) unsigned pin, unsigned long *configs,
unsigned num_configs)
{ {
struct palmas_pctrl_chip_info *pci = pinctrl_dev_get_drvdata(pctldev); struct palmas_pctrl_chip_info *pci = pinctrl_dev_get_drvdata(pctldev);
enum pin_config_param param = pinconf_to_config_param(config); enum pin_config_param param;
u16 param_val = pinconf_to_config_argument(config); u16 param_val;
const struct palmas_pingroup *g; const struct palmas_pingroup *g;
const struct palmas_pin_info *opt; const struct palmas_pin_info *opt;
int ret; int ret;
int base, add, mask; int base, add, mask;
int rval; int rval;
int group_nr; int group_nr;
int i;
for (group_nr = 0; group_nr < pci->num_pin_groups; ++group_nr) { for (group_nr = 0; group_nr < pci->num_pin_groups; ++group_nr) {
if (pci->pin_groups[group_nr].pins[0] == pin) if (pci->pin_groups[group_nr].pins[0] == pin)
...@@ -885,70 +887,77 @@ static int palmas_pinconf_set(struct pinctrl_dev *pctldev, ...@@ -885,70 +887,77 @@ static int palmas_pinconf_set(struct pinctrl_dev *pctldev,
return -ENOTSUPP; return -ENOTSUPP;
} }
switch (param) { for (i = 0; i < num_configs; i++) {
case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: param = pinconf_to_config_param(configs[i]);
return 0; param_val = pinconf_to_config_argument(configs[i]);
case PIN_CONFIG_BIAS_DISABLE:
case PIN_CONFIG_BIAS_PULL_UP: switch (param) {
case PIN_CONFIG_BIAS_PULL_DOWN: case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
if (!opt->pud_info) { return 0;
dev_err(pci->dev, case PIN_CONFIG_BIAS_DISABLE:
"PULL control not supported for pin %s\n", case PIN_CONFIG_BIAS_PULL_UP:
g->name); case PIN_CONFIG_BIAS_PULL_DOWN:
return -ENOTSUPP; if (!opt->pud_info) {
} dev_err(pci->dev,
base = opt->pud_info->pullup_dn_reg_base; "PULL control not supported for pin %s\n",
add = opt->pud_info->pullup_dn_reg_add; g->name);
mask = opt->pud_info->pullup_dn_mask; return -ENOTSUPP;
}
if (param == PIN_CONFIG_BIAS_DISABLE) base = opt->pud_info->pullup_dn_reg_base;
rval = opt->pud_info->normal_val; add = opt->pud_info->pullup_dn_reg_add;
else if (param == PIN_CONFIG_BIAS_PULL_UP) mask = opt->pud_info->pullup_dn_mask;
rval = opt->pud_info->pull_up_val;
else if (param == PIN_CONFIG_BIAS_DISABLE)
rval = opt->pud_info->pull_dn_val; rval = opt->pud_info->normal_val;
else if (param == PIN_CONFIG_BIAS_PULL_UP)
rval = opt->pud_info->pull_up_val;
else
rval = opt->pud_info->pull_dn_val;
if (rval < 0) {
dev_err(pci->dev,
"PULL control not supported for pin %s\n",
g->name);
return -ENOTSUPP;
}
break;
if (rval < 0) { case PIN_CONFIG_DRIVE_OPEN_DRAIN:
dev_err(pci->dev, if (!opt->od_info) {
"PULL control not supported for pin %s\n", dev_err(pci->dev,
g->name); "OD control not supported for pin %s\n",
g->name);
return -ENOTSUPP;
}
base = opt->od_info->od_reg_base;
add = opt->od_info->od_reg_add;
mask = opt->od_info->od_mask;
if (param_val == 0)
rval = opt->od_info->od_disable;
else
rval = opt->od_info->od_enable;
if (rval < 0) {
dev_err(pci->dev,
"OD control not supported for pin %s\n",
g->name);
return -ENOTSUPP;
}
break;
default:
dev_err(pci->dev, "Properties not supported\n");
return -ENOTSUPP; return -ENOTSUPP;
} }
break;
case PIN_CONFIG_DRIVE_OPEN_DRAIN: dev_dbg(pci->dev, "%s(): Add0x%02x:0x%02x:0x%02x:0x%02x\n",
if (!opt->od_info) { __func__, base, add, mask, rval);
dev_err(pci->dev, ret = palmas_update_bits(pci->palmas, base, add, mask, rval);
"OD control not supported for pin %s\n", if (ret < 0) {
g->name); dev_err(pci->dev, "Reg 0x%02x update failed: %d\n",
return -ENOTSUPP; add, ret);
} return ret;
base = opt->od_info->od_reg_base;
add = opt->od_info->od_reg_add;
mask = opt->od_info->od_mask;
if (param_val == 0)
rval = opt->od_info->od_disable;
else
rval = opt->od_info->od_enable;
if (rval < 0) {
dev_err(pci->dev,
"OD control not supported for pin %s\n",
g->name);
return -ENOTSUPP;
} }
break; } /* for each config */
default:
dev_err(pci->dev, "Properties not supported\n");
return -ENOTSUPP;
}
dev_dbg(pci->dev, "%s(): Add0x%02x:0x%02x:0x%02x:0x%02x\n",
__func__, base, add, mask, rval);
ret = palmas_update_bits(pci->palmas, base, add, mask, rval);
if (ret < 0) {
dev_err(pci->dev, "Reg 0x%02x update failed: %d\n", add, ret);
return ret;
}
return 0; return 0;
} }
...@@ -960,7 +969,8 @@ static int palmas_pinconf_group_get(struct pinctrl_dev *pctldev, ...@@ -960,7 +969,8 @@ static int palmas_pinconf_group_get(struct pinctrl_dev *pctldev,
} }
static int palmas_pinconf_group_set(struct pinctrl_dev *pctldev, static int palmas_pinconf_group_set(struct pinctrl_dev *pctldev,
unsigned group, unsigned long config) unsigned group, unsigned long *configs,
unsigned num_configs)
{ {
dev_err(pctldev->dev, "palmas_pinconf_group_set op not supported\n"); dev_err(pctldev->dev, "palmas_pinconf_group_set op not supported\n");
return -ENOTSUPP; return -ENOTSUPP;
......
...@@ -574,32 +574,45 @@ static bool rockchip_pinconf_pull_valid(struct rockchip_pin_ctrl *ctrl, ...@@ -574,32 +574,45 @@ static bool rockchip_pinconf_pull_valid(struct rockchip_pin_ctrl *ctrl,
/* set the pin config settings for a specified pin */ /* set the pin config settings for a specified pin */
static int rockchip_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, static int rockchip_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
unsigned long config) unsigned long *configs, unsigned num_configs)
{ {
struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
struct rockchip_pin_bank *bank = pin_to_bank(info, pin); struct rockchip_pin_bank *bank = pin_to_bank(info, pin);
enum pin_config_param param = pinconf_to_config_param(config); enum pin_config_param param;
u16 arg = pinconf_to_config_argument(config); u16 arg;
int i;
switch (param) { int rc;
case PIN_CONFIG_BIAS_DISABLE:
return rockchip_set_pull(bank, pin - bank->pin_base, param); for (i = 0; i < num_configs; i++) {
break; param = pinconf_to_config_param(configs[i]);
case PIN_CONFIG_BIAS_PULL_UP: arg = pinconf_to_config_argument(configs[i]);
case PIN_CONFIG_BIAS_PULL_DOWN:
case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: switch (param) {
if (!rockchip_pinconf_pull_valid(info->ctrl, param)) case PIN_CONFIG_BIAS_DISABLE:
rc = rockchip_set_pull(bank, pin - bank->pin_base,
param);
if (rc)
return rc;
break;
case PIN_CONFIG_BIAS_PULL_UP:
case PIN_CONFIG_BIAS_PULL_DOWN:
case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
if (!rockchip_pinconf_pull_valid(info->ctrl, param))
return -ENOTSUPP;
if (!arg)
return -EINVAL;
rc = rockchip_set_pull(bank, pin - bank->pin_base,
param);
if (rc)
return rc;
break;
default:
return -ENOTSUPP; return -ENOTSUPP;
break;
if (!arg) }
return -EINVAL; } /* for each config */
return rockchip_set_pull(bank, pin - bank->pin_base, param);
break;
default:
return -ENOTSUPP;
break;
}
return 0; return 0;
} }
......
...@@ -442,9 +442,17 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin, ...@@ -442,9 +442,17 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin,
/* set the pin config settings for a specified pin */ /* set the pin config settings for a specified pin */
static int samsung_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, static int samsung_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
unsigned long config) unsigned long *configs, unsigned num_configs)
{ {
return samsung_pinconf_rw(pctldev, pin, &config, true); int i, ret;
for (i = 0; i < num_configs; i++) {
ret = samsung_pinconf_rw(pctldev, pin, &configs[i], true);
if (ret < 0)
return ret;
} /* for each config */
return 0;
} }
/* get the pin config settings for a specified pin */ /* get the pin config settings for a specified pin */
...@@ -456,7 +464,8 @@ static int samsung_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, ...@@ -456,7 +464,8 @@ static int samsung_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin,
/* set the pin config settings for a specified pin group */ /* set the pin config settings for a specified pin group */
static int samsung_pinconf_group_set(struct pinctrl_dev *pctldev, static int samsung_pinconf_group_set(struct pinctrl_dev *pctldev,
unsigned group, unsigned long config) unsigned group, unsigned long *configs,
unsigned num_configs)
{ {
struct samsung_pinctrl_drv_data *drvdata; struct samsung_pinctrl_drv_data *drvdata;
const unsigned int *pins; const unsigned int *pins;
...@@ -466,7 +475,7 @@ static int samsung_pinconf_group_set(struct pinctrl_dev *pctldev, ...@@ -466,7 +475,7 @@ static int samsung_pinconf_group_set(struct pinctrl_dev *pctldev,
pins = drvdata->pin_groups[group].pins; pins = drvdata->pin_groups[group].pins;
for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++) for (cnt = 0; cnt < drvdata->pin_groups[group].num_pins; cnt++)
samsung_pinconf_set(pctldev, pins[cnt], config); samsung_pinconf_set(pctldev, pins[cnt], configs, num_configs);
return 0; return 0;
} }
......
...@@ -209,7 +209,7 @@ struct pcs_device { ...@@ -209,7 +209,7 @@ struct pcs_device {
static int pcs_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin, static int pcs_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin,
unsigned long *config); unsigned long *config);
static int pcs_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin, static int pcs_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin,
unsigned long config); unsigned long *configs, unsigned num_configs);
static enum pin_config_param pcs_bias[] = { static enum pin_config_param pcs_bias[] = {
PIN_CONFIG_BIAS_PULL_DOWN, PIN_CONFIG_BIAS_PULL_DOWN,
...@@ -536,7 +536,7 @@ static void pcs_pinconf_clear_bias(struct pinctrl_dev *pctldev, unsigned pin) ...@@ -536,7 +536,7 @@ static void pcs_pinconf_clear_bias(struct pinctrl_dev *pctldev, unsigned pin)
int i; int i;
for (i = 0; i < ARRAY_SIZE(pcs_bias); i++) { for (i = 0; i < ARRAY_SIZE(pcs_bias); i++) {
config = pinconf_to_config_packed(pcs_bias[i], 0); config = pinconf_to_config_packed(pcs_bias[i], 0);
pcs_pinconf_set(pctldev, pin, config); pcs_pinconf_set(pctldev, pin, &config, 1);
} }
} }
...@@ -622,22 +622,28 @@ static int pcs_pinconf_get(struct pinctrl_dev *pctldev, ...@@ -622,22 +622,28 @@ static int pcs_pinconf_get(struct pinctrl_dev *pctldev,
} }
static int pcs_pinconf_set(struct pinctrl_dev *pctldev, static int pcs_pinconf_set(struct pinctrl_dev *pctldev,
unsigned pin, unsigned long config) unsigned pin, unsigned long *configs,
unsigned num_configs)
{ {
struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev); struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
struct pcs_function *func; struct pcs_function *func;
unsigned offset = 0, shift = 0, i, data, ret; unsigned offset = 0, shift = 0, i, data, ret;
u16 arg; u16 arg;
int j;
ret = pcs_get_function(pctldev, pin, &func); ret = pcs_get_function(pctldev, pin, &func);
if (ret) if (ret)
return ret; return ret;
for (i = 0; i < func->nconfs; i++) { for (j = 0; j < num_configs; j++) {
if (pinconf_to_config_param(config) == func->conf[i].param) { for (i = 0; i < func->nconfs; i++) {
if (pinconf_to_config_param(configs[j])
!= func->conf[i].param)
continue;
offset = pin * (pcs->width / BITS_PER_BYTE); offset = pin * (pcs->width / BITS_PER_BYTE);
data = pcs->read(pcs->base + offset); data = pcs->read(pcs->base + offset);
arg = pinconf_to_config_argument(config); arg = pinconf_to_config_argument(configs[j]);
switch (func->conf[i].param) { switch (func->conf[i].param) {
/* 2 parameters */ /* 2 parameters */
case PIN_CONFIG_INPUT_SCHMITT: case PIN_CONFIG_INPUT_SCHMITT:
...@@ -667,10 +673,14 @@ static int pcs_pinconf_set(struct pinctrl_dev *pctldev, ...@@ -667,10 +673,14 @@ static int pcs_pinconf_set(struct pinctrl_dev *pctldev,
return -ENOTSUPP; return -ENOTSUPP;
} }
pcs->write(data, pcs->base + offset); pcs->write(data, pcs->base + offset);
return 0;
break;
} }
} if (i >= func->nconfs)
return -ENOTSUPP; return -ENOTSUPP;
} /* for each config */
return 0;
} }
static int pcs_pinconf_group_get(struct pinctrl_dev *pctldev, static int pcs_pinconf_group_get(struct pinctrl_dev *pctldev,
...@@ -695,7 +705,8 @@ static int pcs_pinconf_group_get(struct pinctrl_dev *pctldev, ...@@ -695,7 +705,8 @@ static int pcs_pinconf_group_get(struct pinctrl_dev *pctldev,
} }
static int pcs_pinconf_group_set(struct pinctrl_dev *pctldev, static int pcs_pinconf_group_set(struct pinctrl_dev *pctldev,
unsigned group, unsigned long config) unsigned group, unsigned long *configs,
unsigned num_configs)
{ {
const unsigned *pins; const unsigned *pins;
unsigned npins; unsigned npins;
...@@ -705,7 +716,7 @@ static int pcs_pinconf_group_set(struct pinctrl_dev *pctldev, ...@@ -705,7 +716,7 @@ static int pcs_pinconf_group_set(struct pinctrl_dev *pctldev,
if (ret) if (ret)
return ret; return ret;
for (i = 0; i < npins; i++) { for (i = 0; i < npins; i++) {
if (pcs_pinconf_set(pctldev, pins[i], config)) if (pcs_pinconf_set(pctldev, pins[i], configs, num_configs))
return -ENOTSUPP; return -ENOTSUPP;
} }
return 0; return 0;
......
...@@ -909,15 +909,18 @@ static void st_pinconf_set_retime(struct st_pinctrl *info, ...@@ -909,15 +909,18 @@ static void st_pinconf_set_retime(struct st_pinctrl *info,
config, pin); config, pin);
} }
static int st_pinconf_set(struct pinctrl_dev *pctldev, static int st_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin_id,
unsigned pin_id, unsigned long config) unsigned long *configs, unsigned num_configs)
{ {
int pin = st_gpio_pin(pin_id); int pin = st_gpio_pin(pin_id);
struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); struct st_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
struct st_pio_control *pc = st_get_pio_control(pctldev, pin_id); struct st_pio_control *pc = st_get_pio_control(pctldev, pin_id);
int i;
st_pinconf_set_config(pc, pin, config); for (i = 0; i < num_configs; i++) {
st_pinconf_set_retime(info, pc, pin, config); st_pinconf_set_config(pc, pin, configs[i]);
st_pinconf_set_retime(info, pc, pin, configs[i]);
} /* for each config */
return 0; return 0;
} }
......
...@@ -274,50 +274,55 @@ static int sunxi_pconf_group_get(struct pinctrl_dev *pctldev, ...@@ -274,50 +274,55 @@ static int sunxi_pconf_group_get(struct pinctrl_dev *pctldev,
static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev, static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev,
unsigned group, unsigned group,
unsigned long config) unsigned long *configs,
unsigned num_configs)
{ {
struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
struct sunxi_pinctrl_group *g = &pctl->groups[group]; struct sunxi_pinctrl_group *g = &pctl->groups[group];
u32 val, mask; u32 val, mask;
u16 strength; u16 strength;
u8 dlevel; u8 dlevel;
int i;
switch (pinconf_to_config_param(config)) { for (i = 0; i < num_configs; i++) {
case PIN_CONFIG_DRIVE_STRENGTH: switch (pinconf_to_config_param(configs[i])) {
strength = pinconf_to_config_argument(config); case PIN_CONFIG_DRIVE_STRENGTH:
if (strength > 40) strength = pinconf_to_config_argument(configs[i]);
return -EINVAL; if (strength > 40)
/* return -EINVAL;
* We convert from mA to what the register expects: /*
* 0: 10mA * We convert from mA to what the register expects:
* 1: 20mA * 0: 10mA
* 2: 30mA * 1: 20mA
* 3: 40mA * 2: 30mA
*/ * 3: 40mA
dlevel = strength / 10 - 1; */
val = readl(pctl->membase + sunxi_dlevel_reg(g->pin)); dlevel = strength / 10 - 1;
mask = DLEVEL_PINS_MASK << sunxi_dlevel_offset(g->pin); val = readl(pctl->membase + sunxi_dlevel_reg(g->pin));
writel((val & ~mask) | dlevel << sunxi_dlevel_offset(g->pin), mask = DLEVEL_PINS_MASK << sunxi_dlevel_offset(g->pin);
pctl->membase + sunxi_dlevel_reg(g->pin)); writel((val & ~mask)
break; | dlevel << sunxi_dlevel_offset(g->pin),
case PIN_CONFIG_BIAS_PULL_UP: pctl->membase + sunxi_dlevel_reg(g->pin));
val = readl(pctl->membase + sunxi_pull_reg(g->pin)); break;
mask = PULL_PINS_MASK << sunxi_pull_offset(g->pin); case PIN_CONFIG_BIAS_PULL_UP:
writel((val & ~mask) | 1 << sunxi_pull_offset(g->pin), val = readl(pctl->membase + sunxi_pull_reg(g->pin));
pctl->membase + sunxi_pull_reg(g->pin)); mask = PULL_PINS_MASK << sunxi_pull_offset(g->pin);
break; writel((val & ~mask) | 1 << sunxi_pull_offset(g->pin),
case PIN_CONFIG_BIAS_PULL_DOWN: pctl->membase + sunxi_pull_reg(g->pin));
val = readl(pctl->membase + sunxi_pull_reg(g->pin)); break;
mask = PULL_PINS_MASK << sunxi_pull_offset(g->pin); case PIN_CONFIG_BIAS_PULL_DOWN:
writel((val & ~mask) | 2 << sunxi_pull_offset(g->pin), val = readl(pctl->membase + sunxi_pull_reg(g->pin));
pctl->membase + sunxi_pull_reg(g->pin)); mask = PULL_PINS_MASK << sunxi_pull_offset(g->pin);
break; writel((val & ~mask) | 2 << sunxi_pull_offset(g->pin),
default: pctl->membase + sunxi_pull_reg(g->pin));
break; break;
} default:
break;
}
/* cache the config value */ /* cache the config value */
g->config = config; g->config = configs[i];
} /* for each config */
return 0; return 0;
} }
......
...@@ -436,7 +436,8 @@ static int tegra_pinconf_get(struct pinctrl_dev *pctldev, ...@@ -436,7 +436,8 @@ static int tegra_pinconf_get(struct pinctrl_dev *pctldev,
} }
static int tegra_pinconf_set(struct pinctrl_dev *pctldev, static int tegra_pinconf_set(struct pinctrl_dev *pctldev,
unsigned pin, unsigned long config) unsigned pin, unsigned long *configs,
unsigned num_configs)
{ {
dev_err(pctldev->dev, "pin_config_set op not supported\n"); dev_err(pctldev->dev, "pin_config_set op not supported\n");
return -ENOTSUPP; return -ENOTSUPP;
...@@ -471,51 +472,57 @@ static int tegra_pinconf_group_get(struct pinctrl_dev *pctldev, ...@@ -471,51 +472,57 @@ static int tegra_pinconf_group_get(struct pinctrl_dev *pctldev,
} }
static int tegra_pinconf_group_set(struct pinctrl_dev *pctldev, static int tegra_pinconf_group_set(struct pinctrl_dev *pctldev,
unsigned group, unsigned long config) unsigned group, unsigned long *configs,
unsigned num_configs)
{ {
struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
enum tegra_pinconf_param param = TEGRA_PINCONF_UNPACK_PARAM(config); enum tegra_pinconf_param param;
u16 arg = TEGRA_PINCONF_UNPACK_ARG(config); u16 arg;
const struct tegra_pingroup *g; const struct tegra_pingroup *g;
int ret; int ret, i;
s8 bank, bit, width; s8 bank, bit, width;
s16 reg; s16 reg;
u32 val, mask; u32 val, mask;
g = &pmx->soc->groups[group]; g = &pmx->soc->groups[group];
ret = tegra_pinconf_reg(pmx, g, param, true, &bank, &reg, &bit, for (i = 0; i < num_configs; i++) {
&width); param = TEGRA_PINCONF_UNPACK_PARAM(configs[i]);
if (ret < 0) arg = TEGRA_PINCONF_UNPACK_ARG(configs[i]);
return ret;
val = pmx_readl(pmx, bank, reg); ret = tegra_pinconf_reg(pmx, g, param, true, &bank, &reg, &bit,
&width);
if (ret < 0)
return ret;
/* LOCK can't be cleared */ val = pmx_readl(pmx, bank, reg);
if (param == TEGRA_PINCONF_PARAM_LOCK) {
if ((val & BIT(bit)) && !arg) { /* LOCK can't be cleared */
dev_err(pctldev->dev, "LOCK bit cannot be cleared\n"); if (param == TEGRA_PINCONF_PARAM_LOCK) {
return -EINVAL; if ((val & BIT(bit)) && !arg) {
dev_err(pctldev->dev, "LOCK bit cannot be cleared\n");
return -EINVAL;
}
} }
}
/* Special-case Boolean values; allow any non-zero as true */ /* Special-case Boolean values; allow any non-zero as true */
if (width == 1) if (width == 1)
arg = !!arg; arg = !!arg;
/* Range-check user-supplied value */ /* Range-check user-supplied value */
mask = (1 << width) - 1; mask = (1 << width) - 1;
if (arg & ~mask) { if (arg & ~mask) {
dev_err(pctldev->dev, dev_err(pctldev->dev,
"config %lx: %x too big for %d bit register\n", "config %lx: %x too big for %d bit register\n",
config, arg, width); configs[i], arg, width);
return -EINVAL; return -EINVAL;
} }
/* Update register */ /* Update register */
val &= ~(mask << bit); val &= ~(mask << bit);
val |= arg << bit; val |= arg << bit;
pmx_writel(pmx, val, bank, reg); pmx_writel(pmx, val, bank, reg);
} /* for each config */
return 0; return 0;
} }
......
...@@ -737,39 +737,46 @@ static int tz1090_pdc_pinconf_get(struct pinctrl_dev *pctldev, ...@@ -737,39 +737,46 @@ static int tz1090_pdc_pinconf_get(struct pinctrl_dev *pctldev,
} }
static int tz1090_pdc_pinconf_set(struct pinctrl_dev *pctldev, static int tz1090_pdc_pinconf_set(struct pinctrl_dev *pctldev,
unsigned int pin, unsigned long config) unsigned int pin, unsigned long *configs,
unsigned num_configs)
{ {
struct tz1090_pdc_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); struct tz1090_pdc_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
enum pin_config_param param = pinconf_to_config_param(config); enum pin_config_param param;
unsigned int arg = pinconf_to_config_argument(config); unsigned int arg;
int ret; int ret;
u32 reg, width, mask, shift, val, tmp; u32 reg, width, mask, shift, val, tmp;
unsigned long flags; unsigned long flags;
int i;
dev_dbg(pctldev->dev, "%s(pin=%s, config=%#lx)\n", for (i = 0; i < num_configs; i++) {
__func__, tz1090_pdc_pins[pin].name, config); param = pinconf_to_config_param(configs[i]);
arg = pinconf_to_config_argument(configs[i]);
/* Get register information */ dev_dbg(pctldev->dev, "%s(pin=%s, config=%#lx)\n",
ret = tz1090_pdc_pinconf_reg(pctldev, pin, param, true, __func__, tz1090_pdc_pins[pin].name, configs[i]);
&reg, &width, &mask, &shift, &val);
if (ret < 0)
return ret;
/* Unpack argument and range check it */ /* Get register information */
if (arg > 1) { ret = tz1090_pdc_pinconf_reg(pctldev, pin, param, true,
dev_dbg(pctldev->dev, "%s: arg %u out of range\n", &reg, &width, &mask, &shift, &val);
__func__, arg); if (ret < 0)
return -EINVAL; return ret;
}
/* Write register field */ /* Unpack argument and range check it */
__global_lock2(flags); if (arg > 1) {
tmp = pmx_read(pmx, reg); dev_dbg(pctldev->dev, "%s: arg %u out of range\n",
tmp &= ~mask; __func__, arg);
if (arg) return -EINVAL;
tmp |= val << shift; }
pmx_write(pmx, tmp, reg);
__global_unlock2(flags); /* Write register field */
__global_lock2(flags);
tmp = pmx_read(pmx, reg);
tmp &= ~mask;
if (arg)
tmp |= val << shift;
pmx_write(pmx, tmp, reg);
__global_unlock2(flags);
} /* for each config */
return 0; return 0;
} }
...@@ -860,54 +867,68 @@ static int tz1090_pdc_pinconf_group_get(struct pinctrl_dev *pctldev, ...@@ -860,54 +867,68 @@ static int tz1090_pdc_pinconf_group_get(struct pinctrl_dev *pctldev,
static int tz1090_pdc_pinconf_group_set(struct pinctrl_dev *pctldev, static int tz1090_pdc_pinconf_group_set(struct pinctrl_dev *pctldev,
unsigned int group, unsigned int group,
unsigned long config) unsigned long *configs,
unsigned num_configs)
{ {
struct tz1090_pdc_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); struct tz1090_pdc_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
const struct tz1090_pdc_pingroup *g = &tz1090_pdc_groups[group]; const struct tz1090_pdc_pingroup *g = &tz1090_pdc_groups[group];
enum pin_config_param param = pinconf_to_config_param(config); enum pin_config_param param;
const unsigned int *pit; const unsigned int *pit;
unsigned int i; unsigned int i;
int ret, arg; int ret, arg;
u32 reg, width, mask, shift, val; u32 reg, width, mask, shift, val;
unsigned long flags; unsigned long flags;
const int *map; const int *map;
int j;
dev_dbg(pctldev->dev, "%s(group=%s, config=%#lx)\n", for (j = 0; j < num_configs; j++) {
__func__, g->name, config); param = pinconf_to_config_param(configs[j]);
/* Get register information */ dev_dbg(pctldev->dev, "%s(group=%s, config=%#lx)\n",
ret = tz1090_pdc_pinconf_group_reg(pctldev, g, param, true, __func__, g->name, configs[j]);
&reg, &width, &mask, &shift, &map);
if (ret < 0) {
/*
* Maybe we're trying to set a per-pin configuration of a group,
* so do the pins one by one. This is mainly as a convenience.
*/
for (i = 0, pit = g->pins; i < g->npins; ++i, ++pit) {
ret = tz1090_pdc_pinconf_set(pctldev, *pit, config);
if (ret)
return ret;
}
return 0;
}
/* Unpack argument and map it to register value */ /* Get register information */
arg = pinconf_to_config_argument(config); ret = tz1090_pdc_pinconf_group_reg(pctldev, g, param, true,
for (i = 0; i < BIT(width); ++i) { &reg, &width, &mask, &shift,
if (map[i] == arg || (map[i] == -EINVAL && !arg)) { &map);
/* Write register field */ if (ret < 0) {
__global_lock2(flags); /*
val = pmx_read(pmx, reg); * Maybe we're trying to set a per-pin configuration
val &= ~mask; * of a group, so do the pins one by one. This is
val |= i << shift; * mainly as a convenience.
pmx_write(pmx, val, reg); */
__global_unlock2(flags); for (i = 0, pit = g->pins; i < g->npins; ++i, ++pit) {
ret = tz1090_pdc_pinconf_set(pctldev, *pit,
configs, num_configs);
if (ret)
return ret;
}
return 0; return 0;
} }
}
dev_dbg(pctldev->dev, "%s: arg %u not supported\n", /* Unpack argument and map it to register value */
__func__, arg); arg = pinconf_to_config_argument(configs[j]);
for (i = 0; i < BIT(width); ++i) {
if (map[i] == arg || (map[i] == -EINVAL && !arg)) {
/* Write register field */
__global_lock2(flags);
val = pmx_read(pmx, reg);
val &= ~mask;
val |= i << shift;
pmx_write(pmx, val, reg);
__global_unlock2(flags);
goto next_config;
}
}
dev_dbg(pctldev->dev, "%s: arg %u not supported\n",
__func__, arg);
return 0;
next_config:
;
} /* for each config */
return 0; return 0;
} }
......
...@@ -1762,39 +1762,46 @@ static int tz1090_pinconf_get(struct pinctrl_dev *pctldev, ...@@ -1762,39 +1762,46 @@ static int tz1090_pinconf_get(struct pinctrl_dev *pctldev,
} }
static int tz1090_pinconf_set(struct pinctrl_dev *pctldev, static int tz1090_pinconf_set(struct pinctrl_dev *pctldev,
unsigned int pin, unsigned long config) unsigned int pin, unsigned long *configs,
unsigned num_configs)
{ {
struct tz1090_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); struct tz1090_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
enum pin_config_param param = pinconf_to_config_param(config); enum pin_config_param param;
unsigned int arg = pinconf_to_config_argument(config); unsigned int arg;
int ret; int ret;
u32 reg, width, mask, shift, val, tmp; u32 reg, width, mask, shift, val, tmp;
unsigned long flags; unsigned long flags;
int i;
dev_dbg(pctldev->dev, "%s(pin=%s, config=%#lx)\n", for (i = 0; i < num_configs; i++) {
__func__, tz1090_pins[pin].name, config); param = pinconf_to_config_param(configs[i]);
arg = pinconf_to_config_argument(configs[i]);
/* Get register information */ dev_dbg(pctldev->dev, "%s(pin=%s, config=%#lx)\n",
ret = tz1090_pinconf_reg(pctldev, pin, param, true, __func__, tz1090_pins[pin].name, configs[i]);
&reg, &width, &mask, &shift, &val);
if (ret < 0)
return ret;
/* Unpack argument and range check it */ /* Get register information */
if (arg > 1) { ret = tz1090_pinconf_reg(pctldev, pin, param, true,
dev_dbg(pctldev->dev, "%s: arg %u out of range\n", &reg, &width, &mask, &shift, &val);
__func__, arg); if (ret < 0)
return -EINVAL; return ret;
}
/* Write register field */ /* Unpack argument and range check it */
__global_lock2(flags); if (arg > 1) {
tmp = pmx_read(pmx, reg); dev_dbg(pctldev->dev, "%s: arg %u out of range\n",
tmp &= ~mask; __func__, arg);
if (arg) return -EINVAL;
tmp |= val << shift; }
pmx_write(pmx, tmp, reg);
__global_unlock2(flags); /* Write register field */
__global_lock2(flags);
tmp = pmx_read(pmx, reg);
tmp &= ~mask;
if (arg)
tmp |= val << shift;
pmx_write(pmx, tmp, reg);
__global_unlock2(flags);
} /* for each config */
return 0; return 0;
} }
...@@ -1894,68 +1901,81 @@ static int tz1090_pinconf_group_get(struct pinctrl_dev *pctldev, ...@@ -1894,68 +1901,81 @@ static int tz1090_pinconf_group_get(struct pinctrl_dev *pctldev,
} }
static int tz1090_pinconf_group_set(struct pinctrl_dev *pctldev, static int tz1090_pinconf_group_set(struct pinctrl_dev *pctldev,
unsigned int group, unsigned long config) unsigned int group, unsigned long *configs,
unsigned num_configs)
{ {
struct tz1090_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); struct tz1090_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
const struct tz1090_pingroup *g; const struct tz1090_pingroup *g;
enum pin_config_param param = pinconf_to_config_param(config); enum pin_config_param param;
unsigned int arg, pin, i; unsigned int arg, pin, i;
const unsigned int *pit; const unsigned int *pit;
int ret; int ret;
u32 reg, width, mask, shift, val; u32 reg, width, mask, shift, val;
unsigned long flags; unsigned long flags;
const int *map; const int *map;
int j;
if (group >= ARRAY_SIZE(tz1090_groups)) { if (group >= ARRAY_SIZE(tz1090_groups)) {
pin = group - ARRAY_SIZE(tz1090_groups); pin = group - ARRAY_SIZE(tz1090_groups);
return tz1090_pinconf_set(pctldev, pin, config); return tz1090_pinconf_set(pctldev, pin, configs, num_configs);
} }
g = &tz1090_groups[group]; g = &tz1090_groups[group];
if (g->npins == 1) { if (g->npins == 1) {
pin = g->pins[0]; pin = g->pins[0];
ret = tz1090_pinconf_set(pctldev, pin, config); ret = tz1090_pinconf_set(pctldev, pin, configs, num_configs);
if (ret != -ENOTSUPP) if (ret != -ENOTSUPP)
return ret; return ret;
} }
dev_dbg(pctldev->dev, "%s(group=%s, config=%#lx)\n", for (j = 0; j < num_configs; j++) {
__func__, g->name, config); param = pinconf_to_config_param(configs[j]);
/* Get register information */ dev_dbg(pctldev->dev, "%s(group=%s, config=%#lx)\n",
ret = tz1090_pinconf_group_reg(pctldev, g, param, true, __func__, g->name, configs[j]);
&reg, &width, &mask, &shift, &map);
if (ret < 0) {
/*
* Maybe we're trying to set a per-pin configuration of a group,
* so do the pins one by one. This is mainly as a convenience.
*/
for (i = 0, pit = g->pins; i < g->npins; ++i, ++pit) {
ret = tz1090_pinconf_set(pctldev, *pit, config);
if (ret)
return ret;
}
return 0;
}
/* Unpack argument and map it to register value */ /* Get register information */
arg = pinconf_to_config_argument(config); ret = tz1090_pinconf_group_reg(pctldev, g, param, true, &reg,
for (i = 0; i < BIT(width); ++i) { &width, &mask, &shift, &map);
if (map[i] == arg || (map[i] == -EINVAL && !arg)) { if (ret < 0) {
/* Write register field */ /*
__global_lock2(flags); * Maybe we're trying to set a per-pin configuration
val = pmx_read(pmx, reg); * of a group, so do the pins one by one. This is
val &= ~mask; * mainly as a convenience.
val |= i << shift; */
pmx_write(pmx, val, reg); for (i = 0, pit = g->pins; i < g->npins; ++i, ++pit) {
__global_unlock2(flags); ret = tz1090_pinconf_set(pctldev, *pit, configs,
num_configs);
if (ret)
return ret;
}
return 0; return 0;
} }
}
dev_dbg(pctldev->dev, "%s: arg %u not supported\n", /* Unpack argument and map it to register value */
__func__, arg); arg = pinconf_to_config_argument(configs[j]);
return -EINVAL; for (i = 0; i < BIT(width); ++i) {
if (map[i] == arg || (map[i] == -EINVAL && !arg)) {
/* Write register field */
__global_lock2(flags);
val = pmx_read(pmx, reg);
val &= ~mask;
val |= i << shift;
pmx_write(pmx, val, reg);
__global_unlock2(flags);
goto next_config;
}
}
dev_dbg(pctldev->dev, "%s: arg %u not supported\n",
__func__, arg);
return -EINVAL;
next_config:
;
} /* for each config */
return 0;
} }
static struct pinconf_ops tz1090_pinconf_ops = { static struct pinconf_ops tz1090_pinconf_ops = {
......
...@@ -1027,21 +1027,23 @@ static int u300_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin, ...@@ -1027,21 +1027,23 @@ static int u300_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin,
} }
static int u300_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin, static int u300_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
unsigned long config) unsigned long *configs, unsigned num_configs)
{ {
struct pinctrl_gpio_range *range = struct pinctrl_gpio_range *range =
pinctrl_find_gpio_range_from_pin(pctldev, pin); pinctrl_find_gpio_range_from_pin(pctldev, pin);
int ret; int ret, i;
if (!range) if (!range)
return -EINVAL; return -EINVAL;
/* Note: none of these configurations take any argument */ for (i = 0; i < num_configs; i++) {
ret = u300_gpio_config_set(range->gc, /* Note: none of these configurations take any argument */
(pin - range->pin_base + range->base), ret = u300_gpio_config_set(range->gc,
pinconf_to_config_param(config)); (pin - range->pin_base + range->base),
if (ret) pinconf_to_config_param(configs[i]));
return ret; if (ret)
return ret;
} /* for each config */
return 0; return 0;
} }
......
...@@ -499,74 +499,101 @@ static int xway_pinconf_get(struct pinctrl_dev *pctldev, ...@@ -499,74 +499,101 @@ static int xway_pinconf_get(struct pinctrl_dev *pctldev,
static int xway_pinconf_set(struct pinctrl_dev *pctldev, static int xway_pinconf_set(struct pinctrl_dev *pctldev,
unsigned pin, unsigned pin,
unsigned long config) unsigned long *configs,
unsigned num_configs)
{ {
struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctldev); struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctldev);
enum ltq_pinconf_param param = LTQ_PINCONF_UNPACK_PARAM(config); enum ltq_pinconf_param param;
int arg = LTQ_PINCONF_UNPACK_ARG(config); int arg;
int port = PORT(pin); int port = PORT(pin);
u32 reg; u32 reg;
int i;
for (i = 0; i < num_configs; i++) {
param = LTQ_PINCONF_UNPACK_PARAM(configs[i]);
arg = LTQ_PINCONF_UNPACK_ARG(configs[i]);
switch (param) {
case LTQ_PINCONF_PARAM_OPEN_DRAIN:
if (port == PORT3)
reg = GPIO3_OD;
else
reg = GPIO_OD(pin);
if (arg == 0)
gpio_setbit(info->membase[0],
reg,
PORT_PIN(pin));
else
gpio_clearbit(info->membase[0],
reg,
PORT_PIN(pin));
break;
switch (param) { case LTQ_PINCONF_PARAM_PULL:
case LTQ_PINCONF_PARAM_OPEN_DRAIN: if (port == PORT3)
if (port == PORT3) reg = GPIO3_PUDEN;
reg = GPIO3_OD; else
else reg = GPIO_PUDEN(pin);
reg = GPIO_OD(pin); if (arg == 0) {
if (arg == 0) gpio_clearbit(info->membase[0],
reg,
PORT_PIN(pin));
break;
}
gpio_setbit(info->membase[0], reg, PORT_PIN(pin)); gpio_setbit(info->membase[0], reg, PORT_PIN(pin));
else
gpio_clearbit(info->membase[0], reg, PORT_PIN(pin));
break;
case LTQ_PINCONF_PARAM_PULL: if (port == PORT3)
if (port == PORT3) reg = GPIO3_PUDSEL;
reg = GPIO3_PUDEN; else
else reg = GPIO_PUDSEL(pin);
reg = GPIO_PUDEN(pin); if (arg == 1)
if (arg == 0) { gpio_clearbit(info->membase[0],
gpio_clearbit(info->membase[0], reg, PORT_PIN(pin)); reg,
PORT_PIN(pin));
else if (arg == 2)
gpio_setbit(info->membase[0],
reg,
PORT_PIN(pin));
else
dev_err(pctldev->dev,
"Invalid pull value %d\n", arg);
break; break;
}
gpio_setbit(info->membase[0], reg, PORT_PIN(pin));
if (port == PORT3) case LTQ_PINCONF_PARAM_OUTPUT:
reg = GPIO3_PUDSEL; reg = GPIO_DIR(pin);
else if (arg == 0)
reg = GPIO_PUDSEL(pin); gpio_clearbit(info->membase[0],
if (arg == 1) reg,
gpio_clearbit(info->membase[0], reg, PORT_PIN(pin)); PORT_PIN(pin));
else if (arg == 2) else
gpio_setbit(info->membase[0], reg, PORT_PIN(pin)); gpio_setbit(info->membase[0],
else reg,
dev_err(pctldev->dev, "Invalid pull value %d\n", arg); PORT_PIN(pin));
break; break;
case LTQ_PINCONF_PARAM_OUTPUT: default:
reg = GPIO_DIR(pin); dev_err(pctldev->dev,
if (arg == 0) "Invalid config param %04x\n", param);
gpio_clearbit(info->membase[0], reg, PORT_PIN(pin)); return -ENOTSUPP;
else }
gpio_setbit(info->membase[0], reg, PORT_PIN(pin)); } /* for each config */
break;
default:
dev_err(pctldev->dev, "Invalid config param %04x\n", param);
return -ENOTSUPP;
}
return 0; return 0;
} }
int xway_pinconf_group_set(struct pinctrl_dev *pctldev, int xway_pinconf_group_set(struct pinctrl_dev *pctldev,
unsigned selector, unsigned selector,
unsigned long config) unsigned long *configs,
unsigned num_configs)
{ {
struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctldev); struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctldev);
int i, ret = 0; int i, ret = 0;
for (i = 0; i < info->grps[selector].npins && !ret; i++) for (i = 0; i < info->grps[selector].npins && !ret; i++)
ret = xway_pinconf_set(pctldev, ret = xway_pinconf_set(pctldev,
info->grps[selector].pins[i], config); info->grps[selector].pins[i],
configs,
num_configs);
return ret; return ret;
} }
......
...@@ -529,38 +529,44 @@ static int sh_pfc_pinconf_get(struct pinctrl_dev *pctldev, unsigned _pin, ...@@ -529,38 +529,44 @@ static int sh_pfc_pinconf_get(struct pinctrl_dev *pctldev, unsigned _pin,
} }
static int sh_pfc_pinconf_set(struct pinctrl_dev *pctldev, unsigned _pin, static int sh_pfc_pinconf_set(struct pinctrl_dev *pctldev, unsigned _pin,
unsigned long config) unsigned long *configs, unsigned num_configs)
{ {
struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev);
struct sh_pfc *pfc = pmx->pfc; struct sh_pfc *pfc = pmx->pfc;
enum pin_config_param param = pinconf_to_config_param(config); enum pin_config_param param;
unsigned long flags; unsigned long flags;
unsigned int i;
if (!sh_pfc_pinconf_validate(pfc, _pin, param)) for (i = 0; i < num_configs; i++) {
return -ENOTSUPP; param = pinconf_to_config_param(configs[i]);
switch (param) { if (!sh_pfc_pinconf_validate(pfc, _pin, param))
case PIN_CONFIG_BIAS_PULL_UP:
case PIN_CONFIG_BIAS_PULL_DOWN:
case PIN_CONFIG_BIAS_DISABLE:
if (!pfc->info->ops || !pfc->info->ops->set_bias)
return -ENOTSUPP; return -ENOTSUPP;
spin_lock_irqsave(&pfc->lock, flags); switch (param) {
pfc->info->ops->set_bias(pfc, _pin, param); case PIN_CONFIG_BIAS_PULL_UP:
spin_unlock_irqrestore(&pfc->lock, flags); case PIN_CONFIG_BIAS_PULL_DOWN:
case PIN_CONFIG_BIAS_DISABLE:
if (!pfc->info->ops || !pfc->info->ops->set_bias)
return -ENOTSUPP;
break; spin_lock_irqsave(&pfc->lock, flags);
pfc->info->ops->set_bias(pfc, _pin, param);
spin_unlock_irqrestore(&pfc->lock, flags);
default: break;
return -ENOTSUPP;
} default:
return -ENOTSUPP;
}
} /* for each config */
return 0; return 0;
} }
static int sh_pfc_pinconf_group_set(struct pinctrl_dev *pctldev, unsigned group, static int sh_pfc_pinconf_group_set(struct pinctrl_dev *pctldev, unsigned group,
unsigned long config) unsigned long *configs,
unsigned num_configs)
{ {
struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev);
const unsigned int *pins; const unsigned int *pins;
...@@ -571,7 +577,7 @@ static int sh_pfc_pinconf_group_set(struct pinctrl_dev *pctldev, unsigned group, ...@@ -571,7 +577,7 @@ static int sh_pfc_pinconf_group_set(struct pinctrl_dev *pctldev, unsigned group,
num_pins = pmx->pfc->info->groups[group].nr_pins; num_pins = pmx->pfc->info->groups[group].nr_pins;
for (i = 0; i < num_pins; ++i) for (i = 0; i < num_pins; ++i)
sh_pfc_pinconf_set(pctldev, pins[i], config); sh_pfc_pinconf_set(pctldev, pins[i], configs, num_configs);
return 0; return 0;
} }
......
...@@ -424,15 +424,16 @@ static int wmt_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin, ...@@ -424,15 +424,16 @@ static int wmt_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin,
} }
static int wmt_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin, static int wmt_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin,
unsigned long config) unsigned long *configs, unsigned num_configs)
{ {
struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev); struct wmt_pinctrl_data *data = pinctrl_dev_get_drvdata(pctldev);
enum pin_config_param param = pinconf_to_config_param(config); enum pin_config_param param;
u16 arg = pinconf_to_config_argument(config); u16 arg;
u32 bank = WMT_BANK_FROM_PIN(pin); u32 bank = WMT_BANK_FROM_PIN(pin);
u32 bit = WMT_BIT_FROM_PIN(pin); u32 bit = WMT_BIT_FROM_PIN(pin);
u32 reg_pull_en = data->banks[bank].reg_pull_en; u32 reg_pull_en = data->banks[bank].reg_pull_en;
u32 reg_pull_cfg = data->banks[bank].reg_pull_cfg; u32 reg_pull_cfg = data->banks[bank].reg_pull_cfg;
int i;
if ((reg_pull_en == NO_REG) || (reg_pull_cfg == NO_REG)) { if ((reg_pull_en == NO_REG) || (reg_pull_cfg == NO_REG)) {
dev_err(data->dev, "bias functions not supported on pin %d\n", dev_err(data->dev, "bias functions not supported on pin %d\n",
...@@ -440,28 +441,33 @@ static int wmt_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin, ...@@ -440,28 +441,33 @@ static int wmt_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin,
return -EINVAL; return -EINVAL;
} }
if ((param == PIN_CONFIG_BIAS_PULL_DOWN) || for (i = 0; i < num_configs; i++) {
(param == PIN_CONFIG_BIAS_PULL_UP)) { param = pinconf_to_config_param(configs[i]);
if (arg == 0) arg = pinconf_to_config_argument(configs[i]);
param = PIN_CONFIG_BIAS_DISABLE;
}
switch (param) { if ((param == PIN_CONFIG_BIAS_PULL_DOWN) ||
case PIN_CONFIG_BIAS_DISABLE: (param == PIN_CONFIG_BIAS_PULL_UP)) {
wmt_clearbits(data, reg_pull_en, BIT(bit)); if (arg == 0)
break; param = PIN_CONFIG_BIAS_DISABLE;
case PIN_CONFIG_BIAS_PULL_DOWN: }
wmt_clearbits(data, reg_pull_cfg, BIT(bit));
wmt_setbits(data, reg_pull_en, BIT(bit)); switch (param) {
break; case PIN_CONFIG_BIAS_DISABLE:
case PIN_CONFIG_BIAS_PULL_UP: wmt_clearbits(data, reg_pull_en, BIT(bit));
wmt_setbits(data, reg_pull_cfg, BIT(bit)); break;
wmt_setbits(data, reg_pull_en, BIT(bit)); case PIN_CONFIG_BIAS_PULL_DOWN:
break; wmt_clearbits(data, reg_pull_cfg, BIT(bit));
default: wmt_setbits(data, reg_pull_en, BIT(bit));
dev_err(data->dev, "unknown pinconf param\n"); break;
return -EINVAL; case PIN_CONFIG_BIAS_PULL_UP:
} wmt_setbits(data, reg_pull_cfg, BIT(bit));
wmt_setbits(data, reg_pull_en, BIT(bit));
break;
default:
dev_err(data->dev, "unknown pinconf param\n");
return -EINVAL;
}
} /* for each config */
return 0; return 0;
} }
......
...@@ -47,13 +47,15 @@ struct pinconf_ops { ...@@ -47,13 +47,15 @@ struct pinconf_ops {
unsigned long *config); unsigned long *config);
int (*pin_config_set) (struct pinctrl_dev *pctldev, int (*pin_config_set) (struct pinctrl_dev *pctldev,
unsigned pin, unsigned pin,
unsigned long config); unsigned long *configs,
unsigned num_configs);
int (*pin_config_group_get) (struct pinctrl_dev *pctldev, int (*pin_config_group_get) (struct pinctrl_dev *pctldev,
unsigned selector, unsigned selector,
unsigned long *config); unsigned long *config);
int (*pin_config_group_set) (struct pinctrl_dev *pctldev, int (*pin_config_group_set) (struct pinctrl_dev *pctldev,
unsigned selector, unsigned selector,
unsigned long config); unsigned long *configs,
unsigned num_configs);
int (*pin_config_dbg_parse_modify) (struct pinctrl_dev *pctldev, int (*pin_config_dbg_parse_modify) (struct pinctrl_dev *pctldev,
const char *arg, const char *arg,
unsigned long *config); unsigned long *config);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment