小雷的学习空间
用硬件包围软件 最终实现软硬通吃

版权声明:本文为博主原创文章,未经博主允许不得转载。
博主按:大热的天,刚刚负重从五道口走到石板房,大约4公里吧。终于让我找了一个咖啡屋休息一下,继续写这篇驱动分析。单身的生活就是这样无聊啊。 不发牢骚了,活出个样儿来给自己看!千难万险脚下踩,啥也难不倒咱!继续整!~
先说一下,本文中有个疑惑,一直没有搞懂,写在这里,望高人指点一二,不胜感激!
#define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */
这里I2C_FUNC_PROTOCOL_MANGLING 是什么意思?为什么定义这些东东?看了注释也不太理解。求解释!
3. I2C总线驱动代码分析
s3c2440的总线驱动代码在i2c-s3c2410.c中。照例先从init看起。
- static int __init i2c_adap_s3c_init(void)
- {
- return platform_driver_register(&s3c24xx_i2c_driver);
- }
在init中只是调用了平台驱动注册函数注册了一个i2c的平台驱动s3c24xx_i2c_driver。这个驱动是一个platform_driver的结构体变量。注意这里不是i2c_driver结构体,因为i2c_driver是对设备的驱动,而这里对控制器的驱动要使用platform_driver
- static struct platform_driver s3c24xx_i2c_driver = {
- .probe = s3c24xx_i2c_probe,
- .remove = s3c24xx_i2c_remove,
- .suspend_late = s3c24xx_i2c_suspend_late,
- .resume = s3c24xx_i2c_resume,
- .id_table = s3c24xx_driver_ids,
- .driver = {
- .owner = THIS_MODULE,
- .name = "s3c-i2c",
- },
- };
同样的,重要的函数还是那几个:probe,remove,suspend_late,resume。再加上一个id_table和device_driver结构体变量。
下面逐个分析:
* probe函数
当调用platform_driver_register函数注册platform_driver结构体时,probe指针指向的s3c24xx_i2c_probe函数将会被调用。这部分详细解释参考本博客另一篇文章《S3C2410看门狗驱动分析》。细心的朋友可能会发现,在s3c24xx_i2c_driver中,驱动的名字是"s3c-i2c",而在板文件中可以看到,设备的名字是"s3c2410-i2c",这两个名字不一样,那驱动和设备是如何match的呢?答案就在于id_table。这个id_table包含了驱动所支持的设备ID表。在match的时候,判断这个表中的名字是不是和设备一致,一致则match成功。这也是为什么一个驱动可以同时match成功多个设备的原因。如果只是靠platform_driver-->driver中的名字来匹配的话,那么驱动和设备只能是一对一的关系了。
- static struct platform_device_id s3c24xx_driver_ids[] = {
- {
- .name = "s3c2410-i2c",
- .driver_data = TYPE_S3C2410,
- }, {
- .name = "s3c2440-i2c",
- .driver_data = TYPE_S3C2440,
- }, { },
- };
扯远了,还是看看probe的代码吧~
- static int s3c24xx_i2c_probe(struct platform_device *pdev)
- {
- struct s3c24xx_i2c *i2c;
- struct s3c2410_platform_i2c *pdata;
- struct resource *res;
- int ret;
- pdata = pdev->dev.platform_data;
- if (!pdata) {
- dev_err(&pdev->dev, "no platform data/n");
- return -EINVAL;
- }
- //给s3c24xx_i2c结构体申请空间
- i2c = kzalloc(sizeof(struct s3c24xx_i2c), GFP_KERNEL);
- if (!i2c) {
- dev_err(&pdev->dev, "no memory for state/n");
- return -ENOMEM;
- }
- //填充s3c24xx_i2c结构体中各项,包括名称、所有者、算法、所属class等等
- strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name));
- i2c->adap.owner = THIS_MODULE;
- i2c->adap.algo = &s3c24xx_i2c_algorithm; //这个下面会重点介绍
- i2c->adap.retries = 2;
- i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
- i2c->tx_setup = 50;
- spin_lock_init(&i2c->lock);
- init_waitqueue_head(&i2c->wait);
- /* find the clock and enable it */
- // 找到i2c始终并且使能它
- i2c->dev = &pdev->dev;
- i2c->clk = clk_get(&pdev->dev, "i2c");
- if (IS_ERR(i2c->clk)) {
- dev_err(&pdev->dev, "cannot get clock/n");
- ret = -ENOENT;
- goto err_noclk;
- }
- dev_dbg(&pdev->dev, "clock source %p/n", i2c->clk);
- clk_enable(i2c->clk);
- /* map the registers */
- /*映射寄存器*/
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL) {
- dev_err(&pdev->dev, "cannot find IO resource/n");
- ret = -ENOENT;
- goto err_clk;
- }
- i2c->ioarea = request_mem_region(res->start, resource_size(res),
- pdev->name);
- if (i2c->ioarea == NULL) {
- dev_err(&pdev->dev, "cannot request IO/n");
- ret = -ENXIO;
- goto err_clk;
- }
- i2c->regs = ioremap(res->start, resource_size(res));
- if (i2c->regs == NULL) {
- dev_err(&pdev->dev, "cannot map IO/n");
- ret = -ENXIO;
- goto err_ioarea;
- }
- dev_dbg(&pdev->dev, "registers %p (%p, %p)/n",
- i2c->regs, i2c->ioarea, res);
- /* setup info block for the i2c core */
- i2c->adap.algo_data = i2c;
- i2c->adap.dev.parent = &pdev->dev;
- /* initialise the i2c controller */
- /*s3c24xx_i2c结构体变量i2c的必要的信息都填充完了以后,开始进行初始化*/
- ret = s3c24xx_i2c_init(i2c);
- if (ret != 0)
- goto err_iomap;
- /* find the IRQ for this unit (note, this relies on the init call to
- * ensure no current IRQs pending
- */
- //接下来申请中断
- i2c->irq = ret = platform_get_irq(pdev, 0);
- if (ret <= 0) {
- dev_err(&pdev->dev, "cannot find IRQ/n");
- goto err_iomap;
- }
- ret = request_irq(i2c->irq, s3c24xx_i2c_irq, IRQF_DISABLED,
- dev_name(&pdev->dev), i2c);
- if (ret != 0) {
- dev_err(&pdev->dev, "cannot claim IRQ %d/n", i2c->irq);
- goto err_iomap;
- }
- ret = s3c24xx_i2c_register_cpufreq(i2c);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to register cpufreq notifier/n");
- goto err_irq;
- }
- /* Note, previous versions of the driver used i2c_add_adapter()
- * to add the bus at any number. We now pass the bus number via
- * the platform data, so if unset it will now default to always
- * being bus 0.
- */
- i2c->adap.nr = pdata->bus_num;
- //看到了吧?下面调用了i2c-core中的i2c_add_adapter函数来添加一个i2c控制器
- //i2c_add_numbered_adapter和i2c_add_adapter的区别在于前者用来添加一个在CPU内
- //部集成的适配器,而后者用来添加一个CPU外部的适配器。显然这里应该用前者。
- ret = i2c_add_numbered_adapter(&i2c->adap);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to add bus to i2c core/n");
- goto err_cpufreq;
- }
- platform_set_drvdata(pdev, i2c);
- dev_info(&pdev->dev, "%s: S3C I2C adapter/n", dev_name(&i2c->adap.dev));
- return 0;
- err_cpufreq:
- s3c24xx_i2c_deregister_cpufreq(i2c);
- err_irq:
- free_irq(i2c->irq, i2c);
- err_iomap:
- iounmap(i2c->regs);
- err_ioarea:
- release_resource(i2c->ioarea);
- kfree(i2c->ioarea);
- err_clk:
- clk_disable(i2c->clk);
- clk_put(i2c->clk);
- err_noclk:
- kfree(i2c);
- return ret;
- }
*remove函数
这是和probe相反的一个函数,在i2c_adap_s3c_exit时调用。主要功能是注销适配器,释放中断,释放内存区域,禁止始终等等。看到上边代码中的err_的各个部分了吧? remove是它们的汇总。
*suspend函数和resume函数
把这两个放一起说吧,挂起和恢复函数。挂起时保存状态并置标志位,恢复时重新初始化i2c适配器并置标志位。
Algorithm
哎呀我去,终于到这了。憋得我难受啊。这里要重点介绍一下,不仅要知其然,还要知其所以然,这样我们以后自己写驱动的时候就有把握了。
- static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
- .master_xfer = s3c24xx_i2c_xfer,
- .functionality = s3c24xx_i2c_func,
- };
这里实现的就是这个s3c24xx_i2c_xfer。这个是控制器能不能动作的关键,缺了这个,控制器就是废铜烂铁。
- static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
- struct i2c_msg *msgs, int num)
- {
- struct s3c24xx_i2c *i2c = (struct s3c24xx_i2c *)adap->algo_data;
- int retry;
- int ret;
- for (retry = 0; retry < adap->retries; retry++) {
- ret = s3c24xx_i2c_doxfer(i2c, msgs, num);
- if (ret != -EAGAIN)
- return ret;
- dev_dbg(i2c->dev, "Retrying transmission (%d)/n", retry);
- udelay(100);
- }
- return -EREMOTEIO;
- }
完成任务的函数是s3c24xx_i2c_doxfer(),源码清单如下,
- static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
- struct i2c_msg *msgs, int num)
- {
- unsigned long timeout;
- int ret;
- if (i2c->suspended)
- return -EIO;
- ret = s3c24xx_i2c_set_master(i2c);
- if (ret != 0) {
- dev_err(i2c->dev, "cannot get bus (error %d)/n", ret);
- ret = -EAGAIN;
- goto out;
- }
- spin_lock_irq(&i2c->lock);
- i2c->msg = msgs;
- i2c->msg_num = num;
- i2c->msg_ptr = 0;
- i2c->msg_idx = 0;
- i2c->state = STATE_START;
- s3c24xx_i2c_enable_irq(i2c);
- s3c24xx_i2c_message_start(i2c, msgs);
- spin_unlock_irq(&i2c->lock);
- timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
- ret = i2c->msg_idx;
- /* having these next two as dev_err() makes life very
- * noisy when doing an i2cdetect */
- if (timeout == 0)
- dev_dbg(i2c->dev, "timeout/n");
- else if (ret != num)
- dev_dbg(i2c->dev, "incomplete xfer (%d)/n", ret);
- /* ensure the stop has been through the bus */
- msleep(1);
- out:
- return ret;
- }
上面代码可以分成几个部分来看:
* s3c24xx_i2c_set_master() 这个函数每隔1ms查看一次i2c总线状态,timeout是400ms,如果在这期间总线状态不忙,则返回零。否则返回-ETIMEDOUT
* 将要发送的消息和其他信息付给i2c->msg和其他变量,并将状态设置为STATE_START
* s3c24xx_i2c_enable_irq() 使能中断
* s3c24xx_i2c_message_start() 重中之重啊。在看代码之前先来看看2440的datasheet上是怎么说的吧。
代码清单如下:
- static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,
- struct i2c_msg *msg)
- {
- unsigned int addr = (msg->addr & 0x7f) << 1;
- unsigned long stat;
- unsigned long iiccon;
- stat = 0;
- stat |= S3C2410_IICSTAT_TXRXEN;
- if (msg->flags & I2C_M_RD) {//如果是read data, from slave to master stat |= S3C2410_IICSTAT_MASTER_RX;
- addr |= 1;
- } else
- stat |= S3C2410_IICSTAT_MASTER_TX;
- if (msg->flags & I2C_M_REV_DIR_ADDR)
- addr ^= 1;
- /* todo - check for wether ack wanted or not */
- s3c24xx_i2c_enable_ack(i2c);
- iiccon = readl(i2c->regs + S3C2410_IICCON);
- writel(stat, i2c->regs + S3C2410_IICSTAT);
- dev_dbg(i2c->dev, "START: %08lx to IICSTAT, %02x to DS/n", stat, addr);
- writeb(addr, i2c->regs + S3C2410_IICDS);
- /* delay here to ensure the data byte has gotten onto the bus
- * before the transaction is started */
- ndelay(i2c->tx_setup);
- dev_dbg(i2c->dev, "iiccon, %08lx/n", iiccon);
- writel(iiccon, i2c->regs + S3C2410_IICCON);
- stat |= S3C2410_IICSTAT_START;
- writel(stat, i2c->regs + S3C2410_IICSTAT);
- }
(今天没写完啊,明天继续~)
-
顶
- 0
-
踩
- 0
-
猜你在找
核心技术类目
- 个人资料
-
- 访问:227557次
- 积分:2684
- 等级:
- 排名:第7731名
- 原创:44篇
- 转载:46篇
- 译文:1篇
- 评论:146条
- 文章搜索
- 文章分类
- 阅读排行
- (27925)
- (27116)
- (23994)
- (14318)
- (7520)
- (6097)
- (5082)
- (4937)
- (4751)
- (4551)
- 评论排行
- (53)
- (25)
- (10)
- (10)
- (8)
- (5)
- (4)
- (4)
- (3)
- (3)
- 最新评论
: 非常感谢,让我耳目一新, 后续三 还有么?
: 发错了,不好意思
: 都是内核里面的。。。
: Thanks 这个比较有用
: 您好,请问cbsize是怎么计算的,为什么32位系统就是28,64位系统就是32?多谢指教。。
: 您好,请问cbsize是怎么计算的?为啥32位系统就是28,64位系统就是32?多谢指教。。
: @phker:你是做什么行业的?
: @phker:我在技术上是挺顽固的,“顽固”我当做褒义词来听。哈哈哈
: 说真的,你老不要生气.我看到你照片的第一印象认为你是那种专注技术方向的技术顽固.不好沟通的人.看过你...
: 它山之石可以攻玉,减少“阶段0”的开发 注重核心技术,其余的外包这两点我深有体会啊.
小雷的学习空间
用硬件包围软件 最终实现软硬通吃

