Commit 00bd228ea9f7aad23f7933fa62a13d975d4b213a

Authored by Tero Kristo
Committed by Kevin Hilman
1 parent 2ceec7b25c

ARM: OMAP4: VC: setup I2C parameters based on board data

VC code now provides a table of pre-calculated I2C setup parameters,
which will be used based on the capacitance value calculated for the I2C
trace on the PCB. A default trace length of 6.3cm is used unless board
defines its own value during init. The parameters set will be the I2C
internal pull setup and the I2C timing parameters for high speed use
mode. Full speed mode is not supported as of now.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
Signed-off-by: Kevin Hilman <khilman@ti.com>

Showing 4 changed files with 147 additions and 8 deletions Side-by-side Diff

arch/arm/mach-omap2/omap_twl.c
... ... @@ -183,6 +183,7 @@
183 183 .volt_reg_addr = OMAP4_VDD_MPU_SR_VOLT_REG,
184 184 .cmd_reg_addr = OMAP4_VDD_MPU_SR_CMD_REG,
185 185 .i2c_high_speed = true,
  186 + .i2c_pad_load = 3,
186 187 .vsel_to_uv = twl6030_vsel_to_uv,
187 188 .uv_to_vsel = twl6030_uv_to_vsel,
188 189 };
... ... @@ -200,6 +201,7 @@
200 201 .volt_reg_addr = OMAP4_VDD_IVA_SR_VOLT_REG,
201 202 .cmd_reg_addr = OMAP4_VDD_IVA_SR_CMD_REG,
202 203 .i2c_high_speed = true,
  204 + .i2c_pad_load = 3,
203 205 .vsel_to_uv = twl6030_vsel_to_uv,
204 206 .uv_to_vsel = twl6030_uv_to_vsel,
205 207 };
... ... @@ -216,6 +218,7 @@
216 218 .i2c_slave_addr = OMAP4_SRI2C_SLAVE_ADDR,
217 219 .volt_reg_addr = OMAP4_VDD_CORE_SR_VOLT_REG,
218 220 .cmd_reg_addr = OMAP4_VDD_CORE_SR_CMD_REG,
  221 + .i2c_pad_load = 3,
219 222 .vsel_to_uv = twl6030_vsel_to_uv,
220 223 .uv_to_vsel = twl6030_uv_to_vsel,
221 224 };
arch/arm/mach-omap2/pm.h
... ... @@ -132,9 +132,11 @@
132 132 #ifdef CONFIG_PM
133 133 extern void omap_pm_setup_oscillator(u32 tstart, u32 tshut);
134 134 extern void omap_pm_get_oscillator(u32 *tstart, u32 *tshut);
  135 +extern void omap_pm_setup_sr_i2c_pcb_length(u32 mm);
135 136 #else
136 137 static inline void omap_pm_setup_oscillator(u32 tstart, u32 tshut) { }
137 138 static inline void omap_pm_get_oscillator(u32 *tstart, u32 *tshut) { }
  139 +static inline void omap_pm_setup_sr_i2c_pcb_length(u32 mm) { }
138 140 #endif
139 141  
140 142 #endif
arch/arm/mach-omap2/vc.c
... ... @@ -24,6 +24,7 @@
24 24 #include "prm44xx.h"
25 25 #include "pm.h"
26 26 #include "scrm44xx.h"
  27 +#include "control.h"
27 28  
28 29 /**
29 30 * struct omap_vc_channel_cfg - describe the cfg_channel bitfield
... ... @@ -69,6 +70,9 @@
69 70 };
70 71  
71 72 static struct omap_vc_channel_cfg *vc_cfg_bits;
  73 +
  74 +/* Default I2C trace length on pcb, 6.3cm. Used for capacitance calculations. */
  75 +static u32 sr_i2c_pcb_length = 63;
