rk2928:support pmic tps65910
author张晴 <zhangqing@rock-chips.com>
Thu, 9 Aug 2012 10:07:51 +0000 (18:07 +0800)
committer张晴 <zhangqing@rock-chips.com>
Thu, 9 Aug 2012 10:07:51 +0000 (18:07 +0800)
19 files changed:
arch/arm/configs/rk2928_sdk_defconfig
arch/arm/mach-rk2928/board-rk2928-sdk.c
arch/arm/mach-rk2928/board-rk30-sdk-tps65910.c [new file with mode: 0755]
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpio-tps65910.c [new file with mode: 0755]
drivers/gpio/tps65910-gpio.c [changed mode: 0644->0755]
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/tps65910-irq.c [changed mode: 0644->0755]
drivers/mfd/tps65910.c [changed mode: 0644->0755]
drivers/mfd/tps65911-comparator.c [changed mode: 0644->0755]
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/tps65910-regulator.c [changed mode: 0644->0755]
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-tps65910.c [new file with mode: 0755]
include/linux/mfd/tps65910.h [changed mode: 0644->0755]

index 32ceab278ca3f6482b7743b0846665a6a6f14aca..32f9084f6244a53c817295366de76409ced71feb 100755 (executable)
@@ -247,9 +247,10 @@ CONFIG_SPI_FPGA_GPIO_IRQ_NUM=0
 CONFIG_POWER_SUPPLY=y
 CONFIG_TEST_POWER=y
 # CONFIG_HWMON is not set
 CONFIG_POWER_SUPPLY=y
 CONFIG_TEST_POWER=y
 # CONFIG_HWMON is not set
-CONFIG_MFD_WM831X_I2C=y
+CONFIG_MFD_TPS65910=y
+CONFIG_MFD_TPS65090=y
 CONFIG_REGULATOR=y
 CONFIG_REGULATOR=y
-CONFIG_REGULATOR_WM831X=y
+CONFIG_REGULATOR_TPS65910=y
 CONFIG_MEDIA_SUPPORT=y
 CONFIG_VIDEO_DEV=y
 CONFIG_SOC_CAMERA=y
 CONFIG_MEDIA_SUPPORT=y
 CONFIG_VIDEO_DEV=y
 CONFIG_SOC_CAMERA=y
@@ -359,7 +360,7 @@ CONFIG_SDMMC_RK29=y
 CONFIG_SWITCH=y
 CONFIG_SWITCH_GPIO=y
 CONFIG_RTC_CLASS=y
 CONFIG_SWITCH=y
 CONFIG_SWITCH_GPIO=y
 CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_WM831X=y
+CONFIG_TPS65910_RTC=y
 CONFIG_STAGING=y
 CONFIG_ANDROID=y
 CONFIG_ANDROID_BINDER_IPC=y
 CONFIG_STAGING=y
 CONFIG_ANDROID=y
 CONFIG_ANDROID_BINDER_IPC=y
index 06ac44d87620f23af3a85d06e9f7f5995fafb0b7..604a79d7c685f3cdbc3148ebceb41ff5da3f28e8 100755 (executable)
@@ -44,6 +44,8 @@
 #include <linux/regulator/machine.h>
 #include <linux/rfkill-rk.h>
 #include <linux/sensor-dev.h>
 #include <linux/regulator/machine.h>
 #include <linux/rfkill-rk.h>
 #include <linux/sensor-dev.h>
+#include <linux/mfd/tps65910.h>
+#include <linux/regulator/rk29-pwm-regulator.h>
 #if defined(CONFIG_HDMI_RK30)
        #include "../../../drivers/video/rockchip/hdmi/rk_hdmi.h"
 #endif
 #if defined(CONFIG_HDMI_RK30)
        #include "../../../drivers/video/rockchip/hdmi/rk_hdmi.h"
 #endif
@@ -821,6 +823,7 @@ static struct platform_device device_ion = {
        },
 };
 #endif
        },
 };
 #endif
+
 /**************************************************************************************************
  * SDMMC devices,  include the module of SD,MMC,and sdio.noted by xbw at 2012-03-05
 **************************************************************************************************/
 /**************************************************************************************************
  * SDMMC devices,  include the module of SD,MMC,and sdio.noted by xbw at 2012-03-05
 **************************************************************************************************/
@@ -1075,7 +1078,22 @@ static struct i2c_board_info __initdata i2c0_info[] = {
 };
 #endif
 #ifdef CONFIG_I2C1_RK30
 };
 #endif
 #ifdef CONFIG_I2C1_RK30
+#ifdef CONFIG_MFD_TPS65910
+#define TPS65910_HOST_IRQ        RK2928_PIN3_PC6
+#include "board-rk30-sdk-tps65910.c"
+#endif
 static struct i2c_board_info __initdata i2c1_info[] = {
 static struct i2c_board_info __initdata i2c1_info[] = {
+
+#if defined (CONFIG_MFD_TPS65910)
+       {
+        .type           = "tps65910",
+        .addr           = TPS65910_I2C_ID0,
+        .flags          = 0,
+        .irq            = TPS65910_HOST_IRQ,
+       .platform_data = &tps65910_data,
+       },
+#endif
+
 };
 #endif
 #ifdef CONFIG_I2C2_RK30
 };
 #endif
 #ifdef CONFIG_I2C2_RK30
diff --git a/arch/arm/mach-rk2928/board-rk30-sdk-tps65910.c b/arch/arm/mach-rk2928/board-rk30-sdk-tps65910.c
new file mode 100755 (executable)
index 0000000..7ec12c3
--- /dev/null
@@ -0,0 +1,633 @@
+#include <linux/regulator/machine.h>
+#include <linux/i2c/twl.h>
+#include <linux/mfd/tps65910.h>
+#include <mach/sram.h>
+#include <linux/platform_device.h>
+
+#include <mach/gpio.h>
+#include <mach/iomux.h>
+
+#define grf_readl(offset)      readl_relaxed(RK30_GRF_BASE + offset)
+#define grf_writel(v, offset)  do { writel_relaxed(v, RK30_GRF_BASE + offset); dsb(); } while (0)
+
+#define CRU_CLKGATE5_CON_ADDR 0x00e4
+#define GRF_GPIO6L_DIR_ADDR 0x0030
+#define GRF_GPIO6L_DO_ADDR 0x0068
+#define GRF_GPIO6L_EN_ADDR 0x00a0
+#define GPIO6_PB3_DIR_OUT  0x08000800
+#define GPIO6_PB3_DO_LOW  0x08000000
+#define GPIO6_PB3_DO_HIGH  0x08000800
+#define GPIO6_PB3_EN_MASK  0x08000800
+#define GPIO6_PB3_UNEN_MASK  0x08000000
+#define GPIO6_PB1_DIR_OUT  0x02000200
+#define GPIO6_PB1_DO_LOW  0x02000000
+#define GPIO6_PB1_DO_HIGH  0x02000200
+#define GPIO6_PB1_EN_MASK  0x02000200
+#define GPIO6_PB1_UNEN_MASK  0x02000000
+
+#ifdef CONFIG_MFD_TPS65910
+#define PMU_POWER_SLEEP RK2928_PIN3_PD2        
+extern int platform_device_register(struct platform_device *pdev);
+
+int tps65910_pre_init(struct tps65910 *tps65910){
+
+       int val = 0;
+       int i   = 0;
+       int err = -1;
+               
+       printk("%s,line=%d\n", __func__,__LINE__);      
+       gpio_request(PMU_POWER_SLEEP, "NULL");
+       gpio_direction_output(PMU_POWER_SLEEP, GPIO_LOW);
+
+       val = tps65910_reg_read(tps65910, TPS65910_DEVCTRL2);
+       if (val<0) {
+               printk(KERN_ERR "Unable to read TPS65910_DEVCTRL2 reg\n");
+               return val;
+       }
+       /* Set sleep state active high and allow device turn-off after PWRON long press */
+       val |= (DEVCTRL2_SLEEPSIG_POL_MASK | DEVCTRL2_PWON_LP_OFF_MASK);
+
+       err = tps65910_reg_write(tps65910, TPS65910_DEVCTRL2, val);
+       if (err) {
+               printk(KERN_ERR "Unable to write TPS65910_DEVCTRL2 reg\n");
+               return err;
+       }
+        #if 1
+       /* set PSKIP=0 */
+        val = tps65910_reg_read(tps65910, TPS65910_DCDCCTRL);
+        if (val<0) {
+                printk(KERN_ERR "Unable to read TPS65910_DCDCCTRL reg\n");
+                return val;
+        }
+
+       val &= ~DEVCTRL_DEV_OFF_MASK;
+       val &= ~DEVCTRL_DEV_SLP_MASK;
+        err = tps65910_reg_write(tps65910, TPS65910_DCDCCTRL, val);
+        if (err) {
+                printk(KERN_ERR "Unable to write TPS65910_DCDCCTRL reg\n");
+                return err;
+        }
+       #endif
+       /* Set the maxinum load current */
+       /* VDD1 */
+       val = tps65910_reg_read(tps65910, TPS65910_VDD1);
+       if (val<0) {
+               printk(KERN_ERR "Unable to read TPS65910_VDD1 reg\n");
+               return val;
+       }
+
+       val |= (1<<5);          //when 1: 1.5 A
+       val |= (0x07<<2);       //TSTEP[2:0] = 111 : 2.5 mV/|¨¬s(sampling 3 Mhz/5)
+       err = tps65910_reg_write(tps65910, TPS65910_VDD1, val);
+       if (err) {
+               printk(KERN_ERR "Unable to write TPS65910_VDD1 reg\n");
+               return err;
+       }
+
+       /* VDD2 */
+       val = tps65910_reg_read(tps65910, TPS65910_VDD2);
+       if (val<0) {
+               printk(KERN_ERR "Unable to read TPS65910_VDD2 reg\n");
+               return val;
+       }
+
+       val |= (1<<5);          //when 1: 1.5 A
+       err = tps65910_reg_write(tps65910, TPS65910_VDD2, val);
+       if (err) {
+               printk(KERN_ERR "Unable to write TPS65910_VDD2 reg\n");
+               return err;
+       }
+
+       /* VIO */
+       val = tps65910_reg_read(tps65910, TPS65910_VIO);
+       if (val<0) {
+               printk(KERN_ERR "Unable to read TPS65910_VIO reg\n");
+               return -EIO;
+       }
+
+       val |= (1<<6);  //when 01: 1.0 A
+       err = tps65910_reg_write(tps65910, TPS65910_VIO, val);
+       if (err) {
+               printk(KERN_ERR "Unable to write TPS65910_VIO reg\n");
+               return err;
+       }
+       #if 1
+       /* Mask ALL interrupts */
+       err = tps65910_reg_write(tps65910,TPS65910_INT_MSK, 0xFF);
+       if (err) {
+               printk(KERN_ERR "Unable to write TPS65910_INT_MSK reg\n");
+               return err;
+       }
+       
+       err = tps65910_reg_write(tps65910, TPS65910_INT_MSK2, 0x03);
+       if (err) {
+               printk(KERN_ERR "Unable to write TPS65910_INT_MSK2 reg\n");
+               return err;
+       }
+
+       /* Set RTC Power, disable Smart Reflex in DEVCTRL_REG */
+       #if 1
+       val = 0;
+       val |= (DEVCTRL_SR_CTL_I2C_SEL_MASK);
+       err = tps65910_reg_write(tps65910, TPS65910_DEVCTRL, val);
+       if (err) {
+               printk(KERN_ERR "Unable to write TPS65910_DEVCTRL reg\n");
+               return err;
+       }
+       printk(KERN_INFO "TPS65910 Set default voltage.\n");
+       #endif
+       #if 0
+       //read sleep control register  for debug
+       for(i=0; i<6; i++)
+       {
+        err = tps65910_reg_read(tps65910, &val, TPS65910_DEVCTRL+i);
+        if (err) {
+                printk(KERN_ERR "Unable to read TPS65910_DCDCCTRL reg\n");
+                return -EIO;
+        }
+               else
+               printk("%s.......is  0x%04x\n",__FUNCTION__,val);
+       }
+       #endif
+
+       #if 1
+       //sleep control register
+       /*set func when in sleep mode */
+       val = tps65910_reg_read(tps65910, TPS65910_DEVCTRL);
+        if (val<0) {
+                printk(KERN_ERR "Unable to read TPS65910_DCDCCTRL reg\n");
+                return val;
+        }
+       
+       val |= (1 << 1);
+       err = tps65910_reg_write(tps65910, TPS65910_DEVCTRL, val);
+       if (err) {
+               printk(KERN_ERR "Unable to read TPS65910 Reg at offset 0x%x= \
+                               \n", TPS65910_VDIG1);
+               return err;
+       }
+       
+       /* open ldo when in sleep mode */
+        val = tps65910_reg_read(tps65910, TPS65910_SLEEP_KEEP_LDO_ON);
+        if (val<0) {
+                printk(KERN_ERR "Unable to read TPS65910_DCDCCTRL reg\n");
+                return val;
+        }
+       
+       val &= 0;
+       err = tps65910_reg_write(tps65910, TPS65910_SLEEP_KEEP_LDO_ON, val);
+       if (err) {
+               printk(KERN_ERR "Unable to read TPS65910 Reg at offset 0x%x= \
+                               \n", TPS65910_VDIG1);
+               return err;
+       }
+               
+       /*set dc mode when in sleep mode */
+        val = tps65910_reg_read(tps65910, TPS65910_SLEEP_KEEP_RES_ON);
+        if (val<0) {
+                printk(KERN_ERR "Unable to read TPS65910_DCDCCTRL reg\n");
+                return val;
+        }
+       
+       val  |= 0xff;
+       err = tps65910_reg_write(tps65910, TPS65910_SLEEP_KEEP_RES_ON, val);
+       if (err) {
+               printk(KERN_ERR "Unable to read TPS65910 Reg at offset 0x%x= \
+                               \n", TPS65910_VDIG1);
+               return err;
+       }
+       
+       /*close ldo when in sleep mode */
+        val = tps65910_reg_read(tps65910, TPS65910_SLEEP_SET_LDO_OFF);
+        if (val<0) {
+                printk(KERN_ERR "Unable to read TPS65910_DCDCCTRL reg\n");
+                return val;
+        }
+       
+       val |= 0x9B;
+       err = tps65910_reg_write(tps65910, TPS65910_SLEEP_SET_LDO_OFF, val);
+       if (err) {
+               printk(KERN_ERR "Unable to read TPS65910 Reg at offset 0x%x= \
+                               \n", TPS65910_VDIG1);
+               return err;
+       }
+       
+       #endif
+       #if 0
+       //read sleep control register  for debug
+       for(i=0; i<6; i++)
+       {
+        err = tps65910_reg_read(tps65910, &val, TPS65910_DEVCTRL+i);
+        if (err) {
+                printk(KERN_ERR "Unable to read TPS65910_DCDCCTRL reg\n");
+                return -EIO;
+        }
+               else
+               printk("%s.......is  0x%4x\n",__FUNCTION__,val);
+       }
+       #endif
+       #endif
+       
+       printk("%s,line=%d\n", __func__,__LINE__);
+       return 0;
+
+}
+int tps65910_post_init(struct tps65910 *tps65910)
+{
+       struct regulator *dcdc;
+       struct regulator *ldo;
+       printk("%s,line=%d\n", __func__,__LINE__);
+       
+       dcdc = regulator_get(NULL, "vio");      //vcc_io
+       regulator_set_voltage(dcdc, 3300000, 3300000);
+       regulator_enable(dcdc);
+       printk("%s set vio vcc_io=%dmV end\n", __func__, regulator_get_voltage(dcdc));
+       regulator_put(dcdc);
+       udelay(100);
+
+       ldo = regulator_get(NULL, "vpll");      // vcc25
+       regulator_set_voltage(ldo, 2500000, 2500000);
+       regulator_enable(ldo);
+       printk("%s set vpll vcc25=%dmV end\n", __func__, regulator_get_voltage(ldo));
+       regulator_put(ldo);
+       udelay(100);
+
+       ldo = regulator_get(NULL, "vdig2");     // vdd11
+       regulator_set_voltage(ldo, 1200000, 1200000);
+       regulator_enable(ldo);
+       printk("%s set vdig2 vdd11=%dmV end\n", __func__, regulator_get_voltage(ldo));
+       regulator_put(ldo);
+       udelay(100);
+
+       ldo = regulator_get(NULL, "vaux33");     //vcc_tp
+       regulator_set_voltage(ldo, 3300000, 3300000);
+       regulator_enable(ldo);
+       printk("%s set vaux33 vcc_tp=%dmV end\n", __func__, regulator_get_voltage(ldo));
+       regulator_put(ldo);
+       udelay(100);
+       
+       dcdc = regulator_get(NULL, "vdd_cpu");  //vdd_cpu
+       regulator_set_voltage(dcdc, 1200000, 1200000);
+       regulator_enable(dcdc);
+       printk("%s set vdd1 vdd_cpu=%dmV end\n", __func__, regulator_get_voltage(dcdc));
+       regulator_put(dcdc);
+       udelay(100);
+       
+       dcdc = regulator_get(NULL, "vdd2");     //vcc_ddr 
+       regulator_set_voltage(dcdc, 1200000, 1200000);  // 1.5*4/5 = 1.2 and Vout=1.5v
+       regulator_enable(dcdc);
+       printk("%s set vdd2 vcc_ddr=%dmV end\n", __func__, regulator_get_voltage(dcdc));
+       regulator_put(dcdc);
+       udelay(100);
+       
+       ldo = regulator_get(NULL, "vdig1");     //vcc18_cif
+       regulator_set_voltage(ldo, 1800000, 1800000);
+       regulator_enable(ldo);
+       printk("%s set vdig1 vcc18_cif=%dmV end\n", __func__, regulator_get_voltage(ldo));
+       regulator_put(ldo);
+       udelay(100);
+       
+       dcdc = regulator_get(NULL, "vaux1"); //vcc25_hdmi
+       regulator_set_voltage(dcdc,2500000,2500000);
+       regulator_enable(dcdc); 
+       printk("%s set vaux1 vcc25_hdmi=%dmV end\n", __func__, regulator_get_voltage(dcdc));
+       regulator_put(dcdc);
+       udelay(100);
+
+       ldo = regulator_get(NULL, "vaux2");     //vcca33
+       regulator_set_voltage(ldo, 3300000, 3300000);
+       regulator_enable(ldo);
+       printk("%s set vaux2 vcca33=%dmV end\n", __func__, regulator_get_voltage(ldo));
+       regulator_put(ldo);
+       udelay(100);
+
+       ldo = regulator_get(NULL, "vdac"); // vccio_wl
+       regulator_set_voltage(ldo,1800000,1800000);
+       regulator_enable(ldo); 
+       printk("%s set vdac vccio_wl=%dmV end\n", __func__, regulator_get_voltage(ldo));
+       regulator_put(ldo);
+       udelay(100);
+
+       ldo = regulator_get(NULL, "vmmc");  //vcc28_cif
+       regulator_set_voltage(ldo,2800000,2800000);
+       regulator_enable(ldo); 
+       printk("%s set vmmc vcc28_cif=%dmV end\n", __func__, regulator_get_voltage(ldo));
+       regulator_put(ldo);
+       udelay(100);
+
+       #ifdef CONFIG_RK30_PWM_REGULATOR
+       dcdc = regulator_get(NULL, "vdd_core"); // vdd_log
+       regulator_set_voltage(dcdc, 1100000, 1100000);
+       regulator_enable(dcdc);
+       printk("%s set vdd_core=%dmV end\n", __func__, regulator_get_voltage(dcdc));
+       regulator_put(dcdc);
+       udelay(100);
+       #endif
+
+       printk("%s,line=%d END\n", __func__,__LINE__);
+       
+       return 0;
+}
+
+static struct regulator_consumer_supply tps65910_smps1_supply[] = {
+       {
+               .supply = "vdd1",
+       },
+       {
+               .supply = "vdd_cpu",
+       },
+};
+static struct regulator_consumer_supply tps65910_smps2_supply[] = {
+       {
+               .supply = "vdd2",
+       },
+       
+};
+static struct regulator_consumer_supply tps65910_smps3_supply[] = {
+       {
+               .supply = "vdd3",
+       },
+};
+static struct regulator_consumer_supply tps65910_smps4_supply[] = {
+       {
+               .supply = "vio",
+       },
+};
+static struct regulator_consumer_supply tps65910_ldo1_supply[] = {
+       {
+               .supply = "vdig1",
+       },
+};
+static struct regulator_consumer_supply tps65910_ldo2_supply[] = {
+       {
+               .supply = "vdig2",
+       },
+};
+
+static struct regulator_consumer_supply tps65910_ldo3_supply[] = {
+       {
+               .supply = "vaux1",
+       },
+};
+static struct regulator_consumer_supply tps65910_ldo4_supply[] = {
+       {
+               .supply = "vaux2",
+       },
+};
+static struct regulator_consumer_supply tps65910_ldo5_supply[] = {
+       {
+               .supply = "vaux33",
+       },
+};
+static struct regulator_consumer_supply tps65910_ldo6_supply[] = {
+       {
+               .supply = "vmmc",
+       },
+};
+static struct regulator_consumer_supply tps65910_ldo7_supply[] = {
+       {
+               .supply = "vdac",
+       },
+};
+
+static struct regulator_consumer_supply tps65910_ldo8_supply[] = {
+       {
+               .supply = "vpll",
+       },
+};
+
+static struct regulator_init_data tps65910_smps1 = {
+       .constraints = {
+               .name           = "VDD1",
+               .min_uV                 = 600000,
+               .max_uV                 = 1500000,
+               .apply_uV               = 1,
+               .always_on = 1,
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+               .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+       },
+       .num_consumer_supplies = ARRAY_SIZE(tps65910_smps1_supply),
+       .consumer_supplies =  tps65910_smps1_supply,
+};
+
+/* */
+static struct regulator_init_data tps65910_smps2 = {
+       .constraints = {
+               .name           = "VDD2",
+               .min_uV                 = 600000,
+               .max_uV                 = 1500000,
+               .apply_uV               = 1,
+               .always_on = 1,
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+               .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+       },
+       .num_consumer_supplies = ARRAY_SIZE(tps65910_smps2_supply),
+       .consumer_supplies =  tps65910_smps2_supply,
+};
+
+/* */
+static struct regulator_init_data tps65910_smps3 = {
+       .constraints = {
+               .name           = "VDD3",
+               .min_uV                 = 1000000,
+               .max_uV                 = 1400000,
+               .apply_uV               = 1,
+               .always_on = 1,
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+               .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+       },
+       .num_consumer_supplies = ARRAY_SIZE(tps65910_smps3_supply),
+       .consumer_supplies =  tps65910_smps3_supply,
+};
+
+static struct regulator_init_data tps65910_smps4 = {
+       .constraints = {
+               .name           = "VIO",
+               .min_uV                 = 1800000,
+               .max_uV                 = 3300000,
+               .apply_uV               = 1,
+               .always_on = 1,
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+               .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+       },
+       .num_consumer_supplies = ARRAY_SIZE(tps65910_smps4_supply),
+       .consumer_supplies =  tps65910_smps4_supply,
+};
+static struct regulator_init_data tps65910_ldo1 = {
+       .constraints = {
+               .name           = "VDIG1",
+               .min_uV                 = 1200000,
+               .max_uV                 = 2700000,
+               .apply_uV               = 1,
+               
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+               .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+       },
+       .num_consumer_supplies = ARRAY_SIZE(tps65910_ldo1_supply),
+       .consumer_supplies =  tps65910_ldo1_supply,
+};
+
+/* */
+static struct regulator_init_data tps65910_ldo2 = {
+       .constraints = {
+               .name           = "VDIG2",
+               .min_uV                 = 1000000,
+               .max_uV                 = 1800000,
+               .apply_uV               = 1,
+               
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+               .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+       },
+       .num_consumer_supplies = ARRAY_SIZE(tps65910_ldo2_supply),
+       .consumer_supplies =  tps65910_ldo2_supply,
+};
+
+/* */
+static struct regulator_init_data tps65910_ldo3 = {
+       .constraints = {
+               .name           = "VAUX1",
+               .min_uV                 = 1800000,
+               .max_uV                 = 3300000,
+               .apply_uV               = 1,
+               
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+               .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+       },
+       .num_consumer_supplies = ARRAY_SIZE(tps65910_ldo3_supply),
+       .consumer_supplies =  tps65910_ldo3_supply,
+};
+
+/* */
+static struct regulator_init_data tps65910_ldo4 = {
+       .constraints = {
+               .name           = "VAUX2",
+               .min_uV                 = 1800000,
+               .max_uV                 = 3300000,
+               .apply_uV               = 1,
+               
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+               .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+       },
+       .num_consumer_supplies = ARRAY_SIZE(tps65910_ldo4_supply),
+       .consumer_supplies =  tps65910_ldo4_supply,
+};
+
+/* */
+static struct regulator_init_data tps65910_ldo5 = {
+       .constraints = {
+               .name           = "VAUX33",
+               .min_uV                 = 1800000,
+               .max_uV                 = 3300000,
+               .apply_uV               = 1,
+               
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+               .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+       },
+       .num_consumer_supplies = ARRAY_SIZE(tps65910_ldo5_supply),
+       .consumer_supplies =  tps65910_ldo5_supply,
+};
+
+/* */
+static struct regulator_init_data tps65910_ldo6 = {
+       .constraints = {
+               .name           = "VMMC",
+               .min_uV                 = 1800000,
+               .max_uV                 = 3300000,
+               .apply_uV               = 1,
+               
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+               .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+       },
+       .num_consumer_supplies = ARRAY_SIZE(tps65910_ldo6_supply),
+       .consumer_supplies =  tps65910_ldo6_supply,
+};
+
+/* */
+static struct regulator_init_data tps65910_ldo7 = {
+       .constraints = {
+               .name           = "VDAC",
+               .min_uV                 = 1800000,
+               .max_uV                 = 2850000,
+               .apply_uV               = 1,
+               
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+               .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+       },
+       .num_consumer_supplies = ARRAY_SIZE(tps65910_ldo7_supply),
+       .consumer_supplies =  tps65910_ldo7_supply,
+};
+
+/* */
+static struct regulator_init_data tps65910_ldo8 = {
+       .constraints = {
+               .name           = "VPLL",
+               .min_uV                 = 1000000,
+               .max_uV                 = 2500000,
+               .apply_uV               = 1,
+               .always_on = 1,
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE,
+               .valid_modes_mask = REGULATOR_MODE_STANDBY | REGULATOR_MODE_NORMAL,
+
+       },
+       .num_consumer_supplies = ARRAY_SIZE(tps65910_ldo8_supply),
+       .consumer_supplies =  tps65910_ldo8_supply,
+};
+/*
+void __sramfunc board_pmu_tps65910_suspend(void)
+{      
+       grf_writel(GPIO6_PB1_DIR_OUT, GRF_GPIO6L_DIR_ADDR);
+       grf_writel(GPIO6_PB1_DO_HIGH, GRF_GPIO6L_DO_ADDR);  //set gpio6_b1 output low
+       grf_writel(GPIO6_PB1_EN_MASK, GRF_GPIO6L_EN_ADDR);
+}
+void __sramfunc board_pmu_tps65910_resume(void)
+{
+       grf_writel(GPIO6_PB1_DIR_OUT, GRF_GPIO6L_DIR_ADDR);
+       grf_writel(GPIO6_PB1_DO_LOW, GRF_GPIO6L_DO_ADDR);  //set gpio6_b1 output low
+       grf_writel(GPIO6_PB1_EN_MASK, GRF_GPIO6L_EN_ADDR);
+       #ifdef CONFIG_CLK_SWITCH_TO_32K                 //switch clk to 24M
+       sram_32k_udelay(10000);
+       #else
+       sram_udelay(2000);
+       #endif
+}
+*/
+static struct tps65910_board tps65910_data = {
+       .irq    = (unsigned)TPS65910_HOST_IRQ,          
+       .irq_base = NR_GIC_IRQS + NR_GPIO_IRQS,
+//     .gpio_base = TPS65910_GPIO_EXPANDER_BASE,
+       
+       .pre_init = tps65910_pre_init,
+       .post_init = tps65910_post_init,
+
+       //TPS65910_NUM_REGS = 13
+       // Regulators
+       .tps65910_pmic_init_data[TPS65910_REG_VRTC] = NULL,             
+       .tps65910_pmic_init_data[TPS65910_REG_VIO] = &tps65910_smps4,
+       .tps65910_pmic_init_data[TPS65910_REG_VDD1] = &tps65910_smps1,
+       .tps65910_pmic_init_data[TPS65910_REG_VDD2] = &tps65910_smps2,
+       .tps65910_pmic_init_data[TPS65910_REG_VDD3] = &tps65910_smps3,
+       .tps65910_pmic_init_data[TPS65910_REG_VDIG1] = &tps65910_ldo1,
+       .tps65910_pmic_init_data[TPS65910_REG_VDIG2] = &tps65910_ldo2,
+       .tps65910_pmic_init_data[TPS65910_REG_VPLL] = &tps65910_ldo8,
+       .tps65910_pmic_init_data[TPS65910_REG_VDAC] = &tps65910_ldo7,
+       .tps65910_pmic_init_data[TPS65910_REG_VAUX1] = &tps65910_ldo3,
+       .tps65910_pmic_init_data[TPS65910_REG_VAUX2] = &tps65910_ldo4,
+       .tps65910_pmic_init_data[TPS65910_REG_VAUX33] = &tps65910_ldo5,
+       .tps65910_pmic_init_data[TPS65910_REG_VMMC] = &tps65910_ldo6,
+
+};
+
+#endif
+
index 3b8f6043bf0c4436e1ce47da74bc4f33e73b92d8..9876d32c81730877eb857670f0a532db9058bee4 100755 (executable)
@@ -261,6 +261,12 @@ config GPIO_TC3589X
          This enables support for the GPIOs found on the TC3589X
          I/O Expander.
 
          This enables support for the GPIOs found on the TC3589X
          I/O Expander.
 
