drivers/i2c/i2c_dw.c: rewrite for PCI(e) support

The legacy PCI support in the DesignWare I2C driver is replaced with
the new PCIe support. The Intel Quark X1000 SoC and the galileo board
configurations are updated accordingly.

Signed-off-by: Charles E. Youse <charles.youse@intel.com>
This commit is contained in:
Charles E. Youse 2019-05-16 15:33:09 -07:00 committed by Anas Nashif
commit 309dfef511
9 changed files with 86 additions and 122 deletions

View file

@ -40,7 +40,7 @@ config GPIO_PCAL9535A_0_DEV_NAME
config GPIO_PCAL9535A_0_I2C_ADDR
default 0x25
config GPIO_PCAL9535A_0_I2C_MASTER_DEV_NAME
default "$(dt_str_val,DT_SNPS_DESIGNWARE_I2C_90007000_LABEL)"
default "$(dt_str_val,DT_SNPS_DESIGNWARE_I2C_0_LABEL)"
endif # GPIO_PCAL9535A_0
@ -54,7 +54,7 @@ config GPIO_PCAL9535A_1_DEV_NAME
config GPIO_PCAL9535A_1_I2C_ADDR
default 0x26
config GPIO_PCAL9535A_1_I2C_MASTER_DEV_NAME
default "$(dt_str_val,DT_SNPS_DESIGNWARE_I2C_90007000_LABEL)"
default "$(dt_str_val,DT_SNPS_DESIGNWARE_I2C_0_LABEL)"
endif # GPIO_PCAL9535A_1
@ -68,7 +68,7 @@ config GPIO_PCAL9535A_2_DEV_NAME
config GPIO_PCAL9535A_2_I2C_ADDR
default 0x27
config GPIO_PCAL9535A_2_I2C_MASTER_DEV_NAME
default "$(dt_str_val,DT_SNPS_DESIGNWARE_I2C_90007000_LABEL)"
default "$(dt_str_val,DT_SNPS_DESIGNWARE_I2C_0_LABEL)"
endif # GPIO_PCAL9535A_2
@ -93,7 +93,7 @@ config PWM_PCA9685_0_DEV_NAME
config PWM_PCA9685_0_I2C_ADDR
default 0x47
config PWM_PCA9685_0_I2C_MASTER_DEV_NAME
default "$(dt_str_val,DT_SNPS_DESIGNWARE_I2C_90007000_LABEL)"
default "$(dt_str_val,DT_SNPS_DESIGNWARE_I2C_0_LABEL)"
endif # PWM_PCA9685_0
endif # PWM_PCA9685

View file

@ -17,7 +17,6 @@ CONFIG_PINMUX=y
CONFIG_I2C=y
CONFIG_I2C_DW=y
CONFIG_I2C_0=y
CONFIG_I2C_DW_0_IRQ_SHARED=y
CONFIG_GPIO_PCAL9535A=y
CONFIG_GPIO_SCH=y
CONFIG_GPIO_SCH_0=y

View file

@ -22,28 +22,4 @@ config I2C_DW_CLOCK_SPEED
int "Set the clock speed for I2C"
default 32
config I2C_DW_SHARED_IRQ
bool
choice
prompt "I2C_0 Interrupts via"
default I2C_DW_0_IRQ_DIRECT
depends on I2C_0
config I2C_DW_0_IRQ_DIRECT
bool "Direct Hardware Interrupt"
help
When interrupts fire, the driver's ISR function is being called
directly.
config I2C_DW_0_IRQ_SHARED
bool "Shared IRQ"
depends on SHARED_IRQ
select I2C_DW_SHARED_IRQ
help
When interrupts fire, the shared IRQ driver is notified.
Then the shared IRQ driver dispatches the interrupt to other drivers.
endchoice
endif # I2C_DW

View file

