FYI, here are my compiler errors:
<build-errors>
$ make -C ../../.. M=$PWD
make: Entering directory '/home/steve/code/compton-kernel'
CC [M] /home/steve/code/compton-kernel/drivers/compton/dep-imx8-i2s/dep_i2s.o
/home/steve/code/compton-kernel/drivers/compton/dep-imx8-i2s/dep_i2s.c:110:38: warning: 'struct snd_soc_codec' declared inside parameter list will not be visible outside of this definition or declaration
110 | static int codec_driver_probe(struct snd_soc_codec *codec)
| ^~~~~~~~~~~~~
In file included from ./include/linux/device.h:15,
from ./include/linux/platform_device.h:13,
from ./include/linux/of_device.h:5,
from /home/steve/code/compton-kernel/drivers/compton/dep-imx8-i2s/dep_i2s.c:7:
/home/steve/code/compton-kernel/drivers/compton/dep-imx8-i2s/dep_i2s.c: In function 'codec_driver_probe':
/home/steve/code/compton-kernel/drivers/compton/dep-imx8-i2s/dep_i2s.c:112:19: error: invalid use of undefined type 'struct snd_soc_codec'
112 | dev_info(codec->dev, "Entered %s", __func__);
| ^~
./include/linux/dev_printk.h:110:25: note: in definition of macro 'dev_printk_index_wrap'
110 | _p_func(dev, fmt, ##__VA_ARGS__); \
| ^~~
/home/steve/code/compton-kernel/drivers/compton/dep-imx8-i2s/dep_i2s.c:112:5: note: in expansion of macro 'dev_info'
112 | dev_info(codec->dev, "Entered %s", __func__);
| ^~~~~~~~
/home/steve/code/compton-kernel/drivers/compton/dep-imx8-i2s/dep_i2s.c: At top level:
/home/steve/code/compton-kernel/drivers/compton/dep-imx8-i2s/dep_i2s.c:116:21: error: variable 'codec_driver' has initializer but incomplete type
116 | static const struct snd_soc_codec_driver codec_driver = {
| ^~~~~~~~~~~~~~~~~~~~
/home/steve/code/compton-kernel/drivers/compton/dep-imx8-i2s/dep_i2s.c:117:6: error: 'const struct snd_soc_codec_driver' has no member named 'probe'
117 | .probe = codec_driver_probe,
| ^~~~~
/home/steve/code/compton-kernel/drivers/compton/dep-imx8-i2s/dep_i2s.c:117:14: warning: excess elements in struct initializer
117 | .probe = codec_driver_probe,
| ^~~~~~~~~~~~~~~~~~
/home/steve/code/compton-kernel/drivers/compton/dep-imx8-i2s/dep_i2s.c:117:14: note: (near initialization for 'codec_driver')
/home/steve/code/compton-kernel/drivers/compton/dep-imx8-i2s/dep_i2s.c:118:6: error: 'const struct snd_soc_codec_driver' has no member named 'component_driver'
118 | .component_driver = {
| ^~~~~~~~~~~~~~~~
/home/steve/code/compton-kernel/drivers/compton/dep-imx8-i2s/dep_i2s.c:118:25: error: extra brace group at end of initializer
118 | .component_driver = {
| ^
/home/steve/code/compton-kernel/drivers/compton/dep-imx8-i2s/dep_i2s.c:118:25: note: (near initialization for 'codec_driver')
/home/steve/code/compton-kernel/drivers/compton/dep-imx8-i2s/dep_i2s.c:118:25: warning: excess elements in struct initializer
/home/steve/code/compton-kernel/drivers/compton/dep-imx8-i2s/dep_i2s.c:118:25: note: (near initialization for 'codec_driver')
/home/steve/code/compton-kernel/drivers/compton/dep-imx8-i2s/dep_i2s.c: In function 'platform_driver_probe_':
/home/steve/code/compton-kernel/drivers/compton/dep-imx8-i2s/dep_i2s.c:153:12: error: implicit declaration of function 'snd_soc_register_codec'; did you mean 'snd_soc_register_dai'? [-Werror=implicit-function-declaration]
153 | stat = snd_soc_register_codec(&pdev->dev, &codec_driver, &dai_driver, 1);
| ^~~~~~~~~~~~~~~~~~~~~~
| snd_soc_register_dai
/home/steve/code/compton-kernel/drivers/compton/dep-imx8-i2s/dep_i2s.c: In function 'platform_driver_remove':
/home/steve/code/compton-kernel/drivers/compton/dep-imx8-i2s/dep_i2s.c:166:5: error: implicit declaration of function 'snd_soc_unregister_codec'; did you mean 'snd_soc_unregister_dai'? [-Werror=implicit-function-declaration]
166 | snd_soc_unregister_codec(&pdev->dev);
| ^~~~~~~~~~~~~~~~~~~~~~~~
| snd_soc_unregister_dai
/home/steve/code/compton-kernel/drivers/compton/dep-imx8-i2s/dep_i2s.c: At top level:
/home/steve/code/compton-kernel/drivers/compton/dep-imx8-i2s/dep_i2s.c:116:42: error: storage size of 'codec_driver' isn't known
116 | static const struct snd_soc_codec_driver codec_driver = {
| ^~~~~~~~~~~~
cc1: some warnings being treated as errors
make[2]: *** [scripts/Makefile.build:243: /home/steve/code/compton-kernel/drivers/compton/dep-imx8-i2s/dep_i2s.o] Error 1
make[1]: *** [/home/steve/code/compton-kernel/Makefile:1921: /home/steve/code/compton-kernel/drivers/compton/dep-imx8-i2s] Error 2
make: *** [Makefile:234: __sub-make] Error 2
make: Leaving directory '/home/steve/code/compton-kernel'
</build-errors>
My code (for 4.14 kernel)
---------------------------------
Here's my driver code. The macro INCLUDE_PROBLEMATIC_CODE is used around each chuck that fails to compile. If not defined, the code does compile, but of course is missing important parts.
<my-code>
#define INCLUDE_PROBLEMATIC_CODE
/*
* Audindate Dante Embedded Platform (DEP) I2S Codec (ALSA SoC) driver; Linux module
* Supports sample rates, bit depths and TDM modes for Dante devices.
*/
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/clk.h>
#include <sound/soc.h>
#include <sound/pcm.h>
#include <linux/printk.h>
#define DEP_I2S_PCM_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \
SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000)
#define DEP_I2S_PCM_FORMATS ( SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE )
// for future use
struct instance_state {
unsigned int dummy_holder;
};
static const struct snd_soc_dapm_widget widgets[] = {
SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_OUTPUT("LINEVOUT"),
SND_SOC_DAPM_INPUT("LINEVIN"),
};
static const struct snd_soc_dapm_route routes[] = {
{ "LINEVOUT", NULL, "DAC" },
{ "ADC", NULL, "LINEVIN" },
};
static int set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
// supported
break;
case SND_SOC_DAIFMT_LEFT_J:
// supported
break;
default:
// all other formats unsupported
dev_err(dai->dev, "Invalid DAI format: DEP I2S only supports left justified and I2S, got 0x%04X", fmt);
return -EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
// codec as bit master and frame master (or external clock generator)
// note that jumpers on DEP-EVK-IMX8 must be set correctly
case SND_SOC_DAIFMT_CBM_CFM:
// supported
break;
// codec as bit slave and frame slave (ie clocks driven from SOC)
case SND_SOC_DAIFMT_CBS_CFS:
// supported
break;
default:
// all others unsupported
dev_err(dai->dev, "Invalid DAI format: DEP I2S only supports CODEC as bit and frame clock master, got 0x%04X", fmt);
return -EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
default:
// support bit and frame inversion
break;
}
dev_info(dai->dev, "Set fmt to %u", fmt);
return 0;
}
static struct snd_soc_dai_ops dep_i2s_dai_ops = {
.set_fmt = set_fmt,
// add mute here
};
struct snd_soc_dai_driver dai_driver = {
.name = "dep-i2s",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 16,
.rate_min = 44100,
.rate_max = 192000,
.rates = DEP_I2S_PCM_RATES,
.formats = DEP_I2S_PCM_FORMATS,
},
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 16,
.rate_min = 44100,
.rate_max = 192000,
.rates = DEP_I2S_PCM_RATES,
.formats = DEP_I2S_PCM_FORMATS,
},
.ops = &dep_i2s_dai_ops,
.symmetric_rate = 1,
};
#ifdef INCLUDE_PROBLEMATIC_CODE
// Dummy probe
static int codec_driver_probe(struct snd_soc_codec *codec)
{
dev_info(codec->dev, "Entered %s", __func__);
return 0;
}
static const struct snd_soc_codec_driver codec_driver = {
.probe = codec_driver_probe,
.component_driver = {
.dapm_widgets = widgets,
.num_dapm_widgets = ARRAY_SIZE(widgets),
.dapm_routes = routes,
.num_dapm_routes = ARRAY_SIZE(routes),
},
};
#endif
#if defined(CONFIG_OF)
static const struct of_device_id match_table[] = {
{.compatible = "audinate,dep_i2s"},
{}
};
MODULE_DEVICE_TABLE(of, match_table);
#endif
static int platform_driver_probe_(struct platform_device *pdev)
{
dev_info(&pdev->dev, "Entered %s", __func__);
int stat = 0;
struct instance_state *instance_state = devm_kzalloc(&pdev->dev, sizeof(struct instance_state), GFP_KERNEL);
if (instance_state == NULL) {
return -ENOMEM;
}
platform_set_drvdata(pdev, instance_state);
dev_info(&pdev->dev, "Codec probe pt 2");
#ifdef INCLUDE_PROBLEMATIC_CODE
// 1 == number of DAIs, might need to be 2 for dual direction, or for 2* sai?
stat = snd_soc_register_codec(&pdev->dev, &codec_driver, &dai_driver, 1);
if (stat < 0) {
dev_err(&pdev->dev, "Failed to register codec: %d", stat);
}
#endif
return stat;
}
static int platform_driver_remove(struct platform_device *pdev)
{
dev_info(&pdev->dev, "Entered %s", __func__);
#ifdef INCLUDE_PROBLEMATIC_CODE
snd_soc_unregister_codec(&pdev->dev);
#endif
return 0;
}
static struct platform_driver platform_driver = {
.probe = platform_driver_probe_,
.remove = platform_driver_remove,
.driver = {
.name = "dep-i2s-codec",
.of_match_table = of_match_ptr(match_table),
},
};
module_platform_driver(platform_driver);
MODULE_DESCRIPTION("Audinate DEP generic I2S ASoC codec");
MODULE_AUTHOR("James Stuart <opensource@xxxxxxxxxxxx>");
MODULE_ALIAS("platform:dep-i2s-codec");
MODULE_LICENSE("GPL");
</my-code>
Steve Broshar
Palmer Wireless Medtech