$(eval $(call KernelPackage,sound-soc-hifiberry-dacplusdsp))
+define KernelPackage/sound-soc-hifiberry-dacplushd
+ TITLE:=Support for HifiBerry DAC+HD
+ KCONFIG:= \
+ CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD \
+ CONFIG_SND_SOC_PCM179X \
+ CONFIG_SND_SOC_PCM179X_I2C
+ FILES:= \
+ $(LINUX_DIR)/drivers/clk/clk-hifiberry-dachd.ko \
+ $(LINUX_DIR)/sound/soc/bcm/snd-soc-hifiberry-dacplushd.ko \
+ $(LINUX_DIR)/sound/soc/codecs/snd-soc-pcm179x-codec.ko \
+ $(LINUX_DIR)/sound/soc/codecs/snd-soc-pcm179x-i2c.ko
+ AUTOLOAD:=$(call AutoLoad,68,clk-hifiberry-dachd snd-soc-pcm179x-codec \
+ snd-soc-pcm179x-i2c snd-soc-hifiberry-dacplushd)
+ DEPENDS:= \
+ kmod-sound-soc-bcm2835-i2s \
+ +kmod-i2c-bcm2835 \
+ +kmod-regmap-i2c
+ $(call AddDepends/sound)
+endef
+
+define KernelPackage/sound-soc-hifiberry-dacplushd/description
+ This package contains support for HifiBerry DAC+HD
+endef
+
+$(eval $(call KernelPackage,sound-soc-hifiberry-dacplushd))
+
+
define KernelPackage/sound-soc-hifiberry-dacplusadc-pro
TITLE:=Support for HifiBerry DAC+ADC PRO
KCONFIG:= \
$(eval $(call KernelPackage,sound-soc-i-sabe-q2m))
+define KernelPackage/sound-soc-justboom-both
+ TITLE:=Support for JustBoom DAC and Digi
+ KCONFIG:= \
+ CONFIG_SND_BCM2708_SOC_JUSTBOOM_BOTH \
+ CONFIG_SND_SOC_PCM512x \
+ CONFIG_SND_SOC_WM8804
+ FILES:= \
+ $(LINUX_DIR)/sound/soc/bcm/snd-soc-justboom-both.ko \
+ $(LINUX_DIR)/sound/soc/codecs/snd-soc-pcm512x.ko \
+ $(LINUX_DIR)/sound/soc/codecs/snd-soc-wm8804.ko
+ AUTOLOAD:=$(call AutoLoad,68,snd-soc-pcm512x snd-soc-wm8804 \
+ snd-soc-justboom-both)
+ DEPENDS:= \
+ kmod-sound-soc-bcm2835-i2s \
+ +kmod-sound-soc-rpi-wm8804-soundcard \
+ +kmod-i2c-bcm2835
+ $(call AddDepends/sound)
+endef
+
+define KernelPackage/sound-soc-justboom-both/description
+ This package contains support for JustBoom DAC and Digi
+endef
+
+$(eval $(call KernelPackage,sound-soc-justboom-both))
+
+
define KernelPackage/sound-soc-justboom-dac
TITLE:=Support for JustBoom DAC
KCONFIG:= \
--- /dev/null
+From 05c745c001c8c82bbba8a6d953ad77ad25c92c5f Mon Sep 17 00:00:00 2001
+From: popcornmix <popcornmix@gmail.com>
+Date: Thu, 7 Nov 2019 14:11:08 +0000
+Subject: [PATCH] fixup! clk-raspberrypi: Also support v3d clock
+
+---
+ drivers/clk/bcm/clk-raspberrypi.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/clk/bcm/clk-raspberrypi.c
++++ b/drivers/clk/bcm/clk-raspberrypi.c
+@@ -351,21 +351,21 @@ static const struct clk_ops raspberrypi_
+ .is_prepared = raspberrypi_fw_pll_is_on,
+ .recalc_rate = raspberrypi_fw_pll_get_rate,
+ .set_rate = raspberrypi_fw_pll_set_rate,
+- .determine_rate = raspberrypi_pll_determine_rate,
++ //.determine_rate = raspberrypi_pll_determine_rate,
+ };
+
+ static const struct clk_ops raspberrypi_firmware_pll_divider_clk_ops = {
+ .is_prepared = raspberrypi_fw_pll_div_is_on,
+ .recalc_rate = raspberrypi_fw_pll_div_get_rate,
+ .set_rate = raspberrypi_fw_pll_div_set_rate,
+- .determine_rate = raspberrypi_pll_div_determine_rate,
++ //.determine_rate = raspberrypi_pll_div_determine_rate,
+ };
+
+ static const struct clk_ops raspberrypi_firmware_clk_ops = {
+ .is_prepared = raspberrypi_fw_clock_is_on,
+ .recalc_rate = raspberrypi_fw_clock_get_rate,
+ .set_rate = raspberrypi_fw_clock_set_rate,
+- .determine_rate = raspberrypi_clock_determine_rate,
++ //.determine_rate = raspberrypi_clock_determine_rate,
+ };
+
+
-From 05c745c001c8c82bbba8a6d953ad77ad25c92c5f Mon Sep 17 00:00:00 2001
+From afb2cfe3056fc643cee8ae25991f4b9c22d48bef Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
-Date: Thu, 7 Nov 2019 14:11:08 +0000
+Date: Thu, 7 Nov 2019 14:23:38 +0000
Subject: [PATCH] fixup! clk-raspberrypi: Also support v3d clock
---
- drivers/clk/bcm/clk-raspberrypi.c | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
+ drivers/clk/bcm/clk-raspberrypi.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
--- a/drivers/clk/bcm/clk-raspberrypi.c
+++ b/drivers/clk/bcm/clk-raspberrypi.c
-@@ -351,21 +351,21 @@ static const struct clk_ops raspberrypi_
+@@ -208,6 +208,9 @@ static int raspberrypi_determine_rate(st
+ u32 clock_id, const char *name, unsigned long min_rate, unsigned long max_rate,
+ struct clk_rate_request *req)
+ {
++#if 1
++ req->rate = clamp(req->rate, min_rate, max_rate);
++#else
+ u64 div, final_rate;
+ u32 ndiv, fdiv;
+
+@@ -225,6 +228,7 @@ static int raspberrypi_determine_rate(st
+
+ req->rate = final_rate >> A2W_PLL_FRAC_BITS;
+
++#endif
+ return 0;
+ }
+
+@@ -351,21 +355,21 @@ static const struct clk_ops raspberrypi_
.is_prepared = raspberrypi_fw_pll_is_on,
.recalc_rate = raspberrypi_fw_pll_get_rate,
.set_rate = raspberrypi_fw_pll_set_rate,
-- .determine_rate = raspberrypi_pll_determine_rate,
-+ //.determine_rate = raspberrypi_pll_determine_rate,
+- //.determine_rate = raspberrypi_pll_determine_rate,
++ .determine_rate = raspberrypi_pll_determine_rate,
};
static const struct clk_ops raspberrypi_firmware_pll_divider_clk_ops = {
.is_prepared = raspberrypi_fw_pll_div_is_on,
.recalc_rate = raspberrypi_fw_pll_div_get_rate,
.set_rate = raspberrypi_fw_pll_div_set_rate,
-- .determine_rate = raspberrypi_pll_div_determine_rate,
-+ //.determine_rate = raspberrypi_pll_div_determine_rate,
+- //.determine_rate = raspberrypi_pll_div_determine_rate,
++ .determine_rate = raspberrypi_pll_div_determine_rate,
};
static const struct clk_ops raspberrypi_firmware_clk_ops = {
.is_prepared = raspberrypi_fw_clock_is_on,
.recalc_rate = raspberrypi_fw_clock_get_rate,
.set_rate = raspberrypi_fw_clock_set_rate,
-- .determine_rate = raspberrypi_clock_determine_rate,
-+ //.determine_rate = raspberrypi_clock_determine_rate,
+- //.determine_rate = raspberrypi_clock_determine_rate,
++ .determine_rate = raspberrypi_clock_determine_rate,
};
+++ /dev/null
-From afb2cfe3056fc643cee8ae25991f4b9c22d48bef Mon Sep 17 00:00:00 2001
-From: popcornmix <popcornmix@gmail.com>
-Date: Thu, 7 Nov 2019 14:23:38 +0000
-Subject: [PATCH] fixup! clk-raspberrypi: Also support v3d clock
-
----
- drivers/clk/bcm/clk-raspberrypi.c | 10 +++++++---
- 1 file changed, 7 insertions(+), 3 deletions(-)
-
---- a/drivers/clk/bcm/clk-raspberrypi.c
-+++ b/drivers/clk/bcm/clk-raspberrypi.c
-@@ -208,6 +208,9 @@ static int raspberrypi_determine_rate(st
- u32 clock_id, const char *name, unsigned long min_rate, unsigned long max_rate,
- struct clk_rate_request *req)
- {
-+#if 1
-+ req->rate = clamp(req->rate, min_rate, max_rate);
-+#else
- u64 div, final_rate;
- u32 ndiv, fdiv;
-
-@@ -225,6 +228,7 @@ static int raspberrypi_determine_rate(st
-
- req->rate = final_rate >> A2W_PLL_FRAC_BITS;
-
-+#endif
- return 0;
- }
-
-@@ -351,21 +355,21 @@ static const struct clk_ops raspberrypi_
- .is_prepared = raspberrypi_fw_pll_is_on,
- .recalc_rate = raspberrypi_fw_pll_get_rate,
- .set_rate = raspberrypi_fw_pll_set_rate,
-- //.determine_rate = raspberrypi_pll_determine_rate,
-+ .determine_rate = raspberrypi_pll_determine_rate,
- };
-
- static const struct clk_ops raspberrypi_firmware_pll_divider_clk_ops = {
- .is_prepared = raspberrypi_fw_pll_div_is_on,
- .recalc_rate = raspberrypi_fw_pll_div_get_rate,
- .set_rate = raspberrypi_fw_pll_div_set_rate,
-- //.determine_rate = raspberrypi_pll_div_determine_rate,
-+ .determine_rate = raspberrypi_pll_div_determine_rate,
- };
-
- static const struct clk_ops raspberrypi_firmware_clk_ops = {
- .is_prepared = raspberrypi_fw_clock_is_on,
- .recalc_rate = raspberrypi_fw_clock_get_rate,
- .set_rate = raspberrypi_fw_clock_set_rate,
-- //.determine_rate = raspberrypi_clock_determine_rate,
-+ .determine_rate = raspberrypi_clock_determine_rate,
- };
-
-
--- /dev/null
+From e1bbcb1097b9d968ae61397a66a73a440a0ce705 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 6 Jan 2020 16:04:30 +0000
+Subject: [PATCH] pinctrl: bcm2835: Remove gpiochip on error
+
+A failure in gpiochip_irqchip_add leads to a leak of a gpiochip. Fix
+the leak with the use of devm_gpiochip_add_data.
+
+Fixes: 85ae9e512f43 ("pinctrl: bcm2835: switch to GPIOLIB_IRQCHIP")
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/pinctrl/bcm/pinctrl-bcm2835.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
++++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+@@ -1140,7 +1140,7 @@ static int bcm2835_pinctrl_probe(struct
+ raw_spin_lock_init(&pc->irq_lock[i]);
+ }
+
+- err = gpiochip_add_data(&pc->gpio_chip, pc);
++ err = devm_gpiochip_add_data(dev, &pc->gpio_chip, pc);
+ if (err) {
+ dev_err(dev, "could not add GPIO chip\n");
+ return err;
--- /dev/null
+From 0b3764707993123148b4e94d44ff282b111c8edb Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Mon, 6 Jan 2020 14:05:42 +0000
+Subject: [PATCH] pinctrl: bcm2835: Change init order for gpio hogs
+
+pinctrl-bcm2835 is a combined pinctrl/gpio driver. Currently the gpio
+side is registered first, but this breaks gpio hogs (which are
+configured during gpiochip_add_data). Part of the hog initialisation
+is a call to pinctrl_gpio_request, and since the pinctrl driver hasn't
+yet been registered this results in an -EPROBE_DEFER from which it can
+never recover.
+
+Change the initialisation sequence to register the pinctrl driver
+first.
+
+See: https://www.raspberrypi.org/forums/viewtopic.php?f=107&t=260600
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/pinctrl/bcm/pinctrl-bcm2835.c | 34 +++++++++++++--------------
+ 1 file changed, 17 insertions(+), 17 deletions(-)
+
+--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
++++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+@@ -1140,9 +1140,25 @@ static int bcm2835_pinctrl_probe(struct
+ raw_spin_lock_init(&pc->irq_lock[i]);
+ }
+
++ match = of_match_node(bcm2835_pinctrl_match, pdev->dev.of_node);
++ if (match) {
++ bcm2835_pinctrl_desc.confops =
++ (const struct pinconf_ops *)match->data;
++ }
++
++ pc->pctl_dev = devm_pinctrl_register(dev, &bcm2835_pinctrl_desc, pc);
++ if (IS_ERR(pc->pctl_dev))
++ return PTR_ERR(pc->pctl_dev);
++
++ pc->gpio_range = bcm2835_pinctrl_gpio_range;
++ pc->gpio_range.base = pc->gpio_chip.base;
++ pc->gpio_range.gc = &pc->gpio_chip;
++ pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range);
++
+ err = devm_gpiochip_add_data(dev, &pc->gpio_chip, pc);
+ if (err) {
+ dev_err(dev, "could not add GPIO chip\n");
++ pinctrl_remove_gpio_range(pc->pctl_dev, &pc->gpio_range);
+ return err;
+ }
+
+@@ -1150,6 +1166,7 @@ static int bcm2835_pinctrl_probe(struct
+ 0, handle_level_irq, IRQ_TYPE_NONE);
+ if (err) {
+ dev_info(dev, "could not add irqchip\n");
++ pinctrl_remove_gpio_range(pc->pctl_dev, &pc->gpio_range);
+ return err;
+ }
+
+@@ -1172,23 +1189,6 @@ static int bcm2835_pinctrl_probe(struct
+ bcm2835_gpio_irq_handler);
+ }
+
+- match = of_match_node(bcm2835_pinctrl_match, pdev->dev.of_node);
+- if (match) {
+- bcm2835_pinctrl_desc.confops =
+- (const struct pinconf_ops *)match->data;
+- }
+-
+- pc->pctl_dev = devm_pinctrl_register(dev, &bcm2835_pinctrl_desc, pc);
+- if (IS_ERR(pc->pctl_dev)) {
+- gpiochip_remove(&pc->gpio_chip);
+- return PTR_ERR(pc->pctl_dev);
+- }
+-
+- pc->gpio_range = bcm2835_pinctrl_gpio_range;
+- pc->gpio_range.base = pc->gpio_chip.base;
+- pc->gpio_range.gc = &pc->gpio_chip;
+- pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range);
+-
+ return 0;
+ }
+
--- /dev/null
+From 5b12b655f266ea29e91a7b7a46385df05bb70ed8 Mon Sep 17 00:00:00 2001
+From: Giedrius <giedrius@blokas.io>
+Date: Tue, 7 Jan 2020 11:04:21 +0200
+Subject: [PATCH] Pisound: MIDI communication fixes for scaled down
+ CPU.
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+* Increased maximum SPI communication speed to avoid running too slow
+ when the CPU is scaled down and losing MIDI data.
+
+* Keep track of buffer usage in millibytes for higher precision.
+
+Signed-off-by: Giedrius Trainavičius <giedrius@blokas.io>
+---
+ sound/soc/bcm/pisound.c | 31 ++++++++++++++++++-------------
+ 1 file changed, 18 insertions(+), 13 deletions(-)
+
+--- a/sound/soc/bcm/pisound.c
++++ b/sound/soc/bcm/pisound.c
+@@ -1,6 +1,6 @@
+ /*
+ * Pisound Linux kernel module.
+- * Copyright (C) 2016-2019 Vilniaus Blokas UAB, https://blokas.io/pisound
++ * Copyright (C) 2016-2020 Vilniaus Blokas UAB, https://blokas.io/pisound
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+@@ -326,7 +326,7 @@ static void spi_transfer(const uint8_t *
+ transfer.tx_buf = txbuf;
+ transfer.rx_buf = rxbuf;
+ transfer.len = len;
+- transfer.speed_hz = 100000;
++ transfer.speed_hz = 150000;
+ transfer.delay_usecs = 10;
+ spi_message_add_tail(&transfer, &msg);
+
+@@ -403,9 +403,9 @@ static struct spi_device *pisnd_spi_find
+ static void pisnd_work_handler(struct work_struct *work)
+ {
+ enum { TRANSFER_SIZE = 4 };
+- enum { PISOUND_OUTPUT_BUFFER_SIZE = 128 };
+- enum { MIDI_BYTES_PER_SECOND = 3125 };
+- int out_buffer_used = 0;
++ enum { PISOUND_OUTPUT_BUFFER_SIZE_MILLIBYTES = 127 * 1000 };
++ enum { MIDI_MILLIBYTES_PER_JIFFIE = (3125 * 1000) / HZ };
++ int out_buffer_used_millibytes = 0;
+ unsigned long now;
+ uint8_t val;
+ uint8_t txbuf[TRANSFER_SIZE];
+@@ -445,7 +445,9 @@ static void pisnd_work_handler(struct wo
+ had_data = false;
+ memset(txbuf, 0, sizeof(txbuf));
+ for (i = 0; i < sizeof(txbuf) &&
+- out_buffer_used < PISOUND_OUTPUT_BUFFER_SIZE;
++ ((out_buffer_used_millibytes+1000 <
++ PISOUND_OUTPUT_BUFFER_SIZE_MILLIBYTES) ||
++ g_ledFlashDurationChanged);
+ i += 2) {
+
+ val = 0;
+@@ -458,7 +460,7 @@ static void pisnd_work_handler(struct wo
+ } else if (kfifo_get(&spi_fifo_out, &val)) {
+ txbuf[i+0] = 0x0f;
+ txbuf[i+1] = val;
+- ++out_buffer_used;
++ out_buffer_used_millibytes += 1000;
+ }
+ }
+
+@@ -469,12 +471,14 @@ static void pisnd_work_handler(struct wo
+ * rate.
+ */
+ now = jiffies;
+- out_buffer_used -=
+- (MIDI_BYTES_PER_SECOND / HZ) /
+- (now - last_transfer_at);
+- if (out_buffer_used < 0)
+- out_buffer_used = 0;
+- last_transfer_at = now;
++ if (now != last_transfer_at) {
++ out_buffer_used_millibytes -=
++ (now - last_transfer_at) *
++ MIDI_MILLIBYTES_PER_JIFFIE;
++ if (out_buffer_used_millibytes < 0)
++ out_buffer_used_millibytes = 0;
++ last_transfer_at = now;
++ }
+
+ for (i = 0; i < sizeof(rxbuf); i += 2) {
+ if (rxbuf[i]) {
+@@ -489,6 +493,7 @@ static void pisnd_work_handler(struct wo
+ || !kfifo_is_empty(&spi_fifo_out)
+ || pisnd_spi_has_more()
+ || g_ledFlashDurationChanged
++ || out_buffer_used_millibytes != 0
+ );
+
+ if (!kfifo_is_empty(&spi_fifo_in) && g_recvCallback)
--- /dev/null
+From 1738aaf187e0c8e97fbdd9661960b835f45e8985 Mon Sep 17 00:00:00 2001
+From: Zahari Petkov <zahari@balena.io>
+Date: Mon, 18 Nov 2019 23:02:55 +0200
+Subject: [PATCH] leds: pca963x: Fix open-drain initialization
+
+commit 697529091ac7a0a90ca349b914bb30641c13c753 upstream.
+
+Before commit bb29b9cccd95 ("leds: pca963x: Add bindings to invert
+polarity") Mode register 2 was initialized directly with either 0x01
+or 0x05 for open-drain or totem pole (push-pull) configuration.
+
+Afterwards, MODE2 initialization started using bitwise operations on
+top of the default MODE2 register value (0x05). Using bitwise OR for
+setting OUTDRV with 0x01 and 0x05 does not produce correct results.
+When open-drain is used, instead of setting OUTDRV to 0, the driver
+keeps it as 1:
+
+Open-drain: 0x05 | 0x01 -> 0x05 (0b101 - incorrect)
+Totem pole: 0x05 | 0x05 -> 0x05 (0b101 - correct but still wrong)
+
+Now OUTDRV setting uses correct bitwise operations for initialization:
+
+Open-drain: 0x05 & ~0x04 -> 0x01 (0b001 - correct)
+Totem pole: 0x05 | 0x04 -> 0x05 (0b101 - correct)
+
+Additional MODE2 register definitions are introduced now as well.
+
+Fixes: bb29b9cccd95 ("leds: pca963x: Add bindings to invert polarity")
+Signed-off-by: Zahari Petkov <zahari@balena.io>
+Signed-off-by: Pavel Machek <pavel@ucw.cz>
+---
+ drivers/leds/leds-pca963x.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+--- a/drivers/leds/leds-pca963x.c
++++ b/drivers/leds/leds-pca963x.c
+@@ -43,6 +43,8 @@
+ #define PCA963X_LED_PWM 0x2 /* Controlled through PWM */
+ #define PCA963X_LED_GRP_PWM 0x3 /* Controlled through PWM/GRPPWM */
+
++#define PCA963X_MODE2_OUTDRV 0x04 /* Open-drain or totem pole */
++#define PCA963X_MODE2_INVRT 0x10 /* Normal or inverted direction */
+ #define PCA963X_MODE2_DMBLNK 0x20 /* Enable blinking */
+
+ #define PCA963X_MODE1 0x00
+@@ -462,12 +464,12 @@ static int pca963x_probe(struct i2c_clie
+ PCA963X_MODE2);
+ /* Configure output: open-drain or totem pole (push-pull) */
+ if (pdata->outdrv == PCA963X_OPEN_DRAIN)
+- mode2 |= 0x01;
++ mode2 &= ~PCA963X_MODE2_OUTDRV;
+ else
+- mode2 |= 0x05;
++ mode2 |= PCA963X_MODE2_OUTDRV;
+ /* Configure direction: normal or inverted */
+ if (pdata->dir == PCA963X_INVERTED)
+- mode2 |= 0x10;
++ mode2 |= PCA963X_MODE2_INVRT;
+ i2c_smbus_write_byte_data(pca963x->chip->client, PCA963X_MODE2,
+ mode2);
+ }
--- /dev/null
+From ca88aee39825dd81ef1e8306b5947c5ae3918d1a Mon Sep 17 00:00:00 2001
+From: Willem Remie <w.remie@drebble.io>
+Date: Thu, 9 Jan 2020 21:16:49 +0100
+Subject: [PATCH] add BME680 to i2c-sensor overlay
+
+---
+ arch/arm/boot/dts/overlays/README | 7 +++++--
+ .../boot/dts/overlays/i2c-sensor-overlay.dts | 19 ++++++++++++++++++-
+ 2 files changed, 23 insertions(+), 3 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -1159,12 +1159,15 @@ Name: i2c-sensor
+ Info: Adds support for a number of I2C barometric pressure and temperature
+ sensors on i2c_arm
+ Load: dtoverlay=i2c-sensor,<param>=<val>
+-Params: addr Set the address for the BME280, BMP280, DS1621,
+- HDC100X, LM75, SHT3x or TMP102
++Params: addr Set the address for the BME280, BME680, BMP280,
++ DS1621, HDC100X, LM75, SHT3x or TMP102
+
+ bme280 Select the Bosch Sensortronic BME280
+ Valid addresses 0x76-0x77, default 0x76
+
++ bme680 Select the Bosch Sensortronic BME680
++ Valid addresses 0x76-0x77, default 0x76
++
+ bmp085 Select the Bosch Sensortronic BMP085
+
+ bmp180 Select the Bosch Sensortronic BMP180
+--- a/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c-sensor-overlay.dts
+@@ -216,10 +216,26 @@
+ };
+ };
+
++ fragment@14 {
++ target = <&i2c_arm>;
++ __dormant__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ bme680: bme680@76 {
++ compatible = "bosch,bme680";
++ reg = <0x76>;
++ status = "okay";
++ };
++ };
++ };
++
++
+ __overrides__ {
+ addr = <&bme280>,"reg:0", <&bmp280>,"reg:0", <&tmp102>,"reg:0",
+ <&lm75>,"reg:0", <&hdc100x>,"reg:0", <&sht3x>,"reg:0",
+- <&ds1621>,"reg:0";
++ <&ds1621>,"reg:0", <&bme680>,"reg:0";
+ bme280 = <0>,"+0";
+ bmp085 = <0>,"+1";
+ bmp180 = <0>,"+2";
+@@ -235,5 +251,6 @@
+ sht3x = <0>,"+11";
+ ds1621 = <0>,"+12";
+ max17040 = <0>,"+13";
++ bme680 = <0>,"+14";
+ };
+ };
--- /dev/null
+From 7ae8ef63c14ca2fea76c9db5799321f1b3e31c36 Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.org>
+Date: Tue, 7 Jan 2020 10:08:19 +0000
+Subject: [PATCH] dwc_otg: constrain endpoint max packet and transfer
+ size on split IN
+
+The hcd would unconditionally set the transfer length to the endpoint
+packet size for non-isoc IN transfers. If the remaining buffer length
+was less than the length of returned data, random memory would get
+scribbled over, with bad effects if it crossed a page boundary.
+
+Force a babble error if this happens by limiting the max transfer size
+to the available buffer space. DMA will stop writing to memory on a
+babble condition.
+
+The hardware expects xfersize to be an integer multiple of maxpacket
+size, so override hcchar.b.mps as well.
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
+---
+ drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
+@@ -1813,7 +1813,7 @@ int fiq_fsm_queue_split_transaction(dwc_
+ st->nr_errors = 0;
+
+ st->hcchar_copy.d32 = 0;
+- st->hcchar_copy.b.mps = hc->max_packet;
++ st->hcchar_copy.b.mps = min_t(uint32_t, hc->xfer_len, hc->max_packet);
+ st->hcchar_copy.b.epdir = hc->ep_is_in;
+ st->hcchar_copy.b.devaddr = hc->dev_addr;
+ st->hcchar_copy.b.epnum = hc->ep_num;
+@@ -1858,7 +1858,7 @@ int fiq_fsm_queue_split_transaction(dwc_
+ st->hctsiz_copy.b.pid = hc->data_pid_start;
+
+ if (hc->ep_is_in || (hc->xfer_len > hc->max_packet)) {
+- hc->xfer_len = hc->max_packet;
++ hc->xfer_len = min_t(uint32_t, hc->xfer_len, hc->max_packet);
+ } else if (!hc->ep_is_in && (hc->xfer_len > 188)) {
+ hc->xfer_len = 188;
+ }
--- /dev/null
+From af6743f045159970b95f6426de13c0fb82678e67 Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.org>
+Date: Wed, 8 Jan 2020 12:48:09 +0000
+Subject: [PATCH] dwc_otg: fiq_fsm: pause when cancelling split
+ transactions
+
+Non-periodic splits will DMA to/from the driver-provided transfer_buffer,
+which may be freed immediately after the dequeue call returns. Block until
+we know the transfer is complete.
+
+A similar delay is needed when cleaning up disconnects, as the FIQ could
+have started a periodic transfer in the previous microframe to the one
+that triggered a disconnect.
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
+---
+ drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 33 +++++++++++++++++++++--
+ drivers/usb/host/dwc_otg/dwc_otg_os_dep.h | 1 +
+ 2 files changed, 32 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
+@@ -175,6 +175,7 @@ static void kill_urbs_in_qh_list(dwc_otg
+ dwc_list_link_t *qh_item, *qh_tmp;
+ dwc_otg_qh_t *qh;
+ dwc_otg_qtd_t *qtd, *qtd_tmp;
++ int quiesced = 0;
+
+ DWC_LIST_FOREACH_SAFE(qh_item, qh_tmp, qh_list) {
+ qh = DWC_LIST_ENTRY(qh_item, dwc_otg_qh_t, qh_list_entry);
+@@ -198,8 +199,17 @@ static void kill_urbs_in_qh_list(dwc_otg
+ qh->channel->halt_status = DWC_OTG_HC_XFER_URB_DEQUEUE;
+ qh->channel->halt_pending = 1;
+ if (hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_TURBO ||
+- hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_SLEEPING)
++ hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_SLEEPING)
+ hcd->fiq_state->channel[n].fsm = FIQ_HS_ISOC_ABORTED;
++ /* We're called from disconnect callback or in the middle of freeing the HCD here,
++ * so FIQ is disabled, top-level interrupts masked and we're holding the spinlock.
++ * No further URBs will be submitted, but wait 1 microframe for any previously
++ * submitted periodic DMA to finish.
++ */
++ if (!quiesced) {
++ udelay(125);
++ quiesced = 1;
++ }
+ } else {
+ dwc_otg_hc_halt(hcd->core_if, qh->channel,
+ DWC_OTG_HC_XFER_URB_DEQUEUE);
+@@ -600,15 +610,34 @@ int dwc_otg_hcd_urb_dequeue(dwc_otg_hcd_
+ /* In FIQ FSM mode, we need to shut down carefully.
+ * The FIQ may attempt to restart a disabled channel */
+ if (fiq_fsm_enable && (hcd->fiq_state->channel[n].fsm != FIQ_PASSTHROUGH)) {
++ int retries = 3;
++ int running = 0;
++ enum fiq_fsm_state state;
++
+ local_fiq_disable();
+ fiq_fsm_spin_lock(&hcd->fiq_state->lock);
+ qh->channel->halt_status = DWC_OTG_HC_XFER_URB_DEQUEUE;
+ qh->channel->halt_pending = 1;
+ if (hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_TURBO ||
+- hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_SLEEPING)
++ hcd->fiq_state->channel[n].fsm == FIQ_HS_ISOC_SLEEPING)
+ hcd->fiq_state->channel[n].fsm = FIQ_HS_ISOC_ABORTED;
+ fiq_fsm_spin_unlock(&hcd->fiq_state->lock);
+ local_fiq_enable();
++
++ if (dwc_qh_is_non_per(qh)) {
++ do {
++ state = READ_ONCE(hcd->fiq_state->channel[n].fsm);
++ running = (state != FIQ_NP_SPLIT_DONE) &&
++ (state != FIQ_NP_SPLIT_LS_ABORTED) &&
++ (state != FIQ_NP_SPLIT_HS_ABORTED);
++ if (!running)
++ break;
++ udelay(125);
++ } while(--retries);
++ if (!retries)
++ DWC_WARN("Timed out waiting for FSM NP transfer to complete on %d",
++ qh->channel->hc_num);
++ }
+ } else {
+ dwc_otg_hc_halt(hcd->core_if, qh->channel,
+ DWC_OTG_HC_XFER_URB_DEQUEUE);
+--- a/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
++++ b/drivers/usb/host/dwc_otg/dwc_otg_os_dep.h
+@@ -27,6 +27,7 @@
+ #include <linux/workqueue.h>
+ #include <linux/stat.h>
+ #include <linux/pci.h>
++#include <linux/compiler.h>
+
+ #include <linux/version.h>
+
--- /dev/null
+From b2d43d61a1d6d070664f10d12b3c8b6df11eb21d Mon Sep 17 00:00:00 2001
+From: Jonathan Bell <jonathan@raspberrypi.org>
+Date: Mon, 13 Jan 2020 15:54:55 +0000
+Subject: [PATCH] dwc_otg: fiq_fsm: add a barrier on entry into FIQ
+ handler(s)
+
+On BCM2835, there is no hardware guarantee that multiple outstanding
+reads to different peripherals will complete in-order. The FIQ code
+uses peripheral reads without barriers for performance, so in the case
+where a read to a slow peripheral was issued immediately prior to FIQ
+entry, the first peripheral read that the FIQ did could end up with
+wrong read data returned.
+
+Add dsb(sy) on entry so that all outstanding reads are retired.
+
+The FIQ only issues reads to the dwc_otg core, so per-read barriers
+in the handler itself are not required.
+
+On BCM2836 and BCM2837 the barrier is not strictly required due to
+differences in how the peripheral bus is implemented, but having
+arch-specific handlers that introduce different latencies is risky.
+
+Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
+---
+ drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
++++ b/drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c
+@@ -1259,6 +1259,9 @@ void notrace dwc_otg_fiq_fsm(struct fiq_
+ haintmsk_data_t haintmsk;
+ int kick_irq = 0;
+
++ /* Ensure peripheral reads issued prior to FIQ entry are complete */
++ dsb(sy);
++
+ gintsts_handled.d32 = 0;
+ haint_handled.d32 = 0;
+
+@@ -1379,6 +1382,9 @@ void notrace dwc_otg_fiq_nop(struct fiq_
+ gintmsk_data_t gintmsk;
+ hfnum_data_t hfnum;
+
++ /* Ensure peripheral reads issued prior to FIQ entry are complete */
++ dsb(sy);
++
+ fiq_fsm_spin_lock(&state->lock);
+ hfnum.d32 = FIQ_READ(state->dwc_regs_base + HFNUM);
+ gintsts.d32 = FIQ_READ(state->dwc_regs_base + GINTSTS);
--- /dev/null
+From 4d19be9132ca10cf582450a86dcb2c41f227f589 Mon Sep 17 00:00:00 2001
+From: Ed Spiridonov <edo.rus@gmail.com>
+Date: Tue, 10 Dec 2019 22:45:04 +0300
+Subject: [PATCH] Add universal device tree overlay for SPI devices
+
+Just specify the SPI address and device name ("compatible" property).
+This overlay lacks any device-specific parameter support!
+(some of them could be added later)
+
+Examples:
+1. SPI NOR flash on spi0.1, maximum SPI clock frequency 45MHz:
+ dtoverlay=anyspi:spi0-1,dev="jedec,spi-nor",speed=45000000
+2. MCP3204 ADC on spi1.2, maximum SPI clock frequency 500kHz:
+ dtoverlay=anyspi:spi1-2,dev="microchip,mcp3204"
+
+Signed-off-by: Ed Spiridonov <edo.rus@gmail.com>
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 23 ++
+ arch/arm/boot/dts/overlays/anyspi-overlay.dts | 205 ++++++++++++++++++
+ 3 files changed, 229 insertions(+)
+ create mode 100755 arch/arm/boot/dts/overlays/anyspi-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -15,6 +15,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ allo-katana-dac-audio.dtbo \
+ allo-piano-dac-pcm512x-audio.dtbo \
+ allo-piano-dac-plus-pcm512x-audio.dtbo \
++ anyspi.dtbo \
+ apds9960.dtbo \
+ applepi-dac.dtbo \
+ at86rf233.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -441,6 +441,29 @@ Params: 24db_digital_gain Allow ga
+ better voice quality. (default Off)
+
+
++Name: anyspi
++Info: Universal device tree overlay for SPI devices
++
++ Just specify the SPI address and device name ("compatible" property).
++ This overlay lacks any device-specific parameter support!
++
++ For devices on spi1 or spi2, the interfaces should be enabled
++ with one of the spi1-1/2/3cs and/or spi2-1/2/3cs overlays.
++
++ Examples:
++ 1. SPI NOR flash on spi0.1, maximum SPI clock frequency 45MHz:
++ dtoverlay=anyspi:spi0-1,dev="jedec,spi-nor",speed=45000000
++ 2. MCP3204 ADC on spi1.2, maximum SPI clock frequency 500kHz:
++ dtoverlay=anyspi:spi1-2,dev="microchip,mcp3204"
++Load: dtoverlay=anyspi,<param>=<val>
++Params: spi<n>-<m> Configure device at spi<n>, cs<m>
++ (boolean, required)
++ dev Set device name to search compatible module
++ (string, required)
++ speed Set SPI clock frequency in Hz
++ (integer, optional, default 500000)
++
++
+ Name: apds9960
+ Info: Configures the AVAGO APDS9960 digital proximity, ambient light, RGB and
+ gesture sensor
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/anyspi-overlay.dts
+@@ -0,0 +1,205 @@
++/*
++ * Universal device tree overlay for SPI devices
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835";
++
++ fragment@0 {
++ target = <&spidev0>;
++ __dormant__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@1 {
++ target = <&spidev1>;
++ __dormant__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@2 {
++ target-path = "spi1/spidev@0";
++ __dormant__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@3 {
++ target-path = "spi1/spidev@1";
++ __dormant__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@4 {
++ target-path = "spi1/spidev@2";
++ __dormant__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@5 {
++ target-path = "spi2/spidev@0";
++ __dormant__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@6 {
++ target-path = "spi2/spidev@1";
++ __dormant__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@7 {
++ target-path = "spi2/spidev@2";
++ __dormant__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@8 {
++ target = <&spi0>;
++ __dormant__ {
++ status = "okay";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ anyspi_00: anyspi@0 {
++ reg = <0>;
++ spi-max-frequency = <500000>;
++ };
++ };
++ };
++
++ fragment@9 {
++ target = <&spi0>;
++ __dormant__ {
++ status = "okay";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ anyspi_01: anyspi@1 {
++ reg = <1>;
++ spi-max-frequency = <500000>;
++ };
++ };
++ };
++
++ fragment@10 {
++ target = <&spi1>;
++ __dormant__ {
++ status = "okay";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ anyspi_10: anyspi@0 {
++ reg = <0>;
++ spi-max-frequency = <500000>;
++ };
++ };
++ };
++
++ fragment@11 {
++ target = <&spi1>;
++ __dormant__ {
++ status = "okay";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ anyspi_11: anyspi@1 {
++ reg = <1>;
++ spi-max-frequency = <500000>;
++ };
++ };
++ };
++
++ fragment@12 {
++ target = <&spi1>;
++ __dormant__ {
++ status = "okay";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ anyspi_12: anyspi@2 {
++ reg = <2>;
++ spi-max-frequency = <500000>;
++ };
++ };
++ };
++
++ fragment@13 {
++ target = <&spi2>;
++ __dormant__ {
++ status = "okay";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ anyspi_20: anyspi@0 {
++ reg = <0>;
++ spi-max-frequency = <500000>;
++ };
++ };
++ };
++
++ fragment@14 {
++ target = <&spi2>;
++ __dormant__ {
++ status = "okay";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ anyspi_21: anyspi@1 {
++ reg = <1>;
++ spi-max-frequency = <500000>;
++ };
++ };
++ };
++
++ fragment@15 {
++ target = <&spi2>;
++ __dormant__ {
++ status = "okay";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ anyspi_22: anyspi@2 {
++ reg = <2>;
++ spi-max-frequency = <500000>;
++ };
++ };
++ };
++
++ __overrides__ {
++ spi0-0 = <0>, "+0+8";
++ spi0-1 = <0>, "+1+9";
++ spi1-0 = <0>, "+2+10";
++ spi1-1 = <0>, "+3+11";
++ spi1-2 = <0>, "+4+12";
++ spi2-0 = <0>, "+5+13";
++ spi2-1 = <0>, "+6+14";
++ spi2-2 = <0>, "+7+15";
++ dev = <&anyspi_00>,"compatible",
++ <&anyspi_01>,"compatible",
++ <&anyspi_10>,"compatible",
++ <&anyspi_11>,"compatible",
++ <&anyspi_12>,"compatible",
++ <&anyspi_20>,"compatible",
++ <&anyspi_21>,"compatible",
++ <&anyspi_22>,"compatible";
++ speed = <&anyspi_00>, "spi-max-frequency:0",
++ <&anyspi_01>, "spi-max-frequency:0",
++ <&anyspi_10>, "spi-max-frequency:0",
++ <&anyspi_11>, "spi-max-frequency:0",
++ <&anyspi_12>, "spi-max-frequency:0",
++ <&anyspi_20>, "spi-max-frequency:0",
++ <&anyspi_21>, "spi-max-frequency:0",
++ <&anyspi_22>, "spi-max-frequency:0";
++ };
++};
--- /dev/null
+From bb4781b1dac98688a3cf64cf728a64d811ca6add Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?J=C3=B6rg=20Schambacher?=
+ <j-schambacher@users.noreply.github.com>
+Date: Tue, 21 Jan 2020 15:58:39 +0100
+Subject: [PATCH] sound: Add the HiFiBerry DAC+HD version
+
+This adds the driver for the DAC+HD version supporting HiFiBerry's
+PCM179x based DACs. It also adds PLL control for clock generation.
+
+Signed-off-by: Joerg Schambacher <joerg@i2audio.com>
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 6 +
+ .../overlays/hifiberry-dacplushd-overlay.dts | 106 ++++++
+ drivers/clk/Makefile | 1 +
+ drivers/clk/clk-hifiberry-dachd.c | 333 ++++++++++++++++++
+ sound/soc/bcm/Kconfig | 7 +
+ sound/soc/bcm/Makefile | 2 +
+ sound/soc/bcm/hifiberry_dacplushd.c | 235 ++++++++++++
+ 13 files changed, 696 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts
+ create mode 100644 drivers/clk/clk-hifiberry-dachd.c
+ create mode 100644 sound/soc/bcm/hifiberry_dacplushd.c
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -57,6 +57,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ hifiberry-dacplusadc.dtbo \
+ hifiberry-dacplusadcpro.dtbo \
+ hifiberry-dacplusdsp.dtbo \
++ hifiberry-dacplushd.dtbo \
+ hifiberry-digi.dtbo \
+ hifiberry-digi-pro.dtbo \
+ hy28a.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -956,6 +956,12 @@ Load: dtoverlay=hifiberry-dacplusdsp
+ Params: <None>
+
+
++Name: hifiberry-dacplushd
++Info: Configures the HifiBerry DAC+ HD audio card
++Load: dtoverlay=hifiberry-dacplushd
++Params: <None>
++
++
+ Name: hifiberry-digi
+ Info: Configures the HifiBerry Digi and Digi+ audio card
+ Load: dtoverlay=hifiberry-digi
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts
+@@ -0,0 +1,106 @@
++// Definitions for HiFiBerry DAC+ HD
++/dts-v1/;
++/plugin/;
++
++#include <dt-bindings/gpio/gpio.h>
++
++/ {
++ compatible = "brcm,bcm2835";
++
++ fragment@0 {
++ target-path = "/clocks";
++ __overlay__ {
++ dachd_osc: pll_dachd_osc {
++ compatible = "hifiberry,dachd-clk";
++ #clock-cells = <0>;
++ };
++ };
++ };
++
++ fragment@1 {
++ target = <&i2s>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@2 {
++ target = <&i2c1>;
++ __overlay__ {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ status = "okay";
++
++ pcm1792a@4c {
++ compatible = "ti,pcm1792a";
++ #sound-dai-cells = <0>;
++ #clock-cells = <0>;
++ clocks = <&dachd_osc>;
++ reg = <0x4c>;
++ status = "okay";
++ };
++ pll: pll@62 {
++ compatible = "hifiberry,dachd-clk";
++ #clock-cells = <0>;
++ reg = <0x62>;
++ clocks = <&dachd_osc>;
++ status = "okay";
++ common_pll_regs = [
++ 02 53 03 00 07 20 0F 00
++ 10 0D 11 1D 12 0D 13 8C
++ 14 8C 15 8C 16 8C 17 8C
++ 18 2A 1C 00 1D 0F 1F 00
++ 2A 00 2C 00 2F 00 30 00
++ 31 00 32 00 34 00 37 00
++ 38 00 39 00 3A 00 3B 01
++ 3E 00 3F 00 40 00 41 00
++ 5A 00 5B 00 95 00 96 00
++ 97 00 98 00 99 00 9A 00
++ 9B 00 A2 00 A3 00 A4 00
++ B7 92 ];
++ 192k_pll_regs = [
++ 1A 0C 1B 35 1E F0 20 09
++ 21 50 2B 02 2D 10 2E 40
++ 33 01 35 22 36 80 3C 22
++ 3D 46 ];
++ 96k_pll_regs = [
++ 1A 0C 1B 35 1E F0 20 09
++ 21 50 2B 02 2D 10 2E 40
++ 33 01 35 47 36 00 3C 32
++ 3D 46 ];
++ 48k_pll_regs = [
++ 1A 0C 1B 35 1E F0 20 09
++ 21 50 2B 02 2D 10 2E 40
++ 33 01 35 90 36 00 3C 42
++ 3D 46 ];
++ 176k4_pll_regs = [
++ 1A 3D 1B 09 1E F3 20 13
++ 21 75 2B 04 2D 11 2E E0
++ 33 02 35 25 36 C0 3C 22
++ 3D 7A ];
++ 88k2_pll_regs = [
++ 1A 3D 1B 09 1E F3 20 13
++ 21 75 2B 04 2D 11 2E E0
++ 33 01 35 4D 36 80 3C 32
++ 3D 7A ];
++ 44k1_pll_regs = [
++ 1A 3D 1B 09 1E F3 20 13
++ 21 75 2B 04 2D 11 2E E0
++ 33 01 35 9D 36 00 3C 42
++ 3D 7A ];
++ };
++ };
++ };
++
++ fragment@3 {
++ target = <&sound>;
++ __overlay__ {
++ compatible = "hifiberry,hifiberry-dacplushd";
++ i2s-controller = <&i2s>;
++ clocks = <&pll 0>;
++ reset-gpio = <&gpio 16 GPIO_ACTIVE_LOW>;
++ status = "okay";
++ };
++ };
++
++};
+--- a/drivers/clk/Makefile
++++ b/drivers/clk/Makefile
+@@ -32,6 +32,7 @@ obj-$(CONFIG_COMMON_CLK_ASPEED) += clk-
+ obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
+ obj-$(CONFIG_CLK_HSDK) += clk-hsdk-pll.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += clk-hifiberry-dacpro.o
++obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD) += clk-hifiberry-dachd.o
+ obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
+ obj-$(CONFIG_COMMON_CLK_MAX9485) += clk-max9485.o
+ obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o
+--- /dev/null
++++ b/drivers/clk/clk-hifiberry-dachd.c
+@@ -0,0 +1,333 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Clock Driver for HiFiBerry DAC+ HD
++ *
++ * Author: Joerg Schambacher, i2Audio GmbH for HiFiBerry
++ * Copyright 2020
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ */
++
++#include <linux/clk-provider.h>
++#include <linux/clk.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/slab.h>
++#include <linux/platform_device.h>
++#include <linux/i2c.h>
++#include <linux/regmap.h>
++
++#define NO_PLL_RESET 0
++#define PLL_RESET 1
++#define HIFIBERRY_PLL_MAX_REGISTER 256
++#define DEFAULT_RATE 44100
++
++static struct reg_default hifiberry_pll_reg_defaults[] = {
++ {0x02, 0x53}, {0x03, 0x00}, {0x07, 0x20}, {0x0F, 0x00},
++ {0x10, 0x0D}, {0x11, 0x1D}, {0x12, 0x0D}, {0x13, 0x8C},
++ {0x14, 0x8C}, {0x15, 0x8C}, {0x16, 0x8C}, {0x17, 0x8C},
++ {0x18, 0x2A}, {0x1C, 0x00}, {0x1D, 0x0F}, {0x1F, 0x00},
++ {0x2A, 0x00}, {0x2C, 0x00}, {0x2F, 0x00}, {0x30, 0x00},
++ {0x31, 0x00}, {0x32, 0x00}, {0x34, 0x00}, {0x37, 0x00},
++ {0x38, 0x00}, {0x39, 0x00}, {0x3A, 0x00}, {0x3B, 0x01},
++ {0x3E, 0x00}, {0x3F, 0x00}, {0x40, 0x00}, {0x41, 0x00},
++ {0x5A, 0x00}, {0x5B, 0x00}, {0x95, 0x00}, {0x96, 0x00},
++ {0x97, 0x00}, {0x98, 0x00}, {0x99, 0x00}, {0x9A, 0x00},
++ {0x9B, 0x00}, {0xA2, 0x00}, {0xA3, 0x00}, {0xA4, 0x00},
++ {0xB7, 0x92},
++ {0x1A, 0x3D}, {0x1B, 0x09}, {0x1E, 0xF3}, {0x20, 0x13},
++ {0x21, 0x75}, {0x2B, 0x04}, {0x2D, 0x11}, {0x2E, 0xE0},
++ {0x3D, 0x7A},
++ {0x35, 0x9D}, {0x36, 0x00}, {0x3C, 0x42},
++ { 177, 0xAC},
++};
++static struct reg_default common_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
++static int num_common_pll_regs;
++static struct reg_default dedicated_192k_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
++static int num_dedicated_192k_pll_regs;
++static struct reg_default dedicated_96k_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
++static int num_dedicated_96k_pll_regs;
++static struct reg_default dedicated_48k_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
++static int num_dedicated_48k_pll_regs;
++static struct reg_default dedicated_176k4_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
++static int num_dedicated_176k4_pll_regs;
++static struct reg_default dedicated_88k2_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
++static int num_dedicated_88k2_pll_regs;
++static struct reg_default dedicated_44k1_pll_regs[HIFIBERRY_PLL_MAX_REGISTER];
++static int num_dedicated_44k1_pll_regs;
++
++/**
++ * struct clk_hifiberry_drvdata - Common struct to the HiFiBerry DAC HD Clk
++ * @hw: clk_hw for the common clk framework
++ */
++struct clk_hifiberry_drvdata {
++ struct regmap *regmap;
++ struct clk *clk;
++ struct clk_hw hw;
++ unsigned long rate;
++};
++
++#define to_hifiberry_clk(_hw) \
++ container_of(_hw, struct clk_hifiberry_drvdata, hw)
++
++static int clk_hifiberry_dachd_write_pll_regs(struct regmap *regmap,
++ struct reg_default *regs,
++ int num, int do_pll_reset)
++{
++ int i;
++ int ret = 0;
++ char pll_soft_reset[] = { 177, 0xAC, };
++
++ for (i = 0; i < num; i++) {
++ ret |= regmap_write(regmap, regs[i].reg, regs[i].def);
++ if (ret)
++ return ret;
++ }
++ if (do_pll_reset) {
++ ret |= regmap_write(regmap, pll_soft_reset[0],
++ pll_soft_reset[1]);
++ mdelay(10);
++ }
++ return ret;
++}
++
++static unsigned long clk_hifiberry_dachd_recalc_rate(struct clk_hw *hw,
++ unsigned long parent_rate)
++{
++ return to_hifiberry_clk(hw)->rate;
++}
++
++static long clk_hifiberry_dachd_round_rate(struct clk_hw *hw,
++ unsigned long rate, unsigned long *parent_rate)
++{
++ return rate;
++}
++
++static int clk_hifiberry_dachd_set_rate(struct clk_hw *hw,
++ unsigned long rate, unsigned long parent_rate)
++{
++ int ret;
++ struct clk_hifiberry_drvdata *drvdata = to_hifiberry_clk(hw);
++
++ switch (rate) {
++ case 44100:
++ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
++ dedicated_44k1_pll_regs, num_dedicated_44k1_pll_regs,
++ PLL_RESET);
++ break;
++ case 88200:
++ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
++ dedicated_88k2_pll_regs, num_dedicated_88k2_pll_regs,
++ PLL_RESET);
++ break;
++ case 176400:
++ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
++ dedicated_176k4_pll_regs, num_dedicated_176k4_pll_regs,
++ PLL_RESET);
++ break;
++ case 48000:
++ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
++ dedicated_48k_pll_regs, num_dedicated_48k_pll_regs,
++ PLL_RESET);
++ break;
++ case 96000:
++ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
++ dedicated_96k_pll_regs, num_dedicated_96k_pll_regs,
++ PLL_RESET);
++ break;
++ case 192000:
++ ret = clk_hifiberry_dachd_write_pll_regs(drvdata->regmap,
++ dedicated_192k_pll_regs, num_dedicated_192k_pll_regs,
++ PLL_RESET);
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
++ to_hifiberry_clk(hw)->rate = rate;
++
++ return ret;
++}
++
++const struct clk_ops clk_hifiberry_dachd_rate_ops = {
++ .recalc_rate = clk_hifiberry_dachd_recalc_rate,
++ .round_rate = clk_hifiberry_dachd_round_rate,
++ .set_rate = clk_hifiberry_dachd_set_rate,
++};
++
++static int clk_hifiberry_get_prop_values(struct device *dev,
++ char *prop_name,
++ struct reg_default *regs)
++{
++ int ret;
++ int i;
++ u8 tmp[2 * HIFIBERRY_PLL_MAX_REGISTER];
++
++ ret = of_property_read_variable_u8_array(dev->of_node, prop_name,
++ tmp, 0, 2 * HIFIBERRY_PLL_MAX_REGISTER);
++ if (ret < 0)
++ return ret;
++ if (ret & 1) {
++ dev_err(dev,
++ "%s <%s> -> #%i odd number of bytes for reg/val pairs!",
++ __func__,
++ prop_name,
++ ret);
++ return -EINVAL;
++ }
++ ret /= 2;
++ for (i = 0; i < ret; i++) {
++ regs[i].reg = (u32)tmp[2 * i];
++ regs[i].def = (u32)tmp[2 * i + 1];
++ }
++ return ret;
++}
++
++
++static int clk_hifiberry_dachd_dt_parse(struct device *dev)
++{
++ num_common_pll_regs = clk_hifiberry_get_prop_values(dev,
++ "common_pll_regs", common_pll_regs);
++ num_dedicated_44k1_pll_regs = clk_hifiberry_get_prop_values(dev,
++ "44k1_pll_regs", dedicated_44k1_pll_regs);
++ num_dedicated_88k2_pll_regs = clk_hifiberry_get_prop_values(dev,
++ "88k2_pll_regs", dedicated_88k2_pll_regs);
++ num_dedicated_176k4_pll_regs = clk_hifiberry_get_prop_values(dev,
++ "176k4_pll_regs", dedicated_176k4_pll_regs);
++ num_dedicated_48k_pll_regs = clk_hifiberry_get_prop_values(dev,
++ "48k_pll_regs", dedicated_48k_pll_regs);
++ num_dedicated_96k_pll_regs = clk_hifiberry_get_prop_values(dev,
++ "96k_pll_regs", dedicated_96k_pll_regs);
++ num_dedicated_192k_pll_regs = clk_hifiberry_get_prop_values(dev,
++ "192k_pll_regs", dedicated_192k_pll_regs);
++ return 0;
++}
++
++
++static int clk_hifiberry_dachd_remove(struct device *dev)
++{
++ of_clk_del_provider(dev->of_node);
++ return 0;
++}
++
++const struct regmap_config hifiberry_pll_regmap = {
++ .reg_bits = 8,
++ .val_bits = 8,
++ .max_register = HIFIBERRY_PLL_MAX_REGISTER,
++ .reg_defaults = hifiberry_pll_reg_defaults,
++ .num_reg_defaults = ARRAY_SIZE(hifiberry_pll_reg_defaults),
++ .cache_type = REGCACHE_RBTREE,
++};
++EXPORT_SYMBOL_GPL(hifiberry_pll_regmap);
++
++
++static int clk_hifiberry_dachd_i2c_probe(struct i2c_client *i2c,
++ const struct i2c_device_id *id)
++{
++ struct clk_hifiberry_drvdata *hdclk;
++ int ret = 0;
++ struct clk_init_data init;
++ struct device *dev = &i2c->dev;
++ struct device_node *dev_node = dev->of_node;
++ struct regmap_config config = hifiberry_pll_regmap;
++
++ hdclk = devm_kzalloc(&i2c->dev,
++ sizeof(struct clk_hifiberry_drvdata), GFP_KERNEL);
++ if (!hdclk)
++ return -ENOMEM;
++
++ i2c_set_clientdata(i2c, hdclk);
++
++ hdclk->regmap = devm_regmap_init_i2c(i2c, &config);
++
++ if (IS_ERR(hdclk->regmap))
++ return PTR_ERR(hdclk->regmap);
++
++ /* start PLL to allow detection of DAC */
++ ret = clk_hifiberry_dachd_write_pll_regs(hdclk->regmap,
++ hifiberry_pll_reg_defaults,
++ ARRAY_SIZE(hifiberry_pll_reg_defaults),
++ PLL_RESET);
++ if (ret)
++ return ret;
++
++ clk_hifiberry_dachd_dt_parse(dev);
++
++ /* restart PLL with configs from DTB */
++ ret = clk_hifiberry_dachd_write_pll_regs(hdclk->regmap, common_pll_regs,
++ num_common_pll_regs, PLL_RESET);
++ if (ret)
++ return ret;
++
++ init.name = "clk-hifiberry-dachd";
++ init.ops = &clk_hifiberry_dachd_rate_ops;
++ init.flags = CLK_IS_BASIC;
++ init.parent_names = NULL;
++ init.num_parents = 0;
++
++ hdclk->hw.init = &init;
++
++ hdclk->clk = devm_clk_register(dev, &hdclk->hw);
++ if (IS_ERR(hdclk->clk)) {
++ dev_err(dev, "unable to register %s\n", init.name);
++ return PTR_ERR(hdclk->clk);
++ }
++
++ ret = of_clk_add_provider(dev_node, of_clk_src_simple_get, hdclk->clk);
++ if (ret != 0) {
++ dev_err(dev, "Cannot of_clk_add_provider");
++ return ret;
++ }
++
++ ret = clk_set_rate(hdclk->hw.clk, DEFAULT_RATE);
++ if (ret != 0) {
++ dev_err(dev, "Cannot set rate : %d\n", ret);
++ return -EINVAL;
++ }
++
++ return ret;
++}
++
++static int clk_hifiberry_dachd_i2c_remove(struct i2c_client *i2c)
++{
++ clk_hifiberry_dachd_remove(&i2c->dev);
++ return 0;
++}
++
++static const struct i2c_device_id clk_hifiberry_dachd_i2c_id[] = {
++ { "dachd-clk", },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, clk_hifiberry_dachd_i2c_id);
++
++static const struct of_device_id clk_hifiberry_dachd_of_match[] = {
++ { .compatible = "hifiberry,dachd-clk", },
++ { }
++};
++MODULE_DEVICE_TABLE(of, clk_hifiberry_dachd_of_match);
++
++static struct i2c_driver clk_hifiberry_dachd_i2c_driver = {
++ .probe = clk_hifiberry_dachd_i2c_probe,
++ .remove = clk_hifiberry_dachd_i2c_remove,
++ .id_table = clk_hifiberry_dachd_i2c_id,
++ .driver = {
++ .name = "dachd-clk",
++ .of_match_table = of_match_ptr(clk_hifiberry_dachd_of_match),
++ },
++};
++
++module_i2c_driver(clk_hifiberry_dachd_i2c_driver);
++
++
++MODULE_DESCRIPTION("HiFiBerry DAC+ HD clock driver");
++MODULE_AUTHOR("Joerg Schambacher <joerg@i2audio.com>");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:clk-hifiberry-dachd");
+--- a/sound/soc/bcm/Kconfig
++++ b/sound/soc/bcm/Kconfig
+@@ -40,6 +40,13 @@ config SND_BCM2708_SOC_HIFIBERRY_DACPLUS
+ help
+ Say Y or M if you want to add support for HifiBerry DAC+.
+
++config SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD
++ tristate "Support for HifiBerry DAC+ HD"
++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
++ select SND_SOC_PCM179X_I2C
++ help
++ Say Y or M if you want to add support for HifiBerry DAC+ HD.
++
+ config SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC
+ tristate "Support for HifiBerry DAC+ADC"
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+--- a/sound/soc/bcm/Makefile
++++ b/sound/soc/bcm/Makefile
+@@ -13,6 +13,7 @@ snd-soc-googlevoicehat-codec-objs := goo
+
+ # BCM2708 Machine Support
+ snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o
++snd-soc-hifiberry-dacplushd-objs := hifiberry_dacplushd.o
+ snd-soc-hifiberry-dacplusadc-objs := hifiberry_dacplusadc.o
+ snd-soc-hifiberry-dacplusadcpro-objs := hifiberry_dacplusadcpro.o
+ snd-soc-hifiberry-dacplusdsp-objs := hifiberry_dacplusdsp.o
+@@ -40,6 +41,7 @@ snd-soc-rpi-wm8804-soundcard-objs := rpi
+
+ obj-$(CONFIG_SND_BCM2708_SOC_GOOGLEVOICEHAT_SOUNDCARD) += snd-soc-googlevoicehat-codec.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
++obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSHD) += snd-soc-hifiberry-dacplushd.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADC) += snd-soc-hifiberry-dacplusadc.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSADCPRO) += snd-soc-hifiberry-dacplusadcpro.o
+ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUSDSP) += snd-soc-hifiberry-dacplusdsp.o
+--- /dev/null
++++ b/sound/soc/bcm/hifiberry_dacplushd.c
+@@ -0,0 +1,235 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * ASoC Driver for HiFiBerry DAC+ HD
++ *
++ * Author: Joerg Schambacher, i2Audio GmbH for HiFiBerry
++ * Copyright 2020
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ */
++
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/delay.h>
++#include <linux/gpio.h>
++#include <linux/gpio/consumer.h>
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <linux/i2c.h>
++#include <linux/clk.h>
++
++#include "../codecs/pcm179x.h"
++
++#define DEFAULT_RATE 44100
++
++struct brd_drv_data {
++ struct regmap *regmap;
++ struct clk *sclk;
++};
++
++static struct brd_drv_data drvdata;
++static struct gpio_desc *reset_gpio;
++static const unsigned int hb_dacplushd_rates[] = {
++ 192000, 96000, 48000, 176400, 88200, 44100,
++};
++
++static struct snd_pcm_hw_constraint_list hb_dacplushd_constraints = {
++ .list = hb_dacplushd_rates,
++ .count = ARRAY_SIZE(hb_dacplushd_rates),
++};
++
++static int snd_rpi_hb_dacplushd_startup(struct snd_pcm_substream *substream)
++{
++ /* constraints for standard sample rates */
++ snd_pcm_hw_constraint_list(substream->runtime, 0,
++ SNDRV_PCM_HW_PARAM_RATE,
++ &hb_dacplushd_constraints);
++ return 0;
++}
++
++static void snd_rpi_hifiberry_dacplushd_set_sclk(
++ struct snd_soc_component *component,
++ int sample_rate)
++{
++ if (!IS_ERR(drvdata.sclk))
++ clk_set_rate(drvdata.sclk, sample_rate);
++}
++
++static int snd_rpi_hifiberry_dacplushd_init(struct snd_soc_pcm_runtime *rtd)
++{
++ struct snd_soc_dai_link *dai = rtd->dai_link;
++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
++
++ dai->name = "HiFiBerry DAC+ HD";
++ dai->stream_name = "HiFiBerry DAC+ HD HiFi";
++ dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
++ | SND_SOC_DAIFMT_CBM_CFM;
++
++ /* allow only fixed 32 clock counts per channel */
++ snd_soc_dai_set_bclk_ratio(cpu_dai, 32*2);
++
++ return 0;
++}
++
++static int snd_rpi_hifiberry_dacplushd_hw_params(
++ struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
++{
++ int ret = 0;
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++
++ struct snd_soc_component *component = rtd->codec_dai->component;
++
++ snd_rpi_hifiberry_dacplushd_set_sclk(component, params_rate(params));
++ return ret;
++}
++
++/* machine stream operations */
++static struct snd_soc_ops snd_rpi_hifiberry_dacplushd_ops = {
++ .startup = snd_rpi_hb_dacplushd_startup,
++ .hw_params = snd_rpi_hifiberry_dacplushd_hw_params,
++};
++
++static struct snd_soc_dai_link snd_rpi_hifiberry_dacplushd_dai[] = {
++{
++ .name = "HiFiBerry DAC+ HD",
++ .stream_name = "HiFiBerry DAC+ HD HiFi",
++ .cpu_dai_name = "bcm2708-i2s.0",
++ .codec_dai_name = "pcm179x-hifi",
++ .platform_name = "bcm2708-i2s.0",
++ .codec_name = "pcm179x.1-004c",
++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
++ SND_SOC_DAIFMT_CBS_CFS,
++ .ops = &snd_rpi_hifiberry_dacplushd_ops,
++ .init = snd_rpi_hifiberry_dacplushd_init,
++},
++};
++
++/* audio machine driver */
++static struct snd_soc_card snd_rpi_hifiberry_dacplushd = {
++ .name = "snd_rpi_hifiberry_dacplushd",
++ .driver_name = "HifiberryDacplusHD",
++ .owner = THIS_MODULE,
++ .dai_link = snd_rpi_hifiberry_dacplushd_dai,
++ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dacplushd_dai),
++};
++
++static int snd_rpi_hifiberry_dacplushd_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++ static int dac_reset_done;
++ struct device *dev = &pdev->dev;
++ struct device_node *dev_node = dev->of_node;
++
++ snd_rpi_hifiberry_dacplushd.dev = &pdev->dev;
++
++ /* get GPIO and release DAC from RESET */
++ if (!dac_reset_done) {
++ reset_gpio = gpiod_get(&pdev->dev, "reset", GPIOD_OUT_LOW);
++ if (IS_ERR(reset_gpio)) {
++ dev_err(&pdev->dev, "gpiod_get() failed\n");
++ return -EINVAL;
++ }
++ dac_reset_done = 1;
++ }
++ if (!IS_ERR(reset_gpio))
++ gpiod_set_value(reset_gpio, 0);
++ msleep(1);
++ if (!IS_ERR(reset_gpio))
++ gpiod_set_value(reset_gpio, 1);
++ msleep(1);
++ if (!IS_ERR(reset_gpio))
++ gpiod_set_value(reset_gpio, 0);
++
++ if (pdev->dev.of_node) {
++ struct device_node *i2s_node;
++ struct snd_soc_dai_link *dai;
++
++ dai = &snd_rpi_hifiberry_dacplushd_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;
++ } else {
++ return -EPROBE_DEFER;
++ }
++
++ }
++
++ ret = devm_snd_soc_register_card(&pdev->dev,
++ &snd_rpi_hifiberry_dacplushd);
++ if (ret && ret != -EPROBE_DEFER) {
++ dev_err(&pdev->dev,
++ "snd_soc_register_card() failed: %d\n", ret);
++ return ret;
++ }
++ if (ret == -EPROBE_DEFER)
++ return ret;
++
++ dev_set_drvdata(dev, &drvdata);
++ if (dev_node == NULL) {
++ dev_err(&pdev->dev, "Device tree node not found\n");
++ return -ENODEV;
++ }
++
++ drvdata.sclk = devm_clk_get(dev, NULL);
++ if (IS_ERR(drvdata.sclk)) {
++ drvdata.sclk = ERR_PTR(-ENOENT);
++ return -ENODEV;
++ }
++
++ clk_set_rate(drvdata.sclk, DEFAULT_RATE);
++
++ return ret;
++}
++
++static int snd_rpi_hifiberry_dacplushd_remove(struct platform_device *pdev)
++{
++ if (IS_ERR(reset_gpio))
++ return -EINVAL;
++
++ /* put DAC into RESET and release GPIO */
++ gpiod_set_value(reset_gpio, 0);
++ gpiod_put(reset_gpio);
++
++ return 0;
++}
++
++static const struct of_device_id snd_rpi_hifiberry_dacplushd_of_match[] = {
++ { .compatible = "hifiberry,hifiberry-dacplushd", },
++ {},
++};
++
++MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_dacplushd_of_match);
++
++static struct platform_driver snd_rpi_hifiberry_dacplushd_driver = {
++ .driver = {
++ .name = "snd-rpi-hifiberry-dacplushd",
++ .owner = THIS_MODULE,
++ .of_match_table = snd_rpi_hifiberry_dacplushd_of_match,
++ },
++ .probe = snd_rpi_hifiberry_dacplushd_probe,
++ .remove = snd_rpi_hifiberry_dacplushd_remove,
++};
++
++module_platform_driver(snd_rpi_hifiberry_dacplushd_driver);
++
++MODULE_AUTHOR("Joerg Schambacher <joerg@i2audio.com>");
++MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+ HD");
++MODULE_LICENSE("GPL v2");
--- /dev/null
+From 43551a95378230b8d062e107e012573739af2bf1 Mon Sep 17 00:00:00 2001
+From: Luke Hinds <7058938+lukehinds@users.noreply.github.com>
+Date: Wed, 22 Jan 2020 16:03:00 +0000
+Subject: [PATCH] Initialise rpi-firmware before clk-bcm2835
+
+The IMA (Integrity Measurement Architecture) looks for a TPM (Trusted
+Platform Module) having been registered when it initialises; otherwise
+it assumes there is no TPM. It has been observed on BCM2835 that IMA
+is initialised before TPM, and that initialising the BCM2835 clock
+driver before the firmware driver has the effect of reversing this
+order.
+
+Change the firmware driver to initialise at core_initcall, delaying the
+BCM2835 clock driver to postcore_initcall.
+
+See: https://github.com/raspberrypi/linux/issues/3291
+ https://github.com/raspberrypi/linux/pull/3297
+
+Signed-off-by: Luke Hinds <lhinds@redhat.com>
+Co-authored-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/clk/bcm/clk-bcm2835.c | 2 +-
+ drivers/firmware/raspberrypi.c | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/clk/bcm/clk-bcm2835.c
++++ b/drivers/clk/bcm/clk-bcm2835.c
+@@ -2388,7 +2388,7 @@ static int __init __bcm2835_clk_driver_i
+ {
+ return platform_driver_register(&bcm2835_clk_driver);
+ }
+-core_initcall(__bcm2835_clk_driver_init);
++postcore_initcall(__bcm2835_clk_driver_init);
+
+ MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
+ MODULE_DESCRIPTION("BCM2835 clock driver");
+--- a/drivers/firmware/raspberrypi.c
++++ b/drivers/firmware/raspberrypi.c
+@@ -404,7 +404,7 @@ out2:
+ out1:
+ return ret;
+ }
+-subsys_initcall(rpi_firmware_init);
++core_initcall(rpi_firmware_init);
+
+ static void __init rpi_firmware_exit(void)
+ {
--- /dev/null
+From 898cec85907f8f171264c8be281a9ac2979b1655 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?J=C3=B6rg=20Schambacher?=
+ <j-schambacher@users.noreply.github.com>
+Date: Thu, 23 Jan 2020 13:32:13 +0100
+Subject: [PATCH] Fix master mode settings of HiFiBerry DAC+ADC PRO
+ card (#3424)
+
+This patch fixes the board DAI setting when in master-mode.
+Wrong setting could have caused random pop noise.
+
+Signed-off-by: Joerg Schambacher <joerg@i2audio.com>
+---
+ sound/soc/bcm/hifiberry_dacplusadcpro.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/sound/soc/bcm/hifiberry_dacplusadcpro.c
++++ b/sound/soc/bcm/hifiberry_dacplusadcpro.c
+@@ -285,6 +285,8 @@ static int snd_rpi_hifiberry_dacplusadcp
+
+ dai->name = "HiFiBerry DAC+ADC Pro";
+ dai->stream_name = "HiFiBerry DAC+ADC Pro HiFi";
++ dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
++ | SND_SOC_DAIFMT_CBM_CFM;
+
+ // set DAC DAI configuration
+ ret = snd_soc_dai_set_fmt(rtd->codec_dais[0],
--- /dev/null
+From 0a865ae13d5f98594562ebe5713caec65ab689e5 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 24 Jan 2020 09:02:37 +0000
+Subject: [PATCH] overlays: Use preferred compatible strings
+
+Make sure all overlays have correct compatible strings before enabling
+the automated checking.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/iqaudio-codec-overlay.dts | 2 +-
+ arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts | 2 ++
+ arch/arm/boot/dts/overlays/pwm-overlay.dts | 2 ++
+ arch/arm/boot/dts/overlays/smi-dev-overlay.dts | 2 ++
+ 5 files changed, 8 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target-path = "/clocks";
+--- a/arch/arm/boot/dts/overlays/iqaudio-codec-overlay.dts
++++ b/arch/arm/boot/dts/overlays/iqaudio-codec-overlay.dts
+@@ -3,7 +3,7 @@
+ /plugin/;
+
+ / {
+- compatible = "brcm,bcm2708";
++ compatible = "brcm,bcm2835";
+
+ fragment@0 {
+ target = <&i2s>;
+--- a/arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts
+@@ -17,6 +17,8 @@ N.B.:
+ */
+
+ / {
++ compatible = "brcm,bcm2835";
++
+ fragment@0 {
+ target = <&gpio>;
+ __overlay__ {
+--- a/arch/arm/boot/dts/overlays/pwm-overlay.dts
++++ b/arch/arm/boot/dts/overlays/pwm-overlay.dts
+@@ -15,6 +15,8 @@ N.B.:
+ */
+
+ / {
++ compatible = "brcm,bcm2835";
++
+ fragment@0 {
+ target = <&gpio>;
+ __overlay__ {
+--- a/arch/arm/boot/dts/overlays/smi-dev-overlay.dts
++++ b/arch/arm/boot/dts/overlays/smi-dev-overlay.dts
+@@ -5,6 +5,8 @@
+ /plugin/;
+
+ /{
++ compatible = "brcm,bcm2835";
++
+ fragment@0 {
+ target = <&soc>;
+ __overlay__ {
--- /dev/null
+From d4f4b57c667141ca98711cfcb30ae2b8deb1a034 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 24 Jan 2020 11:38:28 +0000
+Subject: [PATCH] tty: amba-pl011: Add un/throttle support
+
+The PL011 driver lacks throttle and unthrottle methods. As a result,
+sending more data to the Pi than it can immediately sink while CRTSCTS
+is enabled causes a NULL pointer to be followed.
+
+Add a throttle handler that disables the RX interrupts, and an
+unthrottle handler that reenables them.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/tty/serial/amba-pl011.c | 28 ++++++++++++++++++++++++++++
+ 1 file changed, 28 insertions(+)
+
+--- a/drivers/tty/serial/amba-pl011.c
++++ b/drivers/tty/serial/amba-pl011.c
+@@ -1323,6 +1323,32 @@ static void pl011_start_tx(struct uart_p
+ pl011_start_tx_pio(uap);
+ }
+
++static void pl011_throttle(struct uart_port *port)
++{
++ struct uart_amba_port *uap =
++ container_of(port, struct uart_amba_port, port);
++ unsigned long flags;
++
++ spin_lock_irqsave(&uap->port.lock, flags);
++ uap->im &= ~(UART011_RTIM | UART011_RXIM);
++ pl011_write(uap->im, uap, REG_IMSC);
++ spin_unlock_irqrestore(&uap->port.lock, flags);
++}
++
++static void pl011_unthrottle(struct uart_port *port)
++{
++ struct uart_amba_port *uap =
++ container_of(port, struct uart_amba_port, port);
++ unsigned long flags;
++
++ spin_lock_irqsave(&uap->port.lock, flags);
++ uap->im |= UART011_RTIM;
++ if (!pl011_dma_rx_running(uap))
++ uap->im |= UART011_RXIM;
++ pl011_write(uap->im, uap, REG_IMSC);
++ spin_unlock_irqrestore(&uap->port.lock, flags);
++}
++
+ static void pl011_stop_rx(struct uart_port *port)
+ {
+ struct uart_amba_port *uap =
+@@ -2165,6 +2191,8 @@ static const struct uart_ops amba_pl011_
+ .stop_tx = pl011_stop_tx,
+ .start_tx = pl011_start_tx,
+ .stop_rx = pl011_stop_rx,
++ .throttle = pl011_throttle,
++ .unthrottle = pl011_unthrottle,
+ .enable_ms = pl011_enable_ms,
+ .break_ctl = pl011_break_ctl,
+ .startup = pl011_startup,
--- /dev/null
+From 493aa5b9a2f57003dd0a16946eb56b08650090b4 Mon Sep 17 00:00:00 2001
+From: MikeDK <m.kaplan@evva.com>
+Date: Sun, 26 Jan 2020 23:33:54 +0100
+Subject: [PATCH] Fix i2c-pwm-pca9685a overlay
+
+---
+ arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts
++++ b/arch/arm/boot/dts/overlays/i2c-pwm-pca9685a-overlay.dts
+@@ -13,7 +13,7 @@
+ status = "okay";
+
+ pca: pca@40 {
+- compatible = "nxp,pca9685";
++ compatible = "nxp,pca9685-pwm";
+ #pwm-cells = <2>;
+ reg = <0x40>;
+ status = "okay";
--- /dev/null
+From c23190019110e3314041f2184552a8343de55117 Mon Sep 17 00:00:00 2001
+From: j-schambacher <joerg@i2audio.com>
+Date: Mon, 27 Jan 2020 17:45:51 +0100
+Subject: [PATCH] adds LED OFF feature to HiFiBerry DAC+ADC PRO sound
+ card
+
+This adds a DT overlay parameter 'leds_off' which allows
+to switch off the onboard activity LEDs at all times
+which has been requested by some users.
+
+Signed-off-by: Joerg Schambacher <joerg@i2audio.com>
+---
+ arch/arm/boot/dts/overlays/README | 2 ++
+ .../overlays/hifiberry-dacplusadcpro-overlay.dts | 1 +
+ sound/soc/bcm/hifiberry_dacplusadcpro.c | 15 +++++++++++++--
+ 3 files changed, 16 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -948,6 +948,8 @@ Params: 24db_digital_gain Allow ga
+ that does not result in clipping/distortion!)
+ slave Force DAC+ADC Pro into slave mode, using Pi as
+ master for bit clock and frame clock.
++ leds_off If set to 'true' the onboard indicator LEDs
++ are switched off at all times.
+
+
+ Name: hifiberry-dacplusdsp
+--- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts
+@@ -60,5 +60,6 @@
+ 24db_digital_gain =
+ <&hifiberry_dacplusadcpro>,"hifiberry-dacplusadcpro,24db_digital_gain?";
+ slave = <&hifiberry_dacplusadcpro>,"hifiberry-dacplusadcpro,slave?";
++ leds_off = <&hifiberry_dacplusadcpro>,"hifiberry-dacplusadcpro,leds_off?";
+ };
+ };
+--- a/sound/soc/bcm/hifiberry_dacplusadcpro.c
++++ b/sound/soc/bcm/hifiberry_dacplusadcpro.c
+@@ -54,6 +54,7 @@ struct pcm512x_priv {
+ static bool slave;
+ static bool snd_rpi_hifiberry_is_dacpro;
+ static bool digital_gain_0db_limit = true;
++static bool leds_off;
+
+ static const unsigned int pcm186x_adc_input_channel_sel_value[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x10
+@@ -321,7 +322,10 @@ static int snd_rpi_hifiberry_dacplusadcp
+
+ snd_soc_component_update_bits(dac, PCM512x_GPIO_EN, 0x08, 0x08);
+ snd_soc_component_update_bits(dac, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02);
+- snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
++ if (leds_off)
++ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x00);
++ else
++ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
+
+ ret = pcm1863_add_controls(adc);
+ if (ret < 0)
+@@ -331,7 +335,10 @@ static int snd_rpi_hifiberry_dacplusadcp
+ /* set GPIO2 to output, GPIO3 input */
+ snd_soc_component_write(adc, PCM186X_GPIO3_2_CTRL, 0x00);
+ snd_soc_component_write(adc, PCM186X_GPIO3_2_DIR_CTRL, 0x04);
+- snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x40);
++ if (leds_off)
++ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x00);
++ else
++ snd_soc_component_update_bits(adc, PCM186X_GPIO_IN_OUT, 0x40, 0x40);
+
+ if (digital_gain_0db_limit) {
+ int ret;
+@@ -417,6 +424,8 @@ static int snd_rpi_hifiberry_dacplusadcp
+ struct snd_soc_component *dac = rtd->codec_dais[0]->component;
+ struct snd_soc_component *adc = rtd->codec_dais[1]->component;
+
++ if (leds_off)
++ return 0;
+ /* switch on respective LED */
+ if (!substream->stream)
+ snd_soc_component_update_bits(dac, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
+@@ -508,6 +517,8 @@ static int snd_rpi_hifiberry_dacplusadcp
+ pdev->dev.of_node, "hifiberry-dacplusadcpro,24db_digital_gain");
+ slave = of_property_read_bool(pdev->dev.of_node,
+ "hifiberry-dacplusadcpro,slave");
++ leds_off = of_property_read_bool(pdev->dev.of_node,
++ "hifiberry-dacplusadcpro,leds_off");
+ ret = snd_soc_register_card(&snd_rpi_hifiberry_dacplusadcpro);
+ if (ret && ret != -EPROBE_DEFER)
+ dev_err(&pdev->dev,
--- /dev/null
+From ee513338448ddbb72ac8f76e7053865fe926a18c Mon Sep 17 00:00:00 2001
+From: j-schambacher <joerg@i2audio.com>
+Date: Mon, 27 Jan 2020 20:37:34 +0100
+Subject: [PATCH] adds LED OFF feature to HiFiBerry DAC+ADC sound card
+
+This adds a DT overlay parameter 'leds_off' which allows
+to switch off the onboard activity LEDs at all times
+which has been requested by some users.
+
+Signed-off-by: Joerg Schambacher <joerg@i2audio.com>
+---
+ arch/arm/boot/dts/overlays/README | 2 ++
+ .../boot/dts/overlays/hifiberry-dacplusadc-overlay.dts | 1 +
+ sound/soc/bcm/hifiberry_dacplusadc.c | 10 +++++++++-
+ 3 files changed, 12 insertions(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -927,6 +927,8 @@ Params: 24db_digital_gain Allow ga
+ that does not result in clipping/distortion!)
+ slave Force DAC+ Pro into slave mode, using Pi as
+ master for bit clock and frame clock.
++ leds_off If set to 'true' the onboard indicator LEDs
++ are switched off at all times.
+
+
+ Name: hifiberry-dacplusadcpro
+--- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts
+@@ -67,5 +67,6 @@
+ 24db_digital_gain =
+ <&hifiberry_dacplusadc>,"hifiberry,24db_digital_gain?";
+ slave = <&hifiberry_dacplusadc>,"hifiberry-dacplusadc,slave?";
++ leds_off = <&hifiberry_dacplusadc>,"hifiberry-dacplusadc,leds_off?";
+ };
+ };
+--- a/sound/soc/bcm/hifiberry_dacplusadc.c
++++ b/sound/soc/bcm/hifiberry_dacplusadc.c
+@@ -54,6 +54,7 @@ struct pcm512x_priv {
+ static bool slave;
+ static bool snd_rpi_hifiberry_is_dacpro;
+ static bool digital_gain_0db_limit = true;
++static bool leds_off;
+
+ static void snd_rpi_hifiberry_dacplusadc_select_clk(struct snd_soc_component *component,
+ int clk_id)
+@@ -175,7 +176,10 @@ static int snd_rpi_hifiberry_dacplusadc_
+
+ snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x08, 0x08);
+ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02);
+- snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
++ if (leds_off)
++ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x00);
++ else
++ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
+
+ if (digital_gain_0db_limit) {
+ int ret;
+@@ -256,6 +260,8 @@ static int snd_rpi_hifiberry_dacplusadc_
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_component *component = rtd->codec_dai->component;
+
++ if (leds_off)
++ return 0;
+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1,
+ 0x08, 0x08);
+ hifiberry_dacplusadc_LED_cnt++;
+@@ -347,6 +353,8 @@ static int snd_rpi_hifiberry_dacplusadc_
+ pdev->dev.of_node, "hifiberry,24db_digital_gain");
+ slave = of_property_read_bool(pdev->dev.of_node,
+ "hifiberry-dacplusadc,slave");
++ leds_off = of_property_read_bool(pdev->dev.of_node,
++ "hifiberry-dacplusadc,leds_off");
+
+ ret = devm_snd_soc_register_card(&pdev->dev,
+ &snd_rpi_hifiberry_dacplusadc);
--- /dev/null
+From 5eccee0e620b799558d89ebee29280116ad37e4f Mon Sep 17 00:00:00 2001
+From: j-schambacher <joerg@i2audio.com>
+Date: Mon, 27 Jan 2020 20:58:24 +0100
+Subject: [PATCH] adds LED OFF feature to HiFiBerry DAC+/DAC+PRO sound
+ cards
+
+This adds a DT overlay parameter 'leds_off' which allows
+to switch off the onboard activity LEDs at all times
+which has been requested by some users.
+
+Signed-off-by: Joerg Schambacher <joerg@i2audio.com>
+---
+ arch/arm/boot/dts/overlays/README | 2 ++
+ .../boot/dts/overlays/hifiberry-dacplus-overlay.dts | 1 +
+ sound/soc/bcm/hifiberry_dacplus.c | 10 +++++++++-
+ 3 files changed, 12 insertions(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -906,6 +906,8 @@ Params: 24db_digital_gain Allow ga
+ that does not result in clipping/distortion!)
+ slave Force DAC+ Pro into slave mode, using Pi as
+ master for bit clock and frame clock.
++ leds_off If set to 'true' the onboard indicator LEDs
++ are switched off at all times.
+
+
+ Name: hifiberry-dacplusadc
+--- a/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts
++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts
+@@ -55,5 +55,6 @@
+ 24db_digital_gain =
+ <&hifiberry_dacplus>,"hifiberry,24db_digital_gain?";
+ slave = <&hifiberry_dacplus>,"hifiberry-dacplus,slave?";
++ leds_off = <&hifiberry_dacplus>,"hifiberry-dacplus,leds_off?";
+ };
+ };
+--- a/sound/soc/bcm/hifiberry_dacplus.c
++++ b/sound/soc/bcm/hifiberry_dacplus.c
+@@ -50,6 +50,7 @@ struct pcm512x_priv {
+ static bool slave;
+ static bool snd_rpi_hifiberry_is_dacpro;
+ static bool digital_gain_0db_limit = true;
++static bool leds_off;
+
+ static void snd_rpi_hifiberry_dacplus_select_clk(struct snd_soc_component *component,
+ int clk_id)
+@@ -171,7 +172,10 @@ static int snd_rpi_hifiberry_dacplus_ini
+
+ snd_soc_component_update_bits(component, PCM512x_GPIO_EN, 0x08, 0x08);
+ snd_soc_component_update_bits(component, PCM512x_GPIO_OUTPUT_4, 0x0f, 0x02);
+- snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
++ if (leds_off)
++ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x00);
++ else
++ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
+
+ if (digital_gain_0db_limit)
+ {
+@@ -251,6 +255,8 @@ static int snd_rpi_hifiberry_dacplus_sta
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_component *component = rtd->codec_dai->component;
+
++ if (leds_off)
++ return 0;
+ snd_soc_component_update_bits(component, PCM512x_GPIO_CONTROL_1, 0x08, 0x08);
+ return 0;
+ }
+@@ -319,6 +325,8 @@ static int snd_rpi_hifiberry_dacplus_pro
+ pdev->dev.of_node, "hifiberry,24db_digital_gain");
+ slave = of_property_read_bool(pdev->dev.of_node,
+ "hifiberry-dacplus,slave");
++ leds_off = of_property_read_bool(pdev->dev.of_node,
++ "hifiberry-dacplus,leds_off");
+ }
+
+ ret = devm_snd_soc_register_card(&pdev->dev,
--- /dev/null
+From a879ab9cad6b598c08988404934273d3cbfbd993 Mon Sep 17 00:00:00 2001
+From: gtrainavicius <gtrainavicius@users.noreply.github.com>
+Date: Tue, 28 Jan 2020 14:16:37 +0200
+Subject: [PATCH] pisound: Added reading Pisound board hardware
+ revision and exposing it (#3425)
+
+pisound: Added reading Pisound board hardware revision and exposing it in kernel log and sysfs file:
+
+/sys/kernel/pisound/hw_version
+
+Signed-off-by: Giedrius <giedrius@blokas.io>
+---
+ sound/soc/bcm/pisound.c | 86 ++++++++++++++++++++++++++++-------------
+ 1 file changed, 59 insertions(+), 27 deletions(-)
+
+--- a/sound/soc/bcm/pisound.c
++++ b/sound/soc/bcm/pisound.c
+@@ -51,7 +51,8 @@ static void pisnd_spi_set_callback(pisnd
+
+ static const char *pisnd_spi_get_serial(void);
+ static const char *pisnd_spi_get_id(void);
+-static const char *pisnd_spi_get_version(void);
++static const char *pisnd_spi_get_fw_version(void);
++static const char *pisnd_spi_get_hw_version(void);
+
+ static int pisnd_midi_init(struct snd_card *card);
+ static void pisnd_midi_uninit(void);
+@@ -222,7 +223,9 @@ static pisnd_spi_recv_cb g_recvCallback;
+
+ static char g_serial_num[11];
+ static char g_id[25];
+-static char g_version[5];
++enum { MAX_VERSION_STR_LEN = 6 };
++static char g_fw_version[MAX_VERSION_STR_LEN];
++static char g_hw_version[MAX_VERSION_STR_LEN];
+
+ static uint8_t g_ledFlashDuration;
+ static bool g_ledFlashDurationChanged;
+@@ -558,7 +561,8 @@ static int spi_read_info(void)
+ char *p;
+
+ memset(g_serial_num, 0, sizeof(g_serial_num));
+- memset(g_version, 0, sizeof(g_version));
++ memset(g_fw_version, 0, sizeof(g_fw_version));
++ strcpy(g_hw_version, "1.0"); // Assume 1.0 hw version.
+ memset(g_id, 0, sizeof(g_id));
+
+ tmp = spi_transfer16(0);
+@@ -581,12 +585,28 @@ static int spi_read_info(void)
+ return -EINVAL;
+
+ snprintf(
+- g_version,
+- sizeof(g_version),
++ g_fw_version,
++ MAX_VERSION_STR_LEN,
+ "%x.%02x",
+ buffer[0],
+ buffer[1]
+ );
++
++ g_fw_version[MAX_VERSION_STR_LEN-1] = '\0';
++ break;
++ case 3:
++ if (n != 2)
++ return -EINVAL;
++
++ snprintf(
++ g_hw_version,
++ MAX_VERSION_STR_LEN,
++ "%x.%x",
++ buffer[0],
++ buffer[1]
++ );
++
++ g_hw_version[MAX_VERSION_STR_LEN-1] = '\0';
+ break;
+ case 1:
+ if (n >= sizeof(g_serial_num))
+@@ -596,12 +616,14 @@ static int spi_read_info(void)
+ break;
+ case 2:
+ {
+- if (n >= sizeof(g_id))
++ if (n*2 >= sizeof(g_id))
+ return -EINVAL;
+
+ p = g_id;
+ for (j = 0; j < n; ++j)
+ p += sprintf(p, "%02x", buffer[j]);
++
++ *p = '\0';
+ }
+ break;
+ default:
+@@ -619,7 +641,8 @@ static int pisnd_spi_init(struct device
+
+ memset(g_serial_num, 0, sizeof(g_serial_num));
+ memset(g_id, 0, sizeof(g_id));
+- memset(g_version, 0, sizeof(g_version));
++ memset(g_fw_version, 0, sizeof(g_fw_version));
++ memset(g_hw_version, 0, sizeof(g_hw_version));
+
+ spi = pisnd_spi_find_device();
+
+@@ -729,26 +752,22 @@ static void pisnd_spi_set_callback(pisnd
+
+ static const char *pisnd_spi_get_serial(void)
+ {
+- if (strlen(g_serial_num))
+- return g_serial_num;
+-
+- return "";
++ return g_serial_num;
+ }
+
+ static const char *pisnd_spi_get_id(void)
+ {
+- if (strlen(g_id))
+- return g_id;
+-
+- return "";
++ return g_id;
+ }
+
+-static const char *pisnd_spi_get_version(void)
++static const char *pisnd_spi_get_fw_version(void)
+ {
+- if (strlen(g_version))
+- return g_version;
++ return g_fw_version;
++}
+
+- return "";
++static const char *pisnd_spi_get_hw_version(void)
++{
++ return g_hw_version;
+ }
+
+ static const struct of_device_id pisound_of_match[] = {
+@@ -1054,13 +1073,22 @@ static ssize_t pisnd_id_show(
+ return sprintf(buf, "%s\n", pisnd_spi_get_id());
+ }
+
+-static ssize_t pisnd_version_show(
++static ssize_t pisnd_fw_version_show(
+ struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf
+ )
+ {
+- return sprintf(buf, "%s\n", pisnd_spi_get_version());
++ return sprintf(buf, "%s\n", pisnd_spi_get_fw_version());
++}
++
++static ssize_t pisnd_hw_version_show(
++ struct kobject *kobj,
++ struct kobj_attribute *attr,
++ char *buf
++)
++{
++ return sprintf(buf, "%s\n", pisnd_spi_get_hw_version());
+ }
+
+ static ssize_t pisnd_led_store(
+@@ -1085,15 +1113,18 @@ static struct kobj_attribute pisnd_seria
+ __ATTR(serial, 0444, pisnd_serial_show, NULL);
+ static struct kobj_attribute pisnd_id_attribute =
+ __ATTR(id, 0444, pisnd_id_show, NULL);
+-static struct kobj_attribute pisnd_version_attribute =
+- __ATTR(version, 0444, pisnd_version_show, NULL);
++static struct kobj_attribute pisnd_fw_version_attribute =
++ __ATTR(version, 0444, pisnd_fw_version_show, NULL);
++static struct kobj_attribute pisnd_hw_version_attribute =
++__ATTR(hw_version, 0444, pisnd_hw_version_show, NULL);
+ static struct kobj_attribute pisnd_led_attribute =
+ __ATTR(led, 0644, NULL, pisnd_led_store);
+
+ static struct attribute *attrs[] = {
+ &pisnd_serial_attribute.attr,
+ &pisnd_id_attribute.attr,
+- &pisnd_version_attribute.attr,
++ &pisnd_fw_version_attribute.attr,
++ &pisnd_hw_version_attribute.attr,
+ &pisnd_led_attribute.attr,
+ NULL
+ };
+@@ -1112,9 +1143,10 @@ static int pisnd_probe(struct platform_d
+ }
+
+ printi("Detected Pisound card:\n");
+- printi("\tSerial: %s\n", pisnd_spi_get_serial());
+- printi("\tVersion: %s\n", pisnd_spi_get_version());
+- printi("\tId: %s\n", pisnd_spi_get_id());
++ printi("\tSerial: %s\n", pisnd_spi_get_serial());
++ printi("\tFirmware Version: %s\n", pisnd_spi_get_fw_version());
++ printi("\tHardware Version: %s\n", pisnd_spi_get_hw_version());
++ printi("\tId: %s\n", pisnd_spi_get_id());
+
+ pisnd_kobj = kobject_create_and_add("pisound", kernel_kobj);
+ if (!pisnd_kobj) {
--- /dev/null
+From 5ee0de9d7abd644d4cb678fe26ac5130a1a8075f Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 2 Aug 2019 15:20:11 +0100
+Subject: [PATCH] mmc: sdhci-iproc: Fix vmmc regulators on iProc
+
+The Linux support for controlling card power via regulators appears to
+be contentious. I would argue that the default behaviour is contrary to
+the SDHCI spec - turning off the power writes a reserved value to the
+SD Bus Voltage Select field of the Power Control Register, which
+seems to kill the Arasan/iProc controller - but fortunately there is a
+hook in sdhci_ops to override the behaviour. Borrow the implementation
+from sdhci_arasan_set_power.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/mmc/host/sdhci-iproc.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/drivers/mmc/host/sdhci-iproc.c
++++ b/drivers/mmc/host/sdhci-iproc.c
+@@ -162,6 +162,17 @@ static void sdhci_iproc_writeb(struct sd
+ sdhci_iproc_writel(host, newval, reg & ~3);
+ }
+
++static void sdhci_iproc_set_power(struct sdhci_host *host, unsigned char mode,
++ unsigned short vdd)
++{
++ if (!IS_ERR(host->mmc->supply.vmmc)) {
++ struct mmc_host *mmc = host->mmc;
++
++ mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
++ }
++ sdhci_set_power_noreg(host, mode, vdd);
++}
++
+ static const struct sdhci_ops sdhci_iproc_ops = {
+ .set_clock = sdhci_set_clock,
+ .get_max_clock = sdhci_pltfm_clk_get_max_clock,
+@@ -178,6 +189,7 @@ static const struct sdhci_ops sdhci_ipro
+ .write_w = sdhci_iproc_writew,
+ .write_b = sdhci_iproc_writeb,
+ .set_clock = sdhci_set_clock,
++ .set_power = sdhci_iproc_set_power,
+ .get_max_clock = sdhci_pltfm_clk_get_max_clock,
+ .set_bus_width = sdhci_set_bus_width,
+ .reset = sdhci_reset,
--- /dev/null
+From 03bd617d5ba9124a59e86f285385b95415962af7 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Tue, 30 Jul 2019 12:37:02 +0100
+Subject: [PATCH] ARM: dts: Declare RPi 4B SD card power regulator
+
+Later revisions of the Raspberry Pi 4B have a separate control over the
+SD card power. Expose that control to Linux as a fixed regulator with
+a GPIO enable.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 11 +++++++++++
+ arch/arm/configs/bcm2711_defconfig | 2 +-
+ arch/arm64/configs/bcm2711_defconfig | 2 +-
+ 3 files changed, 13 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
+@@ -122,6 +122,16 @@
+ states = <1800000 0x1
+ 3300000 0x0>;
+ };
++
++ sd_vcc_reg: sd_vcc_reg {
++ compatible = "regulator-fixed";
++ regulator-name = "vcc-sd";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-boot-on;
++ enable-active-high;
++ gpio = <&expgpio 6 GPIO_ACTIVE_HIGH>;
++ };
+ };
+
+ &sdhost {
+@@ -132,6 +142,7 @@
+ status = "okay";
+ broken-cd;
+ vqmmc-supply = <&sd_io_1v8_reg>;
++ vmmc-supply = <&sd_vcc_reg>;
+ };
+
+ &leds {
--- /dev/null
+From 4b777f389e22abb364e398f45673e54bcda9cc55 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 12 Jul 2019 11:41:25 +0100
+Subject: [PATCH] pcie-brcmstb: Bounce buffer support is for BCM2711B0
+
+Add a new compatible string to identify BCM2711B0, as later revisions
+don't require the bounce buffer support.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/pci/controller/pcie-brcmstb.c | 31 +++++++++++++++++++++++----
+ 1 file changed, 27 insertions(+), 4 deletions(-)
+
+--- a/drivers/pci/controller/pcie-brcmstb.c
++++ b/drivers/pci/controller/pcie-brcmstb.c
+@@ -206,6 +206,8 @@ enum pcie_type {
+ BCM7435,
+ GENERIC,
+ BCM7278,
++ BCM2711B0,
++ BCM2711,
+ };
+
+ struct brcm_window {
+@@ -302,6 +304,20 @@ static const int pcie_offsets[] = {
+ [EXT_CFG_DATA] = 0x8000,
+ };
+
++static const struct pcie_cfg_data bcm2711b0_cfg = {
++ .reg_field_info = pcie_reg_field_info,
++ .offsets = pcie_offsets,
++ .max_burst_size = BURST_SIZE_128,
++ .type = BCM2711B0,
++};
++
++static const struct pcie_cfg_data bcm2711_cfg = {
++ .reg_field_info = pcie_reg_field_info,
++ .offsets = pcie_offsets,
++ .max_burst_size = BURST_SIZE_128,
++ .type = BCM2711,
++};
++
+ static const struct pcie_cfg_data bcm7435_cfg = {
+ .reg_field_info = pcie_reg_field_info,
+ .offsets = pcie_offsets,
+@@ -312,7 +328,7 @@ static const struct pcie_cfg_data bcm743
+ static const struct pcie_cfg_data generic_cfg = {
+ .reg_field_info = pcie_reg_field_info,
+ .offsets = pcie_offsets,
+- .max_burst_size = BURST_SIZE_128, // before BURST_SIZE_512
++ .max_burst_size = BURST_SIZE_512,
+ .type = GENERIC,
+ };
+
+@@ -380,7 +396,7 @@ static unsigned int bounce_buffer = 32*1
+ module_param(bounce_buffer, uint, 0644);
+ MODULE_PARM_DESC(bounce_buffer, "Size of bounce buffer");
+
+-static unsigned int bounce_threshold = 0xc0000000;
++static unsigned int bounce_threshold;
+ module_param(bounce_threshold, uint, 0644);
+ MODULE_PARM_DESC(bounce_threshold, "Bounce threshold");
+
+@@ -1681,6 +1697,8 @@ static int brcm_pcie_remove(struct platf
+ }
+
+ static const struct of_device_id brcm_pcie_match[] = {
++ { .compatible = "brcm,bcm2711b0-pcie", .data = &bcm2711b0_cfg },
++ { .compatible = "brcm,bcm2711-pcie", .data = &bcm2711_cfg },
+ { .compatible = "brcm,bcm7425-pcie", .data = &bcm7425_cfg },
+ { .compatible = "brcm,bcm7435-pcie", .data = &bcm7435_cfg },
+ { .compatible = "brcm,bcm7278-pcie", .data = &bcm7278_cfg },
+@@ -1736,8 +1754,13 @@ static int brcm_pcie_probe(struct platfo
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+- /* To Do: Add hardware check if this ever gets fixed */
+- if (max_pfn > (bounce_threshold/PAGE_SIZE)) {
++ if (!bounce_threshold) {
++ /* PCIe on BCM2711B0 can only address 3GB */
++ if (pcie->type == BCM2711B0 || pcie->type == GENERIC)
++ bounce_threshold = 0xc0000000;
++ }
++
++ if (bounce_threshold && (max_pfn > (bounce_threshold/PAGE_SIZE))) {
+ int ret;
+ ret = brcm_pcie_bounce_init(&pdev->dev, bounce_buffer,
+ (dma_addr_t)bounce_threshold);
--- /dev/null
+From bacf6a02fe12125d2d675f0c6238d9265d31b45f Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Fri, 12 Jul 2019 11:43:03 +0100
+Subject: [PATCH] bcm2838.dtsi: Use BCM2711 PCIe compatible string
+
+The BCM2711 PCIe controller has a limited address range in the B0
+silicon, and the driver uses a compatible string to identify the
+limitation. The current Pi 4 firmware will override the compatible
+string if it detects a downstream DTB and it is running on a newer
+revision but set the default value to enable the workaround for
+backwards-compatibility with old firmware.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/bcm2838.dtsi | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/bcm2838.dtsi
++++ b/arch/arm/boot/dts/bcm2838.dtsi
+@@ -327,7 +327,8 @@
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ bus-range = <0x0 0x01>;
+- compatible = "brcm,bcm7211-pcie", "brcm,bcm7445-pcie",
++ compatible = "brcm,bcm2711b0-pcie", // Safe value
++ "brcm,bcm2711-pcie",
+ "brcm,pci-plat-dev";
+ max-link-speed = <2>;
+ tot-num-pcie = <1>;
--- /dev/null
+From 8aa8fd89094952e3201b927fb846ba61b30cab6b Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Wed, 29 Jan 2020 11:29:06 +0000
+Subject: [PATCH] ARM: dts: Remove bcm2838-rpi-4-b.dts
+
+Upstream are not going to use the bcm2838 identifier, so begin the
+cleanup by removing the suggested upstream Pi 4 .dts file.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/Makefile | 1 -
+ arch/arm/boot/dts/bcm2838-rpi-4-b.dts | 118 --------------------------
+ 2 files changed, 119 deletions(-)
+ delete mode 100644 arch/arm/boot/dts/bcm2838-rpi-4-b.dts
+
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -95,7 +95,6 @@ dtb-$(CONFIG_ARCH_BCM2835) += \
+ bcm2836-rpi-2-b.dtb \
+ bcm2837-rpi-3-b.dtb \
+ bcm2837-rpi-3-b-plus.dtb \
+- bcm2838-rpi-4-b.dtb \
+ bcm2835-rpi-zero.dtb \
+ bcm2835-rpi-zero-w.dtb
+ dtb-$(CONFIG_ARCH_BCM_5301X) += \
+--- a/arch/arm/boot/dts/bcm2838-rpi-4-b.dts
++++ /dev/null
+@@ -1,118 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0
+-/dts-v1/;
+-#include "bcm2838.dtsi"
+-#include "bcm2835-rpi.dtsi"
+-#include "bcm2838-rpi.dtsi"
+-
+-/ {
+- compatible = "raspberrypi,4-model-b", "brcm,bcm2711";
+- model = "Raspberry Pi 4 Model B";
+-
+- chosen {
+- /* 8250 auxiliary UART instead of pl011 */
+- stdout-path = "serial1:115200n8";
+- };
+-
+- memory@0 {
+- reg = <0 0 0x40000000>;
+- };
+-
+- leds {
+- act {
+- gpios = <&gpio 42 GPIO_ACTIVE_HIGH>;
+- };
+-
+- pwr {
+- label = "PWR";
+- gpios = <&expgpio 2 GPIO_ACTIVE_LOW>;
+- };
+- };
+-
+- wifi_pwrseq: wifi-pwrseq {
+- compatible = "mmc-pwrseq-simple";
+- reset-gpios = <&expgpio 1 GPIO_ACTIVE_LOW>;
+- };
+-
+- sd_io_1v8_reg: sd_io_1v8_reg {
+- status = "okay";
+- compatible = "regulator-gpio";
+- vin-supply = <&vdd_5v0_reg>;
+- regulator-name = "vdd-sd-io";
+- regulator-min-microvolt = <1800000>;
+- regulator-max-microvolt = <3300000>;
+- regulator-boot-on;
+- regulator-always-on;
+- regulator-settling-time-us = <5000>;
+-
+- gpios = <&expgpio 4 GPIO_ACTIVE_HIGH>;
+- states = <1800000 0x1
+- 3300000 0x0>;
+- };
+-};
+-
+-&firmware {
+- expgpio: gpio {
+- compatible = "raspberrypi,firmware-gpio";
+- gpio-controller;
+- #gpio-cells = <2>;
+- gpio-line-names = "BT_ON",
+- "WL_ON",
+- "PWR_LED_OFF",
+- "GLOBAL_RESET",
+- "VDD_SD_IO_SEL",
+- "CAM_GPIO",
+- "",
+- "";
+- status = "okay";
+- };
+-};
+-
+-&pwm1 {
+- pinctrl-names = "default";
+- pinctrl-0 = <&pwm0_gpio40 &pwm1_gpio41>;
+- status = "okay";
+-};
+-
+-/* SDHCI is used to control the SDIO for wireless */
+-&sdhci {
+- #address-cells = <1>;
+- #size-cells = <0>;
+- pinctrl-names = "default";
+- pinctrl-0 = <&emmc_gpio34>;
+- status = "okay";
+- bus-width = <4>;
+- non-removable;
+- mmc-pwrseq = <&wifi_pwrseq>;
+-
+- brcmf: wifi@1 {
+- reg = <1>;
+- compatible = "brcm,bcm4329-fmac";
+- };
+-};
+-
+-/* EMMC2 is used to drive the SD card */
+-&emmc2 {
+- status = "okay";
+- broken-cd;
+- vqmmc-supply = <&sd_io_1v8_reg>;
+-};
+-
+-/* uart0 communicates with the BT module */
+-&uart0 {
+- pinctrl-names = "default";
+- pinctrl-0 = <&uart0_ctsrts_gpio30 &uart0_gpio32 &gpclk2_gpio43>;
+- status = "okay";
+-
+- bluetooth {
+- compatible = "brcm,bcm43438-bt";
+- max-speed = <2000000>;
+- shutdown-gpios = <&expgpio 0 GPIO_ACTIVE_HIGH>;
+- };
+-};
+-
+-/* uart1 is mapped to the pin header */
+-&uart1 {
+- pinctrl-names = "default";
+- pinctrl-0 = <&uart1_gpio14>;
+- status = "okay";
+-};
--- /dev/null
+From 8ef5143f743a4e922fdf0029f81452d3d7003daf Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Wed, 29 Jan 2020 09:35:19 +0000
+Subject: [PATCH] tty: amba-pl011: Avoid rare write-when-full error
+
+Under some circumstances on BCM283x processors data loss can be
+observed - a single byte missing from the TX output stream. These bytes
+are always the last byte of a batch of 8 written from pl011_tx_chars
+when from_irq is true, meaning that the FIFO full flag is not checked
+before writing.
+
+The transmit optimisation relies on the FIFO being half-empty when the
+TX interrupt is raised. Instrumenting the driver further showed that
+the failure case correlated with the TX FIFO full flag being set at the
+point where the last byte was written to the data register, which
+explains the data loss but not how the FIFO appeared to be prematurely
+full. A possible explanation is that a FIFO write was in flight at the
+time the interrupt was raised, but as yet there is no hypothesis as to
+how this might occur.
+
+In the absence of a clear understanding of the failure mechanism, avoid
+the problem by checking the FIFO levels before writing the last byte of
+the group, which will have minimal performance impact.
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ drivers/tty/serial/amba-pl011.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/tty/serial/amba-pl011.c
++++ b/drivers/tty/serial/amba-pl011.c
+@@ -1444,6 +1444,10 @@ static bool pl011_tx_chars(struct uart_a
+ if (likely(from_irq) && count-- == 0)
+ break;
+
++ if (likely(from_irq) && count == 0 &&
++ pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
++ break;
++
+ if (!pl011_tx_char(uap, xmit->buf[xmit->tail], from_irq))
+ break;
+
--- /dev/null
+From fd483c4e43a983d90c308c4d668e83be4fd6a392 Mon Sep 17 00:00:00 2001
+From: Tim Gover <990920+timg236@users.noreply.github.com>
+Date: Wed, 15 Jan 2020 11:26:19 +0000
+Subject: [PATCH] usb: xhci: Raspberry Pi FW loader for VIA VL805
+
+The VL805 FW may either be loaded from an SPI EEPROM or alternatively
+loaded directly by the VideoCore firmware. A PCI reset will reset
+the VL805 XHCI controller on the Raspberry Pi4 requiring the firmware
+to be reloaded if an SPI EEPROM is not present.
+
+Use a VideoCore mailbox to trigger the loading of the VL805
+firmware (if necessary) after a PCI reset.
+
+Signed-off-by: Tim Gover <tim.gover@raspberrypi.org>
+---
+ drivers/usb/host/pci-quirks.c | 31 +++++++++++++++++++++-
+ include/soc/bcm2835/raspberrypi-firmware.h | 2 +-
+ 2 files changed, 31 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/host/pci-quirks.c
++++ b/drivers/usb/host/pci-quirks.c
+@@ -18,7 +18,7 @@
+ #include <linux/dmi.h>
+ #include "pci-quirks.h"
+ #include "xhci-ext-caps.h"
+-
++#include <soc/bcm2835/raspberrypi-firmware.h>
+
+ #define UHCI_USBLEGSUP 0xc0 /* legacy support */
+ #define UHCI_USBCMD 0 /* command register */
+@@ -632,6 +632,32 @@ EXPORT_SYMBOL_GPL(usb_amd_pt_check_port)
+
+ #endif /* CONFIG_PCI_DISABLE_COMMON_QUIRKS */
+
++/* The VL805 firmware may either be loaded from an EEPROM or by the BIOS into
++ * memory. If run from memory it must be reloaded after a PCI fundmental reset.
++ * The Raspberry Pi firmware acts as the BIOS in this case.
++ */
++static void usb_vl805_init(struct pci_dev *pdev)
++{
++#if IS_ENABLED(CONFIG_RASPBERRYPI_FIRMWARE)
++ struct rpi_firmware *fw;
++ struct {
++ u32 dev_addr;
++ } packet;
++ int ret;
++
++ fw = rpi_firmware_get(NULL);
++ if (!fw)
++ return;
++
++ packet.dev_addr = (pdev->bus->number << 20) |
++ (PCI_SLOT(pdev->devfn) << 15) | (PCI_FUNC(pdev->devfn) << 12);
++
++ dev_dbg(&pdev->dev, "RPI_FIRMWARE_NOTIFY_XHCI_RESET %x", packet.dev_addr);
++ ret = rpi_firmware_property(fw, RPI_FIRMWARE_NOTIFY_XHCI_RESET,
++ &packet, sizeof(packet));
++#endif
++}
++
+ #if IS_ENABLED(CONFIG_USB_UHCI_HCD)
+
+ /*
+@@ -1226,6 +1252,9 @@ hc_init:
+ if (pdev->vendor == PCI_VENDOR_ID_INTEL)
+ usb_enable_intel_xhci_ports(pdev);
+
++ if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == 0x3483)
++ usb_vl805_init(pdev);
++
+ op_reg_base = base + XHCI_HC_LENGTH(readl(base));
+
+ /* Wait for the host controller to be ready before writing any
+--- a/include/soc/bcm2835/raspberrypi-firmware.h
++++ b/include/soc/bcm2835/raspberrypi-firmware.h
+@@ -98,7 +98,7 @@ enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_SET_PERIPH_REG = 0x00038045,
+ RPI_FIRMWARE_GET_POE_HAT_VAL = 0x00030049,
+ RPI_FIRMWARE_SET_POE_HAT_VAL = 0x00030050,
+-
++ RPI_FIRMWARE_NOTIFY_XHCI_RESET = 0x00030058,
+
+ /* Dispmanx TAGS */
+ RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE = 0x00040001,
--- /dev/null
+From 8a120b47005fccce4534f8a73c3a3deda92f95fa Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Wed, 29 Jan 2020 14:32:51 +0000
+Subject: [PATCH] overlays: Correct the eth_led* colour assignments
+
+See: https://github.com/raspberrypi/firmware/issues/1311
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/overlays/README | 17 +++++++++--------
+ 1 file changed, 9 insertions(+), 8 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -109,27 +109,28 @@ Params:
+ Legal values are 2, 3, 4, 5 and 0, where
+ 0 means never downshift (default 2). Pi3B+ only.
+
+- eth_led0 Set mode of LED0 (usually orange). The legal
+- values are:
++ eth_led0 Set mode of LED0 - amber on Pi3B+ (default "1"),
++ green on Pi4 (default "0").
++ The legal values are:
+
+ Pi3B+
+
+- 0=link/activity 1=link1000/activity (default)
++ 0=link/activity 1=link1000/activity
+ 2=link100/activity 3=link10/activity
+ 4=link100/1000/activity 5=link10/1000/activity
+ 6=link10/100/activity 14=off 15=on
+
+ Pi4
+
+- 0=Speed/Activity (default) 1=Speed
+- 2=Speed/Flash activity 3=FDX
++ 0=Speed/Activity 1=Speed
++ 2=Flash activity 3=FDX
+ 4=Off 5=On
+ 6=Alt 7=Speed/Flash
+ 8=Link 9=Activity
+
+- eth_led1 Set mode of LED1 (usually green) (Pi3B+ default
+- "6", Pi4 default "8"). See eth_led0 for legal
+- values.
++ eth_led1 Set mode of LED1 - green on Pi3B (default "6"),
++ amber on Pi4 (default "8"). See eth_led0 for
++ legal values.
+
+ eth_max_speed Set the maximum speed a link is allowed
+ to negotiate. Legal values are 10, 100 and
--- /dev/null
+From b006cc7ddfa96c044068ef367c0bc82c2d221ca3 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Tue, 1 Oct 2019 10:19:50 +0100
+Subject: [PATCH] overlays: Remove hack from uart0 overlay
+
+The uart0 overlay contained a hack to return GPIOs 14 and 15 to inputs
+when the UART0 function was moved to alternative pins. This has the
+unwanted side effect of claiming GPIOs 14 & 15, preventing them being
+used for something else.
+
+See: https://github.com/raspberrypi/linux/issues/2856
+ https://www.raspberrypi.org/forums/viewtopic.php?f=98&t=252911
+
+Signed-off-by: Stefan Enge <stefan.enge@escatec.com>
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/overlays/uart0-overlay.dts | 13 ++++++-------
+ 1 file changed, 6 insertions(+), 7 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/uart0-overlay.dts
++++ b/arch/arm/boot/dts/overlays/uart0-overlay.dts
+@@ -17,17 +17,16 @@
+ target = <&gpio>;
+ __overlay__ {
+ uart0_pins: uart0_pins {
+- brcm,pins = <14 15 14 15>;
+- brcm,function = <0 0 4 4>; /* alt0 */
+- brcm,pull = <0 0 0 2>;
++ brcm,pins = <14 15>;
++ brcm,function = <4>; /* alt0 */
++ brcm,pull = <0 2>;
+ };
+ };
+ };
+
+ __overrides__ {
+- txd0_pin = <&uart0_pins>,"brcm,pins:8";
+- rxd0_pin = <&uart0_pins>,"brcm,pins:12";
+- pin_func = <&uart0_pins>,"brcm,function:8",
+- <&uart0_pins>,"brcm,function:12";
++ txd0_pin = <&uart0_pins>,"brcm,pins:0";
++ rxd0_pin = <&uart0_pins>,"brcm,pins:4";
++ pin_func = <&uart0_pins>,"brcm,function:0";
+ };
+ };
--- /dev/null
+From d7044f06dea839c61a01e6016a4b9dee15543f8d Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.org>
+Date: Thu, 30 Jan 2020 09:47:00 +0000
+Subject: [PATCH] ARM: dts: Add sd_poll_once dtparam to bcm283x/2711
+
+The old sdtweak overlay allowed the SD interface to be effectively
+disabled unless there was a card present at boot time, but that
+overlay doesn't work on bcm2711 and has largely been replaced by
+a set of sd_* dtparams (which have the advantage of being board-
+specific.
+
+Add an sd_poll_once dtparam to allow the same functionality on
+all Raspberry Pi boards.
+
+See: https://github.com/raspberrypi/linux/issues/3286
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.org>
+---
+ arch/arm/boot/dts/bcm2708-rpi.dtsi | 1 +
+ arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 2 ++
+ arch/arm/boot/dts/overlays/README | 7 +++++++
+ 3 files changed, 10 insertions(+)
+
+--- a/arch/arm/boot/dts/bcm2708-rpi.dtsi
++++ b/arch/arm/boot/dts/bcm2708-rpi.dtsi
+@@ -92,6 +92,7 @@
+ watchdog = <&watchdog>,"status";
+ random = <&random>,"status";
+ sd_overclock = <&sdhost>,"brcm,overclock-50:0";
++ sd_poll_once = <&sdhost>,"non-removable?";
+ sd_force_pio = <&sdhost>,"brcm,force-pio?";
+ sd_pio_limit = <&sdhost>,"brcm,pio-limit:0";
+ sd_debug = <&sdhost>,"brcm,debug";
+--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
+@@ -349,5 +349,7 @@
+
+ eth_led0 = <&phy1>,"led-modes:0";
+ eth_led1 = <&phy1>,"led-modes:4";
++
++ sd_poll_once = <&emmc2>, "non-removable?";
+ };
+ };
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -165,6 +165,13 @@ Params:
+ sd_overclock Clock (in MHz) to use when the MMC framework
+ requests 50MHz
+
++ sd_poll_once Looks for a card once after booting. Useful
++ for network booting scenarios to avoid the
++ overhead of continuous polling. N.B. Using
++ this option restricts the system to using a
++ single card per boot (or none at all).
++ (default off)
++
+ sd_force_pio Disable DMA support for SD driver (default off)
+
+ sd_pio_limit Number of blocks above which to use DMA for
--- /dev/null
+From db048a80e63c66607b3bd73fa641802ec83bf166 Mon Sep 17 00:00:00 2001
+From: MikeDK <m.kaplan@evva.com>
+Date: Fri, 31 Jan 2020 10:57:21 +0100
+Subject: [PATCH] overlays: Add ssd1306-spi overlay (#3440)
+
+Add an overlay for SSD1306 based OLED boards using SPI.
+This will load the staging fbtft driver.
+
+Signed-off-by: Michael Kaplan <m.kaplan@evva.com>
+---
+ arch/arm/boot/dts/overlays/Makefile | 1 +
+ arch/arm/boot/dts/overlays/README | 12 +++
+ .../boot/dts/overlays/ssd1306-spi-overlay.dts | 82 +++++++++++++++++++
+ 3 files changed, 95 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/ssd1306-spi-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -168,6 +168,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ spi6-1cs.dtbo \
+ spi6-2cs.dtbo \
+ ssd1306.dtbo \
++ ssd1306-spi.dtbo \
+ superaudioboard.dtbo \
+ sx150x.dtbo \
+ tc358743.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -2428,6 +2428,18 @@ Params: address Location
+ https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf
+
+
++Name: ssd1306-spi
++Info: Overlay for SSD1306 OLED via SPI using fbtft staging driver.
++Load: dtoverlay=ssd1306-spi,<param>=<val>
++Params: speed SPI bus speed (default 10000000)
++ rotate Display rotation (0, 90, 180 or 270; default 0)
++ fps Delay between frame updates (default 25)
++ debug Debug output level (0-7; default 0)
++ dc_pin GPIO pin for D/C (default 24)
++ reset_pin GPIO pin for RESET (default 25)
++ height Display height (32 or 64; default 64)
++
++
+ Name: superaudioboard
+ Info: Configures the SuperAudioBoard sound card
+ Load: dtoverlay=superaudioboard,<param>=<val>
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/ssd1306-spi-overlay.dts
+@@ -0,0 +1,82 @@
++/*
++ * Device Tree overlay for SSD1306 based SPI OLED display
++ *
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835";
++
++ fragment@0 {
++ target = <&spi0>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&spidev0>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@2 {
++ target = <&spidev1>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@3 {
++ target = <&gpio>;
++ __overlay__ {
++ ssd1306_pins: ssd1306_pins {
++ brcm,pins = <25 24>;
++ brcm,function = <1 1>; /* out out */
++ };
++ };
++ };
++
++ fragment@4 {
++ target = <&spi0>;
++ __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ ssd1306: ssd1306@0{
++ compatible = "solomon,ssd1306";
++ reg = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&ssd1306_pins>;
++
++ spi-max-frequency = <10000000>;
++ bgr = <0>;
++ bpp = <1>;
++ rotate = <0>;
++ fps = <25>;
++ buswidth = <8>;
++ reset-gpios = <&gpio 25 0>;
++ dc-gpios = <&gpio 24 0>;
++ debug = <0>;
++
++ solomon,height = <64>;
++ solomon,width = <128>;
++ solomon,page-offset = <0>;
++ };
++ };
++ };
++
++ __overrides__ {
++ speed = <&ssd1306>,"spi-max-frequency:0";
++ rotate = <&ssd1306>,"rotate:0";
++ fps = <&ssd1306>,"fps:0";
++ debug = <&ssd1306>,"debug:0";
++ dc_pin = <&ssd1306>,"dc-gpios:4>";
++ reset_pin = <&ssd1306>,"reset-gpios:4>";
++ height = <&ssd1306>,"solomon,height:0>";
++ };
++};
--- /dev/null
+From 1b8ea7066ee06404e0148702bc3e85a191f6d867 Mon Sep 17 00:00:00 2001
+From: MikeDK <m.kaplan@evva.com>
+Date: Fri, 31 Jan 2020 12:45:43 +0100
+Subject: [PATCH] overlays: Add sh1106-spi and ssd1351-spi overlays
+ (#3442)
+
+Add overlays for SH1106 and SSD1351 based OLED displays.
+SH1106 is present in many 1.3 inch OLEDs and SSD1351 is present in
+1.5 inch RGB OLEDs from AliExpress.
+
+This will load the staging fbtft drivers.
+
+Signed-off-by: Michael Kaplan <m.kaplan@evva.com>
+---
+ arch/arm/boot/dts/overlays/Makefile | 2 +
+ arch/arm/boot/dts/overlays/README | 23 ++++++
+ .../boot/dts/overlays/sh1106-spi-overlay.dts | 82 +++++++++++++++++++
+ .../boot/dts/overlays/ssd1351-spi-overlay.dts | 81 ++++++++++++++++++
+ 4 files changed, 188 insertions(+)
+ create mode 100644 arch/arm/boot/dts/overlays/sh1106-spi-overlay.dts
+ create mode 100644 arch/arm/boot/dts/overlays/ssd1351-spi-overlay.dts
+
+--- a/arch/arm/boot/dts/overlays/Makefile
++++ b/arch/arm/boot/dts/overlays/Makefile
+@@ -145,6 +145,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ sdhost.dtbo \
+ sdio.dtbo \
+ sdtweak.dtbo \
++ sh1106-spi.dtbo \
+ smi.dtbo \
+ smi-dev.dtbo \
+ smi-nand.dtbo \
+@@ -169,6 +170,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
+ spi6-2cs.dtbo \
+ ssd1306.dtbo \
+ ssd1306-spi.dtbo \
++ ssd1351-spi.dtbo \
+ superaudioboard.dtbo \
+ sx150x.dtbo \
+ tc358743.dtbo \
+--- a/arch/arm/boot/dts/overlays/README
++++ b/arch/arm/boot/dts/overlays/README
+@@ -2145,6 +2145,18 @@ Params: overclock_50 Clock (i
+ (default on)
+
+
++Name: sh1106-spi
++Info: Overlay for SH1106 OLED via SPI using fbtft staging driver.
++Load: dtoverlay=sh1106-spi,<param>=<val>
++Params: speed SPI bus speed (default 4000000)
++ rotate Display rotation (0, 90, 180 or 270; default 0)
++ fps Delay between frame updates (default 25)
++ debug Debug output level (0-7; default 0)
++ dc_pin GPIO pin for D/C (default 24)
++ reset_pin GPIO pin for RESET (default 25)
++ height Display height (32 or 64; default 64)
++
++
+ Name: smi
+ Info: Enables the Secondary Memory Interface peripheral. Uses GPIOs 2-25!
+ Load: dtoverlay=smi
+@@ -2440,6 +2452,17 @@ Params: speed SPI bus
+ height Display height (32 or 64; default 64)
+
+
++Name: ssd1351-spi
++Info: Overlay for SSD1351 OLED via SPI using fbtft staging driver.
++Load: dtoverlay=ssd1351-spi,<param>=<val>
++Params: speed SPI bus speed (default 4500000)
++ rotate Display rotation (0, 90, 180 or 270; default 0)
++ fps Delay between frame updates (default 25)
++ debug Debug output level (0-7; default 0)
++ dc_pin GPIO pin for D/C (default 24)
++ reset_pin GPIO pin for RESET (default 25)
++
++
+ Name: superaudioboard
+ Info: Configures the SuperAudioBoard sound card
+ Load: dtoverlay=superaudioboard,<param>=<val>
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/sh1106-spi-overlay.dts
+@@ -0,0 +1,82 @@
++/*
++ * Device Tree overlay for SH1106 based SPI OLED display
++ *
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835";
++
++ fragment@0 {
++ target = <&spi0>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&spidev0>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@2 {
++ target = <&spidev1>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@3 {
++ target = <&gpio>;
++ __overlay__ {
++ sh1106_pins: sh1106_pins {
++ brcm,pins = <25 24>;
++ brcm,function = <1 1>; /* out out */
++ };
++ };
++ };
++
++ fragment@4 {
++ target = <&spi0>;
++ __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ sh1106: sh1106@0{
++ compatible = "sinowealth,sh1106";
++ reg = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&sh1106_pins>;
++
++ spi-max-frequency = <4000000>;
++ bgr = <0>;
++ bpp = <1>;
++ rotate = <0>;
++ fps = <25>;
++ buswidth = <8>;
++ reset-gpios = <&gpio 25 0>;
++ dc-gpios = <&gpio 24 0>;
++ debug = <0>;
++
++ sinowealth,height = <64>;
++ sinowealth,width = <128>;
++ sinowealth,page-offset = <0>;
++ };
++ };
++ };
++
++ __overrides__ {
++ speed = <&sh1106>,"spi-max-frequency:0";
++ rotate = <&sh1106>,"rotate:0";
++ fps = <&sh1106>,"fps:0";
++ debug = <&sh1106>,"debug:0";
++ dc_pin = <&sh1106>,"dc-gpios:4>";
++ reset_pin = <&sh1106>,"reset-gpios:4>";
++ height = <&sh1106>,"sinowealth,height:0>";
++ };
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/overlays/ssd1351-spi-overlay.dts
+@@ -0,0 +1,81 @@
++/*
++ * Device Tree overlay for SSD1351 based SPI OLED display
++ *
++ */
++
++/dts-v1/;
++/plugin/;
++
++/ {
++ compatible = "brcm,bcm2835";
++
++ fragment@0 {
++ target = <&spi0>;
++ __overlay__ {
++ status = "okay";
++ };
++ };
++
++ fragment@1 {
++ target = <&spidev0>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@2 {
++ target = <&spidev1>;
++ __overlay__ {
++ status = "disabled";
++ };
++ };
++
++ fragment@3 {
++ target = <&gpio>;
++ __overlay__ {
++ ssd1351_pins: ssd1351_pins {
++ brcm,pins = <25 24>;
++ brcm,function = <1 1>; /* out out */
++ };
++ };
++ };
++
++ fragment@4 {
++ target = <&spi0>;
++ __overlay__ {
++ /* needed to avoid dtc warning */
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ ssd1351: ssd1351@0{
++ compatible = "solomon,ssd1351";
++ reg = <0>;
++ pinctrl-names = "default";
++ pinctrl-0 = <&ssd1351_pins>;
++
++ spi-max-frequency = <4500000>;
++ bgr = <0>;
++ bpp = <16>;
++ rotate = <0>;
++ fps = <25>;
++ buswidth = <8>;
++ reset-gpios = <&gpio 25 0>;
++ dc-gpios = <&gpio 24 0>;
++ debug = <0>;
++
++ solomon,height = <128>;
++ solomon,width = <128>;
++ solomon,page-offset = <0>;
++ };
++ };
++ };
++
++ __overrides__ {
++ speed = <&ssd1351>,"spi-max-frequency:0";
++ rotate = <&ssd1351>,"rotate:0";
++ fps = <&ssd1351>,"fps:0";
++ debug = <&ssd1351>,"debug:0";
++ dc_pin = <&ssd1351>,"dc-gpios:4>";
++ reset_pin = <&ssd1351>,"reset-gpios:4>";
++ };
++};
--- /dev/null
+From 389107911744588cce5e06c23a058c9cfb641f33 Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Tue, 4 Feb 2020 13:03:21 +0000
+Subject: [PATCH] overlays: dwc2: Increase RX FIFO size
+
+The previous version of the dwc2 overlay set the RX FIFO size to
+256 4-byte words. This sounds large enough for a 1024 byte packet (the
+largest isochronous high speed packet allowed), but it doesn't take
+into account some extra space needed by the hardware.
+
+Minas Harutyunyan at Synopsys (the source of the DWC OTG design)
+came up with a more correct value, 301, but since there is spare packet
+RAM this can be increased to 558 to allow two packets per frame.
+
+See: https://github.com/raspberrypi/linux/issues/3447
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ arch/arm/boot/dts/overlays/dwc2-overlay.dts | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/boot/dts/overlays/dwc2-overlay.dts
++++ b/arch/arm/boot/dts/overlays/dwc2-overlay.dts
+@@ -12,7 +12,7 @@
+ compatible = "brcm,bcm2835-usb";
+ dr_mode = "otg";
+ g-np-tx-fifo-size = <32>;
+- g-rx-fifo-size = <256>;
++ g-rx-fifo-size = <558>;
+ g-tx-fifo-size = <512 512 512 512 512 256 256>;
+ status = "okay";
+ };
--- /dev/null
+From 11ef396f6e72b22469e1c8aebf5fd50488a9431d Mon Sep 17 00:00:00 2001
+From: Phil Elwell <phil@raspberrypi.com>
+Date: Tue, 4 Feb 2020 15:22:55 +0000
+Subject: [PATCH] overlays: Fix mcp23017's addr parameter
+
+The addr parameter of the mcp23017 overlay was broken by the addition
+of the noints parameter; splitting the mcp node in two without also
+modifying the second half from the addr parameter would cause the two
+halves to separate. Change the implementation strategy to patch
+fragment 2 (as was originally proposed). This will prevent the
+overlay from being applied at runtime until the "dtoverlay" command
+is improved, but the overlay already has this restriction due to
+fragment 3 so this isn't a step backwards.
+
+See: https://github.com/raspberrypi/linux/issues/3449
+
+Signed-off-by: Phil Elwell <phil@raspberrypi.com>
+---
+ arch/arm/boot/dts/overlays/mcp23017-overlay.dts | 16 +++++++---------
+ 1 file changed, 7 insertions(+), 9 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/mcp23017-overlay.dts
++++ b/arch/arm/boot/dts/overlays/mcp23017-overlay.dts
+@@ -48,15 +48,13 @@
+ };
+
+ fragment@4 {
+- target = <&i2c1>;
+- __overlay__ {
+- mcp23017_irq: mcp@20 {
+- #interrupt-cells=<2>;
+- interrupt-parent = <&gpio>;
+- interrupts = <4 2>;
+- interrupt-controller;
+- microchip,irq-mirror;
+- };
++ target = <&mcp23017>;
++ mcp23017_irq: __overlay__ {
++ #interrupt-cells=<2>;
++ interrupt-parent = <&gpio>;
++ interrupts = <4 2>;
++ interrupt-controller;
++ microchip,irq-mirror;
+ };
+ };
+
--- /dev/null
+From f80af7bdb76f767a236eeb55b6ea210023180cd6 Mon Sep 17 00:00:00 2001
+From: Michael Kaplan <m.kaplan@evva.com>
+Date: Tue, 4 Feb 2020 16:14:48 +0100
+Subject: [PATCH] overlays: fix sh1106-spi, ssd1306-spi and ssd1351-spi overlays
+
+---
+ .../arm/boot/dts/overlays/sh1106-spi-overlay.dts | 16 +++++++++-------
+ .../boot/dts/overlays/ssd1306-spi-overlay.dts | 16 +++++++++-------
+ .../boot/dts/overlays/ssd1351-spi-overlay.dts | 14 ++++++++------
+ 3 files changed, 26 insertions(+), 20 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/sh1106-spi-overlay.dts
++++ b/arch/arm/boot/dts/overlays/sh1106-spi-overlay.dts
+@@ -71,12 +71,14 @@
+ };
+
+ __overrides__ {
+- speed = <&sh1106>,"spi-max-frequency:0";
+- rotate = <&sh1106>,"rotate:0";
+- fps = <&sh1106>,"fps:0";
+- debug = <&sh1106>,"debug:0";
+- dc_pin = <&sh1106>,"dc-gpios:4>";
+- reset_pin = <&sh1106>,"reset-gpios:4>";
+- height = <&sh1106>,"sinowealth,height:0>";
++ speed = <&sh1106>,"spi-max-frequency:0";
++ rotate = <&sh1106>,"rotate:0";
++ fps = <&sh1106>,"fps:0";
++ debug = <&sh1106>,"debug:0";
++ dc_pin = <&sh1106>,"dc-gpios:4",
++ <&sh1106_pins>,"brcm,pins:4;
++ reset_pin = <&sh1106>,"reset-gpios:4",
++ <&sh1106_pins>,"brcm,pins:0;
++ height = <&sh1106>,"sinowealth,height:0";
+ };
+ };
+--- a/arch/arm/boot/dts/overlays/ssd1306-spi-overlay.dts
++++ b/arch/arm/boot/dts/overlays/ssd1306-spi-overlay.dts
+@@ -71,12 +71,14 @@
+ };
+
+ __overrides__ {
+- speed = <&ssd1306>,"spi-max-frequency:0";
+- rotate = <&ssd1306>,"rotate:0";
+- fps = <&ssd1306>,"fps:0";
+- debug = <&ssd1306>,"debug:0";
+- dc_pin = <&ssd1306>,"dc-gpios:4>";
+- reset_pin = <&ssd1306>,"reset-gpios:4>";
+- height = <&ssd1306>,"solomon,height:0>";
++ speed = <&ssd1306>,"spi-max-frequency:0";
++ rotate = <&ssd1306>,"rotate:0";
++ fps = <&ssd1306>,"fps:0";
++ debug = <&ssd1306>,"debug:0";
++ dc_pin = <&ssd1306>,"dc-gpios:4";
++ <&ssd1306_pins>,"brcm,pins:4";
++ reset_pin = <&ssd1306>,"reset-gpios:4";
++ <&ssd1306_pins>,"brcm,pins:0";
++ height = <&ssd1306>,"solomon,height:0";
+ };
+ };
+--- a/arch/arm/boot/dts/overlays/ssd1351-spi-overlay.dts
++++ b/arch/arm/boot/dts/overlays/ssd1351-spi-overlay.dts
+@@ -71,11 +71,13 @@
+ };
+
+ __overrides__ {
+- speed = <&ssd1351>,"spi-max-frequency:0";
+- rotate = <&ssd1351>,"rotate:0";
+- fps = <&ssd1351>,"fps:0";
+- debug = <&ssd1351>,"debug:0";
+- dc_pin = <&ssd1351>,"dc-gpios:4>";
+- reset_pin = <&ssd1351>,"reset-gpios:4>";
++ speed = <&ssd1351>,"spi-max-frequency:0";
++ rotate = <&ssd1351>,"rotate:0";
++ fps = <&ssd1351>,"fps:0";
++ debug = <&ssd1351>,"debug:0";
++ dc_pin = <&ssd1351>,"dc-gpios:4",
++ <&ssd1351_pins>,"brcm,pins:4";
++ reset_pin = <&ssd1351>,"reset-gpios:4";
++ <&ssd1351_pins>,"brcm,pins:0";
+ };
+ };
--- /dev/null
+From 45754db702ff044e45ba14efdcf3708151e25c5f Mon Sep 17 00:00:00 2001
+From: Jason Kim <sukbeom.kim@gmail.com>
+Date: Wed, 5 Feb 2020 01:48:10 +0900
+Subject: [PATCH] Fix a sh1106-spi, ssd1306-spi, ssd1351-spi overlays
+
+---
+ arch/arm/boot/dts/overlays/sh1106-spi-overlay.dts | 4 ++--
+ arch/arm/boot/dts/overlays/ssd1306-spi-overlay.dts | 4 ++--
+ arch/arm/boot/dts/overlays/ssd1351-spi-overlay.dts | 2 +-
+ 3 files changed, 5 insertions(+), 5 deletions(-)
+
+--- a/arch/arm/boot/dts/overlays/sh1106-spi-overlay.dts
++++ b/arch/arm/boot/dts/overlays/sh1106-spi-overlay.dts
+@@ -76,9 +76,9 @@
+ fps = <&sh1106>,"fps:0";
+ debug = <&sh1106>,"debug:0";
+ dc_pin = <&sh1106>,"dc-gpios:4",
+- <&sh1106_pins>,"brcm,pins:4;
++ <&sh1106_pins>,"brcm,pins:4";
+ reset_pin = <&sh1106>,"reset-gpios:4",
+- <&sh1106_pins>,"brcm,pins:0;
++ <&sh1106_pins>,"brcm,pins:0";
+ height = <&sh1106>,"sinowealth,height:0";
+ };
+ };
+--- a/arch/arm/boot/dts/overlays/ssd1306-spi-overlay.dts
++++ b/arch/arm/boot/dts/overlays/ssd1306-spi-overlay.dts
+@@ -75,9 +75,9 @@
+ rotate = <&ssd1306>,"rotate:0";
+ fps = <&ssd1306>,"fps:0";
+ debug = <&ssd1306>,"debug:0";
+- dc_pin = <&ssd1306>,"dc-gpios:4";
++ dc_pin = <&ssd1306>,"dc-gpios:4",
+ <&ssd1306_pins>,"brcm,pins:4";
+- reset_pin = <&ssd1306>,"reset-gpios:4";
++ reset_pin = <&ssd1306>,"reset-gpios:4",
+ <&ssd1306_pins>,"brcm,pins:0";
+ height = <&ssd1306>,"solomon,height:0";
+ };
+--- a/arch/arm/boot/dts/overlays/ssd1351-spi-overlay.dts
++++ b/arch/arm/boot/dts/overlays/ssd1351-spi-overlay.dts
+@@ -77,7 +77,7 @@
+ debug = <&ssd1351>,"debug:0";
+ dc_pin = <&ssd1351>,"dc-gpios:4",
+ <&ssd1351_pins>,"brcm,pins:4";
+- reset_pin = <&ssd1351>,"reset-gpios:4";
++ reset_pin = <&ssd1351>,"reset-gpios:4",
+ <&ssd1351_pins>,"brcm,pins:0";
+ };
+ };