123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 |
- // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
- /*
- * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
- */
- #include <common.h>
- #include <dm.h>
- #include <errno.h>
- #include <regmap.h>
- #include <syscon.h>
- #include <power/pmic.h>
- #include <power/regulator.h>
- #define STM32MP_PWR_CR3 0xc
- #define STM32MP_PWR_CR3_USB33DEN BIT(24)
- #define STM32MP_PWR_CR3_USB33RDY BIT(26)
- #define STM32MP_PWR_CR3_REG18DEN BIT(28)
- #define STM32MP_PWR_CR3_REG18RDY BIT(29)
- #define STM32MP_PWR_CR3_REG11DEN BIT(30)
- #define STM32MP_PWR_CR3_REG11RDY BIT(31)
- struct stm32mp_pwr_reg_info {
- u32 enable;
- u32 ready;
- char *name;
- };
- struct stm32mp_pwr_priv {
- struct regmap *regmap;
- };
- static int stm32mp_pwr_write(struct udevice *dev, uint reg,
- const uint8_t *buff, int len)
- {
- struct stm32mp_pwr_priv *priv = dev_get_priv(dev);
- u32 val = *(u32 *)buff;
- if (len != 4)
- return -EINVAL;
- return regmap_write(priv->regmap, STM32MP_PWR_CR3, val);
- }
- static int stm32mp_pwr_read(struct udevice *dev, uint reg, uint8_t *buff,
- int len)
- {
- struct stm32mp_pwr_priv *priv = dev_get_priv(dev);
- if (len != 4)
- return -EINVAL;
- return regmap_read(priv->regmap, STM32MP_PWR_CR3, (u32 *)buff);
- }
- static int stm32mp_pwr_ofdata_to_platdata(struct udevice *dev)
- {
- struct stm32mp_pwr_priv *priv = dev_get_priv(dev);
- struct regmap *regmap;
- regmap = syscon_get_regmap_by_driver_data(STM32MP_SYSCON_PWR);
- if (IS_ERR(regmap)) {
- pr_err("%s: unable to find regmap (%ld)\n", __func__,
- PTR_ERR(regmap));
- return PTR_ERR(regmap);
- }
- priv->regmap = regmap;
- return 0;
- }
- static const struct pmic_child_info pwr_children_info[] = {
- { .prefix = "reg", .driver = "stm32mp_pwr_regulator"},
- { .prefix = "usb", .driver = "stm32mp_pwr_regulator"},
- { },
- };
- static int stm32mp_pwr_bind(struct udevice *dev)
- {
- int children;
- children = pmic_bind_children(dev, dev->node, pwr_children_info);
- if (!children)
- dev_dbg(dev, "no child found\n");
- return 0;
- }
- static struct dm_pmic_ops stm32mp_pwr_ops = {
- .read = stm32mp_pwr_read,
- .write = stm32mp_pwr_write,
- };
- static const struct udevice_id stm32mp_pwr_ids[] = {
- { .compatible = "st,stm32mp1,pwr-reg" },
- { }
- };
- U_BOOT_DRIVER(stm32mp_pwr_pmic) = {
- .name = "stm32mp_pwr_pmic",
- .id = UCLASS_PMIC,
- .of_match = stm32mp_pwr_ids,
- .bind = stm32mp_pwr_bind,
- .ops = &stm32mp_pwr_ops,
- .ofdata_to_platdata = stm32mp_pwr_ofdata_to_platdata,
- .priv_auto_alloc_size = sizeof(struct stm32mp_pwr_priv),
- };
- static const struct stm32mp_pwr_reg_info stm32mp_pwr_reg11 = {
- .enable = STM32MP_PWR_CR3_REG11DEN,
- .ready = STM32MP_PWR_CR3_REG11RDY,
- .name = "reg11"
- };
- static const struct stm32mp_pwr_reg_info stm32mp_pwr_reg18 = {
- .enable = STM32MP_PWR_CR3_REG18DEN,
- .ready = STM32MP_PWR_CR3_REG18RDY,
- .name = "reg18"
- };
- static const struct stm32mp_pwr_reg_info stm32mp_pwr_usb33 = {
- .enable = STM32MP_PWR_CR3_USB33DEN,
- .ready = STM32MP_PWR_CR3_USB33RDY,
- .name = "usb33"
- };
- static const struct stm32mp_pwr_reg_info *stm32mp_pwr_reg_infos[] = {
- &stm32mp_pwr_reg11,
- &stm32mp_pwr_reg18,
- &stm32mp_pwr_usb33,
- NULL
- };
- static int stm32mp_pwr_regulator_probe(struct udevice *dev)
- {
- const struct stm32mp_pwr_reg_info **p = stm32mp_pwr_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) {
- dev_dbg(dev, "found regulator %s\n", (*p)->name);
- break;
- } else if (rc != -ENODATA) {
- return rc;
- }
- p++;
- }
- if (!*p) {
- int i = 0;
- const char *s;
- dev_dbg(dev, "regulator ");
- while (dev_read_string_index(dev, "regulator-name",
- i++, &s) >= 0)
- dev_dbg(dev, "%s'%s' ", (i > 1) ? ", " : "", s);
- dev_dbg(dev, "%s not supported\n", (i > 2) ? "are" : "is");
- return -EINVAL;
- }
- uc_pdata->type = REGULATOR_TYPE_FIXED;
- dev->priv = (void *)*p;
- return 0;
- }
- static int stm32mp_pwr_regulator_set_value(struct udevice *dev, int uV)
- {
- struct dm_regulator_uclass_platdata *uc_pdata;
- uc_pdata = dev_get_uclass_platdata(dev);
- if (!uc_pdata)
- return -ENXIO;
- if (uc_pdata->min_uV != uV) {
- dev_dbg(dev, "Invalid uV=%d for: %s\n", uV, uc_pdata->name);
- return -EINVAL;
- }
- return 0;
- }
- static int stm32mp_pwr_regulator_get_value(struct udevice *dev)
- {
- struct dm_regulator_uclass_platdata *uc_pdata;
- uc_pdata = dev_get_uclass_platdata(dev);
- if (!uc_pdata)
- return -ENXIO;
- if (uc_pdata->min_uV != uc_pdata->max_uV) {
- dev_dbg(dev, "Invalid constraints for: %s\n", uc_pdata->name);
- return -EINVAL;
- }
- return uc_pdata->min_uV;
- }
- static int stm32mp_pwr_regulator_get_enable(struct udevice *dev)
- {
- const struct stm32mp_pwr_reg_info *p = dev_get_priv(dev);
- int rc;
- u32 reg;
- rc = pmic_read(dev->parent, 0, (uint8_t *)®, sizeof(reg));
- if (rc)
- return rc;
- dev_dbg(dev, "%s id %s\n", p->name, (reg & p->enable) ? "on" : "off");
- return (reg & p->enable) != 0;
- }
- static int stm32mp_pwr_regulator_set_enable(struct udevice *dev, bool enable)
- {
- const struct stm32mp_pwr_reg_info *p = dev_get_priv(dev);
- int rc;
- u32 reg;
- u32 time_start;
- dev_dbg(dev, "Turning %s %s\n", enable ? "on" : "off", p->name);
- rc = pmic_read(dev->parent, 0, (uint8_t *)®, sizeof(reg));
- if (rc)
- return rc;
- /* if regulator is already in the wanted state, nothing to do */
- if (!!(reg & p->enable) == enable)
- return 0;
- reg &= ~p->enable;
- if (enable)
- reg |= p->enable;
- rc = pmic_write(dev->parent, 0, (uint8_t *)®, sizeof(reg));
- if (rc)
- return rc;
- if (!enable)
- return 0;
- /* waiting ready for enable */
- time_start = get_timer(0);
- while (1) {
- rc = pmic_read(dev->parent, 0, (uint8_t *)®, sizeof(reg));
- if (rc)
- return rc;
- if (reg & p->ready)
- break;
- if (get_timer(time_start) > CONFIG_SYS_HZ) {
- dev_dbg(dev, "%s: timeout\n", p->name);
- return -ETIMEDOUT;
- }
- }
- return 0;
- }
- static const struct dm_regulator_ops stm32mp_pwr_regulator_ops = {
- .set_value = stm32mp_pwr_regulator_set_value,
- .get_value = stm32mp_pwr_regulator_get_value,
- .get_enable = stm32mp_pwr_regulator_get_enable,
- .set_enable = stm32mp_pwr_regulator_set_enable,
- };
- U_BOOT_DRIVER(stm32mp_pwr_regulator) = {
- .name = "stm32mp_pwr_regulator",
- .id = UCLASS_REGULATOR,
- .ops = &stm32mp_pwr_regulator_ops,
- .probe = stm32mp_pwr_regulator_probe,
- };
|