
Hello Simon,
Am 21.04.2016 um 08:19 schrieb Stefan Roese:
This patch adds support for the PCI(e) based I2C cores. Which can be found for example on the Intel Bay Trail SoC. It has 7 I2C controllers implemented as PCI devices.
This patch also adds the fixed values for the timing registers for BayTrail which are taken from the Linux designware I2C driver.
Signed-off-by: Stefan Roese sr@denx.de Cc: Simon Glass sjg@chromium.org Cc: Bin Meng bmeng.cn@gmail.com Cc: Marek Vasut marex@denx.de Cc: Heiko Schocher hs@denx.de
v4:
- Used new function dev_get_addr_ptr() in probe function to avoid cast. For this to work, this patch need to be applied: http://patchwork.ozlabs.org/patch/612948/
Is it Ok for you, if I apply this patch through the i2c tree? Or do you want to pick up this patchserie?
bye, Heiko
Rebased on latest mainline
drivers/i2c/designware_i2c.c | 118 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 106 insertions(+), 12 deletions(-)
diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c index d653eff..0c7cd0b 100644 --- a/drivers/i2c/designware_i2c.c +++ b/drivers/i2c/designware_i2c.c @@ -8,11 +8,32 @@ #include <common.h> #include <dm.h> #include <i2c.h> +#include <pci.h> #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; };
static void dw_i2c_enable(struct i2c_regs *i2c_base, bool enable)
@@ -43,6 +64,7 @@ static void dw_i2c_enable(struct i2c_regs *i2c_base, bool enable)
- Set the i2c speed.
*/ static unsigned int __dw_i2c_set_bus_speed(struct i2c_regs *i2c_base,
{ unsigned int cntl;struct dw_scl_sda_cfg *scl_sda_cfg, unsigned int speed)
@@ -62,34 +84,55 @@ 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_HS;
hcnt = (IC_CLK * MIN_HS_SCL_HIGHTIME) / NANO_TO_MICRO;
cntl |= IC_CON_SPD_SS;
if (scl_sda_cfg) {
hcnt = scl_sda_cfg->fs_hcnt;
lcnt = scl_sda_cfg->fs_lcnt;
} else {
hcnt = (IC_CLK * MIN_HS_SCL_HIGHTIME) / NANO_TO_MICRO;
lcnt = (IC_CLK * MIN_HS_SCL_LOWTIME) / NANO_TO_MICRO;
writel(hcnt, &i2c_base->ic_hs_scl_hcnt);}
writel(lcnt, &i2c_base->ic_hs_scl_lcnt); break;lcnt = (IC_CLK * MIN_HS_SCL_LOWTIME) / NANO_TO_MICRO;
+#endif
case IC_SPEED_MODE_STANDARD: cntl |= IC_CON_SPD_SS;
hcnt = (IC_CLK * MIN_SS_SCL_HIGHTIME) / NANO_TO_MICRO;
if (scl_sda_cfg) {
hcnt = scl_sda_cfg->ss_hcnt;
lcnt = scl_sda_cfg->ss_lcnt;
} else {
hcnt = (IC_CLK * MIN_SS_SCL_HIGHTIME) / NANO_TO_MICRO;
lcnt = (IC_CLK * MIN_SS_SCL_LOWTIME) / NANO_TO_MICRO;
writel(hcnt, &i2c_base->ic_ss_scl_hcnt);}
lcnt = (IC_CLK * MIN_SS_SCL_LOWTIME) / NANO_TO_MICRO;
writel(lcnt, &i2c_base->ic_ss_scl_lcnt); break;
case IC_SPEED_MODE_FAST: default: cntl |= IC_CON_SPD_FS;
hcnt = (IC_CLK * MIN_FS_SCL_HIGHTIME) / NANO_TO_MICRO;
if (scl_sda_cfg) {
hcnt = scl_sda_cfg->fs_hcnt;
lcnt = scl_sda_cfg->fs_lcnt;
} else {
hcnt = (IC_CLK * MIN_FS_SCL_HIGHTIME) / NANO_TO_MICRO;
lcnt = (IC_CLK * MIN_FS_SCL_LOWTIME) / NANO_TO_MICRO;
writel(hcnt, &i2c_base->ic_fs_scl_hcnt);}
lcnt = (IC_CLK * MIN_FS_SCL_LOWTIME) / NANO_TO_MICRO;
writel(lcnt, &i2c_base->ic_fs_scl_lcnt); break; }
writel(cntl, &i2c_base->ic_con);
- /* Configure SDA Hold Time if required */
- if (scl_sda_cfg)
writel(scl_sda_cfg->sda_hold, &i2c_base->ic_sda_hold);
- /* Enable back i2c now speed set */ dw_i2c_enable(i2c_base, true);
@@ -316,7 +359,7 @@ static void __dw_i2c_init(struct i2c_regs *i2c_base, int speed, int slaveaddr) writel(IC_TX_TL, &i2c_base->ic_tx_tl); writel(IC_STOP_DET, &i2c_base->ic_intr_mask); #ifndef CONFIG_DM_I2C
- __dw_i2c_set_bus_speed(i2c_base, speed);
- __dw_i2c_set_bus_speed(i2c_base, NULL, speed); writel(slaveaddr, &i2c_base->ic_sar); #endif
@@ -357,7 +400,7 @@ static unsigned int dw_i2c_set_bus_speed(struct i2c_adapter *adap, unsigned int speed) { adap->speed = speed;
- return __dw_i2c_set_bus_speed(i2c_get_base(adap), speed);
return __dw_i2c_set_bus_speed(i2c_get_base(adap), NULL, speed); }
static void dw_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
@@ -448,7 +491,7 @@ static int designware_i2c_set_bus_speed(struct udevice *bus, unsigned int speed) { struct dw_i2c *i2c = dev_get_priv(bus);
- return __dw_i2c_set_bus_speed(i2c->regs, speed);
return __dw_i2c_set_bus_speed(i2c->regs, i2c->scl_sda_cfg, speed); }
static int designware_i2c_probe_chip(struct udevice *bus, uint chip_addr,
@@ -471,14 +514,48 @@ static int designware_i2c_probe(struct udevice *bus) { struct dw_i2c *priv = dev_get_priv(bus);
- /* Save base address from device-tree */
- priv->regs = (struct i2c_regs *)dev_get_addr(bus);
- 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 *)dev_get_addr_ptr(bus);
}
__dw_i2c_init(priv->regs, 0, 0);
return 0; }
+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 = { .xfer = designware_i2c_xfer, .probe_chip = designware_i2c_probe_chip,
@@ -494,9 +571,26 @@ U_BOOT_DRIVER(i2c_designware) = { .name = "i2c_designware", .id = UCLASS_I2C, .of_match = designware_i2c_ids,
- .bind = designware_i2c_bind, .probe = designware_i2c_probe, .priv_auto_alloc_size = sizeof(struct dw_i2c), .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 */