88pm886 and 88pm880 are combo PMIC chip, which integrates
regulator, onkey, rtc, gpadc, charger, fuelgauge function;

this patch add the basic support for them, adding related resource, such as
interrupt, preparing for the client-device driver

Signed-off-by: Yi Zhang <yizh...@marvell.com>
---
 drivers/mfd/88pm880-table.c     | 180 ++++++++++++
 drivers/mfd/88pm886-table.c     | 181 ++++++++++++
 drivers/mfd/88pm88x-core.c      | 591 ++++++++++++++++++++++++++++++++++++++++
 drivers/mfd/88pm88x-i2c.c       | 167 ++++++++++++
 drivers/mfd/88pm88x-irq.c       | 172 ++++++++++++
 drivers/mfd/88pm88x.h           |  51 ++++
 drivers/mfd/Kconfig             |  12 +
 drivers/mfd/Makefile            |   3 +
 include/linux/mfd/88pm880-reg.h |  98 +++++++
 include/linux/mfd/88pm880.h     |  59 ++++
 include/linux/mfd/88pm886-reg.h |  59 ++++
 include/linux/mfd/88pm886.h     |  55 ++++
 include/linux/mfd/88pm88x-reg.h | 118 ++++++++
 include/linux/mfd/88pm88x.h     | 202 ++++++++++++++
 14 files changed, 1948 insertions(+)
 create mode 100644 drivers/mfd/88pm880-table.c
 create mode 100644 drivers/mfd/88pm886-table.c
 create mode 100644 drivers/mfd/88pm88x-core.c
 create mode 100644 drivers/mfd/88pm88x-i2c.c
 create mode 100644 drivers/mfd/88pm88x-irq.c
 create mode 100644 drivers/mfd/88pm88x.h
 create mode 100644 include/linux/mfd/88pm880-reg.h
 create mode 100644 include/linux/mfd/88pm880.h
 create mode 100644 include/linux/mfd/88pm886-reg.h
 create mode 100644 include/linux/mfd/88pm886.h
 create mode 100644 include/linux/mfd/88pm88x-reg.h
 create mode 100644 include/linux/mfd/88pm88x.h

