xref: /linux/drivers/parisc/lasi.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1*1da177e4SLinus Torvalds /*
2*1da177e4SLinus Torvalds  *	LASI Device Driver
3*1da177e4SLinus Torvalds  *
4*1da177e4SLinus Torvalds  *	(c) Copyright 1999 Red Hat Software
5*1da177e4SLinus Torvalds  *	Portions (c) Copyright 1999 The Puffin Group Inc.
6*1da177e4SLinus Torvalds  *	Portions (c) Copyright 1999 Hewlett-Packard
7*1da177e4SLinus Torvalds  *
8*1da177e4SLinus Torvalds  *	This program is free software; you can redistribute it and/or modify
9*1da177e4SLinus Torvalds  *	it under the terms of the GNU General Public License as published by
10*1da177e4SLinus Torvalds  *      the Free Software Foundation; either version 2 of the License, or
11*1da177e4SLinus Torvalds  *      (at your option) any later version.
12*1da177e4SLinus Torvalds  *
13*1da177e4SLinus Torvalds  *	by Alan Cox <alan@redhat.com> and
14*1da177e4SLinus Torvalds  * 	   Alex deVries <alex@onefishtwo.ca>
15*1da177e4SLinus Torvalds  */
16*1da177e4SLinus Torvalds 
17*1da177e4SLinus Torvalds #include <linux/errno.h>
18*1da177e4SLinus Torvalds #include <linux/init.h>
19*1da177e4SLinus Torvalds #include <linux/interrupt.h>
20*1da177e4SLinus Torvalds #include <linux/slab.h>
21*1da177e4SLinus Torvalds #include <linux/module.h>
22*1da177e4SLinus Torvalds #include <linux/pm.h>
23*1da177e4SLinus Torvalds #include <linux/slab.h>
24*1da177e4SLinus Torvalds #include <linux/types.h>
25*1da177e4SLinus Torvalds 
26*1da177e4SLinus Torvalds #include <asm/io.h>
27*1da177e4SLinus Torvalds #include <asm/hardware.h>
28*1da177e4SLinus Torvalds #include <asm/led.h>
29*1da177e4SLinus Torvalds 
30*1da177e4SLinus Torvalds #include "gsc.h"
31*1da177e4SLinus Torvalds 
32*1da177e4SLinus Torvalds 
33*1da177e4SLinus Torvalds #define LASI_VER	0xC008	/* LASI Version */
34*1da177e4SLinus Torvalds 
35*1da177e4SLinus Torvalds #define LASI_IO_CONF	0x7FFFE	/* LASI primary configuration register */
36*1da177e4SLinus Torvalds #define LASI_IO_CONF2	0x7FFFF	/* LASI secondary configuration register */
37*1da177e4SLinus Torvalds 
38*1da177e4SLinus Torvalds static void lasi_choose_irq(struct parisc_device *dev, void *ctrl)
39*1da177e4SLinus Torvalds {
40*1da177e4SLinus Torvalds 	int irq;
41*1da177e4SLinus Torvalds 
42*1da177e4SLinus Torvalds 	switch (dev->id.sversion) {
43*1da177e4SLinus Torvalds 		case 0x74:	irq =  7; break; /* Centronics */
44*1da177e4SLinus Torvalds 		case 0x7B:	irq = 13; break; /* Audio */
45*1da177e4SLinus Torvalds 		case 0x81:	irq = 14; break; /* Lasi itself */
46*1da177e4SLinus Torvalds 		case 0x82:	irq =  9; break; /* SCSI */
47*1da177e4SLinus Torvalds 		case 0x83:	irq = 20; break; /* Floppy */
48*1da177e4SLinus Torvalds 		case 0x84:	irq = 26; break; /* PS/2 Keyboard */
49*1da177e4SLinus Torvalds 		case 0x87:	irq = 18; break; /* ISDN */
50*1da177e4SLinus Torvalds 		case 0x8A:	irq =  8; break; /* LAN */
51*1da177e4SLinus Torvalds 		case 0x8C:	irq =  5; break; /* RS232 */
52*1da177e4SLinus Torvalds 		case 0x8D:	irq = (dev->hw_path == 13) ? 16 : 17; break;
53*1da177e4SLinus Torvalds 						 /* Telephone */
54*1da177e4SLinus Torvalds 		default: 	return;		 /* unknown */
55*1da177e4SLinus Torvalds 	}
56*1da177e4SLinus Torvalds 
57*1da177e4SLinus Torvalds 	gsc_asic_assign_irq(ctrl, irq, &dev->irq);
58*1da177e4SLinus Torvalds }
59*1da177e4SLinus Torvalds 
60*1da177e4SLinus Torvalds static void __init
61*1da177e4SLinus Torvalds lasi_init_irq(struct gsc_asic *this_lasi)
62*1da177e4SLinus Torvalds {
63*1da177e4SLinus Torvalds 	unsigned long lasi_base = this_lasi->hpa;
64*1da177e4SLinus Torvalds 
65*1da177e4SLinus Torvalds 	/* Stop LASI barking for a bit */
66*1da177e4SLinus Torvalds 	gsc_writel(0x00000000, lasi_base+OFFSET_IMR);
67*1da177e4SLinus Torvalds 
68*1da177e4SLinus Torvalds 	/* clear pending interrupts */
69*1da177e4SLinus Torvalds 	gsc_readl(lasi_base+OFFSET_IRR);
70*1da177e4SLinus Torvalds 
71*1da177e4SLinus Torvalds 	/* We're not really convinced we want to reset the onboard
72*1da177e4SLinus Torvalds          * devices. Firmware does it for us...
73*1da177e4SLinus Torvalds 	 */
74*1da177e4SLinus Torvalds 
75*1da177e4SLinus Torvalds 	/* Resets */
76*1da177e4SLinus Torvalds 	/* gsc_writel(0xFFFFFFFF, lasi_base+0x2000);*/	/* Parallel */
77*1da177e4SLinus Torvalds 	if(pdc_add_valid(lasi_base+0x4004) == PDC_OK)
78*1da177e4SLinus Torvalds 		gsc_writel(0xFFFFFFFF, lasi_base+0x4004);	/* Audio */
79*1da177e4SLinus Torvalds 	/* gsc_writel(0xFFFFFFFF, lasi_base+0x5000);*/	/* Serial */
80*1da177e4SLinus Torvalds 	/* gsc_writel(0xFFFFFFFF, lasi_base+0x6000);*/	/* SCSI */
81*1da177e4SLinus Torvalds 	gsc_writel(0xFFFFFFFF, lasi_base+0x7000);	/* LAN */
82*1da177e4SLinus Torvalds 	gsc_writel(0xFFFFFFFF, lasi_base+0x8000);	/* Keyboard */
83*1da177e4SLinus Torvalds 	gsc_writel(0xFFFFFFFF, lasi_base+0xA000);	/* FDC */
84*1da177e4SLinus Torvalds 
85*1da177e4SLinus Torvalds 	/* Ok we hit it on the head with a hammer, our Dog is now
86*1da177e4SLinus Torvalds 	** comatose and muzzled.  Devices will now unmask LASI
87*1da177e4SLinus Torvalds 	** interrupts as they are registered as irq's in the LASI range.
88*1da177e4SLinus Torvalds 	*/
89*1da177e4SLinus Torvalds 	/* XXX: I thought it was `awks that got `it on the `ead with an
90*1da177e4SLinus Torvalds 	 * `ammer.  -- willy
91*1da177e4SLinus Torvalds 	 */
92*1da177e4SLinus Torvalds }
93*1da177e4SLinus Torvalds 
94*1da177e4SLinus Torvalds 
95*1da177e4SLinus Torvalds /*
96*1da177e4SLinus Torvalds    ** lasi_led_init()
97*1da177e4SLinus Torvalds    **
98*1da177e4SLinus Torvalds    ** lasi_led_init() initializes the LED controller on the LASI.
99*1da177e4SLinus Torvalds    **
100*1da177e4SLinus Torvalds    ** Since Mirage and Electra machines use a different LED
101*1da177e4SLinus Torvalds    ** address register, we need to check for these machines
102*1da177e4SLinus Torvalds    ** explicitly.
103*1da177e4SLinus Torvalds  */
104*1da177e4SLinus Torvalds 
105*1da177e4SLinus Torvalds #ifndef CONFIG_CHASSIS_LCD_LED
106*1da177e4SLinus Torvalds 
107*1da177e4SLinus Torvalds #define lasi_led_init(x)	/* nothing */
108*1da177e4SLinus Torvalds 
109*1da177e4SLinus Torvalds #else
110*1da177e4SLinus Torvalds 
111*1da177e4SLinus Torvalds void __init lasi_led_init(unsigned long lasi_hpa)
112*1da177e4SLinus Torvalds {
113*1da177e4SLinus Torvalds 	unsigned long datareg;
114*1da177e4SLinus Torvalds 
115*1da177e4SLinus Torvalds 	switch (CPU_HVERSION) {
116*1da177e4SLinus Torvalds 	/* Gecko machines have only one single LED, which can be permanently
117*1da177e4SLinus Torvalds 	   turned on by writing a zero into the power control register. */
118*1da177e4SLinus Torvalds 	case 0x600:		/* Gecko (712/60) */
119*1da177e4SLinus Torvalds 	case 0x601:		/* Gecko (712/80) */
120*1da177e4SLinus Torvalds 	case 0x602:		/* Gecko (712/100) */
121*1da177e4SLinus Torvalds 	case 0x603:		/* Anole 64 (743/64) */
122*1da177e4SLinus Torvalds 	case 0x604:		/* Anole 100 (743/100) */
123*1da177e4SLinus Torvalds 	case 0x605:		/* Gecko (712/120) */
124*1da177e4SLinus Torvalds 		datareg = lasi_hpa + 0x0000C000;
125*1da177e4SLinus Torvalds 		gsc_writeb(0, datareg);
126*1da177e4SLinus Torvalds 		return; /* no need to register the LED interrupt-function */
127*1da177e4SLinus Torvalds 
128*1da177e4SLinus Torvalds 	/* Mirage and Electra machines need special offsets */
129*1da177e4SLinus Torvalds 	case 0x60A:		/* Mirage Jr (715/64) */
130*1da177e4SLinus Torvalds 	case 0x60B:		/* Mirage 100 */
131*1da177e4SLinus Torvalds 	case 0x60C:		/* Mirage 100+ */
132*1da177e4SLinus Torvalds 	case 0x60D:		/* Electra 100 */
133*1da177e4SLinus Torvalds 	case 0x60E:		/* Electra 120 */
134*1da177e4SLinus Torvalds 		datareg = lasi_hpa - 0x00020000;
135*1da177e4SLinus Torvalds 		break;
136*1da177e4SLinus Torvalds 
137*1da177e4SLinus Torvalds 	default:
138*1da177e4SLinus Torvalds 		datareg = lasi_hpa + 0x0000C000;
139*1da177e4SLinus Torvalds 		break;
140*1da177e4SLinus Torvalds 	}
141*1da177e4SLinus Torvalds 
142*1da177e4SLinus Torvalds 	register_led_driver(DISPLAY_MODEL_LASI, LED_CMD_REG_NONE, datareg);
143*1da177e4SLinus Torvalds }
144*1da177e4SLinus Torvalds #endif
145*1da177e4SLinus Torvalds 
146*1da177e4SLinus Torvalds /*
147*1da177e4SLinus Torvalds  * lasi_power_off
148*1da177e4SLinus Torvalds  *
149*1da177e4SLinus Torvalds  * Function for lasi to turn off the power.  This is accomplished by setting a
150*1da177e4SLinus Torvalds  * 1 to PWR_ON_L in the Power Control Register
151*1da177e4SLinus Torvalds  *
152*1da177e4SLinus Torvalds  */
153*1da177e4SLinus Torvalds 
154*1da177e4SLinus Torvalds static unsigned long lasi_power_off_hpa;
155*1da177e4SLinus Torvalds 
156*1da177e4SLinus Torvalds static void lasi_power_off(void)
157*1da177e4SLinus Torvalds {
158*1da177e4SLinus Torvalds 	unsigned long datareg;
159*1da177e4SLinus Torvalds 
160*1da177e4SLinus Torvalds 	/* calculate addr of the Power Control Register */
161*1da177e4SLinus Torvalds 	datareg = lasi_power_off_hpa + 0x0000C000;
162*1da177e4SLinus Torvalds 
163*1da177e4SLinus Torvalds 	/* Power down the machine */
164*1da177e4SLinus Torvalds 	gsc_writel(0x02, datareg);
165*1da177e4SLinus Torvalds }
166*1da177e4SLinus Torvalds 
167*1da177e4SLinus Torvalds int __init
168*1da177e4SLinus Torvalds lasi_init_chip(struct parisc_device *dev)
169*1da177e4SLinus Torvalds {
170*1da177e4SLinus Torvalds 	struct gsc_asic *lasi;
171*1da177e4SLinus Torvalds 	struct gsc_irq gsc_irq;
172*1da177e4SLinus Torvalds 	int ret;
173*1da177e4SLinus Torvalds 
174*1da177e4SLinus Torvalds 	lasi = kmalloc(sizeof(*lasi), GFP_KERNEL);
175*1da177e4SLinus Torvalds 	if (!lasi)
176*1da177e4SLinus Torvalds 		return -ENOMEM;
177*1da177e4SLinus Torvalds 
178*1da177e4SLinus Torvalds 	lasi->name = "Lasi";
179*1da177e4SLinus Torvalds 	lasi->hpa = dev->hpa;
180*1da177e4SLinus Torvalds 
181*1da177e4SLinus Torvalds 	/* Check the 4-bit (yes, only 4) version register */
182*1da177e4SLinus Torvalds 	lasi->version = gsc_readl(lasi->hpa + LASI_VER) & 0xf;
183*1da177e4SLinus Torvalds 	printk(KERN_INFO "%s version %d at 0x%lx found.\n",
184*1da177e4SLinus Torvalds 		lasi->name, lasi->version, lasi->hpa);
185*1da177e4SLinus Torvalds 
186*1da177e4SLinus Torvalds 	/* initialize the chassis LEDs really early */
187*1da177e4SLinus Torvalds 	lasi_led_init(lasi->hpa);
188*1da177e4SLinus Torvalds 
189*1da177e4SLinus Torvalds 	/* Stop LASI barking for a bit */
190*1da177e4SLinus Torvalds 	lasi_init_irq(lasi);
191*1da177e4SLinus Torvalds 
192*1da177e4SLinus Torvalds 	/* the IRQ lasi should use */
193*1da177e4SLinus Torvalds 	dev->irq = gsc_alloc_irq(&gsc_irq);
194*1da177e4SLinus Torvalds 	if (dev->irq < 0) {
195*1da177e4SLinus Torvalds 		printk(KERN_ERR "%s(): cannot get GSC irq\n",
196*1da177e4SLinus Torvalds 				__FUNCTION__);
197*1da177e4SLinus Torvalds 		kfree(lasi);
198*1da177e4SLinus Torvalds 		return -EBUSY;
199*1da177e4SLinus Torvalds 	}
200*1da177e4SLinus Torvalds 
201*1da177e4SLinus Torvalds 	lasi->eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;
202*1da177e4SLinus Torvalds 
203*1da177e4SLinus Torvalds 	ret = request_irq(gsc_irq.irq, gsc_asic_intr, 0, "lasi", lasi);
204*1da177e4SLinus Torvalds 	if (ret < 0) {
205*1da177e4SLinus Torvalds 		kfree(lasi);
206*1da177e4SLinus Torvalds 		return ret;
207*1da177e4SLinus Torvalds 	}
208*1da177e4SLinus Torvalds 
209*1da177e4SLinus Torvalds 	/* enable IRQ's for devices below LASI */
210*1da177e4SLinus Torvalds 	gsc_writel(lasi->eim, lasi->hpa + OFFSET_IAR);
211*1da177e4SLinus Torvalds 
212*1da177e4SLinus Torvalds 	/* Done init'ing, register this driver */
213*1da177e4SLinus Torvalds 	ret = gsc_common_setup(dev, lasi);
214*1da177e4SLinus Torvalds 	if (ret) {
215*1da177e4SLinus Torvalds 		kfree(lasi);
216*1da177e4SLinus Torvalds 		return ret;
217*1da177e4SLinus Torvalds 	}
218*1da177e4SLinus Torvalds 
219*1da177e4SLinus Torvalds 	gsc_fixup_irqs(dev, lasi, lasi_choose_irq);
220*1da177e4SLinus Torvalds 
221*1da177e4SLinus Torvalds 	/* initialize the power off function */
222*1da177e4SLinus Torvalds 	/* FIXME: Record the LASI HPA for the power off function.  This should
223*1da177e4SLinus Torvalds 	 * ensure that only the first LASI (the one controlling the power off)
224*1da177e4SLinus Torvalds 	 * should set the HPA here */
225*1da177e4SLinus Torvalds 	lasi_power_off_hpa = lasi->hpa;
226*1da177e4SLinus Torvalds 	pm_power_off = lasi_power_off;
227*1da177e4SLinus Torvalds 
228*1da177e4SLinus Torvalds 	return ret;
229*1da177e4SLinus Torvalds }
230*1da177e4SLinus Torvalds 
231*1da177e4SLinus Torvalds static struct parisc_device_id lasi_tbl[] = {
232*1da177e4SLinus Torvalds 	{ HPHW_BA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00081 },
233*1da177e4SLinus Torvalds 	{ 0, }
234*1da177e4SLinus Torvalds };
235*1da177e4SLinus Torvalds 
236*1da177e4SLinus Torvalds struct parisc_driver lasi_driver = {
237*1da177e4SLinus Torvalds 	.name =		"Lasi",
238*1da177e4SLinus Torvalds 	.id_table =	lasi_tbl,
239*1da177e4SLinus Torvalds 	.probe =	lasi_init_chip,
240*1da177e4SLinus Torvalds };
241