* [PATCH v3 1/5] i2c: designware: Refactoring of the i2c-designware core and platform module
2016-11-18 11:19 [PATCH v3 0/5] i2c: designware: Add slave support Luis Oliveira
@ 2016-11-18 11:19 ` Luis Oliveira
2016-11-18 12:26 ` Andy Shevchenko
2016-11-18 11:19 ` [PATCH v3 2/5] i2c: designware: Master mode as separated driver Luis Oliveira
` (3 subsequent siblings)
4 siblings, 1 reply; 19+ messages in thread
From: Luis Oliveira @ 2016-11-18 11:19 UTC (permalink / raw)
To: wsa, robh+dt, mark.rutland, jarkko.nikula, andriy.shevchenko,
mika.westerberg, linux-i2c, devicetree, linux-kernel
Cc: Luis.Oliveira, Ramiro.Oliveira, Joao.Pinto, CARLOS.PALMINHA
- Factor out _master() parts of code to separate functions.
- Standardize all code relatated to I2C master.
Signed-off-by: Luis Oliveira <lolivei@synopsys.com>
---
Changes V2->V3: (Andy Shevchenko)
- indentation and style fix
- nothing else was changed in this patch from v2
drivers/i2c/busses/i2c-designware-core.c | 66 +++++++++++++++++++----------
drivers/i2c/busses/i2c-designware-platdrv.c | 36 ++++++++++------
2 files changed, 66 insertions(+), 36 deletions(-)
diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
index 11e866d..22f79fa 100644
--- a/drivers/i2c/busses/i2c-designware-core.c
+++ b/drivers/i2c/busses/i2c-designware-core.c
@@ -87,13 +87,13 @@
#define DW_IC_INTR_GEN_CALL 0x800
#define DW_IC_INTR_DEFAULT_MASK (DW_IC_INTR_RX_FULL | \
- DW_IC_INTR_TX_EMPTY | \
DW_IC_INTR_TX_ABRT | \
DW_IC_INTR_STOP_DET)
-
+#define DW_IC_INTR_MASTER_MASK (DW_IC_INTR_DEFAULT_MASK | \
+ DW_IC_INTR_TX_EMPTY)
#define DW_IC_STATUS_ACTIVITY 0x1
#define DW_IC_STATUS_TFE BIT(2)
-#define DW_IC_STATUS_MST_ACTIVITY BIT(5)
+#define DW_IC_STATUS_MASTER_ACTIVITY BIT(5)
#define DW_IC_SDA_HOLD_RX_SHIFT 16
#define DW_IC_SDA_HOLD_RX_MASK GENMASK(23, DW_IC_SDA_HOLD_RX_SHIFT)
@@ -204,6 +204,17 @@ static void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset)
}
}
+static void i2c_dw_configure_fifo_master(struct dw_i2c_dev *dev)
+{
+ /* Configure Tx/Rx FIFO threshold levels */
+ dw_writel(dev, dev->tx_fifo_depth / 2, DW_IC_TX_TL);
+ dw_writel(dev, 0, DW_IC_RX_TL);
+
+ /* configure the i2c master */
+ dw_writel(dev, dev->master_cfg, DW_IC_CON);
+ dw_writel(dev, DW_IC_INTR_MASTER_MASK, DW_IC_INTR_MASK);
+}
+
static u32
i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset)
{
@@ -320,10 +331,10 @@ static void i2c_dw_release_lock(struct dw_i2c_dev *dev)
}
/**
- * i2c_dw_init() - initialize the designware i2c master hardware
+ * i2c_dw_init() - initialize the designware i2c hardware
* @dev: device private data
*
- * This functions configures and enables the I2C master.
+ * This functions configures and enables the I2C.
* This function is called during I2C init function, and in case of timeout at
* run time.
*/
@@ -442,12 +453,9 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
"Hardware too old to adjust SDA hold time.\n");
}
- /* Configure Tx/Rx FIFO threshold levels */
- dw_writel(dev, dev->tx_fifo_depth / 2, DW_IC_TX_TL);
- dw_writel(dev, 0, DW_IC_RX_TL);
-
- /* configure the i2c master */
- dw_writel(dev, dev->master_cfg , DW_IC_CON);
+ if ((dev->master_cfg & DW_IC_CON_MASTER) &&
+ (dev->master_cfg & DW_IC_CON_SLAVE_DISABLE))
+ i2c_dw_configure_fifo_master(dev);
i2c_dw_release_lock(dev);
@@ -491,7 +499,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
*/
ic_status = dw_readl(dev, DW_IC_STATUS);
if (!dev->dynamic_tar_update_enabled ||
- (ic_status & DW_IC_STATUS_MST_ACTIVITY) ||
+ (ic_status & DW_IC_STATUS_MASTER_ACTIVITY) ||
!(ic_status & DW_IC_STATUS_TFE)) {
__i2c_dw_enable_and_wait(dev, false);
enabled = false;
@@ -531,7 +539,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
/* Clear and enable interrupts */
dw_readl(dev, DW_IC_CLR_INTR);
- dw_writel(dev, DW_IC_INTR_DEFAULT_MASK, DW_IC_INTR_MASK);
+ dw_writel(dev, DW_IC_INTR_MASTER_MASK, DW_IC_INTR_MASK);
}
/*
@@ -551,7 +559,7 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
u8 *buf = dev->tx_buf;
bool need_restart = false;
- intr_mask = DW_IC_INTR_DEFAULT_MASK;
+ intr_mask = DW_IC_INTR_MASTER_MASK;
for (; dev->msg_write_idx < dev->msgs_num; dev->msg_write_idx++) {
/*
@@ -850,16 +858,9 @@ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
* Interrupt service routine. This gets called whenever an I2C interrupt
* occurs.
*/
-static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
+static bool i2c_dw_irq_handler_master(struct dw_i2c_dev *dev)
{
- struct dw_i2c_dev *dev = dev_id;
- u32 stat, enabled;
-
- enabled = dw_readl(dev, DW_IC_ENABLE);
- stat = dw_readl(dev, DW_IC_RAW_INTR_STAT);
- dev_dbg(dev->dev, "%s: enabled=%#x stat=%#x\n", __func__, enabled, stat);
- if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY))
- return IRQ_NONE;
+ u32 stat;
stat = i2c_dw_read_clear_intrbits(dev);
@@ -906,7 +907,26 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
i2c_dw_disable_int(dev);
dw_writel(dev, stat, DW_IC_INTR_MASK);
}
+ return true;
+}
+
+static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
+{
+ struct dw_i2c_dev *dev = dev_id;
+ u32 stat, enabled, mode;
+
+ enabled = dw_readl(dev, DW_IC_ENABLE);
+ mode = dw_readl(dev, DW_IC_CON);
+ stat = dw_readl(dev, DW_IC_RAW_INTR_STAT);
+
+ dev_dbg(dev->dev, "%s: enabled=%#x stat=%#x\n", __func__, enabled, stat);
+ if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY))
+ return IRQ_NONE;
+
+ if (i2c_dw_irq_handler_master(dev))
+ return IRQ_HANDLED;
+ complete(&dev->cmd_complete);
return IRQ_HANDLED;
}
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index 0b42a12..f4e28ac 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -138,6 +138,28 @@ static inline int dw_i2c_acpi_configure(struct platform_device *pdev)
}
#endif
+static void i2c_dw_configure_master(struct platform_device *pdev)
+{
+ struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
+
+ dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
+ DW_IC_CON_RESTART_EN;
+
+ dev->functionality |= I2C_FUNC_10BIT_ADDR;
+ dev_info(&pdev->dev, "I am registed as a I2C Master!\n");
+
+ switch (dev->clk_freq) {
+ case 100000:
+ dev->master_cfg |= DW_IC_CON_SPEED_STD;
+ break;
+ case 3400000:
+ dev->master_cfg |= DW_IC_CON_SPEED_HIGH;
+ break;
+ default:
+ dev->master_cfg |= DW_IC_CON_SPEED_FAST;
+ }
+}
+
static int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare)
{
if (IS_ERR(i_dev->clk))
@@ -222,19 +244,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_I2C_BLOCK;
- dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
- DW_IC_CON_RESTART_EN;
-
- switch (dev->clk_freq) {
- case 100000:
- dev->master_cfg |= DW_IC_CON_SPEED_STD;
- break;
- case 3400000:
- dev->master_cfg |= DW_IC_CON_SPEED_HIGH;
- break;
- default:
- dev->master_cfg |= DW_IC_CON_SPEED_FAST;
- }
+ i2c_dw_configure_master(pdev);
dev->clk = devm_clk_get(&pdev->dev, NULL);
if (!i2c_dw_plat_prepare_clk(dev, true)) {
--
2.10.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH v3 1/5] i2c: designware: Refactoring of the i2c-designware core and platform module
@ 2016-11-18 12:26 ` Andy Shevchenko
0 siblings, 0 replies; 19+ messages in thread
From: Andy Shevchenko @ 2016-11-18 12:26 UTC (permalink / raw)
To: Luis Oliveira, wsa, robh+dt, mark.rutland, jarkko.nikula,
mika.westerberg, linux-i2c, devicetree, linux-kernel
Cc: Ramiro.Oliveira, Joao.Pinto, CARLOS.PALMINHA
On Fri, 2016-11-18 at 11:19 +0000, Luis Oliveira wrote:
> - Factor out _master() parts of code to separate functions.
> - Standardize all code relatated to I2C master.
>
> Signed-off-by: Luis Oliveira <lolivei@synopsys.com>
Can you shrink Cc list to people who indeed are involved / concerned?
> ---
> Changes V2->V3: (Andy Shevchenko)
> - indentation and style fix
> - nothing else was changed in this patch from v2
Hmm...
May I add few more comments?
> @@ -87,13 +87,13 @@
> #define DW_IC_INTR_GEN_CALL 0x800
>
> #define DW_IC_INTR_DEFAULT_MASK (DW_IC_INTR_RX_FULL |
> \
> - DW_IC_INTR_TX_EMPTY | \
> DW_IC_INTR_TX_ABRT | \
> DW_IC_INTR_STOP_DET)
> -
Do you need to remove it?
I would leave it...
> +#define DW_IC_INTR_MASTER_MASK (DW_IC_INTR_DEFAULT_MAS
> K | \
> + DW_IC_INTR_TX_EMPTY)
...here.
> #define DW_IC_STATUS_ACTIVITY 0x1
> #define DW_IC_STATUS_TFE BIT(2)
> -#define DW_IC_STATUS_MST_ACTIVITY BIT(5)
> +#define DW_IC_STATUS_MASTER_ACTIVITY BIT(5)
> +static void i2c_dw_configure_fifo_master(struct dw_i2c_dev *dev)
> +{
> + /* Configure Tx/Rx FIFO threshold levels */
> + dw_writel(dev, dev->tx_fifo_depth / 2, DW_IC_TX_TL);
> + dw_writel(dev, 0, DW_IC_RX_TL);
> +
> + /* configure the i2c master */
> + dw_writel(dev, dev->master_cfg, DW_IC_CON);
> + dw_writel(dev, DW_IC_INTR_MASTER_MASK, DW_IC_INTR_MASK);
So, in the original code there were 3 writes, now 4. Please, put an
explanation into commit message.
> +}
> @@ -442,12 +453,9 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
> "Hardware too old to adjust SDA hold
> time.\n");
> }
>
> - /* Configure Tx/Rx FIFO threshold levels */
> - dw_writel(dev, dev->tx_fifo_depth / 2, DW_IC_TX_TL);
> - dw_writel(dev, 0, DW_IC_RX_TL);
> -
> - /* configure the i2c master */
> - dw_writel(dev, dev->master_cfg , DW_IC_CON);
> + if ((dev->master_cfg & DW_IC_CON_MASTER) &&
> + (dev->master_cfg & DW_IC_CON_SLAVE_DISABLE))
Indentation!
> + i2c_dw_configure_fifo_master(dev);
> -static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
> +static bool i2c_dw_irq_handler_master(struct dw_i2c_dev *dev)
Perhaps int?
> {
> - struct dw_i2c_dev *dev = dev_id;
> - u32 stat, enabled;
> -
> - enabled = dw_readl(dev, DW_IC_ENABLE);
> - stat = dw_readl(dev, DW_IC_RAW_INTR_STAT);
> - dev_dbg(dev->dev, "%s: enabled=%#x stat=%#x\n", __func__,
> enabled, stat);
> - if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY))
> - return IRQ_NONE;
> + u32 stat;
>
> stat = i2c_dw_read_clear_intrbits(dev);
>
> @@ -906,7 +907,26 @@ static irqreturn_t i2c_dw_isr(int this_irq, void
> *dev_id)
> i2c_dw_disable_int(dev);
> dw_writel(dev, stat, DW_IC_INTR_MASK);
> }
> + return true;
Ditto.
And basically I don't see how this would be not true? Are you planning
to add something here later in the series? Please, elaborate in the
commit message.
> +}
> +
> +static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
> +{
> + struct dw_i2c_dev *dev = dev_id;
> + u32 stat, enabled, mode;
> +
> + enabled = dw_readl(dev, DW_IC_ENABLE);
> + mode = dw_readl(dev, DW_IC_CON);
> + stat = dw_readl(dev, DW_IC_RAW_INTR_STAT);
> +
> + dev_dbg(dev->dev, "%s: enabled=%#x stat=%#x\n", __func__,
> enabled, stat);
For sake of easier review, can we keep same lines same and in the same
order?
struct dw_i2c_dev *dev = dev_id;
u32 stat, enabled;
enabled = dw_readl(dev, DW_IC_ENABLE);
stat = dw_readl(dev, DW_IC_RAW_INTR_STAT);
dev_dbg(dev->dev, "%s: enabled=%#x stat=%#x\n", __func__,
enabled, stat);
if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY))
return IRQ_NONE;
Btw, I do not see how mode is used? Do you have a warning?
Please, fix.
> + if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY))
> + return IRQ_NONE;
> +static void i2c_dw_configure_master(struct platform_device *pdev)
> +{
> + struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
> +
> + dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE
> |
> + DW_IC_CON_RESTART_EN;
> +
> + dev->functionality |= I2C_FUNC_10BIT_ADDR;
Where this came from?
> + dev_info(&pdev->dev, "I am registed as a I2C Master!\n");
> +
> + switch (dev->clk_freq) {
> + case 100000:
> + dev->master_cfg |= DW_IC_CON_SPEED_STD;
> + break;
> + case 3400000:
> + dev->master_cfg |= DW_IC_CON_SPEED_HIGH;
> + break;
> + default:
> + dev->master_cfg |= DW_IC_CON_SPEED_FAST;
> + }
> +}
> +
> static int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool
> prepare)
> {
> if (IS_ERR(i_dev->clk))
> @@ -222,19 +244,7 @@ static int dw_i2c_plat_probe(struct
> platform_device *pdev)
> I2C_FUNC_SMBUS_WORD_DATA |
> I2C_FUNC_SMBUS_I2C_BLOCK;
>
> - dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE
> |
> - DW_IC_CON_RESTART_EN;
> -
> - switch (dev->clk_freq) {
> - case 100000:
> - dev->master_cfg |= DW_IC_CON_SPEED_STD;
> - break;
> - case 3400000:
> - dev->master_cfg |= DW_IC_CON_SPEED_HIGH;
> - break;
> - default:
> - dev->master_cfg |= DW_IC_CON_SPEED_FAST;
> - }
> + i2c_dw_configure_master(pdev);
>
> dev->clk = devm_clk_get(&pdev->dev, NULL);
> if (!i2c_dw_plat_prepare_clk(dev, true)) {
--
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 1/5] i2c: designware: Refactoring of the i2c-designware core and platform module
@ 2016-11-18 12:26 ` Andy Shevchenko
0 siblings, 0 replies; 19+ messages in thread
From: Andy Shevchenko @ 2016-11-18 12:26 UTC (permalink / raw)
To: Luis Oliveira, wsa-z923LK4zBo2bacvFa/9K2g,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
jarkko.nikula-VuQAYsv1563Yd54FQh9/CA,
mika.westerberg-VuQAYsv1563Yd54FQh9/CA,
linux-i2c-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: Ramiro.Oliveira-HKixBCOQz3hWk0Htik3J/w,
Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
CARLOS.PALMINHA-HKixBCOQz3hWk0Htik3J/w
On Fri, 2016-11-18 at 11:19 +0000, Luis Oliveira wrote:
> - Factor out _master() parts of code to separate functions.
> - Standardize all code relatated to I2C master.
>
> Signed-off-by: Luis Oliveira <lolivei-HKixBCOQz3hWk0Htik3J/w@public.gmane.org>
Can you shrink Cc list to people who indeed are involved / concerned?
> ---
> Changes V2->V3: (Andy Shevchenko)
> - indentation and style fix
> - nothing else was changed in this patch from v2
Hmm...
May I add few more comments?
> @@ -87,13 +87,13 @@
> #define DW_IC_INTR_GEN_CALL 0x800
>
> #define DW_IC_INTR_DEFAULT_MASK (DW_IC_INTR_RX_FULL |
> \
> - DW_IC_INTR_TX_EMPTY | \
> DW_IC_INTR_TX_ABRT | \
> DW_IC_INTR_STOP_DET)
> -
Do you need to remove it?
I would leave it...
> +#define DW_IC_INTR_MASTER_MASK (DW_IC_INTR_DEFAULT_MAS
> K | \
> + DW_IC_INTR_TX_EMPTY)
...here.
> #define DW_IC_STATUS_ACTIVITY 0x1
> #define DW_IC_STATUS_TFE BIT(2)
> -#define DW_IC_STATUS_MST_ACTIVITY BIT(5)
> +#define DW_IC_STATUS_MASTER_ACTIVITY BIT(5)
> +static void i2c_dw_configure_fifo_master(struct dw_i2c_dev *dev)
> +{
> + /* Configure Tx/Rx FIFO threshold levels */
> + dw_writel(dev, dev->tx_fifo_depth / 2, DW_IC_TX_TL);
> + dw_writel(dev, 0, DW_IC_RX_TL);
> +
> + /* configure the i2c master */
> + dw_writel(dev, dev->master_cfg, DW_IC_CON);
> + dw_writel(dev, DW_IC_INTR_MASTER_MASK, DW_IC_INTR_MASK);
So, in the original code there were 3 writes, now 4. Please, put an
explanation into commit message.
> +}
> @@ -442,12 +453,9 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
> "Hardware too old to adjust SDA hold
> time.\n");
> }
>
> - /* Configure Tx/Rx FIFO threshold levels */
> - dw_writel(dev, dev->tx_fifo_depth / 2, DW_IC_TX_TL);
> - dw_writel(dev, 0, DW_IC_RX_TL);
> -
> - /* configure the i2c master */
> - dw_writel(dev, dev->master_cfg , DW_IC_CON);
> + if ((dev->master_cfg & DW_IC_CON_MASTER) &&
> + (dev->master_cfg & DW_IC_CON_SLAVE_DISABLE))
Indentation!
> + i2c_dw_configure_fifo_master(dev);
> -static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
> +static bool i2c_dw_irq_handler_master(struct dw_i2c_dev *dev)
Perhaps int?
> {
> - struct dw_i2c_dev *dev = dev_id;
> - u32 stat, enabled;
> -
> - enabled = dw_readl(dev, DW_IC_ENABLE);
> - stat = dw_readl(dev, DW_IC_RAW_INTR_STAT);
> - dev_dbg(dev->dev, "%s: enabled=%#x stat=%#x\n", __func__,
> enabled, stat);
> - if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY))
> - return IRQ_NONE;
> + u32 stat;
>
> stat = i2c_dw_read_clear_intrbits(dev);
>
> @@ -906,7 +907,26 @@ static irqreturn_t i2c_dw_isr(int this_irq, void
> *dev_id)
> i2c_dw_disable_int(dev);
> dw_writel(dev, stat, DW_IC_INTR_MASK);
> }
> + return true;
Ditto.
And basically I don't see how this would be not true? Are you planning
to add something here later in the series? Please, elaborate in the
commit message.
> +}
> +
> +static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
> +{
> + struct dw_i2c_dev *dev = dev_id;
> + u32 stat, enabled, mode;
> +
> + enabled = dw_readl(dev, DW_IC_ENABLE);
> + mode = dw_readl(dev, DW_IC_CON);
> + stat = dw_readl(dev, DW_IC_RAW_INTR_STAT);
> +
> + dev_dbg(dev->dev, "%s: enabled=%#x stat=%#x\n", __func__,
> enabled, stat);
For sake of easier review, can we keep same lines same and in the same
order?
struct dw_i2c_dev *dev = dev_id;
u32 stat, enabled;
enabled = dw_readl(dev, DW_IC_ENABLE);
stat = dw_readl(dev, DW_IC_RAW_INTR_STAT);
dev_dbg(dev->dev, "%s: enabled=%#x stat=%#x\n", __func__,
enabled, stat);
if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY))
return IRQ_NONE;
Btw, I do not see how mode is used? Do you have a warning?
Please, fix.
> + if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY))
> + return IRQ_NONE;
> +static void i2c_dw_configure_master(struct platform_device *pdev)
> +{
> + struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
> +
> + dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE
> |
> + DW_IC_CON_RESTART_EN;
> +
> + dev->functionality |= I2C_FUNC_10BIT_ADDR;
Where this came from?
> + dev_info(&pdev->dev, "I am registed as a I2C Master!\n");
> +
> + switch (dev->clk_freq) {
> + case 100000:
> + dev->master_cfg |= DW_IC_CON_SPEED_STD;
> + break;
> + case 3400000:
> + dev->master_cfg |= DW_IC_CON_SPEED_HIGH;
> + break;
> + default:
> + dev->master_cfg |= DW_IC_CON_SPEED_FAST;
> + }
> +}
> +
> static int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool
> prepare)
> {
> if (IS_ERR(i_dev->clk))
> @@ -222,19 +244,7 @@ static int dw_i2c_plat_probe(struct
> platform_device *pdev)
> I2C_FUNC_SMBUS_WORD_DATA |
> I2C_FUNC_SMBUS_I2C_BLOCK;
>
> - dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE
> |
> - DW_IC_CON_RESTART_EN;
> -
> - switch (dev->clk_freq) {
> - case 100000:
> - dev->master_cfg |= DW_IC_CON_SPEED_STD;
> - break;
> - case 3400000:
> - dev->master_cfg |= DW_IC_CON_SPEED_HIGH;
> - break;
> - default:
> - dev->master_cfg |= DW_IC_CON_SPEED_FAST;
> - }
> + i2c_dw_configure_master(pdev);
>
> dev->clk = devm_clk_get(&pdev->dev, NULL);
> if (!i2c_dw_plat_prepare_clk(dev, true)) {
--
Andy Shevchenko <andriy.shevchenko-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
Intel Finland Oy
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 2/5] i2c: designware: Master mode as separated driver
2016-11-18 11:19 [PATCH v3 0/5] i2c: designware: Add slave support Luis Oliveira
2016-11-18 11:19 ` [PATCH v3 1/5] i2c: designware: Refactoring of the i2c-designware core and platform module Luis Oliveira
@ 2016-11-18 11:19 ` Luis Oliveira
2016-11-18 12:30 ` Andy Shevchenko
2016-11-18 11:19 ` Luis Oliveira
` (2 subsequent siblings)
4 siblings, 1 reply; 19+ messages in thread
From: Luis Oliveira @ 2016-11-18 11:19 UTC (permalink / raw)
To: wsa, robh+dt, mark.rutland, jarkko.nikula, andriy.shevchenko,
mika.westerberg, linux-i2c, devicetree, linux-kernel
Cc: Luis.Oliveira, Ramiro.Oliveira, Joao.Pinto, CARLOS.PALMINHA
- The functions related to I2C master mode of operation were transformed in a single driver.
- The name of the i2c-designware-core.c had to be changed to i2c-designware-src.c to for the cmake to be able to correctly compile both modules into one
- Common definitions were moved to i2c-designware-core.h
Signed-off-by: Luis Oliveira <lolivei@synopsys.com>
---
Changes V2->V3: (Andy Shevchenko)
- runtime PM removed
- necessary definitions moved to i2c-designware-core.h (master)
- indentation and style fix
drivers/i2c/busses/Makefile | 1 +
drivers/i2c/busses/i2c-designware-core.h | 132 +++++++-
...c-designware-core.c => i2c-designware-master.c} | 341 +--------------------
drivers/i2c/busses/i2c-designware-src.c | 252 +++++++++++++++
4 files changed, 386 insertions(+), 340 deletions(-)
rename drivers/i2c/busses/{i2c-designware-core.c => i2c-designware-master.c} (66%)
create mode 100644 drivers/i2c/busses/i2c-designware-src.c
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 29764cc..fc4e554 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o
obj-$(CONFIG_I2C_CPM) += i2c-cpm.o
obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o
obj-$(CONFIG_I2C_DESIGNWARE_CORE) += i2c-designware-core.o
+i2c-designware-core-objs := i2c-designware-src.o i2c-designware-master.o
obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o
i2c-designware-platform-objs := i2c-designware-platdrv.o
i2c-designware-platform-$(CONFIG_I2C_DESIGNWARE_BAYTRAIL) += i2c-designware-baytrail.o
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index 0d44d2a..1d45667 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -21,8 +21,6 @@
* ----------------------------------------------------------------------------
*
*/
-
-
#define DW_IC_CON_MASTER 0x1
#define DW_IC_CON_SPEED_STD 0x2
#define DW_IC_CON_SPEED_FAST 0x4
@@ -32,6 +30,123 @@
#define DW_IC_CON_RESTART_EN 0x20
#define DW_IC_CON_SLAVE_DISABLE 0x40
+/*
+ * Registers offset
+ */
+#define DW_IC_CON 0x0
+#define DW_IC_TAR 0x4
+#define DW_IC_DATA_CMD 0x10
+#define DW_IC_SS_SCL_HCNT 0x14
+#define DW_IC_SS_SCL_LCNT 0x18
+#define DW_IC_FS_SCL_HCNT 0x1c
+#define DW_IC_FS_SCL_LCNT 0x20
+#define DW_IC_HS_SCL_HCNT 0x24
+#define DW_IC_HS_SCL_LCNT 0x28
+#define DW_IC_INTR_STAT 0x2c
+#define DW_IC_INTR_MASK 0x30
+#define DW_IC_RAW_INTR_STAT 0x34
+#define DW_IC_RX_TL 0x38
+#define DW_IC_TX_TL 0x3c
+#define DW_IC_CLR_INTR 0x40
+#define DW_IC_CLR_RX_UNDER 0x44
+#define DW_IC_CLR_RX_OVER 0x48
+#define DW_IC_CLR_TX_OVER 0x4c
+#define DW_IC_CLR_RD_REQ 0x50
+#define DW_IC_CLR_TX_ABRT 0x54
+#define DW_IC_CLR_RX_DONE 0x58
+#define DW_IC_CLR_ACTIVITY 0x5c
+#define DW_IC_CLR_STOP_DET 0x60
+#define DW_IC_CLR_START_DET 0x64
+#define DW_IC_CLR_GEN_CALL 0x68
+#define DW_IC_ENABLE 0x6c
+#define DW_IC_STATUS 0x70
+#define DW_IC_TXFLR 0x74
+#define DW_IC_RXFLR 0x78
+#define DW_IC_SDA_HOLD 0x7c
+#define DW_IC_TX_ABRT_SOURCE 0x80
+#define DW_IC_ENABLE_STATUS 0x9c
+#define DW_IC_COMP_PARAM_1 0xf4
+#define DW_IC_COMP_VERSION 0xf8
+#define DW_IC_SDA_HOLD_MIN_VERS 0x3131312A
+#define DW_IC_COMP_TYPE 0xfc
+#define DW_IC_COMP_TYPE_VALUE 0x44570140
+
+#define DW_IC_INTR_RX_UNDER 0x001
+#define DW_IC_INTR_RX_OVER 0x002
+#define DW_IC_INTR_RX_FULL 0x004
+#define DW_IC_INTR_TX_OVER 0x008
+#define DW_IC_INTR_TX_EMPTY 0x010
+#define DW_IC_INTR_RD_REQ 0x020
+#define DW_IC_INTR_TX_ABRT 0x040
+#define DW_IC_INTR_RX_DONE 0x080
+#define DW_IC_INTR_ACTIVITY 0x100
+#define DW_IC_INTR_STOP_DET 0x200
+#define DW_IC_INTR_START_DET 0x400
+#define DW_IC_INTR_GEN_CALL 0x800
+
+#define DW_IC_INTR_DEFAULT_MASK (DW_IC_INTR_RX_FULL | \
+ DW_IC_INTR_TX_ABRT | \
+ DW_IC_INTR_STOP_DET)
+#define DW_IC_INTR_MASTER_MASK (DW_IC_INTR_DEFAULT_MASK | \
+ DW_IC_INTR_TX_EMPTY)
+#define DW_IC_STATUS_ACTIVITY 0x1
+#define DW_IC_STATUS_TFE BIT(2)
+#define DW_IC_STATUS_MASTER_ACTIVITY BIT(5)
+
+#define DW_IC_SDA_HOLD_RX_SHIFT 16
+#define DW_IC_SDA_HOLD_RX_MASK GENMASK(23, DW_IC_SDA_HOLD_RX_SHIFT)
+
+#define DW_IC_ERR_TX_ABRT 0x1
+
+#define DW_IC_TAR_10BITADDR_MASTER BIT(12)
+
+#define DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH (BIT(2) | BIT(3))
+#define DW_IC_COMP_PARAM_1_SPEED_MODE_MASK GENMASK(3, 2)
+
+/*
+ * status codes
+ */
+#define STATUS_IDLE 0x0
+#define STATUS_WRITE_IN_PROGRESS 0x1
+#define STATUS_READ_IN_PROGRESS 0x2
+
+#define TIMEOUT 20 /* ms */
+
+/*
+ * hardware abort codes from the DW_IC_TX_ABRT_SOURCE register
+ *
+ * only expected abort codes are listed here
+ * refer to the datasheet for the full list
+ */
+#define ABRT_7B_ADDR_NOACK 0
+#define ABRT_10ADDR1_NOACK 1
+#define ABRT_10ADDR2_NOACK 2
+#define ABRT_TXDATA_NOACK 3
+#define ABRT_GCALL_NOACK 4
+#define ABRT_GCALL_READ 5
+#define ABRT_SBYTE_ACKDET 7
+#define ABRT_SBYTE_NORSTRT 9
+#define ABRT_10B_RD_NORSTRT 10
+#define ABRT_MASTER_DIS 11
+#define ARB_LOST 12
+
+#define DW_IC_TX_ABRT_7B_ADDR_NOACK (1UL << ABRT_7B_ADDR_NOACK)
+#define DW_IC_TX_ABRT_10ADDR1_NOACK (1UL << ABRT_10ADDR1_NOACK)
+#define DW_IC_TX_ABRT_10ADDR2_NOACK (1UL << ABRT_10ADDR2_NOACK)
+#define DW_IC_TX_ABRT_TXDATA_NOACK (1UL << ABRT_TXDATA_NOACK)
+#define DW_IC_TX_ABRT_GCALL_NOACK (1UL << ABRT_GCALL_NOACK)
+#define DW_IC_TX_ABRT_GCALL_READ (1UL << ABRT_GCALL_READ)
+#define DW_IC_TX_ABRT_SBYTE_ACKDET (1UL << ABRT_SBYTE_ACKDET)
+#define DW_IC_TX_ABRT_SBYTE_NORSTRT (1UL << ABRT_SBYTE_NORSTRT)
+#define DW_IC_TX_ABRT_10B_RD_NORSTRT (1UL << ABRT_10B_RD_NORSTRT)
+#define DW_IC_TX_ABRT_MASTER_DIS (1UL << ABRT_MASTER_DIS)
+#define DW_IC_TX_ARB_LOST (1UL << ARB_LOST)
+
+#define DW_IC_TX_ABRT_NOACK (DW_IC_TX_ABRT_7B_ADDR_NOACK | \
+ DW_IC_TX_ABRT_10ADDR1_NOACK | \
+ DW_IC_TX_ABRT_10ADDR2_NOACK | \
+ DW_IC_TX_ABRT_TXDATA_NOACK | \
+ DW_IC_TX_ABRT_GCALL_NOACK)
/**
* struct dw_i2c_dev - private i2c-designware data
@@ -124,6 +239,19 @@ struct dw_i2c_dev {
#define ACCESS_16BIT 0x00000002
#define ACCESS_INTR_MASK 0x00000004
+u32 dw_readl(struct dw_i2c_dev *dev, int offset);
+void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset);
+u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset);
+u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset);
+void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable);
+void __i2c_dw_enable_and_wait(struct dw_i2c_dev *dev, bool enable);
+unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev);
+int i2c_dw_acquire_lock(struct dw_i2c_dev *dev);
+void i2c_dw_release_lock(struct dw_i2c_dev *dev);
+int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev);
+int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev);
+u32 i2c_dw_func(struct i2c_adapter *adap);
+
extern int i2c_dw_init(struct dw_i2c_dev *dev);
extern void i2c_dw_disable(struct dw_i2c_dev *dev);
extern void i2c_dw_disable_int(struct dw_i2c_dev *dev);
diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-master.c
similarity index 66%
rename from drivers/i2c/busses/i2c-designware-core.c
rename to drivers/i2c/busses/i2c-designware-master.c
index 22f79fa..e152bce 100644
--- a/drivers/i2c/busses/i2c-designware-core.c
+++ b/drivers/i2c/busses/i2c-designware-master.c
@@ -32,304 +32,17 @@
#include <linux/module.h>
#include "i2c-designware-core.h"
-/*
- * Registers offset
- */
-#define DW_IC_CON 0x0
-#define DW_IC_TAR 0x4
-#define DW_IC_DATA_CMD 0x10
-#define DW_IC_SS_SCL_HCNT 0x14
-#define DW_IC_SS_SCL_LCNT 0x18
-#define DW_IC_FS_SCL_HCNT 0x1c
-#define DW_IC_FS_SCL_LCNT 0x20
-#define DW_IC_HS_SCL_HCNT 0x24
-#define DW_IC_HS_SCL_LCNT 0x28
-#define DW_IC_INTR_STAT 0x2c
-#define DW_IC_INTR_MASK 0x30
-#define DW_IC_RAW_INTR_STAT 0x34
-#define DW_IC_RX_TL 0x38
-#define DW_IC_TX_TL 0x3c
-#define DW_IC_CLR_INTR 0x40
-#define DW_IC_CLR_RX_UNDER 0x44
-#define DW_IC_CLR_RX_OVER 0x48
-#define DW_IC_CLR_TX_OVER 0x4c
-#define DW_IC_CLR_RD_REQ 0x50
-#define DW_IC_CLR_TX_ABRT 0x54
-#define DW_IC_CLR_RX_DONE 0x58
-#define DW_IC_CLR_ACTIVITY 0x5c
-#define DW_IC_CLR_STOP_DET 0x60
-#define DW_IC_CLR_START_DET 0x64
-#define DW_IC_CLR_GEN_CALL 0x68
-#define DW_IC_ENABLE 0x6c
-#define DW_IC_STATUS 0x70
-#define DW_IC_TXFLR 0x74
-#define DW_IC_RXFLR 0x78
-#define DW_IC_SDA_HOLD 0x7c
-#define DW_IC_TX_ABRT_SOURCE 0x80
-#define DW_IC_ENABLE_STATUS 0x9c
-#define DW_IC_COMP_PARAM_1 0xf4
-#define DW_IC_COMP_VERSION 0xf8
-#define DW_IC_SDA_HOLD_MIN_VERS 0x3131312A
-#define DW_IC_COMP_TYPE 0xfc
-#define DW_IC_COMP_TYPE_VALUE 0x44570140
-
-#define DW_IC_INTR_RX_UNDER 0x001
-#define DW_IC_INTR_RX_OVER 0x002
-#define DW_IC_INTR_RX_FULL 0x004
-#define DW_IC_INTR_TX_OVER 0x008
-#define DW_IC_INTR_TX_EMPTY 0x010
-#define DW_IC_INTR_RD_REQ 0x020
-#define DW_IC_INTR_TX_ABRT 0x040
-#define DW_IC_INTR_RX_DONE 0x080
-#define DW_IC_INTR_ACTIVITY 0x100
-#define DW_IC_INTR_STOP_DET 0x200
-#define DW_IC_INTR_START_DET 0x400
-#define DW_IC_INTR_GEN_CALL 0x800
-
-#define DW_IC_INTR_DEFAULT_MASK (DW_IC_INTR_RX_FULL | \
- DW_IC_INTR_TX_ABRT | \
- DW_IC_INTR_STOP_DET)
-#define DW_IC_INTR_MASTER_MASK (DW_IC_INTR_DEFAULT_MASK | \
- DW_IC_INTR_TX_EMPTY)
-#define DW_IC_STATUS_ACTIVITY 0x1
-#define DW_IC_STATUS_TFE BIT(2)
-#define DW_IC_STATUS_MASTER_ACTIVITY BIT(5)
-
-#define DW_IC_SDA_HOLD_RX_SHIFT 16
-#define DW_IC_SDA_HOLD_RX_MASK GENMASK(23, DW_IC_SDA_HOLD_RX_SHIFT)
-
-#define DW_IC_ERR_TX_ABRT 0x1
-
-#define DW_IC_TAR_10BITADDR_MASTER BIT(12)
-
-#define DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH (BIT(2) | BIT(3))
-#define DW_IC_COMP_PARAM_1_SPEED_MODE_MASK GENMASK(3, 2)
-
-/*
- * status codes
- */
-#define STATUS_IDLE 0x0
-#define STATUS_WRITE_IN_PROGRESS 0x1
-#define STATUS_READ_IN_PROGRESS 0x2
-
-#define TIMEOUT 20 /* ms */
-
-/*
- * hardware abort codes from the DW_IC_TX_ABRT_SOURCE register
- *
- * only expected abort codes are listed here
- * refer to the datasheet for the full list
- */
-#define ABRT_7B_ADDR_NOACK 0
-#define ABRT_10ADDR1_NOACK 1
-#define ABRT_10ADDR2_NOACK 2
-#define ABRT_TXDATA_NOACK 3
-#define ABRT_GCALL_NOACK 4
-#define ABRT_GCALL_READ 5
-#define ABRT_SBYTE_ACKDET 7
-#define ABRT_SBYTE_NORSTRT 9
-#define ABRT_10B_RD_NORSTRT 10
-#define ABRT_MASTER_DIS 11
-#define ARB_LOST 12
-
-#define DW_IC_TX_ABRT_7B_ADDR_NOACK (1UL << ABRT_7B_ADDR_NOACK)
-#define DW_IC_TX_ABRT_10ADDR1_NOACK (1UL << ABRT_10ADDR1_NOACK)
-#define DW_IC_TX_ABRT_10ADDR2_NOACK (1UL << ABRT_10ADDR2_NOACK)
-#define DW_IC_TX_ABRT_TXDATA_NOACK (1UL << ABRT_TXDATA_NOACK)
-#define DW_IC_TX_ABRT_GCALL_NOACK (1UL << ABRT_GCALL_NOACK)
-#define DW_IC_TX_ABRT_GCALL_READ (1UL << ABRT_GCALL_READ)
-#define DW_IC_TX_ABRT_SBYTE_ACKDET (1UL << ABRT_SBYTE_ACKDET)
-#define DW_IC_TX_ABRT_SBYTE_NORSTRT (1UL << ABRT_SBYTE_NORSTRT)
-#define DW_IC_TX_ABRT_10B_RD_NORSTRT (1UL << ABRT_10B_RD_NORSTRT)
-#define DW_IC_TX_ABRT_MASTER_DIS (1UL << ABRT_MASTER_DIS)
-#define DW_IC_TX_ARB_LOST (1UL << ARB_LOST)
-
-#define DW_IC_TX_ABRT_NOACK (DW_IC_TX_ABRT_7B_ADDR_NOACK | \
- DW_IC_TX_ABRT_10ADDR1_NOACK | \
- DW_IC_TX_ABRT_10ADDR2_NOACK | \
- DW_IC_TX_ABRT_TXDATA_NOACK | \
- DW_IC_TX_ABRT_GCALL_NOACK)
-
-static char *abort_sources[] = {
- [ABRT_7B_ADDR_NOACK] =
- "slave address not acknowledged (7bit mode)",
- [ABRT_10ADDR1_NOACK] =
- "first address byte not acknowledged (10bit mode)",
- [ABRT_10ADDR2_NOACK] =
- "second address byte not acknowledged (10bit mode)",
- [ABRT_TXDATA_NOACK] =
- "data not acknowledged",
- [ABRT_GCALL_NOACK] =
- "no acknowledgement for a general call",
- [ABRT_GCALL_READ] =
- "read after general call",
- [ABRT_SBYTE_ACKDET] =
- "start byte acknowledged",
- [ABRT_SBYTE_NORSTRT] =
- "trying to send start byte when restart is disabled",
- [ABRT_10B_RD_NORSTRT] =
- "trying to read when restart is disabled (10bit mode)",
- [ABRT_MASTER_DIS] =
- "trying to use disabled adapter",
- [ARB_LOST] =
- "lost arbitration",
-};
-
-static u32 dw_readl(struct dw_i2c_dev *dev, int offset)
-{
- u32 value;
-
- if (dev->accessor_flags & ACCESS_16BIT)
- value = readw_relaxed(dev->base + offset) |
- (readw_relaxed(dev->base + offset + 2) << 16);
- else
- value = readl_relaxed(dev->base + offset);
-
- if (dev->accessor_flags & ACCESS_SWAP)
- return swab32(value);
- else
- return value;
-}
-
-static void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset)
-{
- if (dev->accessor_flags & ACCESS_SWAP)
- b = swab32(b);
-
- if (dev->accessor_flags & ACCESS_16BIT) {
- writew_relaxed((u16)b, dev->base + offset);
- writew_relaxed((u16)(b >> 16), dev->base + offset + 2);
- } else {
- writel_relaxed(b, dev->base + offset);
- }
-}
-
static void i2c_dw_configure_fifo_master(struct dw_i2c_dev *dev)
{
/* Configure Tx/Rx FIFO threshold levels */
dw_writel(dev, dev->tx_fifo_depth / 2, DW_IC_TX_TL);
dw_writel(dev, 0, DW_IC_RX_TL);
- /* configure the i2c master */
+ /* configure the I2C master */
dw_writel(dev, dev->master_cfg, DW_IC_CON);
dw_writel(dev, DW_IC_INTR_MASTER_MASK, DW_IC_INTR_MASK);
}
-static u32
-i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset)
-{
- /*
- * DesignWare I2C core doesn't seem to have solid strategy to meet
- * the tHD;STA timing spec. Configuring _HCNT based on tHIGH spec
- * will result in violation of the tHD;STA spec.
- */
- if (cond)
- /*
- * Conditional expression:
- *
- * IC_[FS]S_SCL_HCNT + (1+4+3) >= IC_CLK * tHIGH
- *
- * This is based on the DW manuals, and represents an ideal
- * configuration. The resulting I2C bus speed will be
- * faster than any of the others.
- *
- * If your hardware is free from tHD;STA issue, try this one.
- */
- return (ic_clk * tSYMBOL + 500000) / 1000000 - 8 + offset;
- else
- /*
- * Conditional expression:
- *
- * IC_[FS]S_SCL_HCNT + 3 >= IC_CLK * (tHD;STA + tf)
- *
- * This is just experimental rule; the tHD;STA period turned
- * out to be proportinal to (_HCNT + 3). With this setting,
- * we could meet both tHIGH and tHD;STA timing specs.
- *
- * If unsure, you'd better to take this alternative.
- *
- * The reason why we need to take into account "tf" here,
- * is the same as described in i2c_dw_scl_lcnt().
- */
- return (ic_clk * (tSYMBOL + tf) + 500000) / 1000000
- - 3 + offset;
-}
-
-static u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)
-{
- /*
- * Conditional expression:
- *
- * IC_[FS]S_SCL_LCNT + 1 >= IC_CLK * (tLOW + tf)
- *
- * DW I2C core starts counting the SCL CNTs for the LOW period
- * of the SCL clock (tLOW) as soon as it pulls the SCL line.
- * In order to meet the tLOW timing spec, we need to take into
- * account the fall time of SCL signal (tf). Default tf value
- * should be 0.3 us, for safety.
- */
- return ((ic_clk * (tLOW + tf) + 500000) / 1000000) - 1 + offset;
-}
-
-static void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable)
-{
- dw_writel(dev, enable, DW_IC_ENABLE);
-}
-
-static void __i2c_dw_enable_and_wait(struct dw_i2c_dev *dev, bool enable)
-{
- int timeout = 100;
-
- do {
- __i2c_dw_enable(dev, enable);
- if ((dw_readl(dev, DW_IC_ENABLE_STATUS) & 1) == enable)
- return;
-
- /*
- * Wait 10 times the signaling period of the highest I2C
- * transfer supported by the driver (for 400KHz this is
- * 25us) as described in the DesignWare I2C databook.
- */
- usleep_range(25, 250);
- } while (timeout--);
-
- dev_warn(dev->dev, "timeout in %sabling adapter\n",
- enable ? "en" : "dis");
-}
-
-static unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev)
-{
- /*
- * Clock is not necessary if we got LCNT/HCNT values directly from
- * the platform code.
- */
- if (WARN_ON_ONCE(!dev->get_clk_rate_khz))
- return 0;
- return dev->get_clk_rate_khz(dev);
-}
-
-static int i2c_dw_acquire_lock(struct dw_i2c_dev *dev)
-{
- int ret;
-
- if (!dev->acquire_lock)
- return 0;
-
- ret = dev->acquire_lock(dev);
- if (!ret)
- return 0;
-
- dev_err(dev->dev, "couldn't acquire bus ownership\n");
-
- return ret;
-}
-
-static void i2c_dw_release_lock(struct dw_i2c_dev *dev)
-{
- if (dev->release_lock)
- dev->release_lock(dev);
-}
-
/**
* i2c_dw_init() - initialize the designware i2c hardware
* @dev: device private data
@@ -463,25 +176,6 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
}
EXPORT_SYMBOL_GPL(i2c_dw_init);
-/*
- * Waiting for bus not busy
- */
-static int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev)
-{
- int timeout = TIMEOUT;
-
- while (dw_readl(dev, DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY) {
- if (timeout <= 0) {
- dev_warn(dev->dev, "timeout waiting for bus ready\n");
- return -ETIMEDOUT;
- }
- timeout--;
- usleep_range(1000, 1100);
- }
-
- return 0;
-}
-
static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
{
struct i2c_msg *msgs = dev->msgs;
@@ -692,29 +386,6 @@ i2c_dw_read(struct dw_i2c_dev *dev)
}
}
-static int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev)
-{
- unsigned long abort_source = dev->abort_source;
- int i;
-
- if (abort_source & DW_IC_TX_ABRT_NOACK) {
- for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources))
- dev_dbg(dev->dev,
- "%s: %s\n", __func__, abort_sources[i]);
- return -EREMOTEIO;
- }
-
- for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources))
- dev_err(dev->dev, "%s: %s\n", __func__, abort_sources[i]);
-
- if (abort_source & DW_IC_TX_ARB_LOST)
- return -EAGAIN;
- else if (abort_source & DW_IC_TX_ABRT_GCALL_READ)
- return -EINVAL; /* wrong msgs[] data */
- else
- return -EIO;
-}
-
/*
* Prepare controller for a transaction and start transfer by calling
* i2c_dw_xfer_init()
@@ -788,12 +459,6 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
return ret;
}
-static u32 i2c_dw_func(struct i2c_adapter *adap)
-{
- struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
- return dev->functionality;
-}
-
static struct i2c_algorithm i2c_dw_algo = {
.master_xfer = i2c_dw_xfer,
.functionality = i2c_dw_func,
@@ -855,7 +520,7 @@ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
}
/*
- * Interrupt service routine. This gets called whenever an I2C interrupt
+ * Interrupt service routine. This gets called whenever an I2C master interrupt
* occurs.
*/
static bool i2c_dw_irq_handler_master(struct dw_i2c_dev *dev)
@@ -1018,5 +683,5 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)
}
EXPORT_SYMBOL_GPL(i2c_dw_probe);
-MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter core");
+MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter master");
MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-designware-src.c b/drivers/i2c/busses/i2c-designware-src.c
new file mode 100644
index 0000000..4ec0045
--- /dev/null
+++ b/drivers/i2c/busses/i2c-designware-src.c
@@ -0,0 +1,252 @@
+/*
+ * Synopsys DesignWare I2C adapter driver (master only).
+ *
+ * Based on the TI DAVINCI I2C adapter driver.
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ * Copyright (C) 2007 MontaVista Software Inc.
+ * Copyright (C) 2009 Provigent Ltd.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/export.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include "i2c-designware-core.h"
+
+static char *abort_sources[] = {
+ [ABRT_7B_ADDR_NOACK] =
+ "slave address not acknowledged (7bit mode)",
+ [ABRT_10ADDR1_NOACK] =
+ "first address byte not acknowledged (10bit mode)",
+ [ABRT_10ADDR2_NOACK] =
+ "second address byte not acknowledged (10bit mode)",
+ [ABRT_TXDATA_NOACK] =
+ "data not acknowledged",
+ [ABRT_GCALL_NOACK] =
+ "no acknowledgment for a general call",
+ [ABRT_GCALL_READ] =
+ "read after general call",
+ [ABRT_SBYTE_ACKDET] =
+ "start byte acknowledged",
+ [ABRT_SBYTE_NORSTRT] =
+ "trying to send start byte when restart is disabled",
+ [ABRT_10B_RD_NORSTRT] =
+ "trying to read when restart is disabled (10bit mode)",
+ [ABRT_MASTER_DIS] =
+ "trying to use disabled adapter",
+ [ARB_LOST] =
+ "lost arbitration",
+};
+
+u32 dw_readl(struct dw_i2c_dev *dev, int offset)
+{
+ u32 value;
+
+ if (dev->accessor_flags & ACCESS_16BIT)
+ value = readw_relaxed(dev->base + offset) |
+ (readw_relaxed(dev->base + offset + 2) << 16);
+ else
+ value = readl_relaxed(dev->base + offset);
+
+ if (dev->accessor_flags & ACCESS_SWAP)
+ return swab32(value);
+ else
+ return value;
+}
+
+void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset)
+{
+ if (dev->accessor_flags & ACCESS_SWAP)
+ b = swab32(b);
+
+ if (dev->accessor_flags & ACCESS_16BIT) {
+ writew_relaxed((u16)b, dev->base + offset);
+ writew_relaxed((u16)(b >> 16), dev->base + offset + 2);
+ } else {
+ writel_relaxed(b, dev->base + offset);
+ }
+}
+
+u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset)
+{
+ /*
+ * DesignWare I2C core doesn't seem to have solid strategy to meet
+ * the tHD;STA timing spec. Configuring _HCNT based on tHIGH spec
+ * will result in violation of the tHD;STA spec.
+ */
+ if (cond)
+ /*
+ * Conditional expression:
+ *
+ * IC_[FS]S_SCL_HCNT + (1+4+3) >= IC_CLK * tHIGH
+ *
+ * This is based on the DW manuals, and represents an ideal
+ * configuration. The resulting I2C bus speed will be
+ * faster than any of the others.
+ *
+ * If your hardware is free from tHD;STA issue, try this one.
+ */
+ return (ic_clk * tSYMBOL + 500000) / 1000000 - 8 + offset;
+ else
+ /*
+ * Conditional expression:
+ *
+ * IC_[FS]S_SCL_HCNT + 3 >= IC_CLK * (tHD;STA + tf)
+ *
+ * This is just experimental rule; the tHD;STA period turned
+ * out to be proportinal to (_HCNT + 3). With this setting,
+ * we could meet both tHIGH and tHD;STA timing specs.
+ *
+ * If unsure, you'd better to take this alternative.
+ *
+ * The reason why we need to take into account "tf" here,
+ * is the same as described in i2c_dw_scl_lcnt().
+ */
+ return (ic_clk * (tSYMBOL + tf) + 500000) / 1000000
+ - 3 + offset;
+}
+
+u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)
+{
+ /*
+ * Conditional expression:
+ *
+ * IC_[FS]S_SCL_LCNT + 1 >= IC_CLK * (tLOW + tf)
+ *
+ * DW I2C core starts counting the SCL CNTs for the LOW period
+ * of the SCL clock (tLOW) as soon as it pulls the SCL line.
+ * In order to meet the tLOW timing spec, we need to take into
+ * account the fall time of SCL signal (tf). Default tf value
+ * should be 0.3 us, for safety.
+ */
+ return ((ic_clk * (tLOW + tf) + 500000) / 1000000) - 1 + offset;
+}
+
+void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable)
+{
+ dw_writel(dev, enable, DW_IC_ENABLE);
+}
+
+void __i2c_dw_enable_and_wait(struct dw_i2c_dev *dev, bool enable)
+{
+ int timeout = 100;
+
+ do {
+ __i2c_dw_enable(dev, enable);
+ if ((dw_readl(dev, DW_IC_ENABLE_STATUS) & 1) == enable)
+ return;
+
+ /*
+ * Wait 10 times the signaling period of the highest I2C
+ * transfer supported by the driver (for 400KHz this is
+ * 25us) as described in the DesignWare I2C databook.
+ */
+ usleep_range(25, 250);
+ } while (timeout--);
+
+ dev_warn(dev->dev, "timeout in %sabling adapter\n",
+ enable ? "en" : "dis");
+}
+
+unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev)
+{
+ /*
+ * Clock is not necessary if we got LCNT/HCNT values directly from
+ * the platform code.
+ */
+ if (WARN_ON_ONCE(!dev->get_clk_rate_khz))
+ return 0;
+ return dev->get_clk_rate_khz(dev);
+}
+
+int i2c_dw_acquire_lock(struct dw_i2c_dev *dev)
+{
+ int ret;
+
+ if (!dev->acquire_lock)
+ return 0;
+
+ ret = dev->acquire_lock(dev);
+ if (!ret)
+ return 0;
+
+ dev_err(dev->dev, "couldn't acquire bus ownership\n");
+
+ return ret;
+}
+
+void i2c_dw_release_lock(struct dw_i2c_dev *dev)
+{
+ if (dev->release_lock)
+ dev->release_lock(dev);
+}
+
+/*
+ * Waiting for bus not busy
+ */
+int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev)
+{
+ int timeout = TIMEOUT;
+
+ while (dw_readl(dev, DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY) {
+ if (timeout <= 0) {
+ dev_warn(dev->dev, "timeout waiting for bus ready\n");
+ return -ETIMEDOUT;
+ }
+ timeout--;
+ usleep_range(1000, 1100);
+ }
+
+ return 0;
+}
+
+int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev)
+{
+ unsigned long abort_source = dev->abort_source;
+ int i;
+
+ if (abort_source & DW_IC_TX_ABRT_NOACK) {
+ for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources))
+ dev_dbg(dev->dev,
+ "%s: %s\n", __func__, abort_sources[i]);
+ return -EREMOTEIO;
+ }
+
+ for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources))
+ dev_err(dev->dev, "%s: %s\n", __func__, abort_sources[i]);
+
+ if (abort_source & DW_IC_TX_ARB_LOST)
+ return -EAGAIN;
+ else if (abort_source & DW_IC_TX_ABRT_GCALL_READ)
+ return -EINVAL; /* wrong msgs[] data */
+ else
+ return -EIO;
+}
+
+u32 i2c_dw_func(struct i2c_adapter *adap)
+{
+ struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
+ return dev->functionality;
+}
+
+MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter core");
+MODULE_LICENSE("GPL");
--
2.10.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH v3 2/5] i2c: designware: Master mode as separated driver
2016-11-18 11:19 ` [PATCH v3 2/5] i2c: designware: Master mode as separated driver Luis Oliveira
@ 2016-11-18 12:30 ` Andy Shevchenko
0 siblings, 0 replies; 19+ messages in thread
From: Andy Shevchenko @ 2016-11-18 12:30 UTC (permalink / raw)
To: Luis Oliveira, wsa, robh+dt, mark.rutland, jarkko.nikula,
mika.westerberg, linux-i2c, devicetree, linux-kernel
Cc: Ramiro.Oliveira, Joao.Pinto, CARLOS.PALMINHA
On Fri, 2016-11-18 at 11:19 +0000, Luis Oliveira wrote:
> - The functions related to I2C master mode of operation were
> transformed in a single driver.
> - The name of the i2c-designware-core.c had to be changed to i2c-
> designware-src.c to for the cmake to be able to correctly compile both
> modules into one
> - Common definitions were moved to i2c-designware-core.h
> drivers/i2c/busses/i2c-designware-src.c | 252
> +++++++++++++++
Perhaps i2c-designware-common.c ?
> @@ -21,8 +21,6 @@
> * ------------------------------------------------------------------
> ----------
> *
> */
> -
> -
No need to do that in this patch.
> #define DW_IC_CON_MASTER 0x1
> #define DW_IC_CON_SPEED_STD 0x2
> #define DW_IC_CON_SPEED_FAST 0x4
> @@ -32,6 +30,123 @@
> #define DW_IC_CON_RESTART_EN 0x20
> #define DW_IC_CON_SLAVE_DISABLE 0x40
>
> +/*
> + * Registers offset
> + */
> +#define DW_IC_CON 0x0
Okay, can we split this to move definitions and the rest?
--
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 3/5] i2c: designware: Add slave definitions
@ 2016-11-18 11:19 ` Luis Oliveira
0 siblings, 0 replies; 19+ messages in thread
From: Luis Oliveira @ 2016-11-18 11:19 UTC (permalink / raw)
To: wsa, robh+dt, mark.rutland, jarkko.nikula, andriy.shevchenko,
mika.westerberg, linux-i2c, devicetree, linux-kernel
Cc: Luis.Oliveira, Ramiro.Oliveira, Joao.Pinto, CARLOS.PALMINHA
- Add slave defintitions to i2c-designware-core
- Changes in Kconfig to auto-enable I2C_SLAVE when compiling the modules
- Add compatible string to designware-core.txt explaining the devicetree bindings
Signed-off-by: Luis Oliveira <lolivei@synopsys.com>
---
Changes V2->V3: (Andy Shevchenko)
- necessary definitions added to i2c-designware-core.h (slave)
- code will be added in the next patch as suggested
- compatible string for slave enabling as suggested
.../devicetree/bindings/i2c/i2c-designware.txt | 4 +++-
drivers/i2c/busses/Kconfig | 1 +
drivers/i2c/busses/i2c-designware-core.h | 24 ++++++++++++++++++++++
drivers/i2c/busses/i2c-designware-src.c | 6 ++++++
4 files changed, 34 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/i2c/i2c-designware.txt b/Documentation/devicetree/bindings/i2c/i2c-designware.txt
index fee26dc..7705434 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-designware.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-designware.txt
@@ -2,7 +2,9 @@
Required properties :
- - compatible : should be "snps,designware-i2c"
+ - compatible : should be:
+ - "snps,designware-i2c" to setup the hardware block as I2C master.
+ - "snps,designware-i2c-slave" to setup the hardware block as I2C slave.
- reg : Offset and length of the register set for the device
- interrupts : <IRQ> where IRQ is the interrupt number.
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index d252276..0de8e30 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -470,6 +470,7 @@ config I2C_DESIGNWARE_CORE
config I2C_DESIGNWARE_PLATFORM
tristate "Synopsys DesignWare Platform"
select I2C_DESIGNWARE_CORE
+ select I2C_SLAVE
depends on (ACPI && COMMON_CLK) || !ACPI
help
If you say yes to this option, support will be included for the
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index 1d45667..8c33324 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -26,15 +26,20 @@
#define DW_IC_CON_SPEED_FAST 0x4
#define DW_IC_CON_SPEED_HIGH 0x6
#define DW_IC_CON_SPEED_MASK 0x6
+#define DW_IC_CON_10BITADDR_SLAVE 0x8
#define DW_IC_CON_10BITADDR_MASTER 0x10
#define DW_IC_CON_RESTART_EN 0x20
#define DW_IC_CON_SLAVE_DISABLE 0x40
+#define DW_IC_CON_STOP_DET_IFADDRESSED 0x80
+#define DW_IC_CON_TX_EMPTY_CTRL 0x100
+#define DW_IC_CON_RX_FIFO_FULL_HLD_CTRL 0x200
/*
* Registers offset
*/
#define DW_IC_CON 0x0
#define DW_IC_TAR 0x4
+#define DW_IC_SAR 0x8
#define DW_IC_DATA_CMD 0x10
#define DW_IC_SS_SCL_HCNT 0x14
#define DW_IC_SS_SCL_LCNT 0x18
@@ -89,9 +94,15 @@
DW_IC_INTR_STOP_DET)
#define DW_IC_INTR_MASTER_MASK (DW_IC_INTR_DEFAULT_MASK | \
DW_IC_INTR_TX_EMPTY)
+#define DW_IC_INTR_SLAVE_MASK (DW_IC_INTR_DEFAULT_MASK | \
+ DW_IC_INTR_RX_DONE | \
+ DW_IC_INTR_RX_UNDER | \
+ DW_IC_INTR_RD_REQ)
+
#define DW_IC_STATUS_ACTIVITY 0x1
#define DW_IC_STATUS_TFE BIT(2)
#define DW_IC_STATUS_MASTER_ACTIVITY BIT(5)
+#define DW_IC_STATUS_SLAVE_ACTIVITY BIT(6)
#define DW_IC_SDA_HOLD_RX_SHIFT 16
#define DW_IC_SDA_HOLD_RX_MASK GENMASK(23, DW_IC_SDA_HOLD_RX_SHIFT)
@@ -129,6 +140,9 @@
#define ABRT_10B_RD_NORSTRT 10
#define ABRT_MASTER_DIS 11
#define ARB_LOST 12
+#define ABRT_SLAVE_FLUSH_TXFIFO 13
+#define ABRT_SLAVE_ARBLOST 14
+#define ABRT_SLAVE_RD_INTX 15
#define DW_IC_TX_ABRT_7B_ADDR_NOACK (1UL << ABRT_7B_ADDR_NOACK)
#define DW_IC_TX_ABRT_10ADDR1_NOACK (1UL << ABRT_10ADDR1_NOACK)
@@ -141,6 +155,9 @@
#define DW_IC_TX_ABRT_10B_RD_NORSTRT (1UL << ABRT_10B_RD_NORSTRT)
#define DW_IC_TX_ABRT_MASTER_DIS (1UL << ABRT_MASTER_DIS)
#define DW_IC_TX_ARB_LOST (1UL << ARB_LOST)
+#define DW_IC_RX_ABRT_SLAVE_RD_INTX (1UL << ABRT_SLAVE_RD_INTX)
+#define DW_IC_RX_ABRT_SLAVE_ARBLOST (1UL << ABRT_SLAVE_ARBLOST)
+#define DW_IC_RX_ABRT_SLAVE_FLUSH_TXFIFO (1UL << ABRT_SLAVE_FLUSH_TXFIFO)
#define DW_IC_TX_ABRT_NOACK (DW_IC_TX_ABRT_7B_ADDR_NOACK | \
DW_IC_TX_ABRT_10ADDR1_NOACK | \
@@ -195,6 +212,7 @@ struct dw_i2c_dev {
void __iomem *base;
struct completion cmd_complete;
struct clk *clk;
+ struct i2c_client *slave;
u32 (*get_clk_rate_khz) (struct dw_i2c_dev *dev);
struct dw_pci_controller *controller;
int cmd_err;
@@ -214,6 +232,7 @@ struct dw_i2c_dev {
struct i2c_adapter adapter;
u32 functionality;
u32 master_cfg;
+ u32 slave_cfg;
unsigned int tx_fifo_depth;
unsigned int rx_fifo_depth;
int rx_outstanding;
@@ -257,6 +276,11 @@ extern void i2c_dw_disable(struct dw_i2c_dev *dev);
extern void i2c_dw_disable_int(struct dw_i2c_dev *dev);
extern u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev);
extern int i2c_dw_probe(struct dw_i2c_dev *dev);
+extern int i2c_dw_init_slave(struct dw_i2c_dev *dev);
+extern void i2c_dw_disable_slave(struct dw_i2c_dev *dev);
+extern void i2c_dw_disable_int_slave(struct dw_i2c_dev *dev);
+extern u32 i2c_dw_read_comp_param_slave(struct dw_i2c_dev *dev);
+extern int i2c_dw_probe_slave(struct dw_i2c_dev *dev);
#if IS_ENABLED(CONFIG_I2C_DESIGNWARE_BAYTRAIL)
extern int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev);
diff --git a/drivers/i2c/busses/i2c-designware-src.c b/drivers/i2c/busses/i2c-designware-src.c
index 4ec0045..838ef66 100644
--- a/drivers/i2c/busses/i2c-designware-src.c
+++ b/drivers/i2c/busses/i2c-designware-src.c
@@ -55,6 +55,12 @@ static char *abort_sources[] = {
"trying to use disabled adapter",
[ARB_LOST] =
"lost arbitration",
+ [ABRT_SLAVE_FLUSH_TXFIFO] =
+ "read command so flush old data in the TX FIFO",
+ [ABRT_SLAVE_ARBLOST] =
+ "slave lost the bus while transmitting data to a remote master",
+ [ABRT_SLAVE_RD_INTX] =
+ "slave request for data to be transmitted and",
};
u32 dw_readl(struct dw_i2c_dev *dev, int offset)
--
2.10.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v3 3/5] i2c: designware: Add slave definitions
@ 2016-11-18 11:19 ` Luis Oliveira
0 siblings, 0 replies; 19+ messages in thread
From: Luis Oliveira @ 2016-11-18 11:19 UTC (permalink / raw)
To: wsa-z923LK4zBo2bacvFa/9K2g, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
mark.rutland-5wv7dgnIgG8, jarkko.nikula-VuQAYsv1563Yd54FQh9/CA,
andriy.shevchenko-VuQAYsv1563Yd54FQh9/CA,
mika.westerberg-VuQAYsv1563Yd54FQh9/CA,
linux-i2c-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: Luis.Oliveira-HKixBCOQz3hWk0Htik3J/w,
Ramiro.Oliveira-HKixBCOQz3hWk0Htik3J/w,
Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
CARLOS.PALMINHA-HKixBCOQz3hWk0Htik3J/w
- Add slave defintitions to i2c-designware-core
- Changes in Kconfig to auto-enable I2C_SLAVE when compiling the modules
- Add compatible string to designware-core.txt explaining the devicetree bindings
Signed-off-by: Luis Oliveira <lolivei-HKixBCOQz3hWk0Htik3J/w@public.gmane.org>
---
Changes V2->V3: (Andy Shevchenko)
- necessary definitions added to i2c-designware-core.h (slave)
- code will be added in the next patch as suggested
- compatible string for slave enabling as suggested
.../devicetree/bindings/i2c/i2c-designware.txt | 4 +++-
drivers/i2c/busses/Kconfig | 1 +
drivers/i2c/busses/i2c-designware-core.h | 24 ++++++++++++++++++++++
drivers/i2c/busses/i2c-designware-src.c | 6 ++++++
4 files changed, 34 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/i2c/i2c-designware.txt b/Documentation/devicetree/bindings/i2c/i2c-designware.txt
index fee26dc..7705434 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-designware.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-designware.txt
@@ -2,7 +2,9 @@
Required properties :
- - compatible : should be "snps,designware-i2c"
+ - compatible : should be:
+ - "snps,designware-i2c" to setup the hardware block as I2C master.
+ - "snps,designware-i2c-slave" to setup the hardware block as I2C slave.
- reg : Offset and length of the register set for the device
- interrupts : <IRQ> where IRQ is the interrupt number.
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index d252276..0de8e30 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -470,6 +470,7 @@ config I2C_DESIGNWARE_CORE
config I2C_DESIGNWARE_PLATFORM
tristate "Synopsys DesignWare Platform"
select I2C_DESIGNWARE_CORE
+ select I2C_SLAVE
depends on (ACPI && COMMON_CLK) || !ACPI
help
If you say yes to this option, support will be included for the
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index 1d45667..8c33324 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -26,15 +26,20 @@
#define DW_IC_CON_SPEED_FAST 0x4
#define DW_IC_CON_SPEED_HIGH 0x6
#define DW_IC_CON_SPEED_MASK 0x6
+#define DW_IC_CON_10BITADDR_SLAVE 0x8
#define DW_IC_CON_10BITADDR_MASTER 0x10
#define DW_IC_CON_RESTART_EN 0x20
#define DW_IC_CON_SLAVE_DISABLE 0x40
+#define DW_IC_CON_STOP_DET_IFADDRESSED 0x80
+#define DW_IC_CON_TX_EMPTY_CTRL 0x100
+#define DW_IC_CON_RX_FIFO_FULL_HLD_CTRL 0x200
/*
* Registers offset
*/
#define DW_IC_CON 0x0
#define DW_IC_TAR 0x4
+#define DW_IC_SAR 0x8
#define DW_IC_DATA_CMD 0x10
#define DW_IC_SS_SCL_HCNT 0x14
#define DW_IC_SS_SCL_LCNT 0x18
@@ -89,9 +94,15 @@
DW_IC_INTR_STOP_DET)
#define DW_IC_INTR_MASTER_MASK (DW_IC_INTR_DEFAULT_MASK | \
DW_IC_INTR_TX_EMPTY)
+#define DW_IC_INTR_SLAVE_MASK (DW_IC_INTR_DEFAULT_MASK | \
+ DW_IC_INTR_RX_DONE | \
+ DW_IC_INTR_RX_UNDER | \
+ DW_IC_INTR_RD_REQ)
+
#define DW_IC_STATUS_ACTIVITY 0x1
#define DW_IC_STATUS_TFE BIT(2)
#define DW_IC_STATUS_MASTER_ACTIVITY BIT(5)
+#define DW_IC_STATUS_SLAVE_ACTIVITY BIT(6)
#define DW_IC_SDA_HOLD_RX_SHIFT 16
#define DW_IC_SDA_HOLD_RX_MASK GENMASK(23, DW_IC_SDA_HOLD_RX_SHIFT)
@@ -129,6 +140,9 @@
#define ABRT_10B_RD_NORSTRT 10
#define ABRT_MASTER_DIS 11
#define ARB_LOST 12
+#define ABRT_SLAVE_FLUSH_TXFIFO 13
+#define ABRT_SLAVE_ARBLOST 14
+#define ABRT_SLAVE_RD_INTX 15
#define DW_IC_TX_ABRT_7B_ADDR_NOACK (1UL << ABRT_7B_ADDR_NOACK)
#define DW_IC_TX_ABRT_10ADDR1_NOACK (1UL << ABRT_10ADDR1_NOACK)
@@ -141,6 +155,9 @@
#define DW_IC_TX_ABRT_10B_RD_NORSTRT (1UL << ABRT_10B_RD_NORSTRT)
#define DW_IC_TX_ABRT_MASTER_DIS (1UL << ABRT_MASTER_DIS)
#define DW_IC_TX_ARB_LOST (1UL << ARB_LOST)
+#define DW_IC_RX_ABRT_SLAVE_RD_INTX (1UL << ABRT_SLAVE_RD_INTX)
+#define DW_IC_RX_ABRT_SLAVE_ARBLOST (1UL << ABRT_SLAVE_ARBLOST)
+#define DW_IC_RX_ABRT_SLAVE_FLUSH_TXFIFO (1UL << ABRT_SLAVE_FLUSH_TXFIFO)
#define DW_IC_TX_ABRT_NOACK (DW_IC_TX_ABRT_7B_ADDR_NOACK | \
DW_IC_TX_ABRT_10ADDR1_NOACK | \
@@ -195,6 +212,7 @@ struct dw_i2c_dev {
void __iomem *base;
struct completion cmd_complete;
struct clk *clk;
+ struct i2c_client *slave;
u32 (*get_clk_rate_khz) (struct dw_i2c_dev *dev);
struct dw_pci_controller *controller;
int cmd_err;
@@ -214,6 +232,7 @@ struct dw_i2c_dev {
struct i2c_adapter adapter;
u32 functionality;
u32 master_cfg;
+ u32 slave_cfg;
unsigned int tx_fifo_depth;
unsigned int rx_fifo_depth;
int rx_outstanding;
@@ -257,6 +276,11 @@ extern void i2c_dw_disable(struct dw_i2c_dev *dev);
extern void i2c_dw_disable_int(struct dw_i2c_dev *dev);
extern u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev);
extern int i2c_dw_probe(struct dw_i2c_dev *dev);
+extern int i2c_dw_init_slave(struct dw_i2c_dev *dev);
+extern void i2c_dw_disable_slave(struct dw_i2c_dev *dev);
+extern void i2c_dw_disable_int_slave(struct dw_i2c_dev *dev);
+extern u32 i2c_dw_read_comp_param_slave(struct dw_i2c_dev *dev);
+extern int i2c_dw_probe_slave(struct dw_i2c_dev *dev);
#if IS_ENABLED(CONFIG_I2C_DESIGNWARE_BAYTRAIL)
extern int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev);
diff --git a/drivers/i2c/busses/i2c-designware-src.c b/drivers/i2c/busses/i2c-designware-src.c
index 4ec0045..838ef66 100644
--- a/drivers/i2c/busses/i2c-designware-src.c
+++ b/drivers/i2c/busses/i2c-designware-src.c
@@ -55,6 +55,12 @@ static char *abort_sources[] = {
"trying to use disabled adapter",
[ARB_LOST] =
"lost arbitration",
+ [ABRT_SLAVE_FLUSH_TXFIFO] =
+ "read command so flush old data in the TX FIFO",
+ [ABRT_SLAVE_ARBLOST] =
+ "slave lost the bus while transmitting data to a remote master",
+ [ABRT_SLAVE_RD_INTX] =
+ "slave request for data to be transmitted and",
};
u32 dw_readl(struct dw_i2c_dev *dev, int offset)
--
2.10.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH v3 3/5] i2c: designware: Add slave definitions
2016-11-18 11:19 ` Luis Oliveira
(?)
@ 2016-11-18 12:35 ` Andy Shevchenko
2016-11-18 17:01 ` Rob Herring
-1 siblings, 1 reply; 19+ messages in thread
From: Andy Shevchenko @ 2016-11-18 12:35 UTC (permalink / raw)
To: Luis Oliveira, wsa, robh+dt, mark.rutland, jarkko.nikula,
mika.westerberg, linux-i2c, devicetree, linux-kernel
Cc: Ramiro.Oliveira, Joao.Pinto, CARLOS.PALMINHA
On Fri, 2016-11-18 at 11:19 +0000, Luis Oliveira wrote:
> - Add slave defintitions to i2c-designware-core
> - Changes in Kconfig to auto-enable I2C_SLAVE when compiling the
> modules
> - Add compatible string to designware-core.txt explaining the
> devicetree bindings
>
> --- a/Documentation/devicetree/bindings/i2c/i2c-designware.txt
> +++ b/Documentation/devicetree/bindings/i2c/i2c-designware.txt
> @@ -2,7 +2,9 @@
>
> Required properties :
>
> - - compatible : should be "snps,designware-i2c"
> + - compatible : should be:
> + - "snps,designware-i2c" to setup the hardware block as I2C master.
> + - "snps,designware-i2c-slave" to setup the hardware block as I2C
> slave.
Not sure about this one.
Compatible string is more generic than list of modes. Basically you have
to add a property which selects mode.
DT people's ACK is a must for this change.
--- a/drivers/i2c/busses/Kconfig
> +++ b/drivers/i2c/busses/Kconfig
> @@ -470,6 +470,7 @@ config I2C_DESIGNWARE_CORE
> config I2C_DESIGNWARE_PLATFORM
> tristate "Synopsys DesignWare Platform"
> select I2C_DESIGNWARE_CORE
> + select I2C_SLAVE
>
Common rule, generic dependencies usually go first
select I2C_SLAVE
select I2C_DESIGNWARE_CORE
--
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 3/5] i2c: designware: Add slave definitions
@ 2016-11-18 17:01 ` Rob Herring
0 siblings, 0 replies; 19+ messages in thread
From: Rob Herring @ 2016-11-18 17:01 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Luis Oliveira, wsa, mark.rutland, jarkko.nikula, mika.westerberg,
linux-i2c, devicetree, linux-kernel, Ramiro.Oliveira, Joao.Pinto,
CARLOS.PALMINHA
On Fri, Nov 18, 2016 at 02:35:52PM +0200, Andy Shevchenko wrote:
> On Fri, 2016-11-18 at 11:19 +0000, Luis Oliveira wrote:
> > - Add slave defintitions to i2c-designware-core
> > - Changes in Kconfig to auto-enable I2C_SLAVE when compiling the
> > modules
> > - Add compatible string to designware-core.txt explaining the
> > devicetree bindings
> >
>
>
> > --- a/Documentation/devicetree/bindings/i2c/i2c-designware.txt
> > +++ b/Documentation/devicetree/bindings/i2c/i2c-designware.txt
> > @@ -2,7 +2,9 @@
> >
> > Required properties :
> >
> > - - compatible : should be "snps,designware-i2c"
> > + - compatible : should be:
> > + - "snps,designware-i2c" to setup the hardware block as I2C master.
> > + - "snps,designware-i2c-slave" to setup the hardware block as I2C
> > slave.
>
> Not sure about this one.
>
> Compatible string is more generic than list of modes. Basically you have
> to add a property which selects mode.
Yes, agreed. And come up with a common property.
> DT people's ACK is a must for this change.
>
>
> --- a/drivers/i2c/busses/Kconfig
> > +++ b/drivers/i2c/busses/Kconfig
> > @@ -470,6 +470,7 @@ config I2C_DESIGNWARE_CORE
> > config I2C_DESIGNWARE_PLATFORM
> > tristate "Synopsys DesignWare Platform"
> > select I2C_DESIGNWARE_CORE
> > + select I2C_SLAVE
> >
>
> Common rule, generic dependencies usually go first
>
> select I2C_SLAVE
> select I2C_DESIGNWARE_CORE
>
> --
> Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> Intel Finland Oy
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 3/5] i2c: designware: Add slave definitions
@ 2016-11-18 17:01 ` Rob Herring
0 siblings, 0 replies; 19+ messages in thread
From: Rob Herring @ 2016-11-18 17:01 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Luis Oliveira, wsa-z923LK4zBo2bacvFa/9K2g,
mark.rutland-5wv7dgnIgG8, jarkko.nikula-VuQAYsv1563Yd54FQh9/CA,
mika.westerberg-VuQAYsv1563Yd54FQh9/CA,
linux-i2c-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
Ramiro.Oliveira-HKixBCOQz3hWk0Htik3J/w,
Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
CARLOS.PALMINHA-HKixBCOQz3hWk0Htik3J/w
On Fri, Nov 18, 2016 at 02:35:52PM +0200, Andy Shevchenko wrote:
> On Fri, 2016-11-18 at 11:19 +0000, Luis Oliveira wrote:
> > - Add slave defintitions to i2c-designware-core
> > - Changes in Kconfig to auto-enable I2C_SLAVE when compiling the
> > modules
> > - Add compatible string to designware-core.txt explaining the
> > devicetree bindings
> >
>
>
> > --- a/Documentation/devicetree/bindings/i2c/i2c-designware.txt
> > +++ b/Documentation/devicetree/bindings/i2c/i2c-designware.txt
> > @@ -2,7 +2,9 @@
> >
> > Required properties :
> >
> > - - compatible : should be "snps,designware-i2c"
> > + - compatible : should be:
> > + - "snps,designware-i2c" to setup the hardware block as I2C master.
> > + - "snps,designware-i2c-slave" to setup the hardware block as I2C
> > slave.
>
> Not sure about this one.
>
> Compatible string is more generic than list of modes. Basically you have
> to add a property which selects mode.
Yes, agreed. And come up with a common property.
> DT people's ACK is a must for this change.
>
>
> --- a/drivers/i2c/busses/Kconfig
> > +++ b/drivers/i2c/busses/Kconfig
> > @@ -470,6 +470,7 @@ config I2C_DESIGNWARE_CORE
> > config I2C_DESIGNWARE_PLATFORM
> > tristate "Synopsys DesignWare Platform"
> > select I2C_DESIGNWARE_CORE
> > + select I2C_SLAVE
> >
>
> Common rule, generic dependencies usually go first
>
> select I2C_SLAVE
> select I2C_DESIGNWARE_CORE
>
> --
> Andy Shevchenko <andriy.shevchenko-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> Intel Finland Oy
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 3/5] i2c: designware: Add slave definitions
2016-11-18 17:01 ` Rob Herring
@ 2016-11-23 14:36 ` Luis Oliveira
-1 siblings, 0 replies; 19+ messages in thread
From: Luis Oliveira @ 2016-11-23 14:36 UTC (permalink / raw)
To: Rob Herring, Andy Shevchenko
Cc: Luis Oliveira, wsa, mark.rutland, jarkko.nikula, mika.westerberg,
linux-i2c, devicetree, linux-kernel, Ramiro.Oliveira, Joao.Pinto,
CARLOS.PALMINHA
OK, I will create a "mode" string property in the devicetree that can be
"master" or "slave".
Thank you all,
Luis
On 18-Nov-16 17:01, Rob Herring wrote:
> On Fri, Nov 18, 2016 at 02:35:52PM +0200, Andy Shevchenko wrote:
>> On Fri, 2016-11-18 at 11:19 +0000, Luis Oliveira wrote:
>>> - Add slave defintitions to i2c-designware-core
>>> - Changes in Kconfig to auto-enable I2C_SLAVE when compiling the
>>> modules
>>> - Add compatible string to designware-core.txt explaining the
>>> devicetree bindings
>>>
>>
>>> --- a/Documentation/devicetree/bindings/i2c/i2c-designware.txt
>>> +++ b/Documentation/devicetree/bindings/i2c/i2c-designware.txt
>>> @@ -2,7 +2,9 @@
>>>
>>> Required properties :
>>>
>>> - - compatible : should be "snps,designware-i2c"
>>> + - compatible : should be:
>>> + - "snps,designware-i2c" to setup the hardware block as I2C master.
>>> + - "snps,designware-i2c-slave" to setup the hardware block as I2C
>>> slave.
>> Not sure about this one.
>>
>> Compatible string is more generic than list of modes. Basically you have
>> to add a property which selects mode.
> Yes, agreed. And come up with a common property.
>
>> DT people's ACK is a must for this change.
>>
>>
>> --- a/drivers/i2c/busses/Kconfig
>>> +++ b/drivers/i2c/busses/Kconfig
>>> @@ -470,6 +470,7 @@ config I2C_DESIGNWARE_CORE
>>> config I2C_DESIGNWARE_PLATFORM
>>> tristate "Synopsys DesignWare Platform"
>>> select I2C_DESIGNWARE_CORE
>>> + select I2C_SLAVE
>>>
>> Common rule, generic dependencies usually go first
>>
>> select I2C_SLAVE
>> select I2C_DESIGNWARE_CORE
>>
>> --
>> Andy Shevchenko <andriy.shevchenko@linux.intel.com>
>> Intel Finland Oy
--
Best regards,
Luis
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 3/5] i2c: designware: Add slave definitions
@ 2016-11-23 14:36 ` Luis Oliveira
0 siblings, 0 replies; 19+ messages in thread
From: Luis Oliveira @ 2016-11-23 14:36 UTC (permalink / raw)
To: Rob Herring, Andy Shevchenko
Cc: Luis Oliveira, wsa, mark.rutland, jarkko.nikula, mika.westerberg,
linux-i2c, devicetree, linux-kernel, Ramiro.Oliveira, Joao.Pinto,
CARLOS.PALMINHA
OK, I will create a "mode" string property in the devicetree that can be
"master" or "slave".
Thank you all,
Luis
On 18-Nov-16 17:01, Rob Herring wrote:
> On Fri, Nov 18, 2016 at 02:35:52PM +0200, Andy Shevchenko wrote:
>> On Fri, 2016-11-18 at 11:19 +0000, Luis Oliveira wrote:
>>> - Add slave defintitions to i2c-designware-core
>>> - Changes in Kconfig to auto-enable I2C_SLAVE when compiling the
>>> modules
>>> - Add compatible string to designware-core.txt explaining the
>>> devicetree bindings
>>>
>>
>>> --- a/Documentation/devicetree/bindings/i2c/i2c-designware.txt
>>> +++ b/Documentation/devicetree/bindings/i2c/i2c-designware.txt
>>> @@ -2,7 +2,9 @@
>>>
>>> Required properties :
>>>
>>> - - compatible : should be "snps,designware-i2c"
>>> + - compatible : should be:
>>> + - "snps,designware-i2c" to setup the hardware block as I2C master.
>>> + - "snps,designware-i2c-slave" to setup the hardware block as I2C
>>> slave.
>> Not sure about this one.
>>
>> Compatible string is more generic than list of modes. Basically you have
>> to add a property which selects mode.
> Yes, agreed. And come up with a common property.
>
>> DT people's ACK is a must for this change.
>>
>>
>> --- a/drivers/i2c/busses/Kconfig
>>> +++ b/drivers/i2c/busses/Kconfig
>>> @@ -470,6 +470,7 @@ config I2C_DESIGNWARE_CORE
>>> config I2C_DESIGNWARE_PLATFORM
>>> tristate "Synopsys DesignWare Platform"
>>> select I2C_DESIGNWARE_CORE
>>> + select I2C_SLAVE
>>>
>> Common rule, generic dependencies usually go first
>>
>> select I2C_SLAVE
>> select I2C_DESIGNWARE_CORE
>>
>> --
>> Andy Shevchenko <andriy.shevchenko@linux.intel.com>
>> Intel Finland Oy
--
Best regards,
Luis
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 4/5] i2c: designware: Add slave mode as separated driver
@ 2016-11-18 11:19 ` Luis Oliveira
0 siblings, 0 replies; 19+ messages in thread
From: Luis Oliveira @ 2016-11-18 11:19 UTC (permalink / raw)
To: wsa, robh+dt, mark.rutland, jarkko.nikula, andriy.shevchenko,
mika.westerberg, linux-i2c, devicetree, linux-kernel
Cc: Luis.Oliveira, Ramiro.Oliveira, Joao.Pinto, CARLOS.PALMINHA
- Slave mode selected by compatibility string in platform module
- Changes in Makefile to compile i2c-designware-core with slave functions
Signed-off-by: Luis Oliveira <lolivei@synopsys.com>
---
Changes V2->V3: (Andy Shevchenko)
- slave code in a separated driver as suggested by Wolfram Sang
- changes in Makefile for compilation purposes
drivers/i2c/busses/Makefile | 2 +-
drivers/i2c/busses/i2c-designware-platdrv.c | 69 ++++-
drivers/i2c/busses/i2c-designware-slave.c | 445 ++++++++++++++++++++++++++++
3 files changed, 507 insertions(+), 9 deletions(-)
create mode 100644 drivers/i2c/busses/i2c-designware-slave.c
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index fc4e554..25e1778 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -40,7 +40,7 @@ obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o
obj-$(CONFIG_I2C_CPM) += i2c-cpm.o
obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o
obj-$(CONFIG_I2C_DESIGNWARE_CORE) += i2c-designware-core.o
-i2c-designware-core-objs := i2c-designware-src.o i2c-designware-master.o
+i2c-designware-core-objs := i2c-designware-src.o i2c-designware-slave.o i2c-designware-master.o
obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o
i2c-designware-platform-objs := i2c-designware-platdrv.o
i2c-designware-platform-$(CONFIG_I2C_DESIGNWARE_BAYTRAIL) += i2c-designware-baytrail.o
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index f4e28ac..7beb0a2 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -160,6 +160,30 @@ static void i2c_dw_configure_master(struct platform_device *pdev)
}
}
+static void i2c_dw_configure_slave(struct platform_device *pdev)
+{
+ struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
+
+ dev->slave_cfg = DW_IC_CON_RX_FIFO_FULL_HLD_CTRL |
+ DW_IC_CON_RESTART_EN | DW_IC_CON_STOP_DET_IFADDRESSED |
+ DW_IC_CON_SPEED_FAST;
+
+ dev->functionality |= I2C_FUNC_SLAVE;
+ dev->functionality &= ~I2C_FUNC_10BIT_ADDR;
+ dev_info(&pdev->dev, "I am registed as a I2C Slave!\n");
+
+ switch (dev->clk_freq) {
+ case 100000:
+ dev->slave_cfg |= DW_IC_CON_SPEED_STD;
+ break;
+ case 3400000:
+ dev->slave_cfg |= DW_IC_CON_SPEED_HIGH;
+ break;
+ default:
+ dev->slave_cfg |= DW_IC_CON_SPEED_FAST;
+ }
+}
+
static int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare)
{
if (IS_ERR(i_dev->clk))
@@ -244,7 +268,11 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_I2C_BLOCK;
- i2c_dw_configure_master(pdev);
+ if (of_device_is_compatible(pdev->dev.of_node,
+ "snps,designware-i2c-slave"))
+ i2c_dw_configure_slave(pdev);
+ else
+ i2c_dw_configure_master(pdev);
dev->clk = devm_clk_get(&pdev->dev, NULL);
if (!i2c_dw_plat_prepare_clk(dev, true)) {
@@ -257,7 +285,13 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
}
if (!dev->tx_fifo_depth) {
- u32 param1 = i2c_dw_read_comp_param(dev);
+ u32 param1;
+
+ if (of_device_is_compatible(pdev->dev.of_node,
+ "snps,designware-i2c-slave"))
+ param1 = i2c_dw_read_comp_param_slave(dev);
+ else
+ param1 = i2c_dw_read_comp_param(dev);
dev->tx_fifo_depth = ((param1 >> 16) & 0xff) + 1;
dev->rx_fifo_depth = ((param1 >> 8) & 0xff) + 1;
@@ -278,8 +312,12 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
}
+ if (of_device_is_compatible(pdev->dev.of_node,
+ "snps,designware-i2c-slave"))
+ r = i2c_dw_probe_slave(dev);
+ else
+ r = i2c_dw_probe(dev);
- r = i2c_dw_probe(dev);
if (r && !dev->pm_runtime_disabled)
pm_runtime_disable(&pdev->dev);
@@ -291,10 +329,13 @@ static int dw_i2c_plat_remove(struct platform_device *pdev)
struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
pm_runtime_get_sync(&pdev->dev);
-
i2c_del_adapter(&dev->adapter);
- i2c_dw_disable(dev);
+ if (of_device_is_compatible(pdev->dev.of_node,
+ "snps,designware-i2c-slave"))
+ i2c_dw_disable_slave(dev);
+ else
+ i2c_dw_disable(dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
pm_runtime_put_sync(&pdev->dev);
@@ -307,6 +348,9 @@ static int dw_i2c_plat_remove(struct platform_device *pdev)
#ifdef CONFIG_OF
static const struct of_device_id dw_i2c_of_match[] = {
{ .compatible = "snps,designware-i2c", },
+#ifndef CONFIG_ACPI
+ { .compatible = "snps,designware-i2c-slave", },
+#endif
{},
};
MODULE_DEVICE_TABLE(of, dw_i2c_of_match);
@@ -334,7 +378,11 @@ static int dw_i2c_plat_suspend(struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
- i2c_dw_disable(i_dev);
+ if (of_device_is_compatible(pdev->dev.of_node,
+ "snps,designware-i2c-slave"))
+ i2c_dw_disable_slave(i_dev);
+ else
+ i2c_dw_disable(i_dev);
i2c_dw_plat_prepare_clk(i_dev, false);
return 0;
@@ -347,8 +395,13 @@ static int dw_i2c_plat_resume(struct device *dev)
i2c_dw_plat_prepare_clk(i_dev, true);
- if (!i_dev->pm_runtime_disabled)
- i2c_dw_init(i_dev);
+ if (!i_dev->pm_runtime_disabled) {
+ if (of_device_is_compatible(pdev->dev.of_node,
+ "snps,designware-i2c-slave"))
+ i2c_dw_init_slave(i_dev);
+ else
+ i2c_dw_init(i_dev);
+ }
return 0;
}
diff --git a/drivers/i2c/busses/i2c-designware-slave.c b/drivers/i2c/busses/i2c-designware-slave.c
new file mode 100644
index 0000000..6b0db3b
--- /dev/null
+++ b/drivers/i2c/busses/i2c-designware-slave.c
@@ -0,0 +1,445 @@
+/*
+ * Synopsys DesignWare I2C adapter driver (master only).
+ *
+ * Based on the TI DAVINCI I2C adapter driver.
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ * Copyright (C) 2007 MontaVista Software Inc.
+ * Copyright (C) 2009 Provigent Ltd.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/export.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include "i2c-designware-core.h"
+
+static void i2c_dw_configure_fifo_slave(struct dw_i2c_dev *dev)
+{
+ /* Configure Tx/Rx FIFO threshold levels */
+ dw_writel(dev, 0, DW_IC_TX_TL);
+ dw_writel(dev, 0, DW_IC_RX_TL);
+
+ /* configure the i2c slave */
+ dw_writel(dev, dev->slave_cfg, DW_IC_CON);
+ dw_writel(dev, DW_IC_INTR_SLAVE_MASK, DW_IC_INTR_MASK);
+}
+
+/**
+ * i2c_dw_init_slave() - initialize the designware i2c slave hardware
+ * @dev: device private data
+ *
+ * This functions configures and enables the I2C.
+ * This function is called during I2C init function, and in case of timeout at
+ * run time.
+ */
+int i2c_dw_init_slave(struct dw_i2c_dev *dev)
+{
+ u32 hcnt, lcnt;
+ u32 reg, comp_param1;
+ u32 sda_falling_time, scl_falling_time;
+ int ret;
+
+ ret = i2c_dw_acquire_lock(dev);
+ if (ret)
+ return ret;
+
+ reg = dw_readl(dev, DW_IC_COMP_TYPE);
+ if (reg == ___constant_swab32(DW_IC_COMP_TYPE_VALUE)) {
+ /* Configure register endianness access */
+ dev->accessor_flags |= ACCESS_SWAP;
+ } else if (reg == (DW_IC_COMP_TYPE_VALUE & 0x0000ffff)) {
+ /* Configure register access mode 16bit */
+ dev->accessor_flags |= ACCESS_16BIT;
+ } else if (reg != DW_IC_COMP_TYPE_VALUE) {
+ dev_err(dev->dev, "Unknown Synopsys component type: "
+ "0x%08x\n", reg);
+ i2c_dw_release_lock(dev);
+ return -ENODEV;
+ }
+
+ comp_param1 = dw_readl(dev, DW_IC_COMP_PARAM_1);
+
+ /* Disable the adapter */
+ __i2c_dw_enable_and_wait(dev, false);
+
+ /* set standard and fast speed deviders for high/low periods */
+ sda_falling_time = dev->sda_falling_time ?: 300; /* ns */
+ scl_falling_time = dev->scl_falling_time ?: 300; /* ns */
+
+ /* Set SCL timing parameters for standard-mode */
+ if (dev->ss_hcnt && dev->ss_lcnt) {
+ hcnt = dev->ss_hcnt;
+ lcnt = dev->ss_lcnt;
+ } else {
+ hcnt = i2c_dw_scl_hcnt(i2c_dw_clk_rate(dev),
+ 4000, /* tHD;STA = tHIGH = 4.0 us */
+ sda_falling_time,
+ 0, /* 0: DW default, 1: Ideal */
+ 0); /* No offset */
+ lcnt = i2c_dw_scl_lcnt(i2c_dw_clk_rate(dev),
+ 4700, /* tLOW = 4.7 us */
+ scl_falling_time,
+ 0); /* No offset */
+ }
+ dw_writel(dev, hcnt, DW_IC_SS_SCL_HCNT);
+ dw_writel(dev, lcnt, DW_IC_SS_SCL_LCNT);
+ dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
+
+ /* Set SCL timing parameters for fast-mode or fast-mode plus */
+ if ((dev->clk_freq == 1000000) && dev->fp_hcnt && dev->fp_lcnt) {
+ hcnt = dev->fp_hcnt;
+ lcnt = dev->fp_lcnt;
+ } else if (dev->fs_hcnt && dev->fs_lcnt) {
+ hcnt = dev->fs_hcnt;
+ lcnt = dev->fs_lcnt;
+ } else {
+ hcnt = i2c_dw_scl_hcnt(i2c_dw_clk_rate(dev),
+ 600, /* tHD;STA = tHIGH = 0.6 us */
+ sda_falling_time,
+ 0, /* 0: DW default, 1: Ideal */
+ 0); /* No offset */
+ lcnt = i2c_dw_scl_lcnt(i2c_dw_clk_rate(dev),
+ 1300, /* tLOW = 1.3 us */
+ scl_falling_time,
+ 0); /* No offset */
+ }
+ dw_writel(dev, hcnt, DW_IC_FS_SCL_HCNT);
+ dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT);
+ dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
+
+ if ((dev->slave_cfg & DW_IC_CON_SPEED_MASK) ==
+ DW_IC_CON_SPEED_HIGH) {
+ if ((comp_param1 & DW_IC_COMP_PARAM_1_SPEED_MODE_MASK)
+ != DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH) {
+ dev_err(dev->dev, "High Speed not supported!\n");
+ dev->slave_cfg &= ~DW_IC_CON_SPEED_MASK;
+ dev->slave_cfg |= DW_IC_CON_SPEED_FAST;
+ } else if (dev->hs_hcnt && dev->hs_lcnt) {
+ hcnt = dev->hs_hcnt;
+ lcnt = dev->hs_lcnt;
+ dw_writel(dev, hcnt, DW_IC_HS_SCL_HCNT);
+ dw_writel(dev, lcnt, DW_IC_HS_SCL_LCNT);
+ dev_dbg(dev->dev, "HighSpeed-mode HCNT:LCNT = %d:%d\n",
+ hcnt, lcnt);
+ }
+ }
+
+ /* Configure SDA Hold Time if required */
+ reg = dw_readl(dev, DW_IC_COMP_VERSION);
+ reg = dw_readl(dev, DW_IC_COMP_VERSION);
+ if (reg >= DW_IC_SDA_HOLD_MIN_VERS) {
+ if (!dev->sda_hold_time) {
+ /* Keep previous hold time setting if no one set it */
+ dev->sda_hold_time = dw_readl(dev, DW_IC_SDA_HOLD);
+ }
+ /*
+ * Workaround for avoiding TX arbitration lost in case I2C
+ * slave pulls SDA down "too quickly" after falling egde of
+ * SCL by enabling non-zero SDA RX hold. Specification says it
+ * extends incoming SDA low to high transition while SCL is
+ * high but it apprears to help also above issue.
+ */
+ if (!(dev->sda_hold_time & DW_IC_SDA_HOLD_RX_MASK))
+ dev->sda_hold_time |= 1 << DW_IC_SDA_HOLD_RX_SHIFT;
+ dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD);
+ } else {
+ dev_warn(dev->dev,
+ "Hardware too old to adjust SDA hold time.\n");
+ }
+
+ i2c_dw_configure_fifo_slave(dev);
+ i2c_dw_release_lock(dev);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(i2c_dw_init_slave);
+
+int i2c_dw_reg_slave(struct i2c_client *slave)
+{
+ struct dw_i2c_dev *dev = i2c_get_adapdata(slave->adapter);
+
+ if (dev->slave)
+ return -EBUSY;
+ if (slave->flags & I2C_CLIENT_TEN)
+ return -EAFNOSUPPORT;
+ /* set slave address in the IC_SAR register,
+ * the address to which the DW_apb_i2c responds */
+
+ __i2c_dw_enable(dev, false);
+ dw_writel(dev, slave->addr, DW_IC_SAR);
+ dev->slave = slave;
+
+ __i2c_dw_enable(dev, true);
+
+ dev->cmd_err = 0;
+ dev->msg_write_idx = 0;
+ dev->msg_read_idx = 0;
+ dev->msg_err = 0;
+ dev->status = STATUS_IDLE;
+ dev->abort_source = 0;
+ dev->rx_outstanding = 0;
+
+ return 0;
+}
+
+static int i2c_dw_unreg_slave(struct i2c_client *slave)
+{
+ struct dw_i2c_dev *dev = i2c_get_adapdata(slave->adapter);
+
+ i2c_dw_disable_int_slave(dev);
+ i2c_dw_disable_slave(dev);
+ dev->slave = NULL;
+
+ return 0;
+}
+
+static u32 i2c_dw_read_clear_intrbits_slave(struct dw_i2c_dev *dev)
+{
+ u32 stat;
+
+ /*
+ * The IC_INTR_STAT register just indicates "enabled" interrupts.
+ * Ths unmasked raw version of interrupt status bits are available
+ * in the IC_RAW_INTR_STAT register.
+ *
+ * That is,
+ * stat = dw_readl(IC_INTR_STAT);
+ * equals to,
+ * stat = dw_readl(IC_RAW_INTR_STAT) & dw_readl(IC_INTR_MASK);
+ *
+ * The raw version might be useful for debugging purposes.
+ */
+ stat = dw_readl(dev, DW_IC_INTR_STAT);
+
+ /*
+ * Do not use the IC_CLR_INTR register to clear interrupts, or
+ * you'll miss some interrupts, triggered during the period from
+ * dw_readl(IC_INTR_STAT) to dw_readl(IC_CLR_INTR).
+ *
+ * Instead, use the separately-prepared IC_CLR_* registers.
+ */
+ if (stat & DW_IC_INTR_RX_UNDER)
+ dw_readl(dev, DW_IC_CLR_RX_UNDER);
+ if (stat & DW_IC_INTR_RX_OVER)
+ dw_readl(dev, DW_IC_CLR_RX_OVER);
+ if (stat & DW_IC_INTR_TX_OVER)
+ dw_readl(dev, DW_IC_CLR_TX_OVER);
+ if (stat & DW_IC_INTR_TX_ABRT) {
+ /*
+ * The IC_TX_ABRT_SOURCE register is cleared whenever
+ * the IC_CLR_TX_ABRT is read. Preserve it beforehand.
+ */
+ dev->abort_source = dw_readl(dev, DW_IC_TX_ABRT_SOURCE);
+ dw_readl(dev, DW_IC_CLR_TX_ABRT);
+ }
+ if (stat & DW_IC_INTR_RX_DONE)
+ dw_readl(dev, DW_IC_CLR_RX_DONE);
+ if (stat & DW_IC_INTR_ACTIVITY)
+ dw_readl(dev, DW_IC_CLR_ACTIVITY);
+ if (stat & DW_IC_INTR_STOP_DET)
+ dw_readl(dev, DW_IC_CLR_STOP_DET);
+ if (stat & DW_IC_INTR_START_DET)
+ dw_readl(dev, DW_IC_CLR_START_DET);
+ if (stat & DW_IC_INTR_GEN_CALL)
+ dw_readl(dev, DW_IC_CLR_GEN_CALL);
+
+ return stat;
+}
+
+/*
+ * Interrupt service routine. This gets called whenever an I2C interrupt
+ * occurs.
+ */
+
+static bool i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev)
+{
+ u32 raw_stat, stat, enabled;
+ u8 val, slave_activity;
+
+ stat = dw_readl(dev, DW_IC_INTR_STAT);
+ enabled = dw_readl(dev, DW_IC_ENABLE);
+ raw_stat = dw_readl(dev, DW_IC_RAW_INTR_STAT);
+ slave_activity = ((dw_readl(dev, DW_IC_STATUS) &
+ DW_IC_STATUS_SLAVE_ACTIVITY)>>6);
+
+ dev_dbg(dev->dev,
+ "%s: %#x SLAVE_ACTV=%#x : RAW_INTR_STAT=%#x : INTR_STAT=%#x\n",
+ __func__, enabled, slave_activity, raw_stat, stat);
+
+ if (stat & DW_IC_INTR_START_DET)
+ dw_readl(dev, DW_IC_CLR_START_DET);
+ if (stat & DW_IC_INTR_ACTIVITY)
+ dw_readl(dev, DW_IC_CLR_ACTIVITY);
+ if (stat & DW_IC_INTR_RX_OVER)
+ dw_readl(dev, DW_IC_CLR_RX_OVER);
+ if ((stat & DW_IC_INTR_RX_FULL) && (stat & DW_IC_INTR_STOP_DET))
+ i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_REQUESTED, &val);
+
+ if (slave_activity) {
+ if (stat & DW_IC_INTR_RD_REQ) {
+ if (stat & DW_IC_INTR_RX_FULL) {
+ val = dw_readl(dev, DW_IC_DATA_CMD);
+ if (!i2c_slave_event(dev->slave,
+ I2C_SLAVE_WRITE_RECEIVED, &val)) {
+ dev_dbg(dev->dev, "Byte %X acked! ",
+ val);
+ }
+ dw_readl(dev, DW_IC_CLR_RD_REQ);
+ stat = i2c_dw_read_clear_intrbits_slave(dev);
+ } else {
+ dw_readl(dev, DW_IC_CLR_RD_REQ);
+ dw_readl(dev, DW_IC_CLR_RX_UNDER);
+ stat = i2c_dw_read_clear_intrbits_slave(dev);
+ }
+ if (!i2c_slave_event(dev->slave,
+ I2C_SLAVE_READ_REQUESTED, &val))
+ dw_writel(dev, val, DW_IC_DATA_CMD);
+ }
+ }
+
+ if (stat & DW_IC_INTR_RX_DONE) {
+ if (!i2c_slave_event(dev->slave, I2C_SLAVE_READ_PROCESSED,
+ &val))
+ dw_readl(dev, DW_IC_CLR_RX_DONE);
+
+ i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &val);
+ stat = i2c_dw_read_clear_intrbits_slave(dev);
+ return true;
+ }
+
+ if (stat & DW_IC_INTR_RX_FULL) {
+ val = dw_readl(dev, DW_IC_DATA_CMD);
+ if (!i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_RECEIVED,
+ &val))
+ dev_dbg(dev->dev, "Byte %X acked! ", val);
+ } else {
+ i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &val);
+ stat = i2c_dw_read_clear_intrbits_slave(dev);
+ }
+
+ if (stat & DW_IC_INTR_TX_OVER) {
+ dw_readl(dev, DW_IC_CLR_TX_OVER);
+ return true;
+ }
+ return true;
+}
+
+static irqreturn_t i2c_dw_isr_slave(int this_irq, void *dev_id)
+{
+ struct dw_i2c_dev *dev = dev_id;
+ u32 stat, enabled, mode;
+
+ enabled = dw_readl(dev, DW_IC_ENABLE);
+ mode = dw_readl(dev, DW_IC_CON);
+ stat = dw_readl(dev, DW_IC_RAW_INTR_STAT);
+
+ dev_dbg(dev->dev, "%s: enabled=%#x stat=%#x\n", __func__, enabled,
+ stat);
+ if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY))
+ return IRQ_NONE;
+
+ stat = i2c_dw_read_clear_intrbits_slave(dev);
+ if (!i2c_dw_irq_handler_slave(dev))
+ return IRQ_NONE;
+
+ complete(&dev->cmd_complete);
+ return IRQ_HANDLED;
+}
+
+static struct i2c_algorithm i2c_dw_algo = {
+ .functionality = i2c_dw_func,
+ .reg_slave = i2c_dw_reg_slave,
+ .unreg_slave = i2c_dw_unreg_slave,
+};
+
+void i2c_dw_disable_slave(struct dw_i2c_dev *dev)
+{
+ /* Disable controller */
+ __i2c_dw_enable_and_wait(dev, false);
+
+ /* Disable all interupts */
+ dw_writel(dev, 0, DW_IC_INTR_MASK);
+ dw_readl(dev, DW_IC_CLR_INTR);
+}
+EXPORT_SYMBOL_GPL(i2c_dw_disable_slave);
+
+void i2c_dw_disable_int_slave(struct dw_i2c_dev *dev)
+{
+ dw_writel(dev, 0, DW_IC_INTR_MASK);
+}
+EXPORT_SYMBOL_GPL(i2c_dw_disable_int_slave);
+
+u32 i2c_dw_read_comp_param_slave(struct dw_i2c_dev *dev)
+{
+ return dw_readl(dev, DW_IC_COMP_PARAM_1);
+}
+EXPORT_SYMBOL_GPL(i2c_dw_read_comp_param_slave);
+
+int i2c_dw_probe_slave(struct dw_i2c_dev *dev)
+{
+ struct i2c_adapter *adap = &dev->adapter;
+ int r;
+
+ init_completion(&dev->cmd_complete);
+
+ r = i2c_dw_init_slave(dev);
+ if (r)
+ return r;
+
+ r = i2c_dw_acquire_lock(dev);
+ if (r)
+ return r;
+
+ i2c_dw_release_lock(dev);
+ snprintf(adap->name, sizeof(adap->name),
+ "Synopsys DesignWare I2C Slave adapter");
+ adap->retries = 3;
+ adap->algo = &i2c_dw_algo;
+ adap->dev.parent = dev->dev;
+ i2c_set_adapdata(adap, dev);
+
+ r = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr_slave,
+ IRQF_SHARED | IRQF_COND_SUSPEND,
+ dev_name(dev->dev), dev);
+ if (r) {
+ dev_err(dev->dev, "failure requesting irq %i: %d\n",
+ dev->irq, r);
+ return r;
+ }
+ /*
+ * Increment PM usage count during adapter registration in order to
+ * avoid possible spurious runtime suspend when adapter device is
+ * registered to the device core and immediate resume in case bus has
+ * registered I2C slaves that do I2C transfers in their probe.
+ */
+ pm_runtime_get_noresume(dev->dev);
+ r = i2c_add_numbered_adapter(adap);
+ if (r)
+ dev_err(dev->dev, "failure adding adapter: %d\n", r);
+ pm_runtime_put_noidle(dev->dev);
+
+ return r;
+}
+EXPORT_SYMBOL_GPL(i2c_dw_probe_slave);
+
+MODULE_DESCRIPTION("Synopsys DesignWare I2C bus slave adapter");
+MODULE_LICENSE("GPL");
--
2.10.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v3 4/5] i2c: designware: Add slave mode as separated driver
@ 2016-11-18 11:19 ` Luis Oliveira
0 siblings, 0 replies; 19+ messages in thread
From: Luis Oliveira @ 2016-11-18 11:19 UTC (permalink / raw)
To: wsa-z923LK4zBo2bacvFa/9K2g, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
mark.rutland-5wv7dgnIgG8, jarkko.nikula-VuQAYsv1563Yd54FQh9/CA,
andriy.shevchenko-VuQAYsv1563Yd54FQh9/CA,
mika.westerberg-VuQAYsv1563Yd54FQh9/CA,
linux-i2c-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: Luis.Oliveira-HKixBCOQz3hWk0Htik3J/w,
Ramiro.Oliveira-HKixBCOQz3hWk0Htik3J/w,
Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
CARLOS.PALMINHA-HKixBCOQz3hWk0Htik3J/w
- Slave mode selected by compatibility string in platform module
- Changes in Makefile to compile i2c-designware-core with slave functions
Signed-off-by: Luis Oliveira <lolivei-HKixBCOQz3hWk0Htik3J/w@public.gmane.org>
---
Changes V2->V3: (Andy Shevchenko)
- slave code in a separated driver as suggested by Wolfram Sang
- changes in Makefile for compilation purposes
drivers/i2c/busses/Makefile | 2 +-
drivers/i2c/busses/i2c-designware-platdrv.c | 69 ++++-
drivers/i2c/busses/i2c-designware-slave.c | 445 ++++++++++++++++++++++++++++
3 files changed, 507 insertions(+), 9 deletions(-)
create mode 100644 drivers/i2c/busses/i2c-designware-slave.c
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index fc4e554..25e1778 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -40,7 +40,7 @@ obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o
obj-$(CONFIG_I2C_CPM) += i2c-cpm.o
obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o
obj-$(CONFIG_I2C_DESIGNWARE_CORE) += i2c-designware-core.o
-i2c-designware-core-objs := i2c-designware-src.o i2c-designware-master.o
+i2c-designware-core-objs := i2c-designware-src.o i2c-designware-slave.o i2c-designware-master.o
obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o
i2c-designware-platform-objs := i2c-designware-platdrv.o
i2c-designware-platform-$(CONFIG_I2C_DESIGNWARE_BAYTRAIL) += i2c-designware-baytrail.o
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index f4e28ac..7beb0a2 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -160,6 +160,30 @@ static void i2c_dw_configure_master(struct platform_device *pdev)
}
}
+static void i2c_dw_configure_slave(struct platform_device *pdev)
+{
+ struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
+
+ dev->slave_cfg = DW_IC_CON_RX_FIFO_FULL_HLD_CTRL |
+ DW_IC_CON_RESTART_EN | DW_IC_CON_STOP_DET_IFADDRESSED |
+ DW_IC_CON_SPEED_FAST;
+
+ dev->functionality |= I2C_FUNC_SLAVE;
+ dev->functionality &= ~I2C_FUNC_10BIT_ADDR;
+ dev_info(&pdev->dev, "I am registed as a I2C Slave!\n");
+
+ switch (dev->clk_freq) {
+ case 100000:
+ dev->slave_cfg |= DW_IC_CON_SPEED_STD;
+ break;
+ case 3400000:
+ dev->slave_cfg |= DW_IC_CON_SPEED_HIGH;
+ break;
+ default:
+ dev->slave_cfg |= DW_IC_CON_SPEED_FAST;
+ }
+}
+
static int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare)
{
if (IS_ERR(i_dev->clk))
@@ -244,7 +268,11 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_I2C_BLOCK;
- i2c_dw_configure_master(pdev);
+ if (of_device_is_compatible(pdev->dev.of_node,
+ "snps,designware-i2c-slave"))
+ i2c_dw_configure_slave(pdev);
+ else
+ i2c_dw_configure_master(pdev);
dev->clk = devm_clk_get(&pdev->dev, NULL);
if (!i2c_dw_plat_prepare_clk(dev, true)) {
@@ -257,7 +285,13 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
}
if (!dev->tx_fifo_depth) {
- u32 param1 = i2c_dw_read_comp_param(dev);
+ u32 param1;
+
+ if (of_device_is_compatible(pdev->dev.of_node,
+ "snps,designware-i2c-slave"))
+ param1 = i2c_dw_read_comp_param_slave(dev);
+ else
+ param1 = i2c_dw_read_comp_param(dev);
dev->tx_fifo_depth = ((param1 >> 16) & 0xff) + 1;
dev->rx_fifo_depth = ((param1 >> 8) & 0xff) + 1;
@@ -278,8 +312,12 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
}
+ if (of_device_is_compatible(pdev->dev.of_node,
+ "snps,designware-i2c-slave"))
+ r = i2c_dw_probe_slave(dev);
+ else
+ r = i2c_dw_probe(dev);
- r = i2c_dw_probe(dev);
if (r && !dev->pm_runtime_disabled)
pm_runtime_disable(&pdev->dev);
@@ -291,10 +329,13 @@ static int dw_i2c_plat_remove(struct platform_device *pdev)
struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
pm_runtime_get_sync(&pdev->dev);
-
i2c_del_adapter(&dev->adapter);
- i2c_dw_disable(dev);
+ if (of_device_is_compatible(pdev->dev.of_node,
+ "snps,designware-i2c-slave"))
+ i2c_dw_disable_slave(dev);
+ else
+ i2c_dw_disable(dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
pm_runtime_put_sync(&pdev->dev);
@@ -307,6 +348,9 @@ static int dw_i2c_plat_remove(struct platform_device *pdev)
#ifdef CONFIG_OF
static const struct of_device_id dw_i2c_of_match[] = {
{ .compatible = "snps,designware-i2c", },
+#ifndef CONFIG_ACPI
+ { .compatible = "snps,designware-i2c-slave", },
+#endif
{},
};
MODULE_DEVICE_TABLE(of, dw_i2c_of_match);
@@ -334,7 +378,11 @@ static int dw_i2c_plat_suspend(struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
- i2c_dw_disable(i_dev);
+ if (of_device_is_compatible(pdev->dev.of_node,
+ "snps,designware-i2c-slave"))
+ i2c_dw_disable_slave(i_dev);
+ else
+ i2c_dw_disable(i_dev);
i2c_dw_plat_prepare_clk(i_dev, false);
return 0;
@@ -347,8 +395,13 @@ static int dw_i2c_plat_resume(struct device *dev)
i2c_dw_plat_prepare_clk(i_dev, true);
- if (!i_dev->pm_runtime_disabled)
- i2c_dw_init(i_dev);
+ if (!i_dev->pm_runtime_disabled) {
+ if (of_device_is_compatible(pdev->dev.of_node,
+ "snps,designware-i2c-slave"))
+ i2c_dw_init_slave(i_dev);
+ else
+ i2c_dw_init(i_dev);
+ }
return 0;
}
diff --git a/drivers/i2c/busses/i2c-designware-slave.c b/drivers/i2c/busses/i2c-designware-slave.c
new file mode 100644
index 0000000..6b0db3b
--- /dev/null
+++ b/drivers/i2c/busses/i2c-designware-slave.c
@@ -0,0 +1,445 @@
+/*
+ * Synopsys DesignWare I2C adapter driver (master only).
+ *
+ * Based on the TI DAVINCI I2C adapter driver.
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ * Copyright (C) 2007 MontaVista Software Inc.
+ * Copyright (C) 2009 Provigent Ltd.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/export.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include "i2c-designware-core.h"
+
+static void i2c_dw_configure_fifo_slave(struct dw_i2c_dev *dev)
+{
+ /* Configure Tx/Rx FIFO threshold levels */
+ dw_writel(dev, 0, DW_IC_TX_TL);
+ dw_writel(dev, 0, DW_IC_RX_TL);
+
+ /* configure the i2c slave */
+ dw_writel(dev, dev->slave_cfg, DW_IC_CON);
+ dw_writel(dev, DW_IC_INTR_SLAVE_MASK, DW_IC_INTR_MASK);
+}
+
+/**
+ * i2c_dw_init_slave() - initialize the designware i2c slave hardware
+ * @dev: device private data
+ *
+ * This functions configures and enables the I2C.
+ * This function is called during I2C init function, and in case of timeout at
+ * run time.
+ */
+int i2c_dw_init_slave(struct dw_i2c_dev *dev)
+{
+ u32 hcnt, lcnt;
+ u32 reg, comp_param1;
+ u32 sda_falling_time, scl_falling_time;
+ int ret;
+
+ ret = i2c_dw_acquire_lock(dev);
+ if (ret)
+ return ret;
+
+ reg = dw_readl(dev, DW_IC_COMP_TYPE);
+ if (reg == ___constant_swab32(DW_IC_COMP_TYPE_VALUE)) {
+ /* Configure register endianness access */
+ dev->accessor_flags |= ACCESS_SWAP;
+ } else if (reg == (DW_IC_COMP_TYPE_VALUE & 0x0000ffff)) {
+ /* Configure register access mode 16bit */
+ dev->accessor_flags |= ACCESS_16BIT;
+ } else if (reg != DW_IC_COMP_TYPE_VALUE) {
+ dev_err(dev->dev, "Unknown Synopsys component type: "
+ "0x%08x\n", reg);
+ i2c_dw_release_lock(dev);
+ return -ENODEV;
+ }
+
+ comp_param1 = dw_readl(dev, DW_IC_COMP_PARAM_1);
+
+ /* Disable the adapter */
+ __i2c_dw_enable_and_wait(dev, false);
+
+ /* set standard and fast speed deviders for high/low periods */
+ sda_falling_time = dev->sda_falling_time ?: 300; /* ns */
+ scl_falling_time = dev->scl_falling_time ?: 300; /* ns */
+
+ /* Set SCL timing parameters for standard-mode */
+ if (dev->ss_hcnt && dev->ss_lcnt) {
+ hcnt = dev->ss_hcnt;
+ lcnt = dev->ss_lcnt;
+ } else {
+ hcnt = i2c_dw_scl_hcnt(i2c_dw_clk_rate(dev),
+ 4000, /* tHD;STA = tHIGH = 4.0 us */
+ sda_falling_time,
+ 0, /* 0: DW default, 1: Ideal */
+ 0); /* No offset */
+ lcnt = i2c_dw_scl_lcnt(i2c_dw_clk_rate(dev),
+ 4700, /* tLOW = 4.7 us */
+ scl_falling_time,
+ 0); /* No offset */
+ }
+ dw_writel(dev, hcnt, DW_IC_SS_SCL_HCNT);
+ dw_writel(dev, lcnt, DW_IC_SS_SCL_LCNT);
+ dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
+
+ /* Set SCL timing parameters for fast-mode or fast-mode plus */
+ if ((dev->clk_freq == 1000000) && dev->fp_hcnt && dev->fp_lcnt) {
+ hcnt = dev->fp_hcnt;
+ lcnt = dev->fp_lcnt;
+ } else if (dev->fs_hcnt && dev->fs_lcnt) {
+ hcnt = dev->fs_hcnt;
+ lcnt = dev->fs_lcnt;
+ } else {
+ hcnt = i2c_dw_scl_hcnt(i2c_dw_clk_rate(dev),
+ 600, /* tHD;STA = tHIGH = 0.6 us */
+ sda_falling_time,
+ 0, /* 0: DW default, 1: Ideal */
+ 0); /* No offset */
+ lcnt = i2c_dw_scl_lcnt(i2c_dw_clk_rate(dev),
+ 1300, /* tLOW = 1.3 us */
+ scl_falling_time,
+ 0); /* No offset */
+ }
+ dw_writel(dev, hcnt, DW_IC_FS_SCL_HCNT);
+ dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT);
+ dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
+
+ if ((dev->slave_cfg & DW_IC_CON_SPEED_MASK) ==
+ DW_IC_CON_SPEED_HIGH) {
+ if ((comp_param1 & DW_IC_COMP_PARAM_1_SPEED_MODE_MASK)
+ != DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH) {
+ dev_err(dev->dev, "High Speed not supported!\n");
+ dev->slave_cfg &= ~DW_IC_CON_SPEED_MASK;
+ dev->slave_cfg |= DW_IC_CON_SPEED_FAST;
+ } else if (dev->hs_hcnt && dev->hs_lcnt) {
+ hcnt = dev->hs_hcnt;
+ lcnt = dev->hs_lcnt;
+ dw_writel(dev, hcnt, DW_IC_HS_SCL_HCNT);
+ dw_writel(dev, lcnt, DW_IC_HS_SCL_LCNT);
+ dev_dbg(dev->dev, "HighSpeed-mode HCNT:LCNT = %d:%d\n",
+ hcnt, lcnt);
+ }
+ }
+
+ /* Configure SDA Hold Time if required */
+ reg = dw_readl(dev, DW_IC_COMP_VERSION);
+ reg = dw_readl(dev, DW_IC_COMP_VERSION);
+ if (reg >= DW_IC_SDA_HOLD_MIN_VERS) {
+ if (!dev->sda_hold_time) {
+ /* Keep previous hold time setting if no one set it */
+ dev->sda_hold_time = dw_readl(dev, DW_IC_SDA_HOLD);
+ }
+ /*
+ * Workaround for avoiding TX arbitration lost in case I2C
+ * slave pulls SDA down "too quickly" after falling egde of
+ * SCL by enabling non-zero SDA RX hold. Specification says it
+ * extends incoming SDA low to high transition while SCL is
+ * high but it apprears to help also above issue.
+ */
+ if (!(dev->sda_hold_time & DW_IC_SDA_HOLD_RX_MASK))
+ dev->sda_hold_time |= 1 << DW_IC_SDA_HOLD_RX_SHIFT;
+ dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD);
+ } else {
+ dev_warn(dev->dev,
+ "Hardware too old to adjust SDA hold time.\n");
+ }
+
+ i2c_dw_configure_fifo_slave(dev);
+ i2c_dw_release_lock(dev);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(i2c_dw_init_slave);
+
+int i2c_dw_reg_slave(struct i2c_client *slave)
+{
+ struct dw_i2c_dev *dev = i2c_get_adapdata(slave->adapter);
+
+ if (dev->slave)
+ return -EBUSY;
+ if (slave->flags & I2C_CLIENT_TEN)
+ return -EAFNOSUPPORT;
+ /* set slave address in the IC_SAR register,
+ * the address to which the DW_apb_i2c responds */
+
+ __i2c_dw_enable(dev, false);
+ dw_writel(dev, slave->addr, DW_IC_SAR);
+ dev->slave = slave;
+
+ __i2c_dw_enable(dev, true);
+
+ dev->cmd_err = 0;
+ dev->msg_write_idx = 0;
+ dev->msg_read_idx = 0;
+ dev->msg_err = 0;
+ dev->status = STATUS_IDLE;
+ dev->abort_source = 0;
+ dev->rx_outstanding = 0;
+
+ return 0;
+}
+
+static int i2c_dw_unreg_slave(struct i2c_client *slave)
+{
+ struct dw_i2c_dev *dev = i2c_get_adapdata(slave->adapter);
+
+ i2c_dw_disable_int_slave(dev);
+ i2c_dw_disable_slave(dev);
+ dev->slave = NULL;
+
+ return 0;
+}
+
+static u32 i2c_dw_read_clear_intrbits_slave(struct dw_i2c_dev *dev)
+{
+ u32 stat;
+
+ /*
+ * The IC_INTR_STAT register just indicates "enabled" interrupts.
+ * Ths unmasked raw version of interrupt status bits are available
+ * in the IC_RAW_INTR_STAT register.
+ *
+ * That is,
+ * stat = dw_readl(IC_INTR_STAT);
+ * equals to,
+ * stat = dw_readl(IC_RAW_INTR_STAT) & dw_readl(IC_INTR_MASK);
+ *
+ * The raw version might be useful for debugging purposes.
+ */
+ stat = dw_readl(dev, DW_IC_INTR_STAT);
+
+ /*
+ * Do not use the IC_CLR_INTR register to clear interrupts, or
+ * you'll miss some interrupts, triggered during the period from
+ * dw_readl(IC_INTR_STAT) to dw_readl(IC_CLR_INTR).
+ *
+ * Instead, use the separately-prepared IC_CLR_* registers.
+ */
+ if (stat & DW_IC_INTR_RX_UNDER)
+ dw_readl(dev, DW_IC_CLR_RX_UNDER);
+ if (stat & DW_IC_INTR_RX_OVER)
+ dw_readl(dev, DW_IC_CLR_RX_OVER);
+ if (stat & DW_IC_INTR_TX_OVER)
+ dw_readl(dev, DW_IC_CLR_TX_OVER);
+ if (stat & DW_IC_INTR_TX_ABRT) {
+ /*
+ * The IC_TX_ABRT_SOURCE register is cleared whenever
+ * the IC_CLR_TX_ABRT is read. Preserve it beforehand.
+ */
+ dev->abort_source = dw_readl(dev, DW_IC_TX_ABRT_SOURCE);
+ dw_readl(dev, DW_IC_CLR_TX_ABRT);
+ }
+ if (stat & DW_IC_INTR_RX_DONE)
+ dw_readl(dev, DW_IC_CLR_RX_DONE);
+ if (stat & DW_IC_INTR_ACTIVITY)
+ dw_readl(dev, DW_IC_CLR_ACTIVITY);
+ if (stat & DW_IC_INTR_STOP_DET)
+ dw_readl(dev, DW_IC_CLR_STOP_DET);
+ if (stat & DW_IC_INTR_START_DET)
+ dw_readl(dev, DW_IC_CLR_START_DET);
+ if (stat & DW_IC_INTR_GEN_CALL)
+ dw_readl(dev, DW_IC_CLR_GEN_CALL);
+
+ return stat;
+}
+
+/*
+ * Interrupt service routine. This gets called whenever an I2C interrupt
+ * occurs.
+ */
+
+static bool i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev)
+{
+ u32 raw_stat, stat, enabled;
+ u8 val, slave_activity;
+
+ stat = dw_readl(dev, DW_IC_INTR_STAT);
+ enabled = dw_readl(dev, DW_IC_ENABLE);
+ raw_stat = dw_readl(dev, DW_IC_RAW_INTR_STAT);
+ slave_activity = ((dw_readl(dev, DW_IC_STATUS) &
+ DW_IC_STATUS_SLAVE_ACTIVITY)>>6);
+
+ dev_dbg(dev->dev,
+ "%s: %#x SLAVE_ACTV=%#x : RAW_INTR_STAT=%#x : INTR_STAT=%#x\n",
+ __func__, enabled, slave_activity, raw_stat, stat);
+
+ if (stat & DW_IC_INTR_START_DET)
+ dw_readl(dev, DW_IC_CLR_START_DET);
+ if (stat & DW_IC_INTR_ACTIVITY)
+ dw_readl(dev, DW_IC_CLR_ACTIVITY);
+ if (stat & DW_IC_INTR_RX_OVER)
+ dw_readl(dev, DW_IC_CLR_RX_OVER);
+ if ((stat & DW_IC_INTR_RX_FULL) && (stat & DW_IC_INTR_STOP_DET))
+ i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_REQUESTED, &val);
+
+ if (slave_activity) {
+ if (stat & DW_IC_INTR_RD_REQ) {
+ if (stat & DW_IC_INTR_RX_FULL) {
+ val = dw_readl(dev, DW_IC_DATA_CMD);
+ if (!i2c_slave_event(dev->slave,
+ I2C_SLAVE_WRITE_RECEIVED, &val)) {
+ dev_dbg(dev->dev, "Byte %X acked! ",
+ val);
+ }
+ dw_readl(dev, DW_IC_CLR_RD_REQ);
+ stat = i2c_dw_read_clear_intrbits_slave(dev);
+ } else {
+ dw_readl(dev, DW_IC_CLR_RD_REQ);
+ dw_readl(dev, DW_IC_CLR_RX_UNDER);
+ stat = i2c_dw_read_clear_intrbits_slave(dev);
+ }
+ if (!i2c_slave_event(dev->slave,
+ I2C_SLAVE_READ_REQUESTED, &val))
+ dw_writel(dev, val, DW_IC_DATA_CMD);
+ }
+ }
+
+ if (stat & DW_IC_INTR_RX_DONE) {
+ if (!i2c_slave_event(dev->slave, I2C_SLAVE_READ_PROCESSED,
+ &val))
+ dw_readl(dev, DW_IC_CLR_RX_DONE);
+
+ i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &val);
+ stat = i2c_dw_read_clear_intrbits_slave(dev);
+ return true;
+ }
+
+ if (stat & DW_IC_INTR_RX_FULL) {
+ val = dw_readl(dev, DW_IC_DATA_CMD);
+ if (!i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_RECEIVED,
+ &val))
+ dev_dbg(dev->dev, "Byte %X acked! ", val);
+ } else {
+ i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &val);
+ stat = i2c_dw_read_clear_intrbits_slave(dev);
+ }
+
+ if (stat & DW_IC_INTR_TX_OVER) {
+ dw_readl(dev, DW_IC_CLR_TX_OVER);
+ return true;
+ }
+ return true;
+}
+
+static irqreturn_t i2c_dw_isr_slave(int this_irq, void *dev_id)
+{
+ struct dw_i2c_dev *dev = dev_id;
+ u32 stat, enabled, mode;
+
+ enabled = dw_readl(dev, DW_IC_ENABLE);
+ mode = dw_readl(dev, DW_IC_CON);
+ stat = dw_readl(dev, DW_IC_RAW_INTR_STAT);
+
+ dev_dbg(dev->dev, "%s: enabled=%#x stat=%#x\n", __func__, enabled,
+ stat);
+ if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY))
+ return IRQ_NONE;
+
+ stat = i2c_dw_read_clear_intrbits_slave(dev);
+ if (!i2c_dw_irq_handler_slave(dev))
+ return IRQ_NONE;
+
+ complete(&dev->cmd_complete);
+ return IRQ_HANDLED;
+}
+
+static struct i2c_algorithm i2c_dw_algo = {
+ .functionality = i2c_dw_func,
+ .reg_slave = i2c_dw_reg_slave,
+ .unreg_slave = i2c_dw_unreg_slave,
+};
+
+void i2c_dw_disable_slave(struct dw_i2c_dev *dev)
+{
+ /* Disable controller */
+ __i2c_dw_enable_and_wait(dev, false);
+
+ /* Disable all interupts */
+ dw_writel(dev, 0, DW_IC_INTR_MASK);
+ dw_readl(dev, DW_IC_CLR_INTR);
+}
+EXPORT_SYMBOL_GPL(i2c_dw_disable_slave);
+
+void i2c_dw_disable_int_slave(struct dw_i2c_dev *dev)
+{
+ dw_writel(dev, 0, DW_IC_INTR_MASK);
+}
+EXPORT_SYMBOL_GPL(i2c_dw_disable_int_slave);
+
+u32 i2c_dw_read_comp_param_slave(struct dw_i2c_dev *dev)
+{
+ return dw_readl(dev, DW_IC_COMP_PARAM_1);
+}
+EXPORT_SYMBOL_GPL(i2c_dw_read_comp_param_slave);
+
+int i2c_dw_probe_slave(struct dw_i2c_dev *dev)
+{
+ struct i2c_adapter *adap = &dev->adapter;
+ int r;
+
+ init_completion(&dev->cmd_complete);
+
+ r = i2c_dw_init_slave(dev);
+ if (r)
+ return r;
+
+ r = i2c_dw_acquire_lock(dev);
+ if (r)
+ return r;
+
+ i2c_dw_release_lock(dev);
+ snprintf(adap->name, sizeof(adap->name),
+ "Synopsys DesignWare I2C Slave adapter");
+ adap->retries = 3;
+ adap->algo = &i2c_dw_algo;
+ adap->dev.parent = dev->dev;
+ i2c_set_adapdata(adap, dev);
+
+ r = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr_slave,
+ IRQF_SHARED | IRQF_COND_SUSPEND,
+ dev_name(dev->dev), dev);
+ if (r) {
+ dev_err(dev->dev, "failure requesting irq %i: %d\n",
+ dev->irq, r);
+ return r;
+ }
+ /*
+ * Increment PM usage count during adapter registration in order to
+ * avoid possible spurious runtime suspend when adapter device is
+ * registered to the device core and immediate resume in case bus has
+ * registered I2C slaves that do I2C transfers in their probe.
+ */
+ pm_runtime_get_noresume(dev->dev);
+ r = i2c_add_numbered_adapter(adap);
+ if (r)
+ dev_err(dev->dev, "failure adding adapter: %d\n", r);
+ pm_runtime_put_noidle(dev->dev);
+
+ return r;
+}
+EXPORT_SYMBOL_GPL(i2c_dw_probe_slave);
+
+MODULE_DESCRIPTION("Synopsys DesignWare I2C bus slave adapter");
+MODULE_LICENSE("GPL");
--
2.10.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH v3 4/5] i2c: designware: Add slave mode as separated driver
2016-11-18 11:19 ` Luis Oliveira
(?)
@ 2016-11-18 12:49 ` Andy Shevchenko
-1 siblings, 0 replies; 19+ messages in thread
From: Andy Shevchenko @ 2016-11-18 12:49 UTC (permalink / raw)
To: Luis Oliveira, wsa, robh+dt, mark.rutland, jarkko.nikula,
mika.westerberg, linux-i2c, devicetree, linux-kernel
Cc: Ramiro.Oliveira, Joao.Pinto, CARLOS.PALMINHA
On Fri, 2016-11-18 at 11:19 +0000, Luis Oliveira wrote:
> - Slave mode selected by compatibility string in platform module
> - Changes in Makefile to compile i2c-designware-core with slave
> functions
> --- a/drivers/i2c/busses/i2c-designware-platdrv.c
> +++ b/drivers/i2c/busses/i2c-designware-platdrv.c
> @@ -160,6 +160,30 @@ static void i2c_dw_configure_master(struct
> platform_device *pdev)
> }
> }
>
> +static void i2c_dw_configure_slave(struct platform_device *pdev)
> +{
> + struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
> +
> + dev->slave_cfg = DW_IC_CON_RX_FIFO_FULL_HLD_CTRL |
> + DW_IC_CON_RESTART_EN |
> DW_IC_CON_STOP_DET_IFADDRESSED |
> + DW_IC_CON_SPEED_FAST;
> +
> + dev->functionality |= I2C_FUNC_SLAVE;
> + dev->functionality &= ~I2C_FUNC_10BIT_ADDR;
> + dev_info(&pdev->dev, "I am registed as a I2C Slave!\n");
Not for production.
> @@ -244,7 +268,11 @@ static int dw_i2c_plat_probe(struct
> platform_device *pdev)
> I2C_FUNC_SMBUS_WORD_DATA |
> I2C_FUNC_SMBUS_I2C_BLOCK;
>
> - i2c_dw_configure_master(pdev);
> + if (of_device_is_compatible(pdev->dev.of_node,
> + "snps,designware-i2c-slave"))
No.
We don't use of_property_*() anymore in general. Instead find
appropriate device_property_*() one. Besides, remind about comment
regarding to the property itself.
> + i2c_dw_configure_slave(pdev);
> + else
> + i2c_dw_configure_master(pdev);
I would go then switch case here, where third variant prints an error
that mode X doesn't supported / invalid and bails out.
> @@ -257,7 +285,13 @@ static int dw_i2c_plat_probe(struct
> platform_device *pdev)
> }
>
> if (!dev->tx_fifo_depth) {
> - u32 param1 = i2c_dw_read_comp_param(dev);
> + u32 param1;
> +
> + if (of_device_is_compatible(pdev->dev.of_node,
> + "snps,designware-i2c-slave"))
Cache it in local variable if needed.
> + param1 = i2c_dw_read_comp_param_slave(dev);
> + else
> + param1 = i2c_dw_read_comp_param(dev);
Shouldn't it have a _master suffix?
>
> dev->tx_fifo_depth = ((param1 >> 16) & 0xff) + 1;
> dev->rx_fifo_depth = ((param1 >> 8) & 0xff) + 1;
> @@ -278,8 +312,12 @@ static int dw_i2c_plat_probe(struct
> platform_device *pdev)
> pm_runtime_set_active(&pdev->dev);
> pm_runtime_enable(&pdev->dev);
> }
> + if (of_device_is_compatible(pdev->dev.of_node,
> + "snps,designware-i2c-slave"))
> + r = i2c_dw_probe_slave(dev);
> + else
> + r = i2c_dw_probe(dev);
Ditto.
> @@ -291,10 +329,13 @@ static int dw_i2c_plat_remove(struct
> platform_device *pdev)
> struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
>
> pm_runtime_get_sync(&pdev->dev);
> -
Doesn't belong to the patch.
> i2c_del_adapter(&dev->adapter);
>
> - i2c_dw_disable(dev);
> + if (of_device_is_compatible(pdev->dev.of_node,
> + "snps,designware-i2c-slave"))
> + i2c_dw_disable_slave(dev);
> + else
> + i2c_dw_disable(dev);
_master?
>
> pm_runtime_dont_use_autosuspend(&pdev->dev);
> pm_runtime_put_sync(&pdev->dev);
> @@ -307,6 +348,9 @@ static int dw_i2c_plat_remove(struct
> platform_device *pdev)
> #ifdef CONFIG_OF
> static const struct of_device_id dw_i2c_of_match[] = {
> { .compatible = "snps,designware-i2c", },
> +#ifndef CONFIG_ACPI
No, no, no.
> + { .compatible = "snps,designware-i2c-slave", },
> +#endif
> {},
> };
> MODULE_DEVICE_TABLE(of, dw_i2c_of_match);
> @@ -334,7 +378,11 @@ static int dw_i2c_plat_suspend(struct device
> *dev)
> struct platform_device *pdev = to_platform_device(dev);
> struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
>
> - i2c_dw_disable(i_dev);
> + if (of_device_is_compatible(pdev->dev.of_node,
> + "snps,designware-i2c-slave"))
> + i2c_dw_disable_slave(i_dev);
> + else
> + i2c_dw_disable(i_dev);
Same comments as above.
> i2c_dw_plat_prepare_clk(i_dev, false);
>
> return 0;
> @@ -347,8 +395,13 @@ static int dw_i2c_plat_resume(struct device *dev)
>
> i2c_dw_plat_prepare_clk(i_dev, true);
>
> - if (!i_dev->pm_runtime_disabled)
> - i2c_dw_init(i_dev);
> + if (!i_dev->pm_runtime_disabled) {
> + if (of_device_is_compatible(pdev->dev.of_node,
> + "snps,designware-i2c-slave"))
> + i2c_dw_init_slave(i_dev);
> + else
> + i2c_dw_init(i_dev);
Ditto.
> --- /dev/null
> +++ b/drivers/i2c/busses/i2c-designware-slave.c
Slave...
> @@ -0,0 +1,445 @@
> +/*
> + * Synopsys DesignWare I2C adapter driver (master only).
Master...
> + *
> + * Based on the TI DAVINCI I2C adapter driver.
> + *
+ * Copyright (C) 2006 Texas Instruments.
> + * Copyright (C) 2007 MontaVista Software Inc.
> + * Copyright (C) 2009 Provigent Ltd.
Are you sure about these lines?
> +#include <linux/export.h>
> +#include <linux/errno.h>
> +#include <linux/err.h>
> +#include <linux/i2c.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/delay.h>
> +#include <linux/module.h>
+ empty line.
> +#include "i2c-designware-core.h"
> +
> +/**
> + * i2c_dw_init_slave() - initialize the designware i2c slave hardware
> + * @dev: device private data
> + *
> + * This functions configures and enables the I2C.
> + * This function is called during I2C init function, and in case of
> timeout at
> + * run time.
> + */
> +int i2c_dw_init_slave(struct dw_i2c_dev *dev)
> +{
> + u32 hcnt, lcnt;
> + u32 reg, comp_param1;
> + u32 sda_falling_time, scl_falling_time;
Reversed tree, pls.
> + int ret;
> +
> + ret = i2c_dw_acquire_lock(dev);
> + if (ret)
> + return ret;
> +
> + reg = dw_readl(dev, DW_IC_COMP_TYPE);
> + if (reg == ___constant_swab32(DW_IC_COMP_TYPE_VALUE)) {
> + /* Configure register endianness access */
> + dev->accessor_flags |= ACCESS_SWAP;
> + } else if (reg == (DW_IC_COMP_TYPE_VALUE & 0x0000ffff)) {
> + /* Configure register access mode 16bit */
> + dev->accessor_flags |= ACCESS_16BIT;
> + } else if (reg != DW_IC_COMP_TYPE_VALUE) {
>
> + dev_err(dev->dev, "Unknown Synopsys component type: "
> + "0x%08x\n", reg);
Don't break literals.
Choose one that fits.
dev_err(dev->dev, "Unknown Synopsys component type: "0x%08x\n",
reg);
dev_err(dev->dev,
"Unknown Synopsys component type: "0x%08x\n", reg);
dev_err(dev->dev,
"Unknown Synopsys component type: "0x%08x\n",
reg);
> + i2c_dw_release_lock(dev);
> + return -ENODEV;
> + }
> +
> + comp_param1 = dw_readl(dev, DW_IC_COMP_PARAM_1);
> +
>
> + /* Disable the adapter */
Useless.
> + __i2c_dw_enable_and_wait(dev, false);
> +
> + /* set standard and fast speed deviders for high/low periods
> */
Capital letter!
> + sda_falling_time = dev->sda_falling_time ?: 300; /* ns */
> + scl_falling_time = dev->scl_falling_time ?: 300; /* ns */
> +
> + /* Set SCL timing parameters for standard-mode */
> + if (dev->ss_hcnt && dev->ss_lcnt) {
> + hcnt = dev->ss_hcnt;
> + lcnt = dev->ss_lcnt;
> + } else {
> + hcnt = i2c_dw_scl_hcnt(i2c_dw_clk_rate(dev),
> + 4000, /* tHD;STA =
> tHIGH = 4.0 us */
> + sda_falling_time,
> + 0, /* 0: DW default,
> 1: Ideal */
> + 0); /* No offset */
> + lcnt = i2c_dw_scl_lcnt(i2c_dw_clk_rate(dev),
> + 4700, /* tLOW = 4.7 us
> */
> + scl_falling_time,
> + 0); /* No offset */
> + }
> + dw_writel(dev, hcnt, DW_IC_SS_SCL_HCNT);
> + dw_writel(dev, lcnt, DW_IC_SS_SCL_LCNT);
> + dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n", hcnt,
> lcnt);
> +
> + /* Set SCL timing parameters for fast-mode or fast-mode plus
> */
> + if ((dev->clk_freq == 1000000) && dev->fp_hcnt && dev-
> >fp_lcnt) {
> + hcnt = dev->fp_hcnt;
> + lcnt = dev->fp_lcnt;
> + } else if (dev->fs_hcnt && dev->fs_lcnt) {
> + hcnt = dev->fs_hcnt;
> + lcnt = dev->fs_lcnt;
> + } else {
> + hcnt = i2c_dw_scl_hcnt(i2c_dw_clk_rate(dev),
> + 600, /* tHD;STA =
> tHIGH = 0.6 us */
> + sda_falling_time,
> + 0, /* 0: DW default,
> 1: Ideal */
> + 0); /* No offset */
> + lcnt = i2c_dw_scl_lcnt(i2c_dw_clk_rate(dev),
> + 1300, /* tLOW = 1.3 us
> */
> + scl_falling_time,
> + 0); /* No offset */
> + }
> + dw_writel(dev, hcnt, DW_IC_FS_SCL_HCNT);
> + dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT);
> + dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt,
> lcnt);
> +
> + if ((dev->slave_cfg & DW_IC_CON_SPEED_MASK) ==
> + DW_IC_CON_SPEED_HIGH) {
> + if ((comp_param1 &
> DW_IC_COMP_PARAM_1_SPEED_MODE_MASK)
> + != DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH) {
> + dev_err(dev->dev, "High Speed not
> supported!\n");
> + dev->slave_cfg &= ~DW_IC_CON_SPEED_MASK;
> + dev->slave_cfg |= DW_IC_CON_SPEED_FAST;
> + } else if (dev->hs_hcnt && dev->hs_lcnt) {
> + hcnt = dev->hs_hcnt;
> + lcnt = dev->hs_lcnt;
> + dw_writel(dev, hcnt, DW_IC_HS_SCL_HCNT);
> + dw_writel(dev, lcnt, DW_IC_HS_SCL_LCNT);
> + dev_dbg(dev->dev, "HighSpeed-mode HCNT:LCNT =
> %d:%d\n",
> + hcnt, lcnt);
> + }
> + }
> +
> + /* Configure SDA Hold Time if required */
> + reg = dw_readl(dev, DW_IC_COMP_VERSION);
> + reg = dw_readl(dev, DW_IC_COMP_VERSION);
> + if (reg >= DW_IC_SDA_HOLD_MIN_VERS) {
> + if (!dev->sda_hold_time) {
> + /* Keep previous hold time setting if no one
> set it */
> + dev->sda_hold_time = dw_readl(dev,
> DW_IC_SDA_HOLD);
> + }
> + /*
> + * Workaround for avoiding TX arbitration lost in
> case I2C
> + * slave pulls SDA down "too quickly" after falling
> egde of
> + * SCL by enabling non-zero SDA RX hold.
> Specification says it
> + * extends incoming SDA low to high transition while
> SCL is
> + * high but it apprears to help also above issue.
> + */
> + if (!(dev->sda_hold_time & DW_IC_SDA_HOLD_RX_MASK))
> + dev->sda_hold_time |= 1 <<
> DW_IC_SDA_HOLD_RX_SHIFT;
> + dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD);
> + } else {
> + dev_warn(dev->dev,
> + "Hardware too old to adjust SDA hold
> time.\n");
> + }
> +
> + i2c_dw_configure_fifo_slave(dev);
> + i2c_dw_release_lock(dev);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(i2c_dw_init_slave);
So, don't make a noise in exported name space. When we need two sets of
functions make an ops structure and assign it where appropriate.
--
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 4/5] i2c: designware: Add slave mode as separated driver
@ 2016-11-18 22:27 ` kbuild test robot
0 siblings, 0 replies; 19+ messages in thread
From: kbuild test robot @ 2016-11-18 22:27 UTC (permalink / raw)
To: Luis Oliveira
Cc: kbuild-all, wsa, robh+dt, mark.rutland, jarkko.nikula,
andriy.shevchenko, mika.westerberg, linux-i2c, devicetree,
linux-kernel, Luis.Oliveira, Ramiro.Oliveira, Joao.Pinto,
CARLOS.PALMINHA
[-- Attachment #1: Type: text/plain, Size: 6345 bytes --]
Hi Luis,
[auto build test ERROR on v4.9-rc5]
[also build test ERROR on next-20161117]
[cannot apply to wsa/i2c/for-next]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Luis-Oliveira/i2c-designware-Add-slave-support/20161118-193236
config: x86_64-randconfig-s4-11190538 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64
All error/warnings (new ones prefixed by >>):
drivers/i2c/busses/i2c-designware-slave.c: In function 'i2c_dw_irq_handler_slave':
>> drivers/i2c/busses/i2c-designware-slave.c:295:3: error: implicit declaration of function 'i2c_slave_event' [-Werror=implicit-function-declaration]
i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_REQUESTED, &val);
^~~~~~~~~~~~~~~
>> drivers/i2c/busses/i2c-designware-slave.c:295:31: error: 'I2C_SLAVE_WRITE_REQUESTED' undeclared (first use in this function)
i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_REQUESTED, &val);
^~~~~~~~~~~~~~~~~~~~~~~~~
drivers/i2c/busses/i2c-designware-slave.c:295:31: note: each undeclared identifier is reported only once for each function it appears in
>> drivers/i2c/busses/i2c-designware-slave.c:302:6: error: 'I2C_SLAVE_WRITE_RECEIVED' undeclared (first use in this function)
I2C_SLAVE_WRITE_RECEIVED, &val)) {
^~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/i2c/busses/i2c-designware-slave.c:314:7: error: 'I2C_SLAVE_READ_REQUESTED' undeclared (first use in this function)
I2C_SLAVE_READ_REQUESTED, &val))
^~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/i2c/busses/i2c-designware-slave.c:320:36: error: 'I2C_SLAVE_READ_PROCESSED' undeclared (first use in this function)
if (!i2c_slave_event(dev->slave, I2C_SLAVE_READ_PROCESSED,
^~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/i2c/busses/i2c-designware-slave.c:324:31: error: 'I2C_SLAVE_STOP' undeclared (first use in this function)
i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &val);
^~~~~~~~~~~~~~
drivers/i2c/busses/i2c-designware-slave.c: At top level:
>> drivers/i2c/busses/i2c-designware-slave.c:370:2: error: unknown field 'reg_slave' specified in initializer
.reg_slave = i2c_dw_reg_slave,
^
>> drivers/i2c/busses/i2c-designware-slave.c:370:15: warning: excess elements in struct initializer
.reg_slave = i2c_dw_reg_slave,
^~~~~~~~~~~~~~~~
drivers/i2c/busses/i2c-designware-slave.c:370:15: note: (near initialization for 'i2c_dw_algo')
>> drivers/i2c/busses/i2c-designware-slave.c:371:2: error: unknown field 'unreg_slave' specified in initializer
.unreg_slave = i2c_dw_unreg_slave,
^
drivers/i2c/busses/i2c-designware-slave.c:371:17: warning: excess elements in struct initializer
.unreg_slave = i2c_dw_unreg_slave,
^~~~~~~~~~~~~~~~~~
drivers/i2c/busses/i2c-designware-slave.c:371:17: note: (near initialization for 'i2c_dw_algo')
cc1: some warnings being treated as errors
vim +/i2c_slave_event +295 drivers/i2c/busses/i2c-designware-slave.c
289 dw_readl(dev, DW_IC_CLR_START_DET);
290 if (stat & DW_IC_INTR_ACTIVITY)
291 dw_readl(dev, DW_IC_CLR_ACTIVITY);
292 if (stat & DW_IC_INTR_RX_OVER)
293 dw_readl(dev, DW_IC_CLR_RX_OVER);
294 if ((stat & DW_IC_INTR_RX_FULL) && (stat & DW_IC_INTR_STOP_DET))
> 295 i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_REQUESTED, &val);
296
297 if (slave_activity) {
298 if (stat & DW_IC_INTR_RD_REQ) {
299 if (stat & DW_IC_INTR_RX_FULL) {
300 val = dw_readl(dev, DW_IC_DATA_CMD);
301 if (!i2c_slave_event(dev->slave,
> 302 I2C_SLAVE_WRITE_RECEIVED, &val)) {
303 dev_dbg(dev->dev, "Byte %X acked! ",
304 val);
305 }
306 dw_readl(dev, DW_IC_CLR_RD_REQ);
307 stat = i2c_dw_read_clear_intrbits_slave(dev);
308 } else {
309 dw_readl(dev, DW_IC_CLR_RD_REQ);
310 dw_readl(dev, DW_IC_CLR_RX_UNDER);
311 stat = i2c_dw_read_clear_intrbits_slave(dev);
312 }
313 if (!i2c_slave_event(dev->slave,
> 314 I2C_SLAVE_READ_REQUESTED, &val))
315 dw_writel(dev, val, DW_IC_DATA_CMD);
316 }
317 }
318
319 if (stat & DW_IC_INTR_RX_DONE) {
> 320 if (!i2c_slave_event(dev->slave, I2C_SLAVE_READ_PROCESSED,
321 &val))
322 dw_readl(dev, DW_IC_CLR_RX_DONE);
323
> 324 i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &val);
325 stat = i2c_dw_read_clear_intrbits_slave(dev);
326 return true;
327 }
328
329 if (stat & DW_IC_INTR_RX_FULL) {
330 val = dw_readl(dev, DW_IC_DATA_CMD);
331 if (!i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_RECEIVED,
332 &val))
333 dev_dbg(dev->dev, "Byte %X acked! ", val);
334 } else {
335 i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &val);
336 stat = i2c_dw_read_clear_intrbits_slave(dev);
337 }
338
339 if (stat & DW_IC_INTR_TX_OVER) {
340 dw_readl(dev, DW_IC_CLR_TX_OVER);
341 return true;
342 }
343 return true;
344 }
345
346 static irqreturn_t i2c_dw_isr_slave(int this_irq, void *dev_id)
347 {
348 struct dw_i2c_dev *dev = dev_id;
349 u32 stat, enabled, mode;
350
351 enabled = dw_readl(dev, DW_IC_ENABLE);
352 mode = dw_readl(dev, DW_IC_CON);
353 stat = dw_readl(dev, DW_IC_RAW_INTR_STAT);
354
355 dev_dbg(dev->dev, "%s: enabled=%#x stat=%#x\n", __func__, enabled,
356 stat);
357 if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY))
358 return IRQ_NONE;
359
360 stat = i2c_dw_read_clear_intrbits_slave(dev);
361 if (!i2c_dw_irq_handler_slave(dev))
362 return IRQ_NONE;
363
364 complete(&dev->cmd_complete);
365 return IRQ_HANDLED;
366 }
367
368 static struct i2c_algorithm i2c_dw_algo = {
369 .functionality = i2c_dw_func,
> 370 .reg_slave = i2c_dw_reg_slave,
> 371 .unreg_slave = i2c_dw_unreg_slave,
372 };
373
374 void i2c_dw_disable_slave(struct dw_i2c_dev *dev)
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 25799 bytes --]
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 4/5] i2c: designware: Add slave mode as separated driver
@ 2016-11-18 22:27 ` kbuild test robot
0 siblings, 0 replies; 19+ messages in thread
From: kbuild test robot @ 2016-11-18 22:27 UTC (permalink / raw)
Cc: kbuild-all-JC7UmRfGjtg, wsa-z923LK4zBo2bacvFa/9K2g,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
jarkko.nikula-VuQAYsv1563Yd54FQh9/CA,
andriy.shevchenko-VuQAYsv1563Yd54FQh9/CA,
mika.westerberg-VuQAYsv1563Yd54FQh9/CA,
linux-i2c-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
Luis.Oliveira-HKixBCOQz3hWk0Htik3J/w,
Ramiro.Oliveira-HKixBCOQz3hWk0Htik3J/w,
Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
CARLOS.PALMINHA-HKixBCOQz3hWk0Htik3J/w
[-- Attachment #1: Type: text/plain, Size: 6345 bytes --]
Hi Luis,
[auto build test ERROR on v4.9-rc5]
[also build test ERROR on next-20161117]
[cannot apply to wsa/i2c/for-next]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Luis-Oliveira/i2c-designware-Add-slave-support/20161118-193236
config: x86_64-randconfig-s4-11190538 (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64
All error/warnings (new ones prefixed by >>):
drivers/i2c/busses/i2c-designware-slave.c: In function 'i2c_dw_irq_handler_slave':
>> drivers/i2c/busses/i2c-designware-slave.c:295:3: error: implicit declaration of function 'i2c_slave_event' [-Werror=implicit-function-declaration]
i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_REQUESTED, &val);
^~~~~~~~~~~~~~~
>> drivers/i2c/busses/i2c-designware-slave.c:295:31: error: 'I2C_SLAVE_WRITE_REQUESTED' undeclared (first use in this function)
i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_REQUESTED, &val);
^~~~~~~~~~~~~~~~~~~~~~~~~
drivers/i2c/busses/i2c-designware-slave.c:295:31: note: each undeclared identifier is reported only once for each function it appears in
>> drivers/i2c/busses/i2c-designware-slave.c:302:6: error: 'I2C_SLAVE_WRITE_RECEIVED' undeclared (first use in this function)
I2C_SLAVE_WRITE_RECEIVED, &val)) {
^~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/i2c/busses/i2c-designware-slave.c:314:7: error: 'I2C_SLAVE_READ_REQUESTED' undeclared (first use in this function)
I2C_SLAVE_READ_REQUESTED, &val))
^~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/i2c/busses/i2c-designware-slave.c:320:36: error: 'I2C_SLAVE_READ_PROCESSED' undeclared (first use in this function)
if (!i2c_slave_event(dev->slave, I2C_SLAVE_READ_PROCESSED,
^~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/i2c/busses/i2c-designware-slave.c:324:31: error: 'I2C_SLAVE_STOP' undeclared (first use in this function)
i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &val);
^~~~~~~~~~~~~~
drivers/i2c/busses/i2c-designware-slave.c: At top level:
>> drivers/i2c/busses/i2c-designware-slave.c:370:2: error: unknown field 'reg_slave' specified in initializer
.reg_slave = i2c_dw_reg_slave,
^
>> drivers/i2c/busses/i2c-designware-slave.c:370:15: warning: excess elements in struct initializer
.reg_slave = i2c_dw_reg_slave,
^~~~~~~~~~~~~~~~
drivers/i2c/busses/i2c-designware-slave.c:370:15: note: (near initialization for 'i2c_dw_algo')
>> drivers/i2c/busses/i2c-designware-slave.c:371:2: error: unknown field 'unreg_slave' specified in initializer
.unreg_slave = i2c_dw_unreg_slave,
^
drivers/i2c/busses/i2c-designware-slave.c:371:17: warning: excess elements in struct initializer
.unreg_slave = i2c_dw_unreg_slave,
^~~~~~~~~~~~~~~~~~
drivers/i2c/busses/i2c-designware-slave.c:371:17: note: (near initialization for 'i2c_dw_algo')
cc1: some warnings being treated as errors
vim +/i2c_slave_event +295 drivers/i2c/busses/i2c-designware-slave.c
289 dw_readl(dev, DW_IC_CLR_START_DET);
290 if (stat & DW_IC_INTR_ACTIVITY)
291 dw_readl(dev, DW_IC_CLR_ACTIVITY);
292 if (stat & DW_IC_INTR_RX_OVER)
293 dw_readl(dev, DW_IC_CLR_RX_OVER);
294 if ((stat & DW_IC_INTR_RX_FULL) && (stat & DW_IC_INTR_STOP_DET))
> 295 i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_REQUESTED, &val);
296
297 if (slave_activity) {
298 if (stat & DW_IC_INTR_RD_REQ) {
299 if (stat & DW_IC_INTR_RX_FULL) {
300 val = dw_readl(dev, DW_IC_DATA_CMD);
301 if (!i2c_slave_event(dev->slave,
> 302 I2C_SLAVE_WRITE_RECEIVED, &val)) {
303 dev_dbg(dev->dev, "Byte %X acked! ",
304 val);
305 }
306 dw_readl(dev, DW_IC_CLR_RD_REQ);
307 stat = i2c_dw_read_clear_intrbits_slave(dev);
308 } else {
309 dw_readl(dev, DW_IC_CLR_RD_REQ);
310 dw_readl(dev, DW_IC_CLR_RX_UNDER);
311 stat = i2c_dw_read_clear_intrbits_slave(dev);
312 }
313 if (!i2c_slave_event(dev->slave,
> 314 I2C_SLAVE_READ_REQUESTED, &val))
315 dw_writel(dev, val, DW_IC_DATA_CMD);
316 }
317 }
318
319 if (stat & DW_IC_INTR_RX_DONE) {
> 320 if (!i2c_slave_event(dev->slave, I2C_SLAVE_READ_PROCESSED,
321 &val))
322 dw_readl(dev, DW_IC_CLR_RX_DONE);
323
> 324 i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &val);
325 stat = i2c_dw_read_clear_intrbits_slave(dev);
326 return true;
327 }
328
329 if (stat & DW_IC_INTR_RX_FULL) {
330 val = dw_readl(dev, DW_IC_DATA_CMD);
331 if (!i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_RECEIVED,
332 &val))
333 dev_dbg(dev->dev, "Byte %X acked! ", val);
334 } else {
335 i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &val);
336 stat = i2c_dw_read_clear_intrbits_slave(dev);
337 }
338
339 if (stat & DW_IC_INTR_TX_OVER) {
340 dw_readl(dev, DW_IC_CLR_TX_OVER);
341 return true;
342 }
343 return true;
344 }
345
346 static irqreturn_t i2c_dw_isr_slave(int this_irq, void *dev_id)
347 {
348 struct dw_i2c_dev *dev = dev_id;
349 u32 stat, enabled, mode;
350
351 enabled = dw_readl(dev, DW_IC_ENABLE);
352 mode = dw_readl(dev, DW_IC_CON);
353 stat = dw_readl(dev, DW_IC_RAW_INTR_STAT);
354
355 dev_dbg(dev->dev, "%s: enabled=%#x stat=%#x\n", __func__, enabled,
356 stat);
357 if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY))
358 return IRQ_NONE;
359
360 stat = i2c_dw_read_clear_intrbits_slave(dev);
361 if (!i2c_dw_irq_handler_slave(dev))
362 return IRQ_NONE;
363
364 complete(&dev->cmd_complete);
365 return IRQ_HANDLED;
366 }
367
368 static struct i2c_algorithm i2c_dw_algo = {
369 .functionality = i2c_dw_func,
> 370 .reg_slave = i2c_dw_reg_slave,
> 371 .unreg_slave = i2c_dw_unreg_slave,
372 };
373
374 void i2c_dw_disable_slave(struct dw_i2c_dev *dev)
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 25799 bytes --]
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3 5/5] i2c: designware: Cleaning and commentary fixes
2016-11-18 11:19 [PATCH v3 0/5] i2c: designware: Add slave support Luis Oliveira
` (3 preceding siblings ...)
2016-11-18 11:19 ` Luis Oliveira
@ 2016-11-18 11:19 ` Luis Oliveira
4 siblings, 0 replies; 19+ messages in thread
From: Luis Oliveira @ 2016-11-18 11:19 UTC (permalink / raw)
To: wsa, robh+dt, mark.rutland, jarkko.nikula, andriy.shevchenko,
mika.westerberg, linux-i2c, devicetree, linux-kernel
Cc: Luis.Oliveira, Ramiro.Oliveira, Joao.Pinto, CARLOS.PALMINHA
Signed-off-by: Luis Oliveira <lolivei@synopsys.com>
---
Changes V2->V3: (Andy Shevchenko)
- nothing except style issues
drivers/i2c/busses/i2c-designware-slave.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/i2c/busses/i2c-designware-slave.c b/drivers/i2c/busses/i2c-designware-slave.c
index 6b0db3b..2417cc8 100644
--- a/drivers/i2c/busses/i2c-designware-slave.c
+++ b/drivers/i2c/busses/i2c-designware-slave.c
@@ -38,7 +38,7 @@ static void i2c_dw_configure_fifo_slave(struct dw_i2c_dev *dev)
dw_writel(dev, 0, DW_IC_TX_TL);
dw_writel(dev, 0, DW_IC_RX_TL);
- /* configure the i2c slave */
+ /* configure the I2C slave */
dw_writel(dev, dev->slave_cfg, DW_IC_CON);
dw_writel(dev, DW_IC_INTR_SLAVE_MASK, DW_IC_INTR_MASK);
}
@@ -182,7 +182,7 @@ int i2c_dw_reg_slave(struct i2c_client *slave)
if (slave->flags & I2C_CLIENT_TEN)
return -EAFNOSUPPORT;
/* set slave address in the IC_SAR register,
- * the address to which the DW_apb_i2c responds */
+ * the address to which the DW_apb_i2c responds */
__i2c_dw_enable(dev, false);
dw_writel(dev, slave->addr, DW_IC_SAR);
@@ -266,7 +266,7 @@ static u32 i2c_dw_read_clear_intrbits_slave(struct dw_i2c_dev *dev)
}
/*
- * Interrupt service routine. This gets called whenever an I2C interrupt
+ * Interrupt service routine. This gets called whenever an I2C slave interrupt
* occurs.
*/
@@ -300,7 +300,7 @@ static bool i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev)
val = dw_readl(dev, DW_IC_DATA_CMD);
if (!i2c_slave_event(dev->slave,
I2C_SLAVE_WRITE_RECEIVED, &val)) {
- dev_dbg(dev->dev, "Byte %X acked! ",
+ dev_dbg(dev->dev, "Byte %X acked!",
val);
}
dw_readl(dev, DW_IC_CLR_RD_REQ);
@@ -330,7 +330,7 @@ static bool i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev)
val = dw_readl(dev, DW_IC_DATA_CMD);
if (!i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_RECEIVED,
&val))
- dev_dbg(dev->dev, "Byte %X acked! ", val);
+ dev_dbg(dev->dev, "Byte %X acked!", val);
} else {
i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &val);
stat = i2c_dw_read_clear_intrbits_slave(dev);
--
2.10.2
^ permalink raw reply related [flat|nested] 19+ messages in thread