linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] mfd: support 88pm8606 in 860x driver
@ 2009-11-06 14:22 Haojian Zhuang
  0 siblings, 0 replies; 2+ messages in thread
From: Haojian Zhuang @ 2009-11-06 14:22 UTC (permalink / raw)
  To: linux-arm-kernel

88PM8606 and 88PM8607 are always used together. Although they're two discrete
chips, the logic function is tightly linked. For example, USB charger driver
is based on these two devices.

Now share one driver to these two devices. Create a logical chip structure
that contains both 8606 device and 8607 device.

All I2C operations are accessed by 860x-i2c driver. In order to support both
I2C client address, the read/write API is changed in below.

reg_read(chip, descriptor, offset)
reg_write(chip, descriptor, offset, data)

At here, descriptor is DESC_8606 or DESC_8607 that means operation on which
real device.

The benefit is that client drivers only need one kind of read/write API. I2C
and MFD driver can be shared in both 8606 and 8607.

Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
---
 drivers/mfd/88pm860x-core.c  |   72 ++++++++++++++++++++-------
 drivers/mfd/88pm860x-i2c.c   |  112 ++++++++++++++++++++++++++++--------------
 include/linux/mfd/88pm8607.h |   45 +++++++++++------
 3 files changed, 158 insertions(+), 71 deletions(-)

diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c
index d1464e5..7485eeb 100644
--- a/drivers/mfd/88pm860x-core.c
+++ b/drivers/mfd/88pm860x-core.c
@@ -1,5 +1,5 @@
 /*
- * Base driver for Marvell 88PM8607
+ * Base driver for Marvell 88PM860x
  *
  * Copyright (C) 2009 Marvell International Ltd.
  * 	Haojian Zhuang <haojian.zhuang@marvell.com>
@@ -67,13 +67,25 @@ static struct mfd_cell pm8607_devs[] = {
 	PM8607_REG_DEVS(ldo14, LDO14),
 };

-int pm860x_device_init(struct pm8607_chip *chip,
-		       struct pm8607_platform_data *pdata)
+static struct mixed_88pm860x mixed_chip;
+
+static int __devinit __88pm8606_init(struct pm860x_chip *chip, void *pdata)
 {
-	int i, count;
-	int ret;
+	chip->parent = &mixed_chip;
+	mixed_chip.pm8606 = chip;
+
+	return 0;
+}

-	ret = pm8607_reg_read(chip, PM8607_CHIP_ID);
+static int __devinit __88pm8607_init(struct pm860x_chip *chip,
+				     struct pm8607_plat_data *pdata)
+{
+	int ret = 0;
+
+	chip->parent = &mixed_chip;
+	mixed_chip.pm8607 = chip;
+
+	ret = pm860x_reg_read(chip->parent, DESC_8607, PM8607_CHIP_ID);
 	if (ret < 0) {
 		dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret);
 		goto out;
@@ -88,47 +100,69 @@ int pm860x_device_init(struct pm8607_chip *chip,
 	}
 	chip->chip_id = ret;

-	ret = pm8607_reg_read(chip, PM8607_BUCK3);
+	ret = pm860x_reg_read(chip->parent, DESC_8607, PM8607_BUCK3);
 	if (ret < 0) {
 		dev_err(chip->dev, "Failed to read BUCK3 register: %d\n", ret);
 		goto out;
 	}
 	if (ret & PM8607_BUCK3_DOUBLE)
-		chip->buck3_double = 1;
+		chip->parent->buck3_double = 1;

-	ret = pm8607_reg_read(chip, PM8607_MISC1);
+	ret = pm860x_reg_read(chip->parent, DESC_8607, PM8607_MISC1);
 	if (ret < 0) {
 		dev_err(chip->dev, "Failed to read MISC1 register: %d\n", ret);
 		goto out;
 	}
-	if (pdata->i2c_port == PI2C_PORT)
+	if (pdata && (pdata->i2c_port == PI2C_PORT))
 		ret |= PM8607_MISC1_PI2C;
 	else
 		ret &= ~PM8607_MISC1_PI2C;
-	ret = pm8607_reg_write(chip, PM8607_MISC1, ret);
+	ret = pm860x_reg_write(chip->parent, DESC_8607, PM8607_MISC1, ret);
 	if (ret < 0) {
 		dev_err(chip->dev, "Failed to write MISC1 register: %d\n", ret);
 		goto out;
 	}
+out:
+	return ret;
+}
+
+int __devinit pm860x_device_init(struct pm860x_chip *chip, void *pdata)
+{
+	int i, count;
+	int ret = -EINVAL;
+
+	/* Mixed chip isn't initialized yet. */
+	if ((mixed_chip.flags & MIXED_FLAG_INITIALIZED) == 0)
+		mutex_init(&mixed_chip.io_lock);

