[計算機軟件及應用]基于高通MSM8x60的I2C驅動終極講解_第1頁
[計算機軟件及應用]基于高通MSM8x60的I2C驅動終極講解_第2頁
[計算機軟件及應用]基于高通MSM8x60的I2C驅動終極講解_第3頁
[計算機軟件及應用]基于高通MSM8x60的I2C驅動終極講解_第4頁
[計算機軟件及應用]基于高通MSM8x60的I2C驅動終極講解_第5頁
已閱讀5頁,還剩33頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、基于高通MSM 8x60的I2C驅動終極講解(1)(2012-04-22 17:30)標簽:轉載 分類:linux driver study原文地址:基于高通MSM 8x60的I2C驅動終極講解(1)作者:shangbaogen網上的I2C驅動講解已經很多啦,我想不想畫蛇添足,我想寫一個完整的I2C驅動,包括系統(tǒng)啟動,總線注冊,驅動注冊,設備注冊,里面會貫穿Linux設備驅動模型,platform機制等等,基于高通MSM 8x60,I2C控制器為qup,下面開始進入正題:首先是平臺設備的注冊:源碼位置:(msm/arch/arm/mach-msm/devices-msm8x60.c)首先說下平

2、臺設備,因為Linux所有的設備都是通過總線控制器連接到CPU的,但是還有一些設備不是通過總線控制器連接到CPU,所以就有了platform總線虛擬總線,把那些不是真正通過總線控制器相連的設備,比如:SOC的片內設備,片內控制器,這些都歸為平臺設備.把這些平臺設備通過虛擬總線連接到cpu上,以便維護Linux設備模型中的,總線,設備,驅動之間的關系。首先注冊BSP的平臺設備驅動,其中I2C控制器的平臺設備如下:先看下高通的8x60,靠,有6個控制器,所有接下來的事情就是淡定。下面的是6個控制器在I2C控制器的ID編號#define MSM_GSBI3_QUP_I2C_BUS_ID 0#defi

3、ne MSM_GSBI4_QUP_I2C_BUS_ID 1#define MSM_GSBI9_QUP_I2C_BUS_ID 2#define MSM_GSBI8_QUP_I2C_BUS_ID 3#define MSM_GSBI7_QUP_I2C_BUS_ID 4#define MSM_GSBI12_QUP_I2C_BUS_ID 5下面是六個控制器所用到的資源static struct resource gsbi3_qup_i2c_resources = .name= qup_phys_addr,.start= MSM_GSBI3_QUP_PHYS,.end= MSM_GSBI3_QUP_PHY

4、S + SZ_4K - 1,.flags= IORESOURCE_MEM,.name= gsbi_qup_i2c_addr,.start= MSM_GSBI3_PHYS,.end= MSM_GSBI3_PHYS + 4 - 1,.flags= IORESOURCE_MEM,.name= qup_err_intr,.start= GSBI3_QUP_IRQ,.end= GSBI3_QUP_IRQ,.flags= IORESOURCE_IRQ,;static struct resource gsbi4_qup_i2c_resources = .name= qup_phys_addr,.start=

5、 MSM_GSBI4_QUP_PHYS,.end= MSM_GSBI4_QUP_PHYS + SZ_4K - 1,.flags= IORESOURCE_MEM,.name= gsbi_qup_i2c_addr,.start= MSM_GSBI4_PHYS,.end= MSM_GSBI4_PHYS + 4 - 1,.flags= IORESOURCE_MEM,.name= qup_err_intr,.start= GSBI4_QUP_IRQ,.end= GSBI4_QUP_IRQ,.flags= IORESOURCE_IRQ,;static struct resource gsbi7_qup_i

