LCD驱动端与设备端名称匹配过程分析(Tiny4412)
Posted DS小龙哥
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LCD驱动端与设备端名称匹配过程分析(Tiny4412)相关的知识,希望对你有一定的参考价值。
LCD驱动端与设备端名称匹配过程
在tiny4412提供的内核下,LCD屏的平台设备名字和平台驱动名字不匹配也能驱动屏点亮,
这是怎么回事的呢?下面我们来分析这是如何实现的。
- 硬件平台
Cpu:exynos4412
板子:tiny4412
Linux内核:linux-3.5
21.6.1 lcd平台驱动层相关代码构架
Lcd平台驱动层在S3c-fb.c (linux-3.5\\drivers\\video)中实现。
21.6.2 s3c_fb_driver平台驱动结构变量
平台驱动结构变量如下:
static struct platform_driver s3c_fb_driver = .probe= s3c_fb_probe, .remove= __devexit_p(s3c_fb_remove), .id_table= s3c_fb_driver_ids, .driver= .name= "s3c-fb", .owner= THIS_MODULE, .pm= &s3cfb_pm_ops, , ; |
驱动层的平台驱动结构实现了id_table,按常理就会根据这个id_table去匹配。
平台驱动结构原型如下:
struct platform_driver int (*probe)(struct platform_device *); int (*remove)(struct platform_device *); void (*shutdown)(struct platform_device *); int (*suspend)(struct platform_device *, pm_message_t state); int (*resume)(struct platform_device *); struct device_driver driver; const struct platform_device_id *id_table; ; |
21.6.3 platform_device_id结构变量
先给出platform_device_id结构原型如下:
struct platform_device_id char name[PLATFORM_NAME_SIZE]; kernel_ulong_t driver_data __attribute__((aligned(sizeof(kernel_ulong_t)))); ; |
name数组:用于存放设备的名字,也就是用来和平台设备结构匹配的依据。
driver_data :类型实际上是 unsigned long;
由驱动编写者决定这个整数的用途;
一般是传入一个结构体变量的地址。
内核中定义kernel_ulong_t如下:
typedef unsigned long kernel_ulong_t; |
那么我们就查看s3c_fb_driver_ids,SI跳转进去发现s3c_fb_driver_ids是一个结构数组。定义了许多这个内核支持的cpu的lcd控制器驱动。
代码如下:
static struct platform_device_id s3c_fb_driver_ids[] = .name= "s3c-fb", .driver_data= (unsigned long)&s3c_fb_data_64xx,//arm11 , .name= "s5pc100-fb", .driver_data= (unsigned long)&s3c_fb_data_s5pc100,//A8 , .name= "s5pv210-fb", .driver_data= (unsigned long)&s3c_fb_data_s5pv210,//A8 , .name= "exynos4-fb",//A9,这个就是tiny4412配套的lcd屏 .driver_data= (unsigned long)&s3c_fb_data_exynos4, , .name= "exynos5-fb", .driver_data= (unsigned long)&s3c_fb_data_exynos5, , .name= "s3c2443-fb", .driver_data= (unsigned long)&s3c_fb_data_s3c2443, , .name= "s5p64x0-fb", .driver_data= (unsigned long)&s3c_fb_data_s5p64x0, , , ; |
按常理来说,lcd屏的设备层会来跟上面的id_table数组进行匹配,匹配成就会获取相应的.driver_data结构数据。
在tiny4412板子上,lcd平台设备端的name应该是"exynos4-fb"才会成功匹配。
21.6.4 lcd平台设备层相关代码构架
Tiny4412 开发板所带内核源码中已经集成了 LCD 驱动的平台设备层代码;
21.6.5 内核启动阶段,板级相关设备驱动初始化结构
内核在启动阶段把平台设备注册进内核,这段代码实现在:
Mach-tiny4412.c (linux-3.5\\arch\\arm\\mach-exynos)文件中。
在文件最后有如下代码段:
MACHINE_START(TINY4412, "TINY4412") /* Maintainer: FriendlyARM (www.arm9.net) */ /* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */ /* Maintainer: Changhwan Youn <chaos.youn@samsung.com> */ .atag_offset= 0x100, .init_irq= exynos4_init_irq, .map_io= smdk4x12_map_io, .handle_irq= gic_handle_irq, .init_machine= smdk4x12_machine_init, .init_late= exynos_init_late, .timer= &exynos4_timer, .restart= exynos4_restart, .reserve= &smdk4x12_reserve, MACHINE_END |
代码中给 .init_machine 指针赋值 smdk4x12_machine_init;
.init_machine 指针指向的函数在系统启动前期就会被运行,板级相关设备驱动初始化、注册一般都是写在这个函数中,平台设备注册一般就是在此函数中编写。
那么接下来找到 smdk4x12_machine_init 函数实现,然后再寻找和平台设备注册相关的代码进行分析。
21.6.6 smdk4x12_machine_init函数实现
smdk4x12_machine_init函数实现代码如下:
static void __initsmdk4x12_machine_init(void) #ifdef CONFIG_S3C64XX_DEV_SPI0 spi_register_board_info(spi0_board_info, ARRAY_SIZE(spi0_board_info)); #endif #ifdef CONFIG_S3C64XX_DEV_SPI1 spi_register_board_info(spi1_board_info, ARRAY_SIZE(spi1_board_info)); #endif #ifdef CONFIG_S3C64XX_DEV_SPI2 spi_register_board_info(spi2_board_info, ARRAY_SIZE(spi2_board_info)); #endif s3c_i2c0_set_platdata(NULL); if (samsung_pack() == EXYNOS4412_PACK_SCP) #ifdef CONFIG_REGULATOR_S5M8767 i2c_register_board_info(0, smdk4x12_i2c_devs0_s5m8767, ARRAY_SIZE(smdk4x12_i2c_devs0_s5m8767)); #endif else #ifdef CONFIG_REGULATOR_MAX77686 max77686_populate_pdata(); i2c_register_board_info(0, smdk4x12_i2c_devs0_max77686, ARRAY_SIZE(smdk4x12_i2c_devs0_max77686)); #endif s3c_i2c1_set_platdata(NULL); i2c_register_board_info(1, smdk4x12_i2c_devs1, ARRAY_SIZE(smdk4x12_i2c_devs1)); s3c_i2c2_set_platdata(NULL); i2c_register_board_info(2, smdk4x12_i2c_devs2, ARRAY_SIZE(smdk4x12_i2c_devs2)); s3c_i2c3_set_platdata(NULL); i2c_register_board_info(3, smdk4x12_i2c_devs3, ARRAY_SIZE(smdk4x12_i2c_devs3)); s3c_i2c4_set_platdata(NULL); smdk4x12_rtc_wake_init(); smdk4x12_pmu_wdt_init(); smdk4x12_touch_init(); s3c_i2c7_set_platdata(NULL); i2c_register_board_info(7, smdk4x12_i2c_devs7, ARRAY_SIZE(smdk4x12_i2c_devs7)); s3c_hsotg_set_platdata(&smdk4x12_hsotg_pdata); #ifdef CONFIG_USB_EXYNOS_SWITCH smdk4x12_usbswitch_init(); #endif samsung_bl_set(&smdk4x12_bl_gpio_info, &smdk4x12_bl_data); s5p_fimd0_set_platdata(&smdk4x12_lcd0_pdata);//设置私有数据 #ifdef CONFIG_LCD_LMS501KF03 spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info)); #endif samsung_keypad_set_platdata(&smdk4x12_keypad_data); #ifdef CONFIG_EXYNOS4_DEV_DWMCI exynos_dwmci_set_platdata(&exynos_dwmci_pdata); #endif s3c_sdhci2_set_platdata(&smdk4x12_hsmmc2_pdata); s3c_sdhci3_set_platdata(&smdk4x12_hsmmc3_pdata); #ifdef CONFIG_ION_EXYNOS exynos_ion_set_platdata(); #endif s5p_tv_setup(); s5p_i2c_hdmiphy_set_platdata(NULL); s5p_hdmi_set_platdata(smdk4x12_i2c_hdmiphy, NULL, 0); #ifdef CONFIG_VIDEO_EXYNOS_FIMG2D s5p_fimg2d_set_platdata(&fimg2d_data); #endif #if defined(CONFIG_VIDEO_M5MOLS) || defined(CONFIG_VIDEO_S5K6A3) smdk4x12_camera_init(); #endif #ifdef CONFIG_VIDEO_EXYNOS_FIMC_LITE smdk4x12_set_camera_flite_platdata(); s3c_set_platdata(&exynos_flite0_default_data, sizeof(exynos_flite0_default_data), &exynos_device_flite0); s3c_set_platdata(&exynos_flite1_default_data, sizeof(exynos_flite1_default_data), &exynos_device_flite1); #endif smdk4x12_ehci_init(); #ifdef CONFIG_S3C64XX_DEV_SPI0 s3c64xx_spi0_set_platdata(NULL, 0, 1); #endif #ifdef CONFIG_S3C64XX_DEV_SPI1 s3c64xx_spi1_set_platdata(NULL, 0, 1); #endif #ifdef CONFIG_S3C64XX_DEV_SPI2 s3c64xx_spi2_set_platdata(NULL, 0, 1); #endif smdk4x12_ohci_init(); /* 注册多个平台设备 */ platform_add_devices(smdk4x12_devices, ARRAY_SIZE(smdk4x12_devices)); #ifdef CONFIG_VIDEO_EXYNOS_FIMC_IS exynos4_fimc_is_set_platdata(NULL); #endif if (soc_is_exynos4412()) if ((samsung_rev() >= EXYNOS4412_REV_2_0)) initialize_prime_clocks(); else initialize_non_prime_clocks(); #ifdef CONFIG_BUSFREQ_OPP dev_add(&busfreq, &exynos4_busfreq.dev); ppmu_init(&exynos_ppmu[PPMU_DMC0], &exynos4_busfreq.dev); ppmu_init(&exynos_ppmu[PPMU_DMC1], &exynos4_busfreq.dev); ppmu_init(&exynos_ppmu[PPMU_CPU], &exynos4_busfreq.dev); #endif set_tmu_platdata(); |
在上面函数中会调用平台设备注册函数,如下:
/* 注册多个平台设备 */ platform_add_devices(smdk4x12_devices, ARRAY_SIZE(smdk4x12_devices)); |
其中参数smdk4x12_devices就是注册的平台设备结构数组指针;
21.6.7 smdk4x12_devices平台设备结构数组
SI跳转查看smdk4x12_devices结构,代码段如下:
/* 多平台设备结构变量指针 */ static struct platform_device *smdk4x12_devices[] __initdata = #ifdef CONFIG_EXYNOS4_DEV_DWMCI &exynos_device_dwmci, #endif &s3c_device_hsmmc2, &s3c_device_hsmmc3, &wm8994_fixed_voltage0, &wm8994_fixed_voltage1, &wm8994_fixed_voltage2, &s3c_device_i2c0, &s3c_device_i2c1, &s3c_device_i2c2, &s3c_device_i2c3, #ifdef CONFIG_VIDEO_M5MOLS &s3c_device_i2c4, #endif &s3c_device_i2c7, &s3c_device_adc, &s3c_device_rtc, &s3c_device_wdt, #ifdef CONFIG_TINY4412_BUZZER &s3c_device_timer[0], #endif #ifdef CONFIG_VIDEO_EXYNOS_FIMC_LITE & 以上是关于LCD驱动端与设备端名称匹配过程分析(Tiny4412)的主要内容,如果未能解决你的问题,请参考以下文章 |