static int sprd_pinconf_set()

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;
}