Commit f5395480f5088a86cc8594d29b5c2f07f6995c3d

Authored by Kevin Hilman
1 parent ce8ebe0dfb

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 <nm@ti.com> 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 <khilman@ti.com>

Showing 6 changed files with 66 additions and 7 deletions Side-by-side Diff

arch/arm/mach-omap2/omap_twl.c
... ... @@ -159,6 +159,7 @@
159 159 .vp_timeout_us = OMAP3_VP_VLIMITTO_TIMEOUT_US,
160 160 .i2c_slave_addr = OMAP3_SRI2C_SLAVE_ADDR,
161 161 .volt_reg_addr = OMAP3_VDD_MPU_SR_CONTROL_REG,
  162 + .i2c_high_speed = true,
162 163 .vsel_to_uv = twl4030_vsel_to_uv,
163 164 .uv_to_vsel = twl4030_uv_to_vsel,
164 165 };
... ... @@ -179,6 +180,7 @@
179 180 .vp_timeout_us = OMAP3_VP_VLIMITTO_TIMEOUT_US,
180 181 .i2c_slave_addr = OMAP3_SRI2C_SLAVE_ADDR,
181 182 .volt_reg_addr = OMAP3_VDD_CORE_SR_CONTROL_REG,
  183 + .i2c_high_speed = true,
182 184 .vsel_to_uv = twl4030_vsel_to_uv,
183 185 .uv_to_vsel = twl4030_uv_to_vsel,
184 186 };
... ... @@ -199,6 +201,7 @@
199 201 .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US,
200 202 .i2c_slave_addr = OMAP4_SRI2C_SLAVE_ADDR,
201 203 .volt_reg_addr = OMAP4_VDD_MPU_SR_VOLT_REG,
  204 + .i2c_high_speed = true,
202 205 .vsel_to_uv = twl6030_vsel_to_uv,
203 206 .uv_to_vsel = twl6030_uv_to_vsel,
204 207 };
... ... @@ -219,6 +222,7 @@
219 222 .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US,
220 223 .i2c_slave_addr = OMAP4_SRI2C_SLAVE_ADDR,
221 224 .volt_reg_addr = OMAP4_VDD_IVA_SR_VOLT_REG,
  225 + .i2c_high_speed = true,
222 226 .vsel_to_uv = twl6030_vsel_to_uv,
223 227 .uv_to_vsel = twl6030_uv_to_vsel,
224 228 };
arch/arm/mach-omap2/vc.c
... ... @@ -208,13 +208,6 @@
208 208 if (is_initialized)
209 209 return;
210 210  
211   - /*
212   - * Generic VC parameters init
213   - * XXX This data should be abstracted out
214   - */
215   - voltdm->write(OMAP3430_MCODE_SHIFT | OMAP3430_HSEN_MASK,
216   - OMAP3_PRM_VC_I2C_CFG_OFFSET);
217   -
218 211 omap3_vfsm_init(voltdm);
219 212  
220 213 is_initialized = true;
... ... @@ -237,6 +230,48 @@
237 230 is_initialized = true;
238 231 }
239 232  
  233 +/**
  234 + * omap_vc_i2c_init - initialize I2C interface to PMIC
  235 + * @voltdm: voltage domain containing VC data
  236 + *
  237 + * Use PMIC supplied seetings for I2C high-speed mode and
  238 + * master code (if set) and program the VC I2C configuration
  239 + * register.
  240 + *
  241 + * The VC I2C configuration is common to all VC channels,
  242 + * so this function only configures I2C for the first VC
  243 + * channel registers. All other VC channels will use the
  244 + * same configuration.
  245 + */
  246 +static void __init omap_vc_i2c_init(struct voltagedomain *voltdm)
  247 +{
  248 + struct omap_vc_channel *vc = voltdm->vc;
  249 + static bool initialized;
  250 + static bool i2c_high_speed;
  251 + u8 mcode;
  252 +
  253 + if (initialized) {
  254 + if (voltdm->pmic->i2c_high_speed != i2c_high_speed)
  255 + pr_warn("%s: I2C config for all channels must match.",
  256 + __func__);
  257 + return;
  258 + }
  259 +
  260 + i2c_high_speed = voltdm->pmic->i2c_high_speed;
  261 + if (i2c_high_speed)
  262 + voltdm->rmw(vc->common->i2c_cfg_hsen_mask,
  263 + vc->common->i2c_cfg_hsen_mask,
  264 + vc->common->i2c_cfg_reg);
  265 +
  266 + mcode = voltdm->pmic->i2c_mcode;
  267 + if (mcode)
  268 + voltdm->rmw(vc->common->i2c_mcode_mask,
  269 + mcode << __ffs(vc->common->i2c_mcode_mask),
  270 + vc->common->i2c_cfg_reg);
  271 +
  272 + initialized = true;
  273 +}
  274 +
