#include #include #include #include #include #include #include #include #include #include #include #include #include #include "pcm1863.h" struct pcm1863_priv { struct regmap *regmap; int rate; int fmt; }; static const struct snd_kcontrol_new pcm1863_controls[] = { SOC_SINGLE("ADC MUX VIN4L", PCM1863_ADC1_INPUT_SEL_L, //not possible with SOC_DOUBLE since PCM1863_SEL_L_VIN4, 1, 0), //two different register? SOC_SINGLE("ADC MUX VIN4R", PCM1863_ADC1_INPUT_SEL_R, PCM1863_SEL_R_VIN4, 1, 0), }; static const struct snd_soc_dapm_widget pcm1863_dapm_widgets[] = { SND_SOC_DAPM_ADC("ADC1", NULL, SND_SOC_NOPM, 0, 0), // ("ADC1", "Capture", SND_SOC_NOPM, 0, 0) another possibility? SND_SOC_DAPM_INPUT("SE_IN_L"), SND_SOC_DAPM_INPUT("SE_IN_R"), }; static const struct snd_soc_dapm_route pcm1863_dapm_routes[] = { { "ADC1", NULL, "SE_IN_L" }, { "ADC1", NULL, "SE_IN_R" }, { "SE_IN_L", NULL, "Capture" }, //this would be obsolete if Capture stream { "SE_IN_R", NULL, "Capture" }, //could be in the adc definition }; static struct snd_soc_codec_driver soc_codec_dev_pcm1863 = { .component_driver = { .controls = pcm1863_controls, .num_controls = ARRAY_SIZE(pcm1863_controls), .dapm_widgets = pcm1863_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(pcm1863_dapm_widgets), .dapm_routes = pcm1863_dapm_routes, .num_dapm_routes = ARRAY_SIZE(pcm1863_dapm_routes), }, }; static int pcm1863_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct snd_soc_codec *codec = dai->codec; struct pcm1863_priv *priv = snd_soc_codec_get_drvdata(codec); priv->fmt = fmt; return 0; } static int pcm1863_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; struct pcm1863_priv *pcm1863 = snd_soc_codec_get_drvdata(codec); int rxlen; int txlen; int divider; int ret; dev_dbg(codec->dev, "hw_params %u Hz, %u channels\n", params_rate(params), params_channels(params)); switch (params_width(params)) { case 16: rxlen = PCM1863_RX_WLEN_16; txlen = PCM1863_TX_WLEN_16; break; case 20: rxlen = PCM1863_RX_WLEN_20; txlen = PCM1863_TX_WLEN_20; break; case 24: rxlen = PCM1863_RX_WLEN_24; txlen = PCM1863_TX_WLEN_24; break; default: dev_err(codec->dev, "Bad frame size: %d\n", params_width(params)); return -EINVAL; } switch (pcm1863->fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: //maybe not possible because it seems like the bck is only an output ret = regmap_update_bits(pcm1863->regmap, PCM1863_CLK_SRC, PCM1863_MST_MODE, 0); ret = regmap_update_bits(pcm1863->regmap, PCM1863_CLK_SRC, PCM1863_MST_SCK_SRC, 1); if (ret != 0) { dev_err(codec->dev, "Failed to enable slave mode: %d\n", ret); return ret; } ret = regmap_update_bits(pcm1863->regmap, PCM1863_CLK_SRC, PCM1863_CLKDET_EN, 1); if (ret != 0) { dev_err(codec->dev, "Failed to enable clock divider autoset: %d\n", ret); return ret; } case SND_SOC_DAIFMT_CBM_CFM: ret = regmap_update_bits(pcm1863->regmap, PCM1863_CLK_SRC, PCM1863_MST_MODE, 1); ret = regmap_update_bits(pcm1863->regmap, PCM1863_CLK_SRC, PCM1863_MST_SCK_SRC, 0); if (ret != 0) { dev_err(codec->dev, "Failed to enable master mode: %d\n", ret); return ret; } default: return -EINVAL; } ret = regmap_update_bits(pcm1863->regmap, PCM1863_FMT_REG, PCM1863_RX_WLEN, rxlen); ret = regmap_update_bits(pcm1863->regmap, PCM1863_FMT_REG, PCM1863_TX_WLEN, txlen); switch (pcm1863->rate) { case 44100: case 48000: divider = PCM1863_DIV_NUM_18; case 88200: case 96000: divider = PCM1863_DIV_NUM_14; case 192000: divider = PCM1863_DIV_NUM_12; default: return -EINVAL; } ret = regmap_update_bits(pcm1863->regmap, PCM1863_SCK_DIV, PCM1863_DIV_NUM, divider); return 0; } static const struct snd_soc_dai_ops pcm1863_dai_ops = { .hw_params = pcm1863_hw_params, .set_fmt = pcm1863_set_fmt, }; static struct snd_soc_dai_driver pcm1863_dai = { .name = "pcm1863", .capture = { .stream_name = "Capture", .channels_min = 2, .channels_max = 2, .rates = SNDRV_PCM_RATE_CONTINUOUS, .rate_min = 8000, .rate_max = 384000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE }, .ops = &pcm1863_dai_ops, }; static const struct regmap_range_cfg pcm1863_range = { .name = "Pages", .range_min = 0x000, .range_max = 0xFD00, .selector_reg = 0, .selector_mask = 0xff, .window_start = 0, .window_len = 0x100, }; const struct regmap_config pcm1863_regmap = { .reg_bits = 8, .val_bits = 8, .ranges = &pcm1863_range, .num_ranges = 1, .max_register = 0xFD00, .cache_type = REGCACHE_RBTREE, }; EXPORT_SYMBOL_GPL(pcm1863_regmap); int pcm1863_probe(struct device *dev, struct regmap *regmap) { int ret; struct pcm1863_priv *pcm1863; if (IS_ERR(regmap)) return PTR_ERR(regmap); pcm1863 = devm_kzalloc(dev, sizeof(*pcm1863), GFP_KERNEL); if (pcm1863 == NULL) return -ENOMEM; pcm1863->regmap = regmap; dev_set_drvdata(dev, pcm1863); ret = snd_soc_register_codec(dev, &soc_codec_dev_pcm1863, &pcm1863_dai, 1); return ret; } EXPORT_SYMBOL_GPL(pcm1863_probe); void pcm1863_remove(struct device *dev) { snd_soc_unregister_codec(dev); } EXPORT_SYMBOL_GPL(pcm1863_remove); MODULE_DESCRIPTION("ASoC pcm1863 driver"); MODULE_AUTHOR("Dummy Name "); MODULE_LICENSE("GPL v2");