2010-09-28 18:37:20 +04:00
/*
* Copyright 2009 - 2010 Pengutronix
* Uwe Kleine - Koenig < u . kleine - koenig @ pengutronix . de >
*
* loosely based on an earlier driver that has
* Copyright 2009 Pengutronix , Sascha Hauer < s . hauer @ pengutronix . de >
*
* 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 .
*/
# include <linux/slab.h>
# include <linux/module.h>
# include <linux/platform_device.h>
# include <linux/mutex.h>
# include <linux/interrupt.h>
# include <linux/mfd/core.h>
# include <linux/mfd/mc13xxx.h>
2011-12-12 21:52:57 +04:00
# include <linux/of.h>
# include <linux/of_device.h>
# include <linux/of_gpio.h>
2010-09-28 18:37:20 +04:00
2012-04-01 10:41:38 +04:00
# include "mc13xxx.h"
2010-09-28 18:37:20 +04:00
# define MC13XXX_IRQSTAT0 0
# define MC13XXX_IRQSTAT0_ADCDONEI (1 << 0)
# define MC13XXX_IRQSTAT0_ADCBISDONEI (1 << 1)
# define MC13XXX_IRQSTAT0_TSI (1 << 2)
# define MC13783_IRQSTAT0_WHIGHI (1 << 3)
# define MC13783_IRQSTAT0_WLOWI (1 << 4)
# define MC13XXX_IRQSTAT0_CHGDETI (1 << 6)
# define MC13783_IRQSTAT0_CHGOVI (1 << 7)
# define MC13XXX_IRQSTAT0_CHGREVI (1 << 8)
# define MC13XXX_IRQSTAT0_CHGSHORTI (1 << 9)
# define MC13XXX_IRQSTAT0_CCCVI (1 << 10)
# define MC13XXX_IRQSTAT0_CHGCURRI (1 << 11)
# define MC13XXX_IRQSTAT0_BPONI (1 << 12)
# define MC13XXX_IRQSTAT0_LOBATLI (1 << 13)
# define MC13XXX_IRQSTAT0_LOBATHI (1 << 14)
# define MC13783_IRQSTAT0_UDPI (1 << 15)
# define MC13783_IRQSTAT0_USBI (1 << 16)
# define MC13783_IRQSTAT0_IDI (1 << 19)
# define MC13783_IRQSTAT0_SE1I (1 << 21)
# define MC13783_IRQSTAT0_CKDETI (1 << 22)
# define MC13783_IRQSTAT0_UDMI (1 << 23)
# define MC13XXX_IRQMASK0 1
# define MC13XXX_IRQMASK0_ADCDONEM MC13XXX_IRQSTAT0_ADCDONEI
# define MC13XXX_IRQMASK0_ADCBISDONEM MC13XXX_IRQSTAT0_ADCBISDONEI
# define MC13XXX_IRQMASK0_TSM MC13XXX_IRQSTAT0_TSI
# define MC13783_IRQMASK0_WHIGHM MC13783_IRQSTAT0_WHIGHI
# define MC13783_IRQMASK0_WLOWM MC13783_IRQSTAT0_WLOWI
# define MC13XXX_IRQMASK0_CHGDETM MC13XXX_IRQSTAT0_CHGDETI
# define MC13783_IRQMASK0_CHGOVM MC13783_IRQSTAT0_CHGOVI
# define MC13XXX_IRQMASK0_CHGREVM MC13XXX_IRQSTAT0_CHGREVI
# define MC13XXX_IRQMASK0_CHGSHORTM MC13XXX_IRQSTAT0_CHGSHORTI
# define MC13XXX_IRQMASK0_CCCVM MC13XXX_IRQSTAT0_CCCVI
# define MC13XXX_IRQMASK0_CHGCURRM MC13XXX_IRQSTAT0_CHGCURRI
# define MC13XXX_IRQMASK0_BPONM MC13XXX_IRQSTAT0_BPONI
# define MC13XXX_IRQMASK0_LOBATLM MC13XXX_IRQSTAT0_LOBATLI
# define MC13XXX_IRQMASK0_LOBATHM MC13XXX_IRQSTAT0_LOBATHI
# define MC13783_IRQMASK0_UDPM MC13783_IRQSTAT0_UDPI
# define MC13783_IRQMASK0_USBM MC13783_IRQSTAT0_USBI
# define MC13783_IRQMASK0_IDM MC13783_IRQSTAT0_IDI
# define MC13783_IRQMASK0_SE1M MC13783_IRQSTAT0_SE1I
# define MC13783_IRQMASK0_CKDETM MC13783_IRQSTAT0_CKDETI
# define MC13783_IRQMASK0_UDMM MC13783_IRQSTAT0_UDMI
# define MC13XXX_IRQSTAT1 3
# define MC13XXX_IRQSTAT1_1HZI (1 << 0)
# define MC13XXX_IRQSTAT1_TODAI (1 << 1)
# define MC13783_IRQSTAT1_ONOFD1I (1 << 3)
# define MC13783_IRQSTAT1_ONOFD2I (1 << 4)
# define MC13783_IRQSTAT1_ONOFD3I (1 << 5)
# define MC13XXX_IRQSTAT1_SYSRSTI (1 << 6)
# define MC13XXX_IRQSTAT1_RTCRSTI (1 << 7)
# define MC13XXX_IRQSTAT1_PCI (1 << 8)
# define MC13XXX_IRQSTAT1_WARMI (1 << 9)
# define MC13XXX_IRQSTAT1_MEMHLDI (1 << 10)
# define MC13783_IRQSTAT1_PWRRDYI (1 << 11)
# define MC13XXX_IRQSTAT1_THWARNLI (1 << 12)
# define MC13XXX_IRQSTAT1_THWARNHI (1 << 13)
# define MC13XXX_IRQSTAT1_CLKI (1 << 14)
# define MC13783_IRQSTAT1_SEMAFI (1 << 15)
# define MC13783_IRQSTAT1_MC2BI (1 << 17)
# define MC13783_IRQSTAT1_HSDETI (1 << 18)
# define MC13783_IRQSTAT1_HSLI (1 << 19)
# define MC13783_IRQSTAT1_ALSPTHI (1 << 20)
# define MC13783_IRQSTAT1_AHSSHORTI (1 << 21)
# define MC13XXX_IRQMASK1 4
# define MC13XXX_IRQMASK1_1HZM MC13XXX_IRQSTAT1_1HZI
# define MC13XXX_IRQMASK1_TODAM MC13XXX_IRQSTAT1_TODAI
# define MC13783_IRQMASK1_ONOFD1M MC13783_IRQSTAT1_ONOFD1I
# define MC13783_IRQMASK1_ONOFD2M MC13783_IRQSTAT1_ONOFD2I
# define MC13783_IRQMASK1_ONOFD3M MC13783_IRQSTAT1_ONOFD3I
# define MC13XXX_IRQMASK1_SYSRSTM MC13XXX_IRQSTAT1_SYSRSTI
# define MC13XXX_IRQMASK1_RTCRSTM MC13XXX_IRQSTAT1_RTCRSTI
# define MC13XXX_IRQMASK1_PCM MC13XXX_IRQSTAT1_PCI
# define MC13XXX_IRQMASK1_WARMM MC13XXX_IRQSTAT1_WARMI
# define MC13XXX_IRQMASK1_MEMHLDM MC13XXX_IRQSTAT1_MEMHLDI
# define MC13783_IRQMASK1_PWRRDYM MC13783_IRQSTAT1_PWRRDYI
# define MC13XXX_IRQMASK1_THWARNLM MC13XXX_IRQSTAT1_THWARNLI
# define MC13XXX_IRQMASK1_THWARNHM MC13XXX_IRQSTAT1_THWARNHI
# define MC13XXX_IRQMASK1_CLKM MC13XXX_IRQSTAT1_CLKI
# define MC13783_IRQMASK1_SEMAFM MC13783_IRQSTAT1_SEMAFI
# define MC13783_IRQMASK1_MC2BM MC13783_IRQSTAT1_MC2BI
# define MC13783_IRQMASK1_HSDETM MC13783_IRQSTAT1_HSDETI
# define MC13783_IRQMASK1_HSLM MC13783_IRQSTAT1_HSLI
# define MC13783_IRQMASK1_ALSPTHM MC13783_IRQSTAT1_ALSPTHI
# define MC13783_IRQMASK1_AHSSHORTM MC13783_IRQSTAT1_AHSSHORTI
# define MC13XXX_REVISION 7
# define MC13XXX_REVISION_REVMETAL (0x07 << 0)
# define MC13XXX_REVISION_REVFULL (0x03 << 3)
# define MC13XXX_REVISION_ICID (0x07 << 6)
# define MC13XXX_REVISION_FIN (0x03 << 9)
# define MC13XXX_REVISION_FAB (0x03 << 11)
# define MC13XXX_REVISION_ICIDCODE (0x3f << 13)
2011-08-24 17:28:21 +04:00
# define MC13XXX_ADC1 44
# define MC13XXX_ADC1_ADEN (1 << 0)
# define MC13XXX_ADC1_RAND (1 << 1)
# define MC13XXX_ADC1_ADSEL (1 << 3)
# define MC13XXX_ADC1_ASC (1 << 20)
# define MC13XXX_ADC1_ADTRIGIGN (1 << 21)
2010-09-28 18:37:20 +04:00
2011-08-24 17:28:21 +04:00
# define MC13XXX_ADC2 45
2010-09-28 18:37:20 +04:00
void mc13xxx_lock ( struct mc13xxx * mc13xxx )
{
if ( ! mutex_trylock ( & mc13xxx - > lock ) ) {
2012-05-01 14:26:46 +04:00
dev_dbg ( mc13xxx - > dev , " wait for %s from %pf \n " ,
2010-09-28 18:37:20 +04:00
__func__ , __builtin_return_address ( 0 ) ) ;
mutex_lock ( & mc13xxx - > lock ) ;
}
2012-05-01 14:26:46 +04:00
dev_dbg ( mc13xxx - > dev , " %s from %pf \n " ,
2010-09-28 18:37:20 +04:00
__func__ , __builtin_return_address ( 0 ) ) ;
}
EXPORT_SYMBOL ( mc13xxx_lock ) ;
void mc13xxx_unlock ( struct mc13xxx * mc13xxx )
{
2012-05-01 14:26:46 +04:00
dev_dbg ( mc13xxx - > dev , " %s from %pf \n " ,
2010-09-28 18:37:20 +04:00
__func__ , __builtin_return_address ( 0 ) ) ;
mutex_unlock ( & mc13xxx - > lock ) ;
}
EXPORT_SYMBOL ( mc13xxx_unlock ) ;
int mc13xxx_reg_read ( struct mc13xxx * mc13xxx , unsigned int offset , u32 * val )
{
int ret ;
BUG_ON ( ! mutex_is_locked ( & mc13xxx - > lock ) ) ;
if ( offset > MC13XXX_NUMREGS )
return - EINVAL ;
2012-04-01 10:41:37 +04:00
ret = regmap_read ( mc13xxx - > regmap , offset , val ) ;
2012-05-01 14:26:46 +04:00
dev_vdbg ( mc13xxx - > dev , " [0x%02x] -> 0x%06x \n " , offset , * val ) ;
2010-09-28 18:37:20 +04:00
2012-05-01 14:26:46 +04:00
return ret ;
2010-09-28 18:37:20 +04:00
}
EXPORT_SYMBOL ( mc13xxx_reg_read ) ;
int mc13xxx_reg_write ( struct mc13xxx * mc13xxx , unsigned int offset , u32 val )
{
BUG_ON ( ! mutex_is_locked ( & mc13xxx - > lock ) ) ;
2012-05-01 14:26:46 +04:00
dev_vdbg ( mc13xxx - > dev , " [0x%02x] <- 0x%06x \n " , offset , val ) ;
2010-09-28 18:37:20 +04:00
if ( offset > MC13XXX_NUMREGS | | val > 0xffffff )
return - EINVAL ;
2012-04-01 10:41:37 +04:00
return regmap_write ( mc13xxx - > regmap , offset , val ) ;
2010-09-28 18:37:20 +04:00
}
EXPORT_SYMBOL ( mc13xxx_reg_write ) ;
int mc13xxx_reg_rmw ( struct mc13xxx * mc13xxx , unsigned int offset ,
u32 mask , u32 val )
{
2012-04-01 10:41:37 +04:00
BUG_ON ( ! mutex_is_locked ( & mc13xxx - > lock ) ) ;
2010-09-28 18:37:20 +04:00
BUG_ON ( val & ~ mask ) ;
2012-04-01 10:41:37 +04:00
dev_vdbg ( mc13xxx - > dev , " [0x%02x] <- 0x%06x (mask: 0x%06x) \n " ,
offset , val , mask ) ;
2010-09-28 18:37:20 +04:00
2012-04-01 10:41:37 +04:00
return regmap_update_bits ( mc13xxx - > regmap , offset , mask , val ) ;
2010-09-28 18:37:20 +04:00
}
EXPORT_SYMBOL ( mc13xxx_reg_rmw ) ;
int mc13xxx_irq_mask ( struct mc13xxx * mc13xxx , int irq )
{
int ret ;
unsigned int offmask = irq < 24 ? MC13XXX_IRQMASK0 : MC13XXX_IRQMASK1 ;
u32 irqbit = 1 < < ( irq < 24 ? irq : irq - 24 ) ;
u32 mask ;
if ( irq < 0 | | irq > = MC13XXX_NUM_IRQ )
return - EINVAL ;
ret = mc13xxx_reg_read ( mc13xxx , offmask , & mask ) ;
if ( ret )
return ret ;
if ( mask & irqbit )
/* already masked */
return 0 ;
return mc13xxx_reg_write ( mc13xxx , offmask , mask | irqbit ) ;
}
EXPORT_SYMBOL ( mc13xxx_irq_mask ) ;
int mc13xxx_irq_unmask ( struct mc13xxx * mc13xxx , int irq )
{
int ret ;
unsigned int offmask = irq < 24 ? MC13XXX_IRQMASK0 : MC13XXX_IRQMASK1 ;
u32 irqbit = 1 < < ( irq < 24 ? irq : irq - 24 ) ;
u32 mask ;
if ( irq < 0 | | irq > = MC13XXX_NUM_IRQ )
return - EINVAL ;
ret = mc13xxx_reg_read ( mc13xxx , offmask , & mask ) ;
if ( ret )
return ret ;
if ( ! ( mask & irqbit ) )
/* already unmasked */
return 0 ;
return mc13xxx_reg_write ( mc13xxx , offmask , mask & ~ irqbit ) ;
}
EXPORT_SYMBOL ( mc13xxx_irq_unmask ) ;
int mc13xxx_irq_status ( struct mc13xxx * mc13xxx , int irq ,
int * enabled , int * pending )
{
int ret ;
unsigned int offmask = irq < 24 ? MC13XXX_IRQMASK0 : MC13XXX_IRQMASK1 ;
unsigned int offstat = irq < 24 ? MC13XXX_IRQSTAT0 : MC13XXX_IRQSTAT1 ;
u32 irqbit = 1 < < ( irq < 24 ? irq : irq - 24 ) ;
if ( irq < 0 | | irq > = MC13XXX_NUM_IRQ )
return - EINVAL ;
if ( enabled ) {
u32 mask ;
ret = mc13xxx_reg_read ( mc13xxx , offmask , & mask ) ;
if ( ret )
return ret ;
* enabled = mask & irqbit ;
}
if ( pending ) {
u32 stat ;
ret = mc13xxx_reg_read ( mc13xxx , offstat , & stat ) ;
if ( ret )
return ret ;
* pending = stat & irqbit ;
}
return 0 ;
}
EXPORT_SYMBOL ( mc13xxx_irq_status ) ;
int mc13xxx_irq_ack ( struct mc13xxx * mc13xxx , int irq )
{
unsigned int offstat = irq < 24 ? MC13XXX_IRQSTAT0 : MC13XXX_IRQSTAT1 ;
unsigned int val = 1 < < ( irq < 24 ? irq : irq - 24 ) ;
BUG_ON ( irq < 0 | | irq > = MC13XXX_NUM_IRQ ) ;
return mc13xxx_reg_write ( mc13xxx , offstat , val ) ;
}
EXPORT_SYMBOL ( mc13xxx_irq_ack ) ;
int mc13xxx_irq_request_nounmask ( struct mc13xxx * mc13xxx , int irq ,
irq_handler_t handler , const char * name , void * dev )
{
BUG_ON ( ! mutex_is_locked ( & mc13xxx - > lock ) ) ;
BUG_ON ( ! handler ) ;
if ( irq < 0 | | irq > = MC13XXX_NUM_IRQ )
return - EINVAL ;
if ( mc13xxx - > irqhandler [ irq ] )
return - EBUSY ;
mc13xxx - > irqhandler [ irq ] = handler ;
mc13xxx - > irqdata [ irq ] = dev ;
return 0 ;
}
EXPORT_SYMBOL ( mc13xxx_irq_request_nounmask ) ;
int mc13xxx_irq_request ( struct mc13xxx * mc13xxx , int irq ,
irq_handler_t handler , const char * name , void * dev )
{
int ret ;
ret = mc13xxx_irq_request_nounmask ( mc13xxx , irq , handler , name , dev ) ;
if ( ret )
return ret ;
ret = mc13xxx_irq_unmask ( mc13xxx , irq ) ;
if ( ret ) {
mc13xxx - > irqhandler [ irq ] = NULL ;
mc13xxx - > irqdata [ irq ] = NULL ;
return ret ;
}
return 0 ;
}
EXPORT_SYMBOL ( mc13xxx_irq_request ) ;
int mc13xxx_irq_free ( struct mc13xxx * mc13xxx , int irq , void * dev )
{
int ret ;
BUG_ON ( ! mutex_is_locked ( & mc13xxx - > lock ) ) ;
if ( irq < 0 | | irq > = MC13XXX_NUM_IRQ | | ! mc13xxx - > irqhandler [ irq ] | |
mc13xxx - > irqdata [ irq ] ! = dev )
return - EINVAL ;
ret = mc13xxx_irq_mask ( mc13xxx , irq ) ;
if ( ret )
return ret ;
mc13xxx - > irqhandler [ irq ] = NULL ;
mc13xxx - > irqdata [ irq ] = NULL ;
return 0 ;
}
EXPORT_SYMBOL ( mc13xxx_irq_free ) ;
static inline irqreturn_t mc13xxx_irqhandler ( struct mc13xxx * mc13xxx , int irq )
{
return mc13xxx - > irqhandler [ irq ] ( irq , mc13xxx - > irqdata [ irq ] ) ;
}
/*
* returns : number of handled irqs or negative error
* locking : holds mc13xxx - > lock
*/
static int mc13xxx_irq_handle ( struct mc13xxx * mc13xxx ,
unsigned int offstat , unsigned int offmask , int baseirq )
{
u32 stat , mask ;
int ret = mc13xxx_reg_read ( mc13xxx , offstat , & stat ) ;
int num_handled = 0 ;
if ( ret )
return ret ;
ret = mc13xxx_reg_read ( mc13xxx , offmask , & mask ) ;
if ( ret )
return ret ;
while ( stat & ~ mask ) {
int irq = __ffs ( stat & ~ mask ) ;
stat & = ~ ( 1 < < irq ) ;
if ( likely ( mc13xxx - > irqhandler [ baseirq + irq ] ) ) {
irqreturn_t handled ;
handled = mc13xxx_irqhandler ( mc13xxx , baseirq + irq ) ;
if ( handled = = IRQ_HANDLED )
num_handled + + ;
} else {
2012-05-01 14:26:46 +04:00
dev_err ( mc13xxx - > dev ,
2010-09-28 18:37:20 +04:00
" BUG: irq %u but no handler \n " ,
baseirq + irq ) ;
mask | = 1 < < irq ;
ret = mc13xxx_reg_write ( mc13xxx , offmask , mask ) ;
}
}
return num_handled ;
}
static irqreturn_t mc13xxx_irq_thread ( int irq , void * data )
{
struct mc13xxx * mc13xxx = data ;
irqreturn_t ret ;
int handled = 0 ;
mc13xxx_lock ( mc13xxx ) ;
ret = mc13xxx_irq_handle ( mc13xxx , MC13XXX_IRQSTAT0 ,
MC13XXX_IRQMASK0 , 0 ) ;
if ( ret > 0 )
handled = 1 ;
ret = mc13xxx_irq_handle ( mc13xxx , MC13XXX_IRQSTAT1 ,
MC13XXX_IRQMASK1 , 24 ) ;
if ( ret > 0 )
handled = 1 ;
mc13xxx_unlock ( mc13xxx ) ;
return IRQ_RETVAL ( handled ) ;
}
2011-09-23 23:51:42 +04:00
static const char * mc13xxx_chipname [ ] = {
2010-09-28 18:37:20 +04:00
[ MC13XXX_ID_MC13783 ] = " mc13783 " ,
[ MC13XXX_ID_MC13892 ] = " mc13892 " ,
} ;
# define maskval(reg, mask) (((reg) & (mask)) >> __ffs(mask))
2012-05-01 14:26:46 +04:00
static int mc13xxx_identify ( struct mc13xxx * mc13xxx )
2010-09-28 18:37:20 +04:00
{
u32 icid ;
u32 revision ;
int ret ;
2012-05-01 14:26:46 +04:00
/*
* Get the generation ID from register 46 , as apparently some older
* IC revisions only have this info at this location . Newer ICs seem to
* have both .
*/
2010-09-28 18:37:20 +04:00
ret = mc13xxx_reg_read ( mc13xxx , 46 , & icid ) ;
if ( ret )
return ret ;
icid = ( icid > > 6 ) & 0x7 ;
switch ( icid ) {
case 2 :
2012-05-01 14:26:46 +04:00
mc13xxx - > ictype = MC13XXX_ID_MC13783 ;
2010-09-28 18:37:20 +04:00
break ;
case 7 :
2012-05-01 14:26:46 +04:00
mc13xxx - > ictype = MC13XXX_ID_MC13892 ;
2010-09-28 18:37:20 +04:00
break ;
default :
2012-05-01 14:26:46 +04:00
mc13xxx - > ictype = MC13XXX_ID_INVALID ;
2010-09-28 18:37:20 +04:00
break ;
}
2012-05-01 14:26:46 +04:00
if ( mc13xxx - > ictype = = MC13XXX_ID_MC13783 | |
mc13xxx - > ictype = = MC13XXX_ID_MC13892 ) {
2010-09-28 18:37:20 +04:00
ret = mc13xxx_reg_read ( mc13xxx , MC13XXX_REVISION , & revision ) ;
2012-05-01 14:26:46 +04:00
dev_info ( mc13xxx - > dev , " %s: rev: %d.%d, "
2010-09-28 18:37:20 +04:00
" fin: %d, fab: %d, icid: %d/%d \n " ,
2012-05-01 14:26:46 +04:00
mc13xxx_chipname [ mc13xxx - > ictype ] ,
2010-09-28 18:37:20 +04:00
maskval ( revision , MC13XXX_REVISION_REVFULL ) ,
maskval ( revision , MC13XXX_REVISION_REVMETAL ) ,
maskval ( revision , MC13XXX_REVISION_FIN ) ,
maskval ( revision , MC13XXX_REVISION_FAB ) ,
maskval ( revision , MC13XXX_REVISION_ICID ) ,
maskval ( revision , MC13XXX_REVISION_ICIDCODE ) ) ;
}
2012-05-01 14:26:46 +04:00
return ( mc13xxx - > ictype = = MC13XXX_ID_INVALID ) ? - ENODEV : 0 ;
2010-09-28 18:37:20 +04:00
}
static const char * mc13xxx_get_chipname ( struct mc13xxx * mc13xxx )
{
2012-05-01 14:26:46 +04:00
return mc13xxx_chipname [ mc13xxx - > ictype ] ;
2010-09-28 18:37:20 +04:00
}
int mc13xxx_get_flags ( struct mc13xxx * mc13xxx )
{
2011-12-12 21:52:57 +04:00
return mc13xxx - > flags ;
2010-09-28 18:37:20 +04:00
}
EXPORT_SYMBOL ( mc13xxx_get_flags ) ;
2011-08-24 17:28:21 +04:00
# define MC13XXX_ADC1_CHAN0_SHIFT 5
# define MC13XXX_ADC1_CHAN1_SHIFT 8
2012-02-20 15:18:13 +04:00
# define MC13783_ADC1_ATO_SHIFT 11
# define MC13783_ADC1_ATOX (1 << 19)
2010-09-28 18:37:20 +04:00
struct mc13xxx_adcdone_data {
struct mc13xxx * mc13xxx ;
struct completion done ;
} ;
2011-08-24 17:28:21 +04:00
static irqreturn_t mc13xxx_handler_adcdone ( int irq , void * data )
2010-09-28 18:37:20 +04:00
{
struct mc13xxx_adcdone_data * adcdone_data = data ;
mc13xxx_irq_ack ( adcdone_data - > mc13xxx , irq ) ;
complete_all ( & adcdone_data - > done ) ;
return IRQ_HANDLED ;
}
2011-08-24 17:28:21 +04:00
# define MC13XXX_ADC_WORKING (1 << 0)
2010-09-28 18:37:20 +04:00
2011-08-24 17:28:21 +04:00
int mc13xxx_adc_do_conversion ( struct mc13xxx * mc13xxx , unsigned int mode ,
2012-02-20 15:18:13 +04:00
unsigned int channel , u8 ato , bool atox ,
unsigned int * sample )
2010-09-28 18:37:20 +04:00
{
u32 adc0 , adc1 , old_adc0 ;
int i , ret ;
struct mc13xxx_adcdone_data adcdone_data = {
. mc13xxx = mc13xxx ,
} ;
init_completion ( & adcdone_data . done ) ;
2012-05-01 14:26:46 +04:00
dev_dbg ( mc13xxx - > dev , " %s \n " , __func__ ) ;
2010-09-28 18:37:20 +04:00
mc13xxx_lock ( mc13xxx ) ;
2011-08-24 17:28:21 +04:00
if ( mc13xxx - > adcflags & MC13XXX_ADC_WORKING ) {
2010-09-28 18:37:20 +04:00
ret = - EBUSY ;
goto out ;
}
2011-08-24 17:28:21 +04:00
mc13xxx - > adcflags | = MC13XXX_ADC_WORKING ;
2010-09-28 18:37:20 +04:00
2011-08-24 17:28:21 +04:00
mc13xxx_reg_read ( mc13xxx , MC13XXX_ADC0 , & old_adc0 ) ;
2010-09-28 18:37:20 +04:00
2011-08-24 17:28:21 +04:00
adc0 = MC13XXX_ADC0_ADINC1 | MC13XXX_ADC0_ADINC2 ;
adc1 = MC13XXX_ADC1_ADEN | MC13XXX_ADC1_ADTRIGIGN | MC13XXX_ADC1_ASC ;
2010-09-28 18:37:20 +04:00
if ( channel > 7 )
2011-08-24 17:28:21 +04:00
adc1 | = MC13XXX_ADC1_ADSEL ;
2010-09-28 18:37:20 +04:00
switch ( mode ) {
2011-08-24 17:28:21 +04:00
case MC13XXX_ADC_MODE_TS :
adc0 | = MC13XXX_ADC0_ADREFEN | MC13XXX_ADC0_TSMOD0 |
MC13XXX_ADC0_TSMOD1 ;
adc1 | = 4 < < MC13XXX_ADC1_CHAN1_SHIFT ;
2010-09-28 18:37:20 +04:00
break ;
2011-08-24 17:28:21 +04:00
case MC13XXX_ADC_MODE_SINGLE_CHAN :
2011-11-29 15:09:03 +04:00
adc0 | = old_adc0 & MC13XXX_ADC0_CONFIG_MASK ;
2011-08-24 17:28:21 +04:00
adc1 | = ( channel & 0x7 ) < < MC13XXX_ADC1_CHAN0_SHIFT ;
adc1 | = MC13XXX_ADC1_RAND ;
2010-09-28 18:37:20 +04:00
break ;
2011-08-24 17:28:21 +04:00
case MC13XXX_ADC_MODE_MULT_CHAN :
2011-11-29 15:09:03 +04:00
adc0 | = old_adc0 & MC13XXX_ADC0_CONFIG_MASK ;
2011-08-24 17:28:21 +04:00
adc1 | = 4 < < MC13XXX_ADC1_CHAN1_SHIFT ;
2010-09-28 18:37:20 +04:00
break ;
default :
2011-08-24 17:28:21 +04:00
mc13xxx_unlock ( mc13xxx ) ;
2010-09-28 18:37:20 +04:00
return - EINVAL ;
}
2012-02-20 15:18:13 +04:00
adc1 | = ato < < MC13783_ADC1_ATO_SHIFT ;
if ( atox )
adc1 | = MC13783_ADC1_ATOX ;
2012-05-01 14:26:46 +04:00
dev_dbg ( mc13xxx - > dev , " %s: request irq \n " , __func__ ) ;
2011-08-24 17:28:21 +04:00
mc13xxx_irq_request ( mc13xxx , MC13XXX_IRQ_ADCDONE ,
mc13xxx_handler_adcdone , __func__ , & adcdone_data ) ;
mc13xxx_irq_ack ( mc13xxx , MC13XXX_IRQ_ADCDONE ) ;
2010-09-28 18:37:20 +04:00
2011-08-24 17:28:21 +04:00
mc13xxx_reg_write ( mc13xxx , MC13XXX_ADC0 , adc0 ) ;
mc13xxx_reg_write ( mc13xxx , MC13XXX_ADC1 , adc1 ) ;
2010-09-28 18:37:20 +04:00
mc13xxx_unlock ( mc13xxx ) ;
ret = wait_for_completion_interruptible_timeout ( & adcdone_data . done , HZ ) ;
if ( ! ret )
ret = - ETIMEDOUT ;
mc13xxx_lock ( mc13xxx ) ;
2011-08-24 17:28:21 +04:00
mc13xxx_irq_free ( mc13xxx , MC13XXX_IRQ_ADCDONE , & adcdone_data ) ;
2010-09-28 18:37:20 +04:00
if ( ret > 0 )
for ( i = 0 ; i < 4 ; + + i ) {
ret = mc13xxx_reg_read ( mc13xxx ,
2011-08-24 17:28:21 +04:00
MC13XXX_ADC2 , & sample [ i ] ) ;
2010-09-28 18:37:20 +04:00
if ( ret )
break ;
}
2011-08-24 17:28:21 +04:00
if ( mode = = MC13XXX_ADC_MODE_TS )
2010-09-28 18:37:20 +04:00
/* restore TSMOD */
2011-08-24 17:28:21 +04:00
mc13xxx_reg_write ( mc13xxx , MC13XXX_ADC0 , old_adc0 ) ;
2010-09-28 18:37:20 +04:00
2011-08-24 17:28:21 +04:00
mc13xxx - > adcflags & = ~ MC13XXX_ADC_WORKING ;
2010-09-28 18:37:20 +04:00
out :
mc13xxx_unlock ( mc13xxx ) ;
return ret ;
}
2011-08-24 17:28:21 +04:00
EXPORT_SYMBOL_GPL ( mc13xxx_adc_do_conversion ) ;
2010-09-28 18:37:20 +04:00
static int mc13xxx_add_subdevice_pdata ( struct mc13xxx * mc13xxx ,
2011-04-08 03:55:01 +04:00
const char * format , void * pdata , size_t pdata_size )
2010-09-28 18:37:20 +04:00
{
char buf [ 30 ] ;
const char * name = mc13xxx_get_chipname ( mc13xxx ) ;
struct mfd_cell cell = {
2011-04-08 03:55:01 +04:00
. platform_data = pdata ,
. pdata_size = pdata_size ,
2010-09-28 18:37:20 +04:00
} ;
/* there is no asnprintf in the kernel :-( */
if ( snprintf ( buf , sizeof ( buf ) , format , name ) > sizeof ( buf ) )
return - E2BIG ;
cell . name = kmemdup ( buf , strlen ( buf ) + 1 , GFP_KERNEL ) ;
if ( ! cell . name )
return - ENOMEM ;
2012-09-11 11:16:36 +04:00
return mfd_add_devices ( mc13xxx - > dev , - 1 , & cell , 1 , NULL , 0 , NULL ) ;
2010-09-28 18:37:20 +04:00
}
static int mc13xxx_add_subdevice ( struct mc13xxx * mc13xxx , const char * format )
{
2011-04-08 03:55:01 +04:00
return mc13xxx_add_subdevice_pdata ( mc13xxx , format , NULL , 0 ) ;
2010-09-28 18:37:20 +04:00
}
2011-12-12 21:52:57 +04:00
# ifdef CONFIG_OF
static int mc13xxx_probe_flags_dt ( struct mc13xxx * mc13xxx )
{
2012-04-01 10:41:37 +04:00
struct device_node * np = mc13xxx - > dev - > of_node ;
2011-12-12 21:52:57 +04:00
if ( ! np )
return - ENODEV ;
if ( of_get_property ( np , " fsl,mc13xxx-uses-adc " , NULL ) )
mc13xxx - > flags | = MC13XXX_USE_ADC ;
if ( of_get_property ( np , " fsl,mc13xxx-uses-codec " , NULL ) )
mc13xxx - > flags | = MC13XXX_USE_CODEC ;
if ( of_get_property ( np , " fsl,mc13xxx-uses-rtc " , NULL ) )
mc13xxx - > flags | = MC13XXX_USE_RTC ;
if ( of_get_property ( np , " fsl,mc13xxx-uses-touch " , NULL ) )
mc13xxx - > flags | = MC13XXX_USE_TOUCHSCREEN ;
return 0 ;
}
# else
static inline int mc13xxx_probe_flags_dt ( struct mc13xxx * mc13xxx )
{
return - ENODEV ;
}
# endif
2012-04-01 10:41:38 +04:00
int mc13xxx_common_init ( struct mc13xxx * mc13xxx ,
2012-05-01 14:26:46 +04:00
struct mc13xxx_platform_data * pdata , int irq )
2010-09-28 18:37:20 +04:00
{
int ret ;
mc13xxx_lock ( mc13xxx ) ;
2012-05-01 14:26:46 +04:00
ret = mc13xxx_identify ( mc13xxx ) ;
if ( ret )
2010-09-28 18:37:20 +04:00
goto err_revision ;
/* mask all irqs */
ret = mc13xxx_reg_write ( mc13xxx , MC13XXX_IRQMASK0 , 0x00ffffff ) ;
if ( ret )
goto err_mask ;
ret = mc13xxx_reg_write ( mc13xxx , MC13XXX_IRQMASK1 , 0x00ffffff ) ;
if ( ret )
goto err_mask ;
2012-05-01 14:26:46 +04:00
ret = request_threaded_irq ( irq , NULL , mc13xxx_irq_thread ,
2010-09-28 18:37:20 +04:00
IRQF_ONESHOT | IRQF_TRIGGER_HIGH , " mc13xxx " , mc13xxx ) ;
if ( ret ) {
err_mask :
err_revision :
2010-11-11 18:47:50 +03:00
mc13xxx_unlock ( mc13xxx ) ;
2010-09-28 18:37:20 +04:00
kfree ( mc13xxx ) ;
return ret ;
}
2012-05-01 14:26:46 +04:00
mc13xxx - > irq = irq ;
2010-09-28 18:37:20 +04:00
mc13xxx_unlock ( mc13xxx ) ;
2011-12-12 21:52:57 +04:00
if ( mc13xxx_probe_flags_dt ( mc13xxx ) < 0 & & pdata )
mc13xxx - > flags = pdata - > flags ;
if ( mc13xxx - > flags & MC13XXX_USE_ADC )
2010-09-28 18:37:20 +04:00
mc13xxx_add_subdevice ( mc13xxx , " %s-adc " ) ;
2011-12-12 21:52:57 +04:00
if ( mc13xxx - > flags & MC13XXX_USE_CODEC )
2012-05-15 15:53:49 +04:00
mc13xxx_add_subdevice_pdata ( mc13xxx , " %s-codec " ,
pdata - > codec , sizeof ( * pdata - > codec ) ) ;
2010-09-28 18:37:20 +04:00
2011-12-12 21:52:57 +04:00
if ( mc13xxx - > flags & MC13XXX_USE_RTC )
2010-09-28 18:37:20 +04:00
mc13xxx_add_subdevice ( mc13xxx , " %s-rtc " ) ;
2011-12-12 21:52:57 +04:00
if ( mc13xxx - > flags & MC13XXX_USE_TOUCHSCREEN )
2012-02-20 15:18:13 +04:00
mc13xxx_add_subdevice_pdata ( mc13xxx , " %s-ts " ,
& pdata - > touch , sizeof ( pdata - > touch ) ) ;
2010-09-28 18:37:20 +04:00
2011-12-12 21:52:57 +04:00
if ( pdata ) {
mc13xxx_add_subdevice_pdata ( mc13xxx , " %s-regulator " ,
& pdata - > regulators , sizeof ( pdata - > regulators ) ) ;
2011-04-08 03:55:01 +04:00
mc13xxx_add_subdevice_pdata ( mc13xxx , " %s-led " ,
pdata - > leds , sizeof ( * pdata - > leds ) ) ;
2011-09-18 20:10:53 +04:00
mc13xxx_add_subdevice_pdata ( mc13xxx , " %s-pwrbutton " ,
pdata - > buttons , sizeof ( * pdata - > buttons ) ) ;
2011-12-12 21:52:57 +04:00
} else {
mc13xxx_add_subdevice ( mc13xxx , " %s-regulator " ) ;
mc13xxx_add_subdevice ( mc13xxx , " %s-led " ) ;
mc13xxx_add_subdevice ( mc13xxx , " %s-pwrbutton " ) ;
}
2011-09-18 20:10:53 +04:00
2010-09-28 18:37:20 +04:00
return 0 ;
}
2012-04-01 10:41:38 +04:00
EXPORT_SYMBOL_GPL ( mc13xxx_common_init ) ;
2010-09-28 18:37:20 +04:00
2012-04-01 10:41:38 +04:00
void mc13xxx_common_cleanup ( struct mc13xxx * mc13xxx )
2010-09-28 18:37:20 +04:00
{
2012-05-01 14:26:46 +04:00
free_irq ( mc13xxx - > irq , mc13xxx ) ;
2010-09-28 18:37:20 +04:00
2012-05-01 14:26:46 +04:00
mfd_remove_devices ( mc13xxx - > dev ) ;
2010-09-28 18:37:20 +04:00
}
2012-04-01 10:41:38 +04:00
EXPORT_SYMBOL_GPL ( mc13xxx_common_cleanup ) ;
2010-09-28 18:37:20 +04:00
MODULE_DESCRIPTION ( " Core driver for Freescale MC13XXX PMIC " ) ;
MODULE_AUTHOR ( " Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;