Chinaunix首页 | 论坛 | 博客
  • 博客访问: 500203
  • 博文数量: 104
  • 博客积分: 3045
  • 博客等级: 少校
  • 技术积分: 1230
  • 用 户 组: 普通用户
  • 注册时间: 2008-02-29 10:18
文章分类

全部博文(104)

文章存档

2011年(72)

2010年(1)

2009年(1)

2008年(30)

分类:

2008-09-07 16:10:55

液晶驱动

s3c2410fb.cstatic int __init s3c2410fb_probe(struct platform_device *pdev)

platform_devicemach-smdk2410

static struct platform_device *smdk2410_devices[] __initdata = {

&s3c_device_usb,

&s3c_device_lcd,

&s3c_device_wdt,

&s3c_device_i2c,

&s3c_device_iis,

};

smdk2410_devices &s3c_device_lcd, 初始化lcd 其中lcd 的初始化是在以下的函数中

static void __init smdk2410_init(void)

{

s3c24xx_fb_set_platdata(&qt2410_fb_info);

platform_add_devices(smdk2410_devices, ARRAY_SIZE(smdk2410_devices));

smdk_machine_init();

}


s3c24xx_fb_set_platdata(&qt2410_fb_info);

void __init s3c24xx_fb_set_platdata(struct s3c2410fb_mach_info *pd)

{

struct s3c2410fb_mach_info *npd;


npd = kmalloc(sizeof(*npd), GFP_KERNEL);

if (npd) {

memcpy(npd, pd, sizeof(*npd));

s3c_device_lcd.dev.platform_data = npd;

} else {

printk(KERN_ERR "no memory for LCD platform data\n");

}

}

其中s3c_device_lcd.dev.platform_data = npd; 语句对lcd 的结构即

static struct s3c2410fb_mach_info qt2410_fb_info __initdata = {

.displays = qt2410_lcd_cfg,

.num_displays = ARRAY_SIZE(qt2410_lcd_cfg),

.default_display = 0,

.gpcup = 0xffffffff,

.gpcup_mask = 0xffffffff,

.gpccon = 0xaaaaaaaa,

.gpccon_mask = 0xffffffff,


.gpdup = 0xffffffff,

.gpdup_mask = 0xffffffff,

.gpdcon = 0xaaaaaaaa,

.gpdcon_mask = 0xffffffff,



.lpcsel = ((0xCE6) & ~7) | 1<<4,

//.lpcsel = 0x0,


}; display 是在 如下定义的 看上面

static struct s3c2410fb_display qt2410_lcd_cfg[] __initdata = {

{

.type = S3C2410_LCDCON1_TFT,

.lcdcon5 = S3C2410_LCDCON5_FRM565 |

S3C2410_LCDCON5_HWSWP|

S3C2410_LCDCON5_PWREN,


.width = 240,

.height = 320,


.pixclock = 100000, /* HCLK/4 */

.xres = 240,

.yres = 320,

.bpp = 16,

.left_margin = 13,

.right_margin = 8,

.hsync_len = 4,

.upper_margin = 2,

},


}; 整个过程是对smdk2410_devices的初始化

回到 s3c2410fb_probe函数 他是lcd probe 函数 即搜索函数

mach_info = pdev->dev.platform_data;

if (mach_info == NULL) {

dev_err(&pdev->dev,

"no platform data for lcd, cannot attach\n");

return -EINVAL;

}

一 检查系统般的类型 是否设置

display = mach_info->displays + mach_info->default_display;

display赋值

irq = platform_get_irq(pdev, 0);

if (irq < 0) {

dev_err(&pdev->dev, "no irq for device\n");

return -ENOENT;

}

获得irq fbinfo 结构分配空间

fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev);

其中fbinfo 的定义

