u8 slave_reg;
bool is_regaddr;
bool is_segment;
+
+ unsigned int scl_high_ns;
+ unsigned int scl_low_ns;
};
struct dw_hdmi {
hdmi_modb(hdmi, data << shift, mask, reg);
}
+static void dw_hdmi_i2c_set_divs(struct dw_hdmi *hdmi)
+{
+ unsigned long clk_rate_khz;
+ unsigned long low_ns, high_ns;
+ unsigned long div_low, div_high;
+
+ /* Standard-mode */
+ if (hdmi->i2c->scl_high_ns < 4000)
+ high_ns = 4708;
+ else
+ high_ns = hdmi->i2c->scl_high_ns;
+
+ if (hdmi->i2c->scl_low_ns < 4700)
+ low_ns = 4916;
+ else
+ low_ns = hdmi->i2c->scl_low_ns;
+
+ /* Adjust to avoid overflow */
+ clk_rate_khz = DIV_ROUND_UP(clk_get_rate(hdmi->isfr_clk), 1000);
+
+ div_low = (clk_rate_khz * low_ns) / 1000000;
+ if ((clk_rate_khz * low_ns) % 1000000)
+ div_low++;
+
+ div_high = (clk_rate_khz * high_ns) / 1000000;
+ if ((clk_rate_khz * high_ns) % 1000000)
+ div_high++;
+
+ /* Maximum divider supported by hw is 0xffff */
+ if (div_low > 0xffff)
+ div_low = 0xffff;
+
+ if (div_high > 0xffff)
+ div_high = 0xffff;
+
+ hdmi_writeb(hdmi, div_high & 0xff, HDMI_I2CM_SS_SCL_HCNT_0_ADDR);
+ hdmi_writeb(hdmi, (div_high >> 8) & 0xff,
+ HDMI_I2CM_SS_SCL_HCNT_1_ADDR);
+ hdmi_writeb(hdmi, div_low & 0xff, HDMI_I2CM_SS_SCL_LCNT_0_ADDR);
+ hdmi_writeb(hdmi, (div_low >> 8) & 0xff,
+ HDMI_I2CM_SS_SCL_LCNT_1_ADDR);
+}
+
static void dw_hdmi_i2c_init(struct dw_hdmi *hdmi)
{
/* Software reset */
/* Mute DONE and ERROR interrupts */
hdmi_writeb(hdmi, HDMI_IH_I2CM_STAT0_ERROR | HDMI_IH_I2CM_STAT0_DONE,
HDMI_IH_MUTE_I2CM_STAT0);
+
+ dw_hdmi_i2c_set_divs(hdmi);
}
static int dw_hdmi_i2c_read(struct dw_hdmi *hdmi,
hdmi->ddc = dw_hdmi_i2c_adapter(hdmi);
if (IS_ERR(hdmi->ddc))
hdmi->ddc = NULL;
+ /*
+ * Read high and low time from device tree. If not available use
+ * the default timing scl clock rate is about 99.6KHz.
+ */
+ if (of_property_read_u32(np, "ddc-i2c-scl-high-time-ns",
+ &hdmi->i2c->scl_high_ns))
+ hdmi->i2c->scl_high_ns = 4708;
+ if (of_property_read_u32(np, "ddc-i2c-scl-low-time-ns",
+ &hdmi->i2c->scl_low_ns))
+ hdmi->i2c->scl_low_ns = 4916;
}
hdmi->regs = devm_ioremap_resource(dev, iores);