控制器驅動
I2C 總線驅動重點是 I2C 適配器驅動,這里要用到兩個重要的數據結構:i2c_adapter 和 i2c_algorithm。其中,Linux 內核將 SOC 的 I2C 適配器(控制器)抽象成 i2c_adapter。
對于一個 I2C 適配器,肯定要對外提供讀寫 API 函數,設備驅動程序可以使用這些 API 函數來完成讀寫操作。i2c_algorithm 就是 I2C 適配器與 I2C 設備進行通信的方法。
I2C 總線驅動,或者說 I2C 適配器驅動的主要工作就是初始化 i2c_adapter 結構體變量,然后設置 i2c_algorithm 中的 master_xfer 函數。完成以后通過 i2c_add_numbered_adapter 或 i2c_add_adapter 這兩個函數向系統注冊設置好的 i2c_adapter。
I2C 控制器驅動加載
設備樹 mt6885.dts
驅動
驅動和設備樹匹配以后,probe 函數開始執行,重要的地方博主都進行了注釋,不重要的部分進行了刪除。
static int mt_i2c_probe(struct platform_device *pdev)
{
int ret = 0;
struct mt_i2c *i2c; //控制器結構體
unsigned int clk_src_in_hz;
struct resource *res;
const struct of_device_id *of_id;
//申請內存
i2c = devm_kzalloc(&pdev- >dev, sizeof(struct mt_i2c), GFP_KERNEL);
//獲取設備樹節點
ret = mt_i2c_parse_dt(pdev- >dev.of_node, i2c);
//從設備樹獲取 I2C 控制器寄存器物理基地址
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
//進行內存映射,得到 Linux 內核使用的虛擬地址
i2c- >base = devm_ioremap_resource(&pdev- >dev, res);
.....
//獲取中斷號
i2c- >irqnr = platform_get_irq(pdev, 0);
init_waitqueue_head(&i2c- >wait);
//請求中斷,中斷服務函數為 mt_i2c_irq
ret = devm_request_irq(&pdev- >dev, i2c- >irqnr, mt_i2c_irq,
IRQF_NO_SUSPEND | IRQF_TRIGGER_NONE, I2C_DRV_NAME, i2c);
of_id = of_match_node(mtk_i2c_of_match, pdev- >dev.of_node);
//填充 adapter 結構體各個參數
i2c- >dev_comp = of_id- >data;
i2c- >i2c_pll_info = &i2c_pll_info;
i2c- >adap.dev.of_node = pdev- >dev.of_node;
i2c- >dev = &i2c- >adap.dev;
i2c- >adap.dev.parent = &pdev- >dev;
i2c- >adap.owner = THIS_MODULE;
i2c- >adap.algo = &mt_i2c_algorithm;
i2c- >adap.algo_data = NULL;
i2c- >adap.timeout = 2 * HZ;
i2c- >adap.retries = 1;
i2c- >adap.nr = i2c- >id;
spin_lock_init(&i2c- >cg_lock);
......
mutex_init(&i2c- >i2c_mutex);
ret = i2c_set_speed(i2c, clk_src_in_hz);
ret = mt_i2c_clock_enable(i2c);
mt_i2c_init_hw(i2c);
mt_i2c_clock_disable(i2c);
// DMA 相關
if (i2c- >ch_offset_default)
i2c- >dma_buf.vaddr = dma_alloc_coherent(&pdev- >dev,
(PAGE_SIZE * 2), &i2c- >dma_buf.paddr, GFP_KERNEL);
else
i2c- >dma_buf.vaddr = dma_alloc_coherent(&pdev- >dev,
PAGE_SIZE, &i2c- >dma_buf.paddr, GFP_KERNEL);
if (i2c- >dma_buf.vaddr == NULL) {
dev_info(&pdev- >dev, "dma_alloc_coherent failn");
return -ENOMEM;
}
i2c_set_adapdata(&i2c- >adap, i2c);
//向 Linux 內核注冊 i2c_adapter
ret = i2c_add_numbered_adapter(&i2c- >adap);
platform_set_drvdata(pdev, i2c);
return 0;
}
-
控制器
+關注
關注
114文章
16854瀏覽量
182368 -
驅動
+關注
關注
12文章
1882瀏覽量
86374 -
I2C
+關注
關注
28文章
1520瀏覽量
126617
發布評論請先 登錄
GPIO模擬I2C總線的驅動設計與實現

實現I2C總線控制器的VHDL源代碼
I2C總線在Linux系統中的驅動設計
MAXQ2000微控制器軟件I2C驅動

基于Verilog的I2C控制器的設計與綜合

I2C總線控制器的工作原理及EEPROM的Linux驅動程序的設計

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

嵌入式內核及驅動開發-09IIC子系統框架使用(I2C協議和時序,I2C驅動框架,I2C從設備驅動開發,MPU6050硬件連接

linux移植MPU6050的I2C驅動

評論