[U-Boot] [PATCH] power: pmic/regulator: Add basic support for TPS65910

Felix Brack fb at ltec.ch
Wed Nov 8 11:04:39 UTC 2017


Texas Instrument's TPS65910 PMIC contains 3 buck DC-DC converts, one
boost DC-DC converter and 8 LDOs. This patch implements driver model
support for the TPS65910 PMIC and its regulators making the get/set
API for regulator value/enable available.
This patch depends on the patch "am33xx: Add a function to query MPU
voltage in uV" to build correctly. For boards relying on the DT
include file tps65910.dtsi the v2 patch "power: extend prefix match
to regulator-name property" and an appropriate regulator naming is
also required.

Signed-off-by: Felix Brack <fb at ltec.ch>
---

 drivers/power/pmic/Kconfig                   |   8 +
 drivers/power/pmic/Makefile                  |   1 +
 drivers/power/pmic/pmic_tps65910_dm.c        | 138 ++++++++
 drivers/power/regulator/Kconfig              |   7 +
 drivers/power/regulator/Makefile             |   1 +
 drivers/power/regulator/tps65910_regulator.c | 493 +++++++++++++++++++++++++++
 include/power/tps65910_pmic.h                | 130 +++++++
 7 files changed, 778 insertions(+)
 create mode 100644 drivers/power/pmic/pmic_tps65910_dm.c
 create mode 100644 drivers/power/regulator/tps65910_regulator.c
 create mode 100644 include/power/tps65910_pmic.h

diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig
index e3f9e4d..5d49c93 100644
--- a/drivers/power/pmic/Kconfig
+++ b/drivers/power/pmic/Kconfig
@@ -201,3 +201,11 @@ config POWER_MC34VR500
 	The MC34VR500 is used in conjunction with the FSL T1 and LS1 series
 	SoC. It provides 4 buck DC-DC convertors and 5 LDOs, and it is accessed
 	via an I2C interface.
+
+config DM_PMIC_TPS65910
+	bool "Enable driver for Texas Instruments TPS65910 PMIC"
+	depends on DM_PMIC
+	---help---
+	The TPS65910 is a PMIC containing 3 buck DC-DC converters, one boost
+	DC-DC converter, 8 LDOs and a RTC. This driver binds the SMPS and LDO
+	pmic children.
diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile
index f7bdfa5..7d6c583 100644
--- a/drivers/power/pmic/Makefile
+++ b/drivers/power/pmic/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_PMIC_RK8XX) += rk8xx.o
 obj-$(CONFIG_PMIC_RN5T567) += rn5t567.o
 obj-$(CONFIG_PMIC_TPS65090) += tps65090.o
 obj-$(CONFIG_PMIC_S5M8767) += s5m8767.o
+obj-$(CONFIG_DM_PMIC_TPS65910) += pmic_tps65910_dm.o
 obj-$(CONFIG_$(SPL_)PMIC_PALMAS) += palmas.o
 obj-$(CONFIG_$(SPL_)PMIC_LP873X) += lp873x.o
 obj-$(CONFIG_$(SPL_)PMIC_LP87565) += lp87565.o
