diff mbox

I2C: EXYNOS: Add slave support to i2c

Message ID CAHuqX+EQ0pZnm27yAVqC=NRX8huQ5EvbC8PGn2G3xYw4D71gQA@mail.gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Giridhar Maruthy Dec. 3, 2012, 12:16 p.m. UTC
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(-)

                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);
        }
-       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

Comments

Kyungmin Park Dec. 3, 2012, 1:28 p.m. UTC | #1
Hi,

On Mon, Dec 3, 2012 at 9:16 PM, Giridhar Maruthy
<giridhar.maruthy@linaro.org> 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;
If it's used for master or not, doesn't better to use 'is_master' or
'is_slave'? what's the meaning of 'i2c_mode'?
and
#define is_master(i2c) (i2c->is_master)

Thank you,
Kyungmin Park
>  };
>
>  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);
>         }
> -       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@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
Giridhar Maruthy Dec. 3, 2012, 10:46 p.m. UTC | #2
Thank you Kyungmin Park for the review.

On 3 December 2012 22:28, Kyungmin Park <kmpark@infradead.org> wrote:

> Hi,
>
> On Mon, Dec 3, 2012 at 9:16 PM, Giridhar Maruthy
> <giridhar.maruthy@linaro.org> 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;
> If it's used for master or not, doesn't better to use 'is_master' or
> 'is_slave'? what's the meaning of 'i2c_mode'?
> and
> #define is_master(i2c) (i2c->is_master)
>

I thought mode indicates master mode or slave mode, but I agree 'is_master'
name is better. Will change that.

>
> Thank you,
> Kyungmin Park
>  >  };
> >
> >  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);
> >         }
> > -       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@lists.infradead.org
> > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> >
>
Giridhar Maruthy Dec. 3, 2012, 10:53 p.m. UTC | #3
Thank you Kyungmin Park for the review.

On 3 December 2012 22:28, Kyungmin Park <kmpark@infradead.org> wrote:
>
> Hi,
>
> On Mon, Dec 3, 2012 at 9:16 PM, Giridhar Maruthy
> <giridhar.maruthy@linaro.org> 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;
> If it's used for master or not, doesn't better to use 'is_master' or
> 'is_slave'? what's the meaning of 'i2c_mode'?
> and
> #define is_master(i2c) (i2c->is_master)


I thought mode indicates master mode or slave mode, but I agree
'is_master' name is better. Will change that.

>
> Thank you,
> Kyungmin Park
> >  };
> >
> >  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);
> >         }
> > -       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
Subash Patel Dec. 6, 2012, 2:05 p.m. UTC | #4
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@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
Regards,
Subash
Giridhar Maruthy Dec. 7, 2012, 11:36 a.m. UTC | #5
Thanks for the review Subash. Please find my reply below.

On 6 December 2012 23:05, Subash Patel <subashrp@gmail.com> wrote:
> 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.

My understanding is that the HDMIPHY always commands and hence,
HDMIPHY does not need to be slave at all.
But if you think it is a policy decision which need not be implemented
in driver, I agree with you.
>
>>          }
>> -       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@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>
> Regards,
> Subash
Tushar Behera Dec. 7, 2012, 12:03 p.m. UTC | #6
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@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
Russell King - ARM Linux Dec. 7, 2012, 12:33 p.m. UTC | #7
On Fri, Dec 07, 2012 at 05:33:17PM +0530, Tushar Behera wrote:
> 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.

