xref: /linux/drivers/auxdisplay/cfag12864b.c (revision 7f71507851fc7764b36a3221839607d3a45c2025)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  *    Filename: cfag12864b.c
4  *     Version: 0.1.0
5  * Description: cfag12864b LCD driver
6  *     Depends: ks0108
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/fs.h>
16 #include <linux/slab.h>
17 #include <linux/cdev.h>
18 #include <linux/delay.h>
19 #include <linux/device.h>
20 #include <linux/jiffies.h>
21 #include <linux/mutex.h>
22 #include <linux/uaccess.h>
23 #include <linux/vmalloc.h>
24 #include <linux/workqueue.h>
25 #include <linux/ks0108.h>
26 #include <linux/cfag12864b.h>
27 
28 
29 #define CFAG12864B_NAME "cfag12864b"
30 
31 /*
32  * Module Parameters
33  */
34 
35 static unsigned int cfag12864b_rate = CONFIG_CFAG12864B_RATE;
36 module_param(cfag12864b_rate, uint, 0444);
37 MODULE_PARM_DESC(cfag12864b_rate,
38 	"Refresh rate (hertz)");
39 
40 /*
41  * cfag12864b Commands
42  *
43  *	E = Enable signal
44  *		Every time E switch from low to high,
45  *		cfag12864b/ks0108 reads the command/data.
46  *
47  *	CS1 = First ks0108controller.
48  *		If high, the first ks0108 controller receives commands/data.
49  *
50  *	CS2 = Second ks0108 controller
51  *		If high, the second ks0108 controller receives commands/data.
52  *
53  *	DI = Data/Instruction
54  *		If low, cfag12864b will expect commands.
55  *		If high, cfag12864b will expect data.
56  *
57  */
58 
59 #define bit(n) (((unsigned char)1)<<(n))
60 
61 #define CFAG12864B_BIT_E	(0)
62 #define CFAG12864B_BIT_CS1	(2)
63 #define CFAG12864B_BIT_CS2	(1)
64 #define CFAG12864B_BIT_DI	(3)
65 
66 static unsigned char cfag12864b_state;
67 
68 static void cfag12864b_set(void)
69 {
70 	ks0108_writecontrol(cfag12864b_state);
71 }
72 
73 static void cfag12864b_setbit(unsigned char state, unsigned char n)
74 {
75 	if (state)
76 		cfag12864b_state |= bit(n);
77 	else
78 		cfag12864b_state &= ~bit(n);
79 }
80 
81 static void cfag12864b_e(unsigned char state)
82 {
83 	cfag12864b_setbit(state, CFAG12864B_BIT_E);
84 	cfag12864b_set();
85 }
86 
87 static void cfag12864b_cs1(unsigned char state)
88 {
89 	cfag12864b_setbit(state, CFAG12864B_BIT_CS1);
90 }
91 
92 static void cfag12864b_cs2(unsigned char state)
93 {
94 	cfag12864b_setbit(state, CFAG12864B_BIT_CS2);
95 }
96 
97 static void cfag12864b_di(unsigned char state)
98 {
99 	cfag12864b_setbit(state, CFAG12864B_BIT_DI);
100 }
101 
102 static void cfag12864b_setcontrollers(unsigned char first,
103 	unsigned char second)
104 {
105 	if (first)
106 		cfag12864b_cs1(0);
107 	else
108 		cfag12864b_cs1(1);
109 
110 	if (second)
111 		cfag12864b_cs2(0);
112 	else
113 		cfag12864b_cs2(1);
114 }
115 
116 static void cfag12864b_controller(unsigned char which)
117 {
118 	if (which == 0)
119 		cfag12864b_setcontrollers(1, 0);
120 	else if (which == 1)
121 		cfag12864b_setcontrollers(0, 1);
122 }
123 
124 static void cfag12864b_displaystate(unsigned char state)
125 {
126 	cfag12864b_di(0);
127 	cfag12864b_e(1);
128 	ks0108_displaystate(state);
129 	cfag12864b_e(0);
130 }
131 
132 static void cfag12864b_address(unsigned char address)
133 {
134 	cfag12864b_di(0);
135 	cfag12864b_e(1);
136 	ks0108_address(address);
137 	cfag12864b_e(0);
138 }
139 
140 static void cfag12864b_page(unsigned char page)
141 {
142 	cfag12864b_di(0);
143 	cfag12864b_e(1);
144 	ks0108_page(page);
145 	cfag12864b_e(0);
146 }
147 
148 static void cfag12864b_startline(unsigned char startline)
149 {
150 	cfag12864b_di(0);
151 	cfag12864b_e(1);
152 	ks0108_startline(startline);
153 	cfag12864b_e(0);
154 }
155 
156 static void cfag12864b_writebyte(unsigned char byte)
157 {
158 	cfag12864b_di(1);
159 	cfag12864b_e(1);
160 	ks0108_writedata(byte);
161 	cfag12864b_e(0);
162 }
163 
164 static void cfag12864b_nop(void)
165 {
166 	cfag12864b_startline(0);
167 }
168 
169 /*
170  * cfag12864b Internal Commands
171  */
172 
173 static void cfag12864b_on(void)
174 {
175 	cfag12864b_setcontrollers(1, 1);
176 	cfag12864b_displaystate(1);
177 }
178 
179 static void cfag12864b_off(void)
180 {
181 	cfag12864b_setcontrollers(1, 1);
182 	cfag12864b_displaystate(0);
183 }
184 
185 static void cfag12864b_clear(void)
186 {
187 	unsigned char i, j;
188 
189 	cfag12864b_setcontrollers(1, 1);
190 	for (i = 0; i < CFAG12864B_PAGES; i++) {
191 		cfag12864b_page(i);
192 		cfag12864b_address(0);
193 		for (j = 0; j < CFAG12864B_ADDRESSES; j++)
194 			cfag12864b_writebyte(0);
195 	}
196 }
197 
198 /*
199  * Update work
200  */
201 
202 unsigned char *cfag12864b_buffer;
203 static unsigned char *cfag12864b_cache;
204 static DEFINE_MUTEX(cfag12864b_mutex);
205 static unsigned char cfag12864b_updating;
206 static void cfag12864b_update(struct work_struct *delayed_work);
207 static struct workqueue_struct *cfag12864b_workqueue;
208 static DECLARE_DELAYED_WORK(cfag12864b_work, cfag12864b_update);
209 
210 static void cfag12864b_queue(void)
211 {
212 	queue_delayed_work(cfag12864b_workqueue, &cfag12864b_work,
213 		HZ / cfag12864b_rate);
214 }
215 
216 unsigned char cfag12864b_enable(void)
217 {
218 	unsigned char ret;
219 
220 	mutex_lock(&cfag12864b_mutex);
221 
222 	if (!cfag12864b_updating) {
223 		cfag12864b_updating = 1;
224 		cfag12864b_queue();
225 		ret = 0;
226 	} else
227 		ret = 1;
228 
229 	mutex_unlock(&cfag12864b_mutex);
230 
231 	return ret;
232 }
233 
234 void cfag12864b_disable(void)
235 {
236 	mutex_lock(&cfag12864b_mutex);
237 
238 	if (cfag12864b_updating) {
239 		cfag12864b_updating = 0;
240 		cancel_delayed_work(&cfag12864b_work);
241 		flush_workqueue(cfag12864b_workqueue);
242 	}
243 
244 	mutex_unlock(&cfag12864b_mutex);
245 }
246 
247 static void cfag12864b_update(struct work_struct *work)
248 {
249 	unsigned char c;
250 	unsigned short i, j, k, b;
251 
252 	if (memcmp(cfag12864b_cache, cfag12864b_buffer, CFAG12864B_SIZE)) {
253 		for (i = 0; i < CFAG12864B_CONTROLLERS; i++) {
254 			cfag12864b_controller(i);
255 			cfag12864b_nop();
256 			for (j = 0; j < CFAG12864B_PAGES; j++) {
257 				cfag12864b_page(j);
258 				cfag12864b_nop();
259 				cfag12864b_address(0);
260 				cfag12864b_nop();
261 				for (k = 0; k < CFAG12864B_ADDRESSES; k++) {
262 					for (c = 0, b = 0; b < 8; b++)
263 						if (cfag12864b_buffer
264 							[i * CFAG12864B_ADDRESSES / 8
265 							+ k / 8 + (j * 8 + b) *
266 							CFAG12864B_WIDTH / 8]
267 							& bit(k % 8))
268 							c |= bit(b);
269 					cfag12864b_writebyte(c);
270 				}
271 			}
272 		}
273 
274 		memcpy(cfag12864b_cache, cfag12864b_buffer, CFAG12864B_SIZE);
275 	}
276 
277 	if (cfag12864b_updating)
278 		cfag12864b_queue();
279 }
280 
281 /*
282  * cfag12864b Exported Symbols
283  */
284 
285 EXPORT_SYMBOL_GPL(cfag12864b_buffer);
286 EXPORT_SYMBOL_GPL(cfag12864b_enable);
287 EXPORT_SYMBOL_GPL(cfag12864b_disable);
288 
289 /*
290  * Is the module inited?
291  */
292 
293 static unsigned char cfag12864b_inited;
294 unsigned char cfag12864b_isinited(void)
295 {
296 	return cfag12864b_inited;
297 }
298 EXPORT_SYMBOL_GPL(cfag12864b_isinited);
299 
300 /*
301  * Module Init & Exit
302  */
303 
304 static int __init cfag12864b_init(void)
305 {
306 	int ret = -EINVAL;
307 
308 	/* ks0108_init() must be called first */
309 	if (!ks0108_isinited()) {
310 		printk(KERN_ERR CFAG12864B_NAME ": ERROR: "
311 			"ks0108 is not initialized\n");
312 		goto none;
313 	}
314 	BUILD_BUG_ON(PAGE_SIZE < CFAG12864B_SIZE);
315 
316 	cfag12864b_buffer = (unsigned char *) get_zeroed_page(GFP_KERNEL);
317 	if (cfag12864b_buffer == NULL) {
318 		printk(KERN_ERR CFAG12864B_NAME ": ERROR: "
319 			"can't get a free page\n");
320 		ret = -ENOMEM;
321 		goto none;
322 	}
323 
324 	cfag12864b_cache = kmalloc(CFAG12864B_SIZE,
325 				   GFP_KERNEL);
326 	if (cfag12864b_cache == NULL) {
327 		printk(KERN_ERR CFAG12864B_NAME ": ERROR: "
328 			"can't alloc cache buffer (%i bytes)\n",
329 			CFAG12864B_SIZE);
330 		ret = -ENOMEM;
331 		goto bufferalloced;
332 	}
333 
334 	cfag12864b_workqueue = create_singlethread_workqueue(CFAG12864B_NAME);
335 	if (cfag12864b_workqueue == NULL)
336 		goto cachealloced;
337 
338 	cfag12864b_clear();
339 	cfag12864b_on();
340 
341 	cfag12864b_inited = 1;
342 	return 0;
343 
344 cachealloced:
345 	kfree(cfag12864b_cache);
346 
347 bufferalloced:
348 	free_page((unsigned long) cfag12864b_buffer);
349 
350 none:
351 	return ret;
352 }
353 
354 static void __exit cfag12864b_exit(void)
355 {
356 	cfag12864b_disable();
357 	cfag12864b_off();
358 	destroy_workqueue(cfag12864b_workqueue);
359 	kfree(cfag12864b_cache);
360 	free_page((unsigned long) cfag12864b_buffer);
361 }
362 
363 module_init(cfag12864b_init);
364 module_exit(cfag12864b_exit);
365 
366 MODULE_LICENSE("GPL v2");
367 MODULE_AUTHOR("Miguel Ojeda <ojeda@kernel.org>");
368 MODULE_DESCRIPTION("cfag12864b LCD driver");
369