summaryrefslogtreecommitdiffstats
path: root/drivers/pinctrl/renesas/pinctrl-rzg2l.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pinctrl/renesas/pinctrl-rzg2l.c')
-rw-r--r--drivers/pinctrl/renesas/pinctrl-rzg2l.c718
1 files changed, 562 insertions, 156 deletions
diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
index 2ea6ef99cc..9de350ad7e 100644
--- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c
+++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
@@ -55,14 +55,22 @@
#define PIN_CFG_FILONOFF BIT(10)
#define PIN_CFG_FILNUM BIT(11)
#define PIN_CFG_FILCLKSEL BIT(12)
+#define PIN_CFG_IOLH_C BIT(13)
+#define PIN_CFG_SOFT_PS BIT(14)
-#define RZG2L_MPXED_PIN_FUNCS (PIN_CFG_IOLH_A | \
- PIN_CFG_SR | \
+#define RZG2L_MPXED_COMMON_PIN_FUNCS(group) \
+ (PIN_CFG_IOLH_##group | \
PIN_CFG_PUPD | \
PIN_CFG_FILONOFF | \
PIN_CFG_FILNUM | \
PIN_CFG_FILCLKSEL)
+#define RZG2L_MPXED_PIN_FUNCS (RZG2L_MPXED_COMMON_PIN_FUNCS(A) | \
+ PIN_CFG_SR)
+
+#define RZG3S_MPXED_PIN_FUNCS(group) (RZG2L_MPXED_COMMON_PIN_FUNCS(group) | \
+ PIN_CFG_SOFT_PS)
+
#define RZG2L_MPXED_ETH_PIN_FUNCS(x) ((x) | \
PIN_CFG_FILONOFF | \
PIN_CFG_FILNUM | \
@@ -74,8 +82,6 @@
*/
#define RZG2L_GPIO_PORT_PACK(n, a, f) (((n) << 28) | ((a) << 20) | (f))
#define RZG2L_GPIO_PORT_GET_PINCNT(x) (((x) & GENMASK(30, 28)) >> 28)
-#define RZG2L_GPIO_PORT_GET_INDEX(x) (((x) & GENMASK(26, 20)) >> 20)
-#define RZG2L_GPIO_PORT_GET_CFGS(x) ((x) & GENMASK(19, 0))
/*
* BIT(31) indicates dedicated pin, p is the register index while
@@ -85,20 +91,22 @@
#define RZG2L_SINGLE_PIN BIT(31)
#define RZG2L_SINGLE_PIN_PACK(p, b, f) (RZG2L_SINGLE_PIN | \
((p) << 24) | ((b) << 20) | (f))
-#define RZG2L_SINGLE_PIN_GET_PORT_OFFSET(x) (((x) & GENMASK(30, 24)) >> 24)
#define RZG2L_SINGLE_PIN_GET_BIT(x) (((x) & GENMASK(22, 20)) >> 20)
-#define RZG2L_SINGLE_PIN_GET_CFGS(x) ((x) & GENMASK(19, 0))
-
-#define P(n) (0x0000 + 0x10 + (n))
-#define PM(n) (0x0100 + 0x20 + (n) * 2)
-#define PMC(n) (0x0200 + 0x10 + (n))
-#define PFC(n) (0x0400 + 0x40 + (n) * 4)
-#define PIN(n) (0x0800 + 0x10 + (n))
-#define IOLH(n) (0x1000 + (n) * 8)
-#define IEN(n) (0x1800 + (n) * 8)
-#define ISEL(n) (0x2c80 + (n) * 8)
-#define PWPR (0x3014)
-#define SD_CH(n) (0x3000 + (n) * 4)
+
+#define RZG2L_PIN_CFG_TO_CAPS(cfg) ((cfg) & GENMASK(19, 0))
+#define RZG2L_PIN_CFG_TO_PORT_OFFSET(cfg) ((cfg) & RZG2L_SINGLE_PIN ? \
+ (((cfg) & GENMASK(30, 24)) >> 24) : \
+ (((cfg) & GENMASK(26, 20)) >> 20))
+
+#define P(off) (0x0000 + (off))
+#define PM(off) (0x0100 + (off) * 2)
+#define PMC(off) (0x0200 + (off))
+#define PFC(off) (0x0400 + (off) * 4)
+#define PIN(off) (0x0800 + (off))
+#define IOLH(off) (0x1000 + (off) * 8)
+#define IEN(off) (0x1800 + (off) * 8)
+#define ISEL(off) (0x2C00 + (off) * 8)
+#define SD_CH(off, ch) ((off) + (ch) * 4)
#define QSPI (0x3008)
#define PVDD_1800 1 /* I/O domain voltage <= 1.8V */
@@ -117,13 +125,59 @@
#define PM_OUTPUT 0x2
#define RZG2L_PIN_ID_TO_PORT(id) ((id) / RZG2L_PINS_PER_PORT)
-#define RZG2L_PIN_ID_TO_PORT_OFFSET(id) (RZG2L_PIN_ID_TO_PORT(id) + 0x10)
#define RZG2L_PIN_ID_TO_PIN(id) ((id) % RZG2L_PINS_PER_PORT)
#define RZG2L_TINT_MAX_INTERRUPT 32
#define RZG2L_TINT_IRQ_START_INDEX 9
#define RZG2L_PACK_HWIRQ(t, i) (((t) << 16) | (i))
+/**
+ * struct rzg2l_register_offsets - specific register offsets
+ * @pwpr: PWPR register offset
+ * @sd_ch: SD_CH register offset
+ */
+struct rzg2l_register_offsets {
+ u16 pwpr;
+ u16 sd_ch;
+};
+
+/**
+ * enum rzg2l_iolh_index - starting indices in IOLH specific arrays
+ * @RZG2L_IOLH_IDX_1V8: starting index for 1V8 power source
+ * @RZG2L_IOLH_IDX_2V5: starting index for 2V5 power source
+ * @RZG2L_IOLH_IDX_3V3: starting index for 3V3 power source
+ * @RZG2L_IOLH_IDX_MAX: maximum index
+ */
+enum rzg2l_iolh_index {
+ RZG2L_IOLH_IDX_1V8 = 0,
+ RZG2L_IOLH_IDX_2V5 = 4,
+ RZG2L_IOLH_IDX_3V3 = 8,
+ RZG2L_IOLH_IDX_MAX = 12,
+};
+
+/* Maximum number of driver strength entries per power source. */
+#define RZG2L_IOLH_MAX_DS_ENTRIES (4)
+
+/**
+ * struct rzg2l_hwcfg - hardware configuration data structure
+ * @regs: hardware specific register offsets
+ * @iolh_groupa_ua: IOLH group A uA specific values
+ * @iolh_groupb_ua: IOLH group B uA specific values
+ * @iolh_groupc_ua: IOLH group C uA specific values
+ * @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)
+ */
+struct rzg2l_hwcfg {
+ const struct rzg2l_register_offsets regs;
+ u16 iolh_groupa_ua[RZG2L_IOLH_IDX_MAX];
+ u16 iolh_groupb_ua[RZG2L_IOLH_IDX_MAX];
+ u16 iolh_groupc_ua[RZG2L_IOLH_IDX_MAX];
+ u16 iolh_groupb_oi[4];
+ bool drive_strength_ua;
+ u8 func_base;
+};
+
struct rzg2l_dedicated_configs {
const char *name;
u32 config;
@@ -133,9 +187,20 @@ struct rzg2l_pinctrl_data {
const char * const *port_pins;
const u32 *port_pin_configs;
unsigned int n_ports;
- struct rzg2l_dedicated_configs *dedicated_pins;
+ const struct rzg2l_dedicated_configs *dedicated_pins;
unsigned int n_port_pins;
unsigned int n_dedicated_pins;
+ const struct rzg2l_hwcfg *hwcfg;
+};
+
+/**
+ * struct rzg2l_pinctrl_pin_settings - pin data
+ * @power_source: power source
+ * @drive_strength_ua: drive strength (in micro amps)
+ */
+struct rzg2l_pinctrl_pin_settings {
+ u16 power_source;
+ u16 drive_strength_ua;
};
struct rzg2l_pinctrl {
@@ -155,44 +220,46 @@ struct rzg2l_pinctrl {
spinlock_t lock; /* lock read/write registers */
struct mutex mutex; /* serialize adding groups and functions */
+
+ struct rzg2l_pinctrl_pin_settings *settings;
};
-static const unsigned int iolh_groupa_mA[] = { 2, 4, 8, 12 };
-static const unsigned int iolh_groupb_oi[] = { 100, 66, 50, 33 };
+static const u16 available_ps[] = { 1800, 2500, 3300 };
static void rzg2l_pinctrl_set_pfc_mode(struct rzg2l_pinctrl *pctrl,
- u8 port, u8 pin, u8 func)
+ u8 pin, u8 off, u8 func)
{
+ const struct rzg2l_register_offsets *regs = &pctrl->data->hwcfg->regs;
unsigned long flags;
u32 reg;
spin_lock_irqsave(&pctrl->lock, flags);
/* Set pin to 'Non-use (Hi-Z input protection)' */
- reg = readw(pctrl->base + PM(port));
+ reg = readw(pctrl->base + PM(off));
reg &= ~(PM_MASK << (pin * 2));
- writew(reg, pctrl->base + PM(port));
+ writew(reg, pctrl->base + PM(off));
/* Temporarily switch to GPIO mode with PMC register */
- reg = readb(pctrl->base + PMC(port));
- writeb(reg & ~BIT(pin), pctrl->base + PMC(port));
+ reg = readb(pctrl->base + PMC(off));
+ writeb(reg & ~BIT(pin), pctrl->base + PMC(off));
/* Set the PWPR register to allow PFC register to write */
- writel(0x0, pctrl->base + PWPR); /* B0WI=0, PFCWE=0 */
- writel(PWPR_PFCWE, pctrl->base + PWPR); /* B0WI=0, PFCWE=1 */
+ writel(0x0, pctrl->base + regs->pwpr); /* B0WI=0, PFCWE=0 */
+ writel(PWPR_PFCWE, pctrl->base + regs->pwpr); /* B0WI=0, PFCWE=1 */
/* Select Pin function mode with PFC register */
- reg = readl(pctrl->base + PFC(port));
+ reg = readl(pctrl->base + PFC(off));
reg &= ~(PFC_MASK << (pin * 4));
- writel(reg | (func << (pin * 4)), pctrl->base + PFC(port));
+ writel(reg | (func << (pin * 4)), pctrl->base + PFC(off));
/* Set the PWPR register to be write-protected */
- writel(0x0, pctrl->base + PWPR); /* B0WI=0, PFCWE=0 */
- writel(PWPR_B0WI, pctrl->base + PWPR); /* B0WI=1, PFCWE=0 */
+ writel(0x0, pctrl->base + regs->pwpr); /* B0WI=0, PFCWE=0 */
+ writel(PWPR_B0WI, pctrl->base + regs->pwpr); /* B0WI=1, PFCWE=0 */
/* Switch to Peripheral pin function with PMC register */
- reg = readb(pctrl->base + PMC(port));
- writeb(reg | BIT(pin), pctrl->base + PMC(port));
+ reg = readb(pctrl->base + PMC(off));
+ writeb(reg | BIT(pin), pctrl->base + PMC(off));
spin_unlock_irqrestore(&pctrl->lock, flags);
};
@@ -202,6 +269,7 @@ static int rzg2l_pinctrl_set_mux(struct pinctrl_dev *pctldev,
unsigned int group_selector)
{
struct rzg2l_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ const struct rzg2l_hwcfg *hwcfg = pctrl->data->hwcfg;
struct function_desc *func;
unsigned int i, *psel_val;
struct group_desc *group;
@@ -218,11 +286,14 @@ static int rzg2l_pinctrl_set_mux(struct pinctrl_dev *pctldev,
pins = group->pins;
for (i = 0; i < group->num_pins; i++) {
- dev_dbg(pctrl->dev, "port:%u pin: %u PSEL:%u\n",
- RZG2L_PIN_ID_TO_PORT(pins[i]), RZG2L_PIN_ID_TO_PIN(pins[i]),
- psel_val[i]);
- rzg2l_pinctrl_set_pfc_mode(pctrl, RZG2L_PIN_ID_TO_PORT(pins[i]),
- RZG2L_PIN_ID_TO_PIN(pins[i]), psel_val[i]);
+ unsigned int *pin_data = pctrl->desc.pins[pins[i]].drv_data;
+ u32 off = RZG2L_PIN_CFG_TO_PORT_OFFSET(*pin_data);
+ u32 pin = RZG2L_PIN_ID_TO_PIN(pins[i]);
+
+ dev_dbg(pctrl->dev, "port:%u pin: %u off:%x PSEL:%u\n",
+ RZG2L_PIN_ID_TO_PORT(pins[i]), pin, off, psel_val[i] - hwcfg->func_base);
+
+ rzg2l_pinctrl_set_pfc_mode(pctrl, pin, off, psel_val[i] - hwcfg->func_base);
}
return 0;
@@ -468,14 +539,14 @@ static int rzg2l_validate_gpio_pin(struct rzg2l_pinctrl *pctrl,
u32 cfg, u32 port, u8 bit)
{
u8 pincount = RZG2L_GPIO_PORT_GET_PINCNT(cfg);
- u32 port_index = RZG2L_GPIO_PORT_GET_INDEX(cfg);
+ u32 off = RZG2L_PIN_CFG_TO_PORT_OFFSET(cfg);
u32 data;
if (bit >= pincount || port >= pctrl->data->n_port_pins)
return -EINVAL;
data = pctrl->data->port_pin_configs[port];
- if (port_index != RZG2L_GPIO_PORT_GET_INDEX(data))
+ if (off != RZG2L_PIN_CFG_TO_PORT_OFFSET(data))
return -EINVAL;
return 0;
@@ -514,31 +585,178 @@ static void rzg2l_rmw_pin_config(struct rzg2l_pinctrl *pctrl, u32 offset,
spin_unlock_irqrestore(&pctrl->lock, flags);
}
+static int rzg2l_caps_to_pwr_reg(const struct rzg2l_register_offsets *regs, u32 caps)
+{
+ if (caps & PIN_CFG_IO_VMC_SD0)
+ 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_QSPI)
+ return QSPI;
+
+ return -EINVAL;
+}
+
+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;
+
+ if (caps & PIN_CFG_SOFT_PS)
+ return pctrl->settings[pin].power_source;
+
+ pwr_reg = rzg2l_caps_to_pwr_reg(regs, caps);
+ if (pwr_reg < 0)
+ return pwr_reg;
+
+ return (readl(pctrl->base + pwr_reg) & PVDD_MASK) ? 1800 : 3300;
+}
+
+static int rzg2l_set_power_source(struct rzg2l_pinctrl *pctrl, u32 pin, u32 caps, u32 ps)
+{
+ const struct rzg2l_hwcfg *hwcfg = pctrl->data->hwcfg;
+ const struct rzg2l_register_offsets *regs = &hwcfg->regs;
+ int pwr_reg;
+
+ if (caps & PIN_CFG_SOFT_PS) {
+ pctrl->settings[pin].power_source = ps;
+ return 0;
+ }
+
+ 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);
+ pctrl->settings[pin].power_source = ps;
+
+ return 0;
+}
+
+static bool rzg2l_ps_is_supported(u16 ps)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(available_ps); i++) {
+ if (available_ps[i] == ps)
+ return true;
+ }
+
+ return false;
+}
+
+static enum rzg2l_iolh_index rzg2l_ps_to_iolh_idx(u16 ps)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(available_ps); i++) {
+ if (available_ps[i] == ps)
+ break;
+ }
+
+ /*
+ * We multiply with RZG2L_IOLH_MAX_DS_ENTRIES as we have
+ * RZG2L_IOLH_MAX_DS_ENTRIES DS values per power source
+ */
+ return i * RZG2L_IOLH_MAX_DS_ENTRIES;
+}
+
+static u16 rzg2l_iolh_val_to_ua(const struct rzg2l_hwcfg *hwcfg, u32 caps, u8 val)
+{
+ if (caps & PIN_CFG_IOLH_A)
+ return hwcfg->iolh_groupa_ua[val];
+
+ if (caps & PIN_CFG_IOLH_B)
+ return hwcfg->iolh_groupb_ua[val];
+
+ if (caps & PIN_CFG_IOLH_C)
+ return hwcfg->iolh_groupc_ua[val];
+
+ /* Should not happen. */
+ return 0;
+}
+
+static int rzg2l_iolh_ua_to_val(const struct rzg2l_hwcfg *hwcfg, u32 caps,
+ enum rzg2l_iolh_index ps_index, u16 ua)
+{
+ const u16 *array = NULL;
+ unsigned int i;
+
+ if (caps & PIN_CFG_IOLH_A)
+ array = &hwcfg->iolh_groupa_ua[ps_index];
+
+ if (caps & PIN_CFG_IOLH_B)
+ array = &hwcfg->iolh_groupb_ua[ps_index];
+
+ if (caps & PIN_CFG_IOLH_C)
+ array = &hwcfg->iolh_groupc_ua[ps_index];
+
+ if (!array)
+ return -EINVAL;
+
+ for (i = 0; i < RZG2L_IOLH_MAX_DS_ENTRIES; i++) {
+ if (array[i] == ua)
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+static bool rzg2l_ds_is_supported(struct rzg2l_pinctrl *pctrl, u32 caps,
+ enum rzg2l_iolh_index iolh_idx,
+ u16 ds)
+{
+ const struct rzg2l_hwcfg *hwcfg = pctrl->data->hwcfg;
+ const u16 *array = NULL;
+ unsigned int i;
+
+ if (caps & PIN_CFG_IOLH_A)
+ array = hwcfg->iolh_groupa_ua;
+
+ if (caps & PIN_CFG_IOLH_B)
+ array = hwcfg->iolh_groupb_ua;
+
+ if (caps & PIN_CFG_IOLH_C)
+ array = hwcfg->iolh_groupc_ua;
+
+ /* Should not happen. */
+ if (!array)
+ return false;
+
+ if (!array[iolh_idx])
+ return false;
+
+ for (i = 0; i < RZG2L_IOLH_MAX_DS_ENTRIES; i++) {
+ if (array[iolh_idx + i] == ds)
+ return true;
+ }
+
+ return false;
+}
+
static int rzg2l_pinctrl_pinconf_get(struct pinctrl_dev *pctldev,
unsigned int _pin,
unsigned long *config)
{
struct rzg2l_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
enum pin_config_param param = pinconf_to_config_param(*config);
+ const struct rzg2l_hwcfg *hwcfg = pctrl->data->hwcfg;
const struct pinctrl_pin_desc *pin = &pctrl->desc.pins[_pin];
unsigned int *pin_data = pin->drv_data;
unsigned int arg = 0;
- unsigned long flags;
- void __iomem *addr;
- u32 port_offset;
- u32 cfg = 0;
- u8 bit = 0;
+ u32 off, cfg;
+ int ret;
+ u8 bit;
if (!pin_data)
return -EINVAL;
+ off = RZG2L_PIN_CFG_TO_PORT_OFFSET(*pin_data);
+ cfg = RZG2L_PIN_CFG_TO_CAPS(*pin_data);
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))
@@ -549,49 +767,58 @@ static int rzg2l_pinctrl_pinconf_get(struct pinctrl_dev *pctldev,
case PIN_CONFIG_INPUT_ENABLE:
if (!(cfg & PIN_CFG_IEN))
return -EINVAL;
- arg = rzg2l_read_pin_config(pctrl, IEN(port_offset), bit, IEN_MASK);
+ arg = rzg2l_read_pin_config(pctrl, IEN(off), bit, IEN_MASK);
if (!arg)
return -EINVAL;
break;
- case PIN_CONFIG_POWER_SOURCE: {
- u32 pwr_reg = 0x0;
+ case PIN_CONFIG_POWER_SOURCE:
+ ret = rzg2l_get_power_source(pctrl, _pin, cfg);
+ if (ret < 0)
+ return ret;
+ arg = ret;
+ break;
+
+ case PIN_CONFIG_DRIVE_STRENGTH: {
+ unsigned int index;
- 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
+ if (!(cfg & PIN_CFG_IOLH_A) || hwcfg->drive_strength_ua)
return -EINVAL;
- spin_lock_irqsave(&pctrl->lock, flags);
- addr = pctrl->base + pwr_reg;
- arg = (readl(addr) & PVDD_MASK) ? 1800 : 3300;
- spin_unlock_irqrestore(&pctrl->lock, flags);
+ index = rzg2l_read_pin_config(pctrl, IOLH(off), bit, IOLH_MASK);
+ /*
+ * Drive strenght mA is supported only by group A and only
+ * for 3V3 port source.
+ */
+ arg = hwcfg->iolh_groupa_ua[index + RZG2L_IOLH_IDX_3V3] / 1000;
break;
}
- case PIN_CONFIG_DRIVE_STRENGTH: {
- unsigned int index;
+ case PIN_CONFIG_DRIVE_STRENGTH_UA: {
+ enum rzg2l_iolh_index iolh_idx;
+ u8 val;
- if (!(cfg & PIN_CFG_IOLH_A))
+ if (!(cfg & (PIN_CFG_IOLH_A | PIN_CFG_IOLH_B | PIN_CFG_IOLH_C)) ||
+ !hwcfg->drive_strength_ua)
return -EINVAL;
- index = rzg2l_read_pin_config(pctrl, IOLH(port_offset), bit, IOLH_MASK);
- arg = iolh_groupa_mA[index];
+ ret = rzg2l_get_power_source(pctrl, _pin, cfg);
+ if (ret < 0)
+ return ret;
+ iolh_idx = rzg2l_ps_to_iolh_idx(ret);
+ val = rzg2l_read_pin_config(pctrl, IOLH(off), bit, IOLH_MASK);
+ arg = rzg2l_iolh_val_to_ua(hwcfg, cfg, iolh_idx + val);
break;
}
case PIN_CONFIG_OUTPUT_IMPEDANCE_OHMS: {
unsigned int index;
- if (!(cfg & PIN_CFG_IOLH_B))
+ if (!(cfg & PIN_CFG_IOLH_B) || !hwcfg->iolh_groupb_oi[0])
return -EINVAL;
- index = rzg2l_read_pin_config(pctrl, IOLH(port_offset), bit, IOLH_MASK);
- arg = iolh_groupb_oi[index];
+ index = rzg2l_read_pin_config(pctrl, IOLH(off), bit, IOLH_MASK);
+ arg = hwcfg->iolh_groupb_oi[index];
break;
}
@@ -611,25 +838,23 @@ static int rzg2l_pinctrl_pinconf_set(struct pinctrl_dev *pctldev,
{
struct rzg2l_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
const struct pinctrl_pin_desc *pin = &pctrl->desc.pins[_pin];
+ const struct rzg2l_hwcfg *hwcfg = pctrl->data->hwcfg;
+ struct rzg2l_pinctrl_pin_settings settings = pctrl->settings[_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;
+ u32 cfg, off;
+ int ret;
+ u8 bit;
if (!pin_data)
return -EINVAL;
+ off = RZG2L_PIN_CFG_TO_PORT_OFFSET(*pin_data);
+ cfg = RZG2L_PIN_CFG_TO_CAPS(*pin_data);
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))
@@ -646,66 +871,56 @@ static int rzg2l_pinctrl_pinconf_set(struct pinctrl_dev *pctldev,
if (!(cfg & PIN_CFG_IEN))
return -EINVAL;
- rzg2l_rmw_pin_config(pctrl, IEN(port_offset), bit, IEN_MASK, !!arg);
+ rzg2l_rmw_pin_config(pctrl, IEN(off), 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);
+ 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;
- if (!(cfg & PIN_CFG_IOLH_A))
+ if (!(cfg & PIN_CFG_IOLH_A) || hwcfg->drive_strength_ua)
return -EINVAL;
- for (index = 0; index < ARRAY_SIZE(iolh_groupa_mA); index++) {
- if (arg == iolh_groupa_mA[index])
+ for (index = RZG2L_IOLH_IDX_3V3;
+ index < RZG2L_IOLH_IDX_3V3 + RZG2L_IOLH_MAX_DS_ENTRIES; index++) {
+ if (arg == (hwcfg->iolh_groupa_ua[index] / 1000))
break;
}
- if (index >= ARRAY_SIZE(iolh_groupa_mA))
+ if (index == (RZG2L_IOLH_IDX_3V3 + RZG2L_IOLH_MAX_DS_ENTRIES))
return -EINVAL;
- rzg2l_rmw_pin_config(pctrl, IOLH(port_offset), bit, IOLH_MASK, index);
+ 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)) ||
+ !hwcfg->drive_strength_ua)
+ return -EINVAL;
+
+ 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;
- if (!(cfg & PIN_CFG_IOLH_B))
+ if (!(cfg & PIN_CFG_IOLH_B) || !hwcfg->iolh_groupb_oi[0])
return -EINVAL;
- for (index = 0; index < ARRAY_SIZE(iolh_groupb_oi); index++) {
- if (arg == iolh_groupb_oi[index])
+ for (index = 0; index < ARRAY_SIZE(hwcfg->iolh_groupb_oi); index++) {
+ if (arg == hwcfg->iolh_groupb_oi[index])
break;
}
- if (index >= ARRAY_SIZE(iolh_groupb_oi))
+ if (index == ARRAY_SIZE(hwcfg->iolh_groupb_oi))
return -EINVAL;
- rzg2l_rmw_pin_config(pctrl, IOLH(port_offset), bit, IOLH_MASK, index);
+ rzg2l_rmw_pin_config(pctrl, IOLH(off), bit, IOLH_MASK, index);
break;
}
@@ -714,6 +929,39 @@ static int rzg2l_pinctrl_pinconf_set(struct pinctrl_dev *pctldev,
}
}
+ /* Apply power source. */
+ if (settings.power_source != pctrl->settings[_pin].power_source) {
+ ret = rzg2l_ps_is_supported(settings.power_source);
+ if (!ret)
+ return -EINVAL;
+
+ /* Apply power source. */
+ ret = rzg2l_set_power_source(pctrl, _pin, cfg, settings.power_source);
+ if (ret)
+ return ret;
+ }
+
+ /* Apply drive strength. */
+ if (settings.drive_strength_ua != pctrl->settings[_pin].drive_strength_ua) {
+ enum rzg2l_iolh_index iolh_idx;
+ int val;
+
+ iolh_idx = rzg2l_ps_to_iolh_idx(settings.power_source);
+ ret = rzg2l_ds_is_supported(pctrl, cfg, iolh_idx,
+ settings.drive_strength_ua);
+ if (!ret)
+ return -EINVAL;
+
+ /* Get register value for this PS/DS tuple. */
+ val = rzg2l_iolh_ua_to_val(hwcfg, cfg, iolh_idx, settings.drive_strength_ua);
+ if (val < 0)
+ return val;
+
+ /* Apply drive strength. */
+ rzg2l_rmw_pin_config(pctrl, IOLH(off), bit, IOLH_MASK, val);
+ pctrl->settings[_pin].drive_strength_ua = settings.drive_strength_ua;
+ }
+
return 0;
}
@@ -795,41 +1043,52 @@ static const struct pinconf_ops rzg2l_pinctrl_confops = {
static int rzg2l_gpio_request(struct gpio_chip *chip, unsigned int offset)
{
struct rzg2l_pinctrl *pctrl = gpiochip_get_data(chip);
+ const struct pinctrl_pin_desc *pin_desc = &pctrl->desc.pins[offset];
+ u32 *pin_data = pin_desc->drv_data;
+ u32 off = RZG2L_PIN_CFG_TO_PORT_OFFSET(*pin_data);
u32 port = RZG2L_PIN_ID_TO_PORT(offset);
u8 bit = RZG2L_PIN_ID_TO_PIN(offset);
unsigned long flags;
u8 reg8;
int ret;
- ret = pinctrl_gpio_request(chip->base + offset);
+ ret = rzg2l_validate_gpio_pin(pctrl, *pin_data, port, bit);
+ if (ret)
+ return ret;
+
+ ret = pinctrl_gpio_request(chip, offset);
if (ret)
return ret;
spin_lock_irqsave(&pctrl->lock, flags);
/* Select GPIO mode in PMC Register */
- reg8 = readb(pctrl->base + PMC(port));
+ reg8 = readb(pctrl->base + PMC(off));
reg8 &= ~BIT(bit);
- writeb(reg8, pctrl->base + PMC(port));
+ writeb(reg8, pctrl->base + PMC(off));
spin_unlock_irqrestore(&pctrl->lock, flags);
return 0;
}
-static void rzg2l_gpio_set_direction(struct rzg2l_pinctrl *pctrl, u32 port,
- u8 bit, bool output)
+static void rzg2l_gpio_set_direction(struct rzg2l_pinctrl *pctrl, u32 offset,
+ bool output)
{
+ const struct pinctrl_pin_desc *pin_desc = &pctrl->desc.pins[offset];
+ unsigned int *pin_data = pin_desc->drv_data;
+ u32 off = RZG2L_PIN_CFG_TO_PORT_OFFSET(*pin_data);
+ u8 bit = RZG2L_PIN_ID_TO_PIN(offset);
unsigned long flags;
u16 reg16;
spin_lock_irqsave(&pctrl->lock, flags);
- reg16 = readw(pctrl->base + PM(port));
+ reg16 = readw(pctrl->base + PM(off));
reg16 &= ~(PM_MASK << (bit * 2));
reg16 |= (output ? PM_OUTPUT : PM_INPUT) << (bit * 2);
- writew(reg16, pctrl->base + PM(port));
+ writew(reg16, pctrl->base + PM(off));
spin_unlock_irqrestore(&pctrl->lock, flags);
}
@@ -837,13 +1096,15 @@ static void rzg2l_gpio_set_direction(struct rzg2l_pinctrl *pctrl, u32 port,
static int rzg2l_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
{
struct rzg2l_pinctrl *pctrl = gpiochip_get_data(chip);
- u32 port = RZG2L_PIN_ID_TO_PORT(offset);
+ const struct pinctrl_pin_desc *pin_desc = &pctrl->desc.pins[offset];
+ unsigned int *pin_data = pin_desc->drv_data;
+ u32 off = RZG2L_PIN_CFG_TO_PORT_OFFSET(*pin_data);
u8 bit = RZG2L_PIN_ID_TO_PIN(offset);
- if (!(readb(pctrl->base + PMC(port)) & BIT(bit))) {
+ if (!(readb(pctrl->base + PMC(off)) & BIT(bit))) {
u16 reg16;
- reg16 = readw(pctrl->base + PM(port));
+ reg16 = readw(pctrl->base + PM(off));
reg16 = (reg16 >> (bit * 2)) & PM_MASK;
if (reg16 == PM_OUTPUT)
return GPIO_LINE_DIRECTION_OUT;
@@ -856,10 +1117,8 @@ static int rzg2l_gpio_direction_input(struct gpio_chip *chip,
unsigned int offset)
{
struct rzg2l_pinctrl *pctrl = gpiochip_get_data(chip);
- u32 port = RZG2L_PIN_ID_TO_PORT(offset);
- u8 bit = RZG2L_PIN_ID_TO_PIN(offset);
- rzg2l_gpio_set_direction(pctrl, port, bit, false);
+ rzg2l_gpio_set_direction(pctrl, offset, false);
return 0;
}
@@ -868,19 +1127,21 @@ static void rzg2l_gpio_set(struct gpio_chip *chip, unsigned int offset,
int value)
{
struct rzg2l_pinctrl *pctrl = gpiochip_get_data(chip);
- u32 port = RZG2L_PIN_ID_TO_PORT(offset);
+ const struct pinctrl_pin_desc *pin_desc = &pctrl->desc.pins[offset];
+ unsigned int *pin_data = pin_desc->drv_data;
+ u32 off = RZG2L_PIN_CFG_TO_PORT_OFFSET(*pin_data);
u8 bit = RZG2L_PIN_ID_TO_PIN(offset);
unsigned long flags;
u8 reg8;
spin_lock_irqsave(&pctrl->lock, flags);
- reg8 = readb(pctrl->base + P(port));
+ reg8 = readb(pctrl->base + P(off));
if (value)
- writeb(reg8 | BIT(bit), pctrl->base + P(port));
+ writeb(reg8 | BIT(bit), pctrl->base + P(off));
else
- writeb(reg8 & ~BIT(bit), pctrl->base + P(port));
+ writeb(reg8 & ~BIT(bit), pctrl->base + P(off));
spin_unlock_irqrestore(&pctrl->lock, flags);
}
@@ -889,11 +1150,9 @@ static int rzg2l_gpio_direction_output(struct gpio_chip *chip,
unsigned int offset, int value)
{
struct rzg2l_pinctrl *pctrl = gpiochip_get_data(chip);
- u32 port = RZG2L_PIN_ID_TO_PORT(offset);
- u8 bit = RZG2L_PIN_ID_TO_PIN(offset);
rzg2l_gpio_set(chip, offset, value);
- rzg2l_gpio_set_direction(pctrl, port, bit, true);
+ rzg2l_gpio_set_direction(pctrl, offset, true);
return 0;
}
@@ -901,17 +1160,19 @@ static int rzg2l_gpio_direction_output(struct gpio_chip *chip,
static int rzg2l_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
struct rzg2l_pinctrl *pctrl = gpiochip_get_data(chip);
- u32 port = RZG2L_PIN_ID_TO_PORT(offset);
+ const struct pinctrl_pin_desc *pin_desc = &pctrl->desc.pins[offset];
+ unsigned int *pin_data = pin_desc->drv_data;
+ u32 off = RZG2L_PIN_CFG_TO_PORT_OFFSET(*pin_data);
u8 bit = RZG2L_PIN_ID_TO_PIN(offset);
u16 reg16;
- reg16 = readw(pctrl->base + PM(port));
+ reg16 = readw(pctrl->base + PM(off));
reg16 = (reg16 >> (bit * 2)) & PM_MASK;
if (reg16 == PM_INPUT)
- return !!(readb(pctrl->base + PIN(port)) & BIT(bit));
+ return !!(readb(pctrl->base + PIN(off)) & BIT(bit));
else if (reg16 == PM_OUTPUT)
- return !!(readb(pctrl->base + P(port)) & BIT(bit));
+ return !!(readb(pctrl->base + P(off)) & BIT(bit));
else
return -EINVAL;
}
@@ -920,7 +1181,7 @@ static void rzg2l_gpio_free(struct gpio_chip *chip, unsigned int offset)
{
unsigned int virq;
- pinctrl_gpio_free(chip->base + offset);
+ pinctrl_gpio_free(chip, offset);
virq = irq_find_mapping(chip->irq.domain, offset);
if (virq)
@@ -985,7 +1246,7 @@ static const char * const rzg2l_gpio_names[] = {
"P48_0", "P48_1", "P48_2", "P48_3", "P48_4", "P48_5", "P48_6", "P48_7",
};
-static const u32 rzg2l_gpio_configs[] = {
+static const u32 r9a07g044_gpio_configs[] = {
RZG2L_GPIO_PORT_PACK(2, 0x10, RZG2L_MPXED_PIN_FUNCS),
RZG2L_GPIO_PORT_PACK(2, 0x11, RZG2L_MPXED_PIN_FUNCS),
RZG2L_GPIO_PORT_PACK(2, 0x12, RZG2L_MPXED_PIN_FUNCS),
@@ -1059,7 +1320,37 @@ static const u32 r9a07g043_gpio_configs[] = {
RZG2L_GPIO_PORT_PACK(6, 0x22, RZG2L_MPXED_PIN_FUNCS),
};
-static struct {
+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 */
+ 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 |
+ PIN_CFG_IO_VMC_ETH0)), /* P3 */
+ RZG2L_GPIO_PORT_PACK(6, 0x33, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IOLH_C |
+ PIN_CFG_IO_VMC_ETH0)), /* P4 */
+ 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 */
+ 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 |
+ PIN_CFG_IO_VMC_ETH1)), /* P9 */
+ RZG2L_GPIO_PORT_PACK(5, 0x37, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IOLH_C |
+ PIN_CFG_IO_VMC_ETH1)), /* P10 */
+ RZG2L_GPIO_PORT_PACK(4, 0x23, RZG3S_MPXED_PIN_FUNCS(B) | PIN_CFG_IEN), /* P11 */
+ RZG2L_GPIO_PORT_PACK(2, 0x24, RZG3S_MPXED_PIN_FUNCS(B) | PIN_CFG_IEN), /* P12 */
+ RZG2L_GPIO_PORT_PACK(5, 0x25, RZG3S_MPXED_PIN_FUNCS(A)), /* P13 */
+ RZG2L_GPIO_PORT_PACK(3, 0x26, RZG3S_MPXED_PIN_FUNCS(A)), /* P14 */
+ RZG2L_GPIO_PORT_PACK(4, 0x27, RZG3S_MPXED_PIN_FUNCS(A)), /* P15 */
+ RZG2L_GPIO_PORT_PACK(2, 0x28, RZG3S_MPXED_PIN_FUNCS(A)), /* P16 */
+ RZG2L_GPIO_PORT_PACK(4, 0x29, RZG3S_MPXED_PIN_FUNCS(A)), /* P17 */
+ RZG2L_GPIO_PORT_PACK(6, 0x2a, RZG3S_MPXED_PIN_FUNCS(A)), /* P18 */
+};
+
+static const struct {
struct rzg2l_dedicated_configs common[35];
struct rzg2l_dedicated_configs rzg2l_pins[7];
} rzg2l_dedicated_pins = {
@@ -1145,6 +1436,46 @@ static struct {
}
};
+static const struct rzg2l_dedicated_configs rzg3s_dedicated_pins[] = {
+ { "NMI", RZG2L_SINGLE_PIN_PACK(0x0, 0, (PIN_CFG_FILONOFF | PIN_CFG_FILNUM |
+ PIN_CFG_FILCLKSEL)) },
+ { "TMS/SWDIO", RZG2L_SINGLE_PIN_PACK(0x1, 0, (PIN_CFG_IOLH_A | PIN_CFG_IEN |
+ PIN_CFG_SOFT_PS)) },
+ { "TDO", RZG2L_SINGLE_PIN_PACK(0x1, 1, (PIN_CFG_IOLH_A | PIN_CFG_SOFT_PS)) },
+ { "WDTOVF_PERROUT#", RZG2L_SINGLE_PIN_PACK(0x6, 0, PIN_CFG_IOLH_A | PIN_CFG_SOFT_PS) },
+ { "SD0_CLK", RZG2L_SINGLE_PIN_PACK(0x10, 0, (PIN_CFG_IOLH_B | PIN_CFG_IO_VMC_SD0)) },
+ { "SD0_CMD", RZG2L_SINGLE_PIN_PACK(0x10, 1, (PIN_CFG_IOLH_B | PIN_CFG_IEN |
+ PIN_CFG_IO_VMC_SD0)) },
+ { "SD0_RST#", RZG2L_SINGLE_PIN_PACK(0x10, 2, (PIN_CFG_IOLH_B | PIN_CFG_IO_VMC_SD0)) },
+ { "SD0_DATA0", RZG2L_SINGLE_PIN_PACK(0x11, 0, (PIN_CFG_IOLH_B | PIN_CFG_IEN |
+ PIN_CFG_IO_VMC_SD0)) },
+ { "SD0_DATA1", RZG2L_SINGLE_PIN_PACK(0x11, 1, (PIN_CFG_IOLH_B | PIN_CFG_IEN |
+ PIN_CFG_IO_VMC_SD0)) },
+ { "SD0_DATA2", RZG2L_SINGLE_PIN_PACK(0x11, 2, (PIN_CFG_IOLH_B | PIN_CFG_IEN |
+ PIN_CFG_IO_VMC_SD0)) },
+ { "SD0_DATA3", RZG2L_SINGLE_PIN_PACK(0x11, 3, (PIN_CFG_IOLH_B | PIN_CFG_IEN |
+ PIN_CFG_IO_VMC_SD0)) },
+ { "SD0_DATA4", RZG2L_SINGLE_PIN_PACK(0x11, 4, (PIN_CFG_IOLH_B | PIN_CFG_IEN |
+ PIN_CFG_IO_VMC_SD0)) },
+ { "SD0_DATA5", RZG2L_SINGLE_PIN_PACK(0x11, 5, (PIN_CFG_IOLH_B | PIN_CFG_IEN |
+ PIN_CFG_IO_VMC_SD0)) },
+ { "SD0_DATA6", RZG2L_SINGLE_PIN_PACK(0x11, 6, (PIN_CFG_IOLH_B | PIN_CFG_IEN |
+ PIN_CFG_IO_VMC_SD0)) },
+ { "SD0_DATA7", RZG2L_SINGLE_PIN_PACK(0x11, 7, (PIN_CFG_IOLH_B | PIN_CFG_IEN |
+ PIN_CFG_IO_VMC_SD0)) },
+ { "SD1_CLK", RZG2L_SINGLE_PIN_PACK(0x12, 0, (PIN_CFG_IOLH_B | PIN_CFG_IO_VMC_SD1)) },
+ { "SD1_CMD", RZG2L_SINGLE_PIN_PACK(0x12, 1, (PIN_CFG_IOLH_B | PIN_CFG_IEN |
+ PIN_CFG_IO_VMC_SD1)) },
+ { "SD1_DATA0", RZG2L_SINGLE_PIN_PACK(0x13, 0, (PIN_CFG_IOLH_B | PIN_CFG_IEN |
+ PIN_CFG_IO_VMC_SD1)) },
+ { "SD1_DATA1", RZG2L_SINGLE_PIN_PACK(0x13, 1, (PIN_CFG_IOLH_B | PIN_CFG_IEN |
+ PIN_CFG_IO_VMC_SD1)) },
+ { "SD1_DATA2", RZG2L_SINGLE_PIN_PACK(0x13, 2, (PIN_CFG_IOLH_B | PIN_CFG_IEN |
+ PIN_CFG_IO_VMC_SD1)) },
+ { "SD1_DATA3", RZG2L_SINGLE_PIN_PACK(0x13, 3, (PIN_CFG_IOLH_B | PIN_CFG_IEN |
+ PIN_CFG_IO_VMC_SD1)) },
+};
+
static int rzg2l_gpio_get_gpioint(unsigned int virq, const struct rzg2l_pinctrl_data *data)
{
unsigned int gpioint;
@@ -1170,17 +1501,16 @@ static void rzg2l_gpio_irq_disable(struct irq_data *d)
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct rzg2l_pinctrl *pctrl = container_of(gc, struct rzg2l_pinctrl, gpio_chip);
unsigned int hwirq = irqd_to_hwirq(d);
+ const struct pinctrl_pin_desc *pin_desc = &pctrl->desc.pins[hwirq];
+ unsigned int *pin_data = pin_desc->drv_data;
+ u32 off = RZG2L_PIN_CFG_TO_PORT_OFFSET(*pin_data);
+ u8 bit = RZG2L_PIN_ID_TO_PIN(hwirq);
unsigned long flags;
void __iomem *addr;
- u32 port;
- u8 bit;
irq_chip_disable_parent(d);
- port = RZG2L_PIN_ID_TO_PORT(hwirq);
- bit = RZG2L_PIN_ID_TO_PIN(hwirq);
-
- addr = pctrl->base + ISEL(port);
+ addr = pctrl->base + ISEL(off);
if (bit >= 4) {
bit -= 4;
addr += 4;
@@ -1198,17 +1528,16 @@ static void rzg2l_gpio_irq_enable(struct irq_data *d)
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct rzg2l_pinctrl *pctrl = container_of(gc, struct rzg2l_pinctrl, gpio_chip);
unsigned int hwirq = irqd_to_hwirq(d);
+ const struct pinctrl_pin_desc *pin_desc = &pctrl->desc.pins[hwirq];
+ unsigned int *pin_data = pin_desc->drv_data;
+ u32 off = RZG2L_PIN_CFG_TO_PORT_OFFSET(*pin_data);
+ u8 bit = RZG2L_PIN_ID_TO_PIN(hwirq);
unsigned long flags;
void __iomem *addr;
- u32 port;
- u8 bit;
gpiochip_enable_irq(gc, hwirq);
- port = RZG2L_PIN_ID_TO_PORT(hwirq);
- bit = RZG2L_PIN_ID_TO_PIN(hwirq);
-
- addr = pctrl->base + ISEL(port);
+ addr = pctrl->base + ISEL(off);
if (bit >= 4) {
bit -= 4;
addr += 4;
@@ -1415,6 +1744,7 @@ static int rzg2l_gpio_register(struct rzg2l_pinctrl *pctrl)
static int rzg2l_pinctrl_register(struct rzg2l_pinctrl *pctrl)
{
+ const struct rzg2l_hwcfg *hwcfg = pctrl->data->hwcfg;
struct pinctrl_pin_desc *pins;
unsigned int i, j;
u32 *pin_data;
@@ -1457,6 +1787,22 @@ static int rzg2l_pinctrl_register(struct rzg2l_pinctrl *pctrl)
pins[index].drv_data = &pin_data[index];
}
+ pctrl->settings = devm_kcalloc(pctrl->dev, pctrl->desc.npins, sizeof(*pctrl->settings),
+ GFP_KERNEL);
+ if (!pctrl->settings)
+ return -ENOMEM;
+
+ for (i = 0; hwcfg->drive_strength_ua && i < pctrl->desc.npins; i++) {
+ if (pin_data[i] & PIN_CFG_SOFT_PS) {
+ pctrl->settings[i].power_source = 3300;
+ } else {
+ ret = rzg2l_get_power_source(pctrl, i, pin_data[i]);
+ if (ret < 0)
+ continue;
+ pctrl->settings[i].power_source = ret;
+ }
+ }
+
ret = devm_pinctrl_register_and_init(pctrl->dev, &pctrl->desc, pctrl,
&pctrl->pctl);
if (ret) {
@@ -1485,12 +1831,15 @@ static int rzg2l_pinctrl_probe(struct platform_device *pdev)
struct clk *clk;
int ret;
- BUILD_BUG_ON(ARRAY_SIZE(rzg2l_gpio_configs) * RZG2L_PINS_PER_PORT >
+ BUILD_BUG_ON(ARRAY_SIZE(r9a07g044_gpio_configs) * RZG2L_PINS_PER_PORT >
ARRAY_SIZE(rzg2l_gpio_names));
BUILD_BUG_ON(ARRAY_SIZE(r9a07g043_gpio_configs) * RZG2L_PINS_PER_PORT >
ARRAY_SIZE(rzg2l_gpio_names));
+ BUILD_BUG_ON(ARRAY_SIZE(r9a08g045_gpio_configs) * RZG2L_PINS_PER_PORT >
+ ARRAY_SIZE(rzg2l_gpio_names));
+
pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL);
if (!pctrl)
return -ENOMEM;
@@ -1524,6 +1873,47 @@ static int rzg2l_pinctrl_probe(struct platform_device *pdev)
return 0;
}
+static const struct rzg2l_hwcfg rzg2l_hwcfg = {
+ .regs = {
+ .pwpr = 0x3014,
+ .sd_ch = 0x3000,
+ },
+ .iolh_groupa_ua = {
+ /* 3v3 power source */
+ [RZG2L_IOLH_IDX_3V3] = 2000, 4000, 8000, 12000,
+ },
+ .iolh_groupb_oi = { 100, 66, 50, 33, },
+};
+
+static const struct rzg2l_hwcfg rzg3s_hwcfg = {
+ .regs = {
+ .pwpr = 0x3000,
+ .sd_ch = 0x3004,
+ },
+ .iolh_groupa_ua = {
+ /* 1v8 power source */
+ [RZG2L_IOLH_IDX_1V8] = 2200, 4400, 9000, 10000,
+ /* 3v3 power source */
+ [RZG2L_IOLH_IDX_3V3] = 1900, 4000, 8000, 9000,
+ },
+ .iolh_groupb_ua = {
+ /* 1v8 power source */
+ [RZG2L_IOLH_IDX_1V8] = 7000, 8000, 9000, 10000,
+ /* 3v3 power source */
+ [RZG2L_IOLH_IDX_3V3] = 4000, 6000, 8000, 9000,
+ },
+ .iolh_groupc_ua = {
+ /* 1v8 power source */
+ [RZG2L_IOLH_IDX_1V8] = 5200, 6000, 6550, 6800,
+ /* 2v5 source */
+ [RZG2L_IOLH_IDX_2V5] = 4700, 5300, 5800, 6100,
+ /* 3v3 power source */
+ [RZG2L_IOLH_IDX_3V3] = 4500, 5200, 5700, 6050,
+ },
+ .drive_strength_ua = true,
+ .func_base = 1,
+};
+
static struct rzg2l_pinctrl_data r9a07g043_data = {
.port_pins = rzg2l_gpio_names,
.port_pin_configs = r9a07g043_gpio_configs,
@@ -1531,16 +1921,28 @@ static struct rzg2l_pinctrl_data r9a07g043_data = {
.dedicated_pins = rzg2l_dedicated_pins.common,
.n_port_pins = ARRAY_SIZE(r9a07g043_gpio_configs) * RZG2L_PINS_PER_PORT,
.n_dedicated_pins = ARRAY_SIZE(rzg2l_dedicated_pins.common),
+ .hwcfg = &rzg2l_hwcfg,
};
static struct rzg2l_pinctrl_data r9a07g044_data = {
.port_pins = rzg2l_gpio_names,
- .port_pin_configs = rzg2l_gpio_configs,
- .n_ports = ARRAY_SIZE(rzg2l_gpio_configs),
+ .port_pin_configs = r9a07g044_gpio_configs,
+ .n_ports = ARRAY_SIZE(r9a07g044_gpio_configs),
.dedicated_pins = rzg2l_dedicated_pins.common,
- .n_port_pins = ARRAY_SIZE(rzg2l_gpio_configs) * RZG2L_PINS_PER_PORT,
+ .n_port_pins = ARRAY_SIZE(r9a07g044_gpio_configs) * RZG2L_PINS_PER_PORT,
.n_dedicated_pins = ARRAY_SIZE(rzg2l_dedicated_pins.common) +
ARRAY_SIZE(rzg2l_dedicated_pins.rzg2l_pins),
+ .hwcfg = &rzg2l_hwcfg,
+};
+
+static struct rzg2l_pinctrl_data r9a08g045_data = {
+ .port_pins = rzg2l_gpio_names,
+ .port_pin_configs = r9a08g045_gpio_configs,
+ .n_ports = ARRAY_SIZE(r9a08g045_gpio_configs),
+ .dedicated_pins = rzg3s_dedicated_pins,
+ .n_port_pins = ARRAY_SIZE(r9a08g045_gpio_configs) * RZG2L_PINS_PER_PORT,
+ .n_dedicated_pins = ARRAY_SIZE(rzg3s_dedicated_pins),
+ .hwcfg = &rzg3s_hwcfg,
};
static const struct of_device_id rzg2l_pinctrl_of_table[] = {
@@ -1552,6 +1954,10 @@ static const struct of_device_id rzg2l_pinctrl_of_table[] = {
.compatible = "renesas,r9a07g044-pinctrl",
.data = &r9a07g044_data,
},
+ {
+ .compatible = "renesas,r9a08g045-pinctrl",
+ .data = &r9a08g045_data,
+ },
{ /* sentinel */ }
};