^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * SoC audio for EDB93xx
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2010 Alexander Sverdlin <subaparts@yandex.ru>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * This driver support CS4271 codec being master or slave, working
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * in control port mode, connected either via SPI or I2C.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * The data format accepted is I2S or left-justified.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * DAPM support not implemented.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/gpio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/soc/cirrus/ep93xx.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <sound/core.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <sound/pcm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <sound/soc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <asm/mach-types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) static int edb93xx_hw_params(struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) struct snd_pcm_hw_params *params)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) unsigned int mclk_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) unsigned int rate = params_rate(params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * According to CS4271 datasheet we use MCLK/LRCK=256 for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * rates below 50kHz and 128 for higher sample rates
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) if (rate < 50000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) mclk_rate = rate * 64 * 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) mclk_rate = rate * 64 * 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) SND_SOC_CLOCK_IN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) return snd_soc_dai_set_sysclk(cpu_dai, 0, mclk_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) SND_SOC_CLOCK_OUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) static const struct snd_soc_ops edb93xx_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) .hw_params = edb93xx_hw_params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) SND_SOC_DAILINK_DEFS(hifi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) DAILINK_COMP_ARRAY(COMP_CPU("ep93xx-i2s")),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) DAILINK_COMP_ARRAY(COMP_CODEC("spi0.0", "cs4271-hifi")),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) DAILINK_COMP_ARRAY(COMP_PLATFORM("ep93xx-i2s")));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) static struct snd_soc_dai_link edb93xx_dai = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) .name = "CS4271",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) .stream_name = "CS4271 HiFi",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) SND_SOC_DAIFMT_CBS_CFS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) .ops = &edb93xx_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) SND_SOC_DAILINK_REG(hifi),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) static struct snd_soc_card snd_soc_edb93xx = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) .name = "EDB93XX",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) .dai_link = &edb93xx_dai,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) .num_links = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) static int edb93xx_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) struct snd_soc_card *card = &snd_soc_edb93xx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) ret = ep93xx_i2s_acquire();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) card->dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) ret = snd_soc_register_card(card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) ep93xx_i2s_release();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) static int edb93xx_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) struct snd_soc_card *card = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) snd_soc_unregister_card(card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) ep93xx_i2s_release();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) static struct platform_driver edb93xx_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) .name = "edb93xx-audio",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) .probe = edb93xx_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) .remove = edb93xx_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) module_platform_driver(edb93xx_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) MODULE_DESCRIPTION("ALSA SoC EDB93xx");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) MODULE_ALIAS("platform:edb93xx-audio");