2005-04-17 02:20:36 +04:00
/*
* LASI Device Driver
*
* ( c ) Copyright 1999 Red Hat Software
* Portions ( c ) Copyright 1999 The Puffin Group Inc .
* Portions ( c ) Copyright 1999 Hewlett - Packard
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* by Alan Cox < alan @ redhat . com > and
* Alex deVries < alex @ onefishtwo . ca >
*/
# include <linux/errno.h>
# include <linux/init.h>
# include <linux/interrupt.h>
# include <linux/slab.h>
# include <linux/module.h>
# include <linux/pm.h>
# include <linux/types.h>
# include <asm/io.h>
# include <asm/hardware.h>
# include <asm/led.h>
# include "gsc.h"
# define LASI_VER 0xC008 /* LASI Version */
# define LASI_IO_CONF 0x7FFFE /* LASI primary configuration register */
# define LASI_IO_CONF2 0x7FFFF /* LASI secondary configuration register */
static void lasi_choose_irq ( struct parisc_device * dev , void * ctrl )
{
int irq ;
switch ( dev - > id . sversion ) {
case 0x74 : irq = 7 ; break ; /* Centronics */
case 0x7B : irq = 13 ; break ; /* Audio */
case 0x81 : irq = 14 ; break ; /* Lasi itself */
case 0x82 : irq = 9 ; break ; /* SCSI */
case 0x83 : irq = 20 ; break ; /* Floppy */
case 0x84 : irq = 26 ; break ; /* PS/2 Keyboard */
case 0x87 : irq = 18 ; break ; /* ISDN */
case 0x8A : irq = 8 ; break ; /* LAN */
case 0x8C : irq = 5 ; break ; /* RS232 */
case 0x8D : irq = ( dev - > hw_path = = 13 ) ? 16 : 17 ; break ;
/* Telephone */
default : return ; /* unknown */
}
gsc_asic_assign_irq ( ctrl , irq , & dev - > irq ) ;
}
static void __init
lasi_init_irq ( struct gsc_asic * this_lasi )
{
unsigned long lasi_base = this_lasi - > hpa ;
/* Stop LASI barking for a bit */
gsc_writel ( 0x00000000 , lasi_base + OFFSET_IMR ) ;
/* clear pending interrupts */
gsc_readl ( lasi_base + OFFSET_IRR ) ;
/* We're not really convinced we want to reset the onboard
* devices . Firmware does it for us . . .
*/
/* Resets */
/* gsc_writel(0xFFFFFFFF, lasi_base+0x2000);*/ /* Parallel */
if ( pdc_add_valid ( lasi_base + 0x4004 ) = = PDC_OK )
gsc_writel ( 0xFFFFFFFF , lasi_base + 0x4004 ) ; /* Audio */
/* gsc_writel(0xFFFFFFFF, lasi_base+0x5000);*/ /* Serial */
/* gsc_writel(0xFFFFFFFF, lasi_base+0x6000);*/ /* SCSI */
gsc_writel ( 0xFFFFFFFF , lasi_base + 0x7000 ) ; /* LAN */
gsc_writel ( 0xFFFFFFFF , lasi_base + 0x8000 ) ; /* Keyboard */
gsc_writel ( 0xFFFFFFFF , lasi_base + 0xA000 ) ; /* FDC */
/* Ok we hit it on the head with a hammer, our Dog is now
* * comatose and muzzled . Devices will now unmask LASI
* * interrupts as they are registered as irq ' s in the LASI range .
*/
/* XXX: I thought it was `awks that got `it on the `ead with an
* ` ammer . - - willy
*/
}
/*
* * lasi_led_init ( )
* *
* * lasi_led_init ( ) initializes the LED controller on the LASI .
* *
* * Since Mirage and Electra machines use a different LED
* * address register , we need to check for these machines
* * explicitly .
*/
# ifndef CONFIG_CHASSIS_LCD_LED
# define lasi_led_init(x) /* nothing */
# else
void __init lasi_led_init ( unsigned long lasi_hpa )
{
unsigned long datareg ;
switch ( CPU_HVERSION ) {
/* Gecko machines have only one single LED, which can be permanently
turned on by writing a zero into the power control register . */
case 0x600 : /* Gecko (712/60) */
case 0x601 : /* Gecko (712/80) */
case 0x602 : /* Gecko (712/100) */
case 0x603 : /* Anole 64 (743/64) */
case 0x604 : /* Anole 100 (743/100) */
case 0x605 : /* Gecko (712/120) */
datareg = lasi_hpa + 0x0000C000 ;
gsc_writeb ( 0 , datareg ) ;
return ; /* no need to register the LED interrupt-function */
/* Mirage and Electra machines need special offsets */
case 0x60A : /* Mirage Jr (715/64) */
case 0x60B : /* Mirage 100 */
case 0x60C : /* Mirage 100+ */
case 0x60D : /* Electra 100 */
case 0x60E : /* Electra 120 */
datareg = lasi_hpa - 0x00020000 ;
break ;
default :
datareg = lasi_hpa + 0x0000C000 ;
break ;
}
register_led_driver ( DISPLAY_MODEL_LASI , LED_CMD_REG_NONE , datareg ) ;
}
# endif
/*
* lasi_power_off
*
* Function for lasi to turn off the power . This is accomplished by setting a
* 1 to PWR_ON_L in the Power Control Register
*
*/
2006-01-11 04:35:03 +03:00
static unsigned long lasi_power_off_hpa __read_mostly ;
2005-04-17 02:20:36 +04:00
static void lasi_power_off ( void )
{
unsigned long datareg ;
/* calculate addr of the Power Control Register */
datareg = lasi_power_off_hpa + 0x0000C000 ;
/* Power down the machine */
gsc_writel ( 0x02 , datareg ) ;
}
int __init
lasi_init_chip ( struct parisc_device * dev )
{
2006-01-18 08:33:32 +03:00
extern void ( * chassis_power_off ) ( void ) ;
2005-04-17 02:20:36 +04:00
struct gsc_asic * lasi ;
struct gsc_irq gsc_irq ;
int ret ;
2006-01-17 22:40:40 +03:00
lasi = kzalloc ( sizeof ( * lasi ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! lasi )
return - ENOMEM ;
lasi - > name = " Lasi " ;
2005-10-22 06:36:40 +04:00
lasi - > hpa = dev - > hpa . start ;
2005-04-17 02:20:36 +04:00
/* Check the 4-bit (yes, only 4) version register */
lasi - > version = gsc_readl ( lasi - > hpa + LASI_VER ) & 0xf ;
printk ( KERN_INFO " %s version %d at 0x%lx found. \n " ,
lasi - > name , lasi - > version , lasi - > hpa ) ;
/* initialize the chassis LEDs really early */
lasi_led_init ( lasi - > hpa ) ;
/* Stop LASI barking for a bit */
lasi_init_irq ( lasi ) ;
/* the IRQ lasi should use */
dev - > irq = gsc_alloc_irq ( & gsc_irq ) ;
if ( dev - > irq < 0 ) {
printk ( KERN_ERR " %s(): cannot get GSC irq \n " ,
__FUNCTION__ ) ;
kfree ( lasi ) ;
return - EBUSY ;
}
lasi - > eim = ( ( u32 ) gsc_irq . txn_addr ) | gsc_irq . txn_data ;
ret = request_irq ( gsc_irq . irq , gsc_asic_intr , 0 , " lasi " , lasi ) ;
if ( ret < 0 ) {
kfree ( lasi ) ;
return ret ;
}
/* enable IRQ's for devices below LASI */
gsc_writel ( lasi - > eim , lasi - > hpa + OFFSET_IAR ) ;
/* Done init'ing, register this driver */
ret = gsc_common_setup ( dev , lasi ) ;
if ( ret ) {
kfree ( lasi ) ;
return ret ;
}
gsc_fixup_irqs ( dev , lasi , lasi_choose_irq ) ;
/* initialize the power off function */
/* FIXME: Record the LASI HPA for the power off function. This should
* ensure that only the first LASI ( the one controlling the power off )
* should set the HPA here */
lasi_power_off_hpa = lasi - > hpa ;
2006-01-18 08:33:32 +03:00
chassis_power_off = lasi_power_off ;
2005-04-17 02:20:36 +04:00
return ret ;
}
static struct parisc_device_id lasi_tbl [ ] = {
{ HPHW_BA , HVERSION_REV_ANY_ID , HVERSION_ANY_ID , 0x00081 } ,
{ 0 , }
} ;
struct parisc_driver lasi_driver = {
2005-10-22 06:36:23 +04:00
. name = " lasi " ,
2005-04-17 02:20:36 +04:00
. id_table = lasi_tbl ,
. probe = lasi_init_chip ,
} ;