i2c: designware: Tidy up PCI support
authorSimon Glass <sjg@chromium.org>
Sat, 7 Dec 2019 04:41:40 +0000 (21:41 -0700)
committerBin Meng <bmeng.cn@gmail.com>
Sun, 15 Dec 2019 03:44:08 +0000 (11:44 +0800)
This is hacked into the driver at present. It seems better to have it as
a separate driver that uses the base driver. Create a new file and put
the X86 code into it.

Actually the Baytrail settings should really come from the device tree.

Note that 'has_max_speed' is added as well. This is currently always false
but since only Baytrail provides the config, it does not affect operation
for other devices.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Heiko Schocher <hs@denx.de>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
drivers/i2c/Makefile
drivers/i2c/designware_i2c.c
drivers/i2c/designware_i2c.h
drivers/i2c/designware_i2c_pci.c [new file with mode: 0644]

index c2f75d87559817c93e054eedfd55ec2dc192bd25..f5a471f88750c4ef3d0bc1c7ff3f279f1cb95d92 100644 (file)
@@ -14,6 +14,9 @@ obj-$(CONFIG_SYS_I2C_AT91) += at91_i2c.o
 obj-$(CONFIG_SYS_I2C_CADENCE) += i2c-cdns.o
 obj-$(CONFIG_SYS_I2C_DAVINCI) += davinci_i2c.o
 obj-$(CONFIG_SYS_I2C_DW) += designware_i2c.o
+ifdef CONFIG_DM_PCI
+obj-$(CONFIG_SYS_I2C_DW) += designware_i2c_pci.o
+endif
 obj-$(CONFIG_SYS_I2C_FSL) += fsl_i2c.o
 obj-$(CONFIG_SYS_I2C_IHS) += ihs_i2c.o
 obj-$(CONFIG_SYS_I2C_INTEL) += intel_i2c.o
index 6daa90e7442e9da916ca50691df250fd72187bcf..b8cdd1c661334fedd866ec100303f533c2e54042 100644 (file)
 #include <asm/io.h>
 #include "designware_i2c.h"
 
