2019-05-27 09:55:06 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2012-06-24 15:09:45 +04:00
/*
* extcon - arizona . c - Extcon driver Wolfson Arizona devices
*
2015-09-28 14:41:42 +03:00
* Copyright ( C ) 2012 - 2014 Wolfson Microelectronics plc
2012-06-24 15:09:45 +04:00
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/slab.h>
# include <linux/interrupt.h>
# include <linux/err.h>
2015-06-19 19:23:31 +03:00
# include <linux/gpio/consumer.h>
2012-06-24 15:09:45 +04:00
# include <linux/gpio.h>
2012-07-20 20:07:29 +04:00
# include <linux/input.h>
2012-06-24 15:09:45 +04:00
# include <linux/pm_runtime.h>
2015-06-19 19:23:29 +03:00
# include <linux/property.h>
2012-06-24 15:09:45 +04:00
# include <linux/regulator/consumer.h>
2021-03-07 18:18:04 +03:00
# include <sound/jack.h>
2013-01-10 23:38:43 +04:00
# include <sound/soc.h>
2012-06-24 15:09:45 +04:00
# include <linux/mfd/arizona/core.h>
# include <linux/mfd/arizona/pdata.h>
# include <linux/mfd/arizona/registers.h>
2015-05-04 07:42:13 +03:00
# include <dt-bindings/mfd/arizona.h>
2012-06-24 15:09:45 +04:00
2021-03-07 18:18:01 +03:00
# include "arizona.h"
2013-04-02 01:03:06 +04:00
# define ARIZONA_MAX_MICD_RANGE 8
2012-07-20 20:07:29 +04:00
2021-03-07 18:18:04 +03:00
/*
* The hardware supports 8 ranges / buttons , but the snd - jack interface
* only supports 6 buttons ( button 0 - 5 ) .
*/
# define ARIZONA_MAX_MICD_BUTTONS 6
2014-05-23 15:54:57 +04:00
# define ARIZONA_MICD_CLAMP_MODE_JDL 0x4
# define ARIZONA_MICD_CLAMP_MODE_JDH 0x5
# define ARIZONA_MICD_CLAMP_MODE_JDL_GP5H 0x9
# define ARIZONA_MICD_CLAMP_MODE_JDH_GP5H 0xb
2015-09-16 12:42:18 +03:00
# define ARIZONA_TST_CAP_DEFAULT 0x3
# define ARIZONA_TST_CAP_CLAMP 0x1
2013-04-01 22:09:45 +04:00
# define ARIZONA_HPDET_MAX 10000
2013-04-01 22:07:28 +04:00
# define HPDET_DEBOUNCE 500
2013-04-01 22:25:55 +04:00
# define DEFAULT_MICD_TIMEOUT 2000
2013-04-01 22:05:27 +04:00
2017-01-25 12:34:06 +03:00
# define ARIZONA_HPDET_WAIT_COUNT 15
# define ARIZONA_HPDET_WAIT_DELAY_MS 20
2015-09-16 12:42:16 +03:00
# define QUICK_HEADPHONE_MAX_OHM 3
# define MICROPHONE_MIN_OHM 1257
# define MICROPHONE_MAX_OHM 30000
2015-06-30 15:32:39 +03:00
# define MICD_DBTIME_TWO_READINGS 2
# define MICD_DBTIME_FOUR_READINGS 4
2013-11-14 20:18:21 +04:00
# define MICD_LVL_1_TO_7 (ARIZONA_MICD_LVL_1 | ARIZONA_MICD_LVL_2 | \
ARIZONA_MICD_LVL_3 | ARIZONA_MICD_LVL_4 | \
ARIZONA_MICD_LVL_5 | ARIZONA_MICD_LVL_6 | \
ARIZONA_MICD_LVL_7 )
# define MICD_LVL_0_TO_7 (ARIZONA_MICD_LVL_0 | MICD_LVL_1_TO_7)
# define MICD_LVL_0_TO_8 (MICD_LVL_0_TO_7 | ARIZONA_MICD_LVL_8)
2012-06-24 15:09:45 +04:00
static const struct arizona_micd_config micd_default_modes [ ] = {
2013-09-23 17:33:59 +04:00
{ ARIZONA_ACCDET_SRC , 1 , 0 } ,
{ 0 , 2 , 1 } ,
2012-06-24 15:09:45 +04:00
} ;
2013-04-02 01:03:06 +04:00
static const struct arizona_micd_range micd_default_ranges [ ] = {
{ . max = 11 , . key = BTN_0 } ,
{ . max = 28 , . key = BTN_1 } ,
{ . max = 54 , . key = BTN_2 } ,
{ . max = 100 , . key = BTN_3 } ,
{ . max = 186 , . key = BTN_4 } ,
{ . max = 430 , . key = BTN_5 } ,
} ;
2015-09-16 12:42:16 +03:00
/* The number of levels in arizona_micd_levels valid for button thresholds */
# define ARIZONA_NUM_MICD_BUTTON_LEVELS 64
2013-04-02 01:03:06 +04:00
static const int arizona_micd_levels [ ] = {
3 , 6 , 8 , 11 , 13 , 16 , 18 , 21 , 23 , 26 , 28 , 31 , 34 , 36 , 39 , 41 , 44 , 46 ,
49 , 52 , 54 , 57 , 60 , 62 , 65 , 67 , 70 , 73 , 75 , 78 , 81 , 83 , 89 , 94 , 100 ,
105 , 111 , 116 , 122 , 127 , 139 , 150 , 161 , 173 , 186 , 196 , 209 , 220 , 245 ,
270 , 295 , 321 , 348 , 375 , 402 , 430 , 489 , 550 , 614 , 681 , 752 , 903 , 1071 ,
2015-09-16 12:42:16 +03:00
1257 , 30000 ,
2012-07-20 20:07:29 +04:00
} ;
2021-03-07 18:18:01 +03:00
static void arizona_start_hpdet_acc_id ( struct arizona_priv * info ) ;
2013-04-01 22:09:45 +04:00
2021-03-07 18:18:01 +03:00
static void arizona_extcon_hp_clamp ( struct arizona_priv * info ,
2015-02-16 18:41:02 +03:00
bool clamp )
2013-02-12 17:00:31 +04:00
{
struct arizona * arizona = info - > arizona ;
2015-02-16 18:41:03 +03:00
unsigned int mask = 0 , val = 0 ;
2015-09-16 12:42:18 +03:00
unsigned int cap_sel = 0 ;
2013-02-12 17:00:31 +04:00
int ret ;
2015-02-16 18:41:03 +03:00
switch ( arizona - > type ) {
2015-09-28 14:41:42 +03:00
case WM8998 :
case WM1814 :
mask = 0 ;
break ;
2015-02-16 18:41:03 +03:00
case WM5110 :
2015-04-30 17:43:37 +03:00
case WM8280 :
2015-02-16 18:41:03 +03:00
mask = ARIZONA_HP1L_SHRTO | ARIZONA_HP1L_FLWR |
ARIZONA_HP1L_SHRTI ;
2015-09-16 12:42:18 +03:00
if ( clamp ) {
2015-02-16 18:41:03 +03:00
val = ARIZONA_HP1L_SHRTO ;
2015-09-16 12:42:18 +03:00
cap_sel = ARIZONA_TST_CAP_CLAMP ;
} else {
2015-02-16 18:41:03 +03:00
val = ARIZONA_HP1L_FLWR | ARIZONA_HP1L_SHRTI ;
2015-09-16 12:42:18 +03:00
cap_sel = ARIZONA_TST_CAP_DEFAULT ;
}
ret = regmap_update_bits ( arizona - > regmap ,
ARIZONA_HP_TEST_CTRL_1 ,
ARIZONA_HP1_TST_CAP_SEL_MASK ,
cap_sel ) ;
2021-03-07 18:18:05 +03:00
if ( ret )
dev_warn ( arizona - > dev , " Failed to set TST_CAP_SEL: %d \n " , ret ) ;
2015-02-16 18:41:03 +03:00
break ;
default :
mask = ARIZONA_RMV_SHRT_HP1L ;
if ( clamp )
val = ARIZONA_RMV_SHRT_HP1L ;
break ;
2016-07-19 15:23:56 +03:00
}
2015-02-16 18:41:02 +03:00
2015-12-29 19:32:03 +03:00
snd_soc_dapm_mutex_lock ( arizona - > dapm ) ;
2013-02-12 17:00:31 +04:00
2015-02-16 18:41:02 +03:00
arizona - > hpdet_clamp = clamp ;
2013-02-12 17:00:31 +04:00
2015-02-16 18:41:02 +03:00
/* Keep the HP output stages disabled while doing the clamp */
if ( clamp ) {
2013-02-22 22:38:03 +04:00
ret = regmap_update_bits ( arizona - > regmap ,
ARIZONA_OUTPUT_ENABLES_1 ,
ARIZONA_OUT1L_ENA |
ARIZONA_OUT1R_ENA , 0 ) ;
2021-03-07 18:18:05 +03:00
if ( ret )
dev_warn ( arizona - > dev , " Failed to disable headphone outputs: %d \n " , ret ) ;
2013-02-22 22:38:03 +04:00
}
2015-09-28 14:41:42 +03:00
if ( mask ) {
ret = regmap_update_bits ( arizona - > regmap , ARIZONA_HP_CTRL_1L ,
mask , val ) ;
2021-03-07 18:18:05 +03:00
if ( ret )
dev_warn ( arizona - > dev , " Failed to do clamp: %d \n " , ret ) ;
2013-02-12 17:00:31 +04:00
2015-09-28 14:41:42 +03:00
ret = regmap_update_bits ( arizona - > regmap , ARIZONA_HP_CTRL_1R ,
mask , val ) ;
2021-03-07 18:18:05 +03:00
if ( ret )
dev_warn ( arizona - > dev , " Failed to do clamp: %d \n " , ret ) ;
2015-09-28 14:41:42 +03:00
}
2013-02-22 22:38:03 +04:00
2015-02-16 18:41:02 +03:00
/* Restore the desired state while not doing the clamp */
if ( ! clamp ) {
2013-02-22 22:38:03 +04:00
ret = regmap_update_bits ( arizona - > regmap ,
ARIZONA_OUTPUT_ENABLES_1 ,
ARIZONA_OUT1L_ENA |
ARIZONA_OUT1R_ENA , arizona - > hp_ena ) ;
2021-03-07 18:18:05 +03:00
if ( ret )
dev_warn ( arizona - > dev , " Failed to restore headphone outputs: %d \n " , ret ) ;
2013-02-12 17:00:31 +04:00
}
2015-12-29 19:32:03 +03:00
snd_soc_dapm_mutex_unlock ( arizona - > dapm ) ;
2013-02-12 17:00:31 +04:00
}
2021-03-07 18:18:01 +03:00
static void arizona_extcon_set_mode ( struct arizona_priv * info , int mode )
2012-06-24 15:09:45 +04:00
{
struct arizona * arizona = info - > arizona ;
2013-04-02 01:03:06 +04:00
mode % = info - > micd_num_modes ;
2013-01-25 16:14:44 +04:00
2016-11-25 16:44:36 +03:00
gpiod_set_value_cansleep ( info - > micd_pol_gpio ,
info - > micd_modes [ mode ] . gpio ) ;
2015-06-19 19:23:31 +03:00
2012-06-24 15:09:45 +04:00
regmap_update_bits ( arizona - > regmap , ARIZONA_MIC_DETECT_1 ,
ARIZONA_MICD_BIAS_SRC_MASK ,
2013-09-23 17:33:59 +04:00
info - > micd_modes [ mode ] . bias < <
ARIZONA_MICD_BIAS_SRC_SHIFT ) ;
2012-06-24 15:09:45 +04:00
regmap_update_bits ( arizona - > regmap , ARIZONA_ACCESSORY_DETECT_MODE_1 ,
ARIZONA_ACCDET_SRC , info - > micd_modes [ mode ] . src ) ;
info - > micd_mode = mode ;
dev_dbg ( arizona - > dev , " Set jack polarity to %d \n " , mode ) ;
}
2021-03-07 18:18:01 +03:00
static const char * arizona_extcon_get_micbias ( struct arizona_priv * info )
2013-01-10 23:38:43 +04:00
{
2013-09-23 17:33:59 +04:00
switch ( info - > micd_modes [ 0 ] . bias ) {
2013-01-10 23:38:43 +04:00
case 1 :
return " MICBIAS1 " ;
case 2 :
return " MICBIAS2 " ;
case 3 :
return " MICBIAS3 " ;
default :
return " MICVDD " ;
}
}
2021-03-07 18:18:01 +03:00
static void arizona_extcon_pulse_micbias ( struct arizona_priv * info )
2013-01-10 23:38:43 +04:00
{
struct arizona * arizona = info - > arizona ;
const char * widget = arizona_extcon_get_micbias ( info ) ;
struct snd_soc_dapm_context * dapm = arizona - > dapm ;
2016-11-29 18:44:41 +03:00
struct snd_soc_component * component = snd_soc_dapm_to_component ( dapm ) ;
2013-01-10 23:38:43 +04:00
int ret ;
2016-11-29 18:44:41 +03:00
ret = snd_soc_component_force_enable_pin ( component , widget ) ;
2021-03-07 18:18:05 +03:00
if ( ret )
dev_warn ( arizona - > dev , " Failed to enable %s: %d \n " , widget , ret ) ;
2013-01-10 23:38:43 +04:00
snd_soc_dapm_sync ( dapm ) ;
if ( ! arizona - > pdata . micd_force_micbias ) {
2016-11-29 18:44:41 +03:00
ret = snd_soc_component_disable_pin ( component , widget ) ;
2021-03-07 18:18:05 +03:00
if ( ret )
dev_warn ( arizona - > dev , " Failed to disable %s: %d \n " , widget , ret ) ;
2013-01-10 23:38:43 +04:00
snd_soc_dapm_sync ( dapm ) ;
}
}
2021-03-07 18:18:01 +03:00
static void arizona_start_mic ( struct arizona_priv * info )
2013-01-11 03:55:46 +04:00
{
struct arizona * arizona = info - > arizona ;
bool change ;
int ret ;
2015-09-16 12:42:16 +03:00
unsigned int mode ;
2013-01-11 03:55:46 +04:00
/* Microphone detection can't use idle mode */
2021-03-07 18:18:02 +03:00
pm_runtime_get_sync ( arizona - > dev ) ;
2013-01-11 03:55:46 +04:00
2013-01-10 23:38:43 +04:00
if ( info - > detecting ) {
ret = regulator_allow_bypass ( info - > micvdd , false ) ;
2021-03-07 18:18:05 +03:00
if ( ret )
dev_err ( arizona - > dev , " Failed to regulate MICVDD: %d \n " , ret ) ;
2013-01-10 23:38:43 +04:00
}
2013-01-11 03:55:46 +04:00
ret = regulator_enable ( info - > micvdd ) ;
2021-03-07 18:18:05 +03:00
if ( ret )
dev_err ( arizona - > dev , " Failed to enable MICVDD: %d \n " , ret ) ;
2013-01-11 03:55:46 +04:00
if ( info - > micd_reva ) {
2019-12-09 14:09:08 +03:00
const struct reg_sequence reva [ ] = {
{ 0x80 , 0x3 } ,
{ 0x294 , 0x0 } ,
{ 0x80 , 0x0 } ,
} ;
regmap_multi_reg_write ( arizona - > regmap , reva , ARRAY_SIZE ( reva ) ) ;
2013-01-11 03:55:46 +04:00
}
2015-09-16 12:42:16 +03:00
if ( info - > detecting & & arizona - > pdata . micd_software_compare )
mode = ARIZONA_ACCDET_MODE_ADC ;
else
mode = ARIZONA_ACCDET_MODE_MIC ;
2013-01-11 03:55:46 +04:00
regmap_update_bits ( arizona - > regmap ,
ARIZONA_ACCESSORY_DETECT_MODE_1 ,
2015-09-16 12:42:16 +03:00
ARIZONA_ACCDET_MODE_MASK , mode ) ;
2013-01-11 03:55:46 +04:00
2013-01-10 23:38:43 +04:00
arizona_extcon_pulse_micbias ( info ) ;
2019-05-29 12:46:05 +03:00
ret = regmap_update_bits_check ( arizona - > regmap , ARIZONA_MIC_DETECT_1 ,
ARIZONA_MICD_ENA , ARIZONA_MICD_ENA ,
& change ) ;
if ( ret < 0 ) {
dev_err ( arizona - > dev , " Failed to enable micd: %d \n " , ret ) ;
} else if ( ! change ) {
2013-01-11 03:55:46 +04:00
regulator_disable ( info - > micvdd ) ;
2021-03-07 18:18:02 +03:00
pm_runtime_put_autosuspend ( arizona - > dev ) ;
2013-01-11 03:55:46 +04:00
}
}
2021-03-07 18:18:01 +03:00
static void arizona_stop_mic ( struct arizona_priv * info )
2013-01-11 03:55:46 +04:00
{
struct arizona * arizona = info - > arizona ;
2013-01-10 23:38:43 +04:00
const char * widget = arizona_extcon_get_micbias ( info ) ;
struct snd_soc_dapm_context * dapm = arizona - > dapm ;
2016-11-29 18:44:41 +03:00
struct snd_soc_component * component = snd_soc_dapm_to_component ( dapm ) ;
2019-05-29 12:46:05 +03:00
bool change = false ;
2013-01-10 23:38:43 +04:00
int ret ;
2013-01-11 03:55:46 +04:00
2019-05-29 12:46:05 +03:00
ret = regmap_update_bits_check ( arizona - > regmap , ARIZONA_MIC_DETECT_1 ,
ARIZONA_MICD_ENA , 0 ,
& change ) ;
if ( ret < 0 )
dev_err ( arizona - > dev , " Failed to disable micd: %d \n " , ret ) ;
2013-01-11 03:55:46 +04:00
2016-11-29 18:44:41 +03:00
ret = snd_soc_component_disable_pin ( component , widget ) ;
2021-03-07 18:18:05 +03:00
if ( ret )
dev_warn ( arizona - > dev , " Failed to disable %s: %d \n " , widget , ret ) ;
2013-01-10 23:38:43 +04:00
snd_soc_dapm_sync ( dapm ) ;
2013-01-11 03:55:46 +04:00
if ( info - > micd_reva ) {
2019-12-09 14:09:08 +03:00
const struct reg_sequence reva [ ] = {
{ 0x80 , 0x3 } ,
{ 0x294 , 0x2 } ,
{ 0x80 , 0x0 } ,
} ;
regmap_multi_reg_write ( arizona - > regmap , reva , ARRAY_SIZE ( reva ) ) ;
2013-01-11 03:55:46 +04:00
}
2013-01-10 23:38:43 +04:00
ret = regulator_allow_bypass ( info - > micvdd , true ) ;
2021-03-07 18:18:05 +03:00
if ( ret )
dev_err ( arizona - > dev , " Failed to bypass MICVDD: %d \n " , ret ) ;
2013-01-10 23:38:43 +04:00
2013-01-11 03:55:46 +04:00
if ( change ) {
regulator_disable ( info - > micvdd ) ;
2021-03-07 18:18:02 +03:00
pm_runtime_mark_last_busy ( arizona - > dev ) ;
pm_runtime_put_autosuspend ( arizona - > dev ) ;
2013-01-11 03:55:46 +04:00
}
}
2013-01-11 03:55:43 +04:00
static struct {
2014-05-30 16:19:17 +04:00
unsigned int threshold ;
2013-01-11 03:55:43 +04:00
unsigned int factor_a ;
unsigned int factor_b ;
} arizona_hpdet_b_ranges [ ] = {
2014-05-30 16:19:17 +04:00
{ 100 , 5528 , 362464 } ,
{ 169 , 11084 , 6186851 } ,
{ 169 , 11065 , 65460395 } ,
2013-01-11 03:55:43 +04:00
} ;
2014-05-30 16:19:17 +04:00
# define ARIZONA_HPDET_B_RANGE_MAX 0x3fb
2013-01-11 03:55:43 +04:00
static struct {
int min ;
int max ;
} arizona_hpdet_c_ranges [ ] = {
{ 0 , 30 } ,
{ 8 , 100 } ,
{ 100 , 1000 } ,
{ 1000 , 10000 } ,
} ;
2021-03-07 18:18:01 +03:00
static int arizona_hpdet_read ( struct arizona_priv * info )
2013-01-11 03:55:43 +04:00
{
struct arizona * arizona = info - > arizona ;
unsigned int val , range ;
int ret ;
ret = regmap_read ( arizona - > regmap , ARIZONA_HEADPHONE_DETECT_2 , & val ) ;
2021-03-07 18:18:05 +03:00
if ( ret ) {
dev_err ( arizona - > dev , " Failed to read HPDET status: %d \n " , ret ) ;
2013-01-11 03:55:43 +04:00
return ret ;
}
2015-04-28 15:34:27 +03:00
switch ( info - > hpdet_ip_version ) {
2013-01-11 03:55:43 +04:00
case 0 :
if ( ! ( val & ARIZONA_HP_DONE ) ) {
2021-03-07 18:18:05 +03:00
dev_err ( arizona - > dev , " HPDET did not complete: %x \n " , val ) ;
2013-01-21 12:30:02 +04:00
return - EAGAIN ;
2013-01-11 03:55:43 +04:00
}
val & = ARIZONA_HP_LVL_MASK ;
break ;
case 1 :
if ( ! ( val & ARIZONA_HP_DONE_B ) ) {
2021-03-07 18:18:05 +03:00
dev_err ( arizona - > dev , " HPDET did not complete: %x \n " , val ) ;
2013-01-21 12:30:02 +04:00
return - EAGAIN ;
2013-01-11 03:55:43 +04:00
}
ret = regmap_read ( arizona - > regmap , ARIZONA_HP_DACVAL , & val ) ;
2021-03-07 18:18:05 +03:00
if ( ret ) {
dev_err ( arizona - > dev , " Failed to read HP value: %d \n " , ret ) ;
2013-01-21 12:30:02 +04:00
return - EAGAIN ;
2013-01-11 03:55:43 +04:00
}
regmap_read ( arizona - > regmap , ARIZONA_HEADPHONE_DETECT_1 ,
& range ) ;
range = ( range & ARIZONA_HP_IMPEDANCE_RANGE_MASK )
> > ARIZONA_HP_IMPEDANCE_RANGE_SHIFT ;
if ( range < ARRAY_SIZE ( arizona_hpdet_b_ranges ) - 1 & &
2014-05-30 16:19:17 +04:00
( val < arizona_hpdet_b_ranges [ range ] . threshold | |
val > = ARIZONA_HPDET_B_RANGE_MAX ) ) {
2013-01-11 03:55:43 +04:00
range + + ;
2021-03-07 18:18:05 +03:00
dev_dbg ( arizona - > dev , " Moving to HPDET range %d \n " , range ) ;
2013-01-11 03:55:43 +04:00
regmap_update_bits ( arizona - > regmap ,
ARIZONA_HEADPHONE_DETECT_1 ,
ARIZONA_HP_IMPEDANCE_RANGE_MASK ,
range < <
ARIZONA_HP_IMPEDANCE_RANGE_SHIFT ) ;
return - EAGAIN ;
}
/* If we go out of range report top of range */
2014-05-30 16:19:17 +04:00
if ( val < arizona_hpdet_b_ranges [ range ] . threshold | |
val > = ARIZONA_HPDET_B_RANGE_MAX ) {
2013-01-11 03:55:43 +04:00
dev_dbg ( arizona - > dev , " Measurement out of range \n " ) ;
2013-04-01 22:09:45 +04:00
return ARIZONA_HPDET_MAX ;
2013-01-11 03:55:43 +04:00
}
2021-03-07 18:18:05 +03:00
dev_dbg ( arizona - > dev , " HPDET read %d in range %d \n " , val , range ) ;
2013-01-11 03:55:43 +04:00
val = arizona_hpdet_b_ranges [ range ] . factor_b
/ ( ( val * 100 ) -
arizona_hpdet_b_ranges [ range ] . factor_a ) ;
break ;
case 2 :
if ( ! ( val & ARIZONA_HP_DONE_B ) ) {
2021-03-07 18:18:05 +03:00
dev_err ( arizona - > dev , " HPDET did not complete: %x \n " , val ) ;
2013-01-21 12:30:02 +04:00
return - EAGAIN ;
2013-01-11 03:55:43 +04:00
}
val & = ARIZONA_HP_LVL_B_MASK ;
2013-11-14 20:18:25 +04:00
/* Convert to ohms, the value is in 0.5 ohm increments */
val / = 2 ;
2013-01-11 03:55:43 +04:00
regmap_read ( arizona - > regmap , ARIZONA_HEADPHONE_DETECT_1 ,
& range ) ;
range = ( range & ARIZONA_HP_IMPEDANCE_RANGE_MASK )
> > ARIZONA_HP_IMPEDANCE_RANGE_SHIFT ;
2013-11-14 20:18:24 +04:00
/* Skip up a range, or report? */
2013-01-11 03:55:43 +04:00
if ( range < ARRAY_SIZE ( arizona_hpdet_c_ranges ) - 1 & &
( val > = arizona_hpdet_c_ranges [ range ] . max ) ) {
range + + ;
dev_dbg ( arizona - > dev , " Moving to HPDET range %d-%d \n " ,
arizona_hpdet_c_ranges [ range ] . min ,
arizona_hpdet_c_ranges [ range ] . max ) ;
regmap_update_bits ( arizona - > regmap ,
ARIZONA_HEADPHONE_DETECT_1 ,
ARIZONA_HP_IMPEDANCE_RANGE_MASK ,
range < <
ARIZONA_HP_IMPEDANCE_RANGE_SHIFT ) ;
return - EAGAIN ;
}
2013-11-14 20:18:24 +04:00
if ( range & & ( val < arizona_hpdet_c_ranges [ range ] . min ) ) {
dev_dbg ( arizona - > dev , " Reporting range boundary %d \n " ,
arizona_hpdet_c_ranges [ range ] . min ) ;
val = arizona_hpdet_c_ranges [ range ] . min ;
}
2015-09-29 13:06:31 +03:00
break ;
default :
2021-03-07 18:18:05 +03:00
dev_warn ( arizona - > dev , " Unknown HPDET IP revision %d \n " , info - > hpdet_ip_version ) ;
2015-09-29 13:06:31 +03:00
return - EINVAL ;
2013-01-11 03:55:43 +04:00
}
dev_dbg ( arizona - > dev , " HP impedance %d ohms \n " , val ) ;
return val ;
}
2021-03-07 18:18:01 +03:00
static int arizona_hpdet_do_id ( struct arizona_priv * info , int * reading ,
2013-02-26 03:42:31 +04:00
bool * mic )
2013-01-11 03:55:51 +04:00
{
struct arizona * arizona = info - > arizona ;
2013-01-11 03:55:54 +04:00
int id_gpio = arizona - > pdata . hpdet_id_gpio ;
2013-01-11 03:55:51 +04:00
2019-12-09 14:09:14 +03:00
if ( ! arizona - > pdata . hpdet_acc_id )
return 0 ;
2013-01-11 03:55:51 +04:00
/*
* If we ' re using HPDET for accessory identification we need
* to take multiple measurements , step through them in sequence .
*/
2019-12-09 14:09:14 +03:00
info - > hpdet_res [ info - > num_hpdet_res + + ] = * reading ;
2013-02-05 21:48:49 +04:00
2019-12-09 14:09:14 +03:00
/* Only check the mic directly if we didn't already ID it */
if ( id_gpio & & info - > num_hpdet_res = = 1 ) {
dev_dbg ( arizona - > dev , " Measuring mic \n " ) ;
2013-04-01 22:09:45 +04:00
2013-01-11 03:55:51 +04:00
regmap_update_bits ( arizona - > regmap ,
ARIZONA_ACCESSORY_DETECT_MODE_1 ,
2019-12-09 14:09:14 +03:00
ARIZONA_ACCDET_MODE_MASK |
2013-01-11 03:55:51 +04:00
ARIZONA_ACCDET_SRC ,
2019-12-09 14:09:14 +03:00
ARIZONA_ACCDET_MODE_HPR |
2013-01-11 03:55:51 +04:00
info - > micd_modes [ 0 ] . src ) ;
2019-12-09 14:09:14 +03:00
gpio_set_value_cansleep ( id_gpio , 1 ) ;
regmap_update_bits ( arizona - > regmap , ARIZONA_HEADPHONE_DETECT_1 ,
ARIZONA_HP_POLL , ARIZONA_HP_POLL ) ;
return - EAGAIN ;
}
/* OK, got both. Now, compare... */
dev_dbg ( arizona - > dev , " HPDET measured %d %d \n " ,
info - > hpdet_res [ 0 ] , info - > hpdet_res [ 1 ] ) ;
/* Take the headphone impedance for the main report */
* reading = info - > hpdet_res [ 0 ] ;
/* Sometimes we get false readings due to slow insert */
if ( * reading > = ARIZONA_HPDET_MAX & & ! info - > hpdet_retried ) {
dev_dbg ( arizona - > dev , " Retrying high impedance \n " ) ;
info - > num_hpdet_res = 0 ;
info - > hpdet_retried = true ;
arizona_start_hpdet_acc_id ( info ) ;
2021-03-07 18:18:02 +03:00
pm_runtime_put ( arizona - > dev ) ;
2019-12-09 14:09:14 +03:00
return - EAGAIN ;
2013-01-11 03:55:51 +04:00
}
2019-12-09 14:09:14 +03:00
/*
* If we measure the mic as high impedance
*/
if ( ! id_gpio | | info - > hpdet_res [ 1 ] > 50 ) {
dev_dbg ( arizona - > dev , " Detected mic \n " ) ;
* mic = true ;
info - > detecting = true ;
} else {
dev_dbg ( arizona - > dev , " Detected headphone \n " ) ;
}
/* Make sure everything is reset back to the real polarity */
regmap_update_bits ( arizona - > regmap , ARIZONA_ACCESSORY_DETECT_MODE_1 ,
ARIZONA_ACCDET_SRC , info - > micd_modes [ 0 ] . src ) ;
2013-01-11 03:55:51 +04:00
return 0 ;
}
2013-01-11 03:55:43 +04:00
static irqreturn_t arizona_hpdet_irq ( int irq , void * data )
{
2021-03-07 18:18:01 +03:00
struct arizona_priv * info = data ;
2013-01-11 03:55:43 +04:00
struct arizona * arizona = info - > arizona ;
2013-01-11 03:55:54 +04:00
int id_gpio = arizona - > pdata . hpdet_id_gpio ;
2021-03-07 18:18:04 +03:00
int ret , reading , state , report ;
2013-02-26 03:42:31 +04:00
bool mic = false ;
2013-01-11 03:55:43 +04:00
mutex_lock ( & info - > lock ) ;
/* If we got a spurious IRQ for some reason then ignore it */
if ( ! info - > hpdet_active ) {
dev_warn ( arizona - > dev , " Spurious HPDET IRQ \n " ) ;
mutex_unlock ( & info - > lock ) ;
return IRQ_NONE ;
}
/* If the cable was removed while measuring ignore the result */
2021-03-07 18:18:04 +03:00
state = info - > jack - > status & SND_JACK_MECHANICAL ;
if ( ! state ) {
2013-01-11 03:55:43 +04:00
dev_dbg ( arizona - > dev , " Ignoring HPDET for removed cable \n " ) ;
goto done ;
}
ret = arizona_hpdet_read ( info ) ;
2013-08-23 05:21:39 +04:00
if ( ret = = - EAGAIN )
2013-01-11 03:55:43 +04:00
goto out ;
2013-08-23 05:21:39 +04:00
else if ( ret < 0 )
2013-01-11 03:55:43 +04:00
goto done ;
2013-01-11 03:55:51 +04:00
reading = ret ;
2013-01-11 03:55:43 +04:00
/* Reset back to starting range */
regmap_update_bits ( arizona - > regmap ,
ARIZONA_HEADPHONE_DETECT_1 ,
2013-01-11 03:55:51 +04:00
ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL ,
0 ) ;
2013-02-26 03:42:31 +04:00
ret = arizona_hpdet_do_id ( info , & reading , & mic ) ;
2013-08-23 05:21:39 +04:00
if ( ret = = - EAGAIN )
2013-01-11 03:55:51 +04:00
goto out ;
2013-08-23 05:21:39 +04:00
else if ( ret < 0 )
2013-01-11 03:55:51 +04:00
goto done ;
2013-01-11 03:55:43 +04:00
/* Report high impedence cables as line outputs */
2013-01-11 03:55:51 +04:00
if ( reading > = 5000 )
2021-03-07 18:18:04 +03:00
report = SND_JACK_LINEOUT ;
2013-01-11 03:55:43 +04:00
else
2021-03-07 18:18:04 +03:00
report = SND_JACK_HEADPHONE ;
2013-01-11 03:55:43 +04:00
2021-03-07 18:18:04 +03:00
snd_soc_jack_report ( info - > jack , report , SND_JACK_LINEOUT | SND_JACK_HEADPHONE ) ;
2013-01-11 03:55:43 +04:00
2013-11-14 20:18:22 +04:00
done :
/* Reset back to starting range */
regmap_update_bits ( arizona - > regmap ,
ARIZONA_HEADPHONE_DETECT_1 ,
ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL ,
0 ) ;
2015-02-16 18:41:02 +03:00
arizona_extcon_hp_clamp ( info , false ) ;
2013-01-11 03:55:43 +04:00
2013-01-11 03:55:54 +04:00
if ( id_gpio )
gpio_set_value_cansleep ( id_gpio , 0 ) ;
2013-01-11 03:55:43 +04:00
/* If we have a mic then reenable MICDET */
2021-03-07 18:17:56 +03:00
if ( state & & ( mic | | info - > mic ) )
2013-01-11 03:55:43 +04:00
arizona_start_mic ( info ) ;
if ( info - > hpdet_active ) {
2021-03-07 18:18:02 +03:00
pm_runtime_put_autosuspend ( arizona - > dev ) ;
2013-01-11 03:55:43 +04:00
info - > hpdet_active = false ;
}
2021-03-07 18:17:56 +03:00
/* Do not set hp_det done when the cable has been unplugged */
if ( state )
info - > hpdet_done = true ;
2013-02-06 00:20:17 +04:00
2013-01-11 03:55:43 +04:00
out :
mutex_unlock ( & info - > lock ) ;
return IRQ_HANDLED ;
}
2021-03-07 18:18:01 +03:00
static void arizona_identify_headphone ( struct arizona_priv * info )
2013-01-11 03:55:43 +04:00
{
struct arizona * arizona = info - > arizona ;
int ret ;
2013-02-06 00:20:17 +04:00
if ( info - > hpdet_done )
return ;
2013-01-11 03:55:43 +04:00
dev_dbg ( arizona - > dev , " Starting HPDET \n " ) ;
/* Make sure we keep the device enabled during the measurement */
2021-03-07 18:18:02 +03:00
pm_runtime_get_sync ( arizona - > dev ) ;
2013-01-11 03:55:43 +04:00
info - > hpdet_active = true ;
2019-12-09 14:09:11 +03:00
arizona_stop_mic ( info ) ;
2013-01-11 03:55:43 +04:00
2015-02-16 18:41:02 +03:00
arizona_extcon_hp_clamp ( info , true ) ;
2013-01-11 03:55:43 +04:00
ret = regmap_update_bits ( arizona - > regmap ,
ARIZONA_ACCESSORY_DETECT_MODE_1 ,
ARIZONA_ACCDET_MODE_MASK ,
2015-05-04 07:42:13 +03:00
arizona - > pdata . hpdet_channel ) ;
2013-01-11 03:55:43 +04:00
if ( ret ! = 0 ) {
2015-05-04 07:42:13 +03:00
dev_err ( arizona - > dev , " Failed to set HPDET mode: %d \n " , ret ) ;
2013-01-11 03:55:43 +04:00
goto err ;
}
ret = regmap_update_bits ( arizona - > regmap , ARIZONA_HEADPHONE_DETECT_1 ,
ARIZONA_HP_POLL , ARIZONA_HP_POLL ) ;
2021-03-07 18:18:05 +03:00
if ( ret ) {
dev_err ( arizona - > dev , " Can't start HPDETL measurement: %d \n " , ret ) ;
2013-01-11 03:55:43 +04:00
goto err ;
}
return ;
err :
2019-12-09 14:09:07 +03:00
arizona_extcon_hp_clamp ( info , false ) ;
2021-03-07 18:18:02 +03:00
pm_runtime_put_autosuspend ( arizona - > dev ) ;
2019-12-09 14:09:07 +03:00
2013-01-11 03:55:43 +04:00
/* Just report headphone */
2021-03-07 18:18:04 +03:00
snd_soc_jack_report ( info - > jack , SND_JACK_HEADPHONE ,
SND_JACK_LINEOUT | SND_JACK_HEADPHONE ) ;
2013-01-11 03:55:43 +04:00
if ( info - > mic )
arizona_start_mic ( info ) ;
info - > hpdet_active = false ;
}
2013-01-11 03:55:51 +04:00
2021-03-07 18:18:01 +03:00
static void arizona_start_hpdet_acc_id ( struct arizona_priv * info )
2013-01-11 03:55:51 +04:00
{
struct arizona * arizona = info - > arizona ;
2013-02-26 03:42:31 +04:00
int hp_reading = 32 ;
bool mic ;
2013-01-11 03:55:51 +04:00
int ret ;
dev_dbg ( arizona - > dev , " Starting identification via HPDET \n " ) ;
/* Make sure we keep the device enabled during the measurement */
2021-03-07 18:18:02 +03:00
pm_runtime_get_sync ( arizona - > dev ) ;
2013-01-11 03:55:51 +04:00
info - > hpdet_active = true ;
2015-02-16 18:41:02 +03:00
arizona_extcon_hp_clamp ( info , true ) ;
2013-01-11 03:55:51 +04:00
ret = regmap_update_bits ( arizona - > regmap ,
ARIZONA_ACCESSORY_DETECT_MODE_1 ,
ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK ,
info - > micd_modes [ 0 ] . src |
2015-05-04 07:42:13 +03:00
arizona - > pdata . hpdet_channel ) ;
2013-01-11 03:55:51 +04:00
if ( ret ! = 0 ) {
2015-05-04 07:42:13 +03:00
dev_err ( arizona - > dev , " Failed to set HPDET mode: %d \n " , ret ) ;
2013-01-11 03:55:51 +04:00
goto err ;
}
2013-02-26 03:42:31 +04:00
if ( arizona - > pdata . hpdet_acc_id_line ) {
ret = regmap_update_bits ( arizona - > regmap ,
ARIZONA_HEADPHONE_DETECT_1 ,
ARIZONA_HP_POLL , ARIZONA_HP_POLL ) ;
2021-03-07 18:18:05 +03:00
if ( ret ) {
dev_err ( arizona - > dev , " Can't start HPDETL measurement: %d \n " , ret ) ;
2013-02-26 03:42:31 +04:00
goto err ;
}
} else {
arizona_hpdet_do_id ( info , & hp_reading , & mic ) ;
2013-01-11 03:55:43 +04:00
}
2013-01-11 03:55:51 +04:00
return ;
err :
/* Just report headphone */
2021-03-07 18:18:04 +03:00
snd_soc_jack_report ( info - > jack , SND_JACK_HEADPHONE ,
SND_JACK_LINEOUT | SND_JACK_HEADPHONE ) ;
2013-01-11 03:55:51 +04:00
2013-01-11 03:55:43 +04:00
info - > hpdet_active = false ;
}
2013-04-01 22:17:34 +04:00
static void arizona_micd_timeout_work ( struct work_struct * work )
{
2021-03-07 18:18:01 +03:00
struct arizona_priv * info = container_of ( work ,
struct arizona_priv ,
2013-08-23 05:21:37 +04:00
micd_timeout_work . work ) ;
2013-04-01 22:17:34 +04:00
mutex_lock ( & info - > lock ) ;
dev_dbg ( info - > arizona - > dev , " MICD timed out, reporting HP \n " ) ;
info - > detecting = false ;
2015-06-19 19:23:32 +03:00
arizona_identify_headphone ( info ) ;
2013-04-01 22:17:34 +04:00
mutex_unlock ( & info - > lock ) ;
}
2021-03-07 18:18:01 +03:00
static int arizona_micd_adc_read ( struct arizona_priv * info )
2012-06-24 15:09:45 +04:00
{
struct arizona * arizona = info - > arizona ;
2019-12-09 14:09:15 +03:00
unsigned int val ;
int ret ;
2013-04-01 22:17:34 +04:00
2019-12-09 14:09:15 +03:00
/* Must disable MICD before we read the ADCVAL */
regmap_update_bits ( arizona - > regmap , ARIZONA_MIC_DETECT_1 ,
ARIZONA_MICD_ENA , 0 ) ;
2012-06-24 15:09:45 +04:00
2019-12-09 14:09:15 +03:00
ret = regmap_read ( arizona - > regmap , ARIZONA_MIC_DETECT_4 , & val ) ;
2021-03-07 18:18:05 +03:00
if ( ret ) {
dev_err ( arizona - > dev , " Failed to read MICDET_ADCVAL: %d \n " , ret ) ;
2019-12-09 14:09:15 +03:00
return ret ;
2013-11-14 20:18:23 +04:00
}
2019-12-09 14:09:15 +03:00
dev_dbg ( arizona - > dev , " MICDET_ADCVAL: %x \n " , val ) ;
2015-09-16 12:42:16 +03:00
2019-12-09 14:09:15 +03:00
val & = ARIZONA_MICDET_ADCVAL_MASK ;
if ( val < ARRAY_SIZE ( arizona_micd_levels ) )
val = arizona_micd_levels [ val ] ;
else
val = INT_MAX ;
if ( val < = QUICK_HEADPHONE_MAX_OHM )
val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_0 ;
else if ( val < = MICROPHONE_MIN_OHM )
val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_1 ;
else if ( val < = MICROPHONE_MAX_OHM )
val = ARIZONA_MICD_STS | ARIZONA_MICD_LVL_8 ;
else
val = ARIZONA_MICD_LVL_8 ;
return val ;
}
2021-03-07 18:18:01 +03:00
static int arizona_micd_read ( struct arizona_priv * info )
2019-12-09 14:09:15 +03:00
{
struct arizona * arizona = info - > arizona ;
unsigned int val = 0 ;
int ret , i ;
2015-09-16 12:42:16 +03:00
2013-11-14 20:18:21 +04:00
for ( i = 0 ; i < 10 & & ! ( val & MICD_LVL_0_TO_8 ) ; i + + ) {
2013-04-01 22:06:29 +04:00
ret = regmap_read ( arizona - > regmap , ARIZONA_MIC_DETECT_3 , & val ) ;
2021-03-07 18:18:05 +03:00
if ( ret ) {
dev_err ( arizona - > dev , " Failed to read MICDET: %d \n " , ret ) ;
2019-12-09 14:09:15 +03:00
return ret ;
2013-04-01 22:06:29 +04:00
}
dev_dbg ( arizona - > dev , " MICDET: %x \n " , val ) ;
2012-06-24 15:09:45 +04:00
2013-04-01 22:06:29 +04:00
if ( ! ( val & ARIZONA_MICD_VALID ) ) {
2021-03-07 18:18:05 +03:00
dev_warn ( arizona - > dev , " Microphone detection state invalid \n " ) ;
2019-12-09 14:09:15 +03:00
return - EINVAL ;
2013-04-01 22:06:29 +04:00
}
}
2012-06-24 15:09:45 +04:00
2013-11-14 20:18:21 +04:00
if ( i = = 10 & & ! ( val & MICD_LVL_0_TO_8 ) ) {
2013-04-01 22:06:29 +04:00
dev_err ( arizona - > dev , " Failed to get valid MICDET value \n " ) ;
2019-12-09 14:09:15 +03:00
return - EINVAL ;
}
return val ;
}
2019-12-09 14:09:16 +03:00
static int arizona_micdet_reading ( void * priv )
2019-12-09 14:09:15 +03:00
{
2021-03-07 18:18:01 +03:00
struct arizona_priv * info = priv ;
2019-12-09 14:09:15 +03:00
struct arizona * arizona = info - > arizona ;
2019-12-09 14:09:16 +03:00
int ret , val ;
2012-06-24 15:09:45 +04:00
2019-12-09 14:09:15 +03:00
if ( info - > detecting & & arizona - > pdata . micd_software_compare )
ret = arizona_micd_adc_read ( info ) ;
else
ret = arizona_micd_read ( info ) ;
if ( ret < 0 )
2019-12-09 14:09:16 +03:00
return ret ;
2019-12-09 14:09:15 +03:00
val = ret ;
2012-06-24 15:09:45 +04:00
/* Due to jack detect this should never happen */
if ( ! ( val & ARIZONA_MICD_STS ) ) {
dev_warn ( arizona - > dev , " Detected open circuit \n " ) ;
2015-06-25 18:47:02 +03:00
info - > mic = false ;
2012-06-24 15:09:45 +04:00
info - > detecting = false ;
2015-06-25 18:47:02 +03:00
arizona_identify_headphone ( info ) ;
2019-12-09 14:09:16 +03:00
return 0 ;
2012-06-24 15:09:45 +04:00
}
/* If we got a high impedence we should have a headset, report it. */
2019-12-09 14:09:16 +03:00
if ( val & ARIZONA_MICD_LVL_8 ) {
2015-06-19 19:23:32 +03:00
info - > mic = true ;
info - > detecting = false ;
2013-01-11 03:55:43 +04:00
arizona_identify_headphone ( info ) ;
2021-03-07 18:18:04 +03:00
snd_soc_jack_report ( info - > jack , SND_JACK_MICROPHONE , SND_JACK_MICROPHONE ) ;
2012-06-24 15:09:45 +04:00
2013-01-10 23:38:43 +04:00
/* Don't need to regulate for button detection */
2014-05-29 19:27:54 +04:00
ret = regulator_allow_bypass ( info - > micvdd , true ) ;
2021-03-07 18:18:05 +03:00
if ( ret )
dev_err ( arizona - > dev , " Failed to bypass MICVDD: %d \n " , ret ) ;
2013-01-10 23:38:43 +04:00
2019-12-09 14:09:16 +03:00
return 0 ;
2012-06-24 15:09:45 +04:00
}
/* If we detected a lower impedence during initial startup
* then we probably have the wrong polarity , flip it . Don ' t
* do this for the lowest impedences to speed up detection of
* plain headphones . If both polarities report a low
* impedence then give up and report headphones .
*/
2019-12-09 14:09:16 +03:00
if ( val & MICD_LVL_1_TO_7 ) {
2013-01-25 16:14:44 +04:00
if ( info - > jack_flips > = info - > micd_num_modes * 10 ) {
2013-01-11 03:55:43 +04:00
dev_dbg ( arizona - > dev , " Detected HP/line \n " ) ;
2012-06-24 15:09:45 +04:00
info - > detecting = false ;
2012-06-28 16:08:31 +04:00
2015-06-19 19:23:32 +03:00
arizona_identify_headphone ( info ) ;
2012-06-24 15:09:45 +04:00
} else {
info - > micd_mode + + ;
if ( info - > micd_mode = = info - > micd_num_modes )
info - > micd_mode = 0 ;
arizona_extcon_set_mode ( info , info - > micd_mode ) ;
info - > jack_flips + + ;
2019-12-09 14:09:16 +03:00
if ( arizona - > pdata . micd_software_compare )
regmap_update_bits ( arizona - > regmap ,
ARIZONA_MIC_DETECT_1 ,
ARIZONA_MICD_ENA ,
ARIZONA_MICD_ENA ) ;
queue_delayed_work ( system_power_efficient_wq ,
& info - > micd_timeout_work ,
msecs_to_jiffies ( arizona - > pdata . micd_timeout ) ) ;
2012-06-24 15:09:45 +04:00
}
2019-12-09 14:09:16 +03:00
return 0 ;
2012-06-24 15:09:45 +04:00
}
2019-12-09 14:09:16 +03:00
/*
* If we ' re still detecting and we detect a short then we ' ve
* got a headphone .
*/
dev_dbg ( arizona - > dev , " Headphone detected \n " ) ;
info - > detecting = false ;
arizona_identify_headphone ( info ) ;
return 0 ;
}
static int arizona_button_reading ( void * priv )
{
2021-03-07 18:18:01 +03:00
struct arizona_priv * info = priv ;
2019-12-09 14:09:16 +03:00
struct arizona * arizona = info - > arizona ;
2021-03-07 18:18:04 +03:00
int val , key , lvl ;
2019-12-09 14:09:16 +03:00
val = arizona_micd_read ( info ) ;
if ( val < 0 )
return val ;
2012-06-24 15:09:45 +04:00
/*
* If we ' re still detecting and we detect a short then we ' ve
2012-07-20 20:07:29 +04:00
* got a headphone . Otherwise it ' s a button press .
2012-06-24 15:09:45 +04:00
*/
2013-11-14 20:18:21 +04:00
if ( val & MICD_LVL_0_TO_7 ) {
2012-06-24 15:09:45 +04:00
if ( info - > mic ) {
dev_dbg ( arizona - > dev , " Mic button detected \n " ) ;
2012-07-20 20:07:29 +04:00
lvl = val & ARIZONA_MICD_LVL_MASK ;
lvl > > = ARIZONA_MICD_LVL_SHIFT ;
2013-04-02 01:03:06 +04:00
if ( lvl & & ffs ( lvl ) - 1 < info - > num_micd_ranges ) {
2021-03-07 18:18:04 +03:00
key = ffs ( lvl ) - 1 ;
snd_soc_jack_report ( info - > jack ,
SND_JACK_BTN_0 > > key ,
info - > micd_button_mask ) ;
2019-12-09 14:09:13 +03:00
} else {
dev_err ( arizona - > dev , " Button out of range \n " ) ;
2013-04-02 01:03:06 +04:00
}
2012-06-24 15:09:45 +04:00
} else {
2021-03-07 18:18:05 +03:00
dev_warn ( arizona - > dev , " Button with no mic: %x \n " , val ) ;
2012-06-24 15:09:45 +04:00
}
} else {
dev_dbg ( arizona - > dev , " Mic button released \n " ) ;
2021-03-07 18:18:04 +03:00
snd_soc_jack_report ( info - > jack , 0 , info - > micd_button_mask ) ;
2013-01-10 23:38:43 +04:00
arizona_extcon_pulse_micbias ( info ) ;
2012-06-24 15:09:45 +04:00
}
2019-12-09 14:09:16 +03:00
return 0 ;
}
2015-09-16 12:42:16 +03:00
2019-12-09 14:09:16 +03:00
static void arizona_micd_detect ( struct work_struct * work )
{
2021-03-07 18:18:01 +03:00
struct arizona_priv * info = container_of ( work ,
struct arizona_priv ,
2019-12-09 14:09:16 +03:00
micd_detect_work . work ) ;
struct arizona * arizona = info - > arizona ;
cancel_delayed_work_sync ( & info - > micd_timeout_work ) ;
mutex_lock ( & info - > lock ) ;
/* If the cable was removed while measuring ignore the result */
2021-03-07 18:18:04 +03:00
if ( ! ( info - > jack - > status & SND_JACK_MECHANICAL ) ) {
2019-12-09 14:09:16 +03:00
dev_dbg ( arizona - > dev , " Ignoring MICDET for removed cable \n " ) ;
mutex_unlock ( & info - > lock ) ;
return ;
2015-09-16 12:42:16 +03:00
}
2013-04-01 22:17:34 +04:00
2019-12-09 14:09:16 +03:00
if ( info - > detecting )
arizona_micdet_reading ( info ) ;
else
arizona_button_reading ( info ) ;
2021-03-07 18:18:02 +03:00
pm_runtime_mark_last_busy ( arizona - > dev ) ;
2012-06-24 15:09:45 +04:00
mutex_unlock ( & info - > lock ) ;
2013-04-01 22:21:48 +04:00
}
static irqreturn_t arizona_micdet ( int irq , void * data )
{
2021-03-07 18:18:01 +03:00
struct arizona_priv * info = data ;
2013-04-01 22:21:48 +04:00
struct arizona * arizona = info - > arizona ;
int debounce = arizona - > pdata . micd_detect_debounce ;
cancel_delayed_work_sync ( & info - > micd_detect_work ) ;
cancel_delayed_work_sync ( & info - > micd_timeout_work ) ;
mutex_lock ( & info - > lock ) ;
if ( ! info - > detecting )
debounce = 0 ;
mutex_unlock ( & info - > lock ) ;
if ( debounce )
2013-07-19 01:42:22 +04:00
queue_delayed_work ( system_power_efficient_wq ,
& info - > micd_detect_work ,
msecs_to_jiffies ( debounce ) ) ;
2013-04-01 22:21:48 +04:00
else
arizona_micd_detect ( & info - > micd_detect_work . work ) ;
2012-06-24 15:09:45 +04:00
return IRQ_HANDLED ;
}
2013-02-06 01:00:15 +04:00
static void arizona_hpdet_work ( struct work_struct * work )
{
2021-03-07 18:18:01 +03:00
struct arizona_priv * info = container_of ( work ,
struct arizona_priv ,
2013-08-23 05:21:37 +04:00
hpdet_work . work ) ;
2013-02-06 01:00:15 +04:00
mutex_lock ( & info - > lock ) ;
arizona_start_hpdet_acc_id ( info ) ;
mutex_unlock ( & info - > lock ) ;
}
2021-03-07 18:18:01 +03:00
static int arizona_hpdet_wait ( struct arizona_priv * info )
2017-01-25 12:34:06 +03:00
{
struct arizona * arizona = info - > arizona ;
unsigned int val ;
int i , ret ;
for ( i = 0 ; i < ARIZONA_HPDET_WAIT_COUNT ; i + + ) {
ret = regmap_read ( arizona - > regmap , ARIZONA_HEADPHONE_DETECT_2 ,
& val ) ;
if ( ret ) {
2021-03-07 18:18:05 +03:00
dev_err ( arizona - > dev , " Failed to read HPDET state: %d \n " , ret ) ;
2017-01-25 12:34:06 +03:00
return ret ;
}
switch ( info - > hpdet_ip_version ) {
case 0 :
if ( val & ARIZONA_HP_DONE )
return 0 ;
break ;
default :
if ( val & ARIZONA_HP_DONE_B )
return 0 ;
break ;
}
msleep ( ARIZONA_HPDET_WAIT_DELAY_MS ) ;
}
dev_warn ( arizona - > dev , " HPDET did not appear to complete \n " ) ;
return - ETIMEDOUT ;
}
2012-06-24 15:09:45 +04:00
static irqreturn_t arizona_jackdet ( int irq , void * data )
{
2021-03-07 18:18:01 +03:00
struct arizona_priv * info = data ;
2012-06-24 15:09:45 +04:00
struct arizona * arizona = info - > arizona ;
2013-01-11 03:55:39 +04:00
unsigned int val , present , mask ;
2013-04-01 22:17:34 +04:00
bool cancelled_hp , cancelled_mic ;
2012-07-20 20:07:29 +04:00
int ret , i ;
2012-06-24 15:09:45 +04:00
2013-04-01 22:17:34 +04:00
cancelled_hp = cancel_delayed_work_sync ( & info - > hpdet_work ) ;
cancelled_mic = cancel_delayed_work_sync ( & info - > micd_timeout_work ) ;
2012-06-24 15:09:45 +04:00
2021-03-07 18:18:02 +03:00
pm_runtime_get_sync ( arizona - > dev ) ;
2013-02-06 01:00:15 +04:00
2012-06-24 15:09:45 +04:00
mutex_lock ( & info - > lock ) ;
2015-09-16 12:42:20 +03:00
if ( info - > micd_clamp ) {
2013-01-11 03:55:39 +04:00
mask = ARIZONA_MICD_CLAMP_STS ;
2015-09-16 12:42:19 +03:00
present = 0 ;
2013-01-11 03:55:39 +04:00
} else {
mask = ARIZONA_JD1_STS ;
2014-05-23 15:54:57 +04:00
if ( arizona - > pdata . jd_invert )
present = 0 ;
else
present = ARIZONA_JD1_STS ;
2013-01-11 03:55:39 +04:00
}
2012-06-24 15:09:45 +04:00
ret = regmap_read ( arizona - > regmap , ARIZONA_AOD_IRQ_RAW_STATUS , & val ) ;
2021-03-07 18:18:05 +03:00
if ( ret ) {
dev_err ( arizona - > dev , " Failed to read jackdet status: %d \n " , ret ) ;
2012-06-24 15:09:45 +04:00
mutex_unlock ( & info - > lock ) ;
2021-03-07 18:18:02 +03:00
pm_runtime_put_autosuspend ( arizona - > dev ) ;
2012-06-24 15:09:45 +04:00
return IRQ_NONE ;
}
2013-04-01 22:05:27 +04:00
val & = mask ;
if ( val = = info - > last_jackdet ) {
dev_dbg ( arizona - > dev , " Suppressing duplicate JACKDET \n " ) ;
2013-04-01 22:17:34 +04:00
if ( cancelled_hp )
2013-07-19 01:42:22 +04:00
queue_delayed_work ( system_power_efficient_wq ,
& info - > hpdet_work ,
msecs_to_jiffies ( HPDET_DEBOUNCE ) ) ;
2013-04-01 22:05:27 +04:00
2013-08-23 05:21:37 +04:00
if ( cancelled_mic ) {
2019-12-09 14:09:09 +03:00
int micd_timeout = arizona - > pdata . micd_timeout ;
2013-08-23 05:21:37 +04:00
2013-07-19 01:42:22 +04:00
queue_delayed_work ( system_power_efficient_wq ,
& info - > micd_timeout_work ,
2013-08-23 05:21:37 +04:00
msecs_to_jiffies ( micd_timeout ) ) ;
}
2013-04-01 22:17:34 +04:00
2013-04-01 22:05:27 +04:00
goto out ;
}
info - > last_jackdet = val ;
if ( info - > last_jackdet = = present ) {
2012-06-24 15:09:45 +04:00
dev_dbg ( arizona - > dev , " Detected jack \n " ) ;
2021-03-07 18:18:04 +03:00
snd_soc_jack_report ( info - > jack , SND_JACK_MECHANICAL , SND_JACK_MECHANICAL ) ;
2012-06-24 15:09:45 +04:00
2019-12-09 14:09:10 +03:00
info - > detecting = true ;
info - > mic = false ;
info - > jack_flips = 0 ;
2013-01-11 03:55:51 +04:00
2019-12-09 14:09:10 +03:00
if ( ! arizona - > pdata . hpdet_acc_id ) {
2013-01-11 03:55:51 +04:00
arizona_start_mic ( info ) ;
} else {
2013-07-19 01:42:22 +04:00
queue_delayed_work ( system_power_efficient_wq ,
& info - > hpdet_work ,
msecs_to_jiffies ( HPDET_DEBOUNCE ) ) ;
2013-01-11 03:55:51 +04:00
}
2013-01-15 17:09:20 +04:00
2015-09-16 12:42:21 +03:00
if ( info - > micd_clamp | | ! arizona - > pdata . jd_invert )
regmap_update_bits ( arizona - > regmap ,
ARIZONA_JACK_DETECT_DEBOUNCE ,
ARIZONA_MICD_CLAMP_DB |
ARIZONA_JD1_DB , 0 ) ;
2012-06-24 15:09:45 +04:00
} else {
dev_dbg ( arizona - > dev , " Detected jack removal \n " ) ;
arizona_stop_mic ( info ) ;
2013-01-11 03:55:51 +04:00
info - > num_hpdet_res = 0 ;
for ( i = 0 ; i < ARRAY_SIZE ( info - > hpdet_res ) ; i + + )
info - > hpdet_res [ i ] = 0 ;
info - > mic = false ;
2013-02-06 00:20:17 +04:00
info - > hpdet_done = false ;
2013-04-01 22:09:45 +04:00
info - > hpdet_retried = false ;
2013-01-11 03:55:39 +04:00
2021-03-07 18:18:04 +03:00
snd_soc_jack_report ( info - > jack , 0 , ARIZONA_JACK_MASK | info - > micd_button_mask ) ;
2013-01-15 17:09:20 +04:00
2017-01-25 12:34:06 +03:00
/*
* If the jack was removed during a headphone detection we
* need to wait for the headphone detection to finish , as
* it can not be aborted . We don ' t want to be able to start
* a new headphone detection from a fresh insert until this
* one is finished .
*/
arizona_hpdet_wait ( info ) ;
2013-01-15 17:09:20 +04:00
regmap_update_bits ( arizona - > regmap ,
ARIZONA_JACK_DETECT_DEBOUNCE ,
ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB ,
ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB ) ;
2012-06-24 15:09:45 +04:00
}
2013-08-07 15:17:14 +04:00
out :
2013-02-05 14:13:38 +04:00
/* Clear trig_sts to make sure DCVDD is not forced up */
regmap_write ( arizona - > regmap , ARIZONA_AOD_WKUP_AND_TRIG ,
ARIZONA_MICD_CLAMP_FALL_TRIG_STS |
ARIZONA_MICD_CLAMP_RISE_TRIG_STS |
ARIZONA_JD1_FALL_TRIG_STS |
ARIZONA_JD1_RISE_TRIG_STS ) ;
2012-06-24 15:09:45 +04:00
mutex_unlock ( & info - > lock ) ;
2021-03-07 18:18:02 +03:00
pm_runtime_mark_last_busy ( arizona - > dev ) ;
pm_runtime_put_autosuspend ( arizona - > dev ) ;
2012-06-24 15:09:45 +04:00
return IRQ_HANDLED ;
}
2013-04-02 01:03:06 +04:00
/* Map a level onto a slot in the register bank */
static void arizona_micd_set_level ( struct arizona * arizona , int index ,
unsigned int level )
{
int reg ;
unsigned int mask ;
reg = ARIZONA_MIC_DETECT_LEVEL_4 - ( index / 2 ) ;
if ( ! ( index % 2 ) ) {
mask = 0x3f00 ;
level < < = 8 ;
} else {
mask = 0x3f ;
}
/* Program the level itself */
regmap_update_bits ( arizona - > regmap , reg , mask , level ) ;
}
2015-12-14 13:37:11 +03:00
static int arizona_extcon_get_micd_configs ( struct device * dev ,
struct arizona * arizona )
{
const char * const prop = " wlf,micd-configs " ;
const int entries_per_config = 3 ;
struct arizona_micd_config * micd_configs ;
int nconfs , ret ;
int i , j ;
u32 * vals ;
2019-07-23 20:40:21 +03:00
nconfs = device_property_count_u32 ( arizona - > dev , prop ) ;
2015-12-14 13:37:11 +03:00
if ( nconfs < = 0 )
return 0 ;
vals = kcalloc ( nconfs , sizeof ( u32 ) , GFP_KERNEL ) ;
if ( ! vals )
return - ENOMEM ;
ret = device_property_read_u32_array ( arizona - > dev , prop , vals , nconfs ) ;
if ( ret < 0 )
goto out ;
nconfs / = entries_per_config ;
2017-04-23 23:44:19 +03:00
micd_configs = devm_kcalloc ( dev , nconfs , sizeof ( * micd_configs ) ,
2015-12-14 13:37:11 +03:00
GFP_KERNEL ) ;
if ( ! micd_configs ) {
ret = - ENOMEM ;
goto out ;
}
for ( i = 0 , j = 0 ; i < nconfs ; + + i ) {
micd_configs [ i ] . src = vals [ j + + ] ? ARIZONA_ACCDET_SRC : 0 ;
micd_configs [ i ] . bias = vals [ j + + ] ;
micd_configs [ i ] . gpio = vals [ j + + ] ;
}
arizona - > pdata . micd_configs = micd_configs ;
arizona - > pdata . num_micd_configs = nconfs ;
out :
kfree ( vals ) ;
return ret ;
}
static int arizona_extcon_device_get_pdata ( struct device * dev ,
struct arizona * arizona )
2015-05-04 07:42:13 +03:00
{
struct arizona_pdata * pdata = & arizona - > pdata ;
unsigned int val = ARIZONA_ACCDET_MODE_HPL ;
2015-12-14 13:37:11 +03:00
int ret ;
2015-05-04 07:42:13 +03:00
2015-06-19 19:23:29 +03:00
device_property_read_u32 ( arizona - > dev , " wlf,hpdet-channel " , & val ) ;
2015-05-04 07:42:13 +03:00
switch ( val ) {
case ARIZONA_ACCDET_MODE_HPL :
case ARIZONA_ACCDET_MODE_HPR :
pdata - > hpdet_channel = val ;
break ;
default :
2021-03-07 18:18:05 +03:00
dev_err ( arizona - > dev , " Wrong wlf,hpdet-channel DT value %d \n " , val ) ;
2015-05-04 07:42:13 +03:00
pdata - > hpdet_channel = ARIZONA_ACCDET_MODE_HPL ;
}
2015-06-19 19:23:30 +03:00
device_property_read_u32 ( arizona - > dev , " wlf,micd-detect-debounce " ,
& pdata - > micd_detect_debounce ) ;
device_property_read_u32 ( arizona - > dev , " wlf,micd-bias-start-time " ,
& pdata - > micd_bias_start_time ) ;
device_property_read_u32 ( arizona - > dev , " wlf,micd-rate " ,
& pdata - > micd_rate ) ;
device_property_read_u32 ( arizona - > dev , " wlf,micd-dbtime " ,
& pdata - > micd_dbtime ) ;
2015-11-23 17:51:30 +03:00
device_property_read_u32 ( arizona - > dev , " wlf,micd-timeout-ms " ,
2015-06-19 19:23:30 +03:00
& pdata - > micd_timeout ) ;
pdata - > micd_force_micbias = device_property_read_bool ( arizona - > dev ,
" wlf,micd-force-micbias " ) ;
2015-11-19 18:45:35 +03:00
pdata - > micd_software_compare = device_property_read_bool ( arizona - > dev ,
" wlf,micd-software-compare " ) ;
2015-11-19 18:45:37 +03:00
pdata - > jd_invert = device_property_read_bool ( arizona - > dev ,
" wlf,jd-invert " ) ;
2015-11-19 18:45:36 +03:00
device_property_read_u32 ( arizona - > dev , " wlf,gpsw " , & pdata - > gpsw ) ;
2015-11-19 18:45:38 +03:00
pdata - > jd_gpio5 = device_property_read_bool ( arizona - > dev ,
2015-11-20 11:53:59 +03:00
" wlf,use-jd2 " ) ;
2015-11-19 18:45:38 +03:00
pdata - > jd_gpio5_nopull = device_property_read_bool ( arizona - > dev ,
2015-11-20 11:53:59 +03:00
" wlf,use-jd2-nopull " ) ;
2015-11-19 18:45:38 +03:00
2015-12-14 13:37:11 +03:00
ret = arizona_extcon_get_micd_configs ( dev , arizona ) ;
if ( ret < 0 )
dev_err ( arizona - > dev , " Failed to read micd configs: %d \n " , ret ) ;
2015-05-04 07:42:13 +03:00
return 0 ;
}
2021-03-07 18:18:03 +03:00
int arizona_jack_codec_dev_probe ( struct arizona_priv * info , struct device * dev )
2012-06-24 15:09:45 +04:00
{
2021-03-07 18:18:03 +03:00
struct arizona * arizona = info - > arizona ;
2013-09-28 18:34:57 +04:00
struct arizona_pdata * pdata = & arizona - > pdata ;
2021-03-07 18:18:03 +03:00
int ret , mode ;
2012-06-24 15:09:45 +04:00
2015-06-19 19:23:29 +03:00
if ( ! dev_get_platdata ( arizona - > dev ) )
2021-03-07 18:18:03 +03:00
arizona_extcon_device_get_pdata ( dev , arizona ) ;
2015-05-04 07:42:13 +03:00
2021-03-07 18:18:03 +03:00
info - > micvdd = devm_regulator_get ( dev , " MICVDD " ) ;
2021-03-07 18:18:05 +03:00
if ( IS_ERR ( info - > micvdd ) )
return dev_err_probe ( arizona - > dev , PTR_ERR ( info - > micvdd ) , " getting MICVDD \n " ) ;
2012-06-24 15:09:45 +04:00
mutex_init ( & info - > lock ) ;
2013-04-01 22:05:27 +04:00
info - > last_jackdet = ~ ( ARIZONA_MICD_CLAMP_STS | ARIZONA_JD1_STS ) ;
2013-02-06 01:00:15 +04:00
INIT_DELAYED_WORK ( & info - > hpdet_work , arizona_hpdet_work ) ;
2013-04-01 22:21:48 +04:00
INIT_DELAYED_WORK ( & info - > micd_detect_work , arizona_micd_detect ) ;
2013-04-01 22:17:34 +04:00
INIT_DELAYED_WORK ( & info - > micd_timeout_work , arizona_micd_timeout_work ) ;
2012-06-24 15:09:45 +04:00
switch ( arizona - > type ) {
case WM5102 :
switch ( arizona - > rev ) {
case 0 :
info - > micd_reva = true ;
break ;
default :
2013-01-11 03:55:36 +04:00
info - > micd_clamp = true ;
2015-04-28 15:34:27 +03:00
info - > hpdet_ip_version = 1 ;
2012-06-24 15:09:45 +04:00
break ;
}
break ;
2013-11-14 20:18:25 +04:00
case WM5110 :
2015-01-17 18:21:26 +03:00
case WM8280 :
2013-11-14 20:18:25 +04:00
switch ( arizona - > rev ) {
case 0 . . . 2 :
break ;
default :
info - > micd_clamp = true ;
2015-04-28 15:34:27 +03:00
info - > hpdet_ip_version = 2 ;
2013-11-14 20:18:25 +04:00
break ;
}
break ;
2015-09-28 14:41:42 +03:00
case WM8998 :
case WM1814 :
info - > micd_clamp = true ;
info - > hpdet_ip_version = 2 ;
break ;
2012-06-24 15:09:45 +04:00
default :
break ;
}
2019-12-09 14:09:09 +03:00
if ( ! pdata - > micd_timeout )
pdata - > micd_timeout = DEFAULT_MICD_TIMEOUT ;
2012-06-24 15:09:45 +04:00
if ( pdata - > num_micd_configs ) {
info - > micd_modes = pdata - > micd_configs ;
info - > micd_num_modes = pdata - > num_micd_configs ;
} else {
info - > micd_modes = micd_default_modes ;
info - > micd_num_modes = ARRAY_SIZE ( micd_default_modes ) ;
}
2015-09-16 12:42:17 +03:00
if ( arizona - > pdata . gpsw > 0 )
regmap_update_bits ( arizona - > regmap , ARIZONA_GP_SWITCH_1 ,
ARIZONA_SW1_MODE_MASK , arizona - > pdata . gpsw ) ;
2016-11-25 16:44:36 +03:00
if ( pdata - > micd_pol_gpio > 0 ) {
2012-06-24 15:09:45 +04:00
if ( info - > micd_modes [ 0 ] . gpio )
mode = GPIOF_OUT_INIT_HIGH ;
else
mode = GPIOF_OUT_INIT_LOW ;
2021-03-07 18:18:03 +03:00
ret = devm_gpio_request_one ( dev , pdata - > micd_pol_gpio ,
2016-11-25 16:44:36 +03:00
mode , " MICD polarity " ) ;
2012-06-24 15:09:45 +04:00
if ( ret ! = 0 ) {
dev_err ( arizona - > dev , " Failed to request GPIO%d: %d \n " ,
2016-11-25 16:44:36 +03:00
pdata - > micd_pol_gpio , ret ) ;
2020-05-23 09:17:26 +03:00
return ret ;
2012-06-24 15:09:45 +04:00
}
2016-11-25 16:44:36 +03:00
info - > micd_pol_gpio = gpio_to_desc ( pdata - > micd_pol_gpio ) ;
2015-06-19 19:23:31 +03:00
} else {
if ( info - > micd_modes [ 0 ] . gpio )
mode = GPIOD_OUT_HIGH ;
else
mode = GPIOD_OUT_LOW ;
/* We can't use devm here because we need to do the get
* against the MFD device , as that is where the of_node
* will reside , but if we devm against that the GPIO
* will not be freed if the extcon driver is unloaded .
*/
info - > micd_pol_gpio = gpiod_get_optional ( arizona - > dev ,
" wlf,micd-pol " ,
2021-03-07 18:17:58 +03:00
mode ) ;
2015-06-19 19:23:31 +03:00
if ( IS_ERR ( info - > micd_pol_gpio ) ) {
ret = PTR_ERR ( info - > micd_pol_gpio ) ;
2021-03-07 18:18:05 +03:00
dev_err_probe ( arizona - > dev , ret , " getting microphone polarity GPIO \n " ) ;
2020-05-23 09:17:26 +03:00
return ret ;
2015-06-19 19:23:31 +03:00
}
2012-06-24 15:09:45 +04:00
}
2013-01-11 03:55:54 +04:00
if ( arizona - > pdata . hpdet_id_gpio > 0 ) {
2021-03-07 18:18:03 +03:00
ret = devm_gpio_request_one ( dev , arizona - > pdata . hpdet_id_gpio ,
2013-01-11 03:55:54 +04:00
GPIOF_OUT_INIT_LOW ,
" HPDET " ) ;
if ( ret ! = 0 ) {
dev_err ( arizona - > dev , " Failed to request GPIO%d: %d \n " ,
arizona - > pdata . hpdet_id_gpio , ret ) ;
2021-03-07 18:18:03 +03:00
gpiod_put ( info - > micd_pol_gpio ) ;
return ret ;
2013-01-11 03:55:54 +04:00
}
}
2021-03-07 18:18:03 +03:00
return 0 ;
}
EXPORT_SYMBOL_GPL ( arizona_jack_codec_dev_probe ) ;
int arizona_jack_codec_dev_remove ( struct arizona_priv * info )
{
gpiod_put ( info - > micd_pol_gpio ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( arizona_jack_codec_dev_remove ) ;
static int arizona_jack_enable_jack_detect ( struct arizona_priv * info ,
struct snd_soc_jack * jack )
{
struct arizona * arizona = info - > arizona ;
struct arizona_pdata * pdata = & arizona - > pdata ;
unsigned int val ;
unsigned int clamp_mode ;
int jack_irq_fall , jack_irq_rise ;
int ret , i , j ;
2013-01-11 03:55:24 +04:00
if ( arizona - > pdata . micd_bias_start_time )
regmap_update_bits ( arizona - > regmap , ARIZONA_MIC_DETECT_1 ,
ARIZONA_MICD_BIAS_STARTTIME_MASK ,
arizona - > pdata . micd_bias_start_time
< < ARIZONA_MICD_BIAS_STARTTIME_SHIFT ) ;
2013-01-21 12:36:33 +04:00
if ( arizona - > pdata . micd_rate )
regmap_update_bits ( arizona - > regmap , ARIZONA_MIC_DETECT_1 ,
ARIZONA_MICD_RATE_MASK ,
arizona - > pdata . micd_rate
< < ARIZONA_MICD_RATE_SHIFT ) ;
2015-06-30 15:32:39 +03:00
switch ( arizona - > pdata . micd_dbtime ) {
case MICD_DBTIME_FOUR_READINGS :
2013-01-21 12:36:33 +04:00
regmap_update_bits ( arizona - > regmap , ARIZONA_MIC_DETECT_1 ,
ARIZONA_MICD_DBTIME_MASK ,
2015-06-30 15:32:39 +03:00
ARIZONA_MICD_DBTIME ) ;
break ;
case MICD_DBTIME_TWO_READINGS :
regmap_update_bits ( arizona - > regmap , ARIZONA_MIC_DETECT_1 ,
ARIZONA_MICD_DBTIME_MASK , 0 ) ;
break ;
default :
break ;
}
2013-01-21 12:36:33 +04:00
2015-09-16 12:42:16 +03:00
BUILD_BUG_ON ( ARRAY_SIZE ( arizona_micd_levels ) <
ARIZONA_NUM_MICD_BUTTON_LEVELS ) ;
2013-04-02 01:03:06 +04:00
if ( arizona - > pdata . num_micd_ranges ) {
info - > micd_ranges = pdata - > micd_ranges ;
info - > num_micd_ranges = pdata - > num_micd_ranges ;
} else {
info - > micd_ranges = micd_default_ranges ;
info - > num_micd_ranges = ARRAY_SIZE ( micd_default_ranges ) ;
}
2021-03-07 18:18:04 +03:00
if ( arizona - > pdata . num_micd_ranges > ARIZONA_MAX_MICD_BUTTONS ) {
dev_err ( arizona - > dev , " Too many MICD ranges: %d > %d \n " ,
arizona - > pdata . num_micd_ranges , ARIZONA_MAX_MICD_BUTTONS ) ;
2021-03-07 18:18:03 +03:00
return - EINVAL ;
2013-04-02 01:03:06 +04:00
}
if ( info - > num_micd_ranges > 1 ) {
for ( i = 1 ; i < info - > num_micd_ranges ; i + + ) {
if ( info - > micd_ranges [ i - 1 ] . max >
info - > micd_ranges [ i ] . max ) {
2021-03-07 18:18:03 +03:00
dev_err ( arizona - > dev , " MICD ranges must be sorted \n " ) ;
return - EINVAL ;
2013-04-02 01:03:06 +04:00
}
}
}
/* Disable all buttons by default */
regmap_update_bits ( arizona - > regmap , ARIZONA_MIC_DETECT_2 ,
ARIZONA_MICD_LVL_SEL_MASK , 0x81 ) ;
/* Set up all the buttons the user specified */
for ( i = 0 ; i < info - > num_micd_ranges ; i + + ) {
2015-09-16 12:42:16 +03:00
for ( j = 0 ; j < ARIZONA_NUM_MICD_BUTTON_LEVELS ; j + + )
2013-04-02 01:03:06 +04:00
if ( arizona_micd_levels [ j ] > = info - > micd_ranges [ i ] . max )
break ;
2015-09-16 12:42:16 +03:00
if ( j = = ARIZONA_NUM_MICD_BUTTON_LEVELS ) {
2013-04-02 01:03:06 +04:00
dev_err ( arizona - > dev , " Unsupported MICD level %d \n " ,
info - > micd_ranges [ i ] . max ) ;
2021-03-07 18:18:03 +03:00
return - EINVAL ;
2013-04-02 01:03:06 +04:00
}
dev_dbg ( arizona - > dev , " %d ohms for MICD threshold %d \n " ,
arizona_micd_levels [ j ] , i ) ;
arizona_micd_set_level ( arizona , i , j ) ;
2021-03-07 18:18:04 +03:00
/* SND_JACK_BTN_# masks start with the most significant bit */
info - > micd_button_mask | = SND_JACK_BTN_0 > > i ;
snd_jack_set_key ( jack - > jack , SND_JACK_BTN_0 > > i ,
info - > micd_ranges [ i ] . key ) ;
2013-04-02 01:03:06 +04:00
/* Enable reporting of that range */
regmap_update_bits ( arizona - > regmap , ARIZONA_MIC_DETECT_2 ,
1 < < i , 1 < < i ) ;
}
/* Set all the remaining keys to a maximum */
for ( ; i < ARIZONA_MAX_MICD_RANGE ; i + + )
arizona_micd_set_level ( arizona , i , 0x3f ) ;
2013-01-11 03:55:36 +04:00
/*
2013-01-11 03:55:39 +04:00
* If we have a clamp use it , activating in conjunction with
* GPIO5 if that is connected for jack detect operation .
2013-01-11 03:55:36 +04:00
*/
if ( info - > micd_clamp ) {
2013-01-11 03:55:39 +04:00
if ( arizona - > pdata . jd_gpio5 ) {
2013-04-01 22:03:52 +04:00
/* Put the GPIO into input mode with optional pull */
val = 0xc101 ;
if ( arizona - > pdata . jd_gpio5_nopull )
val & = ~ ARIZONA_GPN_PU ;
2013-01-11 03:55:39 +04:00
regmap_write ( arizona - > regmap , ARIZONA_GPIO5_CTRL ,
2013-04-01 22:03:52 +04:00
val ) ;
2013-01-11 03:55:39 +04:00
2014-05-23 15:54:57 +04:00
if ( arizona - > pdata . jd_invert )
clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH_GP5H ;
else
clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL_GP5H ;
2013-01-11 03:55:39 +04:00
} else {
2014-05-23 15:54:57 +04:00
if ( arizona - > pdata . jd_invert )
clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDH ;
else
clamp_mode = ARIZONA_MICD_CLAMP_MODE_JDL ;
2013-01-11 03:55:39 +04:00
}
2014-05-23 15:54:57 +04:00
regmap_update_bits ( arizona - > regmap ,
ARIZONA_MICD_CLAMP_CONTROL ,
ARIZONA_MICD_CLAMP_MODE_MASK , clamp_mode ) ;
2013-01-11 03:55:36 +04:00
regmap_update_bits ( arizona - > regmap ,
ARIZONA_JACK_DETECT_DEBOUNCE ,
ARIZONA_MICD_CLAMP_DB ,
ARIZONA_MICD_CLAMP_DB ) ;
}
2012-06-24 15:09:45 +04:00
arizona_extcon_set_mode ( info , 0 ) ;
2021-03-07 18:18:04 +03:00
info - > jack = jack ;
2021-03-07 18:18:02 +03:00
pm_runtime_get_sync ( arizona - > dev ) ;
2012-06-24 15:09:45 +04:00
2015-09-16 12:42:20 +03:00
if ( info - > micd_clamp ) {
2013-01-11 03:55:39 +04:00
jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE ;
jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL ;
} else {
jack_irq_rise = ARIZONA_IRQ_JD_RISE ;
jack_irq_fall = ARIZONA_IRQ_JD_FALL ;
}
ret = arizona_request_irq ( arizona , jack_irq_rise ,
2012-06-24 15:09:45 +04:00
" JACKDET rise " , arizona_jackdet , info ) ;
if ( ret ! = 0 ) {
2021-03-07 18:18:03 +03:00
dev_err ( arizona - > dev , " Failed to get JACKDET rise IRQ: %d \n " , ret ) ;
2020-05-23 09:17:26 +03:00
goto err_pm ;
2012-06-24 15:09:45 +04:00
}
2013-01-11 03:55:39 +04:00
ret = arizona_set_irq_wake ( arizona , jack_irq_rise , 1 ) ;
2012-06-24 15:09:45 +04:00
if ( ret ! = 0 ) {
2021-03-07 18:18:03 +03:00
dev_err ( arizona - > dev , " Failed to set JD rise IRQ wake: %d \n " , ret ) ;
2012-06-24 15:09:45 +04:00
goto err_rise ;
}
2013-01-11 03:55:39 +04:00
ret = arizona_request_irq ( arizona , jack_irq_fall ,
2012-06-24 15:09:45 +04:00
" JACKDET fall " , arizona_jackdet , info ) ;
if ( ret ! = 0 ) {
2021-03-07 18:18:03 +03:00
dev_err ( arizona - > dev , " Failed to get JD fall IRQ: %d \n " , ret ) ;
2012-06-24 15:09:45 +04:00
goto err_rise_wake ;
}
2013-01-11 03:55:39 +04:00
ret = arizona_set_irq_wake ( arizona , jack_irq_fall , 1 ) ;
2012-06-24 15:09:45 +04:00
if ( ret ! = 0 ) {
2021-03-07 18:18:03 +03:00
dev_err ( arizona - > dev , " Failed to set JD fall IRQ wake: %d \n " , ret ) ;
2012-06-24 15:09:45 +04:00
goto err_fall ;
}
ret = arizona_request_irq ( arizona , ARIZONA_IRQ_MICDET ,
" MICDET " , arizona_micdet , info ) ;
if ( ret ! = 0 ) {
2021-03-07 18:18:03 +03:00
dev_err ( arizona - > dev , " Failed to get MICDET IRQ: %d \n " , ret ) ;
2012-06-24 15:09:45 +04:00
goto err_fall_wake ;
}
2013-01-11 03:55:43 +04:00
ret = arizona_request_irq ( arizona , ARIZONA_IRQ_HPDET ,
" HPDET " , arizona_hpdet_irq , info ) ;
if ( ret ! = 0 ) {
2021-03-07 18:18:03 +03:00
dev_err ( arizona - > dev , " Failed to get HPDET IRQ: %d \n " , ret ) ;
2013-01-11 03:55:43 +04:00
goto err_micdet ;
}
2012-06-24 15:09:45 +04:00
arizona_clk32k_enable ( arizona ) ;
regmap_update_bits ( arizona - > regmap , ARIZONA_JACK_DETECT_DEBOUNCE ,
ARIZONA_JD1_DB , ARIZONA_JD1_DB ) ;
regmap_update_bits ( arizona - > regmap , ARIZONA_JACK_DETECT_ANALOGUE ,
ARIZONA_JD1_ENA , ARIZONA_JD1_ENA ) ;
2012-09-07 13:01:15 +04:00
ret = regulator_allow_bypass ( info - > micvdd , true ) ;
if ( ret ! = 0 )
2021-03-07 18:18:03 +03:00
dev_warn ( arizona - > dev , " Failed to set MICVDD to bypass: %d \n " , ret ) ;
2012-09-07 13:01:15 +04:00
2021-03-07 18:18:02 +03:00
pm_runtime_put ( arizona - > dev ) ;
2020-05-23 09:17:26 +03:00
2012-06-24 15:09:45 +04:00
return 0 ;
2012-08-27 00:58:20 +04:00
err_micdet :
arizona_free_irq ( arizona , ARIZONA_IRQ_MICDET , info ) ;
2012-06-24 15:09:45 +04:00
err_fall_wake :
2013-01-11 03:55:39 +04:00
arizona_set_irq_wake ( arizona , jack_irq_fall , 0 ) ;
2012-06-24 15:09:45 +04:00
err_fall :
2013-01-11 03:55:39 +04:00
arizona_free_irq ( arizona , jack_irq_fall , info ) ;
2012-06-24 15:09:45 +04:00
err_rise_wake :
2013-01-11 03:55:39 +04:00
arizona_set_irq_wake ( arizona , jack_irq_rise , 0 ) ;
2012-06-24 15:09:45 +04:00
err_rise :
2013-01-11 03:55:39 +04:00
arizona_free_irq ( arizona , jack_irq_rise , info ) ;
2020-05-23 09:17:26 +03:00
err_pm :
2021-03-07 18:18:02 +03:00
pm_runtime_put ( arizona - > dev ) ;
2021-03-07 18:18:04 +03:00
info - > jack = NULL ;
2012-06-24 15:09:45 +04:00
return ret ;
}
2021-03-07 18:18:03 +03:00
static int arizona_jack_disable_jack_detect ( struct arizona_priv * info )
2012-06-24 15:09:45 +04:00
{
struct arizona * arizona = info - > arizona ;
2013-01-11 03:55:39 +04:00
int jack_irq_rise , jack_irq_fall ;
2019-04-04 19:33:56 +03:00
bool change ;
2019-05-29 12:46:05 +03:00
int ret ;
2019-04-04 19:33:56 +03:00
2021-03-07 18:18:04 +03:00
if ( ! info - > jack )
return 0 ;
2015-09-16 12:42:20 +03:00
if ( info - > micd_clamp ) {
2013-01-11 03:55:39 +04:00
jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE ;
jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL ;
} else {
jack_irq_rise = ARIZONA_IRQ_JD_RISE ;
jack_irq_fall = ARIZONA_IRQ_JD_FALL ;
}
arizona_set_irq_wake ( arizona , jack_irq_rise , 0 ) ;
arizona_set_irq_wake ( arizona , jack_irq_fall , 0 ) ;
arizona_free_irq ( arizona , ARIZONA_IRQ_HPDET , info ) ;
2012-06-24 15:09:45 +04:00
arizona_free_irq ( arizona , ARIZONA_IRQ_MICDET , info ) ;
2013-01-11 03:55:39 +04:00
arizona_free_irq ( arizona , jack_irq_rise , info ) ;
arizona_free_irq ( arizona , jack_irq_fall , info ) ;
2013-02-06 01:00:15 +04:00
cancel_delayed_work_sync ( & info - > hpdet_work ) ;
2021-03-07 18:17:57 +03:00
cancel_delayed_work_sync ( & info - > micd_detect_work ) ;
cancel_delayed_work_sync ( & info - > micd_timeout_work ) ;
ret = regmap_update_bits_check ( arizona - > regmap , ARIZONA_MIC_DETECT_1 ,
ARIZONA_MICD_ENA , 0 ,
& change ) ;
if ( ret < 0 ) {
2021-03-07 18:18:03 +03:00
dev_err ( arizona - > dev , " Failed to disable micd on remove: %d \n " , ret ) ;
2021-03-07 18:17:57 +03:00
} else if ( change ) {
regulator_disable ( info - > micvdd ) ;
2021-03-07 18:18:02 +03:00
pm_runtime_put ( arizona - > dev ) ;
2021-03-07 18:17:57 +03:00
}
regmap_update_bits ( arizona - > regmap ,
ARIZONA_MICD_CLAMP_CONTROL ,
ARIZONA_MICD_CLAMP_MODE_MASK , 0 ) ;
2012-06-24 15:09:45 +04:00
regmap_update_bits ( arizona - > regmap , ARIZONA_JACK_DETECT_ANALOGUE ,
ARIZONA_JD1_ENA , 0 ) ;
arizona_clk32k_disable ( arizona ) ;
2021-03-07 18:18:04 +03:00
info - > jack = NULL ;
2012-06-24 15:09:45 +04:00
return 0 ;
}
2021-03-07 18:18:03 +03:00
int arizona_jack_set_jack ( struct snd_soc_component * component ,
struct snd_soc_jack * jack , void * data )
{
struct arizona_priv * info = snd_soc_component_get_drvdata ( component ) ;
2012-06-24 15:09:45 +04:00
2021-03-07 18:18:03 +03:00
if ( jack )
return arizona_jack_enable_jack_detect ( info , jack ) ;
else
return arizona_jack_disable_jack_detect ( info ) ;
}
EXPORT_SYMBOL_GPL ( arizona_jack_set_jack ) ;