uboot/drivers/power/regulator/pbias_regulator.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2016 Texas Instruments Incorporated, <www.ti.com>
   4 * Jean-Jacques Hiblot <jjhiblot@ti.com>
   5 */
   6
   7#include <common.h>
   8#include <errno.h>
   9#include <dm.h>
  10#include <log.h>
  11#include <linux/delay.h>
  12#include <linux/err.h>
  13#include <power/pmic.h>
  14#include <power/regulator.h>
  15#include <regmap.h>
  16#include <syscon.h>
  17#include <linux/bitops.h>
  18#include <linux/ioport.h>
  19#include <dm/device-internal.h>
  20#include <dm/read.h>
  21#ifdef CONFIG_MMC_OMAP36XX_PINS
  22#include <asm/arch/sys_proto.h>
  23#include <asm/io.h>
  24#include <asm/arch/mux.h>
  25#endif
  26
  27struct pbias_reg_info {
  28        u32 enable;
  29        u32 enable_mask;
  30        u32 disable_val;
  31        u32 vmode;
  32        unsigned int enable_time;
  33        char *name;
  34};
  35
  36struct pbias_priv {
  37        struct regmap *regmap;
  38        int offset;
  39};
  40
  41static const struct pmic_child_info pmic_children_info[] = {
  42        { .prefix = "pbias", .driver = "pbias_regulator"},
  43        { },
  44};
  45
  46static int pbias_write(struct udevice *dev, uint reg, const uint8_t *buff,
  47                       int len)
  48{
  49        struct pbias_priv *priv = dev_get_priv(dev);
  50        u32 val = *(u32 *)buff;
  51
  52        if (len != 4)
  53                return -EINVAL;
  54
  55        return regmap_write(priv->regmap, priv->offset, val);
  56}
  57
  58static int pbias_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
  59{
  60        struct pbias_priv *priv = dev_get_priv(dev);
  61
  62        if (len != 4)
  63                return -EINVAL;
  64
  65        return regmap_read(priv->regmap, priv->offset, (u32 *)buff);
  66}
  67
  68static int pbias_of_to_plat(struct udevice *dev)
  69{
  70        struct pbias_priv *priv = dev_get_priv(dev);
  71        struct udevice *syscon;
  72        struct regmap *regmap;
  73        struct resource res;
  74        int err;
  75
  76        err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
  77                                           "syscon", &syscon);
  78        if (err) {
  79                pr_err("%s: unable to find syscon device (%d)\n", __func__,
  80                      err);
  81                return err;
  82        }
  83
  84        regmap = syscon_get_regmap(syscon);
  85        if (IS_ERR(regmap)) {
  86                pr_err("%s: unable to find regmap (%ld)\n", __func__,
  87                      PTR_ERR(regmap));
  88                return PTR_ERR(regmap);
  89        }
  90        priv->regmap = regmap;
  91
  92        err = dev_read_resource(dev, 0, &res);
  93        if (err) {
  94                pr_err("%s: unable to find offset (%d)\n", __func__, err);
  95                return err;
  96        }
  97        priv->offset = res.start;
  98
  99        return 0;
 100}
 101
 102static int pbias_bind(struct udevice *dev)
 103{
 104        int children;
 105
 106        children = pmic_bind_children(dev, dev_ofnode(dev),
 107                                      pmic_children_info);
 108        if (!children)
 109                debug("%s: %s - no child found\n", __func__, dev->name);
 110
 111        return 0;
 112}
 113
 114static struct dm_pmic_ops pbias_ops = {
 115        .read = pbias_read,
 116        .write = pbias_write,
 117};
 118
 119static const struct udevice_id pbias_ids[] = {
 120        { .compatible = "ti,pbias-dra7" },
 121        { .compatible = "ti,pbias-omap2" },
 122        { .compatible = "ti,pbias-omap3" },
 123        { .compatible = "ti,pbias-omap4" },
 124        { .compatible = "ti,pbias-omap5" },
 125        { }
 126};
 127
 128U_BOOT_DRIVER(pbias_pmic) = {
 129        .name = "pbias_pmic",
 130        .id = UCLASS_PMIC,
 131        .of_match = pbias_ids,
 132        .bind = pbias_bind,
 133        .ops = &pbias_ops,
 134        .of_to_plat = pbias_of_to_plat,
 135        .priv_auto      = sizeof(struct pbias_priv),
 136};
 137
 138static const struct pbias_reg_info pbias_mmc_omap2430 = {
 139        .enable = BIT(1),
 140        .enable_mask = BIT(1),
 141        .vmode = BIT(0),
 142        .disable_val = 0,
 143        .enable_time = 100,
 144        .name = "pbias_mmc_omap2430"
 145};
 146
 147static const struct pbias_reg_info pbias_sim_omap3 = {
 148        .enable = BIT(9),
 149        .enable_mask = BIT(9),
 150        .vmode = BIT(8),
 151        .enable_time = 100,
 152        .name = "pbias_sim_omap3"
 153};
 154
 155static const struct pbias_reg_info pbias_mmc_omap4 = {
 156        .enable = BIT(26) | BIT(22),
 157        .enable_mask = BIT(26) | BIT(25) | BIT(22),
 158        .disable_val = BIT(25),
 159        .vmode = BIT(21),
 160        .enable_time = 100,
 161        .name = "pbias_mmc_omap4"
 162};
 163
 164static const struct pbias_reg_info pbias_mmc_omap5 = {
 165        .enable = BIT(27) | BIT(26),
 166        .enable_mask = BIT(27) | BIT(25) | BIT(26),
 167        .disable_val = BIT(25),
 168        .vmode = BIT(21),
 169        .enable_time = 100,
 170        .name = "pbias_mmc_omap5"
 171};
 172
 173static const struct pbias_reg_info *pbias_reg_infos[] = {
 174        &pbias_mmc_omap5,
 175        &pbias_mmc_omap4,
 176        &pbias_sim_omap3,
 177        &pbias_mmc_omap2430,
 178        NULL
 179};
 180
 181static int pbias_regulator_probe(struct udevice *dev)
 182{
 183        const struct pbias_reg_info **p = pbias_reg_infos;
 184        struct dm_regulator_uclass_plat *uc_pdata;
 185
 186        uc_pdata = dev_get_uclass_plat(dev);
 187
 188        while (*p) {
 189                int rc;
 190
 191                rc = dev_read_stringlist_search(dev, "regulator-name",
 192                                                (*p)->name);
 193                if (rc >= 0) {
 194                        debug("found regulator %s\n", (*p)->name);
 195                        break;
 196                } else if (rc != -ENODATA) {
 197                        return rc;
 198                }
 199                p++;
 200        }
 201        if (!*p) {
 202                int i = 0;
 203                const char *s;
 204
 205                debug("regulator ");
 206                while (dev_read_string_index(dev, "regulator-name", i++, &s) >= 0)
 207                        debug("%s'%s' ", (i > 1) ? ", " : "", s);
 208                debug("%s not supported\n", (i > 2) ? "are" : "is");
 209                return -EINVAL;
 210        }
 211
 212        uc_pdata->type = REGULATOR_TYPE_OTHER;
 213        dev_set_priv(dev, (void *)*p);
 214
 215        return 0;
 216}
 217
 218static int pbias_regulator_get_value(struct udevice *dev)
 219{
 220        const struct pbias_reg_info *p = dev_get_priv(dev);
 221        int rc;
 222        u32 reg;
 223
 224        rc = pmic_read(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
 225        if (rc)
 226                return rc;
 227
 228        debug("%s voltage id %s\n", p->name,
 229              (reg & p->vmode) ? "3.0v" : "1.8v");
 230        return (reg & p->vmode) ? 3000000 : 1800000;
 231}
 232
 233static int pbias_regulator_set_value(struct udevice *dev, int uV)
 234{
 235        const struct pbias_reg_info *p = dev_get_priv(dev);
 236        int rc, ret;
 237        u32 reg;
 238#ifdef CONFIG_MMC_OMAP36XX_PINS
 239        u32 wkup_ctrl = readl(OMAP34XX_CTRL_WKUP_CTRL);
 240#endif
 241
 242        rc = pmic_read(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
 243        if (rc)
 244                return rc;
 245
 246        if (uV == 3300000)
 247                reg |= p->vmode;
 248        else if (uV == 1800000)
 249                reg &= ~p->vmode;
 250        else
 251                return -EINVAL;
 252
 253        debug("Setting %s voltage to %s\n", p->name,
 254              (reg & p->vmode) ? "3.0v" : "1.8v");
 255
 256#ifdef CONFIG_MMC_OMAP36XX_PINS
 257        if (get_cpu_family() == CPU_OMAP36XX) {
 258                /* Disable extended drain IO before changing PBIAS */
 259                wkup_ctrl &= ~OMAP34XX_CTRL_WKUP_CTRL_GPIO_IO_PWRDNZ;
 260                writel(wkup_ctrl, OMAP34XX_CTRL_WKUP_CTRL);
 261        }
 262#endif
 263        ret = pmic_write(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
 264#ifdef CONFIG_MMC_OMAP36XX_PINS
 265        if (get_cpu_family() == CPU_OMAP36XX) {
 266                /* Enable extended drain IO after changing PBIAS */
 267                writel(wkup_ctrl |
 268                                OMAP34XX_CTRL_WKUP_CTRL_GPIO_IO_PWRDNZ,
 269                                OMAP34XX_CTRL_WKUP_CTRL);
 270        }
 271#endif
 272        return ret;
 273}
 274
 275static int pbias_regulator_get_enable(struct udevice *dev)
 276{
 277        const struct pbias_reg_info *p = dev_get_priv(dev);
 278        int rc;
 279        u32 reg;
 280
 281        rc = pmic_read(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
 282        if (rc)
 283                return rc;
 284
 285        debug("%s id %s\n", p->name,
 286              (reg & p->enable_mask) == (p->disable_val) ? "on" : "off");
 287
 288        return (reg & p->enable_mask) == (p->disable_val);
 289}
 290
 291static int pbias_regulator_set_enable(struct udevice *dev, bool enable)
 292{
 293        const struct pbias_reg_info *p = dev_get_priv(dev);
 294        int rc;
 295        u32 reg;
 296#ifdef CONFIG_MMC_OMAP36XX_PINS
 297        u32 wkup_ctrl = readl(OMAP34XX_CTRL_WKUP_CTRL);
 298#endif
 299
 300        debug("Turning %s %s\n", enable ? "on" : "off", p->name);
 301
 302#ifdef CONFIG_MMC_OMAP36XX_PINS
 303        if (get_cpu_family() == CPU_OMAP36XX) {
 304                /* Disable extended drain IO before changing PBIAS */
 305                wkup_ctrl &= ~OMAP34XX_CTRL_WKUP_CTRL_GPIO_IO_PWRDNZ;
 306                writel(wkup_ctrl, OMAP34XX_CTRL_WKUP_CTRL);
 307        }
 308#endif
 309
 310        rc = pmic_read(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
 311        if (rc)
 312                return rc;
 313
 314        reg &= ~p->enable_mask;
 315        if (enable)
 316                reg |= p->enable;
 317        else
 318                reg |= p->disable_val;
 319
 320        rc = pmic_write(dev->parent, 0, (uint8_t *)&reg, sizeof(reg));
 321
 322#ifdef CONFIG_MMC_OMAP36XX_PINS
 323        if (get_cpu_family() == CPU_OMAP36XX) {
 324                /* Enable extended drain IO after changing PBIAS */
 325                writel(wkup_ctrl |
 326                                OMAP34XX_CTRL_WKUP_CTRL_GPIO_IO_PWRDNZ,
 327                                OMAP34XX_CTRL_WKUP_CTRL);
 328        }
 329#endif
 330
 331        if (rc)
 332                return rc;
 333
 334        if (enable)
 335                udelay(p->enable_time);
 336
 337        return 0;
 338}
 339
 340static const struct dm_regulator_ops pbias_regulator_ops = {
 341        .get_value  = pbias_regulator_get_value,
 342        .set_value  = pbias_regulator_set_value,
 343        .get_enable = pbias_regulator_get_enable,
 344        .set_enable = pbias_regulator_set_enable,
 345};
 346
 347U_BOOT_DRIVER(pbias_regulator) = {
 348        .name = "pbias_regulator",
 349        .id = UCLASS_REGULATOR,
 350        .ops = &pbias_regulator_ops,
 351        .probe = pbias_regulator_probe,
 352};
 353