From 5f17e24bea60b696815d2c6cb578e1e23f61cd57 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Wed, 12 Nov 2014 17:07:02 +0000
Subject: [PATCH 064/114] Adding Device Tree support for some RPi audio cards

---
 arch/arm/boot/dts/Makefile                      |  2 +
 arch/arm/boot/dts/bcm2708-rpi-b-plus.dts        | 81 +++++++++++++++++++++++++
 arch/arm/boot/dts/bcm2708-rpi-b.dts             | 19 +++++-
 arch/arm/boot/dts/bcm2708.dtsi                  | 18 ++++--
 arch/arm/boot/dts/hifiberry-dac-overlay.dts     | 34 +++++++++++
 arch/arm/boot/dts/hifiberry-dacplus-overlay.dts | 39 ++++++++++++
 arch/arm/boot/dts/hifiberry-digi-overlay.dts    | 39 ++++++++++++
 arch/arm/boot/dts/iqaudio-dac-overlay.dts       | 39 ++++++++++++
 arch/arm/boot/dts/iqaudio-dacplus-overlay.dts   | 39 ++++++++++++
 sound/soc/bcm/hifiberry_dac.c                   | 22 +++++++
 sound/soc/bcm/hifiberry_dacplus.c               | 22 +++++++
 sound/soc/bcm/hifiberry_digi.c                  | 22 +++++++
 sound/soc/bcm/iqaudio-dac.c                     | 16 +++++
 sound/soc/codecs/pcm5102a.c                     |  7 +++
 14 files changed, 393 insertions(+), 6 deletions(-)
 create mode 100644 arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
 create mode 100644 arch/arm/boot/dts/hifiberry-dac-overlay.dts
 create mode 100644 arch/arm/boot/dts/hifiberry-dacplus-overlay.dts
 create mode 100644 arch/arm/boot/dts/hifiberry-digi-overlay.dts
 create mode 100644 arch/arm/boot/dts/iqaudio-dac-overlay.dts
 create mode 100644 arch/arm/boot/dts/iqaudio-dacplus-overlay.dts

--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -54,6 +54,7 @@ dtb-$(CONFIG_ARCH_AT91)	+= at91-sama5d4e
 dtb-$(CONFIG_ARCH_ATLAS6) += atlas6-evb.dtb
 dtb-$(CONFIG_ARCH_AXXIA) += axm5516-amarillo.dtb
 dtb-$(CONFIG_BCM2708_DT) += bcm2708-rpi-b.dtb
+dtb-$(CONFIG_BCM2708_DT) += bcm2708-rpi-b-plus.dtb
 dtb-$(CONFIG_ARCH_BCM2835) += bcm2835-rpi-b.dtb
 dtb-$(CONFIG_ARCH_BCM_5301X) += bcm4708-netgear-r6250.dtb
 dtb-$(CONFIG_ARCH_BCM_63XX) += bcm963138dvt.dtb
@@ -520,6 +521,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt6589-aq
 
 targets += dtbs dtbs_install
 targets += $(dtb-y)
+
 endif
 
 # *.dtb used to be generated in the directory above. Clean out the
--- /dev/null
+++ b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
@@ -0,0 +1,81 @@
+/dts-v1/;
+
+/include/ "bcm2708.dtsi"
+
+/ {
+	compatible = "brcm,bcm2708";
+	model = "Raspberry Pi Model B+";
+
+	aliases {
+		spi0 = &spi0;
+		i2c0 = &i2c0;
+		i2c1 = &i2c1;
+		i2s  = &i2s;
+		gpio = &gpio;
+		sound = &sound;
+	};
+
+	sound: sound {
+	};
+};
+
+&gpio {
+	spi0_pins: spi0_pins {
+		brcm,pins = <7 8 9 10 11>;
+		brcm,function = <4>; /* alt0 */
+	};
+
+	i2c0_pins: i2c0 {
+		brcm,pins = <0 1>;
+		brcm,function = <4>;
+	};
+
+	i2c1_pins: i2c1 {
+		brcm,pins = <2 3>;
+		brcm,function = <4>;
+	};
+
+	i2s_pins: i2s {
+		brcm,pins = <18 19 20 21>;
+		brcm,function = <4>; /* alt0 */
+	};
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi0_pins>;
+
+	spidev@0{
+		compatible = "spidev";
+		reg = <0>;	/* CE0 */
+		#address-cells = <1>;
+		#size-cells = <0>;
+		spi-max-frequency = <500000>;
+	};
+
+	spidev@1{
+		compatible = "spidev";
+		reg = <1>;	/* CE1 */
+		#address-cells = <1>;
+		#size-cells = <0>;
+		spi-max-frequency = <500000>;
+	};
+};
+
+&i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c0_pins>;
+	clock-frequency = <100000>;
+};
+
+&i2c1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
+	clock-frequency = <100000>;
+};
+
+&i2s {
+	#sound-dai-cells = <0>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2s_pins>;
+};
--- a/arch/arm/boot/dts/bcm2708-rpi-b.dts
+++ b/arch/arm/boot/dts/bcm2708-rpi-b.dts
@@ -4,12 +4,18 @@
 
 / {
 	compatible = "brcm,bcm2708";
-	model = "Raspberry Pi";
+	model = "Raspberry Pi Model B";
 
 	aliases {
 		spi0 = &spi0;
 		i2c0 = &i2c0;
 		i2c1 = &i2c1;
+		i2s  = &i2s;
+		gpio = &gpio;
+		sound = &sound;
+	};
+
+	sound: sound {
 	};
 };
 
