Skip to content
Snippets Groups Projects
Commit 080f4e14 authored by Gianfranco Mariotti's avatar Gianfranco Mariotti
Browse files

[i.MX] i2c: Implement errata ERR007805 bus frequency limit

Workaround for NXP chip errata 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"
This errata is found on the following SoCs:
* MX8M{M,N,P,Q}
* MX7{S,D}
* MX6{UL{,L,Z},S{,LL,X},S,D,DL,Q,DP,QP}

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.

REFERENCE: https://lore.kernel.org/linux-arm-kernel/YlngkTlsJ8M1gB3z@shikoro/T/
parent 8b49e4aa
No related branches found
No related tags found
1 merge request!117[i.MX] i2c: Implement errata ERR007805 bus frequency limit
......@@ -217,7 +217,6 @@ enum imx_i2c_type {
IMX1_I2C,
IMX21_I2C,
VF610_I2C,
IMX7D_I2C,
};
struct imx_i2c_hwdata {
......@@ -227,6 +226,12 @@ struct imx_i2c_hwdata {
unsigned ndivs;
unsigned i2sr_clr_opcode;
unsigned 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 {
......@@ -278,7 +283,7 @@ static const struct imx_i2c_hwdata imx1_i2c_hwdata = {
.ndivs = ARRAY_SIZE(imx_i2c_clk_div),
.i2sr_clr_opcode = I2SR_CLR_OPCODE_W0C,
.i2cr_ien_opcode = I2CR_IEN_OPCODE_1,
.has_err007805 = false,
};
static const struct imx_i2c_hwdata imx21_i2c_hwdata = {
......@@ -288,7 +293,7 @@ static const struct imx_i2c_hwdata imx21_i2c_hwdata = {
.ndivs = ARRAY_SIZE(imx_i2c_clk_div),
.i2sr_clr_opcode = I2SR_CLR_OPCODE_W0C,
.i2cr_ien_opcode = I2CR_IEN_OPCODE_1,
.has_err007805 = false,
};
static struct imx_i2c_hwdata vf610_i2c_hwdata = {
......@@ -298,17 +303,17 @@ static struct imx_i2c_hwdata vf610_i2c_hwdata = {
.ndivs = ARRAY_SIZE(vf610_i2c_clk_div),
.i2sr_clr_opcode = I2SR_CLR_OPCODE_W1C,
.i2cr_ien_opcode = I2CR_IEN_OPCODE_0,
.has_err007805 = false,
};
static const struct imx_i2c_hwdata imx7d_i2c_hwdata = {
.devtype = IMX7D_I2C,
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 const struct platform_device_id imx_i2c_devtype[] = {
......@@ -328,7 +333,17 @@ static const struct of_device_id i2c_imx_dt_ids[] = {
{ .compatible = "fsl,imx1-i2c", .data = &imx1_i2c_hwdata, },
{ .compatible = "fsl,imx21-i2c", .data = &imx21_i2c_hwdata, },
{ .compatible = "fsl,vf610-i2c", .data = &vf610_i2c_hwdata, },
{ .compatible = "fsl,imx7d-i2c", .data = &imx7d_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,imx7d-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, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, i2c_imx_dt_ids);
......@@ -348,11 +363,6 @@ static inline int is_imx1_i2c(struct imx_i2c_struct *i2c_imx)
return i2c_imx->hwdata->devtype == IMX1_I2C;
}
static inline int is_imx7d_i2c(struct imx_i2c_struct *i2c_imx)
{
return i2c_imx->hwdata->devtype == IMX7D_I2C;
}
static inline void imx_i2c_write_reg(unsigned int val,
struct imx_i2c_struct *i2c_imx, unsigned int reg)
{
......@@ -620,6 +630,14 @@ static int i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
unsigned int div;
int i;
/* i.MX hardware issue: errata e7805 */
if (i2c_imx->hwdata->has_err007805 && i2c_imx->bitrate > IMX_I2C_MAX_E_BIT_RATE) {
dev_info(i2c_imx->adapter.dev.parent,
"SoC errata ERR007805 or e7805 applies, bus frequency limited from %d Hz to %d Hz.\n",
i2c_imx->bitrate, IMX_I2C_MAX_E_BIT_RATE);
i2c_imx->bitrate = IMX_I2C_MAX_E_BIT_RATE;
}
if (i2c_imx->cur_clk == i2c_clk_rate)
return 0;
......@@ -1656,14 +1674,6 @@ static int i2c_imx_probe(struct platform_device *pdev)
goto clk_notifier_unregister;
}
/*
* This limit caused by an i.MX7D hardware issue(e7805 in Errata).
* If there is no limit, when the bitrate set up to 400KHz, it will
* cause the SCK low level period less than 1.3us.
*/
if (is_imx7d_i2c(i2c_imx) && i2c_imx->bitrate > IMX_I2C_MAX_E_BIT_RATE)
i2c_imx->bitrate = IMX_I2C_MAX_E_BIT_RATE;
i2c_imx_reset_regs(i2c_imx);
/* Init optional bus recovery */
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment