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 / lcm3.c
blob0313b1e79d5883dbd1240c4b7fe9da41aabb8119
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 WG16080A 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 : 0x04000000 read only, data -> LCM & control signal
14 * : 0x04002000 write only, LCM -> data & control signal
16 * History:
17 * Date Aurhor Comment
18 * 09-02-2008 Victor Yu. Create it.
20 #include <linux/config.h>
21 #include <asm/arch/moxa.h>
22 #include <linux/module.h>
23 #include <linux/kernel.h>
24 #include <linux/types.h>
25 #include <linux/miscdevice.h>
26 #include <linux/fcntl.h>
27 #include <linux/init.h>
28 #include <linux/poll.h>
29 #include <linux/proc_fs.h>
30 #include <linux/spinlock.h>
31 #include <linux/delay.h>
32 #include <linux/rtc.h>
33 #include <linux/timer.h>
34 #include <linux/ioport.h>
36 #include <asm/io.h>
37 #include <asm/uaccess.h>
38 #include <asm/system.h>
39 #include "moxalcm.h"
41 #define LCM_READ_ADDR 0x84002000
42 #define LCM_WRITE_ADDR 0x84000000
44 #define MOXA_LCM_MINOR 102
46 static spinlock_t lcm_lock= SPIN_LOCK_UNLOCKED;
49 // LCM file operation function call
51 static unsigned char fnt8x8[]={
52 0x0E,0x11,0x19,0x15,0x13,0x11,0x0E,0x00,0x04,0x06,0x04,0x04,0x04,0x04,0x1F,0x00,
53 0x0E,0x11,0x10,0x08,0x04,0x12,0x1F,0x00,0x0E,0x11,0x10,0x0E,0x10,0x11,0x0E,0x00,
54 0x08,0x0C,0x0A,0x09,0x1F,0x08,0x1C,0x00,0x1F,0x01,0x0F,0x10,0x10,0x11,0x0E,0x00,
55 0x0C,0x12,0x01,0x0F,0x11,0x11,0x0E,0x00,0x1F,0x11,0x08,0x04,0x04,0x04,0x04,0x00,
56 0x0E,0x11,0x11,0x0E,0x11,0x11,0x0E,0x00,0x0E,0x11,0x11,0x1E,0x10,0x11,0x0E,0x00,
57 0x04,0x0A,0x11,0x11,0x1F,0x11,0x11,0x00,0x0F,0x12,0x12,0x0E,0x12,0x12,0x0F,0x00,
58 0x0C,0x12,0x01,0x01,0x01,0x12,0x0C,0x00,0x07,0x09,0x11,0x11,0x11,0x09,0x07,0x00,
59 0x1F,0x12,0x02,0x0E,0x02,0x12,0x1F,0x00,0x1F,0x12,0x02,0x0E,0x02,0x02,0x07,0x00,
60 0x01,0x07,0x1F,0x7F,0x1F,0x07,0x01,0x00,0x40,0x70,0x7C,0x7F,0x7C,0x70,0x40,0x00,
61 0x18,0x3C,0x7E,0x18,0x18,0x7E,0x3C,0x18,0x66,0x66,0x66,0x66,0x66,0x00,0x66,0x00,
62 0xFE,0xDB,0xDB,0xDE,0xD8,0xD8,0xD8,0x00,0x7C,0xC6,0x1C,0x36,0x36,0x1C,0x33,0x1E,
63 0x00,0x00,0x00,0x00,0x7E,0x7E,0x7E,0x00,0x18,0x3C,0x7E,0x18,0x7E,0x3C,0x18,0xFF,
64 0x18,0x3C,0x7E,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00,
65 0x00,0x18,0x30,0x7F,0x30,0x18,0x00,0x00,0x00,0x0C,0x06,0x7F,0x06,0x0C,0x00,0x00,
66 0x00,0x00,0x03,0x03,0x03,0x7F,0x00,0x00,0x00,0x24,0x66,0xFF,0x66,0x24,0x00,0x00,
67 0x00,0x18,0x3C,0x7E,0xFF,0xFF,0x00,0x00,0x00,0xFF,0xFF,0x7E,0x3C,0x18,0x00,0x00,
68 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x08,0x08,0x08,0x00,0x08,0x00,
69 0x22,0x22,0x22,0x00,0x00,0x00,0x00,0x00,0x22,0x22,0x7F,0x22,0x7F,0x22,0x22,0x00,
70 0x04,0x0E,0x01,0x0E,0x10,0x0F,0x04,0x00,0x43,0x23,0x10,0x08,0x04,0x62,0x61,0x00,
71 0x0E,0x11,0x0A,0x2E,0x11,0x21,0x5E,0x00,0x02,0x02,0x01,0x00,0x00,0x00,0x00,0x00,
72 0x10,0x08,0x04,0x04,0x04,0x08,0x10,0x00,0x04,0x08,0x10,0x10,0x10,0x08,0x04,0x00,
73 0x00,0x42,0x24,0xFF,0x24,0x42,0x00,0x00,0x00,0x08,0x08,0x3E,0x08,0x08,0x00,0x00,
74 0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x04,0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x00,
75 0x00,0x00,0x00,0x00,0x00,0x0C,0x0C,0x00,0x40,0x20,0x10,0x08,0x04,0x02,0x01,0x00,
76 0x3E,0x61,0x51,0x49,0x45,0x43,0x3E,0x00,0x04,0x06,0x04,0x04,0x04,0x04,0x1F,0x00,
77 0x1E,0x21,0x20,0x18,0x06,0x01,0x3F,0x00,0x1E,0x21,0x20,0x18,0x20,0x21,0x1E,0x00,
78 0x38,0x24,0x22,0x21,0x7F,0x20,0x70,0x00,0x3F,0x01,0x1F,0x20,0x20,0x21,0x1E,0x00,
79 0x0C,0x02,0x01,0x1F,0x21,0x21,0x1E,0x00,0x3F,0x21,0x20,0x10,0x08,0x08,0x08,0x00,
80 0x1E,0x21,0x21,0x1E,0x21,0x21,0x1E,0x00,0x1E,0x21,0x21,0x3E,0x20,0x10,0x0E,0x00,
81 0x00,0x04,0x04,0x00,0x00,0x04,0x04,0x00,0x00,0x04,0x04,0x00,0x00,0x04,0x04,0x02,
82 0x08,0x04,0x02,0x01,0x02,0x04,0x08,0x00,0x00,0x00,0x1F,0x00,0x00,0x1F,0x00,0x00,
83 0x04,0x08,0x10,0x20,0x10,0x08,0x04,0x00,0x1E,0x21,0x20,0x10,0x08,0x00,0x08,0x00,
84 0x3E,0x41,0x41,0x41,0x39,0x01,0x1E,0x00,0x04,0x0A,0x11,0x11,0x1F,0x11,0x11,0x00,
85 0x1F,0x22,0x22,0x1E,0x22,0x22,0x1F,0x00,0x1C,0x22,0x01,0x01,0x01,0x22,0x1C,0x00,
86 0x1F,0x22,0x42,0x42,0x42,0x22,0x1F,0x00,0x7F,0x01,0x01,0x0F,0x01,0x01,0x7F,0x00,
87 0x7F,0x01,0x01,0x0F,0x01,0x01,0x01,0x00,0x3C,0x42,0x01,0x01,0x61,0x42,0x3C,0x00,
88 0x21,0x21,0x21,0x3F,0x21,0x21,0x21,0x00,0x0E,0x04,0x04,0x04,0x04,0x04,0x0E,0x00,
89 0x70,0x20,0x20,0x20,0x21,0x21,0x1E,0x00,0x42,0x42,0x22,0x1E,0x22,0x42,0x42,0x00,
90 0x02,0x02,0x02,0x02,0x02,0x02,0x7E,0x00,0x41,0x63,0x55,0x49,0x41,0x41,0x41,0x00,
91 0x41,0x43,0x45,0x49,0x51,0x61,0x41,0x00,0x1C,0x22,0x41,0x41,0x41,0x22,0x1C,0x00,
92 0x3E,0x42,0x42,0x3E,0x02,0x02,0x02,0x00,0x1E,0x21,0x21,0x21,0x21,0x1E,0x30,0x00,
93 0x1F,0x21,0x21,0x1F,0x11,0x21,0x21,0x00,0x1E,0x21,0x01,0x1E,0x20,0x21,0x1E,0x00,
94 0x7F,0x08,0x08,0x08,0x08,0x08,0x08,0x00,0x21,0x21,0x21,0x21,0x21,0x21,0x1E,0x00,
95 0x21,0x21,0x21,0x21,0x21,0x12,0x0C,0x00,0x41,0x41,0x41,0x49,0x55,0x63,0x41,0x00,
96 0x41,0x22,0x14,0x08,0x14,0x22,0x41,0x00,0x11,0x11,0x11,0x0E,0x04,0x04,0x04,0x00,
97 0x7F,0x20,0x10,0x08,0x04,0x02,0x7F,0x00,0x1E,0x02,0x02,0x02,0x02,0x02,0x1E,0x00,
98 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x00,0x1E,0x10,0x10,0x10,0x10,0x10,0x1E,0x00,
99 0x08,0x14,0x22,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,
100 0x08,0x08,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0x20,0x3E,0x21,0x6E,0x00,
101 0x02,0x02,0x02,0x3E,0x42,0x42,0x3E,0x00,0x00,0x00,0x1E,0x21,0x01,0x21,0x1E,0x00,
102 0x20,0x20,0x20,0x3E,0x21,0x21,0x1E,0x00,0x00,0x00,0x1E,0x21,0x1F,0x01,0x1E,0x00,
103 0x1C,0x22,0x02,0x0F,0x02,0x02,0x02,0x00,0x00,0x00,0x1E,0x21,0x21,0x3E,0x20,0x1F,
104 0x02,0x02,0x02,0x3E,0x42,0x42,0x42,0x00,0x08,0x00,0x08,0x08,0x08,0x08,0x08,0x00,
105 0x20,0x00,0x20,0x20,0x20,0x21,0x21,0x1E,0x01,0x01,0x21,0x11,0x0F,0x11,0x21,0x00,
106 0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x00,0x00,0x00,0x22,0x55,0x49,0x41,0x41,0x00,
107 0x00,0x00,0x1F,0x21,0x21,0x21,0x21,0x00,0x00,0x00,0x1E,0x21,0x21,0x21,0x1E,0x00,
108 0x00,0x00,0x1F,0x21,0x21,0x1F,0x01,0x01,0x00,0x00,0x3E,0x21,0x21,0x3E,0x20,0x20,
109 0x00,0x00,0x1D,0x23,0x01,0x01,0x01,0x00,0x00,0x00,0x3E,0x01,0x1E,0x20,0x1F,0x00,
110 0x08,0x08,0x1C,0x08,0x08,0x08,0x08,0x00,0x00,0x00,0x21,0x21,0x21,0x21,0x1E,0x00,
111 0x00,0x00,0x21,0x21,0x21,0x12,0x0C,0x00,0x00,0x00,0x41,0x41,0x49,0x55,0x22,0x00,
112 0x00,0x00,0x22,0x14,0x08,0x14,0x22,0x00,0x00,0x00,0x21,0x21,0x21,0x3E,0x20,0x1F,
113 0x00,0x00,0x3F,0x10,0x08,0x04,0x3F,0x00,0x30,0x08,0x08,0x06,0x08,0x08,0x30,0x00,
114 0x08,0x08,0x08,0x00,0x08,0x08,0x08,0x00,0x03,0x04,0x04,0x18,0x04,0x04,0x03,0x00,
115 0x6E,0x3B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x14,0x22,0x41,0x41,0x7F,0x00,
116 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
117 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,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,
181 static int lcmx; // now character position
182 static int lcmy; // now dot position
184 // LCM register number
185 #define LCM_REG_MODE_CONTROL 0 // mode control
186 #define LCM_CMD_DISPLAY_BIT 0x20
187 #define LCM_CMD_MASTER_BIT 0x10
188 #define LCM_CMD_BLINK_BIT 0x08
189 #define LCM_CMD_CURSOR_BIT 0x04
190 #define LCM_CMD_MODE_BIT 0x02
191 #define LCM_CMD_CG_BIT 0x01 // external CG, 0 for built-in CG
192 #define LCM_CMD_GRAPHIC_MODE 0x32 // setting the graphic mode
193 #define LCM_CMD_TEXT_MODE 0x30 // setting the charactic mode
194 #define LCM_CMD_DISPLAY_ON 0x32
195 #define LCM_CMD_DISPLAY_OFF 0x12
196 #define LCM_CMD_CURSOR_ON 0x34
197 #define LCM_CMD_CURSOR_OFF 0x30
198 #define LCM_CMD_CHAR_BLINK 0x38
199 #define LCM_CMD_CURSOR_BLINK 0x3c
201 #define LCM_REG_SET_CH_PITCH 1 // setting the character pitch
202 #define LCM_H_PITCH_6 0x05
203 #define LCM_H_PITCH_7 0x06
204 #define LCM_H_PITCH_8 0x07
206 #define LCM_REG_SET_NO_CH 2 // setting the number of characters
207 #define LCM_REG_SET_TIME_DIV 3 // setting the time division number
208 #define LCM_REG_SET_CUR_POS 4 // setting the cursor position
209 #define LCM_REG_SET_DIS_LADDR 8 // setting the display start lower address
210 #define LCM_REG_SET_DIS_UADDR 9 // setting the display start upper address
211 #define LCM_REG_SET_CUR_LADDR 10 // setting the cursor (lower) address
212 #define LCM_REG_SET_CUR_UADDR 11 // setting the cursor (upper) address
213 #define LCM_REG_W_DIS_DATA 12 // writing display data
214 #define LCM_REG_R_DIS_DATA 13 // reading display data
216 #define LCM_REG_BIT_CLEAR 14 // bit clear
217 #define LCM_BIT_CLEAR_MASK 0x07
219 #define LCM_REG_BIT_SET 15 // bit set
220 #define LCM_BIT_SET 0x07
222 #define LCM_BUSY_FLAG 0x80 // when you read this bit,
223 // you must set RS & R/W are both high
225 // following LCM control
226 #define LCM_DATA 0
227 #define LCM_CMD (1<<8)
228 #define LCM_READ (1<<9)
229 #define LCM_WRITE 0
230 #define LCM_EBIT_ON (1<<10)
231 #define LCM_EBIT_OFF 0
232 #define LCM_BACK_LIGHT_ON 0
233 #define LCM_BACK_LIGHT_OFF (1<<11)
234 #define LCM_DISPLAY_OFF 0
235 #define LCM_DISPLAY_ON (1<<13)
236 #define LCM_CS_OFF (1<<12) // chip enable "active" L
237 #define LCM_CS_ON 0 // chip enable "active" L
238 #define LCM_WRITE_ENABLE 0
239 #define LCM_READ_ENABLE (1<<14)
241 #define LCM_MAX_X_DOTS 160 // max x dots (colum)
242 #define LCM_MAX_Y_DOTS 80 // max y dots (row)
243 #define LCM_X_DOTS 8 // x dots for each character
244 #define LCM_Y_DOTS 8 // y dots for each character
245 #define LCM_X_DOTS_MASK (LCM_X_DOTS-1)
246 #define LCM_Y_DOTS_MASK (LCM_Y_DOTS-1)
247 #define LCM_X_DOTS_SHIFT 3
248 #define LCM_Y_DOTS_SHIFT 3
249 #define LCM_MAX_X (LCM_MAX_X_DOTS/LCM_X_DOTS) // max x char.
250 #define LCM_MAX_Y (LCM_MAX_Y_DOTS/LCM_Y_DOTS) // max y char.
252 static unsigned char lcm_pix_buffer[LCM_MAX_X][LCM_MAX_Y_DOTS];
253 static u16 lcm_ctrl_data=LCM_DISPLAY_ON|LCM_BACK_LIGHT_ON;
254 static int lcm_auto_scroll_flag=1;
255 static int lcm_reverse_flag=0;
256 static unsigned short lcm_start_ram_address=0; // embedded on LCM module RAM
258 typedef struct lcm_xy {
259 int x; // 0 - LCM_MAX_X
260 int y; // 0 - LCM_MAX_Y
261 } lcm_xy_t;
263 #define LCM_NOT_LOCK_INT
264 #if 0
265 #define LCM_delay() udelay(1)
266 #else
267 #define LCM_delay()
268 #endif
270 static void LCM_write_register(u16 regno, u16 data)
272 #ifndef LCM_NOT_LOCK_INT
273 unsigned long flags;
275 save_flags(flags);
276 cli();
277 #endif
278 spin_lock(&lcm_lock);
280 // first write the register number
281 //outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_READ|LCM_CMD|LCM_READ_ENABLE|LCM_CS_ON, LCM_WRITE_ADDR);
282 outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_WRITE|LCM_CMD|LCM_WRITE_ENABLE|LCM_CS_ON|regno, LCM_WRITE_ADDR);
283 LCM_delay();
284 outw(lcm_ctrl_data|LCM_EBIT_ON|LCM_WRITE|LCM_CMD|LCM_WRITE_ENABLE|LCM_CS_ON|regno, LCM_WRITE_ADDR);
285 LCM_delay();
286 outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_WRITE|LCM_CMD|LCM_WRITE_ENABLE|LCM_CS_ON|regno, LCM_WRITE_ADDR);
287 //LCM_delay();
288 //outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_READ|LCM_CMD|LCM_READ_ENABLE|LCM_CS_OFF, LCM_WRITE_ADDR);
290 // second write the data for this register
291 //outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_READ|LCM_DATA|LCM_READ_ENABLE|LCM_CS_ON, LCM_WRITE_ADDR);
292 //LCM_delay();
293 outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_WRITE|LCM_DATA|LCM_WRITE_ENABLE|LCM_CS_ON|data, LCM_WRITE_ADDR);
294 LCM_delay();
295 outw(lcm_ctrl_data|LCM_EBIT_ON|LCM_WRITE|LCM_DATA|LCM_WRITE_ENABLE|LCM_CS_ON|data, LCM_WRITE_ADDR);
296 LCM_delay();
297 outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_WRITE|LCM_DATA|LCM_WRITE_ENABLE|LCM_CS_ON|data, LCM_WRITE_ADDR);
298 //LCM_delay();
299 outw(lcm_ctrl_data|LCM_EBIT_OFF|LCM_READ|LCM_DATA|LCM_READ_ENABLE|LCM_CS_OFF, LCM_WRITE_ADDR);
301 spin_unlock(&lcm_lock);
302 #ifndef LCM_NOT_LOCK_INT
303 restore_flags(flags);
304 #endif
307 static void lcm_up_one_line(void)
309 int x, y;
311 // first up one line for lcm buffer
312 spin_lock(&lcm_lock);
313 for ( y=1; y<LCM_MAX_Y; y++ ) {
314 for ( x=0; x<LCM_MAX_X; x++ ) {
315 memcpy(&lcm_pix_buffer[x][(y-1)*LCM_Y_DOTS], &lcm_pix_buffer[x][y*LCM_Y_DOTS], LCM_Y_DOTS);
318 for ( x=0; x<LCM_MAX_X; x++ ) {
319 if ( lcm_reverse_flag )
320 memset(&lcm_pix_buffer[x][(LCM_MAX_Y-1)*LCM_Y_DOTS], 1, LCM_Y_DOTS);
321 else
322 memset(&lcm_pix_buffer[x][(LCM_MAX_Y-1)*LCM_Y_DOTS], 0, LCM_Y_DOTS);
324 spin_unlock(&lcm_lock);
326 // set cursor address to be start ram address
327 LCM_write_register(LCM_REG_SET_CUR_LADDR, lcm_start_ram_address & 0xff);
328 LCM_write_register(LCM_REG_SET_CUR_UADDR, (lcm_start_ram_address >> 8) & 0xff);
330 // second redisplay up one line on LCM
331 LCM_write_register(LCM_REG_MODE_CONTROL, LCM_CMD_DISPLAY_OFF);
332 for ( y=0; y<LCM_MAX_Y_DOTS; y++ ) {
333 for ( x=0; x<LCM_MAX_X; x++ ) {
334 LCM_write_register(LCM_REG_W_DIS_DATA, lcm_pix_buffer[x][y]);
338 LCM_write_register(LCM_REG_MODE_CONTROL, LCM_CMD_DISPLAY_ON);
339 spin_lock(&lcm_lock);
340 lcmx = 0;
341 lcmy = (LCM_MAX_Y - 1) * LCM_Y_DOTS;
342 spin_unlock(&lcm_lock);
345 static void LCM_printf_char(unsigned char ch)
347 int index, i, j, k;
349 if ( ch == '\n' ) {
350 spin_lock(&lcm_lock);
351 for ( i=lcmx; i<LCM_MAX_X; i++ ) {
352 if ( lcm_reverse_flag )
353 memset(&lcm_pix_buffer[i][lcmy], 1, LCM_Y_DOTS);
354 else
355 memset(&lcm_pix_buffer[i][lcmy], 0, LCM_Y_DOTS);
357 lcmx = 0;
358 lcmy += LCM_Y_DOTS;
359 if ( lcmy >= LCM_MAX_Y_DOTS ) {
360 if ( lcm_auto_scroll_flag ) {
361 lcmy = (LCM_MAX_Y - 1) * LCM_Y_DOTS;
362 spin_unlock(&lcm_lock);
363 lcm_up_one_line();
364 return;
365 } else {
366 lcmy = 0;
369 spin_unlock(&lcm_lock);
370 return;
373 index = ch * LCM_X_DOTS;
374 for ( i=0, k=lcmy; i<LCM_Y_DOTS; i++, index++, k++ ) {
375 spin_lock(&lcm_lock);
376 if ( lcm_reverse_flag )
377 lcm_pix_buffer[lcmx][k] = ~fnt8x8[index];
378 else
379 lcm_pix_buffer[lcmx][k] = fnt8x8[index];
380 spin_unlock(&lcm_lock);
381 j = lcmx + (k * LCM_MAX_X) + lcm_start_ram_address;
382 LCM_write_register(LCM_REG_SET_CUR_LADDR, j & 0xff);
383 LCM_write_register(LCM_REG_SET_CUR_UADDR, (j >> 8) & 0xff);
384 LCM_write_register(LCM_REG_W_DIS_DATA, lcm_pix_buffer[lcmx][k]);
387 spin_lock(&lcm_lock);
388 lcmx++;
389 if ( lcmx >= LCM_MAX_X ) {
390 lcmx = 0;
391 lcmy += LCM_Y_DOTS;
392 if ( lcmy >= LCM_MAX_Y_DOTS ) {
393 if ( lcm_auto_scroll_flag ) {
394 lcmy = (LCM_MAX_Y - 1) * LCM_Y_DOTS;
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, 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[x][lcmy], 1, LCM_Y_DOTS);
414 else
415 memset(&lcm_pix_buffer[x][lcmy], 0, LCM_Y_DOTS);
416 spin_unlock(&lcm_lock);
419 i = lcmy * LCM_MAX_X + lcm_start_ram_address;
420 LCM_write_register(LCM_REG_SET_CUR_LADDR, i & 0xff);
421 LCM_write_register(LCM_REG_SET_CUR_UADDR, (i >> 8) & 0xff);
422 for ( i=0; i<LCM_Y_DOTS; i++ ) {
423 for ( x=0; x<LCM_MAX_X; x++ ) {
424 LCM_write_register(LCM_REG_W_DIS_DATA, lcm_pix_buffer[x][lcmy+i]);
428 spin_lock(&lcm_lock);
429 lcmx = 0;
430 spin_unlock(&lcm_lock);
433 static void LCM_cls(void)
435 int x, y;
437 LCM_write_register(LCM_REG_MODE_CONTROL, LCM_CMD_DISPLAY_OFF);
439 // set cursor address to be 0
440 LCM_write_register(LCM_REG_SET_CUR_LADDR, lcm_start_ram_address & 0xff);
441 LCM_write_register(LCM_REG_SET_CUR_UADDR, (lcm_start_ram_address >> 8) & 0xff);
443 for ( y=0; y<LCM_MAX_Y_DOTS; y++ ) {
444 // clear LCM hardware
445 for ( x=0; x<LCM_MAX_X; x++ ) {
446 spin_lock(&lcm_lock);
447 if ( lcm_reverse_flag )
448 lcm_pix_buffer[x][y] = 0xff;
449 else
450 lcm_pix_buffer[x][y] = 0;
451 spin_unlock(&lcm_lock);
452 if ( lcm_reverse_flag ) {
453 LCM_write_register(LCM_REG_W_DIS_DATA, 0xff);
454 } else {
455 LCM_write_register(LCM_REG_W_DIS_DATA, 0);
459 LCM_write_register(LCM_REG_MODE_CONTROL, LCM_CMD_DISPLAY_ON);
461 LCM_write_register(LCM_REG_SET_CUR_LADDR, lcm_start_ram_address & 0xff);
462 LCM_write_register(LCM_REG_SET_CUR_UADDR, (lcm_start_ram_address >> 8) & 0xff);
464 spin_lock(&lcm_lock);
465 lcmx = lcmy = 0;
466 spin_unlock(&lcm_lock);
470 * I don't know why cannot malloc memory from kernel.
471 * 03-10-2004 Victor Yu.
473 #define USE_WRITE_BUFFER
474 #ifdef USE_WRITE_BUFFER
475 static char write_buffer[LCM_MAX_X * LCM_MAX_Y];
476 #endif
477 static ssize_t lcm_write(struct file * filp, const char * buf, size_t count, loff_t *ppos)
479 #ifndef USE_WRITE_BUFFER
480 char *ptr;
481 #endif
482 int i;
484 if ( count == 0 )
485 return 0;
486 #ifdef USE_WRITE_BUFFER
487 if ( count > (LCM_MAX_X * LCM_MAX_Y) )
488 count = LCM_MAX_X * LCM_MAX_Y;
489 if ( copy_from_user(write_buffer, buf, count) ) {
490 return -EFAULT;
492 for ( i=0; i<count; i++ )
493 LCM_printf_char(write_buffer[i]);
494 #else
495 ptr = kmalloc(count, GFP_KERNEL);
496 if ( ptr == NULL )
497 return -ENOMEM;
498 if ( copy_from_user(ptr, buf, count) ) {
499 kfree(ptr);
500 return -EFAULT;
502 for ( i=0; i<count; i++ )
503 LCM_printf_char(*ptr++);
504 kfree(ptr);
505 #endif
506 return count;
509 static int lcm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
511 lcm_xy_t pos;
512 static unsigned char user_data;
514 switch ( cmd ) {
515 case IOCTL_LCM_PIX_ON :
516 case IOCTL_LCM_PIX_OFF :
518 unsigned char v, mask;
519 int i, x;
521 if ( copy_from_user(&pos, (void *)arg, sizeof(pos)) )
522 return -EFAULT;
523 if ( pos.x < 0 || pos.x >= LCM_MAX_X_DOTS || pos.y < 0 || pos.y >= LCM_MAX_Y_DOTS )
524 return -EINVAL;
525 spin_lock(&lcm_lock);
526 x = pos.x >> LCM_X_DOTS_SHIFT;
527 v = lcm_pix_buffer[x][pos.y];
528 mask = 1 << (pos.x & LCM_X_DOTS_MASK);
529 if ( cmd == IOCTL_LCM_PIX_ON )
530 v |= mask;
531 else
532 v &= ~mask;
533 lcm_pix_buffer[x][pos.y] = v;
534 spin_unlock(&lcm_lock);
535 i = (pos.y * LCM_MAX_X) + x + lcm_start_ram_address;
536 LCM_write_register(LCM_REG_SET_CUR_LADDR, i & 0xff);
537 LCM_write_register(LCM_REG_SET_CUR_UADDR, (i >> 8) & 0xff);
538 LCM_write_register(LCM_REG_W_DIS_DATA, lcm_pix_buffer[x][pos.y]);
539 break;
541 case IOCTL_LCM_GOTO_XY :
542 if ( copy_from_user(&pos, (void *)arg, sizeof(pos)) )
543 return -EFAULT;
544 if ( pos.x < 0 || pos.x >= LCM_MAX_X || pos.y < 0 || pos.y >= LCM_MAX_Y )
545 return -EINVAL;
546 spin_lock(&lcm_lock);
547 lcmx = pos.x;
548 lcmy = pos.y * LCM_Y_DOTS;
549 spin_unlock(&lcm_lock);
550 break;
551 case IOCTL_LCM_CLS :
552 LCM_cls();
553 break;
554 case IOCTL_LCM_CLEAN_LINE :
555 LCM_clear_line();
556 break;
557 case IOCTL_LCM_GET_XY :
558 spin_lock(&lcm_lock);
559 pos.x = lcmx;
560 pos.y = lcmy / LCM_Y_DOTS;
561 spin_unlock(&lcm_lock);
562 if ( copy_to_user((void *)arg, &pos,sizeof(pos)) )
563 return -EFAULT;
564 break;
565 case IOCTL_LCM_BACK_LIGHT_ON :
566 spin_lock(&lcm_lock);
567 lcm_ctrl_data &= ~LCM_BACK_LIGHT_OFF;
568 outw(lcm_ctrl_data, LCM_WRITE_ADDR);
569 spin_unlock(&lcm_lock);
570 break;
571 case IOCTL_LCM_BACK_LIGHT_OFF :
572 spin_lock(&lcm_lock);
573 lcm_ctrl_data |= LCM_BACK_LIGHT_OFF;
574 outw(lcm_ctrl_data, LCM_WRITE_ADDR);
575 spin_unlock(&lcm_lock);
576 break;
577 case IOCTL_LCM_AUTO_SCROLL_ON :
578 spin_lock(&lcm_lock);
579 lcm_auto_scroll_flag = 1;
580 spin_unlock(&lcm_lock);
581 break;
582 case IOCTL_LCM_AUTO_SCROLL_OFF :
583 spin_lock(&lcm_lock);
584 lcm_auto_scroll_flag = 0;
585 spin_unlock(&lcm_lock);
586 break;
587 case IOCTL_LCM_REVERSE_ON :
588 spin_lock(&lcm_lock);
589 lcm_reverse_flag = 1;
590 spin_unlock(&lcm_lock);
591 break;
592 case IOCTL_LCM_REVERSE_OFF :
593 spin_lock(&lcm_lock);
594 lcm_reverse_flag = 0;
595 spin_unlock(&lcm_lock);
596 break;
597 case IOCTL_LCM_SAVE_BYTE :
598 if ( copy_from_user(&user_data, (void *)arg, sizeof(user_data)) )
599 return -EFAULT;
600 break;
601 case IOCTL_LCM_WRITE_BYTE :
603 int i, x;
604 if ( copy_from_user(&pos, (void *)arg, sizeof(pos)) )
605 return -EFAULT;
606 if ( pos.x < 0 || pos.x >= LCM_MAX_X_DOTS || pos.y < 0 || pos.y >= LCM_MAX_Y_DOTS )
607 return -EINVAL;
608 spin_lock(&lcm_lock);
609 x = pos.x >> LCM_X_DOTS_SHIFT;
610 lcm_pix_buffer[x][pos.y] = user_data;
611 spin_unlock(&lcm_lock);
612 i = (pos.y * LCM_MAX_X) + x + lcm_start_ram_address;
613 LCM_write_register(LCM_REG_SET_CUR_LADDR, i & 0xff);
614 LCM_write_register(LCM_REG_SET_CUR_UADDR, (i >> 8) & 0xff);
615 LCM_write_register(LCM_REG_W_DIS_DATA, lcm_pix_buffer[x][pos.y]);
616 break;
618 case IOCTL_LCM_DISPLAY_OFF :
619 LCM_write_register(LCM_REG_MODE_CONTROL, LCM_CMD_DISPLAY_OFF);
620 break;
621 case IOCTL_LCM_DISPLAY_ON :
622 LCM_write_register(LCM_REG_MODE_CONTROL, LCM_CMD_DISPLAY_ON);
623 break;
624 default:
625 return -EINVAL;
628 return 0;
631 static int lcm_open(struct inode *inode, struct file *file)
633 if ( MINOR(inode->i_rdev) == MOXA_LCM_MINOR )
634 return 0;
635 return -ENODEV;
638 static int lcm_release(struct inode *inode, struct file *file)
640 return 0;
643 static struct file_operations lcm_fops = {
644 owner:THIS_MODULE,
645 llseek:NULL,
646 write:lcm_write,
647 ioctl:lcm_ioctl,
648 open:lcm_open,
649 release:lcm_release,
651 static struct miscdevice lcm_dev = {
652 MOXA_LCM_MINOR,
653 "lcm",
654 &lcm_fops
657 #if 1 // add by Victor Yu. 04-03-2007
658 extern int lcm_module_flag;
659 #endif
660 static void __exit ivtc_lcm3_exit(void)
662 misc_deregister(&lcm_dev);
663 lcm_module_flag = 0;
666 static int __init ivtc_lcm3_init(void)
668 printk("Moxa CPU misc: Register LCM module WG16080A misc ver1.0 ");
669 if ( lcm_module_flag ) {
670 printk("fail !\nThe other type LCM module device driver has loaded.\n");
671 return -ENOMEM;
673 if ( misc_register(&lcm_dev) ) {
674 printk("fail !\n");
675 return -ENOMEM;
677 lcm_module_flag = 1;
678 printk("OK.\n");
680 // setting the LCM to be graphic mode
681 LCM_write_register(LCM_REG_MODE_CONTROL, LCM_CMD_GRAPHIC_MODE);
682 LCM_write_register(LCM_REG_SET_CH_PITCH, 0x77);
683 LCM_write_register(LCM_REG_SET_NO_CH, LCM_MAX_X-1);
684 LCM_write_register(LCM_REG_SET_TIME_DIV, LCM_MAX_Y_DOTS-1);
686 // setting the start address is from 0
687 LCM_write_register(LCM_REG_SET_DIS_LADDR, lcm_start_ram_address & 0xff);
688 LCM_write_register(LCM_REG_SET_DIS_UADDR, (lcm_start_ram_address >> 8) & 0xff);
689 LCM_write_register(LCM_REG_SET_CUR_LADDR, lcm_start_ram_address & 0xff);
690 LCM_write_register(LCM_REG_SET_CUR_UADDR, (lcm_start_ram_address >> 8) & 0xff);
692 LCM_cls();
693 return 0;
696 module_init(ivtc_lcm3_init);
697 module_exit(ivtc_lcm3_exit);
699 MODULE_AUTHOR("Victor Yu");
700 MODULE_LICENSE("GPL");