sandbox: add: sandbox PMIC device drivers: I2C emul, pmic, regulator
[oweals/u-boot.git] / drivers / power / pmic / i2c_pmic_emul.c
diff --git a/drivers/power/pmic/i2c_pmic_emul.c b/drivers/power/pmic/i2c_pmic_emul.c
new file mode 100644 (file)
index 0000000..aeab5c9
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ *  Copyright (C) 2015 Samsung Electronics
+ *  Przemyslaw Marczak  <p.marczak@samsung.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <fdtdec.h>
+#include <errno.h>
+#include <dm.h>
+#include <i2c.h>
+#include <power/pmic.h>
+#include <power/sandbox_pmic.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * struct sandbox_i2c_pmic_plat_data - platform data for the PMIC
+ *
+ * @rw_reg: PMICs register of the chip I/O transaction
+ * @reg:    PMICs registers array
+ */
+struct sandbox_i2c_pmic_plat_data {
+       u8 rw_reg;
+       u8 reg[SANDBOX_PMIC_REG_COUNT];
+};
+
+static int sandbox_i2c_pmic_read_data(struct udevice *emul, uchar chip,
+                                     uchar *buffer, int len)
+{
+       struct sandbox_i2c_pmic_plat_data *plat = dev_get_platdata(emul);
+
+       if (plat->rw_reg + len > SANDBOX_PMIC_REG_COUNT) {
+               error("Request exceeds PMIC register range! Max register: %#x",
+                     SANDBOX_PMIC_REG_COUNT);
+               return -EFAULT;
+       }
+
+       debug("Read PMIC: %#x at register: %#x count: %d\n",
+             (unsigned)chip & 0xff, plat->rw_reg, len);
+
+       memcpy(buffer, &plat->reg[plat->rw_reg], len);
+
+       return 0;
+}
+
+static int sandbox_i2c_pmic_write_data(struct udevice *emul, uchar chip,
+                                      uchar *buffer, int len,
+                                      bool next_is_read)
+{
+       struct sandbox_i2c_pmic_plat_data *plat = dev_get_platdata(emul);
+
+       /* Probe only */
+       if (!len)
+               return 0;
+
+       /* Set PMIC register for I/O */
+       plat->rw_reg = *buffer;
+
+       debug("Write PMIC: %#x at register: %#x count: %d\n",
+             (unsigned)chip & 0xff, plat->rw_reg, len);
+
+       /* For read operation, set (write) only chip reg */
+       if (next_is_read)
+               return 0;
+
+       buffer++;
+       len--;
+
+       if (plat->rw_reg + len > SANDBOX_PMIC_REG_COUNT) {
+               error("Request exceeds PMIC register range! Max register: %#x",
+                     SANDBOX_PMIC_REG_COUNT);
+       }
+
+       memcpy(&plat->reg[plat->rw_reg], buffer, len);
+
+       return 0;
+}
+
+static int sandbox_i2c_pmic_xfer(struct udevice *emul, struct i2c_msg *msg,
+                                int nmsgs)
+{
+       int ret = 0;
+
+       for (; nmsgs > 0; nmsgs--, msg++) {
+               bool next_is_read = nmsgs > 1 && (msg[1].flags & I2C_M_RD);
+               if (msg->flags & I2C_M_RD) {
+                       ret = sandbox_i2c_pmic_read_data(emul, msg->addr,
+                                                        msg->buf, msg->len);
+               } else {
+                       ret = sandbox_i2c_pmic_write_data(emul, msg->addr,
+                                                         msg->buf, msg->len,
+                                                         next_is_read);
+               }
+
+               if (ret)
+                       break;
+       }
+
+       return ret;
+}
+
+static int sandbox_i2c_pmic_ofdata_to_platdata(struct udevice *emul)
+{
+       struct sandbox_i2c_pmic_plat_data *plat = dev_get_platdata(emul);
+       const u8 *reg_defaults;
+
+       debug("%s:%d Setting PMIC default registers\n", __func__, __LINE__);
+
+       reg_defaults = fdtdec_locate_byte_array(gd->fdt_blob, emul->of_offset,
+                                               "reg-defaults",
+                                               SANDBOX_PMIC_REG_COUNT);
+
+       if (!reg_defaults) {
+               error("Property \"reg-defaults\" not found for device: %s!",
+                     emul->name);
+               return -EINVAL;
+       }
+
+       memcpy(&plat->reg, reg_defaults, SANDBOX_PMIC_REG_COUNT);
+
+       return 0;
+}
+
+struct dm_i2c_ops sandbox_i2c_pmic_emul_ops = {
+       .xfer = sandbox_i2c_pmic_xfer,
+};
+
+static const struct udevice_id sandbox_i2c_pmic_ids[] = {
+       { .compatible = "sandbox,i2c-pmic" },
+       { }
+};
+
+U_BOOT_DRIVER(sandbox_i2c_pmic_emul) = {
+       .name           = "sandbox_i2c_pmic_emul",
+       .id             = UCLASS_I2C_EMUL,
+       .of_match       = sandbox_i2c_pmic_ids,
+       .ofdata_to_platdata = sandbox_i2c_pmic_ofdata_to_platdata,
+       .platdata_auto_alloc_size = sizeof(struct sandbox_i2c_pmic_plat_data),
+       .ops            = &sandbox_i2c_pmic_emul_ops,
+};