diff options
-rw-r--r-- | arch/arm/mach-omap2/Kconfig | 4 | ||||
-rw-r--r-- | arch/arm/mach-omap2/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-omap2/board-4430sdp.c | 11 | ||||
-rw-r--r-- | arch/arm/mach-omap2/omap_pmic.c | 1 | ||||
-rw-r--r-- | arch/arm/mach-omap2/omap_tps6236x.c | 340 | ||||
-rw-r--r-- | arch/arm/mach-omap2/omap_twl.c | 5 | ||||
-rw-r--r-- | arch/arm/mach-omap2/pm.h | 17 | ||||
-rw-r--r-- | arch/arm/mach-omap2/voltage.h | 5 |
8 files changed, 379 insertions, 5 deletions
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 19d5891..3602a13 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -314,6 +314,7 @@ config MACH_OMAP_4430SDP select OMAP_PACKAGE_CBL select OMAP_PACKAGE_CBS select REGULATOR_FIXED_VOLTAGE + select OMAP_TPS6236X config MACH_OMAP4_PANDA bool "OMAP4 Panda Board" @@ -342,6 +343,9 @@ config OMAP3_SDRC_AC_TIMING wish to say no. Selecting yes without understanding what is going on could result in system crashes; +config OMAP_TPS6236X + bool + endmenu endif diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 66a6b6d0..d950fd0 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_ARCH_OMAP4) += prm44xx.o $(hwmod-common) obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o obj-$(CONFIG_TWL4030_CORE) += omap_twl.o +obj-$(CONFIG_OMAP_TPS6236X) += omap_tps6236x.o # SMP support ONLY available for OMAP4 obj-$(CONFIG_SMP) += omap-smp.o omap-headsmp.o diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index 63de2d3..3ed043c 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -43,6 +43,7 @@ #include "timer-gp.h" #include "control.h" #include "common-board-devices.h" +#include "pm.h" #define ETH_KS8851_IRQ 34 #define ETH_KS8851_POWER_ON 48 @@ -52,6 +53,8 @@ #define HDMI_GPIO_HPD 60 /* Hot plug pin for HDMI */ #define HDMI_GPIO_LS_OE 41 /* Level shifter for HDMI */ +#define TPS62361_GPIO 7 + static const int sdp4430_keymap[] = { KEY(0, 0, KEY_E), KEY(0, 1, KEY_R), @@ -757,6 +760,14 @@ static void __init omap_4430sdp_init(void) pr_err("Keypad initialization failed: %d\n", status); omap_4430sdp_display_init(); + + if (cpu_is_omap446x()) { + /* Vsel0 = gpio, vsel1 = gnd */ + status = omap_tps6236x_board_setup(true, TPS62361_GPIO, -1, + OMAP_PIN_OFF_OUTPUT_HIGH, -1); + if (status) + pr_err("TPS62361 initialization failed: %d\n", status); + } } static void __init omap_4430sdp_map_io(void) diff --git a/arch/arm/mach-omap2/omap_pmic.c b/arch/arm/mach-omap2/omap_pmic.c index c11003c..ddf1b9d 100644 --- a/arch/arm/mach-omap2/omap_pmic.c +++ b/arch/arm/mach-omap2/omap_pmic.c @@ -22,6 +22,7 @@ void __init omap_pmic_data_init(void) { omap_twl_init(); + omap_tps6236x_init(); } /** diff --git a/arch/arm/mach-omap2/omap_tps6236x.c b/arch/arm/mach-omap2/omap_tps6236x.c new file mode 100644 index 0000000..9d49c2b --- /dev/null +++ b/arch/arm/mach-omap2/omap_tps6236x.c @@ -0,0 +1,340 @@ +/* + * OMAP and TPS6236x specific initialization + * + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ + * Vishwanath BS + * Nishanth Menon + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/gpio.h> +#include <linux/i2c/twl.h> + +#include "pm.h" +#include "vc.h" +#include "mux.h" + +/* Voltage limits supported */ +#define MIN_VOLTAGE_TPS62360_62_UV 770000 +#define MAX_VOLTAGE_TPS62360_62_UV 1400000 + +#define MIN_VOLTAGE_TPS62361_UV 500000 +#define MAX_VOLTAGE_TPS62361_UV 1770000 + +#define MAX_VOLTAGE_RAMP_TPS6236X_UV 32000 + +/* + * This is the voltage delta between 2 values in voltage register. + * when switching voltage V1 to V2, TPS62361 can ramp up or down + * initially with step sizes of 20mV with a last step of 10mV. + * In the case of TPS6236[0|2], it is a constant 10mV steps + * we choose the 10mV step for linearity when SR is configured. + */ +#define STEP_SIZE_TPS6236X 10000 + +/* I2C access parameters */ +#define I2C_TPS6236X_SLAVE_ADDR 0x60 + +#define DEF_SET_REG(VSEL0, VSEL1) (((VSEL1) << 1| (VSEL0) << 0) & 0x3) +#define REG_TPS6236X_SET_0 0x00 +#define REG_TPS6236X_SET_1 0x01 +#define REG_TPS6236X_SET_2 0x02 +#define REG_TPS6236X_SET_3 0x03 +#define REG_TPS6236X_CTRL 0x04 +#define REG_TPS6236X_TEMP 0x05 +#define REG_TPS6236X_RAMP_CTRL 0x06 +#define REG_TPS6236X_CHIP_ID0 0x08 +#define REG_TPS6236X_CHIP_ID1 0x09 + +#define MODE_TPS6236X_AUTO_PFM_PWM 0x00 +#define MODE_TPS6236X_FORCE_PWM BIT(7) + +/* We use Auto PFM/PWM mode currently seems to have the best trade off */ +#define VOLTAGE_PFM_MODE_VAL MODE_TPS6236X_AUTO_PFM_PWM + +#define REG_TPS6236X_RAMP_CTRL_RMP_MASK (0x7 << 5) +#define REG_TPS6236X_RAMP_CTRL_EN_DISC BIT(2) +#define REG_TPS6236X_RAMP_CTRL_RAMP_PFM BIT(1) + +#define REG_TPS6236X_CTRL_PD_EN BIT(7) +#define REG_TPS6236X_CTRL_PD_VSEL0 BIT(6) +#define REG_TPS6236X_CTRL_PD_VSEL1 BIT(5) + +/* TWL usage */ +#define TWL6030_REG_SYSEN_CFG_GRP 0xB3 +#define TWL6030_BIT_APE_GRP BIT(0) + +/* Voltage params of the attached device (all in uV) */ +static unsigned long voltage_min; +static unsigned long voltage_max; + +/* Which register do we use by default? */ +static int __initdata default_reg = -1;; + +/* Do we need to setup internal pullups? */ +static int __initdata pd_vsel0 = -1; +static int __initdata pd_vsel1 = -1; + +static int __init _bd_setup(char *name,int gpio_vsel, int *pull, int *pd_vsel) +{ + int pull_dir; + int r; + + if (gpio_vsel == -1) { + if (*pull != -1) { + *pd_vsel = (*pull == OMAP_PIN_OFF_OUTPUT_HIGH); + *pull = *pd_vsel; + } else { + *pull = 0; + } + return 0; + } + + /* if we have a pull gpio, with bad dir, pull low */ + if (*pull == -1 || (*pull != OMAP_PIN_OFF_OUTPUT_HIGH && + *pull != OMAP_PIN_OFF_OUTPUT_LOW)) + *pull = OMAP_PIN_OFF_OUTPUT_LOW; + + r = omap_mux_init_gpio(gpio_vsel, *pull); + if (r) { + pr_err("%s: unable to mux gpio%d=%d\n", __func__, + gpio_vsel, r); + goto out; + } + + pull_dir = (*pull == OMAP_PIN_OFF_OUTPUT_HIGH); + *pull = pull_dir; + + r = gpio_request(gpio_vsel, name); + if (r) { + pr_err("%s: unable to req gpio%d=%d\n", __func__, + gpio_vsel, r); + goto out; + } + r = gpio_direction_output(gpio_vsel, pull_dir); + if (r) { + pr_err("%s: unable to pull[%d] gpio%d=%d\n", __func__, + gpio_vsel, pull_dir, r); + gpio_free(gpio_vsel); + goto out; + } +out: + return r; +} + +/* Convert the ramp voltage to ramp value. */ +static u8 __init tps6236x_ramp_value(unsigned long uv) +{ + if (!uv) + return 0; + + if (uv > MAX_VOLTAGE_RAMP_TPS6236X_UV) { + pr_err("%s: uv%ld greater than max %d\n", __func__, + uv, MAX_VOLTAGE_RAMP_TPS6236X_UV); + uv = MAX_VOLTAGE_RAMP_TPS6236X_UV; + } + return fls(MAX_VOLTAGE_RAMP_TPS6236X_UV / uv) - 1; +} + +static unsigned long tps6236x_vsel_to_uv(const u8 vsel) +{ + return (voltage_min + + (STEP_SIZE_TPS6236X * (vsel & ~VOLTAGE_PFM_MODE_VAL))); +} + +static u8 tps6236x_uv_to_vsel(unsigned long uv) +{ + if (!uv) + return 0; + + /* Round off requests to limits */ + if (uv > voltage_max) { + pr_err("%s:Request for overvoltage[%ld] than supported[%ld]\n", + __func__, uv, voltage_max); + uv = voltage_max; + } + if (uv < voltage_min) { + pr_err("%s:Request for undervoltage[%ld] than supported[%ld]\n", + __func__, uv, voltage_min); + uv = voltage_min; + } + return DIV_ROUND_UP(uv - voltage_min, STEP_SIZE_TPS6236X) | + VOLTAGE_PFM_MODE_VAL; +} + +static struct omap_voltdm_pmic omap4_mpu_pmic = { + .slew_rate = 8000, + .step_size = STEP_SIZE_TPS6236X, + .on_volt = 1375000, + .onlp_volt = 1375000, + .ret_volt = 830000, + .off_volt = 0, + .volt_setup_time = 0, + .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, + .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, + .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, + .vp_vddmin = OMAP4_VP_MPU_VLIMITTO_VDDMIN, + .vp_vddmax = OMAP4_VP_MPU_VLIMITTO_VDDMAX, + .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, + .i2c_slave_addr = I2C_TPS6236X_SLAVE_ADDR, + .volt_reg_addr = REG_TPS6236X_SET_0, + .cmd_reg_addr = REG_TPS6236X_SET_0, + .i2c_high_speed = true, + .i2c_scll_low = 0x28, + .i2c_scll_high = 0x2C, + .i2c_hscll_low = 0x0B, + .i2c_hscll_high = 0x00, + .vsel_to_uv = tps6236x_vsel_to_uv, + .uv_to_vsel = tps6236x_uv_to_vsel, +}; + +/** + * omap4_twl_tps62361_enable() - Enable tps chip + * + * This function enables TPS chip by associating SYSEN signal + * to APE resource group of TWL6030. + * + * Returns 0 on sucess, error is returned if I2C read/write fails. + */ +static int __init omap4_twl_tps62361_enable(struct voltagedomain *voltdm) +{ + int ret = 0; + u8 val; + + /* Dont trust the bootloader. start with max, pm will set to proper */ + val = voltdm->pmic->uv_to_vsel(voltdm->pmic->vp_vddmax); + ret = omap_vc_bypass_send_i2c_msg(voltdm, voltdm->pmic->i2c_slave_addr, + default_reg, val); + + /* Setup Ramp */ + val = tps6236x_ramp_value(voltdm->pmic->slew_rate) << + __ffs(REG_TPS6236X_RAMP_CTRL_RMP_MASK); + val &= REG_TPS6236X_RAMP_CTRL_RMP_MASK; + + /* We would like to ramp the voltage asap */ + val |= REG_TPS6236X_RAMP_CTRL_RAMP_PFM; + + ret = omap_vc_bypass_send_i2c_msg(voltdm, voltdm->pmic->i2c_slave_addr, + REG_TPS6236X_RAMP_CTRL, val); + if (ret) + goto out; + + /* Setup the internal pulls to select if needed */ + if (pd_vsel0 != -1 || pd_vsel1 != -1) { + val = REG_TPS6236X_CTRL_PD_EN; + val |= (pd_vsel0) ? 0 : REG_TPS6236X_CTRL_PD_VSEL0; + val |= (pd_vsel1) ? 0 : REG_TPS6236X_CTRL_PD_VSEL1; + ret = omap_vc_bypass_send_i2c_msg(voltdm, + voltdm->pmic->i2c_slave_addr, + REG_TPS6236X_CTRL, val); + if (ret) + goto out; + } + + /* Enable thermal shutdown - 0 is enable :) */ + ret = omap_vc_bypass_send_i2c_msg(voltdm, + voltdm->pmic->i2c_slave_addr, + REG_TPS6236X_TEMP, 0x0); + if (ret) + goto out; + + /* if we have to work with TWL */ +#ifdef CONFIG_TWL4030_CORE + ret = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &val, + TWL6030_REG_SYSEN_CFG_GRP); + if (ret) + goto out; + + val |= TWL6030_BIT_APE_GRP; + ret = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, val, + TWL6030_REG_SYSEN_CFG_GRP); +#endif + +out: + if (ret) + pr_err("%s: Error enabling TPS(%d)\n", __func__, ret); + + return ret; +} + +static __initdata struct omap_pmic_map omap_tps_map[] = { + { + .name = "mpu", + .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP446X), + .pmic_data = &omap4_mpu_pmic, + .special_action = omap4_twl_tps62361_enable, + }, + /* Terminator */ + { .name = NULL,.pmic_data = NULL}, +}; + +int __init omap_tps6236x_init(void) +{ + struct omap_pmic_map *map; + + /* Without registers, I wont proceed */ + if (default_reg == -1) + return -EINVAL; + + map = omap_tps_map; + + /* setup all the pmic's voltage addresses to the default one */ + while (map->name) { + map->pmic_data->volt_reg_addr = default_reg; + map->pmic_data->cmd_reg_addr = default_reg; + map++; + } + + return omap_pmic_register_data(omap_tps_map); +} + +/** + * omap_tps6236x_board_setup() - provide the board config for TPS connect + * @use_62361: Do we use TPS62361 variant? + * @gpio_vsel0: If using GPIO to control VSEL0, provide gpio number, else -1 + * @gpio_vsel1: If using GPIO to control VSEL1, provide gpio number, else -1 + * @pull0: If using GPIO, provide mux mode OMAP_PIN_OFF_OUTPUT_[HIGH|LOW] + * else provide any internal pull required, -1 if unused. + * @pull1: If using GPIO, provide mux mode OMAP_PIN_OFF_OUTPUT_[HIGH|LOW] + * else provide any internal pull required, -1 if unused. + * + * TPS6236x variants of PMIC can be hooked in numerous combinations on to the + * board. Some platforms can choose to hardwire and save on a GPIO for other + * uses, while others may hook a single line for GPIO control and may ground + * the other line. support these configurations. + * + * WARNING: for platforms using GPIO, be careful to provide MUX setting + * considering OFF mode configuration as well. + */ +int __init omap_tps6236x_board_setup(bool use_62361, int gpio_vsel0, + int gpio_vsel1, int pull0, int pull1) +{ + int r; + + r = _bd_setup("tps6236x_vsel0", gpio_vsel0, &pull0, &pd_vsel0); + if (r) + goto out; + r = _bd_setup("tps6236x_vsel1", gpio_vsel1, &pull1, &pd_vsel1); + if (r) { + if (gpio_vsel0 != -1) + gpio_free(gpio_vsel0); + goto out; + } + + default_reg = ((pull1 & 0x1) << 1) | (pull0 & 0x1); + + if (use_62361) { + voltage_min = MIN_VOLTAGE_TPS62361_UV; + voltage_max = MAX_VOLTAGE_TPS62361_UV; + } else { + voltage_min = MIN_VOLTAGE_TPS62360_62_UV; + voltage_max = MAX_VOLTAGE_TPS62360_62_UV; + } +out: + return r; +} diff --git a/arch/arm/mach-omap2/omap_twl.c b/arch/arm/mach-omap2/omap_twl.c index 50bc705..0e30412 100644 --- a/arch/arm/mach-omap2/omap_twl.c +++ b/arch/arm/mach-omap2/omap_twl.c @@ -38,11 +38,6 @@ #define OMAP4_VDD_CORE_SR_VOLT_REG 0x61 #define OMAP4_VDD_CORE_SR_CMD_REG 0x62 -#define OMAP4_VP_CONFIG_ERROROFFSET 0x00 -#define OMAP4_VP_VSTEPMIN_VSTEPMIN 0x01 -#define OMAP4_VP_VSTEPMAX_VSTEPMAX 0x04 -#define OMAP4_VP_VLIMITTO_TIMEOUT_US 200 - static bool is_offset_valid; static u8 smps_offset; /* diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index 7f4fe9a..3894c3b 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.h @@ -163,4 +163,21 @@ static inline int omap_twl_init(void) } #endif +#ifdef CONFIG_OMAP_TPS6236X +extern int omap_tps6236x_board_setup(bool use_62361, int gpio_vsel0, + int gpio_vsel1, int pull0, int pull1); +extern int omap_tps6236x_init(void); + +#else +static inline int omap_tps6236x_board_setup(bool use_62361, int gpio_vsel0, + int gpio_vsel1, int pull0, int pull1) +{ + return -EINVAL; +} +static inline int omap_tps6236x_init(void) +{ + return -EINVAL; +} +#endif + #endif diff --git a/arch/arm/mach-omap2/voltage.h b/arch/arm/mach-omap2/voltage.h index da2ce55..fb5acdc 100644 --- a/arch/arm/mach-omap2/voltage.h +++ b/arch/arm/mach-omap2/voltage.h @@ -137,6 +137,11 @@ struct omap_volt_data { #define OMAP4_VP_CORE_VLIMITTO_VDDMIN 830000 #define OMAP4_VP_CORE_VLIMITTO_VDDMAX 1200000 +#define OMAP4_VP_CONFIG_ERROROFFSET 0x00 +#define OMAP4_VP_VSTEPMIN_VSTEPMIN 0x01 +#define OMAP4_VP_VSTEPMAX_VSTEPMAX 0x04 +#define OMAP4_VP_VLIMITTO_TIMEOUT_US 200 + /** * struct omap_voltdm_pmic - PMIC specific data required by voltage driver. * @slew_rate: PMIC slew rate (in uv/us) |