Commit 57dbde63 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'i2c/for-4.20' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux

Pull i2c updates from Wolfram Sang:
 "I2C has not so much stuff this time. Mostly driver enablement for new
  SoCs, some driver bugfixes, and some cleanups"

* 'i2c/for-4.20' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (35 commits)
  MAINTAINERS: add maintainer for Renesas RIIC driver
  i2c: sh_mobile: Remove dummy runtime PM callbacks
  i2c: uniphier-f: fix race condition when IRQ is cleared
  i2c: uniphier-f: fix occasional timeout error
  i2c: uniphier-f: make driver robust against concurrency
  i2c: i2c-qcom-geni: Simplify irq handler
  i2c: i2c-qcom-geni: Simplify tx/rx functions
  i2c: designware: Set IRQF_NO_SUSPEND flag for all BYT and CHT controllers
  i2c: mux: mlxcpld: simplify code to reach the adapter
  i2c: mux: ltc4306: simplify code to reach the adapter
  i2c: mux: pca954x: simplify code to reach the adapter
  i2c: core: remove level of indentation in i2c_transfer
  i2c: core: remove outdated DEBUG output
  i2c: zx2967: use core to detect 'no zero length' quirk
  i2c: tegra: use core to detect 'no zero length' quirk
  i2c: qup: use core to detect 'no zero length' quirk
  i2c: omap: use core to detect 'no zero length' quirk
  i2c: Convert to using %pOFn instead of device_node.name
  i2c: brcmstb: Allow enabling the driver on DSL SoCs
  eeprom: at24: fix unexpected timeout under high load
  ...
