1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 20ed275efSAlexander Shiyan /* 30ed275efSAlexander Shiyan * SoC audio for EDB93xx 40ed275efSAlexander Shiyan * 50ed275efSAlexander Shiyan * Copyright (c) 2010 Alexander Sverdlin <subaparts@yandex.ru> 60ed275efSAlexander Shiyan * 70ed275efSAlexander Shiyan * This driver support CS4271 codec being master or slave, working 80ed275efSAlexander Shiyan * in control port mode, connected either via SPI or I2C. 90ed275efSAlexander Shiyan * The data format accepted is I2S or left-justified. 100ed275efSAlexander Shiyan * DAPM support not implemented. 110ed275efSAlexander Shiyan */ 120ed275efSAlexander Shiyan 130ed275efSAlexander Shiyan #include <linux/platform_device.h> 140ed275efSAlexander Shiyan #include <linux/gpio.h> 150ed275efSAlexander Shiyan #include <linux/module.h> 1667e38f57SArnd Bergmann #include <linux/soc/cirrus/ep93xx.h> 170ed275efSAlexander Shiyan #include <sound/core.h> 180ed275efSAlexander Shiyan #include <sound/pcm.h> 190ed275efSAlexander Shiyan #include <sound/soc.h> 200ed275efSAlexander Shiyan #include <asm/mach-types.h> 210ed275efSAlexander Shiyan 220ed275efSAlexander Shiyan static int edb93xx_hw_params(struct snd_pcm_substream *substream, 230ed275efSAlexander Shiyan struct snd_pcm_hw_params *params) 240ed275efSAlexander Shiyan { 25d42df940SKuninori Morimoto struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 2607c497a6SKuninori Morimoto struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 2707c497a6SKuninori Morimoto struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 280ed275efSAlexander Shiyan int err; 290ed275efSAlexander Shiyan unsigned int mclk_rate; 300ed275efSAlexander Shiyan unsigned int rate = params_rate(params); 310ed275efSAlexander Shiyan 320ed275efSAlexander Shiyan /* 330ed275efSAlexander Shiyan * According to CS4271 datasheet we use MCLK/LRCK=256 for 340ed275efSAlexander Shiyan * rates below 50kHz and 128 for higher sample rates 350ed275efSAlexander Shiyan */ 360ed275efSAlexander Shiyan if (rate < 50000) 370ed275efSAlexander Shiyan mclk_rate = rate * 64 * 4; 380ed275efSAlexander Shiyan else 390ed275efSAlexander Shiyan mclk_rate = rate * 64 * 2; 400ed275efSAlexander Shiyan 410ed275efSAlexander Shiyan err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk_rate, 420ed275efSAlexander Shiyan SND_SOC_CLOCK_IN); 430ed275efSAlexander Shiyan if (err) 440ed275efSAlexander Shiyan return err; 450ed275efSAlexander Shiyan 460ed275efSAlexander Shiyan return snd_soc_dai_set_sysclk(cpu_dai, 0, mclk_rate, 470ed275efSAlexander Shiyan SND_SOC_CLOCK_OUT); 480ed275efSAlexander Shiyan } 490ed275efSAlexander Shiyan 507f8159acSBhumika Goyal static const struct snd_soc_ops edb93xx_ops = { 510ed275efSAlexander Shiyan .hw_params = edb93xx_hw_params, 520ed275efSAlexander Shiyan }; 530ed275efSAlexander Shiyan 545e883ff1SKuninori Morimoto SND_SOC_DAILINK_DEFS(hifi, 555e883ff1SKuninori Morimoto DAILINK_COMP_ARRAY(COMP_CPU("ep93xx-i2s")), 565e883ff1SKuninori Morimoto DAILINK_COMP_ARRAY(COMP_CODEC("spi0.0", "cs4271-hifi")), 575e883ff1SKuninori Morimoto DAILINK_COMP_ARRAY(COMP_PLATFORM("ep93xx-i2s"))); 585e883ff1SKuninori Morimoto 590ed275efSAlexander Shiyan static struct snd_soc_dai_link edb93xx_dai = { 600ed275efSAlexander Shiyan .name = "CS4271", 610ed275efSAlexander Shiyan .stream_name = "CS4271 HiFi", 622d534113SAlexander Sverdlin .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 630ed275efSAlexander Shiyan SND_SOC_DAIFMT_CBS_CFS, 640ed275efSAlexander Shiyan .ops = &edb93xx_ops, 655e883ff1SKuninori Morimoto SND_SOC_DAILINK_REG(hifi), 660ed275efSAlexander Shiyan }; 670ed275efSAlexander Shiyan 680ed275efSAlexander Shiyan static struct snd_soc_card snd_soc_edb93xx = { 690ed275efSAlexander Shiyan .name = "EDB93XX", 700ed275efSAlexander Shiyan .owner = THIS_MODULE, 710ed275efSAlexander Shiyan .dai_link = &edb93xx_dai, 720ed275efSAlexander Shiyan .num_links = 1, 730ed275efSAlexander Shiyan }; 740ed275efSAlexander Shiyan 75145e2879SBill Pemberton static int edb93xx_probe(struct platform_device *pdev) 760ed275efSAlexander Shiyan { 770ed275efSAlexander Shiyan struct snd_soc_card *card = &snd_soc_edb93xx; 780ed275efSAlexander Shiyan int ret; 790ed275efSAlexander Shiyan 800ed275efSAlexander Shiyan ret = ep93xx_i2s_acquire(); 810ed275efSAlexander Shiyan if (ret) 820ed275efSAlexander Shiyan return ret; 830ed275efSAlexander Shiyan 840ed275efSAlexander Shiyan card->dev = &pdev->dev; 850ed275efSAlexander Shiyan 860ed275efSAlexander Shiyan ret = snd_soc_register_card(card); 870ed275efSAlexander Shiyan if (ret) { 880ed275efSAlexander Shiyan dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", 890ed275efSAlexander Shiyan ret); 900ed275efSAlexander Shiyan ep93xx_i2s_release(); 910ed275efSAlexander Shiyan } 920ed275efSAlexander Shiyan 930ed275efSAlexander Shiyan return ret; 940ed275efSAlexander Shiyan } 950ed275efSAlexander Shiyan 96145e2879SBill Pemberton static int edb93xx_remove(struct platform_device *pdev) 970ed275efSAlexander Shiyan { 980ed275efSAlexander Shiyan struct snd_soc_card *card = platform_get_drvdata(pdev); 990ed275efSAlexander Shiyan 1000ed275efSAlexander Shiyan snd_soc_unregister_card(card); 1010ed275efSAlexander Shiyan ep93xx_i2s_release(); 1020ed275efSAlexander Shiyan 1030ed275efSAlexander Shiyan return 0; 1040ed275efSAlexander Shiyan } 1050ed275efSAlexander Shiyan 1060ed275efSAlexander Shiyan static struct platform_driver edb93xx_driver = { 1070ed275efSAlexander Shiyan .driver = { 1080ed275efSAlexander Shiyan .name = "edb93xx-audio", 1090ed275efSAlexander Shiyan }, 1100ed275efSAlexander Shiyan .probe = edb93xx_probe, 111145e2879SBill Pemberton .remove = edb93xx_remove, 1120ed275efSAlexander Shiyan }; 1130ed275efSAlexander Shiyan 1140ed275efSAlexander Shiyan module_platform_driver(edb93xx_driver); 1150ed275efSAlexander Shiyan 1160ed275efSAlexander Shiyan MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>"); 1170ed275efSAlexander Shiyan MODULE_DESCRIPTION("ALSA SoC EDB93xx"); 1180ed275efSAlexander Shiyan MODULE_LICENSE("GPL"); 1190ed275efSAlexander Shiyan MODULE_ALIAS("platform:edb93xx-audio"); 120