MOXA linux-2.6.x / linux-2.6.19-uc1 from UC-7110-LX-BOOTLOADER-1.9_VERSION-4.2.tgz
[linux-2.6.19-moxart.git] / drivers / char / lcm2.c
blobdc7fc269e23d62c8e4e02dd0128f8ef7525dd019
1 /*
2 * Copyright (C) MOXA Inc. All rights reserved.
4 * This software is distributed under the terms of the
5 * MOXA License. See the file COPYING-MOXA for details.
7 * This is Moxa CPU for IVTC ODM LCM moudle WG12232C device driver.
8 * It is from misc interface. So the device node major number is 10.
9 * The device node minor number is following:
10 * lcm : 102
12 * There devices are mapping system memory is following:
13 * lcm : 0x84002000 read only, data -> LCM & control signal
14 * : 0x84000000 write only, LCM -> data & control signal
16 * History:
17 * Date Aurhor Comment
18 * 12-05-2005 Victor Yu. Create it.
19 * 05-11-2006 Jimmy Chen. Fix to work.
20 * 09-03-2008 Victor Yu. Modify to support IVTC write byte feature.
22 #include <linux/config.h>
23 #include <asm/arch/moxa.h>
24 #include <linux/module.h>
25 #include <linux/kernel.h>
26 #include <linux/types.h>
27 #include <linux/miscdevice.h>
28 #include <linux/fcntl.h>
29 #include <linux/init.h>
30 #include <linux/poll.h>
31 #include <linux/proc_fs.h>
32 #include <linux/spinlock.h>
33 #include <linux/delay.h>
34 #include <linux/rtc.h>
35 #include <linux/timer.h>
36 #include <linux/ioport.h>
38 #include <asm/io.h>
39 #include <asm/uaccess.h>
40 #include <asm/system.h>
41 #include "moxalcm.h"
43 #define LCM_READ_ADDR 0x84002000
44 #define LCM_WRITE_ADDR 0x84000000
46 #define MOXA_LCM_MINOR 102
48 static spinlock_t lcm_lock= SPIN_LOCK_UNLOCKED;
51 // LCM file operation function call
53 static unsigned char fnt8x8[]={
54 0x3E,0x51,0x49,0x45,0x3E,0x00,0x00,0x00,0x40,0x42,0x7F,0x40,0x40,0x00,0x00,0x00,
55 0x42,0x61,0x51,0x49,0x66,0x00,0x00,0x00,0x22,0x49,0x49,0x49,0x36,0x00,0x00,0x00,
56 0x18,0x14,0x52,0x7F,0x50,0x00,0x00,0x00,0x27,0x45,0x45,0x45,0x39,0x00,0x00,0x00,
57 0x3C,0x4A,0x49,0x49,0x32,0x00,0x00,0x00,0x03,0x01,0x79,0x05,0x03,0x00,0x00,0x00,
58 0x36,0x49,0x49,0x49,0x36,0x00,0x00,0x00,0x26,0x49,0x49,0x49,0x3E,0x00,0x00,0x00,
59 0x7C,0x12,0x11,0x12,0x7C,0x00,0x00,0x00,0x41,0x7F,0x49,0x49,0x36,0x00,0x00,0x00,
60 0x1C,0x22,0x41,0x41,0x22,0x00,0x00,0x00,0x7F,0x41,0x41,0x22,0x1C,0x00,0x00,0x00,
61 0x41,0x7F,0x49,0x49,0x63,0x00,0x00,0x00,0x41,0x7F,0x49,0x09,0x03,0x00,0x00,0x00,
62 0x7F,0x3E,0x3E,0x1C,0x1C,0x08,0x08,0x00,0x08,0x08,0x1C,0x1C,0x3E,0x3E,0x7F,0x00,
63 0x00,0x24,0x66,0xFF,0xFF,0x66,0x24,0x00,0x00,0x5F,0x5F,0x00,0x00,0x5F,0x5F,0x00,
64 0x06,0x0F,0x09,0x7F,0x7F,0x01,0x7F,0x7F,0x40,0xDA,0xBF,0xA5,0xFD,0x59,0x03,0x02,
65 0x00,0x70,0x70,0x70,0x70,0x70,0x70,0x00,0x80,0x94,0xB6,0xFF,0xFF,0xB6,0x94,0x80,
66 0x00,0x04,0x06,0x7F,0x7F,0x06,0x04,0x00,0x00,0x10,0x30,0x7F,0x7F,0x30,0x10,0x00,
67 0x08,0x08,0x08,0x2A,0x3E,0x1C,0x08,0x00,0x08,0x1C,0x3E,0x2A,0x08,0x08,0x08,0x00,
68 0x3C,0x3C,0x20,0x20,0x20,0x20,0x20,0x00,0x08,0x1C,0x3E,0x08,0x08,0x3E,0x1C,0x08,
69 0x30,0x38,0x3C,0x3E,0x3E,0x3C,0x38,0x30,0x06,0x0E,0x1E,0x3E,0x3E,0x1E,0x0E,0x06,
70 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x00,
71 0x00,0x07,0x00,0x00,0x00,0x07,0x00,0x00,0x14,0x7F,0x14,0x14,0x14,0x7F,0x14,0x00,
72 0x24,0x2A,0x6B,0x2A,0x10,0x00,0x00,0x00,0x43,0x23,0x10,0x08,0x04,0x62,0x61,0x00,
73 0x32,0x4D,0x49,0x4D,0x52,0x28,0x40,0x00,0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
74 0x00,0x00,0x1C,0x22,0x41,0x00,0x00,0x00,0x00,0x00,0x41,0x22,0x1C,0x00,0x00,0x00,
75 0x08,0x2A,0x1C,0x08,0x08,0x1C,0x2A,0x08,0x00,0x08,0x08,0x3E,0x08,0x08,0x00,0x00,
76 0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00,0x08,0x08,0x08,0x08,0x08,0x00,0x00,0x00,
77 0x00,0x00,0x60,0x60,0x00,0x00,0x00,0x00,0x40,0x20,0x10,0x08,0x04,0x02,0x01,0x00,
78 0x3E,0x61,0x51,0x49,0x45,0x43,0x3E,0x00,0x40,0x42,0x7F,0x40,0x40,0x00,0x00,0x00,
79 0x62,0x51,0x51,0x49,0x49,0x46,0x00,0x00,0x22,0x41,0x41,0x49,0x49,0x36,0x00,0x00,
80 0x18,0x14,0x12,0x11,0x51,0x7F,0x50,0x00,0x27,0x45,0x45,0x45,0x45,0x39,0x00,0x00,
81 0x3C,0x4A,0x49,0x49,0x48,0x30,0x00,0x00,0x03,0x01,0x01,0x71,0x09,0x07,0x00,0x00,
82 0x36,0x49,0x49,0x49,0x49,0x36,0x00,0x00,0x06,0x49,0x49,0x49,0x29,0x1E,0x00,0x00,
83 0x00,0x00,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x66,0x00,0x00,0x00,0x00,0x00,
84 0x08,0x14,0x22,0x41,0x00,0x00,0x00,0x00,0x24,0x24,0x24,0x24,0x24,0x00,0x00,0x00,
85 0x00,0x00,0x41,0x22,0x14,0x08,0x00,0x00,0x02,0x01,0x01,0x51,0x09,0x06,0x00,0x00,
86 0x3E,0x41,0x41,0x51,0x51,0x11,0x0E,0x00,0x7C,0x12,0x11,0x12,0x7C,0x00,0x00,0x00,
87 0x41,0x7F,0x49,0x49,0x49,0x36,0x00,0x00,0x1C,0x22,0x41,0x41,0x41,0x22,0x00,0x00,
88 0x41,0x7F,0x41,0x41,0x41,0x22,0x1C,0x00,0x7F,0x49,0x49,0x49,0x41,0x41,0x41,0x00,
89 0x7F,0x09,0x09,0x09,0x01,0x01,0x01,0x00,0x1C,0x22,0x41,0x41,0x41,0x51,0x32,0x00,
90 0x7F,0x08,0x08,0x08,0x08,0x7F,0x00,0x00,0x00,0x41,0x7F,0x41,0x00,0x00,0x00,0x00,
91 0x30,0x40,0x40,0x40,0x41,0x3F,0x01,0x00,0x00,0x7F,0x08,0x08,0x08,0x14,0x63,0x00,
92 0x00,0x7F,0x40,0x40,0x40,0x40,0x40,0x00,0x7F,0x02,0x04,0x08,0x04,0x02,0x7F,0x00,
93 0x7F,0x02,0x04,0x08,0x10,0x20,0x7F,0x00,0x1C,0x22,0x41,0x41,0x41,0x22,0x1C,0x00,
94 0x00,0x7F,0x09,0x09,0x09,0x09,0x06,0x00,0x1E,0x21,0x21,0x21,0x61,0x5E,0x00,0x00,
95 0x7F,0x09,0x09,0x09,0x19,0x66,0x00,0x00,0x26,0x49,0x49,0x49,0x49,0x32,0x00,0x00,
96 0x01,0x01,0x01,0x7F,0x01,0x01,0x01,0x00,0x3F,0x40,0x40,0x40,0x40,0x3F,0x00,0x00,
97 0x1F,0x20,0x40,0x40,0x20,0x1F,0x00,0x00,0x7F,0x20,0x10,0x08,0x10,0x20,0x7F,0x00,
98 0x41,0x22,0x14,0x08,0x14,0x22,0x41,0x00,0x07,0x08,0x78,0x08,0x07,0x00,0x00,0x00,
99 0x41,0x61,0x51,0x49,0x45,0x43,0x41,0x00,0x00,0x7F,0x41,0x41,0x41,0x00,0x00,0x00,
100 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x00,0x00,0x41,0x41,0x41,0x7F,0x00,0x00,0x00,
101 0x08,0x04,0x02,0x01,0x02,0x04,0x08,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
102 0x00,0x00,0x00,0x03,0x04,0x00,0x00,0x00,0x20,0x54,0x54,0x54,0x14,0x78,0x40,0x00,
103 0x00,0x7F,0x48,0x48,0x48,0x48,0x30,0x00,0x38,0x44,0x44,0x44,0x44,0x28,0x00,0x00,
104 0x30,0x48,0x48,0x48,0x48,0x3F,0x00,0x00,0x38,0x54,0x54,0x54,0x54,0x08,0x00,0x00,
105 0x08,0x7E,0x09,0x09,0x01,0x02,0x00,0x00,0x98,0xA4,0xA4,0xA4,0xA4,0x78,0x00,0x00,
106 0x00,0x7F,0x08,0x08,0x08,0x08,0x70,0x00,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0x00,
107 0x60,0x80,0x80,0x80,0x80,0x7D,0x00,0x00,0x7F,0x10,0x10,0x10,0x28,0x44,0x00,0x00,
108 0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x78,0x04,0x08,0x10,0x08,0x04,0x78,0x00,
109 0x7C,0x04,0x04,0x04,0x04,0x78,0x00,0x00,0x38,0x44,0x44,0x44,0x44,0x38,0x00,0x00,
110 0xFC,0x24,0x24,0x24,0x24,0x18,0x00,0x00,0x18,0x24,0x24,0x24,0x24,0xFC,0x00,0x00,
111 0x7C,0x08,0x04,0x04,0x04,0x08,0x00,0x00,0x48,0x54,0x54,0x54,0x54,0x24,0x00,0x00,
112 0x00,0x00,0x04,0x7F,0x04,0x00,0x00,0x00,0x3C,0x40,0x40,0x40,0x40,0x3C,0x00,0x00,
113 0x1C,0x20,0x40,0x40,0x20,0x1C,0x00,0x00,0x3C,0x40,0x20,0x10,0x20,0x40,0x3C,0x00,
114 0x00,0x44,0x28,0x10,0x28,0x44,0x00,0x00,0x9C,0xA0,0xA0,0xA0,0xA0,0x7C,0x00,0x00,
115 0x44,0x44,0x64,0x54,0x4C,0x44,0x00,0x00,0x00,0x08,0x08,0x36,0x41,0x41,0x00,0x00,
116 0x00,0x00,0x00,0x77,0x00,0x00,0x00,0x00,0x41,0x41,0x36,0x08,0x08,0x00,0x00,0x00,
117 0x02,0x03,0x01,0x03,0x02,0x03,0x01,0x00,0x70,0x48,0x44,0x42,0x44,0x48,0x70,0x00,
118 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
119 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
120 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
121 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
122 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
123 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
124 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
125 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
126 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
127 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
128 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
129 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
130 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
131 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
132 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
133 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
134 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
135 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
136 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
137 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
138 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
139 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
140 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
141 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
142 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
143 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
144 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
145 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
146 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
147 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
148 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
149 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
150 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
151 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
152 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
153 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
154 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
155 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
156 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
157 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
158 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
159 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
160 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
161 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
162 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
163 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
164 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
165 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
166 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
167 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
168 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
169 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
170 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
171 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
172 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
173 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
174 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
175 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
176 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
177 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
178 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
179 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
180 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
181 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
183 static int lcmx, lcmy; // dots position
185 // following on LCM command
186 #define LCM_CMD_DISPLAY_ON 0xaf
187 #define LCM_CMD_DISPLAY_OFF 0xae
188 #define LCM_CMD_DISPLAY_START_LINE 0xc0
189 #define LCM_DISPLAY_START_LINE_MASK 0x1F // 0-31
190 #define LCM_CMD_SET_PAGE 0xb8 // x address
191 #define LCM_SET_PAGE_MASK 0x03 // x address 0-3
192 #define LCM_CMD_SET_ADDRESS 0x00 // y address, from 0x40 to 0xc0
193 #define LCM_SET_ADDRESS_MASK 0x7F // y address 0-79
194 #define LCM_STATUS_BUSY 0x80
195 #define LCM_STATUS_ON 0x20
196 #define LCM_STATUS_RESET 0x10
197 #define LCM_MODE_SELECT 0x05
199 // following LCM control
200 #define LCM_DATA (1<<8)
201 #define LCM_CMD 0
202 #define LCM_READ (1<<9)
203 #define LCM_WRITE 0
204 #define LCM_EBIT_ON (1<<10)
205 #define LCM_EBIT_OFF 0
206 #define LCM_BACK_LIGHT_OFF (1<<11)
207 #define LCM_BACK_LIGHT_ON 0
208 #define LCM_CS1 (1<<13)
209 #define LCM_CS2 (1<<12)
210 #define LCM_WRITE_ENABLE (1<<14)
211 #define LCM_READ_ENABLE 0
212 #define LCM_DATA_MASK 0xff
213 #define LCM_ADC 0xa0
214 #define LCM_ADC_MASK 0x1
216 //#define LCM_MAX_X_DOTS 120
217 #define LCM_MAX_X_DOTS 120
218 #define LCM_MAX_Y_DOTS 32
219 #define LCM_HALF_X_DOTS 61
220 //#define LCM_HALF_X_DOTS (LCM_MAX_X_DOTS/2)
221 #define LCM_X_DOTS 8
222 #define LCM_Y_DOTS 8
223 #define LCM_MAX_X (LCM_MAX_X_DOTS/LCM_X_DOTS)
224 #define LCM_MAX_Y (LCM_MAX_Y_DOTS/LCM_Y_DOTS)
226 static unsigned char lcm_pix_buffer[LCM_MAX_Y][LCM_MAX_X_DOTS];
227 static u16 lcm_ctrl_data=LCM_BACK_LIGHT_ON;
228 static int lcm_auto_scroll_flag=1;
229 static int lcm_reverse_flag=0;
230 typedef struct lcm_xy {
231 int x; // 0 - 15
232 int y; // 0 - 7
233 } lcm_xy_t;
235 #define LCM_NOT_LOCK_INT
237 static void LCM_write_cmd(u16 cmd, u16 cs)
239 #ifndef LCM_NOT_LOCK_INT
240 unsigned long flags;
242 save_flags(flags);
243 cli();
244 #endif
245 spin_lock(&lcm_lock);
246 outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_READ|LCM_CMD|LCM_READ_ENABLE|cs, LCM_WRITE_ADDR);
247 outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_WRITE|LCM_CMD|LCM_READ_ENABLE|cs, LCM_WRITE_ADDR);
248 udelay(20) ;
249 outw(lcm_ctrl_data|LCM_EBIT_ON|LCM_WRITE|LCM_CMD|LCM_READ_ENABLE|cs|cmd, LCM_WRITE_ADDR);
250 udelay(20) ;
251 outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_WRITE|LCM_CMD|LCM_WRITE_ENABLE|cs|cmd, LCM_WRITE_ADDR);
252 outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_READ|LCM_CMD|LCM_READ_ENABLE|cs, LCM_WRITE_ADDR);
253 spin_unlock(&lcm_lock);
254 #ifndef LCM_NOT_LOCK_INT
255 restore_flags(flags);
256 #endif
259 static void LCM_write_data(unsigned char data, u16 cs)
261 #ifndef LCM_NOT_LOCK_INT
262 unsigned long flags;
264 save_flags(flags);
265 cli();
266 #endif
267 spin_lock(&lcm_lock);
268 outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_READ|LCM_DATA|LCM_READ_ENABLE|cs, LCM_WRITE_ADDR);
269 outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_WRITE|LCM_DATA|LCM_READ_ENABLE|cs, LCM_WRITE_ADDR);
270 udelay(20) ;
271 outw(lcm_ctrl_data|LCM_EBIT_ON|LCM_WRITE|LCM_DATA|LCM_READ_ENABLE|cs|(u16)data, LCM_WRITE_ADDR);
272 udelay(20) ;
273 outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_WRITE|LCM_DATA|LCM_WRITE_ENABLE|cs|(u16)data, LCM_WRITE_ADDR);
274 outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_READ|LCM_DATA|LCM_READ_ENABLE|cs, LCM_WRITE_ADDR);
275 spin_unlock(&lcm_lock);
276 #ifndef LCM_NOT_LOCK_INT
277 restore_flags(flags);
278 #endif
281 static void lcm_up_one_line(void)
283 int x, y, index, i;
285 // first up one line for lcm buffer
286 spin_lock(&lcm_lock);
287 for ( y=1; y<LCM_MAX_Y; y++ ) {
288 for ( x=0; x<LCM_MAX_X; x++ ) {
289 memcpy(&lcm_pix_buffer[y-1][x*LCM_X_DOTS], &lcm_pix_buffer[y][x*LCM_X_DOTS], LCM_X_DOTS);
292 for ( x=0; x<LCM_MAX_X; x++ ) {
293 memset(&lcm_pix_buffer[LCM_MAX_Y-1][x*LCM_X_DOTS], 0, LCM_X_DOTS);
295 spin_unlock(&lcm_lock);
297 // second redisplay up one line on LCM
298 LCM_write_cmd(LCM_CMD_DISPLAY_OFF, LCM_CS1);
299 LCM_write_cmd(LCM_CMD_DISPLAY_OFF, LCM_CS2);
300 for ( y=0; y<LCM_MAX_Y; y++ ) {
301 for ( x=0; x<LCM_MAX_X; x++ ) {
302 if ( x == 0 ) {
303 LCM_write_cmd(LCM_CMD_SET_ADDRESS, LCM_CS1);
304 LCM_write_cmd(LCM_CMD_SET_PAGE | (y & LCM_SET_PAGE_MASK), LCM_CS1);
305 } else if ( x == (LCM_HALF_X_DOTS/LCM_X_DOTS) ) {
306 LCM_write_cmd(LCM_CMD_SET_ADDRESS, LCM_CS2);
307 LCM_write_cmd(LCM_CMD_SET_PAGE | (y & LCM_SET_PAGE_MASK), LCM_CS2);
309 index = x * LCM_X_DOTS;
310 for ( i=0; i<LCM_X_DOTS; i++, index++ ) {
311 if ( x < (LCM_HALF_X_DOTS/LCM_X_DOTS) ) {
312 LCM_write_data(lcm_pix_buffer[y][index], LCM_CS1);
313 } else {
314 LCM_write_data(lcm_pix_buffer[y][index], LCM_CS2);
319 LCM_write_cmd(LCM_CMD_DISPLAY_ON, LCM_CS1);
320 LCM_write_cmd(LCM_CMD_DISPLAY_ON, LCM_CS2);
321 spin_lock(&lcm_lock);
322 lcmx = 0;
323 lcmy = LCM_MAX_Y - 1;
324 spin_unlock(&lcm_lock);
327 static void LCM_printf_char(unsigned char ch)
329 int index, i;
331 if ( ch == '\n' ) {
332 spin_lock(&lcm_lock);
333 for ( i=(lcmx/LCM_X_DOTS); i<LCM_MAX_X; i++ ) {
334 if ( lcm_reverse_flag )
335 memset(&lcm_pix_buffer[lcmy][i*LCM_X_DOTS], 1, LCM_X_DOTS);
336 else
337 memset(&lcm_pix_buffer[lcmy][i*LCM_X_DOTS], 0, LCM_X_DOTS);
339 lcmx = 0;
340 lcmy++;
341 if ( lcmy >= LCM_MAX_Y ) {
342 if ( lcm_auto_scroll_flag ) {
343 lcmy = LCM_MAX_Y - 1;
344 spin_unlock(&lcm_lock);
345 lcm_up_one_line();
346 return;
347 } else {
348 lcmy = 0;
351 spin_unlock(&lcm_lock);
352 return;
354 #if 0
355 if ( lcmx < LCM_HALF_X_DOTS ) {
356 LCM_write_cmd(LCM_CMD_SET_ADDRESS|(unsigned char)lcmx, LCM_CS1);
357 LCM_write_cmd(LCM_CMD_SET_PAGE | (lcmy & LCM_SET_PAGE_MASK), LCM_CS1);
358 } else {
359 LCM_write_cmd(LCM_CMD_SET_ADDRESS|(unsigned char)(lcmx-LCM_HALF_X_DOTS), LCM_CS2);
360 LCM_write_cmd(LCM_CMD_SET_PAGE | (lcmy & LCM_SET_PAGE_MASK), LCM_CS2);
362 #endif
363 index = ch * LCM_Y_DOTS;
364 for ( i=0; i<LCM_X_DOTS; i++, index++, lcmx++ ) {
365 if(lcmx==LCM_MAX_X_DOTS)
366 break;
367 if ( lcmx < LCM_HALF_X_DOTS ) {
368 LCM_write_cmd(LCM_CMD_SET_ADDRESS|(unsigned char)lcmx, LCM_CS1);
369 LCM_write_cmd(LCM_CMD_SET_PAGE | (lcmy & LCM_SET_PAGE_MASK), LCM_CS1);
370 } else {
371 LCM_write_cmd(LCM_CMD_SET_ADDRESS|(unsigned char)(lcmx-LCM_HALF_X_DOTS), LCM_CS2);
372 LCM_write_cmd(LCM_CMD_SET_PAGE | (lcmy & LCM_SET_PAGE_MASK), LCM_CS2);
374 spin_lock(&lcm_lock);
375 if ( lcm_reverse_flag )
376 lcm_pix_buffer[lcmy][lcmx] = ~fnt8x8[index];
377 else
378 lcm_pix_buffer[lcmy][lcmx] = fnt8x8[index];
379 spin_unlock(&lcm_lock);
380 if ( lcmx < LCM_HALF_X_DOTS )
382 LCM_write_data(fnt8x8[index], LCM_CS1);
384 else
386 LCM_write_data(fnt8x8[index], LCM_CS2);
388 spin_lock(&lcm_lock);
389 if ( lcmx >= LCM_MAX_X_DOTS ) {
390 lcmx = 0;
391 lcmy++;
392 if ( lcmy >= LCM_MAX_Y ) {
393 if ( lcm_auto_scroll_flag ) {
394 lcmy = LCM_MAX_Y - 1;
395 spin_unlock(&lcm_lock);
396 lcm_up_one_line();
397 return;
398 } else {
399 lcmy = 0;
403 spin_unlock(&lcm_lock);
406 static void LCM_clear_line(void)
408 int x, index, i;
410 for ( x=0; x<LCM_MAX_X; x++ ) {
411 spin_lock(&lcm_lock);
412 if ( lcm_reverse_flag )
413 memset(&lcm_pix_buffer[lcmy][x*LCM_X_DOTS], 1, LCM_X_DOTS);
414 else
415 memset(&lcm_pix_buffer[lcmy][x*LCM_X_DOTS], 0, LCM_X_DOTS);
416 spin_unlock(&lcm_lock);
417 if ( x == 0 ) {
418 LCM_write_cmd(LCM_CMD_SET_ADDRESS, LCM_CS1);
419 LCM_write_cmd(LCM_CMD_SET_PAGE | (lcmy & LCM_SET_PAGE_MASK), LCM_CS1);
420 } else if ( x == (LCM_HALF_X_DOTS/LCM_X_DOTS) ) {
421 LCM_write_cmd(LCM_CMD_SET_ADDRESS, LCM_CS2);
422 LCM_write_cmd(LCM_CMD_SET_PAGE | (lcmy & LCM_SET_PAGE_MASK), LCM_CS2);
424 index = x * LCM_X_DOTS;
425 for ( i=0; i<LCM_X_DOTS; i++, index++ ) {
426 if ( x < (LCM_HALF_X_DOTS/LCM_X_DOTS) ) {
427 LCM_write_data(lcm_pix_buffer[lcmy][index], LCM_CS1);
428 } else {
429 LCM_write_data(lcm_pix_buffer[lcmy][index], LCM_CS2);
433 spin_lock(&lcm_lock);
434 lcmx = 0;
435 spin_unlock(&lcm_lock);
438 static void LCM_cls(void)
440 int x, y;
442 LCM_write_cmd(LCM_CMD_DISPLAY_OFF, LCM_CS1);
443 LCM_write_cmd(LCM_CMD_DISPLAY_OFF, LCM_CS2);
444 for ( y=0; y<LCM_MAX_Y; y++ ) {
445 // clear LCM hardware
446 for ( x=0; x<122; x++ ) {
447 if ( x == 0 ) {
448 LCM_write_cmd(LCM_CMD_SET_ADDRESS, LCM_CS1);
449 LCM_write_cmd(LCM_CMD_SET_PAGE | (y & LCM_SET_PAGE_MASK), LCM_CS1);
450 } else if ( x == LCM_HALF_X_DOTS ) {
451 LCM_write_cmd(LCM_CMD_SET_ADDRESS, LCM_CS2);
452 LCM_write_cmd(LCM_CMD_SET_PAGE | (y & LCM_SET_PAGE_MASK), LCM_CS2);
454 spin_lock(&lcm_lock);
455 if ( lcm_reverse_flag )
456 lcm_pix_buffer[y][x] = 0xff;
457 else
458 lcm_pix_buffer[y][x] = 0;
459 spin_unlock(&lcm_lock);
460 if ( lcm_reverse_flag ) {
461 if ( x < LCM_HALF_X_DOTS )
462 LCM_write_data(0xff, LCM_CS1);
463 else
464 LCM_write_data(0xff, LCM_CS2);
465 } else {
466 if ( x < LCM_HALF_X_DOTS )
467 LCM_write_data(0, LCM_CS1);
468 else
469 LCM_write_data(0, LCM_CS2);
473 LCM_write_cmd(LCM_CMD_DISPLAY_ON, LCM_CS1);
474 LCM_write_cmd(LCM_CMD_DISPLAY_ON, LCM_CS2);
475 spin_lock(&lcm_lock);
476 lcmx = lcmy = 0;
477 spin_unlock(&lcm_lock);
481 * I don't know why cannot malloc memory from kernel.
482 * 03-10-2004 Victor Yu.
484 #define USE_WRITE_BUFFER
485 static ssize_t lcm_write(struct file * filp, const char * buf, size_t count, loff_t *ppos)
487 #ifdef USE_WRITE_BUFFER
488 char write_buffer[LCM_MAX_X * LCM_MAX_Y];
489 #else
490 char *ptr;
491 #endif
492 int i;
494 if ( count == 0 )
495 return 0;
496 #ifdef USE_WRITE_BUFFER
497 if ( count > (LCM_MAX_X * LCM_MAX_Y) )
498 count = LCM_MAX_X * LCM_MAX_Y;
499 if ( copy_from_user(write_buffer, buf, count) ) {
500 return -EFAULT;
502 for ( i=0; i<count; i++ )
503 LCM_printf_char(write_buffer[i]);
504 #else
505 ptr = kmalloc(count, GFP_KERNEL);
506 if ( ptr == NULL )
507 return -ENOMEM;
508 if ( copy_from_user(ptr, buf, count) ) {
509 kfree(ptr);
510 return -EFAULT;
512 for ( i=0; i<count; i++ )
513 LCM_printf_char(*ptr++);
514 kfree(ptr);
515 #endif
516 return count;
519 static int lcm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
521 lcm_xy_t pos;
522 static unsigned char user_data;
524 switch ( cmd ) {
525 case IOCTL_LCM_PIX_ON :
526 case IOCTL_LCM_PIX_OFF :
528 unsigned char v, mask;
530 if ( copy_from_user(&pos, (void *)arg, sizeof(pos)) )
531 return -EFAULT;
532 if ( pos.x < 0 || pos.x >= LCM_MAX_X_DOTS || pos.y < 0 || pos.y >= LCM_MAX_Y_DOTS )
533 return -EINVAL;
534 spin_lock(&lcm_lock);
535 v = lcm_pix_buffer[pos.y/LCM_Y_DOTS][pos.x];
536 mask = 1 << (pos.y % LCM_Y_DOTS);
537 if ( cmd == IOCTL_LCM_PIX_ON )
538 v |= mask;
539 else
540 v &= ~mask;
541 lcm_pix_buffer[pos.y/LCM_Y_DOTS][pos.x] = v;
542 spin_unlock(&lcm_lock);
543 if ( pos.x < LCM_HALF_X_DOTS ) {
544 LCM_write_cmd(LCM_CMD_SET_ADDRESS|(unsigned char)pos.x, LCM_CS1);
545 LCM_write_cmd(LCM_CMD_SET_PAGE | ((pos.y/LCM_Y_DOTS) & LCM_SET_PAGE_MASK), LCM_CS1);
546 LCM_write_data(v, LCM_CS1);
547 } else {
548 LCM_write_cmd(LCM_CMD_SET_ADDRESS|(unsigned char)(pos.x-LCM_HALF_X_DOTS), LCM_CS2);
549 LCM_write_cmd(LCM_CMD_SET_PAGE | ((pos.y/LCM_Y_DOTS) & LCM_SET_PAGE_MASK), LCM_CS2);
550 LCM_write_data(v, LCM_CS2);
552 break;
554 case IOCTL_LCM_GOTO_XY :
555 if ( copy_from_user(&pos, (void *)arg, sizeof(pos)) )
556 return -EFAULT;
557 if ( pos.x < 0 || pos.x >= LCM_MAX_X || pos.y < 0 || pos.y >= LCM_MAX_Y )
558 return -EINVAL;
559 spin_lock(&lcm_lock);
560 lcmx = pos.x * LCM_X_DOTS;
561 lcmy = pos.y;
562 spin_unlock(&lcm_lock);
563 break;
564 case IOCTL_LCM_CLS :
565 LCM_cls();
566 break;
567 case IOCTL_LCM_CLEAN_LINE :
568 LCM_clear_line();
569 break;
570 case IOCTL_LCM_GET_XY :
571 spin_lock(&lcm_lock);
572 pos.x = lcmx / LCM_X_DOTS;
573 pos.y = lcmy;
574 spin_unlock(&lcm_lock);
575 if ( copy_to_user((void *)arg, &pos,sizeof(pos)) )
576 return -EFAULT;
577 break;
578 case IOCTL_LCM_BACK_LIGHT_ON :
579 spin_lock(&lcm_lock);
580 lcm_ctrl_data |= LCM_BACK_LIGHT_ON;
581 outw(lcm_ctrl_data, LCM_WRITE_ADDR);
582 spin_unlock(&lcm_lock);
583 break;
584 case IOCTL_LCM_BACK_LIGHT_OFF :
585 spin_lock(&lcm_lock);
586 lcm_ctrl_data &= ~LCM_BACK_LIGHT_ON;
587 outw(lcm_ctrl_data, LCM_WRITE_ADDR);
588 spin_unlock(&lcm_lock);
589 break;
590 case IOCTL_LCM_AUTO_SCROLL_ON :
591 spin_lock(&lcm_lock);
592 lcm_auto_scroll_flag = 1;
593 spin_unlock(&lcm_lock);
594 break;
595 case IOCTL_LCM_AUTO_SCROLL_OFF :
596 spin_lock(&lcm_lock);
597 lcm_auto_scroll_flag = 0;
598 spin_unlock(&lcm_lock);
599 break;
600 case IOCTL_LCM_REVERSE_ON :
601 spin_lock(&lcm_lock);
602 lcm_reverse_flag = 1;
603 spin_unlock(&lcm_lock);
604 break;
605 case IOCTL_LCM_REVERSE_OFF :
606 spin_lock(&lcm_lock);
607 lcm_reverse_flag = 0;
608 spin_unlock(&lcm_lock);
609 break;
610 case IOCTL_LCM_SAVE_BYTE :
611 if ( copy_from_user(&user_data, (void *)arg, sizeof(user_data)) )
612 return -EFAULT;
613 break;
614 case IOCTL_LCM_WRITE_BYTE :
616 unsigned char v, mask, cbit;
617 int i, x, y, ybit;
618 if ( copy_from_user(&pos, (void *)arg, sizeof(pos)) )
619 return -EFAULT;
620 if ( pos.x < 0 || pos.x >= LCM_MAX_X_DOTS || pos.y < 0 || pos.y >= LCM_MAX_Y_DOTS )
621 return -EINVAL;
622 spin_lock(&lcm_lock);
623 y = pos.y / LCM_Y_DOTS;
624 ybit = pos.y % LCM_Y_DOTS;
625 for ( i=0, x=pos.x, cbit=1; i<sizeof(unsigned char); i++, x++, cbit<<=1 ) {
626 v = lcm_pix_buffer[y][x];
627 mask = 1 << ybit;
628 if ( user_data & cbit )
629 v |= mask;
630 else
631 v &= ~mask;
632 lcm_pix_buffer[y][x] = v;
634 spin_unlock(&lcm_lock);
635 for ( i=0, x=pos.x; i<sizeof(unsigned char); i++, x++ ) {
636 if ( x < LCM_HALF_X_DOTS ) {
637 LCM_write_cmd(LCM_CMD_SET_ADDRESS|(unsigned char)x, LCM_CS1);
638 LCM_write_cmd(LCM_CMD_SET_PAGE | (y & LCM_SET_PAGE_MASK), LCM_CS1);
639 LCM_write_data(lcm_pix_buffer[y][x], LCM_CS1);
640 } else {
641 LCM_write_cmd(LCM_CMD_SET_ADDRESS|(unsigned char)(x-LCM_HALF_X_DOTS), LCM_CS2);
642 LCM_write_cmd(LCM_CMD_SET_PAGE | (y & LCM_SET_PAGE_MASK), LCM_CS2);
643 LCM_write_data(lcm_pix_buffer[y][x], LCM_CS2);
646 break;
648 case IOCTL_LCM_DISPLAY_OFF :
649 LCM_write_cmd(LCM_CMD_DISPLAY_OFF, LCM_CS1);
650 LCM_write_cmd(LCM_CMD_DISPLAY_OFF, LCM_CS2);
651 break;
652 case IOCTL_LCM_DISPLAY_ON :
653 LCM_write_cmd(LCM_CMD_DISPLAY_ON, LCM_CS1);
654 LCM_write_cmd(LCM_CMD_DISPLAY_ON, LCM_CS2);
655 break;
656 default:
657 return -EINVAL;
660 return 0;
663 static int lcm_open(struct inode *inode, struct file *file)
665 if ( MINOR(inode->i_rdev) == MOXA_LCM_MINOR )
666 return 0;
667 return -ENODEV;
670 static int lcm_release(struct inode *inode, struct file *file)
672 return 0;
675 static struct file_operations lcm_fops = {
676 owner:THIS_MODULE,
677 llseek:NULL,
678 write:lcm_write,
679 ioctl:lcm_ioctl,
680 open:lcm_open,
681 release:lcm_release,
683 static struct miscdevice lcm_dev = {
684 MOXA_LCM_MINOR,
685 "lcm",
686 &lcm_fops
689 #if 1 // add by Victor Yu. 04-03-2007
690 extern int lcm_module_flag;
691 #endif
692 static void __exit ivtc_lcm2_exit(void)
694 misc_deregister(&lcm_dev);
695 lcm_module_flag = 0;
698 static int __init ivtc_lcm2_init(void)
700 printk("Moxa CPU misc: Register LCM module WG12232C misc ver1.0 ");
701 if ( lcm_module_flag ) {
702 printk("fail !\nThe other type LCM module device driver has loaded.\n");
703 return -ENOMEM;
705 if ( misc_register(&lcm_dev) ) {
706 printk("fail !\n");
707 return -ENOMEM;
709 lcm_module_flag = 1;
710 printk("OK.\n");
711 LCM_cls() ;
713 LCM_write_cmd(LCM_CMD_DISPLAY_START_LINE|(0x07&LCM_DISPLAY_START_LINE_MASK),LCM_CS1|LCM_CS2) ;
714 LCM_write_cmd(LCM_ADC|(0&LCM_ADC_MASK),LCM_CS1|LCM_CS2) ;
715 #if 0
716 LCM_write_cmd(LCM_CMD_DISPLAY_OFF, LCM_CS1);
717 LCM_write_cmd(LCM_CMD_SET_ADDRESS, LCM_CS1);
718 LCM_write_cmd(LCM_CMD_SET_PAGE | (2 & LCM_SET_PAGE_MASK), LCM_CS1);
719 LCM_write_data(0xaa, LCM_CS1);
720 LCM_write_cmd(LCM_CMD_DISPLAY_ON, LCM_CS1);
721 #endif
722 return 0;
725 module_init(ivtc_lcm2_init);
726 module_exit(ivtc_lcm2_exit);
728 MODULE_AUTHOR("Victor Yu");
729 MODULE_LICENSE("GPL");