2010-05-11 02:25:29 +04:00
/*
* Copyright ( C ) 2007 - 2010 ST - Ericsson
* License terms : GNU General Public License ( GPL ) version 2
* Low - level core for exclusive access to the AB3550 IC on the I2C bus
* and some basic chip - configuration .
* Author : Bengt Jonsson < bengt . g . jonsson @ stericsson . com >
* Author : Mattias Nilsson < mattias . i . nilsson @ stericsson . com >
* Author : Mattias Wallin < mattias . wallin @ stericsson . com >
* Author : Rickard Andersson < rickard . andersson @ stericsson . com >
*/
# include <linux/i2c.h>
# include <linux/mutex.h>
# include <linux/err.h>
# include <linux/platform_device.h>
# include <linux/slab.h>
# include <linux/device.h>
# include <linux/irq.h>
# include <linux/interrupt.h>
# include <linux/random.h>
# include <linux/workqueue.h>
# include <linux/debugfs.h>
# include <linux/seq_file.h>
# include <linux/uaccess.h>
# include <linux/mfd/abx500.h>
# include <linux/list.h>
# include <linux/bitops.h>
# include <linux/spinlock.h>
# include <linux/mfd/core.h>
# define AB3550_NAME_STRING "ab3550"
# define AB3550_ID_FORMAT_STRING "AB3550 %s"
# define AB3550_NUM_BANKS 2
# define AB3550_NUM_EVENT_REG 5
/* These are the only registers inside AB3550 used in this main file */
/* Chip ID register */
# define AB3550_CID_REG 0x20
/* Interrupt event registers */
# define AB3550_EVENT_BANK 0
# define AB3550_EVENT_REG 0x22
/* Read/write operation values. */
# define AB3550_PERM_RD (0x01)
# define AB3550_PERM_WR (0x02)
/* Read/write permissions. */
# define AB3550_PERM_RO (AB3550_PERM_RD)
# define AB3550_PERM_RW (AB3550_PERM_RD | AB3550_PERM_WR)
/**
* struct ab3550
* @ access_mutex : lock out concurrent accesses to the AB registers
* @ i2c_client : I2C client for this chip
* @ chip_name : name of this chip variant
* @ chip_id : 8 bit chip ID for this chip variant
* @ mask_work : a worker for writing to mask registers
* @ event_lock : a lock to protect the event_mask
* @ event_mask : a local copy of the mask event registers
* @ startup_events : a copy of the first reading of the event registers
* @ startup_events_read : whether the first events have been read
*/
struct ab3550 {
struct mutex access_mutex ;
struct i2c_client * i2c_client [ AB3550_NUM_BANKS ] ;
char chip_name [ 32 ] ;
u8 chip_id ;
struct work_struct mask_work ;
spinlock_t event_lock ;
u8 event_mask [ AB3550_NUM_EVENT_REG ] ;
u8 startup_events [ AB3550_NUM_EVENT_REG ] ;
bool startup_events_read ;
# ifdef CONFIG_DEBUG_FS
unsigned int debug_bank ;
unsigned int debug_address ;
# endif
} ;
/**
* struct ab3550_reg_range
* @ first : the first address of the range
* @ last : the last address of the range
* @ perm : access permissions for the range
*/
struct ab3550_reg_range {
u8 first ;
u8 last ;
u8 perm ;
} ;
/**
* struct ab3550_reg_ranges
* @ count : the number of ranges in the list
* @ range : the list of register ranges
*/
struct ab3550_reg_ranges {
u8 count ;
const struct ab3550_reg_range * range ;
} ;
/*
* Permissible register ranges for reading and writing per device and bank .
*
* The ranges must be listed in increasing address order , and no overlaps are
* allowed . It is assumed that write permission implies read permission
* ( i . e . only RO and RW permissions should be used ) . Ranges with write
* permission must not be split up .
*/
# define NO_RANGE {.count = 0, .range = NULL,}
static struct
ab3550_reg_ranges ab3550_reg_ranges [ AB3550_NUM_DEVICES ] [ AB3550_NUM_BANKS ] = {
[ AB3550_DEVID_DAC ] = {
NO_RANGE ,
{
. count = 2 ,
. range = ( struct ab3550_reg_range [ ] ) {
{
. first = 0xb0 ,
. last = 0xba ,
. perm = AB3550_PERM_RW ,
} ,
{
. first = 0xbc ,
. last = 0xc3 ,
. perm = AB3550_PERM_RW ,
} ,
} ,
} ,
} ,
[ AB3550_DEVID_LEDS ] = {
NO_RANGE ,
{
. count = 2 ,
. range = ( struct ab3550_reg_range [ ] ) {
{
. first = 0x5a ,
. last = 0x88 ,
. perm = AB3550_PERM_RW ,
} ,
{
. first = 0x8a ,
. last = 0xad ,
. perm = AB3550_PERM_RW ,
} ,
}
} ,
} ,
[ AB3550_DEVID_POWER ] = {
{
. count = 1 ,
. range = ( struct ab3550_reg_range [ ] ) {
{
. first = 0x21 ,
. last = 0x21 ,
. perm = AB3550_PERM_RO ,
} ,
}
} ,
NO_RANGE ,
} ,
[ AB3550_DEVID_REGULATORS ] = {
{
. count = 1 ,
. range = ( struct ab3550_reg_range [ ] ) {
{
. first = 0x69 ,
. last = 0xa3 ,
. perm = AB3550_PERM_RW ,
} ,
}
} ,
{
. count = 1 ,
. range = ( struct ab3550_reg_range [ ] ) {
{
. first = 0x14 ,
. last = 0x16 ,
. perm = AB3550_PERM_RW ,
} ,
}
} ,
} ,
[ AB3550_DEVID_SIM ] = {
{
. count = 1 ,
. range = ( struct ab3550_reg_range [ ] ) {
{
. first = 0x21 ,
. last = 0x21 ,
. perm = AB3550_PERM_RO ,
} ,
}
} ,
{
. count = 1 ,
. range = ( struct ab3550_reg_range [ ] ) {
{
. first = 0x14 ,
. last = 0x17 ,
. perm = AB3550_PERM_RW ,
} ,
}
} ,
} ,
[ AB3550_DEVID_UART ] = {
NO_RANGE ,
NO_RANGE ,
} ,
[ AB3550_DEVID_RTC ] = {
{
. count = 1 ,
. range = ( struct ab3550_reg_range [ ] ) {
{
. first = 0x00 ,
. last = 0x0c ,
. perm = AB3550_PERM_RW ,
} ,
}
} ,
NO_RANGE ,
} ,
[ AB3550_DEVID_CHARGER ] = {
{
. count = 2 ,
. range = ( struct ab3550_reg_range [ ] ) {
{
. first = 0x10 ,
. last = 0x1a ,
. perm = AB3550_PERM_RW ,
} ,
{
. first = 0x21 ,
. last = 0x21 ,
. perm = AB3550_PERM_RO ,
} ,
}
} ,
NO_RANGE ,
} ,
[ AB3550_DEVID_ADC ] = {
NO_RANGE ,
{
. count = 1 ,
. range = ( struct ab3550_reg_range [ ] ) {
{
. first = 0x20 ,
. last = 0x56 ,
. perm = AB3550_PERM_RW ,
} ,
}
} ,
} ,
[ AB3550_DEVID_FUELGAUGE ] = {
{
. count = 1 ,
. range = ( struct ab3550_reg_range [ ] ) {
{
. first = 0x21 ,
. last = 0x21 ,
. perm = AB3550_PERM_RO ,
} ,
}
} ,
{
. count = 1 ,
. range = ( struct ab3550_reg_range [ ] ) {
{
. first = 0x00 ,
. last = 0x0e ,
. perm = AB3550_PERM_RW ,
} ,
}
} ,
} ,
[ AB3550_DEVID_VIBRATOR ] = {
NO_RANGE ,
{
. count = 1 ,
. range = ( struct ab3550_reg_range [ ] ) {
{
. first = 0x10 ,
. last = 0x13 ,
. perm = AB3550_PERM_RW ,
} ,
}
} ,
} ,
[ AB3550_DEVID_CODEC ] = {
{
. count = 2 ,
. range = ( struct ab3550_reg_range [ ] ) {
{
. first = 0x31 ,
. last = 0x63 ,
. perm = AB3550_PERM_RW ,
} ,
{
. first = 0x65 ,
. last = 0x68 ,
. perm = AB3550_PERM_RW ,
} ,
}
} ,
NO_RANGE ,
} ,
} ;
static struct mfd_cell ab3550_devs [ AB3550_NUM_DEVICES ] = {
[ AB3550_DEVID_DAC ] = {
. name = " ab3550-dac " ,
. id = AB3550_DEVID_DAC ,
. num_resources = 0 ,
} ,
[ AB3550_DEVID_LEDS ] = {
. name = " ab3550-leds " ,
. id = AB3550_DEVID_LEDS ,
} ,
[ AB3550_DEVID_POWER ] = {
. name = " ab3550-power " ,
. id = AB3550_DEVID_POWER ,
} ,
[ AB3550_DEVID_REGULATORS ] = {
. name = " ab3550-regulators " ,
. id = AB3550_DEVID_REGULATORS ,
} ,
[ AB3550_DEVID_SIM ] = {
. name = " ab3550-sim " ,
. id = AB3550_DEVID_SIM ,
} ,
[ AB3550_DEVID_UART ] = {
. name = " ab3550-uart " ,
. id = AB3550_DEVID_UART ,
} ,
[ AB3550_DEVID_RTC ] = {
. name = " ab3550-rtc " ,
. id = AB3550_DEVID_RTC ,
} ,
[ AB3550_DEVID_CHARGER ] = {
. name = " ab3550-charger " ,
. id = AB3550_DEVID_CHARGER ,
} ,
[ AB3550_DEVID_ADC ] = {
. name = " ab3550-adc " ,
. id = AB3550_DEVID_ADC ,
. num_resources = 10 ,
. resources = ( struct resource [ ] ) {
{
. name = " TRIGGER-0 " ,
. flags = IORESOURCE_IRQ ,
. start = 16 ,
. end = 16 ,
} ,
{
. name = " TRIGGER-1 " ,
. flags = IORESOURCE_IRQ ,
. start = 17 ,
. end = 17 ,
} ,
{
. name = " TRIGGER-2 " ,
. flags = IORESOURCE_IRQ ,
. start = 18 ,
. end = 18 ,
} ,
{
. name = " TRIGGER-3 " ,
. flags = IORESOURCE_IRQ ,
. start = 19 ,
. end = 19 ,
} ,
{
. name = " TRIGGER-4 " ,
. flags = IORESOURCE_IRQ ,
. start = 20 ,
. end = 20 ,
} ,
{
. name = " TRIGGER-5 " ,
. flags = IORESOURCE_IRQ ,
. start = 21 ,
. end = 21 ,
} ,
{
. name = " TRIGGER-6 " ,
. flags = IORESOURCE_IRQ ,
. start = 22 ,
. end = 22 ,
} ,
{
. name = " TRIGGER-7 " ,
. flags = IORESOURCE_IRQ ,
. start = 23 ,
. end = 23 ,
} ,
{
. name = " TRIGGER-VBAT-TXON " ,
. flags = IORESOURCE_IRQ ,
. start = 13 ,
. end = 13 ,
} ,
{
. name = " TRIGGER-VBAT " ,
. flags = IORESOURCE_IRQ ,
. start = 12 ,
. end = 12 ,
} ,
} ,
} ,
[ AB3550_DEVID_FUELGAUGE ] = {
. name = " ab3550-fuelgauge " ,
. id = AB3550_DEVID_FUELGAUGE ,
} ,
[ AB3550_DEVID_VIBRATOR ] = {
. name = " ab3550-vibrator " ,
. id = AB3550_DEVID_VIBRATOR ,
} ,
[ AB3550_DEVID_CODEC ] = {
. name = " ab3550-codec " ,
. id = AB3550_DEVID_CODEC ,
} ,
} ;
/*
* I2C transactions with error messages .
*/
static int ab3550_i2c_master_send ( struct ab3550 * ab , u8 bank , u8 * data ,
u8 count )
{
int err ;
err = i2c_master_send ( ab - > i2c_client [ bank ] , data , count ) ;
if ( err < 0 ) {
dev_err ( & ab - > i2c_client [ 0 ] - > dev , " send error: %d \n " , err ) ;
return err ;
}
return 0 ;
}
static int ab3550_i2c_master_recv ( struct ab3550 * ab , u8 bank , u8 * data ,
u8 count )
{
int err ;
err = i2c_master_recv ( ab - > i2c_client [ bank ] , data , count ) ;
if ( err < 0 ) {
dev_err ( & ab - > i2c_client [ 0 ] - > dev , " receive error: %d \n " , err ) ;
return err ;
}
return 0 ;
}
/*
* Functionality for getting / setting register values .
*/
static int get_register_interruptible ( struct ab3550 * ab , u8 bank , u8 reg ,
u8 * value )
{
int err ;
err = mutex_lock_interruptible ( & ab - > access_mutex ) ;
if ( err )
return err ;
err = ab3550_i2c_master_send ( ab , bank , & reg , 1 ) ;
if ( ! err )
err = ab3550_i2c_master_recv ( ab , bank , value , 1 ) ;
mutex_unlock ( & ab - > access_mutex ) ;
return err ;
}
static int get_register_page_interruptible ( struct ab3550 * ab , u8 bank ,
u8 first_reg , u8 * regvals , u8 numregs )
{
int err ;
err = mutex_lock_interruptible ( & ab - > access_mutex ) ;
if ( err )
return err ;
err = ab3550_i2c_master_send ( ab , bank , & first_reg , 1 ) ;
if ( ! err )
err = ab3550_i2c_master_recv ( ab , bank , regvals , numregs ) ;
mutex_unlock ( & ab - > access_mutex ) ;
return err ;
}
static int mask_and_set_register_interruptible ( struct ab3550 * ab , u8 bank ,
u8 reg , u8 bitmask , u8 bitvalues )
{
int err = 0 ;
if ( likely ( bitmask ) ) {
u8 reg_bits [ 2 ] = { reg , 0 } ;
err = mutex_lock_interruptible ( & ab - > access_mutex ) ;
if ( err )
return err ;
if ( bitmask = = 0xFF ) /* No need to read in this case. */
reg_bits [ 1 ] = bitvalues ;
else { /* Read and modify the register value. */
u8 bits ;
err = ab3550_i2c_master_send ( ab , bank , & reg , 1 ) ;
if ( err )
goto unlock_and_return ;
err = ab3550_i2c_master_recv ( ab , bank , & bits , 1 ) ;
if ( err )
goto unlock_and_return ;
reg_bits [ 1 ] = ( ( ~ bitmask & bits ) |
( bitmask & bitvalues ) ) ;
}
/* Write the new value. */
err = ab3550_i2c_master_send ( ab , bank , reg_bits , 2 ) ;
unlock_and_return :
mutex_unlock ( & ab - > access_mutex ) ;
}
return err ;
}
/*
* Read / write permission checking functions .
*/
static bool page_write_allowed ( const struct ab3550_reg_ranges * ranges ,
u8 first_reg , u8 last_reg )
{
u8 i ;
if ( last_reg < first_reg )
return false ;
for ( i = 0 ; i < ranges - > count ; i + + ) {
if ( first_reg < ranges - > range [ i ] . first )
break ;
if ( ( last_reg < = ranges - > range [ i ] . last ) & &
( ranges - > range [ i ] . perm & AB3550_PERM_WR ) )
return true ;
}
return false ;
}
static bool reg_write_allowed ( const struct ab3550_reg_ranges * ranges , u8 reg )
{
return page_write_allowed ( ranges , reg , reg ) ;
}
static bool page_read_allowed ( const struct ab3550_reg_ranges * ranges ,
u8 first_reg , u8 last_reg )
{
u8 i ;
if ( last_reg < first_reg )
return false ;
/* Find the range (if it exists in the list) that includes first_reg. */
for ( i = 0 ; i < ranges - > count ; i + + ) {
if ( first_reg < ranges - > range [ i ] . first )
return false ;
if ( first_reg < = ranges - > range [ i ] . last )
break ;
}
/* Make sure that the entire range up to and including last_reg is
* readable . This may span several of the ranges in the list .
*/
while ( ( i < ranges - > count ) & &
( ranges - > range [ i ] . perm & AB3550_PERM_RD ) ) {
if ( last_reg < = ranges - > range [ i ] . last )
return true ;
if ( ( + + i > = ranges - > count ) | |
( ranges - > range [ i ] . first ! =
( ranges - > range [ i - 1 ] . last + 1 ) ) ) {
break ;
}
}
return false ;
}
static bool reg_read_allowed ( const struct ab3550_reg_ranges * ranges , u8 reg )
{
return page_read_allowed ( ranges , reg , reg ) ;
}
/*
2010-06-09 17:54:54 +04:00
* The register access functionality .
2010-05-11 02:25:29 +04:00
*/
2010-06-09 17:54:54 +04:00
static int ab3550_get_chip_id ( struct device * dev )
2010-05-11 02:25:29 +04:00
{
struct ab3550 * ab = dev_get_drvdata ( dev - > parent ) ;
return ( int ) ab - > chip_id ;
}
2010-06-09 17:54:54 +04:00
static int ab3550_mask_and_set_register_interruptible ( struct device * dev ,
u8 bank , u8 reg , u8 bitmask , u8 bitvalues )
2010-05-11 02:25:29 +04:00
{
struct ab3550 * ab ;
struct platform_device * pdev = to_platform_device ( dev ) ;
if ( ( AB3550_NUM_BANKS < = bank ) | |
! reg_write_allowed ( & ab3550_reg_ranges [ pdev - > id ] [ bank ] , reg ) )
return - EINVAL ;
ab = dev_get_drvdata ( dev - > parent ) ;
return mask_and_set_register_interruptible ( ab , bank , reg ,
bitmask , bitvalues ) ;
}
2010-06-09 17:54:54 +04:00
static int ab3550_set_register_interruptible ( struct device * dev , u8 bank ,
u8 reg , u8 value )
2010-05-11 02:25:29 +04:00
{
return ab3550_mask_and_set_register_interruptible ( dev , bank , reg , 0xFF ,
value ) ;
}
2010-06-09 17:54:54 +04:00
static int ab3550_get_register_interruptible ( struct device * dev , u8 bank ,
u8 reg , u8 * value )
2010-05-11 02:25:29 +04:00
{
struct ab3550 * ab ;
struct platform_device * pdev = to_platform_device ( dev ) ;
if ( ( AB3550_NUM_BANKS < = bank ) | |
! reg_read_allowed ( & ab3550_reg_ranges [ pdev - > id ] [ bank ] , reg ) )
return - EINVAL ;
ab = dev_get_drvdata ( dev - > parent ) ;
return get_register_interruptible ( ab , bank , reg , value ) ;
}
2010-06-09 17:54:54 +04:00
static int ab3550_get_register_page_interruptible ( struct device * dev , u8 bank ,
2010-05-11 02:25:29 +04:00
u8 first_reg , u8 * regvals , u8 numregs )
{
struct ab3550 * ab ;
struct platform_device * pdev = to_platform_device ( dev ) ;
if ( ( AB3550_NUM_BANKS < = bank ) | |
! page_read_allowed ( & ab3550_reg_ranges [ pdev - > id ] [ bank ] ,
first_reg , ( first_reg + numregs - 1 ) ) )
return - EINVAL ;
ab = dev_get_drvdata ( dev - > parent ) ;
return get_register_page_interruptible ( ab , bank , first_reg , regvals ,
numregs ) ;
}
2010-06-09 17:54:54 +04:00
static int ab3550_event_registers_startup_state_get ( struct device * dev ,
u8 * event )
2010-05-11 02:25:29 +04:00
{
struct ab3550 * ab ;
ab = dev_get_drvdata ( dev - > parent ) ;
if ( ! ab - > startup_events_read )
return - EAGAIN ; /* Try again later */
memcpy ( event , ab - > startup_events , AB3550_NUM_EVENT_REG ) ;
return 0 ;
}
2010-06-09 17:54:54 +04:00
static int ab3550_startup_irq_enabled ( struct device * dev , unsigned int irq )
2010-05-11 02:25:29 +04:00
{
struct ab3550 * ab ;
struct ab3550_platform_data * plf_data ;
bool val ;
2011-03-25 14:12:32 +03:00
ab = irq_get_chip_data ( irq ) ;
2010-05-11 02:25:29 +04:00
plf_data = ab - > i2c_client [ 0 ] - > dev . platform_data ;
irq - = plf_data - > irq . base ;
val = ( ( ab - > startup_events [ irq / 8 ] & BIT ( irq % 8 ) ) ! = 0 ) ;
return val ;
}
static struct abx500_ops ab3550_ops = {
. get_chip_id = ab3550_get_chip_id ,
. get_register = ab3550_get_register_interruptible ,
. set_register = ab3550_set_register_interruptible ,
. get_register_page = ab3550_get_register_page_interruptible ,
. set_register_page = NULL ,
. mask_and_set_register = ab3550_mask_and_set_register_interruptible ,
. event_registers_startup_state_get =
ab3550_event_registers_startup_state_get ,
. startup_irq_enabled = ab3550_startup_irq_enabled ,
} ;
static irqreturn_t ab3550_irq_handler ( int irq , void * data )
{
struct ab3550 * ab = data ;
int err ;
unsigned int i ;
u8 e [ AB3550_NUM_EVENT_REG ] ;
u8 * events ;
unsigned long flags ;
events = ( ab - > startup_events_read ? e : ab - > startup_events ) ;
err = get_register_page_interruptible ( ab , AB3550_EVENT_BANK ,
AB3550_EVENT_REG , events , AB3550_NUM_EVENT_REG ) ;
if ( err )
goto err_event_rd ;
if ( ! ab - > startup_events_read ) {
dev_info ( & ab - > i2c_client [ 0 ] - > dev ,
" startup events 0x%x,0x%x,0x%x,0x%x,0x%x \n " ,
ab - > startup_events [ 0 ] , ab - > startup_events [ 1 ] ,
ab - > startup_events [ 2 ] , ab - > startup_events [ 3 ] ,
ab - > startup_events [ 4 ] ) ;
ab - > startup_events_read = true ;
goto out ;
}
/* The two highest bits in event[4] are not used. */
events [ 4 ] & = 0x3f ;
spin_lock_irqsave ( & ab - > event_lock , flags ) ;
for ( i = 0 ; i < AB3550_NUM_EVENT_REG ; i + + )
events [ i ] & = ~ ab - > event_mask [ i ] ;
spin_unlock_irqrestore ( & ab - > event_lock , flags ) ;
for ( i = 0 ; i < AB3550_NUM_EVENT_REG ; i + + ) {
u8 bit ;
u8 event_reg ;
dev_dbg ( & ab - > i2c_client [ 0 ] - > dev , " IRQ Event[%d]: 0x%2x \n " ,
i , events [ i ] ) ;
event_reg = events [ i ] ;
for ( bit = 0 ; event_reg ; bit + + , event_reg / = 2 ) {
if ( event_reg % 2 ) {
unsigned int irq ;
struct ab3550_platform_data * plf_data ;
plf_data = ab - > i2c_client [ 0 ] - > dev . platform_data ;
irq = plf_data - > irq . base + ( i * 8 ) + bit ;
handle_nested_irq ( irq ) ;
}
}
}
out :
return IRQ_HANDLED ;
err_event_rd :
dev_dbg ( & ab - > i2c_client [ 0 ] - > dev , " error reading event registers \n " ) ;
return IRQ_HANDLED ;
}
# ifdef CONFIG_DEBUG_FS
static struct ab3550_reg_ranges debug_ranges [ AB3550_NUM_BANKS ] = {
{
. count = 6 ,
. range = ( struct ab3550_reg_range [ ] ) {
{
. first = 0x00 ,
. last = 0x0e ,
} ,
{
. first = 0x10 ,
. last = 0x1a ,
} ,
{
. first = 0x1e ,
. last = 0x4f ,
} ,
{
. first = 0x51 ,
. last = 0x63 ,
} ,
{
. first = 0x65 ,
. last = 0xa3 ,
} ,
{
. first = 0xa5 ,
. last = 0xa8 ,
} ,
}
} ,
{
. count = 8 ,
. range = ( struct ab3550_reg_range [ ] ) {
{
. first = 0x00 ,
. last = 0x0e ,
} ,
{
. first = 0x10 ,
. last = 0x17 ,
} ,
{
. first = 0x1a ,
. last = 0x1c ,
} ,
{
. first = 0x20 ,
. last = 0x56 ,
} ,
{
. first = 0x5a ,
. last = 0x88 ,
} ,
{
. first = 0x8a ,
. last = 0xad ,
} ,
{
. first = 0xb0 ,
. last = 0xba ,
} ,
{
. first = 0xbc ,
. last = 0xc3 ,
} ,
}
} ,
} ;
static int ab3550_registers_print ( struct seq_file * s , void * p )
{
struct ab3550 * ab = s - > private ;
int bank ;
seq_printf ( s , AB3550_NAME_STRING " register values: \n " ) ;
for ( bank = 0 ; bank < AB3550_NUM_BANKS ; bank + + ) {
unsigned int i ;
seq_printf ( s , " bank %d: \n " , bank ) ;
for ( i = 0 ; i < debug_ranges [ bank ] . count ; i + + ) {
u8 reg ;
for ( reg = debug_ranges [ bank ] . range [ i ] . first ;
reg < = debug_ranges [ bank ] . range [ i ] . last ;
reg + + ) {
u8 value ;
get_register_interruptible ( ab , bank , reg ,
& value ) ;
seq_printf ( s , " [%d/0x%02X]: 0x%02X \n " , bank ,
reg , value ) ;
}
}
}
return 0 ;
}
static int ab3550_registers_open ( struct inode * inode , struct file * file )
{
return single_open ( file , ab3550_registers_print , inode - > i_private ) ;
}
static const struct file_operations ab3550_registers_fops = {
. open = ab3550_registers_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
. owner = THIS_MODULE ,
} ;
static int ab3550_bank_print ( struct seq_file * s , void * p )
{
struct ab3550 * ab = s - > private ;
seq_printf ( s , " %d \n " , ab - > debug_bank ) ;
return 0 ;
}
static int ab3550_bank_open ( struct inode * inode , struct file * file )
{
return single_open ( file , ab3550_bank_print , inode - > i_private ) ;
}
static ssize_t ab3550_bank_write ( struct file * file ,
const char __user * user_buf ,
size_t count , loff_t * ppos )
{
struct ab3550 * ab = ( ( struct seq_file * ) ( file - > private_data ) ) - > private ;
char buf [ 32 ] ;
int buf_size ;
unsigned long user_bank ;
int err ;
/* Get userspace string and assure termination */
buf_size = min ( count , ( sizeof ( buf ) - 1 ) ) ;
if ( copy_from_user ( buf , user_buf , buf_size ) )
return - EFAULT ;
buf [ buf_size ] = 0 ;
err = strict_strtoul ( buf , 0 , & user_bank ) ;
if ( err )
return - EINVAL ;
if ( user_bank > = AB3550_NUM_BANKS ) {
dev_err ( & ab - > i2c_client [ 0 ] - > dev ,
" debugfs error input > number of banks \n " ) ;
return - EINVAL ;
}
ab - > debug_bank = user_bank ;
return buf_size ;
}
static int ab3550_address_print ( struct seq_file * s , void * p )
{
struct ab3550 * ab = s - > private ;
seq_printf ( s , " 0x%02X \n " , ab - > debug_address ) ;
return 0 ;
}
static int ab3550_address_open ( struct inode * inode , struct file * file )
{
return single_open ( file , ab3550_address_print , inode - > i_private ) ;
}
static ssize_t ab3550_address_write ( struct file * file ,
const char __user * user_buf ,
size_t count , loff_t * ppos )
{
struct ab3550 * ab = ( ( struct seq_file * ) ( file - > private_data ) ) - > private ;
char buf [ 32 ] ;
int buf_size ;
unsigned long user_address ;
int err ;
/* Get userspace string and assure termination */
buf_size = min ( count , ( sizeof ( buf ) - 1 ) ) ;
if ( copy_from_user ( buf , user_buf , buf_size ) )
return - EFAULT ;
buf [ buf_size ] = 0 ;
err = strict_strtoul ( buf , 0 , & user_address ) ;
if ( err )
return - EINVAL ;
if ( user_address > 0xff ) {
dev_err ( & ab - > i2c_client [ 0 ] - > dev ,
" debugfs error input > 0xff \n " ) ;
return - EINVAL ;
}
ab - > debug_address = user_address ;
return buf_size ;
}
static int ab3550_val_print ( struct seq_file * s , void * p )
{
struct ab3550 * ab = s - > private ;
int err ;
u8 regvalue ;
err = get_register_interruptible ( ab , ( u8 ) ab - > debug_bank ,
( u8 ) ab - > debug_address , & regvalue ) ;
if ( err )
return - EINVAL ;
seq_printf ( s , " 0x%02X \n " , regvalue ) ;
return 0 ;
}
static int ab3550_val_open ( struct inode * inode , struct file * file )
{
return single_open ( file , ab3550_val_print , inode - > i_private ) ;
}
static ssize_t ab3550_val_write ( struct file * file ,
const char __user * user_buf ,
size_t count , loff_t * ppos )
{
struct ab3550 * ab = ( ( struct seq_file * ) ( file - > private_data ) ) - > private ;
char buf [ 32 ] ;
int buf_size ;
unsigned long user_val ;
int err ;
u8 regvalue ;
/* Get userspace string and assure termination */
buf_size = min ( count , ( sizeof ( buf ) - 1 ) ) ;
if ( copy_from_user ( buf , user_buf , buf_size ) )
return - EFAULT ;
buf [ buf_size ] = 0 ;
err = strict_strtoul ( buf , 0 , & user_val ) ;
if ( err )
return - EINVAL ;
if ( user_val > 0xff ) {
dev_err ( & ab - > i2c_client [ 0 ] - > dev ,
" debugfs error input > 0xff \n " ) ;
return - EINVAL ;
}
err = mask_and_set_register_interruptible (
ab , ( u8 ) ab - > debug_bank ,
( u8 ) ab - > debug_address , 0xFF , ( u8 ) user_val ) ;
if ( err )
return - EINVAL ;
get_register_interruptible ( ab , ( u8 ) ab - > debug_bank ,
( u8 ) ab - > debug_address , & regvalue ) ;
if ( err )
return - EINVAL ;
return buf_size ;
}
static const struct file_operations ab3550_bank_fops = {
. open = ab3550_bank_open ,
. write = ab3550_bank_write ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
. owner = THIS_MODULE ,
} ;
static const struct file_operations ab3550_address_fops = {
. open = ab3550_address_open ,
. write = ab3550_address_write ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
. owner = THIS_MODULE ,
} ;
static const struct file_operations ab3550_val_fops = {
. open = ab3550_val_open ,
. write = ab3550_val_write ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
. owner = THIS_MODULE ,
} ;
static struct dentry * ab3550_dir ;
static struct dentry * ab3550_reg_file ;
static struct dentry * ab3550_bank_file ;
static struct dentry * ab3550_address_file ;
static struct dentry * ab3550_val_file ;
static inline void ab3550_setup_debugfs ( struct ab3550 * ab )
{
ab - > debug_bank = 0 ;
ab - > debug_address = 0x00 ;
ab3550_dir = debugfs_create_dir ( AB3550_NAME_STRING , NULL ) ;
if ( ! ab3550_dir )
goto exit_no_debugfs ;
ab3550_reg_file = debugfs_create_file ( " all-registers " ,
S_IRUGO , ab3550_dir , ab , & ab3550_registers_fops ) ;
if ( ! ab3550_reg_file )
goto exit_destroy_dir ;
ab3550_bank_file = debugfs_create_file ( " register-bank " ,
2011-02-04 15:23:39 +03:00
( S_IRUGO | S_IWUSR ) , ab3550_dir , ab , & ab3550_bank_fops ) ;
2010-05-11 02:25:29 +04:00
if ( ! ab3550_bank_file )
goto exit_destroy_reg ;
ab3550_address_file = debugfs_create_file ( " register-address " ,
2011-02-04 15:23:39 +03:00
( S_IRUGO | S_IWUSR ) , ab3550_dir , ab , & ab3550_address_fops ) ;
2010-05-11 02:25:29 +04:00
if ( ! ab3550_address_file )
goto exit_destroy_bank ;
ab3550_val_file = debugfs_create_file ( " register-value " ,
2011-02-04 15:23:39 +03:00
( S_IRUGO | S_IWUSR ) , ab3550_dir , ab , & ab3550_val_fops ) ;
2010-05-11 02:25:29 +04:00
if ( ! ab3550_val_file )
goto exit_destroy_address ;
return ;
exit_destroy_address :
debugfs_remove ( ab3550_address_file ) ;
exit_destroy_bank :
debugfs_remove ( ab3550_bank_file ) ;
exit_destroy_reg :
debugfs_remove ( ab3550_reg_file ) ;
exit_destroy_dir :
debugfs_remove ( ab3550_dir ) ;
exit_no_debugfs :
dev_err ( & ab - > i2c_client [ 0 ] - > dev , " failed to create debugfs entries. \n " ) ;
return ;
}
static inline void ab3550_remove_debugfs ( void )
{
debugfs_remove ( ab3550_val_file ) ;
debugfs_remove ( ab3550_address_file ) ;
debugfs_remove ( ab3550_bank_file ) ;
debugfs_remove ( ab3550_reg_file ) ;
debugfs_remove ( ab3550_dir ) ;
}
# else /* !CONFIG_DEBUG_FS */
static inline void ab3550_setup_debugfs ( struct ab3550 * ab )
{
}
static inline void ab3550_remove_debugfs ( void )
{
}
# endif
/*
* Basic set - up , datastructure creation / destruction and I2C interface .
* This sets up a default config in the AB3550 chip so that it
* will work as expected .
*/
static int __init ab3550_setup ( struct ab3550 * ab )
{
int err = 0 ;
int i ;
struct ab3550_platform_data * plf_data ;
struct abx500_init_settings * settings ;
plf_data = ab - > i2c_client [ 0 ] - > dev . platform_data ;
settings = plf_data - > init_settings ;
for ( i = 0 ; i < plf_data - > init_settings_sz ; i + + ) {
err = mask_and_set_register_interruptible ( ab ,
settings [ i ] . bank ,
settings [ i ] . reg ,
0xFF , settings [ i ] . setting ) ;
if ( err )
goto exit_no_setup ;
/* If event mask register update the event mask in ab3550 */
if ( ( settings [ i ] . bank = = 0 ) & &
( AB3550_IMR1 < = settings [ i ] . reg ) & &
( settings [ i ] . reg < = AB3550_IMR5 ) ) {
ab - > event_mask [ settings [ i ] . reg - AB3550_IMR1 ] =
settings [ i ] . setting ;
}
}
exit_no_setup :
return err ;
}
static void ab3550_mask_work ( struct work_struct * work )
{
struct ab3550 * ab = container_of ( work , struct ab3550 , mask_work ) ;
int i ;
unsigned long flags ;
u8 mask [ AB3550_NUM_EVENT_REG ] ;
spin_lock_irqsave ( & ab - > event_lock , flags ) ;
for ( i = 0 ; i < AB3550_NUM_EVENT_REG ; i + + )
mask [ i ] = ab - > event_mask [ i ] ;
spin_unlock_irqrestore ( & ab - > event_lock , flags ) ;
for ( i = 0 ; i < AB3550_NUM_EVENT_REG ; i + + ) {
int err ;
err = mask_and_set_register_interruptible ( ab , 0 ,
( AB3550_IMR1 + i ) , ~ 0 , mask [ i ] ) ;
if ( err )
dev_err ( & ab - > i2c_client [ 0 ] - > dev ,
" ab3550_mask_work failed 0x%x,0x%x \n " ,
( AB3550_IMR1 + i ) , mask [ i ] ) ;
}
}
2010-12-11 16:14:12 +03:00
static void ab3550_mask ( struct irq_data * data )
2010-05-11 02:25:29 +04:00
{
unsigned long flags ;
struct ab3550 * ab ;
struct ab3550_platform_data * plf_data ;
2010-12-11 16:14:12 +03:00
int irq ;
2010-05-11 02:25:29 +04:00
2010-12-11 16:14:12 +03:00
ab = irq_data_get_irq_chip_data ( data ) ;
2010-05-11 02:25:29 +04:00
plf_data = ab - > i2c_client [ 0 ] - > dev . platform_data ;
2010-12-11 16:14:12 +03:00
irq = data - > irq - plf_data - > irq . base ;
2010-05-11 02:25:29 +04:00
spin_lock_irqsave ( & ab - > event_lock , flags ) ;
ab - > event_mask [ irq / 8 ] | = BIT ( irq % 8 ) ;
spin_unlock_irqrestore ( & ab - > event_lock , flags ) ;
schedule_work ( & ab - > mask_work ) ;
}
2010-12-11 16:14:12 +03:00
static void ab3550_unmask ( struct irq_data * data )
2010-05-11 02:25:29 +04:00
{
unsigned long flags ;
struct ab3550 * ab ;
struct ab3550_platform_data * plf_data ;
2010-12-11 16:14:12 +03:00
int irq ;
2010-05-11 02:25:29 +04:00
2010-12-11 16:14:12 +03:00
ab = irq_data_get_irq_chip_data ( data ) ;
2010-05-11 02:25:29 +04:00
plf_data = ab - > i2c_client [ 0 ] - > dev . platform_data ;
2010-12-11 16:14:12 +03:00
irq = data - > irq - plf_data - > irq . base ;
2010-05-11 02:25:29 +04:00
spin_lock_irqsave ( & ab - > event_lock , flags ) ;
ab - > event_mask [ irq / 8 ] & = ~ BIT ( irq % 8 ) ;
spin_unlock_irqrestore ( & ab - > event_lock , flags ) ;
schedule_work ( & ab - > mask_work ) ;
}
2010-12-11 16:14:12 +03:00
static void noop ( struct irq_data * data )
2010-05-11 02:25:29 +04:00
{
}
static struct irq_chip ab3550_irq_chip = {
. name = " ab3550-core " , /* Keep the same name as the request */
2010-12-11 16:14:12 +03:00
. irq_disable = ab3550_mask , /* No default to mask in chip.c */
. irq_ack = noop ,
. irq_mask = ab3550_mask ,
. irq_unmask = ab3550_unmask ,
2010-05-11 02:25:29 +04:00
} ;
struct ab_family_id {
u8 id ;
char * name ;
} ;
static const struct ab_family_id ids [ ] __initdata = {
/* AB3550 */
{
. id = AB3550_P1A ,
. name = " P1A "
} ,
/* Terminator */
{
. id = 0x00 ,
}
} ;
static int __init ab3550_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
{
struct ab3550 * ab ;
struct ab3550_platform_data * ab3550_plf_data =
client - > dev . platform_data ;
int err ;
int i ;
int num_i2c_clients = 0 ;
ab = kzalloc ( sizeof ( struct ab3550 ) , GFP_KERNEL ) ;
if ( ! ab ) {
dev_err ( & client - > dev ,
" could not allocate " AB3550_NAME_STRING " device \n " ) ;
return - ENOMEM ;
}
/* Initialize data structure */
mutex_init ( & ab - > access_mutex ) ;
spin_lock_init ( & ab - > event_lock ) ;
ab - > i2c_client [ 0 ] = client ;
i2c_set_clientdata ( client , ab ) ;
/* Read chip ID register */
err = get_register_interruptible ( ab , 0 , AB3550_CID_REG , & ab - > chip_id ) ;
if ( err ) {
dev_err ( & client - > dev , " could not communicate with the analog "
" baseband chip \n " ) ;
goto exit_no_detect ;
}
for ( i = 0 ; ids [ i ] . id ! = 0x0 ; i + + ) {
if ( ids [ i ] . id = = ab - > chip_id ) {
snprintf ( & ab - > chip_name [ 0 ] , sizeof ( ab - > chip_name ) - 1 ,
AB3550_ID_FORMAT_STRING , ids [ i ] . name ) ;
break ;
}
}
if ( ids [ i ] . id = = 0x0 ) {
dev_err ( & client - > dev , " unknown analog baseband chip id: 0x%x \n " ,
ab - > chip_id ) ;
dev_err ( & client - > dev , " driver not started! \n " ) ;
goto exit_no_detect ;
}
dev_info ( & client - > dev , " detected AB chip: %s \n " , & ab - > chip_name [ 0 ] ) ;
/* Attach other dummy I2C clients. */
while ( + + num_i2c_clients < AB3550_NUM_BANKS ) {
ab - > i2c_client [ num_i2c_clients ] =
i2c_new_dummy ( client - > adapter ,
( client - > addr + num_i2c_clients ) ) ;
if ( ! ab - > i2c_client [ num_i2c_clients ] ) {
err = - ENOMEM ;
goto exit_no_dummy_client ;
}
strlcpy ( ab - > i2c_client [ num_i2c_clients ] - > name , id - > name ,
sizeof ( ab - > i2c_client [ num_i2c_clients ] - > name ) ) ;
}
err = ab3550_setup ( ab ) ;
if ( err )
goto exit_no_setup ;
INIT_WORK ( & ab - > mask_work , ab3550_mask_work ) ;
for ( i = 0 ; i < ab3550_plf_data - > irq . count ; i + + ) {
unsigned int irq ;
irq = ab3550_plf_data - > irq . base + i ;
2011-03-25 14:12:32 +03:00
irq_set_chip_data ( irq , ab ) ;
irq_set_chip_and_handler ( irq , & ab3550_irq_chip ,
handle_simple_irq ) ;
irq_set_nested_thread ( irq , 1 ) ;
2010-05-11 02:25:29 +04:00
# ifdef CONFIG_ARM
set_irq_flags ( irq , IRQF_VALID ) ;
# else
2011-03-25 14:12:32 +03:00
irq_set_noprobe ( irq ) ;
2010-05-11 02:25:29 +04:00
# endif
}
err = request_threaded_irq ( client - > irq , NULL , ab3550_irq_handler ,
IRQF_ONESHOT , " ab3550-core " , ab ) ;
/* This real unpredictable IRQ is of course sampled for entropy */
rand_initialize_irq ( client - > irq ) ;
if ( err )
goto exit_no_irq ;
err = abx500_register_ops ( & client - > dev , & ab3550_ops ) ;
if ( err )
goto exit_no_ops ;
/* Set up and register the platform devices. */
2011-02-18 06:07:11 +03:00
for ( i = 0 ; i < AB3550_NUM_DEVICES ; i + + )
2011-02-18 06:07:25 +03:00
ab3550_devs [ i ] . mfd_data = ab3550_plf_data - > dev_data [ i ] ;
2010-05-11 02:25:29 +04:00
err = mfd_add_devices ( & client - > dev , 0 , ab3550_devs ,
ARRAY_SIZE ( ab3550_devs ) , NULL ,
ab3550_plf_data - > irq . base ) ;
ab3550_setup_debugfs ( ab ) ;
return 0 ;
exit_no_ops :
exit_no_irq :
exit_no_setup :
exit_no_dummy_client :
/* Unregister the dummy i2c clients. */
while ( - - num_i2c_clients )
i2c_unregister_device ( ab - > i2c_client [ num_i2c_clients ] ) ;
exit_no_detect :
kfree ( ab ) ;
return err ;
}
static int __exit ab3550_remove ( struct i2c_client * client )
{
struct ab3550 * ab = i2c_get_clientdata ( client ) ;
int num_i2c_clients = AB3550_NUM_BANKS ;
mfd_remove_devices ( & client - > dev ) ;
ab3550_remove_debugfs ( ) ;
while ( - - num_i2c_clients )
i2c_unregister_device ( ab - > i2c_client [ num_i2c_clients ] ) ;
/*
* At this point , all subscribers should have unregistered
* their notifiers so deactivate IRQ
*/
free_irq ( client - > irq , ab ) ;
kfree ( ab ) ;
return 0 ;
}
static const struct i2c_device_id ab3550_id [ ] = {
{ AB3550_NAME_STRING , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , ab3550_id ) ;
static struct i2c_driver ab3550_driver = {
. driver = {
. name = AB3550_NAME_STRING ,
. owner = THIS_MODULE ,
} ,
. id_table = ab3550_id ,
. probe = ab3550_probe ,
. remove = __exit_p ( ab3550_remove ) ,
} ;
static int __init ab3550_i2c_init ( void )
{
return i2c_add_driver ( & ab3550_driver ) ;
}
static void __exit ab3550_i2c_exit ( void )
{
i2c_del_driver ( & ab3550_driver ) ;
}
subsys_initcall ( ab3550_i2c_init ) ;
module_exit ( ab3550_i2c_exit ) ;
MODULE_AUTHOR ( " Mattias Wallin <mattias.wallin@stericsson.com> " ) ;
MODULE_DESCRIPTION ( " AB3550 core driver " ) ;
MODULE_LICENSE ( " GPL " ) ;