diff options
author | Przemyslaw Marczak <p.marczak@samsung.com> | 2015-05-13 13:38:32 +0200 |
---|---|---|
committer | Simon Glass <sjg@chromium.org> | 2015-05-14 19:58:34 -0600 |
commit | 5d387d0df9816cdf05d7bce3b7379057068a7e58 (patch) | |
tree | fdb07e7f1beb9cc1afe1b1653298f33b4d57eb3c /drivers/power/pmic/i2c_pmic_emul.c | |
parent | a989ec8dd4bb548708220146391d5ed7b575331f (diff) | |
download | u-boot-imx-5d387d0df9816cdf05d7bce3b7379057068a7e58.zip u-boot-imx-5d387d0df9816cdf05d7bce3b7379057068a7e58.tar.gz u-boot-imx-5d387d0df9816cdf05d7bce3b7379057068a7e58.tar.bz2 |
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 <p.marczak@samsung.com>
Acked-by: Simon Glass <sjg@chromium.org>
Tested on sandbox:
Tested-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'drivers/power/pmic/i2c_pmic_emul.c')
-rw-r--r-- | drivers/power/pmic/i2c_pmic_emul.c | 142 |
1 files changed, 142 insertions, 0 deletions
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 <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, +}; |