diff --git a/drivers/power/pmic/pmic_tps65910_dm.c b/drivers/power/pmic/pmic_tps65910_dm.c
new file mode 100644
index 0000000..1410657
--- /dev/null
+++ b/drivers/power/pmic/pmic_tps65910_dm.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) EETS GmbH, 2017, Felix Brack <f.brack at eets.ch>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/tps65910_pmic.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const struct pmic_child_info pmic_children_info[] = {
+	{ .prefix = "ldo_", .driver = TPS65910_LDO_DRIVER },
+	{ .prefix = "buck_", .driver = TPS65910_BUCK_DRIVER },
+	{ .prefix = "boost_", .driver = TPS65910_BOOST_DRIVER },
+	{ },
+};
+
+static const char * const supply_names[] = {
+	"vccio-supply",
+	"vcc1-supply",
+	"vcc2-supply",
+	"vcc3-supply",
+	"vcc4-supply",
+	"vcc5-supply",
+	"vcc6-supply",
+	"vcc7-supply",
+};
+
+static int pmic_tps65910_reg_count(struct udevice *dev)
+{
+	return TPS65910_NUM_REGS;
+}
+
+static int pmic_tps65910_write(struct udevice *dev, uint reg, const u8 *buffer,
+			       int len)
+{
+	if (dm_i2c_write(dev, reg, buffer, len)) {
+		error("%s write error on register %02x\n", dev->name, reg);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int pmic_tps65910_read(struct udevice *dev, uint reg, u8 *buffer,
+			      int len)
+{
+	if (dm_i2c_read(dev, reg, buffer, len)) {
+		error("%s read error on register %02x\n", dev->name, reg);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int pmic_tps65910_bind(struct udevice *dev)
+{
+	ofnode regulators_node;
+	int children;
+
+	regulators_node = dev_read_subnode(dev, "regulators");
+	if (!ofnode_valid(regulators_node)) {
+		debug("%s regulators subnode not found\n", dev->name);
+		return -ENXIO;
+	}
+
+	children = pmic_bind_children(dev, regulators_node, pmic_children_info);
+	if (!children)
+		debug("%s has no children (regulators)\n", dev->name);
+
+	return 0;
+}
+
+static int pmic_tps65910_probe(struct udevice *dev)
+{
+	/* use I2C control interface instead of I2C smartreflex interface to
+	 * access smartrefelex registers VDD1_OP_REG, VDD1_SR_REG, VDD2_OP_REG
+	 * and VDD2_SR_REG
+	 */
+	return pmic_clrsetbits(dev, TPS65910_REG_DEVICE_CTRL, 0,
+			       TPS65910_I2C_SEL_MASK);
+}
+
+static int pmic_tps65910_ofdata_to_platdata(struct udevice *dev)
+{
+	struct tps65910_pdata *pdata = dev->platdata;
+	int i, voltage;
+	const char *supply_name;
+	struct udevice *supply;
+
+	/* for each PMIC regulator get its supply voltage */
+	for (i = TPS65910_SUPPLY_VCCIO; i < TPS65910_NUM_SUPPLIES; i++) {
+		supply_name = *(supply_names + i);
+		debug("Looking up supply power %s\n", supply_name);
+		if (device_get_supply_regulator(dev, supply_name, &supply)) {
+			debug("  missing supply power %s\n", supply_name);
+			continue;
+		}
+		voltage = regulator_get_value(supply);
+		if (voltage < 0) {
+			debug("  invalid supply voltage for regulator %s\n",
+			      supply->name);
+			continue;
+		}
+		*(pdata->supply + i) = voltage;
+		debug("  set to %duV by %s\n", *(pdata->supply + i),
+		      supply->name);
+	}
+
+	return 0;
+}
+
+static struct dm_pmic_ops pmic_tps65910_ops = {
+	.reg_count = pmic_tps65910_reg_count,
+	.read = pmic_tps65910_read,
+	.write = pmic_tps65910_write,
+};
+
+static const struct udevice_id pmic_tps65910_match[] = {
+	{ .compatible = "ti,tps65910" },
+	{ /* sentinel */ }
+};
+
+U_BOOT_DRIVER(pmic_tps65910) = {
+	.name = "pmic_tps65910",
+	.id = UCLASS_PMIC,
+	.of_match = pmic_tps65910_match,
+	.bind = pmic_tps65910_bind,
+	.probe = pmic_tps65910_probe,
+	.ops = &pmic_tps65910_ops,
+	.platdata_auto_alloc_size = sizeof(struct tps65910_pdata),
+	.ofdata_to_platdata = pmic_tps65910_ofdata_to_platdata,
+};
diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig
index c82a936..2d6a150 100644
--- a/drivers/power/regulator/Kconfig
+++ b/drivers/power/regulator/Kconfig
@@ -168,3 +168,10 @@ config DM_REGULATOR_LP87565
 	LP87565 series of PMICs have 4 single phase BUCKs that can also
 	be configured in multi phase modes. The driver implements
 	get/set api for value and enable.
+
+config DM_REGULATOR_TPS65910
+	bool "Enable driver for TPS65910 PMIC regulators"
+	depends on DM_PMIC_TPS65910
+	---help---
+	The TPS65910 PMIC provides 4 SMPSs and 8 LDOs. This driver implements
+	the get/set api for value and enable for these regulators.
diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile
index 18fb870..3eef297 100644
--- a/drivers/power/regulator/Makefile
+++ b/drivers/power/regulator/Makefile
@@ -20,3 +20,4 @@ obj-$(CONFIG_REGULATOR_TPS65090) += tps65090_regulator.o
 obj-$(CONFIG_$(SPL_)DM_REGULATOR_PALMAS) += palmas_regulator.o
 obj-$(CONFIG_$(SPL_)DM_REGULATOR_LP873X) += lp873x_regulator.o
 obj-$(CONFIG_$(SPL_)DM_REGULATOR_LP87565) += lp87565_regulator.o
+obj-$(CONFIG_DM_REGULATOR_TPS65910) += tps65910_regulator.o
diff --git a/drivers/power/regulator/tps65910_regulator.c b/drivers/power/regulator/tps65910_regulator.c
new file mode 100644
index 0000000..d212b70
--- /dev/null
+++ b/drivers/power/regulator/tps65910_regulator.c
@@ -0,0 +1,493 @@
+/*
+ * Copyright (C) EETS GmbH, 2017, Felix Brack <f.brack at eets.ch>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <power/pmic.h>
+#include <power/regulator.h>
+#include <power/tps65910_pmic.h>
+
+#define VOUT_CHOICE_COUNT 4
+
+/*
+ * struct regulator_props - Properties of a LDO and VIO SMPS regulator
+ *
+ * All of these regulators allow setting one out of four output voltages.
+ * These output voltages are only achievable when supplying the regulator
+ * with a minimum input voltage.
+ *
+ * @vin_min[]: minimum supply input voltage in uV required to achieve the
+ *             corresponding vout[] voltage
+ * @vout[]:    regulator output voltage in uV
+ * @reg:       I2C register used to set regulator voltage
+ */
+struct regulator_props {
+	int vin_min[VOUT_CHOICE_COUNT];
+	int vout[VOUT_CHOICE_COUNT];
+	int reg;
+};
+
+static const struct regulator_props ldo_props_vdig1 = {
+	.vin_min = { 1700000, 2100000, 2700000, 3200000 },
+	.vout = { 1200000, 1500000, 1800000, 2700000 },
+	.reg = TPS65910_REG_VDIG1
+};
+
+static const struct regulator_props ldo_props_vdig2 = {
+	.vin_min = { 1700000, 1700000, 1700000, 2700000 },
+	.vout = { 1000000, 1100000, 1200000, 1800000 },
+	.reg = TPS65910_REG_VDIG2
+};
+
+static const struct regulator_props ldo_props_vpll = {
+	.vin_min = { 2700000, 2700000, 2700000, 3000000 },
+	.vout = { 1000000, 1100000, 1800000, 2500000 },
+	.reg = TPS65910_REG_VPLL
+};
+
+static const struct regulator_props ldo_props_vdac = {
+	.vin_min = { 2700000, 3000000, 3200000, 3200000 },
+	.vout = { 1800000, 2600000, 2800000, 2850000 },
+	.reg = TPS65910_REG_VDAC
+};
+
+static const struct regulator_props ldo_props_vaux1 = {
+	.vin_min = { 2700000, 3200000, 3200000, 3200000 },
+	.vout = { 1800000, 2500000, 2800000, 2850000 },
+	.reg = TPS65910_REG_VAUX1
+};
+
+static const struct regulator_props ldo_props_vaux2 = {
+	.vin_min = { 2700000, 3200000, 3200000, 3600000 },
+	.vout = { 1800000, 2800000, 2900000, 3300000 },
+	.reg = TPS65910_REG_VAUX2
+};
+
+static const struct regulator_props ldo_props_vaux33 = {
+	.vin_min = { 2700000, 2700000, 3200000, 3600000 },
+	.vout = { 1800000, 2000000, 2800000, 3300000 },
+	.reg = TPS65910_REG_VAUX33
+};
+
+static const struct regulator_props ldo_props_vmmc = {
+	.vin_min = { 2700000, 3200000, 3200000, 3600000 },
+	.vout = { 1800000, 2800000, 3000000, 3300000 },
+	.reg = TPS65910_REG_VMMC
+};
+
+static const struct regulator_props smps_props_vio = {
+	.vin_min = { 3200000, 3200000, 4000000, 4400000 },
+	.vout = { 1500000, 1800000, 2500000, 3300000 },
+	.reg = TPS65910_REG_VIO
+};
+
+static int get_ctrl_reg_from_unit_addr(const int unit_addr)
+{
+	switch (unit_addr) {
+	case TPS65910_UNIT_VRTC:
+		return TPS65910_REG_VRTC;
+	case TPS65910_UNIT_VIO:
+		return TPS65910_REG_VIO;
+	case TPS65910_UNIT_VDD1:
+		return TPS65910_REG_VDD1;
+	case TPS65910_UNIT_VDD2:
+		return TPS65910_REG_VDD2;
+	case TPS65910_UNIT_VDD3:
+		return TPS65910_REG_VDD3;
+	case TPS65910_UNIT_VDIG1:
+		return TPS65910_REG_VDIG1;
+	case TPS65910_UNIT_VDIG2:
+		return TPS65910_REG_VDIG2;
+	case TPS65910_UNIT_VPLL:
+		return TPS65910_REG_VPLL;
+	case TPS65910_UNIT_VDAC:
+		return TPS65910_REG_VDAC;
+	case TPS65910_UNIT_VAUX1:
+		return TPS65910_REG_VAUX1;
+	case TPS65910_UNIT_VAUX2:
+		return TPS65910_REG_VAUX2;
+	case TPS65910_UNIT_VAUX33:
+		return TPS65910_REG_VAUX33;
+	case TPS65910_UNIT_VMMC:
+		return TPS65910_REG_VMMC;
+	}
+
+	return -ENXIO;
+}
+
+static int simple_regulator_get_value(struct udevice *dev,
+				      const struct regulator_props *rgp)
+{
+	int sel;
+	u8 val;
+	int vout = 0;
+	struct tps65910_regulator_pdata *pdata = dev->platdata;
+	int vin = pdata->supply;
+
+	val = pmic_reg_read(dev->parent, rgp->reg);
+	if (val < 0)
+		return val;
+	sel = (val & TPS65910_SEL_MASK) >> 2;
+	vout = (vin >= *(rgp->vin_min + sel)) ? *(rgp->vout + sel) : 0;
+	vout = ((val & TPS65910_SUPPLY_STATE_MASK) == 1) ? vout : 0;
+
+	return vout;
+}
+
+static int tps65910_ldo_get_value(struct udevice *dev)
+{
+	struct tps65910_regulator_pdata *pdata = dev->platdata;
+	int vin = pdata->supply;
+
+	switch (dev->driver_data) {
+	case TPS65910_UNIT_VRTC:
+		/* VRTC is fixed and can't be turned off */
+		return (vin >= 2500000) ? 1830000 : 0;
+	case TPS65910_UNIT_VDIG1:
+		return simple_regulator_get_value(dev, &ldo_props_vdig1);
+	case TPS65910_UNIT_VDIG2:
+		return simple_regulator_get_value(dev, &ldo_props_vdig2);
+	case TPS65910_UNIT_VPLL:
+		return simple_regulator_get_value(dev, &ldo_props_vpll);
+	case TPS65910_UNIT_VDAC:
+		return simple_regulator_get_value(dev, &ldo_props_vdac);
+	case TPS65910_UNIT_VAUX1:
+		return simple_regulator_get_value(dev, &ldo_props_vaux1);
+	case TPS65910_UNIT_VAUX2:
+		return simple_regulator_get_value(dev, &ldo_props_vaux2);
+	case TPS65910_UNIT_VAUX33:
+		return simple_regulator_get_value(dev, &ldo_props_vaux33);
+	case TPS65910_UNIT_VMMC:
+		return simple_regulator_get_value(dev, &ldo_props_vmmc);
+	}
+
+	return 0;
+}
+
+static int simple_regulator_set_value(struct udevice *dev,
+				      const struct regulator_props *ldo,
+				      int uV)
+{
+	u8 val;
+	int sel = 0;
+	struct tps65910_regulator_pdata *pdata = dev->platdata;
+
+	do {
+		/* we only allow exact voltage matches */
+		if (uV == *(ldo->vout + sel))
+			break;
+	} while (++sel < VOUT_CHOICE_COUNT);
+	if (sel == VOUT_CHOICE_COUNT)
+		return -EINVAL;
+	if (pdata->supply < *(ldo->vin_min + sel))
+		return -EINVAL;
+
+	val = pmic_reg_read(dev->parent, ldo->reg);
+	if (val < 0)
+		return val;
+	val &= ~TPS65910_SEL_MASK;
+	val |= sel << 2;
+	return pmic_reg_write(dev->parent, ldo->reg, val);
+}
+
+static int tps65910_ldo_set_value(struct udevice *dev, int uV)
+{
+	struct tps65910_regulator_pdata *pdata = dev->platdata;
+	int vin = pdata->supply;
+
+	switch (dev->driver_data) {
+	case TPS65910_UNIT_VRTC:
+		/* VRTC is fixed to 1.83V and can't be turned off */
+		if (vin < 2500000)
+			return -EINVAL;
+		return 0;
+	case TPS65910_UNIT_VDIG1:
+		return simple_regulator_set_value(dev, &ldo_props_vdig1, uV);
+	case TPS65910_UNIT_VDIG2:
+		return simple_regulator_set_value(dev, &ldo_props_vdig2, uV);
+	case TPS65910_UNIT_VPLL:
+		return simple_regulator_set_value(dev, &ldo_props_vpll, uV);
+	case TPS65910_UNIT_VDAC:
+		return simple_regulator_set_value(dev, &ldo_props_vdac, uV);
+	case TPS65910_UNIT_VAUX1:
+		return simple_regulator_set_value(dev, &ldo_props_vaux1, uV);
+	case TPS65910_UNIT_VAUX2:
+		return simple_regulator_set_value(dev, &ldo_props_vaux2, uV);
+	case TPS65910_UNIT_VAUX33:
+		return simple_regulator_set_value(dev, &ldo_props_vaux33, uV);
+	case TPS65910_UNIT_VMMC:
+		return simple_regulator_set_value(dev, &ldo_props_vmmc, uV);
+	}
+
+	return 0;
+}
+
+static int tps65910_get_enable(struct udevice *dev)
+{
+	int reg, ret;
+	u8 val;
+
+	reg = get_ctrl_reg_from_unit_addr(dev->driver_data);
+	if (reg < 0)
+		return reg;
+
+	ret = pmic_read(dev->parent, reg, &val, 1);
+	if (ret)
+		return ret;
+
+	/* bits 2:0 of regulator control register define state */
+	return ((val & TPS65910_SUPPLY_STATE_MASK) == 1);
+}
+
+static int tps65910_set_enable(struct udevice *dev, bool enable)
+{
+	int reg;
+	uint clr, set;
+
+	reg = get_ctrl_reg_from_unit_addr(dev->driver_data);
+	if (reg < 0)
+		return reg;
+
+	if (enable) {
+		clr = 0x02;
+		set = 0x01;
+	} else {
+		clr = 0x03;
+		set = 0x00;
+	}
+	return pmic_clrsetbits(dev->parent, reg, clr, set);
+}
+
+static int tps65910_ldo_probe(struct udevice *dev)
+{
+	int ret = 0;
+	int unit = dev->driver_data;
+	struct tps65910_pdata *pmic_pdata = dev->parent->platdata;
+	struct tps65910_regulator_pdata *pdata = dev->platdata;
+
+	switch (unit) {
+	case TPS65910_UNIT_VRTC:
+		pdata->supply = *(pmic_pdata->supply + TPS65910_SUPPLY_VCC7);
+		break;
+	case TPS65910_UNIT_VDIG1:
+	case TPS65910_UNIT_VDIG2:
+		pdata->supply = *(pmic_pdata->supply + TPS65910_SUPPLY_VCC6);
+		break;
+	case TPS65910_UNIT_VPLL:
+	case TPS65910_UNIT_VDAC:
+		pdata->supply = *(pmic_pdata->supply + TPS65910_SUPPLY_VCC5);
+		break;
+	case TPS65910_UNIT_VAUX1:
+	case TPS65910_UNIT_VAUX2:
+		pdata->supply = *(pmic_pdata->supply + TPS65910_SUPPLY_VCC4);
+		break;
+	case TPS65910_UNIT_VAUX33:
+	case TPS65910_UNIT_VMMC:
+		pdata->supply = *(pmic_pdata->supply + TPS65910_SUPPLY_VCC3);
+		break;
+	default:
+		ret = -ENXIO;
+	}
+
+	return ret;
+}
+
+static int buck_get_vdd1_vdd2_value(struct udevice *dev, int reg_vdd)
+{
+	int gain;
+	u8 val = pmic_reg_read(dev, reg_vdd);
+
+	if (val < 0)
+		return val;
+	gain = (val & TPS65910_GAIN_SEL_MASK) >> 6;
+	gain = (gain == 0) ? 1 : gain;
+	val = pmic_reg_read(dev, reg_vdd + 1);
+	if (val < 0)
+		return val;
+	if (val & TPS65910_VDD_SR_MASK)
+		/* use smart reflex value instead */
+		val = pmic_reg_read(dev, reg_vdd + 2);
+	if (val < 0)
+		return val;
+	return (562500 + (val & TPS65910_VDD_SEL_MASK) * 12500) * gain;
+}
+
+static int tps65910_buck_get_value(struct udevice *dev)
+{
+	int vout = 0;
+
+	switch (dev->driver_data) {
+	case TPS65910_UNIT_VIO:
+		vout = simple_regulator_get_value(dev, &smps_props_vio);
+		break;
+	case TPS65910_UNIT_VDD1:
+		vout = buck_get_vdd1_vdd2_value(dev->parent, TPS65910_REG_VDD1);
+		break;
+	case TPS65910_UNIT_VDD2:
+		vout = buck_get_vdd1_vdd2_value(dev->parent, TPS65910_REG_VDD2);
+		break;
+	}
+
+	return vout;
+}
+
+static int buck_set_vdd1_vdd2_value(struct udevice *dev, int uV)
+{
+	int ret, reg_vdd, gain;
+	u32 limit;
+	int val;
+
+	switch (dev->driver_data) {
+	case TPS65910_UNIT_VDD1:
+		reg_vdd = TPS65910_REG_VDD1;
+		break;
+	case TPS65910_UNIT_VDD2:
+		reg_vdd = TPS65910_REG_VDD2;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* check setpoint is within limits */
+	ret = ofnode_read_u32(dev->node, "regulator-min-microvolt", &limit);
+	if (ret) {
+		/* too dangerous without limit */
+		error("missing regulator-min-microvolt property for %s\n",
+		      dev->name);
+		return ret;
+	}
+	if (uV < limit) {
+		error("voltage %duV for %s too low\n",
+		      limit, dev->name);
+		return -EINVAL;
+	}
+	ret = ofnode_read_u32(dev->node, "regulator-max-microvolt", &limit);
+	if (ret) {
+		/* too dangerous without limit */
+		error("missing regulator-max-microvolt property for %s\n",
+		      dev->name);
+		return ret;
+	}
+	if (uV > limit) {
+		error("voltage %duV for %s too high\n",
+		      limit, dev->name);
+		return -EINVAL;
+	}
+
+	val = pmic_reg_read(dev->parent, reg_vdd);
+	if (val < 0)
+		return val;
+	gain = (val & TPS65910_GAIN_SEL_MASK) >> 6;
+	gain = (gain == 0) ? 1 : gain;
+	val = ((uV / gain) - 562500) / 12500;
+	if ((val < 3) || (val > 75))
+		/* neither do we change the gain, nor do we allow shutdown or
+		 *  any approximate value (for now)
+		 */
+		return -EPERM;
+	val &= TPS65910_VDD_SEL_MASK;
+	ret = pmic_reg_write(dev->parent, reg_vdd + 1, val);
+	if (ret)
+		return ret;
+	return 0;
+}
+
+static int tps65910_buck_set_value(struct udevice *dev, int uV)
+{
+	if (dev->driver_data == TPS65910_UNIT_VIO)
+		return simple_regulator_set_value(dev, &smps_props_vio, uV);
+
+	return buck_set_vdd1_vdd2_value(dev, uV);
+}
+
+static int tps65910_buck_probe(struct udevice *dev)
+{
+	int ret = 0;
+	int unit = dev->driver_data;
+	struct tps65910_pdata *pmic_pdata = dev->parent->platdata;
+	struct tps65910_regulator_pdata *pdata = dev->platdata;
+
+	switch (unit) {
+	case TPS65910_UNIT_VIO:
+		pdata->supply = *(pmic_pdata->supply + TPS65910_SUPPLY_VCCIO);
+		break;
+	case TPS65910_UNIT_VDD1:
+		pdata->supply = *(pmic_pdata->supply + TPS65910_SUPPLY_VCC1);
+		break;
+	case TPS65910_UNIT_VDD2:
+		pdata->supply = *(pmic_pdata->supply + TPS65910_SUPPLY_VCC2);
+		break;
+	default:
+		ret = -ENXIO;
+	}
+	return ret;
+}
+
+static int tps65910_boost_get_value(struct udevice *dev)
+{
+	int vout;
+	struct tps65910_regulator_pdata *pdata = dev->platdata;
+
+	vout = (pdata->supply >= 3000000) ? 5000000 : 0;
+	return vout;
+}
+
+static int tps65910_boost_probe(struct udevice *dev)
+{
+	int unit = dev->driver_data;
+	struct tps65910_pdata *pmic_pdata = dev->parent->platdata;
+	struct tps65910_regulator_pdata *pdata = dev->platdata;
+
+	if (unit != TPS65910_UNIT_VDD3)
+		return -ENXIO;
+
+	pdata->supply = *(pmic_pdata->supply + TPS65910_SUPPLY_VCC7);
+	return 0;
+}
+
+static const struct dm_regulator_ops tps65910_boost_ops = {
+	.get_value  = tps65910_boost_get_value,
+	.get_enable = tps65910_get_enable,
+	.set_enable = tps65910_set_enable,
+};
+
+U_BOOT_DRIVER(tps65910_boost) = {
+	.name = TPS65910_BOOST_DRIVER,
+	.id = UCLASS_REGULATOR,
+	.ops = &tps65910_boost_ops,
+	.probe = tps65910_boost_probe,
+	.platdata_auto_alloc_size = sizeof(struct tps65910_regulator_pdata),
+};
+
+static const struct dm_regulator_ops tps65910_buck_ops = {
+	.get_value  = tps65910_buck_get_value,
+	.set_value  = tps65910_buck_set_value,
+	.get_enable = tps65910_get_enable,
+	.set_enable = tps65910_set_enable,
+};
+
+U_BOOT_DRIVER(tps65910_buck) = {
+	.name = TPS65910_BUCK_DRIVER,
+	.id = UCLASS_REGULATOR,
+	.ops = &tps65910_buck_ops,
+	.probe = tps65910_buck_probe,
+	.platdata_auto_alloc_size = sizeof(struct tps65910_regulator_pdata),
+};
+
+static const struct dm_regulator_ops tps65910_ldo_ops = {
+	.get_value  = tps65910_ldo_get_value,
+	.set_value  = tps65910_ldo_set_value,
+	.get_enable = tps65910_get_enable,
+	.set_enable = tps65910_set_enable,
+};
+
+U_BOOT_DRIVER(tps65910_ldo) = {
+	.name = TPS65910_LDO_DRIVER,
+	.id = UCLASS_REGULATOR,
+	.ops = &tps65910_ldo_ops,
+	.probe = tps65910_ldo_probe,
+	.platdata_auto_alloc_size = sizeof(struct tps65910_regulator_pdata),
+};
diff --git a/include/power/tps65910_pmic.h b/include/power/tps65910_pmic.h
new file mode 100644
index 0000000..23e031e
--- /dev/null
+++ b/include/power/tps65910_pmic.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) EETS GmbH, 2017, Felix Brack <f.brack at eets.ch>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __TPS65910_PMIC_H_
+#define __TPS65910_PMIC_H_
+
+#define TPS65910_I2C_SEL_MASK (0x1 << 4)
+#define TPS65910_VDD_SR_MASK (0x1 << 7)
+#define TPS65910_GAIN_SEL_MASK (0x3 << 6)
+#define TPS65910_VDD_SEL_MASK (0x7f)
+#define TPS65910_SEL_MASK (0x3 << 2)
+#define TPS65910_SUPPLY_STATE_MASK (0x3)
+
+/* i2c registers */
+enum {
+	TPS65910_REG_RTC_SEC			= 0x00,
+	TPS65910_REG_RTC_MIN,
+	TPS65910_REG_RTC_HOUR,
+	TPS65910_REG_RTC_DAY,
+	TPS65910_REG_RTC_MONTH,
+	TPS65910_REG_RTC_YEAR,
+	TPS65910_REG_RTC_WEEK,
+	TPS65910_REG_RTC_ALARM_SEC		= 0x08,
+	TPS65910_REG_RTC_ALARM_MIN,
+	TPS65910_REG_RTC_ALARM_HOUR,
+	TPS65910_REG_RTC_ALARM_DAY,
+	TPS65910_REG_RTC_ALARM_MONTH,
+	TPS65910_REG_RTC_ALARM_YEAR,
+	TPS65910_REG_RTC_CTRL			= 0x10,
+	TPS65910_REG_RTC_STAT,
+	TPS65910_REG_RTC_INT,
+	TPS65910_REG_RTC_COMP_LSB,
+	TPS65910_REG_RTC_COMP_MSB,
+	TPS65910_REG_RTC_RESISTOR_PRG,
+	TPS65910_REG_RTC_RESET_STAT,
+	TPS65910_REG_BACKUP1,
+	TPS65910_REG_BACKUP2,
+	TPS65910_REG_BACKUP3,
+	TPS65910_REG_BACKUP4,
+	TPS65910_REG_BACKUP5,
+	TPS65910_REG_PUADEN,
+	TPS65910_REG_REF,
+	TPS65910_REG_VRTC,
+	TPS65910_REG_VIO			= 0x20,
+	TPS65910_REG_VDD1,
+	TPS65910_REG_VDD1_VAL,
+	TPS65910_REG_VDD1_VAL_SR,
+	TPS65910_REG_VDD2,
+	TPS65910_REG_VDD2_VAL,
+	TPS65910_REG_VDD2_VAL_SR,
+	TPS65910_REG_VDD3,
+	TPS65910_REG_VDIG1			= 0x30,
+	TPS65910_REG_VDIG2,
+	TPS65910_REG_VAUX1,
+	TPS65910_REG_VAUX2,
+	TPS65910_REG_VAUX33,
+	TPS65910_REG_VMMC,
+	TPS65910_REG_VPLL,
+	TPS65910_REG_VDAC,
+	TPS65910_REG_THERM,
+	TPS65910_REG_BATTERY_BACKUP_CHARGE,
+	TPS65910_REG_DCDC_CTRL			= 0x3e,
+	TPS65910_REG_DEVICE_CTRL,
+	TPS65910_REG_DEVICE_CTRL2,
+	TPS65910_REG_SLEEP_KEEP_LDO_ON,
+	TPS65910_REG_SLEEP_KEEP_RES_ON,
+	TPS65910_REG_SLEEP_SET_LDO_OFF,
+	TPS65910_REG_SLEEP_SET_RES_OFF,
+	TPS65910_REG_EN1_LDO_ASS,
+	TPS65910_REG_EM1_SMPS_ASS,
+	TPS65910_REG_EN2_LDO_ASS,
+	TPS65910_REG_EM2_SMPS_ASS,
+	TPS65910_REG_INT_STAT			= 0x50,
+	TPS65910_REG_INT_MASK,
+	TPS65910_REG_INT_STAT2,
+	TPS65910_REG_INT_MASK2,
+	TPS65910_REG_GPIO			= 0x60,
+	TPS65910_REG_JTAGREVNUM			= 0x80,
+	TPS65910_NUM_REGS
+};
+
+/* chip supplies */
+enum {
+	TPS65910_SUPPLY_VCCIO	= 0x00,
+	TPS65910_SUPPLY_VCC1,
+	TPS65910_SUPPLY_VCC2,
+	TPS65910_SUPPLY_VCC3,
+	TPS65910_SUPPLY_VCC4,
+	TPS65910_SUPPLY_VCC5,
+	TPS65910_SUPPLY_VCC6,
+	TPS65910_SUPPLY_VCC7,
+	TPS65910_NUM_SUPPLIES
+};
+
+/* regulator unit numbers */
+enum {
+	TPS65910_UNIT_VRTC = 0x00,
+	TPS65910_UNIT_VIO,
+	TPS65910_UNIT_VDD1,
+	TPS65910_UNIT_VDD2,
+	TPS65910_UNIT_VDD3,
+	TPS65910_UNIT_VDIG1,
+	TPS65910_UNIT_VDIG2,
+	TPS65910_UNIT_VPLL,
+	TPS65910_UNIT_VDAC,
+	TPS65910_UNIT_VAUX1,
+	TPS65910_UNIT_VAUX2,
+	TPS65910_UNIT_VAUX33,
+	TPS65910_UNIT_VMMC,
+	TPS65910_UNIT_VBB,
+};
+
+/* platform data */
+struct tps65910_pdata {
+	u32 supply[TPS65910_NUM_SUPPLIES]; /* regulator supply voltage in uV */
+};
+
+struct tps65910_regulator_pdata {
+	u32 supply;    /* regulator supply voltage in uV */
+};
+
+/* driver names */
+#define TPS65910_BUCK_DRIVER "tps65910_buck"
+#define TPS65910_BOOST_DRIVER "tps65910_boost"
+#define TPS65910_LDO_DRIVER "tps65910_ldo"
+
+ #endif /* __TPS65910_PMIC_H_ */
-- 
2.7.4



More information about the U-Boot mailing list