+config GPIO_TPS65912
+       tristate "TI TPS65912 GPIO"
+       depends on (MFD_TPS65912_I2C || MFD_TPS65912_SPI)
+       help
+         This driver supports TPS65912 gpio chip
+
 config GPIO_TWL4030
        tristate "TWL4030, TWL5030, and TPS659x0 GPIOs"
        depends on TWL4030_CORE
 config GPIO_TWL4030
        tristate "TWL4030, TWL5030, and TPS659x0 GPIOs"
        depends on TWL4030_CORE
index 46508ae87340a6bef5ad17008d1eab67d48dba58..9a470d2235f7f529ba2c4e0e2b1cb12deb4d39cc 100755 (executable)
@@ -54,4 +54,5 @@ obj-$(CONFIG_GPIO_SX150X)     += sx150x.o
 obj-$(CONFIG_GPIO_VX855)       += vx855_gpio.o
 obj-$(CONFIG_GPIO_ML_IOH)      += ml_ioh_gpio.o
 obj-$(CONFIG_AB8500_GPIO)       += ab8500-gpio.o
 obj-$(CONFIG_GPIO_VX855)       += vx855_gpio.o
 obj-$(CONFIG_GPIO_ML_IOH)      += ml_ioh_gpio.o
 obj-$(CONFIG_AB8500_GPIO)       += ab8500-gpio.o
-obj-$(CONFIG_GPIO_TPS65910)    += tps65910-gpio.o
+obj-$(CONFIG_GPIO_TPS65910)    += gpio-tps65910.o
+obj-$(CONFIG_GPIO_TPS65912)    += gpio-tps65912.o
diff --git a/drivers/gpio/gpio-tps65910.c b/drivers/gpio/gpio-tps65910.c
new file mode 100755 (executable)
index 0000000..7eef648
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * TI TPS6591x GPIO driver
+ *
+ * Copyright 2010 Texas Instruments Inc.
+ *
+ * Author: Graeme Gregory <gg@slimlogic.co.uk>
+ * Author: Jorge Eduardo Candelaria jedu@slimlogic.co.uk>
+ *
+ *  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/module.h>
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/mfd/tps65910.h>
+
+static int tps65910_gpio_get(struct gpio_chip *gc, unsigned offset)
+{
+       struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio);
+       uint8_t val;
+
+       tps65910->read(tps65910, TPS65910_GPIO0 + offset, 1, &val);
+
+       if (val & GPIO_STS_MASK)
+               return 1;
+
+       return 0;
+}
+
+static void tps65910_gpio_set(struct gpio_chip *gc, unsigned offset,
+                             int value)
+{
+       struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio);
+
+       if (value)
+               tps65910_set_bits(tps65910, TPS65910_GPIO0 + offset,
+                                               GPIO_SET_MASK);
+       else
+               tps65910_clear_bits(tps65910, TPS65910_GPIO0 + offset,
+                                               GPIO_SET_MASK);
+}
+
+static int tps65910_gpio_output(struct gpio_chip *gc, unsigned offset,
+                               int value)
+{
+       struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio);
+
+       /* Set the initial value */
+       tps65910_gpio_set(gc, offset, value);
+
+       return tps65910_set_bits(tps65910, TPS65910_GPIO0 + offset,
+                                               GPIO_CFG_MASK);
+}
+
+static int tps65910_gpio_input(struct gpio_chip *gc, unsigned offset)
+{
+       struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio);
+
+       return tps65910_clear_bits(tps65910, TPS65910_GPIO0 + offset,
+                                               GPIO_CFG_MASK);
+}
+
+void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base)
+{
+       int ret;
+       struct tps65910_board *board_data;
+
+       if (!gpio_base)
+               return;
+
+       tps65910->gpio.owner            = THIS_MODULE;
+       tps65910->gpio.label            = tps65910->i2c_client->name;
+       tps65910->gpio.dev              = tps65910->dev;
+       tps65910->gpio.base             = gpio_base;
+
+       switch(tps65910_chip_id(tps65910)) {
+       case TPS65910:
+               tps65910->gpio.ngpio    = TPS65910_NUM_GPIO;
+               break;
+       case TPS65911:
+               tps65910->gpio.ngpio    = TPS65911_NUM_GPIO;
+               break;
+       default:
+               return;
+       }
+       tps65910->gpio.can_sleep        = 1;
+
+       tps65910->gpio.direction_input  = tps65910_gpio_input;
+       tps65910->gpio.direction_output = tps65910_gpio_output;
+       tps65910->gpio.set              = tps65910_gpio_set;
+       tps65910->gpio.get              = tps65910_gpio_get;
+
+       /* Configure sleep control for gpios */
+       board_data = dev_get_platdata(tps65910->dev);
+       if (board_data) {
+               int i;
+               for (i = 0; i < tps65910->gpio.ngpio; ++i) {
+                       if (board_data->en_gpio_sleep[i]) {
+                               ret = tps65910_set_bits(tps65910,
+                                       TPS65910_GPIO0 + i, GPIO_SLEEP_MASK);
+                               if (ret < 0)
+                                       dev_warn(tps65910->dev,
+                                               "GPIO Sleep setting failed\n");
+                       }
+               }
+       }
+
+       ret = gpiochip_add(&tps65910->gpio);
+
+       if (ret)
+               dev_warn(tps65910->dev, "GPIO registration failed: %d\n", ret);
+}
old mode 100644 (file)
new mode 100755 (executable)
index 35ff8fe221835b242ddcef88509f57510fc9d3fa..43c5d038be131bc76515fad1d696252874afddff 100755 (executable)
@@ -171,6 +171,37 @@ config MFD_TPS6586X
          This driver can also be built as a module.  If so, the module
          will be called tps6586x.
 
          This driver can also be built as a module.  If so, the module
          will be called tps6586x.
 
+config MFD_TPS65910
+       bool "TPS65910 Power Management chip"
+       depends on I2C=y && GPIOLIB
+       select MFD_CORE
+       select GPIO_TPS65910
+       select REGMAP_I2C
+       help
+         if you say yes here you get support for the TPS65910 series of
+         Power Management chips.
+
+config MFD_TPS65912
+       bool
+       depends on GPIOLIB
+
+config MFD_TPS65912_I2C
+       bool "TPS65912 Power Management chip with I2C"
+       select MFD_CORE
+       select MFD_TPS65912
+       depends on I2C=y && GPIOLIB
+       help
+         If you say yes here you get support for the TPS65912 series of
+         PM chips with I2C interface.
+
+config MFD_TPS65912_SPI
+       bool "TPS65912 Power Management chip with SPI"
+       select MFD_CORE
+       select MFD_TPS65912
+       depends on SPI_MASTER && GPIOLIB
+       help
+         If you say yes here you get support for the TPS65912 series of
+         PM chips with SPI interface.
 config MENELAUS
        bool "Texas Instruments TWL92330/Menelaus PM chip"
        depends on I2C=y && ARCH_OMAP2
 config MENELAUS
        bool "Texas Instruments TWL92330/Menelaus PM chip"
        depends on I2C=y && ARCH_OMAP2