72 76 #define CFG_CHANNEL_MASK 0x1f
73 77  
74 78 /**
75 79  
76 80  
77 81  
78 82  
79 83  
80 84  
... ... @@ -464,22 +468,135 @@
464 468 /* OMAP4 specific voltage init functions */
465 469 static void __init omap4_vc_init_channel(struct voltagedomain *voltdm)
466 470 {
467   - static bool is_initialized;
468   - u32 vc_val;
469   -
470 471 omap4_set_timings(voltdm, true);
471 472 omap4_set_timings(voltdm, false);
  473 +}
472 474  
473   - if (is_initialized)
  475 +struct i2c_init_data {
  476 + u8 loadbits;
  477 + u8 load;
  478 + u8 hsscll_38_4;
  479 + u8 hsscll_26;
  480 + u8 hsscll_19_2;
  481 + u8 hsscll_16_8;
  482 + u8 hsscll_12;
  483 +};
  484 +
  485 +static const __initdata struct i2c_init_data omap4_i2c_timing_data[] = {
  486 + {
  487 + .load = 50,
  488 + .loadbits = 0x3,
  489 + .hsscll_38_4 = 13,
  490 + .hsscll_26 = 11,
  491 + .hsscll_19_2 = 9,
  492 + .hsscll_16_8 = 9,
  493 + .hsscll_12 = 8,
  494 + },
  495 + {
  496 + .load = 25,
  497 + .loadbits = 0x2,
  498 + .hsscll_38_4 = 13,
  499 + .hsscll_26 = 11,
  500 + .hsscll_19_2 = 9,
  501 + .hsscll_16_8 = 9,
  502 + .hsscll_12 = 8,
  503 + },
  504 + {
  505 + .load = 12,
  506 + .loadbits = 0x1,
  507 + .hsscll_38_4 = 11,
  508 + .hsscll_26 = 10,
  509 + .hsscll_19_2 = 9,
  510 + .hsscll_16_8 = 9,
  511 + .hsscll_12 = 8,
  512 + },
  513 + {
  514 + .load = 0,
  515 + .loadbits = 0x0,
  516 + .hsscll_38_4 = 12,
  517 + .hsscll_26 = 10,
  518 + .hsscll_19_2 = 9,
  519 + .hsscll_16_8 = 8,
  520 + .hsscll_12 = 8,
  521 + },
  522 +};
  523 +
  524 +/**
  525 + * omap4_vc_i2c_timing_init - sets up board I2C timing parameters
  526 + * @voltdm: voltagedomain pointer to get data from
  527 + *
  528 + * Use PMIC + board supplied settings for calculating the total I2C
  529 + * channel capacitance and set the timing parameters based on this.
  530 + * Pre-calculated values are provided in data tables, as it is not
  531 + * too straightforward to calculate these runtime.
  532 + */
  533 +static void __init omap4_vc_i2c_timing_init(struct voltagedomain *voltdm)
  534 +{
  535 + u32 capacitance;
  536 + u32 val;
  537 + u16 hsscll;
  538 + const struct i2c_init_data *i2c_data;
  539 +
  540 + if (!voltdm->pmic->i2c_high_speed) {
  541 + pr_warn("%s: only high speed supported!\n", __func__);
474 542 return;
  543 + }
475 544  
476   - /* XXX These are magic numbers and do not belong! */
477   - vc_val = (0x60 << OMAP4430_SCLL_SHIFT | 0x26 << OMAP4430_SCLH_SHIFT);
478   - voltdm->write(vc_val, OMAP4_PRM_VC_CFG_I2C_CLK_OFFSET);
  545 + /* PCB trace capacitance, 0.125pF / mm => mm / 8 */
  546 + capacitance = DIV_ROUND_UP(sr_i2c_pcb_length, 8);
479 547  
480   - is_initialized = true;
  548 + /* OMAP pad capacitance */
  549 + capacitance += 4;
  550 +
  551 + /* PMIC pad capacitance */
  552 + capacitance += voltdm->pmic->i2c_pad_load;
  553 +
  554 + /* Search for capacitance match in the table */
  555 + i2c_data = omap4_i2c_timing_data;
  556 +
  557 + while (i2c_data->load > capacitance)
  558 + i2c_data++;
  559 +
  560 + /* Select proper values based on sysclk frequency */
  561 + switch (voltdm->sys_clk.rate) {
  562 + case 38400000:
  563 + hsscll = i2c_data->hsscll_38_4;
  564 + break;
  565 + case 26000000:
  566 + hsscll = i2c_data->hsscll_26;
  567 + break;
  568 + case 19200000:
  569 + hsscll = i2c_data->hsscll_19_2;
  570 + break;
  571 + case 16800000:
  572 + hsscll = i2c_data->hsscll_16_8;
  573 + break;
  574 + case 12000000:
  575 + hsscll = i2c_data->hsscll_12;
  576 + break;
  577 + default:
  578 + pr_warn("%s: unsupported sysclk rate: %d!\n", __func__,
  579 + voltdm->sys_clk.rate);
  580 + return;
  581 + }
  582 +
  583 + /* Loadbits define pull setup for the I2C channels */
  584 + val = i2c_data->loadbits << 25 | i2c_data->loadbits << 29;
  585 +
  586 + /* Write to SYSCTRL_PADCONF_WKUP_CTRL_I2C_2 to setup I2C pull */
  587 + __raw_writel(val, OMAP2_L4_IO_ADDRESS(OMAP4_CTRL_MODULE_PAD_WKUP +
  588 + OMAP4_CTRL_MODULE_PAD_WKUP_CONTROL_I2C_2));
  589 +
  590 + /* HSSCLH can always be zero */
  591 + val = hsscll << OMAP4430_HSSCLL_SHIFT;
  592 + val |= (0x28 << OMAP4430_SCLL_SHIFT | 0x2c << OMAP4430_SCLH_SHIFT);
  593 +
  594 + /* Write setup times to I2C config register */
  595 + voltdm->write(val, OMAP4_PRM_VC_CFG_I2C_CLK_OFFSET);
481 596 }
482 597  
  598 +
  599 +
483 600 /**
484 601 * omap_vc_i2c_init - initialize I2C interface to PMIC
485 602 * @voltdm: voltage domain containing VC data
... ... @@ -519,6 +636,9 @@
519 636 mcode << __ffs(vc->common->i2c_mcode_mask),
520 637 vc->common->i2c_cfg_reg);
521 638  
  639 + if (cpu_is_omap44xx())
  640 + omap4_vc_i2c_timing_init(voltdm);
  641 +
522 642 initialized = true;
523 643 }
524 644  
... ... @@ -544,6 +664,19 @@
544 664 }
545 665  
546 666 return voltdm->pmic->uv_to_vsel(uvolt);
  667 +}
  668 +
  669 +/**
  670 + * omap_pm_setup_sr_i2c_pcb_length - set length of SR I2C traces on PCB
  671 + * @mm: length of the PCB trace in millimetres
  672 + *
  673 + * Sets the PCB trace length for the I2C channel. By default uses 63mm.
  674 + * This is needed for properly calculating the capacitance value for
  675 + * the PCB trace, and for setting the SR I2C channel timing parameters.
  676 + */
  677 +void __init omap_pm_setup_sr_i2c_pcb_length(u32 mm)
  678 +{
  679 + sr_i2c_pcb_length = mm;
547 680 }
548 681  
549 682 void __init omap_vc_init_channel(struct voltagedomain *voltdm)
arch/arm/mach-omap2/voltage.h
... ... @@ -139,6 +139,7 @@
139 139 u32 vddmax;
140 140 u8 vp_timeout_us;
141 141 bool i2c_high_speed;
  142 + u32 i2c_pad_load;
142 143 u8 i2c_mcode;
143 144 unsigned long (*vsel_to_uv) (const u8 vsel);
144 145 u8 (*uv_to_vsel) (unsigned long uV);