drm: bridge: dw-hdmi: set ddc scl clock rate according to dts

To set dw hdmi i2c bus adapter scl clock rate, we introduce two device
tree parameter, ddc-i2c-scl-high-time-ns and ddc-i2c-scl-low-time-ns.

ddc-i2c-scl-high-time-ns: how many ns SCL hold high
ddc-i2c-scl-low-time-ns: how many ns SCL hold low

After measurement, 50KHz scl clock rate recommended configuration is:

&hdmi {
	ddc-i2c-scl-high-time-ns = <9625>;
	ddc-i2c-scl-low-time-ns = <10000>;
};

100KHz recommended configuration is:
&hdmi {
        ddc-i2c-scl-high-time-ns = <4708>;
        ddc-i2c-scl-low-time-ns = <4916>;
};

If dts parameter is not available, the default scl rate is 100KHz.

Change-Id: I6f6b0bf1694ab59e70da789ead99e15a53c93e4d
Signed-off-by: Zheng Yang <zhengyang@rock-chips.com>
This commit is contained in:
Zheng Yang
2017-03-28 18:28:16 +08:00
committed by Huang, Tao
parent eee051ca31
commit a0b524450b

View File

@@ -176,6 +176,9 @@ struct dw_hdmi_i2c {
u8 slave_reg;
bool is_regaddr;
bool is_segment;
unsigned int scl_high_ns;
unsigned int scl_low_ns;
};
struct dw_hdmi {
@@ -281,6 +284,49 @@ static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u8 data, unsigned int reg,
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 */
@@ -302,6 +348,8 @@ static void dw_hdmi_i2c_init(struct dw_hdmi *hdmi)
/* 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,
@@ -2401,6 +2449,16 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
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);