diff options
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/busses/i2c-mxs.c | 13 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-pxa.c | 95 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-tegra.c | 2 |
3 files changed, 85 insertions, 25 deletions
diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 7e78f7c..3d471d5 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -72,6 +72,7 @@ #define MXS_I2C_QUEUESTAT (0x70) #define MXS_I2C_QUEUESTAT_RD_QUEUE_EMPTY 0x00002000 +#define MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK 0x0000001F #define MXS_I2C_QUEUECMD (0x80) @@ -219,14 +220,14 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int ret; int flags; - init_completion(&i2c->cmd_complete); - dev_dbg(i2c->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n", msg->addr, msg->len, msg->flags, stop); if (msg->len == 0) return -EINVAL; + init_completion(&i2c->cmd_complete); + flags = stop ? MXS_I2C_CTRL0_POST_SEND_STOP : 0; if (msg->flags & I2C_M_RD) @@ -286,6 +287,7 @@ static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id) { struct mxs_i2c_dev *i2c = dev_id; u32 stat = readl(i2c->regs + MXS_I2C_CTRL1) & MXS_I2C_IRQ_MASK; + bool is_last_cmd; if (!stat) return IRQ_NONE; @@ -300,9 +302,14 @@ static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id) else i2c->cmd_err = 0; - complete(&i2c->cmd_complete); + is_last_cmd = (readl(i2c->regs + MXS_I2C_QUEUESTAT) & + MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK) == 0; + + if (is_last_cmd || i2c->cmd_err) + complete(&i2c->cmd_complete); writel(stat, i2c->regs + MXS_I2C_CTRL1_CLR); + return IRQ_HANDLED; } diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index d603646..f673326 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -29,6 +29,8 @@ #include <linux/errno.h> #include <linux/interrupt.h> #include <linux/i2c-pxa.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <linux/of_i2c.h> #include <linux/platform_device.h> #include <linux/err.h> @@ -1044,23 +1046,60 @@ static const struct i2c_algorithm i2c_pxa_pio_algorithm = { .functionality = i2c_pxa_functionality, }; -static int i2c_pxa_probe(struct platform_device *dev) +static struct of_device_id i2c_pxa_dt_ids[] = { + { .compatible = "mrvl,pxa-i2c", .data = (void *)REGS_PXA2XX }, + { .compatible = "mrvl,pwri2c", .data = (void *)REGS_PXA3XX }, + { .compatible = "mrvl,mmp-twsi", .data = (void *)REGS_PXA2XX }, + {} +}; +MODULE_DEVICE_TABLE(of, i2c_pxa_dt_ids); + +static int i2c_pxa_probe_dt(struct platform_device *pdev, struct pxa_i2c *i2c, + enum pxa_i2c_types *i2c_types) { - struct pxa_i2c *i2c; - struct resource *res; - struct i2c_pxa_platform_data *plat = dev->dev.platform_data; - const struct platform_device_id *id = platform_get_device_id(dev); - enum pxa_i2c_types i2c_type = id->driver_data; + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *of_id = + of_match_device(i2c_pxa_dt_ids, &pdev->dev); int ret; - int irq; - res = platform_get_resource(dev, IORESOURCE_MEM, 0); - irq = platform_get_irq(dev, 0); - if (res == NULL || irq < 0) - return -ENODEV; + if (!of_id) + return 1; + ret = of_alias_get_id(np, "i2c"); + if (ret < 0) { + dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret); + return ret; + } + pdev->id = ret; + if (of_get_property(np, "mrvl,i2c-polling", NULL)) + i2c->use_pio = 1; + if (of_get_property(np, "mrvl,i2c-fast-mode", NULL)) + i2c->fast_mode = 1; + *i2c_types = (u32)(of_id->data); + return 0; +} - if (!request_mem_region(res->start, resource_size(res), res->name)) - return -ENOMEM; +static int i2c_pxa_probe_pdata(struct platform_device *pdev, + struct pxa_i2c *i2c, + enum pxa_i2c_types *i2c_types) +{ + struct i2c_pxa_platform_data *plat = pdev->dev.platform_data; + const struct platform_device_id *id = platform_get_device_id(pdev); + + *i2c_types = id->driver_data; + if (plat) { + i2c->use_pio = plat->use_pio; + i2c->fast_mode = plat->fast_mode; + } + return 0; +} + +static int i2c_pxa_probe(struct platform_device *dev) +{ + struct i2c_pxa_platform_data *plat = dev->dev.platform_data; + enum pxa_i2c_types i2c_type; + struct pxa_i2c *i2c; + struct resource *res = NULL; + int ret, irq; i2c = kzalloc(sizeof(struct pxa_i2c), GFP_KERNEL); if (!i2c) { @@ -1068,6 +1107,24 @@ static int i2c_pxa_probe(struct platform_device *dev) goto emalloc; } + ret = i2c_pxa_probe_dt(dev, i2c, &i2c_type); + if (ret > 0) + ret = i2c_pxa_probe_pdata(dev, i2c, &i2c_type); + if (ret < 0) + goto eclk; + + res = platform_get_resource(dev, IORESOURCE_MEM, 0); + irq = platform_get_irq(dev, 0); + if (res == NULL || irq < 0) { + ret = -ENODEV; + goto eclk; + } + + if (!request_mem_region(res->start, resource_size(res), res->name)) { + ret = -ENOMEM; + goto eclk; + } + i2c->adap.owner = THIS_MODULE; i2c->adap.retries = 5; @@ -1109,21 +1166,16 @@ static int i2c_pxa_probe(struct platform_device *dev) i2c->slave_addr = I2C_PXA_SLAVE_ADDR; -#ifdef CONFIG_I2C_PXA_SLAVE if (plat) { +#ifdef CONFIG_I2C_PXA_SLAVE i2c->slave_addr = plat->slave_addr; i2c->slave = plat->slave; - } #endif - - clk_enable(i2c->clk); - - if (plat) { i2c->adap.class = plat->class; - i2c->use_pio = plat->use_pio; - i2c->fast_mode = plat->fast_mode; } + clk_enable(i2c->clk); + if (i2c->use_pio) { i2c->adap.algo = &i2c_pxa_pio_algorithm; } else { @@ -1234,6 +1286,7 @@ static struct platform_driver i2c_pxa_driver = { .name = "pxa2xx-i2c", .owner = THIS_MODULE, .pm = I2C_PXA_DEV_PM_OPS, + .of_match_table = i2c_pxa_dt_ids, }, .id_table = i2c_pxa_id_table, }; diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 6381604..0ab4a95 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -755,7 +755,7 @@ MODULE_DEVICE_TABLE(of, tegra_i2c_of_match); static struct platform_driver tegra_i2c_driver = { .probe = tegra_i2c_probe, - .remove = tegra_i2c_remove, + .remove = __devexit_p(tegra_i2c_remove), #ifdef CONFIG_PM .suspend = tegra_i2c_suspend, .resume = tegra_i2c_resume, |