GNU Linux-libre 6.9.1-gnu
[releases.git] / sound / soc / qcom / x1e80100.c
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2023, Linaro Limited
3
4 #include <dt-bindings/sound/qcom,q6afe.h>
5 #include <linux/module.h>
6 #include <linux/platform_device.h>
7 #include <linux/soundwire/sdw.h>
8 #include <sound/pcm.h>
9 #include <sound/jack.h>
10 #include <sound/soc.h>
11 #include <sound/soc-dapm.h>
12
13 #include "common.h"
14 #include "qdsp6/q6afe.h"
15 #include "sdw.h"
16
17 struct x1e80100_snd_data {
18         bool stream_prepared[AFE_PORT_MAX];
19         struct snd_soc_card *card;
20         struct sdw_stream_runtime *sruntime[AFE_PORT_MAX];
21         struct snd_soc_jack jack;
22         bool jack_setup;
23 };
24
25 static int x1e80100_snd_init(struct snd_soc_pcm_runtime *rtd)
26 {
27         struct x1e80100_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
28
29         return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup);
30 }
31
32 static void x1e80100_snd_shutdown(struct snd_pcm_substream *substream)
33 {
34         struct snd_soc_pcm_runtime *rtd = substream->private_data;
35         struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
36         struct x1e80100_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
37         struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
38
39         data->sruntime[cpu_dai->id] = NULL;
40         sdw_release_stream(sruntime);
41 }
42
43 static int x1e80100_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
44                                      struct snd_pcm_hw_params *params)
45 {
46         struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
47         struct snd_interval *rate = hw_param_interval(params,
48                                                       SNDRV_PCM_HW_PARAM_RATE);
49         struct snd_interval *channels = hw_param_interval(params,
50                                                           SNDRV_PCM_HW_PARAM_CHANNELS);
51
52         rate->min = rate->max = 48000;
53         switch (cpu_dai->id) {
54         case TX_CODEC_DMA_TX_0:
55         case TX_CODEC_DMA_TX_1:
56         case TX_CODEC_DMA_TX_2:
57         case TX_CODEC_DMA_TX_3:
58                 channels->min = 1;
59                 break;
60         default:
61                 break;
62         }
63
64         return 0;
65 }
66
67 static int x1e80100_snd_hw_params(struct snd_pcm_substream *substream,
68                                 struct snd_pcm_hw_params *params)
69 {
70         struct snd_soc_pcm_runtime *rtd = substream->private_data;
71         struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
72         struct x1e80100_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
73
74         return qcom_snd_sdw_hw_params(substream, params, &data->sruntime[cpu_dai->id]);
75 }
76
77 static int x1e80100_snd_prepare(struct snd_pcm_substream *substream)
78 {
79         struct snd_soc_pcm_runtime *rtd = substream->private_data;
80         struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
81         struct x1e80100_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
82         struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
83
84         return qcom_snd_sdw_prepare(substream, sruntime,
85                                     &data->stream_prepared[cpu_dai->id]);
86 }
87
88 static int x1e80100_snd_hw_free(struct snd_pcm_substream *substream)
89 {
90         struct snd_soc_pcm_runtime *rtd = substream->private_data;
91         struct x1e80100_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
92         struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
93         struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
94
95         return qcom_snd_sdw_hw_free(substream, sruntime,
96                                     &data->stream_prepared[cpu_dai->id]);
97 }
98
99 static const struct snd_soc_ops x1e80100_be_ops = {
100         .startup = qcom_snd_sdw_startup,
101         .shutdown = x1e80100_snd_shutdown,
102         .hw_params = x1e80100_snd_hw_params,
103         .hw_free = x1e80100_snd_hw_free,
104         .prepare = x1e80100_snd_prepare,
105 };
106
107 static void x1e80100_add_be_ops(struct snd_soc_card *card)
108 {
109         struct snd_soc_dai_link *link;
110         int i;
111
112         for_each_card_prelinks(card, i, link) {
113                 if (link->no_pcm == 1) {
114                         link->init = x1e80100_snd_init;
115                         link->be_hw_params_fixup = x1e80100_be_hw_params_fixup;
116                         link->ops = &x1e80100_be_ops;
117                 }
118         }
119 }
120
121 static int x1e80100_platform_probe(struct platform_device *pdev)
122 {
123         struct snd_soc_card *card;
124         struct x1e80100_snd_data *data;
125         struct device *dev = &pdev->dev;
126         int ret;
127
128         card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
129         if (!card)
130                 return -ENOMEM;
131         /* Allocate the private data */
132         data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
133         if (!data)
134                 return -ENOMEM;
135
136         card->owner = THIS_MODULE;
137         card->dev = dev;
138         dev_set_drvdata(dev, card);
139         snd_soc_card_set_drvdata(card, data);
140
141         ret = qcom_snd_parse_of(card);
142         if (ret)
143                 return ret;
144
145         card->driver_name = "x1e80100";
146         x1e80100_add_be_ops(card);
147
148         return devm_snd_soc_register_card(dev, card);
149 }
150
151 static const struct of_device_id snd_x1e80100_dt_match[] = {
152         { .compatible = "qcom,x1e80100-sndcard", },
153         {}
154 };
155 MODULE_DEVICE_TABLE(of, snd_x1e80100_dt_match);
156
157 static struct platform_driver snd_x1e80100_driver = {
158         .probe  = x1e80100_platform_probe,
159         .driver = {
160                 .name = "snd-x1e80100",
161                 .of_match_table = snd_x1e80100_dt_match,
162         },
163 };
164 module_platform_driver(snd_x1e80100_driver);
165 MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
166 MODULE_AUTHOR("Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>");
167 MODULE_DESCRIPTION("Qualcomm X1E80100 ASoC Machine Driver");
168 MODULE_LICENSE("GPL");