|
@@ -506,3 +506,117 @@ static const __initdata struct i2c_init_data omap4_i2c_timing_data[] = {
|
|
|
.loadbits = 0x1,
|
|
|
.hsscll_38_4 = 11,
|
|
|
.hsscll_26 = 10,
|
|
|
+ .hsscll_19_2 = 9,
|
|
|
+ .hsscll_16_8 = 9,
|
|
|
+ .hsscll_12 = 8,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .load = 0,
|
|
|
+ .loadbits = 0x0,
|
|
|
+ .hsscll_38_4 = 12,
|
|
|
+ .hsscll_26 = 10,
|
|
|
+ .hsscll_19_2 = 9,
|
|
|
+ .hsscll_16_8 = 8,
|
|
|
+ .hsscll_12 = 8,
|
|
|
+ },
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * omap4_vc_i2c_timing_init - sets up board I2C timing parameters
|
|
|
+ * @voltdm: voltagedomain pointer to get data from
|
|
|
+ *
|
|
|
+ * Use PMIC + board supplied settings for calculating the total I2C
|
|
|
+ * channel capacitance and set the timing parameters based on this.
|
|
|
+ * Pre-calculated values are provided in data tables, as it is not
|
|
|
+ * too straightforward to calculate these runtime.
|
|
|
+ */
|
|
|
+static void __init omap4_vc_i2c_timing_init(struct voltagedomain *voltdm)
|
|
|
+{
|
|
|
+ u32 capacitance;
|
|
|
+ u32 val;
|
|
|
+ u16 hsscll;
|
|
|
+ const struct i2c_init_data *i2c_data;
|
|
|
+
|
|
|
+ if (!voltdm->pmic->i2c_high_speed) {
|
|
|
+ pr_warn("%s: only high speed supported!\n", __func__);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* PCB trace capacitance, 0.125pF / mm => mm / 8 */
|
|
|
+ capacitance = DIV_ROUND_UP(sr_i2c_pcb_length, 8);
|
|
|
+
|
|
|
+ /* OMAP pad capacitance */
|
|
|
+ capacitance += 4;
|
|
|
+
|
|
|
+ /* PMIC pad capacitance */
|
|
|
+ capacitance += voltdm->pmic->i2c_pad_load;
|
|
|
+
|
|
|
+ /* Search for capacitance match in the table */
|
|
|
+ i2c_data = omap4_i2c_timing_data;
|
|
|
+
|
|
|
+ while (i2c_data->load > capacitance)
|
|
|
+ i2c_data++;
|
|
|
+
|
|
|
+ /* Select proper values based on sysclk frequency */
|
|
|
+ switch (voltdm->sys_clk.rate) {
|
|
|
+ case 38400000:
|
|
|
+ hsscll = i2c_data->hsscll_38_4;
|
|
|
+ break;
|
|
|
+ case 26000000:
|
|
|
+ hsscll = i2c_data->hsscll_26;
|
|
|
+ break;
|
|
|
+ case 19200000:
|
|
|
+ hsscll = i2c_data->hsscll_19_2;
|
|
|
+ break;
|
|
|
+ case 16800000:
|
|
|
+ hsscll = i2c_data->hsscll_16_8;
|
|
|
+ break;
|
|
|
+ case 12000000:
|
|
|
+ hsscll = i2c_data->hsscll_12;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ pr_warn("%s: unsupported sysclk rate: %d!\n", __func__,
|
|
|
+ voltdm->sys_clk.rate);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Loadbits define pull setup for the I2C channels */
|
|
|
+ val = i2c_data->loadbits << 25 | i2c_data->loadbits << 29;
|
|
|
+
|
|
|
+ /* Write to SYSCTRL_PADCONF_WKUP_CTRL_I2C_2 to setup I2C pull */
|
|
|
+ __raw_writel(val, OMAP2_L4_IO_ADDRESS(OMAP4_CTRL_MODULE_PAD_WKUP +
|
|
|
+ OMAP4_CTRL_MODULE_PAD_WKUP_CONTROL_I2C_2));
|
|
|
+
|
|
|
+ /* HSSCLH can always be zero */
|
|
|
+ val = hsscll << OMAP4430_HSSCLL_SHIFT;
|
|
|
+ val |= (0x28 << OMAP4430_SCLL_SHIFT | 0x2c << OMAP4430_SCLH_SHIFT);
|
|
|
+
|
|
|
+ /* Write setup times to I2C config register */
|
|
|
+ voltdm->write(val, OMAP4_PRM_VC_CFG_I2C_CLK_OFFSET);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * omap_vc_i2c_init - initialize I2C interface to PMIC
|
|
|
+ * @voltdm: voltage domain containing VC data
|
|
|
+ *
|
|
|
+ * Use PMIC supplied settings 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 vdd_%s does not match other channels (%u).\n",
|