On 30 April 2015 at 14:31, Ben Hutchings <ben.hutchings@xxxxxxxxxxxxxxx> wrote: > Model the choice of 1.8V or 3.3V signalling for each SD interface as a > regulator. > > Signed-off-by: Ben Hutchings <ben.hutchings@xxxxxxxxxxxxxxx> You need also to send this to the pinctrl maintainer and the corresponding list. Kind regards Uffe > --- > drivers/pinctrl/sh-pfc/Kconfig | 1 + > drivers/pinctrl/sh-pfc/core.c | 2 +- > drivers/pinctrl/sh-pfc/core.h | 1 + > drivers/pinctrl/sh-pfc/pfc-r8a7790.c | 189 ++++++++++++++++++++++++++++++++++ > 4 files changed, 192 insertions(+), 1 deletion(-) > > diff --git a/drivers/pinctrl/sh-pfc/Kconfig b/drivers/pinctrl/sh-pfc/Kconfig > index 8c4b3d391823..4b1895a6ac69 100644 > --- a/drivers/pinctrl/sh-pfc/Kconfig > +++ b/drivers/pinctrl/sh-pfc/Kconfig > @@ -49,6 +49,7 @@ config PINCTRL_PFC_R8A7790 > def_bool y > depends on ARCH_R8A7790 > select PINCTRL_SH_PFC > + select REGULATOR if OF > > config PINCTRL_PFC_R8A7791 > def_bool y > diff --git a/drivers/pinctrl/sh-pfc/core.c b/drivers/pinctrl/sh-pfc/core.c > index 7b2c9495c383..7d51f96afc9a 100644 > --- a/drivers/pinctrl/sh-pfc/core.c > +++ b/drivers/pinctrl/sh-pfc/core.c > @@ -92,7 +92,7 @@ static int sh_pfc_map_resources(struct sh_pfc *pfc, > return 0; > } > > -static void __iomem *sh_pfc_phys_to_virt(struct sh_pfc *pfc, u32 reg) > +void __iomem *sh_pfc_phys_to_virt(struct sh_pfc *pfc, u32 reg) > { > struct sh_pfc_window *window; > phys_addr_t address = reg; > diff --git a/drivers/pinctrl/sh-pfc/core.h b/drivers/pinctrl/sh-pfc/core.h > index 6dc8a6fc2746..af355629c5d2 100644 > --- a/drivers/pinctrl/sh-pfc/core.h > +++ b/drivers/pinctrl/sh-pfc/core.h > @@ -57,6 +57,7 @@ int sh_pfc_unregister_gpiochip(struct sh_pfc *pfc); > int sh_pfc_register_pinctrl(struct sh_pfc *pfc); > int sh_pfc_unregister_pinctrl(struct sh_pfc *pfc); > > +void __iomem *sh_pfc_phys_to_virt(struct sh_pfc *pfc, u32 address); > u32 sh_pfc_read_raw_reg(void __iomem *mapped_reg, unsigned int reg_width); > void sh_pfc_write_raw_reg(void __iomem *mapped_reg, unsigned int reg_width, > u32 data); > diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c > index 22a5470889f5..0c9d2c018a10 100644 > --- a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c > +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c > @@ -23,6 +23,13 @@ > > #include <linux/kernel.h> > #include <linux/platform_data/gpio-rcar.h> > +#ifdef CONFIG_OF > +#include <linux/of.h> > +#include <linux/regulator/driver.h> > +#include <linux/regulator/machine.h> > +#include <linux/regulator/of_regulator.h> > +#include <linux/string.h> > +#endif > > #include "core.h" > #include "sh_pfc.h" > @@ -5586,8 +5593,190 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = { > { }, > }; > > +#ifdef CONFIG_OF > + > +struct r8a7790_sd_regulator_data { > + struct regulator_desc desc; > + char name[10]; > + struct regulator_dev *dev; > + int state; > +}; > + > +#define SD_REGULATOR_NAME "regulator-r8a7790-sd" > + > +#define SD_LOW_VOLTAGE 1800000 > +#define SD_STD_VOLTAGE 3300000 > + > +static int r8a7790_sd_regulator_set_voltage(struct regulator_dev *dev, > + int min_uV, int max_uV, > + unsigned int *selector) > +{ > + struct r8a7790_sd_regulator_data *drvdata = rdev_get_drvdata(dev); > + struct sh_pfc *pfc = dev_get_drvdata(dev->dev.parent); > + void __iomem *mapped_reg; > + u32 data, mask; > + int state; > + > + if (min_uV <= SD_LOW_VOLTAGE && max_uV >= SD_LOW_VOLTAGE) > + state = 0; > + else if (min_uV <= SD_STD_VOLTAGE && max_uV >= SD_STD_VOLTAGE) > + state = 1; > + else > + return -EINVAL; > + > + /* Map IOCTRL6 */ > + mapped_reg = sh_pfc_phys_to_virt(pfc, 0xe606008c); > + > + spin_lock(&pfc->lock); > + > + data = sh_pfc_read_raw_reg(mapped_reg, 32); > + > + /* Set I/O voltage for the 8 pins for this SD interface */ > + mask = 0xff << (24 - drvdata->desc.id * 8); > + if (state) > + data |= mask; > + else > + data &= ~mask; > + > + sh_pfc_write_raw_reg( > + sh_pfc_phys_to_virt(pfc, pfc->info->unlock_reg), 32, > + ~data); > + sh_pfc_write_raw_reg(mapped_reg, 32, data); > + > + spin_unlock(&pfc->lock); > + > + drvdata->state = state; > + if (selector) > + *selector = state; > + > + return 0; > +} > + > +static int r8a7790_sd_regulator_list_voltage(struct regulator_dev *dev, > + unsigned int selector) > +{ > + switch (selector) { > + case 0: > + return SD_LOW_VOLTAGE; > + case 1: > + return SD_STD_VOLTAGE; > + default: > + return -EINVAL; > + } > +} > + > +static int r8a7790_sd_regulator_get_voltage(struct regulator_dev *dev) > +{ > + struct r8a7790_sd_regulator_data *drvdata = rdev_get_drvdata(dev); > + > + return r8a7790_sd_regulator_list_voltage(dev, drvdata->state); > +} > + > +static const struct regulator_ops r8a7790_sd_regulator_ops = { > + .set_voltage = r8a7790_sd_regulator_set_voltage, > + .get_voltage = r8a7790_sd_regulator_get_voltage, > + .list_voltage = r8a7790_sd_regulator_list_voltage, > +}; > + > +static const struct regulator_init_data r8a7790_sd_regulator_init = { > + .constraints = { > + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, > + .min_uV = SD_LOW_VOLTAGE, > + .max_uV = SD_STD_VOLTAGE, > + }, > +}; > + > +static int r8a7790_sd_regulator_probe(struct sh_pfc *pfc, int index) > +{ > + char child_name[20]; > + struct device_node *np; > + struct r8a7790_sd_regulator_data *drvdata; > + struct regulator_config cfg = { }; > + void __iomem *mapped_reg; > + int ret; > + > + snprintf(child_name, sizeof(child_name), "sd-regulator@%d", index); > + np = NULL; > + while ((np = of_get_next_available_child(pfc->dev->of_node, np))) { > + if (!strcmp(kbasename(np->full_name), child_name)) > + break; > + } > + if (!np) { > + dev_dbg(pfc->dev, "no %s child node found\n", child_name); > + return -ENODEV; > + } > + > + drvdata = devm_kzalloc(pfc->dev, sizeof(*drvdata), GFP_KERNEL); > + if (!drvdata) { > + ret = -ENOMEM; > + goto out; > + } > + drvdata->desc.owner = THIS_MODULE; > + /* XXX drvdata->desc.enable_time = ???; */ > + drvdata->desc.id = index; > + drvdata->desc.type = REGULATOR_VOLTAGE; > + drvdata->desc.ops = &r8a7790_sd_regulator_ops; > + drvdata->desc.n_voltages = 2; > + > + snprintf(drvdata->name, sizeof(drvdata->name), "sd%d-vccq", index); > + drvdata->desc.name = drvdata->name; > + > + /* Read initial state from IOCTRL6 */ > + mapped_reg = sh_pfc_phys_to_virt(pfc, 0xe606008c); > + switch ((sh_pfc_read_raw_reg(mapped_reg, 32) >> (24 - index * 8)) & > + 0xff) { > + case 0: /* low = 1.8V */ > + drvdata->state = 0; > + break; > + case 0xff: /* standard = 3.3V */ > + drvdata->state = 1; > + break; > + default: /* mixed?! */ > + drvdata->state = -1; > + break; > + } > + > + cfg.dev = pfc->dev; > + cfg.of_node = np; > + cfg.driver_data = drvdata; > + cfg.init_data = &r8a7790_sd_regulator_init; > + > + drvdata->dev = devm_regulator_register(pfc->dev, &drvdata->desc, &cfg); > + if (IS_ERR(drvdata->dev)) { > + ret = PTR_ERR(drvdata->dev); > + dev_err(pfc->dev, "Failed to register regulator: %d\n", ret); > + } > + > +out: > + of_node_put(np); > + return ret; > +} > + > +static int r8a7790_pinmux_soc_init(struct sh_pfc *pfc) > +{ > + int i, ret; > + > + for (i = 0; i < 4; ++i) { > + ret = r8a7790_sd_regulator_probe(pfc, i); > + if (ret && ret != -ENODEV) > + return ret; > + } > + > + return 0; > +} > + > +#endif /* CONFIG_OF */ > + > +static const struct sh_pfc_soc_operations pinmux_ops = { > +#ifdef CONFIG_OF > + .init = r8a7790_pinmux_soc_init, > +#endif > +}; > + > const struct sh_pfc_soc_info r8a7790_pinmux_info = { > .name = "r8a77900_pfc", > + .ops = &pinmux_ops, > + > .unlock_reg = 0xe6060000, /* PMMR */ > > .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END }, > -- > 1.7.10.4 > > > > > -- > To unsubscribe from this list: send the line "unsubscribe linux-mmc" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html