Skip to content

Commit

Permalink
Added IQaudIO Pi-Codec board support (#2969)
Browse files Browse the repository at this point in the history
Add support for the IQaudIO Pi-Codec board.

Signed-off-by: Gordon <[email protected]>
  • Loading branch information
IQaudIO authored and popcornmix committed Jun 4, 2019
1 parent 52764db commit 328ae2c
Show file tree
Hide file tree
Showing 7 changed files with 309 additions and 0 deletions.
1 change: 1 addition & 0 deletions arch/arm/boot/dts/overlays/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
i2c1-bcm2708.dtbo \
i2s-gpio28-31.dtbo \
ilitek251x.dtbo \
iqaudio-codec.dtbo \
iqaudio-dac.dtbo \
iqaudio-dacplus.dtbo \
iqaudio-digi-wm8804-audio.dtbo \
Expand Down
6 changes: 6 additions & 0 deletions arch/arm/boot/dts/overlays/README
Original file line number Diff line number Diff line change
Expand Up @@ -1134,6 +1134,12 @@ Params: interrupt GPIO used for interrupt (default 4)
touchscreen (in pixels)


Name: iqaudio-codec
Info: Configures the IQaudio Codec audio card
Load: dtoverlay=iqaudio-codec
Params: <None>


Name: iqaudio-dac
Info: Configures the IQaudio DAC audio card
Load: dtoverlay=iqaudio-dac,<param>
Expand Down
42 changes: 42 additions & 0 deletions arch/arm/boot/dts/overlays/iqaudio-codec-overlay.dts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Definitions for IQaudIO CODEC
/dts-v1/;
/plugin/;

/ {
compatible = "brcm,bcm2708";

fragment@0 {
target = <&i2s>;
__overlay__ {
status = "okay";
};
};

fragment@1 {
target = <&i2c1>;
__overlay__ {
#address-cells = <1>;
#size-cells = <0>;
status = "okay";

da2713@1a {
#sound-dai-cells = <0>;
compatible = "dlg,da7213";
reg = <0x1a>;
status = "okay";
};
};
};

fragment@2 {
target = <&sound>;
iqaudio_dac: __overlay__ {
compatible = "iqaudio,iqaudio-codec";
i2s-controller = <&i2s>;
status = "okay";
};
};

__overrides__ {
};
};
1 change: 1 addition & 0 deletions arch/arm64/configs/bcmrpi3_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -803,6 +803,7 @@ CONFIG_SND_BCM2708_SOC_RPI_DAC=m
CONFIG_SND_BCM2708_SOC_RPI_PROTO=m
CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC=m
CONFIG_SND_BCM2708_SOC_JUSTBOOM_DIGI=m
CONFIG_SND_BCM2708_SOC_IQAUDIO_CODEC=m
CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m
CONFIG_SND_BCM2708_SOC_IQAUDIO_DIGI=m
CONFIG_SND_BCM2708_SOC_I_SABRE_Q2M=m
Expand Down
7 changes: 7 additions & 0 deletions sound/soc/bcm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,13 @@ config SND_BCM2708_SOC_JUSTBOOM_DIGI
help
Say Y or M if you want to add support for JustBoom Digi.

config SND_BCM2708_SOC_IQAUDIO_CODEC
tristate "Support for IQaudIO-CODEC"
depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
select SND_SOC_DA7213
help
Say Y or M if you want to add support for IQaudIO-CODEC.

config SND_BCM2708_SOC_IQAUDIO_DAC
tristate "Support for IQaudIO-DAC"
depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
Expand Down
2 changes: 2 additions & 0 deletions sound/soc/bcm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o
snd-soc-justboom-dac-objs := justboom-dac.o
snd-soc-rpi-cirrus-objs := rpi-cirrus.o
snd-soc-rpi-proto-objs := rpi-proto.o
snd-soc-iqaudio-codec-objs := iqaudio-codec.o
snd-soc-iqaudio-dac-objs := iqaudio-dac.o
snd-soc-i-sabre-q2m-objs := i-sabre-q2m.o
snd-soc-audioinjector-pi-soundcard-objs := audioinjector-pi-soundcard.o
Expand All @@ -41,6 +42,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusa
obj-$(CONFIG_SND_BCM2708_SOC_JUSTBOOM_DAC) += snd-soc-justboom-dac.o
obj-$(CONFIG_SND_BCM2708_SOC_RPI_CIRRUS) += snd-soc-rpi-cirrus.o
obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_CODEC) += snd-soc-iqaudio-codec.o
obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
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
Expand Down
250 changes: 250 additions & 0 deletions sound/soc/bcm/iqaudio-codec.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
/*
* ASoC Driver for IQaudIO Raspberry Pi Codec board
*
* Author: Gordon Garrity <[email protected]>
* (C) Copyright IQaudio Limited, 2017-2019
*
* 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 <linux/module.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>

#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/jack.h>

#include <linux/acpi.h>
#include <linux/slab.h>
#include "../codecs/da7213.h"

static int pll_out = DA7213_PLL_FREQ_OUT_90316800;

static int snd_rpi_iqaudio_pll_control(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
int ret = 0;
struct snd_soc_dapm_context *dapm = w->dapm;
struct snd_soc_card *card = dapm->card;
struct snd_soc_pcm_runtime *rtd =
snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
struct snd_soc_dai *codec_dai = rtd->codec_dai;

if (SND_SOC_DAPM_EVENT_OFF(event)) {
ret = snd_soc_dai_set_pll(codec_dai, 0, DA7213_SYSCLK_MCLK, 0,
0);
if (ret)
dev_err(card->dev, "Failed to bypass PLL: %d\n", ret);
} else if (SND_SOC_DAPM_EVENT_ON(event)) {
ret = snd_soc_dai_set_pll(codec_dai, 0, DA7213_SYSCLK_PLL, 0,
pll_out);
if (ret)
dev_err(card->dev, "Failed to enable PLL: %d\n", ret);
}

return ret;
}

static int snd_rpi_iqaudio_post_dapm_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
{
switch (event) {
case SND_SOC_DAPM_POST_PMU:
/* Delay for mic bias ramp */
msleep(1000);
break;
default:
break;
}

