2010-02-02 18:47:56 +03:00
/*
* SuperH IrDA Driver
*
* Copyright ( C ) 2009 Renesas Solutions Corp .
* Kuninori Morimoto < morimoto . kuninori @ renesas . com >
*
* Based on bfin_sir . c
* Copyright 2006 - 2009 Analog Devices Inc .
*
* 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/module.h>
# include <linux/platform_device.h>
# include <net/irda/wrapper.h>
# include <net/irda/irda_device.h>
# include <asm/clock.h>
# define DRIVER_NAME "sh_sir"
# define RX_PHASE (1 << 0)
# define TX_PHASE (1 << 1)
# define TX_COMP_PHASE (1 << 2) /* tx complete */
# define NONE_PHASE (1 << 31)
# define IRIF_RINTCLR 0x0016 /* DMA rx interrupt source clear */
# define IRIF_TINTCLR 0x0018 /* DMA tx interrupt source clear */
# define IRIF_SIR0 0x0020 /* IrDA-SIR10 control */
# define IRIF_SIR1 0x0022 /* IrDA-SIR10 baudrate error correction */
# define IRIF_SIR2 0x0024 /* IrDA-SIR10 baudrate count */
# define IRIF_SIR3 0x0026 /* IrDA-SIR10 status */
# define IRIF_SIR_FRM 0x0028 /* Hardware frame processing set */
# define IRIF_SIR_EOF 0x002A /* EOF value */
# define IRIF_SIR_FLG 0x002C /* Flag clear */
# define IRIF_UART_STS2 0x002E /* UART status 2 */
# define IRIF_UART0 0x0030 /* UART control */
# define IRIF_UART1 0x0032 /* UART status */
# define IRIF_UART2 0x0034 /* UART mode */
# define IRIF_UART3 0x0036 /* UART transmit data */
# define IRIF_UART4 0x0038 /* UART receive data */
# define IRIF_UART5 0x003A /* UART interrupt mask */
# define IRIF_UART6 0x003C /* UART baud rate error correction */
# define IRIF_UART7 0x003E /* UART baud rate count set */
# define IRIF_CRC0 0x0040 /* CRC engine control */
# define IRIF_CRC1 0x0042 /* CRC engine input data */
# define IRIF_CRC2 0x0044 /* CRC engine calculation */
# define IRIF_CRC3 0x0046 /* CRC engine output data 1 */
# define IRIF_CRC4 0x0048 /* CRC engine output data 2 */
/* IRIF_SIR0 */
# define IRTPW (1 << 1) /* transmit pulse width select */
# define IRERRC (1 << 0) /* Clear receive pulse width error */
/* IRIF_SIR3 */
# define IRERR (1 << 0) /* received pulse width Error */
/* IRIF_SIR_FRM */
# define EOFD (1 << 9) /* EOF detection flag */
# define FRER (1 << 8) /* Frame Error bit */
# define FRP (1 << 0) /* Frame processing set */
/* IRIF_UART_STS2 */
# define IRSME (1 << 6) /* Receive Sum Error flag */
# define IROVE (1 << 5) /* Receive Overrun Error flag */
# define IRFRE (1 << 4) /* Receive Framing Error flag */
# define IRPRE (1 << 3) /* Receive Parity Error flag */
/* IRIF_UART0_*/
# define TBEC (1 << 2) /* Transmit Data Clear */
# define RIE (1 << 1) /* Receive Enable */
# define TIE (1 << 0) /* Transmit Enable */
/* IRIF_UART1 */
# define URSME (1 << 6) /* Receive Sum Error Flag */
# define UROVE (1 << 5) /* Receive Overrun Error Flag */
# define URFRE (1 << 4) /* Receive Framing Error Flag */
# define URPRE (1 << 3) /* Receive Parity Error Flag */
# define RBF (1 << 2) /* Receive Buffer Full Flag */
# define TSBE (1 << 1) /* Transmit Shift Buffer Empty Flag */
# define TBE (1 << 0) /* Transmit Buffer Empty flag */
# define TBCOMP (TSBE | TBE)
/* IRIF_UART5 */
# define RSEIM (1 << 6) /* Receive Sum Error Flag IRQ Mask */
# define RBFIM (1 << 2) /* Receive Buffer Full Flag IRQ Mask */
# define TSBEIM (1 << 1) /* Transmit Shift Buffer Empty Flag IRQ Mask */
# define TBEIM (1 << 0) /* Transmit Buffer Empty Flag IRQ Mask */
# define RX_MASK (RSEIM | RBFIM)
/* IRIF_CRC0 */
# define CRC_RST (1 << 15) /* CRC Engine Reset */
# define CRC_CT_MASK 0x0FFF
/************************************************************************
structure
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct sh_sir_self {
void __iomem * membase ;
unsigned int irq ;
struct clk * clk ;
struct net_device * ndev ;
struct irlap_cb * irlap ;
struct qos_info qos ;
iobuff_t tx_buff ;
iobuff_t rx_buff ;
} ;
/************************************************************************
common function
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void sh_sir_write ( struct sh_sir_self * self , u32 offset , u16 data )
{
iowrite16 ( data , self - > membase + offset ) ;
}
static u16 sh_sir_read ( struct sh_sir_self * self , u32 offset )
{
return ioread16 ( self - > membase + offset ) ;
}
static void sh_sir_update_bits ( struct sh_sir_self * self , u32 offset ,
u16 mask , u16 data )
{
u16 old , new ;
old = sh_sir_read ( self , offset ) ;
new = ( old & ~ mask ) | data ;
if ( old ! = new )
sh_sir_write ( self , offset , new ) ;
}
/************************************************************************
CRC function
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void sh_sir_crc_reset ( struct sh_sir_self * self )
{
sh_sir_write ( self , IRIF_CRC0 , CRC_RST ) ;
}
static void sh_sir_crc_add ( struct sh_sir_self * self , u8 data )
{
sh_sir_write ( self , IRIF_CRC1 , ( u16 ) data ) ;
}
static u16 sh_sir_crc_cnt ( struct sh_sir_self * self )
{
return CRC_CT_MASK & sh_sir_read ( self , IRIF_CRC0 ) ;
}
static u16 sh_sir_crc_out ( struct sh_sir_self * self )
{
return sh_sir_read ( self , IRIF_CRC4 ) ;
}
static int sh_sir_crc_init ( struct sh_sir_self * self )
{
struct device * dev = & self - > ndev - > dev ;
int ret = - EIO ;
u16 val ;
sh_sir_crc_reset ( self ) ;
sh_sir_crc_add ( self , 0xCC ) ;
sh_sir_crc_add ( self , 0xF5 ) ;
sh_sir_crc_add ( self , 0xF1 ) ;
sh_sir_crc_add ( self , 0xA7 ) ;
val = sh_sir_crc_cnt ( self ) ;
if ( 4 ! = val ) {
dev_err ( dev , " CRC count error %x \n " , val ) ;
goto crc_init_out ;
}
val = sh_sir_crc_out ( self ) ;
if ( 0x51DF ! = val ) {
dev_err ( dev , " CRC result error%x \n " , val ) ;
goto crc_init_out ;
}
ret = 0 ;
crc_init_out :
sh_sir_crc_reset ( self ) ;
return ret ;
}
/************************************************************************
baud rate functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# define SCLK_BASE 1843200 /* 1.8432MHz */
static u32 sh_sir_find_sclk ( struct clk * irda_clk )
{
struct cpufreq_frequency_table * freq_table = irda_clk - > freq_table ;
struct clk * pclk = clk_get ( NULL , " peripheral_clk " ) ;
u32 limit , min = 0xffffffff , tmp ;
int i , index = 0 ;
limit = clk_get_rate ( pclk ) ;
clk_put ( pclk ) ;
/* IrDA can not set over peripheral_clk */
for ( i = 0 ;
freq_table [ i ] . frequency ! = CPUFREQ_TABLE_END ;
i + + ) {
u32 freq = freq_table [ i ] . frequency ;
if ( freq = = CPUFREQ_ENTRY_INVALID )
continue ;
/* IrDA should not over peripheral_clk */
if ( freq > limit )
continue ;
tmp = freq % SCLK_BASE ;
if ( tmp < min ) {
min = tmp ;
index = i ;
}
}
return freq_table [ index ] . frequency ;
}
# define ERR_ROUNDING(a) ((a + 5000) / 10000)
static int sh_sir_set_baudrate ( struct sh_sir_self * self , u32 baudrate )
{
struct clk * clk ;
struct device * dev = & self - > ndev - > dev ;
u32 rate ;
u16 uabca , uabc ;
u16 irbca , irbc ;
u32 min , rerr , tmp ;
int i ;
/* Baud Rate Error Correction x 10000 */
u32 rate_err_array [ ] = {
0000 , 0625 , 1250 , 1875 ,
2500 , 3125 , 3750 , 4375 ,
5000 , 5625 , 6250 , 6875 ,
7500 , 8125 , 8750 , 9375 ,
} ;
/*
* FIXME
*
* it support 9600 only now
*/
switch ( baudrate ) {
case 9600 :
break ;
default :
dev_err ( dev , " un-supported baudrate %d \n " , baudrate ) ;
return - EIO ;
}
clk = clk_get ( NULL , " irda_clk " ) ;
if ( ! clk ) {
dev_err ( dev , " can not get irda_clk \n " ) ;
return - EIO ;
}
clk_set_rate ( clk , sh_sir_find_sclk ( clk ) ) ;
rate = clk_get_rate ( clk ) ;
clk_put ( clk ) ;
dev_dbg ( dev , " selected sclk = %d \n " , rate ) ;
/*
* CALCULATION
*
* 1843200 = system rate / ( irbca + ( irbc + 1 ) )
*/
irbc = rate / SCLK_BASE ;
tmp = rate - ( SCLK_BASE * irbc ) ;
tmp * = 10000 ;
rerr = tmp / SCLK_BASE ;
min = 0xffffffff ;
irbca = 0 ;
for ( i = 0 ; i < ARRAY_SIZE ( rate_err_array ) ; i + + ) {
tmp = abs ( rate_err_array [ i ] - rerr ) ;
if ( min > tmp ) {
min = tmp ;
irbca = i ;
}
}
tmp = rate / ( irbc + ERR_ROUNDING ( rate_err_array [ irbca ] ) ) ;
if ( ( SCLK_BASE / 100 ) < abs ( tmp - SCLK_BASE ) )
dev_warn ( dev , " IrDA freq error margin over %d \n " , tmp ) ;
dev_dbg ( dev , " target = %d, result = %d, infrared = %d.%d \n " ,
SCLK_BASE , tmp , irbc , rate_err_array [ irbca ] ) ;
irbca = ( irbca & 0xF ) < < 4 ;
irbc = ( irbc - 1 ) & 0xF ;
if ( ! irbc ) {
dev_err ( dev , " sh_sir can not set 0 in IRIF_SIR2 \n " ) ;
return - EIO ;
}
sh_sir_write ( self , IRIF_SIR0 , IRTPW | IRERRC ) ;
sh_sir_write ( self , IRIF_SIR1 , irbca ) ;
sh_sir_write ( self , IRIF_SIR2 , irbc ) ;
/*
* CALCULATION
*
* BaudRate [ bps ] = system rate / ( uabca + ( uabc + 1 ) x 16 )
*/
uabc = rate / baudrate ;
uabc = ( uabc / 16 ) - 1 ;
uabc = ( uabc + 1 ) * 16 ;
tmp = rate - ( uabc * baudrate ) ;
tmp * = 10000 ;
rerr = tmp / baudrate ;
min = 0xffffffff ;
uabca = 0 ;
for ( i = 0 ; i < ARRAY_SIZE ( rate_err_array ) ; i + + ) {
tmp = abs ( rate_err_array [ i ] - rerr ) ;
if ( min > tmp ) {
min = tmp ;
uabca = i ;
}
}
tmp = rate / ( uabc + ERR_ROUNDING ( rate_err_array [ uabca ] ) ) ;
if ( ( baudrate / 100 ) < abs ( tmp - baudrate ) )
dev_warn ( dev , " UART freq error margin over %d \n " , tmp ) ;
dev_dbg ( dev , " target = %d, result = %d, uart = %d.%d \n " ,
baudrate , tmp ,
uabc , rate_err_array [ uabca ] ) ;
uabca = ( uabca & 0xF ) < < 4 ;
uabc = ( uabc / 16 ) - 1 ;
sh_sir_write ( self , IRIF_UART6 , uabca ) ;
sh_sir_write ( self , IRIF_UART7 , uabc ) ;
return 0 ;
}
/************************************************************************
iobuf function
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int __sh_sir_init_iobuf ( iobuff_t * io , int size )
{
io - > head = kmalloc ( size , GFP_KERNEL ) ;
if ( ! io - > head )
return - ENOMEM ;
io - > truesize = size ;
io - > in_frame = FALSE ;
io - > state = OUTSIDE_FRAME ;
io - > data = io - > head ;
return 0 ;
}
static void sh_sir_remove_iobuf ( struct sh_sir_self * self )
{
kfree ( self - > rx_buff . head ) ;
kfree ( self - > tx_buff . head ) ;
self - > rx_buff . head = NULL ;
self - > tx_buff . head = NULL ;
}
static int sh_sir_init_iobuf ( struct sh_sir_self * self , int rxsize , int txsize )
{
int err = - ENOMEM ;
if ( self - > rx_buff . head | |
self - > tx_buff . head ) {
dev_err ( & self - > ndev - > dev , " iobuff has already existed. " ) ;
return err ;
}
err = __sh_sir_init_iobuf ( & self - > rx_buff , rxsize ) ;
if ( err )
goto iobuf_err ;
err = __sh_sir_init_iobuf ( & self - > tx_buff , txsize ) ;
iobuf_err :
if ( err )
sh_sir_remove_iobuf ( self ) ;
return err ;
}
/************************************************************************
status function
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void sh_sir_clear_all_err ( struct sh_sir_self * self )
{
/* Clear error flag for receive pulse width */
sh_sir_update_bits ( self , IRIF_SIR0 , IRERRC , IRERRC ) ;
/* Clear frame / EOF error flag */
sh_sir_write ( self , IRIF_SIR_FLG , 0xffff ) ;
/* Clear all status error */
sh_sir_write ( self , IRIF_UART_STS2 , 0 ) ;
}
static void sh_sir_set_phase ( struct sh_sir_self * self , int phase )
{
u16 uart5 = 0 ;
u16 uart0 = 0 ;
switch ( phase ) {
case TX_PHASE :
uart5 = TBEIM ;
uart0 = TBEC | TIE ;
break ;
case TX_COMP_PHASE :
uart5 = TSBEIM ;
uart0 = TIE ;
break ;
case RX_PHASE :
uart5 = RX_MASK ;
uart0 = RIE ;
break ;
default :
break ;
}
sh_sir_write ( self , IRIF_UART5 , uart5 ) ;
sh_sir_write ( self , IRIF_UART0 , uart0 ) ;
}
static int sh_sir_is_which_phase ( struct sh_sir_self * self )
{
u16 val = sh_sir_read ( self , IRIF_UART5 ) ;
if ( val & TBEIM )
return TX_PHASE ;
if ( val & TSBEIM )
return TX_COMP_PHASE ;
if ( val & RX_MASK )
return RX_PHASE ;
return NONE_PHASE ;
}
static void sh_sir_tx ( struct sh_sir_self * self , int phase )
{
switch ( phase ) {
case TX_PHASE :
if ( 0 > = self - > tx_buff . len ) {
sh_sir_set_phase ( self , TX_COMP_PHASE ) ;
} else {
sh_sir_write ( self , IRIF_UART3 , self - > tx_buff . data [ 0 ] ) ;
self - > tx_buff . len - - ;
self - > tx_buff . data + + ;
}
break ;
case TX_COMP_PHASE :
sh_sir_set_phase ( self , RX_PHASE ) ;
netif_wake_queue ( self - > ndev ) ;
break ;
default :
dev_err ( & self - > ndev - > dev , " should not happen \n " ) ;
break ;
}
}
static int sh_sir_read_data ( struct sh_sir_self * self )
{
u16 val ;
int timeout = 1024 ;
while ( timeout - - ) {
val = sh_sir_read ( self , IRIF_UART1 ) ;
/* data get */
if ( val & RBF ) {
if ( val & ( URSME | UROVE | URFRE | URPRE ) )
break ;
return ( int ) sh_sir_read ( self , IRIF_UART4 ) ;
}
udelay ( 1 ) ;
}
dev_err ( & self - > ndev - > dev , " UART1 %04x : STATUS %04x \n " ,
val , sh_sir_read ( self , IRIF_UART_STS2 ) ) ;
/* read data register for clear error */
sh_sir_read ( self , IRIF_UART4 ) ;
return - 1 ;
}
static void sh_sir_rx ( struct sh_sir_self * self )
{
int timeout = 1024 ;
int data ;
while ( timeout - - ) {
data = sh_sir_read_data ( self ) ;
if ( data < 0 )
break ;
async_unwrap_char ( self - > ndev , & self - > ndev - > stats ,
& self - > rx_buff , ( u8 ) data ) ;
self - > ndev - > last_rx = jiffies ;
if ( EOFD & sh_sir_read ( self , IRIF_SIR_FRM ) )
continue ;
break ;
}
}
static irqreturn_t sh_sir_irq ( int irq , void * dev_id )
{
struct sh_sir_self * self = dev_id ;
struct device * dev = & self - > ndev - > dev ;
int phase = sh_sir_is_which_phase ( self ) ;
switch ( phase ) {
case TX_COMP_PHASE :
case TX_PHASE :
sh_sir_tx ( self , phase ) ;
break ;
case RX_PHASE :
if ( sh_sir_read ( self , IRIF_SIR3 ) )
dev_err ( dev , " rcv pulse width error occurred \n " ) ;
sh_sir_rx ( self ) ;
sh_sir_clear_all_err ( self ) ;
break ;
default :
dev_err ( dev , " unknown interrupt \n " ) ;
}
return IRQ_HANDLED ;
}
/************************************************************************
net_device_ops function
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int sh_sir_hard_xmit ( struct sk_buff * skb , struct net_device * ndev )
{
struct sh_sir_self * self = netdev_priv ( ndev ) ;
int speed = irda_get_next_speed ( skb ) ;
if ( ( 0 < speed ) & &
( 9600 ! = speed ) ) {
dev_err ( & ndev - > dev , " support 9600 only (%d) \n " , speed ) ;
return - EIO ;
}
netif_stop_queue ( ndev ) ;
self - > tx_buff . data = self - > tx_buff . head ;
self - > tx_buff . len = 0 ;
if ( skb - > len )
self - > tx_buff . len = async_wrap_skb ( skb , self - > tx_buff . data ,
self - > tx_buff . truesize ) ;
sh_sir_set_phase ( self , TX_PHASE ) ;
dev_kfree_skb ( skb ) ;
return 0 ;
}
static int sh_sir_ioctl ( struct net_device * ndev , struct ifreq * ifreq , int cmd )
{
/*
* FIXME
*
* This function is needed for irda framework .
* But nothing to do now
*/
return 0 ;
}
static struct net_device_stats * sh_sir_stats ( struct net_device * ndev )
{
struct sh_sir_self * self = netdev_priv ( ndev ) ;
return & self - > ndev - > stats ;
}
static int sh_sir_open ( struct net_device * ndev )
{
struct sh_sir_self * self = netdev_priv ( ndev ) ;
int err ;
clk_enable ( self - > clk ) ;
err = sh_sir_crc_init ( self ) ;
if ( err )
goto open_err ;
sh_sir_set_baudrate ( self , 9600 ) ;
self - > irlap = irlap_open ( ndev , & self - > qos , DRIVER_NAME ) ;
2010-04-05 22:43:09 +04:00
if ( ! self - > irlap ) {
err = - ENODEV ;
2010-02-02 18:47:56 +03:00
goto open_err ;
2010-04-05 22:43:09 +04:00
}
2010-02-02 18:47:56 +03:00
/*
* Now enable the interrupt then start the queue
*/
sh_sir_update_bits ( self , IRIF_SIR_FRM , FRP , FRP ) ;
sh_sir_read ( self , IRIF_UART1 ) ; /* flag clear */
sh_sir_read ( self , IRIF_UART4 ) ; /* flag clear */
sh_sir_set_phase ( self , RX_PHASE ) ;
netif_start_queue ( ndev ) ;
dev_info ( & self - > ndev - > dev , " opened \n " ) ;
return 0 ;
open_err :
clk_disable ( self - > clk ) ;
return err ;
}
static int sh_sir_stop ( struct net_device * ndev )
{
struct sh_sir_self * self = netdev_priv ( ndev ) ;
/* Stop IrLAP */
if ( self - > irlap ) {
irlap_close ( self - > irlap ) ;
self - > irlap = NULL ;
}
netif_stop_queue ( ndev ) ;
dev_info ( & ndev - > dev , " stoped \n " ) ;
return 0 ;
}
static const struct net_device_ops sh_sir_ndo = {
. ndo_open = sh_sir_open ,
. ndo_stop = sh_sir_stop ,
. ndo_start_xmit = sh_sir_hard_xmit ,
. ndo_do_ioctl = sh_sir_ioctl ,
. ndo_get_stats = sh_sir_stats ,
} ;
/************************************************************************
platform_driver function
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int __devinit sh_sir_probe ( struct platform_device * pdev )
{
struct net_device * ndev ;
struct sh_sir_self * self ;
struct resource * res ;
char clk_name [ 8 ] ;
void __iomem * base ;
unsigned int irq ;
int err = - ENOMEM ;
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
irq = platform_get_irq ( pdev , 0 ) ;
if ( ! res | | irq < 0 ) {
dev_err ( & pdev - > dev , " Not enough platform resources. \n " ) ;
goto exit ;
}
ndev = alloc_irdadev ( sizeof ( * self ) ) ;
if ( ! ndev )
goto exit ;
base = ioremap_nocache ( res - > start , resource_size ( res ) ) ;
if ( ! base ) {
err = - ENXIO ;
dev_err ( & pdev - > dev , " Unable to ioremap. \n " ) ;
goto err_mem_1 ;
}
self = netdev_priv ( ndev ) ;
err = sh_sir_init_iobuf ( self , IRDA_SKB_MAX_MTU , IRDA_SIR_MAX_FRAME ) ;
if ( err )
goto err_mem_2 ;
snprintf ( clk_name , sizeof ( clk_name ) , " irda%d " , pdev - > id ) ;
self - > clk = clk_get ( & pdev - > dev , clk_name ) ;
if ( IS_ERR ( self - > clk ) ) {
dev_err ( & pdev - > dev , " cannot get clock \" %s \" \n " , clk_name ) ;
goto err_mem_3 ;
}
irda_init_max_qos_capabilies ( & self - > qos ) ;
ndev - > netdev_ops = & sh_sir_ndo ;
ndev - > irq = irq ;
self - > membase = base ;
self - > ndev = ndev ;
self - > qos . baud_rate . bits & = IR_9600 ; /* FIXME */
self - > qos . min_turn_time . bits = 1 ; /* 10 ms or more */
irda_qos_bits_to_value ( & self - > qos ) ;
err = register_netdev ( ndev ) ;
if ( err )
goto err_mem_4 ;
platform_set_drvdata ( pdev , ndev ) ;
if ( request_irq ( irq , sh_sir_irq , IRQF_DISABLED , " sh_sir " , self ) ) {
dev_warn ( & pdev - > dev , " Unable to attach sh_sir interrupt \n " ) ;
goto err_mem_4 ;
}
dev_info ( & pdev - > dev , " SuperH IrDA probed \n " ) ;
goto exit ;
err_mem_4 :
clk_put ( self - > clk ) ;
err_mem_3 :
sh_sir_remove_iobuf ( self ) ;
err_mem_2 :
iounmap ( self - > membase ) ;
err_mem_1 :
free_netdev ( ndev ) ;
exit :
return err ;
}
static int __devexit sh_sir_remove ( struct platform_device * pdev )
{
struct net_device * ndev = platform_get_drvdata ( pdev ) ;
struct sh_sir_self * self = netdev_priv ( ndev ) ;
if ( ! self )
return 0 ;
unregister_netdev ( ndev ) ;
clk_put ( self - > clk ) ;
sh_sir_remove_iobuf ( self ) ;
iounmap ( self - > membase ) ;
free_netdev ( ndev ) ;
platform_set_drvdata ( pdev , NULL ) ;
return 0 ;
}
static struct platform_driver sh_sir_driver = {
. probe = sh_sir_probe ,
. remove = __devexit_p ( sh_sir_remove ) ,
. driver = {
. name = DRIVER_NAME ,
} ,
} ;
static int __init sh_sir_init ( void )
{
return platform_driver_register ( & sh_sir_driver ) ;
}
static void __exit sh_sir_exit ( void )
{
platform_driver_unregister ( & sh_sir_driver ) ;
}
module_init ( sh_sir_init ) ;
module_exit ( sh_sir_exit ) ;
MODULE_AUTHOR ( " Kuninori Morimoto <morimoto.kuninori@renesas.com> " ) ;
MODULE_DESCRIPTION ( " SuperH IrDA driver " ) ;
MODULE_LICENSE ( " GPL " ) ;