1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (C) 2014 Marvell |
4 | * |
5 | * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> |
6 | */ |
7 | |
8 | #include <linux/module.h> |
9 | #include <linux/moduleparam.h> |
10 | #include <linux/interrupt.h> |
11 | #include <linux/platform_device.h> |
12 | #include <linux/slab.h> |
13 | #include <sound/soc.h> |
14 | #include <linux/of.h> |
15 | #include <linux/platform_data/asoc-kirkwood.h> |
16 | #include "../codecs/cs42l51.h" |
17 | |
18 | static int a370db_hw_params(struct snd_pcm_substream *substream, |
19 | struct snd_pcm_hw_params *params) |
20 | { |
21 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
22 | struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); |
23 | unsigned int freq; |
24 | |
25 | switch (params_rate(p: params)) { |
26 | default: |
27 | case 44100: |
28 | freq = 11289600; |
29 | break; |
30 | case 48000: |
31 | freq = 12288000; |
32 | break; |
33 | case 96000: |
34 | freq = 24576000; |
35 | break; |
36 | } |
37 | |
38 | return snd_soc_dai_set_sysclk(dai: codec_dai, clk_id: 0, freq, SND_SOC_CLOCK_IN); |
39 | } |
40 | |
41 | static const struct snd_soc_ops a370db_ops = { |
42 | .hw_params = a370db_hw_params, |
43 | }; |
44 | |
45 | static const struct snd_soc_dapm_widget a370db_dapm_widgets[] = { |
46 | SND_SOC_DAPM_HP("Out Jack" , NULL), |
47 | SND_SOC_DAPM_LINE("In Jack" , NULL), |
48 | }; |
49 | |
50 | static const struct snd_soc_dapm_route a370db_route[] = { |
51 | { "Out Jack" , NULL, "HPL" }, |
52 | { "Out Jack" , NULL, "HPR" }, |
53 | { "AIN1L" , NULL, "In Jack" }, |
54 | { "AIN1L" , NULL, "In Jack" }, |
55 | }; |
56 | |
57 | SND_SOC_DAILINK_DEFS(analog, |
58 | DAILINK_COMP_ARRAY(COMP_CPU("i2s" )), |
59 | DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "cs42l51-hifi" )), |
60 | DAILINK_COMP_ARRAY(COMP_EMPTY())); |
61 | |
62 | SND_SOC_DAILINK_DEFS(spdif_out, |
63 | DAILINK_COMP_ARRAY(COMP_CPU("spdif" )), |
64 | DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "dit-hifi" )), |
65 | DAILINK_COMP_ARRAY(COMP_EMPTY())); |
66 | |
67 | SND_SOC_DAILINK_DEFS(spdif_in, |
68 | DAILINK_COMP_ARRAY(COMP_CPU("spdif" )), |
69 | DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "dir-hifi" )), |
70 | DAILINK_COMP_ARRAY(COMP_EMPTY())); |
71 | |
72 | static struct snd_soc_dai_link a370db_dai[] = { |
73 | { |
74 | .name = "CS42L51" , |
75 | .stream_name = "analog" , |
76 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS, |
77 | .ops = &a370db_ops, |
78 | SND_SOC_DAILINK_REG(analog), |
79 | }, |
80 | { |
81 | .name = "S/PDIF out" , |
82 | .stream_name = "spdif-out" , |
83 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS, |
84 | SND_SOC_DAILINK_REG(spdif_out), |
85 | }, |
86 | { |
87 | .name = "S/PDIF in" , |
88 | .stream_name = "spdif-in" , |
89 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS, |
90 | SND_SOC_DAILINK_REG(spdif_in), |
91 | }, |
92 | }; |
93 | |
94 | static struct snd_soc_card a370db = { |
95 | .name = "a370db" , |
96 | .owner = THIS_MODULE, |
97 | .dai_link = a370db_dai, |
98 | .num_links = ARRAY_SIZE(a370db_dai), |
99 | .dapm_widgets = a370db_dapm_widgets, |
100 | .num_dapm_widgets = ARRAY_SIZE(a370db_dapm_widgets), |
101 | .dapm_routes = a370db_route, |
102 | .num_dapm_routes = ARRAY_SIZE(a370db_route), |
103 | }; |
104 | |
105 | static int a370db_probe(struct platform_device *pdev) |
106 | { |
107 | struct snd_soc_card *card = &a370db; |
108 | |
109 | card->dev = &pdev->dev; |
110 | |
111 | a370db_dai[0].cpus->of_node = |
112 | of_parse_phandle(np: pdev->dev.of_node, |
113 | phandle_name: "marvell,audio-controller" , index: 0); |
114 | a370db_dai[0].platforms->of_node = a370db_dai[0].cpus->of_node; |
115 | |
116 | a370db_dai[0].codecs->of_node = |
117 | of_parse_phandle(np: pdev->dev.of_node, |
118 | phandle_name: "marvell,audio-codec" , index: 0); |
119 | |
120 | a370db_dai[1].cpus->of_node = a370db_dai[0].cpus->of_node; |
121 | a370db_dai[1].platforms->of_node = a370db_dai[0].cpus->of_node; |
122 | |
123 | a370db_dai[1].codecs->of_node = |
124 | of_parse_phandle(np: pdev->dev.of_node, |
125 | phandle_name: "marvell,audio-codec" , index: 1); |
126 | |
127 | a370db_dai[2].cpus->of_node = a370db_dai[0].cpus->of_node; |
128 | a370db_dai[2].platforms->of_node = a370db_dai[0].cpus->of_node; |
129 | |
130 | a370db_dai[2].codecs->of_node = |
131 | of_parse_phandle(np: pdev->dev.of_node, |
132 | phandle_name: "marvell,audio-codec" , index: 2); |
133 | |
134 | return devm_snd_soc_register_card(dev: card->dev, card); |
135 | } |
136 | |
137 | static const struct of_device_id a370db_dt_ids[] __maybe_unused = { |
138 | { .compatible = "marvell,a370db-audio" }, |
139 | { }, |
140 | }; |
141 | MODULE_DEVICE_TABLE(of, a370db_dt_ids); |
142 | |
143 | static struct platform_driver a370db_driver = { |
144 | .driver = { |
145 | .name = "a370db-audio" , |
146 | .of_match_table = of_match_ptr(a370db_dt_ids), |
147 | }, |
148 | .probe = a370db_probe, |
149 | }; |
150 | |
151 | module_platform_driver(a370db_driver); |
152 | |
153 | MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>" ); |
154 | MODULE_DESCRIPTION("ALSA SoC a370db audio client" ); |
155 | MODULE_LICENSE("GPL" ); |
156 | MODULE_ALIAS("platform:a370db-audio" ); |
157 | |