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_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
|
||||
|
|
|
@ -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,25 +537,20 @@ 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);
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
if (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);
|
||||
}
|
||||
|
||||
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 */
|
||||
|
|
|
@ -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_ */
|
||||
|
|
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