18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Filename: cfag12864bfb.c 48c2ecf20Sopenharmony_ci * Version: 0.1.0 58c2ecf20Sopenharmony_ci * Description: cfag12864b LCD framebuffer driver 68c2ecf20Sopenharmony_ci * Depends: cfag12864b 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Author: Copyright (C) Miguel Ojeda Sandonis 98c2ecf20Sopenharmony_ci * Date: 2006-10-31 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/delay.h> 168c2ecf20Sopenharmony_ci#include <linux/errno.h> 178c2ecf20Sopenharmony_ci#include <linux/fb.h> 188c2ecf20Sopenharmony_ci#include <linux/mm.h> 198c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 208c2ecf20Sopenharmony_ci#include <linux/string.h> 218c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 228c2ecf20Sopenharmony_ci#include <linux/cfag12864b.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define CFAG12864BFB_NAME "cfag12864bfb" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic const struct fb_fix_screeninfo cfag12864bfb_fix = { 278c2ecf20Sopenharmony_ci .id = "cfag12864b", 288c2ecf20Sopenharmony_ci .type = FB_TYPE_PACKED_PIXELS, 298c2ecf20Sopenharmony_ci .visual = FB_VISUAL_MONO10, 308c2ecf20Sopenharmony_ci .xpanstep = 0, 318c2ecf20Sopenharmony_ci .ypanstep = 0, 328c2ecf20Sopenharmony_ci .ywrapstep = 0, 338c2ecf20Sopenharmony_ci .line_length = CFAG12864B_WIDTH / 8, 348c2ecf20Sopenharmony_ci .accel = FB_ACCEL_NONE, 358c2ecf20Sopenharmony_ci}; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic const struct fb_var_screeninfo cfag12864bfb_var = { 388c2ecf20Sopenharmony_ci .xres = CFAG12864B_WIDTH, 398c2ecf20Sopenharmony_ci .yres = CFAG12864B_HEIGHT, 408c2ecf20Sopenharmony_ci .xres_virtual = CFAG12864B_WIDTH, 418c2ecf20Sopenharmony_ci .yres_virtual = CFAG12864B_HEIGHT, 428c2ecf20Sopenharmony_ci .bits_per_pixel = 1, 438c2ecf20Sopenharmony_ci .red = { 0, 1, 0 }, 448c2ecf20Sopenharmony_ci .green = { 0, 1, 0 }, 458c2ecf20Sopenharmony_ci .blue = { 0, 1, 0 }, 468c2ecf20Sopenharmony_ci .left_margin = 0, 478c2ecf20Sopenharmony_ci .right_margin = 0, 488c2ecf20Sopenharmony_ci .upper_margin = 0, 498c2ecf20Sopenharmony_ci .lower_margin = 0, 508c2ecf20Sopenharmony_ci .vmode = FB_VMODE_NONINTERLACED, 518c2ecf20Sopenharmony_ci}; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic int cfag12864bfb_mmap(struct fb_info *info, struct vm_area_struct *vma) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci struct page *pages = virt_to_page(cfag12864b_buffer); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci return vm_map_pages_zero(vma, &pages, 1); 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic const struct fb_ops cfag12864bfb_ops = { 618c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 628c2ecf20Sopenharmony_ci .fb_read = fb_sys_read, 638c2ecf20Sopenharmony_ci .fb_write = fb_sys_write, 648c2ecf20Sopenharmony_ci .fb_fillrect = sys_fillrect, 658c2ecf20Sopenharmony_ci .fb_copyarea = sys_copyarea, 668c2ecf20Sopenharmony_ci .fb_imageblit = sys_imageblit, 678c2ecf20Sopenharmony_ci .fb_mmap = cfag12864bfb_mmap, 688c2ecf20Sopenharmony_ci}; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic int cfag12864bfb_probe(struct platform_device *device) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci int ret = -EINVAL; 738c2ecf20Sopenharmony_ci struct fb_info *info = framebuffer_alloc(0, &device->dev); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci if (!info) 768c2ecf20Sopenharmony_ci goto none; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci info->screen_base = (char __iomem *) cfag12864b_buffer; 798c2ecf20Sopenharmony_ci info->screen_size = CFAG12864B_SIZE; 808c2ecf20Sopenharmony_ci info->fbops = &cfag12864bfb_ops; 818c2ecf20Sopenharmony_ci info->fix = cfag12864bfb_fix; 828c2ecf20Sopenharmony_ci info->var = cfag12864bfb_var; 838c2ecf20Sopenharmony_ci info->pseudo_palette = NULL; 848c2ecf20Sopenharmony_ci info->par = NULL; 858c2ecf20Sopenharmony_ci info->flags = FBINFO_FLAG_DEFAULT; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if (register_framebuffer(info) < 0) 888c2ecf20Sopenharmony_ci goto fballoced; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci platform_set_drvdata(device, info); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci fb_info(info, "%s frame buffer device\n", info->fix.id); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci return 0; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cifballoced: 978c2ecf20Sopenharmony_ci framebuffer_release(info); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cinone: 1008c2ecf20Sopenharmony_ci return ret; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic int cfag12864bfb_remove(struct platform_device *device) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci struct fb_info *info = platform_get_drvdata(device); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci if (info) { 1088c2ecf20Sopenharmony_ci unregister_framebuffer(info); 1098c2ecf20Sopenharmony_ci framebuffer_release(info); 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci return 0; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic struct platform_driver cfag12864bfb_driver = { 1168c2ecf20Sopenharmony_ci .probe = cfag12864bfb_probe, 1178c2ecf20Sopenharmony_ci .remove = cfag12864bfb_remove, 1188c2ecf20Sopenharmony_ci .driver = { 1198c2ecf20Sopenharmony_ci .name = CFAG12864BFB_NAME, 1208c2ecf20Sopenharmony_ci }, 1218c2ecf20Sopenharmony_ci}; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic struct platform_device *cfag12864bfb_device; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic int __init cfag12864bfb_init(void) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci int ret = -EINVAL; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci /* cfag12864b_init() must be called first */ 1308c2ecf20Sopenharmony_ci if (!cfag12864b_isinited()) { 1318c2ecf20Sopenharmony_ci printk(KERN_ERR CFAG12864BFB_NAME ": ERROR: " 1328c2ecf20Sopenharmony_ci "cfag12864b is not initialized\n"); 1338c2ecf20Sopenharmony_ci goto none; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci if (cfag12864b_enable()) { 1378c2ecf20Sopenharmony_ci printk(KERN_ERR CFAG12864BFB_NAME ": ERROR: " 1388c2ecf20Sopenharmony_ci "can't enable cfag12864b refreshing (being used)\n"); 1398c2ecf20Sopenharmony_ci return -ENODEV; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci ret = platform_driver_register(&cfag12864bfb_driver); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci if (!ret) { 1458c2ecf20Sopenharmony_ci cfag12864bfb_device = 1468c2ecf20Sopenharmony_ci platform_device_alloc(CFAG12864BFB_NAME, 0); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (cfag12864bfb_device) 1498c2ecf20Sopenharmony_ci ret = platform_device_add(cfag12864bfb_device); 1508c2ecf20Sopenharmony_ci else 1518c2ecf20Sopenharmony_ci ret = -ENOMEM; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci if (ret) { 1548c2ecf20Sopenharmony_ci platform_device_put(cfag12864bfb_device); 1558c2ecf20Sopenharmony_ci platform_driver_unregister(&cfag12864bfb_driver); 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_cinone: 1608c2ecf20Sopenharmony_ci return ret; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic void __exit cfag12864bfb_exit(void) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci platform_device_unregister(cfag12864bfb_device); 1668c2ecf20Sopenharmony_ci platform_driver_unregister(&cfag12864bfb_driver); 1678c2ecf20Sopenharmony_ci cfag12864b_disable(); 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cimodule_init(cfag12864bfb_init); 1718c2ecf20Sopenharmony_cimodule_exit(cfag12864bfb_exit); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1748c2ecf20Sopenharmony_ciMODULE_AUTHOR("Miguel Ojeda Sandonis <miguel.ojeda.sandonis@gmail.com>"); 1758c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("cfag12864b LCD framebuffer driver"); 176