Skip to content

Commit 784ef64

Browse files
j-schambacherpelwell
authored andcommitted
ASoC: add driver for new HiFiBerry ADC only board(s)
Adds the driver for the soon to be released first ADC only board. It includes the same ADC controls as used by the DAC+ADC Pro driver. Signed-off-by: j-schambacher <[email protected]>
1 parent 3d21dab commit 784ef64

File tree

3 files changed

+183
-0
lines changed

3 files changed

+183
-0
lines changed

sound/soc/bcm/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ config SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD
3939
help
4040
Say Y or M if you want to add support for voiceHAT soundcard.
4141

42+
config SND_BCM2708_SOC_HIFIBERRY_ADC
43+
tristate "Support for HifiBerry ADC"
44+
select SND_SOC_PCM186X_I2C
45+
select SND_RPI_HIFIBERRY_ADC
46+
help
47+
Say Y or M if you want to add support for HifiBerry ADC.
48+
4249
config SND_BCM2708_SOC_HIFIBERRY_DAC
4350
tristate "Support for HifiBerry DAC and DAC8X"
4451
select SND_SOC_PCM5102A

sound/soc/bcm/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ obj-$(CONFIG_SND_BCM63XX_I2S_WHISTLER) += snd-soc-63xx.o
1818
snd-soc-googlevoicehat-codec-objs := googlevoicehat-codec.o
1919

2020
# BCM2708 Machine Support
21+
snd-soc-hifiberry-adc-objs := hifiberry_adc.o
2122
snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o
2223
snd-soc-hifiberry-dacplushd-objs := hifiberry_dacplushd.o
2324
snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o
@@ -51,6 +52,7 @@ snd-soc-chipdip-dac-objs := chipdip-dac.o
5152
snd-soc-dacberry400-objs := dacberry400.o
5253

5354
obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD) += snd-soc-googlevoicehat-codec.o
55+
obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_ADC) += snd-soc-hifiberry-adc.o
5456
obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
5557
obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD) += snd-soc-hifiberry-dacplushd.o
5658
obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o

