mtk 平台的 I2C 适配器注册流程

前言

简单介绍了下 mtk 平台的 I2C 适配器注册流程
基于 3.18 内核

Adapter 注册流程

参考自韦东山视频 3.4 内核

static int s3c2440_i2c_xfer(struct i2c_adapter *adap,
		struct i2c_msg *msgs, int num)
{
}

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. 分配/设置i2c_adapter
 */
static struct i2c_adapter s3c2440_i2c_adapter = {
 .name			 = "s3c2440_100ask",
 .algo			 = &s3c2440_i2c_algo,
 .owner 		 = THIS_MODULE,
};

static int i2c_bus_s3c2440_init(void)
{
	/* 2. 注册i2c_adapter */

	i2c_add_adapter(&s3c2440_i2c_adapter);
	
	return 0;
}

static void i2c_bus_s3c2440_exit(void)
{
	i2c_del_adapter(&s3c2440_i2c_adapter);	
}

module_init(i2c_bus_s3c2440_init);
module_exit(i2c_bus_s3c2440_init);
MODULE_LICENSE("GPL");

MTK 适配器注册流程

/
// 为什么确定调用此文件?

// 定义位置:非主流
./drivers/misc/mediatek/cam_cal/src/common/cat24c16/cat24c16.c:19:#ifndef CONFIG_MTK_I2C_EXTENSION
./drivers/misc/mediatek/cam_cal/src/common/cat24c16/cat24c16.c:20:#define CONFIG_MTK_I2C_EXTENSION // 【这里定义了?应该不影响吧】
./drivers/misc/mediatek/cam_cal/src/common/cat24c16/cat24c16.c:23:#undef CONFIG_MTK_I2C_EXTENSION
./drivers/misc/mediatek/cam_cal/src/common/GT24c32a/GT24c32a.c:35:#ifndef CONFIG_MTK_I2C_EXTENSION
./drivers/misc/mediatek/cam_cal/src/common/GT24c32a/GT24c32a.c:36:#define CONFIG_MTK_I2C_EXTENSION
./drivers/misc/mediatek/cam_cal/src/common/GT24c32a/GT24c32a.c:39:#undef CONFIG_MTK_I2C_EXTENSION

///
// 最终确认:
Z:\work\E266L_CMCC_0508_eng\out\target\product\E266L\obj\KERNEL_OBJ\.config
    CONFIG_MTK_I2C=y
    CONFIG_MTK_I2C_EXTENSION=y

/
// 使用位置:使用了哪种 i2c
./drivers/misc/mediatek/i2c/Makefile:1:ifeq ($(CONFIG_MTK_I2C_EXTENSION),y) 
    ifeq ($(CONFIG_MTK_I2C_EXTENSION),y)
    obj-$(CONFIG_MTK_I2C)  += i2c/
    endif
    
    // i2c/Makefile
    obj-$(CONFIG_MTK_I2C) := i2c.o i2c_common.o
    
./drivers/i2c/busses/Makefile:88:ifneq ($(CONFIG_MTK_I2C_EXTENSION),y)
    ifneq ($(CONFIG_MTK_I2C_EXTENSION),y)   // 注册判断条件为没有定义
    obj-$(CONFIG_MTK_I2C)		+= i2c-mtk.o
    obj-$(CONFIG_MTK_I2C)		+= i2c_mtk_debug.o
    endif


///
// i2c 总线的注册:
// I2c-core.c (kernel-3.18\drivers\i2c)
postcore_initcall(i2c_init);
static int __init i2c_init(void)
        //
        //      struct bus_type i2c_bus_type = {
        //          .name		= "i2c",
        //          .match		= i2c_device_match,
        //          .probe		= i2c_device_probe,
        //          .remove		= i2c_device_remove,
        //          .shutdown	= i2c_device_shutdown,
        //          .pm		= &i2c_device_pm_ops,
        //      };
        retval = bus_register(&i2c_bus_type);
        retval = i2c_add_driver(&dummy_driver);






