enum sh_pfc_model {
SH_PFC_R8A7795 = 0,
SH_PFC_R8A7796,
+ SH_PFC_R8A77970,
+ SH_PFC_R8A77995,
};
struct sh_pfc_pin_config {
return priv->pfc.info->functions[selector].name;
}
+int sh_pfc_config_mux_for_gpio(struct udevice *dev, unsigned pin_selector)
+{
+ struct sh_pfc_pinctrl_priv *priv = dev_get_priv(dev);
+ struct sh_pfc_pinctrl *pmx = &priv->pmx;
+ struct sh_pfc *pfc = &priv->pfc;
+ struct sh_pfc_pin_config *cfg;
+ const struct sh_pfc_pin *pin = NULL;
+ int i, idx;
+
+ for (i = 1; i < pfc->info->nr_pins; i++) {
+ if (priv->pfc.info->pins[i].pin != pin_selector)
+ continue;
+
+ pin = &priv->pfc.info->pins[i];
+ break;
+ }
+
+ if (!pin)
+ return -EINVAL;
+
+ idx = sh_pfc_get_pin_index(pfc, pin->pin);
+ cfg = &pmx->configs[idx];
+
+ if (cfg->type != PINMUX_TYPE_NONE)
+ return -EBUSY;
+
+ return sh_pfc_config_mux(pfc, pin->enum_id, PINMUX_TYPE_GPIO);
+}
+
+static int sh_pfc_pinctrl_pin_set(struct udevice *dev, unsigned pin_selector,
+ unsigned func_selector)
+{
+ struct sh_pfc_pinctrl_priv *priv = dev_get_priv(dev);
+ struct sh_pfc_pinctrl *pmx = &priv->pmx;
+ struct sh_pfc *pfc = &priv->pfc;
+ const struct sh_pfc_pin *pin = &priv->pfc.info->pins[pin_selector];
+ int idx = sh_pfc_get_pin_index(pfc, pin->pin);
+ struct sh_pfc_pin_config *cfg = &pmx->configs[idx];
+
+ if (cfg->type != PINMUX_TYPE_NONE)
+ return -EBUSY;
+
+ return sh_pfc_config_mux(pfc, pin->enum_id, PINMUX_TYPE_FUNCTION);
+}
+
static int sh_pfc_pinctrl_group_set(struct udevice *dev, unsigned group_selector,
unsigned func_selector)
{
done:
return ret;
}
+#if CONFIG_IS_ENABLED(PINCONF)
+static const struct pinconf_param sh_pfc_pinconf_params[] = {
+ { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
+ { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
+ { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
+ { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
+ { "power-source", PIN_CONFIG_POWER_SOURCE, 3300 },
+};
+
+static void __iomem *
+sh_pfc_pinconf_find_drive_strength_reg(struct sh_pfc *pfc, unsigned int pin,
+ unsigned int *offset, unsigned int *size)
+{
+ const struct pinmux_drive_reg_field *field;
+ const struct pinmux_drive_reg *reg;
+ unsigned int i;
+
+ for (reg = pfc->info->drive_regs; reg->reg; ++reg) {
+ for (i = 0; i < ARRAY_SIZE(reg->fields); ++i) {
+ field = ®->fields[i];
+
+ if (field->size && field->pin == pin) {
+ *offset = field->offset;
+ *size = field->size;
+
+ return (void __iomem *)(uintptr_t)reg->reg;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static int sh_pfc_pinconf_set_drive_strength(struct sh_pfc *pfc,
+ unsigned int pin, u16 strength)
+{
+ unsigned int offset;
+ unsigned int size;
+ unsigned int step;
+ void __iomem *reg;
+ void __iomem *unlock_reg =
+ (void __iomem *)(uintptr_t)pfc->info->unlock_reg;
+ u32 val;
+
+ reg = sh_pfc_pinconf_find_drive_strength_reg(pfc, pin, &offset, &size);
+ if (!reg)
+ return -EINVAL;
+
+ step = size == 2 ? 6 : 3;
+
+ if (strength < step || strength > 24)
+ return -EINVAL;
+
+ /* Convert the value from mA based on a full drive strength value of
+ * 24mA. We can make the full value configurable later if needed.
+ */
+ strength = strength / step - 1;
+
+ val = sh_pfc_read_raw_reg(reg, 32);
+ val &= ~GENMASK(offset + size - 1, offset);
+ val |= strength << offset;
+
+ if (unlock_reg)
+ sh_pfc_write_raw_reg(unlock_reg, 32, ~val);
+
+ sh_pfc_write_raw_reg(reg, 32, val);
+
+ return 0;
+}
+
+/* Check whether the requested parameter is supported for a pin. */
+static bool sh_pfc_pinconf_validate(struct sh_pfc *pfc, unsigned int _pin,
+ unsigned int param)
+{
+ int idx = sh_pfc_get_pin_index(pfc, _pin);
+ const struct sh_pfc_pin *pin = &pfc->info->pins[idx];
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ return pin->configs &
+ (SH_PFC_PIN_CFG_PULL_UP | SH_PFC_PIN_CFG_PULL_DOWN);
+
+ case PIN_CONFIG_BIAS_PULL_UP:
+ return pin->configs & SH_PFC_PIN_CFG_PULL_UP;
+
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ return pin->configs & SH_PFC_PIN_CFG_PULL_DOWN;
+
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ return pin->configs & SH_PFC_PIN_CFG_DRIVE_STRENGTH;
+
+ case PIN_CONFIG_POWER_SOURCE:
+ return pin->configs & SH_PFC_PIN_CFG_IO_VOLTAGE;
+
+ default:
+ return false;
+ }
+}
+
+static int sh_pfc_pinconf_set(struct sh_pfc_pinctrl *pmx, unsigned _pin,
+ unsigned int param, unsigned int arg)
+{
+ struct sh_pfc *pfc = pmx->pfc;
+ void __iomem *pocctrl;
+ void __iomem *unlock_reg =
+ (void __iomem *)(uintptr_t)pfc->info->unlock_reg;
+ u32 addr, val;
+ int bit, ret;
+
+ if (!sh_pfc_pinconf_validate(pfc, _pin, param))
+ return -ENOTSUPP;
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_PULL_UP:
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ case PIN_CONFIG_BIAS_DISABLE:
+ if (!pfc->info->ops || !pfc->info->ops->set_bias)
+ return -ENOTSUPP;
+
+ pfc->info->ops->set_bias(pfc, _pin, param);
+
+ break;
+
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ ret = sh_pfc_pinconf_set_drive_strength(pfc, _pin, arg);
+ if (ret < 0)
+ return ret;
+
+ break;
+
+ case PIN_CONFIG_POWER_SOURCE:
+ if (!pfc->info->ops || !pfc->info->ops->pin_to_pocctrl)
+ return -ENOTSUPP;
+
+ bit = pfc->info->ops->pin_to_pocctrl(pfc, _pin, &addr);
+ if (bit < 0) {
+ printf("invalid pin %#x", _pin);
+ return bit;
+ }
+
+ if (arg != 1800 && arg != 3300)
+ return -EINVAL;
+
+ pocctrl = (void __iomem *)(uintptr_t)addr;
+
+ val = sh_pfc_read_raw_reg(pocctrl, 32);
+ if (arg == 3300)
+ val |= BIT(bit);
+ else
+ val &= ~BIT(bit);
+
+ if (unlock_reg)
+ sh_pfc_write_raw_reg(unlock_reg, 32, ~val);
+
+ sh_pfc_write_raw_reg(pocctrl, 32, val);
+
+ break;
+
+ default:
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
+static int sh_pfc_pinconf_pin_set(struct udevice *dev,
+ unsigned int pin_selector,
+ unsigned int param, unsigned int arg)
+{
+ struct sh_pfc_pinctrl_priv *priv = dev_get_priv(dev);
+ struct sh_pfc_pinctrl *pmx = &priv->pmx;
+ struct sh_pfc *pfc = &priv->pfc;
+ const struct sh_pfc_pin *pin = &pfc->info->pins[pin_selector];
+
+ sh_pfc_pinconf_set(pmx, pin->pin, param, arg);
+
+ return 0;
+}
+
+static int sh_pfc_pinconf_group_set(struct udevice *dev,
+ unsigned int group_selector,
+ unsigned int param, unsigned int arg)
+{
+ struct sh_pfc_pinctrl_priv *priv = dev_get_priv(dev);
+ struct sh_pfc_pinctrl *pmx = &priv->pmx;
+ struct sh_pfc *pfc = &priv->pfc;
+ const struct sh_pfc_pin_group *grp = &pfc->info->groups[group_selector];
+ unsigned int i;
+
+ for (i = 0; i < grp->nr_pins; i++)
+ sh_pfc_pinconf_set(pmx, grp->pins[i], param, arg);
+
+ return 0;
+}
+#endif
static struct pinctrl_ops sh_pfc_pinctrl_ops = {
.get_pins_count = sh_pfc_pinctrl_get_pins_count,
.get_functions_count = sh_pfc_pinctrl_get_functions_count,
.get_function_name = sh_pfc_pinctrl_get_function_name,
+#if CONFIG_IS_ENABLED(PINCONF)
+ .pinconf_num_params = ARRAY_SIZE(sh_pfc_pinconf_params),
+ .pinconf_params = sh_pfc_pinconf_params,
+ .pinconf_set = sh_pfc_pinconf_pin_set,
+ .pinconf_group_set = sh_pfc_pinconf_group_set,
+#endif
+ .pinmux_set = sh_pfc_pinctrl_pin_set,
.pinmux_group_set = sh_pfc_pinctrl_group_set,
.set_state = pinctrl_generic_set_state,
};
if (model == SH_PFC_R8A7796)
priv->pfc.info = &r8a7796_pinmux_info;
#endif
+#ifdef CONFIG_PINCTRL_PFC_R8A77970
+ if (model == SH_PFC_R8A77970)
+ priv->pfc.info = &r8a77970_pinmux_info;
+#endif
+#ifdef CONFIG_PINCTRL_PFC_R8A77995
+ if (model == SH_PFC_R8A77995)
+ priv->pfc.info = &r8a77995_pinmux_info;
+#endif
priv->pmx.pfc = &priv->pfc;
sh_pfc_init_ranges(&priv->pfc);
.compatible = "renesas,pfc-r8a7796",
.data = SH_PFC_R8A7796,
},
+#endif
+#ifdef CONFIG_PINCTRL_PFC_R8A77970
+ {
+ .compatible = "renesas,pfc-r8a77970",
+ .data = SH_PFC_R8A77970,
+ },
+#endif
+#ifdef CONFIG_PINCTRL_PFC_R8A77995
+ {
+ .compatible = "renesas,pfc-r8a77995",
+ .data = SH_PFC_R8A77995,
+ },
#endif
{ },
};