设为首页 加入收藏

TOP

Linux下CPU注册i2c控制器(adapter)过程(一)
2014-11-24 08:07:52 来源: 作者: 【 】 浏览:3
Tags:Linux CPU 注册 i2c 控制器 adapter 过程

无论是三星的s3c2410, 还是cavium 的octeon, AMD的amd8111等等, 任何处理器在linux下添加自己的adapter都是大致的方法, 都是实现自己的driver, 最后调用i2c-core提供的API完成整个注册. 广泛地讲, linux将任何类型的设备, 任何类型的总线等都作为文件来处理, 只不过使用了不同的数据结构的driver和device.


I2c的逻辑简单实用. 在linux精妙的架构下, 代码量非常小. 现在大部分的IC都有I2C接口. 至于spi, uart, can, usb, pci, stat等等各种各样的, 虽然协议不同, 特点不用, 但本质上都是一样的.


至于I2C具体的协议, 时序等请参考其他资料. 这里只做软件上的架构分析.


下面以octeon处理器为例, 重点介绍下octeon_i2c_probe()中部分重要的代码, 在其他处理器的xxx_i2c_probe() 函数中, 无论是获取设备资源, 获取中断, CPU时钟, 配置adapter 等等操作在任何处理器中的步骤大致都是相同的, 也都是不可或缺的.


By 韩大卫@吉林师范大学


内核代码drivers/i2c/busses/i2c-octeon.c



static int __init octeon_i2c_init(void)
{
int rv; /*
i2c 控制器是被集成在CPU上的, 寄存器地址可以被CPU直接寻址到, linux将这个adapter抽象为一个platfrom device , 其驱动使用数据结构: struct platfrom_driver. 一般将usb host, serial 控制器等也做同样处理.
实现好driver后, 使用 platform_driver_register()函数将其注册到linux内核的设备树中.
*/ rv = platform_driver_register(&octeon_i2c_driver);
return rv;
}


static struct platform_driver octeon_i2c_driver = {
.probe = octeon_i2c_probe,


.remove = __devexit_p(octeon_i2c_remove),
.driver = {
.owner = THIS_MODULE,
.name = DRV_NAME,
.of_match_table = octeon_i2c_match,
},
};


#define DRV_NAME "i2c-octeon"



static int __devinit octeon_i2c_probe(struct platform_device *pdev)
{
int irq, result = 0;
struct octeon_i2c *i2c;
struct resource *res_mem;
const __be32 *data;
int len;


/*
获取设备的中断号
*/
/* All adaptors have an irq. */
irq = platform_get_irq(pdev, 0);



/*
为其数据结构分配内存
*/
i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
if (!i2c) {
dev_err(&pdev->dev, "kzalloc failed\n");
result = -ENOMEM;
goto out;
}
i2c->dev = &pdev->dev;

/* platform_driver_register() 注册时会对所有已注册的所有 platform_device 中的 name 和当前注册的 platform_driver 的driver.name 进行比较,只有找到相同的名称的 platfomr_device 才能注册成功,当注册成功时会调用 platform_driver 结构元素 probe 函数指针,这里就是octeon_i2c_probe(), 当进入 probe 函数后,需要获取设备的资源信息,常用获取资源的函数主要是:structresource * platform_get_resource(struct platform_device *dev,unsigned int type, unsigned int num);


根据参数 type 所指定类型,例如 IORESOURCE_MEM ,来获取指定的资源,即获取设备的IO资源地址.


*/
res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);


if (res_mem == NULL) {
dev_err(i2c->dev, "found no memory resource\n");
result = -ENXIO;
goto fail_region;
}


i2c->twsi_phys = res_mem->start;
i2c->regsize = resource_size(res_mem);

data = of_get_property(pdev->dev.of_node, "clock-rate", &len);
if (data && len == sizeof(*data)) {
/*
设置I2C时钟频率
*/
i2c->twsi_freq = be32_to_cpup(data);
} else {
dev_err(i2c->dev, "no I2C 'clock-rate' property\n");
result = -ENXIO;
goto fail_region;
}


/*
设置I2C系统IO时钟频率
*/
i2c->sys_freq = octeon_get_io_clock_rate();


/*
申请IO域
*/
if (!devm_request_mem_region(&pdev->dev, i2c->twsi_phys, i2c->regsize,
res_mem->name)) {
dev_err(i2c->dev, "request_mem_region failed\n");
goto fail_region;
}


/*
申请成功后将其映射到内核空间.
*/
i2c->twsi_base = ioremap(i2c->twsi_phys, i2c->regsize);


/*
初始化I2C的等待队列
*/
init_waitqueue_head(&i2c->queue);



i2c->irq = irq;

/*
注册I2C的中断号
*/
result = request_irq(i2c->irq, octeon_i2c_isr, 0, DRV_NAME, i2c);
if (result < 0) {
dev_err(i2c->dev, "fa

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇shell脚本--Linux终端运行Hadoop-.. 下一篇UNIX中的restrict

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

·TCP/UDP协议_百度百科 (2025-12-26 12:20:11)
·什么是TCP和UDP协议 (2025-12-26 12:20:09)
·TCP和UDP详解 (非常 (2025-12-26 12:20:06)
·Python 教程 - W3Sch (2025-12-26 12:00:51)
·Python基础教程,Pyt (2025-12-26 12:00:48)