truct fb_info {

int node;

int flags;

struct fb_var_screeninfo var; /* Current var */

struct fb_fix_screeninfo fix; /* Current fix */

struct fb_monspecs monspecs; /* Current Monitor specs */

struct work_struct queue; /* Framebuffer event queue */

struct fb_pixmap pixmap; /* Image hardware mapper */

struct fb_pixmap sprite; /* Cursor hardware mapper */

struct fb_cmap cmap; /* Current cmap */

struct list_head modelist; /* mode list */

struct fb_videomode *mode; /* current mode */


#ifdef CONFIG_FB_BACKLIGHT

/* assigned backlight device */

/* set before framebuffer registration,

remove after unregister */

struct backlight_device *bl_dev;


/* Backlight level curve */

struct mutex bl_curve_mutex;

u8 bl_curve[FB_BACKLIGHT_LEVELS];

truct fb_info {

int node;

int flags;

struct fb_var_screeninfo var; /* Current var */

struct fb_fix_screeninfo fix; /* Current fix */

struct fb_monspecs monspecs; /* Current Monitor specs */

struct work_struct queue; /* Framebuffer event queue */

struct fb_pixmap pixmap; /* Image hardware mapper */

struct fb_pixmap sprite; /* Cursor hardware mapper */

struct fb_cmap cmap; /* Current cmap */

struct list_head modelist; /* mode list */

struct fb_videomode *mode; /* current mode */


#ifdef CONFIG_FB_BACKLIGHT

/* assigned backlight device */

/* set before framebuffer registration,

remove after unregister */

struct backlight_device *bl_dev;


/* Backlight level curve */

struct mutex bl_curve_mutex;

u8 bl_curve[FB_BACKLIGHT_LEVELS];

/* From here on everything is device dependent */

void *par;

};

二 为fb_info 赋值

platform_set_drvdata(pdev, fbinfo);

info = fbinfo->par;

info->dev = &pdev->dev;


res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

size = (res->end - res->start) + 1;

info->mem = request_mem_region(res->start, size, pdev->name);

if (info->mem == NULL) {

dev_err(&pdev->dev, "failed to get memory region\n");

ret = -ENOENT;

goto dealloc_fb;

}

三 分配寄存器地址

/* Stop the video */

lcdcon1 = readl(info->io + S3C2410_LCDCON1);

writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, info->io + S3C2410_LCDCON1);



四 停止显示

fbinfo->fbops = &s3c2410fb_ops;

在相同文件下的定义如下

static struct fb_ops s3c2410fb_ops = {

.owner = THIS_MODULE,

.fb_check_var = s3c2410fb_check_var,

.fb_set_par = s3c2410fb_set_par,

.fb_blank = s3c2410fb_blank,

.fb_setcolreg = s3c2410fb_setcolreg,

.fb_fillrect = cfb_fillrect,

.fb_copyarea = cfb_copyarea,

.fb_imageblit = cfb_imageblit,

};

s3c2410fb_setcolreg()设置颜色寄存器调用

schedule_palette_update(fbi, regno, val);

find maximum required memory size for display

for (i = 0; i < mach_info->num_displays; i++) {

unsigned long smem_len = mach_info->displays[i].xres;


smem_len *= mach_info->displays[i].yres;

smem_len *= mach_info->displays[i].bpp;

smem_len >>= 3;

if (fbinfo->fix.smem_len < smem_len)

fbinfo->fix.smem_len = smem_len;

}

六 为 DMA分配内才能

ret = s3c2410fb_map_video_memory(fbinfo);

if (ret) {

printk(KERN_ERR "Failed to allocate video RAM: %d\n", ret);

ret = -ENOMEM;

goto release_clock;

}

七 初始化寄存器

s3c2410fb_init_registers(fbinfo);

定义如下

static int s3c2410fb_init_registers(struct fb_info *info)

