diff options
author | Miguel Ojeda Sandonis <maxextreme@gmail.com> | 2007-02-10 04:44:32 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-11 13:51:24 -0500 |
commit | 70e840499aae90be1de542894062ad2899d23642 (patch) | |
tree | 4d5122672bfb03fec0823540f19c7974979483f4 /drivers | |
parent | 81d79bec348ab06cba9ae9fc03eb015b6b83703a (diff) |
[PATCH] drivers: add LCD support
Add support for auxiliary displays, the ks0108 LCD controller, the
cfag12864b LCD and adds a framebuffer device: cfag12864bfb.
- Add a "auxdisplay/" folder in "drivers/" for auxiliary display
drivers.
- Add support for the ks0108 LCD Controller as a device driver. (uses
parport interface)
- Add support for the cfag12864b LCD as a device driver. (uses ks0108
LCD Controller driver)
- Add a framebuffer device called cfag12864bfb. (uses cfag12864b LCD
driver)
- Add the usual Documentation, includes, Makefiles, Kconfigs,
MAINTAINERS, CREDITS...
- Miguel Ojeda will maintain all the stuff above.
[rdunlap@xenotime.net: workqueue fixups]
[akpm@osdl.org: kconfig fix]
Signed-off-by: Miguel Ojeda Sandonis <maxextreme@gmail.com>
Cc: Greg KH <greg@kroah.com>
Acked-by: Paulo Marques <pmarques@grupopie.com>
Cc: "Randy.Dunlap" <rdunlap@xenotime.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/Kconfig | 2 | ||||
-rw-r--r-- | drivers/Makefile | 1 | ||||
-rw-r--r-- | drivers/auxdisplay/Kconfig | 109 | ||||
-rw-r--r-- | drivers/auxdisplay/Makefile | 6 | ||||
-rw-r--r-- | drivers/auxdisplay/cfag12864b.c | 383 | ||||
-rw-r--r-- | drivers/auxdisplay/cfag12864bfb.c | 180 | ||||
-rw-r--r-- | drivers/auxdisplay/ks0108.c | 166 |
7 files changed, 847 insertions, 0 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index e7da9fa724ec..050323fd79e9 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig | |||
@@ -80,6 +80,8 @@ source "drivers/rtc/Kconfig" | |||
80 | 80 | ||
81 | source "drivers/dma/Kconfig" | 81 | source "drivers/dma/Kconfig" |
82 | 82 | ||
83 | source "drivers/auxdisplay/Kconfig" | ||
84 | |||
83 | source "drivers/kvm/Kconfig" | 85 | source "drivers/kvm/Kconfig" |
84 | 86 | ||
85 | endmenu | 87 | endmenu |
diff --git a/drivers/Makefile b/drivers/Makefile index f28dcb4ec8b3..3a718f51350e 100644 --- a/drivers/Makefile +++ b/drivers/Makefile | |||
@@ -38,6 +38,7 @@ obj-$(CONFIG_ATA) += ata/ | |||
38 | obj-$(CONFIG_FUSION) += message/ | 38 | obj-$(CONFIG_FUSION) += message/ |
39 | obj-$(CONFIG_IEEE1394) += ieee1394/ | 39 | obj-$(CONFIG_IEEE1394) += ieee1394/ |
40 | obj-y += cdrom/ | 40 | obj-y += cdrom/ |
41 | obj-y += auxdisplay/ | ||
41 | obj-$(CONFIG_MTD) += mtd/ | 42 | obj-$(CONFIG_MTD) += mtd/ |
42 | obj-$(CONFIG_SPI) += spi/ | 43 | obj-$(CONFIG_SPI) += spi/ |
43 | obj-$(CONFIG_PCCARD) += pcmcia/ | 44 | obj-$(CONFIG_PCCARD) += pcmcia/ |
diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig new file mode 100644 index 000000000000..0300e7f54cc4 --- /dev/null +++ b/drivers/auxdisplay/Kconfig | |||
@@ -0,0 +1,109 @@ | |||
1 | # | ||
2 | # For a description of the syntax of this configuration file, | ||
3 | # see Documentation/kbuild/kconfig-language.txt. | ||
4 | # | ||
5 | # Auxiliary display drivers configuration. | ||
6 | # | ||
7 | |||
8 | menu "Auxiliary Display support" | ||
9 | |||
10 | config KS0108 | ||
11 | tristate "KS0108 LCD Controller" | ||
12 | depends on PARPORT_PC | ||
13 | default n | ||
14 | ---help--- | ||
15 | If you have a LCD controlled by one or more KS0108 | ||
16 | controllers, say Y. You will need also another more specific | ||
17 | driver for your LCD. | ||
18 | |||
19 | Depends on Parallel Port support. If you say Y at | ||
20 | parport, you will be able to compile this as a module (M) | ||
21 | and built-in as well (Y). | ||
22 | |||
23 | To compile this as a module, choose M here: | ||
24 | the module will be called ks0108. | ||
25 | |||
26 | If unsure, say N. | ||
27 | |||
28 | config KS0108_PORT | ||
29 | hex "Parallel port where the LCD is connected" | ||
30 | depends on KS0108 | ||
31 | default 0x378 | ||
32 | ---help--- | ||
33 | The address of the parallel port where the LCD is connected. | ||
34 | |||
35 | The first standard parallel port address is 0x378. | ||
36 | The second standard parallel port address is 0x278. | ||
37 | The third standard parallel port address is 0x3BC. | ||
38 | |||
39 | You can specify a different address if you need. | ||
40 | |||
41 | If you don't know what I'm talking about, load the parport module, | ||
42 | and execute "dmesg" or "cat /proc/ioports". You can see there how | ||
43 | many parallel ports are present and which address each one has. | ||
44 | |||
45 | Usually you only need to use 0x378. | ||
46 | |||
47 | If you compile this as a module, you can still override this | ||
48 | using the module parameters. | ||
49 | |||
50 | config KS0108_DELAY | ||
51 | int "Delay between each control writing (microseconds)" | ||
52 | depends on KS0108 | ||
53 | default "2" | ||
54 | ---help--- | ||
55 | Amount of time the ks0108 should wait between each control write | ||
56 | to the parallel port. | ||
57 | |||
58 | If your driver seems to miss random writings, increment this. | ||
59 | |||
60 | If you don't know what I'm talking about, ignore it. | ||
61 | |||
62 | If you compile this as a module, you can still override this | ||
63 | value using the module parameters. | ||
64 | |||
65 | config CFAG12864B | ||
66 | tristate "CFAG12864B LCD" | ||
67 | depends on X86 | ||
68 | depends on FB | ||
69 | depends on KS0108 | ||
70 | default n | ||
71 | ---help--- | ||
72 | If you have a Crystalfontz 128x64 2-color LCD, cfag12864b Series, | ||
73 | say Y. You also need the ks0108 LCD Controller driver. | ||
74 | |||
75 | For help about how to wire your LCD to the parallel port, | ||
76 | check Documentation/auxdisplay/cfag12864b | ||
77 | |||
78 | Depends on the x86 arch and the framebuffer support. | ||
79 | |||
80 | The LCD framebuffer driver can be attached to a console. | ||
81 | It will work fine. However, you can't attach it to the fbdev driver | ||
82 | of the xorg server. | ||
83 | |||
84 | To compile this as a module, choose M here: | ||
85 | the modules will be called cfag12864b and cfag12864bfb. | ||
86 | |||
87 | If unsure, say N. | ||
88 | |||
89 | config CFAG12864B_RATE | ||
90 | int "Refresh rate (hertz)" | ||
91 | depends on CFAG12864B | ||
92 | default "20" | ||
93 | ---help--- | ||
94 | Refresh rate of the LCD. | ||
95 | |||
96 | As the LCD is not memory mapped, the driver has to make the work by | ||
97 | software. This means you should be careful setting this value higher. | ||
98 | If your CPUs are really slow or you feel the system is slowed down, | ||
99 | decrease the value. | ||
100 | |||
101 | Be careful modifying this value to a very high value: | ||
102 | You can freeze the computer, or the LCD maybe can't draw as fast as you | ||
103 | are requesting. | ||
104 | |||
105 | If you don't know what I'm talking about, ignore it. | ||
106 | |||
107 | If you compile this as a module, you can still override this | ||
108 | value using the module parameters. | ||
109 | endmenu | ||
diff --git a/drivers/auxdisplay/Makefile b/drivers/auxdisplay/Makefile new file mode 100644 index 000000000000..8a8936a468b9 --- /dev/null +++ b/drivers/auxdisplay/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # | ||
2 | # Makefile for the kernel auxiliary displays device drivers. | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_KS0108) += ks0108.o | ||
6 | obj-$(CONFIG_CFAG12864B) += cfag12864b.o cfag12864bfb.o | ||
diff --git a/drivers/auxdisplay/cfag12864b.c b/drivers/auxdisplay/cfag12864b.c new file mode 100644 index 000000000000..889583dfc1a6 --- /dev/null +++ b/drivers/auxdisplay/cfag12864b.c | |||
@@ -0,0 +1,383 @@ | |||
1 | /* | ||
2 | * Filename: cfag12864b.c | ||
3 | * Version: 0.1.0 | ||
4 | * Description: cfag12864b LCD driver | ||
5 | * License: GPLv2 | ||
6 | * Depends: ks0108 | ||
7 | * | ||
8 | * Author: Copyright (C) Miguel Ojeda Sandonis <maxextreme@gmail.com> | ||
9 | * Date: 2006-10-31 | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #include <linux/init.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/fs.h> | ||
30 | #include <linux/cdev.h> | ||
31 | #include <linux/delay.h> | ||
32 | #include <linux/device.h> | ||
33 | #include <linux/jiffies.h> | ||
34 | #include <linux/mutex.h> | ||
35 | #include <linux/uaccess.h> | ||
36 | #include <linux/vmalloc.h> | ||
37 | #include <linux/workqueue.h> | ||
38 | #include <linux/ks0108.h> | ||
39 | #include <linux/cfag12864b.h> | ||
40 | |||
41 | |||
42 | #define CFAG12864B_NAME "cfag12864b" | ||
43 | |||
44 | /* | ||
45 | * Module Parameters | ||
46 | */ | ||
47 | |||
48 | static unsigned int cfag12864b_rate = CONFIG_CFAG12864B_RATE; | ||
49 | module_param(cfag12864b_rate, uint, S_IRUGO); | ||
50 | MODULE_PARM_DESC(cfag12864b_rate, | ||
51 | "Refresh rate (hertzs)"); | ||
52 | |||
53 | unsigned int cfag12864b_getrate(void) | ||
54 | { | ||
55 | return cfag12864b_rate; | ||
56 | } | ||
57 | |||
58 | /* | ||
59 | * cfag12864b Commands | ||
60 | * | ||
61 | * E = Enable signal | ||
62 | * Everytime E switch from low to high, | ||
63 | * cfag12864b/ks0108 reads the command/data. | ||
64 | * | ||
65 | * CS1 = First ks0108controller. | ||
66 | * If high, the first ks0108 controller receives commands/data. | ||
67 | * | ||
68 | * CS2 = Second ks0108 controller | ||
69 | * If high, the second ks0108 controller receives commands/data. | ||
70 | * | ||
71 | * DI = Data/Instruction | ||
72 | * If low, cfag12864b will expect commands. | ||
73 | * If high, cfag12864b will expect data. | ||
74 | * | ||
75 | */ | ||
76 | |||
77 | #define bit(n) (((unsigned char)1)<<(n)) | ||
78 | |||
79 | #define CFAG12864B_BIT_E (0) | ||
80 | #define CFAG12864B_BIT_CS1 (2) | ||
81 | #define CFAG12864B_BIT_CS2 (1) | ||
82 | #define CFAG12864B_BIT_DI (3) | ||
83 | |||
84 | static unsigned char cfag12864b_state; | ||
85 | |||
86 | static void cfag12864b_set(void) | ||
87 | { | ||
88 | ks0108_writecontrol(cfag12864b_state); | ||
89 | } | ||
90 | |||
91 | static void cfag12864b_setbit(unsigned char state, unsigned char n) | ||
92 | { | ||
93 | if (state) | ||
94 | cfag12864b_state |= bit(n); | ||
95 | else | ||
96 | cfag12864b_state &= ~bit(n); | ||
97 | } | ||
98 | |||
99 | static void cfag12864b_e(unsigned char state) | ||
100 | { | ||
101 | cfag12864b_setbit(state, CFAG12864B_BIT_E); | ||
102 | cfag12864b_set(); | ||
103 | } | ||
104 | |||
105 | static void cfag12864b_cs1(unsigned char state) | ||
106 | { | ||
107 | cfag12864b_setbit(state, CFAG12864B_BIT_CS1); | ||
108 | } | ||
109 | |||
110 | static void cfag12864b_cs2(unsigned char state) | ||
111 | { | ||
112 | cfag12864b_setbit(state, CFAG12864B_BIT_CS2); | ||
113 | } | ||
114 | |||
115 | static void cfag12864b_di(unsigned char state) | ||
116 | { | ||
117 | cfag12864b_setbit(state, CFAG12864B_BIT_DI); | ||
118 | } | ||
119 | |||
120 | static void cfag12864b_setcontrollers(unsigned char first, | ||
121 | unsigned char second) | ||
122 | { | ||
123 | if (first) | ||
124 | cfag12864b_cs1(0); | ||
125 | else | ||
126 | cfag12864b_cs1(1); | ||
127 | |||
128 | if (second) | ||
129 | cfag12864b_cs2(0); | ||
130 | else | ||
131 | cfag12864b_cs2(1); | ||
132 | } | ||
133 | |||
134 | static void cfag12864b_controller(unsigned char which) | ||
135 | { | ||
136 | if (which == 0) | ||
137 | cfag12864b_setcontrollers(1, 0); | ||
138 | else if (which == 1) | ||
139 | cfag12864b_setcontrollers(0, 1); | ||
140 | } | ||
141 | |||
142 | static void cfag12864b_displaystate(unsigned char state) | ||
143 | { | ||
144 | cfag12864b_di(0); | ||
145 | cfag12864b_e(1); | ||
146 | ks0108_displaystate(state); | ||
147 | cfag12864b_e(0); | ||
148 | } | ||
149 | |||
150 | static void cfag12864b_address(unsigned char address) | ||
151 | { | ||
152 | cfag12864b_di(0); | ||
153 | cfag12864b_e(1); | ||
154 | ks0108_address(address); | ||
155 | cfag12864b_e(0); | ||
156 | } | ||
157 | |||
158 | static void cfag12864b_page(unsigned char page) | ||
159 | { | ||
160 | cfag12864b_di(0); | ||
161 | cfag12864b_e(1); | ||
162 | ks0108_page(page); | ||
163 | cfag12864b_e(0); | ||
164 | } | ||
165 | |||
166 | static void cfag12864b_startline(unsigned char startline) | ||
167 | { | ||
168 | cfag12864b_di(0); | ||
169 | cfag12864b_e(1); | ||
170 | ks0108_startline(startline); | ||
171 | cfag12864b_e(0); | ||
172 | } | ||
173 | |||
174 | static void cfag12864b_writebyte(unsigned char byte) | ||
175 | { | ||
176 | cfag12864b_di(1); | ||
177 | cfag12864b_e(1); | ||
178 | ks0108_writedata(byte); | ||
179 | cfag12864b_e(0); | ||
180 | } | ||
181 | |||
182 | static void cfag12864b_nop(void) | ||
183 | { | ||
184 | cfag12864b_startline(0); | ||
185 | } | ||
186 | |||
187 | /* | ||
188 | * cfag12864b Internal Commands | ||
189 | */ | ||
190 | |||
191 | static void cfag12864b_on(void) | ||
192 | { | ||
193 | cfag12864b_setcontrollers(1, 1); | ||
194 | cfag12864b_displaystate(1); | ||
195 | } | ||
196 | |||
197 | static void cfag12864b_off(void) | ||
198 | { | ||
199 | cfag12864b_setcontrollers(1, 1); | ||
200 | cfag12864b_displaystate(0); | ||
201 | } | ||
202 | |||
203 | static void cfag12864b_clear(void) | ||
204 | { | ||
205 | unsigned char i, j; | ||
206 | |||
207 | cfag12864b_setcontrollers(1, 1); | ||
208 | for (i = 0; i < CFAG12864B_PAGES; i++) { | ||
209 | cfag12864b_page(i); | ||
210 | cfag12864b_address(0); | ||
211 | for (j = 0; j < CFAG12864B_ADDRESSES; j++) | ||
212 | cfag12864b_writebyte(0); | ||
213 | } | ||
214 | } | ||
215 | |||
216 | /* | ||
217 | * Update work | ||
218 | */ | ||
219 | |||
220 | unsigned char *cfag12864b_buffer; | ||
221 | static unsigned char *cfag12864b_cache; | ||
222 | static DEFINE_MUTEX(cfag12864b_mutex); | ||
223 | static unsigned char cfag12864b_updating; | ||
224 | static void cfag12864b_update(struct work_struct *delayed_work); | ||
225 | static struct workqueue_struct *cfag12864b_workqueue; | ||
226 | static DECLARE_DELAYED_WORK(cfag12864b_work, cfag12864b_update); | ||
227 | |||
228 | static void cfag12864b_queue(void) | ||
229 | { | ||
230 | queue_delayed_work(cfag12864b_workqueue, &cfag12864b_work, | ||
231 | HZ / cfag12864b_rate); | ||
232 | } | ||
233 | |||
234 | unsigned char cfag12864b_enable(void) | ||
235 | { | ||
236 | unsigned char ret; | ||
237 | |||
238 | mutex_lock(&cfag12864b_mutex); | ||
239 | |||
240 | if (!cfag12864b_updating) { | ||
241 | cfag12864b_updating = 1; | ||
242 | cfag12864b_queue(); | ||
243 | ret = 0; | ||
244 | } else | ||
245 | ret = 1; | ||
246 | |||
247 | mutex_unlock(&cfag12864b_mutex); | ||
248 | |||
249 | return ret; | ||
250 | } | ||
251 | |||
252 | void cfag12864b_disable(void) | ||
253 | { | ||
254 | mutex_lock(&cfag12864b_mutex); | ||
255 | |||
256 | if (cfag12864b_updating) { | ||
257 | cfag12864b_updating = 0; | ||
258 | cancel_delayed_work(&cfag12864b_work); | ||
259 | flush_workqueue(cfag12864b_workqueue); | ||
260 | } | ||
261 | |||
262 | mutex_unlock(&cfag12864b_mutex); | ||
263 | } | ||
264 | |||
265 | unsigned char cfag12864b_isenabled(void) | ||
266 | { | ||
267 | return cfag12864b_updating; | ||
268 | } | ||
269 | |||
270 | static void cfag12864b_update(struct work_struct *work) | ||
271 | { | ||
272 | unsigned char c; | ||
273 | unsigned short i, j, k, b; | ||
274 | |||
275 | if (memcmp(cfag12864b_cache, cfag12864b_buffer, CFAG12864B_SIZE)) { | ||
276 | for (i = 0; i < CFAG12864B_CONTROLLERS; i++) { | ||
277 | cfag12864b_controller(i); | ||
278 | cfag12864b_nop(); | ||
279 | for (j = 0; j < CFAG12864B_PAGES; j++) { | ||
280 | cfag12864b_page(j); | ||
281 | cfag12864b_nop(); | ||
282 | cfag12864b_address(0); | ||
283 | cfag12864b_nop(); | ||
284 | for (k = 0; k < CFAG12864B_ADDRESSES; k++) { | ||
285 | for (c = 0, b = 0; b < 8; b++) | ||
286 | if (cfag12864b_buffer | ||
287 | [i * CFAG12864B_ADDRESSES / 8 | ||
288 | + k / 8 + (j * 8 + b) * | ||
289 | CFAG12864B_WIDTH / 8] | ||
290 | & bit(k % 8)) | ||
291 | c |= bit(b); | ||
292 | cfag12864b_writebyte(c); | ||
293 | } | ||
294 | } | ||
295 | } | ||
296 | |||
297 | memcpy(cfag12864b_cache, cfag12864b_buffer, CFAG12864B_SIZE); | ||
298 | } | ||
299 | |||
300 | if (cfag12864b_updating) | ||
301 | cfag12864b_queue(); | ||
302 | } | ||
303 | |||
304 | /* | ||
305 | * cfag12864b Exported Symbols | ||
306 | */ | ||
307 | |||
308 | EXPORT_SYMBOL_GPL(cfag12864b_buffer); | ||
309 | EXPORT_SYMBOL_GPL(cfag12864b_getrate); | ||
310 | EXPORT_SYMBOL_GPL(cfag12864b_enable); | ||
311 | EXPORT_SYMBOL_GPL(cfag12864b_disable); | ||
312 | EXPORT_SYMBOL_GPL(cfag12864b_isenabled); | ||
313 | |||
314 | /* | ||
315 | * Module Init & Exit | ||
316 | */ | ||
317 | |||
318 | static int __init cfag12864b_init(void) | ||
319 | { | ||
320 | int ret = -EINVAL; | ||
321 | |||
322 | if (PAGE_SIZE < CFAG12864B_SIZE) { | ||
323 | printk(KERN_ERR CFAG12864B_NAME ": ERROR: " | ||
324 | "page size (%i) < cfag12864b size (%i)\n", | ||
325 | (unsigned int)PAGE_SIZE, CFAG12864B_SIZE); | ||
326 | ret = -ENOMEM; | ||
327 | goto none; | ||
328 | } | ||
329 | |||
330 | cfag12864b_buffer = (unsigned char *) __get_free_page(GFP_KERNEL); | ||
331 | if (cfag12864b_buffer == NULL) { | ||
332 | printk(KERN_ERR CFAG12864B_NAME ": ERROR: " | ||
333 | "can't get a free page\n"); | ||
334 | ret = -ENOMEM; | ||
335 | goto none; | ||
336 | } | ||
337 | |||
338 | cfag12864b_cache = kmalloc(sizeof(unsigned char) * | ||
339 | CFAG12864B_SIZE, GFP_KERNEL); | ||
340 | if (cfag12864b_buffer == NULL) { | ||
341 | printk(KERN_ERR CFAG12864B_NAME ": ERROR: " | ||
342 | "can't alloc cache buffer (%i bytes)\n", | ||
343 | CFAG12864B_SIZE); | ||
344 | ret = -ENOMEM; | ||
345 | goto bufferalloced; | ||
346 | } | ||
347 | |||
348 | cfag12864b_workqueue = create_singlethread_workqueue(CFAG12864B_NAME); | ||
349 | if (cfag12864b_workqueue == NULL) | ||
350 | goto cachealloced; | ||
351 | |||
352 | memset(cfag12864b_buffer, 0, CFAG12864B_SIZE); | ||
353 | |||
354 | cfag12864b_clear(); | ||
355 | cfag12864b_on(); | ||
356 | |||
357 | return 0; | ||
358 | |||
359 | cachealloced: | ||
360 | kfree(cfag12864b_cache); | ||
361 | |||
362 | bufferalloced: | ||
363 | free_page((unsigned long) cfag12864b_buffer); | ||
364 | |||
365 | none: | ||
366 | return ret; | ||
367 | } | ||
368 | |||
369 | static void __exit cfag12864b_exit(void) | ||
370 | { | ||
371 | cfag12864b_disable(); | ||
372 | cfag12864b_off(); | ||
373 | destroy_workqueue(cfag12864b_workqueue); | ||
374 | kfree(cfag12864b_cache); | ||
375 | free_page((unsigned long) cfag12864b_buffer); | ||
376 | } | ||
377 | |||
378 | module_init(cfag12864b_init); | ||
379 | module_exit(cfag12864b_exit); | ||
380 | |||
381 | MODULE_LICENSE("GPL v2"); | ||
382 | MODULE_AUTHOR("Miguel Ojeda Sandonis <maxextreme@gmail.com>"); | ||
383 | MODULE_DESCRIPTION("cfag12864b LCD driver"); | ||
diff --git a/drivers/auxdisplay/cfag12864bfb.c b/drivers/auxdisplay/cfag12864bfb.c new file mode 100644 index 000000000000..94765e78315f --- /dev/null +++ b/drivers/auxdisplay/cfag12864bfb.c | |||
@@ -0,0 +1,180 @@ | |||
1 | /* | ||
2 | * Filename: cfag12864bfb.c | ||
3 | * Version: 0.1.0 | ||
4 | * Description: cfag12864b LCD framebuffer driver | ||
5 | * License: GPLv2 | ||
6 | * Depends: cfag12864b | ||
7 | * | ||
8 | * Author: Copyright (C) Miguel Ojeda Sandonis <maxextreme@gmail.com> | ||
9 | * Date: 2006-10-31 | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #include <linux/init.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/delay.h> | ||
30 | #include <linux/errno.h> | ||
31 | #include <linux/fb.h> | ||
32 | #include <linux/mm.h> | ||
33 | #include <linux/platform_device.h> | ||
34 | #include <linux/slab.h> | ||
35 | #include <linux/string.h> | ||
36 | #include <linux/uaccess.h> | ||
37 | #include <linux/cfag12864b.h> | ||
38 | |||
39 | #define CFAG12864BFB_NAME "cfag12864bfb" | ||
40 | |||
41 | static struct fb_fix_screeninfo cfag12864bfb_fix __initdata = { | ||
42 | .id = "cfag12864b", | ||
43 | .type = FB_TYPE_PACKED_PIXELS, | ||
44 | .visual = FB_VISUAL_MONO10, | ||
45 | .xpanstep = 0, | ||
46 | .ypanstep = 0, | ||
47 | .ywrapstep = 0, | ||
48 | .line_length = CFAG12864B_WIDTH / 8, | ||
49 | .accel = FB_ACCEL_NONE, | ||
50 | }; | ||
51 | |||
52 | static struct fb_var_screeninfo cfag12864bfb_var __initdata = { | ||
53 | .xres = CFAG12864B_WIDTH, | ||
54 | .yres = CFAG12864B_HEIGHT, | ||
55 | .xres_virtual = CFAG12864B_WIDTH, | ||
56 | .yres_virtual = CFAG12864B_HEIGHT, | ||
57 | .bits_per_pixel = 1, | ||
58 | .red = { 0, 1, 0 }, | ||
59 | .green = { 0, 1, 0 }, | ||
60 | .blue = { 0, 1, 0 }, | ||
61 | .left_margin = 0, | ||
62 | .right_margin = 0, | ||
63 | .upper_margin = 0, | ||
64 | .lower_margin = 0, | ||
65 | .vmode = FB_VMODE_NONINTERLACED, | ||
66 | }; | ||
67 | |||
68 | static int cfag12864bfb_mmap(struct fb_info *info, struct vm_area_struct *vma) | ||
69 | { | ||
70 | return vm_insert_page(vma, vma->vm_start, | ||
71 | virt_to_page(cfag12864b_buffer)); | ||
72 | } | ||
73 | |||
74 | static struct fb_ops cfag12864bfb_ops = { | ||
75 | .owner = THIS_MODULE, | ||
76 | .fb_fillrect = cfb_fillrect, | ||
77 | .fb_copyarea = cfb_copyarea, | ||
78 | .fb_imageblit = cfb_imageblit, | ||
79 | .fb_mmap = cfag12864bfb_mmap, | ||
80 | }; | ||
81 | |||
82 | static int __init cfag12864bfb_probe(struct platform_device *device) | ||
83 | { | ||
84 | int ret = -EINVAL; | ||
85 | struct fb_info *info = framebuffer_alloc(0, &device->dev); | ||
86 | |||
87 | if (!info) | ||
88 | goto none; | ||
89 | |||
90 | info->screen_base = (char __iomem *) cfag12864b_buffer; | ||
91 | info->screen_size = CFAG12864B_SIZE; | ||
92 | info->fbops = &cfag12864bfb_ops; | ||
93 | info->fix = cfag12864bfb_fix; | ||
94 | info->var = cfag12864bfb_var; | ||
95 | info->pseudo_palette = NULL; | ||
96 | info->par = NULL; | ||
97 | info->flags = FBINFO_FLAG_DEFAULT; | ||
98 | |||
99 | if (register_framebuffer(info) < 0) | ||
100 | goto fballoced; | ||
101 | |||
102 | platform_set_drvdata(device, info); | ||
103 | |||
104 | printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, | ||
105 | info->fix.id); | ||
106 | |||
107 | return 0; | ||
108 | |||
109 | fballoced: | ||
110 | framebuffer_release(info); | ||
111 | |||
112 | none: | ||
113 | return ret; | ||
114 | } | ||
115 | |||
116 | static int cfag12864bfb_remove(struct platform_device *device) | ||
117 | { | ||
118 | struct fb_info *info = platform_get_drvdata(device); | ||
119 | |||
120 | if (info) { | ||
121 | unregister_framebuffer(info); | ||
122 | framebuffer_release(info); | ||
123 | } | ||
124 | |||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static struct platform_driver cfag12864bfb_driver = { | ||
129 | .probe = cfag12864bfb_probe, | ||
130 | .remove = cfag12864bfb_remove, | ||
131 | .driver = { | ||
132 | .name = CFAG12864BFB_NAME, | ||
133 | }, | ||
134 | }; | ||
135 | |||
136 | static struct platform_device *cfag12864bfb_device; | ||
137 | |||
138 | static int __init cfag12864bfb_init(void) | ||
139 | { | ||
140 | int ret; | ||
141 | |||
142 | if (cfag12864b_enable()) { | ||
143 | printk(KERN_ERR CFAG12864BFB_NAME ": ERROR: " | ||
144 | "can't enable cfag12864b refreshing (being used)\n"); | ||
145 | return -ENODEV; | ||
146 | } | ||
147 | |||
148 | ret = platform_driver_register(&cfag12864bfb_driver); | ||
149 | |||
150 | if (!ret) { | ||
151 | cfag12864bfb_device = | ||
152 | platform_device_alloc(CFAG12864BFB_NAME, 0); | ||
153 | |||
154 | if (cfag12864bfb_device) | ||
155 | ret = platform_device_add(cfag12864bfb_device); | ||
156 | else | ||
157 | ret = -ENOMEM; | ||
158 | |||
159 | if (ret) { | ||
160 | platform_device_put(cfag12864bfb_device); | ||
161 | platform_driver_unregister(&cfag12864bfb_driver); | ||
162 | } | ||
163 | } | ||
164 | |||
165 | return ret; | ||
166 | } | ||
167 | |||
168 | static void __exit cfag12864bfb_exit(void) | ||
169 | { | ||
170 | platform_device_unregister(cfag12864bfb_device); | ||
171 | platform_driver_unregister(&cfag12864bfb_driver); | ||
172 | cfag12864b_disable(); | ||
173 | } | ||
174 | |||
175 | module_init(cfag12864bfb_init); | ||
176 | module_exit(cfag12864bfb_exit); | ||
177 | |||
178 | MODULE_LICENSE("GPL v2"); | ||
179 | MODULE_AUTHOR("Miguel Ojeda Sandonis <maxextreme@gmail.com>"); | ||
180 | MODULE_DESCRIPTION("cfag12864b LCD framebuffer driver"); | ||
diff --git a/drivers/auxdisplay/ks0108.c b/drivers/auxdisplay/ks0108.c new file mode 100644 index 000000000000..a637575b9106 --- /dev/null +++ b/drivers/auxdisplay/ks0108.c | |||
@@ -0,0 +1,166 @@ | |||
1 | /* | ||
2 | * Filename: ks0108.c | ||
3 | * Version: 0.1.0 | ||
4 | * Description: ks0108 LCD Controller driver | ||
5 | * License: GPLv2 | ||
6 | * Depends: parport | ||
7 | * | ||
8 | * Author: Copyright (C) Miguel Ojeda Sandonis <maxextreme@gmail.com> | ||
9 | * Date: 2006-10-31 | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #include <linux/init.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/delay.h> | ||
30 | #include <linux/fs.h> | ||
31 | #include <linux/io.h> | ||
32 | #include <linux/parport.h> | ||
33 | #include <linux/uaccess.h> | ||
34 | #include <linux/ks0108.h> | ||
35 | |||
36 | #define KS0108_NAME "ks0108" | ||
37 | |||
38 | /* | ||
39 | * Module Parameters | ||
40 | */ | ||
41 | |||
42 | static unsigned int ks0108_port = CONFIG_KS0108_PORT; | ||
43 | module_param(ks0108_port, uint, S_IRUGO); | ||
44 | MODULE_PARM_DESC(ks0108_port, "Parallel port where the LCD is connected"); | ||
45 | |||
46 | static unsigned int ks0108_delay = CONFIG_KS0108_DELAY; | ||
47 | module_param(ks0108_delay, uint, S_IRUGO); | ||
48 | MODULE_PARM_DESC(ks0108_delay, "Delay between each control writing (microseconds)"); | ||
49 | |||
50 | /* | ||
51 | * Device | ||
52 | */ | ||
53 | |||
54 | static struct parport *ks0108_parport; | ||
55 | static struct pardevice *ks0108_pardevice; | ||
56 | |||
57 | /* | ||
58 | * ks0108 Exported Commands (don't lock) | ||
59 | * | ||
60 | * You _should_ lock in the top driver: This functions _should not_ | ||
61 | * get race conditions in any way. Locking for each byte here would be | ||
62 | * so slow and useless. | ||
63 | * | ||
64 | * There are not bit definitions because they are not flags, | ||
65 | * just arbitrary combinations defined by the documentation for each | ||
66 | * function in the ks0108 LCD controller. If you want to know what means | ||
67 | * a specific combination, look at the function's name. | ||
68 | * | ||
69 | * The ks0108_writecontrol bits need to be reverted ^(0,1,3) because | ||
70 | * the parallel port also revert them using a "not" logic gate. | ||
71 | */ | ||
72 | |||
73 | #define bit(n) (((unsigned char)1)<<(n)) | ||
74 | |||
75 | void ks0108_writedata(unsigned char byte) | ||
76 | { | ||
77 | parport_write_data(ks0108_parport, byte); | ||
78 | } | ||
79 | |||
80 | void ks0108_writecontrol(unsigned char byte) | ||
81 | { | ||
82 | udelay(ks0108_delay); | ||
83 | parport_write_control(ks0108_parport, byte ^ (bit(0) | bit(1) | bit(3))); | ||
84 | } | ||
85 | |||
86 | void ks0108_displaystate(unsigned char state) | ||
87 | { | ||
88 | ks0108_writedata((state ? bit(0) : 0) | bit(1) | bit(2) | bit(3) | bit(4) | bit(5)); | ||
89 | } | ||
90 | |||
91 | void ks0108_startline(unsigned char startline) | ||
92 | { | ||
93 | ks0108_writedata(min(startline,(unsigned char)63) | bit(6) | bit(7)); | ||
94 | } | ||
95 | |||
96 | void ks0108_address(unsigned char address) | ||
97 | { | ||
98 | ks0108_writedata(min(address,(unsigned char)63) | bit(6)); | ||
99 | } | ||
100 | |||
101 | void ks0108_page(unsigned char page) | ||
102 | { | ||
103 | ks0108_writedata(min(page,(unsigned char)7) | bit(3) | bit(4) | bit(5) | bit(7)); | ||
104 | } | ||
105 | |||
106 | EXPORT_SYMBOL_GPL(ks0108_writedata); | ||
107 | EXPORT_SYMBOL_GPL(ks0108_writecontrol); | ||
108 | EXPORT_SYMBOL_GPL(ks0108_displaystate); | ||
109 | EXPORT_SYMBOL_GPL(ks0108_startline); | ||
110 | EXPORT_SYMBOL_GPL(ks0108_address); | ||
111 | EXPORT_SYMBOL_GPL(ks0108_page); | ||
112 | |||
113 | /* | ||
114 | * Module Init & Exit | ||
115 | */ | ||
116 | |||
117 | static int __init ks0108_init(void) | ||
118 | { | ||
119 | int result; | ||
120 | int ret = -EINVAL; | ||
121 | |||
122 | ks0108_parport = parport_find_base(ks0108_port); | ||
123 | if (ks0108_parport == NULL) { | ||
124 | printk(KERN_ERR KS0108_NAME ": ERROR: " | ||
125 | "parport didn't find %i port\n", ks0108_port); | ||
126 | goto none; | ||
127 | } | ||
128 | |||
129 | ks0108_pardevice = parport_register_device(ks0108_parport, KS0108_NAME, | ||
130 | NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); | ||
131 | if (ks0108_pardevice == NULL) { | ||
132 | printk(KERN_ERR KS0108_NAME ": ERROR: " | ||
133 | "parport didn't register new device\n"); | ||
134 | goto none; | ||
135 | } | ||
136 | |||
137 | result = parport_claim(ks0108_pardevice); | ||
138 | if (result != 0) { | ||
139 | printk(KERN_ERR KS0108_NAME ": ERROR: " | ||
140 | "can't claim %i parport, maybe in use\n", ks0108_port); | ||
141 | ret = result; | ||
142 | goto registered; | ||
143 | } | ||
144 | |||
145 | return 0; | ||
146 | |||
147 | registered: | ||
148 | parport_unregister_device(ks0108_pardevice); | ||
149 | |||
150 | none: | ||
151 | return ret; | ||
152 | } | ||
153 | |||
154 | static void __exit ks0108_exit(void) | ||
155 | { | ||
156 | parport_release(ks0108_pardevice); | ||
157 | parport_unregister_device(ks0108_pardevice); | ||
158 | } | ||
159 | |||
160 | module_init(ks0108_init); | ||
161 | module_exit(ks0108_exit); | ||
162 | |||
163 | MODULE_LICENSE("GPL v2"); | ||
164 | MODULE_AUTHOR("Miguel Ojeda Sandonis <maxextreme@gmail.com>"); | ||
165 | MODULE_DESCRIPTION("ks0108 LCD Controller driver"); | ||
166 | |||