1 // SPDX-License-Identifier: GPL-2.0
3 // Copyright (c) 2020 BayLibre, SAS.
4 // Author: Jerome Brunet <jbrunet@baylibre.com>
6 #include <linux/bitfield.h>
8 #include <linux/module.h>
9 #include <linux/of_platform.h>
10 #include <linux/regmap.h>
11 #include <linux/reset.h>
12 #include <sound/soc.h>
13 #include <sound/soc-dai.h>
15 #include <dt-bindings/sound/meson-aiu.h>
19 #define AIU_I2S_MISC_958_SRC_SHIFT 3
21 static const char * const aiu_spdif_encode_sel_texts
[] = {
25 static SOC_ENUM_SINGLE_DECL(aiu_spdif_encode_sel_enum
, AIU_I2S_MISC
,
26 AIU_I2S_MISC_958_SRC_SHIFT
,
27 aiu_spdif_encode_sel_texts
);
29 static const struct snd_kcontrol_new aiu_spdif_encode_mux
=
30 SOC_DAPM_ENUM("SPDIF Buffer Src", aiu_spdif_encode_sel_enum
);
32 static const struct snd_soc_dapm_widget aiu_cpu_dapm_widgets
[] = {
33 SND_SOC_DAPM_MUX("SPDIF SRC SEL", SND_SOC_NOPM
, 0, 0,
34 &aiu_spdif_encode_mux
),
37 static const struct snd_soc_dapm_route aiu_cpu_dapm_routes
[] = {
38 { "I2S Encoder Playback", NULL
, "I2S FIFO Playback" },
39 { "SPDIF SRC SEL", "SPDIF", "SPDIF FIFO Playback" },
40 { "SPDIF SRC SEL", "I2S", "I2S FIFO Playback" },
41 { "SPDIF Encoder Playback", NULL
, "SPDIF SRC SEL" },
44 int aiu_of_xlate_dai_name(struct snd_soc_component
*component
,
45 struct of_phandle_args
*args
,
46 const char **dai_name
,
47 unsigned int component_id
)
49 struct snd_soc_dai
*dai
;
52 if (args
->args_count
!= 2)
55 if (args
->args
[0] != component_id
)
60 if (id
< 0 || id
>= component
->num_dai
)
63 for_each_component_dais(component
, dai
) {
69 *dai_name
= dai
->driver
->name
;
74 static int aiu_cpu_of_xlate_dai_name(struct snd_soc_component
*component
,
75 struct of_phandle_args
*args
,
76 const char **dai_name
)
78 return aiu_of_xlate_dai_name(component
, args
, dai_name
, AIU_CPU
);
81 static int aiu_cpu_component_probe(struct snd_soc_component
*component
)
83 struct aiu
*aiu
= snd_soc_component_get_drvdata(component
);
85 /* Required for the SPDIF Source control operation */
86 return clk_prepare_enable(aiu
->i2s
.clks
[PCLK
].clk
);
89 static void aiu_cpu_component_remove(struct snd_soc_component
*component
)
91 struct aiu
*aiu
= snd_soc_component_get_drvdata(component
);
93 clk_disable_unprepare(aiu
->i2s
.clks
[PCLK
].clk
);
96 static const struct snd_soc_component_driver aiu_cpu_component
= {
98 .dapm_widgets
= aiu_cpu_dapm_widgets
,
99 .num_dapm_widgets
= ARRAY_SIZE(aiu_cpu_dapm_widgets
),
100 .dapm_routes
= aiu_cpu_dapm_routes
,
101 .num_dapm_routes
= ARRAY_SIZE(aiu_cpu_dapm_routes
),
102 .of_xlate_dai_name
= aiu_cpu_of_xlate_dai_name
,
103 .pointer
= aiu_fifo_pointer
,
104 .probe
= aiu_cpu_component_probe
,
105 .remove
= aiu_cpu_component_remove
,
108 static struct snd_soc_dai_driver aiu_cpu_dai_drv
[] = {
112 .stream_name
= "I2S FIFO Playback",
115 .rates
= SNDRV_PCM_RATE_CONTINUOUS
,
118 .formats
= AIU_FORMATS
,
120 .ops
= &aiu_fifo_i2s_dai_ops
,
121 .pcm_new
= aiu_fifo_pcm_new
,
122 .probe
= aiu_fifo_i2s_dai_probe
,
123 .remove
= aiu_fifo_dai_remove
,
126 .name
= "SPDIF FIFO",
128 .stream_name
= "SPDIF FIFO Playback",
131 .rates
= SNDRV_PCM_RATE_CONTINUOUS
,
134 .formats
= AIU_FORMATS
,
136 .ops
= &aiu_fifo_spdif_dai_ops
,
137 .pcm_new
= aiu_fifo_pcm_new
,
138 .probe
= aiu_fifo_spdif_dai_probe
,
139 .remove
= aiu_fifo_dai_remove
,
141 [CPU_I2S_ENCODER
] = {
142 .name
= "I2S Encoder",
144 .stream_name
= "I2S Encoder Playback",
147 .rates
= SNDRV_PCM_RATE_8000_192000
,
148 .formats
= AIU_FORMATS
,
150 .ops
= &aiu_encoder_i2s_dai_ops
,
152 [CPU_SPDIF_ENCODER
] = {
153 .name
= "SPDIF Encoder",
155 .stream_name
= "SPDIF Encoder Playback",
158 .rates
= (SNDRV_PCM_RATE_32000
|
159 SNDRV_PCM_RATE_44100
|
160 SNDRV_PCM_RATE_48000
|
161 SNDRV_PCM_RATE_88200
|
162 SNDRV_PCM_RATE_96000
|
163 SNDRV_PCM_RATE_176400
|
164 SNDRV_PCM_RATE_192000
),
165 .formats
= AIU_FORMATS
,
167 .ops
= &aiu_encoder_spdif_dai_ops
,
171 static const struct regmap_config aiu_regmap_cfg
= {
175 .max_register
= 0x2ac,
178 static int aiu_clk_bulk_get(struct device
*dev
,
179 const char * const *ids
,
181 struct aiu_interface
*interface
)
183 struct clk_bulk_data
*clks
;
186 clks
= devm_kcalloc(dev
, num
, sizeof(*clks
), GFP_KERNEL
);
190 for (i
= 0; i
< num
; i
++)
193 ret
= devm_clk_bulk_get(dev
, num
, clks
);
197 interface
->clks
= clks
;
198 interface
->clk_num
= num
;
202 static const char * const aiu_i2s_ids
[] = {
204 [AOCLK
] = "i2s_aoclk",
206 [MIXER
] = "i2s_mixer",
209 static const char * const aiu_spdif_ids
[] = {
210 [PCLK
] = "spdif_pclk",
211 [AOCLK
] = "spdif_aoclk",
212 [MCLK
] = "spdif_mclk_sel"
215 static int aiu_clk_get(struct device
*dev
)
217 struct aiu
*aiu
= dev_get_drvdata(dev
);
220 aiu
->pclk
= devm_clk_get(dev
, "pclk");
221 if (IS_ERR(aiu
->pclk
)) {
222 if (PTR_ERR(aiu
->pclk
) != -EPROBE_DEFER
)
223 dev_err(dev
, "Can't get the aiu pclk\n");
224 return PTR_ERR(aiu
->pclk
);
227 aiu
->spdif_mclk
= devm_clk_get(dev
, "spdif_mclk");
228 if (IS_ERR(aiu
->spdif_mclk
)) {
229 if (PTR_ERR(aiu
->spdif_mclk
) != -EPROBE_DEFER
)
230 dev_err(dev
, "Can't get the aiu spdif master clock\n");
231 return PTR_ERR(aiu
->spdif_mclk
);
234 ret
= aiu_clk_bulk_get(dev
, aiu_i2s_ids
, ARRAY_SIZE(aiu_i2s_ids
),
237 if (ret
!= -EPROBE_DEFER
)
238 dev_err(dev
, "Can't get the i2s clocks\n");
242 ret
= aiu_clk_bulk_get(dev
, aiu_spdif_ids
, ARRAY_SIZE(aiu_spdif_ids
),
245 if (ret
!= -EPROBE_DEFER
)
246 dev_err(dev
, "Can't get the spdif clocks\n");
250 ret
= clk_prepare_enable(aiu
->pclk
);
252 dev_err(dev
, "peripheral clock enable failed\n");
256 ret
= devm_add_action_or_reset(dev
,
257 (void(*)(void *))clk_disable_unprepare
,
260 dev_err(dev
, "failed to add reset action on pclk");
265 static int aiu_probe(struct platform_device
*pdev
)
267 struct device
*dev
= &pdev
->dev
;
273 aiu
= devm_kzalloc(dev
, sizeof(*aiu
), GFP_KERNEL
);
277 aiu
->platform
= device_get_match_data(dev
);
281 platform_set_drvdata(pdev
, aiu
);
283 ret
= device_reset(dev
);
285 if (ret
!= -EPROBE_DEFER
)
286 dev_err(dev
, "Failed to reset device\n");
290 regs
= devm_platform_ioremap_resource(pdev
, 0);
292 return PTR_ERR(regs
);
294 map
= devm_regmap_init_mmio(dev
, regs
, &aiu_regmap_cfg
);
296 dev_err(dev
, "failed to init regmap: %ld\n",
301 aiu
->i2s
.irq
= platform_get_irq_byname(pdev
, "i2s");
302 if (aiu
->i2s
.irq
< 0)
305 aiu
->spdif
.irq
= platform_get_irq_byname(pdev
, "spdif");
306 if (aiu
->spdif
.irq
< 0)
307 return aiu
->spdif
.irq
;
309 ret
= aiu_clk_get(dev
);
313 /* Register the cpu component of the aiu */
314 ret
= snd_soc_register_component(dev
, &aiu_cpu_component
,
316 ARRAY_SIZE(aiu_cpu_dai_drv
));
318 dev_err(dev
, "Failed to register cpu component\n");
322 /* Register the hdmi codec control component */
323 ret
= aiu_hdmi_ctrl_register_component(dev
);
325 dev_err(dev
, "Failed to register hdmi control component\n");
329 /* Register the internal dac control component on gxl */
330 if (aiu
->platform
->has_acodec
) {
331 ret
= aiu_acodec_ctrl_register_component(dev
);
334 "Failed to register acodec control component\n");
341 snd_soc_unregister_component(dev
);
345 static int aiu_remove(struct platform_device
*pdev
)
347 snd_soc_unregister_component(&pdev
->dev
);
352 static const struct aiu_platform_data aiu_gxbb_pdata
= {
354 .has_clk_ctrl_more_i2s_div
= true,
357 static const struct aiu_platform_data aiu_gxl_pdata
= {
359 .has_clk_ctrl_more_i2s_div
= true,
362 static const struct aiu_platform_data aiu_meson8_pdata
= {
364 .has_clk_ctrl_more_i2s_div
= false,
367 static const struct of_device_id aiu_of_match
[] = {
368 { .compatible
= "amlogic,aiu-gxbb", .data
= &aiu_gxbb_pdata
},
369 { .compatible
= "amlogic,aiu-gxl", .data
= &aiu_gxl_pdata
},
370 { .compatible
= "amlogic,aiu-meson8", .data
= &aiu_meson8_pdata
},
371 { .compatible
= "amlogic,aiu-meson8b", .data
= &aiu_meson8_pdata
},
374 MODULE_DEVICE_TABLE(of
, aiu_of_match
);
376 static struct platform_driver aiu_pdrv
= {
378 .remove
= aiu_remove
,
381 .of_match_table
= aiu_of_match
,
384 module_platform_driver(aiu_pdrv
);
386 MODULE_DESCRIPTION("Meson AIU Driver");
387 MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
388 MODULE_LICENSE("GPL v2");