Commit 39c02572 authored by Marek Vasut's avatar Marek Vasut Committed by Wolfram Sang

i2c: imx: Implement errata ERR007805 or e7805 bus frequency limit

The i.MX8MP Mask Set Errata for Mask 1P33A, Rev. 2.0 has description of
errata ERR007805 as below. This errata is found on all MX8M{M,N,P,Q},
MX7{S,D}, MX6{UL{,L,Z},S{,LL,X},S,D,DL,Q,DP,QP} . MX7ULP, MX8Q, MX8X
are not affected. MX53 and older status is unknown, as the errata
first appears in MX6 errata sheets from 2016 and the latest errata
sheet for MX53 is from 2015. Older SoC errata sheets predate the
MX53 errata sheet. MX8ULP and MX9 status is unknown as the errata
sheet is not available yet.

"
ERR007805 I2C: When the I2C clock speed is configured for 400 kHz,
the SCL low period violates the I2C spec of 1.3 uS min

Description: When the I2C module is programmed to operate at the
maximum clock speed of 400 kHz (as defined by the I2C spec), the SCL
clock low period violates the I2C spec of 1.3 uS min. The user must
reduce the clock speed to obtain the SCL low time to meet the 1.3us
I2C minimum required. This behavior means the SoC is not compliant
to the I2C spec at 400kHz.

Workaround: To meet the clock low period requirement in fast speed
mode, SCL must be configured to 384KHz or less.
"

Implement the workaround by matching on the affected SoC specific
compatible strings and by limiting the maximum bus frequency in case
the SoC is affected.
Signed-off-by: default avatarMarek Vasut <marex@denx.de>
To: linux-i2c@vger.kernel.org
Acked-by: default avatarOleksij Rempel <o.rempel@pengutronix.de>
Signed-off-by: default avatarWolfram Sang <wsa@kernel.org>
parent bd8963e6
...@@ -179,6 +179,12 @@ struct imx_i2c_hwdata { ...@@ -179,6 +179,12 @@ struct imx_i2c_hwdata {
unsigned int ndivs; unsigned int ndivs;
unsigned int i2sr_clr_opcode; unsigned int i2sr_clr_opcode;
unsigned int i2cr_ien_opcode; unsigned int i2cr_ien_opcode;
/*
* Errata ERR007805 or e7805:
* I2C: When the I2C clock speed is configured for 400 kHz,
* the SCL low period violates the I2C spec of 1.3 uS min.
*/
bool has_err007805;
}; };
struct imx_i2c_dma { struct imx_i2c_dma {
...@@ -240,6 +246,16 @@ static const struct imx_i2c_hwdata imx21_i2c_hwdata = { ...@@ -240,6 +246,16 @@ static const struct imx_i2c_hwdata imx21_i2c_hwdata = {
}; };
static const struct imx_i2c_hwdata imx6_i2c_hwdata = {
.devtype = IMX21_I2C,
.regshift = IMX_I2C_REGSHIFT,
.clk_div = imx_i2c_clk_div,
.ndivs = ARRAY_SIZE(imx_i2c_clk_div),
.i2sr_clr_opcode = I2SR_CLR_OPCODE_W0C,
.i2cr_ien_opcode = I2CR_IEN_OPCODE_1,
.has_err007805 = true,
};
static struct imx_i2c_hwdata vf610_i2c_hwdata = { static struct imx_i2c_hwdata vf610_i2c_hwdata = {
.devtype = VF610_I2C, .devtype = VF610_I2C,
.regshift = VF610_I2C_REGSHIFT, .regshift = VF610_I2C_REGSHIFT,
...@@ -266,6 +282,16 @@ MODULE_DEVICE_TABLE(platform, imx_i2c_devtype); ...@@ -266,6 +282,16 @@ MODULE_DEVICE_TABLE(platform, imx_i2c_devtype);
static const struct of_device_id i2c_imx_dt_ids[] = { static const struct of_device_id i2c_imx_dt_ids[] = {
{ .compatible = "fsl,imx1-i2c", .data = &imx1_i2c_hwdata, }, { .compatible = "fsl,imx1-i2c", .data = &imx1_i2c_hwdata, },
{ .compatible = "fsl,imx21-i2c", .data = &imx21_i2c_hwdata, }, { .compatible = "fsl,imx21-i2c", .data = &imx21_i2c_hwdata, },
{ .compatible = "fsl,imx6q-i2c", .data = &imx6_i2c_hwdata, },
{ .compatible = "fsl,imx6sl-i2c", .data = &imx6_i2c_hwdata, },
{ .compatible = "fsl,imx6sll-i2c", .data = &imx6_i2c_hwdata, },
{ .compatible = "fsl,imx6sx-i2c", .data = &imx6_i2c_hwdata, },
{ .compatible = "fsl,imx6ul-i2c", .data = &imx6_i2c_hwdata, },
{ .compatible = "fsl,imx7s-i2c", .data = &imx6_i2c_hwdata, },
{ .compatible = "fsl,imx8mm-i2c", .data = &imx6_i2c_hwdata, },
{ .compatible = "fsl,imx8mn-i2c", .data = &imx6_i2c_hwdata, },
{ .compatible = "fsl,imx8mp-i2c", .data = &imx6_i2c_hwdata, },
{ .compatible = "fsl,imx8mq-i2c", .data = &imx6_i2c_hwdata, },
{ .compatible = "fsl,vf610-i2c", .data = &vf610_i2c_hwdata, }, { .compatible = "fsl,vf610-i2c", .data = &vf610_i2c_hwdata, },
{ /* sentinel */ } { /* sentinel */ }
}; };
...@@ -551,6 +577,13 @@ static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx, ...@@ -551,6 +577,13 @@ static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
unsigned int div; unsigned int div;
int i; int i;
if (i2c_imx->hwdata->has_err007805 && i2c_imx->bitrate > 384000) {
dev_dbg(&i2c_imx->adapter.dev,
"SoC errata ERR007805 or e7805 applies, bus frequency limited from %d Hz to 384000 Hz.\n",
i2c_imx->bitrate);
i2c_imx->bitrate = 384000;
}
/* Divider value calculation */ /* Divider value calculation */
if (i2c_imx->cur_clk == i2c_clk_rate) if (i2c_imx->cur_clk == i2c_clk_rate)
return; return;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment