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/auxdisplay | |
| 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/auxdisplay')
| -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 |
5 files changed, 844 insertions, 0 deletions
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 | |||
