核心下gpio模擬i2c驅動修改
Linux核心很多驅動都使用到I2C子系統。EEPROM、RTC,電池,tp等。
inux核心的i2c-gpio是使用GPIO模擬I2C協議的驅動,在核心中已經實現了,我們要做的只需要配置2根GPIO即可。
GPIO模擬I2C協議的驅動位於drivers/i2c/busses目錄。驅動名稱為“i2c-gpio”,驅動檔案為drivers/i2c/busses/i2c-gpio.c
1. GPIO支援要先保證是選上的
2. 先配置核心
Device Drivers->
I2C support --->
I2C Hardware Bus support --->
<*> GPIO-based bitbanging I2C
3. 修改核心檔案
static struct i2c_gpio_platform_data da850_gpio_i2c_pdata = {
.sda_pin = DA850_GPIO_I2C_SDA, //通用的gpio引腳
.scl_pin = DA850_GPIO_I2C_SCL, //通用的gpio引腳
.udelay = 10, /* 50 KHz */
.timeout = 100,
};
static struct platform_device da850_gpio_i2c = {
.name = "i2c-gpio",
.id = 2, //生成 i2c-gpio.2
.dev = {
.platform_data = &da850_gpio_i2c_pdata,
},
};
平臺初始化
static __init void da850_evm_init(void)
{
..........
..........
/*
* Though bootloader takes care to set emif clock at allowed
* possible rate. Kernel needs to reconfigure this rate to
* support platforms requiring fixed emif clock rate.
*/
ret = da850_set_emif_clk_rate();
if (ret)
pr_warning("da850_evm_init: Failed to set rate of pll0_sysclk3/emif clock: %d\n",
ret);
ret = da850_register_edma(da850_edma_rsv);
if (ret)
pr_warning("da850_evm_init: edma registration failed: %d\n",
ret);
ret = davinci_cfg_reg_list(da850_i2c0_pins);
if (ret)
pr_warning("da850_evm_init: i2c0 mux setup failed: %d\n",
ret);
platform_device_register(&da850_gpio_i2c); //註冊平臺裝置
ret = da8xx_register_i2c(0, &da850_evm_i2c_pdata);
if (ret) {
pr_warning("da850_evm_init: i2c0 mux setup failed: %d\n",
ret);
return;
}
.........
i2c_register_board_info(2, da850_gpio_i2c_devices, //gpio-i2c
ARRAY_SIZE(da850_gpio_i2c_devices));
........
}
i2c_board_info :這是個列舉型別的陣列,把要加入的GPIO加入到這個陣列裡面。
static struct i2c_board_info __initdata da850_gpio_i2c_devices[] = {
{
I2C_BOARD_INFO("bq20z75", 0x0b),
},
};
這樣就實現了gpio-i2c功能了,但是在使用前需要先確保當期使用的io口是作為GPIO使用的,我就踩了這個坑。
對於引腳配置成GPIO過程
OMAP-L138 C6000 DSP+ARM Processor Technical Reference Manual (Rev.A).pdf 244頁有相應的管腳配置說明
引腳配置複用的位置在\linux-3.3\arch\arm\mach-davinci\da850.c的 結構體static const struct mux_config da850_pins[] = {}
static const struct mux_config da850_pins[] = {
#ifdef CONFIG_DAVINCI_MUX
..............
MUX_CFG(DA850, EMA_A_22, 10, 4, 15, 1, false)
MUX_CFG(DA850, EMA_A_20, 10, 12, 15, 1, false)
...............
}
引數說明: MUX_CFG(DA850, EMA_A_22, 4, 24, 15, 2, false)
MUX_CFG :這個巨集在arch/arm/mach-davinci/mux.h定義
#define MUX_CFG(soc, desc, muxreg, mode_offset, mode_mask, mux_mode, dbg)
DA850: 平臺
EMA_A_22: 管腳描述
4: 第4組pinmux暫存器(引腳複用暫存器的名稱,展開為 PINMUX4 )
24: 在暫存器PINMUX4中的bit24到bit27位,相應位的偏移值
15: 就是pinmux相應位全為1的值(掩碼值)
2 : mux_mode(設定這個複用暫存器的GPIO引腳功能)
現在需要將da850.c使用為EMA_A的預設的引腳複用為GPIO引腳,檢視管腳配置pdf說明是否支援,
//需要注意將使用該暫存器複用功能的地方全註釋,不然編譯會報錯
da850.c , include/mach/mux.h , board-da850-evm.c
管腳描述改為當前的修改後的描述,我當前修改描述為GPIO4_4
///
管腳配置完成修改完成後對核心修改驗證方式
用i2cdetect檢測有幾組i2c匯流排在系統上,輸入:./i2cdetect -l
用i2cdetect檢測掛載在i2c匯流排上器件,
i2cdetect -r -y 2(檢測i2c-1上的掛載情況)
由上圖可知 0x0b地址有掛載。而這幾個分別是0x0b(bq20z75)
i2cset -f -y 1 0x0b 0x09 0x3f (設定i2c-1上0x0b 器件的0x09 暫存器值為0x3f)
i2cget -f -y 1 0x0b 0x09 (讀取i2c-1上0x0b 器件的0x09 暫存器值)
i2cdetect -r -y 2 這個命令能確定i2c-2匯流排上那個地址是掛載裝置的
此方式驗證i2c功能的從裝置地址是否正確,如果寫入的從裝置地址不是實際地址則寫入時是不生效的
i2c功能資料讀寫
//test.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <linux/i2c.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
#include <errno.h>
#include <string.h>
unsigned char i2c_read(unsigned char device_addr, unsigned char sub_addr, unsigned char *buff, int ByteNo)
{
int fd, ret, i;
unsigned char buftmp[32];
struct i2c_rdwr_ioctl_data i2c_data;
const char *i2c_dev = "/dev/i2c-2";
device_addr >>= 1;
//init
fd = open(i2c_dev, O_RDWR);
if (fd<0)
{
printf("not have /dev/i2c-1 t\r\n");
return -1;
}
i2c_data.nmsgs = 2;
i2c_data.msgs = (struct i2c_msg *)malloc(i2c_data.nmsgs *sizeof(struct i2c_msg));
if (i2c_data.msgs == NULL)
{
printf("malloc error");
close(fd);
return -1;
}
ioctl(fd, I2C_TIMEOUT, 1);
ioctl(fd, I2C_RETRIES, 2);
寫i2c暫存器直接寫,讀i2c暫存器之前需要先向要讀取的暫存器寫,我這個只有讀操作
//write reg
memset(buftmp, 0, 32);
buftmp[0] = sub_addr;
i2c_data.msgs[0].len = 1;
i2c_data.msgs[0].addr = device_addr;
i2c_data.msgs[0].flags = 0; // 0: write 1:read
i2c_data.msgs[0].buf = buftmp;
//read data
i2c_data.msgs[1].len = ByteNo;
i2c_data.msgs[1].addr = device_addr;
i2c_data.msgs[1].flags = 1; // 0: write 1:read
i2c_data.msgs[1].buf = buff;
ret = ioctl(fd, I2C_RDWR, (unsigned long)&i2c_data);
if (ret < 0)
{
printf("read data %x %x error\r\n", device_addr, sub_addr);
close(fd);
free(i2c_data.msgs);
return 1;
}
free(i2c_data.msgs);
close(fd);
printf("i2c_read from: 0x%02x:\t",buftmp[0]);
//讀取的是2byte資料,先低8位,後高8位,拼接起來就是實際資料,根據需要對資料進行操作
int data = buff[1] *256 + buff[0];
printf(" %d\n",data);
for (i = 0; i < ByteNo; i++)
{
printf(" 0x%02x",buff[i]);
}
printf("\n");
return 0;
}
int main(void)
{
unsigned char buf[10]= {0};
i2c_read(0x16, 0x16, buf, 2); //10 is on charging, 50 is not charging
}
相關文章
- 驅動篇——核心空間與核心模組
- 【linux】驅動-2-核心模組Linux
- 驅動Driver-Pinctrl-GPIO子系統
- 【linux】驅動-11-gpio子系統Linux
- Arduino 驅動模擬溫度感測器模組UI
- Linux驅動之I2C匯流排裝置以及驅動Linux
- Linux驅動實踐:如何編寫【 GPIO 】裝置的驅動程式?Linux
- MM32F0140 GPIO驅動LED燈(MM32F0140 GPIO)
- AP316C I2C驅動示例
- MM32F0020 GPIO驅動LED燈(MM32F0020 GPIO Toggle)
- Linux核心模組驅動載入與dmesg除錯Linux除錯
- ZYNQ的gpio的硬體驅動庫知識
- FPGA對EEPROM驅動控制(I2C協議)FPGA協議
- 04_Linux下把驅動編譯進核心Linux編譯
- myvue 模擬vue核心原理Vue
- 驅動除錯—還原 QQ 過濾驅動對關鍵核心設施所做的修改(Part II)除錯
- linux核心匯流排驅動模型-驅動篇Linux模型
- 人工智慧:大規模技術驅動創新的核心人工智慧
- Linux驅動之GPIO子系統和pinctrl子系統Linux
- 核心必須懂(四): 撰寫核心驅動
- 框架-裝置與驅動的拆分及實現-I2C框架
- MicroPython 硬體 I2C 驅動 MPU6050 - RaspberryPi Pico 示例Python
- Windows核心驅動-程序回撥Windows
- ubuntu修改預設啟動核心Ubuntu
- xmake v2.6.2 釋出,新增 Linux 核心驅動模組構建支援Linux
- STM32 HAL 庫硬體 I2C 驅動 MPU6050
- linuxI2C驅動核心梳理Linux
- 領域驅動設計核心概念
- 港大發布OpenCity: 大模型驅動下的智慧城市"新核心"大模型
- 關於Linux核心自帶GPIO LED控制Linux
- Helloworld 驅動模組載入
- 移動端模擬滾動
- 驅動篇——核心程式設計基礎程式設計
- 模擬資料管理與運維管理,驅動新型電力系統創新運維
- Windows核心驅動學習(六)程式碼注入與核心掛鉤Windows
- 模擬滑屏動畫動畫
- .NET 下 模擬陣列越界陣列
- 驅動遊戲世界運轉的“心跳”:遊戲迴圈及實時模擬遊戲