hi3531的i2c部分
一、关于编译Hi3531 SDK:
之前编译SDK时编译到make uImage总出错,一是找不到.config文件,这个问题是必须先make menuconfig 然后保存.config文件。
二是编译到make uImage的快结束时,会出现找不到mkimage命令错误。
解决方法:
查看最底层的Makefile:arch/arm/boot/Makefile,可以看到:
quiet_cmd_uimage = UIMAGE $@
cmd_uimage = $(CONFIG_SHELL) $( MKIMAGE) -A arm -O linux -T kernel \
-C none -a $(LOADADDR) -e $(STARTADDR) \
-n 'Linux-$(KERNELRELEASE)' -d $< $@
而 MKIMAGE 的值为:
MKIMAGE := $(srctree)/scripts/mkuboot.sh
所以打开kernel/scripts/mkuboot.sh,修改mkimage的路径,然后编译,就通过了
说明:没有权限向公司的编译服务器拷贝mkimage,只能改Makefile中mkimage的路径
2、注意:最好修改osd目录下的Makefile,将删除linux-3.0.x的命令和重新解压的命令去掉,否则每次都
将之前的删除掉再重新解压,所以每次都要修改,没必要,也比较麻烦,编译也很费时间
二、关于I2C支持的工作总结
1、开始在SDK里编译的驱动一直没加上,提示:
# insmod gpioi2c.ko
gpioi2c: version magic '3.0.1 SMP mod_unload ARMv7 ' should be '3.0.1 mod_unload ARMv7 '
insmod: can't insert 'gpioi2c.ko': invalid module format
2、但是,SDK里和gpioi2c放一起的实例跑的是正确的结果:
# ./i2c_write 0x56 0x01 0x11
device_addr:0x56; reg_addr:0x 1; reg_value:0x11.
# ./i2c_read 0x56 0x01
device_addr:0x56; reg_addr:0x 1.
0x11
# ./i2c_write 0x56 0x02 0x22
device_addr:0x56; reg_addr:0x 2; reg_value:0x22.
# ./i2c_read 0x56 0x02
device_addr:0x56; reg_addr:0x 2.
0x22
读写的数据一致。
说明原来的驱动没有问题,可能是库里的代码有问题。
但是还是编译了SDK里的gpioi2c.ko驱动,因为这一个驱动被其他三个驱动使用了,所以需要先rmmod 那三个驱动,然后再卸载这个驱动。
3、先说这个问题怎么解决的:
# insmod gpioi2c.ko
gpioi2c: version magic '3.0.1 SMP mod_unload ARMv7 ' should be '3.0.1 mod_unload ARMv7 '
insmod: can't insert 'gpioi2c.ko': invalid module format
这是因为内核配置的不对,修改内核配置项,取消Kernel type->Symmetrical Multi-Processing这一项,编译出的驱动便可以insmod了。
使用了SDK中所带的驱动代码,因为tw2865、tlv_320aic31和sil9024使用了gpioi2c.ko,所以对这四个驱动都重新编译了。
代码存放路径:
[li_xiangping@xn-linux extdrv_hi3531]$ pwd
/home/li_xiangping/Hi3531_SDK_V1.0.2.0/mpp/extdrv_hi3531
在该路径下执行make,然后将四个子目录w2865、tlv_320aic31、sil9024和gpio_i2c_8b下的.ko文件拷贝到demo板,替换到原来的驱动
4、 对库的修改:
4.1
将I2cWrite()中的:
if (ioctl(I2cFd, I2C_WRITE, &Value) < 0)
改为:
if (ioctl(I2cFd, GPIO_I2C_WRITE, &Value) < 0)
4.2
将I2cRead()中的:
if (ioctl(I2cFd, GPIO_I2C_READ, &Value) < 0)
改为:
if (ioctl(I2cFd, GPIO_I2C_READ, &Value) < 0)
4.3
在Inner/i2c.h中添加:
#define GPIO_I2C_READ 0x01
#define GPIO_I2C_WRITE 0x03
修改原因:
ioctl()的cmd值不一致,导致I2cWrite()失败。
写的时候总失败,读出来的数据是正确的,因为原来定义的宏是:
#define I2C_READ 0x01
#define I2C_WRITE 0x02
修改后便正确了
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/time.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/cpufreq.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/miscdevice.h>
#include <linux/fcntl.h>
#include <linux/proc_fs.h>
#include <linux/workqueue.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#define DEV_NAME "mic i2c driver"
#define DRV_VERSION "1.0.0"
#define I2C_WAIT_TIME_OUT 0x1000
#define I2C_ADRESS_BASE 0x200D0000
#define I2C_ADRESS_PHY_LEN 0x20
#define MIC_I2C_CLOCK (110000000)
#define MIC_I2C_RATE (100000)
#define READ_OPERATION (1)
#define WRITE_OPERATION 0xfe
/* the offset of reg */
#define I2C_CTRL_REG 0x000
#define I2C_COM_REB 0x004
#define I2C_ICR_REG 0x008
#define I2C_SR_REG 0x00C
#define I2C_SCL_H_REG 0x010
#define I2C_SCL_L_REG 0x014
#define I2C_TXR_REG 0x018
#define I2C_RXR_REG 0x01C
/* I2C_CTRL_REG */
#define I2C_ENABLE (1 << 8)
#define I2C_UNMASK_TOTAL (1 << 7)
#define I2C_UNMASK_START (1 << 6)
#define I2C_UNMASK_END (1 << 5)
#define I2C_UNMASK_SEND (1 << 4)
#define I2C_UNMASK_RECEIVE (1 << 3)
#define I2C_UNMASK_ACK (1 << 2)
#define I2C_UNMASK_ARBITRATE (1 << 1)
#define I2C_UNMASK_OVER (1 << 0)
#define I2C_UNMASK_ALL (I2C_UNMASK_START | I2C_UNMASK_END | \
I2C_UNMASK_SEND | I2C_UNMASK_RECEIVE | \
I2C_UNMASK_ACK | I2C_UNMASK_ARBITRATE | \
I2C_UNMASK_OVER)
/* I2C_SR_REG */
#define I2C_BUSY (1 << 7)
#define I2C_START_INTR (1 << 6)
#define I2C_END_INTR (1 << 5)
#define I2C_SEND_INTR (1 << 4)
#define I2C_RECEIVE_INTR (1 << 3)
#define I2C_ACK_INTR (1 << 2)
#define I2C_ARBITRATE_INTR (1 << 1)
#define I2C_OVER_INTR (1 << 0)
/* I2C_ICR_REG */
#define I2C_CLEAR_START (1 << 6)
#define I2C_CLEAR_END (1 << 5)
#define I2C_CLEAR_SEND (1 << 4)
#define I2C_CLEAR_RECEIVE (1 << 3)
#define I2C_CLEAR_ACK (1 << 2)
#define I2C_CLEAR_ARBITRATE (1 << 1)
#define I2C_CLEAR_OVER (1 << 0)
#define I2C_CLEAR_ALL (I2C_CLEAR_START | I2C_CLEAR_END | \
I2C_CLEAR_SEND | I2C_CLEAR_RECEIVE | \
I2C_CLEAR_ACK | I2C_CLEAR_ARBITRATE | \
I2C_CLEAR_OVER)
/* I2C_COM_REB */
#define I2C_SEND_ACK (~(1 << 4))
#define I2C_START (1 << 3)
#define I2C_READ (1 << 2)
#define I2C_WRITE (1 << 1)
#define I2C_STOP (1 << 0)
#define mic_i2c_write(addr, value) ((*(volatile unsigned int *)(addr)) = (value))
#define mic_i2c_read(addr) (*(volatile unsigned int *)(addr))
#define MUXCTRL_REG102 IO_ADDRESS(0x200f0000 + 0x198) // I2C_SDA
#define MUXCTRL_REG103 IO_ADDRESS(0x200f0000 + 0x19c) // I2C_SCL
/* i2c controller state */
enum mic_i2c_state {
STATE_IDLE,
STATE_START,
STATE_READ,
STATE_WRITE,
STATE_STOP
};
enum mic_i2c_type {
TYPE_MIC_I2C,
TYPE_MIC_NULL,
};
struct mic_i2c {
spinlock_t lock;
wait_queue_head_t wait;
struct i2c_msg *msg;
unsigned int irq;
enum mic_i2c_state state;
unsigned long clkrate;
void __iomem *regs;
struct clk *clk;
struct device *dev;
struct resource *ioarea;
struct i2c_adapter adap;
};
struct resource mic_i2c_resource[] = {
[0]={
.start = I2C_ADRESS_BASE,
.end = I2C_ADRESS_BASE + I2C_ADRESS_PHY_LEN,
.flags = IORESOURCE_MEM,
}
};
static short mic_poll_status(struct i2c_adapter *adap, unsigned long bit)
{
int loop_cntr = 10000;
unsigned int reg = 0x00;
struct mic_i2c *i2c = container_of(adap, struct mic_i2c, adap);
do {
udelay(10);
} while (!(reg = mic_i2c_read(i2c->regs + I2C_SR_REG) & bit) && (--loop_cntr > 0));
mic_i2c_write((i2c->regs + I2C_ICR_REG), I2C_CLEAR_ALL);
loop_cntr = 10000;
while((mic_i2c_read(i2c->regs + I2C_SR_REG) & I2C_ACK_INTR) && (--loop_cntr > 0));
return loop_cntr;
}
static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length)
{
struct mic_i2c *i2c = container_of(adap, struct mic_i2c, adap);
/* Read data */
while(length) {
/* Send Start */
if(length - 1)
mic_i2c_write((i2c->regs + I2C_COM_REB), I2C_READ);
else
mic_i2c_write((i2c->regs + I2C_COM_REB), I2C_READ | (~I2C_SEND_ACK));
if(!mic_poll_status(adap, I2C_RECEIVE_INTR)) {
dev_info(&adap->dev, "TXRDY timeout\n");
return -ETIMEDOUT;
}
*buf++ = (mic_i2c_read(i2c->regs + I2C_RXR_REG) & 0xff);
length--;
}
mic_i2c_write((i2c->regs + I2C_ICR_REG), I2C_STOP);
return 0;
}
static int xfer_write(struct i2c_adapter *adap, unsigned char *buf, int length)
{
struct mic_i2c *i2c = container_of(adap, struct mic_i2c, adap);
while(length--)
{
mic_i2c_write((i2c->regs + I2C_TXR_REG), *buf++);
mic_i2c_write((i2c->regs + I2C_COM_REB), I2C_WRITE);
if(!mic_poll_status(adap, I2C_OVER_INTR))
{
dev_dbg(&adap->dev, "TXRDY timeout\n");
return -ETIMEDOUT;
}
}
return 0;
}
/*
* first port of call from the i2c bus code when an message needs
* transferring across the i2c bus.
*/
static int mic_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg, int num)
{
int i, ret;
unsigned char device_addr = 0x00;
struct mic_i2c *i2c = container_of(adap, struct mic_i2c, adap);
for(i = 0; i < num; i++) {
mic_i2c_write((i2c->regs + I2C_COM_REB), I2C_WRITE | I2C_START);
if((pmsg->addr >> 8) & 0x00ff) {
device_addr = (char)((pmsg->flags & I2C_M_RD) ? ((pmsg->addr >> 8) | READ_OPERATION) : ((pmsg->addr >> 8) & WRITE_OPERATION));
xfer_write(adap, &device_addr, 1);
device_addr = (char)((pmsg->flags & I2C_M_RD) ? (pmsg->addr | READ_OPERATION) : (pmsg->addr & WRITE_OPERATION));
xfer_write(adap, &device_addr, 1);
}
else {
device_addr = (char)((pmsg->flags & I2C_M_RD) ? (pmsg->addr | READ_OPERATION) : (pmsg->addr & WRITE_OPERATION));
xfer_write(adap, &device_addr, 1);
}
pmsg->addr = device_addr;
if (pmsg->len && pmsg->buf) { /* sanity check */
if (pmsg->flags & I2C_M_RD)
ret = xfer_read(adap, pmsg->buf, pmsg->len);
else
ret = xfer_write(adap, pmsg->buf, pmsg->len);
}
/* Wait until transfer is finished */
mic_i2c_write((i2c->regs + I2C_COM_REB), I2C_STOP);
if(!mic_poll_status(adap, I2C_OVER_INTR)) {
dev_info(&adap->dev, "TXRDY timeout\n");
return -ETIMEDOUT;
mic_i2c_write((i2c->regs + I2C_ICR_REG), 0x01);
if(ret < 0)
return ret;
}
pmsg++; /* next message */
}
return i;
}
/* declare our i2c functionality */
static u32 mic_i2c_func(struct i2c_adapter *adap)
{
printk(KERN_ALERT "%s:%s,%s\r\n", __FUNCTION__,__DATE__,__TIME__);
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;
}
/* i2c bus registration info */
static const struct i2c_algorithm mic_i2c_algorithm = {
.master_xfer = mic_i2c_xfer,
.functionality = mic_i2c_func,
};
static int mic_i2c_probe(struct platform_device *pdev)
{
struct mic_i2c *i2c;
int ret;
unsigned int value, value_h, value_l;
writel(0x01, MUXCTRL_REG102);
writel(0x01, MUXCTRL_REG103);
i2c = kzalloc(sizeof(struct mic_i2c), GFP_KERNEL);
if (!i2c) {
dev_err(&pdev->dev, "no memory for state\n");
return -ENOMEM;
}
snprintf(i2c->adap.name, sizeof(i2c->adap.name), "mic");
i2c->adap.algo = &mic_i2c_algorithm;
i2c->adap.class = I2C_CLASS_HWMON;
i2c->adap.dev.parent = &pdev->dev;
i2c->adap.nr = pdev->id;
i2c->ioarea = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!i2c->ioarea)
return -ENXIO;
if (!request_mem_region(i2c->ioarea->start, resource_size(i2c->ioarea), "mic_i2c"))
return -EBUSY;
i2c->regs = ioremap(i2c->ioarea->start, resource_size(i2c->ioarea));
if (!i2c->regs) {
ret = -ENOMEM;
goto fail0;
}
spin_lock_init(&i2c->lock);
/* clk */
/* Read CTRL */
value = mic_i2c_read(i2c->regs + I2C_CTRL_REG);
/* maskable interrupt of i2c */
mic_i2c_write((i2c->regs + I2C_CTRL_REG), (value & (~I2C_UNMASK_TOTAL)));
value_h = (MIC_I2C_CLOCK / (MIC_I2C_RATE * 2)) / 2 - 1;
mic_i2c_write((i2c->regs + I2C_SCL_H_REG), value_h);
value_l = (MIC_I2C_CLOCK / (MIC_I2C_RATE * 2)) / 2 - 1;
mic_i2c_write((i2c->regs + I2C_SCL_L_REG), value_l);
/* enable interrupt of i2c */
mic_i2c_write((i2c->regs + I2C_ICR_REG), 0x03);
mic_i2c_write((i2c->regs + I2C_CTRL_REG), 0x0187 | value);
platform_set_drvdata(pdev, i2c);
ret = i2c_add_numbered_adapter(&i2c->adap);
if (ret) {
dev_err(&pdev->dev, "Adapter %s registration failed\n",
i2c->adap.name);
goto fail1;
}
dev_info(&pdev->dev, "mic i2c bus driver.\n");
return 0;
fail1:
platform_set_drvdata(pdev, NULL);
fail0:
release_mem_region(i2c->ioarea->start, resource_size(i2c->ioarea));
iounmap(i2c->regs);
kfree(i2c);
return ret;
}
static int __devexit mic_i2c_remove(struct platform_device *pdev)
{
struct mic_i2c *i2c = platform_get_drvdata(pdev);
printk(KERN_ALERT "%s:%s,%s\r\n", __FUNCTION__,__DATE__,__TIME__);
i2c_del_adapter(&i2c->adap);
platform_set_drvdata(pdev, NULL);
release_mem_region(i2c->ioarea->start, resource_size(i2c->ioarea));
iounmap(i2c->regs);
kfree(i2c);
return 0;
}
#ifdef CONFIG_PM_RUNTIME
static int mic_i2c_suspend_noirq(struct device *dev)
{
printk(KERN_ALERT "%s:%s,%s\r\n", __FUNCTION__,__DATE__,__TIME__);
return 0;
}
static int mic_i2c_resume(struct device *dev)
{
printk(KERN_ALERT "%s:%s,%s\r\n", __FUNCTION__,__DATE__,__TIME__);
return 0;
}
static const struct dev_pm_ops mic_i2c_dev_pm_ops = {
.suspend_noirq = s3c24xx_i2c_suspend_noirq,
.resume = mic_i2c_resume,
};
#define MIC_DEV_PM_OPS (&mic_i2c_dev_pm_ops)
#else
#define MIC_DEV_PM_OPS NULL
#endif
static void mic_i2c_release(struct device * dev)
{
}
struct platform_device mic_i2c_device = {
.name = "mic-i2c",
.id = 0,
.num_resources = ARRAY_SIZE(mic_i2c_resource),
.resource = mic_i2c_resource,
.dev =
{
.release = mic_i2c_release,
}
};
static struct platform_driver mic_i2c_driver = {
.probe = mic_i2c_probe,
.remove = mic_i2c_remove,
.driver = {
.owner = THIS_MODULE,
.name = "mic-i2c",
.pm = MIC_DEV_PM_OPS,
},
};
static int __init mic_i2c_init(void)
{
int ret = -ENODEV;
printk(KERN_INFO "%s %s V%s\n", __func__, DEV_NAME, DRV_VERSION);
platform_device_register(&mic_i2c_device);
ret = platform_driver_register(&mic_i2c_driver);
if(ret)
{
platform_device_unregister(&mic_i2c_device);
printk("platform_device_register is fail!\n");
goto end;
}
end:
return ret;
}
subsys_initcall(mic_i2c_init);
static void __exit mic_i2c_exit(void)
{
printk(KERN_INFO "%s %s V%s\n", __func__, DEV_NAME, DRV_VERSION);
platform_driver_unregister(&mic_i2c_driver);
platform_device_unregister(&mic_i2c_device);
}
module_exit(mic_i2c_exit);
MODULE_DESCRIPTION("mic i2c driver");
MODULE_AUTHOR("microcreat <microcreat@gmail.com>");
MODULE_LICENSE("GPL");
直接可以编译成ko,加载进内核,进入内核可以看到i2c设备成功加载!
hi3531的i2c部分的更多相关文章
- I2C子系统之驱动SSD1306 OLED
理解I2C设备驱动框架,主要围绕四个结构体去分析就容易了. struct i2c_algorithm:提供I2C协议的实现的操作,如:master_xfer实现数据收发的最基本方法. struct i ...
- AM335x kernel 4.4.12 i2c eeprom AT24c02驱动移植
kernel 4.4.12 i2c eeprom AT24c02驱动移植 在kernel make menuconfig ARCH=ARM 中打开: Device Drivers ---> Mi ...
- I2C基础知识
常识 两条总线线路:串行数据总线SDA,串行时钟总线SCL 每个连接到总线的器件都有唯一的地址供其他设备寻址 每个连接到总线的器件都可以作为发送器和接收器 是多主机总线,如果两个或更多主机同时初始化, ...
- I2C 基础原理详解
今天来学习下I2C通信~ I2C(Inter-Intergrated Circuit)指的是 IC(Intergrated Circuit)之间的(Inter) 通信方式.如上图所以有很多的周边设备都 ...
- i2c协议
i2c协议 http://blog.csdn.net/g_salamander/article/details/8016698 总线设备驱动模型 http://blog.csdn.net/u01395 ...
- I2S/PCM/IOM-2、I2C/SPI/UART/GPIO/slimbus
概述 I2S,PCM,IOM-2都是数字音频接口,传数据的. I2C,SPI,UART,GPIO是控制接口,传控制信令的. I2S I2S(Inter-IC Sound Bus)是飞利浦公司为数字音频 ...
- I2C总线(异步)
起始位与停止位的定义: 起始信号:当SCL为高期间,SDA由高到低的跳变:启动信号是一种电平跳变时序信号,而不是一个电平信号. 停止信号:当SCL为高期间,SDA由低到高的跳变:停止信号也是一种电平跳 ...
- Uart、SPI和I2C的区别
串口通信:UART.SPI.I2C区别[引用] 1.UART就是两线,一根发送一根接收,可以全双工通信,线数也比较少.数据是异步传输的,对双方的时序要求比较严格,通信速度也不是很快.在多机通信上面 ...
- Raspberry Pi I2C驱动 (Python)
本文参考 http://www.instructables.com/id/Raspberry-Pi-I2C-Python/all/?lang=zh 作者 AntMan232 In this instr ...
随机推荐
- 安装pcntl以实现php多进程
pcntl 扩展包一般就在php源码的ext目录下. cd ./ext/pcntl /opt/server/php5/bin/phpize ./configure \ --with-php-confi ...
- CTSC 2017 滚粗记
CTSC 2017 滚粗记 结束好几天了一直没写. 明天就要去参加二轮省选了,填一下坑吧. 所以可能很多东西已经忘了 Day -2 [5.5 Fri] 周五晚上是其他学信竞的同学来机房的时间... 也 ...
- Win10无法使用小娜搜索本地应用问题的解决方案
小娜介绍 win10的Cortana小娜是一个功能非常强大的语音和搜索助手,用户可以通过小娜助手搜索任意的文件和应用软件,不过有用户发现win10的小娜搜索不到已安装的本地软件,那么win10小娜助手 ...
- Python数据结构之二——tuple(元组)
Python版本:3.6.2 操作系统:Windows 作者:SmallWZQ 列表和元组是Python中最常见的内建序列.元组与列表一样,但是tuple一旦创建就不能修改.创建元组的语法非常简单 ...
- React项目模板-从项目搭建到部署
前一段时间做了一个小项目,时间比较紧,就一个人月.最终希望能够通过微信公众号链接启动应用. 项目的业务细节就不多说了,主要是想分享一下做这个项目技术方面的一些经验. 技术选型 参考范围大致三种:Ang ...
- 使用腾讯云“自定义监控”监控GPU使用率
欢迎大家前往云+社区,获取更多腾讯海量技术实践干货哦~ 作者:李想 随着人工智能以及比特币的火热,GPU云服务的使用场景是越来越广,在很多场景下我们也需要获取GPU服务器的性能参数来优化程序的执行.目 ...
- go 开发环境安装教程 windows
首先进入go 语言官网下载最新安装包,我目前安装的版本是 1.8.3版本:go1.8.3.windows-amd64.msi 如果下载慢,这个是百度云地址:https://pan.baidu ...
- Python3实现QQ机器人自动爬取百度文库的搜索结果并发送给好友(主要是爬虫)
一.效果如下: 二.运行环境: win10系统:python3:PyCharm 三.QQ机器人用的是qqbot模块 用pip安装命令是: pip install qqbot (前提需要有request ...
- Java经典编程题50道之三十九
写一个函数,求一个字符串的长度,在main函数中输入字符串,并输出其长度. public class Example39 { public static void main(String[] a ...
- java9 - 异常处理
Java异常 1.异常初见 System.out.println(1/0); 运行上面语句之后打印出: Exception in thread "main" java.lang.A ...