OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [char/] [vr41xx_keyb.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * FILE NAME
3
 *      drivers/char/vr41xx_keyb.c
4
 *
5
 * BRIEF MODULE DESCRIPTION
6
 *      Keyboard driver for NEC VR4100 series Keyboard Interface Unit.
7
 *
8
 * Copyright (C) 1999 Bradley D. LaRonde
9
 * Copyright (C) 1999 Hiroshi Kawashima <kawashima@iname.com>
10
 * Copyright (C) 2000 Michael Klar <wyldfier@iname.com>
11
 * Copyright (C) 2002,2003 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
12
 *
13
 * This file is subject to the terms and conditions of the GNU General Public
14
 * License.  See the file "COPYING" in the main directory of this archive
15
 * for more details.
16
 */
17
/*
18
 * Changes:
19
 *  version 1.0
20
 *  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>  Mon, 25 Mar 2002
21
 *  -  Rewrote extensively because of 2.4.18.
22
 *
23
 *  version 1.1
24
 *  Yoichi Yuasa <yuasa@hh.iij4u.or.jp>  Wed,  9 Sep 200
25
 *  -  Added NEC VRC4173 KIU support.
26
 */
27
#include <linux/config.h>
28
#include <linux/init.h>
29
#include <linux/errno.h>
30
#include <linux/kbd_ll.h>
31
#ifdef CONFIG_PCI
32
#include <linux/pci.h>
33
#endif
34
#include <linux/pm.h>
35
 
36
#include <asm/addrspace.h>
37
#include <asm/cpu.h>
38
#include <asm/io.h>
39
#include <asm/param.h>
40
#include <asm/vr41xx/vr41xx.h>
41
#ifdef CONFIG_VRC4173
42
#include <asm/vr41xx/vrc4173.h>
43
#endif
44
 
45
#define KIU_BASE                        KSEG1ADDR(0x0b000180)
46
#define MKIUINTREG                      KSEG1ADDR(0x0b000092)
47
 
48
#define VRC4173_KIU_OFFSET              0x100
49
#define VRC4173_MKIUINTREG_OFFSET       0x072
50
 
51
#define KIUDAT0                         0x00
52
#define KIUDAT1                         0x02
53
#define KIUDAT2                         0x04
54
#define KIUDAT3                         0x06
55
#define KIUDAT4                         0x08
56
#define KIUDAT5                         0x0a
57
#define KIUDAT6                         0x0c
58
#define KIUDAT7                         0x0e
59
#define KIUSCANREP                      0x10
60
 #define KIUSCANREP_KEYEN               0x8000
61
 #define KIUSCANREP_STPREP(x)           ((x) << 4)
62
 #define KIUSCANREP_SCANSTP             0x0008
63
 #define KIUSCANREP_SCANSTART           0x0004
64
 #define KIUSCANREP_ATSTP               0x0002
65
 #define KIUSCANREP_ATSCAN              0x0001
66
#define KIUSCANS                        0x12
67
 #define KIUSCANS_SCANNING              0x0003
68
 #define KIUSCANS_INTERVAL              0x0002
69
 #define KIUSCANS_WAITKEYIN             0x0001
70
 #define KIUSCANS_STOPPED               0x0000
71
#define KIUWKS                          0x14
72
 #define KIUWKS_T3CNT                   0x7c00
73
 #define KIUWKS_T3CNT_SHIFT             10
74
 #define KIUWKS_T2CNT                   0x03e0
75
 #define KIUWKS_T2CNT_SHIFT             5
76
 #define KIUWKS_T1CNT                   0x001f
77
 #define KIUWKS_T1CNT_SHIFT             0
78
 #define KIUWKS_CNT_USEC(x)             (((x) / 30) - 1)
79
#define KIUWKI                          0x16
80
 #define KIUWKI_INTERVAL_USEC(x)        ((x) / 30)
81
#define KIUINT                          0x18
82
 #define KIUINT_KDATLOST                0x0004
83
 #define KIUINT_KDATRDY                 0x0002
84
 #define KIUINT_SCANINT                 0x0001
85
#define KIURST                          0x1a
86
 #define KIURST_KIURST                  0x0001
87
#define KIUGPEN                         0x1c
88
 #define KIUGPEN_KGPEN(x)               ((uint16_t)1 << (x))
89
#define SCANLINE                        0x1e
90
 #define SCANLINE_DONTUSE               0x0003
91
 #define SCANLINE_8LINES                0x0002
92
 #define SCANLINE_10LINES               0x0001
93
 #define SCANLINE_12LINES               0x0000
94
 
95
static unsigned long kiu_base;
96
static unsigned long mkiuintreg;
97
 
98
#ifdef CONFIG_VRC4173
99
#define kiu_readw(offset)               vrc4173_inw(kiu_base + (offset))
100
#define kiu_writew(val, offset)         vrc4173_outw(val, kiu_base + (offset))
101
#define mkiuintreg_writew(val)          vrc4173_outw((val), mkiuintreg)
102
#else
103
#define kiu_readw(offset)               readw(kiu_base + (offset))
104
#define kiu_writew(val, offset)         writew(val, kiu_base + (offset))
105
#define mkiuintreg_writew(val)          writew((val), mkiuintreg)
106
#endif
107
 
108
#define KIU_CLOCK                       0x0008
109
 
110
#ifdef CONFIG_VRC4173
111
#define KIU_IRQ                         VRC4173_KIU_IRQ
112
#else
113
#define KIU_IRQ                         SYSINT1_IRQ(7)
114
#endif
115
 
116
#define KEY_UP                          0
117
#define KEY_DOWN                        1
118
 
119
#define DEFAULT_KIUDAT_REGS             6
120
#define DEFAULT_DATA_NOT_REVERSED       0
121
#define DEFAULT_T3CNT                   KIUWKS_CNT_USEC(200)
122
#define DEFAULT_T2CNT                   KIUWKS_CNT_USEC(200)
123
#define DEFAULT_T1CNT                   KIUWKS_CNT_USEC(200)
124
#define DEFAULT_SCAN_INTERVAL           KIUWKI_INTERVAL_USEC(30000)
125
#define DEFAULT_REPEAT_DELAY            HZ/4
126
#define DEFAULT_REPEAT_RATE             HZ/25
127
 
128
static char *kiu_driver_name = "Keyboard driver";
129
static char *kiu_driver_version = "1.1";
130
static char *kiu_driver_revdate = "2003-09-09";
131
static char *kiu_driver_device_name = "NEC VR4100 series KIU";
132
 
133
static unsigned char kiudat_regs = DEFAULT_KIUDAT_REGS;
134
static unsigned char data_reverse = DEFAULT_DATA_NOT_REVERSED;
135
static uint16_t scanlines = SCANLINE_12LINES;
136
static uint16_t t3cnt = DEFAULT_T3CNT;
137
static uint16_t t2cnt = DEFAULT_T2CNT;
138
static uint16_t t1cnt = DEFAULT_T1CNT;
139
static uint16_t scan_interval = DEFAULT_SCAN_INTERVAL;
140
 
141
static unsigned long repeat_delay = DEFAULT_REPEAT_DELAY;
142
static unsigned long repeat_rate = DEFAULT_REPEAT_RATE;
143
 
144
static int repeat_scancode = -1;
145
static unsigned long next_handle_time;
146
 
147
struct kiudat_t {
148
        uint32_t reg;
149
        uint16_t data;
150
};
151
 
152
static struct kiudat_t kiudat [8] = {
153
        {KIUDAT0, 0}, {KIUDAT1, 0},
154
        {KIUDAT2, 0}, {KIUDAT3, 0},
155
        {KIUDAT4, 0}, {KIUDAT5, 0},
156
        {KIUDAT6, 0}, {KIUDAT7, 0},
157
};
158
 
159
int kbd_setkeycode(unsigned int scancode, unsigned int keycode)
160
{
161
        return (scancode == keycode) ? 0 : -EINVAL;
162
}
163
 
164
int kbd_getkeycode(unsigned int scancode)
165
{
166
        return scancode;
167
}
168
 
169
int kbd_translate(unsigned char scancode, unsigned char *keycode, char raw_mode)
170
{
171
        *keycode = scancode;
172
        return 1;
173
}
174
 
175
char kbd_unexpected_up(unsigned char keycode)
176
{
177
        printk(KERN_WARNING "vr41xx_keyb: unexpected up, keycode 0x%02x\n", keycode);
178
        return 0x80;
179
}
180
 
181
void kbd_leds(unsigned char leds)
182
{
183
        return;
184
}
185
 
186
static inline void handle_kiudat(uint16_t data, uint16_t cmp_data, int scancode)
187
{
188
        uint16_t mask;
189
        int down, candidate_scancode = 0;
190
 
191
        for (mask = 0x0001; mask ; mask <<= 1) {
192
                if (cmp_data & mask) {
193
                        down = data & mask ? KEY_DOWN : KEY_UP;
194
                        if (down == KEY_DOWN) {
195
                                repeat_scancode = scancode;
196
                                next_handle_time = jiffies + repeat_delay;
197
                        }
198
                        else {
199
                                if (repeat_scancode == scancode)
200
                                        repeat_scancode = -1;
201
                        }
202
                        handle_scancode(scancode, down);
203
                }
204
                if (data & mask) {
205
                        candidate_scancode = scancode;
206
                }
207
                scancode++;
208
        }
209
 
210
        if ((repeat_scancode < 0) && (candidate_scancode > 0)) {
211
                        repeat_scancode = candidate_scancode;
212
                        next_handle_time = jiffies + repeat_delay;
213
        }
214
}
215
 
216
static inline void handle_kiu_event(void)
217
{
218
        struct kiudat_t *kiu = kiudat;
219
        uint16_t data, last_data, cmp_data;
220
        int i;
221
 
222
        for (i = 0; i < kiudat_regs; i++) {
223
                last_data = kiu->data;
224
                data = kiu_readw(kiu->reg);
225
                if (data_reverse)
226
                        data = ~data;
227
                kiu->data = data;
228
                cmp_data = data ^ last_data;
229
                handle_kiudat(data, cmp_data, i * 16);
230
                kiu++;
231
        }
232
 
233
        if ((repeat_scancode >= 0) &&
234
            (time_after_eq(jiffies, next_handle_time))) {
235
                handle_scancode(repeat_scancode, KEY_DOWN);
236
                next_handle_time = jiffies + repeat_rate;
237
        }
238
}
239
 
240
static void kiu_interrupt(int irq, void *dev_id, struct pt_regs *regs)
241
{
242
        uint16_t status;
243
 
244
        mkiuintreg_writew(0);
245
 
246
        status = kiu_readw(KIUINT);
247
        kiu_writew(KIUINT_KDATLOST | KIUINT_KDATRDY | KIUINT_SCANINT, KIUINT);
248
 
249
        if (status & KIUINT_KDATRDY)
250
                handle_kiu_event();
251
 
252
        mkiuintreg_writew(KIUINT_KDATLOST | KIUINT_KDATRDY);
253
}
254
 
255
#ifdef CONFIG_PM
256
 
257
static int pm_kiu_request(struct pm_dev *dev, pm_request_t rqst, void *data)
258
{
259
        switch (rqst) {
260
        case PM_SUSPEND:
261
                mkiuintreg_writew(KIUINT_SCANINT);
262
                break;
263
        case PM_RESUME:
264
                kiu_writew(KIUINT_KDATLOST | KIUINT_KDATRDY | KIUINT_SCANINT, KIUINT);
265
                mkiuintreg_writew(KIUINT_KDATLOST | KIUINT_KDATRDY, MKIUINTREG);
266
                break;
267
        }
268
 
269
        return 0;
270
}
271
 
272
#endif
273
 
274
void __devinit kbd_init_hw(void)
275
{
276
        uint16_t kiugpen = 0;
277
        int i;
278
 
279
        if (current_cpu_data.cputype == CPU_VR4111 ||
280
            current_cpu_data.cputype == CPU_VR4121) {
281
                kiu_base = KIU_BASE;
282
                mkiuintreg = MKIUINTREG;
283
#if defined(CONFIG_PCI) && defined(CONFIG_VRC4173)
284
        } else if (current_cpu_data.cputype == CPU_VR4122 ||
285
                   current_cpu_data.cputype == CPU_VR4131) {
286
                struct pci_dev *dev;
287
                int found = 0;
288
                dev = pci_find_device(PCI_VENDOR_ID_NEC,
289
                                      PCI_DEVICE_ID_NEC_VRC4173, NULL);
290
                if (dev != NULL) {
291
                        switch (scanlines) {
292
                        case SCANLINE_8LINES:
293
                                vrc4173_select_function(KIU8_SELECT);
294
                                found = 1;
295
                                break;
296
                        case SCANLINE_10LINES:
297
                                vrc4173_select_function(KIU10_SELECT);
298
                                found = 1;
299
                                break;
300
                        case SCANLINE_12LINES:
301
                                vrc4173_select_function(KIU12_SELECT);
302
                                found = 1;
303
                                break;
304
                        default:
305
                                break;
306
                        }
307
 
308
                        if (found != 0) {
309
                                kiu_base = VRC4173_KIU_OFFSET;
310
                                mkiuintreg = VRC4173_MKIUINTREG_OFFSET;
311
                                vrc4173_clock_supply(VRC4173_KIU_CLOCK);
312
                        }
313
                }
314
#endif
315
        }
316
 
317
        if (kiu_base == 0 || mkiuintreg == 0)
318
                return;
319
 
320
        printk(KERN_INFO "%s version %s (%s) for %s\n",
321
               kiu_driver_name, kiu_driver_version,
322
               kiu_driver_revdate, kiu_driver_device_name);
323
 
324
        mkiuintreg_writew(0);
325
 
326
        if (current_cpu_data.cputype == CPU_VR4111 ||
327
            current_cpu_data.cputype == CPU_VR4121)
328
                vr41xx_clock_supply(KIU_CLOCK);
329
 
330
        kiu_writew(KIURST_KIURST, KIURST);
331
 
332
        for (i = 0; i < scanlines; i++)
333
                kiugpen &= ~(0x0001 << i);
334
 
335
        kiu_writew(kiugpen, KIUGPEN);
336
        kiu_writew(scanlines, SCANLINE);
337
        kiu_writew((t3cnt << KIUWKS_T3CNT_SHIFT) |
338
                   (t2cnt << KIUWKS_T2CNT_SHIFT) |
339
                   (t1cnt << KIUWKS_T1CNT_SHIFT), KIUWKS);
340
        kiu_writew(scan_interval, KIUWKI);
341
        kiu_writew(KIUINT_KDATLOST | KIUINT_KDATRDY | KIUINT_SCANINT, KIUINT);
342
 
343
 
344
        request_irq(KIU_IRQ, kiu_interrupt, 0, "keyboard", NULL);
345
 
346
        mkiuintreg_writew(KIUINT_KDATLOST | KIUINT_KDATRDY);
347
        kiu_writew(KIUSCANREP_KEYEN | KIUSCANREP_STPREP(1) |
348
               KIUSCANREP_ATSTP | KIUSCANREP_ATSCAN, KIUSCANREP);
349
 
350
#ifdef CONFIG_PM
351
        pm_register(PM_SYS_DEV, PM_SYS_KBC, pm_kiu_request);
352
#endif
353
}
354
 
355
static int __devinit vr41xx_kbd_setup(char *options)
356
{
357
        char *this_opt;
358
        int num;
359
 
360
        if (!options || !*options)
361
                return 1;
362
 
363
        for (this_opt = strtok(options, ","); this_opt; this_opt = strtok(NULL, ",")) {
364
                if (!strncmp(this_opt, "regs:", 5)) {
365
                        num = simple_strtoul(this_opt+5, NULL, 0);
366
                        if (num == 6 || num == 8)
367
                                kiudat_regs = num;
368
                } else if (!strncmp(this_opt, "lines:", 6)) {
369
                        num = simple_strtoul(this_opt+6, NULL, 0);
370
                        if (num == 8)
371
                                scanlines = SCANLINE_8LINES;
372
                        else if (num == 10)
373
                                scanlines = SCANLINE_10LINES;
374
                        else if (num == 12)
375
                                scanlines = SCANLINE_12LINES;
376
                } else if (!strncmp(this_opt, "reverse:", 8)) {
377
                        num = simple_strtoul(this_opt+8, NULL, 0);
378
                        if (num == 0 || num == 1)
379
                                data_reverse = num;
380
                } else if (!strncmp(this_opt, "t3cnt:", 6)) {
381
                        num = simple_strtoul(this_opt+6, NULL, 0);
382
                        if (num >= 60 && num <= 960)
383
                                t3cnt = KIUWKS_CNT_USEC(num);
384
                } else if (!strncmp(this_opt, "t2cnt:", 6)) {
385
                        num = simple_strtoul(this_opt+6, NULL, 0);
386
                        if (num >= 60 && num <= 960)
387
                                t2cnt = KIUWKS_CNT_USEC(num);
388
                } else if (!strncmp(this_opt, "t1cnt:", 6)) {
389
                        num = simple_strtoul(this_opt+6, NULL, 0);
390
                        if (num >= 60 && num <= 960)
391
                                t1cnt = KIUWKS_CNT_USEC(num);
392
                } else if (!strncmp(this_opt, "interval:", 9)) {
393
                        num = simple_strtoul(this_opt+9, NULL, 0);
394
                        if (num >= 30 && num <= 30690)
395
                                scan_interval = KIUWKI_INTERVAL_USEC(num);
396
                } else if (!strncmp(this_opt, "delay:", 6)) {
397
                        num = simple_strtoul(this_opt+6, NULL, 0);
398
                        if (num > 0 && num <= HZ)
399
                                repeat_delay = num;
400
                } else if (!strncmp(this_opt, "rate:", 5)) {
401
                        num = simple_strtoul(this_opt+5, NULL, 0);
402
                        if (num > 0 && num <= HZ)
403
                                repeat_rate = num;
404
                }
405
        }
406
 
407
        return 1;
408
}
409
 
410
__setup("vr41xx_kbd=", vr41xx_kbd_setup);

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.