@@ -769,17 +800,20 @@ config MFD_PM8XXX_IRQ
          This is required to use certain other PM 8xxx features, such as GPIO
          and MPP.
 
          This is required to use certain other PM 8xxx features, such as GPIO
          and MPP.
 
-config MFD_TPS65910
-       bool "TPS65910 Power Management chip"
-       depends on I2C=y && GPIOLIB
+config TPS65911_COMPARATOR
+       tristate
+
+config MFD_TPS65090
+       bool "TPS65090 Power Management chips"
+       depends on I2C=y && GENERIC_HARDIRQS
        select MFD_CORE
        select MFD_CORE
-       select GPIO_TPS65910
+       select REGMAP_I2C
        help
        help
-         if you say yes here you get support for the TPS65910 series of
+         If you say yes here you get support for the TPS65090 series of
          Power Management chips.
          Power Management chips.
-
-config TPS65911_COMPARATOR
-       tristate
+         This driver provides common support for accessing the device,
+         additional drivers must be enabled in order to use the
+         functionality of the device.
 
 config MFD_RK610
        bool "RK610(Jetta) Multimedia support"
 
 config MFD_RK610
        bool "RK610(Jetta) Multimedia support"
index bd569e97306c6daf27279bf3e2f9b7addcac6779..59d550bfe5739c24c7f7ce63d981dee2988ad163 100755 (executable)
@@ -36,6 +36,11 @@ obj-$(CONFIG_MFD_WM8994)     += wm8994-core.o wm8994-irq.o
 obj-$(CONFIG_TPS6105X)         += tps6105x.o
 obj-$(CONFIG_TPS65010)         += tps65010.o
 obj-$(CONFIG_TPS6507X)         += tps6507x.o
 obj-$(CONFIG_TPS6105X)         += tps6105x.o
 obj-$(CONFIG_TPS65010)         += tps65010.o
 obj-$(CONFIG_TPS6507X)         += tps6507x.o
+obj-$(CONFIG_MFD_TPS65910)     += tps65910.o tps65910-irq.o
+tps65912-objs                   := tps65912-core.o tps65912-irq.o
+obj-$(CONFIG_MFD_TPS65912)     += tps65912.o
+obj-$(CONFIG_MFD_TPS65912_I2C) += tps65912-i2c.o
+obj-$(CONFIG_MFD_TPS65912_SPI)  += tps65912-spi.o
 obj-$(CONFIG_MENELAUS)         += menelaus.o
 
 obj-$(CONFIG_TWL4030_CORE)     += twl-core.o twl4030-irq.o twl6030-irq.o
 obj-$(CONFIG_MENELAUS)         += menelaus.o
 
 obj-$(CONFIG_TWL4030_CORE)     += twl-core.o twl4030-irq.o twl6030-irq.o
old mode 100644 (file)
new mode 100755 (executable)
index a56be93..bcec383
@@ -45,7 +45,7 @@ static irqreturn_t tps65910_irq(int irq, void *irq_data)
        u32 irq_mask;
        u8 reg;
        int i;
        u32 irq_mask;
        u8 reg;
        int i;
-
+       
        tps65910->read(tps65910, TPS65910_INT_STS, 1, &reg);
        irq_sts = reg;
        tps65910->read(tps65910, TPS65910_INT_STS2, 1, &reg);
        tps65910->read(tps65910, TPS65910_INT_STS, 1, &reg);
        irq_sts = reg;
        tps65910->read(tps65910, TPS65910_INT_STS2, 1, &reg);
