in nomadik/pinctrl-abx500.c [239:357]
static int abx500_set_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
unsigned gpio, int alt_setting)
{
struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
struct alternate_functions af = pct->soc->alternate_functions[gpio];
int ret;
int val;
unsigned offset;
const char *modes[] = {
[ABX500_DEFAULT] = "default",
[ABX500_ALT_A] = "altA",
[ABX500_ALT_B] = "altB",
[ABX500_ALT_C] = "altC",
};
/* sanity check */
if (((alt_setting == ABX500_ALT_A) && (af.gpiosel_bit == UNUSED)) ||
((alt_setting == ABX500_ALT_B) && (af.alt_bit1 == UNUSED)) ||
((alt_setting == ABX500_ALT_C) && (af.alt_bit2 == UNUSED))) {
dev_dbg(pct->dev, "pin %d doesn't support %s mode\n", gpio,
modes[alt_setting]);
return -EINVAL;
}
/* on ABx5xx, there is no GPIO0, so adjust the offset */
offset = gpio - 1;
switch (alt_setting) {
case ABX500_DEFAULT:
/*
* for ABx5xx family, default mode is always selected by
* writing 0 to GPIOSELx register, except for pins which
* support at least ALT_B mode, default mode is selected
* by writing 1 to GPIOSELx register
*/
val = 0;
if (af.alt_bit1 != UNUSED)
val++;
ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
offset, val);
break;
case ABX500_ALT_A:
/*
* for ABx5xx family, alt_a mode is always selected by
* writing 1 to GPIOSELx register, except for pins which
* support at least ALT_B mode, alt_a mode is selected
* by writing 0 to GPIOSELx register and 0 in ALTFUNC
* register
*/
if (af.alt_bit1 != UNUSED) {
ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
offset, 0);
if (ret < 0)
goto out;
ret = abx500_gpio_set_bits(chip,
AB8500_GPIO_ALTFUN_REG,
af.alt_bit1,
!!(af.alta_val & BIT(0)));
if (ret < 0)
goto out;
if (af.alt_bit2 != UNUSED)
ret = abx500_gpio_set_bits(chip,
AB8500_GPIO_ALTFUN_REG,
af.alt_bit2,
!!(af.alta_val & BIT(1)));
} else
ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
offset, 1);
break;
case ABX500_ALT_B:
ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
offset, 0);
if (ret < 0)
goto out;
ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG,
af.alt_bit1, !!(af.altb_val & BIT(0)));
if (ret < 0)
goto out;
if (af.alt_bit2 != UNUSED)
ret = abx500_gpio_set_bits(chip,
AB8500_GPIO_ALTFUN_REG,
af.alt_bit2,
!!(af.altb_val & BIT(1)));
break;
case ABX500_ALT_C:
ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
offset, 0);
if (ret < 0)
goto out;
ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG,
af.alt_bit2, !!(af.altc_val & BIT(0)));
if (ret < 0)
goto out;
ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG,
af.alt_bit2, !!(af.altc_val & BIT(1)));
break;
default:
dev_dbg(pct->dev, "unknown alt_setting %d\n", alt_setting);
return -EINVAL;
}
out:
if (ret < 0)
dev_err(pct->dev, "%s failed (%d)\n", __func__, ret);
return ret;
}