在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Linux內核中描述I2C的四個核心結構體

嵌入式開發愛好者 ? 來源:嵌入式開發愛好者 ? 2023-09-04 09:35 ? 次閱讀

第一:LinuxI2C驅動框架分析

45107e60-4a73-11ee-97a6-92fbcf53809c.png

I2C核心(i2c_core)

I2C核心維護了i2c_bus結構體,提供了I2C總線驅動設備驅動的注冊、注銷方法,維護了I2C總線的驅動、設備鏈表,實現了設備、驅動的匹配探測。此部分代碼由Linux內核提供。

I2C總線驅動

I2C總線驅動維護了I2C適配器數據結構(i2c_adapter)和適配器的通信方法數據結構(i2c_algorithm)。所以I2C總線驅動可控制I2C適配器產生start、stop、ACK等。此部分代碼由具體的芯片廠商提供,比如Samsung、高通

I2C設備驅動

I2C設備驅動主要維護兩個結構體:i2c_driver和i2c_client,實現和用戶交互的文件操作集合fops、cdev等。此部分代碼就是驅動開發者需要完成的。

第二:Linux內核中描述I2C的四個核心結構體

1)i2c_client—掛在I2C總線上的I2C從設備

每一個i2c從設備都需要用一個i2c_client結構體來描述,i2c_client對應真實的i2c物理設備device。

struct i2c_client { 
    unsigned short flags;     //標志位 (讀寫) 
  unsigned short addr;      //7位的設備地址(低7位) 
  char name[I2C_NAME_SIZE]; //設備的名字,用來和i2c_driver匹配 
  struct i2c_adapter *adapter; //依附的適配器(adapter),適配器指明所屬的總線(i2c0/1/2_bus) 
  struct device dev;           //繼承的設備結構體 
  int irq;                     //設備申請的中斷號
  struct list_head detected;   //已經被發現的設備鏈表 
};

但是i2c_client不是我們自己寫程序去創建的,而是通過以下常用的方式自動創建的:

方法一: 分配、設置、注冊i2c_board_info

方法二: 獲取adapter調用i2c_new_device

方法三: 通過設備樹(devicetree)創建

方法1和方法2通過platform創建,這兩種方法在內核3.0版本以前使用所以在這不詳細介紹;**方法3是最新的方法,**3.0版本之后的內核都是通過這種方式創建的,文章后面的案例就按方法3。

2)i2c_adapter

I2C總線適配器,即soc中的I2C總線控制器,硬件上每一對I2C總線都對應一個適配器來控制它。在Linux內核代碼中,每一個adapter提供了一個描述它的結構(struct i2c_adapter),再通過i2c core層將i2c設備與i2c adapter關聯起來。主要用來完成i2c總線控制器相關的數據通信,此結構體在芯片廠商提供的代碼中維護。

struct i2c_adapter {
    struct module *owner;
    unsigned int class;               //允許匹配的設備的類型
    const struct i2c_algorithm *algo; //指向適配器的驅動程序,實現發送數據的算法
    struct device dev;                //指向適配器的設備結構體
    char name[48];                    //適配器的名字
};

3)i2c_algorithm
I2C總線數據通信算法,通過管理I2C總線控制器,實現對I2C總線上數據的發送和接收等操作。亦可以理解為I2C總線控制器(適配器adapter)對應的驅動程序,每一個適配器對應一個驅動程序,用來描述適配器和設備之間的通信方法,由芯片廠商去實現的。

struct i2c_algorithm {
    //傳輸函數指針,指向實現IIC總線通信協議的函數
    int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);        
};

4)i2c_driver
用于管理I2C的驅動程序和i2c設備(client)的匹配探測,實現與應用層交互的文件操作集合fops、cdev等。

struct i2c_driver {
    int (*probe)(struct i2c_client *, const struct i2c_device_id *); //設備匹配成功調用的函數
    int (*remove)(struct i2c_client *);                              //設備移除之后調用的函數
    struct device_driver driver;                                     //設備驅動結構體
    const struct i2c_device_id *id_table;   //設備的ID表,匹配用platform創建的client
};

第三:應用實例,實現mpu6050驅動,讀取溫度

在設備樹中描述I2C設備信息

@i2c-0 {//表示這個i2c_client所依附的adapter是i2c-0
    //對應i2c_client的name = "invensense,mpu6050"
    compatible = "invensense,mpu6050";
    //對應i2c_client的addr = 0x69  -- 從機設備的地址
    reg = <0x69>;
    //對應i2c_client的irq
    interrupts = <70>;
};