parents 134bf98c 84de6e96
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
Required properties : Required properties :
- compatible : should be "snps,designware-i2c" - compatible : should be "snps,designware-i2c"
or "mscc,ocelot-i2c" with "snps,designware-i2c" for fallback
- reg : Offset and length of the register set for the device - reg : Offset and length of the register set for the device
- interrupts : <IRQ> where IRQ is the interrupt number. - interrupts : <IRQ> where IRQ is the interrupt number.
...@@ -11,8 +12,12 @@ Recommended properties : ...@@ -11,8 +12,12 @@ Recommended properties :
- clock-frequency : desired I2C bus clock frequency in Hz. - clock-frequency : desired I2C bus clock frequency in Hz.
Optional properties : Optional properties :
- reg : for "mscc,ocelot-i2c", a second register set to configure the SDA hold
time, named ICPU_CFG:TWI_DELAY in the datasheet.
- i2c-sda-hold-time-ns : should contain the SDA hold time in nanoseconds. - i2c-sda-hold-time-ns : should contain the SDA hold time in nanoseconds.
This option is only supported in hardware blocks version 1.11a or newer. This option is only supported in hardware blocks version 1.11a or newer and
on Microsemi SoCs ("mscc,ocelot-i2c" compatible).
- i2c-scl-falling-time-ns : should contain the SCL falling time in nanoseconds. - i2c-scl-falling-time-ns : should contain the SCL falling time in nanoseconds.
This value which is by default 300ns is used to compute the tLOW period. This value which is by default 300ns is used to compute the tLOW period.
......
...@@ -3,7 +3,9 @@ I2C for R-Car platforms ...@@ -3,7 +3,9 @@ I2C for R-Car platforms
Required properties: Required properties:
- compatible: - compatible:
"renesas,i2c-r8a7743" if the device is a part of a R8A7743 SoC. "renesas,i2c-r8a7743" if the device is a part of a R8A7743 SoC.
"renesas,i2c-r8a7744" if the device is a part of a R8A7744 SoC.
"renesas,i2c-r8a7745" if the device is a part of a R8A7745 SoC. "renesas,i2c-r8a7745" if the device is a part of a R8A7745 SoC.
"renesas,i2c-r8a77470" if the device is a part of a R8A77470 SoC.
"renesas,i2c-r8a774a1" if the device is a part of a R8A774A1 SoC. "renesas,i2c-r8a774a1" if the device is a part of a R8A774A1 SoC.
"renesas,i2c-r8a7778" if the device is a part of a R8A7778 SoC. "renesas,i2c-r8a7778" if the device is a part of a R8A7778 SoC.
"renesas,i2c-r8a7779" if the device is a part of a R8A7779 SoC. "renesas,i2c-r8a7779" if the device is a part of a R8A7779 SoC.
......
...@@ -5,6 +5,7 @@ Required properties: ...@@ -5,6 +5,7 @@ Required properties:
- "renesas,iic-r8a73a4" (R-Mobile APE6) - "renesas,iic-r8a73a4" (R-Mobile APE6)
- "renesas,iic-r8a7740" (R-Mobile A1) - "renesas,iic-r8a7740" (R-Mobile A1)
- "renesas,iic-r8a7743" (RZ/G1M) - "renesas,iic-r8a7743" (RZ/G1M)
- "renesas,iic-r8a7744" (RZ/G1N)
- "renesas,iic-r8a7745" (RZ/G1E) - "renesas,iic-r8a7745" (RZ/G1E)
- "renesas,iic-r8a774a1" (RZ/G2M) - "renesas,iic-r8a774a1" (RZ/G2M)
- "renesas,iic-r8a7790" (R-Car H2) - "renesas,iic-r8a7790" (R-Car H2)
......
...@@ -12548,6 +12548,12 @@ S: Supported ...@@ -12548,6 +12548,12 @@ S: Supported
F: drivers/i2c/busses/i2c-rcar.c F: drivers/i2c/busses/i2c-rcar.c
F: drivers/i2c/busses/i2c-sh_mobile.c F: drivers/i2c/busses/i2c-sh_mobile.c
RENESAS RIIC DRIVER
M: Chris Brandt <chris.brandt@renesas.com>
S: Supported
F: Documentation/devicetree/bindings/i2c/i2c-riic.txt
F: drivers/i2c/busses/i2c-riic.c
RENESAS USB PHY DRIVER RENESAS USB PHY DRIVER
M: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> M: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
L: linux-renesas-soc@vger.kernel.org L: linux-renesas-soc@vger.kernel.org
......
...@@ -432,12 +432,13 @@ config I2C_BCM_KONA ...@@ -432,12 +432,13 @@ config I2C_BCM_KONA
If you do not need KONA I2C interface, say N. If you do not need KONA I2C interface, say N.
config I2C_BRCMSTB config I2C_BRCMSTB
tristate "BRCM Settop I2C controller" tristate "BRCM Settop/DSL I2C controller"
depends on ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST depends on ARCH_BRCMSTB || BMIPS_GENERIC || ARCH_BCM_63XX || \
COMPILE_TEST
default y default y
help help
If you say yes to this option, support will be included for the If you say yes to this option, support will be included for the
I2C interface on the Broadcom Settop SoCs. I2C interface on the Broadcom Settop/DSL SoCs.
If you do not need I2C interface, say N. If you do not need I2C interface, say N.
......
This diff is collapsed.
...@@ -164,7 +164,7 @@ int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev) ...@@ -164,7 +164,7 @@ int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev)
dev_info(dev->dev, "I2C bus managed by PUNIT\n"); dev_info(dev->dev, "I2C bus managed by PUNIT\n");
dev->acquire_lock = baytrail_i2c_acquire; dev->acquire_lock = baytrail_i2c_acquire;
dev->release_lock = baytrail_i2c_release; dev->release_lock = baytrail_i2c_release;
dev->pm_disabled = true; dev->shared_with_punit = true;
pm_qos_add_request(&dev->pm_qos, PM_QOS_CPU_DMA_LATENCY, pm_qos_add_request(&dev->pm_qos, PM_QOS_CPU_DMA_LATENCY,
PM_QOS_DEFAULT_VALUE); PM_QOS_DEFAULT_VALUE);
......
...@@ -201,6 +201,8 @@ int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev) ...@@ -201,6 +201,8 @@ int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev)
dev_dbg(dev->dev, "SDA Hold Time TX:RX = %d:%d\n", dev_dbg(dev->dev, "SDA Hold Time TX:RX = %d:%d\n",
dev->sda_hold_time & ~(u32)DW_IC_SDA_HOLD_RX_MASK, dev->sda_hold_time & ~(u32)DW_IC_SDA_HOLD_RX_MASK,
dev->sda_hold_time >> DW_IC_SDA_HOLD_RX_SHIFT); dev->sda_hold_time >> DW_IC_SDA_HOLD_RX_SHIFT);
} else if (dev->set_sda_hold_time) {
dev->set_sda_hold_time(dev);
} else if (dev->sda_hold_time) { } else if (dev->sda_hold_time) {
dev_warn(dev->dev, dev_warn(dev->dev,
"Hardware too old to adjust SDA hold time.\n"); "Hardware too old to adjust SDA hold time.\n");
......
...@@ -212,7 +212,7 @@ ...@@ -212,7 +212,7 @@
* @pm_qos: pm_qos_request used while holding a hardware lock on the bus * @pm_qos: pm_qos_request used while holding a hardware lock on the bus
* @acquire_lock: function to acquire a hardware lock on the bus * @acquire_lock: function to acquire a hardware lock on the bus
* @release_lock: function to release a hardware lock on the bus * @release_lock: function to release a hardware lock on the bus
* @pm_disabled: true if power-management should be disabled for this i2c-bus * @shared_with_punit: true if this bus is shared with the SoCs PUNIT
* @disable: function to disable the controller * @disable: function to disable the controller
* @disable_int: function to disable all interrupts * @disable_int: function to disable all interrupts
* @init: function to initialize the I2C hardware * @init: function to initialize the I2C hardware
...@@ -225,6 +225,7 @@ ...@@ -225,6 +225,7 @@
struct dw_i2c_dev { struct dw_i2c_dev {
struct device *dev; struct device *dev;
void __iomem *base; void __iomem *base;
void __iomem *ext;
struct completion cmd_complete; struct completion cmd_complete;
struct clk *clk; struct clk *clk;
struct reset_control *rst; struct reset_control *rst;
...@@ -265,10 +266,11 @@ struct dw_i2c_dev { ...@@ -265,10 +266,11 @@ struct dw_i2c_dev {
struct pm_qos_request pm_qos; struct pm_qos_request pm_qos;
int (*acquire_lock)(struct dw_i2c_dev *dev); int (*acquire_lock)(struct dw_i2c_dev *dev);
void (*release_lock)(struct dw_i2c_dev *dev); void (*release_lock)(struct dw_i2c_dev *dev);
bool pm_disabled; bool shared_with_punit;
void (*disable)(struct dw_i2c_dev *dev); void (*disable)(struct dw_i2c_dev *dev);
void (*disable_int)(struct dw_i2c_dev *dev); void (*disable_int)(struct dw_i2c_dev *dev);
int (*init)(struct dw_i2c_dev *dev); int (*init)(struct dw_i2c_dev *dev);
int (*set_sda_hold_time)(struct dw_i2c_dev *dev);
int mode; int mode;
struct i2c_bus_recovery_info rinfo; struct i2c_bus_recovery_info rinfo;
}; };
...@@ -276,8 +278,11 @@ struct dw_i2c_dev { ...@@ -276,8 +278,11 @@ struct dw_i2c_dev {
#define ACCESS_SWAP 0x00000001 #define ACCESS_SWAP 0x00000001
#define ACCESS_16BIT 0x00000002 #define ACCESS_16BIT 0x00000002
#define ACCESS_INTR_MASK 0x00000004 #define ACCESS_INTR_MASK 0x00000004
#define ACCESS_NO_IRQ_SUSPEND 0x00000008
#define MODEL_CHERRYTRAIL 0x00000100 #define MODEL_CHERRYTRAIL 0x00000100
#define MODEL_MSCC_OCELOT 0x00000200
#define MODEL_MASK 0x00000f00
u32 dw_readl(struct dw_i2c_dev *dev, int offset); u32 dw_readl(struct dw_i2c_dev *dev, int offset);
void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset); void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset);
......
...@@ -709,7 +709,7 @@ int i2c_dw_probe(struct dw_i2c_dev *dev) ...@@ -709,7 +709,7 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)
adap->dev.parent = dev->dev; adap->dev.parent = dev->dev;
i2c_set_adapdata(adap, dev); i2c_set_adapdata(adap, dev);
if (dev->pm_disabled) { if (dev->flags & ACCESS_NO_IRQ_SUSPEND) {
irq_flags = IRQF_NO_SUSPEND; irq_flags = IRQF_NO_SUSPEND;
} else { } else {
irq_flags = IRQF_SHARED | IRQF_COND_SUSPEND; irq_flags = IRQF_SHARED | IRQF_COND_SUSPEND;
......
...@@ -85,10 +85,6 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev) ...@@ -85,10 +85,6 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev)
struct dw_i2c_dev *dev = platform_get_drvdata(pdev); struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
struct i2c_timings *t = &dev->timings; struct i2c_timings *t = &dev->timings;
u32 ss_ht = 0, fp_ht = 0, hs_ht = 0, fs_ht = 0; u32 ss_ht = 0, fp_ht = 0, hs_ht = 0, fs_ht = 0;
acpi_handle handle = ACPI_HANDLE(&pdev->dev);
const struct acpi_device_id *id;
struct acpi_device *adev;
const char *uid;
dev->adapter.nr = -1; dev->adapter.nr = -1;
dev->tx_fifo_depth = 32; dev->tx_fifo_depth = 32;
...@@ -119,22 +115,6 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev) ...@@ -119,22 +115,6 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev)
break; break;
} }
id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev);
if (id && id->driver_data)
dev->flags |= (u32)id->driver_data;
if (acpi_bus_get_device(handle, &adev))
return -ENODEV;
/*
* Cherrytrail I2C7 gets used for the PMIC which gets accessed
* through ACPI opregions during late suspend / early resume
* disable pm for it.
*/
uid = adev->pnp.unique_id;
if ((dev->flags & MODEL_CHERRYTRAIL) && !strcmp(uid, "7"))
dev->pm_disabled = true;
return 0; return 0;
} }
...@@ -143,8 +123,8 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = { ...@@ -143,8 +123,8 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = {
{ "INT33C3", 0 }, { "INT33C3", 0 },
{ "INT3432", 0 }, { "INT3432", 0 },
{ "INT3433", 0 }, { "INT3433", 0 },
{ "80860F41", 0 }, { "80860F41", ACCESS_NO_IRQ_SUSPEND },
{ "808622C1", MODEL_CHERRYTRAIL }, { "808622C1", ACCESS_NO_IRQ_SUSPEND | MODEL_CHERRYTRAIL },
{ "AMD0010", ACCESS_INTR_MASK }, { "AMD0010", ACCESS_INTR_MASK },
{ "AMDI0010", ACCESS_INTR_MASK }, { "AMDI0010", ACCESS_INTR_MASK },
{ "AMDI0510", 0 }, { "AMDI0510", 0 },
...@@ -161,6 +141,51 @@ static inline int dw_i2c_acpi_configure(struct platform_device *pdev) ...@@ -161,6 +141,51 @@ static inline int dw_i2c_acpi_configure(struct platform_device *pdev)
} }
#endif #endif
#ifdef CONFIG_OF
#define MSCC_ICPU_CFG_TWI_DELAY 0x0
#define MSCC_ICPU_CFG_TWI_DELAY_ENABLE BIT(0)
#define MSCC_ICPU_CFG_TWI_SPIKE_FILTER 0x4
static int mscc_twi_set_sda_hold_time(struct dw_i2c_dev *dev)
{
writel((dev->sda_hold_time << 1) | MSCC_ICPU_CFG_TWI_DELAY_ENABLE,
dev->ext + MSCC_ICPU_CFG_TWI_DELAY);
return 0;
}
static int dw_i2c_of_configure(struct platform_device *pdev)
{
struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
struct resource *mem;
switch (dev->flags & MODEL_MASK) {
case MODEL_MSCC_OCELOT:
mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
dev->ext = devm_ioremap_resource(&pdev->dev, mem);
if (!IS_ERR(dev->ext))
dev->set_sda_hold_time = mscc_twi_set_sda_hold_time;
break;
default:
break;
}
return 0;
}
static const struct of_device_id dw_i2c_of_match[] = {
{ .compatible = "snps,designware-i2c", },
{ .compatible = "mscc,ocelot-i2c", .data = (void *)MODEL_MSCC_OCELOT },
{},
};
MODULE_DEVICE_TABLE(of, dw_i2c_of_match);
#else
static inline int dw_i2c_of_configure(struct platform_device *pdev)
{
return -ENODEV;
}
#endif
static void i2c_dw_configure_master(struct dw_i2c_dev *dev) static void i2c_dw_configure_master(struct dw_i2c_dev *dev)
{ {
struct i2c_timings *t = &dev->timings; struct i2c_timings *t = &dev->timings;
...@@ -221,7 +246,7 @@ static void dw_i2c_plat_pm_cleanup(struct dw_i2c_dev *dev) ...@@ -221,7 +246,7 @@ static void dw_i2c_plat_pm_cleanup(struct dw_i2c_dev *dev)
{ {
pm_runtime_disable(dev->dev); pm_runtime_disable(dev->dev);
if (dev->pm_disabled) if (dev->shared_with_punit)
pm_runtime_put_noidle(dev->dev); pm_runtime_put_noidle(dev->dev);
} }
...@@ -291,6 +316,11 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) ...@@ -291,6 +316,11 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
else else
t->bus_freq_hz = 400000; t->bus_freq_hz = 400000;
dev->flags |= (uintptr_t)device_get_match_data(&pdev->dev);
if (pdev->dev.of_node)
dw_i2c_of_configure(pdev);
if (has_acpi_companion(&pdev->dev)) if (has_acpi_companion(&pdev->dev))
dw_i2c_acpi_configure(pdev); dw_i2c_acpi_configure(pdev);
...@@ -348,7 +378,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) ...@@ -348,7 +378,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_active(&pdev->dev); pm_runtime_set_active(&pdev->dev);
if (dev->pm_disabled) if (dev->shared_with_punit)
pm_runtime_get_noresume(&pdev->dev); pm_runtime_get_noresume(&pdev->dev);
pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev);
...@@ -393,14 +423,6 @@ static int dw_i2c_plat_remove(struct platform_device *pdev) ...@@ -393,14 +423,6 @@ static int dw_i2c_plat_remove(struct platform_device *pdev)
return 0; return 0;
} }
#ifdef CONFIG_OF
static const struct of_device_id dw_i2c_of_match[] = {
{ .compatible = "snps,designware-i2c", },
{},
};
MODULE_DEVICE_TABLE(of, dw_i2c_of_match);
#endif
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
static int dw_i2c_plat_prepare(struct device *dev) static int dw_i2c_plat_prepare(struct device *dev)
{ {
...@@ -434,7 +456,7 @@ static int dw_i2c_plat_suspend(struct device *dev) ...@@ -434,7 +456,7 @@ static int dw_i2c_plat_suspend(struct device *dev)
{ {
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
if (i_dev->pm_disabled) if (i_dev->shared_with_punit)
return 0; return 0;
i_dev->disable(i_dev); i_dev->disable(i_dev);
...@@ -447,7 +469,7 @@ static int dw_i2c_plat_resume(struct device *dev) ...@@ -447,7 +469,7 @@ static int dw_i2c_plat_resume(struct device *dev)
{ {
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
if (!i_dev->pm_disabled) if (!i_dev->shared_with_punit)
i2c_dw_prepare_clk(i_dev, true); i2c_dw_prepare_clk(i_dev, true);
i_dev->init(i_dev); i_dev->init(i_dev);
......
...@@ -441,6 +441,8 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs, ...@@ -441,6 +441,8 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
u16 control_reg; u16 control_reg;
u16 restart_flag = 0; u16 restart_flag = 0;
u32 reg_4g_mode; u32 reg_4g_mode;
u8 *dma_rd_buf = NULL;
u8 *dma_wr_buf = NULL;
dma_addr_t rpaddr = 0; dma_addr_t rpaddr = 0;
dma_addr_t wpaddr = 0; dma_addr_t wpaddr = 0;
int ret; int ret;
...@@ -500,10 +502,18 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs, ...@@ -500,10 +502,18 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
if (i2c->op == I2C_MASTER_RD) { if (i2c->op == I2C_MASTER_RD) {
writel(I2C_DMA_INT_FLAG_NONE, i2c->pdmabase + OFFSET_INT_FLAG); writel(I2C_DMA_INT_FLAG_NONE, i2c->pdmabase + OFFSET_INT_FLAG);
writel(I2C_DMA_CON_RX, i2c->pdmabase + OFFSET_CON); writel(I2C_DMA_CON_RX, i2c->pdmabase + OFFSET_CON);
rpaddr = dma_map_single(i2c->dev, msgs->buf,
dma_rd_buf = i2c_get_dma_safe_msg_buf(msgs, 0);
if (!dma_rd_buf)
return -ENOMEM;
rpaddr = dma_map_single(i2c->dev, dma_rd_buf,
msgs->len, DMA_FROM_DEVICE); msgs->len, DMA_FROM_DEVICE);
if (dma_mapping_error(i2c->dev, rpaddr)) if (dma_mapping_error(i2c->dev, rpaddr)) {
i2c_put_dma_safe_msg_buf(dma_rd_buf, msgs, false);
return -ENOMEM; return -ENOMEM;
}
if (i2c->dev_comp->support_33bits) { if (i2c->dev_comp->support_33bits) {
reg_4g_mode = mtk_i2c_set_4g_mode(rpaddr); reg_4g_mode = mtk_i2c_set_4g_mode(rpaddr);
...@@ -515,10 +525,18 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs, ...@@ -515,10 +525,18 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
} else if (i2c->op == I2C_MASTER_WR) { } else if (i2c->op == I2C_MASTER_WR) {
writel(I2C_DMA_INT_FLAG_NONE, i2c->pdmabase + OFFSET_INT_FLAG); writel(I2C_DMA_INT_FLAG_NONE, i2c->pdmabase + OFFSET_INT_FLAG);
writel(I2C_DMA_CON_TX, i2c->pdmabase + OFFSET_CON); writel(I2C_DMA_CON_TX, i2c->pdmabase + OFFSET_CON);
wpaddr = dma_map_single(i2c->dev, msgs->buf,
dma_wr_buf = i2c_get_dma_safe_msg_buf(msgs, 0);
if (!dma_wr_buf)
return -ENOMEM;
wpaddr = dma_map_single(i2c->dev, dma_wr_buf,
msgs->len, DMA_TO_DEVICE); msgs->len, DMA_TO_DEVICE);
if (dma_mapping_error(i2c->dev, wpaddr)) if (dma_mapping_error(i2c->dev, wpaddr)) {
i2c_put_dma_safe_msg_buf(dma_wr_buf, msgs, false);
return -ENOMEM; return -ENOMEM;
}
if (i2c->dev_comp->support_33bits) { if (i2c->dev_comp->support_33bits) {
reg_4g_mode = mtk_i2c_set_4g_mode(wpaddr); reg_4g_mode = mtk_i2c_set_4g_mode(wpaddr);
...@@ -530,16 +548,39 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs, ...@@ -530,16 +548,39 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
} else { } else {
writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_INT_FLAG); writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_INT_FLAG);
writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_CON); writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_CON);
wpaddr = dma_map_single(i2c->dev, msgs->buf,
dma_wr_buf = i2c_get_dma_safe_msg_buf(msgs, 0);
if (!dma_wr_buf)
return -ENOMEM;
wpaddr = dma_map_single(i2c->dev, dma_wr_buf,
msgs->len, DMA_TO_DEVICE); msgs->len, DMA_TO_DEVICE);
if (dma_mapping_error(i2c->dev, wpaddr)) if (dma_mapping_error(i2c->dev, wpaddr)) {
i2c_put_dma_safe_msg_buf(dma_wr_buf, msgs, false);
return -ENOMEM; return -ENOMEM;
rpaddr = dma_map_single(i2c->dev, (msgs + 1)->buf, }
dma_rd_buf = i2c_get_dma_safe_msg_buf((msgs + 1), 0);
if (!dma_rd_buf) {
dma_unmap_single(i2c->dev, wpaddr,
msgs->len, DMA_TO_DEVICE);
i2c_put_dma_safe_msg_buf(dma_wr_buf, msgs, false);
return -ENOMEM;
}
rpaddr = dma_map_single(i2c->dev, dma_rd_buf,
(msgs + 1)->len, (msgs + 1)->len,
DMA_FROM_DEVICE); DMA_FROM_DEVICE);
if (dma_mapping_error(i2c->dev, rpaddr)) { if (dma_mapping_error(i2c->dev, rpaddr)) {
dma_unmap_single(i2c->dev, wpaddr, dma_unmap_single(i2c->dev, wpaddr,
msgs->len, DMA_TO_DEVICE); msgs->len, DMA_TO_DEVICE);
i2c_put_dma_safe_msg_buf(dma_wr_buf, msgs, false);
i2c_put_dma_safe_msg_buf(dma_rd_buf, (msgs + 1), false);
return -ENOMEM; return -ENOMEM;
} }
...@@ -578,14 +619,21 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs, ...@@ -578,14 +619,21 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
if (i2c->op == I2C_MASTER_WR) { if (i2c->op == I2C_MASTER_WR) {
dma_unmap_single(i2c->dev, wpaddr, dma_unmap_single(i2c->dev, wpaddr,
msgs->len, DMA_TO_DEVICE); msgs->len, DMA_TO_DEVICE);
i2c_put_dma_safe_msg_buf(dma_wr_buf, msgs, true);
} else if (i2c->op == I2C_MASTER_RD) { } else if (i2c->op == I2C_MASTER_RD) {
dma_unmap_single(i2c->dev, rpaddr, dma_unmap_single(i2c->dev, rpaddr,
msgs->len, DMA_FROM_DEVICE); msgs->len, DMA_FROM_DEVICE);
i2c_put_dma_safe_msg_buf(dma_rd_buf, msgs, true);
} else { } else {
dma_unmap_single(i2c->dev, wpaddr, msgs->len, dma_unmap_single(i2c->dev, wpaddr, msgs->len,
DMA_TO_DEVICE); DMA_TO_DEVICE);
dma_unmap_single(i2c->dev, rpaddr, (msgs + 1)->len, dma_unmap_single(i2c->dev, rpaddr, (msgs + 1)->len,
DMA_FROM_DEVICE); DMA_FROM_DEVICE);
i2c_put_dma_safe_msg_buf(dma_wr_buf, msgs, true);
i2c_put_dma_safe_msg_buf(dma_rd_buf, (msgs + 1), true);
} }
if (ret == 0) { if (ret == 0) {
......
...@@ -661,9 +661,6 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, ...@@ -661,9 +661,6 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
dev_dbg(omap->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n", dev_dbg(omap->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
msg->addr, msg->len, msg->flags, stop); msg->addr, msg->len, msg->flags, stop);
if (msg->len == 0)
return -EINVAL;
omap->receiver = !!(msg->flags & I2C_M_RD); omap->receiver = !!(msg->flags & I2C_M_RD);
omap_i2c_resize_fifo(omap, msg->len, omap->receiver); omap_i2c_resize_fifo(omap, msg->len, omap->receiver);
...@@ -1179,6 +1176,10 @@ static const struct i2c_algorithm omap_i2c_algo = { ...@@ -1179,6 +1176,10 @@ static const struct i2c_algorithm omap_i2c_algo = {
.functionality = omap_i2c_func, .functionality = omap_i2c_func,
}; };
static const struct i2c_adapter_quirks omap_i2c_quirks = {
.flags = I2C_AQ_NO_ZERO_LEN,
};
#ifdef CONFIG_OF #ifdef CONFIG_OF
static struct omap_i2c_bus_platform_data omap2420_pdata = { static struct omap_i2c_bus_platform_data omap2420_pdata = {
.rev = OMAP_I2C_IP_VERSION_1, .rev = OMAP_I2C_IP_VERSION_1,
...@@ -1453,6 +1454,7 @@ omap_i2c_probe(struct platform_device *pdev) ...@@ -1453,6 +1454,7 @@ omap_i2c_probe(struct platform_device *pdev)
adap->class = I2C_CLASS_DEPRECATED; adap->class = I2C_CLASS_DEPRECATED;
strlcpy(adap->name, "OMAP I2C adapter", sizeof(adap->name)); strlcpy(adap->name, "OMAP I2C adapter", sizeof(adap->name));
adap->algo = &omap_i2c_algo; adap->algo = &omap_i2c_algo;
adap->quirks = &omap_i2c_quirks;
adap->dev.parent = &pdev->dev; adap->dev.parent = &pdev->dev;
adap->dev.of_node = pdev->dev.of_node; adap->dev.of_node = pdev->dev.of_node;
adap->bus_recovery_info = &omap_i2c_bus_recovery_info; adap->bus_recovery_info = &omap_i2c_bus_recovery_info;
......
...@@ -388,9 +388,8 @@ static void i2c_powermac_register_devices(struct i2c_adapter *adap, ...@@ -388,9 +388,8 @@ static void i2c_powermac_register_devices(struct i2c_adapter *adap,
static int i2c_powermac_probe(struct platform_device *dev) static int i2c_powermac_probe(struct platform_device *dev)
{ {
struct pmac_i2c_bus *bus = dev_get_platdata(&dev->dev); struct pmac_i2c_bus *bus = dev_get_platdata(&dev->dev);
struct device_node *parent = NULL; struct device_node *parent;
struct i2c_adapter *adapter; struct i2c_adapter *adapter;
const char *basename;
int rc; int rc;
if (bus == NULL) if (bus == NULL)
...@@ -407,23 +406,25 @@ static int i2c_powermac_probe(struct platform_device *dev) ...@@ -407,23 +406,25 @@ static int i2c_powermac_probe(struct platform_device *dev)
parent = of_get_parent(pmac_i2c_get_controller(bus)); parent = of_get_parent(pmac_i2c_get_controller(bus));
if (parent == NULL) if (parent == NULL)
return -EINVAL; return -EINVAL;
basename = parent->name; snprintf(adapter->name, sizeof(adapter->name), "%pOFn %d",
parent,
pmac_i2c_get_channel(bus));
of_node_put(parent);
break; break;
case pmac_i2c_bus_pmu: case pmac_i2c_bus_pmu:
basename = "pmu"; snprintf(adapter->name, sizeof(adapter->name), "pmu %d",
pmac_i2c_get_channel(bus));
break; break;
case pmac_i2c_bus_smu: case pmac_i2c_bus_smu:
/* This is not what we used to do but I'm fixing drivers at /* This is not what we used to do but I'm fixing drivers at
* the same time as this change * the same time as this change
*/ */
basename = "smu"; snprintf(adapter->name, sizeof(adapter->name), "smu %d",
pmac_i2c_get_channel(bus));
break; break;
default: default:
return -EINVAL; return -EINVAL;
} }
snprintf(adapter->name, sizeof(adapter->name), "%s %d", basename,
pmac_i2c_get_channel(bus));
of_node_put(parent);
platform_set_drvdata(dev, adapter); platform_set_drvdata(dev, adapter);
adapter->algo = &i2c_powermac_algorithm; adapter->algo = &i2c_powermac_algorithm;
......
...@@ -201,21 +201,23 @@ static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err) ...@@ -201,21 +201,23 @@ static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err)
static irqreturn_t geni_i2c_irq(int irq, void *dev) static irqreturn_t geni_i2c_irq(int irq, void *dev)
{ {
struct geni_i2c_dev *gi2c = dev; struct geni_i2c_dev *gi2c = dev;
int j; void __iomem *base = gi2c->se.base;
int j, p;
u32 m_stat; u32 m_stat;
u32 rx_st; u32 rx_st;
u32 dm_tx_st; u32 dm_tx_st;
u32 dm_rx_st; u32 dm_rx_st;
u32 dma; u32 dma;
u32 val;
struct i2c_msg *cur; struct i2c_msg *cur;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&gi2c->lock, flags); spin_lock_irqsave(&gi2c->lock, flags);
m_stat = readl_relaxed(gi2c->se.base + SE_GENI_M_IRQ_STATUS); m_stat = readl_relaxed(base + SE_GENI_M_IRQ_STATUS);
rx_st = readl_relaxed(gi2c->se.base + SE_GENI_RX_FIFO_STATUS); rx_st = readl_relaxed(base + SE_GENI_RX_FIFO_STATUS);
dm_tx_st = readl_relaxed(gi2c->se.base + SE_DMA_TX_IRQ_STAT); dm_tx_st = readl_relaxed(base + SE_DMA_TX_IRQ_STAT);
dm_rx_st = readl_relaxed(gi2c->se.base + SE_DMA_RX_IRQ_STAT); dm_rx_st = readl_relaxed(base + SE_DMA_RX_IRQ_STAT);
dma = readl_relaxed(gi2c->se.base + SE_GENI_DMA_MODE_EN); dma = readl_relaxed(base + SE_GENI_DMA_MODE_EN);
cur = gi2c->cur; cur = gi2c->cur;
if (!cur || if (!cur ||
...@@ -238,26 +240,17 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev) ...@@ -238,26 +240,17 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev)
/* Disable the TX Watermark interrupt to stop TX */ /* Disable the TX Watermark interrupt to stop TX */
if (!dma) if (!dma)
writel_relaxed(0, gi2c->se.base + writel_relaxed(0, base + SE_GENI_TX_WATERMARK_REG);
SE_GENI_TX_WATERMARK_REG); } else if (dma) {
goto irqret;
}
if (dma) {
dev_dbg(gi2c->se.dev, "i2c dma tx:0x%x, dma rx:0x%x\n", dev_dbg(gi2c->se.dev, "i2c dma tx:0x%x, dma rx:0x%x\n",
dm_tx_st, dm_rx_st); dm_tx_st, dm_rx_st);
goto irqret; } else if (cur->flags & I2C_M_RD &&
} m_stat & (M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN)) {
if (cur->flags & I2C_M_RD &&
m_stat & (M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN)) {
u32 rxcnt = rx_st & RX_FIFO_WC_MSK; u32 rxcnt = rx_st & RX_FIFO_WC_MSK;
for (j = 0; j < rxcnt; j++) { for (j = 0; j < rxcnt; j++) {
u32 val; p = 0;
int p = 0; val = readl_relaxed(base + SE_GENI_RX_FIFOn);
val = readl_relaxed(gi2c->se.base + SE_GENI_RX_FIFOn);
while (gi2c->cur_rd < cur->len && p < sizeof(val)) { while (gi2c->cur_rd < cur->len && p < sizeof(val)) {
cur->buf[gi2c->cur_rd++] = val & 0xff; cur->buf[gi2c->cur_rd++] = val & 0xff;
val >>= 8; val >>= 8;
...@@ -270,44 +263,39 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev) ...@@ -270,44 +263,39 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev)
m_stat & M_TX_FIFO_WATERMARK_EN) { m_stat & M_TX_FIFO_WATERMARK_EN) {
for (j = 0; j < gi2c->tx_wm; j++) { for (j = 0; j < gi2c->tx_wm; j++) {
u32 temp; u32 temp;
u32 val = 0;
int p = 0;
val = 0;
p = 0;
while (gi2c->cur_wr < cur->len && p < sizeof(val)) { while (gi2c->cur_wr < cur->len && p < sizeof(val)) {
temp = cur->buf[gi2c->cur_wr++]; temp = cur->buf[gi2c->cur_wr++];
val |= temp << (p * 8); val |= temp << (p * 8);
p++; p++;
} }
writel_relaxed(val, gi2c->se.base + SE_GENI_TX_FIFOn); writel_relaxed(val, base + SE_GENI_TX_FIFOn);
/* TX Complete, Disable the TX Watermark interrupt */ /* TX Complete, Disable the TX Watermark interrupt */
if (gi2c->cur_wr == cur->len) { if (gi2c->cur_wr == cur->len) {
writel_relaxed(0, gi2c->se.base + writel_relaxed(0, base + SE_GENI_TX_WATERMARK_REG);
SE_GENI_TX_WATERMARK_REG);
break; break;
} }
} }
} }
irqret:
if (m_stat) if (m_stat)
writel_relaxed(m_stat, gi2c->se.base + SE_GENI_M_IRQ_CLEAR); writel_relaxed(m_stat, base + SE_GENI_M_IRQ_CLEAR);
if (dma && dm_tx_st)
writel_relaxed(dm_tx_st, base + SE_DMA_TX_IRQ_CLR);
if (dma && dm_rx_st)
writel_relaxed(dm_rx_st, base + SE_DMA_RX_IRQ_CLR);
if (dma) {
if (dm_tx_st)
writel_relaxed(dm_tx_st, gi2c->se.base +
SE_DMA_TX_IRQ_CLR);
if (dm_rx_st)
writel_relaxed(dm_rx_st, gi2c->se.base +
SE_DMA_RX_IRQ_CLR);
}
/* if this is err with done-bit not set, handle that through timeout. */ /* if this is err with done-bit not set, handle that through timeout. */
if (m_stat & M_CMD_DONE_EN || m_stat & M_CMD_ABORT_EN) if (m_stat & M_CMD_DONE_EN || m_stat & M_CMD_ABORT_EN ||
complete(&gi2c->done); dm_tx_st & TX_DMA_DONE || dm_tx_st & TX_RESET_DONE ||
else if (dm_tx_st & TX_DMA_DONE || dm_tx_st & TX_RESET_DONE) dm_rx_st & RX_DMA_DONE || dm_rx_st & RX_RESET_DONE)
complete(&gi2c->done);
else if (dm_rx_st & RX_DMA_DONE || dm_rx_st & RX_RESET_DONE)
complete(&gi2c->done); complete(&gi2c->done);
spin_unlock_irqrestore(&gi2c->lock, flags); spin_unlock_irqrestore(&gi2c->lock, flags);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -365,29 +353,24 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, ...@@ -365,29 +353,24 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
u32 m_param) u32 m_param)
{ {
dma_addr_t rx_dma; dma_addr_t rx_dma;
enum geni_se_xfer_mode mode; unsigned long time_left;
unsigned long time_left = XFER_TIMEOUT;
void *dma_buf; void *dma_buf;
struct geni_se *se = &gi2c->se;
size_t len = msg->len;
gi2c->cur = msg;
mode = GENI_SE_FIFO;
dma_buf = i2c_get_dma_safe_msg_buf(msg, 32); dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
if (dma_buf) if (dma_buf)
mode = GENI_SE_DMA; geni_se_select_mode(se, GENI_SE_DMA);
else
geni_se_select_mode(&gi2c->se, mode); geni_se_select_mode(se, GENI_SE_FIFO);
writel_relaxed(msg->len, gi2c->se.base + SE_I2C_RX_TRANS_LEN);
geni_se_setup_m_cmd(&gi2c->se, I2C_READ, m_param); writel_relaxed(len, se->base + SE_I2C_RX_TRANS_LEN);
if (mode == GENI_SE_DMA) { geni_se_setup_m_cmd(se, I2C_READ, m_param);
int ret;
if (dma_buf && geni_se_rx_dma_prep(se, dma_buf, len, &rx_dma)) {
ret = geni_se_rx_dma_prep(&gi2c->se, dma_buf, msg->len, geni_se_select_mode(se, GENI_SE_FIFO);
&rx_dma); i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
if (ret) { dma_buf = NULL;
mode = GENI_SE_FIFO;
geni_se_select_mode(&gi2c->se, mode);
i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
}
} }
time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT); time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
...@@ -395,12 +378,13 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, ...@@ -395,12 +378,13 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
geni_i2c_abort_xfer(gi2c); geni_i2c_abort_xfer(gi2c);
gi2c->cur_rd = 0; gi2c->cur_rd = 0;
if (mode == GENI_SE_DMA) { if (dma_buf) {
if (gi2c->err) if (gi2c->err)
geni_i2c_rx_fsm_rst(gi2c); geni_i2c_rx_fsm_rst(gi2c);
geni_se_rx_dma_unprep(&gi2c->se, rx_dma, msg->len); geni_se_rx_dma_unprep(se, rx_dma, len);
i2c_put_dma_safe_msg_buf(dma_buf, msg, !gi2c->err); i2c_put_dma_safe_msg_buf(dma_buf, msg, !gi2c->err);
} }
return gi2c->err; return gi2c->err;
} }
...@@ -408,45 +392,41 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, ...@@ -408,45 +392,41 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
u32 m_param) u32 m_param)
{ {
dma_addr_t tx_dma; dma_addr_t tx_dma;
enum geni_se_xfer_mode mode;
unsigned long time_left; unsigned long time_left;
void *dma_buf; void *dma_buf;
struct geni_se *se = &gi2c->se;
size_t len = msg->len;
gi2c->cur = msg;
mode = GENI_SE_FIFO;
dma_buf = i2c_get_dma_safe_msg_buf(msg, 32); dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
if (dma_buf) if (dma_buf)
mode = GENI_SE_DMA; geni_se_select_mode(se, GENI_SE_DMA);
else
geni_se_select_mode(&gi2c->se, mode); geni_se_select_mode(se, GENI_SE_FIFO);
writel_relaxed(msg->len, gi2c->se.base + SE_I2C_TX_TRANS_LEN);
geni_se_setup_m_cmd(&gi2c->se, I2C_WRITE, m_param); writel_relaxed(len, se->base + SE_I2C_TX_TRANS_LEN);
if (mode == GENI_SE_DMA) { geni_se_setup_m_cmd(se, I2C_WRITE, m_param);
int ret;
if (dma_buf && geni_se_tx_dma_prep(se, dma_buf, len, &tx_dma)) {
ret = geni_se_tx_dma_prep(&gi2c->se, dma_buf, msg->len, geni_se_select_mode(se, GENI_SE_FIFO);
&tx_dma); i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
if (ret) { dma_buf = NULL;
mode = GENI_SE_FIFO;
geni_se_select_mode(&gi2c->se, mode);
i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
}
} }
if (mode == GENI_SE_FIFO) /* Get FIFO IRQ */ if (!dma_buf) /* Get FIFO IRQ */
writel_relaxed(1, gi2c->se.base + SE_GENI_TX_WATERMARK_REG); writel_relaxed(1, se->base + SE_GENI_TX_WATERMARK_REG);
time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT); time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
if (!time_left) if (!time_left)
geni_i2c_abort_xfer(gi2c); geni_i2c_abort_xfer(gi2c);
gi2c->cur_wr = 0; gi2c->cur_wr = 0;
if (mode == GENI_SE_DMA) { if (dma_buf) {
if (gi2c->err) if (gi2c->err)
geni_i2c_tx_fsm_rst(gi2c); geni_i2c_tx_fsm_rst(gi2c);
geni_se_tx_dma_unprep(&gi2c->se, tx_dma, msg->len); geni_se_tx_dma_unprep(se, tx_dma, len);
i2c_put_dma_safe_msg_buf(dma_buf, msg, !gi2c->err); i2c_put_dma_safe_msg_buf(dma_buf, msg, !gi2c->err);
} }
return gi2c->err; return gi2c->err;
} }
...@@ -474,6 +454,7 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, ...@@ -474,6 +454,7 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
m_param |= ((msgs[i].addr << SLV_ADDR_SHFT) & SLV_ADDR_MSK); m_param |= ((msgs[i].addr << SLV_ADDR_SHFT) & SLV_ADDR_MSK);
gi2c->cur = &msgs[i];
if (msgs[i].flags & I2C_M_RD) if (msgs[i].flags & I2C_M_RD)
ret = geni_i2c_rx_one_msg(gi2c, &msgs[i], m_param); ret = geni_i2c_rx_one_msg(gi2c, &msgs[i], m_param);
else else
......
...@@ -1088,11 +1088,6 @@ static int qup_i2c_xfer(struct i2c_adapter *adap, ...@@ -1088,11 +1088,6 @@ static int qup_i2c_xfer(struct i2c_adapter *adap,
writel(I2C_MINI_CORE | I2C_N_VAL, qup->base + QUP_CONFIG); writel(I2C_MINI_CORE | I2C_N_VAL, qup->base + QUP_CONFIG);
for (idx = 0; idx < num; idx++) { for (idx = 0; idx < num; idx++) {
if (msgs[idx].len == 0) {
ret = -EINVAL;
goto out;
}
if (qup_i2c_poll_state_i2c_master(qup)) { if (qup_i2c_poll_state_i2c_master(qup)) {
ret = -EIO; ret = -EIO;
goto out; goto out;
...@@ -1520,9 +1515,6 @@ qup_i2c_determine_mode_v2(struct qup_i2c_dev *qup, ...@@ -1520,9 +1515,6 @@ qup_i2c_determine_mode_v2(struct qup_i2c_dev *qup,
/* All i2c_msgs should be transferred using either dma or cpu */ /* All i2c_msgs should be transferred using either dma or cpu */
for (idx = 0; idx < num; idx++) { for (idx = 0; idx < num; idx++) {
if (msgs[idx].len == 0)
return -EINVAL;
if (msgs[idx].flags & I2C_M_RD) if (msgs[idx].flags & I2C_M_RD)
max_rx_len = max_t(unsigned int, max_rx_len, max_rx_len = max_t(unsigned int, max_rx_len,
msgs[idx].len); msgs[idx].len);
...@@ -1636,9 +1628,14 @@ static const struct i2c_algorithm qup_i2c_algo_v2 = { ...@@ -1636,9 +1628,14 @@ static const struct i2c_algorithm qup_i2c_algo_v2 = {
* which limits the possible read to 256 (QUP_READ_LIMIT) bytes. * which limits the possible read to 256 (QUP_READ_LIMIT) bytes.
*/ */
static const struct i2c_adapter_quirks qup_i2c_quirks = { static const struct i2c_adapter_quirks qup_i2c_quirks = {
.flags = I2C_AQ_NO_ZERO_LEN,
.max_read_len = QUP_READ_LIMIT, .max_read_len = QUP_READ_LIMIT,
}; };
static const struct i2c_adapter_quirks qup_i2c_quirks_v2 = {
.flags = I2C_AQ_NO_ZERO_LEN,
};
static void qup_i2c_enable_clocks(struct qup_i2c_dev *qup) static void qup_i2c_enable_clocks(struct qup_i2c_dev *qup)
{ {
clk_prepare_enable(qup->clk); clk_prepare_enable(qup->clk);
...@@ -1701,6 +1698,7 @@ static int qup_i2c_probe(struct platform_device *pdev) ...@@ -1701,6 +1698,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
is_qup_v1 = true; is_qup_v1 = true;
} else { } else {
qup->adap.algo = &qup_i2c_algo_v2; qup->adap.algo = &qup_i2c_algo_v2;
qup->adap.quirks = &qup_i2c_quirks_v2;
is_qup_v1 = false; is_qup_v1 = false;
if (acpi_match_device(qup_i2c_acpi_match, qup->dev)) if (acpi_match_device(qup_i2c_acpi_match, qup->dev))
goto nodma; goto nodma;
......
...@@ -947,27 +947,9 @@ static int sh_mobile_i2c_remove(struct platform_device *dev) ...@@ -947,27 +947,9 @@ static int sh_mobile_i2c_remove(struct platform_device *dev)
return 0; return 0;
} }
static int sh_mobile_i2c_runtime_nop(struct device *dev)
{
/* Runtime PM callback shared between ->runtime_suspend()
* and ->runtime_resume(). Simply returns success.
*
* This driver re-initializes all registers after
* pm_runtime_get_sync() anyway so there is no need
* to save and restore registers here.
*/
return 0;
}
static const struct dev_pm_ops sh_mobile_i2c_dev_pm_ops = {
.runtime_suspend = sh_mobile_i2c_runtime_nop,
.runtime_resume = sh_mobile_i2c_runtime_nop,
};
static struct platform_driver sh_mobile_i2c_driver = { static struct platform_driver sh_mobile_i2c_driver = {
.driver = { .driver = {
.name = "i2c-sh_mobile", .name = "i2c-sh_mobile",
.pm = &sh_mobile_i2c_dev_pm_ops,
.of_match_table = sh_mobile_i2c_dt_ids, .of_match_table = sh_mobile_i2c_dt_ids,
}, },
.probe = sh_mobile_i2c_probe, .probe = sh_mobile_i2c_probe,
......
...@@ -404,7 +404,7 @@ static irqreturn_t synquacer_i2c_isr(int irq, void *dev_id) ...@@ -404,7 +404,7 @@ static irqreturn_t synquacer_i2c_isr(int irq, void *dev_id)
if (i2c->state == STATE_READ) if (i2c->state == STATE_READ)
goto prepare_read; goto prepare_read;
/* fallthru */ /* fall through */
case STATE_WRITE: case STATE_WRITE:
if (bsr & SYNQUACER_I2C_BSR_LRB) { if (bsr & SYNQUACER_I2C_BSR_LRB) {
......
...@@ -684,9 +684,6 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, ...@@ -684,9 +684,6 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
tegra_i2c_flush_fifos(i2c_dev); tegra_i2c_flush_fifos(i2c_dev);
if (msg->len == 0)
return -EINVAL;
i2c_dev->msg_buf = msg->buf; i2c_dev->msg_buf = msg->buf;
i2c_dev->msg_buf_remaining = msg->len; i2c_dev->msg_buf_remaining = msg->len;
i2c_dev->msg_err = I2C_ERR_NONE; i2c_dev->msg_err = I2C_ERR_NONE;
...@@ -831,6 +828,7 @@ static const struct i2c_algorithm tegra_i2c_algo = { ...@@ -831,6 +828,7 @@ static const struct i2c_algorithm tegra_i2c_algo = {
/* payload size is only 12 bit */ /* payload size is only 12 bit */
static const struct i2c_adapter_quirks tegra_i2c_quirks = { static const struct i2c_adapter_quirks tegra_i2c_quirks = {
.flags = I2C_AQ_NO_ZERO_LEN,
.max_read_len = 4096, .max_read_len = 4096,
.max_write_len = 4096, .max_write_len = 4096,
}; };
......
...@@ -98,6 +98,7 @@ struct uniphier_fi2c_priv { ...@@ -98,6 +98,7 @@ struct uniphier_fi2c_priv {
unsigned int flags; unsigned int flags;
unsigned int busy_cnt; unsigned int busy_cnt;
unsigned int clk_cycle; unsigned int clk_cycle;
spinlock_t lock; /* IRQ synchronization */
}; };
static void uniphier_fi2c_fill_txfifo(struct uniphier_fi2c_priv *priv, static void uniphier_fi2c_fill_txfifo(struct uniphier_fi2c_priv *priv,
...@@ -142,9 +143,10 @@ static void uniphier_fi2c_set_irqs(struct uniphier_fi2c_priv *priv) ...@@ -142,9 +143,10 @@ static void uniphier_fi2c_set_irqs(struct uniphier_fi2c_priv *priv)
writel(priv->enabled_irqs, priv->membase + UNIPHIER_FI2C_IE); writel(priv->enabled_irqs, priv->membase + UNIPHIER_FI2C_IE);
} }
static void uniphier_fi2c_clear_irqs(struct uniphier_fi2c_priv *priv) static void uniphier_fi2c_clear_irqs(struct uniphier_fi2c_priv *priv,
u32 mask)
{ {
writel(-1, priv->membase + UNIPHIER_FI2C_IC); writel(mask, priv->membase + UNIPHIER_FI2C_IC);
} }
static void uniphier_fi2c_stop(struct uniphier_fi2c_priv *priv) static void uniphier_fi2c_stop(struct uniphier_fi2c_priv *priv)
...@@ -162,12 +164,17 @@ static irqreturn_t uniphier_fi2c_interrupt(int irq, void *dev_id) ...@@ -162,12 +164,17 @@ static irqreturn_t uniphier_fi2c_interrupt(int irq, void *dev_id)
struct uniphier_fi2c_priv *priv = dev_id; struct uniphier_fi2c_priv *priv = dev_id;
u32 irq_status; u32 irq_status;
spin_lock(&priv->lock);
irq_status = readl(priv->membase + UNIPHIER_FI2C_INT); irq_status = readl(priv->membase + UNIPHIER_FI2C_INT);
irq_status &= priv->enabled_irqs;
dev_dbg(&priv->adap.dev, dev_dbg(&priv->adap.dev,
"interrupt: enabled_irqs=%04x, irq_status=%04x\n", "interrupt: enabled_irqs=%04x, irq_status=%04x\n",
priv->enabled_irqs, irq_status); priv->enabled_irqs, irq_status);
uniphier_fi2c_clear_irqs(priv, irq_status);
if (irq_status & UNIPHIER_FI2C_INT_STOP) if (irq_status & UNIPHIER_FI2C_INT_STOP)
goto complete; goto complete;
...@@ -230,6 +237,8 @@ static irqreturn_t uniphier_fi2c_interrupt(int irq, void *dev_id) ...@@ -230,6 +237,8 @@ static irqreturn_t uniphier_fi2c_interrupt(int irq, void *dev_id)
goto handled; goto handled;
} }
spin_unlock(&priv->lock);
return IRQ_NONE; return IRQ_NONE;
data_done: data_done:
...@@ -244,7 +253,7 @@ static irqreturn_t uniphier_fi2c_interrupt(int irq, void *dev_id) ...@@ -244,7 +253,7 @@ static irqreturn_t uniphier_fi2c_interrupt(int irq, void *dev_id)
} }
handled: handled:
uniphier_fi2c_clear_irqs(priv); spin_unlock(&priv->lock);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -252,6 +261,8 @@ static irqreturn_t uniphier_fi2c_interrupt(int irq, void *dev_id) ...@@ -252,6 +261,8 @@ static irqreturn_t uniphier_fi2c_interrupt(int irq, void *dev_id)
static void uniphier_fi2c_tx_init(struct uniphier_fi2c_priv *priv, u16 addr) static void uniphier_fi2c_tx_init(struct uniphier_fi2c_priv *priv, u16 addr)
{ {
priv->enabled_irqs |= UNIPHIER_FI2C_INT_TE; priv->enabled_irqs |= UNIPHIER_FI2C_INT_TE;
uniphier_fi2c_set_irqs(priv);
/* do not use TX byte counter */ /* do not use TX byte counter */
writel(0, priv->membase + UNIPHIER_FI2C_TBC); writel(0, priv->membase + UNIPHIER_FI2C_TBC);
/* set slave address */ /* set slave address */
...@@ -284,6 +295,8 @@ static void uniphier_fi2c_rx_init(struct uniphier_fi2c_priv *priv, u16 addr) ...@@ -284,6 +295,8 @@ static void uniphier_fi2c_rx_init(struct uniphier_fi2c_priv *priv, u16 addr)
priv->enabled_irqs |= UNIPHIER_FI2C_INT_RF; priv->enabled_irqs |= UNIPHIER_FI2C_INT_RF;
} }
uniphier_fi2c_set_irqs(priv);
/* set slave address with RD bit */ /* set slave address with RD bit */
writel(UNIPHIER_FI2C_DTTX_CMD | UNIPHIER_FI2C_DTTX_RD | addr << 1, writel(UNIPHIER_FI2C_DTTX_CMD | UNIPHIER_FI2C_DTTX_RD | addr << 1,
priv->membase + UNIPHIER_FI2C_DTTX); priv->membase + UNIPHIER_FI2C_DTTX);
...@@ -307,14 +320,16 @@ static void uniphier_fi2c_recover(struct uniphier_fi2c_priv *priv) ...@@ -307,14 +320,16 @@ static void uniphier_fi2c_recover(struct uniphier_fi2c_priv *priv)
} }
static int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap, static int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap,
struct i2c_msg *msg, bool stop) struct i2c_msg *msg, bool repeat,
bool stop)
{ {
struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap); struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap);
bool is_read = msg->flags & I2C_M_RD; bool is_read = msg->flags & I2C_M_RD;
unsigned long time_left; unsigned long time_left, flags;
dev_dbg(&adap->dev, "%s: addr=0x%02x, len=%d, stop=%d\n", dev_dbg(&adap->dev, "%s: addr=0x%02x, len=%d, repeat=%d, stop=%d\n",
is_read ? "receive" : "transmit", msg->addr, msg->len, stop); is_read ? "receive" : "transmit", msg->addr, msg->len,
repeat, stop);
priv->len = msg->len; priv->len = msg->len;
priv->buf = msg->buf; priv->buf = msg->buf;
...@@ -326,22 +341,36 @@ static int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap, ...@@ -326,22 +341,36 @@ static int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap,
priv->flags |= UNIPHIER_FI2C_STOP; priv->flags |= UNIPHIER_FI2C_STOP;
reinit_completion(&priv->comp); reinit_completion(&priv->comp);
uniphier_fi2c_clear_irqs(priv); uniphier_fi2c_clear_irqs(priv, U32_MAX);
writel(UNIPHIER_FI2C_RST_TBRST | UNIPHIER_FI2C_RST_RBRST, writel(UNIPHIER_FI2C_RST_TBRST | UNIPHIER_FI2C_RST_RBRST,
priv->membase + UNIPHIER_FI2C_RST); /* reset TX/RX FIFO */ priv->membase + UNIPHIER_FI2C_RST); /* reset TX/RX FIFO */
spin_lock_irqsave(&priv->lock, flags);
if (is_read) if (is_read)
uniphier_fi2c_rx_init(priv, msg->addr); uniphier_fi2c_rx_init(priv, msg->addr);
else else
uniphier_fi2c_tx_init(priv, msg->addr); uniphier_fi2c_tx_init(priv, msg->addr);
uniphier_fi2c_set_irqs(priv);
dev_dbg(&adap->dev, "start condition\n"); dev_dbg(&adap->dev, "start condition\n");
writel(UNIPHIER_FI2C_CR_MST | UNIPHIER_FI2C_CR_STA, /*
priv->membase + UNIPHIER_FI2C_CR); * For a repeated START condition, writing a slave address to the FIFO
* kicks the controller. So, the UNIPHIER_FI2C_CR register should be
* written only for a non-repeated START condition.
*/
if (!repeat)
writel(UNIPHIER_FI2C_CR_MST | UNIPHIER_FI2C_CR_STA,
priv->membase + UNIPHIER_FI2C_CR);
spin_unlock_irqrestore(&priv->lock, flags);
time_left = wait_for_completion_timeout(&priv->comp, adap->timeout); time_left = wait_for_completion_timeout(&priv->comp, adap->timeout);
spin_lock_irqsave(&priv->lock, flags);
priv->enabled_irqs = 0;
uniphier_fi2c_set_irqs(priv);
spin_unlock_irqrestore(&priv->lock, flags);
if (!time_left) { if (!time_left) {
dev_err(&adap->dev, "transaction timeout.\n"); dev_err(&adap->dev, "transaction timeout.\n");
uniphier_fi2c_recover(priv); uniphier_fi2c_recover(priv);
...@@ -394,6 +423,7 @@ static int uniphier_fi2c_master_xfer(struct i2c_adapter *adap, ...@@ -394,6 +423,7 @@ static int uniphier_fi2c_master_xfer(struct i2c_adapter *adap,
struct i2c_msg *msgs, int num) struct i2c_msg *msgs, int num)
{ {
struct i2c_msg *msg, *emsg = msgs + num; struct i2c_msg *msg, *emsg = msgs + num;
bool repeat = false;
int ret; int ret;
ret = uniphier_fi2c_check_bus_busy(adap); ret = uniphier_fi2c_check_bus_busy(adap);
...@@ -404,9 +434,11 @@ static int uniphier_fi2c_master_xfer(struct i2c_adapter *adap, ...@@ -404,9 +434,11 @@ static int uniphier_fi2c_master_xfer(struct i2c_adapter *adap,
/* Emit STOP if it is the last message or I2C_M_STOP is set. */ /* Emit STOP if it is the last message or I2C_M_STOP is set. */
bool stop = (msg + 1 == emsg) || (msg->flags & I2C_M_STOP); bool stop = (msg + 1 == emsg) || (msg->flags & I2C_M_STOP);
ret = uniphier_fi2c_master_xfer_one(adap, msg, stop); ret = uniphier_fi2c_master_xfer_one(adap, msg, repeat, stop);
if (ret) if (ret)
return ret; return ret;
repeat = !stop;
} }
return num; return num;
...@@ -529,6 +561,7 @@ static int uniphier_fi2c_probe(struct platform_device *pdev) ...@@ -529,6 +561,7 @@ static int uniphier_fi2c_probe(struct platform_device *pdev)
priv->clk_cycle = clk_rate / bus_speed; priv->clk_cycle = clk_rate / bus_speed;
init_completion(&priv->comp); init_completion(&priv->comp);
spin_lock_init(&priv->lock);
priv->adap.owner = THIS_MODULE; priv->adap.owner = THIS_MODULE;
priv->adap.algo = &uniphier_fi2c_algo; priv->adap.algo = &uniphier_fi2c_algo;
priv->adap.dev.parent = dev; priv->adap.dev.parent = dev;
......
...@@ -281,9 +281,6 @@ static int zx2967_i2c_xfer_msg(struct zx2967_i2c *i2c, ...@@ -281,9 +281,6 @@ static int zx2967_i2c_xfer_msg(struct zx2967_i2c *i2c,
int ret; int ret;
int i; int i;
if (msg->len == 0)
return -EINVAL;
zx2967_i2c_flush_fifos(i2c); zx2967_i2c_flush_fifos(i2c);
i2c->cur_trans = msg->buf; i2c->cur_trans = msg->buf;
...@@ -498,6 +495,10 @@ static const struct i2c_algorithm zx2967_i2c_algo = { ...@@ -498,6 +495,10 @@ static const struct i2c_algorithm zx2967_i2c_algo = {
.functionality = zx2967_i2c_func, .functionality = zx2967_i2c_func,
}; };
static const struct i2c_adapter_quirks zx2967_i2c_quirks = {
.flags = I2C_AQ_NO_ZERO_LEN,
};
static const struct of_device_id zx2967_i2c_of_match[] = { static const struct of_device_id zx2967_i2c_of_match[] = {
{ .compatible = "zte,zx296718-i2c", }, { .compatible = "zte,zx296718-i2c", },
{ }, { },
...@@ -568,6 +569,7 @@ static int zx2967_i2c_probe(struct platform_device *pdev) ...@@ -568,6 +569,7 @@ static int zx2967_i2c_probe(struct platform_device *pdev)
strlcpy(i2c->adap.name, "zx2967 i2c adapter", strlcpy(i2c->adap.name, "zx2967 i2c adapter",
sizeof(i2c->adap.name)); sizeof(i2c->adap.name));
i2c->adap.algo = &zx2967_i2c_algo; i2c->adap.algo = &zx2967_i2c_algo;
i2c->adap.quirks = &zx2967_i2c_quirks;
i2c->adap.nr = pdev->id; i2c->adap.nr = pdev->id;
i2c->adap.dev.parent = &pdev->dev; i2c->adap.dev.parent = &pdev->dev;
i2c->adap.dev.of_node = pdev->dev.of_node; i2c->adap.dev.of_node = pdev->dev.of_node;
......
...@@ -1922,6 +1922,11 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) ...@@ -1922,6 +1922,11 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{ {
int ret; int ret;
if (!adap->algo->master_xfer) {
dev_dbg(&adap->dev, "I2C level transfers not supported\n");
return -EOPNOTSUPP;
}
/* REVISIT the fault reporting model here is weak: /* REVISIT the fault reporting model here is weak:
* *
* - When we get an error after receiving N bytes from a slave, * - When we get an error after receiving N bytes from a slave,
...@@ -1938,35 +1943,19 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) ...@@ -1938,35 +1943,19 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
* one (discarding status on the second message) or errno * one (discarding status on the second message) or errno
* (discarding status on the first one). * (discarding status on the first one).
*/ */
if (in_atomic() || irqs_disabled()) {
if (adap->algo->master_xfer) { ret = i2c_trylock_bus(adap, I2C_LOCK_SEGMENT);
#ifdef DEBUG if (!ret)
for (ret = 0; ret < num; ret++) { /* I2C activity is ongoing. */
dev_dbg(&adap->dev, return -EAGAIN;
"master_xfer[%d] %c, addr=0x%02x, len=%d%s\n",
ret, (msgs[ret].flags & I2C_M_RD) ? 'R' : 'W',
msgs[ret].addr, msgs[ret].len,
(msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
}
#endif
if (in_atomic() || irqs_disabled()) {
ret = i2c_trylock_bus(adap, I2C_LOCK_SEGMENT);
if (!ret)
/* I2C activity is ongoing. */
return -EAGAIN;
} else {
i2c_lock_bus(adap, I2C_LOCK_SEGMENT);
}
ret = __i2c_transfer(adap, msgs, num);
i2c_unlock_bus(adap, I2C_LOCK_SEGMENT);
return ret;
} else { } else {
dev_dbg(&adap->dev, "I2C level transfers not supported\n"); i2c_lock_bus(adap, I2C_LOCK_SEGMENT);
return -EOPNOTSUPP;
} }
ret = __i2c_transfer(adap, msgs, num);
i2c_unlock_bus(adap, I2C_LOCK_SEGMENT);
return ret;
} }
EXPORT_SYMBOL(i2c_transfer); EXPORT_SYMBOL(i2c_transfer);
......
...@@ -120,8 +120,8 @@ static int i2c_mux_probe(struct platform_device *pdev) ...@@ -120,8 +120,8 @@ static int i2c_mux_probe(struct platform_device *pdev)
ret = of_property_read_u32(child, "reg", &chan); ret = of_property_read_u32(child, "reg", &chan);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "no reg property for node '%s'\n", dev_err(dev, "no reg property for node '%pOFn'\n",
child->name); child);
goto err_children; goto err_children;
} }
......
...@@ -208,7 +208,7 @@ MODULE_DEVICE_TABLE(of, ltc4306_of_match); ...@@ -208,7 +208,7 @@ MODULE_DEVICE_TABLE(of, ltc4306_of_match);
static int ltc4306_probe(struct i2c_client *client) static int ltc4306_probe(struct i2c_client *client)
{ {
struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); struct i2c_adapter *adap = client->adapter;
const struct chip_desc *chip; const struct chip_desc *chip;
struct i2c_mux_core *muxc; struct i2c_mux_core *muxc;
struct ltc4306 *data; struct ltc4306 *data;
......
...@@ -132,7 +132,7 @@ static int mlxcpld_mux_deselect(struct i2c_mux_core *muxc, u32 chan) ...@@ -132,7 +132,7 @@ static int mlxcpld_mux_deselect(struct i2c_mux_core *muxc, u32 chan)
static int mlxcpld_mux_probe(struct i2c_client *client, static int mlxcpld_mux_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); struct i2c_adapter *adap = client->adapter;
struct mlxcpld_mux_plat_data *pdata = dev_get_platdata(&client->dev); struct mlxcpld_mux_plat_data *pdata = dev_get_platdata(&client->dev);
struct i2c_mux_core *muxc; struct i2c_mux_core *muxc;
int num, force; int num, force;
......
...@@ -347,7 +347,7 @@ static void pca954x_cleanup(struct i2c_mux_core *muxc) ...@@ -347,7 +347,7 @@ static void pca954x_cleanup(struct i2c_mux_core *muxc)
static int pca954x_probe(struct i2c_client *client, static int pca954x_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); struct i2c_adapter *adap = client->adapter;
struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev); struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev);
struct device *dev = &client->dev; struct device *dev = &client->dev;
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
......
...@@ -106,23 +106,6 @@ static unsigned int at24_write_timeout = 25; ...@@ -106,23 +106,6 @@ static unsigned int at24_write_timeout = 25;
module_param_named(write_timeout, at24_write_timeout, uint, 0); module_param_named(write_timeout, at24_write_timeout, uint, 0);
MODULE_PARM_DESC(at24_write_timeout, "Time (in ms) to try writes (default 25)"); MODULE_PARM_DESC(at24_write_timeout, "Time (in ms) to try writes (default 25)");
/*
* Both reads and writes fail if the previous write didn't complete yet. This
* macro loops a few times waiting at least long enough for one entire page
* write to work while making sure that at least one iteration is run before
* checking the break condition.
*
* It takes two parameters: a variable in which the future timeout in jiffies
* will be stored and a temporary variable holding the time of the last
* iteration of processing the request. Both should be unsigned integers
* holding at least 32 bits.
*/
#define at24_loop_until_timeout(tout, op_time) \
for (tout = jiffies + msecs_to_jiffies(at24_write_timeout), \
op_time = 0; \
op_time ? time_before(op_time, tout) : true; \
usleep_range(1000, 1500), op_time = jiffies)
struct at24_chip_data { struct at24_chip_data {
/* /*
* these fields mirror their equivalents in * these fields mirror their equivalents in
...@@ -308,13 +291,22 @@ static ssize_t at24_regmap_read(struct at24_data *at24, char *buf, ...@@ -308,13 +291,22 @@ static ssize_t at24_regmap_read(struct at24_data *at24, char *buf,
/* adjust offset for mac and serial read ops */ /* adjust offset for mac and serial read ops */
offset += at24->offset_adj; offset += at24->offset_adj;
at24_loop_until_timeout(timeout, read_time) { timeout = jiffies + msecs_to_jiffies(at24_write_timeout);
do {
/*
* The timestamp shall be taken before the actual operation
* to avoid a premature timeout in case of high CPU load.
*/
read_time = jiffies;
ret = regmap_bulk_read(regmap, offset, buf, count); ret = regmap_bulk_read(regmap, offset, buf, count);
dev_dbg(&client->dev, "read %zu@%d --> %d (%ld)\n", dev_dbg(&client->dev, "read %zu@%d --> %d (%ld)\n",
count, offset, ret, jiffies); count, offset, ret, jiffies);
if (!ret) if (!ret)
return count; return count;
}
usleep_range(1000, 1500);
} while (time_before(read_time, timeout));
return -ETIMEDOUT; return -ETIMEDOUT;
} }
...@@ -358,14 +350,23 @@ static ssize_t at24_regmap_write(struct at24_data *at24, const char *buf, ...@@ -358,14 +350,23 @@ static ssize_t at24_regmap_write(struct at24_data *at24, const char *buf,
regmap = at24_client->regmap; regmap = at24_client->regmap;
client = at24_client->client; client = at24_client->client;
count = at24_adjust_write_count(at24, offset, count); count = at24_adjust_write_count(at24, offset, count);
timeout = jiffies + msecs_to_jiffies(at24_write_timeout);
do {
/*
* The timestamp shall be taken before the actual operation
* to avoid a premature timeout in case of high CPU load.
*/
write_time = jiffies;
at24_loop_until_timeout(timeout, write_time) {
ret = regmap_bulk_write(regmap, offset, buf, count); ret = regmap_bulk_write(regmap, offset, buf, count);
dev_dbg(&client->dev, "write %zu@%d --> %d (%ld)\n", dev_dbg(&client->dev, "write %zu@%d --> %d (%ld)\n",
count, offset, ret, jiffies); count, offset, ret, jiffies);
if (!ret) if (!ret)
return count; return count;
}
usleep_range(1000, 1500);
} while (time_before(write_time, timeout));
return -ETIMEDOUT; return -ETIMEDOUT;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment