From: Yi Zhang <[email protected]>
v2: fix an "&&" usage error of "mfd: 88pm800: fix probe bug" in v1
Yi Zhang (4):
mfd: 88pm800: fix NULL pointer error
mfd: 88pm800: remove "IRQF_TRIGGER_FALLING" flag
mfd: 88pm800: fix probe bug
mfd: 88pm800: add regulator support
drivers/mfd/88pm800.c | 147 +++++++++++++++++++++++++++++++++++++++----
include/linux/mfd/88pm80x.h | 48 ++++++++++++++
2 files changed, 182 insertions(+), 13 deletions(-)
--
1.7.4.1
From: Yi Zhang <[email protected]>
1) return 0 when probe function is successful
2) fine-tune pm800_pages_init()
Signed-off-by: Yi Zhang <[email protected]>
---
drivers/mfd/88pm800.c | 29 +++++++++++++++++++++--------
1 files changed, 21 insertions(+), 8 deletions(-)
diff --git a/drivers/mfd/88pm800.c b/drivers/mfd/88pm800.c
index 618a6b9..2c68cbc 100644
--- a/drivers/mfd/88pm800.c
+++ b/drivers/mfd/88pm800.c
@@ -369,32 +369,43 @@ static int pm800_pages_init(struct pm80x_chip *chip)
struct pm80x_subchip *subchip;
struct i2c_client *client = chip->client;
+ int ret = -ENODEV;
+
subchip = chip->subchip;
/* PM800 block power: i2c addr 0x31 */
- if (subchip->power_page_addr) {
+ if (subchip && (subchip->power_page_addr)) {
subchip->power_page =
i2c_new_dummy(client->adapter, subchip->power_page_addr);
subchip->regmap_power =
devm_regmap_init_i2c(subchip->power_page,
&pm80x_regmap_config);
i2c_set_clientdata(subchip->power_page, chip);
- } else
+ } else {
dev_info(chip->dev,
"PM800 block power 0x31: No power_page_addr\n");
+ return ret;
+ }
/* PM800 block GPADC: i2c addr 0x32 */
- if (subchip->gpadc_page_addr) {
+ if (subchip && (subchip->gpadc_page_addr)) {
subchip->gpadc_page = i2c_new_dummy(client->adapter,
subchip->gpadc_page_addr);
subchip->regmap_gpadc =
devm_regmap_init_i2c(subchip->gpadc_page,
&pm80x_regmap_config);
i2c_set_clientdata(subchip->gpadc_page, chip);
- } else
+ } else {
dev_info(chip->dev,
"PM800 block GPADC 0x32: No gpadc_page_addr\n");
+ goto out_gpadc_page;
+ }
return 0;
+
+out_gpadc_page:
+ regmap_exit(subchip->regmap_power);
+ i2c_unregister_device(subchip->power_page);
+ return ret;
}
static void pm800_pages_exit(struct pm80x_chip *chip)
@@ -537,16 +548,18 @@ static int pm800_probe(struct i2c_client *client,
ret = device_800_init(chip, pdata);
if (ret) {
dev_err(chip->dev, "%s id 0x%x failed!\n", __func__, chip->id);
- goto err_subchip_alloc;
+ goto err_800_init;
}
if (pdata->plat_config)
pdata->plat_config(chip, pdata);
-err_subchip_alloc:
- mfd_remove_devices(chip->dev);
- device_irq_exit_800(chip);
+ return 0;
+
+err_800_init:
+ pm800_pages_exit(chip);
err_page_init:
+err_subchip_alloc:
pm80x_deinit();
out_init:
return ret;
--
1.7.4.1
From: Yi Zhang <[email protected]>
move "device_800_init" to fix NULL pointer error when
calling "device_gpadc_init"
for "device_gpadc_init" needs "subchip->regmap_gpadc"
to set registers via regmap interface
Signed-off-by: Yi Zhang <[email protected]>
---
drivers/mfd/88pm800.c | 16 ++++++++--------
1 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/mfd/88pm800.c b/drivers/mfd/88pm800.c
index 582bda5..bbb6aa8 100644
--- a/drivers/mfd/88pm800.c
+++ b/drivers/mfd/88pm800.c
@@ -528,25 +528,25 @@ static int pm800_probe(struct i2c_client *client,
subchip->gpadc_page_addr = pdata->gpadc_page_addr;
chip->subchip = subchip;
- ret = device_800_init(chip, pdata);
- if (ret) {
- dev_err(chip->dev, "%s id 0x%x failed!\n", __func__, chip->id);
- goto err_subchip_alloc;
- }
-
ret = pm800_pages_init(chip);
if (ret) {
dev_err(&client->dev, "pm800_pages_init failed!\n");
goto err_page_init;
}
+ ret = device_800_init(chip, pdata);
+ if (ret) {
+ dev_err(chip->dev, "%s id 0x%x failed!\n", __func__, chip->id);
+ goto err_subchip_alloc;
+ }
+
if (pdata->plat_config)
pdata->plat_config(chip, pdata);
-err_page_init:
+err_subchip_alloc:
mfd_remove_devices(chip->dev);
device_irq_exit_800(chip);
-err_subchip_alloc:
+err_page_init:
pm80x_deinit();
out_init:
return ret;
--
1.7.4.1
From: Yi Zhang <[email protected]>
Signed-off-by: Yi Zhang <[email protected]>
---
drivers/mfd/88pm800.c | 108 +++++++++++++++++++++++++++++++++++++++++++
include/linux/mfd/88pm80x.h | 48 +++++++++++++++++++
2 files changed, 156 insertions(+), 0 deletions(-)
diff --git a/drivers/mfd/88pm800.c b/drivers/mfd/88pm800.c
index 2c68cbc..477295f 100644
--- a/drivers/mfd/88pm800.c
+++ b/drivers/mfd/88pm800.c
@@ -167,6 +167,62 @@ static struct mfd_cell onkey_devs[] = {
},
};
+static struct resource regulator_resources[] = {
+ {PM800_ID_BUCK1, PM800_ID_BUCK1, "buck-1", IORESOURCE_IO,},
+ {PM800_ID_BUCK2, PM800_ID_BUCK2, "buck-2", IORESOURCE_IO,},
+ {PM800_ID_BUCK3, PM800_ID_BUCK3, "buck-3", IORESOURCE_IO,},
+ {PM800_ID_BUCK4, PM800_ID_BUCK4, "buck-4", IORESOURCE_IO,},
+ {PM800_ID_BUCK5, PM800_ID_BUCK5, "buck-5", IORESOURCE_IO,},
+ {PM800_ID_LDO1, PM800_ID_LDO1, "ldo-01", IORESOURCE_IO,},
+ {PM800_ID_LDO2, PM800_ID_LDO2, "ldo-02", IORESOURCE_IO,},
+ {PM800_ID_LDO3, PM800_ID_LDO3, "ldo-03", IORESOURCE_IO,},
+ {PM800_ID_LDO4, PM800_ID_LDO4, "ldo-04", IORESOURCE_IO,},
+ {PM800_ID_LDO5, PM800_ID_LDO5, "ldo-05", IORESOURCE_IO,},
+ {PM800_ID_LDO6, PM800_ID_LDO6, "ldo-06", IORESOURCE_IO,},
+ {PM800_ID_LDO7, PM800_ID_LDO7, "ldo-07", IORESOURCE_IO,},
+ {PM800_ID_LDO8, PM800_ID_LDO8, "ldo-08", IORESOURCE_IO,},
+ {PM800_ID_LDO9, PM800_ID_LDO9, "ldo-09", IORESOURCE_IO,},
+ {PM800_ID_LDO10, PM800_ID_LDO10, "ldo-10", IORESOURCE_IO,},
+ {PM800_ID_LDO11, PM800_ID_LDO11, "ldo-11", IORESOURCE_IO,},
+ {PM800_ID_LDO12, PM800_ID_LDO12, "ldo-12", IORESOURCE_IO,},
+ {PM800_ID_LDO13, PM800_ID_LDO13, "ldo-13", IORESOURCE_IO,},
+ {PM800_ID_LDO14, PM800_ID_LDO14, "ldo-14", IORESOURCE_IO,},
+ {PM800_ID_LDO15, PM800_ID_LDO15, "ldo-15", IORESOURCE_IO,},
+ {PM800_ID_LDO16, PM800_ID_LDO16, "ldo-16", IORESOURCE_IO,},
+ {PM800_ID_LDO17, PM800_ID_LDO17, "ldo-17", IORESOURCE_IO,},
+ {PM800_ID_LDO18, PM800_ID_LDO18, "ldo-18", IORESOURCE_IO,},
+ {PM800_ID_LDO19, PM800_ID_LDO19, "ldo-19", IORESOURCE_IO,},
+};
+
+static struct mfd_cell regulator_devs[] = {
+ {"88pm80x-regulator", 0,},
+ {"88pm80x-regulator", 1,},
+ {"88pm80x-regulator", 2,},
+ {"88pm80x-regulator", 3,},
+ {"88pm80x-regulator", 4,},
+ {"88pm80x-regulator", 5,},
+ {"88pm80x-regulator", 6,},
+ {"88pm80x-regulator", 7,},
+ {"88pm80x-regulator", 8,},
+ {"88pm80x-regulator", 9,},
+ {"88pm80x-regulator", 10,},
+ {"88pm80x-regulator", 11,},
+ {"88pm80x-regulator", 12,},
+ {"88pm80x-regulator", 13,},
+ {"88pm80x-regulator", 14,},
+ {"88pm80x-regulator", 15,},
+ {"88pm80x-regulator", 16,},
+ {"88pm80x-regulator", 17,},
+ {"88pm80x-regulator", 18,},
+ {"88pm80x-regulator", 19,},
+ {"88pm80x-regulator", 20,},
+ {"88pm80x-regulator", 21,},
+ {"88pm80x-regulator", 22,},
+ {"88pm80x-regulator", 23,},
+};
+
+static struct regulator_init_data regulator_pdata[ARRAY_SIZE(regulator_devs)];
+
static const struct regmap_irq pm800_irqs[] = {
/* INT0 */
[PM800_IRQ_ONKEY] = {
@@ -315,6 +371,52 @@ out:
return ret;
}
+static int device_regulator_init(struct pm80x_chip *chip,
+ struct pm80x_platform_data *pdata)
+{
+ struct regulator_init_data *initdata;
+ int ret = 0;
+ int i, seq;
+
+ if (!pdata || !pdata->regulator) {
+ dev_warn(chip->dev, "Regulator pdata is unavailable!\n");
+ return 0;
+ }
+
+ if (pdata->num_regulators > ARRAY_SIZE(regulator_devs))
+ pdata->num_regulators = ARRAY_SIZE(regulator_devs);
+
+ for (i = 0; i < pdata->num_regulators; i++) {
+ initdata = &pdata->regulator[i];
+ seq = *(unsigned int *)initdata->driver_data;
+ if ((seq < 0) || (seq > PM800_ID_RG_MAX)) {
+ dev_err(chip->dev, "Wrong ID(%d) on regulator(%s)\n",
+ seq, initdata->constraints.name);
+ ret = -EINVAL;
+ goto out_err;
+ }
+ memcpy(®ulator_pdata[i], &pdata->regulator[i],
+ sizeof(struct regulator_init_data));
+ regulator_devs[i].platform_data = ®ulator_pdata[i];
+ regulator_devs[i].pdata_size =
+ sizeof(struct regulator_init_data);
+ regulator_devs[i].num_resources = 1;
+ regulator_devs[i].resources = ®ulator_resources[seq];
+
+ ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[i], 1,
+ ®ulator_resources[seq], 0, NULL);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to add regulator subdev\n");
+ goto out_err;
+ }
+ }
+
+ return 0;
+
+out_err:
+ return ret;
+}
+
static int device_irq_init_800(struct pm80x_chip *chip)
{
struct regmap *map = chip->regmap;
@@ -479,6 +581,12 @@ static int device_800_init(struct pm80x_chip *chip,
goto out;
}
+ ret = device_regulator_init(chip, pdata);
+ if (ret < 0) {
+ dev_err(chip->dev, "[%s]Failed to init regulators\n", __func__);
+ goto out;
+ }
+
ret =
mfd_add_devices(chip->dev, 0, &onkey_devs[0],
ARRAY_SIZE(onkey_devs), &onkey_resources[0], 0,
diff --git a/include/linux/mfd/88pm80x.h b/include/linux/mfd/88pm80x.h
index e94537b..2a3a959 100644
--- a/include/linux/mfd/88pm80x.h
+++ b/include/linux/mfd/88pm80x.h
@@ -16,6 +16,7 @@
#include <linux/interrupt.h>
#include <linux/regmap.h>
#include <linux/atomic.h>
+#include <linux/regulator/machine.h>
#define PM80X_VERSION_MASK (0xFF) /* 80X chip ID mask */
enum {
@@ -139,6 +140,51 @@ enum {
#define PM800_BUCK1_SLP1_SHIFT 0
#define PM800_BUCK1_SLP1_MASK (0x3 << PM800_BUCK1_SLP1_SHIFT)
+/* page 1 POWER */
+
+/* BUCK4 with DVC[0..3] */
+#define PM800_AUDIO_MODE_CONFIG1 (0x38)
+#define PM800_BUCK3 (0x41)
+#define PM800_BUCK4 (0x42)
+#define PM800_BUCK4_1 (0x43)
+#define PM800_BUCK4_2 (0x44)
+#define PM800_BUCK4_3 (0x45)
+#define PM800_BUCK5 (0x46)
+/* BUCK Sleep Mode Register 2: BUCK5 */
+#define PM800_BUCK_SLP2 (0x5B)
+#define PM800_BUCK5_SLP2_SHIFT 0
+#define PM800_BUCK5_SLP2_MASK (0x3 << PM800_BUCK5_SLP2_SHIFT)
+
+#define PM800_LDO1_1 (0x08)
+#define PM800_LDO1_2 (0x09)
+#define PM800_LDO1_3 (0x0a)
+#define PM800_LDO2 (0x0b)
+#define PM800_LDO3 (0x0c)
+#define PM800_LDO4 (0x0d)
+#define PM800_LDO5 (0x0e)
+#define PM800_LDO6 (0x0f)
+#define PM800_LDO7 (0x10)
+#define PM800_LDO8 (0x11)
+#define PM800_LDO9 (0x12)
+#define PM800_LDO10 (0x13)
+#define PM800_LDO11 (0x14)
+#define PM800_LDO12 (0x15)
+#define PM800_LDO13 (0x16)
+#define PM800_LDO14 (0x17)
+#define PM800_LDO15 (0x18)
+#define PM800_LDO16 (0x19)
+#define PM800_LDO17 (0x1a)
+#define PM800_LDO18 (0x1b)
+#define PM800_LDO19 (0x1c)
+/* LDO Sleep Mode Register 5: LDO[17..19] */
+#define PM800_LDO_SLP5 (0x60)
+#define PM800_LDO17_SLP5_SHIFT 0
+#define PM800_LDO17_SLP5_MASK (0x3 << PM800_LDO17_SLP5_SHIFT)
+#define PM800_LDO18_SLP5_SHIFT 2
+#define PM800_LDO18_SLP5_MASK (0x3 << PM800_LDO18_SLP5_SHIFT)
+#define PM800_LDO19_SLP5_SHIFT 4
+#define PM800_LDO19_SLP5_MASK (0x3 << PM800_LDO19_SLP5_SHIFT)
+
/* page 2 GPADC: slave adder 0x02 */
#define PM800_GPADC_MEAS_EN1 (0x01)
#define PM800_MEAS_EN1_VBAT (1 << 2)
@@ -309,10 +355,12 @@ struct pm80x_chip {
struct pm80x_platform_data {
struct pm80x_rtc_pdata *rtc;
+ struct regulator_init_data *regulator;
unsigned short power_page_addr; /* power page I2C address */
unsigned short gpadc_page_addr; /* gpadc page I2C address */
int irq_mode; /* Clear interrupt by read/write(0/1) */
int batt_det; /* enable/disable */
+ int num_regulators;
int (*plat_config)(struct pm80x_chip *chip,
struct pm80x_platform_data *pdata);
};
--
1.7.4.1
From: Yi Zhang <[email protected]>
for interrupt controller such as GIC who is level triggered,
"IRQF_TRIGGER_FALLING" will fail to request irq
Signed-off-by: Yi Zhang <[email protected]>
---
drivers/mfd/88pm800.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/mfd/88pm800.c b/drivers/mfd/88pm800.c
index bbb6aa8..618a6b9 100644
--- a/drivers/mfd/88pm800.c
+++ b/drivers/mfd/88pm800.c
@@ -318,7 +318,7 @@ out:
static int device_irq_init_800(struct pm80x_chip *chip)
{
struct regmap *map = chip->regmap;
- unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
+ unsigned long flags = IRQF_ONESHOT;
int data, mask, ret = -EINVAL;
if (!map || !chip->irq) {
--
1.7.4.1