From 5d387d0df9816cdf05d7bce3b7379057068a7e58 Mon Sep 17 00:00:00 2001 From: Przemyslaw Marczak Date: Wed, 13 May 2015 13:38:32 +0200 Subject: sandbox: add: sandbox PMIC device drivers: I2C emul, pmic, regulator This commit adds emulation of sandbox PMIC device, which includes: - PMIC I2C emulation driver - PMIC I/O driver (UCLASS_PMIC) - PMIC regulator driver (UCLASS_REGULATOR) The sandbox PMIC has 12 significant registers and 4 as padding to 16 bytes, which allows using 'i2c md' command with the default count (16). The sandbox PMIC provides regulators: - 2x BUCK - 2x LDO Each, with adjustable output: - Enable state - Voltage - Current limit (LDO1/BUCK1 only) - Operation mode (different for BUCK and LDO) Each attribute has it's own register, beside the enable state, which depends on operation mode. The header file: sandbox_pmic.h includes PMIC's default register values, which are set on i2c pmic emul driver's probe() method. Signed-off-by: Przemyslaw Marczak Acked-by: Simon Glass Tested on sandbox: Tested-by: Simon Glass --- drivers/power/pmic/i2c_pmic_emul.c | 142 +++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 drivers/power/pmic/i2c_pmic_emul.c (limited to '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 index 0000000..aeab5c9 --- /dev/null +++ b/drivers/power/pmic/i2c_pmic_emul.c @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2015 Samsung Electronics + * Przemyslaw Marczak + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include + +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, +}; -- cgit v1.1