2012-11-22 18:39:18 +04:00
/*
* Samsung LSI S5C73M3 8 M pixel camera driver
*
* Copyright ( C ) 2012 , Samsung Electronics , Co . , Ltd .
* Sylwester Nawrocki < s . nawrocki @ samsung . com >
* Andrzej Hajda < a . hajda @ samsung . com >
*
* 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 .
*
* 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/sizes.h>
# include <linux/delay.h>
# include <linux/init.h>
# include <linux/media.h>
# include <linux/module.h>
# include <linux/slab.h>
# include <linux/spi/spi.h>
# include "s5c73m3.h"
# define S5C73M3_SPI_DRV_NAME "S5C73M3-SPI"
2013-12-21 02:46:44 +04:00
static const struct of_device_id s5c73m3_spi_ids [ ] = {
{ . compatible = " samsung,s5c73m3 " } ,
{ }
} ;
2012-11-22 18:39:18 +04:00
enum spi_direction {
SPI_DIR_RX ,
SPI_DIR_TX
} ;
static int spi_xmit ( struct spi_device * spi_dev , void * addr , const int len ,
enum spi_direction dir )
{
struct spi_message msg ;
int r ;
struct spi_transfer xfer = {
. len = len ,
} ;
if ( dir = = SPI_DIR_TX )
xfer . tx_buf = addr ;
else
xfer . rx_buf = addr ;
if ( spi_dev = = NULL ) {
dev_err ( & spi_dev - > dev , " SPI device is uninitialized \n " ) ;
return - ENODEV ;
}
spi_message_init ( & msg ) ;
spi_message_add_tail ( & xfer , & msg ) ;
r = spi_sync ( spi_dev , & msg ) ;
if ( r < 0 )
dev_err ( & spi_dev - > dev , " %s spi_sync failed %d \n " , __func__ , r ) ;
return r ;
}
int s5c73m3_spi_write ( struct s5c73m3 * state , const void * addr ,
const unsigned int len , const unsigned int tx_size )
{
struct spi_device * spi_dev = state - > spi_dev ;
u32 count = len / tx_size ;
u32 extra = len % tx_size ;
unsigned int i , j = 0 ;
u8 padding [ 32 ] ;
int r = 0 ;
memset ( padding , 0 , sizeof ( padding ) ) ;
2013-04-30 12:04:09 +04:00
for ( i = 0 ; i < count ; i + + ) {
2012-11-22 18:39:18 +04:00
r = spi_xmit ( spi_dev , ( void * ) addr + j , tx_size , SPI_DIR_TX ) ;
if ( r < 0 )
return r ;
j + = tx_size ;
}
if ( extra > 0 ) {
r = spi_xmit ( spi_dev , ( void * ) addr + j , extra , SPI_DIR_TX ) ;
if ( r < 0 )
return r ;
}
return spi_xmit ( spi_dev , padding , sizeof ( padding ) , SPI_DIR_TX ) ;
}
int s5c73m3_spi_read ( struct s5c73m3 * state , void * addr ,
const unsigned int len , const unsigned int tx_size )
{
struct spi_device * spi_dev = state - > spi_dev ;
u32 count = len / tx_size ;
u32 extra = len % tx_size ;
unsigned int i , j = 0 ;
int r = 0 ;
2013-04-30 12:04:09 +04:00
for ( i = 0 ; i < count ; i + + ) {
2012-11-22 18:39:18 +04:00
r = spi_xmit ( spi_dev , addr + j , tx_size , SPI_DIR_RX ) ;
if ( r < 0 )
return r ;
j + = tx_size ;
}
if ( extra > 0 )
return spi_xmit ( spi_dev , addr + j , extra , SPI_DIR_RX ) ;
return 0 ;
}
2013-02-07 00:35:41 +04:00
static int s5c73m3_spi_probe ( struct spi_device * spi )
2012-11-22 18:39:18 +04:00
{
int r ;
struct s5c73m3 * state = container_of ( spi - > dev . driver , struct s5c73m3 ,
spidrv . driver ) ;
spi - > bits_per_word = 32 ;
r = spi_setup ( spi ) ;
if ( r < 0 ) {
dev_err ( & spi - > dev , " spi_setup() failed \n " ) ;
return r ;
}
mutex_lock ( & state - > lock ) ;
state - > spi_dev = spi ;
mutex_unlock ( & state - > lock ) ;
v4l2_info ( & state - > sensor_sd , " S5C73M3 SPI probed successfully \n " ) ;
return 0 ;
}
2013-02-07 00:35:41 +04:00
static int s5c73m3_spi_remove ( struct spi_device * spi )
2012-11-22 18:39:18 +04:00
{
return 0 ;
}
int s5c73m3_register_spi_driver ( struct s5c73m3 * state )
{
struct spi_driver * spidrv = & state - > spidrv ;
2013-02-07 00:35:41 +04:00
spidrv - > remove = s5c73m3_spi_remove ;
2012-11-22 18:39:18 +04:00
spidrv - > probe = s5c73m3_spi_probe ;
spidrv - > driver . name = S5C73M3_SPI_DRV_NAME ;
spidrv - > driver . bus = & spi_bus_type ;
spidrv - > driver . owner = THIS_MODULE ;
2013-12-21 02:46:44 +04:00
spidrv - > driver . of_match_table = s5c73m3_spi_ids ;
2012-11-22 18:39:18 +04:00
return spi_register_driver ( spidrv ) ;
}
void s5c73m3_unregister_spi_driver ( struct s5c73m3 * state )
{
spi_unregister_driver ( & state - > spidrv ) ;
}