@@ -145,12 +145,23 @@ static void tps65910_irq_disable(struct irq_data *data)
        tps65910->irq_mask |= ( 1 << irq_to_tps65910_irq(tps65910, data->irq));
 }
 
        tps65910->irq_mask |= ( 1 << irq_to_tps65910_irq(tps65910, data->irq));
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int tps65910_irq_set_wake(struct irq_data *data, unsigned int enable)
+{
+       struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data);
+       return irq_set_irq_wake(tps65910->chip_irq, enable);
+}
+#else
+#define tps65910_irq_set_wake NULL
+#endif
+
 static struct irq_chip tps65910_irq_chip = {
        .name = "tps65910",
        .irq_bus_lock = tps65910_irq_lock,
        .irq_bus_sync_unlock = tps65910_irq_sync_unlock,
        .irq_disable = tps65910_irq_disable,
        .irq_enable = tps65910_irq_enable,
 static struct irq_chip tps65910_irq_chip = {
        .name = "tps65910",
        .irq_bus_lock = tps65910_irq_lock,
        .irq_bus_sync_unlock = tps65910_irq_sync_unlock,
        .irq_disable = tps65910_irq_disable,
        .irq_enable = tps65910_irq_enable,
+       .irq_set_wake = tps65910_irq_set_wake,
 };
 
 int tps65910_irq_init(struct tps65910 *tps65910, int irq,
 };
 
 int tps65910_irq_init(struct tps65910 *tps65910, int irq,
@@ -158,17 +169,27 @@ int tps65910_irq_init(struct tps65910 *tps65910, int irq,
 {
        int ret, cur_irq;
        int flags = IRQF_ONESHOT;
 {
        int ret, cur_irq;
        int flags = IRQF_ONESHOT;
+       u8 reg;
 
        if (!irq) {
                dev_warn(tps65910->dev, "No interrupt support, no core IRQ\n");
 
        if (!irq) {
                dev_warn(tps65910->dev, "No interrupt support, no core IRQ\n");
-               return -EINVAL;
+               return 0;
        }
 
        if (!pdata || !pdata->irq_base) {
                dev_warn(tps65910->dev, "No interrupt support, no IRQ base\n");
        }
 
        if (!pdata || !pdata->irq_base) {
                dev_warn(tps65910->dev, "No interrupt support, no IRQ base\n");
-               return -EINVAL;
+               return 0;
        }
 
        }
 
+       /* Clear unattended interrupts */
+       tps65910->read(tps65910, TPS65910_INT_STS, 1, &reg);
+       tps65910->write(tps65910, TPS65910_INT_STS, 1, &reg);
+       tps65910->read(tps65910, TPS65910_INT_STS2, 1, &reg);
+       tps65910->write(tps65910, TPS65910_INT_STS2, 1, &reg);
+       tps65910->read(tps65910, TPS65910_INT_STS3, 1, &reg);
+       tps65910->write(tps65910, TPS65910_INT_STS3, 1, &reg);
+
+       /* Mask top level interrupts */
        tps65910->irq_mask = 0xFFFFFF;
 
        mutex_init(&tps65910->irq_lock);
        tps65910->irq_mask = 0xFFFFFF;
 
        mutex_init(&tps65910->irq_lock);
@@ -215,6 +236,7 @@ int tps65910_irq_init(struct tps65910 *tps65910, int irq,
 
 int tps65910_irq_exit(struct tps65910 *tps65910)
 {
 
 int tps65910_irq_exit(struct tps65910 *tps65910)
 {
-       free_irq(tps65910->chip_irq, tps65910);
+       if (tps65910->chip_irq)
+               free_irq(tps65910->chip_irq, tps65910);
        return 0;
 }
        return 0;
 }
old mode 100644 (file)
new mode 100755 (executable)
index 2229e66..6b16534
@@ -22,6 +22,8 @@
 #include <linux/mfd/core.h>
 #include <linux/mfd/tps65910.h>
 
 #include <linux/mfd/core.h>
 #include <linux/mfd/tps65910.h>
 
+struct tps65910 *g_tps65910;
+
 static struct mfd_cell tps65910s[] = {
        {
                .name = "tps65910-pmic",
 static struct mfd_cell tps65910s[] = {
        {
                .name = "tps65910-pmic",
@@ -34,6 +36,7 @@ static struct mfd_cell tps65910s[] = {
        },
 };
 
        },
 };
 
+#define TPS65910_SPEED         200 * 1000
 
 static int tps65910_i2c_read(struct tps65910 *tps65910, u8 reg,
                                  int bytes, void *dest)
 
 static int tps65910_i2c_read(struct tps65910 *tps65910, u8 reg,
                                  int bytes, void *dest)
@@ -41,25 +44,30 @@ static int tps65910_i2c_read(struct tps65910 *tps65910, u8 reg,
        struct i2c_client *i2c = tps65910->i2c_client;
        struct i2c_msg xfer[2];
        int ret;
        struct i2c_client *i2c = tps65910->i2c_client;
        struct i2c_msg xfer[2];
        int ret;
+       //int i;
 
        /* Write register */
        xfer[0].addr = i2c->addr;
        xfer[0].flags = 0;
        xfer[0].len = 1;
        xfer[0].buf = &reg;
 
        /* Write register */
        xfer[0].addr = i2c->addr;
        xfer[0].flags = 0;
        xfer[0].len = 1;
        xfer[0].buf = &reg;
+       xfer[0].scl_rate = TPS65910_SPEED;
 
        /* Read data */
        xfer[1].addr = i2c->addr;
        xfer[1].flags = I2C_M_RD;
        xfer[1].len = bytes;
        xfer[1].buf = dest;
 
        /* Read data */
        xfer[1].addr = i2c->addr;
        xfer[1].flags = I2C_M_RD;
        xfer[1].len = bytes;
        xfer[1].buf = dest;
+       xfer[1].scl_rate = TPS65910_SPEED;
 
        ret = i2c_transfer(i2c->adapter, xfer, 2);
 
        ret = i2c_transfer(i2c->adapter, xfer, 2);
+       //for(i=0;i<bytes;i++)
+       //printk("%s:reg=0x%x,value=0x%x\n",__func__,reg+i,*(u8 *)dest++);
        if (ret == 2)
                ret = 0;
        else if (ret >= 0)
                ret = -EIO;
        if (ret == 2)
                ret = 0;
        else if (ret >= 0)
                ret = -EIO;
-
+       
        return ret;
 }
 
        return ret;
 }
 
@@ -70,21 +78,114 @@ static int tps65910_i2c_write(struct tps65910 *tps65910, u8 reg,
        /* we add 1 byte for device register */
        u8 msg[TPS65910_MAX_REGISTER + 1];
        int ret;
        /* we add 1 byte for device register */
        u8 msg[TPS65910_MAX_REGISTER + 1];
        int ret;
-
+       //int i;
+       
        if (bytes > TPS65910_MAX_REGISTER)
                return -EINVAL;
        if (bytes > TPS65910_MAX_REGISTER)
                return -EINVAL;
-
+       
        msg[0] = reg;
        memcpy(&msg[1], src, bytes);
 
        msg[0] = reg;
        memcpy(&msg[1], src, bytes);
 
+       //for(i=0;i<bytes;i++)
+       //printk("%s:reg=0x%x,value=0x%x\n",__func__,reg+i,msg[i+1]);
+       
        ret = i2c_master_send(i2c, msg, bytes + 1);
        if (ret < 0)
                return ret;
        if (ret != bytes + 1)
                return -EIO;
        ret = i2c_master_send(i2c, msg, bytes + 1);
        if (ret < 0)
                return ret;
        if (ret != bytes + 1)
                return -EIO;
+
        return 0;
 }
 
        return 0;
 }
 
+static inline int tps65910_read(struct tps65910 *tps65910, u8 reg)
+{
+       u8 val;
+       int err;
+
+       err = tps65910->read(tps65910, reg, 1, &val);
+       if (err < 0)
+               return err;
+
+       return val;
+}
+
+static inline int tps65910_write(struct tps65910 *tps65910, u8 reg, u8 val)
+{
+       return tps65910->write(tps65910, reg, 1, &val);
+}
+
+int tps65910_reg_read(struct tps65910 *tps65910, u8 reg)
+{
+       int data;
+
+       mutex_lock(&tps65910->io_mutex);
+
+       data = tps65910_read(tps65910, reg);
+       if (data < 0)
+               dev_err(tps65910->dev, "Read from reg 0x%x failed\n", reg);
+
+       mutex_unlock(&tps65910->io_mutex);
+       return data;
+}
+EXPORT_SYMBOL_GPL(tps65910_reg_read);
+
+int tps65910_reg_write(struct tps65910 *tps65910, u8 reg, u8 val)
+{
+       int err;
+
+       mutex_lock(&tps65910->io_mutex);
+
+       err = tps65910_write(tps65910, reg, val);
+       if (err < 0)
+               dev_err(tps65910->dev, "Write for reg 0x%x failed\n", reg);
+
+       mutex_unlock(&tps65910->io_mutex);
+       return err;
+}
+EXPORT_SYMBOL_GPL(tps65910_reg_write);
+
+/**
+ * tps65910_bulk_read: Read multiple tps65910 registers
+ *
+ * @tps65910: Device to read from
+ * @reg: First register
+ * @count: Number of registers
+ * @buf: Buffer to fill.
+ */
+int tps65910_bulk_read(struct tps65910 *tps65910, u8 reg,
+                    int count, u8 *buf)
+{
+       int ret;
+
+       mutex_lock(&tps65910->io_mutex);
+       
+       ret = tps65910->read(tps65910, reg, count, buf);
+
+       mutex_unlock(&tps65910->io_mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(tps65910_bulk_read);
+
+int tps65910_bulk_write(struct tps65910 *tps65910, u8 reg,
+                    int count, u8 *buf)
+{
+       int ret;
+
+       mutex_lock(&tps65910->io_mutex);
+       
+       ret = tps65910->write(tps65910, reg, count, buf);
+
+       mutex_unlock(&tps65910->io_mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(tps65910_bulk_write);
+
+
+
+
 int tps65910_set_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
 {
        u8 data;
 int tps65910_set_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
 {
        u8 data;
@@ -93,14 +194,14 @@ int tps65910_set_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
        mutex_lock(&tps65910->io_mutex);
        err = tps65910_i2c_read(tps65910, reg, 1, &data);
        if (err) {
        mutex_lock(&tps65910->io_mutex);
        err = tps65910_i2c_read(tps65910, reg, 1, &data);
        if (err) {
-               dev_err(tps65910->dev, "read from reg %x failed\n", reg);
+               dev_err(tps65910->dev, "%s:read from reg %x failed\n", __func__,reg);
                goto out;
        }
 
        data |= mask;
        err = tps65910_i2c_write(tps65910, reg, 1, &data);
        if (err)
                goto out;
        }
 
        data |= mask;
        err = tps65910_i2c_write(tps65910, reg, 1, &data);
        if (err)
-               dev_err(tps65910->dev, "write to reg %x failed\n", reg);
+               dev_err(tps65910->dev, "%s:write to reg %x failed\n", __func__,reg);
 
 out:
        mutex_unlock(&tps65910->io_mutex);
 
 out:
        mutex_unlock(&tps65910->io_mutex);
@@ -120,7 +221,7 @@ int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
                goto out;
        }
 
                goto out;
        }
 
-       data &= mask;
+       data &= ~mask;
        err = tps65910_i2c_write(tps65910, reg, 1, &data);
        if (err)
                dev_err(tps65910->dev, "write to reg %x failed\n", reg);
        err = tps65910_i2c_write(tps65910, reg, 1, &data);
        if (err)
                dev_err(tps65910->dev, "write to reg %x failed\n", reg);
@@ -138,7 +239,7 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
        struct tps65910_board *pmic_plat_data;
        struct tps65910_platform_data *init_data;
        int ret = 0;
        struct tps65910_board *pmic_plat_data;
        struct tps65910_platform_data *init_data;
        int ret = 0;
-
+       
        pmic_plat_data = dev_get_platdata(&i2c->dev);
        if (!pmic_plat_data)
                return -EINVAL;
        pmic_plat_data = dev_get_platdata(&i2c->dev);
        if (!pmic_plat_data)
                return -EINVAL;
@@ -148,7 +249,7 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
                return -ENOMEM;
 
        init_data->irq = pmic_plat_data->irq;
                return -ENOMEM;
 
        init_data->irq = pmic_plat_data->irq;
-       init_data->irq_base = pmic_plat_data->irq;
+       init_data->irq_base = pmic_plat_data->irq_base;
 
        tps65910 = kzalloc(sizeof(struct tps65910), GFP_KERNEL);
        if (tps65910 == NULL)
 
        tps65910 = kzalloc(sizeof(struct tps65910), GFP_KERNEL);
        if (tps65910 == NULL)
@@ -167,6 +268,16 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
                              NULL, 0);
        if (ret < 0)
                goto err;
                              NULL, 0);
        if (ret < 0)
                goto err;
+       
+       g_tps65910 = tps65910;
+       
+       if (pmic_plat_data && pmic_plat_data->pre_init) {
+               ret = pmic_plat_data->pre_init(tps65910);
+               if (ret != 0) {
+                       dev_err(tps65910->dev, "pre_init() failed: %d\n", ret);
+                       goto err;
+               }
+       }
 
        tps65910_gpio_init(tps65910, pmic_plat_data->gpio_base);
 
 
        tps65910_gpio_init(tps65910, pmic_plat_data->gpio_base);
 
@@ -174,6 +285,15 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
        if (ret < 0)
                goto err;
 
        if (ret < 0)
                goto err;
 
+       if (pmic_plat_data && pmic_plat_data->post_init) {
+               ret = pmic_plat_data->post_init(tps65910);
+               if (ret != 0) {
+                       dev_err(tps65910->dev, "post_init() failed: %d\n", ret);
+                       goto err;
+               }
+       }
+
+       printk("%s:irq=%d,irq_base=%d,gpio_base=%d\n",__func__,init_data->irq,init_data->irq_base,pmic_plat_data->gpio_base);
        return ret;
 
 err:
        return ret;
 
 err:
@@ -182,6 +302,36 @@ err:
        return ret;
 }
 
        return ret;
 }
 
+
+int tps65910_device_shutdown(void)
+{
+       int val = 0;
+       int err = -1;
+       struct tps65910 *tps65910 = g_tps65910;
+       
+       printk("%s\n",__func__);
+
+       val = tps65910_reg_read(tps65910, TPS65910_DEVCTRL);
+        if (val<0) {
+                printk(KERN_ERR "Unable to read TPS65910_REG_DCDCCTRL reg\n");
+                return -EIO;
+        }
+       
+       val |= DEVCTRL_DEV_OFF_MASK;
+       val &= ~DEVCTRL_CK32K_CTRL_MASK;        //keep rtc
+       err = tps65910_reg_write(tps65910, TPS65910_DEVCTRL, val);
+       if (err) {
+               printk(KERN_ERR "Unable to read TPS65910 Reg at offset 0x%x= \
+                               \n", TPS65910_REG_VDIG1);
+               return err;
+       }
+       
+       return 0;       
+}
+EXPORT_SYMBOL_GPL(tps65910_device_shutdown);
+
+
+
 static int tps65910_i2c_remove(struct i2c_client *i2c)
 {
        struct tps65910 *tps65910 = i2c_get_clientdata(i2c);
 static int tps65910_i2c_remove(struct i2c_client *i2c)
 {
        struct tps65910 *tps65910 = i2c_get_clientdata(i2c);
@@ -215,7 +365,7 @@ static int __init tps65910_i2c_init(void)
        return i2c_add_driver(&tps65910_i2c_driver);
 }
 /* init early so consumer devices can complete system boot */
        return i2c_add_driver(&tps65910_i2c_driver);
 }
 /* init early so consumer devices can complete system boot */
-subsys_initcall(tps65910_i2c_init);
+subsys_initcall_sync(tps65910_i2c_init);
 
 static void __exit tps65910_i2c_exit(void)
 {
 
 static void __exit tps65910_i2c_exit(void)
 {
old mode 100644 (file)
new mode 100755 (executable)
index 90c87c9797c5c5da8972d7a03f7f0f40255006ea..b425fd61c4b209bfad8c8c71de3cc045bc0677b4 100755 (executable)
@@ -125,6 +125,17 @@ config REGULATOR_MAX8998
          via I2C bus. The provided regulator is suitable for S3C6410
          and S5PC1XX chips to control VCC_CORE and VCC_USIM voltages.
 
          via I2C bus. The provided regulator is suitable for S3C6410
          and S5PC1XX chips to control VCC_CORE and VCC_USIM voltages.
 
+config REGULATOR_TPS65910
+       tristate "TI TPS65910/TPS65911 Power Regulators"
+       depends on MFD_TPS65910
+       help
+         This driver supports TPS65910/TPS65911 voltage regulator chips.
+
+config REGULATOR_TPS65912
+       tristate "TI TPS65912 Power regulator"
+       depends on (MFD_TPS65912_I2C || MFD_TPS65912_SPI)
+       help
+           This driver supports TPS65912 voltage regulator chip.
 config REGULATOR_TWL4030
        bool "TI TWL4030/TWL5030/TWL6030/TPS659x0 PMIC"
        depends on TWL4030_CORE
 config REGULATOR_TWL4030
        bool "TI TWL4030/TWL5030/TWL6030/TPS659x0 PMIC"
        depends on TWL4030_CORE
@@ -324,11 +335,7 @@ config REGULATOR_TPS6524X
          serial interface currently supported on the sequencer serial
          port controller.
 
          serial interface currently supported on the sequencer serial
          port controller.
 
-config REGULATOR_TPS65910
-       tristate "TI TPS65910 Power Regulator"
-       depends on MFD_TPS65910
-       help
-         This driver supports TPS65910 voltage regulator chips.
+
 
 endif
 
 
 endif
 
index 68db7129f878e9eaa9f30ff2985b7da524bd86dc..d4f86bae7bf97397d968feeee2552e420b615d2c 100755 (executable)
@@ -49,6 +49,7 @@ obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
 obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o
 obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o
 obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o
 obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o
 obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o
 obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o
+obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o
 obj-$(CONFIG_REGULATOR_ACT8891) += act8891.o
 
 ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
 obj-$(CONFIG_REGULATOR_ACT8891) += act8891.o
 
 ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
old mode 100644 (file)
new mode 100755 (executable)
index 425aab3..22e06e2
 #include <linux/gpio.h>
 #include <linux/mfd/tps65910.h>
 
 #include <linux/gpio.h>
 #include <linux/mfd/tps65910.h>
 
-#define TPS65910_REG_VRTC              0
-#define TPS65910_REG_VIO               1
-#define TPS65910_REG_VDD1              2
-#define TPS65910_REG_VDD2              3
-#define TPS65910_REG_VDD3              4
-#define TPS65910_REG_VDIG1             5
-#define TPS65910_REG_VDIG2             6
-#define TPS65910_REG_VPLL              7
-#define TPS65910_REG_VDAC              8
-#define TPS65910_REG_VAUX1             9
-#define TPS65910_REG_VAUX2             10
-#define TPS65910_REG_VAUX33            11
-#define TPS65910_REG_VMMC              12
-
-#define TPS65911_REG_VDDCTRL           4
-#define TPS65911_REG_LDO1              5
-#define TPS65911_REG_LDO2              6
-#define TPS65911_REG_LDO3              7
-#define TPS65911_REG_LDO4              8
-#define TPS65911_REG_LDO5              9
-#define TPS65911_REG_LDO6              10
-#define TPS65911_REG_LDO7              11
-#define TPS65911_REG_LDO8              12
-
-#define TPS65910_NUM_REGULATOR         13
 #define TPS65910_SUPPLY_STATE_ENABLED  0x1
 #define TPS65910_SUPPLY_STATE_ENABLED  0x1
+#define EXT_SLEEP_CONTROL (TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1 |      \
+                       TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2 |          \
+                       TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3 |          \
+                       TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP)
 
 /* supported VIO voltages in milivolts */
 static const u16 VIO_VSEL_table[] = {
        1500, 1800, 2500, 3300,
 };
 
 
 /* supported VIO voltages in milivolts */
 static const u16 VIO_VSEL_table[] = {
        1500, 1800, 2500, 3300,
 };
 
-/* VSEL tables for TPS65910 specific LDOs and dcdc's */
+/* 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,
+};
 
 
-/* supported VDD3 voltages in milivolts */
+/* TPS65910 VDD3 */
 static const u16 VDD3_VSEL_table[] = {
 static const u16 VDD3_VSEL_table[] = {
-       5000,
+       1000,1400
 };
 
 };
 
+
 /* supported VDIG1 voltages in milivolts */
 static const u16 VDIG1_VSEL_table[] = {
        1200, 1500, 1800, 2700,
 /* supported VDIG1 voltages in milivolts */
 static const u16 VDIG1_VSEL_table[] = {
        1200, 1500, 1800, 2700,
@@ -108,169 +114,250 @@ struct tps_info {
        const char *name;
        unsigned min_uV;
        unsigned max_uV;
        const char *name;
        unsigned min_uV;
        unsigned max_uV;
-       u8 table_len;
-       const u16 *table;
+       u8 n_voltages;
+       const u16 *voltage_table;
+       int enable_time_us;
 };
 
 static struct tps_info tps65910_regs[] = {
        {
                .name = "VRTC",
 };
 
 static struct tps_info tps65910_regs[] = {
        {
                .name = "VRTC",
+               .enable_time_us = 2200,
        },
        {
                .name = "VIO",
                .min_uV = 1500000,
                .max_uV = 3300000,
        },
        {
                .name = "VIO",
                .min_uV = 1500000,
                .max_uV = 3300000,
-               .table_len = ARRAY_SIZE(VIO_VSEL_table),
-               .table = VIO_VSEL_table,
+               .n_voltages = ARRAY_SIZE(VIO_VSEL_table),
+               .voltage_table = VIO_VSEL_table,
+               .enable_time_us = 350,
        },
        {
                .name = "VDD1",
                .min_uV = 600000,
        },
        {
                .name = "VDD1",
                .min_uV = 600000,
-               .max_uV = 4500000,
+               .max_uV = 1500000,
+               .n_voltages = ARRAY_SIZE(VDD1_VSEL_table),
+               .voltage_table = VDD1_VSEL_table,
+               .enable_time_us = 350,
        },
        {
                .name = "VDD2",
                .min_uV = 600000,
        },
        {
                .name = "VDD2",
                .min_uV = 600000,
-               .max_uV = 4500000,
+               .max_uV = 1500000,
+               .n_voltages = ARRAY_SIZE(VDD2_VSEL_table),
+               .voltage_table = VDD2_VSEL_table,
+               .enable_time_us = 350,
        },
        {
                .name = "VDD3",
        },
        {
                .name = "VDD3",
-               .min_uV = 5000000,
-               .max_uV = 5000000,
-               .table_len = ARRAY_SIZE(VDD3_VSEL_table),
-               .table = VDD3_VSEL_table,
+               .min_uV = 1000000,
+               .max_uV = 1400000,
+               .n_voltages = ARRAY_SIZE(VDD3_VSEL_table),
+               .voltage_table = VDD3_VSEL_table,
+               .enable_time_us = 200,
        },
        {
                .name = "VDIG1",
                .min_uV = 1200000,
                .max_uV = 2700000,
        },
        {
                .name = "VDIG1",
                .min_uV = 1200000,
                .max_uV = 2700000,
-               .table_len = ARRAY_SIZE(VDIG1_VSEL_table),
-               .table = VDIG1_VSEL_table,
+               .n_voltages = ARRAY_SIZE(VDIG1_VSEL_table),
+               .voltage_table = VDIG1_VSEL_table,
+               .enable_time_us = 100,
        },
        {
                .name = "VDIG2",
                .min_uV = 1000000,
                .max_uV = 1800000,
        },
        {
                .name = "VDIG2",
                .min_uV = 1000000,
                .max_uV = 1800000,
-               .table_len = ARRAY_SIZE(VDIG2_VSEL_table),
-               .table = VDIG2_VSEL_table,
+               .n_voltages = ARRAY_SIZE(VDIG2_VSEL_table),
+               .voltage_table = VDIG2_VSEL_table,
+               .enable_time_us = 100,
        },
        {
                .name = "VPLL",
                .min_uV = 1000000,
                .max_uV = 2500000,
        },
        {
                .name = "VPLL",
                .min_uV = 1000000,
                .max_uV = 2500000,
-               .table_len = ARRAY_SIZE(VPLL_VSEL_table),
-               .table = VPLL_VSEL_table,
+               .n_voltages = ARRAY_SIZE(VPLL_VSEL_table),
+               .voltage_table = VPLL_VSEL_table,
+               .enable_time_us = 100,
        },
        {
                .name = "VDAC",
                .min_uV = 1800000,
                .max_uV = 2850000,
        },
        {
                .name = "VDAC",
                .min_uV = 1800000,
                .max_uV = 2850000,
-               .table_len = ARRAY_SIZE(VDAC_VSEL_table),
-               .table = VDAC_VSEL_table,
+               .n_voltages = ARRAY_SIZE(VDAC_VSEL_table),
+               .voltage_table = VDAC_VSEL_table,
+               .enable_time_us = 100,
        },
        {
                .name = "VAUX1",
                .min_uV = 1800000,
                .max_uV = 2850000,
        },
        {
                .name = "VAUX1",
                .min_uV = 1800000,
                .max_uV = 2850000,
-               .table_len = ARRAY_SIZE(VAUX1_VSEL_table),
-               .table = VAUX1_VSEL_table,
+               .n_voltages = ARRAY_SIZE(VAUX1_VSEL_table),
+               .voltage_table = VAUX1_VSEL_table,
+               .enable_time_us = 100,
        },
        {
                .name = "VAUX2",
                .min_uV = 1800000,
                .max_uV = 3300000,
        },
        {
                .name = "VAUX2",
                .min_uV = 1800000,
                .max_uV = 3300000,
-               .table_len = ARRAY_SIZE(VAUX2_VSEL_table),
-               .table = VAUX2_VSEL_table,
+               .n_voltages = ARRAY_SIZE(VAUX2_VSEL_table),
+               .voltage_table = VAUX2_VSEL_table,
+               .enable_time_us = 100,
        },
        {
                .name = "VAUX33",
                .min_uV = 1800000,
                .max_uV = 3300000,
        },
        {
                .name = "VAUX33",
                .min_uV = 1800000,
                .max_uV = 3300000,
-               .table_len = ARRAY_SIZE(VAUX33_VSEL_table),
-               .table = VAUX33_VSEL_table,
+               .n_voltages = ARRAY_SIZE(VAUX33_VSEL_table),
+               .voltage_table = VAUX33_VSEL_table,
+               .enable_time_us = 100,
        },
        {
                .name = "VMMC",
                .min_uV = 1800000,
                .max_uV = 3300000,
        },
        {
                .name = "VMMC",
                .min_uV = 1800000,
                .max_uV = 3300000,
-               .table_len = ARRAY_SIZE(VMMC_VSEL_table),
-               .table = VMMC_VSEL_table,
+               .n_voltages = ARRAY_SIZE(VMMC_VSEL_table),
+               .voltage_table = VMMC_VSEL_table,
+               .enable_time_us = 100,
        },
 };
 
 static struct tps_info tps65911_regs[] = {
        },
 };
 
 static struct tps_info tps65911_regs[] = {
+       {
+               .name = "VRTC",
+               .enable_time_us = 2200,
+       },
        {
                .name = "VIO",
                .min_uV = 1500000,
                .max_uV = 3300000,
        {
                .name = "VIO",
                .min_uV = 1500000,
                .max_uV = 3300000,
-               .table_len = ARRAY_SIZE(VIO_VSEL_table),
-               .table = VIO_VSEL_table,
+               .n_voltages = ARRAY_SIZE(VIO_VSEL_table),
+               .voltage_table = VIO_VSEL_table,
+               .enable_time_us = 350,
        },
        {
                .name = "VDD1",
                .min_uV = 600000,
                .max_uV = 4500000,
        },
        {
                .name = "VDD1",
                .min_uV = 600000,
                .max_uV = 4500000,
+               .n_voltages = 73,
+               .enable_time_us = 350,
        },
        {
                .name = "VDD2",
                .min_uV = 600000,
                .max_uV = 4500000,
        },
        {
                .name = "VDD2",
                .min_uV = 600000,
                .max_uV = 4500000,
+               .n_voltages = 73,
+               .enable_time_us = 350,
        },
        {
                .name = "VDDCTRL",
                .min_uV = 600000,
                .max_uV = 1400000,
        },
        {
                .name = "VDDCTRL",
                .min_uV = 600000,
                .max_uV = 1400000,
+               .n_voltages = 65,
+               .enable_time_us = 900,
        },
        {
                .name = "LDO1",
                .min_uV = 1000000,
                .max_uV = 3300000,
        },
        {
                .name = "LDO1",
                .min_uV = 1000000,
                .max_uV = 3300000,
+               .n_voltages = 47,
+               .enable_time_us = 420,
        },
        {
                .name = "LDO2",
                .min_uV = 1000000,
                .max_uV = 3300000,
        },
        {
                .name = "LDO2",
                .min_uV = 1000000,
                .max_uV = 3300000,
+               .n_voltages = 47,
+               .enable_time_us = 420,
        },
        {
                .name = "LDO3",
                .min_uV = 1000000,
                .max_uV = 3300000,
        },
        {
                .name = "LDO3",
                .min_uV = 1000000,
                .max_uV = 3300000,
+               .n_voltages = 24,
+               .enable_time_us = 230,
        },
        {
                .name = "LDO4",
                .min_uV = 1000000,
                .max_uV = 3300000,
        },
        {
                .name = "LDO4",
                .min_uV = 1000000,
                .max_uV = 3300000,
+               .n_voltages = 47,
+               .enable_time_us = 230,
        },
        {
                .name = "LDO5",
                .min_uV = 1000000,
                .max_uV = 3300000,
        },
        {
                .name = "LDO5",
                .min_uV = 1000000,
                .max_uV = 3300000,
+               .n_voltages = 24,
+               .enable_time_us = 230,
        },
        {
                .name = "LDO6",
                .min_uV = 1000000,
                .max_uV = 3300000,
        },
        {
                .name = "LDO6",
                .min_uV = 1000000,
                .max_uV = 3300000,
+               .n_voltages = 24,
+               .enable_time_us = 230,
        },
        {
                .name = "LDO7",
                .min_uV = 1000000,
                .max_uV = 3300000,
        },
        {
                .name = "LDO7",
                .min_uV = 1000000,
                .max_uV = 3300000,
+               .n_voltages = 24,
+               .enable_time_us = 230,
        },
        {
                .name = "LDO8",
                .min_uV = 1000000,
                .max_uV = 3300000,
        },
        {
                .name = "LDO8",
                .min_uV = 1000000,
                .max_uV = 3300000,
+               .n_voltages = 24,
+               .enable_time_us = 230,
        },
 };
 
        },
 };
 
+#define EXT_CONTROL_REG_BITS(id, regs_offs, bits) (((regs_offs) << 8) | (bits))
+static unsigned int tps65910_ext_sleep_control[] = {
+       0,
+       EXT_CONTROL_REG_BITS(VIO,    1, 0),
+       EXT_CONTROL_REG_BITS(VDD1,   1, 1),
+       EXT_CONTROL_REG_BITS(VDD2,   1, 2),
+       EXT_CONTROL_REG_BITS(VDD3,   1, 3),
+       EXT_CONTROL_REG_BITS(VDIG1,  0, 1),
+       EXT_CONTROL_REG_BITS(VDIG2,  0, 2),
+       EXT_CONTROL_REG_BITS(VPLL,   0, 6),
+       EXT_CONTROL_REG_BITS(VDAC,   0, 7),
+       EXT_CONTROL_REG_BITS(VAUX1,  0, 3),
+       EXT_CONTROL_REG_BITS(VAUX2,  0, 4),
+       EXT_CONTROL_REG_BITS(VAUX33, 0, 5),
+       EXT_CONTROL_REG_BITS(VMMC,   0, 0),
+};
+
+static unsigned int tps65911_ext_sleep_control[] = {
+       0,
+       EXT_CONTROL_REG_BITS(VIO,     1, 0),
+       EXT_CONTROL_REG_BITS(VDD1,    1, 1),
+       EXT_CONTROL_REG_BITS(VDD2,    1, 2),
+       EXT_CONTROL_REG_BITS(VDDCTRL, 1, 3),
+       EXT_CONTROL_REG_BITS(LDO1,    0, 1),
+       EXT_CONTROL_REG_BITS(LDO2,    0, 2),
+       EXT_CONTROL_REG_BITS(LDO3,    0, 7),
+       EXT_CONTROL_REG_BITS(LDO4,    0, 6),
+       EXT_CONTROL_REG_BITS(LDO5,    0, 3),
+       EXT_CONTROL_REG_BITS(LDO6,    0, 0),
+       EXT_CONTROL_REG_BITS(LDO7,    0, 5),
+       EXT_CONTROL_REG_BITS(LDO8,    0, 4),
+};
+
 struct tps65910_reg {
 struct tps65910_reg {
-       struct regulator_desc desc[TPS65910_NUM_REGULATOR];
+       struct regulator_desc *desc;
        struct tps65910 *mfd;
        struct tps65910 *mfd;
-       struct regulator_dev *rdev[TPS65910_NUM_REGULATOR];
-       struct tps_info *info[TPS65910_NUM_REGULATOR];
+       struct regulator_dev **rdev;
+       struct tps_info **info;
        struct mutex mutex;
        struct mutex mutex;
+       int num_regulators;
        int mode;
        int  (*get_ctrl_reg)(int);
        int mode;
        int  (*get_ctrl_reg)(int);
+       unsigned int *ext_sleep_control;
+       unsigned int board_ext_control[TPS65910_NUM_REGS];
 };
 
 static inline int tps65910_read(struct tps65910_reg *pmic, u8 reg)
 };
 
 static inline int tps65910_read(struct tps65910_reg *pmic, u8 reg)
@@ -315,7 +402,7 @@ out:
        return err;
 }
 
        return err;
 }
 
-static int tps65910_reg_read(struct tps65910_reg *pmic, u8 reg)
+static int tps65910_pmic_reg_read(struct tps65910_reg *pmic, u8 reg)
 {
        int data;
 
 {
        int data;
 
@@ -329,7 +416,7 @@ static int tps65910_reg_read(struct tps65910_reg *pmic, u8 reg)
        return data;
 }
 
        return data;
 }
 
-static int tps65910_reg_write(struct tps65910_reg *pmic, u8 reg, u8 val)
+static int tps65910_pmic_reg_write(struct tps65910_reg *pmic, u8 reg, u8 val)
 {
        int err;
 
 {
        int err;
 
@@ -420,7 +507,7 @@ static int tps65910_is_enabled(struct regulator_dev *dev)
        if (reg < 0)
                return reg;
 
        if (reg < 0)
                return reg;
 
-       value = tps65910_reg_read(pmic, reg);
+       value = tps65910_pmic_reg_read(pmic, reg);
        if (value < 0)
                return value;
 
        if (value < 0)
                return value;
 
@@ -453,6 +540,12 @@ static int tps65910_disable(struct regulator_dev *dev)
        return tps65910_clear_bits(mfd, reg, TPS65910_SUPPLY_STATE_ENABLED);
 }
 
        return tps65910_clear_bits(mfd, reg, TPS65910_SUPPLY_STATE_ENABLED);
 }
 
+static int tps65910_enable_time(struct regulator_dev *dev)
+{
+       struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+       int id = rdev_get_id(dev);
+       return pmic->info[id]->enable_time_us;
+}
 
 static int tps65910_set_mode(struct regulator_dev *dev, unsigned int mode)
 {
 
 static int tps65910_set_mode(struct regulator_dev *dev, unsigned int mode)
 {
@@ -487,11 +580,11 @@ static unsigned int tps65910_get_mode(struct regulator_dev *dev)
        if (reg < 0)
                return reg;
 
        if (reg < 0)
                return reg;
 
-       value = tps65910_reg_read(pmic, reg);
+       value = tps65910_pmic_reg_read(pmic, reg);
        if (value < 0)
                return value;
 
        if (value < 0)
                return value;
 
-       if (value & LDO_ST_ON_BIT)
+       if (!(value & LDO_ST_ON_BIT))
                return REGULATOR_MODE_STANDBY;
        else if (value & LDO_ST_MODE_BIT)
                return REGULATOR_MODE_IDLE;
                return REGULATOR_MODE_STANDBY;
        else if (value & LDO_ST_MODE_BIT)
                return REGULATOR_MODE_IDLE;
@@ -499,36 +592,36 @@ static unsigned int tps65910_get_mode(struct regulator_dev *dev)
                return REGULATOR_MODE_NORMAL;
 }
 
                return REGULATOR_MODE_NORMAL;
 }
 
-static int tps65910_get_voltage_dcdc(struct regulator_dev *dev)
+static int tps65910_get_voltage_dcdc_sel(struct regulator_dev *dev)
 {
        struct tps65910_reg *pmic = rdev_get_drvdata(dev);
 {
        struct tps65910_reg *pmic = rdev_get_drvdata(dev);
-       int id = rdev_get_id(dev), voltage = 0;
+       int id = rdev_get_id(dev);
        int opvsel = 0, srvsel = 0, vselmax = 0, mult = 0, sr = 0;
 
        switch (id) {
        case TPS65910_REG_VDD1:
        int opvsel = 0, srvsel = 0, vselmax = 0, mult = 0, sr = 0;
 
        switch (id) {
        case TPS65910_REG_VDD1:
-               opvsel = tps65910_reg_read(pmic, TPS65910_VDD1_OP);
-               mult = tps65910_reg_read(pmic, TPS65910_VDD1);
+               opvsel = tps65910_pmic_reg_read(pmic, TPS65910_VDD1_OP);
+               mult = tps65910_pmic_reg_read(pmic, TPS65910_VDD1);
                mult = (mult & VDD1_VGAIN_SEL_MASK) >> VDD1_VGAIN_SEL_SHIFT;
                mult = (mult & VDD1_VGAIN_SEL_MASK) >> VDD1_VGAIN_SEL_SHIFT;
-               srvsel = tps65910_reg_read(pmic, TPS65910_VDD1_SR);
+               srvsel = tps65910_pmic_reg_read(pmic, TPS65910_VDD1_SR);
                sr = opvsel & VDD1_OP_CMD_MASK;
                opvsel &= VDD1_OP_SEL_MASK;
                srvsel &= VDD1_SR_SEL_MASK;
                vselmax = 75;
                break;
        case TPS65910_REG_VDD2:
                sr = opvsel & VDD1_OP_CMD_MASK;
                opvsel &= VDD1_OP_SEL_MASK;
                srvsel &= VDD1_SR_SEL_MASK;
                vselmax = 75;
                break;
        case TPS65910_REG_VDD2:
-               opvsel = tps65910_reg_read(pmic, TPS65910_VDD2_OP);
-               mult = tps65910_reg_read(pmic, TPS65910_VDD2);
+               opvsel = tps65910_pmic_reg_read(pmic, TPS65910_VDD2_OP);
+               mult = tps65910_pmic_reg_read(pmic, TPS65910_VDD2);
                mult = (mult & VDD2_VGAIN_SEL_MASK) >> VDD2_VGAIN_SEL_SHIFT;
                mult = (mult & VDD2_VGAIN_SEL_MASK) >> VDD2_VGAIN_SEL_SHIFT;
-               srvsel = tps65910_reg_read(pmic, TPS65910_VDD2_SR);
+               srvsel = tps65910_pmic_reg_read(pmic, TPS65910_VDD2_SR);
                sr = opvsel & VDD2_OP_CMD_MASK;
                opvsel &= VDD2_OP_SEL_MASK;
                srvsel &= VDD2_SR_SEL_MASK;
                vselmax = 75;
                break;
        case TPS65911_REG_VDDCTRL:
                sr = opvsel & VDD2_OP_CMD_MASK;
                opvsel &= VDD2_OP_SEL_MASK;
                srvsel &= VDD2_SR_SEL_MASK;
                vselmax = 75;
                break;
        case TPS65911_REG_VDDCTRL:
-               opvsel = tps65910_reg_read(pmic, TPS65911_VDDCTRL_OP);
-               srvsel = tps65910_reg_read(pmic, TPS65911_VDDCTRL_SR);
+               opvsel = tps65910_pmic_reg_read(pmic, TPS65911_VDDCTRL_OP);
+               srvsel = tps65910_pmic_reg_read(pmic, TPS65911_VDDCTRL_SR);
                sr = opvsel & VDDCTRL_OP_CMD_MASK;
                opvsel &= VDDCTRL_OP_SEL_MASK;
                srvsel &= VDDCTRL_SR_SEL_MASK;
                sr = opvsel & VDDCTRL_OP_CMD_MASK;
                opvsel &= VDDCTRL_OP_SEL_MASK;
                srvsel &= VDDCTRL_SR_SEL_MASK;
@@ -546,9 +639,7 @@ static int tps65910_get_voltage_dcdc(struct regulator_dev *dev)
                        srvsel = 3;
                if (srvsel > vselmax)
                        srvsel = vselmax;
                        srvsel = 3;
                if (srvsel > vselmax)
                        srvsel = vselmax;
-               srvsel -= 3;
-
-               voltage = (srvsel * VDD1_2_OFFSET + VDD1_2_MIN_VOLT) * 100;
+               return srvsel - 3;
        } else {
 
                /* normalise to valid range*/
        } else {
 
                /* normalise to valid range*/
@@ -556,14 +647,9 @@ static int tps65910_get_voltage_dcdc(struct regulator_dev *dev)
                        opvsel = 3;
                if (opvsel > vselmax)
                        opvsel = vselmax;
                        opvsel = 3;
                if (opvsel > vselmax)
                        opvsel = vselmax;
-               opvsel -= 3;
-
-               voltage = (opvsel * VDD1_2_OFFSET + VDD1_2_MIN_VOLT) * 100;
+               return opvsel - 3;
        }
        }
-
-       voltage *= mult;
-
-       return voltage;
+       return -EINVAL;
 }
 
 static int tps65910_get_voltage(struct regulator_dev *dev)
 }
 
 static int tps65910_get_voltage(struct regulator_dev *dev)
@@ -575,7 +661,7 @@ static int tps65910_get_voltage(struct regulator_dev *dev)
        if (reg < 0)
                return reg;
 
        if (reg < 0)
                return reg;
 
-       value = tps65910_reg_read(pmic, reg);
+       value = tps65910_pmic_reg_read(pmic, reg);
        if (value < 0)
                return value;
 
        if (value < 0)
                return value;
 
@@ -596,7 +682,7 @@ static int tps65910_get_voltage(struct regulator_dev *dev)
                return -EINVAL;
        }
 
                return -EINVAL;
        }
 
-       voltage = pmic->info[id]->table[value] * 1000;
+       voltage = pmic->info[id]->voltage_table[value] * 1000;
 
        return voltage;
 }
 
        return voltage;
 }
@@ -614,7 +700,7 @@ static int tps65911_get_voltage(struct regulator_dev *dev)
 
        reg = pmic->get_ctrl_reg(id);
 
 
        reg = pmic->get_ctrl_reg(id);
 
-       value = tps65910_reg_read(pmic, reg);
+       value = tps65910_pmic_reg_read(pmic, reg);
 
        switch (id) {
        case TPS65911_REG_LDO1:
 
        switch (id) {
        case TPS65911_REG_LDO1:
@@ -646,8 +732,9 @@ static int tps65911_get_voltage(struct regulator_dev *dev)
                step_mv = 100;
                break;
        case TPS65910_REG_VIO:
                step_mv = 100;
                break;
        case TPS65910_REG_VIO:
-               return pmic->info[id]->table[value] * 1000;
-               break;
+               value &= LDO_SEL_MASK;
+               value >>= LDO_SEL_SHIFT;
+               return pmic->info[id]->voltage_table[value] * 1000;
        default:
                return -EINVAL;
        }
        default:
                return -EINVAL;
        }
@@ -655,8 +742,8 @@ static int tps65911_get_voltage(struct regulator_dev *dev)
        return (LDO_MIN_VOLT + value * step_mv) * 1000;
 }
 
        return (LDO_MIN_VOLT + value * step_mv) * 1000;
 }
 
