2012-06-19 19:31:53 +04:00
/*
* Arizona core driver
*
* Copyright 2012 Wolfson Microelectronics plc
*
* Author : Mark Brown < broonie @ opensource . wolfsonmicro . 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 .
*/
2016-09-02 18:52:46 +03:00
# include <linux/clk.h>
2012-06-19 19:31:53 +04:00
# include <linux/delay.h>
2012-07-09 02:31:36 +04:00
# include <linux/err.h>
2012-06-19 19:31:53 +04:00
# include <linux/gpio.h>
# include <linux/interrupt.h>
# include <linux/mfd/core.h>
# include <linux/module.h>
2013-03-25 04:11:27 +04:00
# include <linux/of.h>
# include <linux/of_device.h>
# include <linux/of_gpio.h>
2012-06-19 19:31:53 +04:00
# include <linux/pm_runtime.h>
# include <linux/regmap.h>
# include <linux/regulator/consumer.h>
2013-04-23 22:44:16 +04:00
# include <linux/regulator/machine.h>
2012-06-19 19:31:53 +04:00
# include <linux/slab.h>
2015-10-02 15:29:13 +03:00
# include <linux/platform_device.h>
2012-06-19 19:31:53 +04:00
# include <linux/mfd/arizona/core.h>
# include <linux/mfd/arizona/registers.h>
# include "arizona.h"
2015-08-11 11:34:31 +03:00
static const char * const wm5102_core_supplies [ ] = {
2012-06-19 19:31:53 +04:00
" AVDD " ,
" DBVDD1 " ,
} ;
int arizona_clk32k_enable ( struct arizona * arizona )
{
int ret = 0 ;
mutex_lock ( & arizona - > clk_lock ) ;
arizona - > clk32k_ref + + ;
2013-03-19 17:47:47 +04:00
if ( arizona - > clk32k_ref = = 1 ) {
switch ( arizona - > pdata . clk32k_src ) {
case ARIZONA_32KZ_MCLK1 :
ret = pm_runtime_get_sync ( arizona - > dev ) ;
if ( ret ! = 0 )
2016-09-02 18:52:46 +03:00
goto err_ref ;
ret = clk_prepare_enable ( arizona - > mclk [ ARIZONA_MCLK1 ] ) ;
if ( ret ! = 0 )
goto err_pm ;
break ;
case ARIZONA_32KZ_MCLK2 :
ret = clk_prepare_enable ( arizona - > mclk [ ARIZONA_MCLK2 ] ) ;
if ( ret ! = 0 )
goto err_ref ;
2013-03-19 17:47:47 +04:00
break ;
}
2012-06-19 19:31:53 +04:00
ret = regmap_update_bits ( arizona - > regmap , ARIZONA_CLOCK_32K_1 ,
ARIZONA_CLK_32K_ENA ,
ARIZONA_CLK_32K_ENA ) ;
2013-03-19 17:47:47 +04:00
}
2012-06-19 19:31:53 +04:00
2016-09-02 18:52:46 +03:00
err_pm :
pm_runtime_put_sync ( arizona - > dev ) ;
err_ref :
2012-06-19 19:31:53 +04:00
if ( ret ! = 0 )
arizona - > clk32k_ref - - ;
mutex_unlock ( & arizona - > clk_lock ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( arizona_clk32k_enable ) ;
int arizona_clk32k_disable ( struct arizona * arizona )
{
mutex_lock ( & arizona - > clk_lock ) ;
BUG_ON ( arizona - > clk32k_ref < = 0 ) ;
arizona - > clk32k_ref - - ;
2013-03-19 17:47:47 +04:00
if ( arizona - > clk32k_ref = = 0 ) {
2012-06-19 19:31:53 +04:00
regmap_update_bits ( arizona - > regmap , ARIZONA_CLOCK_32K_1 ,
ARIZONA_CLK_32K_ENA , 0 ) ;
2013-03-19 17:47:47 +04:00
switch ( arizona - > pdata . clk32k_src ) {
case ARIZONA_32KZ_MCLK1 :
pm_runtime_put_sync ( arizona - > dev ) ;
2016-09-02 18:52:46 +03:00
clk_disable_unprepare ( arizona - > mclk [ ARIZONA_MCLK1 ] ) ;
break ;
case ARIZONA_32KZ_MCLK2 :
clk_disable_unprepare ( arizona - > mclk [ ARIZONA_MCLK2 ] ) ;
2013-03-19 17:47:47 +04:00
break ;
}
}
2012-06-19 19:31:53 +04:00
mutex_unlock ( & arizona - > clk_lock ) ;
2015-09-29 14:26:02 +03:00
return 0 ;
2012-06-19 19:31:53 +04:00
}
EXPORT_SYMBOL_GPL ( arizona_clk32k_disable ) ;
static irqreturn_t arizona_clkgen_err ( int irq , void * data )
{
struct arizona * arizona = data ;
dev_err ( arizona - > dev , " CLKGEN error \n " ) ;
return IRQ_HANDLED ;
}
static irqreturn_t arizona_underclocked ( int irq , void * data )
{
struct arizona * arizona = data ;
unsigned int val ;
int ret ;
ret = regmap_read ( arizona - > regmap , ARIZONA_INTERRUPT_RAW_STATUS_8 ,
& val ) ;
if ( ret ! = 0 ) {
dev_err ( arizona - > dev , " Failed to read underclock status: %d \n " ,
ret ) ;
return IRQ_NONE ;
}
if ( val & ARIZONA_AIF3_UNDERCLOCKED_STS )
dev_err ( arizona - > dev , " AIF3 underclocked \n " ) ;
if ( val & ARIZONA_AIF2_UNDERCLOCKED_STS )
2012-11-20 08:46:20 +04:00
dev_err ( arizona - > dev , " AIF2 underclocked \n " ) ;
if ( val & ARIZONA_AIF1_UNDERCLOCKED_STS )
2012-06-19 19:31:53 +04:00
dev_err ( arizona - > dev , " AIF1 underclocked \n " ) ;
2014-07-15 14:21:49 +04:00
if ( val & ARIZONA_ISRC3_UNDERCLOCKED_STS )
dev_err ( arizona - > dev , " ISRC3 underclocked \n " ) ;
2012-06-19 19:31:53 +04:00
if ( val & ARIZONA_ISRC2_UNDERCLOCKED_STS )
dev_err ( arizona - > dev , " ISRC2 underclocked \n " ) ;
if ( val & ARIZONA_ISRC1_UNDERCLOCKED_STS )
dev_err ( arizona - > dev , " ISRC1 underclocked \n " ) ;
if ( val & ARIZONA_FX_UNDERCLOCKED_STS )
dev_err ( arizona - > dev , " FX underclocked \n " ) ;
if ( val & ARIZONA_ASRC_UNDERCLOCKED_STS )
dev_err ( arizona - > dev , " ASRC underclocked \n " ) ;
if ( val & ARIZONA_DAC_UNDERCLOCKED_STS )
dev_err ( arizona - > dev , " DAC underclocked \n " ) ;
if ( val & ARIZONA_ADC_UNDERCLOCKED_STS )
dev_err ( arizona - > dev , " ADC underclocked \n " ) ;
if ( val & ARIZONA_MIXER_UNDERCLOCKED_STS )
2013-01-27 20:32:53 +04:00
dev_err ( arizona - > dev , " Mixer dropped sample \n " ) ;
2012-06-19 19:31:53 +04:00
return IRQ_HANDLED ;
}
static irqreturn_t arizona_overclocked ( int irq , void * data )
{
struct arizona * arizona = data ;
2015-07-03 18:16:35 +03:00
unsigned int val [ 3 ] ;
2012-06-19 19:31:53 +04:00
int ret ;
2015-08-11 11:34:31 +03:00
2012-06-19 19:31:53 +04:00
ret = regmap_bulk_read ( arizona - > regmap , ARIZONA_INTERRUPT_RAW_STATUS_6 ,
2015-07-03 18:16:35 +03:00
& val [ 0 ] , 3 ) ;
2012-06-19 19:31:53 +04:00
if ( ret ! = 0 ) {
dev_err ( arizona - > dev , " Failed to read overclock status: %d \n " ,
ret ) ;
return IRQ_NONE ;
}
2015-07-03 18:16:35 +03:00
switch ( arizona - > type ) {
case WM8998 :
case WM1814 :
/* Some bits are shifted on WM8998,
* rearrange to match the standard bit layout
*/
val [ 0 ] = ( ( val [ 0 ] & 0x60e0 ) > > 1 ) |
( ( val [ 0 ] & 0x1e00 ) > > 2 ) |
( val [ 0 ] & 0x000f ) ;
break ;
default :
break ;
}
2012-06-19 19:31:53 +04:00
if ( val [ 0 ] & ARIZONA_PWM_OVERCLOCKED_STS )
dev_err ( arizona - > dev , " PWM overclocked \n " ) ;
if ( val [ 0 ] & ARIZONA_FX_CORE_OVERCLOCKED_STS )
dev_err ( arizona - > dev , " FX core overclocked \n " ) ;
if ( val [ 0 ] & ARIZONA_DAC_SYS_OVERCLOCKED_STS )
dev_err ( arizona - > dev , " DAC SYS overclocked \n " ) ;
if ( val [ 0 ] & ARIZONA_DAC_WARP_OVERCLOCKED_STS )
dev_err ( arizona - > dev , " DAC WARP overclocked \n " ) ;
if ( val [ 0 ] & ARIZONA_ADC_OVERCLOCKED_STS )
dev_err ( arizona - > dev , " ADC overclocked \n " ) ;
if ( val [ 0 ] & ARIZONA_MIXER_OVERCLOCKED_STS )
dev_err ( arizona - > dev , " Mixer overclocked \n " ) ;
if ( val [ 0 ] & ARIZONA_AIF3_SYNC_OVERCLOCKED_STS )
dev_err ( arizona - > dev , " AIF3 overclocked \n " ) ;
if ( val [ 0 ] & ARIZONA_AIF2_SYNC_OVERCLOCKED_STS )
dev_err ( arizona - > dev , " AIF2 overclocked \n " ) ;
if ( val [ 0 ] & ARIZONA_AIF1_SYNC_OVERCLOCKED_STS )
dev_err ( arizona - > dev , " AIF1 overclocked \n " ) ;
if ( val [ 0 ] & ARIZONA_PAD_CTRL_OVERCLOCKED_STS )
dev_err ( arizona - > dev , " Pad control overclocked \n " ) ;
if ( val [ 1 ] & ARIZONA_SLIMBUS_SUBSYS_OVERCLOCKED_STS )
dev_err ( arizona - > dev , " Slimbus subsystem overclocked \n " ) ;
if ( val [ 1 ] & ARIZONA_SLIMBUS_ASYNC_OVERCLOCKED_STS )
dev_err ( arizona - > dev , " Slimbus async overclocked \n " ) ;
if ( val [ 1 ] & ARIZONA_SLIMBUS_SYNC_OVERCLOCKED_STS )
dev_err ( arizona - > dev , " Slimbus sync overclocked \n " ) ;
if ( val [ 1 ] & ARIZONA_ASRC_ASYNC_SYS_OVERCLOCKED_STS )
dev_err ( arizona - > dev , " ASRC async system overclocked \n " ) ;
if ( val [ 1 ] & ARIZONA_ASRC_ASYNC_WARP_OVERCLOCKED_STS )
dev_err ( arizona - > dev , " ASRC async WARP overclocked \n " ) ;
if ( val [ 1 ] & ARIZONA_ASRC_SYNC_SYS_OVERCLOCKED_STS )
dev_err ( arizona - > dev , " ASRC sync system overclocked \n " ) ;
if ( val [ 1 ] & ARIZONA_ASRC_SYNC_WARP_OVERCLOCKED_STS )
dev_err ( arizona - > dev , " ASRC sync WARP overclocked \n " ) ;
if ( val [ 1 ] & ARIZONA_ADSP2_1_OVERCLOCKED_STS )
dev_err ( arizona - > dev , " DSP1 overclocked \n " ) ;
2014-07-15 14:21:49 +04:00
if ( val [ 1 ] & ARIZONA_ISRC3_OVERCLOCKED_STS )
dev_err ( arizona - > dev , " ISRC3 overclocked \n " ) ;
2012-06-19 19:31:53 +04:00
if ( val [ 1 ] & ARIZONA_ISRC2_OVERCLOCKED_STS )
dev_err ( arizona - > dev , " ISRC2 overclocked \n " ) ;
if ( val [ 1 ] & ARIZONA_ISRC1_OVERCLOCKED_STS )
dev_err ( arizona - > dev , " ISRC1 overclocked \n " ) ;
2015-07-03 18:16:35 +03:00
if ( val [ 2 ] & ARIZONA_SPDIF_OVERCLOCKED_STS )
dev_err ( arizona - > dev , " SPDIF overclocked \n " ) ;
2012-06-19 19:31:53 +04:00
return IRQ_HANDLED ;
}
2017-03-15 17:58:38 +03:00
# define ARIZONA_REG_POLL_DELAY_US 7500
2013-03-26 21:38:45 +04:00
static int arizona_poll_reg ( struct arizona * arizona ,
2017-03-15 17:58:38 +03:00
int timeout_ms , unsigned int reg ,
2013-03-26 21:38:45 +04:00
unsigned int mask , unsigned int target )
2012-06-19 19:31:53 +04:00
{
2013-03-26 21:38:45 +04:00
unsigned int val = 0 ;
2017-03-15 17:58:38 +03:00
int ret ;
2013-03-26 21:38:45 +04:00
2017-03-15 17:58:38 +03:00
ret = regmap_read_poll_timeout ( arizona - > regmap ,
ARIZONA_INTERRUPT_RAW_STATUS_5 , val ,
( ( val & mask ) = = target ) ,
ARIZONA_REG_POLL_DELAY_US ,
timeout_ms * 1000 ) ;
if ( ret )
dev_err ( arizona - > dev , " Polling reg 0x%x timed out: %x \n " ,
reg , val ) ;
2012-06-19 19:31:53 +04:00
2017-03-15 17:58:38 +03:00
return ret ;
2013-03-26 21:38:45 +04:00
}
static int arizona_wait_for_boot ( struct arizona * arizona )
{
int ret ;
/*
* We can ' t use an interrupt as we need to runtime resume to do so ,
* we won ' t race with the interrupt handler as it ' ll be blocked on
* runtime resume .
*/
2017-03-15 17:58:38 +03:00
ret = arizona_poll_reg ( arizona , 30 , ARIZONA_INTERRUPT_RAW_STATUS_5 ,
2013-03-26 21:38:45 +04:00
ARIZONA_BOOT_DONE_STS , ARIZONA_BOOT_DONE_STS ) ;
if ( ! ret )
2012-06-19 19:31:53 +04:00
regmap_write ( arizona - > regmap , ARIZONA_INTERRUPT_STATUS_5 ,
ARIZONA_BOOT_DONE_STS ) ;
pm_runtime_mark_last_busy ( arizona - > dev ) ;
2013-03-26 21:38:45 +04:00
return ret ;
2012-06-19 19:31:53 +04:00
}
2015-05-11 15:58:02 +03:00
static inline void arizona_enable_reset ( struct arizona * arizona )
{
if ( arizona - > pdata . reset )
gpio_set_value_cansleep ( arizona - > pdata . reset , 0 ) ;
}
static void arizona_disable_reset ( struct arizona * arizona )
{
if ( arizona - > pdata . reset ) {
2015-05-11 15:58:10 +03:00
switch ( arizona - > type ) {
case WM5110 :
case WM8280 :
/* Meet requirements for minimum reset duration */
2015-10-28 15:42:30 +03:00
usleep_range ( 5000 , 10000 ) ;
2015-05-11 15:58:10 +03:00
break ;
default :
break ;
}
2015-05-11 15:58:02 +03:00
gpio_set_value_cansleep ( arizona - > pdata . reset , 1 ) ;
2015-10-28 15:42:30 +03:00
usleep_range ( 1000 , 5000 ) ;
2015-05-11 15:58:02 +03:00
}
}
2015-05-11 15:58:05 +03:00
struct arizona_sysclk_state {
unsigned int fll ;
unsigned int sysclk ;
} ;
static int arizona_enable_freerun_sysclk ( struct arizona * arizona ,
struct arizona_sysclk_state * state )
2013-03-26 22:46:15 +04:00
{
int ret , err ;
/* Cache existing FLL and SYSCLK settings */
2015-05-11 15:58:05 +03:00
ret = regmap_read ( arizona - > regmap , ARIZONA_FLL1_CONTROL_1 , & state - > fll ) ;
2015-05-11 15:58:04 +03:00
if ( ret ) {
2013-03-26 22:46:15 +04:00
dev_err ( arizona - > dev , " Failed to cache FLL settings: %d \n " ,
ret ) ;
return ret ;
}
2015-05-11 15:58:05 +03:00
ret = regmap_read ( arizona - > regmap , ARIZONA_SYSTEM_CLOCK_1 ,
& state - > sysclk ) ;
2015-05-11 15:58:04 +03:00
if ( ret ) {
2013-03-26 22:46:15 +04:00
dev_err ( arizona - > dev , " Failed to cache SYSCLK settings: %d \n " ,
ret ) ;
return ret ;
}
/* Start up SYSCLK using the FLL in free running mode */
ret = regmap_write ( arizona - > regmap , ARIZONA_FLL1_CONTROL_1 ,
ARIZONA_FLL1_ENA | ARIZONA_FLL1_FREERUN ) ;
2015-05-11 15:58:04 +03:00
if ( ret ) {
2013-03-26 22:46:15 +04:00
dev_err ( arizona - > dev ,
" Failed to start FLL in freerunning mode: %d \n " ,
ret ) ;
return ret ;
}
2017-03-15 17:58:38 +03:00
ret = arizona_poll_reg ( arizona , 180 , ARIZONA_INTERRUPT_RAW_STATUS_5 ,
2013-03-26 22:46:15 +04:00
ARIZONA_FLL1_CLOCK_OK_STS ,
ARIZONA_FLL1_CLOCK_OK_STS ) ;
2017-03-15 17:58:36 +03:00
if ( ret )
2013-03-26 22:46:15 +04:00
goto err_fll ;
ret = regmap_write ( arizona - > regmap , ARIZONA_SYSTEM_CLOCK_1 , 0x0144 ) ;
2015-05-11 15:58:04 +03:00
if ( ret ) {
2013-03-26 22:46:15 +04:00
dev_err ( arizona - > dev , " Failed to start SYSCLK: %d \n " , ret ) ;
goto err_fll ;
}
2015-05-11 15:58:05 +03:00
return 0 ;
err_fll :
err = regmap_write ( arizona - > regmap , ARIZONA_FLL1_CONTROL_1 , state - > fll ) ;
if ( err )
dev_err ( arizona - > dev ,
" Failed to re-apply old FLL settings: %d \n " , err ) ;
return ret ;
}
static int arizona_disable_freerun_sysclk ( struct arizona * arizona ,
struct arizona_sysclk_state * state )
{
int ret ;
ret = regmap_write ( arizona - > regmap , ARIZONA_SYSTEM_CLOCK_1 ,
state - > sysclk ) ;
if ( ret ) {
dev_err ( arizona - > dev ,
" Failed to re-apply old SYSCLK settings: %d \n " , ret ) ;
return ret ;
}
ret = regmap_write ( arizona - > regmap , ARIZONA_FLL1_CONTROL_1 , state - > fll ) ;
if ( ret ) {
dev_err ( arizona - > dev ,
" Failed to re-apply old FLL settings: %d \n " , ret ) ;
return ret ;
}
return 0 ;
}
static int wm5102_apply_hardware_patch ( struct arizona * arizona )
{
struct arizona_sysclk_state state ;
int err , ret ;
ret = arizona_enable_freerun_sysclk ( arizona , & state ) ;
if ( ret )
return ret ;
2013-03-26 22:46:15 +04:00
/* Start the write sequencer and wait for it to finish */
ret = regmap_write ( arizona - > regmap , ARIZONA_WRITE_SEQUENCER_CTRL_0 ,
2015-05-11 15:58:04 +03:00
ARIZONA_WSEQ_ENA | ARIZONA_WSEQ_START | 160 ) ;
if ( ret ) {
2013-03-26 22:46:15 +04:00
dev_err ( arizona - > dev , " Failed to start write sequencer: %d \n " ,
ret ) ;
2015-05-11 15:58:05 +03:00
goto err ;
2013-03-26 22:46:15 +04:00
}
2015-05-11 15:58:05 +03:00
2017-03-15 17:58:38 +03:00
ret = arizona_poll_reg ( arizona , 30 , ARIZONA_WRITE_SEQUENCER_CTRL_1 ,
2013-03-26 22:46:15 +04:00
ARIZONA_WSEQ_BUSY , 0 ) ;
2017-03-15 17:58:36 +03:00
if ( ret )
2013-03-26 22:46:15 +04:00
regmap_write ( arizona - > regmap , ARIZONA_WRITE_SEQUENCER_CTRL_0 ,
2015-05-11 15:58:04 +03:00
ARIZONA_WSEQ_ABORT ) ;
2013-03-26 22:46:15 +04:00
2015-05-11 15:58:05 +03:00
err :
err = arizona_disable_freerun_sysclk ( arizona , & state ) ;
2013-03-26 22:46:15 +04:00
2015-05-11 15:58:04 +03:00
return ret ? : err ;
2013-03-26 22:46:15 +04:00
}
2015-05-11 15:58:06 +03:00
/*
* Register patch to some of the CODECs internal write sequences
* to ensure a clean exit from the low power sleep state .
*/
2015-07-16 18:36:21 +03:00
static const struct reg_sequence wm5110_sleep_patch [ ] = {
2015-05-11 15:58:06 +03:00
{ 0x337A , 0xC100 } ,
{ 0x337B , 0x0041 } ,
{ 0x3300 , 0xA210 } ,
{ 0x3301 , 0x050C } ,
} ;
static int wm5110_apply_sleep_patch ( struct arizona * arizona )
{
struct arizona_sysclk_state state ;
int err , ret ;
ret = arizona_enable_freerun_sysclk ( arizona , & state ) ;
if ( ret )
return ret ;
ret = regmap_multi_reg_write_bypassed ( arizona - > regmap ,
wm5110_sleep_patch ,
ARRAY_SIZE ( wm5110_sleep_patch ) ) ;
err = arizona_disable_freerun_sysclk ( arizona , & state ) ;
return ret ? : err ;
}
2015-05-11 15:58:03 +03:00
static int wm5102_clear_write_sequencer ( struct arizona * arizona )
{
int ret ;
ret = regmap_write ( arizona - > regmap , ARIZONA_WRITE_SEQUENCER_CTRL_3 ,
0x0 ) ;
if ( ret ) {
dev_err ( arizona - > dev ,
" Failed to clear write sequencer state: %d \n " , ret ) ;
return ret ;
}
arizona_enable_reset ( arizona ) ;
regulator_disable ( arizona - > dcvdd ) ;
msleep ( 20 ) ;
ret = regulator_enable ( arizona - > dcvdd ) ;
if ( ret ) {
dev_err ( arizona - > dev , " Failed to re-enable DCVDD: %d \n " , ret ) ;
return ret ;
}
arizona_disable_reset ( arizona ) ;
return 0 ;
}
2014-12-05 05:04:12 +03:00
# ifdef CONFIG_PM
2015-10-02 15:29:10 +03:00
static int arizona_isolate_dcvdd ( struct arizona * arizona )
{
int ret ;
ret = regmap_update_bits ( arizona - > regmap ,
ARIZONA_ISOLATION_CONTROL ,
ARIZONA_ISOLATE_DCVDD1 ,
ARIZONA_ISOLATE_DCVDD1 ) ;
if ( ret ! = 0 )
dev_err ( arizona - > dev , " Failed to isolate DCVDD: %d \n " , ret ) ;
return ret ;
}
static int arizona_connect_dcvdd ( struct arizona * arizona )
{
int ret ;
ret = regmap_update_bits ( arizona - > regmap ,
ARIZONA_ISOLATION_CONTROL ,
ARIZONA_ISOLATE_DCVDD1 , 0 ) ;
if ( ret ! = 0 )
dev_err ( arizona - > dev , " Failed to connect DCVDD: %d \n " , ret ) ;
return ret ;
}
2015-10-02 15:29:11 +03:00
static int arizona_is_jack_det_active ( struct arizona * arizona )
{
unsigned int val ;
int ret ;
ret = regmap_read ( arizona - > regmap , ARIZONA_JACK_DETECT_ANALOGUE , & val ) ;
if ( ret ) {
dev_err ( arizona - > dev ,
" Failed to check jack det status: %d \n " , ret ) ;
return ret ;
} else if ( val & ARIZONA_JD1_ENA ) {
return 1 ;
} else {
return 0 ;
}
}
2012-06-19 19:31:53 +04:00
static int arizona_runtime_resume ( struct device * dev )
{
struct arizona * arizona = dev_get_drvdata ( dev ) ;
int ret ;
2012-07-20 20:09:12 +04:00
dev_dbg ( arizona - > dev , " Leaving AoD mode \n " ) ;
2015-05-11 15:58:09 +03:00
if ( arizona - > has_fully_powered_off ) {
dev_dbg ( arizona - > dev , " Re-enabling core supplies \n " ) ;
ret = regulator_bulk_enable ( arizona - > num_core_supplies ,
arizona - > core_supplies ) ;
if ( ret ) {
dev_err ( dev , " Failed to enable core supplies: %d \n " ,
ret ) ;
return ret ;
}
}
2012-07-09 02:31:36 +04:00
ret = regulator_enable ( arizona - > dcvdd ) ;
if ( ret ! = 0 ) {
dev_err ( arizona - > dev , " Failed to enable DCVDD: %d \n " , ret ) ;
2015-05-11 15:58:09 +03:00
if ( arizona - > has_fully_powered_off )
regulator_bulk_disable ( arizona - > num_core_supplies ,
arizona - > core_supplies ) ;
2012-07-09 02:31:36 +04:00
return ret ;
}
2012-06-19 19:31:53 +04:00
2015-05-11 15:58:09 +03:00
if ( arizona - > has_fully_powered_off ) {
arizona_disable_reset ( arizona ) ;
enable_irq ( arizona - > irq ) ;
arizona - > has_fully_powered_off = false ;
}
2012-06-19 19:31:53 +04:00
regcache_cache_only ( arizona - > regmap , false ) ;
2013-03-26 22:01:49 +04:00
switch ( arizona - > type ) {
case WM5102 :
2013-04-23 22:44:16 +04:00
if ( arizona - > external_dcvdd ) {
2015-10-02 15:29:10 +03:00
ret = arizona_connect_dcvdd ( arizona ) ;
if ( ret ! = 0 )
2013-04-23 22:44:16 +04:00
goto err ;
}
2013-03-26 22:01:49 +04:00
ret = wm5102_patch ( arizona ) ;
if ( ret ! = 0 ) {
dev_err ( arizona - > dev , " Failed to apply patch: %d \n " ,
ret ) ;
goto err ;
}
2013-03-26 22:46:15 +04:00
2015-05-11 15:58:04 +03:00
ret = wm5102_apply_hardware_patch ( arizona ) ;
if ( ret ) {
2013-03-26 22:46:15 +04:00
dev_err ( arizona - > dev ,
" Failed to apply hardware patch: %d \n " ,
ret ) ;
goto err ;
}
break ;
2015-05-11 15:58:08 +03:00
case WM5110 :
case WM8280 :
ret = arizona_wait_for_boot ( arizona ) ;
if ( ret )
goto err ;
if ( arizona - > external_dcvdd ) {
2015-10-02 15:29:10 +03:00
ret = arizona_connect_dcvdd ( arizona ) ;
if ( ret ! = 0 )
2015-05-11 15:58:08 +03:00
goto err ;
} else {
/*
* As this is only called for the internal regulator
* ( where we know voltage ranges available ) it is ok
* to request an exact range .
*/
ret = regulator_set_voltage ( arizona - > dcvdd ,
1200000 , 1200000 ) ;
if ( ret < 0 ) {
dev_err ( arizona - > dev ,
" Failed to set resume voltage: %d \n " ,
ret ) ;
goto err ;
}
}
2015-05-11 15:58:09 +03:00
ret = wm5110_apply_sleep_patch ( arizona ) ;
if ( ret ) {
dev_err ( arizona - > dev ,
" Failed to re-apply sleep patch: %d \n " ,
ret ) ;
goto err ;
}
2015-05-11 15:58:08 +03:00
break ;
2015-11-03 18:08:32 +03:00
case WM1831 :
case CS47L24 :
ret = arizona_wait_for_boot ( arizona ) ;
if ( ret ! = 0 )
goto err ;
break ;
2013-03-26 22:46:15 +04:00
default :
2013-03-27 13:49:40 +04:00
ret = arizona_wait_for_boot ( arizona ) ;
2015-08-11 11:34:31 +03:00
if ( ret ! = 0 )
2013-03-27 13:49:40 +04:00
goto err ;
2013-04-23 22:44:16 +04:00
if ( arizona - > external_dcvdd ) {
2015-10-02 15:29:10 +03:00
ret = arizona_connect_dcvdd ( arizona ) ;
if ( ret ! = 0 )
2013-04-23 22:44:16 +04:00
goto err ;
}
2013-03-26 22:46:15 +04:00
break ;
2013-03-26 22:01:49 +04:00
}
2013-01-04 21:16:12 +04:00
ret = regcache_sync ( arizona - > regmap ) ;
if ( ret ! = 0 ) {
dev_err ( arizona - > dev , " Failed to restore register cache \n " ) ;
2013-01-14 10:50:38 +04:00
goto err ;
2013-01-04 21:16:12 +04:00
}
2012-06-19 19:31:53 +04:00
return 0 ;
2013-01-14 10:50:38 +04:00
err :
regcache_cache_only ( arizona - > regmap , true ) ;
regulator_disable ( arizona - > dcvdd ) ;
return ret ;
2012-06-19 19:31:53 +04:00
}
static int arizona_runtime_suspend ( struct device * dev )
{
struct arizona * arizona = dev_get_drvdata ( dev ) ;
2015-10-19 13:18:05 +03:00
int jd_active = 0 ;
2013-04-23 22:44:16 +04:00
int ret ;
2012-06-19 19:31:53 +04:00
2012-07-20 20:09:12 +04:00
dev_dbg ( arizona - > dev , " Entering AoD mode \n " ) ;
2015-05-11 15:58:09 +03:00
switch ( arizona - > type ) {
case WM5110 :
case WM8280 :
2015-10-02 15:29:11 +03:00
jd_active = arizona_is_jack_det_active ( arizona ) ;
if ( jd_active < 0 )
return jd_active ;
2015-10-02 15:29:10 +03:00
if ( arizona - > external_dcvdd ) {
ret = arizona_isolate_dcvdd ( arizona ) ;
if ( ret ! = 0 )
return ret ;
} else {
/*
* As this is only called for the internal regulator
* ( where we know voltage ranges available ) it is ok
* to request an exact range .
*/
ret = regulator_set_voltage ( arizona - > dcvdd ,
1175000 , 1175000 ) ;
if ( ret < 0 ) {
dev_err ( arizona - > dev ,
" Failed to set suspend voltage: %d \n " ,
ret ) ;
return ret ;
}
2015-05-11 15:58:09 +03:00
}
break ;
case WM5102 :
2015-10-02 15:29:11 +03:00
jd_active = arizona_is_jack_det_active ( arizona ) ;
if ( jd_active < 0 )
return jd_active ;
2015-10-02 15:29:10 +03:00
if ( arizona - > external_dcvdd ) {
ret = arizona_isolate_dcvdd ( arizona ) ;
if ( ret ! = 0 )
return ret ;
}
2015-10-02 15:29:11 +03:00
if ( ! jd_active ) {
2015-05-11 15:58:09 +03:00
ret = regmap_write ( arizona - > regmap ,
ARIZONA_WRITE_SEQUENCER_CTRL_3 , 0x0 ) ;
if ( ret ) {
2015-05-11 15:58:08 +03:00
dev_err ( arizona - > dev ,
2015-05-11 15:58:09 +03:00
" Failed to clear write sequencer: %d \n " ,
2015-05-11 15:58:08 +03:00
ret ) ;
return ret ;
}
}
2015-05-11 15:58:09 +03:00
break ;
2015-11-03 18:08:32 +03:00
case WM1831 :
case CS47L24 :
break ;
2015-05-11 15:58:09 +03:00
default :
2015-10-02 15:29:11 +03:00
jd_active = arizona_is_jack_det_active ( arizona ) ;
if ( jd_active < 0 )
return jd_active ;
2015-10-02 15:29:10 +03:00
if ( arizona - > external_dcvdd ) {
ret = arizona_isolate_dcvdd ( arizona ) ;
if ( ret ! = 0 )
return ret ;
}
2015-05-11 15:58:09 +03:00
break ;
2013-04-23 22:44:16 +04:00
}
2012-07-09 02:31:36 +04:00
regcache_cache_only ( arizona - > regmap , true ) ;
regcache_mark_dirty ( arizona - > regmap ) ;
2013-08-06 20:18:35 +04:00
regulator_disable ( arizona - > dcvdd ) ;
2012-06-19 19:31:53 +04:00
2015-05-11 15:58:09 +03:00
/* Allow us to completely power down if no jack detection */
2015-10-02 15:29:11 +03:00
if ( ! jd_active ) {
2015-05-11 15:58:09 +03:00
dev_dbg ( arizona - > dev , " Fully powering off \n " ) ;
arizona - > has_fully_powered_off = true ;
2015-06-14 17:41:49 +03:00
disable_irq_nosync ( arizona - > irq ) ;
2015-05-11 15:58:09 +03:00
arizona_enable_reset ( arizona ) ;
regulator_bulk_disable ( arizona - > num_core_supplies ,
arizona - > core_supplies ) ;
}
2012-06-19 19:31:53 +04:00
return 0 ;
}
# endif
2013-01-27 08:07:32 +04:00
# ifdef CONFIG_PM_SLEEP
2013-04-10 15:40:26 +04:00
static int arizona_suspend ( struct device * dev )
{
struct arizona * arizona = dev_get_drvdata ( dev ) ;
dev_dbg ( arizona - > dev , " Suspend, disabling IRQ \n " ) ;
disable_irq ( arizona - > irq ) ;
return 0 ;
}
2016-08-30 12:33:10 +03:00
static int arizona_suspend_noirq ( struct device * dev )
2013-04-10 15:40:26 +04:00
{
struct arizona * arizona = dev_get_drvdata ( dev ) ;
dev_dbg ( arizona - > dev , " Late suspend, reenabling IRQ \n " ) ;
enable_irq ( arizona - > irq ) ;
return 0 ;
}
2013-01-27 08:07:32 +04:00
static int arizona_resume_noirq ( struct device * dev )
{
struct arizona * arizona = dev_get_drvdata ( dev ) ;
dev_dbg ( arizona - > dev , " Early resume, disabling IRQ \n " ) ;
disable_irq ( arizona - > irq ) ;
return 0 ;
}
static int arizona_resume ( struct device * dev )
{
struct arizona * arizona = dev_get_drvdata ( dev ) ;
2016-08-30 12:33:10 +03:00
dev_dbg ( arizona - > dev , " Resume, reenabling IRQ \n " ) ;
2013-01-27 08:07:32 +04:00
enable_irq ( arizona - > irq ) ;
return 0 ;
}
# endif
2012-06-19 19:31:53 +04:00
const struct dev_pm_ops arizona_pm_ops = {
SET_RUNTIME_PM_OPS ( arizona_runtime_suspend ,
arizona_runtime_resume ,
NULL )
2013-04-10 15:40:26 +04:00
SET_SYSTEM_SLEEP_PM_OPS ( arizona_suspend , arizona_resume )
2016-08-30 12:33:10 +03:00
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS ( arizona_suspend_noirq ,
arizona_resume_noirq )
2012-06-19 19:31:53 +04:00
} ;
EXPORT_SYMBOL_GPL ( arizona_pm_ops ) ;
2013-03-25 04:11:27 +04:00
# ifdef CONFIG_OF
2014-07-02 17:28:46 +04:00
unsigned long arizona_of_get_type ( struct device * dev )
2013-03-25 04:11:27 +04:00
{
const struct of_device_id * id = of_match_device ( arizona_of_match , dev ) ;
if ( id )
2014-07-02 17:28:46 +04:00
return ( unsigned long ) id - > data ;
2013-03-25 04:11:27 +04:00
else
return 0 ;
}
EXPORT_SYMBOL_GPL ( arizona_of_get_type ) ;
static int arizona_of_get_core_pdata ( struct arizona * arizona )
{
2014-04-16 13:01:37 +04:00
struct arizona_pdata * pdata = & arizona - > pdata ;
2014-08-30 06:27:18 +04:00
struct property * prop ;
const __be32 * cur ;
u32 val ;
2016-09-13 12:05:44 +03:00
u32 pdm_val [ ARIZONA_MAX_PDM_SPK ] ;
2013-03-25 04:11:27 +04:00
int ret , i ;
2014-08-30 06:27:18 +04:00
int count = 0 ;
2013-03-25 04:11:27 +04:00
2016-09-20 18:30:13 +03:00
pdata - > reset = of_get_named_gpio ( arizona - > dev - > of_node , " wlf,reset " , 0 ) ;
2016-09-20 18:30:14 +03:00
if ( pdata - > reset = = - EPROBE_DEFER ) {
return pdata - > reset ;
} else if ( pdata - > reset < 0 ) {
2016-09-20 18:30:13 +03:00
dev_err ( arizona - > dev , " Reset GPIO missing/malformed: %d \n " ,
pdata - > reset ) ;
pdata - > reset = 0 ;
}
2013-03-25 04:11:27 +04:00
ret = of_property_read_u32_array ( arizona - > dev - > of_node ,
" wlf,gpio-defaults " ,
2015-08-11 11:34:31 +03:00
pdata - > gpio_defaults ,
ARRAY_SIZE ( pdata - > gpio_defaults ) ) ;
2013-03-25 04:11:27 +04:00
if ( ret > = 0 ) {
/*
* All values are literal except out of range values
* which are chip default , translate into platform
* data which uses 0 as chip default and out of range
* as zero .
*/
2015-08-11 11:34:31 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( pdata - > gpio_defaults ) ; i + + ) {
if ( pdata - > gpio_defaults [ i ] > 0xffff )
pdata - > gpio_defaults [ i ] = 0 ;
else if ( pdata - > gpio_defaults [ i ] = = 0 )
pdata - > gpio_defaults [ i ] = 0x10000 ;
2013-03-25 04:11:27 +04:00
}
} else {
dev_err ( arizona - > dev , " Failed to parse GPIO defaults: %d \n " ,
ret ) ;
}
2014-08-30 06:27:18 +04:00
of_property_for_each_u32 ( arizona - > dev - > of_node , " wlf,inmode " , prop ,
cur , val ) {
2015-08-11 11:34:31 +03:00
if ( count = = ARRAY_SIZE ( pdata - > inmode ) )
2014-08-30 06:27:18 +04:00
break ;
2015-08-11 11:34:31 +03:00
pdata - > inmode [ count ] = val ;
2014-08-30 06:27:18 +04:00
count + + ;
}
2015-03-03 18:04:53 +03:00
count = 0 ;
of_property_for_each_u32 ( arizona - > dev - > of_node , " wlf,dmic-ref " , prop ,
cur , val ) {
2015-08-11 11:34:31 +03:00
if ( count = = ARRAY_SIZE ( pdata - > dmic_ref ) )
2015-03-03 18:04:53 +03:00
break ;
2015-08-11 11:34:31 +03:00
pdata - > dmic_ref [ count ] = val ;
2015-03-03 18:04:53 +03:00
count + + ;
}
2015-12-14 13:19:11 +03:00
count = 0 ;
of_property_for_each_u32 ( arizona - > dev - > of_node , " wlf,out-mono " , prop ,
cur , val ) {
if ( count = = ARRAY_SIZE ( pdata - > out_mono ) )
break ;
pdata - > out_mono [ count ] = ! ! val ;
count + + ;
}
2016-09-13 12:05:44 +03:00
count = 0 ;
of_property_for_each_u32 ( arizona - > dev - > of_node ,
" wlf,max-channels-clocked " ,
prop , cur , val ) {
if ( count = = ARRAY_SIZE ( pdata - > max_channels_clocked ) )
break ;
pdata - > max_channels_clocked [ count ] = val ;
count + + ;
}
ret = of_property_read_u32_array ( arizona - > dev - > of_node ,
" wlf,spk-fmt " ,
pdm_val ,
ARRAY_SIZE ( pdm_val ) ) ;
if ( ret > = 0 )
for ( count = 0 ; count < ARRAY_SIZE ( pdata - > spk_fmt ) ; + + count )
pdata - > spk_fmt [ count ] = pdm_val [ count ] ;
ret = of_property_read_u32_array ( arizona - > dev - > of_node ,
" wlf,spk-mute " ,
pdm_val ,
ARRAY_SIZE ( pdm_val ) ) ;
if ( ret > = 0 )
for ( count = 0 ; count < ARRAY_SIZE ( pdata - > spk_mute ) ; + + count )
pdata - > spk_mute [ count ] = pdm_val [ count ] ;
2013-03-25 04:11:27 +04:00
return 0 ;
}
const struct of_device_id arizona_of_match [ ] = {
{ . compatible = " wlf,wm5102 " , . data = ( void * ) WM5102 } ,
{ . compatible = " wlf,wm5110 " , . data = ( void * ) WM5110 } ,
2015-01-17 18:21:22 +03:00
{ . compatible = " wlf,wm8280 " , . data = ( void * ) WM8280 } ,
2013-06-13 12:43:29 +04:00
{ . compatible = " wlf,wm8997 " , . data = ( void * ) WM8997 } ,
2015-07-03 18:16:35 +03:00
{ . compatible = " wlf,wm8998 " , . data = ( void * ) WM8998 } ,
{ . compatible = " wlf,wm1814 " , . data = ( void * ) WM1814 } ,
2015-11-03 18:08:32 +03:00
{ . compatible = " wlf,wm1831 " , . data = ( void * ) WM1831 } ,
{ . compatible = " cirrus,cs47l24 " , . data = ( void * ) CS47L24 } ,
2013-03-25 04:11:27 +04:00
{ } ,
} ;
EXPORT_SYMBOL_GPL ( arizona_of_match ) ;
# else
static inline int arizona_of_get_core_pdata ( struct arizona * arizona )
{
return 0 ;
}
# endif
2013-11-18 17:33:06 +04:00
static const struct mfd_cell early_devs [ ] = {
2012-06-19 19:31:53 +04:00
{ . name = " arizona-ldo1 " } ,
} ;
2015-08-11 11:34:31 +03:00
static const char * const wm5102_supplies [ ] = {
2014-07-25 19:24:44 +04:00
" MICVDD " ,
2013-10-15 23:14:22 +04:00
" DBVDD2 " ,
" DBVDD3 " ,
" CPVDD " ,
" SPKVDDL " ,
" SPKVDDR " ,
} ;
2013-11-18 17:33:06 +04:00
static const struct mfd_cell wm5102_devs [ ] = {
2012-12-20 19:38:03 +04:00
{ . name = " arizona-micsupp " } ,
2016-04-15 15:18:47 +03:00
{ . name = " arizona-gpio " } ,
2014-07-25 19:24:44 +04:00
{
. name = " arizona-extcon " ,
. parent_supplies = wm5102_supplies ,
. num_parent_supplies = 1 , /* We only need MICVDD */
} ,
2012-11-27 21:36:38 +04:00
{ . name = " arizona-haptics " } ,
2012-06-19 19:31:53 +04:00
{ . name = " arizona-pwm " } ,
2013-10-15 23:14:22 +04:00
{
. name = " wm5102-codec " ,
. parent_supplies = wm5102_supplies ,
. num_parent_supplies = ARRAY_SIZE ( wm5102_supplies ) ,
} ,
2012-06-19 19:31:53 +04:00
} ;
2013-11-18 17:33:06 +04:00
static const struct mfd_cell wm5110_devs [ ] = {
2012-12-20 19:38:03 +04:00
{ . name = " arizona-micsupp " } ,
2016-04-15 15:18:47 +03:00
{ . name = " arizona-gpio " } ,
2014-07-25 19:24:44 +04:00
{
. name = " arizona-extcon " ,
. parent_supplies = wm5102_supplies ,
. num_parent_supplies = 1 , /* We only need MICVDD */
} ,
2012-11-27 21:36:38 +04:00
{ . name = " arizona-haptics " } ,
2012-07-10 15:37:58 +04:00
{ . name = " arizona-pwm " } ,
2013-10-15 23:14:22 +04:00
{
. name = " wm5110-codec " ,
. parent_supplies = wm5102_supplies ,
. num_parent_supplies = ARRAY_SIZE ( wm5102_supplies ) ,
} ,
} ;
2015-11-03 18:08:32 +03:00
static const char * const cs47l24_supplies [ ] = {
" MICVDD " ,
" CPVDD " ,
" SPKVDD " ,
} ;
static const struct mfd_cell cs47l24_devs [ ] = {
{ . name = " arizona-gpio " } ,
{ . name = " arizona-haptics " } ,
{ . name = " arizona-pwm " } ,
{
. name = " cs47l24-codec " ,
. parent_supplies = cs47l24_supplies ,
. num_parent_supplies = ARRAY_SIZE ( cs47l24_supplies ) ,
} ,
} ;
2015-08-11 11:34:31 +03:00
static const char * const wm8997_supplies [ ] = {
2014-07-25 19:24:43 +04:00
" MICVDD " ,
2013-10-15 23:14:22 +04:00
" DBVDD2 " ,
" CPVDD " ,
" SPKVDD " ,
2012-07-10 15:37:58 +04:00
} ;
2013-11-18 17:33:06 +04:00
static const struct mfd_cell wm8997_devs [ ] = {
2013-06-13 12:43:29 +04:00
{ . name = " arizona-micsupp " } ,
2016-04-15 15:18:47 +03:00
{ . name = " arizona-gpio " } ,
2014-07-25 19:24:44 +04:00
{
. name = " arizona-extcon " ,
. parent_supplies = wm8997_supplies ,
. num_parent_supplies = 1 , /* We only need MICVDD */
} ,
2013-06-13 12:43:29 +04:00
{ . name = " arizona-haptics " } ,
{ . name = " arizona-pwm " } ,
2013-10-15 23:14:22 +04:00
{
. name = " wm8997-codec " ,
. parent_supplies = wm8997_supplies ,
. num_parent_supplies = ARRAY_SIZE ( wm8997_supplies ) ,
} ,
2013-06-13 12:43:29 +04:00
} ;
2015-07-03 18:16:35 +03:00
static const struct mfd_cell wm8998_devs [ ] = {
2016-04-15 15:18:47 +03:00
{ . name = " arizona-micsupp " } ,
{ . name = " arizona-gpio " } ,
2015-07-03 18:16:35 +03:00
{
. name = " arizona-extcon " ,
. parent_supplies = wm5102_supplies ,
. num_parent_supplies = 1 , /* We only need MICVDD */
} ,
{ . name = " arizona-haptics " } ,
{ . name = " arizona-pwm " } ,
{
. name = " wm8998-codec " ,
. parent_supplies = wm5102_supplies ,
. num_parent_supplies = ARRAY_SIZE ( wm5102_supplies ) ,
} ,
} ;
2012-11-19 22:23:04 +04:00
int arizona_dev_init ( struct arizona * arizona )
2012-06-19 19:31:53 +04:00
{
2016-09-02 18:52:46 +03:00
const char * const mclk_name [ ] = { " mclk1 " , " mclk2 " } ;
2012-06-19 19:31:53 +04:00
struct device * dev = arizona - > dev ;
2015-11-03 18:08:32 +03:00
const char * type_name = NULL ;
2015-07-03 18:16:35 +03:00
unsigned int reg , val , mask ;
2012-12-02 06:41:46 +04:00
int ( * apply_patch ) ( struct arizona * ) = NULL ;
2015-10-02 15:29:13 +03:00
const struct mfd_cell * subdevs = NULL ;
int n_subdevs , ret , i ;
2012-06-19 19:31:53 +04:00
dev_set_drvdata ( arizona - > dev , arizona ) ;
mutex_init ( & arizona - > clk_lock ) ;
2016-09-20 18:30:14 +03:00
if ( dev_get_platdata ( arizona - > dev ) ) {
2012-06-19 19:31:53 +04:00
memcpy ( & arizona - > pdata , dev_get_platdata ( arizona - > dev ) ,
sizeof ( arizona - > pdata ) ) ;
2016-09-20 18:30:14 +03:00
} else {
ret = arizona_of_get_core_pdata ( arizona ) ;
if ( ret < 0 )
return ret ;
}
2012-06-19 19:31:53 +04:00
2016-09-02 18:52:46 +03:00
BUILD_BUG_ON ( ARRAY_SIZE ( arizona - > mclk ) ! = ARRAY_SIZE ( mclk_name ) ) ;
for ( i = 0 ; i < ARRAY_SIZE ( arizona - > mclk ) ; i + + ) {
arizona - > mclk [ i ] = devm_clk_get ( arizona - > dev , mclk_name [ i ] ) ;
if ( IS_ERR ( arizona - > mclk [ i ] ) ) {
dev_info ( arizona - > dev , " Failed to get %s: %ld \n " ,
mclk_name [ i ] , PTR_ERR ( arizona - > mclk [ i ] ) ) ;
arizona - > mclk [ i ] = NULL ;
}
}
2012-06-19 19:31:53 +04:00
regcache_cache_only ( arizona - > regmap , true ) ;
switch ( arizona - > type ) {
case WM5102 :
2012-07-10 15:37:58 +04:00
case WM5110 :
2015-01-17 18:21:22 +03:00
case WM8280 :
2013-06-13 12:43:29 +04:00
case WM8997 :
2015-07-03 18:16:35 +03:00
case WM8998 :
case WM1814 :
2015-11-03 18:08:32 +03:00
case WM1831 :
case CS47L24 :
2012-06-19 19:31:53 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( wm5102_core_supplies ) ; i + + )
arizona - > core_supplies [ i ] . supply
= wm5102_core_supplies [ i ] ;
arizona - > num_core_supplies = ARRAY_SIZE ( wm5102_core_supplies ) ;
break ;
default :
dev_err ( arizona - > dev , " Unknown device type %d \n " ,
arizona - > type ) ;
2016-08-31 12:41:30 +03:00
return - ENODEV ;
2012-06-19 19:31:53 +04:00
}
2014-04-16 13:01:38 +04:00
/* Mark DCVDD as external, LDO1 driver will clear if internal */
arizona - > external_dcvdd = true ;
2015-11-03 18:08:32 +03:00
switch ( arizona - > type ) {
case WM1831 :
case CS47L24 :
break ; /* No LDO1 regulator */
default :
ret = mfd_add_devices ( arizona - > dev , - 1 , early_devs ,
ARRAY_SIZE ( early_devs ) , NULL , 0 , NULL ) ;
if ( ret ! = 0 ) {
dev_err ( dev , " Failed to add early children: %d \n " , ret ) ;
return ret ;
}
break ;
2012-06-19 19:31:53 +04:00
}
ret = devm_regulator_bulk_get ( dev , arizona - > num_core_supplies ,
arizona - > core_supplies ) ;
if ( ret ! = 0 ) {
dev_err ( dev , " Failed to request core supplies: %d \n " ,
ret ) ;
goto err_early ;
}
2014-06-19 19:04:23 +04:00
/**
* Don ' t use devres here because the only device we have to get
* against is the MFD device and DCVDD will likely be supplied by
* one of its children . Meaning that the regulator will be
* destroyed by the time devres calls regulator put .
*/
2014-06-02 12:50:41 +04:00
arizona - > dcvdd = regulator_get ( arizona - > dev , " DCVDD " ) ;
2012-07-09 02:31:36 +04:00
if ( IS_ERR ( arizona - > dcvdd ) ) {
ret = PTR_ERR ( arizona - > dcvdd ) ;
dev_err ( dev , " Failed to request DCVDD: %d \n " , ret ) ;
goto err_early ;
}
2013-03-26 16:15:26 +04:00
if ( arizona - > pdata . reset ) {
/* Start out with /RESET low to put the chip into reset */
2015-05-11 15:58:01 +03:00
ret = devm_gpio_request_one ( arizona - > dev , arizona - > pdata . reset ,
GPIOF_DIR_OUT | GPIOF_INIT_LOW ,
" arizona /RESET " ) ;
2013-03-26 16:15:26 +04:00
if ( ret ! = 0 ) {
dev_err ( dev , " Failed to request /RESET: %d \n " , ret ) ;
2014-06-02 12:50:41 +04:00
goto err_dcvdd ;
2013-03-26 16:15:26 +04:00
}
}
2012-06-19 19:31:53 +04:00
ret = regulator_bulk_enable ( arizona - > num_core_supplies ,
arizona - > core_supplies ) ;
if ( ret ! = 0 ) {
dev_err ( dev , " Failed to enable core supplies: %d \n " ,
ret ) ;
2014-06-02 12:50:41 +04:00
goto err_dcvdd ;
2012-06-19 19:31:53 +04:00
}
2012-07-09 02:31:36 +04:00
ret = regulator_enable ( arizona - > dcvdd ) ;
if ( ret ! = 0 ) {
dev_err ( dev , " Failed to enable DCVDD: %d \n " , ret ) ;
goto err_enable ;
}
2015-05-11 15:58:02 +03:00
arizona_disable_reset ( arizona ) ;
2012-06-19 19:31:53 +04:00
regcache_cache_only ( arizona - > regmap , false ) ;
2013-04-09 19:04:35 +04:00
/* Verify that this is a chip we know about */
2012-06-19 19:31:53 +04:00
ret = regmap_read ( arizona - > regmap , ARIZONA_SOFTWARE_RESET , & reg ) ;
if ( ret ! = 0 ) {
dev_err ( dev , " Failed to read ID register: %d \n " , ret ) ;
2012-07-09 02:31:36 +04:00
goto err_reset ;
2012-06-19 19:31:53 +04:00
}
switch ( reg ) {
case 0x5102 :
2012-07-10 15:37:58 +04:00
case 0x5110 :
2015-07-03 18:16:35 +03:00
case 0x6349 :
2015-11-03 18:08:32 +03:00
case 0x6363 :
2013-06-13 12:43:29 +04:00
case 0x8997 :
2012-07-10 15:37:58 +04:00
break ;
2012-06-19 19:31:53 +04:00
default :
2013-04-09 19:04:35 +04:00
dev_err ( arizona - > dev , " Unknown device ID: %x \n " , reg ) ;
2016-08-31 12:41:30 +03:00
ret = - ENODEV ;
2012-07-09 02:31:36 +04:00
goto err_reset ;
2012-06-19 19:31:53 +04:00
}
/* If we have a /RESET GPIO we'll already be reset */
if ( ! arizona - > pdata . reset ) {
ret = regmap_write ( arizona - > regmap , ARIZONA_SOFTWARE_RESET , 0 ) ;
if ( ret ! = 0 ) {
dev_err ( dev , " Failed to reset device: %d \n " , ret ) ;
2012-07-09 02:31:36 +04:00
goto err_reset ;
2012-06-19 19:31:53 +04:00
}
2012-11-20 09:49:10 +04:00
2015-10-28 15:42:30 +03:00
usleep_range ( 1000 , 5000 ) ;
2012-06-19 19:31:53 +04:00
}
2013-04-09 19:04:35 +04:00
/* Ensure device startup is complete */
2013-04-03 12:45:29 +04:00
switch ( arizona - > type ) {
case WM5102 :
2014-08-13 14:42:46 +04:00
ret = regmap_read ( arizona - > regmap ,
ARIZONA_WRITE_SEQUENCER_CTRL_3 , & val ) ;
2015-05-11 15:58:03 +03:00
if ( ret ) {
2013-04-03 12:45:29 +04:00
dev_err ( dev ,
" Failed to check write sequencer state: %d \n " ,
ret ) ;
2015-05-11 15:58:03 +03:00
} else if ( val & 0x01 ) {
ret = wm5102_clear_write_sequencer ( arizona ) ;
if ( ret )
return ret ;
2013-04-03 12:45:29 +04:00
}
break ;
2015-05-11 15:58:03 +03:00
default :
break ;
}
ret = arizona_wait_for_boot ( arizona ) ;
if ( ret ) {
dev_err ( arizona - > dev , " Device failed initial boot: %d \n " , ret ) ;
goto err_reset ;
2012-07-09 14:56:43 +04:00
}
2012-06-19 19:31:53 +04:00
2013-04-09 19:04:35 +04:00
/* Read the device ID information & do device specific stuff */
ret = regmap_read ( arizona - > regmap , ARIZONA_SOFTWARE_RESET , & reg ) ;
if ( ret ! = 0 ) {
dev_err ( dev , " Failed to read ID register: %d \n " , ret ) ;
goto err_reset ;
}
ret = regmap_read ( arizona - > regmap , ARIZONA_DEVICE_REVISION ,
& arizona - > rev ) ;
if ( ret ! = 0 ) {
dev_err ( dev , " Failed to read revision register: %d \n " , ret ) ;
goto err_reset ;
}
arizona - > rev & = ARIZONA_DEVICE_REVISION_MASK ;
switch ( reg ) {
case 0x5102 :
2015-10-02 15:29:14 +03:00
if ( IS_ENABLED ( CONFIG_MFD_WM5102 ) ) {
type_name = " WM5102 " ;
if ( arizona - > type ! = WM5102 ) {
dev_warn ( arizona - > dev ,
" WM5102 registered as %d \n " ,
arizona - > type ) ;
arizona - > type = WM5102 ;
}
apply_patch = wm5102_patch ;
arizona - > rev & = 0x7 ;
subdevs = wm5102_devs ;
n_subdevs = ARRAY_SIZE ( wm5102_devs ) ;
2013-04-09 19:04:35 +04:00
}
break ;
case 0x5110 :
2015-10-02 15:29:14 +03:00
if ( IS_ENABLED ( CONFIG_MFD_WM5110 ) ) {
switch ( arizona - > type ) {
case WM5110 :
type_name = " WM5110 " ;
break ;
case WM8280 :
type_name = " WM8280 " ;
break ;
default :
type_name = " WM5110 " ;
dev_warn ( arizona - > dev ,
" WM5110 registered as %d \n " ,
arizona - > type ) ;
arizona - > type = WM5110 ;
break ;
}
apply_patch = wm5110_patch ;
subdevs = wm5110_devs ;
n_subdevs = ARRAY_SIZE ( wm5110_devs ) ;
2013-04-09 19:04:35 +04:00
}
break ;
2015-11-03 18:08:32 +03:00
case 0x6363 :
if ( IS_ENABLED ( CONFIG_MFD_CS47L24 ) ) {
switch ( arizona - > type ) {
case CS47L24 :
type_name = " CS47L24 " ;
break ;
case WM1831 :
type_name = " WM1831 " ;
break ;
default :
dev_warn ( arizona - > dev ,
" CS47L24 registered as %d \n " ,
arizona - > type ) ;
arizona - > type = CS47L24 ;
break ;
}
apply_patch = cs47l24_patch ;
subdevs = cs47l24_devs ;
n_subdevs = ARRAY_SIZE ( cs47l24_devs ) ;
}
break ;
2013-06-13 12:43:29 +04:00
case 0x8997 :
2015-10-02 15:29:14 +03:00
if ( IS_ENABLED ( CONFIG_MFD_WM8997 ) ) {
type_name = " WM8997 " ;
if ( arizona - > type ! = WM8997 ) {
dev_warn ( arizona - > dev ,
" WM8997 registered as %d \n " ,
arizona - > type ) ;
arizona - > type = WM8997 ;
}
apply_patch = wm8997_patch ;
subdevs = wm8997_devs ;
n_subdevs = ARRAY_SIZE ( wm8997_devs ) ;
2013-06-13 12:43:29 +04:00
}
break ;
2015-07-03 18:16:35 +03:00
case 0x6349 :
2015-10-02 15:29:14 +03:00
if ( IS_ENABLED ( CONFIG_MFD_WM8998 ) ) {
switch ( arizona - > type ) {
case WM8998 :
type_name = " WM8998 " ;
break ;
case WM1814 :
type_name = " WM1814 " ;
break ;
default :
type_name = " WM8998 " ;
dev_warn ( arizona - > dev ,
" WM8998 registered as %d \n " ,
arizona - > type ) ;
arizona - > type = WM8998 ;
}
2015-07-03 18:16:35 +03:00
2015-10-02 15:29:14 +03:00
apply_patch = wm8998_patch ;
subdevs = wm8998_devs ;
n_subdevs = ARRAY_SIZE ( wm8998_devs ) ;
2015-07-03 18:16:35 +03:00
}
break ;
2013-04-09 19:04:35 +04:00
default :
dev_err ( arizona - > dev , " Unknown device ID %x \n " , reg ) ;
2016-08-31 12:41:30 +03:00
ret = - ENODEV ;
2013-04-09 19:04:35 +04:00
goto err_reset ;
}
2015-10-02 15:29:14 +03:00
if ( ! subdevs ) {
dev_err ( arizona - > dev ,
" No kernel support for device ID %x \n " , reg ) ;
2016-08-31 12:41:30 +03:00
ret = - ENODEV ;
2015-10-02 15:29:14 +03:00
goto err_reset ;
}
2013-04-09 19:04:35 +04:00
dev_info ( dev , " %s revision %c \n " , type_name , arizona - > rev + ' A ' ) ;
2012-12-02 06:41:46 +04:00
if ( apply_patch ) {
ret = apply_patch ( arizona ) ;
if ( ret ! = 0 ) {
dev_err ( arizona - > dev , " Failed to apply patch: %d \n " ,
ret ) ;
goto err_reset ;
}
2013-03-26 22:46:15 +04:00
switch ( arizona - > type ) {
case WM5102 :
2015-05-11 15:58:04 +03:00
ret = wm5102_apply_hardware_patch ( arizona ) ;
if ( ret ) {
2013-03-26 22:46:15 +04:00
dev_err ( arizona - > dev ,
" Failed to apply hardware patch: %d \n " ,
ret ) ;
goto err_reset ;
}
break ;
2015-05-11 15:58:06 +03:00
case WM5110 :
case WM8280 :
ret = wm5110_apply_sleep_patch ( arizona ) ;
if ( ret ) {
dev_err ( arizona - > dev ,
" Failed to apply sleep patch: %d \n " ,
ret ) ;
goto err_reset ;
}
break ;
2013-03-26 22:46:15 +04:00
default :
break ;
}
2012-12-02 06:41:46 +04:00
}
2012-06-19 19:31:53 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( arizona - > pdata . gpio_defaults ) ; i + + ) {
if ( ! arizona - > pdata . gpio_defaults [ i ] )
continue ;
regmap_write ( arizona - > regmap , ARIZONA_GPIO1_CTRL + i ,
arizona - > pdata . gpio_defaults [ i ] ) ;
}
/* Chip default */
if ( ! arizona - > pdata . clk32k_src )
arizona - > pdata . clk32k_src = ARIZONA_32KZ_MCLK2 ;
switch ( arizona - > pdata . clk32k_src ) {
case ARIZONA_32KZ_MCLK1 :
case ARIZONA_32KZ_MCLK2 :
regmap_update_bits ( arizona - > regmap , ARIZONA_CLOCK_32K_1 ,
ARIZONA_CLK_32K_SRC_MASK ,
arizona - > pdata . clk32k_src - 1 ) ;
2013-03-19 22:04:46 +04:00
arizona_clk32k_enable ( arizona ) ;
2012-06-19 19:31:53 +04:00
break ;
case ARIZONA_32KZ_NONE :
regmap_update_bits ( arizona - > regmap , ARIZONA_CLOCK_32K_1 ,
ARIZONA_CLK_32K_SRC_MASK , 2 ) ;
break ;
default :
dev_err ( arizona - > dev , " Invalid 32kHz clock source: %d \n " ,
arizona - > pdata . clk32k_src ) ;
ret = - EINVAL ;
2012-07-09 02:31:36 +04:00
goto err_reset ;
2012-06-19 19:31:53 +04:00
}
2013-01-28 20:47:37 +04:00
for ( i = 0 ; i < ARIZONA_MAX_MICBIAS ; i + + ) {
2013-01-29 14:44:41 +04:00
if ( ! arizona - > pdata . micbias [ i ] . mV & &
! arizona - > pdata . micbias [ i ] . bypass )
2013-01-28 20:47:37 +04:00
continue ;
2013-01-29 14:44:41 +04:00
/* Apply default for bypass mode */
if ( ! arizona - > pdata . micbias [ i ] . mV )
arizona - > pdata . micbias [ i ] . mV = 2800 ;
2013-01-28 20:47:37 +04:00
val = ( arizona - > pdata . micbias [ i ] . mV - 1500 ) / 100 ;
2013-01-29 14:44:41 +04:00
2013-01-28 20:47:37 +04:00
val < < = ARIZONA_MICB1_LVL_SHIFT ;
if ( arizona - > pdata . micbias [ i ] . ext_cap )
val | = ARIZONA_MICB1_EXT_CAP ;
if ( arizona - > pdata . micbias [ i ] . discharge )
val | = ARIZONA_MICB1_DISCH ;
2013-05-21 17:56:58 +04:00
if ( arizona - > pdata . micbias [ i ] . soft_start )
2013-01-28 20:47:37 +04:00
val | = ARIZONA_MICB1_RATE ;
2013-01-29 14:44:41 +04:00
if ( arizona - > pdata . micbias [ i ] . bypass )
val | = ARIZONA_MICB1_BYPASS ;
2013-01-28 20:47:37 +04:00
regmap_update_bits ( arizona - > regmap ,
ARIZONA_MIC_BIAS_CTRL_1 + i ,
ARIZONA_MICB1_LVL_MASK |
2014-09-24 13:37:11 +04:00
ARIZONA_MICB1_EXT_CAP |
2013-01-28 20:47:37 +04:00
ARIZONA_MICB1_DISCH |
2013-01-29 14:44:41 +04:00
ARIZONA_MICB1_BYPASS |
2013-01-28 20:47:37 +04:00
ARIZONA_MICB1_RATE , val ) ;
}
2012-06-19 19:31:53 +04:00
for ( i = 0 ; i < ARIZONA_MAX_INPUT ; i + + ) {
/* Default for both is 0 so noop with defaults */
val = arizona - > pdata . dmic_ref [ i ]
< < ARIZONA_IN1_DMIC_SUP_SHIFT ;
2015-05-01 18:15:12 +03:00
if ( arizona - > pdata . inmode [ i ] & ARIZONA_INMODE_DMIC )
val | = 1 < < ARIZONA_IN1_MODE_SHIFT ;
2015-07-03 18:16:35 +03:00
switch ( arizona - > type ) {
case WM8998 :
case WM1814 :
regmap_update_bits ( arizona - > regmap ,
ARIZONA_ADC_DIGITAL_VOLUME_1L + ( i * 8 ) ,
ARIZONA_IN1L_SRC_SE_MASK ,
( arizona - > pdata . inmode [ i ] & ARIZONA_INMODE_SE )
< < ARIZONA_IN1L_SRC_SE_SHIFT ) ;
regmap_update_bits ( arizona - > regmap ,
ARIZONA_ADC_DIGITAL_VOLUME_1R + ( i * 8 ) ,
ARIZONA_IN1R_SRC_SE_MASK ,
( arizona - > pdata . inmode [ i ] & ARIZONA_INMODE_SE )
< < ARIZONA_IN1R_SRC_SE_SHIFT ) ;
mask = ARIZONA_IN1_DMIC_SUP_MASK |
ARIZONA_IN1_MODE_MASK ;
break ;
default :
if ( arizona - > pdata . inmode [ i ] & ARIZONA_INMODE_SE )
val | = 1 < < ARIZONA_IN1_SINGLE_ENDED_SHIFT ;
mask = ARIZONA_IN1_DMIC_SUP_MASK |
ARIZONA_IN1_MODE_MASK |
ARIZONA_IN1_SINGLE_ENDED_MASK ;
break ;
}
2012-06-19 19:31:53 +04:00
regmap_update_bits ( arizona - > regmap ,
ARIZONA_IN1L_CONTROL + ( i * 8 ) ,
2015-07-03 18:16:35 +03:00
mask , val ) ;
2012-06-19 19:31:53 +04:00
}
for ( i = 0 ; i < ARIZONA_MAX_OUTPUT ; i + + ) {
/* Default is 0 so noop with defaults */
if ( arizona - > pdata . out_mono [ i ] )
val = ARIZONA_OUT1_MONO ;
else
val = 0 ;
regmap_update_bits ( arizona - > regmap ,
ARIZONA_OUTPUT_PATH_CONFIG_1L + ( i * 8 ) ,
ARIZONA_OUT1_MONO , val ) ;
}
for ( i = 0 ; i < ARIZONA_MAX_PDM_SPK ; i + + ) {
if ( arizona - > pdata . spk_mute [ i ] )
regmap_update_bits ( arizona - > regmap ,
2012-07-09 22:33:14 +04:00
ARIZONA_PDM_SPK1_CTRL_1 + ( i * 2 ) ,
2012-06-19 19:31:53 +04:00
ARIZONA_SPK1_MUTE_ENDIAN_MASK |
ARIZONA_SPK1_MUTE_SEQ1_MASK ,
arizona - > pdata . spk_mute [ i ] ) ;
if ( arizona - > pdata . spk_fmt [ i ] )
regmap_update_bits ( arizona - > regmap ,
2012-07-09 22:33:14 +04:00
ARIZONA_PDM_SPK1_CTRL_2 + ( i * 2 ) ,
2012-06-19 19:31:53 +04:00
ARIZONA_SPK1_FMT_MASK ,
arizona - > pdata . spk_fmt [ i ] ) ;
}
2015-06-14 17:41:50 +03:00
pm_runtime_set_active ( arizona - > dev ) ;
pm_runtime_enable ( arizona - > dev ) ;
2012-06-19 19:31:53 +04:00
/* Set up for interrupts */
ret = arizona_irq_init ( arizona ) ;
if ( ret ! = 0 )
2016-06-27 17:19:11 +03:00
goto err_pm ;
2012-06-19 19:31:53 +04:00
2015-06-14 17:41:50 +03:00
pm_runtime_set_autosuspend_delay ( arizona - > dev , 100 ) ;
pm_runtime_use_autosuspend ( arizona - > dev ) ;
2012-06-19 19:31:53 +04:00
arizona_request_irq ( arizona , ARIZONA_IRQ_CLKGEN_ERR , " CLKGEN error " ,
arizona_clkgen_err , arizona ) ;
arizona_request_irq ( arizona , ARIZONA_IRQ_OVERCLOCKED , " Overclocked " ,
arizona_overclocked , arizona ) ;
arizona_request_irq ( arizona , ARIZONA_IRQ_UNDERCLOCKED , " Underclocked " ,
arizona_underclocked , arizona ) ;
2015-10-02 15:29:13 +03:00
ret = mfd_add_devices ( arizona - > dev , PLATFORM_DEVID_NONE ,
subdevs , n_subdevs , NULL , 0 , NULL ) ;
2012-06-19 19:31:53 +04:00
2015-10-02 15:29:13 +03:00
if ( ret ) {
2012-06-19 19:31:53 +04:00
dev_err ( arizona - > dev , " Failed to add subdevices: %d \n " , ret ) ;
goto err_irq ;
}
return 0 ;
err_irq :
arizona_irq_exit ( arizona ) ;
2016-06-27 17:19:11 +03:00
err_pm :
pm_runtime_disable ( arizona - > dev ) ;
2012-06-19 19:31:53 +04:00
err_reset :
2015-05-11 15:58:02 +03:00
arizona_enable_reset ( arizona ) ;
2012-07-09 02:31:36 +04:00
regulator_disable ( arizona - > dcvdd ) ;
2012-06-19 19:31:53 +04:00
err_enable :
2012-07-09 02:45:53 +04:00
regulator_bulk_disable ( arizona - > num_core_supplies ,
2012-06-19 19:31:53 +04:00
arizona - > core_supplies ) ;
2014-06-02 12:50:41 +04:00
err_dcvdd :
regulator_put ( arizona - > dcvdd ) ;
2012-06-19 19:31:53 +04:00
err_early :
mfd_remove_devices ( dev ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( arizona_dev_init ) ;
2012-11-19 22:26:01 +04:00
int arizona_dev_exit ( struct arizona * arizona )
2012-06-19 19:31:53 +04:00
{
2016-11-14 20:15:56 +03:00
disable_irq ( arizona - > irq ) ;
2014-06-02 12:50:39 +04:00
pm_runtime_disable ( arizona - > dev ) ;
2014-06-02 12:50:40 +04:00
regulator_disable ( arizona - > dcvdd ) ;
2014-06-02 12:50:41 +04:00
regulator_put ( arizona - > dcvdd ) ;
2014-06-02 12:50:40 +04:00
2012-06-19 19:31:53 +04:00
mfd_remove_devices ( arizona - > dev ) ;
arizona_free_irq ( arizona , ARIZONA_IRQ_UNDERCLOCKED , arizona ) ;
arizona_free_irq ( arizona , ARIZONA_IRQ_OVERCLOCKED , arizona ) ;
arizona_free_irq ( arizona , ARIZONA_IRQ_CLKGEN_ERR , arizona ) ;
arizona_irq_exit ( arizona ) ;
2015-05-11 15:58:02 +03:00
arizona_enable_reset ( arizona ) ;
2014-06-02 12:50:40 +04:00
2014-06-02 12:50:42 +04:00
regulator_bulk_disable ( arizona - > num_core_supplies ,
2013-03-26 16:16:26 +04:00
arizona - > core_supplies ) ;
2012-06-19 19:31:53 +04:00
return 0 ;
}
EXPORT_SYMBOL_GPL ( arizona_dev_exit ) ;