diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/power/pmic/Kconfig | 7 | ||||
-rw-r--r-- | drivers/power/pmic/Makefile | 1 | ||||
-rw-r--r-- | drivers/power/pmic/i2c_pmic_emul.c | 45 | ||||
-rw-r--r-- | drivers/power/pmic/mc34708.c | 105 | ||||
-rw-r--r-- | drivers/power/pmic/pmic-uclass.c | 52 |
5 files changed, 184 insertions, 26 deletions
diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index 40ab9f7fa5..d504c28b77 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -69,6 +69,13 @@ config DM_PMIC_MAX8998 This config enables implementation of driver-model pmic uclass features for PMIC MAX8998. The driver implements read/write operations. +config DM_PMIC_MC34708 + bool "Enable Driver Model for PMIC MC34708" + depends on DM_PMIC + help + This config enables implementation of driver-model pmic uclass features + for PMIC MC34708. The driver implements read/write operations. + config PMIC_MAX8997 bool "Enable Driver Model for PMIC MAX8997" depends on DM_PMIC diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index 85ab176c0a..29ca442933 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_DM_PMIC) += pmic-uclass.o obj-$(CONFIG_DM_PMIC_MAX77686) += max77686.o obj-$(CONFIG_DM_PMIC_MAX8998) += max8998.o +obj-$(CONFIG_DM_PMIC_MC34708) += mc34708.o obj-$(CONFIG_$(SPL_)DM_PMIC_PFUZE100) += pfuze100.o obj-$(CONFIG_PMIC_S2MPS11) += s2mps11.o obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o diff --git a/drivers/power/pmic/i2c_pmic_emul.c b/drivers/power/pmic/i2c_pmic_emul.c index c0b53091cc..61fa76a561 100644 --- a/drivers/power/pmic/i2c_pmic_emul.c +++ b/drivers/power/pmic/i2c_pmic_emul.c @@ -18,8 +18,11 @@ * @reg: PMICs registers array */ struct sandbox_i2c_pmic_plat_data { - u8 rw_reg; - u8 reg[SANDBOX_PMIC_REG_COUNT]; + u8 rw_reg, rw_idx; + u8 reg_count; + u8 trans_len; + u8 buf_size; + u8 *reg; }; static int sandbox_i2c_pmic_read_data(struct udevice *emul, uchar chip, @@ -27,16 +30,16 @@ static int sandbox_i2c_pmic_read_data(struct udevice *emul, uchar chip, { struct sandbox_i2c_pmic_plat_data *plat = dev_get_platdata(emul); - if (plat->rw_reg + len > SANDBOX_PMIC_REG_COUNT) { + if (plat->rw_idx + len > plat->buf_size) { pr_err("Request exceeds PMIC register range! Max register: %#x", - SANDBOX_PMIC_REG_COUNT); + plat->reg_count); return -EFAULT; } - debug("Read PMIC: %#x at register: %#x count: %d\n", - (unsigned)chip & 0xff, plat->rw_reg, len); + debug("Read PMIC: %#x at register: %#x idx: %#x count: %d\n", + (unsigned int)chip & 0xff, plat->rw_reg, plat->rw_idx, len); - memcpy(buffer, &plat->reg[plat->rw_reg], len); + memcpy(buffer, plat->reg + plat->rw_idx, len); return 0; } @@ -53,9 +56,10 @@ static int sandbox_i2c_pmic_write_data(struct udevice *emul, uchar chip, /* Set PMIC register for I/O */ plat->rw_reg = *buffer; + plat->rw_idx = plat->rw_reg * plat->trans_len; - debug("Write PMIC: %#x at register: %#x count: %d\n", - (unsigned)chip & 0xff, plat->rw_reg, len); + debug("Write PMIC: %#x at register: %#x idx: %#x count: %d\n", + (unsigned int)chip & 0xff, plat->rw_reg, plat->rw_idx, len); /* For read operation, set (write) only chip reg */ if (next_is_read) @@ -64,12 +68,12 @@ static int sandbox_i2c_pmic_write_data(struct udevice *emul, uchar chip, buffer++; len--; - if (plat->rw_reg + len > SANDBOX_PMIC_REG_COUNT) { + if (plat->rw_idx + len > plat->buf_size) { pr_err("Request exceeds PMIC register range! Max register: %#x", - SANDBOX_PMIC_REG_COUNT); + plat->reg_count); } - memcpy(&plat->reg[plat->rw_reg], buffer, len); + memcpy(plat->reg + plat->rw_idx, buffer, len); return 0; } @@ -100,20 +104,33 @@ static int sandbox_i2c_pmic_xfer(struct udevice *emul, struct i2c_msg *msg, static int sandbox_i2c_pmic_ofdata_to_platdata(struct udevice *emul) { struct sandbox_i2c_pmic_plat_data *plat = dev_get_platdata(emul); + struct udevice *pmic_dev = dev_get_parent(emul); + struct uc_pmic_priv *priv = dev_get_uclass_priv(pmic_dev); const u8 *reg_defaults; debug("%s:%d Setting PMIC default registers\n", __func__, __LINE__); + plat->reg_count = pmic_reg_count(pmic_dev); + plat->trans_len = priv->trans_len; + plat->buf_size = plat->reg_count * plat->trans_len; + + plat->reg = calloc(1, plat->buf_size); + if (!plat->reg) { + debug("Canot allocate memory (%d B) for PMIC I2C emulation!\n", + plat->buf_size); + return -ENOMEM; + } reg_defaults = dev_read_u8_array_ptr(emul, "reg-defaults", - SANDBOX_PMIC_REG_COUNT); + plat->buf_size); if (!reg_defaults) { pr_err("Property \"reg-defaults\" not found for device: %s!", emul->name); + free(plat->reg); return -EINVAL; } - memcpy(&plat->reg, reg_defaults, SANDBOX_PMIC_REG_COUNT); + memcpy(plat->reg, reg_defaults, plat->buf_size); return 0; } diff --git a/drivers/power/pmic/mc34708.c b/drivers/power/pmic/mc34708.c new file mode 100644 index 0000000000..2b2fc72a47 --- /dev/null +++ b/drivers/power/pmic/mc34708.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018 + * Lukasz Majewski, DENX Software Engineering, lukma@denx.de + * + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <fsl_pmic.h> +#include <i2c.h> +#include <power/pmic.h> + +DECLARE_GLOBAL_DATA_PTR; + +static int mc34708_reg_count(struct udevice *dev) +{ + return PMIC_NUM_OF_REGS; +} + +static int mc34708_write(struct udevice *dev, uint reg, const u8 *buff, + int len) +{ + u8 buf[3] = { 0 }; + int ret; + + if (len != MC34708_TRANSFER_SIZE) + return -EINVAL; + + /* + * The MC34708 sends data with big endian format, hence we need to + * perform manual byte swap. + */ + buf[0] = buff[2]; + buf[1] = buff[1]; + buf[2] = buff[0]; + + ret = dm_i2c_write(dev, reg, buf, len); + if (ret) + printf("write error to device: %p register: %#x!", dev, reg); + + return ret; +} + +static int mc34708_read(struct udevice *dev, uint reg, u8 *buff, int len) +{ + u8 buf[3] = { 0 }; + int ret; + + if (len != MC34708_TRANSFER_SIZE) + return -EINVAL; + + ret = dm_i2c_read(dev, reg, buf, len); + if (ret) + printf("read error from device: %p register: %#x!", dev, reg); + + buff[0] = buf[2]; + buff[1] = buf[1]; + buff[2] = buf[0]; + + return ret; +} + +static int mc34708_probe(struct udevice *dev) +{ + struct uc_pmic_priv *priv = dev_get_uclass_priv(dev); + + priv->trans_len = MC34708_TRANSFER_SIZE; + + /* + * Handle PMIC Errata 37: APS mode not fully functional, + * use explicit PWM or PFM instead + */ + pmic_clrsetbits(dev, MC34708_REG_SW12_OPMODE, + MC34708_SW1AMODE_MASK | MC34708_SW2MODE_MASK, + SW_MODE_PWMPWM | (SW_MODE_PWMPWM << 14u)); + + pmic_clrsetbits(dev, MC34708_REG_SW345_OPMODE, + MC34708_SW3MODE_MASK | MC34708_SW4AMODE_MASK | + MC34708_SW4BMODE_MASK | MC34708_SW5MODE_MASK, + SW_MODE_PWMPWM | (SW_MODE_PWMPWM << 6u) | + (SW_MODE_PWMPWM << 12u) | (SW_MODE_PWMPWM << 18u)); + + return 0; +} + +static struct dm_pmic_ops mc34708_ops = { + .reg_count = mc34708_reg_count, + .read = mc34708_read, + .write = mc34708_write, +}; + +static const struct udevice_id mc34708_ids[] = { + { .compatible = "fsl,mc34708" }, + { } +}; + +U_BOOT_DRIVER(pmic_mc34708) = { + .name = "mc34708_pmic", + .id = UCLASS_PMIC, + .of_match = mc34708_ids, + .probe = mc34708_probe, + .ops = &mc34708_ops, +}; diff --git a/drivers/power/pmic/pmic-uclass.c b/drivers/power/pmic/pmic-uclass.c index 5f0f6ff93e..db68c766f5 100644 --- a/drivers/power/pmic/pmic-uclass.c +++ b/drivers/power/pmic/pmic-uclass.c @@ -130,23 +130,35 @@ int pmic_write(struct udevice *dev, uint reg, const uint8_t *buffer, int len) int pmic_reg_read(struct udevice *dev, uint reg) { - u8 byte; + struct uc_pmic_priv *priv = dev_get_uclass_priv(dev); + u32 val = 0; int ret; - debug("%s: reg=%x", __func__, reg); - ret = pmic_read(dev, reg, &byte, 1); - debug(", value=%x, ret=%d\n", byte, ret); + if (priv->trans_len < 1 || priv->trans_len > sizeof(val)) { + debug("Wrong transmission size [%d]\n", priv->trans_len); + return -EINVAL; + } + + debug("%s: reg=%x priv->trans_len:%d", __func__, reg, priv->trans_len); + ret = pmic_read(dev, reg, (uint8_t *)&val, priv->trans_len); + debug(", value=%x, ret=%d\n", val, ret); - return ret ? ret : byte; + return ret ? ret : val; } int pmic_reg_write(struct udevice *dev, uint reg, uint value) { - u8 byte = value; + struct uc_pmic_priv *priv = dev_get_uclass_priv(dev); int ret; - debug("%s: reg=%x, value=%x", __func__, reg, value); - ret = pmic_write(dev, reg, &byte, 1); + if (priv->trans_len < 1 || priv->trans_len > sizeof(value)) { + debug("Wrong transmission size [%d]\n", priv->trans_len); + return -EINVAL; + } + + debug("%s: reg=%x, value=%x priv->trans_len:%d", __func__, reg, value, + priv->trans_len); + ret = pmic_write(dev, reg, (uint8_t *)&value, priv->trans_len); debug(", ret=%d\n", ret); return ret; @@ -154,18 +166,34 @@ int pmic_reg_write(struct udevice *dev, uint reg, uint value) int pmic_clrsetbits(struct udevice *dev, uint reg, uint clr, uint set) { - u8 byte; + struct uc_pmic_priv *priv = dev_get_uclass_priv(dev); + u32 val = 0; int ret; - ret = pmic_reg_read(dev, reg); + if (priv->trans_len < 1 || priv->trans_len > sizeof(val)) { + debug("Wrong transmission size [%d]\n", priv->trans_len); + return -EINVAL; + } + + ret = pmic_read(dev, reg, (uint8_t *)&val, priv->trans_len); if (ret < 0) return ret; - byte = (ret & ~clr) | set; - return pmic_reg_write(dev, reg, byte); + val = (val & ~clr) | set; + return pmic_write(dev, reg, (uint8_t *)&val, priv->trans_len); +} + +static int pmic_pre_probe(struct udevice *dev) +{ + struct uc_pmic_priv *pmic_priv = dev_get_uclass_priv(dev); + + pmic_priv->trans_len = 1; + return 0; } UCLASS_DRIVER(pmic) = { .id = UCLASS_PMIC, .name = "pmic", + .pre_probe = pmic_pre_probe, + .per_device_auto_alloc_size = sizeof(struct uc_pmic_priv), }; |