-static int tps65910_set_voltage_dcdc(struct regulator_dev *dev,
-                               unsigned selector)
+static int tps65910_set_voltage_dcdc_sel(struct regulator_dev *dev,
+                                        unsigned selector)
 {
        struct tps65910_reg *pmic = rdev_get_drvdata(dev);
        int id = rdev_get_id(dev), vsel;
 {
        struct tps65910_reg *pmic = rdev_get_drvdata(dev);
        int id = rdev_get_id(dev), vsel;
@@ -664,36 +751,37 @@ static int tps65910_set_voltage_dcdc(struct regulator_dev *dev,
 
        switch (id) {
        case TPS65910_REG_VDD1:
 
        switch (id) {
        case TPS65910_REG_VDD1:
-               dcdc_mult = (selector / VDD1_2_NUM_VOLTS) + 1;
+               dcdc_mult = (selector / VDD1_2_NUM_VOLT_FINE) + 1;
                if (dcdc_mult == 1)
                        dcdc_mult--;
                if (dcdc_mult == 1)
                        dcdc_mult--;
-               vsel = (selector % VDD1_2_NUM_VOLTS) + 3;
+               vsel = (selector % VDD1_2_NUM_VOLT_FINE) + 3;
 
                tps65910_modify_bits(pmic, TPS65910_VDD1,
                                (dcdc_mult << VDD1_VGAIN_SEL_SHIFT),
                                                VDD1_VGAIN_SEL_MASK);
 
                tps65910_modify_bits(pmic, TPS65910_VDD1,
                                (dcdc_mult << VDD1_VGAIN_SEL_SHIFT),
                                                VDD1_VGAIN_SEL_MASK);
-               tps65910_reg_write(pmic, TPS65910_VDD1_OP, vsel);
+               tps65910_pmic_reg_write(pmic, TPS65910_VDD1_OP, vsel);
                break;
        case TPS65910_REG_VDD2:
                break;
        case TPS65910_REG_VDD2:
-               dcdc_mult = (selector / VDD1_2_NUM_VOLTS) + 1;
+               dcdc_mult = (selector / VDD1_2_NUM_VOLT_FINE) + 1;
                if (dcdc_mult == 1)
                        dcdc_mult--;
                if (dcdc_mult == 1)
                        dcdc_mult--;
-               vsel = (selector % VDD1_2_NUM_VOLTS) + 3;
+               vsel = (selector % VDD1_2_NUM_VOLT_FINE) + 3;
 
                tps65910_modify_bits(pmic, TPS65910_VDD2,
                                (dcdc_mult << VDD2_VGAIN_SEL_SHIFT),
                                                VDD1_VGAIN_SEL_MASK);
 
                tps65910_modify_bits(pmic, TPS65910_VDD2,
                                (dcdc_mult << VDD2_VGAIN_SEL_SHIFT),
                                                VDD1_VGAIN_SEL_MASK);
-               tps65910_reg_write(pmic, TPS65910_VDD2_OP, vsel);
+               tps65910_pmic_reg_write(pmic, TPS65910_VDD2_OP, vsel);
                break;
        case TPS65911_REG_VDDCTRL:
                break;
        case TPS65911_REG_VDDCTRL:
-               vsel = selector;
-               tps65910_reg_write(pmic, TPS65911_VDDCTRL_OP, vsel);
+               vsel = selector + 3;
+               tps65910_pmic_reg_write(pmic, TPS65911_VDDCTRL_OP, vsel);
        }
 
        return 0;
 }
 
        }
 
        return 0;
 }
 
-static int tps65910_set_voltage(struct regulator_dev *dev, unsigned selector)
+static int tps65910_set_voltage_sel(struct regulator_dev *dev,
+                                   unsigned selector)
 {
        struct tps65910_reg *pmic = rdev_get_drvdata(dev);
        int reg, id = rdev_get_id(dev);
 {
        struct tps65910_reg *pmic = rdev_get_drvdata(dev);
        int reg, id = rdev_get_id(dev);
@@ -719,7 +807,8 @@ static int tps65910_set_voltage(struct regulator_dev *dev, unsigned selector)
        return -EINVAL;
 }
 
        return -EINVAL;
 }
 
-static int tps65911_set_voltage(struct regulator_dev *dev, unsigned selector)
+static int tps65911_set_voltage_sel(struct regulator_dev *dev,
+                                   unsigned selector)
 {
        struct tps65910_reg *pmic = rdev_get_drvdata(dev);
        int reg, id = rdev_get_id(dev);
 {
        struct tps65910_reg *pmic = rdev_get_drvdata(dev);
        int reg, id = rdev_get_id(dev);
@@ -739,9 +828,11 @@ static int tps65911_set_voltage(struct regulator_dev *dev, unsigned selector)
        case TPS65911_REG_LDO6:
        case TPS65911_REG_LDO7:
        case TPS65911_REG_LDO8:
        case TPS65911_REG_LDO6:
        case TPS65911_REG_LDO7:
        case TPS65911_REG_LDO8:
-       case TPS65910_REG_VIO:
                return tps65910_modify_bits(pmic, reg,
                                (selector << LDO_SEL_SHIFT), LDO3_SEL_MASK);
                return tps65910_modify_bits(pmic, reg,
                                (selector << LDO_SEL_SHIFT), LDO3_SEL_MASK);
+       case TPS65910_REG_VIO:
+               return tps65910_modify_bits(pmic, reg,
+                               (selector << LDO_SEL_SHIFT), LDO_SEL_MASK);
        }
 
        return -EINVAL;
        }
 
        return -EINVAL;
@@ -756,9 +847,9 @@ static int tps65910_list_voltage_dcdc(struct regulator_dev *dev,
        switch (id) {
        case TPS65910_REG_VDD1:
        case TPS65910_REG_VDD2:
        switch (id) {
        case TPS65910_REG_VDD1:
        case TPS65910_REG_VDD2:
-               mult = (selector / VDD1_2_NUM_VOLTS) + 1;
+               mult = (selector / VDD1_2_NUM_VOLT_FINE) + 1;
                volt = VDD1_2_MIN_VOLT +
                volt = VDD1_2_MIN_VOLT +
-                               (selector % VDD1_2_NUM_VOLTS) * VDD1_2_OFFSET;
+                               (selector % VDD1_2_NUM_VOLT_FINE) * VDD1_2_OFFSET;
                break;
        case TPS65911_REG_VDDCTRL:
                volt = VDDCTRL_MIN_VOLT + (selector * VDDCTRL_OFFSET);
                break;
        case TPS65911_REG_VDDCTRL:
                volt = VDDCTRL_MIN_VOLT + (selector * VDDCTRL_OFFSET);
@@ -780,11 +871,11 @@ static int tps65910_list_voltage(struct regulator_dev *dev,
        if (id < TPS65910_REG_VIO || id > TPS65910_REG_VMMC)
                return -EINVAL;
 
        if (id < TPS65910_REG_VIO || id > TPS65910_REG_VMMC)
                return -EINVAL;
 
-       if (selector >= pmic->info[id]->table_len)
+       if (selector >= pmic->info[id]->n_voltages)
                return -EINVAL;
        else
                return -EINVAL;
        else
-               voltage = pmic->info[id]->table[selector] * 1000;
-
+               voltage = pmic->info[id]->voltage_table[selector] * 1000;
+       
        return voltage;
 }
 
        return voltage;
 }
 
@@ -819,7 +910,7 @@ static int tps65911_list_voltage(struct regulator_dev *dev, unsigned selector)
                step_mv = 100;
                break;
        case TPS65910_REG_VIO:
                step_mv = 100;
                break;
        case TPS65910_REG_VIO:
-               return pmic->info[id]->table[selector] * 1000;
+               return pmic->info[id]->voltage_table[selector] * 1000;
        default:
                return -EINVAL;
        }
        default:
                return -EINVAL;
        }
@@ -827,15 +918,42 @@ static int tps65911_list_voltage(struct regulator_dev *dev, unsigned selector)
        return (LDO_MIN_VOLT + selector * step_mv) * 1000;
 }
 
        return (LDO_MIN_VOLT + selector * step_mv) * 1000;
 }
 
