summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2019-12-06 21:41:40 -0700
committerBin Meng <bmeng.cn@gmail.com>2019-12-15 11:44:08 +0800
commit457df2337fc90431dc60b9b256ac1fdb8809f4cf (patch)
tree314e61460ac2a14e68d358d242f45dfa7505f090 /drivers
parentd721001fd6d4162738578ba03c94c1198a5ef462 (diff)
i2c: designware: Tidy up PCI support
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/i2c/Makefile3
-rw-r--r--drivers/i2c/designware_i2c.c106
-rw-r--r--drivers/i2c/designware_i2c.h35
-rw-r--r--drivers/i2c/designware_i2c_pci.c79
4 files changed, 134 insertions, 89 deletions
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index c2f75d8755..f5a471f887 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -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
diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c
index 6daa90e744..b8cdd1c661 100644
--- a/drivers/i2c/designware_i2c.c
+++ b/drivers/i2c/designware_i2c.c
@@ -13,34 +13,6 @@
#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 */
diff --git a/drivers/i2c/designware_i2c.h b/drivers/i2c/designware_i2c.h
index 20ff20d9b8..48766d0806 100644
--- a/drivers/i2c/designware_i2c.h
+++ b/drivers/i2c/designware_i2c.h
@@ -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
index 0000000000..e8fc6f2a90
--- /dev/null
+++ b/drivers/i2c/designware_i2c_pci.c
@@ -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);