zoukankan      html  css  js  c++  java
  • 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 ");                       
                        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 ");                       
                        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 ");                       
                         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 ", __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 ");
                    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 ",
                                    i2c->adap.name);
                    goto fail1;
            }

            dev_info(&pdev->dev, "mic i2c bus driver. ");

            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 ", __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 ", __FUNCTION__,__DATE__,__TIME__);

            return 0;
    }

    static int mic_i2c_resume(struct device *dev)
    {
            printk(KERN_ALERT "%s:%s,%s ", __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 ", __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! ");
                    goto end;
                    }
           
    end:       
            return ret;  
    }
    subsys_initcall(mic_i2c_init);

    static void __exit mic_i2c_exit(void)
    {
        printk(KERN_INFO "%s %s V%s ", __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设备成功加载!

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    登录界面
    冲刺一阶段(5月9日)-个人总结07
    冲刺一阶段(5月8日)-个人总结06
    冲刺一阶段(5月7日)-个人总结05
    冲刺一阶段(5月6日)-个人总结04
    冲刺一阶段(5月5日)-个人总结03
    冲刺一阶段(5月4日)-个人总结02
    第一阶段冲刺--个人总结01(忘记发了)
    软件需求分析(补发)
    第八周工作进程表
  • 原文地址:https://www.cnblogs.com/mao0504/p/4706640.html
Copyright © 2011-2022 走看看