From mboxrd@z Thu Jan 1 00:00:00 1970 From: Xiubo Li Subject: [PATCHv3 5/7] ASoC: fsl: Add SGTL5000 based audio machine driver. Date: Tue, 17 Dec 2013 11:24:42 +0800 Message-ID: <1387250684-23406-6-git-send-email-Li.Xiubo@freescale.com> References: <1387250684-23406-1-git-send-email-Li.Xiubo@freescale.com> Mime-Version: 1.0 Content-Type: text/plain Return-path: In-Reply-To: <1387250684-23406-1-git-send-email-Li.Xiubo@freescale.com> Sender: linux-kernel-owner@vger.kernel.org To: lgirdwood@gmail.com, broonie@kernel.org, timur@tabi.org, perex@perex.cz Cc: r64188@freescale.com, rob.herring@calxeda.com, pawel.moll@arm.com, mark.rutland@arm.com, swarren@wwwdotorg.org, ian.campbell@citrix.com, rob@landley.net, linux@arm.linux.org.uk, tiwai@suse.de, grant.likely@linaro.org, fabio.estevam@freescale.com, LW@KARO-electronics.de, oskar@scara.com, shawn.guo@linaro.org, b42378@freescale.com, b18965@freescale.com, devicetree@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, alsa-devel@alsa-project.org List-Id: devicetree@vger.kernel.org This is the SGTL5000 codec based audio driver supported with both playback and capture dai link implemention. This implementation is only compatible with device tree definition. Signed-off-by: Xiubo Li Signed-off-by: Alison Wang +#include +#include +#include +#include + +#include "../codecs/sgtl5000.h" +#include "fsl_sai.h" + +static unsigned int sysclk_rate; + +static int vf610_sgtl5000_dai_init(struct snd_soc_pcm_runtime *rtd) +{ + int ret; + struct device *dev = rtd->card->dev; + + ret = snd_soc_dai_set_sysclk(rtd->codec_dai, SGTL5000_SYSCLK, + sysclk_rate, SND_SOC_CLOCK_IN); + if (ret) { + dev_err(dev, "could not set codec driver clock params :%d\n", + ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, FSL_SAI_CLK_BUS, + sysclk_rate, SND_SOC_CLOCK_OUT); + if (ret) { + dev_err(dev, "could not set cpu dai driver clock params :%d\n", + ret); + return ret; + } + + return 0; +} + +static struct snd_soc_dai_link vf610_sgtl5000_dai = { + .name = "HiFi", + .stream_name = "HiFi", + .codec_dai_name = "sgtl5000", + .init = &vf610_sgtl5000_dai_init, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM, +}; + +static const struct snd_soc_dapm_widget vf610_sgtl5000_dapm_widgets[] = { + SND_SOC_DAPM_MIC("Mic Jack", NULL), + SND_SOC_DAPM_LINE("Line In Jack", NULL), + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_SPK("Line Out Jack", NULL), + SND_SOC_DAPM_SPK("Ext Spk", NULL), +}; + +static struct snd_soc_card vf610_sgtl5000_card = { + .owner = THIS_MODULE, + .num_links = 1, + .dai_link = &vf610_sgtl5000_dai, + .dapm_widgets = vf610_sgtl5000_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(vf610_sgtl5000_dapm_widgets), +}; + +static int vf610_sgtl5000_parse_dt(struct platform_device *pdev) +{ + int ret; + struct device_node *sai_np, *codec_np; + struct clk *codec_clk; + struct i2c_client *codec_dev; + struct device_node *np = pdev->dev.of_node; + + ret = snd_soc_of_parse_card_name(&vf610_sgtl5000_card, "model"); + if (ret) + return ret; + + ret = snd_soc_of_parse_audio_routing(&vf610_sgtl5000_card, + "audio-routing"); + if (ret) + return ret; + + sai_np = of_parse_phandle(np, "saif-controller", 0); + if (!sai_np) { + dev_err(&pdev->dev, "\"saif-controller\" phandle missing or " + "invalid\n"); + return -EINVAL; + } + vf610_sgtl5000_dai.cpu_of_node = sai_np; + vf610_sgtl5000_dai.platform_of_node = sai_np; + + codec_np = of_parse_phandle(np, "audio-codec", 0); + if (!codec_np) { + dev_err(&pdev->dev, "\"audio-codec\" phandle missing or " + "invalid\n"); + ret = -EINVAL; + goto sai_np_fail; + } + vf610_sgtl5000_dai.codec_of_node = codec_np; + + codec_dev = of_find_i2c_device_by_node(codec_np); + if (!codec_dev) { + dev_err(&pdev->dev, "failed to find codec platform device\n"); + ret = PTR_ERR(codec_dev); + goto codec_np_fail; + } + + codec_clk = devm_clk_get(&codec_dev->dev, NULL); + if (IS_ERR(codec_clk)) { + dev_err(&pdev->dev, "failed to get codec clock\n"); + ret = PTR_ERR(codec_clk); + goto codec_np_fail; + } + + sysclk_rate = clk_get_rate(codec_clk); + +codec_np_fail: + of_node_put(codec_np); +sai_np_fail: + of_node_put(sai_np); + + return ret; +} + +static int vf610_sgtl5000_probe(struct platform_device *pdev) +{ + int ret; + + vf610_sgtl5000_card.dev = &pdev->dev; + + ret = vf610_sgtl5000_parse_dt(pdev); + if (ret) { + dev_err(&pdev->dev, "parse sgtl5000 device tree failed :%d\n", + ret); + return ret; + } + + ret = devm_snd_soc_register_card(&pdev->dev, &vf610_sgtl5000_card); + if (ret) { + dev_err(&pdev->dev, "TWR-AUDIO-SGTL board required :%d\n", + ret); + return ret; + } + + return 0; +} + +static int vf610_sgtl5000_remove(struct platform_device *pdev) +{ + return 0; +} + +static const struct of_device_id vf610_sgtl5000_dt_ids[] = { + { .compatible = "fsl,vf610-sgtl5000", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, vf610_sgtl5000_dt_ids); + +static struct platform_driver vf610_sgtl5000_driver = { + .driver = { + .name = "vf610-sgtl5000", + .owner = THIS_MODULE, + .of_match_table = vf610_sgtl5000_dt_ids, + }, + .probe = vf610_sgtl5000_probe, + .remove = vf610_sgtl5000_remove, +}; +module_platform_driver(vf610_sgtl5000_driver); + +MODULE_AUTHOR("Xiubo Li "); +MODULE_DESCRIPTION("Freescale SGTL5000 ASoC driver"); +MODULE_LICENSE("GPL"); -- 1.8.4