From mboxrd@z Thu Jan 1 00:00:00 1970 From: nm@ti.com (Nishanth Menon) Date: Fri, 4 May 2012 17:00:48 -0500 Subject: [PATCH 3/3] ARM: OMAP2+ PM: Add support for TPS62361 In-Reply-To: <1336139842-845-4-git-send-email-t-kristo@ti.com> References: <1336139842-845-1-git-send-email-t-kristo@ti.com> <1336139842-845-4-git-send-email-t-kristo@ti.com> Message-ID: <20120504220046.GA20795@senorita.am.dhcp.ti.com> To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org On 16:57-20120504, Tero Kristo wrote: > From: Vishwanath BS > > TPS62361 is a new PMIC used with OMAP4460 on SDP4430 platform > and panda board ES to supply MPU VDD. > Rest of the VDDs continue to be supplied via TWL6030. > > As part of this, the following have been moved to common > location in voltage.h > OMAP4_VP_CONFIG_ERROROFFSET, OMAP4_VP_VSTEPMIN_VSTEPMIN, > OMAP4_VP_VSTEPMAX_VSTEPMAX, OMAP4_VP_VLIMITTO_TIMEOUT_US > > [nm at ti.com: cleaned up TPS to handle board variations] > Signed-off-by: Nishanth Menon > Signed-off-by: Vishwanath BS > [t-kristo at ti.com: minor cleanup, added panda board support] > Signed-off-by: Tero Kristo > --- > arch/arm/mach-omap2/Kconfig | 9 ++ > arch/arm/mach-omap2/Makefile | 1 + > arch/arm/mach-omap2/board-4430sdp.c | 10 ++ > arch/arm/mach-omap2/board-omap4panda.c | 8 + > arch/arm/mach-omap2/omap_tps6236x.c | 247 ++++++++++++++++++++++++++++++++ > arch/arm/mach-omap2/omap_twl.c | 5 - > arch/arm/mach-omap2/twl-common.c | 1 + > arch/arm/mach-omap2/twl-common.h | 16 ++ > arch/arm/mach-omap2/voltage.h | 5 + > 9 files changed, 297 insertions(+), 5 deletions(-) > create mode 100644 arch/arm/mach-omap2/omap_tps6236x.c > > diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig > index 8141b76..a147f00 100644 > --- a/arch/arm/mach-omap2/Kconfig > +++ b/arch/arm/mach-omap2/Kconfig > @@ -334,6 +334,7 @@ config MACH_OMAP_4430SDP > select OMAP_PACKAGE_CBL > select OMAP_PACKAGE_CBS > select REGULATOR_FIXED_VOLTAGE if REGULATOR > + select OMAP_TPS6236X > > config MACH_OMAP4_PANDA > bool "OMAP4 Panda Board" > @@ -342,6 +343,7 @@ config MACH_OMAP4_PANDA > select OMAP_PACKAGE_CBL > select OMAP_PACKAGE_CBS > select REGULATOR_FIXED_VOLTAGE if REGULATOR > + select OMAP_TPS6236X > > config OMAP3_EMU > bool "OMAP3 debugging peripherals" > @@ -384,6 +386,13 @@ config OMAP4_ERRATA_I688 > In MPU case, L3 T2ASYNC FIFO and DDR T2ASYNC FIFO needs to be drained. > IO barrier ensure that there is no synchronisation loss on initiators > operating on both interconnect port simultaneously. > + > +config OMAP_TPS6236X > + bool "OMAP4 support for TPS6236X power IC" > + help > + TPS62361 is a PMIC used with OMAP4460 to supply MPU VDD voltage. > + Rest of the VDDs continue to be supplied via TWL6030. > + > endmenu > > endif > diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile > index 49f92bc..58861a2 100644 > --- a/arch/arm/mach-omap2/Makefile > +++ b/arch/arm/mach-omap2/Makefile > @@ -22,6 +22,7 @@ obj-y += mcbsp.o > endif > > 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 a39fc4b..58fbf64 100644 > --- a/arch/arm/mach-omap2/board-4430sdp.c > +++ b/arch/arm/mach-omap2/board-4430sdp.c > @@ -63,6 +63,8 @@ > #define GPIO_WIFI_PMENA 54 > #define GPIO_WIFI_IRQ 53 > > +#define TPS62361_GPIO 7 > + > static const int sdp4430_keymap[] = { > KEY(0, 0, KEY_E), > KEY(0, 1, KEY_R), > @@ -958,6 +960,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); > + } > } > > MACHINE_START(OMAP_4430SDP, "OMAP4430 4430SDP board") > diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c > index d8c0e89..5b5a6bc 100644 > --- a/arch/arm/mach-omap2/board-omap4panda.c > +++ b/arch/arm/mach-omap2/board-omap4panda.c > @@ -55,6 +55,7 @@ > #define HDMI_GPIO_CT_CP_HPD 60 /* HPD mode enable/disable */ > #define HDMI_GPIO_LS_OE 41 /* Level shifter for HDMI */ > #define HDMI_GPIO_HPD 63 /* Hotplug detect */ > +#define TPS62361_GPIO 7 /* Vsel0 control for TPS62361 */ > > /* wl127x BT, FM, GPS connectivity chip */ > static int wl1271_gpios[] = {46, -1, -1}; > @@ -572,6 +573,13 @@ static void __init omap4_panda_init(void) > omap4_ehci_init(); > usb_musb_init(&musb_board_data); > omap4_panda_display_init(); > + if (cpu_is_omap446x()) { > + /* vsel0 = gpio, vsel1 = gnd */ > + ret = omap_tps6236x_board_setup(true, TPS62361_GPIO, -1, > + OMAP_PIN_OFF_OUTPUT_HIGH, -1); > + if (ret) > + pr_err("TPS62361 initialization failed: %d\n", ret); > + } > } > > MACHINE_START(OMAP4_PANDA, "OMAP4 Panda board") > diff --git a/arch/arm/mach-omap2/omap_tps6236x.c b/arch/arm/mach-omap2/omap_tps6236x.c > new file mode 100644 > index 0000000..84b07c2 > --- /dev/null > +++ b/arch/arm/mach-omap2/omap_tps6236x.c > @@ -0,0 +1,247 @@ > +/* > + * 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 > +#include > +#include > +#include > + > +#include "pm.h" > +#include "vc.h" > +#include "mux.h" > +#include "twl-common.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) These should be used appropriately. we have reg defines without usage. suggestion is - please port over the changes from the original source as well as there are configurations of thermal shutdown, and other configurations that are necessary as well. > + > +/* TWL usage */ > +#define TWL6030_REG_SYSEN_CFG_GRP 0xB3 > +#define TWL6030_BIT_APE_GRP BIT(0) You dont really need 6030 defines here in tps file now do you? > + > +/* 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); I think a better mechanism to choose the pull should be used IMHO. > + *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; We dont need to set OFF_OUTPUT on OMAP4 as these are automatically latched when going to OFF. > + > + 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; note below > + > + 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; > +} > + > +static unsigned long tps6236x_vsel_to_uv(const u8 vsel); > +static u8 tps6236x_uv_to_vsel(unsigned long uv); > + > +static struct omap_voltdm_pmic omap4_mpu_pmic = { > + .slew_rate = 8000, without programing the slew rate, it is a bad idea to use the default here considering we can go to 32mV/uSec by programing the register > + .step_size = STEP_SIZE_TPS6236X, > + .startup_time = 1000, > + .shutdown_time = 1, > + .vddmin = MIN_VOLTAGE_TPS62361_UV, > + .vddmax = MAX_VOLTAGE_TPS62361_UV, > + .volt_setup_time = 0, > + .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, > + .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, > + .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, > + .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, > + .vsel_to_uv = tps6236x_vsel_to_uv, > + .uv_to_vsel = tps6236x_uv_to_vsel, > +}; > + > +static unsigned long tps6236x_vsel_to_uv(const u8 vsel) > +{ > + return omap4_mpu_pmic.vddmin + > + (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 > omap4_mpu_pmic.vddmax) { > + pr_err("%s:Request for overvoltage[%ld] than supported[%u]\n", > + __func__, uv, omap4_mpu_pmic.vddmax); > + uv = omap4_mpu_pmic.vddmax; > + } > + if (uv < omap4_mpu_pmic.vddmin) { > + pr_err("%s:Request for undervoltage[%ld] than supported[%u]\n", > + __func__, uv, omap4_mpu_pmic.vddmin); > + uv = omap4_mpu_pmic.vddmin; > + } > + return DIV_ROUND_UP(uv - omap4_mpu_pmic.vddmin, STEP_SIZE_TPS6236X) | > + VOLTAGE_PFM_MODE_VAL; > +} > + > +static __initdata struct omap_pmic_map omap_tps_map[] = { > + { > + .name = "mpu", > + .cpu = PMIC_CPU_OMAP4460, > + .pmic_data = &omap4_mpu_pmic, > + }, > + /* 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); it is a better idea not to reuse the same old variable as the meaning changes at this point from pointing@OFF state config. the variable no longer contains the pull param passed as input as it has been modified by _bd_setup > + > + if (!use_62361) { > + omap4_mpu_pmic.vddmin = MIN_VOLTAGE_TPS62360_62_UV; > + omap4_mpu_pmic.vddmax = 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 c8e418e..fef14df 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/twl-common.c b/arch/arm/mach-omap2/twl-common.c > index 2588e04..ec802d8 100644 > --- a/arch/arm/mach-omap2/twl-common.c > +++ b/arch/arm/mach-omap2/twl-common.c > @@ -78,6 +78,7 @@ void __init omap_pmic_late_init(void) > return; > > omap_twl_init(); > + omap_tps6236x_init(); > } > > #if defined(CONFIG_ARCH_OMAP3) > diff --git a/arch/arm/mach-omap2/twl-common.h b/arch/arm/mach-omap2/twl-common.h > index 2f805a3..0655efc 100644 > --- a/arch/arm/mach-omap2/twl-common.h > +++ b/arch/arm/mach-omap2/twl-common.h > @@ -86,4 +86,20 @@ struct omap_pmic_map { > extern int omap_pmic_register_data(struct omap_pmic_map *map); > extern void omap_pmic_data_init(void); > > +#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 makes no sense to have this in twl-common.h - this is a different PMIC. This standard is not scalable if I need to define a new set of PMICs to use. > + > #endif /* __OMAP_PMIC_COMMON__ */ > diff --git a/arch/arm/mach-omap2/voltage.h b/arch/arm/mach-omap2/voltage.h > index 54b959c..ac68a0e 100644 > --- a/arch/arm/mach-omap2/voltage.h > +++ b/arch/arm/mach-omap2/voltage.h > @@ -138,6 +138,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) One more point to consider is that with this - we *should* disable VCORE3 and VMEM else we can have weird behavior such as those seen by pandaboard-ES early adopters. -- Regards, Nishanth Menon