12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2dbc6b6adSRichard Purdie /* 3dbc6b6adSRichard Purdie * ac97.c -- ALSA Soc AC97 codec support 4dbc6b6adSRichard Purdie * 5dbc6b6adSRichard Purdie * Copyright 2005 Wolfson Microelectronics PLC. 6d331124dSLiam Girdwood * Author: Liam Girdwood <lrg@slimlogic.co.uk> 7dbc6b6adSRichard Purdie * 8dbc6b6adSRichard Purdie * Generic AC97 support. 9dbc6b6adSRichard Purdie */ 10dbc6b6adSRichard Purdie 11dbc6b6adSRichard Purdie #include <linux/init.h> 125a0e3ad6STejun Heo #include <linux/slab.h> 13dbc6b6adSRichard Purdie #include <linux/kernel.h> 14dbc6b6adSRichard Purdie #include <linux/device.h> 15da155d5bSPaul Gortmaker #include <linux/module.h> 16dbc6b6adSRichard Purdie #include <sound/core.h> 17dbc6b6adSRichard Purdie #include <sound/pcm.h> 18dbc6b6adSRichard Purdie #include <sound/ac97_codec.h> 19dbc6b6adSRichard Purdie #include <sound/initval.h> 20dbc6b6adSRichard Purdie #include <sound/soc.h> 21dbc6b6adSRichard Purdie 22d2a369cbSMark Brown static const struct snd_soc_dapm_widget ac97_widgets[] = { 23d2a369cbSMark Brown SND_SOC_DAPM_INPUT("RX"), 24d2a369cbSMark Brown SND_SOC_DAPM_OUTPUT("TX"), 25d2a369cbSMark Brown }; 26d2a369cbSMark Brown 27d2a369cbSMark Brown static const struct snd_soc_dapm_route ac97_routes[] = { 28d2a369cbSMark Brown { "AC97 Capture", NULL, "RX" }, 29d2a369cbSMark Brown { "TX", NULL, "AC97 Playback" }, 30d2a369cbSMark Brown }; 31d2a369cbSMark Brown 32dee89c4dSMark Brown static int ac97_prepare(struct snd_pcm_substream *substream, 33dee89c4dSMark Brown struct snd_soc_dai *dai) 34dbc6b6adSRichard Purdie { 35c95869e5SKuninori Morimoto struct snd_soc_component *component = dai->component; 36c95869e5SKuninori Morimoto struct snd_ac97 *ac97 = snd_soc_component_get_drvdata(component); 37dbc6b6adSRichard Purdie 38dbc6b6adSRichard Purdie int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 39dbc6b6adSRichard Purdie AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE; 40358a8bb5SLars-Peter Clausen return snd_ac97_set_rate(ac97, reg, substream->runtime->rate); 41dbc6b6adSRichard Purdie } 42dbc6b6adSRichard Purdie 4385e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops ac97_dai_ops = { 446335d055SEric Miao .prepare = ac97_prepare, 456335d055SEric Miao }; 466335d055SEric Miao 47f0fba2adSLiam Girdwood static struct snd_soc_dai_driver ac97_dai = { 48f0fba2adSLiam Girdwood .name = "ac97-hifi", 49dbc6b6adSRichard Purdie .playback = { 50dbc6b6adSRichard Purdie .stream_name = "AC97 Playback", 51dbc6b6adSRichard Purdie .channels_min = 1, 525a8ec343SLiam Girdwood .channels_max = 2, 53df82ca70SMaciej S. Szmigiero .rates = SNDRV_PCM_RATE_KNOT, 5433f503c9SMark Brown .formats = SND_SOC_STD_AC97_FMTS,}, 55dbc6b6adSRichard Purdie .capture = { 56dbc6b6adSRichard Purdie .stream_name = "AC97 Capture", 57dbc6b6adSRichard Purdie .channels_min = 1, 585a8ec343SLiam Girdwood .channels_max = 2, 59df82ca70SMaciej S. Szmigiero .rates = SNDRV_PCM_RATE_KNOT, 6033f503c9SMark Brown .formats = SND_SOC_STD_AC97_FMTS,}, 616335d055SEric Miao .ops = &ac97_dai_ops, 62dbc6b6adSRichard Purdie }; 63dbc6b6adSRichard Purdie 64c95869e5SKuninori Morimoto static int ac97_soc_probe(struct snd_soc_component *component) 65dbc6b6adSRichard Purdie { 66358a8bb5SLars-Peter Clausen struct snd_ac97 *ac97; 67dbc6b6adSRichard Purdie struct snd_ac97_bus *ac97_bus; 68dbc6b6adSRichard Purdie struct snd_ac97_template ac97_template; 69f0fba2adSLiam Girdwood int ret; 70dbc6b6adSRichard Purdie 71dbc6b6adSRichard Purdie /* add codec as bus device for standard ac97 */ 72c95869e5SKuninori Morimoto ret = snd_ac97_bus(component->card->snd_card, 0, soc_ac97_ops, 7300200107SLars-Peter Clausen NULL, &ac97_bus); 74dbc6b6adSRichard Purdie if (ret < 0) 75f0fba2adSLiam Girdwood return ret; 76dbc6b6adSRichard Purdie 77dbc6b6adSRichard Purdie memset(&ac97_template, 0, sizeof(struct snd_ac97_template)); 78358a8bb5SLars-Peter Clausen ret = snd_ac97_mixer(ac97_bus, &ac97_template, &ac97); 79dbc6b6adSRichard Purdie if (ret < 0) 80dbc6b6adSRichard Purdie return ret; 81f0fba2adSLiam Girdwood 82c95869e5SKuninori Morimoto snd_soc_component_set_drvdata(component, ac97); 83358a8bb5SLars-Peter Clausen 84f0fba2adSLiam Girdwood return 0; 85dbc6b6adSRichard Purdie } 86dbc6b6adSRichard Purdie 873f775987SManuel Lauss #ifdef CONFIG_PM 88c95869e5SKuninori Morimoto static int ac97_soc_suspend(struct snd_soc_component *component) 893f775987SManuel Lauss { 90c95869e5SKuninori Morimoto struct snd_ac97 *ac97 = snd_soc_component_get_drvdata(component); 91358a8bb5SLars-Peter Clausen 92358a8bb5SLars-Peter Clausen snd_ac97_suspend(ac97); 933f775987SManuel Lauss 943f775987SManuel Lauss return 0; 953f775987SManuel Lauss } 963f775987SManuel Lauss 97c95869e5SKuninori Morimoto static int ac97_soc_resume(struct snd_soc_component *component) 983f775987SManuel Lauss { 99358a8bb5SLars-Peter Clausen 100c95869e5SKuninori Morimoto struct snd_ac97 *ac97 = snd_soc_component_get_drvdata(component); 101358a8bb5SLars-Peter Clausen 102358a8bb5SLars-Peter Clausen snd_ac97_resume(ac97); 1033f775987SManuel Lauss 1043f775987SManuel Lauss return 0; 1053f775987SManuel Lauss } 1063f775987SManuel Lauss #else 1073f775987SManuel Lauss #define ac97_soc_suspend NULL 1083f775987SManuel Lauss #define ac97_soc_resume NULL 1093f775987SManuel Lauss #endif 1103f775987SManuel Lauss 111c95869e5SKuninori Morimoto static const struct snd_soc_component_driver soc_component_dev_ac97 = { 112dbc6b6adSRichard Purdie .probe = ac97_soc_probe, 1133f775987SManuel Lauss .suspend = ac97_soc_suspend, 1143f775987SManuel Lauss .resume = ac97_soc_resume, 115d2a369cbSMark Brown .dapm_widgets = ac97_widgets, 116d2a369cbSMark Brown .num_dapm_widgets = ARRAY_SIZE(ac97_widgets), 117d2a369cbSMark Brown .dapm_routes = ac97_routes, 118d2a369cbSMark Brown .num_dapm_routes = ARRAY_SIZE(ac97_routes), 119c95869e5SKuninori Morimoto .idle_bias_on = 1, 120c95869e5SKuninori Morimoto .use_pmdown_time = 1, 121c95869e5SKuninori Morimoto .endianness = 1, 122c95869e5SKuninori Morimoto .non_legacy_dai_naming = 1, 123dbc6b6adSRichard Purdie }; 124f0fba2adSLiam Girdwood 1257a79e94eSBill Pemberton static int ac97_probe(struct platform_device *pdev) 126f0fba2adSLiam Girdwood { 127c95869e5SKuninori Morimoto return devm_snd_soc_register_component(&pdev->dev, 128c95869e5SKuninori Morimoto &soc_component_dev_ac97, &ac97_dai, 1); 129f0fba2adSLiam Girdwood } 130f0fba2adSLiam Girdwood 1317a79e94eSBill Pemberton static int ac97_remove(struct platform_device *pdev) 132f0fba2adSLiam Girdwood { 133f0fba2adSLiam Girdwood return 0; 134f0fba2adSLiam Girdwood } 135f0fba2adSLiam Girdwood 136f0fba2adSLiam Girdwood static struct platform_driver ac97_codec_driver = { 137f0fba2adSLiam Girdwood .driver = { 138f0fba2adSLiam Girdwood .name = "ac97-codec", 139f0fba2adSLiam Girdwood }, 140f0fba2adSLiam Girdwood 141f0fba2adSLiam Girdwood .probe = ac97_probe, 1427a79e94eSBill Pemberton .remove = ac97_remove, 143f0fba2adSLiam Girdwood }; 144f0fba2adSLiam Girdwood 1455bbcc3c0SMark Brown module_platform_driver(ac97_codec_driver); 146dbc6b6adSRichard Purdie 147dbc6b6adSRichard Purdie MODULE_DESCRIPTION("Soc Generic AC97 driver"); 148dbc6b6adSRichard Purdie MODULE_AUTHOR("Liam Girdwood"); 149dbc6b6adSRichard Purdie MODULE_LICENSE("GPL"); 1500afe6b90SMika Westerberg MODULE_ALIAS("platform:ac97-codec"); 151