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_MFD_WM831X_I2C=y
+CONFIG_MFD_TPS65910=y
+CONFIG_MFD_TPS65090=y
 CONFIG_REGULATOR=y
-CONFIG_REGULATOR_WM831X=y
+CONFIG_REGULATOR_TPS65910=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_RTC_DRV_WM831X=y
+CONFIG_TPS65910_RTC=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/mfd/tps65910.h>
+#include <linux/regulator/rk29-pwm-regulator.h>
 #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
+
 /**************************************************************************************************
  * 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
+#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[] = {
+
+#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
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.
 
+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
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_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.
 
+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
@@ -769,17 +800,20 @@ config MFD_PM8XXX_IRQ
          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 GPIO_TPS65910
+       select REGMAP_I2C
        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.
-
-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"
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_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
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;
-
+       
        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));
 }
 
+#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,
+       .irq_set_wake = tps65910_irq_set_wake,
 };
 
 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;
+       u8 reg;
 
        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");
-               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);
@@ -215,6 +236,7 @@ int tps65910_irq_init(struct tps65910 *tps65910, int irq,
 
 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;
 }
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>
 
+struct tps65910 *g_tps65910;
+
 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)
@@ -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;
+       //int i;
 
        /* 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;
+       xfer[1].scl_rate = TPS65910_SPEED;
 
        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;
-
+       
        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;
-
+       //int i;
+       
        if (bytes > TPS65910_MAX_REGISTER)
                return -EINVAL;
-
+       
        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;
+
        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;
@@ -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) {
-               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)
-               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);
@@ -120,7 +221,7 @@ int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
                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);
@@ -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;
-
+       
        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;
-       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)
@@ -167,6 +268,16 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
                              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);
 
@@ -174,6 +285,15 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
        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:
@@ -182,6 +302,36 @@ err:
        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);
@@ -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 */
-subsys_initcall(tps65910_i2c_init);
+subsys_initcall_sync(tps65910_i2c_init);
 
 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.
 
+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
@@ -324,11 +335,7 @@ config REGULATOR_TPS6524X
          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
 
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_TPS65912) += tps65912-regulator.o
 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>
 
-#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 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,
 };
 
-/* 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[] = {
-       5000,
+       1000,1400
 };
 
+
 /* 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;
-       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",
+               .enable_time_us = 2200,
        },
        {
                .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,
+               .max_uV = 1500000,
+               .n_voltages = ARRAY_SIZE(VDD1_VSEL_table),
+               .voltage_table = VDD1_VSEL_table,
+               .enable_time_us = 350,
        },
        {
                .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",
-               .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,
-               .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,
-               .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,
-               .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,
-               .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,
-               .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,
-               .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,
-               .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,
-               .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[] = {
+       {
+               .name = "VRTC",
+               .enable_time_us = 2200,
+       },
        {
                .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,
+               .n_voltages = 73,
+               .enable_time_us = 350,
        },
        {
                .name = "VDD2",
                .min_uV = 600000,
                .max_uV = 4500000,
+               .n_voltages = 73,
+               .enable_time_us = 350,
        },
        {
                .name = "VDDCTRL",
                .min_uV = 600000,
                .max_uV = 1400000,
+               .n_voltages = 65,
+               .enable_time_us = 900,
        },
        {
                .name = "LDO1",
                .min_uV = 1000000,
                .max_uV = 3300000,
+               .n_voltages = 47,
+               .enable_time_us = 420,
        },
        {
                .name = "LDO2",
                .min_uV = 1000000,
                .max_uV = 3300000,
+               .n_voltages = 47,
+               .enable_time_us = 420,
        },
        {
                .name = "LDO3",
                .min_uV = 1000000,
                .max_uV = 3300000,
+               .n_voltages = 24,
+               .enable_time_us = 230,
        },
        {
                .name = "LDO4",
                .min_uV = 1000000,
                .max_uV = 3300000,
+               .n_voltages = 47,
+               .enable_time_us = 230,
        },
        {
                .name = "LDO5",
                .min_uV = 1000000,
                .max_uV = 3300000,
+               .n_voltages = 24,
+               .enable_time_us = 230,
        },
        {
                .name = "LDO6",
                .min_uV = 1000000,
                .max_uV = 3300000,
+               .n_voltages = 24,
+               .enable_time_us = 230,
        },
        {
                .name = "LDO7",
                .min_uV = 1000000,
                .max_uV = 3300000,
+               .n_voltages = 24,
+               .enable_time_us = 230,
        },
        {
                .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 regulator_desc desc[TPS65910_NUM_REGULATOR];
+       struct regulator_desc *desc;
        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;
+       int num_regulators;
        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)
@@ -315,7 +402,7 @@ out:
        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;
 
@@ -329,7 +416,7 @@ static int tps65910_reg_read(struct tps65910_reg *pmic, u8 reg)
        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;
 
@@ -420,7 +507,7 @@ static int tps65910_is_enabled(struct regulator_dev *dev)
        if (reg < 0)
                return reg;
 
-       value = tps65910_reg_read(pmic, reg);
+       value = tps65910_pmic_reg_read(pmic, reg);
        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);
 }
 
+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)
 {
@@ -487,11 +580,11 @@ static unsigned int tps65910_get_mode(struct regulator_dev *dev)
        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 & 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;
@@ -499,36 +592,36 @@ static unsigned int tps65910_get_mode(struct regulator_dev *dev)
                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);
-       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:
-               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;
-               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:
-               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;
-               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:
-               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;
@@ -546,9 +639,7 @@ static int tps65910_get_voltage_dcdc(struct regulator_dev *dev)
                        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*/