// I2c.c (kernel-3.18\drivers\misc\mediatek\i2c\mt6755)
【i2c 适配器初始化流程】:
module_init(mt_i2c_init);
mt_i2c_init(void)      
    /
    // ioremap the AP_DMA base and use offset get the I2C DMA base
    // dts 中的相关设备 dma 设置
    //      ap_dma@11000000 {
    //          compatible = "mediatek,ap_dma";
    //          reg = <0x11000000 0x1000>;
    //          interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_LOW>;
    //      };
    ap_dma_node = of_find_compatible_node(NULL, NULL, "mediatek,ap_dma");
    ap_dma_base = of_iomap(ap_dma_node, 0);
    
    
    //
    // 注册平台设备
    //      static struct platform_driver mt_i2c_driver = {
    //          .probe = mt_i2c_probe,
    //          .remove = mt_i2c_remove,
    //          .suspend = mt_i2c_suspend,
    //          .resume = mt_i2c_resume,
    //          .driver = {
    //              .name = I2C_DRV_NAME,
    //              .owner = THIS_MODULE,
    //      #ifdef CONFIG_OF
    //              .of_match_table = mt_i2c_of_match,
    //                      // static const struct of_device_id mt_i2c_of_match[] = {
    //                      //     {.compatible = "mediatek,mt6755-i2c",},
    //                      //     {},
    //                      // };
    //                      
    //                      // dts 相关项:【注册流程在 平台初始化时添加的 platform_device 】
    //                      //   // Mt6755.dtsi (z:\work\e266l_cmcc\kernel-3.18\arch\arm64\boot\dts)
    //                      //   i2c1: i2c@11008000 {
    //                      //       compatible = "mediatek,mt6755-i2c", "mediatek,i2c1";
    //                      //       cell-index = <1>;
    //                      //       reg = <0x11008000 0x1000>,
    //                      //             <0x11000180 0x80>;
    //                      //       interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_LOW>;
    //                      //       clock-div = <10>;
    //                      //       clocks = <&infrasys INFRA_I2C1>, <&infrasys INFRA_AP_DMA>;
    //                      //       clock-names = "main", "dma";
    //                      //       #address-cells = <1>;
    //                      //       #size-cells = <0>;
    //                      //   };
    //      #endif
    //          },
    //      };
    platform_driver_register(&mt_i2c_driver);


