diff options
author | Timo Teräs <timo.teras@iki.fi> | 2016-06-02 11:00:57 +0000 |
---|---|---|
committer | Timo Teräs <timo.teras@iki.fi> | 2016-06-02 11:01:51 +0000 |
commit | bd87780d5cca8b28eb53f39a3c12abc29fc5148a (patch) | |
tree | ba33111ed76fbac8c03650fd98a986a4dfc7760d /main/linux-rpi | |
parent | 526628d341e39ea0ba9de83e9e19d00d4921aebf (diff) | |
download | aports-bd87780d5cca8b28eb53f39a3c12abc29fc5148a.tar.bz2 aports-bd87780d5cca8b28eb53f39a3c12abc29fc5148a.tar.xz |
main/linux-rpi: upgrade to 4.4.12
Diffstat (limited to 'main/linux-rpi')
-rw-r--r-- | main/linux-rpi/APKBUILD | 26 | ||||
-rw-r--r-- | main/linux-rpi/rpi-cirrus-4.4.y-20160514.patch | 1534 |
2 files changed, 13 insertions, 1547 deletions
diff --git a/main/linux-rpi/APKBUILD b/main/linux-rpi/APKBUILD index a6b4696ec8..9fccd274a8 100644 --- a/main/linux-rpi/APKBUILD +++ b/main/linux-rpi/APKBUILD @@ -1,12 +1,12 @@ # Maintainer: Natanael Copa <ncopa@alpinelinux.org> pkgname=linux-rpi -pkgver=4.4.11 +pkgver=4.4.12 case $pkgver in *.*.*) _kernver=${pkgver%.*};; *.*) _kernver=${pkgver};; esac -pkgrel=3 +pkgrel=0 pkgdesc="Linux kernel with Raspberry Pi patches" url=https://github.com/raspberrypi/linux depends="mkinitfs linux-firmware" @@ -15,8 +15,8 @@ options="!strip" install= source="http://ftp.kernel.org/pub/linux/kernel/v4.x/linux-$_kernver.tar.xz http://ftp.kernel.org/pub/linux/kernel/v4.x/patch-$pkgver.xz - http://dev.alpinelinux.org/~tteras/rpi/linux-4.4.y-rpi-20160514.patch - rpi-cirrus-4.4.y-20160514.patch + http://dev.alpinelinux.org/~tteras/rpi/linux-4.4.y-rpi-20160602.patch + http://dev.alpinelinux.org/~tteras/rpi/rpi-cirrus-4.4.y-20160602.patch gpio-mcp23s08-pullups.patch rotary-encoder-fix.patch issue-4973.patch @@ -196,9 +196,9 @@ for _f in $_flavors; do done md5sums="9a78fa2eb6c68ca5a40ed5af08142599 linux-4.4.tar.xz -5c1d328f03aaafb9cf7fdc442468c348 patch-4.4.11.xz -1d08efb60aaa1a161aaa128807fcd8ce linux-4.4.y-rpi-20160514.patch -1ac525e064919fd4ffec5d40b910cae1 rpi-cirrus-4.4.y-20160514.patch +80d71a51152029a3f2fe99ba94548009 patch-4.4.12.xz +1609c27d419440bc5eb338feffa4ab9d linux-4.4.y-rpi-20160602.patch +f7142b2154dd5cfb5688ba692195ef6f rpi-cirrus-4.4.y-20160602.patch b66e8aa4991ca5c2ccd61559ed7e6491 gpio-mcp23s08-pullups.patch 5508d2b3e5967bd57f92f551d90b3e54 rotary-encoder-fix.patch 29281b74d2cef6965fa4ab6d826a2aa4 issue-4973.patch @@ -206,9 +206,9 @@ b66e8aa4991ca5c2ccd61559ed7e6491 gpio-mcp23s08-pullups.patch 26fbc79db35af5f371caf258336d5ab9 config-rpi2.armhf e587cae1dca2f5992555d9bcf53deecf markdt" sha256sums="401d7c8fef594999a460d10c72c5a94e9c2e1022f16795ec51746b0d165418b2 linux-4.4.tar.xz -394c3970865c092f21cd02b8f433024adbf8539114567d6bde197fed6612f553 patch-4.4.11.xz -68b19c4c589afa869d6278d775a34bb30bc83b3e09c703d9df3163f144a9d36e linux-4.4.y-rpi-20160514.patch -651845267ee7ee815cc5e78cad9dad87d3de388ce07f911f68b20880ca1e3292 rpi-cirrus-4.4.y-20160514.patch +1eb89dddd7e89caf2df17470b4b15da451ef1aa97f8e1a88578a8ee2da75729a patch-4.4.12.xz +f05f9cb93a6445b07231afd4ac1052ca572bf7441c7d5c073edc2c99a28af096 linux-4.4.y-rpi-20160602.patch +2e108a1d5e261e9193a2999afafef41e04e274db4c43607a1164d03d744c1e8e rpi-cirrus-4.4.y-20160602.patch b389a556bbd98053881b43deef1adf20640f980557c5f37cfd7ece2daeecbda9 gpio-mcp23s08-pullups.patch ab6740577fe8c1d71d2c716720ebbbf9a750985963d6938093b4ca9194b6e871 rotary-encoder-fix.patch 3a16e927ce53a8c56e7f1dd86fe8ad08b1c06466f5206c521a7e2de1e4796d6c issue-4973.patch @@ -216,9 +216,9 @@ ab6740577fe8c1d71d2c716720ebbbf9a750985963d6938093b4ca9194b6e871 rotary-encoder b46b7f6fece372840d8818c35fc74f09de7f2fba71eb2b86b184e37b5ed07484 config-rpi2.armhf 0f6681fc5c3590e1dbe13a2bde796403bd1529cf0fe19720899eaa0db79bcb49 markdt" sha512sums="13c8459933a8b80608e226a1398e3d1848352ace84bcfb7e6a4a33cb230bbe1ab719d4b58e067283df91ce5311be6d2d595fc8c19e2ae6ecc652499415614b3e linux-4.4.tar.xz -697e6dd2b85da13ae65ac70b9654c9c3fa00c3120d425fdb53104fc234457cda40b9f0ebe29e7ae5c1a191730666c0bbd291721b16623ee8e402287771f20def patch-4.4.11.xz -77818e23a9ae1854589da425377f8ea96581166597a18f5fd70f1cfca2a7049d42aea239c25836e91702436b079369f0aa427c4eee58e43d1e4d5dcf7d62488d linux-4.4.y-rpi-20160514.patch -abe4d482a98450335eb935cf49be468accc8955a464553c45280f15d4114a87e96b158800536c2f6c09be07474386bef952d1f96e58eaac5a4f6d6bd47e845c1 rpi-cirrus-4.4.y-20160514.patch +c3aca55f26fc883b489635a90b79c03d7c6d591efddb4e406b5bfe49fc4326ff2a957521b1d8ea126b95f1d0573e5185d96bce10d05eae595a51f8eb27690404 patch-4.4.12.xz +bb7bde9521281e5507bf0b0ed8912f56bd374df908f7f5f348a2faf223f3b92702988bdd07d0515aa90b4b03630de0edba598b3ebe49653483992828eea59e2b linux-4.4.y-rpi-20160602.patch +9313a0553eee9d21efc019444273a4f6359afa6efaf12f1a65876f0fec43358e0a82ac851c6b830e28f8ae7f30e803949dcc40bcab43d57b3c50234fad2e621a rpi-cirrus-4.4.y-20160602.patch 36724ba56cb8fdf3a3d347cffb67ae1cc3d7b1052d526b6b5134ebf6baae9f9724b586c97833453dc7697ab24699426f0749af78b6a80be36967a80033a0cf40 gpio-mcp23s08-pullups.patch 3a711e2cdb6c0ecaceb3755437d38626dec8403e8aa167a6e16f64d8a8b7cc5bdc7e04aa7c05938719ebc90e319ec4124ee2151a7855e7838ee143b62d140ad0 rotary-encoder-fix.patch 501c91bf2538a18102da59bbccc3097f9c3c90079acc0e946ff075074160c09b8a66934e5ce5470e170f0e4f93d114709a95230367426d0bb7ea02c4bdf4cc9b issue-4973.patch diff --git a/main/linux-rpi/rpi-cirrus-4.4.y-20160514.patch b/main/linux-rpi/rpi-cirrus-4.4.y-20160514.patch deleted file mode 100644 index 26c41b867d..0000000000 --- a/main/linux-rpi/rpi-cirrus-4.4.y-20160514.patch +++ /dev/null @@ -1,1534 +0,0 @@ -diff --git a/Documentation/devicetree/bindings/mfd/arizona.txt b/Documentation/devicetree/bindings/mfd/arizona.txt -index 18be0cb..4b3510a 100644 ---- a/Documentation/devicetree/bindings/mfd/arizona.txt -+++ b/Documentation/devicetree/bindings/mfd/arizona.txt -@@ -44,6 +44,23 @@ Required properties: - Optional properties: - - - wlf,reset : GPIO specifier for the GPIO controlling /RESET -+ - wlf,clk32k-src : set input source for codec 32kHz clock. -+ 0 = default, 1 = MCLK1, 2 = MCLK2, 3 = None -+ -+ - wlf,micd-ranges : Microphone detection level and key configuration, this -+ field can be of variable length but should always be a multiple of 2 cells -+ long, each two cell group represents one button configuration -+ The first cell is the maximum impedance for this button in ohms -+ The second cell the key that should be reported to the input layer -+ - wlf,micd-configs : Headset polarity configurations, the field can be of -+ variable length but should always be a multiple of 3 cells long, each two -+ cell group represents one polarity configration -+ The first cell is the accessory detection source as per the ACCDET_SRC bits -+ in the ACCESSORY_DETECT_MODE_1 register -+ The second cell represents the MICBIAS to be used as per the MICD_BIAS_SRC -+ bits in the MIC_DETECT_1 register -+ The third cell represents the value of the micd-pol-gpio pin, a non-zero -+ value indicates this should be on - - - wlf,gpio-defaults : A list of GPIO configuration register values. Defines - for the appropriate values can found in <dt-bindings/mfd/arizona.txt>. If -@@ -51,6 +68,10 @@ Optional properties: - a value that is out of range for a 16 bit register then the chip default - will be used. If present exactly five values must be specified. - -+ - wlf,dmic-ref : DMIC reference for each input, must contain four cells if -+ specified. 0 indicates MICVDD and is the default, 1,2,3 indicate the -+ respective MICBIAS. -+ - - wlf,inmode : A list of INn_MODE register values, where n is the number - of input signals. Valid values are 0 (Differential), 1 (Single-ended) and - 2 (Digital Microphone). If absent, INn_MODE registers set to 0 by default. -@@ -87,6 +108,19 @@ codec: wm5102@1a { - gpio-controller; - #gpio-cells = <2>; - -+ wlf,micd-ranges = < -+ 11 0x100 -+ 28 0x101 -+ 54 0x102 -+ 100 0x103 -+ 186 0x104 -+ 430 0x105 -+ >; -+ wlf,micd-configs = < -+ 0x1 1 0 -+ 0x0 2 1 -+ >; -+ - wlf,gpio-defaults = < - ARIZONA_GP_FN_TXLRCLK - ARIZONA_GP_DEFAULT -@@ -94,4 +128,6 @@ codec: wm5102@1a { - ARIZONA_GP_DEFAULT - ARIZONA_GP_DEFAULT - >; -+ -+ wlf,dmic-ref = <0 0 1 0>; - }; -diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile -index 3d8de47..156c29d 100644 ---- a/arch/arm/boot/dts/overlays/Makefile -+++ b/arch/arm/boot/dts/overlays/Makefile -@@ -61,6 +61,7 @@ dtbo-$(RPI_DT_OVERLAYS) += pwm-2chan.dtbo - dtbo-$(RPI_DT_OVERLAYS) += qca7000.dtbo - dtbo-$(RPI_DT_OVERLAYS) += raspidac3.dtbo - dtbo-$(RPI_DT_OVERLAYS) += rpi-backlight.dtbo -+dtbo-$(RPI_DT_OVERLAYS) += rpi-cirrus-wm5102.dtbo - dtbo-$(RPI_DT_OVERLAYS) += rpi-dac.dtbo - dtbo-$(RPI_DT_OVERLAYS) += rpi-display.dtbo - dtbo-$(RPI_DT_OVERLAYS) += rpi-ft5406.dtbo -diff --git a/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts b/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts -new file mode 100644 -index 0000000..3cb63a5 ---- /dev/null -+++ b/arch/arm/boot/dts/overlays/rpi-cirrus-wm5102-overlay.dts -@@ -0,0 +1,138 @@ -+// Definitions for Cirrus audio card -+/dts-v1/; -+/plugin/; -+ -+/ { -+ compatible = "brcm,bcm2708"; -+ -+ fragment@0 { -+ target-path = "/"; -+ __overlay__ { -+ aliases { -+ ldo0 = &ldo0; -+ ldo1 = &ldo1; -+ }; -+ }; -+ }; -+ -+ fragment@1 { -+ target = <&sound>; -+ __overlay__ { -+ compatible = "wlf,rpi-wm5102"; -+ i2s-controller = <&i2s>; -+ status = "okay"; -+ }; -+ }; -+ -+ fragment@2 { -+ target = <&i2s>; -+ __overlay__ { -+ status = "okay"; -+ }; -+ }; -+ -+ fragment@3 { -+ target = <&gpio>; -+ __overlay__ { -+ wlf_pins: wlf_pins { -+ brcm,pins = <17 22 27 8>; -+ brcm,function = <1 1 0 1>; -+ }; -+ }; -+ }; -+ -+ fragment@4 { -+ target-path = "/soc"; -+ __overlay__ { -+ -+ ldo1: ldo1 { -+ compatible = "regulator-fixed"; -+ regulator-name = "DC_5V"; -+ regulator-min-microvolt = <5000000>; -+ regulator-max-microvolt = <5000000>; -+ enable-active-high; -+ regulator-always-on; -+ }; -+ -+ ldo0: ldo0 { -+ compatible = "regulator-fixed"; -+ regulator-name = "DC_1V8"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ enable-active-high; -+ regulator-always-on; -+ }; -+ }; -+ }; -+ -+ fragment@5 { -+ target = <&spi0>; -+ __overlay__ { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "okay"; -+ -+ spidev@0{ -+ status = "disabled"; -+ }; -+ -+ spidev@1{ -+ status = "disabled"; -+ }; -+ -+ wm5102@1{ -+ compatible = "wlf,wm5102"; -+ reg = <1>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ spi-max-frequency = <500000>; -+ -+ interrupt-parent = <&gpio>; -+ interrupts = <27 8>; -+ -+ LDOVDD-supply = <&ldo0>; -+ AVDD-supply = <&ldo0>; -+ DBVDD1-supply = <&ldo0>; -+ DBVDD2-supply = <&ldo0>; -+ DBVDD3-supply = <&ldo0>; -+ CPVDD-supply = <&ldo0>; -+ SPKVDDL-supply = <&ldo1>; -+ SPKVDDR-supply = <&ldo1>; -+ -+ wlf,reset = <&gpio 17 0>; -+ wlf,ldoena = <&gpio 22 0>; -+ wlf,gpio-defaults = < -+ 0x000fffff -+ 0x000fffff -+ 0x000fffff -+ 0x000fffff -+ 0x000fffff -+ >; -+ wlf,micd-configs = <0 1 0>; -+ wlf,dmic-ref = <0 2 0 0>; -+ wlf,clk32k-src = <3>; -+ wlf,inmode = <0 2 1 0>; -+ status = "okay"; -+ }; -+ }; -+ }; -+ -+ fragment@6 { -+ target = <&i2c1>; -+ __overlay__ { -+ status = "okay"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ wm8804@3b { -+ #sound-dai-cells = <0>; -+ compatible = "wlf,wm8804"; -+ reg = <0x3b>; -+ status = "okay"; -+ PVDD-supply = <&ldo0>; -+ DVDD-supply = <&ldo0>; -+ wlf,reset-gpio = <&gpio 8 0>; -+ }; -+ }; -+ }; -+}; -diff --git a/arch/arm/configs/bcm2709_defconfig b/arch/arm/configs/bcm2709_defconfig -index 0bdc631..4de55c8 100644 ---- a/arch/arm/configs/bcm2709_defconfig -+++ b/arch/arm/configs/bcm2709_defconfig -@@ -650,6 +650,9 @@ CONFIG_STMPE_SPI=y - CONFIG_MFD_ARIZONA_I2C=m - CONFIG_MFD_ARIZONA_SPI=m - CONFIG_MFD_WM5102=y -+CONFIG_REGULATOR=y -+CONFIG_REGULATOR_FIXED_VOLTAGE=m -+CONFIG_REGULATOR_ARIZONA=m - CONFIG_MEDIA_SUPPORT=m - CONFIG_MEDIA_CAMERA_SUPPORT=y - CONFIG_MEDIA_ANALOG_TV_SUPPORT=y -@@ -863,6 +866,7 @@ CONFIG_SND_BCM2708_SOC_BOOMBERRY_DIGI=m - CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m - CONFIG_SND_BCM2708_SOC_RASPIDAC3=m - CONFIG_SND_BCM2708_SOC_ADAU1977_ADC=m -+CONFIG_SND_BCM2708_SOC_RPI_CODEC_WSP=m - CONFIG_SND_SOC_ADAU1701=m - CONFIG_SND_SOC_WM8804_I2C=m - CONFIG_SND_SIMPLE_CARD=m -diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig -index 57393b5..55ef0a5 100644 ---- a/arch/arm/configs/bcmrpi_defconfig -+++ b/arch/arm/configs/bcmrpi_defconfig -@@ -642,6 +642,9 @@ CONFIG_STMPE_SPI=y - CONFIG_MFD_ARIZONA_I2C=m - CONFIG_MFD_ARIZONA_SPI=m - CONFIG_MFD_WM5102=y -+CONFIG_REGULATOR=y -+CONFIG_REGULATOR_FIXED_VOLTAGE=m -+CONFIG_REGULATOR_ARIZONA=m - CONFIG_MEDIA_SUPPORT=m - CONFIG_MEDIA_CAMERA_SUPPORT=y - CONFIG_MEDIA_ANALOG_TV_SUPPORT=y -@@ -855,6 +858,7 @@ CONFIG_SND_BCM2708_SOC_BOOMBERRY_DIGI=m - CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m - CONFIG_SND_BCM2708_SOC_RASPIDAC3=m - CONFIG_SND_BCM2708_SOC_ADAU1977_ADC=m -+CONFIG_SND_BCM2708_SOC_RPI_CODEC_WSP=m - CONFIG_SND_SOC_ADAU1701=m - CONFIG_SND_SOC_WM8804_I2C=m - CONFIG_SND_SIMPLE_CARD=m -diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c -index d26b6bd..dad4f48 100644 ---- a/drivers/dma/bcm2835-dma.c -+++ b/drivers/dma/bcm2835-dma.c -@@ -144,12 +144,6 @@ struct bcm2835_desc { - */ - #define MAX_LITE_TRANSFER (SZ_64K - 4) - --/* -- * Transfers larger than 32k cause issues with the bcm2708-i2s driver, -- * so limit transfer size to 32k as bcm2708-dmaengine did. -- */ --#define MAX_CYCLIC_LITE_TRANSFER SZ_32K -- - static inline struct bcm2835_dmadev *to_bcm2835_dma_dev(struct dma_device *d) - { - return container_of(d, struct bcm2835_dmadev, ddev); -@@ -385,6 +379,15 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic( - unsigned int frame, max_size; - int i; - -+ if (!buf_len || !period_len) -+ return NULL; -+ -+ if (buf_len % period_len) { -+ dev_err(chan->device->dev, -+ "Buffer length should be a multiple of period\n"); -+ return NULL; -+ } -+ - /* Grab configuration */ - if (!is_slave_direction(direction)) { - dev_err(chan->device->dev, "%s: bad direction?\n", __func__); -@@ -410,6 +413,18 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic( - return NULL; - } - -+ if (c->ch >= 8) /* LITE channel */ -+ max_size = MAX_LITE_TRANSFER; -+ else -+ max_size = MAX_NORMAL_TRANSFER; -+ -+ if (period_len > max_size) { -+ dev_err(chan->device->dev, -+ "Period length %d larger than maximum %d\n", -+ period_len, max_size); -+ return NULL; -+ } -+ - /* Now allocate and setup the descriptor. */ - d = kzalloc(sizeof(*d), GFP_NOWAIT); - if (!d) -@@ -417,12 +432,8 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic( - - d->c = c; - d->dir = direction; -- if (c->ch >= 8) /* LITE channel */ -- max_size = MAX_CYCLIC_LITE_TRANSFER; -- else -- max_size = MAX_NORMAL_TRANSFER; -- period_len = min(period_len, max_size); -- d->frames = (buf_len - 1) / (period_len + 1); -+ d->frames = buf_len / period_len; -+ d->size = buf_len; - - d->cb_list = kcalloc(d->frames, sizeof(*d->cb_list), GFP_KERNEL); - if (!d->cb_list) { -@@ -470,12 +481,7 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic( - BCM2835_DMA_PER_MAP(c->dreq); - - /* Length of a frame */ -- if (frame != d->frames - 1) -- control_block->length = period_len; -- else -- control_block->length = buf_len - (d->frames - 1) * -- period_len; -- d->size += control_block->length; -+ control_block->length = period_len; - - /* - * Next block is the next frame. -diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c -index d474732..a899b57 100644 ---- a/drivers/mfd/arizona-core.c -+++ b/drivers/mfd/arizona-core.c -@@ -16,6 +16,7 @@ - #include <linux/interrupt.h> - #include <linux/mfd/core.h> - #include <linux/module.h> -+#include <linux/notifier.h> - #include <linux/of.h> - #include <linux/of_device.h> - #include <linux/of_gpio.h> -@@ -460,6 +461,20 @@ static int wm5102_clear_write_sequencer(struct arizona *arizona) - return 0; - } - -+static int arizona_dcvdd_notify(struct notifier_block *nb, -+ unsigned long action, void *data) -+{ -+ struct arizona *arizona = container_of(nb, struct arizona, -+ dcvdd_notifier); -+ -+ dev_dbg(arizona->dev, "DCVDD notify %lx\n", action); -+ -+ if (action & REGULATOR_EVENT_DISABLE) -+ msleep(20); -+ -+ return NOTIFY_DONE; -+} -+ - #ifdef CONFIG_PM - static int arizona_isolate_dcvdd(struct arizona *arizona) - { -@@ -800,6 +815,154 @@ int arizona_of_get_named_gpio(struct arizona *arizona, const char *prop, - } - EXPORT_SYMBOL_GPL(arizona_of_get_named_gpio); - -+static int arizona_of_get_u32_num_groups(struct arizona *arizona, -+ const char *prop, -+ int group_size) -+{ -+ int len_prop; -+ int num_groups; -+ -+ if (!of_get_property(arizona->dev->of_node, prop, &len_prop)) -+ return -EINVAL; -+ -+ num_groups = len_prop / (group_size * sizeof(u32)); -+ -+ if (num_groups * group_size * sizeof(u32) != len_prop) { -+ dev_err(arizona->dev, -+ "DT property %s is malformed: %d\n", -+ prop, -EOVERFLOW); -+ return -EOVERFLOW; -+ } -+ -+ return num_groups; -+} -+ -+static int arizona_of_get_micd_ranges(struct arizona *arizona, -+ const char *prop) -+{ -+ int nranges; -+ int i, j; -+ int ret = 0; -+ u32 value; -+ struct arizona_micd_range *micd_ranges; -+ -+ nranges = arizona_of_get_u32_num_groups(arizona, prop, 2); -+ if (nranges < 0) -+ return nranges; -+ -+ micd_ranges = devm_kzalloc(arizona->dev, -+ nranges * sizeof(struct arizona_micd_range), -+ GFP_KERNEL); -+ -+ for (i = 0, j = 0; i < nranges; ++i) { -+ ret = of_property_read_u32_index(arizona->dev->of_node, -+ prop, j++, &value); -+ if (ret < 0) -+ goto error; -+ micd_ranges[i].max = value; -+ -+ ret = of_property_read_u32_index(arizona->dev->of_node, -+ prop, j++, &value); -+ if (ret < 0) -+ goto error; -+ micd_ranges[i].key = value; -+ } -+ -+ arizona->pdata.micd_ranges = micd_ranges; -+ arizona->pdata.num_micd_ranges = nranges; -+ -+ return ret; -+ -+error: -+ devm_kfree(arizona->dev, micd_ranges); -+ dev_err(arizona->dev, "DT property %s is malformed: %d\n", prop, ret); -+ return ret; -+} -+ -+static int arizona_of_get_micd_configs(struct arizona *arizona, -+ const char *prop) -+{ -+ int nconfigs; -+ int i, j; -+ int ret = 0; -+ u32 value; -+ struct arizona_micd_config *micd_configs; -+ -+ nconfigs = arizona_of_get_u32_num_groups(arizona, prop, 3); -+ if (nconfigs < 0) -+ return nconfigs; -+ -+ micd_configs = devm_kzalloc(arizona->dev, -+ nconfigs * -+ sizeof(struct arizona_micd_config), -+ GFP_KERNEL); -+ -+ for (i = 0, j = 0; i < nconfigs; ++i) { -+ ret = of_property_read_u32_index(arizona->dev->of_node, -+ prop, j++, &value); -+ if (ret < 0) -+ goto error; -+ micd_configs[i].src = value; -+ -+ ret = of_property_read_u32_index(arizona->dev->of_node, -+ prop, j++, &value); -+ if (ret < 0) -+ goto error; -+ micd_configs[i].bias = value; -+ -+ ret = of_property_read_u32_index(arizona->dev->of_node, -+ prop, j++, &value); -+ if (ret < 0) -+ goto error; -+ micd_configs[i].gpio = value; -+ } -+ -+ arizona->pdata.micd_configs = micd_configs; -+ arizona->pdata.num_micd_configs = nconfigs; -+ -+ return ret; -+ -+error: -+ devm_kfree(arizona->dev, micd_configs); -+ dev_err(arizona->dev, "DT property %s is malformed: %d\n", prop, ret); -+ return ret; -+} -+ -+static int arizona_of_read_u32_array(struct arizona *arizona, -+ const char *prop, bool mandatory, -+ u32 *data, size_t num) -+{ -+ int ret; -+ -+ ret = of_property_read_u32_array(arizona->dev->of_node, prop, -+ data, num); -+ -+ if (ret >= 0) -+ return 0; -+ -+ switch (ret) { -+ case -EINVAL: -+ if (mandatory) -+ dev_err(arizona->dev, -+ "Mandatory DT property %s is missing\n", -+ prop); -+ break; -+ default: -+ dev_err(arizona->dev, -+ "DT property %s is malformed: %d\n", -+ prop, ret); -+ } -+ -+ return ret; -+} -+ -+static int arizona_of_read_u32(struct arizona *arizona, -+ const char* prop, bool mandatory, -+ u32 *data) -+{ -+ return arizona_of_read_u32_array(arizona, prop, mandatory, data, 1); -+} -+ - static int arizona_of_get_core_pdata(struct arizona *arizona) - { - struct arizona_pdata *pdata = &arizona->pdata; -@@ -833,6 +996,15 @@ static int arizona_of_get_core_pdata(struct arizona *arizona) - ret); - } - -+ arizona_of_read_u32(arizona, "wlf,clk32k-src", false, -+ &pdata->clk32k_src); -+ -+ arizona_of_get_micd_ranges(arizona, "wlf,micd-ranges"); -+ arizona_of_get_micd_configs(arizona, "wlf,micd-configs"); -+ -+ arizona_of_read_u32_array(arizona, "wlf,dmic-ref", false, -+ pdata->dmic_ref, ARRAY_SIZE(pdata->dmic_ref)); -+ - of_property_for_each_u32(arizona->dev->of_node, "wlf,inmode", prop, - cur, val) { - if (count == ARRAY_SIZE(pdata->inmode)) -@@ -852,6 +1024,9 @@ static int arizona_of_get_core_pdata(struct arizona *arizona) - count++; - } - -+ arizona_of_read_u32(arizona, "wlf,irq_gpio", false, -+ &pdata->irq_gpio); -+ - return 0; - } - -@@ -1029,6 +1204,14 @@ int arizona_dev_init(struct arizona *arizona) - goto err_early; - } - -+ arizona->dcvdd_notifier.notifier_call = arizona_dcvdd_notify; -+ ret = regulator_register_notifier(arizona->dcvdd, -+ &arizona->dcvdd_notifier); -+ if (ret < 0) { -+ dev_err(dev, "Failed to register DCVDD notifier %d\n", ret); -+ goto err_dcvdd; -+ } -+ - if (arizona->pdata.reset) { - /* Start out with /RESET low to put the chip into reset */ - ret = devm_gpio_request_one(arizona->dev, arizona->pdata.reset, -@@ -1036,16 +1219,19 @@ int arizona_dev_init(struct arizona *arizona) - "arizona /RESET"); - if (ret != 0) { - dev_err(dev, "Failed to request /RESET: %d\n", ret); -- goto err_dcvdd; -+ goto err_notifier; - } - } - -+ /* Ensure period of reset asserted before we apply the supplies */ -+ msleep(20); -+ - ret = regulator_bulk_enable(arizona->num_core_supplies, - arizona->core_supplies); - if (ret != 0) { - dev_err(dev, "Failed to enable core supplies: %d\n", - ret); -- goto err_dcvdd; -+ goto err_notifier; - } - - ret = regulator_enable(arizona->dcvdd); -@@ -1420,6 +1606,8 @@ err_reset: - err_enable: - regulator_bulk_disable(arizona->num_core_supplies, - arizona->core_supplies); -+err_notifier: -+ regulator_unregister_notifier(arizona->dcvdd, &arizona->dcvdd_notifier); - err_dcvdd: - regulator_put(arizona->dcvdd); - err_early: -@@ -1433,6 +1621,7 @@ int arizona_dev_exit(struct arizona *arizona) - pm_runtime_disable(arizona->dev); - - regulator_disable(arizona->dcvdd); -+ regulator_unregister_notifier(arizona->dcvdd, &arizona->dcvdd_notifier); - regulator_put(arizona->dcvdd); - - mfd_remove_devices(arizona->dev); -diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c -index f7c88ff..19fdcd4 100644 ---- a/drivers/regulator/arizona-ldo1.c -+++ b/drivers/regulator/arizona-ldo1.c -@@ -288,6 +288,7 @@ static int arizona_ldo1_probe(struct platform_device *pdev) - } - - config.ena_gpio = arizona->pdata.ldoena; -+ config.ena_gpio_flags = GPIOF_OUT_INIT_LOW; - - if (arizona->pdata.ldo1) - config.init_data = arizona->pdata.ldo1; -diff --git a/include/linux/mfd/arizona/core.h b/include/linux/mfd/arizona/core.h -index 79e607e..39a23eb 100644 ---- a/include/linux/mfd/arizona/core.h -+++ b/include/linux/mfd/arizona/core.h -@@ -119,6 +119,7 @@ struct arizona { - int num_core_supplies; - struct regulator_bulk_data core_supplies[ARIZONA_MAX_CORE_SUPPLIES]; - struct regulator *dcvdd; -+ struct notifier_block dcvdd_notifier; - bool has_fully_powered_off; - - struct arizona_pdata pdata; -diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h -index 95a937e..8262719 100644 ---- a/include/sound/soc-dapm.h -+++ b/include/sound/soc-dapm.h -@@ -383,10 +383,11 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, - int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card); - void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card); - int snd_soc_dapm_new_pcm(struct snd_soc_card *card, -- const struct snd_soc_pcm_stream *params, -+ struct snd_soc_pcm_stream *params, - unsigned int num_params, - struct snd_soc_dapm_widget *source, -- struct snd_soc_dapm_widget *sink); -+ struct snd_soc_dapm_widget *sink, -+ void *priv); - - /* dapm path setup */ - int snd_soc_dapm_new_widgets(struct snd_soc_card *card); -@@ -553,7 +554,7 @@ struct snd_soc_dapm_widget { - - void *priv; /* widget specific data */ - struct regulator *regulator; /* attached regulator */ -- const struct snd_soc_pcm_stream *params; /* params for dai links */ -+ struct snd_soc_pcm_stream *params; /* params for dai links */ - unsigned int num_params; /* number of params for dai links */ - unsigned int params_select; /* currently selected param for dai link */ - -diff --git a/include/sound/soc.h b/include/sound/soc.h -index fb955e6..bbdc05d 100644 ---- a/include/sound/soc.h -+++ b/include/sound/soc.h -@@ -989,7 +989,9 @@ struct snd_soc_dai_link { - struct device_node *platform_of_node; - int be_id; /* optional ID for machine driver BE identification */ - -- const struct snd_soc_pcm_stream *params; -+ struct snd_soc_pcm_stream *params; -+ /* optional params re-writing for dai links */ -+ int (*params_fixup)(struct snd_soc_dapm_widget *w, int event); - unsigned int num_params; - - unsigned int dai_fmt; /* format to set on init */ -diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig -index c05e656..0fb2384 100644 ---- a/sound/soc/bcm/Kconfig -+++ b/sound/soc/bcm/Kconfig -@@ -85,3 +85,12 @@ config SND_BCM2708_SOC_ADAU1977_ADC - select SND_SOC_ADAU1977_I2C - help - Say Y or M if you want to add support for ADAU1977 ADC. -+ -+config SND_BCM2708_SOC_RPI_CODEC_WSP -+ tristate "Support for Cirrus sound pi" -+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S -+ select SND_SOC_WM5102 -+ select SND_SOC_WM8804 -+ help -+ Say Y or M if you want to add support for Cirrus sound pi -+ -diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -index 7de2ef1..4d6c910 100644 ---- a/sound/soc/bcm/Makefile -+++ b/sound/soc/bcm/Makefile -@@ -15,6 +15,7 @@ snd-soc-rpi-dac-objs := rpi-dac.o - snd-soc-rpi-proto-objs := rpi-proto.o - snd-soc-iqaudio-dac-objs := iqaudio-dac.o - snd-soc-raspidac3-objs := raspidac3.o -+snd-soc-rpi-wsp-objs := rpi-cirrus-sound-pi.o - - obj-$(CONFIG_SND_BCM2708_SOC_ADAU1977_ADC) += snd-soc-adau1977-adc.o - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o -@@ -27,3 +28,4 @@ obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o - obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o - obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o - obj-$(CONFIG_SND_BCM2708_SOC_RASPIDAC3) += snd-soc-raspidac3.o -+obj-$(CONFIG_SND_BCM2708_SOC_RPI_CODEC_WSP) += snd-soc-rpi-wsp.o -diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c -index aedb01f..c413973 100644 ---- a/sound/soc/bcm/bcm2835-i2s.c -+++ b/sound/soc/bcm/bcm2835-i2s.c -@@ -813,16 +813,16 @@ static struct snd_pcm_hardware bcm2835_pcm_hardware = { - SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, - .period_bytes_min = 32, -- .period_bytes_max = 64 * PAGE_SIZE, -+ .period_bytes_max = SZ_64K - 4, - .periods_min = 2, - .periods_max = 255, -- .buffer_bytes_max = 128 * PAGE_SIZE, -+ .buffer_bytes_max = SZ_512K, - }; - - static const struct snd_dmaengine_pcm_config bcm2835_dmaengine_pcm_config = { - .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, - .pcm_hardware = &bcm2835_pcm_hardware, -- .prealloc_buffer_size = 256 * PAGE_SIZE, -+ .prealloc_buffer_size = SZ_1M, - }; - - static int bcm2835_i2s_probe(struct platform_device *pdev) -diff --git a/sound/soc/bcm/rpi-cirrus-sound-pi.c b/sound/soc/bcm/rpi-cirrus-sound-pi.c -new file mode 100644 -index 0000000..3abfff1 ---- /dev/null -+++ b/sound/soc/bcm/rpi-cirrus-sound-pi.c -@@ -0,0 +1,638 @@ -+/* -+ * ASoC machine driver for Cirrus Audio Card (with a WM5102 and WM8804 codecs ) -+ * connected to a Raspberry Pi -+ * -+ * Copyright 2015 Cirrus Logic Inc. -+ * -+ * Author: Nikesh Oswal, <Nikesh.Oswal@wolfsonmicro.com> -+ * Partly based on sound/soc/bcm/iqaudio-dac.c -+ * -+ * 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. -+ */ -+ -+#include <linux/module.h> -+#include <linux/mutex.h> -+#include <linux/slab.h> -+#include <sound/pcm_params.h> -+ -+#include "../codecs/wm5102.h" -+#include "../codecs/wm8804.h" -+ -+#define WM8804_CLKOUT_HZ 12000000 -+ -+#define RPI_WLF_SR 44100 -+#define WM5102_MAX_SYSCLK_1 49152000 /*max sysclk for 4K family*/ -+#define WM5102_MAX_SYSCLK_2 45158400 /*max sysclk for 11.025K family*/ -+ -+#define DAI_WM5102 0 -+#define DAI_WM8804 1 -+ -+static struct snd_soc_card snd_rpi_wsp; -+ -+struct wm5102_machine_priv { -+ int wm8804_sr; -+ int wm5102_sr; -+ int sync_path_enable; -+ int fll1_freq; /* negative means RefClock in spdif rx case */ -+ /* mutex for synchronzing FLL1 access with DAPM */ -+ struct mutex fll1_mutex; -+}; -+ -+int spdif_rx_enable_event(struct snd_soc_dapm_widget *w, -+ struct snd_kcontrol *kcontrol, int event) -+{ -+ struct snd_soc_card *card = &snd_rpi_wsp; -+ struct wm5102_machine_priv *priv = snd_soc_card_get_drvdata(card); -+ struct snd_soc_pcm_runtime *wm5102_rtd; -+ struct snd_soc_codec *wm5102_codec; -+ int ret = 0; -+ int clk_freq; -+ int sr = priv->wm8804_sr; -+ -+ dev_dbg(card->dev, "spdif_rx event %d\n", event); -+ -+ wm5102_rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_WM5102].name); -+ if (!wm5102_rtd) { -+ dev_warn(card->dev, "spdif_rx_enable_event: couldn't get WM5102 rtd\n"); -+ return -EFAULT; -+ } -+ wm5102_codec = wm5102_rtd->codec; -+ -+ switch (event) { -+ case SND_SOC_DAPM_POST_PMU: -+ mutex_lock(&priv->fll1_mutex); -+ -+ dev_dbg(wm5102_codec->dev, -+ "spdif_rx: changing FLL1 to use Ref Clock\n"); -+ -+ /* Enable sync path in case of SPDIF capture use case */ -+ clk_freq = (sr % 4000 == 0) ? WM5102_MAX_SYSCLK_1 : WM5102_MAX_SYSCLK_2; -+ -+ /*reset FLL1*/ -+ snd_soc_codec_set_pll(wm5102_codec, WM5102_FLL1_REFCLK, -+ ARIZONA_FLL_SRC_NONE, 0, 0); -+ snd_soc_codec_set_pll(wm5102_codec, WM5102_FLL1, -+ ARIZONA_FLL_SRC_NONE, 0, 0); -+ -+ ret = snd_soc_codec_set_pll(wm5102_codec, WM5102_FLL1_REFCLK, -+ ARIZONA_CLK_SRC_MCLK1, -+ WM8804_CLKOUT_HZ, -+ clk_freq); -+ if (ret != 0) { -+ dev_err(wm5102_codec->dev, "Failed to enable FLL1 with Ref Clock Loop: %d\n", ret); -+ mutex_unlock(&priv->fll1_mutex); -+ return ret; -+ } -+ -+ ret = snd_soc_codec_set_pll(wm5102_codec, WM5102_FLL1, -+ ARIZONA_CLK_SRC_AIF2BCLK, -+ sr * 64, clk_freq); -+ if (!ret) -+ /* set to negative to indicate we're doing spdif rx */ -+ priv->fll1_freq = -clk_freq; -+ -+ mutex_unlock(&priv->fll1_mutex); -+ -+ if (ret != 0) { -+ dev_err(wm5102_codec->dev, "Failed to enable FLL1 Sync Clock Loop: %d\n", ret); -+ return ret; -+ } -+ priv->sync_path_enable = 1; -+ break; -+ case SND_SOC_DAPM_POST_PMD: -+ priv->sync_path_enable = 0; -+ break; -+ } -+ -+ return ret; -+} -+ -+static const struct snd_kcontrol_new rpi_wsp_controls[] = { -+ SOC_DAPM_PIN_SWITCH("DMIC"), -+ SOC_DAPM_PIN_SWITCH("Headset Mic"), -+ SOC_DAPM_PIN_SWITCH("SPDIF Out"), -+ SOC_DAPM_PIN_SWITCH("SPDIF In"), -+ SOC_DAPM_PIN_SWITCH("Line Input"), -+}; -+ -+const struct snd_soc_dapm_widget rpi_wsp_dapm_widgets[] = { -+ SND_SOC_DAPM_MIC("DMIC", NULL), -+ SND_SOC_DAPM_MIC("Headset Mic", NULL), -+ SND_SOC_DAPM_MIC("Line Input", NULL), -+ SND_SOC_DAPM_INPUT("dummy SPDIF in"), -+ SND_SOC_DAPM_PGA_E("dummy SPDIFRX", SND_SOC_NOPM, 0, 0,NULL, 0, -+ spdif_rx_enable_event, -+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), -+}; -+ -+const struct snd_soc_dapm_route rpi_wsp_dapm_routes[] = { -+ { "IN1L", NULL, "Headset Mic" }, -+ { "IN1R", NULL, "Headset Mic" }, -+ { "Headset Mic", NULL, "MICBIAS1" }, -+ -+ { "IN2L", NULL, "DMIC" }, -+ { "IN2R", NULL, "DMIC" }, -+ { "DMIC", NULL, "MICBIAS2" }, -+ -+ { "IN3L", NULL, "Line Input" }, -+ { "IN3R", NULL, "Line Input" }, -+ { "Line Input", NULL, "MICBIAS3" }, -+ -+ /* Dummy routes to check whether SPDIF RX is enabled or not */ -+ {"dummy SPDIFRX", NULL, "dummy SPDIF in"}, -+ {"AIFTX", NULL, "dummy SPDIFRX"}, -+}; -+ -+static int rpi_set_bias_level(struct snd_soc_card *card, -+ struct snd_soc_dapm_context *dapm, -+ enum snd_soc_bias_level level) -+{ -+ struct snd_soc_pcm_runtime *wm5102_rtd; -+ struct snd_soc_codec *wm5102_codec; -+ struct snd_soc_dai *wm5102_codec_dai; -+ struct wm5102_machine_priv *priv = snd_soc_card_get_drvdata(card); -+ -+ int ret; -+ int sr = priv->wm5102_sr; -+ int clk_freq = (sr % 4000 == 0) ? WM5102_MAX_SYSCLK_1 : WM5102_MAX_SYSCLK_2; -+ -+ wm5102_rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_WM5102].name); -+ if (!wm5102_rtd) { -+ dev_warn(card->dev, "rpi_set_bias_level: couldn't get WM5102 rtd\n"); -+ return -EFAULT; -+ } -+ wm5102_codec = wm5102_rtd->codec; -+ wm5102_codec_dai = wm5102_rtd->codec_dai; -+ -+ if (dapm->dev != wm5102_codec_dai->dev) -+ return 0; -+ -+ dev_dbg(wm5102_codec->dev, "change bias level from %d to %d, sync=%d\n", -+ dapm->bias_level, level, priv->sync_path_enable); -+ -+ switch (level) { -+ case SND_SOC_BIAS_ON: -+ /* no need to check current level, it can only be PREPARE */ -+ if (!priv->sync_path_enable) { -+ mutex_lock(&priv->fll1_mutex); -+ -+ dev_dbg(wm5102_codec->dev, -+ "bias_on: changing FLL1 from %d to %d\n", -+ priv->fll1_freq, clk_freq); -+ -+ ret = snd_soc_codec_set_pll(wm5102_codec, WM5102_FLL1, -+ ARIZONA_CLK_SRC_MCLK1, -+ WM8804_CLKOUT_HZ, -+ clk_freq); -+ if (!ret) -+ priv->fll1_freq = clk_freq; -+ -+ mutex_unlock(&priv->fll1_mutex); -+ -+ if (ret != 0) { -+ dev_err(wm5102_codec->dev, "Failed to enable FLL1: %d\n", ret); -+ return ret; -+ } -+ } -+ break; -+ case SND_SOC_BIAS_STANDBY: -+ if (dapm->bias_level != SND_SOC_BIAS_PREPARE) -+ break; -+ -+ mutex_lock(&priv->fll1_mutex); -+ -+ dev_dbg(wm5102_codec->dev, -+ "bias_standby: changing FLL1 from %d to off\n", -+ priv->fll1_freq); -+ -+ ret = snd_soc_codec_set_pll(wm5102_codec, WM5102_FLL1, -+ ARIZONA_FLL_SRC_NONE, 0, 0); -+ if (ret) -+ dev_warn(wm5102_codec->dev, "set_bias_level: Failed to stop FLL1: %d\n", ret); -+ -+ ret = snd_soc_codec_set_pll(wm5102_codec, WM5102_FLL1_REFCLK, -+ ARIZONA_FLL_SRC_NONE, 0, 0); -+ if (ret) -+ dev_warn(wm5102_codec->dev, "set_bias_level: Failed to stop FLL1_REFCLK: %d\n", ret); -+ -+ priv->fll1_freq = 0; -+ -+ mutex_unlock(&priv->fll1_mutex); -+ -+ break; -+ default: -+ break; -+ } -+ -+ return 0; -+} -+ -+static int snd_rpi_wsp_config_5102_clks( -+ struct wm5102_machine_priv *priv, -+ struct snd_soc_codec *wm5102_codec, int sr) -+{ -+ int ret; -+ int clk_freq = (sr % 4000 == 0) ? WM5102_MAX_SYSCLK_1 : WM5102_MAX_SYSCLK_2; -+ -+ /* -+ * Manually set up FLL1 if it's configured to another rate but only -+ * if we are not using spdif rx (fll1_freq negative). -+ * This is necessary if delayed DAPM powerdown hasn't stopped -+ * the FLL before. -+ */ -+ if ((priv->fll1_freq > 0) && (priv->fll1_freq != clk_freq)) { -+ mutex_lock(&priv->fll1_mutex); -+ -+ dev_dbg(wm5102_codec->dev, -+ "config_5102_clks: changing FLL1 from %d to %d\n", -+ priv->fll1_freq, clk_freq); -+ -+ /*reset FLL1*/ -+ snd_soc_codec_set_pll(wm5102_codec, WM5102_FLL1, -+ ARIZONA_FLL_SRC_NONE, 0, 0); -+ -+ ret = snd_soc_codec_set_pll(wm5102_codec, WM5102_FLL1, -+ ARIZONA_CLK_SRC_MCLK1, -+ WM8804_CLKOUT_HZ, -+ clk_freq); -+ if (!ret) -+ priv->fll1_freq = clk_freq; -+ -+ mutex_unlock(&priv->fll1_mutex); -+ -+ if (ret) { -+ dev_err(wm5102_codec->dev, "Failed to set FLL1: %d\n", ret); -+ return ret; -+ } -+ -+ } -+ -+ ret = snd_soc_codec_set_sysclk(wm5102_codec, -+ ARIZONA_CLK_SYSCLK, -+ ARIZONA_CLK_SRC_FLL1, -+ clk_freq, -+ SND_SOC_CLOCK_IN); -+ if (ret != 0) { -+ dev_err(wm5102_codec->dev, "Failed to set AYNCCLK: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+ } -+ -+static int snd_rpi_wsp_config_8804_clks(struct snd_soc_codec *wm8804_codec, -+ struct snd_soc_dai *wm8804_dai, int sr) -+ { -+ int ret; -+ -+ /*Set OSC(12MHz) to CLK2 freq*/ -+ /*Based on MCLKDIV it will be 128fs (MCLKDIV=1) or 256fs mode (MCLKDIV=0)*/ -+ /*BCLK will be MCLK/2 (MCLKDIV=1) or MCLK/4 (MCLKDIV=0) so BCLK is 64fs always*/ -+ ret = snd_soc_dai_set_pll(wm8804_dai, 0, 0, WM8804_CLKOUT_HZ, sr * 256); -+ if (ret != 0) { -+ dev_err(wm8804_codec->dev, "Failed to set OSC to CLK2 frequency: %d\n", ret); -+ return ret; -+ } -+ -+ /*Set MCLK as PLL Output*/ -+ ret = snd_soc_dai_set_sysclk(wm8804_dai, WM8804_TX_CLKSRC_PLL, sr * 256, 0); -+ if (ret != 0) { -+ dev_err(wm8804_codec->dev, "Failed to set MCLK as PLL Output: %d\n", ret); -+ return ret; -+ } -+ -+ /*Fix MCLKDIV=0 for 256fs to avoid any issues switching between TX and RX. RX always expects 256fs*/ -+ ret = snd_soc_dai_set_clkdiv(wm8804_dai, WM8804_MCLK_DIV, 0 ); -+ if (ret != 0) { -+ dev_err(wm8804_codec->dev, "Failed to set MCLK_DIV to 256fs: %d\n", ret); -+ return ret; -+ } -+ -+ /*Set CLKOUT as OSC Frequency*/ -+ ret = snd_soc_dai_set_sysclk(wm8804_dai, WM8804_CLKOUT_SRC_OSCCLK, WM8804_CLKOUT_HZ, 0); -+ if (ret != 0) { -+ dev_err(wm8804_codec->dev, "Failed to set CLKOUT as OSC Frequency: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int snd_rpi_wsp_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params) -+{ -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ struct snd_soc_card *card = rtd->card; -+ struct snd_soc_pcm_runtime *wm5102_rtd, *wm8804_rtd; -+ struct snd_soc_codec *wm5102_codec, *wm8804_codec; -+ struct snd_soc_dai *wm8804_codec_dai, *bcm_i2s_dai = rtd->cpu_dai; -+ struct wm5102_machine_priv *priv = snd_soc_card_get_drvdata(card); -+ int ret, capture_stream_opened,playback_stream_opened; -+ unsigned int bclkratio, tx_mask, rx_mask; -+ int width, num_slots=1; -+ -+ wm5102_rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_WM5102].name); -+ if (!wm5102_rtd) { -+ dev_warn(card->dev, "snd_rpi_wsp_hw_params: couldn't get WM5102 rtd\n"); -+ return -EFAULT; -+ } -+ wm8804_rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_WM8804].name); -+ if (!wm8804_rtd) { -+ dev_warn(card->dev, "snd_rpi_wsp_hw_params: couldn't get WM8804 rtd\n"); -+ return -EFAULT; -+ } -+ wm5102_codec = wm5102_rtd->codec; -+ wm8804_codec = wm8804_rtd->codec; -+ wm8804_codec_dai = wm8804_rtd->codec_dai; -+ -+ bclkratio = 2 * snd_pcm_format_physical_width(params_format(params)); -+ -+ ret = snd_soc_dai_set_bclk_ratio(bcm_i2s_dai, bclkratio); -+ if (ret < 0) { -+ dev_err(wm5102_codec->dev, "set_bclk_ratio failed: %d\n", ret); -+ return ret; -+ } -+ -+ /*8804 supports sample rates from 32k only*/ -+ /*Setting <32k raises error from 8804 driver while setting the clock*/ -+ if(params_rate(params) >= 32000) -+ { -+ ret = snd_rpi_wsp_config_8804_clks(wm8804_codec, wm8804_codec_dai, -+ params_rate(params)); -+ -+ if (ret != 0) { -+ dev_err(wm8804_codec->dev, "snd_rpi_wsp_config_8804_clks failed: %d\n", -+ ret); -+ return ret; -+ } -+ } -+ -+ capture_stream_opened = -+ substream->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_opened; -+ playback_stream_opened = -+ substream->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_opened; -+ -+ priv->wm5102_sr = params_rate(params); -+ -+ ret = snd_rpi_wsp_config_5102_clks(priv, wm5102_codec, params_rate(params)); -+ if (ret != 0) { -+ dev_err(wm5102_codec->dev, "snd_rpi_wsp_config_5102_clks failed: %d\n", ret); -+ return ret; -+ } -+ -+ width = snd_pcm_format_physical_width(params_format(params)); -+ -+ if (capture_stream_opened) { -+ tx_mask = 0; -+ rx_mask = 1; -+ } -+ if (playback_stream_opened) { -+ tx_mask = 1; -+ rx_mask = 0; -+ } -+ ret = snd_soc_dai_set_tdm_slot(rtd->codec_dai, tx_mask, rx_mask, num_slots, width); -+ if (ret < 0) -+ return ret; -+ -+ priv->wm8804_sr = params_rate(params); -+ -+ return 0; -+} -+ -+static int dai_link2_params_fixup(struct snd_soc_dapm_widget *w, int event) -+{ -+ struct snd_soc_card *card = &snd_rpi_wsp; -+ struct wm5102_machine_priv *priv = snd_soc_card_get_drvdata(card); -+ struct snd_soc_pcm_stream *config = w->params; -+ -+ if (event == SND_SOC_DAPM_PRE_PMU) { -+ config->rate_min = priv->wm8804_sr; -+ config->rate_max = priv->wm8804_sr; -+ } else if (event == SND_SOC_DAPM_PRE_PMD) { -+ config->rate_min = RPI_WLF_SR; -+ config->rate_max = RPI_WLF_SR; -+ } -+ -+ return 0; -+} -+ -+static int snd_rpi_wsp_hw_free(struct snd_pcm_substream *substream) -+{ -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ struct snd_soc_codec *wm5102_codec = rtd->codec; -+ int ret,playback_stream_opened,capture_stream_opened; -+ -+ playback_stream_opened = substream->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_opened; -+ -+ capture_stream_opened = substream->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_opened; -+ -+ if((playback_stream_opened + capture_stream_opened) == 1){ -+ -+ ret = snd_soc_codec_set_sysclk(wm5102_codec, -+ ARIZONA_CLK_SYSCLK, -+ ARIZONA_CLK_SRC_FLL1, -+ 0, -+ SND_SOC_CLOCK_IN); -+ -+ if (ret != 0) { -+ dev_err(wm5102_codec->dev, "Failed to set SYSCLK to Zero: %d\n", ret); -+ return ret; -+ } -+ } -+ -+ return 0; -+} -+ -+static struct snd_soc_ops snd_rpi_wsp_ops = { -+ .hw_params = snd_rpi_wsp_hw_params, -+ .hw_free = snd_rpi_wsp_hw_free, -+}; -+ -+static struct snd_soc_pcm_stream dai_link2_params = { -+ .formats = SNDRV_PCM_FMTBIT_S24_LE, -+ .rate_min = RPI_WLF_SR, -+ .rate_max = RPI_WLF_SR, -+ .channels_min = 2, -+ .channels_max = 2, -+}; -+ -+static struct snd_soc_dai_link snd_rpi_wsp_dai[] = { -+ { -+ .name = "WM5102", -+ .stream_name = "WM5102 AiFi", -+ .cpu_dai_name = "bcm2708-i2s.0", -+ .codec_dai_name = "wm5102-aif1", -+ .platform_name = "bcm2708-i2s.0", -+ .codec_name = "wm5102-codec", -+ .dai_fmt = SND_SOC_DAIFMT_I2S -+ | SND_SOC_DAIFMT_NB_NF -+ | SND_SOC_DAIFMT_CBM_CFM, -+ .ops = &snd_rpi_wsp_ops, -+ }, -+ { -+ .name = "WM5102 SPDIF", -+ .stream_name = "SPDIF Tx/Rx", -+ .cpu_dai_name = "wm5102-aif2", -+ .codec_dai_name = "wm8804-spdif", -+ .codec_name = "wm8804.1-003b", -+ .dai_fmt = SND_SOC_DAIFMT_I2S -+ | SND_SOC_DAIFMT_NB_NF -+ | SND_SOC_DAIFMT_CBM_CFM, -+ .ignore_suspend = 1, -+ .params = &dai_link2_params, -+ .params_fixup = dai_link2_params_fixup, -+ }, -+}; -+ -+static int snd_rpi_wsp_late_probe(struct snd_soc_card *card) -+{ -+ struct wm5102_machine_priv *priv = snd_soc_card_get_drvdata(card); -+ struct snd_soc_pcm_runtime *wm5102_rtd, *wm8804_rtd; -+ struct snd_soc_codec *wm5102_codec, *wm8804_codec; -+ struct snd_soc_dai *wm5102_codec_dai, *wm8804_codec_dai, *wm8804_cpu_dai; -+ int ret; -+ -+ wm5102_rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_WM5102].name); -+ if (!wm5102_rtd) { -+ dev_warn(card->dev, "snd_rpi_wsp_late_probe: couldn't get WM5102 rtd\n"); -+ return -EFAULT; -+ } -+ wm8804_rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_WM8804].name); -+ if (!wm8804_rtd) { -+ dev_warn(card->dev, "snd_rpi_wsp_late_probe: couldn't get WM8804 rtd\n"); -+ return -EFAULT; -+ } -+ wm5102_codec = wm5102_rtd->codec; -+ wm5102_codec_dai = wm5102_rtd->codec_dai; -+ wm8804_codec = wm8804_rtd->codec; -+ wm8804_codec_dai = wm8804_rtd->codec_dai; -+ wm8804_cpu_dai = wm8804_rtd->cpu_dai; -+ -+ priv->wm8804_sr = RPI_WLF_SR; -+ priv->wm5102_sr = RPI_WLF_SR; -+ priv->sync_path_enable = 0; -+ -+ ret = snd_soc_codec_set_sysclk(wm5102_codec, ARIZONA_CLK_SYSCLK, ARIZONA_CLK_SRC_FLL1, -+ 0, SND_SOC_CLOCK_IN); -+ if (ret != 0) { -+ dev_err(wm5102_codec->dev, "Failed to set SYSCLK to Zero: %d\n", ret); -+ return ret; -+ } -+ -+ ret = snd_rpi_wsp_config_8804_clks(wm8804_codec, wm8804_codec_dai, RPI_WLF_SR); -+ -+ if (ret != 0) { -+ dev_err(wm8804_codec->dev, "snd_rpi_wsp_config_8804_clks failed: %d\n", ret); -+ return ret; -+ } -+ -+ ret = snd_soc_dai_set_sysclk(wm5102_codec_dai, ARIZONA_CLK_SYSCLK, 0, 0); -+ if (ret != 0) { -+ dev_err(wm5102_codec_dai->dev, "Failed to set codec dai clk domain: %d\n", ret); -+ return ret; -+ } -+ -+ ret = snd_soc_dai_set_sysclk(wm8804_cpu_dai, ARIZONA_CLK_SYSCLK, 0, 0); -+ if (ret != 0) { -+ dev_err(wm8804_cpu_dai->dev, "Failed to set codec dai clk domain: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+/* audio machine driver */ -+static struct snd_soc_card snd_rpi_wsp = { -+ .name = "snd_rpi_wsp", -+ .owner = THIS_MODULE, -+ .dai_link = snd_rpi_wsp_dai, -+ .num_links = ARRAY_SIZE(snd_rpi_wsp_dai), -+ .late_probe = snd_rpi_wsp_late_probe, -+ .controls = rpi_wsp_controls, -+ .num_controls = ARRAY_SIZE(rpi_wsp_controls), -+ .dapm_widgets = rpi_wsp_dapm_widgets, -+ .num_dapm_widgets = ARRAY_SIZE(rpi_wsp_dapm_widgets), -+ .dapm_routes = rpi_wsp_dapm_routes, -+ .num_dapm_routes = ARRAY_SIZE(rpi_wsp_dapm_routes), -+ .set_bias_level = rpi_set_bias_level, -+}; -+ -+static int snd_rpi_wsp_probe(struct platform_device *pdev) -+{ -+ int ret = 0; -+ struct wm5102_machine_priv *wm5102; -+ -+ wm5102 = kzalloc(sizeof *wm5102, GFP_KERNEL); -+ if (!wm5102) -+ return -ENOMEM; -+ -+ wm5102->fll1_freq = 0; -+ mutex_init(&wm5102->fll1_mutex); -+ -+ snd_soc_card_set_drvdata(&snd_rpi_wsp, wm5102); -+ -+ if (pdev->dev.of_node) { -+ struct device_node *i2s_node; -+ struct snd_soc_dai_link *dai = &snd_rpi_wsp_dai[DAI_WM5102]; -+ 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; -+ } -+ } -+ -+ snd_rpi_wsp.dev = &pdev->dev; -+ ret = snd_soc_register_card(&snd_rpi_wsp); -+ if (ret) { -+ if (ret == -EPROBE_DEFER) -+ dev_dbg(&pdev->dev, "register card requested probe deferral\n"); -+ else -+ dev_err(&pdev->dev, "Failed to register card: %d\n", ret); -+ -+ kfree(wm5102); -+ } -+ -+ return ret; -+} -+ -+static int snd_rpi_wsp_remove(struct platform_device *pdev) -+{ -+ struct snd_soc_card *card = &snd_rpi_wsp; -+ struct wm5102_machine_priv *wm5102 = snd_soc_card_get_drvdata(card); -+ -+ snd_soc_unregister_card(&snd_rpi_wsp); -+ kfree(wm5102); -+ -+ return 0; -+} -+ -+#ifdef CONFIG_OF -+static const struct of_device_id snd_rpi_wsp_of_match[] = { -+ { .compatible = "wlf,rpi-wm5102", }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, snd_rpi_wsp_of_match); -+#endif /* CONFIG_OF */ -+ -+static struct platform_driver snd_rpi_wsp_driver = { -+ .driver = { -+ .name = "snd-rpi-wsp", -+ .owner = THIS_MODULE, -+ .of_match_table = of_match_ptr(snd_rpi_wsp_of_match), -+ }, -+ .probe = snd_rpi_wsp_probe, -+ .remove = snd_rpi_wsp_remove, -+}; -+ -+module_platform_driver(snd_rpi_wsp_driver); -+ -+MODULE_AUTHOR("Nikesh Oswal"); -+MODULE_AUTHOR("Liu Xin"); -+MODULE_DESCRIPTION("ASoC Driver for Raspberry Pi connected to Cirrus sound pi"); -+MODULE_LICENSE("GPL"); -diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c -index 93b4008..1be8d2e 100644 ---- a/sound/soc/codecs/arizona.c -+++ b/sound/soc/codecs/arizona.c -@@ -1095,7 +1095,7 @@ int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, - unsigned int reg; - unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK; - unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT; -- unsigned int *clk; -+ int *clk; - - switch (clk_id) { - case ARIZONA_CLK_SYSCLK: -@@ -1375,6 +1375,9 @@ static int arizona_startup(struct snd_pcm_substream *substream, - const struct snd_pcm_hw_constraint_list *constraint; - unsigned int base_rate; - -+ if (!substream->runtime) -+ return 0; -+ - switch (dai_priv->clk) { - case ARIZONA_CLK_SYSCLK: - base_rate = priv->sysclk; -@@ -2093,9 +2096,9 @@ static int arizona_enable_fll(struct arizona_fll *fll) - /* Facilitate smooth refclk across the transition */ - regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x9, - ARIZONA_FLL1_GAIN_MASK, 0); -- regmap_update_bits_async(fll->arizona->regmap, fll->base + 1, -- ARIZONA_FLL1_FREERUN, -- ARIZONA_FLL1_FREERUN); -+ regmap_update_bits(fll->arizona->regmap, fll->base + 1, -+ ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN); -+ udelay(32); - } - - /* -@@ -2180,6 +2183,8 @@ static void arizona_disable_fll(struct arizona_fll *fll) - { - struct arizona *arizona = fll->arizona; - bool change; -+ int i; -+ unsigned int val; - - regmap_update_bits_async(arizona->regmap, fll->base + 1, - ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN); -@@ -2190,6 +2195,25 @@ static void arizona_disable_fll(struct arizona_fll *fll) - regmap_update_bits_async(arizona->regmap, fll->base + 1, - ARIZONA_FLL1_FREERUN, 0); - -+ arizona_fll_dbg(fll, "Waiting for FLL disable...\n"); -+ val = 0; -+ for (i = 0; i < 15; i++) { -+ if (i < 5) -+ usleep_range(200, 400); -+ else -+ msleep(20); -+ -+ regmap_read(arizona->regmap, -+ ARIZONA_INTERRUPT_RAW_STATUS_5, -+ &val); -+ if (!(val & (ARIZONA_FLL1_CLOCK_OK_STS << (fll->id - 1)))) -+ break; -+ } -+ if (i == 15) -+ arizona_fll_warn(fll, "Timed out waiting for disable\n"); -+ else -+ arizona_fll_dbg(fll, "FLL disabled (%d polls)\n", i); -+ - if (change) - pm_runtime_put_autosuspend(arizona->dev); - } -diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c -index a1305f8..31f36e6 100644 ---- a/sound/soc/soc-core.c -+++ b/sound/soc/soc-core.c -@@ -1295,7 +1295,7 @@ static int soc_link_dai_widgets(struct snd_soc_card *card, - if (play_w && capture_w) { - ret = snd_soc_dapm_new_pcm(card, dai_link->params, - dai_link->num_params, capture_w, -- play_w); -+ play_w, dai_link); - if (ret != 0) { - dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n", - play_w->name, capture_w->name, ret); -@@ -1308,7 +1308,7 @@ static int soc_link_dai_widgets(struct snd_soc_card *card, - if (play_w && capture_w) { - ret = snd_soc_dapm_new_pcm(card, dai_link->params, - dai_link->num_params, capture_w, -- play_w); -+ play_w, dai_link); - if (ret != 0) { - dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n", - play_w->name, capture_w->name, ret); -diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c -index afb70a5..104888d 100644 ---- a/sound/soc/soc-dapm.c -+++ b/sound/soc/soc-dapm.c -@@ -3450,11 +3450,12 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, - { - struct snd_soc_dapm_path *source_p, *sink_p; - struct snd_soc_dai *source, *sink; -- const struct snd_soc_pcm_stream *config = w->params + w->params_select; -+ struct snd_soc_pcm_stream *config = w->params + w->params_select; -+ struct snd_soc_dai_link *dai_link = w->priv; - struct snd_pcm_substream substream; - struct snd_pcm_hw_params *params = NULL; - u64 fmt; -- int ret; -+ int ret = 0; - - if (WARN_ON(!config) || - WARN_ON(list_empty(&w->edges[SND_SOC_DAPM_DIR_OUT]) || -@@ -3472,6 +3473,16 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, - source = source_p->source->priv; - sink = sink_p->sink->priv; - -+ if (dai_link && dai_link->params_fixup) { -+ ret = dai_link->params_fixup(w, event); -+ if (ret < 0) { -+ dev_err(w->dapm->dev, -+ "ASoC: params_fixup for dai link widget failed %d\n", -+ ret); -+ goto out; -+ } -+ } -+ - /* Be a little careful as we don't want to overflow the mask array */ - if (config->formats) { - fmt = ffs(config->formats) - 1; -@@ -3601,10 +3612,11 @@ static int snd_soc_dapm_dai_link_put(struct snd_kcontrol *kcontrol, - } - - int snd_soc_dapm_new_pcm(struct snd_soc_card *card, -- const struct snd_soc_pcm_stream *params, -+ struct snd_soc_pcm_stream *params, - unsigned int num_params, - struct snd_soc_dapm_widget *source, -- struct snd_soc_dapm_widget *sink) -+ struct snd_soc_dapm_widget *sink, -+ void *priv) - { - struct snd_soc_dapm_widget template; - struct snd_soc_dapm_widget *w; -@@ -3706,6 +3718,7 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card, - - w->params = params; - w->num_params = num_params; -+ w->priv = priv; - - ret = snd_soc_dapm_add_path(&card->dapm, source, w, NULL, NULL); - if (ret) |