openbmc开发-->aspeed-->slave-i2c[ast2400]

  • 前言
  • ast2400 内核修改启用i2c从机模拟eeprom
    • 测试驱动
  • ast2400 i2c-aspeed.c 驱动修改

前言

  1. 在使用ast2400从机驱动中,当从机设备在被读取时丢失数据,仅仅在偶数时丢失。故对官方驱动做出相应的修改。
  2. openbmc开发包的使用、ast2400配置、uboot修改、其他驱动、device-tree等修改见其他文档。
  3. 首次写博客,速度和文档质量不做保障,只保障代码质量,请各位看客谅解。

ast2400 内核修改启用i2c从机模拟eeprom


> Device Drivers > I2C support
[*] I2C slave support
[*] I2C eeprom slave driver

测试驱动

在linux-aspeed/Documentation/i2c/slave-eeprom-backend.rst手册中有描述如何使用slave EEPROM驱动
注:设备树或者其他信息都可以在Documentation目录下找到对应的描述

注意时间差,aspeed官方驱动在读取时ack应答间隔不一致,会导致数据丢失
读取处理时,接收ASPEED_I2CD_INTR_TX_ACK中断和ASPEED_I2CD_INTR_RX_DONE中断状态分时处里了,
本人理解为ACK的接收同样也应触发接收中断,故将终端状态合并ASPEED_I2CD_INTR_TX_ACK|ASPEED_I2CD_INTR_RX_DONE
并进行统一处理

ast2400 i2c-aspeed.c 驱动修改

以下为修改的函数

static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
{u32 command, irq_handled = 0;struct i2c_client *slave = bus->slave;u8 value;if (!slave)return 0;command = readl(bus->base + ASPEED_I2C_CMD_REG);/* Slave was requested, restart state machine. */if (irq_status & ASPEED_I2CD_INTR_SLAVE_MATCH) {irq_handled |= ASPEED_I2CD_INTR_SLAVE_MATCH;bus->slave_state = ASPEED_I2C_SLAVE_START;}/* Slave is not currently active, irq was for someone else. */if (bus->slave_state == ASPEED_I2C_SLAVE_INACTIVE)return irq_handled;dev_dbg(bus->dev, "slave irq status 0x%08x, cmd 0x%08x\n",irq_status, command);/* Slave was sent something. */if (irq_status & ASPEED_I2CD_INTR_RX_DONE) {value = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) >> 8;/* Handle address frame. */if (bus->slave_state == ASPEED_I2C_SLAVE_START) {if (value & 0x1)bus->slave_state =ASPEED_I2C_SLAVE_READ_REQUESTED;elsebus->slave_state =ASPEED_I2C_SLAVE_WRITE_REQUESTED;}irq_handled |= ASPEED_I2CD_INTR_RX_DONE;}/* Slave was asked to stop. */if (irq_status & ASPEED_I2CD_INTR_NORMAL_STOP) {irq_handled |= ASPEED_I2CD_INTR_NORMAL_STOP;bus->slave_state = ASPEED_I2C_SLAVE_STOP;}if (irq_status & ASPEED_I2CD_INTR_TX_NAK &&bus->slave_state == ASPEED_I2C_SLAVE_READ_PROCESSED) {irq_handled |= ASPEED_I2CD_INTR_TX_NAK;bus->slave_state = ASPEED_I2C_SLAVE_STOP;}switch (bus->slave_state) {case ASPEED_I2C_SLAVE_READ_REQUESTED:if (unlikely(irq_status & ASPEED_I2CD_INTR_TX_ACK))dev_err(bus->dev, "Unexpected ACK on read request.\n");bus->slave_state = ASPEED_I2C_SLAVE_READ_PROCESSED;i2c_slave_event(slave, I2C_SLAVE_READ_REQUESTED, &value);// printk("slave send value %x\n", value);writel(value, bus->base + ASPEED_I2C_BYTE_BUF_REG);writel(ASPEED_I2CD_S_TX_CMD, bus->base + ASPEED_I2C_CMD_REG);break;case ASPEED_I2C_SLAVE_READ_PROCESSED:#if 0 /*aspeed*/if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) {dev_err(bus->dev,"Expected ACK after processed read.\n");break;}irq_handled |= ASPEED_I2CD_INTR_TX_ACK;#else /*wish*/irq_handled |= ASPEED_I2CD_INTR_TX_ACK|ASPEED_I2CD_INTR_RX_DONE;#endif i2c_slave_event(slave, I2C_SLAVE_READ_PROCESSED, &value);// printk("slave send value %x\n", value);writel(value, bus->base + ASPEED_I2C_BYTE_BUF_REG);writel(ASPEED_I2CD_S_TX_CMD, bus->base + ASPEED_I2C_CMD_REG);break;case ASPEED_I2C_SLAVE_WRITE_REQUESTED:bus->slave_state = ASPEED_I2C_SLAVE_WRITE_RECEIVED;i2c_slave_event(slave, I2C_SLAVE_WRITE_REQUESTED, &value);break;case ASPEED_I2C_SLAVE_WRITE_RECEIVED:i2c_slave_event(slave, I2C_SLAVE_WRITE_RECEIVED, &value);break;case ASPEED_I2C_SLAVE_STOP:i2c_slave_event(slave, I2C_SLAVE_STOP, &value);bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE;break;case ASPEED_I2C_SLAVE_START:/* Slave was just started. Waiting for the next event. */;break;default:dev_err(bus->dev, "unknown slave_state: %d\n",bus->slave_state);bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE;break;}return irq_handled;
}
static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id)
{struct aspeed_i2c_bus *bus = dev_id;u32 irq_received, irq_remaining, irq_handled;spin_lock(&bus->lock);irq_received = readl(bus->base + ASPEED_I2C_INTR_STS_REG);/* Ack all interrupts except for Rx done */#if 0 /*aspeed*/writel(irq_received & ~ASPEED_I2CD_INTR_RX_DONE,bus->base + ASPEED_I2C_INTR_STS_REG);#else /*wish*/if(bus->slave_state == ASPEED_I2C_SLAVE_READ_PROCESSED){if(irq_received == ASPEED_I2CD_INTR_TX_ACK){// printk("irq_received & ASPEED_I2CD_INTR_TX_ACK");irq_received |= ASPEED_I2CD_INTR_RX_DONE;}// 该分支因为修改后不会在发生,所以注释// if(irq_received == ASPEED_I2CD_INTR_RX_DONE){//   printk("irq_received & ASPEED_I2CD_INTR_RX_DONE");//  irq_received |= ASPEED_I2CD_INTR_TX_ACK;// }writel(irq_received & ~(ASPEED_I2CD_INTR_RX_DONE|ASPEED_I2CD_INTR_TX_ACK),bus->base + ASPEED_I2C_INTR_STS_REG);}else{writel(irq_received & ~ASPEED_I2CD_INTR_RX_DONE,bus->base + ASPEED_I2C_INTR_STS_REG);}#endifreadl(bus->base + ASPEED_I2C_INTR_STS_REG);irq_received &= ASPEED_I2CD_INTR_RECV_MASK;irq_remaining = irq_received;#if IS_ENABLED(CONFIG_I2C_SLAVE)/** In most cases, interrupt bits will be set one by one, although* multiple interrupt bits could be set at the same time. It's also* possible that master interrupt bits could be set along with slave* interrupt bits. Each case needs to be handled using corresponding* handlers depending on the current state.*/if (bus->master_state != ASPEED_I2C_MASTER_INACTIVE &&bus->master_state != ASPEED_I2C_MASTER_PENDING) {irq_handled = aspeed_i2c_master_irq(bus, irq_remaining);irq_remaining &= ~irq_handled;if (irq_remaining)irq_handled |= aspeed_i2c_slave_irq(bus, irq_remaining);} else {// printk("irq_remaining %x\n", irq_remaining);irq_handled = aspeed_i2c_slave_irq(bus, irq_remaining);// printk("irq_handled %x\n", irq_handled);irq_remaining &= ~irq_handled;if (irq_remaining)// printk("master_irq %x\n", irq_remaining);irq_handled |= aspeed_i2c_master_irq(bus,irq_remaining);}/** Start a pending master command at here if a slave operation is* completed.*/if (bus->master_state == ASPEED_I2C_MASTER_PENDING &&bus->slave_state == ASPEED_I2C_SLAVE_INACTIVE)aspeed_i2c_do_start(bus);
#elseirq_handled = aspeed_i2c_master_irq(bus, irq_remaining);
#endif /* CONFIG_I2C_SLAVE */irq_remaining &= ~irq_handled;if (irq_remaining)dev_err(bus->dev,"irq handled != irq. expected 0x%08x, but was 0x%08x\n",irq_received, irq_handled);/* Ack Rx done */#if 0 /*aspeed*/if (irq_received & ASPEED_I2CD_INTR_RX_DONE) {writel(ASPEED_I2CD_INTR_RX_DONE,bus->base + ASPEED_I2C_INTR_STS_REG);readl(bus->base + ASPEED_I2C_INTR_STS_REG); }#else /*wish*/if (irq_received & ASPEED_I2CD_INTR_RX_DONE) {if (irq_received == (ASPEED_I2CD_INTR_RX_DONE|ASPEED_I2CD_INTR_TX_ACK)) {// printk("ack rx down\n");writel(ASPEED_I2CD_INTR_RX_DONE|ASPEED_I2CD_INTR_TX_ACK,bus->base + ASPEED_I2C_INTR_STS_REG);readl(bus->base + ASPEED_I2C_INTR_STS_REG);}else{// printk("other rx down\n");writel(ASPEED_I2CD_INTR_RX_DONE,bus->base + ASPEED_I2C_INTR_STS_REG);readl(bus->base + ASPEED_I2C_INTR_STS_REG);} }// 测试统一都按ASPEED_I2CD_INTR_RX_DONE|ASPEED_I2CD_INTR_TX_ACK处理十分会有其他错误// if (irq_received & ASPEED_I2CD_INTR_RX_DONE){//  writel(ASPEED_I2CD_INTR_RX_DONE|ASPEED_I2CD_INTR_TX_ACK,//          bus->base + ASPEED_I2C_INTR_STS_REG);//     readl(bus->base + ASPEED_I2C_INTR_STS_REG);// }#endif spin_unlock(&bus->lock);return irq_remaining ? IRQ_NONE : IRQ_HANDLED;
}

openbmc开发-->aspeed-->slave-i2c[ast2400]相关推荐

  1. OpenBmc开发1:openbmc简介

    1.OpenBMC简介 在说OpenBMC之前,先说一下BMC(Baseboard Manager Controller,简称BMC),BMC应用了IPMI架构的智能性,是嵌入在计算机(通常是服务器) ...

  2. firefly-rk3288j开发板--linux I2C实验之eeprom驱动

    firefly-rk3288j开发板–linux I2C实验之eeprom驱动 1 准备工作 开发板:aio-rk3288j SDK版本:rk3288_linux_release_20210304 下 ...

  3. openbmc开发28:fru配置和测试

    在openbmc开发23:添加fru信息到ipmi中说明了如何将fru信息添加到ipmi中,本文将讲述如何生成fru以及fru信息获取展示以及修改等. 1 yaml配置文件转换成cpp 在软件包下有一 ...

  4. 【Renesas RA6M4开发板之I2C读取mpu6050】

    [Renesas RA6M4开发板之I2C读取mpu6050] 1.0 mpu6050 1.1 mpu6050介绍 1.2 mpu6050特点 1.3 mpu6050应用 2. RT-theard配置 ...

  5. 【OpenBMC 系列】1.OpenBMC 开发环境搭建

    目标: 安装Linux 系统,推荐使用Ubuntu18+,作为开发环境. 安装Qemu 作为bmc运行的虚拟机. 受众:熟悉 Linux 和 BMC 的程序员 先决条件:当前的 Linux.Mac 或 ...

  6. 【Renesas RA6M4开发板之I2C(模拟)驱动ssd1306 OLED屏幕】

    [Renesas RA6M4开发板之I2C(模拟)驱动ssd1306 OLED屏幕] 1.0 OLED 1.1产品特性: 1.2产品参数: 2. RT-theard配置 2.1 硬件需求 2.2 软件 ...

  7. 【Renesas RA6M4开发板之I2C读取BMP180气压温度】

    [Renesas RA6M4开发板之I2C读取BMP180气压温度] 1.0 BMP180 1.1 BMP180介绍 1.2 BMP180特点 1.3 产品应用 2. RT-theard配置 2.1 ...

  8. STM32开发 -- PMIC、I2C详解

    如需转载请注明出处:https://juyou.blog.csdn.net/article/details/103391329 终于到PMIC了,这部分有用到I2C,之前一直想讲来着,现在正好一并讲了 ...

  9. MPU6050开发 -- 进阶之I2C/SPI通信协议

    如需转载请注明出处:https://blog.csdn.net/qq_29350001/article/details/78611309 上一篇基本概念讲了一通,大体上对MPU6050有了一个了解.对 ...

最新文章

  1. python round函数_Python round() 函数
  2. 通用测试用例大全(转自——知了.Test)
  3. 20应用统计考研复试要点(part37)--概率论与数理统计
  4. 单片机机器周期怎么计算公式_单片机定时器周期计算公式
  5. Spring 解耦工厂模式
  6. 2016年新运维:优云论《普通运维人员就是秋后的蚂蚱》
  7. asp.net zero
  8. allavsoft mac版:支持从各种视频分享网站下载视频
  9. 【clion】自定义优美的代码配色(主题)
  10. MySQL的启动和停止
  11. Mendeley Destop引用格式自定义调整
  12. 因特网中的域名服务器系统负责全网IP,因特网中的域名服务器系统负责全网IP地址的解析工作,它的好处是()...
  13. 电脑连接树莓派3B+
  14. 大数据运维题库2018年
  15. 用Electron创建第一个桌面应用、打包并加密代码
  16. linux下测试ftp传输,linux下ftp命令使用详解---linux文件传输ftp命令
  17. 基频分析方法汇总【笔记】
  18. mac DBPC 和 Druid jar 包下载
  19. 《Activiti/Flowable 深入BPM工作流》---工作流中的网关有哪些?
  20. 一个屌丝程序员的青春(二九一)

热门文章

  1. 如何将本地文件通过终端上传到apache上(压缩文件)
  2. 自然语言处理(NLP)入门(3)——文本预处理
  3. 深入理解计算机系统——知识总结(二)
  4. FFplay源码分析-avformat_open_input
  5. 从零开始搭建属于自己的语音识别API服务器(ASRT开源项目)
  6. 51单片机入门——定时器与外部中断
  7. 岳麓对话:刘韧对话鲍岳桥周明卢凯解傅盛蒋涛伟俊
  8. html5页面嵌入pdf,有没有办法将pdf文件嵌入到html5页面?
  9. 大家好!我是屁孩君儿子,今天给大家带来一个 1085 球弹跳高度的计算
  10. 蓝桥杯(单片机开发)训练笔记