From patchwork Sun Jun 19 01:00:00 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marcel Ziswiler X-Patchwork-Id: 9190165 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 86A3E601C0 for ; Tue, 21 Jun 2016 10:08:48 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7378527F9C for ; Tue, 21 Jun 2016 10:08:48 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 67D962807B; Tue, 21 Jun 2016 10:08:48 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-1.9 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE autolearn=unavailable version=3.3.1 Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C517027F9C for ; Tue, 21 Jun 2016 10:08:45 +0000 (UTC) Received: by alsa0.perex.cz (Postfix, from userid 1000) id C10B92668C2; Tue, 21 Jun 2016 12:08:44 +0200 (CEST) Received: from alsa0.perex.cz (localhost [127.0.0.1]) by alsa0.perex.cz (Postfix) with ESMTP id C51D92614FD; Tue, 21 Jun 2016 12:08:08 +0200 (CEST) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id E7090265593; Sun, 19 Jun 2016 03:01:50 +0200 (CEST) Received: from mout.perfora.net (mout.perfora.net [74.208.4.194]) by alsa0.perex.cz (Postfix) with ESMTP id 194A9265328 for ; Sun, 19 Jun 2016 03:01:44 +0200 (CEST) Received: from localhost.net ([84.227.37.153]) by mrelay.perfora.net (mreueus001) with ESMTPA (Nemesis) id 0MhT1A-1b1jXZ045C-00MlKM; Sun, 19 Jun 2016 03:00:31 +0200 From: Marcel Ziswiler To: linux-tegra@vger.kernel.org Date: Sun, 19 Jun 2016 03:00:00 +0200 Message-Id: <1466298002-12576-2-git-send-email-marcel.ziswiler@toradex.com> X-Mailer: git-send-email 2.5.5 In-Reply-To: <1466298002-12576-1-git-send-email-marcel.ziswiler@toradex.com> References: <1466298002-12576-1-git-send-email-marcel.ziswiler@toradex.com> X-Provags-ID: V03:K0:t3VrlvbJaMgr+XxVz8wv2wvakBTUO6ZMLZFPOGx9O+B/HWmowDf SvAqbVI/qW+3yeUFmceMA+e5bSYLd91HpM6haTYx27eO5L1kJMBVvtZr3wnMcLmmnRKhGRY iQfx36SZCrMJv1bezjc3h4wAkAcQsnHdjvxCq0OQbaLhQNUMNRY4VPC67zYzMK2Of99N0J+ SHMKkHaVMQ3HjUU/eI4BA== X-UI-Out-Filterresults: notjunk:1; V01:K0:vgcR4/TdEm0=:MYjncv/n7x7kLjgal4V98C ubk8ND5B235paroPY9R5CoFjVP6XOKAyxCICRKWZy6Q2mgO4zMfdUg73ojadRgKZjlJorn0yo tyU5yDipGsRzTafcN9F5q5nAsqvTDt13Xc3mxcBYPL0kJ8XKKJph/ZstobXZb9xseDTBo/z0D ZDIP3pQWgnL7Iv0seRYEjj4N5prWsaoL8wb+HmuJ0MuNWMswBb4SYHY6YSAfWcH9jiGreRj0q Ukjj6qp0TZULUpizB8OSYbrZj61ixiSn3we47SPjJr8mX6eSbXHlnHy3T54eJ0HW+Y2iMxsCw VKARqCeZx/02XwSYN07sVAjfFlHBDPLlALqY5mNOICpMk/qlDu2ygAAPWPj9C+/ACb4yWwZvV XmDEOJ1qYWHFtspDFejGZ+4ckMSvITdJjrQPWTLM4aD3OeRbXWBmEWG5jtTBMFyq/8VSgef2g oidJ0rqY18fnG9lqrdE6UoegIId5bd2hGjQZYzwd2mEtS/xVgAtj2LJyazP85sFb1+0FniN06 xT8ZDGeL8Nuzjn0vYM6z0ELIIz/64L5DtuU0LcfsIFWpbzDHvs41DhU9y+vPM39KvfaXX3Zpz rVi/m3bLyHJLH91lTKsXfM1i+tBzDPH66M7nvfebNR0OZWso16eAyYbc384w65lPQZlcL3oV8 RsvwDeWB8iv9CPiD4v3C+nSwgBo+FnIn4RXPo2Vycu2iwLI7f9Pm1wtR8wdQY3l9+8N4= X-Mailman-Approved-At: Tue, 21 Jun 2016 12:08:06 +0200 Cc: Mark Rutland , devicetree@vger.kernel.org, alsa-devel@alsa-project.org, Stephen Warren , Marcel Ziswiler , linux-kernel@vger.kernel.org, Mark Brown , Takashi Iwai , Liam Girdwood , Rob Herring , Thierry Reding , Marcel Ziswiler , Alexandre Courbot Subject: [alsa-devel] [PATCH v4 1/3] ASoC: tegra: add tegra sgtl5000 machine driver X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP This binding and driver describe/support playback to headphones, and capture from line-in and microphone. This driver is useful for the Toradex Apalis T30, Apalis TK1 and Colibri T30 modules. Signed-off-by: Marcel Ziswiler Reviewed-by: Stephen Warren Signed-off-by: Marcel Ziswiler Acked-by: Rob Herring --- Changes in v4: - simple-audio-card does still not allow for more advanced use cases like Tegra SoCs - further platform drivers have been accepted since my last attempt (e.g. rt5677 one) - relevance for one further board the new Toradex Apalis TK1 - drop unused sound/jack.h include - in tegra_sgtl5000_driver_remove() pass return value of snd_soc_unregister_card() on to caller - no longer set owner property in platform_driver to THIS_MODULE - re-based/resend Changes in v3: - revert to not using simple-audio-card being incompatible with tegra - rebased to for-next Changes in v2: - using simple-audio-card as suggested by Fabio .../bindings/sound/nvidia,tegra-audio-sgtl5000.txt | 42 ++++ sound/soc/tegra/Kconfig | 11 ++ sound/soc/tegra/Makefile | 2 + sound/soc/tegra/tegra_sgtl5000.c | 212 +++++++++++++++++++++ 4 files changed, 267 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/nvidia,tegra-audio-sgtl5000.txt create mode 100644 sound/soc/tegra/tegra_sgtl5000.c diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-sgtl5000.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-sgtl5000.txt new file mode 100644 index 0000000..5da7da4 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-sgtl5000.txt @@ -0,0 +1,42 @@ +NVIDIA Tegra audio complex, with SGTL5000 CODEC + +Required properties: +- compatible : "nvidia,tegra-audio-sgtl5000" +- clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. +- clock-names : Must include the following entries: + - pll_a + - pll_a_out0 + - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) +- nvidia,model : The user-visible name of this sound complex. +- nvidia,audio-routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. Valid names for sources and + sinks are the SGTL5000's pins (as documented in its binding), and the jacks + on the board: + + * Headphone Jack + * Line In Jack + * Mic Jack + +- nvidia,i2s-controller : The phandle of the Tegra I2S controller that's + connected to the CODEC. +- nvidia,audio-codec : The phandle of the SGTL5000 audio codec. + +Example: + +sound { + compatible = "toradex,tegra-audio-sgtl5000-apalis_t30", + "nvidia,tegra-audio-sgtl5000"; + nvidia,model = "Toradex Apalis T30"; + nvidia,audio-routing = + "Headphone Jack", "HP_OUT", + "LINE_IN", "Line In Jack", + "MIC_IN", "Mic Jack"; + nvidia,i2s-controller = <&tegra_i2s2>; + nvidia,audio-codec = <&sgtl5000>; + clocks = <&tegra_car TEGRA30_CLK_PLL_A>, + <&tegra_car TEGRA30_CLK_PLL_A_OUT0>, + <&tegra_car TEGRA30_CLK_EXTERN1>; + clock-names = "pll_a", "pll_a_out0", "mclk"; +}; diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig index a6768f8..efbe8d4 100644 --- a/sound/soc/tegra/Kconfig +++ b/sound/soc/tegra/Kconfig @@ -138,3 +138,14 @@ config SND_SOC_TEGRA_RT5677 help Say Y or M here if you want to add support for SoC audio on Tegra boards using the RT5677 codec, such as Ryu. + +config SND_SOC_TEGRA_SGTL5000 + tristate "SoC Audio support for Tegra boards using a SGTL5000 codec" + depends on SND_SOC_TEGRA && I2C && GPIOLIB + select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC + select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC + select SND_SOC_SGTL5000 + help + Say Y or M here if you want to add support for SoC audio on Tegra + boards using the SGTL5000 codec, such as Apalis T30, Apalis TK1 or + Colibri T30. diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile index 9171655..f214a3f 100644 --- a/sound/soc/tegra/Makefile +++ b/sound/soc/tegra/Makefile @@ -26,6 +26,7 @@ snd-soc-tegra-wm9712-objs := tegra_wm9712.o snd-soc-tegra-trimslice-objs := trimslice.o snd-soc-tegra-alc5632-objs := tegra_alc5632.o snd-soc-tegra-max98090-objs := tegra_max98090.o +snd-soc-tegra-sgtl5000-objs := tegra_sgtl5000.o obj-$(CONFIG_SND_SOC_TEGRA_RT5640) += snd-soc-tegra-rt5640.o obj-$(CONFIG_SND_SOC_TEGRA_RT5677) += snd-soc-tegra-rt5677.o @@ -35,3 +36,4 @@ obj-$(CONFIG_SND_SOC_TEGRA_WM9712) += snd-soc-tegra-wm9712.o obj-$(CONFIG_SND_SOC_TEGRA_TRIMSLICE) += snd-soc-tegra-trimslice.o obj-$(CONFIG_SND_SOC_TEGRA_ALC5632) += snd-soc-tegra-alc5632.o obj-$(CONFIG_SND_SOC_TEGRA_MAX98090) += snd-soc-tegra-max98090.o +obj-$(CONFIG_SND_SOC_TEGRA_SGTL5000) += snd-soc-tegra-sgtl5000.o \ No newline at end of file diff --git a/sound/soc/tegra/tegra_sgtl5000.c b/sound/soc/tegra/tegra_sgtl5000.c new file mode 100644 index 0000000..1e76869 --- /dev/null +++ b/sound/soc/tegra/tegra_sgtl5000.c @@ -0,0 +1,212 @@ +/* + * tegra_sgtl5000.c - Tegra machine ASoC driver for boards using SGTL5000 codec + * + * Author: Marcel Ziswiler + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Based on code copyright/by: + * + * Copyright (C) 2010-2012 - NVIDIA, Inc. + * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd. + * Copyright 2007 Wolfson Microelectronics PLC. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "../codecs/sgtl5000.h" + +#include "tegra_asoc_utils.h" + +#define DRV_NAME "tegra-snd-sgtl5000" + +struct tegra_sgtl5000 { + struct tegra_asoc_utils_data util_data; +}; + +static int tegra_sgtl5000_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_card *card = rtd->card; + struct tegra_sgtl5000 *machine = snd_soc_card_get_drvdata(card); + int srate, mclk; + int err; + + srate = params_rate(params); + switch (srate) { + case 11025: + case 22050: + case 44100: + case 88200: + mclk = 11289600; + break; + default: + mclk = 12288000; + break; + } + + err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk); + if (err < 0) { + dev_err(card->dev, "Can't configure clocks\n"); + return err; + } + + err = snd_soc_dai_set_sysclk(codec_dai, SGTL5000_SYSCLK, mclk, + SND_SOC_CLOCK_IN); + if (err < 0) { + dev_err(card->dev, "codec_dai clock not set\n"); + return err; + } + + return 0; +} + +static struct snd_soc_ops tegra_sgtl5000_ops = { + .hw_params = tegra_sgtl5000_hw_params, +}; + +static const struct snd_soc_dapm_widget tegra_sgtl5000_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_LINE("Line In Jack", NULL), + SND_SOC_DAPM_MIC("Mic Jack", NULL), +}; + +static struct snd_soc_dai_link tegra_sgtl5000_dai = { + .name = "sgtl5000", + .stream_name = "HiFi", + .codec_dai_name = "sgtl5000", + .ops = &tegra_sgtl5000_ops, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, +}; + +static struct snd_soc_card snd_soc_tegra_sgtl5000 = { + .name = "tegra-sgtl5000", + .owner = THIS_MODULE, + .dai_link = &tegra_sgtl5000_dai, + .num_links = 1, + .dapm_widgets = tegra_sgtl5000_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tegra_sgtl5000_dapm_widgets), + .fully_routed = true, +}; + +static int tegra_sgtl5000_driver_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct snd_soc_card *card = &snd_soc_tegra_sgtl5000; + struct tegra_sgtl5000 *machine; + int ret; + + machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_sgtl5000), + GFP_KERNEL); + if (!machine) { + dev_err(&pdev->dev, "Can't allocate tegra_sgtl5000 struct\n"); + return -ENOMEM; + } + + card->dev = &pdev->dev; + platform_set_drvdata(pdev, card); + snd_soc_card_set_drvdata(card, machine); + + ret = snd_soc_of_parse_card_name(card, "nvidia,model"); + if (ret) + goto err; + + ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing"); + if (ret) + goto err; + + tegra_sgtl5000_dai.codec_of_node = of_parse_phandle(np, + "nvidia,audio-codec", 0); + if (!tegra_sgtl5000_dai.codec_of_node) { + dev_err(&pdev->dev, + "Property 'nvidia,audio-codec' missing or invalid\n"); + ret = -EINVAL; + goto err; + } + + tegra_sgtl5000_dai.cpu_of_node = of_parse_phandle(np, + "nvidia,i2s-controller", 0); + if (!tegra_sgtl5000_dai.cpu_of_node) { + dev_err(&pdev->dev, + "Property 'nvidia,i2s-controller' missing/invalid\n"); + ret = -EINVAL; + goto err; + } + + tegra_sgtl5000_dai.platform_of_node = tegra_sgtl5000_dai.cpu_of_node; + + ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); + if (ret) + goto err; + + ret = snd_soc_register_card(card); + if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", + ret); + goto err_fini_utils; + } + + return 0; + +err_fini_utils: + tegra_asoc_utils_fini(&machine->util_data); +err: + return ret; +} + +static int tegra_sgtl5000_driver_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct tegra_sgtl5000 *machine = snd_soc_card_get_drvdata(card); + int ret; + + ret = snd_soc_unregister_card(card); + + tegra_asoc_utils_fini(&machine->util_data); + + return ret; +} + +static const struct of_device_id tegra_sgtl5000_of_match[] = { + { .compatible = "nvidia,tegra-audio-sgtl5000", }, + { /* sentinel */ }, +}; + +static struct platform_driver tegra_sgtl5000_driver = { + .driver = { + .name = DRV_NAME, + .pm = &snd_soc_pm_ops, + .of_match_table = tegra_sgtl5000_of_match, + }, + .probe = tegra_sgtl5000_driver_probe, + .remove = tegra_sgtl5000_driver_remove, +}; +module_platform_driver(tegra_sgtl5000_driver); + +MODULE_AUTHOR("Marcel Ziswiler "); +MODULE_DESCRIPTION("Tegra SGTL5000 machine ASoC driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); +MODULE_DEVICE_TABLE(of, tegra_sgtl5000_of_match);