+static int tps65910_set_voltage_dcdc_time_sel(struct regulator_dev *dev,
+               unsigned int old_selector, unsigned int new_selector)
+{
+       int id = rdev_get_id(dev);
+       int old_volt, new_volt;
+
+       old_volt = tps65910_list_voltage_dcdc(dev, old_selector);
+       if (old_volt < 0)
+               return old_volt;
+
+       new_volt = tps65910_list_voltage_dcdc(dev, new_selector);
+       if (new_volt < 0)
+               return new_volt;
+
+       /* VDD1 and VDD2 are 12.5mV/us, VDDCTRL is 100mV/20us */
+       switch (id) {
+       case TPS65910_REG_VDD1:
+       case TPS65910_REG_VDD2:
+               return DIV_ROUND_UP(abs(old_volt - new_volt), 12500);
+       case TPS65911_REG_VDDCTRL:
+               return DIV_ROUND_UP(abs(old_volt - new_volt), 5000);
+       }
+       return -EINVAL;
+}
+
 /* Regulator ops (except VRTC) */
 static struct regulator_ops tps65910_ops_dcdc = {
        .is_enabled             = tps65910_is_enabled,
        .enable                 = tps65910_enable,
        .disable                = tps65910_disable,
 /* Regulator ops (except VRTC) */
 static struct regulator_ops tps65910_ops_dcdc = {
        .is_enabled             = tps65910_is_enabled,
        .enable                 = tps65910_enable,
        .disable                = tps65910_disable,
+       .enable_time            = tps65910_enable_time,
        .set_mode               = tps65910_set_mode,
        .get_mode               = tps65910_get_mode,
        .set_mode               = tps65910_set_mode,
        .get_mode               = tps65910_get_mode,
-       .get_voltage            = tps65910_get_voltage_dcdc,
-       .set_voltage_sel        = tps65910_set_voltage_dcdc,
+       .get_voltage_sel        = tps65910_get_voltage_dcdc_sel,
+       .set_voltage_sel        = tps65910_set_voltage_dcdc_sel,
+       .set_voltage_time_sel   = tps65910_set_voltage_dcdc_time_sel,
        .list_voltage           = tps65910_list_voltage_dcdc,
 };
 
        .list_voltage           = tps65910_list_voltage_dcdc,
 };
 
@@ -843,6 +961,7 @@ static struct regulator_ops tps65910_ops_vdd3 = {
        .is_enabled             = tps65910_is_enabled,
        .enable                 = tps65910_enable,
        .disable                = tps65910_disable,
        .is_enabled             = tps65910_is_enabled,
        .enable                 = tps65910_enable,
        .disable                = tps65910_disable,
+       .enable_time            = tps65910_enable_time,
        .set_mode               = tps65910_set_mode,
        .get_mode               = tps65910_get_mode,
        .get_voltage            = tps65910_get_voltage_vdd3,
        .set_mode               = tps65910_set_mode,
        .get_mode               = tps65910_get_mode,
        .get_voltage            = tps65910_get_voltage_vdd3,
@@ -853,10 +972,11 @@ static struct regulator_ops tps65910_ops = {
        .is_enabled             = tps65910_is_enabled,
        .enable                 = tps65910_enable,
        .disable                = tps65910_disable,
        .is_enabled             = tps65910_is_enabled,
        .enable                 = tps65910_enable,
        .disable                = tps65910_disable,
+       .enable_time            = tps65910_enable_time,
        .set_mode               = tps65910_set_mode,
        .get_mode               = tps65910_get_mode,
        .get_voltage            = tps65910_get_voltage,
        .set_mode               = tps65910_set_mode,
        .get_mode               = tps65910_get_mode,
        .get_voltage            = tps65910_get_voltage,
-       .set_voltage_sel        = tps65910_set_voltage,
+       .set_voltage_sel        = tps65910_set_voltage_sel,
        .list_voltage           = tps65910_list_voltage,
 };
 
        .list_voltage           = tps65910_list_voltage,
 };
 
@@ -864,13 +984,147 @@ static struct regulator_ops tps65911_ops = {
        .is_enabled             = tps65910_is_enabled,
        .enable                 = tps65910_enable,
        .disable                = tps65910_disable,
        .is_enabled             = tps65910_is_enabled,
        .enable                 = tps65910_enable,
        .disable                = tps65910_disable,
+       .enable_time            = tps65910_enable_time,
        .set_mode               = tps65910_set_mode,
        .get_mode               = tps65910_get_mode,
        .get_voltage            = tps65911_get_voltage,
        .set_mode               = tps65910_set_mode,
        .get_mode               = tps65910_get_mode,
        .get_voltage            = tps65911_get_voltage,
-       .set_voltage_sel        = tps65911_set_voltage,
+       .set_voltage_sel        = tps65911_set_voltage_sel,
        .list_voltage           = tps65911_list_voltage,
 };
 
        .list_voltage           = tps65911_list_voltage,
 };
 
+static int tps65910_set_ext_sleep_config(struct tps65910_reg *pmic,
+               int id, int ext_sleep_config)
+{
+       struct tps65910 *mfd = pmic->mfd;
+       u8 regoffs = (pmic->ext_sleep_control[id] >> 8) & 0xFF;
+       u8 bit_pos = (1 << pmic->ext_sleep_control[id] & 0xFF);
+       int ret;
+
+       /*
+        * Regulator can not be control from multiple external input EN1, EN2
+        * and EN3 together.
+        */
+       if (ext_sleep_config & EXT_SLEEP_CONTROL) {
+               int en_count;
+               en_count = ((ext_sleep_config &
+                               TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1) != 0);
+               en_count += ((ext_sleep_config &
+                               TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2) != 0);
+               en_count += ((ext_sleep_config &
+                               TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3) != 0);
+               en_count += ((ext_sleep_config &
+                               TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP) != 0);
+               if (en_count > 1) {
+                       dev_err(mfd->dev,
+                               "External sleep control flag is not proper\n");
+                       return -EINVAL;
+               }
+       }
+
+       pmic->board_ext_control[id] = ext_sleep_config;
+
+       /* External EN1 control */
+       if (ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1)
+               ret = tps65910_set_bits(mfd,
+                               TPS65910_EN1_LDO_ASS + regoffs, bit_pos);
+       else
+               ret = tps65910_clear_bits(mfd,
+                               TPS65910_EN1_LDO_ASS + regoffs, bit_pos);
+       if (ret < 0) {
+               dev_err(mfd->dev,
+                       "Error in configuring external control EN1\n");
+               return ret;
+       }
+
+       /* External EN2 control */
+       if (ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2)
+               ret = tps65910_set_bits(mfd,
+                               TPS65910_EN2_LDO_ASS + regoffs, bit_pos);
+       else
+               ret = tps65910_clear_bits(mfd,
+                               TPS65910_EN2_LDO_ASS + regoffs, bit_pos);
+       if (ret < 0) {
+               dev_err(mfd->dev,
+                       "Error in configuring external control EN2\n");
+               return ret;
+       }
+
+       /* External EN3 control for TPS65910 LDO only */
+       if ((tps65910_chip_id(mfd) == TPS65910) &&
+                       (id >= TPS65910_REG_VDIG1)) {
+               if (ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3)
+                       ret = tps65910_set_bits(mfd,
+                               TPS65910_EN3_LDO_ASS + regoffs, bit_pos);
+               else
+                       ret = tps65910_clear_bits(mfd,
+                               TPS65910_EN3_LDO_ASS + regoffs, bit_pos);
+               if (ret < 0) {
+                       dev_err(mfd->dev,
+                               "Error in configuring external control EN3\n");
+                       return ret;
+               }
+       }
+
+       /* Return if no external control is selected */
+       if (!(ext_sleep_config & EXT_SLEEP_CONTROL)) {
+               /* Clear all sleep controls */
+               ret = tps65910_clear_bits(mfd,
+                       TPS65910_SLEEP_KEEP_LDO_ON + regoffs, bit_pos);
+               if (!ret)
+                       ret = tps65910_clear_bits(mfd,
+                               TPS65910_SLEEP_SET_LDO_OFF + regoffs, bit_pos);
+               if (ret < 0)
+                       dev_err(mfd->dev,
+                               "Error in configuring SLEEP register\n");
+               return ret;
+       }
+
+       /*
+        * For regulator that has separate operational and sleep register make
+        * sure that operational is used and clear sleep register to turn
+        * regulator off when external control is inactive
+        */
+       if ((id == TPS65910_REG_VDD1) ||
+               (id == TPS65910_REG_VDD2) ||
+                       ((id == TPS65911_REG_VDDCTRL) &&
+                               (tps65910_chip_id(mfd) == TPS65911))) {
+               int op_reg_add = pmic->get_ctrl_reg(id) + 1;
+               int sr_reg_add = pmic->get_ctrl_reg(id) + 2;
+               int opvsel = tps65910_pmic_reg_read(pmic, op_reg_add);
+               int srvsel = tps65910_pmic_reg_read(pmic, sr_reg_add);
+               if (opvsel & VDD1_OP_CMD_MASK) {
+                       u8 reg_val = srvsel & VDD1_OP_SEL_MASK;
+                       ret = tps65910_pmic_reg_write(pmic, op_reg_add, reg_val);
+                       if (ret < 0) {
+                               dev_err(mfd->dev,
+                                       "Error in configuring op register\n");
+                               return ret;
+                       }
+               }
+               ret = tps65910_pmic_reg_write(pmic, sr_reg_add, 0);
+               if (ret < 0) {
+                       dev_err(mfd->dev, "Error in settting sr register\n");
+                       return ret;
+               }
+       }
+
+       ret = tps65910_clear_bits(mfd,
+                       TPS65910_SLEEP_KEEP_LDO_ON + regoffs, bit_pos);
+       if (!ret) {
+               if (ext_sleep_config & TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP)
+                       ret = tps65910_set_bits(mfd,
+                               TPS65910_SLEEP_SET_LDO_OFF + regoffs, bit_pos);
+               else
+                       ret = tps65910_clear_bits(mfd,
+                               TPS65910_SLEEP_SET_LDO_OFF + regoffs, bit_pos);
+       }
+       if (ret < 0)
+               dev_err(mfd->dev,
+                       "Error in configuring SLEEP register\n");
+
+       return ret;
+}
+
 static __devinit int tps65910_probe(struct platform_device *pdev)
 {
        struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent);
 static __devinit int tps65910_probe(struct platform_device *pdev)
 {
        struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent);
@@ -885,8 +1139,6 @@ static __devinit int tps65910_probe(struct platform_device *pdev)
        if (!pmic_plat_data)
                return -EINVAL;
 
        if (!pmic_plat_data)
                return -EINVAL;
 
-       reg_data = pmic_plat_data->tps65910_pmic_init_data;
-
        pmic = kzalloc(sizeof(*pmic), GFP_KERNEL);
        if (!pmic)
                return -ENOMEM;
        pmic = kzalloc(sizeof(*pmic), GFP_KERNEL);
        if (!pmic)
                return -ENOMEM;
@@ -902,27 +1154,64 @@ static __devinit int tps65910_probe(struct platform_device *pdev)
        switch(tps65910_chip_id(tps65910)) {
        case TPS65910:
                pmic->get_ctrl_reg = &tps65910_get_ctrl_register;
        switch(tps65910_chip_id(tps65910)) {
        case TPS65910:
                pmic->get_ctrl_reg = &tps65910_get_ctrl_register;
+               pmic->num_regulators = ARRAY_SIZE(tps65910_regs);
+               pmic->ext_sleep_control = tps65910_ext_sleep_control;
                info = tps65910_regs;
                break;
        case TPS65911:
                pmic->get_ctrl_reg = &tps65911_get_ctrl_register;
                info = tps65910_regs;
                break;
        case TPS65911:
                pmic->get_ctrl_reg = &tps65911_get_ctrl_register;
+               pmic->num_regulators = ARRAY_SIZE(tps65911_regs);
+               pmic->ext_sleep_control = tps65911_ext_sleep_control;
                info = tps65911_regs;
                break;
        default:
                pr_err("Invalid tps chip version\n");
                info = tps65911_regs;
                break;
        default:
                pr_err("Invalid tps chip version\n");
+               kfree(pmic);
                return -ENODEV;
        }
 
                return -ENODEV;
        }
 
-       for (i = 0; i < TPS65910_NUM_REGULATOR; i++, info++, reg_data++) {
+       pmic->desc = kcalloc(pmic->num_regulators,
+                       sizeof(struct regulator_desc), GFP_KERNEL);
+       if (!pmic->desc) {
+               err = -ENOMEM;
+               goto err_free_pmic;
+       }
+
+       pmic->info = kcalloc(pmic->num_regulators,
+                       sizeof(struct tps_info *), GFP_KERNEL);
+       if (!pmic->info) {
+               err = -ENOMEM;
+               goto err_free_desc;
+       }
+
+       pmic->rdev = kcalloc(pmic->num_regulators,
+                       sizeof(struct regulator_dev *), GFP_KERNEL);
+       if (!pmic->rdev) {
+               err = -ENOMEM;
+               goto err_free_info;
+       }
+
+       for (i = 0; i < pmic->num_regulators && i < TPS65910_NUM_REGS;
+                       i++, info++) {
+
+               reg_data = pmic_plat_data->tps65910_pmic_init_data[i];
+
+               /* Regulator API handles empty constraints but not NULL
+                * constraints */
+               if (!reg_data)
+                       continue;
+
                /* Register the regulators */
                pmic->info[i] = info;
 
                pmic->desc[i].name = info->name;
                pmic->desc[i].id = i;
                /* Register the regulators */
                pmic->info[i] = info;
 
                pmic->desc[i].name = info->name;
                pmic->desc[i].id = i;
-               pmic->desc[i].n_voltages = info->table_len;
+               pmic->desc[i].n_voltages = info->n_voltages;
 
                if (i == TPS65910_REG_VDD1 || i == TPS65910_REG_VDD2) {
                        pmic->desc[i].ops = &tps65910_ops_dcdc;
 
                if (i == TPS65910_REG_VDD1 || i == TPS65910_REG_VDD2) {
                        pmic->desc[i].ops = &tps65910_ops_dcdc;
+                       pmic->desc[i].n_voltages = VDD1_2_NUM_VOLT_FINE *
+                                                       VDD1_2_NUM_VOLT_COARSE;
                } else if (i == TPS65910_REG_VDD3) {
                        if (tps65910_chip_id(tps65910) == TPS65910)
                                pmic->desc[i].ops = &tps65910_ops_vdd3;
                } else if (i == TPS65910_REG_VDD3) {
                        if (tps65910_chip_id(tps65910) == TPS65910)
                                pmic->desc[i].ops = &tps65910_ops_vdd3;
@@ -935,6 +1224,16 @@ static __devinit int tps65910_probe(struct platform_device *pdev)
                                pmic->desc[i].ops = &tps65911_ops;
                }
 
                                pmic->desc[i].ops = &tps65911_ops;
                }
 
+               err = tps65910_set_ext_sleep_config(pmic, i,
+                               pmic_plat_data->regulator_ext_sleep_control[i]);
+               /*
+                * Failing on regulator for configuring externally control
+                * is not a serious issue, just throw warning.
+                */
+               if (err < 0)
+                       dev_warn(tps65910->dev,
+                               "Failed to initialise ext control config\n");
+
                pmic->desc[i].type = REGULATOR_VOLTAGE;
                pmic->desc[i].owner = THIS_MODULE;
 
                pmic->desc[i].type = REGULATOR_VOLTAGE;
                pmic->desc[i].owner = THIS_MODULE;
 
@@ -945,7 +1244,7 @@ static __devinit int tps65910_probe(struct platform_device *pdev)
                                "failed to register %s regulator\n",
                                pdev->name);
                        err = PTR_ERR(rdev);
                                "failed to register %s regulator\n",
                                pdev->name);
                        err = PTR_ERR(rdev);
-                       goto err;
+                       goto err_unregister_regulator;
                }
 
                /* Save regulator for cleanup */
                }
 
                /* Save regulator for cleanup */
@@ -953,26 +1252,64 @@ static __devinit int tps65910_probe(struct platform_device *pdev)
        }
        return 0;
 
        }
        return 0;
 
-err:
+err_unregister_regulator:
        while (--i >= 0)
                regulator_unregister(pmic->rdev[i]);
        while (--i >= 0)
                regulator_unregister(pmic->rdev[i]);
-
+       kfree(pmic->rdev);
+err_free_info:
+       kfree(pmic->info);
+err_free_desc:
+       kfree(pmic->desc);
+err_free_pmic:
        kfree(pmic);
        return err;
 }
 
 static int __devexit tps65910_remove(struct platform_device *pdev)
 {
        kfree(pmic);
        return err;
 }
 
 static int __devexit tps65910_remove(struct platform_device *pdev)
 {
-       struct tps65910_reg *tps65910_reg = platform_get_drvdata(pdev);
+       struct tps65910_reg *pmic = platform_get_drvdata(pdev);
        int i;
 
        int i;
 
-       for (i = 0; i < TPS65910_NUM_REGULATOR; i++)
-               regulator_unregister(tps65910_reg->rdev[i]);
+       for (i = 0; i < pmic->num_regulators; i++)
+               regulator_unregister(pmic->rdev[i]);
 
 
-       kfree(tps65910_reg);
+       kfree(pmic->rdev);
+       kfree(pmic->info);
+       kfree(pmic->desc);
+       kfree(pmic);
        return 0;
 }
 
        return 0;
 }
 
