| 1 | /* $Id$ |
|---|
| 2 | * $URL$ |
|---|
| 3 | * |
|---|
| 4 | * new style driver for HD44780-based displays |
|---|
| 5 | * |
|---|
| 6 | * Copyright (C) 2003 Michael Reinelt <michael@reinelt.co.at> |
|---|
| 7 | * Copyright (C) 2004 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net> |
|---|
| 8 | * |
|---|
| 9 | * Support for I2C bus |
|---|
| 10 | * Copyright (C) 2005 Luis Correia <lfcorreia@users.sf.net> |
|---|
| 11 | * |
|---|
| 12 | * Modification for 4-Bit mode |
|---|
| 13 | * Copyright (C) 2003 Martin Hejl (martin@hejl.de) |
|---|
| 14 | * |
|---|
| 15 | * Modification for 2nd controller support |
|---|
| 16 | * Copyright (C) 2003 Jesse Brook Kovach <jkovach@wam.umd.edu> |
|---|
| 17 | * |
|---|
| 18 | * This file is part of LCD4Linux. |
|---|
| 19 | * |
|---|
| 20 | * LCD4Linux is free software; you can redistribute it and/or modify |
|---|
| 21 | * it under the terms of the GNU General Public License as published by |
|---|
| 22 | * the Free Software Foundation; either version 2, or (at your option) |
|---|
| 23 | * any later version. |
|---|
| 24 | * |
|---|
| 25 | * LCD4Linux is distributed in the hope that it will be useful, |
|---|
| 26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 28 | * GNU General Public License for more details. |
|---|
| 29 | * |
|---|
| 30 | * You should have received a copy of the GNU General Public License |
|---|
| 31 | * along with this program; if not, write to the Free Software |
|---|
| 32 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
|---|
| 33 | * |
|---|
| 34 | */ |
|---|
| 35 | |
|---|
| 36 | /* |
|---|
| 37 | * |
|---|
| 38 | * exported fuctions: |
|---|
| 39 | * |
|---|
| 40 | * struct DRIVER drv_HD44780 |
|---|
| 41 | * |
|---|
| 42 | */ |
|---|
| 43 | |
|---|
| 44 | #include "config.h" |
|---|
| 45 | |
|---|
| 46 | #include <stdlib.h> |
|---|
| 47 | #include <stdio.h> |
|---|
| 48 | #include <string.h> |
|---|
| 49 | #include <errno.h> |
|---|
| 50 | #include <unistd.h> |
|---|
| 51 | #include <termios.h> |
|---|
| 52 | #include <fcntl.h> |
|---|
| 53 | #include <sys/time.h> |
|---|
| 54 | #include <sys/ioctl.h> |
|---|
| 55 | |
|---|
| 56 | #include "debug.h" |
|---|
| 57 | #include "cfg.h" |
|---|
| 58 | #include "udelay.h" |
|---|
| 59 | #include "qprintf.h" |
|---|
| 60 | #include "timer.h" |
|---|
| 61 | #include "plugin.h" |
|---|
| 62 | #include "widget.h" |
|---|
| 63 | #include "widget_text.h" |
|---|
| 64 | #include "widget_icon.h" |
|---|
| 65 | #include "widget_bar.h" |
|---|
| 66 | #include "widget_keypad.h" |
|---|
| 67 | #include "drv.h" |
|---|
| 68 | #include "drv_generic_text.h" |
|---|
| 69 | #include "drv_generic_gpio.h" |
|---|
| 70 | |
|---|
| 71 | #ifdef WITH_PARPORT |
|---|
| 72 | #include "drv_generic_parport.h" |
|---|
| 73 | #include "drv_generic_keypad.h" |
|---|
| 74 | #include "widget_keypad.h" |
|---|
| 75 | #endif |
|---|
| 76 | |
|---|
| 77 | #ifdef WITH_I2C |
|---|
| 78 | #include "drv_generic_i2c.h" |
|---|
| 79 | #endif |
|---|
| 80 | |
|---|
| 81 | static char Name[] = "HD44780"; |
|---|
| 82 | |
|---|
| 83 | static int Bus; |
|---|
| 84 | static int Model; |
|---|
| 85 | static int Capabilities; |
|---|
| 86 | |
|---|
| 87 | |
|---|
| 88 | /* Timings */ |
|---|
| 89 | #ifdef WITH_PARPORT |
|---|
| 90 | static int T_CY, T_PW, T_AS, T_AH; |
|---|
| 91 | #endif |
|---|
| 92 | static int T_INIT1, T_INIT2, T_EXEC, T_WRCG, T_CLEAR, T_HOME, T_ONOFF; |
|---|
| 93 | #ifdef WITH_PARPORT |
|---|
| 94 | static int T_POWER, T_GPO_ST, T_GPO_PW; |
|---|
| 95 | #endif |
|---|
| 96 | |
|---|
| 97 | static int Bits = 0; |
|---|
| 98 | static int numControllers = 0; |
|---|
| 99 | static int allControllers = 0; |
|---|
| 100 | static int currController = 0; |
|---|
| 101 | |
|---|
| 102 | /* size of every single controller */ |
|---|
| 103 | static int CROWS[4]; |
|---|
| 104 | static int CCOLS[4]; |
|---|
| 105 | |
|---|
| 106 | static unsigned char SIGNAL_RW; |
|---|
| 107 | static unsigned char SIGNAL_RS; |
|---|
| 108 | static unsigned char SIGNAL_ENABLE; |
|---|
| 109 | static unsigned char SIGNAL_ENABLE2; |
|---|
| 110 | static unsigned char SIGNAL_ENABLE3; |
|---|
| 111 | static unsigned char SIGNAL_ENABLE4; |
|---|
| 112 | |
|---|
| 113 | static unsigned char SIGNAL_GPO; |
|---|
| 114 | #ifdef WITH_PARPORT |
|---|
| 115 | static unsigned char SIGNAL_BACKLIGHT; |
|---|
| 116 | static unsigned char SIGNAL_POWER; |
|---|
| 117 | #endif |
|---|
| 118 | |
|---|
| 119 | /* maximum time to wait for the busy-flag (in usec) */ |
|---|
| 120 | #define MAX_BUSYFLAG_WAIT 10000 |
|---|
| 121 | |
|---|
| 122 | /* maximum busy flag errors before falling back to busy-waiting */ |
|---|
| 123 | #define MAX_BUSYFLAG_ERRORS 20 |
|---|
| 124 | |
|---|
| 125 | /* flag for busy-waiting vs. busy flag checking */ |
|---|
| 126 | #ifdef WITH_PARPORT |
|---|
| 127 | static int UseBusy = 0; |
|---|
| 128 | #endif |
|---|
| 129 | |
|---|
| 130 | /* buffer holding the GPO state */ |
|---|
| 131 | #ifdef WITH_PARPORT |
|---|
| 132 | static unsigned char GPO = 0; |
|---|
| 133 | #endif |
|---|
| 134 | |
|---|
| 135 | typedef struct { |
|---|
| 136 | int type; |
|---|
| 137 | char *name; |
|---|
| 138 | int capabilities; |
|---|
| 139 | } MODEL; |
|---|
| 140 | |
|---|
| 141 | #define CAP_PARPORT (1<<0) |
|---|
| 142 | #define CAP_I2C (1<<1) |
|---|
| 143 | #define CAP_GPO (1<<2) |
|---|
| 144 | #define CAP_BACKLIGHT (1<<3) |
|---|
| 145 | #define CAP_BRIGHTNESS (1<<4) |
|---|
| 146 | #define CAP_BUSY4BIT (1<<5) |
|---|
| 147 | #define CAP_HD66712 (1<<6) |
|---|
| 148 | #define CAP_LCM162 (1<<7) |
|---|
| 149 | |
|---|
| 150 | #define BUS_PP CAP_PARPORT |
|---|
| 151 | #define BUS_I2C CAP_I2C |
|---|
| 152 | |
|---|
| 153 | |
|---|
| 154 | static MODEL Models[] = { |
|---|
| 155 | {0x01, "generic", CAP_PARPORT | CAP_I2C | CAP_GPO | CAP_BACKLIGHT}, |
|---|
| 156 | {0x02, "Noritake", CAP_PARPORT | CAP_I2C | CAP_GPO | CAP_BRIGHTNESS}, |
|---|
| 157 | {0x03, "Soekris", CAP_PARPORT | CAP_BUSY4BIT}, |
|---|
| 158 | {0x04, "HD66712", CAP_PARPORT | CAP_I2C | CAP_GPO | CAP_BACKLIGHT | CAP_HD66712}, |
|---|
| 159 | {0x05, "LCM-162", CAP_PARPORT | CAP_LCM162}, |
|---|
| 160 | {0xff, "Unknown", 0} |
|---|
| 161 | }; |
|---|
| 162 | |
|---|
| 163 | |
|---|
| 164 | /****************************************/ |
|---|
| 165 | /*** generic functions ***/ |
|---|
| 166 | /****************************************/ |
|---|
| 167 | |
|---|
| 168 | static int (*drv_HD_load) (const char *section); |
|---|
| 169 | static void (*drv_HD_command) (const unsigned char controller, const unsigned char cmd, const unsigned long delay); |
|---|
| 170 | static void (*drv_HD_data) (const unsigned char controller, const char *string, const int len, |
|---|
| 171 | const unsigned long delay); |
|---|
| 172 | static void (*drv_HD_stop) (void); |
|---|
| 173 | |
|---|
| 174 | |
|---|
| 175 | |
|---|
| 176 | /****************************************/ |
|---|
| 177 | /*** parport dependant functions ***/ |
|---|
| 178 | /****************************************/ |
|---|
| 179 | |
|---|
| 180 | #ifdef WITH_PARPORT |
|---|
| 181 | |
|---|
| 182 | static void drv_HD_PP_busy(const int controller) |
|---|
| 183 | { |
|---|
| 184 | static unsigned int errors = 0; |
|---|
| 185 | |
|---|
| 186 | unsigned char enable; |
|---|
| 187 | unsigned char data = 0xFF; |
|---|
| 188 | unsigned char busymask; |
|---|
| 189 | unsigned char ctrlmask; |
|---|
| 190 | unsigned int counter; |
|---|
| 191 | |
|---|
| 192 | if (Bits == 8) { |
|---|
| 193 | busymask = 0x80; |
|---|
| 194 | } else { |
|---|
| 195 | /* Since in 4-Bit mode DB0 on the parport is mapped to DB4 on the LCD |
|---|
| 196 | * (and consequently, DB3 on the partport is mapped to DB7 on the LCD) |
|---|
| 197 | * we need to listen for DB3 on the parport to go low |
|---|
| 198 | */ |
|---|
| 199 | busymask = 0x08; |
|---|
| 200 | } |
|---|
| 201 | |
|---|
| 202 | ctrlmask = 0x08; |
|---|
| 203 | while (ctrlmask > 0) { |
|---|
| 204 | |
|---|
| 205 | if (controller & ctrlmask) { |
|---|
| 206 | |
|---|
| 207 | enable = 0; |
|---|
| 208 | if (ctrlmask & 0x01) |
|---|
| 209 | enable = SIGNAL_ENABLE; |
|---|
| 210 | else if (ctrlmask & 0x02) |
|---|
| 211 | enable = SIGNAL_ENABLE2; |
|---|
| 212 | else if (ctrlmask & 0x04) |
|---|
| 213 | enable = SIGNAL_ENABLE3; |
|---|
| 214 | else if (ctrlmask & 0x08) |
|---|
| 215 | enable = SIGNAL_ENABLE4; |
|---|
| 216 | |
|---|
| 217 | /* set data-lines to input */ |
|---|
| 218 | drv_generic_parport_direction(1); |
|---|
| 219 | |
|---|
| 220 | if (Bits == 8) { |
|---|
| 221 | /* Set RW, clear RS */ |
|---|
| 222 | drv_generic_parport_control(SIGNAL_RW | SIGNAL_RS, SIGNAL_RW); |
|---|
| 223 | } else { |
|---|
| 224 | drv_generic_parport_data(SIGNAL_RW); |
|---|
| 225 | } |
|---|
| 226 | |
|---|
| 227 | /* Address set-up time */ |
|---|
| 228 | ndelay(T_AS); |
|---|
| 229 | |
|---|
| 230 | /* rise ENABLE */ |
|---|
| 231 | if (Bits == 8) { |
|---|
| 232 | drv_generic_parport_control(enable, enable); |
|---|
| 233 | } else { |
|---|
| 234 | drv_generic_parport_data(SIGNAL_RW | enable); |
|---|
| 235 | } |
|---|
| 236 | |
|---|
| 237 | counter = 0; |
|---|
| 238 | while (1) { |
|---|
| 239 | /* read the busy flag */ |
|---|
| 240 | data = drv_generic_parport_read(); |
|---|
| 241 | if ((data & busymask) == 0) { |
|---|
| 242 | errors = 0; |
|---|
| 243 | break; |
|---|
| 244 | } |
|---|
| 245 | |
|---|
| 246 | /* make sure we don't wait forever |
|---|
| 247 | * - but only check after 5 iterations |
|---|
| 248 | * that way, we won't slow down normal mode |
|---|
| 249 | * (where we don't need the timeout anyway) |
|---|
| 250 | */ |
|---|
| 251 | counter++; |
|---|
| 252 | |
|---|
| 253 | if (counter >= 5) { |
|---|
| 254 | struct timeval now, end; |
|---|
| 255 | |
|---|
| 256 | if (counter == 5) { |
|---|
| 257 | /* determine the time when the timeout has expired */ |
|---|
| 258 | gettimeofday(&end, NULL); |
|---|
| 259 | end.tv_usec += MAX_BUSYFLAG_WAIT; |
|---|
| 260 | while (end.tv_usec > 1000000) { |
|---|
| 261 | end.tv_usec -= 1000000; |
|---|
| 262 | end.tv_sec++; |
|---|
| 263 | } |
|---|
| 264 | } |
|---|
| 265 | |
|---|
| 266 | /* get the current time */ |
|---|
| 267 | gettimeofday(&now, NULL); |
|---|
| 268 | if (now.tv_sec == end.tv_sec ? now.tv_usec >= end.tv_usec : now.tv_sec >= end.tv_sec) { |
|---|
| 269 | error("%s: timeout waiting for busy flag on controller %x (0x%02x)", Name, ctrlmask, data); |
|---|
| 270 | if (++errors >= MAX_BUSYFLAG_ERRORS) { |
|---|
| 271 | error("%s: too many busy flag failures, turning off busy flag checking.", Name); |
|---|
| 272 | UseBusy = 0; |
|---|
| 273 | } |
|---|
| 274 | break; |
|---|
| 275 | } |
|---|
| 276 | } |
|---|
| 277 | } |
|---|
| 278 | |
|---|
| 279 | /* RS=low, RW=low, EN=low */ |
|---|
| 280 | if (Bits == 8) { |
|---|
| 281 | /* Lower EN */ |
|---|
| 282 | drv_generic_parport_control(enable, 0); |
|---|
| 283 | |
|---|
| 284 | /* Address hold time */ |
|---|
| 285 | ndelay(T_AH); |
|---|
| 286 | |
|---|
| 287 | drv_generic_parport_control(SIGNAL_RW | SIGNAL_RS, 0); |
|---|
| 288 | } else { |
|---|
| 289 | /* Lower EN */ |
|---|
| 290 | drv_generic_parport_data(SIGNAL_RW); |
|---|
| 291 | ndelay(T_AH); |
|---|
| 292 | drv_generic_parport_data(0); |
|---|
| 293 | } |
|---|
| 294 | |
|---|
| 295 | /* set data-lines to output */ |
|---|
| 296 | drv_generic_parport_direction(0); |
|---|
| 297 | } |
|---|
| 298 | ctrlmask >>= 1; |
|---|
| 299 | } |
|---|
| 300 | } |
|---|
| 301 | |
|---|
| 302 | |
|---|
| 303 | static void drv_HD_PP_nibble(const unsigned char controller, const unsigned char nibble) |
|---|
| 304 | { |
|---|
| 305 | unsigned char enable; |
|---|
| 306 | |
|---|
| 307 | /* enable signal: 'controller' is a bitmask */ |
|---|
| 308 | /* bit n .. send to controller #n */ |
|---|
| 309 | /* so we can send a byte to more controllers at the same time! */ |
|---|
| 310 | enable = 0; |
|---|
| 311 | if (controller & 0x01) |
|---|
| 312 | enable |= SIGNAL_ENABLE; |
|---|
| 313 | if (controller & 0x02) |
|---|
| 314 | enable |= SIGNAL_ENABLE2; |
|---|
| 315 | if (controller & 0x04) |
|---|
| 316 | enable |= SIGNAL_ENABLE3; |
|---|
| 317 | if (controller & 0x08) |
|---|
| 318 | enable |= SIGNAL_ENABLE4; |
|---|
| 319 | |
|---|
| 320 | /* clear ENABLE */ |
|---|
| 321 | /* put data on DB1..DB4 */ |
|---|
| 322 | /* nibble already contains RS bit! */ |
|---|
| 323 | drv_generic_parport_data(nibble); |
|---|
| 324 | |
|---|
| 325 | /* Address set-up time */ |
|---|
| 326 | ndelay(T_AS); |
|---|
| 327 | |
|---|
| 328 | /* rise ENABLE */ |
|---|
| 329 | drv_generic_parport_data(nibble | enable); |
|---|
| 330 | |
|---|
| 331 | /* Enable pulse width */ |
|---|
| 332 | ndelay(T_PW); |
|---|
| 333 | |
|---|
| 334 | /* lower ENABLE */ |
|---|
| 335 | drv_generic_parport_data(nibble); |
|---|
| 336 | } |
|---|
| 337 | |
|---|
| 338 | |
|---|
| 339 | static void drv_HD_PP_byte(const unsigned char controller, const unsigned char data, const unsigned char RS) |
|---|
| 340 | { |
|---|
| 341 | /* send high nibble of the data */ |
|---|
| 342 | drv_HD_PP_nibble(controller, ((data >> 4) & 0x0f) | RS); |
|---|
| 343 | |
|---|
| 344 | /* Make sure we honour T_CY */ |
|---|
| 345 | ndelay(T_CY - T_AS - T_PW); |
|---|
| 346 | |
|---|
| 347 | /* send low nibble of the data */ |
|---|
| 348 | drv_HD_PP_nibble(controller, (data & 0x0f) | RS); |
|---|
| 349 | } |
|---|
| 350 | |
|---|
| 351 | |
|---|
| 352 | static void drv_HD_PP_command(const unsigned char controller, const unsigned char cmd, const unsigned long delay) |
|---|
| 353 | { |
|---|
| 354 | unsigned char enable; |
|---|
| 355 | |
|---|
| 356 | if (UseBusy) |
|---|
| 357 | drv_HD_PP_busy(controller); |
|---|
| 358 | |
|---|
| 359 | if (Bits == 8) { |
|---|
| 360 | |
|---|
| 361 | /* enable signal: 'controller' is a bitmask */ |
|---|
| 362 | /* bit n .. send to controller #n */ |
|---|
| 363 | /* so we can send a byte to more controllers at the same time! */ |
|---|
| 364 | enable = 0; |
|---|
| 365 | if (controller & 0x01) |
|---|
| 366 | enable |= SIGNAL_ENABLE; |
|---|
| 367 | if (controller & 0x02) |
|---|
| 368 | enable |= SIGNAL_ENABLE2; |
|---|
| 369 | if (controller & 0x04) |
|---|
| 370 | enable |= SIGNAL_ENABLE3; |
|---|
| 371 | if (controller & 0x08) |
|---|
| 372 | enable |= SIGNAL_ENABLE4; |
|---|
| 373 | |
|---|
| 374 | /* put data on DB1..DB8 */ |
|---|
| 375 | drv_generic_parport_data(cmd); |
|---|
| 376 | |
|---|
| 377 | /* clear RW and RS */ |
|---|
| 378 | drv_generic_parport_control(SIGNAL_RW | SIGNAL_RS, 0); |
|---|
| 379 | |
|---|
| 380 | /* Address set-up time */ |
|---|
| 381 | ndelay(T_AS); |
|---|
| 382 | |
|---|
| 383 | /* send command */ |
|---|
| 384 | drv_generic_parport_toggle(enable, 1, T_PW); |
|---|
| 385 | |
|---|
| 386 | } else { |
|---|
| 387 | |
|---|
| 388 | drv_HD_PP_byte(controller, cmd, 0); |
|---|
| 389 | |
|---|
| 390 | } |
|---|
| 391 | |
|---|
| 392 | /* wait for command completion */ |
|---|
| 393 | if (!UseBusy) |
|---|
| 394 | udelay(delay); |
|---|
| 395 | |
|---|
| 396 | } |
|---|
| 397 | |
|---|
| 398 | |
|---|
| 399 | static void drv_HD_PP_data(const unsigned char controller, const char *string, const int len, const unsigned long delay) |
|---|
| 400 | { |
|---|
| 401 | int l = len; |
|---|
| 402 | unsigned char enable; |
|---|
| 403 | |
|---|
| 404 | /* sanity check */ |
|---|
| 405 | if (len <= 0) |
|---|
| 406 | return; |
|---|
| 407 | |
|---|
| 408 | if (Bits == 8) { |
|---|
| 409 | |
|---|
| 410 | /* enable signal: 'controller' is a bitmask */ |
|---|
| 411 | /* bit n .. send to controller #n */ |
|---|
| 412 | /* so we can send a byte to more controllers at the same time! */ |
|---|
| 413 | enable = 0; |
|---|
| 414 | if (controller & 0x01) |
|---|
| 415 | enable |= SIGNAL_ENABLE; |
|---|
| 416 | if (controller & 0x02) |
|---|
| 417 | enable |= SIGNAL_ENABLE2; |
|---|
| 418 | if (controller & 0x04) |
|---|
| 419 | enable |= SIGNAL_ENABLE3; |
|---|
| 420 | if (controller & 0x08) |
|---|
| 421 | enable |= SIGNAL_ENABLE4; |
|---|
| 422 | |
|---|
| 423 | if (!UseBusy) { |
|---|
| 424 | /* clear RW, set RS */ |
|---|
| 425 | drv_generic_parport_control(SIGNAL_RW | SIGNAL_RS, SIGNAL_RS); |
|---|
| 426 | /* Address set-up time */ |
|---|
| 427 | ndelay(T_AS); |
|---|
| 428 | } |
|---|
| 429 | |
|---|
| 430 | while (l--) { |
|---|
| 431 | |
|---|
| 432 | if (UseBusy) { |
|---|
| 433 | drv_HD_PP_busy(controller); |
|---|
| 434 | /* clear RW, set RS */ |
|---|
| 435 | drv_generic_parport_control(SIGNAL_RW | SIGNAL_RS, SIGNAL_RS); |
|---|
| 436 | /* Address set-up time */ |
|---|
| 437 | ndelay(T_AS); |
|---|
| 438 | } |
|---|
| 439 | |
|---|
| 440 | /* put data on DB1..DB8 */ |
|---|
| 441 | drv_generic_parport_data(*(string++)); |
|---|
| 442 | |
|---|
| 443 | /* send command */ |
|---|
| 444 | drv_generic_parport_toggle(enable, 1, T_PW); |
|---|
| 445 | |
|---|
| 446 | /* wait for command completion */ |
|---|
| 447 | if (!UseBusy) |
|---|
| 448 | udelay(delay); |
|---|
| 449 | } |
|---|
| 450 | |
|---|
| 451 | } else { /* 4 bit mode */ |
|---|
| 452 | |
|---|
| 453 | while (l--) { |
|---|
| 454 | if (UseBusy) |
|---|
| 455 | drv_HD_PP_busy(controller); |
|---|
| 456 | |
|---|
| 457 | /* send data with RS enabled */ |
|---|
| 458 | drv_HD_PP_byte(controller, *(string++), SIGNAL_RS); |
|---|
| 459 | |
|---|
| 460 | /* wait for command completion */ |
|---|
| 461 | if (!UseBusy) |
|---|
| 462 | udelay(delay); |
|---|
| 463 | } |
|---|
| 464 | } |
|---|
| 465 | } |
|---|
| 466 | |
|---|
| 467 | |
|---|
| 468 | static int drv_HD_PP_load(const char *section) |
|---|
| 469 | { |
|---|
| 470 | if (cfg_number(section, "Bits", 8, 4, 8, &Bits) < 0) |
|---|
| 471 | return -1; |
|---|
| 472 | |
|---|
| 473 | if (Bits != 4 && Bits != 8) { |
|---|
| 474 | error("%s: bad %s.Bits '%d' from %s, should be '4' or '8'", Name, section, Bits, cfg_source()); |
|---|
| 475 | return -1; |
|---|
| 476 | } |
|---|
| 477 | |
|---|
| 478 | /* LCM-162 only supports 8-bit-mode */ |
|---|
| 479 | if (Capabilities & CAP_LCM162 && Bits != 8) { |
|---|
| 480 | error("%s: Model '%s' does not support %d bit mode!", Name, Models[Model].name, Bits); |
|---|
| 481 | Bits = 8; |
|---|
| 482 | } |
|---|
| 483 | info("%s: using %d bit mode", Name, Bits); |
|---|
| 484 | |
|---|
| 485 | if (drv_generic_parport_open(section, Name) != 0) { |
|---|
| 486 | error("%s: could not initialize parallel port!", Name); |
|---|
| 487 | return -1; |
|---|
| 488 | } |
|---|
| 489 | |
|---|
| 490 | /* Soft-Wiring */ |
|---|
| 491 | if (Capabilities & CAP_LCM162) { |
|---|
| 492 | /* the LCM-162 is hardwired */ |
|---|
| 493 | if ((SIGNAL_RS = drv_generic_parport_hardwire_ctrl("RS", "SLCTIN")) == 0xff) |
|---|
| 494 | return -1; |
|---|
| 495 | if ((SIGNAL_RW = drv_generic_parport_hardwire_ctrl("RW", "INIT")) == 0xff) |
|---|
| 496 | return -1; |
|---|
| 497 | if ((SIGNAL_ENABLE = drv_generic_parport_hardwire_ctrl("ENABLE", "AUTOFD")) == 0xff) |
|---|
| 498 | return -1; |
|---|
| 499 | if ((SIGNAL_ENABLE2 = drv_generic_parport_hardwire_ctrl("ENABLE2", "GND")) == 0xff) |
|---|
| 500 | return -1; |
|---|
| 501 | if ((SIGNAL_ENABLE3 = drv_generic_parport_hardwire_ctrl("ENABLE3", "GND")) == 0xff) |
|---|
| 502 | return -1; |
|---|
| 503 | if ((SIGNAL_ENABLE4 = drv_generic_parport_hardwire_ctrl("ENABLE4", "GND")) == 0xff) |
|---|
| 504 | return -1; |
|---|
| 505 | if ((SIGNAL_BACKLIGHT = drv_generic_parport_hardwire_ctrl("BACKLIGHT", "GND")) == 0xff) |
|---|
| 506 | return -1; |
|---|
| 507 | if ((SIGNAL_GPO = drv_generic_parport_hardwire_ctrl("GPO", "GND")) == 0xff) |
|---|
| 508 | return -1; |
|---|
| 509 | if ((SIGNAL_POWER = drv_generic_parport_hardwire_ctrl("POWER", "GND")) == 0xff) |
|---|
| 510 | return -1; |
|---|
| 511 | } else { |
|---|
| 512 | if (Bits == 8) { |
|---|
| 513 | if ((SIGNAL_RS = drv_generic_parport_wire_ctrl("RS", "AUTOFD")) == 0xff) |
|---|
| 514 | return -1; |
|---|
| 515 | if ((SIGNAL_RW = drv_generic_parport_wire_ctrl("RW", "GND")) == 0xff) |
|---|
| 516 | return -1; |
|---|
| 517 | if ((SIGNAL_ENABLE = drv_generic_parport_wire_ctrl("ENABLE", "STROBE")) == 0xff) |
|---|
| 518 | return -1; |
|---|
| 519 | if ((SIGNAL_ENABLE2 = drv_generic_parport_wire_ctrl("ENABLE2", "GND")) == 0xff) |
|---|
| 520 | return -1; |
|---|
| 521 | if ((SIGNAL_ENABLE3 = drv_generic_parport_wire_ctrl("ENABLE3", "GND")) == 0xff) |
|---|
| 522 | return -1; |
|---|
| 523 | if ((SIGNAL_ENABLE4 = drv_generic_parport_wire_ctrl("ENABLE4", "GND")) == 0xff) |
|---|
| 524 | return -1; |
|---|
| 525 | } else { |
|---|
| 526 | if ((SIGNAL_RS = drv_generic_parport_wire_data("RS", "DB4")) == 0xff) |
|---|
| 527 | return -1; |
|---|
| 528 | if ((SIGNAL_RW = drv_generic_parport_wire_data("RW", "DB5")) == 0xff) |
|---|
| 529 | return -1; |
|---|
| 530 | if ((SIGNAL_ENABLE = drv_generic_parport_wire_data("ENABLE", "DB6")) == 0xff) |
|---|
| 531 | return -1; |
|---|
| 532 | if ((SIGNAL_ENABLE2 = drv_generic_parport_wire_data("ENABLE2", "GND")) == 0xff) |
|---|
| 533 | return -1; |
|---|
| 534 | if ((SIGNAL_ENABLE3 = drv_generic_parport_wire_data("ENABLE3", "GND")) == 0xff) |
|---|
| 535 | return -1; |
|---|
| 536 | if ((SIGNAL_ENABLE4 = drv_generic_parport_wire_data("ENABLE4", "GND")) == 0xff) |
|---|
| 537 | return -1; |
|---|
| 538 | } |
|---|
| 539 | /* backlight GPO and power are always control signals */ |
|---|
| 540 | if ((SIGNAL_BACKLIGHT = drv_generic_parport_wire_ctrl("BACKLIGHT", "GND")) == 0xff) |
|---|
| 541 | return -1; |
|---|
| 542 | if ((SIGNAL_GPO = drv_generic_parport_wire_ctrl("GPO", "GND")) == 0xff) |
|---|
| 543 | return -1; |
|---|
| 544 | if ((SIGNAL_POWER = drv_generic_parport_wire_ctrl("POWER", "GND")) == 0xff) |
|---|
| 545 | return -1; |
|---|
| 546 | } |
|---|
| 547 | |
|---|
| 548 | /* clear capabilities if corresponding signal is GND */ |
|---|
| 549 | if (SIGNAL_BACKLIGHT == 0) { |
|---|
| 550 | Capabilities &= ~CAP_BACKLIGHT; |
|---|
| 551 | } |
|---|
| 552 | if (SIGNAL_GPO == 0) { |
|---|
| 553 | Capabilities &= ~CAP_GPO; |
|---|
| 554 | } |
|---|
| 555 | |
|---|
| 556 | /* Timings */ |
|---|
| 557 | |
|---|
| 558 | /* low level communication timings [nanoseconds] |
|---|
| 559 | * as these values differ from spec to spec, |
|---|
| 560 | * we use the worst-case default values, but allow |
|---|
| 561 | * modification from the config file. |
|---|
| 562 | */ |
|---|
| 563 | T_CY = timing(Name, section, "CY", 1000, "ns"); /* Enable cycle time */ |
|---|
| 564 | T_PW = timing(Name, section, "PW", 450, "ns"); /* Enable pulse width */ |
|---|
| 565 | T_AS = timing(Name, section, "AS", 140, "ns"); /* Address setup time */ |
|---|
| 566 | T_AH = timing(Name, section, "AH", 20, "ns"); /* Address hold time */ |
|---|
| 567 | |
|---|
| 568 | /* GPO timing */ |
|---|
| 569 | if (SIGNAL_GPO != 0) { |
|---|
| 570 | T_GPO_ST = timing(Name, section, "GPO_ST", 20, "ns"); /* 74HCT573 set-up time */ |
|---|
| 571 | T_GPO_PW = timing(Name, section, "GPO_PW", 230, "ns"); /* 74HCT573 enable pulse width */ |
|---|
| 572 | } else { |
|---|
| 573 | T_GPO_ST = 0; |
|---|
| 574 | T_GPO_PW = 0; |
|---|
| 575 | } |
|---|
| 576 | |
|---|
| 577 | /* HD44780 execution timings [microseconds] |
|---|
| 578 | * as these values differ from spec to spec, |
|---|
| 579 | * we use the worst-case default values, but allow |
|---|
| 580 | * modification from the config file. |
|---|
| 581 | */ |
|---|
| 582 | T_INIT1 = timing(Name, section, "INIT1", 4100, "us"); /* first init sequence: 4.1 msec */ |
|---|
| 583 | T_INIT2 = timing(Name, section, "INIT2", 100, "us"); /* second init sequence: 100 usec */ |
|---|
| 584 | T_EXEC = timing(Name, section, "EXEC", 80, "us"); /* normal execution time */ |
|---|
| 585 | T_WRCG = timing(Name, section, "WRCG", 120, "us"); /* CG RAM Write */ |
|---|
| 586 | T_CLEAR = timing(Name, section, "CLEAR", 2250, "us"); /* Clear Display */ |
|---|
| 587 | T_HOME = timing(Name, section, "HOME", 2250, "us"); /* Return Cursor Home */ |
|---|
| 588 | T_ONOFF = timing(Name, section, "ONOFF", 2250, "us"); /* Display On/Off Control */ |
|---|
| 589 | |
|---|
| 590 | /* Power-on delay */ |
|---|
| 591 | if (SIGNAL_POWER != 0) { |
|---|
| 592 | T_POWER = timing(Name, section, "POWER", 500, "ms"); |
|---|
| 593 | } else { |
|---|
| 594 | T_POWER = 0; |
|---|
| 595 | } |
|---|
| 596 | |
|---|
| 597 | /* clear all signals */ |
|---|
| 598 | if (Bits == 8) { |
|---|
| 599 | drv_generic_parport_control(SIGNAL_RS | SIGNAL_RW | |
|---|
| 600 | SIGNAL_ENABLE | SIGNAL_ENABLE2 | SIGNAL_ENABLE3 | SIGNAL_ENABLE4 | |
|---|
| 601 | SIGNAL_BACKLIGHT | SIGNAL_GPO | SIGNAL_POWER, 0); |
|---|
| 602 | } else { |
|---|
| 603 | drv_generic_parport_control(SIGNAL_BACKLIGHT | SIGNAL_GPO | SIGNAL_POWER, 0); |
|---|
| 604 | drv_generic_parport_data(0); |
|---|
| 605 | } |
|---|
| 606 | |
|---|
| 607 | /* set direction: write */ |
|---|
| 608 | drv_generic_parport_direction(0); |
|---|
| 609 | |
|---|
| 610 | /* raise power pin */ |
|---|
| 611 | if (SIGNAL_POWER != 0) { |
|---|
| 612 | drv_generic_parport_control(SIGNAL_POWER, SIGNAL_POWER); |
|---|
| 613 | udelay(1000 * T_POWER); |
|---|
| 614 | } |
|---|
| 615 | |
|---|
| 616 | /* initialize *all* controllers */ |
|---|
| 617 | if (Bits == 8) { |
|---|
| 618 | drv_HD_PP_command(allControllers, 0x30, T_INIT1); /* 8 Bit mode, wait 4.1 ms */ |
|---|
| 619 | drv_HD_PP_command(allControllers, 0x30, T_INIT2); /* 8 Bit mode, wait 100 us */ |
|---|
| 620 | drv_HD_PP_command(allControllers, 0x38, T_EXEC); /* 8 Bit mode, 1/16 duty cycle, 5x8 font */ |
|---|
| 621 | } else { |
|---|
| 622 | drv_HD_PP_nibble(allControllers, 0x03); |
|---|
| 623 | udelay(T_INIT1); /* 4 Bit mode, wait 4.1 ms */ |
|---|
| 624 | drv_HD_PP_nibble(allControllers, 0x03); |
|---|
| 625 | udelay(T_INIT2); /* 4 Bit mode, wait 100 us */ |
|---|
| 626 | drv_HD_PP_nibble(allControllers, 0x03); |
|---|
| 627 | udelay(T_INIT1); /* 4 Bit mode, wait 4.1 ms */ |
|---|
| 628 | drv_HD_PP_nibble(allControllers, 0x02); |
|---|
| 629 | udelay(T_INIT2); /* 4 Bit mode, wait 100 us */ |
|---|
| 630 | drv_HD_PP_command(allControllers, 0x28, T_EXEC); /* 4 Bit mode, 1/16 duty cycle, 5x8 font */ |
|---|
| 631 | } |
|---|
| 632 | |
|---|
| 633 | /* maybe use busy-flag from now on */ |
|---|
| 634 | /* (we can't use the busy flag during the init sequence) */ |
|---|
| 635 | cfg_number(section, "UseBusy", 0, 0, 1, &UseBusy); |
|---|
| 636 | |
|---|
| 637 | /* make sure we don't use the busy flag with RW wired to GND */ |
|---|
| 638 | if (UseBusy && !SIGNAL_RW) { |
|---|
| 639 | error("%s: busy-flag checking is impossible with RW wired to GND!", Name); |
|---|
| 640 | UseBusy = 0; |
|---|
| 641 | } |
|---|
| 642 | |
|---|
| 643 | /* make sure the display supports busy-flag checking in 4-Bit-Mode */ |
|---|
| 644 | /* at the moment this is inly possible with Martin Hejl's gpio driver, */ |
|---|
| 645 | /* which allows to use 4 bits as input and 4 bits as output */ |
|---|
| 646 | if (UseBusy && Bits == 4 && !(Capabilities & CAP_BUSY4BIT)) { |
|---|
| 647 | error("%s: Model '%s' does not support busy-flag checking in 4 bit mode", Name, Models[Model].name); |
|---|
| 648 | UseBusy = 0; |
|---|
| 649 | } |
|---|
| 650 | |
|---|
| 651 | info("%s: %susing busy-flag checking", Name, UseBusy ? "" : "not "); |
|---|
| 652 | |
|---|
| 653 | /* The LCM-162 should really use BusyFlag checking */ |
|---|
| 654 | if (!UseBusy && (Capabilities & CAP_LCM162)) { |
|---|
| 655 | error("%s: Model '%s' should definitely use busy-flag checking!", Name, Models[Model].name); |
|---|
| 656 | } |
|---|
| 657 | |
|---|
| 658 | return 0; |
|---|
| 659 | } |
|---|
| 660 | |
|---|
| 661 | |
|---|
| 662 | static void drv_HD_PP_stop(void) |
|---|
| 663 | { |
|---|
| 664 | /* clear all signals */ |
|---|
| 665 | if (Bits == 8) { |
|---|
| 666 | drv_generic_parport_control(SIGNAL_RS | |
|---|
| 667 | SIGNAL_RW | SIGNAL_ENABLE | SIGNAL_ENABLE2 | SIGNAL_ENABLE3 | SIGNAL_ENABLE4 | |
|---|
| 668 | SIGNAL_BACKLIGHT | SIGNAL_GPO, 0); |
|---|
| 669 | } else { |
|---|
| 670 | drv_generic_parport_data(0); |
|---|
| 671 | drv_generic_parport_control(SIGNAL_BACKLIGHT | SIGNAL_GPO | SIGNAL_POWER, 0); |
|---|
| 672 | } |
|---|
| 673 | |
|---|
| 674 | drv_generic_parport_close(); |
|---|
| 675 | |
|---|
| 676 | } |
|---|
| 677 | |
|---|
| 678 | #endif |
|---|
| 679 | |
|---|
| 680 | |
|---|
| 681 | #ifdef WITH_I2C |
|---|
| 682 | |
|---|
| 683 | /****************************************/ |
|---|
| 684 | /*** i2c dependant functions ***/ |
|---|
| 685 | /****************************************/ |
|---|
| 686 | |
|---|
| 687 | /* |
|---|
| 688 | DISCLAIMER!!!! |
|---|
| 689 | |
|---|
| 690 | The following code is WORK IN PROGRESS, since it basicly 'works for us...' |
|---|
| 691 | |
|---|
| 692 | (C) 2005 Paul Kamphuis & Luis Correia |
|---|
| 693 | |
|---|
| 694 | We have removed all of the delays from this code, as the I2C bus is slow enough... |
|---|
| 695 | (maximum possible speed is 100KHz only) |
|---|
| 696 | |
|---|
| 697 | */ |
|---|
| 698 | |
|---|
| 699 | static void drv_HD_I2C_nibble(unsigned char controller, unsigned char nibble) |
|---|
| 700 | { |
|---|
| 701 | unsigned char enable; |
|---|
| 702 | unsigned char command; /* this is actually the first data byte on the PCF8574 */ |
|---|
| 703 | unsigned char data_block[2]; |
|---|
| 704 | /* enable signal: 'controller' is a bitmask */ |
|---|
| 705 | /* bit n .. send to controller #n */ |
|---|
| 706 | /* so we can send a byte to more controllers at the same time! */ |
|---|
| 707 | enable = 0; |
|---|
| 708 | if (controller & 0x01) |
|---|
| 709 | enable |= SIGNAL_ENABLE; |
|---|
| 710 | if (controller & 0x02) |
|---|
| 711 | enable |= SIGNAL_ENABLE2; |
|---|
| 712 | if (controller & 0x04) |
|---|
| 713 | enable |= SIGNAL_ENABLE3; |
|---|
| 714 | if (controller & 0x08) |
|---|
| 715 | enable |= SIGNAL_ENABLE4; |
|---|
| 716 | |
|---|
| 717 | /* |
|---|
| 718 | The new method Paul Kamphuis has concocted places the 3 needed writes to the I2C device |
|---|
| 719 | as a single operation, using the 'i2c_smbus_write_block_data' function. |
|---|
| 720 | These actual writes are performed by putting the nibble along with the 'EN' signal. |
|---|
| 721 | |
|---|
| 722 | command = first byte to be written, which contains the nibble (DB0..DB3) |
|---|
| 723 | data [0] = second byte to be written, which contains the nibble plus the EN signal |
|---|
| 724 | data [1] = third byte to be written, which contains the nibble (DB0..DB3) |
|---|
| 725 | |
|---|
| 726 | Then we write the block as a whole. |
|---|
| 727 | |
|---|
| 728 | The main advantage we see is that we do 2 less IOCTL's from our driver. |
|---|
| 729 | */ |
|---|
| 730 | |
|---|
| 731 | command = nibble; |
|---|
| 732 | data_block[0] = nibble | enable; |
|---|
| 733 | data_block[1] = nibble; |
|---|
| 734 | |
|---|
| 735 | drv_generic_i2c_command(command, data_block, 2); |
|---|
| 736 | } |
|---|
| 737 | |
|---|
| 738 | |
|---|
| 739 | static void drv_HD_I2C_byte(const unsigned char controller, const unsigned char data) |
|---|
| 740 | { |
|---|
| 741 | /* send data with RS enabled */ |
|---|
| 742 | drv_HD_I2C_nibble(controller, ((data >> 4) & 0x0f) | SIGNAL_RS); |
|---|
| 743 | drv_HD_I2C_nibble(controller, (data & 0x0f) | SIGNAL_RS); |
|---|
| 744 | } |
|---|
| 745 | |
|---|
| 746 | |
|---|
| 747 | static void drv_HD_I2C_command(const unsigned char controller, const unsigned char cmd, __attribute__ ((unused)) |
|---|
| 748 | const unsigned long delay) |
|---|
| 749 | { |
|---|
| 750 | /* send data with RS disabled */ |
|---|
| 751 | drv_HD_I2C_nibble(controller, ((cmd >> 4) & 0x0f)); |
|---|
| 752 | drv_HD_I2C_nibble(controller, ((cmd) & 0x0f)); |
|---|
| 753 | } |
|---|
| 754 | |
|---|
| 755 | static void drv_HD_I2C_data(const unsigned char controller, const char *string, const int len, __attribute__ ((unused)) |
|---|
| 756 | const unsigned long delay) |
|---|
| 757 | { |
|---|
| 758 | int l = len; |
|---|
| 759 | |
|---|
| 760 | /* sanity check */ |
|---|
| 761 | if (len <= 0) |
|---|
| 762 | return; |
|---|
| 763 | |
|---|
| 764 | while (l--) { |
|---|
| 765 | drv_HD_I2C_byte(controller, *(string++)); |
|---|
| 766 | } |
|---|
| 767 | } |
|---|
| 768 | |
|---|
| 769 | |
|---|
| 770 | static int drv_HD_I2C_load(const char *section) |
|---|
| 771 | { |
|---|
| 772 | if (cfg_number(section, "Bits", 8, 4, 8, &Bits) < 0) |
|---|
| 773 | return -1; |
|---|
| 774 | if (Bits != 4) { |
|---|
| 775 | error("%s: bad %s.Bits '%d' from %s, should be '4'", Name, section, Bits, cfg_source()); |
|---|
| 776 | return -1; |
|---|
| 777 | } |
|---|
| 778 | |
|---|
| 779 | info("%s: using %d bit mode", Name, Bits); |
|---|
| 780 | |
|---|
| 781 | if (drv_generic_i2c_open(section, Name) != 0) { |
|---|
| 782 | error("%s: could not initialize i2c attached device!", Name); |
|---|
| 783 | return -1; |
|---|
| 784 | } |
|---|
| 785 | |
|---|
| 786 | if ((SIGNAL_RS = drv_generic_i2c_wire |
|---|