2019-05-29 07:18:02 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2014-03-12 23:04:35 +00:00
/*
* Intel Baytrail SST RT5640 machine driver
* Copyright ( c ) 2014 , Intel Corporation .
*/
# include <linux/init.h>
# include <linux/module.h>
# include <linux/platform_device.h>
# include <linux/acpi.h>
# include <linux/device.h>
2014-09-29 16:58:16 +03:00
# include <linux/dmi.h>
2014-03-12 23:04:35 +00:00
# include <linux/slab.h>
# include <sound/pcm.h>
# include <sound/pcm_params.h>
# include <sound/soc.h>
# include <sound/jack.h>
2015-04-02 15:37:02 +08:00
# include "../../codecs/rt5640.h"
2014-03-12 23:04:35 +00:00
2015-04-02 15:37:02 +08:00
# include "../common/sst-dsp.h"
2014-03-12 23:04:35 +00:00
static const struct snd_soc_dapm_widget byt_rt5640_widgets [ ] = {
SND_SOC_DAPM_HP ( " Headphone " , NULL ) ,
SND_SOC_DAPM_MIC ( " Headset Mic " , NULL ) ,
SND_SOC_DAPM_MIC ( " Internal Mic " , NULL ) ,
SND_SOC_DAPM_SPK ( " Speaker " , NULL ) ,
} ;
static const struct snd_soc_dapm_route byt_rt5640_audio_map [ ] = {
2014-06-09 14:39:06 +03:00
{ " Headset Mic " , NULL , " MICBIAS1 " } ,
2014-03-12 23:04:35 +00:00
{ " IN2P " , NULL , " Headset Mic " } ,
{ " Headphone " , NULL , " HPOL " } ,
{ " Headphone " , NULL , " HPOR " } ,
{ " Speaker " , NULL , " SPOLP " } ,
{ " Speaker " , NULL , " SPOLN " } ,
{ " Speaker " , NULL , " SPORP " } ,
{ " Speaker " , NULL , " SPORN " } ,
} ;
2014-09-29 16:58:16 +03:00
static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic1_map [ ] = {
{ " DMIC1 " , NULL , " Internal Mic " } ,
} ;
2014-10-02 13:29:08 +03:00
static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic2_map [ ] = {
{ " DMIC2 " , NULL , " Internal Mic " } ,
} ;
2014-09-29 16:58:16 +03:00
static const struct snd_soc_dapm_route byt_rt5640_intmic_in1_map [ ] = {
{ " Internal Mic " , NULL , " MICBIAS1 " } ,
{ " IN1P " , NULL , " Internal Mic " } ,
} ;
enum {
BYT_RT5640_DMIC1_MAP ,
2014-10-02 13:29:08 +03:00
BYT_RT5640_DMIC2_MAP ,
2014-09-29 16:58:16 +03:00
BYT_RT5640_IN1_MAP ,
} ;
2014-10-01 15:08:15 +03:00
# define BYT_RT5640_MAP(quirk) ((quirk) & 0xff)
# define BYT_RT5640_DMIC_EN BIT(16)
static unsigned long byt_rt5640_quirk = BYT_RT5640_DMIC1_MAP |
BYT_RT5640_DMIC_EN ;
2014-09-29 16:58:16 +03:00
2014-03-12 23:04:35 +00:00
static const struct snd_kcontrol_new byt_rt5640_controls [ ] = {
SOC_DAPM_PIN_SWITCH ( " Headphone " ) ,
SOC_DAPM_PIN_SWITCH ( " Headset Mic " ) ,
SOC_DAPM_PIN_SWITCH ( " Internal Mic " ) ,
SOC_DAPM_PIN_SWITCH ( " Speaker " ) ,
} ;
static int byt_rt5640_hw_params ( struct snd_pcm_substream * substream ,
struct snd_pcm_hw_params * params )
{
2020-07-27 10:08:29 +09:00
struct snd_soc_pcm_runtime * rtd = asoc_substream_to_rtd ( substream ) ;
2020-03-23 14:19:05 +09:00
struct snd_soc_dai * codec_dai = asoc_rtd_to_codec ( rtd , 0 ) ;
2014-03-12 23:04:35 +00:00
int ret ;
ret = snd_soc_dai_set_sysclk ( codec_dai , RT5640_SCLK_S_PLL1 ,
params_rate ( params ) * 256 ,
SND_SOC_CLOCK_IN ) ;
if ( ret < 0 ) {
dev_err ( codec_dai - > dev , " can't set codec clock %d \n " , ret ) ;
return ret ;
}
ret = snd_soc_dai_set_pll ( codec_dai , 0 , RT5640_PLL1_S_BCLK1 ,
params_rate ( params ) * 64 ,
params_rate ( params ) * 256 ) ;
if ( ret < 0 ) {
dev_err ( codec_dai - > dev , " can't set codec pll: %d \n " , ret ) ;
return ret ;
}
return 0 ;
}
2014-09-29 16:58:16 +03:00
static int byt_rt5640_quirk_cb ( const struct dmi_system_id * id )
{
2014-10-01 15:08:15 +03:00
byt_rt5640_quirk = ( unsigned long ) id - > driver_data ;
2014-09-29 16:58:16 +03:00
return 1 ;
}
static const struct dmi_system_id byt_rt5640_quirk_table [ ] = {
{
. callback = byt_rt5640_quirk_cb ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " ASUSTeK COMPUTER INC. " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " T100TA " ) ,
} ,
. driver_data = ( unsigned long * ) BYT_RT5640_IN1_MAP ,
} ,
2014-10-02 13:29:08 +03:00
{
. callback = byt_rt5640_quirk_cb ,
. matches = {
DMI_MATCH ( DMI_SYS_VENDOR , " DellInc. " ) ,
DMI_MATCH ( DMI_PRODUCT_NAME , " Venue 8 Pro 5830 " ) ,
} ,
. driver_data = ( unsigned long * ) ( BYT_RT5640_DMIC2_MAP |
BYT_RT5640_DMIC_EN ) ,
} ,
2014-09-29 16:58:16 +03:00
{ }
} ;
2014-03-12 23:04:35 +00:00
static int byt_rt5640_init ( struct snd_soc_pcm_runtime * runtime )
{
int ret ;
2020-03-23 14:19:05 +09:00
struct snd_soc_component * component = asoc_rtd_to_codec ( runtime , 0 ) - > component ;
2014-03-12 23:04:35 +00:00
struct snd_soc_card * card = runtime - > card ;
2014-09-29 16:58:16 +03:00
const struct snd_soc_dapm_route * custom_map ;
int num_routes ;
2014-03-12 23:04:35 +00:00
card - > dapm . idle_bias_off = true ;
ret = snd_soc_add_card_controls ( card , byt_rt5640_controls ,
ARRAY_SIZE ( byt_rt5640_controls ) ) ;
if ( ret ) {
dev_err ( card - > dev , " unable to add card controls \n " ) ;
return ret ;
}
2014-09-29 16:58:16 +03:00
dmi_check_system ( byt_rt5640_quirk_table ) ;
2014-10-01 15:08:15 +03:00
switch ( BYT_RT5640_MAP ( byt_rt5640_quirk ) ) {
2014-09-29 16:58:16 +03:00
case BYT_RT5640_IN1_MAP :
custom_map = byt_rt5640_intmic_in1_map ;
num_routes = ARRAY_SIZE ( byt_rt5640_intmic_in1_map ) ;
break ;
2014-10-02 13:29:08 +03:00
case BYT_RT5640_DMIC2_MAP :
custom_map = byt_rt5640_intmic_dmic2_map ;
num_routes = ARRAY_SIZE ( byt_rt5640_intmic_dmic2_map ) ;
break ;
2014-09-29 16:58:16 +03:00
default :
custom_map = byt_rt5640_intmic_dmic1_map ;
num_routes = ARRAY_SIZE ( byt_rt5640_intmic_dmic1_map ) ;
2014-10-04 19:09:33 +01:00
}
2014-09-29 16:58:16 +03:00
2015-01-01 11:23:45 +01:00
ret = snd_soc_dapm_add_routes ( & card - > dapm , custom_map , num_routes ) ;
2014-09-29 16:58:16 +03:00
if ( ret )
return ret ;
2014-10-01 15:08:15 +03:00
if ( byt_rt5640_quirk & BYT_RT5640_DMIC_EN ) {
2018-01-29 03:42:46 +00:00
ret = rt5640_dmic_enable ( component , 0 , 0 ) ;
2014-10-01 15:08:15 +03:00
if ( ret )
return ret ;
}
2015-01-01 11:23:44 +01:00
snd_soc_dapm_ignore_suspend ( & card - > dapm , " Headphone " ) ;
snd_soc_dapm_ignore_suspend ( & card - > dapm , " Speaker " ) ;
2014-03-12 23:04:35 +00:00
return ret ;
}
static struct snd_soc_ops byt_rt5640_ops = {
. hw_params = byt_rt5640_hw_params ,
} ;
2019-06-06 13:20:10 +09:00
SND_SOC_DAILINK_DEFS ( audio ,
DAILINK_COMP_ARRAY ( COMP_CPU ( " baytrail-pcm-audio " ) ) ,
DAILINK_COMP_ARRAY ( COMP_CODEC ( " i2c-10EC5640:00 " , " rt5640-aif1 " ) ) ,
DAILINK_COMP_ARRAY ( COMP_PLATFORM ( " baytrail-pcm-audio " ) ) ) ;
2014-03-12 23:04:35 +00:00
static struct snd_soc_dai_link byt_rt5640_dais [ ] = {
{
. name = " Baytrail Audio " ,
. stream_name = " Audio " ,
. dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS ,
. init = byt_rt5640_init ,
. ops = & byt_rt5640_ops ,
2019-06-06 13:20:10 +09:00
SND_SOC_DAILINK_REG ( audio ) ,
2014-03-12 23:04:35 +00:00
} ,
} ;
static struct snd_soc_card byt_rt5640_card = {
. name = " byt-rt5640 " ,
2015-08-21 20:59:21 +08:00
. owner = THIS_MODULE ,
2014-03-12 23:04:35 +00:00
. dai_link = byt_rt5640_dais ,
. num_links = ARRAY_SIZE ( byt_rt5640_dais ) ,
. dapm_widgets = byt_rt5640_widgets ,
. num_dapm_widgets = ARRAY_SIZE ( byt_rt5640_widgets ) ,
. dapm_routes = byt_rt5640_audio_map ,
. num_dapm_routes = ARRAY_SIZE ( byt_rt5640_audio_map ) ,
2014-10-02 13:29:09 +03:00
. fully_routed = true ,
2014-03-12 23:04:35 +00:00
} ;
static int byt_rt5640_probe ( struct platform_device * pdev )
{
struct snd_soc_card * card = & byt_rt5640_card ;
card - > dev = & pdev - > dev ;
2014-05-28 12:35:39 +03:00
return devm_snd_soc_register_card ( & pdev - > dev , card ) ;
2014-03-12 23:04:35 +00:00
}
static struct platform_driver byt_rt5640_audio = {
. probe = byt_rt5640_probe ,
. driver = {
. name = " byt-rt5640 " ,
2014-05-26 16:56:33 +03:00
. pm = & snd_soc_pm_ops ,
2014-03-12 23:04:35 +00:00
} ,
} ;
module_platform_driver ( byt_rt5640_audio )
MODULE_DESCRIPTION ( " ASoC Intel(R) Baytrail Machine driver " ) ;
MODULE_AUTHOR ( " Omair Md Abdullah, Jarkko Nikula " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_ALIAS ( " platform:byt-rt5640 " ) ;