aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/power/pmic/Kconfig7
-rw-r--r--drivers/power/pmic/Makefile1
-rw-r--r--drivers/power/pmic/i2c_pmic_emul.c45
-rw-r--r--drivers/power/pmic/mc34708.c105
-rw-r--r--drivers/power/pmic/pmic-uclass.c52
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),
};