@@ -28,6 +34,11 @@
 		brcm,pins = <2 3>;
 		brcm,function = <4>;
 	};
+
+	i2s_pins: i2s {
+		brcm,pins = <28 29 30 31>;
+		brcm,function = <4>; /* alt0 */
+	};
 };
 
 &spi0 {
@@ -62,3 +73,9 @@
 	pinctrl-0 = <&i2c1_pins>;
 	clock-frequency = <100000>;
 };
+
+&i2s {
+	#sound-dai-cells = <0>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2s_pins>;
+};
--- a/arch/arm/boot/dts/bcm2708.dtsi
+++ b/arch/arm/boot/dts/bcm2708.dtsi
@@ -7,11 +7,8 @@
 	interrupt-parent = <&intc>;
 
 	chosen {
-		/*
-		   bootargs must be 1024 characters long because the
-		   VC bootloader can't expand it
-		*/
-		bootargs = "console=ttyAMA0                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 ";
+		/* No padding required - the boot loader can do that. */
+		bootargs = "";
 	};
 
 	soc {
@@ -39,6 +36,17 @@
 			#interrupt-cells = <2>;
 		};
 
+		i2s: i2s@7e203000 {
+			compatible = "brcm,bcm2708-i2s";
+			reg = <0x7e203000 0x20>,
+			      <0x7e101098 0x02>;
+
+			//dmas = <&dma 2>,
+			//       <&dma 3>;
+			dma-names = "tx", "rx";
+			status = "disabled";
+		};
+
 		spi0: spi@7e204000 {
 			compatible = "brcm,bcm2708-spi";
 			reg = <0x7e204000 0x1000>;
--- /dev/null
+++ b/arch/arm/boot/dts/hifiberry-dac-overlay.dts
@@ -0,0 +1,34 @@
+// Definitions for HiFiBerry DAC
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2708";
+
+	fragment@0 {
+		target = <&sound>;
+		__overlay__ {
+			compatible = "hifiberry,hifiberry-dac";
+			i2s-controller = <&i2s>;
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target-path = "/";
+		__overlay__ {
+			pcm5102a-codec {
+				#sound-dai-cells = <0>;
+				compatible = "ti,pcm5102a";
+				status = "okay";
+			};
+		};
+	};
+};
--- /dev/null
+++ b/arch/arm/boot/dts/hifiberry-dacplus-overlay.dts
@@ -0,0 +1,39 @@
+// Definitions for HiFiBerry DAC+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2708";
+
+	fragment@0 {
+		target = <&sound>;
+		__overlay__ {
+			compatible = "hifiberry,hifiberry-dacplus";
+			i2s-controller = <&i2s>;
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			pcm5122@4d {
+				#sound-dai-cells = <0>;
+				compatible = "ti,pcm5122";
+				reg = <0x4d>;
+				status = "okay";
+			};
+		};
+	};
+};
--- /dev/null
+++ b/arch/arm/boot/dts/hifiberry-digi-overlay.dts
@@ -0,0 +1,39 @@
+// Definitions for HiFiBerry Digi
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2708";
+
+	fragment@0 {
+		target = <&sound>;
+		__overlay__ {
+			compatible = "hifiberry,hifiberry-digi";
+			i2s-controller = <&i2s>;
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			wm8804@3b {
+				#sound-dai-cells = <0>;
+				compatible = "wlf,wm8804";
+				reg = <0x3b>;
+				status = "okay";
+			};
+		};
+	};
+};
--- /dev/null
+++ b/arch/arm/boot/dts/iqaudio-dac-overlay.dts
@@ -0,0 +1,39 @@
+// Definitions for IQaudIO DAC
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2708";
+
+	fragment@0 {
+		target = <&sound>;
+		__overlay__ {
+			compatible = "iqaudio,iqaudio-dac";
+			i2s-controller = <&i2s>;
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			pcm5122@4c {
+				#sound-dai-cells = <0>;
+				compatible = "ti,pcm5122";
+				reg = <0x4c>;
+				status = "okay";
+			};
+		};
+	};
+};
--- /dev/null
+++ b/arch/arm/boot/dts/iqaudio-dacplus-overlay.dts
@@ -0,0 +1,39 @@
+// Definitions for IQaudIO DAC+
+/dts-v1/;
+/plugin/;
+
+/ {
+	compatible = "brcm,bcm2708";
+
+	fragment@0 {
+		target = <&sound>;
+		__overlay__ {
+			compatible = "iqaudio,iqaudio-dac";
+			i2s-controller = <&i2s>;
+			status = "okay";
+		};
+	};
+
+	fragment@1 {
+		target = <&i2s>;
+		__overlay__ {
+			status = "okay";
+		};
+	};
+
+	fragment@2 {
+		target = <&i2c1>;
+		__overlay__ {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			pcm5122@4c {
+				#sound-dai-cells = <0>;
+				compatible = "ti,pcm5122";
+				reg = <0x4c>;
+				status = "okay";
+			};
+		};
+	};
+};
--- a/sound/soc/bcm/hifiberry_dac.c
+++ b/sound/soc/bcm/hifiberry_dac.c
@@ -72,6 +72,21 @@ static int snd_rpi_hifiberry_dac_probe(s
 	int ret = 0;
 
 	snd_rpi_hifiberry_dac.dev = &pdev->dev;
+
+	if (pdev->dev.of_node) {
+	    struct device_node *i2s_node;
+	    struct snd_soc_dai_link *dai = &snd_rpi_hifiberry_dac_dai[0];
+	    i2s_node = of_parse_phandle(pdev->dev.of_node,
+					"i2s-controller", 0);
+
+	    if (i2s_node) {
+		dai->cpu_dai_name = NULL;
+		dai->cpu_of_node = i2s_node;
+		dai->platform_name = NULL;
+		dai->platform_of_node = i2s_node;
+	    }
+	}
+
 	ret = snd_soc_register_card(&snd_rpi_hifiberry_dac);
 	if (ret)
 		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret);
