From d8f52a4b9849fb5387b248b2cb3c10963c113f65 Mon Sep 17 00:00:00 2001 From: lw Date: Thu, 26 Jul 2012 21:45:55 +0800 Subject: [PATCH] phonepad:add PMIC TPS65910 support --- arch/arm/configs/rk30_phonepad_defconfig | 8 +- arch/arm/mach-rk30/board-rk30-phonepad.c | 9 +- arch/arm/mach-rk30/board-rk30-sdk-tps65910.c | 635 +++++++++++++++++ drivers/gpio/Kconfig | 6 + drivers/gpio/Makefile | 3 +- drivers/gpio/gpio-tps65910.c | 118 ++++ drivers/mfd/Kconfig | 50 +- drivers/mfd/Makefile | 5 + drivers/mfd/tps65910-irq.c | 14 +- drivers/mfd/tps65910.c | 77 +- drivers/regulator/Kconfig | 17 +- drivers/regulator/Makefile | 1 + drivers/regulator/tps65910-regulator.c | 554 ++++++++++++--- drivers/rtc/Kconfig | 5 + drivers/rtc/Makefile | 1 + drivers/rtc/rtc-tps65910.c | 706 +++++++++++++++++++ include/linux/mfd/tps65910.h | 247 ++++++- include/linux/mfd/tps65912.h | 327 +++++++++ 18 files changed, 2634 insertions(+), 149 deletions(-) create mode 100755 arch/arm/mach-rk30/board-rk30-sdk-tps65910.c create mode 100644 drivers/gpio/gpio-tps65910.c create mode 100755 drivers/rtc/rtc-tps65910.c create mode 100644 include/linux/mfd/tps65912.h diff --git a/arch/arm/configs/rk30_phonepad_defconfig b/arch/arm/configs/rk30_phonepad_defconfig index bbaf22b953c0..bca7523e8d11 100644 --- a/arch/arm/configs/rk30_phonepad_defconfig +++ b/arch/arm/configs/rk30_phonepad_defconfig @@ -224,7 +224,6 @@ CONFIG_INPUT_KEYRESET=y CONFIG_INPUT_JOYSTICK=y CONFIG_INPUT_TABLET=y CONFIG_INPUT_TOUCHSCREEN=y -CONFIG_TOUCHSCREEN_GT82X_IIC=y CONFIG_INPUT_MISC=y CONFIG_INPUT_KEYCHORD=y CONFIG_INPUT_UINPUT=y @@ -253,7 +252,6 @@ CONFIG_I2C1_CONTROLLER_RK30=y CONFIG_I2C2_CONTROLLER_RK30=y CONFIG_I2C3_CONTROLLER_RK30=y CONFIG_I2C4_CONTROLLER_RK30=y -CONFIG_GPIO_WM831X=y CONFIG_EXPANDED_GPIO_NUM=0 CONFIG_EXPANDED_GPIO_IRQ_NUM=0 CONFIG_SPI_FPGA_GPIO_NUM=0 @@ -261,9 +259,9 @@ 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_REGULATOR=y -CONFIG_REGULATOR_WM831X=y +CONFIG_REGULATOR_TPS65910=y CONFIG_MEDIA_SUPPORT=y CONFIG_VIDEO_DEV=y CONFIG_SOC_CAMERA=y @@ -376,7 +374,7 @@ CONFIG_LEDS_GPIO=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-rk30/board-rk30-phonepad.c b/arch/arm/mach-rk30/board-rk30-phonepad.c index 8e219c973560..f397266f6472 100755 --- a/arch/arm/mach-rk30/board-rk30-phonepad.c +++ b/arch/arm/mach-rk30/board-rk30-phonepad.c @@ -44,11 +44,13 @@ #include #include #include +#include + #if defined(CONFIG_HDMI_RK30) #include "../../../drivers/video/rockchip/hdmi/rk_hdmi.h" #endif -#define TPS65910_HOST_IRQ RK30_PIN6_PA4 + #ifdef CONFIG_TOUCHSCREEN_GT82X_IIC #include #endif @@ -77,7 +79,7 @@ #else #define RK30_FB0_MEM_SIZE 8*SZ_1M #endif -int PMIC_IS_WM831X = 0; +#define PMIC_IS_WM831X 0 #ifdef CONFIG_VIDEO_RK29 /*---------------- Camera Sensor Macro Define Begin ------------------------*/ @@ -1692,6 +1694,7 @@ static struct i2c_board_info __initdata i2c0_info[] = { #include "board-rk30-sdk-wm8326.c" #endif #ifdef CONFIG_MFD_TPS65910 +#define TPS65910_HOST_IRQ RK30_PIN6_PA4 #include "board-rk30-sdk-tps65910.c" #endif @@ -1707,7 +1710,7 @@ static struct i2c_board_info __initdata i2c1_info[] = { #endif #if defined (CONFIG_MFD_TPS65910) { - .type = "tps659102", + .type = "tps65910", .addr = TPS65910_I2C_ID0, .flags = 0, .irq = TPS65910_HOST_IRQ, diff --git a/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c b/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c new file mode 100755 index 000000000000..179ced8a4ab4 --- /dev/null +++ b/arch/arm/mach-rk30/board-rk30-sdk-tps65910.c @@ -0,0 +1,635 @@ +#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 RK30_PIN6_PB1 +extern int platform_device_register(struct platform_device *pdev); + +int tps65910_pre_init(struct tps65910 *tps65910){ + + u8 val = 0; + int i = 0; + int err = -1; + + #ifdef CONFIG_RK30_PWM_REGULATOR + platform_device_register(&pwm_regulator_device[0]); + #endif + + printk("%s,line=%d\n", __func__,__LINE__); + //gpio_request(PMU_POWER_SLEEP, "NULL"); + //gpio_direction_output(PMU_POWER_SLEEP, GPIO_HIGH); + + err = tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_DEVCTRL2); + if (err) { + printk(KERN_ERR "Unable to read TPS65910_REG_DEVCTRL2 reg\n"); + return -EIO; + } + /* Set sleep state active high and allow device turn-off after PWRON long press */ + val |= (TPS65910_DEV2_SLEEPSIG_POL | TPS65910_DEV2_PWON_LP_OFF); + + err = tps65910_i2c_write_u8(TPS65910_I2C_ID0, val, + TPS65910_REG_DEVCTRL2); + if (err) { + printk(KERN_ERR "Unable to write TPS65910_REG_DEVCTRL2 reg\n"); + return -EIO; + } + #if 1 + /* set PSKIP=0 */ + err = tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_DCDCCTRL); + if (err) { + printk(KERN_ERR "Unable to read TPS65910_REG_DCDCCTRL reg\n"); + return -EIO; + } + //val &= ~(1 << 4); + val &= 0xFC; + // val |= 0x03; + + err = tps65910_i2c_write_u8(TPS65910_I2C_ID0, val, + TPS65910_REG_DCDCCTRL); + if (err) { + printk(KERN_ERR "Unable to write TPS65910_REG_DCDCCTRL reg\n"); + return -EIO; + } + #endif + /* Set the maxinum load current */ + /* VDD1 */ + err = tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_VDD1); + if (err) { + printk(KERN_ERR "Unable to read TPS65910_REG_VDD1 reg\n"); + return -EIO; + } + + val |= (1<<5); + val |= (0x07<<2); + err = tps65910_i2c_write_u8(TPS65910_I2C_ID0, val, TPS65910_REG_VDD1); + if (err) { + printk(KERN_ERR "Unable to write TPS65910_REG_VDD1 reg\n"); + return -EIO; + } + + /* VDD2 */ + err = tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_VDD2); + if (err) { + printk(KERN_ERR "Unable to read TPS65910_REG_VDD2 reg\n"); + return -EIO; + } + + val |= (1<<5); + err = tps65910_i2c_write_u8(TPS65910_I2C_ID0, val, TPS65910_REG_VDD2); + if (err) { + printk(KERN_ERR "Unable to write TPS65910_REG_VDD2 reg\n"); + return -EIO; + } + + /* VIO */ + err = tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_VIO); + if (err) { + printk(KERN_ERR "Unable to read TPS65910_REG_VIO reg\n"); + return -EIO; + } + + val |= (1<<6); + err = tps65910_i2c_write_u8(TPS65910_I2C_ID0, val, TPS65910_REG_VIO); + if (err) { + printk(KERN_ERR "Unable to write TPS65910_REG_VIO reg\n"); + return -EIO; + } + #if 1 + /* Mask ALL interrupts */ + err = tps65910_i2c_write_u8(TPS65910_I2C_ID0, 0xFF, + TPS65910_REG_INT_MSK); + if (err) { + printk(KERN_ERR "Unable to write TPS65910_REG_INT_MSK reg\n"); + return -EIO; + } + err = tps65910_i2c_write_u8(TPS65910_I2C_ID0, 0x03, + TPS65910_REG_INT_MSK2); + if (err) { + printk(KERN_ERR "Unable to write TPS65910_REG_INT_MSK2 reg\n"); + return -EIO; + } + + /* Set RTC Power, disable Smart Reflex in DEVCTRL_REG */ + #if 1 + val = 0; + val |= (TPS65910_SR_CTL_I2C_SEL); + err = tps65910_i2c_write_u8(TPS65910_I2C_ID0, val, + TPS65910_REG_DEVCTRL); + if (err) { + printk(KERN_ERR "Unable to write TPS65910_REG_DEVCTRL reg\n"); + return -EIO; + } + 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_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_DEVCTRL+i); + if (err) { + printk(KERN_ERR "Unable to read TPS65910_REG_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 */ + err = tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_DEVCTRL); + if (err) { + printk(KERN_ERR "Unable to read TPS65910_REG_DCDCCTRL reg\n"); + return -EIO; + } + val |= (1 << 1); + err = tps65910_i2c_write_u8(TPS65910_I2C_ID0, val, TPS65910_REG_DEVCTRL); + if (err) { + printk(KERN_ERR "Unable to read TPS65910 Reg at offset 0x%x= \ + \n", TPS65910_REG_VDIG1); + return -EIO; + } + /* open ldo when in sleep mode */ + err = tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_SLEEP_KEEP_LDO_ON); + if (err) { + printk(KERN_ERR "Unable to read TPS65910_REG_DCDCCTRL reg\n"); + return -EIO; + } + val &= 0; + err = tps65910_i2c_write_u8(TPS65910_I2C_ID0, val, TPS65910_REG_SLEEP_KEEP_LDO_ON); + if (err) { + printk(KERN_ERR "Unable to read TPS65910 Reg at offset 0x%x= \ + \n", TPS65910_REG_VDIG1); + return -EIO; + } + /*set dc mode when in sleep mode */ + err = tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_SLEEP_KEEP_RES_ON); + if (err) { + printk(KERN_ERR "Unable to read TPS65910_REG_DCDCCTRL reg\n"); + return -EIO; + } + val |= 0xff; + err = tps65910_i2c_write_u8(TPS65910_I2C_ID0, val, TPS65910_REG_SLEEP_KEEP_RES_ON); + if (err) { + printk(KERN_ERR "Unable to read TPS65910 Reg at offset 0x%x= \ + \n", TPS65910_REG_VDIG1); + return -EIO; + } + /*close ldo when in sleep mode */ + err = tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_SLEEP_SET_LDO_OFF); + if (err) { + printk(KERN_ERR "Unable to read TPS65910_REG_DCDCCTRL reg\n"); + return -EIO; + } + val |= 0x9B; + err = tps65910_i2c_write_u8(TPS65910_I2C_ID0, val, TPS65910_REG_SLEEP_SET_LDO_OFF); + if (err) { + printk(KERN_ERR "Unable to read TPS65910 Reg at offset 0x%x= \ + \n", TPS65910_REG_VDIG1); + return -EIO; + } + #endif + #if 0 + //read sleep control register for debug + for(i=0; i<6; i++) + { + err = tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_DEVCTRL+i); + if (err) { + printk(KERN_ERR "Unable to read TPS65910_REG_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, 3000000, 3000000); + 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"); // vdd11 + regulator_set_voltage(ldo, 1100000, 1100000); + regulator_enable(ldo); + printk("%s set vpll vdd11=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + + ldo = regulator_get(NULL, "vdig2"); // vdd11_hdmi + regulator_set_voltage(ldo, 1100000, 1100000); + regulator_enable(ldo); + printk("%s set vdig2 vdd11_hdmi=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + + ldo = regulator_get(NULL, "vaux33"); //vcc33 + regulator_set_voltage(ldo, 3300000, 3300000); + regulator_enable(ldo); + printk("%s set vaux33 vcc33=%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, 1100000, 1100000); + 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, 1500000, 1500000); + 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"); //vccio_wl + regulator_set_voltage(ldo, 1700000, 1700000); + regulator_enable(ldo); + printk("%s set vdig1 vccio_wl=%dmV end\n", __func__, regulator_get_voltage(ldo)); + regulator_put(ldo); + udelay(100); + + dcdc = regulator_get(NULL, "vaux1"); //vcc25 + regulator_set_voltage(dcdc,2500000,2500000); + regulator_enable(dcdc); + printk("%s set vaux1 vcc25=%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"); // vcc18_cif + regulator_set_voltage(ldo,1800000,1800000); + regulator_enable(ldo); + printk("%s set vdac vcc18_cif=%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, 1150000, 1150000); + 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_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_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, + + .pre_init = tps65910_pre_init, + .post_init = tps65910_post_init, + + //TPS65910_NUM_REGS = 13 + // Regulators + .tps65910_pmic_init_data = { + NULL, + &tps65910_smps4, + &tps65910_smps1, + &tps65910_smps2, + &tps65910_smps3, + + &tps65910_ldo1, + &tps65910_ldo2, + &tps65910_ldo3, + &tps65910_ldo4, + &tps65910_ldo5, + &tps65910_ldo6, + &tps65910_ldo7, + &tps65910_ldo8, + }, + + +}; + +#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 441f198aac86..e245db7665fa 100755 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -52,4 +52,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 100644 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/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 index a56be931551c..c9ed5c00a621 100644 --- a/drivers/mfd/tps65910-irq.c +++ b/drivers/mfd/tps65910-irq.c @@ -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, @@ -215,6 +226,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 index 2229e66d80db..a5a7b3cf2700 100644 --- 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 400 * 1000 static int tps65910_i2c_read(struct tps65910 *tps65910, u8 reg, int bytes, void *dest) @@ -41,25 +44,29 @@ static int tps65910_i2c_read(struct tps65910 *tps65910, u8 reg, struct i2c_client *i2c = tps65910->i2c_client; struct i2c_msg xfer[2]; int ret; + + //printk("%s:reg=0x%x,value=%d\n",__func__,reg,*(char *)dest); /* Write register */ xfer[0].addr = i2c->addr; xfer[0].flags = 0; xfer[0].len = 1; xfer[0].buf = ® + xfer[0].scl_rate = 200*1000; /* 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 = 200*1000; ret = i2c_transfer(i2c->adapter, xfer, 2); if (ret == 2) ret = 0; else if (ret >= 0) ret = -EIO; - + return ret; } @@ -70,10 +77,12 @@ 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; - + if (bytes > TPS65910_MAX_REGISTER) return -EINVAL; + //printk("%s:reg=0x%x,value=%d\n",__func__,reg,*(char *)&src); + msg[0] = reg; memcpy(&msg[1], src, bytes); @@ -82,6 +91,7 @@ static int tps65910_i2c_write(struct tps65910 *tps65910, u8 reg, return ret; if (ret != bytes + 1) return -EIO; + return 0; } @@ -93,14 +103,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); @@ -167,6 +177,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 +194,14 @@ 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; + } + } + return ret; err: @@ -182,6 +210,45 @@ err: return ret; } + +int tps65910_i2c_write_u8(u8 slave_addr, u8 value, u8 reg) +{ + struct tps65910 *tps65910 = g_tps65910; + return tps65910->write(g_tps65910, reg, 1, &value); +} +EXPORT_SYMBOL_GPL(tps65910_i2c_write_u8); + + +int tps65910_i2c_read_u8(u8 slave_addr, u8 *value, u8 reg) +{ + struct tps65910 *tps65910 = g_tps65910; + return tps65910->read(g_tps65910, reg, 1, value); +} +EXPORT_SYMBOL_GPL(tps65910_i2c_read_u8); + +int tps65910_device_shutdown(void) +{ + u8 val = 0; + int err = -1; + printk("%s\n",__func__); + err = tps65910_i2c_read_u8(TPS65910_I2C_ID0, &val, TPS65910_REG_DEVCTRL); + if (err) { + printk(KERN_ERR "Unable to read TPS65910_REG_DCDCCTRL reg\n"); + return -EIO; + } + val |= (1 << 3)|(1 << 0); + err = tps65910_i2c_write_u8(TPS65910_I2C_ID0, val, TPS65910_REG_DEVCTRL); + if (err) { + printk(KERN_ERR "Unable to read TPS65910 Reg at offset 0x%x= \ + \n", TPS65910_REG_VDIG1); + return -EIO; + } + 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 +282,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); +module_init(tps65910_i2c_init); static void __exit tps65910_i2c_exit(void) { 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 index 425aab38981e..ca736adfada0 100644 --- 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) @@ -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) { @@ -491,7 +584,7 @@ static unsigned int tps65910_get_mode(struct regulator_dev *dev) 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,10 +592,10 @@ 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) { @@ -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) @@ -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; } @@ -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,10 +751,10 @@ 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), @@ -675,10 +762,10 @@ static int tps65910_set_voltage_dcdc(struct regulator_dev *dev, tps65910_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), @@ -686,14 +773,15 @@ static int tps65910_set_voltage_dcdc(struct regulator_dev *dev, tps65910_reg_write(pmic, TPS65910_VDD2_OP, vsel); break; case TPS65911_REG_VDDCTRL: - vsel = selector; + vsel = selector + 3; tps65910_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_reg_read(pmic, op_reg_add); + int srvsel = tps65910_reg_read(pmic, sr_reg_add); + if (opvsel & VDD1_OP_CMD_MASK) { + u8 reg_val = srvsel & VDD1_OP_SEL_MASK; + ret = tps65910_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_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); +module_init(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..93290a16ad22 --- /dev/null +++ b/drivers/rtc/rtc-tps65910.c @@ -0,0 +1,706 @@ +/* + * rtc-tps65910.c -- TPS65910 Real Time Clock interface + * + * Copyright (C) 2010 Mistral Solutions Pvt Ltd. + * Author: Umesh K + * + * Based on rtc-twl.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define DBG(x...) printk(KERN_INFO x) +#else +#define DBG(x...) +#endif + +/* RTC Definitions */ +/* RTC_CTRL_REG bitfields */ +#define BIT_RTC_CTRL_REG_STOP_RTC_M 0x01 +#define BIT_RTC_CTRL_REG_ROUND_30S_M 0x02 +#define BIT_RTC_CTRL_REG_AUTO_COMP_M 0x04 +#define BIT_RTC_CTRL_REG_MODE_12_24_M 0x08 +#define BIT_RTC_CTRL_REG_TEST_MODE_M 0x10 +#define BIT_RTC_CTRL_REG_SET_32_COUNTER_M 0x20 +#define BIT_RTC_CTRL_REG_GET_TIME_M 0x40 +#define BIT_RTC_CTRL_REG_RTC_V_OPT_M 0x80 + +/* RTC_STATUS_REG bitfields */ +#define BIT_RTC_STATUS_REG_RUN_M 0x02 +#define BIT_RTC_STATUS_REG_1S_EVENT_M 0x04 +#define BIT_RTC_STATUS_REG_1M_EVENT_M 0x08 +#define BIT_RTC_STATUS_REG_1H_EVENT_M 0x10 +#define BIT_RTC_STATUS_REG_1D_EVENT_M 0x20 +#define BIT_RTC_STATUS_REG_ALARM_M 0x40 +#define BIT_RTC_STATUS_REG_POWER_UP_M 0x80 + +/* RTC_INTERRUPTS_REG bitfields */ +#define BIT_RTC_INTERRUPTS_REG_EVERY_M 0x03 +#define BIT_RTC_INTERRUPTS_REG_IT_TIMER_M 0x04 +#define BIT_RTC_INTERRUPTS_REG_IT_ALARM_M 0x08 + +/* DEVCTRL bitfields */ +#define BIT_RTC_PWDN 0x40 + +/* REG_SECONDS_REG through REG_YEARS_REG is how many registers? */ +#define ALL_TIME_REGS 6 + +/* + * Supports 1 byte read from TPS65910 RTC register. + */ +static int tps65910_rtc_read_u8(u8 *data, u8 reg) +{ + int ret; + + ret = tps65910_i2c_read_u8(TPS65910_I2C_ID0, data, reg); + + if (ret < 0) + pr_err("tps65910_rtc: Could not read TPS65910" + "register %X - error %d\n", reg, ret); + return ret; +} + +/* + * Supports 1 byte write to TPS65910 RTC registers. + */ +static int tps65910_rtc_write_u8(u8 data, u8 reg) +{ + int ret; + + ret = tps65910_i2c_write_u8(TPS65910_I2C_ID0, data, reg); + if (ret < 0) + pr_err("tps65910_rtc: Could not write TPS65910" + "register %X - error %d\n", reg, ret); + return ret; +} + +/* + * Cache the value for timer/alarm interrupts register; this is + * only changed by callers holding rtc ops lock (or resume). + */ +static unsigned char rtc_irq_bits; + +/* + * Enable 1/second update and/or alarm interrupts. + */ +static int set_rtc_irq_bit(unsigned char bit) +{ + unsigned char val; + int ret; + + val = rtc_irq_bits | bit; + val |= bit; + ret = tps65910_rtc_write_u8(val, TPS65910_REG_RTC_INTERRUPTS); + if (ret == 0) + rtc_irq_bits = val; + + return ret; +} + +/* + * Disable update and/or alarm interrupts. + */ +static int mask_rtc_irq_bit(unsigned char bit) +{ + unsigned char val; + int ret; + + val = rtc_irq_bits & ~bit; + ret = tps65910_rtc_write_u8(val, TPS65910_REG_RTC_INTERRUPTS); + if (ret == 0) + rtc_irq_bits = val; + + return ret; +} + +static int tps65910_rtc_alarm_irq_enable(struct device *dev, unsigned enabled) +{ + int ret; + + if (enabled) + ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); + else + ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); + + return ret; +} + +static int tps65910_rtc_update_irq_enable(struct device *dev, unsigned enabled) +{ + int ret; + + if (enabled) + ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); + else + ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); + + return ret; +} + +#if 1 /* Debugging periodic interrupts */ +/* + * We will just handle setting the frequency and make use the framework for + * reading the periodic interupts. + * + * @freq: Current periodic IRQ freq: + * bit 0: every second + * bit 1: every minute + * bit 2: every hour + * bit 3: every day + */ + +static int tps65910_rtc_irq_set_freq(struct device *dev, int freq) +{ + struct rtc_device *rtc = dev_get_drvdata(dev); + + if (freq < 0 || freq > 3) + return -EINVAL; + + rtc->irq_freq = freq; + /* set rtc irq freq to user defined value */ + set_rtc_irq_bit(freq); + + return 0; +} +#endif + +/* + * Gets current TPS65910 RTC time and date parameters. + * + * The RTC's time/alarm representation is not what gmtime(3) requires + * Linux to use: + * + * - Months are 1..12 vs Linux 0-11 + * - Years are 0..99 vs Linux 1900..N (we assume 21st century) + */ +static int tps65910_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + unsigned char rtc_data[ALL_TIME_REGS + 1]; + int ret; + u8 save_control; + + tps65910_rtc_read_u8(&save_control, TPS65910_REG_RTC_CTRL); + ret = tps65910_rtc_read_u8(&save_control, TPS65910_REG_RTC_CTRL); + if (ret < 0) + return ret; + + save_control &= ~BIT_RTC_CTRL_REG_RTC_V_OPT_M; + + ret = tps65910_rtc_write_u8(save_control, TPS65910_REG_RTC_CTRL); + if (ret < 0) + return ret; + + ret = tps65910_rtc_read_u8(&rtc_data[0], TPS65910_REG_SECONDS); + if (ret < 0) { + dev_err(dev, "rtc_read_time error %d\n", ret); + return ret; + } + ret = tps65910_rtc_read_u8(&rtc_data[1], TPS65910_REG_MINUTES); + if (ret < 0) { + dev_err(dev, "rtc_read_time error %d\n", ret); + return ret; + } + ret = tps65910_rtc_read_u8(&rtc_data[2], TPS65910_REG_HOURS); + if (ret < 0) { + dev_err(dev, "rtc_read_time error %d\n", ret); + return ret; + } + ret = tps65910_rtc_read_u8(&rtc_data[3], TPS65910_REG_DAYS); + if (ret < 0) { + dev_err(dev, "rtc_read_time error %d\n", ret); + return ret; + } + ret = tps65910_rtc_read_u8(&rtc_data[4], TPS65910_REG_MONTHS); + if (ret < 0) { + dev_err(dev, "rtc_read_time error %d\n", ret); + return ret; + } + ret = tps65910_rtc_read_u8(&rtc_data[5], TPS65910_REG_YEARS); + if (ret < 0) { + dev_err(dev, "rtc_read_time error %d\n", ret); + return ret; + } + + tm->tm_sec = bcd2bin(rtc_data[0]); + tm->tm_min = bcd2bin(rtc_data[1]); + tm->tm_hour = bcd2bin(rtc_data[2]); + tm->tm_mday = bcd2bin(rtc_data[3]); + tm->tm_mon = bcd2bin(rtc_data[4]) - 1; + tm->tm_year = bcd2bin(rtc_data[5]) + 100; + + DBG("%s [%d]tm_wday=%d \n",__FUNCTION__,__LINE__,tm->tm_wday); + DBG("%s [%d]tm_sec=%d \n",__FUNCTION__,__LINE__,tm->tm_sec); + DBG("%s [%d]tm_min=%d \n",__FUNCTION__,__LINE__,tm->tm_min); + DBG("%s [%d]tm_hour=%d \n",__FUNCTION__,__LINE__,tm->tm_hour); + DBG("%s [%d]tm_mday=%d \n",__FUNCTION__,__LINE__,tm->tm_mday); + DBG("%s [%d]tm_mon=%d \n",__FUNCTION__,__LINE__,tm->tm_mon); + DBG("%s [%d]tm_year=%d \n",__FUNCTION__,__LINE__,tm->tm_year); + + return ret; +} + +static int tps65910_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + unsigned char save_control; + unsigned char rtc_data[ALL_TIME_REGS + 1]; + int ret; + + DBG("%s [%d]tm_wday=%d \n",__FUNCTION__,__LINE__,tm->tm_wday); + DBG("%s [%d]tm_sec=%d \n",__FUNCTION__,__LINE__,tm->tm_sec); + DBG("%s [%d]tm_min=%d \n",__FUNCTION__,__LINE__,tm->tm_min); + DBG("%s [%d]tm_hour=%d \n",__FUNCTION__,__LINE__,tm->tm_hour); + DBG("%s [%d]tm_mday=%d \n",__FUNCTION__,__LINE__,tm->tm_mday); + DBG("%s [%d]tm_mon=%d \n",__FUNCTION__,__LINE__,tm->tm_mon); + DBG("%s [%d]tm_year=%d \n",__FUNCTION__,__LINE__,tm->tm_year); + + rtc_data[1] = bin2bcd(tm->tm_sec); + rtc_data[2] = bin2bcd(tm->tm_min); + rtc_data[3] = bin2bcd(tm->tm_hour); + rtc_data[4] = bin2bcd(tm->tm_mday); + rtc_data[5] = bin2bcd(tm->tm_mon + 1); + rtc_data[6] = bin2bcd(tm->tm_year - 100); + + /*Dummy read*/ + ret = tps65910_rtc_read_u8(&save_control, TPS65910_REG_RTC_CTRL); + + /* Stop RTC while updating the TC registers */ + ret = tps65910_rtc_read_u8(&save_control, TPS65910_REG_RTC_CTRL); + if (ret < 0) + goto out; + + save_control &= ~BIT_RTC_CTRL_REG_STOP_RTC_M; + + tps65910_rtc_write_u8(save_control, TPS65910_REG_RTC_CTRL); + + /* update all the time registers in one shot */ + ret = tps65910_rtc_write_u8(rtc_data[1], TPS65910_REG_SECONDS); + if (ret < 0) { + dev_err(dev, "rtc_write_time error %d\n", ret); + return ret; + } + ret = tps65910_rtc_write_u8(rtc_data[2], TPS65910_REG_MINUTES); + if (ret < 0) { + dev_err(dev, "rtc_write_time error %d\n", ret); + return ret; + } + ret = tps65910_rtc_write_u8(rtc_data[3], TPS65910_REG_HOURS); + if (ret < 0) { + dev_err(dev, "rtc_write_time error %d\n", ret); + return ret; + } + ret = tps65910_rtc_write_u8(rtc_data[4], TPS65910_REG_DAYS); + if (ret < 0) { + dev_err(dev, "rtc_write_time error %d\n", ret); + return ret; + } + ret = tps65910_rtc_write_u8(rtc_data[5], TPS65910_REG_MONTHS); + if (ret < 0) { + dev_err(dev, "rtc_write_time error %d\n", ret); + return ret; + } + ret = tps65910_rtc_write_u8(rtc_data[6], TPS65910_REG_YEARS); + if (ret < 0) { + dev_err(dev, "rtc_write_time error %d\n", ret); + return ret; + } + + /*Dummy read*/ + ret = tps65910_rtc_read_u8(&save_control, TPS65910_REG_RTC_CTRL); + + ret = tps65910_rtc_read_u8(&save_control, TPS65910_REG_RTC_CTRL); + if (ret < 0) + goto out; + /* Start back RTC */ + save_control |= BIT_RTC_CTRL_REG_STOP_RTC_M; + ret = tps65910_rtc_write_u8(save_control, TPS65910_REG_RTC_CTRL); + +out: + return ret; +} + +/* + * Gets current TPS65910 RTC alarm time. + */ +static int tps65910_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) +{ + unsigned char rtc_data[ALL_TIME_REGS + 1]; + int ret; + + ret = tps65910_rtc_read_u8(&rtc_data[0], TPS65910_REG_ALARM_SECONDS); + if (ret < 0) { + dev_err(dev, "rtc_read_time error %d\n", ret); + return ret; + } + ret = tps65910_rtc_read_u8(&rtc_data[1], TPS65910_REG_ALARM_MINUTES); + if (ret < 0) { + dev_err(dev, "rtc_read_time error %d\n", ret); + return ret; + } + ret = tps65910_rtc_read_u8(&rtc_data[2], TPS65910_REG_ALARM_HOURS); + if (ret < 0) { + dev_err(dev, "rtc_read_time error %d\n", ret); + return ret; + } + ret = tps65910_rtc_read_u8(&rtc_data[3], TPS65910_REG_ALARM_DAYS); + if (ret < 0) { + dev_err(dev, "rtc_read_time error %d\n", ret); + return ret; + } + ret = tps65910_rtc_read_u8(&rtc_data[4], TPS65910_REG_ALARM_MONTHS); + if (ret < 0) { + dev_err(dev, "rtc_read_time error %d\n", ret); + return ret; + } + ret = tps65910_rtc_read_u8(&rtc_data[5], TPS65910_REG_ALARM_YEARS); + if (ret < 0) { + dev_err(dev, "rtc_read_time error %d\n", ret); + return ret; + } + + /* some of these fields may be wildcard/"match all" */ + alm->time.tm_sec = bcd2bin(rtc_data[0]); + alm->time.tm_min = bcd2bin(rtc_data[1]); + alm->time.tm_hour = bcd2bin(rtc_data[2]); + alm->time.tm_mday = bcd2bin(rtc_data[3]); + alm->time.tm_mon = bcd2bin(rtc_data[4]) - 1; + alm->time.tm_year = bcd2bin(rtc_data[5]) + 100; + + /* report cached alarm enable state */ + if (rtc_irq_bits & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M) + alm->enabled = 1; + + return ret; +} + +static int tps65910_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) +{ + unsigned char alarm_data[ALL_TIME_REGS + 1]; + int ret; + + ret = tps65910_rtc_alarm_irq_enable(dev, 0); + if (ret) + goto out; + + alarm_data[1] = bin2bcd(alm->time.tm_sec); + alarm_data[2] = bin2bcd(alm->time.tm_min); + alarm_data[3] = bin2bcd(alm->time.tm_hour); + alarm_data[4] = bin2bcd(alm->time.tm_mday); + alarm_data[5] = bin2bcd(alm->time.tm_mon + 1); + alarm_data[6] = bin2bcd(alm->time.tm_year - 100); + + /* update all the alarm registers in one shot */ + ret = tps65910_rtc_write_u8(alarm_data[1], TPS65910_REG_ALARM_SECONDS); + if (ret < 0) { + dev_err(dev, "rtc_write_time error %d\n", ret); + return ret; + } + ret = tps65910_rtc_write_u8(alarm_data[2], TPS65910_REG_ALARM_MINUTES); + if (ret < 0) { + dev_err(dev, "rtc_write_time error %d\n", ret); + return ret; + } + ret = tps65910_rtc_write_u8(alarm_data[3], TPS65910_REG_ALARM_HOURS); + if (ret < 0) { + dev_err(dev, "rtc_write_time error %d\n", ret); + return ret; + } + ret = tps65910_rtc_write_u8(alarm_data[4], TPS65910_REG_ALARM_DAYS); + if (ret < 0) { + dev_err(dev, "rtc_write_time error %d\n", ret); + return ret; + } + ret = tps65910_rtc_write_u8(alarm_data[5], TPS65910_REG_ALARM_MONTHS); + if (ret < 0) { + dev_err(dev, "rtc_write_time error %d\n", ret); + return ret; + } + ret = tps65910_rtc_write_u8(alarm_data[6], TPS65910_REG_ALARM_YEARS); + if (ret < 0) { + dev_err(dev, "rtc_write_time error %d\n", ret); + return ret; + } + + if (alm->enabled) + ret = tps65910_rtc_alarm_irq_enable(dev, 1); +out: + return ret; +} + + +struct work_struct rtc_wq; +unsigned long rtc_events; +struct rtc_device *global_rtc; + +void tps65910_rtc_work(void *data) +{ + int res; + u8 rd_reg; + unsigned long events = 0; + + DBG("Enter::%s %d\n",__FUNCTION__,__LINE__); + + res = tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_INT_STS); + + if (res < 0) + goto out; + /* + * Figure out source of interrupt: ALARM or TIMER in RTC_STATUS_REG. + * only one (ALARM or RTC) interrupt source may be enabled + * at time, we also could check our results + * by reading RTS_INTERRUPTS_REGISTER[IT_TIMER,IT_ALARM] + */ + if (rd_reg & TPS65910_RTC_ALARM_IT) { + res = tps65910_rtc_write_u8(rd_reg | TPS65910_RTC_ALARM_IT, + TPS65910_REG_INT_STS); + if (res < 0) + goto out; + + /*Dummy read -- mandatory for status register*/ + res = tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_RTC_STATUS); + mdelay(100); + res = tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_RTC_STATUS); + res = tps65910_rtc_write_u8(rd_reg, TPS65910_REG_RTC_STATUS); + + rtc_events |= RTC_IRQF | RTC_AF; + } else if (rd_reg & TPS65910_RTC_PERIOD_IT) { + res = tps65910_rtc_write_u8(rd_reg | TPS65910_RTC_PERIOD_IT, + TPS65910_REG_INT_STS); + if (res < 0) + goto out; + + /*Dummy read -- mandatory for status register*/ + res = tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_RTC_STATUS); + mdelay(100); + res = tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_RTC_STATUS); + rd_reg &= 0xC3; + res = tps65910_rtc_write_u8(rd_reg, TPS65910_REG_RTC_STATUS); + rtc_events |= RTC_IRQF | RTC_UF; + } +out: + /* Notify RTC core on event */ + events = rtc_events; + rtc_update_irq(global_rtc, 1, events); +} + +static struct rtc_class_ops tps65910_rtc_ops = { + .read_time = tps65910_rtc_read_time, + .set_time = tps65910_rtc_set_time, + .read_alarm = tps65910_rtc_read_alarm, + .set_alarm = tps65910_rtc_set_alarm, + .alarm_irq_enable = tps65910_rtc_alarm_irq_enable, +// .update_irq_enable = tps65910_rtc_update_irq_enable, +// .irq_set_freq = tps65910_rtc_irq_set_freq, +}; + +static int __devinit tps65910_rtc_probe(struct platform_device *pdev) +{ + struct rtc_device *rtc; + int ret = 0, stop_run = 0; + u8 rd_reg; + struct rtc_time tm_def = { // 2011.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, + }; + + rtc = rtc_device_register(pdev->name, + &pdev->dev, &tps65910_rtc_ops, THIS_MODULE); + + if (IS_ERR(rtc)) { + ret = PTR_ERR(rtc); + dev_err(&pdev->dev, "can't register TPS65910 RTC device,\ + err %ld\n", PTR_ERR(rtc)); + goto out0; + + } + printk(KERN_INFO "TPS65910 RTC device successfully registered\n"); + + platform_set_drvdata(pdev, rtc); + /* Take rtc out of reset */ + tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_DEVCTRL); + rd_reg &= ~BIT_RTC_PWDN; + ret = tps65910_rtc_write_u8(rd_reg, TPS65910_REG_DEVCTRL); + + /* Dummy read to ensure that the register gets updated. + * Please refer tps65910 TRM table:25 for details + */ + stop_run = 0; + ret = tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_RTC_STATUS); + if (ret < 0) { + printk(KERN_ERR "TPS65910 RTC STATUS REG READ FAILED\n"); + goto out1; + } + + if (rd_reg & BIT_RTC_STATUS_REG_POWER_UP_M) { + dev_warn(&pdev->dev, "Power up reset detected.\n"); + // cwz:if rtc power up reset, set default time. + printk(KERN_INFO "TPS65910 RTC set to default time\n"); + tps65910_rtc_set_time(&rtc->dev, &tm_def); + } + if (!(rd_reg & BIT_RTC_STATUS_REG_RUN_M)) { + dev_warn(&pdev->dev, "RTC stop run.\n"); + stop_run = 1; + } + if (rd_reg & BIT_RTC_STATUS_REG_ALARM_M) + dev_warn(&pdev->dev, "Pending Alarm interrupt detected.\n"); + + /* Clear RTC Power up reset and pending alarm interrupts */ + ret = tps65910_rtc_write_u8(rd_reg, TPS65910_REG_RTC_STATUS); + if (ret < 0) + goto out1; + + ret = tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_INT_STS); + if (ret < 0) { + printk(KERN_ERR "TPS65910 RTC STATUS REG READ FAILED\n"); + goto out1; + } + + if (rd_reg & 0x40) { + printk(KERN_INFO "pending alarm interrupt!!! clearing!!!"); + tps65910_rtc_write_u8(rd_reg, TPS65910_REG_INT_STS); + } + + global_rtc = rtc; + + /* Link RTC IRQ handler to TPS65910 Core */ + //tps65910_add_irq_work(TPS65910_RTC_ALARM_IRQ, tps65910_rtc_work); + //tps65910_add_irq_work(TPS65910_RTC_PERIOD_IRQ, tps65910_rtc_work); + + /* Check RTC module status, Enable if it is off */ + if (stop_run) { + dev_info(&pdev->dev, "Enabling TPS65910-RTC.\n"); + // cwz:if rtc stop, set default time, then enable rtc + printk(KERN_INFO "TPS65910 RTC set to default time\n"); + tps65910_rtc_set_time(&rtc->dev, &tm_def); + ret = tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_RTC_CTRL); + if (ret < 0) + goto out1; + + rd_reg |= BIT_RTC_CTRL_REG_STOP_RTC_M; + ret = tps65910_rtc_write_u8(rd_reg, TPS65910_REG_RTC_CTRL); + if (ret < 0) + goto out1; + } + + /* init cached IRQ enable bits */ + ret = tps65910_rtc_read_u8(&rtc_irq_bits, TPS65910_REG_RTC_INTERRUPTS); + if (ret < 0) + goto out1; + + tps65910_rtc_write_u8(0x3F, TPS65910_REG_INT_MSK); + return ret; + +out1: + rtc_device_unregister(rtc); +out0: + return ret; +} + +/* + * Disable all TPS65910 RTC module interrupts. + * Sets status flag to free. + */ +static int __devexit tps65910_rtc_remove(struct platform_device *pdev) +{ + /* leave rtc running, but disable irqs */ + struct rtc_device *rtc = platform_get_drvdata(pdev); + int irq = platform_get_irq(pdev, 0); + + mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); + mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); + + + free_irq(irq, rtc); + + rtc_device_unregister(rtc); + platform_set_drvdata(pdev, NULL); + return 0; +} + +static void tps65910_rtc_shutdown(struct platform_device *pdev) +{ + /* mask timer interrupts, but leave alarm interrupts on to enable + * power-on when alarm is triggered + */ + mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); +} + +#ifdef CONFIG_PM + +static unsigned char irqstat; + +static +int tps65910_rtc_suspend(struct platform_device *pdev, pm_message_t state) +{ + irqstat = rtc_irq_bits; + mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); + return 0; +} + +static int tps65910_rtc_resume(struct platform_device *pdev) +{ + set_rtc_irq_bit(irqstat); + return 0; +} + +#else +#define tps65910_rtc_suspend NULL +#define tps65910_rtc_resume NULL +#endif + + +static struct platform_driver tps65910rtc_driver = { + .probe = tps65910_rtc_probe, + .remove = __devexit_p(tps65910_rtc_remove), + .shutdown = tps65910_rtc_shutdown, + .suspend = tps65910_rtc_suspend, + .resume = tps65910_rtc_resume, + .driver = { + .owner = THIS_MODULE, + .name = "tps65910_rtc", + }, +}; + +//extern int board_wm831x ; +static int __init tps65910_rtc_init(void) +{ +// if (board_wm831x == 1) +// { +// printk("board with wm831 not tps65910,so skip register tps65910\n"); +// return 0; +// } + + return platform_driver_register(&tps65910rtc_driver); +} +module_init(tps65910_rtc_init); + +static void __exit tps65910_rtc_exit(void) +{ + platform_driver_unregister(&tps65910rtc_driver); +} +module_exit(tps65910_rtc_exit); + +MODULE_ALIAS("platform:tps65910_rtc"); +MODULE_AUTHOR("cwz + /* 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 */ @@ -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,200 @@ #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 + + + + +/* + * ---------------------------------------------------------------------------- + * Registers, all 8 bits + * ---------------------------------------------------------------------------- */ +#define TPS65910_REG_SECONDS 0x00 +#define TPS65910_REG_MINUTES 0x01 +#define TPS65910_REG_HOURS 0x02 +#define TPS65910_REG_DAYS 0x03 +#define TPS65910_REG_MONTHS 0x04 +#define TPS65910_REG_YEARS 0x05 +#define TPS65910_REG_WEEKS 0x06 +#define TPS65910_REG_ALARM_SECONDS 0x08 +#define TPS65910_REG_ALARM_MINUTES 0x09 +#define TPS65910_REG_ALARM_HOURS 0x0A +#define TPS65910_REG_ALARM_DAYS 0x0B +#define TPS65910_REG_ALARM_MONTHS 0x0C +#define TPS65910_REG_ALARM_YEARS 0x0D + +#define TPS65910_REG_RTC_CTRL 0x10 +#define TPS65910_REG_RTC_STATUS 0x11 +#define TPS65910_REG_RTC_INTERRUPTS 0x12 +#define TPS65910_REG_RTC_COMP_LSB 0x13 +#define TPS65910_REG_RTC_COMP_MSB 0x14 +#define TPS65910_REG_RTC_RES_PROG 0x15 +#define TPS65910_REG_RTC_RESET_STATUS 0x16 +#define TPS65910_REG_BCK1 0x17 +#define TPS65910_REG_BCK2 0x18 +#define TPS65910_REG_BCK3 0x19 +#define TPS65910_REG_BCK4 0x1A +#define TPS65910_REG_BCK5 0x1B +#define TPS65910_REG_PUADEN 0x1C +#define TPS65910_REG_REF 0x1D + +#define TPS65910_REG_THERM 0x38 +#define TPS65910_REG_BBCH 0x39 + +#define TPS65910_REG_DCDCCTRL 0x3E +#define TPS65910_REG_DEVCTRL 0x3F +#define TPS65910_REG_DEVCTRL2 0x40 +#define TPS65910_REG_SLEEP_KEEP_LDO_ON 0x41 +#define TPS65910_REG_SLEEP_KEEP_RES_ON 0x42 +#define TPS65910_REG_SLEEP_SET_LDO_OFF 0x43 +#define TPS65910_REG_SLEEP_SET_RES_OFF 0x44 +#define TPS65910_REG_EN1_LDO_ASS 0x45 +#define TPS65910_REG_EN1_SMPS_ASS 0x46 +#define TPS65910_REG_EN2_LDO_ASS 0x47 +#define TPS65910_REG_EN2_SMPS_ASS 0x48 +#define TPS65910_REG_EN3_LDO_ASS 0x49 +#define TPS65910_REG_SPARE 0x4A + +#define TPS65910_REG_INT_STS 0x50 +#define TPS65910_REG_INT_MSK 0x51 +#define TPS65910_REG_INT_STS2 0x52 +#define TPS65910_REG_INT_MSK2 0x53 +#define TPS65910_REG_INT_STS3 0x54 +#define TPS65910_REG_INT_MSK3 0x55 + +#define TPS65910_REG_GPIO0 0x60 + +#define TPS65910_REG_JTAGVERNUM 0x80 + +/* TPS65910 GPIO Specific flags */ +#define TPS65910_GPIO_INT_FALLING 0 +#define TPS65910_GPIO_INT_RISING 1 + +#define TPS65910_DEBOUNCE_91_5_MS 0 +#define TPS65910_DEBOUNCE_150_MS 1 + +#define TPS65910_GPIO_PUDIS (1 << 3) +#define TPS65910_GPIO_CFG_OUTPUT (1 << 2) + + + +/* TPS65910 Interrupt events */ + +/* RTC Driver */ +#define TPS65910_RTC_ALARM_IT 0x80 +#define TPS65910_RTC_PERIOD_IT 0x40 + +/*Core Driver */ +#define TPS65910_HOT_DIE_IT 0x20 +#define TPS65910_PWRHOLD_IT 0x10 +#define TPS65910_PWRON_LP_IT 0x08 +#define TPS65910_PWRON_IT 0x04 +#define TPS65910_VMBHI_IT 0x02 +#define TPS65910_VMBGCH_IT 0x01 + +/* GPIO driver */ +#define TPS65910_GPIO_F_IT 0x02 +#define TPS65910_GPIO_R_IT 0x01 + + +#define TPS65910_VRTC_OFFMASK (1<<3) + +/* Back-up battery charger control */ +#define TPS65910_BBCHEN 0x01 + +/* Back-up battery charger voltage */ +#define TPS65910_BBSEL_3P0 0x00 +#define TPS65910_BBSEL_2P52 0x02 +#define TPS65910_BBSEL_3P15 0x04 +#define TPS65910_BBSEL_VBAT 0x06 + +/* DEVCTRL_REG flags */ +#define TPS65910_RTC_PWDNN 0x40 +#define TPS65910_CK32K_CTRL 0x20 +#define TPS65910_SR_CTL_I2C_SEL 0x10 +#define TPS65910_DEV_OFF_RST 0x08 +#define TPS65910_DEV_ON 0x04 +#define TPS65910_DEV_SLP 0x02 +#define TPS65910_DEV_OFF 0x01 + +/* DEVCTRL2_REG flags */ +#define TPS65910_DEV2_TSLOT_LENGTH 0x30 +#define TPS65910_DEV2_SLEEPSIG_POL 0x08 +#define TPS65910_DEV2_PWON_LP_OFF 0x04 +#define TPS65910_DEV2_PWON_LP_RST 0x02 +#define TPS65910_DEV2_IT_POL 0x01 + +/* Number of step-down/up converters available */ +#define TPS65910_NUM_DCDC 4 + +/* Number of LDO voltage regulators available */ +#define TPS65910_NUM_LDO 9 + +/* Number of total regulators available */ +#define TPS65910_NUM_REGULATOR (TPS65910_NUM_DCDC + TPS65910_NUM_LDO) + + +/* Regulator Supply state */ +#define SUPPLY_STATE_FLAG 0x03 +/* OFF States */ +#define TPS65910_REG_OFF_00 0x00 +#define TPS65910_REG_OFF_10 0x02 +/* OHP - on High Power */ +#define TPS65910_REG_OHP 0x01 +/* OLP - on Low Power */ +#define TPS65910_REG_OLP 0x03 + +#define TPS65910_MAX_IRQS 10 +#define TPS65910_VMBDCH_IRQ 0 +#define TPS65910_VMBHI_IRQ 1 +#define TPS65910_PWRON_IRQ 2 +#define TPS65910_PWRON_LP_IRQ 3 +#define TPS65910_PWRHOLD_IRQ 4 +#define TPS65910_HOTDIE_IRQ 5 +#define TPS65910_RTC_ALARM_IRQ 6 +#define TPS65910_RTC_PERIOD_IRQ 7 +#define TPS65910_GPIO0_R_IRQ 8 +#define TPS65910_GPIO0_F_IRQ 9 -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,6 +950,7 @@ 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); @@ -786,11 +977,41 @@ 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_i2c_write_u8(u8 slave_addr, u8 value, u8 reg); +int tps65910_i2c_read_u8(u8 slave_addr, u8 *value, u8 reg); +int tps65910_device_shutdown(void); + static inline int tps65910_chip_id(struct tps65910 *tps65910) { diff --git a/include/linux/mfd/tps65912.h b/include/linux/mfd/tps65912.h new file mode 100644 index 000000000000..aaceab402ec5 --- /dev/null +++ b/include/linux/mfd/tps65912.h @@ -0,0 +1,327 @@ +/* + * tps65912.h -- TI TPS6591x + * + * Copyright 2011 Texas Instruments Inc. + * + * Author: Margarita Olaya + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __LINUX_MFD_TPS65912_H +#define __LINUX_MFD_TPS65912_H + +/* TPS regulator type list */ +#define REGULATOR_LDO 0 +#define REGULATOR_DCDC 1 + +/* + * List of registers for TPS65912 + */ + +#define TPS65912_DCDC1_CTRL 0x00 +#define TPS65912_DCDC2_CTRL 0x01 +#define TPS65912_DCDC3_CTRL 0x02 +#define TPS65912_DCDC4_CTRL 0x03 +#define TPS65912_DCDC1_OP 0x04 +#define TPS65912_DCDC1_AVS 0x05 +#define TPS65912_DCDC1_LIMIT 0x06 +#define TPS65912_DCDC2_OP 0x07 +#define TPS65912_DCDC2_AVS 0x08 +#define TPS65912_DCDC2_LIMIT 0x09 +#define TPS65912_DCDC3_OP 0x0A +#define TPS65912_DCDC3_AVS 0x0B +#define TPS65912_DCDC3_LIMIT 0x0C +#define TPS65912_DCDC4_OP 0x0D +#define TPS65912_DCDC4_AVS 0x0E +#define TPS65912_DCDC4_LIMIT 0x0F +#define TPS65912_LDO1_OP 0x10 +#define TPS65912_LDO1_AVS 0x11 +#define TPS65912_LDO1_LIMIT 0x12 +#define TPS65912_LDO2_OP 0x13 +#define TPS65912_LDO2_AVS 0x14 +#define TPS65912_LDO2_LIMIT 0x15 +#define TPS65912_LDO3_OP 0x16 +#define TPS65912_LDO3_AVS 0x17 +#define TPS65912_LDO3_LIMIT 0x18 +#define TPS65912_LDO4_OP 0x19 +#define TPS65912_LDO4_AVS 0x1A +#define TPS65912_LDO4_LIMIT 0x1B +#define TPS65912_LDO5 0x1C +#define TPS65912_LDO6 0x1D +#define TPS65912_LDO7 0x1E +#define TPS65912_LDO8 0x1F +#define TPS65912_LDO9 0x20 +#define TPS65912_LDO10 0x21 +#define TPS65912_THRM 0x22 +#define TPS65912_CLK32OUT 0x23 +#define TPS65912_DEVCTRL 0x24 +#define TPS65912_DEVCTRL2 0x25 +#define TPS65912_I2C_SPI_CFG 0x26 +#define TPS65912_KEEP_ON 0x27 +#define TPS65912_KEEP_ON2 0x28 +#define TPS65912_SET_OFF1 0x29 +#define TPS65912_SET_OFF2 0x2A +#define TPS65912_DEF_VOLT 0x2B +#define TPS65912_DEF_VOLT_MAPPING 0x2C +#define TPS65912_DISCHARGE 0x2D +#define TPS65912_DISCHARGE2 0x2E +#define TPS65912_EN1_SET1 0x2F +#define TPS65912_EN1_SET2 0x30 +#define TPS65912_EN2_SET1 0x31 +#define TPS65912_EN2_SET2 0x32 +#define TPS65912_EN3_SET1 0x33 +#define TPS65912_EN3_SET2 0x34 +#define TPS65912_EN4_SET1 0x35 +#define TPS65912_EN4_SET2 0x36 +#define TPS65912_PGOOD 0x37 +#define TPS65912_PGOOD2 0x38 +#define TPS65912_INT_STS 0x39 +#define TPS65912_INT_MSK 0x3A +#define TPS65912_INT_STS2 0x3B +#define TPS65912_INT_MSK2 0x3C +#define TPS65912_INT_STS3 0x3D +#define TPS65912_INT_MSK3 0x3E +#define TPS65912_INT_STS4 0x3F +#define TPS65912_INT_MSK4 0x40 +#define TPS65912_GPIO1 0x41 +#define TPS65912_GPIO2 0x42 +#define TPS65912_GPIO3 0x43 +#define TPS65912_GPIO4 0x44 +#define TPS65912_GPIO5 0x45 +#define TPS65912_VMON 0x46 +#define TPS65912_LEDA_CTRL1 0x47 +#define TPS65912_LEDA_CTRL2 0x48 +#define TPS65912_LEDA_CTRL3 0x49 +#define TPS65912_LEDA_CTRL4 0x4A +#define TPS65912_LEDA_CTRL5 0x4B +#define TPS65912_LEDA_CTRL6 0x4C +#define TPS65912_LEDA_CTRL7 0x4D +#define TPS65912_LEDA_CTRL8 0x4E +#define TPS65912_LEDB_CTRL1 0x4F +#define TPS65912_LEDB_CTRL2 0x50 +#define TPS65912_LEDB_CTRL3 0x51 +#define TPS65912_LEDB_CTRL4 0x52 +#define TPS65912_LEDB_CTRL5 0x53 +#define TPS65912_LEDB_CTRL6 0x54 +#define TPS65912_LEDB_CTRL7 0x55 +#define TPS65912_LEDB_CTRL8 0x56 +#define TPS65912_LEDC_CTRL1 0x57 +#define TPS65912_LEDC_CTRL2 0x58 +#define TPS65912_LEDC_CTRL3 0x59 +#define TPS65912_LEDC_CTRL4 0x5A +#define TPS65912_LEDC_CTRL5 0x5B +#define TPS65912_LEDC_CTRL6 0x5C +#define TPS65912_LEDC_CTRL7 0x5D +#define TPS65912_LEDC_CTRL8 0x5E +#define TPS65912_LED_RAMP_UP_TIME 0x5F +#define TPS65912_LED_RAMP_DOWN_TIME 0x60 +#define TPS65912_LED_SEQ_EN 0x61 +#define TPS65912_LOADSWITCH 0x62 +#define TPS65912_SPARE 0x63 +#define TPS65912_VERNUM 0x64 +#define TPS6591X_MAX_REGISTER 0x64 + +/* IRQ Definitions */ +#define TPS65912_IRQ_PWRHOLD_F 0 +#define TPS65912_IRQ_VMON 1 +#define TPS65912_IRQ_PWRON 2 +#define TPS65912_IRQ_PWRON_LP 3 +#define TPS65912_IRQ_PWRHOLD_R 4 +#define TPS65912_IRQ_HOTDIE 5 +#define TPS65912_IRQ_GPIO1_R 6 +#define TPS65912_IRQ_GPIO1_F 7 +#define TPS65912_IRQ_GPIO2_R 8 +#define TPS65912_IRQ_GPIO2_F 9 +#define TPS65912_IRQ_GPIO3_R 10 +#define TPS65912_IRQ_GPIO3_F 11 +#define TPS65912_IRQ_GPIO4_R 12 +#define TPS65912_IRQ_GPIO4_F 13 +#define TPS65912_IRQ_GPIO5_R 14 +#define TPS65912_IRQ_GPIO5_F 15 +#define TPS65912_IRQ_PGOOD_DCDC1 16 +#define TPS65912_IRQ_PGOOD_DCDC2 17 +#define TPS65912_IRQ_PGOOD_DCDC3 18 +#define TPS65912_IRQ_PGOOD_DCDC4 19 +#define TPS65912_IRQ_PGOOD_LDO1 20 +#define TPS65912_IRQ_PGOOD_LDO2 21 +#define TPS65912_IRQ_PGOOD_LDO3 22 +#define TPS65912_IRQ_PGOOD_LDO4 23 +#define TPS65912_IRQ_PGOOD_LDO5 24 +#define TPS65912_IRQ_PGOOD_LDO6 25 +#define TPS65912_IRQ_PGOOD_LDO7 26 +#define TPS65912_IRQ_PGOOD_LD08 27 +#define TPS65912_IRQ_PGOOD_LDO9 28 +#define TPS65912_IRQ_PGOOD_LDO10 29 + +#define TPS65912_NUM_IRQ 30 + +/* GPIO 1 and 2 Register Definitions */ +#define GPIO_SLEEP_MASK 0x80 +#define GPIO_SLEEP_SHIFT 7 +#define GPIO_DEB_MASK 0x10 +#define GPIO_DEB_SHIFT 4 +#define GPIO_CFG_MASK 0x04 +#define GPIO_CFG_SHIFT 2 +#define GPIO_STS_MASK 0x02 +#define GPIO_STS_SHIFT 1 +#define GPIO_SET_MASK 0x01 +#define GPIO_SET_SHIFT 0 + +/* GPIO 3 Register Definitions */ +#define GPIO3_SLEEP_MASK 0x80 +#define GPIO3_SLEEP_SHIFT 7 +#define GPIO3_SEL_MASK 0x40 +#define GPIO3_SEL_SHIFT 6 +#define GPIO3_ODEN_MASK 0x20 +#define GPIO3_ODEN_SHIFT 5 +#define GPIO3_DEB_MASK 0x10 +#define GPIO3_DEB_SHIFT 4 +#define GPIO3_PDEN_MASK 0x08 +#define GPIO3_PDEN_SHIFT 3 +#define GPIO3_CFG_MASK 0x04 +#define GPIO3_CFG_SHIFT 2 +#define GPIO3_STS_MASK 0x02 +#define GPIO3_STS_SHIFT 1 +#define GPIO3_SET_MASK 0x01 +#define GPIO3_SET_SHIFT 0 + +/* GPIO 4 Register Definitions */ +#define GPIO4_SLEEP_MASK 0x80 +#define GPIO4_SLEEP_SHIFT 7 +#define GPIO4_SEL_MASK 0x40 +#define GPIO4_SEL_SHIFT 6 +#define GPIO4_ODEN_MASK 0x20 +#define GPIO4_ODEN_SHIFT 5 +#define GPIO4_DEB_MASK 0x10 +#define GPIO4_DEB_SHIFT 4 +#define GPIO4_PDEN_MASK 0x08 +#define GPIO4_PDEN_SHIFT 3 +#define GPIO4_CFG_MASK 0x04 +#define GPIO4_CFG_SHIFT 2 +#define GPIO4_STS_MASK 0x02 +#define GPIO4_STS_SHIFT 1 +#define GPIO4_SET_MASK 0x01 +#define GPIO4_SET_SHIFT 0 + +/* Register THERM (0x80) register.RegisterDescription */ +#define THERM_THERM_HD_MASK 0x20 +#define THERM_THERM_HD_SHIFT 5 +#define THERM_THERM_TS_MASK 0x10 +#define THERM_THERM_TS_SHIFT 4 +#define THERM_THERM_HDSEL_MASK 0x0C +#define THERM_THERM_HDSEL_SHIFT 2 +#define THERM_RSVD1_MASK 0x02 +#define THERM_RSVD1_SHIFT 1 +#define THERM_THERM_STATE_MASK 0x01 +#define THERM_THERM_STATE_SHIFT 0 + +/* Register DCDCCTRL1 register.RegisterDescription */ +#define DCDCCTRL_VCON_ENABLE_MASK 0x80 +#define DCDCCTRL_VCON_ENABLE_SHIFT 7 +#define DCDCCTRL_VCON_RANGE1_MASK 0x40 +#define DCDCCTRL_VCON_RANGE1_SHIFT 6 +#define DCDCCTRL_VCON_RANGE0_MASK 0x20 +#define DCDCCTRL_VCON_RANGE0_SHIFT 5 +#define DCDCCTRL_TSTEP2_MASK 0x10 +#define DCDCCTRL_TSTEP2_SHIFT 4 +#define DCDCCTRL_TSTEP1_MASK 0x08 +#define DCDCCTRL_TSTEP1_SHIFT 3 +#define DCDCCTRL_TSTEP0_MASK 0x04 +#define DCDCCTRL_TSTEP0_SHIFT 2 +#define DCDCCTRL_DCDC1_MODE_MASK 0x02 +#define DCDCCTRL_DCDC1_MODE_SHIFT 1 + +/* Register DCDCCTRL2 and DCDCCTRL3 register.RegisterDescription */ +#define DCDCCTRL_TSTEP2_MASK 0x10 +#define DCDCCTRL_TSTEP2_SHIFT 4 +#define DCDCCTRL_TSTEP1_MASK 0x08 +#define DCDCCTRL_TSTEP1_SHIFT 3 +#define DCDCCTRL_TSTEP0_MASK 0x04 +#define DCDCCTRL_TSTEP0_SHIFT 2 +#define DCDCCTRL_DCDC_MODE_MASK 0x02 +#define DCDCCTRL_DCDC_MODE_SHIFT 1 +#define DCDCCTRL_RSVD0_MASK 0x01 +#define DCDCCTRL_RSVD0_SHIFT 0 + +/* Register DCDCCTRL4 register.RegisterDescription */ +#define DCDCCTRL_RAMP_TIME_MASK 0x01 +#define DCDCCTRL_RAMP_TIME_SHIFT 0 + +/* Register DCDCx_AVS */ +#define DCDC_AVS_ENABLE_MASK 0x80 +#define DCDC_AVS_ENABLE_SHIFT 7 +#define DCDC_AVS_ECO_MASK 0x40 +#define DCDC_AVS_ECO_SHIFT 6 + +/* Register DCDCx_LIMIT */ +#define DCDC_LIMIT_RANGE_MASK 0xC0 +#define DCDC_LIMIT_RANGE_SHIFT 6 +#define DCDC_LIMIT_MAX_SEL_MASK 0x3F +#define DCDC_LIMIT_MAX_SEL_SHIFT 0 + +/** + * struct tps65912_board + * Board platform dat may be used to initialize regulators. + */ +struct tps65912_board { + int is_dcdc1_avs; + int is_dcdc2_avs; + int is_dcdc3_avs; + int is_dcdc4_avs; + int irq; + int irq_base; + int gpio_base; + struct regulator_init_data *tps65912_pmic_init_data; +}; + +/** + * struct tps65912 - tps65912 sub-driver chip access routines + */ + +struct tps65912 { + struct device *dev; + /* for read/write acces */ + struct mutex io_mutex; + + /* For device IO interfaces: I2C or SPI */ + void *control_data; + + int (*read)(struct tps65912 *tps65912, u8 reg, int size, void *dest); + int (*write)(struct tps65912 *tps65912, u8 reg, int size, void *src); + + /* Client devices */ + struct tps65912_pmic *pmic; + + /* GPIO Handling */ + struct gpio_chip gpio; + + /* IRQ Handling */ + struct mutex irq_lock; + int chip_irq; + int irq_base; + int irq_num; + u32 irq_mask; +}; + +struct tps65912_platform_data { + int irq; + int irq_base; +}; + +unsigned int tps_chip(void); + +int tps65912_set_bits(struct tps65912 *tps65912, u8 reg, u8 mask); +int tps65912_clear_bits(struct tps65912 *tps65912, u8 reg, u8 mask); +int tps65912_reg_read(struct tps65912 *tps65912, u8 reg); +int tps65912_reg_write(struct tps65912 *tps65912, u8 reg, u8 val); +int tps65912_device_init(struct tps65912 *tps65912); +void tps65912_device_exit(struct tps65912 *tps65912); +int tps65912_irq_init(struct tps65912 *tps65912, int irq, + struct tps65912_platform_data *pdata); + +#endif /* __LINUX_MFD_TPS65912_H */ -- 2.34.1