其中probe函数的实现
static int nuc970fb_probe(struct platform_device *pdev)
{
struct nuc970fb_info *fbi;
struct nuc970fb_display *display;
struct fb_info *fbinfo;
struct nuc970fb_mach_info *mach_info;
struct resource *res;
int ret;
int irq;
int i;
int size;
struct pinctrl *p;
struct clk *clkmux, *clkuplldiv;
dev_dbg(&pdev->dev, "devinit\n");
mach_info = pdev->dev.platform_data;
if (mach_info == NULL) {
dev_err(&pdev->dev,
"no platform data for lcd, cannot attach\n");
return -EINVAL;
}
if (mach_info->default_display > mach_info->num_displays) {
dev_err(&pdev->dev,
"default display No. is %d but only %d displays \n",
mach_info->default_display, mach_info->num_displays);
return -EINVAL;
}
display = mach_info->displays + mach_info->default_display;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "no irq for device\n");
return -ENOENT;
}
fbinfo = framebuffer_alloc(sizeof(struct nuc970fb_info), &pdev->dev);
if (!fbinfo)
return -ENOMEM;
platform_set_drvdata(pdev, fbinfo);
fbi = fbinfo->par;
fbi->dev = &pdev->dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
size = resource_size(res);
fbi->mem = request_mem_region(res->start, size, pdev->name);
if (fbi->mem == NULL) {
dev_err(&pdev->dev, "failed to alloc memory region\n");
ret = -ENOENT;
goto free_fb;
}
fbi->io = ioremap(res->start, size);
if (fbi->io == NULL) {
dev_err(&pdev->dev, "ioremap() of lcd registers failed\n");
ret = -ENXIO;
goto release_mem_region;
}
fbi->irq_base = fbi->io + REG_LCM_INT_CS;
/* Stop the LCD */
writel(0, fbi->io + REG_LCM_DCCS);
/* fill the fbinfo*/
strcpy(fbinfo->fix.id, driver_name);
fbinfo->fix.type = FB_TYPE_PACKED_PIXELS;
fbinfo->fix.type_aux = 0;
fbinfo->fix.xpanstep = 0;
fbinfo->fix.ypanstep = 0;
fbinfo->fix.ywrapstep = 0;
fbinfo->fix.accel = FB_ACCEL_NONE;
fbinfo->var.nonstd = 0;
fbinfo->var.activate = FB_ACTIVATE_NOW;
fbinfo->var.accel_flags = 0;
fbinfo->var.vmode = FB_VMODE_NONINTERLACED;
fbinfo->fbops = &nuc970fb_ops;
fbinfo->flags = FBINFO_FLAG_DEFAULT;
fbinfo->pseudo_palette = &fbi->pseudo_pal;
ret = request_irq(irq, nuc970fb_irqhandler, 0,
pdev->name, fbinfo);
if (ret) {
dev_err(&pdev->dev, "cannot register irq handler %d -err %d\n",
irq, ret);
ret = -EBUSY;
goto release_regs;
}
clk_prepare(clk_get(NULL, "lcd_hclk"));
clk_enable(clk_get(NULL, "lcd_hclk"));
fbi->clk = clk_get(NULL, "lcd_eclk");
if(display->pixclock > 12000000)
{
// change clock source to upll
clkmux = clk_get(NULL, "lcd_eclk_mux");
if (IS_ERR(clkmux)) {
printk(KERN_ERR "nuc970-lcd:failed to get lcd clock mux control\n");
ret = PTR_ERR(clkmux);
return ret;
}
clkuplldiv = clk_get(NULL, "lcd_uplldiv");
if (IS_ERR(clkuplldiv)) {
printk(KERN_ERR "nuc970-lcd:failed to get lcd clock divider control\n");
ret = PTR_ERR(clkuplldiv);
return ret;
}
// select lcd clock from upll
clk_set_parent(clkmux, clkuplldiv);
}
clk_set_rate(fbi->clk, display->pixclock);
clk_prepare(fbi->clk);
clk_enable(fbi->clk);
fbi->clk_rate = clk_get_rate(fbi->clk);
dev_dbg(&pdev->dev, "got and enabled clock\n");
/* calutate the video buffer size */
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;
}
/* Initialize Video Memory */
ret = nuc970fb_map_video_memory(fbinfo);
if (ret) {
printk(KERN_ERR "Failed to allocate video RAM: %x\n", ret);
goto release_clock;
}
dev_dbg(&pdev->dev, "got video memory\n");
fbinfo->var.xres = display->xres;
fbinfo->var.yres = display->yres;
fbinfo->var.bits_per_pixel = display->bpp;
nuc970fb_init_registers(fbinfo);
nuc970fb_check_var(&fbinfo->var, fbinfo);
ret = nuc970fb_cpufreq_register(fbi);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register cpufreq\n");
goto free_video_memory;
}
ret = register_framebuffer(fbinfo);
if (ret) {
printk(KERN_ERR "failed to register framebuffer device: %d\n",
ret);
goto free_cpufreq;
}
#if defined(CONFIG_FB_NUC970_16BIT_PIN)
p = devm_pinctrl_get_select(&pdev->dev, "lcd-16bit");
#elif defined(CONFIG_FB_NUC970_18BIT_PIN)
p = devm_pinctrl_get_select(&pdev->dev, "lcd-18bit");
#else
p = devm_pinctrl_get_select(&pdev->dev, "lcd-24bit");
#endif
if(IS_ERR(p)) {
dev_err(&pdev->dev, "unable to reserve pin\n");
ret = PTR_ERR(p);
}
printk(KERN_INFO "fb%d: %s frame buffer device\n",
fbinfo->node, fbinfo->fix.id);
#ifdef CONFIG_ILI9431_MPU80_240x320
init_ili9341(fbinfo);
#endif
return 0;
free_cpufreq:
nuc970fb_cpufreq_deregister(fbi);
free_video_memory:
nuc970fb_unmap_video_memory(fbinfo);
release_clock:
clk_disable(fbi->clk);
clk_put(fbi->clk);
free_irq(irq, fbi);
release_regs:
iounmap(fbi->io);
release_mem_region:
release_mem_region(res->start, size);
free_fb:
framebuffer_release(fbinfo);
return ret;
}
|