全部博文(51)
分类: LINUX
2016-06-03 17:52:21
struct bus_type i2c_bus_type = {
.name = "i2c",
.match = i2c_device_match,
.probe = i2c_device_probe,
.remove = i2c_device_remove,
.shutdown = i2c_device_shutdown,
.pm = &i2c_device_pm_ops,
};
static int __init i2c_init(void)
{
int retval;
retval = bus_register(&i2c_bus_type); //注册i2c类型的bus;创建目录/sys/bus/i2c/, /sys/bus/i2c/devices, /sys/bus/i2c/drivers, uevent, drivers_probe, drivers_autoprobe
if (retval)
return retval;
#ifdef CONFIG_I2C_COMPAT
i2c_adapter_compat_class = class_compat_register("i2c-adapter");
if (!i2c_adapter_compat_class) {
retval = -ENOMEM;
goto bus_err;
}
#endif
retval = i2c_add_driver(&dummy_driver);
if (retval)
goto class_err;
return 0;
......
}
|
postcore_initcall(i2c_init); |
|
MACHINE_START(AVANTA_LP, "Marvell AvantaLP 88f66xx Board")
.atag_offset = BOOT_PARAMS_OFFSET,
.map_io = alp_map_io,
.init_irq = alp_irq_init,
.timer = &alp_timer,
.handle_irq = gic_handle_irq,
.init_machine = alp_board_init,
.restart = board_restart,
.dma_zone_size = SZ_64M,
MACHINE_END
|
#define MACHINE_START(_type,_name) \
static const struct machine_desc __mach_desc_##_type \
__used \
__attribute__((__section__(".arch.info.init"))) = { \
.nr = MACH_TYPE_##_type, \
.name = _name,
#define MACHINE_END \
};
|
static void __init alp_i2c_init(void)
{
#ifdef CONFIG_I2C_MV64XXX
if (mvUnitMapIsMine(I2C0) == MV_TRUE)
platform_device_register(&alp_i2c0);
if (mvCtrlSocUnitInfoNumGet(I2C_UNIT_ID) > 1 &&
mvUnitMapIsMine(I2C1) == MV_TRUE)
platform_device_register(&alp_i2c1);
#endif
}
|
static struct mv64xxx_i2c_pdata alp_i2c_pdata = {
.freq_m = 8, /* assumes 166 MHz TCLK */
.freq_n = 3,
.timeout = 1000, /* Default timeout of 1 second */
};
static struct resource alp_i2c_0_resources[] = {
{
.name = "i2c base",
.start = INTER_REGS_PHYS_BASE + MV_TWSI_SLAVE_REGS_OFFSET(0),
.end = INTER_REGS_PHYS_BASE + MV_TWSI_SLAVE_REGS_OFFSET(0) + 0x20 - 1,
.flags = IORESOURCE_MEM,
},
{
.name = "i2c irq",
.start = IRQ_GLOBAL_I2C0,
.end = IRQ_GLOBAL_I2C0,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device alp_i2c0 = {
.name = MV64XXX_I2C_CTLR_NAME, //"mv64xxx_i2c"
.id = 0,
.num_resources = ARRAY_SIZE(alp_i2c_0_resources),
.resource = alp_i2c_0_resources,
.dev = {
.platform_data = &alp_i2c_pdata,
},
};
|
int platform_device_add(struct platform_device *pdev)
{
if (!pdev->dev.parent)
pdev->dev.parent = &platform_bus; //"platform",
pdev->dev.bus = &platform_bus_type;
if (pdev->id != -1)
dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); //设备名 dev->kobj.name“mv64xxx_i2c.0”
else
dev_set_name(&pdev->dev, "%s", pdev->name);
for (i = 0; i < pdev->num_resources; i++) {
/*检查分配resource是否合法*/
}
ret = device_add(&pdev->dev);
if (ret == 0)
return ret;
......
}
|
int device_add(struct device *dev)
{
dev = get_device(dev); //这样写的目的是增加设备引用计数
if (!dev->p) { //分配struct device_private *p结构
error = device_private_init(dev);
if (error)
goto done;
}
parent = get_device(dev->parent); //同样是增加parent引用计数, “platform"
kobj = get_device_parent(dev, parent);
if (kobj)
dev->kobj.parent = kobj; //parent`s kobj
error = kobject_add(&dev->kobj, dev->kobj.parent, NULL); //创建/sys/devices/platform/mv64XXX_i2c.0节点
if (error)
goto Error;
/*创建 /sys/devices/platform/mv64XXX_i2c.0/ 下的文件及链接 */
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_ADD_DEVICE, dev); //发送消息通知链
kobject_uevent(&dev->kobj, KOBJ_ADD); //uevent消息;
bus_probe_device(dev); //probe drivers for a new device
if (parent)
klist_add_tail(&dev->p->knode_parent, //knode_parent建立device和parent的关联
&parent->p->klist_children);
}
|
module_init(i2c_dev_init);
#define I2C_MAJOR 89
static const struct file_operations i2cdev_fops = { //i2c设备的文件操作函数
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = i2cdev_read,
.write = i2cdev_write,
.unlocked_ioctl = i2cdev_ioctl,
.open = i2cdev_open,
.release = i2cdev_release,
};
|
static int __init i2c_dev_init(void)
{
res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);
i2c_dev_class = class_create(THIS_MODULE, "i2c-dev"); //创建设备类,/sys/class/i2c-dev/
res = bus_register_notifier(&i2c_bus_type, &i2cdev_notifier); //注册消息通知链
i2c_for_each_dev(NULL, i2cdev_attach_adapter); //对i2c_bus_type总线上注册的设备调用i2cdev_attach_adapter, 此时还没有该类型总线设备;
}
|
static struct platform_driver mv64xxx_i2c_driver = {
.probe = mv64xxx_i2c_probe,
.remove = __devexit_p(mv64xxx_i2c_remove),
.driver = {
.owner = THIS_MODULE,
.name = MV64XXX_I2C_CTLR_NAME, //#define MV64XXX_I2C_CTLR_NAME "mv64xxx_i2c"
},
};
module_platform_driver(mv64xxx_i2c_driver);
|
#define module_platform_driver(__platform_driver) \ //这个宏目的是对模块init和exit操作进行封装
module_driver(__platform_driver, platform_driver_register, \
platform_driver_unregister)
|
#define module_driver(__driver, __register, __unregister, ...) \
static int __init __driver##_init(void) \
{ \
return __register(&(__driver) , ##__VA_ARGS__); \
} \
module_init(__driver##_init); \
static void __exit __driver##_exit(void) \
{ \
__unregister(&(__driver) , ##__VA_ARGS__); \
} \
module_exit(__driver##_exit);
|
int platform_driver_register(struct platform_driver *drv)
{
drv->driver.bus = &platform_bus_type;
if (drv->probe)
drv->driver.probe = platform_drv_probe;
if (drv->remove)
drv->driver.remove = platform_drv_remove;
if (drv->shutdown)
drv->driver.shutdown = platform_drv_shutdown;
return driver_register(&drv->driver);
}
|
int driver_register(struct device_driver *drv)
{
int ret;
struct device_driver *other;
BUG_ON(!drv->bus->p);
if ((drv->bus->probe && drv->probe) ||
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown))
printk(KERN_WARNING "Driver '%s' needs updating - please use "
"bus_type methods\n", drv->name);
other = driver_find(drv->name, drv->bus); //检查驱动是否已经注册过了,若注册了则other非NULL;
if (other) {
printk(KERN_ERR "Error: Driver '%s' is already registered, "
"aborting...\n", drv->name);
return -EBUSY;
}
ret = bus_add_driver(drv); //add the driver to the bus
if (ret)
return ret;
ret = driver_add_groups(drv, drv->groups);
if (ret)
bus_remove_driver(drv);
return ret;
}
|
int bus_add_driver(struct device_driver *drv)
{
。。。。。。
bus = bus_get(drv->bus);
priv = kzalloc(sizeof(*priv), GFP_KERNEL); //驱动私有信息
if (!priv) {
error = -ENOMEM;
goto out_put_bus;
}
klist_init(&priv->klist_devices, NULL, NULL);
priv->driver = drv;
drv->p = priv; //priv与driver关联
priv->kobj.kset = bus->p->drivers_kset; //驱动kobject与bus的kset
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL, //在/sys/bus/platform/drivers/下创建目录
"%s", drv->name);
if (error)
goto out_unregister;
if (drv->bus->p->drivers_autoprobe) { //drivers_autoprobe默认为1
error = driver_attach(drv);
if (error)
goto out_unregister;
}
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); //driver的klist_node结构,添加到bus对应的klist_drivers列表;
module_add_driver(drv->owner, drv);
。。。。。。
}
|
int driver_attach(struct device_driver *drv)
{
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); //每个设备调用__driver_attach
}
|
static int __driver_attach(struct device *dev, void *data)
{
if (!driver_match_device(drv, dev)) //调用platform_match,检查设备id 是否在驱动支持的id列表内;通过设备ID或者设备name来检测;
return 0;
if (dev->parent) /* Needed for USB */
device_lock(dev->parent);
device_lock(dev);
if (!dev->driver) //driver为NULL, 说明没有加载过驱动
driver_probe_device(drv, dev);
device_unlock(dev);
if (dev->parent)
device_unlock(dev->parent);
return 0;
}
|
static int really_probe(struct device *dev, struct device_driver *drv)
{
。。。。。。
dev->driver = drv; //设备关联驱动
if (driver_sysfs_add(dev)) { //生成sys下目录
printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
__func__, dev_name(dev));
goto probe_failed;
}
if (dev->bus->probe) { //bus无probe
ret = dev->bus->probe(dev);
if (ret)
goto probe_failed;
} else if (drv->probe) {
ret = drv->probe(dev); //调用驱动probe,这里是 mv64xxx_i2c_probe
if (ret)
goto probe_failed;
}
driver_bound(dev); //设备关联到driver的klist_devices;
。。。。。。
}
|
static int __devinit
mv64xxx_i2c_probe(struct platform_device *pd)
{
struct mv64xxx_i2c_data *drv_data; //设备对应驱动的私有信息
struct mv64xxx_i2c_pdata *pdata = pd->dev.platform_data; //平台相关数据
drv_data = kzalloc(sizeof(struct mv64xxx_i2c_data), GFP_KERNEL);
if (!drv_data)
return -ENOMEM;
if (mv64xxx_i2c_map_regs(pd, drv_data)) { //寄存器地址映射
rc = -ENODEV;
goto exit_kfree;
}
strlcpy(drv_data->adapter.name, MV64XXX_I2C_CTLR_NAME " adapter",
sizeof(drv_data->adapter.name)); //"mv64xxx_i2c adapter"
/*初始化wait队列和自旋锁*/
init_waitqueue_head(&drv_data->waitq);
spin_lock_init(&drv_data->lock);
/*私有数据初始化*/
drv_data->freq_m = pdata->freq_m;
drv_data->freq_n = pdata->freq_n;
drv_data->irq = platform_get_irq(pd, 0);
if (drv_data->irq < 0) {
rc = -ENXIO;
goto exit_unmap_regs;
}
drv_data->adapter.dev.parent = &pd->dev; //parent为mv64xxx_i2c.0
drv_data->adapter.algo = &mv64xxx_i2c_algo;
drv_data->adapter.owner = THIS_MODULE;
drv_data->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
drv_data->adapter.timeout = msecs_to_jiffies(pdata->timeout);
drv_data->adapter.nr = pd->id; //i2c-%d
platform_set_drvdata(pd, drv_data); //pdev->dev->p->driver_data = drv_data; 设备私有信息中的驱动数据赋值;
i2c_set_adapdata(&drv_data->adapter, drv_data);
mv64xxx_i2c_hw_init(drv_data); //硬件初始化
if (request_irq(drv_data->irq, mv64xxx_i2c_intr, 0, /*注册中断处理函数, 若没有出错的话继续执行 else if*/
MV64XXX_I2C_CTLR_NAME, drv_data)) {
dev_err(&drv_data->adapter.dev,
"mv64xxx: Can't register intr handler irq: %d\n",
drv_data->irq);
rc = -EINVAL;
goto exit_unmap_regs;
} else if ((rc = i2c_add_numbered_adapter(&drv_data->adapter)) != 0) {
dev_err(&drv_data->adapter.dev,
"mv64xxx: Can't add i2c adapter, rc: %d\n", -rc);
goto exit_free_irq;
}
。。。。。。
}
|
static int i2c_register_adapter(struct i2c_adapter *adap)
{
/*合法性检查*/
......
dev_set_name(&adap->dev, "i2c-%d", adap->nr);
adap->dev.bus = &i2c_bus_type; //bus为 i2c
adap->dev.type = &i2c_adapter_type;
res = device_register(&adap->dev); //注册设备, /sys/devices/platform/mv64xxx_i2c.0/i2c-0/ 在device_add中,会调用i2c相关的bus通知链;即调用i2cdev_attach_adapter; 该设备会加入到i2c bus的bus->p->klist_drivers
if (res)
goto out_list;
}
|
static int i2cdev_attach_adapter(struct device *dev, void *dummy)
{
adap = to_i2c_adapter(dev);
i2c_dev = get_free_i2c_dev(adap); //每个i2c_dev代表一个i2c适配器
if (IS_ERR(i2c_dev))
return PTR_ERR(i2c_dev);
/* register this i2c device with the driver core */
i2c_dev->dev = device_create(i2c_dev_class, &adap->dev, //i2c-dev类i2c_dev_class,“i2c-dev”,最后还是会调用device_add
MKDEV(I2C_MAJOR, adap->nr), NULL,
"i2c-%d", adap->nr);
......
}
|
device_add
if (MAJOR(dev->devt)) {
error = device_create_file(dev, &devt_attr);
if (error)
goto ueventattrError;
error = device_create_sys_dev_entry(dev);
if (error)
goto devtattrError;
devtmpfs_create_node(dev);
}
|
cat /sys/devices/platform/mv64xxx_i2c.0/ i2c-0/i2c-dev/i2c-0/dev
89:0
|
#ONT/system/shell>cat /proc/interrupts
CPU0 CPU1
29: 3929395 3665693 GIC twd
34: 268898 0 GIC mv64xxx_i2c
35: 0 0 GIC mv64xxx_i2c
41: 16 0 GIC alp_clk_evt
44: 2668 0 GIC serial
48: 0 0 GIC xhci-hcd:usb3
49: 0 0 GIC ehci_hcd:usb2
50: 0 0 GIC ehci_hcd:usb1
54: 2 0 GIC mv_xor.0
|
#ONT/system/shell>pwd
/sys/bus/i2c
#ONT/system/shell>ls -l
total 0
drwxr-xr-x 2 root root 0 Jan 1 00:16 devices
drwxr-xr-x 3 root root 0 Jan 1 00:16 drivers
-rw-r--r-- 1 root root 4096 Jan 1 00:16 drivers_autoprobe
--w------- 1 root root 4096 Jan 1 00:16 drivers_probe
--w------- 1 root root 4096 Jan 1 00:16 uevent
#ONT/system/shell>pwd
/sys/devices/platform/mv64xxx_i2c.0
#ONT/system/shell>
#ONT/system/shell>ls
driver i2c-0 modalias subsystem uevent
#ONT/system/shell>cat i2c-0/name
mv64xxx_i2c adapter
#ONT/system/shell>ls i2c-0/i2c-dev
i2c-0
#ONT/system/shell>ls i2c-0/i2c-dev/i2c-0
dev device name subsystem uevent
#ONT/system/shell>cat i2c-0/i2c-dev/i2c-0/name
mv64xxx_i2c adapter
#ONT/system/shell>pwd
/sys/bus/platform
#ONT/system/shell>
#ONT/system/shell>
#ONT/system/shell>
#ONT/system/shell>ls -l
total 0
drwxr-xr-x 2 root root 0 Jan 1 05:15 devices
drwxr-xr-x 18 root root 0 Jan 1 00:19 drivers
-rw-r--r-- 1 root root 4096 Jan 1 05:15 drivers_autoprobe
--w------- 1 root root 4096 Jan 1 05:15 drivers_probe
--w------- 1 root root 4096 Jan 1 05:15 uevent
#ONT/system/shell>ls -l devices
total 0
lrwxrwxrwx 1 root root 0 Jan 1 05:15 alarmtimer -> ../../../devices/platform/alarmtimer
lrwxrwxrwx 1 root root 0 Jan 1 05:15 alp-temp.0 -> ../../../devices/platform/alp-temp.0
lrwxrwxrwx 1 root root 0 Jan 1 05:15 arm-pmu.0 -> ../../../devices/platform/arm-pmu.0
lrwxrwxrwx 1 root root 0 Jan 1 05:15 armada-nand.0 -> ../../../devices/platform/armada-nand.0
lrwxrwxrwx 1 root root 0 Jan 1 05:15 ehci_marvell.0 -> ../../../devices/platform/ehci_marvell.0
lrwxrwxrwx 1 root root 0 Jan 1 05:15 ehci_marvell.1 -> ../../../devices/platform/ehci_marvell.1
lrwxrwxrwx 1 root root 0 Jan 1 05:15 mv64xxx_i2c.0 -> ../../../devices/platform/mv64xxx_i2c.0
lrwxrwxrwx 1 root root 0 Jan 1 05:15 mv64xxx_i2c.1 -> ../../../devices/platform/mv64xxx_i2c.1
lrwxrwxrwx 1 root root 0 Jan 1 05:15 mv_gpio.0 -> ../../../devices/platform/mv_gpio.0
lrwxrwxrwx 1 root root 0 Jan 1 05:15 mv_pex.0 -> ../../../devices/platform/mv_pex.0
lrwxrwxrwx 1 root root 0 Jan 1 05:15 mv_pp2_port.0 -> ../../../devices/platform/mv_pp2_port.0
lrwxrwxrwx 1 root root 0 Jan 1 05:15 mv_pp2_port.1 -> ../../../devices/platform/mv_pp2_port.1
lrwxrwxrwx 1 root root 0 Jan 1 05:15 mv_pp2_port.2 -> ../../../devices/platform/mv_pp2_port.2
lrwxrwxrwx 1 root root 0 Jan 1 05:15 mv_pp2_port.3 -> ../../../devices/platform/mv_pp2_port.3
lrwxrwxrwx 1 root root 0 Jan 1 05:15 mv_switch.0 -> ../../../devices/platform/mv_switch.0
lrwxrwxrwx 1 root root 0 Jan 1 05:15 mv_xor.0 -> ../../../devices/platform/mv_xor.0
lrwxrwxrwx 1 root root 0 Jan 1 05:15 mv_xor.1 -> ../../../devices/platform/mv_xor.1
lrwxrwxrwx 1 root root 0 Jan 1 05:15 mv_xor.2 -> ../../../devices/platform/mv_xor.2
lrwxrwxrwx 1 root root 0 Jan 1 05:15 mv_xor.3 -> ../../../devices/platform/mv_xor.3
lrwxrwxrwx 1 root root 0 Jan 1 05:15 mv_xor_shared.0 -> ../../../devices/platform/mv_xor_shared.0
lrwxrwxrwx 1 root root 0 Jan 1 05:15 mv_xor_shared.1 -> ../../../devices/platform/mv_xor_shared.1
lrwxrwxrwx 1 root root 0 Jan 1 05:15 mvsdio -> ../../../devices/platform/mvsdio
lrwxrwxrwx 1 root root 0 Jan 1 05:15 orion_wdt -> ../../../devices/platform/orion_wdt
lrwxrwxrwx 1 root root 0 Jan 1 05:15 pon -> ../../../devices/platform/pon
lrwxrwxrwx 1 root root 0 Jan 1 05:15 pp2 -> ../../../devices/platform/pp2
lrwxrwxrwx 1 root root 0 Jan 1 05:15 rtc-mv -> ../../../devices/platform/rtc-mv
lrwxrwxrwx 1 root root 0 Jan 1 05:15 serial8250 -> ../../../devices/platform/serial8250
lrwxrwxrwx 1 root root 0 Jan 1 05:15 serial8250.0 -> ../../../devices/platform/serial8250.0
lrwxrwxrwx 1 root root 0 Jan 1 05:15 tpm -> ../../../devices/platform/tpm
lrwxrwxrwx 1 root root 0 Jan 1 05:15 xhci-hcd -> ../../../devices/platform/xhci-hcd
#ONT/system/shell>ls -l drivers
total 0
drwxr-xr-x 2 root root 0 Jan 1 05:16 alarmtimer
drwxr-xr-x 2 root root 0 Jan 1 05:16 arm-pmu
drwxr-xr-x 2 root root 0 Jan 1 05:16 armada-nand
drwxr-xr-x 2 root root 0 Jan 1 05:16 dw-apb-uart
drwxr-xr-x 2 root root 0 Jan 1 05:16 ehci_marvell
drwxr-xr-x 2 root root 0 Jan 1 00:19 mv64xxx_i2c
drwxr-xr-x 2 root root 0 Jan 1 05:16 mv_gpio
drwxr-xr-x 2 root root 0 Jan 1 05:16 mv_pex
drwxr-xr-x 2 root root 0 Jan 1 05:16 mv_pp2_port
drwxr-xr-x 2 root root 0 Jan 1 05:16 mv_switch
drwxr-xr-x 2 root root 0 Jan 1 05:16 mv_xor
drwxr-xr-x 2 root root 0 Jan 1 05:16 mv_xor_shared
drwxr-xr-x 2 root root 0 Jan 1 05:16 orion_wdt
drwxr-xr-x 2 root root 0 Jan 1 05:16 physmap-flash
drwxr-xr-x 2 root root 0 Jan 1 05:16 serial8250
drwxr-xr-x 2 root root 0 Jan 1 05:16 xhci-hcd
|