static unsigned int nhd_data_pin_config[] = { AT91_PIN_PE13, AT91_PIN_PE14, AT91_PIN_PE17, AT91_PIN_PE18, AT91_PIN_PE19, AT91_PIN_PE20, AT91_PIN_PE21, AT91_PIN_PE22 }; static unsigned int nhd_gpio_pin_config[] = { AT91_PIN_PE0, // RESET AT91_PIN_PE2, // DC AT91_PIN_PE5, // CLK AT91_PIN_PE6, // RD AT91_PIN_PE1 // WR };
static void nhd_write_data(int command, unsigned short value) { int i; at91_set_gpio_output(AT91_PIN_PE12, 1); //R/D for (i=0; i<ARRAY_SIZE(nhd_data_pin_config); i++) at91_set_gpio_output(nhd_data_pin_config[i], (value>>i)&0x01); if (command) at91_set_gpio_output(AT91_PIN_PE10, 0); //D/C else at91_set_gpio_output(AT91_PIN_PE10, 1); //D/C at91_set_gpio_output(AT91_PIN_PE11, 0); //WR at91_set_gpio_output(AT91_PIN_PE26, 0); //CS at91_set_gpio_output(AT91_PIN_PE26, 1); //CS at91_set_gpio_output(AT91_PIN_PE11, 1); //WR }
static struct fb_fix_screeninfo ssd1963_fix __initdata = { .id = "SSD1963", .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_TRUECOLOR, .accel = FB_ACCEL_NONE, .line_length = 320 * 4, }; static struct fb_var_screeninfo ssd1963_var __initdata = { .xres = 320, .yres = 240, .xres_virtual = 320, .yres_virtual = 240, .width = 320, .height = 240, .bits_per_pixel = 32, .transp = {24, 8, 0}, .red = {16, 8, 0}, .green = {8, 8, 0}, .blue = {0, 8, 0}, .activate = FB_ACTIVATE_NOW, .vmode = FB_VMODE_NONINTERLACED, };
struct ssd1963_page { unsigned short x; unsigned short y; unsigned long *buffer; unsigned short len; int must_update; }; struct ssd1963 { struct device *dev; struct fb_info *info; unsigned int pages_count; struct ssd1963_page *pages; }; struct platform_driver ssd1963_driver = { .probe = ssd1963_probe, .remove = ssd1963_remove, .driver = { .name = "ssd1963" } };
static int __init ssd1963_init(void) { int ret = 0; ret = platform_driver_register(&ssd1963_driver); if (ret) { pr_err("%s: unable to platform_driver_register\n", __func__); } return ret; } module_init(ssd1963_init);
static int __init ssd1963_probe(struct platform_device *dev) { int ret = 0; struct ssd1963 *item; struct fb_info *info; // Allocating memory for ssd1663 device item = kzalloc(sizeof(struct ssd1963), GFP_KERNEL); if (!item) { dev_err(&dev->dev, "%s: unable to kzalloc for ssd1963\n", __func__); ret = -ENOMEM; goto out; } item->dev = &dev->dev; dev_set_drvdata(&dev->dev, item); // Initializing fb_info struct using kernel framebuffer API info = framebuffer_alloc(sizeof(struct ssd1963), &dev->dev); if (!info) { ret = -ENOMEM; dev_err(&dev->dev, "%s: unable to framebuffer_alloc\n", __func__); goto out_item; } item->info = info; //Here info->par pointer is commonly used to store private data // In our case, we can use it to store pointer to ssd1963 device info->par = item; info->dev = &dev->dev; info->fbops = &ssd1963_fbops; info->flags = FBINFO_FLAG_DEFAULT; info->fix = ssd1963_fix; info->var = ssd1963_var; ret = ssd1963_video_alloc(item); if (ret) { dev_err(&dev->dev, "%s: unable to ssd1963_video_alloc\n", __func__); goto out_info; } info->screen_base = (char __iomem *)item->info->fix.smem_start; ret = ssd1963_pages_alloc(item); if (ret < 0) { dev_err(&dev->dev, "%s: unable to ssd1963_pages_init\n", __func__); goto out_video; } info->fbdefio = &ssd1963_defio; fb_deferred_io_init(info); ret = register_framebuffer(info); if (ret < 0) { dev_err(&dev->dev, "%s: unable to register_frambuffer\n", __func__); goto out_pages; } ssd1963_setup(item); ssd1963_update_all(item); return ret; out_pages: ssd1963_pages_free(item); out_video: ssd1963_video_free(item); out_info: framebuffer_release(info); out_item: kfree(item); out: return ret; }
void ssd1963_setup(struct ssd1963 *item) { nhd_init_gpio_regs(); //initializations of pins in nhd_data-gpio_pin_config at91_set_gpio_output(AT91_PIN_PE27, 0); //RESET udelay(5); at91_set_gpio_output(AT91_PIN_PE27, 1); //RESET udelay(100); nhd_write_data(NHD_COMMAND, 0x01); //Software Reset ... nhd_write_to_register(0xe0, 0x03); //LOCK PLL nhd_write_data(NHD_COMMAND, 0xb0); //SET LCD MODE TFT 18Bits nhd_write_data(NHD_DATA, 0x0c); //SET MODE 24 bits & hsync+Vsync+DEN … }
static int ssd1963_remove(struct platform_device *device) { struct fb_info *info = platform_get_drvdata(device); struct ssd1963 *item = (struct ssd1963 *)info->par; if (info) { unregister_framebuffer(info); ssd1963_pages_free(item); ssd1963_video_free(item); framebuffer_release(info); kfree(item); } return 0; }
static struct fb_ops ssd1963_fbops = { .owner = THIS_MODULE, .fb_read = fb_sys_read, .fb_write = ssd1963_write, .fb_fillrect = ssd1963_fillrect, .fb_copyarea = ssd1963_copyarea, .fb_imageblit = ssd1963_imageblit, .fb_setcolreg = ssd1963_setcolreg, .fb_blank = ssd1963_blank, };
static void ssd1963_fillrect(struct fb_info *p, const struct fb_fillrect *rect) { sys_fillrect(p, rect); ssd1963_touch(p, rect->dx, rect->dy, rect->width, rect->height); }
static void ssd1963_touch(struct fb_info *info, int x, int y, int w, int h) { struct fb_deferred_io *fbdefio = info->fbdefio; struct ssd1963 *item = (struct ssd1963 *)info->par; int i, ystart, yend; if (fbdefio) { //Touch the pages, so the deferred io will update them. for (i=0; i<item->pages_count; i++) { ystart=item->pages[i].y; yend=item->pages[i].y+(item->pages[i].len/info->fix.line_length)+1; if (!((y+h)<ystart || y>yend)) { item->pages[i].must_update=1; } } //Schedule the deferred IO to kick in after a delay. schedule_delayed_work(&info->deferred_work, fbdefio->delay); } }
static struct fb_deferred_io ssd1963_defio = { .delay = HZ / 20, .deferred_io = &ssd1963_update, };
static void ssd1963_update(struct fb_info *info, struct list_head *pagelist) { struct ssd1963 *item = (struct ssd1963 *)info->par; struct page *page; int i; list_for_each_entry(page, pagelist, lru) { item->pages[page->index].must_update=1; } //Copy changed pages. for (i=0; i<item->pages_count; i++) { if (item->pages[i].must_update) { item->pages[i].must_update=0; ssd1963_copy(item, i); } } }
static void ssd1963_copy(struct ssd1963 *item, unsigned int index) { unsigned short x,y, startx, endx, starty, endy, offset; unsigned long *buffer; unsigned int len; unsigned int count; x = item->pages[index].x; y = item->pages[index].y; buffer = item->pages[index].buffer; len = item->pages[index].len; switch (index%5) { case 0: offset = 0; startx = x; starty = y; endx = 319; endy = y+2; len = 960; nhd_set_window(startx, endx, starty, endy); nhd_write_data(NHD_COMMAND, 0x2c); for (count = 0; count < len; count++) { nhd_write_data(NHD_DATA,(unsigned char)((buffer[count+offset])>>16)); //red nhd_write_data(NHD_DATA,(unsigned char)((buffer[count+offset])>>8)); //green nhd_write_data(NHD_DATA,(unsigned char)(buffer[count+offset])); //blue } offset = len; startx = x; starty = y+3; endx = x+63; endy = y+3; len = 64; nhd_set_window(startx, endx, starty, endy); nhd_write_data(NHD_COMMAND, 0x2c); for (count = 0; count < len; count++) { nhd_write_data(NHD_DATA,(unsigned char)((buffer[count+offset])>>16)); //red nhd_write_data(NHD_DATA,(unsigned char)((buffer[count+offset])>>8)); //green nhd_write_data(NHD_DATA,(unsigned char)(buffer[count+offset])); //blue } break; case 1: ….
Source: https://habr.com/ru/post/213775/
All Articles