diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-sh_mobile.c')
| -rw-r--r-- | drivers/i2c/busses/i2c-sh_mobile.c | 122 |
1 files changed, 58 insertions, 64 deletions
diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 2d2e630fd438..dae8967f8749 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -20,10 +20,11 @@ #include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/slab.h> +#include <linux/string_choices.h> /* Transmit operation: */ /* */ @@ -409,7 +410,7 @@ static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id) pd->sr |= sr; /* remember state */ dev_dbg(pd->dev, "i2c_isr 0x%02x 0x%02x %s %d %d!\n", sr, pd->sr, - (pd->msg->flags & I2C_M_RD) ? "read" : "write", + str_read_write(pd->msg->flags & I2C_M_RD), pd->pos, pd->msg->len); /* Kick off TxDMA after preface was done */ @@ -442,34 +443,26 @@ static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static void sh_mobile_i2c_dma_unmap(struct sh_mobile_i2c_data *pd) +static void sh_mobile_i2c_cleanup_dma(struct sh_mobile_i2c_data *pd, bool terminate) { struct dma_chan *chan = pd->dma_direction == DMA_FROM_DEVICE ? pd->dma_rx : pd->dma_tx; + /* only allowed from thread context! */ + if (terminate) + dmaengine_terminate_sync(chan); + dma_unmap_single(chan->device->dev, sg_dma_address(&pd->sg), pd->msg->len, pd->dma_direction); pd->dma_direction = DMA_NONE; } -static void sh_mobile_i2c_cleanup_dma(struct sh_mobile_i2c_data *pd) -{ - if (pd->dma_direction == DMA_NONE) - return; - else if (pd->dma_direction == DMA_FROM_DEVICE) - dmaengine_terminate_all(pd->dma_rx); - else if (pd->dma_direction == DMA_TO_DEVICE) - dmaengine_terminate_all(pd->dma_tx); - - sh_mobile_i2c_dma_unmap(pd); -} - static void sh_mobile_i2c_dma_callback(void *data) { struct sh_mobile_i2c_data *pd = data; - sh_mobile_i2c_dma_unmap(pd); + sh_mobile_i2c_cleanup_dma(pd, false); pd->pos = pd->msg->len; pd->stop_after_dma = true; @@ -549,7 +542,7 @@ static void sh_mobile_i2c_xfer_dma(struct sh_mobile_i2c_data *pd) DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!txdesc) { dev_dbg(pd->dev, "dma prep slave sg failed, using PIO\n"); - sh_mobile_i2c_cleanup_dma(pd); + sh_mobile_i2c_cleanup_dma(pd, false); return; } @@ -559,7 +552,7 @@ static void sh_mobile_i2c_xfer_dma(struct sh_mobile_i2c_data *pd) cookie = dmaengine_submit(txdesc); if (dma_submit_error(cookie)) { dev_dbg(pd->dev, "submitting dma failed, using PIO\n"); - sh_mobile_i2c_cleanup_dma(pd); + sh_mobile_i2c_cleanup_dma(pd, false); return; } @@ -696,9 +689,8 @@ static int sh_mobile_xfer(struct sh_mobile_i2c_data *pd, } if (!time_left) { - dev_err(pd->dev, "Transfer request timed out\n"); if (pd->dma_direction != DMA_NONE) - sh_mobile_i2c_cleanup_dma(pd); + sh_mobile_i2c_cleanup_dma(pd, true); err = -ETIMEDOUT; break; @@ -748,8 +740,8 @@ static u32 sh_mobile_i2c_func(struct i2c_adapter *adapter) static const struct i2c_algorithm sh_mobile_i2c_algorithm = { .functionality = sh_mobile_i2c_func, - .master_xfer = sh_mobile_i2c_xfer, - .master_xfer_atomic = sh_mobile_i2c_xfer_atomic, + .xfer = sh_mobile_i2c_xfer, + .xfer_atomic = sh_mobile_i2c_xfer_atomic, }; static const struct i2c_adapter_quirks sh_mobile_i2c_quirks = { @@ -781,7 +773,7 @@ static int sh_mobile_i2c_r8a7740_workaround(struct sh_mobile_i2c_data *pd) iic_wr(pd, ICCR, ICCR_TRS); udelay(10); - return sh_mobile_i2c_init(pd); + return sh_mobile_i2c_v2_init(pd); } static const struct sh_mobile_dt_config default_dt_config = { @@ -791,11 +783,6 @@ static const struct sh_mobile_dt_config default_dt_config = { static const struct sh_mobile_dt_config fast_clock_dt_config = { .clks_per_count = 2, - .setup = sh_mobile_i2c_init, -}; - -static const struct sh_mobile_dt_config v2_freq_calc_dt_config = { - .clks_per_count = 2, .setup = sh_mobile_i2c_v2_init, }; @@ -807,17 +794,17 @@ static const struct sh_mobile_dt_config r8a7740_dt_config = { static const struct of_device_id sh_mobile_i2c_dt_ids[] = { { .compatible = "renesas,iic-r8a73a4", .data = &fast_clock_dt_config }, { .compatible = "renesas,iic-r8a7740", .data = &r8a7740_dt_config }, - { .compatible = "renesas,iic-r8a774c0", .data = &v2_freq_calc_dt_config }, - { .compatible = "renesas,iic-r8a7790", .data = &v2_freq_calc_dt_config }, - { .compatible = "renesas,iic-r8a7791", .data = &v2_freq_calc_dt_config }, - { .compatible = "renesas,iic-r8a7792", .data = &v2_freq_calc_dt_config }, - { .compatible = "renesas,iic-r8a7793", .data = &v2_freq_calc_dt_config }, - { .compatible = "renesas,iic-r8a7794", .data = &v2_freq_calc_dt_config }, - { .compatible = "renesas,iic-r8a7795", .data = &v2_freq_calc_dt_config }, - { .compatible = "renesas,iic-r8a77990", .data = &v2_freq_calc_dt_config }, + { .compatible = "renesas,iic-r8a774c0", .data = &fast_clock_dt_config }, + { .compatible = "renesas,iic-r8a7790", .data = &fast_clock_dt_config }, + { .compatible = "renesas,iic-r8a7791", .data = &fast_clock_dt_config }, + { .compatible = "renesas,iic-r8a7792", .data = &fast_clock_dt_config }, + { .compatible = "renesas,iic-r8a7793", .data = &fast_clock_dt_config }, + { .compatible = "renesas,iic-r8a7794", .data = &fast_clock_dt_config }, + { .compatible = "renesas,iic-r8a7795", .data = &fast_clock_dt_config }, + { .compatible = "renesas,iic-r8a77990", .data = &fast_clock_dt_config }, { .compatible = "renesas,iic-sh73a0", .data = &fast_clock_dt_config }, - { .compatible = "renesas,rcar-gen2-iic", .data = &v2_freq_calc_dt_config }, - { .compatible = "renesas,rcar-gen3-iic", .data = &v2_freq_calc_dt_config }, + { .compatible = "renesas,rcar-gen2-iic", .data = &fast_clock_dt_config }, + { .compatible = "renesas,rcar-gen3-iic", .data = &fast_clock_dt_config }, { .compatible = "renesas,rmobile-iic", .data = &default_dt_config }, {}, }; @@ -838,20 +825,38 @@ static void sh_mobile_i2c_release_dma(struct sh_mobile_i2c_data *pd) static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, struct sh_mobile_i2c_data *pd) { - struct resource *res; - resource_size_t n; + struct device_node *np = dev_of_node(&dev->dev); int k = 0, ret; - while ((res = platform_get_resource(dev, IORESOURCE_IRQ, k))) { - for (n = res->start; n <= res->end; n++) { - ret = devm_request_irq(&dev->dev, n, sh_mobile_i2c_isr, - 0, dev_name(&dev->dev), pd); + if (np) { + int irq; + + while ((irq = platform_get_irq_optional(dev, k)) != -ENXIO) { + if (irq < 0) + return irq; + ret = devm_request_irq(&dev->dev, irq, sh_mobile_i2c_isr, + 0, dev_name(&dev->dev), pd); if (ret) { - dev_err(&dev->dev, "cannot request IRQ %pa\n", &n); + dev_err(&dev->dev, "cannot request IRQ %d\n", irq); return ret; } + k++; + } + } else { + struct resource *res; + resource_size_t n; + + while ((res = platform_get_resource(dev, IORESOURCE_IRQ, k))) { + for (n = res->start; n <= res->end; n++) { + ret = devm_request_irq(&dev->dev, n, sh_mobile_i2c_isr, + 0, dev_name(&dev->dev), pd); + if (ret) { + dev_err(&dev->dev, "cannot request IRQ %pa\n", &n); + return ret; + } + } + k++; } - k++; } return k > 0 ? 0 : -ENOENT; @@ -861,7 +866,6 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) { struct sh_mobile_i2c_data *pd; struct i2c_adapter *adap; - struct resource *res; const struct sh_mobile_dt_config *config; int ret; u32 bus_speed; @@ -883,10 +887,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) pd->dev = &dev->dev; platform_set_drvdata(dev, pd); - res = platform_get_resource(dev, IORESOURCE_MEM, 0); - - pd->res = res; - pd->reg = devm_ioremap_resource(&dev->dev, res); + pd->reg = devm_platform_get_and_ioremap_resource(dev, 0, &pd->res); if (IS_ERR(pd->reg)) return PTR_ERR(pd->reg); @@ -895,7 +896,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) pd->clks_per_count = 1; /* Newer variants come with two new bits in ICIC */ - if (resource_size(res) > 0x17) + if (resource_size(pd->res) > 0x17) pd->flags |= IIC_FLAG_HAS_ICIC67; pm_runtime_enable(&dev->dev); @@ -930,7 +931,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) adap->nr = dev->id; adap->dev.of_node = dev->dev.of_node; - strlcpy(adap->name, dev->name, sizeof(adap->name)); + strscpy(adap->name, dev->name, sizeof(adap->name)); spin_lock_init(&pd->lock); init_waitqueue_head(&pd->wait); @@ -946,17 +947,15 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) return 0; } -static int sh_mobile_i2c_remove(struct platform_device *dev) +static void sh_mobile_i2c_remove(struct platform_device *dev) { struct sh_mobile_i2c_data *pd = platform_get_drvdata(dev); i2c_del_adapter(&pd->adap); sh_mobile_i2c_release_dma(pd); pm_runtime_disable(&dev->dev); - return 0; } -#ifdef CONFIG_PM_SLEEP static int sh_mobile_i2c_suspend(struct device *dev) { struct sh_mobile_i2c_data *pd = dev_get_drvdata(dev); @@ -974,20 +973,15 @@ static int sh_mobile_i2c_resume(struct device *dev) } static const struct dev_pm_ops sh_mobile_i2c_pm_ops = { - SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(sh_mobile_i2c_suspend, - sh_mobile_i2c_resume) + NOIRQ_SYSTEM_SLEEP_PM_OPS(sh_mobile_i2c_suspend, + sh_mobile_i2c_resume) }; -#define DEV_PM_OPS (&sh_mobile_i2c_pm_ops) -#else -#define DEV_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ - static struct platform_driver sh_mobile_i2c_driver = { .driver = { .name = "i2c-sh_mobile", .of_match_table = sh_mobile_i2c_dt_ids, - .pm = DEV_PM_OPS, + .pm = pm_sleep_ptr(&sh_mobile_i2c_pm_ops), }, .probe = sh_mobile_i2c_probe, .remove = sh_mobile_i2c_remove, |
