rk3588 i2c algorithm 分析

来了来了,上次分析完i2c的驱动框架 今天我们就看看i2c的algorithm是如何实现的

  1. static const struct i2c_algorithm rk3x_i2c_algorithm = {
  2. .master_xfer = rk3x_i2c_xfer,
  3. .master_xfer_atomic = rk3x_i2c_xfer_polling,
  4. .functionality = rk3x_i2c_func,
  5. };

我们就分析master_xfer 函数怎么实现的把。 .functionality比较简单大家可以自己看看了解一下

直接步入正题把。

1.1 i2c时序

首先给大家说一下发送i2c时序的步骤把

  1. 发送一个其实信号
  2. 发送7bit设备地址再加1bit读写.最低为1表示读,0为写
  3. 主机发送完一个从机地址,假设设备是存在的此时为给设备发送一个ACK应答位
  4. 发送寄存器地址 8bit数据 如果你的数据是 16bit 那就发两次呗。
  5. 发送一个8bit 等待ACK,在发送一个就在等一个ACK
  6. 之后发送数据 最多是32位 所以还是要注意的。发送8bit就等一个ACK 这是必须的
  7. 下来发送一个停止信号。

1.1.1 起始信号

SCL位高 SDA 来一个下降沿 之后就开始通信把。

1.1.2 数据信号

SCL 为高电平,数据有效。

1.1.3 应答信号

SCL为高 的第9bit 为高 则代表有效 如果ACK没有应答 在驱动中则将停止通信了。

1.1.4 停止信号

SCL为高电平 SDA来个上升沿 就结束了。

这样总结很简单把根据这个我们都可以自己手画了一个时序图了。

好了 有了这些 我们就分析驱动吧。

rk3x_i2c_xfer他调用的式 rk3x_i2c_xfer_common 代码很多我们一句一句看

  1. static int rk3x_i2c_xfer_common(struct i2c_adapter *adap,
  2. struct i2c_msg *msgs, int num, bool polling)
  3. {
  4. struct rk3x_i2c *i2c = (struct rk3x_i2c *)adap->algo_data;
  5. unsigned long timeout, flags;
  6. u32 val;
  7. int ret = 0;
  8. int i;
  9. if (i2c->suspended)
  10. return -EACCES;
  11. spin_lock_irqsave(&i2c->lock, flags); //保存本地中断状态 关闭中断
  12. clk_enable(i2c->clk); //使能了两个时钟
  13. clk_enable(i2c->pclk);
  14. i2c->is_last_msg = false; //把最后一个消息置为否
  15. /*
  16. * Process msgs. We can handle more than one message at once (see
  17. * rk3x_i2c_setup()).
  18. */
  19. for (i = 0; i < num; i += ret) { //这个num 就是r/w的个数
  20. ret = rk3x_i2c_setup(i2c, msgs + i, num - i); //大概说一下干什么 下面分析 就是判断寄存器地址是否为16bit
  21. if (ret < 0) {
  22. dev_err(i2c->dev, "rk3x_i2c_setup() failed\n");
  23. break;
  24. }
  25. if (i + ret >= num) //判断 当前i+ret(已经传输的个数如果大于) num了 那么就是最后一个信号了 是不是停止信号呢?
  26. i2c->is_last_msg = true;
  27. rk3x_i2c_start(i2c); // 下面分析 大概说一下 就是配置接收发送中断
  28. spin_unlock_irqrestore(&i2c->lock, flags);
  29. if (!polling) { //这个是是否阻塞 如果超时阻塞 那么等待唤醒
  30. timeout = wait_event_timeout(i2c->wait, !i2c->busy,
  31. msecs_to_jiffies(WAIT_TIMEOUT));
  32. } else { //这个暂时不分析了
  33. timeout = rk3x_i2c_wait_xfer_poll(i2c);
  34. }
  35. spin_lock_irqsave(&i2c->lock, flags);
  36. if (timeout == 0) { //返回0了 那就超时了
  37. dev_err(i2c->dev, "timeout, ipd: 0x%02x, state: %d\n",
  38. i2c_readl(i2c, REG_IPD), i2c->state);
  39. /* Force a STOP condition without interrupt */
  40. rk3x_i2c_disable_irq(i2c); //关闭中断
  41. val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK; //读取 i2c控制器控制寄存器 保存 是否停止配置设置寄存器
  42. val |= REG_CON_EN | REG_CON_STOP; //0x1001 意思是使能i2c模块 并产生一个i2c停止信号
  43. i2c_writel(i2c, val, REG_CON); //写入控制寄存器
  44. i2c->state = STATE_IDLE; //设置为空闲状态
  45. ret = -ETIMEDOUT; //返回超时错误码
  46. break;
  47. }
  48. if (i2c->error) {
  49. ret = i2c->error;
  50. break;
  51. }
  52. }
  53. rk3x_i2c_disable_irq(i2c); //禁用中断
  54. rk3x_i2c_disable(i2c); //除了 保存停止配置设置寄存器的值 剩下都置为0 意思就是把所有都关闭了
  55. clk_disable(i2c->pclk); //关闭时钟
  56. clk_disable(i2c->clk);
  57. spin_unlock_irqrestore(&i2c->lock, flags);
  58. return ret < 0 ? ret : num;
  59. }

