2010-06-24 17:11:28 +04:00
/*
* Copyright 2008 - 2009 Freescale Semiconductor , Inc . All Rights Reserved .
* Copyright ( C ) 2010 Jason Wang < jason77 . wang @ gmail . com >
*
* The code contained herein is licensed under the GNU General Public
* License . You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations :
*
* http : //www.opensource.org/licenses/gpl-license.html
* http : //www.gnu.org/copyleft/gpl.html
*/
# include <linux/interrupt.h>
# include <linux/irq.h>
# include <linux/io.h>
# include <linux/platform_device.h>
# include <linux/gpio.h>
# include <linux/smsc911x.h>
# include <mach/hardware.h>
/* LAN9217 ethernet base address */
# define LAN9217_BASE_ADDR(n) (n + 0x0)
/* External UART */
# define UARTA_BASE_ADDR(n) (n + 0x8000)
# define UARTB_BASE_ADDR(n) (n + 0x10000)
# define BOARD_IO_ADDR(n) (n + 0x20000)
/* LED switchs */
# define LED_SWITCH_REG 0x00
/* buttons */
# define SWITCH_BUTTONS_REG 0x08
/* status, interrupt */
# define INTR_STATUS_REG 0x10
# define INTR_MASK_REG 0x38
# define INTR_RESET_REG 0x20
/* magic word for debug CPLD */
# define MAGIC_NUMBER1_REG 0x40
# define MAGIC_NUMBER2_REG 0x48
/* CPLD code version */
# define CPLD_CODE_VER_REG 0x50
/* magic word for debug CPLD */
# define MAGIC_NUMBER3_REG 0x58
/* module reset register*/
# define MODULE_RESET_REG 0x60
/* CPU ID and Personality ID */
# define MCU_BOARD_ID_REG 0x68
# define MXC_IRQ_TO_EXPIO(irq) ((irq) - MXC_BOARD_IRQ_START)
# define MXC_IRQ_TO_GPIO(irq) ((irq) - MXC_INTERNAL_IRQS)
# define MXC_EXP_IO_BASE (MXC_BOARD_IRQ_START)
# define MXC_MAX_EXP_IO_LINES 16
/* interrupts like external uart , external ethernet etc*/
# define EXPIO_INT_ENET (MXC_BOARD_IRQ_START + 0)
# define EXPIO_INT_XUART_A (MXC_BOARD_IRQ_START + 1)
# define EXPIO_INT_XUART_B (MXC_BOARD_IRQ_START + 2)
# define EXPIO_INT_BUTTON_A (MXC_BOARD_IRQ_START + 3)
# define EXPIO_INT_BUTTON_B (MXC_BOARD_IRQ_START + 4)
static void __iomem * brd_io ;
static struct resource smsc911x_resources [ ] = {
{
. flags = IORESOURCE_MEM ,
} , {
. start = EXPIO_INT_ENET ,
. end = EXPIO_INT_ENET ,
. flags = IORESOURCE_IRQ ,
} ,
} ;
static struct smsc911x_platform_config smsc911x_config = {
. irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW ,
. flags = SMSC911X_USE_32BIT | SMSC911X_FORCE_INTERNAL_PHY ,
} ;
static struct platform_device smsc_lan9217_device = {
. name = " smsc911x " ,
. id = 0 ,
. dev = {
. platform_data = & smsc911x_config ,
} ,
. num_resources = ARRAY_SIZE ( smsc911x_resources ) ,
. resource = smsc911x_resources ,
} ;
static void mxc_expio_irq_handler ( u32 irq , struct irq_desc * desc )
{
u32 imr_val ;
u32 int_valid ;
u32 expio_irq ;
2010-11-29 13:16:23 +03:00
/* irq = gpio irq number */
desc - > irq_data . chip - > irq_mask ( & desc - > irq_data ) ;
2010-06-24 17:11:28 +04:00
imr_val = __raw_readw ( brd_io + INTR_MASK_REG ) ;
int_valid = __raw_readw ( brd_io + INTR_STATUS_REG ) & ~ imr_val ;
expio_irq = MXC_BOARD_IRQ_START ;
for ( ; int_valid ! = 0 ; int_valid > > = 1 , expio_irq + + ) {
if ( ( int_valid & 1 ) = = 0 )
continue ;
2011-03-24 14:43:25 +03:00
generic_handle_irq ( expio_irq ) ;
2010-06-24 17:11:28 +04:00
}
2010-11-29 13:16:23 +03:00
desc - > irq_data . chip - > irq_ack ( & desc - > irq_data ) ;
desc - > irq_data . chip - > irq_unmask ( & desc - > irq_data ) ;
2010-06-24 17:11:28 +04:00
}
/*
* Disable an expio pin ' s interrupt by setting the bit in the imr .
* Irq is an expio virtual irq number
*/
2010-11-29 13:16:23 +03:00
static void expio_mask_irq ( struct irq_data * d )
2010-06-24 17:11:28 +04:00
{
u16 reg ;
2010-11-29 13:16:23 +03:00
u32 expio = MXC_IRQ_TO_EXPIO ( d - > irq ) ;
2010-06-24 17:11:28 +04:00
reg = __raw_readw ( brd_io + INTR_MASK_REG ) ;
reg | = ( 1 < < expio ) ;
__raw_writew ( reg , brd_io + INTR_MASK_REG ) ;
}
2010-11-29 13:16:23 +03:00
static void expio_ack_irq ( struct irq_data * d )
2010-06-24 17:11:28 +04:00
{
2010-11-29 13:16:23 +03:00
u32 expio = MXC_IRQ_TO_EXPIO ( d - > irq ) ;
2010-06-24 17:11:28 +04:00
__raw_writew ( 1 < < expio , brd_io + INTR_RESET_REG ) ;
__raw_writew ( 0 , brd_io + INTR_RESET_REG ) ;
2010-11-29 13:16:23 +03:00
expio_mask_irq ( d ) ;
2010-06-24 17:11:28 +04:00
}
2010-11-29 13:16:23 +03:00
static void expio_unmask_irq ( struct irq_data * d )
2010-06-24 17:11:28 +04:00
{
u16 reg ;
2010-11-29 13:16:23 +03:00
u32 expio = MXC_IRQ_TO_EXPIO ( d - > irq ) ;
2010-06-24 17:11:28 +04:00
reg = __raw_readw ( brd_io + INTR_MASK_REG ) ;
reg & = ~ ( 1 < < expio ) ;
__raw_writew ( reg , brd_io + INTR_MASK_REG ) ;
}
static struct irq_chip expio_irq_chip = {
2010-11-29 13:16:23 +03:00
. irq_ack = expio_ack_irq ,
. irq_mask = expio_mask_irq ,
. irq_unmask = expio_unmask_irq ,
2010-06-24 17:11:28 +04:00
} ;
int __init mxc_expio_init ( u32 base , u32 p_irq )
{
int i ;
brd_io = ioremap ( BOARD_IO_ADDR ( base ) , SZ_4K ) ;
if ( brd_io = = NULL )
return - ENOMEM ;
if ( ( __raw_readw ( brd_io + MAGIC_NUMBER1_REG ) ! = 0xAAAA ) | |
( __raw_readw ( brd_io + MAGIC_NUMBER2_REG ) ! = 0x5555 ) | |
( __raw_readw ( brd_io + MAGIC_NUMBER3_REG ) ! = 0xCAFE ) ) {
pr_info ( " 3-Stack Debug board not detected \n " ) ;
iounmap ( brd_io ) ;
brd_io = NULL ;
return - ENODEV ;
}
pr_info ( " 3-Stack Debug board detected, rev = 0x%04X \n " ,
readw ( brd_io + CPLD_CODE_VER_REG ) ) ;
/*
* Configure INT line as GPIO input
*/
gpio_request ( MXC_IRQ_TO_GPIO ( p_irq ) , " expio_pirq " ) ;
gpio_direction_input ( MXC_IRQ_TO_GPIO ( p_irq ) ) ;
/* disable the interrupt and clear the status */
__raw_writew ( 0 , brd_io + INTR_MASK_REG ) ;
__raw_writew ( 0xFFFF , brd_io + INTR_RESET_REG ) ;
__raw_writew ( 0 , brd_io + INTR_RESET_REG ) ;
__raw_writew ( 0x1F , brd_io + INTR_MASK_REG ) ;
for ( i = MXC_EXP_IO_BASE ;
i < ( MXC_EXP_IO_BASE + MXC_MAX_EXP_IO_LINES ) ; i + + ) {
2011-03-24 15:25:22 +03:00
irq_set_chip ( i , & expio_irq_chip ) ;
irq_set_handler ( i , handle_level_irq ) ;
2010-06-24 17:11:28 +04:00
set_irq_flags ( i , IRQF_VALID ) ;
}
2011-03-24 15:25:22 +03:00
irq_set_irq_type ( p_irq , IRQF_TRIGGER_LOW ) ;
irq_set_chained_handler ( p_irq , mxc_expio_irq_handler ) ;
2010-06-24 17:11:28 +04:00
/* Register Lan device on the debugboard */
smsc911x_resources [ 0 ] . start = LAN9217_BASE_ADDR ( base ) ;
smsc911x_resources [ 0 ] . end = LAN9217_BASE_ADDR ( base ) + 0x100 - 1 ;
platform_device_register ( & smsc_lan9217_device ) ;
return 0 ;
}