Re: [RFC PATCH 3/7] pinctrl: sh-pfc: r8a7790: Add regulators for SD voltage switch

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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




[Index of Archives]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux