hi3531的i2c部分 分类: HI3531 2014-03-18 14:41 948人阅读 评论(0) 收藏
一、关于编译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设备成功加载!
版权声明:本文为博主原创文章,未经博主允许不得转载。