看一下 rk3x_i2c_setup

  1. static int rk3x_i2c_setup(struct rk3x_i2c *i2c, struct i2c_msg *msgs, int num)
  2. {
  3. u32 addr = (msgs[0].addr & 0x7f) << 1; //地址左移1bit 这不就和协议对上了 7bit+r/w 位
  4. int ret = 0;
  5. /*
  6. * The I2C adapter can issue a small (len < 4) write packet before
  7. * reading. This speeds up SMBus-style register reads.
  8. * The MRXADDR/MRXRADDR hold the slave address and the slave register
  9. * address in this case.
  10. */
  11. if (num >= 2 && msgs[0].len < 4 &&
  12. !(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD)) { //就是16bit的寄存器
  13. u32 reg_addr = 0;
  14. int i;
  15. dev_dbg(i2c->dev, "Combined write/read from addr 0x%x\n",
  16. addr >> 1);
  17. /* Fill MRXRADDR with the register address(es) */
  18. for (i = 0; i < msgs[0].len; ++i) {
  19. reg_addr |= msgs[0].buf[i] << (i * 8);
  20. reg_addr |= REG_MRXADDR_VALID(i);
  21. } //硬件操作发送16bit寄存器地址
  22. /* msgs[0] is handled by hw. */
  23. i2c->msg = &msgs[1];
  24. i2c->mode = REG_CON_MOD_REGISTER_TX;
  25. i2c_writel(i2c, addr | REG_MRXADDR_VALID(0), REG_MRXADDR); //下来发送数据
  26. i2c_writel(i2c, reg_addr, REG_MRXRADDR);
  27. ret = 2;
  28. } else {
  29. /*
  30. * We'll have to do it the boring way and process the msgs
  31. * one-by-one.
  32. */
  33. if (msgs[0].flags & I2C_M_RD) {
  34. addr |= 1; /* set read bit */ //设置了一个读位
  35. /*
  36. * We have to transmit the slave addr first. Use
  37. * MOD_REGISTER_TX for that purpose.
  38. */
  39. i2c->mode = REG_CON_MOD_REGISTER_TX;
  40. i2c_writel(i2c, addr | REG_MRXADDR_VALID(0),
  41. REG_MRXADDR);
  42. i2c_writel(i2c, 0, REG_MRXRADDR);
  43. } else {
  44. i2c->mode = REG_CON_MOD_TX;
  45. }
  46. i2c->msg = &msgs[0];
  47. ret = 1;
  48. }
  49. i2c->addr = msgs[0].addr;
  50. i2c->busy = true;
  51. i2c->processed = 0;
  52. i2c->error = 0;
  53. rk3x_i2c_clean_ipd(i2c);
  54. if (i2c->autostop_supported)
  55. i2c_writel(i2c, 0, REG_CON1);
  56. return ret;
  57. }