@ -22,10 +22,6 @@
#include <misc/util.h>
#ifdef CONFIG_SHARED_IRQ
#include <shared_irq.h>
#endif
#ifdef CONFIG_IOAPIC
#include <drivers/ioapic.h>
#endif
@ -198,16 +194,6 @@ static void i2c_dw_isr(void *arg)
*/
intr_stat.raw = regs->ic_intr_stat.raw;
#if CONFIG_SHARED_IRQ
/* If using with shared IRQ, this function will be called
* by the shared IRQ driver. So check here if the interrupt
* is coming from the I2C controller (or somewhere else).
*/
if (!intr_stat.raw) {
return;
}
#endif
/*
* Causes of an interrupt:
* - STOP condition is detected
@ -620,43 +606,23 @@ static const struct i2c_driver_api funcs = {
.transfer = i2c_dw_transfer,
};
#ifdef CONFIG_PCI
static inline int i2c_dw_pci_setup(struct device *dev)
{
struct i2c_dw_dev_config * const dw = dev->driver_data;
pci_bus_scan_init();
if (!pci_bus_scan(&dw->pci_dev)) {
LOG_DBG("Could not find device");
return 0;
}
#ifdef CONFIG_PCI_ENUMERATION
dw->base_address = dw->pci_dev.addr;
#endif
pci_enable_regs(&dw->pci_dev);
pci_show(&dw->pci_dev);
return 1;
}
#else
#define i2c_dw_pci_setup(_unused_) (1)
#endif /* CONFIG_PCI */
static int i2c_dw_initialize(struct device *dev)
{
const struct i2c_dw_rom_config * const rom = dev->config->config_info;
struct i2c_dw_dev_config * const dw = dev->driver_data;
volatile struct i2c_dw_registers *regs;
if (!i2c_dw_pci_setup(dev)) {
dev->driver_api = NULL;
return -EIO;
#ifdef I2C_DW_PCIE_ENABLED
if (rom->pcie) {
if (!pcie_probe(rom->pcie_bdf, rom->pcie_id)) {
return -EINVAL;
}
dw->base_address = pcie_get_mbar(rom->pcie_bdf, 0);
pcie_set_cmd(rom->pcie_bdf, PCIE_CONF_CMDSTAT_MEM, true);
}
#endif
k_sem_init(&dw->device_sync_sem, 0, UINT_MAX);
regs = (struct i2c_dw_registers *) dw->base_address;

View file

@ -11,10 +11,18 @@
#include <i2c.h>
#include <stdbool.h>
#ifdef CONFIG_PCI
#include <pci/pci.h>
#include <pci/pci_mgr.h>
#endif /* CONFIG_PCI */
#if DT_SNPS_DESIGNWARE_I2C_0_PCIE || \
DT_SNPS_DESIGNWARE_I2C_1_PCIE || \
DT_SNPS_DESIGNWARE_I2C_2_PCIE || \
DT_SNPS_DESIGNWARE_I2C_3_PCIE || \
DT_SNPS_DESIGNWARE_I2C_4_PCIE || \
DT_SNPS_DESIGNWARE_I2C_5_PCIE || \
DT_SNPS_DESIGNWARE_I2C_6_PCIE || \
DT_SNPS_DESIGNWARE_I2C_7_PCIE
BUILD_ASSERT_MSG(IS_ENABLED(CONFIG_PCIE), "DW I2C in DT needs CONFIG_PCIE");
#define I2C_DW_PCIE_ENABLED
#include <drivers/pcie/pcie.h>
#endif
#ifdef __cplusplus
extern "C" {
@ -86,15 +94,14 @@ typedef void (*i2c_isr_cb_t)(struct device *port);
struct i2c_dw_rom_config {
i2c_isr_cb_t config_func;
#ifdef CONFIG_I2C_DW_SHARED_IRQ
char *shared_irq_dev_name;
#endif /* CONFIG_I2C_DW_SHARED_IRQ */
u32_t bitrate;
#ifdef I2C_DW_PCIE_ENABLED
bool pcie;
pcie_bdf_t pcie_bdf;
pcie_id_t pcie_id;
#endif /* I2C_DW_PCIE_ENABLED */
};
struct i2c_dw_dev_config {
u32_t base_address;
struct k_sem device_sync_sem;
@ -112,9 +119,6 @@ struct i2c_dw_dev_config {
u8_t request_bytes;
u8_t xfr_flags;
bool support_hs_mode;
#ifdef CONFIG_PCI
struct pci_dev_info pci_dev;
#endif /* CONFIG_PCI */
};
#ifdef __cplusplus

View file

@ -10,24 +10,17 @@ static void i2c_config_@NUM@(struct device *port);
static const struct i2c_dw_rom_config i2c_config_dw_@NUM@ = {
.config_func = i2c_config_@NUM@,
#ifdef CONFIG_I2C_DW_@NUM@_IRQ_SHARED
.shared_irq_dev_name = DT_I2C_DW_@NUM@_IRQ_SHARED_NAME,
#endif
.bitrate = DT_SNPS_DESIGNWARE_I2C_@NUM@_CLOCK_FREQUENCY,
#if DT_SNPS_DESIGNWARE_I2C_@NUM@_PCIE
.pcie = true,
.pcie_bdf = DT_SNPS_DESIGNWARE_I2C_@NUM@_BASE_ADDRESS,
.pcie_id = DT_SNPS_DESIGNWARE_I2C_@NUM@_SIZE,
#endif
};
static struct i2c_dw_dev_config i2c_@NUM@_runtime = {
.base_address = DT_SNPS_DESIGNWARE_I2C_@NUM@_BASE_ADDRESS,
#if CONFIG_PCI
.pci_dev.class_type = I2C_DW_@NUM@_PCI_CLASS,
.pci_dev.bus = I2C_DW_@NUM@_PCI_BUS,
.pci_dev.dev = I2C_DW_@NUM@_PCI_DEV,
.pci_dev.vendor_id = I2C_DW_@NUM@_PCI_VENDOR_ID,
.pci_dev.device_id = I2C_DW_@NUM@_PCI_DEVICE_ID,
.pci_dev.function = I2C_DW_@NUM@_PCI_FUNCTION,
.pci_dev.bar = I2C_DW_@NUM@_PCI_BAR,
#endif
.base_address = DT_SNPS_DESIGNWARE_I2C_@NUM@_BASE_ADDRESS
};
DEVICE_AND_API_INIT(i2c_@NUM@, DT_SNPS_DESIGNWARE_I2C_@NUM@_LABEL,
@ -41,19 +34,51 @@ DEVICE_AND_API_INIT(i2c_@NUM@, DT_SNPS_DESIGNWARE_I2C_@NUM@_LABEL,
#endif
static void i2c_config_@NUM@(struct device *port)
{
#if defined(CONFIG_I2C_DW_@NUM@_IRQ_SHARED)
const struct i2c_dw_rom_config * const config =
port->config->config_info;
struct device *shared_irq_dev;
ARG_UNUSED(port);
#if DT_SNPS_DESIGNWARE_I2C_@NUM@_PCIE
#if DT_SNPS_DESIGNWARE_I2C_@NUM@_IRQ_0 == PCIE_IRQ_DETECT
/* PCI(e) with auto IRQ detection */
BUILD_ASSERT_MSG(IS_ENABLED(CONFIG_DYNAMIC_INTERRUPTS),
"DW I2C PCI auto-IRQ needs CONFIG_DYNAMIC_INTERRUPTS");
unsigned int irq;
irq = pcie_wired_irq(DT_SNPS_DESIGNWARE_I2C_@NUM@_BASE_ADDRESS);
if (irq == PCIE_CONF_INTR_IRQ_NONE) {
return;
}
irq_connect_dynamic(irq,
DT_SNPS_DESIGNWARE_I2C_@NUM@_IRQ_0_PRIORITY,
i2c_dw_isr, DEVICE_GET(i2c_@NUM@),
DT_SNPS_DESIGNWARE_I2C_@NUM@_IRQ_0_SENSE);
pcie_irq_enable(DT_SNPS_DESIGNWARE_I2C_@NUM@_BASE_ADDRESS, irq);
shared_irq_dev = device_get_binding(config->shared_irq_dev_name);
shared_irq_isr_register(shared_irq_dev, (isr_t)i2c_dw_isr, port);
shared_irq_enable(shared_irq_dev, port);
#else
/* PCI(e) with fixed or MSI IRQ */
IRQ_CONNECT(DT_SNPS_DESIGNWARE_I2C_@NUM@_IRQ_0,
DT_SNPS_DESIGNWARE_I2C_@NUM@_IRQ_0_PRIORITY,
i2c_dw_isr, DEVICE_GET(i2c_@NUM@),
DT_SNPS_DESIGNWARE_I2C_@NUM@_IRQ_0_SENSE);
pcie_irq_enable(DT_SNPS_DESIGNWARE_I2C_@NUM@_BASE_ADDRESS,
DT_SNPS_DESIGNWARE_I2C_@NUM@_IRQ_0);
#endif
#else
/* not PCI(e) */
IRQ_CONNECT(DT_SNPS_DESIGNWARE_I2C_@NUM@_IRQ_0,
DT_SNPS_DESIGNWARE_I2C_@NUM@_IRQ_0_PRIORITY,
i2c_dw_isr, DEVICE_GET(i2c_@NUM@),
DT_SNPS_DESIGNWARE_I2C_@NUM@_IRQ_0_SENSE);
irq_enable(DT_SNPS_DESIGNWARE_I2C_@NUM@_IRQ_0);
#endif
}

View file

@ -29,4 +29,9 @@ properties:
description: required interrupts
generation: define
pcie:
type: boolean
category: optional
description: attached via PCI(e) bus
generation: define
...

View file

@ -69,13 +69,14 @@
status = "disabled";
};
i2c0: i2c@90007000 {
i2c0: i2c@0 {
compatible = "snps,designware-i2c";
clock-frequency = <I2C_BITRATE_STANDARD>;
#address-cells = <1>;
#size-cells = <0>;
reg = <0x90007000 0x400>;
interrupts = <18 IRQ_TYPE_LEVEL_LOW 2>;
pcie;
reg = <PCIE_BDF(0,21,2) PCIE_ID(0x8086,0x0934)>;
interrupts = <25 IRQ_TYPE_LEVEL_LOW 2>;
interrupt-parent = <&intc>;
label = "I2C_0";

View file

@ -85,18 +85,6 @@
#define DT_GPIO_DW_0_IRQ_FLAGS (IOAPIC_LEVEL | IOAPIC_LOW)
#endif
/*
* I2C
*/
#define I2C_DW_0_PCI_VENDOR_ID 0x8086
#define I2C_DW_0_PCI_DEVICE_ID 0x0934
#define I2C_DW_0_PCI_CLASS 0x0C
#define I2C_DW_0_PCI_BUS 0
#define I2C_DW_0_PCI_DEV 21
#define I2C_DW_0_PCI_FUNCTION 2
#define I2C_DW_0_PCI_BAR 0
#ifdef CONFIG_IOAPIC
#define UART_IRQ_FLAGS (IOAPIC_LEVEL | IOAPIC_LOW)
#endif /* CONFIG_IOAPIC */