2009-01-07 01:41:41 +03:00
/*
2011-06-06 11:16:30 +04:00
* SPI master driver using generic bitbanged GPIO
2009-01-07 01:41:41 +03:00
*
* Copyright ( C ) 2006 , 2008 David Brownell
*
* 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 .
*/
# include <linux/kernel.h>
2011-07-03 23:44:29 +04:00
# include <linux/module.h>
2009-01-07 01:41:41 +03:00
# include <linux/platform_device.h>
# include <linux/gpio.h>
2013-10-11 15:51:53 +04:00
# include <linux/of.h>
2012-09-05 13:04:36 +04:00
# include <linux/of_device.h>
# include <linux/of_gpio.h>
2009-01-07 01:41:41 +03:00
# include <linux/spi/spi.h>
# include <linux/spi/spi_bitbang.h>
# include <linux/spi/spi_gpio.h>
/*
* This bitbanging SPI master driver should help make systems usable
* when a native hardware SPI engine is not available , perhaps because
* its driver isn ' t yet working or because the I / O pins it requires
* are used for other purposes .
*
* platform_device - > driver_data . . . points to spi_gpio
*
* spi - > controller_state . . . reserved for bitbang framework code
* spi - > controller_data . . . holds chipselect GPIO
*
* spi - > master - > dev . driver_data . . . points to spi_gpio - > bitbang
*/
struct spi_gpio {
struct spi_bitbang bitbang ;
struct spi_gpio_platform_data pdata ;
struct platform_device * pdev ;
2014-11-07 20:11:58 +03:00
unsigned long cs_gpios [ 0 ] ;
2009-01-07 01:41:41 +03:00
} ;
/*----------------------------------------------------------------------*/
/*
* Because the overhead of going through four GPIO procedure calls
* per transferred bit can make performance a problem , this code
* is set up so that you can use it in either of two ways :
*
* - The slow generic way : set up platform_data to hold the GPIO
* numbers used for MISO / MOSI / SCK , and issue procedure calls for
* each of them . This driver can handle several such busses .
*
* - The quicker inlined way : only helps with platform GPIO code
* that inlines operations for constant GPIOs . This can give
* you tight ( fast ! ) inner loops , but each such bus needs a
* new driver . You ' ll define a new C file , with Makefile and
* Kconfig support ; the C code can be a total of six lines :
*
* # define DRIVER_NAME " myboard_spi2 "
* # define SPI_MISO_GPIO 119
* # define SPI_MOSI_GPIO 120
* # define SPI_SCK_GPIO 121
* # define SPI_N_CHIPSEL 4
2011-06-06 11:16:30 +04:00
* # include " spi-gpio.c "
2009-01-07 01:41:41 +03:00
*/
# ifndef DRIVER_NAME
# define DRIVER_NAME "spi_gpio"
# define GENERIC_BITBANG /* vs tight inlines */
/* all functions referencing these symbols must define pdata */
# define SPI_MISO_GPIO ((pdata)->miso)
# define SPI_MOSI_GPIO ((pdata)->mosi)
# define SPI_SCK_GPIO ((pdata)->sck)
# define SPI_N_CHIPSEL ((pdata)->num_chipselect)
# endif
/*----------------------------------------------------------------------*/
2015-01-05 15:01:03 +03:00
static inline struct spi_gpio * __pure
2012-09-05 13:04:35 +04:00
spi_to_spi_gpio ( const struct spi_device * spi )
2009-01-07 01:41:41 +03:00
{
const struct spi_bitbang * bang ;
2012-09-05 13:04:35 +04:00
struct spi_gpio * spi_gpio ;
2009-01-07 01:41:41 +03:00
bang = spi_master_get_devdata ( spi - > master ) ;
spi_gpio = container_of ( bang , struct spi_gpio , bitbang ) ;
2012-09-05 13:04:35 +04:00
return spi_gpio ;
}
2015-01-05 15:01:03 +03:00
static inline struct spi_gpio_platform_data * __pure
2012-09-05 13:04:35 +04:00
spi_to_pdata ( const struct spi_device * spi )
{
return & spi_to_spi_gpio ( spi ) - > pdata ;
2009-01-07 01:41:41 +03:00
}
/* this is #defined to avoid unused-variable warnings when inlining */
# define pdata spi_to_pdata(spi)
static inline void setsck ( const struct spi_device * spi , int is_on )
{
2013-11-24 16:37:01 +04:00
gpio_set_value_cansleep ( SPI_SCK_GPIO , is_on ) ;
2009-01-07 01:41:41 +03:00
}
static inline void setmosi ( const struct spi_device * spi , int is_on )
{
2013-11-24 16:37:01 +04:00
gpio_set_value_cansleep ( SPI_MOSI_GPIO , is_on ) ;
2009-01-07 01:41:41 +03:00
}
static inline int getmiso ( const struct spi_device * spi )
{
2013-11-24 16:37:01 +04:00
return ! ! gpio_get_value_cansleep ( SPI_MISO_GPIO ) ;
2009-01-07 01:41:41 +03:00
}
# undef pdata
/*
* NOTE : this clocks " as fast as we can " . It " should " be a function of the
* requested device clock . Software overhead means we usually have trouble
* reaching even one Mbit / sec ( except when we can inline bitops ) , so for now
* we ' ll just assume we never need additional per - bit slowdowns .
*/
# define spidelay(nsecs) do {} while (0)
2011-06-06 11:16:30 +04:00
# include "spi-bitbang-txrx.h"
2009-01-07 01:41:41 +03:00
/*
* These functions can leverage inline expansion of GPIO calls to shrink
* costs for a txrx bit , often by factors of around ten ( by instruction
* count ) . That is particularly visible for larger word sizes , but helps
* even with default 8 - bit words .
*
* REVISIT overheads calling these functions for each word also have
* significant performance costs . Having txrx_bufs ( ) calls that inline
* the txrx_word ( ) logic would help performance , e . g . on larger blocks
* used with flash storage or MMC / SD . There should also be ways to make
* GCC be less stupid about reloading registers inside the I / O loops ,
* even without inlined GPIO calls ; __attribute__ ( ( hot ) ) on GCC 4.3 ?
*/
static u32 spi_gpio_txrx_word_mode0 ( struct spi_device * spi ,
unsigned nsecs , u32 word , u8 bits )
{
2010-07-01 00:27:32 +04:00
return bitbang_txrx_be_cpha0 ( spi , nsecs , 0 , 0 , word , bits ) ;
2009-01-07 01:41:41 +03:00
}
static u32 spi_gpio_txrx_word_mode1 ( struct spi_device * spi ,
unsigned nsecs , u32 word , u8 bits )
{
2010-07-01 00:27:32 +04:00
return bitbang_txrx_be_cpha1 ( spi , nsecs , 0 , 0 , word , bits ) ;
2009-01-07 01:41:41 +03:00
}
static u32 spi_gpio_txrx_word_mode2 ( struct spi_device * spi ,
unsigned nsecs , u32 word , u8 bits )
{
2010-07-01 00:27:32 +04:00
return bitbang_txrx_be_cpha0 ( spi , nsecs , 1 , 0 , word , bits ) ;
2009-01-07 01:41:41 +03:00
}
static u32 spi_gpio_txrx_word_mode3 ( struct spi_device * spi ,
unsigned nsecs , u32 word , u8 bits )
{
2010-07-01 00:27:32 +04:00
return bitbang_txrx_be_cpha1 ( spi , nsecs , 1 , 0 , word , bits ) ;
2009-01-07 01:41:41 +03:00
}
2010-07-01 00:27:37 +04:00
/*
* These functions do not call setmosi or getmiso if respective flag
* ( SPI_MASTER_NO_RX or SPI_MASTER_NO_TX ) is set , so they are safe to
* call when such pin is not present or defined in the controller .
* A separate set of callbacks is defined to get highest possible
* speed in the generic case ( when both MISO and MOSI lines are
* available ) , as optimiser will remove the checks when argument is
* constant .
*/
static u32 spi_gpio_spec_txrx_word_mode0 ( struct spi_device * spi ,
unsigned nsecs , u32 word , u8 bits )
{
unsigned flags = spi - > master - > flags ;
return bitbang_txrx_be_cpha0 ( spi , nsecs , 0 , flags , word , bits ) ;
}
static u32 spi_gpio_spec_txrx_word_mode1 ( struct spi_device * spi ,
unsigned nsecs , u32 word , u8 bits )
{
unsigned flags = spi - > master - > flags ;
return bitbang_txrx_be_cpha1 ( spi , nsecs , 0 , flags , word , bits ) ;
}
static u32 spi_gpio_spec_txrx_word_mode2 ( struct spi_device * spi ,
unsigned nsecs , u32 word , u8 bits )
{
unsigned flags = spi - > master - > flags ;
return bitbang_txrx_be_cpha0 ( spi , nsecs , 1 , flags , word , bits ) ;
}
static u32 spi_gpio_spec_txrx_word_mode3 ( struct spi_device * spi ,
unsigned nsecs , u32 word , u8 bits )
{
unsigned flags = spi - > master - > flags ;
return bitbang_txrx_be_cpha1 ( spi , nsecs , 1 , flags , word , bits ) ;
}
2009-01-07 01:41:41 +03:00
/*----------------------------------------------------------------------*/
static void spi_gpio_chipselect ( struct spi_device * spi , int is_active )
{
2012-09-05 13:04:35 +04:00
struct spi_gpio * spi_gpio = spi_to_spi_gpio ( spi ) ;
2014-11-07 20:11:58 +03:00
unsigned long cs = spi_gpio - > cs_gpios [ spi - > chip_select ] ;
2009-01-07 01:41:41 +03:00
/* set initial clock polarity */
if ( is_active )
setsck ( spi , spi - > mode & SPI_CPOL ) ;
2009-04-03 03:57:07 +04:00
if ( cs ! = SPI_GPIO_NO_CHIPSELECT ) {
/* SPI is normally active-low */
2013-11-24 16:37:01 +04:00
gpio_set_value_cansleep ( cs , ( spi - > mode & SPI_CS_HIGH ) ? is_active : ! is_active ) ;
2009-04-03 03:57:07 +04:00
}
2009-01-07 01:41:41 +03:00
}
static int spi_gpio_setup ( struct spi_device * spi )
{
2014-11-07 20:11:58 +03:00
unsigned long cs ;
2012-09-05 13:04:35 +04:00
int status = 0 ;
struct spi_gpio * spi_gpio = spi_to_spi_gpio ( spi ) ;
2012-09-05 13:04:36 +04:00
struct device_node * np = spi - > master - > dev . of_node ;
2009-01-07 01:41:41 +03:00
2012-09-05 13:04:36 +04:00
if ( np ) {
/*
* In DT environments , the CS GPIOs have already been
* initialized from the " cs-gpios " property of the node .
*/
cs = spi_gpio - > cs_gpios [ spi - > chip_select ] ;
} else {
/*
* . . . otherwise , take it from spi - > controller_data
*/
2014-11-07 20:11:58 +03:00
cs = ( uintptr_t ) spi - > controller_data ;
2012-09-05 13:04:36 +04:00
}
2009-01-07 01:41:41 +03:00
if ( ! spi - > controller_state ) {
2009-04-03 03:57:07 +04:00
if ( cs ! = SPI_GPIO_NO_CHIPSELECT ) {
status = gpio_request ( cs , dev_name ( & spi - > dev ) ) ;
if ( status )
return status ;
2012-02-10 01:21:45 +04:00
status = gpio_direction_output ( cs ,
! ( spi - > mode & SPI_CS_HIGH ) ) ;
2009-04-03 03:57:07 +04:00
}
2009-01-07 01:41:41 +03:00
}
2012-09-05 13:04:35 +04:00
if ( ! status ) {
2012-09-05 13:04:36 +04:00
/* in case it was initialized from static board data */
2012-09-05 13:04:35 +04:00
spi_gpio - > cs_gpios [ spi - > chip_select ] = cs ;
2013-04-09 21:25:34 +04:00
status = spi_bitbang_setup ( spi ) ;
2012-09-05 13:04:35 +04:00
}
2009-01-07 01:41:41 +03:00
if ( status ) {
2009-04-03 03:57:07 +04:00
if ( ! spi - > controller_state & & cs ! = SPI_GPIO_NO_CHIPSELECT )
2009-01-07 01:41:41 +03:00
gpio_free ( cs ) ;
}
return status ;
}
static void spi_gpio_cleanup ( struct spi_device * spi )
{
2012-09-05 13:04:35 +04:00
struct spi_gpio * spi_gpio = spi_to_spi_gpio ( spi ) ;
2014-11-07 20:11:58 +03:00
unsigned long cs = spi_gpio - > cs_gpios [ spi - > chip_select ] ;
2009-01-07 01:41:41 +03:00
2009-04-03 03:57:07 +04:00
if ( cs ! = SPI_GPIO_NO_CHIPSELECT )
gpio_free ( cs ) ;
2009-01-07 01:41:41 +03:00
spi_bitbang_cleanup ( spi ) ;
}
2012-12-07 20:57:14 +04:00
static int spi_gpio_alloc ( unsigned pin , const char * label , bool is_in )
2009-01-07 01:41:41 +03:00
{
int value ;
value = gpio_request ( pin , label ) ;
if ( value = = 0 ) {
if ( is_in )
value = gpio_direction_input ( pin ) ;
else
value = gpio_direction_output ( pin , 0 ) ;
}
return value ;
}
2012-12-07 20:57:14 +04:00
static int spi_gpio_request ( struct spi_gpio_platform_data * pdata ,
const char * label , u16 * res_flags )
2009-01-07 01:41:41 +03:00
{
int value ;
/* NOTE: SPI_*_GPIO symbols may reference "pdata" */
2010-07-01 00:27:37 +04:00
if ( SPI_MOSI_GPIO ! = SPI_GPIO_NO_MOSI ) {
value = spi_gpio_alloc ( SPI_MOSI_GPIO , label , false ) ;
if ( value )
goto done ;
} else {
/* HW configuration without MOSI pin */
* res_flags | = SPI_MASTER_NO_TX ;
}
2009-01-07 01:41:41 +03:00
2010-07-01 00:27:37 +04:00
if ( SPI_MISO_GPIO ! = SPI_GPIO_NO_MISO ) {
value = spi_gpio_alloc ( SPI_MISO_GPIO , label , true ) ;
if ( value )
goto free_mosi ;
} else {
/* HW configuration without MISO pin */
* res_flags | = SPI_MASTER_NO_RX ;
}
2009-01-07 01:41:41 +03:00
value = spi_gpio_alloc ( SPI_SCK_GPIO , label , false ) ;
if ( value )
goto free_miso ;
goto done ;
free_miso :
2010-07-01 00:27:37 +04:00
if ( SPI_MISO_GPIO ! = SPI_GPIO_NO_MISO )
gpio_free ( SPI_MISO_GPIO ) ;
2009-01-07 01:41:41 +03:00
free_mosi :
2010-07-01 00:27:37 +04:00
if ( SPI_MOSI_GPIO ! = SPI_GPIO_NO_MOSI )
gpio_free ( SPI_MOSI_GPIO ) ;
2009-01-07 01:41:41 +03:00
done :
return value ;
}
2012-09-05 13:04:36 +04:00
# ifdef CONFIG_OF
2014-05-07 11:48:59 +04:00
static const struct of_device_id spi_gpio_dt_ids [ ] = {
2012-09-05 13:04:36 +04:00
{ . compatible = " spi-gpio " } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , spi_gpio_dt_ids ) ;
static int spi_gpio_probe_dt ( struct platform_device * pdev )
{
int ret ;
u32 tmp ;
struct spi_gpio_platform_data * pdata ;
struct device_node * np = pdev - > dev . of_node ;
const struct of_device_id * of_id =
of_match_device ( spi_gpio_dt_ids , & pdev - > dev ) ;
if ( ! of_id )
return 0 ;
pdata = devm_kzalloc ( & pdev - > dev , sizeof ( * pdata ) , GFP_KERNEL ) ;
if ( ! pdata )
return - ENOMEM ;
2013-01-25 12:39:34 +04:00
ret = of_get_named_gpio ( np , " gpio-sck " , 0 ) ;
if ( ret < 0 ) {
dev_err ( & pdev - > dev , " gpio-sck property not found \n " ) ;
goto error_free ;
}
pdata - > sck = ret ;
ret = of_get_named_gpio ( np , " gpio-miso " , 0 ) ;
if ( ret < 0 ) {
dev_info ( & pdev - > dev , " gpio-miso property not found, switching to no-rx mode \n " ) ;
pdata - > miso = SPI_GPIO_NO_MISO ;
} else
pdata - > miso = ret ;
ret = of_get_named_gpio ( np , " gpio-mosi " , 0 ) ;
if ( ret < 0 ) {
dev_info ( & pdev - > dev , " gpio-mosi property not found, switching to no-tx mode \n " ) ;
pdata - > mosi = SPI_GPIO_NO_MOSI ;
} else
pdata - > mosi = ret ;
2012-09-05 13:04:36 +04:00
ret = of_property_read_u32 ( np , " num-chipselects " , & tmp ) ;
if ( ret < 0 ) {
dev_err ( & pdev - > dev , " num-chipselects property not found \n " ) ;
goto error_free ;
}
pdata - > num_chipselect = tmp ;
pdev - > dev . platform_data = pdata ;
return 1 ;
error_free :
devm_kfree ( & pdev - > dev , pdata ) ;
return ret ;
}
# else
2012-09-07 04:23:06 +04:00
static inline int spi_gpio_probe_dt ( struct platform_device * pdev )
2012-09-05 13:04:36 +04:00
{
return 0 ;
}
# endif
2012-12-07 20:57:14 +04:00
static int spi_gpio_probe ( struct platform_device * pdev )
2009-01-07 01:41:41 +03:00
{
int status ;
struct spi_master * master ;
struct spi_gpio * spi_gpio ;
struct spi_gpio_platform_data * pdata ;
2010-07-01 00:27:37 +04:00
u16 master_flags = 0 ;
2012-09-05 13:04:36 +04:00
bool use_of = 0 ;
2014-11-03 19:17:55 +03:00
int num_devices ;
2012-09-05 13:04:36 +04:00
status = spi_gpio_probe_dt ( pdev ) ;
if ( status < 0 )
return status ;
if ( status > 0 )
use_of = 1 ;
2009-01-07 01:41:41 +03:00
2013-07-30 11:58:59 +04:00
pdata = dev_get_platdata ( & pdev - > dev ) ;
2009-01-07 01:41:41 +03:00
# ifdef GENERIC_BITBANG
2014-11-03 19:17:55 +03:00
if ( ! pdata | | ( ! use_of & & ! pdata - > num_chipselect ) )
2009-01-07 01:41:41 +03:00
return - ENODEV ;
# endif
2014-11-03 19:17:55 +03:00
if ( use_of & & ! SPI_N_CHIPSEL )
num_devices = 1 ;
else
num_devices = SPI_N_CHIPSEL ;
2010-07-01 00:27:37 +04:00
status = spi_gpio_request ( pdata , dev_name ( & pdev - > dev ) , & master_flags ) ;
2009-01-07 01:41:41 +03:00
if ( status < 0 )
return status ;
2012-09-05 13:04:35 +04:00
master = spi_alloc_master ( & pdev - > dev , sizeof ( * spi_gpio ) +
2014-11-07 20:11:58 +03:00
( sizeof ( unsigned long ) * num_devices ) ) ;
2009-01-07 01:41:41 +03:00
if ( ! master ) {
status = - ENOMEM ;
goto gpio_free ;
}
spi_gpio = spi_master_get_devdata ( master ) ;
platform_set_drvdata ( pdev , spi_gpio ) ;
spi_gpio - > pdev = pdev ;
if ( pdata )
spi_gpio - > pdata = * pdata ;
2013-05-22 06:36:35 +04:00
master - > bits_per_word_mask = SPI_BPW_RANGE_MASK ( 1 , 32 ) ;
2010-07-01 00:27:37 +04:00
master - > flags = master_flags ;
2009-01-07 01:41:41 +03:00
master - > bus_num = pdev - > id ;
2014-11-03 19:17:55 +03:00
master - > num_chipselect = num_devices ;
2009-01-07 01:41:41 +03:00
master - > setup = spi_gpio_setup ;
master - > cleanup = spi_gpio_cleanup ;
2012-09-05 13:04:36 +04:00
# ifdef CONFIG_OF
master - > dev . of_node = pdev - > dev . of_node ;
if ( use_of ) {
int i ;
struct device_node * np = pdev - > dev . of_node ;
/*
* In DT environments , take the CS GPIO from the " cs-gpios "
* property of the node .
*/
2014-11-03 19:17:55 +03:00
if ( ! SPI_N_CHIPSEL )
spi_gpio - > cs_gpios [ 0 ] = SPI_GPIO_NO_CHIPSELECT ;
else
2014-11-07 20:11:58 +03:00
for ( i = 0 ; i < SPI_N_CHIPSEL ; i + + ) {
status = of_get_named_gpio ( np , " cs-gpios " , i ) ;
if ( status < 0 ) {
dev_err ( & pdev - > dev ,
" invalid cs-gpios property \n " ) ;
goto gpio_free ;
}
spi_gpio - > cs_gpios [ i ] = status ;
}
2012-09-05 13:04:36 +04:00
}
# endif
2009-01-07 01:41:41 +03:00
2013-09-10 11:43:41 +04:00
spi_gpio - > bitbang . master = master ;
2009-01-07 01:41:41 +03:00
spi_gpio - > bitbang . chipselect = spi_gpio_chipselect ;
2010-07-01 00:27:37 +04:00
2010-10-02 16:03:32 +04:00
if ( ( master_flags & ( SPI_MASTER_NO_TX | SPI_MASTER_NO_RX ) ) = = 0 ) {
2010-07-01 00:27:37 +04:00
spi_gpio - > bitbang . txrx_word [ SPI_MODE_0 ] = spi_gpio_txrx_word_mode0 ;
spi_gpio - > bitbang . txrx_word [ SPI_MODE_1 ] = spi_gpio_txrx_word_mode1 ;
spi_gpio - > bitbang . txrx_word [ SPI_MODE_2 ] = spi_gpio_txrx_word_mode2 ;
spi_gpio - > bitbang . txrx_word [ SPI_MODE_3 ] = spi_gpio_txrx_word_mode3 ;
} else {
spi_gpio - > bitbang . txrx_word [ SPI_MODE_0 ] = spi_gpio_spec_txrx_word_mode0 ;
spi_gpio - > bitbang . txrx_word [ SPI_MODE_1 ] = spi_gpio_spec_txrx_word_mode1 ;
spi_gpio - > bitbang . txrx_word [ SPI_MODE_2 ] = spi_gpio_spec_txrx_word_mode2 ;
spi_gpio - > bitbang . txrx_word [ SPI_MODE_3 ] = spi_gpio_spec_txrx_word_mode3 ;
}
2009-01-07 01:41:41 +03:00
spi_gpio - > bitbang . setup_transfer = spi_bitbang_setup_transfer ;
spi_gpio - > bitbang . flags = SPI_CS_HIGH ;
status = spi_bitbang_start ( & spi_gpio - > bitbang ) ;
if ( status < 0 ) {
gpio_free :
2010-07-01 00:27:37 +04:00
if ( SPI_MISO_GPIO ! = SPI_GPIO_NO_MISO )
gpio_free ( SPI_MISO_GPIO ) ;
if ( SPI_MOSI_GPIO ! = SPI_GPIO_NO_MOSI )
gpio_free ( SPI_MOSI_GPIO ) ;
2009-01-07 01:41:41 +03:00
gpio_free ( SPI_SCK_GPIO ) ;
spi_master_put ( master ) ;
}
return status ;
}
2012-12-07 20:57:14 +04:00
static int spi_gpio_remove ( struct platform_device * pdev )
2009-01-07 01:41:41 +03:00
{
struct spi_gpio * spi_gpio ;
struct spi_gpio_platform_data * pdata ;
spi_gpio = platform_get_drvdata ( pdev ) ;
2013-07-30 11:58:59 +04:00
pdata = dev_get_platdata ( & pdev - > dev ) ;
2009-01-07 01:41:41 +03:00
/* stop() unregisters child devices too */
2014-03-29 14:50:12 +04:00
spi_bitbang_stop ( & spi_gpio - > bitbang ) ;
2009-01-07 01:41:41 +03:00
2010-07-01 00:27:37 +04:00
if ( SPI_MISO_GPIO ! = SPI_GPIO_NO_MISO )
gpio_free ( SPI_MISO_GPIO ) ;
if ( SPI_MOSI_GPIO ! = SPI_GPIO_NO_MOSI )
gpio_free ( SPI_MOSI_GPIO ) ;
2009-01-07 01:41:41 +03:00
gpio_free ( SPI_SCK_GPIO ) ;
2013-09-10 11:43:41 +04:00
spi_master_put ( spi_gpio - > bitbang . master ) ;
2009-01-07 01:41:41 +03:00
2014-03-29 14:50:12 +04:00
return 0 ;
2009-01-07 01:41:41 +03:00
}
MODULE_ALIAS ( " platform: " DRIVER_NAME ) ;
static struct platform_driver spi_gpio_driver = {
2012-09-05 13:04:36 +04:00
. driver = {
. name = DRIVER_NAME ,
. of_match_table = of_match_ptr ( spi_gpio_dt_ids ) ,
} ,
2011-10-05 21:29:49 +04:00
. probe = spi_gpio_probe ,
2012-12-07 20:57:14 +04:00
. remove = spi_gpio_remove ,
2009-01-07 01:41:41 +03:00
} ;
2011-10-05 21:29:49 +04:00
module_platform_driver ( spi_gpio_driver ) ;
2009-01-07 01:41:41 +03:00
MODULE_DESCRIPTION ( " SPI master driver using generic bitbanged GPIO " ) ;
MODULE_AUTHOR ( " David Brownell " ) ;
MODULE_LICENSE ( " GPL " ) ;