看一下 rk3x_i2c_start

  1. static void rk3x_i2c_start(struct rk3x_i2c *i2c)
  2. {
  3. u32 val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK;
  4. bool auto_stop = rk3x_i2c_auto_stop(i2c);
  5. int length = 0;
  6. /* enable appropriate interrupts */
  7. if (i2c->mode == REG_CON_MOD_TX) {
  8. if (!auto_stop) { //使能发送中断
  9. i2c_writel(i2c, REG_INT_MBTF | REG_INT_NAKRCV, REG_IEN);
  10. i2c->state = STATE_WRITE;
  11. }
  12. length = rk3x_i2c_fill_transmit_buf(i2c, false);
  13. } else {
  14. /* in any other case, we are going to be reading. */
  15. if (!auto_stop) {
  16. i2c_writel(i2c, REG_INT_MBRF | REG_INT_NAKRCV, REG_IEN); //使能接受中断
  17. i2c->state = STATE_READ;
  18. }
  19. }
  20. /* enable adapter with correct mode, send START condition */
  21. val |= REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START;
  22. /* if we want to react to NACK, set ACTACK bit */
  23. if (!(i2c->msg->flags & I2C_M_IGNORE_NAK))
  24. val |= REG_CON_ACTACK;
  25. i2c_writel(i2c, val, REG_CON);
  26. /* enable transition */
  27. if (i2c->mode == REG_CON_MOD_TX)
  28. i2c_writel(i2c, length, REG_MTXCNT); //使能接受或者发送
  29. else
  30. rk3x_i2c_prepare_read(i2c);
  31. }

差一个irq 明天继续 记录一下思路 开启中断后 每次 将会填充 发送或者接受 数据寄存器 当满了之后呢么保存数据 或者发送 都保存在 msg->buf 里了 这就是所谓了i2c通信算法 就是根据协议去写 更清楚的了解了 i2c协议

