From f5395480f5088a86cc8594d29b5c2f07f6995c3d Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Wed, 30 Mar 2011 16:36:30 -0700 Subject: OMAP3+: VC: make I2C config programmable with PMIC-specific settings Remove hard-coded I2C configuration in favor of settings that can be configured from PMIC-specific values. Currently only high-speed mode and the master-code value are supported, since they were the only fields currently used, but extending this is now trivial. Thanks to Nishanth Menon for reporting/fixing a sparse problem and making omap_vc_i2c_init() static, as well as finding and fixing a problem with the shift/mask of mcode. Signed-off-by: Kevin Hilman --- arch/arm/mach-omap2/omap_twl.c | 4 +++ arch/arm/mach-omap2/vc.c | 51 +++++++++++++++++++++++++++++++++------ arch/arm/mach-omap2/vc.h | 8 ++++++ arch/arm/mach-omap2/vc3xxx_data.c | 3 +++ arch/arm/mach-omap2/vc44xx_data.c | 3 +++ arch/arm/mach-omap2/voltage.h | 4 +++ 6 files changed, 66 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-omap2/omap_twl.c b/arch/arm/mach-omap2/omap_twl.c index e467d45..6b247d1 100644 --- a/arch/arm/mach-omap2/omap_twl.c +++ b/arch/arm/mach-omap2/omap_twl.c @@ -159,6 +159,7 @@ static struct omap_voltdm_pmic omap3_mpu_pmic = { .vp_timeout_us = OMAP3_VP_VLIMITTO_TIMEOUT_US, .i2c_slave_addr = OMAP3_SRI2C_SLAVE_ADDR, .volt_reg_addr = OMAP3_VDD_MPU_SR_CONTROL_REG, + .i2c_high_speed = true, .vsel_to_uv = twl4030_vsel_to_uv, .uv_to_vsel = twl4030_uv_to_vsel, }; @@ -179,6 +180,7 @@ static struct omap_voltdm_pmic omap3_core_pmic = { .vp_timeout_us = OMAP3_VP_VLIMITTO_TIMEOUT_US, .i2c_slave_addr = OMAP3_SRI2C_SLAVE_ADDR, .volt_reg_addr = OMAP3_VDD_CORE_SR_CONTROL_REG, + .i2c_high_speed = true, .vsel_to_uv = twl4030_vsel_to_uv, .uv_to_vsel = twl4030_uv_to_vsel, }; @@ -199,6 +201,7 @@ static struct omap_voltdm_pmic omap4_mpu_pmic = { .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, .i2c_slave_addr = OMAP4_SRI2C_SLAVE_ADDR, .volt_reg_addr = OMAP4_VDD_MPU_SR_VOLT_REG, + .i2c_high_speed = true, .vsel_to_uv = twl6030_vsel_to_uv, .uv_to_vsel = twl6030_uv_to_vsel, }; @@ -219,6 +222,7 @@ static struct omap_voltdm_pmic omap4_iva_pmic = { .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, .i2c_slave_addr = OMAP4_SRI2C_SLAVE_ADDR, .volt_reg_addr = OMAP4_VDD_IVA_SR_VOLT_REG, + .i2c_high_speed = true, .vsel_to_uv = twl6030_vsel_to_uv, .uv_to_vsel = twl6030_uv_to_vsel, }; diff --git a/arch/arm/mach-omap2/vc.c b/arch/arm/mach-omap2/vc.c index 4ac7614..5d54563 100644 --- a/arch/arm/mach-omap2/vc.c +++ b/arch/arm/mach-omap2/vc.c @@ -208,13 +208,6 @@ static void __init omap3_vc_init_channel(struct voltagedomain *voltdm) if (is_initialized) return; - /* - * Generic VC parameters init - * XXX This data should be abstracted out - */ - voltdm->write(OMAP3430_MCODE_SHIFT | OMAP3430_HSEN_MASK, - OMAP3_PRM_VC_I2C_CFG_OFFSET); - omap3_vfsm_init(voltdm); is_initialized = true; @@ -237,6 +230,48 @@ static void __init omap4_vc_init_channel(struct voltagedomain *voltdm) is_initialized = true; } +/** + * omap_vc_i2c_init - initialize I2C interface to PMIC + * @voltdm: voltage domain containing VC data + * + * Use PMIC supplied seetings for I2C high-speed mode and + * master code (if set) and program the VC I2C configuration + * register. + * + * The VC I2C configuration is common to all VC channels, + * so this function only configures I2C for the first VC + * channel registers. All other VC channels will use the + * same configuration. + */ +static void __init omap_vc_i2c_init(struct voltagedomain *voltdm) +{ + struct omap_vc_channel *vc = voltdm->vc; + static bool initialized; + static bool i2c_high_speed; + u8 mcode; + + if (initialized) { + if (voltdm->pmic->i2c_high_speed != i2c_high_speed) + pr_warn("%s: I2C config for all channels must match.", + __func__); + return; + } + + i2c_high_speed = voltdm->pmic->i2c_high_speed; + if (i2c_high_speed) + voltdm->rmw(vc->common->i2c_cfg_hsen_mask, + vc->common->i2c_cfg_hsen_mask, + vc->common->i2c_cfg_reg); + + mcode = voltdm->pmic->i2c_mcode; + if (mcode) + voltdm->rmw(vc->common->i2c_mcode_mask, + mcode << __ffs(vc->common->i2c_mcode_mask), + vc->common->i2c_cfg_reg); + + initialized = true; +} + void __init omap_vc_init_channel(struct voltagedomain *voltdm) { struct omap_vc_channel *vc = voltdm->vc; @@ -305,6 +340,8 @@ void __init omap_vc_init_channel(struct voltagedomain *voltdm) vc->setup_time << __ffs(voltdm->vfsm->voltsetup_mask), voltdm->vfsm->voltsetup_reg); + omap_vc_i2c_init(voltdm); + if (cpu_is_omap34xx()) omap3_vc_init_channel(voltdm); else if (cpu_is_omap44xx()) diff --git a/arch/arm/mach-omap2/vc.h b/arch/arm/mach-omap2/vc.h index fd38528..c863013 100644 --- a/arch/arm/mach-omap2/vc.h +++ b/arch/arm/mach-omap2/vc.h @@ -37,6 +37,9 @@ struct voltagedomain; * @cmd_ret_shift: RET field shift in PRM_VC_CMD_VAL_* register * @cmd_off_shift: OFF field shift in PRM_VC_CMD_VAL_* register * @cfg_channel_reg: VC channel configuration register + * @i2c_cfg_reg: I2C configuration register offset + * @i2c_cfg_hsen_mask: high-speed mode bit field mask in I2C config register + * @i2c_mcode_mask: MCODE field mask for I2C config register * * XXX One of cmd_on_mask and cmd_on_shift are not needed * XXX VALID should probably be a shift, not a mask @@ -56,6 +59,9 @@ struct omap_vc_common { u8 cmd_ret_shift; u8 cmd_off_shift; u8 cfg_channel_reg; + u8 i2c_cfg_reg; + u8 i2c_cfg_hsen_mask; + u8 i2c_mcode_mask; }; /* omap_vc_channel.flags values */ @@ -68,6 +74,7 @@ struct omap_vc_common { * @cmd_reg_addr: command configuration register address * @setup_time: setup time (in sys_clk cycles) of regulator for this channel * @cfg_channel: current value of VC channel configuration register + * @i2c_high_speed: whether or not to use I2C high-speed mode * * @common: pointer to VC common data for this platform * @smps_sa_mask: i2c slave address bitmask in the PRM_VC_SMPS_SA register @@ -84,6 +91,7 @@ struct omap_vc_channel { u16 cmd_reg_addr; u16 setup_time; u8 cfg_channel; + bool i2c_high_speed; /* register access data */ const struct omap_vc_common *common; diff --git a/arch/arm/mach-omap2/vc3xxx_data.c b/arch/arm/mach-omap2/vc3xxx_data.c index f4449eb..95d7701 100644 --- a/arch/arm/mach-omap2/vc3xxx_data.c +++ b/arch/arm/mach-omap2/vc3xxx_data.c @@ -44,6 +44,9 @@ static struct omap_vc_common omap3_vc_common = { .cmd_ret_shift = OMAP3430_VC_CMD_RET_SHIFT, .cmd_off_shift = OMAP3430_VC_CMD_OFF_SHIFT, .cfg_channel_reg = OMAP3_PRM_VC_CH_CONF_OFFSET, + .i2c_cfg_hsen_mask = OMAP3430_HSEN_MASK, + .i2c_cfg_reg = OMAP3_PRM_VC_I2C_CFG_OFFSET, + .i2c_mcode_mask = OMAP3430_MCODE_MASK, }; struct omap_vc_channel omap3_vc_mpu = { diff --git a/arch/arm/mach-omap2/vc44xx_data.c b/arch/arm/mach-omap2/vc44xx_data.c index 1610bde..148be18 100644 --- a/arch/arm/mach-omap2/vc44xx_data.c +++ b/arch/arm/mach-omap2/vc44xx_data.c @@ -45,6 +45,9 @@ static const struct omap_vc_common omap4_vc_common = { .cmd_ret_shift = OMAP4430_RET_SHIFT, .cmd_off_shift = OMAP4430_OFF_SHIFT, .cfg_channel_reg = OMAP4_PRM_VC_CFG_CHANNEL_OFFSET, + .i2c_cfg_reg = OMAP4_PRM_VC_CFG_I2C_MODE_OFFSET, + .i2c_cfg_hsen_mask = OMAP4430_HSMODEEN_MASK, + .i2c_mcode_mask = OMAP4430_HSMCODE_MASK, }; /* VC instance data for each controllable voltage line */ diff --git a/arch/arm/mach-omap2/voltage.h b/arch/arm/mach-omap2/voltage.h index 43ee7bf..a36d2cf 100644 --- a/arch/arm/mach-omap2/voltage.h +++ b/arch/arm/mach-omap2/voltage.h @@ -103,6 +103,8 @@ struct omap_volt_data { * @i2c_slave_addr: I2C slave address of PMIC * @volt_reg_addr: voltage configuration register address * @cmd_reg_addr: command (on, on-LP, ret, off) configuration register address + * @i2c_high_speed: whether VC uses I2C high-speed mode to PMIC + * @i2c_mcode: master code value for I2C high-speed preamble transmission * @vsel_to_uv: PMIC API to convert vsel value to actual voltage in uV. * @uv_to_vsel: PMIC API to convert voltage in uV to vsel value. */ @@ -123,6 +125,8 @@ struct omap_voltdm_pmic { u8 vp_vddmin; u8 vp_vddmax; u8 vp_timeout_us; + bool i2c_high_speed; + u8 i2c_mcode; unsigned long (*vsel_to_uv) (const u8 vsel); u8 (*uv_to_vsel) (unsigned long uV); }; -- cgit v1.1