控制器驅(qū)動
I2C 總線驅(qū)動重點(diǎn)是 I2C 適配器驅(qū)動,這里要用到兩個(gè)重要的數(shù)據(jù)結(jié)構(gòu):i2c_adapter 和 i2c_algorithm。其中,Linux 內(nèi)核將 SOC 的 I2C 適配器(控制器)抽象成 i2c_adapter。
對于一個(gè) I2C 適配器,肯定要對外提供讀寫 API 函數(shù),設(shè)備驅(qū)動程序可以使用這些 API 函數(shù)來完成讀寫操作。i2c_algorithm 就是 I2C 適配器與 I2C 設(shè)備進(jìn)行通信的方法。
I2C 總線驅(qū)動,或者說 I2C 適配器驅(qū)動的主要工作就是初始化 i2c_adapter 結(jié)構(gòu)體變量,然后設(shè)置 i2c_algorithm 中的 master_xfer 函數(shù)。完成以后通過 i2c_add_numbered_adapter 或 i2c_add_adapter 這兩個(gè)函數(shù)向系統(tǒng)注冊設(shè)置好的 i2c_adapter。
I2C 控制器驅(qū)動加載
設(shè)備樹 mt6885.dts

驅(qū)動

驅(qū)動和設(shè)備樹匹配以后,probe 函數(shù)開始執(zhí)行,重要的地方博主都進(jìn)行了注釋,不重要的部分進(jìn)行了刪除。
static int mt_i2c_probe(struct platform_device *pdev)
{
int ret = 0;
struct mt_i2c *i2c; //控制器結(jié)構(gòu)體
unsigned int clk_src_in_hz;
struct resource *res;
const struct of_device_id *of_id;
//申請內(nèi)存
i2c = devm_kzalloc(&pdev- >dev, sizeof(struct mt_i2c), GFP_KERNEL);
//獲取設(shè)備樹節(jié)點(diǎn)
ret = mt_i2c_parse_dt(pdev- >dev.of_node, i2c);
//從設(shè)備樹獲取 I2C 控制器寄存器物理基地址
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
//進(jìn)行內(nèi)存映射,得到 Linux 內(nèi)核使用的虛擬地址
i2c- >base = devm_ioremap_resource(&pdev- >dev, res);
.....
//獲取中斷號
i2c- >irqnr = platform_get_irq(pdev, 0);
init_waitqueue_head(&i2c- >wait);
//請求中斷,中斷服務(wù)函數(shù)為 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 結(jié)構(gòu)體各個(gè)參數(shù)
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 相關(guān)
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 內(nèi)核注冊 i2c_adapter
ret = i2c_add_numbered_adapter(&i2c- >adap);
platform_set_drvdata(pdev, i2c);
return 0;
}
-
控制器
+關(guān)注
關(guān)注
114文章
17787瀏覽量
193097 -
驅(qū)動
+關(guān)注
關(guān)注
12文章
1954瀏覽量
88522 -
I2C
+關(guān)注
關(guān)注
28文章
1556瀏覽量
131221
發(fā)布評論請先 登錄
GPIO模擬I2C總線的驅(qū)動設(shè)計(jì)與實(shí)現(xiàn)
實(shí)現(xiàn)I2C總線控制器的VHDL源代碼
I2C總線在Linux系統(tǒng)中的驅(qū)動設(shè)計(jì)
基于Verilog的I2C控制器的設(shè)計(jì)與綜合
I2C控制器使用指南
I2C總線控制器的工作原理及EEPROM的Linux驅(qū)動程序的設(shè)計(jì)
Linux驅(qū)動:I2C設(shè)備驅(qū)動(基于Freescale i.MX6ULL平臺了解I2C的驅(qū)動框架,順便寫個(gè)簡陋的MPU6050驅(qū)動)
嵌入式內(nèi)核及驅(qū)動開發(fā)-09IIC子系統(tǒng)框架使用(I2C協(xié)議和時(shí)序,I2C驅(qū)動框架,I2C從設(shè)備驅(qū)動開發(fā),MPU6050硬件連接
linux移植MPU6050的I2C驅(qū)動
硬件I2C與模擬I2C
I2C子系統(tǒng)SW Architecture
I2C控制器驅(qū)動介紹
評論