2010-05-19 11:39:02 +02:00
/*
* Copyright ( C ) ST - Ericsson SA 2010
*
* License Terms : GNU General Public License v2
* Author : Srinidhi Kasagar < srinidhi . kasagar @ stericsson . com >
*/
# include <linux/kernel.h>
# include <linux/slab.h>
# include <linux/init.h>
# include <linux/module.h>
# include <linux/platform_device.h>
# include <linux/spi/spi.h>
# include <linux/mfd/ab8500.h>
/*
* This funtion writes to any AB8500 registers using
* SPI protocol & before it writes it packs the data
* in the below 24 bit frame format
*
* * | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
* * | 23 | 22. . .18 | 17. . . . . . .10 | 9 | 8 | 7. . . . . .0 |
* * | r / w bank adr data |
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*
* This function shouldn ' t be called from interrupt
* context
*/
static int ab8500_spi_write ( struct ab8500 * ab8500 , u16 addr , u8 data )
{
struct spi_device * spi = container_of ( ab8500 - > dev , struct spi_device ,
dev ) ;
unsigned long spi_data = addr < < 10 | data ;
struct spi_transfer xfer ;
struct spi_message msg ;
ab8500 - > tx_buf [ 0 ] = spi_data ;
ab8500 - > rx_buf [ 0 ] = 0 ;
xfer . tx_buf = ab8500 - > tx_buf ;
xfer . rx_buf = NULL ;
xfer . len = sizeof ( unsigned long ) ;
spi_message_init ( & msg ) ;
spi_message_add_tail ( & xfer , & msg ) ;
return spi_sync ( spi , & msg ) ;
}
static int ab8500_spi_read ( struct ab8500 * ab8500 , u16 addr )
{
struct spi_device * spi = container_of ( ab8500 - > dev , struct spi_device ,
dev ) ;
unsigned long spi_data = 1 < < 23 | addr < < 10 ;
struct spi_transfer xfer ;
struct spi_message msg ;
int ret ;
ab8500 - > tx_buf [ 0 ] = spi_data ;
ab8500 - > rx_buf [ 0 ] = 0 ;
xfer . tx_buf = ab8500 - > tx_buf ;
xfer . rx_buf = ab8500 - > rx_buf ;
xfer . len = sizeof ( unsigned long ) ;
spi_message_init ( & msg ) ;
spi_message_add_tail ( & xfer , & msg ) ;
ret = spi_sync ( spi , & msg ) ;
if ( ! ret )
2010-05-28 02:59:44 +02:00
/*
* Only the 8 lowermost bytes are
* defined with value , the rest may
* vary depending on chip / board noise .
*/
ret = ab8500 - > rx_buf [ 0 ] & 0xFFU ;
2010-05-19 11:39:02 +02:00
return ret ;
}
static int __devinit ab8500_spi_probe ( struct spi_device * spi )
{
struct ab8500 * ab8500 ;
int ret ;
2010-09-16 06:18:50 -07:00
spi - > bits_per_word = 24 ;
ret = spi_setup ( spi ) ;
if ( ret < 0 )
return ret ;
2010-05-19 11:39:02 +02:00
ab8500 = kzalloc ( sizeof * ab8500 , GFP_KERNEL ) ;
if ( ! ab8500 )
return - ENOMEM ;
ab8500 - > dev = & spi - > dev ;
ab8500 - > irq = spi - > irq ;
ab8500 - > read = ab8500_spi_read ;
ab8500 - > write = ab8500_spi_write ;
spi_set_drvdata ( spi , ab8500 ) ;
ret = ab8500_init ( ab8500 ) ;
if ( ret )
kfree ( ab8500 ) ;
return ret ;
}
static int __devexit ab8500_spi_remove ( struct spi_device * spi )
{
struct ab8500 * ab8500 = spi_get_drvdata ( spi ) ;
ab8500_exit ( ab8500 ) ;
kfree ( ab8500 ) ;
return 0 ;
}
static struct spi_driver ab8500_spi_driver = {
. driver = {
. name = " ab8500 " ,
. owner = THIS_MODULE ,
} ,
. probe = ab8500_spi_probe ,
. remove = __devexit_p ( ab8500_spi_remove )
} ;
static int __init ab8500_spi_init ( void )
{
return spi_register_driver ( & ab8500_spi_driver ) ;
}
subsys_initcall ( ab8500_spi_init ) ;
static void __exit ab8500_spi_exit ( void )
{
spi_unregister_driver ( & ab8500_spi_driver ) ;
}
module_exit ( ab8500_spi_exit ) ;
MODULE_AUTHOR ( " Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com " ) ;
MODULE_DESCRIPTION ( " AB8500 SPI " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;