xref: /linux/drivers/auxdisplay/cfag12864b.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
1351f683bSMiguel Ojeda // SPDX-License-Identifier: GPL-2.0
270e84049SMiguel Ojeda Sandonis /*
370e84049SMiguel Ojeda Sandonis  *    Filename: cfag12864b.c
470e84049SMiguel Ojeda Sandonis  *     Version: 0.1.0
570e84049SMiguel Ojeda Sandonis  * Description: cfag12864b LCD driver
670e84049SMiguel Ojeda Sandonis  *     Depends: ks0108
770e84049SMiguel Ojeda Sandonis  *
8c131bd0bSMiguel Ojeda  *      Author: Copyright (C) Miguel Ojeda <ojeda@kernel.org>
970e84049SMiguel Ojeda Sandonis  *        Date: 2006-10-31
1070e84049SMiguel Ojeda Sandonis  */
1170e84049SMiguel Ojeda Sandonis 
1270e84049SMiguel Ojeda Sandonis #include <linux/init.h>
1370e84049SMiguel Ojeda Sandonis #include <linux/module.h>
1470e84049SMiguel Ojeda Sandonis #include <linux/kernel.h>
1570e84049SMiguel Ojeda Sandonis #include <linux/fs.h>
165a0e3ad6STejun Heo #include <linux/slab.h>
1770e84049SMiguel Ojeda Sandonis #include <linux/cdev.h>
1870e84049SMiguel Ojeda Sandonis #include <linux/delay.h>
1970e84049SMiguel Ojeda Sandonis #include <linux/device.h>
2070e84049SMiguel Ojeda Sandonis #include <linux/jiffies.h>
2170e84049SMiguel Ojeda Sandonis #include <linux/mutex.h>
2270e84049SMiguel Ojeda Sandonis #include <linux/uaccess.h>
2370e84049SMiguel Ojeda Sandonis #include <linux/vmalloc.h>
2470e84049SMiguel Ojeda Sandonis #include <linux/workqueue.h>
2570e84049SMiguel Ojeda Sandonis #include <linux/ks0108.h>
2670e84049SMiguel Ojeda Sandonis #include <linux/cfag12864b.h>
2770e84049SMiguel Ojeda Sandonis 
2870e84049SMiguel Ojeda Sandonis 
2970e84049SMiguel Ojeda Sandonis #define CFAG12864B_NAME "cfag12864b"
3070e84049SMiguel Ojeda Sandonis 
3170e84049SMiguel Ojeda Sandonis /*
3270e84049SMiguel Ojeda Sandonis  * Module Parameters
3370e84049SMiguel Ojeda Sandonis  */
3470e84049SMiguel Ojeda Sandonis 
3570e84049SMiguel Ojeda Sandonis static unsigned int cfag12864b_rate = CONFIG_CFAG12864B_RATE;
36*24ebc044SJinchao Wang module_param(cfag12864b_rate, uint, 0444);
3770e84049SMiguel Ojeda Sandonis MODULE_PARM_DESC(cfag12864b_rate,
3825985edcSLucas De Marchi 	"Refresh rate (hertz)");
3970e84049SMiguel Ojeda Sandonis 
cfag12864b_getrate(void)4070e84049SMiguel Ojeda Sandonis unsigned int cfag12864b_getrate(void)
4170e84049SMiguel Ojeda Sandonis {
4270e84049SMiguel Ojeda Sandonis 	return cfag12864b_rate;
4370e84049SMiguel Ojeda Sandonis }
4470e84049SMiguel Ojeda Sandonis 
4570e84049SMiguel Ojeda Sandonis /*
4670e84049SMiguel Ojeda Sandonis  * cfag12864b Commands
4770e84049SMiguel Ojeda Sandonis  *
4870e84049SMiguel Ojeda Sandonis  *	E = Enable signal
4970e84049SMiguel Ojeda Sandonis  *		Every time E switch from low to high,
5070e84049SMiguel Ojeda Sandonis  *		cfag12864b/ks0108 reads the command/data.
5170e84049SMiguel Ojeda Sandonis  *
5270e84049SMiguel Ojeda Sandonis  *	CS1 = First ks0108controller.
5370e84049SMiguel Ojeda Sandonis  *		If high, the first ks0108 controller receives commands/data.
5470e84049SMiguel Ojeda Sandonis  *
5570e84049SMiguel Ojeda Sandonis  *	CS2 = Second ks0108 controller
5670e84049SMiguel Ojeda Sandonis  *		If high, the second ks0108 controller receives commands/data.
5770e84049SMiguel Ojeda Sandonis  *
5870e84049SMiguel Ojeda Sandonis  *	DI = Data/Instruction
5970e84049SMiguel Ojeda Sandonis  *		If low, cfag12864b will expect commands.
6070e84049SMiguel Ojeda Sandonis  *		If high, cfag12864b will expect data.
6170e84049SMiguel Ojeda Sandonis  *
6270e84049SMiguel Ojeda Sandonis  */
6370e84049SMiguel Ojeda Sandonis 
6470e84049SMiguel Ojeda Sandonis #define bit(n) (((unsigned char)1)<<(n))
6570e84049SMiguel Ojeda Sandonis 
6670e84049SMiguel Ojeda Sandonis #define CFAG12864B_BIT_E	(0)
6770e84049SMiguel Ojeda Sandonis #define CFAG12864B_BIT_CS1	(2)
6870e84049SMiguel Ojeda Sandonis #define CFAG12864B_BIT_CS2	(1)
6970e84049SMiguel Ojeda Sandonis #define CFAG12864B_BIT_DI	(3)
7070e84049SMiguel Ojeda Sandonis 
7170e84049SMiguel Ojeda Sandonis static unsigned char cfag12864b_state;
7270e84049SMiguel Ojeda Sandonis 
cfag12864b_set(void)7370e84049SMiguel Ojeda Sandonis static void cfag12864b_set(void)
7470e84049SMiguel Ojeda Sandonis {
7570e84049SMiguel Ojeda Sandonis 	ks0108_writecontrol(cfag12864b_state);
7670e84049SMiguel Ojeda Sandonis }
7770e84049SMiguel Ojeda Sandonis 
cfag12864b_setbit(unsigned char state,unsigned char n)7870e84049SMiguel Ojeda Sandonis static void cfag12864b_setbit(unsigned char state, unsigned char n)
7970e84049SMiguel Ojeda Sandonis {
8070e84049SMiguel Ojeda Sandonis 	if (state)
8170e84049SMiguel Ojeda Sandonis 		cfag12864b_state |= bit(n);
8270e84049SMiguel Ojeda Sandonis 	else
8370e84049SMiguel Ojeda Sandonis 		cfag12864b_state &= ~bit(n);
8470e84049SMiguel Ojeda Sandonis }
8570e84049SMiguel Ojeda Sandonis 
cfag12864b_e(unsigned char state)8670e84049SMiguel Ojeda Sandonis static void cfag12864b_e(unsigned char state)
8770e84049SMiguel Ojeda Sandonis {
8870e84049SMiguel Ojeda Sandonis 	cfag12864b_setbit(state, CFAG12864B_BIT_E);
8970e84049SMiguel Ojeda Sandonis 	cfag12864b_set();
9070e84049SMiguel Ojeda Sandonis }
9170e84049SMiguel Ojeda Sandonis 
cfag12864b_cs1(unsigned char state)9270e84049SMiguel Ojeda Sandonis static void cfag12864b_cs1(unsigned char state)
9370e84049SMiguel Ojeda Sandonis {
9470e84049SMiguel Ojeda Sandonis 	cfag12864b_setbit(state, CFAG12864B_BIT_CS1);
9570e84049SMiguel Ojeda Sandonis }
9670e84049SMiguel Ojeda Sandonis 
cfag12864b_cs2(unsigned char state)9770e84049SMiguel Ojeda Sandonis static void cfag12864b_cs2(unsigned char state)
9870e84049SMiguel Ojeda Sandonis {
9970e84049SMiguel Ojeda Sandonis 	cfag12864b_setbit(state, CFAG12864B_BIT_CS2);
10070e84049SMiguel Ojeda Sandonis }
10170e84049SMiguel Ojeda Sandonis 
cfag12864b_di(unsigned char state)10270e84049SMiguel Ojeda Sandonis static void cfag12864b_di(unsigned char state)
10370e84049SMiguel Ojeda Sandonis {
10470e84049SMiguel Ojeda Sandonis 	cfag12864b_setbit(state, CFAG12864B_BIT_DI);
10570e84049SMiguel Ojeda Sandonis }
10670e84049SMiguel Ojeda Sandonis 
cfag12864b_setcontrollers(unsigned char first,unsigned char second)10770e84049SMiguel Ojeda Sandonis static void cfag12864b_setcontrollers(unsigned char first,
10870e84049SMiguel Ojeda Sandonis 	unsigned char second)
10970e84049SMiguel Ojeda Sandonis {
11070e84049SMiguel Ojeda Sandonis 	if (first)
11170e84049SMiguel Ojeda Sandonis 		cfag12864b_cs1(0);
11270e84049SMiguel Ojeda Sandonis 	else
11370e84049SMiguel Ojeda Sandonis 		cfag12864b_cs1(1);
11470e84049SMiguel Ojeda Sandonis 
11570e84049SMiguel Ojeda Sandonis 	if (second)
11670e84049SMiguel Ojeda Sandonis 		cfag12864b_cs2(0);
11770e84049SMiguel Ojeda Sandonis 	else
11870e84049SMiguel Ojeda Sandonis 		cfag12864b_cs2(1);
11970e84049SMiguel Ojeda Sandonis }
12070e84049SMiguel Ojeda Sandonis 
cfag12864b_controller(unsigned char which)12170e84049SMiguel Ojeda Sandonis static void cfag12864b_controller(unsigned char which)
12270e84049SMiguel Ojeda Sandonis {
12370e84049SMiguel Ojeda Sandonis 	if (which == 0)
12470e84049SMiguel Ojeda Sandonis 		cfag12864b_setcontrollers(1, 0);
12570e84049SMiguel Ojeda Sandonis 	else if (which == 1)
12670e84049SMiguel Ojeda Sandonis 		cfag12864b_setcontrollers(0, 1);
12770e84049SMiguel Ojeda Sandonis }
12870e84049SMiguel Ojeda Sandonis 
cfag12864b_displaystate(unsigned char state)12970e84049SMiguel Ojeda Sandonis static void cfag12864b_displaystate(unsigned char state)
13070e84049SMiguel Ojeda Sandonis {
13170e84049SMiguel Ojeda Sandonis 	cfag12864b_di(0);
13270e84049SMiguel Ojeda Sandonis 	cfag12864b_e(1);
13370e84049SMiguel Ojeda Sandonis 	ks0108_displaystate(state);
13470e84049SMiguel Ojeda Sandonis 	cfag12864b_e(0);
13570e84049SMiguel Ojeda Sandonis }
13670e84049SMiguel Ojeda Sandonis 
cfag12864b_address(unsigned char address)13770e84049SMiguel Ojeda Sandonis static void cfag12864b_address(unsigned char address)
13870e84049SMiguel Ojeda Sandonis {
13970e84049SMiguel Ojeda Sandonis 	cfag12864b_di(0);
14070e84049SMiguel Ojeda Sandonis 	cfag12864b_e(1);
14170e84049SMiguel Ojeda Sandonis 	ks0108_address(address);
14270e84049SMiguel Ojeda Sandonis 	cfag12864b_e(0);
14370e84049SMiguel Ojeda Sandonis }
14470e84049SMiguel Ojeda Sandonis 
cfag12864b_page(unsigned char page)14570e84049SMiguel Ojeda Sandonis static void cfag12864b_page(unsigned char page)
14670e84049SMiguel Ojeda Sandonis {
14770e84049SMiguel Ojeda Sandonis 	cfag12864b_di(0);
14870e84049SMiguel Ojeda Sandonis 	cfag12864b_e(1);
14970e84049SMiguel Ojeda Sandonis 	ks0108_page(page);
15070e84049SMiguel Ojeda Sandonis 	cfag12864b_e(0);
15170e84049SMiguel Ojeda Sandonis }
15270e84049SMiguel Ojeda Sandonis 
cfag12864b_startline(unsigned char startline)15370e84049SMiguel Ojeda Sandonis static void cfag12864b_startline(unsigned char startline)
15470e84049SMiguel Ojeda Sandonis {
15570e84049SMiguel Ojeda Sandonis 	cfag12864b_di(0);
15670e84049SMiguel Ojeda Sandonis 	cfag12864b_e(1);
15770e84049SMiguel Ojeda Sandonis 	ks0108_startline(startline);
15870e84049SMiguel Ojeda Sandonis 	cfag12864b_e(0);
15970e84049SMiguel Ojeda Sandonis }
16070e84049SMiguel Ojeda Sandonis 
cfag12864b_writebyte(unsigned char byte)16170e84049SMiguel Ojeda Sandonis static void cfag12864b_writebyte(unsigned char byte)
16270e84049SMiguel Ojeda Sandonis {
16370e84049SMiguel Ojeda Sandonis 	cfag12864b_di(1);
16470e84049SMiguel Ojeda Sandonis 	cfag12864b_e(1);
16570e84049SMiguel Ojeda Sandonis 	ks0108_writedata(byte);
16670e84049SMiguel Ojeda Sandonis 	cfag12864b_e(0);
16770e84049SMiguel Ojeda Sandonis }
16870e84049SMiguel Ojeda Sandonis 
cfag12864b_nop(void)16970e84049SMiguel Ojeda Sandonis static void cfag12864b_nop(void)
17070e84049SMiguel Ojeda Sandonis {
17170e84049SMiguel Ojeda Sandonis 	cfag12864b_startline(0);
17270e84049SMiguel Ojeda Sandonis }
17370e84049SMiguel Ojeda Sandonis 
17470e84049SMiguel Ojeda Sandonis /*
17570e84049SMiguel Ojeda Sandonis  * cfag12864b Internal Commands
17670e84049SMiguel Ojeda Sandonis  */
17770e84049SMiguel Ojeda Sandonis 
cfag12864b_on(void)17870e84049SMiguel Ojeda Sandonis static void cfag12864b_on(void)
17970e84049SMiguel Ojeda Sandonis {
18070e84049SMiguel Ojeda Sandonis 	cfag12864b_setcontrollers(1, 1);
18170e84049SMiguel Ojeda Sandonis 	cfag12864b_displaystate(1);
18270e84049SMiguel Ojeda Sandonis }
18370e84049SMiguel Ojeda Sandonis 
cfag12864b_off(void)18470e84049SMiguel Ojeda Sandonis static void cfag12864b_off(void)
18570e84049SMiguel Ojeda Sandonis {
18670e84049SMiguel Ojeda Sandonis 	cfag12864b_setcontrollers(1, 1);
18770e84049SMiguel Ojeda Sandonis 	cfag12864b_displaystate(0);
18870e84049SMiguel Ojeda Sandonis }
18970e84049SMiguel Ojeda Sandonis 
cfag12864b_clear(void)19070e84049SMiguel Ojeda Sandonis static void cfag12864b_clear(void)
19170e84049SMiguel Ojeda Sandonis {
19270e84049SMiguel Ojeda Sandonis 	unsigned char i, j;
19370e84049SMiguel Ojeda Sandonis 
19470e84049SMiguel Ojeda Sandonis 	cfag12864b_setcontrollers(1, 1);
19570e84049SMiguel Ojeda Sandonis 	for (i = 0; i < CFAG12864B_PAGES; i++) {
19670e84049SMiguel Ojeda Sandonis 		cfag12864b_page(i);
19770e84049SMiguel Ojeda Sandonis 		cfag12864b_address(0);
19870e84049SMiguel Ojeda Sandonis 		for (j = 0; j < CFAG12864B_ADDRESSES; j++)
19970e84049SMiguel Ojeda Sandonis 			cfag12864b_writebyte(0);
20070e84049SMiguel Ojeda Sandonis 	}
20170e84049SMiguel Ojeda Sandonis }
20270e84049SMiguel Ojeda Sandonis 
20370e84049SMiguel Ojeda Sandonis /*
20470e84049SMiguel Ojeda Sandonis  * Update work
20570e84049SMiguel Ojeda Sandonis  */
20670e84049SMiguel Ojeda Sandonis 
20770e84049SMiguel Ojeda Sandonis unsigned char *cfag12864b_buffer;
20870e84049SMiguel Ojeda Sandonis static unsigned char *cfag12864b_cache;
20970e84049SMiguel Ojeda Sandonis static DEFINE_MUTEX(cfag12864b_mutex);
21070e84049SMiguel Ojeda Sandonis static unsigned char cfag12864b_updating;
21170e84049SMiguel Ojeda Sandonis static void cfag12864b_update(struct work_struct *delayed_work);
21270e84049SMiguel Ojeda Sandonis static struct workqueue_struct *cfag12864b_workqueue;
21370e84049SMiguel Ojeda Sandonis static DECLARE_DELAYED_WORK(cfag12864b_work, cfag12864b_update);
21470e84049SMiguel Ojeda Sandonis 
cfag12864b_queue(void)21570e84049SMiguel Ojeda Sandonis static void cfag12864b_queue(void)
21670e84049SMiguel Ojeda Sandonis {
21770e84049SMiguel Ojeda Sandonis 	queue_delayed_work(cfag12864b_workqueue, &cfag12864b_work,
21870e84049SMiguel Ojeda Sandonis 		HZ / cfag12864b_rate);
21970e84049SMiguel Ojeda Sandonis }
22070e84049SMiguel Ojeda Sandonis 
cfag12864b_enable(void)22170e84049SMiguel Ojeda Sandonis unsigned char cfag12864b_enable(void)
22270e84049SMiguel Ojeda Sandonis {
22370e84049SMiguel Ojeda Sandonis 	unsigned char ret;
22470e84049SMiguel Ojeda Sandonis 
22570e84049SMiguel Ojeda Sandonis 	mutex_lock(&cfag12864b_mutex);
22670e84049SMiguel Ojeda Sandonis 
22770e84049SMiguel Ojeda Sandonis 	if (!cfag12864b_updating) {
22870e84049SMiguel Ojeda Sandonis 		cfag12864b_updating = 1;
22970e84049SMiguel Ojeda Sandonis 		cfag12864b_queue();
23070e84049SMiguel Ojeda Sandonis 		ret = 0;
23170e84049SMiguel Ojeda Sandonis 	} else
23270e84049SMiguel Ojeda Sandonis 		ret = 1;
23370e84049SMiguel Ojeda Sandonis 
23470e84049SMiguel Ojeda Sandonis 	mutex_unlock(&cfag12864b_mutex);
23570e84049SMiguel Ojeda Sandonis 
23670e84049SMiguel Ojeda Sandonis 	return ret;
23770e84049SMiguel Ojeda Sandonis }
23870e84049SMiguel Ojeda Sandonis 
cfag12864b_disable(void)23970e84049SMiguel Ojeda Sandonis void cfag12864b_disable(void)
24070e84049SMiguel Ojeda Sandonis {
24170e84049SMiguel Ojeda Sandonis 	mutex_lock(&cfag12864b_mutex);
24270e84049SMiguel Ojeda Sandonis 
24370e84049SMiguel Ojeda Sandonis 	if (cfag12864b_updating) {
24470e84049SMiguel Ojeda Sandonis 		cfag12864b_updating = 0;
24570e84049SMiguel Ojeda Sandonis 		cancel_delayed_work(&cfag12864b_work);
24670e84049SMiguel Ojeda Sandonis 		flush_workqueue(cfag12864b_workqueue);
24770e84049SMiguel Ojeda Sandonis 	}
24870e84049SMiguel Ojeda Sandonis 
24970e84049SMiguel Ojeda Sandonis 	mutex_unlock(&cfag12864b_mutex);
25070e84049SMiguel Ojeda Sandonis }
25170e84049SMiguel Ojeda Sandonis 
cfag12864b_isenabled(void)25270e84049SMiguel Ojeda Sandonis unsigned char cfag12864b_isenabled(void)
25370e84049SMiguel Ojeda Sandonis {
25470e84049SMiguel Ojeda Sandonis 	return cfag12864b_updating;
25570e84049SMiguel Ojeda Sandonis }
25670e84049SMiguel Ojeda Sandonis 
cfag12864b_update(struct work_struct * work)25770e84049SMiguel Ojeda Sandonis static void cfag12864b_update(struct work_struct *work)
25870e84049SMiguel Ojeda Sandonis {
25970e84049SMiguel Ojeda Sandonis 	unsigned char c;
26070e84049SMiguel Ojeda Sandonis 	unsigned short i, j, k, b;
26170e84049SMiguel Ojeda Sandonis 
26270e84049SMiguel Ojeda Sandonis 	if (memcmp(cfag12864b_cache, cfag12864b_buffer, CFAG12864B_SIZE)) {
26370e84049SMiguel Ojeda Sandonis 		for (i = 0; i < CFAG12864B_CONTROLLERS; i++) {
26470e84049SMiguel Ojeda Sandonis 			cfag12864b_controller(i);
26570e84049SMiguel Ojeda Sandonis 			cfag12864b_nop();
26670e84049SMiguel Ojeda Sandonis 			for (j = 0; j < CFAG12864B_PAGES; j++) {
26770e84049SMiguel Ojeda Sandonis 				cfag12864b_page(j);
26870e84049SMiguel Ojeda Sandonis 				cfag12864b_nop();
26970e84049SMiguel Ojeda Sandonis 				cfag12864b_address(0);
27070e84049SMiguel Ojeda Sandonis 				cfag12864b_nop();
27170e84049SMiguel Ojeda Sandonis 				for (k = 0; k < CFAG12864B_ADDRESSES; k++) {
27270e84049SMiguel Ojeda Sandonis 					for (c = 0, b = 0; b < 8; b++)
27370e84049SMiguel Ojeda Sandonis 						if (cfag12864b_buffer
27470e84049SMiguel Ojeda Sandonis 							[i * CFAG12864B_ADDRESSES / 8
27570e84049SMiguel Ojeda Sandonis 							+ k / 8 + (j * 8 + b) *
27670e84049SMiguel Ojeda Sandonis 							CFAG12864B_WIDTH / 8]
27770e84049SMiguel Ojeda Sandonis 							& bit(k % 8))
27870e84049SMiguel Ojeda Sandonis 							c |= bit(b);
27970e84049SMiguel Ojeda Sandonis 					cfag12864b_writebyte(c);
28070e84049SMiguel Ojeda Sandonis 				}
28170e84049SMiguel Ojeda Sandonis 			}
28270e84049SMiguel Ojeda Sandonis 		}
28370e84049SMiguel Ojeda Sandonis 
28470e84049SMiguel Ojeda Sandonis 		memcpy(cfag12864b_cache, cfag12864b_buffer, CFAG12864B_SIZE);
28570e84049SMiguel Ojeda Sandonis 	}
28670e84049SMiguel Ojeda Sandonis 
28770e84049SMiguel Ojeda Sandonis 	if (cfag12864b_updating)
28870e84049SMiguel Ojeda Sandonis 		cfag12864b_queue();
28970e84049SMiguel Ojeda Sandonis }
29070e84049SMiguel Ojeda Sandonis 
29170e84049SMiguel Ojeda Sandonis /*
29270e84049SMiguel Ojeda Sandonis  * cfag12864b Exported Symbols
29370e84049SMiguel Ojeda Sandonis  */
29470e84049SMiguel Ojeda Sandonis 
29570e84049SMiguel Ojeda Sandonis EXPORT_SYMBOL_GPL(cfag12864b_buffer);
29670e84049SMiguel Ojeda Sandonis EXPORT_SYMBOL_GPL(cfag12864b_getrate);
29770e84049SMiguel Ojeda Sandonis EXPORT_SYMBOL_GPL(cfag12864b_enable);
29870e84049SMiguel Ojeda Sandonis EXPORT_SYMBOL_GPL(cfag12864b_disable);
29970e84049SMiguel Ojeda Sandonis EXPORT_SYMBOL_GPL(cfag12864b_isenabled);
30070e84049SMiguel Ojeda Sandonis 
30170e84049SMiguel Ojeda Sandonis /*
30234173a4aSMiguel Ojeda  * Is the module inited?
30334173a4aSMiguel Ojeda  */
30434173a4aSMiguel Ojeda 
30534173a4aSMiguel Ojeda static unsigned char cfag12864b_inited;
cfag12864b_isinited(void)30634173a4aSMiguel Ojeda unsigned char cfag12864b_isinited(void)
30734173a4aSMiguel Ojeda {
30834173a4aSMiguel Ojeda 	return cfag12864b_inited;
30934173a4aSMiguel Ojeda }
31034173a4aSMiguel Ojeda EXPORT_SYMBOL_GPL(cfag12864b_isinited);
31134173a4aSMiguel Ojeda 
31234173a4aSMiguel Ojeda /*
31370e84049SMiguel Ojeda Sandonis  * Module Init & Exit
31470e84049SMiguel Ojeda Sandonis  */
31570e84049SMiguel Ojeda Sandonis 
cfag12864b_init(void)31670e84049SMiguel Ojeda Sandonis static int __init cfag12864b_init(void)
31770e84049SMiguel Ojeda Sandonis {
31870e84049SMiguel Ojeda Sandonis 	int ret = -EINVAL;
31970e84049SMiguel Ojeda Sandonis 
32034173a4aSMiguel Ojeda 	/* ks0108_init() must be called first */
32134173a4aSMiguel Ojeda 	if (!ks0108_isinited()) {
32234173a4aSMiguel Ojeda 		printk(KERN_ERR CFAG12864B_NAME ": ERROR: "
32334173a4aSMiguel Ojeda 			"ks0108 is not initialized\n");
32434173a4aSMiguel Ojeda 		goto none;
32534173a4aSMiguel Ojeda 	}
326b340e8a5SAkinobu Mita 	BUILD_BUG_ON(PAGE_SIZE < CFAG12864B_SIZE);
32734173a4aSMiguel Ojeda 
328b340e8a5SAkinobu Mita 	cfag12864b_buffer = (unsigned char *) get_zeroed_page(GFP_KERNEL);
32970e84049SMiguel Ojeda Sandonis 	if (cfag12864b_buffer == NULL) {
33070e84049SMiguel Ojeda Sandonis 		printk(KERN_ERR CFAG12864B_NAME ": ERROR: "
33170e84049SMiguel Ojeda Sandonis 			"can't get a free page\n");
33270e84049SMiguel Ojeda Sandonis 		ret = -ENOMEM;
33370e84049SMiguel Ojeda Sandonis 		goto none;
33470e84049SMiguel Ojeda Sandonis 	}
33570e84049SMiguel Ojeda Sandonis 
3366da2ec56SKees Cook 	cfag12864b_cache = kmalloc(CFAG12864B_SIZE,
3376da2ec56SKees Cook 				   GFP_KERNEL);
338fe58103aSMiguel Ojeda 	if (cfag12864b_cache == NULL) {
33970e84049SMiguel Ojeda Sandonis 		printk(KERN_ERR CFAG12864B_NAME ": ERROR: "
34070e84049SMiguel Ojeda Sandonis 			"can't alloc cache buffer (%i bytes)\n",
34170e84049SMiguel Ojeda Sandonis 			CFAG12864B_SIZE);
34270e84049SMiguel Ojeda Sandonis 		ret = -ENOMEM;
34370e84049SMiguel Ojeda Sandonis 		goto bufferalloced;
34470e84049SMiguel Ojeda Sandonis 	}
34570e84049SMiguel Ojeda Sandonis 
34670e84049SMiguel Ojeda Sandonis 	cfag12864b_workqueue = create_singlethread_workqueue(CFAG12864B_NAME);
34770e84049SMiguel Ojeda Sandonis 	if (cfag12864b_workqueue == NULL)
34870e84049SMiguel Ojeda Sandonis 		goto cachealloced;
34970e84049SMiguel Ojeda Sandonis 
35070e84049SMiguel Ojeda Sandonis 	cfag12864b_clear();
35170e84049SMiguel Ojeda Sandonis 	cfag12864b_on();
35270e84049SMiguel Ojeda Sandonis 
35334173a4aSMiguel Ojeda 	cfag12864b_inited = 1;
35470e84049SMiguel Ojeda Sandonis 	return 0;
35570e84049SMiguel Ojeda Sandonis 
35670e84049SMiguel Ojeda Sandonis cachealloced:
35770e84049SMiguel Ojeda Sandonis 	kfree(cfag12864b_cache);
35870e84049SMiguel Ojeda Sandonis 
35970e84049SMiguel Ojeda Sandonis bufferalloced:
36070e84049SMiguel Ojeda Sandonis 	free_page((unsigned long) cfag12864b_buffer);
36170e84049SMiguel Ojeda Sandonis 
36270e84049SMiguel Ojeda Sandonis none:
36370e84049SMiguel Ojeda Sandonis 	return ret;
36470e84049SMiguel Ojeda Sandonis }
36570e84049SMiguel Ojeda Sandonis 
cfag12864b_exit(void)36670e84049SMiguel Ojeda Sandonis static void __exit cfag12864b_exit(void)
36770e84049SMiguel Ojeda Sandonis {
36870e84049SMiguel Ojeda Sandonis 	cfag12864b_disable();
36970e84049SMiguel Ojeda Sandonis 	cfag12864b_off();
37070e84049SMiguel Ojeda Sandonis 	destroy_workqueue(cfag12864b_workqueue);
37170e84049SMiguel Ojeda Sandonis 	kfree(cfag12864b_cache);
37270e84049SMiguel Ojeda Sandonis 	free_page((unsigned long) cfag12864b_buffer);
37370e84049SMiguel Ojeda Sandonis }
37470e84049SMiguel Ojeda Sandonis 
37570e84049SMiguel Ojeda Sandonis module_init(cfag12864b_init);
37670e84049SMiguel Ojeda Sandonis module_exit(cfag12864b_exit);
37770e84049SMiguel Ojeda Sandonis 
37870e84049SMiguel Ojeda Sandonis MODULE_LICENSE("GPL v2");
379c131bd0bSMiguel Ojeda MODULE_AUTHOR("Miguel Ojeda <ojeda@kernel.org>");
38070e84049SMiguel Ojeda Sandonis MODULE_DESCRIPTION("cfag12864b LCD driver");
381