return 0;
}

static const struct snd_soc_dapm_widget dapm_widgets[] = {
SND_SOC_DAPM_HP("HP Jack", NULL),
SND_SOC_DAPM_MIC("MIC Jack", NULL),
SND_SOC_DAPM_MIC("Onboard MIC", NULL),
SND_SOC_DAPM_LINE("AUX Jack", NULL),
SND_SOC_DAPM_SUPPLY("PLL Control", SND_SOC_NOPM, 0, 0,
snd_rpi_iqaudio_pll_control,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_POST("Post Power Up Event", snd_rpi_iqaudio_post_dapm_event),
};

static const struct snd_soc_dapm_route audio_map[] = {
{"HP Jack", NULL, "HPL"},
{"HP Jack", NULL, "HPR"},
{"HP Jack", NULL, "PLL Control"},

{"AUX Jack", NULL, "AUXR"},
{"AUX Jack", NULL, "AUXL"},
{"AUX Jack", NULL, "PLL Control"},

/* Assume Mic1 is linked to Headset and Mic2 to on-board mic */
{"MIC Jack", NULL, "MIC1"},
{"MIC Jack", NULL, "PLL Control"},
{"Onboard MIC", NULL, "MIC2"},
{"Onboard MIC", NULL, "PLL Control"},
};

/* machine stream operations */

static int snd_rpi_iqaudio_codec_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;

/* Set bclk ratio to align with codec's BCLK rate */
ret = snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
if (ret) {
dev_err(rtd->dev, "Failed to set CPU BLCK ratio\n");
return ret;
}

/* Set MCLK frequency to codec, onboard 11.2896MHz clock */
return snd_soc_dai_set_sysclk(codec_dai, DA7213_CLKSRC_MCLK, 11289600,
SND_SOC_CLOCK_OUT);
}

