From: Ben Dooks <ben-linux@fluff.org>
To: Tony Lindgren <tony@atomide.com>
Cc: i2c@lm-sensors.org, linux-omap@vger.kernel.org,
Jason P Marini <jason.marini@gmail.com>
Subject: Re: [i2c] [PATCH 4/8] i2c-omap: FIFO handling support and broken hw workaround for i2c-omap
Date: Mon, 29 Sep 2008 23:27:33 +0100 [thread overview]
Message-ID: <20080929222733.GR2716@fluff.org.uk> (raw)
In-Reply-To: <1222329234-31473-5-git-send-email-tony@atomide.com>
On Thu, Sep 25, 2008 at 10:53:50AM +0300, Tony Lindgren wrote:
> From: Nishanth Menon <menon.nishanth@gmail.com>
>
> Based on an earlier patch from Nishant Menon:
>
> - Transfers can use FIFO on FIFO capable devices
> - Prevents errors for HSI2C if FIFO is not used
> - Implemented errenous handling of STT-STP handling on SDP2430
>
> Also merged in is a fix from Jaron Marini to fix occasional i2c
> hang if OMAP_I2C_CON_STT remains asserted.
This looks ok
> Signed-off-by: Jason P Marini <jason.marini@gmail.com>
> Signed-off-by: Nishanth Menon <menon.nishanth@gmail.com>
> Signed-off-by: Tony Lindgren <tony@atomide.com>
> ---
> drivers/i2c/busses/i2c-omap.c | 189 ++++++++++++++++++++++++++++++++---------
> 1 files changed, 149 insertions(+), 40 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
> index 0d30790..ded4636 100644
> --- a/drivers/i2c/busses/i2c-omap.c
> +++ b/drivers/i2c/busses/i2c-omap.c
> @@ -55,8 +55,11 @@
> #define OMAP_I2C_SCLL_REG 0x34
> #define OMAP_I2C_SCLH_REG 0x38
> #define OMAP_I2C_SYSTEST_REG 0x3c
> +#define OMAP_I2C_BUFSTAT_REG 0x40
>
> /* I2C Interrupt Enable Register (OMAP_I2C_IE): */
> +#define OMAP_I2C_IE_XDR (1 << 14) /* TX Buffer drain int enable */
> +#define OMAP_I2C_IE_RDR (1 << 13) /* RX Buffer drain int enable */
> #define OMAP_I2C_IE_XRDY (1 << 4) /* TX data ready int enable */
> #define OMAP_I2C_IE_RRDY (1 << 3) /* RX data ready int enable */
> #define OMAP_I2C_IE_ARDY (1 << 2) /* Access ready int enable */
> @@ -64,7 +67,8 @@
> #define OMAP_I2C_IE_AL (1 << 0) /* Arbitration lost int ena */
>
> /* I2C Status Register (OMAP_I2C_STAT): */
> -#define OMAP_I2C_STAT_SBD (1 << 15) /* Single byte data */
> +#define OMAP_I2C_STAT_XDR (1 << 14) /* TX Buffer draining */
> +#define OMAP_I2C_STAT_RDR (1 << 13) /* RX Buffer draining */
> #define OMAP_I2C_STAT_BB (1 << 12) /* Bus busy */
> #define OMAP_I2C_STAT_ROVR (1 << 11) /* Receive overrun */
> #define OMAP_I2C_STAT_XUDF (1 << 10) /* Transmit underflow */
> @@ -78,12 +82,14 @@
>
> /* I2C Buffer Configuration Register (OMAP_I2C_BUF): */
> #define OMAP_I2C_BUF_RDMA_EN (1 << 15) /* RX DMA channel enable */
> +#define OMAP_I2C_BUF_RXFIF_CLR (1 << 14) /* RX FIFO Clear */
> #define OMAP_I2C_BUF_XDMA_EN (1 << 7) /* TX DMA channel enable */
> +#define OMAP_I2C_BUF_TXFIF_CLR (1 << 6) /* TX FIFO Clear */
>
> /* I2C Configuration Register (OMAP_I2C_CON): */
> #define OMAP_I2C_CON_EN (1 << 15) /* I2C module enable */
> #define OMAP_I2C_CON_BE (1 << 14) /* Big endian mode */
> -#define OMAP_I2C_CON_OPMODE (1 << 12) /* High Speed support */
> +#define OMAP_I2C_CON_OPMODE_HS (1 << 12) /* High Speed support */
> #define OMAP_I2C_CON_STB (1 << 11) /* Start byte mode (master) */
> #define OMAP_I2C_CON_MST (1 << 10) /* Master/slave mode */
> #define OMAP_I2C_CON_TRX (1 << 9) /* TX/RX mode (master only) */
> @@ -127,7 +133,12 @@ struct omap_i2c_dev {
> u8 *buf;
> size_t buf_len;
> struct i2c_adapter adapter;
> + u8 fifo_size; /* use as flag and value
> + * fifo_size==0 implies no fifo
> + * if set, should be trsh+1
> + */
> unsigned rev1:1;
> + unsigned b_hw:1; /* bad h/w fixes */
> unsigned idle:1;
> u16 iestate; /* Saved interrupt register */
> };
> @@ -310,6 +321,14 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
> omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, scll);
> omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, sclh);
>
> + if (dev->fifo_size)
> + /* Note: setup required fifo size - 1 */
> + omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG,
> + (dev->fifo_size - 1) << 8 | /* RTRSH */
> + OMAP_I2C_BUF_RXFIF_CLR |
> + (dev->fifo_size - 1) | /* XTRSH */
> + OMAP_I2C_BUF_TXFIF_CLR);
> +
> /* Take the I2C module out of reset: */
> omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
>
> @@ -317,7 +336,8 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
> omap_i2c_write_reg(dev, OMAP_I2C_IE_REG,
> (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
> OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
> - OMAP_I2C_IE_AL));
> + OMAP_I2C_IE_AL) | ((dev->fifo_size) ?
> + (OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0));
> return 0;
> }
>
> @@ -364,6 +384,11 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
>
> omap_i2c_write_reg(dev, OMAP_I2C_CNT_REG, dev->buf_len);
>
> + /* Clear the FIFO Buffers */
> + w = omap_i2c_read_reg(dev, OMAP_I2C_BUF_REG);
> + w |= OMAP_I2C_BUF_RXFIF_CLR | OMAP_I2C_BUF_TXFIF_CLR;
> + omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, w);
> +
> init_completion(&dev->cmd_complete);
> dev->cmd_err = 0;
>
> @@ -371,16 +396,38 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
>
> /* High speed configuration */
> if (dev->speed > 400)
> - w |= OMAP_I2C_CON_OPMODE;
> + w |= OMAP_I2C_CON_OPMODE_HS;
>
> if (msg->flags & I2C_M_TEN)
> w |= OMAP_I2C_CON_XA;
> if (!(msg->flags & I2C_M_RD))
> w |= OMAP_I2C_CON_TRX;
> - if (stop)
> + if (!dev->b_hw && stop)
> w |= OMAP_I2C_CON_STP;
> omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
>
> + /*
> + * Don't write stt and stp together on some hardware
> + */
> + if (dev->b_hw && stop) {
> + unsigned long delay = jiffies + OMAP_I2C_TIMEOUT;
> + u16 con = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
> + while (con & OMAP_I2C_CON_STT) {
> + con = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
> +
> + /* Let the user know if i2c is in a bad state */
> + if (time_after(jiffies, delay)) {
> + dev_err(dev->dev, "controller timed out "
> + "waiting for start condition to finish\n");
> + return -ETIMEDOUT;
> + }
> + cpu_relax();
> + }
> +
> + w |= OMAP_I2C_CON_STP;
> + w &= ~OMAP_I2C_CON_STT;
> + omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
> + }
> r = wait_for_completion_timeout(&dev->cmd_complete,
> OMAP_I2C_TIMEOUT);
> dev->buf_len = 0;
> @@ -525,7 +572,7 @@ omap_i2c_isr(int this_irq, void *dev_id)
> struct omap_i2c_dev *dev = dev_id;
> u16 bits;
> u16 stat, w;
> - int count = 0;
> + int err, count = 0;
>
> if (dev->idle)
> return IRQ_NONE;
> @@ -540,39 +587,94 @@ omap_i2c_isr(int this_irq, void *dev_id)
>
> omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat);
>
> - if (stat & OMAP_I2C_STAT_ARDY) {
> - omap_i2c_complete_cmd(dev, 0);
> - continue;
> + err = 0;
> + if (stat & OMAP_I2C_STAT_NACK) {
> + err |= OMAP_I2C_STAT_NACK;
> + omap_i2c_write_reg(dev, OMAP_I2C_CON_REG,
> + OMAP_I2C_CON_STP);
> }
> - if (stat & OMAP_I2C_STAT_RRDY) {
> - w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
> - if (dev->buf_len) {
> - *dev->buf++ = w;
> - dev->buf_len--;
> + if (stat & OMAP_I2C_STAT_AL) {
> + dev_err(dev->dev, "Arbitration lost\n");
> + err |= OMAP_I2C_STAT_AL;
> + }
> + if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK |
> + OMAP_I2C_STAT_AL))
> + omap_i2c_complete_cmd(dev, err);
> + if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) {
> + u8 num_bytes = 1;
> + if (dev->fifo_size) {
> + if (stat & OMAP_I2C_STAT_RRDY)
> + num_bytes = dev->fifo_size;
> + else
> + num_bytes = omap_i2c_read_reg(dev,
> + OMAP_I2C_BUFSTAT_REG);
> + }
> + while (num_bytes) {
> + num_bytes--;
> + w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
> if (dev->buf_len) {
> - *dev->buf++ = w >> 8;
> + *dev->buf++ = w;
> dev->buf_len--;
> + /* Data reg from 2430 is 8 bit wide */
> + if (!cpu_is_omap2430()) {
> + if (dev->buf_len) {
> + *dev->buf++ = w >> 8;
> + dev->buf_len--;
> + }
> + }
> + } else {
> + if (stat & OMAP_I2C_STAT_RRDY)
> + dev_err(dev->dev,
> + "RRDY IRQ while no data"
> + " requested\n");
> + if (stat & OMAP_I2C_STAT_RDR)
> + dev_err(dev->dev,
> + "RDR IRQ while no data"
> + " requested\n");
> + break;
> }
> - } else
> - dev_err(dev->dev, "RRDY IRQ while no data "
> - "requested\n");
> - omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RRDY);
> + }
> + omap_i2c_ack_stat(dev,
> + stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR));
> continue;
> }
> - if (stat & OMAP_I2C_STAT_XRDY) {
> - w = 0;
> - if (dev->buf_len) {
> - w = *dev->buf++;
> - dev->buf_len--;
> + if (stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)) {
> + u8 num_bytes = 1;
> + if (dev->fifo_size) {
> + if (stat & OMAP_I2C_STAT_XRDY)
> + num_bytes = dev->fifo_size;
> + else
> + num_bytes = omap_i2c_read_reg(dev,
> + OMAP_I2C_BUFSTAT_REG);
> + }
> + while (num_bytes) {
> + num_bytes--;
> + w = 0;
> if (dev->buf_len) {
> - w |= *dev->buf++ << 8;
> + w = *dev->buf++;
> dev->buf_len--;
> + /* Data reg from 2430 is 8 bit wide */
> + if (!cpu_is_omap2430()) {
> + if (dev->buf_len) {
> + w |= *dev->buf++ << 8;
> + dev->buf_len--;
> + }
> + }
> + } else {
> + if (stat & OMAP_I2C_STAT_XRDY)
> + dev_err(dev->dev,
> + "XRDY IRQ while no "
> + "data to send\n");
> + if (stat & OMAP_I2C_STAT_XDR)
> + dev_err(dev->dev,
> + "XDR IRQ while no "
> + "data to send\n");
> + break;
> }
> - } else
> - dev_err(dev->dev, "XRDY IRQ while no "
> - "data to send\n");
> - omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
> - omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XRDY);
> + omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
> + }
> + omap_i2c_ack_stat(dev,
> + stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
> continue;
> }
> if (stat & OMAP_I2C_STAT_ROVR) {
> @@ -580,18 +682,9 @@ omap_i2c_isr(int this_irq, void *dev_id)
> dev->cmd_err |= OMAP_I2C_STAT_ROVR;
> }
> if (stat & OMAP_I2C_STAT_XUDF) {
> - dev_err(dev->dev, "Transmit overflow\n");
> + dev_err(dev->dev, "Transmit underflow\n");
> dev->cmd_err |= OMAP_I2C_STAT_XUDF;
> }
> - if (stat & OMAP_I2C_STAT_NACK) {
> - omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_NACK);
> - omap_i2c_write_reg(dev, OMAP_I2C_CON_REG,
> - OMAP_I2C_CON_STP);
> - }
> - if (stat & OMAP_I2C_STAT_AL) {
> - dev_err(dev->dev, "Arbitration lost\n");
> - omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_AL);
> - }
> }
>
> return count ? IRQ_HANDLED : IRQ_NONE;
> @@ -655,6 +748,22 @@ omap_i2c_probe(struct platform_device *pdev)
> if (cpu_is_omap15xx())
> dev->rev1 = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) < 0x20;
>
> + if (cpu_is_omap2430()) {
> + u16 s;
> +
> + /* Set up the fifo size - Get total size */
> + s = (omap_i2c_read_reg(dev, OMAP_I2C_BUFSTAT_REG) >> 14) & 0x3;
how about some constants for these instead of us having to guess what
is going on here?
> + dev->fifo_size = 0x8 << s;
> +
> + /*
> + * Set up notification threshold as half the total available
> + * size. This is to ensure that we can handle the status on int
> + * call back latencies.
> + */
> + dev->fifo_size = (dev->fifo_size / 2);
> + dev->b_hw = 1; /* Enable hardware fixes */
> + }
> +
> /* reset ASAP, clearing any IRQs */
> omap_i2c_init(dev);
>
> --
> 1.5.6.rc3.21.g8c6b5
>
>
> _______________________________________________
> i2c mailing list
> i2c@lm-sensors.org
> http://lists.lm-sensors.org/mailman/listinfo/i2c
--
Ben (ben@fluff.org, http://www.fluff.org/)
'a smiley only costs 4 bytes'
next prev parent reply other threads:[~2008-09-29 22:27 UTC|newest]
Thread overview: 34+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-09-25 7:53 [PATCH 0/8] Updates for i2c-omap from linux-omap tree for review, v2 Tony Lindgren
2008-09-25 7:53 ` [PATCH 1/8] i2c-omap: Do not use interruptible wait call in omap_i2c_xfer_msg Tony Lindgren
2008-09-25 7:53 ` [PATCH 2/8] i2c-omap: Close suspected race between omap_i2c_idle() and omap_i2c_isr() Tony Lindgren
2008-09-25 7:53 ` [PATCH 3/8] i2c-omap: Add high-speed support to omap-i2c Tony Lindgren
2008-09-25 7:53 ` [PATCH 4/8] i2c-omap: FIFO handling support and broken hw workaround for i2c-omap Tony Lindgren
2008-09-25 7:53 ` [PATCH 5/8] i2c-omap: Add support on 34xx Tony Lindgren
2008-09-25 7:53 ` [PATCH 6/8] i2c-omap: Mark init-only functions as __init Tony Lindgren
2008-09-25 7:53 ` [PATCH 7/8] i2c-omap: Don't compile in OMAP15xx I2C ISR for non-OMAP15xx builds Tony Lindgren
2008-09-25 7:53 ` [PATCH 8/8] i2c-omap: Clean-up i2c-omap Tony Lindgren
2008-09-25 11:40 ` [PATCH 8/8] i2c-omap: Clean-up i2c-omap, v3 Tony Lindgren
2008-09-29 22:31 ` [i2c] [PATCH 8/8] i2c-omap: Clean-up i2c-omap Ben Dooks
2008-10-17 15:41 ` Tony Lindgren
[not found] ` <1222329234-31473-9-git-send-email-tony-4v6yS6AI5VpBDgjK7y7TUQ@public.gmane.org>
2008-10-17 15:47 ` [PATCH 9/8] i2c-omap: fix I2C timeouts due to recursive omap_i2c_{un, }idle() Tony Lindgren
2008-09-29 22:29 ` [i2c] [PATCH 7/8] i2c-omap: Don't compile in OMAP15xx I2C ISR for non-OMAP15xx builds Ben Dooks
2008-09-29 23:06 ` David Brownell
2008-09-30 5:35 ` Paul Walmsley
2008-09-30 5:36 ` Paul Walmsley
2008-10-17 15:40 ` Tony Lindgren
2008-09-29 22:30 ` [i2c] [PATCH 6/8] i2c-omap: Mark init-only functions as __init Ben Dooks
2008-10-17 15:39 ` Tony Lindgren
2008-10-17 17:07 ` Tony Lindgren
2008-09-29 22:28 ` [i2c] [PATCH 5/8] i2c-omap: Add support on 34xx Ben Dooks
2008-10-17 15:38 ` Tony Lindgren
2008-09-25 11:39 ` [PATCH 4/8] i2c-omap: FIFO handling support and broken hw workaround for i2c-omap, v3 Tony Lindgren
2008-09-29 22:27 ` Ben Dooks [this message]
2008-09-29 22:25 ` [i2c] [PATCH 3/8] i2c-omap: Add high-speed support to omap-i2c Ben Dooks
2008-10-17 15:37 ` Tony Lindgren
2008-09-29 22:21 ` [i2c] [PATCH 2/8] i2c-omap: Close suspected race between omap_i2c_idle() and omap_i2c_isr() Ben Dooks
2008-09-29 22:21 ` [i2c] [PATCH 1/8] i2c-omap: Do not use interruptible wait call in omap_i2c_xfer_msg Ben Dooks
2008-09-30 11:51 ` Jarkko Nikula
2008-10-17 15:35 ` Tony Lindgren
2008-09-29 22:23 ` [i2c] [PATCH 0/8] Updates for i2c-omap from linux-omap tree for review, v2 Ben Dooks
2008-09-30 5:35 ` Tony Lindgren
2008-10-17 16:04 ` git-pull request for i2c-omap changes (Re: [i2c] [PATCH 0/8] Updates for i2c-omap from linux-omap tree for review, v2) Tony Lindgren
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=20080929222733.GR2716@fluff.org.uk \
--to=ben-linux@fluff.org \
--cc=i2c@lm-sensors.org \
--cc=jason.marini@gmail.com \
--cc=linux-omap@vger.kernel.org \
--cc=tony@atomide.com \
/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: link
Be 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.