Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Refactor Vangogh acp5x machine driver

Merge series from Lucas Tanure <lucas.tanure@collabora.com>:

Provide small fixes and refactor the code for easier insertion of a new
platform using the same acp5x machine driver.

+167 -176
+167 -176
sound/soc/amd/vangogh/acp5x-mach.c
··· 6 6 * Copyright 2021 Advanced Micro Devices, Inc. 7 7 */ 8 8 9 - #include <sound/soc.h> 10 - #include <sound/soc-dapm.h> 11 - #include <linux/module.h> 12 - #include <linux/io.h> 13 - #include <sound/pcm.h> 14 - #include <sound/pcm_params.h> 15 - 16 - #include <sound/jack.h> 17 - #include <linux/clk.h> 18 - #include <linux/gpio.h> 19 - #include <linux/gpio/consumer.h> 20 - #include <linux/i2c.h> 21 - #include <linux/input.h> 22 9 #include <linux/acpi.h> 23 10 #include <linux/dmi.h> 11 + #include <linux/gpio/consumer.h> 12 + #include <linux/i2c.h> 13 + #include <linux/input-event-codes.h> 14 + #include <linux/module.h> 15 + #include <sound/jack.h> 16 + #include <sound/pcm_params.h> 17 + #include <sound/soc.h> 18 + #include <sound/soc-dapm.h> 24 19 25 20 #include "../../codecs/nau8821.h" 26 - #include "../../codecs/cs35l41.h" 27 - 28 21 #include "acp5x.h" 29 22 30 - #define DRV_NAME "acp5x_mach" 31 - #define DUAL_CHANNEL 2 32 - #define ACP5X_NUVOTON_CODEC_DAI "nau8821-hifi" 33 - #define VG_JUPITER 1 34 - #define ACP5X_NUVOTON_BCLK 3072000 35 - #define ACP5X_NAU8821_FREQ_OUT 12288000 23 + #define DRV_NAME "acp5x_mach" 24 + #define DUAL_CHANNEL 2 25 + #define VG_JUPITER 1 26 + #define ACP5X_NAU8821_BCLK 3072000 27 + #define ACP5X_NAU8821_FREQ_OUT 12288000 28 + #define ACP5X_NAU8821_COMP_NAME "i2c-NVTN2020:00" 29 + #define ACP5X_NAU8821_DAI_NAME "nau8821-hifi" 30 + #define ACP5X_CS35L41_COMP_LNAME "spi-VLV1776:00" 31 + #define ACP5X_CS35L41_COMP_RNAME "spi-VLV1776:01" 32 + #define ACP5X_CS35L41_DAI_NAME "cs35l41-pcm" 36 33 37 34 static unsigned long acp5x_machine_id; 38 35 static struct snd_soc_jack vg_headset; 36 + 37 + SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM("acp5x_i2s_dma.0"))); 38 + SND_SOC_DAILINK_DEF(acp5x_i2s, DAILINK_COMP_ARRAY(COMP_CPU("acp5x_i2s_playcap.0"))); 39 + SND_SOC_DAILINK_DEF(acp5x_bt, DAILINK_COMP_ARRAY(COMP_CPU("acp5x_i2s_playcap.1"))); 40 + SND_SOC_DAILINK_DEF(nau8821, DAILINK_COMP_ARRAY(COMP_CODEC(ACP5X_NAU8821_COMP_NAME, 41 + ACP5X_NAU8821_DAI_NAME))); 39 42 40 43 static struct snd_soc_jack_pin acp5x_nau8821_jack_pins[] = { 41 44 { ··· 51 48 }, 52 49 }; 53 50 51 + static const struct snd_kcontrol_new acp5x_8821_controls[] = { 52 + SOC_DAPM_PIN_SWITCH("Headphone"), 53 + SOC_DAPM_PIN_SWITCH("Headset Mic"), 54 + SOC_DAPM_PIN_SWITCH("Int Mic"), 55 + }; 56 + 57 + static int platform_clock_control(struct snd_soc_dapm_widget *w, 58 + struct snd_kcontrol *k, int event) 59 + { 60 + struct snd_soc_dapm_context *dapm = w->dapm; 61 + struct snd_soc_card *card = dapm->card; 62 + struct snd_soc_dai *dai; 63 + int ret = 0; 64 + 65 + dai = snd_soc_card_get_codec_dai(card, ACP5X_NAU8821_DAI_NAME); 66 + if (!dai) { 67 + dev_err(card->dev, "Codec dai not found\n"); 68 + return -EIO; 69 + } 70 + 71 + if (SND_SOC_DAPM_EVENT_OFF(event)) { 72 + ret = snd_soc_dai_set_sysclk(dai, NAU8821_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN); 73 + if (ret < 0) { 74 + dev_err(card->dev, "set sysclk err = %d\n", ret); 75 + return -EIO; 76 + } 77 + } else { 78 + ret = snd_soc_dai_set_sysclk(dai, NAU8821_CLK_FLL_BLK, 0, SND_SOC_CLOCK_IN); 79 + if (ret < 0) 80 + dev_err(dai->dev, "can't set BLK clock %d\n", ret); 81 + ret = snd_soc_dai_set_pll(dai, 0, 0, ACP5X_NAU8821_BCLK, ACP5X_NAU8821_FREQ_OUT); 82 + if (ret < 0) 83 + dev_err(dai->dev, "can't set FLL: %d\n", ret); 84 + } 85 + 86 + return ret; 87 + } 88 + 54 89 static int acp5x_8821_init(struct snd_soc_pcm_runtime *rtd) 55 90 { 91 + struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; 56 92 int ret; 57 - struct snd_soc_card *card = rtd->card; 58 - struct snd_soc_component *component = 59 - asoc_rtd_to_codec(rtd, 0)->component; 60 93 61 94 /* 62 95 * Headset buttons map to the google Reference headset. 63 96 * These can be configured by userspace. 64 97 */ 65 - ret = snd_soc_card_jack_new_pins(card, "Headset Jack", 98 + ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", 66 99 SND_JACK_HEADSET | SND_JACK_BTN_0, 67 100 &vg_headset, acp5x_nau8821_jack_pins, 68 101 ARRAY_SIZE(acp5x_nau8821_jack_pins)); ··· 109 70 110 71 snd_jack_set_key(vg_headset.jack, SND_JACK_BTN_0, KEY_MEDIA); 111 72 nau8821_enable_jack_detect(component, &vg_headset); 112 - return ret; 113 - } 114 73 115 - static int acp5x_cs35l41_init(struct snd_soc_pcm_runtime *rtd) 116 - { 117 - return 0; 74 + return ret; 118 75 } 119 76 120 77 static const unsigned int rates[] = { ··· 144 109 { 145 110 struct snd_pcm_runtime *runtime = substream->runtime; 146 111 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 147 - struct snd_soc_card *card = rtd->card; 148 - struct acp5x_platform_info *machine = snd_soc_card_get_drvdata(card); 112 + struct acp5x_platform_info *machine = snd_soc_card_get_drvdata(rtd->card); 149 113 150 114 machine->play_i2s_instance = I2S_SP_INSTANCE; 151 115 machine->cap_i2s_instance = I2S_SP_INSTANCE; ··· 157 123 snd_pcm_hw_constraint_list(substream->runtime, 0, 158 124 SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 159 125 &constraints_sample_bits); 126 + 160 127 return 0; 161 128 } 162 129 ··· 166 131 { 167 132 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 168 133 struct snd_soc_card *card = rtd->card; 169 - struct snd_soc_dai *codec_dai = 170 - snd_soc_card_get_codec_dai(card, 171 - ACP5X_NUVOTON_CODEC_DAI); 172 - int ret; 134 + struct snd_soc_dai *dai = snd_soc_card_get_codec_dai(card, ACP5X_NAU8821_DAI_NAME); 135 + int ret, bclk; 173 136 174 - ret = snd_soc_dai_set_sysclk(codec_dai, NAU8821_CLK_FLL_BLK, 0, 175 - SND_SOC_CLOCK_IN); 137 + ret = snd_soc_dai_set_sysclk(dai, NAU8821_CLK_FLL_BLK, 0, SND_SOC_CLOCK_IN); 176 138 if (ret < 0) 177 139 dev_err(card->dev, "can't set FS clock %d\n", ret); 178 - ret = snd_soc_dai_set_pll(codec_dai, 0, 0, snd_soc_params_to_bclk(params), 179 - params_rate(params) * 256); 140 + 141 + bclk = snd_soc_params_to_bclk(params); 142 + if (bclk < 0) { 143 + dev_err(dai->dev, "Fail to get BCLK rate: %d\n", bclk); 144 + return bclk; 145 + } 146 + 147 + ret = snd_soc_dai_set_pll(dai, 0, 0, bclk, params_rate(params) * 256); 180 148 if (ret < 0) 181 149 dev_err(card->dev, "can't set FLL: %d\n", ret); 182 - 183 - return ret; 184 - } 185 - 186 - static int acp5x_cs35l41_startup(struct snd_pcm_substream *substream) 187 - { 188 - struct snd_pcm_runtime *runtime = substream->runtime; 189 - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 190 - struct snd_soc_card *card = rtd->card; 191 - struct acp5x_platform_info *machine = snd_soc_card_get_drvdata(card); 192 - 193 - machine->play_i2s_instance = I2S_HS_INSTANCE; 194 - 195 - runtime->hw.channels_max = DUAL_CHANNEL; 196 - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 197 - &constraints_channels); 198 - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 199 - &constraints_rates); 200 - return 0; 201 - } 202 - 203 - static int acp5x_cs35l41_hw_params(struct snd_pcm_substream *substream, 204 - struct snd_pcm_hw_params *params) 205 - { 206 - struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 207 - struct snd_soc_card *card = rtd->card; 208 - struct snd_soc_dai *codec_dai; 209 - int ret, i; 210 - unsigned int num_codecs = rtd->dai_link->num_codecs; 211 - unsigned int bclk_val; 212 - 213 - ret = 0; 214 - for (i = 0; i < num_codecs; i++) { 215 - codec_dai = asoc_rtd_to_codec(rtd, i); 216 - if (strcmp(codec_dai->name, "cs35l41-pcm") == 0) { 217 - switch (params_rate(params)) { 218 - case 48000: 219 - bclk_val = 1536000; 220 - break; 221 - default: 222 - dev_err(card->dev, "Invalid Samplerate:0x%x\n", 223 - params_rate(params)); 224 - return -EINVAL; 225 - } 226 - ret = snd_soc_component_set_sysclk(codec_dai->component, 227 - 0, 0, bclk_val, SND_SOC_CLOCK_IN); 228 - if (ret < 0) { 229 - dev_err(card->dev, "failed to set sysclk for CS35l41 dai\n"); 230 - return ret; 231 - } 232 - } 233 - } 234 150 235 151 return ret; 236 152 } ··· 191 205 .hw_params = acp5x_nau8821_hw_params, 192 206 }; 193 207 208 + static int acp5x_cs35l41_startup(struct snd_pcm_substream *substream) 209 + { 210 + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 211 + struct acp5x_platform_info *machine = snd_soc_card_get_drvdata(rtd->card); 212 + struct snd_pcm_runtime *runtime = substream->runtime; 213 + 214 + machine->play_i2s_instance = I2S_HS_INSTANCE; 215 + 216 + runtime->hw.channels_max = DUAL_CHANNEL; 217 + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 218 + &constraints_channels); 219 + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 220 + &constraints_rates); 221 + 222 + return 0; 223 + } 224 + 225 + static int acp5x_cs35l41_hw_params(struct snd_pcm_substream *substream, 226 + struct snd_pcm_hw_params *params) 227 + { 228 + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 229 + unsigned int bclk, rate = params_rate(params); 230 + struct snd_soc_component *comp; 231 + int ret, i; 232 + 233 + switch (rate) { 234 + case 48000: 235 + bclk = 1536000; 236 + break; 237 + default: 238 + bclk = 0; 239 + break; 240 + } 241 + 242 + for_each_rtd_components(rtd, i, comp) { 243 + if (!(strcmp(comp->name, ACP5X_CS35L41_COMP_LNAME)) || 244 + !(strcmp(comp->name, ACP5X_CS35L41_COMP_RNAME))) { 245 + if (!bclk) { 246 + dev_err(comp->dev, "Invalid sample rate: 0x%x\n", rate); 247 + return -EINVAL; 248 + } 249 + 250 + ret = snd_soc_component_set_sysclk(comp, 0, 0, bclk, SND_SOC_CLOCK_IN); 251 + if (ret) { 252 + dev_err(comp->dev, "failed to set SYSCLK: %d\n", ret); 253 + return ret; 254 + } 255 + } 256 + } 257 + 258 + return 0; 259 + 260 + } 261 + 194 262 static const struct snd_soc_ops acp5x_cs35l41_play_ops = { 195 263 .startup = acp5x_cs35l41_startup, 196 264 .hw_params = acp5x_cs35l41_hw_params, 197 265 }; 198 266 199 - static struct snd_soc_codec_conf cs35l41_conf[] = { 267 + static struct snd_soc_codec_conf acp5x_cs35l41_conf[] = { 200 268 { 201 - .dlc = COMP_CODEC_CONF("spi-VLV1776:00"), 269 + .dlc = COMP_CODEC_CONF(ACP5X_CS35L41_COMP_LNAME), 202 270 .name_prefix = "Left", 203 271 }, 204 272 { 205 - .dlc = COMP_CODEC_CONF("spi-VLV1776:01"), 273 + .dlc = COMP_CODEC_CONF(ACP5X_CS35L41_COMP_RNAME), 206 274 .name_prefix = "Right", 207 275 }, 208 276 }; 209 277 210 - SND_SOC_DAILINK_DEF(acp5x_i2s, 211 - DAILINK_COMP_ARRAY(COMP_CPU("acp5x_i2s_playcap.0"))); 278 + SND_SOC_DAILINK_DEF(cs35l41, DAILINK_COMP_ARRAY(COMP_CODEC(ACP5X_CS35L41_COMP_LNAME, 279 + ACP5X_CS35L41_DAI_NAME), 280 + COMP_CODEC(ACP5X_CS35L41_COMP_RNAME, 281 + ACP5X_CS35L41_DAI_NAME))); 212 282 213 - SND_SOC_DAILINK_DEF(acp5x_bt, 214 - DAILINK_COMP_ARRAY(COMP_CPU("acp5x_i2s_playcap.1"))); 215 - 216 - SND_SOC_DAILINK_DEF(nau8821, 217 - DAILINK_COMP_ARRAY(COMP_CODEC("i2c-NVTN2020:00", 218 - "nau8821-hifi"))); 219 - 220 - SND_SOC_DAILINK_DEF(cs35l41, 221 - DAILINK_COMP_ARRAY(COMP_CODEC("spi-VLV1776:00", "cs35l41-pcm"), 222 - COMP_CODEC("spi-VLV1776:01", "cs35l41-pcm"))); 223 - 224 - SND_SOC_DAILINK_DEF(platform, 225 - DAILINK_COMP_ARRAY(COMP_PLATFORM("acp5x_i2s_dma.0"))); 226 - 227 - static struct snd_soc_dai_link acp5x_dai[] = { 283 + static struct snd_soc_dai_link acp5x_8821_35l41_dai[] = { 228 284 { 229 285 .name = "acp5x-8821-play", 230 286 .stream_name = "Playback/Capture", 231 - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 287 + .dai_fmt = SND_SOC_DAIFMT_I2S | 288 + SND_SOC_DAIFMT_NB_NF | 232 289 SND_SOC_DAIFMT_CBC_CFC, 233 290 .dpcm_playback = 1, 234 291 .dpcm_capture = 1, ··· 282 253 { 283 254 .name = "acp5x-CS35L41-Stereo", 284 255 .stream_name = "CS35L41 Stereo Playback", 285 - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 256 + .dai_fmt = SND_SOC_DAIFMT_I2S | 257 + SND_SOC_DAIFMT_NB_NF | 286 258 SND_SOC_DAIFMT_CBC_CFC, 287 259 .dpcm_playback = 1, 288 260 .playback_only = 1, 289 261 .ops = &acp5x_cs35l41_play_ops, 290 - .init = acp5x_cs35l41_init, 291 262 SND_SOC_DAILINK_REG(acp5x_bt, cs35l41, platform), 292 263 }, 293 264 }; 294 265 295 - static int platform_clock_control(struct snd_soc_dapm_widget *w, 296 - struct snd_kcontrol *k, int event) 297 - { 298 - struct snd_soc_dapm_context *dapm = w->dapm; 299 - struct snd_soc_card *card = dapm->card; 300 - struct snd_soc_dai *codec_dai; 301 - int ret = 0; 302 266 303 - codec_dai = snd_soc_card_get_codec_dai(card, ACP5X_NUVOTON_CODEC_DAI); 304 - if (!codec_dai) { 305 - dev_err(card->dev, "Codec dai not found\n"); 306 - return -EIO; 307 - } 308 267 309 - if (SND_SOC_DAPM_EVENT_OFF(event)) { 310 - ret = snd_soc_dai_set_sysclk(codec_dai, NAU8821_CLK_INTERNAL, 311 - 0, SND_SOC_CLOCK_IN); 312 - if (ret < 0) { 313 - dev_err(card->dev, "set sysclk err = %d\n", ret); 314 - return -EIO; 315 - } 316 - } else { 317 - ret = snd_soc_dai_set_sysclk(codec_dai, NAU8821_CLK_FLL_BLK, 0, 318 - SND_SOC_CLOCK_IN); 319 - if (ret < 0) 320 - dev_err(codec_dai->dev, "can't set BLK clock %d\n", ret); 321 - ret = snd_soc_dai_set_pll(codec_dai, 0, 0, ACP5X_NUVOTON_BCLK, 322 - ACP5X_NAU8821_FREQ_OUT); 323 - if (ret < 0) 324 - dev_err(codec_dai->dev, "can't set FLL: %d\n", ret); 325 - } 326 - return ret; 327 - } 328 - 329 - static const struct snd_kcontrol_new acp5x_8821_controls[] = { 330 - SOC_DAPM_PIN_SWITCH("Headphone"), 331 - SOC_DAPM_PIN_SWITCH("Headset Mic"), 332 - SOC_DAPM_PIN_SWITCH("Int Mic"), 333 - }; 334 - 335 - static const struct snd_soc_dapm_widget acp5x_8821_widgets[] = { 268 + static const struct snd_soc_dapm_widget acp5x_8821_35l41_widgets[] = { 336 269 SND_SOC_DAPM_HP("Headphone", NULL), 337 270 SND_SOC_DAPM_MIC("Headset Mic", NULL), 338 271 SND_SOC_DAPM_MIC("Int Mic", NULL), 339 272 SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, 340 - platform_clock_control, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 273 + platform_clock_control, 274 + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 341 275 }; 342 276 343 - static const struct snd_soc_dapm_route acp5x_8821_audio_route[] = { 277 + static const struct snd_soc_dapm_route acp5x_8821_35l41_audio_route[] = { 344 278 /* HP jack connectors - unknown if we have jack detection */ 345 279 { "Headphone", NULL, "HPOL" }, 346 280 { "Headphone", NULL, "HPOR" }, ··· 316 324 { "Int Mic", NULL, "Platform Clock" }, 317 325 }; 318 326 319 - static struct snd_soc_card acp5x_card = { 327 + static struct snd_soc_card acp5x_8821_35l41_card = { 320 328 .name = "acp5x", 321 329 .owner = THIS_MODULE, 322 - .dai_link = acp5x_dai, 323 - .num_links = ARRAY_SIZE(acp5x_dai), 324 - .dapm_widgets = acp5x_8821_widgets, 325 - .num_dapm_widgets = ARRAY_SIZE(acp5x_8821_widgets), 326 - .dapm_routes = acp5x_8821_audio_route, 327 - .num_dapm_routes = ARRAY_SIZE(acp5x_8821_audio_route), 328 - .codec_conf = cs35l41_conf, 329 - .num_configs = ARRAY_SIZE(cs35l41_conf), 330 + .dai_link = acp5x_8821_35l41_dai, 331 + .num_links = ARRAY_SIZE(acp5x_8821_35l41_dai), 332 + .dapm_widgets = acp5x_8821_35l41_widgets, 333 + .num_dapm_widgets = ARRAY_SIZE(acp5x_8821_35l41_widgets), 334 + .dapm_routes = acp5x_8821_35l41_audio_route, 335 + .num_dapm_routes = ARRAY_SIZE(acp5x_8821_35l41_audio_route), 336 + .codec_conf = acp5x_cs35l41_conf, 337 + .num_configs = ARRAY_SIZE(acp5x_cs35l41_conf), 330 338 .controls = acp5x_8821_controls, 331 339 .num_controls = ARRAY_SIZE(acp5x_8821_controls), 332 340 }; ··· 334 342 static int acp5x_vg_quirk_cb(const struct dmi_system_id *id) 335 343 { 336 344 acp5x_machine_id = VG_JUPITER; 345 + 337 346 return 1; 338 347 } 339 348 ··· 351 358 352 359 static int acp5x_probe(struct platform_device *pdev) 353 360 { 354 - int ret; 355 361 struct acp5x_platform_info *machine; 362 + struct device *dev = &pdev->dev; 356 363 struct snd_soc_card *card; 364 + int ret; 357 365 358 - machine = devm_kzalloc(&pdev->dev, sizeof(struct acp5x_platform_info), 359 - GFP_KERNEL); 366 + machine = devm_kzalloc(dev, sizeof(*machine), GFP_KERNEL); 360 367 if (!machine) 361 368 return -ENOMEM; 362 369 363 370 dmi_check_system(acp5x_vg_quirk_table); 364 371 switch (acp5x_machine_id) { 365 372 case VG_JUPITER: 366 - card = &acp5x_card; 367 - acp5x_card.dev = &pdev->dev; 373 + card = &acp5x_8821_35l41_card; 368 374 break; 369 375 default: 370 376 return -ENODEV; 371 377 } 378 + card->dev = dev; 372 379 platform_set_drvdata(pdev, card); 373 380 snd_soc_card_set_drvdata(card, machine); 374 381 375 - ret = devm_snd_soc_register_card(&pdev->dev, card); 376 - if (ret) { 377 - return dev_err_probe(&pdev->dev, ret, 378 - "snd_soc_register_card(%s) failed\n", 379 - acp5x_card.name); 380 - } 382 + ret = devm_snd_soc_register_card(dev, card); 383 + if (ret) 384 + return dev_err_probe(dev, ret, "Register card (%s) failed\n", card->name); 385 + 381 386 return 0; 382 387 } 383 388