diff --git a/drivers/mfd/88pm880-table.c b/drivers/mfd/88pm880-table.c
new file mode 100644
index 0000000..8bf1603
--- /dev/null
+++ b/drivers/mfd/88pm880-table.c
@@ -0,0 +1,180 @@
+/*
+ * Marvell 88PM880 specific setting
+ *
+ * Copyright (C) 2015 Marvell International Ltd.
+ *  Yi Zhang <yizh...@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/mfd/88pm88x.h>
+#include <linux/mfd/88pm880.h>
+#include <linux/mfd/88pm88x-reg.h>
+
+#include "88pm88x.h"
+
+#define PM880_BUCK_NAME                "88pm880-buck"
+#define PM880_LDO_NAME         "88pm880-ldo"
+
+const struct regmap_config pm880_base_i2c_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = 0xfe,
+};
+EXPORT_SYMBOL_GPL(pm880_base_i2c_regmap);
+
+const struct regmap_config pm880_power_i2c_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = 0xfe,
+};
+EXPORT_SYMBOL_GPL(pm880_power_i2c_regmap);
+
+const struct regmap_config pm880_gpadc_i2c_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = 0xfe,
+};
+EXPORT_SYMBOL_GPL(pm880_gpadc_i2c_regmap);
+
+const struct regmap_config pm880_battery_i2c_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = 0xfe,
+};
+EXPORT_SYMBOL_GPL(pm880_battery_i2c_regmap);
+
+const struct regmap_config pm880_test_i2c_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = 0xfe,
+};
+EXPORT_SYMBOL_GPL(pm880_test_i2c_regmap);
+
+static const struct resource buck_resources[] = {
+       {
+       .name = PM880_BUCK_NAME,
+       },
+};
+
+static const struct resource ldo_resources[] = {
+       {
+       .name = PM880_LDO_NAME,
+       },
+};
+
+const struct mfd_cell pm880_cell_devs[] = {
+       CELL_DEV(PM880_BUCK_NAME, buck_resources, "marvell,88pm880-buck1a", 0),
+       CELL_DEV(PM880_BUCK_NAME, buck_resources, "marvell,88pm880-buck2", 1),
+       CELL_DEV(PM880_BUCK_NAME, buck_resources, "marvell,88pm880-buck3", 2),
+       CELL_DEV(PM880_BUCK_NAME, buck_resources, "marvell,88pm880-buck4", 3),
+       CELL_DEV(PM880_BUCK_NAME, buck_resources, "marvell,88pm880-buck5", 4),
+       CELL_DEV(PM880_BUCK_NAME, buck_resources, "marvell,88pm880-buck6", 5),
+       CELL_DEV(PM880_BUCK_NAME, buck_resources, "marvell,88pm880-buck7", 6),
+       CELL_DEV(PM880_LDO_NAME, ldo_resources, "marvell,88pm880-ldo1", 7),
+       CELL_DEV(PM880_LDO_NAME, ldo_resources, "marvell,88pm880-ldo2", 8),
+       CELL_DEV(PM880_LDO_NAME, ldo_resources, "marvell,88pm880-ldo3", 9),
+       CELL_DEV(PM880_LDO_NAME, ldo_resources, "marvell,88pm880-ldo4", 10),
+       CELL_DEV(PM880_LDO_NAME, ldo_resources, "marvell,88pm880-ldo5", 11),
+       CELL_DEV(PM880_LDO_NAME, ldo_resources, "marvell,88pm880-ldo6", 12),
+       CELL_DEV(PM880_LDO_NAME, ldo_resources, "marvell,88pm880-ldo7", 13),
+       CELL_DEV(PM880_LDO_NAME, ldo_resources, "marvell,88pm880-ldo8", 14),
+       CELL_DEV(PM880_LDO_NAME, ldo_resources, "marvell,88pm880-ldo9", 15),
+       CELL_DEV(PM880_LDO_NAME, ldo_resources, "marvell,88pm880-ldo10", 16),
+       CELL_DEV(PM880_LDO_NAME, ldo_resources, "marvell,88pm880-ldo11", 17),
+       CELL_DEV(PM880_LDO_NAME, ldo_resources, "marvell,88pm880-ldo12", 18),
+       CELL_DEV(PM880_LDO_NAME, ldo_resources, "marvell,88pm880-ldo13", 19),
+       CELL_DEV(PM880_LDO_NAME, ldo_resources, "marvell,88pm880-ldo14", 20),
+       CELL_DEV(PM880_LDO_NAME, ldo_resources, "marvell,88pm880-ldo15", 21),
+       CELL_DEV(PM880_LDO_NAME, ldo_resources, "marvell,88pm880-ldo16", 22),
+       CELL_DEV(PM880_LDO_NAME, ldo_resources, "marvell,88pm880-ldo17", 23),
+       CELL_DEV(PM880_LDO_NAME, ldo_resources, "marvell,88pm880-ldo18", 24),
+};
+EXPORT_SYMBOL_GPL(pm880_cell_devs);
+
+struct pmic_cell_info pm880_cell_info = {
+       .cells   = pm880_cell_devs,
+       .cell_nr = ARRAY_SIZE(pm880_cell_devs),
+};
+EXPORT_SYMBOL_GPL(pm880_cell_info);
+
+static const struct reg_default pm880_base_patch[] = {
+       {PM88X_WDOG, 0x1},       /* disable watchdog */
+       {PM88X_AON_CTRL2, 0x2a},  /* output 32kHZ from XO */
+       {PM88X_BK_OSC_CTRL1, 0x0f}, /* OSC_FREERUN = 1, to lock FLL */
+       {PM88X_LOWPOWER2, 0x20}, /* XO_LJ = 1, enable low jitter for 32kHZ */
+       /* enable LPM for internal reference group in sleep */
+       {PM88X_LOWPOWER4, 0xc0},
+       {PM88X_BK_OSC_CTRL3, 0xc0}, /* set the duty cycle of charger DC/DC to 
max */
+};
+
+static const struct reg_default pm880_power_patch[] = {
+};
+
+static const struct reg_default pm880_gpadc_patch[] = {
+       {PM88X_GPADC_CONFIG6, 0x03}, /* enable non-stop mode */
+};
+
+static const struct reg_default pm880_battery_patch[] = {
+       {PM88X_CHGBK_CONFIG6, 0xe1},
+};
+
+static const struct reg_default pm880_test_patch[] = {
+};
+
+/* 88pm880 chip itself related */
+int pm880_apply_patch(struct pm88x_chip *chip)
+{
+       int ret, size;
+
+       if (!chip || !chip->base_regmap || !chip->power_regmap ||
+           !chip->gpadc_regmap || !chip->battery_regmap ||
+           !chip->test_regmap)
+               return -EINVAL;
+
+       size = ARRAY_SIZE(pm880_base_patch);
+       if (size == 0)
+               goto power;
+       ret = regmap_register_patch(chip->base_regmap, pm880_base_patch, size);
+       if (ret < 0)
+               return ret;
+
+power:
+       size = ARRAY_SIZE(pm880_power_patch);
+       if (size == 0)
+               goto gpadc;
+       ret = regmap_register_patch(chip->power_regmap, pm880_power_patch, 
size);
+       if (ret < 0)
+               return ret;
+
+gpadc:
+       size = ARRAY_SIZE(pm880_gpadc_patch);
+       if (size == 0)
+               goto battery;
+       ret = regmap_register_patch(chip->gpadc_regmap, pm880_gpadc_patch, 
size);
+       if (ret < 0)
+               return ret;
+battery:
+       size = ARRAY_SIZE(pm880_battery_patch);
+       if (size == 0)
+               goto test;
+       ret = regmap_register_patch(chip->battery_regmap, pm880_battery_patch, 
size);
+       if (ret < 0)
+               return ret;
+
+test:
+       size = ARRAY_SIZE(pm880_test_patch);
+       if (size == 0)
+               goto out;
+       ret = regmap_register_patch(chip->test_regmap, pm880_test_patch, size);
+       if (ret < 0)
+               return ret;
+out:
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pm880_apply_patch);
diff --git a/drivers/mfd/88pm886-table.c b/drivers/mfd/88pm886-table.c
new file mode 100644
index 0000000..eda0921
--- /dev/null
+++ b/drivers/mfd/88pm886-table.c
@@ -0,0 +1,181 @@
+/*
+ * Marvell 88PM886 specific setting
+ *
+ * Copyright (C) 2015 Marvell International Ltd.
+ *  Yi Zhang <yizh...@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/mfd/88pm88x.h>
+#include <linux/mfd/88pm886.h>
+#include <linux/mfd/88pm886-reg.h>
+#include <linux/mfd/88pm88x-reg.h>
+
+#include "88pm88x.h"
+
+#define PM886_BUCK_NAME                "88pm886-buck"
+#define PM886_LDO_NAME         "88pm886-ldo"
+
+const struct regmap_config pm886_base_i2c_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = 0xfe,
+};
+EXPORT_SYMBOL_GPL(pm886_base_i2c_regmap);
+
+const struct regmap_config pm886_power_i2c_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = 0xfe,
+};
+EXPORT_SYMBOL_GPL(pm886_power_i2c_regmap);
+
+const struct regmap_config pm886_gpadc_i2c_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = 0xfe,
+};
+EXPORT_SYMBOL_GPL(pm886_gpadc_i2c_regmap);
+
+const struct regmap_config pm886_battery_i2c_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = 0xfe,
+};
+EXPORT_SYMBOL_GPL(pm886_battery_i2c_regmap);
+
+const struct regmap_config pm886_test_i2c_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = 0xfe,
+};
+EXPORT_SYMBOL_GPL(pm886_test_i2c_regmap);
+
+static const struct resource buck_resources[] = {
+       {
+       .name = PM886_BUCK_NAME,
+       },
+};
+
+static const struct resource ldo_resources[] = {
+       {
+       .name = PM886_LDO_NAME,
+       },
+};
+
+const struct mfd_cell pm886_cell_devs[] = {
+       CELL_DEV(PM886_BUCK_NAME, buck_resources, "marvell,88pm886-buck1", 0),
+       CELL_DEV(PM886_BUCK_NAME, buck_resources, "marvell,88pm886-buck2", 1),
+       CELL_DEV(PM886_BUCK_NAME, buck_resources, "marvell,88pm886-buck3", 2),
+       CELL_DEV(PM886_BUCK_NAME, buck_resources, "marvell,88pm886-buck4", 3),
+       CELL_DEV(PM886_BUCK_NAME, buck_resources, "marvell,88pm886-buck5", 4),
+       CELL_DEV(PM886_LDO_NAME, ldo_resources, "marvell,88pm886-ldo1", 5),
+       CELL_DEV(PM886_LDO_NAME, ldo_resources, "marvell,88pm886-ldo2", 6),
+       CELL_DEV(PM886_LDO_NAME, ldo_resources, "marvell,88pm886-ldo3", 7),
+       CELL_DEV(PM886_LDO_NAME, ldo_resources, "marvell,88pm886-ldo4", 8),
+       CELL_DEV(PM886_LDO_NAME, ldo_resources, "marvell,88pm886-ldo5", 9),
+       CELL_DEV(PM886_LDO_NAME, ldo_resources, "marvell,88pm886-ldo6", 10),
+       CELL_DEV(PM886_LDO_NAME, ldo_resources, "marvell,88pm886-ldo7", 11),
+       CELL_DEV(PM886_LDO_NAME, ldo_resources, "marvell,88pm886-ldo8", 12),
+       CELL_DEV(PM886_LDO_NAME, ldo_resources, "marvell,88pm886-ldo9", 13),
+       CELL_DEV(PM886_LDO_NAME, ldo_resources, "marvell,88pm886-ldo10", 14),
+       CELL_DEV(PM886_LDO_NAME, ldo_resources, "marvell,88pm886-ldo11", 15),
+       CELL_DEV(PM886_LDO_NAME, ldo_resources, "marvell,88pm886-ldo12", 16),
+       CELL_DEV(PM886_LDO_NAME, ldo_resources, "marvell,88pm886-ldo13", 17),
+       CELL_DEV(PM886_LDO_NAME, ldo_resources, "marvell,88pm886-ldo14", 18),
+       CELL_DEV(PM886_LDO_NAME, ldo_resources, "marvell,88pm886-ldo15", 19),
+       CELL_DEV(PM886_LDO_NAME, ldo_resources, "marvell,88pm886-ldo16", 20),
+};
+EXPORT_SYMBOL_GPL(pm886_cell_devs);
+
+struct pmic_cell_info pm886_cell_info = {
+       .cells   = pm886_cell_devs,
+       .cell_nr = ARRAY_SIZE(pm886_cell_devs),
+};
+EXPORT_SYMBOL_GPL(pm886_cell_info);
+
+static const struct reg_default pm886_base_patch[] = {
+       {PM88X_WDOG, 0x1},       /* disable watchdog */
+       {PM88X_GPIO_CTRL1, 0x40}, /* gpio1: dvc    , gpio0: input   */
+       {PM88X_GPIO_CTRL2, 0x00}, /*               , gpio2: input   */
+       {PM88X_GPIO_CTRL3, 0x44}, /* dvc2          , dvc1           */
+       {PM88X_GPIO_CTRL4, 0x00}, /* gpio5v_1:input, gpio5v_2: input*/
+       {PM88X_AON_CTRL2, 0x2a},  /* output 32kHZ from XO */
+       {PM88X_BK_OSC_CTRL1, 0x0f}, /* OSC_FREERUN = 1, to lock FLL */
+       {PM88X_LOWPOWER2, 0x20}, /* XO_LJ = 1, enable low jitter for 32kHZ */
+       /* enable LPM for internal reference group in sleep */
+       {PM88X_LOWPOWER4, 0xc0},
+       {PM88X_BK_OSC_CTRL3, 0xc0}, /* set the duty cycle of charger DC/DC to 
max */
+};
+
+static const struct reg_default pm886_power_patch[] = {
+};
+
+static const struct reg_default pm886_gpadc_patch[] = {
+       {PM88X_GPADC_CONFIG6, 0x03}, /* enable non-stop mode */
+};
+
+static const struct reg_default pm886_battery_patch[] = {
+       {PM88X_CHGBK_CONFIG6, 0xe1},
+};
+
+static const struct reg_default pm886_test_patch[] = {
+};
+
+/* 88pm886 chip itself related */
+int pm886_apply_patch(struct pm88x_chip *chip)
+{
+       int ret, size;
+
+       if (!chip || !chip->base_regmap || !chip->power_regmap ||
+           !chip->gpadc_regmap || !chip->battery_regmap ||
+           !chip->test_regmap)
+               return -EINVAL;
+
+       size = ARRAY_SIZE(pm886_base_patch);
+       if (size == 0)
+               goto power;
+       ret = regmap_register_patch(chip->base_regmap, pm886_base_patch, size);
+       if (ret < 0)
+               return ret;
+
+power:
+       size = ARRAY_SIZE(pm886_power_patch);
+       if (size == 0)
+               goto gpadc;
+       ret = regmap_register_patch(chip->power_regmap, pm886_power_patch, 
size);
+       if (ret < 0)
+               return ret;
+
+gpadc:
+       size = ARRAY_SIZE(pm886_gpadc_patch);
+       if (size == 0)
+               goto battery;
+       ret = regmap_register_patch(chip->gpadc_regmap, pm886_gpadc_patch, 
size);
+       if (ret < 0)
+               return ret;
+battery:
+       size = ARRAY_SIZE(pm886_battery_patch);
+       if (size == 0)
+               goto test;
+       ret = regmap_register_patch(chip->battery_regmap, pm886_battery_patch, 
size);
+       if (ret < 0)
+               return ret;
+
+test:
+       size = ARRAY_SIZE(pm886_test_patch);
+       if (size == 0)
+               goto out;
+       ret = regmap_register_patch(chip->test_regmap, pm886_test_patch, size);
+       if (ret < 0)
+               return ret;
+out:
+       return 0;
+}
+EXPORT_SYMBOL_GPL(pm886_apply_patch);
diff --git a/drivers/mfd/88pm88x-core.c b/drivers/mfd/88pm88x-core.c
new file mode 100644
index 0000000..294abad
--- /dev/null
+++ b/drivers/mfd/88pm88x-core.c
@@ -0,0 +1,591 @@
+/*
+ * Base driver for Marvell 88PM886/88PM880 PMIC
+ *
+ * Copyright (C) 2015 Marvell International Ltd.
+ *  Yi Zhang <yizh...@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/88pm88x.h>
+#include <linux/mfd/88pm886.h>
+#include <linux/mfd/88pm880.h>
+#include <linux/regulator/machine.h>
+
+#include "88pm88x.h"
+
+#define PM88X_POWER_UP_LOG             (0x17)
+#define PM88X_POWER_DOWN_LOG1          (0xe5)
+#define PM88X_POWER_DOWN_LOG2          (0xe6)
+#define PM88X_SW_PDOWN                 (1 << 5)
+
+static const struct resource onkey_resources[] = {
+       CELL_IRQ_RESOURCE(PM88X_ONKEY_NAME, PM88X_IRQ_ONKEY),
+};
+
+static const struct resource rtc_resources[] = {
+       CELL_IRQ_RESOURCE(PM88X_RTC_NAME, PM88X_IRQ_RTC),
+};
+
+static const struct resource charger_resources[] = {
+       CELL_IRQ_RESOURCE("88pm88x-chg-fail", PM88X_IRQ_CHG_FAIL),
+       CELL_IRQ_RESOURCE("88pm88x-chg-done", PM88X_IRQ_CHG_DONE),
+       CELL_IRQ_RESOURCE("88pm88x-chg-good", PM88X_IRQ_CHG_GOOD),
+};
+
+static const struct resource battery_resources[] = {
+       CELL_IRQ_RESOURCE("88pm88x-bat-cc", PM88X_IRQ_CC),
+       CELL_IRQ_RESOURCE("88pm88x-bat-volt", PM88X_IRQ_VBAT),
+       CELL_IRQ_RESOURCE("88pm88x-bat-detect", PM88X_IRQ_BAT_DET),
+};
+
+static const struct resource headset_resources[] = {
+       CELL_IRQ_RESOURCE("88pm88x-headset-det", PM88X_IRQ_HS_DET),
+       CELL_IRQ_RESOURCE("88pm88x-mic-det", PM88X_IRQ_MIC_DET),
+};
+
+static const struct resource vbus_resources[] = {
+       CELL_IRQ_RESOURCE("88pm88x-vbus-det", PM88X_IRQ_VBUS),
+       CELL_IRQ_RESOURCE("88pm88x-gpadc0", PM88X_IRQ_GPADC0),
+       CELL_IRQ_RESOURCE("88pm88x-gpadc1", PM88X_IRQ_GPADC1),
+       CELL_IRQ_RESOURCE("88pm88x-gpadc2", PM88X_IRQ_GPADC2),
+       CELL_IRQ_RESOURCE("88pm88x-gpadc3", PM88X_IRQ_GPADC3),
+       CELL_IRQ_RESOURCE("88pm88x-otg-fail", PM88X_IRQ_OTG_FAIL),
+};
+
+static const struct resource leds_resources[] = {
+       CELL_IRQ_RESOURCE("88pm88x-cfd-fail", PM88X_IRQ_CFD_FAIL),
+};
+
+static const struct resource dvc_resources[] = {
+       {
+       .name = PM88X_DVC_NAME,
+       },
+};
+
+static const struct resource rgb_resources[] = {
+       {
+       .name = PM88X_RGB_NAME,
+       },
+};
+
+static const struct resource gpadc_resources[] = {
+       {
+       .name = PM88X_GPADC_NAME,
+       },
+};
+
+static const struct mfd_cell common_cell_devs[] = {
+       CELL_DEV(PM88X_RTC_NAME, rtc_resources, "marvell,88pm88x-rtc", -1),
+       CELL_DEV(PM88X_ONKEY_NAME, onkey_resources, "marvell,88pm88x-onkey", 
-1),
+       CELL_DEV(PM88X_CHARGER_NAME, charger_resources, 
"marvell,88pm88x-charger", -1),
+       CELL_DEV(PM88X_BATTERY_NAME, battery_resources, 
"marvell,88pm88x-battery", -1),
+       CELL_DEV(PM88X_HEADSET_NAME, headset_resources, 
"marvell,88pm88x-headset", -1),
+       CELL_DEV(PM88X_VBUS_NAME, vbus_resources, "marvell,88pm88x-vbus", -1),
+       CELL_DEV(PM88X_CFD_NAME, leds_resources, "marvell,88pm88x-leds", 
PM88X_FLASH_LED),
+       CELL_DEV(PM88X_CFD_NAME, leds_resources, "marvell,88pm88x-leds", 
PM88X_TORCH_LED),
+       CELL_DEV(PM88X_DVC_NAME, dvc_resources, "marvell,88pm88x-dvc", -1),
+       CELL_DEV(PM88X_RGB_NAME, rgb_resources, "marvell,88pm88x-rgb0", 
PM88X_RGB_LED0),
+       CELL_DEV(PM88X_RGB_NAME, rgb_resources, "marvell,88pm88x-rgb1", 
PM88X_RGB_LED1),
+       CELL_DEV(PM88X_RGB_NAME, rgb_resources, "marvell,88pm88x-rgb2", 
PM88X_RGB_LED2),
+       CELL_DEV(PM88X_GPADC_NAME, gpadc_resources, "marvell,88pm88x-gpadc", 
-1),
+};
+
+const struct of_device_id pm88x_of_match[] = {
+       { .compatible = "marvell,88pm886", .data = (void *)PM886 },
+       { .compatible = "marvell,88pm880", .data = (void *)PM880 },
+       {},
+};
+EXPORT_SYMBOL_GPL(pm88x_of_match);
+
+struct pm88x_chip *pm88x_init_chip(struct i2c_client *client)
+{
+       struct pm88x_chip *chip;
+
+       chip = devm_kzalloc(&client->dev, sizeof(struct pm88x_chip), 
GFP_KERNEL);
+       if (!chip)
+               return ERR_PTR(-ENOMEM);
+
+       chip->client = client;
+       chip->irq = client->irq;
+       chip->dev = &client->dev;
+       chip->ldo_page_addr = client->addr + 1;
+       chip->power_page_addr = client->addr + 1;
+       chip->gpadc_page_addr = client->addr + 2;
+       chip->battery_page_addr = client->addr + 3;
+       chip->buck_page_addr = client->addr + 4;
+       chip->test_page_addr = client->addr + 7;
+
+       dev_set_drvdata(chip->dev, chip);
+       i2c_set_clientdata(chip->client, chip);
+
+       device_init_wakeup(&client->dev, 1);
+
+       return chip;
+}
+
+int pm88x_parse_dt(struct device_node *np, struct pm88x_chip *chip)
+{
+       if (!chip)
+               return -EINVAL;
+
+       chip->irq_mode =
+               !of_property_read_bool(np, "marvell,88pm88x-irq-write-clear");
+
+       return 0;
+}
+
+
+static void parse_powerup_down_log(struct pm88x_chip *chip)
+{
+       int powerup, powerdown1, powerdown2, bit;
+       int powerup_bits, powerdown1_bits, powerdown2_bits;
+       static const char * const powerup_name[] = {
+               "ONKEY_WAKEUP   ",
+               "CHG_WAKEUP     ",
+               "EXTON_WAKEUP   ",
+               "SMPL_WAKEUP    ",
+               "ALARM_WAKEUP   ",
+               "FAULT_WAKEUP   ",
+               "BAT_WAKEUP     ",
+               "WLCHG_WAKEUP   ",
+       };
+       static const char * const powerdown1_name[] = {
+               "OVER_TEMP ",
+               "UV_VANA5  ",
+               "SW_PDOWN  ",
+               "FL_ALARM  ",
+               "WD        ",
+               "LONG_ONKEY",
+               "OV_VSYS   ",
+               "RTC_RESET "
+       };
+       static const char * const powerdown2_name[] = {
+               "HYB_DONE   ",
+               "UV_VBAT    ",
+               "HW_RESET2  ",
+               "PGOOD_PDOWN",
+               "LONKEY_RTC ",
+               "HW_RESET1  ",
+       };
+
+       regmap_read(chip->base_regmap, PM88X_POWER_UP_LOG, &powerup);
+       regmap_read(chip->base_regmap, PM88X_POWER_DOWN_LOG1, &powerdown1);
+       regmap_read(chip->base_regmap, PM88X_POWER_DOWN_LOG2, &powerdown2);
+
+       /*
+        * mask reserved bits
+        *
+        * note: HYB_DONE and HW_RESET1 are kept,
+        *       but should not be considered as power down events
+        */
+       switch (chip->type) {
+       case PM886:
+               powerup &= 0x7f;
+               powerdown2 &= 0x1f;
+               powerup_bits = 7;
+               powerdown1_bits = 8;
+               powerdown2_bits = 5;
+               break;
+       case PM880:
+               powerdown2 &= 0x3f;
+               powerup_bits = 8;
+               powerdown1_bits = 8;
+               powerdown2_bits = 6;
+               break;
+       default:
+               return;
+       }
+
+       /* keep globals for external usage */
+       chip->powerup = powerup;
+       chip->powerdown1 = powerdown1;
+       chip->powerdown2 = powerdown2;
+
+       /* power up log */
+       dev_info(chip->dev, "powerup log 0x%x: 0x%x\n",
+                PM88X_POWER_UP_LOG, powerup);
+       dev_info(chip->dev, " ----------------------------\n");
+       dev_info(chip->dev, "|  name(power up) |  status  |\n");
+       dev_info(chip->dev, "|-----------------|----------|\n");
+       for (bit = 0; bit < powerup_bits; bit++)
+               dev_info(chip->dev, "|  %s  |    %x     |\n",
+                       powerup_name[bit], (powerup >> bit) & 1);
+       dev_info(chip->dev, " ----------------------------\n");
+
+       /* power down log1 */
+       dev_info(chip->dev, "PowerDW Log1 0x%x: 0x%x\n",
+               PM88X_POWER_DOWN_LOG1, powerdown1);
+       dev_info(chip->dev, " -------------------------------\n");
+       dev_info(chip->dev, "| name(power down1)  |  status  |\n");
+       dev_info(chip->dev, "|--------------------|----------|\n");
+       for (bit = 0; bit < powerdown1_bits; bit++)
+               dev_info(chip->dev, "|    %s      |    %x     |\n",
+                       powerdown1_name[bit], (powerdown1 >> bit) & 1);
+       dev_info(chip->dev, " -------------------------------\n");
+
+       /* power down log2 */
+       dev_info(chip->dev, "PowerDW Log2 0x%x: 0x%x\n",
+               PM88X_POWER_DOWN_LOG2, powerdown2);
+       dev_info(chip->dev, " -------------------------------\n");
+       dev_info(chip->dev, "|  name(power down2) |  status  |\n");
+       dev_info(chip->dev, "|--------------------|----------|\n");
+       for (bit = 0; bit < powerdown2_bits; bit++)
+               dev_info(chip->dev, "|    %s     |    %x     |\n",
+                       powerdown2_name[bit], (powerdown2 >> bit) & 1);
+       dev_info(chip->dev, " -------------------------------\n");
+
+       /* write to clear power down log */
+       regmap_write(chip->base_regmap, PM88X_POWER_DOWN_LOG1, 0xff);
+       regmap_write(chip->base_regmap, PM88X_POWER_DOWN_LOG2, 0xff);
+}
+
+static const char *chip_stepping_to_string(unsigned int id)
+{
+       switch (id) {
+       case 0x00:
+               return "88pm886 A0";
+       case 0xa1:
+               return "88pm886 A1";
+       case 0xb0:
+               return "88pm880 A0";
+       case 0xb1:
+               return "88pm880 A1";
+       default:
+               break;
+       }
+
+       return "Unknown";
+}
+
+int pm88x_post_init_chip(struct pm88x_chip *chip)
+{
+       int ret;
+       unsigned int val;
+
+       if (!chip || !chip->base_regmap || !chip->power_regmap ||
+           !chip->gpadc_regmap || !chip->battery_regmap)
+               return -EINVAL;
+
+       /* save chip stepping */
+       ret = regmap_read(chip->base_regmap, PM88X_ID_REG, &val);
+       if (ret < 0) {
+               dev_err(chip->dev, "Failed to read chip ID: %d\n", ret);
+               return ret;
+       }
+       chip->chip_id = val;
+
+       dev_info(chip->dev, "PM88X chip ID = 0x%x(%s)\n", val,
+                       chip_stepping_to_string(chip->chip_id));
+
+       /* read before alarm wake up bit before initialize interrupt */
+       ret = regmap_read(chip->base_regmap, PM88X_RTC_ALARM_CTRL1, &val);
+       if (ret < 0) {
+               dev_err(chip->dev, "Failed to read RTC register: %d\n", ret);
+               return ret;
+       }
+       chip->rtc_wakeup = !!(val & PM88X_ALARM_WAKEUP);
+
+       parse_powerup_down_log(chip);
+
+       return 0;
+}
+
+int pm88x_init_pages(struct pm88x_chip *chip)
+{
+       struct i2c_client *client = chip->client;
+       const struct regmap_config *base_regmap_config;
+       const struct regmap_config *power_regmap_config;
+       const struct regmap_config *gpadc_regmap_config;
+       const struct regmap_config *battery_regmap_config;
+       const struct regmap_config *test_regmap_config;
+       int ret = 0;
+
+       if (!chip || !chip->power_page_addr ||
+           !chip->gpadc_page_addr || !chip->battery_page_addr)
+               return -ENODEV;
+
+       chip->type = pm88x_of_get_type(&client->dev);
+       switch (chip->type) {
+       case PM886:
+               base_regmap_config = &pm886_base_i2c_regmap;
+               power_regmap_config = &pm886_power_i2c_regmap;
+               gpadc_regmap_config = &pm886_gpadc_i2c_regmap;
+               battery_regmap_config = &pm886_battery_i2c_regmap;
+               test_regmap_config = &pm886_test_i2c_regmap;
+               break;
+       case PM880:
+               base_regmap_config = &pm880_base_i2c_regmap;
+               power_regmap_config = &pm880_power_i2c_regmap;
+               gpadc_regmap_config = &pm880_gpadc_i2c_regmap;
+               battery_regmap_config = &pm880_battery_i2c_regmap;
+               test_regmap_config = &pm880_test_i2c_regmap;
+               break;
+       default:
+               return -ENODEV;
+       }
+
+       /* base page */
+       chip->base_regmap = devm_regmap_init_i2c(client, base_regmap_config);
+       if (IS_ERR(chip->base_regmap)) {
+               dev_err(chip->dev, "Failed to init base_regmap: %d\n", ret);
+               ret = PTR_ERR(chip->base_regmap);
+               goto out;
+       }
+
+       /* power page */
+       chip->power_page = i2c_new_dummy(client->adapter, 
chip->power_page_addr);
+       if (!chip->power_page) {
+               dev_err(chip->dev, "Failed to new power_page: %d\n", ret);
+               ret = -ENODEV;
+               goto out;
+       }
+       chip->power_regmap = devm_regmap_init_i2c(chip->power_page,
+                                                 power_regmap_config);
+       if (IS_ERR(chip->power_regmap)) {
+               dev_err(chip->dev, "Failed to init power_regmap: %d\n", ret);
+               ret = PTR_ERR(chip->power_regmap);
+               goto out;
+       }
+
+       /* gpadc page */
+       chip->gpadc_page = i2c_new_dummy(client->adapter, 
chip->gpadc_page_addr);
+       if (!chip->gpadc_page) {
+               dev_err(chip->dev, "Failed to new gpadc_page: %d\n", ret);
+               ret = -ENODEV;
+               goto out;
+       }
+       chip->gpadc_regmap = devm_regmap_init_i2c(chip->gpadc_page,
+                                                 gpadc_regmap_config);
+       if (IS_ERR(chip->gpadc_regmap)) {
+               dev_err(chip->dev, "Failed to init gpadc_regmap: %d\n", ret);
+               ret = PTR_ERR(chip->gpadc_regmap);
+               goto out;
+       }
+
+       /* battery page */
+       chip->battery_page = i2c_new_dummy(client->adapter, 
chip->battery_page_addr);
+       if (!chip->battery_page) {
+               dev_err(chip->dev, "Failed to new gpadc_page: %d\n", ret);
+               ret = -ENODEV;
+               goto out;
+       }
+       chip->battery_regmap = devm_regmap_init_i2c(chip->battery_page,
+                                                 battery_regmap_config);
+       if (IS_ERR(chip->battery_regmap)) {
+               dev_err(chip->dev, "Failed to init battery_regmap: %d\n", ret);
+               ret = PTR_ERR(chip->battery_regmap);
+               goto out;
+       }
+
+       /* test page */
+       chip->test_page = i2c_new_dummy(client->adapter, chip->test_page_addr);
+       if (!chip->test_page) {
+               dev_err(chip->dev, "Failed to new test_page: %d\n", ret);
+               ret = -ENODEV;
+               goto out;
+       }
+       chip->test_regmap = devm_regmap_init_i2c(chip->test_page,
+                                                test_regmap_config);
+       if (IS_ERR(chip->test_regmap)) {
+               dev_err(chip->dev, "Failed to init test_regmap: %d\n", ret);
+               ret = PTR_ERR(chip->test_regmap);
+               goto out;
+       }
+
+       chip->type = pm88x_of_get_type(&client->dev);
+       switch (chip->type) {
+       case PM886:
+               /* ldo page */
+               chip->ldo_page = chip->power_page;
+               chip->ldo_regmap = chip->power_regmap;
+               /* buck page */
+               chip->buck_regmap = chip->power_regmap;
+               break;
+       case PM880:
+               /* ldo page */
+               chip->ldo_page = chip->power_page;
+               chip->ldo_regmap = chip->power_regmap;
+
+               /* buck page */
+               chip->buck_page = i2c_new_dummy(client->adapter,
+                                               chip->buck_page_addr);
+               if (!chip->buck_page) {
+                       dev_err(chip->dev, "Failed to new buck_page: %d\n", 
ret);
+                       ret = -ENODEV;
+                       goto out;
+               }
+               chip->buck_regmap = devm_regmap_init_i2c(chip->buck_page,
+                                                        power_regmap_config);
+               if (IS_ERR(chip->buck_regmap)) {
+                       dev_err(chip->dev, "Failed to init buck_regmap: %d\n", 
ret);
+                       ret = PTR_ERR(chip->buck_regmap);
+                       goto out;
+               }
+
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+out:
+       return ret;
+}
+
+void pm800_exit_pages(struct pm88x_chip *chip)
+{
+       if (!chip)
+               return;
+
+       if (chip->ldo_page)
+               i2c_unregister_device(chip->ldo_page);
+       if (chip->gpadc_page)
+               i2c_unregister_device(chip->gpadc_page);
+       if (chip->test_page)
+               i2c_unregister_device(chip->test_page);
+       /* no need to unregister ldo_page */
+       switch (chip->type) {
+       case PM886:
+               break;
+       case PM880:
+               if (chip->buck_page)
+                       i2c_unregister_device(chip->buck_page);
+               break;
+       default:
+               break;
+       }
+}
+
+int pm88x_init_subdev(struct pm88x_chip *chip)
+{
+       int ret;
+       if (!chip)
+               return -EINVAL;
+
+       ret = mfd_add_devices(chip->dev, 0, common_cell_devs,
+                             ARRAY_SIZE(common_cell_devs), NULL, 0,
+                             regmap_irq_get_domain(chip->irq_data));
+       if (ret < 0)
+               return ret;
+
+       switch (chip->type) {
+       case PM886:
+               ret = mfd_add_devices(chip->dev, 0, pm886_cell_info.cells,
+                                     pm886_cell_info.cell_nr, NULL, 0,
+                                     regmap_irq_get_domain(chip->irq_data));
+               break;
+       case PM880:
+               ret = mfd_add_devices(chip->dev, 0, pm880_cell_info.cells,
+                                     pm880_cell_info.cell_nr, NULL, 0,
+                                     regmap_irq_get_domain(chip->irq_data));
+               break;
+       default:
+               break;
+       }
+       return ret;
+}
+
+static int (*apply_to_chip)(struct pm88x_chip *chip);
+/* PMIC chip itself related */
+int pm88x_apply_patch(struct pm88x_chip *chip)
+{
+       if (!chip || !chip->client)
+               return -EINVAL;
+
+       chip->type = pm88x_of_get_type(&chip->client->dev);
+       switch (chip->type) {
+       case PM886:
+               apply_to_chip = pm886_apply_patch;
+               break;
+       case PM880:
+               apply_to_chip = pm880_apply_patch;
+               break;
+       default:
+               break;
+       }
+       if (apply_to_chip)
+               apply_to_chip(chip);
+       return 0;
+}
+
+int pm88x_stepping_fixup(struct pm88x_chip *chip)
+{
+       if (!chip || !chip->client)
+               return -EINVAL;
+
+       chip->type = pm88x_of_get_type(&chip->client->dev);
+       switch (chip->type) {
+       case PM886:
+       case PM880:
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+int pm88x_apply_board_fixup(struct pm88x_chip *chip, struct device_node *np)
+{
+       /* add board design specific setting, parsed via device tree */
+       return 0;
+}
+
+long pm88x_of_get_type(struct device *dev)
+{
+       const struct of_device_id *id = of_match_device(pm88x_of_match, dev);
+
+       if (id)
+               return (long)id->data;
+       else
+               return 0;
+}
+
+void pm88x_dev_exit(struct pm88x_chip *chip)
+{
+       mfd_remove_devices(chip->dev);
+       pm88x_irq_exit(chip);
+}
+
+void pm88x_power_off(void)
+{
+       pr_info("powers off the system.");
+       /* TODO: implement later */
+
+       for (;;)
+               cpu_relax();
+}
+
+int pm88x_reboot_notifier_callback(struct notifier_block *this,
+                                  unsigned long code, void *unused)
+{
+       struct pm88x_chip *chip =
+               container_of(this, struct pm88x_chip, reboot_notifier);
+
+       switch (code) {
+       case SYS_HALT:
+       case SYS_POWER_OFF:
+               dev_info(chip->dev, "system is down.\n");
+               break;
+       case SYS_RESTART:
+       default:
+               dev_info(chip->dev, "system will reboot.\n");
+               break;
+       }
+
+       return 0;
+}
diff --git a/drivers/mfd/88pm88x-i2c.c b/drivers/mfd/88pm88x-i2c.c
new file mode 100644
index 0000000..8a96bc5
--- /dev/null
+++ b/drivers/mfd/88pm88x-i2c.c
@@ -0,0 +1,167 @@
+/*
+ * 88pm88x-i2c.c  --  88pm88x i2c bus interface
+ *
+ * Copyright (C) 2015 Marvell International Ltd.
+ *  Yi Zhang <yizh...@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/88pm886.h>
+#include <linux/mfd/88pm880.h>
+#include <linux/mfd/88pm88x.h>
+
+static int pm88x_i2c_probe(struct i2c_client *client,
+                      const struct i2c_device_id *id)
+{
+       struct pm88x_chip *chip;
+       struct device_node *node = client->dev.of_node;
+       int ret = 0;
+
+       chip = pm88x_init_chip(client);
+       if (IS_ERR(chip)) {
+               ret = PTR_ERR(chip);
+               dev_err(chip->dev, "initialize 88pm88x chip fails!\n");
+               goto err;
+       }
+
+       ret = pm88x_parse_dt(node, chip);
+       if (ret < 0) {
+               dev_err(chip->dev, "parse dt fails!\n");
+               goto err;
+       }
+
+       ret = pm88x_init_pages(chip);
+       if (ret) {
+               dev_err(chip->dev, "initialize 88pm88x pages fails!\n");
+               goto err;
+       }
+
+       ret = pm88x_post_init_chip(chip);
+       if (ret) {
+               dev_err(chip->dev, "post initialize 88pm88x fails!\n");
+               goto err;
+       }
+
+       ret = pm88x_irq_init(chip);
+       if (ret) {
+               dev_err(chip->dev, "initialize 88pm88x interrupt fails!\n");
+               goto err_init_irq;
+       }
+
+       ret = pm88x_init_subdev(chip);
+       if (ret) {
+               dev_err(chip->dev, "initialize 88pm88x sub-device fails\n");
+               goto err_init_subdev;
+       }
+
+       /* patch for PMIC chip itself */
+       ret = pm88x_apply_patch(chip);
+       if (ret) {
+               dev_err(chip->dev, "apply 88pm88x register patch fails\n");
+               goto err_apply_patch;
+       }
+
+       /* fixup according PMIC stepping */
+       ret = pm88x_stepping_fixup(chip);
+       if (ret) {
+               dev_err(chip->dev, "fixup according to chip stepping\n");
+               goto err_apply_patch;
+       }
+
+       /* patch for board configuration */
+       ret = pm88x_apply_board_fixup(chip, node);
+       if (ret) {
+               dev_err(chip->dev, "apply 88pm88x register for board fails\n");
+               goto err_apply_patch;
+       }
+
+       pm_power_off = pm88x_power_off;
+
+       chip->reboot_notifier.notifier_call = pm88x_reboot_notifier_callback;
+       register_reboot_notifier(&(chip->reboot_notifier));
+
+       return 0;
+
+err_apply_patch:
+       mfd_remove_devices(chip->dev);
+err_init_subdev:
+       regmap_del_irq_chip(chip->irq, chip->irq_data);
+err_init_irq:
+       pm800_exit_pages(chip);
+err:
+       return ret;
+}
+
+static int pm88x_i2c_remove(struct i2c_client *i2c)
+{
+       struct pm88x_chip *chip = dev_get_drvdata(&i2c->dev);
+       pm88x_dev_exit(chip);
+       return 0;
+}
+
+static const struct i2c_device_id pm88x_i2c_id[] = {
+       { "88pm886", PM886 },
+       { "88pm880", PM880 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, pm88x_i2c_id);
+
+static int pm88x_i2c_suspend(struct device *dev)
+{
+       return 0;
+}
+
+static int pm88x_i2c_resume(struct device *dev)
+{
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(pm88x_pm_ops, pm88x_i2c_suspend, pm88x_i2c_resume);
+
+static struct i2c_driver pm88x_i2c_driver = {
+       .driver = {
+               .name   = "88pm88x",
+               .owner  = THIS_MODULE,
+               .pm     = &pm88x_pm_ops,
+               .of_match_table = of_match_ptr(pm88x_of_match),
+       },
+       .probe          = pm88x_i2c_probe,
+       .remove         = pm88x_i2c_remove,
+       .id_table       = pm88x_i2c_id,
+};
+
+static int pm88x_i2c_init(void)
+{
+       int ret;
+
+       ret = i2c_add_driver(&pm88x_i2c_driver);
+       if (ret != 0) {
+               pr_err("88pm88x I2C registration failed %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+subsys_initcall(pm88x_i2c_init);
+
+static void pm88x_i2c_exit(void)
+{
+       i2c_del_driver(&pm88x_i2c_driver);
+}
+module_exit(pm88x_i2c_exit);
+
+MODULE_DESCRIPTION("88pm88x I2C bus interface");
+MODULE_AUTHOR("Yi Zhang<yizh...@marvell.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/88pm88x-irq.c b/drivers/mfd/88pm88x-irq.c
new file mode 100644
index 0000000..3d5ba0c
--- /dev/null
+++ b/drivers/mfd/88pm88x-irq.c
@@ -0,0 +1,172 @@
+/*
+ * 88pm886 interrupt support
+ *
+ * Copyright (C) 2015 Marvell International Ltd.
+ *  Yi Zhang <yizh...@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/mfd/88pm88x.h>
+#include <linux/mfd/88pm886.h>
+#include <linux/mfd/88pm880.h>
+
+/* interrupt status registers */
+#define PM88X_INT_STATUS1              (0x05)
+
+#define PM88X_INT_ENA_1                        (0x0a)
+#define PM88X_ONKEY_INT_ENA1           (1 << 0)
+#define PM88X_EXTON_INT_ENA1           (1 << 1)
+#define PM88X_CHG_INT_ENA1             (1 << 2)
+#define PM88X_BAT_INT_ENA1             (1 << 3)
+#define PM88X_RTC_INT_ENA1             (1 << 4)
+#define PM88X_CLASSD_INT_ENA1          (1 << 5)
+#define PM88X_XO_INT_ENA1              (1 << 6)
+#define PM88X_GPIO_INT_ENA1            (1 << 7)
+
+#define PM88X_INT_ENA_2                        (0x0b)
+#define PM88X_VBAT_INT_ENA2            (1 << 0)
+#define PM88X_RSVED1_INT_ENA2          (1 << 1)
+#define PM88X_VBUS_INT_ENA2            (1 << 2)
+#define PM88X_ITEMP_INT_ENA2           (1 << 3)
+#define PM88X_BUCK_PGOOD_INT_ENA2      (1 << 4)
+#define PM88X_LDO_PGOOD_INT_ENA2       (1 << 5)
+#define PM88X_RSVED6_INT_ENA2          (1 << 6)
+#define PM88X_RSVED7_INT_ENA2          (1 << 7)
+
+#define PM88X_INT_ENA_3                        (0x0c)
+#define PM88X_GPADC0_INT_ENA3          (1 << 0)
+#define PM88X_GPADC1_INT_ENA3          (1 << 1)
+#define PM88X_GPADC2_INT_ENA3          (1 << 2)
+#define PM88X_GPADC3_INT_ENA3          (1 << 3)
+#define PM88X_MIC_INT_ENA3             (1 << 4)
+#define PM88X_HS_INT_ENA3              (1 << 5)
+#define PM88X_GND_INT_ENA3             (1 << 6)
+#define PM88X_RSVED7_INT_ENA3          (1 << 7)
+
+#define PM88X_INT_ENA_4                        (0x0d)
+#define PM88X_CHG_FAIL_INT_ENA4                (1 << 0)
+#define PM88X_CHG_DONE_INT_ENA4                (1 << 1)
+#define PM88X_RSVED2_INT_ENA4          (1 << 2)
+#define PM88X_OTG_FAIL_INT_ENA4                (1 << 3)
+#define PM88X_RSVED4_INT_ENA4          (1 << 4)
+#define PM88X_CHG_ILIM_INT_ENA4                (1 << 5)
+#define PM88X_CC_INT_ENA4              (1 << 6)
+#define PM88X_RSVED7_INT_ENA4          (1 << 7)
+
+#define PM88X_MISC_CONFIG2             (0x15)
+#define PM88X_INV_INT                  (1 << 0)
+#define PM88X_INT_CLEAR                        (1 << 1)
+#define PM88X_INT_RC                   (0 << 1)
+#define PM88X_INT_WC                   (1 << 1)
+#define PM88X_INT_MASK_MODE            (1 << 2)
+
+static const struct regmap_irq pm88x_irqs[] = {
+       /* INT0 */
+       [PM88X_IRQ_ONKEY] = {.reg_offset = 0, .mask = PM88X_ONKEY_INT_ENA1,},
+       [PM88X_IRQ_EXTON] = {.reg_offset = 0, .mask = PM88X_EXTON_INT_ENA1,},
+       [PM88X_IRQ_CHG_GOOD] = {.reg_offset = 0, .mask = PM88X_CHG_INT_ENA1,},
+       [PM88X_IRQ_BAT_DET] = {.reg_offset = 0, .mask = PM88X_BAT_INT_ENA1,},
+       [PM88X_IRQ_RTC] = {.reg_offset = 0, .mask = PM88X_RTC_INT_ENA1,},
+       [PM88X_IRQ_CLASSD] = { .reg_offset = 0, .mask = PM88X_CLASSD_INT_ENA1,},
+       [PM88X_IRQ_XO] = {.reg_offset = 0, .mask = PM88X_XO_INT_ENA1,},
+       [PM88X_IRQ_GPIO] = {.reg_offset = 0, .mask = PM88X_GPIO_INT_ENA1,},
+
+       /* INT1 */
+       [PM88X_IRQ_VBAT] = {.reg_offset = 1, .mask = PM88X_VBAT_INT_ENA2,},
+       [PM88X_IRQ_VBUS] = {.reg_offset = 1, .mask = PM88X_VBUS_INT_ENA2,},
+       [PM88X_IRQ_ITEMP] = {.reg_offset = 1, .mask = PM88X_ITEMP_INT_ENA2,},
+       [PM88X_IRQ_BUCK_PGOOD] = {
+               .reg_offset = 1,
+               .mask = PM88X_BUCK_PGOOD_INT_ENA2,
+       },
+       [PM88X_IRQ_LDO_PGOOD] = {
+               .reg_offset = 1,
+               .mask = PM88X_LDO_PGOOD_INT_ENA2,
+       },
+       /* INT2 */
+       [PM88X_IRQ_GPADC0] = {.reg_offset = 2, .mask = PM88X_GPADC0_INT_ENA3,},
+       [PM88X_IRQ_GPADC1] = {.reg_offset = 2, .mask = PM88X_GPADC1_INT_ENA3,},
+       [PM88X_IRQ_GPADC2] = {.reg_offset = 2, .mask = PM88X_GPADC2_INT_ENA3,},
+       [PM88X_IRQ_GPADC3] = {.reg_offset = 2, .mask = PM88X_GPADC3_INT_ENA3,},
+       [PM88X_IRQ_MIC_DET] = {.reg_offset = 2, .mask = PM88X_MIC_INT_ENA3,},
+       [PM88X_IRQ_HS_DET] = {.reg_offset = 2, .mask = PM88X_HS_INT_ENA3,},
+       [PM88X_IRQ_GND_DET] = {.reg_offset = 2, .mask = PM88X_GND_INT_ENA3,},
+
+       /* INT3 */
+       [PM88X_IRQ_CHG_FAIL] = {
+               .reg_offset = 3,
+               .mask = PM88X_CHG_FAIL_INT_ENA4,
+       },
+       [PM88X_IRQ_CHG_DONE] = {
+               .reg_offset = 3,
+               .mask = PM88X_CHG_DONE_INT_ENA4,
+       },
+       [PM88X_IRQ_OTG_FAIL] = {
+               .reg_offset = 3,
+               .mask = PM88X_OTG_FAIL_INT_ENA4,
+       },
+       [PM88X_IRQ_CHG_ILIM] = {
+               .reg_offset = 3,
+               .mask = PM88X_CHG_ILIM_INT_ENA4,
+       },
+       [PM88X_IRQ_CC] = {.reg_offset = 3, .mask = PM88X_CC_INT_ENA4,},
+};
+
+struct regmap_irq_chip pm88x_irq_chip = {
+       .name = "88pm88x",
+       .irqs = pm88x_irqs,
+       .num_irqs = ARRAY_SIZE(pm88x_irqs),
+
+       .num_regs = 4,
+       .status_base = PM88X_INT_STATUS1,
+       .mask_base = PM88X_INT_ENA_1,
+       .ack_base = PM88X_INT_STATUS1,
+       .mask_invert = 1,
+};
+
+int pm88x_irq_init(struct pm88x_chip *chip)
+{
+       int mask, data, ret;
+       struct regmap *map;
+
+       if (!chip || !chip->base_regmap || !chip->irq) {
+               pr_err("cannot initialize interrupt!\n");
+               return -EINVAL;
+       }
+       map = chip->base_regmap;
+
+       /*
+        * irq_mode defines the way of clearing interrupt.
+        * it's read-clear by default.
+        */
+       mask = PM88X_INV_INT | PM88X_INT_CLEAR | PM88X_INT_MASK_MODE;
+       data = (chip->irq_mode) ? PM88X_INT_WC : PM88X_INT_RC;
+       ret = regmap_update_bits(map, PM88X_MISC_CONFIG2, mask, data);
+       if (ret < 0) {
+               dev_err(chip->dev, "cannot set interrupt mode!\n");
+               return ret;
+       }
+
+       ret = regmap_add_irq_chip(map, chip->irq, IRQF_ONESHOT, -1,
+                                 &pm88x_irq_chip, &chip->irq_data);
+       return ret;
+}
+
+int pm88x_irq_exit(struct pm88x_chip *chip)
+{
+       regmap_del_irq_chip(chip->irq, chip->irq_data);
+       return 0;
+}
diff --git a/drivers/mfd/88pm88x.h b/drivers/mfd/88pm88x.h
new file mode 100644
index 0000000..a85a486
--- /dev/null
+++ b/drivers/mfd/88pm88x.h
@@ -0,0 +1,51 @@
+#ifndef _MFD_88PM88X_H
+#define _MFD_88PM88X_H
+
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/mfd/core.h>
+
+struct pmic_cell_info {
+       const struct mfd_cell *cells;
+       int             cell_nr;
+};
+
+#define CELL_IRQ_RESOURCE(_name, _irq) { \
+       .name = _name, \
+       .start = _irq, .end = _irq, \
+       .flags = IORESOURCE_IRQ, \
+       }
+#define CELL_DEV(_name, _r, _compatible, _id) { \
+       .name = _name, \
+       .of_compatible = _compatible, \
+       .num_resources = ARRAY_SIZE(_r), \
+       .resources = _r, \
+       .id = _id, \
+       }
+
+/* 88pm886 */
+extern const struct regmap_config pm886_base_i2c_regmap;
+extern const struct regmap_config pm886_power_i2c_regmap;
+extern const struct regmap_config pm886_gpadc_i2c_regmap;
+extern const struct regmap_config pm886_battery_i2c_regmap;
+extern const struct regmap_config pm886_test_i2c_regmap;
+
+extern const struct mfd_cell pm886_cell_devs[];
+extern struct pmic_cell_info pm886_cell_info;
+
+int pm886_apply_patch(struct pm88x_chip *chip);
+
+/* 88pm880 */
+extern const struct regmap_config pm880_base_i2c_regmap;
+extern const struct regmap_config pm880_power_i2c_regmap;
+extern const struct regmap_config pm880_gpadc_i2c_regmap;
+extern const struct regmap_config pm880_battery_i2c_regmap;
+extern const struct regmap_config pm880_test_i2c_regmap;
+
+extern const struct mfd_cell pm880_cell_devs[];
+extern struct pmic_cell_info pm880_cell_info;
+
+int pm880_apply_patch(struct pm88x_chip *chip);
+
+#endif
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index d5ad04d..8ffe3d8 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -390,6 +390,18 @@ config MFD_KEMPLD
          This driver can also be built as a module. If so, the module
          will be called kempld-core.
 
+config MFD_88PM88X
+       bool "Marvell 88PM886/880 PMIC"
+       depends on I2C=y
+       select REGMAP_I2C
+       select MFD_CORE
+       help
+         This supports for Marvell 88PM88X Series Power Management IC:
+         88pm886 and 88pm880;
+         This includes the I2C driver, the interrupt resource distribution
+         and the core APIs, for individual sub-device as voltage regulators,
+         RTC, charger, fuelgauge, etc please select under the corresponding 
menus.
+
 config MFD_88PM800
        tristate "Marvell 88PM800"
        depends on I2C=y
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 0e5cfeb..365d1fa 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -6,6 +6,9 @@
 obj-$(CONFIG_MFD_88PM860X)     += 88pm860x.o
 obj-$(CONFIG_MFD_88PM800)      += 88pm800.o 88pm80x.o
 obj-$(CONFIG_MFD_88PM805)      += 88pm805.o 88pm80x.o
+88pm88x-objs                   := 88pm88x-core.o 88pm88x-i2c.o 88pm88x-irq.o 
88pm886-table.o 88pm880-table.o
+obj-$(CONFIG_MFD_88PM88X)      += 88pm88x.o
+
 obj-$(CONFIG_MFD_SM501)                += sm501.o
 obj-$(CONFIG_MFD_ASIC3)                += asic3.o tmio_core.o
 obj-$(CONFIG_MFD_BCM590XX)     += bcm590xx.o
diff --git a/include/linux/mfd/88pm880-reg.h b/include/linux/mfd/88pm880-reg.h
new file mode 100644
index 0000000..fdf2315
--- /dev/null
+++ b/include/linux/mfd/88pm880-reg.h
@@ -0,0 +1,98 @@
+/*
+ * Marvell 88PM880 registers
+ *
+ * Copyright (C) 2014 Marvell International Ltd.
+ *  Yi Zhang <yizh...@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_MFD_88PM880_REG_H
+#define __LINUX_MFD_88PM880_REG_H
+
+#define PM880_BUCK1_VOUT       (0x28)
+
+#define PM880_BUCK1A_VOUT      (0x28) /* voltage 0 */
+#define PM880_BUCK1A_1_VOUT    (0x29)
+#define PM880_BUCK1A_2_VOUT    (0x2a)
+#define PM880_BUCK1A_3_VOUT    (0x2b)
+#define PM880_BUCK1A_4_VOUT    (0x2c)
+#define PM880_BUCK1A_5_VOUT    (0x2d)
+#define PM880_BUCK1A_6_VOUT    (0x2e)
+#define PM880_BUCK1A_7_VOUT    (0x2f)
+#define PM880_BUCK1A_8_VOUT    (0x30)
+#define PM880_BUCK1A_9_VOUT    (0x31)
+#define PM880_BUCK1A_10_VOUT   (0x32)
+#define PM880_BUCK1A_11_VOUT   (0x33)
+#define PM880_BUCK1A_12_VOUT   (0x34)
+#define PM880_BUCK1A_13_VOUT   (0x35)
+#define PM880_BUCK1A_14_VOUT   (0x36)
+#define PM880_BUCK1A_15_VOUT   (0x37)
+
+#define PM880_BUCK1B_VOUT      (0x40)
+#define PM880_BUCK1B_1_VOUT    (0x41)
+#define PM880_BUCK1B_2_VOUT    (0x42)
+#define PM880_BUCK1B_3_VOUT    (0x43)
+#define PM880_BUCK1B_4_VOUT    (0x44)
+#define PM880_BUCK1B_5_VOUT    (0x45)
+#define PM880_BUCK1B_6_VOUT    (0x46)
+#define PM880_BUCK1B_7_VOUT    (0x47)
+#define PM880_BUCK1B_8_VOUT    (0x48)
+#define PM880_BUCK1B_9_VOUT    (0x49)
+#define PM880_BUCK1B_10_VOUT   (0x4a)
+#define PM880_BUCK1B_11_VOUT   (0x4b)
+#define PM880_BUCK1B_12_VOUT   (0x4c)
+#define PM880_BUCK1B_13_VOUT   (0x4d)
+#define PM880_BUCK1B_14_VOUT   (0x4e)
+#define PM880_BUCK1B_15_VOUT   (0x4f)
+
+/* buck7 has dvc function */
+#define PM880_BUCK7_VOUT       (0xb8) /* voltage 0 */
+#define PM880_BUCK7_1_VOUT     (0xb9)
+#define PM880_BUCK7_2_VOUT     (0xba)
+#define PM880_BUCK7_3_VOUT     (0xbb)
+
+/*
+ * buck sleep mode control registers:
+ * 00-disable,
+ * 01/10-sleep voltage,
+ * 11-active voltage
+ */
+#define PM880_BUCK1A_SLP_CTRL  (0x27)
+#define PM880_BUCK1B_SLP_CTRL  (0x3c)
+#define PM880_BUCK2_SLP_CTRL   (0x54)
+#define PM880_BUCK3_SLP_CTRL   (0x6c)
+/* TODO: there are 7 controls bit for buck4~7 */
+#define PM880_BUCK4_SLP_CTRL   (0x84)
+#define PM880_BUCK5_SLP_CTRL   (0x94)
+#define PM880_BUCK6_SLP_CTRL   (0xa4)
+#define PM880_BUCK7_SLP_CTRL   (0xb4)
+
+/*
+ * ldo sleep mode control registers:
+ * 00-disable,
+ * 01/10-sleep voltage,
+ * 11-active voltage
+ */
+#define PM880_LDO1_SLP_CTRL    (0x21)
+#define PM880_LDO2_SLP_CTRL    (0x27)
+#define PM880_LDO3_SLP_CTRL    (0x2d)
+#define PM880_LDO4_SLP_CTRL    (0x33)
+#define PM880_LDO5_SLP_CTRL    (0x39)
+#define PM880_LDO6_SLP_CTRL    (0x3f)
+#define PM880_LDO7_SLP_CTRL    (0x45)
+#define PM880_LDO8_SLP_CTRL    (0x4b)
+#define PM880_LDO9_SLP_CTRL    (0x51)
+#define PM880_LDO10_SLP_CTRL   (0x57)
+#define PM880_LDO11_SLP_CTRL   (0x5d)
+#define PM880_LDO12_SLP_CTRL   (0x63)
+#define PM880_LDO13_SLP_CTRL   (0x69)
+#define PM880_LDO14_SLP_CTRL   (0x6f)
+#define PM880_LDO15_SLP_CTRL   (0x75)
+#define PM880_LDO16_SLP_CTRL   (0x7b)
+#define PM880_LDO17_SLP_CTRL   (0x81)
+#define PM880_LDO18_SLP_CTRL   (0x87)
+
+#endif /*__LINUX_MFD_88PM880_REG_H */
diff --git a/include/linux/mfd/88pm880.h b/include/linux/mfd/88pm880.h
new file mode 100644
index 0000000..94b9e063
--- /dev/null
+++ b/include/linux/mfd/88pm880.h
@@ -0,0 +1,59 @@
+/*
+ * Marvell 88PM880 Interface
+ *
+ * Copyright (C) 2015 Marvell International Ltd.
+ *  Yi Zhang <yizh...@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 88pm880 specific configuration: at present it's regulators and dvc part
+ */
+
+#ifndef __LINUX_MFD_88PM880_H
+#define __LINUX_MFD_88PM880_H
+
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/regmap.h>
+#include <linux/atomic.h>
+#include <linux/reboot.h>
+#include "88pm880-reg.h"
+
+enum {
+       PM880_ID_BUCK1A = 0,
+       PM880_ID_BUCK2,
+       PM880_ID_BUCK3,
+       PM880_ID_BUCK4,
+       PM880_ID_BUCK5,
+       PM880_ID_BUCK6,
+       PM880_ID_BUCK7,
+
+       PM880_ID_BUCK_MAX = 7,
+};
+
+enum {
+       PM880_ID_LDO1 = 0,
+       PM880_ID_LDO2,
+       PM880_ID_LDO3,
+       PM880_ID_LDO4,
+       PM880_ID_LDO5,
+       PM880_ID_LDO6,
+       PM880_ID_LDO7,
+       PM880_ID_LDO8,
+       PM880_ID_LDO9,
+       PM880_ID_LDO10,
+       PM880_ID_LDO11,
+       PM880_ID_LDO12,
+       PM880_ID_LDO13,
+       PM880_ID_LDO14 = 13,
+       PM880_ID_LDO15,
+       PM880_ID_LDO16 = 15,
+
+       PM880_ID_LDO17 = 16,
+       PM880_ID_LDO18 = 17,
+
+       PM880_ID_LDO_MAX = 18,
+};
+#endif /* __LINUX_MFD_88PM880_H */
diff --git a/include/linux/mfd/88pm886-reg.h b/include/linux/mfd/88pm886-reg.h
new file mode 100644
index 0000000..38a7ecd
--- /dev/null
+++ b/include/linux/mfd/88pm886-reg.h
@@ -0,0 +1,59 @@
+/*
+ * Marvell 88PM886 registers
+ *
+ * Copyright (C) 2014 Marvell International Ltd.
+ *  Yi Zhang <yizh...@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_MFD_88PM886_REG_H
+#define __LINUX_MFD_88PM886_REG_H
+
+#define PM886_BUCK1_VOUT       (0xa5)
+#define PM886_BUCK1_1_VOUT     (0xa6)
+#define PM886_BUCK1_2_VOUT     (0xa7)
+#define PM886_BUCK1_3_VOUT     (0xa8)
+#define PM886_BUCK1_4_VOUT     (0x9a)
+#define PM886_BUCK1_5_VOUT     (0x9b)
+#define PM886_BUCK1_6_VOUT     (0x9c)
+#define PM886_BUCK1_7_VOUT     (0x9d)
+
+/*
+ * buck sleep mode control registers:
+ * 00-disable,
+ * 01/10-sleep voltage,
+ * 11-active voltage
+ */
+#define PM886_BUCK1_SLP_CTRL   (0xa2)
+#define PM886_BUCK2_SLP_CTRL   (0xb0)
+#define PM886_BUCK3_SLP_CTRL   (0xbe)
+#define PM886_BUCK4_SLP_CTRL   (0xcc)
+#define PM886_BUCK5_SLP_CTRL   (0xda)
+
+/*
+ * ldo sleep mode control registers:
+ * 00-disable,
+ * 01/10-sleep voltage,
+ * 11-active voltage
+ */
+#define PM886_LDO1_SLP_CTRL    (0x21)
+#define PM886_LDO2_SLP_CTRL    (0x27)
+#define PM886_LDO3_SLP_CTRL    (0x2d)
+#define PM886_LDO4_SLP_CTRL    (0x33)
+#define PM886_LDO5_SLP_CTRL    (0x39)
+#define PM886_LDO6_SLP_CTRL    (0x3f)
+#define PM886_LDO7_SLP_CTRL    (0x45)
+#define PM886_LDO8_SLP_CTRL    (0x4b)
+#define PM886_LDO9_SLP_CTRL    (0x51)
+#define PM886_LDO10_SLP_CTRL   (0x57)
+#define PM886_LDO11_SLP_CTRL   (0x5d)
+#define PM886_LDO12_SLP_CTRL   (0x63)
+#define PM886_LDO13_SLP_CTRL   (0x69)
+#define PM886_LDO14_SLP_CTRL   (0x6f)
+#define PM886_LDO15_SLP_CTRL   (0x75)
+#define PM886_LDO16_SLP_CTRL   (0x7b)
+
+#endif
diff --git a/include/linux/mfd/88pm886.h b/include/linux/mfd/88pm886.h
new file mode 100644
index 0000000..9390406
--- /dev/null
+++ b/include/linux/mfd/88pm886.h
@@ -0,0 +1,55 @@
+/*
+ * Marvell 88PM886 Interface
+ *
+ * Copyright (C) 2015 Marvell International Ltd.
+ *  Yi Zhang <yizh...@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 88pm886 specific configuration: at present it's regulators and dvc part
+ */
+
+#ifndef __LINUX_MFD_88PM886_H
+#define __LINUX_MFD_88PM886_H
+
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/regmap.h>
+#include <linux/atomic.h>
+#include <linux/reboot.h>
+#include "88pm886-reg.h"
+
+enum {
+       PM886_ID_BUCK1 = 0,
+       PM886_ID_BUCK2,
+       PM886_ID_BUCK3,
+       PM886_ID_BUCK4,
+       PM886_ID_BUCK5,
+
+       PM886_ID_BUCK_MAX = 5,
+};
+
+enum {
+       PM886_ID_LDO1 = 0,
+       PM886_ID_LDO2,
+       PM886_ID_LDO3,
+       PM886_ID_LDO4,
+       PM886_ID_LDO5,
+       PM886_ID_LDO6,
+       PM886_ID_LDO7,
+       PM886_ID_LDO8,
+       PM886_ID_LDO9,
+       PM886_ID_LDO10,
+       PM886_ID_LDO11,
+       PM886_ID_LDO12,
+       PM886_ID_LDO13,
+       PM886_ID_LDO14,
+       PM886_ID_LDO15,
+       PM886_ID_LDO16 = 15,
+
+       PM886_ID_LDO_MAX = 16,
+};
+
+#endif /* __LINUX_MFD_88PM886_H */
diff --git a/include/linux/mfd/88pm88x-reg.h b/include/linux/mfd/88pm88x-reg.h
new file mode 100644
index 0000000..d767b31
--- /dev/null
+++ b/include/linux/mfd/88pm88x-reg.h
@@ -0,0 +1,118 @@
+/*
+ * Marvell 88PM88X registers
+ *
+ * Copyright (C) 2014 Marvell International Ltd.
+ *  Yi Zhang <yizh...@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_MFD_88PM88X_REG_H
+#define __LINUX_MFD_88PM88X_REG_H
+/*
+ * This file is just used for the common registers,
+ * which are shared by sub-clients
+ */
+
+/*--base page:--------------------------------------------------------------*/
+#define PM88X_ID_REG                   (0x0)
+
+#define PM88X_STATUS1                  (0x1)
+#define PM88X_CHG_DET                  (1 << 2)
+#define PM88X_BAT_DET                  (1 << 3)
+
+#define PM88X_MISC_CONFIG1             (0x14)
+#define PM88X_LONKEY_RST               (1 << 3)
+
+#define PM88X_WDOG                     (0x1d)
+
+#define PM88X_LOWPOWER2                        (0x21)
+#define PM88X_LOWPOWER4                        (0x23)
+
+/* clk control register */
+#define PM88X_CLK_CTRL1                        (0x25)
+
+/* gpio */
+#define PM88X_GPIO_CTRL1               (0x30)
+#define PM88X_GPIO0_VAL_MSK            (0x1 << 0)
+#define PM88X_GPIO0_MODE_MSK           (0x7 << 1)
+#define PM88X_GPIO1_VAL_MSK            (0x1 << 4)
+#define PM88X_GPIO1_MODE_MSK           (0x7 << 5)
+#define PM88X_GPIO1_SET_DVC            (0x2 << 5)
+
+#define PM88X_GPIO_CTRL2               (0x31)
+#define PM88X_GPIO2_VAL_MSK            (0x1 << 0)
+#define PM88X_GPIO2_MODE_MSK           (0x7 << 1)
+
+#define PM88X_GPIO_CTRL3               (0x32)
+
+#define PM88X_GPIO_CTRL4               (0x33)
+#define PM88X_GPIO5V_1_VAL_MSK         (0x1 << 0)
+#define PM88X_GPIO5V_1_MODE_MSK                (0x7 << 1)
+#define PM88X_GPIO5V_2_VAL_MSK         (0x1 << 4)
+#define PM88X_GPIO5V_2_MODE_MSK                (0x7 << 5)
+
+#define PM88X_BK_OSC_CTRL1             (0x50)
+#define PM88X_BK_OSC_CTRL3             (0x52)
+
+#define PM88X_RTC_ALARM_CTRL1          (0xd0)
+#define PM88X_ALARM_WAKEUP             (1 << 4)
+#define PM88X_USE_XO                   (1 << 7)
+
+#define PM88X_AON_CTRL2                        (0xe2)
+#define PM88X_AON_CTRL3                        (0xe3)
+#define PM88X_AON_CTRL4                        (0xe4)
+#define PM88X_AON_CTRL7                        (0xe7)
+
+/* 0xea, 0xeb, 0xec, 0xed are reserved by RTC */
+#define PM88X_RTC_SPARE5               (0xee)
+#define PM88X_RTC_SPARE6               (0xef)
+/*-------------------------------------------------------------------------*/
+
+/*--power page:------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------*/
+
+/*--gpadc page:------------------------------------------------------------*/
+
+#define PM88X_GPADC_CONFIG1            (0x1)
+
+#define PM88X_GPADC_CONFIG2            (0x2)
+#define PM88X_GPADC0_MEAS_EN           (1 << 2)
+#define PM88X_GPADC1_MEAS_EN           (1 << 3)
+#define PM88X_GPADC2_MEAS_EN           (1 << 4)
+#define PM88X_GPADC3_MEAS_EN           (1 << 5)
+
+#define PM88X_GPADC_CONFIG3            (0x3)
+
+#define PM88X_GPADC_CONFIG6            (0x6)
+#define PM88X_GPADC_CONFIG8            (0x8)
+
+#define PM88X_GPADC0_LOW_TH            (0x20)
+#define PM88X_GPADC1_LOW_TH            (0x21)
+#define PM88X_GPADC2_LOW_TH            (0x22)
+#define PM88X_GPADC3_LOW_TH            (0x23)
+
+#define PM88X_GPADC0_UPP_TH            (0x30)
+#define PM88X_GPADC1_UPP_TH            (0x31)
+#define PM88X_GPADC2_UPP_TH            (0x32)
+#define PM88X_GPADC3_UPP_TH            (0x33)
+
+#define PM88X_VBUS_MEAS1               (0x4A)
+#define PM88X_GPADC0_MEAS1             (0x54)
+#define PM88X_GPADC1_MEAS1             (0x56)
+#define PM88X_GPADC2_MEAS1             (0x58)
+#define PM88X_GPADC3_MEAS1             (0x5A)
+
+
+/*--charger page:------------------------------------------------------------*/
+#define PM88X_CHG_CONFIG1              (0x28)
+#define PM88X_CHGBK_CONFIG6            (0x50)
+/*-------------------------------------------------------------------------*/
+
+/*--test page:-------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------*/
+#endif
diff --git a/include/linux/mfd/88pm88x.h b/include/linux/mfd/88pm88x.h
new file mode 100644
index 0000000..efa2fe6
--- /dev/null
+++ b/include/linux/mfd/88pm88x.h
@@ -0,0 +1,202 @@
+/*
+ * Marvell 88PM88X PMIC Common Interface
+ *
+ * Copyright (C) 2014 Marvell International Ltd.
+ *  Yi Zhang <yizh...@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *
+ * This file configures the common part of the 88pm88x series PMIC
+ */
+
+#ifndef __LINUX_MFD_88PM88X_H
+#define __LINUX_MFD_88PM88X_H
+
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/regmap.h>
+#include <linux/atomic.h>
+#include <linux/reboot.h>
+#include "88pm88x-reg.h"
+#include "88pm886-reg.h"
+
+#define PM88X_RTC_NAME         "88pm88x-rtc"
+#define PM88X_ONKEY_NAME       "88pm88x-onkey"
+#define PM88X_CHARGER_NAME     "88pm88x-charger"
+#define PM88X_BATTERY_NAME     "88pm88x-battery"
+#define PM88X_HEADSET_NAME     "88pm88x-headset"
+#define PM88X_VBUS_NAME                "88pm88x-vbus"
+#define PM88X_CFD_NAME         "88pm88x-leds"
+#define PM88X_RGB_NAME         "88pm88x-rgb"
+#define PM88X_GPADC_NAME       "88pm88x-gpadc"
+#define PM88X_DVC_NAME         "88pm88x-dvc"
+
+enum pm88x_type {
+       PM886 = 1,
+       PM880 = 2,
+};
+
+enum pm88x_pages {
+       PM88X_BASE_PAGE = 0,
+       PM88X_LDO_PAGE,
+       PM88X_GPADC_PAGE,
+       PM88X_BATTERY_PAGE,
+       PM88X_BUCK_PAGE = 4,
+       PM88X_TEST_PAGE = 7,
+};
+
+enum pm88x_gpadc {
+       PM88X_NO_GPADC = -1,
+       PM88X_GPADC0 = 0,
+       PM88X_GPADC1,
+       PM88X_GPADC2,
+       PM88X_GPADC3,
+};
+
+/* interrupt number */
+enum pm88x_irq_number {
+       PM88X_IRQ_ONKEY,        /* EN1b0 *//* 0 */
+       PM88X_IRQ_EXTON,        /* EN1b1 */
+       PM88X_IRQ_CHG_GOOD,     /* EN1b2 */
+       PM88X_IRQ_BAT_DET,      /* EN1b3 */
+       PM88X_IRQ_RTC,          /* EN1b4 */
+       PM88X_IRQ_CLASSD,       /* EN1b5 *//* 5 */
+       PM88X_IRQ_XO,           /* EN1b6 */
+       PM88X_IRQ_GPIO,         /* EN1b7 */
+
+       PM88X_IRQ_VBAT,         /* EN2b0 *//* 8 */
+                               /* EN2b1 */
+       PM88X_IRQ_VBUS,         /* EN2b2 */
+       PM88X_IRQ_ITEMP,        /* EN2b3 *//* 10 */
+       PM88X_IRQ_BUCK_PGOOD,   /* EN2b4 */
+       PM88X_IRQ_LDO_PGOOD,    /* EN2b5 */
+
+       PM88X_IRQ_GPADC0,       /* EN3b0 */
+       PM88X_IRQ_GPADC1,       /* EN3b1 */
+       PM88X_IRQ_GPADC2,       /* EN3b2 *//* 15 */
+       PM88X_IRQ_GPADC3,       /* EN3b3 */
+       PM88X_IRQ_MIC_DET,      /* EN3b4 */
+       PM88X_IRQ_HS_DET,       /* EN3b5 */
+       PM88X_IRQ_GND_DET,      /* EN3b6 */
+
+       PM88X_IRQ_CHG_FAIL,     /* EN4b0 *//* 20 */
+       PM88X_IRQ_CHG_DONE,     /* EN4b1 */
+                               /* EN4b2 */
+       PM88X_IRQ_CFD_FAIL,     /* EN4b3 */
+       PM88X_IRQ_OTG_FAIL,     /* EN4b4 */
+       PM88X_IRQ_CHG_ILIM,     /* EN4b5 *//* 25 */
+                               /* EN4b6 */
+       PM88X_IRQ_CC,           /* EN4b7 *//* 27 */
+
+       PM88X_MAX_IRQ,                     /* 28 */
+};
+
+/* 3 rgb led indicators */
+enum {
+       PM88X_RGB_LED0,
+       PM88X_RGB_LED1,
+       PM88X_RGB_LED2,
+};
+
+/* camera flash/torch */
+enum {
+       PM88X_NO_LED = -1,
+       PM88X_FLASH_LED = 0,
+       PM88X_TORCH_LED,
+};
+
+struct pm88x_dvc_ops {
+       void (*level_to_reg)(u8 level);
+};
+
+struct pm88x_buck1_dvc_desc {
+       u8 current_reg;
+       int max_level;
+       int uV_step1;
+       int uV_step2;
+       int min_uV;
+       int mid_uV;
+       int max_uV;
+       int mid_reg_val;
+};
+
+struct pm88x_dvc {
+       struct device *dev;
+       struct pm88x_chip *chip;
+       struct pm88x_dvc_ops ops;
+       struct pm88x_buck1_dvc_desc desc;
+};
+
+struct pm88x_chip {
+       struct i2c_client *client;
+       struct device *dev;
+
+       struct i2c_client *ldo_page;    /* chip client for ldo page */
+       struct i2c_client *power_page;  /* chip client for power page */
+       struct i2c_client *gpadc_page;  /* chip client for gpadc page */
+       struct i2c_client *battery_page;/* chip client for battery page */
+       struct i2c_client *buck_page;   /* chip client for buck page */
+       struct i2c_client *test_page;   /* chip client for test page */
+
+       struct regmap *base_regmap;
+       struct regmap *ldo_regmap;
+       struct regmap *power_regmap;
+       struct regmap *gpadc_regmap;
+       struct regmap *battery_regmap;
+       struct regmap *buck_regmap;
+       struct regmap *test_regmap;
+       struct regmap *codec_regmap;
+
+       unsigned short ldo_page_addr;   /* ldo page I2C address */
+       unsigned short power_page_addr; /* power page I2C address */
+       unsigned short gpadc_page_addr; /* gpadc page I2C address */
+       unsigned short battery_page_addr;/* battery page I2C address */
+       unsigned short buck_page_addr;  /* buck page I2C address */
+       unsigned short test_page_addr;  /* test page I2C address */
+
+       unsigned int chip_id;
+       long type;                      /* specific chip */
+       int irq;
+
+       int irq_mode;                   /* write/read clear */
+       struct regmap_irq_chip_data *irq_data;
+
+       bool rtc_wakeup;                /* is it powered up by expired alarm? */
+       u8 powerdown1;                  /* save power down reason */
+       u8 powerdown2;
+       u8 powerup;                     /* the reason of power on */
+
+       struct notifier_block reboot_notifier;
+       struct pm88x_dvc *dvc;
+};
+
+extern struct regmap_irq_chip pm88x_irq_chip;
+extern const struct of_device_id pm88x_of_match[];
+
+struct pm88x_chip *pm88x_init_chip(struct i2c_client *client);
+int pm88x_parse_dt(struct device_node *np, struct pm88x_chip *chip);
+
+int pm88x_init_pages(struct pm88x_chip *chip);
+int pm88x_post_init_chip(struct pm88x_chip *chip);
+void pm800_exit_pages(struct pm88x_chip *chip);
+
+int pm88x_init_subdev(struct pm88x_chip *chip);
+long pm88x_of_get_type(struct device *dev);
+void pm88x_dev_exit(struct pm88x_chip *chip);
+
+int pm88x_irq_init(struct pm88x_chip *chip);
+int pm88x_irq_exit(struct pm88x_chip *chip);
+int pm88x_apply_patch(struct pm88x_chip *chip);
+int pm88x_stepping_fixup(struct pm88x_chip *chip);
+int pm88x_apply_board_fixup(struct pm88x_chip *chip, struct device_node *np);
+
+struct pm88x_chip *pm88x_get_chip(void);
+void pm88x_set_chip(struct pm88x_chip *chip);
+void pm88x_power_off(void);
+int pm88x_reboot_notifier_callback(struct notifier_block *nb,
+                                  unsigned long code, void *unused);
+
+#endif /* __LINUX_MFD_88PM88X_H */
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to