[PATCH v2 09/12] i2c: designware: Unpin Microsemi Ocelot I2C into a glue driver

Serge Semin
2020-05-10T09:51:19Z

Since glue-layer drivers design is now supported by the DW APB I2C
platform code lets unpin MSCC Ocelot I2C driver at least. It won't be that
hard because the only difference between this controller and vanilly core
is in what the former sets the sda hold time in a dedicated configure
registers space.

Note I enabled the new driver by default for the MSCC Ocelot platform so
one would be automatically built and we wouldn't need to alter the in- and
out-of-source tree platform configs.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
Cc: Alexey Malahov <Alexey.Malahov@baikalelectronics.ru>
Cc: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
Cc: Paul Burton <paulburton@kernel.org>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: Wolfram Sang <wsa@the-dreams.de>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Frank Rowand <frowand.list@gmail.com>
Cc: linux-mips@vger.kernel.org
Cc: devicetree@vger.kernel.org
---
drivers/i2c/busses/Kconfig | 12 +++
drivers/i2c/busses/Makefile | 1 +
drivers/i2c/busses/i2c-designware-core.h | 3 -
drivers/i2c/busses/i2c-designware-mscc.c | 83 +++++++++++++++++++++
drivers/i2c/busses/i2c-designware-platdrv.c | 40 ----------
5 files changed, 96 insertions(+), 43 deletions(-)
create mode 100644 drivers/i2c/busses/i2c-designware-mscc.c

diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index ed6927c4c540..2f047cf07fee 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -566,6 +566,18 @@ config I2C_DESIGNWARE_SLAVE
This is not a standalone module, this module compiles together with
i2c-designware-core.

