linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
From: subashrp@gmail.com (Subash Patel)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH] I2C: EXYNOS: Add slave support to i2c
Date: Thu, 06 Dec 2012 19:35:49 +0530	[thread overview]
Message-ID: <50C0A63D.1010906@gmail.com> (raw)
In-Reply-To: <CAHuqX+EQ0pZnm27yAVqC=NRX8huQ5EvbC8PGn2G3xYw4D71gQA@mail.gmail.com>

Hi Giridhar,

On 12/03/2012 05:46 PM, Giridhar Maruthy wrote:
> This patch adds slave support to i2c. The dt entry i2c-mode
> decides at probe time if the controller needs to work in
> slave mode and the controller is accordingly programmed.
>
> Signed-off-by: Giridhar Maruthy <giridhar.maruthy@linaro.org
> <mailto:giridhar.maruthy@linaro.org>>
> ---
>   drivers/i2c/busses/i2c-s3c2410.c |  100
> ++++++++++++++++++++++++++------------
>   1 file changed, 68 insertions(+), 32 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-s3c2410.c
> b/drivers/i2c/busses/i2c-s3c2410.c
> index e93e7d6..d83a6d7 100644
> --- a/drivers/i2c/busses/i2c-s3c2410.c
> +++ b/drivers/i2c/busses/i2c-s3c2410.c
> @@ -53,6 +53,9 @@
>   /* Max time to wait for bus to become idle after a xfer (in us) */
>   #define S3C2410_IDLE_TIMEOUT   5000
>
> +/* To find the master/slave mode of current controller */
> +#define is_master(i2c) (!i2c->i2c_mode)
> +
>   /* i2c controller state */
>   enum s3c24xx_i2c_state {
>          STATE_IDLE,
> @@ -89,6 +92,8 @@ struct s3c24xx_i2c {
>   #ifdef CONFIG_CPU_FREQ
>          struct notifier_block   freq_transition;
>   #endif
> +       /* i2c_mode: 0 is for master; and 1 is for slave */
> +       unsigned int            i2c_mode;
>   };
>
>   static struct platform_device_id s3c24xx_driver_ids[] = {
> @@ -202,11 +207,21 @@ static void s3c24xx_i2c_message_start(struct
> s3c24xx_i2c *i2c,
>          stat = 0;
>          stat |=  S3C2410_IICSTAT_TXRXEN;
>
> -       if (msg->flags & I2C_M_RD) {
> -               stat |= S3C2410_IICSTAT_MASTER_RX;
> -               addr |= 1;
> -       } else
> -               stat |= S3C2410_IICSTAT_MASTER_TX;
> +       if (is_master(i2c)) {
> +               /* Master mode */
> +               if (msg->flags & I2C_M_RD) {
> +                       stat |= S3C2410_IICSTAT_MASTER_RX;
> +                       addr |= 1;
> +               } else
> +                       stat |= S3C2410_IICSTAT_MASTER_TX;
> +       } else {
> +               /* Slave mode */
> +               if (msg->flags & I2C_M_RD) {
> +                       stat |= S3C2410_IICSTAT_SLAVE_RX;
> +                       addr |= 1;
> +               } else
> +                       stat |= S3C2410_IICSTAT_SLAVE_TX;
> +       }
>
>          if (msg->flags & I2C_M_REV_DIR_ADDR)
>                  addr ^= 1;
> @@ -228,8 +243,10 @@ static void s3c24xx_i2c_message_start(struct
> s3c24xx_i2c *i2c,
>          dev_dbg(i2c->dev, "iiccon, %08lx\n", iiccon);
>          writel(iiccon, i2c->regs + S3C2410_IICCON);
>
> -       stat |= S3C2410_IICSTAT_START;
> -       writel(stat, i2c->regs + S3C2410_IICSTAT);
> +       if (is_master(i2c)) {
> +               stat |= S3C2410_IICSTAT_START;
> +               writel(stat, i2c->regs + S3C2410_IICSTAT);
> +       }
>   }
>
>   static inline void s3c24xx_i2c_stop(struct s3c24xx_i2c *i2c, int ret)
> @@ -272,14 +289,19 @@ static inline void s3c24xx_i2c_stop(struct
> s3c24xx_i2c *i2c, int ret)
>           * devices, the host as Master and the HDMIPHY device as the slave.
>           * Skipping the STOP condition has been tested on this bus and
> works.
>           */
> -       if (i2c->quirks & QUIRK_HDMIPHY) {
> -               /* Stop driving the I2C pins */
> -               iicstat &= ~S3C2410_IICSTAT_TXRXEN;
> -       } else {
> -               /* stop the transfer */
> -               iicstat &= ~S3C2410_IICSTAT_START;
> +       if (is_master(i2c)) {
> +               if (i2c->quirks & QUIRK_HDMIPHY) {
> +                       /* Stop driving the I2C pins */
> +                       iicstat &= ~S3C2410_IICSTAT_TXRXEN;
> +               } else {
> +                       /* stop the transfer */
> +                       if (is_master(i2c)) {
> +                               /* Start/Stop required only for master */
> +                               iicstat &= ~S3C2410_IICSTAT_START;
> +                       }
> +               }
> +               writel(iicstat, i2c->regs + S3C2410_IICSTAT);

I don't see i2c controller for HDMIPHY working in slave mode. So do we 
need to check if its master and proceed? Cant the quirks check enough 
for it? Even if it is configured as slave, there is no error indication 
for this here.

>          }
> -       writel(iicstat, i2c->regs + S3C2410_IICSTAT);
>
>          i2c->state = STATE_STOP;
>
> @@ -348,7 +370,8 @@ static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c
> *i2c, unsigned long iicstat)
>                   */
>
>                  if (iicstat & S3C2410_IICSTAT_LASTBIT &&
> -                   !(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
> +                   !(i2c->msg->flags & I2C_M_IGNORE_NAK) &&
> +                   is_master(i2c)) {
>                          /* ack was not received... */
>
>                          dev_dbg(i2c->dev, "ack was not received\n");
> @@ -380,7 +403,7 @@ static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c
> *i2c, unsigned long iicstat)
>                   * end of the message, and if so, work out what to do
>                   */
>
> -               if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
> +               if (!(i2c->msg->flags & I2C_M_IGNORE_NAK) &&
> is_master(i2c)) {
>                          if (iicstat & S3C2410_IICSTAT_LASTBIT) {
>                                  dev_dbg(i2c->dev, "WRITE: No Ack\n");
>
> @@ -432,7 +455,6 @@ static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c
> *i2c, unsigned long iicstat)
>
>                  } else {
>                          /* send stop */
> -
>                          s3c24xx_i2c_stop(i2c, 0);
>                  }
>                  break;
> @@ -447,7 +469,7 @@ static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c
> *i2c, unsigned long iicstat)
>                  i2c->msg->buf[i2c->msg_ptr++] = byte;
>
>    prepare_read:
> -               if (is_msglast(i2c)) {
> +               if (is_msglast(i2c) && is_master(i2c)) {
>                          /* last byte of buffer */
>
>                          if (is_lastmsg(i2c))
> @@ -612,11 +634,13 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
>          if (i2c->suspended)
>                  return -EIO;
>
> -       ret = s3c24xx_i2c_set_master(i2c);
> -       if (ret != 0) {
> -               dev_err(i2c->dev, "cannot get bus (error %d)\n", ret);
> -               ret = -EAGAIN;
> -               goto out;
> +       if (is_master(i2c)) {
> +               ret = s3c24xx_i2c_set_master(i2c);
> +               if (ret != 0) {
> +                       dev_err(i2c->dev, "cannot get bus (error %d)\n",
> ret);
> +                       ret = -EAGAIN;
> +                       goto out;
> +               }
>          }
>
>          i2c->msg     = msgs;
> @@ -628,23 +652,29 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
>          s3c24xx_i2c_enable_irq(i2c);
>          s3c24xx_i2c_message_start(i2c, msgs);
>
> -       timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
> +       if (is_master(i2c))
> +               timeout = wait_event_timeout(i2c->wait,\
> +                               i2c->msg_num == 0, HZ * 5);
> +       else
> +               wait_event_interruptible(i2c->wait, i2c->msg_num == 0);
>
>          ret = i2c->msg_idx;
>
>          /* having these next two as dev_err() makes life very
>           * noisy when doing an i2cdetect */
>
> -       if (timeout == 0)
> -               dev_dbg(i2c->dev, "timeout\n");
> -       else if (ret != num)
> -               dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret);
> +       if (is_master(i2c)) {
> +               if (timeout == 0)
> +                       dev_dbg(i2c->dev, "timeout\n");
> +               else if (ret != num)
> +                       dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret);
>
> -       /* For QUIRK_HDMIPHY, bus is already disabled */
> -       if (i2c->quirks & QUIRK_HDMIPHY)
> -               goto out;
> +               /* For QUIRK_HDMIPHY, bus is already disabled */
> +               if (i2c->quirks & QUIRK_HDMIPHY)
> +                       goto out;
>
> -       s3c24xx_i2c_wait_idle(i2c);
> +               s3c24xx_i2c_wait_idle(i2c);
> +       }
>
>    out:
>          return ret;
> @@ -963,6 +993,7 @@ s3c24xx_i2c_parse_dt(struct device_node *np, struct
> s3c24xx_i2c *i2c)
>          of_property_read_u32(np, "samsung,i2c-slave-addr",
> &pdata->slave_addr);
>          of_property_read_u32(np, "samsung,i2c-max-bus-freq",
>                                  (u32 *)&pdata->frequency);
> +       of_property_read_u32(np, "samsung,i2c-mode", &i2c->i2c_mode);
>   }
>   #else
>   static void
> @@ -1004,6 +1035,10 @@ static int s3c24xx_i2c_probe(struct
> platform_device *pdev)
>                  goto err_noclk;
>          }
>
> +       /* By default, i2c works in master mode */
> +       /* This currently will be updated using DT */
> +       i2c->i2c_mode   = 0;
> +
>          i2c->quirks = s3c24xx_get_device_quirks(pdev);
>          if (pdata)
>                  memcpy(i2c->pdata, pdata, sizeof(*pdata));
> @@ -1017,6 +1052,7 @@ static int s3c24xx_i2c_probe(struct
> platform_device *pdev)
>          i2c->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD;
>          i2c->tx_setup     = 50;
>
> +
>          init_waitqueue_head(&i2c->wait);
>
>          /* find the clock and enable it */
> --
> 1.7.9.5
>
>
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
Regards,
Subash

  parent reply	other threads:[~2012-12-06 14:05 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <1354354961-28833-1-git-send-email-giridhar.maruthy@linaro.org>
2012-12-03 12:16 ` [PATCH] I2C: EXYNOS: Add slave support to i2c Giridhar Maruthy
2012-12-03 13:28   ` Kyungmin Park
2012-12-03 22:46     ` Giridhar Maruthy
2012-12-03 22:53     ` Giridhar Maruthy
2012-12-06 14:05   ` Subash Patel [this message]
2012-12-07 11:36     ` Giridhar Maruthy
2012-12-07 12:03   ` Tushar Behera
2012-12-07 12:33     ` Russell King - ARM Linux
2012-12-10  9:32       ` Giridhar Maruthy
2012-12-10 12:44         ` Russell King - ARM Linux
2012-12-10  8:10     ` Giridhar Maruthy

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=50C0A63D.1010906@gmail.com \
    --to=subashrp@gmail.com \
    --cc=linux-arm-kernel@lists.infradead.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: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).