static int rzg2l_pinctrl_pinconf_set()

in renesas/pinctrl-rzg2l.c [572:683]


static int rzg2l_pinctrl_pinconf_set(struct pinctrl_dev *pctldev,
				     unsigned int _pin,
				     unsigned long *_configs,
				     unsigned int num_configs)
{
	struct rzg2l_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
	const struct pinctrl_pin_desc *pin = &pctrl->desc.pins[_pin];
	unsigned int *pin_data = pin->drv_data;
	enum pin_config_param param;
	unsigned long flags;
	void __iomem *addr;
	u32 port_offset;
	unsigned int i;
	u32 cfg = 0;
	u8 bit = 0;

	if (!pin_data)
		return -EINVAL;

	if (*pin_data & RZG2L_SINGLE_PIN) {
		port_offset = RZG2L_SINGLE_PIN_GET_PORT_OFFSET(*pin_data);
		cfg = RZG2L_SINGLE_PIN_GET_CFGS(*pin_data);
		bit = RZG2L_SINGLE_PIN_GET_BIT(*pin_data);
	} else {
		cfg = RZG2L_GPIO_PORT_GET_CFGS(*pin_data);
		port_offset = RZG2L_PIN_ID_TO_PORT_OFFSET(_pin);
		bit = RZG2L_PIN_ID_TO_PIN(_pin);

		if (rzg2l_validate_gpio_pin(pctrl, *pin_data, RZG2L_PIN_ID_TO_PORT(_pin), bit))
			return -EINVAL;
	}

	for (i = 0; i < num_configs; i++) {
		param = pinconf_to_config_param(_configs[i]);
		switch (param) {
		case PIN_CONFIG_INPUT_ENABLE: {
			unsigned int arg =
					pinconf_to_config_argument(_configs[i]);

			if (!(cfg & PIN_CFG_IEN))
				return -EINVAL;

			rzg2l_rmw_pin_config(pctrl, IEN(port_offset), bit, IEN_MASK, !!arg);
			break;
		}

		case PIN_CONFIG_POWER_SOURCE: {
			unsigned int mV = pinconf_to_config_argument(_configs[i]);
			u32 pwr_reg = 0x0;

			if (mV != 1800 && mV != 3300)
				return -EINVAL;

			if (cfg & PIN_CFG_IO_VMC_SD0)
				pwr_reg = SD_CH(0);
			else if (cfg & PIN_CFG_IO_VMC_SD1)
				pwr_reg = SD_CH(1);
			else if (cfg & PIN_CFG_IO_VMC_QSPI)
				pwr_reg = QSPI;
			else
				return -EINVAL;

			addr = pctrl->base + pwr_reg;
			spin_lock_irqsave(&pctrl->lock, flags);
			writel((mV == 1800) ? PVDD_1800 : PVDD_3300, addr);
			spin_unlock_irqrestore(&pctrl->lock, flags);
			break;
		}

		case PIN_CONFIG_DRIVE_STRENGTH: {
			unsigned int arg = pinconf_to_config_argument(_configs[i]);
			unsigned int index;

			if (!(cfg & PIN_CFG_IOLH_A))
				return -EINVAL;

			for (index = 0; index < ARRAY_SIZE(iolh_groupa_mA); index++) {
				if (arg == iolh_groupa_mA[index])
					break;
			}
			if (index >= ARRAY_SIZE(iolh_groupa_mA))
				return -EINVAL;

			rzg2l_rmw_pin_config(pctrl, IOLH(port_offset), bit, IOLH_MASK, index);
			break;
		}

		case PIN_CONFIG_OUTPUT_IMPEDANCE_OHMS: {
			unsigned int arg = pinconf_to_config_argument(_configs[i]);
			unsigned int index;

			if (!(cfg & PIN_CFG_IOLH_B))
				return -EINVAL;

			for (index = 0; index < ARRAY_SIZE(iolh_groupb_oi); index++) {
				if (arg == iolh_groupb_oi[index])
					break;
			}
			if (index >= ARRAY_SIZE(iolh_groupb_oi))
				return -EINVAL;

			rzg2l_rmw_pin_config(pctrl, IOLH(port_offset), bit, IOLH_MASK, index);
			break;
		}

		default:
			return -EOPNOTSUPP;
		}
	}

	return 0;
}