Hello,
Because the designware IP was not able to handle the SDA hold time before
version 1.11a, MSCC has its own implementation. Add support for it and then add
i2c on ocelot boards.
I would expect patches 1 to 4 to go through the i2c tree and 5-6 through
the mips tree once patch 4 has been reviewed by the DT maintainers.
This is based on top of i2c-next plus on
https://patchwork.ozlabs.org/project/linux-i2c/list/?series=57551
Changes in v3:
- collected review tags
- fixed build warnings on 64bit machines
Changes in v2:
- removed first patch as a similar one is in i2c-next
- rebase on top of i2c-next
- Added two patches to implement ideas from Andy
Alexandre Belloni (6):
i2c: designware: use generic table matching
i2c: designware: move #ifdef CONFIG_OF to the top
i2c: designware: allow IP specific sda_hold_time
i2c: designware: add MSCC Ocelot support
MIPS: dts: mscc: Add i2c on ocelot
MIPS: dts: mscc: enable i2c on ocelot_pcb123
.../bindings/i2c/i2c-designware.txt | 9 ++-
arch/mips/boot/dts/mscc/ocelot.dtsi | 18 ++++++
arch/mips/boot/dts/mscc/ocelot_pcb123.dts | 6 ++
drivers/i2c/busses/i2c-designware-common.c | 2 +
drivers/i2c/busses/i2c-designware-core.h | 4 ++
drivers/i2c/busses/i2c-designware-platdrv.c | 63 +++++++++++++++----
6 files changed, 87 insertions(+), 15 deletions(-)
--
2.18.0
Enable the i2c controller on ocelot PCB123. While there are no i2c devices
on the board itself, it can be used to control the SFP transceivers.
Signed-off-by: Alexandre Belloni <[email protected]>
---
arch/mips/boot/dts/mscc/ocelot_pcb123.dts | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/mips/boot/dts/mscc/ocelot_pcb123.dts b/arch/mips/boot/dts/mscc/ocelot_pcb123.dts
index 4ccd65379059..336c859a9bbe 100644
--- a/arch/mips/boot/dts/mscc/ocelot_pcb123.dts
+++ b/arch/mips/boot/dts/mscc/ocelot_pcb123.dts
@@ -26,6 +26,12 @@
status = "okay";
};
+&i2c {
+ clock-frequency = <100000>;
+ i2c-sda-hold-time-ns = <300>;
+ status = "okay";
+};
+
&mdio0 {
status = "okay";
};
--
2.18.0
Because some old designware IPs were not supporting setting an SDA hold
time, vendors developed their own solution. Add a way for the final driver
to provide its own SDA hold time handling.
Signed-off-by: Alexandre Belloni <[email protected]>
Reviewed-by: Andy Shevchenko <[email protected]>
---
drivers/i2c/busses/i2c-designware-common.c | 2 ++
drivers/i2c/busses/i2c-designware-core.h | 1 +
2 files changed, 3 insertions(+)
diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c
index e67d6c7d552c..463906a02c7f 100644
--- a/drivers/i2c/busses/i2c-designware-common.c
+++ b/drivers/i2c/busses/i2c-designware-common.c
@@ -201,6 +201,8 @@ int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev)
dev_dbg(dev->dev, "SDA Hold Time TX:RX = %d:%d\n",
dev->sda_hold_time & ~(u32)DW_IC_SDA_HOLD_RX_MASK,
dev->sda_hold_time >> DW_IC_SDA_HOLD_RX_SHIFT);
+ } else if (dev->set_sda_hold_time) {
+ dev->set_sda_hold_time(dev);
} else if (dev->sda_hold_time) {
dev_warn(dev->dev,
"Hardware too old to adjust SDA hold time.\n");
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index 70c188d6fb6b..870444bbbcc4 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -269,6 +269,7 @@ struct dw_i2c_dev {
void (*disable)(struct dw_i2c_dev *dev);
void (*disable_int)(struct dw_i2c_dev *dev);
int (*init)(struct dw_i2c_dev *dev);
+ int (*set_sda_hold_time)(struct dw_i2c_dev *dev);
int mode;
struct i2c_bus_recovery_info rinfo;
};
--
2.18.0
The Microsemi Ocelot I2C controller is a designware IP. It also has a
second set of registers to allow tweaking SDA hold time and spike
filtering.
Cc: Rob Herring <[email protected]>
Reviewed-by: Andy Shevchenko <[email protected]>
Signed-off-by: Alexandre Belloni <[email protected]>
---
.../bindings/i2c/i2c-designware.txt | 9 ++++-
drivers/i2c/busses/i2c-designware-core.h | 3 ++
drivers/i2c/busses/i2c-designware-platdrv.c | 40 +++++++++++++++++++
3 files changed, 50 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/i2c/i2c-designware.txt b/Documentation/devicetree/bindings/i2c/i2c-designware.txt
index fbb0a6d8b964..7886f2dc6675 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-designware.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-designware.txt
@@ -2,7 +2,8 @@
Required properties :
- - compatible : should be "snps,designware-i2c"
+ - compatible : should be "snps,designware-i2c" or "mscc,ocelot-i2c" followed by
+ "snps,designware-i2c" for fallback
- reg : Offset and length of the register set for the device
- interrupts : <IRQ> where IRQ is the interrupt number.
@@ -11,8 +12,12 @@ Recommended properties :
- clock-frequency : desired I2C bus clock frequency in Hz.
Optional properties :
+ - reg : for "mscc,ocelot-i2c", a second register set to configure the SDA hold
+ time, named ICPU_CFG:TWI_DELAY in the datasheet.
+
- i2c-sda-hold-time-ns : should contain the SDA hold time in nanoseconds.
- This option is only supported in hardware blocks version 1.11a or newer.
+ This option is only supported in hardware blocks version 1.11a or newer and
+ on Microsemi SoCs ("mscc,ocelot-i2c" compatible).
- i2c-scl-falling-time-ns : should contain the SCL falling time in nanoseconds.
This value which is by default 300ns is used to compute the tLOW period.
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index 870444bbbcc4..5e240ce9968e 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -225,6 +225,7 @@
struct dw_i2c_dev {
struct device *dev;
void __iomem *base;
+ void __iomem *ext;
struct completion cmd_complete;
struct clk *clk;
struct reset_control *rst;
@@ -279,6 +280,8 @@ struct dw_i2c_dev {
#define ACCESS_INTR_MASK 0x00000004
#define MODEL_CHERRYTRAIL 0x00000100
+#define MODEL_MSCC_OCELOT 0x00000200
+#define MODEL_MASK 0x00000f00
u32 dw_readl(struct dw_i2c_dev *dev, int offset);
void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset);
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index 1bcaab777a2e..39aab03cb416 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -157,11 +157,48 @@ static inline int dw_i2c_acpi_configure(struct platform_device *pdev)
#endif
#ifdef CONFIG_OF
+#define MSCC_ICPU_CFG_TWI_DELAY 0x0
+#define MSCC_ICPU_CFG_TWI_DELAY_ENABLE BIT(0)
+#define MSCC_ICPU_CFG_TWI_SPIKE_FILTER 0x4
+
+static int mscc_twi_set_sda_hold_time(struct dw_i2c_dev *dev)
+{
+ writel((dev->sda_hold_time << 1) | MSCC_ICPU_CFG_TWI_DELAY_ENABLE,
+ dev->ext + MSCC_ICPU_CFG_TWI_DELAY);
+
+ return 0;
+}
+
+int dw_i2c_of_configure(struct platform_device *pdev)
+{
+ struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
+ struct resource *mem;
+
+ switch (dev->flags & MODEL_MASK) {
+ case MODEL_MSCC_OCELOT:
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ dev->ext = devm_ioremap_resource(&pdev->dev, mem);
+ if (!IS_ERR(dev->ext))
+ dev->set_sda_hold_time = mscc_twi_set_sda_hold_time;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static const struct of_device_id dw_i2c_of_match[] = {
{ .compatible = "snps,designware-i2c", },
+ { .compatible = "mscc,ocelot-i2c", .data = (void *)MODEL_MSCC_OCELOT },
{},
};
MODULE_DEVICE_TABLE(of, dw_i2c_of_match);
+#else
+static inline int dw_i2c_of_configure(struct platform_device *pdev)
+{
+ return -ENODEV;
+}
#endif
static void i2c_dw_configure_master(struct dw_i2c_dev *dev)
@@ -296,6 +333,9 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
dev->flags |= (uintptr_t)device_get_match_data(&pdev->dev);
+ if (pdev->dev.of_node)
+ dw_i2c_of_configure(pdev);
+
if (has_acpi_companion(&pdev->dev))
dw_i2c_acpi_configure(pdev);
--
2.18.0
Move the #ifdef CONFIG_OF section to the top of the file, after the ACPI
section so functions defined there can be used in dw_i2c_plat_probe.
Reviewed-by: Andy Shevchenko <[email protected]>
Signed-off-by: Alexandre Belloni <[email protected]>
---
drivers/i2c/busses/i2c-designware-platdrv.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index d117c120730d..1bcaab777a2e 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -156,6 +156,14 @@ static inline int dw_i2c_acpi_configure(struct platform_device *pdev)
}
#endif
+#ifdef CONFIG_OF
+static const struct of_device_id dw_i2c_of_match[] = {
+ { .compatible = "snps,designware-i2c", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, dw_i2c_of_match);
+#endif
+
static void i2c_dw_configure_master(struct dw_i2c_dev *dev)
{
struct i2c_timings *t = &dev->timings;
@@ -390,14 +398,6 @@ static int dw_i2c_plat_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_OF
-static const struct of_device_id dw_i2c_of_match[] = {
- { .compatible = "snps,designware-i2c", },
- {},
-};
-MODULE_DEVICE_TABLE(of, dw_i2c_of_match);
-#endif
-
#ifdef CONFIG_PM_SLEEP
static int dw_i2c_plat_prepare(struct device *dev)
{
--
2.18.0
Switch to device_get_match_data in probe to match the device specific data
instead of using the acpi specific function.
Suggested-by: Andy Shevchenko <[email protected]>
Signed-off-by: Alexandre Belloni <[email protected]>
---
Changes in v3:
- removed unused variable
- switched to uintptr_t for the cast
drivers/i2c/busses/i2c-designware-platdrv.c | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index ddf13527aaee..d117c120730d 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -86,7 +86,6 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev)
struct i2c_timings *t = &dev->timings;
u32 ss_ht = 0, fp_ht = 0, hs_ht = 0, fs_ht = 0;
acpi_handle handle = ACPI_HANDLE(&pdev->dev);
- const struct acpi_device_id *id;
struct acpi_device *adev;
const char *uid;
@@ -119,10 +118,6 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev)
break;
}
- id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev);
- if (id && id->driver_data)
- dev->flags |= (u32)id->driver_data;
-
if (acpi_bus_get_device(handle, &adev))
return -ENODEV;
@@ -291,6 +286,8 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
else
t->bus_freq_hz = 400000;
+ dev->flags |= (uintptr_t)device_get_match_data(&pdev->dev);
+
if (has_acpi_companion(&pdev->dev))
dw_i2c_acpi_configure(pdev);
--
2.18.0
Ocelot has an i2c controller, add it. There is only one possible pinmux
configuration so add it as well.
Signed-off-by: Alexandre Belloni <[email protected]>
---
arch/mips/boot/dts/mscc/ocelot.dtsi | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/arch/mips/boot/dts/mscc/ocelot.dtsi b/arch/mips/boot/dts/mscc/ocelot.dtsi
index 4f33dbc67348..34093acebc0d 100644
--- a/arch/mips/boot/dts/mscc/ocelot.dtsi
+++ b/arch/mips/boot/dts/mscc/ocelot.dtsi
@@ -78,6 +78,19 @@
status = "disabled";
};
+ i2c: i2c@100400 {
+ compatible = "mscc,ocelot-i2c", "snps,designware-i2c";
+ pinctrl-0 = <&i2c_pins>;
+ pinctrl-names = "default";
+ reg = <0x100400 0x100>, <0x198 0x8>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <8>;
+ clocks = <&ahb_clk>;
+
+ status = "disabled";
+ };
+
uart2: serial@100800 {
pinctrl-0 = <&uart2_pins>;
pinctrl-names = "default";
@@ -178,6 +191,11 @@
pins = "GPIO_12", "GPIO_13";
function = "uart2";
};
+
+ i2c_pins: i2c-pins {
+ pins = "GPIO_16", "GPIO_17";
+ function = "twi";
+ };
};
mdio0: mdio@107009c {
--
2.18.0
On 08/06/2018 09:54 PM, Alexandre Belloni wrote:
> Hello,
>
> Because the designware IP was not able to handle the SDA hold time before
> version 1.11a, MSCC has its own implementation. Add support for it and then add
> i2c on ocelot boards.
>
> I would expect patches 1 to 4 to go through the i2c tree and 5-6 through
> the mips tree once patch 4 has been reviewed by the DT maintainers.
>
For the patches 1-4/6 that touch i2c-designware:
Tested-by: Jarkko Nikula <[email protected]>
Acked-by: Jarkko Nikula <[email protected]>
I tested acpi_match_device() conversion to device_get_match_data()
didn't affect MODEL_CHERRYTRAIL case and quick test that i2c
communication continue working.
On Mon, Aug 06, 2018 at 08:54:10PM +0200, Alexandre Belloni wrote:
> The Microsemi Ocelot I2C controller is a designware IP. It also has a
> second set of registers to allow tweaking SDA hold time and spike
> filtering.
>
> Cc: Rob Herring <[email protected]>
> Reviewed-by: Andy Shevchenko <[email protected]>
> Signed-off-by: Alexandre Belloni <[email protected]>
> ---
> .../bindings/i2c/i2c-designware.txt | 9 ++++-
Please split binding patches.
> drivers/i2c/busses/i2c-designware-core.h | 3 ++
> drivers/i2c/busses/i2c-designware-platdrv.c | 40 +++++++++++++++++++
> 3 files changed, 50 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/i2c/i2c-designware.txt b/Documentation/devicetree/bindings/i2c/i2c-designware.txt
> index fbb0a6d8b964..7886f2dc6675 100644
> --- a/Documentation/devicetree/bindings/i2c/i2c-designware.txt
> +++ b/Documentation/devicetree/bindings/i2c/i2c-designware.txt
> @@ -2,7 +2,8 @@
>
> Required properties :
>
> - - compatible : should be "snps,designware-i2c"
> + - compatible : should be "snps,designware-i2c" or "mscc,ocelot-i2c" followed by
> + "snps,designware-i2c" for fallback
Please reformat to one valid combination per line.
> - reg : Offset and length of the register set for the device
> - interrupts : <IRQ> where IRQ is the interrupt number.
>
> @@ -11,8 +12,12 @@ Recommended properties :
> - clock-frequency : desired I2C bus clock frequency in Hz.
>
> Optional properties :
> + - reg : for "mscc,ocelot-i2c", a second register set to configure the SDA hold
> + time, named ICPU_CFG:TWI_DELAY in the datasheet.
> +
> - i2c-sda-hold-time-ns : should contain the SDA hold time in nanoseconds.
> - This option is only supported in hardware blocks version 1.11a or newer.
> + This option is only supported in hardware blocks version 1.11a or newer and
> + on Microsemi SoCs ("mscc,ocelot-i2c" compatible).
>
> - i2c-scl-falling-time-ns : should contain the SCL falling time in nanoseconds.
> This value which is by default 300ns is used to compute the tLOW period.
On Mon, Aug 06, 2018 at 08:54:07PM +0200, Alexandre Belloni wrote:
> Switch to device_get_match_data in probe to match the device specific data
> instead of using the acpi specific function.
>
> Suggested-by: Andy Shevchenko <[email protected]>
> Signed-off-by: Alexandre Belloni <[email protected]>
Andy, you happy with this patch?
On Wed, 2018-08-08 at 22:22 +0200, Wolfram Sang wrote:
> On Mon, Aug 06, 2018 at 08:54:07PM +0200, Alexandre Belloni wrote:
> > Switch to device_get_match_data in probe to match the device
> > specific data
> > instead of using the acpi specific function.
> >
> > Suggested-by: Andy Shevchenko <[email protected]>
> > Signed-off-by: Alexandre Belloni <[email protected]>
>
> Andy, you happy with this patch?
>
Yes, yes.
If you need my formal tag, here it is
Acked-by: Andy Shevchenko <[email protected]>
--
Andy Shevchenko <[email protected]>
Intel Finland Oy