6、2c_resources = .name= qup_phys_addr,.start= MSM_GSBI7_QUP_PHYS,.end= MSM_GSBI7_QUP_PHYS + SZ_4K - 1,.flags= IORESOURCE_MEM,.name= gsbi_qup_i2c_addr,.start= MSM_GSBI7_PHYS,.end= MSM_GSBI7_PHYS + 4 - 1,.flags= IORESOURCE_MEM,.name= qup_err_intr,.start= GSBI7_QUP_IRQ,.end= GSBI7_QUP_IRQ,.flags= IORESOU

7、RCE_IRQ,;static struct resource gsbi8_qup_i2c_resources = .name= qup_phys_addr,.start= MSM_GSBI8_QUP_PHYS,.end= MSM_GSBI8_QUP_PHYS + SZ_4K - 1,.flags= IORESOURCE_MEM,.name= gsbi_qup_i2c_addr,.start= MSM_GSBI8_PHYS,.end= MSM_GSBI8_PHYS + 4 - 1,.flags= IORESOURCE_MEM,.name= qup_err_intr,.start= GSBI8_

8、QUP_IRQ,.end= GSBI8_QUP_IRQ,.flags= IORESOURCE_IRQ,;static struct resource gsbi9_qup_i2c_resources = .name= qup_phys_addr,.start= MSM_GSBI9_QUP_PHYS,.end= MSM_GSBI9_QUP_PHYS + SZ_4K - 1,.flags= IORESOURCE_MEM,.name= gsbi_qup_i2c_addr,.start= MSM_GSBI9_PHYS,.end= MSM_GSBI9_PHYS + 4 - 1,.flags= IORESO

9、URCE_MEM,.name= qup_err_intr,.start= GSBI9_QUP_IRQ,.end= GSBI9_QUP_IRQ,.flags= IORESOURCE_IRQ,;static struct resource gsbi12_qup_i2c_resources = .name= qup_phys_addr,.start= MSM_GSBI12_QUP_PHYS,.end= MSM_GSBI12_QUP_PHYS + SZ_4K - 1,.flags= IORESOURCE_MEM,.name= gsbi_qup_i2c_addr,.start= MSM_GSBI12_P

10、HYS,.end= MSM_GSBI12_PHYS + 4 - 1,.flags= IORESOURCE_MEM,.name= qup_err_intr,.start= GSBI12_QUP_IRQ,.end= GSBI12_QUP_IRQ,.flags= IORESOURCE_IRQ,;下面是為6個I2C控制器所注冊平臺設備驅動需要的結構體/* Use GSBI3 QUP for /dev/i2c-0 */struct platform_device msm_gsbi3_qup_i2c_device = .name= qup_i2c,.id= MSM_GSBI3_QUP_I2C_BUS_ID

11、,.num_resources= ARRAY_SIZE(gsbi3_qup_i2c_resources),.resource= gsbi3_qup_i2c_resources,;/* Use GSBI4 QUP for /dev/i2c-1 */struct platform_device msm_gsbi4_qup_i2c_device = .name= qup_i2c,.id= MSM_GSBI4_QUP_I2C_BUS_ID,.num_resources= ARRAY_SIZE(gsbi4_qup_i2c_resources),.resource= gsbi4_qup_i2c_resou

12、rces,;/* Use GSBI8 QUP for /dev/i2c-3 */struct platform_device msm_gsbi8_qup_i2c_device = .name= qup_i2c,.id= MSM_GSBI8_QUP_I2C_BUS_ID,.num_resources= ARRAY_SIZE(gsbi8_qup_i2c_resources),.resource= gsbi8_qup_i2c_resources,;/* Use GSBI9 QUP for /dev/i2c-2 */struct platform_device msm_gsbi9_qup_i2c_de

13、vice = .name= qup_i2c,.id= MSM_GSBI9_QUP_I2C_BUS_ID,.num_resources= ARRAY_SIZE(gsbi9_qup_i2c_resources),.resource= gsbi9_qup_i2c_resources,;/* Use GSBI7 QUP for /dev/i2c-4 (Marimba) */struct platform_device msm_gsbi7_qup_i2c_device = .name= qup_i2c,.id= MSM_GSBI7_QUP_I2C_BUS_ID,.num_resources= ARRAY

