[U-Boot] [PATCH v3 00/11] pmic: sandbox: Add support for MC34709 PMIC

Adding this device required some changes into the PMIC uclass. Most notable one was the support for 3 bytes r/w operations. Moreover, emulation and tests for this device has been added to sandbox.
Travis-CI: https://travis-ci.org/lmajewski/u-boot-dfu/builds/378678458
Changes in v3: - None - None - Rename dm_pmic_info to uc_pmic_priv - Rename dm_pmic_info -> uc_pmic_priv - Replace printf() -> debug() - Use priv->trans_len instead of tx_num - Rename dm_pmic_info with uc_pmic_priv - Sort alphabetically includes - Add comment regarding MC34708 byte ordering - Replace dm_pmic_info with uc_pmic_priv - Replace pmic_info with priv - Replace pr_err() with debug() - dm_pmic_info -> uc_pmic_priv - Fix DTS property style to compy with Device Tree specification as suggested by Fabio. - Enable MC34708 PMIC support in sandbox_{flattree|spl}_defconfig - None - Fix pmic.c test code after adjusting the sandbox PMIC related dts
Changes in v2: - None - None - New patch - pmic_reg_* fixes to use uclass private structure - Support for uclass private data with trasfer length - New patch - New patch - New patch - New patch - New patch - New patch
Lukasz Majewski (11): pmic: fsl: Provide some more definitions for MC34708 PMIC pmic: fsl: Define number of bytes sent at once by MC34708 PMIC pmic: Add support for setting transmission length in uclass private data pmic: dm: Rewrite pmic_reg_{read|write|clrsetbits} to support 3 bytes transmissions pmic: dm: Add support for MC34708 for PMIC DM pmic: Rewrite the pmic command to not only work with single byte transmission sandbox: Rewrite i2c_pmic_emul.c to support PMIC with 3 bytes transmission sandbox: Enable support for MC34708 PMIC in DTS sandbox: Enable MC34708 PMIC support sandbox: tests: Exclude common test code (pmic_get) in test/dm/pmic.c sandbox: tests: Add tests for mc34708 PMIC device
arch/sandbox/dts/sandbox.dts | 4 ++ arch/sandbox/dts/sandbox64.dts | 4 ++ arch/sandbox/dts/sandbox_pmic.dtsi | 33 ++++++++++++ arch/sandbox/dts/test.dts | 4 ++ cmd/pmic.c | 31 ++++++----- configs/sandbox_defconfig | 1 + configs/sandbox_flattree_defconfig | 1 + configs/sandbox_spl_defconfig | 1 + drivers/power/pmic/Kconfig | 7 +++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/i2c_pmic_emul.c | 45 +++++++++++----- drivers/power/pmic/mc34708.c | 105 +++++++++++++++++++++++++++++++++++++ drivers/power/pmic/pmic-uclass.c | 52 +++++++++++++----- include/fsl_pmic.h | 41 +++++++++++++++ include/power/pmic.h | 9 ++++ test/dm/pmic.c | 68 +++++++++++++++++++++++- 16 files changed, 367 insertions(+), 40 deletions(-) create mode 100644 drivers/power/pmic/mc34708.c