-struct dw_scl_sda_cfg {
-       u32 ss_hcnt;
-       u32 fs_hcnt;
-       u32 ss_lcnt;
-       u32 fs_lcnt;
-       u32 sda_hold;
-};
-
-#ifdef CONFIG_X86
-/* BayTrail HCNT/LCNT/SDA hold time */
-static struct dw_scl_sda_cfg byt_config = {
-       .ss_hcnt = 0x200,
-       .fs_hcnt = 0x55,
-       .ss_lcnt = 0x200,
-       .fs_lcnt = 0x99,
-       .sda_hold = 0x6,
-};
-#endif
-
-struct dw_i2c {
-       struct i2c_regs *regs;
-       struct dw_scl_sda_cfg *scl_sda_cfg;
-       struct reset_ctl_bulk resets;
-#if CONFIG_IS_ENABLED(CLK)
-       struct clk clk;
-#endif
-};
-
 #ifdef CONFIG_SYS_I2C_DW_ENABLE_STATUS_UNSUPPORTED
 static int  dw_i2c_enable(struct i2c_regs *i2c_base, bool enable)
 {
@@ -90,7 +62,9 @@ static unsigned int __dw_i2c_set_bus_speed(struct i2c_regs *i2c_base,
        unsigned int ena;
        int i2c_spd;
 
-       if (speed >= I2C_MAX_SPEED)
+       /* Allow max speed if there is no config, or the config allows it */
+       if (speed >= I2C_MAX_SPEED &&
+           (!scl_sda_cfg || scl_sda_cfg->has_max_speed))
                i2c_spd = IC_SPEED_MODE_MAX;
        else if (speed >= I2C_FAST_SPEED)
                i2c_spd = IC_SPEED_MODE_FAST;
@@ -106,7 +80,6 @@ static unsigned int __dw_i2c_set_bus_speed(struct i2c_regs *i2c_base,
        cntl = (readl(&i2c_base->ic_con) & (~IC_CON_SPD_MSK));
 
        switch (i2c_spd) {
-#ifndef CONFIG_X86 /* No High-speed for BayTrail yet */
        case IC_SPEED_MODE_MAX:
                cntl |= IC_CON_SPD_SS;
                if (scl_sda_cfg) {
@@ -119,7 +92,6 @@ static unsigned int __dw_i2c_set_bus_speed(struct i2c_regs *i2c_base,
                writel(hcnt, &i2c_base->ic_hs_scl_hcnt);
                writel(lcnt, &i2c_base->ic_hs_scl_lcnt);
                break;
-#endif
 
        case IC_SPEED_MODE_STANDARD:
                cntl |= IC_CON_SPD_SS;
@@ -565,24 +537,19 @@ static int designware_i2c_probe_chip(struct udevice *bus, uint chip_addr,
        return ret;
 }
 
-static int designware_i2c_probe(struct udevice *bus)
+static int designware_i2c_ofdata_to_platdata(struct udevice *bus)
 {
        struct dw_i2c *priv = dev_get_priv(bus);
-       int ret;
 
-       if (device_is_on_pci_bus(bus)) {
-#ifdef CONFIG_DM_PCI
-               /* Save base address from PCI BAR */
-               priv->regs = (struct i2c_regs *)
-                       dm_pci_map_bar(bus, PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
-#ifdef CONFIG_X86
-               /* Use BayTrail specific timing values */
-               priv->scl_sda_cfg = &byt_config;
-#endif
-#endif
-       } else {
-               priv->regs = (struct i2c_regs *)devfdt_get_addr_ptr(bus);
-       }
+       priv->regs = (struct i2c_regs *)devfdt_get_addr_ptr(bus);
+
+       return 0;
+}
+
+int designware_i2c_probe(struct udevice *bus)
+{
+       struct dw_i2c *priv = dev_get_priv(bus);
+       int ret;
 
        ret = reset_get_bulk(bus, &priv->resets);
        if (ret)
@@ -606,7 +573,7 @@ static int designware_i2c_probe(struct udevice *bus)
        return __dw_i2c_init(priv->regs, 0, 0);
 }
 
-static int designware_i2c_remove(struct udevice *dev)
+int designware_i2c_remove(struct udevice *dev)
 {
        struct dw_i2c *priv = dev_get_priv(dev);
 
@@ -618,30 +585,7 @@ static int designware_i2c_remove(struct udevice *dev)
        return reset_release_bulk(&priv->resets);
 }
 
-static int designware_i2c_bind(struct udevice *dev)
-{
-       static int num_cards;
-       char name[20];
-
-       /* Create a unique device name for PCI type devices */
-       if (device_is_on_pci_bus(dev)) {
-               /*
-                * ToDo:
-                * Setting req_seq in the driver is probably not recommended.
-                * But without a DT alias the number is not configured. And
-                * using this driver is impossible for PCIe I2C devices.
-                * This can be removed, once a better (correct) way for this
-                * is found and implemented.
-                */
-               dev->req_seq = num_cards;
-               sprintf(name, "i2c_designware#%u", num_cards++);
-               device_set_name(dev, name);
-       }
-
-       return 0;
-}
-
-static const struct dm_i2c_ops designware_i2c_ops = {
+const struct dm_i2c_ops designware_i2c_ops = {
        .xfer           = designware_i2c_xfer,
        .probe_chip     = designware_i2c_probe_chip,
        .set_bus_speed  = designware_i2c_set_bus_speed,
@@ -656,28 +600,12 @@ U_BOOT_DRIVER(i2c_designware) = {
        .name   = "i2c_designware",
        .id     = UCLASS_I2C,
        .of_match = designware_i2c_ids,
-       .bind   = designware_i2c_bind,
+       .ofdata_to_platdata = designware_i2c_ofdata_to_platdata,
        .probe  = designware_i2c_probe,
        .priv_auto_alloc_size = sizeof(struct dw_i2c),
        .remove = designware_i2c_remove,
-       .flags = DM_FLAG_OS_PREPARE,
+       .flags  = DM_FLAG_OS_PREPARE,
        .ops    = &designware_i2c_ops,
 };
 
-#ifdef CONFIG_X86
-static struct pci_device_id designware_pci_supported[] = {
-       /* Intel BayTrail has 7 I2C controller located on the PCI bus */
-       { PCI_VDEVICE(INTEL, 0x0f41) },
-       { PCI_VDEVICE(INTEL, 0x0f42) },
-       { PCI_VDEVICE(INTEL, 0x0f43) },
-       { PCI_VDEVICE(INTEL, 0x0f44) },
-       { PCI_VDEVICE(INTEL, 0x0f45) },
-       { PCI_VDEVICE(INTEL, 0x0f46) },
-       { PCI_VDEVICE(INTEL, 0x0f47) },
-       {},
-};
-
-U_BOOT_PCI_DEVICE(i2c_designware, designware_pci_supported);
-#endif
-
 #endif /* CONFIG_DM_I2C */
index 20ff20d9b835bbb01b4f85ac0a0b170b1b757e6f..48766d080671db7d3749e6e0555af191facaf015 100644 (file)
@@ -7,6 +7,8 @@
 #ifndef __DW_I2C_H_
 #define __DW_I2C_H_
 
+#include <reset.h>
+
 struct i2c_regs {
        u32 ic_con;             /* 0x00 */
        u32 ic_tar;             /* 0x04 */
@@ -131,4 +133,37 @@ struct i2c_regs {
 #define I2C_FAST_SPEED         400000
 #define I2C_STANDARD_SPEED     100000
 
+/**
+ * struct dw_scl_sda_cfg - I2C timing configuration
+ *
+ * @has_max_speed: Support maximum speed (1Mbps)
+ * @ss_hcnt: Standard speed high time in ns
+ * @fs_hcnt: Fast speed high time in ns
+ * @ss_lcnt: Standard speed low time in ns
+ * @fs_lcnt: Fast speed low time in ns
+ * @sda_hold: SDA hold time
+ */
+struct dw_scl_sda_cfg {
+       bool has_max_speed;
+       u32 ss_hcnt;
+       u32 fs_hcnt;
+       u32 ss_lcnt;
+       u32 fs_lcnt;
+       u32 sda_hold;
+};
+
+struct dw_i2c {
+       struct i2c_regs *regs;
+       struct dw_scl_sda_cfg *scl_sda_cfg;
+       struct reset_ctl_bulk resets;
+#if CONFIG_IS_ENABLED(CLK)
+       struct clk clk;
+#endif
+};
+
+extern const struct dm_i2c_ops designware_i2c_ops;
+
+int designware_i2c_probe(struct udevice *bus);
+int designware_i2c_remove(struct udevice *dev);
+
 #endif /* __DW_I2C_H_ */
diff --git a/drivers/i2c/designware_i2c_pci.c b/drivers/i2c/designware_i2c_pci.c
new file mode 100644 (file)
index 0000000..e8fc6f2
--- /dev/null
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2009
+ * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
+ * Copyright 2019 Google Inc
+ */
+
+#include <common.h>
+#include <dm.h>
+#include "designware_i2c.h"
+
+/* BayTrail HCNT/LCNT/SDA hold time */
+static struct dw_scl_sda_cfg byt_config = {
+       .ss_hcnt = 0x200,
+       .fs_hcnt = 0x55,
+       .ss_lcnt = 0x200,
+       .fs_lcnt = 0x99,
+       .sda_hold = 0x6,
+};
+
+static int designware_i2c_pci_probe(struct udevice *dev)
+{
+       struct dw_i2c *priv = dev_get_priv(dev);
+
+       /* Save base address from PCI BAR */
+       priv->regs = (struct i2c_regs *)
+               dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, PCI_REGION_MEM);
+       if (IS_ENABLED(CONFIG_INTEL_BAYTRAIL))
+               /* Use BayTrail specific timing values */
+               priv->scl_sda_cfg = &byt_config;
+
+       return designware_i2c_probe(dev);
+}
+
+static int designware_i2c_pci_bind(struct udevice *dev)
+{
+       static int num_cards;
+       char name[20];
+
+       /*
+        * Create a unique device name for PCI type devices
+        * ToDo:
+        * Setting req_seq in the driver is probably not recommended.
+        * But without a DT alias the number is not configured. And
+        * using this driver is impossible for PCIe I2C devices.
+        * This can be removed, once a better (correct) way for this
+        * is found and implemented.
+        */
+       dev->req_seq = num_cards;
+       sprintf(name, "i2c_designware#%u", num_cards++);
+       device_set_name(dev, name);
+
+       return 0;
+}
+
+U_BOOT_DRIVER(i2c_designware_pci) = {
+       .name   = "i2c_designware_pci",
+       .id     = UCLASS_I2C,
+       .bind   = designware_i2c_pci_bind,
+       .probe  = designware_i2c_pci_probe,
+       .priv_auto_alloc_size = sizeof(struct dw_i2c),
+       .remove = designware_i2c_remove,
+       .flags = DM_FLAG_OS_PREPARE,
+       .ops    = &designware_i2c_ops,
+};
+
+static struct pci_device_id designware_pci_supported[] = {
+       /* Intel BayTrail has 7 I2C controller located on the PCI bus */
+       { PCI_VDEVICE(INTEL, 0x0f41) },
+       { PCI_VDEVICE(INTEL, 0x0f42) },
+       { PCI_VDEVICE(INTEL, 0x0f43) },
+       { PCI_VDEVICE(INTEL, 0x0f44) },
+       { PCI_VDEVICE(INTEL, 0x0f45) },
+       { PCI_VDEVICE(INTEL, 0x0f46) },
+       { PCI_VDEVICE(INTEL, 0x0f47) },
+       {},
+};
+
+U_BOOT_PCI_DEVICE(i2c_designware_pci, designware_pci_supported);