Message ID | 1430397095.5802.42.camel@xylophone.i.decadent.org.uk (mailing list archive) |
---|---|
State | Superseded |
Delegated to: | Geert Uytterhoeven |
Headers | show |
On 30 April 2015 at 14:31, Ben Hutchings <ben.hutchings@codethink.co.uk> 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@codethink.co.uk> 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@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-sh" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Tue, 2015-05-05 at 09:52 +0200, Ulf Hansson wrote: > On 30 April 2015 at 14:31, Ben Hutchings <ben.hutchings@codethink.co.uk> 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@codethink.co.uk> > > You need also to send this to the pinctrl maintainer and the corresponding list. [...] OK, will do next time. Ben. -- To unsubscribe from this list: send the line "unsubscribe linux-sh" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
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 },
Model the choice of 1.8V or 3.3V signalling for each SD interface as a regulator. Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk> --- 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(-)