linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
From: tushar.behera@linaro.org (Tushar Behera)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH] I2C: EXYNOS: Add slave support to i2c
Date: Fri, 07 Dec 2012 17:33:17 +0530	[thread overview]
Message-ID: <50C1DB05.7090500@linaro.org> (raw)
In-Reply-To: <CAHuqX+EQ0pZnm27yAVqC=NRX8huQ5EvbC8PGn2G3xYw4D71gQA@mail.gmail.com>

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>
> ---
>  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)) {

This is executed only if is_master(i2c) is true, so there seems no need
to checking it again.

> +                               /* Start/Stop required only for master */
> +                               iicstat &= ~S3C2410_IICSTAT_START;
> +                       }
> +               }
> +               writel(iicstat, i2c->regs + S3C2410_IICSTAT);
>         }
> -       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
> 


-- 
Tushar Behera

  parent reply	other threads:[~2012-12-07 12:03 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
2012-12-07 11:36     ` Giridhar Maruthy
2012-12-07 12:03   ` Tushar Behera [this message]
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=50C1DB05.7090500@linaro.org \
    --to=tushar.behera@linaro.org \
    --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).