hi3531的i2c部分-阿里云开发者社区

开发者社区> 开发与运维> 正文
登录阅读全文

hi3531的i2c部分

简介: <p>一、关于编译Hi3531 SDK: <br> 之前编译SDK时编译到make uImage总出错,一是找不到.config文件,这个问题是必须先make menuconfig 然后保存.config文件。 <br> 二是编译到make uImage的快结束时,会出现找不到mkimage命令错误。 <br> 解决方法: <br>     查看最底层的Makefile:arch/

一、关于编译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设备成功加载!

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享: