openbmc开发-->aspeed-->slave-i2c[ast2400]
openbmc开发-->aspeed-->slave-i2c[ast2400]
- 前言
- ast2400 内核修改启用i2c从机模拟eeprom
- 测试驱动
- ast2400 i2c-aspeed.c 驱动修改
前言
- 在使用ast2400从机驱动中,当从机设备在被读取时丢失数据,仅仅在偶数时丢失。故对官方驱动做出相应的修改。
- openbmc开发包的使用、ast2400配置、uboot修改、其他驱动、device-tree等修改见其他文档。
- 首次写博客,速度和文档质量不做保障,只保障代码质量,请各位看客谅解。
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]相关推荐
- OpenBmc开发1:openbmc简介
1.OpenBMC简介 在说OpenBMC之前,先说一下BMC(Baseboard Manager Controller,简称BMC),BMC应用了IPMI架构的智能性,是嵌入在计算机(通常是服务器) ...
- firefly-rk3288j开发板--linux I2C实验之eeprom驱动
firefly-rk3288j开发板–linux I2C实验之eeprom驱动 1 准备工作 开发板:aio-rk3288j SDK版本:rk3288_linux_release_20210304 下 ...
- openbmc开发28:fru配置和测试
在openbmc开发23:添加fru信息到ipmi中说明了如何将fru信息添加到ipmi中,本文将讲述如何生成fru以及fru信息获取展示以及修改等. 1 yaml配置文件转换成cpp 在软件包下有一 ...
- 【Renesas RA6M4开发板之I2C读取mpu6050】
[Renesas RA6M4开发板之I2C读取mpu6050] 1.0 mpu6050 1.1 mpu6050介绍 1.2 mpu6050特点 1.3 mpu6050应用 2. RT-theard配置 ...
- 【OpenBMC 系列】1.OpenBMC 开发环境搭建
目标: 安装Linux 系统,推荐使用Ubuntu18+,作为开发环境. 安装Qemu 作为bmc运行的虚拟机. 受众:熟悉 Linux 和 BMC 的程序员 先决条件:当前的 Linux.Mac 或 ...
- 【Renesas RA6M4开发板之I2C(模拟)驱动ssd1306 OLED屏幕】
[Renesas RA6M4开发板之I2C(模拟)驱动ssd1306 OLED屏幕] 1.0 OLED 1.1产品特性: 1.2产品参数: 2. RT-theard配置 2.1 硬件需求 2.2 软件 ...
- 【Renesas RA6M4开发板之I2C读取BMP180气压温度】
[Renesas RA6M4开发板之I2C读取BMP180气压温度] 1.0 BMP180 1.1 BMP180介绍 1.2 BMP180特点 1.3 产品应用 2. RT-theard配置 2.1 ...
- STM32开发 -- PMIC、I2C详解
如需转载请注明出处:https://juyou.blog.csdn.net/article/details/103391329 终于到PMIC了,这部分有用到I2C,之前一直想讲来着,现在正好一并讲了 ...
- MPU6050开发 -- 进阶之I2C/SPI通信协议
如需转载请注明出处:https://blog.csdn.net/qq_29350001/article/details/78611309 上一篇基本概念讲了一通,大体上对MPU6050有了一个了解.对 ...
最新文章
- python round函数_Python round() 函数
- 通用测试用例大全(转自——知了.Test)
- 20应用统计考研复试要点(part37)--概率论与数理统计
- 单片机机器周期怎么计算公式_单片机定时器周期计算公式
- Spring 解耦工厂模式
- 2016年新运维:优云论《普通运维人员就是秋后的蚂蚱》
- asp.net zero
- allavsoft mac版:支持从各种视频分享网站下载视频
- 【clion】自定义优美的代码配色(主题)
- MySQL的启动和停止
- Mendeley Destop引用格式自定义调整
- 因特网中的域名服务器系统负责全网IP,因特网中的域名服务器系统负责全网IP地址的解析工作,它的好处是()...
- 电脑连接树莓派3B+
- 大数据运维题库2018年
- 用Electron创建第一个桌面应用、打包并加密代码
- linux下测试ftp传输,linux下ftp命令使用详解---linux文件传输ftp命令
- 基频分析方法汇总【笔记】
- mac DBPC 和 Druid jar 包下载
- 《Activiti/Flowable 深入BPM工作流》---工作流中的网关有哪些?
- 一个屌丝程序员的青春(二九一)