blob: 0322262f88543f30b1d0ee6d1b732ee1a69eee4c [file] [log] [blame]
/* drivers/i2c/busses/i2c-msm.c
*
* Copyright (C) 2007 Google, Inc.
*
* 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.
*
*/
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/wakelock.h>
#include <mach/system.h>
#define DEBUG 0
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,
};
struct msm_i2c_dev {
struct device *dev;
void __iomem *base; /* virtual */
int irq;
struct clk *clk;
struct i2c_adapter adapter;
spinlock_t lock;
struct i2c_msg *msg;
int rem;
int pos;
int cnt;
int ret;
bool need_flush;
int flush_cnt;
void *complete;
struct wake_lock wakelock;
bool is_suspended;
};
#if 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 void msm_i2c_write_delay(struct msm_i2c_dev *dev)
{
/* If scl is still high we have >4us (for 100kbps) to write the data
* register before we risk hitting a bug where the controller releases
* scl to soon after driving sda low. Writing the data after the
* scheduled release time for scl also avoids the bug.
*/
if (readl(dev->base + I2C_INTERFACE_SELECT) & I2C_INTERFACE_SELECT_SCL)
return;
udelay(6);
}
static bool msm_i2c_fill_write_buffer(struct msm_i2c_dev *dev)
{
uint16_t val;
if (dev->pos < 0) {
val = I2C_WRITE_DATA_ADDR_BYTE | dev->msg->addr << 1;
if (dev->msg->flags & I2C_M_RD)
val |= 1;
if (dev->rem == 1 && dev->msg->len == 0)
val |= I2C_WRITE_DATA_LAST_BYTE;
msm_i2c_write_delay(dev);
writel(val, dev->base + I2C_WRITE_DATA);
dev->pos++;
return true;
}
if (dev->msg->flags & I2C_M_RD)
return false;
if (!dev->cnt)
return false;
/* Ready to take a byte */
val = dev->msg->buf[dev->pos];
if (dev->cnt == 1 && dev->rem == 1)
val |= I2C_WRITE_DATA_LAST_BYTE;
msm_i2c_write_delay(dev);
writel(val, dev->base + I2C_WRITE_DATA);
dev->pos++;
dev->cnt--;
return true;
}
static void msm_i2c_read_buffer(struct msm_i2c_dev *dev)
{
/*
* Theres something in the FIFO.
* Are we expecting data or flush crap?
*/
if ((dev->msg->flags & I2C_M_RD) && dev->pos >= 0 && dev->cnt) {
switch (dev->cnt) {
case 1:
if (dev->pos != 0)
break;
dev->need_flush = true;
/* fall-trough */
case 2:
writel(I2C_WRITE_DATA_LAST_BYTE,
dev->base + I2C_WRITE_DATA);
}
dev->msg->buf[dev->pos] = readl(dev->base + I2C_READ_DATA);
dev->cnt--;
dev->pos++;
} else { /* FLUSH */
if (dev->flush_cnt & 1) {
/*
* Stop requests are sometimes ignored, but writing
* more than one request generates a write error.
*/
writel(I2C_WRITE_DATA_LAST_BYTE,
dev->base + I2C_WRITE_DATA);
}
readl(dev->base + I2C_READ_DATA);
if (dev->need_flush)
dev->need_flush = false;
else
dev->flush_cnt++;
}
}
static void msm_i2c_interrupt_locked(struct msm_i2c_dev *dev)
{
uint32_t status = readl(dev->base + I2C_STATUS);
bool not_done = true;
#if DEBUG
dump_status(status);
#endif
if (!dev->msg) {
dev_err(dev->dev,
"IRQ but nothing to do!, status %x\n", status);
return;
}
if (status & I2C_STATUS_ERROR_MASK)
goto out_err;
if (!(status & I2C_STATUS_WR_BUFFER_FULL))
not_done = msm_i2c_fill_write_buffer(dev);
if (status & I2C_STATUS_RD_BUFFER_FULL)
msm_i2c_read_buffer(dev);
if (dev->pos >= 0 && dev->cnt == 0) {
if (dev->rem > 1) {
dev->rem--;
dev->msg++;
dev->pos = -1;
dev->cnt = dev->msg->len;
} else if (!not_done && !dev->need_flush)
goto out_complete;
}
return;
out_err:
dev_err(dev->dev, "error, status %x\n", status);
dev->ret = -EIO;
out_complete:
complete(dev->complete);
}
static irqreturn_t
msm_i2c_interrupt(int irq, void *devid)
{
struct msm_i2c_dev *dev = devid;
spin_lock(&dev->lock);
msm_i2c_interrupt_locked(dev);
spin_unlock(&dev->lock);
return IRQ_HANDLED;
}
static int
msm_i2c_poll_notbusy(struct msm_i2c_dev *dev, int warn)
{
uint32_t retries = 0;
while (retries != 200) {
uint32_t status = readl(dev->base + I2C_STATUS);
if (!(status & I2C_STATUS_BUS_ACTIVE)) {
if (retries && warn)
dev_warn(dev->dev,
"Warning bus was busy (%d)\n", retries);
return 0;
}
if (retries++ > 100)
msleep(10);
}
dev_err(dev->dev, "Error waiting for notbusy (%d)\n", warn);
return -ETIMEDOUT;
}
static int
msm_i2c_recover_bus_busy(struct msm_i2c_dev *dev)
{
int i;
uint32_t status = readl(dev->base + I2C_STATUS);
int gpio_clk, gpio_dat;
bool gpio_clk_status = false;
if (!(status & (I2C_STATUS_BUS_ACTIVE | I2C_STATUS_WR_BUFFER_FULL)))
return 0;
msm_set_i2c_mux(true, &gpio_clk, &gpio_dat);
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);
}
dev_warn(dev->dev, "i2c_scl: %d, i2c_sda: %d\n",
gpio_get_value(gpio_clk), gpio_get_value(gpio_dat));
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))
udelay(20);
if (!gpio_get_value(gpio_clk))
msleep(10);
gpio_clk_status = gpio_get_value(gpio_clk);
gpio_direction_input(gpio_dat);
udelay(5);
}
msm_set_i2c_mux(false, NULL, NULL);
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));
return 0;
}
dev_warn(dev->dev, "Bus still busy, status %x, intf %x\n",
status, readl(dev->base + I2C_INTERFACE_SELECT));
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;
long timeout;
unsigned long flags;
if (WARN_ON(!num))
return -EINVAL;
/*
* If there is an i2c_xfer after driver has been suspended,
* grab wakelock to abort suspend.
*/
if (dev->is_suspended)
wake_lock(&dev->wakelock);
clk_enable(dev->clk);
enable_irq(dev->irq);
ret = msm_i2c_poll_notbusy(dev, 1);
if (ret) {
ret = msm_i2c_recover_bus_busy(dev);
if (ret)
goto err;
}
spin_lock_irqsave(&dev->lock, flags);
if (dev->flush_cnt) {
dev_warn(dev->dev, "%d unrequested bytes read\n",
dev->flush_cnt);
}
dev->msg = msgs;
dev->rem = num;
dev->pos = -1;
dev->ret = num;
dev->need_flush = false;
dev->flush_cnt = 0;
dev->cnt = msgs->len;
dev->complete = &complete;
msm_i2c_interrupt_locked(dev);
spin_unlock_irqrestore(&dev->lock, flags);
/*
* 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
*/
timeout = wait_for_completion_timeout(&complete, HZ);
msm_i2c_poll_notbusy(dev, 0); /* Read may not have stopped in time */
spin_lock_irqsave(&dev->lock, flags);
if (dev->flush_cnt) {
dev_warn(dev->dev, "%d unrequested bytes read\n",
dev->flush_cnt);
}
ret = dev->ret;
dev->complete = NULL;
dev->msg = NULL;
dev->rem = 0;
dev->pos = 0;
dev->ret = 0;
dev->flush_cnt = 0;
dev->cnt = 0;
spin_unlock_irqrestore(&dev->lock, flags);
if (!timeout) {
dev_err(dev->dev, "Transaction timed out\n");
ret = -ETIMEDOUT;
}
if (ret < 0) {
dev_err(dev->dev, "Error during data xfer %x (%d)\n",
msgs[0].addr, ret);
msm_i2c_recover_bus_busy(dev);
}
err:
disable_irq(dev->irq);
clk_disable(dev->clk);
if (dev->is_suspended)
wake_unlock(&dev->wakelock);
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;
int target_clk;
struct clk *clk;
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, "i2c_clk");
if (IS_ERR(clk)) {
dev_err(&pdev->dev, "Could not get clock\n");
ret = PTR_ERR(clk);
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->base = ioremap(mem->start, (mem->end - mem->start) + 1);
if (!dev->base) {
ret = -ENOMEM;
goto err_ioremap_failed;
}
spin_lock_init(&dev->lock);
wake_lock_init(&dev->wakelock, WAKE_LOCK_SUSPEND, "i2c");
platform_set_drvdata(pdev, dev);
msm_set_i2c_mux(false, NULL, NULL);
clk_enable(clk);
/* 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 */
target_clk = 100000;
/* target_clk = 200000; */
fs_div = ((i2c_clk / target_clk) / 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)));
clk_disable(clk);
i2c_set_adapdata(&dev->adapter, dev);
dev->adapter.algo = &msm_i2c_algo;
strncpy(dev->adapter.name,
"MSM I2C adapter",
sizeof(dev->adapter.name));
dev->adapter.nr = pdev->id;
ret = i2c_add_numbered_adapter(&dev->adapter);
if (ret) {
dev_err(&pdev->dev, "i2c_add_adapter failed\n");
goto err_i2c_add_adapter_failed;
}
ret = request_irq(dev->irq, msm_i2c_interrupt,
IRQF_DISABLED | IRQF_TRIGGER_RISING, pdev->name, dev);
if (ret) {
dev_err(&pdev->dev, "request_irq failed\n");
goto err_request_irq_failed;
}
disable_irq(dev->irq);
return 0;
/* free_irq(dev->irq, dev); */
err_request_irq_failed:
i2c_del_adapter(&dev->adapter);
err_i2c_add_adapter_failed:
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;
platform_set_drvdata(pdev, NULL);
enable_irq(dev->irq);
free_irq(dev->irq, dev);
i2c_del_adapter(&dev->adapter);
wake_lock_destroy(&dev->wakelock);
clk_put(dev->clk);
iounmap(dev->base);
kfree(dev);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(mem->start, (mem->end - mem->start) + 1);
return 0;
}
static int msm_i2c_suspend_noirq(struct device *device)
{
struct platform_device *pdev = to_platform_device(device);
struct msm_i2c_dev *dev = platform_get_drvdata(pdev);
/* Block to allow any i2c_xfers to finish */
i2c_lock_adapter(&dev->adapter);
dev->is_suspended = true;
i2c_unlock_adapter(&dev->adapter);
return 0;
}
static int msm_i2c_resume_noirq(struct device *device) {
struct platform_device *pdev = to_platform_device(device);
struct msm_i2c_dev *dev = platform_get_drvdata(pdev);
/* Block to allow any i2c_xfers to finish */
i2c_lock_adapter(&dev->adapter);
dev->is_suspended = false;
i2c_unlock_adapter(&dev->adapter);
return 0;
}
static struct dev_pm_ops msm_i2c_pm_ops = {
.suspend_noirq = msm_i2c_suspend_noirq,
.resume_noirq = msm_i2c_resume_noirq,
};
static struct platform_driver msm_i2c_driver = {
.probe = msm_i2c_probe,
.remove = msm_i2c_remove,
.driver = {
.name = "msm_i2c",
.owner = THIS_MODULE,
.pm = &msm_i2c_pm_ops,
},
};
/* 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);