in pinctrl-at91-pio4.c [791:903]
static int atmel_conf_pin_config_group_set(struct pinctrl_dev *pctldev,
unsigned int group,
unsigned long *configs,
unsigned int num_configs)
{
struct atmel_pioctrl *atmel_pioctrl = pinctrl_dev_get_drvdata(pctldev);
struct atmel_group *grp = atmel_pioctrl->groups + group;
unsigned int bank, pin, pin_id = grp->pin;
u32 mask, conf = 0;
int i;
conf = atmel_pin_config_read(pctldev, pin_id);
/* Keep slew rate enabled by default. */
if (atmel_pioctrl->slew_rate_support)
conf |= ATMEL_PIO_SR_MASK;
for (i = 0; i < num_configs; i++) {
unsigned int param = pinconf_to_config_param(configs[i]);
unsigned int arg = pinconf_to_config_argument(configs[i]);
dev_dbg(pctldev->dev, "%s: pin=%u, config=0x%lx\n",
__func__, pin_id, configs[i]);
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
conf &= (~ATMEL_PIO_PUEN_MASK);
conf &= (~ATMEL_PIO_PDEN_MASK);
break;
case PIN_CONFIG_BIAS_PULL_UP:
conf |= ATMEL_PIO_PUEN_MASK;
conf &= (~ATMEL_PIO_PDEN_MASK);
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
conf |= ATMEL_PIO_PDEN_MASK;
conf &= (~ATMEL_PIO_PUEN_MASK);
break;
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
if (arg == 0)
conf &= (~ATMEL_PIO_OPD_MASK);
else
conf |= ATMEL_PIO_OPD_MASK;
break;
case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
if (arg == 0)
conf |= ATMEL_PIO_SCHMITT_MASK;
else
conf &= (~ATMEL_PIO_SCHMITT_MASK);
break;
case PIN_CONFIG_INPUT_DEBOUNCE:
if (arg == 0) {
conf &= (~ATMEL_PIO_IFEN_MASK);
conf &= (~ATMEL_PIO_IFSCEN_MASK);
} else {
/*
* We don't care about the debounce value for several reasons:
* - can't have different debounce periods inside a same group,
* - the register to configure this period is a secure register.
* The debouncing filter can filter a pulse with a duration of less
* than 1/2 slow clock period.
*/
conf |= ATMEL_PIO_IFEN_MASK;
conf |= ATMEL_PIO_IFSCEN_MASK;
}
break;
case PIN_CONFIG_OUTPUT:
conf |= ATMEL_PIO_DIR_MASK;
bank = ATMEL_PIO_BANK(pin_id);
pin = ATMEL_PIO_LINE(pin_id);
mask = 1 << pin;
if (arg == 0) {
writel_relaxed(mask, atmel_pioctrl->reg_base +
bank * ATMEL_PIO_BANK_OFFSET +
ATMEL_PIO_CODR);
} else {
writel_relaxed(mask, atmel_pioctrl->reg_base +
bank * ATMEL_PIO_BANK_OFFSET +
ATMEL_PIO_SODR);
}
break;
case PIN_CONFIG_SLEW_RATE:
if (!atmel_pioctrl->slew_rate_support)
break;
/* And remove it if explicitly requested. */
if (arg == 0)
conf &= ~ATMEL_PIO_SR_MASK;
break;
case ATMEL_PIN_CONFIG_DRIVE_STRENGTH:
switch (arg) {
case ATMEL_PIO_DRVSTR_LO:
case ATMEL_PIO_DRVSTR_ME:
case ATMEL_PIO_DRVSTR_HI:
conf &= (~ATMEL_PIO_DRVSTR_MASK);
conf |= arg << ATMEL_PIO_DRVSTR_OFFSET;
break;
default:
dev_warn(pctldev->dev, "drive strength not updated (incorrect value)\n");
}
break;
default:
dev_warn(pctldev->dev,
"unsupported configuration parameter: %u\n",
param);
continue;
}
}
dev_dbg(pctldev->dev, "%s: reg=0x%08x\n", __func__, conf);
atmel_pin_config_write(pctldev, pin_id, conf);
return 0;
}