in sprd/pinctrl-sprd.c [590:739]
static int sprd_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin_id,
unsigned long *configs, unsigned int num_configs)
{
struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
struct sprd_pin *pin = sprd_pinctrl_get_pin_by_id(pctl, pin_id);
bool is_sleep_config;
unsigned long reg;
int i;
if (!pin)
return -EINVAL;
is_sleep_config = sprd_pinctrl_check_sleep_config(configs, num_configs);
for (i = 0; i < num_configs; i++) {
unsigned int param, arg, shift, mask, val;
param = pinconf_to_config_param(configs[i]);
arg = pinconf_to_config_argument(configs[i]);
val = 0;
shift = 0;
mask = 0;
if (pin->type == GLOBAL_CTRL_PIN &&
param == SPRD_PIN_CONFIG_CONTROL) {
val = arg;
} else if (pin->type == COMMON_PIN || pin->type == MISC_PIN) {
switch (param) {
case SPRD_PIN_CONFIG_SLEEP_MODE:
if (arg & AP_SLEEP)
val |= AP_SLEEP_MODE;
if (arg & PUBCP_SLEEP)
val |= PUBCP_SLEEP_MODE;
if (arg & TGLDSP_SLEEP)
val |= TGLDSP_SLEEP_MODE;
if (arg & AGDSP_SLEEP)
val |= AGDSP_SLEEP_MODE;
if (arg & CM4_SLEEP)
val |= CM4_SLEEP_MODE;
mask = SLEEP_MODE_MASK;
shift = SLEEP_MODE_SHIFT;
break;
case PIN_CONFIG_INPUT_ENABLE:
if (is_sleep_config == true) {
if (arg > 0)
val |= SLEEP_INPUT;
else
val &= ~SLEEP_INPUT;
mask = SLEEP_INPUT_MASK;
shift = SLEEP_INPUT_SHIFT;
}
break;
case PIN_CONFIG_OUTPUT_ENABLE:
if (is_sleep_config == true) {
if (arg > 0)
val |= SLEEP_OUTPUT;
else
val &= ~SLEEP_OUTPUT;
mask = SLEEP_OUTPUT_MASK;
shift = SLEEP_OUTPUT_SHIFT;
}
break;
case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
if (is_sleep_config == true) {
val = shift = 0;
mask = SLEEP_OUTPUT | SLEEP_INPUT;
}
break;
case PIN_CONFIG_DRIVE_STRENGTH:
if (arg < 2 || arg > 60)
return -EINVAL;
val = sprd_pinconf_drive(arg);
mask = DRIVE_STRENGTH_MASK;
shift = DRIVE_STRENGTH_SHIFT;
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
if (is_sleep_config == true) {
val |= SLEEP_PULL_DOWN;
mask = SLEEP_PULL_DOWN_MASK;
shift = SLEEP_PULL_DOWN_SHIFT;
} else {
val |= PULL_DOWN;
mask = PULL_DOWN_MASK;
shift = PULL_DOWN_SHIFT;
}
break;
case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
if (arg > 0)
val |= INPUT_SCHMITT;
else
val &= ~INPUT_SCHMITT;
mask = INPUT_SCHMITT_MASK;
shift = INPUT_SCHMITT_SHIFT;
break;
case PIN_CONFIG_BIAS_PULL_UP:
if (is_sleep_config) {
val |= SLEEP_PULL_UP;
mask = SLEEP_PULL_UP_MASK;
shift = SLEEP_PULL_UP_SHIFT;
} else {
if (arg == 20000)
val |= PULL_UP_20K;
else if (arg == 4700)
val |= PULL_UP_4_7K;
mask = PULL_UP_MASK;
shift = PULL_UP_SHIFT;
}
break;
case PIN_CONFIG_BIAS_DISABLE:
if (is_sleep_config == true) {
val = shift = 0;
mask = SLEEP_PULL_DOWN | SLEEP_PULL_UP;
} else {
val = shift = 0;
mask = PULL_DOWN | PULL_UP_20K |
PULL_UP_4_7K;
}
break;
case PIN_CONFIG_SLEEP_HARDWARE_STATE:
continue;
default:
return -ENOTSUPP;
}
} else {
return -ENOTSUPP;
}
if (pin->type == GLOBAL_CTRL_PIN) {
reg = readl((void __iomem *)pin->reg);
reg &= ~(PINCTRL_BIT_MASK(pin->bit_width)
<< pin->bit_offset);
reg |= (val & PINCTRL_BIT_MASK(pin->bit_width))
<< pin->bit_offset;
writel(reg, (void __iomem *)pin->reg);
} else {
reg = readl((void __iomem *)pin->reg);
reg &= ~(mask << shift);
reg |= val;
writel(reg, (void __iomem *)pin->reg);
}
}
return 0;
}