Linux设备驱动--LCD平台设备与驱动(smdk6410)

时间:2022-10-27 12:20:54

1 环境与简介

    Host:Ubuntu14.04(64bit)

    Target:smdk6410

    Kernel:linux-3.5.0
    在《Linux设备驱动--LCD平台设备与驱动(smdk2440)》中基于linux-2.6.39.4对LCD平台设备与驱动进行了分析,在此继续基于linux-3.5.0对LCD平台设备与驱动进行分析(本文所有源码均来自Linux内核)。

2 平台设备

2.1 声明

extern struct platform_device s3c_device_fb;
源文件:arch/arm/plat-samsung/include/plat/devs.h
对比分析:与《 Linux设备驱动--LCD平台设备与驱动(smdk2440)》不同的是,这里不是通过 EXPORT_SYMBOL(s3c_device_fb)使其在别的源文件可见,而是在头文件中声明该变量。

2.2 定义

(1)平台设备

    定义全局变量s3c_device_fb

struct platform_device s3c_device_fb = {
.name = "s3c-fb",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_fb_resource),
.resource = s3c_fb_resource,
.dev = {
.dma_mask = &samsung_device_dma_mask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
};
源文件:arch/arm/plat-samsung/devs.c

(2)平台资源

static struct resource s3c_fb_resource[] = {
[0] = DEFINE_RES_MEM(S3C_PA_FB, SZ_16K),
[1] = DEFINE_RES_IRQ(IRQ_LCD_VSYNC),
[2] = DEFINE_RES_IRQ(IRQ_LCD_FIFO),
[3] = DEFINE_RES_IRQ(IRQ_LCD_SYSTEM),
};
源文件:arch/arm/plat-samsung/devs.c

2.3 引用

    定义一个平台设备数组smdk6410_devices,该数组包含了smdk6410开发板的所有平台设备,其中当然包括上述s3c_device_fb,如下第10行所示:

static struct platform_device *smdk6410_devices[] __initdata = {
#ifdef CONFIG_SMDK6410_SD_CH0
&s3c_device_hsmmc0,
#endif
#ifdef CONFIG_SMDK6410_SD_CH1
&s3c_device_hsmmc1,
#endif
&s3c_device_i2c0,
&s3c_device_i2c1,
&s3c_device_fb,
&s3c_device_ohci,
&s3c_device_usb_hsotg,
&samsung_asoc_dma,
&s3c64xx_device_iisv4,
&samsung_device_keypad,

#ifdef CONFIG_REGULATOR
&smdk6410_b_pwr_5v,
#endif
&smdk6410_lcd_powerdev,

&smdk6410_smsc911x,
&s3c_device_adc,
&s3c_device_cfcon,
&s3c_device_rtc,
&s3c_device_ts,
&s3c_device_wdt,
};

源文件:arch/arm/mach-s3c64xx/mach-smdk6410.c

2.4 注册

(1)注册函数

    在smdk6410_machine_init()函数中调用platform_add_devices()函数将上述smdk6410_devices注册到系统,即可完成平台设备的注册,如下最后1行所示:

static void __init smdk6410_machine_init(void)
{
u32 cs1;

s3c_i2c0_set_platdata(NULL);
s3c_i2c1_set_platdata(NULL);
s3c_fb_set_platdata(&smdk6410_lcd_pdata); /* LCD平台数据. */
s3c_hsotg_set_platdata(&smdk6410_hsotg_pdata);

samsung_keypad_set_platdata(&smdk6410_keypad_data);

s3c24xx_ts_set_platdata(NULL);

/* configure nCS1 width to 16 bits */

cs1 = __raw_readl(S3C64XX_SROM_BW) &
~(S3C64XX_SROM_BW__CS_MASK << S3C64XX_SROM_BW__NCS1__SHIFT);
cs1 |= ((1 << S3C64XX_SROM_BW__DATAWIDTH__SHIFT) |
(1 << S3C64XX_SROM_BW__WAITENABLE__SHIFT) |
(1 << S3C64XX_SROM_BW__BYTEENABLE__SHIFT)) <<
S3C64XX_SROM_BW__NCS1__SHIFT;
__raw_writel(cs1, S3C64XX_SROM_BW);

/* set timing for nCS1 suitable for ethernet chip */

__raw_writel((0 << S3C64XX_SROM_BCX__PMC__SHIFT) |
(6 << S3C64XX_SROM_BCX__TACP__SHIFT) |
(4 << S3C64XX_SROM_BCX__TCAH__SHIFT) |
(1 << S3C64XX_SROM_BCX__TCOH__SHIFT) |
(0xe << S3C64XX_SROM_BCX__TACC__SHIFT) |
(4 << S3C64XX_SROM_BCX__TCOS__SHIFT) |
(0 << S3C64XX_SROM_BCX__TACS__SHIFT), S3C64XX_SROM_BC1);

gpio_request(S3C64XX_GPN(5), "LCD power");
gpio_request(S3C64XX_GPF(13), "LCD power");

i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0));
i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));

s3c_ide_set_platdata(&smdk6410_ide_pdata);

samsung_bl_set(&smdk6410_bl_gpio_info, &smdk6410_bl_data);

platform_add_devices(smdk6410_devices, ARRAY_SIZE(smdk6410_devices)); /* 注册平台设备. */
}
源文件:arch/arm/mach-s3c64xx/mach-smdk6410.c

(2)注册时机

    上述smdk6410_machine_init()函数是何时被调用的呢?答案是在内核初始化设备的时候,如下第8行所示:

MACHINE_START(SMDK6410, "SMDK6410")
/* Maintainer: Ben Dooks <ben-linux@fluff.org> */
.atag_offset = 0x100,

.init_irq = s3c6410_init_irq,
.handle_irq = vic_handle_irq,
.map_io = smdk6410_map_io,
.init_machine = smdk6410_machine_init,
.init_late = s3c64xx_init_late,
.timer = &s3c24xx_timer,
.restart = s3c64xx_restart,
MACHINE_END
源文件:arch/arm/mach-s3c64xx/mach-smdk6410.c

3 平台驱动

3.1 定义

    为了和平台设备匹配,平台驱动的name要与平台设备的name一致:

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,
},
};
源文件:drivers/video/s3c-fb.c

3.2 注册

module_platform_driver(s3c_fb_driver); 

源文件:drivers/video/s3c-fb.c

    module_platform_driver()是新版本内核新添加的宏,根据参考资料[1]的提示,上述宏可展开为:

static int __init s3c_fb_driver_init(void)
{
return platform_driver_register(&s3c_fb_driver);
}
module_init(s3c_fb_driver_init);
static void __exit s3c_fb_driver_init(void)
{
return platform_driver_unregister(&s3c_fb_driver);
}
module_exit(s3c_fb_driver_exit);

4 设备与驱动匹配

    同《Linux设备驱动--WDT平台设备与驱动》第4节。

参考资料

[1]module_platform_driver宏解析