{

struct s3c2410fb_info *fbi = info->par;

struct s3c2410fb_mach_info *mach_info = fbi->dev->platform_data;

unsigned long flags;

void __iomem *regs = fbi->io;

/* Initialise LCD with values from haret */

local_irq_save(flags);


/* modify the gpio(s) with interrupts set (bjd) */


modify_gpio(S3C2410_GPCUP, mach_info->gpcup, mach_info->gpcup_mask);

modify_gpio(S3C2410_GPCCON, mach_info->gpccon, mach_info->gpccon_mask);

modify_gpio(S3C2410_GPDUP, mach_info->gpdup, mach_info->gpdup_mask);

modify_gpio(S3C2410_GPDCON, mach_info->gpdcon, mach_info->gpdcon_mask);


local_irq_restore(flags);


dprintk("LPCSEL = 0x%08lx\n", mach_info->lpcsel);

}也就是在mach-smdk2410GPCUP GPCCON的设置

八 检查fbinfo 中内存中fbinfo->var 的设置

s3c2410fb_check_var(&fbinfo->var, fbinfo);

九 注册内存

ret = register_framebuffer(fbinfo);

十 注册文件

device_create_file(&pdev->dev, &dev_attr_debug);

十一 返回

return 0;

总结


static struct platform_driver s3c2410fb_driver = {

.probe = s3c2410fb_probe,

.remove = s3c2410fb_remove,

.suspend = s3c2410fb_suspend,

.resume = s3c2410fb_resume,

.driver = { schedule_palette_update(fbi, regno, val);

.name = "s3c2410-lcd",

.owner = THIS_MODULE,

},

};

s3c2410fb_probe,

s3c2410fb_remove,

3c2410fb_suspend,

s3c2410fb_resume,

这些函数的都是 io_ctl的必备函数

lcd 的初始化 就是在 内核初始化的时候

int __init s3c2410fb_init(void)

{

return platform_driver_register(&s3c2410fb_driver);

}

其中最重要的就是fb_info frame buffer 的设置 这是以后 从上层对该层的调用

整个驱动的注册的过程就是设置各个寄存器的设置设置调色板

注册irq 然后 注册文件操作函数

注册函数初始化

int platform_driver_register(struct platform_driver *drv)

{

drv->driver.bus = &platform_bus_type;

if (drv->probe)

drv->driver.probe = platform_drv_probe;

if (drv->remove)

drv->driver.remove = platform_drv_remove;

if (drv->shutdown)

drv->driver.shutdown = platform_drv_shutdown;

if (drv->suspend)

drv->driver.suspend = platform_drv_suspend;

if (drv->resume)

drv->driver.resume = platform_drv_resume;

return driver_register(&drv->driver);

}

其中 platform_driver 的配置如下

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 (*suspend_late)(struct platform_device *, pm_message_t state);

int (*resume_early)(struct platform_device *);

int (*resume)(struct platform_device *);

struct device_driver driver;

};

device_driver

struct device_driver {

const char * name;

struct bus_type * bus;


struct kobject kobj;

struct klist klist_devices;

struct klist_node knode_bus;


struct module * owner;

const char * mod_name; /* used for built-in modules */

struct module_kobject * mkobj;


int (*probe) (struct device * dev);

int (*remove) (struct device * dev);

void (*shutdown) (struct device * dev);

int (*suspend) (struct device * dev, pm_message_t state);

int (*resume) (struct device * dev);

};

二 注册总线

int driver_register(struct device_driver * drv)

{

if ((drv->bus->probe && drv->probe) ||

(drv->bus->remove && drv->remove) ||

(drv->bus->shutdown && drv->shutdown)) {

printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name);

}


klist_init(&drv->klist_devices, NULL, NULL);

return bus_add_driver(drv);

}

klist_init()函数 是用来初始化 如下的函数

四 最重要的函数 就是bus_add_driver 函数

int bus_add_driver(struct device_driver *drv)

{

error = kobject_set_name(&drv->kobj, "%s", drv->name);

error = kobject_register(&drv->kobj);


klist_add_tail(&drv->knode_bus, &bus->klist_drivers);


module_add_driver(drv->owner, drv);


error = driver_create_file(drv, &driver_attr_uevent);


}











阅读(2212) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~