On Sat, Mar 28, 2009 at 10:36:50PM +0100, Guennadi Liakhovetski wrote:
> On Wed, 25 Mar 2009, Wolfram Sang wrote:
> 
> > > Because I hurry to submit this, because merge window is open.
> 
> Ok, I waited for this driver, I really did, and I really prefer having one 
> driver for as many hardware (SoC) variants as possible instead of having 
> different drivers, and I really hoped its new version will work 
> out-of-the-box in my setup (pcm037 with a mt9t031 camera). Unfortunately, 
> it didn't. I've spent more than a full working day trying to get it to 
> work, but I didn't succeed so far. It works with the on-board rtc, but it 
> doesn't work with the camera, connected over a flex cable.
> 
> Attached to this email is a version of the i2c driver for i.mx31 that I've 
> been using with my setup for about half a year now. I adjusted it slightly 
> to accept the same platform data, so, it is really a drop-in replacement 
> for i2c-imx.c. Of course, you have to adjust or extend the Makefile. I 
> actually added a new Kconfig entry for this driver, so I could easily 
> compare them during the tests.
> 
> The source of "my" version does look more logical and more clean to me on 
> quite a few occasions. So, maybe someone could give it a quick spin on 
> other *mx* SoCs and see if we can use this one instead? You might have to 
> replace {read,write}w with readb and writeb, so, it might be a good idea 
> to abstract them into inlines or macros. Otherwise, I think, it might work 
> for other CPUs straight away.
> 
> I just would like to avoid committing a driver and having to spend hours 
> or days fixing it afterwards when a possibly more mature version exists.

I'm going to hold off pushing my current tree until this/tommorow
evening so that people have some time to get back to me on what is
the best way to proceed.
 
