From: Chris Packham <chris.packham@alliedtelesis.co.nz> To: wsa@kernel.org, andriy.shevchenko@linux.intel.com, andy.shevchenko@gmail.com, robh+dt@kernel.org, mpe@ellerman.id.au Cc: linux-i2c@vger.kernel.org, devicetree@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org, Chris Packham <chris.packham@alliedtelesis.co.nz> Subject: [PATCH v3 4/4] i2c: mpc: implement erratum A-004447 workaround Date: Wed, 12 May 2021 09:20:52 +1200 [thread overview] Message-ID: <20210511212052.27242-5-chris.packham@alliedtelesis.co.nz> (raw) In-Reply-To: <20210511212052.27242-1-chris.packham@alliedtelesis.co.nz> The P2040/P2041 has an erratum where the normal i2c recovery mechanism does not work. Implement the alternative recovery mechanism documented in the P2040 Chip Errata Rev Q. Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz> --- Notes: Changes in v3: - Further code reduction in i2c_mpc_wait_sr() Changes in v2: - Use readb_poll_timeout instead of open-coded loop drivers/i2c/busses/i2c-mpc.c | 81 +++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 30d9e89a3db2..dcca9c2396db 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -19,6 +19,7 @@ #include <linux/clk.h> #include <linux/io.h> +#include <linux/iopoll.h> #include <linux/fsl_devices.h> #include <linux/i2c.h> #include <linux/interrupt.h> @@ -45,6 +46,7 @@ #define CCR_MTX 0x10 #define CCR_TXAK 0x08 #define CCR_RSTA 0x04 +#define CCR_RSVD 0x02 #define CSR_MCF 0x80 #define CSR_MAAS 0x40 @@ -97,7 +99,7 @@ struct mpc_i2c { u32 block; int rc; int expect_rxack; - + bool has_errata_A004447; }; struct mpc_i2c_divider { @@ -136,6 +138,75 @@ static void mpc_i2c_fixup(struct mpc_i2c *i2c) } } +static int i2c_mpc_wait_sr(struct mpc_i2c *i2c, int mask) +{ + void __iomem *addr = i2c->base + MPC_I2C_SR; + u8 val; + + return readb_poll_timeout(addr, val, val & mask, 0, 100); +} + +/* + * Workaround for Erratum A004447. From the P2040CE Rev Q + * + * 1. Set up the frequency divider and sampling rate. + * 2. I2CCR - a0h + * 3. Poll for I2CSR[MBB] to get set. + * 4. If I2CSR[MAL] is set (an indication that SDA is stuck low), then go to + * step 5. If MAL is not set, then go to step 13. + * 5. I2CCR - 00h + * 6. I2CCR - 22h + * 7. I2CCR - a2h + * 8. Poll for I2CSR[MBB] to get set. + * 9. Issue read to I2CDR. + * 10. Poll for I2CSR[MIF] to be set. + * 11. I2CCR - 82h + * 12. Workaround complete. Skip the next steps. + * 13. Issue read to I2CDR. + * 14. Poll for I2CSR[MIF] to be set. + * 15. I2CCR - 80h + */ +static void mpc_i2c_fixup_A004447(struct mpc_i2c *i2c) +{ + int ret; + u32 val; + + writeccr(i2c, CCR_MEN | CCR_MSTA); + ret = i2c_mpc_wait_sr(i2c, CSR_MBB); + if (ret) { + dev_err(i2c->dev, "timeout waiting for CSR_MBB\n"); + return; + } + + val = readb(i2c->base + MPC_I2C_SR); + + if (val & CSR_MAL) { + writeccr(i2c, 0x00); + writeccr(i2c, CCR_MSTA | CCR_RSVD); + writeccr(i2c, CCR_MEN | CCR_MSTA | CCR_RSVD); + ret = i2c_mpc_wait_sr(i2c, CSR_MBB); + if (ret) { + dev_err(i2c->dev, "timeout waiting for CSR_MBB\n"); + return; + } + val = readb(i2c->base + MPC_I2C_DR); + ret = i2c_mpc_wait_sr(i2c, CSR_MIF); + if (ret) { + dev_err(i2c->dev, "timeout waiting for CSR_MIF\n"); + return; + } + writeccr(i2c, CCR_MEN | CCR_RSVD); + } else { + val = readb(i2c->base + MPC_I2C_DR); + ret = i2c_mpc_wait_sr(i2c, CSR_MIF); + if (ret) { + dev_err(i2c->dev, "timeout waiting for CSR_MIF\n"); + return; + } + writeccr(i2c, CCR_MEN); + } +} + #if defined(CONFIG_PPC_MPC52xx) || defined(CONFIG_PPC_MPC512x) static const struct mpc_i2c_divider mpc_i2c_dividers_52xx[] = { {20, 0x20}, {22, 0x21}, {24, 0x22}, {26, 0x23}, @@ -670,7 +741,10 @@ static int fsl_i2c_bus_recovery(struct i2c_adapter *adap) { struct mpc_i2c *i2c = i2c_get_adapdata(adap); - mpc_i2c_fixup(i2c); + if (i2c->has_errata_A004447) + mpc_i2c_fixup_A004447(i2c); + else + mpc_i2c_fixup(i2c); return 0; } @@ -767,6 +841,9 @@ static int fsl_i2c_probe(struct platform_device *op) } dev_info(i2c->dev, "timeout %u us\n", mpc_ops.timeout * 1000000 / HZ); + if (of_property_read_bool(op->dev.of_node, "fsl,i2c-erratum-a004447")) + i2c->has_errata_A004447 = true; + i2c->adap = mpc_ops; scnprintf(i2c->adap.name, sizeof(i2c->adap.name), "MPC adapter (%s)", of_node_full_name(op->dev.of_node)); -- 2.31.1
WARNING: multiple messages have this Message-ID (diff)
From: Chris Packham <chris.packham@alliedtelesis.co.nz> To: wsa@kernel.org, andriy.shevchenko@linux.intel.com, andy.shevchenko@gmail.com, robh+dt@kernel.org, mpe@ellerman.id.au Cc: devicetree@vger.kernel.org, Chris Packham <chris.packham@alliedtelesis.co.nz>, linuxppc-dev@lists.ozlabs.org, linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v3 4/4] i2c: mpc: implement erratum A-004447 workaround Date: Wed, 12 May 2021 09:20:52 +1200 [thread overview] Message-ID: <20210511212052.27242-5-chris.packham@alliedtelesis.co.nz> (raw) In-Reply-To: <20210511212052.27242-1-chris.packham@alliedtelesis.co.nz> The P2040/P2041 has an erratum where the normal i2c recovery mechanism does not work. Implement the alternative recovery mechanism documented in the P2040 Chip Errata Rev Q. Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz> --- Notes: Changes in v3: - Further code reduction in i2c_mpc_wait_sr() Changes in v2: - Use readb_poll_timeout instead of open-coded loop drivers/i2c/busses/i2c-mpc.c | 81 +++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 30d9e89a3db2..dcca9c2396db 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -19,6 +19,7 @@ #include <linux/clk.h> #include <linux/io.h> +#include <linux/iopoll.h> #include <linux/fsl_devices.h> #include <linux/i2c.h> #include <linux/interrupt.h> @@ -45,6 +46,7 @@ #define CCR_MTX 0x10 #define CCR_TXAK 0x08 #define CCR_RSTA 0x04 +#define CCR_RSVD 0x02 #define CSR_MCF 0x80 #define CSR_MAAS 0x40 @@ -97,7 +99,7 @@ struct mpc_i2c { u32 block; int rc; int expect_rxack; - + bool has_errata_A004447; }; struct mpc_i2c_divider { @@ -136,6 +138,75 @@ static void mpc_i2c_fixup(struct mpc_i2c *i2c) } } +static int i2c_mpc_wait_sr(struct mpc_i2c *i2c, int mask) +{ + void __iomem *addr = i2c->base + MPC_I2C_SR; + u8 val; + + return readb_poll_timeout(addr, val, val & mask, 0, 100); +} + +/* + * Workaround for Erratum A004447. From the P2040CE Rev Q + * + * 1. Set up the frequency divider and sampling rate. + * 2. I2CCR - a0h + * 3. Poll for I2CSR[MBB] to get set. + * 4. If I2CSR[MAL] is set (an indication that SDA is stuck low), then go to + * step 5. If MAL is not set, then go to step 13. + * 5. I2CCR - 00h + * 6. I2CCR - 22h + * 7. I2CCR - a2h + * 8. Poll for I2CSR[MBB] to get set. + * 9. Issue read to I2CDR. + * 10. Poll for I2CSR[MIF] to be set. + * 11. I2CCR - 82h + * 12. Workaround complete. Skip the next steps. + * 13. Issue read to I2CDR. + * 14. Poll for I2CSR[MIF] to be set. + * 15. I2CCR - 80h + */ +static void mpc_i2c_fixup_A004447(struct mpc_i2c *i2c) +{ + int ret; + u32 val; + + writeccr(i2c, CCR_MEN | CCR_MSTA); + ret = i2c_mpc_wait_sr(i2c, CSR_MBB); + if (ret) { + dev_err(i2c->dev, "timeout waiting for CSR_MBB\n"); + return; + } + + val = readb(i2c->base + MPC_I2C_SR); + + if (val & CSR_MAL) { + writeccr(i2c, 0x00); + writeccr(i2c, CCR_MSTA | CCR_RSVD); + writeccr(i2c, CCR_MEN | CCR_MSTA | CCR_RSVD); + ret = i2c_mpc_wait_sr(i2c, CSR_MBB); + if (ret) { + dev_err(i2c->dev, "timeout waiting for CSR_MBB\n"); + return; + } + val = readb(i2c->base + MPC_I2C_DR); + ret = i2c_mpc_wait_sr(i2c, CSR_MIF); + if (ret) { + dev_err(i2c->dev, "timeout waiting for CSR_MIF\n"); + return; + } + writeccr(i2c, CCR_MEN | CCR_RSVD); + } else { + val = readb(i2c->base + MPC_I2C_DR); + ret = i2c_mpc_wait_sr(i2c, CSR_MIF); + if (ret) { + dev_err(i2c->dev, "timeout waiting for CSR_MIF\n"); + return; + } + writeccr(i2c, CCR_MEN); + } +} + #if defined(CONFIG_PPC_MPC52xx) || defined(CONFIG_PPC_MPC512x) static const struct mpc_i2c_divider mpc_i2c_dividers_52xx[] = { {20, 0x20}, {22, 0x21}, {24, 0x22}, {26, 0x23}, @@ -670,7 +741,10 @@ static int fsl_i2c_bus_recovery(struct i2c_adapter *adap) { struct mpc_i2c *i2c = i2c_get_adapdata(adap); - mpc_i2c_fixup(i2c); + if (i2c->has_errata_A004447) + mpc_i2c_fixup_A004447(i2c); + else + mpc_i2c_fixup(i2c); return 0; } @@ -767,6 +841,9 @@ static int fsl_i2c_probe(struct platform_device *op) } dev_info(i2c->dev, "timeout %u us\n", mpc_ops.timeout * 1000000 / HZ); + if (of_property_read_bool(op->dev.of_node, "fsl,i2c-erratum-a004447")) + i2c->has_errata_A004447 = true; + i2c->adap = mpc_ops; scnprintf(i2c->adap.name, sizeof(i2c->adap.name), "MPC adapter (%s)", of_node_full_name(op->dev.of_node)); -- 2.31.1
next prev parent reply other threads:[~2021-05-11 21:21 UTC|newest] Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top 2021-05-11 21:20 [PATCH v3 0/4] P2040/P2041 i2c recovery erratum Chris Packham 2021-05-11 21:20 ` Chris Packham 2021-05-11 21:20 ` [PATCH v3 1/4] dt-bindings: i2c: mpc: Add fsl,i2c-erratum-a004447 flag Chris Packham 2021-05-11 21:20 ` [PATCH v3 1/4] dt-bindings: i2c: mpc: Add fsl, i2c-erratum-a004447 flag Chris Packham 2021-05-11 21:20 ` [PATCH v3 2/4] powerpc/fsl: set fsl,i2c-erratum-a004447 flag for P2041 i2c controllers Chris Packham 2021-05-11 21:20 ` [PATCH v3 2/4] powerpc/fsl: set fsl, i2c-erratum-a004447 " Chris Packham 2021-05-26 1:02 ` [PATCH v3 2/4] powerpc/fsl: set fsl,i2c-erratum-a004447 " Michael Ellerman 2021-05-26 1:02 ` Michael Ellerman 2021-05-11 21:20 ` [PATCH v3 3/4] powerpc/fsl: set fsl,i2c-erratum-a004447 flag for P1010 " Chris Packham 2021-05-11 21:20 ` [PATCH v3 3/4] powerpc/fsl: set fsl, i2c-erratum-a004447 " Chris Packham 2021-05-26 1:02 ` [PATCH v3 3/4] powerpc/fsl: set fsl,i2c-erratum-a004447 " Michael Ellerman 2021-05-26 1:02 ` Michael Ellerman 2021-05-11 21:20 ` Chris Packham [this message] 2021-05-11 21:20 ` [PATCH v3 4/4] i2c: mpc: implement erratum A-004447 workaround Chris Packham 2021-05-11 22:10 ` [PATCH v3 0/4] P2040/P2041 i2c recovery erratum Joakim Tjernlund 2021-05-11 22:10 ` Joakim Tjernlund 2021-05-12 1:48 ` Chris Packham 2021-05-12 1:48 ` Chris Packham 2021-05-12 8:57 ` Joakim Tjernlund 2021-05-12 8:57 ` Joakim Tjernlund 2021-05-12 15:01 ` wsa 2021-05-12 15:01 ` wsa 2021-05-20 3:36 ` Chris Packham 2021-05-20 3:36 ` Chris Packham 2021-05-25 18:49 ` wsa 2021-05-25 18:49 ` wsa 2021-05-25 18:53 ` Wolfram Sang 2021-05-25 18:53 ` Wolfram Sang 2021-05-26 1:02 ` Michael Ellerman 2021-05-26 1:02 ` Michael Ellerman 2021-05-27 19:53 ` Wolfram Sang 2021-05-27 19:53 ` Wolfram Sang
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20210511212052.27242-5-chris.packham@alliedtelesis.co.nz \ --to=chris.packham@alliedtelesis.co.nz \ --cc=andriy.shevchenko@linux.intel.com \ --cc=andy.shevchenko@gmail.com \ --cc=devicetree@vger.kernel.org \ --cc=linux-i2c@vger.kernel.org \ --cc=linux-kernel@vger.kernel.org \ --cc=linuxppc-dev@lists.ozlabs.org \ --cc=mpe@ellerman.id.au \ --cc=robh+dt@kernel.org \ --cc=wsa@kernel.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.