2014-01-08 11:44:21 +01:00
/* Helper functions for Thinkpad LED control;
* to be included from codec driver
*/
# if IS_ENABLED(CONFIG_THINKPAD_ACPI)
# include <linux/acpi.h>
# include <linux/thinkpad_acpi.h>
static int ( * led_set_func ) ( int , bool ) ;
2014-01-14 14:56:55 +01:00
static void ( * old_vmaster_hook ) ( void * , int ) ;
2014-01-08 11:44:21 +01:00
static bool is_thinkpad ( struct hda_codec * codec )
{
2016-01-14 22:05:03 +01:00
return ( codec - > core . subsystem_id > > 16 = = 0x17aa ) & &
2016-03-24 13:15:20 +01:00
( acpi_dev_found ( " LEN0068 " ) | | acpi_dev_found ( " IBM0068 " ) ) ;
2014-01-08 11:44:21 +01:00
}
static void update_tpacpi_mute_led ( void * private_data , int enabled )
{
2014-01-14 14:56:55 +01:00
if ( old_vmaster_hook )
old_vmaster_hook ( private_data , enabled ) ;
2014-01-08 11:44:21 +01:00
if ( led_set_func )
led_set_func ( TPACPI_LED_MUTE , ! enabled ) ;
}
static void update_tpacpi_micmute_led ( struct hda_codec * codec ,
2014-01-30 17:59:02 +01:00
struct snd_kcontrol * kcontrol ,
2014-01-08 11:44:21 +01:00
struct snd_ctl_elem_value * ucontrol )
{
if ( ! ucontrol | | ! led_set_func )
return ;
if ( strcmp ( " Capture Switch " , ucontrol - > id . name ) = = 0 & & ucontrol - > id . index = = 0 ) {
/* TODO: How do I verify if it's a mono or stereo here? */
bool val = ucontrol - > value . integer . value [ 0 ] | | ucontrol - > value . integer . value [ 1 ] ;
led_set_func ( TPACPI_LED_MICMUTE , ! val ) ;
}
}
static void hda_fixup_thinkpad_acpi ( struct hda_codec * codec ,
const struct hda_fixup * fix , int action )
{
struct hda_gen_spec * spec = codec - > spec ;
bool removefunc = false ;
if ( action = = HDA_FIXUP_ACT_PROBE ) {
if ( ! is_thinkpad ( codec ) )
return ;
if ( ! led_set_func )
led_set_func = symbol_request ( tpacpi_led_set ) ;
if ( ! led_set_func ) {
2014-02-25 12:21:03 +01:00
codec_warn ( codec ,
" Failed to find thinkpad-acpi symbol tpacpi_led_set \n " ) ;
2014-01-08 11:44:21 +01:00
return ;
}
removefunc = true ;
if ( led_set_func ( TPACPI_LED_MUTE , false ) > = 0 ) {
2014-01-14 14:56:55 +01:00
old_vmaster_hook = spec - > vmaster_mute . hook ;
2014-01-08 11:44:21 +01:00
spec - > vmaster_mute . hook = update_tpacpi_mute_led ;
removefunc = false ;
}
if ( led_set_func ( TPACPI_LED_MICMUTE , false ) > = 0 ) {
2016-10-11 10:48:58 +08:00
if ( spec - > num_adc_nids > 1 & & ! spec - > dyn_adc_switch )
2014-02-25 12:21:03 +01:00
codec_dbg ( codec ,
" Skipping micmute LED control due to several ADCs " ) ;
2014-01-08 11:44:21 +01:00
else {
spec - > cap_sync_hook = update_tpacpi_micmute_led ;
removefunc = false ;
}
}
}
if ( led_set_func & & ( action = = HDA_FIXUP_ACT_FREE | | removefunc ) ) {
symbol_put ( tpacpi_led_set ) ;
led_set_func = NULL ;
2014-01-14 14:56:55 +01:00
old_vmaster_hook = NULL ;
2014-01-08 11:44:21 +01:00
}
}
# else /* CONFIG_THINKPAD_ACPI */
static void hda_fixup_thinkpad_acpi ( struct hda_codec * codec ,
const struct hda_fixup * fix , int action )
{
}
# endif /* CONFIG_THINKPAD_ACPI */