/
// 匹配后调用 probe() 详见【平台设备驱动】看如何解析 dts, 添加 platform_device
mt_i2c_probe(struct platform_device *pdev)
    /
    // 这也是在解析 dts 时添加了相关硬件资源 
    // Request platform_device IO resource
    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    request_mem_region(res->start, resource_size(res), pdev->name)
    
    /
    // 分配 MTK 封装的适配器驱动结构体
    //
    //      struct mt_i2c_t {
    //      #ifdef I2C_DRIVER_IN_KERNEL
    //          // ==========only used in kernel================  
    //          struct i2c_adapter adap;	    // i2c host adapter  
    //          struct device *dev;	            // the device object of i2c host adapter  
    //          atomic_t trans_err;	            // i2c transfer error  
    //          atomic_t trans_comp;	        // i2c transfer completion  
    //          atomic_t trans_stop;	        // i2c transfer stop  
    //          spinlock_t lock;	            // for struct mt_i2c_t protection  
    //          struct mutex mutex;	            // protect from different API  
    //          wait_queue_head_t wait;	        // i2c transfer wait queue  
    //      #endif
    //          // ==========set in i2c probe============  
    //          void __iomem *base;	            // i2c base addr  
    //          u16 id;
    //          u32 irqnr;		                // i2c interrupt number  
    //          u16 irq_stat;		            // i2c interrupt status  
    //          u32 clk;		                // host clock speed in khz  
    //          u32 pdn;		                //clock number  
    //          // ==========common data define============  
    //          enum i2c_trans_st_rs st_rs;
    //          enum mt_trans_op op;
    //          void __iomem *pdmabase;
    //          u32 speed;		                // The speed (khz)  
    //          u16 delay_len;		            // number of half pulse between transfers in a trasaction  
    //          u32 msg_len;		            // number of bytes for transaction  
    //          u8 *msg_buf;		            // pointer to msg data       
    //          u8 addr;		                // The 7-bit address of the slave device  
    //          u8 master_code;		            // master code in HS mode  
    //          u8 mode;		                // ST/FS/HS mode  
    //          // ==========reserved function============  
    //          u8 is_push_pull_enable;	        // IO push-pull or open-drain  
    //          u8 is_clk_ext_disable;	        // clk entend default enable  
    //          u8 is_dma_enabled;	            // Transaction via DMA instead of 8-byte FIFO  
    //          u8 read_flag;		            // read,write,read_write  
    //          bool dma_en;
    //          bool poll_en;
    //          bool pushpull;		            // open drain  
    //          bool filter_msg;	            // filter msg error log  
    //          bool i2c_3dcamera_flag;	// flag for 3dcamera  
    //      
    //          // ==========define reg============  
    //          u16 timing_reg;
    //          u16 high_speed_reg;
    //          u16 control_reg;
    //          u32 last_speed;
    //          u8 last_mode;
    //          u32 default_speed;
    //          struct mt_trans_data trans_data;
    //          struct i2c_dma_buf dma_buf;
    //      #if !defined(CONFIG_MTK_CLKMGR)
    //          struct clk *clk_main;	        // main clock for i2c bus  
    //          struct clk *clk_dma;	        // DMA clock for i2c via DMA  
    //      #endif
    //      };
    i2c = kzalloc(sizeof(struct mt_i2c_t), GFP_KERNEL);

    /
    // 初始化 mt_i2c_t 结构体
    i2c->base = of_iomap(pdev->dev.of_node, 0);
    if (of_property_read_u32(pdev->dev.of_node, "cell-index", &pdev->id)) 
    irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
    if (of_property_read_u32(pdev->dev.of_node, "def_speed", &pdev->id))
    i2c->irqnr = irq;
    i2c->adap.nr = i2c->id;
	i2c->adap.owner = THIS_MODULE;
	i2c->adap.algo = &mt_i2c_algorithm;     // 核心收发函数
	i2c->adap.algo_data = NULL;
	i2c->adap.timeout = 2 * HZ;	// 2s
	i2c->adap.retries = 1;	                // DO NOT TRY 
	// need GFP_DMA32 flag to confirm DMA alloc PA is 32bit range 
	i2c->dma_buf.vaddr = dma_alloc_coherent(&pdev->dev, MAX_DMA_TRANS_NUM,&i2c->dma_buf.paddr, GFP_KERNEL | GFP_DMA32);
    i2c->pdmabase = DMA_I2C_BASE(i2c->id, ap_dma_base);
    init_waitqueue_head(&i2c->wait);

	mt_i2c_clock_enable(i2c);
	mt_i2c_init_hw(i2c);
	mt_i2c_clock_disable(i2c);
    /
    // 申请 I2C 中断
    ret = request_irq(i2c->irqnr, mt_i2c_irq, IRQF_TRIGGER_LOW, dev_name(&pdev->dev), i2c);

    /
    //  i2c_add_numbered_adapter()
    //      如果 dts 没有指定 id, 则动态分配一个,再进行注册
    //      注册指定 id 号的 i2c 适配器
    //           device_register(): 这里仅是将 adapter 也放在总线的设备列表中
    //              发送 uevent 事件通知用户空间
    //              查找现有驱动是否有匹配当前设备的
    //                   1. 在 dts 中进行匹配   
    //                   2. 匹配 i2c driver 的 id_table   
    //              匹配上了,调用 probe() 函数
    //                   首先调用总线的 i2c_device_probe() 函数, 主要根据 dts 设置通信频率
    //                   然后调用驱动的 probe() 函数 
    //      
    //           of_i2c_register_devices(adap):
    //               这里遍历的应该是 compatible = "mediatek,mt6755-i2c" 
    //               相关的节点,因为适配器适配时,就用的些属性值,表示其代表一个 i2c 适配器
    //               那么这个节点下辖相关的,就是i2c device,需要通过 i2c_new_device() 注册
    //      
    //           遍历调用 i2c_board_info, 注册 i2c device
    //      
    //           Detect supported devices on that bus, and instantiate them
    //           遍历 drviver 的 address_list, 通过 i2c_smbus_xfer() 检测是否有设备
    //               如果检测到设备:创建 i2c device
    //               调用老的 i2c 驱动接口 driver->attach_adapter(adap);
    ret = i2c_add_numbered_adapter(&i2c->adap);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值