@@ -556,14 +647,9 @@ static int tps65910_get_voltage_dcdc(struct regulator_dev *dev)
                        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)
@@ -575,7 +661,7 @@ static int tps65910_get_voltage(struct regulator_dev *dev)
        if (reg < 0)
                return reg;
 
-       value = tps65910_reg_read(pmic, reg);
+       value = tps65910_pmic_reg_read(pmic, reg);
        if (value < 0)
                return value;
 
@@ -596,7 +682,7 @@ static int tps65910_get_voltage(struct regulator_dev *dev)
                return -EINVAL;
        }
 
-       voltage = pmic->info[id]->table[value] * 1000;
+       voltage = pmic->info[id]->voltage_table[value] * 1000;
 
        return voltage;
 }
@@ -614,7 +700,7 @@ static int tps65911_get_voltage(struct regulator_dev *dev)
 
        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:
@@ -646,8 +732,9 @@ static int tps65911_get_voltage(struct regulator_dev *dev)
                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;
        }
@@ -655,8 +742,8 @@ static int tps65911_get_voltage(struct regulator_dev *dev)
        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;
@@ -664,36 +751,37 @@ static int tps65910_set_voltage_dcdc(struct regulator_dev *dev,
 
        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--;
-               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_reg_write(pmic, TPS65910_VDD1_OP, vsel);
+               tps65910_pmic_reg_write(pmic, TPS65910_VDD1_OP, vsel);
                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--;
-               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_reg_write(pmic, TPS65910_VDD2_OP, vsel);
+               tps65910_pmic_reg_write(pmic, TPS65910_VDD2_OP, vsel);
                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;
 }
 
-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);
@@ -719,7 +807,8 @@ static int tps65910_set_voltage(struct regulator_dev *dev, unsigned selector)
        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);
@@ -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 TPS65910_REG_VIO:
                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;
@@ -756,9 +847,9 @@ static int tps65910_list_voltage_dcdc(struct regulator_dev *dev,
        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 +
-                               (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);
@@ -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 (selector >= pmic->info[id]->table_len)
+       if (selector >= pmic->info[id]->n_voltages)
                return -EINVAL;
        else
-               voltage = pmic->info[id]->table[selector] * 1000;
-
+               voltage = pmic->info[id]->voltage_table[selector] * 1000;
+       
        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:
-               return pmic->info[id]->table[selector] * 1000;
+               return pmic->info[id]->voltage_table[selector] * 1000;
        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;
 }
 
+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,
+       .enable_time            = tps65910_enable_time,
        .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,
 };
 
@@ -843,6 +961,7 @@ static struct regulator_ops tps65910_ops_vdd3 = {
        .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,
@@ -853,10 +972,11 @@ static struct regulator_ops tps65910_ops = {
        .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_voltage_sel        = tps65910_set_voltage,
+       .set_voltage_sel        = tps65910_set_voltage_sel,
        .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,
+       .enable_time            = tps65910_enable_time,
        .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,
 };
 
+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);
@@ -885,8 +1139,6 @@ static __devinit int tps65910_probe(struct platform_device *pdev)
        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;
@@ -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;
+               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;
+               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");
+               kfree(pmic);
                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;
-               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;
+                       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;
@@ -935,6 +1224,16 @@ static __devinit int tps65910_probe(struct platform_device *pdev)
                                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;
 
@@ -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);
-                       goto err;
+                       goto err_unregister_regulator;
                }
 
                /* Save regulator for cleanup */
@@ -953,26 +1252,64 @@ static __devinit int tps65910_probe(struct platform_device *pdev)
        }
        return 0;
 
-err:
+err_unregister_regulator:
        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)
 {
-       struct tps65910_reg *tps65910_reg = platform_get_drvdata(pdev);
+       struct tps65910_reg *pmic = platform_get_drvdata(pdev);
        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;
 }
 
+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",
@@ -980,13 +1317,14 @@ static struct platform_driver tps65910_driver = {
        },
        .probe = tps65910_probe,
        .remove = __devexit_p(tps65910_remove),
+       .shutdown = tps65910_shutdown,
 };
 
 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)
 {
@@ -995,6 +1333,6 @@ static void __exit tps65910_cleanup(void)
 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");
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.
+config  TPS65910_RTC
+       tristate "tps65910 rtc for rk"
+       depends on MFD_TPS65910
+       help
+               enable tps65910 rtc for system
 
 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_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
 
+#include <linux/gpio.h>
+
 /* TPS chip id list */
 #define TPS65910                       0
 #define TPS65911                       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
  *
 
 
 /*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 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 */
 #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_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
 
 
 /*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 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
@@ -760,15 +800,16 @@ struct tps65910_board {
 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 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;
@@ -786,11 +827,45 @@ struct tps65910_platform_data {
        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_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)
 {