最終內核會將這個設備樹的節點解析為一個i2c_client結構體與i2c_driver結構體進行匹配。

第四:編寫驅動代碼

分配、設置、注冊i2c_driver結構體

struct i2c_driver mpu6050_driver = { .
  driver = {
     .name = "mpu6050", 
     .owner = THIS_MODULE, 
     .of_match_table = of_match_ptr(mpu6050_of_match), 
   }, 
   .probe = mpu6050_probe, .remove = mpu6050_remove, 
};


static int mpu6050_init(void)
{
    printk("%s called
", __func__);


    i2c_add_driver(&mpu6050_driver);


    return 0;
}

i2c總線驅動模型屬于設備模型中的一類,同樣struct i2c_driver結構體繼承于struct driver,匹配方法和設備模型中講的一樣,這里要去匹配設備樹,所以必須實現i2c_driver結構體中的driver成員中的of_match_table成員:

/* 用來匹配mpu6050的設備樹 */
static struct of_device_id mpu6050_of_match[] = {
    {.compatible = "invensense,mpu6050"},
    {},
};

如果和設備樹匹配成功,那么就好調用probe函數

/* 匹配函數,設備樹中的mpu6050結點對應轉換為一個client結構體 */ 
static int mpu6050_probe(struct i2c_client * client, const struct i2c_device_id * id) 
{ 
  int ret; 
  printk("mpu6050 match ok!
"); 
  
  mpu6050_dev.client = client; /* 注冊設備號 */ 
  mpu6050_dev.devno = MKDEV(MAJOR, MINOR); 
  ret = register_chrdev_region(mpu6050_dev.devno, 1, "mpu6050"); 
  if (ret < 0) goto err1; 
  
  cdev_init(&mpu6050_dev.cdev, &mpu6050_fops); 
  mpu6050_dev.cdev.owner = THIS_MODULE; 
  ret = cdev_add(&mpu6050_dev.cdev, mpu6050_dev.devno, 1); 
  if (ret < 0) goto err2; 
    return 0; 
err2: 
  unregister_chrdev_region(mpu6050_dev.devno, 1); 
err1: 
  return -1; 
}

實現文件操作集合

struct file_operations mpu6050_fops = { 
  .owner = THIS_MODULE, 
  .open = mpu6050_open, 
  .release = mpu6050_release, 
  .unlocked_ioctl = mpu6050_ioctl, 
};
static int mpu6050_open(struct inode * inodep, struct file * filep) 
{ 
  printk("%s called
", __func__); 
  mpu6050_write_byte(mpu6050_dev.client, PWR_MGMT_1, 0x00); 
  mpu6050_write_byte(mpu6050_dev.client, SMPLRT_DIV, 0x07); 
  mpu6050_write_byte(mpu6050_dev.client, CONFIG, 0x06); 
  mpu6050_write_byte(mpu6050_dev.client, GYRO_CONFIG, 0xF8); 
  mpu6050_write_byte(mpu6050_dev.client, ACCEL_CONFIG, 0x19); 
  return 0; 
} 
static int mpu6050_release(struct inode * inodep, struct file * filep) 
{ 
  printk("%s called
", __func__); 
  return 0; 
} 
void get_temp(union mpu6050_data * data) 
{ 
  data->temp = mpu6050_read_byte(mpu6050_dev.client, TEMP_OUT_L); 
  data->temp |= mpu6050_read_byte(mpu6050_dev.client, TEMP_OUT_H) << 8; 
} 
static long mpu6050_ioctl(struct file * filep, unsigned int cmd, unsigned long arg) 
{ 
  union mpu6050_data data; 
  switch (cmd) 
  { 
    case GET_TEMP: 
      get_temp(&data); 
      break; 
    default: 
      break; 
  } 
  if (copy_to_user((unsigned int *)arg, &data, sizeof(data))) 
    return -1; 
  return 0; 
}

如何實現對i2c從設備的讀寫操作?

/* 讀取mpu6050中一個字節的數據,將讀取的數據的地址返回 */ 
static int mpu6050_read_byte(struct i2c_client * client, unsigned char reg_add) 
{ 
  int ret; /* 要讀取的那個寄存器的地址 */ 
  char txbuf = reg_add; /* 用來接收讀到的數據 */ 
  char rxbuf[1]; /* i2c_msg指明要操作的從機地址,方向,緩沖區 */ 
  struct i2c_msg msg[] = { 
    {client->addr, 0, 1, &txbuf}, //0表示寫,向往從機寫要操作的寄存器的地址 
    {client->addr, I2C_M_RD, 1, rxbuf}, //讀數據 
  }; 
  /* 通過i2c_transfer函數操作msg */ 
  ret = i2c_transfer(client->adapter, msg, 2); //執行2條msg 
  if (ret < 0) 
  { 
    printk("i2c_transfer read err
"); 
    return -1; 
  } 
  return rxbuf[0]; 
} 
static int mpu6050_write_byte(struct i2c_client * client, unsigned char reg_addr, unsigned char data) 
{ 
  int ret; /* 要寫的那個寄存器的地址和要寫的數據 */ 
  char txbuf[] = {reg_addr, data}; /* 1個msg,寫兩次 */
  struct i2c_msg msg[] = { 
    {client->addr, 0, 2, txbuf} 
  }; 
  ret = i2c_transfer(client->adapter, msg, 1); if (ret < 0) 
  { 
    printk("i2c_transfer write err
"); 
    return -1; 
  } 
  return 0; 
}

在實現讀寫操作的時候,使用了一個重要的函數i2c_transfer(),這個函數是i2c核心提供給設備驅動的,通過它發送的數據需要被打包成i2c_msg結構,這個函數最終會回調相應i2c_adapter->i2c_algorithm->master_xfer()接口將i2c_msg對象發送到i2c物理控制器

struct i2c_msg {
    __u16 addr;     /* slave address  */
    __u16 flags;    /* 1 - 讀  0 - 寫 */
    __u16 len;      /* msg length     */
    __u8 *buf;      /* 要發送的數據   */
};

以上是我對Linux中I2C驅動框架的分析及實際案例分析,如有不足歡迎指出。






審核編輯:劉清

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 控制器
    +關注

    關注

    112

    文章

    16361

    瀏覽量

    178028
  • 內核
    +關注

    關注

    3

    文章

    1372

    瀏覽量

    40289
  • 適配器
    +關注

    關注

    8

    文章

    1952

    瀏覽量

    68024
  • Linux
    +關注

    關注

    87

    文章

    11304

    瀏覽量

    209476
  • I2C
    I2C
    +關注

    關注

    28

    文章

    1487

    瀏覽量

    123740
  • I2C總線
    +關注

    關注

    8

    文章

    391

    瀏覽量

    60936
  • LINUX內核
    +關注

    關注

    1

    文章

    316

    瀏覽量

    21650
  • MPU6050
    +關注

    關注

    39

    文章

    307

    瀏覽量

    71403

原文標題:Linux系統中I2C子系統基本分析

文章出處:【微信號:嵌入式開發愛好者,微信公眾號:嵌入式開發愛好者】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    Linux內核I2C系統的設計思路

    [ 導讀] 本文通過閱讀內核代碼,來梳理一下I2C子系統的整體視圖。在開發I2C設備驅動程序時,往往缺乏對于系統整體的認識,沒有一清晰的思路。所以從高層級來分析一下
    發表于 09-06 09:40 ?529次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內核</b><b class='flag-5'>中</b><b class='flag-5'>I2C</b>系統的設計思路

    如何仿照Linux內核去編寫I2C驅動

    仿照Linux內核編寫MCU的I2C驅動I2C是很常用的串行通信接口,用于連接各種外設,傳感器等器件。在單片機開發
    發表于 08-23 08:03

    請問imx6dl的第四個I2C接口該如何配置使能呢

    在飛凌官網購買的一塊開發板,CPU型號為imx6dl,使用的內核版本為Linux3.0.35。芯片手冊上說明了有四個I2C接口,請問第四個
    發表于 01-07 08:17

    基于I2C總線的EEPROM驅動程序

     I2C總線是由Philips公司開發的用于器件之間連接的2線式雙向同步串行總線。Linux內核針對
    發表于 12-07 13:58 ?55次下載

    Linux設備驅動開發詳解》第15章、LinuxI2C核心、總線與設備驅動

    Linux設備驅動開發詳解》第15章、LinuxI2C核心、總線與設備驅動
    發表于 10-27 11:19 ?8次下載
    《<b class='flag-5'>Linux</b>設備驅動開發詳解》第15章、<b class='flag-5'>Linux</b>的<b class='flag-5'>I2C</b><b class='flag-5'>核心</b>、總線與設備驅動

    基于嵌入式Linux下的I2C設備驅動的總體思路與框架設計

    由于I2C總線的通用性,Linux作為一款優秀的嵌入式操作系統,也必須要對其要有很好的支持。在Linux內核源碼
    發表于 08-20 09:04 ?3748次閱讀
    基于嵌入式<b class='flag-5'>Linux</b>下的<b class='flag-5'>I2C</b>設備驅動的總體思路與框架設計

    linux自帶i2c工具使用

    平臺管理總線),DDC(顯示數據通道)以及ATCA(高級電信架構).如果沒記錯的話,linuxI2C框架是完全支持SMBus的.
    發表于 05-13 09:23 ?3988次閱讀

    LinuxI2C驅動架構

    1.???? LinuxI2C驅動架構LinuxI2C總線的驅動分為兩部分
    發表于 04-02 14:38 ?680次閱讀

    Linux內核I2C子系統的整體視圖

    本文通過閱讀內核代碼,來梳理一下I2C子系統的整體視圖。在開發I2C設備驅動程序時,往往缺乏對于系統整體的認識,沒有一清晰的思路。所以從高層級來分析一下
    的頭像 發表于 12-31 10:40 ?2187次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內核</b><b class='flag-5'>中</b><b class='flag-5'>I2C</b>子系統的整體視圖

    Linux驅動:I2C設備驅動(基于Freescale i.MX6ULL平臺了解I2C的驅動框架,順便寫個簡陋的MPU6050驅動)

    文章目錄1、簡介2I2C總線、設備和驅動的結構定義2.1 結構定義--
    發表于 12-06 13:51 ?8次下載
    <b class='flag-5'>Linux</b>驅動:<b class='flag-5'>I2C</b>設備驅動(基于Freescale <b class='flag-5'>i</b>.MX6ULL平臺了解<b class='flag-5'>I2C</b>的驅動框架,順便寫個簡陋的MPU6050驅動)

    I2C控制器驅動介紹

    控制器驅動 I2C 總線驅動重點是 I2C 適配器驅動,這里要用到兩重要的數據結構i2c_adapter 和
    的頭像 發表于 07-22 15:38 ?1493次閱讀
    <b class='flag-5'>I2C</b>控制器驅動介紹

    I2C設備驅動的兩個數據結構

    i2c_client,每檢測到一 I2C 設備就會給這個 I2C 設備分配一 i2c_cl
    的頭像 發表于 07-22 15:49 ?838次閱讀
    <b class='flag-5'>I2C</b>設備驅動的兩個數據<b class='flag-5'>結構</b>

    I2C子系統SW Architecture

    適配器(控制器)驅動,這里用到兩重要的數據結構i2c_adapter 和 i2c_algorithm。其中,Linux
    的頭像 發表于 07-22 16:01 ?955次閱讀
    <b class='flag-5'>I2C</b>子系統SW Architecture

    I2C子系統幾個主要的結構

    I2C Data Structure 我們要搞懂一 Linux 子系統,必須研究它的數據結構,搞懂每個結構
    的頭像 發表于 07-22 16:04 ?849次閱讀
    <b class='flag-5'>I2C</b>子系統幾個主要的<b class='flag-5'>結構</b><b class='flag-5'>體</b>

    Linux內核網絡擁塞控制算法的實現框架(二)

    :[Linux內核網絡基礎-TCP相關的幾個關鍵結構-小記]中進行了介紹,如下圖是四個核心結構
    的頭像 發表于 07-28 11:34 ?828次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內核</b>網絡擁塞控制算法的實現框架(二)
    主站蜘蛛池模板: 爱爱帝国亚洲一区二区三区| 亚洲人成网站在线| 午夜一级影院| 干人人| 久久婷五月综合| 亚洲网站一区| 在线欧美成人| 毛片大全免费| 天天综合色天天综合色sb| 殴美一级| 欧美性猛交xxxx免费| 午夜老司机永久免费看片| 黄色免费毛片| 一本久草| 国产午夜毛片一区二区三区| 乱轮黄色小说| 久久这里精品青草免费| 欧美成人天天综合天天在线| 国产在线精品一区免费香蕉 | 成人欧美一区二区三区视频不卡| 亚洲国产精品热久久2022| 欧美乱强性伦xxxxx| 国产性老妇女做爰在线| 精品人人| 99精品视频在线播放2| 5060午夜一级| 国产精品资源手机在线播放| 日本人xxxxxxxxxⅹ69| 日本免费一级视频| 日本黄页网址| 老师喂我吃她的奶水脱她胸罩| 六月婷婷啪啪| 在线观看亚洲专3333| 骚黄视频| 欧美肥胖女人bbwbbw视频| 亚洲最色网站| 一级毛片免费不卡在线视频| 免费网站看黄| 欧美一级特黄啪啪片免费看| 免费一级毛片正在播放| 五月婷婷丁香在线观看|