From patchwork Thu Sep 19 08:54:37 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jean-Francois Moine X-Patchwork-Id: 2910301 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 962769F1BF for ; Thu, 19 Sep 2013 08:53:16 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 3B7E52043C for ; Thu, 19 Sep 2013 08:53:15 +0000 (UTC) Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 980D720420 for ; Thu, 19 Sep 2013 08:53:13 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1VMZz0-00045i-Lv; Thu, 19 Sep 2013 08:53:07 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1VMZyy-00087X-9s; Thu, 19 Sep 2013 08:53:04 +0000 Received: from smtp1-g21.free.fr ([2a01:e0c:1:1599::10]) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1VMZyt-00085f-L6 for linux-arm-kernel@lists.infradead.org; Thu, 19 Sep 2013 08:53:02 +0000 Received: from armhf (unknown [IPv6:2a01:e35:2f5c:9de0:212:bfff:fe1e:9ce4]) by smtp1-g21.free.fr (Postfix) with ESMTP id 0FBEE9401F1; Thu, 19 Sep 2013 10:52:20 +0200 (CEST) Date: Thu, 19 Sep 2013 10:54:37 +0200 From: Jean-Francois Moine To: Liam Girdwood , Mark Brown , alsa-devel@alsa-project.org, devicetree@vger.kernel.org Subject: [PATCH] ASoC: generic: Add generic DT based simple codec Message-ID: <20130919105437.75e0f0a3@armhf> X-Mailer: Claws Mail 3.9.2 (GTK+ 2.24.20; arm-unknown-linux-gnueabihf) Mime-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130919_045300_496234_4FFE4DAF X-CRM114-Status: GOOD ( 23.52 ) X-Spam-Score: -1.9 (-) Cc: Takashi Iwai , linux-arm-kernel@lists.infradead.org, Jaroslav Kysela X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.8 required=5.0 tests=BAYES_00,FREEMAIL_FROM, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch adds a simple sound codec which is described by the DT. This codec may be used when no specific codec action is needed. Signed-off-by: Jean-Francois Moine --- .../devicetree/bindings/sound/simple-codec.txt | 103 +++++++++++++ sound/soc/generic/Kconfig | 6 + sound/soc/generic/Makefile | 2 + sound/soc/generic/simple-codec.c | 197 +++++++++++++++++++++++++ 4 files changed, 3088 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/simple-codec.txt b/Documentation/devicetree/bindings/sound/simple-codec.txt new file mode 100644 index 0000000..75be747 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/simple-codec.txt @@ -0,0 +1,103 @@ +Device-Tree bindings for the simple codec + +Required properties: +- compatible: should be "linux,simple-codec". +- dai-name: name of the codec + +Optional properties: +- capture: information about capture +- playback: information about playback +At least one of the 'capture' or 'playback' nodes must be present. + +Child 'capture' and 'playback' required properties: +- stream-name: name of the stream +- formats: list of the supported formats (see below) +- rates: list of the supported rates (see below) +- #channels: minimum and maximum numbers of channels + +Formats: + "s8" + "u8" + "s16_le" + "s16_be" + "u16_le" + "u16_be" + "s24_le" + "s24_be" + "u24_le" + "u24_be" + "s32_le" + "s32_be" + "u32_le" + "u32_be" + "float_le" + "float_be" + "float64_le" + "float64_be" + "iec958_subframe_le" + "iec958_subframe_be" + "mu_law" + "a_law" + "ima_adpcm" + "mpeg" + "gsm" + "special" + "s24_3l" + "s24_3be" + "u24_3le" + "u24_3be" + "s20_3le" + "s20_3be" + "u20_3le" + "u20_3be" + "s18_3le" + "s18_3b" + "u18_3le" + "u18_3be" + "g723_24" + "g723_24_1b" + "g723_40" + "g723_40_1b" + "dsd_u8" + "dsd_u16_le" + +Rates: + 5512 + 8000 + 11025 + 16000 + 22050 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 176400 + 192000 + +Examples: + + spdifo: spdif-transmitter { + compatible = "linux,simple-codec"; + dai-name = "dit-hifi"; + playback { + stream-name = "S/PDIF Playback"; + formats = "s16_le"; + rates = <8000 11025 16000 22050 32000 44100 + 48000 64000 88200 96000>; + #channels = <1 384>; + }; + }; + + hdmio: hdmi-transmitter { + compatible = "linux,simple-codec"; + dai-name = "hdmi-hifi"; + playback { + stream-name = "HDMI Playback"; + formats = "s16_le", "s24_le"; + rates = <32000 44100 48000 88200 96000 + 176400 192000>; + #channels = <2 8>; + }; + }; diff --git a/sound/soc/generic/Kconfig b/sound/soc/generic/Kconfig index 610f612..d9221539 100644 --- a/sound/soc/generic/Kconfig +++ b/sound/soc/generic/Kconfig @@ -2,3 +2,9 @@ config SND_SIMPLE_CARD tristate "ASoC Simple sound card support" help This option enables generic simple sound card support + +config SND_SIMPLE_CODEC + tristate "ASoC Simple sound codec support" + depends on OF + help + This option enables generic simple sound codec support diff --git a/sound/soc/generic/Makefile b/sound/soc/generic/Makefile index 9c3b246..f94620e 100644 --- a/sound/soc/generic/Makefile +++ b/sound/soc/generic/Makefile @@ -1,3 +1,5 @@ snd-soc-simple-card-objs := simple-card.o +snd-soc-simple-codec-objs := simple-codec.o obj-$(CONFIG_SND_SIMPLE_CARD) += snd-soc-simple-card.o +obj-$(CONFIG_SND_SIMPLE_CODEC) += snd-soc-simple-codec.o diff --git a/sound/soc/generic/simple-codec.c b/sound/soc/generic/simple-codec.c new file mode 100644 index 0000000..217cd0e --- /dev/null +++ b/sound/soc/generic/simple-codec.c @@ -0,0 +1,197 @@ +/* + * ALSA SoC simple codec driver + * + * This driver is used by controllers which do not need any codec + * (s/pdif, hdmi..). + * Its parameters are built from a DT description. + * + * Copyright: (C) 2013 Jean-François Moine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include + +#define DRV_NAME "simple-codec" + +static struct snd_soc_codec_driver soc_codec_simple_codec; + +static char *format_tb[] = { + "s8", "u8", "s16_le", "s16_be", + "u16_le", "u16_be", "s24_le", "s24_be", + "u24_le", "u24_be", "s32_le", "s32_be", + "u32_le", "u32_be", "float_le", "float_be", + + "float64_le", "float64_be", "iec958_subframe_le", "iec958_subframe_be", + "mu_law", "a_law", "ima_adpcm", "mpeg", + "gsm", "", "", "", + "", "", "", "special", + + "s24_3l", "s24_3be", "u24_3le", "u24_3be", + "s20_3le", "s20_3be", "u20_3le", "u20_3be", + "s18_3le", "s18_3b", "u18_3le", "u18_3be", + "g723_24", "g723_24_1b", "g723_40", "g723_40_1b", + + "dsd_u8", "dsd_u16_le", +}; + +#if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 12 +#error "Change this table" +#endif +static u32 rate_tb[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, + 48000, 64000, 88200, 96000, 176400, 192000 }; + +static int get_format(u64 *p_formats, char *p) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(format_tb); i++) { + if (strcmp(format_tb[i], p) == 0) { + *p_formats |= 1 << i; + return 0; + } + } + return -EINVAL; +} + +static int get_rate(u32 *p_rates, u32 val) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(rate_tb); i++) { + if (rate_tb[i] == val) { + *p_rates |= 1 << i; + return 0; + } + } + return -EINVAL; +} + +static int stream_populate(struct device *dev, + struct snd_soc_pcm_stream *stream, + struct device_node *np) +{ + u64 formats; + u32 rates, val; + char *p; + int i, ret; + + ret = of_property_read_string(np, "stream-name", &stream->stream_name); + if (ret) { + dev_err(dev, "Failed to parse stream-name string\n"); + return ret; + } + + i = 0; + formats = 0; + for (;;) { + ret = of_property_read_string_index(np, "formats", i, + (const char **) &p); + if (ret) + break; + ret = get_format(&formats, p); + if (ret) { + dev_err(dev, "Bad codec format\n"); + return ret; + } + i++; + } + stream->formats = formats; + + i = 0; + rates = 0; + for (;;) { + ret = of_property_read_u32_index(np, "rates", i, &val); + if (ret) + break; + ret = get_rate(&rates, val); + if (ret) { + dev_err(dev, "Bad rate\n"); + return ret; + } + i++; + } + stream->rates = rates; + + ret = of_property_read_u32_index(np, "#channels", 0, &val); + if (ret) { + dev_err(dev, "Bad min channel\n"); + return ret; + } + stream->channels_min = val; + ret = of_property_read_u32_index(np, "#channels", 1, &val); + if (ret) { + dev_err(dev, "Bad max channel\n"); + return ret; + } + stream->channels_max = val; + + return 0; +} + +static int simple_codec_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct device_node *np2; + struct snd_soc_dai_driver *dai; + int ret; + + dai = devm_kzalloc(dev, sizeof *dai, GFP_KERNEL); + if (!dai) + return -ENOMEM; + + ret = of_property_read_string(np, "dai-name", &dai->name); + if (ret) { + dev_err(dev, "Failed to parse dai-name\n"); + return ret; + } + + np2 = of_find_node_by_name(np, "capture"); + if (np2) { + ret = stream_populate(dev, &dai->capture, np2); + if (ret) + return ret; + } + np2 = of_find_node_by_name(np, "playback"); + if (np2) { + ret = stream_populate(dev, &dai->playback, np2); + if (ret) + return ret; + } + + return snd_soc_register_codec(dev, &soc_codec_simple_codec, + dai, 1); +} + +static int simple_codec_remove(struct platform_device *pdev) +{ + snd_soc_unregister_codec(&pdev->dev); + return 0; +} + +static const struct of_device_id simple_codec_of_match[] = { + { .compatible = "linux,simple-codec", }, + { } +}; +MODULE_DEVICE_TABLE(of, simple_codec_of_match); + +static struct platform_driver simple_codec_driver = { + .probe = simple_codec_probe, + .remove = simple_codec_remove, + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = simple_codec_of_match, + }, +}; + +module_platform_driver(simple_codec_driver); + +MODULE_AUTHOR("Jean-Francois Moine "); +MODULE_DESCRIPTION("simple codec driver"); +MODULE_LICENSE("GPL");