medfield 平台中,i2c总线,通过pci总线来配置。
代码位于: /drivers/i2c/busses/i2c-designware-pcidrv.c 中
1. 首先是pci 设备表:
static struct dw_pci_controller dw_pci_controllers[] = {
[moorestown_0] = {
.bus_num = 0,
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
.clk_khz = 25000,
},
[moorestown_1] = {
.bus_num = 1,
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
.clk_khz = 25000,
},
[moorestown_2] = {
.bus_num = 2,
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
.clk_khz = 25000,
},
#ifdef FIXME_MLD // DV0.9 changes to match the GB tree
[medfield_0] = {
.bus_num = 0,
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
.clk_khz = 25000,
},
[medfield_1] = {
.bus_num = 1,
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
.clk_khz = 25000,
},
[medfield_2] = {
.bus_num = 2,
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
.clk_khz = 25000,
},
[medfield_3] = {
.bus_num = 3,
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_STD,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
.clk_khz = 25000,
},
[medfield_4] = {
.bus_num = 4,
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
.clk_khz = 25000,
},
[medfield_5] = {
.bus_num = 5,
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
.clk_khz = 25000,
},
#else
[medfield_0] = {
.bus_num = 0,
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_STD,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
.clk_khz = 17000,
},
[medfield_1] = {
.bus_num = 1,
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
.clk_khz = 25000,
},
[medfield_2] = {
.bus_num = 2,
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
.clk_khz = 25000,
},
[medfield_3] = {
.bus_num = 3,
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_STD,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
.clk_khz = 25000,
},
[medfield_4] = {
.bus_num = 4,
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
.clk_khz = 25000,
},
[medfield_5] = {
.bus_num = 5,
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
.clk_khz = 25000,
},
#endif
};
2. 代码开始,注册PCI 驱动:
static int __init dw_i2c_init_driver(void)
{
return pci_register_driver(&dw_i2c_driver); //把dw_i2c_driver 注册进pci总线。
}
module_init(dw_i2c_init_driver);
static void __exit dw_i2c_exit_driver(void)
{
pci_unregister_driver(&dw_i2c_driver);
}
module_exit(dw_i2c_exit_driver);
MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
MODULE_DESCRIPTION("Synopsys DesignWare PCI I2C bus adapter");
MODULE_LICENSE("GPL");
dw_i2c_driver 内容:
static struct pci_driver dw_i2c_driver = {
.name = DRIVER_NAME,
.id_table = i2_designware_pci_ids,
.probe = i2c_dw_pci_probe,
.remove = __devexit_p(i2c_dw_pci_remove),
.driver = {
.pm = &i2c_dw_pm_ops,
},
};
3. DRIVER_NAME:
#define DRIVER_NAME "i2c-designware-pci"
4. i2_designware_pci_ids: pci的设备表。
DEFINE_PCI_DEVICE_TABLE(i2_designware_pci_ids) = {
/* Moorestown */
{ PCI_VDEVICE(INTEL, 0x0802), moorestown_0 },
{ PCI_VDEVICE(INTEL, 0x0803), moorestown_1 },
{ PCI_VDEVICE(INTEL, 0x0804), moorestown_2 },
/* Medfield */
{ PCI_VDEVICE(INTEL, 0x0817), medfield_3,},
{ PCI_VDEVICE(INTEL, 0x0818), medfield_4 },
{ PCI_VDEVICE(INTEL, 0x0819), medfield_5 },
{ PCI_VDEVICE(INTEL, 0x082C), medfield_0 },
{ PCI_VDEVICE(INTEL, 0x082D), medfield_1 },
{ PCI_VDEVICE(INTEL, 0x082E), medfield_2 },
{ 0,}
};
MODULE_DEVICE_TABLE(pci, i2_designware_pci_ids);
5. i2c_dw_pci_probe()
static int __devinit i2c_dw_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
struct dw_i2c_dev *dev;
struct i2c_adapter *adap;
unsigned long start, len;
void __iomem *base;
int r;
struct dw_pci_controller *controller;
if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) {
printk(KERN_ERR "dw_i2c_pci_probe: invalid driver data %ld\n",
id->driver_data);
return -EINVAL;
}
controller = &dw_pci_controllers[id->driver_data];
r = pci_enable_device(pdev);
if (r) {
dev_err(&pdev->dev, "Failed to enable I2C PCI device (%d)\n",
r);
goto exit;
}
/* Determine the address of the I2C area */
start = pci_resource_start(pdev, 0);
len = pci_resource_len(pdev, 0);
if (!start || len == 0) {
dev_err(&pdev->dev, "base address not set\n");
r = -ENODEV;
goto exit;
}
r = pci_request_region(pdev, 0, DRIVER_NAME);
if (r) {
dev_err(&pdev->dev, "failed to request I2C region "
"0x%lx-0x%lx\n", start,
(unsigned long)pci_resource_end(pdev, 0));
goto exit;
}
base = ioremap_nocache(start, len);
if (!base) {
dev_err(&pdev->dev, "I/O memory remapping failed\n");
r = -ENOMEM;
goto err_release_region;
}
dev = kzalloc(sizeof(struct dw_i2c_dev), GFP_KERNEL);
6. i2c_dw_pm_ops :
static const struct dev_pm_ops i2c_dw_pm_ops = {
.resume = i2c_dw_pci_resume,
.suspend = i2c_dw_pci_suspend,
SET_RUNTIME_PM_OPS(i2c_dw_pci_suspend,
i2c_dw_pci_resume,
i2c_dw_pci_runtime_idle)
};