2008-02-07 11:14:49 +03:00
/*
* driver / mfd / asic3 . c
*
* Compaq ASIC3 support .
*
* 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 .
*
* Copyright 2001 Compaq Computer Corporation .
* Copyright 2004 - 2005 Phil Blundell
2008-06-20 13:02:19 +04:00
* Copyright 2007 - 2008 OpenedHand Ltd .
2008-02-07 11:14:49 +03:00
*
* Authors : Phil Blundell < pb @ handhelds . org > ,
* Samuel Ortiz < sameo @ openedhand . com >
*
*/
# include <linux/version.h>
# include <linux/kernel.h>
# include <linux/irq.h>
2008-06-20 13:02:19 +04:00
# include <linux/gpio.h>
2008-02-07 11:14:49 +03:00
# include <linux/io.h>
# include <linux/spinlock.h>
# include <linux/platform_device.h>
# include <linux/mfd/asic3.h>
2008-06-20 13:02:19 +04:00
struct asic3 {
void __iomem * mapping ;
unsigned int bus_shift ;
unsigned int irq_nr ;
unsigned int irq_base ;
spinlock_t lock ;
u16 irq_bothedge [ 4 ] ;
struct gpio_chip gpio ;
struct device * dev ;
} ;
static int asic3_gpio_get ( struct gpio_chip * chip , unsigned offset ) ;
2008-02-07 11:14:49 +03:00
static inline void asic3_write_register ( struct asic3 * asic ,
unsigned int reg , u32 value )
{
2008-03-29 06:10:58 +03:00
iowrite16 ( value , asic - > mapping +
2008-02-07 11:14:49 +03:00
( reg > > asic - > bus_shift ) ) ;
}
static inline u32 asic3_read_register ( struct asic3 * asic ,
unsigned int reg )
{
2008-03-29 06:10:58 +03:00
return ioread16 ( asic - > mapping +
2008-02-07 11:14:49 +03:00
( reg > > asic - > bus_shift ) ) ;
}
/* IRQs */
# define MAX_ASIC_ISR_LOOPS 20
2008-06-20 13:12:21 +04:00
# define ASIC3_GPIO_BASE_INCR \
( ASIC3_GPIO_B_BASE - ASIC3_GPIO_A_BASE )
2008-02-07 11:14:49 +03:00
static void asic3_irq_flip_edge ( struct asic3 * asic ,
u32 base , int bit )
{
u16 edge ;
unsigned long flags ;
spin_lock_irqsave ( & asic - > lock , flags ) ;
edge = asic3_read_register ( asic ,
2008-06-20 13:12:21 +04:00
base + ASIC3_GPIO_EDGE_TRIGGER ) ;
2008-02-07 11:14:49 +03:00
edge ^ = bit ;
asic3_write_register ( asic ,
2008-06-20 13:12:21 +04:00
base + ASIC3_GPIO_EDGE_TRIGGER , edge ) ;
2008-02-07 11:14:49 +03:00
spin_unlock_irqrestore ( & asic - > lock , flags ) ;
}
static void asic3_irq_demux ( unsigned int irq , struct irq_desc * desc )
{
int iter , i ;
unsigned long flags ;
struct asic3 * asic ;
desc - > chip - > ack ( irq ) ;
asic = desc - > handler_data ;
for ( iter = 0 ; iter < MAX_ASIC_ISR_LOOPS ; iter + + ) {
u32 status ;
int bank ;
spin_lock_irqsave ( & asic - > lock , flags ) ;
status = asic3_read_register ( asic ,
2008-06-20 13:12:21 +04:00
ASIC3_OFFSET ( INTR , P_INT_STAT ) ) ;
2008-02-07 11:14:49 +03:00
spin_unlock_irqrestore ( & asic - > lock , flags ) ;
/* Check all ten register bits */
if ( ( status & 0x3ff ) = = 0 )
break ;
/* Handle GPIO IRQs */
for ( bank = 0 ; bank < ASIC3_NUM_GPIO_BANKS ; bank + + ) {
if ( status & ( 1 < < bank ) ) {
unsigned long base , istat ;
2008-06-20 13:12:21 +04:00
base = ASIC3_GPIO_A_BASE
+ bank * ASIC3_GPIO_BASE_INCR ;
2008-02-07 11:14:49 +03:00
spin_lock_irqsave ( & asic - > lock , flags ) ;
istat = asic3_read_register ( asic ,
base +
2008-06-20 13:12:21 +04:00
ASIC3_GPIO_INT_STATUS ) ;
2008-02-07 11:14:49 +03:00
/* Clearing IntStatus */
asic3_write_register ( asic ,
base +
2008-06-20 13:12:21 +04:00
ASIC3_GPIO_INT_STATUS , 0 ) ;
2008-02-07 11:14:49 +03:00
spin_unlock_irqrestore ( & asic - > lock , flags ) ;
for ( i = 0 ; i < ASIC3_GPIOS_PER_BANK ; i + + ) {
int bit = ( 1 < < i ) ;
unsigned int irqnr ;
if ( ! ( istat & bit ) )
continue ;
irqnr = asic - > irq_base +
( ASIC3_GPIOS_PER_BANK * bank )
+ i ;
desc = irq_desc + irqnr ;
desc - > handle_irq ( irqnr , desc ) ;
if ( asic - > irq_bothedge [ bank ] & bit )
asic3_irq_flip_edge ( asic , base ,
bit ) ;
}
}
}
/* Handle remaining IRQs in the status register */
for ( i = ASIC3_NUM_GPIOS ; i < ASIC3_NR_IRQS ; i + + ) {
/* They start at bit 4 and go up */
if ( status & ( 1 < < ( i - ASIC3_NUM_GPIOS + 4 ) ) ) {
desc = irq_desc + + i ;
desc - > handle_irq ( asic - > irq_base + i ,
desc ) ;
}
}
}
if ( iter > = MAX_ASIC_ISR_LOOPS )
2008-06-20 13:11:19 +04:00
dev_err ( asic - > dev , " interrupt processing overrun \n " ) ;
2008-02-07 11:14:49 +03:00
}
static inline int asic3_irq_to_bank ( struct asic3 * asic , int irq )
{
int n ;
n = ( irq - asic - > irq_base ) > > 4 ;
2008-06-20 13:12:21 +04:00
return ( n * ( ASIC3_GPIO_B_BASE - ASIC3_GPIO_A_BASE ) ) ;
2008-02-07 11:14:49 +03:00
}
static inline int asic3_irq_to_index ( struct asic3 * asic , int irq )
{
return ( irq - asic - > irq_base ) & 0xf ;
}
static void asic3_mask_gpio_irq ( unsigned int irq )
{
struct asic3 * asic = get_irq_chip_data ( irq ) ;
u32 val , bank , index ;
unsigned long flags ;
bank = asic3_irq_to_bank ( asic , irq ) ;
index = asic3_irq_to_index ( asic , irq ) ;
spin_lock_irqsave ( & asic - > lock , flags ) ;
2008-06-20 13:12:21 +04:00
val = asic3_read_register ( asic , bank + ASIC3_GPIO_MASK ) ;
2008-02-07 11:14:49 +03:00
val | = 1 < < index ;
2008-06-20 13:12:21 +04:00
asic3_write_register ( asic , bank + ASIC3_GPIO_MASK , val ) ;
2008-02-07 11:14:49 +03:00
spin_unlock_irqrestore ( & asic - > lock , flags ) ;
}
static void asic3_mask_irq ( unsigned int irq )
{
struct asic3 * asic = get_irq_chip_data ( irq ) ;
int regval ;
unsigned long flags ;
spin_lock_irqsave ( & asic - > lock , flags ) ;
regval = asic3_read_register ( asic ,
2008-06-20 13:12:21 +04:00
ASIC3_INTR_BASE +
ASIC3_INTR_INT_MASK ) ;
2008-02-07 11:14:49 +03:00
regval & = ~ ( ASIC3_INTMASK_MASK0 < <
( irq - ( asic - > irq_base + ASIC3_NUM_GPIOS ) ) ) ;
asic3_write_register ( asic ,
2008-06-20 13:12:21 +04:00
ASIC3_INTR_BASE +
ASIC3_INTR_INT_MASK ,
2008-02-07 11:14:49 +03:00
regval ) ;
spin_unlock_irqrestore ( & asic - > lock , flags ) ;
}
static void asic3_unmask_gpio_irq ( unsigned int irq )
{
struct asic3 * asic = get_irq_chip_data ( irq ) ;
u32 val , bank , index ;
unsigned long flags ;
bank = asic3_irq_to_bank ( asic , irq ) ;
index = asic3_irq_to_index ( asic , irq ) ;
spin_lock_irqsave ( & asic - > lock , flags ) ;
2008-06-20 13:12:21 +04:00
val = asic3_read_register ( asic , bank + ASIC3_GPIO_MASK ) ;
2008-02-07 11:14:49 +03:00
val & = ~ ( 1 < < index ) ;
2008-06-20 13:12:21 +04:00
asic3_write_register ( asic , bank + ASIC3_GPIO_MASK , val ) ;
2008-02-07 11:14:49 +03:00
spin_unlock_irqrestore ( & asic - > lock , flags ) ;
}
static void asic3_unmask_irq ( unsigned int irq )
{
struct asic3 * asic = get_irq_chip_data ( irq ) ;
int regval ;
unsigned long flags ;
spin_lock_irqsave ( & asic - > lock , flags ) ;
regval = asic3_read_register ( asic ,
2008-06-20 13:12:21 +04:00
ASIC3_INTR_BASE +
ASIC3_INTR_INT_MASK ) ;
2008-02-07 11:14:49 +03:00
regval | = ( ASIC3_INTMASK_MASK0 < <
( irq - ( asic - > irq_base + ASIC3_NUM_GPIOS ) ) ) ;
asic3_write_register ( asic ,
2008-06-20 13:12:21 +04:00
ASIC3_INTR_BASE +
ASIC3_INTR_INT_MASK ,
2008-02-07 11:14:49 +03:00
regval ) ;
spin_unlock_irqrestore ( & asic - > lock , flags ) ;
}
static int asic3_gpio_irq_type ( unsigned int irq , unsigned int type )
{
struct asic3 * asic = get_irq_chip_data ( irq ) ;
u32 bank , index ;
u16 trigger , level , edge , bit ;
unsigned long flags ;
bank = asic3_irq_to_bank ( asic , irq ) ;
index = asic3_irq_to_index ( asic , irq ) ;
bit = 1 < < index ;
spin_lock_irqsave ( & asic - > lock , flags ) ;
level = asic3_read_register ( asic ,
2008-06-20 13:12:21 +04:00
bank + ASIC3_GPIO_LEVEL_TRIGGER ) ;
2008-02-07 11:14:49 +03:00
edge = asic3_read_register ( asic ,
2008-06-20 13:12:21 +04:00
bank + ASIC3_GPIO_EDGE_TRIGGER ) ;
2008-02-07 11:14:49 +03:00
trigger = asic3_read_register ( asic ,
2008-06-20 13:12:21 +04:00
bank + ASIC3_GPIO_TRIGGER_TYPE ) ;
2008-02-07 11:14:49 +03:00
asic - > irq_bothedge [ ( irq - asic - > irq_base ) > > 4 ] & = ~ bit ;
if ( type = = IRQT_RISING ) {
trigger | = bit ;
edge | = bit ;
} else if ( type = = IRQT_FALLING ) {
trigger | = bit ;
edge & = ~ bit ;
} else if ( type = = IRQT_BOTHEDGE ) {
trigger | = bit ;
2008-06-20 13:02:19 +04:00
if ( asic3_gpio_get ( & asic - > gpio , irq - asic - > irq_base ) )
2008-02-07 11:14:49 +03:00
edge & = ~ bit ;
else
edge | = bit ;
asic - > irq_bothedge [ ( irq - asic - > irq_base ) > > 4 ] | = bit ;
} else if ( type = = IRQT_LOW ) {
trigger & = ~ bit ;
level & = ~ bit ;
} else if ( type = = IRQT_HIGH ) {
trigger & = ~ bit ;
level | = bit ;
} else {
/*
* if type = = IRQT_NOEDGE , we should mask interrupts , but
* be careful to not unmask them if mask was also called .
* Probably need internal state for mask .
*/
2008-06-20 13:11:19 +04:00
dev_notice ( asic - > dev , " irq type not changed \n " ) ;
2008-02-07 11:14:49 +03:00
}
2008-06-20 13:12:21 +04:00
asic3_write_register ( asic , bank + ASIC3_GPIO_LEVEL_TRIGGER ,
2008-02-07 11:14:49 +03:00
level ) ;
2008-06-20 13:12:21 +04:00
asic3_write_register ( asic , bank + ASIC3_GPIO_EDGE_TRIGGER ,
2008-02-07 11:14:49 +03:00
edge ) ;
2008-06-20 13:12:21 +04:00
asic3_write_register ( asic , bank + ASIC3_GPIO_TRIGGER_TYPE ,
2008-02-07 11:14:49 +03:00
trigger ) ;
spin_unlock_irqrestore ( & asic - > lock , flags ) ;
return 0 ;
}
static struct irq_chip asic3_gpio_irq_chip = {
. name = " ASIC3-GPIO " ,
. ack = asic3_mask_gpio_irq ,
. mask = asic3_mask_gpio_irq ,
. unmask = asic3_unmask_gpio_irq ,
. set_type = asic3_gpio_irq_type ,
} ;
static struct irq_chip asic3_irq_chip = {
. name = " ASIC3 " ,
. ack = asic3_mask_irq ,
. mask = asic3_mask_irq ,
. unmask = asic3_unmask_irq ,
} ;
static int asic3_irq_probe ( struct platform_device * pdev )
{
struct asic3 * asic = platform_get_drvdata ( pdev ) ;
unsigned long clksel = 0 ;
unsigned int irq , irq_base ;
asic - > irq_nr = platform_get_irq ( pdev , 0 ) ;
if ( asic - > irq_nr < 0 )
return asic - > irq_nr ;
/* turn on clock to IRQ controller */
clksel | = CLOCK_SEL_CX ;
asic3_write_register ( asic , ASIC3_OFFSET ( CLOCK , SEL ) ,
clksel ) ;
irq_base = asic - > irq_base ;
for ( irq = irq_base ; irq < irq_base + ASIC3_NR_IRQS ; irq + + ) {
if ( irq < asic - > irq_base + ASIC3_NUM_GPIOS )
set_irq_chip ( irq , & asic3_gpio_irq_chip ) ;
else
set_irq_chip ( irq , & asic3_irq_chip ) ;
set_irq_chip_data ( irq , asic ) ;
set_irq_handler ( irq , handle_level_irq ) ;
set_irq_flags ( irq , IRQF_VALID | IRQF_PROBE ) ;
}
2008-06-20 13:12:21 +04:00
asic3_write_register ( asic , ASIC3_OFFSET ( INTR , INT_MASK ) ,
2008-02-07 11:14:49 +03:00
ASIC3_INTMASK_GINTMASK ) ;
set_irq_chained_handler ( asic - > irq_nr , asic3_irq_demux ) ;
set_irq_type ( asic - > irq_nr , IRQT_RISING ) ;
set_irq_data ( asic - > irq_nr , asic ) ;
return 0 ;
}
static void asic3_irq_remove ( struct platform_device * pdev )
{
struct asic3 * asic = platform_get_drvdata ( pdev ) ;
unsigned int irq , irq_base ;
irq_base = asic - > irq_base ;
for ( irq = irq_base ; irq < irq_base + ASIC3_NR_IRQS ; irq + + ) {
set_irq_flags ( irq , 0 ) ;
set_irq_handler ( irq , NULL ) ;
set_irq_chip ( irq , NULL ) ;
set_irq_chip_data ( irq , NULL ) ;
}
set_irq_chained_handler ( asic - > irq_nr , NULL ) ;
}
/* GPIOs */
2008-06-20 13:02:19 +04:00
static int asic3_gpio_direction ( struct gpio_chip * chip ,
unsigned offset , int out )
{
u32 mask = ASIC3_GPIO_TO_MASK ( offset ) , out_reg ;
unsigned int gpio_base ;
unsigned long flags ;
struct asic3 * asic ;
asic = container_of ( chip , struct asic3 , gpio ) ;
gpio_base = ASIC3_GPIO_TO_BASE ( offset ) ;
2008-06-20 13:12:21 +04:00
if ( gpio_base > ASIC3_GPIO_D_BASE ) {
2008-06-20 13:11:19 +04:00
dev_err ( asic - > dev , " Invalid base (0x%x) for gpio %d \n " ,
gpio_base , offset ) ;
2008-06-20 13:02:19 +04:00
return - EINVAL ;
}
spin_lock_irqsave ( & asic - > lock , flags ) ;
2008-06-20 13:12:21 +04:00
out_reg = asic3_read_register ( asic , gpio_base + ASIC3_GPIO_DIRECTION ) ;
2008-06-20 13:02:19 +04:00
/* Input is 0, Output is 1 */
if ( out )
out_reg | = mask ;
else
out_reg & = ~ mask ;
2008-06-20 13:12:21 +04:00
asic3_write_register ( asic , gpio_base + ASIC3_GPIO_DIRECTION , out_reg ) ;
2008-06-20 13:02:19 +04:00
spin_unlock_irqrestore ( & asic - > lock , flags ) ;
return 0 ;
}
static int asic3_gpio_direction_input ( struct gpio_chip * chip ,
unsigned offset )
{
return asic3_gpio_direction ( chip , offset , 0 ) ;
}
static int asic3_gpio_direction_output ( struct gpio_chip * chip ,
unsigned offset , int value )
{
return asic3_gpio_direction ( chip , offset , 1 ) ;
}
static int asic3_gpio_get ( struct gpio_chip * chip ,
unsigned offset )
{
unsigned int gpio_base ;
u32 mask = ASIC3_GPIO_TO_MASK ( offset ) ;
struct asic3 * asic ;
asic = container_of ( chip , struct asic3 , gpio ) ;
gpio_base = ASIC3_GPIO_TO_BASE ( offset ) ;
2008-06-20 13:12:21 +04:00
if ( gpio_base > ASIC3_GPIO_D_BASE ) {
2008-06-20 13:11:19 +04:00
dev_err ( asic - > dev , " Invalid base (0x%x) for gpio %d \n " ,
gpio_base , offset ) ;
2008-06-20 13:02:19 +04:00
return - EINVAL ;
}
2008-06-20 13:12:21 +04:00
return asic3_read_register ( asic , gpio_base + ASIC3_GPIO_STATUS ) & mask ;
2008-06-20 13:02:19 +04:00
}
static void asic3_gpio_set ( struct gpio_chip * chip ,
unsigned offset , int value )
{
u32 mask , out_reg ;
unsigned int gpio_base ;
unsigned long flags ;
struct asic3 * asic ;
asic = container_of ( chip , struct asic3 , gpio ) ;
gpio_base = ASIC3_GPIO_TO_BASE ( offset ) ;
2008-06-20 13:12:21 +04:00
if ( gpio_base > ASIC3_GPIO_D_BASE ) {
2008-06-20 13:11:19 +04:00
dev_err ( asic - > dev , " Invalid base (0x%x) for gpio %d \n " ,
gpio_base , offset ) ;
2008-06-20 13:02:19 +04:00
return ;
}
mask = ASIC3_GPIO_TO_MASK ( offset ) ;
spin_lock_irqsave ( & asic - > lock , flags ) ;
2008-06-20 13:12:21 +04:00
out_reg = asic3_read_register ( asic , gpio_base + ASIC3_GPIO_OUT ) ;
2008-06-20 13:02:19 +04:00
if ( value )
out_reg | = mask ;
else
out_reg & = ~ mask ;
2008-06-20 13:12:21 +04:00
asic3_write_register ( asic , gpio_base + ASIC3_GPIO_OUT , out_reg ) ;
2008-06-20 13:02:19 +04:00
spin_unlock_irqrestore ( & asic - > lock , flags ) ;
return ;
}
2008-06-20 13:09:51 +04:00
static int asic3_gpio_probe ( struct platform_device * pdev ,
u16 * gpio_config , int num )
2008-02-07 11:14:49 +03:00
{
struct asic3 * asic = platform_get_drvdata ( pdev ) ;
2008-06-20 13:09:51 +04:00
u16 alt_reg [ ASIC3_NUM_GPIO_BANKS ] ;
u16 out_reg [ ASIC3_NUM_GPIO_BANKS ] ;
u16 dir_reg [ ASIC3_NUM_GPIO_BANKS ] ;
int i ;
2008-02-07 11:14:49 +03:00
2008-06-20 13:09:51 +04:00
memset ( alt_reg , 0 , ASIC3_NUM_GPIO_BANKS ) ;
memset ( out_reg , 0 , ASIC3_NUM_GPIO_BANKS ) ;
memset ( dir_reg , 0 , ASIC3_NUM_GPIO_BANKS ) ;
/* Enable all GPIOs */
2008-06-20 13:12:21 +04:00
asic3_write_register ( asic , ASIC3_GPIO_OFFSET ( A , MASK ) , 0xffff ) ;
asic3_write_register ( asic , ASIC3_GPIO_OFFSET ( B , MASK ) , 0xffff ) ;
asic3_write_register ( asic , ASIC3_GPIO_OFFSET ( C , MASK ) , 0xffff ) ;
asic3_write_register ( asic , ASIC3_GPIO_OFFSET ( D , MASK ) , 0xffff ) ;
2008-02-07 11:14:49 +03:00
2008-06-20 13:09:51 +04:00
for ( i = 0 ; i < num ; i + + ) {
u8 alt , pin , dir , init , bank_num , bit_num ;
u16 config = gpio_config [ i ] ;
pin = ASIC3_CONFIG_GPIO_PIN ( config ) ;
alt = ASIC3_CONFIG_GPIO_ALT ( config ) ;
dir = ASIC3_CONFIG_GPIO_DIR ( config ) ;
init = ASIC3_CONFIG_GPIO_INIT ( config ) ;
bank_num = ASIC3_GPIO_TO_BANK ( pin ) ;
bit_num = ASIC3_GPIO_TO_BIT ( pin ) ;
alt_reg [ bank_num ] | = ( alt < < bit_num ) ;
out_reg [ bank_num ] | = ( init < < bit_num ) ;
dir_reg [ bank_num ] | = ( dir < < bit_num ) ;
}
for ( i = 0 ; i < ASIC3_NUM_GPIO_BANKS ; i + + ) {
asic3_write_register ( asic ,
ASIC3_BANK_TO_BASE ( i ) +
2008-06-20 13:12:21 +04:00
ASIC3_GPIO_DIRECTION ,
2008-06-20 13:09:51 +04:00
dir_reg [ i ] ) ;
asic3_write_register ( asic ,
2008-06-20 13:12:21 +04:00
ASIC3_BANK_TO_BASE ( i ) + ASIC3_GPIO_OUT ,
2008-06-20 13:09:51 +04:00
out_reg [ i ] ) ;
asic3_write_register ( asic ,
ASIC3_BANK_TO_BASE ( i ) +
2008-06-20 13:12:21 +04:00
ASIC3_GPIO_ALT_FUNCTION ,
2008-06-20 13:09:51 +04:00
alt_reg [ i ] ) ;
2008-02-07 11:14:49 +03:00
}
2008-06-20 13:02:19 +04:00
return gpiochip_add ( & asic - > gpio ) ;
2008-02-07 11:14:49 +03:00
}
2008-06-20 13:02:19 +04:00
static int asic3_gpio_remove ( struct platform_device * pdev )
2008-02-07 11:14:49 +03:00
{
2008-06-20 13:02:19 +04:00
struct asic3 * asic = platform_get_drvdata ( pdev ) ;
return gpiochip_remove ( & asic - > gpio ) ;
2008-02-07 11:14:49 +03:00
}
/* Core */
static int asic3_probe ( struct platform_device * pdev )
{
struct asic3_platform_data * pdata = pdev - > dev . platform_data ;
struct asic3 * asic ;
struct resource * mem ;
unsigned long clksel ;
2008-06-20 13:02:19 +04:00
int ret = 0 ;
2008-02-07 11:14:49 +03:00
asic = kzalloc ( sizeof ( struct asic3 ) , GFP_KERNEL ) ;
2008-06-20 13:02:19 +04:00
if ( asic = = NULL ) {
printk ( KERN_ERR " kzalloc failed \n " ) ;
2008-02-07 11:14:49 +03:00
return - ENOMEM ;
2008-06-20 13:02:19 +04:00
}
2008-02-07 11:14:49 +03:00
spin_lock_init ( & asic - > lock ) ;
platform_set_drvdata ( pdev , asic ) ;
asic - > dev = & pdev - > dev ;
mem = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( ! mem ) {
ret = - ENOMEM ;
2008-06-20 13:11:19 +04:00
dev_err ( asic - > dev , " no MEM resource \n " ) ;
2008-06-20 13:02:19 +04:00
goto out_free ;
2008-02-07 11:14:49 +03:00
}
2008-06-20 13:02:19 +04:00
2008-02-07 11:14:49 +03:00
asic - > mapping = ioremap ( mem - > start , PAGE_SIZE ) ;
if ( ! asic - > mapping ) {
ret = - ENOMEM ;
2008-06-20 13:11:19 +04:00
dev_err ( asic - > dev , " Couldn't ioremap \n " ) ;
2008-06-20 13:02:19 +04:00
goto out_free ;
2008-02-07 11:14:49 +03:00
}
asic - > irq_base = pdata - > irq_base ;
if ( pdata & & pdata - > bus_shift )
asic - > bus_shift = 2 - pdata - > bus_shift ;
else
asic - > bus_shift = 0 ;
clksel = 0 ;
asic3_write_register ( asic , ASIC3_OFFSET ( CLOCK , SEL ) , clksel ) ;
ret = asic3_irq_probe ( pdev ) ;
if ( ret < 0 ) {
2008-06-20 13:11:19 +04:00
dev_err ( asic - > dev , " Couldn't probe IRQs \n " ) ;
2008-06-20 13:02:19 +04:00
goto out_unmap ;
}
asic - > gpio . base = pdata - > gpio_base ;
asic - > gpio . ngpio = ASIC3_NUM_GPIOS ;
asic - > gpio . get = asic3_gpio_get ;
asic - > gpio . set = asic3_gpio_set ;
asic - > gpio . direction_input = asic3_gpio_direction_input ;
asic - > gpio . direction_output = asic3_gpio_direction_output ;
2008-06-20 13:09:51 +04:00
ret = asic3_gpio_probe ( pdev ,
pdata - > gpio_config ,
pdata - > gpio_config_num ) ;
2008-06-20 13:02:19 +04:00
if ( ret < 0 ) {
2008-06-20 13:11:19 +04:00
dev_err ( asic - > dev , " GPIO probe failed \n " ) ;
2008-06-20 13:02:19 +04:00
goto out_irq ;
2008-02-07 11:14:49 +03:00
}
2008-06-20 13:11:19 +04:00
dev_info ( asic - > dev , " ASIC3 Core driver \n " ) ;
2008-02-07 11:14:49 +03:00
return 0 ;
2008-06-20 13:02:19 +04:00
out_irq :
asic3_irq_remove ( pdev ) ;
out_unmap :
2008-02-07 11:14:49 +03:00
iounmap ( asic - > mapping ) ;
2008-06-20 13:02:19 +04:00
out_free :
2008-02-07 11:14:49 +03:00
kfree ( asic ) ;
return ret ;
}
static int asic3_remove ( struct platform_device * pdev )
{
2008-06-20 13:02:19 +04:00
int ret ;
2008-02-07 11:14:49 +03:00
struct asic3 * asic = platform_get_drvdata ( pdev ) ;
2008-06-20 13:02:19 +04:00
ret = asic3_gpio_remove ( pdev ) ;
if ( ret < 0 )
return ret ;
2008-02-07 11:14:49 +03:00
asic3_irq_remove ( pdev ) ;
asic3_write_register ( asic , ASIC3_OFFSET ( CLOCK , SEL ) , 0 ) ;
iounmap ( asic - > mapping ) ;
kfree ( asic ) ;
return 0 ;
}
static void asic3_shutdown ( struct platform_device * pdev )
{
}
static struct platform_driver asic3_device_driver = {
. driver = {
. name = " asic3 " ,
} ,
. probe = asic3_probe ,
. remove = __devexit_p ( asic3_remove ) ,
. shutdown = asic3_shutdown ,
} ;
static int __init asic3_init ( void )
{
int retval = 0 ;
retval = platform_driver_register ( & asic3_device_driver ) ;
return retval ;
}
subsys_initcall ( asic3_init ) ;