Linux-libre 5.4.49-gnu
[librecmc/linux-libre.git] / drivers / staging / vc04_services / bcm2835-audio / bcm2835.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright 2011 Broadcom Corporation.  All rights reserved. */
3
4 #include <linux/platform_device.h>
5
6 #include <linux/init.h>
7 #include <linux/slab.h>
8 #include <linux/module.h>
9
10 #include "bcm2835.h"
11
12 static bool enable_hdmi;
13 static bool enable_headphones;
14 static bool enable_compat_alsa = true;
15 static int num_channels = MAX_SUBSTREAMS;
16
17 module_param(enable_hdmi, bool, 0444);
18 MODULE_PARM_DESC(enable_hdmi, "Enables HDMI virtual audio device");
19 module_param(enable_headphones, bool, 0444);
20 MODULE_PARM_DESC(enable_headphones, "Enables Headphones virtual audio device");
21 module_param(enable_compat_alsa, bool, 0444);
22 MODULE_PARM_DESC(enable_compat_alsa,
23                  "Enables ALSA compatibility virtual audio device");
24 module_param(num_channels, int, 0644);
25 MODULE_PARM_DESC(num_channels, "Number of audio channels (default: 8)");
26
27 static void bcm2835_devm_free_vchi_ctx(struct device *dev, void *res)
28 {
29         struct bcm2835_vchi_ctx *vchi_ctx = res;
30
31         bcm2835_free_vchi_ctx(vchi_ctx);
32 }
33
34 static int bcm2835_devm_add_vchi_ctx(struct device *dev)
35 {
36         struct bcm2835_vchi_ctx *vchi_ctx;
37         int ret;
38
39         vchi_ctx = devres_alloc(bcm2835_devm_free_vchi_ctx, sizeof(*vchi_ctx),
40                                 GFP_KERNEL);
41         if (!vchi_ctx)
42                 return -ENOMEM;
43
44         ret = bcm2835_new_vchi_ctx(dev, vchi_ctx);
45         if (ret) {
46                 devres_free(vchi_ctx);
47                 return ret;
48         }
49
50         devres_add(dev, vchi_ctx);
51
52         return 0;
53 }
54
55 typedef int (*bcm2835_audio_newpcm_func)(struct bcm2835_chip *chip,
56                                          const char *name,
57                                          enum snd_bcm2835_route route,
58                                          u32 numchannels);
59
60 typedef int (*bcm2835_audio_newctl_func)(struct bcm2835_chip *chip);
61
62 struct bcm2835_audio_driver {
63         struct device_driver driver;
64         const char *shortname;
65         const char *longname;
66         int minchannels;
67         bcm2835_audio_newpcm_func newpcm;
68         bcm2835_audio_newctl_func newctl;
69         enum snd_bcm2835_route route;
70 };
71
72 static int bcm2835_audio_alsa_newpcm(struct bcm2835_chip *chip,
73                                      const char *name,
74                                      enum snd_bcm2835_route route,
75                                      u32 numchannels)
76 {
77         int err;
78
79         err = snd_bcm2835_new_pcm(chip, "bcm2835 ALSA", 0, AUDIO_DEST_AUTO,
80                                   numchannels - 1, false);
81         if (err)
82                 return err;
83
84         err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI", 1, 0, 1, true);
85         if (err)
86                 return err;
87
88         return 0;
89 }
90
91 static int bcm2835_audio_simple_newpcm(struct bcm2835_chip *chip,
92                                        const char *name,
93                                        enum snd_bcm2835_route route,
94                                        u32 numchannels)
95 {
96         return snd_bcm2835_new_pcm(chip, name, 0, route, numchannels, false);
97 }
98
99 static struct bcm2835_audio_driver bcm2835_audio_alsa = {
100         .driver = {
101                 .name = "bcm2835_alsa",
102                 .owner = THIS_MODULE,
103         },
104         .shortname = "bcm2835 ALSA",
105         .longname  = "bcm2835 ALSA",
106         .minchannels = 2,
107         .newpcm = bcm2835_audio_alsa_newpcm,
108         .newctl = snd_bcm2835_new_ctl,
109 };
110
111 static struct bcm2835_audio_driver bcm2835_audio_hdmi = {
112         .driver = {
113                 .name = "bcm2835_hdmi",
114                 .owner = THIS_MODULE,
115         },
116         .shortname = "bcm2835 HDMI",
117         .longname  = "bcm2835 HDMI",
118         .minchannels = 1,
119         .newpcm = bcm2835_audio_simple_newpcm,
120         .newctl = snd_bcm2835_new_hdmi_ctl,
121         .route = AUDIO_DEST_HDMI
122 };
123
124 static struct bcm2835_audio_driver bcm2835_audio_headphones = {
125         .driver = {
126                 .name = "bcm2835_headphones",
127                 .owner = THIS_MODULE,
128         },
129         .shortname = "bcm2835 Headphones",
130         .longname  = "bcm2835 Headphones",
131         .minchannels = 1,
132         .newpcm = bcm2835_audio_simple_newpcm,
133         .newctl = snd_bcm2835_new_headphones_ctl,
134         .route = AUDIO_DEST_HEADPHONES
135 };
136
137 struct bcm2835_audio_drivers {
138         struct bcm2835_audio_driver *audio_driver;
139         const bool *is_enabled;
140 };
141
142 static struct bcm2835_audio_drivers children_devices[] = {
143         {
144                 .audio_driver = &bcm2835_audio_alsa,
145                 .is_enabled = &enable_compat_alsa,
146         },
147         {
148                 .audio_driver = &bcm2835_audio_hdmi,
149                 .is_enabled = &enable_hdmi,
150         },
151         {
152                 .audio_driver = &bcm2835_audio_headphones,
153                 .is_enabled = &enable_headphones,
154         },
155 };
156
157 static void bcm2835_card_free(void *data)
158 {
159         snd_card_free(data);
160 }
161
162 static int snd_add_child_device(struct device *dev,
163                                 struct bcm2835_audio_driver *audio_driver,
164                                 u32 numchans)
165 {
166         struct bcm2835_chip *chip;
167         struct snd_card *card;
168         int err;
169
170         err = snd_card_new(dev, -1, NULL, THIS_MODULE, sizeof(*chip), &card);
171         if (err < 0) {
172                 dev_err(dev, "Failed to create card");
173                 return err;
174         }
175
176         chip = card->private_data;
177         chip->card = card;
178         chip->dev = dev;
179         mutex_init(&chip->audio_mutex);
180
181         chip->vchi_ctx = devres_find(dev,
182                                      bcm2835_devm_free_vchi_ctx, NULL, NULL);
183         if (!chip->vchi_ctx) {
184                 err = -ENODEV;
185                 goto error;
186         }
187
188         strcpy(card->driver, audio_driver->driver.name);
189         strcpy(card->shortname, audio_driver->shortname);
190         strcpy(card->longname, audio_driver->longname);
191
192         err = audio_driver->newpcm(chip, audio_driver->shortname,
193                 audio_driver->route,
194                 numchans);
195         if (err) {
196                 dev_err(dev, "Failed to create pcm, error %d\n", err);
197                 goto error;
198         }
199
200         err = audio_driver->newctl(chip);
201         if (err) {
202                 dev_err(dev, "Failed to create controls, error %d\n", err);
203                 goto error;
204         }
205
206         err = snd_card_register(card);
207         if (err) {
208                 dev_err(dev, "Failed to register card, error %d\n", err);
209                 goto error;
210         }
211
212         dev_set_drvdata(dev, chip);
213
214         err = devm_add_action(dev, bcm2835_card_free, card);
215         if (err < 0) {
216                 dev_err(dev, "Failed to add devm action, err %d\n", err);
217                 goto error;
218         }
219
220         dev_info(dev, "card created with %d channels\n", numchans);
221         return 0;
222
223  error:
224         snd_card_free(card);
225         return err;
226 }
227
228 static int snd_add_child_devices(struct device *device, u32 numchans)
229 {
230         int extrachannels_per_driver = 0;
231         int extrachannels_remainder = 0;
232         int count_devices = 0;
233         int extrachannels = 0;
234         int minchannels = 0;
235         int i;
236
237         for (i = 0; i < ARRAY_SIZE(children_devices); i++)
238                 if (*children_devices[i].is_enabled)
239                         count_devices++;
240
241         if (!count_devices)
242                 return 0;
243
244         for (i = 0; i < ARRAY_SIZE(children_devices); i++)
245                 if (*children_devices[i].is_enabled)
246                         minchannels +=
247                                 children_devices[i].audio_driver->minchannels;
248
249         if (minchannels < numchans) {
250                 extrachannels = numchans - minchannels;
251                 extrachannels_per_driver = extrachannels / count_devices;
252                 extrachannels_remainder = extrachannels % count_devices;
253         }
254
255         dev_dbg(device, "minchannels %d\n", minchannels);
256         dev_dbg(device, "extrachannels %d\n", extrachannels);
257         dev_dbg(device, "extrachannels_per_driver %d\n",
258                 extrachannels_per_driver);
259         dev_dbg(device, "extrachannels_remainder %d\n",
260                 extrachannels_remainder);
261
262         for (i = 0; i < ARRAY_SIZE(children_devices); i++) {
263                 struct bcm2835_audio_driver *audio_driver;
264                 int numchannels_this_device;
265                 int err;
266
267                 if (!*children_devices[i].is_enabled)
268                         continue;
269
270                 audio_driver = children_devices[i].audio_driver;
271
272                 if (audio_driver->minchannels > numchans) {
273                         dev_err(device,
274                                 "Out of channels, needed %d but only %d left\n",
275                                 audio_driver->minchannels,
276                                 numchans);
277                         continue;
278                 }
279
280                 numchannels_this_device =
281                         audio_driver->minchannels + extrachannels_per_driver +
282                         extrachannels_remainder;
283                 extrachannels_remainder = 0;
284
285                 numchans -= numchannels_this_device;
286
287                 err = snd_add_child_device(device, audio_driver,
288                                            numchannels_this_device);
289                 if (err)
290                         return err;
291         }
292
293         return 0;
294 }
295
296 static int snd_bcm2835_alsa_probe(struct platform_device *pdev)
297 {
298         struct device *dev = &pdev->dev;
299         int err;
300
301         if (num_channels <= 0 || num_channels > MAX_SUBSTREAMS) {
302                 num_channels = MAX_SUBSTREAMS;
303                 dev_warn(dev, "Illegal num_channels value, will use %u\n",
304                          num_channels);
305         }
306
307         err = bcm2835_devm_add_vchi_ctx(dev);
308         if (err)
309                 return err;
310
311         err = snd_add_child_devices(dev, num_channels);
312         if (err)
313                 return err;
314
315         return 0;
316 }
317
318 #ifdef CONFIG_PM
319
320 static int snd_bcm2835_alsa_suspend(struct platform_device *pdev,
321                                     pm_message_t state)
322 {
323         return 0;
324 }
325
326 static int snd_bcm2835_alsa_resume(struct platform_device *pdev)
327 {
328         return 0;
329 }
330
331 #endif
332
333 static struct platform_driver bcm2835_alsa_driver = {
334         .probe = snd_bcm2835_alsa_probe,
335 #ifdef CONFIG_PM
336         .suspend = snd_bcm2835_alsa_suspend,
337         .resume = snd_bcm2835_alsa_resume,
338 #endif
339         .driver = {
340                 .name = "bcm2835_audio",
341         },
342 };
343 module_platform_driver(bcm2835_alsa_driver);
344
345 MODULE_AUTHOR("Dom Cobley");
346 MODULE_DESCRIPTION("Alsa driver for BCM2835 chip");
347 MODULE_LICENSE("GPL");
348 MODULE_ALIAS("platform:bcm2835_audio");