root/branches/volker_dev/drv_LPH7508.c

Revision 771, 11.5 kB (checked in by michael, 23 months ago)

lots of compiler warnings removed, C++-style comments removed, changed struc initialisation from 'field:value' to '.field=value'

  • Property svn:keywords set to Id URL Rev
Line 
1/* $Id$
2 * $URL$
3 *
4 * driver for Pollin LPH7508
5 *
6 * Copyright (C) 2005 Michael Reinelt <reinelt@eunet.at>
7 * Copyright (C) 2005 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
8 *
9 * This file is part of LCD4Linux.
10 *
11 * LCD4Linux is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2, or (at your option)
14 * any later version.
15 *
16 * LCD4Linux is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28 *
29 * exported fuctions:
30 *
31 * struct DRIVER drv_LPH7508
32 *
33 */
34
35#include "config.h"
36
37#include <stdlib.h>
38#include <stdio.h>
39#include <string.h>
40#include <errno.h>
41#include <unistd.h>
42#include <termios.h>
43#include <fcntl.h>
44#include <sys/time.h>
45
46#include "debug.h"
47#include "cfg.h"
48#include "qprintf.h"
49#include "udelay.h"
50#include "plugin.h"
51#include "drv.h"
52#include "drv_generic_graphic.h"
53#include "drv_generic_gpio.h"
54#include "drv_generic_parport.h"
55
56#ifdef WITH_DMALLOC
57#include <dmalloc.h>
58#endif
59
60static char Name[] = "LPH7508";
61
62
63static unsigned char SIGNAL_RES;
64static unsigned char SIGNAL_CS1;
65static unsigned char SIGNAL_RW;
66static unsigned char SIGNAL_A0;
67
68static int PAGES, SROWS, SCOLS;
69
70static unsigned char *Buffer1, *Buffer2;
71
72
73
74/****************************************/
75/***  hardware dependant functions    ***/
76/****************************************/
77
78static void drv_L7_write_ctrl(const unsigned char data)
79{
80    /* put data on DB1..DB8 */
81    drv_generic_parport_data(data);
82
83    /* CS1 = high, RW = low, A0 = low */
84    drv_generic_parport_control(SIGNAL_CS1 | SIGNAL_RW | SIGNAL_A0, SIGNAL_CS1);
85
86    /* Address Setup Time = 10 ns */
87    /* Data Setup Time = 20 ns */
88    ndelay(20);
89
90    /* Control L Pulse Width = 22 ns */
91    drv_generic_parport_toggle(SIGNAL_CS1, 0, 22);
92
93    /* Address & Data Hold Time = 10 ns */
94    ndelay(10);
95}
96
97
98static void drv_L7_write_data(const unsigned char data)
99{
100    /* put data on DB1..DB8 */
101    drv_generic_parport_data(data);
102
103    /* CS1 = high, RW = low, A0 = high */
104    drv_generic_parport_control(SIGNAL_CS1 | SIGNAL_RW | SIGNAL_A0, SIGNAL_CS1 | SIGNAL_A0);
105
106    /* Address Setup Time = 10 ns */
107    /* Data Setup Time = 20 ns */
108    ndelay(20);
109
110    /* Control L Pulse Width = 22 ns */
111    drv_generic_parport_toggle(SIGNAL_CS1, 0, 22);
112
113    /* Address & Data Hold Time = 10 ns */
114    ndelay(10);
115}
116
117
118static void drv_L7_page(int page)
119{
120    static int cp = -1;
121
122    if (page != cp) {
123  cp = page;
124  drv_L7_write_ctrl(0xb0 | cp);
125    }
126
127}
128
129
130static void drv_L7_put(int col, int val)
131{
132    static int cc = -1;
133
134    /* select page 8 */
135    drv_L7_page(8);
136
137    if (col != cc) {
138  cc = col;
139  drv_L7_write_ctrl(0x00 | (cc & 0x0f));
140  drv_L7_write_ctrl(0x10 | (cc >> 4));
141    }
142    drv_L7_write_data(val);
143    cc++;
144}
145
146
147static void drv_L7_clear(void)
148{
149    int p, c;
150
151    for (p = 0; p < PAGES; p++) {
152  /* select page */
153  drv_L7_page(p);
154  /* select column address */
155  drv_L7_write_ctrl(0x00);
156  drv_L7_write_ctrl(0x10);
157  for (c = 0; c < SCOLS; c++) {
158      drv_L7_write_data(0);
159  }
160    }
161}
162
163
164static void drv_L7_blit(const int row, const int col, const int height, const int width)
165{
166    int r, p, c, a;
167    unsigned char m;
168
169    /* transfer layout to display framebuffer */
170    for (r = row; r < row + height; r++) {
171  /* do not process extra row for symbols */
172  if (r >= SROWS - 1)
173      break;
174  /* page */
175  p = r / 8;
176  for (c = col; c < col + width; c++) {
177      if (c >= SCOLS)
178    break;
179      /* RAM address */
180      a = p * SCOLS + c;
181      /* bit mask */
182      m = 1 << (r % 8);
183      if (drv_generic_graphic_black(r, c)) {
184    /* set bit */
185    Buffer1[a] |= m;
186      } else {
187    /* clear bit */
188    Buffer1[a] &= ~m;
189      }
190  }
191    }
192
193    /* process display framebuffer */
194    for (p = row / 8; p <= (row + height) / 8; p++) {
195  int i, j, a, e;
196  if (p >= PAGES)
197      break;
198  for (i = col; i < col + width; i++) {
199      if (i >= SCOLS)
200    break;
201      a = p * SCOLS + i;
202      if (Buffer1[a] == Buffer2[a])
203    continue;
204      for (j = i, e = 0; i < col + width; i++) {
205    a = p * SCOLS + i;
206    if (Buffer1[a] == Buffer2[a]) {
207        if (++e > 2)
208      break;
209    } else {
210        e = 0;
211    }
212      }
213      /* select page */
214      drv_L7_page(p);
215      /* column address */
216      /* first column address = 32 */
217      drv_L7_write_ctrl(0x00 | ((j + 32) & 0x0f));
218      drv_L7_write_ctrl(0x10 | ((j + 32) >> 4));
219      /* data */
220      for (j = j; j <= i - e; j++) {
221    a = p * SCOLS + j;
222    drv_L7_write_data(Buffer1[a]);
223    Buffer2[a] = Buffer1[a];
224      }
225  }
226    }
227}
228
229
230static int drv_L7_GPO(const int num, const int val)
231{
232    int v = 0;
233
234    switch (num) {
235    case 0:
236  /* battery symbol */
237  v = (val > 0) ? 1 : 0;
238  drv_L7_put(32, v);
239  break;
240    case 1:
241  /* battery level */
242  if (val < 0) {
243      v = 0;
244      drv_L7_put(46, v);
245      drv_L7_put(47, v);
246      drv_L7_put(48, v);
247      drv_L7_put(49, v);
248  } else {
249      v = val & 0x0f;
250      drv_L7_put(46, (v & 1) ? 1 : 0);
251      drv_L7_put(47, (v & 2) ? 1 : 0);
252      drv_L7_put(48, (v & 4) ? 1 : 0);
253      drv_L7_put(49, (v & 8) ? 1 : 0);
254  }
255  break;
256    case 2:
257  /* earpiece */
258  v = (val > 0) ? 1 : 0;
259  drv_L7_put(59, v);
260  break;
261    case 3:
262  /* triangle */
263  v = (val > 0) ? 1 : 0;
264  drv_L7_put(69, v);
265  Buffer1[8 * SCOLS + 69 - 32] = (val > 0);
266  break;
267    case 4:
268  /* head */
269  v = (val > 0) ? 1 : 0;
270  drv_L7_put(83, v);
271  Buffer1[8 * SCOLS + 83 - 32] = (val > 0);
272  break;
273    case 5:
274  /* message */
275  v = (val > 0) ? 1 : 0;
276  drv_L7_put(98, v);
277  Buffer1[8 * SCOLS + 98 - 32] = (val > 0);
278  break;
279    case 6:
280  /* antenna */
281  v = (val > 0) ? 1 : 0;
282  drv_L7_put(117, v);
283  Buffer1[8 * SCOLS + 117 - 32] = (val > 0);
284  break;
285    case 7:
286  /* signal level */
287  if (val < 0) {
288      v = 0;
289      drv_L7_put(112, v);
290      drv_L7_put(113, v);
291      drv_L7_put(114, v);
292      drv_L7_put(115, v);
293  } else {
294      v = val & 0x0f;
295      drv_L7_put(112, (v & 1) ? 1 : 0);
296      drv_L7_put(113, (v & 2) ? 1 : 0);
297      drv_L7_put(114, (v & 4) ? 1 : 0);
298      drv_L7_put(115, (v & 8) ? 1 : 0);
299  }
300  break;
301    }
302
303    return v;
304}
305
306
307static int drv_L7_contrast(int contrast)
308{
309    if (contrast < 0)
310  contrast = 0;
311    if (contrast > 31)
312  contrast = 31;
313
314    drv_L7_write_ctrl(0x80 | contrast);
315
316    return contrast;
317}
318
319
320static int drv_L7_start(const char *section)
321{
322    char *s;
323    int contrast;
324
325    /* fixed size */
326    DROWS = 64;
327    DCOLS = 100;
328    GPOS = 8;
329
330    /* SED1560 display RAM layout */
331    PAGES = 8;
332    SROWS = 64;
333    SCOLS = 166;
334
335    s = cfg_get(section, "Font", "6x8");
336    if (s == NULL || *s == '\0') {
337  error("%s: no '%s.Font' entry from %s", Name, section, cfg_source());
338  return -1;
339    }
340
341    XRES = -1;
342    YRES = -1;
343    if (sscanf(s, "%dx%d", &XRES, &YRES) != 2 || XRES < 1 || YRES < 1) {
344  error("%s: bad Font '%s' from %s", Name, s, cfg_source());
345  return -1;
346    }
347
348    /* Fixme: provider other fonts someday... */
349    if (XRES != 6 && YRES != 8) {
350  error("%s: bad Font '%s' from %s (only 6x8 at the moment)", Name, s, cfg_source());
351  return -1;
352    }
353
354    /* provide room for page 8 (symbols) */
355    Buffer1 = malloc(PAGES * SCOLS);
356    if (Buffer1 == NULL) {
357  error("%s: framebuffer #1 could not be allocated: malloc() failed", Name);
358  return -1;
359    }
360
361    Buffer2 = malloc(PAGES * SCOLS);
362    if (Buffer2 == NULL) {
363  error("%s: framebuffer #2 could not be allocated: malloc() failed", Name);
364  return -1;
365    }
366
367    memset(Buffer1, 0, PAGES * SCOLS * sizeof(*Buffer1));
368    memset(Buffer2, 0, PAGES * SCOLS * sizeof(*Buffer2));
369
370    if (drv_generic_parport_open(section, Name) != 0) {
371  error("%s: could not initialize parallel port!", Name);
372  return -1;
373    }
374
375    if ((SIGNAL_RES = drv_generic_parport_hardwire_ctrl("RES", "INIT")) == 0xff)
376  return -1;
377    if ((SIGNAL_CS1 = drv_generic_parport_hardwire_ctrl("CS1", "STROBE")) == 0xff)
378  return -1;
379    if ((SIGNAL_RW = drv_generic_parport_hardwire_ctrl("RW", "SLCTIN")) == 0xff)
380  return -1;
381    if ((SIGNAL_A0 = drv_generic_parport_hardwire_ctrl("A0", "AUTOFD")) == 0xff)
382  return -1;
383
384    /* rise RES, CS1, RW and A0 */
385    drv_generic_parport_control(SIGNAL_RES | SIGNAL_CS1 | SIGNAL_RW | SIGNAL_A0,
386        SIGNAL_RES | SIGNAL_CS1 | SIGNAL_RW | SIGNAL_A0);
387
388    /* set direction: write */
389    drv_generic_parport_direction(0);
390
391    /* reset display: lower RESET for 1 usec */
392    drv_generic_parport_control(SIGNAL_RES, 0);
393    udelay(1);
394    drv_generic_parport_control(SIGNAL_RES, SIGNAL_RES);
395    udelay(100);
396
397    /* just to make sure: send a software reset */
398    drv_L7_write_ctrl(0xe2);
399    udelay(20000);
400
401    drv_L7_write_ctrl(0xAE);  /* Display off */
402    drv_L7_write_ctrl(0x40);  /* Start Display Line = 0 */
403    drv_L7_write_ctrl(0x20);  /* reverse line driving off */
404    drv_L7_write_ctrl(0xCC);  /* OutputStatus = $0C, 102x64 */
405    drv_L7_write_ctrl(0xA0);  /* ADC = normal */
406    drv_L7_write_ctrl(0xA9);  /* LCD-Duty = 1/64 */
407    drv_L7_write_ctrl(0xAB);  /* LCD-Duty +1 (1/65, symbols) */
408    drv_L7_write_ctrl(0x25);  /* power supply on */
409    udelay(100 * 1000);   /* wait 100 msec */
410    drv_L7_write_ctrl(0xED);  /* power supply on completion */
411    drv_L7_write_ctrl(0x8F);  /* Contrast medium */
412    drv_L7_write_ctrl(0xA4);  /* Display Test off */
413    drv_L7_write_ctrl(0xAF);  /* Display on */
414    drv_L7_write_ctrl(0xA6);  /* Display on */
415
416    /* clear display */
417    drv_L7_clear();
418
419    if (cfg_number(section, "Contrast", 15, 0, 31, &contrast) > 0) {
420  drv_L7_contrast(contrast);
421    }
422
423    return 0;
424}
425
426
427/****************************************/
428/***            plugins               ***/
429/****************************************/
430
431
432static void plugin_contrast(RESULT * result, RESULT * arg1)
433{
434    double contrast = drv_L7_contrast(R2N(arg1));
435    SetResult(&result, R_NUMBER, &contrast);
436}
437
438
439/****************************************/
440/***        exported functions        ***/
441/****************************************/
442
443
444/* list models */
445int drv_L7_list(void)
446{
447    printf("LPH7508");
448    return 0;
449}
450
451
452/* initialize driver & display */
453int drv_L7_init(const char *section, const int quiet)
454{
455    int ret;
456
457    info("%s: %s", Name, "$Rev$");
458
459    /* real worker functions */
460    drv_generic_graphic_real_blit = drv_L7_blit;
461    drv_generic_gpio_real_set = drv_L7_GPO;
462
463    /* start display */
464    if ((ret = drv_L7_start(section)) != 0)
465  return ret;
466
467    /* initialize generic graphic driver */
468    if ((ret = drv_generic_graphic_init(section, Name)) != 0)
469  return ret;
470
471    /* initialize generic GPIO driver */
472    if ((ret = drv_generic_gpio_init(section, Name)) != 0)
473  return ret;
474
475    if (!quiet) {
476  char buffer[40];
477  qprintf(buffer, sizeof(buffer), "%s %dx%d", Name, DCOLS, DROWS);
478  if (drv_generic_graphic_greet(buffer, NULL)) {
479      sleep(3);
480      drv_generic_graphic_clear();
481  }
482    }
483
484
485    /* register plugins */
486    AddFunction("LCD::contrast", 1, plugin_contrast);
487
488
489    return 0;
490}
491
492
493/* close driver & display */
494int drv_L7_quit(const int quiet)
495{
496
497    info("%s: shutting down display.", Name);
498
499    drv_generic_graphic_clear();
500
501    if (!quiet) {
502  drv_generic_graphic_greet("goodbye!", NULL);
503    }
504
505    drv_generic_graphic_quit();
506    drv_generic_gpio_quit();
507    drv_generic_parport_close();
508
509    if (Buffer1) {
510  free(Buffer1);
511  Buffer1 = NULL;
512    }
513
514    if (Buffer2) {
515  free(Buffer2);
516  Buffer2 = NULL;
517    }
518
519    return (0);
520}
521
522
523DRIVER drv_LPH7508 = {
524    .name = Name,
525    .list = drv_L7_list,
526    .init = drv_L7_init,
527    .quit = drv_L7_quit,
528};
Note: See TracBrowser for help on using the browser.