18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// Copyright (C) 2015 - 2016 Samsung Electronics Co., Ltd. 48c2ecf20Sopenharmony_ci// 58c2ecf20Sopenharmony_ci// Authors: Inha Song <ideal.song@samsung.com> 68c2ecf20Sopenharmony_ci// Sylwester Nawrocki <s.nawrocki@samsung.com> 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/clk.h> 98c2ecf20Sopenharmony_ci#include <linux/gpio.h> 108c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/of.h> 138c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 148c2ecf20Sopenharmony_ci#include <sound/soc.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "i2s.h" 178c2ecf20Sopenharmony_ci#include "../codecs/wm5110.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* 208c2ecf20Sopenharmony_ci * The source clock is XCLKOUT with its mux set to the external fixed rate 218c2ecf20Sopenharmony_ci * oscillator (XXTI). 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_ci#define MCLK_RATE 24000000U 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define TM2_DAI_AIF1 0 268c2ecf20Sopenharmony_ci#define TM2_DAI_AIF2 1 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistruct tm2_machine_priv { 298c2ecf20Sopenharmony_ci struct snd_soc_component *component; 308c2ecf20Sopenharmony_ci unsigned int sysclk_rate; 318c2ecf20Sopenharmony_ci struct gpio_desc *gpio_mic_bias; 328c2ecf20Sopenharmony_ci}; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic int tm2_start_sysclk(struct snd_soc_card *card) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card); 378c2ecf20Sopenharmony_ci struct snd_soc_component *component = priv->component; 388c2ecf20Sopenharmony_ci int ret; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci ret = snd_soc_component_set_pll(component, WM5110_FLL1_REFCLK, 418c2ecf20Sopenharmony_ci ARIZONA_FLL_SRC_MCLK1, 428c2ecf20Sopenharmony_ci MCLK_RATE, 438c2ecf20Sopenharmony_ci priv->sysclk_rate); 448c2ecf20Sopenharmony_ci if (ret < 0) { 458c2ecf20Sopenharmony_ci dev_err(component->dev, "Failed to set FLL1 source: %d\n", ret); 468c2ecf20Sopenharmony_ci return ret; 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci ret = snd_soc_component_set_pll(component, WM5110_FLL1, 508c2ecf20Sopenharmony_ci ARIZONA_FLL_SRC_MCLK1, 518c2ecf20Sopenharmony_ci MCLK_RATE, 528c2ecf20Sopenharmony_ci priv->sysclk_rate); 538c2ecf20Sopenharmony_ci if (ret < 0) { 548c2ecf20Sopenharmony_ci dev_err(component->dev, "Failed to start FLL1: %d\n", ret); 558c2ecf20Sopenharmony_ci return ret; 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci ret = snd_soc_component_set_sysclk(component, ARIZONA_CLK_SYSCLK, 598c2ecf20Sopenharmony_ci ARIZONA_CLK_SRC_FLL1, 608c2ecf20Sopenharmony_ci priv->sysclk_rate, 618c2ecf20Sopenharmony_ci SND_SOC_CLOCK_IN); 628c2ecf20Sopenharmony_ci if (ret < 0) { 638c2ecf20Sopenharmony_ci dev_err(component->dev, "Failed to set SYSCLK source: %d\n", ret); 648c2ecf20Sopenharmony_ci return ret; 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci return 0; 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic int tm2_stop_sysclk(struct snd_soc_card *card) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card); 738c2ecf20Sopenharmony_ci struct snd_soc_component *component = priv->component; 748c2ecf20Sopenharmony_ci int ret; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci ret = snd_soc_component_set_pll(component, WM5110_FLL1, 0, 0, 0); 778c2ecf20Sopenharmony_ci if (ret < 0) { 788c2ecf20Sopenharmony_ci dev_err(component->dev, "Failed to stop FLL1: %d\n", ret); 798c2ecf20Sopenharmony_ci return ret; 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci ret = snd_soc_component_set_sysclk(component, ARIZONA_CLK_SYSCLK, 838c2ecf20Sopenharmony_ci ARIZONA_CLK_SRC_FLL1, 0, 0); 848c2ecf20Sopenharmony_ci if (ret < 0) { 858c2ecf20Sopenharmony_ci dev_err(component->dev, "Failed to stop SYSCLK: %d\n", ret); 868c2ecf20Sopenharmony_ci return ret; 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci return 0; 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic int tm2_aif1_hw_params(struct snd_pcm_substream *substream, 938c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 968c2ecf20Sopenharmony_ci struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; 978c2ecf20Sopenharmony_ci struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(rtd->card); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci switch (params_rate(params)) { 1008c2ecf20Sopenharmony_ci case 4000: 1018c2ecf20Sopenharmony_ci case 8000: 1028c2ecf20Sopenharmony_ci case 12000: 1038c2ecf20Sopenharmony_ci case 16000: 1048c2ecf20Sopenharmony_ci case 24000: 1058c2ecf20Sopenharmony_ci case 32000: 1068c2ecf20Sopenharmony_ci case 48000: 1078c2ecf20Sopenharmony_ci case 96000: 1088c2ecf20Sopenharmony_ci case 192000: 1098c2ecf20Sopenharmony_ci /* Highest possible SYSCLK frequency: 147.456MHz */ 1108c2ecf20Sopenharmony_ci priv->sysclk_rate = 147456000U; 1118c2ecf20Sopenharmony_ci break; 1128c2ecf20Sopenharmony_ci case 11025: 1138c2ecf20Sopenharmony_ci case 22050: 1148c2ecf20Sopenharmony_ci case 44100: 1158c2ecf20Sopenharmony_ci case 88200: 1168c2ecf20Sopenharmony_ci case 176400: 1178c2ecf20Sopenharmony_ci /* Highest possible SYSCLK frequency: 135.4752 MHz */ 1188c2ecf20Sopenharmony_ci priv->sysclk_rate = 135475200U; 1198c2ecf20Sopenharmony_ci break; 1208c2ecf20Sopenharmony_ci default: 1218c2ecf20Sopenharmony_ci dev_err(component->dev, "Not supported sample rate: %d\n", 1228c2ecf20Sopenharmony_ci params_rate(params)); 1238c2ecf20Sopenharmony_ci return -EINVAL; 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci return tm2_start_sysclk(rtd->card); 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic struct snd_soc_ops tm2_aif1_ops = { 1308c2ecf20Sopenharmony_ci .hw_params = tm2_aif1_hw_params, 1318c2ecf20Sopenharmony_ci}; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic int tm2_aif2_hw_params(struct snd_pcm_substream *substream, 1348c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 1378c2ecf20Sopenharmony_ci struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; 1388c2ecf20Sopenharmony_ci unsigned int asyncclk_rate; 1398c2ecf20Sopenharmony_ci int ret; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci switch (params_rate(params)) { 1428c2ecf20Sopenharmony_ci case 8000: 1438c2ecf20Sopenharmony_ci case 12000: 1448c2ecf20Sopenharmony_ci case 16000: 1458c2ecf20Sopenharmony_ci /* Highest possible ASYNCCLK frequency: 49.152MHz */ 1468c2ecf20Sopenharmony_ci asyncclk_rate = 49152000U; 1478c2ecf20Sopenharmony_ci break; 1488c2ecf20Sopenharmony_ci case 11025: 1498c2ecf20Sopenharmony_ci /* Highest possible ASYNCCLK frequency: 45.1584 MHz */ 1508c2ecf20Sopenharmony_ci asyncclk_rate = 45158400U; 1518c2ecf20Sopenharmony_ci break; 1528c2ecf20Sopenharmony_ci default: 1538c2ecf20Sopenharmony_ci dev_err(component->dev, "Not supported sample rate: %d\n", 1548c2ecf20Sopenharmony_ci params_rate(params)); 1558c2ecf20Sopenharmony_ci return -EINVAL; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci ret = snd_soc_component_set_pll(component, WM5110_FLL2_REFCLK, 1598c2ecf20Sopenharmony_ci ARIZONA_FLL_SRC_MCLK1, 1608c2ecf20Sopenharmony_ci MCLK_RATE, 1618c2ecf20Sopenharmony_ci asyncclk_rate); 1628c2ecf20Sopenharmony_ci if (ret < 0) { 1638c2ecf20Sopenharmony_ci dev_err(component->dev, "Failed to set FLL2 source: %d\n", ret); 1648c2ecf20Sopenharmony_ci return ret; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci ret = snd_soc_component_set_pll(component, WM5110_FLL2, 1688c2ecf20Sopenharmony_ci ARIZONA_FLL_SRC_MCLK1, 1698c2ecf20Sopenharmony_ci MCLK_RATE, 1708c2ecf20Sopenharmony_ci asyncclk_rate); 1718c2ecf20Sopenharmony_ci if (ret < 0) { 1728c2ecf20Sopenharmony_ci dev_err(component->dev, "Failed to start FLL2: %d\n", ret); 1738c2ecf20Sopenharmony_ci return ret; 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci ret = snd_soc_component_set_sysclk(component, ARIZONA_CLK_ASYNCCLK, 1778c2ecf20Sopenharmony_ci ARIZONA_CLK_SRC_FLL2, 1788c2ecf20Sopenharmony_ci asyncclk_rate, 1798c2ecf20Sopenharmony_ci SND_SOC_CLOCK_IN); 1808c2ecf20Sopenharmony_ci if (ret < 0) { 1818c2ecf20Sopenharmony_ci dev_err(component->dev, "Failed to set ASYNCCLK source: %d\n", ret); 1828c2ecf20Sopenharmony_ci return ret; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci return 0; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic int tm2_aif2_hw_free(struct snd_pcm_substream *substream) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 1918c2ecf20Sopenharmony_ci struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; 1928c2ecf20Sopenharmony_ci int ret; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci /* disable FLL2 */ 1958c2ecf20Sopenharmony_ci ret = snd_soc_component_set_pll(component, WM5110_FLL2, ARIZONA_FLL_SRC_MCLK1, 1968c2ecf20Sopenharmony_ci 0, 0); 1978c2ecf20Sopenharmony_ci if (ret < 0) 1988c2ecf20Sopenharmony_ci dev_err(component->dev, "Failed to stop FLL2: %d\n", ret); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci return ret; 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic struct snd_soc_ops tm2_aif2_ops = { 2048c2ecf20Sopenharmony_ci .hw_params = tm2_aif2_hw_params, 2058c2ecf20Sopenharmony_ci .hw_free = tm2_aif2_hw_free, 2068c2ecf20Sopenharmony_ci}; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic int tm2_hdmi_hw_params(struct snd_pcm_substream *substream, 2098c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 2128c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 2138c2ecf20Sopenharmony_ci unsigned int bfs; 2148c2ecf20Sopenharmony_ci int bitwidth, ret; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci bitwidth = snd_pcm_format_width(params_format(params)); 2178c2ecf20Sopenharmony_ci if (bitwidth < 0) { 2188c2ecf20Sopenharmony_ci dev_err(rtd->card->dev, "Invalid bit-width: %d\n", bitwidth); 2198c2ecf20Sopenharmony_ci return bitwidth; 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci switch (bitwidth) { 2238c2ecf20Sopenharmony_ci case 48: 2248c2ecf20Sopenharmony_ci bfs = 64; 2258c2ecf20Sopenharmony_ci break; 2268c2ecf20Sopenharmony_ci case 16: 2278c2ecf20Sopenharmony_ci bfs = 32; 2288c2ecf20Sopenharmony_ci break; 2298c2ecf20Sopenharmony_ci default: 2308c2ecf20Sopenharmony_ci dev_err(rtd->card->dev, "Unsupported bit-width: %d\n", bitwidth); 2318c2ecf20Sopenharmony_ci return -EINVAL; 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci switch (params_rate(params)) { 2358c2ecf20Sopenharmony_ci case 48000: 2368c2ecf20Sopenharmony_ci case 96000: 2378c2ecf20Sopenharmony_ci case 192000: 2388c2ecf20Sopenharmony_ci break; 2398c2ecf20Sopenharmony_ci default: 2408c2ecf20Sopenharmony_ci dev_err(rtd->card->dev, "Unsupported sample rate: %d\n", 2418c2ecf20Sopenharmony_ci params_rate(params)); 2428c2ecf20Sopenharmony_ci return -EINVAL; 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_OPCLK, 2468c2ecf20Sopenharmony_ci 0, SAMSUNG_I2S_OPCLK_PCLK); 2478c2ecf20Sopenharmony_ci if (ret < 0) 2488c2ecf20Sopenharmony_ci return ret; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_clkdiv(cpu_dai, SAMSUNG_I2S_DIV_BCLK, bfs); 2518c2ecf20Sopenharmony_ci if (ret < 0) 2528c2ecf20Sopenharmony_ci return ret; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci return 0; 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic struct snd_soc_ops tm2_hdmi_ops = { 2588c2ecf20Sopenharmony_ci .hw_params = tm2_hdmi_hw_params, 2598c2ecf20Sopenharmony_ci}; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic int tm2_mic_bias(struct snd_soc_dapm_widget *w, 2628c2ecf20Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci struct snd_soc_card *card = w->dapm->card; 2658c2ecf20Sopenharmony_ci struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci switch (event) { 2688c2ecf20Sopenharmony_ci case SND_SOC_DAPM_PRE_PMU: 2698c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(priv->gpio_mic_bias, 1); 2708c2ecf20Sopenharmony_ci break; 2718c2ecf20Sopenharmony_ci case SND_SOC_DAPM_POST_PMD: 2728c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(priv->gpio_mic_bias, 0); 2738c2ecf20Sopenharmony_ci break; 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci return 0; 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistatic int tm2_set_bias_level(struct snd_soc_card *card, 2808c2ecf20Sopenharmony_ci struct snd_soc_dapm_context *dapm, 2818c2ecf20Sopenharmony_ci enum snd_soc_bias_level level) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci if (dapm->dev != asoc_rtd_to_codec(rtd, 0)->dev) 2888c2ecf20Sopenharmony_ci return 0; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci switch (level) { 2918c2ecf20Sopenharmony_ci case SND_SOC_BIAS_STANDBY: 2928c2ecf20Sopenharmony_ci if (card->dapm.bias_level == SND_SOC_BIAS_OFF) 2938c2ecf20Sopenharmony_ci tm2_start_sysclk(card); 2948c2ecf20Sopenharmony_ci break; 2958c2ecf20Sopenharmony_ci case SND_SOC_BIAS_OFF: 2968c2ecf20Sopenharmony_ci tm2_stop_sysclk(card); 2978c2ecf20Sopenharmony_ci break; 2988c2ecf20Sopenharmony_ci default: 2998c2ecf20Sopenharmony_ci break; 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci return 0; 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic struct snd_soc_aux_dev tm2_speaker_amp_dev; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic int tm2_late_probe(struct snd_soc_card *card) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card); 3108c2ecf20Sopenharmony_ci unsigned int ch_map[] = { 0, 1 }; 3118c2ecf20Sopenharmony_ci struct snd_soc_dai *amp_pdm_dai; 3128c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd; 3138c2ecf20Sopenharmony_ci struct snd_soc_dai *aif1_dai; 3148c2ecf20Sopenharmony_ci struct snd_soc_dai *aif2_dai; 3158c2ecf20Sopenharmony_ci int ret; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[TM2_DAI_AIF1]); 3188c2ecf20Sopenharmony_ci aif1_dai = asoc_rtd_to_codec(rtd, 0); 3198c2ecf20Sopenharmony_ci priv->component = asoc_rtd_to_codec(rtd, 0)->component; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_sysclk(aif1_dai, ARIZONA_CLK_SYSCLK, 0, 0); 3228c2ecf20Sopenharmony_ci if (ret < 0) { 3238c2ecf20Sopenharmony_ci dev_err(aif1_dai->dev, "Failed to set SYSCLK: %d\n", ret); 3248c2ecf20Sopenharmony_ci return ret; 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[TM2_DAI_AIF2]); 3288c2ecf20Sopenharmony_ci aif2_dai = asoc_rtd_to_codec(rtd, 0); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0); 3318c2ecf20Sopenharmony_ci if (ret < 0) { 3328c2ecf20Sopenharmony_ci dev_err(aif2_dai->dev, "Failed to set ASYNCCLK: %d\n", ret); 3338c2ecf20Sopenharmony_ci return ret; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci amp_pdm_dai = snd_soc_find_dai(&tm2_speaker_amp_dev.dlc); 3378c2ecf20Sopenharmony_ci if (!amp_pdm_dai) 3388c2ecf20Sopenharmony_ci return -ENODEV; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci /* Set the MAX98504 V/I sense PDM Tx DAI channel mapping */ 3418c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_channel_map(amp_pdm_dai, ARRAY_SIZE(ch_map), 3428c2ecf20Sopenharmony_ci ch_map, 0, NULL); 3438c2ecf20Sopenharmony_ci if (ret < 0) 3448c2ecf20Sopenharmony_ci return ret; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_tdm_slot(amp_pdm_dai, 0x3, 0x0, 2, 16); 3478c2ecf20Sopenharmony_ci if (ret < 0) 3488c2ecf20Sopenharmony_ci return ret; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci return 0; 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new tm2_controls[] = { 3548c2ecf20Sopenharmony_ci SOC_DAPM_PIN_SWITCH("HP"), 3558c2ecf20Sopenharmony_ci SOC_DAPM_PIN_SWITCH("SPK"), 3568c2ecf20Sopenharmony_ci SOC_DAPM_PIN_SWITCH("RCV"), 3578c2ecf20Sopenharmony_ci SOC_DAPM_PIN_SWITCH("VPS"), 3588c2ecf20Sopenharmony_ci SOC_DAPM_PIN_SWITCH("HDMI"), 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci SOC_DAPM_PIN_SWITCH("Main Mic"), 3618c2ecf20Sopenharmony_ci SOC_DAPM_PIN_SWITCH("Sub Mic"), 3628c2ecf20Sopenharmony_ci SOC_DAPM_PIN_SWITCH("Third Mic"), 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci SOC_DAPM_PIN_SWITCH("Headset Mic"), 3658c2ecf20Sopenharmony_ci}; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget tm2_dapm_widgets[] = { 3688c2ecf20Sopenharmony_ci SND_SOC_DAPM_HP("HP", NULL), 3698c2ecf20Sopenharmony_ci SND_SOC_DAPM_SPK("SPK", NULL), 3708c2ecf20Sopenharmony_ci SND_SOC_DAPM_SPK("RCV", NULL), 3718c2ecf20Sopenharmony_ci SND_SOC_DAPM_LINE("VPS", NULL), 3728c2ecf20Sopenharmony_ci SND_SOC_DAPM_LINE("HDMI", NULL), 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIC("Main Mic", tm2_mic_bias), 3758c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIC("Sub Mic", NULL), 3768c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIC("Third Mic", NULL), 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIC("Headset Mic", NULL), 3798c2ecf20Sopenharmony_ci}; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver tm2_component = { 3828c2ecf20Sopenharmony_ci .name = "tm2-audio", 3838c2ecf20Sopenharmony_ci}; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver tm2_ext_dai[] = { 3868c2ecf20Sopenharmony_ci { 3878c2ecf20Sopenharmony_ci .name = "Voice call", 3888c2ecf20Sopenharmony_ci .playback = { 3898c2ecf20Sopenharmony_ci .channels_min = 1, 3908c2ecf20Sopenharmony_ci .channels_max = 4, 3918c2ecf20Sopenharmony_ci .rate_min = 8000, 3928c2ecf20Sopenharmony_ci .rate_max = 48000, 3938c2ecf20Sopenharmony_ci .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | 3948c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_48000), 3958c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE, 3968c2ecf20Sopenharmony_ci }, 3978c2ecf20Sopenharmony_ci .capture = { 3988c2ecf20Sopenharmony_ci .channels_min = 1, 3998c2ecf20Sopenharmony_ci .channels_max = 4, 4008c2ecf20Sopenharmony_ci .rate_min = 8000, 4018c2ecf20Sopenharmony_ci .rate_max = 48000, 4028c2ecf20Sopenharmony_ci .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | 4038c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_48000), 4048c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE, 4058c2ecf20Sopenharmony_ci }, 4068c2ecf20Sopenharmony_ci }, 4078c2ecf20Sopenharmony_ci { 4088c2ecf20Sopenharmony_ci .name = "Bluetooth", 4098c2ecf20Sopenharmony_ci .playback = { 4108c2ecf20Sopenharmony_ci .channels_min = 1, 4118c2ecf20Sopenharmony_ci .channels_max = 4, 4128c2ecf20Sopenharmony_ci .rate_min = 8000, 4138c2ecf20Sopenharmony_ci .rate_max = 16000, 4148c2ecf20Sopenharmony_ci .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000), 4158c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE, 4168c2ecf20Sopenharmony_ci }, 4178c2ecf20Sopenharmony_ci .capture = { 4188c2ecf20Sopenharmony_ci .channels_min = 1, 4198c2ecf20Sopenharmony_ci .channels_max = 2, 4208c2ecf20Sopenharmony_ci .rate_min = 8000, 4218c2ecf20Sopenharmony_ci .rate_max = 16000, 4228c2ecf20Sopenharmony_ci .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000), 4238c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE, 4248c2ecf20Sopenharmony_ci }, 4258c2ecf20Sopenharmony_ci }, 4268c2ecf20Sopenharmony_ci}; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEFS(aif1, 4298c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CPU(SAMSUNG_I2S_DAI)), 4308c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm5110-aif1")), 4318c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_EMPTY())); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEFS(voice, 4348c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CPU(SAMSUNG_I2S_DAI)), 4358c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm5110-aif2")), 4368c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_EMPTY())); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEFS(bt, 4398c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CPU(SAMSUNG_I2S_DAI)), 4408c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm5110-aif3")), 4418c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_EMPTY())); 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEFS(hdmi, 4448c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_EMPTY()), 4458c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_EMPTY()), 4468c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_EMPTY())); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistatic struct snd_soc_dai_link tm2_dai_links[] = { 4498c2ecf20Sopenharmony_ci { 4508c2ecf20Sopenharmony_ci .name = "WM5110 AIF1", 4518c2ecf20Sopenharmony_ci .stream_name = "HiFi Primary", 4528c2ecf20Sopenharmony_ci .ops = &tm2_aif1_ops, 4538c2ecf20Sopenharmony_ci .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 4548c2ecf20Sopenharmony_ci SND_SOC_DAIFMT_CBM_CFM, 4558c2ecf20Sopenharmony_ci SND_SOC_DAILINK_REG(aif1), 4568c2ecf20Sopenharmony_ci }, { 4578c2ecf20Sopenharmony_ci .name = "WM5110 Voice", 4588c2ecf20Sopenharmony_ci .stream_name = "Voice call", 4598c2ecf20Sopenharmony_ci .ops = &tm2_aif2_ops, 4608c2ecf20Sopenharmony_ci .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 4618c2ecf20Sopenharmony_ci SND_SOC_DAIFMT_CBM_CFM, 4628c2ecf20Sopenharmony_ci .ignore_suspend = 1, 4638c2ecf20Sopenharmony_ci SND_SOC_DAILINK_REG(voice), 4648c2ecf20Sopenharmony_ci }, { 4658c2ecf20Sopenharmony_ci .name = "WM5110 BT", 4668c2ecf20Sopenharmony_ci .stream_name = "Bluetooth", 4678c2ecf20Sopenharmony_ci .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 4688c2ecf20Sopenharmony_ci SND_SOC_DAIFMT_CBM_CFM, 4698c2ecf20Sopenharmony_ci .ignore_suspend = 1, 4708c2ecf20Sopenharmony_ci SND_SOC_DAILINK_REG(bt), 4718c2ecf20Sopenharmony_ci }, { 4728c2ecf20Sopenharmony_ci .name = "HDMI", 4738c2ecf20Sopenharmony_ci .stream_name = "i2s1", 4748c2ecf20Sopenharmony_ci .ops = &tm2_hdmi_ops, 4758c2ecf20Sopenharmony_ci .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 4768c2ecf20Sopenharmony_ci SND_SOC_DAIFMT_CBS_CFS, 4778c2ecf20Sopenharmony_ci SND_SOC_DAILINK_REG(hdmi), 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci}; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_cistatic struct snd_soc_card tm2_card = { 4828c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci .dai_link = tm2_dai_links, 4858c2ecf20Sopenharmony_ci .controls = tm2_controls, 4868c2ecf20Sopenharmony_ci .num_controls = ARRAY_SIZE(tm2_controls), 4878c2ecf20Sopenharmony_ci .dapm_widgets = tm2_dapm_widgets, 4888c2ecf20Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(tm2_dapm_widgets), 4898c2ecf20Sopenharmony_ci .aux_dev = &tm2_speaker_amp_dev, 4908c2ecf20Sopenharmony_ci .num_aux_devs = 1, 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci .late_probe = tm2_late_probe, 4938c2ecf20Sopenharmony_ci .set_bias_level = tm2_set_bias_level, 4948c2ecf20Sopenharmony_ci}; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_cistatic int tm2_probe(struct platform_device *pdev) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci struct device_node *cpu_dai_node[2] = {}; 4998c2ecf20Sopenharmony_ci struct device_node *codec_dai_node[2] = {}; 5008c2ecf20Sopenharmony_ci const char *cells_name = NULL; 5018c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 5028c2ecf20Sopenharmony_ci struct snd_soc_card *card = &tm2_card; 5038c2ecf20Sopenharmony_ci struct tm2_machine_priv *priv; 5048c2ecf20Sopenharmony_ci struct of_phandle_args args; 5058c2ecf20Sopenharmony_ci struct snd_soc_dai_link *dai_link; 5068c2ecf20Sopenharmony_ci int num_codecs, ret, i; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 5098c2ecf20Sopenharmony_ci if (!priv) 5108c2ecf20Sopenharmony_ci return -ENOMEM; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci snd_soc_card_set_drvdata(card, priv); 5138c2ecf20Sopenharmony_ci card->dev = dev; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci priv->gpio_mic_bias = devm_gpiod_get(dev, "mic-bias", GPIOD_OUT_HIGH); 5168c2ecf20Sopenharmony_ci if (IS_ERR(priv->gpio_mic_bias)) { 5178c2ecf20Sopenharmony_ci dev_err(dev, "Failed to get mic bias gpio\n"); 5188c2ecf20Sopenharmony_ci return PTR_ERR(priv->gpio_mic_bias); 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci ret = snd_soc_of_parse_card_name(card, "model"); 5228c2ecf20Sopenharmony_ci if (ret < 0) { 5238c2ecf20Sopenharmony_ci dev_err(dev, "Card name is not specified\n"); 5248c2ecf20Sopenharmony_ci return ret; 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing"); 5288c2ecf20Sopenharmony_ci if (ret < 0) { 5298c2ecf20Sopenharmony_ci dev_err(dev, "Audio routing is not specified or invalid\n"); 5308c2ecf20Sopenharmony_ci return ret; 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci card->aux_dev[0].dlc.of_node = of_parse_phandle(dev->of_node, 5348c2ecf20Sopenharmony_ci "audio-amplifier", 0); 5358c2ecf20Sopenharmony_ci if (!card->aux_dev[0].dlc.of_node) { 5368c2ecf20Sopenharmony_ci dev_err(dev, "audio-amplifier property invalid or missing\n"); 5378c2ecf20Sopenharmony_ci return -EINVAL; 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci num_codecs = of_count_phandle_with_args(dev->of_node, "audio-codec", 5418c2ecf20Sopenharmony_ci NULL); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci /* Skip the HDMI link if not specified in DT */ 5448c2ecf20Sopenharmony_ci if (num_codecs > 1) { 5458c2ecf20Sopenharmony_ci card->num_links = ARRAY_SIZE(tm2_dai_links); 5468c2ecf20Sopenharmony_ci cells_name = "#sound-dai-cells"; 5478c2ecf20Sopenharmony_ci } else { 5488c2ecf20Sopenharmony_ci card->num_links = ARRAY_SIZE(tm2_dai_links) - 1; 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci for (i = 0; i < num_codecs; i++) { 5528c2ecf20Sopenharmony_ci struct of_phandle_args args; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci ret = of_parse_phandle_with_args(dev->of_node, "i2s-controller", 5558c2ecf20Sopenharmony_ci cells_name, i, &args); 5568c2ecf20Sopenharmony_ci if (ret) { 5578c2ecf20Sopenharmony_ci dev_err(dev, "i2s-controller property parse error: %d\n", i); 5588c2ecf20Sopenharmony_ci ret = -EINVAL; 5598c2ecf20Sopenharmony_ci goto dai_node_put; 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci cpu_dai_node[i] = args.np; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci codec_dai_node[i] = of_parse_phandle(dev->of_node, 5648c2ecf20Sopenharmony_ci "audio-codec", i); 5658c2ecf20Sopenharmony_ci if (!codec_dai_node[i]) { 5668c2ecf20Sopenharmony_ci dev_err(dev, "audio-codec property parse error\n"); 5678c2ecf20Sopenharmony_ci ret = -EINVAL; 5688c2ecf20Sopenharmony_ci goto dai_node_put; 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci } 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci /* Initialize WM5110 - I2S and HDMI - I2S1 DAI links */ 5738c2ecf20Sopenharmony_ci for_each_card_prelinks(card, i, dai_link) { 5748c2ecf20Sopenharmony_ci unsigned int dai_index = 0; /* WM5110 */ 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci dai_link->cpus->name = NULL; 5778c2ecf20Sopenharmony_ci dai_link->platforms->name = NULL; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci if (num_codecs > 1 && i == card->num_links - 1) 5808c2ecf20Sopenharmony_ci dai_index = 1; /* HDMI */ 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci dai_link->codecs->of_node = codec_dai_node[dai_index]; 5838c2ecf20Sopenharmony_ci dai_link->cpus->of_node = cpu_dai_node[dai_index]; 5848c2ecf20Sopenharmony_ci dai_link->platforms->of_node = cpu_dai_node[dai_index]; 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci if (num_codecs > 1) { 5888c2ecf20Sopenharmony_ci /* HDMI DAI link (I2S1) */ 5898c2ecf20Sopenharmony_ci i = card->num_links - 1; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci ret = of_parse_phandle_with_fixed_args(dev->of_node, 5928c2ecf20Sopenharmony_ci "audio-codec", 0, 1, &args); 5938c2ecf20Sopenharmony_ci if (ret) { 5948c2ecf20Sopenharmony_ci dev_err(dev, "audio-codec property parse error\n"); 5958c2ecf20Sopenharmony_ci goto dai_node_put; 5968c2ecf20Sopenharmony_ci } 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci ret = snd_soc_get_dai_name(&args, &card->dai_link[i].codecs->dai_name); 5998c2ecf20Sopenharmony_ci if (ret) { 6008c2ecf20Sopenharmony_ci dev_err(dev, "Unable to get codec_dai_name\n"); 6018c2ecf20Sopenharmony_ci goto dai_node_put; 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci ret = devm_snd_soc_register_component(dev, &tm2_component, 6068c2ecf20Sopenharmony_ci tm2_ext_dai, ARRAY_SIZE(tm2_ext_dai)); 6078c2ecf20Sopenharmony_ci if (ret < 0) { 6088c2ecf20Sopenharmony_ci dev_err(dev, "Failed to register component: %d\n", ret); 6098c2ecf20Sopenharmony_ci goto dai_node_put; 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci ret = devm_snd_soc_register_card(dev, card); 6138c2ecf20Sopenharmony_ci if (ret < 0) { 6148c2ecf20Sopenharmony_ci dev_err_probe(dev, ret, "Failed to register card\n"); 6158c2ecf20Sopenharmony_ci goto dai_node_put; 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_cidai_node_put: 6198c2ecf20Sopenharmony_ci for (i = 0; i < num_codecs; i++) { 6208c2ecf20Sopenharmony_ci of_node_put(codec_dai_node[i]); 6218c2ecf20Sopenharmony_ci of_node_put(cpu_dai_node[i]); 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci of_node_put(card->aux_dev[0].dlc.of_node); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci return ret; 6278c2ecf20Sopenharmony_ci} 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_cistatic int tm2_pm_prepare(struct device *dev) 6308c2ecf20Sopenharmony_ci{ 6318c2ecf20Sopenharmony_ci struct snd_soc_card *card = dev_get_drvdata(dev); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci return tm2_stop_sysclk(card); 6348c2ecf20Sopenharmony_ci} 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_cistatic void tm2_pm_complete(struct device *dev) 6378c2ecf20Sopenharmony_ci{ 6388c2ecf20Sopenharmony_ci struct snd_soc_card *card = dev_get_drvdata(dev); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci tm2_start_sysclk(card); 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_cistatic const struct dev_pm_ops tm2_pm_ops = { 6448c2ecf20Sopenharmony_ci .prepare = tm2_pm_prepare, 6458c2ecf20Sopenharmony_ci .suspend = snd_soc_suspend, 6468c2ecf20Sopenharmony_ci .resume = snd_soc_resume, 6478c2ecf20Sopenharmony_ci .complete = tm2_pm_complete, 6488c2ecf20Sopenharmony_ci .freeze = snd_soc_suspend, 6498c2ecf20Sopenharmony_ci .thaw = snd_soc_resume, 6508c2ecf20Sopenharmony_ci .poweroff = snd_soc_poweroff, 6518c2ecf20Sopenharmony_ci .restore = snd_soc_resume, 6528c2ecf20Sopenharmony_ci}; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_cistatic const struct of_device_id tm2_of_match[] = { 6558c2ecf20Sopenharmony_ci { .compatible = "samsung,tm2-audio" }, 6568c2ecf20Sopenharmony_ci { }, 6578c2ecf20Sopenharmony_ci}; 6588c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, tm2_of_match); 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_cistatic struct platform_driver tm2_driver = { 6618c2ecf20Sopenharmony_ci .driver = { 6628c2ecf20Sopenharmony_ci .name = "tm2-audio", 6638c2ecf20Sopenharmony_ci .pm = &tm2_pm_ops, 6648c2ecf20Sopenharmony_ci .of_match_table = tm2_of_match, 6658c2ecf20Sopenharmony_ci }, 6668c2ecf20Sopenharmony_ci .probe = tm2_probe, 6678c2ecf20Sopenharmony_ci}; 6688c2ecf20Sopenharmony_cimodule_platform_driver(tm2_driver); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ciMODULE_AUTHOR("Inha Song <ideal.song@samsung.com>"); 6718c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ALSA SoC Exynos TM2 Audio Support"); 6728c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 673