Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/auxdisplay/cfag12864b.c
26278 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Filename: cfag12864b.c
4
* Version: 0.1.0
5
* Description: cfag12864b LCD driver
6
* Depends: ks0108
7
*
8
* Author: Copyright (C) Miguel Ojeda <[email protected]>
9
* Date: 2006-10-31
10
*/
11
12
#include <linux/init.h>
13
#include <linux/module.h>
14
#include <linux/kernel.h>
15
#include <linux/fs.h>
16
#include <linux/slab.h>
17
#include <linux/cdev.h>
18
#include <linux/delay.h>
19
#include <linux/device.h>
20
#include <linux/jiffies.h>
21
#include <linux/mutex.h>
22
#include <linux/uaccess.h>
23
#include <linux/vmalloc.h>
24
#include <linux/workqueue.h>
25
#include <linux/ks0108.h>
26
#include <linux/cfag12864b.h>
27
28
29
#define CFAG12864B_NAME "cfag12864b"
30
31
/*
32
* Module Parameters
33
*/
34
35
static unsigned int cfag12864b_rate = CONFIG_CFAG12864B_RATE;
36
module_param(cfag12864b_rate, uint, 0444);
37
MODULE_PARM_DESC(cfag12864b_rate,
38
"Refresh rate (hertz)");
39
40
/*
41
* cfag12864b Commands
42
*
43
* E = Enable signal
44
* Every time E switch from low to high,
45
* cfag12864b/ks0108 reads the command/data.
46
*
47
* CS1 = First ks0108controller.
48
* If high, the first ks0108 controller receives commands/data.
49
*
50
* CS2 = Second ks0108 controller
51
* If high, the second ks0108 controller receives commands/data.
52
*
53
* DI = Data/Instruction
54
* If low, cfag12864b will expect commands.
55
* If high, cfag12864b will expect data.
56
*
57
*/
58
59
#define bit(n) (((unsigned char)1)<<(n))
60
61
#define CFAG12864B_BIT_E (0)
62
#define CFAG12864B_BIT_CS1 (2)
63
#define CFAG12864B_BIT_CS2 (1)
64
#define CFAG12864B_BIT_DI (3)
65
66
static unsigned char cfag12864b_state;
67
68
static void cfag12864b_set(void)
69
{
70
ks0108_writecontrol(cfag12864b_state);
71
}
72
73
static void cfag12864b_setbit(unsigned char state, unsigned char n)
74
{
75
if (state)
76
cfag12864b_state |= bit(n);
77
else
78
cfag12864b_state &= ~bit(n);
79
}
80
81
static void cfag12864b_e(unsigned char state)
82
{
83
cfag12864b_setbit(state, CFAG12864B_BIT_E);
84
cfag12864b_set();
85
}
86
87
static void cfag12864b_cs1(unsigned char state)
88
{
89
cfag12864b_setbit(state, CFAG12864B_BIT_CS1);
90
}
91
92
static void cfag12864b_cs2(unsigned char state)
93
{
94
cfag12864b_setbit(state, CFAG12864B_BIT_CS2);
95
}
96
97
static void cfag12864b_di(unsigned char state)
98
{
99
cfag12864b_setbit(state, CFAG12864B_BIT_DI);
100
}
101
102
static void cfag12864b_setcontrollers(unsigned char first,
103
unsigned char second)
104
{
105
if (first)
106
cfag12864b_cs1(0);
107
else
108
cfag12864b_cs1(1);
109
110
if (second)
111
cfag12864b_cs2(0);
112
else
113
cfag12864b_cs2(1);
114
}
115
116
static void cfag12864b_controller(unsigned char which)
117
{
118
if (which == 0)
119
cfag12864b_setcontrollers(1, 0);
120
else if (which == 1)
121
cfag12864b_setcontrollers(0, 1);
122
}
123
124
static void cfag12864b_displaystate(unsigned char state)
125
{
126
cfag12864b_di(0);
127
cfag12864b_e(1);
128
ks0108_displaystate(state);
129
cfag12864b_e(0);
130
}
131
132
static void cfag12864b_address(unsigned char address)
133
{
134
cfag12864b_di(0);
135
cfag12864b_e(1);
136
ks0108_address(address);
137
cfag12864b_e(0);
138
}
139
140
static void cfag12864b_page(unsigned char page)
141
{
142
cfag12864b_di(0);
143
cfag12864b_e(1);
144
ks0108_page(page);
145
cfag12864b_e(0);
146
}
147
148
static void cfag12864b_startline(unsigned char startline)
149
{
150
cfag12864b_di(0);
151
cfag12864b_e(1);
152
ks0108_startline(startline);
153
cfag12864b_e(0);
154
}
155
156
static void cfag12864b_writebyte(unsigned char byte)
157
{
158
cfag12864b_di(1);
159
cfag12864b_e(1);
160
ks0108_writedata(byte);
161
cfag12864b_e(0);
162
}
163
164
static void cfag12864b_nop(void)
165
{
166
cfag12864b_startline(0);
167
}
168
169
/*
170
* cfag12864b Internal Commands
171
*/
172
173
static void cfag12864b_on(void)
174
{
175
cfag12864b_setcontrollers(1, 1);
176
cfag12864b_displaystate(1);
177
}
178
179
static void cfag12864b_off(void)
180
{
181
cfag12864b_setcontrollers(1, 1);
182
cfag12864b_displaystate(0);
183
}
184
185
static void cfag12864b_clear(void)
186
{
187
unsigned char i, j;
188
189
cfag12864b_setcontrollers(1, 1);
190
for (i = 0; i < CFAG12864B_PAGES; i++) {
191
cfag12864b_page(i);
192
cfag12864b_address(0);
193
for (j = 0; j < CFAG12864B_ADDRESSES; j++)
194
cfag12864b_writebyte(0);
195
}
196
}
197
198
/*
199
* Update work
200
*/
201
202
unsigned char *cfag12864b_buffer;
203
static unsigned char *cfag12864b_cache;
204
static DEFINE_MUTEX(cfag12864b_mutex);
205
static unsigned char cfag12864b_updating;
206
static void cfag12864b_update(struct work_struct *delayed_work);
207
static struct workqueue_struct *cfag12864b_workqueue;
208
static DECLARE_DELAYED_WORK(cfag12864b_work, cfag12864b_update);
209
210
static void cfag12864b_queue(void)
211
{
212
queue_delayed_work(cfag12864b_workqueue, &cfag12864b_work,
213
HZ / cfag12864b_rate);
214
}
215
216
unsigned char cfag12864b_enable(void)
217
{
218
unsigned char ret;
219
220
mutex_lock(&cfag12864b_mutex);
221
222
if (!cfag12864b_updating) {
223
cfag12864b_updating = 1;
224
cfag12864b_queue();
225
ret = 0;
226
} else
227
ret = 1;
228
229
mutex_unlock(&cfag12864b_mutex);
230
231
return ret;
232
}
233
234
void cfag12864b_disable(void)
235
{
236
mutex_lock(&cfag12864b_mutex);
237
238
if (cfag12864b_updating) {
239
cfag12864b_updating = 0;
240
cancel_delayed_work(&cfag12864b_work);
241
flush_workqueue(cfag12864b_workqueue);
242
}
243
244
mutex_unlock(&cfag12864b_mutex);
245
}
246
247
static void cfag12864b_update(struct work_struct *work)
248
{
249
unsigned char c;
250
unsigned short i, j, k, b;
251
252
if (memcmp(cfag12864b_cache, cfag12864b_buffer, CFAG12864B_SIZE)) {
253
for (i = 0; i < CFAG12864B_CONTROLLERS; i++) {
254
cfag12864b_controller(i);
255
cfag12864b_nop();
256
for (j = 0; j < CFAG12864B_PAGES; j++) {
257
cfag12864b_page(j);
258
cfag12864b_nop();
259
cfag12864b_address(0);
260
cfag12864b_nop();
261
for (k = 0; k < CFAG12864B_ADDRESSES; k++) {
262
for (c = 0, b = 0; b < 8; b++)
263
if (cfag12864b_buffer
264
[i * CFAG12864B_ADDRESSES / 8
265
+ k / 8 + (j * 8 + b) *
266
CFAG12864B_WIDTH / 8]
267
& bit(k % 8))
268
c |= bit(b);
269
cfag12864b_writebyte(c);
270
}
271
}
272
}
273
274
memcpy(cfag12864b_cache, cfag12864b_buffer, CFAG12864B_SIZE);
275
}
276
277
if (cfag12864b_updating)
278
cfag12864b_queue();
279
}
280
281
/*
282
* cfag12864b Exported Symbols
283
*/
284
285
EXPORT_SYMBOL_GPL(cfag12864b_buffer);
286
EXPORT_SYMBOL_GPL(cfag12864b_enable);
287
EXPORT_SYMBOL_GPL(cfag12864b_disable);
288
289
/*
290
* Is the module inited?
291
*/
292
293
static unsigned char cfag12864b_inited;
294
unsigned char cfag12864b_isinited(void)
295
{
296
return cfag12864b_inited;
297
}
298
EXPORT_SYMBOL_GPL(cfag12864b_isinited);
299
300
/*
301
* Module Init & Exit
302
*/
303
304
static int __init cfag12864b_init(void)
305
{
306
int ret = -EINVAL;
307
308
/* ks0108_init() must be called first */
309
if (!ks0108_isinited()) {
310
printk(KERN_ERR CFAG12864B_NAME ": ERROR: "
311
"ks0108 is not initialized\n");
312
goto none;
313
}
314
BUILD_BUG_ON(PAGE_SIZE < CFAG12864B_SIZE);
315
316
cfag12864b_buffer = (unsigned char *) get_zeroed_page(GFP_KERNEL);
317
if (cfag12864b_buffer == NULL) {
318
printk(KERN_ERR CFAG12864B_NAME ": ERROR: "
319
"can't get a free page\n");
320
ret = -ENOMEM;
321
goto none;
322
}
323
324
cfag12864b_cache = kmalloc(CFAG12864B_SIZE,
325
GFP_KERNEL);
326
if (cfag12864b_cache == NULL) {
327
printk(KERN_ERR CFAG12864B_NAME ": ERROR: "
328
"can't alloc cache buffer (%i bytes)\n",
329
CFAG12864B_SIZE);
330
ret = -ENOMEM;
331
goto bufferalloced;
332
}
333
334
cfag12864b_workqueue = create_singlethread_workqueue(CFAG12864B_NAME);
335
if (cfag12864b_workqueue == NULL)
336
goto cachealloced;
337
338
cfag12864b_clear();
339
cfag12864b_on();
340
341
cfag12864b_inited = 1;
342
return 0;
343
344
cachealloced:
345
kfree(cfag12864b_cache);
346
347
bufferalloced:
348
free_page((unsigned long) cfag12864b_buffer);
349
350
none:
351
return ret;
352
}
353
354
static void __exit cfag12864b_exit(void)
355
{
356
cfag12864b_disable();
357
cfag12864b_off();
358
destroy_workqueue(cfag12864b_workqueue);
359
kfree(cfag12864b_cache);
360
free_page((unsigned long) cfag12864b_buffer);
361
}
362
363
module_init(cfag12864b_init);
364
module_exit(cfag12864b_exit);
365
366
MODULE_LICENSE("GPL v2");
367
MODULE_AUTHOR("Miguel Ojeda <[email protected]>");
368
MODULE_DESCRIPTION("cfag12864b LCD driver");
369
370