sound/soc/bcm/hifiberry_adc.c

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* ASoC Driver for HiFiBerry ADC
4+
*
5+
* Author: Joerg Schambacher <[email protected]>
6+
* Copyright 2024
7+
*
8+
* This program is free software; you can redistribute it and/or
9+
* modify it under the terms of the GNU General Public License
10+
* version 2 as published by the Free Software Foundation.
11+
*
12+
* This program is distributed in the hope that it will be useful, but
13+
* WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15+
* General Public License for more details.
16+
*/
17+
18+
#include <linux/module.h>
19+
#include <linux/platform_device.h>
20+
#include <linux/kernel.h>
21+
#include <linux/clk.h>
22+
#include <linux/kernel.h>
23+
#include <linux/module.h>
24+
#include <linux/of.h>
25+
#include <linux/slab.h>
26+
#include <linux/delay.h>
27+
#include <linux/i2c.h>
28+
29+
#include <sound/core.h>
30+
#include <sound/pcm.h>
31+
#include <sound/pcm_params.h>
32+
#include <sound/soc.h>
33+
#include <sound/jack.h>
34+
#include <sound/tlv.h>
35+
36+
#include "../codecs/pcm186x.h"
37+
#include "hifiberry_adc_controls.h"
38+
39+
static bool leds_off;
40+
41+
static int pcm1863_add_controls(struct snd_soc_component *component)
42+
{
43+
snd_soc_add_component_controls(component,
44+
pcm1863_snd_controls_card,
45+
ARRAY_SIZE(pcm1863_snd_controls_card));
46+
return 0;
47+
}
48+
49+
static int snd_rpi_hifiberry_adc_init(struct snd_soc_pcm_runtime *rtd)
50+
{
51+
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
52+
struct snd_soc_component *adc = codec_dai->component;
53+
int ret;
54+
55+
ret = pcm1863_add_controls(adc);
56+
if (ret < 0)
57+
dev_warn(rtd->dev, "Failed to add pcm1863 controls: %d\n",
58+
ret);
59+
60+
codec_dai->driver->capture.rates =
61+
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
62+
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
63+
SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000;
64+
65+
/* set GPIO2 to output, GPIO3 input */
66+
snd_soc_component_write(adc, PCM186X_GPIO3_2_CTRL, 0x00);
67+
snd_soc_component_write(adc, PCM186X_GPIO3_2_DIR_CTRL, 0x04);
68+
if (leds_off)
69+
snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x00);
70+
else
71+
snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x40);
72+
73+
return 0;
74+
}
75+
76+
static int snd_rpi_hifiberry_adc_hw_params(
77+
struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
78+
{
79+
int ret = 0;
80+
struct snd_soc_pcm_runtime *rtd = substream->private_data;
81+
int channels = params_channels(params);
82+
int width = snd_pcm_format_width(params_format(params));
83+
84+
/* Using powers of 2 allows for an integer clock divisor */
85+
width = width <= 16 ? 16 : 32;
86+
87+
ret = snd_soc_dai_set_bclk_ratio(asoc_rtd_to_cpu(rtd, 0), channels * width);
88+
return ret;
89+
}
90+
91+
/* machine stream operations */
92+
static const struct snd_soc_ops snd_rpi_hifiberry_adc_ops = {
93+
.hw_params = snd_rpi_hifiberry_adc_hw_params,
94+
};
95+
96+
SND_SOC_DAILINK_DEFS(hifi,
97+
DAILINK_COMP_ARRAY(COMP_CPU("bcm2708-i2s.0")),
98+
DAILINK_COMP_ARRAY(COMP_CODEC("pcm186x.1-004a", "pcm1863-aif")),
99+
DAILINK_COMP_ARRAY(COMP_PLATFORM("bcm2708-i2s.0")));
100+
101+
static struct snd_soc_dai_link snd_rpi_hifiberry_adc_dai[] = {
102+
{
103+
.name = "HiFiBerry ADC",
104+
.stream_name = "HiFiBerry ADC HiFi",
105+
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
106+
SND_SOC_DAIFMT_CBS_CFS,
107+
.ops = &snd_rpi_hifiberry_adc_ops,
108+
.init = snd_rpi_hifiberry_adc_init,
109+
SND_SOC_DAILINK_REG(hifi),
110+
},
111+
};
112+
113+
/* audio machine driver */
114+
static struct snd_soc_card snd_rpi_hifiberry_adc = {
115+
.name = "snd_rpi_hifiberry_adc",
116+
.driver_name = "HifiberryAdc",
117+
.owner = THIS_MODULE,
118+
.dai_link = snd_rpi_hifiberry_adc_dai,
119+
.num_links = ARRAY_SIZE(snd_rpi_hifiberry_adc_dai),
120+
};
121+
122+
static int snd_rpi_hifiberry_adc_probe(struct platform_device *pdev)
123+
{
124+
int ret = 0, i = 0;
125+
struct snd_soc_card *card = &snd_rpi_hifiberry_adc;
126+
127+
snd_rpi_hifiberry_adc.dev = &pdev->dev;
128+
if (pdev->dev.of_node) {
129+
struct device_node *i2s_node;
130+
struct snd_soc_dai_link *dai;
131+
132+
dai = &snd_rpi_hifiberry_adc_dai[0];
133+
i2s_node = of_parse_phandle(pdev->dev.of_node,
134+
"i2s-controller", 0);
135+
if (i2s_node) {
136+
for (i = 0; i < card->num_links; i++) {
137+
dai->cpus->dai_name = NULL;
138+
dai->cpus->of_node = i2s_node;
139+
dai->platforms->name = NULL;
140+
dai->platforms->of_node = i2s_node;
141+
}
142+
}
143+
}
144+
leds_off = of_property_read_bool(pdev->dev.of_node,
145+
"hifiberry-adc,leds_off");
146+
ret = snd_soc_register_card(&snd_rpi_hifiberry_adc);
147+
if (ret && ret != -EPROBE_DEFER)
148+
dev_err(&pdev->dev,
149+
"snd_soc_register_card() failed: %d\n", ret);
150+
151+
return ret;
152+
}
153+
154+
static const struct of_device_id snd_rpi_hifiberry_adc_of_match[] = {
155+
{ .compatible = "hifiberry,hifiberry-adc", },
156+
{},
157+
};
158+
159+
MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_adc_of_match);
160+
161+
static struct platform_driver snd_rpi_hifiberry_adc_driver = {
162+
.driver = {
163+
.name = "snd-rpi-hifiberry-adc",
164+
.owner = THIS_MODULE,
165+
.of_match_table = snd_rpi_hifiberry_adc_of_match,
166+
},
167+
.probe = snd_rpi_hifiberry_adc_probe,
168+
};
169+
170+
module_platform_driver(snd_rpi_hifiberry_adc_driver);
171+
172+
MODULE_AUTHOR("Joerg Schambacher <[email protected]>");
173+
MODULE_DESCRIPTION("ASoC Driver for HiFiBerry ADC");
174+
MODULE_LICENSE("GPL");

0 commit comments

Comments
 (0)