14、_SIZE(gsbi7_qup_i2c_resources),.resource= gsbi7_qup_i2c_resources,;/* Use GSBI12 QUP for /dev/i2c-5 (Sensors) */struct platform_device msm_gsbi12_qup_i2c_device = .name= qup_i2c,.id= MSM_GSBI12_QUP_I2C_BUS_ID,.num_resources= ARRAY_SIZE(gsbi12_qup_i2c_resources),.resource= gsbi12_qup_i2c_resources,;注

15、意該6個平臺設備結構體的name都是qup_i2c,下面這些平臺設備將在BSP資源注冊的時候給添加到系統(tǒng)。基于高通MSM 8x60的I2C驅動終極講解(2)(2012-04-22 17:30)標簽:轉載 分類:linux driver study原文地址:基于高通MSM 8x60的I2C驅動終極講解(2)作者:shangbaogen上一篇文章已經把I2C控制器所用的platform devices準備好啦,現在開始注冊,該文件在板級支持文件中,board-xxx.c文件中。static struct platform_device *surf_devices _initdata = .#ifd

16、ef CONFIG_I2C_QUP&msm_gsbi3_qup_i2c_device,&msm_gsbi4_qup_i2c_device,&msm_gsbi7_qup_i2c_device,&msm_gsbi8_qup_i2c_device,&msm_gsbi9_qup_i2c_device,&msm_gsbi12_qup_i2c_device,#endif.;繼續(xù)對該I2C平臺設備結構體初始化static void _initmsm8x60_init_buses(void).#ifdef CONFIG_I2C_QUPmsm_gsbi3_qup_i2c_device.dev.platform_

17、data = &msm_gsbi3_qup_i2c_pdata;msm_gsbi4_qup_i2c_device.dev.platform_data = &msm_gsbi4_qup_i2c_pdata;msm_gsbi7_qup_i2c_device.dev.platform_data = &msm_gsbi7_qup_i2c_pdata;msm_gsbi8_qup_i2c_device.dev.platform_data = &msm_gsbi8_qup_i2c_pdata;msm_gsbi9_qup_i2c_device.dev.platform_data = &msm_gsbi9_qu

18、p_i2c_pdata;msm_gsbi12_qup_i2c_device.dev.platform_data = &msm_gsbi12_qup_i2c_pdata;#endif.其中初始化的platform_data如下static struct msm_i2c_platform_data msm_gsbi3_qup_i2c_pdata = .clk_freq = 100000,.src_clk_rate = 24000000,.clk = gsbi_qup_clk,.pclk = gsbi_pclk,.msm_i2c_config_gpio = gsbi_qup_i2c_gpio_con

19、fig,;static struct msm_i2c_platform_data msm_gsbi4_qup_i2c_pdata = .clk_freq = 100000,.src_clk_rate = 24000000,.clk = gsbi_qup_clk,.pclk = gsbi_pclk,.msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,;static struct msm_i2c_platform_data msm_gsbi7_qup_i2c_pdata = .clk_freq = 100000,.src_clk_rate = 24000

20、000,.clk = gsbi_qup_clk,.pclk = gsbi_pclk,.pri_clk = 60,.pri_dat = 59,.msm_i2c_config_gpio = gsbi7_qup_i2c_gpio_config,;static struct msm_i2c_platform_data msm_gsbi8_qup_i2c_pdata = .clk_freq = 100000,.src_clk_rate = 24000000,.clk = gsbi_qup_clk,.pclk = gsbi_pclk,.msm_i2c_config_gpio = gsbi_qup_i2c_

21、gpio_config,;static struct msm_i2c_platform_data msm_gsbi9_qup_i2c_pdata = .clk_freq = 100000,.src_clk_rate = 24000000,.clk = gsbi_qup_clk,.pclk = gsbi_pclk,.msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,;static struct msm_i2c_platform_data msm_gsbi12_qup_i2c_pdata = .clk_freq = 100000,.src_clk_rat