版权声明:本文为博主原创文章,未经博主允许不得转载。
博主按:大热的天,刚刚负重从五道口走到石板房,大约4公里吧。终于让我找了一个咖啡屋休息一下,继续写这篇驱动分析。单身的生活就是这样无聊啊。 不发牢骚了,活出个样儿来给自己看!千难万险脚下踩,啥也难不倒咱!继续整!~
先说一下,本文中有个疑惑,一直没有搞懂,写在这里,望高人指点一二,不胜感激!
#define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */
这里I2C_FUNC_PROTOCOL_MANGLING 是什么意思?为什么定义这些东东?看了注释也不太理解。求解释!
3. I2C总线驱动代码分析
s3c2440的总线驱动代码在i2c-s3c2410.c中。照例先从init看起。
- static int __init i2c_adap_s3c_init(void)
- {
- return platform_driver_register(&s3c24xx_i2c_driver);
- }
在init中只是调用了平台驱动注册函数注册了一个i2c的平台驱动s3c24xx_i2c_driver。这个驱动是一个platform_driver的结构体变量。注意这里不是i2c_driver结构体,因为i2c_driver是对设备的驱动,而这里对控制器的驱动要使用platform_driver
- static struct platform_driver s3c24xx_i2c_driver = {
- .probe = s3c24xx_i2c_probe,
- .remove = s3c24xx_i2c_remove,
- .suspend_late = s3c24xx_i2c_suspend_late,
- .resume = s3c24xx_i2c_resume,
- .id_table = s3c24xx_driver_ids,
- .driver = {
- .owner = THIS_MODULE,
- .name = "s3c-i2c",
- },
- };
同样的,重要的函数还是那几个:probe,remove,suspend_late,resume。再加上一个id_table和device_driver结构体变量。
下面逐个分析:
* probe函数
当调用platform_driver_register函数注册platform_driver结构体时,probe指针指向的s3c24xx_i2c_probe函数将会被调用。这部分详细解释参考本博客另一篇文章《S3C2410看门狗驱动分析》。细心的朋友可能会发现,在s3c24xx_i2c_driver中,驱动的名字是"s3c-i2c",而在板文件中可以看到,设备的名字是"s3c2410-i2c",这两个名字不一样,那驱动和设备是如何match的呢?答案就在于id_table。这个id_table包含了驱动所支持的设备ID表。在match的时候,判断这个表中的名字是不是和设备一致,一致则match成功。这也是为什么一个驱动可以同时match成功多个设备的原因。如果只是靠platform_driver-->driver中的名字来匹配的话,那么驱动和设备只能是一对一的关系了。
- static struct platform_device_id s3c24xx_driver_ids[] = {
- {
- .name = "s3c2410-i2c",
- .driver_data = TYPE_S3C2410,
- }, {
- .name = "s3c2440-i2c",
- .driver_data = TYPE_S3C2440,
- }, { },
- };
扯远了,还是看看probe的代码吧~
- static int s3c24xx_i2c_probe(struct platform_device *pdev)
- {
- struct s3c24xx_i2c *i2c;
- struct s3c2410_platform_i2c *pdata;
- struct resource *res;
- int ret;
- pdata = pdev->dev.platform_data;
- if (!pdata) {
- dev_err(&pdev->dev, "no platform data/n");
- return -EINVAL;
- }
- //给s3c24xx_i2c结构体申请空间
- i2c = kzalloc(sizeof(struct s3c24xx_i2c), GFP_KERNEL);
- if (!i2c) {
- dev_err(&pdev->dev, "no memory for state/n");
- return -ENOMEM;
- }
- //填充s3c24xx_i2c结构体中各项,包括名称、所有者、算法、所属class等等
- strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name));
- i2c->adap.owner = THIS_MODULE;
- i2c->adap.algo = &s3c24xx_i2c_algorithm; //这个下面会重点介绍
- i2c->adap.retries = 2;
- i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
- i2c->tx_setup = 50;
- spin_lock_init(&i2c->lock);
- init_waitqueue_head(&i2c->wait);
- /* find the clock and enable it */
- // 找到i2c始终并且使能它
- i2c->dev = &pdev->dev;
- i2c->clk = clk_get(&pdev->dev, "i2c");
- if (IS_ERR(i2c->clk)) {
- dev_err(&pdev->dev, "cannot get clock/n");
- ret = -ENOENT;
- goto err_noclk;
- }
- dev_dbg(&pdev->dev, "clock source %p/n", i2c->clk);
- clk_enable(i2c->clk);
- /* map the registers */
- /*映射寄存器*/
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL) {
- dev_err(&pdev->dev, "cannot find IO resource/n");
- ret = -ENOENT;
- goto err_clk;
- }
- i2c->ioarea = request_mem_region(res->start, resource_size(res),
- pdev->name);
- if (i2c->ioarea == NULL) {
- dev_err(&pdev->dev, "cannot request IO/n");
- ret = -ENXIO;
- goto err_clk;
- }
- i2c->regs = ioremap(res->start, resource_size(res));
- if (i2c->regs == NULL) {
- dev_err(&pdev->dev, "cannot map IO/n");
- ret = -ENXIO;
- goto err_ioarea;
- }
- dev_dbg(&pdev->dev, "registers %p (%p, %p)/n",
- i2c->regs, i2c->ioarea, res);
- /* setup info block for the i2c core */
- i2c->adap.algo_data = i2c;
- i2c->adap.dev.parent = &pdev->dev;
- /* initialise the i2c controller */
- /*s3c24xx_i2c结构体变量i2c的必要的信息都填充完了以后,开始进行初始化*/
- ret = s3c24xx_i2c_init(i2c);
- if (ret != 0)
- goto err_iomap;
- /* find the IRQ for this unit (note, this relies on the init call to
- * ensure no current IRQs pending
- */
- //接下来申请中断
- i2c->irq = ret = platform_get_irq(pdev, 0);
- if (ret <= 0) {
- dev_err(&pdev->dev, "cannot find IRQ/n");
- goto err_iomap;
- }
- ret = request_irq(i2c->irq, s3c24xx_i2c_irq, IRQF_DISABLED,
- dev_name(&pdev->dev), i2c);
- if (ret != 0) {
- dev_err(&pdev->dev, "cannot claim IRQ %d/n", i2c->irq);
- goto err_iomap;
- }
- ret = s3c24xx_i2c_register_cpufreq(i2c);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to register cpufreq notifier/n");
- goto err_irq;
- }
- /* Note, previous versions of the driver used i2c_add_adapter()
- * to add the bus at any number. We now pass the bus number via
- * the platform data, so if unset it will now default to always
- * being bus 0.
- */
- i2c->adap.nr = pdata->bus_num;
- //看到了吧?下面调用了i2c-core中的i2c_add_adapter函数来添加一个i2c控制器
- //i2c_add_numbered_adapter和i2c_add_adapter的区别在于前者用来添加一个在CPU内
- //部集成的适配器,而后者用来添加一个CPU外部的适配器。显然这里应该用前者。
- ret = i2c_add_numbered_adapter(&i2c->adap);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to add bus to i2c core/n");
- goto err_cpufreq;
- }
- platform_set_drvdata(pdev, i2c);
- dev_info(&pdev->dev, "%s: S3C I2C adapter/n", dev_name(&i2c->adap.dev));
- return 0;
- err_cpufreq:
- s3c24xx_i2c_deregister_cpufreq(i2c);
- err_irq:
- free_irq(i2c->irq, i2c);
- err_iomap:
- iounmap(i2c->regs);
- err_ioarea:
- release_resource(i2c->ioarea);
- kfree(i2c->ioarea);
- err_clk:
- clk_disable(i2c->clk);
- clk_put(i2c->clk);
- err_noclk:
- kfree(i2c);
- return ret;
- }
*remove函数
这是和probe相反的一个函数,在i2c_adap_s3c_exit时调用。主要功能是注销适配器,释放中断,释放内存区域,禁止始终等等。看到上边代码中的err_的各个部分了吧? remove是它们的汇总。
*suspend函数和resume函数
把这两个放一起说吧,挂起和恢复函数。挂起时保存状态并置标志位,恢复时重新初始化i2c适配器并置标志位。
Algorithm
哎呀我去,终于到这了。憋得我难受啊。这里要重点介绍一下,不仅要知其然,还要知其所以然,这样我们以后自己写驱动的时候就有把握了。
- static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
- .master_xfer = s3c24xx_i2c_xfer,
- .functionality = s3c24xx_i2c_func,
- };
这里实现的就是这个s3c24xx_i2c_xfer。这个是控制器能不能动作的关键,缺了这个,控制器就是废铜烂铁。
- static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
- struct i2c_msg *msgs, int num)
- {
- struct s3c24xx_i2c *i2c = (struct s3c24xx_i2c *)adap->algo_data;
- int retry;
- int ret;
- for (retry = 0; retry < adap->retries; retry++) {
- ret = s3c24xx_i2c_doxfer(i2c, msgs, num);
- if (ret != -EAGAIN)
- return ret;
- dev_dbg(i2c->dev, "Retrying transmission (%d)/n", retry);
- udelay(100);
- }
- return -EREMOTEIO;
- }
完成任务的函数是s3c24xx_i2c_doxfer(),源码清单如下,
- static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
- struct i2c_msg *msgs, int num)
- {
- unsigned long timeout;
- int ret;
- if (i2c->suspended)
- return -EIO;
- ret = s3c24xx_i2c_set_master(i2c);
- if (ret != 0) {
- dev_err(i2c->dev, "cannot get bus (error %d)/n", ret);
- ret = -EAGAIN;
- goto out;
- }
- spin_lock_irq(&i2c->lock);
- i2c->msg = msgs;
- i2c->msg_num = num;
- i2c->msg_ptr = 0;
- i2c->msg_idx = 0;
- i2c->state = STATE_START;
- s3c24xx_i2c_enable_irq(i2c);
- s3c24xx_i2c_message_start(i2c, msgs);
- spin_unlock_irq(&i2c->lock);
- timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
- ret = i2c->msg_idx;
- /* having these next two as dev_err() makes life very
- * noisy when doing an i2cdetect */
- if (timeout == 0)
- dev_dbg(i2c->dev, "timeout/n");
- else if (ret != num)
- dev_dbg(i2c->dev, "incomplete xfer (%d)/n", ret);
- /* ensure the stop has been through the bus */
- msleep(1);
- out:
- return ret;
- }
上面代码可以分成几个部分来看:
* s3c24xx_i2c_set_master() 这个函数每隔1ms查看一次i2c总线状态,timeout是400ms,如果在这期间总线状态不忙,则返回零。否则返回-ETIMEDOUT
* 将要发送的消息和其他信息付给i2c->msg和其他变量,并将状态设置为STATE_START
* s3c24xx_i2c_enable_irq() 使能中断
* s3c24xx_i2c_message_start() 重中之重啊。在看代码之前先来看看2440的datasheet上是怎么说的吧。
代码清单如下:
- static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,
- struct i2c_msg *msg)
- {
- unsigned int addr = (msg->addr & 0x7f) << 1;
- unsigned long stat;
- unsigned long iiccon;
- stat = 0;
- stat |= S3C2410_IICSTAT_TXRXEN;
- if (msg->flags & I2C_M_RD) {//如果是read data, from slave to master stat |= S3C2410_IICSTAT_MASTER_RX;
- addr |= 1;
- } else
- stat |= S3C2410_IICSTAT_MASTER_TX;
- if (msg->flags & I2C_M_REV_DIR_ADDR)
- addr ^= 1;
- /* todo - check for wether ack wanted or not */
- s3c24xx_i2c_enable_ack(i2c);
- iiccon = readl(i2c->regs + S3C2410_IICCON);
- writel(stat, i2c->regs + S3C2410_IICSTAT);
- dev_dbg(i2c->dev, "START: %08lx to IICSTAT, %02x to DS/n", stat, addr);
- writeb(addr, i2c->regs + S3C2410_IICDS);
- /* delay here to ensure the data byte has gotten onto the bus
- * before the transaction is started */
- ndelay(i2c->tx_setup);
- dev_dbg(i2c->dev, "iiccon, %08lx/n", iiccon);
- writel(iiccon, i2c->regs + S3C2410_IICCON);
- stat |= S3C2410_IICSTAT_START;
- writel(stat, i2c->regs + S3C2410_IICSTAT);
- }
(今天没写完啊,明天继续~)
-
顶
- 0
-
踩
- 0
-
猜你在找
-
25楼
terry_wang2003 2015-09-20 18:54发表
-
- 非常感谢,让我耳目一新, 后续三 还有么?
-
24楼
Healthy_蓝 2014-11-25 09:38发表
-
- 楼主啊,你倒是继续写撒...这葵花宝典看着难受啊...走火入魔中.....
-
23楼
guaiguaixiangai 2014-11-24 22:51发表
-
- 里面提到timeout = 400ms 是在哪里赋值的,在哪里看到的呀?
-
22楼
sdkhy0808 2014-07-05 13:21发表
-
- 我也期待着继续写下去呢
-
21楼
sdkhy0808 2014-07-05 13:20发表
-
- 转了哈
-
20楼
sdkhy0808 2014-07-05 13:20发表
-
- 赞!
-
19楼
云在青天水在瓶-_- 2013-08-10 00:33发表
-
-
先说一下,本文中有个疑惑,一直没有搞懂
这几个宏定义是GPIO模拟i2c总线算法实现用的
-
18楼
yuelengloulan 2013-06-17 14:36发表
-
- 楼主文章很精简清晰,怎么不继续写了啊
-
17楼
tian1112yong 2013-05-27 17:27发表
-
- 后续呢,楼主。
-
16楼
TC_CT 2013-04-09 11:57发表
-
- 博主居然没有坚持写完,唉,失望了
-
15楼
刘二傻 2013-04-01 17:36发表
-
- 怎么没有下面了吗?
-
14楼
kcchao 2012-11-05 17:40发表
-
- For I2C_FUNC_PROTOCOL_MANGLING, you can see the explanation in http://www.kernel.org/doc/Documentation/i2c/i2c-protocol
-
13楼
way 2012-08-02 23:44发表
-
- 写得很好,把总线驱动分析得不错,要是把设备驱动的几种写法都分析一下,那i2c驱动就算很完美了,不过现在的方法,不管是写总线驱动,还是设备驱动,都够了,不过三星公司的总线驱动太复杂
-
12楼
bbs598598 2012-07-31 15:56发表
-
- 顶一个,翘首等待
-
11楼
Ugly_Jorney 2012-07-24 14:13发表
-
- 顶起!
-
10楼
zgwstar 2012-07-20 20:06发表
-
- 太佩服楼主了 向楼主学习
-
9楼
jackylongchen 2012-06-15 16:19发表
-
- 来学习
-
8楼
maybe2101 2012-04-21 15:27发表
-
- 难道不会出后续了么?%>_<%
-
7楼
yhl2007kaka 2011-11-23 11:15发表
-
- 支持楼主!写的确实非常好!
-
6楼
junziyou1324325 2011-10-28 10:39发表
-
- 太期盼了!!楼主说的再详细一点吧!!
-
5楼
烂笔头 2011-10-11 09:54发表
-
- 楼主,请问一下如果从机是单片机而不是一个芯片应该怎么写驱动啊?
-
4楼
laobenzhuang1 2011-09-02 23:23发表
-
- 等待三、四的出现,楼主写的太好了
-
3楼
lwc92008 2011-08-10 12:30发表
-
-
关于I2C_M_NOSTART之类的困惑可以在
Document/i2c/i2c-protocol
文件找到说明。
-
2楼
yanyang_031 2011-07-27 15:19发表
-
- 翘首等待三、四的出现,楼主写的太好了~~
-
1楼
Quietly 2011-06-30 17:53发表
-
- [e03]
核心技术类目
- 个人资料
-
- 访问:227557次
- 积分:2684
- 等级:
- 排名:第7731名
- 原创:44篇
- 转载:46篇
- 译文:1篇
- 评论:146条
- 文章搜索
- 文章分类
- 阅读排行
- (27925)
- (27116)
- (23994)
- (14318)
- (7520)
- (6097)
- (5082)
- (4937)
- (4751)
- (4551)
- 评论排行
- (53)
- (25)
- (10)
- (10)
- (8)
- (5)
- (4)
- (4)
- (3)
- (3)
- 最新评论
: 非常感谢,让我耳目一新, 后续三 还有么?
: 发错了,不好意思
: 都是内核里面的。。。
: Thanks 这个比较有用
: 您好,请问cbsize是怎么计算的,为什么32位系统就是28,64位系统就是32?多谢指教。。
: 您好,请问cbsize是怎么计算的?为啥32位系统就是28,64位系统就是32?多谢指教。。
: @phker:你是做什么行业的?
: @phker:我在技术上是挺顽固的,“顽固”我当做褒义词来听。哈哈哈
: 说真的,你老不要生气.我看到你照片的第一印象认为你是那种专注技术方向的技术顽固.不好沟通的人.看过你...
: 它山之石可以攻玉,减少“阶段0”的开发 注重核心技术,其余的外包这两点我深有体会啊.
25楼 terry_wang2003 2015-09-20 18:54发表 [回复]-
-
非常感谢,让我耳目一新, 后续三 还有么?
24楼 Healthy_蓝 2014-11-25 09:38发表 [回复]-
-
楼主啊,你倒是继续写撒...这葵花宝典看着难受啊...走火入魔中.....
23楼 guaiguaixiangai 2014-11-24 22:51发表 [回复]-
-
里面提到timeout = 400ms 是在哪里赋值的,在哪里看到的呀?
22楼 sdkhy0808 2014-07-05 13:21发表 [回复]-
-
我也期待着继续写下去呢
21楼 sdkhy0808 2014-07-05 13:20发表 [回复]-
-
转了哈
20楼 sdkhy0808 2014-07-05 13:20发表 [回复]-
-
赞!
19楼 云在青天水在瓶-_- 2013-08-10 00:33发表 [回复]-
-
先说一下,本文中有个疑惑,一直没有搞懂
这几个宏定义是GPIO模拟i2c总线算法实现用的
18楼 yuelengloulan 2013-06-17 14:36发表 [回复]-
-
楼主文章很精简清晰,怎么不继续写了啊
17楼 tian1112yong 2013-05-27 17:27发表 [回复]-
-
后续呢,楼主。
16楼 TC_CT 2013-04-09 11:57发表 [回复]-
-
博主居然没有坚持写完,唉,失望了
15楼 刘二傻 2013-04-01 17:36发表 [回复]-
-
怎么没有下面了吗?
14楼 kcchao 2012-11-05 17:40发表 [回复]-
-
For I2C_FUNC_PROTOCOL_MANGLING, you can see the explanation in http://www.kernel.org/doc/Documentation/i2c/i2c-protocol
13楼 way 2012-08-02 23:44发表 [回复]-
-
写得很好,把总线驱动分析得不错,要是把设备驱动的几种写法都分析一下,那i2c驱动就算很完美了,不过现在的方法,不管是写总线驱动,还是设备驱动,都够了,不过三星公司的总线驱动太复杂
12楼 bbs598598 2012-07-31 15:56发表 [回复]-
-
顶一个,翘首等待
11楼 Ugly_Jorney 2012-07-24 14:13发表 [回复]-
-
顶起!
10楼 zgwstar 2012-07-20 20:06发表 [回复]-
-
太佩服楼主了 向楼主学习
9楼 jackylongchen 2012-06-15 16:19发表 [回复]-
-
来学习
8楼 maybe2101 2012-04-21 15:27发表 [回复]-
-
难道不会出后续了么?%>_<%
7楼 yhl2007kaka 2011-11-23 11:15发表 [回复]-
-
支持楼主!写的确实非常好!
6楼 junziyou1324325 2011-10-28 10:39发表 [回复]-
-
太期盼了!!楼主说的再详细一点吧!!
5楼 烂笔头 2011-10-11 09:54发表 [回复]-
-
楼主,请问一下如果从机是单片机而不是一个芯片应该怎么写驱动啊?
4楼 laobenzhuang1 2011-09-02 23:23发表 [回复]-
-
等待三、四的出现,楼主写的太好了
3楼 lwc92008 2011-08-10 12:30发表 [回复]-
-
关于I2C_M_NOSTART之类的困惑可以在
Document/i2c/i2c-protocol
文件找到说明。
2楼 yanyang_031 2011-07-27 15:19发表 [回复]-
-
翘首等待三、四的出现,楼主写的太好了~~
1楼 Quietly 2011-06-30 17:53发表 [回复]-
-
[e03]