-	count = ARRAY_SIZE(pm8607_devs);
-	for (i = 0; i < count; i++) {
-		ret = mfd_add_devices(chip->dev, i, &pm8607_devs[i],
-				      1, NULL, 0);
-		if (ret != 0) {
-			dev_err(chip->dev, "Failed to add subdevs\n");
+	if (!strcmp(chip->id.name, "88PM8607")) {
+		ret = __88pm8607_init(chip, (struct pm8607_plat_data *)pdata);
+		if (ret < 0)
 			goto out;
+
+		count = ARRAY_SIZE(pm8607_devs);
+		for (i = 0; i < count; i++) {
+			ret = mfd_add_devices(chip->dev, i, &pm8607_devs[i],
+					      1, NULL, 0);
+			if (ret != 0) {
+				dev_err(chip->dev, "Failed to add subdevs\n");
+				goto out;
+			}
 		}
+	} else if (!strcmp(chip->id.name, "88PM8606")) {
+		ret = __88pm8606_init(chip, pdata);
+		if (ret < 0)
+			goto out;
 	}
 out:
 	return ret;
 }

-void pm8607_device_exit(struct pm8607_chip *chip)
+void __devexit pm8607_device_exit(struct pm860x_chip *chip)
 {
 	mfd_remove_devices(chip->dev);
 }

-MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM8607");
+MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM860x");
 MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
 MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/88pm860x-i2c.c b/drivers/mfd/88pm860x-i2c.c
index dda23cb..5738cf1 100644
--- a/drivers/mfd/88pm860x-i2c.c
+++ b/drivers/mfd/88pm860x-i2c.c
@@ -1,5 +1,5 @@
 /*
- * I2C driver for Marvell 88PM8607
+ * I2C driver for Marvell 88PM860x
  *
  * Copyright (C) 2009 Marvell International Ltd.
  * 	Haojian Zhuang <haojian.zhuang@marvell.com>
@@ -14,8 +14,8 @@
 #include <linux/i2c.h>
 #include <linux/mfd/88pm8607.h>

-static inline int pm8607_read_device(struct pm8607_chip *chip,
-				     int reg, int bytes, void *dest)
+static inline int __88pm860x_read(struct pm860x_chip *chip,
+				  int reg, int bytes, void *dest)
 {
 	struct i2c_client *i2c = chip->client;
 	unsigned char data;
@@ -32,8 +32,8 @@ static inline int pm8607_read_device(struct pm8607_chip *chip,
 	return 0;
 }

-static inline int pm8607_write_device(struct pm8607_chip *chip,
-				      int reg, int bytes, void *src)
+static inline int __88pm860x_write(struct pm860x_chip *chip,
+				   int reg, int bytes, void *src)
 {
 	struct i2c_client *i2c = chip->client;
 	unsigned char buf[bytes + 1];
@@ -48,82 +48,123 @@ static inline int pm8607_write_device(struct
pm8607_chip *chip,
 	return 0;
 }

-int pm8607_reg_read(struct pm8607_chip *chip, int reg)
+/* Get the chip that is specified by descriptor */
+#define MATCH_860X_CHIP(p, c, id)			\
+do {							\
+	if (p == NULL)					\
+		goto out;				\
+	if ((id == DESC_8606) && (p->pm8606))		\
+		c = p->pm8606;				\
+	else if ((id == DESC_8607) && (p->pm8607))	\
+		c = p->pm8607;				\
+	else						\
+		goto out;				\
+} while (0)
+
+int pm860x_reg_read(struct mixed_88pm860x *parent, int desc, int reg)
 {
+	struct pm860x_chip *chip = NULL;
 	unsigned char data;
 	int ret;

-	mutex_lock(&chip->io_lock);
+	MATCH_860X_CHIP(parent, chip, desc);
+
+	mutex_lock(&parent->io_lock);
 	ret = chip->read(chip, reg, 1, &data);
-	mutex_unlock(&chip->io_lock);
+	mutex_unlock(&parent->io_lock);
+	dev_dbg(chip->dev, "read [%d]:0x%x\n", reg, ret);

 	if (ret < 0)
 		return ret;
 	else
 		return (int)data;
+out:
+	return -EINVAL;
 }
-EXPORT_SYMBOL(pm8607_reg_read);
+EXPORT_SYMBOL(pm860x_reg_read);

-int pm8607_reg_write(struct pm8607_chip *chip, int reg,
+int pm860x_reg_write(struct mixed_88pm860x *parent, int desc, int reg,
 		     unsigned char data)
 {
+	struct pm860x_chip *chip = NULL;
 	int ret;

-	mutex_lock(&chip->io_lock);
+	MATCH_860X_CHIP(parent, chip, desc);
+
+	mutex_lock(&parent->io_lock);
 	ret = chip->write(chip, reg, 1, &data);
-	mutex_unlock(&chip->io_lock);
+	mutex_unlock(&parent->io_lock);
+	dev_dbg(chip->dev, "write [%d]:0x%x\n", reg, data);

 	return ret;
+out:
+	return -EINVAL;
 }
-EXPORT_SYMBOL(pm8607_reg_write);
+EXPORT_SYMBOL(pm860x_reg_write);

-int pm8607_bulk_read(struct pm8607_chip *chip, int reg,
+int pm860x_bulk_read(struct mixed_88pm860x *parent, int desc, int reg,
 		     int count, unsigned char *buf)
 {
+	struct pm860x_chip *chip = NULL;
 	int ret;

-	mutex_lock(&chip->io_lock);
+	MATCH_860X_CHIP(parent, chip, desc);
+
+	mutex_lock(&parent->io_lock);
 	ret = chip->read(chip, reg, count, buf);
-	mutex_unlock(&chip->io_lock);
+	mutex_unlock(&parent->io_lock);

 	return ret;
+out:
+	return -EINVAL;
 }
-EXPORT_SYMBOL(pm8607_bulk_read);
+EXPORT_SYMBOL(pm860x_bulk_read);

-int pm8607_bulk_write(struct pm8607_chip *chip, int reg,
+int pm860x_bulk_write(struct mixed_88pm860x *parent, int desc, int reg,
 		      int count, unsigned char *buf)
 {
+	struct pm860x_chip *chip = NULL;
 	int ret;

-	mutex_lock(&chip->io_lock);
+	MATCH_860X_CHIP(parent, chip, desc);
+
+	mutex_lock(&parent->io_lock);
 	ret = chip->write(chip, reg, count, buf);
-	mutex_unlock(&chip->io_lock);
+	mutex_unlock(&parent->io_lock);

 	return ret;
+out:
+	return -EINVAL;
 }
-EXPORT_SYMBOL(pm8607_bulk_write);
+EXPORT_SYMBOL(pm860x_bulk_write);

-int pm8607_set_bits(struct pm8607_chip *chip, int reg,
+int pm860x_set_bits(struct mixed_88pm860x *parent, int desc, int reg,
 		    unsigned char mask, unsigned char data)
 {
+	struct pm860x_chip *chip = NULL;
 	unsigned char value;
 	int ret;

-	mutex_lock(&chip->io_lock);
+	MATCH_860X_CHIP(parent, chip, desc);
+
+	mutex_lock(&parent->io_lock);
 	ret = chip->read(chip, reg, 1, &value);
 	if (ret < 0)
-		goto out;
+		goto out_rd;
 	value &= ~mask;
 	value |= data;
 	ret = chip->write(chip, reg, 1, &value);
-out:
-	mutex_unlock(&chip->io_lock);
+out_rd:
+	mutex_unlock(&parent->io_lock);
+	dev_dbg(chip->dev, "set bits [%d]:0x%x, ret:%d\n", reg, data, ret);
+
 	return ret;
+out:
+	return -EINVAL;
 }
-EXPORT_SYMBOL(pm8607_set_bits);
-

 static const struct i2c_device_id pm860x_id_table[] = {
+	{ "88PM8606", 0 },
 	{ "88PM8607", 0 },
 	{}
 };
@@ -132,31 +173,28 @@ MODULE_DEVICE_TABLE(i2c, pm860x_id_table);
 static int __devinit pm860x_probe(struct i2c_client *client,
 				  const struct i2c_device_id *id)
 {
-	struct pm8607_platform_data *pdata = client->dev.platform_data;
-	struct pm8607_chip *chip;
+	struct pm860x_chip *chip;
+	struct pm860x_plat_data *pdata;
 	int ret;

-	chip = kzalloc(sizeof(struct pm8607_chip), GFP_KERNEL);
+	chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL);
 	if (chip == NULL)
 		return -ENOMEM;

 	chip->client = client;
 	chip->dev = &client->dev;
-	chip->read = pm8607_read_device;
-	chip->write = pm8607_write_device;
+	chip->read = __88pm860x_read;
+	chip->write = __88pm860x_write;
 	memcpy(&chip->id, id, sizeof(struct i2c_device_id));
 	i2c_set_clientdata(client, chip);

-	mutex_init(&chip->io_lock);
 	dev_set_drvdata(chip->dev, chip);
-
+	pdata = (struct pm860x_plat_data *)client->dev.platform_data;
 	ret = pm860x_device_init(chip, pdata);
 	if (ret < 0)
 		goto out;

-
 	return 0;
-
 out:
 	i2c_set_clientdata(client, NULL);
 	kfree(chip);
diff --git a/include/linux/mfd/88pm8607.h b/include/linux/mfd/88pm8607.h
index 6e4dcdc..bacc1f9 100644
--- a/include/linux/mfd/88pm8607.h
+++ b/include/linux/mfd/88pm8607.h
@@ -13,6 +13,13 @@
 #define __LINUX_MFD_88PM8607_H

 enum {
+	DESC_INVAL = 0,
+	DESC_8606,
+	DESC_8607,
+	DESC_MAX,
+};
+
+enum {
 	PM8607_ID_BUCK1 = 0,
 	PM8607_ID_BUCK2,
 	PM8607_ID_BUCK3,
@@ -180,19 +187,28 @@ enum {
 	PM8607_CHIP_B0 = 0x48,
 };

+struct pm860x_chip;

-struct pm8607_chip {
+#define MIXED_FLAG_INITIALIZED		(1 << 0)
+
+struct mixed_88pm860x {
+	struct pm860x_chip	*pm8606;
+	struct pm860x_chip	*pm8607;
+	struct mutex		io_lock;
+	int			buck3_double;	/* DVC ramp slope double */
+	int			flags;
+};
+
+struct pm860x_chip {
 	struct device		*dev;
 	struct mutex		io_lock;
 	struct i2c_client	*client;
 	struct i2c_device_id	id;
-
-	int (*read)(struct pm8607_chip *chip, int reg, int bytes, void *dest);
-	int (*write)(struct pm8607_chip *chip, int reg, int bytes, void *src);
-
-	int			buck3_double;	/* DVC ramp slope double */
+	struct mixed_88pm860x	*parent;
 	unsigned char		chip_id;

+	int (*read)(struct pm860x_chip *chip, int reg, int bytes, void *dest);
+	int (*write)(struct pm860x_chip *chip, int reg, int bytes, void *src);
 };

 #define PM8607_MAX_REGULATOR	15	/* 3 Bucks, 12 LDOs */
@@ -202,22 +218,21 @@ enum {
 	PI2C_PORT,
 };

-struct pm8607_platform_data {
+struct pm8607_plat_data {
 	int	i2c_port;	/* Controlled by GI2C or PI2C */
 	struct regulator_init_data *regulator[PM8607_MAX_REGULATOR];
 };

-extern int pm8607_reg_read(struct pm8607_chip *, int);
-extern int pm8607_reg_write(struct pm8607_chip *, int, unsigned char);
-extern int pm8607_bulk_read(struct pm8607_chip *, int, int,
+extern int pm860x_reg_read(struct mixed_88pm860x *, int, int);
+extern int pm860x_reg_write(struct mixed_88pm860x *, int, int, unsigned char);
+extern int pm860x_bulk_read(struct mixed_88pm860x *, int, int, int,
 			    unsigned char *);
-extern int pm8607_bulk_write(struct pm8607_chip *, int, int,
+extern int pm860x_bulk_write(struct mixed_88pm860x *, int, int, int,
 			     unsigned char *);
-extern int pm8607_set_bits(struct pm8607_chip *, int, unsigned char,
+extern int pm860x_set_bits(struct mixed_88pm860x *, int, int, unsigned char,
 			   unsigned char);

-extern int pm860x_device_init(struct pm8607_chip *chip,
-			      struct pm8607_platform_data *pdata);
-extern void pm860x_device_exit(struct pm8607_chip *chip);
+extern int pm860x_device_init(struct pm860x_chip *chip, void *pdata);
+extern void pm860x_device_exit(struct pm860x_chip *chip);

 #endif /* __LINUX_MFD_88PM860X_H */
-- 
1.5.6.5

^ permalink raw reply related	[flat|nested] 2+ messages in thread

* [PATCH] mfd: support 88pm8606 in 860x driver
@ 2009-12-08 14:05 Haojian Zhuang
  0 siblings, 0 replies; 2+ messages in thread
From: Haojian Zhuang @ 2009-12-08 14:05 UTC (permalink / raw)
  To: linux-arm-kernel

88PM8606 and 88PM8607 are two discrete chips used for power management.
Hardware designer can use them together or only one of them according to
requirement.

There's some logic tightly linked between these two chips. For example, USB
charger driver needs to access both chips by I2C interface.

Now share one driver to these two devices. Only one I2C client is identified
in platform init data. If another chip is also used, user should mark it in
companion_addr field of platform init data. Then driver could create another
I2C client for the companion chip.

All I2C operations are accessed by 860x-i2c driver. In order to support both
I2C client address, the read/write API is changed in below.

reg_read(client, offset)
reg_write(client, offset, data)

The benefit is that client drivers only need one kind of read/write API. I2C
and MFD driver can be shared in both 8606 and 8607.

Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
---
 drivers/mfd/88pm860x-core.c  |   61 ++++++++----
 drivers/mfd/88pm860x-i2c.c   |  156 +++++++++++++++++++----------
 include/linux/mfd/88pm8607.h |  223 -----------------------------------------
 include/linux/mfd/88pm860x.h |  226 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 369 insertions(+), 297 deletions(-)
 delete mode 100644 include/linux/mfd/88pm8607.h
 create mode 100644 include/linux/mfd/88pm860x.h

diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c
index d1464e5..72b0030 100644
--- a/drivers/mfd/88pm860x-core.c
+++ b/drivers/mfd/88pm860x-core.c
@@ -14,7 +14,7 @@
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/core.h>
-#include <linux/mfd/88pm8607.h>
+#include <linux/mfd/88pm860x.h>


 #define PM8607_REG_RESOURCE(_start, _end)		\
@@ -67,18 +67,23 @@ static struct mfd_cell pm8607_devs[] = {
 	PM8607_REG_DEVS(ldo14, LDO14),
 };

-int pm860x_device_init(struct pm8607_chip *chip,
-		       struct pm8607_platform_data *pdata)
+static void device_8606_init(struct pm860x_chip *chip, struct i2c_client *i2c,
+			     struct pm860x_platform_data *pdata)
+{
+}
+
+static void device_8607_init(struct pm860x_chip *chip, struct i2c_client *i2c,
+			     struct pm860x_platform_data *pdata)
 {
 	int i, count;
 	int ret;

-	ret = pm8607_reg_read(chip, PM8607_CHIP_ID);
+	ret = pm860x_reg_read(i2c, PM8607_CHIP_ID);
 	if (ret < 0) {
 		dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret);
 		goto out;
 	}
-	if ((ret & PM8607_ID_MASK) == PM8607_ID)
+	if ((ret & PM8607_VERSION_MASK) == PM8607_VERSION)
 		dev_info(chip->dev, "Marvell 88PM8607 (ID: %02x) detected\n",
 			 ret);
 	else {
@@ -86,9 +91,9 @@ int pm860x_device_init(struct pm8607_chip *chip,
 			"Chip ID: %02x\n", ret);
 		goto out;
 	}
-	chip->chip_id = ret;
+	chip->chip_version = ret;

-	ret = pm8607_reg_read(chip, PM8607_BUCK3);
+	ret = pm860x_reg_read(i2c, PM8607_BUCK3);
 	if (ret < 0) {
 		dev_err(chip->dev, "Failed to read BUCK3 register: %d\n", ret);
 		goto out;
@@ -96,20 +101,11 @@ int pm860x_device_init(struct pm8607_chip *chip,
 	if (ret & PM8607_BUCK3_DOUBLE)
 		chip->buck3_double = 1;

-	ret = pm8607_reg_read(chip, PM8607_MISC1);
+	ret = pm860x_reg_read(i2c, PM8607_MISC1);
 	if (ret < 0) {
 		dev_err(chip->dev, "Failed to read MISC1 register: %d\n", ret);
 		goto out;
 	}
-	if (pdata->i2c_port == PI2C_PORT)
-		ret |= PM8607_MISC1_PI2C;
-	else
-		ret &= ~PM8607_MISC1_PI2C;
-	ret = pm8607_reg_write(chip, PM8607_MISC1, ret);
-	if (ret < 0) {
-		dev_err(chip->dev, "Failed to write MISC1 register: %d\n", ret);
-		goto out;
-	}

 	count = ARRAY_SIZE(pm8607_devs);
 	for (i = 0; i < count; i++) {
@@ -121,14 +117,39 @@ int pm860x_device_init(struct pm8607_chip *chip,
 		}
 	}
 out:
-	return ret;
+	return;
+}
+
+int pm860x_device_init(struct pm860x_chip *chip,
+		       struct pm860x_platform_data *pdata)
+{
+	switch (chip->id) {
+	case CHIP_PM8606:
+		device_8606_init(chip, chip->client, pdata);
+		break;
+	case CHIP_PM8607:
+		device_8607_init(chip, chip->client, pdata);
+		break;
+	}
+
+	if (chip->companion) {
+		switch (chip->id) {
+		case CHIP_PM8607:
+			device_8606_init(chip, chip->companion, pdata);
+			break;
+		case CHIP_PM8606:
+			device_8607_init(chip, chip->companion, pdata);
+			break;
+		}
+	}
+	return 0;
 }

-void pm8607_device_exit(struct pm8607_chip *chip)
+void pm860x_device_exit(struct pm860x_chip *chip)
 {
 	mfd_remove_devices(chip->dev);
 }

-MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM8607");
+MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM860x");
 MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
 MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/88pm860x-i2c.c b/drivers/mfd/88pm860x-i2c.c
index dda23cb..a5c6b49 100644
--- a/drivers/mfd/88pm860x-i2c.c
+++ b/drivers/mfd/88pm860x-i2c.c
@@ -1,5 +1,5 @@
 /*
- * I2C driver for Marvell 88PM8607
+ * I2C driver for Marvell 88PM860x
  *
  * Copyright (C) 2009 Marvell International Ltd.
  * 	Haojian Zhuang <haojian.zhuang@marvell.com>
@@ -12,12 +12,13 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
-#include <linux/mfd/88pm8607.h>
+#include <linux/mfd/88pm860x.h>

-static inline int pm8607_read_device(struct pm8607_chip *chip,
+static struct mutex io_lock;
+
+static inline int pm860x_read_device(struct i2c_client *i2c,
 				     int reg, int bytes, void *dest)
 {
-	struct i2c_client *i2c = chip->client;
 	unsigned char data;
 	int ret;

@@ -32,10 +33,9 @@ static inline int pm8607_read_device(struct
pm8607_chip *chip,
 	return 0;
 }

-static inline int pm8607_write_device(struct pm8607_chip *chip,
+static inline int pm860x_write_device(struct i2c_client *i2c,
 				      int reg, int bytes, void *src)
 {
-	struct i2c_client *i2c = chip->client;
 	unsigned char buf[bytes + 1];
 	int ret;

@@ -48,116 +48,162 @@ static inline int pm8607_write_device(struct
pm8607_chip *chip,
 	return 0;
 }

-int pm8607_reg_read(struct pm8607_chip *chip, int reg)
+int pm860x_reg_read(struct i2c_client *i2c, int reg)
 {
 	unsigned char data;
 	int ret;

-	mutex_lock(&chip->io_lock);
-	ret = chip->read(chip, reg, 1, &data);
-	mutex_unlock(&chip->io_lock);
+	mutex_lock(&io_lock);
+	ret = pm860x_read_device(i2c, reg, 1, &data);
+	mutex_unlock(&io_lock);

 	if (ret < 0)
 		return ret;
 	else
 		return (int)data;
 }
-EXPORT_SYMBOL(pm8607_reg_read);
+EXPORT_SYMBOL(pm860x_reg_read);

-int pm8607_reg_write(struct pm8607_chip *chip, int reg,
+int pm860x_reg_write(struct i2c_client *i2c, int reg,
 		     unsigned char data)
 {
 	int ret;

-	mutex_lock(&chip->io_lock);
-	ret = chip->write(chip, reg, 1, &data);
-	mutex_unlock(&chip->io_lock);
+	mutex_lock(&io_lock);
+	ret = pm860x_write_device(i2c, reg, 1, &data);
+	mutex_unlock(&io_lock);

 	return ret;
 }
-EXPORT_SYMBOL(pm8607_reg_write);
+EXPORT_SYMBOL(pm860x_reg_write);

-int pm8607_bulk_read(struct pm8607_chip *chip, int reg,
+int pm860x_bulk_read(struct i2c_client *i2c, int reg,
 		     int count, unsigned char *buf)
 {
 	int ret;

-	mutex_lock(&chip->io_lock);
-	ret = chip->read(chip, reg, count, buf);
-	mutex_unlock(&chip->io_lock);
+	mutex_lock(&io_lock);
+	ret = pm860x_read_device(i2c, reg, count, buf);
+	mutex_unlock(&io_lock);

 	return ret;
 }
-EXPORT_SYMBOL(pm8607_bulk_read);
+EXPORT_SYMBOL(pm860x_bulk_read);

-int pm8607_bulk_write(struct pm8607_chip *chip, int reg,
+int pm860x_bulk_write(struct i2c_client *i2c, int reg,
 		      int count, unsigned char *buf)
 {
 	int ret;

-	mutex_lock(&chip->io_lock);
-	ret = chip->write(chip, reg, count, buf);
-	mutex_unlock(&chip->io_lock);
+	mutex_lock(&io_lock);
+	ret = pm860x_write_device(i2c, reg, count, buf);
+	mutex_unlock(&io_lock);

 	return ret;
 }
-EXPORT_SYMBOL(pm8607_bulk_write);
+EXPORT_SYMBOL(pm860x_bulk_write);

-int pm8607_set_bits(struct pm8607_chip *chip, int reg,
+int pm860x_set_bits(struct i2c_client *i2c, int reg,
 		    unsigned char mask, unsigned char data)
 {
 	unsigned char value;
 	int ret;

-	mutex_lock(&chip->io_lock);
-	ret = chip->read(chip, reg, 1, &value);
+	mutex_lock(&io_lock);
+	ret = pm860x_read_device(i2c, reg, 1, &value);
 	if (ret < 0)
 		goto out;
 	value &= ~mask;
 	value |= data;
-	ret = chip->write(chip, reg, 1, &value);
+	ret = pm860x_write_device(i2c, reg, 1, &value);
 out:
-	mutex_unlock(&chip->io_lock);
+	mutex_unlock(&io_lock);
 	return ret;
 }
-EXPORT_SYMBOL(pm8607_set_bits);
+EXPORT_SYMBOL(pm860x_set_bits);


 static const struct i2c_device_id pm860x_id_table[] = {
-	{ "88PM8607", 0 },
+	{ "88PM860x", 0 },
 	{}
 };
 MODULE_DEVICE_TABLE(i2c, pm860x_id_table);

+static int verify_addr(struct i2c_client *i2c)
+{
+	unsigned short addr_8607[] = {0x30, 0x34};
+	unsigned short addr_8606[] = {0x10, 0x11};
+	int size, i;
+
+	if (i2c == NULL)
+		return 0;
+	size = ARRAY_SIZE(addr_8606);
+	for (i = 0; i < size; i++) {
+		if (i2c->addr == *(addr_8606 + i))
+			return CHIP_PM8606;
+	}
+	size = ARRAY_SIZE(addr_8607);
+	for (i = 0; i < size; i++) {
+		if (i2c->addr == *(addr_8607 + i))
+			return CHIP_PM8607;
+	}
+	return 0;
+}
+
 static int __devinit pm860x_probe(struct i2c_client *client,
 				  const struct i2c_device_id *id)
 {
-	struct pm8607_platform_data *pdata = client->dev.platform_data;
-	struct pm8607_chip *chip;
+	struct pm860x_platform_data *pdata = client->dev.platform_data;
+	struct pm860x_chip *chip;
+	struct i2c_board_info i2c_info = {
+		.type		= "88PM860x",
+		.platform_data	= client->dev.platform_data,
+	};
+	int addr_c, found_companion = 0;
 	int ret;

-	chip = kzalloc(sizeof(struct pm8607_chip), GFP_KERNEL);
-	if (chip == NULL)
-		return -ENOMEM;
-
-	chip->client = client;
-	chip->dev = &client->dev;
-	chip->read = pm8607_read_device;
-	chip->write = pm8607_write_device;
-	memcpy(&chip->id, id, sizeof(struct i2c_device_id));
-	i2c_set_clientdata(client, chip);
-
-	mutex_init(&chip->io_lock);
-	dev_set_drvdata(chip->dev, chip);
-
-	ret = pm860x_device_init(chip, pdata);
-	if (ret < 0)
-		goto out;
-
+	if (pdata == NULL) {
+		pr_info("No platform data in %s!\n", __func__);
+		return -EINVAL;
+	}
+
+	addr_c = pdata->companion_addr;
+	if (addr_c && (addr_c != client->addr)) {
+		i2c_info.addr = addr_c;
+		found_companion = 1;
+	}
+
+	if (found_companion || (addr_c == 0)) {
+		chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL);
+		if (chip == NULL)
+			return -ENOMEM;
+
+		chip->id = verify_addr(client);
+		chip->client = client;
+		i2c_set_clientdata(client, chip);
+		chip->dev = &client->dev;
+		mutex_init(&io_lock);
+		dev_set_drvdata(chip->dev, chip);
+
+		if (found_companion) {
+			chip->companion = i2c_new_device(client->adapter,
+							 &i2c_info);
+			i2c_set_clientdata(chip->companion, chip);
+		}
+
+		ret = pm860x_device_init(chip, pdata);
+		if (ret < 0)
+			goto out;
+	}

 	return 0;

 out:
+	if (chip->companion) {
+		i2c_unregister_device(chip->companion);
+		i2c_set_clientdata(chip->companion, NULL);
+		return 0;
+	}
 	i2c_set_clientdata(client, NULL);
 	kfree(chip);
 	return ret;
@@ -165,8 +211,10 @@ out:

 static int __devexit pm860x_remove(struct i2c_client *client)
 {
-	struct pm8607_chip *chip = i2c_get_clientdata(client);
+	struct pm860x_chip *chip = i2c_get_clientdata(client);

+	if (chip->companion)
+		i2c_unregister_device(chip->companion);
 	kfree(chip);
 	return 0;
 }
diff --git a/include/linux/mfd/88pm8607.h b/include/linux/mfd/88pm8607.h
deleted file mode 100644
index 6e4dcdc..0000000
--- a/include/linux/mfd/88pm8607.h
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * Marvell 88PM8607 Interface
- *
- * Copyright (C) 2009 Marvell International Ltd.
- * 	Haojian Zhuang <haojian.zhuang@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_88PM8607_H
-#define __LINUX_MFD_88PM8607_H
-
-enum {
-	PM8607_ID_BUCK1 = 0,
-	PM8607_ID_BUCK2,
-	PM8607_ID_BUCK3,
-
-	PM8607_ID_LDO1,
-	PM8607_ID_LDO2,
-	PM8607_ID_LDO3,
-	PM8607_ID_LDO4,
-	PM8607_ID_LDO5,
-	PM8607_ID_LDO6,
-	PM8607_ID_LDO7,
-	PM8607_ID_LDO8,
-	PM8607_ID_LDO9,
-	PM8607_ID_LDO10,
-	PM8607_ID_LDO12,
-	PM8607_ID_LDO14,
-
-	PM8607_ID_RG_MAX,
-};
-
-#define PM8607_ID			(0x40)	/* 8607 chip ID */
-#define PM8607_ID_MASK			(0xF8)	/* 8607 chip ID mask */
-
-/* Interrupt Registers */
-#define PM8607_STATUS_1			(0x01)
-#define PM8607_STATUS_2			(0x02)
-#define PM8607_INT_STATUS1		(0x03)
-#define PM8607_INT_STATUS2		(0x04)
-#define PM8607_INT_STATUS3		(0x05)
-#define PM8607_INT_MASK_1		(0x06)
-#define PM8607_INT_MASK_2		(0x07)
-#define PM8607_INT_MASK_3		(0x08)
-
-/* Regulator Control Registers */
-#define PM8607_LDO1			(0x10)
-#define PM8607_LDO2			(0x11)
-#define PM8607_LDO3			(0x12)
-#define PM8607_LDO4			(0x13)
-#define PM8607_LDO5			(0x14)
-#define PM8607_LDO6			(0x15)
-#define PM8607_LDO7			(0x16)
-#define PM8607_LDO8			(0x17)
-#define PM8607_LDO9			(0x18)
-#define PM8607_LDO10			(0x19)
-#define PM8607_LDO12			(0x1A)
-#define PM8607_LDO14			(0x1B)
-#define PM8607_SLEEP_MODE1		(0x1C)
-#define PM8607_SLEEP_MODE2		(0x1D)
-#define PM8607_SLEEP_MODE3		(0x1E)
-#define PM8607_SLEEP_MODE4		(0x1F)
-#define PM8607_GO			(0x20)
-#define PM8607_SLEEP_BUCK1		(0x21)
-#define PM8607_SLEEP_BUCK2		(0x22)
-#define PM8607_SLEEP_BUCK3		(0x23)
-#define PM8607_BUCK1			(0x24)
-#define PM8607_BUCK2			(0x25)
-#define PM8607_BUCK3			(0x26)
-#define PM8607_BUCK_CONTROLS		(0x27)
-#define PM8607_SUPPLIES_EN11		(0x2B)
-#define PM8607_SUPPLIES_EN12		(0x2C)
-#define PM8607_GROUP1			(0x2D)
-#define PM8607_GROUP2			(0x2E)
-#define PM8607_GROUP3			(0x2F)
-#define PM8607_GROUP4			(0x30)
-#define PM8607_GROUP5			(0x31)
-#define PM8607_GROUP6			(0x32)
-#define PM8607_SUPPLIES_EN21		(0x33)
-#define PM8607_SUPPLIES_EN22		(0x34)
-
-/* RTC Control Registers */
-#define PM8607_RTC1			(0xA0)
-#define PM8607_RTC_COUNTER1		(0xA1)
-#define PM8607_RTC_COUNTER2		(0xA2)
-#define PM8607_RTC_COUNTER3		(0xA3)
-#define PM8607_RTC_COUNTER4		(0xA4)
-#define PM8607_RTC_EXPIRE1		(0xA5)
-#define PM8607_RTC_EXPIRE2		(0xA6)
-#define PM8607_RTC_EXPIRE3		(0xA7)
-#define PM8607_RTC_EXPIRE4		(0xA8)
-#define PM8607_RTC_TRIM1		(0xA9)
-#define PM8607_RTC_TRIM2		(0xAA)
-#define PM8607_RTC_TRIM3		(0xAB)
-#define PM8607_RTC_TRIM4		(0xAC)
-#define PM8607_RTC_MISC1		(0xAD)
-#define PM8607_RTC_MISC2		(0xAE)
-#define PM8607_RTC_MISC3		(0xAF)
-
-/* Misc Registers */
-#define PM8607_CHIP_ID			(0x00)
-#define PM8607_LDO1			(0x10)
-#define PM8607_DVC3			(0x26)
-#define PM8607_MISC1			(0x40)
-
-/* bit definitions for PM8607 events */
-#define PM8607_EVENT_ONKEY		(1 << 0)
-#define PM8607_EVENT_EXTON		(1 << 1)
-#define PM8607_EVENT_CHG		(1 << 2)
-#define PM8607_EVENT_BAT		(1 << 3)
-#define PM8607_EVENT_RTC		(1 << 4)
-#define PM8607_EVENT_CC			(1 << 5)
-#define PM8607_EVENT_VBAT		(1 << 8)
-#define PM8607_EVENT_VCHG		(1 << 9)
-#define PM8607_EVENT_VSYS		(1 << 10)
-#define PM8607_EVENT_TINT		(1 << 11)
-#define PM8607_EVENT_GPADC0		(1 << 12)
-#define PM8607_EVENT_GPADC1		(1 << 13)
-#define PM8607_EVENT_GPADC2		(1 << 14)
-#define PM8607_EVENT_GPADC3		(1 << 15)
-#define PM8607_EVENT_AUDIO_SHORT	(1 << 16)
-#define PM8607_EVENT_PEN		(1 << 17)
-#define PM8607_EVENT_HEADSET		(1 << 18)
-#define PM8607_EVENT_HOOK		(1 << 19)
-#define PM8607_EVENT_MICIN		(1 << 20)
-#define PM8607_EVENT_CHG_TIMEOUT	(1 << 21)
-#define PM8607_EVENT_CHG_DONE		(1 << 22)
-#define PM8607_EVENT_CHG_FAULT		(1 << 23)
-
-/* bit definitions of Status Query Interface */
-#define PM8607_STATUS_CC		(1 << 3)
-#define PM8607_STATUS_PEN		(1 << 4)
-#define PM8607_STATUS_HEADSET		(1 << 5)
-#define PM8607_STATUS_HOOK		(1 << 6)
-#define PM8607_STATUS_MICIN		(1 << 7)
-#define PM8607_STATUS_ONKEY		(1 << 8)
-#define PM8607_STATUS_EXTON		(1 << 9)
-#define PM8607_STATUS_CHG		(1 << 10)
-#define PM8607_STATUS_BAT		(1 << 11)
-#define PM8607_STATUS_VBUS		(1 << 12)
-#define PM8607_STATUS_OV		(1 << 13)
-
-/* bit definitions of BUCK3 */
-#define PM8607_BUCK3_DOUBLE		(1 << 6)
-
-/* bit definitions of Misc1 */
-#define PM8607_MISC1_PI2C		(1 << 0)
-
-/* Interrupt Number in 88PM8607 */
-enum {
-	PM8607_IRQ_ONKEY = 0,
-	PM8607_IRQ_EXTON,
-	PM8607_IRQ_CHG,
-	PM8607_IRQ_BAT,
-	PM8607_IRQ_RTC,
-	PM8607_IRQ_VBAT = 8,
-	PM8607_IRQ_VCHG,
-	PM8607_IRQ_VSYS,
-	PM8607_IRQ_TINT,
-	PM8607_IRQ_GPADC0,
-	PM8607_IRQ_GPADC1,
-	PM8607_IRQ_GPADC2,
-	PM8607_IRQ_GPADC3,
-	PM8607_IRQ_AUDIO_SHORT = 16,
-	PM8607_IRQ_PEN,
-	PM8607_IRQ_HEADSET,
-	PM8607_IRQ_HOOK,
-	PM8607_IRQ_MICIN,
-	PM8607_IRQ_CHG_FAIL,
-	PM8607_IRQ_CHG_DONE,
-	PM8607_IRQ_CHG_FAULT,
-};
-
-enum {
-	PM8607_CHIP_A0 = 0x40,
-	PM8607_CHIP_A1 = 0x41,
-	PM8607_CHIP_B0 = 0x48,
-};
-
-
-struct pm8607_chip {
-	struct device		*dev;
-	struct mutex		io_lock;
-	struct i2c_client	*client;
-	struct i2c_device_id	id;
-
-	int (*read)(struct pm8607_chip *chip, int reg, int bytes, void *dest);
-	int (*write)(struct pm8607_chip *chip, int reg, int bytes, void *src);
-
-	int			buck3_double;	/* DVC ramp slope double */
-	unsigned char		chip_id;
-
-};
-
-#define PM8607_MAX_REGULATOR	15	/* 3 Bucks, 12 LDOs */
-
-enum {
-	GI2C_PORT = 0,
-	PI2C_PORT,
-};
-
-struct pm8607_platform_data {
-	int	i2c_port;	/* Controlled by GI2C or PI2C */
-	struct regulator_init_data *regulator[PM8607_MAX_REGULATOR];
-};
-
-extern int pm8607_reg_read(struct pm8607_chip *, int);
-extern int pm8607_reg_write(struct pm8607_chip *, int, unsigned char);
-extern int pm8607_bulk_read(struct pm8607_chip *, int, int,
-			    unsigned char *);
-extern int pm8607_bulk_write(struct pm8607_chip *, int, int,
-			     unsigned char *);
-extern int pm8607_set_bits(struct pm8607_chip *, int, unsigned char,
-			   unsigned char);
-
-extern int pm860x_device_init(struct pm8607_chip *chip,
-			      struct pm8607_platform_data *pdata);
-extern void pm860x_device_exit(struct pm8607_chip *chip);
-
-#endif /* __LINUX_MFD_88PM860X_H */
diff --git a/include/linux/mfd/88pm860x.h b/include/linux/mfd/88pm860x.h
new file mode 100644
index 0000000..b648b9f
--- /dev/null
+++ b/include/linux/mfd/88pm860x.h
@@ -0,0 +1,226 @@
+/*
+ * Marvell 88PM860x Interface
+ *
+ * Copyright (C) 2009 Marvell International Ltd.
+ * 	Haojian Zhuang <haojian.zhuang@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_88PM860X_H
+#define __LINUX_MFD_88PM860X_H
+
+enum {
+	CHIP_INVALID = 0,
+	CHIP_PM8606,
+	CHIP_PM8607,
+	CHIP_MAX,
+};
+
+enum {
+	PM8607_ID_BUCK1 = 0,
+	PM8607_ID_BUCK2,
+	PM8607_ID_BUCK3,
+
+	PM8607_ID_LDO1,
+	PM8607_ID_LDO2,
+	PM8607_ID_LDO3,
+	PM8607_ID_LDO4,
+	PM8607_ID_LDO5,
+	PM8607_ID_LDO6,
+	PM8607_ID_LDO7,
+	PM8607_ID_LDO8,
+	PM8607_ID_LDO9,
+	PM8607_ID_LDO10,
+	PM8607_ID_LDO12,
+	PM8607_ID_LDO14,
+
+	PM8607_ID_RG_MAX,
+};
+
+#define PM8607_VERSION			(0x40)	/* 8607 chip ID */
+#define PM8607_VERSION_MASK		(0xF0)	/* 8607 chip ID mask */
+
+/* Interrupt Registers */
+#define PM8607_STATUS_1			(0x01)
+#define PM8607_STATUS_2			(0x02)
+#define PM8607_INT_STATUS1		(0x03)
+#define PM8607_INT_STATUS2		(0x04)
+#define PM8607_INT_STATUS3		(0x05)
+#define PM8607_INT_MASK_1		(0x06)
+#define PM8607_INT_MASK_2		(0x07)
+#define PM8607_INT_MASK_3		(0x08)
+
+/* Regulator Control Registers */
+#define PM8607_LDO1			(0x10)
+#define PM8607_LDO2			(0x11)
+#define PM8607_LDO3			(0x12)
+#define PM8607_LDO4			(0x13)
+#define PM8607_LDO5			(0x14)
+#define PM8607_LDO6			(0x15)
+#define PM8607_LDO7			(0x16)
+#define PM8607_LDO8			(0x17)
+#define PM8607_LDO9			(0x18)
+#define PM8607_LDO10			(0x19)
+#define PM8607_LDO12			(0x1A)
+#define PM8607_LDO14			(0x1B)
+#define PM8607_SLEEP_MODE1		(0x1C)
+#define PM8607_SLEEP_MODE2		(0x1D)
+#define PM8607_SLEEP_MODE3		(0x1E)
+#define PM8607_SLEEP_MODE4		(0x1F)
+#define PM8607_GO			(0x20)
+#define PM8607_SLEEP_BUCK1		(0x21)
+#define PM8607_SLEEP_BUCK2		(0x22)
+#define PM8607_SLEEP_BUCK3		(0x23)
+#define PM8607_BUCK1			(0x24)
+#define PM8607_BUCK2			(0x25)
+#define PM8607_BUCK3			(0x26)
+#define PM8607_BUCK_CONTROLS		(0x27)
+#define PM8607_SUPPLIES_EN11		(0x2B)
+#define PM8607_SUPPLIES_EN12		(0x2C)
+#define PM8607_GROUP1			(0x2D)
+#define PM8607_GROUP2			(0x2E)
+#define PM8607_GROUP3			(0x2F)
+#define PM8607_GROUP4			(0x30)
+#define PM8607_GROUP5			(0x31)
+#define PM8607_GROUP6			(0x32)
+#define PM8607_SUPPLIES_EN21		(0x33)
+#define PM8607_SUPPLIES_EN22		(0x34)
+
+/* RTC Control Registers */
+#define PM8607_RTC1			(0xA0)
+#define PM8607_RTC_COUNTER1		(0xA1)
+#define PM8607_RTC_COUNTER2		(0xA2)
+#define PM8607_RTC_COUNTER3		(0xA3)
+#define PM8607_RTC_COUNTER4		(0xA4)
+#define PM8607_RTC_EXPIRE1		(0xA5)
+#define PM8607_RTC_EXPIRE2		(0xA6)
+#define PM8607_RTC_EXPIRE3		(0xA7)
+#define PM8607_RTC_EXPIRE4		(0xA8)
+#define PM8607_RTC_TRIM1		(0xA9)
+#define PM8607_RTC_TRIM2		(0xAA)
+#define PM8607_RTC_TRIM3		(0xAB)
+#define PM8607_RTC_TRIM4		(0xAC)
+#define PM8607_RTC_MISC1		(0xAD)
+#define PM8607_RTC_MISC2		(0xAE)
+#define PM8607_RTC_MISC3		(0xAF)
+
+/* Misc Registers */
+#define PM8607_CHIP_ID			(0x00)
+#define PM8607_LDO1			(0x10)
+#define PM8607_DVC3			(0x26)
+#define PM8607_MISC1			(0x40)
+
+/* bit definitions for PM8607 events */
+#define PM8607_EVENT_ONKEY		(1 << 0)
+#define PM8607_EVENT_EXTON		(1 << 1)
+#define PM8607_EVENT_CHG		(1 << 2)
+#define PM8607_EVENT_BAT		(1 << 3)
+#define PM8607_EVENT_RTC		(1 << 4)
+#define PM8607_EVENT_CC			(1 << 5)
+#define PM8607_EVENT_VBAT		(1 << 8)
+#define PM8607_EVENT_VCHG		(1 << 9)
+#define PM8607_EVENT_VSYS		(1 << 10)
+#define PM8607_EVENT_TINT		(1 << 11)
+#define PM8607_EVENT_GPADC0		(1 << 12)
+#define PM8607_EVENT_GPADC1		(1 << 13)
+#define PM8607_EVENT_GPADC2		(1 << 14)
+#define PM8607_EVENT_GPADC3		(1 << 15)
+#define PM8607_EVENT_AUDIO_SHORT	(1 << 16)
+#define PM8607_EVENT_PEN		(1 << 17)
+#define PM8607_EVENT_HEADSET		(1 << 18)
+#define PM8607_EVENT_HOOK		(1 << 19)
+#define PM8607_EVENT_MICIN		(1 << 20)
+#define PM8607_EVENT_CHG_TIMEOUT	(1 << 21)
+#define PM8607_EVENT_CHG_DONE		(1 << 22)
+#define PM8607_EVENT_CHG_FAULT		(1 << 23)
+
+/* bit definitions of Status Query Interface */
+#define PM8607_STATUS_CC		(1 << 3)
+#define PM8607_STATUS_PEN		(1 << 4)
+#define PM8607_STATUS_HEADSET		(1 << 5)
+#define PM8607_STATUS_HOOK		(1 << 6)
+#define PM8607_STATUS_MICIN		(1 << 7)
+#define PM8607_STATUS_ONKEY		(1 << 8)
+#define PM8607_STATUS_EXTON		(1 << 9)
+#define PM8607_STATUS_CHG		(1 << 10)
+#define PM8607_STATUS_BAT		(1 << 11)
+#define PM8607_STATUS_VBUS		(1 << 12)
+#define PM8607_STATUS_OV		(1 << 13)
+
+/* bit definitions of BUCK3 */
+#define PM8607_BUCK3_DOUBLE		(1 << 6)
+
+/* bit definitions of Misc1 */
+#define PM8607_MISC1_PI2C		(1 << 0)
+
+/* Interrupt Number in 88PM8607 */
+enum {
+	PM8607_IRQ_ONKEY = 0,
+	PM8607_IRQ_EXTON,
+	PM8607_IRQ_CHG,
+	PM8607_IRQ_BAT,
+	PM8607_IRQ_RTC,
+	PM8607_IRQ_VBAT = 8,
+	PM8607_IRQ_VCHG,
+	PM8607_IRQ_VSYS,
+	PM8607_IRQ_TINT,
+	PM8607_IRQ_GPADC0,
+	PM8607_IRQ_GPADC1,
+	PM8607_IRQ_GPADC2,
+	PM8607_IRQ_GPADC3,
+	PM8607_IRQ_AUDIO_SHORT = 16,
+	PM8607_IRQ_PEN,
+	PM8607_IRQ_HEADSET,
+	PM8607_IRQ_HOOK,
+	PM8607_IRQ_MICIN,
+	PM8607_IRQ_CHG_FAIL,
+	PM8607_IRQ_CHG_DONE,
+	PM8607_IRQ_CHG_FAULT,
+};
+
+enum {
+	PM8607_CHIP_A0 = 0x40,
+	PM8607_CHIP_A1 = 0x41,
+	PM8607_CHIP_B0 = 0x48,
+};
+
+struct pm860x_chip {
+	struct device		*dev;
+	struct mutex		io_lock;
+	struct i2c_client	*client;
+	struct i2c_client	*companion;	/* companion chip client */
+
+	int			buck3_double;	/* DVC ramp slope double */
+	int			id;
+	unsigned char		chip_version;
+
+};
+
+#define PM8607_MAX_REGULATOR	15	/* 3 Bucks, 12 LDOs */
+
+enum {
+	GI2C_PORT = 0,
+	PI2C_PORT,
+};
+
+struct pm860x_platform_data {
+	unsigned short	companion_addr;	/* I2C address of companion chip */
+	int		i2c_port;	/* Controlled by GI2C or PI2C */
+	struct regulator_init_data *regulator[PM8607_MAX_REGULATOR];
+};
+
+extern int pm860x_reg_read(struct i2c_client *, int);
+extern int pm860x_reg_write(struct i2c_client *, int, unsigned char);
+extern int pm860x_bulk_read(struct i2c_client *, int, int, unsigned char *);
+extern int pm860x_bulk_write(struct i2c_client *, int, int, unsigned char *);
+extern int pm860x_set_bits(struct i2c_client *, int, unsigned char,
+			   unsigned char);
+
+extern int pm860x_device_init(struct pm860x_chip *chip,
+			      struct pm860x_platform_data *pdata);
+extern void pm860x_device_exit(struct pm860x_chip *chip);
+
+#endif /* __LINUX_MFD_88PM860X_H */
-- 
1.5.6.5

^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2009-12-08 14:05 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-12-08 14:05 [PATCH] mfd: support 88pm8606 in 860x driver Haojian Zhuang
  -- strict thread matches above, loose matches on Subject: below --
2009-11-06 14:22 Haojian Zhuang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).