2008-10-10 18:58:10 +04:00
/*
* wm8350 - core . c - - Device access for Wolfson WM8350
*
* Copyright 2007 , 2008 Wolfson Microelectronics PLC .
*
* Author : Liam Girdwood , Mark Brown
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation ; either version 2 of the License , or ( at your
* option ) any later version .
*
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/init.h>
2008-10-10 18:58:14 +04:00
# include <linux/bug.h>
2008-10-10 18:58:10 +04:00
# include <linux/device.h>
# include <linux/delay.h>
# include <linux/interrupt.h>
2008-10-10 18:58:14 +04:00
# include <linux/workqueue.h>
2008-10-10 18:58:10 +04:00
# include <linux/mfd/wm8350/core.h>
# include <linux/mfd/wm8350/audio.h>
2008-10-10 18:58:14 +04:00
# include <linux/mfd/wm8350/comparator.h>
2008-10-10 18:58:10 +04:00
# include <linux/mfd/wm8350/gpio.h>
# include <linux/mfd/wm8350/pmic.h>
2008-10-10 18:58:14 +04:00
# include <linux/mfd/wm8350/rtc.h>
2008-10-10 18:58:10 +04:00
# include <linux/mfd/wm8350/supply.h>
2008-10-10 18:58:14 +04:00
# include <linux/mfd/wm8350/wdt.h>
2008-10-10 18:58:10 +04:00
# define WM8350_UNLOCK_KEY 0x0013
# define WM8350_LOCK_KEY 0x0000
# define WM8350_CLOCK_CONTROL_1 0x28
# define WM8350_AIF_TEST 0x74
/* debug */
# define WM8350_BUS_DEBUG 0
# if WM8350_BUS_DEBUG
# define dump(regs, src) do { \
int i_ ; \
u16 * src_ = src ; \
printk ( KERN_DEBUG ) ; \
for ( i_ = 0 ; i_ < regs ; i_ + + ) \
printk ( " 0x%4.4x " , * src_ + + ) ; \
printk ( " \n " ) ; \
} while ( 0 ) ;
# else
# define dump(bytes, src)
# endif
# define WM8350_LOCK_DEBUG 0
# if WM8350_LOCK_DEBUG
# define ldbg(format, arg...) printk(format, ## arg)
# else
# define ldbg(format, arg...)
# endif
/*
* WM8350 Device IO
*/
static DEFINE_MUTEX ( io_mutex ) ;
static DEFINE_MUTEX ( reg_lock_mutex ) ;
/* Perform a physical read from the device.
*/
static int wm8350_phys_read ( struct wm8350 * wm8350 , u8 reg , int num_regs ,
u16 * dest )
{
int i , ret ;
int bytes = num_regs * 2 ;
dev_dbg ( wm8350 - > dev , " volatile read \n " ) ;
ret = wm8350 - > read_dev ( wm8350 , reg , bytes , ( char * ) dest ) ;
for ( i = reg ; i < reg + num_regs ; i + + ) {
/* Cache is CPU endian */
dest [ i - reg ] = be16_to_cpu ( dest [ i - reg ] ) ;
/* Mask out non-readable bits */
dest [ i - reg ] & = wm8350_reg_io_map [ i ] . readable ;
}
dump ( num_regs , dest ) ;
return ret ;
}
static int wm8350_read ( struct wm8350 * wm8350 , u8 reg , int num_regs , u16 * dest )
{
int i ;
int end = reg + num_regs ;
int ret = 0 ;
int bytes = num_regs * 2 ;
if ( wm8350 - > read_dev = = NULL )
return - ENODEV ;
if ( ( reg + num_regs - 1 ) > WM8350_MAX_REGISTER ) {
dev_err ( wm8350 - > dev , " invalid reg %x \n " ,
reg + num_regs - 1 ) ;
return - EINVAL ;
}
dev_dbg ( wm8350 - > dev ,
" %s R%d(0x%2.2x) %d regs \n " , __func__ , reg , reg , num_regs ) ;
# if WM8350_BUS_DEBUG
/* we can _safely_ read any register, but warn if read not supported */
for ( i = reg ; i < end ; i + + ) {
if ( ! wm8350_reg_io_map [ i ] . readable )
dev_warn ( wm8350 - > dev ,
" reg R%d is not readable \n " , i ) ;
}
# endif
/* if any volatile registers are required, then read back all */
for ( i = reg ; i < end ; i + + )
if ( wm8350_reg_io_map [ i ] . vol )
return wm8350_phys_read ( wm8350 , reg , num_regs , dest ) ;
/* no volatiles, then cache is good */
dev_dbg ( wm8350 - > dev , " cache read \n " ) ;
memcpy ( dest , & wm8350 - > reg_cache [ reg ] , bytes ) ;
dump ( num_regs , dest ) ;
return ret ;
}
static inline int is_reg_locked ( struct wm8350 * wm8350 , u8 reg )
{
if ( reg = = WM8350_SECURITY | |
wm8350 - > reg_cache [ WM8350_SECURITY ] = = WM8350_UNLOCK_KEY )
return 0 ;
if ( ( reg = = WM8350_GPIO_CONFIGURATION_I_O ) | |
( reg > = WM8350_GPIO_FUNCTION_SELECT_1 & &
reg < = WM8350_GPIO_FUNCTION_SELECT_4 ) | |
( reg > = WM8350_BATTERY_CHARGER_CONTROL_1 & &
reg < = WM8350_BATTERY_CHARGER_CONTROL_3 ) )
return 1 ;
return 0 ;
}
static int wm8350_write ( struct wm8350 * wm8350 , u8 reg , int num_regs , u16 * src )
{
int i ;
int end = reg + num_regs ;
int bytes = num_regs * 2 ;
if ( wm8350 - > write_dev = = NULL )
return - ENODEV ;
if ( ( reg + num_regs - 1 ) > WM8350_MAX_REGISTER ) {
dev_err ( wm8350 - > dev , " invalid reg %x \n " ,
reg + num_regs - 1 ) ;
return - EINVAL ;
}
/* it's generally not a good idea to write to RO or locked registers */
for ( i = reg ; i < end ; i + + ) {
if ( ! wm8350_reg_io_map [ i ] . writable ) {
dev_err ( wm8350 - > dev ,
" attempted write to read only reg R%d \n " , i ) ;
return - EINVAL ;
}
if ( is_reg_locked ( wm8350 , i ) ) {
dev_err ( wm8350 - > dev ,
" attempted write to locked reg R%d \n " , i ) ;
return - EINVAL ;
}
src [ i - reg ] & = wm8350_reg_io_map [ i ] . writable ;
wm8350 - > reg_cache [ i ] =
( wm8350 - > reg_cache [ i ] & ~ wm8350_reg_io_map [ i ] . writable )
| src [ i - reg ] ;
src [ i - reg ] = cpu_to_be16 ( src [ i - reg ] ) ;
}
/* Actually write it out */
return wm8350 - > write_dev ( wm8350 , reg , bytes , ( char * ) src ) ;
}
/*
* Safe read , modify , write methods
*/
int wm8350_clear_bits ( struct wm8350 * wm8350 , u16 reg , u16 mask )
{
u16 data ;
int err ;
mutex_lock ( & io_mutex ) ;
err = wm8350_read ( wm8350 , reg , 1 , & data ) ;
if ( err ) {
dev_err ( wm8350 - > dev , " read from reg R%d failed \n " , reg ) ;
goto out ;
}
data & = ~ mask ;
err = wm8350_write ( wm8350 , reg , 1 , & data ) ;
if ( err )
dev_err ( wm8350 - > dev , " write to reg R%d failed \n " , reg ) ;
out :
mutex_unlock ( & io_mutex ) ;
return err ;
}
EXPORT_SYMBOL_GPL ( wm8350_clear_bits ) ;
int wm8350_set_bits ( struct wm8350 * wm8350 , u16 reg , u16 mask )
{
u16 data ;
int err ;
mutex_lock ( & io_mutex ) ;
err = wm8350_read ( wm8350 , reg , 1 , & data ) ;
if ( err ) {
dev_err ( wm8350 - > dev , " read from reg R%d failed \n " , reg ) ;
goto out ;
}
data | = mask ;
err = wm8350_write ( wm8350 , reg , 1 , & data ) ;
if ( err )
dev_err ( wm8350 - > dev , " write to reg R%d failed \n " , reg ) ;
out :
mutex_unlock ( & io_mutex ) ;
return err ;
}
EXPORT_SYMBOL_GPL ( wm8350_set_bits ) ;
u16 wm8350_reg_read ( struct wm8350 * wm8350 , int reg )
{
u16 data ;
int err ;
mutex_lock ( & io_mutex ) ;
err = wm8350_read ( wm8350 , reg , 1 , & data ) ;
if ( err )
dev_err ( wm8350 - > dev , " read from reg R%d failed \n " , reg ) ;
mutex_unlock ( & io_mutex ) ;
return data ;
}
EXPORT_SYMBOL_GPL ( wm8350_reg_read ) ;
int wm8350_reg_write ( struct wm8350 * wm8350 , int reg , u16 val )
{
int ret ;
u16 data = val ;
mutex_lock ( & io_mutex ) ;
ret = wm8350_write ( wm8350 , reg , 1 , & data ) ;
if ( ret )
dev_err ( wm8350 - > dev , " write to reg R%d failed \n " , reg ) ;
mutex_unlock ( & io_mutex ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( wm8350_reg_write ) ;
int wm8350_block_read ( struct wm8350 * wm8350 , int start_reg , int regs ,
u16 * dest )
{
int err = 0 ;
mutex_lock ( & io_mutex ) ;
err = wm8350_read ( wm8350 , start_reg , regs , dest ) ;
if ( err )
dev_err ( wm8350 - > dev , " block read starting from R%d failed \n " ,
start_reg ) ;
mutex_unlock ( & io_mutex ) ;
return err ;
}
EXPORT_SYMBOL_GPL ( wm8350_block_read ) ;
int wm8350_block_write ( struct wm8350 * wm8350 , int start_reg , int regs ,
u16 * src )
{
int ret = 0 ;
mutex_lock ( & io_mutex ) ;
ret = wm8350_write ( wm8350 , start_reg , regs , src ) ;
if ( ret )
dev_err ( wm8350 - > dev , " block write starting at R%d failed \n " ,
start_reg ) ;
mutex_unlock ( & io_mutex ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( wm8350_block_write ) ;
2008-11-08 02:57:33 +03:00
/**
* wm8350_reg_lock ( )
*
* The WM8350 has a hardware lock which can be used to prevent writes to
* some registers ( generally those which can cause particularly serious
* problems if misused ) . This function enables that lock .
*/
2008-10-10 18:58:10 +04:00
int wm8350_reg_lock ( struct wm8350 * wm8350 )
{
u16 key = WM8350_LOCK_KEY ;
int ret ;
ldbg ( __func__ ) ;
mutex_lock ( & io_mutex ) ;
ret = wm8350_write ( wm8350 , WM8350_SECURITY , 1 , & key ) ;
if ( ret )
dev_err ( wm8350 - > dev , " lock failed \n " ) ;
mutex_unlock ( & io_mutex ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( wm8350_reg_lock ) ;
2008-11-08 02:57:33 +03:00
/**
* wm8350_reg_unlock ( )
*
* The WM8350 has a hardware lock which can be used to prevent writes to
* some registers ( generally those which can cause particularly serious
* problems if misused ) . This function disables that lock so updates
* can be performed . For maximum safety this should be done only when
* required .
*/
2008-10-10 18:58:10 +04:00
int wm8350_reg_unlock ( struct wm8350 * wm8350 )
{
u16 key = WM8350_UNLOCK_KEY ;
int ret ;
ldbg ( __func__ ) ;
mutex_lock ( & io_mutex ) ;
ret = wm8350_write ( wm8350 , WM8350_SECURITY , 1 , & key ) ;
if ( ret )
dev_err ( wm8350 - > dev , " unlock failed \n " ) ;
mutex_unlock ( & io_mutex ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( wm8350_reg_unlock ) ;
2008-11-08 03:10:21 +03:00
int wm8350_read_auxadc ( struct wm8350 * wm8350 , int channel , int scale , int vref )
{
u16 reg , result = 0 ;
int tries = 5 ;
if ( channel < WM8350_AUXADC_AUX1 | | channel > WM8350_AUXADC_TEMP )
return - EINVAL ;
if ( channel > = WM8350_AUXADC_USB & & channel < = WM8350_AUXADC_TEMP
& & ( scale ! = 0 | | vref ! = 0 ) )
return - EINVAL ;
mutex_lock ( & wm8350 - > auxadc_mutex ) ;
/* Turn on the ADC */
reg = wm8350_reg_read ( wm8350 , WM8350_POWER_MGMT_5 ) ;
wm8350_reg_write ( wm8350 , WM8350_POWER_MGMT_5 , reg | WM8350_AUXADC_ENA ) ;
if ( scale | | vref ) {
reg = scale < < 13 ;
reg | = vref < < 12 ;
wm8350_reg_write ( wm8350 , WM8350_AUX1_READBACK + channel , reg ) ;
}
reg = wm8350_reg_read ( wm8350 , WM8350_DIGITISER_CONTROL_1 ) ;
reg | = 1 < < channel | WM8350_AUXADC_POLL ;
wm8350_reg_write ( wm8350 , WM8350_DIGITISER_CONTROL_1 , reg ) ;
do {
schedule_timeout_interruptible ( 1 ) ;
reg = wm8350_reg_read ( wm8350 , WM8350_DIGITISER_CONTROL_1 ) ;
2009-03-01 22:11:58 +03:00
} while ( ( reg & WM8350_AUXADC_POLL ) & & - - tries ) ;
2008-11-08 03:10:21 +03:00
if ( ! tries )
dev_err ( wm8350 - > dev , " adc chn %d read timeout \n " , channel ) ;
else
result = wm8350_reg_read ( wm8350 ,
WM8350_AUX1_READBACK + channel ) ;
/* Turn off the ADC */
reg = wm8350_reg_read ( wm8350 , WM8350_POWER_MGMT_5 ) ;
wm8350_reg_write ( wm8350 , WM8350_POWER_MGMT_5 ,
reg & ~ WM8350_AUXADC_ENA ) ;
mutex_unlock ( & wm8350 - > auxadc_mutex ) ;
return result & WM8350_AUXADC_DATA1_MASK ;
}
EXPORT_SYMBOL_GPL ( wm8350_read_auxadc ) ;
2008-10-10 18:58:10 +04:00
/*
* Cache is always host endian .
*/
2008-12-19 01:09:50 +03:00
static int wm8350_create_cache ( struct wm8350 * wm8350 , int type , int mode )
2008-10-10 18:58:10 +04:00
{
int i , ret = 0 ;
u16 value ;
const u16 * reg_map ;
2008-12-19 01:09:50 +03:00
switch ( type ) {
2008-10-10 18:58:10 +04:00
case 0 :
2008-12-19 01:09:50 +03:00
switch ( mode ) {
# ifdef CONFIG_MFD_WM8350_CONFIG_MODE_0
case 0 :
reg_map = wm8350_mode0_defaults ;
break ;
2008-10-10 18:58:10 +04:00
# endif
# ifdef CONFIG_MFD_WM8350_CONFIG_MODE_1
2008-12-19 01:09:50 +03:00
case 1 :
reg_map = wm8350_mode1_defaults ;
break ;
2008-10-10 18:58:10 +04:00
# endif
# ifdef CONFIG_MFD_WM8350_CONFIG_MODE_2
2008-12-19 01:09:50 +03:00
case 2 :
reg_map = wm8350_mode2_defaults ;
break ;
2008-10-10 18:58:10 +04:00
# endif
# ifdef CONFIG_MFD_WM8350_CONFIG_MODE_3
2008-12-19 01:09:50 +03:00
case 3 :
reg_map = wm8350_mode3_defaults ;
break ;
2008-10-10 18:58:10 +04:00
# endif
2008-12-19 01:09:50 +03:00
default :
dev_err ( wm8350 - > dev ,
" WM8350 configuration mode %d not supported \n " ,
mode ) ;
return - EINVAL ;
}
2008-12-19 01:20:14 +03:00
break ;
2008-12-19 01:09:50 +03:00
2008-12-19 01:12:28 +03:00
case 1 :
switch ( mode ) {
# ifdef CONFIG_MFD_WM8351_CONFIG_MODE_0
case 0 :
reg_map = wm8351_mode0_defaults ;
break ;
# endif
# ifdef CONFIG_MFD_WM8351_CONFIG_MODE_1
case 1 :
reg_map = wm8351_mode1_defaults ;
break ;
# endif
# ifdef CONFIG_MFD_WM8351_CONFIG_MODE_2
case 2 :
reg_map = wm8351_mode2_defaults ;
break ;
# endif
# ifdef CONFIG_MFD_WM8351_CONFIG_MODE_3
case 3 :
reg_map = wm8351_mode3_defaults ;
break ;
# endif
default :
dev_err ( wm8350 - > dev ,
" WM8351 configuration mode %d not supported \n " ,
mode ) ;
return - EINVAL ;
}
break ;
2008-12-19 01:09:50 +03:00
case 2 :
switch ( mode ) {
# ifdef CONFIG_MFD_WM8352_CONFIG_MODE_0
case 0 :
reg_map = wm8352_mode0_defaults ;
break ;
# endif
# ifdef CONFIG_MFD_WM8352_CONFIG_MODE_1
case 1 :
reg_map = wm8352_mode1_defaults ;
break ;
# endif
# ifdef CONFIG_MFD_WM8352_CONFIG_MODE_2
case 2 :
reg_map = wm8352_mode2_defaults ;
break ;
# endif
# ifdef CONFIG_MFD_WM8352_CONFIG_MODE_3
case 3 :
reg_map = wm8352_mode3_defaults ;
break ;
# endif
default :
dev_err ( wm8350 - > dev ,
" WM8352 configuration mode %d not supported \n " ,
mode ) ;
return - EINVAL ;
}
break ;
2008-10-10 18:58:10 +04:00
default :
2008-12-19 01:09:50 +03:00
dev_err ( wm8350 - > dev ,
" WM835x configuration mode %d not supported \n " ,
2008-10-10 18:58:10 +04:00
mode ) ;
return - EINVAL ;
}
wm8350 - > reg_cache =
2009-02-05 00:43:55 +03:00
kmalloc ( sizeof ( u16 ) * ( WM8350_MAX_REGISTER + 1 ) , GFP_KERNEL ) ;
2008-10-10 18:58:10 +04:00
if ( wm8350 - > reg_cache = = NULL )
return - ENOMEM ;
/* Read the initial cache state back from the device - this is
* a PMIC so the device many not be in a virgin state and we
* can ' t rely on the silicon values .
*/
2009-02-05 00:43:55 +03:00
ret = wm8350 - > read_dev ( wm8350 , 0 ,
sizeof ( u16 ) * ( WM8350_MAX_REGISTER + 1 ) ,
wm8350 - > reg_cache ) ;
if ( ret < 0 ) {
dev_err ( wm8350 - > dev ,
" failed to read initial cache values \n " ) ;
goto out ;
}
/* Mask out uncacheable/unreadable bits and the audio. */
2008-10-10 18:58:10 +04:00
for ( i = 0 ; i < WM8350_MAX_REGISTER ; i + + ) {
if ( wm8350_reg_io_map [ i ] . readable & &
( i < WM8350_CLOCK_CONTROL_1 | | i > WM8350_AIF_TEST ) ) {
2009-02-05 00:43:55 +03:00
value = be16_to_cpu ( wm8350 - > reg_cache [ i ] ) ;
2008-10-10 18:58:10 +04:00
value & = wm8350_reg_io_map [ i ] . readable ;
wm8350 - > reg_cache [ i ] = value ;
} else
wm8350 - > reg_cache [ i ] = reg_map [ i ] ;
}
out :
return ret ;
}
2008-10-10 18:58:16 +04:00
/*
* Register a client device . This is non - fatal since there is no need to
* fail the entire device init due to a single platform device failing .
*/
static void wm8350_client_dev_register ( struct wm8350 * wm8350 ,
const char * name ,
struct platform_device * * pdev )
{
int ret ;
* pdev = platform_device_alloc ( name , - 1 ) ;
if ( pdev = = NULL ) {
dev_err ( wm8350 - > dev , " Failed to allocate %s \n " , name ) ;
return ;
}
( * pdev ) - > dev . parent = wm8350 - > dev ;
platform_set_drvdata ( * pdev , wm8350 ) ;
ret = platform_device_add ( * pdev ) ;
if ( ret ! = 0 ) {
dev_err ( wm8350 - > dev , " Failed to register %s: %d \n " , name , ret ) ;
platform_device_put ( * pdev ) ;
* pdev = NULL ;
}
}
2008-10-10 18:58:14 +04:00
int wm8350_device_init ( struct wm8350 * wm8350 , int irq ,
2008-10-10 18:58:13 +04:00
struct wm8350_platform_data * pdata )
2008-10-10 18:58:10 +04:00
{
2009-02-04 23:09:38 +03:00
int ret ;
2008-11-24 22:22:58 +03:00
u16 id1 , id2 , mask_rev ;
u16 cust_id , mode , chip_rev ;
2008-10-10 18:58:10 +04:00
/* get WM8350 revision and config mode */
2009-02-04 23:09:38 +03:00
ret = wm8350 - > read_dev ( wm8350 , WM8350_RESET_ID , sizeof ( id1 ) , & id1 ) ;
if ( ret ! = 0 ) {
dev_err ( wm8350 - > dev , " Failed to read ID: %d \n " , ret ) ;
goto err ;
}
ret = wm8350 - > read_dev ( wm8350 , WM8350_ID , sizeof ( id2 ) , & id2 ) ;
if ( ret ! = 0 ) {
dev_err ( wm8350 - > dev , " Failed to read ID: %d \n " , ret ) ;
goto err ;
}
ret = wm8350 - > read_dev ( wm8350 , WM8350_REVISION , sizeof ( mask_rev ) ,
& mask_rev ) ;
if ( ret ! = 0 ) {
dev_err ( wm8350 - > dev , " Failed to read revision: %d \n " , ret ) ;
goto err ;
}
2008-10-10 18:58:10 +04:00
id1 = be16_to_cpu ( id1 ) ;
id2 = be16_to_cpu ( id2 ) ;
2008-11-24 22:22:58 +03:00
mask_rev = be16_to_cpu ( mask_rev ) ;
2008-10-10 18:58:10 +04:00
2008-11-24 22:22:58 +03:00
if ( id1 ! = 0x6143 ) {
dev_err ( wm8350 - > dev ,
" Device with ID %x is not a WM8350 \n " , id1 ) ;
ret = - ENODEV ;
goto err ;
}
mode = id2 & WM8350_CONF_STS_MASK > > 10 ;
cust_id = id2 & WM8350_CUST_ID_MASK ;
chip_rev = ( id2 & WM8350_CHIP_REV_MASK ) > > 12 ;
dev_info ( wm8350 - > dev ,
" CONF_STS %d, CUST_ID %d, MASK_REV %d, CHIP_REV %d \n " ,
mode , cust_id , mask_rev , chip_rev ) ;
if ( cust_id ! = 0 ) {
dev_err ( wm8350 - > dev , " Unsupported CUST_ID \n " ) ;
ret = - ENODEV ;
goto err ;
}
switch ( mask_rev ) {
case 0 :
2008-12-19 01:12:16 +03:00
wm8350 - > pmic . max_dcdc = WM8350_DCDC_6 ;
wm8350 - > pmic . max_isink = WM8350_ISINK_B ;
2008-11-24 22:22:58 +03:00
switch ( chip_rev ) {
2008-10-10 18:58:10 +04:00
case WM8350_REV_E :
2008-11-24 22:22:58 +03:00
dev_info ( wm8350 - > dev , " WM8350 Rev E \n " ) ;
2008-10-10 18:58:10 +04:00
break ;
case WM8350_REV_F :
2008-11-24 22:22:58 +03:00
dev_info ( wm8350 - > dev , " WM8350 Rev F \n " ) ;
2008-10-10 18:58:10 +04:00
break ;
case WM8350_REV_G :
2008-11-24 22:22:58 +03:00
dev_info ( wm8350 - > dev , " WM8350 Rev G \n " ) ;
2008-11-24 22:20:30 +03:00
wm8350 - > power . rev_g_coeff = 1 ;
2008-10-10 18:58:10 +04:00
break ;
2008-11-08 03:10:16 +03:00
case WM8350_REV_H :
2008-11-24 22:22:58 +03:00
dev_info ( wm8350 - > dev , " WM8350 Rev H \n " ) ;
2008-11-24 22:20:30 +03:00
wm8350 - > power . rev_g_coeff = 1 ;
2008-11-08 03:10:16 +03:00
break ;
2008-10-10 18:58:10 +04:00
default :
/* For safety we refuse to run on unknown hardware */
2008-11-24 22:22:58 +03:00
dev_err ( wm8350 - > dev , " Unknown WM8350 CHIP_REV \n " ) ;
2008-10-10 18:58:10 +04:00
ret = - ENODEV ;
goto err ;
}
2008-11-24 22:22:58 +03:00
break ;
2008-12-19 01:12:28 +03:00
case 1 :
wm8350 - > pmic . max_dcdc = WM8350_DCDC_4 ;
wm8350 - > pmic . max_isink = WM8350_ISINK_A ;
switch ( chip_rev ) {
case 0 :
dev_info ( wm8350 - > dev , " WM8351 Rev A \n " ) ;
wm8350 - > power . rev_g_coeff = 1 ;
break ;
2009-03-13 00:31:36 +03:00
case 1 :
dev_info ( wm8350 - > dev , " WM8351 Rev B \n " ) ;
wm8350 - > power . rev_g_coeff = 1 ;
break ;
2008-12-19 01:12:28 +03:00
default :
dev_err ( wm8350 - > dev , " Unknown WM8351 CHIP_REV \n " ) ;
ret = - ENODEV ;
goto err ;
}
break ;
2008-12-19 01:09:50 +03:00
case 2 :
2008-12-19 01:12:16 +03:00
wm8350 - > pmic . max_dcdc = WM8350_DCDC_6 ;
wm8350 - > pmic . max_isink = WM8350_ISINK_B ;
2008-12-19 01:09:50 +03:00
switch ( chip_rev ) {
case 0 :
dev_info ( wm8350 - > dev , " WM8352 Rev A \n " ) ;
wm8350 - > power . rev_g_coeff = 1 ;
break ;
default :
dev_err ( wm8350 - > dev , " Unknown WM8352 CHIP_REV \n " ) ;
ret = - ENODEV ;
goto err ;
}
break ;
2008-11-24 22:22:58 +03:00
default :
dev_err ( wm8350 - > dev , " Unknown MASK_REV \n " ) ;
2008-10-10 18:58:10 +04:00
ret = - ENODEV ;
goto err ;
}
2008-12-19 01:09:50 +03:00
ret = wm8350_create_cache ( wm8350 , mask_rev , mode ) ;
2008-10-10 18:58:10 +04:00
if ( ret < 0 ) {
2008-11-24 22:22:58 +03:00
dev_err ( wm8350 - > dev , " Failed to create register cache \n " ) ;
2008-10-10 18:58:10 +04:00
return ret ;
}
2008-11-08 03:10:21 +03:00
mutex_init ( & wm8350 - > auxadc_mutex ) ;
2009-02-06 17:27:13 +03:00
2009-10-12 19:15:09 +04:00
ret = wm8350_irq_init ( wm8350 , irq , pdata ) ;
if ( ret < 0 )
2008-10-10 18:58:14 +04:00
goto err ;
2009-02-04 22:49:52 +03:00
if ( pdata & & pdata - > init ) {
ret = pdata - > init ( wm8350 ) ;
if ( ret ! = 0 ) {
dev_err ( wm8350 - > dev , " Platform init() failed: %d \n " ,
ret ) ;
2009-10-12 19:15:09 +04:00
goto err_irq ;
2009-02-04 22:49:52 +03:00
}
}
2008-10-10 18:58:14 +04:00
wm8350_reg_write ( wm8350 , WM8350_SYSTEM_INTERRUPTS_MASK , 0x0 ) ;
2008-10-13 18:45:22 +04:00
wm8350_client_dev_register ( wm8350 , " wm8350-codec " ,
& ( wm8350 - > codec . pdev ) ) ;
wm8350_client_dev_register ( wm8350 , " wm8350-gpio " ,
& ( wm8350 - > gpio . pdev ) ) ;
2009-07-20 15:43:45 +04:00
wm8350_client_dev_register ( wm8350 , " wm8350-hwmon " ,
& ( wm8350 - > hwmon . pdev ) ) ;
2008-10-13 18:45:22 +04:00
wm8350_client_dev_register ( wm8350 , " wm8350-power " ,
& ( wm8350 - > power . pdev ) ) ;
wm8350_client_dev_register ( wm8350 , " wm8350-rtc " , & ( wm8350 - > rtc . pdev ) ) ;
wm8350_client_dev_register ( wm8350 , " wm8350-wdt " , & ( wm8350 - > wdt . pdev ) ) ;
2008-10-10 18:58:10 +04:00
return 0 ;
2009-10-12 19:15:09 +04:00
err_irq :
wm8350_irq_exit ( wm8350 ) ;
2008-10-10 18:58:10 +04:00
err :
kfree ( wm8350 - > reg_cache ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( wm8350_device_init ) ;
void wm8350_device_exit ( struct wm8350 * wm8350 )
{
2008-10-10 18:58:15 +04:00
int i ;
2008-12-04 19:52:33 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( wm8350 - > pmic . led ) ; i + + )
platform_device_unregister ( wm8350 - > pmic . led [ i ] . pdev ) ;
2008-10-10 18:58:15 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( wm8350 - > pmic . pdev ) ; i + + )
2008-10-13 18:45:22 +04:00
platform_device_unregister ( wm8350 - > pmic . pdev [ i ] ) ;
platform_device_unregister ( wm8350 - > wdt . pdev ) ;
platform_device_unregister ( wm8350 - > rtc . pdev ) ;
platform_device_unregister ( wm8350 - > power . pdev ) ;
2009-07-20 15:43:45 +04:00
platform_device_unregister ( wm8350 - > hwmon . pdev ) ;
2008-10-13 18:45:22 +04:00
platform_device_unregister ( wm8350 - > gpio . pdev ) ;
platform_device_unregister ( wm8350 - > codec . pdev ) ;
2008-10-10 18:58:15 +04:00
2009-10-12 19:15:09 +04:00
wm8350_irq_exit ( wm8350 ) ;
2008-10-10 18:58:10 +04:00
kfree ( wm8350 - > reg_cache ) ;
}
EXPORT_SYMBOL_GPL ( wm8350_device_exit ) ;
2008-10-10 18:58:14 +04:00
MODULE_DESCRIPTION ( " WM8350 AudioPlus PMIC core driver " ) ;
2008-10-10 18:58:10 +04:00
MODULE_LICENSE ( " GPL " ) ;