2006-01-09 00:34:26 +03:00
/*
* spi_bitbang . c - polling / bitbanging SPI master controller driver utilities
*
* 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/init.h>
# include <linux/spinlock.h>
# include <linux/workqueue.h>
# include <linux/interrupt.h>
# include <linux/delay.h>
# include <linux/errno.h>
# include <linux/platform_device.h>
# include <linux/spi/spi.h>
# include <linux/spi/spi_bitbang.h>
/*----------------------------------------------------------------------*/
/*
* FIRST PART ( OPTIONAL ) : word - at - a - time spi_transfer support .
* Use this for GPIO or shift - register level hardware APIs .
*
* spi_bitbang_cs is in spi_device - > controller_state , which is unavailable
* to glue code . These bitbang setup ( ) and cleanup ( ) routines are always
* used , though maybe they ' re called from controller - aware code .
*
* chipselect ( ) and friends may use use spi_device - > controller_data and
* controller registers as appropriate .
*
*
* NOTE : SPI controller pins can often be used as GPIO pins instead ,
* which means you could use a bitbang driver either to get hardware
* working quickly , or testing for differences that aren ' t speed related .
*/
struct spi_bitbang_cs {
unsigned nsecs ; /* (clock cycle time)/2 */
u32 ( * txrx_word ) ( struct spi_device * spi , unsigned nsecs ,
u32 word , u8 bits ) ;
unsigned ( * txrx_bufs ) ( struct spi_device * ,
u32 ( * txrx_word ) (
struct spi_device * spi ,
unsigned nsecs ,
u32 word , u8 bits ) ,
unsigned , struct spi_transfer * ) ;
} ;
static unsigned bitbang_txrx_8 (
struct spi_device * spi ,
u32 ( * txrx_word ) ( struct spi_device * spi ,
unsigned nsecs ,
u32 word , u8 bits ) ,
unsigned ns ,
struct spi_transfer * t
) {
unsigned bits = spi - > bits_per_word ;
unsigned count = t - > len ;
const u8 * tx = t - > tx_buf ;
u8 * rx = t - > rx_buf ;
while ( likely ( count > 0 ) ) {
u8 word = 0 ;
if ( tx )
word = * tx + + ;
word = txrx_word ( spi , ns , word , bits ) ;
if ( rx )
* rx + + = word ;
count - = 1 ;
}
return t - > len - count ;
}
static unsigned bitbang_txrx_16 (
struct spi_device * spi ,
u32 ( * txrx_word ) ( struct spi_device * spi ,
unsigned nsecs ,
u32 word , u8 bits ) ,
unsigned ns ,
struct spi_transfer * t
) {
unsigned bits = spi - > bits_per_word ;
unsigned count = t - > len ;
const u16 * tx = t - > tx_buf ;
u16 * rx = t - > rx_buf ;
while ( likely ( count > 1 ) ) {
u16 word = 0 ;
if ( tx )
word = * tx + + ;
word = txrx_word ( spi , ns , word , bits ) ;
if ( rx )
* rx + + = word ;
count - = 2 ;
}
return t - > len - count ;
}
static unsigned bitbang_txrx_32 (
struct spi_device * spi ,
u32 ( * txrx_word ) ( struct spi_device * spi ,
unsigned nsecs ,
u32 word , u8 bits ) ,
unsigned ns ,
struct spi_transfer * t
) {
unsigned bits = spi - > bits_per_word ;
unsigned count = t - > len ;
const u32 * tx = t - > tx_buf ;
u32 * rx = t - > rx_buf ;
while ( likely ( count > 3 ) ) {
u32 word = 0 ;
if ( tx )
word = * tx + + ;
word = txrx_word ( spi , ns , word , bits ) ;
if ( rx )
* rx + + = word ;
count - = 4 ;
}
return t - > len - count ;
}
2006-04-03 01:06:35 +04:00
int spi_bitbang_setup_transfer ( struct spi_device * spi , struct spi_transfer * t )
2006-02-17 21:02:18 +03:00
{
struct spi_bitbang_cs * cs = spi - > controller_state ;
u8 bits_per_word ;
u32 hz ;
if ( t ) {
bits_per_word = t - > bits_per_word ;
hz = t - > speed_hz ;
} else {
bits_per_word = 0 ;
hz = 0 ;
}
/* spi_transfer level calls that work per-word */
if ( ! bits_per_word )
bits_per_word = spi - > bits_per_word ;
if ( bits_per_word < = 8 )
cs - > txrx_bufs = bitbang_txrx_8 ;
else if ( bits_per_word < = 16 )
cs - > txrx_bufs = bitbang_txrx_16 ;
else if ( bits_per_word < = 32 )
cs - > txrx_bufs = bitbang_txrx_32 ;
else
return - EINVAL ;
/* nsecs = (clock period)/2 */
if ( ! hz )
hz = spi - > max_speed_hz ;
2006-04-07 09:25:56 +04:00
if ( hz ) {
cs - > nsecs = ( 1000000000 / 2 ) / hz ;
if ( cs - > nsecs > ( MAX_UDELAY_MS * 1000 * 1000 ) )
return - EINVAL ;
}
2006-02-17 21:02:18 +03:00
return 0 ;
}
2006-04-03 01:06:35 +04:00
EXPORT_SYMBOL_GPL ( spi_bitbang_setup_transfer ) ;
2006-02-17 21:02:18 +03:00
2006-01-09 00:34:26 +03:00
/**
* spi_bitbang_setup - default setup for per - word I / O loops
*/
int spi_bitbang_setup ( struct spi_device * spi )
{
struct spi_bitbang_cs * cs = spi - > controller_state ;
struct spi_bitbang * bitbang ;
2006-02-17 21:02:18 +03:00
int retval ;
2008-01-09 02:32:40 +03:00
unsigned long flags ;
2006-01-09 00:34:26 +03:00
2006-04-04 02:46:22 +04:00
bitbang = spi_master_get_devdata ( spi - > master ) ;
2006-01-09 00:34:26 +03:00
if ( ! cs ) {
2006-12-07 07:33:17 +03:00
cs = kzalloc ( sizeof * cs , GFP_KERNEL ) ;
2006-01-09 00:34:26 +03:00
if ( ! cs )
return - ENOMEM ;
spi - > controller_state = cs ;
}
/* per-word shift register access, in hardware or bitbanging */
cs - > txrx_word = bitbang - > txrx_word [ spi - > mode & ( SPI_CPOL | SPI_CPHA ) ] ;
if ( ! cs - > txrx_word )
return - EINVAL ;
2007-02-12 11:52:44 +03:00
retval = bitbang - > setup_transfer ( spi , NULL ) ;
2006-02-17 21:02:18 +03:00
if ( retval < 0 )
return retval ;
2006-01-09 00:34:26 +03:00
2009-06-18 03:26:03 +04:00
dev_dbg ( & spi - > dev , " %s, %u nsec/bit \n " , __func__ , 2 * cs - > nsecs ) ;
2006-01-09 00:34:26 +03:00
/* NOTE we _need_ to call chipselect() early, ideally with adapter
* setup , unless the hardware defaults cooperate to avoid confusion
* between normal ( active low ) and inverted chipselects .
*/
/* deselect chip (low or high) */
2008-01-09 02:32:40 +03:00
spin_lock_irqsave ( & bitbang - > lock , flags ) ;
2006-01-09 00:34:26 +03:00
if ( ! bitbang - > busy ) {
2006-01-09 00:34:28 +03:00
bitbang - > chipselect ( spi , BITBANG_CS_INACTIVE ) ;
2006-01-09 00:34:26 +03:00
ndelay ( cs - > nsecs ) ;
}
2008-01-09 02:32:40 +03:00
spin_unlock_irqrestore ( & bitbang - > lock , flags ) ;
2006-01-09 00:34:26 +03:00
return 0 ;
}
EXPORT_SYMBOL_GPL ( spi_bitbang_setup ) ;
/**
* spi_bitbang_cleanup - default cleanup for per - word I / O loops
*/
2007-02-12 11:52:45 +03:00
void spi_bitbang_cleanup ( struct spi_device * spi )
2006-01-09 00:34:26 +03:00
{
kfree ( spi - > controller_state ) ;
}
EXPORT_SYMBOL_GPL ( spi_bitbang_cleanup ) ;
static int spi_bitbang_bufs ( struct spi_device * spi , struct spi_transfer * t )
{
struct spi_bitbang_cs * cs = spi - > controller_state ;
unsigned nsecs = cs - > nsecs ;
return cs - > txrx_bufs ( spi , cs - > txrx_word , nsecs , t ) ;
}
/*----------------------------------------------------------------------*/
/*
* SECOND PART . . . simple transfer queue runner .
*
* This costs a task context per controller , running the queue by
* performing each transfer in sequence . Smarter hardware can queue
* several DMA transfers at once , and process several controller queues
* in parallel ; this driver doesn ' t match such hardware very well .
*
* Drivers can provide word - at - a - time i / o primitives , or provide
* transfer - at - a - time ones to leverage dma or fifo hardware .
*/
2006-11-22 17:57:56 +03:00
static void bitbang_work ( struct work_struct * work )
2006-01-09 00:34:26 +03:00
{
2006-11-22 17:57:56 +03:00
struct spi_bitbang * bitbang =
container_of ( work , struct spi_bitbang , work ) ;
2006-01-09 00:34:26 +03:00
unsigned long flags ;
2009-06-30 22:41:30 +04:00
int do_setup = - 1 ;
int ( * setup_transfer ) ( struct spi_device * ,
struct spi_transfer * ) ;
setup_transfer = bitbang - > setup_transfer ;
2006-01-09 00:34:26 +03:00
spin_lock_irqsave ( & bitbang - > lock , flags ) ;
bitbang - > busy = 1 ;
while ( ! list_empty ( & bitbang - > queue ) ) {
struct spi_message * m ;
struct spi_device * spi ;
unsigned nsecs ;
2006-01-09 00:34:28 +03:00
struct spi_transfer * t = NULL ;
2006-01-09 00:34:26 +03:00
unsigned tmp ;
2006-01-09 00:34:28 +03:00
unsigned cs_change ;
2006-01-09 00:34:26 +03:00
int status ;
m = container_of ( bitbang - > queue . next , struct spi_message ,
queue ) ;
list_del_init ( & m - > queue ) ;
spin_unlock_irqrestore ( & bitbang - > lock , flags ) ;
2006-01-09 00:34:28 +03:00
/* FIXME this is made-up ... the correct value is known to
* word - at - a - time bitbang code , and presumably chipselect ( )
* should enforce these requirements too ?
*/
nsecs = 100 ;
2006-01-09 00:34:26 +03:00
spi = m - > spi ;
tmp = 0 ;
2006-01-09 00:34:28 +03:00
cs_change = 1 ;
2006-01-09 00:34:26 +03:00
status = 0 ;
2006-01-09 00:34:28 +03:00
list_for_each_entry ( t , & m - > transfers , transfer_list ) {
2006-01-09 00:34:26 +03:00
2009-06-30 22:41:30 +04:00
/* override speed or wordsize? */
if ( t - > speed_hz | | t - > bits_per_word )
do_setup = 1 ;
/* init (-1) or override (1) transfer params */
if ( do_setup ! = 0 ) {
2006-02-17 21:02:18 +03:00
if ( ! setup_transfer ) {
status = - ENOPROTOOPT ;
break ;
}
status = setup_transfer ( spi , t ) ;
if ( status < 0 )
break ;
}
2006-01-09 00:34:28 +03:00
/* set up default clock polarity, and activate chip;
* this implicitly updates clock and spi modes as
* previously recorded for this device via setup ( ) .
* ( and also deselects any other chip that might be
* selected . . . )
*/
if ( cs_change ) {
bitbang - > chipselect ( spi , BITBANG_CS_ACTIVE ) ;
2006-01-09 00:34:26 +03:00
ndelay ( nsecs ) ;
}
2006-01-09 00:34:28 +03:00
cs_change = t - > cs_change ;
2006-01-09 00:34:26 +03:00
if ( ! t - > tx_buf & & ! t - > rx_buf & & t - > len ) {
status = - EINVAL ;
break ;
}
2006-01-09 00:34:28 +03:00
/* transfer data. the lower level code handles any
* new dma mappings it needs . our caller always gave
* us dma - safe buffers .
*/
2006-01-09 00:34:26 +03:00
if ( t - > len ) {
2006-01-09 00:34:28 +03:00
/* REVISIT dma API still needs a designated
* DMA_ADDR_INVALID ; ~ 0 might be better .
2006-01-09 00:34:26 +03:00
*/
2006-01-09 00:34:28 +03:00
if ( ! m - > is_dma_mapped )
t - > rx_dma = t - > tx_dma = 0 ;
2006-01-09 00:34:26 +03:00
status = bitbang - > txrx_bufs ( spi , t ) ;
}
2008-03-13 22:32:39 +03:00
if ( status > 0 )
m - > actual_length + = status ;
2006-01-09 00:34:26 +03:00
if ( status ! = t - > len ) {
2008-03-13 22:32:39 +03:00
/* always report some kind of error */
if ( status > = 0 )
status = - EREMOTEIO ;
2006-01-09 00:34:26 +03:00
break ;
}
status = 0 ;
/* protocol tweaks before next transfer */
if ( t - > delay_usecs )
udelay ( t - > delay_usecs ) ;
2006-01-09 00:34:28 +03:00
if ( ! cs_change )
2006-01-09 00:34:26 +03:00
continue ;
2006-01-09 00:34:28 +03:00
if ( t - > transfer_list . next = = & m - > transfers )
break ;
2006-01-09 00:34:26 +03:00
2006-01-09 00:34:28 +03:00
/* sometimes a short mid-message deselect of the chip
* may be needed to terminate a mode or command
*/
ndelay ( nsecs ) ;
bitbang - > chipselect ( spi , BITBANG_CS_INACTIVE ) ;
ndelay ( nsecs ) ;
2006-01-09 00:34:26 +03:00
}
m - > status = status ;
m - > complete ( m - > context ) ;
2009-06-30 22:41:30 +04:00
/* restore speed and wordsize if it was overridden */
if ( do_setup = = 1 )
2006-02-17 21:02:18 +03:00
setup_transfer ( spi , NULL ) ;
2009-06-30 22:41:30 +04:00
do_setup = 0 ;
2006-02-17 21:02:18 +03:00
2006-01-09 00:34:28 +03:00
/* normally deactivate chipselect ... unless no error and
* cs_change has hinted that the next message will probably
* be for this chip too .
*/
if ( ! ( status = = 0 & & cs_change ) ) {
ndelay ( nsecs ) ;
bitbang - > chipselect ( spi , BITBANG_CS_INACTIVE ) ;
ndelay ( nsecs ) ;
}
2006-01-09 00:34:26 +03:00
spin_lock_irqsave ( & bitbang - > lock , flags ) ;
}
bitbang - > busy = 0 ;
spin_unlock_irqrestore ( & bitbang - > lock , flags ) ;
}
/**
* spi_bitbang_transfer - default submit to transfer queue
*/
int spi_bitbang_transfer ( struct spi_device * spi , struct spi_message * m )
{
struct spi_bitbang * bitbang ;
unsigned long flags ;
2006-04-07 09:25:56 +04:00
int status = 0 ;
2006-01-09 00:34:26 +03:00
m - > actual_length = 0 ;
m - > status = - EINPROGRESS ;
bitbang = spi_master_get_devdata ( spi - > master ) ;
spin_lock_irqsave ( & bitbang - > lock , flags ) ;
2006-04-07 09:25:56 +04:00
if ( ! spi - > max_speed_hz )
status = - ENETDOWN ;
else {
list_add_tail ( & m - > queue , & bitbang - > queue ) ;
queue_work ( bitbang - > workqueue , & bitbang - > work ) ;
}
2006-01-09 00:34:26 +03:00
spin_unlock_irqrestore ( & bitbang - > lock , flags ) ;
2006-04-07 09:25:56 +04:00
return status ;
2006-01-09 00:34:26 +03:00
}
EXPORT_SYMBOL_GPL ( spi_bitbang_transfer ) ;
/*----------------------------------------------------------------------*/
/**
* spi_bitbang_start - start up a polled / bitbanging SPI master driver
* @ bitbang : driver handle
*
* Caller should have zero - initialized all parts of the structure , and then
* provided callbacks for chip selection and I / O loops . If the master has
* a transfer method , its final step should call spi_bitbang_transfer ; or ,
* that ' s the default if the transfer routine is not initialized . It should
* also set up the bus number and number of chipselects .
*
* For i / o loops , provide callbacks either per - word ( for bitbanging , or for
* hardware that basically exposes a shift register ) or per - spi_transfer
* ( which takes better advantage of hardware like fifos or DMA engines ) .
*
2007-02-12 11:52:44 +03:00
* Drivers using per - word I / O loops should use ( or call ) spi_bitbang_setup ,
* spi_bitbang_cleanup and spi_bitbang_setup_transfer to handle those spi
* master methods . Those methods are the defaults if the bitbang - > txrx_bufs
* routine isn ' t initialized .
2006-01-09 00:34:26 +03:00
*
* This routine registers the spi_master , which will process requests in a
* dedicated task , keeping IRQs unblocked most of the time . To stop
* processing those requests , call spi_bitbang_stop ( ) .
*/
int spi_bitbang_start ( struct spi_bitbang * bitbang )
{
int status ;
if ( ! bitbang - > master | | ! bitbang - > chipselect )
return - EINVAL ;
2006-11-22 17:57:56 +03:00
INIT_WORK ( & bitbang - > work , bitbang_work ) ;
2006-01-09 00:34:26 +03:00
spin_lock_init ( & bitbang - > lock ) ;
INIT_LIST_HEAD ( & bitbang - > queue ) ;
2009-06-18 03:26:04 +04:00
if ( ! bitbang - > master - > mode_bits )
bitbang - > master - > mode_bits = SPI_CPOL | SPI_CPHA | bitbang - > flags ;
2006-01-09 00:34:26 +03:00
if ( ! bitbang - > master - > transfer )
bitbang - > master - > transfer = spi_bitbang_transfer ;
if ( ! bitbang - > txrx_bufs ) {
bitbang - > use_dma = 0 ;
bitbang - > txrx_bufs = spi_bitbang_bufs ;
if ( ! bitbang - > master - > setup ) {
2006-04-03 01:06:35 +04:00
if ( ! bitbang - > setup_transfer )
bitbang - > setup_transfer =
spi_bitbang_setup_transfer ;
2006-01-09 00:34:26 +03:00
bitbang - > master - > setup = spi_bitbang_setup ;
bitbang - > master - > cleanup = spi_bitbang_cleanup ;
}
} else if ( ! bitbang - > master - > setup )
return - EINVAL ;
/* this task is the only thing to touch the SPI bits */
bitbang - > busy = 0 ;
bitbang - > workqueue = create_singlethread_workqueue (
2009-01-06 21:44:37 +03:00
dev_name ( bitbang - > master - > dev . parent ) ) ;
2006-01-09 00:34:26 +03:00
if ( bitbang - > workqueue = = NULL ) {
status = - EBUSY ;
goto err1 ;
}
/* driver may get busy before register() returns, especially
* if someone registered boardinfo for devices
*/
status = spi_register_master ( bitbang - > master ) ;
if ( status < 0 )
goto err2 ;
return status ;
err2 :
destroy_workqueue ( bitbang - > workqueue ) ;
err1 :
return status ;
}
EXPORT_SYMBOL_GPL ( spi_bitbang_start ) ;
/**
* spi_bitbang_stop - stops the task providing spi communication
*/
int spi_bitbang_stop ( struct spi_bitbang * bitbang )
{
2007-03-17 00:38:13 +03:00
spi_unregister_master ( bitbang - > master ) ;
2006-01-09 00:34:26 +03:00
2007-03-17 00:38:13 +03:00
WARN_ON ( ! list_empty ( & bitbang - > queue ) ) ;
2006-01-09 00:34:26 +03:00
destroy_workqueue ( bitbang - > workqueue ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( spi_bitbang_stop ) ;
MODULE_LICENSE ( " GPL " ) ;