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 WG12864C device driver.
8 * It is from misc interface. So the device node major number is 10.
9 * The device node minor number is following:
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
18 * 12-05-2005 Victor Yu. Create it.
19 * 09-03-2008 Victor Yu. Modify to support IVTC write byte feature.
21 #include <linux/config.h>
22 #include <asm/arch/moxa.h>
23 #include <linux/module.h>
24 #include <linux/kernel.h>
25 #include <linux/types.h>
26 #include <linux/miscdevice.h>
27 #include <linux/fcntl.h>
28 #include <linux/init.h>
29 #include <linux/poll.h>
30 #include <linux/proc_fs.h>
31 #include <linux/spinlock.h>
32 #include <linux/delay.h>
33 #include <linux/rtc.h>
34 #include <linux/timer.h>
35 #include <linux/ioport.h>
38 #include <asm/uaccess.h>
39 #include <asm/system.h>
42 #define LCM_READ_ADDR 0x84002000
43 #define LCM_WRITE_ADDR 0x84000000
45 #define MOXA_LCM_MINOR 102
47 static spinlock_t lcm_lock
= SPIN_LOCK_UNLOCKED
;
50 // LCM file operation function call
52 static unsigned char fnt8x8
[]={
53 0x3E,0x51,0x49,0x45,0x3E,0x00,0x00,0x00,0x40,0x42,0x7F,0x40,0x40,0x00,0x00,0x00,
54 0x42,0x61,0x51,0x49,0x66,0x00,0x00,0x00,0x22,0x49,0x49,0x49,0x36,0x00,0x00,0x00,
55 0x18,0x14,0x52,0x7F,0x50,0x00,0x00,0x00,0x27,0x45,0x45,0x45,0x39,0x00,0x00,0x00,
56 0x3C,0x4A,0x49,0x49,0x32,0x00,0x00,0x00,0x03,0x01,0x79,0x05,0x03,0x00,0x00,0x00,
57 0x36,0x49,0x49,0x49,0x36,0x00,0x00,0x00,0x26,0x49,0x49,0x49,0x3E,0x00,0x00,0x00,
58 0x7C,0x12,0x11,0x12,0x7C,0x00,0x00,0x00,0x41,0x7F,0x49,0x49,0x36,0x00,0x00,0x00,
59 0x1C,0x22,0x41,0x41,0x22,0x00,0x00,0x00,0x7F,0x41,0x41,0x22,0x1C,0x00,0x00,0x00,
60 0x41,0x7F,0x49,0x49,0x63,0x00,0x00,0x00,0x41,0x7F,0x49,0x09,0x03,0x00,0x00,0x00,
61 0x7F,0x3E,0x3E,0x1C,0x1C,0x08,0x08,0x00,0x08,0x08,0x1C,0x1C,0x3E,0x3E,0x7F,0x00,
62 0x00,0x24,0x66,0xFF,0xFF,0x66,0x24,0x00,0x00,0x5F,0x5F,0x00,0x00,0x5F,0x5F,0x00,
63 0x06,0x0F,0x09,0x7F,0x7F,0x01,0x7F,0x7F,0x40,0xDA,0xBF,0xA5,0xFD,0x59,0x03,0x02,
64 0x00,0x70,0x70,0x70,0x70,0x70,0x70,0x00,0x80,0x94,0xB6,0xFF,0xFF,0xB6,0x94,0x80,
65 0x00,0x04,0x06,0x7F,0x7F,0x06,0x04,0x00,0x00,0x10,0x30,0x7F,0x7F,0x30,0x10,0x00,
66 0x08,0x08,0x08,0x2A,0x3E,0x1C,0x08,0x00,0x08,0x1C,0x3E,0x2A,0x08,0x08,0x08,0x00,
67 0x3C,0x3C,0x20,0x20,0x20,0x20,0x20,0x00,0x08,0x1C,0x3E,0x08,0x08,0x3E,0x1C,0x08,
68 0x30,0x38,0x3C,0x3E,0x3E,0x3C,0x38,0x30,0x06,0x0E,0x1E,0x3E,0x3E,0x1E,0x0E,0x06,
69 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5F,0x00,0x00,0x00,0x00,
70 0x00,0x07,0x00,0x00,0x00,0x07,0x00,0x00,0x14,0x7F,0x14,0x14,0x14,0x7F,0x14,0x00,
71 0x24,0x2A,0x6B,0x2A,0x10,0x00,0x00,0x00,0x43,0x23,0x10,0x08,0x04,0x62,0x61,0x00,
72 0x32,0x4D,0x49,0x4D,0x52,0x28,0x40,0x00,0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
73 0x00,0x00,0x1C,0x22,0x41,0x00,0x00,0x00,0x00,0x00,0x41,0x22,0x1C,0x00,0x00,0x00,
74 0x08,0x2A,0x1C,0x08,0x08,0x1C,0x2A,0x08,0x00,0x08,0x08,0x3E,0x08,0x08,0x00,0x00,
75 0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00,0x08,0x08,0x08,0x08,0x08,0x00,0x00,0x00,
76 0x00,0x00,0x60,0x60,0x00,0x00,0x00,0x00,0x40,0x20,0x10,0x08,0x04,0x02,0x01,0x00,
77 0x3E,0x61,0x51,0x49,0x45,0x43,0x3E,0x00,0x40,0x42,0x7F,0x40,0x40,0x00,0x00,0x00,
78 0x62,0x51,0x51,0x49,0x49,0x46,0x00,0x00,0x22,0x41,0x41,0x49,0x49,0x36,0x00,0x00,
79 0x18,0x14,0x12,0x11,0x51,0x7F,0x50,0x00,0x27,0x45,0x45,0x45,0x45,0x39,0x00,0x00,
80 0x3C,0x4A,0x49,0x49,0x48,0x30,0x00,0x00,0x03,0x01,0x01,0x71,0x09,0x07,0x00,0x00,
81 0x36,0x49,0x49,0x49,0x49,0x36,0x00,0x00,0x06,0x49,0x49,0x49,0x29,0x1E,0x00,0x00,
82 0x00,0x00,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x66,0x00,0x00,0x00,0x00,0x00,
83 0x08,0x14,0x22,0x41,0x00,0x00,0x00,0x00,0x24,0x24,0x24,0x24,0x24,0x00,0x00,0x00,
84 0x00,0x00,0x41,0x22,0x14,0x08,0x00,0x00,0x02,0x01,0x01,0x51,0x09,0x06,0x00,0x00,
85 0x3E,0x41,0x41,0x51,0x51,0x11,0x0E,0x00,0x7C,0x12,0x11,0x12,0x7C,0x00,0x00,0x00,
86 0x41,0x7F,0x49,0x49,0x49,0x36,0x00,0x00,0x1C,0x22,0x41,0x41,0x41,0x22,0x00,0x00,
87 0x41,0x7F,0x41,0x41,0x41,0x22,0x1C,0x00,0x7F,0x49,0x49,0x49,0x41,0x41,0x41,0x00,
88 0x7F,0x09,0x09,0x09,0x01,0x01,0x01,0x00,0x1C,0x22,0x41,0x41,0x41,0x51,0x32,0x00,
89 0x7F,0x08,0x08,0x08,0x08,0x7F,0x00,0x00,0x00,0x41,0x7F,0x41,0x00,0x00,0x00,0x00,
90 0x30,0x40,0x40,0x40,0x41,0x3F,0x01,0x00,0x00,0x7F,0x08,0x08,0x08,0x14,0x63,0x00,
91 0x00,0x7F,0x40,0x40,0x40,0x40,0x40,0x00,0x7F,0x02,0x04,0x08,0x04,0x02,0x7F,0x00,
92 0x7F,0x02,0x04,0x08,0x10,0x20,0x7F,0x00,0x1C,0x22,0x41,0x41,0x41,0x22,0x1C,0x00,
93 0x00,0x7F,0x09,0x09,0x09,0x09,0x06,0x00,0x1E,0x21,0x21,0x21,0x61,0x5E,0x00,0x00,
94 0x7F,0x09,0x09,0x09,0x19,0x66,0x00,0x00,0x26,0x49,0x49,0x49,0x49,0x32,0x00,0x00,
95 0x01,0x01,0x01,0x7F,0x01,0x01,0x01,0x00,0x3F,0x40,0x40,0x40,0x40,0x3F,0x00,0x00,
96 0x1F,0x20,0x40,0x40,0x20,0x1F,0x00,0x00,0x7F,0x20,0x10,0x08,0x10,0x20,0x7F,0x00,
97 0x41,0x22,0x14,0x08,0x14,0x22,0x41,0x00,0x07,0x08,0x78,0x08,0x07,0x00,0x00,0x00,
98 0x41,0x61,0x51,0x49,0x45,0x43,0x41,0x00,0x00,0x7F,0x41,0x41,0x41,0x00,0x00,0x00,
99 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x00,0x00,0x41,0x41,0x41,0x7F,0x00,0x00,0x00,
100 0x08,0x04,0x02,0x01,0x02,0x04,0x08,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
101 0x00,0x00,0x00,0x03,0x04,0x00,0x00,0x00,0x20,0x54,0x54,0x54,0x14,0x78,0x40,0x00,
102 0x00,0x7F,0x48,0x48,0x48,0x48,0x30,0x00,0x38,0x44,0x44,0x44,0x44,0x28,0x00,0x00,
103 0x30,0x48,0x48,0x48,0x48,0x3F,0x00,0x00,0x38,0x54,0x54,0x54,0x54,0x08,0x00,0x00,
104 0x08,0x7E,0x09,0x09,0x01,0x02,0x00,0x00,0x98,0xA4,0xA4,0xA4,0xA4,0x78,0x00,0x00,
105 0x00,0x7F,0x08,0x08,0x08,0x08,0x70,0x00,0x00,0x00,0x00,0x7D,0x00,0x00,0x00,0x00,
106 0x60,0x80,0x80,0x80,0x80,0x7D,0x00,0x00,0x7F,0x10,0x10,0x10,0x28,0x44,0x00,0x00,
107 0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x78,0x04,0x08,0x10,0x08,0x04,0x78,0x00,
108 0x7C,0x04,0x04,0x04,0x04,0x78,0x00,0x00,0x38,0x44,0x44,0x44,0x44,0x38,0x00,0x00,
109 0xFC,0x24,0x24,0x24,0x24,0x18,0x00,0x00,0x18,0x24,0x24,0x24,0x24,0xFC,0x00,0x00,
110 0x7C,0x08,0x04,0x04,0x04,0x08,0x00,0x00,0x48,0x54,0x54,0x54,0x54,0x24,0x00,0x00,
111 0x00,0x00,0x04,0x7F,0x04,0x00,0x00,0x00,0x3C,0x40,0x40,0x40,0x40,0x3C,0x00,0x00,
112 0x1C,0x20,0x40,0x40,0x20,0x1C,0x00,0x00,0x3C,0x40,0x20,0x10,0x20,0x40,0x3C,0x00,
113 0x00,0x44,0x28,0x10,0x28,0x44,0x00,0x00,0x9C,0xA0,0xA0,0xA0,0xA0,0x7C,0x00,0x00,
114 0x44,0x44,0x64,0x54,0x4C,0x44,0x00,0x00,0x00,0x08,0x08,0x36,0x41,0x41,0x00,0x00,
115 0x00,0x00,0x00,0x77,0x00,0x00,0x00,0x00,0x41,0x41,0x36,0x08,0x08,0x00,0x00,0x00,
116 0x02,0x03,0x01,0x03,0x02,0x03,0x01,0x00,0x70,0x48,0x44,0x42,0x44,0x48,0x70,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,
180 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
182 static int lcmx
, lcmy
; // dots position
184 // following on LCM command
185 #define LCM_CMD_DISPLAY_ON 0x3f
186 #define LCM_CMD_DISPLAY_OFF 0x3e
187 #define LCM_CMD_DISPLAY_START_LINE 0xc0
188 #define LCM_DISPLAY_START_LINE_MASK 0x3F // 0-63
189 #define LCM_CMD_SET_PAGE 0xb8 // x address
190 #define LCM_SET_PAGE_MASK 0x07 // x address 0-7
191 #define LCM_CMD_SET_ADDRESS 0x40 // y address, from 0x40 to 0xc0
192 #define LCM_SET_ADDRESS_MASK 0x3F // y address 0-63
193 #define LCM_STATUS_BUSY 0x80
194 #define LCM_STATUS_ON 0x20
195 #define LCM_STATUS_RESET 0x10
196 #define LCM_MODE_SELECT 0x05
198 // following LCM control
199 #define LCM_DATA (1<<8)
201 #define LCM_READ (1<<9)
203 #define LCM_EBIT_ON (1<<10)
204 #define LCM_EBIT_OFF 0
205 #define LCM_BACK_LIGHT_ON (1<<11)
206 #define LCM_BACK_LIGHT_OFF 0
207 #define LCM_CS1 (1<<13)
208 #define LCM_CS2 (1<<12)
209 #define LCM_WRITE_ENABLE (1<<14)
210 #define LCM_READ_ENABLE 0
211 #define LCM_DATA_MASK 0xff
213 #define LCM_MAX_X_DOTS 128
214 #define LCM_MAX_Y_DOTS 64
215 #define LCM_HALF_X_DOTS (LCM_MAX_X_DOTS/2)
218 #define LCM_MAX_X (LCM_MAX_X_DOTS/LCM_X_DOTS)
219 #define LCM_MAX_Y (LCM_MAX_Y_DOTS/LCM_Y_DOTS)
221 static unsigned char lcm_pix_buffer
[LCM_MAX_Y
][LCM_MAX_X_DOTS
];
222 static u16 lcm_ctrl_data
=LCM_BACK_LIGHT_ON
;
223 static int lcm_auto_scroll_flag
=1;
224 static int lcm_reverse_flag
=0;
225 typedef struct lcm_xy
{
230 #define LCM_NOT_LOCK_INT
232 static void LCM_write_cmd(u16 cmd
, u16 cs
)
234 #ifndef LCM_NOT_LOCK_INT
240 spin_lock(&lcm_lock
);
241 outw(lcm_ctrl_data
|LCM_EBIT_OFF
|LCM_READ
|LCM_CMD
|LCM_READ_ENABLE
|cs
, LCM_WRITE_ADDR
);
242 outw(lcm_ctrl_data
|LCM_EBIT_OFF
|LCM_WRITE
|LCM_CMD
|LCM_READ_ENABLE
|cs
, LCM_WRITE_ADDR
);
244 outw(lcm_ctrl_data
|LCM_EBIT_ON
|LCM_WRITE
|LCM_CMD
|LCM_READ_ENABLE
|cs
|cmd
, LCM_WRITE_ADDR
);
246 outw(lcm_ctrl_data
|LCM_EBIT_OFF
|LCM_WRITE
|LCM_CMD
|LCM_WRITE_ENABLE
|cs
|cmd
, LCM_WRITE_ADDR
);
247 outw(lcm_ctrl_data
|LCM_EBIT_OFF
|LCM_READ
|LCM_CMD
|LCM_READ_ENABLE
|cs
, LCM_WRITE_ADDR
);
248 spin_unlock(&lcm_lock
);
249 #ifndef LCM_NOT_LOCK_INT
250 restore_flags(flags
);
254 static void LCM_write_data(unsigned char data
, u16 cs
)
256 #ifndef LCM_NOT_LOCK_INT
262 spin_lock(&lcm_lock
);
263 outw(lcm_ctrl_data
|LCM_EBIT_OFF
|LCM_READ
|LCM_DATA
|LCM_READ_ENABLE
|cs
, LCM_WRITE_ADDR
);
264 outw(lcm_ctrl_data
|LCM_EBIT_OFF
|LCM_WRITE
|LCM_DATA
|LCM_READ_ENABLE
|cs
, LCM_WRITE_ADDR
);
266 outw(lcm_ctrl_data
|LCM_EBIT_ON
|LCM_WRITE
|LCM_DATA
|LCM_READ_ENABLE
|cs
|(u16
)data
, LCM_WRITE_ADDR
);
268 outw(lcm_ctrl_data
|LCM_EBIT_OFF
|LCM_WRITE
|LCM_DATA
|LCM_WRITE_ENABLE
|cs
|(u16
)data
, LCM_WRITE_ADDR
);
269 outw(lcm_ctrl_data
|LCM_EBIT_OFF
|LCM_READ
|LCM_DATA
|LCM_READ_ENABLE
|cs
, LCM_WRITE_ADDR
);
270 spin_unlock(&lcm_lock
);
271 #ifndef LCM_NOT_LOCK_INT
272 restore_flags(flags
);
276 static void lcm_up_one_line(void)
280 // first up one line for lcm buffer
281 spin_lock(&lcm_lock
);
282 for ( y
=1; y
<LCM_MAX_Y
; y
++ ) {
283 for ( x
=0; x
<LCM_MAX_X
; x
++ ) {
284 memcpy(&lcm_pix_buffer
[y
-1][x
*LCM_X_DOTS
], &lcm_pix_buffer
[y
][x
*LCM_X_DOTS
], LCM_X_DOTS
);
287 for ( x
=0; x
<LCM_MAX_X
; x
++ ) {
288 memset(&lcm_pix_buffer
[LCM_MAX_Y
-1][x
*LCM_X_DOTS
], 0, LCM_X_DOTS
);
290 spin_unlock(&lcm_lock
);
292 // second redisplay up one line on LCM
293 LCM_write_cmd(LCM_CMD_DISPLAY_OFF
, LCM_CS1
);
294 LCM_write_cmd(LCM_CMD_DISPLAY_OFF
, LCM_CS2
);
295 for ( y
=0; y
<LCM_MAX_Y
; y
++ ) {
296 for ( x
=0; x
<LCM_MAX_X
; x
++ ) {
298 LCM_write_cmd(LCM_CMD_SET_ADDRESS
, LCM_CS1
);
299 LCM_write_cmd(LCM_CMD_SET_PAGE
| (y
& LCM_SET_PAGE_MASK
), LCM_CS1
);
300 } else if ( x
== (LCM_HALF_X_DOTS
/LCM_X_DOTS
) ) {
301 LCM_write_cmd(LCM_CMD_SET_ADDRESS
, LCM_CS2
);
302 LCM_write_cmd(LCM_CMD_SET_PAGE
| (y
& LCM_SET_PAGE_MASK
), LCM_CS2
);
304 index
= x
* LCM_X_DOTS
;
305 for ( i
=0; i
<LCM_X_DOTS
; i
++, index
++ ) {
306 if ( x
< (LCM_HALF_X_DOTS
/LCM_X_DOTS
) ) {
307 LCM_write_data(lcm_pix_buffer
[y
][index
], LCM_CS1
);
309 LCM_write_data(lcm_pix_buffer
[y
][index
], LCM_CS2
);
314 LCM_write_cmd(LCM_CMD_DISPLAY_ON
, LCM_CS1
);
315 LCM_write_cmd(LCM_CMD_DISPLAY_ON
, LCM_CS2
);
316 spin_lock(&lcm_lock
);
318 lcmy
= LCM_MAX_Y
- 1;
319 spin_unlock(&lcm_lock
);
322 static void LCM_printf_char(unsigned char ch
)
327 spin_lock(&lcm_lock
);
328 for ( i
=(lcmx
/LCM_X_DOTS
); i
<LCM_MAX_X
; i
++ ) {
329 if ( lcm_reverse_flag
)
330 memset(&lcm_pix_buffer
[lcmy
][i
*LCM_X_DOTS
], 1, LCM_X_DOTS
);
332 memset(&lcm_pix_buffer
[lcmy
][i
*LCM_X_DOTS
], 0, LCM_X_DOTS
);
336 if ( lcmy
>= LCM_MAX_Y
) {
337 if ( lcm_auto_scroll_flag
) {
338 lcmy
= LCM_MAX_Y
- 1;
339 spin_unlock(&lcm_lock
);
346 spin_unlock(&lcm_lock
);
349 if ( lcmx
< LCM_HALF_X_DOTS
) {
350 LCM_write_cmd(LCM_CMD_SET_ADDRESS
|(unsigned char)lcmx
, LCM_CS1
);
351 LCM_write_cmd(LCM_CMD_SET_PAGE
| (lcmy
& LCM_SET_PAGE_MASK
), LCM_CS1
);
353 LCM_write_cmd(LCM_CMD_SET_ADDRESS
|(unsigned char)(lcmx
-LCM_HALF_X_DOTS
), LCM_CS2
);
354 LCM_write_cmd(LCM_CMD_SET_PAGE
| (lcmy
& LCM_SET_PAGE_MASK
), LCM_CS2
);
356 index
= ch
* LCM_Y_DOTS
;
357 for ( i
=0; i
<LCM_X_DOTS
; i
++, index
++, lcmx
++ ) {
358 spin_lock(&lcm_lock
);
359 if ( lcm_reverse_flag
)
360 lcm_pix_buffer
[lcmy
][lcmx
] = ~fnt8x8
[index
];
362 lcm_pix_buffer
[lcmy
][lcmx
] = fnt8x8
[index
];
363 spin_unlock(&lcm_lock
);
364 if ( lcmx
< LCM_HALF_X_DOTS
)
365 LCM_write_data(fnt8x8
[index
], LCM_CS1
);
367 LCM_write_data(fnt8x8
[index
], LCM_CS2
);
369 spin_lock(&lcm_lock
);
370 if ( lcmx
>= LCM_MAX_X_DOTS
) {
373 if ( lcmy
>= LCM_MAX_Y
) {
374 if ( lcm_auto_scroll_flag
) {
375 lcmy
= LCM_MAX_Y
- 1;
376 spin_unlock(&lcm_lock
);
384 spin_unlock(&lcm_lock
);
387 static void LCM_clear_line(void)
391 for ( x
=0; x
<LCM_MAX_X
; x
++ ) {
392 spin_lock(&lcm_lock
);
393 if ( lcm_reverse_flag
)
394 memset(&lcm_pix_buffer
[lcmy
][x
*LCM_X_DOTS
], 1, LCM_X_DOTS
);
396 memset(&lcm_pix_buffer
[lcmy
][x
*LCM_X_DOTS
], 0, LCM_X_DOTS
);
397 spin_unlock(&lcm_lock
);
399 LCM_write_cmd(LCM_CMD_SET_ADDRESS
, LCM_CS1
);
400 LCM_write_cmd(LCM_CMD_SET_PAGE
| (lcmy
& LCM_SET_PAGE_MASK
), LCM_CS1
);
401 } else if ( x
== (LCM_HALF_X_DOTS
/LCM_X_DOTS
) ) {
402 LCM_write_cmd(LCM_CMD_SET_ADDRESS
, LCM_CS2
);
403 LCM_write_cmd(LCM_CMD_SET_PAGE
| (lcmy
& LCM_SET_PAGE_MASK
), LCM_CS2
);
405 index
= x
* LCM_X_DOTS
;
406 for ( i
=0; i
<LCM_X_DOTS
; i
++, index
++ ) {
407 if ( x
< (LCM_HALF_X_DOTS
/LCM_X_DOTS
) ) {
408 LCM_write_data(lcm_pix_buffer
[lcmy
][index
], LCM_CS1
);
410 LCM_write_data(lcm_pix_buffer
[lcmy
][index
], LCM_CS2
);
414 spin_lock(&lcm_lock
);
416 spin_unlock(&lcm_lock
);
419 static void LCM_cls(void)
423 LCM_write_cmd(LCM_CMD_DISPLAY_OFF
, LCM_CS1
);
424 LCM_write_cmd(LCM_CMD_DISPLAY_OFF
, LCM_CS2
);
425 for ( y
=0; y
<LCM_MAX_Y
; y
++ ) {
426 // clear LCM hardware
427 for ( x
=0; x
<LCM_MAX_X_DOTS
; x
++ ) {
429 LCM_write_cmd(LCM_CMD_SET_ADDRESS
, LCM_CS1
);
430 LCM_write_cmd(LCM_CMD_SET_PAGE
| (y
& LCM_SET_PAGE_MASK
), LCM_CS1
);
431 } else if ( x
== LCM_HALF_X_DOTS
) {
432 LCM_write_cmd(LCM_CMD_SET_ADDRESS
, LCM_CS2
);
433 LCM_write_cmd(LCM_CMD_SET_PAGE
| (y
& LCM_SET_PAGE_MASK
), LCM_CS2
);
435 spin_lock(&lcm_lock
);
436 if ( lcm_reverse_flag
)
437 lcm_pix_buffer
[y
][x
] = 0xff;
439 lcm_pix_buffer
[y
][x
] = 0;
440 spin_unlock(&lcm_lock
);
441 if ( lcm_reverse_flag
) {
442 if ( x
< LCM_HALF_X_DOTS
)
443 LCM_write_data(0xff, LCM_CS1
);
445 LCM_write_data(0xff, LCM_CS2
);
447 if ( x
< LCM_HALF_X_DOTS
)
448 LCM_write_data(0, LCM_CS1
);
450 LCM_write_data(0, LCM_CS2
);
454 LCM_write_cmd(LCM_CMD_DISPLAY_ON
, LCM_CS1
);
455 LCM_write_cmd(LCM_CMD_DISPLAY_ON
, LCM_CS2
);
456 spin_lock(&lcm_lock
);
458 spin_unlock(&lcm_lock
);
462 * I don't know why cannot malloc memory from kernel.
463 * 03-10-2004 Victor Yu.
465 #define USE_WRITE_BUFFER
466 static ssize_t
lcm_write(struct file
* filp
, const char * buf
, size_t count
, loff_t
*ppos
)
468 #ifdef USE_WRITE_BUFFER
469 char write_buffer
[LCM_MAX_X
* LCM_MAX_Y
];
477 #ifdef USE_WRITE_BUFFER
478 if ( count
> (LCM_MAX_X
* LCM_MAX_Y
) )
479 count
= LCM_MAX_X
* LCM_MAX_Y
;
480 if ( copy_from_user(write_buffer
, buf
, count
) ) {
483 for ( i
=0; i
<count
; i
++ )
484 LCM_printf_char(write_buffer
[i
]);
486 ptr
= kmalloc(count
, GFP_KERNEL
);
489 if ( copy_from_user(ptr
, buf
, count
) ) {
493 for ( i
=0; i
<count
; i
++ )
494 LCM_printf_char(*ptr
++);
500 static int lcm_ioctl(struct inode
*inode
, struct file
*file
, unsigned int cmd
, unsigned long arg
)
503 static unsigned char user_data
;
506 case IOCTL_LCM_PIX_ON
:
507 case IOCTL_LCM_PIX_OFF
:
509 unsigned char v
, mask
;
511 if ( copy_from_user(&pos
, (void *)arg
, sizeof(pos
)) )
513 if ( pos
.x
< 0 || pos
.x
>= LCM_MAX_X_DOTS
|| pos
.y
< 0 || pos
.y
>= LCM_MAX_Y_DOTS
)
515 spin_lock(&lcm_lock
);
516 v
= lcm_pix_buffer
[pos
.y
/LCM_Y_DOTS
][pos
.x
];
517 mask
= 1 << (pos
.y
% LCM_Y_DOTS
);
518 if ( cmd
== IOCTL_LCM_PIX_ON
)
522 lcm_pix_buffer
[pos
.y
/LCM_Y_DOTS
][pos
.x
] = v
;
523 spin_unlock(&lcm_lock
);
524 if ( pos
.x
< LCM_HALF_X_DOTS
) {
525 LCM_write_cmd(LCM_CMD_SET_ADDRESS
|(unsigned char)pos
.x
, LCM_CS1
);
526 LCM_write_cmd(LCM_CMD_SET_PAGE
| ((pos
.y
/LCM_Y_DOTS
) & LCM_SET_PAGE_MASK
), LCM_CS1
);
527 LCM_write_data(v
, LCM_CS1
);
529 LCM_write_cmd(LCM_CMD_SET_ADDRESS
|(unsigned char)(pos
.x
-LCM_HALF_X_DOTS
), LCM_CS2
);
530 LCM_write_cmd(LCM_CMD_SET_PAGE
| ((pos
.y
/LCM_Y_DOTS
) & LCM_SET_PAGE_MASK
), LCM_CS2
);
531 LCM_write_data(v
, LCM_CS2
);
535 case IOCTL_LCM_GOTO_XY
:
536 if ( copy_from_user(&pos
, (void *)arg
, sizeof(pos
)) )
538 if ( pos
.x
< 0 || pos
.x
>= LCM_MAX_X
|| pos
.y
< 0 || pos
.y
>= LCM_MAX_Y
)
540 spin_lock(&lcm_lock
);
541 lcmx
= pos
.x
* LCM_X_DOTS
;
543 spin_unlock(&lcm_lock
);
548 case IOCTL_LCM_CLEAN_LINE
:
551 case IOCTL_LCM_GET_XY
:
552 spin_lock(&lcm_lock
);
553 pos
.x
= lcmx
/ LCM_X_DOTS
;
555 spin_unlock(&lcm_lock
);
556 if ( copy_to_user((void *)arg
, &pos
,sizeof(pos
)) )
559 case IOCTL_LCM_BACK_LIGHT_ON
:
560 spin_lock(&lcm_lock
);
561 lcm_ctrl_data
|= LCM_BACK_LIGHT_ON
;
562 outw(lcm_ctrl_data
, LCM_WRITE_ADDR
);
563 spin_unlock(&lcm_lock
);
565 case IOCTL_LCM_BACK_LIGHT_OFF
:
566 spin_lock(&lcm_lock
);
567 lcm_ctrl_data
&= ~LCM_BACK_LIGHT_ON
;
568 outw(lcm_ctrl_data
, LCM_WRITE_ADDR
);
569 spin_unlock(&lcm_lock
);
571 case IOCTL_LCM_AUTO_SCROLL_ON
:
572 spin_lock(&lcm_lock
);
573 lcm_auto_scroll_flag
= 1;
574 spin_unlock(&lcm_lock
);
576 case IOCTL_LCM_AUTO_SCROLL_OFF
:
577 spin_lock(&lcm_lock
);
578 lcm_auto_scroll_flag
= 0;
579 spin_unlock(&lcm_lock
);
581 case IOCTL_LCM_REVERSE_ON
:
582 spin_lock(&lcm_lock
);
583 lcm_reverse_flag
= 1;
584 spin_unlock(&lcm_lock
);
586 case IOCTL_LCM_REVERSE_OFF
:
587 spin_lock(&lcm_lock
);
588 lcm_reverse_flag
= 0;
589 spin_unlock(&lcm_lock
);
591 case IOCTL_LCM_SAVE_BYTE
:
592 if ( copy_from_user(&user_data
, (void *)arg
, sizeof(user_data
)) )
595 case IOCTL_LCM_WRITE_BYTE
:
597 unsigned char v
, mask
, cbit
;
599 if ( copy_from_user(&pos
, (void *)arg
, sizeof(pos
)) )
601 if ( pos
.x
< 0 || pos
.x
>= LCM_MAX_X_DOTS
|| pos
.y
< 0 || pos
.y
>= LCM_MAX_Y_DOTS
)
603 spin_lock(&lcm_lock
);
604 y
= pos
.y
/ LCM_Y_DOTS
;
605 ybit
= pos
.y
% LCM_Y_DOTS
;
606 for ( i
=0, x
=pos
.x
, cbit
=1; i
<sizeof(unsigned char); i
++, x
++, cbit
<<=1 ) {
607 v
= lcm_pix_buffer
[y
][x
];
609 if ( user_data
& cbit
)
613 lcm_pix_buffer
[y
][x
] = v
;
615 spin_unlock(&lcm_lock
);
616 for ( i
=0, x
=pos
.x
; i
<sizeof(unsigned char); i
++, x
++ ) {
617 if ( x
< LCM_HALF_X_DOTS
) {
618 LCM_write_cmd(LCM_CMD_SET_ADDRESS
|(unsigned char)x
, LCM_CS1
);
619 LCM_write_cmd(LCM_CMD_SET_PAGE
| (y
& LCM_SET_PAGE_MASK
), LCM_CS1
);
620 LCM_write_data(lcm_pix_buffer
[y
][x
], LCM_CS1
);
622 LCM_write_cmd(LCM_CMD_SET_ADDRESS
|(unsigned char)(x
-LCM_HALF_X_DOTS
), LCM_CS2
);
623 LCM_write_cmd(LCM_CMD_SET_PAGE
| (y
& LCM_SET_PAGE_MASK
), LCM_CS2
);
624 LCM_write_data(lcm_pix_buffer
[y
][x
], LCM_CS2
);
629 case IOCTL_LCM_DISPLAY_OFF
:
630 LCM_write_cmd(LCM_CMD_DISPLAY_OFF
, LCM_CS1
);
631 LCM_write_cmd(LCM_CMD_DISPLAY_OFF
, LCM_CS2
);
633 case IOCTL_LCM_DISPLAY_ON
:
634 LCM_write_cmd(LCM_CMD_DISPLAY_ON
, LCM_CS1
);
635 LCM_write_cmd(LCM_CMD_DISPLAY_ON
, LCM_CS2
);
644 static int lcm_open(struct inode
*inode
, struct file
*file
)
646 if ( MINOR(inode
->i_rdev
) == MOXA_LCM_MINOR
)
651 static int lcm_release(struct inode
*inode
, struct file
*file
)
656 static struct file_operations lcm_fops
= {
664 static struct miscdevice lcm_dev
= {
670 #if 1 // add by Victor Yu. 04-03-2007
671 extern int lcm_module_flag
;
673 static void __exit
ivtc_lcm0_exit(void)
675 misc_deregister(&lcm_dev
);
679 static int __init
ivtc_lcm0_init(void)
681 printk("Moxa CPU misc: Register LCM module WG12864C misc ver1.0 ");
682 if ( lcm_module_flag
) {
683 printk("fail !\nThe other type LCM module device driver has loaded.\n");
686 if ( misc_register(&lcm_dev
) ) {
696 module_init(ivtc_lcm0_init
);
697 module_exit(ivtc_lcm0_exit
);
699 MODULE_AUTHOR("Victor Yu");
700 MODULE_LICENSE("GPL");