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 | |
parent | a989ec8dd4bb548708220146391d5ed7b575331f (diff) | |
download | u-boot-5d387d0df9816cdf05d7bce3b7379057068a7e58.tar.gz |
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')
-rw-r--r-- | drivers/power/pmic/Kconfig | 25 | ||||
-rw-r--r-- | drivers/power/pmic/Makefile | 3 | ||||
-rw-r--r-- | drivers/power/pmic/i2c_pmic_emul.c | 142 | ||||
-rw-r--r-- | drivers/power/pmic/sandbox.c | 79 |
4 files changed, 248 insertions, 1 deletions
diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index d99d9e3a06..164f42143f 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -16,3 +16,28 @@ config DM_PMIC_MAX77686 ---help--- This config enables implementation of driver-model pmic uclass features for PMIC MAX77686. The driver implements read/write operations. + +config DM_PMIC_SANDBOX + bool "Enable Driver Model for emulated Sandbox PMIC " + depends on DM_PMIC + ---help--- + Enable the driver for Sandbox PMIC emulation. The emulated PMIC device + depends on two drivers: + - sandbox PMIC I/O driver - implements dm pmic operations + - sandbox PMIC i2c emul driver - emulates the PMIC's I2C transmission + + A detailed information can be found in header: '<power/sandbox_pmic.h>' + + The Sandbox PMIC info: + * I/O interface: + - I2C chip address: 0x40 + - first register address: 0x0 + - register count: 0x10 + * Adjustable outputs: + - 2x LDO + - 2x BUCK + - Each, with a different operating conditions (header). + * Reset values: + - set by i2c emul driver's probe() (defaults in header) + + Driver binding info: doc/device-tree-bindings/pmic/sandbox.txt diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index 8cb993d0a7..ae86f041f3 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -6,12 +6,13 @@ # 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_POWER_LTC3676) += pmic_ltc3676.o obj-$(CONFIG_POWER_MAX8998) += pmic_max8998.o obj-$(CONFIG_POWER_MAX8997) += pmic_max8997.o obj-$(CONFIG_POWER_MUIC_MAX8997) += muic_max8997.o obj-$(CONFIG_POWER_MAX77686) += pmic_max77686.o -obj-$(CONFIG_DM_PMIC_MAX77686) += max77686.o obj-$(CONFIG_POWER_PFUZE100) += pmic_pfuze100.o obj-$(CONFIG_POWER_TPS65090_I2C) += pmic_tps65090.o obj-$(CONFIG_POWER_TPS65090_EC) += pmic_tps65090_ec.o diff --git a/drivers/power/pmic/i2c_pmic_emul.c b/drivers/power/pmic/i2c_pmic_emul.c new file mode 100644 index 0000000000..aeab5c949a --- /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, +}; diff --git a/drivers/power/pmic/sandbox.c b/drivers/power/pmic/sandbox.c new file mode 100644 index 0000000000..3e56acd5e2 --- /dev/null +++ b/drivers/power/pmic/sandbox.c @@ -0,0 +1,79 @@ +/* + * 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/regulator.h> +#include <power/sandbox_pmic.h> + +DECLARE_GLOBAL_DATA_PTR; + +static const struct pmic_child_info pmic_children_info[] = { + { .prefix = SANDBOX_OF_LDO_PREFIX, .driver = SANDBOX_LDO_DRIVER }, + { .prefix = SANDBOX_OF_BUCK_PREFIX, .driver = SANDBOX_BUCK_DRIVER }, + { }, +}; + +static int sandbox_pmic_reg_count(struct udevice *dev) +{ + return SANDBOX_PMIC_REG_COUNT; +} + +static int sandbox_pmic_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 sandbox_pmic_read(struct udevice *dev, uint reg, + uint8_t *buff, int len) +{ + if (dm_i2c_read(dev, reg, buff, len)) { + error("read error from device: %p register: %#x!", dev, reg); + return -EIO; + } + + return 0; +} + +static int sandbox_pmic_bind(struct udevice *dev) +{ + if (!pmic_bind_children(dev, dev->of_offset, pmic_children_info)) + error("%s:%d PMIC: %s - no child found!", __func__, __LINE__, + dev->name); + + /* Always return success for this device - allows for PMIC I/O */ + return 0; +} + +static struct dm_pmic_ops sandbox_pmic_ops = { + .reg_count = sandbox_pmic_reg_count, + .read = sandbox_pmic_read, + .write = sandbox_pmic_write, +}; + +static const struct udevice_id sandbox_pmic_ids[] = { + { .compatible = "sandbox,pmic" }, + { } +}; + +U_BOOT_DRIVER(sandbox_pmic) = { + .name = "sandbox_pmic", + .id = UCLASS_PMIC, + .of_match = sandbox_pmic_ids, + .bind = sandbox_pmic_bind, + .ops = &sandbox_pmic_ops, +}; |