aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHaitao Zhang <haitao.zhang@linaro.org>2012-04-20 14:50:44 +0800
committerHaitao Zhang <hzhang@canonical.com>2012-04-20 14:50:44 +0800
commit988d1ae8e3274dcf600c6594e285c421777bb746 (patch)
treed105ce2f0d0f729c90f57ba4d38275bdded3d014
parent14afa455185e3cd868d31f19ce27df8030b8be17 (diff)
parentf3d28445de908bf2a848f6e8104b5c7f347ecd64 (diff)
Merge branch 'lt-3.4-topic-ripleydt' of git://git.linaro.org/people/paulliu/linux-2.6 into lt-3.4lt-3.4
-rw-r--r--Documentation/devicetree/bindings/mfd/mc34708.txt61
-rw-r--r--arch/arm/boot/dts/imx53-qsb.dts104
-rw-r--r--drivers/mfd/Kconfig11
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/mc34708-core.c634
-rw-r--r--drivers/regulator/Kconfig7
-rw-r--r--drivers/regulator/Makefile1
-rw-r--r--drivers/regulator/mc34708-regulator.c729
-rw-r--r--drivers/regulator/mc34708.h79
-rw-r--r--include/linux/mfd/mc34708.h134
10 files changed, 1761 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/mfd/mc34708.txt b/Documentation/devicetree/bindings/mfd/mc34708.txt
new file mode 100644
index 00000000000..2bb5c9eacb2
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/mc34708.txt
@@ -0,0 +1,61 @@
+* Freescale MC34708 Power Management Integrated Circuit (PMIC)
+
+Required properties:
+- compatible : Must be "fsl,mc34708"
+
+Optional properties:
+- fsl,mc34708-uses-adc : Indicate the ADC is being used
+- fsl,mc34708-uses-rtc : Indicate the RTC is being used
+- fsl,mc34708-uses-ts : Indicate the touchscreen controller is being used
+
+Sub-nodes:
+- regulators : Contain the regulator nodes. The MC34708 regulators are
+ bound using their names as listed below for enabling.
+
+ mc34708__sw1a : regulator SW1A
+ mc34708__sw1b : regulator SW1B
+ mc34708__sw2 : regulator SW2
+ mc34708__sw3 : regulator SW3
+ mc34708__sw4A : regulator SW4A
+ mc34708__sw4b : regulator SW4B
+ mc34708__swbst : regulator SWBST
+ mc34708__vpll : regulator VPLL
+ mc34708__vrefddr : regulator VREFDDR
+ mc34708__vusb : regulator VUSB
+ mc34708__vusb2 : regulator VUSB2
+ mc34708__vdac : regulator VDAC
+ mc34708__vgen1 : regulator VGEN1
+ mc34708__vgen2 : regulator VGEN2
+
+ The bindings details of individual regulator device can be found in:
+ Documentation/devicetree/bindings/regulator/regulator.txt
+
+Examples:
+
+i2c@63fc8000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,imx53-i2c", "fsl,imx1-i2c";
+ reg = <0x63fc8000 0x4000>;
+ interrupts = <62>;
+ status = "okay";
+
+ pmic: mc34708@8 {
+ compatible = "fsl,mc34708";
+ reg = <0x08>;
+
+ regulators {
+ mc34708__sw1a {
+ regulator-min-microvolt = <650000>;
+ regulator-max-microvolt = <1437500>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ mc34708__vusb {
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/imx53-qsb.dts b/arch/arm/boot/dts/imx53-qsb.dts
index 03f2edc86a6..ce73ab610d5 100644
--- a/arch/arm/boot/dts/imx53-qsb.dts
+++ b/arch/arm/boot/dts/imx53-qsb.dts
@@ -166,6 +166,110 @@
};
};
};
+
+ ripley@8 {
+ compatible = "fsl,mc34708";
+ reg = <0x08>;
+ regulators {
+ mc34708__sw1a {
+ regulator-name = "SW1";
+ regulator-min-microvolt = <650000>;
+ regulator-max-microvolt = <1437500>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ mc34708__sw1b {
+ regulator-name = "SW1B";
+ regulator-min-microvolt = <650000>;
+ regulator-max-microvolt = <1437500>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ mc34708__sw2 {
+ regulator-name = "SW2";
+ regulator-min-microvolt = <650000>;
+ regulator-max-microvolt = <1437500>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ mc34708__sw3 {
+ regulator-name = "SW3";
+ regulator-min-microvolt = <650000>;
+ regulator-max-microvolt = <1425000>;
+ regulator-boot-on;
+ };
+ mc34708__sw4a {
+ regulator-name = "SW4A";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ mc34708__sw4b {
+ regulator-name = "SW4B";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ mc34708__sw5 {
+ regulator-name = "SW5";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1975000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ mc34708__swbst {
+ regulator-name = "SWBST";
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ mc34708__vpll {
+ regulator-name = "VPLL";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-boot-on;
+ };
+ mc34708__vrefddr {
+ regulator-name = "VREFDDR";
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ mc34708__vusb {
+ regulator-name = "VUSB";
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ mc34708__vusb2 {
+ regulator-name = "VUSB2";
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ mc34708__vdac {
+ regulator-name = "VDAC";
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <2775000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ mc34708__vgen1 {
+ regulator-name = "VGEN1";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1550000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ mc34708__vgen2 {
+ regulator-name = "VGEN2";
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ };
+ };
};
fec@63fec000 {
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 29f463cc09c..6421e67e026 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -600,6 +600,17 @@ config MFD_MC13XXX
additional drivers must be enabled in order to use the
functionality of the device.
+config MFD_MC34708
+ tristate "Support for Freescale's PMIC MC34708"
+ depends on I2C
+ depends on OF
+ select MFD_CORE
+ help
+ Support for the Freescale's PMIC MC34708
+ This driver provides common support for accessing the device,
+ additional drivers must be enabled in order to use the
+ functionality of the device.
+
config ABX500_CORE
bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions"
default y if ARCH_U300 || ARCH_U8500
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 05fa538c5ef..b98d9435507 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_TWL6030_PWM) += twl6030-pwm.o
obj-$(CONFIG_TWL6040_CORE) += twl6040-core.o twl6040-irq.o
obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o
+obj-$(CONFIG_MFD_MC34708) += mc34708-core.o
obj-$(CONFIG_MFD_CORE) += mfd-core.o
diff --git a/drivers/mfd/mc34708-core.c b/drivers/mfd/mc34708-core.c
new file mode 100644
index 00000000000..54f469b8e95
--- /dev/null
+++ b/drivers/mfd/mc34708-core.c
@@ -0,0 +1,634 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/mc34708.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+struct mc34708 {
+ struct i2c_client *i2c_client;
+ struct mutex lock;
+ int irq;
+
+ irq_handler_t irqhandler[MC34708_NUM_IRQ];
+ void *irqdata[MC34708_NUM_IRQ];
+};
+
+/*!
+ * This is the enumeration of versions of PMIC
+ */
+enum mc34708_id {
+ MC_PMIC_ID_MC34708,
+ MC_PMIC_ID_INVALID,
+};
+
+struct mc34708_version_t {
+ /*!
+ * PMIC version identifier.
+ */
+ enum mc34708_id id;
+ /*!
+ * Revision of the PMIC.
+ */
+ int revision;
+};
+
+#define PMIC_I2C_RETRY_TIMES 10
+
+static const struct i2c_device_id mc34708_device_id[] = {
+ {"mc34708", MC_PMIC_ID_MC34708},
+ {},
+};
+
+static const char * const mc34708_chipname[] = {
+ [MC_PMIC_ID_MC34708] = "mc34708",
+};
+
+void mc34708_lock(struct mc34708 *mc_pmic)
+{
+ if (!mutex_trylock(&mc_pmic->lock)) {
+ dev_dbg(&mc_pmic->i2c_client->dev, "wait for %s from %pf\n",
+ __func__, __builtin_return_address(0));
+
+ mutex_lock(&mc_pmic->lock);
+ }
+ dev_dbg(&mc_pmic->i2c_client->dev, "%s from %pf\n",
+ __func__, __builtin_return_address(0));
+}
+EXPORT_SYMBOL(mc34708_lock);
+
+void mc34708_unlock(struct mc34708 *mc_pmic)
+{
+ dev_dbg(&mc_pmic->i2c_client->dev, "%s from %pf\n",
+ __func__, __builtin_return_address(0));
+ mutex_unlock(&mc_pmic->lock);
+}
+EXPORT_SYMBOL(mc34708_unlock);
+
+static int mc34708_i2c_24bit_read(struct i2c_client *client,
+ unsigned int offset,
+ unsigned int *value)
+{
+ unsigned char buf[3];
+ int ret;
+ int i;
+
+ memset(buf, 0, 3);
+ for (i = 0; i < PMIC_I2C_RETRY_TIMES; i++) {
+ ret = i2c_smbus_read_i2c_block_data(client, offset, 3, buf);
+ if (ret == 3)
+ break;
+ usleep_range(1000, 1500);
+ }
+
+ if (ret == 3) {
+ *value = buf[0] << 16 | buf[1] << 8 | buf[2];
+ return ret;
+ } else {
+ dev_err(&client->dev, "24bit read error, ret = %d\n", ret);
+ return -1; /* return -1 on failure */
+ }
+}
+
+int mc34708_reg_read(struct mc34708 *mc_pmic, unsigned int offset,
+ u32 *val)
+{
+ BUG_ON(!mutex_is_locked(&mc_pmic->lock));
+
+ if (offset > MC34708_NUMREGS)
+ return -EINVAL;
+
+ if (mc34708_i2c_24bit_read(mc_pmic->i2c_client, offset, val) == -1)
+ return -1;
+ *val &= 0xffffff;
+
+ dev_vdbg(&mc_pmic->i2c_client->dev, "mc_pmic read [%02d] -> 0x%06x\n",
+ offset, *val);
+
+ return 0;
+}
+EXPORT_SYMBOL(mc34708_reg_read);
+
+static int mc34708_i2c_24bit_write(struct i2c_client *client,
+ unsigned int offset, unsigned int reg_val)
+{
+ char buf[3];
+ int ret;
+ int i;
+
+ buf[0] = (reg_val >> 16) & 0xff;
+ buf[1] = (reg_val >> 8) & 0xff;
+ buf[2] = (reg_val) & 0xff;
+
+ for (i = 0; i < PMIC_I2C_RETRY_TIMES; i++) {
+ ret = i2c_smbus_write_i2c_block_data(client, offset, 3, buf);
+ if (ret == 0)
+ break;
+ usleep_range(1000, 1500);
+ }
+ if (i == PMIC_I2C_RETRY_TIMES)
+ dev_err(&client->dev, "24bit write error, ret = %d\n", ret);
+
+ return ret;
+}
+
+int mc34708_reg_write(struct mc34708 *mc_pmic, unsigned int offset, u32 val)
+{
+ BUG_ON(!mutex_is_locked(&mc_pmic->lock));
+
+ if (offset > MC34708_NUMREGS)
+ return -EINVAL;
+
+ if (mc34708_i2c_24bit_write(mc_pmic->i2c_client, offset, val))
+ return -1;
+ val &= 0xffffff;
+
+ dev_vdbg(&mc_pmic->i2c_client->dev, "mc_pmic write[%02d] -> 0x%06x\n",
+ offset, val);
+
+ return 0;
+}
+EXPORT_SYMBOL(mc34708_reg_write);
+
+int mc34708_reg_rmw(struct mc34708 *mc_pmic, unsigned int offset, u32 mask,
+ u32 val)
+{
+ int ret;
+ u32 valread;
+
+ BUG_ON(val & ~mask);
+
+ ret = mc34708_reg_read(mc_pmic, offset, &valread);
+ if (ret)
+ return ret;
+
+ valread = (valread & ~mask) | val;
+
+ return mc34708_reg_write(mc_pmic, offset, valread);
+}
+EXPORT_SYMBOL(mc34708_reg_rmw);
+
+int mc34708_irq_mask(struct mc34708 *mc_pmic, int irq)
+{
+ int ret;
+ unsigned int offmask =
+ irq < 24 ? MC34708_REG_INT_MASK0 : MC34708_REG_INT_MASK1;
+ u32 irqbit = 1 << (irq < 24 ? irq : irq - 24);
+ u32 mask;
+
+ if (irq < 0 || irq >= MC34708_NUM_IRQ)
+ return -EINVAL;
+
+ ret = mc34708_reg_read(mc_pmic, offmask, &mask);
+ if (ret)
+ return ret;
+
+ if (mask & irqbit)
+ /* already masked */
+ return 0;
+
+ return mc34708_reg_write(mc_pmic, offmask, mask | irqbit);
+}
+EXPORT_SYMBOL(mc34708_irq_mask);
+
+int mc34708_irq_unmask(struct mc34708 *mc_pmic, int irq)
+{
+ int ret;
+ unsigned int offmask =
+ irq < 24 ? MC34708_REG_INT_MASK0 : MC34708_REG_INT_MASK1;
+ u32 irqbit = 1 << (irq < 24 ? irq : irq - 24);
+ u32 mask;
+
+ if (irq < 0 || irq >= MC34708_NUM_IRQ)
+ return -EINVAL;
+
+ ret = mc34708_reg_read(mc_pmic, offmask, &mask);
+ if (ret)
+ return ret;
+
+ if (!(mask & irqbit))
+ /* already unmasked */
+ return 0;
+
+ return mc34708_reg_write(mc_pmic, offmask, mask & ~irqbit);
+}
+EXPORT_SYMBOL(mc34708_irq_unmask);
+
+int mc34708_irq_status(struct mc34708 *mc_pmic, int irq, int *enabled,
+ int *pending)
+{
+ int ret;
+ unsigned int offmask =
+ irq < 24 ? MC34708_REG_INT_MASK0 : MC34708_REG_INT_MASK1;
+ unsigned int offstat =
+ irq < 24 ? MC34708_REG_INT_STATUS0 : MC34708_REG_INT_STATUS1;
+ u32 irqbit = 1 << (irq < 24 ? irq : irq - 24);
+
+ if (irq < 0 || irq >= MC34708_NUM_IRQ)
+ return -EINVAL;
+
+ if (enabled) {
+ u32 mask;
+
+ ret = mc34708_reg_read(mc_pmic, offmask, &mask);
+ if (ret)
+ return ret;
+
+ *enabled = mask & irqbit;
+ }
+
+ if (pending) {
+ u32 stat;
+
+ ret = mc34708_reg_read(mc_pmic, offstat, &stat);
+ if (ret)
+ return ret;
+
+ *pending = stat & irqbit;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(mc34708_irq_status);
+
+int mc34708_irq_ack(struct mc34708 *mc_pmic, int irq)
+{
+ unsigned int offstat =
+ irq < 24 ? MC34708_REG_INT_STATUS0 : MC34708_REG_INT_STATUS1;
+ unsigned int val = 1 << (irq < 24 ? irq : irq - 24);
+
+ BUG_ON(irq < 0 || irq >= MC34708_NUM_IRQ);
+
+ return mc34708_reg_write(mc_pmic, offstat, val);
+}
+EXPORT_SYMBOL(mc34708_irq_ack);
+
+int mc34708_irq_request_nounmask(struct mc34708 *mc_pmic, int irq,
+ irq_handler_t handler, const char *name,
+ void *dev)
+{
+ BUG_ON(!mutex_is_locked(&mc_pmic->lock));
+ BUG_ON(!handler);
+
+ if (irq < 0 || irq >= MC34708_NUM_IRQ)
+ return -EINVAL;
+
+ if (mc_pmic->irqhandler[irq])
+ return -EBUSY;
+
+ mc_pmic->irqhandler[irq] = handler;
+ mc_pmic->irqdata[irq] = dev;
+
+ return 0;
+}
+EXPORT_SYMBOL(mc34708_irq_request_nounmask);
+
+int mc34708_irq_request(struct mc34708 *mc_pmic, int irq,
+ irq_handler_t handler, const char *name, void *dev)
+{
+ int ret;
+
+ ret = mc34708_irq_request_nounmask(mc_pmic, irq, handler, name, dev);
+ if (ret)
+ return ret;
+
+ ret = mc34708_irq_unmask(mc_pmic, irq);
+ if (ret) {
+ mc_pmic->irqhandler[irq] = NULL;
+ mc_pmic->irqdata[irq] = NULL;
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(mc34708_irq_request);
+
+int mc34708_irq_free(struct mc34708 *mc_pmic, int irq, void *dev)
+{
+ int ret;
+ BUG_ON(!mutex_is_locked(&mc_pmic->lock));
+
+ if (irq < 0 || irq >= MC34708_NUM_IRQ || !mc_pmic->irqhandler[irq] ||
+ mc_pmic->irqdata[irq] != dev)
+ return -EINVAL;
+
+ ret = mc34708_irq_mask(mc_pmic, irq);
+ if (ret)
+ return ret;
+
+ mc_pmic->irqhandler[irq] = NULL;
+ mc_pmic->irqdata[irq] = NULL;
+
+ return 0;
+}
+EXPORT_SYMBOL(mc34708_irq_free);
+
+static inline irqreturn_t mc34708_irqhandler(struct mc34708 *mc_pmic, int irq)
+{
+ return mc_pmic->irqhandler[irq] (irq, mc_pmic->irqdata[irq]);
+}
+
+/*
+ * returns: number of handled irqs or negative error
+ * locking: holds mc_pmic->lock
+ */
+static int mc34708_irq_handle(struct mc34708 *mc_pmic,
+ unsigned int offstat, unsigned int offmask,
+ int baseirq)
+{
+ u32 stat, mask;
+ int ret = mc34708_reg_read(mc_pmic, offstat, &stat);
+ int num_handled = 0;
+
+ if (ret)
+ return ret;
+
+ ret = mc34708_reg_read(mc_pmic, offmask, &mask);
+ if (ret)
+ return ret;
+
+ while (stat & ~mask) {
+ int irq = __ffs(stat & ~mask);
+
+ stat &= ~(1 << irq);
+
+ if (likely(mc_pmic->irqhandler[baseirq + irq])) {
+ irqreturn_t handled;
+
+ handled = mc34708_irqhandler(mc_pmic, baseirq + irq);
+ if (handled == IRQ_HANDLED)
+ num_handled++;
+ } else {
+ dev_err(&mc_pmic->i2c_client->dev,
+ "BUG: irq %u but no handler\n", baseirq + irq);
+
+ mask |= 1 << irq;
+
+ ret = mc34708_reg_write(mc_pmic, offmask, mask);
+ }
+ }
+
+ return num_handled;
+}
+
+static irqreturn_t mc34708_irq_thread(int irq, void *data)
+{
+ struct mc34708 *mc_pmic = data;
+ irqreturn_t ret;
+ int handled = 0;
+
+ mc34708_lock(mc_pmic);
+
+ ret = mc34708_irq_handle(mc_pmic, MC34708_REG_INT_STATUS0,
+ MC34708_REG_INT_MASK0, 0);
+ if (ret > 0)
+ handled = 1;
+
+ ret = mc34708_irq_handle(mc_pmic, MC34708_REG_INT_STATUS1,
+ MC34708_REG_INT_MASK1, 24);
+ if (ret > 0)
+ handled = 1;
+
+ mc34708_unlock(mc_pmic);
+
+ return IRQ_RETVAL(handled);
+}
+
+#define maskval(reg, mask) (((reg) & (mask)) >> __ffs(mask))
+static int mc34708_identify(struct mc34708 *mc_pmic,
+ struct mc34708_version_t *ver)
+{
+ int rev_id = 0;
+ int rev1 = 0;
+ int rev2 = 0;
+ int finid = 0;
+ int icid = 0;
+ int ret;
+ ret = mc34708_reg_read(mc_pmic, MC34708_REG_IDENTIFICATION, &rev_id);
+ if (ret) {
+ dev_dbg(&mc_pmic->i2c_client->dev, "read ID error!%x\n", ret);
+ return ret;
+ }
+ rev1 = (rev_id & 0x018) >> 3;
+ rev2 = (rev_id & 0x007);
+ icid = (rev_id & 0x01C0) >> 6;
+ finid = (rev_id & 0x01E00) >> 9;
+ ver->id = MC_PMIC_ID_MC34708;
+
+ ver->revision = ((rev1 * 10) + rev2);
+ dev_dbg(&mc_pmic->i2c_client->dev,
+ "mc_pmic Rev %d.%d FinVer %x detected\n", rev1, rev2, finid);
+
+ return 0;
+}
+
+static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,
+ const struct i2c_client *client)
+{
+ while (id->name[0]) {
+ if (strcmp(client->name, id->name) == 0)
+ return id;
+ id++;
+ }
+
+ return NULL;
+}
+
+static const struct i2c_device_id *i2c_get_device_id(const struct i2c_client
+ *idev)
+{
+ const struct i2c_driver *idrv = to_i2c_driver(idev->dev.driver);
+
+ return i2c_match_id(idrv->id_table, idev);
+}
+
+static const char *mc34708_get_chipname(struct mc34708 *mc_pmic)
+{
+ const struct i2c_device_id *devid =
+ i2c_get_device_id(mc_pmic->i2c_client);
+
+ if (!devid)
+ return NULL;
+
+ return mc34708_chipname[devid->driver_data];
+}
+
+int mc34708_get_flags(struct mc34708 *mc_pmic)
+{
+ struct mc34708_platform_data *pdata =
+ dev_get_platdata(&mc_pmic->i2c_client->dev);
+
+ return pdata->flags;
+}
+EXPORT_SYMBOL(mc34708_get_flags);
+
+static int mc34708_add_subdevice_pdata(struct mc34708 *mc_pmic,
+ const char *format, void *pdata,
+ size_t pdata_size)
+{
+ char buf[30];
+ const char *name = mc34708_get_chipname(mc_pmic);
+
+ struct mfd_cell cell = {
+ .platform_data = pdata,
+ .pdata_size = pdata_size,
+ };
+
+ /* there is no asnprintf in the kernel :-( */
+ if (snprintf(buf, sizeof(buf), format, name) > sizeof(buf))
+ return -E2BIG;
+
+ cell.name = kmemdup(buf, strlen(buf) + 1, GFP_KERNEL);
+ if (!cell.name)
+ return -ENOMEM;
+
+ return mfd_add_devices(&mc_pmic->i2c_client->dev, -1, &cell, 1, NULL,
+ 0);
+}
+
+static int mc34708_add_subdevice(struct mc34708 *mc_pmic, const char *format)
+{
+ return mc34708_add_subdevice_pdata(mc_pmic, format, NULL, 0);
+}
+
+static int mc34708_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct mc34708 *mc_pmic;
+ struct mc34708_version_t version;
+ struct mc34708_platform_data *pdata = client->dev.platform_data;
+ struct device_node *np = client->dev.of_node;
+ int ret;
+
+ mc_pmic = kzalloc(sizeof(*mc_pmic), GFP_KERNEL);
+ if (!mc_pmic)
+ return -ENOMEM;
+ i2c_set_clientdata(client, mc_pmic);
+ mc_pmic->i2c_client = client;
+
+ mutex_init(&mc_pmic->lock);
+ mc34708_lock(mc_pmic);
+ mc34708_identify(mc_pmic, &version);
+ /* mask all irqs */
+ ret = mc34708_reg_write(mc_pmic, MC34708_REG_INT_MASK0, 0x00ffffff);
+ if (ret)
+ goto err_mask;
+
+ ret = mc34708_reg_write(mc_pmic, MC34708_REG_INT_MASK1, 0x00ffffff);
+ if (ret)
+ goto err_mask;
+
+ ret = request_threaded_irq(client->irq, NULL, mc34708_irq_thread,
+ IRQF_ONESHOT | IRQF_TRIGGER_HIGH, "mc_pmic",
+ mc_pmic);
+
+ if (ret) {
+ err_mask:
+ mc34708_unlock(mc_pmic);
+ dev_set_drvdata(&client->dev, NULL);
+ kfree(mc_pmic);
+ return ret;
+ }
+
+ mc34708_unlock(mc_pmic);
+
+ if (pdata && pdata->flags & MC34708_USE_ADC)
+ mc34708_add_subdevice(mc_pmic, "%s-adc");
+ else if (of_get_property(np, "fsl,mc34708-uses-adc", NULL))
+ mc34708_add_subdevice(mc_pmic, "%s-adc");
+
+
+ if (pdata && pdata->flags & MC34708_USE_REGULATOR) {
+ struct mc34708_regulator_platform_data regulator_pdata = {
+ .num_regulators = pdata->num_regulators,
+ .regulators = pdata->regulators,
+ };
+
+ mc34708_add_subdevice_pdata(mc_pmic, "%s-regulator",
+ &regulator_pdata,
+ sizeof(regulator_pdata));
+ } else if (of_find_node_by_name(np, "regulators")) {
+ mc34708_add_subdevice(mc_pmic, "%s-regulator");
+ }
+
+ if (pdata && pdata->flags & MC34708_USE_RTC)
+ mc34708_add_subdevice(mc_pmic, "%s-rtc");
+ else if (of_get_property(np, "fsl,mc34708-uses-rtc", NULL))
+ mc34708_add_subdevice(mc_pmic, "%s-rtc");
+
+ if (pdata && pdata->flags & MC34708_USE_TOUCHSCREEN)
+ mc34708_add_subdevice(mc_pmic, "%s-ts");
+ else if (of_get_property(np, "fsl,mc34708-uses-ts", NULL))
+ mc34708_add_subdevice(mc_pmic, "%s-ts");
+
+ return 0;
+}
+
+static int __devexit mc34708_remove(struct i2c_client *client)
+{
+ struct mc34708 *mc_pmic = dev_get_drvdata(&client->dev);
+
+ free_irq(mc_pmic->i2c_client->irq, mc_pmic);
+
+ mfd_remove_devices(&client->dev);
+
+ kfree(mc_pmic);
+
+ return 0;
+}
+
+static const struct of_device_id mc34708_dt_ids[] = {
+ { .compatible = "fsl,mc34708" },
+ { /* sentinel */ }
+};
+
+static struct i2c_driver mc34708_driver = {
+ .id_table = mc34708_device_id,
+ .driver = {
+ .name = "mc34708",
+ .owner = THIS_MODULE,
+ .of_match_table = mc34708_dt_ids,
+ },
+ .probe = mc34708_probe,
+ .remove = __devexit_p(mc34708_remove),
+};
+
+static int __init mc34708_init(void)
+{
+ return i2c_add_driver(&mc34708_driver);
+}
+subsys_initcall(mc34708_init);
+
+static void __exit mc34708_exit(void)
+{
+ i2c_del_driver(&mc34708_driver);
+}
+module_exit(mc34708_exit);
+
+MODULE_DESCRIPTION("Core driver for Freescale MC34708 PMIC");
+MODULE_AUTHOR("Robin Gong <B38343@freescale.com>, "
+ "Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 36db5a441eb..84302aa5f7d 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -129,6 +129,13 @@ config REGULATOR_MC13892
Say y here to support the regulators found on the Freescale MC13892
PMIC.
+config REGULATOR_MC34708
+ tristate "Freescale MC34708 regulator driver"
+ depends on MFD_MC34708
+ help
+ Say y here to support the regulators found on the Freescale MC34708
+ PMIC.
+
config REGULATOR_ISL6271A
tristate "Intersil ISL6271A Power regulator"
depends on I2C
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 94b52745e95..435fb6bf558 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -33,6 +33,7 @@ obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o
obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o
+obj-$(CONFIG_REGULATOR_MC34708) += mc34708-regulator.o
obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
diff --git a/drivers/regulator/mc34708-regulator.c b/drivers/regulator/mc34708-regulator.c
new file mode 100644
index 00000000000..d306e6ec1aa
--- /dev/null
+++ b/drivers/regulator/mc34708-regulator.c
@@ -0,0 +1,729 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/mfd/mc34708.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/driver.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/of.h>
+#include "mc34708.h"
+
+static const int mc34708_sw1A[] = {
+ 650000, 662500, 675000, 687500, 700000, 712500,
+ 725000, 737500, 750000, 762500, 775000, 787500,
+ 800000, 812500, 825000, 837500, 850000, 862500,
+ 875000, 887500, 900000, 912500, 925000, 937500,
+ 950000, 962500, 975000, 987500, 1000000, 1012500,
+ 1025000, 1037500, 1050000, 1062500, 1075000, 1087500,
+ 1100000, 1112500, 1125000, 1137500, 1150000, 1162500,
+ 1175000, 1187500, 1200000, 1212500, 1225000, 1237500,
+ 1250000, 1262500, 1275000, 1287500, 1300000, 1312500,
+ 1325000, 1337500, 1350000, 1362500, 1375000, 1387500,
+ 1400000, 1412500, 1425000, 1437500,
+};
+
+
+static const int mc34708_sw2[] = {
+ 650000, 662500, 675000, 687500, 700000, 712500,
+ 725000, 737500, 750000, 762500, 775000, 787500,
+ 800000, 812500, 825000, 837500, 850000, 862500,
+ 875000, 887500, 900000, 912500, 925000, 937500,
+ 950000, 962500, 975000, 987500, 1000000, 1012500,
+ 1025000, 1037500, 1050000, 1062500, 1075000, 1087500,
+ 1100000, 1112500, 1125000, 1137500, 1150000, 1162500,
+ 1175000, 1187500, 1200000, 1212500, 1225000, 1237500,
+ 1250000, 1262500, 1275000, 1287500, 1300000, 1312500,
+ 1325000, 1337500, 1350000, 1362500, 1375000, 1387500,
+ 1400000, 1412500, 1425000, 1437500,
+};
+
+static const int mc34708_sw3[] = {
+ 650000, 675000, 700000, 725000, 750000, 775000,
+ 800000, 825000, 850000, 875000, 900000, 925000,
+ 950000, 975000, 1000000, 1025000, 1050000, 1075000,
+ 1100000, 1125000, 1150000, 1175000, 1200000, 1225000,
+ 1250000, 1275000, 1300000, 1325000, 1350000, 1375000,
+ 1400000, 1425000,
+};
+
+static const int mc34708_sw4A[] = {
+ 1200000, 1225000, 1250000, 1275000, 1300000, 1325000,
+ 1350000, 1375000, 1400000, 1425000, 1450000, 1475000,
+ 1500000, 1525000, 1550000, 1575000, 1600000, 1625000,
+ 1650000, 1675000, 1700000, 1725000, 1750000, 1775000,
+ 1800000, 1825000, 1850000, 2500000, 3150000,
+};
+
+
+static const int mc34708_sw5[] = {
+ 1200000, 1225000, 1250000, 1275000, 1300000, 1325000,
+ 1350000, 1375000, 1400000, 1425000, 1450000, 1475000,
+ 1500000, 1525000, 1550000, 1575000, 1600000, 1625000,
+ 1650000, 1675000, 1700000, 1725000, 1750000, 1775000,
+ 1800000, 1825000, 1850000,
+};
+
+static const int mc34708_swbst[] = {
+ 5000000, 5050000, 5100000, 5150000,
+};
+
+static const int mc34708_vpll[] = {
+ 1200000, 1250000, 1500000, 1800000,
+};
+
+static const int mc34708_vrefddr[] = {
+ 600000,
+};
+
+static const int mc34708_vusb[] = {
+ 3300000,
+};
+
+static const int mc34708_vusb2[] = {
+ 2500000, 2600000, 2750000, 3000000,
+};
+
+static const int mc34708_vdac[] = {
+ 2500000, 2600000, 2750000, 2775000,
+};
+
+static const int mc34708_vgen1[] = {
+ 1200000, 1250000, 1300000, 1350000,
+ 1400000, 1450000, 1500000, 1550000,
+};
+
+static const int mc34708_vgen2[] = {
+ 2500000, 2700000, 2800000, 2900000,
+ 3000000, 3100000, 3150000, 3300000,
+};
+
+static struct regulator_ops mc34708_regulator_ops;
+static struct regulator_ops mc34708_fixed_regulator_ops;
+/* sw regulators need special care due to the "hi bit" */
+static struct regulator_ops mc34708_sw_regulator_ops;
+static struct regulator_ops mc34708_sw4_regulator_ops;
+
+#define MC34708_FIXED_VOL_DEFINE(name, reg, voltages) \
+ MC34708_FIXED_DEFINE(MC34708_, name, reg, voltages, \
+ mc34708_fixed_regulator_ops)
+
+#define MC34708_SW_DEFINE(name, reg, vsel_reg, voltages) \
+ MC34708_DEFINE(MC34708_, name, reg, vsel_reg, voltages, \
+ mc34708_sw_regulator_ops)
+
+#define MC34708_DEFINE_REGU(name, reg, vsel_reg, voltages) \
+ MC34708_DEFINE(MC34708_, name, reg, vsel_reg, voltages, \
+ mc34708_regulator_ops)
+
+#define MC34708_SW4_DEFINE(name, reg, vsel_reg, voltages) \
+ MC34708_DEFINE(MC34708_, name, reg, vsel_reg, voltages, \
+ mc34708_sw4_regulator_ops)
+
+#define MC34708_REVISION 7
+
+#define MC34708_SW1ABVOL 24
+#define MC34708_SW1ABVOL_SW1AVSEL 0
+#define MC34708_SW1ABVOL_SW1AVSEL_M (0x3f<<0)
+#define MC34708_SW1ABVOL_SW1AEN 0
+#define MC34708_SW1ABVOL_SW1BVSEL 0
+#define MC34708_SW1ABVOL_SW1BVSEL_M (0x3f<<0)
+#define MC34708_SW1ABVOL_SW1BEN 0
+
+#define MC34708_SW23VOL 25
+#define MC34708_SW23VOL_SW2VSEL 0
+#define MC34708_SW23VOL_SW2VSEL_M (0x3f<<0)
+#define MC34708_SW23VOL_SW2EN 0
+#define MC34708_SW23VOL_SW3VSEL 12
+#define MC34708_SW23VOL_SW3VSEL_M (0x3f<<12)
+#define MC34708_SW23VOL_SW3EN 0
+
+#define MC34708_SW4ABVOL 26
+#define MC34708_SW4ABVOL_SW4AVSEL 0
+#define MC34708_SW4ABVOL_SW4AVSEL_M (0x1f<<0)
+#define MC34708_SW4ABVOL_SW4AHI 10
+#define MC34708_SW4ABVOL_SW4AHI_M (0x3<<10)
+#define MC34708_SW4ABVOL_SW4AEN 0
+#define MC34708_SW4ABVOL_SW4BVSEL 12
+#define MC34708_SW4ABVOL_SW4BVSEL_M (0x1f<<12)
+#define MC34708_SW4ABVOL_SW4BHI 22
+#define MC34708_SW4ABVOL_SW4BHI_M (0x3<<22)
+#define MC34708_SW4ABVOL_SW4BEN 0
+
+#define MC34708_SW5VOL 27
+#define MC34708_SW5VOL_SW5VSEL 0
+#define MC34708_SW5VOL_SW5VSEL_M (0x1f<<0)
+#define MC34708_SW5VOL_SW5EN 0
+
+#define MC34708_SW12OP 28
+#define MC34708_SW12OP_SW1AMODE_M (0xf<<0)
+#define MC34708_SW12OP_SW1AMODE_VALUE (0xc<<0) /*Normal:APS,Standby:PFM */
+#define MC34708_SW12OP_SW2MODE_M (0xf<<14)
+#define MC34708_SW12OP_SW2MODE_VALUE (0xc<<14) /*Normal:APS,Standby:PFM */
+
+#define MC34708_SW345OP 29
+#define MC34708_SW345OP_SW3MODE_M (0xf<<0)
+#define MC34708_SW345OP_SW3MODE_VALUE (0x0<<0) /*Normal:OFF,Standby:OFF */
+#define MC34708_SW345OP_SW4AMODE_M (0xf<<6)
+#define MC34708_SW345OP_SW4AMODE_VALUE (0xc<<6) /*Normal:APS,Standby:PFM */
+#define MC34708_SW345OP_SW4BMODE_M (0xf<<12)
+#define MC34708_SW345OP_SW4BMODE_VALUE (0xc<<12) /*Normal:APS,Standby:PFM */
+#define MC34708_SW345OP_SW5MODE_M (0xf<<18)
+#define MC34708_SW345OP_SW5MODE_VALUE (0xc<<18) /*Normal:APS,Standby:PFM */
+
+#define MC34708_REGULATORSET0 30
+#define MC34708_REGULATORSET0_VGEN1VSEL 0
+#define MC34708_REGULATORSET0_VGEN1VSEL_M (0x7<<0)
+#define MC34708_REGULATORSET0_VDACVSEL 4
+#define MC34708_REGULATORSET0_VDACVSEL_M (0x3<<4)
+#define MC34708_REGULATORSET0_VGEN2VSEL 6
+#define MC34708_REGULATORSET0_VGEN2VSEL_M (0x7<<6)
+#define MC34708_REGULATORSET0_VPLLVSEL 9
+#define MC34708_REGULATORSET0_VPLLVSEL_M (0x3<<9)
+#define MC34708_REGULATORSET0_VUSB2VSEL 11
+#define MC34708_REGULATORSET0_VUSB2VSEL_M (0x3<<9)
+
+#define MC34708_SWBSTCONTROL 31
+#define MC34708_SWBSTCONTROL_SWBSTVSEL 0
+#define MC34708_SWBSTCONTROL_SWBSTVSEL_M (0x3<<0)
+#define MC34708_SWBSTCONTROL_SWBSTMODE_M (0x3<<5)
+#define MC34708_SWBSTCONTROL_SWBSTMODE_VALUE (0x2<<5) /*auto mode */
+#define MC34708_SWBSTCONTROL_SWBSTEN 0
+
+#define MC34708_REGULATORMODE0 32
+#define MC34708_REGULATORMODE0_VGEN1EN 0
+#define MC34708_REGULATORMODE0_VUSBEN 3
+#define MC34708_REGULATORMODE0_VDACEN 4
+#define MC34708_REGULATORMODE0_VREFDDREN 10
+#define MC34708_REGULATORMODE0_VGEN2EN 12
+#define MC34708_REGULATORMODE0_VPLLEN 15
+#define MC34708_REGULATORMODE0_VUSB2EN 18
+
+#define MC34708_USBCONTROL 39
+#define MC34708_USBCONTROL_SWHOLD_M (0x1<<12)
+#define MC34708_USBCONTROL_SWHOLD_NORM (0x0<<12)
+
+static struct mc34708_regulator mc34708_regulators[] = {
+ MC34708_SW_DEFINE(SW1A, SW1ABVOL, SW1ABVOL, mc34708_sw1A),
+ MC34708_SW_DEFINE(SW1B, SW1ABVOL, SW1ABVOL, mc34708_sw1A),
+ MC34708_SW_DEFINE(SW2, SW23VOL, SW23VOL, mc34708_sw2),
+ MC34708_SW_DEFINE(SW3, SW23VOL, SW23VOL, mc34708_sw3),
+ MC34708_SW4_DEFINE(SW4A, SW4ABVOL, SW4ABVOL, mc34708_sw4A),
+ MC34708_SW4_DEFINE(SW4B, SW4ABVOL, SW4ABVOL, mc34708_sw4A),
+ MC34708_SW_DEFINE(SW5, SW5VOL, SW5VOL, mc34708_sw5),
+ MC34708_SW_DEFINE(SWBST, SWBSTCONTROL, SWBSTCONTROL, mc34708_swbst),
+ MC34708_DEFINE_REGU(VPLL, REGULATORMODE0, REGULATORSET0, mc34708_vpll),
+ MC34708_FIXED_VOL_DEFINE(VREFDDR, REGULATORMODE0, mc34708_vrefddr),
+ MC34708_FIXED_VOL_DEFINE(VUSB, REGULATORMODE0, mc34708_vusb),
+ MC34708_DEFINE_REGU(VUSB2, REGULATORMODE0, REGULATORSET0,
+ mc34708_vusb2),
+ MC34708_DEFINE_REGU(VDAC, REGULATORMODE0, REGULATORSET0, mc34708_vdac),
+ MC34708_DEFINE_REGU(VGEN1, REGULATORMODE0, REGULATORSET0,
+ mc34708_vgen1),
+ MC34708_DEFINE_REGU(VGEN2, REGULATORMODE0, REGULATORSET0,
+ mc34708_vgen2),
+};
+
+static int mc34708_regulator_enable(struct regulator_dev *rdev)
+{
+ struct mc34708_regulator_priv *priv = rdev_get_drvdata(rdev);
+ struct mc34708_regulator *mc34708_regulators = priv->mc34708_regulators;
+ int id = rdev_get_id(rdev);
+ int ret;
+
+ dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
+
+ mc34708_lock(priv->mc34708);
+ ret = mc34708_reg_rmw(priv->mc34708, mc34708_regulators[id].reg,
+ mc34708_regulators[id].enable_bit,
+ mc34708_regulators[id].enable_bit);
+ mc34708_unlock(priv->mc34708);
+
+ return ret;
+}
+
+static int mc34708_regulator_disable(struct regulator_dev *rdev)
+{
+ struct mc34708_regulator_priv *priv = rdev_get_drvdata(rdev);
+ struct mc34708_regulator *mc34708_regulators = priv->mc34708_regulators;
+ int id = rdev_get_id(rdev);
+ int ret;
+
+ dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
+
+ mc34708_lock(priv->mc34708);
+ ret = mc34708_reg_rmw(priv->mc34708, mc34708_regulators[id].reg,
+ mc34708_regulators[id].enable_bit, 0);
+ mc34708_unlock(priv->mc34708);
+
+ return ret;
+}
+
+static int mc34708_regulator_is_enabled(struct regulator_dev *rdev)
+{
+ struct mc34708_regulator_priv *priv = rdev_get_drvdata(rdev);
+ struct mc34708_regulator *mc34708_regulators = priv->mc34708_regulators;
+ int ret, id = rdev_get_id(rdev);
+ unsigned int val;
+
+ mc34708_lock(priv->mc34708);
+ ret = mc34708_reg_read(priv->mc34708, mc34708_regulators[id].reg, &val);
+ mc34708_unlock(priv->mc34708);
+
+ if (ret)
+ return ret;
+
+ return (val & mc34708_regulators[id].enable_bit) != 0;
+}
+
+int
+mc34708_regulator_list_voltage(struct regulator_dev *rdev, unsigned selector)
+{
+ int id = rdev_get_id(rdev);
+ struct mc34708_regulator_priv *priv = rdev_get_drvdata(rdev);
+ struct mc34708_regulator *mc34708_regulators = priv->mc34708_regulators;
+
+ if (selector >= mc34708_regulators[id].desc.n_voltages)
+ return -EINVAL;
+
+ return mc34708_regulators[id].voltages[selector];
+}
+EXPORT_SYMBOL_GPL(mc34708_regulator_list_voltage);
+
+int
+mc34708_get_best_voltage_index(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ struct mc34708_regulator_priv *priv = rdev_get_drvdata(rdev);
+ struct mc34708_regulator *mc34708_regulators = priv->mc34708_regulators;
+ int reg_id = rdev_get_id(rdev);
+ int i;
+ int bestmatch;
+ int bestindex;
+
+ /*
+ * Locate the minimum voltage fitting the criteria on
+ * this regulator. The switchable voltages are not
+ * in strict falling order so we need to check them
+ * all for the best match.
+ */
+ bestmatch = INT_MAX;
+ bestindex = -1;
+ for (i = 0; i < mc34708_regulators[reg_id].desc.n_voltages; i++) {
+ if (mc34708_regulators[reg_id].voltages[i] >= min_uV &&
+ mc34708_regulators[reg_id].voltages[i] < bestmatch) {
+ bestmatch = mc34708_regulators[reg_id].voltages[i];
+ bestindex = i;
+ }
+ }
+
+ if (bestindex < 0 || bestmatch > max_uV) {
+ dev_warn(&rdev->dev, "no possible value for %d<=x<=%d uV\n",
+ min_uV, max_uV);
+ return -EINVAL;
+ }
+ return bestindex;
+}
+EXPORT_SYMBOL_GPL(mc34708_get_best_voltage_index);
+
+static int
+mc34708_regulator_set_voltage(struct regulator_dev *rdev, int min_uV,
+ int max_uV, unsigned *selector)
+{
+ struct mc34708_regulator_priv *priv = rdev_get_drvdata(rdev);
+ struct mc34708_regulator *mc34708_regulators = priv->mc34708_regulators;
+ int value, id = rdev_get_id(rdev);
+ int ret;
+
+ dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n",
+ __func__, id, min_uV, max_uV);
+
+ /* Find the best index */
+ value = mc34708_get_best_voltage_index(rdev, min_uV, max_uV);
+ dev_dbg(rdev_get_dev(rdev), "%s best value: %d\n", __func__, value);
+ if (value < 0)
+ return value;
+
+ mc34708_lock(priv->mc34708);
+ ret = mc34708_reg_rmw(priv->mc34708, mc34708_regulators[id].vsel_reg,
+ mc34708_regulators[id].vsel_mask,
+ value << mc34708_regulators[id].vsel_shift);
+ mc34708_unlock(priv->mc34708);
+
+ return ret;
+}
+
+static int mc34708_regulator_get_voltage(struct regulator_dev *rdev)
+{
+ struct mc34708_regulator_priv *priv = rdev_get_drvdata(rdev);
+ struct mc34708_regulator *mc34708_regulators = priv->mc34708_regulators;
+ int ret, id = rdev_get_id(rdev);
+ unsigned int val;
+
+ dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
+
+ mc34708_lock(priv->mc34708);
+ ret = mc34708_reg_read(priv->mc34708,
+ mc34708_regulators[id].vsel_reg, &val);
+ mc34708_unlock(priv->mc34708);
+
+ if (ret)
+ return ret;
+
+ val = (val & mc34708_regulators[id].vsel_mask)
+ >> mc34708_regulators[id].vsel_shift;
+
+ dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val);
+
+ BUG_ON(val > mc34708_regulators[id].desc.n_voltages);
+
+ return mc34708_regulators[id].voltages[val];
+}
+
+static struct regulator_ops mc34708_regulator_ops = {
+ .enable = mc34708_regulator_enable,
+ .disable = mc34708_regulator_disable,
+ .is_enabled = mc34708_regulator_is_enabled,
+ .list_voltage = mc34708_regulator_list_voltage,
+ .set_voltage = mc34708_regulator_set_voltage,
+ .get_voltage = mc34708_regulator_get_voltage,
+};
+EXPORT_SYMBOL_GPL(mc34708_regulator_ops);
+
+int
+mc34708_fixed_regulator_set_voltage(struct regulator_dev *rdev, int min_uV,
+ int max_uV, unsigned *selector)
+{
+ struct mc34708_regulator_priv *priv = rdev_get_drvdata(rdev);
+ struct mc34708_regulator *mc34708_regulators = priv->mc34708_regulators;
+ int id = rdev_get_id(rdev);
+
+ dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n",
+ __func__, id, min_uV, max_uV);
+
+ if (min_uV >= mc34708_regulators[id].voltages[0] &&
+ max_uV <= mc34708_regulators[id].voltages[0])
+ return 0;
+ else
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(mc34708_fixed_regulator_set_voltage);
+
+int mc34708_fixed_regulator_get_voltage(struct regulator_dev *rdev)
+{
+ struct mc34708_regulator_priv *priv = rdev_get_drvdata(rdev);
+ struct mc34708_regulator *mc34708_regulators = priv->mc34708_regulators;
+ int id = rdev_get_id(rdev);
+
+ dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
+
+ return mc34708_regulators[id].voltages[0];
+}
+EXPORT_SYMBOL_GPL(mc34708_fixed_regulator_get_voltage);
+
+static struct regulator_ops mc34708_fixed_regulator_ops = {
+ .enable = mc34708_regulator_enable,
+ .disable = mc34708_regulator_disable,
+ .is_enabled = mc34708_regulator_is_enabled,
+ .list_voltage = mc34708_regulator_list_voltage,
+ .set_voltage = mc34708_fixed_regulator_set_voltage,
+ .get_voltage = mc34708_fixed_regulator_get_voltage,
+};
+EXPORT_SYMBOL_GPL(mc34708_fixed_regulator_ops);
+
+int mc34708_sw_regulator_is_enabled(struct regulator_dev *rdev)
+{
+ return 1;
+}
+EXPORT_SYMBOL_GPL(mc34708_sw_regulator_is_enabled);
+
+static int mc34708_sw4_regulator_get_voltage(struct regulator_dev *rdev)
+{
+ struct mc34708_regulator_priv *priv = rdev_get_drvdata(rdev);
+ struct mc34708_regulator *mc34708_regulators = priv->mc34708_regulators;
+ int ret, id = rdev_get_id(rdev);
+ unsigned int val, hi;
+
+ dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
+
+ mc34708_lock(priv->mc34708);
+ ret = mc34708_reg_read(priv->mc34708,
+ mc34708_regulators[id].vsel_reg, &val);
+ mc34708_unlock(priv->mc34708);
+
+ if (ret)
+ return ret;
+ hi = (val & MC34708_SW4ABVOL_SW4BHI_M) >> MC34708_SW4ABVOL_SW4BHI;
+ val = (val & mc34708_regulators[id].vsel_mask)
+ >> mc34708_regulators[id].vsel_shift;
+ dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val);
+
+ if (hi == 0x1) /*2500000 */
+ val = 27;
+ else if (hi == 0x2) /*3150000 */
+ val = 28;
+
+ return mc34708_regulators[id].voltages[val];
+}
+
+static int
+mc34708_sw4_regulator_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV, unsigned *selector)
+{
+ struct mc34708_regulator_priv *priv = rdev_get_drvdata(rdev);
+ struct mc34708_regulator *mc34708_regulators = priv->mc34708_regulators;
+ int value, id = rdev_get_id(rdev);
+ int ret, hi;
+
+ dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n",
+ __func__, id, min_uV, max_uV);
+
+ /* Find the best index */
+ value = mc34708_get_best_voltage_index(rdev, min_uV, max_uV);
+ dev_dbg(rdev_get_dev(rdev), "%s best value: %d\n", __func__, value);
+ if (value < 0)
+ return value;
+ if (value <= 26)
+ hi = 0x0;
+ else if (value == 27)
+ hi = 0x1;
+ else
+ hi = 0x2;
+ mc34708_lock(priv->mc34708);
+ ret = mc34708_reg_rmw(priv->mc34708, mc34708_regulators[id].vsel_reg,
+ mc34708_regulators[id].vsel_mask |
+ MC34708_SW4ABVOL_SW4BHI_M,
+ value << mc34708_regulators[id].vsel_shift |
+ (hi << MC34708_SW4ABVOL_SW4BHI));
+ mc34708_unlock(priv->mc34708);
+
+ return ret;
+}
+
+static struct regulator_ops mc34708_sw4_regulator_ops = {
+ .is_enabled = mc34708_sw_regulator_is_enabled,
+ .list_voltage = mc34708_regulator_list_voltage,
+ .set_voltage = mc34708_sw4_regulator_set_voltage,
+ .get_voltage = mc34708_sw4_regulator_get_voltage,
+};
+
+static struct regulator_ops mc34708_sw_regulator_ops = {
+ .is_enabled = mc34708_sw_regulator_is_enabled,
+ .list_voltage = mc34708_regulator_list_voltage,
+ .set_voltage = mc34708_regulator_set_voltage,
+ .get_voltage = mc34708_regulator_get_voltage,
+};
+
+static struct mc34708_regulator_platform_data *
+mc34708_get_pdata_from_dt(struct platform_device *pdev)
+{
+ struct mc34708_regulator_platform_data *pdata;
+ struct device_node *nproot = pdev->dev.parent->of_node;
+ struct device_node *np;
+ int i, j;
+
+ if (!nproot)
+ return ERR_PTR(-ENODEV);
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(&pdev->dev, "cannot allocate memory for pdata\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ nproot = of_find_node_by_name(nproot, "regulators");
+ if (!nproot)
+ return pdata;
+
+ for (np = of_get_next_child(nproot, NULL); np;
+ np = of_get_next_child(nproot, np)) {
+ pdata->num_regulators++;
+ }
+ pdata->regulators = devm_kzalloc(&pdev->dev,
+ sizeof(*pdata->regulators) * pdata->num_regulators,
+ GFP_KERNEL);
+ if (!pdata->regulators) {
+ dev_err(&pdev->dev, "cannot allocate memory for regulators\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ j = 0;
+ for (np = of_get_next_child(nproot, NULL); np;
+ np = of_get_next_child(nproot, np)) {
+ for (i = 0; i < ARRAY_SIZE(mc34708_regulators); i++) {
+ if (!of_node_cmp(np->name,
+ mc34708_regulators[i].desc.name)) {
+ pdata->regulators[j].id = i;
+ pdata->regulators[j].init_data =
+ of_get_regulator_init_data(&pdev->dev,
+ np);
+ j++;
+ break;
+ }
+ }
+ if (i >= ARRAY_SIZE(mc34708_regulators))
+ dev_warn(&pdev->dev, "can't find regulator %s\n",
+ np->name);
+ }
+ pdata->num_regulators = j;
+
+ return pdata;
+}
+
+static int __devinit mc34708_regulator_probe(struct platform_device *pdev)
+{
+ struct mc34708_regulator_priv *priv;
+ struct mc34708 *mc34708 = dev_get_drvdata(pdev->dev.parent);
+ struct mc34708_regulator_platform_data *pdata =
+ dev_get_platdata(&pdev->dev);
+ struct mc34708_regulator_init_data *init_data;
+ int i, ret;
+ u32 val = 0;
+
+ if (!pdata) {
+ pdata = mc34708_get_pdata_from_dt(pdev);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+ }
+
+ priv = kzalloc(sizeof(*priv) +
+ pdata->num_regulators * sizeof(priv->regulators[0]),
+ GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->mc34708_regulators = mc34708_regulators;
+ priv->mc34708 = mc34708;
+
+ mc34708_lock(mc34708);
+ ret = mc34708_reg_read(mc34708, MC34708_REVISION, &val);
+ if (ret)
+ goto err_free;
+
+ ret = mc34708_reg_rmw(mc34708, MC34708_SW12OP,
+ MC34708_SW12OP_SW1AMODE_M |
+ MC34708_SW12OP_SW2MODE_M,
+ MC34708_SW12OP_SW1AMODE_VALUE |
+ MC34708_SW12OP_SW2MODE_VALUE);
+ if (ret)
+ goto err_free;
+
+ ret = mc34708_reg_rmw(mc34708, MC34708_SW345OP,
+ MC34708_SW345OP_SW3MODE_M |
+ MC34708_SW345OP_SW4AMODE_M |
+ MC34708_SW345OP_SW4BMODE_M |
+ MC34708_SW345OP_SW5MODE_M,
+ MC34708_SW345OP_SW3MODE_VALUE |
+ MC34708_SW345OP_SW4AMODE_VALUE |
+ MC34708_SW345OP_SW4BMODE_VALUE |
+ MC34708_SW345OP_SW5MODE_VALUE);
+ if (ret)
+ goto err_free;
+
+ ret = mc34708_reg_rmw(mc34708, MC34708_SWBSTCONTROL,
+ MC34708_SWBSTCONTROL_SWBSTMODE_M,
+ MC34708_SWBSTCONTROL_SWBSTMODE_VALUE);
+ if (ret)
+ goto err_free;
+
+ ret = mc34708_reg_rmw(mc34708, MC34708_USBCONTROL,
+ MC34708_USBCONTROL_SWHOLD_M,
+ MC34708_USBCONTROL_SWHOLD_NORM);
+ if (ret)
+ goto err_free;
+
+ mc34708_unlock(mc34708);
+ dev_dbg(&pdev->dev, "PMIC MC34708 ID:0x%x\n", val);
+
+ for (i = 0; i < pdata->num_regulators; i++) {
+ init_data = &pdata->regulators[i];
+ priv->regulators[i] =
+ regulator_register(
+ &mc34708_regulators[init_data->id].desc,
+ &pdev->dev, init_data->init_data, priv,
+ NULL);
+
+ if (IS_ERR(priv->regulators[i])) {
+ dev_err(&pdev->dev, "fail to register regulator %s\n",
+ mc34708_regulators[i].desc.name);
+ ret = PTR_ERR(priv->regulators[i]);
+ goto err;
+ }
+ }
+
+ platform_set_drvdata(pdev, priv);
+
+ return 0;
+ err:
+ while (--i >= 0)
+ regulator_unregister(priv->regulators[i]);
+
+ err_free:
+ mc34708_unlock(mc34708);
+ kfree(priv);
+
+ return ret;
+}
+
+static int __devexit mc34708_regulator_remove(struct platform_device *pdev)
+{
+ struct mc34708_regulator_priv *priv = platform_get_drvdata(pdev);
+ struct mc34708_regulator_platform_data *pdata =
+ dev_get_platdata(&pdev->dev);
+ int i;
+
+ platform_set_drvdata(pdev, NULL);
+
+ for (i = 0; i < pdata->num_regulators; i++)
+ regulator_unregister(priv->regulators[i]);
+
+ kfree(priv);
+ return 0;
+}
+
+static struct platform_driver mc34708_regulator_driver = {
+ .driver = {
+ .name = "mc34708-regulator",
+ .owner = THIS_MODULE,
+ },
+ .remove = __devexit_p(mc34708_regulator_remove),
+ .probe = mc34708_regulator_probe,
+};
+
+static int __init mc34708_regulator_init(void)
+{
+ return platform_driver_register(&mc34708_regulator_driver);
+}
+subsys_initcall(mc34708_regulator_init);
+
+static void __exit mc34708_regulator_exit(void)
+{
+ platform_driver_unregister(&mc34708_regulator_driver);
+}
+module_exit(mc34708_regulator_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Robin Gong <B38343@freescale.com>, "
+ "Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>");
+MODULE_DESCRIPTION("Regulator Driver for Freescale MC34708 PMIC");
+MODULE_ALIAS("platform:mc34708-regulator");
diff --git a/drivers/regulator/mc34708.h b/drivers/regulator/mc34708.h
new file mode 100644
index 00000000000..f765086863f
--- /dev/null
+++ b/drivers/regulator/mc34708.h
@@ -0,0 +1,79 @@
+/*
+ * mc34708.h - regulators for the Freescale mc34708 PMIC
+ * Copyright (C) 2004-2011 Freescale Semiconductor, Inc.
+ * based on:
+ * Copyright (C) 2010 Yong Shen <yong.shen@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __LINUX_REGULATOR_MC34708_H
+#define __LINUX_REGULATOR_MC34708_H
+
+#include <linux/regulator/driver.h>
+
+struct mc34708_regulator {
+ struct regulator_desc desc;
+ int reg;
+ int enable_bit;
+ int vsel_reg;
+ int vsel_shift;
+ int vsel_mask;
+ int hi_bit;
+ int const *voltages;
+};
+
+struct mc34708_regulator_priv {
+ struct mc34708 *mc34708;
+ struct mc34708_regulator *mc34708_regulators;
+ struct regulator_dev *regulators[];
+};
+
+int mc34708_sw_regulator(struct regulator_dev *rdev);
+int mc34708_sw_regulator_is_enabled(struct regulator_dev *rdev);
+int mc34708_get_best_voltage_index(struct regulator_dev *rdev,
+ int min_uV, int max_uV);
+int mc34708_regulator_list_voltage(struct regulator_dev *rdev,
+ unsigned selector);
+int mc34708_fixed_regulator_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV,
+ unsigned *selector);
+int mc34708_fixed_regulator_get_voltage(struct regulator_dev *rdev);
+
+#define MC34708_DEFINE(prefix, _name, _reg, _vsel_reg, _voltages, _ops) \
+ [prefix ## _name] = { \
+ .desc = { \
+ .name = #prefix "_" #_name, \
+ .n_voltages = ARRAY_SIZE(_voltages), \
+ .ops = &_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = prefix ## _name, \
+ .owner = THIS_MODULE, \
+ }, \
+ .reg = prefix ## _reg, \
+ .enable_bit = prefix ## _reg ## _ ## _name ## EN, \
+ .vsel_reg = prefix ## _vsel_reg, \
+ .vsel_shift = prefix ## _vsel_reg ## _ ## _name ## VSEL,\
+ .vsel_mask = prefix ## _vsel_reg ## _ ## _name ## VSEL_M,\
+ .voltages = _voltages, \
+ }
+
+#define MC34708_FIXED_DEFINE(prefix, _name, _reg, _voltages, _ops) \
+ [prefix ## _name] = { \
+ .desc = { \
+ .name = #prefix "_" #_name, \
+ .n_voltages = ARRAY_SIZE(_voltages), \
+ .ops = &_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = prefix ## _name, \
+ .owner = THIS_MODULE, \
+ }, \
+ .reg = prefix ## _reg, \
+ .enable_bit = prefix ## _reg ## _ ## _name ## EN, \
+ .voltages = _voltages, \
+ }
+
+#endif
diff --git a/include/linux/mfd/mc34708.h b/include/linux/mfd/mc34708.h
new file mode 100644
index 00000000000..505813d5d64
--- /dev/null
+++ b/include/linux/mfd/mc34708.h
@@ -0,0 +1,134 @@
+/* For mc34708's pmic driver
+ * Copyright (C) 2004-2011 Freescale Semiconductor, Inc.
+ *
+ * based on:
+ * Copyright 2009-2010 Pengutronix, Uwe Kleine-Koenig
+ * <u.kleine-koenig@pengutronix.de>
+ *
+ * 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_MC_34708_H
+#define __LINUX_MFD_MC_34708_H
+
+#include <linux/interrupt.h>
+#include <linux/regulator/driver.h>
+
+struct mc34708;
+
+void mc34708_lock(struct mc34708 *mc_pmic);
+void mc34708_unlock(struct mc34708 *mc_pmic);
+
+int mc34708_reg_read(struct mc34708 *mc_pmic, unsigned int offset, u32 *val);
+int mc34708_reg_write(struct mc34708 *mc_pmic, unsigned int offset, u32 val);
+int mc34708_reg_rmw(struct mc34708 *mc_pmic, unsigned int offset,
+ u32 mask, u32 val);
+
+int mc34708_get_flags(struct mc34708 *mc_pmic);
+
+int mc34708_irq_request(struct mc34708 *mc_pmic, int irq,
+ irq_handler_t handler, const char *name, void *dev);
+int mc34708_irq_request_nounmask(struct mc34708 *mc_pmic, int irq,
+ irq_handler_t handler, const char *name,
+ void *dev);
+int mc34708_irq_free(struct mc34708 *mc_pmic, int irq, void *dev);
+int mc34708_irq_mask(struct mc34708 *mc_pmic, int irq);
+int mc34708_irq_unmask(struct mc34708 *mc_pmic, int irq);
+int mc34708_irq_status(struct mc34708 *mc_pmic, int irq,
+ int *enabled, int *pending);
+int mc34708_irq_ack(struct mc34708 *mc_pmic, int irq);
+
+int mc34708_get_flags(struct mc34708 *mc_pmic);
+
+#define MC34708_SW1A 0
+#define MC34708_SW1B 1
+#define MC34708_SW2 2
+#define MC34708_SW3 3
+#define MC34708_SW4A 4
+#define MC34708_SW4B 5
+#define MC34708_SW5 6
+#define MC34708_SWBST 7
+#define MC34708_VPLL 8
+#define MC34708_VREFDDR 9
+#define MC34708_VUSB 10
+#define MC34708_VUSB2 11
+#define MC34708_VDAC 12
+#define MC34708_VGEN1 13
+#define MC34708_VGEN2 14
+#define MC34708_REGU_NUM 15
+
+#define MC34708_REG_INT_STATUS0 0
+#define MC34708_REG_INT_MASK0 1
+#define MC34708_REG_INT_STATUS1 3
+#define MC34708_REG_INT_MASK1 4
+#define MC34708_REG_IDENTIFICATION 7
+
+#define MC34708_IRQ_ADCDONE 0
+#define MC34708_IRQ_TSDONE 1
+#define MC34708_IRQ_TSPENDET 2
+#define MC34708_IRQ_USBDET 3
+#define MC34708_IRQ_AUXDET 4
+#define MC34708_IRQ_USBOVP 5
+#define MC34708_IRQ_AUXOVP 6
+#define MC34708_IRQ_CHRTIMEEXP 7
+#define MC34708_IRQ_BATTOTP 8
+#define MC34708_IRQ_BATTOVP 9
+#define MC34708_IRQ_CHRCMPL 10
+#define MC34708_IRQ_WKVBUSDET 11
+#define MC34708_IRQ_WKAUXDET 12
+#define MC34708_IRQ_LOWBATT 13
+#define MC34708_IRQ_VBUSREGMI 14
+#define MC34708_IRQ_ATTACH 15
+#define MC34708_IRQ_DETACH 16
+#define MC34708_IRQ_KP 17
+#define MC34708_IRQ_LKP 18
+#define MC34708_IRQ_LKR 19
+#define MC34708_IRQ_UKNOW_ATTA 20
+#define MC34708_IRQ_ADC_CHANGE 21
+#define MC34708_IRQ_STUCK_KEY 22
+#define MC34708_IRQ_STUCK_KEY_RCV 23
+#define MC34708_IRQ_1HZ 24
+#define MC34708_IRQ_TODA 25
+#define MC34708_IRQ_UNUSED1 26
+#define MC34708_IRQ_PWRON1 27
+#define MC34708_IRQ_PWRON2 28
+#define MC34708_IRQ_WDIRESET 29
+#define MC34708_IRQ_SYSRST 30
+#define MC34708_IRQ_RTCRST 31
+#define MC34708_IRQ_PCI 32
+#define MC34708_IRQ_WARM 33
+#define MC34708_IRQ_MEMHLD 34
+#define MC34708_IRQ_UNUSED2 35
+#define MC34708_IRQ_THWARNL 36
+#define MC34708_IRQ_THWARNH 37
+#define MC34708_IRQ_CLK 38
+#define MC34708_IRQ_UNUSED3 39
+#define MC34708_IRQ_SCP 40
+#define MC34708_NUMREGS 0x3f
+#define MC34708_NUM_IRQ 46
+
+struct mc34708_regulator_init_data {
+ int id;
+ struct regulator_init_data *init_data;
+};
+
+struct mc34708_regulator_platform_data {
+ int num_regulators;
+ struct mc34708_regulator_init_data *regulators;
+};
+
+struct mc34708_platform_data {
+#define MC34708_USE_TOUCHSCREEN (1 << 0)
+#define MC34708_USE_CODEC (1 << 1)
+#define MC34708_USE_ADC (1 << 2)
+#define MC34708_USE_RTC (1 << 3)
+#define MC34708_USE_REGULATOR (1 << 4)
+#define MC34708_USE_LED (1 << 5)
+ unsigned int flags;
+
+ int num_regulators;
+ struct mc34708_regulator_init_data *regulators;
+};
+
+#endif /* ifndef __LINUX_MFD_MC_PMIC_H */