2005-04-16 15:20:36 -07:00
/* arch/arm/mach-lh7a40x/arch-lpd7a40x.c
*
* Copyright ( C ) 2004 Logic Product Development
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation .
*
*/
# include <linux/tty.h>
# include <linux/init.h>
2005-10-29 19:07:23 +01:00
# include <linux/platform_device.h>
2005-04-16 15:20:36 -07:00
# include <linux/interrupt.h>
2006-07-01 22:32:40 +01:00
# include <linux/irq.h>
2005-04-16 15:20:36 -07:00
2008-08-05 16:14:15 +01:00
# include <mach/hardware.h>
2005-04-16 15:20:36 -07:00
# include <asm/setup.h>
# include <asm/mach-types.h>
# include <asm/mach/arch.h>
# include <asm/irq.h>
# include <asm/mach/irq.h>
# include <asm/mach/map.h>
# include "common.h"
2006-05-16 11:41:28 +01:00
# define CPLD_INT_NETHERNET (1<<0)
# define CPLD_INTMASK_ETHERNET (1<<2)
# if defined (CONFIG_MACH_LPD7A400)
# define CPLD_INT_NTOUCH (1<<1)
# define CPLD_INTMASK_TOUCH (1<<3)
# define CPLD_INT_PEN (1<<4)
# define CPLD_INTMASK_PEN (1<<4)
# define CPLD_INT_PIRQ (1<<4)
# endif
# define CPLD_INTMASK_CPLD (1<<7)
# define CPLD_INT_CPLD (1<<6)
# define CPLD_CONTROL_SWINT (1<<7) /* Disable all CPLD IRQs */
# define CPLD_CONTROL_OCMSK (1<<6) /* Mask USB1 connect IRQ */
# define CPLD_CONTROL_PDRV (1<<5) /* PCC_nDRV high */
# define CPLD_CONTROL_USB1C (1<<4) /* USB1 connect IRQ active */
# define CPLD_CONTROL_USB1P (1<<3) /* USB1 power disable */
# define CPLD_CONTROL_AWKP (1<<2) /* Auto-wakeup disabled */
# define CPLD_CONTROL_LCD_ENABLE (1<<1) /* LCD Vee enable */
# define CPLD_CONTROL_WRLAN_NENABLE (1<<0) /* SMC91x power disable */
2005-04-16 15:20:36 -07:00
static struct resource smc91x_resources [ ] = {
[ 0 ] = {
. start = CPLD00_PHYS ,
. end = CPLD00_PHYS + CPLD00_SIZE - 1 , /* Only needs 16B */
. flags = IORESOURCE_MEM ,
} ,
[ 1 ] = {
. start = IRQ_LPD7A40X_ETH_INT ,
. end = IRQ_LPD7A40X_ETH_INT ,
. flags = IORESOURCE_IRQ ,
} ,
} ;
static struct platform_device smc91x_device = {
. name = " smc91x " ,
. id = 0 ,
. num_resources = ARRAY_SIZE ( smc91x_resources ) ,
. resource = smc91x_resources ,
} ;
static struct resource lh7a40x_usbclient_resources [ ] = {
[ 0 ] = {
. start = USB_PHYS ,
2006-05-16 11:41:28 +01:00
. end = ( USB_PHYS + PAGE_SIZE ) ,
2005-04-16 15:20:36 -07:00
. flags = IORESOURCE_MEM ,
} ,
[ 1 ] = {
2006-05-16 11:41:28 +01:00
. start = IRQ_USB ,
. end = IRQ_USB ,
2005-04-16 15:20:36 -07:00
. flags = IORESOURCE_IRQ ,
} ,
} ;
static u64 lh7a40x_usbclient_dma_mask = 0xffffffffUL ;
static struct platform_device lh7a40x_usbclient_device = {
2006-05-16 11:41:28 +01:00
// .name = "lh7a40x_udc",
. name = " lh7-udc " ,
2005-04-16 15:20:36 -07:00
. id = 0 ,
. dev = {
. dma_mask = & lh7a40x_usbclient_dma_mask ,
. coherent_dma_mask = 0xffffffffUL ,
} ,
. num_resources = ARRAY_SIZE ( lh7a40x_usbclient_resources ) ,
. resource = lh7a40x_usbclient_resources ,
} ;
# if defined (CONFIG_ARCH_LH7A404)
static struct resource lh7a404_usbhost_resources [ ] = {
[ 0 ] = {
. start = USBH_PHYS ,
. end = ( USBH_PHYS + 0xFF ) ,
. flags = IORESOURCE_MEM ,
} ,
[ 1 ] = {
. start = IRQ_USHINTR ,
. end = IRQ_USHINTR ,
. flags = IORESOURCE_IRQ ,
} ,
} ;
static u64 lh7a404_usbhost_dma_mask = 0xffffffffUL ;
static struct platform_device lh7a404_usbhost_device = {
. name = " lh7a404-ohci " ,
. id = 0 ,
. dev = {
. dma_mask = & lh7a404_usbhost_dma_mask ,
. coherent_dma_mask = 0xffffffffUL ,
} ,
. num_resources = ARRAY_SIZE ( lh7a404_usbhost_resources ) ,
. resource = lh7a404_usbhost_resources ,
} ;
# endif
2006-05-16 11:41:28 +01:00
static struct platform_device * lpd7a40x_devs [ ] __initdata = {
2005-04-16 15:20:36 -07:00
& smc91x_device ,
& lh7a40x_usbclient_device ,
# if defined (CONFIG_ARCH_LH7A404)
& lh7a404_usbhost_device ,
# endif
} ;
extern void lpd7a400_map_io ( void ) ;
static void __init lpd7a40x_init ( void )
{
2006-05-16 11:41:28 +01:00
# if defined (CONFIG_MACH_LPD7A400)
CPLD_CONTROL | = 0
| CPLD_CONTROL_SWINT /* Disable software interrupt */
| CPLD_CONTROL_OCMSK ; /* Mask USB1 connection IRQ */
2005-04-16 15:20:36 -07:00
CPLD_CONTROL & = ~ ( 0
2006-05-16 11:41:28 +01:00
| CPLD_CONTROL_LCD_ENABLE /* Disable LCD */
| CPLD_CONTROL_WRLAN_NENABLE /* Enable SMC91x */
2005-04-16 15:20:36 -07:00
) ;
2006-05-16 11:41:28 +01:00
# endif
# if defined (CONFIG_MACH_LPD7A404)
CPLD_CONTROL & = ~ ( 0
| CPLD_CONTROL_WRLAN_NENABLE /* Enable SMC91x */
) ;
# endif
2005-04-16 15:20:36 -07:00
platform_add_devices ( lpd7a40x_devs , ARRAY_SIZE ( lpd7a40x_devs ) ) ;
2006-05-16 11:41:28 +01:00
# if defined (CONFIG_FB_ARMCLCD)
lh7a40x_clcd_init ( ) ;
# endif
2005-04-16 15:20:36 -07:00
}
static void lh7a40x_ack_cpld_irq ( u32 irq )
{
2006-05-16 11:41:28 +01:00
/* CPLD doesn't have ack capability, but some devices may */
# if defined (CPLD_INTMASK_TOUCH)
2006-10-03 22:21:02 +02:00
/* The touch control *must* mask the interrupt because the
2006-05-16 11:41:28 +01:00
* interrupt bit is read by the driver to determine if the pen
* is still down . */
if ( irq = = IRQ_TOUCH )
CPLD_INTERRUPTS | = CPLD_INTMASK_TOUCH ;
# endif
2005-04-16 15:20:36 -07:00
}
static void lh7a40x_mask_cpld_irq ( u32 irq )
{
switch ( irq ) {
case IRQ_LPD7A40X_ETH_INT :
2006-05-16 11:41:28 +01:00
CPLD_INTERRUPTS | = CPLD_INTMASK_ETHERNET ;
2005-04-16 15:20:36 -07:00
break ;
2006-05-16 11:41:28 +01:00
# if defined (IRQ_TOUCH)
case IRQ_TOUCH :
CPLD_INTERRUPTS | = CPLD_INTMASK_TOUCH ;
2005-04-16 15:20:36 -07:00
break ;
2006-05-16 11:41:28 +01:00
# endif
2005-04-16 15:20:36 -07:00
}
}
static void lh7a40x_unmask_cpld_irq ( u32 irq )
{
switch ( irq ) {
case IRQ_LPD7A40X_ETH_INT :
2006-05-16 11:41:28 +01:00
CPLD_INTERRUPTS & = ~ CPLD_INTMASK_ETHERNET ;
2005-04-16 15:20:36 -07:00
break ;
2006-05-16 11:41:28 +01:00
# if defined (IRQ_TOUCH)
case IRQ_TOUCH :
CPLD_INTERRUPTS & = ~ CPLD_INTMASK_TOUCH ;
2005-04-16 15:20:36 -07:00
break ;
2006-05-16 11:41:28 +01:00
# endif
2005-04-16 15:20:36 -07:00
}
}
2006-08-01 22:26:25 +01:00
static struct irq_chip lpd7a40x_cpld_chip = {
. name = " CPLD " ,
2005-04-16 15:20:36 -07:00
. ack = lh7a40x_ack_cpld_irq ,
. mask = lh7a40x_mask_cpld_irq ,
. unmask = lh7a40x_unmask_cpld_irq ,
} ;
2006-11-23 11:41:32 +00:00
static void lpd7a40x_cpld_handler ( unsigned int irq , struct irq_desc * desc )
2005-04-16 15:20:36 -07:00
{
unsigned int mask = CPLD_INTERRUPTS ;
desc - > chip - > ack ( irq ) ;
2006-05-16 11:41:28 +01:00
if ( ( mask & ( 1 < < 0 ) ) = = 0 ) /* WLAN */
2008-10-09 13:36:24 +01:00
generic_handle_irq ( IRQ_LPD7A40X_ETH_INT ) ;
2005-04-16 15:20:36 -07:00
2006-05-16 11:41:28 +01:00
# if defined (IRQ_TOUCH)
if ( ( mask & ( 1 < < 1 ) ) = = 0 ) /* Touch */
2008-10-09 13:36:24 +01:00
generic_handle_irq ( IRQ_TOUCH ) ;
2006-05-16 11:41:28 +01:00
# endif
2005-04-16 15:20:36 -07:00
desc - > chip - > unmask ( irq ) ; /* Level-triggered need this */
}
void __init lh7a40x_init_board_irq ( void )
{
int irq ;
/* Rev A (v2.8): PF0, PF1, PF2, and PF3 are available IRQs.
PF7 supports the CPLD .
Rev B ( v3 .4 ) : PF0 , PF1 , and PF2 are available IRQs .
PF3 supports the CPLD .
( Some ) LPD7A404 prerelease boards report a version
number of 0x16 , but we force an override since the
hardware is of the newer variety .
*/
unsigned char cpld_version = CPLD_REVISION ;
int pinCPLD = ( cpld_version = = 0x28 ) ? 7 : 3 ;
# if defined CONFIG_MACH_LPD7A404
cpld_version = 0x34 ; /* Coerce LPD7A404 to RevB */
# endif
/* First, configure user controlled GPIOF interrupts */
GPIO_PFDD & = ~ 0x0f ; /* PF0-3 are inputs */
GPIO_INTTYPE1 & = ~ 0x0f ; /* PF0-3 are level triggered */
GPIO_INTTYPE2 & = ~ 0x0f ; /* PF0-3 are active low */
barrier ( ) ;
GPIO_GPIOFINTEN | = 0x0f ; /* Enable PF0, PF1, PF2, and PF3 IRQs */
/* Then, configure CPLD interrupt */
2006-05-16 11:41:28 +01:00
/* Disable all CPLD interrupts */
# if defined (CONFIG_MACH_LPD7A400)
CPLD_INTERRUPTS = CPLD_INTMASK_TOUCH | CPLD_INTMASK_PEN
| CPLD_INTMASK_ETHERNET ;
/* *** FIXME: don't know why we need 7 and 4. 7 is way wrong
and 4 is uncefined . */
// (1<<7)|(1<<4)|(1<<3)|(1<<2);
# endif
# if defined (CONFIG_MACH_LPD7A404)
CPLD_INTERRUPTS = CPLD_INTMASK_ETHERNET ;
/* *** FIXME: don't know why we need 6 and 5, neither is defined. */
// (1<<6)|(1<<5)|(1<<3);
# endif
2005-04-16 15:20:36 -07:00
GPIO_PFDD & = ~ ( 1 < < pinCPLD ) ; /* Make input */
2006-05-16 11:41:28 +01:00
GPIO_INTTYPE1 & = ~ ( 1 < < pinCPLD ) ; /* Level triggered */
2005-04-16 15:20:36 -07:00
GPIO_INTTYPE2 & = ~ ( 1 < < pinCPLD ) ; /* Active low */
barrier ( ) ;
GPIO_GPIOFINTEN | = ( 1 < < pinCPLD ) ; /* Enable */
/* Cascade CPLD interrupts */
for ( irq = IRQ_BOARD_START ;
irq < IRQ_BOARD_START + NR_IRQ_BOARD ; + + irq ) {
set_irq_chip ( irq , & lpd7a40x_cpld_chip ) ;
2006-11-23 11:41:32 +00:00
set_irq_handler ( irq , handle_level_irq ) ;
2005-04-16 15:20:36 -07:00
set_irq_flags ( irq , IRQF_VALID ) ;
}
set_irq_chained_handler ( ( cpld_version = = 0x28 )
? IRQ_CPLD_V28
: IRQ_CPLD_V34 ,
lpd7a40x_cpld_handler ) ;
}
2006-05-16 11:41:28 +01:00
static struct map_desc lpd7a40x_io_desc [ ] __initdata = {
2005-10-28 15:18:59 +01:00
{
2006-05-16 11:41:28 +01:00
. virtual = IO_VIRT ,
2005-10-28 15:18:59 +01:00
. pfn = __phys_to_pfn ( IO_PHYS ) ,
2006-05-16 11:41:28 +01:00
. length = IO_SIZE ,
2005-10-28 15:18:59 +01:00
. type = MT_DEVICE
2006-05-16 11:41:28 +01:00
} ,
{ /* Mapping added to work around chip select problems */
2005-10-28 15:18:59 +01:00
. virtual = IOBARRIER_VIRT ,
. pfn = __phys_to_pfn ( IOBARRIER_PHYS ) ,
. length = IOBARRIER_SIZE ,
. type = MT_DEVICE
2006-05-16 11:41:28 +01:00
} ,
{
2005-10-28 15:18:59 +01:00
. virtual = CF_VIRT ,
. pfn = __phys_to_pfn ( CF_PHYS ) ,
2006-05-16 11:41:28 +01:00
. length = CF_SIZE ,
2005-10-28 15:18:59 +01:00
. type = MT_DEVICE
2006-05-16 11:41:28 +01:00
} ,
{
2005-10-28 15:18:59 +01:00
. virtual = CPLD02_VIRT ,
. pfn = __phys_to_pfn ( CPLD02_PHYS ) ,
2006-05-16 11:41:28 +01:00
. length = CPLD02_SIZE ,
2005-10-28 15:18:59 +01:00
. type = MT_DEVICE
2006-05-16 11:41:28 +01:00
} ,
{
2005-10-28 15:18:59 +01:00
. virtual = CPLD06_VIRT ,
. pfn = __phys_to_pfn ( CPLD06_PHYS ) ,
2006-05-16 11:41:28 +01:00
. length = CPLD06_SIZE ,
. type = MT_DEVICE
} ,
{
. virtual = CPLD08_VIRT ,
. pfn = __phys_to_pfn ( CPLD08_PHYS ) ,
. length = CPLD08_SIZE ,
2005-10-28 15:18:59 +01:00
. type = MT_DEVICE
2006-05-16 11:41:28 +01:00
} ,
{
2005-10-28 15:18:59 +01:00
. virtual = CPLD08_VIRT ,
. pfn = __phys_to_pfn ( CPLD08_PHYS ) ,
2006-05-16 11:41:28 +01:00
. length = CPLD08_SIZE ,
2005-10-28 15:18:59 +01:00
. type = MT_DEVICE
2006-05-16 11:41:28 +01:00
} ,
{
. virtual = CPLD0A_VIRT ,
. pfn = __phys_to_pfn ( CPLD0A_PHYS ) ,
. length = CPLD0A_SIZE ,
. type = MT_DEVICE
} ,
{
2005-10-28 15:18:59 +01:00
. virtual = CPLD0C_VIRT ,
. pfn = __phys_to_pfn ( CPLD0C_PHYS ) ,
2006-05-16 11:41:28 +01:00
. length = CPLD0C_SIZE ,
2005-10-28 15:18:59 +01:00
. type = MT_DEVICE
2006-05-16 11:41:28 +01:00
} ,
{
2005-10-28 15:18:59 +01:00
. virtual = CPLD0E_VIRT ,
. pfn = __phys_to_pfn ( CPLD0E_PHYS ) ,
2006-05-16 11:41:28 +01:00
. length = CPLD0E_SIZE ,
2005-10-28 15:18:59 +01:00
. type = MT_DEVICE
2006-05-16 11:41:28 +01:00
} ,
{
2005-10-28 15:18:59 +01:00
. virtual = CPLD10_VIRT ,
. pfn = __phys_to_pfn ( CPLD10_PHYS ) ,
2006-05-16 11:41:28 +01:00
. length = CPLD10_SIZE ,
2005-10-28 15:18:59 +01:00
. type = MT_DEVICE
2006-05-16 11:41:28 +01:00
} ,
{
2005-10-28 15:18:59 +01:00
. virtual = CPLD12_VIRT ,
. pfn = __phys_to_pfn ( CPLD12_PHYS ) ,
2006-05-16 11:41:28 +01:00
. length = CPLD12_SIZE ,
2005-10-28 15:18:59 +01:00
. type = MT_DEVICE
2006-05-16 11:41:28 +01:00
} ,
{
2005-10-28 15:18:59 +01:00
. virtual = CPLD14_VIRT ,
. pfn = __phys_to_pfn ( CPLD14_PHYS ) ,
2006-05-16 11:41:28 +01:00
. length = CPLD14_SIZE ,
2005-10-28 15:18:59 +01:00
. type = MT_DEVICE
2006-05-16 11:41:28 +01:00
} ,
{
2005-10-28 15:18:59 +01:00
. virtual = CPLD16_VIRT ,
. pfn = __phys_to_pfn ( CPLD16_PHYS ) ,
2006-05-16 11:41:28 +01:00
. length = CPLD16_SIZE ,
2005-10-28 15:18:59 +01:00
. type = MT_DEVICE
2006-05-16 11:41:28 +01:00
} ,
{
2005-10-28 15:18:59 +01:00
. virtual = CPLD18_VIRT ,
. pfn = __phys_to_pfn ( CPLD18_PHYS ) ,
2006-05-16 11:41:28 +01:00
. length = CPLD18_SIZE ,
2005-10-28 15:18:59 +01:00
. type = MT_DEVICE
2006-05-16 11:41:28 +01:00
} ,
{
2005-10-28 15:18:59 +01:00
. virtual = CPLD1A_VIRT ,
. pfn = __phys_to_pfn ( CPLD1A_PHYS ) ,
2006-05-16 11:41:28 +01:00
. length = CPLD1A_SIZE ,
2005-10-28 15:18:59 +01:00
. type = MT_DEVICE
} ,
2005-04-16 15:20:36 -07:00
} ;
void __init
2006-05-16 11:41:28 +01:00
lpd7a40x_map_io ( void )
2005-04-16 15:20:36 -07:00
{
2006-05-16 11:41:28 +01:00
iotable_init ( lpd7a40x_io_desc , ARRAY_SIZE ( lpd7a40x_io_desc ) ) ;
2005-04-16 15:20:36 -07:00
}
# ifdef CONFIG_MACH_LPD7A400
MACHINE_START ( LPD7A400 , " Logic Product Development LPD7A400-10 " )
2005-07-03 17:38:58 +01:00
/* Maintainer: Marc Singer */
. phys_io = 0x80000000 ,
. io_pg_offst = ( ( io_p2v ( 0x80000000 ) ) > > 18 ) & 0xfffc ,
. boot_params = 0xc0000100 ,
2006-05-16 11:41:28 +01:00
. map_io = lpd7a40x_map_io ,
2005-07-03 17:38:58 +01:00
. init_irq = lh7a400_init_irq ,
2005-04-16 15:20:36 -07:00
. timer = & lh7a40x_timer ,
2005-07-03 17:38:58 +01:00
. init_machine = lpd7a40x_init ,
2005-04-16 15:20:36 -07:00
MACHINE_END
# endif
# ifdef CONFIG_MACH_LPD7A404
MACHINE_START ( LPD7A404 , " Logic Product Development LPD7A404-10 " )
2005-07-03 17:38:58 +01:00
/* Maintainer: Marc Singer */
. phys_io = 0x80000000 ,
. io_pg_offst = ( ( io_p2v ( 0x80000000 ) ) > > 18 ) & 0xfffc ,
. boot_params = 0xc0000100 ,
2006-05-16 11:41:28 +01:00
. map_io = lpd7a40x_map_io ,
2005-07-03 17:38:58 +01:00
. init_irq = lh7a404_init_irq ,
2005-04-16 15:20:36 -07:00
. timer = & lh7a40x_timer ,
2005-07-03 17:38:58 +01:00
. init_machine = lpd7a40x_init ,
2005-04-16 15:20:36 -07:00
MACHINE_END
# endif