1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Filename: cfag12864bfb.c |
4 | * Version: 0.1.0 |
5 | * Description: cfag12864b LCD framebuffer driver |
6 | * Depends: cfag12864b |
7 | * |
8 | * Author: Copyright (C) Miguel Ojeda <ojeda@kernel.org> |
9 | * Date: 2006-10-31 |
10 | */ |
11 | |
12 | #include <linux/init.h> |
13 | #include <linux/module.h> |
14 | #include <linux/kernel.h> |
15 | #include <linux/errno.h> |
16 | #include <linux/fb.h> |
17 | #include <linux/mm.h> |
18 | #include <linux/platform_device.h> |
19 | #include <linux/cfag12864b.h> |
20 | |
21 | #define CFAG12864BFB_NAME "cfag12864bfb" |
22 | |
23 | static const struct fb_fix_screeninfo cfag12864bfb_fix = { |
24 | .id = "cfag12864b" , |
25 | .type = FB_TYPE_PACKED_PIXELS, |
26 | .visual = FB_VISUAL_MONO10, |
27 | .xpanstep = 0, |
28 | .ypanstep = 0, |
29 | .ywrapstep = 0, |
30 | .line_length = CFAG12864B_WIDTH / 8, |
31 | .accel = FB_ACCEL_NONE, |
32 | }; |
33 | |
34 | static const struct fb_var_screeninfo cfag12864bfb_var = { |
35 | .xres = CFAG12864B_WIDTH, |
36 | .yres = CFAG12864B_HEIGHT, |
37 | .xres_virtual = CFAG12864B_WIDTH, |
38 | .yres_virtual = CFAG12864B_HEIGHT, |
39 | .bits_per_pixel = 1, |
40 | .red = { 0, 1, 0 }, |
41 | .green = { 0, 1, 0 }, |
42 | .blue = { 0, 1, 0 }, |
43 | .left_margin = 0, |
44 | .right_margin = 0, |
45 | .upper_margin = 0, |
46 | .lower_margin = 0, |
47 | .vmode = FB_VMODE_NONINTERLACED, |
48 | }; |
49 | |
50 | static int cfag12864bfb_mmap(struct fb_info *info, struct vm_area_struct *vma) |
51 | { |
52 | struct page *pages = virt_to_page(cfag12864b_buffer); |
53 | |
54 | vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); |
55 | |
56 | return vm_map_pages_zero(vma, pages: &pages, num: 1); |
57 | } |
58 | |
59 | static const struct fb_ops cfag12864bfb_ops = { |
60 | .owner = THIS_MODULE, |
61 | __FB_DEFAULT_SYSMEM_OPS_RDWR, |
62 | __FB_DEFAULT_SYSMEM_OPS_DRAW, |
63 | .fb_mmap = cfag12864bfb_mmap, |
64 | }; |
65 | |
66 | static int cfag12864bfb_probe(struct platform_device *device) |
67 | { |
68 | int ret = -EINVAL; |
69 | struct fb_info *info = framebuffer_alloc(size: 0, dev: &device->dev); |
70 | |
71 | if (!info) |
72 | goto none; |
73 | |
74 | info->flags = FBINFO_VIRTFB; |
75 | info->screen_buffer = cfag12864b_buffer; |
76 | info->screen_size = CFAG12864B_SIZE; |
77 | info->fbops = &cfag12864bfb_ops; |
78 | info->fix = cfag12864bfb_fix; |
79 | info->var = cfag12864bfb_var; |
80 | info->pseudo_palette = NULL; |
81 | info->par = NULL; |
82 | |
83 | if (register_framebuffer(fb_info: info) < 0) |
84 | goto fballoced; |
85 | |
86 | platform_set_drvdata(pdev: device, data: info); |
87 | |
88 | fb_info(info, "%s frame buffer device\n" , info->fix.id); |
89 | |
90 | return 0; |
91 | |
92 | fballoced: |
93 | framebuffer_release(info); |
94 | |
95 | none: |
96 | return ret; |
97 | } |
98 | |
99 | static void cfag12864bfb_remove(struct platform_device *device) |
100 | { |
101 | struct fb_info *info = platform_get_drvdata(pdev: device); |
102 | |
103 | if (info) { |
104 | unregister_framebuffer(fb_info: info); |
105 | framebuffer_release(info); |
106 | } |
107 | } |
108 | |
109 | static struct platform_driver cfag12864bfb_driver = { |
110 | .probe = cfag12864bfb_probe, |
111 | .remove_new = cfag12864bfb_remove, |
112 | .driver = { |
113 | .name = CFAG12864BFB_NAME, |
114 | }, |
115 | }; |
116 | |
117 | static struct platform_device *cfag12864bfb_device; |
118 | |
119 | static int __init cfag12864bfb_init(void) |
120 | { |
121 | int ret = -EINVAL; |
122 | |
123 | /* cfag12864b_init() must be called first */ |
124 | if (!cfag12864b_isinited()) { |
125 | printk(KERN_ERR CFAG12864BFB_NAME ": ERROR: " |
126 | "cfag12864b is not initialized\n" ); |
127 | goto none; |
128 | } |
129 | |
130 | if (cfag12864b_enable()) { |
131 | printk(KERN_ERR CFAG12864BFB_NAME ": ERROR: " |
132 | "can't enable cfag12864b refreshing (being used)\n" ); |
133 | return -ENODEV; |
134 | } |
135 | |
136 | ret = platform_driver_register(&cfag12864bfb_driver); |
137 | |
138 | if (!ret) { |
139 | cfag12864bfb_device = |
140 | platform_device_alloc(CFAG12864BFB_NAME, id: 0); |
141 | |
142 | if (cfag12864bfb_device) |
143 | ret = platform_device_add(pdev: cfag12864bfb_device); |
144 | else |
145 | ret = -ENOMEM; |
146 | |
147 | if (ret) { |
148 | platform_device_put(pdev: cfag12864bfb_device); |
149 | platform_driver_unregister(&cfag12864bfb_driver); |
150 | } |
151 | } |
152 | |
153 | none: |
154 | return ret; |
155 | } |
156 | |
157 | static void __exit cfag12864bfb_exit(void) |
158 | { |
159 | platform_device_unregister(cfag12864bfb_device); |
160 | platform_driver_unregister(&cfag12864bfb_driver); |
161 | cfag12864b_disable(); |
162 | } |
163 | |
164 | module_init(cfag12864bfb_init); |
165 | module_exit(cfag12864bfb_exit); |
166 | |
167 | MODULE_LICENSE("GPL v2" ); |
168 | MODULE_AUTHOR("Miguel Ojeda <ojeda@kernel.org>" ); |
169 | MODULE_DESCRIPTION("cfag12864b LCD framebuffer driver" ); |
170 | |