> Thanks
> Guennadi
> ---
> Guennadi Liakhovetski, Ph.D.
> Freelance Open-Source Software Developer
> /*
>  * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
>  *
>  * The code contained herein is licensed under the GNU General Public
>  * License. You may obtain a copy of the GNU General Public License
>  * Version 2 or later at the following locations:
>  *
>  * http://www.opensource.org/licenses/gpl-license.html
>  * http://www.gnu.org/copyleft/gpl.html
>  */
> 
> #include <linux/module.h>
> #include <linux/kernel.h>
> #include <linux/delay.h>
> #include <linux/interrupt.h>
> #include <linux/platform_device.h>
> #include <linux/i2c.h>
> #include <linux/clk.h>
> #include <linux/err.h>
> 
> #include <asm/irq.h>
> #include <asm/io.h>
> 
> #include <mach/i2c.h>
> #include <mach/iomux-mx3.h>
> 
> /* Address offsets of the I2C registers */
> #define MXC_IADR                0x00  /* Address Register */
> #define MXC_IFDR                0x04  /* Freq div register */
> #define MXC_I2CR                0x08  /* Control regsiter */
> #define MXC_I2SR                0x0C  /* Status register */
> #define MXC_I2DR                0x10  /* Data I/O register */
> 
> /* Bit definitions of I2CR */
> #define MXC_I2CR_IEN            0x0080
> #define MXC_I2CR_IIEN           0x0040
> #define MXC_I2CR_MSTA           0x0020
> #define MXC_I2CR_MTX            0x0010
> #define MXC_I2CR_TXAK           0x0008
> #define MXC_I2CR_RSTA           0x0004
> 
> /* Bit definitions of I2SR */
> #define MXC_I2SR_ICF            0x0080
> #define MXC_I2SR_IAAS           0x0040
> #define MXC_I2SR_IBB            0x0020
> #define MXC_I2SR_IAL            0x0010
> #define MXC_I2SR_SRW            0x0004
> #define MXC_I2SR_IIF            0x0002
> #define MXC_I2SR_RXAK           0x0001
> 
> #define MXC_ADAPTER_NAME        "MXC I2C Adapter"
> 
> /*
>  * In case the MXC device has multiple I2C modules, this structure is used to
>  * store information specific to each I2C module.
>  */
> struct mxc_i2c_device {
>       struct i2c_adapter adap;
>       wait_queue_head_t wq;           /* Transfer completion wait queue */
>       void __iomem *membase;
>       int irq;
>       unsigned int clkdiv;            /* Default clock divider */
>       struct clk *clk;
>       bool low_power;                 /* Current power state */
>       bool transfer_done;
>       bool tx_success;                /* ACK received */
>       struct resource *res;
> };
> 
> struct clk_div_table {
>       int reg_value;
>       int div;
> };
> 
> static const struct clk_div_table i2c_clk_table[] = {
>       {0x20, 22}, {0x21, 24}, {0x22, 26}, {0x23, 28},
>       {0, 30}, {1, 32}, {0x24, 32}, {2, 36},
>       {0x25, 36}, {0x26, 40}, {3, 42}, {0x27, 44},
>       {4, 48}, {0x28, 48}, {5, 52}, {0x29, 56},
>       {6, 60}, {0x2A, 64}, {7, 72}, {0x2B, 72},
>       {8, 80}, {0x2C, 80}, {9, 88}, {0x2D, 96},
>       {0xA, 104}, {0x2E, 112}, {0xB, 128}, {0x2F, 128},
>       {0xC, 144}, {0xD, 160}, {0x30, 160}, {0xE, 192},
>       {0x31, 192}, {0x32, 224}, {0xF, 240}, {0x33, 256},
>       {0x10, 288}, {0x11, 320}, {0x34, 320}, {0x12, 384},
>       {0x35, 384}, {0x36, 448}, {0x13, 480}, {0x37, 512},
>       {0x14, 576}, {0x15, 640}, {0x38, 640}, {0x16, 768},
>       {0x39, 768}, {0x3A, 896}, {0x17, 960}, {0x3B, 1024},
>       {0x18, 1152}, {0x19, 1280}, {0x3C, 1280}, {0x1A, 1536},
>       {0x3D, 1536}, {0x3E, 1792}, {0x1B, 1920}, {0x3F, 2048},
>       {0x1C, 2304}, {0x1D, 2560}, {0x1E, 3072}, {0x1F, 3840},
>       {0, 0}
> };
> 
> /**
>  * Transmit a \b STOP signal to the slave device.
>  *
>  * @param   dev   the mxc i2c structure used to get to the right i2c device
>  */
> static void mxc_i2c_stop(struct mxc_i2c_device * dev)
> {
>       unsigned int cr;
>       int retry = 200;
> 
>       cr = readw(dev->membase + MXC_I2CR);
>       cr &= ~(MXC_I2CR_MSTA | MXC_I2CR_MTX);
>       writew(cr, dev->membase + MXC_I2CR);
> 
>       /*
>        * Make sure STOP meets setup requirement.
>        */
>       for (;;) {
>               unsigned int sr = readw(dev->membase + MXC_I2SR);
>               if ((sr & MXC_I2SR_IBB) == 0)
>                       break;
>               if (retry-- <= 0) {
>                       printk(KERN_DEBUG "Bus busy\n");
>                       break;
>               }
>               udelay(3);
>       }
> }
> 
> /**
>  * Wait for the transmission of the data byte to complete. This function waits
>  * till we get a signal from the interrupt service routine indicating 
> completion
>  * of the address cycle or we time out.
>  *
>  * @param   dev         the mxc i2c structure used to get to the right i2c 
> device
>  * @param   trans_flag  transfer flag
>  *
>  *
>  * @return  The function returns 0 on success or -1 if an ack was not received
>  */
> 
> static int mxc_i2c_wait_for_tc(struct mxc_i2c_device *dev, int trans_flag)
> {
>       int retry = 16;
> 
>       while (retry-- && !dev->transfer_done)
>               wait_event_interruptible_timeout(dev->wq,
>                                                dev->transfer_done,
>                                                dev->adap.timeout);
> 
>       dev->transfer_done = false;
> 
>       if (retry <= 0) {
>               /* Unable to send data */
>               dev_warn(&dev->adap.dev, "Data not transmitted\n");
>               return -ETIMEDOUT;
>       }
> 
>       if (!dev->tx_success) {
>               /* An ACK was not received for transmitted byte */
>               dev_dbg(&dev->adap.dev, "ACK not received \n");
>               return -EREMOTEIO;
>       }
> 
>       return 0;
> }
> 
> /**
>  * Transmit a \b START signal to the slave device.
>  *
>  * @param   dev   the mxc i2c structure used to get to the right i2c device
>  * @param   *msg  pointer to a message structure that contains the slave
>  *                address
>  */
> static void mxc_i2c_start(struct mxc_i2c_device *dev, struct i2c_msg *msg)
> {
>       unsigned int cr, sr;
>       unsigned int addr_trans;
>       int retry = 16;
> 
>       /*
>        * Set the slave address and the requested transfer mode
>        * in the data register
>        */
>       addr_trans = msg->addr << 1;
>       if (msg->flags & I2C_M_RD)
>               addr_trans |= 0x01;
> 
>       dev_dbg(&dev->adap.dev, "%s: start %x\n", __func__, msg->addr);
> 
>       /* Set the Master bit */
>       cr = readw(dev->membase + MXC_I2CR);
>       cr |= MXC_I2CR_MSTA;
>       writew(cr, dev->membase + MXC_I2CR);
> 
>       /* Wait till the Bus Busy bit is set */
>       sr = readw(dev->membase + MXC_I2SR);
>       while (retry-- && (!(sr & MXC_I2SR_IBB))) {
>               udelay(3);
>               sr = readw(dev->membase + MXC_I2SR);
>       }
>       if (retry <= 0)
>               dev_warn(&dev->adap.dev, "Could not grab Bus ownership\n");
> 
>       /* Set the Transmit bit */
>       cr = readw(dev->membase + MXC_I2CR);
>       cr |= MXC_I2CR_MTX;
>       writew(cr, dev->membase + MXC_I2CR);
> 
>       writew(addr_trans, dev->membase + MXC_I2DR);
> }
> 
> /**
>  * Transmit a \b REPEAT START to the slave device
>  *
>  * @param   dev   the mxc i2c structure used to get to the right i2c device
>  * @param   *msg  pointer to a message structure that contains the slave
>  *                address
>  */
> static void mxc_i2c_repstart(struct mxc_i2c_device *dev, struct i2c_msg *msg)
> {
>       unsigned int cr;
>       unsigned int addr_trans;
> 
>       /*
>        * Set the slave address and the requested transfer mode
>        * in the data register
>        */
>       addr_trans = msg->addr << 1;
>       if (msg->flags & I2C_M_RD)
>               addr_trans |= 0x01;
> 
>       dev_dbg(&dev->adap.dev, "%s: repeat start %x\n", __func__, msg->addr);
> 
>       cr = readw(dev->membase + MXC_I2CR);
>       cr |= MXC_I2CR_RSTA;
>       writew(cr, dev->membase + MXC_I2CR);
>       udelay(3);
>       writew(addr_trans, dev->membase + MXC_I2DR);
> }
> 
> /**
>  * Read the received data. The function waits till data is available or times
>  * out. Generates a stop signal if this is the last message to be received.
>  * Sends an ack for all the bytes received except the last byte.
>  *
>  * @param  dev       the mxc i2c structure used to get to the right i2c device
>  * @param  *msg      pointer to a message structure that contains the slave
>  *                   address and a pointer to the receive buffer
>  * @param  last      indicates that this is the last message to be received
>  * @param  addr_comp flag indicates that we just finished the address cycle
>  *
>  * @return  The function returns the number of bytes read or -1 on time out.
>  */
> static int mxc_i2c_readbytes(struct mxc_i2c_device *dev, struct i2c_msg *msg,
>                            int last, int addr_comp)
> {
>       int i;
>       char *buf = msg->buf;
>       int len = msg->len;
>       unsigned int cr;
> 
>       dev_dbg(&dev->adap.dev, "%s: last %d, addr_comp %d\n",
>               __func__, last, addr_comp);
> 
>       cr = readw(dev->membase + MXC_I2CR);
>       /*
>        * Clear MTX to switch to receive mode.
>        */
>       cr &= ~MXC_I2CR_MTX;
>       /*
>        * Clear the TXAK bit to gen an ack when receiving only one byte.
>        */
>       if (len == 1)
>               cr |= MXC_I2CR_TXAK;
>       else
>               cr &= ~MXC_I2CR_TXAK;
> 
>       writew(cr, dev->membase + MXC_I2CR);
>       /*
>        * Dummy read only at the end of an address cycle
>        */
>       if (addr_comp > 0)
>               readw(dev->membase + MXC_I2DR);
> 
>       for (i = 0; i < len; i++) {
>               int ret;
>               /*
>                * Wait for data transmission to complete
>                */
>               ret = mxc_i2c_wait_for_tc(dev, msg->flags);
>               if (ret < 0) {
>                       dev_err(&dev->adap.dev, "%s: rx #%d of %d failed!\n",
>                               __func__, i, len);
>                       mxc_i2c_stop(dev);
>                       return ret;
>               }
>               /*
>                * Do not generate an ACK for the last byte
>                */
>               if (i == len - 2) {
>                       cr = readw(dev->membase + MXC_I2CR);
>                       cr |= MXC_I2CR_TXAK;
>                       writew(cr, dev->membase + MXC_I2CR);
>               } else if (i == len - 1) {
>                       if (last)
>                               mxc_i2c_stop(dev);
>               }
>               /* Read the data */
>               *buf++ = readw(dev->membase + MXC_I2DR);
>       }
> 
>       return i;
> }
> 
> /**
>  * Write the data to the data register. Generates a stop signal if this is
>  * the last message to be sent or if no ack was received for the data sent.
>  *
>  * @param   dev   the mxc i2c structure used to get to the right i2c device
>  * @param   *msg  pointer to a message structure that contains the slave
>  *                address and data to be sent
>  * @param   last  indicates that this is the last message to be received
>  *
>  * @return  The function returns the number of bytes written or -1 on time out
>  *          or if no ack was received for the data that was sent.
>  */
> static int mxc_i2c_writebytes(struct mxc_i2c_device *dev, struct i2c_msg *msg,
>                             int last)
> {
>       int i;
>       char *buf = msg->buf;
>       int len = msg->len;
>       unsigned int cr;
> 
>       dev_dbg(&dev->adap.dev, "%s: last %d\n", __func__, last);
> 
>       cr = readw(dev->membase + MXC_I2CR);
>       /* Set MTX to switch to transmit mode */
>       writew(cr | MXC_I2CR_MTX, dev->membase + MXC_I2CR);
> 
>       for (i = 0; i < len; i++) {
>               int ret;
>               /*
>                * Write the data
>                */
>               writew(*buf++, dev->membase + MXC_I2DR);
>               ret = mxc_i2c_wait_for_tc(dev, msg->flags);
>               if (ret < 0) {
>                       dev_err(&dev->adap.dev, "%s: tx #%d of %d timed out!\n",
>                               __func__, i, len);
>                       mxc_i2c_stop(dev);
>                       return ret;
>               }
>       }
>       if (last > 0)
>               mxc_i2c_stop(dev);
> 
>       return i;
> }
> 
> /**
>  * Function enables the I2C module and initializes the registers.
>  *
>  * @param   dev   the mxc i2c structure used to get to the right i2c device
>  * @param   trans_flag  transfer flag
>  */
> static void mxc_i2c_module_en(struct mxc_i2c_device *dev, int trans_flag)
> {
>       clk_enable(dev->clk);
>       /* Set the frequency divider */
>       writew(dev->clkdiv, dev->membase + MXC_IFDR);
>       /* Clear the status register */
>       writew(0x0, dev->membase + MXC_I2SR);
>       /* Enable I2C and its interrupts */
>       writew(MXC_I2CR_IEN, dev->membase + MXC_I2CR);
>       writew(MXC_I2CR_IEN | MXC_I2CR_IIEN, dev->membase + MXC_I2CR);
> }
> 
> /**
>  * Disables the I2C module.
>  *
>  * @param   dev   the mxc i2c structure used to get to the right i2c device
>  */
> static void mxc_i2c_module_dis(struct mxc_i2c_device * dev)
> {
>       writew(0x0, dev->membase + MXC_I2CR);
>       clk_disable(dev->clk);
> }
> 
> /**
>  * The function is registered in the adapter structure. It is called when an 
> MXC
>  * driver wishes to transfer data to a device connected to the I2C device.
>  *
>  * @param   adap   adapter structure for the MXC i2c device
>  * @param   msgs[] array of messages to be transferred to the device
>  * @param   num    number of messages to be transferred to the device
>  *
>  * @return  The function returns the number of messages transferred,
>  *          \b -EREMOTEIO on I2C failure and a 0 if the num argument is
>  *          less than 0.
>  */
> static int mxc_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int 
> num)
> {
>       struct mxc_i2c_device *dev = i2c_get_adapdata(adap);
>       int i, ret = 0, addr_comp = 0;
>       unsigned int sr;
> 
>       if (dev->low_power) {
>               dev_warn(&dev->adap.dev, "I2C Device in low power mode\n");
>               return -EREMOTEIO;
>       }
> 
>       if (num < 1)
>               return 0;
> 
>       dev_dbg(&dev->adap.dev, "%s: xfer %d msgs\n", __func__, num);
> 
>       mxc_i2c_module_en(dev, msgs[0].flags);
>       sr = readw(dev->membase + MXC_I2SR);
>       /*
>        * Check bus state
>        */
>       if (sr & MXC_I2SR_IBB) {
>               mxc_i2c_module_dis(dev);
>               printk(KERN_DEBUG "Bus busy\n");
>               return -EREMOTEIO;
>       }
> 
>       dev->transfer_done = false;
>       dev->tx_success = false;
>       for (i = 0; i < num && ret >= 0; i++) {
>               addr_comp = 0;
>               /*
>                * Send the slave address and transfer direction in the
>                * address cycle
>                */
>               if (i == 0) {
>                       /*
>                        * Send a start or repeat start signal
>                        */
>                       mxc_i2c_start(dev, &msgs[0]);
>                       /* Wait for the address cycle to complete */
>                       if (mxc_i2c_wait_for_tc(dev, msgs[0].flags)) {
>                               mxc_i2c_stop(dev);
>                               mxc_i2c_module_dis(dev);
>                               dev_err(&dev->adap.dev,
>                                       "%s: Address failed!\n", __func__);
>                               return -EREMOTEIO;
>                       }
>                       addr_comp = 1;
>               } else {
>                       /*
>                        * Generate repeat start only if required i.e. the
>                        * address changed or the transfer direction changed
>                        */
>                       if ((msgs[i].addr != msgs[i - 1].addr) ||
>                           ((msgs[i].flags & I2C_M_RD) !=
>                            (msgs[i - 1].flags & I2C_M_RD))) {
>                               mxc_i2c_repstart(dev, &msgs[i]);
>                               /* Wait for the address cycle to complete */
>                               if (mxc_i2c_wait_for_tc(dev, msgs[i].flags)) {
>                                       mxc_i2c_stop(dev);
>                                       mxc_i2c_module_dis(dev);
>                                       dev_err(&dev->adap.dev,
>                                               "%s: Address repeat failed!\n",
>                                               __func__);
>                                       return -EREMOTEIO;
>                               }
>                               addr_comp = 1;
>                       }
>               }
> 
>               /* Transfer the data */
>               if (msgs[i].flags & I2C_M_RD) {
>                       /* Read the data */
>                       ret = mxc_i2c_readbytes(dev, &msgs[i], i + 1 == num,
>                                               addr_comp);
>                       if (ret < 0) {
>                               dev_err(&dev->adap.dev, "mxc_i2c_readbytes: 
> fail.\n");
>                               break;
>                       }
>               } else {
>                       /* Write the data */
>                       ret = mxc_i2c_writebytes(dev, &msgs[i], i + 1 == num);
>                       if (ret < 0) {
>                               dev_err(&dev->adap.dev, "mxc_i2c_writebytes: 
> fail.\n");
>                               break;
>                       }
>               }
>       }
> 
>       mxc_i2c_module_dis(dev);
> 
>       dev_dbg(&dev->adap.dev, "%s: %d msgs success\n", __func__, i);
> 
>       /*
>        * Decrease by 1 as we do not want Start message to be included in
>        * the count
>        */
>       return i;
> }
> 
> /**
>  * Returns the i2c functionality supported by this driver.
>  *
>  * @param   adap adapter structure for this i2c device
>  *
>  * @return Returns the functionality that is supported.
>  */
> static u32 mxc_i2c_func(struct i2c_adapter *adap)
> {
>       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
> }
> 
> static struct i2c_algorithm mxc_i2c_algorithm = {
>       .master_xfer = mxc_i2c_xfer,
>       .functionality = mxc_i2c_func
> };
> 
> /*
>  * Interrupt Service Routine. It signals to the process about the data 
> transfer
>  * completion. Also sets a flag if bus arbitration is lost.
>  */
> static irqreturn_t mxc_i2c_handler(int irq, void *dev_id)
> {
>       struct mxc_i2c_device *dev = dev_id;
>       unsigned int sr, cr;
> 
>       sr = readw(dev->membase + MXC_I2SR);
>       cr = readw(dev->membase + MXC_I2CR);
> 
>       /*
>        * Clear the interrupt bit
>        */
>       writew(0x0, dev->membase + MXC_I2SR);
> 
>       if (sr & MXC_I2SR_IAL) {
>               printk(KERN_DEBUG "Bus Arbitration lost\n");
>       } else {
>               /* Interrupt due byte transfer completion */
>               dev->tx_success = true;
>               /* Check if RXAK is received in Transmit mode */
>               if ((cr & MXC_I2CR_MTX) && (sr & MXC_I2SR_RXAK))
>                       dev->tx_success = false;
> 
>               dev->transfer_done = true;
>               wake_up_interruptible(&dev->wq);
>       }
> 
>       return IRQ_HANDLED;
> }
> 
> static int mxci2c_suspend(struct platform_device *pdev, pm_message_t state)
> {
>       struct mxc_i2c_device *mxcdev = platform_get_drvdata(pdev);
>       struct imxi2c_platform_data *i2c_plat_data = pdev->dev.platform_data;
>       unsigned int sr;
> 
>       if (mxcdev == NULL)
>               return -ENODEV;
> 
>       /* Prevent further calls to be processed */
>       mxcdev->low_power = true;
>       /* Wait till we finish the current transfer */
>       sr = readw(mxcdev->membase + MXC_I2SR);
>       while (sr & MXC_I2SR_IBB) {
>               msleep(10);
>               sr = readw(mxcdev->membase + MXC_I2SR);
>       }
> 
>       if (i2c_plat_data->exit)
>               i2c_plat_data->exit(&pdev->dev);
> 
>       return 0;
> }
> 
> static int mxci2c_resume(struct platform_device *pdev)
> {
>       struct mxc_i2c_device *mxcdev = platform_get_drvdata(pdev);
>       struct imxi2c_platform_data *i2c_plat_data = pdev->dev.platform_data;
> 
>       if (mxcdev == NULL)
>               return -ENODEV;
> 
>       mxcdev->low_power = false;
>       if (i2c_plat_data->init)
>               i2c_plat_data->init(&pdev->dev);
> 
>       return 0;
> }
> 
> static int __init mxci2c_probe(struct platform_device *pdev)
> {
>       struct mxc_i2c_device *mxc_i2c;
>       struct imxi2c_platform_data *i2c_plat_data = pdev->dev.platform_data;
>       struct resource *res;
>       int id = pdev->id;
>       u32 clk_freq;
>       int ret;
>       int i;
> 
>       mxc_i2c = kzalloc(sizeof(struct mxc_i2c_device), GFP_KERNEL);
>       if (!mxc_i2c)
>               return -ENOMEM;
> 
>       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>       if (res == NULL) {
>               ret = -ENODEV;
>               goto egetres;
>       }
> 
>       if (!request_mem_region(res->start, resource_size(res), res->name)) {
>               ret = -ENOMEM;
>               goto ereqmemr;
>       }
> 
>       mxc_i2c->membase = ioremap(res->start, resource_size(res));
>       if (!mxc_i2c->membase) {
>               ret = -ENOMEM;
>               goto eiomap;
>       }
> 
>       mxc_i2c->res = res;
> 
>       /*
>        * Request the I2C interrupt
>        */
>       mxc_i2c->irq = platform_get_irq(pdev, 0);
>       if (mxc_i2c->irq < 0) {
>               ret = mxc_i2c->irq;
>               goto epgirq;
>       }
> 
>       ret = request_irq(mxc_i2c->irq, mxc_i2c_handler,
>                         0, pdev->name, mxc_i2c);
>       if (ret < 0)
>               goto ereqirq;
> 
>       init_waitqueue_head(&mxc_i2c->wq);
> 
>       mxc_i2c->low_power      = false;
>       mxc_i2c->transfer_done  = false;
>       mxc_i2c->tx_success     = false;
> 
>       if (i2c_plat_data->init)
>               i2c_plat_data->init(&pdev->dev);
> 
>       mxc_i2c->clk = clk_get(&pdev->dev, "i2c_clk");
>       if (IS_ERR(mxc_i2c->clk)) {
>               ret = PTR_ERR(mxc_i2c->clk);
>               dev_err(&pdev->dev, "can't get I2C clock\n");
>               goto eclkget;
>       }
>       clk_freq = clk_get_rate(mxc_i2c->clk);
> 
>       mxc_i2c->clkdiv = -1;
>       if (i2c_plat_data->bitrate) {
>               /* Calculate divider and round up any fractional part */
>               int div = (clk_freq + i2c_plat_data->bitrate - 1) /
>                       i2c_plat_data->bitrate;
>               for (i = 0; i2c_clk_table[i].div != 0; i++) {
>                       if (i2c_clk_table[i].div >= div) {
>                               mxc_i2c->clkdiv = i2c_clk_table[i].reg_value;
>                               break;
>                       }
>               }
>       }
>       if (mxc_i2c->clkdiv == -1) {
>               i = ARRAY_SIZE(i2c_clk_table) - 2;
>               /* Use max divider */
>               mxc_i2c->clkdiv = i2c_clk_table[i].reg_value;
>       }
>       dev_dbg(&pdev->dev, "i2c speed is %d/%d = %d bps, reg val = 0x%02X\n",
>               clk_freq, i2c_clk_table[i].div, clk_freq / i2c_clk_table[i].div,
>               mxc_i2c->clkdiv);
> 
>       /*
>        * Set the adapter information
>        */
>       strcpy(mxc_i2c->adap.name, MXC_ADAPTER_NAME);
>       mxc_i2c->adap.nr        = id;
>       mxc_i2c->adap.algo      = &mxc_i2c_algorithm;
>       mxc_i2c->adap.timeout   = 1;
>       mxc_i2c->adap.dev.parent= &pdev->dev;
>       mxc_i2c->adap.class     = I2C_CLASS_HWMON | I2C_CLASS_SPD;
>       platform_set_drvdata(pdev, mxc_i2c);
>       i2c_set_adapdata(&mxc_i2c->adap, mxc_i2c);
>       if ((ret = i2c_add_numbered_adapter(&mxc_i2c->adap)) < 0)
>               goto eaddadap;
> 
>       return 0;
> 
> eaddadap:
>       platform_set_drvdata(pdev, NULL);
>       clk_put(mxc_i2c->clk);
> eclkget:
>       if (i2c_plat_data->exit)
>               i2c_plat_data->exit(&pdev->dev);
>       free_irq(mxc_i2c->irq, mxc_i2c);
> ereqirq:
> epgirq:
>       iounmap(mxc_i2c->membase);
> eiomap:
>       release_mem_region(res->start, resource_size(res));
> ereqmemr:
> egetres:
>       kfree(mxc_i2c);
>       dev_err(&pdev->dev, "failed to probe i2c adapter\n");
>       return ret;
> }
> 
> static int __exit mxci2c_remove(struct platform_device *pdev)
> {
>       struct mxc_i2c_device *mxc_i2c = platform_get_drvdata(pdev);
>       struct imxi2c_platform_data *i2c_plat_data = pdev->dev.platform_data;
> 
>       free_irq(mxc_i2c->irq, mxc_i2c);
>       i2c_del_adapter(&mxc_i2c->adap);
>       if (i2c_plat_data->exit)
>               i2c_plat_data->exit(&pdev->dev);
>       clk_put(mxc_i2c->clk);
>       platform_set_drvdata(pdev, NULL);
>       iounmap(mxc_i2c->membase);
>       release_mem_region(mxc_i2c->res->start, resource_size(mxc_i2c->res));
>       kfree(mxc_i2c);
>       return 0;
> }
> 
> static struct platform_driver mxci2c_driver = {
>       .driver = {
>                  .name = "imx-i2c",
>                  .owner = THIS_MODULE,
>       },
>       .remove = __exit_p(mxci2c_remove),
>       .suspend = mxci2c_suspend,
>       .resume = mxci2c_resume,
> };
> 
> static int __init mxc_i2c_init(void)
> {
>       return platform_driver_probe(&mxci2c_driver, mxci2c_probe);
> }
> 
> static void __exit mxc_i2c_exit(void)
> {
>       platform_driver_unregister(&mxci2c_driver);
> }
> 
> subsys_initcall(mxc_i2c_init);
> module_exit(mxc_i2c_exit);
> 
> MODULE_AUTHOR("Freescale Semiconductor, Inc.");
> MODULE_DESCRIPTION("MXC I2C driver");
> MODULE_LICENSE("GPL");


-- 
Ben ([email protected], http://www.fluff.org/)

  'a smiley only costs 4 bytes'
--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to