sof_sdw_rt1308.c (3940B)
1// SPDX-License-Identifier: GPL-2.0-only 2// Copyright (c) 2020 Intel Corporation 3 4/* 5 * sof_sdw_rt1308 - Helpers to handle RT1308 from generic machine driver 6 */ 7 8#include <linux/device.h> 9#include <linux/errno.h> 10#include <sound/control.h> 11#include <sound/soc.h> 12#include <sound/soc-acpi.h> 13#include <sound/soc-dapm.h> 14#include "sof_sdw_common.h" 15#include "../../codecs/rt1308.h" 16 17static const struct snd_soc_dapm_widget rt1308_widgets[] = { 18 SND_SOC_DAPM_SPK("Speaker", NULL), 19}; 20 21/* 22 * dapm routes for rt1308 will be registered dynamically according 23 * to the number of rt1308 used. The first two entries will be registered 24 * for one codec case, and the last two entries are also registered 25 * if two 1308s are used. 26 */ 27static const struct snd_soc_dapm_route rt1308_map[] = { 28 { "Speaker", NULL, "rt1308-1 SPOL" }, 29 { "Speaker", NULL, "rt1308-1 SPOR" }, 30 { "Speaker", NULL, "rt1308-2 SPOL" }, 31 { "Speaker", NULL, "rt1308-2 SPOR" }, 32}; 33 34static const struct snd_kcontrol_new rt1308_controls[] = { 35 SOC_DAPM_PIN_SWITCH("Speaker"), 36}; 37 38static int first_spk_init(struct snd_soc_pcm_runtime *rtd) 39{ 40 struct snd_soc_card *card = rtd->card; 41 int ret; 42 43 card->components = devm_kasprintf(card->dev, GFP_KERNEL, 44 "%s spk:rt1308", 45 card->components); 46 if (!card->components) 47 return -ENOMEM; 48 49 ret = snd_soc_add_card_controls(card, rt1308_controls, 50 ARRAY_SIZE(rt1308_controls)); 51 if (ret) { 52 dev_err(card->dev, "rt1308 controls addition failed: %d\n", ret); 53 return ret; 54 } 55 56 ret = snd_soc_dapm_new_controls(&card->dapm, rt1308_widgets, 57 ARRAY_SIZE(rt1308_widgets)); 58 if (ret) { 59 dev_err(card->dev, "rt1308 widgets addition failed: %d\n", ret); 60 return ret; 61 } 62 63 ret = snd_soc_dapm_add_routes(&card->dapm, rt1308_map, 2); 64 if (ret) 65 dev_err(rtd->dev, "failed to add first SPK map: %d\n", ret); 66 67 return ret; 68} 69 70static int second_spk_init(struct snd_soc_pcm_runtime *rtd) 71{ 72 struct snd_soc_card *card = rtd->card; 73 int ret; 74 75 ret = snd_soc_dapm_add_routes(&card->dapm, rt1308_map + 2, 2); 76 if (ret) 77 dev_err(rtd->dev, "failed to add second SPK map: %d\n", ret); 78 79 return ret; 80} 81 82static int all_spk_init(struct snd_soc_pcm_runtime *rtd) 83{ 84 int ret; 85 86 ret = first_spk_init(rtd); 87 if (ret) 88 return ret; 89 90 return second_spk_init(rtd); 91} 92 93static int rt1308_i2s_hw_params(struct snd_pcm_substream *substream, 94 struct snd_pcm_hw_params *params) 95{ 96 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 97 struct snd_soc_card *card = rtd->card; 98 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 99 int clk_id, clk_freq, pll_out; 100 int err; 101 102 clk_id = RT1308_PLL_S_MCLK; 103 clk_freq = 38400000; 104 105 pll_out = params_rate(params) * 512; 106 107 /* Set rt1308 pll */ 108 err = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out); 109 if (err < 0) { 110 dev_err(card->dev, "Failed to set RT1308 PLL: %d\n", err); 111 return err; 112 } 113 114 /* Set rt1308 sysclk */ 115 err = snd_soc_dai_set_sysclk(codec_dai, RT1308_FS_SYS_S_PLL, pll_out, 116 SND_SOC_CLOCK_IN); 117 if (err < 0) { 118 dev_err(card->dev, "Failed to set RT1308 SYSCLK: %d\n", err); 119 return err; 120 } 121 122 return 0; 123} 124 125/* machine stream operations */ 126struct snd_soc_ops sof_sdw_rt1308_i2s_ops = { 127 .hw_params = rt1308_i2s_hw_params, 128}; 129 130int sof_sdw_rt1308_init(struct snd_soc_card *card, 131 const struct snd_soc_acpi_link_adr *link, 132 struct snd_soc_dai_link *dai_links, 133 struct sof_sdw_codec_info *info, 134 bool playback) 135{ 136 /* Count amp number and do init on playback link only. */ 137 if (!playback) 138 return 0; 139 140 info->amp_num++; 141 if (info->amp_num == 1) 142 dai_links->init = first_spk_init; 143 144 if (info->amp_num == 2) { 145 /* 146 * if two 1308s are in one dai link, the init function 147 * in this dai link will be first set for the first speaker, 148 * and it should be reset to initialize all speakers when 149 * the second speaker is found. 150 */ 151 if (dai_links->init) 152 dai_links->init = all_spk_init; 153 else 154 dai_links->init = second_spk_init; 155 } 156 157 return 0; 158}