From 426997197d3a971fee38e27f36eb6c8aab2b52a1 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E5=BC=A0=E6=99=B4?= Date: Thu, 9 Aug 2012 18:07:51 +0800 Subject: [PATCH] rk2928:support pmic tps65910 --- arch/arm/configs/rk2928_sdk_defconfig | 7 +- arch/arm/mach-rk2928/board-rk2928-sdk.c | 18 + .../arm/mach-rk2928/board-rk30-sdk-tps65910.c | 633 ++++++++++++++++ drivers/gpio/Kconfig | 6 + drivers/gpio/Makefile | 3 +- drivers/gpio/gpio-tps65910.c | 118 +++ drivers/gpio/tps65910-gpio.c | 0 drivers/mfd/Kconfig | 50 +- drivers/mfd/Makefile | 5 + drivers/mfd/tps65910-irq.c | 30 +- drivers/mfd/tps65910.c | 168 ++++- drivers/mfd/tps65911-comparator.c | 0 drivers/regulator/Kconfig | 17 +- drivers/regulator/Makefile | 1 + drivers/regulator/tps65910-regulator.c | 588 +++++++++++---- drivers/rtc/Kconfig | 5 + drivers/rtc/Makefile | 1 + drivers/rtc/rtc-tps65910.c | 695 ++++++++++++++++++ include/linux/mfd/tps65910.h | 113 ++- 19 files changed, 2284 insertions(+), 174 deletions(-) create mode 100755 arch/arm/mach-rk2928/board-rk30-sdk-tps65910.c create mode 100755 drivers/gpio/gpio-tps65910.c mode change 100644 => 100755 drivers/gpio/tps65910-gpio.c mode change 100644 => 100755 drivers/mfd/tps65910-irq.c mode change 100644 => 100755 drivers/mfd/tps65910.c mode change 100644 => 100755 drivers/mfd/tps65911-comparator.c mode change 100644 => 100755 drivers/regulator/tps65910-regulator.c create mode 100755 drivers/rtc/rtc-tps65910.c mode change 100644 => 100755 include/linux/mfd/tps65910.h diff --git a/arch/arm/configs/rk2928_sdk_defconfig b/arch/arm/configs/rk2928_sdk_defconfig index 32ceab278ca3..32f9084f6244 100755 --- a/arch/arm/configs/rk2928_sdk_defconfig +++ b/arch/arm/configs/rk2928_sdk_defconfig @@ -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 diff --git a/arch/arm/mach-rk2928/board-rk2928-sdk.c b/arch/arm/mach-rk2928/board-rk2928-sdk.c index 06ac44d87620..604a79d7c685 100755 --- a/arch/arm/mach-rk2928/board-rk2928-sdk.c +++ b/arch/arm/mach-rk2928/board-rk2928-sdk.c @@ -44,6 +44,8 @@ #include #include #include +#include +#include #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 index 000000000000..7ec12c302a3a --- /dev/null +++ b/arch/arm/mach-rk2928/board-rk30-sdk-tps65910.c @@ -0,0 +1,633 @@ +#include +#include +#include +#include +#include + +#include +#include + +#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 + diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 3b8f6043bf0c..9876d32c8173 100755 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -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 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 46508ae87340..9a470d2235f7 100755 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -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 index 000000000000..7eef648a3351 --- /dev/null +++ b/drivers/gpio/gpio-tps65910.c @@ -0,0 +1,118 @@ +/* + * TI TPS6591x GPIO driver + * + * Copyright 2010 Texas Instruments Inc. + * + * Author: Graeme Gregory + * 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 +#include +#include +#include +#include +#include + +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); +} diff --git a/drivers/gpio/tps65910-gpio.c b/drivers/gpio/tps65910-gpio.c old mode 100644 new mode 100755 diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 35ff8fe22183..43c5d038be13 100755 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -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" diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index bd569e97306c..59d550bfe573 100755 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -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 diff --git a/drivers/mfd/tps65910-irq.c b/drivers/mfd/tps65910-irq.c old mode 100644 new mode 100755 index a56be931551c..bcec38371c94 --- a/drivers/mfd/tps65910-irq.c +++ b/drivers/mfd/tps65910-irq.c @@ -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, ®); irq_sts = reg; tps65910->read(tps65910, TPS65910_INT_STS2, 1, ®); @@ -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, ®); + tps65910->write(tps65910, TPS65910_INT_STS, 1, ®); + tps65910->read(tps65910, TPS65910_INT_STS2, 1, ®); + tps65910->write(tps65910, TPS65910_INT_STS2, 1, ®); + tps65910->read(tps65910, TPS65910_INT_STS3, 1, ®); + tps65910->write(tps65910, TPS65910_INT_STS3, 1, ®); + + /* 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; } diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c old mode 100644 new mode 100755 index 2229e66d80db..6b16534548ad --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -22,6 +22,8 @@ #include #include +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 = ® + 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= 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;iread(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) { diff --git a/drivers/mfd/tps65911-comparator.c b/drivers/mfd/tps65911-comparator.c old mode 100644 new mode 100755 diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 90c87c9797c5..b425fd61c4b2 100755 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -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 diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 68db7129f878..d4f86bae7bf9 100755 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -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 diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c old mode 100644 new mode 100755 index 425aab38981e..22e06e2cb98e --- a/drivers/regulator/tps65910-regulator.c +++ b/drivers/regulator/tps65910-regulator.c @@ -25,45 +25,51 @@ #include #include -#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 "); -MODULE_DESCRIPTION("TPS6507x voltage regulator driver"); +MODULE_DESCRIPTION("TPS65910/TPS65911 voltage regulator driver"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:tps65910-pmic"); diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index a567a8e131e7..bfa8a408fb33 100755 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -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 diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 3f5e0685673b..6d4c945e6b42 100755 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -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 index 000000000000..f6a8693cabcf --- /dev/null +++ b/drivers/rtc/rtc-tps65910.c @@ -0,0 +1,695 @@ +/* + * Real Time Clock driver for Wolfson Microelectronics tps65910 + * + * Copyright (C) 2009 Wolfson Microelectronics PLC. + * + * Author: Mark Brown + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* 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"); diff --git a/include/linux/mfd/tps65910.h b/include/linux/mfd/tps65910.h old mode 100644 new mode 100755 index 8bb85b930c07..c093c477477b --- a/include/linux/mfd/tps65910.h +++ b/include/linux/mfd/tps65910.h @@ -17,6 +17,8 @@ #ifndef __LINUX_MFD_TPS65910_H #define __LINUX_MFD_TPS65910_H +#include + /* TPS chip id list */ #define TPS65910 0 #define TPS65911 1 @@ -25,6 +27,10 @@ #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 * @@ -243,7 +249,8 @@ /*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 @@ -269,7 +276,7 @@ #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 */ @@ -361,7 +368,7 @@ #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 @@ -378,7 +385,7 @@ #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 @@ -656,6 +663,8 @@ /*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 @@ -739,19 +748,50 @@ #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) { -- 2.34.1