cwz add tps65910 driver
authorubuntu <superboy@ubuntu.(none)>
Mon, 28 Feb 2011 02:19:53 +0000 (18:19 -0800)
committerubuntu <superboy@ubuntu.(none)>
Mon, 28 Feb 2011 02:19:53 +0000 (18:19 -0800)
18 files changed:
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/tps65910-gpio.c [new file with mode: 0644]
drivers/input/misc/Kconfig
drivers/input/misc/Makefile
drivers/input/misc/tps65910-pwrbutton.c [new file with mode: 0644]
drivers/input/touchscreen/eeti_egalax_i2c.c
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/tps65010.c
drivers/mfd/tps65910-core.c [new file with mode: 0644]
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/tps65910-regulator.c [new file with mode: 0644]
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-tps65910.c [new file with mode: 0644]
include/linux/i2c/tps65910.h [new file with mode: 0644]

index 27553305bab0752e016c6303c7dab4b8669c0e13..f6f188669374a1e439966d62925ad28c9663ffa7 100755 (executable)
@@ -155,6 +155,13 @@ config GPIO_TWL4030
          Say yes here to access the GPIO signals of various multi-function
          power management chips from Texas Instruments.
 
+config GPIO_TPS65910
+       bool "TPS65910 GPIOs"
+       depends on TPS65910_CORE
+       help
+         Say yes here to access the GPIO signal of TPS65910x multi-function
+         power management chips from Texas Instruments.
+
 config GPIO_WM831X
        tristate "WM831x GPIOs"
        depends on MFD_WM831X
index dd031a14d055914fd1bbc83965bc94354ae260dd..e0b37e098e76def56fc7e36c9d8a5e47c2f38463 100755 (executable)
@@ -14,6 +14,7 @@ obj-$(CONFIG_GPIO_PCA953X)    += pca953x.o
 obj-$(CONFIG_GPIO_PCF857X)     += pcf857x.o
 obj-$(CONFIG_GPIO_PL061)       += pl061.o
 obj-$(CONFIG_GPIO_TWL4030)     += twl4030-gpio.o
+obj-$(CONFIG_GPIO_TPS65910)    += tps65910-gpio.o
 obj-$(CONFIG_GPIO_UCB1400)     += ucb1400_gpio.o
 obj-$(CONFIG_GPIO_XILINX)      += xilinx_gpio.o
 obj-$(CONFIG_GPIO_BT8XX)       += bt8xxgpio.o
diff --git a/drivers/gpio/tps65910-gpio.c b/drivers/gpio/tps65910-gpio.c
new file mode 100644 (file)
index 0000000..36e1889
--- /dev/null
@@ -0,0 +1,364 @@
+/*
+ * tps65910_gpio.c -- access to GPIOs on TPS65910x chips
+ *
+ * Copyright (C) 2010 Mistral solutions Pvt Ltd <www.mistralsolutions.com>
+ *
+ * Based on twl4030-gpio.c
+ *
+ * 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/init.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <linux/i2c/tps65910.h>
+
+static int gpio_tps65910_remove(struct platform_device *pdev);
+
+/*
+ * The GPIO "subchip" supports 1 GPIOs which can be configured as
+ * inputs or outputs, with pullups or pulldowns on each pin.  Each
+ * GPIO can trigger interrupts on either or both edges.
+ */
+
+
+/* Data structures */
+static struct gpio_chip tps65910_gpiochip;
+static DEFINE_MUTEX(gpio_lock);
+static unsigned int gpio_usage_count;
+static struct work_struct  gpio_work;
+static struct mutex work_lock;
+/*
+ * To configure TPS65910 GPIO registers
+ */
+static inline int gpio_tps65910_write(u8 address, u8 data)
+{
+       return tps65910_i2c_write_u8(TPS65910_I2C_ID0, data, address);
+}
+
+
+/*
+ * To read a TPS65910 GPIO module register
+ */
+static inline int gpio_tps65910_read(u8 address)
+{
+       u8 data;
+       int ret = 0;
+
+       ret = tps65910_i2c_read_u8(TPS65910_I2C_ID0, &data, address);
+       return (ret < 0) ? ret : data;
+}
+
+static int tps65910_request(struct gpio_chip *chip, unsigned offset)
+{
+       int status = 0;
+
+       mutex_lock(&gpio_lock);
+
+       /* initialize TPS65910 GPIO */
+       /* By default the GPIO_CKSYNC signal is GPIO */
+       if (!gpio_usage_count)
+               gpio_usage_count++;
+
+       mutex_unlock(&gpio_lock);
+       return status;
+}
+
+static void tps65910_free(struct gpio_chip *chip, unsigned offset)
+{
+       mutex_lock(&gpio_lock);
+
+       /* on last use, switch off GPIO module */
+       if (!gpio_usage_count)
+               gpio_usage_count--;
+
+       mutex_unlock(&gpio_lock);
+}
+
+static int tps65910_direction_in(struct gpio_chip *chip, unsigned offset)
+{
+       /* Configure TPS65910 GPIO as input */
+       u8 val;
+
+       mutex_lock(&gpio_lock);
+
+       val = gpio_tps65910_read(TPS65910_REG_GPIO0);
+
+       val &= ~(TPS65910_GPIO_CFG_OUTPUT);
+
+       val = gpio_tps65910_read(TPS65910_REG_GPIO0);
+
+       mutex_unlock(&gpio_lock);
+
+       return 0;
+}
+
+static int tps65910_get(struct gpio_chip *chip, unsigned offset)
+{
+       int status = 0;
+
+       mutex_lock(&gpio_lock);
+
+       status = gpio_tps65910_read(TPS65910_REG_GPIO0);
+
+       mutex_unlock(&gpio_lock);
+       if (status & 0x01)
+               return 1;
+       else
+               return 0;
+}
+static
+int tps65910_direction_out(struct gpio_chip *chip, unsigned offset, int value)
+{
+       /* Configure TPS65910 GPIO as input */
+       u8 val;
+       u32 ret;
+       mutex_lock(&gpio_lock);
+       val = gpio_tps65910_read(TPS65910_REG_GPIO0);
+
+       val |= TPS65910_GPIO_CFG_OUTPUT;
+
+       ret = gpio_tps65910_write(TPS65910_REG_GPIO0, val);
+       mutex_unlock(&gpio_lock);
+
+       if (ret != 0)
+               return -EIO;
+       return 0;
+}
+
+static void tps65910_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+       int val = 0;
+       u32 ret;
+
+       mutex_lock(&gpio_lock);
+       val = gpio_tps65910_read(TPS65910_REG_GPIO0);
+
+       if (value == 1)
+               val |= 0x01;
+       else
+               val &= 0xFE;
+
+       ret = gpio_tps65910_write(TPS65910_REG_GPIO0, val);
+
+       mutex_unlock(&gpio_lock);
+}
+
+
+
+static void tps65910_gpio_set_debounce(u8 debounce)
+{
+       u8 val;
+
+       mutex_lock(&gpio_lock);
+
+       val = gpio_tps65910_read(TPS65910_REG_GPIO0);
+
+       if (debounce == TPS65910_DEBOUNCE_91_5_MS)
+               val = (0<<4);
+       else if (debounce == TPS65910_DEBOUNCE_150_MS)
+               val = (1<<4);
+       else
+               printk(KERN_ERR "Invalid argument to %s\n", __func__);
+
+       gpio_tps65910_write(TPS65910_REG_GPIO0, val);
+
+       mutex_unlock(&gpio_lock);
+}
+EXPORT_SYMBOL(tps65910_gpio_set_debounce);
+
+
+static void tps65910_gpio_pullup_enable(void)
+{
+       u8 val;
+       u32 ret;
+
+       mutex_lock(&gpio_lock);
+
+       val = gpio_tps65910_read(TPS65910_REG_GPIO0);
+
+       val = (1<<3);
+
+       ret = gpio_tps65910_write(TPS65910_REG_GPIO0, val);
+
+       mutex_unlock(&gpio_lock);
+
+       if (ret != 0)
+               printk(KERN_ERR "Error writing to TPS65910_REG_GPIO0 in %s \n",
+                               __func__);
+}
+EXPORT_SYMBOL(tps65910_gpio_pullup_enable);
+
+static void tps65910_gpio_pullup_disable(void)
+{
+       u8 val;
+       u32 ret;
+
+       mutex_lock(&gpio_lock);
+
+       val = gpio_tps65910_read(TPS65910_REG_GPIO0);
+
+       val = (0<<3);
+
+       ret = gpio_tps65910_write(TPS65910_REG_GPIO0, val);
+
+       mutex_unlock(&gpio_lock);
+}
+EXPORT_SYMBOL(tps65910_gpio_pullup_disable);
+
+static void tps65910_gpio_work(struct work_struct *work)
+{
+
+       /* Read the status register and take action  */
+       u8 status2;
+       int err;
+       mutex_lock(&work_lock);
+       err =  tps65910_i2c_read_u8(TPS65910_I2C_ID0, &status2,
+                       TPS65910_REG_INT_STS);
+       if (!err) {
+               switch (status2) {
+               case TPS65910_GPIO_F_IT:
+                       printk(KERN_NOTICE "Received TPS65910 GPIO falling \
+                               edge interrupt \n");
+                       /* Clear interrupt */
+                       tps65910_i2c_write_u8(TPS65910_I2C_ID0, status2,
+                                       TPS65910_REG_INT_STS);
+                       /* Add code accroding to board requirment */
+                       break;
+               case TPS65910_GPIO_R_IT:
+                       printk(KERN_NOTICE "Received TPS65910 GPIO Raising \
+                                edge interrupt \n");
+                       /* Clear interrupt */
+                       tps65910_i2c_write_u8(TPS65910_I2C_ID0, status2,
+                                       TPS65910_REG_INT_STS);
+                       /* Add code accroding to board requirment */
+                       break;
+               }
+       } else {
+               printk(KERN_ERR"Could not read TPS65910_REG_INT_STS\n");
+       }
+
+       mutex_unlock(&work_lock);
+
+}
+
+
+
+static irqreturn_t tps65910_gpio_isr(int irq, void *_tps65910)
+{
+       /* Disable IRQ, schedule work, enable IRQ and  acknowledge */
+       disable_irq(irq);
+       (void) schedule_work(&gpio_work);
+       enable_irq(irq);
+       return IRQ_HANDLED;
+}
+
+
+static struct gpio_chip tps65910_gpiochip = {
+       .label                  = "tps65910",
+       .owner                  = THIS_MODULE,
+       .request                = tps65910_request,
+       .free                   = tps65910_free,
+       .direction_input        = tps65910_direction_in,
+       .get                    = tps65910_get,
+       .direction_output       = tps65910_direction_out,
+       .set                    = tps65910_set,
+};
+
+
+static int __devinit gpio_tps65910_probe(struct platform_device *pdev)
+{
+       int ret = -1;
+       int status = 0;
+
+       struct tps65910_gpio *pdata = pdev->dev.platform_data;
+
+       if (pdata->gpio_mode == TPS65910_GPIO_AS_IRQ) {
+
+               if (pdata->irq_num) {
+                       status = request_irq(pdata->irq_num, tps65910_gpio_isr,
+                                       IRQF_SHARED, "tps65910_gpio", pdev);
+                       if (status < 0) {
+                               pr_err("tps65910: could not claim irq%d: %d\n",
+                                       pdata->irq_num, status);
+                       }
+
+               }
+
+               INIT_WORK(&gpio_work, tps65910_gpio_work);
+               mutex_init(&work_lock);
+
+               tps65910_gpiochip.ngpio = TPS65910_GPIO_MAX;
+               tps65910_gpiochip.dev = &pdev->dev;
+
+               ret = gpiochip_add(&tps65910_gpiochip);
+
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "could not register gpiochip \
+                                %d\n", ret);
+                       tps65910_gpiochip.ngpio = 0;
+                       gpio_tps65910_remove(pdev);
+                       return -ENODEV;
+               }
+               if (pdata->gpio_setup)
+                       pdata->gpio_setup(pdata);
+       }
+       return ret;
+}
+
+static int gpio_tps65910_remove(struct platform_device *pdev)
+{
+       struct tps65910_gpio *pdata = pdev->dev.platform_data;
+       int status;
+
+       if (pdata->gpio_taredown)
+               pdata->gpio_taredown(pdata);
+       if (pdata->gpio_mode == TPS65910_GPIO_AS_IRQ)
+               free_irq(pdata->irq_num, NULL);
+
+       status = gpiochip_remove(&tps65910_gpiochip);
+       if (status < 0)
+               return status;
+       return 0;
+}
+
+static struct platform_driver gpio_tps65910_driver = {
+       .driver.name    = "tps65910_gpio",
+       .driver.owner   = THIS_MODULE,
+       .probe          = gpio_tps65910_probe,
+       .remove         = gpio_tps65910_remove,
+};
+
+static int __init gpio_tps65910_init(void)
+{
+       return platform_driver_register(&gpio_tps65910_driver);
+}
+subsys_initcall(gpio_tps65910_init);
+
+static void __exit gpio_tps65910_exit(void)
+{
+       platform_driver_unregister(&gpio_tps65910_driver);
+}
+module_exit(gpio_tps65910_exit);
+
+MODULE_AUTHOR("Mistral Solutions Pvt Ltd.");
+MODULE_DESCRIPTION("GPIO interface for TPS65910");
+MODULE_LICENSE("GPL");
index 9ec984730f8ee55f4d5c3a58ae8470d6d7ff0a77..b585257bc2f685bfd6d0eb88cd586f9ebab7260a 100755 (executable)
@@ -220,6 +220,16 @@ config INPUT_TWL4030_PWRBUTTON
          To compile this driver as a module, choose M here. The module will
          be called twl4030_pwrbutton.
 
+config INPUT_TPS65910_PWRBUTTON
+       tristate "TPS65910 Power button Driver"
+       depends on TPS65910_CORE
+       help
+         Say Y here if you want to enable power key reporting via the
+         TPS65910 family of chips.
+
+         To compile this driver as a module, choose M here. The module will
+         be called tps65910_pwrbutton.
+
 config INPUT_UINPUT
        tristate "User level driver support"
        help
