2010-06-30 17:57:12 +01:00
/*
* max3107 . c - spi uart protocol driver for Maxim 3107
* Based on max3100 . c
* by Christian Pellegrin < chripell @ evolware . org >
* and max3110 . c
* by Feng Tang < feng . tang @ intel . com >
*
* Copyright ( C ) Aavamobile 2009
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* 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 .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
*/
# include <linux/delay.h>
# include <linux/device.h>
# include <linux/serial_core.h>
# include <linux/serial.h>
2010-06-30 17:58:38 +01:00
# include <linux/gpio.h>
2010-06-30 17:57:12 +01:00
# include <linux/spi/spi.h>
# include <linux/freezer.h>
# include "max3107.h"
2010-06-30 17:58:38 +01:00
static const struct baud_table brg26_ext [ ] = {
2010-06-30 17:57:12 +01:00
{ 300 , MAX3107_BRG26_B300 } ,
{ 600 , MAX3107_BRG26_B600 } ,
{ 1200 , MAX3107_BRG26_B1200 } ,
{ 2400 , MAX3107_BRG26_B2400 } ,
{ 4800 , MAX3107_BRG26_B4800 } ,
{ 9600 , MAX3107_BRG26_B9600 } ,
{ 19200 , MAX3107_BRG26_B19200 } ,
{ 57600 , MAX3107_BRG26_B57600 } ,
{ 115200 , MAX3107_BRG26_B115200 } ,
{ 230400 , MAX3107_BRG26_B230400 } ,
{ 460800 , MAX3107_BRG26_B460800 } ,
{ 921600 , MAX3107_BRG26_B921600 } ,
{ 0 , 0 }
} ;
2010-06-30 17:58:38 +01:00
static const struct baud_table brg13_int [ ] = {
2010-06-30 17:57:12 +01:00
{ 300 , MAX3107_BRG13_IB300 } ,
{ 600 , MAX3107_BRG13_IB600 } ,
{ 1200 , MAX3107_BRG13_IB1200 } ,
{ 2400 , MAX3107_BRG13_IB2400 } ,
{ 4800 , MAX3107_BRG13_IB4800 } ,
{ 9600 , MAX3107_BRG13_IB9600 } ,
{ 19200 , MAX3107_BRG13_IB19200 } ,
{ 57600 , MAX3107_BRG13_IB57600 } ,
{ 115200 , MAX3107_BRG13_IB115200 } ,
{ 230400 , MAX3107_BRG13_IB230400 } ,
{ 460800 , MAX3107_BRG13_IB460800 } ,
{ 921600 , MAX3107_BRG13_IB921600 } ,
{ 0 , 0 }
} ;
static u32 get_new_brg ( int baud , struct max3107_port * s )
{
int i ;
2010-06-30 17:58:38 +01:00
const struct baud_table * baud_tbl = s - > baud_tbl ;
2010-06-30 17:57:12 +01:00
for ( i = 0 ; i < 13 ; i + + ) {
if ( baud = = baud_tbl [ i ] . baud )
return baud_tbl [ i ] . new_brg ;
}
return 0 ;
}
/* Perform SPI transfer for write/read of device register(s) */
2010-06-30 17:58:38 +01:00
int max3107_rw ( struct max3107_port * s , u8 * tx , u8 * rx , int len )
2010-06-30 17:57:12 +01:00
{
struct spi_message spi_msg ;
struct spi_transfer spi_xfer ;
/* Initialize SPI ,message */
spi_message_init ( & spi_msg ) ;
/* Initialize SPI transfer */
memset ( & spi_xfer , 0 , sizeof spi_xfer ) ;
spi_xfer . len = len ;
spi_xfer . tx_buf = tx ;
spi_xfer . rx_buf = rx ;
spi_xfer . speed_hz = MAX3107_SPI_SPEED ;
/* Add SPI transfer to SPI message */
spi_message_add_tail ( & spi_xfer , & spi_msg ) ;
# ifdef DBG_TRACE_SPI_DATA
{
int i ;
pr_info ( " tx len %d: \n " , spi_xfer . len ) ;
for ( i = 0 ; i < spi_xfer . len & & i < 32 ; i + + )
pr_info ( " %x " , ( ( u8 * ) spi_xfer . tx_buf ) [ i ] ) ;
pr_info ( " \n " ) ;
}
# endif
/* Perform synchronous SPI transfer */
if ( spi_sync ( s - > spi , & spi_msg ) ) {
dev_err ( & s - > spi - > dev , " spi_sync failure \n " ) ;
return - EIO ;
}
# ifdef DBG_TRACE_SPI_DATA
if ( spi_xfer . rx_buf ) {
int i ;
pr_info ( " rx len %d: \n " , spi_xfer . len ) ;
for ( i = 0 ; i < spi_xfer . len & & i < 32 ; i + + )
pr_info ( " %x " , ( ( u8 * ) spi_xfer . rx_buf ) [ i ] ) ;
pr_info ( " \n " ) ;
}
# endif
return 0 ;
}
2010-06-30 17:58:38 +01:00
EXPORT_SYMBOL_GPL ( max3107_rw ) ;
2010-06-30 17:57:12 +01:00
/* Puts received data to circular buffer */
static void put_data_to_circ_buf ( struct max3107_port * s , unsigned char * data ,
int len )
{
struct uart_port * port = & s - > port ;
struct tty_struct * tty ;
if ( ! port - > state )
return ;
tty = port - > state - > port . tty ;
if ( ! tty )
return ;
/* Insert received data */
tty_insert_flip_string ( tty , data , len ) ;
/* Update RX counter */
port - > icount . rx + = len ;
}
/* Handle data receiving */
static void max3107_handlerx ( struct max3107_port * s , u16 rxlvl )
{
int i ;
int j ;
int len ; /* SPI transfer buffer length */
u16 * buf ;
u8 * valid_str ;
if ( ! s - > rx_enabled )
/* RX is disabled */
return ;
if ( rxlvl = = 0 ) {
/* RX fifo is empty */
return ;
} else if ( rxlvl > = MAX3107_RX_FIFO_SIZE ) {
dev_warn ( & s - > spi - > dev , " Possible RX FIFO overrun %d \n " , rxlvl ) ;
/* Ensure sanity of RX level */
rxlvl = MAX3107_RX_FIFO_SIZE ;
}
if ( ( s - > rxbuf = = 0 ) | | ( s - > rxstr = = 0 ) ) {
dev_warn ( & s - > spi - > dev , " Rx buffer/str isn't ready \n " ) ;
return ;
}
buf = s - > rxbuf ;
valid_str = s - > rxstr ;
while ( rxlvl ) {
pr_debug ( " rxlvl %d \n " , rxlvl ) ;
/* Clear buffer */
memset ( buf , 0 , sizeof ( u16 ) * ( MAX3107_RX_FIFO_SIZE + 2 ) ) ;
len = 0 ;
if ( s - > irqen_reg & MAX3107_IRQ_RXFIFO_BIT ) {
/* First disable RX FIFO interrupt */
pr_debug ( " Disabling RX INT \n " ) ;
buf [ 0 ] = ( MAX3107_WRITE_BIT | MAX3107_IRQEN_REG ) ;
s - > irqen_reg & = ~ MAX3107_IRQ_RXFIFO_BIT ;
buf [ 0 ] | = s - > irqen_reg ;
len + + ;
}
/* Just increase the length by amount of words in FIFO since
* buffer was zeroed and SPI transfer of 0x0000 means reading
* from RX FIFO
*/
len + = rxlvl ;
/* Append RX level query */
buf [ len ] = MAX3107_RXFIFOLVL_REG ;
len + + ;
/* Perform the SPI transfer */
if ( max3107_rw ( s , ( u8 * ) buf , ( u8 * ) buf , len * 2 ) ) {
dev_err ( & s - > spi - > dev , " SPI transfer for RX h failed \n " ) ;
return ;
}
/* Skip RX FIFO interrupt disabling word if it was added */
j = ( ( len - 1 ) - rxlvl ) ;
/* Read received words */
for ( i = 0 ; i < rxlvl ; i + + , j + + )
valid_str [ i ] = ( u8 ) buf [ j ] ;
put_data_to_circ_buf ( s , valid_str , rxlvl ) ;
/* Get new RX level */
rxlvl = ( buf [ len - 1 ] & MAX3107_SPI_RX_DATA_MASK ) ;
}
if ( s - > rx_enabled ) {
/* RX still enabled, re-enable RX FIFO interrupt */
pr_debug ( " Enabling RX INT \n " ) ;
buf [ 0 ] = ( MAX3107_WRITE_BIT | MAX3107_IRQEN_REG ) ;
s - > irqen_reg | = MAX3107_IRQ_RXFIFO_BIT ;
buf [ 0 ] | = s - > irqen_reg ;
if ( max3107_rw ( s , ( u8 * ) buf , NULL , 2 ) )
dev_err ( & s - > spi - > dev , " RX FIFO INT enabling failed \n " ) ;
}
/* Push the received data to receivers */
if ( s - > port . state - > port . tty )
tty_flip_buffer_push ( s - > port . state - > port . tty ) ;
}
/* Handle data sending */
static void max3107_handletx ( struct max3107_port * s )
{
struct circ_buf * xmit = & s - > port . state - > xmit ;
int i ;
unsigned long flags ;
int len ; /* SPI transfer buffer length */
u16 * buf ;
if ( ! s - > tx_fifo_empty )
/* Don't send more data before previous data is sent */
return ;
if ( uart_circ_empty ( xmit ) | | uart_tx_stopped ( & s - > port ) )
/* No data to send or TX is stopped */
return ;
if ( ! s - > txbuf ) {
dev_warn ( & s - > spi - > dev , " Txbuf isn't ready \n " ) ;
return ;
}
buf = s - > txbuf ;
/* Get length of data pending in circular buffer */
len = uart_circ_chars_pending ( xmit ) ;
if ( len ) {
/* Limit to size of TX FIFO */
if ( len > MAX3107_TX_FIFO_SIZE )
len = MAX3107_TX_FIFO_SIZE ;
pr_debug ( " txlen %d \n " , len ) ;
/* Update TX counter */
s - > port . icount . tx + = len ;
/* TX FIFO will no longer be empty */
s - > tx_fifo_empty = 0 ;
i = 0 ;
if ( s - > irqen_reg & MAX3107_IRQ_TXEMPTY_BIT ) {
/* First disable TX empty interrupt */
pr_debug ( " Disabling TE INT \n " ) ;
buf [ i ] = ( MAX3107_WRITE_BIT | MAX3107_IRQEN_REG ) ;
s - > irqen_reg & = ~ MAX3107_IRQ_TXEMPTY_BIT ;
buf [ i ] | = s - > irqen_reg ;
i + + ;
len + + ;
}
/* Add data to send */
spin_lock_irqsave ( & s - > port . lock , flags ) ;
for ( ; i < len ; i + + ) {
buf [ i ] = ( MAX3107_WRITE_BIT | MAX3107_THR_REG ) ;
buf [ i ] | = ( ( u16 ) xmit - > buf [ xmit - > tail ] &
MAX3107_SPI_TX_DATA_MASK ) ;
xmit - > tail = ( xmit - > tail + 1 ) & ( UART_XMIT_SIZE - 1 ) ;
}
spin_unlock_irqrestore ( & s - > port . lock , flags ) ;
if ( ! ( s - > irqen_reg & MAX3107_IRQ_TXEMPTY_BIT ) ) {
/* Enable TX empty interrupt */
pr_debug ( " Enabling TE INT \n " ) ;
buf [ i ] = ( MAX3107_WRITE_BIT | MAX3107_IRQEN_REG ) ;
s - > irqen_reg | = MAX3107_IRQ_TXEMPTY_BIT ;
buf [ i ] | = s - > irqen_reg ;
i + + ;
len + + ;
}
if ( ! s - > tx_enabled ) {
/* Enable TX */
pr_debug ( " Enable TX \n " ) ;
buf [ i ] = ( MAX3107_WRITE_BIT | MAX3107_MODE1_REG ) ;
spin_lock_irqsave ( & s - > data_lock , flags ) ;
s - > mode1_reg & = ~ MAX3107_MODE1_TXDIS_BIT ;
buf [ i ] | = s - > mode1_reg ;
spin_unlock_irqrestore ( & s - > data_lock , flags ) ;
s - > tx_enabled = 1 ;
i + + ;
len + + ;
}
/* Perform the SPI transfer */
if ( max3107_rw ( s , ( u8 * ) buf , NULL , len * 2 ) ) {
dev_err ( & s - > spi - > dev ,
" SPI transfer TX handling failed \n " ) ;
return ;
}
}
/* Indicate wake up if circular buffer is getting low on data */
if ( uart_circ_chars_pending ( xmit ) < WAKEUP_CHARS )
uart_write_wakeup ( & s - > port ) ;
}
/* Handle interrupts
* Also reads and returns current RX FIFO level
*/
static u16 handle_interrupt ( struct max3107_port * s )
{
u16 buf [ 4 ] ; /* Buffer for SPI transfers */
u8 irq_status ;
u16 rx_level ;
unsigned long flags ;
/* Read IRQ status register */
buf [ 0 ] = MAX3107_IRQSTS_REG ;
/* Read status IRQ status register */
buf [ 1 ] = MAX3107_STS_IRQSTS_REG ;
/* Read LSR IRQ status register */
buf [ 2 ] = MAX3107_LSR_IRQSTS_REG ;
/* Query RX level */
buf [ 3 ] = MAX3107_RXFIFOLVL_REG ;
if ( max3107_rw ( s , ( u8 * ) buf , ( u8 * ) buf , 8 ) ) {
dev_err ( & s - > spi - > dev ,
" SPI transfer for INTR handling failed \n " ) ;
return 0 ;
}
irq_status = ( u8 ) buf [ 0 ] ;
pr_debug ( " IRQSTS %x \n " , irq_status ) ;
rx_level = ( buf [ 3 ] & MAX3107_SPI_RX_DATA_MASK ) ;
if ( irq_status & MAX3107_IRQ_LSR_BIT ) {
/* LSR interrupt */
if ( buf [ 2 ] & MAX3107_LSR_RXTO_BIT )
/* RX timeout interrupt,
* handled by normal RX handling
*/
pr_debug ( " RX TO INT \n " ) ;
}
if ( irq_status & MAX3107_IRQ_TXEMPTY_BIT ) {
/* Tx empty interrupt,
* disable TX and set tx_fifo_empty flag
*/
pr_debug ( " TE INT, disabling TX \n " ) ;
buf [ 0 ] = ( MAX3107_WRITE_BIT | MAX3107_MODE1_REG ) ;
spin_lock_irqsave ( & s - > data_lock , flags ) ;
s - > mode1_reg | = MAX3107_MODE1_TXDIS_BIT ;
buf [ 0 ] | = s - > mode1_reg ;
spin_unlock_irqrestore ( & s - > data_lock , flags ) ;
if ( max3107_rw ( s , ( u8 * ) buf , NULL , 2 ) )
dev_err ( & s - > spi - > dev , " SPI transfer TX dis failed \n " ) ;
s - > tx_enabled = 0 ;
s - > tx_fifo_empty = 1 ;
}
if ( irq_status & MAX3107_IRQ_RXFIFO_BIT )
/* RX FIFO interrupt,
* handled by normal RX handling
*/
pr_debug ( " RFIFO INT \n " ) ;
/* Return RX level */
return rx_level ;
}
/* Trigger work thread*/
static void max3107_dowork ( struct max3107_port * s )
{
if ( ! work_pending ( & s - > work ) & & ! freezing ( current ) & & ! s - > suspended )
queue_work ( s - > workqueue , & s - > work ) ;
else
dev_warn ( & s - > spi - > dev , " interrup isn't serviced normally! \n " ) ;
}
/* Work thread */
static void max3107_work ( struct work_struct * w )
{
struct max3107_port * s = container_of ( w , struct max3107_port , work ) ;
u16 rxlvl = 0 ;
int len ; /* SPI transfer buffer length */
u16 buf [ 5 ] ; /* Buffer for SPI transfers */
unsigned long flags ;
/* Start by reading current RX FIFO level */
buf [ 0 ] = MAX3107_RXFIFOLVL_REG ;
if ( max3107_rw ( s , ( u8 * ) buf , ( u8 * ) buf , 2 ) ) {
dev_err ( & s - > spi - > dev , " SPI transfer RX lev failed \n " ) ;
rxlvl = 0 ;
} else {
rxlvl = ( buf [ 0 ] & MAX3107_SPI_RX_DATA_MASK ) ;
}
do {
pr_debug ( " rxlvl %d \n " , rxlvl ) ;
/* Handle RX */
max3107_handlerx ( s , rxlvl ) ;
rxlvl = 0 ;
if ( s - > handle_irq ) {
/* Handle pending interrupts
* We also get new RX FIFO level since new data may
* have been received while pushing received data to
* receivers
*/
s - > handle_irq = 0 ;
rxlvl = handle_interrupt ( s ) ;
}
/* Handle TX */
max3107_handletx ( s ) ;
/* Handle configuration changes */
len = 0 ;
spin_lock_irqsave ( & s - > data_lock , flags ) ;
if ( s - > mode1_commit ) {
pr_debug ( " mode1_commit \n " ) ;
buf [ len ] = ( MAX3107_WRITE_BIT | MAX3107_MODE1_REG ) ;
buf [ len + + ] | = s - > mode1_reg ;
s - > mode1_commit = 0 ;
}
if ( s - > lcr_commit ) {
pr_debug ( " lcr_commit \n " ) ;
buf [ len ] = ( MAX3107_WRITE_BIT | MAX3107_LCR_REG ) ;
buf [ len + + ] | = s - > lcr_reg ;
s - > lcr_commit = 0 ;
}
if ( s - > brg_commit ) {
pr_debug ( " brg_commit \n " ) ;
buf [ len ] = ( MAX3107_WRITE_BIT | MAX3107_BRGDIVMSB_REG ) ;
buf [ len + + ] | = ( ( s - > brg_cfg > > 16 ) &
MAX3107_SPI_TX_DATA_MASK ) ;
buf [ len ] = ( MAX3107_WRITE_BIT | MAX3107_BRGDIVLSB_REG ) ;
buf [ len + + ] | = ( ( s - > brg_cfg > > 8 ) &
MAX3107_SPI_TX_DATA_MASK ) ;
buf [ len ] = ( MAX3107_WRITE_BIT | MAX3107_BRGCFG_REG ) ;
buf [ len + + ] | = ( ( s - > brg_cfg ) & 0xff ) ;
s - > brg_commit = 0 ;
}
spin_unlock_irqrestore ( & s - > data_lock , flags ) ;
if ( len > 0 ) {
if ( max3107_rw ( s , ( u8 * ) buf , NULL , len * 2 ) )
dev_err ( & s - > spi - > dev ,
" SPI transfer config failed \n " ) ;
}
/* Reloop if interrupt handling indicated data in RX FIFO */
} while ( rxlvl ) ;
}
/* Set sleep mode */
static void max3107_set_sleep ( struct max3107_port * s , int mode )
{
u16 buf [ 1 ] ; /* Buffer for SPI transfer */
unsigned long flags ;
pr_debug ( " enter, mode %d \n " , mode ) ;
buf [ 0 ] = ( MAX3107_WRITE_BIT | MAX3107_MODE1_REG ) ;
spin_lock_irqsave ( & s - > data_lock , flags ) ;
switch ( mode ) {
case MAX3107_DISABLE_FORCED_SLEEP :
s - > mode1_reg & = ~ MAX3107_MODE1_FORCESLEEP_BIT ;
break ;
case MAX3107_ENABLE_FORCED_SLEEP :
s - > mode1_reg | = MAX3107_MODE1_FORCESLEEP_BIT ;
break ;
case MAX3107_DISABLE_AUTOSLEEP :
s - > mode1_reg & = ~ MAX3107_MODE1_AUTOSLEEP_BIT ;
break ;
case MAX3107_ENABLE_AUTOSLEEP :
s - > mode1_reg | = MAX3107_MODE1_AUTOSLEEP_BIT ;
break ;
default :
spin_unlock_irqrestore ( & s - > data_lock , flags ) ;
dev_warn ( & s - > spi - > dev , " invalid sleep mode \n " ) ;
return ;
}
buf [ 0 ] | = s - > mode1_reg ;
spin_unlock_irqrestore ( & s - > data_lock , flags ) ;
if ( max3107_rw ( s , ( u8 * ) buf , NULL , 2 ) )
dev_err ( & s - > spi - > dev , " SPI transfer sleep mode failed \n " ) ;
if ( mode = = MAX3107_DISABLE_AUTOSLEEP | |
mode = = MAX3107_DISABLE_FORCED_SLEEP )
msleep ( MAX3107_WAKEUP_DELAY ) ;
}
/* Perform full register initialization */
static void max3107_register_init ( struct max3107_port * s )
{
u16 buf [ 11 ] ; /* Buffer for SPI transfers */
/* 1. Configure baud rate, 9600 as default */
s - > baud = 9600 ;
/* the below is default*/
if ( s - > ext_clk ) {
s - > brg_cfg = MAX3107_BRG26_B9600 ;
s - > baud_tbl = ( struct baud_table * ) brg26_ext ;
} else {
s - > brg_cfg = MAX3107_BRG13_IB9600 ;
s - > baud_tbl = ( struct baud_table * ) brg13_int ;
}
2010-06-30 17:58:38 +01:00
if ( s - > pdata - > init )
s - > pdata - > init ( s ) ;
2010-06-30 17:57:12 +01:00
buf [ 0 ] = ( MAX3107_WRITE_BIT | MAX3107_BRGDIVMSB_REG )
| ( ( s - > brg_cfg > > 16 ) & MAX3107_SPI_TX_DATA_MASK ) ;
buf [ 1 ] = ( MAX3107_WRITE_BIT | MAX3107_BRGDIVLSB_REG )
| ( ( s - > brg_cfg > > 8 ) & MAX3107_SPI_TX_DATA_MASK ) ;
buf [ 2 ] = ( MAX3107_WRITE_BIT | MAX3107_BRGCFG_REG )
| ( ( s - > brg_cfg ) & 0xff ) ;
/* 2. Configure LCR register, 8N1 mode by default */
s - > lcr_reg = MAX3107_LCR_WORD_LEN_8 ;
buf [ 3 ] = ( MAX3107_WRITE_BIT | MAX3107_LCR_REG )
| s - > lcr_reg ;
/* 3. Configure MODE 1 register */
s - > mode1_reg = 0 ;
/* Enable IRQ pin */
s - > mode1_reg | = MAX3107_MODE1_IRQSEL_BIT ;
/* Disable TX */
s - > mode1_reg | = MAX3107_MODE1_TXDIS_BIT ;
s - > tx_enabled = 0 ;
/* RX is enabled */
s - > rx_enabled = 1 ;
buf [ 4 ] = ( MAX3107_WRITE_BIT | MAX3107_MODE1_REG )
| s - > mode1_reg ;
/* 4. Configure MODE 2 register */
buf [ 5 ] = ( MAX3107_WRITE_BIT | MAX3107_MODE2_REG ) ;
if ( s - > loopback ) {
/* Enable loopback */
buf [ 5 ] | = MAX3107_MODE2_LOOPBACK_BIT ;
}
/* Reset FIFOs */
buf [ 5 ] | = MAX3107_MODE2_FIFORST_BIT ;
s - > tx_fifo_empty = 1 ;
/* 5. Configure FIFO trigger level register */
buf [ 6 ] = ( MAX3107_WRITE_BIT | MAX3107_FIFOTRIGLVL_REG ) ;
/* RX FIFO trigger for 16 words, TX FIFO trigger not used */
buf [ 6 ] | = ( MAX3107_FIFOTRIGLVL_RX ( 16 ) | MAX3107_FIFOTRIGLVL_TX ( 0 ) ) ;
/* 6. Configure flow control levels */
buf [ 7 ] = ( MAX3107_WRITE_BIT | MAX3107_FLOWLVL_REG ) ;
/* Flow control halt level 96, resume level 48 */
buf [ 7 ] | = ( MAX3107_FLOWLVL_RES ( 48 ) | MAX3107_FLOWLVL_HALT ( 96 ) ) ;
/* 7. Configure flow control */
buf [ 8 ] = ( MAX3107_WRITE_BIT | MAX3107_FLOWCTRL_REG ) ;
/* Enable auto CTS and auto RTS flow control */
buf [ 8 ] | = ( MAX3107_FLOWCTRL_AUTOCTS_BIT | MAX3107_FLOWCTRL_AUTORTS_BIT ) ;
/* 8. Configure RX timeout register */
buf [ 9 ] = ( MAX3107_WRITE_BIT | MAX3107_RXTO_REG ) ;
/* Timeout after 48 character intervals */
buf [ 9 ] | = 0x0030 ;
/* 9. Configure LSR interrupt enable register */
buf [ 10 ] = ( MAX3107_WRITE_BIT | MAX3107_LSR_IRQEN_REG ) ;
/* Enable RX timeout interrupt */
buf [ 10 ] | = MAX3107_LSR_RXTO_BIT ;
/* Perform SPI transfer */
if ( max3107_rw ( s , ( u8 * ) buf , NULL , 22 ) )
dev_err ( & s - > spi - > dev , " SPI transfer for init failed \n " ) ;
/* 10. Clear IRQ status register by reading it */
buf [ 0 ] = MAX3107_IRQSTS_REG ;
/* 11. Configure interrupt enable register */
/* Enable LSR interrupt */
s - > irqen_reg = MAX3107_IRQ_LSR_BIT ;
/* Enable RX FIFO interrupt */
s - > irqen_reg | = MAX3107_IRQ_RXFIFO_BIT ;
buf [ 1 ] = ( MAX3107_WRITE_BIT | MAX3107_IRQEN_REG )
| s - > irqen_reg ;
/* 12. Clear FIFO reset that was set in step 6 */
buf [ 2 ] = ( MAX3107_WRITE_BIT | MAX3107_MODE2_REG ) ;
if ( s - > loopback ) {
/* Keep loopback enabled */
buf [ 2 ] | = MAX3107_MODE2_LOOPBACK_BIT ;
}
/* Perform SPI transfer */
if ( max3107_rw ( s , ( u8 * ) buf , ( u8 * ) buf , 6 ) )
dev_err ( & s - > spi - > dev , " SPI transfer for init failed \n " ) ;
}
/* IRQ handler */
static irqreturn_t max3107_irq ( int irqno , void * dev_id )
{
struct max3107_port * s = dev_id ;
if ( irqno ! = s - > spi - > irq ) {
/* Unexpected IRQ */
return IRQ_NONE ;
}
/* Indicate irq */
s - > handle_irq = 1 ;
/* Trigger work thread */
max3107_dowork ( s ) ;
return IRQ_HANDLED ;
}
/* HW suspension function
*
* Currently autosleep is used to decrease current consumption , alternative
* approach would be to set the chip to reset mode if UART is not being
* used but that would mess the GPIOs
*
*/
2010-06-30 17:58:38 +01:00
void max3107_hw_susp ( struct max3107_port * s , int suspend )
2010-06-30 17:57:12 +01:00
{
pr_debug ( " enter, suspend %d \n " , suspend ) ;
if ( suspend ) {
/* Suspend requested,
* enable autosleep to decrease current consumption
*/
s - > suspended = 1 ;
max3107_set_sleep ( s , MAX3107_ENABLE_AUTOSLEEP ) ;
} else {
/* Resume requested,
* disable autosleep
*/
s - > suspended = 0 ;
max3107_set_sleep ( s , MAX3107_DISABLE_AUTOSLEEP ) ;
}
}
2010-06-30 17:58:38 +01:00
EXPORT_SYMBOL_GPL ( max3107_hw_susp ) ;
2010-06-30 17:57:12 +01:00
/* Modem status IRQ enabling */
static void max3107_enable_ms ( struct uart_port * port )
{
/* Modem status not supported */
}
/* Data send function */
static void max3107_start_tx ( struct uart_port * port )
{
struct max3107_port * s = container_of ( port , struct max3107_port , port ) ;
/* Trigger work thread for sending data */
max3107_dowork ( s ) ;
}
/* Function for checking that there is no pending transfers */
static unsigned int max3107_tx_empty ( struct uart_port * port )
{
struct max3107_port * s = container_of ( port , struct max3107_port , port ) ;
pr_debug ( " returning %d \n " ,
( s - > tx_fifo_empty & & uart_circ_empty ( & s - > port . state - > xmit ) ) ) ;
return s - > tx_fifo_empty & & uart_circ_empty ( & s - > port . state - > xmit ) ;
}
/* Function for stopping RX */
static void max3107_stop_rx ( struct uart_port * port )
{
struct max3107_port * s = container_of ( port , struct max3107_port , port ) ;
unsigned long flags ;
/* Set RX disabled in MODE 1 register */
spin_lock_irqsave ( & s - > data_lock , flags ) ;
s - > mode1_reg | = MAX3107_MODE1_RXDIS_BIT ;
s - > mode1_commit = 1 ;
spin_unlock_irqrestore ( & s - > data_lock , flags ) ;
/* Set RX disabled */
s - > rx_enabled = 0 ;
/* Trigger work thread for doing the actual configuration change */
max3107_dowork ( s ) ;
}
/* Function for returning control pin states */
static unsigned int max3107_get_mctrl ( struct uart_port * port )
{
/* DCD and DSR are not wired and CTS/RTS is handled automatically
* so just indicate DSR and CAR asserted
*/
return TIOCM_DSR | TIOCM_CAR ;
}
/* Function for setting control pin states */
static void max3107_set_mctrl ( struct uart_port * port , unsigned int mctrl )
{
/* DCD and DSR are not wired and CTS/RTS is hadnled automatically
* so do nothing
*/
}
/* Function for configuring UART parameters */
static void max3107_set_termios ( struct uart_port * port ,
struct ktermios * termios ,
struct ktermios * old )
{
struct max3107_port * s = container_of ( port , struct max3107_port , port ) ;
struct tty_struct * tty ;
int baud ;
u16 new_lcr = 0 ;
u32 new_brg = 0 ;
unsigned long flags ;
if ( ! port - > state )
return ;
tty = port - > state - > port . tty ;
if ( ! tty )
return ;
/* Get new LCR register values */
/* Word size */
if ( ( termios - > c_cflag & CSIZE ) = = CS7 )
new_lcr | = MAX3107_LCR_WORD_LEN_7 ;
else
new_lcr | = MAX3107_LCR_WORD_LEN_8 ;
/* Parity */
if ( termios - > c_cflag & PARENB ) {
new_lcr | = MAX3107_LCR_PARITY_BIT ;
if ( ! ( termios - > c_cflag & PARODD ) )
new_lcr | = MAX3107_LCR_EVENPARITY_BIT ;
}
/* Stop bits */
if ( termios - > c_cflag & CSTOPB ) {
/* 2 stop bits */
new_lcr | = MAX3107_LCR_STOPLEN_BIT ;
}
/* Mask termios capabilities we don't support */
termios - > c_cflag & = ~ CMSPAR ;
/* Set status ignore mask */
s - > port . ignore_status_mask = 0 ;
if ( termios - > c_iflag & IGNPAR )
s - > port . ignore_status_mask | = MAX3107_ALL_ERRORS ;
/* Set low latency to immediately handle pushed data */
s - > port . state - > port . tty - > low_latency = 1 ;
/* Get new baud rate generator configuration */
baud = tty_get_baud_rate ( tty ) ;
spin_lock_irqsave ( & s - > data_lock , flags ) ;
new_brg = get_new_brg ( baud , s ) ;
/* if can't find the corrent config, use previous */
if ( ! new_brg ) {
baud = s - > baud ;
new_brg = s - > brg_cfg ;
}
spin_unlock_irqrestore ( & s - > data_lock , flags ) ;
tty_termios_encode_baud_rate ( termios , baud , baud ) ;
s - > baud = baud ;
/* Update timeout according to new baud rate */
uart_update_timeout ( port , termios - > c_cflag , baud ) ;
spin_lock_irqsave ( & s - > data_lock , flags ) ;
if ( s - > lcr_reg ! = new_lcr ) {
s - > lcr_reg = new_lcr ;
s - > lcr_commit = 1 ;
}
if ( s - > brg_cfg ! = new_brg ) {
s - > brg_cfg = new_brg ;
s - > brg_commit = 1 ;
}
spin_unlock_irqrestore ( & s - > data_lock , flags ) ;
/* Trigger work thread for doing the actual configuration change */
max3107_dowork ( s ) ;
}
/* Port shutdown function */
static void max3107_shutdown ( struct uart_port * port )
{
struct max3107_port * s = container_of ( port , struct max3107_port , port ) ;
2010-06-30 17:58:38 +01:00
if ( s - > suspended & & s - > pdata - > hw_suspend )
s - > pdata - > hw_suspend ( s , 0 ) ;
2010-06-30 17:57:12 +01:00
/* Free the interrupt */
free_irq ( s - > spi - > irq , s ) ;
if ( s - > workqueue ) {
/* Flush and destroy work queue */
flush_workqueue ( s - > workqueue ) ;
destroy_workqueue ( s - > workqueue ) ;
s - > workqueue = NULL ;
}
/* Suspend HW */
2010-06-30 17:58:38 +01:00
if ( s - > pdata - > hw_suspend )
s - > pdata - > hw_suspend ( s , 1 ) ;
2010-06-30 17:57:12 +01:00
}
/* Port startup function */
static int max3107_startup ( struct uart_port * port )
{
struct max3107_port * s = container_of ( port , struct max3107_port , port ) ;
/* Initialize work queue */
s - > workqueue = create_freezeable_workqueue ( " max3107 " ) ;
if ( ! s - > workqueue ) {
dev_err ( & s - > spi - > dev , " Workqueue creation failed \n " ) ;
return - EBUSY ;
}
INIT_WORK ( & s - > work , max3107_work ) ;
/* Setup IRQ */
if ( request_irq ( s - > spi - > irq , max3107_irq , IRQF_TRIGGER_FALLING ,
" max3107 " , s ) ) {
dev_err ( & s - > spi - > dev , " IRQ reguest failed \n " ) ;
destroy_workqueue ( s - > workqueue ) ;
s - > workqueue = NULL ;
return - EBUSY ;
}
/* Resume HW */
2010-06-30 17:58:38 +01:00
if ( s - > pdata - > hw_suspend )
s - > pdata - > hw_suspend ( s , 0 ) ;
2010-06-30 17:57:12 +01:00
/* Init registers */
max3107_register_init ( s ) ;
return 0 ;
}
/* Port type function */
static const char * max3107_type ( struct uart_port * port )
{
struct max3107_port * s = container_of ( port , struct max3107_port , port ) ;
return s - > spi - > modalias ;
}
/* Port release function */
static void max3107_release_port ( struct uart_port * port )
{
/* Do nothing */
}
/* Port request function */
static int max3107_request_port ( struct uart_port * port )
{
/* Do nothing */
return 0 ;
}
/* Port config function */
static void max3107_config_port ( struct uart_port * port , int flags )
{
struct max3107_port * s = container_of ( port , struct max3107_port , port ) ;
2010-06-30 17:58:38 +01:00
s - > port . type = PORT_MAX3107 ;
2010-06-30 17:57:12 +01:00
}
/* Port verify function */
static int max3107_verify_port ( struct uart_port * port ,
struct serial_struct * ser )
{
2010-06-30 17:58:38 +01:00
if ( ser - > type = = PORT_UNKNOWN | | ser - > type = = PORT_MAX3107 )
2010-06-30 17:57:12 +01:00
return 0 ;
return - EINVAL ;
}
/* Port stop TX function */
static void max3107_stop_tx ( struct uart_port * port )
{
/* Do nothing */
}
/* Port break control function */
static void max3107_break_ctl ( struct uart_port * port , int break_state )
{
/* We don't support break control, do nothing */
}
/* Port functions */
static struct uart_ops max3107_ops = {
. tx_empty = max3107_tx_empty ,
. set_mctrl = max3107_set_mctrl ,
. get_mctrl = max3107_get_mctrl ,
. stop_tx = max3107_stop_tx ,
. start_tx = max3107_start_tx ,
. stop_rx = max3107_stop_rx ,
. enable_ms = max3107_enable_ms ,
. break_ctl = max3107_break_ctl ,
. startup = max3107_startup ,
. shutdown = max3107_shutdown ,
. set_termios = max3107_set_termios ,
. type = max3107_type ,
. release_port = max3107_release_port ,
. request_port = max3107_request_port ,
. config_port = max3107_config_port ,
. verify_port = max3107_verify_port ,
} ;
/* UART driver data */
static struct uart_driver max3107_uart_driver = {
. owner = THIS_MODULE ,
. driver_name = " ttyMAX " ,
. dev_name = " ttyMAX " ,
. nr = 1 ,
} ;
2010-06-30 17:58:38 +01:00
static int driver_registered = 0 ;
/* 'Generic' platform data */
static struct max3107_plat generic_plat_data = {
. loopback = 0 ,
. ext_clk = 1 ,
. hw_suspend = max3107_hw_susp ,
. polled_mode = 0 ,
. poll_time = 0 ,
2010-06-30 17:57:12 +01:00
} ;
2010-06-30 17:58:38 +01:00
/*******************************************************************/
/**
* max3107_probe - SPI bus probe entry point
* @ spi : the spi device
*
* SPI wants us to probe this device and if appropriate claim it .
* Perform any platform specific requirements and then initialise
* the device .
*/
int max3107_probe ( struct spi_device * spi , struct max3107_plat * pdata )
2010-06-30 17:57:12 +01:00
{
struct max3107_port * s ;
u16 buf [ 2 ] ; /* Buffer for SPI transfers */
int retval ;
pr_info ( " enter max3107 probe \n " ) ;
/* Allocate port structure */
s = kzalloc ( sizeof ( * s ) , GFP_KERNEL ) ;
if ( ! s ) {
pr_err ( " Allocating port structure failed \n " ) ;
return - ENOMEM ;
}
2010-06-30 17:58:38 +01:00
s - > pdata = pdata ;
2010-06-30 17:57:12 +01:00
/* SPI Rx buffer
* + 2 for RX FIFO interrupt
* disabling and RX level query
*/
s - > rxbuf = kzalloc ( sizeof ( u16 ) * ( MAX3107_RX_FIFO_SIZE + 2 ) , GFP_KERNEL ) ;
if ( ! s - > rxbuf ) {
pr_err ( " Allocating RX buffer failed \n " ) ;
2010-09-13 12:08:11 -04:00
retval = - ENOMEM ;
goto err_free4 ;
2010-06-30 17:57:12 +01:00
}
s - > rxstr = kzalloc ( sizeof ( u8 ) * MAX3107_RX_FIFO_SIZE , GFP_KERNEL ) ;
if ( ! s - > rxstr ) {
pr_err ( " Allocating RX buffer failed \n " ) ;
2010-09-13 12:08:11 -04:00
retval = - ENOMEM ;
goto err_free3 ;
2010-06-30 17:57:12 +01:00
}
/* SPI Tx buffer
* SPI transfer buffer
* + 3 for TX FIFO empty
* interrupt disabling and
* enabling and TX enabling
*/
s - > txbuf = kzalloc ( sizeof ( u16 ) * MAX3107_TX_FIFO_SIZE + 3 , GFP_KERNEL ) ;
if ( ! s - > txbuf ) {
pr_err ( " Allocating TX buffer failed \n " ) ;
2010-09-13 12:08:11 -04:00
retval = - ENOMEM ;
goto err_free2 ;
2010-06-30 17:57:12 +01:00
}
/* Initialize shared data lock */
spin_lock_init ( & s - > data_lock ) ;
/* SPI intializations */
dev_set_drvdata ( & spi - > dev , s ) ;
spi - > mode = SPI_MODE_0 ;
spi - > dev . platform_data = pdata ;
spi - > bits_per_word = 16 ;
s - > ext_clk = pdata - > ext_clk ;
s - > loopback = pdata - > loopback ;
spi_setup ( spi ) ;
s - > spi = spi ;
/* Check REV ID to ensure we are talking to what we expect */
buf [ 0 ] = MAX3107_REVID_REG ;
if ( max3107_rw ( s , ( u8 * ) buf , ( u8 * ) buf , 2 ) ) {
dev_err ( & s - > spi - > dev , " SPI transfer for REVID read failed \n " ) ;
2010-09-13 12:08:11 -04:00
retval = - EIO ;
goto err_free1 ;
2010-06-30 17:57:12 +01:00
}
if ( ( buf [ 0 ] & MAX3107_SPI_RX_DATA_MASK ) ! = MAX3107_REVID1 & &
( buf [ 0 ] & MAX3107_SPI_RX_DATA_MASK ) ! = MAX3107_REVID2 ) {
dev_err ( & s - > spi - > dev , " REVID %x does not match \n " ,
( buf [ 0 ] & MAX3107_SPI_RX_DATA_MASK ) ) ;
2010-09-13 12:08:11 -04:00
retval = - ENODEV ;
goto err_free1 ;
2010-06-30 17:57:12 +01:00
}
/* Disable all interrupts */
buf [ 0 ] = ( MAX3107_WRITE_BIT | MAX3107_IRQEN_REG | 0x0000 ) ;
buf [ 0 ] | = 0x0000 ;
/* Configure clock source */
buf [ 1 ] = ( MAX3107_WRITE_BIT | MAX3107_CLKSRC_REG ) ;
if ( s - > ext_clk ) {
/* External clock */
buf [ 1 ] | = MAX3107_CLKSRC_EXTCLK_BIT ;
}
/* PLL bypass ON */
buf [ 1 ] | = MAX3107_CLKSRC_PLLBYP_BIT ;
/* Perform SPI transfer */
if ( max3107_rw ( s , ( u8 * ) buf , NULL , 4 ) ) {
dev_err ( & s - > spi - > dev , " SPI transfer for init failed \n " ) ;
2010-09-13 12:08:11 -04:00
retval = - EIO ;
goto err_free1 ;
2010-06-30 17:57:12 +01:00
}
/* Register UART driver */
2010-06-30 17:58:38 +01:00
if ( ! driver_registered ) {
retval = uart_register_driver ( & max3107_uart_driver ) ;
if ( retval ) {
dev_err ( & s - > spi - > dev , " Registering UART driver failed \n " ) ;
2010-09-13 12:08:11 -04:00
goto err_free1 ;
2010-06-30 17:58:38 +01:00
}
driver_registered = 1 ;
2010-06-30 17:57:12 +01:00
}
/* Initialize UART port data */
s - > port . fifosize = 128 ;
s - > port . ops = & max3107_ops ;
s - > port . line = 0 ;
s - > port . dev = & spi - > dev ;
s - > port . uartclk = 9600 ;
s - > port . flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF ;
s - > port . irq = s - > spi - > irq ;
2010-06-30 17:58:38 +01:00
s - > port . type = PORT_MAX3107 ;
2010-06-30 17:57:12 +01:00
/* Add UART port */
retval = uart_add_one_port ( & max3107_uart_driver , & s - > port ) ;
if ( retval < 0 ) {
dev_err ( & s - > spi - > dev , " Adding UART port failed \n " ) ;
2010-09-13 12:08:11 -04:00
goto err_free1 ;
2010-06-30 17:57:12 +01:00
}
2010-06-30 17:58:38 +01:00
if ( pdata - > configure ) {
retval = pdata - > configure ( s ) ;
if ( retval < 0 )
2010-09-13 12:08:11 -04:00
goto err_free1 ;
2010-06-30 17:57:12 +01:00
}
/* Go to suspend mode */
2010-06-30 17:58:38 +01:00
if ( pdata - > hw_suspend )
pdata - > hw_suspend ( s , 1 ) ;
2010-06-30 17:57:12 +01:00
return 0 ;
2010-09-13 12:08:11 -04:00
err_free1 :
kfree ( s - > txbuf ) ;
err_free2 :
kfree ( s - > rxstr ) ;
err_free3 :
kfree ( s - > rxbuf ) ;
err_free4 :
kfree ( s ) ;
return retval ;
2010-06-30 17:57:12 +01:00
}
2010-06-30 17:58:38 +01:00
EXPORT_SYMBOL_GPL ( max3107_probe ) ;
2010-06-30 17:57:12 +01:00
/* Driver remove function */
2010-06-30 17:58:38 +01:00
int max3107_remove ( struct spi_device * spi )
2010-06-30 17:57:12 +01:00
{
struct max3107_port * s = dev_get_drvdata ( & spi - > dev ) ;
pr_info ( " enter max3107 remove \n " ) ;
/* Remove port */
if ( uart_remove_one_port ( & max3107_uart_driver , & s - > port ) )
dev_warn ( & s - > spi - > dev , " Removing UART port failed \n " ) ;
/* Free TxRx buffer */
kfree ( s - > rxbuf ) ;
kfree ( s - > rxstr ) ;
kfree ( s - > txbuf ) ;
/* Free port structure */
kfree ( s ) ;
return 0 ;
}
2010-06-30 17:58:38 +01:00
EXPORT_SYMBOL_GPL ( max3107_remove ) ;
2010-06-30 17:57:12 +01:00
/* Driver suspend function */
2010-06-30 17:58:38 +01:00
int max3107_suspend ( struct spi_device * spi , pm_message_t state )
2010-06-30 17:57:12 +01:00
{
# ifdef CONFIG_PM
struct max3107_port * s = dev_get_drvdata ( & spi - > dev ) ;
pr_debug ( " enter suspend \n " ) ;
/* Suspend UART port */
uart_suspend_port ( & max3107_uart_driver , & s - > port ) ;
/* Go to suspend mode */
2010-06-30 17:58:38 +01:00
if ( s - > pdata - > hw_suspend )
s - > pdata - > hw_suspend ( s , 1 ) ;
2010-06-30 17:57:12 +01:00
# endif /* CONFIG_PM */
return 0 ;
}
2010-06-30 17:58:38 +01:00
EXPORT_SYMBOL_GPL ( max3107_suspend ) ;
2010-06-30 17:57:12 +01:00
/* Driver resume function */
2010-06-30 17:58:38 +01:00
int max3107_resume ( struct spi_device * spi )
2010-06-30 17:57:12 +01:00
{
# ifdef CONFIG_PM
struct max3107_port * s = dev_get_drvdata ( & spi - > dev ) ;
pr_debug ( " enter resume \n " ) ;
/* Resume from suspend */
2010-06-30 17:58:38 +01:00
if ( s - > pdata - > hw_suspend )
s - > pdata - > hw_suspend ( s , 0 ) ;
2010-06-30 17:57:12 +01:00
/* Resume UART port */
uart_resume_port ( & max3107_uart_driver , & s - > port ) ;
# endif /* CONFIG_PM */
return 0 ;
}
2010-06-30 17:58:38 +01:00
EXPORT_SYMBOL_GPL ( max3107_resume ) ;
static int max3107_probe_generic ( struct spi_device * spi )
{
return max3107_probe ( spi , & generic_plat_data ) ;
}
2010-06-30 17:57:12 +01:00
/* Spi driver data */
static struct spi_driver max3107_driver = {
. driver = {
. name = " max3107 " ,
. bus = & spi_bus_type ,
. owner = THIS_MODULE ,
} ,
2010-06-30 17:58:38 +01:00
. probe = max3107_probe_generic ,
2010-06-30 17:57:12 +01:00
. remove = __devexit_p ( max3107_remove ) ,
. suspend = max3107_suspend ,
. resume = max3107_resume ,
} ;
/* Driver init function */
static int __init max3107_init ( void )
{
pr_info ( " enter max3107 init \n " ) ;
return spi_register_driver ( & max3107_driver ) ;
}
/* Driver exit function */
static void __exit max3107_exit ( void )
{
pr_info ( " enter max3107 exit \n " ) ;
2010-06-30 17:58:38 +01:00
/* Unregister UART driver */
if ( driver_registered )
uart_unregister_driver ( & max3107_uart_driver ) ;
2010-06-30 17:57:12 +01:00
spi_unregister_driver ( & max3107_driver ) ;
}
module_init ( max3107_init ) ;
module_exit ( max3107_exit ) ;
MODULE_DESCRIPTION ( " MAX3107 driver " ) ;
MODULE_AUTHOR ( " Aavamobile " ) ;
2010-06-30 17:58:38 +01:00
MODULE_ALIAS ( " max3107-spi " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;