1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
3 // Copyright (c) 2020 BayLibre, SAS.
4 // Author: Jerome Brunet <jbrunet@baylibre.com>
6 #include <linux/module.h>
7 #include <linux/of_platform.h>
9 #include <sound/soc-dai.h>
11 #include "meson-card.h"
13 struct gx_dai_link_i2s_data
{
18 * Base params for the codec to codec links
19 * Those will be over-written by the CPU side of the link
21 static const struct snd_soc_pcm_stream codec_params
= {
22 .formats
= SNDRV_PCM_FMTBIT_S24_LE
,
29 static int gx_card_i2s_be_hw_params(struct snd_pcm_substream
*substream
,
30 struct snd_pcm_hw_params
*params
)
32 struct snd_soc_pcm_runtime
*rtd
= asoc_substream_to_rtd(substream
);
33 struct meson_card
*priv
= snd_soc_card_get_drvdata(rtd
->card
);
34 struct gx_dai_link_i2s_data
*be
=
35 (struct gx_dai_link_i2s_data
*)priv
->link_data
[rtd
->num
];
37 return meson_card_i2s_set_sysclk(substream
, params
, be
->mclk_fs
);
40 static const struct snd_soc_ops gx_card_i2s_be_ops
= {
41 .hw_params
= gx_card_i2s_be_hw_params
,
44 static int gx_card_parse_i2s(struct snd_soc_card
*card
,
45 struct device_node
*node
,
48 struct meson_card
*priv
= snd_soc_card_get_drvdata(card
);
49 struct snd_soc_dai_link
*link
= &card
->dai_link
[*index
];
50 struct gx_dai_link_i2s_data
*be
;
52 /* Allocate i2s link parameters */
53 be
= devm_kzalloc(card
->dev
, sizeof(*be
), GFP_KERNEL
);
56 priv
->link_data
[*index
] = be
;
59 link
->ops
= &gx_card_i2s_be_ops
;
60 link
->dai_fmt
= meson_card_parse_daifmt(node
, link
->cpus
->of_node
);
62 of_property_read_u32(node
, "mclk-fs", &be
->mclk_fs
);
67 static int gx_card_cpu_identify(struct snd_soc_dai_link_component
*c
,
70 if (of_device_is_compatible(c
->of_node
, DT_PREFIX
"aiu")) {
71 if (strstr(c
->dai_name
, match
))
79 static int gx_card_add_link(struct snd_soc_card
*card
, struct device_node
*np
,
82 struct snd_soc_dai_link
*dai_link
= &card
->dai_link
[*index
];
83 struct snd_soc_dai_link_component
*cpu
;
86 cpu
= devm_kzalloc(card
->dev
, sizeof(*cpu
), GFP_KERNEL
);
91 dai_link
->num_cpus
= 1;
93 ret
= meson_card_parse_dai(card
, np
, &dai_link
->cpus
->of_node
,
94 &dai_link
->cpus
->dai_name
);
98 if (gx_card_cpu_identify(dai_link
->cpus
, "FIFO"))
99 return meson_card_set_fe_link(card
, dai_link
, np
, true);
101 ret
= meson_card_set_be_link(card
, dai_link
, np
);
105 /* Or apply codec to codec params if necessary */
106 if (gx_card_cpu_identify(dai_link
->cpus
, "CODEC CTRL")) {
107 dai_link
->params
= &codec_params
;
109 dai_link
->no_pcm
= 1;
110 snd_soc_dai_link_set_capabilities(dai_link
);
111 /* Check if the cpu is the i2s encoder and parse i2s data */
112 if (gx_card_cpu_identify(dai_link
->cpus
, "I2S Encoder"))
113 ret
= gx_card_parse_i2s(card
, np
, index
);
119 static const struct meson_card_match_data gx_card_match_data
= {
120 .add_link
= gx_card_add_link
,
123 static const struct of_device_id gx_card_of_match
[] = {
125 .compatible
= "amlogic,gx-sound-card",
126 .data
= &gx_card_match_data
,
129 MODULE_DEVICE_TABLE(of
, gx_card_of_match
);
131 static struct platform_driver gx_card_pdrv
= {
132 .probe
= meson_card_probe
,
133 .remove
= meson_card_remove
,
135 .name
= "gx-sound-card",
136 .of_match_table
= gx_card_of_match
,
139 module_platform_driver(gx_card_pdrv
);
141 MODULE_DESCRIPTION("Amlogic GX ALSA machine driver");
142 MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
143 MODULE_LICENSE("GPL v2");