dm: power: Add a new driver for the TPS65090 PMIC
authorSimon Glass <sjg@chromium.org>
Fri, 3 Jul 2015 00:15:58 +0000 (18:15 -0600)
committerSimon Glass <sjg@chromium.org>
Thu, 6 Aug 2015 03:06:12 +0000 (21:06 -0600)
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 <sjg@chromium.org>
Acked-by: Przemyslaw Marczak <p.marczak@samsung.com>
drivers/power/pmic/Kconfig
drivers/power/pmic/Makefile
drivers/power/pmic/tps65090.c [new file with mode: 0644]
include/power/tps65090.h [new file with mode: 0644]

index 164f421..fd8af81 100644 (file)
@@ -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.
index 4ad6df3..43b706b 100644 (file)
@@ -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 (file)
index 0000000..4797f32
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <i2c.h>
+#include <power/pmic.h>
+#include <power/tps65090.h>
+
+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,
+};
diff --git a/include/power/tps65090.h b/include/power/tps65090.h
new file mode 100644 (file)
index 0000000..3a0690b
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __TPS65090_PMIC_H_
+#define __TPS65090_PMIC_H_
+
+/* I2C device address for TPS65090 PMU */
+#define TPS65090_I2C_ADDR      0x48
+
+/* TPS65090 register addresses */
+enum {
+       REG_IRQ1 = 0,
+       REG_CG_CTRL0 = 4,
+       REG_CG_STATUS1 = 0xa,
+       REG_FET_BASE = 0xe,     /* Not a real register, FETs count from here */
+       REG_FET1_CTRL,
+       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 */
+};
+
+enum {
+       /* Status register fields */
+       TPS65090_ST1_OTC        = 1 << 0,
+       TPS65090_ST1_OCC        = 1 << 1,
+       TPS65090_ST1_STATE_SHIFT = 4,
+       TPS65090_ST1_STATE_MASK = 0xf << TPS65090_ST1_STATE_SHIFT,
+};
+
+/* Drivers name */
+#define TPS65090_FET_DRIVER    "tps65090_fet"
+
+#endif /* __TPS65090_PMIC_H_ */