aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/vc04_services/bcm2835-audio/bcm2835.c')
-rw-r--r--drivers/staging/vc04_services/bcm2835-audio/bcm2835.c125
1 files changed, 109 insertions, 16 deletions
diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
index cf5f80f5ca6b..b9716f3e264c 100644
--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
+++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.c
@@ -6,13 +6,14 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
+#include <linux/of.h>
#include "bcm2835.h"
+#include <soc/bcm2835/raspberrypi-firmware.h>
-static bool enable_hdmi;
+static bool enable_hdmi, enable_hdmi0, enable_hdmi1;
static bool enable_headphones;
static bool enable_compat_alsa = true;
-static int num_channels = MAX_SUBSTREAMS;
module_param(enable_hdmi, bool, 0444);
MODULE_PARM_DESC(enable_hdmi, "Enables HDMI virtual audio device");
@@ -21,8 +22,6 @@ MODULE_PARM_DESC(enable_headphones, "Enables Headphones virtual audio device");
module_param(enable_compat_alsa, bool, 0444);
MODULE_PARM_DESC(enable_compat_alsa,
"Enables ALSA compatibility virtual audio device");
-module_param(num_channels, int, 0644);
-MODULE_PARM_DESC(num_channels, "Number of audio channels (default: 8)");
static void bcm2835_devm_free_vchi_ctx(struct device *dev, void *res)
{
@@ -81,7 +80,11 @@ static int bcm2835_audio_alsa_newpcm(struct bcm2835_chip *chip,
if (err)
return err;
- err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI", 1, 0, 1, true);
+ err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI", 1, AUDIO_DEST_HDMI0, 1, true);
+ if (err)
+ return err;
+
+ err = snd_bcm2835_new_pcm(chip, "bcm2835 IEC958/HDMI1", 2, AUDIO_DEST_HDMI1, 1, true);
if (err)
return err;
@@ -108,17 +111,30 @@ static struct bcm2835_audio_driver bcm2835_audio_alsa = {
.newctl = snd_bcm2835_new_ctl,
};
-static struct bcm2835_audio_driver bcm2835_audio_hdmi = {
+static struct bcm2835_audio_driver bcm2835_audio_hdmi0 = {
.driver = {
.name = "bcm2835_hdmi",
.owner = THIS_MODULE,
},
- .shortname = "bcm2835 HDMI",
- .longname = "bcm2835 HDMI",
+ .shortname = "bcm2835 HDMI 1",
+ .longname = "bcm2835 HDMI 1",
.minchannels = 1,
.newpcm = bcm2835_audio_simple_newpcm,
.newctl = snd_bcm2835_new_hdmi_ctl,
- .route = AUDIO_DEST_HDMI
+ .route = AUDIO_DEST_HDMI0
+};
+
+static struct bcm2835_audio_driver bcm2835_audio_hdmi1 = {
+ .driver = {
+ .name = "bcm2835_hdmi",
+ .owner = THIS_MODULE,
+ },
+ .shortname = "bcm2835 HDMI 2",
+ .longname = "bcm2835 HDMI 2",
+ .minchannels = 1,
+ .newpcm = bcm2835_audio_simple_newpcm,
+ .newctl = snd_bcm2835_new_hdmi_ctl,
+ .route = AUDIO_DEST_HDMI1
};
static struct bcm2835_audio_driver bcm2835_audio_headphones = {
@@ -145,8 +161,12 @@ static struct bcm2835_audio_drivers children_devices[] = {
.is_enabled = &enable_compat_alsa,
},
{
- .audio_driver = &bcm2835_audio_hdmi,
- .is_enabled = &enable_hdmi,
+ .audio_driver = &bcm2835_audio_hdmi0,
+ .is_enabled = &enable_hdmi0,
+ },
+ {
+ .audio_driver = &bcm2835_audio_hdmi1,
+ .is_enabled = &enable_hdmi1,
},
{
.audio_driver = &bcm2835_audio_headphones,
@@ -293,22 +313,88 @@ static int snd_add_child_devices(struct device *device, u32 numchans)
return 0;
}
+static void set_hdmi_enables(struct device *dev)
+{
+ struct device_node *firmware_node;
+ struct rpi_firmware *firmware;
+ u32 num_displays, i, display_id;
+ int ret;
+
+ firmware_node = of_parse_phandle(dev->of_node, "brcm,firmware", 0);
+ firmware = rpi_firmware_get(firmware_node);
+
+ if (!firmware)
+ return;
+
+ of_node_put(firmware_node);
+
+ ret = rpi_firmware_property(firmware,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_NUM_DISPLAYS,
+ &num_displays, sizeof(u32));
+
+ if (ret)
+ return;
+
+ for (i = 0; i < num_displays; i++) {
+ display_id = i;
+ ret = rpi_firmware_property(firmware,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_DISPLAY_ID,
+ &display_id, sizeof(display_id));
+ if (!ret) {
+ if (display_id == 2)
+ enable_hdmi0 = true;
+ if (display_id == 7)
+ enable_hdmi1 = true;
+ }
+ }
+
+ if (!enable_hdmi0 && enable_hdmi1) {
+ /* Swap them over and reassign route. This means
+ * that if we only have one connected, it is always named
+ * HDMI1, irrespective of if its on port HDMI0 or HDMI1.
+ * This should match with the naming of HDMI ports in DRM
+ */
+ enable_hdmi0 = true;
+ enable_hdmi1 = false;
+ bcm2835_audio_hdmi0.route = AUDIO_DEST_HDMI1;
+ }
+}
+
static int snd_bcm2835_alsa_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ u32 numchans;
int err;
- if (num_channels <= 0 || num_channels > MAX_SUBSTREAMS) {
- num_channels = MAX_SUBSTREAMS;
- dev_warn(dev, "Illegal num_channels value, will use %u\n",
- num_channels);
+ err = of_property_read_u32(dev->of_node, "brcm,pwm-channels",
+ &numchans);
+ if (err) {
+ dev_err(dev, "Failed to get DT property 'brcm,pwm-channels'");
+ return err;
+ }
+
+ if (numchans == 0 || numchans > MAX_SUBSTREAMS) {
+ numchans = MAX_SUBSTREAMS;
+ dev_warn(dev,
+ "Illegal 'brcm,pwm-channels' value, will use %u\n",
+ numchans);
+ }
+
+ if (!enable_compat_alsa) {
+ if (!of_property_read_bool(dev->of_node, "brcm,disable-hdmi"))
+ set_hdmi_enables(dev);
+
+ // In this mode, always enable analog output
+ enable_headphones = true;
+ } else {
+ enable_hdmi0 = enable_hdmi;
}
err = bcm2835_devm_add_vchi_ctx(dev);
if (err)
return err;
- err = snd_add_child_devices(dev, num_channels);
+ err = snd_add_child_devices(dev, numchans);
if (err)
return err;
@@ -330,6 +416,12 @@ static int snd_bcm2835_alsa_resume(struct platform_device *pdev)
#endif
+static const struct of_device_id snd_bcm2835_of_match_table[] = {
+ { .compatible = "brcm,bcm2835-audio",},
+ {},
+};
+MODULE_DEVICE_TABLE(of, snd_bcm2835_of_match_table);
+
static struct platform_driver bcm2835_alsa_driver = {
.probe = snd_bcm2835_alsa_probe,
#ifdef CONFIG_PM
@@ -338,6 +430,7 @@ static struct platform_driver bcm2835_alsa_driver = {
#endif
.driver = {
.name = "bcm2835_audio",
+ .of_match_table = snd_bcm2835_of_match_table,
},
};
module_platform_driver(bcm2835_alsa_driver);