+static void tps65910_shutdown(struct platform_device *pdev)
+{
+       struct tps65910_reg *pmic = platform_get_drvdata(pdev);
+       int i;
+
+       /*
+        * Before bootloader jumps to kernel, it makes sure that required
+        * external control signals are in desired state so that given rails
+        * can be configure accordingly.
+        * If rails are configured to be controlled from external control
+        * then before shutting down/rebooting the system, the external
+        * control configuration need to be remove from the rails so that
+        * its output will be available as per register programming even
+        * if external controls are removed. This is require when the POR
+        * value of the control signals are not in active state and before
+        * bootloader initializes it, the system requires the rail output
+        * to be active for booting.
+        */
+       for (i = 0; i < pmic->num_regulators; i++) {
+               int err;
+               if (!pmic->rdev[i])
+                       continue;
+
+               err = tps65910_set_ext_sleep_config(pmic, i, 0);
+               if (err < 0)
+                       dev_err(&pdev->dev,
+                               "Error in clearing external control\n");
+       }
+}
+
 static struct platform_driver tps65910_driver = {
        .driver = {
                .name = "tps65910-pmic",
 static struct platform_driver tps65910_driver = {
        .driver = {
                .name = "tps65910-pmic",
@@ -980,13 +1317,14 @@ static struct platform_driver tps65910_driver = {
        },
        .probe = tps65910_probe,
        .remove = __devexit_p(tps65910_remove),
        },
        .probe = tps65910_probe,
        .remove = __devexit_p(tps65910_remove),
+       .shutdown = tps65910_shutdown,
 };
 
 static int __init tps65910_init(void)
 {
        return platform_driver_register(&tps65910_driver);
 }
 };
 
 static int __init tps65910_init(void)
 {
        return platform_driver_register(&tps65910_driver);
 }
-subsys_initcall(tps65910_init);
+subsys_initcall_sync(tps65910_init);
 
 static void __exit tps65910_cleanup(void)
 {
 
 static void __exit tps65910_cleanup(void)
 {
@@ -995,6 +1333,6 @@ static void __exit tps65910_cleanup(void)
 module_exit(tps65910_cleanup);
 
 MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>");
 module_exit(tps65910_cleanup);
 
 MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>");
-MODULE_DESCRIPTION("TPS6507x voltage regulator driver");
+MODULE_DESCRIPTION("TPS65910/TPS65911 voltage regulator driver");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:tps65910-pmic");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:tps65910-pmic");
index a567a8e131e7f87aa0f0b2896ecbd279608b04a0..bfa8a408fb33e8bce7226884d7ee619fa117e522 100755 (executable)
@@ -1110,5 +1110,10 @@ config RTC_DRV_PUV3
 
          This drive can also be built as a module. If so, the module
          will be called rtc-puv3.
 
          This drive can also be built as a module. If so, the module
          will be called rtc-puv3.
+config  TPS65910_RTC
+       tristate "tps65910 rtc for rk"
+       depends on MFD_TPS65910
+       help
+               enable tps65910 rtc for system
 
 endif # RTC_CLASS
 
 endif # RTC_CLASS
index 3f5e0685673bfc2abafdef611d6a49ca88542b50..6d4c945e6b42bbde4d8c3b677ee2cfb1f5aba3ee 100755 (executable)
@@ -115,3 +115,4 @@ obj-$(CONFIG_RTC_DRV_WM8350)        += rtc-wm8350.o
 obj-$(CONFIG_RTC_DRV_X1205)    += rtc-x1205.o
 obj-$(CONFIG_RTC_HYM8563)      += rtc-HYM8563.o
 obj-$(CONFIG_RTC_M41T66)       += rtc-m41t66.o
 obj-$(CONFIG_RTC_DRV_X1205)    += rtc-x1205.o
 obj-$(CONFIG_RTC_HYM8563)      += rtc-HYM8563.o
 obj-$(CONFIG_RTC_M41T66)       += rtc-m41t66.o
+obj-$(CONFIG_TPS65910_RTC)  += rtc-tps65910.o
diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c
new file mode 100755 (executable)
index 0000000..f6a8693
--- /dev/null
@@ -0,0 +1,695 @@
+/*
+ *     Real Time Clock driver for Wolfson Microelectronics tps65910
+ *
+ *     Copyright (C) 2009 Wolfson Microelectronics PLC.
+ *
+ *  Author: Mark Brown <broonie@opensource.wolfsonmicro.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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/time.h>
+#include <linux/rtc.h>
+#include <linux/slab.h>
+#include <linux/bcd.h>
+#include <linux/interrupt.h>
+#include <linux/ioctl.h>
+#include <linux/completion.h>
+#include <linux/mfd/tps65910.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/miscdevice.h>
+
+
+/* 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                          7
+#define ALL_ALM_REGS                           6
+
+
+#define RTC_SET_TIME_RETRIES   5
+#define RTC_GET_TIME_RETRIES   5
+
+
+struct tps65910_rtc {
+       struct tps65910 *tps65910;
+       struct rtc_device *rtc;
+       unsigned int alarm_enabled:1;
+};
+
+/*
+ * Read current time and date in RTC
+ */
+static int tps65910_rtc_readtime(struct device *dev, struct rtc_time *tm)
+{
+       struct tps65910_rtc *tps65910_rtc = dev_get_drvdata(dev);
+       struct tps65910 *tps65910 = tps65910_rtc->tps65910;
+       int ret;
+       int count = 0;
+       unsigned char rtc_data[ALL_TIME_REGS + 1];
+       u8 rtc_ctl;
+
+       /*Dummy read*/  
+       ret = tps65910_reg_read(tps65910, TPS65910_RTC_CTRL);
+       
+       /* Has the RTC been programmed? */
+       ret = tps65910_reg_read(tps65910, TPS65910_RTC_CTRL);
+       if (ret < 0) {
+               dev_err(dev, "Failed to read RTC control: %d\n", ret);
+               return ret;
+       }
+
+       rtc_ctl = ret & (~BIT_RTC_CTRL_REG_RTC_V_OPT_M);
+
+       ret = tps65910_reg_write(tps65910, TPS65910_RTC_CTRL, rtc_ctl);
+       if (ret < 0) {
+               dev_err(dev, "Failed to write RTC control: %d\n", ret);
+               return ret;
+       }
+
+       
+       /* Read twice to make sure we don't read a corrupt, partially
+        * incremented, value.
+        */
+       do {
+               ret = tps65910_bulk_read(tps65910, TPS65910_SECONDS,
+                                      ALL_TIME_REGS, rtc_data);
+               if (ret != 0)
+                       continue;
+
+               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;       
+               tm->tm_wday = bcd2bin(rtc_data[6]);
+
+               dev_dbg(dev, "RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n",
+                       1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, tm->tm_wday,
+                       tm->tm_hour, tm->tm_min, tm->tm_sec);
+               
+               return ret;
+
+       } while (++count < RTC_GET_TIME_RETRIES);
+       dev_err(dev, "Timed out reading current time\n");
+
+       return -EIO;
+
+}
+
+/*
+ * Set current time and date in RTC
+ */
+static int tps65910_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct tps65910_rtc *tps65910_rtc = dev_get_drvdata(dev);
+       struct tps65910 *tps65910 = tps65910_rtc->tps65910;
+       int ret;
+       u8 rtc_ctl;     
+       unsigned char rtc_data[ALL_TIME_REGS + 1];
+       
+       rtc_data[0] = bin2bcd(tm->tm_sec);
+       rtc_data[1] = bin2bcd(tm->tm_min);
+       rtc_data[2] = bin2bcd(tm->tm_hour);
+       rtc_data[3] = bin2bcd(tm->tm_mday);
+       rtc_data[4] = bin2bcd(tm->tm_mon + 1);
+       rtc_data[5] = bin2bcd(tm->tm_year - 100);
+       rtc_data[6] = bin2bcd(tm->tm_wday);
+
+       /*Dummy read*/  
+       ret = tps65910_reg_read(tps65910, TPS65910_RTC_CTRL);
+       
+       /* Stop RTC while updating the TC registers */
+       ret = tps65910_reg_read(tps65910, TPS65910_RTC_CTRL);
+       if (ret < 0) {
+               dev_err(dev, "Failed to read RTC control: %d\n", ret);
+               return ret;
+       }
+       
+       rtc_ctl = ret & (~BIT_RTC_CTRL_REG_STOP_RTC_M);
+
+       ret = tps65910_reg_write(tps65910, TPS65910_RTC_CTRL, rtc_ctl);
+       if (ret < 0) {
+               dev_err(dev, "Failed to write RTC control: %d\n", ret);
+               return ret;
+       }
+       
+       /* update all the time registers in one shot */
+       ret = tps65910_bulk_write(tps65910, TPS65910_SECONDS,
+                                      ALL_TIME_REGS, rtc_data);
+       if (ret < 0) {
+               dev_err(dev, "Failed to read RTC times: %d\n", ret);
+               return ret;
+       }
+       
+       /*Dummy read*/  
+       ret = tps65910_reg_read(tps65910, TPS65910_RTC_CTRL);
+       
+       /* Start RTC again */
+       ret = tps65910_reg_read(tps65910, TPS65910_RTC_CTRL);
+       if (ret < 0) {
+               dev_err(dev, "Failed to read RTC control: %d\n", ret);
+               return ret;
+       }
+       
+       rtc_ctl = ret | BIT_RTC_CTRL_REG_STOP_RTC_M;
+
+       ret = tps65910_reg_write(tps65910, TPS65910_RTC_CTRL, rtc_ctl);
+       if (ret < 0) {
+               dev_err(dev, "Failed to write RTC control: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+/*
+ * Read alarm time and date in RTC
+ */
+static int tps65910_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct tps65910_rtc *tps65910_rtc = dev_get_drvdata(dev);
+       int ret;
+       unsigned char alrm_data[ALL_ALM_REGS + 1];
+
+       ret = tps65910_bulk_read(tps65910_rtc->tps65910, TPS65910_ALARM_SECONDS,
+                              ALL_ALM_REGS, alrm_data);
+       if (ret != 0) {
+               dev_err(dev, "Failed to read alarm time: %d\n", ret);
+               return ret;
+       }
+
+       /* some of these fields may be wildcard/"match all" */
+       alrm->time.tm_sec = bcd2bin(alrm_data[0]);
+       alrm->time.tm_min = bcd2bin(alrm_data[1]);
+       alrm->time.tm_hour = bcd2bin(alrm_data[2]);
+       alrm->time.tm_mday = bcd2bin(alrm_data[3]);
+       alrm->time.tm_mon = bcd2bin(alrm_data[4]) - 1;
+       alrm->time.tm_year = bcd2bin(alrm_data[5]) + 100;
+
+       ret = tps65910_reg_read(tps65910_rtc->tps65910, TPS65910_RTC_INTERRUPTS);
+       if (ret < 0) {
+               dev_err(dev, "Failed to read RTC control: %d\n", ret);
+               return ret;
+       }
+
+       if (ret & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M)
+               alrm->enabled = 1;
+       else
+               alrm->enabled = 0;
+
+       return 0;
+}
+
+static int tps65910_rtc_stop_alarm(struct tps65910_rtc *tps65910_rtc)
+{
+       tps65910_rtc->alarm_enabled = 0;
+
+       return tps65910_clear_bits(tps65910_rtc->tps65910, TPS65910_RTC_INTERRUPTS,
+                              BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+
+}
+
+static int tps65910_rtc_start_alarm(struct tps65910_rtc *tps65910_rtc)
+{
+       tps65910_rtc->alarm_enabled = 1;
+
+       return tps65910_set_bits(tps65910_rtc->tps65910, TPS65910_RTC_INTERRUPTS,
+                              BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+
+}
+
+static int tps65910_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct tps65910_rtc *tps65910_rtc = dev_get_drvdata(dev);
+       int ret;
+       unsigned char alrm_data[ALL_TIME_REGS + 1];
+
+       ret = tps65910_rtc_stop_alarm(tps65910_rtc);
+       if (ret < 0) {
+               dev_err(dev, "Failed to stop alarm: %d\n", ret);
+               return ret;
+       }
+
+       alrm_data[0] = bin2bcd(alrm->time.tm_sec);
+       alrm_data[1] = bin2bcd(alrm->time.tm_min);
+       alrm_data[2] = bin2bcd(alrm->time.tm_hour);
+       alrm_data[3] = bin2bcd(alrm->time.tm_mday);
+       alrm_data[4] = bin2bcd(alrm->time.tm_mon + 1);
+       alrm_data[5] = bin2bcd(alrm->time.tm_year - 100);
+
+       ret = tps65910_bulk_write(tps65910_rtc->tps65910, TPS65910_ALARM_SECONDS,
+                              ALL_ALM_REGS, alrm_data);
+       if (ret != 0) {
+               dev_err(dev, "Failed to read alarm time: %d\n", ret);
+               return ret;
+       }
+
+       if (alrm->enabled) {
+               ret = tps65910_rtc_start_alarm(tps65910_rtc);
+               if (ret < 0) {
+                       dev_err(dev, "Failed to start alarm: %d\n", ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int tps65910_rtc_alarm_irq_enable(struct device *dev,
+                                      unsigned int enabled)
+{
+       struct tps65910_rtc *tps65910_rtc = dev_get_drvdata(dev);
+
+       if (enabled)
+               return tps65910_rtc_start_alarm(tps65910_rtc);
+       else
+               return tps65910_rtc_stop_alarm(tps65910_rtc);
+}
+
+static int tps65910_rtc_update_irq_enable(struct device *dev,
+                                      unsigned int enabled)
+{
+       struct tps65910_rtc *tps65910_rtc = dev_get_drvdata(dev);
+
+       if (enabled)
+               return tps65910_set_bits(tps65910_rtc->tps65910, TPS65910_RTC_INTERRUPTS,
+                              BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
+       else
+               return tps65910_clear_bits(tps65910_rtc->tps65910, TPS65910_RTC_INTERRUPTS,
+                              BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
+}
+
+/*
+ * 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 tps65910_rtc *tps65910_rtc = dev_get_drvdata(dev);
+       int ret;        
+       u8 rtc_ctl;     
+       
+       if (freq < 0 || freq > 3)
+               return -EINVAL;
+
+       ret = tps65910_reg_read(tps65910_rtc->tps65910, TPS65910_RTC_INTERRUPTS);
+       if (ret < 0) {
+               dev_err(dev, "Failed to read RTC interrupt: %d\n", ret);
+               return ret;
+       }
+       
+       rtc_ctl = ret | freq;
+       
+       ret = tps65910_reg_write(tps65910_rtc->tps65910, TPS65910_RTC_INTERRUPTS, rtc_ctl);
+       if (ret < 0) {
+               dev_err(dev, "Failed to write RTC control: %d\n", ret);
+               return ret;
+       }
+       
+       return ret;
+}
+
+
+
+static irqreturn_t tps65910_alm_irq(int irq, void *data)
+{
+       struct tps65910_rtc *tps65910_rtc = data;
+
+       rtc_update_irq(tps65910_rtc->rtc, 1, RTC_IRQF | RTC_AF);
+       
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t tps65910_per_irq(int irq, void *data)
+{
+       struct tps65910_rtc *tps65910_rtc = data;
+
+       rtc_update_irq(tps65910_rtc->rtc, 1, RTC_IRQF | RTC_UF);
+
+       //printk("%s:irq=%d\n",__func__,irq);
+       return IRQ_HANDLED;
+}
+
+static const struct rtc_class_ops tps65910_rtc_ops = {
+       .read_time = tps65910_rtc_readtime,
+       //.set_mmss = tps65910_rtc_set_mmss,
+       .set_time = tps65910_rtc_set_time,
+       .read_alarm = tps65910_rtc_readalarm,
+       .set_alarm = tps65910_rtc_setalarm,
+       .alarm_irq_enable = tps65910_rtc_alarm_irq_enable,
+       //.update_irq_enable = tps65910_rtc_update_irq_enable,
+       //.irq_set_freq = tps65910_rtc_irq_set_freq,
+};
+
+#ifdef CONFIG_PM
+/* Turn off the alarm if it should not be a wake source. */
+static int tps65910_rtc_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct tps65910_rtc *tps65910_rtc = dev_get_drvdata(&pdev->dev);
+       int ret;
+       
+       if (tps65910_rtc->alarm_enabled && device_may_wakeup(&pdev->dev))
+               ret = tps65910_rtc_start_alarm(tps65910_rtc);
+       else
+               ret = tps65910_rtc_stop_alarm(tps65910_rtc);
+
+       if (ret != 0)
+               dev_err(&pdev->dev, "Failed to update RTC alarm: %d\n", ret);
+
+       return 0;
+}
+
+/* Enable the alarm if it should be enabled (in case it was disabled to
+ * prevent use as a wake source).
+ */
+static int tps65910_rtc_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct tps65910_rtc *tps65910_rtc = dev_get_drvdata(&pdev->dev);
+       int ret;
+
+       if (tps65910_rtc->alarm_enabled) {
+               ret = tps65910_rtc_start_alarm(tps65910_rtc);
+               if (ret != 0)
+                       dev_err(&pdev->dev,
+                               "Failed to restart RTC alarm: %d\n", ret);
+       }
+
+       return 0;
+}
+
+/* Unconditionally disable the alarm */
+static int tps65910_rtc_freeze(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct tps65910_rtc *tps65910_rtc = dev_get_drvdata(&pdev->dev);
+       int ret;
+       
+       ret = tps65910_rtc_stop_alarm(tps65910_rtc);
+       if (ret != 0)
+               dev_err(&pdev->dev, "Failed to stop RTC alarm: %d\n", ret);
+
+       return 0;
+}
+#else
+#define tps65910_rtc_suspend NULL
+#define tps65910_rtc_resume NULL
+#define tps65910_rtc_freeze NULL
+#endif
+
+struct platform_device *g_pdev;
+static int tps65910_rtc_probe(struct platform_device *pdev)
+{
+       struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent);
+       struct tps65910_rtc *tps65910_rtc;
+       int per_irq;
+       int alm_irq;
+       int ret = 0;
+       u8 rtc_ctl;
+       
+       struct rtc_time tm;
+       struct rtc_time tm_def = {      //      2012.1.1 12:00:00 Saturday
+                       .tm_wday = 6,
+                       .tm_year = 111,
+                       .tm_mon = 0,
+                       .tm_mday = 1,
+                       .tm_hour = 12,
+                       .tm_min = 0,
+                       .tm_sec = 0,
+               };
+       
+       tps65910_rtc = kzalloc(sizeof(*tps65910_rtc), GFP_KERNEL);
+       if (tps65910_rtc == NULL)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, tps65910_rtc);
+       tps65910_rtc->tps65910 = tps65910;
+       per_irq = tps65910->irq_base + TPS65910_IRQ_RTC_PERIOD;
+       alm_irq = tps65910->irq_base + TPS65910_IRQ_RTC_ALARM;
+       
+       /* Take rtc out of reset */
+       ret = tps65910_reg_read(tps65910, TPS65910_DEVCTRL);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to read TPS65910_DEVCTRL: %d\n", ret);
+               return ret;
+       }
+
+       if(ret & BIT_RTC_PWDN)
+       {
+               rtc_ctl = ret & (~BIT_RTC_PWDN);
+
+               ret = tps65910_reg_write(tps65910, TPS65910_DEVCTRL, rtc_ctl);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "Failed to write RTC control: %d\n", ret);
+                       return ret;
+               }
+       }
+       
+       /*start rtc default*/
+       ret = tps65910_reg_read(tps65910, TPS65910_RTC_CTRL);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to read RTC control: %d\n", ret);
+               return ret;
+       }
+
+       if(!(ret & BIT_RTC_CTRL_REG_STOP_RTC_M))
+       {
+               rtc_ctl = ret | BIT_RTC_CTRL_REG_STOP_RTC_M;
+
+               ret = tps65910_reg_write(tps65910, TPS65910_RTC_CTRL, rtc_ctl);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "Failed to write RTC control: %d\n", ret);
+                       return ret;
+               }
+       }
+       
+       ret = tps65910_reg_read(tps65910, TPS65910_RTC_STATUS);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to read RTC status: %d\n", ret);
+               return ret;
+       }
+               
+       /*set init time*/
+       ret = tps65910_rtc_readtime(&pdev->dev, &tm);
+       if (ret)
+       {
+               dev_err(&pdev->dev, "Failed to read RTC time\n");
+               return ret;
+       }
+       
+       ret = rtc_valid_tm(&tm);
+       if (ret) {
+               dev_err(&pdev->dev,"invalid date/time and init time\n");
+               tps65910_rtc_set_time(&pdev->dev, &tm_def); // 2011-01-01 12:00:00
+               dev_info(&pdev->dev, "set RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n",
+                               1900 + tm_def.tm_year, tm_def.tm_mon + 1, tm_def.tm_mday, tm_def.tm_wday,
+                               tm_def.tm_hour, tm_def.tm_min, tm_def.tm_sec);
+       }
+
+       device_init_wakeup(&pdev->dev, 1);
+
+       tps65910_rtc->rtc = rtc_device_register("tps65910", &pdev->dev,
+                                             &tps65910_rtc_ops, THIS_MODULE);
+       if (IS_ERR(tps65910_rtc->rtc)) {
+               ret = PTR_ERR(tps65910_rtc->rtc);
+               goto err;
+       }
+
+       /*request rtc and alarm irq of tps65910*/
+       ret = request_threaded_irq(per_irq, NULL, tps65910_per_irq,
+                                  IRQF_TRIGGER_RISING, "RTC period",
+                                  tps65910_rtc);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "Failed to request periodic IRQ %d: %d\n",
+                       per_irq, ret);
+       }
+
+       ret = request_threaded_irq(alm_irq, NULL, tps65910_alm_irq,
+                                  IRQF_TRIGGER_RISING, "RTC alarm",
+                                  tps65910_rtc);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n",
+                       alm_irq, ret);
+       }
+
+       //for rtc irq test
+       //tps65910_set_bits(tps65910_rtc->tps65910, TPS65910_RTC_INTERRUPTS,
+       //                             BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
+
+       g_pdev = pdev;
+       
+       printk("%s:ok\n",__func__);
+       
+       return 0;
+
+err:
+       kfree(tps65910_rtc);
+       return ret;
+}
+
+static int __devexit tps65910_rtc_remove(struct platform_device *pdev)
+{
+       struct tps65910_rtc *tps65910_rtc = platform_get_drvdata(pdev);
+       int per_irq = tps65910_rtc->tps65910->irq_base + TPS65910_IRQ_RTC_PERIOD;
+       int alm_irq = tps65910_rtc->tps65910->irq_base + TPS65910_IRQ_RTC_ALARM;
+
+       free_irq(alm_irq, tps65910_rtc);
+       free_irq(per_irq, tps65910_rtc);
+       rtc_device_unregister(tps65910_rtc->rtc);
+       kfree(tps65910_rtc);
+
+       return 0;
+}
+
+static const struct dev_pm_ops tps65910_rtc_pm_ops = {
+       .suspend = tps65910_rtc_suspend,
+       .resume = tps65910_rtc_resume,
+
+       .freeze = tps65910_rtc_freeze,
+       .thaw = tps65910_rtc_resume,
+       .restore = tps65910_rtc_resume,
+
+       .poweroff = tps65910_rtc_suspend,
+};
+
+static struct platform_driver tps65910_rtc_driver = {
+       .probe = tps65910_rtc_probe,
+       .remove = __devexit_p(tps65910_rtc_remove),
+       .driver = {
+               .name = "tps65910-rtc",
+               .pm = &tps65910_rtc_pm_ops,
+       },
+};
+
+static ssize_t rtc_tps65910_test_write(struct file *file, 
+                       const char __user *buf, size_t count, loff_t *offset)
+{
+       char nr_buf[8];
+       int nr = 0, ret;
+       struct platform_device *pdev;   
+       struct rtc_time tm;
+       
+       if(count > 3)
+               return -EFAULT;
+       ret = copy_from_user(nr_buf, buf, count);
+       if(ret < 0)
+               return -EFAULT;
+
+       sscanf(nr_buf, "%d", &nr);
+       if(nr >= 2 || nr < 0)
+       {
+               printk("%s:data is error\n",__func__);
+               return -EFAULT;
+       }
+
+       if(!g_pdev)
+               return -EFAULT;
+       else
+               pdev = g_pdev;
+
+       if(nr == 0)
+       {       
+               tm.tm_wday = 6;
+               tm.tm_year = 111;
+               tm.tm_mon = 0;
+               tm.tm_mday = 1;
+               tm.tm_hour = 12;
+               tm.tm_min = 0;
+               tm.tm_sec = 0;
+       
+               ret = tps65910_rtc_set_time(&pdev->dev, &tm); // 2011-01-01 12:00:00
+               if (ret)
+               {
+                       dev_err(&pdev->dev, "Failed to set RTC time\n");
+                       return -EFAULT;
+               }
+
+       }
+       
+       /*set init time*/
+       ret = tps65910_rtc_readtime(&pdev->dev, &tm);
+       if (ret)
+               dev_err(&pdev->dev, "Failed to read RTC time\n");
+       else
+               dev_info(&pdev->dev, "RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n",
+                       1900 + tm.tm_year, tm.tm_mon + 1, tm.tm_mday, tm.tm_wday,
+                       tm.tm_hour, tm.tm_min, tm.tm_sec);
+               
+       if(!ret)
+       printk("%s:ok\n",__func__);
+       else
+       printk("%s:error\n",__func__);
+       
+       return count;
+}
+
+static const struct file_operations rtc_tps65910_test_fops = {
+       .write = rtc_tps65910_test_write,
+};
+
+static struct miscdevice rtc_tps65910_test_misc = {
+       .minor = MISC_DYNAMIC_MINOR,
+       .name = "rtc_tps65910_test",
+       .fops = &rtc_tps65910_test_fops,
+};
+
+
+static int __init tps65910_rtc_init(void)
+{
+       misc_register(&rtc_tps65910_test_misc);
+       return platform_driver_register(&tps65910_rtc_driver);
+}
+subsys_initcall_sync(tps65910_rtc_init);
+
+static void __exit tps65910_rtc_exit(void)
+{      
+        misc_deregister(&rtc_tps65910_test_misc);
+       platform_driver_unregister(&tps65910_rtc_driver);
+}
+module_exit(tps65910_rtc_exit);
+
+MODULE_DESCRIPTION("RTC driver for the tps65910 series PMICs");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:tps65910-rtc");
old mode 100644 (file)
new mode 100755 (executable)
index 8bb85b9..c093c47
@@ -17,6 +17,8 @@
 #ifndef __LINUX_MFD_TPS65910_H
 #define __LINUX_MFD_TPS65910_H
 
 #ifndef __LINUX_MFD_TPS65910_H
 #define __LINUX_MFD_TPS65910_H
 
