| /* drivers/i2c/busses/i2c-msm.c |
| * |
| * Copyright (C) 2007 Google, Inc. |
| * Copyright (c) 2009, The Linux Foundation. All rights reserved. |
| * |
| * This software is licensed under the terms of the GNU General Public |
| * License version 2, as published by the Free Software Foundation, and |
| * may be copied, distributed, and modified under those terms. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| */ |
| |
| /* #define DEBUG */ |
| |
| #include <linux/slab.h> |
| #include <linux/clk.h> |
| #include <linux/err.h> |
| #include <linux/init.h> |
| #include <linux/i2c.h> |
| #include <linux/interrupt.h> |
| #include <linux/irq.h> |
| #include <linux/platform_device.h> |
| #include <linux/delay.h> |
| #include <linux/io.h> |
| #include <mach/board.h> |
| #include <linux/mutex.h> |
| #include <linux/timer.h> |
| #include <linux/remote_spinlock.h> |
| #include <linux/pm_qos.h> |
| #include <linux/gpio.h> |
| #include <linux/module.h> |
| |
| |
| enum { |
| I2C_WRITE_DATA = 0x00, |
| I2C_CLK_CTL = 0x04, |
| I2C_STATUS = 0x08, |
| I2C_READ_DATA = 0x0c, |
| I2C_INTERFACE_SELECT = 0x10, |
| |
| I2C_WRITE_DATA_DATA_BYTE = 0xff, |
| I2C_WRITE_DATA_ADDR_BYTE = 1U << 8, |
| I2C_WRITE_DATA_LAST_BYTE = 1U << 9, |
| |
| I2C_CLK_CTL_FS_DIVIDER_VALUE = 0xff, |
| I2C_CLK_CTL_HS_DIVIDER_VALUE = 7U << 8, |
| |
| I2C_STATUS_WR_BUFFER_FULL = 1U << 0, |
| I2C_STATUS_RD_BUFFER_FULL = 1U << 1, |
| I2C_STATUS_BUS_ERROR = 1U << 2, |
| I2C_STATUS_PACKET_NACKED = 1U << 3, |
| I2C_STATUS_ARB_LOST = 1U << 4, |
| I2C_STATUS_INVALID_WRITE = 1U << 5, |
| I2C_STATUS_FAILED = 3U << 6, |
| I2C_STATUS_BUS_ACTIVE = 1U << 8, |
| I2C_STATUS_BUS_MASTER = 1U << 9, |
| I2C_STATUS_ERROR_MASK = 0xfc, |
| |
| I2C_INTERFACE_SELECT_INTF_SELECT = 1U << 0, |
| I2C_INTERFACE_SELECT_SCL = 1U << 8, |
| I2C_INTERFACE_SELECT_SDA = 1U << 9, |
| I2C_STATUS_RX_DATA_STATE = 3U << 11, |
| I2C_STATUS_LOW_CLK_STATE = 3U << 13, |
| }; |
| |
| struct msm_i2c_dev { |
| struct device *dev; |
| void __iomem *base; /* virtual */ |
| int irq; |
| struct clk *clk; |
| struct i2c_adapter adap_pri; |
| struct i2c_adapter adap_aux; |
| |
| spinlock_t lock; |
| |
| struct i2c_msg *msg; |
| int rem; |
| int pos; |
| int cnt; |
| int err; |
| int flush_cnt; |
| int rd_acked; |
| int one_bit_t; |
| remote_mutex_t r_lock; |
| int suspended; |
| struct mutex mlock; |
| struct msm_i2c_platform_data *pdata; |
| struct timer_list pwr_timer; |
| int clk_state; |
| void *complete; |
| |
| struct pm_qos_request pm_qos_req; |
| }; |
| |
| static void |
| msm_i2c_pwr_mgmt(struct msm_i2c_dev *dev, unsigned int state) |
| { |
| dev->clk_state = state; |
| if (state != 0) |
| clk_enable(dev->clk); |
| else |
| clk_disable(dev->clk); |
| } |
| |
| static void |
| msm_i2c_pwr_timer(unsigned long data) |
| { |
| struct msm_i2c_dev *dev = (struct msm_i2c_dev *) data; |
| dev_dbg(dev->dev, "I2C_Power: Inactivity based power management\n"); |
| if (dev->clk_state == 1) |
| msm_i2c_pwr_mgmt(dev, 0); |
| } |
| |
| #ifdef DEBUG |
| static void |
| dump_status(uint32_t status) |
| { |
| printk("STATUS (0x%.8x): ", status); |
| if (status & I2C_STATUS_BUS_MASTER) |
| printk("MST "); |
| if (status & I2C_STATUS_BUS_ACTIVE) |
| printk("ACT "); |
| if (status & I2C_STATUS_INVALID_WRITE) |
| printk("INV_WR "); |
| if (status & I2C_STATUS_ARB_LOST) |
| printk("ARB_LST "); |
| if (status & I2C_STATUS_PACKET_NACKED) |
| printk("NAK "); |
| if (status & I2C_STATUS_BUS_ERROR) |
| printk("BUS_ERR "); |
| if (status & I2C_STATUS_RD_BUFFER_FULL) |
| printk("RD_FULL "); |
| if (status & I2C_STATUS_WR_BUFFER_FULL) |
| printk("WR_FULL "); |
| if (status & I2C_STATUS_FAILED) |
| printk("FAIL 0x%x", (status & I2C_STATUS_FAILED)); |
| printk("\n"); |
| } |
| #endif |
| |
| static irqreturn_t |
| msm_i2c_interrupt(int irq, void *devid) |
| { |
| struct msm_i2c_dev *dev = devid; |
| uint32_t status = readl(dev->base + I2C_STATUS); |
| int err = 0; |
| |
| #ifdef DEBUG |
| dump_status(status); |
| #endif |
| |
| spin_lock(&dev->lock); |
| if (!dev->msg) { |
| printk(KERN_ERR "%s: IRQ but nothing to do!\n", __func__); |
| spin_unlock(&dev->lock); |
| return IRQ_HANDLED; |
| } |
| |
| if (status & I2C_STATUS_ERROR_MASK) { |
| err = -EIO; |
| goto out_err; |
| } |
| |
| if (dev->msg->flags & I2C_M_RD) { |
| if (status & I2C_STATUS_RD_BUFFER_FULL) { |
| |
| /* |
| * Theres something in the FIFO. |
| * Are we expecting data or flush crap? |
| */ |
| if (dev->cnt) { /* DATA */ |
| uint8_t *data = &dev->msg->buf[dev->pos]; |
| |
| /* This is in spin-lock. So there will be no |
| * scheduling between reading the second-last |
| * byte and writing LAST_BYTE to the controller. |
| * So extra read-cycle-clock won't be generated |
| * Per I2C MSM HW Specs: Write LAST_BYTE befure |
| * reading 2nd last byte |
| */ |
| if (dev->cnt == 2) |
| writel(I2C_WRITE_DATA_LAST_BYTE, |
| dev->base + I2C_WRITE_DATA); |
| *data = readl(dev->base + I2C_READ_DATA); |
| dev->cnt--; |
| dev->pos++; |
| if (dev->msg->len == 1) |
| dev->rd_acked = 0; |
| if (dev->cnt == 0) |
| goto out_complete; |
| |
| } else { |
| /* Now that extra read-cycle-clocks aren't |
| * generated, this becomes error condition |
| */ |
| dev_err(dev->dev, |
| "read did not stop, status - %x\n", |
| status); |
| err = -EIO; |
| goto out_err; |
| } |
| } else if (dev->msg->len == 1 && dev->rd_acked == 0 && |
| ((status & I2C_STATUS_RX_DATA_STATE) == |
| I2C_STATUS_RX_DATA_STATE)) |
| writel(I2C_WRITE_DATA_LAST_BYTE, |
| dev->base + I2C_WRITE_DATA); |
| } else { |
| uint16_t data; |
| |
| if (status & I2C_STATUS_WR_BUFFER_FULL) { |
| dev_err(dev->dev, |
| "Write buffer full in ISR on write?\n"); |
| err = -EIO; |
| goto out_err; |
| } |
| |
| if (dev->cnt) { |
| /* Ready to take a byte */ |
| data = dev->msg->buf[dev->pos]; |
| if (dev->cnt == 1 && dev->rem == 1) |
| data |= I2C_WRITE_DATA_LAST_BYTE; |
| |
| status = readl(dev->base + I2C_STATUS); |
| /* |
| * Due to a hardware timing issue, data line setup time |
| * may be reduced to less than recommended 250 ns. |
| * This happens when next byte is written in a |
| * particular window of clock line being low and master |
| * not stretching the clock line. Due to setup time |
| * violation, some slaves may miss first-bit of data, or |
| * misinterprete data as start condition. |
| * We introduce delay of just over 1/2 clock cycle to |
| * ensure master stretches the clock line thereby |
| * avoiding setup time violation. Delay is introduced |
| * only if I2C clock FSM is LOW. The delay is not needed |
| * if I2C clock FSM is HIGH or FORCED_LOW. |
| */ |
| if ((status & I2C_STATUS_LOW_CLK_STATE) == |
| I2C_STATUS_LOW_CLK_STATE) |
| udelay((dev->one_bit_t >> 1) + 1); |
| writel(data, dev->base + I2C_WRITE_DATA); |
| dev->pos++; |
| dev->cnt--; |
| } else |
| goto out_complete; |
| } |
| |
| spin_unlock(&dev->lock); |
| return IRQ_HANDLED; |
| |
| out_err: |
| dev->err = err; |
| out_complete: |
| complete(dev->complete); |
| spin_unlock(&dev->lock); |
| return IRQ_HANDLED; |
| } |
| |
| static int |
| msm_i2c_poll_writeready(struct msm_i2c_dev *dev) |
| { |
| uint32_t retries = 0; |
| |
| while (retries != 2000) { |
| uint32_t status = readl(dev->base + I2C_STATUS); |
| |
| if (!(status & I2C_STATUS_WR_BUFFER_FULL)) |
| return 0; |
| if (retries++ > 1000) |
| usleep_range(100, 200); |
| } |
| return -ETIMEDOUT; |
| } |
| |
| static int |
| msm_i2c_poll_notbusy(struct msm_i2c_dev *dev) |
| { |
| uint32_t retries = 0; |
| |
| while (retries != 2000) { |
| uint32_t status = readl(dev->base + I2C_STATUS); |
| |
| if (!(status & I2C_STATUS_BUS_ACTIVE)) |
| return 0; |
| if (retries++ > 1000) |
| usleep_range(100, 200); |
| } |
| return -ETIMEDOUT; |
| } |
| |
| static int |
| msm_i2c_recover_bus_busy(struct msm_i2c_dev *dev, struct i2c_adapter *adap) |
| { |
| int i; |
| int gpio_clk; |
| int gpio_dat; |
| uint32_t status = readl(dev->base + I2C_STATUS); |
| bool gpio_clk_status = false; |
| |
| if (!(status & (I2C_STATUS_BUS_ACTIVE | I2C_STATUS_WR_BUFFER_FULL))) |
| return 0; |
| |
| dev->pdata->msm_i2c_config_gpio(adap->nr, 0); |
| /* Even adapter is primary and Odd adapter is AUX */ |
| if (adap->nr % 2) { |
| gpio_clk = dev->pdata->aux_clk; |
| gpio_dat = dev->pdata->aux_dat; |
| } else { |
| gpio_clk = dev->pdata->pri_clk; |
| gpio_dat = dev->pdata->pri_dat; |
| } |
| |
| disable_irq(dev->irq); |
| if (status & I2C_STATUS_RD_BUFFER_FULL) { |
| dev_warn(dev->dev, "Read buffer full, status %x, intf %x\n", |
| status, readl(dev->base + I2C_INTERFACE_SELECT)); |
| writel(I2C_WRITE_DATA_LAST_BYTE, dev->base + I2C_WRITE_DATA); |
| readl(dev->base + I2C_READ_DATA); |
| } else if (status & I2C_STATUS_BUS_MASTER) { |
| dev_warn(dev->dev, "Still the bus master, status %x, intf %x\n", |
| status, readl(dev->base + I2C_INTERFACE_SELECT)); |
| writel(I2C_WRITE_DATA_LAST_BYTE | 0xff, |
| dev->base + I2C_WRITE_DATA); |
| } |
| |
| for (i = 0; i < 9; i++) { |
| if (gpio_get_value(gpio_dat) && gpio_clk_status) |
| break; |
| gpio_direction_output(gpio_clk, 0); |
| udelay(5); |
| gpio_direction_output(gpio_dat, 0); |
| udelay(5); |
| gpio_direction_input(gpio_clk); |
| udelay(5); |
| if (!gpio_get_value(gpio_clk)) |
| usleep_range(20, 30); |
| if (!gpio_get_value(gpio_clk)) |
| msleep(10); |
| gpio_clk_status = gpio_get_value(gpio_clk); |
| gpio_direction_input(gpio_dat); |
| udelay(5); |
| } |
| dev->pdata->msm_i2c_config_gpio(adap->nr, 1); |
| udelay(10); |
| |
| status = readl(dev->base + I2C_STATUS); |
| if (!(status & I2C_STATUS_BUS_ACTIVE)) { |
| dev_info(dev->dev, "Bus busy cleared after %d clock cycles, " |
| "status %x, intf %x\n", |
| i, status, readl(dev->base + I2C_INTERFACE_SELECT)); |
| enable_irq(dev->irq); |
| return 0; |
| } |
| |
| dev_err(dev->dev, "Bus still busy, status %x, intf %x\n", |
| status, readl(dev->base + I2C_INTERFACE_SELECT)); |
| enable_irq(dev->irq); |
| return -EBUSY; |
| } |
| |
| static int |
| msm_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) |
| { |
| DECLARE_COMPLETION_ONSTACK(complete); |
| struct msm_i2c_dev *dev = i2c_get_adapdata(adap); |
| int ret; |
| int rem = num; |
| uint16_t addr; |
| long timeout; |
| unsigned long flags; |
| int check_busy = 1; |
| |
| del_timer_sync(&dev->pwr_timer); |
| mutex_lock(&dev->mlock); |
| if (dev->suspended) { |
| mutex_unlock(&dev->mlock); |
| return -EIO; |
| } |
| |
| if (dev->clk_state == 0) { |
| dev_dbg(dev->dev, "I2C_Power: Enable I2C clock(s)\n"); |
| msm_i2c_pwr_mgmt(dev, 1); |
| } |
| |
| /* Don't allow power collapse until we release remote spinlock */ |
| pm_qos_update_request(&dev->pm_qos_req, dev->pdata->pm_lat); |
| if (dev->pdata->rmutex) { |
| remote_mutex_lock(&dev->r_lock); |
| /* If other processor did some transactions, we may have |
| * interrupt pending. Clear it |
| */ |
| irq_get_chip(dev->irq)->irq_ack(irq_get_irq_data(dev->irq)); |
| } |
| |
| if (adap == &dev->adap_pri) |
| writel(0, dev->base + I2C_INTERFACE_SELECT); |
| else |
| writel(I2C_INTERFACE_SELECT_INTF_SELECT, |
| dev->base + I2C_INTERFACE_SELECT); |
| enable_irq(dev->irq); |
| while (rem) { |
| addr = msgs->addr << 1; |
| if (msgs->flags & I2C_M_RD) |
| addr |= 1; |
| |
| spin_lock_irqsave(&dev->lock, flags); |
| dev->msg = msgs; |
| dev->rem = rem; |
| dev->pos = 0; |
| dev->err = 0; |
| dev->flush_cnt = 0; |
| dev->cnt = msgs->len; |
| dev->complete = &complete; |
| spin_unlock_irqrestore(&dev->lock, flags); |
| |
| if (check_busy) { |
| ret = msm_i2c_poll_notbusy(dev); |
| if (ret) |
| ret = msm_i2c_recover_bus_busy(dev, adap); |
| if (ret) { |
| dev_err(dev->dev, |
| "Error waiting for notbusy\n"); |
| goto out_err; |
| } |
| check_busy = 0; |
| } |
| |
| if (rem == 1 && msgs->len == 0) |
| addr |= I2C_WRITE_DATA_LAST_BYTE; |
| |
| /* Wait for WR buffer not full */ |
| ret = msm_i2c_poll_writeready(dev); |
| if (ret) { |
| ret = msm_i2c_recover_bus_busy(dev, adap); |
| if (ret) { |
| dev_err(dev->dev, |
| "Error waiting for write ready before addr\n"); |
| goto out_err; |
| } |
| } |
| |
| /* special case for doing 1 byte read. |
| * There should be no scheduling between I2C controller becoming |
| * ready to read and writing LAST-BYTE to I2C controller |
| * This will avoid potential of I2C controller starting to latch |
| * another extra byte. |
| */ |
| if ((msgs->len == 1) && (msgs->flags & I2C_M_RD)) { |
| uint32_t retries = 0; |
| spin_lock_irqsave(&dev->lock, flags); |
| |
| writel(I2C_WRITE_DATA_ADDR_BYTE | addr, |
| dev->base + I2C_WRITE_DATA); |
| |
| /* Poll for I2C controller going into RX_DATA mode to |
| * ensure controller goes into receive mode. |
| * Just checking write_buffer_full may not work since |
| * there is delay between the write-buffer becoming |
| * empty and the slave sending ACK to ensure I2C |
| * controller goes in receive mode to receive data. |
| */ |
| while (retries != 2000) { |
| uint32_t status = readl(dev->base + I2C_STATUS); |
| |
| if ((status & I2C_STATUS_RX_DATA_STATE) |
| == I2C_STATUS_RX_DATA_STATE) |
| break; |
| retries++; |
| } |
| if (retries >= 2000) { |
| dev->rd_acked = 0; |
| spin_unlock_irqrestore(&dev->lock, flags); |
| /* 1-byte-reads from slow devices in interrupt |
| * context |
| */ |
| goto wait_for_int; |
| } |
| |
| dev->rd_acked = 1; |
| writel(I2C_WRITE_DATA_LAST_BYTE, |
| dev->base + I2C_WRITE_DATA); |
| spin_unlock_irqrestore(&dev->lock, flags); |
| } else { |
| writel(I2C_WRITE_DATA_ADDR_BYTE | addr, |
| dev->base + I2C_WRITE_DATA); |
| } |
| /* Polling and waiting for write_buffer_empty is not necessary. |
| * Even worse, if we do, it can result in invalid status and |
| * error if interrupt(s) occur while polling. |
| */ |
| |
| /* |
| * Now that we've setup the xfer, the ISR will transfer the data |
| * and wake us up with dev->err set if there was an error |
| */ |
| wait_for_int: |
| |
| timeout = wait_for_completion_timeout(&complete, HZ); |
| if (!timeout) { |
| dev_err(dev->dev, "Transaction timed out\n"); |
| writel(I2C_WRITE_DATA_LAST_BYTE, |
| dev->base + I2C_WRITE_DATA); |
| msleep(100); |
| /* FLUSH */ |
| readl(dev->base + I2C_READ_DATA); |
| readl(dev->base + I2C_STATUS); |
| ret = -ETIMEDOUT; |
| goto out_err; |
| } |
| if (dev->err) { |
| dev_err(dev->dev, |
| "(%04x) Error during data xfer (%d)\n", |
| addr, dev->err); |
| ret = dev->err; |
| goto out_err; |
| } |
| |
| if (msgs->flags & I2C_M_RD) |
| check_busy = 1; |
| |
| msgs++; |
| rem--; |
| } |
| |
| ret = num; |
| out_err: |
| spin_lock_irqsave(&dev->lock, flags); |
| dev->complete = NULL; |
| dev->msg = NULL; |
| dev->rem = 0; |
| dev->pos = 0; |
| dev->err = 0; |
| dev->flush_cnt = 0; |
| dev->cnt = 0; |
| spin_unlock_irqrestore(&dev->lock, flags); |
| disable_irq(dev->irq); |
| if (dev->pdata->rmutex) |
| remote_mutex_unlock(&dev->r_lock); |
| pm_qos_update_request(&dev->pm_qos_req, |
| PM_QOS_DEFAULT_VALUE); |
| mod_timer(&dev->pwr_timer, (jiffies + 3*HZ)); |
| mutex_unlock(&dev->mlock); |
| return ret; |
| } |
| |
| static u32 |
| msm_i2c_func(struct i2c_adapter *adap) |
| { |
| return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); |
| } |
| |
| static const struct i2c_algorithm msm_i2c_algo = { |
| .master_xfer = msm_i2c_xfer, |
| .functionality = msm_i2c_func, |
| }; |
| |
| static int |
| msm_i2c_probe(struct platform_device *pdev) |
| { |
| struct msm_i2c_dev *dev; |
| struct resource *mem, *irq, *ioarea; |
| int ret; |
| int fs_div; |
| int hs_div; |
| int i2c_clk; |
| int clk_ctl; |
| struct clk *clk; |
| struct msm_i2c_platform_data *pdata; |
| |
| printk(KERN_INFO "msm_i2c_probe\n"); |
| |
| /* NOTE: driver uses the static register mapping */ |
| mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| if (!mem) { |
| dev_err(&pdev->dev, "no mem resource?\n"); |
| return -ENODEV; |
| } |
| irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
| if (!irq) { |
| dev_err(&pdev->dev, "no irq resource?\n"); |
| return -ENODEV; |
| } |
| |
| ioarea = request_mem_region(mem->start, (mem->end - mem->start) + 1, |
| pdev->name); |
| if (!ioarea) { |
| dev_err(&pdev->dev, "I2C region already claimed\n"); |
| return -EBUSY; |
| } |
| clk = clk_get(&pdev->dev, "core_clk"); |
| if (IS_ERR(clk)) { |
| dev_err(&pdev->dev, "Could not get clock\n"); |
| ret = PTR_ERR(clk); |
| goto err_clk_get_failed; |
| } |
| |
| pdata = pdev->dev.platform_data; |
| if (!pdata) { |
| dev_err(&pdev->dev, "platform data not initialized\n"); |
| ret = -ENOSYS; |
| goto err_clk_get_failed; |
| } |
| if (!pdata->msm_i2c_config_gpio) { |
| dev_err(&pdev->dev, "config_gpio function not initialized\n"); |
| ret = -ENOSYS; |
| goto err_clk_get_failed; |
| } |
| /* We support frequencies upto FAST Mode(400KHz) */ |
| if (pdata->clk_freq <= 0 || pdata->clk_freq > 400000) { |
| dev_err(&pdev->dev, "clock frequency not supported\n"); |
| ret = -EIO; |
| goto err_clk_get_failed; |
| } |
| |
| dev = kzalloc(sizeof(struct msm_i2c_dev), GFP_KERNEL); |
| if (!dev) { |
| ret = -ENOMEM; |
| goto err_alloc_dev_failed; |
| } |
| |
| dev->dev = &pdev->dev; |
| dev->irq = irq->start; |
| dev->clk = clk; |
| dev->pdata = pdata; |
| dev->base = ioremap(mem->start, (mem->end - mem->start) + 1); |
| if (!dev->base) { |
| ret = -ENOMEM; |
| goto err_ioremap_failed; |
| } |
| |
| dev->one_bit_t = USEC_PER_SEC/pdata->clk_freq; |
| spin_lock_init(&dev->lock); |
| platform_set_drvdata(pdev, dev); |
| |
| clk_prepare_enable(clk); |
| |
| if (pdata->rmutex) { |
| struct remote_mutex_id rmid; |
| rmid.r_spinlock_id = pdata->rsl_id; |
| rmid.delay_us = 10000000/pdata->clk_freq; |
| if (remote_mutex_init(&dev->r_lock, &rmid) != 0) |
| pdata->rmutex = 0; |
| } |
| /* I2C_HS_CLK = I2C_CLK/(3*(HS_DIVIDER_VALUE+1) */ |
| /* I2C_FS_CLK = I2C_CLK/(2*(FS_DIVIDER_VALUE+3) */ |
| /* FS_DIVIDER_VALUE = ((I2C_CLK / I2C_FS_CLK) / 2) - 3 */ |
| i2c_clk = 19200000; /* input clock */ |
| fs_div = ((i2c_clk / pdata->clk_freq) / 2) - 3; |
| hs_div = 3; |
| clk_ctl = ((hs_div & 0x7) << 8) | (fs_div & 0xff); |
| writel(clk_ctl, dev->base + I2C_CLK_CTL); |
| printk(KERN_INFO "msm_i2c_probe: clk_ctl %x, %d Hz\n", |
| clk_ctl, i2c_clk / (2 * ((clk_ctl & 0xff) + 3))); |
| |
| i2c_set_adapdata(&dev->adap_pri, dev); |
| dev->adap_pri.algo = &msm_i2c_algo; |
| strlcpy(dev->adap_pri.name, |
| "MSM I2C adapter-PRI", |
| sizeof(dev->adap_pri.name)); |
| |
| dev->adap_pri.nr = pdev->id; |
| ret = i2c_add_numbered_adapter(&dev->adap_pri); |
| if (ret) { |
| dev_err(&pdev->dev, "Primary i2c_add_adapter failed\n"); |
| goto err_i2c_add_adapter_failed; |
| } |
| |
| i2c_set_adapdata(&dev->adap_aux, dev); |
| dev->adap_aux.algo = &msm_i2c_algo; |
| strlcpy(dev->adap_aux.name, |
| "MSM I2C adapter-AUX", |
| sizeof(dev->adap_aux.name)); |
| |
| dev->adap_aux.nr = pdev->id + 1; |
| ret = i2c_add_numbered_adapter(&dev->adap_aux); |
| if (ret) { |
| dev_err(&pdev->dev, "auxiliary i2c_add_adapter failed\n"); |
| i2c_del_adapter(&dev->adap_pri); |
| goto err_i2c_add_adapter_failed; |
| } |
| ret = request_irq(dev->irq, msm_i2c_interrupt, |
| IRQF_TRIGGER_RISING, pdev->name, dev); |
| if (ret) { |
| dev_err(&pdev->dev, "request_irq failed\n"); |
| goto err_request_irq_failed; |
| } |
| pm_qos_add_request(&dev->pm_qos_req, PM_QOS_CPU_DMA_LATENCY, |
| PM_QOS_DEFAULT_VALUE); |
| disable_irq(dev->irq); |
| dev->suspended = 0; |
| mutex_init(&dev->mlock); |
| dev->clk_state = 0; |
| /* Config GPIOs for primary and secondary lines */ |
| pdata->msm_i2c_config_gpio(dev->adap_pri.nr, 1); |
| pdata->msm_i2c_config_gpio(dev->adap_aux.nr, 1); |
| clk_disable_unprepare(dev->clk); |
| clk_prepare(dev->clk); |
| setup_timer(&dev->pwr_timer, msm_i2c_pwr_timer, (unsigned long) dev); |
| |
| return 0; |
| |
| err_request_irq_failed: |
| i2c_del_adapter(&dev->adap_pri); |
| i2c_del_adapter(&dev->adap_aux); |
| err_i2c_add_adapter_failed: |
| clk_disable_unprepare(clk); |
| iounmap(dev->base); |
| err_ioremap_failed: |
| kfree(dev); |
| err_alloc_dev_failed: |
| clk_put(clk); |
| err_clk_get_failed: |
| release_mem_region(mem->start, (mem->end - mem->start) + 1); |
| return ret; |
| } |
| |
| static int |
| msm_i2c_remove(struct platform_device *pdev) |
| { |
| struct msm_i2c_dev *dev = platform_get_drvdata(pdev); |
| struct resource *mem; |
| |
| /* Grab mutex to ensure ongoing transaction is over */ |
| mutex_lock(&dev->mlock); |
| dev->suspended = 1; |
| mutex_unlock(&dev->mlock); |
| mutex_destroy(&dev->mlock); |
| del_timer_sync(&dev->pwr_timer); |
| if (dev->clk_state != 0) |
| msm_i2c_pwr_mgmt(dev, 0); |
| platform_set_drvdata(pdev, NULL); |
| pm_qos_remove_request(&dev->pm_qos_req); |
| free_irq(dev->irq, dev); |
| i2c_del_adapter(&dev->adap_pri); |
| i2c_del_adapter(&dev->adap_aux); |
| clk_unprepare(dev->clk); |
| clk_put(dev->clk); |
| iounmap(dev->base); |
| kfree(dev); |
| mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| if (mem) |
| release_mem_region(mem->start, (mem->end - mem->start) + 1); |
| return 0; |
| } |
| |
| static int msm_i2c_suspend(struct platform_device *pdev, pm_message_t state) |
| { |
| struct msm_i2c_dev *dev = platform_get_drvdata(pdev); |
| /* Wait until current transaction finishes |
| * Make sure remote lock is released before we suspend |
| */ |
| if (dev) { |
| /* Grab mutex to ensure ongoing transaction is over */ |
| mutex_lock(&dev->mlock); |
| dev->suspended = 1; |
| mutex_unlock(&dev->mlock); |
| del_timer_sync(&dev->pwr_timer); |
| if (dev->clk_state != 0) |
| msm_i2c_pwr_mgmt(dev, 0); |
| clk_unprepare(dev->clk); |
| } |
| |
| return 0; |
| } |
| |
| static int msm_i2c_resume(struct platform_device *pdev) |
| { |
| struct msm_i2c_dev *dev = platform_get_drvdata(pdev); |
| clk_prepare(dev->clk); |
| dev->suspended = 0; |
| return 0; |
| } |
| |
| static struct platform_driver msm_i2c_driver = { |
| .probe = msm_i2c_probe, |
| .remove = msm_i2c_remove, |
| .suspend = msm_i2c_suspend, |
| .resume = msm_i2c_resume, |
| .driver = { |
| .name = "msm_i2c", |
| .owner = THIS_MODULE, |
| }, |
| }; |
| |
| /* I2C may be needed to bring up other drivers */ |
| static int __init |
| msm_i2c_init_driver(void) |
| { |
| return platform_driver_register(&msm_i2c_driver); |
| } |
| subsys_initcall(msm_i2c_init_driver); |
| |
| static void __exit msm_i2c_exit_driver(void) |
| { |
| platform_driver_unregister(&msm_i2c_driver); |
| } |
| module_exit(msm_i2c_exit_driver); |
| |