FL2440 LCD内置控制器,320*240 TFT型LCD。
自我理解总结的两种添加驱动模式:
非platform方式添加驱动:
加载驱动:
1,硬件初始化,申请内存,并作地址映射
2,分配设备号,分配结构体
3,注册设备
卸载驱动:
1,释放内存
2,释放结构体,返还设备号
3,注销设备
platform总线方式添加驱动(主流方式):
1.编写设备链
struct platform_device
{
const chat *name;
u32 id;
struct device dev;
u32 num_resources;
struct resources * resources;
};
2,编写驱动链
static struct platform_driver
{
int (*probe)( struct platform_device*),//探测函数
int (*remove)( structplatform_device*),//删除函数
……
struct device_driver driver;
};
3,在设备链注册设备和在驱动链注册驱动
int __init xxx_init()
{
.....
platform_device_register();
platform_driver_register();
.....
}
4,反向在驱动链注销驱动,在设备链注销设备
void __exit xxx_exit()
{
.....
platform_driver_unregister();
platform_device_unregister();
.....
}
开始添加LCD驱动:内核版本linux-3.8.0
1,在arch/arm/mach-s3c24xx/mach-smdk2440.c中修改相关信息平台数据
/* LCD driver info */
static struct s3c2410fb_display smdk2440_lcd_cfg __initdata = {
.lcdcon5 = S3C2410_LCDCON5_FRM565|
S3C2410_LCDCON5_INVVLINE |
S3C2410_LCDCON5_INVVFRAME |
S3C2410_LCDCON5_PWREN |
S3C2410_LCDCON5_HWSWP,
.type = S3C2410_LCDCON1_TFT,
.width = 320,
.height = 240,
.pixclock = 111111, /* HCLK 60 MHz, divisor 10 */
.xres = 480,
.yres = 272,
.bpp = 16,
.left_margin = 38,
.right_margin = 20,
.hsync_len = 30,
.upper_margin = 15,
.lower_margin = 12,
.vsync_len = 3,
};
static struct s3c2410fb_mach_info smdk2440_fb_info __initdata = {
.displays = &smdk2440_lcd_cfg,
.num_displays = 1,
.default_display = 0,
#if 0
/* currently setup by downloader */
.gpccon = 0xaa940659,
.gpccon_mask = 0xffffffff,
.gpcup = 0x0000ffff,
.gpcup_mask = 0xffffffff,
.gpdcon = 0xaa84aaa0,
.gpdcon_mask = 0xffffffff,
.gpdup = 0x0000faff,
.gpdup_mask = 0xffffffff,
#endif
.lpcsel = ((0xCE6) & ~7) | 1<<1,
};
2,由于在arch/arm/plat-samsung/devs.c已经定义了LCD的设备以及平台添加函数,如下
/* LCD Controller */
#ifdef CONFIG_PLAT_S3C24XX
static struct resource s3c_lcd_resource[]= {
[0] = DEFINE_RES_MEM(S3C24XX_PA_LCD, S3C24XX_SZ_LCD),
[1] = DEFINE_RES_IRQ(IRQ_LCD),
};
struct platform_device s3c_device_lcd= {
.name = "s3c2410-lcd",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_lcd_resource),
.resource = s3c_lcd_resource,
.dev = {
.dma_mask = &samsung_device_dma_mask,
.coherent_dma_mask = DMA_BIT_MASK(32),
}
};
//平台添加函数
void __init s3c24xx_fb_set_platdata(structs3c2410fb_mach_info *pd)
{
struct s3c2410fb_mach_info *npd;
npd = s3c_set_platdata(pd, sizeof(*npd), &s3c_device_lcd);
if (npd) {
npd->displays =kmemdup(pd->displays,
sizeof(struct s3c2410fb_display) * npd->num_displays,
GFP_KERNEL);
if (!npd->displays)
printk(KERN_ERR "no memory forLCD display datan");
} else {
printk(KERN_ERR "no memory for LCDplatform datan");
}
}
#endif /*CONFIG_PLAT_S3C24XX */
所以在arch/arm/mach-s3c24xx/mach-smdk2440.c只需注册设备:
static struct platform_device *smdk2440_devices[] __initdata = {
&s3c_device_ohci,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c0,
&s3c_device_iis,
&s3c_device_dm9000,
&s3c_device_adc,
&s3c_device_ts,
&s3c_device_rtc,
&globalfifo_device
};
通过调用smdk2440_machine_init添加到设备链,
static void __init smdk2440_machine_init(void)
{
//调用该函数将上面定义的LCD硬件信息保存到平台数据中
s3c24xx_fb_set_platdata(&smdk2440_fb_info);
s3c_i2c0_set_platdata(NULL);
platform_add_devices(smdk2440_devices,ARRAY_SIZE(smdk2440_devices));
smdk_machine_init();
}
跟踪platform_add_devices函数,其实际调用了platform_device_register和platform_device_unregister函数,如下:
在drivers/base/platform.c下定义:
int platform_add_devices(struct platform_device **devs, int num)
{
int i, ret = 0;
for (i = 0; i < num; i++) {
ret = platform_device_register(devs[i]);
if (ret) {
while (--i >= 0)
platform_device_unregister(devs[i]);
break;
}
}
return ret;
}
EXPORT_SYMBOL_GPL(platform_add_devices);