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