This commit adds some more defines for MC34708 PMIC.
Signed-off-by: Lukasz Majewski lukma@denx.de
---
Changes in v3: - None
Changes in v2: - None
include/fsl_pmic.h | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+)
diff --git a/include/fsl_pmic.h b/include/fsl_pmic.h index 6cab77ecb5..fc9e3152a9 100644 --- a/include/fsl_pmic.h +++ b/include/fsl_pmic.h @@ -107,6 +107,7 @@ enum {
/* MC34708 Definitions */ #define SWx_VOLT_MASK_MC34708 0x3F +#define SWx_1_110V_MC34708 0x24 #define SWx_1_250V_MC34708 0x30 #define SWx_1_300V_MC34708 0x34 #define TIMER_MASK_MC34708 0x300 @@ -116,4 +117,43 @@ enum { #define SWBST_CTRL 31 #define SWBST_AUTO 0x8
+#define MC34708_REG_SW12_OPMODE 28 + +#define MC34708_SW1AMODE_MASK 0x00000f +#define MC34708_SW1AMHMODE 0x000010 +#define MC34708_SW1AUOMODE 0x000020 +#define MC34708_SW1DVSSPEED 0x0000c0 +#define MC34708_SW2MODE_MASK 0x03c000 +#define MC34708_SW2MHMODE 0x040000 +#define MC34708_SW2UOMODE 0x080000 +#define MC34708_SW2DVSSPEED 0x300000 +#define MC34708_PLLEN 0x400000 +#define MC34708_PLLX 0x800000 + +#define MC34708_REG_SW345_OPMODE 29 + +#define MC34708_SW3MODE_MASK 0x00000f +#define MC34708_SW3MHMODE 0x000010 +#define MC34708_SW3UOMODE 0x000020 +#define MC34708_SW4AMODE_MASK 0x0003c0 +#define MC34708_SW4AMHMODE 0x000400 +#define MC34708_SW4AUOMODE 0x000800 +#define MC34708_SW4BMODE_MASK 0x00f000 +#define MC34708_SW4BMHMODE 0x010000 +#define MC34708_SW4BUOMODE 0x020000 +#define MC34708_SW5MODE_MASK 0x3c0000 +#define MC34708_SW5MHMODE 0x400000 +#define MC34708_SW5UOMODE 0x800000 + +#define SW_MODE_OFFOFF 0x00 +#define SW_MODE_PWMOFF 0x01 +#define SW_MODE_PFMOFF 0x03 +#define SW_MODE_APSOFF 0x04 +#define SW_MODE_PWMPWM 0x05 +#define SW_MODE_PWMAPS 0x06 +#define SW_MODE_APSAPS 0x08 +#define SW_MODE_APSPFM 0x0c +#define SW_MODE_PWMPFM 0x0d +#define SW_MODE_PFMPFM 0x0f + #endif

On 15 May 2018 at 08:26, Lukasz Majewski lukma@denx.de wrote:
This commit adds some more defines for MC34708 PMIC.
Signed-off-by: Lukasz Majewski lukma@denx.de
Changes in v3:
- None
Changes in v2:
- None
include/fsl_pmic.h | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org

This patch adds definition of the number of bytes sent at once by the MC34708 PMIC.
Signed-off-by: Lukasz Majewski lukma@denx.de Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v3: - None
Changes in v2: - None
include/fsl_pmic.h | 1 + 1 file changed, 1 insertion(+)
diff --git a/include/fsl_pmic.h b/include/fsl_pmic.h index fc9e3152a9..132db81757 100644 --- a/include/fsl_pmic.h +++ b/include/fsl_pmic.h @@ -156,4 +156,5 @@ enum { #define SW_MODE_PWMPFM 0x0d #define SW_MODE_PFMPFM 0x0f
+#define MC34708_TRANSFER_SIZE 3 #endif

The struct uc_pmic_priv's trans_len field stores the number of types to be transmitted per PMIC transfer.
Signed-off-by: Lukasz Majewski lukma@denx.de Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v3: - Rename dm_pmic_info to uc_pmic_priv
Changes in v2: - New patch
drivers/power/pmic/pmic-uclass.c | 10 ++++++++++ include/power/pmic.h | 9 +++++++++ 2 files changed, 19 insertions(+)
diff --git a/drivers/power/pmic/pmic-uclass.c b/drivers/power/pmic/pmic-uclass.c index 5f0f6ff93e..d7e559a615 100644 --- a/drivers/power/pmic/pmic-uclass.c +++ b/drivers/power/pmic/pmic-uclass.c @@ -165,7 +165,17 @@ int pmic_clrsetbits(struct udevice *dev, uint reg, uint clr, uint set) return pmic_reg_write(dev, reg, byte); }
+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), }; diff --git a/include/power/pmic.h b/include/power/pmic.h index 2ca9365fc8..be9de6b4de 100644 --- a/include/power/pmic.h +++ b/include/power/pmic.h @@ -297,6 +297,15 @@ int pmic_reg_write(struct udevice *dev, uint reg, uint value); */ int pmic_clrsetbits(struct udevice *dev, uint reg, uint clr, uint set);
+/* + * This structure holds the private data for PMIC uclass + * For now we store information about the number of bytes + * being sent at once to the device. + */ +struct uc_pmic_priv { + uint trans_len; +}; + #endif /* CONFIG_DM_PMIC */
#ifdef CONFIG_POWER

This commit provides support for transmissions larger than 1 byte for PMIC devices used with DM (e.g. MC34708 from NXP).
Signed-off-by: Lukasz Majewski lukma@denx.de Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v3: - Rename dm_pmic_info -> uc_pmic_priv - Replace printf() -> debug() - Use priv->trans_len instead of tx_num
Changes in v2: - pmic_reg_* fixes to use uclass private structure
drivers/power/pmic/pmic-uclass.c | 42 ++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-)
diff --git a/drivers/power/pmic/pmic-uclass.c b/drivers/power/pmic/pmic-uclass.c index d7e559a615..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,15 +166,21 @@ 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)

This patch adds support for MC34708 PMIC, to be used with driver model (DM).
Signed-off-by: Lukasz Majewski lukma@denx.de
---
Changes in v3: - Rename dm_pmic_info with uc_pmic_priv - Sort alphabetically includes - Add comment regarding MC34708 byte ordering
Changes in v2: - Support for uclass private data with trasfer length
drivers/power/pmic/Kconfig | 7 +++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/mc34708.c | 105 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 drivers/power/pmic/mc34708.c
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 64382b9deb..2ab3b9f9e1 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/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, +};

On 15 May 2018 at 08:26, Lukasz Majewski lukma@denx.de wrote:
This patch adds support for MC34708 PMIC, to be used with driver model (DM).
Signed-off-by: Lukasz Majewski lukma@denx.de
Changes in v3:
- Rename dm_pmic_info with uc_pmic_priv
- Sort alphabetically includes
- Add comment regarding MC34708 byte ordering
Changes in v2:
- Support for uclass private data with trasfer length
drivers/power/pmic/Kconfig | 7 +++ drivers/power/pmic/Makefile | 1 + drivers/power/pmic/mc34708.c | 105 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 drivers/power/pmic/mc34708.c
Reviewed-by: Simon Glass sjg@chromium.org

