📄 atmel_lcdfb.c
字号:
}static int __init atmel_lcdfb_init_fbinfo(struct atmel_lcdfb_info *sinfo){ struct fb_info *info = sinfo->info; int ret = 0; info->var.activate |= FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW; dev_info(info->device, "%luKiB frame buffer at %08lx (mapped at %p)\n", (unsigned long)info->fix.smem_len / 1024, (unsigned long)info->fix.smem_start, info->screen_base); /* Allocate colormap */ ret = fb_alloc_cmap(&info->cmap, 256, 0); if (ret < 0) dev_err(info->device, "Alloc color map failed\n"); return ret;}static void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo){ if (sinfo->bus_clk) clk_enable(sinfo->bus_clk); clk_enable(sinfo->lcdc_clk);}static void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo){ if (sinfo->bus_clk) clk_disable(sinfo->bus_clk); clk_disable(sinfo->lcdc_clk);}static int __init atmel_lcdfb_probe(struct platform_device *pdev){ struct device *dev = &pdev->dev; struct fb_info *info; struct atmel_lcdfb_info *sinfo; struct atmel_lcdfb_info *pdata_sinfo; struct fb_videomode fbmode; struct resource *regs = NULL; struct resource *map = NULL; int ret; dev_dbg(dev, "%s BEGIN\n", __func__); ret = -ENOMEM; info = framebuffer_alloc(sizeof(struct atmel_lcdfb_info), dev); if (!info) { dev_err(dev, "cannot allocate memory\n"); goto out; } sinfo = info->par; if (dev->platform_data) { pdata_sinfo = (struct atmel_lcdfb_info *)dev->platform_data; sinfo->default_bpp = pdata_sinfo->default_bpp; sinfo->default_dmacon = pdata_sinfo->default_dmacon; sinfo->default_lcdcon2 = pdata_sinfo->default_lcdcon2; sinfo->default_monspecs = pdata_sinfo->default_monspecs; sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control; sinfo->guard_time = pdata_sinfo->guard_time; sinfo->smem_len = pdata_sinfo->smem_len; sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight; sinfo->lcd_wiring_mode = pdata_sinfo->lcd_wiring_mode; } else { dev_err(dev, "cannot get default configuration\n"); goto free_info; } sinfo->info = info; sinfo->pdev = pdev; strcpy(info->fix.id, sinfo->pdev->name); info->flags = ATMEL_LCDFB_FBINFO_DEFAULT; info->pseudo_palette = sinfo->pseudo_palette; info->fbops = &atmel_lcdfb_ops; memcpy(&info->monspecs, sinfo->default_monspecs, sizeof(info->monspecs)); info->fix = atmel_lcdfb_fix; /* Enable LCDC Clocks */ if (cpu_is_at91sam9261() || cpu_is_at32ap7000()) { sinfo->bus_clk = clk_get(dev, "hck1"); if (IS_ERR(sinfo->bus_clk)) { ret = PTR_ERR(sinfo->bus_clk); goto free_info; } } sinfo->lcdc_clk = clk_get(dev, "lcdc_clk"); if (IS_ERR(sinfo->lcdc_clk)) { ret = PTR_ERR(sinfo->lcdc_clk); goto put_bus_clk; } atmel_lcdfb_start_clock(sinfo); ret = fb_find_mode(&info->var, info, NULL, info->monspecs.modedb, info->monspecs.modedb_len, info->monspecs.modedb, sinfo->default_bpp); if (!ret) { dev_err(dev, "no suitable video mode found\n"); goto stop_clk; } regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!regs) { dev_err(dev, "resources unusable\n"); ret = -ENXIO; goto stop_clk; } sinfo->irq_base = platform_get_irq(pdev, 0); if (sinfo->irq_base < 0) { dev_err(dev, "unable to get irq\n"); ret = sinfo->irq_base; goto stop_clk; } /* Initialize video memory */ map = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (map) { /* use a pre-allocated memory buffer */ info->fix.smem_start = map->start; info->fix.smem_len = map->end - map->start + 1; if (!request_mem_region(info->fix.smem_start, info->fix.smem_len, pdev->name)) { ret = -EBUSY; goto stop_clk; } info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); if (!info->screen_base) goto release_intmem; /* * Don't clear the framebuffer -- someone may have set * up a splash image. */ } else { /* alocate memory buffer */ ret = atmel_lcdfb_alloc_video_memory(sinfo); if (ret < 0) { dev_err(dev, "cannot allocate framebuffer: %d\n", ret); goto stop_clk; } } /* LCDC registers */ info->fix.mmio_start = regs->start; info->fix.mmio_len = regs->end - regs->start + 1; if (!request_mem_region(info->fix.mmio_start, info->fix.mmio_len, pdev->name)) { ret = -EBUSY; goto free_fb; } sinfo->mmio = ioremap(info->fix.mmio_start, info->fix.mmio_len); if (!sinfo->mmio) { dev_err(dev, "cannot map LCDC registers\n"); goto release_mem; } /* Initialize PWM for contrast or backlight ("off") */ init_contrast(sinfo); /* interrupt */ ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info); if (ret) { dev_err(dev, "request_irq failed: %d\n", ret); goto unmap_mmio; } /* Some operations on the LCDC might sleep and * require a preemptible task context */ INIT_WORK(&sinfo->task, atmel_lcdfb_task); ret = atmel_lcdfb_init_fbinfo(sinfo); if (ret < 0) { dev_err(dev, "init fbinfo failed: %d\n", ret); goto unregister_irqs; } /* * This makes sure that our colour bitfield * descriptors are correctly initialised. */ atmel_lcdfb_check_var(&info->var, info); ret = fb_set_var(info, &info->var); if (ret) { dev_warn(dev, "unable to set display parameters\n"); goto free_cmap; } dev_set_drvdata(dev, info); /* * Tell the world that we're ready to go */ ret = register_framebuffer(info); if (ret < 0) { dev_err(dev, "failed to register framebuffer device: %d\n", ret); goto reset_drvdata; } /* add selected videomode to modelist */ fb_var_to_videomode(&fbmode, &info->var); fb_add_videomode(&fbmode, &info->modelist); /* Power up the LCDC screen */ if (sinfo->atmel_lcdfb_power_control) sinfo->atmel_lcdfb_power_control(1); dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %lu\n", info->node, info->fix.mmio_start, sinfo->mmio, sinfo->irq_base); return 0;reset_drvdata: dev_set_drvdata(dev, NULL);free_cmap: fb_dealloc_cmap(&info->cmap);unregister_irqs: cancel_work_sync(&sinfo->task); free_irq(sinfo->irq_base, info);unmap_mmio: exit_backlight(sinfo); iounmap(sinfo->mmio);release_mem: release_mem_region(info->fix.mmio_start, info->fix.mmio_len);free_fb: if (map) iounmap(info->screen_base); else atmel_lcdfb_free_video_memory(sinfo);release_intmem: if (map) release_mem_region(info->fix.smem_start, info->fix.smem_len);stop_clk: atmel_lcdfb_stop_clock(sinfo); clk_put(sinfo->lcdc_clk);put_bus_clk: if (sinfo->bus_clk) clk_put(sinfo->bus_clk);free_info: framebuffer_release(info);out: dev_dbg(dev, "%s FAILED\n", __func__); return ret;}static int __exit atmel_lcdfb_remove(struct platform_device *pdev){ struct device *dev = &pdev->dev; struct fb_info *info = dev_get_drvdata(dev); struct atmel_lcdfb_info *sinfo; if (!info || !info->par) return 0; sinfo = info->par; cancel_work_sync(&sinfo->task); exit_backlight(sinfo); if (sinfo->atmel_lcdfb_power_control) sinfo->atmel_lcdfb_power_control(0); unregister_framebuffer(info); atmel_lcdfb_stop_clock(sinfo); clk_put(sinfo->lcdc_clk); if (sinfo->bus_clk) clk_put(sinfo->bus_clk); fb_dealloc_cmap(&info->cmap); free_irq(sinfo->irq_base, info); iounmap(sinfo->mmio); release_mem_region(info->fix.mmio_start, info->fix.mmio_len); if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) { iounmap(info->screen_base); release_mem_region(info->fix.smem_start, info->fix.smem_len); } else { atmel_lcdfb_free_video_memory(sinfo); } dev_set_drvdata(dev, NULL); framebuffer_release(info); return 0;}#ifdef CONFIG_PMstatic int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg){ struct fb_info *info = platform_get_drvdata(pdev); struct atmel_lcdfb_info *sinfo = info->par; /* * We don't want to handle interrupts while the clock is * stopped. It may take forever. */ lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL); sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0); if (sinfo->atmel_lcdfb_power_control) sinfo->atmel_lcdfb_power_control(0); atmel_lcdfb_stop(sinfo); atmel_lcdfb_stop_clock(sinfo); return 0;}static int atmel_lcdfb_resume(struct platform_device *pdev){ struct fb_info *info = platform_get_drvdata(pdev); struct atmel_lcdfb_info *sinfo = info->par; atmel_lcdfb_start_clock(sinfo); atmel_lcdfb_start(sinfo); if (sinfo->atmel_lcdfb_power_control) sinfo->atmel_lcdfb_power_control(1); lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, sinfo->saved_lcdcon); /* Enable FIFO & DMA errors */ lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI); return 0;}#else#define atmel_lcdfb_suspend NULL#define atmel_lcdfb_resume NULL#endifstatic struct platform_driver atmel_lcdfb_driver = { .remove = __exit_p(atmel_lcdfb_remove), .suspend = atmel_lcdfb_suspend, .resume = atmel_lcdfb_resume, .driver = { .name = "atmel_lcdfb", .owner = THIS_MODULE, },};static int __init atmel_lcdfb_init(void){ return platform_driver_probe(&atmel_lcdfb_driver, atmel_lcdfb_probe);}static void __exit atmel_lcdfb_exit(void){ platform_driver_unregister(&atmel_lcdfb_driver);}module_init(atmel_lcdfb_init);module_exit(atmel_lcdfb_exit);MODULE_DESCRIPTION("AT91/AT32 LCD Controller framebuffer driver");MODULE_AUTHOR("Nicolas Ferre <nicolas.ferre@atmel.com>");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -