mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-28 15:41:40 +00:00
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>
This commit is contained in:
parent
d721001fd6
commit
457df2337f
4 changed files with 134 additions and 89 deletions
|
@ -14,6 +14,9 @@ obj-$(CONFIG_SYS_I2C_AT91) += at91_i2c.o
|
||||||
obj-$(CONFIG_SYS_I2C_CADENCE) += i2c-cdns.o
|
obj-$(CONFIG_SYS_I2C_CADENCE) += i2c-cdns.o
|
||||||
obj-$(CONFIG_SYS_I2C_DAVINCI) += davinci_i2c.o
|
obj-$(CONFIG_SYS_I2C_DAVINCI) += davinci_i2c.o
|
||||||
obj-$(CONFIG_SYS_I2C_DW) += designware_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_FSL) += fsl_i2c.o
|
||||||
obj-$(CONFIG_SYS_I2C_IHS) += ihs_i2c.o
|
obj-$(CONFIG_SYS_I2C_IHS) += ihs_i2c.o
|
||||||
obj-$(CONFIG_SYS_I2C_INTEL) += intel_i2c.o
|
obj-$(CONFIG_SYS_I2C_INTEL) += intel_i2c.o
|
||||||
|
|
|
@ -13,34 +13,6 @@
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include "designware_i2c.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
|
#ifdef CONFIG_SYS_I2C_DW_ENABLE_STATUS_UNSUPPORTED
|
||||||
static int dw_i2c_enable(struct i2c_regs *i2c_base, bool enable)
|
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;
|
unsigned int ena;
|
||||||
int i2c_spd;
|
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;
|
i2c_spd = IC_SPEED_MODE_MAX;
|
||||||
else if (speed >= I2C_FAST_SPEED)
|
else if (speed >= I2C_FAST_SPEED)
|
||||||
i2c_spd = IC_SPEED_MODE_FAST;
|
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));
|
cntl = (readl(&i2c_base->ic_con) & (~IC_CON_SPD_MSK));
|
||||||
|
|
||||||
switch (i2c_spd) {
|
switch (i2c_spd) {
|
||||||
#ifndef CONFIG_X86 /* No High-speed for BayTrail yet */
|
|
||||||
case IC_SPEED_MODE_MAX:
|
case IC_SPEED_MODE_MAX:
|
||||||
cntl |= IC_CON_SPD_SS;
|
cntl |= IC_CON_SPD_SS;
|
||||||
if (scl_sda_cfg) {
|
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(hcnt, &i2c_base->ic_hs_scl_hcnt);
|
||||||
writel(lcnt, &i2c_base->ic_hs_scl_lcnt);
|
writel(lcnt, &i2c_base->ic_hs_scl_lcnt);
|
||||||
break;
|
break;
|
||||||
#endif
|
|
||||||
|
|
||||||
case IC_SPEED_MODE_STANDARD:
|
case IC_SPEED_MODE_STANDARD:
|
||||||
cntl |= IC_CON_SPD_SS;
|
cntl |= IC_CON_SPD_SS;
|
||||||
|
@ -565,25 +537,20 @@ static int designware_i2c_probe_chip(struct udevice *bus, uint chip_addr,
|
||||||
return ret;
|
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);
|
||||||
|
|
||||||
|
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);
|
struct dw_i2c *priv = dev_get_priv(bus);
|
||||||
int ret;
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = reset_get_bulk(bus, &priv->resets);
|
ret = reset_get_bulk(bus, &priv->resets);
|
||||||
if (ret)
|
if (ret)
|
||||||
dev_warn(bus, "Can't get reset: %d\n", ret);
|
dev_warn(bus, "Can't get reset: %d\n", ret);
|
||||||
|
@ -606,7 +573,7 @@ static int designware_i2c_probe(struct udevice *bus)
|
||||||
return __dw_i2c_init(priv->regs, 0, 0);
|
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);
|
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);
|
return reset_release_bulk(&priv->resets);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int designware_i2c_bind(struct udevice *dev)
|
const struct dm_i2c_ops designware_i2c_ops = {
|
||||||
{
|
|
||||||
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,
|
.xfer = designware_i2c_xfer,
|
||||||
.probe_chip = designware_i2c_probe_chip,
|
.probe_chip = designware_i2c_probe_chip,
|
||||||
.set_bus_speed = designware_i2c_set_bus_speed,
|
.set_bus_speed = designware_i2c_set_bus_speed,
|
||||||
|
@ -656,28 +600,12 @@ U_BOOT_DRIVER(i2c_designware) = {
|
||||||
.name = "i2c_designware",
|
.name = "i2c_designware",
|
||||||
.id = UCLASS_I2C,
|
.id = UCLASS_I2C,
|
||||||
.of_match = designware_i2c_ids,
|
.of_match = designware_i2c_ids,
|
||||||
.bind = designware_i2c_bind,
|
.ofdata_to_platdata = designware_i2c_ofdata_to_platdata,
|
||||||
.probe = designware_i2c_probe,
|
.probe = designware_i2c_probe,
|
||||||
.priv_auto_alloc_size = sizeof(struct dw_i2c),
|
.priv_auto_alloc_size = sizeof(struct dw_i2c),
|
||||||
.remove = designware_i2c_remove,
|
.remove = designware_i2c_remove,
|
||||||
.flags = DM_FLAG_OS_PREPARE,
|
.flags = DM_FLAG_OS_PREPARE,
|
||||||
.ops = &designware_i2c_ops,
|
.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 */
|
#endif /* CONFIG_DM_I2C */
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
#ifndef __DW_I2C_H_
|
#ifndef __DW_I2C_H_
|
||||||
#define __DW_I2C_H_
|
#define __DW_I2C_H_
|
||||||
|
|
||||||
|
#include <reset.h>
|
||||||
|
|
||||||
struct i2c_regs {
|
struct i2c_regs {
|
||||||
u32 ic_con; /* 0x00 */
|
u32 ic_con; /* 0x00 */
|
||||||
u32 ic_tar; /* 0x04 */
|
u32 ic_tar; /* 0x04 */
|
||||||
|
@ -131,4 +133,37 @@ struct i2c_regs {
|
||||||
#define I2C_FAST_SPEED 400000
|
#define I2C_FAST_SPEED 400000
|
||||||
#define I2C_STANDARD_SPEED 100000
|
#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_ */
|
#endif /* __DW_I2C_H_ */
|
||||||
|
|
79
drivers/i2c/designware_i2c_pci.c
Normal file
79
drivers/i2c/designware_i2c_pci.c
Normal file
|
@ -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);
|
Loading…
Reference in a new issue