@ -13,6 +13,7 @@
# include <linux/clk.h>
# include <linux/delay.h>
# include <linux/gpio.h>
# include <linux/interrupt.h>
# include <linux/io.h>
# include <linux/module.h>
@ -127,6 +128,10 @@ struct cdns_spi {
u32 is_decoded_cs ;
} ;
struct cdns_spi_device_data {
bool gpio_requested ;
} ;
/* Macros for the SPI controller read/write */
static inline u32 cdns_spi_read ( struct cdns_spi * xspi , u32 offset )
{
@ -456,6 +461,64 @@ static int cdns_unprepare_transfer_hardware(struct spi_master *master)
return 0 ;
}
static int cdns_spi_setup ( struct spi_device * spi )
{
int ret = - EINVAL ;
struct cdns_spi_device_data * cdns_spi_data = spi_get_ctldata ( spi ) ;
/* this is a pin managed by the controller, leave it alone */
if ( spi - > cs_gpio = = - ENOENT )
return 0 ;
/* this seems to be the first time we're here */
if ( ! cdns_spi_data ) {
cdns_spi_data = kzalloc ( sizeof ( * cdns_spi_data ) , GFP_KERNEL ) ;
if ( ! cdns_spi_data )
return - ENOMEM ;
cdns_spi_data - > gpio_requested = false ;
spi_set_ctldata ( spi , cdns_spi_data ) ;
}
/* if we haven't done so, grab the gpio */
if ( ! cdns_spi_data - > gpio_requested & & gpio_is_valid ( spi - > cs_gpio ) ) {
ret = gpio_request_one ( spi - > cs_gpio ,
( spi - > mode & SPI_CS_HIGH ) ?
GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH ,
dev_name ( & spi - > dev ) ) ;
if ( ret )
dev_err ( & spi - > dev , " can't request chipselect gpio %d \n " ,
spi - > cs_gpio ) ;
else
cdns_spi_data - > gpio_requested = true ;
} else {
if ( gpio_is_valid ( spi - > cs_gpio ) ) {
int mode = ( ( spi - > mode & SPI_CS_HIGH ) ?
GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH ) ;
ret = gpio_direction_output ( spi - > cs_gpio , mode ) ;
if ( ret )
dev_err ( & spi - > dev , " chipselect gpio %d setup failed (%d) \n " ,
spi - > cs_gpio , ret ) ;
}
}
return ret ;
}
static void cdns_spi_cleanup ( struct spi_device * spi )
{
struct cdns_spi_device_data * cdns_spi_data = spi_get_ctldata ( spi ) ;
if ( cdns_spi_data ) {
if ( cdns_spi_data - > gpio_requested )
gpio_free ( spi - > cs_gpio ) ;
kfree ( cdns_spi_data ) ;
spi_set_ctldata ( spi , NULL ) ;
}
}
/**
* cdns_spi_probe - Probe method for the SPI driver
* @ pdev : Pointer to the platform_device structure
@ -555,6 +618,8 @@ static int cdns_spi_probe(struct platform_device *pdev)
master - > transfer_one = cdns_transfer_one ;
master - > unprepare_transfer_hardware = cdns_unprepare_transfer_hardware ;
master - > set_cs = cdns_spi_chipselect ;
master - > setup = cdns_spi_setup ;
master - > cleanup = cdns_spi_cleanup ;
master - > auto_runtime_pm = true ;
master - > mode_bits = SPI_CPOL | SPI_CPHA ;