(I don't have the original patches.)

Hmm.  How has slave-mode support been tested?

Remembering that I2C slave devices do not initiate bus accesses, all
accesses will be started by some other master.  How are you dealing
with the bytes received from the master, and how are you returning a
response to the master in reply to a read request?

We had support for this on PXA I2C through a callback from the driver
into PXA code (used for the Psion Teklogix Netbook device) and it worked
really well, but what you can't do is use the standard I2C interfaces
for slave mode.
Giridhar Maruthy Dec. 10, 2012, 8:10 a.m. UTC | #8
Thanks Tushar,

On 7 December 2012 17:33, Tushar Behera <tushar.behera@linaro.org> wrote:
> 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.
>

Agreed, I will correct this.
>> +                               /* 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@lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>
>
>
> --
> Tushar Behera
Giridhar Maruthy Dec. 10, 2012, 9:32 a.m. UTC | #9
Hi Russel,

Thanks for review and please find my replies below.

On 7 December 2012 18:03, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
> On Fri, Dec 07, 2012 at 05:33:17PM +0530, Tushar Behera wrote:
>> 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.
>
> (I don't have the original patches.)
>
> Hmm.  How has slave-mode support been tested?

I have taken two I2C controllers in exynos5250.
I configured one as slave and the other as master port.
Then physically connected the pins of the two ports.
>
> Remembering that I2C slave devices do not initiate bus accesses, all
> accesses will be started by some other master.  How are you dealing
> with the bytes received from the master,

I run the slave read application in background.
The resulting slave read will sleep till all bytes are received
(wait_event_interruptible)

once the master sends the data, an ack is given out by the slave controller
in the ISR and the data is cached in the buffer(
buffer sent by slave receive application).
After all data is received, the read wakes up and the
slave receive program gets the data.

> and how are you returning a response to the master in reply to a read request?

Similarl logic works in slave transmit mode (read request). Slave
sleeps till the master initiates the transfer.
>
> We had support for this on PXA I2C through a callback from the driver
> into PXA code (used for the Psion Teklogix Netbook device) and it worked
> really well, but what you can't do is use the standard I2C interfaces
> for slave mode.

I have a question here. Since the same framework can work for both
master and slave, is there any technical limitations I have overseen
which prevents the slave mode to work?
Russell King - ARM Linux Dec. 10, 2012, 12:44 p.m. UTC | #10
On Mon, Dec 10, 2012 at 03:02:28PM +0530, Giridhar Maruthy wrote:
> Hi Russel,
> 
> Thanks for review and please find my replies below.
> 
> On 7 December 2012 18:03, Russell King - ARM Linux
> <linux@arm.linux.org.uk> wrote:
> > On Fri, Dec 07, 2012 at 05:33:17PM +0530, Tushar Behera wrote:
> >> 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.
> >
> > (I don't have the original patches.)
> >
> > Hmm.  How has slave-mode support been tested?
> 
> I have taken two I2C controllers in exynos5250.
> I configured one as slave and the other as master port.
> Then physically connected the pins of the two ports.
> >
> > Remembering that I2C slave devices do not initiate bus accesses, all
> > accesses will be started by some other master.  How are you dealing
> > with the bytes received from the master,
> 
> I run the slave read application in background.
> The resulting slave read will sleep till all bytes are received
> (wait_event_interruptible)

Oh god no, not more broken interruptible waits in I2C code.  I've seen
already the results of crap like this with a kernel I2C peripheral driver
falling over because the I2C layer returns -ERESTARTcrap with the Marvell
I2C bus adapter.

> once the master sends the data, an ack is given out by the slave controller
> in the ISR and the data is cached in the buffer(
> buffer sent by slave receive application).
> After all data is received, the read wakes up and the
> slave receive program gets the data.
> 
> > and how are you returning a response to the master in reply to a read request?
> 
> Similarl logic works in slave transmit mode (read request). Slave
> sleeps till the master initiates the transfer.
> >
> > We had support for this on PXA I2C through a callback from the driver
> > into PXA code (used for the Psion Teklogix Netbook device) and it worked
> > really well, but what you can't do is use the standard I2C interfaces
> > for slave mode.
> 
> I have a question here. Since the same framework can work for both
> master and slave, is there any technical limitations I have overseen
> which prevents the slave mode to work?

I don't really call your description above as "working" - it sounds like
a bodge - it sounds like trying to bend a layer designed for master mode
to sort-of-maybe-if-the-wind-is-in-the-right-direction-and-the-cows-are-
all-standing-up-work.  What if the application is trying to read in slave
mode while the master is also trying to read?  How do you deal with that?
What about the converse?  What if the application is trying to write data
and the master also issues a write request?

Finally, what about a multi-master situation?  I can see no way for your
implementation to have any hope of working there because there is no
distinction between operating the interface in master mode and slave mode.
diff mbox

Patch

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)