From 5b37b08ff1c29e7386eb8a29b168e94e33cf82c3 Mon Sep 17 00:00:00 2001 From: Matt Flax Date: Wed, 8 Apr 2020 20:00:30 +1000 Subject: [PATCH] Add support for the AudioInjector.net Isolated sound card This patch adds support for the Audio Injector Isolated sound card. Signed-off-by: Matt Flax --- arch/arm/boot/dts/overlays/Makefile | 1 + arch/arm/boot/dts/overlays/README | 6 + ...dioinjector-isolated-soundcard-overlay.dts | 55 ++++++ sound/soc/bcm/Kconfig | 7 + sound/soc/bcm/Makefile | 2 + .../bcm/audioinjector-isolated-soundcard.c | 183 ++++++++++++++++++ 11 files changed, 259 insertions(+), 5 deletions(-) create mode 100644 arch/arm/boot/dts/overlays/audioinjector-isolated-soundcard-overlay.dts create mode 100644 sound/soc/bcm/audioinjector-isolated-soundcard.c --- a/arch/arm/boot/dts/overlays/Makefile +++ b/arch/arm/boot/dts/overlays/Makefile @@ -22,6 +22,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \ applepi-dac.dtbo \ at86rf233.dtbo \ audioinjector-addons.dtbo \ + audioinjector-isolated-soundcard.dtbo \ audioinjector-ultra.dtbo \ audioinjector-wm8731-audio.dtbo \ audiosense-pi.dtbo \ --- a/arch/arm/boot/dts/overlays/README +++ b/arch/arm/boot/dts/overlays/README @@ -505,6 +505,12 @@ Params: non-stop-clocks Keeps th is paused or stopped (default off) +Name: audioinjector-isolated-soundcard +Info: Configures the audioinjector.net isolated soundcard +Load: dtoverlay=audioinjector-isolated-soundcard +Params: + + Name: audioinjector-ultra Info: Configures the audioinjector.net ultra soundcard Load: dtoverlay=audioinjector-ultra --- /dev/null +++ b/arch/arm/boot/dts/overlays/audioinjector-isolated-soundcard-overlay.dts @@ -0,0 +1,55 @@ +// Definitions for audioinjector.net audio isolated soundcard +/dts-v1/; +/plugin/; + +/ { + compatible = "brcm,bcm2835"; + + fragment@0 { + target = <&i2s>; + __overlay__ { + status = "okay"; + }; + }; + + fragment@1 { + target-path = "/"; + __overlay__ { + cs4272_mclk: codec-mclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24576000>; + }; + }; + }; + + fragment@2 { + target = <&i2c1>; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + cs4272: cs4271@10 { + #sound-dai-cells = <0>; + compatible = "cirrus,cs4271"; + reg = <0x10>; + reset-gpio = <&gpio 5 0>; + clocks = <&cs4272_mclk>; + clock-names = "mclk"; + status = "okay"; + }; + }; + }; + + fragment@3 { + target = <&sound>; + snd: __overlay__ { + compatible = "ai,audioinjector-isolated-soundcard"; + mute-gpios = <&gpio 17 0>; + i2s-controller = <&i2s>; + codec = <&cs4272>; + status = "okay"; + }; + }; +}; --- a/sound/soc/bcm/Kconfig +++ b/sound/soc/bcm/Kconfig @@ -192,6 +192,13 @@ config SND_AUDIOINJECTOR_OCTO_SOUNDCARD help Say Y or M if you want to add support for audioinjector.net octo add on +config SND_AUDIOINJECTOR_ISOLATED_SOUNDCARD + tristate "Support for audioinjector.net isolated DAC and ADC soundcard" + depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + select SND_SOC_CS4271_I2C + help + Say Y or M if you want to add support for audioinjector.net isolated soundcard + config SND_AUDIOSENSE_PI tristate "Support for AudioSense Add-On Soundcard" depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S --- a/sound/soc/bcm/Makefile +++ b/sound/soc/bcm/Makefile @@ -27,6 +27,7 @@ snd-soc-iqaudio-dac-objs := iqaudio-dac. snd-soc-i-sabre-q2m-objs := i-sabre-q2m.o snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o snd-soc-audioinjector-octo-soundcard-objs := audioinjector-octo-soundcard.o +snd-soc-audioinjector-isolated-soundcard-objs := audioinjector-isolated-soundcard.o snd-soc-audiosense-pi-objs := audiosense-pi.o snd-soc-digidac1-soundcard-objs := digidac1-soundcard.o snd-soc-dionaudio-loco-objs := dionaudio_loco.o @@ -55,6 +56,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC obj-$(CONFIG_SND_BCM2708_SOC_I_SABRE_Q2M) += snd-soc-i-sabre-q2m.o obj-$(CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD) += snd-soc-audioinjector-pi-soundcard.o obj-$(CONFIG_SND_AUDIOINJECTOR_OCTO_SOUNDCARD) += snd-soc-audioinjector-octo-soundcard.o +obj-$(CONFIG_SND_AUDIOINJECTOR_ISOLATED_SOUNDCARD) += snd-soc-audioinjector-isolated-soundcard.o obj-$(CONFIG_SND_AUDIOSENSE_PI) += snd-soc-audiosense-pi.o obj-$(CONFIG_SND_DIGIDAC1_SOUNDCARD) += snd-soc-digidac1-soundcard.o obj-$(CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO) += snd-soc-dionaudio-loco.o --- /dev/null +++ b/sound/soc/bcm/audioinjector-isolated-soundcard.c @@ -0,0 +1,183 @@ +/* + * ASoC Driver for AudioInjector.net isolated soundcard + * + * Created on: 20-February-2020 + * Author: flatmax@flatmax.org + * based on audioinjector-octo-soundcard.c + * + * Copyright (C) 2020 Flatmax Pty. Ltd. + * + * 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. + * + * This program is distributed in the hope that 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. + */ + +#include +#include +#include + +#include +#include +#include +#include + +static struct gpio_desc *mute_gpio; + +static const unsigned int audioinjector_isolated_rates[] = { + 192000, 96000, 48000, 32000, 24000, 16000, 8000 +}; + +static struct snd_pcm_hw_constraint_list audioinjector_isolated_constraints = { + .list = audioinjector_isolated_rates, + .count = ARRAY_SIZE(audioinjector_isolated_rates), +}; + +static int audioinjector_isolated_dai_init(struct snd_soc_pcm_runtime *rtd) +{ + int ret=snd_soc_dai_set_sysclk(rtd->codec_dai, 0, 24576000, 0); + if (ret) + return ret; + + return snd_soc_dai_set_bclk_ratio(rtd->cpu_dai, 64); +} + +static int audioinjector_isolated_startup(struct snd_pcm_substream *substream) +{ + snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &audioinjector_isolated_constraints); + + return 0; +} + +static int audioinjector_isolated_trigger(struct snd_pcm_substream *substream, + int cmd){ + + switch (cmd) { + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + gpiod_set_value(mute_gpio, 0); + break; + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + gpiod_set_value(mute_gpio, 1); + break; + default: + return -EINVAL; + } + return 0; +} + +static struct snd_soc_ops audioinjector_isolated_ops = { + .startup = audioinjector_isolated_startup, + .trigger = audioinjector_isolated_trigger, +}; + +SND_SOC_DAILINK_DEFS(audioinjector_isolated, + DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")), + DAILINK_COMP_ARRAY(COMP_CODEC("cs4271.1-0010", "cs4271-hifi")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0"))); + +static struct snd_soc_dai_link audioinjector_isolated_dai[] = { + { + .name = "AudioInjector ISO", + .stream_name = "AI-HIFI", + .ops = &audioinjector_isolated_ops, + .init = audioinjector_isolated_dai_init, + .symmetric_rates = 1, + .symmetric_channels = 1, + .dai_fmt = SND_SOC_DAIFMT_CBM_CFM|SND_SOC_DAIFMT_I2S|SND_SOC_DAIFMT_NB_NF, + SND_SOC_DAILINK_REG(audioinjector_isolated), + } +}; + +static const struct snd_soc_dapm_widget audioinjector_isolated_widgets[] = { + SND_SOC_DAPM_OUTPUT("OUTPUTS"), + SND_SOC_DAPM_INPUT("INPUTS"), +}; + +static const struct snd_soc_dapm_route audioinjector_isolated_route[] = { + /* Balanced outputs */ + {"OUTPUTS", NULL, "AOUTA+"}, + {"OUTPUTS", NULL, "AOUTA-"}, + {"OUTPUTS", NULL, "AOUTB+"}, + {"OUTPUTS", NULL, "AOUTB-"}, + + /* Balanced inputs */ + {"AINA", NULL, "INPUTS"}, + {"AINB", NULL, "INPUTS"}, +}; + +static struct snd_soc_card snd_soc_audioinjector_isolated = { + .name = "audioinjector-isolated-soundcard", + .dai_link = audioinjector_isolated_dai, + .num_links = ARRAY_SIZE(audioinjector_isolated_dai), + + .dapm_widgets = audioinjector_isolated_widgets, + .num_dapm_widgets = ARRAY_SIZE(audioinjector_isolated_widgets), + .dapm_routes = audioinjector_isolated_route, + .num_dapm_routes = ARRAY_SIZE(audioinjector_isolated_route), +}; + +static int audioinjector_isolated_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &snd_soc_audioinjector_isolated; + int ret; + + card->dev = &pdev->dev; + + if (pdev->dev.of_node) { + struct snd_soc_dai_link *dai = &audioinjector_isolated_dai[0]; + struct device_node *i2s_node = + of_parse_phandle(pdev->dev.of_node, "i2s-controller", 0); + + if (i2s_node) { + dai->cpus->dai_name = NULL; + dai->cpus->of_node = i2s_node; + dai->platforms->name = NULL; + dai->platforms->of_node = i2s_node; + } else { + dev_err(&pdev->dev, + "i2s-controller missing or invalid in DT\n"); + return -EINVAL; + } + + mute_gpio = devm_gpiod_get_optional(&pdev->dev, "mute", GPIOD_OUT_LOW); + if (IS_ERR(mute_gpio)){ + dev_err(&pdev->dev, "mute gpio not found in dt overlay\n"); + return PTR_ERR(mute_gpio); + } + } + + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret && ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); + return ret; +} + +static const struct of_device_id audioinjector_isolated_of_match[] = { + { .compatible = "ai,audioinjector-isolated-soundcard", }, + {}, +}; +MODULE_DEVICE_TABLE(of, audioinjector_isolated_of_match); + +static struct platform_driver audioinjector_isolated_driver = { + .driver = { + .name = "audioinjector-isolated", + .owner = THIS_MODULE, + .of_match_table = audioinjector_isolated_of_match, + }, + .probe = audioinjector_isolated_probe, +}; + +module_platform_driver(audioinjector_isolated_driver); +MODULE_AUTHOR("Matt Flax "); +MODULE_DESCRIPTION("AudioInjector.net isolated Soundcard"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:audioinjector-isolated-soundcard");