static int snd_rpi_iqaudio_codec_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
unsigned int samplerate = params_rate(params);

switch (samplerate) {
case 8000:
case 16000:
case 32000:
case 48000:
case 96000:
pll_out = DA7213_PLL_FREQ_OUT_98304000;
return 0;
case 44100:
case 88200:
pll_out = DA7213_PLL_FREQ_OUT_90316800;
return 0;
default:
dev_err(rtd->dev,"Unsupported samplerate %d\n", samplerate);
return -EINVAL;
}
}

static const struct snd_soc_ops snd_rpi_iqaudio_codec_ops = {
.hw_params = snd_rpi_iqaudio_codec_hw_params,
};


static struct snd_soc_dai_link snd_rpi_iqaudio_codec_dai[] = {
{
.cpu_dai_name = "bcm2708-i2s.0",
.codec_dai_name = "da7213-hifi",
.platform_name = "bmc2708-i2s.0",
.codec_name = "da7213.1-001a",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBM_CFM,
.init = snd_rpi_iqaudio_codec_init,
.ops = &snd_rpi_iqaudio_codec_ops,
.symmetric_rates = 1,
.symmetric_channels = 1,
.symmetric_samplebits = 1,
},
};

/* audio machine driver */
static struct snd_soc_card snd_rpi_iqaudio_codec = {
.owner = THIS_MODULE,
.dai_link = snd_rpi_iqaudio_codec_dai,
.num_links = ARRAY_SIZE(snd_rpi_iqaudio_codec_dai),
.dapm_widgets = dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(dapm_widgets),
.dapm_routes = audio_map,
.num_dapm_routes = ARRAY_SIZE(audio_map),
};

static int snd_rpi_iqaudio_codec_probe(struct platform_device *pdev)
{
int ret = 0;

snd_rpi_iqaudio_codec.dev = &pdev->dev;

if (pdev->dev.of_node) {
struct device_node *i2s_node;
struct snd_soc_card *card = &snd_rpi_iqaudio_codec;
struct snd_soc_dai_link *dai = &snd_rpi_iqaudio_codec_dai[0];

i2s_node = of_parse_phandle(pdev->dev.of_node,
"i2s-controller", 0);
if (i2s_node) {
dai->cpu_dai_name = NULL;
dai->cpu_of_node = i2s_node;
dai->platform_name = NULL;
dai->platform_of_node = i2s_node;
}

if (of_property_read_string(pdev->dev.of_node, "card_name",
&card->name))
card->name = "IQaudIOCODEC";

if (of_property_read_string(pdev->dev.of_node, "dai_name",
&dai->name))
dai->name = "IQaudIO CODEC";

if (of_property_read_string(pdev->dev.of_node,
"dai_stream_name", &dai->stream_name))
dai->stream_name = "IQaudIO CODEC HiFi v1.1";

}

ret = snd_soc_register_card(&snd_rpi_iqaudio_codec);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev,
"snd_soc_register_card() failed: %d\n", ret);
return ret;
}

return 0;
}

static int snd_rpi_iqaudio_codec_remove(struct platform_device *pdev)
{
return snd_soc_unregister_card(&snd_rpi_iqaudio_codec);
}

static const struct of_device_id iqaudio_of_match[] = {
{ .compatible = "iqaudio,iqaudio-codec", },
{},
};

MODULE_DEVICE_TABLE(of, iqaudio_of_match);

static struct platform_driver snd_rpi_iqaudio_codec_driver = {
.driver = {
.name = "snd-rpi-iqaudio-codec",
.owner = THIS_MODULE,
.of_match_table = iqaudio_of_match,
},
.probe = snd_rpi_iqaudio_codec_probe,
.remove = snd_rpi_iqaudio_codec_remove,
};



module_platform_driver(snd_rpi_iqaudio_codec_driver);

MODULE_AUTHOR("Gordon Garrity <[email protected]>");
MODULE_DESCRIPTION("ASoC Driver for IQaudIO CODEC");
MODULE_LICENSE("GPL v2");

0 comments on commit 328ae2c

Please sign in to comment.