1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright 2011 Broadcom Corporation. All rights reserved. */
4 #include <linux/platform_device.h>
6 #include <linux/init.h>
7 #include <linux/slab.h>
8 #include <linux/module.h>
12 #include <soc/bcm2835/raspberrypi-firmware.h>
14 static bool enable_hdmi, enable_hdmi0, enable_hdmi1;
15 static bool enable_headphones;
16 static bool enable_compat_alsa = true;
18 module_param(enable_hdmi, bool, 0444);
19 MODULE_PARM_DESC(enable_hdmi, "Enables HDMI virtual audio device");
20 module_param(enable_headphones, bool, 0444);
21 MODULE_PARM_DESC(enable_headphones, "Enables Headphones virtual audio device");
22 module_param(enable_compat_alsa, bool, 0444);
23 MODULE_PARM_DESC(enable_compat_alsa,
24 "Enables ALSA compatibility virtual audio device");
26 static void bcm2835_devm_free_vchi_ctx(struct device *dev, void *res)
28 struct bcm2835_vchi_ctx *vchi_ctx = res;
30 bcm2835_free_vchi_ctx(vchi_ctx);
33 static int bcm2835_devm_add_vchi_ctx(struct device *dev)
35 struct bcm2835_vchi_ctx *vchi_ctx;
38 vchi_ctx = devres_alloc(bcm2835_devm_free_vchi_ctx, sizeof(*vchi_ctx),
43 ret = bcm2835_new_vchi_ctx(dev, vchi_ctx);
45 devres_free(vchi_ctx);
49 devres_add(dev, vchi_ctx);
54 typedef int (*bcm2835_audio_newpcm_func)(struct bcm2835_chip *chip,
56 enum snd_bcm2835_route route,
59 typedef int (*bcm2835_audio_newctl_func)(struct bcm2835_chip *chip);
61 struct bcm2835_audio_driver {
62 struct device_driver driver;
63 const char *shortname;
66 bcm2835_audio_newpcm_func newpcm;
67 bcm2835_audio_newctl_func newctl;
68 enum snd_bcm2835_route route;
71 static int bcm2835_audio_alsa_newpcm(struct bcm2835_chip *chip,
73 enum snd_bcm2835_route route,
78 err = snd_bcm2835_new_pcm(chip, "bcm2835 ALSA", 0, AUDIO_DEST_AUTO,
79 numchannels - 1, false);
83 err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI", 1, AUDIO_DEST_HDMI0, 1, true);
87 err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI1", 2, AUDIO_DEST_HDMI1, 1, true);
94 static int bcm2835_audio_simple_newpcm(struct bcm2835_chip *chip,
96 enum snd_bcm2835_route route,
99 return snd_bcm2835_new_pcm(chip, name, 0, route, numchannels, false);
102 static struct bcm2835_audio_driver bcm2835_audio_alsa = {
104 .name = "bcm2835_alsa",
105 .owner = THIS_MODULE,
107 .shortname = "bcm2835 ALSA",
108 .longname = "bcm2835 ALSA",
110 .newpcm = bcm2835_audio_alsa_newpcm,
111 .newctl = snd_bcm2835_new_ctl,
114 static struct bcm2835_audio_driver bcm2835_audio_hdmi0 = {
116 .name = "bcm2835_hdmi",
117 .owner = THIS_MODULE,
119 .shortname = "bcm2835 HDMI 1",
120 .longname = "bcm2835 HDMI 1",
122 .newpcm = bcm2835_audio_simple_newpcm,
123 .newctl = snd_bcm2835_new_hdmi_ctl,
124 .route = AUDIO_DEST_HDMI0
127 static struct bcm2835_audio_driver bcm2835_audio_hdmi1 = {
129 .name = "bcm2835_hdmi",
130 .owner = THIS_MODULE,
132 .shortname = "bcm2835 HDMI 2",
133 .longname = "bcm2835 HDMI 2",
135 .newpcm = bcm2835_audio_simple_newpcm,
136 .newctl = snd_bcm2835_new_hdmi_ctl,
137 .route = AUDIO_DEST_HDMI1
140 static struct bcm2835_audio_driver bcm2835_audio_headphones = {
142 .name = "bcm2835_headphones",
143 .owner = THIS_MODULE,
145 .shortname = "bcm2835 Headphones",
146 .longname = "bcm2835 Headphones",
148 .newpcm = bcm2835_audio_simple_newpcm,
149 .newctl = snd_bcm2835_new_headphones_ctl,
150 .route = AUDIO_DEST_HEADPHONES
153 struct bcm2835_audio_drivers {
154 struct bcm2835_audio_driver *audio_driver;
155 const bool *is_enabled;
158 static struct bcm2835_audio_drivers children_devices[] = {
160 .audio_driver = &bcm2835_audio_alsa,
161 .is_enabled = &enable_compat_alsa,
164 .audio_driver = &bcm2835_audio_hdmi0,
165 .is_enabled = &enable_hdmi0,
168 .audio_driver = &bcm2835_audio_hdmi1,
169 .is_enabled = &enable_hdmi1,
172 .audio_driver = &bcm2835_audio_headphones,
173 .is_enabled = &enable_headphones,
177 static void bcm2835_card_free(void *data)
182 static int snd_add_child_device(struct device *dev,
183 struct bcm2835_audio_driver *audio_driver,
186 struct bcm2835_chip *chip;
187 struct snd_card *card;
190 err = snd_card_new(dev, -1, NULL, THIS_MODULE, sizeof(*chip), &card);
192 dev_err(dev, "Failed to create card");
196 chip = card->private_data;
199 mutex_init(&chip->audio_mutex);
201 chip->vchi_ctx = devres_find(dev,
202 bcm2835_devm_free_vchi_ctx, NULL, NULL);
203 if (!chip->vchi_ctx) {
208 strscpy(card->driver, audio_driver->driver.name, sizeof(card->driver));
209 strscpy(card->shortname, audio_driver->shortname, sizeof(card->shortname));
210 strscpy(card->longname, audio_driver->longname, sizeof(card->longname));
212 err = audio_driver->newpcm(chip, audio_driver->shortname,
216 dev_err(dev, "Failed to create pcm, error %d\n", err);
220 err = audio_driver->newctl(chip);
222 dev_err(dev, "Failed to create controls, error %d\n", err);
226 err = snd_card_register(card);
228 dev_err(dev, "Failed to register card, error %d\n", err);
232 dev_set_drvdata(dev, chip);
234 err = devm_add_action(dev, bcm2835_card_free, card);
236 dev_err(dev, "Failed to add devm action, err %d\n", err);
240 dev_info(dev, "card created with %d channels\n", numchans);
248 static int snd_add_child_devices(struct device *device, u32 numchans)
250 int extrachannels_per_driver = 0;
251 int extrachannels_remainder = 0;
252 int count_devices = 0;
253 int extrachannels = 0;
257 for (i = 0; i < ARRAY_SIZE(children_devices); i++)
258 if (*children_devices[i].is_enabled)
264 for (i = 0; i < ARRAY_SIZE(children_devices); i++)
265 if (*children_devices[i].is_enabled)
267 children_devices[i].audio_driver->minchannels;
269 if (minchannels < numchans) {
270 extrachannels = numchans - minchannels;
271 extrachannels_per_driver = extrachannels / count_devices;
272 extrachannels_remainder = extrachannels % count_devices;
275 dev_dbg(device, "minchannels %d\n", minchannels);
276 dev_dbg(device, "extrachannels %d\n", extrachannels);
277 dev_dbg(device, "extrachannels_per_driver %d\n",
278 extrachannels_per_driver);
279 dev_dbg(device, "extrachannels_remainder %d\n",
280 extrachannels_remainder);
282 for (i = 0; i < ARRAY_SIZE(children_devices); i++) {
283 struct bcm2835_audio_driver *audio_driver;
284 int numchannels_this_device;
287 if (!*children_devices[i].is_enabled)
290 audio_driver = children_devices[i].audio_driver;
292 if (audio_driver->minchannels > numchans) {
294 "Out of channels, needed %d but only %d left\n",
295 audio_driver->minchannels,
300 numchannels_this_device =
301 audio_driver->minchannels + extrachannels_per_driver +
302 extrachannels_remainder;
303 extrachannels_remainder = 0;
305 numchans -= numchannels_this_device;
307 err = snd_add_child_device(device, audio_driver,
308 numchannels_this_device);
316 static void set_hdmi_enables(struct device *dev)
318 struct device_node *firmware_node;
319 struct rpi_firmware *firmware;
320 u32 num_displays, i, display_id;
323 firmware_node = of_parse_phandle(dev->of_node, "brcm,firmware", 0);
324 firmware = rpi_firmware_get(firmware_node);
329 of_node_put(firmware_node);
331 ret = rpi_firmware_property(firmware,
332 RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS,
333 &num_displays, sizeof(u32));
338 for (i = 0; i < num_displays; i++) {
340 ret = rpi_firmware_property(firmware,
341 RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_ID,
342 &display_id, sizeof(display_id));
351 if (!enable_hdmi0 && enable_hdmi1) {
352 /* Swap them over and reassign route. This means
353 * that if we only have one connected, it is always named
354 * HDMI1, irrespective of if its on port HDMI0 or HDMI1.
355 * This should match with the naming of HDMI ports in DRM
358 enable_hdmi1 = false;
359 bcm2835_audio_hdmi0.route = AUDIO_DEST_HDMI1;
363 static int snd_bcm2835_alsa_probe(struct platform_device *pdev)
365 struct device *dev = &pdev->dev;
369 err = of_property_read_u32(dev->of_node, "brcm,pwm-channels",
372 dev_err(dev, "Failed to get DT property 'brcm,pwm-channels'");
376 if (numchans == 0 || numchans > MAX_SUBSTREAMS) {
377 numchans = MAX_SUBSTREAMS;
379 "Illegal 'brcm,pwm-channels' value, will use %u\n",
383 if (!enable_compat_alsa) {
384 // In this mode, enable analog output by default
385 u32 disable_headphones = 0;
387 if (!of_property_read_bool(dev->of_node, "brcm,disable-hdmi"))
388 set_hdmi_enables(dev);
390 of_property_read_u32(dev->of_node,
391 "brcm,disable-headphones",
392 &disable_headphones);
393 enable_headphones = !disable_headphones;
395 enable_hdmi0 = enable_hdmi;
398 err = bcm2835_devm_add_vchi_ctx(dev);
402 err = snd_add_child_devices(dev, numchans);
411 static int snd_bcm2835_alsa_suspend(struct platform_device *pdev,
417 static int snd_bcm2835_alsa_resume(struct platform_device *pdev)
424 static const struct of_device_id snd_bcm2835_of_match_table[] = {
425 { .compatible = "brcm,bcm2835-audio",},
428 MODULE_DEVICE_TABLE(of, snd_bcm2835_of_match_table);
430 static struct platform_driver bcm2835_alsa_driver = {
431 .probe = snd_bcm2835_alsa_probe,
433 .suspend = snd_bcm2835_alsa_suspend,
434 .resume = snd_bcm2835_alsa_resume,
437 .name = "bcm2835_audio",
438 .of_match_table = snd_bcm2835_of_match_table,
441 module_platform_driver(bcm2835_alsa_driver);
443 MODULE_AUTHOR("Dom Cobley");
444 MODULE_DESCRIPTION("Alsa driver for BCM2835 chip");
445 MODULE_LICENSE("GPL");
446 MODULE_ALIAS("platform:bcm2835_audio");