240 275 void __init omap_vc_init_channel(struct voltagedomain *voltdm)
241 276 {
242 277 struct omap_vc_channel *vc = voltdm->vc;
... ... @@ -304,6 +339,8 @@
304 339 voltdm->rmw(voltdm->vfsm->voltsetup_mask,
305 340 vc->setup_time << __ffs(voltdm->vfsm->voltsetup_mask),
306 341 voltdm->vfsm->voltsetup_reg);
  342 +
  343 + omap_vc_i2c_init(voltdm);
307 344  
308 345 if (cpu_is_omap34xx())
309 346 omap3_vc_init_channel(voltdm);
arch/arm/mach-omap2/vc.h
... ... @@ -37,6 +37,9 @@
37 37 * @cmd_ret_shift: RET field shift in PRM_VC_CMD_VAL_* register
38 38 * @cmd_off_shift: OFF field shift in PRM_VC_CMD_VAL_* register
39 39 * @cfg_channel_reg: VC channel configuration register
  40 + * @i2c_cfg_reg: I2C configuration register offset
  41 + * @i2c_cfg_hsen_mask: high-speed mode bit field mask in I2C config register
  42 + * @i2c_mcode_mask: MCODE field mask for I2C config register
40 43 *
41 44 * XXX One of cmd_on_mask and cmd_on_shift are not needed
42 45 * XXX VALID should probably be a shift, not a mask
... ... @@ -56,6 +59,9 @@
56 59 u8 cmd_ret_shift;
57 60 u8 cmd_off_shift;
58 61 u8 cfg_channel_reg;
  62 + u8 i2c_cfg_reg;
  63 + u8 i2c_cfg_hsen_mask;
  64 + u8 i2c_mcode_mask;
59 65 };
60 66  
61 67 /* omap_vc_channel.flags values */
... ... @@ -68,6 +74,7 @@
68 74 * @cmd_reg_addr: command configuration register address
69 75 * @setup_time: setup time (in sys_clk cycles) of regulator for this channel
70 76 * @cfg_channel: current value of VC channel configuration register
  77 + * @i2c_high_speed: whether or not to use I2C high-speed mode
71 78 *
72 79 * @common: pointer to VC common data for this platform
73 80 * @smps_sa_mask: i2c slave address bitmask in the PRM_VC_SMPS_SA register
... ... @@ -84,6 +91,7 @@
84 91 u16 cmd_reg_addr;
85 92 u16 setup_time;
86 93 u8 cfg_channel;
  94 + bool i2c_high_speed;
87 95  
88 96 /* register access data */
89 97 const struct omap_vc_common *common;
arch/arm/mach-omap2/vc3xxx_data.c
... ... @@ -44,6 +44,9 @@
44 44 .cmd_ret_shift = OMAP3430_VC_CMD_RET_SHIFT,
45 45 .cmd_off_shift = OMAP3430_VC_CMD_OFF_SHIFT,
46 46 .cfg_channel_reg = OMAP3_PRM_VC_CH_CONF_OFFSET,
  47 + .i2c_cfg_hsen_mask = OMAP3430_HSEN_MASK,
  48 + .i2c_cfg_reg = OMAP3_PRM_VC_I2C_CFG_OFFSET,
  49 + .i2c_mcode_mask = OMAP3430_MCODE_MASK,
47 50 };
48 51  
49 52 struct omap_vc_channel omap3_vc_mpu = {
arch/arm/mach-omap2/vc44xx_data.c
... ... @@ -45,6 +45,9 @@
45 45 .cmd_ret_shift = OMAP4430_RET_SHIFT,
46 46 .cmd_off_shift = OMAP4430_OFF_SHIFT,
47 47 .cfg_channel_reg = OMAP4_PRM_VC_CFG_CHANNEL_OFFSET,
  48 + .i2c_cfg_reg = OMAP4_PRM_VC_CFG_I2C_MODE_OFFSET,
  49 + .i2c_cfg_hsen_mask = OMAP4430_HSMODEEN_MASK,
  50 + .i2c_mcode_mask = OMAP4430_HSMCODE_MASK,
48 51 };
49 52  
50 53 /* VC instance data for each controllable voltage line */
arch/arm/mach-omap2/voltage.h
... ... @@ -103,6 +103,8 @@
103 103 * @i2c_slave_addr: I2C slave address of PMIC
104 104 * @volt_reg_addr: voltage configuration register address
105 105 * @cmd_reg_addr: command (on, on-LP, ret, off) configuration register address
  106 + * @i2c_high_speed: whether VC uses I2C high-speed mode to PMIC
  107 + * @i2c_mcode: master code value for I2C high-speed preamble transmission
106 108 * @vsel_to_uv: PMIC API to convert vsel value to actual voltage in uV.
107 109 * @uv_to_vsel: PMIC API to convert voltage in uV to vsel value.
108 110 */
... ... @@ -123,6 +125,8 @@
123 125 u8 vp_vddmin;
124 126 u8 vp_vddmax;
125 127 u8 vp_timeout_us;
  128 + bool i2c_high_speed;
  129 + u8 i2c_mcode;
126 130 unsigned long (*vsel_to_uv) (const u8 vsel);
127 131 u8 (*uv_to_vsel) (unsigned long uV);
128 132 };