index 32460bdbc4df25e153e4a91dc476e4de5be07f13..a5ea67fdcb1c6d6df617786fc284007294bdd5c6 100755 (executable)
@@ -29,6 +29,7 @@ obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER)       += rotary_encoder.o
 obj-$(CONFIG_INPUT_SGI_BTNS)           += sgi_btns.o
 obj-$(CONFIG_INPUT_SPARCSPKR)          += sparcspkr.o
 obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON)  += twl4030-pwrbutton.o
+obj-$(CONFIG_INPUT_TPS65910_PWRBUTTON) += tps65910-pwrbutton.o
 obj-$(CONFIG_INPUT_UINPUT)             += uinput.o
 obj-$(CONFIG_INPUT_WINBOND_CIR)                += winbond-cir.o
 obj-$(CONFIG_INPUT_WISTRON_BTNS)       += wistron_btns.o
diff --git a/drivers/input/misc/tps65910-pwrbutton.c b/drivers/input/misc/tps65910-pwrbutton.c
new file mode 100644 (file)
index 0000000..587de97
--- /dev/null
@@ -0,0 +1,148 @@
+/**
+ * tps65910-pwrbutton.c - TPS65910 Power Button Input Driver
+ *
+ * Copyright (C) 2010 Mistral Solutions Pvt Ltd <www.mistralsolutions.com>
+ *
+ * Based on twl4030-pwrbutton.c
+ *
+ * Written by Srinath.R <srinath@mistralsolutions.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ * 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/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/i2c/tps65910.h>
+
+#define TPS65910_PWR_PWRON_IRQ (1 << 2)
+
+
+static irqreturn_t powerbutton_irq(int irq, void *_pwr)
+{
+       struct input_dev *pwr = _pwr;
+       int err;
+       u8 value;
+
+#ifdef CONFIG_LOCKDEP
+       /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
+        * we don't want and can't tolerate since this is a threaded
+        * IRQ and can sleep due to the i2c reads it has to issue.
+        * Although it might be friendlier not to borrow this thread
+        * context...
+        */
+       local_irq_enable();
+#endif
+       err = tps65910_i2c_read_u8(TPS65910_I2C_ID0, &value,
+                               TPS65910_REG_INT_STS);
+       if (!err  && (value & TPS65910_PWR_PWRON_IRQ))  {
+
+               if (value & TPS65910_PWR_PWRON_IRQ) {
+
+                       input_report_key(pwr, KEY_POWER,
+                                       TPS65910_PWR_PWRON_IRQ);
+                       input_sync(pwr);
+                       return IRQ_HANDLED;
+               }
+       } else {
+               dev_err(pwr->dev.parent, "tps65910: i2c error %d while reading"
+                       " TPS65910_REG_INT_STS register\n", err);
+       }
+       return IRQ_HANDLED;
+}
+
+static int __devinit tps65910_pwrbutton_probe(struct platform_device *pdev)
+{
+       struct input_dev *pwr;
+       int irq = platform_get_irq(pdev, 0);
+       int err;
+
+       pwr = input_allocate_device();
+       if (!pwr) {
+               dev_dbg(&pdev->dev, "Can't allocate power button\n");
+               return -ENOMEM;
+       }
+
+       pwr->evbit[0] = BIT_MASK(EV_KEY);
+       pwr->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER);
+       pwr->name = "tps65910_pwrbutton";
+       pwr->phys = "tps65910_pwrbutton/input0";
+       pwr->dev.parent = &pdev->dev;
+
+       err = request_irq(irq, powerbutton_irq,
+                       (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
+                       IRQF_SHARED), "tps65910_pwrbutton", pwr);
+       if (err < 0) {
+               dev_dbg(&pdev->dev, "Can't get IRQ for pwrbutton: %d\n", err);
+               goto free_input_dev;
+       }
+
+       err = input_register_device(pwr);
+       if (err) {
+               dev_dbg(&pdev->dev, "Can't register power button: %d\n", err);
+               goto free_irq;
+       }
+
+       platform_set_drvdata(pdev, pwr);
+
+       return 0;
+
+free_irq:
+       free_irq(irq, NULL);
+free_input_dev:
+       input_free_device(pwr);
+       return err;
+}
+
+static int __devexit tps65910_pwrbutton_remove(struct platform_device *pdev)
+{
+       struct input_dev *pwr = platform_get_drvdata(pdev);
+       int irq = platform_get_irq(pdev, 0);
+
+       free_irq(irq, pwr);
+       input_unregister_device(pwr);
+
+       return 0;
+}
+
+struct platform_driver tps65910_pwrbutton_driver = {
+       .probe          = tps65910_pwrbutton_probe,
+       .remove         = __devexit_p(tps65910_pwrbutton_remove),
+       .driver         = {
+               .name   = "tps65910_pwrbutton",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init tps65910_pwrbutton_init(void)
+{
+       return platform_driver_register(&tps65910_pwrbutton_driver);
+}
+module_init(tps65910_pwrbutton_init);
+
+static void __exit tps65910_pwrbutton_exit(void)
+{
+       platform_driver_unregister(&tps65910_pwrbutton_driver);
+}
+module_exit(tps65910_pwrbutton_exit);
+
+MODULE_ALIAS("platform:tps65910_pwrbutton");
+MODULE_DESCRIPTION("TPS65910 Power Button");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Srinath R <srinath@mistralsolutions.com>");
+
index f16067d690c5df08de9b015b19978edb5252880b..6a02cb5f701c1ae5c82f0f5fe7e8a2361a79b39c 100644 (file)
@@ -553,7 +553,7 @@ static int __devinit egalax_i2c_probe(struct i2c_client *client)
        int ret;
        int gpio = client->irq;
        struct eeti_egalax_platform_data *pdata = pdata = client->dev.platform_data;
-       DBG();
+
        printk(KERN_DEBUG "[egalax_i2c]: start probe\n");
 
        p_egalax_i2c_dev = (struct _egalax_i2c *)kzalloc(sizeof(struct _egalax_i2c), GFP_KERNEL);
index a111745fa291114dc5b068ad870cbec023c93467..cc4cf1274a3edff44f69ffc21d7ef5d73511575a 100755 (executable)
@@ -121,6 +121,18 @@ config TWL4030_POWER
          and load scripts controling which resources are switched off/on
          or reset when a sleep, wakeup or warm reset event occurs.
 
+config TPS65910_CORE
+       bool "Texas Instruments TPS65910 Support"
+       depends on I2C=y && GENERIC_HARDIRQS
+       help
+         Say yes here if you have TPS65910 family chip on your board.
+         This core driver provides register access and registers devices
+          for the various functions so that function-specific drivers can
+          bind to them.
+
+         These multi-function chips are found on many AM35xx boards,
+          providing power management, RTC, GPIO features.
+
 config MFD_TMIO
        bool
        default n
index aa2270196611c83cf18e599e0a39d3604fb9c2cf..9b2463df22b715a4c0bcbc8aaf225f07a05c7d5c 100755 (executable)
@@ -29,6 +29,8 @@ obj-$(CONFIG_MENELAUS)                += menelaus.o
 obj-$(CONFIG_TWL4030_CORE)     += twl4030-core.o twl4030-irq.o
 obj-$(CONFIG_TWL4030_POWER)    += twl4030-power.o
 
+obj-$(CONFIG_TPS65910_CORE)     += tps65910-core.o
+
 obj-$(CONFIG_MFD_MC13783)      += mc13783-core.o
 
 obj-$(CONFIG_MFD_CORE)         += mfd-core.o
index acf8b9d5f575fec8cfe3d2578ab909c0956ce178..e5955306c2fa3397d97c5dba149adf1c67213159 100644 (file)
@@ -637,7 +637,7 @@ static int tps65010_probe(struct i2c_client *client,
                                tps, DEBUG_FOPS);
 
        /* optionally register GPIOs */
-       if (board && board->base > 0) {
+       if (board && board->base != 0) {
                tps->outmask = board->outmask;
 
                tps->chip.label = client->name;
@@ -964,6 +964,34 @@ int tps65010_config_vregs1(unsigned value)
 }
 EXPORT_SYMBOL(tps65010_config_vregs1);
 
+int tps65010_config_vdcdc2(unsigned value)
+{
+       struct i2c_client *c;
+       int      status;
+
+       if (!the_tps)
+               return -ENODEV;
+
+       c = the_tps->client;
+       mutex_lock(&the_tps->lock);
+
+       pr_debug("%s: vdcdc2 0x%02x\n", DRIVER_NAME,
+                i2c_smbus_read_byte_data(c, TPS_VDCDC2));
+
+       status = i2c_smbus_write_byte_data(c, TPS_VDCDC2, value);
+
+       if (status != 0)
+               printk(KERN_ERR "%s: Failed to write vdcdc2 register\n",
+                       DRIVER_NAME);
+       else
+               pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME,
+                        i2c_smbus_read_byte_data(c, TPS_VDCDC2));
+
+       mutex_unlock(&the_tps->lock);
+       return status;
+}
+EXPORT_SYMBOL(tps65010_config_vdcdc2);
+
 /*-------------------------------------------------------------------------*/
 /* tps65013_set_low_pwr parameter:
  * mode: ON or OFF
diff --git a/drivers/mfd/tps65910-core.c b/drivers/mfd/tps65910-core.c
new file mode 100644 (file)
index 0000000..1616342
--- /dev/null
@@ -0,0 +1,732 @@
+/*
+ * tps65910-core.c -- Multifunction core driver for  TPS65910x chips
+ *
+ * Copyright (C) 2010 Mistral solutions Pvt Ltd <www.mistralsolutions.com>
+ *
+ * Based on twl-core.c
+ *
+ * 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/init.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#include <linux/regulator/machine.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c/tps65910.h>
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#if 1
+#define DBG(x...)      printk(KERN_INFO x)
+#else
+#define DBG(x...)
+#endif
+#define TPS65910_SPEED         400 * 1000
+
+
+#define DRIVER_NAME                    "tps65910"
+
+#if defined(CONFIG_GPIO_TPS65910)
+#define tps65910_has_gpio()            true
+#else
+#define tps65910_has_gpio()            false
+#endif
+
+#if defined(CONFIG_REGULATOR_TPS65910)
+#define tps65910_has_regulator()       true
+#else
+#define tps65910_has_regulator()       false
+#endif
+
+#if defined(CONFIG_RTC_DRV_TPS65910)
+#define tps65910_has_rtc()             true
+#else
+#define tps65910_has_rtc()             false
+#endif
+
+#define TPS65910_GENERAL                       0
+#define TPS65910_SMARTREFLEX           1
+
+
+struct tps65910_platform_data *the_tps65910;
+
+enum tps65910x_model {
+       TPS65910,       /* TI processors OMAP3 family */
+       TPS659101,      /* Samsung - S5PV210, S5PC1xx */
+       TPS659102,      /* Samsung - S3C64xx */
+       TPS659103,      /* Reserved */
+       TPS659104,      /* Reserved */
+       TPS659105,      /* TI processors - DM643x, DM644x */
+       TPS659106,      /* Reserved */
+       TPS659107,      /* Reserved */
+       TPS659108,      /* Reserved */
+       TPS659109,      /* Freescale - i.MX51 */
+
+};
+
+static bool inuse;
+static struct work_struct core_work;
+static struct mutex work_lock;
+
+/* Structure for each TPS65910 Slave */
+struct tps65910_client {
+       struct i2c_client *client;
+       u8 address;
+       /* max numb of i2c_msg required for read = 2 */
+       struct i2c_msg xfer_msg[2];
+       /* To lock access to xfer_msg */
+       struct mutex xfer_lock;
+};
+static struct tps65910_client tps65910_modules[TPS65910_NUM_SLAVES];
+
+/* bbch = Back-up battery charger control register */
+int tps65910_enable_bbch(u8 voltage)
+{
+       u8 val = 0;
+       int err;
+
+       if (voltage == TPS65910_BBSEL_3P0 || voltage == TPS65910_BBSEL_2P52 ||
+                       voltage == TPS65910_BBSEL_3P15 ||
+                       voltage == TPS65910_BBSEL_VBAT) {
+               val = (voltage | TPS65910_BBCHEN);
+               err = tps65910_i2c_write_u8(TPS65910_I2C_ID0, val,
+                               TPS65910_REG_BBCH);
+               if (err) {
+                       printk(KERN_ERR "Unable write TPS65910_REG_BBCH reg\n");
+                       return -EIO;
+               }
+       } else {
+               printk(KERN_ERR"Invalid argumnet for %s \n", __func__);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(tps65910_enable_bbch);
+
+int tps65910_disable_bbch(void)
+{
+       u8 val = 0;
+       int err;
+
+       err = tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_BBCH);
+
+       if (!err) {
+               val &= ~TPS65910_BBCHEN;
+
+               err = tps65910_i2c_write_u8(TPS65910_I2C_ID0, val,
+                               TPS65910_REG_BBCH);
+               if (err) {
+                       printk(KERN_ERR "Unable write TPS65910_REG_BBCH \
+                                       reg\n");
+                       return -EIO;
+               }
+       } else {
+               printk(KERN_ERR "Unable to read TPS65910_REG_BBCH reg\n");
+               return -EIO;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(tps65910_disable_bbch);
+
+int tps65910_i2c_read_u8(u8 mod_no, u8 *value, u8 reg)
+{
+       struct tps65910_client *tps65910;
+       int ret;
+       
+       switch (mod_no) {
+       case TPS65910_I2C_ID0:
+               tps65910 = &tps65910_modules[0];
+               tps65910->address = TPS65910_I2C_ID0;
+               break;
+       case TPS65910_I2C_ID1:
+               tps65910 = &tps65910_modules[1];
+               tps65910->address = TPS65910_I2C_ID1;
+               break;
+       default:
+               printk(KERN_ERR "Invalid Slave address for TPS65910\n");
+               return -ENODEV;
+       }
+       
+       ret = i2c_master_reg8_recv(tps65910->client, reg, (char *)value, 1, TPS65910_SPEED);
+       DBG("%s: ret=%d, slave_addr=0x%x, reg=0x%x, value=0x%x\n", __FUNCTION__, (ret > 0 ? 0: -EINVAL), mod_no, reg, *value);
+
+       return (ret > 0 ? 0: -EINVAL);
+}
+EXPORT_SYMBOL(tps65910_i2c_read_u8);
+
+int tps65910_i2c_write_u8(u8 slave_addr, u8 value, u8 reg)
+{
+       struct tps65910_client *tps65910;
+       int ret;
+
+       switch (slave_addr) {
+       case TPS65910_I2C_ID0:
+               tps65910 = &tps65910_modules[0];
+               tps65910->address = TPS65910_I2C_ID0;
+               break;
+       case TPS65910_I2C_ID1:
+               tps65910 = &tps65910_modules[1];
+               tps65910->address = TPS65910_I2C_ID1;
+               break;
+       default:
+               printk(KERN_ERR "Invalid Slave address for TPS65910\n");
+               return -ENODEV;
+       }
+
+       ret = i2c_master_reg8_send(tps65910->client, reg, (char *)&value, 1, TPS65910_SPEED);
+       DBG("%s: ret=%d, slave_addr=0x%x, reg=0x%x, value=0x%x\n", __FUNCTION__, ret, slave_addr, reg, value);
+
+       if (ret < 0)
+               return -EIO;
+       else
+               return 0;
+}
+EXPORT_SYMBOL(tps65910_i2c_write_u8);
+
+
+int tps65910_enable_irq(int irq)
+{
+       u8  mask = 0x00;
+
+       if (irq > 7) {
+               irq -= 8;
+               tps65910_i2c_read_u8(TPS65910_I2C_ID0,
+                               &mask, TPS65910_REG_INT_MSK2);
+               mask &= ~(1 << irq);
+               return tps65910_i2c_write_u8(TPS65910_I2C_ID0,
+                               mask, TPS65910_REG_INT_MSK2);
+       } else {
+               tps65910_i2c_read_u8(TPS65910_I2C_ID0,
+                               &mask, TPS65910_REG_INT_MSK);
+               mask &= ~(1 << irq);
+               return tps65910_i2c_write_u8(TPS65910_I2C_ID0,
+                               mask, TPS65910_REG_INT_MSK);
+       }
+}
+EXPORT_SYMBOL(tps65910_enable_irq);
+
+int tps65910_disable_irq(int irq)
+{
+       u8  mask = 0x00;
+
+       if (irq > 7) {
+               irq -= 8;
+               tps65910_i2c_read_u8(TPS65910_I2C_ID0,
+                               &mask, TPS65910_REG_INT_MSK2);
+               mask |= (1 << irq);
+               return tps65910_i2c_write_u8(TPS65910_I2C_ID0,
+                               mask, TPS65910_REG_INT_MSK2);
+       } else {
+               tps65910_i2c_read_u8(TPS65910_I2C_ID0,
+                               &mask, TPS65910_REG_INT_MSK);
+               mask = (1 << irq);
+               return tps65910_i2c_write_u8(TPS65910_I2C_ID0,
+                               mask, TPS65910_REG_INT_MSK);
+       }
+}
+EXPORT_SYMBOL(tps65910_disable_irq);
+
+int tps65910_add_irq_work(int irq,
+               void (*handler)(void *data))
+{
+       int ret = 0;
+       the_tps65910->handlers[irq] = handler;
+       ret = tps65910_enable_irq(irq);
+
+       return ret;
+}
+EXPORT_SYMBOL(tps65910_add_irq_work);
+
+int tps65910_remove_irq_work(int irq)
+{
+       int ret = 0;
+       ret = tps65910_disable_irq(irq);
+       the_tps65910->handlers[irq] = NULL;
+       return ret;
+}
+EXPORT_SYMBOL(tps65910_remove_irq_work);
+
+static void tps65910_core_work(struct work_struct *work)
+{
+       /* Read the status register and take action  */
+       u8      status = 0x00;
+       u8      status2 = 0x00;
+       u8      mask = 0x00;
+       u8      mask2 = 0x00;
+       u16 isr = 0x00;
+       u16 irq = 0;
+       void    (*handler)(void *data) = NULL;
+
+       mutex_lock(&work_lock);
+       while (1) {
+               tps65910_i2c_read_u8(TPS65910_I2C_ID0, &status2,
+                               TPS65910_REG_INT_STS2);
+               tps65910_i2c_read_u8(TPS65910_I2C_ID0, &mask2,
+                               TPS65910_REG_INT_MSK2);
+               status2 &= (~mask2);
+               isr = (status2 << 8);
+               tps65910_i2c_read_u8(TPS65910_I2C_ID0, &status,
+                               TPS65910_REG_INT_STS);
+               tps65910_i2c_read_u8(TPS65910_I2C_ID0, &mask,
+                               TPS65910_REG_INT_MSK);
+               status &= ~(mask);
+               isr |= status;
+               if (!isr)
+                       break;
+
+               while (isr) {
+                       irq = fls(isr) - 1;
+                       isr &= ~(1 << irq);
+                       handler = the_tps65910->handlers[irq];
+                       if (handler)
+                               handler(the_tps65910);
+               }
+       }
+       enable_irq(the_tps65910->irq_num);
+       mutex_unlock(&work_lock);
+}
+
+
+static irqreturn_t tps65910_isr(int irq,  void *data)
+{
+       disable_irq_nosync(irq);
+       (void) schedule_work(&core_work);
+       return IRQ_HANDLED;
+}
+
+
+static struct device *add_numbered_child(unsigned chip, const char *name,
+       int num, void *pdata, unsigned pdata_len, bool can_wakeup, int irq)
+{
+
+       struct platform_device  *pdev;
+       struct tps65910_client  *tps65910 = &tps65910_modules[chip];
+       int  status;
+
+       pdev = platform_device_alloc(name, num);
+       if (!pdev) {
+               dev_dbg(&tps65910->client->dev, "can't alloc dev\n");
+               status = -ENOMEM;
+               goto err;
+       }
+       device_init_wakeup(&pdev->dev, can_wakeup);
+       pdev->dev.parent = &tps65910->client->dev;
+
+       if (pdata) {
+               status = platform_device_add_data(pdev, pdata, pdata_len);
+               if (status < 0) {
+                       dev_dbg(&pdev->dev, "can't add platform_data\n");
+                       goto err;
+               }
+       }
+       status = platform_device_add(pdev);
+
+err:
+       if (status < 0) {
+               platform_device_put(pdev);
+               dev_err(&tps65910->client->dev, "can't add %s dev\n", name);
+               return ERR_PTR(status);
+       }
+       return &pdev->dev;
+
+}
+
+static inline struct device *add_child(unsigned chip, const char *name,
+               void *pdata, unsigned pdata_len,
+               bool can_wakeup, int irq)
+{
+       return add_numbered_child(chip, name, -1, pdata, pdata_len,
+                       can_wakeup, irq);
+}
+
+static
+struct device *add_regulator_linked(int num, struct regulator_init_data *pdata,
+               struct regulator_consumer_supply *consumers,
+               unsigned num_consumers)
+{
+       /* regulator framework demands init_data */
+       if (!pdata)
+               return NULL;
+
+       if (consumers) {
+               pdata->consumer_supplies = consumers;
+               pdata->num_consumer_supplies = num_consumers;
+       }
+       return add_numbered_child(TPS65910_GENERAL, "tps65910_regulator", num,
+                       pdata, sizeof(*pdata), false, TPS65910_HOST_IRQ);
+}
+
+       static struct device *
+add_regulator(int num, struct regulator_init_data *pdata)
+{
+       return add_regulator_linked(num, pdata, NULL, 0);
+}
+
+static int
+add_children(struct tps65910_platform_data *pdata, unsigned long features)
+{
+       int             status;
+       struct device   *child;
+
+       struct platform_device  *pdev = NULL;
+
+       if (tps65910_has_gpio() && (pdata->gpio != NULL)) {
+
+               pdev = platform_device_alloc("tps65910_gpio", -1);
+               if (!pdev) {
+                       status = -ENOMEM;
+                       goto err;
+               }
+               pdev->dev.parent = &tps65910_modules[0].client->dev;
+               device_init_wakeup(&pdev->dev, 0);
+               if (pdata) {
+                       status = platform_device_add_data(pdev, pdata,
+                                                       sizeof(*pdata));
+                       if (status < 0) {
+                               dev_dbg(&pdev->dev,
+                               "can't add platform_data\n");
+                               goto err;
+                       }
+               }
+       }
+       if (tps65910_has_rtc()) {
+               child = add_child(TPS65910_GENERAL, "tps65910_rtc",
+                               NULL, 0, true, pdata->irq_num);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+       }
+
+       if (tps65910_has_regulator()) {
+
+               child = add_regulator(TPS65910_VIO, pdata->vio);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TPS65910_VDD1, pdata->vdd1);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TPS65910_VDD2, pdata->vdd2);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TPS65910_VDD3, pdata->vdd3);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TPS65910_VDIG1, pdata->vdig1);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TPS65910_VDIG2, pdata->vdig2);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TPS65910_VAUX33, pdata->vaux33);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TPS65910_VMMC, pdata->vmmc);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TPS65910_VAUX1, pdata->vaux1);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TPS65910_VAUX2, pdata->vaux2);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TPS65910_VDAC, pdata->vdac);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+
+               child = add_regulator(TPS65910_VPLL, pdata->vpll);
+               if (IS_ERR(child))
+                       return PTR_ERR(child);
+       }
+       return 0;
+
+err:
+       return -1;
+
+}
+
+static int tps65910_remove(struct i2c_client *client)
+{
+       unsigned i;
+
+       for (i = 0; i < TPS65910_NUM_SLAVES; i++) {
+
+               struct tps65910_client *tps65910 = &tps65910_modules[i];
+
+               if (tps65910->client && tps65910->client != client)
+                       i2c_unregister_device(tps65910->client);
+
+               tps65910_modules[i].client = NULL;
+       }
+       inuse = false;
+       return 0;
+}
+
+static int __init
+tps65910_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+       int      status;
+       unsigned i;
+       struct tps65910_platform_data   *pdata;
+       pdata = client->dev.platform_data;
+       the_tps65910 = pdata;
+
+       DBG("cwz: tps65910_i2c_probe\n");
+       
+       if (!pdata) {
+               dev_dbg(&client->dev, "no platform data?\n");
+               return -EINVAL;
+       }
+
+       if (!i2c_check_functionality(client->adapter,I2C_FUNC_I2C)) {
+               dev_dbg(&client->dev, "can't talk I2C?\n");
+               return -EIO;
+       }
+
+       if (inuse) {
+               dev_dbg(&client->dev, "driver is already in use\n");
+               return -EBUSY;
+       } 
+       for (i = 0; i < TPS65910_NUM_SLAVES; i++) {
+
+               struct tps65910_client  *tps65910 = &tps65910_modules[i];
+
+               tps65910->address = client->addr;
+
+               if (i == 0)
+                       tps65910->client = client;
+               else {
+                       tps65910->client = i2c_new_dummy(client->adapter,
+                                       tps65910->address);
+
+                       if (!tps65910->client) {
+                               dev_err(&client->dev,
+                                               "can't attach client %d\n", i);
+                               status = -ENOMEM;
+                               goto fail;
+                       }
+               }
+               mutex_init(&tps65910->xfer_lock);
+       } 
+
+       inuse = true;
+
+       if (pdata->board_tps65910_config != NULL)
+               pdata->board_tps65910_config(pdata);
+
+#if 0  //      cwz close, the tps65910_core_work may have some error.
+       if (pdata->irq_num) {
+               /* TPS65910 power ON interrupt(s) would have already been
+                * occurred, so immediately after request_irq the control will
+                * be transferred to tps65910_isr, if we do core_work
+                * initialization after requesting IRQ, the system crashes
+                * and does not boot; to avoid this we do core_work
+                * initialization before requesting IRQ
+                */
+               mutex_init(&work_lock);
+               INIT_WORK(&core_work, tps65910_core_work);
+
+               status = request_irq(pdata->irq_num, tps65910_isr,
+                                       IRQF_DISABLED, "tps65910", pdata);
+               if (status < 0) {
+                       pr_err("tps65910: could not claim irq%d: %d\n",
+                                       pdata->irq_num, status);
+                       goto fail;
+               }
+       }
+#endif
+
+       status = add_children(pdata, 0x00);
+       if (status < 0)
+               goto fail;
+
+       return 0;
+
+fail:
+       if (status < 0)
+               tps65910_remove(client);
+
+       return status;
+}
+
+
+static int tps65910_i2c_remove(struct i2c_client *client)
+{
+       unsigned i;
+
+       for (i = 0; i < TPS65910_NUM_SLAVES; i++) {
+
+               struct tps65910_client  *tps65910 = &tps65910_modules[i];
+
+               if (tps65910->client && tps65910->client != client)
+                       i2c_unregister_device(tps65910->client);
+
+               tps65910_modules[i].client = NULL;
+       }
+       inuse = false;
+       return 0;
+}
+
+/* chip-specific feature flags, for i2c_device_id.driver_data */
+static const struct i2c_device_id tps65910_i2c_ids[] = {
+       { "tps65910", TPS65910 },
+       { "tps659101", TPS659101 },
+       { "tps659102", TPS659102 },
+       { "tps659103", TPS659103 },
+       { "tps659104", TPS659104 },
+       { "tps659105", TPS659105 },
+       { "tps659106", TPS659106 },
+       { "tps659107", TPS659107 },
+       { "tps659108", TPS659108 },
+       { "tps659109", TPS659109 },
+       {/* end of list */ },
+};
+MODULE_DEVICE_TABLE(i2c, tps65910_i2c_ids);
+
+/* One Client Driver ,3 Clients - Regulator, RTC , GPIO */
+static struct i2c_driver tps65910_i2c_driver = {
+       .driver         = {
+               .name   = DRIVER_NAME,
+               .owner  = THIS_MODULE,
+       },
+       .id_table       = tps65910_i2c_ids,
+       .probe          = tps65910_i2c_probe,
+       .remove         = __devexit_p(tps65910_i2c_remove),
+};
+
+static int __init tps65910_init(void)
+{
+       int res;
+
+       res = i2c_add_driver(&tps65910_i2c_driver);
+       if (res < 0) {
+               pr_err(DRIVER_NAME ": driver registration failed\n");
+               return res;
+       }
+
+       return 0;
+}
+subsys_initcall_sync(tps65910_init);
+
+static void __exit tps65910_exit(void)
+{
+       i2c_del_driver(&tps65910_i2c_driver);
+}
+module_exit(tps65910_exit);
+
+
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+static int proc_tps65910_show(struct seq_file *s, void *v)
+{
+    u8 val = 0;
+    struct regulator *vldo;
+       
+       seq_printf(s, "\n\nTPS65910 Registers is:\n");
+       
+       tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_VDD1);
+       seq_printf(s, "VDD1_REG=0x%x, Value=0x%x\n", TPS65910_REG_VDD1, val);
+       tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_VDD1_OP);
+       seq_printf(s, "VDD1_OP_REG=0x%x, Value=0x%x\n", TPS65910_REG_VDD1_OP, val);
+
+       tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_VDD2);
+       seq_printf(s, "VDD2_REG=0x%x, Value=0x%x\n", TPS65910_REG_VDD2, val);
+       tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_VDD2_OP);
+       seq_printf(s, "VDD2_OP_REG=0x%x, Value=0x%x\n", TPS65910_REG_VDD2_OP, val);
+
+       tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_VIO);
+       seq_printf(s, "VIO_REG=0x%x, Value=0x%x\n", TPS65910_REG_VIO, val);
+
+       tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_VDIG1);
+       seq_printf(s, "VDIG1_REG=0x%x, Value=0x%x\n", TPS65910_REG_VDIG1, val);
+       tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_VDIG2);
+       seq_printf(s, "VDIG2_REG=0x%x, Value=0x%x\n", TPS65910_REG_VDIG2, val);
+       tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_VAUX1);
+       seq_printf(s, "VAUX1_REG=0x%x, Value=0x%x\n", TPS65910_REG_VAUX1, val);
+       tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_VAUX2);
+       seq_printf(s, "VAUX2_REG=0x%x, Value=0x%x\n", TPS65910_REG_VAUX2, val);
+       tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_VAUX33);
+       seq_printf(s, "VAUX33_REG=0x%x, Value=0x%x\n", TPS65910_REG_VAUX33, val);
+       tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_VMMC);
+       seq_printf(s, "VMMC_REG=0x%x, Value=0x%x\n", TPS65910_REG_VMMC, val);
+       tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_VPLL);
+       seq_printf(s, "VPLL_REG=0x%x, Value=0x%x\n", TPS65910_REG_VPLL, val);
+       tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_VDAC);
+       seq_printf(s, "VDAC_REG=0x%x, Value=0x%x\n", TPS65910_REG_VDAC, val);
+
+       tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_DEVCTRL);
+       seq_printf(s, "DEVCTRL_REG=0x%x, Value=0x%x\n", TPS65910_REG_DEVCTRL, val);
+       tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_DEVCTRL2);
+       seq_printf(s, "DEVCTRL2_REG=0x%x, Value=0x%x\n", TPS65910_REG_DEVCTRL2, val);
+
+#if 0  //      cwz 1 test vcore
+       vldo = regulator_get(NULL, "vcore");
+       if (vldo != NULL)
+       {
+               int uV = 0;
+               
+               seq_printf(s, "Set VCORE.\n");
+               regulator_set_voltage(vldo,1100000,1100000);
+
+               uV = regulator_get_voltage(vldo);
+               seq_printf(s, "Get VCORE=%d(uV).\n", uV);
+       }
+#endif 
+       return 0;
+}
+
+static int proc_tps65910_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, proc_tps65910_show, NULL);
+}
+
+static const struct file_operations proc_tps65910_fops = {
+       .open           = proc_tps65910_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int __init proc_tps65910_init(void)
+{
+       proc_create("tps65910", 0, NULL, &proc_tps65910_fops);
+       return 0;
+}
+late_initcall(proc_tps65910_init);
+#endif /* CONFIG_PROC_FS */
+
+MODULE_AUTHOR("cwz <cwz@rock-chips.com>");
+MODULE_DESCRIPTION("I2C Core interface for TPS65910");
+MODULE_LICENSE("GPL");
index 0b93f4ad25f44d6a6415c3a5ce7eea0eac0cba8d..9c24042e6952a3fa7e9cf252de95e27d634b9f14 100644 (file)
@@ -76,6 +76,13 @@ config REGULATOR_TWL4030
          This driver supports the voltage regulators provided by
          this family of companion chips.
 
+config REGULATOR_TPS65910
+       bool "TI TPS69510x PMIC"
+       depends on TPS65910_CORE
+       help
+         This driver supports the voltage regulators provided by
+         this family of companion chips.
+         
 config REGULATOR_WM831X
        tristate "Wolfson Microelcronics WM831x PMIC regulators"
        depends on MFD_WM831X
index 77befcd24bf3338dc56041e9aed7bfe3a66c3513..ec0e204b5541b3c58843a65e7f6054a098cd9a68 100644 (file)
@@ -12,6 +12,7 @@ obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o
 obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
 obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
 obj-$(CONFIG_REGULATOR_TWL4030) += twl4030-regulator.o
+obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o
 obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o
 obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o
 obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o
diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c
new file mode 100644 (file)
index 0000000..67d6c1d
--- /dev/null
@@ -0,0 +1,760 @@
+/*
+ * tps65910-regulator.c -- support regulators in tps65910x family chips
+ *
+ *
+ * Copyright (C) 2010 Mistral Solutions Pvt Ltd <www.mistralsolutions.com>
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
+ * whether express or implied; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/i2c/tps65910.h>
+
+#if 1
+#define DBG(x...)      printk(KERN_INFO x)
+#else
+#define DBG(x...)
+#endif
+
+/*
+ * The TPS65910x family chips include power management, a GPIO
+ * RTC. These chips are often used in AM35xx-based systems.
+ *
+ * This driver implements software-based resource control for various
+ * voltage regulators.  This is usually augmented with state machine
+ * based control.
+ */
+
+
+struct tps65910reg_info {
+       /* tps65910 resource ID, for resource control state machine */
+       u8                      id;
+       /* voltage in mV = table[VSEL]; table_len must be a power-of-two */
+       u8                      table_len;
+       const u16               *table;
+
+       /* regulator specific turn-on delay */
+       u32                     delay;
+       /* chip constraints on regulator behavior */
+       u16                     min_mV;
+       u16                     max_mV;
+       /* used by regulator core */
+       struct regulator_desc   desc;
+};
+
+
+/* Supported voltage values for regulators */
+
+/* TPS65910  VIO */
+static const u16 VIO_VSEL_table[] = {
+       1500, 1800, 2500, 3300,
+};
+
+/* TPS65910 VDD1 and VDD2 */
+/* value round off 12.5 is made as 12 */
+static const u16 VDD1_VSEL_table[] = {
+          0,  600,  600,  600,  612,  625,  637,  650,
+        662,  675,  687,  700,  712,  725,  737,  750,
+        762,  775,  787,  800,  812,  825,  837,  850,
+        862,  875,  887,  900,  912,  925,  937,  950,
+        962,  975,  987, 1000, 1012, 1025, 1037, 1050,
+       1062, 1075, 1087, 1100, 1112, 1125, 1137, 1150,
+       1162, 1175, 1187, 1200, 1212, 1225, 1237, 1250,
+       1262, 1275, 1287, 1300, 1312, 1325, 1337, 1350,
+       1362, 1375, 1387, 1400, 1412, 1425, 1437, 1450,
+       1462, 1475, 1487, 1500,
+};
+
+static const u16 VDD2_VSEL_table[] = {
+          0,  600,  600,  600,  612,  625,  637,  650,
+        662,  675,  687,  700,  712,  725,  737,  750,
+        762,  775,  787,  800,  812,  825,  837,  850,
+        862,  875,  887,  900,  912,  925,  937,  950,
+        962,  975,  987, 1000, 1012, 1025, 1037, 1050,
+       1062, 1075, 1087, 1100, 1112, 1125, 1137, 1150,
+       1162, 1175, 1187, 1200, 1212, 1225, 1237, 1250,
+       1262, 1275, 1287, 1300, 1312, 1325, 1337, 1350,
+       1362, 1375, 1387, 1400, 1412, 1425, 1437, 1450,
+       1462, 1475, 1487, 1500,
+};
+
+/* TPS65910 VDD3 */
+static const u16 VDD3_VSEL_table[] = {
+       5000,
+};
+
+/* VDIG1 */
+static const u16 VDIG1_VSEL_table[] = {
+       1200, 1500, 1800, 2700,
+};
+
+/* VDIG2 */
+static const u16 VDIG2_VSEL_table[] = {
+       1000, 1100, 1200, 1800,
+};
+
+/* VAUX33 */
+static const u16 VAUX33_VSEL_table[] = {
+       1800, 2000, 2800, 3300,
+};
+
+/* VMMC */
+static const u16 VMMC_VSEL_table[] = {
+       1800, 2800, 3000, 3300,
+};
+
+/* VAUX1 */
+static const u16 VAUX1_VSEL_table[] = {
+       1800, 2000, 2800, 3300,
+};
+
+/* VAUX2 */
+static const u16 VAUX2_VSEL_table[] = {
+       1800, 2800, 2900, 3300,
+};
+
+/* VDAC */
+static const u16 VDAC_VSEL_table[] = {
+       1800, 2600, 2800, 2850,
+};
+
+
+/* VPLL */
+static const u16 VPLL_VSEL_table[] = {
+       1000, 1100, 1800, 2500,
+};
+
+/* VRTC, supports only enable/disable */
+static const u16 VRTC_VSEL_table[] = {
+       1800,
+};
+
+static inline int
+tps65910reg_read(struct tps65910reg_info *info, unsigned slave_addr,
+               u8 offset)
+{
+       u8 value;
+       int status;
+       status = tps65910_i2c_read_u8(slave_addr, &value, offset);
+
+       return (status < 0) ? status : value;
+}
+
+static inline int
+tps65910reg_write(struct tps65910reg_info *info, unsigned slave_addr,
+               u8 offset, u8 value)
+{
+       if (0 == tps65910_i2c_write_u8(slave_addr, value, offset))
+               return 0;
+       else
+               return -1;
+}
+
+static u8 tps65910reg_find_offset(u8 regulator_id)
+{
+       u8 offset = 0;
+
+       switch (regulator_id) {
+
+       case TPS65910_VIO:
+               offset =  TPS65910_REG_VIO;
+               break;
+       case TPS65910_VDD1:
+               offset =  TPS65910_REG_VDD1_OP;
+               break;
+       case TPS65910_VDD2:
+               offset =  TPS65910_REG_VDD2_OP;
+               break;
+       case TPS65910_VDD3:
+               offset =  TPS65910_REG_VDD3;
+               break;
+       case TPS65910_VDIG1:
+               offset =  TPS65910_REG_VDIG1;
+               break;
+       case  TPS65910_VDIG2:
+               offset =  TPS65910_REG_VDIG2;
+               break;
+       case TPS65910_VAUX33:
+               offset =  TPS65910_REG_VAUX33;
+               break;
+       case TPS65910_VMMC:
+               offset =  TPS65910_REG_VMMC;
+               break;
+       case TPS65910_VAUX1:
+               offset =  TPS65910_REG_VAUX1;
+               break;
+       case TPS65910_VAUX2:
+               offset =  TPS65910_REG_VAUX2;
+               break;
+       case TPS65910_VDAC:
+               offset =  TPS65910_REG_VDAC;
+               break;
+       case TPS65910_VPLL:
+               offset =  TPS65910_REG_VPLL;
+               break;
+       }
+       return offset;
+}
+
+static int tps65910reg_is_enabled(struct regulator_dev *rdev)
+{
+       int    val;
+       u8    offset;
+
+       struct tps65910reg_info *info = rdev_get_drvdata(rdev);
+
+       offset = tps65910reg_find_offset(info->id);
+
+       val = tps65910reg_read(info, TPS65910_I2C_ID0, offset);
+       if (val < 0) {
+               printk(KERN_ERR "Unable to read TPS65910 Reg at offset 0x%x= \
+                               \n", offset);
+               return -EIO;
+       }
+       if ((val & TPS65910_REG_OHP) || (val & TPS65910_REG_OLP))
+               return 1;
+       else
+               return 0;
+}
+
+
+static int tps65910reg_enable(struct regulator_dev *rdev)
+{
+       int     val;
+       u8      offset;
+       struct tps65910reg_info *info = rdev_get_drvdata(rdev);
+
+       offset = tps65910reg_find_offset(info->id);
+
+       val = tps65910reg_read(info, TPS65910_I2C_ID0, offset);
+
+       if (val < 0) {
+
+               printk(KERN_ERR "Unable to read TPS65910 Reg at offset = 0x%x \
+                               \n", offset);
+               return -EIO;
+       }
+       val |= TPS65910_REG_OHP;
+
+       return tps65910reg_write(info, TPS65910_I2C_ID0, offset, val);
+}
+
+static int tps65910reg_disable(struct regulator_dev *rdev)
+{
+       int     val;
+       u8      offset;
+
+       struct tps65910reg_info *info = rdev_get_drvdata(rdev);
+
+       offset = tps65910reg_find_offset(info->id);
+
+       val = tps65910reg_read(info, TPS65910_I2C_ID0, offset);
+
+       if (val < 0) {
+
+               printk(KERN_ERR "Unable to read TPS65910 Reg at offset = \
+                        0x%x\n", offset);
+               return -EIO;
+       }
+       val &= TPS65910_REG_OFF_00;
+
+       return tps65910reg_write(info, TPS65910_I2C_ID0, offset, val);
+}
+
+static int tps65910reg_get_status(struct regulator_dev *rdev)
+{
+       int     val;
+       u8      offset;
+       u8      ret;
+       struct tps65910reg_info *info = rdev_get_drvdata(rdev);
+
+       offset = tps65910reg_find_offset(info->id);
+
+       val = tps65910reg_read(info, TPS65910_I2C_ID0, offset);
+
+       if (val < 0) {
+
+               printk(KERN_ERR "Unable to read TPS65910 Reg at offset = \
+                       0x%x\n", offset);
+               return -EIO;
+       }
+       switch ((val & SUPPLY_STATE_FLAG)) {
+
+       case TPS65910_REG_OFF_00:
+       case TPS65910_REG_OFF_10:
+               ret =  REGULATOR_STATUS_OFF;
+               break;
+       case TPS65910_REG_OHP:
+       case TPS65910_REG_OLP:
+               ret =  REGULATOR_STATUS_ON;
+               break;
+       default:
+               ret =  REGULATOR_STATUS_OFF;
+       }
+       return ret;
+}
+
+
+static int tps65910reg_set_mode(struct regulator_dev *rdev, unsigned mode)
+{
+       struct  tps65910reg_info   *info = rdev_get_drvdata(rdev);
+       u8      offset;
+       u8      val;
+
+       offset = tps65910reg_find_offset(info->id);
+       val = tps65910reg_read(info, TPS65910_I2C_ID0, offset);
+
+       if (val < 0) {
+               printk(KERN_ERR"Unable to read TPS65910 Reg at offset \
+                        = 0x%x\n", offset);
+               return -EIO;
+       }
+
+       switch (mode) {
+       case REGULATOR_MODE_NORMAL:
+               return tps65910reg_write(info, TPS65910_I2C_ID0, offset,
+                                               (val | TPS65910_REG_OHP));
+       case REGULATOR_MODE_STANDBY:
+               return tps65910reg_write(info, TPS65910_I2C_ID0, offset,
+                                               (val | TPS65910_REG_OLP));
+       default:
+               return -EINVAL;
+       }
+}
+
+static
+int tps65910_ldo_list_voltage(struct regulator_dev *rdev, unsigned index)
+{
+       struct tps65910reg_info      *info = rdev_get_drvdata(rdev);
+       int    mV = info->table[index];
+       return mV * 1000;
+}
+
+static int get_voltage_index(int ldo_id, int uv)
+{
+       int i = 0;
+       int size = 0;
+       u16 *ptr = NULL;
+       
+       uv = uv/1000;
+
+       if (((ldo_id == TPS65910_VDD1) || (ldo_id == TPS65910_VDD2))) {
+               for (i = 0; i < ARRAY_SIZE(VDD1_VSEL_table); i++) {
+                       if (VDD1_VSEL_table[i] == uv) {
+                               DBG("%s: regulator id=%d, volage=%d, get index=%d\n", __FUNCTION__, ldo_id, uv, i);
+                               return i;
+                       }
+               }
+               if (i == ARRAY_SIZE(VDD1_VSEL_table)) {
+                       DBG("%s: regulator id=%d, can't find volage index\n", __FUNCTION__, ldo_id);
+                       return -1;
+               }
+       }
+
+       /* Lookup table to match LDO volatge to Index*/
+       switch (ldo_id) {
+
+       case TPS65910_VIO:
+               ptr = (u16 *)&VIO_VSEL_table[0];
+               size = ARRAY_SIZE(VIO_VSEL_table);
+               break;
+       case TPS65910_VDIG1:
+               ptr = (u16 *)&VDIG1_VSEL_table[0];
+               size = ARRAY_SIZE(VDIG1_VSEL_table);
+               break;
+       case TPS65910_VDIG2:
+               ptr = (u16 *)&VDIG2_VSEL_table[0];
+               size = ARRAY_SIZE(VDIG2_VSEL_table);
+               break;
+       case TPS65910_VAUX33:
+               ptr = (u16 *)&VAUX33_VSEL_table[0];
+               size = ARRAY_SIZE(VAUX33_VSEL_table);
+               break;
+       case TPS65910_VMMC:
+               ptr = (u16 *)&VMMC_VSEL_table[0];
+               size = ARRAY_SIZE(VMMC_VSEL_table);
+               break;
+       case TPS65910_VAUX1:
+               ptr = (u16 *)&VAUX1_VSEL_table[0];
+               size = ARRAY_SIZE(VAUX1_VSEL_table);
+               break;
+       case TPS65910_VAUX2:
+               ptr = (u16 *)&VAUX2_VSEL_table[0];
+               size = ARRAY_SIZE(VAUX2_VSEL_table);
+               break;
+       case TPS65910_VDAC:
+               ptr = (u16 *)&VDAC_VSEL_table[0];
+               size = ARRAY_SIZE(VDAC_VSEL_table);
+               break;
+       case TPS65910_VPLL:
+               ptr = (u16 *)&VPLL_VSEL_table[0];
+               size = ARRAY_SIZE(VPLL_VSEL_table);
+               break;
+       default:
+               ptr = NULL;
+               break;
+       }
+
+       if (ptr != NULL) {
+               for (i = 0; i < size; i++) {
+                       if (*ptr++  == uv) {
+                               DBG("%s: regulator id=%d, volage=%d, get index=%d\n", __FUNCTION__, ldo_id, uv, i);
+                               return i;
+                       }
+               }
+       }
+       DBG("%s: regulator id=%d, can't find volage index\n", __FUNCTION__, ldo_id);
+
+       if (ptr == NULL || i == size)
+               return -1;
+       /* For warning */
+       return -1;
+}
+
+static int get_index_voltage(int ldo_id, int index)
+{
+       int vsel;
+       int size = 0;
+       u16 *ptr = NULL;
+       
+       /* Get the index of voltage value from Reg and map to table */
+       if (ldo_id == TPS65910_VDD1 || ldo_id == TPS65910_VDD2) {
+               index &= 0x7F;
+               ptr = (u16 *)&VDD1_VSEL_table[0];
+               size = ARRAY_SIZE(VDD1_VSEL_table);
+               /* For VDD1 and VDD2 */
+               if (index >= size) {
+                       vsel = size - 1;
+               } else {
+                       vsel = index;
+               }
+       } else {
+               vsel = (index & 0xF3);
+               vsel = (vsel >> 2);
+
+               /* Lookup table to match LDO volatge to Index*/
+               switch (ldo_id) {
+               
+               case TPS65910_VIO:
+                       ptr = (u16 *)&VIO_VSEL_table[0];
+                       size = ARRAY_SIZE(VIO_VSEL_table);
+                       break;
+               case TPS65910_VDIG1:
+                       ptr = (u16 *)&VDIG1_VSEL_table[0];
+                       size = ARRAY_SIZE(VDIG1_VSEL_table);
+                       break;
+               case TPS65910_VDIG2:
+                       ptr = (u16 *)&VDIG2_VSEL_table[0];
+                       size = ARRAY_SIZE(VDIG2_VSEL_table);
+                       break;
+               case TPS65910_VAUX33:
+                       ptr = (u16 *)&VAUX33_VSEL_table[0];
+                       size = ARRAY_SIZE(VAUX33_VSEL_table);
+                       break;
+               case TPS65910_VMMC:
+                       ptr = (u16 *)&VMMC_VSEL_table[0];
+                       size = ARRAY_SIZE(VMMC_VSEL_table);
+                       break;
+               case TPS65910_VAUX1:
+                       ptr = (u16 *)&VAUX1_VSEL_table[0];
+                       size = ARRAY_SIZE(VAUX1_VSEL_table);
+                       break;
+               case TPS65910_VAUX2:
+                       ptr = (u16 *)&VAUX2_VSEL_table[0];
+                       size = ARRAY_SIZE(VAUX2_VSEL_table);
+                       break;
+               case TPS65910_VDAC:
+                       ptr = (u16 *)&VDAC_VSEL_table[0];
+                       size = ARRAY_SIZE(VDAC_VSEL_table);
+                       break;
+               case TPS65910_VPLL:
+                       ptr = (u16 *)&VPLL_VSEL_table[0];
+                       size = ARRAY_SIZE(VPLL_VSEL_table);
+                       break;
+               default:
+                       ptr = NULL;
+                       break;
+               }
+               
+               if (vsel >= size)
+                       vsel = size - 1;
+       }
+
+       if (ptr != NULL) {
+               DBG("%s: regulator id=%d index=%d, get volage=%d(mV)\n", __FUNCTION__, ldo_id, index, ptr[vsel]);
+               return ptr[vsel] * 1000;
+       }
+       /* For warning */
+       DBG("%s: regulator id=%d index=%d, get volage error\n", __FUNCTION__, ldo_id, index);
+       return -1;
+}
+
+static int
+tps65910_ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
+{
+       struct tps65910reg_info      *info = rdev_get_drvdata(rdev);
+       int vsel;
+       u8      offset;
+       u8      val;
+       u8      index;
+
+       if (info == NULL)
+               return 0;
+       
+       DBG("%s: regulator(%s) id=%d, set volage=(min_uV:%d, max_uV:%d)\n", __FUNCTION__, info->desc.name, info->id, min_uV, max_uV);
+       if (rdev->constraints) {
+               if (min_uV < rdev->constraints->min_uV || min_uV > rdev->constraints->max_uV)
+                       return -EINVAL;
+               if (max_uV < rdev->constraints->min_uV || max_uV > rdev->constraints->max_uV)
+                       return -EINVAL;
+       }
+
+       for (vsel = 0; vsel < info->table_len; vsel++) {
+
+               int mV = info->table[vsel];
+               int uV;
+
+               uV = mV * 1000;
+
+               /* Break at the first in-range value */
+               if (min_uV <= uV && uV <= max_uV) {
+                       offset = tps65910reg_find_offset(info->id);
+                       val = tps65910reg_read(info, TPS65910_I2C_ID0, offset);
+                       if (val < 0) {
+                               printk(KERN_ERR"Unable to read TPS65910 Reg at offset = 0x%x\n",
+                                               offset);
+                               return -EIO;
+                       }
+
+                       index = get_voltage_index(info->id, uV);
+                       /* For VDD1 and VDD2 */
+                       if (info->id == TPS65910_VDD1 || info->id == TPS65910_VDD2) {
+                               val = index;
+                               return tps65910reg_write(info, TPS65910_I2C_ID0, offset, val);
+                       }
+                       
+                       val &= 0xF3;
+                       val = (index << 2);
+                       val |= 0x01;
+                       if (index < 0) {
+                               printk(KERN_ERR "Invaild voltage for LDO \n");
+                               return -EINVAL;
+                       }
+                       
+                       return tps65910reg_write(info, TPS65910_I2C_ID0, offset, val);
+               }
+       }
+       
+       return -EINVAL;
+}
+
+static int tps65910_ldo_get_voltage(struct regulator_dev *rdev)
+{
+       struct tps65910reg_info      *info = rdev_get_drvdata(rdev);
+       int vsel;
+       u8      offset;
+
+       offset = tps65910reg_find_offset(info->id);
+       vsel = tps65910reg_read(info, TPS65910_I2C_ID0, offset);
+       if (vsel < 0) {
+               printk(KERN_ERR"Unable to read TPS65910 Reg at offset = \
+                       0x%x\n", offset);
+               return -EIO;
+       }
+       
+       /* Get the index of voltage value from Reg and map to table */
+       return get_index_voltage(info->id, vsel);
+}
+
+
+static struct regulator_ops tps65910_ldo_ops = {
+       .list_voltage   = tps65910_ldo_list_voltage,
+       .set_voltage    = tps65910_ldo_set_voltage,
+       .get_voltage    = tps65910_ldo_get_voltage,
+       .enable         = tps65910reg_enable,
+       .disable        = tps65910reg_disable,
+       .is_enabled     = tps65910reg_is_enabled,
+       .set_mode       = tps65910reg_set_mode,
+       .get_status     = tps65910reg_get_status,
+};
+
+static
+int tps65910_fixed_list_voltage(struct regulator_dev *rdev, unsigned index)
+{
+       struct tps65910reg_info      *info = rdev_get_drvdata(rdev);
+
+       return info->min_mV * 1000;
+}
+
+static int tps65910_fixed_get_voltage(struct regulator_dev *rdev)
+{
+       struct tps65910reg_info      *info = rdev_get_drvdata(rdev);
+
+       return info->min_mV * 1000;
+}
+
+static struct regulator_ops tps65910_fixed_ops = {
+       .list_voltage   = tps65910_fixed_list_voltage,
+       .get_voltage    = tps65910_fixed_get_voltage,
+       .enable         = tps65910reg_enable,
+       .disable        = tps65910reg_disable,
+       .is_enabled     = tps65910reg_is_enabled,
+       .set_mode       = tps65910reg_set_mode,
+       .get_status     = tps65910reg_get_status,
+};
+
+#define TPS65910_ADJUSTABLE_LDO(label, num, min_mVolts, max_mVolts,\
+                                turnon_delay) { \
+       .id = num, \
+       .table_len = ARRAY_SIZE(label##_VSEL_table), \
+       .table = label##_VSEL_table, \
+       .min_mV = min_mVolts, \
+       .max_mV = max_mVolts, \
+       .delay = turnon_delay, \
+       .desc = { \
+               .name = #label, \
+               .id = TPS65910_##label, \
+               .n_voltages = ARRAY_SIZE(label##_VSEL_table), \
+               .ops = &tps65910_ldo_ops, \
+               .type = REGULATOR_VOLTAGE, \
+               .owner = THIS_MODULE, \
+       }, \
+}
+
+#define TPS65910_FIXED_LDO(label, num, mVolts, turnon_delay) { \
+       .id = num, \
+       .min_mV = mVolts, \
+       .delay = turnon_delay, \
+       .desc = { \
+               .name = #label, \
+               .id = TPS65910_##label, \
+               .n_voltages = 1, \
+               .ops = &tps65910_fixed_ops, \
+               .type = REGULATOR_VOLTAGE, \
+               .owner = THIS_MODULE, \
+       }, \
+}
+
+/*
+ * We list regulators here if systems need some level of
+ * software control over them after boot.
+ */
+static struct tps65910reg_info tps65910_regs[] = {
+               
+       TPS65910_ADJUSTABLE_LDO(VDD1, TPS65910_VDD1, 950, 1400, 1500),
+       TPS65910_FIXED_LDO(VDD2, TPS65910_VDD2, 1200, 1500),
+       TPS65910_FIXED_LDO(VIO, TPS65910_VIO, 3300, 3300),
+       
+       TPS65910_FIXED_LDO(VDD3, TPS65910_VDD3, 5000, 200),
+       
+       TPS65910_FIXED_LDO(VDIG1, TPS65910_VDIG1, 2700, 2700),
+       TPS65910_FIXED_LDO(VDIG2, TPS65910_VDIG2, 1200, 1800),
+       TPS65910_FIXED_LDO(VAUX33, TPS65910_VAUX33, 3300, 3300),
+       TPS65910_FIXED_LDO(VMMC, TPS65910_VMMC, 3000, 3300),
+       TPS65910_FIXED_LDO(VAUX1, TPS65910_VAUX1, 2800, 3300),
+       TPS65910_FIXED_LDO(VAUX2, TPS65910_VAUX1, 2900, 3300),
+       TPS65910_FIXED_LDO(VDAC, TPS65910_VDAC, 1800, 2850),
+       TPS65910_FIXED_LDO(VPLL, TPS65910_VPLL, 2500, 2500),
+};
+
+static int tps65910_regulator_probe(struct platform_device *pdev)
+{
+       int                             i;
+       struct tps65910reg_info         *info;
+       struct regulator_init_data      *initdata;
+       struct regulation_constraints   *c;
+       struct regulator_dev            *rdev;
+
+       
+       DBG("%s\n", __FUNCTION__);
+       for (i = 0, info = NULL; i < ARRAY_SIZE(tps65910_regs); i++) {
+               if (tps65910_regs[i].desc.id != pdev->id)
+                       continue;
+               info = tps65910_regs + i;
+               break;
+       }
+       if (!info)
+               return -ENODEV;
+
+       DBG("%s: reguloter(%s) id=%d\n", __FUNCTION__, info->desc.name, info->id);
+
+       initdata = pdev->dev.platform_data;
+       if (!initdata)
+               return -EINVAL;
+
+       /* Constrain board-specific capabilities according to what
+        * this driver and the chip itself can actually do.
+        */
+       c = &initdata->constraints;
+       c->valid_modes_mask &= REGULATOR_MODE_NORMAL | REGULATOR_MODE_STANDBY;
+       c->valid_ops_mask &= REGULATOR_CHANGE_VOLTAGE
+               | REGULATOR_CHANGE_MODE
+               | REGULATOR_CHANGE_STATUS;
+
+       switch (pdev->id) {
+       case TPS65910_REG_VDD1:
+       case TPS65910_REG_VIO:
+       case TPS65910_REG_VDD2:
+       case TPS65910_REG_VPLL:
+       case TPS65910_REG_VDIG2:
+               c->always_on = true;
+               break;
+       default:
+               break;
+       }
+
+       rdev = regulator_register(&info->desc, &pdev->dev, initdata, info);
+
+       if (IS_ERR(rdev)) {
+               dev_err(&pdev->dev, "can't register %s, %ld\n",
+                               info->desc.name, PTR_ERR(rdev));
+               return PTR_ERR(rdev);
+       }
+       platform_set_drvdata(pdev, rdev);
+
+       DBG("%s: reguloter register OK.\n", __FUNCTION__);
+       return 0;
+}
+
+static int __devexit tps65910_regulator_remove(struct platform_device *pdev)
+{
+       regulator_unregister(platform_get_drvdata(pdev));
+       return 0;
+}
+
+static struct platform_driver tps65910_regulator_driver = {
+       .probe          = tps65910_regulator_probe,
+       .remove         = tps65910_regulator_remove,
+       .driver.name    = "tps65910_regulator",
+       .driver.owner   = THIS_MODULE,
+};
+
+static int __init tps65910_regulator_init(void)
+{
+       return platform_driver_register(&tps65910_regulator_driver);
+}
+module_init(tps65910_regulator_init);
+
+static void __exit tps65910_regulator_exit(void)
+{
+       platform_driver_unregister(&tps65910_regulator_driver);
+}
+module_exit(tps65910_regulator_exit)
+
+MODULE_AUTHOR("cwz <cwz@rock-chips.com>");
+MODULE_DESCRIPTION("TPS65910 voltage regulator driver");
+MODULE_LICENSE("GPL");
index 9a1495575e224375a2e389824818a5ef7822869e..3c6c44b138ace3aedbd76e48f0eccdcdb79f3f9d 100755 (executable)
@@ -294,6 +294,13 @@ config RTC_DRV_TWL4030
          This driver can also be built as a module. If so, the module
          will be called rtc-twl4030.
 
+config RTC_DRV_TPS65910
+       boolean "TI TPS65910"
+       depends on RTC_CLASS && TPS65910_CORE
+       help
+         If you say yes here you get support for the RTC on the
+         TPS65910 family chips, used mostly with OMAP3/AM35xx platforms.
+
 config RTC_DRV_S35390A
        tristate "Seiko Instruments S-35390A"
        select BITREVERSE
index a0ec07e5ab2c44958df68772060906b31954518d..984c79a950497bc5b928e9ac9bbfd27b70c3280f 100755 (executable)
@@ -82,6 +82,7 @@ obj-$(CONFIG_RTC_DRV_STMP)    += rtc-stmp3xxx.o
 obj-$(CONFIG_RTC_DRV_SUN4V)    += rtc-sun4v.o
 obj-$(CONFIG_RTC_DRV_TEST)     += rtc-test.o
 obj-$(CONFIG_RTC_DRV_TWL4030)  += rtc-twl4030.o
+obj-$(CONFIG_RTC_DRV_TPS65910) += rtc-tps65910.o
 obj-$(CONFIG_RTC_DRV_TX4939)   += rtc-tx4939.o
 obj-$(CONFIG_RTC_DRV_V3020)    += rtc-v3020.o
 obj-$(CONFIG_RTC_DRV_VR41XX)   += rtc-vr41xx.o
diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c
new file mode 100644 (file)
index 0000000..4b7666d
--- /dev/null
@@ -0,0 +1,695 @@
+/*
+ * rtc-tps65910.c -- TPS65910 Real Time Clock interface
+ *
+ * Copyright (C) 2010 Mistral Solutions Pvt Ltd. <www.mistralsolutions.com>
+ * Author: Umesh K <umeshk@mistralsolutions.com>
+ *
+ * Based on rtc-twl.c
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/i2c/tps65910.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+
+#if 0
+#define DBG(x...)      printk(KERN_INFO x)
+#else
+#define DBG(x...)
+#endif
+
+/* RTC Definitions */
+/* RTC_CTRL_REG bitfields */
+#define BIT_RTC_CTRL_REG_STOP_RTC_M            0x01
+#define BIT_RTC_CTRL_REG_ROUND_30S_M           0x02
+#define BIT_RTC_CTRL_REG_AUTO_COMP_M           0x04
+#define BIT_RTC_CTRL_REG_MODE_12_24_M          0x08
+#define BIT_RTC_CTRL_REG_TEST_MODE_M           0x10
+#define BIT_RTC_CTRL_REG_SET_32_COUNTER_M      0x20
+#define BIT_RTC_CTRL_REG_GET_TIME_M            0x40
+#define BIT_RTC_CTRL_REG_RTC_V_OPT_M           0x80
+
+/* RTC_STATUS_REG bitfields */
+#define BIT_RTC_STATUS_REG_RUN_M               0x02
+#define BIT_RTC_STATUS_REG_1S_EVENT_M          0x04
+#define BIT_RTC_STATUS_REG_1M_EVENT_M          0x08
+#define BIT_RTC_STATUS_REG_1H_EVENT_M          0x10
+#define BIT_RTC_STATUS_REG_1D_EVENT_M          0x20
+#define BIT_RTC_STATUS_REG_ALARM_M             0x40
+#define BIT_RTC_STATUS_REG_POWER_UP_M          0x80
+
+/* RTC_INTERRUPTS_REG bitfields */
+#define BIT_RTC_INTERRUPTS_REG_EVERY_M         0x03
+#define BIT_RTC_INTERRUPTS_REG_IT_TIMER_M      0x04
+#define BIT_RTC_INTERRUPTS_REG_IT_ALARM_M      0x08
+
+/* DEVCTRL bitfields */
+#define BIT_RTC_PWDN                           0x40
+
+/* REG_SECONDS_REG through REG_YEARS_REG is how many registers? */
+#define ALL_TIME_REGS                          6
+
+/*
+ * Supports 1 byte read from TPS65910 RTC register.
+ */
+static int tps65910_rtc_read_u8(u8 *data, u8 reg)
+{
+       int ret;
+
+       ret = tps65910_i2c_read_u8(TPS65910_I2C_ID0, data, reg);
+
+       if (ret < 0)
+               pr_err("tps65910_rtc: Could not read TPS65910"
+                               "register %X - error %d\n", reg, ret);
+       return ret;
+}
+
+/*
+ * Supports 1 byte write to TPS65910 RTC registers.
+ */
+static int tps65910_rtc_write_u8(u8 data, u8 reg)
+{
+       int ret;
+
+       ret = tps65910_i2c_write_u8(TPS65910_I2C_ID0, data, reg);
+       if (ret < 0)
+               pr_err("tps65910_rtc: Could not write TPS65910"
+                               "register %X - error %d\n", reg, ret);
+       return ret;
+}
+
+/*
+ * Cache the value for timer/alarm interrupts register; this is
+ * only changed by callers holding rtc ops lock (or resume).
+ */
+static unsigned char rtc_irq_bits;
+
+/*
+ * Enable 1/second update and/or alarm interrupts.
+ */
+static int set_rtc_irq_bit(unsigned char bit)
+{
+       unsigned char val;
+       int ret;
+
+       val = rtc_irq_bits | bit;
+       val |= bit;
+       ret = tps65910_rtc_write_u8(val, TPS65910_REG_RTC_INTERRUPTS);
+       if (ret == 0)
+               rtc_irq_bits = val;
+
+       return ret;
+}
+
+/*
+ * Disable update and/or alarm interrupts.
+ */
+static int mask_rtc_irq_bit(unsigned char bit)
+{
+       unsigned char val;
+       int ret;
+
+       val = rtc_irq_bits & ~bit;
+       ret = tps65910_rtc_write_u8(val, TPS65910_REG_RTC_INTERRUPTS);
+       if (ret == 0)
+               rtc_irq_bits = val;
+
+       return ret;
+}
+
+static int tps65910_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)
+{
+       int ret;
+
+       if (enabled)
+               ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+       else
+               ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+
+       return ret;
+}
+
+static int tps65910_rtc_update_irq_enable(struct device *dev, unsigned enabled)
+{
+       int ret;
+
+       if (enabled)
+               ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
+       else
+               ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
+
+       return ret;
+}
+
+#if 1 /* Debugging periodic interrupts */
+/*
+ * We will just handle setting the frequency and make use the framework for
+ * reading the periodic interupts.
+ *
+ * @freq: Current periodic IRQ freq:
+ * bit 0: every second
+ * bit 1: every minute
+ * bit 2: every hour
+ * bit 3: every day
+ */
+
+static int tps65910_rtc_irq_set_freq(struct device *dev, int freq)
+{
+       struct rtc_device *rtc = dev_get_drvdata(dev);
+
+       if (freq < 0 || freq > 3)
+               return -EINVAL;
+
+       rtc->irq_freq = freq;
+       /* set rtc irq freq to user defined value */
+       set_rtc_irq_bit(freq);
+
+       return 0;
+}
+#endif
+
+/*
+ * Gets current TPS65910 RTC time and date parameters.
+ *
+ * The RTC's time/alarm representation is not what gmtime(3) requires
+ * Linux to use:
+ *
+ *  - Months are 1..12 vs Linux 0-11
+ *  - Years are 0..99 vs Linux 1900..N (we assume 21st century)
+ */
+static int tps65910_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       unsigned char rtc_data[ALL_TIME_REGS + 1];
+       int ret;
+       u8 save_control;
+
+       tps65910_rtc_read_u8(&save_control, TPS65910_REG_RTC_CTRL);
+       ret = tps65910_rtc_read_u8(&save_control, TPS65910_REG_RTC_CTRL);
+       if (ret < 0)
+               return ret;
+
+       save_control &= ~BIT_RTC_CTRL_REG_RTC_V_OPT_M;
+
+       ret = tps65910_rtc_write_u8(save_control, TPS65910_REG_RTC_CTRL);
+       if (ret < 0)
+               return ret;
+
+       ret = tps65910_rtc_read_u8(&rtc_data[0], TPS65910_REG_SECONDS);
+       if (ret < 0) {
+               dev_err(dev, "rtc_read_time error %d\n", ret);
+               return ret;
+       }
+       ret = tps65910_rtc_read_u8(&rtc_data[1], TPS65910_REG_MINUTES);
+       if (ret < 0) {
+               dev_err(dev, "rtc_read_time error %d\n", ret);
+               return ret;
+       }
+       ret = tps65910_rtc_read_u8(&rtc_data[2], TPS65910_REG_HOURS);
+       if (ret < 0) {
+               dev_err(dev, "rtc_read_time error %d\n", ret);
+               return ret;
+       }
+       ret = tps65910_rtc_read_u8(&rtc_data[3], TPS65910_REG_DAYS);
+       if (ret < 0) {
+               dev_err(dev, "rtc_read_time error %d\n", ret);
+               return ret;
+       }
+       ret = tps65910_rtc_read_u8(&rtc_data[4], TPS65910_REG_MONTHS);
+       if (ret < 0) {
+               dev_err(dev, "rtc_read_time error %d\n", ret);
+               return ret;
+       }
+       ret = tps65910_rtc_read_u8(&rtc_data[5], TPS65910_REG_YEARS);
+       if (ret < 0) {
+               dev_err(dev, "rtc_read_time error %d\n", ret);
+               return ret;
+       }
+
+       tm->tm_sec = bcd2bin(rtc_data[0]);
+       tm->tm_min = bcd2bin(rtc_data[1]);
+       tm->tm_hour = bcd2bin(rtc_data[2]);
+       tm->tm_mday = bcd2bin(rtc_data[3]);
+       tm->tm_mon = bcd2bin(rtc_data[4]) - 1;
+       tm->tm_year = bcd2bin(rtc_data[5]) + 100;
+       
+       DBG("%s [%d]tm_wday=%d \n",__FUNCTION__,__LINE__,tm->tm_wday);
+       DBG("%s [%d]tm_sec=%d \n",__FUNCTION__,__LINE__,tm->tm_sec);
+       DBG("%s [%d]tm_min=%d \n",__FUNCTION__,__LINE__,tm->tm_min);
+       DBG("%s [%d]tm_hour=%d \n",__FUNCTION__,__LINE__,tm->tm_hour);
+       DBG("%s [%d]tm_mday=%d \n",__FUNCTION__,__LINE__,tm->tm_mday);
+       DBG("%s [%d]tm_mon=%d \n",__FUNCTION__,__LINE__,tm->tm_mon);
+       DBG("%s [%d]tm_year=%d \n",__FUNCTION__,__LINE__,tm->tm_year);
+
+       return ret;
+}
+
+static int tps65910_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       unsigned char save_control;
+       unsigned char rtc_data[ALL_TIME_REGS + 1];
+       int ret;
+
+       DBG("%s [%d]tm_wday=%d \n",__FUNCTION__,__LINE__,tm->tm_wday);
+       DBG("%s [%d]tm_sec=%d \n",__FUNCTION__,__LINE__,tm->tm_sec);
+       DBG("%s [%d]tm_min=%d \n",__FUNCTION__,__LINE__,tm->tm_min);
+       DBG("%s [%d]tm_hour=%d \n",__FUNCTION__,__LINE__,tm->tm_hour);
+       DBG("%s [%d]tm_mday=%d \n",__FUNCTION__,__LINE__,tm->tm_mday);
+       DBG("%s [%d]tm_mon=%d \n",__FUNCTION__,__LINE__,tm->tm_mon);
+       DBG("%s [%d]tm_year=%d \n",__FUNCTION__,__LINE__,tm->tm_year);
+
+       rtc_data[1] = bin2bcd(tm->tm_sec);
+       rtc_data[2] = bin2bcd(tm->tm_min);
+       rtc_data[3] = bin2bcd(tm->tm_hour);
+       rtc_data[4] = bin2bcd(tm->tm_mday);
+       rtc_data[5] = bin2bcd(tm->tm_mon + 1);
+       rtc_data[6] = bin2bcd(tm->tm_year - 100);
+
+       /*Dummy read*/
+       ret = tps65910_rtc_read_u8(&save_control, TPS65910_REG_RTC_CTRL);
+
+       /* Stop RTC while updating the TC registers */
+       ret = tps65910_rtc_read_u8(&save_control, TPS65910_REG_RTC_CTRL);
+       if (ret < 0)
+               goto out;
+
+       save_control &= ~BIT_RTC_CTRL_REG_STOP_RTC_M;
+
+       tps65910_rtc_write_u8(save_control, TPS65910_REG_RTC_CTRL);
+
+       /* update all the time registers in one shot */
+       ret = tps65910_rtc_write_u8(rtc_data[1], TPS65910_REG_SECONDS);
+       if (ret < 0) {
+               dev_err(dev, "rtc_write_time error %d\n", ret);
+               return ret;
+       }
+       ret = tps65910_rtc_write_u8(rtc_data[2], TPS65910_REG_MINUTES);
+       if (ret < 0) {
+               dev_err(dev, "rtc_write_time error %d\n", ret);
+               return ret;
+       }
+       ret = tps65910_rtc_write_u8(rtc_data[3], TPS65910_REG_HOURS);
+       if (ret < 0) {
+               dev_err(dev, "rtc_write_time error %d\n", ret);
+               return ret;
+       }
+       ret = tps65910_rtc_write_u8(rtc_data[4], TPS65910_REG_DAYS);
+       if (ret < 0) {
+               dev_err(dev, "rtc_write_time error %d\n", ret);
+               return ret;
+       }
+       ret = tps65910_rtc_write_u8(rtc_data[5], TPS65910_REG_MONTHS);
+       if (ret < 0) {
+               dev_err(dev, "rtc_write_time error %d\n", ret);
+               return ret;
+       }
+       ret = tps65910_rtc_write_u8(rtc_data[6], TPS65910_REG_YEARS);
+       if (ret < 0) {
+               dev_err(dev, "rtc_write_time error %d\n", ret);
+               return ret;
+       }
+
+       /*Dummy read*/
+       ret = tps65910_rtc_read_u8(&save_control, TPS65910_REG_RTC_CTRL);
+
+       ret = tps65910_rtc_read_u8(&save_control, TPS65910_REG_RTC_CTRL);
+       if (ret < 0)
+               goto out;
+       /* Start back RTC */
+       save_control |= BIT_RTC_CTRL_REG_STOP_RTC_M;
+       ret = tps65910_rtc_write_u8(save_control, TPS65910_REG_RTC_CTRL);
+
+out:
+       return ret;
+}
+
+/*
+ * Gets current TPS65910 RTC alarm time.
+ */
+static int tps65910_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+       unsigned char rtc_data[ALL_TIME_REGS + 1];
+       int ret;
+
+       ret = tps65910_rtc_read_u8(&rtc_data[0], TPS65910_REG_ALARM_SECONDS);
+       if (ret < 0) {
+               dev_err(dev, "rtc_read_time error %d\n", ret);
+               return ret;
+       }
+       ret = tps65910_rtc_read_u8(&rtc_data[1], TPS65910_REG_ALARM_MINUTES);
+       if (ret < 0) {
+               dev_err(dev, "rtc_read_time error %d\n", ret);
+               return ret;
+       }
+       ret = tps65910_rtc_read_u8(&rtc_data[2], TPS65910_REG_ALARM_HOURS);
+       if (ret < 0) {
+               dev_err(dev, "rtc_read_time error %d\n", ret);
+               return ret;
+       }
+       ret = tps65910_rtc_read_u8(&rtc_data[3], TPS65910_REG_ALARM_DAYS);
+       if (ret < 0) {
+               dev_err(dev, "rtc_read_time error %d\n", ret);
+               return ret;
+       }
+       ret = tps65910_rtc_read_u8(&rtc_data[4], TPS65910_REG_ALARM_MONTHS);
+       if (ret < 0) {
+               dev_err(dev, "rtc_read_time error %d\n", ret);
+               return ret;
+       }
+       ret = tps65910_rtc_read_u8(&rtc_data[5], TPS65910_REG_ALARM_YEARS);
+       if (ret < 0) {
+               dev_err(dev, "rtc_read_time error %d\n", ret);
+               return ret;
+       }
+
+       /* some of these fields may be wildcard/"match all" */
+       alm->time.tm_sec = bcd2bin(rtc_data[0]);
+       alm->time.tm_min = bcd2bin(rtc_data[1]);
+       alm->time.tm_hour = bcd2bin(rtc_data[2]);
+       alm->time.tm_mday = bcd2bin(rtc_data[3]);
+       alm->time.tm_mon = bcd2bin(rtc_data[4]) - 1;
+       alm->time.tm_year = bcd2bin(rtc_data[5]) + 100;
+
+       /* report cached alarm enable state */
+       if (rtc_irq_bits & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M)
+               alm->enabled = 1;
+
+       return ret;
+}
+
+static int tps65910_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+       unsigned char alarm_data[ALL_TIME_REGS + 1];
+       int ret;
+
+       ret = tps65910_rtc_alarm_irq_enable(dev, 0);
+       if (ret)
+               goto out;
+
+       alarm_data[1] = bin2bcd(alm->time.tm_sec);
+       alarm_data[2] = bin2bcd(alm->time.tm_min);
+       alarm_data[3] = bin2bcd(alm->time.tm_hour);
+       alarm_data[4] = bin2bcd(alm->time.tm_mday);
+       alarm_data[5] = bin2bcd(alm->time.tm_mon + 1);
+       alarm_data[6] = bin2bcd(alm->time.tm_year - 100);
+
+       /* update all the alarm registers in one shot */
+       ret = tps65910_rtc_write_u8(alarm_data[1], TPS65910_REG_ALARM_SECONDS);
+       if (ret < 0) {
+               dev_err(dev, "rtc_write_time error %d\n", ret);
+               return ret;
+       }
+       ret = tps65910_rtc_write_u8(alarm_data[2], TPS65910_REG_ALARM_MINUTES);
+       if (ret < 0) {
+               dev_err(dev, "rtc_write_time error %d\n", ret);
+               return ret;
+       }
+       ret = tps65910_rtc_write_u8(alarm_data[3], TPS65910_REG_ALARM_HOURS);
+       if (ret < 0) {
+               dev_err(dev, "rtc_write_time error %d\n", ret);
+               return ret;
+       }
+       ret = tps65910_rtc_write_u8(alarm_data[4], TPS65910_REG_ALARM_DAYS);
+       if (ret < 0) {
+               dev_err(dev, "rtc_write_time error %d\n", ret);
+               return ret;
+       }
+       ret = tps65910_rtc_write_u8(alarm_data[5], TPS65910_REG_ALARM_MONTHS);
+       if (ret < 0) {
+               dev_err(dev, "rtc_write_time error %d\n", ret);
+               return ret;
+       }
+       ret = tps65910_rtc_write_u8(alarm_data[6], TPS65910_REG_ALARM_YEARS);
+       if (ret < 0) {
+               dev_err(dev, "rtc_write_time error %d\n", ret);
+               return ret;
+       }
+
+       if (alm->enabled)
+               ret = tps65910_rtc_alarm_irq_enable(dev, 1);
+out:
+       return ret;
+}
+
+
+struct work_struct rtc_wq;
+unsigned long rtc_events;
+struct rtc_device *global_rtc;
+
+void  rtc_work(void  *data)
+{
+
+       int res;
+       u8 rd_reg;
+       unsigned long events = 0;
+
+       res = tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_INT_STS);
+
+       if (res < 0)
+               goto out;
+       /*
+        * Figure out source of interrupt: ALARM or TIMER in RTC_STATUS_REG.
+        * only one (ALARM or RTC) interrupt source may be enabled
+        * at time, we also could check our results
+        * by reading RTS_INTERRUPTS_REGISTER[IT_TIMER,IT_ALARM]
+        */
+       if (rd_reg & TPS65910_RTC_ALARM_IT) {
+               res = tps65910_rtc_write_u8(rd_reg | TPS65910_RTC_ALARM_IT,
+                               TPS65910_REG_INT_STS);
+               if (res < 0)
+                       goto out;
+
+               /*Dummy read -- mandatory for status register*/
+               res = tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_RTC_STATUS);
+               mdelay(100);
+               res = tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_RTC_STATUS);
+               res = tps65910_rtc_write_u8(rd_reg, TPS65910_REG_RTC_STATUS);
+
+               rtc_events |= RTC_IRQF | RTC_AF;
+       } else if (rd_reg & TPS65910_RTC_PERIOD_IT) {
+               res = tps65910_rtc_write_u8(rd_reg | TPS65910_RTC_PERIOD_IT,
+                               TPS65910_REG_INT_STS);
+               if (res < 0)
+                       goto out;
+
+               /*Dummy read -- mandatory for status register*/
+               res = tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_RTC_STATUS);
+               mdelay(100);
+               res = tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_RTC_STATUS);
+               rd_reg &= 0xC3;
+               res = tps65910_rtc_write_u8(rd_reg, TPS65910_REG_RTC_STATUS);
+               rtc_events |= RTC_IRQF | RTC_UF;
+       }
+out:
+       /* Notify RTC core on event */
+       events = rtc_events;
+       rtc_update_irq(global_rtc, 1, events);
+}
+
+static struct rtc_class_ops tps65910_rtc_ops = {
+       .read_time      = tps65910_rtc_read_time,
+       .set_time       = tps65910_rtc_set_time,
+       .read_alarm     = tps65910_rtc_read_alarm,
+       .set_alarm      = tps65910_rtc_set_alarm,
+       .alarm_irq_enable = tps65910_rtc_alarm_irq_enable,
+       .update_irq_enable = tps65910_rtc_update_irq_enable,
+       .irq_set_freq   = tps65910_rtc_irq_set_freq,
+};
+
+static int __devinit tps65910_rtc_probe(struct platform_device *pdev)
+{
+       struct rtc_device *rtc;
+       int ret = 0;
+       u8 rd_reg;
+       struct rtc_time tm_def = {      //      2011.1.1 12:00 Saturday
+               .tm_wday = 6,
+               .tm_year = 111,
+               .tm_mon = 0,
+               .tm_mday = 1,
+               .tm_hour = 12,
+               .tm_min = 0,
+               .tm_sec = 0,
+       };
+       
+       rtc = rtc_device_register(pdev->name,
+                       &pdev->dev, &tps65910_rtc_ops, THIS_MODULE);
+
+       if (IS_ERR(rtc)) {
+               ret = PTR_ERR(rtc);
+               dev_err(&pdev->dev, "can't register TPS65910 RTC device,\
+                                        err %ld\n", PTR_ERR(rtc));
+               goto out0;
+
+       }
+       printk(KERN_INFO "TPS65910 RTC device successfully registered\n");
+
+       platform_set_drvdata(pdev, rtc);
+
+       /* Take rtc out of reset */
+       tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_DEVCTRL);
+       rd_reg &= ~BIT_RTC_PWDN;
+       ret = tps65910_rtc_write_u8(rd_reg, TPS65910_REG_DEVCTRL);
+
+       /* Dummy read to ensure that the register gets updated.
+        * Please refer tps65910 TRM table:25 for details
+        */
+       tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_RTC_STATUS);
+
+       ret = tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_RTC_STATUS);
+       if (ret < 0) {
+               printk(KERN_ERR "TPS65910 RTC STATUS REG READ FAILED\n");
+               goto out1;
+       }
+
+       if (rd_reg & BIT_RTC_STATUS_REG_POWER_UP_M) {
+               dev_warn(&pdev->dev, "Power up reset detected.\n");
+               //      cwz:if rtc power up reset, set default time.
+               printk(KERN_INFO "TPS65910 RTC set to default time\n");
+               tps65910_rtc_set_time(rtc, &tm_def);
+       }
+       
+       if (rd_reg & BIT_RTC_STATUS_REG_ALARM_M)
+               dev_warn(&pdev->dev, "Pending Alarm interrupt detected.\n");
+
+       /* Clear RTC Power up reset and pending alarm interrupts */
+       ret = tps65910_rtc_write_u8(rd_reg, TPS65910_REG_RTC_STATUS);
+       if (ret < 0)
+               goto out1;
+       ret = tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_INT_STS);
+       if (ret < 0) {
+               printk(KERN_ERR "TPS65910 RTC STATUS REG READ FAILED\n");
+               goto out1;
+       }
+
+       if (rd_reg & 0x40) {
+               printk(KERN_INFO "pending alarm interrupt!!! clearing!!!");
+               tps65910_rtc_write_u8(rd_reg, TPS65910_REG_INT_STS);
+       }
+
+       global_rtc = rtc;
+
+       /* Link RTC IRQ handler to TPS65910 Core */
+       tps65910_add_irq_work(TPS65910_RTC_ALARM_IRQ, rtc_work);
+       tps65910_add_irq_work(TPS65910_RTC_PERIOD_IRQ, rtc_work);
+
+       /* Check RTC module status, Enable if it is off */
+       ret = tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_RTC_CTRL);
+       if (ret < 0)
+               goto out1;
+
+       if (!(rd_reg & BIT_RTC_CTRL_REG_STOP_RTC_M)) {          
+               dev_info(&pdev->dev, "Enabling TPS65910-RTC.\n");
+               //      cwz:if rtc stop, set default time, then enable rtc
+               printk(KERN_INFO "TPS65910 RTC set to default time\n");
+               tps65910_rtc_set_time(rtc, &tm_def);
+               rd_reg |= BIT_RTC_CTRL_REG_STOP_RTC_M;
+               ret = tps65910_rtc_write_u8(rd_reg, TPS65910_REG_RTC_CTRL);
+               if (ret < 0)
+                       goto out1;
+       }
+
+       /* init cached IRQ enable bits */
+       ret = tps65910_rtc_read_u8(&rtc_irq_bits, TPS65910_REG_RTC_INTERRUPTS);
+       if (ret < 0)
+               goto out1;
+
+       tps65910_rtc_write_u8(0x3F, TPS65910_REG_INT_MSK);
+       return ret;
+
+out1:
+       rtc_device_unregister(rtc);
+out0:
+       return ret;
+}
+
+/*
+ * Disable all TPS65910 RTC module interrupts.
+ * Sets status flag to free.
+ */
+static int __devexit tps65910_rtc_remove(struct platform_device *pdev)
+{
+       /* leave rtc running, but disable irqs */
+       struct rtc_device *rtc = platform_get_drvdata(pdev);
+       int irq = platform_get_irq(pdev, 0);
+
+       mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+       mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
+
+
+       free_irq(irq, rtc);
+
+       rtc_device_unregister(rtc);
+       platform_set_drvdata(pdev, NULL);
+       return 0;
+}
+
+static void tps65910_rtc_shutdown(struct platform_device *pdev)
+{
+       /* mask timer interrupts, but leave alarm interrupts on to enable
+        * power-on when alarm is triggered
+        */
+       mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
+}
+
+#ifdef CONFIG_PM
+
+static unsigned char irqstat;
+
+static
+int tps65910_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       irqstat = rtc_irq_bits;
+       mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
+       return 0;
+}
+
+static int tps65910_rtc_resume(struct platform_device *pdev)
+{
+       set_rtc_irq_bit(irqstat);
+       return 0;
+}
+
+#else
+#define tps65910_rtc_suspend NULL
+#define tps65910_rtc_resume  NULL
+#endif
+
+
+static struct platform_driver tps65910rtc_driver = {
+       .probe          = tps65910_rtc_probe,
+       .remove         = __devexit_p(tps65910_rtc_remove),
+       .shutdown       = tps65910_rtc_shutdown,
+       .suspend        = tps65910_rtc_suspend,
+       .resume         = tps65910_rtc_resume,
+       .driver         = {
+               .owner  = THIS_MODULE,
+               .name   = "tps65910_rtc",
+       },
+};
+static int __init tps65910_rtc_init(void)
+{
+       return platform_driver_register(&tps65910rtc_driver);
+}
+module_init(tps65910_rtc_init);
+
+static void __exit tps65910_rtc_exit(void)
+{
+       platform_driver_unregister(&tps65910rtc_driver);
+}
+module_exit(tps65910_rtc_exit);
+
+MODULE_ALIAS("platform:tps65910_rtc");
+MODULE_AUTHOR("cwz  <cwz@rockchips.com");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/i2c/tps65910.h b/include/linux/i2c/tps65910.h
new file mode 100644 (file)
index 0000000..d6deb36
--- /dev/null
@@ -0,0 +1,275 @@
+/* linux/i2c/tps65910.h
+ *
+ *  TPS65910 Power Management Device Definitions.
+ *
+ * Based on include/linux/i2c/twl.h
+ *
+ * Copyright (C) 2010 Mistral Solutions Pvt Ltd <www.mistralsolutions.com>
+ *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __LINUX_I2C_TPS65910_H
+#define __LINUX_I2C_TPS65910_H
+
+#define TPS65910_NUM_SLAVES    1
+/* I2C Slave Address 7-bit */
+#define        TPS65910_I2C_ID0        0x2D /* general-purpose */
+#define        TPS65910_I2C_ID1        0x12 /* Smart Reflex */
+
+/* TPS65910 to host IRQ */
+#define TPS65910_HOST_IRQ      RK29_PIN6_PD3
+
+/* TPS65910 MAX GPIOs */
+#define TPS65910_GPIO_MAX      1
+
+/*
+ * ----------------------------------------------------------------------------
+ * Registers, all 8 bits
+ * ----------------------------------------------------------------------------
+ */
+#define        TPS65910_REG_SECONDS            0x00
+#define TPS65910_REG_MINUTES           0x01
+#define TPS65910_REG_HOURS             0x02
+#define TPS65910_REG_DAYS              0x03
+#define TPS65910_REG_MONTHS            0x04
+#define TPS65910_REG_YEARS             0x05
+#define TPS65910_REG_WEEKS             0x06
+#define TPS65910_REG_ALARM_SECONDS     0x08
+#define TPS65910_REG_ALARM_MINUTES     0x09
+#define TPS65910_REG_ALARM_HOURS       0x0A
+#define TPS65910_REG_ALARM_DAYS                0x0B
+#define TPS65910_REG_ALARM_MONTHS      0x0C
+#define TPS65910_REG_ALARM_YEARS       0x0D
+
+#define TPS65910_REG_RTC_CTRL          0x10
+#define TPS65910_REG_RTC_STATUS                0x11
+#define TPS65910_REG_RTC_INTERRUPTS    0x12
+#define TPS65910_REG_RTC_COMP_LSB      0x13
+#define TPS65910_REG_RTC_COMP_MSB      0x14
+#define TPS65910_REG_RTC_RES_PROG      0x15
+#define TPS65910_REG_RTC_RESET_STATUS  0x16
+#define TPS65910_REG_BCK1              0x17
+#define TPS65910_REG_BCK2              0x18
+#define TPS65910_REG_BCK3              0x19
+#define TPS65910_REG_BCK4              0x1A
+#define TPS65910_REG_BCK5              0x1B
+#define TPS65910_REG_PUADEN            0x1C
+#define TPS65910_REG_REF               0x1D
+#define TPS65910_REG_VRTC              0x1E
+
+#define TPS65910_REG_VIO               0x20
+#define TPS65910_REG_VDD1              0x21
+#define TPS65910_REG_VDD1_OP           0x22
+#define TPS65910_REG_VDD1_SR           0x23
+#define TPS65910_REG_VDD2              0x24
+#define TPS65910_REG_VDD2_OP           0x25
+#define TPS65910_REG_VDD2_SR           0x26
+#define TPS65910_REG_VDD3              0x27
+
+#define TPS65910_REG_VDIG1             0x30
+#define TPS65910_REG_VDIG2             0x31
+#define TPS65910_REG_VAUX1             0x32
+#define TPS65910_REG_VAUX2             0x33
+#define TPS65910_REG_VAUX33            0x34
+#define TPS65910_REG_VMMC              0x35
+#define TPS65910_REG_VPLL              0x36
+#define TPS65910_REG_VDAC              0x37
+#define TPS65910_REG_THERM             0x38
+#define TPS65910_REG_BBCH              0x39
+
+#define TPS65910_REG_DCDCCTRL          0x3E
+#define TPS65910_REG_DEVCTRL           0x3F
+#define TPS65910_REG_DEVCTRL2          0x40
+#define TPS65910_REG_SLEEP_KEEP_LDO_ON 0x41
+#define TPS65910_REG_SLEEP_KEEP_RES_ON 0x42
+#define TPS65910_REG_SLEEP_SET_LDO_OFF 0x43
+#define TPS65910_REG_SLEEP_SET_RES_OFF 0x44
+#define TPS65910_REG_EN1_LDO_ASS       0x45
+#define TPS65910_REG_EN1_SMPS_ASS      0x46
+#define TPS65910_REG_EN2_LDO_ASS       0x47
+#define TPS65910_REG_EN2_SMPS_ASS      0x48
+#define TPS65910_REG_EN3_LDO_ASS       0x49
+#define TPS65910_REG_SPARE             0x4A
+
+#define TPS65910_REG_INT_STS           0x50
+#define TPS65910_REG_INT_MSK           0x51
+#define TPS65910_REG_INT_STS2          0x52
+#define TPS65910_REG_INT_MSK2          0x53
+#define TPS65910_REG_INT_STS3          0x54
+#define TPS65910_REG_INT_MSK3          0x55
+
+#define TPS65910_REG_GPIO0             0x60
+
+#define TPS65910_REG_JTAGVERNUM                0x80
+
+/* TPS65910 GPIO Specific flags */
+#define TPS65910_GPIO_INT_FALLING      0
+#define TPS65910_GPIO_INT_RISING       1
+
+#define TPS65910_DEBOUNCE_91_5_MS      0
+#define TPS65910_DEBOUNCE_150_MS       1
+
+#define TPS65910_GPIO_PUDIS            (1 << 3)
+#define TPS65910_GPIO_CFG_OUTPUT       (1 << 2)
+
+
+
+/* TPS65910 Interrupt events */
+
+/* RTC Driver */
+#define TPS65910_RTC_ALARM_IT          0x80
+#define TPS65910_RTC_PERIOD_IT         0x40
+
+/*Core Driver */
+#define TPS65910_HOT_DIE_IT            0x20
+#define TPS65910_PWRHOLD_IT            0x10
+#define TPS65910_PWRON_LP_IT           0x08
+#define TPS65910_PWRON_IT              0x04
+#define TPS65910_VMBHI_IT              0x02
+#define TPS65910_VMBGCH_IT             0x01
+
+/* GPIO driver */
+#define TPS65910_GPIO_F_IT             0x02
+#define TPS65910_GPIO_R_IT             0x01
+
+
+#define TPS65910_VRTC_OFFMASK          (1<<3)
+
+/* Back-up battery charger control */
+#define TPS65910_BBCHEN                        0x01
+
+/* Back-up battery charger voltage */
+#define TPS65910_BBSEL_3P0             0x00
+#define TPS65910_BBSEL_2P52            0x02
+#define TPS65910_BBSEL_3P15            0x04
+#define TPS65910_BBSEL_VBAT            0x06
+
+/* DEVCTRL_REG flags */
+#define TPS65910_RTC_PWDNN             0x40
+#define TPS65910_CK32K_CTRL            0x20
+#define TPS65910_SR_CTL_I2C_SEL        0x10
+#define TPS65910_DEV_OFF_RST           0x08
+#define TPS65910_DEV_ON                        0x04
+#define TPS65910_DEV_SLP               0x02
+#define TPS65910_DEV_OFF               0x01
+
+/* DEVCTRL2_REG flags */
+#define TPS65910_DEV2_TSLOT_LENGTH     0x30
+#define TPS65910_DEV2_SLEEPSIG_POL     0x08
+#define TPS65910_DEV2_PWON_LP_OFF      0x04
+#define TPS65910_DEV2_PWON_LP_RST      0x02
+#define TPS65910_DEV2_IT_POL           0x01
+
+/* TPS65910 SMPS/LDO's */
+#define TPS65910_VIO                   0
+#define TPS65910_VDD1                  1
+#define TPS65910_VDD2                  2
+#define TPS65910_VDD3                  3
+/* LDOs */
+#define TPS65910_VDIG1                 4
+#define TPS65910_VDIG2                 5
+#define TPS65910_VAUX33                        6
+#define TPS65910_VMMC                  7
+#define TPS65910_VAUX1                 8
+#define TPS65910_VAUX2                 9
+#define TPS65910_VDAC                  10
+#define TPS65910_VPLL                  11
+/* Internal LDO */
+#define TPS65910_VRTC                  12
+
+/* Number of step-down/up converters available */
+#define TPS65910_NUM_DCDC              4
+
+/* Number of LDO voltage regulators  available */
+#define TPS65910_NUM_LDO               9
+
+/* Number of total regulators available */
+#define TPS65910_NUM_REGULATOR  (TPS65910_NUM_DCDC + TPS65910_NUM_LDO)
+
+
+/* Regulator Supply state */
+#define SUPPLY_STATE_FLAG              0x03
+/* OFF States */
+#define TPS65910_REG_OFF_00            0x00
+#define TPS65910_REG_OFF_10            0x02
+/* OHP - on High Power */
+#define TPS65910_REG_OHP               0x01
+/* OLP - on Low Power */
+#define TPS65910_REG_OLP               0x03
+
+#define TPS65910_MAX_IRQS              10
+#define TPS65910_VMBDCH_IRQ            0
+#define TPS65910_VMBHI_IRQ             1
+#define TPS65910_PWRON_IRQ             2
+#define TPS65910_PWRON_LP_IRQ          3
+#define TPS65910_PWRHOLD_IRQ           4
+#define TPS65910_HOTDIE_IRQ            5
+#define TPS65910_RTC_ALARM_IRQ         6
+#define TPS65910_RTC_PERIOD_IRQ        7
+#define TPS65910_GPIO0_R_IRQ           8
+#define TPS65910_GPIO0_F_IRQ           9
+
+/* TPS65910 has 1 GPIO  */
+struct tps65910_gpio {
+       u8      debounce;
+       u8      pullup_pulldown;
+       u8      gpio_config;  /* Input or output */
+       u8      gpio_val;    /* Output value */
+       int (*gpio_setup)(struct tps65910_gpio *pdata);
+       int (*gpio_taredown)(struct tps65910_gpio *pdata);
+};
+
+struct tps65910_platform_data {
+
+       unsigned irq_num;  /* TPS65910 to Host IRQ Number */
+       struct tps65910_gpio    *gpio;
+
+       /* plaform specific data to be initialised in board file */
+       struct regulator_init_data *vio;
+       struct regulator_init_data *vdd1;
+       struct regulator_init_data *vdd2;
+       struct regulator_init_data *vdd3;
+       struct regulator_init_data *vdig1;
+       struct regulator_init_data *vdig2;
+       struct regulator_init_data *vaux33;
+       struct regulator_init_data *vmmc;
+       struct regulator_init_data *vaux1;
+       struct regulator_init_data *vaux2;
+       struct regulator_init_data *vdac;
+       struct regulator_init_data *vpll;
+
+       void  (*handlers[TPS65910_MAX_IRQS]) (void  *data);
+       /* Configure TP65910 to board specific usage*/
+       int (*board_tps65910_config)(struct tps65910_platform_data *pdata);
+};
+
+int tps65910_enable_bbch(u8 voltage);
+int tps65910_disable_bbch(void);
+
+int tps65910_remove_irq_work(int irq);
+int tps65910_add_irq_work(int irq, void (*handler)(void *data));
+
+int tps65910_i2c_write_u8(u8 slave_addr, u8 val, u8 reg);
+int tps65910_i2c_read_u8(u8 slave_addr, u8 *val, u8 reg);
+
+#endif /*  __LINUX_I2C_TPS65910_H */
+