On 08/07/2017 06:43 PM, Jean-Jacques Hiblot wrote: > In the TI SOCs a PBIAS cell exists to provide a bias voltage to the MMC1 > IO cells. Without this bias voltage these I/O cells can not function > properly. The PBIAS cell is controlled by software. > > Signed-off-by: Jean-Jacques Hiblot <jjhib...@ti.com> > Reviewed-by: Tom Rini <tr...@konsulko.com> > Reviewed-by: Simon Glass <s...@chromium.org>
Applied to u-boot-mmc! Sorry for late. Best Regards, Jaehoon Chung > --- > > Hi Jaehoon, > > Here is the patch for the PBIAS regulator. I modified the KConfig to select > the REGMAP and SYSCON features as you suggested. > Thanks. > JJ > > changes since v2: > - automatically select REGMAP and SYSCON if PBIAS is selected. > > changes since v1: > - automatically select the PBIAS driver if DM_REGULATOR, DM_MMC and > MMC_OMAP_HS are set > - use the dev_read_*() API to access the DT > > > drivers/mmc/Kconfig | 1 + > drivers/power/regulator/Kconfig | 13 ++ > drivers/power/regulator/Makefile | 1 + > drivers/power/regulator/pbias_regulator.c | 302 > ++++++++++++++++++++++++++++++ > 4 files changed, 317 insertions(+) > create mode 100644 drivers/power/regulator/pbias_regulator.c > > diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig > index 588e118..63e1122 100644 > --- a/drivers/mmc/Kconfig > +++ b/drivers/mmc/Kconfig > @@ -158,6 +158,7 @@ config MMC_PCI > config MMC_OMAP_HS > bool "TI OMAP High Speed Multimedia Card Interface support" > select DM_MMC_OPS if DM_MMC > + select DM_REGULATOR_PBIAS if DM_MMC && DM_REGULATOR > help > This selects the TI OMAP High Speed Multimedia card Interface. > If you have an omap2plus board with a Multimedia Card slot, > diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig > index f213487..cb5ea08 100644 > --- a/drivers/power/regulator/Kconfig > +++ b/drivers/power/regulator/Kconfig > @@ -142,6 +142,19 @@ config DM_REGULATOR_PALMAS > features for REGULATOR PALMAS and the family of PALMAS PMICs. > The driver implements get/set api for: value and enable. > > +config DM_REGULATOR_PBIAS > + bool "Enable driver for PBIAS regulator" > + depends on DM_REGULATOR > + select REGMAP > + select SYSCON > + ---help--- > + This enables implementation of driver-model regulator uclass > + features for pseudo-regulator PBIAS found in the OMAP SOCs. > + This pseudo-regulator is used to provide a BIAS voltage to MMC1 > + signal pads and must be configured properly during a voltage switch. > + Voltage switching is required by some operating modes of SDcards and > + eMMC. > + > config DM_REGULATOR_LP873X > bool "Enable driver for LP873X PMIC regulators" > depends on PMIC_LP873X > diff --git a/drivers/power/regulator/Makefile > b/drivers/power/regulator/Makefile > index ce14d08..75d611a 100644 > --- a/drivers/power/regulator/Makefile > +++ b/drivers/power/regulator/Makefile > @@ -17,5 +17,6 @@ obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o > obj-$(CONFIG_DM_REGULATOR_SANDBOX) += sandbox.o > obj-$(CONFIG_REGULATOR_TPS65090) += tps65090_regulator.o > obj-$(CONFIG_$(SPL_)DM_REGULATOR_PALMAS) += palmas_regulator.o > +obj-$(CONFIG_$(SPL_)DM_REGULATOR_PBIAS) += pbias_regulator.o > obj-$(CONFIG_$(SPL_)DM_REGULATOR_LP873X) += lp873x_regulator.o > obj-$(CONFIG_$(SPL_)DM_REGULATOR_LP87565) += lp87565_regulator.o > diff --git a/drivers/power/regulator/pbias_regulator.c > b/drivers/power/regulator/pbias_regulator.c > new file mode 100644 > index 0000000..303eca9 > --- /dev/null > +++ b/drivers/power/regulator/pbias_regulator.c > @@ -0,0 +1,302 @@ > +/* > + * (C) Copyright 2016 Texas Instruments Incorporated, <www.ti.com> > + * Jean-Jacques Hiblot <jjhib...@ti.com> > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > + > +#include <common.h> > +#include <errno.h> > +#include <dm.h> > +#include <power/pmic.h> > +#include <power/regulator.h> > +#include <regmap.h> > +#include <syscon.h> > +#include <linux/bitops.h> > +#include <linux/ioport.h> > +#include <dm/read.h> > + > +DECLARE_GLOBAL_DATA_PTR; > + > +struct pbias_reg_info { > + u32 enable; > + u32 enable_mask; > + u32 disable_val; > + u32 vmode; > + unsigned int enable_time; > + char *name; > +}; > + > +struct pbias_priv { > + struct regmap *regmap; > + int offset; > +}; > + > +static const struct pmic_child_info pmic_children_info[] = { > + { .prefix = "pbias", .driver = "pbias_regulator"}, > + { }, > +}; > + > +static int pbias_write(struct udevice *dev, uint reg, const uint8_t *buff, > + int len) > +{ > + struct pbias_priv *priv = dev_get_priv(dev); > + uint32_t val = *(uint32_t *)buff; > + > + if (len != 4) > + return -EINVAL; > + > + return regmap_write(priv->regmap, priv->offset, val); > +} > + > +static int pbias_read(struct udevice *dev, uint reg, uint8_t *buff, int len) > +{ > + struct pbias_priv *priv = dev_get_priv(dev); > + > + if (len != 4) > + return -EINVAL; > + > + return regmap_read(priv->regmap, priv->offset, (uint32_t *)buff); > +} > + > +static int pbias_ofdata_to_platdata(struct udevice *dev) > +{ > + struct pbias_priv *priv = dev_get_priv(dev); > + struct udevice *syscon; > + struct regmap *regmap; > + struct resource res; > + int err; > + > + err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, > + "syscon", &syscon); > + if (err) { > + error("%s: unable to find syscon device (%d)\n", __func__, > + err); > + return err; > + } > + > + regmap = syscon_get_regmap(syscon); > + if (IS_ERR(regmap)) { > + error("%s: unable to find regmap (%ld)\n", __func__, > + PTR_ERR(regmap)); > + return PTR_ERR(regmap); > + } > + priv->regmap = regmap; > + > + err = dev_read_resource(dev, 0, &res); > + if (err) { > + error("%s: unable to find offset (%d)\n", __func__, err); > + return err; > + } > + priv->offset = res.start; > + > + return 0; > +} > + > +static int pbias_bind(struct udevice *dev) > +{ > + int children; > + > + children = pmic_bind_children(dev, dev->node, pmic_children_info); > + if (!children) > + debug("%s: %s - no child found\n", __func__, dev->name); > + > + return 0; > +} > + > +static struct dm_pmic_ops pbias_ops = { > + .read = pbias_read, > + .write = pbias_write, > +}; > + > +static const struct udevice_id pbias_ids[] = { > + { .compatible = "ti,pbias-dra7" }, > + { } > +}; > + > +U_BOOT_DRIVER(pbias_pmic) = { > + .name = "pbias_pmic", > + .id = UCLASS_PMIC, > + .of_match = pbias_ids, > + .bind = pbias_bind, > + .ops = &pbias_ops, > + .ofdata_to_platdata = pbias_ofdata_to_platdata, > + .priv_auto_alloc_size = sizeof(struct pbias_priv), > +}; > + > +static const struct pbias_reg_info pbias_mmc_omap2430 = { > + .enable = BIT(1), > + .enable_mask = BIT(1), > + .vmode = BIT(0), > + .disable_val = 0, > + .enable_time = 100, > + .name = "pbias_mmc_omap2430" > +}; > + > +static const struct pbias_reg_info pbias_sim_omap3 = { > + .enable = BIT(9), > + .enable_mask = BIT(9), > + .vmode = BIT(8), > + .enable_time = 100, > + .name = "pbias_sim_omap3" > +}; > + > +static const struct pbias_reg_info pbias_mmc_omap4 = { > + .enable = BIT(26) | BIT(22), > + .enable_mask = BIT(26) | BIT(25) | BIT(22), > + .disable_val = BIT(25), > + .vmode = BIT(21), > + .enable_time = 100, > + .name = "pbias_mmc_omap4" > +}; > + > +static const struct pbias_reg_info pbias_mmc_omap5 = { > + .enable = BIT(27) | BIT(26), > + .enable_mask = BIT(27) | BIT(25) | BIT(26), > + .disable_val = BIT(25), > + .vmode = BIT(21), > + .enable_time = 100, > + .name = "pbias_mmc_omap5" > +}; > + > +static const struct pbias_reg_info *pbias_reg_infos[] = { > + &pbias_mmc_omap5, > + &pbias_mmc_omap4, > + &pbias_sim_omap3, > + &pbias_mmc_omap2430, > + NULL > +}; > + > + > +static int pbias_regulator_probe(struct udevice *dev) > +{ > + const struct pbias_reg_info **p = pbias_reg_infos; > + struct dm_regulator_uclass_platdata *uc_pdata; > + > + uc_pdata = dev_get_uclass_platdata(dev); > + > + > + while (*p) { > + int rc; > + rc = dev_read_stringlist_search(dev, "regulator-name", > + (*p)->name); > + if (rc >= 0) { > + debug("found regulator %s\n", (*p)->name); > + break; > + } else if (rc != -ENODATA) { > + return rc; > + } > + p++; > + } > + if (!*p) { > + int i = 0; > + const char *s; > + > + debug("regulator "); > + while (dev_read_string_index(dev, "regulator-name", i++, &s) >= > 0) > + debug("%s'%s' ", (i > 1) ? ", " : "", s); > + debug("%s not supported\n", (i > 2) ? "are" : "is"); > + return -EINVAL; > + } > + > + uc_pdata->type = REGULATOR_TYPE_OTHER; > + dev->priv = (void *)*p; > + > + return 0; > +} > + > +static int pbias_regulator_get_value(struct udevice *dev) > +{ > + const struct pbias_reg_info *p = dev_get_priv(dev); > + int rc; > + uint32_t reg; > + > + rc = pmic_read(dev->parent, 0, (uint8_t *)®, sizeof(reg)); > + if (rc) > + return rc; > + > + debug("%s voltage id %s\n", p->name, > + (reg & p->vmode) ? "3.0v" : "1.8v"); > + return (reg & p->vmode) ? 3000000 : 1800000; > +} > + > +static int pbias_regulator_set_value(struct udevice *dev, int uV) > +{ > + const struct pbias_reg_info *p = dev_get_priv(dev); > + int rc; > + uint32_t reg; > + > + debug("Setting %s voltage to %s\n", p->name, > + (reg & p->vmode) ? "3.0v" : "1.8v"); > + > + rc = pmic_read(dev->parent, 0, (uint8_t *)®, sizeof(reg)); > + if (rc) > + return rc; > + > + if (uV == 3000000) > + reg |= p->vmode; > + else if (uV == 1800000) > + reg &= ~p->vmode; > + else > + return -EINVAL; > + > + return pmic_write(dev->parent, 0, (uint8_t *)®, sizeof(reg)); > +} > + > +static int pbias_regulator_get_enable(struct udevice *dev) > +{ > + const struct pbias_reg_info *p = dev_get_priv(dev); > + int rc; > + uint32_t reg; > + > + rc = pmic_read(dev->parent, 0, (uint8_t *)®, sizeof(reg)); > + if (rc) > + return rc; > + > + debug("%s id %s\n", p->name, > + (reg & p->enable_mask) == (p->disable_val) ? "on" : "off"); > + > + return (reg & p->enable_mask) == (p->disable_val); > +} > + > +static int pbias_regulator_set_enable(struct udevice *dev, bool enable) > +{ > + const struct pbias_reg_info *p = dev_get_priv(dev); > + int rc; > + uint32_t reg; > + > + debug("Turning %s %s\n", enable ? "on" : "off", p->name); > + > + rc = pmic_read(dev->parent, 0, (uint8_t *)®, sizeof(reg)); > + if (rc) > + return rc; > + > + reg &= ~p->enable_mask; > + if (enable) > + reg |= p->enable; > + else > + reg |= p->disable_val; > + > + rc = pmic_write(dev->parent, 0, (uint8_t *)®, sizeof(reg)); > + if (rc) > + return rc; > + > + if (enable) > + udelay(p->enable_time); > + > + return 0; > +} > + > +static const struct dm_regulator_ops pbias_regulator_ops = { > + .get_value = pbias_regulator_get_value, > + .set_value = pbias_regulator_set_value, > + .get_enable = pbias_regulator_get_enable, > + .set_enable = pbias_regulator_set_enable, > +}; > + > +U_BOOT_DRIVER(pbias_regulator) = { > + .name = "pbias_regulator", > + .id = UCLASS_REGULATOR, > + .ops = &pbias_regulator_ops, > + .probe = pbias_regulator_probe, > +}; > _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot