2 * vrc4173.c, NEC VRC4173 base driver for NEC VR4122/VR4131.
4 * Copyright (C) 2001-2003 MontaVista Software Inc.
5 * Author: Yoichi Yuasa <yyuasa@mvista.com, or source@mvista.com>
6 * Copyright (C) 2004 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
7 * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include <linux/init.h>
24 #include <linux/module.h>
25 #include <linux/interrupt.h>
26 #include <linux/irq.h>
27 #include <linux/pci.h>
28 #include <linux/spinlock.h>
29 #include <linux/types.h>
31 #include <asm/vr41xx/vr41xx.h>
32 #include <asm/vr41xx/vrc4173.h>
34 MODULE_DESCRIPTION("NEC VRC4173 base driver for NEC VR4122/4131");
35 MODULE_AUTHOR("Yoichi Yuasa <yyuasa@mvista.com>");
36 MODULE_LICENSE("GPL");
38 #define VRC4173_CMUCLKMSK 0x040
42 #define MSKPS2CH1 0x0008
43 #define MSKPS2CH2 0x0010
45 #define MSKCARD1 0x0040
46 #define MSKCARD2 0x0080
47 #define MSKAC97 0x0100
48 #define MSK48MUSB 0x0400
49 #define MSK48MPIN 0x0800
50 #define MSK48MOSC 0x1000
51 #define VRC4173_CMUSRST 0x042
53 #define CARD1RST 0x0002
54 #define CARD2RST 0x0004
55 #define AC97RST 0x0008
57 #define VRC4173_SYSINT1REG 0x060
58 #define VRC4173_MSYSINT1REG 0x06c
59 #define VRC4173_MPIUINTREG 0x06e
60 #define VRC4173_MAIUINTREG 0x070
61 #define VRC4173_MKIUINTREG 0x072
63 #define VRC4173_SELECTREG 0x09e
69 static struct pci_device_id vrc4173_id_table
[] __devinitdata
= {
70 { .vendor
= PCI_VENDOR_ID_NEC
,
71 .device
= PCI_DEVICE_ID_NEC_VRC4173
,
72 .subvendor
= PCI_ANY_ID
,
73 .subdevice
= PCI_ANY_ID
, },
77 unsigned long vrc4173_io_offset
= 0;
79 EXPORT_SYMBOL(vrc4173_io_offset
);
81 static int vrc4173_initialized
;
82 static uint16_t vrc4173_cmuclkmsk
;
83 static uint16_t vrc4173_selectreg
;
84 static spinlock_t vrc4173_cmu_lock
;
85 static spinlock_t vrc4173_giu_lock
;
87 static inline void set_cmusrst(uint16_t val
)
91 cmusrst
= vrc4173_inw(VRC4173_CMUSRST
);
93 vrc4173_outw(cmusrst
, VRC4173_CMUSRST
);
96 static inline void clear_cmusrst(uint16_t val
)
100 cmusrst
= vrc4173_inw(VRC4173_CMUSRST
);
102 vrc4173_outw(cmusrst
, VRC4173_CMUSRST
);
105 void vrc4173_supply_clock(vrc4173_clock_t clock
)
107 if (vrc4173_initialized
) {
108 spin_lock_irq(&vrc4173_cmu_lock
);
111 case VRC4173_PIU_CLOCK
:
112 vrc4173_cmuclkmsk
|= MSKPIU
;
114 case VRC4173_KIU_CLOCK
:
115 vrc4173_cmuclkmsk
|= MSKKIU
;
117 case VRC4173_AIU_CLOCK
:
118 vrc4173_cmuclkmsk
|= MSKAIU
;
120 case VRC4173_PS2_CH1_CLOCK
:
121 vrc4173_cmuclkmsk
|= MSKPS2CH1
;
123 case VRC4173_PS2_CH2_CLOCK
:
124 vrc4173_cmuclkmsk
|= MSKPS2CH2
;
126 case VRC4173_USBU_PCI_CLOCK
:
128 vrc4173_cmuclkmsk
|= MSKUSB
;
130 case VRC4173_CARDU1_PCI_CLOCK
:
131 set_cmusrst(CARD1RST
);
132 vrc4173_cmuclkmsk
|= MSKCARD1
;
134 case VRC4173_CARDU2_PCI_CLOCK
:
135 set_cmusrst(CARD2RST
);
136 vrc4173_cmuclkmsk
|= MSKCARD2
;
138 case VRC4173_AC97U_PCI_CLOCK
:
139 set_cmusrst(AC97RST
);
140 vrc4173_cmuclkmsk
|= MSKAC97
;
142 case VRC4173_USBU_48MHz_CLOCK
:
144 vrc4173_cmuclkmsk
|= MSK48MUSB
;
146 case VRC4173_EXT_48MHz_CLOCK
:
147 if (vrc4173_cmuclkmsk
& MSK48MOSC
)
148 vrc4173_cmuclkmsk
|= MSK48MPIN
;
151 "vrc4173_supply_clock: "
152 "Please supply VRC4173_48MHz_CLOCK first "
153 "rather than VRC4173_EXT_48MHz_CLOCK.\n");
155 case VRC4173_48MHz_CLOCK
:
156 vrc4173_cmuclkmsk
|= MSK48MOSC
;
160 "vrc4173_supply_clock: Invalid CLOCK value %u\n", clock
);
164 vrc4173_outw(vrc4173_cmuclkmsk
, VRC4173_CMUCLKMSK
);
167 case VRC4173_USBU_PCI_CLOCK
:
168 case VRC4173_USBU_48MHz_CLOCK
:
169 clear_cmusrst(USBRST
);
171 case VRC4173_CARDU1_PCI_CLOCK
:
172 clear_cmusrst(CARD1RST
);
174 case VRC4173_CARDU2_PCI_CLOCK
:
175 clear_cmusrst(CARD2RST
);
177 case VRC4173_AC97U_PCI_CLOCK
:
178 clear_cmusrst(AC97RST
);
184 spin_unlock_irq(&vrc4173_cmu_lock
);
188 EXPORT_SYMBOL(vrc4173_supply_clock
);
190 void vrc4173_mask_clock(vrc4173_clock_t clock
)
192 if (vrc4173_initialized
) {
193 spin_lock_irq(&vrc4173_cmu_lock
);
196 case VRC4173_PIU_CLOCK
:
197 vrc4173_cmuclkmsk
&= ~MSKPIU
;
199 case VRC4173_KIU_CLOCK
:
200 vrc4173_cmuclkmsk
&= ~MSKKIU
;
202 case VRC4173_AIU_CLOCK
:
203 vrc4173_cmuclkmsk
&= ~MSKAIU
;
205 case VRC4173_PS2_CH1_CLOCK
:
206 vrc4173_cmuclkmsk
&= ~MSKPS2CH1
;
208 case VRC4173_PS2_CH2_CLOCK
:
209 vrc4173_cmuclkmsk
&= ~MSKPS2CH2
;
211 case VRC4173_USBU_PCI_CLOCK
:
213 vrc4173_cmuclkmsk
&= ~MSKUSB
;
215 case VRC4173_CARDU1_PCI_CLOCK
:
216 set_cmusrst(CARD1RST
);
217 vrc4173_cmuclkmsk
&= ~MSKCARD1
;
219 case VRC4173_CARDU2_PCI_CLOCK
:
220 set_cmusrst(CARD2RST
);
221 vrc4173_cmuclkmsk
&= ~MSKCARD2
;
223 case VRC4173_AC97U_PCI_CLOCK
:
224 set_cmusrst(AC97RST
);
225 vrc4173_cmuclkmsk
&= ~MSKAC97
;
227 case VRC4173_USBU_48MHz_CLOCK
:
229 vrc4173_cmuclkmsk
&= ~MSK48MUSB
;
231 case VRC4173_EXT_48MHz_CLOCK
:
232 vrc4173_cmuclkmsk
&= ~MSK48MPIN
;
234 case VRC4173_48MHz_CLOCK
:
235 vrc4173_cmuclkmsk
&= ~MSK48MOSC
;
238 printk(KERN_WARNING
"vrc4173_mask_clock: Invalid CLOCK value %u\n", clock
);
242 vrc4173_outw(vrc4173_cmuclkmsk
, VRC4173_CMUCLKMSK
);
245 case VRC4173_USBU_PCI_CLOCK
:
246 case VRC4173_USBU_48MHz_CLOCK
:
247 clear_cmusrst(USBRST
);
249 case VRC4173_CARDU1_PCI_CLOCK
:
250 clear_cmusrst(CARD1RST
);
252 case VRC4173_CARDU2_PCI_CLOCK
:
253 clear_cmusrst(CARD2RST
);
255 case VRC4173_AC97U_PCI_CLOCK
:
256 clear_cmusrst(AC97RST
);
262 spin_unlock_irq(&vrc4173_cmu_lock
);
266 EXPORT_SYMBOL(vrc4173_mask_clock
);
268 static inline void vrc4173_cmu_init(void)
270 vrc4173_cmuclkmsk
= vrc4173_inw(VRC4173_CMUCLKMSK
);
272 spin_lock_init(&vrc4173_cmu_lock
);
275 void vrc4173_select_function(vrc4173_function_t function
)
277 if (vrc4173_initialized
) {
278 spin_lock_irq(&vrc4173_giu_lock
);
282 vrc4173_selectreg
|= SEL2
;
285 vrc4173_selectreg
|= SEL1
;
288 vrc4173_selectreg
&= SEL2
| SEL1
| SEL0
;
290 case KEYBOARD_8SCANLINES
:
291 vrc4173_selectreg
&= SEL3
| SEL2
| SEL1
;
293 case KEYBOARD_10SCANLINES
:
294 vrc4173_selectreg
&= SEL3
| SEL2
;
296 case KEYBOARD_12SCANLINES
:
297 vrc4173_selectreg
&= SEL3
;
300 vrc4173_selectreg
|= SEL0
;
303 vrc4173_selectreg
|= SEL3
;
307 vrc4173_outw(vrc4173_selectreg
, VRC4173_SELECTREG
);
309 spin_unlock_irq(&vrc4173_giu_lock
);
313 EXPORT_SYMBOL(vrc4173_select_function
);
315 static inline void vrc4173_giu_init(void)
317 vrc4173_selectreg
= vrc4173_inw(VRC4173_SELECTREG
);
319 spin_lock_init(&vrc4173_giu_lock
);
322 void vrc4173_enable_piuint(uint16_t mask
)
324 irq_desc_t
*desc
= irq_desc
+ VRC4173_PIU_IRQ
;
328 spin_lock_irqsave(&desc
->lock
, flags
);
329 val
= vrc4173_inw(VRC4173_MPIUINTREG
);
331 vrc4173_outw(val
, VRC4173_MPIUINTREG
);
332 spin_unlock_irqrestore(&desc
->lock
, flags
);
335 EXPORT_SYMBOL(vrc4173_enable_piuint
);
337 void vrc4173_disable_piuint(uint16_t mask
)
339 irq_desc_t
*desc
= irq_desc
+ VRC4173_PIU_IRQ
;
343 spin_lock_irqsave(&desc
->lock
, flags
);
344 val
= vrc4173_inw(VRC4173_MPIUINTREG
);
346 vrc4173_outw(val
, VRC4173_MPIUINTREG
);
347 spin_unlock_irqrestore(&desc
->lock
, flags
);
350 EXPORT_SYMBOL(vrc4173_disable_piuint
);
352 void vrc4173_enable_aiuint(uint16_t mask
)
354 irq_desc_t
*desc
= irq_desc
+ VRC4173_AIU_IRQ
;
358 spin_lock_irqsave(&desc
->lock
, flags
);
359 val
= vrc4173_inw(VRC4173_MAIUINTREG
);
361 vrc4173_outw(val
, VRC4173_MAIUINTREG
);
362 spin_unlock_irqrestore(&desc
->lock
, flags
);
365 EXPORT_SYMBOL(vrc4173_enable_aiuint
);
367 void vrc4173_disable_aiuint(uint16_t mask
)
369 irq_desc_t
*desc
= irq_desc
+ VRC4173_AIU_IRQ
;
373 spin_lock_irqsave(&desc
->lock
, flags
);
374 val
= vrc4173_inw(VRC4173_MAIUINTREG
);
376 vrc4173_outw(val
, VRC4173_MAIUINTREG
);
377 spin_unlock_irqrestore(&desc
->lock
, flags
);
380 EXPORT_SYMBOL(vrc4173_disable_aiuint
);
382 void vrc4173_enable_kiuint(uint16_t mask
)
384 irq_desc_t
*desc
= irq_desc
+ VRC4173_KIU_IRQ
;
388 spin_lock_irqsave(&desc
->lock
, flags
);
389 val
= vrc4173_inw(VRC4173_MKIUINTREG
);
391 vrc4173_outw(val
, VRC4173_MKIUINTREG
);
392 spin_unlock_irqrestore(&desc
->lock
, flags
);
395 EXPORT_SYMBOL(vrc4173_enable_kiuint
);
397 void vrc4173_disable_kiuint(uint16_t mask
)
399 irq_desc_t
*desc
= irq_desc
+ VRC4173_KIU_IRQ
;
403 spin_lock_irqsave(&desc
->lock
, flags
);
404 val
= vrc4173_inw(VRC4173_MKIUINTREG
);
406 vrc4173_outw(val
, VRC4173_MKIUINTREG
);
407 spin_unlock_irqrestore(&desc
->lock
, flags
);
410 EXPORT_SYMBOL(vrc4173_disable_kiuint
);
412 static void enable_vrc4173_irq(unsigned int irq
)
416 val
= vrc4173_inw(VRC4173_MSYSINT1REG
);
417 val
|= (uint16_t)1 << (irq
- VRC4173_IRQ_BASE
);
418 vrc4173_outw(val
, VRC4173_MSYSINT1REG
);
421 static void disable_vrc4173_irq(unsigned int irq
)
425 val
= vrc4173_inw(VRC4173_MSYSINT1REG
);
426 val
&= ~((uint16_t)1 << (irq
- VRC4173_IRQ_BASE
));
427 vrc4173_outw(val
, VRC4173_MSYSINT1REG
);
430 static unsigned int startup_vrc4173_irq(unsigned int irq
)
432 enable_vrc4173_irq(irq
);
433 return 0; /* never anything pending */
436 #define shutdown_vrc4173_irq disable_vrc4173_irq
437 #define ack_vrc4173_irq disable_vrc4173_irq
439 static void end_vrc4173_irq(unsigned int irq
)
441 if (!(irq_desc
[irq
].status
& (IRQ_DISABLED
| IRQ_INPROGRESS
)))
442 enable_vrc4173_irq(irq
);
445 static struct hw_interrupt_type vrc4173_irq_type
= {
446 .typename
= "VRC4173",
447 .startup
= startup_vrc4173_irq
,
448 .shutdown
= shutdown_vrc4173_irq
,
449 .enable
= enable_vrc4173_irq
,
450 .disable
= disable_vrc4173_irq
,
451 .ack
= ack_vrc4173_irq
,
452 .end
= end_vrc4173_irq
,
455 static int vrc4173_get_irq_number(int irq
)
457 uint16_t status
, mask
;
460 status
= vrc4173_inw(VRC4173_SYSINT1REG
);
461 mask
= vrc4173_inw(VRC4173_MSYSINT1REG
);
465 for (i
= 0; i
< 16; i
++)
466 if (status
& (0x0001 << i
))
467 return VRC4173_IRQ(i
);
473 static inline int vrc4173_icu_init(int cascade_irq
)
477 if (cascade_irq
< GIU_IRQ(0) || cascade_irq
> GIU_IRQ(15))
480 vrc4173_outw(0, VRC4173_MSYSINT1REG
);
482 vr41xx_set_irq_trigger(GIU_IRQ_TO_PIN(cascade_irq
), TRIGGER_LEVEL
, SIGNAL_THROUGH
);
483 vr41xx_set_irq_level(GIU_IRQ_TO_PIN(cascade_irq
), LEVEL_LOW
);
485 for (i
= VRC4173_IRQ_BASE
; i
<= VRC4173_IRQ_LAST
; i
++)
486 irq_desc
[i
].handler
= &vrc4173_irq_type
;
491 static int __devinit
vrc4173_probe(struct pci_dev
*dev
,
492 const struct pci_device_id
*id
)
494 unsigned long start
, flags
;
497 err
= pci_enable_device(dev
);
499 printk(KERN_ERR
"vrc4173: Failed to enable PCI device, aborting\n");
505 start
= pci_resource_start(dev
, 0);
507 printk(KERN_ERR
"vrc4173:No such PCI I/O resource, aborting\n");
511 flags
= pci_resource_flags(dev
, 0);
512 if ((flags
& IORESOURCE_IO
) == 0) {
513 printk(KERN_ERR
"vrc4173: No such PCI I/O resource, aborting\n");
517 err
= pci_request_regions(dev
, "NEC VRC4173");
519 printk(KERN_ERR
"vrc4173: PCI resources are busy, aborting\n");
523 set_vrc4173_io_offset(start
);
528 err
= vrc4173_icu_init(dev
->irq
);
530 printk(KERN_ERR
"vrc4173: Invalid IRQ %d, aborting\n", dev
->irq
);
534 err
= vr41xx_cascade_irq(dev
->irq
, vrc4173_get_irq_number
);
536 printk(KERN_ERR
"vrc4173: IRQ resource %d is busy, aborting\n", dev
->irq
);
541 "NEC VRC4173 at 0x%#08lx, IRQ is cascaded to %d\n", start
, dev
->irq
);
546 static void vrc4173_remove(struct pci_dev
*dev
)
548 free_irq(dev
->irq
, NULL
);
550 pci_release_regions(dev
);
553 static struct pci_driver vrc4173_driver
= {
554 .name
= "NEC VRC4173",
555 .probe
= vrc4173_probe
,
556 .remove
= vrc4173_remove
,
557 .id_table
= vrc4173_id_table
,
560 static int __devinit
vrc4173_init(void)
564 err
= pci_module_init(&vrc4173_driver
);
568 vrc4173_initialized
= 1;
573 static void __devexit
vrc4173_exit(void)
575 vrc4173_initialized
= 0;
577 pci_unregister_driver(&vrc4173_driver
);
580 module_init(vrc4173_init
);
581 module_exit(vrc4173_exit
);