Commit 84e769e6 authored by Linus Walleij's avatar Linus Walleij
Browse files

Merge tag 'renesas-pinctrl-for-v6.8-tag2' of...

Merge tag 'renesas-pinctrl-for-v6.8-tag2' of git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers

 into devel

pinctrl: renesas: Updates for v6.8 (take two)

  - Add pinmux groups, power source, and input/output enable support for
    Ethernet pins on RZ/G2L SoCs,
  - Miscellaneous fixes and improvements.

Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parents 2ddb7c42 9e5889c6
Loading
Loading
Loading
Loading
+145 −19
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@
#define PIN_CFG_FILCLKSEL		BIT(12)
#define PIN_CFG_IOLH_C			BIT(13)
#define PIN_CFG_SOFT_PS			BIT(14)
#define PIN_CFG_OEN			BIT(15)

#define RZG2L_MPXED_COMMON_PIN_FUNCS(group) \
					(PIN_CFG_IOLH_##group | \
@@ -107,8 +108,11 @@
#define IEN(off)		(0x1800 + (off) * 8)
#define ISEL(off)		(0x2C00 + (off) * 8)
#define SD_CH(off, ch)		((off) + (ch) * 4)
#define ETH_POC(off, ch)	((off) + (ch) * 4)
#define QSPI			(0x3008)
#define ETH_MODE		(0x3018)

#define PVDD_2500		2	/* I/O domain voltage 2.5V */
#define PVDD_1800		1	/* I/O domain voltage <= 1.8V */
#define PVDD_3300		0	/* I/O domain voltage >= 3.3V */

@@ -116,7 +120,6 @@
#define PWPR_PFCWE		BIT(6)	/* PFC Register Write Enable */

#define PM_MASK			0x03
#define PVDD_MASK		0x01
#define PFC_MASK		0x07
#define IEN_MASK		0x01
#define IOLH_MASK		0x03
@@ -135,10 +138,12 @@
 * struct rzg2l_register_offsets - specific register offsets
 * @pwpr: PWPR register offset
 * @sd_ch: SD_CH register offset
 * @eth_poc: ETH_POC register offset
 */
struct rzg2l_register_offsets {
	u16 pwpr;
	u16 sd_ch;
	u16 eth_poc;
};

/**
@@ -167,6 +172,8 @@ enum rzg2l_iolh_index {
 * @iolh_groupb_oi: IOLH group B output impedance specific values
 * @drive_strength_ua: drive strength in uA is supported (otherwise mA is supported)
 * @func_base: base number for port function (see register PFC)
 * @oen_max_pin: the maximum pin number supporting output enable
 * @oen_max_port: the maximum port number supporting output enable
 */
struct rzg2l_hwcfg {
	const struct rzg2l_register_offsets regs;
@@ -176,6 +183,8 @@ struct rzg2l_hwcfg {
	u16 iolh_groupb_oi[4];
	bool drive_strength_ua;
	u8 func_base;
	u8 oen_max_pin;
	u8 oen_max_port;
};

struct rzg2l_dedicated_configs {
@@ -376,8 +385,11 @@ static int rzg2l_dt_subnode_to_map(struct pinctrl_dev *pctldev,
		goto done;
	}

	if (num_pinmux)
	if (num_pinmux) {
		nmaps += 1;
		if (num_configs)
			nmaps += 1;
	}

	if (num_pins)
		nmaps += num_pins;
@@ -462,6 +474,16 @@ static int rzg2l_dt_subnode_to_map(struct pinctrl_dev *pctldev,
	maps[idx].data.mux.function = name;
	idx++;

	if (num_configs) {
		ret = rzg2l_map_add_config(&maps[idx], name,
					   PIN_MAP_TYPE_CONFIGS_GROUP,
					   configs, num_configs);
		if (ret < 0)
			goto remove_group;

		idx++;
	}

	dev_dbg(pctrl->dev, "Parsed %pOF with %d pins\n", np, num_pinmux);
	ret = 0;
	goto done;
@@ -591,6 +613,10 @@ static int rzg2l_caps_to_pwr_reg(const struct rzg2l_register_offsets *regs, u32
		return SD_CH(regs->sd_ch, 0);
	if (caps & PIN_CFG_IO_VMC_SD1)
		return SD_CH(regs->sd_ch, 1);
	if (caps & PIN_CFG_IO_VMC_ETH0)
		return ETH_POC(regs->eth_poc, 0);
	if (caps & PIN_CFG_IO_VMC_ETH1)
		return ETH_POC(regs->eth_poc, 1);
	if (caps & PIN_CFG_IO_VMC_QSPI)
		return QSPI;

@@ -602,6 +628,7 @@ static int rzg2l_get_power_source(struct rzg2l_pinctrl *pctrl, u32 pin, u32 caps
	const struct rzg2l_hwcfg *hwcfg = pctrl->data->hwcfg;
	const struct rzg2l_register_offsets *regs = &hwcfg->regs;
	int pwr_reg;
	u8 val;

	if (caps & PIN_CFG_SOFT_PS)
		return pctrl->settings[pin].power_source;
@@ -610,7 +637,18 @@ static int rzg2l_get_power_source(struct rzg2l_pinctrl *pctrl, u32 pin, u32 caps
	if (pwr_reg < 0)
		return pwr_reg;

	return (readl(pctrl->base + pwr_reg) & PVDD_MASK) ? 1800 : 3300;
	val = readb(pctrl->base + pwr_reg);
	switch (val) {
	case PVDD_1800:
		return 1800;
	case PVDD_2500:
		return 2500;
	case PVDD_3300:
		return 3300;
	default:
		/* Should not happen. */
		return -EINVAL;
	}
}

static int rzg2l_set_power_source(struct rzg2l_pinctrl *pctrl, u32 pin, u32 caps, u32 ps)
@@ -618,17 +656,32 @@ static int rzg2l_set_power_source(struct rzg2l_pinctrl *pctrl, u32 pin, u32 caps
	const struct rzg2l_hwcfg *hwcfg = pctrl->data->hwcfg;
	const struct rzg2l_register_offsets *regs = &hwcfg->regs;
	int pwr_reg;
	u8 val;

	if (caps & PIN_CFG_SOFT_PS) {
		pctrl->settings[pin].power_source = ps;
		return 0;
	}

	switch (ps) {
	case 1800:
		val = PVDD_1800;
		break;
	case 2500:
		val = PVDD_2500;
		break;
	case 3300:
		val = PVDD_3300;
		break;
	default:
		return -EINVAL;
	}

	pwr_reg = rzg2l_caps_to_pwr_reg(regs, caps);
	if (pwr_reg < 0)
		return pwr_reg;

	writel((ps == 1800) ? PVDD_1800 : PVDD_3300, pctrl->base + pwr_reg);
	writeb(val, pctrl->base + pwr_reg);
	pctrl->settings[pin].power_source = ps;

	return 0;
@@ -735,6 +788,66 @@ static bool rzg2l_ds_is_supported(struct rzg2l_pinctrl *pctrl, u32 caps,
	return false;
}

static bool rzg2l_oen_is_supported(u32 caps, u8 pin, u8 max_pin)
{
	if (!(caps & PIN_CFG_OEN))
		return false;

	if (pin > max_pin)
		return false;

	return true;
}

static u8 rzg2l_pin_to_oen_bit(u32 offset, u8 pin, u8 max_port)
{
	if (pin)
		pin *= 2;

	if (offset / RZG2L_PINS_PER_PORT == max_port)
		pin += 1;

	return pin;
}

static u32 rzg2l_read_oen(struct rzg2l_pinctrl *pctrl, u32 caps, u32 offset, u8 pin)
{
	u8 max_port = pctrl->data->hwcfg->oen_max_port;
	u8 max_pin = pctrl->data->hwcfg->oen_max_pin;
	u8 bit;

	if (!rzg2l_oen_is_supported(caps, pin, max_pin))
		return 0;

	bit = rzg2l_pin_to_oen_bit(offset, pin, max_port);

	return !(readb(pctrl->base + ETH_MODE) & BIT(bit));
}

static int rzg2l_write_oen(struct rzg2l_pinctrl *pctrl, u32 caps, u32 offset, u8 pin, u8 oen)
{
	u8 max_port = pctrl->data->hwcfg->oen_max_port;
	u8 max_pin = pctrl->data->hwcfg->oen_max_pin;
	unsigned long flags;
	u8 val, bit;

	if (!rzg2l_oen_is_supported(caps, pin, max_pin))
		return -EINVAL;

	bit = rzg2l_pin_to_oen_bit(offset, pin, max_port);

	spin_lock_irqsave(&pctrl->lock, flags);
	val = readb(pctrl->base + ETH_MODE);
	if (oen)
		val &= ~BIT(bit);
	else
		val |= BIT(bit);
	writeb(val, pctrl->base + ETH_MODE);
	spin_unlock_irqrestore(&pctrl->lock, flags);

	return 0;
}

static int rzg2l_pinctrl_pinconf_get(struct pinctrl_dev *pctldev,
				     unsigned int _pin,
				     unsigned long *config)
@@ -772,6 +885,12 @@ static int rzg2l_pinctrl_pinconf_get(struct pinctrl_dev *pctldev,
			return -EINVAL;
		break;

	case PIN_CONFIG_OUTPUT_ENABLE:
		arg = rzg2l_read_oen(pctrl, cfg, _pin, bit);
		if (!arg)
			return -EINVAL;
		break;

	case PIN_CONFIG_POWER_SOURCE:
		ret = rzg2l_get_power_source(pctrl, _pin, cfg);
		if (ret < 0)
@@ -842,7 +961,7 @@ static int rzg2l_pinctrl_pinconf_set(struct pinctrl_dev *pctldev,
	struct rzg2l_pinctrl_pin_settings settings = pctrl->settings[_pin];
	unsigned int *pin_data = pin->drv_data;
	enum pin_config_param param;
	unsigned int i;
	unsigned int i, arg, index;
	u32 cfg, off;
	int ret;
	u8 bit;
@@ -864,24 +983,28 @@ static int rzg2l_pinctrl_pinconf_set(struct pinctrl_dev *pctldev,
	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]);
		case PIN_CONFIG_INPUT_ENABLE:
			arg = pinconf_to_config_argument(_configs[i]);

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

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

		case PIN_CONFIG_OUTPUT_ENABLE:
			arg = pinconf_to_config_argument(_configs[i]);
			ret = rzg2l_write_oen(pctrl, cfg, _pin, bit, !!arg);
			if (ret)
				return ret;
			break;

		case PIN_CONFIG_POWER_SOURCE:
			settings.power_source = pinconf_to_config_argument(_configs[i]);
			break;

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

			if (!(cfg & PIN_CFG_IOLH_A) || hwcfg->drive_strength_ua)
				return -EINVAL;
@@ -896,7 +1019,6 @@ static int rzg2l_pinctrl_pinconf_set(struct pinctrl_dev *pctldev,

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

		case PIN_CONFIG_DRIVE_STRENGTH_UA:
			if (!(cfg & (PIN_CFG_IOLH_A | PIN_CFG_IOLH_B | PIN_CFG_IOLH_C)) ||
@@ -906,9 +1028,8 @@ static int rzg2l_pinctrl_pinconf_set(struct pinctrl_dev *pctldev,
			settings.drive_strength_ua = pinconf_to_config_argument(_configs[i]);
			break;

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

			if (!(cfg & PIN_CFG_IOLH_B) || !hwcfg->iolh_groupb_oi[0])
				return -EINVAL;
@@ -922,7 +1043,6 @@ static int rzg2l_pinctrl_pinconf_set(struct pinctrl_dev *pctldev,

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

		default:
			return -EOPNOTSUPP;
@@ -1323,7 +1443,8 @@ static const u32 r9a07g043_gpio_configs[] = {
static const u32 r9a08g045_gpio_configs[] = {
	RZG2L_GPIO_PORT_PACK(4, 0x20, RZG3S_MPXED_PIN_FUNCS(A)),			/* P0  */
	RZG2L_GPIO_PORT_PACK(5, 0x30, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IOLH_C |
								PIN_CFG_IO_VMC_ETH0)),	/* P1 */
								PIN_CFG_IO_VMC_ETH0)) |
				      PIN_CFG_OEN | PIN_CFG_IEN,			/* P1 */
	RZG2L_GPIO_PORT_PACK(4, 0x31, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IOLH_C |
								PIN_CFG_IO_VMC_ETH0)),	/* P2 */
	RZG2L_GPIO_PORT_PACK(4, 0x32, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IOLH_C |
@@ -1333,7 +1454,8 @@ static const u32 r9a08g045_gpio_configs[] = {
	RZG2L_GPIO_PORT_PACK(5, 0x21, RZG3S_MPXED_PIN_FUNCS(A)),			/* P5  */
	RZG2L_GPIO_PORT_PACK(5, 0x22, RZG3S_MPXED_PIN_FUNCS(A)),			/* P6  */
	RZG2L_GPIO_PORT_PACK(5, 0x34, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IOLH_C |
								PIN_CFG_IO_VMC_ETH1)),	/* P7 */
								PIN_CFG_IO_VMC_ETH1)) |
				      PIN_CFG_OEN | PIN_CFG_IEN,			/* P7 */
	RZG2L_GPIO_PORT_PACK(5, 0x35, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IOLH_C |
								PIN_CFG_IO_VMC_ETH1)),	/* P8 */
	RZG2L_GPIO_PORT_PACK(4, 0x36, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IOLH_C |
@@ -1878,6 +2000,7 @@ static const struct rzg2l_hwcfg rzg2l_hwcfg = {
	.regs = {
		.pwpr = 0x3014,
		.sd_ch = 0x3000,
		.eth_poc = 0x300c,
	},
	.iolh_groupa_ua = {
		/* 3v3 power source */
@@ -1890,6 +2013,7 @@ static const struct rzg2l_hwcfg rzg3s_hwcfg = {
	.regs = {
		.pwpr = 0x3000,
		.sd_ch = 0x3004,
		.eth_poc = 0x3010,
	},
	.iolh_groupa_ua = {
		/* 1v8 power source */
@@ -1913,6 +2037,8 @@ static const struct rzg2l_hwcfg rzg3s_hwcfg = {
	},
	.drive_strength_ua = true,
	.func_base = 1,
	.oen_max_pin = 1, /* Pin 1 of P0 and P7 is the maximum OEN pin. */
	.oen_max_port = 7, /* P7_1 is the maximum OEN port. */
};

static struct rzg2l_pinctrl_data r9a07g043_data = {