From cc456bd7df06225819258dec9d4a5047e8da4952 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 3 Aug 2015 08:19:23 -0600 Subject: dm: cros_ec: Convert the I2C tunnel code to use driver model The Chrome OS EC supports tunnelling through to an I2C bus on the EC. This currently uses a copy of the I2C command code and a special 'crosec' sub-command. With driver model we can define an I2C bus which tunnels through to the EC, and use the normal 'i2c' command to access it. This simplifies the code and removes some duplication. Add an I2C driver which tunnels through to the EC. Adjust the EC code to support binding child devices so that it can be set up. Adjust the existing I2C xfer function to fit driver model better. For now the old code remains to allow things to still work. It will be removed in a later patch once the new flow is fully enabled. Signed-off-by: Simon Glass --- drivers/power/pmic/pmic_tps65090_ec.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/power') diff --git a/drivers/power/pmic/pmic_tps65090_ec.c b/drivers/power/pmic/pmic_tps65090_ec.c index ac0d44fec8..f79a8782c9 100644 --- a/drivers/power/pmic/pmic_tps65090_ec.c +++ b/drivers/power/pmic/pmic_tps65090_ec.c @@ -56,8 +56,8 @@ enum { */ static int tps65090_read(u32 reg, u8 *val) { - return cros_ec_i2c_xfer(config.dev, TPS65090_ADDR, reg, 1, - val, 1, true); + return cros_ec_i2c_xfer_old(config.dev, TPS65090_ADDR, reg, 1, + val, 1, true); } /** @@ -69,8 +69,8 @@ static int tps65090_read(u32 reg, u8 *val) */ static int tps65090_write(u32 reg, u8 val) { - return cros_ec_i2c_xfer(config.dev, TPS65090_ADDR, reg, 1, - &val, 1, false); + return cros_ec_i2c_xfer_old(config.dev, TPS65090_ADDR, reg, 1, + &val, 1, false); } /** -- cgit From 151b223b9c4e309d65166558afdfa0ce3c3b3213 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 2 Jul 2015 18:15:58 -0600 Subject: dm: power: Add a new driver for the TPS65090 PMIC The existing TPS65090 driver does not support driver model. Add a new one that does. This can be used as a base for a regulator driver also. It uses the standard device tree binding. Signed-off-by: Simon Glass Acked-by: Przemyslaw Marczak --- drivers/power/pmic/Kconfig | 9 +++++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/tps65090.c | 94 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+) create mode 100644 drivers/power/pmic/tps65090.c (limited to 'drivers/power') diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index 164f42143f..fd8af8161e 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -41,3 +41,12 @@ config DM_PMIC_SANDBOX - set by i2c emul driver's probe() (defaults in header) Driver binding info: doc/device-tree-bindings/pmic/sandbox.txt + +config PMIC_TPS65090 + bool "Enable driver for Texas Instruments TPS65090 PMIC" + depends on DM_PMIC + ---help--- + The TPS65090 is a PMIC containing several LDOs, DC to DC convertors, + FETs and a battery charger. This driver provides register access + only, and you can enable the regulator/charger drivers separately if + required. diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index 4ad6df36c2..43b706b688 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_DM_PMIC) += pmic-uclass.o obj-$(CONFIG_DM_PMIC_MAX77686) += max77686.o obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o +obj-$(CONFIG_PMIC_TPS65090) += tps65090.o obj-$(CONFIG_POWER_LTC3676) += pmic_ltc3676.o obj-$(CONFIG_POWER_MAX77696) += pmic_max77696.o obj-$(CONFIG_POWER_MAX8998) += pmic_max8998.o diff --git a/drivers/power/pmic/tps65090.c b/drivers/power/pmic/tps65090.c new file mode 100644 index 0000000000..4797f327fa --- /dev/null +++ b/drivers/power/pmic/tps65090.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2015 Google, Inc + * Written by Simon Glass + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +static const struct pmic_child_info pmic_children_info[] = { + { .prefix = "fet", .driver = TPS65090_FET_DRIVER }, + { }, +}; + +static int tps65090_reg_count(struct udevice *dev) +{ + return TPS65090_NUM_REGS; +} + +static int tps65090_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + if (dm_i2c_write(dev, reg, buff, len)) { + error("write error to device: %p register: %#x!", dev, reg); + return -EIO; + } + + return 0; +} + +static int tps65090_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + int ret; + + ret = dm_i2c_read(dev, reg, buff, len); + if (ret) { + error("read error %d from device: %p register: %#x!", ret, dev, + reg); + return -EIO; + } + + return 0; +} + +static int tps65090_bind(struct udevice *dev) +{ + int regulators_node; + const void *blob = gd->fdt_blob; + int children; + + regulators_node = fdt_subnode_offset(blob, dev->of_offset, + "regulators"); + if (regulators_node <= 0) { + debug("%s: %s regulators subnode not found!", __func__, + dev->name); + return -ENXIO; + } + + debug("%s: '%s' - found regulators subnode\n", __func__, dev->name); + + children = pmic_bind_children(dev, regulators_node, pmic_children_info); + if (!children) + debug("%s: %s - no child found\n", __func__, dev->name); + + /* Always return success for this device */ + return 0; +} + +static struct dm_pmic_ops tps65090_ops = { + .reg_count = tps65090_reg_count, + .read = tps65090_read, + .write = tps65090_write, +}; + +static const struct udevice_id tps65090_ids[] = { + { .compatible = "ti,tps65090" }, + { } +}; + +U_BOOT_DRIVER(pmic_tps65090) = { + .name = "tps65090 pmic", + .id = UCLASS_PMIC, + .of_match = tps65090_ids, + .bind = tps65090_bind, + .ops = &tps65090_ops, +}; -- cgit From 1c88b67ec8faa33c12438cab8a5191bbab6c85e3 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 2 Jul 2015 18:15:59 -0600 Subject: dm: power: Add support for TPS65090 FETs The TPS65090 has 7 FETs which are modelled as regulators. This allows them to be controlled by drivers easier, accessed through the 'regulator' command and used by other drivers. Signed-off-by: Simon Glass Acked-by: Przemyslaw Marczak --- drivers/power/regulator/Kconfig | 10 ++ drivers/power/regulator/Makefile | 1 + drivers/power/regulator/tps65090_regulator.c | 138 +++++++++++++++++++++++++++ 3 files changed, 149 insertions(+) create mode 100644 drivers/power/regulator/tps65090_regulator.c (limited to 'drivers/power') diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig index 6289b83910..d0906501d0 100644 --- a/drivers/power/regulator/Kconfig +++ b/drivers/power/regulator/Kconfig @@ -61,3 +61,13 @@ config DM_REGULATOR_SANDBOX A detailed information can be found in header: '' Binding info: 'doc/device-tree-bindings/pmic/max77686.txt' + +config REGULATOR_TPS65090 + bool "Enable driver for TPS65090 PMIC regulators" + depends on PMIC_TPS65090 + ---help--- + The TPS65090 provides several FETs (Field-effect Transistors, + effectively switches) which are supported by this driver as + regulators, one for each FET. The standard regulator interface is + supported, but it is only possible to turn the regulators on or off. + There is no voltage/current control. diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile index 96aa624961..43f4d2ce43 100644 --- a/drivers/power/regulator/Makefile +++ b/drivers/power/regulator/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_DM_REGULATOR) += regulator-uclass.o obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.o obj-$(CONFIG_DM_REGULATOR_FIXED) += fixed.o obj-$(CONFIG_DM_REGULATOR_SANDBOX) += sandbox.o +obj-$(CONFIG_REGULATOR_TPS65090) += tps65090_regulator.o diff --git a/drivers/power/regulator/tps65090_regulator.c b/drivers/power/regulator/tps65090_regulator.c new file mode 100644 index 0000000000..affc504071 --- /dev/null +++ b/drivers/power/regulator/tps65090_regulator.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2015 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include + +static int tps65090_fet_probe(struct udevice *dev) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + + uc_pdata = dev_get_uclass_platdata(dev); + + uc_pdata->type = REGULATOR_TYPE_OTHER; + uc_pdata->mode_count = 0; + + return 0; +} + +static bool tps65090_fet_get_enable(struct udevice *dev) +{ + struct udevice *pmic = dev_get_parent(dev); + int ret, fet_id; + + fet_id = dev->driver_data; + debug("%s: fet_id=%d\n", __func__, fet_id); + + ret = pmic_reg_read(pmic, REG_FET_BASE + fet_id); + if (ret < 0) + return ret; + + return ret & FET_CTRL_ENFET; +} + +/** + * Set the power state for a FET + * + * @param pmic pmic structure for the tps65090 + * @param fet_id FET number to set (1..MAX_FET_NUM) + * @param set 1 to power on FET, 0 to power off + * @return -EIO if we got a comms error, -EAGAIN if the FET failed to + * change state. If all is ok, returns 0. + */ +static int tps65090_fet_set(struct udevice *pmic, int fet_id, bool set) +{ + int retry; + u32 value; + int ret; + + value = FET_CTRL_ADENFET | FET_CTRL_WAIT; + if (set) + value |= FET_CTRL_ENFET; + + if (pmic_reg_write(pmic, REG_FET_BASE + fet_id, value)) + return -EIO; + + /* Try reading until we get a result */ + for (retry = 0; retry < MAX_CTRL_READ_TRIES; retry++) { + ret = pmic_reg_read(pmic, REG_FET_BASE + fet_id); + if (ret < 0) + return ret; + + /* Check that the FET went into the expected state */ + debug("%s: flags=%x\n", __func__, ret); + if (!!(ret & FET_CTRL_PGFET) == set) + return 0; + + /* If we got a timeout, there is no point in waiting longer */ + if (ret & FET_CTRL_TOFET) + break; + + mdelay(1); + } + + debug("FET %d: Power good should have set to %d but reg=%#02x\n", + fet_id, set, ret); + return -EAGAIN; +} + +static int tps65090_fet_set_enable(struct udevice *dev, bool enable) +{ + struct udevice *pmic = dev_get_parent(dev); + int ret, fet_id; + ulong start; + int loops; + + fet_id = dev->driver_data; + debug("%s: fet_id=%d, enable=%d\n", __func__, fet_id, enable); + + start = get_timer(0); + for (loops = 0;; loops++) { + ret = tps65090_fet_set(pmic, fet_id, enable); + if (!ret) + break; + + if (get_timer(start) > 100) + break; + + /* Turn it off and try again until we time out */ + tps65090_fet_set(pmic, fet_id, false); + } + + if (ret) + debug("%s: FET%d failed to power on: time=%lums, loops=%d\n", + __func__, fet_id, get_timer(start), loops); + else if (loops) + debug("%s: FET%d powered on after %lums, loops=%d\n", + __func__, fet_id, get_timer(start), loops); + + /* + * Unfortunately there are some conditions where the power-good bit + * will be 0, but the FET still comes up. One such case occurs with + * the LCD backlight on snow. We'll just return 0 here and assume + * that the FET will eventually come up. + */ + if (ret == -EAGAIN) + ret = 0; + + return ret; +} + +static const struct dm_regulator_ops tps65090_fet_ops = { + .get_enable = tps65090_fet_get_enable, + .set_enable = tps65090_fet_set_enable, +}; + +U_BOOT_DRIVER(tps65090_fet) = { + .name = TPS65090_FET_DRIVER, + .id = UCLASS_REGULATOR, + .ops = &tps65090_fet_ops, + .probe = tps65090_fet_probe, +}; -- cgit From d308c0136d8a530d4846ab08ce02e6d40614d7e7 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 2 Jul 2015 18:16:00 -0600 Subject: dm: power: Add support for the S5M8767 PMIC This PMIC is used with SoCs which need a combination of BUCKs and LDOs. The driver supports probing and basic register access. It supports the standard device tree binding and supports driver model. A regulator driver can be provided also. Signed-off-by: Simon Glass Acked-by: Przemyslaw Marczak --- drivers/power/pmic/Kconfig | 9 +++++ drivers/power/pmic/Makefile | 2 + drivers/power/pmic/s5m8767.c | 95 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+) create mode 100644 drivers/power/pmic/s5m8767.c (limited to 'drivers/power') diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index fd8af8161e..7b98189ad8 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -42,6 +42,15 @@ config DM_PMIC_SANDBOX Driver binding info: doc/device-tree-bindings/pmic/sandbox.txt +config PMIC_S5M8767 + bool "Enable Driver Model for the Samsung S5M8767 PMIC" + depends on DM_PMIC + ---help--- + The S5M8767 PMIC provides a large array of LDOs and BUCKs for use + as a SoC power controller. It also provides 32KHz clock outputs. This + driver provides basic register access and sets up the attached + regulators if regulator support is enabled. + config PMIC_TPS65090 bool "Enable driver for Texas Instruments TPS65090 PMIC" depends on DM_PMIC diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index 43b706b688..322c2c6cac 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -9,6 +9,8 @@ obj-$(CONFIG_DM_PMIC) += pmic-uclass.o obj-$(CONFIG_DM_PMIC_MAX77686) += max77686.o obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o obj-$(CONFIG_PMIC_TPS65090) += tps65090.o +obj-$(CONFIG_PMIC_S5M8767) += s5m8767.o + obj-$(CONFIG_POWER_LTC3676) += pmic_ltc3676.o obj-$(CONFIG_POWER_MAX77696) += pmic_max77696.o obj-$(CONFIG_POWER_MAX8998) += pmic_max8998.o diff --git a/drivers/power/pmic/s5m8767.c b/drivers/power/pmic/s5m8767.c new file mode 100644 index 0000000000..075fe7e2f1 --- /dev/null +++ b/drivers/power/pmic/s5m8767.c @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2015 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +static const struct pmic_child_info pmic_children_info[] = { + { .prefix = "LDO", .driver = S5M8767_LDO_DRIVER }, + { .prefix = "BUCK", .driver = S5M8767_BUCK_DRIVER }, + { }, +}; + +static int s5m8767_reg_count(struct udevice *dev) +{ + return S5M8767_NUM_OF_REGS; +} + +static int s5m8767_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + if (dm_i2c_write(dev, reg, buff, len)) { + error("write error to device: %p register: %#x!", dev, reg); + return -EIO; + } + + return 0; +} + +static int s5m8767_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + if (dm_i2c_read(dev, reg, buff, len)) { + error("read error from device: %p register: %#x!", dev, reg); + return -EIO; + } + + return 0; +} + +int s5m8767_enable_32khz_cp(struct udevice *dev) +{ + return pmic_clrsetbits(dev, S5M8767_EN32KHZ_CP, 0, 1 << 1); +} + +static int s5m8767_bind(struct udevice *dev) +{ + int node; + const void *blob = gd->fdt_blob; + int children; + + node = fdt_subnode_offset(blob, dev->of_offset, "regulators"); + if (node <= 0) { + debug("%s: %s regulators subnode not found!", __func__, + dev->name); + return -ENXIO; + } + + debug("%s: '%s' - found regulators subnode\n", __func__, dev->name); + + children = pmic_bind_children(dev, node, pmic_children_info); + if (!children) + debug("%s: %s - no child found\n", __func__, dev->name); + + /* Always return success for this device */ + return 0; +} + +static struct dm_pmic_ops s5m8767_ops = { + .reg_count = s5m8767_reg_count, + .read = s5m8767_read, + .write = s5m8767_write, +}; + +static const struct udevice_id s5m8767_ids[] = { + { .compatible = "samsung,s5m8767-pmic" }, + { } +}; + +U_BOOT_DRIVER(pmic_s5m8767) = { + .name = "s5m8767_pmic", + .id = UCLASS_PMIC, + .of_match = s5m8767_ids, + .bind = s5m8767_bind, + .ops = &s5m8767_ops, +}; -- cgit From f615e6a64d23952d3c68b9ac92b4ef5fa5ebdf8a Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 2 Jul 2015 18:16:01 -0600 Subject: dm: power: Add support for S5M8767 regulators This PMIC is used with SoCs which need a combination of BUCKs and LDOs. The driver supports changing voltage and enabling/disabling each regulator. It supports the standard device tree binding and supports driver model. Signed-off-by: Simon Glass Acked-by: Przemyslaw Marczak --- drivers/power/regulator/Kconfig | 9 ++ drivers/power/regulator/Makefile | 1 + drivers/power/regulator/s5m8767.c | 269 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 279 insertions(+) create mode 100644 drivers/power/regulator/s5m8767.c (limited to 'drivers/power') diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig index d0906501d0..e85c69231e 100644 --- a/drivers/power/regulator/Kconfig +++ b/drivers/power/regulator/Kconfig @@ -32,6 +32,15 @@ config DM_REGULATOR_FIXED features for fixed value regulators. The driver implements get/set api for enable and get only for voltage value. +config REGULATOR_S5M8767 + bool "Enable support for S5M8767 regulator" + depends on DM_REGULATOR && PMIC_S5M8767 + ---help--- + This enables the regulator features of the S5M8767, allowing voltages + to be set, etc. The driver is not fully complete but supports most + common requirements, including all LDOs and BUCKs. This allows many + supplies to be set automatically using the device tree values. + config DM_REGULATOR_SANDBOX bool "Enable Driver Model for Sandbox PMIC regulator" depends on DM_REGULATOR && DM_PMIC_SANDBOX diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile index 43f4d2ce43..08d7b0d26d 100644 --- a/drivers/power/regulator/Makefile +++ b/drivers/power/regulator/Makefile @@ -8,5 +8,6 @@ obj-$(CONFIG_DM_REGULATOR) += regulator-uclass.o obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.o obj-$(CONFIG_DM_REGULATOR_FIXED) += fixed.o +obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o obj-$(CONFIG_DM_REGULATOR_SANDBOX) += sandbox.o obj-$(CONFIG_REGULATOR_TPS65090) += tps65090_regulator.o diff --git a/drivers/power/regulator/s5m8767.c b/drivers/power/regulator/s5m8767.c new file mode 100644 index 0000000000..93a3c942d1 --- /dev/null +++ b/drivers/power/regulator/s5m8767.c @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2015 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +static const struct sec_voltage_desc buck_v1 = { + .max = 2225000, + .min = 650000, + .step = 6250, +}; + +static const struct sec_voltage_desc buck_v2 = { + .max = 1600000, + .min = 600000, + .step = 6250, +}; + +static const struct sec_voltage_desc buck_v3 = { + .max = 3000000, + .min = 750000, + .step = 12500, +}; + +static const struct sec_voltage_desc ldo_v1 = { + .max = 3950000, + .min = 800000, + .step = 50000, +}; + +static const struct sec_voltage_desc ldo_v2 = { + .max = 2375000, + .min = 800000, + .step = 25000, +}; + +static const struct s5m8767_para buck_param[] = { + /* + * | voltage ----| | enable -| voltage + * regnum addr bpos mask addr on desc + */ + {S5M8767_BUCK1, 0x33, 0x0, 0xff, 0x32, 0x3, &buck_v1}, + {S5M8767_BUCK2, 0x35, 0x0, 0xff, 0x34, 0x1, &buck_v2}, + {S5M8767_BUCK3, 0x3e, 0x0, 0xff, 0x3d, 0x1, &buck_v2}, + {S5M8767_BUCK4, 0x47, 0x0, 0xff, 0x46, 0x1, &buck_v2}, + {S5M8767_BUCK5, 0x50, 0x0, 0xff, 0x4f, 0x3, &buck_v1}, + {S5M8767_BUCK6, 0x55, 0x0, 0xff, 0x54, 0x3, &buck_v1}, + {S5M8767_BUCK7, 0x57, 0x0, 0xff, 0x56, 0x3, &buck_v3}, + {S5M8767_BUCK8, 0x59, 0x0, 0xff, 0x58, 0x3, &buck_v3}, + {S5M8767_BUCK9, 0x5b, 0x0, 0xff, 0x5a, 0x3, &buck_v3}, +}; + +static const struct s5m8767_para ldo_param[] = { + {S5M8767_LDO1, 0x5c, 0x0, 0x3f, 0x5c, 0x3, &ldo_v2}, + {S5M8767_LDO2, 0x5d, 0x0, 0x3f, 0x5d, 0x1, &ldo_v2}, + {S5M8767_LDO3, 0x61, 0x0, 0x3f, 0x61, 0x3, &ldo_v1}, + {S5M8767_LDO4, 0x62, 0x0, 0x3f, 0x62, 0x3, &ldo_v1}, + {S5M8767_LDO5, 0x63, 0x0, 0x3f, 0x63, 0x3, &ldo_v1}, + {S5M8767_LDO6, 0x64, 0x0, 0x3f, 0x64, 0x1, &ldo_v2}, + {S5M8767_LDO7, 0x65, 0x0, 0x3f, 0x65, 0x1, &ldo_v2}, + {S5M8767_LDO8, 0x66, 0x0, 0x3f, 0x66, 0x1, &ldo_v2}, + {S5M8767_LDO9, 0x67, 0x0, 0x3f, 0x67, 0x3, &ldo_v1}, + {S5M8767_LDO10, 0x68, 0x0, 0x3f, 0x68, 0x1, &ldo_v1}, + {S5M8767_LDO11, 0x69, 0x0, 0x3f, 0x69, 0x1, &ldo_v1}, + {S5M8767_LDO12, 0x6a, 0x0, 0x3f, 0x6a, 0x1, &ldo_v1}, + {S5M8767_LDO13, 0x6b, 0x0, 0x3f, 0x6b, 0x3, &ldo_v1}, + {S5M8767_LDO14, 0x6c, 0x0, 0x3f, 0x6c, 0x1, &ldo_v1}, + {S5M8767_LDO15, 0x6d, 0x0, 0x3f, 0x6d, 0x1, &ldo_v2}, + {S5M8767_LDO16, 0x6e, 0x0, 0x3f, 0x6e, 0x1, &ldo_v1}, + {S5M8767_LDO17, 0x6f, 0x0, 0x3f, 0x6f, 0x3, &ldo_v1}, + {S5M8767_LDO18, 0x70, 0x0, 0x3f, 0x70, 0x3, &ldo_v1}, + {S5M8767_LDO19, 0x71, 0x0, 0x3f, 0x71, 0x3, &ldo_v1}, + {S5M8767_LDO20, 0x72, 0x0, 0x3f, 0x72, 0x3, &ldo_v1}, + {S5M8767_LDO21, 0x73, 0x0, 0x3f, 0x73, 0x3, &ldo_v1}, + {S5M8767_LDO22, 0x74, 0x0, 0x3f, 0x74, 0x3, &ldo_v1}, + {S5M8767_LDO23, 0x75, 0x0, 0x3f, 0x75, 0x3, &ldo_v1}, + {S5M8767_LDO24, 0x76, 0x0, 0x3f, 0x76, 0x3, &ldo_v1}, + {S5M8767_LDO25, 0x77, 0x0, 0x3f, 0x77, 0x3, &ldo_v1}, + {S5M8767_LDO26, 0x78, 0x0, 0x3f, 0x78, 0x3, &ldo_v1}, + {S5M8767_LDO27, 0x79, 0x0, 0x3f, 0x79, 0x3, &ldo_v1}, + {S5M8767_LDO28, 0x7a, 0x0, 0x3f, 0x7a, 0x3, &ldo_v1}, +}; + +enum { + ENABLE_SHIFT = 6, + ENABLE_MASK = 3, +}; + +static int reg_get_value(struct udevice *dev, const struct s5m8767_para *param) +{ + const struct sec_voltage_desc *desc; + int ret, uv, val; + + ret = pmic_reg_read(dev->parent, param->vol_addr); + if (ret < 0) + return ret; + + desc = param->vol; + val = (ret >> param->vol_bitpos) & param->vol_bitmask; + uv = desc->min + val * desc->step; + + return uv; +} + +static int reg_set_value(struct udevice *dev, const struct s5m8767_para *param, + int uv) +{ + const struct sec_voltage_desc *desc; + int ret, val; + + desc = param->vol; + if (uv < desc->min || uv > desc->max) + return -EINVAL; + val = (uv - desc->min) / desc->step; + val = (val & param->vol_bitmask) << param->vol_bitpos; + ret = pmic_clrsetbits(dev->parent, param->vol_addr, + param->vol_bitmask << param->vol_bitpos, + val); + + return ret; +} + +static int s5m8767_ldo_probe(struct udevice *dev) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + + uc_pdata = dev_get_uclass_platdata(dev); + + uc_pdata->type = REGULATOR_TYPE_LDO; + uc_pdata->mode_count = 0; + + return 0; +} +static int ldo_get_value(struct udevice *dev) +{ + int ldo = dev->driver_data; + + return reg_get_value(dev, &ldo_param[ldo]); +} + +static int ldo_set_value(struct udevice *dev, int uv) +{ + int ldo = dev->driver_data; + + return reg_set_value(dev, &ldo_param[ldo], uv); +} + +static int reg_get_enable(struct udevice *dev, const struct s5m8767_para *param) +{ + bool enable; + int ret; + + ret = pmic_reg_read(dev->parent, param->reg_enaddr); + if (ret < 0) + return ret; + + enable = (ret >> ENABLE_SHIFT) & ENABLE_MASK; + + return enable; +} + +static int reg_set_enable(struct udevice *dev, const struct s5m8767_para *param, + bool enable) +{ + int ret; + + ret = pmic_reg_read(dev->parent, param->reg_enaddr); + if (ret < 0) + return ret; + + ret = pmic_clrsetbits(dev->parent, param->reg_enaddr, + ENABLE_MASK << ENABLE_SHIFT, + enable ? param->reg_enbiton << ENABLE_SHIFT : 0); + + return ret; +} + +static bool ldo_get_enable(struct udevice *dev) +{ + int ldo = dev->driver_data; + + return reg_get_enable(dev, &ldo_param[ldo]); +} + +static int ldo_set_enable(struct udevice *dev, bool enable) +{ + int ldo = dev->driver_data; + + return reg_set_enable(dev, &ldo_param[ldo], enable); +} + +static int s5m8767_buck_probe(struct udevice *dev) +{ + struct dm_regulator_uclass_platdata *uc_pdata; + + uc_pdata = dev_get_uclass_platdata(dev); + + uc_pdata->type = REGULATOR_TYPE_BUCK; + uc_pdata->mode_count = 0; + + return 0; +} + +static int buck_get_value(struct udevice *dev) +{ + int buck = dev->driver_data; + + return reg_get_value(dev, &buck_param[buck]); +} + +static int buck_set_value(struct udevice *dev, int uv) +{ + int buck = dev->driver_data; + + return reg_set_value(dev, &buck_param[buck], uv); +} + +static bool buck_get_enable(struct udevice *dev) +{ + int buck = dev->driver_data; + + return reg_get_enable(dev, &buck_param[buck]); +} + +static int buck_set_enable(struct udevice *dev, bool enable) +{ + int buck = dev->driver_data; + + return reg_set_enable(dev, &buck_param[buck], enable); +} + +static const struct dm_regulator_ops s5m8767_ldo_ops = { + .get_value = ldo_get_value, + .set_value = ldo_set_value, + .get_enable = ldo_get_enable, + .set_enable = ldo_set_enable, +}; + +U_BOOT_DRIVER(s5m8767_ldo) = { + .name = S5M8767_LDO_DRIVER, + .id = UCLASS_REGULATOR, + .ops = &s5m8767_ldo_ops, + .probe = s5m8767_ldo_probe, +}; + +static const struct dm_regulator_ops s5m8767_buck_ops = { + .get_value = buck_get_value, + .set_value = buck_set_value, + .get_enable = buck_get_enable, + .set_enable = buck_set_enable, +}; + +U_BOOT_DRIVER(s5m8767_buck) = { + .name = S5M8767_BUCK_DRIVER, + .id = UCLASS_REGULATOR, + .ops = &s5m8767_buck_ops, + .probe = s5m8767_buck_probe, +}; -- cgit From b5ffa4fdcb656b8995d6800f9c10dad76a44d38b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 2 Jul 2015 18:16:02 -0600 Subject: dm: pmic: max77686: Correct a few nits The driver name should not have a space in it. Also the regulator names should match the case of the device tree. Fix these problems. Signed-off-by: Simon Glass Acked-by: Przemyslaw Marczak --- drivers/power/pmic/max77686.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/power') diff --git a/drivers/power/pmic/max77686.c b/drivers/power/pmic/max77686.c index 3523b4a2de..dc5a54a6a3 100644 --- a/drivers/power/pmic/max77686.c +++ b/drivers/power/pmic/max77686.c @@ -17,8 +17,8 @@ DECLARE_GLOBAL_DATA_PTR; static const struct pmic_child_info pmic_children_info[] = { - { .prefix = "ldo", .driver = MAX77686_LDO_DRIVER }, - { .prefix = "buck", .driver = MAX77686_BUCK_DRIVER }, + { .prefix = "LDO", .driver = MAX77686_LDO_DRIVER }, + { .prefix = "BUCK", .driver = MAX77686_BUCK_DRIVER }, { }, }; @@ -84,7 +84,7 @@ static const struct udevice_id max77686_ids[] = { }; U_BOOT_DRIVER(pmic_max77686) = { - .name = "max77686 pmic", + .name = "max77686_pmic", .id = UCLASS_PMIC, .of_match = max77686_ids, .bind = max77686_bind, -- cgit From cd367d89979c0476e2fcbca445a49008b372872b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 2 Jul 2015 18:16:03 -0600 Subject: dm: pmic: Correct the pmic_reg_write() implementation This should write the register, not read it. Fix this bug. Signed-off-by: Simon Glass Acked-by: Przemyslaw Marczak --- drivers/power/pmic/pmic-uclass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/power') diff --git a/drivers/power/pmic/pmic-uclass.c b/drivers/power/pmic/pmic-uclass.c index d99cb9aada..49709f3084 100644 --- a/drivers/power/pmic/pmic-uclass.c +++ b/drivers/power/pmic/pmic-uclass.c @@ -142,7 +142,7 @@ int pmic_reg_write(struct udevice *dev, uint reg, uint value) u8 byte = value; debug("%s: reg=%x, value=%x\n", __func__, reg, value); - return pmic_read(dev, reg, &byte, 1); + return pmic_write(dev, reg, &byte, 1); } int pmic_clrsetbits(struct udevice *dev, uint reg, uint clr, uint set) -- cgit From 8c4287090cc9bfa172370976c77b420d9c37f94c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 2 Jul 2015 18:16:04 -0600 Subject: dm: power: max77686: Correct BUCK register access Some regulators use the wrong voltage register and thus it is not possible to control them. Fix this. Signed-off-by: Simon Glass Acked-by: Przemyslaw Marczak --- drivers/power/regulator/max77686.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/power') diff --git a/drivers/power/regulator/max77686.c b/drivers/power/regulator/max77686.c index 37ebe94521..21173fc3ee 100644 --- a/drivers/power/regulator/max77686.c +++ b/drivers/power/regulator/max77686.c @@ -61,10 +61,14 @@ static struct dm_regulator_mode max77686_buck_mode_onoff[] = { MODE(OPMODE_ON, MAX77686_BUCK_MODE_ON, "ON"), }; -static const char max77686_buck_addr[] = { +static const char max77686_buck_ctrl[] = { 0xff, 0x10, 0x12, 0x1c, 0x26, 0x30, 0x32, 0x34, 0x36, 0x38 }; +static const char max77686_buck_out[] = { + 0xff, 0x11, 0x14, 0x1e, 0x28, 0x31, 0x33, 0x35, 0x37, 0x39 +}; + static int max77686_buck_volt2hex(int buck, int uV) { unsigned int hex = 0; @@ -368,7 +372,7 @@ static int max77686_buck_val(struct udevice *dev, int op, int *uV) *uV = 0; /* &buck_out = ctrl + 1 */ - adr = max77686_buck_addr[buck] + 1; + adr = max77686_buck_out[buck]; /* mask */ switch (buck) { @@ -549,7 +553,7 @@ static int max77686_buck_mode(struct udevice *dev, int op, int *opmode) return -EINVAL; } - adr = max77686_buck_addr[buck]; + adr = max77686_buck_ctrl[buck]; /* mask */ switch (buck) { -- cgit From 75a429f1a299cf4cd4ab3f18eb75a7eb632776c9 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 3 Aug 2015 08:19:25 -0600 Subject: dm: pmic: max77686: Support all BUCK regulators Add support for all BUCK regulators, now that the correct register is accessed for each. Signed-off-by: Simon Glass --- drivers/power/regulator/max77686.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'drivers/power') diff --git a/drivers/power/regulator/max77686.c b/drivers/power/regulator/max77686.c index 21173fc3ee..946b87c60a 100644 --- a/drivers/power/regulator/max77686.c +++ b/drivers/power/regulator/max77686.c @@ -81,13 +81,15 @@ static int max77686_buck_volt2hex(int buck, int uV) /* hex = (uV - 600000) / 12500; */ hex = (uV - MAX77686_BUCK_UV_LMIN) / MAX77686_BUCK_UV_LSTEP; hex_max = MAX77686_BUCK234_VOLT_MAX_HEX; - /** - * Those use voltage scaller - temporary not implemented - * so return just 0 - */ - return -ENOSYS; + break; default: - /* hex = (uV - 750000) / 50000; */ + /* + * hex = (uV - 750000) / 50000. We assume that dynamic voltage + * scaling via GPIOs is not enabled and don't support that. + * If this is enabled then the driver will need to take that + * into account anrd check different registers depending on + * the current setting See the datasheet for details. + */ hex = (uV - MAX77686_BUCK_UV_HMIN) / MAX77686_BUCK_UV_HSTEP; hex_max = MAX77686_BUCK_VOLT_MAX_HEX; break; @@ -379,11 +381,11 @@ static int max77686_buck_val(struct udevice *dev, int op, int *uV) case 2: case 3: case 4: - /* Those use voltage scallers - will support in the future */ mask = MAX77686_BUCK234_VOLT_MASK; - return -ENOSYS; + break; default: mask = MAX77686_BUCK_VOLT_MASK; + break; } ret = pmic_read(dev->parent, adr, &val, 1); -- cgit From d08504d18a0a6af2ba6171a4a3e71a032d2836b6 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 2 Jul 2015 18:16:06 -0600 Subject: dm: power: Don't return an error when regulators are not autoset Not all regulators can be set up automatically. Adjust the code so that regulators_enable_boot_on() will return success when some are skipped. Only genuine errors are reported. Signed-off-by: Simon Glass Acked-by: Przemyslaw Marczak --- drivers/power/regulator/regulator-uclass.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/power') diff --git a/drivers/power/regulator/regulator-uclass.c b/drivers/power/regulator/regulator-uclass.c index 12e141b4ad..f3fe7a55e1 100644 --- a/drivers/power/regulator/regulator-uclass.c +++ b/drivers/power/regulator/regulator-uclass.c @@ -319,8 +319,10 @@ int regulators_enable_boot_on(bool verbose) dev && !ret; uclass_next_device(&dev)) { ret = regulator_autoset(dev); - if (ret == -EMEDIUMTYPE) + if (ret == -EMEDIUMTYPE) { + ret = 0; continue; + } if (verbose) regulator_show(dev, ret); } -- cgit From 05bccbcd761e7170e236c982915781b143051abb Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 3 Aug 2015 08:19:32 -0600 Subject: power: Remove old TPS65090 drivers Remove the old drivers (both the normal one and the cros_ec one) now that we have new drivers that use driver model. Signed-off-by: Simon Glass --- drivers/power/pmic/Makefile | 2 - drivers/power/pmic/pmic_tps65090.c | 310 ---------------------------------- drivers/power/pmic/pmic_tps65090_ec.c | 218 ------------------------ 3 files changed, 530 deletions(-) delete mode 100644 drivers/power/pmic/pmic_tps65090.c delete mode 100644 drivers/power/pmic/pmic_tps65090_ec.c (limited to 'drivers/power') diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index 322c2c6cac..6ef149aee7 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -18,8 +18,6 @@ obj-$(CONFIG_POWER_MAX8997) += pmic_max8997.o obj-$(CONFIG_POWER_MUIC_MAX8997) += muic_max8997.o obj-$(CONFIG_POWER_MAX77686) += pmic_max77686.o obj-$(CONFIG_POWER_PFUZE100) += pmic_pfuze100.o -obj-$(CONFIG_POWER_TPS65090_I2C) += pmic_tps65090.o -obj-$(CONFIG_POWER_TPS65090_EC) += pmic_tps65090_ec.o obj-$(CONFIG_POWER_TPS65217) += pmic_tps65217.o obj-$(CONFIG_POWER_TPS65218) += pmic_tps62362.o obj-$(CONFIG_POWER_TPS65218) += pmic_tps65218.o diff --git a/drivers/power/pmic/pmic_tps65090.c b/drivers/power/pmic/pmic_tps65090.c deleted file mode 100644 index 337903acec..0000000000 --- a/drivers/power/pmic/pmic_tps65090.c +++ /dev/null @@ -1,310 +0,0 @@ -/* - * Copyright (c) 2012 The Chromium OS Authors. - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include -#include -#include - -DECLARE_GLOBAL_DATA_PTR; - -#define TPS65090_NAME "TPS65090_PMIC" - -/* TPS65090 register addresses */ -enum { - REG_IRQ1 = 0, - REG_CG_CTRL0 = 4, - REG_CG_STATUS1 = 0xa, - REG_FET1_CTRL = 0x0f, - REG_FET2_CTRL, - REG_FET3_CTRL, - REG_FET4_CTRL, - REG_FET5_CTRL, - REG_FET6_CTRL, - REG_FET7_CTRL, - TPS65090_NUM_REGS, -}; - -enum { - IRQ1_VBATG = 1 << 3, - CG_CTRL0_ENC_MASK = 0x01, - - MAX_FET_NUM = 7, - MAX_CTRL_READ_TRIES = 5, - - /* TPS65090 FET_CTRL register values */ - FET_CTRL_TOFET = 1 << 7, /* Timeout, startup, overload */ - FET_CTRL_PGFET = 1 << 4, /* Power good for FET status */ - FET_CTRL_WAIT = 3 << 2, /* Overcurrent timeout max */ - FET_CTRL_ADENFET = 1 << 1, /* Enable output auto discharge */ - FET_CTRL_ENFET = 1 << 0, /* Enable FET */ -}; - -/** - * Checks for a valid FET number - * - * @param fet_id FET number to check - * @return 0 if ok, -EINVAL if FET value is out of range - */ -static int tps65090_check_fet(unsigned int fet_id) -{ - if (fet_id == 0 || fet_id > MAX_FET_NUM) { - debug("parameter fet_id is out of range, %u not in 1 ~ %u\n", - fet_id, MAX_FET_NUM); - return -EINVAL; - } - - return 0; -} - -/** - * Set the power state for a FET - * - * @param pmic pmic structure for the tps65090 - * @param fet_id Fet number to set (1..MAX_FET_NUM) - * @param set 1 to power on FET, 0 to power off - * @return -EIO if we got a comms error, -EAGAIN if the FET failed to - * change state. If all is ok, returns 0. - */ -static int tps65090_fet_set(struct pmic *pmic, int fet_id, bool set) -{ - int retry; - u32 reg, value; - - value = FET_CTRL_ADENFET | FET_CTRL_WAIT; - if (set) - value |= FET_CTRL_ENFET; - - if (pmic_reg_write(pmic, REG_FET1_CTRL + fet_id - 1, value)) - return -EIO; - - /* Try reading until we get a result */ - for (retry = 0; retry < MAX_CTRL_READ_TRIES; retry++) { - if (pmic_reg_read(pmic, REG_FET1_CTRL + fet_id - 1, ®)) - return -EIO; - - /* Check that the fet went into the expected state */ - if (!!(reg & FET_CTRL_PGFET) == set) - return 0; - - /* If we got a timeout, there is no point in waiting longer */ - if (reg & FET_CTRL_TOFET) - break; - - mdelay(1); - } - - debug("FET %d: Power good should have set to %d but reg=%#02x\n", - fet_id, set, reg); - return -EAGAIN; -} - -int tps65090_fet_enable(unsigned int fet_id) -{ - struct pmic *pmic; - ulong start; - int loops; - int ret; - - ret = tps65090_check_fet(fet_id); - if (ret) - return ret; - - pmic = pmic_get(TPS65090_NAME); - if (!pmic) - return -EACCES; - - start = get_timer(0); - for (loops = 0;; loops++) { - ret = tps65090_fet_set(pmic, fet_id, true); - if (!ret) - break; - - if (get_timer(start) > 100) - break; - - /* Turn it off and try again until we time out */ - tps65090_fet_set(pmic, fet_id, false); - } - - if (ret) - debug("%s: FET%d failed to power on: time=%lums, loops=%d\n", - __func__, fet_id, get_timer(start), loops); - else if (loops) - debug("%s: FET%d powered on after %lums, loops=%d\n", - __func__, fet_id, get_timer(start), loops); - - /* - * Unfortunately, there are some conditions where the power - * good bit will be 0, but the fet still comes up. One such - * case occurs with the lcd backlight. We'll just return 0 here - * and assume that the fet will eventually come up. - */ - if (ret == -EAGAIN) - ret = 0; - - return ret; -} - -int tps65090_fet_disable(unsigned int fet_id) -{ - struct pmic *pmic; - int ret; - - ret = tps65090_check_fet(fet_id); - if (ret) - return ret; - - pmic = pmic_get(TPS65090_NAME); - if (!pmic) - return -EACCES; - ret = tps65090_fet_set(pmic, fet_id, false); - - return ret; -} - -int tps65090_fet_is_enabled(unsigned int fet_id) -{ - struct pmic *pmic; - u32 reg; - int ret; - - ret = tps65090_check_fet(fet_id); - if (ret) - return ret; - - pmic = pmic_get(TPS65090_NAME); - if (!pmic) - return -ENODEV; - ret = pmic_reg_read(pmic, REG_FET1_CTRL + fet_id - 1, ®); - if (ret) { - debug("fail to read FET%u_CTRL register over I2C", fet_id); - return -EIO; - } - - return reg & FET_CTRL_ENFET; -} - -int tps65090_get_charging(void) -{ - struct pmic *pmic; - u32 val; - int ret; - - pmic = pmic_get(TPS65090_NAME); - if (!pmic) - return -EACCES; - - ret = pmic_reg_read(pmic, REG_CG_CTRL0, &val); - if (ret) - return ret; - - return !!(val & CG_CTRL0_ENC_MASK); -} - -static int tps65090_charger_state(struct pmic *pmic, int state, - int current) -{ - u32 val; - int ret; - - ret = pmic_reg_read(pmic, REG_CG_CTRL0, &val); - if (!ret) { - if (state == PMIC_CHARGER_ENABLE) - val |= CG_CTRL0_ENC_MASK; - else - val &= ~CG_CTRL0_ENC_MASK; - ret = pmic_reg_write(pmic, REG_CG_CTRL0, val); - } - if (ret) { - debug("%s: Failed to read/write register\n", __func__); - return ret; - } - - return 0; -} - -int tps65090_get_status(void) -{ - struct pmic *pmic; - u32 val; - int ret; - - pmic = pmic_get(TPS65090_NAME); - if (!pmic) - return -EACCES; - - ret = pmic_reg_read(pmic, REG_CG_STATUS1, &val); - if (ret) - return ret; - - return val; -} - -static int tps65090_charger_bat_present(struct pmic *pmic) -{ - u32 val; - int ret; - - ret = pmic_reg_read(pmic, REG_IRQ1, &val); - if (ret) - return ret; - - return !!(val & IRQ1_VBATG); -} - -static struct power_chrg power_chrg_pmic_ops = { - .chrg_bat_present = tps65090_charger_bat_present, - .chrg_state = tps65090_charger_state, -}; - -int tps65090_init(void) -{ - struct pmic *p; - int bus; - int addr; - const void *blob = gd->fdt_blob; - int node, parent; - - node = fdtdec_next_compatible(blob, 0, COMPAT_TI_TPS65090); - if (node < 0) { - debug("PMIC: No node for PMIC Chip in device tree\n"); - debug("node = %d\n", node); - return -ENODEV; - } - - parent = fdt_parent_offset(blob, node); - if (parent < 0) { - debug("%s: Cannot find node parent\n", __func__); - return -EINVAL; - } - - bus = i2c_get_bus_num_fdt(parent); - if (bus < 0) { - debug("%s: Cannot find I2C bus\n", __func__); - return -ENOENT; - } - addr = fdtdec_get_int(blob, node, "reg", TPS65090_I2C_ADDR); - p = pmic_alloc(); - if (!p) { - printf("%s: POWER allocation error!\n", __func__); - return -ENOMEM; - } - - p->name = TPS65090_NAME; - p->bus = bus; - p->interface = PMIC_I2C; - p->number_of_regs = TPS65090_NUM_REGS; - p->hw.i2c.addr = addr; - p->hw.i2c.tx_num = 1; - p->chrg = &power_chrg_pmic_ops; - - puts("TPS65090 PMIC init\n"); - - return 0; -} diff --git a/drivers/power/pmic/pmic_tps65090_ec.c b/drivers/power/pmic/pmic_tps65090_ec.c deleted file mode 100644 index f79a8782c9..0000000000 --- a/drivers/power/pmic/pmic_tps65090_ec.c +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (c) 2013 The Chromium OS Authors. - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include - -DECLARE_GLOBAL_DATA_PTR; - -#define TPS65090_ADDR 0x48 - -static struct tps65090 { - struct cros_ec_dev *dev; /* The CROS_EC device */ -} config; - -/* TPS65090 register addresses */ -enum { - REG_IRQ1 = 0, - REG_CG_CTRL0 = 4, - REG_CG_STATUS1 = 0xa, - REG_FET1_CTRL = 0x0f, - REG_FET2_CTRL, - REG_FET3_CTRL, - REG_FET4_CTRL, - REG_FET5_CTRL, - REG_FET6_CTRL, - REG_FET7_CTRL, - TPS65090_NUM_REGS, -}; - -enum { - IRQ1_VBATG = 1 << 3, - CG_CTRL0_ENC_MASK = 0x01, - - MAX_FET_NUM = 7, - MAX_CTRL_READ_TRIES = 5, - - /* TPS65090 FET_CTRL register values */ - FET_CTRL_TOFET = 1 << 7, /* Timeout, startup, overload */ - FET_CTRL_PGFET = 1 << 4, /* Power good for FET status */ - FET_CTRL_WAIT = 3 << 2, /* Overcurrent timeout max */ - FET_CTRL_ADENFET = 1 << 1, /* Enable output auto discharge */ - FET_CTRL_ENFET = 1 << 0, /* Enable FET */ -}; - -/** - * tps65090_read - read a byte from tps6090 - * - * @param reg The register address to read from. - * @param val We'll return value value read here. - * @return 0 if ok; error if EC returns failure. - */ -static int tps65090_read(u32 reg, u8 *val) -{ - return cros_ec_i2c_xfer_old(config.dev, TPS65090_ADDR, reg, 1, - val, 1, true); -} - -/** - * tps65090_write - write a byte to tps6090 - * - * @param reg The register address to write to. - * @param val The value to write. - * @return 0 if ok; error if EC returns failure. - */ -static int tps65090_write(u32 reg, u8 val) -{ - return cros_ec_i2c_xfer_old(config.dev, TPS65090_ADDR, reg, 1, - &val, 1, false); -} - -/** - * Checks for a valid FET number - * - * @param fet_id FET number to check - * @return 0 if ok, -EINVAL if FET value is out of range - */ -static int tps65090_check_fet(unsigned int fet_id) -{ - if (fet_id == 0 || fet_id > MAX_FET_NUM) { - debug("parameter fet_id is out of range, %u not in 1 ~ %u\n", - fet_id, MAX_FET_NUM); - return -EINVAL; - } - - return 0; -} - -/** - * Set the power state for a FET - * - * @param fet_id Fet number to set (1..MAX_FET_NUM) - * @param set 1 to power on FET, 0 to power off - * @return -EIO if we got a comms error, -EAGAIN if the FET failed to - * change state. If all is ok, returns 0. - */ -static int tps65090_fet_set(int fet_id, bool set) -{ - int retry; - u8 reg, value; - - value = FET_CTRL_ADENFET | FET_CTRL_WAIT; - if (set) - value |= FET_CTRL_ENFET; - - if (tps65090_write(REG_FET1_CTRL + fet_id - 1, value)) - return -EIO; - - /* Try reading until we get a result */ - for (retry = 0; retry < MAX_CTRL_READ_TRIES; retry++) { - if (tps65090_read(REG_FET1_CTRL + fet_id - 1, ®)) - return -EIO; - - /* Check that the fet went into the expected state */ - if (!!(reg & FET_CTRL_PGFET) == set) - return 0; - - /* If we got a timeout, there is no point in waiting longer */ - if (reg & FET_CTRL_TOFET) - break; - - mdelay(1); - } - - debug("FET %d: Power good should have set to %d but reg=%#02x\n", - fet_id, set, reg); - return -EAGAIN; -} - -int tps65090_fet_enable(unsigned int fet_id) -{ - ulong start; - int loops; - int ret; - - ret = tps65090_check_fet(fet_id); - if (ret) - return ret; - - start = get_timer(0); - for (loops = 0;; loops++) { - ret = tps65090_fet_set(fet_id, true); - if (!ret) - break; - - if (get_timer(start) > 100) - break; - - /* Turn it off and try again until we time out */ - tps65090_fet_set(fet_id, false); - } - - if (ret) { - debug("%s: FET%d failed to power on: time=%lums, loops=%d\n", - __func__, fet_id, get_timer(start), loops); - } else if (loops) { - debug("%s: FET%d powered on after %lums, loops=%d\n", - __func__, fet_id, get_timer(start), loops); - } - /* - * Unfortunately, there are some conditions where the power - * good bit will be 0, but the fet still comes up. One such - * case occurs with the lcd backlight. We'll just return 0 here - * and assume that the fet will eventually come up. - */ - if (ret == -EAGAIN) - ret = 0; - - return ret; -} - -int tps65090_fet_disable(unsigned int fet_id) -{ - int ret; - - ret = tps65090_check_fet(fet_id); - if (ret) - return ret; - - ret = tps65090_fet_set(fet_id, false); - - return ret; -} - -int tps65090_fet_is_enabled(unsigned int fet_id) -{ - u8 reg = 0; - int ret; - - ret = tps65090_check_fet(fet_id); - if (ret) - return ret; - ret = tps65090_read(REG_FET1_CTRL + fet_id - 1, ®); - if (ret) { - debug("fail to read FET%u_CTRL register over I2C", fet_id); - return -EIO; - } - - return reg & FET_CTRL_ENFET; -} - -int tps65090_init(void) -{ - puts("TPS65090 PMIC EC init\n"); - - config.dev = board_get_cros_ec_dev(); - if (!config.dev) { - debug("%s: no cros_ec device: cannot init tps65090\n", - __func__); - return -ENODEV; - } - - return 0; -} -- cgit