+#include <linux/gpio.h>
+
 /* TPS chip id list */
 #define TPS65910                       0
 #define TPS65911                       1
 /* TPS chip id list */
 #define TPS65910                       0
 #define TPS65911                       1
 #define REGULATOR_LDO                  0
 #define REGULATOR_DCDC                 1
 
 #define REGULATOR_LDO                  0
 #define REGULATOR_DCDC                 1
 
+/* I2C Slave Address 7-bit */
+#define TPS65910_I2C_ID0        0x2D /* general-purpose */
+#define TPS65910_I2C_ID1        0x12 /* Smart Reflex */
+
 /*
  * List of registers for component TPS65910
  *
 /*
  * List of registers for component TPS65910
  *
 
 
 /*Registers VDD1, VDD2 voltage values definitions */
 
 
 /*Registers VDD1, VDD2 voltage values definitions */
-#define VDD1_2_NUM_VOLTS                               73
+#define VDD1_2_NUM_VOLT_FINE                           73
+#define VDD1_2_NUM_VOLT_COARSE                         3
 #define VDD1_2_MIN_VOLT                                        6000
 #define VDD1_2_OFFSET                                  125
 
 #define VDD1_2_MIN_VOLT                                        6000
 #define VDD1_2_OFFSET                                  125
 
 #define LDO1_SEL_MASK                                  0xFC
 #define LDO3_SEL_MASK                                  0x7C
 #define LDO_MIN_VOLT                                   1000
 #define LDO1_SEL_MASK                                  0xFC
 #define LDO3_SEL_MASK                                  0x7C
 #define LDO_MIN_VOLT                                   1000
-#define LDO_MAX_VOLT                                   3300;
+#define LDO_MAX_VOLT                                   3300
 
 
 /*Register VDIG1  (0x80) register.RegisterDescription */
 
 
 /*Register VDIG1  (0x80) register.RegisterDescription */
 #define DCDCCTRL_DCDCCKSYNC_SHIFT                      0
 
 
 #define DCDCCTRL_DCDCCKSYNC_SHIFT                      0
 
 
-/*Register DEVCTRL  (0x80) register.RegisterDescription */
+/*Register DEVCTRL  (0x3F) register.RegisterDescription */
 #define DEVCTRL_RTC_PWDN_MASK                          0x40
 #define DEVCTRL_RTC_PWDN_SHIFT                         6
 #define DEVCTRL_CK32K_CTRL_MASK                                0x20
 #define DEVCTRL_RTC_PWDN_MASK                          0x40
 #define DEVCTRL_RTC_PWDN_SHIFT                         6
 #define DEVCTRL_CK32K_CTRL_MASK                                0x20
 #define DEVCTRL_DEV_OFF_SHIFT                          0
 
 
 #define DEVCTRL_DEV_OFF_SHIFT                          0
 
 
-/*Register DEVCTRL2  (0x80) register.RegisterDescription */
+/*Register DEVCTRL2  (0x40) register.RegisterDescription */
 #define DEVCTRL2_TSLOT_LENGTH_MASK                     0x30
 #define DEVCTRL2_TSLOT_LENGTH_SHIFT                    4
 #define DEVCTRL2_SLEEPSIG_POL_MASK                     0x08
 #define DEVCTRL2_TSLOT_LENGTH_MASK                     0x30
 #define DEVCTRL2_TSLOT_LENGTH_SHIFT                    4
 #define DEVCTRL2_SLEEPSIG_POL_MASK                     0x08
 
 
 /*Register GPIO  (0x80) register.RegisterDescription */
 
 
 /*Register GPIO  (0x80) register.RegisterDescription */
+#define GPIO_SLEEP_MASK                         0x80
+#define GPIO_SLEEP_SHIFT                        7
 #define GPIO_DEB_MASK                           0x10
 #define GPIO_DEB_SHIFT                          4
 #define GPIO_PUEN_MASK                          0x08
 #define GPIO_DEB_MASK                           0x10
 #define GPIO_DEB_SHIFT                          4
 #define GPIO_PUEN_MASK                          0x08
 #define TPS65910_GPIO_STS                              BIT(1)
 #define TPS65910_GPIO_SET                              BIT(0)
 
 #define TPS65910_GPIO_STS                              BIT(1)
 #define TPS65910_GPIO_SET                              BIT(0)
 
-/**
- * struct tps65910_board
- * Board platform data may be used to initialize regulators.
- */
+/* Max number of TPS65910/11 GPIOs */
+#define TPS65910_NUM_GPIO                              6
+#define TPS65911_NUM_GPIO                              9
+#define TPS6591X_MAX_NUM_GPIO                          9
+
+/* Regulator Index Definitions */
+#define TPS65910_REG_VRTC                              0
+#define TPS65910_REG_VIO                               1
+#define TPS65910_REG_VDD1                              2
+#define TPS65910_REG_VDD2                              3
+#define TPS65910_REG_VDD3                              4
+#define TPS65910_REG_VDIG1                             5
+#define TPS65910_REG_VDIG2                             6
+#define TPS65910_REG_VPLL                              7
+#define TPS65910_REG_VDAC                              8
+#define TPS65910_REG_VAUX1                             9
+#define TPS65910_REG_VAUX2                             10
+#define TPS65910_REG_VAUX33                            11
+#define TPS65910_REG_VMMC                              12
+
+#define TPS65911_REG_VDDCTRL                           4
+#define TPS65911_REG_LDO1                              5
+#define TPS65911_REG_LDO2                              6
+#define TPS65911_REG_LDO3                              7
+#define TPS65911_REG_LDO4                              8
+#define TPS65911_REG_LDO5                              9
+#define TPS65911_REG_LDO6                              10
+#define TPS65911_REG_LDO7                              11
+#define TPS65911_REG_LDO8                              12
+
+/* Max number of TPS65910/11 regulators */
+#define TPS65910_NUM_REGS                              13
+
+/* External sleep controls through EN1/EN2/EN3/SLEEP inputs */
+#define TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1           0x1
+#define TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2           0x2
+#define TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3           0x4
+#define TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP         0x8
+
+
+
+
+
 
 
-struct tps65910_board {
-       int gpio_base;
-       int irq;
-       int irq_base;
-       int vmbch_threshold;
-       int vmbch2_threshold;
-       struct regulator_init_data *tps65910_pmic_init_data;
-};
 
 /**
  * struct tps65910 - tps65910 sub-driver chip access routines
 
 /**
  * struct tps65910 - tps65910 sub-driver chip access routines
@@ -760,15 +800,16 @@ struct tps65910_board {
 struct tps65910 {
        struct device *dev;
        struct i2c_client *i2c_client;
 struct tps65910 {
        struct device *dev;
        struct i2c_client *i2c_client;
+       struct regmap *regmap;
        struct mutex io_mutex;
        unsigned int id;
        int (*read)(struct tps65910 *tps65910, u8 reg, int size, void *dest);
        int (*write)(struct tps65910 *tps65910, u8 reg, int size, void *src);
 
        /* Client devices */
        struct mutex io_mutex;
        unsigned int id;
        int (*read)(struct tps65910 *tps65910, u8 reg, int size, void *dest);
        int (*write)(struct tps65910 *tps65910, u8 reg, int size, void *src);
 
        /* Client devices */
-       struct tps65910_pmic *pmic;
-       struct tps65910_rtc *rtc;
-       struct tps65910_power *power;
+       //struct tps65910_pmic *pmic;
+       //struct tps65910_rtc *rtc;
+       //struct tps65910_power *power;
 
        /* GPIO Handling */
        struct gpio_chip gpio;
 
        /* GPIO Handling */
        struct gpio_chip gpio;
@@ -786,11 +827,45 @@ struct tps65910_platform_data {
        int irq_base;
 };
 
        int irq_base;
 };
 
+
+/**
+ * struct tps65910_board
+ * Board platform data may be used to initialize regulators.
+ */
+
+struct tps65910_board {
+       int gpio_base;
+       int irq;
+       int irq_base;
+       int vmbch_threshold;
+       int vmbch2_threshold;
+       bool en_gpio_sleep[TPS6591X_MAX_NUM_GPIO];
+       unsigned long regulator_ext_sleep_control[TPS65910_NUM_REGS];
+       struct regulator_init_data *tps65910_pmic_init_data[TPS65910_NUM_REGS];
+
+       /** Called before subdevices are set up */
+       int (*pre_init)(struct tps65910 *tps65910);
+       /** Called after subdevices are set up */
+       int (*post_init)(struct tps65910 *tps65910);
+       /** Called before subdevices are power down */
+       int (*last_deinit)(struct tps65910 *tps65910);
+};
+
+
 int tps65910_set_bits(struct tps65910 *tps65910, u8 reg, u8 mask);
 int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask);
 void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base);
 int tps65910_irq_init(struct tps65910 *tps65910, int irq,
                struct tps65910_platform_data *pdata);
 int tps65910_set_bits(struct tps65910 *tps65910, u8 reg, u8 mask);
 int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask);
 void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base);
 int tps65910_irq_init(struct tps65910 *tps65910, int irq,
                struct tps65910_platform_data *pdata);
+int tps65910_irq_exit(struct tps65910 *tps65910);
+int tps65910_reg_read(struct tps65910 *tps65910, u8 reg);
+int tps65910_reg_write(struct tps65910 *tps65910, u8 reg, u8 val);
+int tps65910_bulk_read(struct tps65910 *tps65910, u8 reg,
+                    int count, u8 *buf);
+int tps65910_bulk_write(struct tps65910 *tps65910, u8 reg,
+                    int count, u8 *buf);
+int tps65910_device_shutdown(void);
+
 
 static inline int tps65910_chip_id(struct tps65910 *tps65910)
 {
 
 static inline int tps65910_chip_id(struct tps65910 *tps65910)
 {