[PATCH] I2C: EXYNOS: Add slave support to i2c

Giridhar Maruthy giridhar.maruthy at linaro.org
Mon Dec 3 17:46:56 EST 2012


Thank you Kyungmin Park for the review.

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

> Hi,
>
> On Mon, Dec 3, 2012 at 9:16 PM, Giridhar Maruthy
> <giridhar.maruthy at 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 at 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 at lists.infradead.org
> > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> >
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121204/8fa2b6e8/attachment-0001.html>


More information about the linux-arm-kernel mailing list