基于rk3588----i2c驱动框架学习(2)-总线驱动 algorithm 分析的更多相关文章

  1. RT Thread的SPI设备驱动框架的使用以及内部机制分析

    注释:这是19年初的博客,写得很一般,理解不到位也不全面.19年末得空时又重新看了RTThread的SPI和GPIO,这次理解得比较深刻.有时间时再整理上传. -------------------- ...

  2. Android 框架学习2:源码分析 EventBus 3.0 如何实现事件总线

    Go beyond yourself rather than beyond others. 上篇文章 深入理解 EventBus 3.0 之使用篇 我们了解了 EventBus 的特性以及如何使用,这 ...

  3. Linux 驱动框架---cdev字符设备驱动和misc杂项设备驱动

    字符设备 Linux中设备常见分类是字符设备,块设备.网络设备,其中字符设备也是Linux驱动中最常用的设备类型.因此开发Linux设备驱动肯定是要先学习一下字符设备的抽象的.在内核中使用struct ...

  4. Linux 驱动框架---i2c驱动框架

    i2c驱动在Linux通过一个周的学习后发现i2c总线的驱动框架还是和Linux整体的驱动框架是相同的,思想并不特殊比较复杂的内容如i2c核心的内容都是内核驱动框架实现完成的,今天我们暂时只分析驱动开 ...

  5. I2C驱动框架(kernel-2.6.22.6)

    以用i2c通信的实时时钟为例 框架入口源文件:i2c_m41t11.c (可根据入口源文件,再按着框架到内核走一遍) 内核版本:linux_2.6.22.6   硬件平台:JZ2440 以下是驱动框架 ...

  6. spi驱动框架全面分析,从master驱动到设备驱动

    内核版本:linux2.6.32.2  硬件资源:s3c2440 参考:  韦东山SPI视频教程 内容概括:     1.I2C 驱动框架回顾     2.SPI 框架简单介绍     3.maste ...

  7. 驱动框架入门——以LED为例[【转】

    本文转载自;http://blog.csdn.net/oqqHuTu12345678/article/details/72783903 以下内容源于朱有鹏<物联网大讲堂>课程的学习,如有侵 ...

  8. lcd驱动框架

    目录 lcd驱动框架 框图 程序分析 入口 打开open 读read 初始化registered_fb 注册 小结 程序设计 测试 方式一操作fb0 方式二操作tty 方式三操作终端 完整程序 tit ...

  9. linux-2.6.38 IIC驱动框架分析

    在linux-2.6内核中,IIC的驱动程序可以大概分为三部分: (1)IIC核心代码:/drivers/i2c/i2c-core.c IIC核心提供了IIC总线驱动和设备驱动的注册.注销方法和IIC ...

  10. Linux驱动框架之framebuffer驱动框架

    1.什么是framebuffer? (1)framebuffer帧缓冲(一屏幕数据)(简称fb)是linux内核中虚拟出的一个设备,framebuffer向应用层提供一个统一标准接口的显示设备.帧缓冲 ...

随机推荐

  1. Java设计模式-外观模式Facade

    介绍 外观模式(Facade),也叫"过程模式:外观模式为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用 外观模式通过定义一个一致的接口, ...

  2. python-web:flask框架下的html实例——用户注册页面

    1.submit实现页面跳转,方法为get <h1>用户注册</h1> <!-- 使用get方式提交,method为post/get,action保存提交到哪里 --&g ...

  3. 代码+案例,实战解析BeautifulSoup4

    本文分享自华为云社区<从HTML到实战:深入解析BeautifulSoup4的爬虫奇妙世界>,作者:柠檬味拥抱. 网络上的信息浩如烟海,而爬虫技术正是帮助我们从中获取有用信息的重要工具.在 ...

  4. 【Android 抓包对抗】代理检查绕过

    1. 安装apk,点进去发现一点就挂 2. apk 拖入到jadx中观察,发现多出检查,一旦满足条件就会退出 .... if (((ConnectivityManager) getSystemServ ...

  5. [BUUCTF][WEB][极客大挑战 2019]PHP 1

    打开靶机URL 看到字面提示 因为每次猫猫都在我键盘上乱跳,所以我有一个良好的备份网站的习惯不愧是我!!! 说明该网站有备份,说不定放在了Http服务器的某个目录下 那么这里我们可以用dirsearc ...

  6. 【LeetCode二叉树#01】二叉树的遍历(递归/迭代)

    二叉树递归遍历 写递归算法时候需要遵循的三个点: 确定递归函数的参数和返回值: 确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么进而确定递归函 ...

  7. Hello-FPGA CoaXPress 2.0 FPGA DEVICE IP Core Demo

    Hello-FPGA CoaXPress 2.0 Device FPGA IP Core Demo 1     说明 本手册针对Helllo-FPGA的CoaXPress 2.0 DEVICE FPG ...

  8. Spring使用注解方式进行事务管理

    目录 使用步骤: 步骤一.在spring配置文件中引入tx:命名空间 步骤二.具有@Transactional 注解的bean自动配置为声明式事务支持 步骤三.在接口或类的声明处 ,写一个@Trans ...

  9. 【Azure Cache for Redis】Redis的导出页面无法配置Storage SAS时通过az cli来完成

    问题描述 在Azure Redis的导出页面,突然不能配置Storage Account的SAS作为授权方式. 那么是否可以通过AZ CLI或者是Powershell来实现SAS的配置呢? 问题解答 ...

  10. 【Azure Key Vault】使用Azure CLI获取Key Vault 机密遇见问题后使用curl命令来获取机密内容

    问题描述 在使用Azure Key Vault的过程中,遇见无法获取机密信息,在不方便直接写代码的情况下,快速使用Azure CLI指令来验证当前使用的认证是否可以获取到正确的机密值. 使用CLI的指 ...