xref: /linux/drivers/auxdisplay/cfag12864b.c (revision 5a0e3ad6af8660be21ca98a971cd00f331318c05)
170e84049SMiguel Ojeda Sandonis /*
270e84049SMiguel Ojeda Sandonis  *    Filename: cfag12864b.c
370e84049SMiguel Ojeda Sandonis  *     Version: 0.1.0
470e84049SMiguel Ojeda Sandonis  * Description: cfag12864b LCD driver
570e84049SMiguel Ojeda Sandonis  *     License: GPLv2
670e84049SMiguel Ojeda Sandonis  *     Depends: ks0108
770e84049SMiguel Ojeda Sandonis  *
8450c622eSMiguel Ojeda  *      Author: Copyright (C) Miguel Ojeda Sandonis
970e84049SMiguel Ojeda Sandonis  *        Date: 2006-10-31
1070e84049SMiguel Ojeda Sandonis  *
1170e84049SMiguel Ojeda Sandonis  *  This program is free software; you can redistribute it and/or modify
1270e84049SMiguel Ojeda Sandonis  *  it under the terms of the GNU General Public License version 2 as
1370e84049SMiguel Ojeda Sandonis  *  published by the Free Software Foundation.
1470e84049SMiguel Ojeda Sandonis  *
1570e84049SMiguel Ojeda Sandonis  *  This program is distributed in the hope that it will be useful,
1670e84049SMiguel Ojeda Sandonis  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1770e84049SMiguel Ojeda Sandonis  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1870e84049SMiguel Ojeda Sandonis  *  GNU General Public License for more details.
1970e84049SMiguel Ojeda Sandonis  *
2070e84049SMiguel Ojeda Sandonis  *  You should have received a copy of the GNU General Public License
2170e84049SMiguel Ojeda Sandonis  *  along with this program; if not, write to the Free Software
2270e84049SMiguel Ojeda Sandonis  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
2370e84049SMiguel Ojeda Sandonis  *
2470e84049SMiguel Ojeda Sandonis  */
2570e84049SMiguel Ojeda Sandonis 
2670e84049SMiguel Ojeda Sandonis #include <linux/init.h>
2770e84049SMiguel Ojeda Sandonis #include <linux/module.h>
2870e84049SMiguel Ojeda Sandonis #include <linux/kernel.h>
2970e84049SMiguel Ojeda Sandonis #include <linux/fs.h>
30*5a0e3ad6STejun Heo #include <linux/slab.h>
3170e84049SMiguel Ojeda Sandonis #include <linux/cdev.h>
3270e84049SMiguel Ojeda Sandonis #include <linux/delay.h>
3370e84049SMiguel Ojeda Sandonis #include <linux/device.h>
3470e84049SMiguel Ojeda Sandonis #include <linux/jiffies.h>
3570e84049SMiguel Ojeda Sandonis #include <linux/mutex.h>
3670e84049SMiguel Ojeda Sandonis #include <linux/uaccess.h>
3770e84049SMiguel Ojeda Sandonis #include <linux/vmalloc.h>
3870e84049SMiguel Ojeda Sandonis #include <linux/workqueue.h>
3970e84049SMiguel Ojeda Sandonis #include <linux/ks0108.h>
4070e84049SMiguel Ojeda Sandonis #include <linux/cfag12864b.h>
4170e84049SMiguel Ojeda Sandonis 
4270e84049SMiguel Ojeda Sandonis 
4370e84049SMiguel Ojeda Sandonis #define CFAG12864B_NAME "cfag12864b"
4470e84049SMiguel Ojeda Sandonis 
4570e84049SMiguel Ojeda Sandonis /*
4670e84049SMiguel Ojeda Sandonis  * Module Parameters
4770e84049SMiguel Ojeda Sandonis  */
4870e84049SMiguel Ojeda Sandonis 
4970e84049SMiguel Ojeda Sandonis static unsigned int cfag12864b_rate = CONFIG_CFAG12864B_RATE;
5070e84049SMiguel Ojeda Sandonis module_param(cfag12864b_rate, uint, S_IRUGO);
5170e84049SMiguel Ojeda Sandonis MODULE_PARM_DESC(cfag12864b_rate,
5270e84049SMiguel Ojeda Sandonis 	"Refresh rate (hertzs)");
5370e84049SMiguel Ojeda Sandonis 
5470e84049SMiguel Ojeda Sandonis unsigned int cfag12864b_getrate(void)
5570e84049SMiguel Ojeda Sandonis {
5670e84049SMiguel Ojeda Sandonis 	return cfag12864b_rate;
5770e84049SMiguel Ojeda Sandonis }
5870e84049SMiguel Ojeda Sandonis 
5970e84049SMiguel Ojeda Sandonis /*
6070e84049SMiguel Ojeda Sandonis  * cfag12864b Commands
6170e84049SMiguel Ojeda Sandonis  *
6270e84049SMiguel Ojeda Sandonis  *	E = Enable signal
6370e84049SMiguel Ojeda Sandonis  *		Everytime E switch from low to high,
6470e84049SMiguel Ojeda Sandonis  *		cfag12864b/ks0108 reads the command/data.
6570e84049SMiguel Ojeda Sandonis  *
6670e84049SMiguel Ojeda Sandonis  *	CS1 = First ks0108controller.
6770e84049SMiguel Ojeda Sandonis  *		If high, the first ks0108 controller receives commands/data.
6870e84049SMiguel Ojeda Sandonis  *
6970e84049SMiguel Ojeda Sandonis  *	CS2 = Second ks0108 controller
7070e84049SMiguel Ojeda Sandonis  *		If high, the second ks0108 controller receives commands/data.
7170e84049SMiguel Ojeda Sandonis  *
7270e84049SMiguel Ojeda Sandonis  *	DI = Data/Instruction
7370e84049SMiguel Ojeda Sandonis  *		If low, cfag12864b will expect commands.
7470e84049SMiguel Ojeda Sandonis  *		If high, cfag12864b will expect data.
7570e84049SMiguel Ojeda Sandonis  *
7670e84049SMiguel Ojeda Sandonis  */
7770e84049SMiguel Ojeda Sandonis 
7870e84049SMiguel Ojeda Sandonis #define bit(n) (((unsigned char)1)<<(n))
7970e84049SMiguel Ojeda Sandonis 
8070e84049SMiguel Ojeda Sandonis #define CFAG12864B_BIT_E	(0)
8170e84049SMiguel Ojeda Sandonis #define CFAG12864B_BIT_CS1	(2)
8270e84049SMiguel Ojeda Sandonis #define CFAG12864B_BIT_CS2	(1)
8370e84049SMiguel Ojeda Sandonis #define CFAG12864B_BIT_DI	(3)
8470e84049SMiguel Ojeda Sandonis 
8570e84049SMiguel Ojeda Sandonis static unsigned char cfag12864b_state;
8670e84049SMiguel Ojeda Sandonis 
8770e84049SMiguel Ojeda Sandonis static void cfag12864b_set(void)
8870e84049SMiguel Ojeda Sandonis {
8970e84049SMiguel Ojeda Sandonis 	ks0108_writecontrol(cfag12864b_state);
9070e84049SMiguel Ojeda Sandonis }
9170e84049SMiguel Ojeda Sandonis 
9270e84049SMiguel Ojeda Sandonis static void cfag12864b_setbit(unsigned char state, unsigned char n)
9370e84049SMiguel Ojeda Sandonis {
9470e84049SMiguel Ojeda Sandonis 	if (state)
9570e84049SMiguel Ojeda Sandonis 		cfag12864b_state |= bit(n);
9670e84049SMiguel Ojeda Sandonis 	else
9770e84049SMiguel Ojeda Sandonis 		cfag12864b_state &= ~bit(n);
9870e84049SMiguel Ojeda Sandonis }
9970e84049SMiguel Ojeda Sandonis 
10070e84049SMiguel Ojeda Sandonis static void cfag12864b_e(unsigned char state)
10170e84049SMiguel Ojeda Sandonis {
10270e84049SMiguel Ojeda Sandonis 	cfag12864b_setbit(state, CFAG12864B_BIT_E);
10370e84049SMiguel Ojeda Sandonis 	cfag12864b_set();
10470e84049SMiguel Ojeda Sandonis }
10570e84049SMiguel Ojeda Sandonis 
10670e84049SMiguel Ojeda Sandonis static void cfag12864b_cs1(unsigned char state)
10770e84049SMiguel Ojeda Sandonis {
10870e84049SMiguel Ojeda Sandonis 	cfag12864b_setbit(state, CFAG12864B_BIT_CS1);
10970e84049SMiguel Ojeda Sandonis }
11070e84049SMiguel Ojeda Sandonis 
11170e84049SMiguel Ojeda Sandonis static void cfag12864b_cs2(unsigned char state)
11270e84049SMiguel Ojeda Sandonis {
11370e84049SMiguel Ojeda Sandonis 	cfag12864b_setbit(state, CFAG12864B_BIT_CS2);
11470e84049SMiguel Ojeda Sandonis }
11570e84049SMiguel Ojeda Sandonis 
11670e84049SMiguel Ojeda Sandonis static void cfag12864b_di(unsigned char state)
11770e84049SMiguel Ojeda Sandonis {
11870e84049SMiguel Ojeda Sandonis 	cfag12864b_setbit(state, CFAG12864B_BIT_DI);
11970e84049SMiguel Ojeda Sandonis }
12070e84049SMiguel Ojeda Sandonis 
12170e84049SMiguel Ojeda Sandonis static void cfag12864b_setcontrollers(unsigned char first,
12270e84049SMiguel Ojeda Sandonis 	unsigned char second)
12370e84049SMiguel Ojeda Sandonis {
12470e84049SMiguel Ojeda Sandonis 	if (first)
12570e84049SMiguel Ojeda Sandonis 		cfag12864b_cs1(0);
12670e84049SMiguel Ojeda Sandonis 	else
12770e84049SMiguel Ojeda Sandonis 		cfag12864b_cs1(1);
12870e84049SMiguel Ojeda Sandonis 
12970e84049SMiguel Ojeda Sandonis 	if (second)
13070e84049SMiguel Ojeda Sandonis 		cfag12864b_cs2(0);
13170e84049SMiguel Ojeda Sandonis 	else
13270e84049SMiguel Ojeda Sandonis 		cfag12864b_cs2(1);
13370e84049SMiguel Ojeda Sandonis }
13470e84049SMiguel Ojeda Sandonis 
13570e84049SMiguel Ojeda Sandonis static void cfag12864b_controller(unsigned char which)
13670e84049SMiguel Ojeda Sandonis {
13770e84049SMiguel Ojeda Sandonis 	if (which == 0)
13870e84049SMiguel Ojeda Sandonis 		cfag12864b_setcontrollers(1, 0);
13970e84049SMiguel Ojeda Sandonis 	else if (which == 1)
14070e84049SMiguel Ojeda Sandonis 		cfag12864b_setcontrollers(0, 1);
14170e84049SMiguel Ojeda Sandonis }
14270e84049SMiguel Ojeda Sandonis 
14370e84049SMiguel Ojeda Sandonis static void cfag12864b_displaystate(unsigned char state)
14470e84049SMiguel Ojeda Sandonis {
14570e84049SMiguel Ojeda Sandonis 	cfag12864b_di(0);
14670e84049SMiguel Ojeda Sandonis 	cfag12864b_e(1);
14770e84049SMiguel Ojeda Sandonis 	ks0108_displaystate(state);
14870e84049SMiguel Ojeda Sandonis 	cfag12864b_e(0);
14970e84049SMiguel Ojeda Sandonis }
15070e84049SMiguel Ojeda Sandonis 
15170e84049SMiguel Ojeda Sandonis static void cfag12864b_address(unsigned char address)
15270e84049SMiguel Ojeda Sandonis {
15370e84049SMiguel Ojeda Sandonis 	cfag12864b_di(0);
15470e84049SMiguel Ojeda Sandonis 	cfag12864b_e(1);
15570e84049SMiguel Ojeda Sandonis 	ks0108_address(address);
15670e84049SMiguel Ojeda Sandonis 	cfag12864b_e(0);
15770e84049SMiguel Ojeda Sandonis }
15870e84049SMiguel Ojeda Sandonis 
15970e84049SMiguel Ojeda Sandonis static void cfag12864b_page(unsigned char page)
16070e84049SMiguel Ojeda Sandonis {
16170e84049SMiguel Ojeda Sandonis 	cfag12864b_di(0);
16270e84049SMiguel Ojeda Sandonis 	cfag12864b_e(1);
16370e84049SMiguel Ojeda Sandonis 	ks0108_page(page);
16470e84049SMiguel Ojeda Sandonis 	cfag12864b_e(0);
16570e84049SMiguel Ojeda Sandonis }
16670e84049SMiguel Ojeda Sandonis 
16770e84049SMiguel Ojeda Sandonis static void cfag12864b_startline(unsigned char startline)
16870e84049SMiguel Ojeda Sandonis {
16970e84049SMiguel Ojeda Sandonis 	cfag12864b_di(0);
17070e84049SMiguel Ojeda Sandonis 	cfag12864b_e(1);
17170e84049SMiguel Ojeda Sandonis 	ks0108_startline(startline);
17270e84049SMiguel Ojeda Sandonis 	cfag12864b_e(0);
17370e84049SMiguel Ojeda Sandonis }
17470e84049SMiguel Ojeda Sandonis 
17570e84049SMiguel Ojeda Sandonis static void cfag12864b_writebyte(unsigned char byte)
17670e84049SMiguel Ojeda Sandonis {
17770e84049SMiguel Ojeda Sandonis 	cfag12864b_di(1);
17870e84049SMiguel Ojeda Sandonis 	cfag12864b_e(1);
17970e84049SMiguel Ojeda Sandonis 	ks0108_writedata(byte);
18070e84049SMiguel Ojeda Sandonis 	cfag12864b_e(0);
18170e84049SMiguel Ojeda Sandonis }
18270e84049SMiguel Ojeda Sandonis 
18370e84049SMiguel Ojeda Sandonis static void cfag12864b_nop(void)
18470e84049SMiguel Ojeda Sandonis {
18570e84049SMiguel Ojeda Sandonis 	cfag12864b_startline(0);
18670e84049SMiguel Ojeda Sandonis }
18770e84049SMiguel Ojeda Sandonis 
18870e84049SMiguel Ojeda Sandonis /*
18970e84049SMiguel Ojeda Sandonis  * cfag12864b Internal Commands
19070e84049SMiguel Ojeda Sandonis  */
19170e84049SMiguel Ojeda Sandonis 
19270e84049SMiguel Ojeda Sandonis static void cfag12864b_on(void)
19370e84049SMiguel Ojeda Sandonis {
19470e84049SMiguel Ojeda Sandonis 	cfag12864b_setcontrollers(1, 1);
19570e84049SMiguel Ojeda Sandonis 	cfag12864b_displaystate(1);
19670e84049SMiguel Ojeda Sandonis }
19770e84049SMiguel Ojeda Sandonis 
19870e84049SMiguel Ojeda Sandonis static void cfag12864b_off(void)
19970e84049SMiguel Ojeda Sandonis {
20070e84049SMiguel Ojeda Sandonis 	cfag12864b_setcontrollers(1, 1);
20170e84049SMiguel Ojeda Sandonis 	cfag12864b_displaystate(0);
20270e84049SMiguel Ojeda Sandonis }
20370e84049SMiguel Ojeda Sandonis 
20470e84049SMiguel Ojeda Sandonis static void cfag12864b_clear(void)
20570e84049SMiguel Ojeda Sandonis {
20670e84049SMiguel Ojeda Sandonis 	unsigned char i, j;
20770e84049SMiguel Ojeda Sandonis 
20870e84049SMiguel Ojeda Sandonis 	cfag12864b_setcontrollers(1, 1);
20970e84049SMiguel Ojeda Sandonis 	for (i = 0; i < CFAG12864B_PAGES; i++) {
21070e84049SMiguel Ojeda Sandonis 		cfag12864b_page(i);
21170e84049SMiguel Ojeda Sandonis 		cfag12864b_address(0);
21270e84049SMiguel Ojeda Sandonis 		for (j = 0; j < CFAG12864B_ADDRESSES; j++)
21370e84049SMiguel Ojeda Sandonis 			cfag12864b_writebyte(0);
21470e84049SMiguel Ojeda Sandonis 	}
21570e84049SMiguel Ojeda Sandonis }
21670e84049SMiguel Ojeda Sandonis 
21770e84049SMiguel Ojeda Sandonis /*
21870e84049SMiguel Ojeda Sandonis  * Update work
21970e84049SMiguel Ojeda Sandonis  */
22070e84049SMiguel Ojeda Sandonis 
22170e84049SMiguel Ojeda Sandonis unsigned char *cfag12864b_buffer;
22270e84049SMiguel Ojeda Sandonis static unsigned char *cfag12864b_cache;
22370e84049SMiguel Ojeda Sandonis static DEFINE_MUTEX(cfag12864b_mutex);
22470e84049SMiguel Ojeda Sandonis static unsigned char cfag12864b_updating;
22570e84049SMiguel Ojeda Sandonis static void cfag12864b_update(struct work_struct *delayed_work);
22670e84049SMiguel Ojeda Sandonis static struct workqueue_struct *cfag12864b_workqueue;
22770e84049SMiguel Ojeda Sandonis static DECLARE_DELAYED_WORK(cfag12864b_work, cfag12864b_update);
22870e84049SMiguel Ojeda Sandonis 
22970e84049SMiguel Ojeda Sandonis static void cfag12864b_queue(void)
23070e84049SMiguel Ojeda Sandonis {
23170e84049SMiguel Ojeda Sandonis 	queue_delayed_work(cfag12864b_workqueue, &cfag12864b_work,
23270e84049SMiguel Ojeda Sandonis 		HZ / cfag12864b_rate);
23370e84049SMiguel Ojeda Sandonis }
23470e84049SMiguel Ojeda Sandonis 
23570e84049SMiguel Ojeda Sandonis unsigned char cfag12864b_enable(void)
23670e84049SMiguel Ojeda Sandonis {
23770e84049SMiguel Ojeda Sandonis 	unsigned char ret;
23870e84049SMiguel Ojeda Sandonis 
23970e84049SMiguel Ojeda Sandonis 	mutex_lock(&cfag12864b_mutex);
24070e84049SMiguel Ojeda Sandonis 
24170e84049SMiguel Ojeda Sandonis 	if (!cfag12864b_updating) {
24270e84049SMiguel Ojeda Sandonis 		cfag12864b_updating = 1;
24370e84049SMiguel Ojeda Sandonis 		cfag12864b_queue();
24470e84049SMiguel Ojeda Sandonis 		ret = 0;
24570e84049SMiguel Ojeda Sandonis 	} else
24670e84049SMiguel Ojeda Sandonis 		ret = 1;
24770e84049SMiguel Ojeda Sandonis 
24870e84049SMiguel Ojeda Sandonis 	mutex_unlock(&cfag12864b_mutex);
24970e84049SMiguel Ojeda Sandonis 
25070e84049SMiguel Ojeda Sandonis 	return ret;
25170e84049SMiguel Ojeda Sandonis }
25270e84049SMiguel Ojeda Sandonis 
25370e84049SMiguel Ojeda Sandonis void cfag12864b_disable(void)
25470e84049SMiguel Ojeda Sandonis {
25570e84049SMiguel Ojeda Sandonis 	mutex_lock(&cfag12864b_mutex);
25670e84049SMiguel Ojeda Sandonis 
25770e84049SMiguel Ojeda Sandonis 	if (cfag12864b_updating) {
25870e84049SMiguel Ojeda Sandonis 		cfag12864b_updating = 0;
25970e84049SMiguel Ojeda Sandonis 		cancel_delayed_work(&cfag12864b_work);
26070e84049SMiguel Ojeda Sandonis 		flush_workqueue(cfag12864b_workqueue);
26170e84049SMiguel Ojeda Sandonis 	}
26270e84049SMiguel Ojeda Sandonis 
26370e84049SMiguel Ojeda Sandonis 	mutex_unlock(&cfag12864b_mutex);
26470e84049SMiguel Ojeda Sandonis }
26570e84049SMiguel Ojeda Sandonis 
26670e84049SMiguel Ojeda Sandonis unsigned char cfag12864b_isenabled(void)
26770e84049SMiguel Ojeda Sandonis {
26870e84049SMiguel Ojeda Sandonis 	return cfag12864b_updating;
26970e84049SMiguel Ojeda Sandonis }
27070e84049SMiguel Ojeda Sandonis 
27170e84049SMiguel Ojeda Sandonis static void cfag12864b_update(struct work_struct *work)
27270e84049SMiguel Ojeda Sandonis {
27370e84049SMiguel Ojeda Sandonis 	unsigned char c;
27470e84049SMiguel Ojeda Sandonis 	unsigned short i, j, k, b;
27570e84049SMiguel Ojeda Sandonis 
27670e84049SMiguel Ojeda Sandonis 	if (memcmp(cfag12864b_cache, cfag12864b_buffer, CFAG12864B_SIZE)) {
27770e84049SMiguel Ojeda Sandonis 		for (i = 0; i < CFAG12864B_CONTROLLERS; i++) {
27870e84049SMiguel Ojeda Sandonis 			cfag12864b_controller(i);
27970e84049SMiguel Ojeda Sandonis 			cfag12864b_nop();
28070e84049SMiguel Ojeda Sandonis 			for (j = 0; j < CFAG12864B_PAGES; j++) {
28170e84049SMiguel Ojeda Sandonis 				cfag12864b_page(j);
28270e84049SMiguel Ojeda Sandonis 				cfag12864b_nop();
28370e84049SMiguel Ojeda Sandonis 				cfag12864b_address(0);
28470e84049SMiguel Ojeda Sandonis 				cfag12864b_nop();
28570e84049SMiguel Ojeda Sandonis 				for (k = 0; k < CFAG12864B_ADDRESSES; k++) {
28670e84049SMiguel Ojeda Sandonis 					for (c = 0, b = 0; b < 8; b++)
28770e84049SMiguel Ojeda Sandonis 						if (cfag12864b_buffer
28870e84049SMiguel Ojeda Sandonis 							[i * CFAG12864B_ADDRESSES / 8
28970e84049SMiguel Ojeda Sandonis 							+ k / 8 + (j * 8 + b) *
29070e84049SMiguel Ojeda Sandonis 							CFAG12864B_WIDTH / 8]
29170e84049SMiguel Ojeda Sandonis 							& bit(k % 8))
29270e84049SMiguel Ojeda Sandonis 							c |= bit(b);
29370e84049SMiguel Ojeda Sandonis 					cfag12864b_writebyte(c);
29470e84049SMiguel Ojeda Sandonis 				}
29570e84049SMiguel Ojeda Sandonis 			}
29670e84049SMiguel Ojeda Sandonis 		}
29770e84049SMiguel Ojeda Sandonis 
29870e84049SMiguel Ojeda Sandonis 		memcpy(cfag12864b_cache, cfag12864b_buffer, CFAG12864B_SIZE);
29970e84049SMiguel Ojeda Sandonis 	}
30070e84049SMiguel Ojeda Sandonis 
30170e84049SMiguel Ojeda Sandonis 	if (cfag12864b_updating)
30270e84049SMiguel Ojeda Sandonis 		cfag12864b_queue();
30370e84049SMiguel Ojeda Sandonis }
30470e84049SMiguel Ojeda Sandonis 
30570e84049SMiguel Ojeda Sandonis /*
30670e84049SMiguel Ojeda Sandonis  * cfag12864b Exported Symbols
30770e84049SMiguel Ojeda Sandonis  */
30870e84049SMiguel Ojeda Sandonis 
30970e84049SMiguel Ojeda Sandonis EXPORT_SYMBOL_GPL(cfag12864b_buffer);
31070e84049SMiguel Ojeda Sandonis EXPORT_SYMBOL_GPL(cfag12864b_getrate);
31170e84049SMiguel Ojeda Sandonis EXPORT_SYMBOL_GPL(cfag12864b_enable);
31270e84049SMiguel Ojeda Sandonis EXPORT_SYMBOL_GPL(cfag12864b_disable);
31370e84049SMiguel Ojeda Sandonis EXPORT_SYMBOL_GPL(cfag12864b_isenabled);
31470e84049SMiguel Ojeda Sandonis 
31570e84049SMiguel Ojeda Sandonis /*
31634173a4aSMiguel Ojeda  * Is the module inited?
31734173a4aSMiguel Ojeda  */
31834173a4aSMiguel Ojeda 
31934173a4aSMiguel Ojeda static unsigned char cfag12864b_inited;
32034173a4aSMiguel Ojeda unsigned char cfag12864b_isinited(void)
32134173a4aSMiguel Ojeda {
32234173a4aSMiguel Ojeda 	return cfag12864b_inited;
32334173a4aSMiguel Ojeda }
32434173a4aSMiguel Ojeda EXPORT_SYMBOL_GPL(cfag12864b_isinited);
32534173a4aSMiguel Ojeda 
32634173a4aSMiguel Ojeda /*
32770e84049SMiguel Ojeda Sandonis  * Module Init & Exit
32870e84049SMiguel Ojeda Sandonis  */
32970e84049SMiguel Ojeda Sandonis 
33070e84049SMiguel Ojeda Sandonis static int __init cfag12864b_init(void)
33170e84049SMiguel Ojeda Sandonis {
33270e84049SMiguel Ojeda Sandonis 	int ret = -EINVAL;
33370e84049SMiguel Ojeda Sandonis 
33434173a4aSMiguel Ojeda 	/* ks0108_init() must be called first */
33534173a4aSMiguel Ojeda 	if (!ks0108_isinited()) {
33634173a4aSMiguel Ojeda 		printk(KERN_ERR CFAG12864B_NAME ": ERROR: "
33734173a4aSMiguel Ojeda 			"ks0108 is not initialized\n");
33834173a4aSMiguel Ojeda 		goto none;
33934173a4aSMiguel Ojeda 	}
340b340e8a5SAkinobu Mita 	BUILD_BUG_ON(PAGE_SIZE < CFAG12864B_SIZE);
34134173a4aSMiguel Ojeda 
342b340e8a5SAkinobu Mita 	cfag12864b_buffer = (unsigned char *) get_zeroed_page(GFP_KERNEL);
34370e84049SMiguel Ojeda Sandonis 	if (cfag12864b_buffer == NULL) {
34470e84049SMiguel Ojeda Sandonis 		printk(KERN_ERR CFAG12864B_NAME ": ERROR: "
34570e84049SMiguel Ojeda Sandonis 			"can't get a free page\n");
34670e84049SMiguel Ojeda Sandonis 		ret = -ENOMEM;
34770e84049SMiguel Ojeda Sandonis 		goto none;
34870e84049SMiguel Ojeda Sandonis 	}
34970e84049SMiguel Ojeda Sandonis 
35070e84049SMiguel Ojeda Sandonis 	cfag12864b_cache = kmalloc(sizeof(unsigned char) *
35170e84049SMiguel Ojeda Sandonis 		CFAG12864B_SIZE, GFP_KERNEL);
352fe58103aSMiguel Ojeda 	if (cfag12864b_cache == NULL) {
35370e84049SMiguel Ojeda Sandonis 		printk(KERN_ERR CFAG12864B_NAME ": ERROR: "
35470e84049SMiguel Ojeda Sandonis 			"can't alloc cache buffer (%i bytes)\n",
35570e84049SMiguel Ojeda Sandonis 			CFAG12864B_SIZE);
35670e84049SMiguel Ojeda Sandonis 		ret = -ENOMEM;
35770e84049SMiguel Ojeda Sandonis 		goto bufferalloced;
35870e84049SMiguel Ojeda Sandonis 	}
35970e84049SMiguel Ojeda Sandonis 
36070e84049SMiguel Ojeda Sandonis 	cfag12864b_workqueue = create_singlethread_workqueue(CFAG12864B_NAME);
36170e84049SMiguel Ojeda Sandonis 	if (cfag12864b_workqueue == NULL)
36270e84049SMiguel Ojeda Sandonis 		goto cachealloced;
36370e84049SMiguel Ojeda Sandonis 
36470e84049SMiguel Ojeda Sandonis 	cfag12864b_clear();
36570e84049SMiguel Ojeda Sandonis 	cfag12864b_on();
36670e84049SMiguel Ojeda Sandonis 
36734173a4aSMiguel Ojeda 	cfag12864b_inited = 1;
36870e84049SMiguel Ojeda Sandonis 	return 0;
36970e84049SMiguel Ojeda Sandonis 
37070e84049SMiguel Ojeda Sandonis cachealloced:
37170e84049SMiguel Ojeda Sandonis 	kfree(cfag12864b_cache);
37270e84049SMiguel Ojeda Sandonis 
37370e84049SMiguel Ojeda Sandonis bufferalloced:
37470e84049SMiguel Ojeda Sandonis 	free_page((unsigned long) cfag12864b_buffer);
37570e84049SMiguel Ojeda Sandonis 
37670e84049SMiguel Ojeda Sandonis none:
37770e84049SMiguel Ojeda Sandonis 	return ret;
37870e84049SMiguel Ojeda Sandonis }
37970e84049SMiguel Ojeda Sandonis 
38070e84049SMiguel Ojeda Sandonis static void __exit cfag12864b_exit(void)
38170e84049SMiguel Ojeda Sandonis {
38270e84049SMiguel Ojeda Sandonis 	cfag12864b_disable();
38370e84049SMiguel Ojeda Sandonis 	cfag12864b_off();
38470e84049SMiguel Ojeda Sandonis 	destroy_workqueue(cfag12864b_workqueue);
38570e84049SMiguel Ojeda Sandonis 	kfree(cfag12864b_cache);
38670e84049SMiguel Ojeda Sandonis 	free_page((unsigned long) cfag12864b_buffer);
38770e84049SMiguel Ojeda Sandonis }
38870e84049SMiguel Ojeda Sandonis 
38970e84049SMiguel Ojeda Sandonis module_init(cfag12864b_init);
39070e84049SMiguel Ojeda Sandonis module_exit(cfag12864b_exit);
39170e84049SMiguel Ojeda Sandonis 
39270e84049SMiguel Ojeda Sandonis MODULE_LICENSE("GPL v2");
393450c622eSMiguel Ojeda MODULE_AUTHOR("Miguel Ojeda Sandonis <miguel.ojeda.sandonis@gmail.com>");
39470e84049SMiguel Ojeda Sandonis MODULE_DESCRIPTION("cfag12864b LCD driver");
395