22、e = 24000000,.clk = gsbi_qup_clk,.pclk = gsbi_pclk,.use_gsbi_shared_mode = 1,.msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,;其中的msm_i2c_config_gpio賦值的值的定義如下static void gsbi7_qup_i2c_gpio_config(int adap_id, int config_type)if (config_type = 0) gpio_tlmm_config(gsbi7_gpio_table0, GPIO_CFG_ENABLE);gp

23、io_tlmm_config(gsbi7_gpio_table1, GPIO_CFG_ENABLE); else gpio_tlmm_config(gsbi7_i2c_table0, GPIO_CFG_ENABLE);gpio_tlmm_config(gsbi7_i2c_table1, GPIO_CFG_ENABLE);下面的函數會注冊該平臺設備static void _initmsm8x60_init(struct msm_board_data *board_data) .msm8x60_init_buses(); .platform_add_devices(surf_devices,ARR

24、AY_SIZE(surf_devices); .下面的函數會調用上面的初始化static void _initmsm8x60_ep680_init(void)msm8x60_init(&msm8x60_ep680_board_data);上面的函數會掛載到板級的結構中。MACHINE_START(MSM8X60_EP680, QCT MSM8X60 EP680).map_io = msm8x60_map_io,.init_irq = msm8x60_init_irq,.init_machine =msm8x60_ep680_init,/掛載的板級初始化函數.timer = &msm_timer

25、,MACHINE_END以上就是對I2C控制器的注冊?;诟咄∕SM 8x60的I2C驅動終極講解(3)(2012-05-15 11:40)標簽:轉載 分類:高通I2C原文地址:基于高通MSM 8x60的I2C驅動終極講解(3)作者:shangbaogen 上一節(jié)分解到平臺設備已經注冊,掛載到BSP板級結構體的.init_machine成員中啦,但是這個成員什么時間調用呢,也就是我們的驅動是在什么時候注冊進系統(tǒng)的呢,現在就來跟蹤下,看.init_machine函數什么時候調用的。要想知道整個流程是什么樣的,這個還要從老掉牙的start_kernel()函數說起該函數是整個kernel的起始入口

26、點:asmlinkage void _init start_kernel(void) . setup_arch(&command_line); .rest_init(); .其中的setup_arch()函數如下:void _init setup_arch(char *cmdline_p)struct machine_desc *mdesc;/*通過機器碼獲取板級結構體,這個結構體就是在BSP文件中的那個大的結構體*/mdesc = setup_machine(machine_arch_type); .init_machine = mdesc-init_machine;其中init_machi

27、ne是一個函數指針,該函數指針的初始化如下static void (*init_machine)(void) _initdata;static int _init customize_machine(void)/* customizes platform devices, or adds new ones */if (init_machine)init_machine();return 0;arch_initcall(customize_machine);其中牽涉到arch_initcall宏,把該宏展開,如下#define arch_initcall(fn)_define_initcall(

28、3,fn,3)#define _define_initcall(level,fn,id) static initcall_t _initcall_#fn#id _used _attribute_(_section_(.initcall level .init) = fn展開后的結果如下:static initcall_t _initcall_customize_machine3_used _attribute_(_section_(.initcall3.init) = customize_machine其中typedef int (*initcall_t)(void);把該函數放到.initc

29、all3.init段內該段在如下函數中執(zhí)行:static noinline void _init_refokrest_init(void) _releases(kernel_lock).kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);.其中kernel_init函數如下:static int _init kernel_init(void * unused).do_basic_setup();.其中的do_basic_setup()函數如下:static void _init do_basic_setup(void).do_i

