色婷婷AⅤ一区二区三区|亚洲精品第一国产综合亚AV|久久精品官方网视频|日本28视频香蕉

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > I2C總線驅(qū)動(dòng)程序

          I2C總線驅(qū)動(dòng)程序

          作者: 時(shí)間:2016-11-21 來源:網(wǎng)絡(luò) 收藏
          #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/pm_runtime.h"
          #include "linux/clk.h"
          #include "linux/cpufreq.h"
          #include "linux/slab.h"
          #include "linux/io.h"
          #include "linux/of_i2c.h"
          #include "linux/of_gpio.h"
          #include "plat/gpio-cfg.h"
          #include "mach/regs-gpio.h"
          #include "asm/irq.h"
          #include "plat/regs-iic.h"
          #include "plat/iic.h"
          //#define PRINTK printk
          #define PRINTK(...)
          enum s3c24xx_i2c_state {
          STATE_IDLE,
          STATE_START,
          STATE_READ,
          STATE_WRITE,
          STATE_STOP
          };
          struct s3c2440_i2c_regs {
          unsigned int iiccon;
          unsigned int iicstat;
          unsigned int iicadd;
          unsigned int iicds;
          unsigned int iiclc;
          };
          struct s3c2440_i2c_xfer_data {
          struct i2c_msg *msgs;
          int msn_num;
          int cur_msg;
          int cur_ptr;
          int state;
          int err;
          wait_queue_head_t wait;
          };
          static struct s3c2440_i2c_xfer_data s3c2440_i2c_xfer_data;
          static struct s3c2440_i2c_regs *s3c2440_i2c_regs;
          static void s3c2440_i2c_start(void)
          {
          s3c2440_i2c_xfer_data.state = STATE_START;
          if (s3c2440_i2c_xfer_data.msgs->flags & I2C_M_RD) // 讀 //
          {
          s3c2440_i2c_regs->iicds = s3c2440_i2c_xfer_data.msgs->addr << 1;
          s3c2440_i2c_regs->iicstat = 0xb0; // 主機(jī)接收,啟動(dòng)
          }
          else // 寫 //
          {
          s3c2440_i2c_regs->iicds = s3c2440_i2c_xfer_data.msgs->addr << 1;
          s3c2440_i2c_regs->iicstat = 0xf0; // 主機(jī)發(fā)送,啟動(dòng)
          }
          }
          static void s3c2440_i2c_stop(int err)
          {
          s3c2440_i2c_xfer_data.state = STATE_STOP;
          s3c2440_i2c_xfer_data.err = err;
          PRINTK("STATE_STOP, err = %dn", err);
          if (s3c2440_i2c_xfer_data.msgs->flags & I2C_M_RD) // 讀 //
          {
          // 下面兩行恢復(fù)I2C操作,發(fā)出P信號(hào)
          s3c2440_i2c_regs->iicstat = 0x90;
          s3c2440_i2c_regs->iiccon = 0xaf;
          ndelay(50); // 等待一段時(shí)間以便P信號(hào)已經(jīng)發(fā)出
          }
          else // 寫 //
          {
          // 下面兩行用來恢復(fù)I2C操作,發(fā)出P信號(hào)
          s3c2440_i2c_regs->iicstat = 0xd0;
          s3c2440_i2c_regs->iiccon = 0xaf;
          ndelay(50); // 等待一段時(shí)間以便P信號(hào)已經(jīng)發(fā)出
          }
          // 喚醒 //
          wake_up(&s3c2440_i2c_xfer_data.wait);
          }
          static int s3c2440_i2c_xfer(struct i2c_adapter *adap,
          struct i2c_msg *msgs, int num)
          {
          unsigned long timeout;
          // 把num個(gè)msg的I2C數(shù)據(jù)發(fā)送出去/讀進(jìn)來 //
          s3c2440_i2c_xfer_data.msgs = msgs;
          s3c2440_i2c_xfer_data.msn_num = num;
          s3c2440_i2c_xfer_data.cur_msg = 0;
          s3c2440_i2c_xfer_data.cur_ptr = 0;
          s3c2440_i2c_xfer_data.err = -ENODEV;
          s3c2440_i2c_start();
          // 休眠 //
          timeout = wait_event_timeout(s3c2440_i2c_xfer_data.wait, (s3c2440_i2c_xfer_data.state == STATE_STOP), HZ * 5);
          if (0 == timeout)
          {
          printk("s3c2440_i2c_xfer time outn");
          return -ETIMEDOUT;
          }
          else
          {
          return s3c2440_i2c_xfer_data.err;
          }
          }
          static u32 s3c2440_i2c_func(struct i2c_adapter *adap)
          {
          return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;
          }
          static const struct i2c_algorithm s3c2440_i2c_algo = {
          // .smbus_xfer = ,
          .master_xfer = s3c2440_i2c_xfer,
          .functionality = s3c2440_i2c_func,
          };
          // 1. 分配/設(shè)置i2c_adapter
          //
          static struct i2c_adapter s3c2440_i2c_adapter = {
          .name = "s3c2440_100ask",
          .algo = &s3c2440_i2c_algo,
          .owner = THIS_MODULE,
          };
          static int isLastMsg(void)
          {
          return (s3c2440_i2c_xfer_data.cur_msg == s3c2440_i2c_xfer_data.msn_num - 1);
          }
          static int isEndData(void)
          {
          return (s3c2440_i2c_xfer_data.cur_ptr >= s3c2440_i2c_xfer_data.msgs->len);
          }
          static int isLastData(void)
          {
          return (s3c2440_i2c_xfer_data.cur_ptr == s3c2440_i2c_xfer_data.msgs->len - 1);
          }
          static irqreturn_t s3c2440_i2c_xfer_irq(int irq, void *dev_id)
          {
          unsigned int iicSt;
          iicSt = s3c2440_i2c_regs->iicstat;
          if(iicSt & 0x8){ printk("Bus arbitration failednr"); }
          switch (s3c2440_i2c_xfer_data.state)
          {
          case STATE_START : // 發(fā)出S和設(shè)備地址后,產(chǎn)生中斷 //
          {
          PRINTK("Startn");
          // 如果沒有ACK, 返回錯(cuò)誤 //
          if (iicSt & S3C2410_IICSTAT_LASTBIT)
          {
          s3c2440_i2c_stop(-ENODEV);
          break;
          }
          if (isLastMsg() && isEndData())
          {
          s3c2440_i2c_stop(0);
          break;
          }
          // 進(jìn)入下一個(gè)狀態(tài) //
          if (s3c2440_i2c_xfer_data.msgs->flags & I2C_M_RD) // 讀 //
          {
          s3c2440_i2c_xfer_data.state = STATE_READ;
          goto next_read;
          }
          else
          {
          s3c2440_i2c_xfer_data.state = STATE_WRITE;
          }
          }
          case STATE_WRITE:
          {
          PRINTK("STATE_WRITEn");
          // 如果沒有ACK, 返回錯(cuò)誤 //
          if (iicSt & S3C2410_IICSTAT_LASTBIT)
          {
          s3c2440_i2c_stop(-ENODEV);
          break;
          }
          if (!isEndData()) // 如果當(dāng)前msg還有數(shù)據(jù)要發(fā)送 //
          {
          s3c2440_i2c_regs->iicds = s3c2440_i2c_xfer_data.msgs->buf[s3c2440_i2c_xfer_data.cur_ptr];
          s3c2440_i2c_xfer_data.cur_ptr++;
          // 將數(shù)據(jù)寫入IICDS后,需要一段時(shí)間才能出現(xiàn)在SDA線上
          ndelay(50);
          s3c2440_i2c_regs->iiccon = 0xaf; // 恢復(fù)I2C傳輸
          break;
          }
          else if (!isLastMsg())
          {
          // 開始處理下一個(gè)消息 //
          s3c2440_i2c_xfer_data.msgs++;
          s3c2440_i2c_xfer_data.cur_msg++;
          s3c2440_i2c_xfer_data.cur_ptr = 0;
          s3c2440_i2c_xfer_data.state = STATE_START;
          // 發(fā)出START信號(hào)和發(fā)出設(shè)備地址 //
          s3c2440_i2c_start();
          break;
          }
          else
          {
          // 是最后一個(gè)消息的最后一個(gè)數(shù)據(jù) //
          s3c2440_i2c_stop(0);
          break;
          }
          break;
          }
          case STATE_READ:
          {
          PRINTK("STATE_READn");
          // 讀出數(shù)據(jù) //
          s3c2440_i2c_xfer_data.msgs->buf[s3c2440_i2c_xfer_data.cur_ptr] = s3c2440_i2c_regs->iicds;
          s3c2440_i2c_xfer_data.cur_ptr++;
          next_read:
          if (!isEndData()) // 如果數(shù)據(jù)沒讀完, 繼續(xù)發(fā)起讀操作 //
          {
          if (isLastData()) // 如果即將讀的數(shù)據(jù)是最后一個(gè), 不發(fā)ack //
          {
          s3c2440_i2c_regs->iiccon = 0x2f; // 恢復(fù)I2C傳輸,接收到下一數(shù)據(jù)時(shí)無ACK
          }
          else
          {
          s3c2440_i2c_regs->iiccon = 0xaf; // 恢復(fù)I2C傳輸,接收到下一數(shù)據(jù)時(shí)發(fā)出ACK
          }
          break;
          }
          else if (!isLastMsg())
          {
          // 開始處理下一個(gè)消息 //
          s3c2440_i2c_xfer_data.msgs++;
          s3c2440_i2c_xfer_data.cur_msg++;
          s3c2440_i2c_xfer_data.cur_ptr = 0;
          s3c2440_i2c_xfer_data.state = STATE_START;
          // 發(fā)出START信號(hào)和發(fā)出設(shè)備地址 //
          s3c2440_i2c_start();
          break;
          }
          else
          {
          // 是最后一個(gè)消息的最后一個(gè)數(shù)據(jù) //
          s3c2440_i2c_stop(0);
          break;
          }
          break;
          }
          default: break;
          }
          // 清中斷 //
          s3c2440_i2c_regs->iiccon &= ~(S3C2410_IICCON_IRQPEND);
          return IRQ_HANDLED;
          }
          //
          * I2C初始化
          //
          static void s3c2440_i2c_init(void)
          {
          struct clk *clk;
          clk = clk_get(NULL, "i2c");
          clk_enable(clk);
          // 選擇引腳功能:GPE15:IICSDA, GPE14:IICSCL
          s3c_gpio_cfgpin(S3C2410_GPE(14), S3C2410_GPE14_IICSCL);
          s3c_gpio_cfgpin(S3C2410_GPE(15), S3C2410_GPE15_IICSDA);
          // bit[7] = 1, 使能ACK
          * bit[6] = 0, IICCLK = PCLK/16
          * bit[5] = 1, 使能中斷
          * bit[3:0] = 0xf, Tx clock = IICCLK/16
          * PCLK = 50MHz, IICCLK = 3.125MHz, Tx Clock = 0.195MHz
          //
          s3c2440_i2c_regs->iiccon = (1<<7) | (0<<6) | (1<<5) | (0xf); // 0xaf
          s3c2440_i2c_regs->iicadd = 0x10; // S3C24xx slave address = [7:1]
          s3c2440_i2c_regs->iicstat = 0x10; // I2C串行輸出使能(Rx/Tx)
          }
          static int i2c_bus_s3c2440_init(void)
          {
          // 2. 硬件相關(guān)的設(shè)置 //
          s3c2440_i2c_regs = ioremap(0x54000000, sizeof(struct s3c2440_i2c_regs));
          s3c2440_i2c_init();
          request_irq(IRQ_IIC, s3c2440_i2c_xfer_irq, 0, "s3c2440-i2c", NULL);
          init_waitqueue_head(&s3c2440_i2c_xfer_data.wait);
          // 3. 注冊(cè)i2c_adapter //
          i2c_add_adapter(&s3c2440_i2c_adapter);
          return 0;
          }
          static void i2c_bus_s3c2440_exit(void)
          {
          i2c_del_adapter(&s3c2440_i2c_adapter);
          free_irq(IRQ_IIC, NULL);
          iounmap(s3c2440_i2c_regs);
          }
          module_init(i2c_bus_s3c2440_init);
          module_exit(i2c_bus_s3c2440_exit);
          MODULE_LICENSE("GPL");
          ==============================================================
          解析:
          編寫"總線(適配器adapter)"驅(qū)動(dòng)
          Device Drivers
          I2C support
          I2C Hardware Bus support
          < > S3C2410 I2C Driver
          nfs 30000000 192.168.1.123:/work/nfs_root/uImage_noi2cbus; bootm 30000000
          應(yīng)用程序發(fā)送消息出去時(shí),會(huì)調(diào)用適配器adapter里面的算法函數(shù)algo里面的master_xfer函數(shù),先把消息記錄下來之后調(diào)用start函數(shù),start函數(shù)里發(fā)送start啟動(dòng)信號(hào)并且把設(shè)備地址發(fā)送出去,然后休眠。發(fā)送完之后產(chǎn)生一個(gè)中斷,在中斷函數(shù)里面讀出狀態(tài),如果沒有ack的話認(rèn)為發(fā)生錯(cuò)誤發(fā)出停止信號(hào)喚醒應(yīng)用程序;如果有ack信號(hào)而且是最后一個(gè)消息,最后一個(gè)數(shù)據(jù)則發(fā)出停止信號(hào),否則進(jìn)入下一個(gè)狀態(tài)讀/寫,如果是寫判斷是否是最后一個(gè)數(shù)據(jù),若還有數(shù)據(jù)要發(fā)送把數(shù)據(jù)發(fā)送出去,若是最后一個(gè)數(shù)據(jù)但是不是最后一個(gè)消息的話開始處理下一個(gè)消息,發(fā)出start信號(hào)和設(shè)備地址,若是最后一個(gè)消息的最后一個(gè)數(shù)據(jù)則發(fā)出停止信號(hào);如果是讀判斷數(shù)據(jù)是否讀完,如果沒有讀完但是接收到的不是最后一個(gè)數(shù)據(jù)則發(fā)送ack信號(hào),若接收到最后一個(gè)數(shù)據(jù)否則無ack,但若數(shù)據(jù)已經(jīng)讀完則處理下一個(gè)消息發(fā)送start信號(hào)。



          評(píng)論


          技術(shù)專區(qū)

          關(guān)閉