Up till now it was only possible to use 'pmic' command with a single byte transmission. The pmic_read|write functions has been replaced with ones, which don't need the transmission length as a parameter.
Due to that it is possible now to read data from PMICs transmitting more data than 1 byte at once (e.g. mc34708)
Signed-off-by: Lukasz Majewski lukma@denx.de Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v3: - Replace dm_pmic_info with uc_pmic_priv - Replace pmic_info with priv
Changes in v2: - New patch
cmd/pmic.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-)
diff --git a/cmd/pmic.c b/cmd/pmic.c index f4b4a3f588..e46d813a70 100644 --- a/cmd/pmic.c +++ b/cmd/pmic.c @@ -75,8 +75,9 @@ static int do_list(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
static int do_dump(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { + struct uc_pmic_priv *priv; struct udevice *dev; - uint8_t value; + char fmt[16]; uint reg; int ret;
@@ -86,12 +87,15 @@ static int do_dump(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) }
dev = currdev; - + priv = dev_get_uclass_priv(dev); printf("Dump pmic: %s registers\n", dev->name);
+ sprintf(fmt, "%%%d.%dx ", priv->trans_len * 2, + priv->trans_len * 2); + for (reg = 0; reg < pmic_reg_count(dev); reg++) { - ret = pmic_read(dev, reg, &value, 1); - if (ret) { + ret = pmic_reg_read(dev, reg); + if (ret < 0) { printf("Can't read register: %d\n", reg); return failure(ret); } @@ -99,7 +103,7 @@ static int do_dump(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) if (!(reg % 16)) printf("\n0x%02x: ", reg);
- printf("%2.2x ", value); + printf(fmt, ret); } printf("\n");
@@ -108,9 +112,10 @@ static int do_dump(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
static int do_read(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { + struct uc_pmic_priv *priv; struct udevice *dev; int regs, ret; - uint8_t value; + char fmt[24]; uint reg;
if (!currdev) { @@ -119,6 +124,7 @@ static int do_read(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) }
dev = currdev; + priv = dev_get_uclass_priv(dev);
if (argc != 2) return CMD_RET_USAGE; @@ -130,13 +136,15 @@ static int do_read(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return failure(-EFAULT); }
- ret = pmic_read(dev, reg, &value, 1); - if (ret) { + ret = pmic_reg_read(dev, reg); + if (ret < 0) { printf("Can't read PMIC register: %d!\n", reg); return failure(ret); }
- printf("0x%02x: 0x%2.2x\n", reg, value); + sprintf(fmt, "0x%%02x: 0x%%%d.%dx\n", priv->trans_len * 2, + priv->trans_len * 2); + printf(fmt, reg, ret);
return CMD_RET_SUCCESS; } @@ -144,9 +152,8 @@ static int do_read(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) static int do_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { struct udevice *dev; + uint reg, value; int regs, ret; - uint8_t value; - uint reg;
if (!currdev) { printf("First, set the PMIC device!\n"); @@ -167,7 +174,7 @@ static int do_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
value = simple_strtoul(argv[2], NULL, 0);
- ret = pmic_write(dev, reg, &value, 1); + ret = pmic_reg_write(dev, reg, value); if (ret) { printf("Can't write PMIC register: %d!\n", reg); return failure(ret);

This change enables support for MC34708 PMIC in sandbox. Now we can emulate the I2C transfers larger than 1 byte.
Notable changes for this driver:
- From now on the register number is not equal to index in the buffer, which emulates the PMIC registers
- The PMIC register's pool is now dynamically allocated up till 64 regs * 3 bytes each = 192 B
Signed-off-by: Lukasz Majewski lukma@denx.de Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v3: - Replace pr_err() with debug() - dm_pmic_info -> uc_pmic_priv
Changes in v2: - New patch
drivers/power/pmic/i2c_pmic_emul.c | 45 ++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 14 deletions(-)
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; }

This commit also provides the default values of the emulated MC34708 PMIC internal registers content.
Signed-off-by: Lukasz Majewski lukma@denx.de Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v3: - Fix DTS property style to compy with Device Tree specification as suggested by Fabio.
Changes in v2: - New patch
arch/sandbox/dts/sandbox.dts | 4 ++++ arch/sandbox/dts/sandbox64.dts | 4 ++++ arch/sandbox/dts/sandbox_pmic.dtsi | 33 +++++++++++++++++++++++++++++++++ arch/sandbox/dts/test.dts | 4 ++++ 4 files changed, 45 insertions(+)
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts index 1fb8225fbb..86680a6b11 100644 --- a/arch/sandbox/dts/sandbox.dts +++ b/arch/sandbox/dts/sandbox.dts @@ -115,6 +115,10 @@ sandbox_pmic: sandbox_pmic { reg = <0x40>; }; + + mc34708: pmic@41 { + reg = <0x41>; + }; };
lcd { diff --git a/arch/sandbox/dts/sandbox64.dts b/arch/sandbox/dts/sandbox64.dts index d6efc011de..8f707b47db 100644 --- a/arch/sandbox/dts/sandbox64.dts +++ b/arch/sandbox/dts/sandbox64.dts @@ -115,6 +115,10 @@ sandbox_pmic: sandbox_pmic { reg = <0x40>; }; + + mc34708: pmic@41 { + reg = <0x41>; + }; };
lcd { diff --git a/arch/sandbox/dts/sandbox_pmic.dtsi b/arch/sandbox/dts/sandbox_pmic.dtsi index 8a85cb9d6c..403656f25e 100644 --- a/arch/sandbox/dts/sandbox_pmic.dtsi +++ b/arch/sandbox/dts/sandbox_pmic.dtsi @@ -81,3 +81,36 @@ regulator-max-microvolt = <1500000>; }; }; + +&mc34708 { + compatible = "fsl,mc34708"; + + pmic_emul { + compatible = "sandbox,i2c-pmic"; + + reg-defaults = /bits/ 8 < + 0x00 0x80 0x08 0xff 0xff 0xff 0x2e 0x01 0x08 + 0x40 0x80 0x81 0x5f 0xff 0xfb 0x1e 0x80 0x18 + 0x00 0x00 0x0e 0x00 0x00 0x14 0x00 0x00 0x00 + 0x00 0x00 0x20 0x00 0x01 0x3a 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x40 0x00 0x00 0x00 + 0x42 0x21 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x30 0x5f + 0x01 0xff 0xff 0x00 0x00 0x00 0x00 0x7f 0xff + 0x92 0x49 0x24 0x59 0x6d 0x34 0x18 0xc1 0x8c + 0x00 0x60 0x18 0x51 0x48 0x45 0x14 0x51 0x45 + 0x00 0x06 0x32 0x00 0x00 0x00 0x06 0x9c 0x99 + 0x00 0x38 0x0a 0x00 0x38 0x0a 0x00 0x38 0x0a + 0x00 0x38 0x0a 0x84 0x00 0x00 0x00 0x00 0x00 + 0x80 0x90 0x8f 0xf8 0x00 0x04 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x01 0x31 0x7e 0x2b 0x03 0xfd 0xc0 0x36 0x1b + 0x60 0x06 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 0x00 0x00 0x00 + >; + }; +}; diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 06d0e8ce85..1bb5fb0f0f 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -227,6 +227,10 @@ sandbox_pmic: sandbox_pmic { reg = <0x40>; }; + + mc34708: pmic@41 { + reg = <0x41>; + }; };
adc@0 {

This MC34708 PMIC is somewhat special - it used single transfers (R/W) with 3 bytes size - up till now U-Boot's PMICs only used 1 byte.
Signed-off-by: Lukasz Majewski lukma@denx.de Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v3: - Enable MC34708 PMIC support in sandbox_{flattree|spl}_defconfig
Changes in v2: - New patch
configs/sandbox_defconfig | 1 + configs/sandbox_flattree_defconfig | 1 + configs/sandbox_spl_defconfig | 1 + 3 files changed, 3 insertions(+)
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index c1cdd59c54..2fc84a16c9 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -142,6 +142,7 @@ CONFIG_DM_PMIC=y CONFIG_PMIC_ACT8846=y CONFIG_DM_PMIC_PFUZE100=y CONFIG_DM_PMIC_MAX77686=y +CONFIG_DM_PMIC_MC34708=y CONFIG_PMIC_PM8916=y CONFIG_PMIC_RK8XX=y CONFIG_PMIC_S2MPS11=y diff --git a/configs/sandbox_flattree_defconfig b/configs/sandbox_flattree_defconfig index 9b8d033838..e922c4b38f 100644 --- a/configs/sandbox_flattree_defconfig +++ b/configs/sandbox_flattree_defconfig @@ -125,6 +125,7 @@ CONFIG_DM_PMIC=y CONFIG_PMIC_ACT8846=y CONFIG_DM_PMIC_PFUZE100=y CONFIG_DM_PMIC_MAX77686=y +CONFIG_DM_PMIC_MC34708=y CONFIG_PMIC_PM8916=y CONFIG_PMIC_S2MPS11=y CONFIG_DM_PMIC_SANDBOX=y diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig index c308628199..fb6bb4baa2 100644 --- a/configs/sandbox_spl_defconfig +++ b/configs/sandbox_spl_defconfig @@ -141,6 +141,7 @@ CONFIG_DM_PMIC=y CONFIG_PMIC_ACT8846=y CONFIG_DM_PMIC_PFUZE100=y CONFIG_DM_PMIC_MAX77686=y +CONFIG_DM_PMIC_MC34708=y CONFIG_PMIC_PM8916=y CONFIG_PMIC_RK8XX=y CONFIG_PMIC_S2MPS11=y

The common code can be excluded to be reused by tests for other PMIC.
Signed-off-by: Lukasz Majewski lukma@denx.de Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v3: - None
Changes in v2: - New patch
test/dm/pmic.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/test/dm/pmic.c b/test/dm/pmic.c index b2061178fc..c24bd3b0a1 100644 --- a/test/dm/pmic.c +++ b/test/dm/pmic.c @@ -21,9 +21,9 @@ #include <test/ut.h>
/* Test PMIC get method */ -static int dm_test_power_pmic_get(struct unit_test_state *uts) + +static inline int power_pmic_get(struct unit_test_state *uts, char *name) { - const char *name = "sandbox_pmic"; struct udevice *dev;
ut_assertok(pmic_get(name, &dev)); @@ -34,6 +34,14 @@ static int dm_test_power_pmic_get(struct unit_test_state *uts)
return 0; } + +/* Test PMIC get method */ +static int dm_test_power_pmic_get(struct unit_test_state *uts) +{ + power_pmic_get(uts, "sandbox_pmic"); + + return 0; +} DM_TEST(dm_test_power_pmic_get, DM_TESTF_SCAN_FDT);
/* Test PMIC I/O */

Following tests has been added for mc34708 device:
- get_test for mc34708 PMIC - Check if proper number of registers is read - Check if default (emulated via i2c device) value is properly read - Check if value write/read operation is correct - Perform tests to check if pmic_clrsetbits() is working correctly
Signed-off-by: Lukasz Majewski lukma@denx.de Reviewed-by: Simon Glass sjg@chromium.org
---
Changes in v3: - Fix pmic.c test code after adjusting the sandbox PMIC related dts
Changes in v2: - New patch
test/dm/pmic.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+)
diff --git a/test/dm/pmic.c b/test/dm/pmic.c index c24bd3b0a1..b582329a9c 100644 --- a/test/dm/pmic.c +++ b/test/dm/pmic.c @@ -19,6 +19,7 @@ #include <power/pmic.h> #include <power/sandbox_pmic.h> #include <test/ut.h> +#include <fsl_pmic.h>
/* Test PMIC get method */
@@ -44,6 +45,16 @@ static int dm_test_power_pmic_get(struct unit_test_state *uts) } DM_TEST(dm_test_power_pmic_get, DM_TESTF_SCAN_FDT);
+/* PMIC get method - MC34708 - for 3 bytes transmission */ +static int dm_test_power_pmic_mc34708_get(struct unit_test_state *uts) +{ + power_pmic_get(uts, "pmic@41"); + + return 0; +} + +DM_TEST(dm_test_power_pmic_mc34708_get, DM_TESTF_SCAN_FDT); + /* Test PMIC I/O */ static int dm_test_power_pmic_io(struct unit_test_state *uts) { @@ -72,3 +83,48 @@ static int dm_test_power_pmic_io(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_power_pmic_io, DM_TESTF_SCAN_FDT); + +#define MC34708_PMIC_REG_COUNT 64 +#define MC34708_PMIC_TEST_VAL 0x125534 +static int dm_test_power_pmic_mc34708_regs_check(struct unit_test_state *uts) +{ + struct udevice *dev; + int reg_count; + + ut_assertok(pmic_get("pmic@41", &dev)); + + /* Check number of PMIC registers */ + reg_count = pmic_reg_count(dev); + ut_asserteq(reg_count, MC34708_PMIC_REG_COUNT); + + return 0; +} + +DM_TEST(dm_test_power_pmic_mc34708_regs_check, DM_TESTF_SCAN_FDT); + +static int dm_test_power_pmic_mc34708_rw_val(struct unit_test_state *uts) +{ + struct udevice *dev; + int val; + + ut_assertok(pmic_get("pmic@41", &dev)); + + /* Check if single 3 byte read is successful */ + val = pmic_reg_read(dev, REG_POWER_CTL2); + ut_asserteq(val, 0x422100); + + /* Check if RW works */ + val = 0; + ut_assertok(pmic_reg_write(dev, REG_RTC_TIME, val)); + ut_assertok(pmic_reg_write(dev, REG_RTC_TIME, MC34708_PMIC_TEST_VAL)); + val = pmic_reg_read(dev, REG_RTC_TIME); + ut_asserteq(val, MC34708_PMIC_TEST_VAL); + + pmic_clrsetbits(dev, REG_POWER_CTL2, 0x3 << 8, 1 << 9); + val = pmic_reg_read(dev, REG_POWER_CTL2); + ut_asserteq(val, (0x422100 & ~(0x3 << 8)) | (1 << 9)); + + return 0; +} + +DM_TEST(dm_test_power_pmic_mc34708_rw_val, DM_TESTF_SCAN_FDT);
participants (2)
-
Lukasz Majewski
-
Simon Glass