30、nitcalls();.其中do_initcalls()函數如下:static void _init do_initcalls(void)initcall_t *fn;for (fn = _early_initcall_end; fn .initcall1.initpostcore_initcall(fn) -.initcall2.initarch_initcall(fn) -.initcall3.initsubsys_initcall(fn) -.initcall4.initfs_initcall(fn) -.initcall5.initdevice_initcall(fn) -.initc

31、all6.initlate_initcall(fn) -.initcall7.init而與2.4兼容的initcall(fn)則等價于device_initcall(fn)。各個子區(qū)段之間的順序是確定的,即先調用.initcall1.init中的函數指針再調用.initcall2.init中的函數指針,等等.而在每個子區(qū)段中的函數指針的順序是和鏈接順序相關的,是不確定的。在內核中,不同的init函數被放在不同的子區(qū)段中,因此也就決定了它們的調用順序.這樣也就解決了一些init函數之間必須保證一定的調用順序的問題。Uboot完成系統(tǒng)的引導并將Linux內核拷貝到內存之后,bootm - do_b

32、ootm_linux()跳轉到kernel的起始位置;壓縮過的kernel入口在arch/arm/boot/compressed/head.S,它將調用函數 decompress_kernel()解壓,打印 “Uncompressing Linux.”,調用gunzip(),打印done, booting the kernel.然后call_kernel,執(zhí)行解壓后的kernel,經linux/arch/arm/kernel/head.S調用start_kernel轉入體系結構無關的通用C代碼,在start_kernel()中完成了一系列系統(tǒng)初始化,設備及驅動的注冊即在此時完成:asmlink

33、age void _initstart_kernel(void) .rest_init();start_kernel()中的函數rest_init()將創(chuàng)建第一個核心線程kernel_thread(init, NULL, CLONE_FS | CLONE_SIGHAND),調用init()函數:static intinit(void * unused)do_basic_setup();/判斷在啟動時是否指定了init參數,如果指定則執(zhí)行用戶init進程,成功將不會返回 if (execute_command) run_init_process(execute_command); printk(

34、KERN_WARNING Failed to execute %s. Attempting defaults.n, execute_command);/*如果沒有指定init啟動參數,則查找下面的目錄init進程,成功將不會返回,否則打印出錯信息*/run_init_process(/sbin/init);run_init_process(/etc/init);run_init_process(/bin/init);run_init_process(/bin/sh);panic(No init found. Try passing init= option to kernel.);繼而調用函數

35、do_basic_setup()(此時與體系結構相關的部分已經初始化完了,現在開始初始化設備了):static void _initdo_basic_setup(void)/* drivers will send hotplug events */init_workqueues();usermodehelper_init();driver_init(); /建立設備模型子系統(tǒng)#ifdef CONFIG_SYSCTLsysctl_init();#endif/* Networking initialization needs a process context */sock_init();do_i

36、nitcalls(); /系統(tǒng)初始化(包括設備,文件系統(tǒng),內核模塊等)/*driver_init - initialize driver model.*Call the driver model init functions to initialize their*subsystems. Called early from init/main.c.*/void _initdriver_init(void)/* These are the core pieces */devices_init(); int _init devices_init(void) return subsystem_reg

37、ister(&devices_subsys); buses_init();classes_init();firmware_init();/* These are also core pieces, but must come after the * core core pieces. */platform_bus_init();system_bus_init();cpu_dev_init();memory_dev_init();attribute_container_init();extern initcall_t _initcall_start, _initcall_end;static v

38、oid _initdo_initcalls(void)initcall_t *call;int count = preempt_count();for (call = _initcall_start; call _initcall_end; call ) (*call)(); /調用一系列初始化函數 _initcall_start和_initcall_end界定了存放初始化函數指針區(qū)域的起始地址,即從_initcall_start開始到 _initcall_end結束的區(qū)域中存放了指向各個初始化函數的函數指針。由 (*call)()完成各個部分的初始化工作,且便于擴充。具體實現如下:_init

39、call_start = .;*(.initcall1.init)*(.initcall2.init)*(.initcall3.init)*(.initcall4.init)*(.initcall5.init)*(.initcall6.init)*(.initcall7.init)_initcall_end = .;#ifndef MODULE /*如果驅動模塊靜態(tài)編譯進內核*/#define _define_initcall(level,fn) static initcall_t _initcall_#fn _attribute_used_ _attribute_(_section_(.in

40、itcall level .init) = fn#define core_initcall(fn)_define_initcall(1,fn)#define postcore_initcall(fn)_define_initcall(2,fn)#define arch_initcall(fn)_define_initcall(3,fn)#define subsys_initcall(fn)_define_initcall(4,fn)#define fs_initcall(fn)_define_initcall(5,fn)#define device_initcall(fn)_define_in