@@ -84,10 +99,17 @@ static int snd_rpi_hifiberry_dac_remove(
 	return snd_soc_unregister_card(&snd_rpi_hifiberry_dac);
 }
 
+static const struct of_device_id snd_rpi_hifiberry_dac_of_match[] = {
+	{ .compatible = "hifiberry,hifiberry-dac", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_dac_of_match);
+
 static struct platform_driver snd_rpi_hifiberry_dac_driver = {
         .driver = {
                 .name   = "snd-hifiberry-dac",
                 .owner  = THIS_MODULE,
+		.of_match_table = snd_rpi_hifiberry_dac_of_match,
         },
         .probe          = snd_rpi_hifiberry_dac_probe,
         .remove         = snd_rpi_hifiberry_dac_remove,
--- a/sound/soc/bcm/hifiberry_dacplus.c
+++ b/sound/soc/bcm/hifiberry_dacplus.c
@@ -90,6 +90,21 @@ static int snd_rpi_hifiberry_dacplus_pro
 	int ret = 0;
 
 	snd_rpi_hifiberry_dacplus.dev = &pdev->dev;
+
+	if (pdev->dev.of_node) {
+	    struct device_node *i2s_node;
+	    struct snd_soc_dai_link *dai = &snd_rpi_hifiberry_dacplus_dai[0];
+	    i2s_node = of_parse_phandle(pdev->dev.of_node,
+					"i2s-controller", 0);
+
+	    if (i2s_node) {
+		dai->cpu_dai_name = NULL;
+		dai->cpu_of_node = i2s_node;
+		dai->platform_name = NULL;
+		dai->platform_of_node = i2s_node;
+	    }
+	}
+
 	ret = snd_soc_register_card(&snd_rpi_hifiberry_dacplus);
 	if (ret)
 		dev_err(&pdev->dev,
@@ -103,10 +118,17 @@ static int snd_rpi_hifiberry_dacplus_rem
 	return snd_soc_unregister_card(&snd_rpi_hifiberry_dacplus);
 }
 
+static const struct of_device_id snd_rpi_hifiberry_dacplus_of_match[] = {
+	{ .compatible = "hifiberry,hifiberry-dacplus", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_dacplus_of_match);
+
 static struct platform_driver snd_rpi_hifiberry_dacplus_driver = {
 	.driver = {
 		.name   = "snd-rpi-hifiberry-dacplus",
 		.owner  = THIS_MODULE,
+		.of_match_table = snd_rpi_hifiberry_dacplus_of_match,
 	},
 	.probe          = snd_rpi_hifiberry_dacplus_probe,
 	.remove         = snd_rpi_hifiberry_dacplus_remove,
--- a/sound/soc/bcm/hifiberry_digi.c
+++ b/sound/soc/bcm/hifiberry_digi.c
@@ -125,6 +125,21 @@ static int snd_rpi_hifiberry_digi_probe(
 	int ret = 0;
 
 	snd_rpi_hifiberry_digi.dev = &pdev->dev;
+
+	if (pdev->dev.of_node) {
+	    struct device_node *i2s_node;
+	    struct snd_soc_dai_link *dai = &snd_rpi_hifiberry_digi_dai[0];
+	    i2s_node = of_parse_phandle(pdev->dev.of_node,
+					"i2s-controller", 0);
+
+	    if (i2s_node) {
+		dai->cpu_dai_name = NULL;
+		dai->cpu_of_node = i2s_node;
+		dai->platform_name = NULL;
+		dai->platform_of_node = i2s_node;
+	    }
+	}
+
 	ret = snd_soc_register_card(&snd_rpi_hifiberry_digi);
 	if (ret)
 		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret);
@@ -137,10 +152,17 @@ static int snd_rpi_hifiberry_digi_remove
 	return snd_soc_unregister_card(&snd_rpi_hifiberry_digi);
 }
 
+static const struct of_device_id snd_rpi_hifiberry_digi_of_match[] = {
+	{ .compatible = "hifiberry,hifiberry-digi", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_digi_of_match);
+
 static struct platform_driver snd_rpi_hifiberry_digi_driver = {
 	.driver = {
 		.name   = "snd-hifiberry-digi",
 		.owner  = THIS_MODULE,
+		.of_match_table = snd_rpi_hifiberry_digi_of_match,
 	},
 	.probe          = snd_rpi_hifiberry_digi_probe,
 	.remove         = snd_rpi_hifiberry_digi_remove,
--- a/sound/soc/bcm/iqaudio-dac.c
+++ b/sound/soc/bcm/iqaudio-dac.c
@@ -76,6 +76,21 @@ static int snd_rpi_iqaudio_dac_probe(str
 	int ret = 0;
 
 	snd_rpi_iqaudio_dac.dev = &pdev->dev;
+
+	if (pdev->dev.of_node) {
+	    struct device_node *i2s_node;
+	    struct snd_soc_dai_link *dai = &snd_rpi_iqaudio_dac_dai[0];
+	    i2s_node = of_parse_phandle(pdev->dev.of_node,
+					"i2s-controller", 0);
+
+	    if (i2s_node) {
+		dai->cpu_dai_name = NULL;
+		dai->cpu_of_node = i2s_node;
+		dai->platform_name = NULL;
+		dai->platform_of_node = i2s_node;
+	    }
+	}
+
 	ret = snd_soc_register_card(&snd_rpi_iqaudio_dac);
 	if (ret)
 		dev_err(&pdev->dev,
@@ -93,6 +108,7 @@ static const struct of_device_id iqaudio
 	{ .compatible = "iqaudio,iqaudio-dac", },
 	{},
 };
+MODULE_DEVICE_TABLE(of, iqaudio_of_match);
 
 static struct platform_driver snd_rpi_iqaudio_dac_driver = {
 	.driver = {
--- a/sound/soc/codecs/pcm5102a.c
+++ b/sound/soc/codecs/pcm5102a.c
@@ -47,12 +47,19 @@ static int pcm5102a_remove(struct platfo
 	return 0;
 }
 
+static const struct of_device_id pcm5102a_of_match[] = {
+	{ .compatible = "ti,pcm5102a", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, pcm5102a_of_match);
+
 static struct platform_driver pcm5102a_codec_driver = {
 	.probe 		= pcm5102a_probe,
 	.remove 	= pcm5102a_remove,
 	.driver		= {
 		.name	= "pcm5102a-codec",
 		.owner	= THIS_MODULE,
+		.of_match_table = pcm5102a_of_match,
 	},
 };