+config I2C_DESIGNWARE_MSCC
+ tristate "Microsemi Ocelot I2C"
+ depends on MSCC_OCELOT
+ select I2C_DESIGNWARE_PLATFORM
+ default y
+ help
+ This driver supports the Microsemi Ocelot SoC version of the Synopsys
+ Designware I2C IP-core.
+
+ The driver can also be built as a module. If so, the module will be
+ called i2c-designware-mscc.
+
config I2C_DESIGNWARE_PCI
tristate "Synopsys DesignWare PCI"
depends on PCI
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index c6813d7b2780..480a9fe4fb64 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -55,6 +55,7 @@ i2c-designware-core-$(CONFIG_I2C_DESIGNWARE_SLAVE) += i2c-designware-slave.o
obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o
i2c-designware-platform-y := i2c-designware-platdrv.o
i2c-designware-platform-$(CONFIG_I2C_DESIGNWARE_BAYTRAIL) += i2c-designware-baytrail.o
+obj-$(CONFIG_I2C_DESIGNWARE_MSCC) += i2c-designware-mscc.o
obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o
i2c-designware-pci-y := i2c-designware-pcidrv.o
obj-$(CONFIG_I2C_DIGICOLOR) += i2c-digicolor.o
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index 10606266b30c..64544777a1fa 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -177,7 +177,6 @@
* @dev: driver model device node
* @map: IO registers map
* @base: IO registers pointer
- * @ext: Extended IO registers pointer
* @cmd_complete: tx completion indicator
* @clk: input reference clock
* @pclk: clock required to access the registers
@@ -229,7 +228,6 @@ struct dw_i2c_dev {
struct device *dev;
struct regmap *map;
void __iomem *base;
- void __iomem *ext;
struct completion cmd_complete;
struct clk *clk;
struct clk *pclk;
@@ -284,7 +282,6 @@ struct dw_i2c_dev {
#define ACCESS_NO_IRQ_SUSPEND 0x00000008

#define MODEL_CHERRYTRAIL 0x00000100
-#define MODEL_MSCC_OCELOT 0x00000200
#define MODEL_MASK 0x00000f00

int i2c_dw_init_regmap(struct dw_i2c_dev *dev);
diff --git a/drivers/i2c/busses/i2c-designware-mscc.c b/drivers/i2c/busses/i2c-designware-mscc.c
new file mode 100644
index 000000000000..0649e3d1fefc
--- /dev/null
+++ b/drivers/i2c/busses/i2c-designware-mscc.c
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Microsemi Ocelot I2C Controller.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+
+#include "i2c-designware-core.h"
+#include "i2c-designware-platdrv.h"
+
+#define MSCC_ICPU_CFG_TWI_DELAY 0x0
+#define MSCC_ICPU_CFG_TWI_DELAY_ENABLE BIT(0)
+#define MSCC_ICPU_CFG_TWI_SPIKE_FILTER 0x4
+
+struct mscc_i2c_dev {
+ struct dw_i2c_dev dev;
+ void __iomem *ext;
+};
+#define to_mscc_device(_dev) container_of((_dev), struct mscc_i2c_dev, dev)
+
+static int mscc_twi_set_sda_hold_time(struct dw_i2c_dev *dev)
+{
+ struct mscc_i2c_dev *mscc = to_mscc_device(dev);
+
+ writel((dev->sda_hold_time << 1) | MSCC_ICPU_CFG_TWI_DELAY_ENABLE,
+ mscc->ext + MSCC_ICPU_CFG_TWI_DELAY);
+
+ return 0;
+}
+
+static int mscc_i2c_plat_probe(struct platform_device *pdev)
+{
+ struct mscc_i2c_dev *mscc;
+ struct resource *mem;
+
+ mscc = devm_kzalloc(&pdev->dev, sizeof(*mscc), GFP_KERNEL);
+ if (!mscc)
+ return -ENOMEM;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ mscc->ext = devm_ioremap_resource(&pdev->dev, mem);
+ if (!IS_ERR(mscc->ext))
+ mscc->dev.set_sda_hold_time = mscc_twi_set_sda_hold_time;
+
+ mscc->dev.dev = &pdev->dev;
+ platform_set_drvdata(pdev, mscc);
+
+ return i2c_dw_plat_setup(&mscc->dev);
+}
+
+static int mscc_i2c_plat_remove(struct platform_device *pdev)
+{
+ struct mscc_i2c_dev *mscc = platform_get_drvdata(pdev);
+
+ return i2c_dw_plat_clear(&mscc->dev);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id mscc_i2c_of_match[] = {
+ { .compatible = "mscc,ocelot-i2c" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mscc_i2c_of_match);
+#endif
+
+static struct platform_driver mscc_i2c_driver = {
+ .probe = mscc_i2c_plat_probe,
+ .remove = mscc_i2c_plat_remove,
+ .driver = {
+ .name = "i2c_ocelot",
+ .of_match_table = of_match_ptr(mscc_i2c_of_match),
+ .pm = &i2c_dw_plat_dev_pm_ops,
+ },
+};
+module_platform_driver(mscc_i2c_driver);
+
+MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@bootlin.com>");
+MODULE_DESCRIPTION("Microsemi Ocelot I2C Controller");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index 274953155569..1f56865bb6ca 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -143,48 +143,11 @@ static inline int dw_i2c_acpi_configure(struct dw_i2c_dev *dev)
#endif

#ifdef CONFIG_OF
-#define MSCC_ICPU_CFG_TWI_DELAY 0x0
-#define MSCC_ICPU_CFG_TWI_DELAY_ENABLE BIT(0)
-#define MSCC_ICPU_CFG_TWI_SPIKE_FILTER 0x4
-
-static int mscc_twi_set_sda_hold_time(struct dw_i2c_dev *dev)
-{
- writel((dev->sda_hold_time << 1) | MSCC_ICPU_CFG_TWI_DELAY_ENABLE,
- dev->ext + MSCC_ICPU_CFG_TWI_DELAY);
-
- return 0;
-}
-
-static int dw_i2c_of_configure(struct dw_i2c_dev *dev)
-{
- struct platform_device *pdev = to_platform_device(dev->dev);
- 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 dw_i2c_dev *dev)
-{
- return -ENODEV;
-}
#endif

static void i2c_dw_configure_master(struct dw_i2c_dev *dev)
@@ -288,9 +251,6 @@ int i2c_dw_plat_setup(struct dw_i2c_dev *dev)
else
t->bus_freq_hz = I2C_MAX_FAST_MODE_FREQ;

- if (pdev->dev.of_node)
- dw_i2c_of_configure(dev);
-
if (has_acpi_companion(&pdev->dev))
dw_i2c_acpi_configure(dev);

--
2.25.1