41、itcall(6,fn)/此處初始化了靜態(tài)編譯的驅動模塊#define late_initcall(fn) _define_initcall(7,fn)#define _initcall(fn) device_initcall(fn)/*靜態(tài)編譯的驅動模塊作為device_initcall在內核啟動就被do_initcalls*/#define module_init(x)_initcall(x);#define module_exit(x)_exitcall(x);#else /* MODULE如果驅動模塊動態(tài)加載入內核 */* Each module must use one module

42、_init(), or one no_module_init */#define module_init(initfn)static inline initcall_t _inittest(void) return initfn; int init_module(void) _attribute_(alias(#initfn);/insmod 是通過系統(tǒng)調用sys_init_module(const char *name_user, struct module *mod_user)將動態(tài)驅動模塊載入到內核空間/* This is only required if you want to be

43、unloadable. */#define module_exit(exitfn)static inline exitcall_t _exittest(void) return exitfn; void cleanup_module(void) _attribute_(alias(#exitfn);基于高通MSM 8x60的I2C驅動終極講解(5)(2012-04-22 17:31)標簽:轉載 分類:linux driver study原文地址:基于高通MSM 8x60的I2C驅動終極講解(5)作者:shangbaogen 現在是初始化講完啦,下面就看平臺設備的注冊啦,也就是咱們的I2C控制器

44、的注冊,注冊函數為platform_add_devices(surf_devices,ARRAY_SIZE(surf_devices);該函數已經在第一講中提到,但是沒有進入分析,下面咱們就進入看下平臺設備是怎么注冊的。后面的代碼只列出主要部分,以免其他代碼干擾我們的視線。int platform_add_devices(struct platform_device *devs, int num)int i, ret = 0; for (i = 0; i dev);/初始化平臺設備的dev結構體,為加入設備驅動模型做準備returnplatform_device_add(pdev);下面繼續(xù)跟

45、蹤函數intplatform_device_add(struct platform_device *pdev)if (!pdev-dev.parent)pdev-dev.parent = &platform_bus;/如果pdev-dev.parent為空就賦值為platform_bus pdev-dev.bus = &platform_bus_type;/設置該設備的總線類型/*根據pdev-id的值設備pdev-dev的name*/if (pdev-id != -1)dev_set_name(&pdev-dev, %s.%d, pdev-name, pdev-id);elsedev_set

46、_name(&pdev-dev, %s, pdev-name);/*下面是對資源的處理,把每個平臺設備的資源插入相應的資源樹中*/for (i = 0; i num_resources; i+) struct resource *p, *r = &pdev-resourcei;if (r-name = NULL)r-name = dev_name(&pdev-dev);p = r-parent;if (!p) if (resource_type(r) = IORESOURCE_MEM)p = &iomem_resource;else if (resource_type(r) = IORESOU

47、RCE_IO)p = &ioport_resource;if (p & insert_resource(p, r) printk(KERN_ERR %s: failed to claim resource %dn, dev_name(&pdev-dev), i);ret = -EBUSY;goto failed; ret =device_add(&pdev-dev);/把該設備注冊到設備驅動模型中下面的函數處理就和一般的設備注冊是一樣的啦!在上述函數中用到的兩個結構體定義如下struct device platform_bus = .init_name= platform,;struct bus_t

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論