Merge "msm: pm: Notify secure code of L2 power mode from last core only"
diff --git a/Documentation/devicetree/bindings/usb/ice40-hcd.txt b/Documentation/devicetree/bindings/usb/ice40-hcd.txt
new file mode 100644
index 0000000..43d24dc
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/ice40-hcd.txt
@@ -0,0 +1,45 @@
+ICE40 FPGA based SPI-USB bridge
+
+Documentation/devicetree/bindings/spi/spi-bus.txt provides the details
+of the required and optional properties of a SPI slave device node.
+
+The purpose of this document is to provide the additional properties
+that are required to use the ICE40 FPGA based SPI slave device as a
+USB host controller.
+
+Required properties:
+- compatible : should be "lattice,ice40-spi-usb"
+- <supply-name>-supply: handle to the regulator device tree node
+  Required "supply-name" is "core-vcc" and "spi-vcc"
+- reset-gpio: gpio used to assert the bridge chip reset
+- slave-select-gpio: gpio used to select the slave during configuration
+  loading
+- config-done-gpio: gpio used to indicate the configuration status
+- vcc-en-gpio: gpio used to enable the chip power supply
+
+Optional properties:
+- interrupts: IRQ lines used by this controller
+- clk-en-gpio: gpio used to enable the 19.2 MHZ clock to the bridge
+  chip. If it is not present, assume that the clock is available on
+  the bridge chip board.
+- <supply-name>-supply: handle to the regulator device tree node
+  Optional "supply-name" is "gpio" used to power up the gpio bank
+  used by this device
+
+	spi@f9923000 {
+		lattice,spi-usb@3 {
+			compatible = "lattice,ice40-spi-usb";
+			reg = <3>;
+			spi-max-frequency = <50000000>;
+			spi-cpol = <1>;
+			spi-cpha = <1>;
+			interrupt-parent = <&msmgpio>;
+			interrupts = <121 0x8>;
+			core-vcc-supply = <&pm8226_l2>;
+			spi-vcc-supply = <&pm8226_l5>;
+			lattice,reset-gpio = <&msmgpio 114 0>;
+			lattice,slave-select-gpio = <&msmgpio 118 0>;
+			lattice,config-done-gpio = <&msmgpio 115 0>;
+			lattice,vcc-en-gpio = <&msmgpio 117 0>;
+		};
+	};
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index b94b587..440dac1 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -29,6 +29,7 @@
 idt	Integrated Device Technologies, Inc.
 intercontrol	Inter Control Group
 invn	InvenSense Inc.
+lattice	Lattice Semiconductor.
 linux	Linux-specific binding
 kionix	Kionix Inc.
 marvell	Marvell Technology Group Ltd.
diff --git a/Documentation/usb/ice40-hcd.txt b/Documentation/usb/ice40-hcd.txt
new file mode 100644
index 0000000..54f845e
--- /dev/null
+++ b/Documentation/usb/ice40-hcd.txt
@@ -0,0 +1,247 @@
+Introduction
+============
+
+USB UICC connectivity is required for MSM8x12. This SoC has only 1 USB
+controller which is used for peripheral mode and charging. Hence an external
+USB host controller over SPI is used to connect a USB UICC card. ICE40 FPGA
+based SPI to IC-USB (Inter-Chip USB) bridge chip is used.
+
+The ICE40 Host controller driver (ice40-hcd) is registered as a SPI protocol
+driver and interacts with the SPI subsystem on one side and interacts with the
+USB core on the other side.
+
+Hardware description
+====================
+
+The ICE40 devices are SRAM-based FPGAs. The SRAM memory cells are volatile,
+meaning that once power is removed from the device, its configuration is lost
+and must be reloaded on the next power-up. An on-chip non-volatile configuration
+memory or an external SPI flash are not used to store the configuration data due
+to increased power consumption.  Instead, the software loads the configuration
+data through SPI interface after powering up the bridge chip. Once the
+configuration data is programmed successfully, the bridge chip will be ready for
+the USB host controller operations.
+
+The ICE40 device has an interrupt signal apart from the standard SPI signals
+CSn, SCLK, MOSI and MISO. It has support for 25 to 50 MHz frequencies. The
+maximum operating frequency during configuration loading is 25 MHz.
+
+The bridge chip requires two power supplies, SPI_VCC (1.8v - 3.3v) and VCC_CORE
+(1.2v). The SPI_VCC manages the SPI slave portion and VCC_CORE manages the USB
+serial engine (SIE) portion.  It requires a 19.2 MHz reference clock and a
+32 MHz clock is required for remote wakeup detection during suspend.
+
+The configuration loading sequence:
+
+- Assert the RSTn pin. This keeps bridge chip in reset state after downloading
+the configuration data.
+- The bridge chip samples the SPI interface chip select pin during power-up and
+enters SPI slave mode if it is low. Drive the chip select pin low before
+powering up the bridge chip.
+- Power-up the bridge chip by enabling SPI_VCC and VCC_CORE
+- De-assert the chip select pin after 50 usec.
+- Transfer the configuration data over SPI. Note that the bridge chip requires
+49 dummy clock cycles after sending the data.
+- The bridge chip indicates the status of the configuration loading via config
+done pin. It may take 50 usec to assert this pin.
+
+The 19.2 MHz clock should be supplied before de-asserting the RSTn pin. A PLL
+is used to generate a 48MHz clock signal that then creates a 12MHz clock signal
+by a divider. When the PLLOK bit is set in USB Transfer Result register, it
+indicates that the PLL output is locked to the input reference clock. When it
+is 0, it indicates that the PLL is out of lock. It is recommended to assert the
+RSTn pin to re-synchronize the PLL to the reference clock when the PLL loses
+lock. The chip will be ready for the USB host controller operations after it is
+brought out of reset and PLL is synchronized to the reference clock.
+
+The software is responsible for initiating all the USB host transfers by writing
+the associated registers. The SIE in the bridge chip performs the USB host
+operations via the IC-USB bus based on the registers set by the software. The
+USB transfer results as well as the bus status like the peripheral connection,
+disconnection, resume, etc. are notified to software through the interrupt and
+the internal registers.
+
+The bridge chip provides the DP & DM pull-down resistor control to the software.
+The pull-down resistors are enabled automatically after the power up to force
+the SE0 condition on the bus. The software is required to disable these
+resistors before driving the reset on the bus. Control, Bulk and Interrupt
+transfers are supported. The data toggling states are not maintained in the
+hardware and should be serviced by the software. The bridge chip returns
+one of the following values for a USB transaction (SETUP/IN/OUT) via Transfer
+result register.
+
+xSUCCESS: Successful transfer.
+xBUSY: The SIE is busy with a USB transfer.
+xPKTERR: Packet Error (stuff, EOP).
+xPIDERR: PID check bits are incorrect.
+xNAK: Device returned NAK. This is not an error condition for IN/OUT. But it
+is an error condition for SETUP.
+xSTALL: Device returned STALL.
+xWRONGPID: Wrong PID is received. For example a IN transaction is attempted on
+OUT endpoint.
+xCRCERR: CRC error.
+xTOGERR: Toggle bit error. The SIE returns ACK when the toggle mismatch happens
+for IN transaction  and returns this error code. Software should discard the
+data as it was received already in the previous transaction.
+xBADLEN: Too big packet size received.
+xTIMEOUT: Device failed to respond in time.
+
+Software description
+====================
+
+This driver is compiled as a module and is loaded by the userspace after
+getting the UICC card insertion event from the modem processor. The module is
+unloaded upon the UICC card removal.
+
+This driver registers as a SPI protocol driver. The SPI controller driver
+manages the chip select pin. This pin needs to be driven low before powering
+up the bridge chip. Hence this pin settings are overridden temporarily during
+the bridge chip power-up sequence. The original settings are restored before
+sending the configuration data to the bridge chip which acts as a SPI slave.
+Both pinctl and gpiomux framework allow this type of use case.
+
+The configuration data file is stored on the eMMC card. Firmware class API
+request_firmware() is used to read the configuration data file. The
+configuration data is then sent to the bridge chip via SPI interface. The
+bridge chip asserts the config done pin once the configuration is completed.
+
+The driver registers as a Full Speed (USB 1.1) HCD. The following methods
+are implemented that are part of hc_drive struct:
+
+reset: It is called one time by the core during HCD registration. The
+default address 0 is programmed and the line state is sampled to check if any
+device is connected. If any device is connected, the port flags are updated
+accordingly. As the module is loaded after the UICC card is inserted, the
+device would be present at this time.
+
+start: This method is called one time by the core during HCD registration.
+The bridge chip is programmed to transmit the SOFs.
+
+stop: The method is called one time by the core during HCD deregistration.
+The bridge chip is programmed to stop transmitting the SOFs.
+
+hub_control: This method is called by the core to manage the Root HUB. The
+hardware does not maintain port state.  The software maintain the port
+state and provide the information to the core when required.  The following
+HUB class requests are supported.
+
+- GetHubDescriptor: The HUB descriptor is sent to the core. Only 1 port
+is present. Over current protection and port power control are not supported.
+- SetPortFeature: The device reset and suspend are supported. The The DP & DM
+pull-down resistors are disabled before driving the reset as per the IC-USB
+spec. The reset signaling is stopped when the core queries the port status.
+- GetPortStatus: The device connection status is sent to the core.  If a reset
+is in progress, it is stopped before returning the port status.
+- ClearPortFeature: The device resume (clear suspend) is supported.
+
+urb_enqueue: This method is called by the core to initiate a USB Control/Bulk
+transfer.  If the endpoint private context is not present, it will be created to
+hold the endpoint number, host endpoint structure, transaction error count, halt
+state and unlink state. The URB is attached to the endpoint URB list. If the
+endpoint is not active, it is attached to the asynchronous schedule list and the
+work is scheduled to traverse this list. The traversal algorithm is explained
+later in this document.
+
+urb_dequeue: This method is called by the core when an URB is unlinked.  If the
+endpoint is not active, the URB is unlinked immediately.  Otherwise the endpoint
+is marked for unlink and URB is unlinked from the asynchronous schedule work.
+
+bus_suspend: This method is called by the core during root hub suspend. The SOFs
+are already stopped during the port suspend which happens before root hub
+suspend. Assert the RSTn pin to put the bridge chip in reset state and stop XO
+(19.2 MHz) clock.
+
+bus_resume: This method is called by the core during root hub resume. Turn on
+the XO clock and de-assert the RSTn signal to bring the chip out of reset.
+
+endpoint_disable: This method is called by the core during the device
+disconnect. All the URB are unlinked by this time, so free the endpoint private
+structure.
+
+Asynchronous scheduling:
+
+All the active endpoints are queued to the asynchronous schedule list. A worker
+thread iterates over this circular list and process the URBs. Processing an URB
+involves initiating multiple SETUP/IN/OUT transactions and checking the result.
+After receiving the DATA/ACK, the toggle bit is inverted.
+
+A URB is finished when any of the following events occur:
+
+- The entire data is received for an OUT endpoint or a short packet is received
+for an IN endpoint.
+- The endpoint is stalled by the device. -EPIPE is returned.
+- Transaction error is occurred consecutively 3 times. -EPROTO is returned.
+- A NAK received for a SETUP transaction.
+- The URB is unlinked.
+
+The next transaction is issued on the next endpoint (if available) irrespective
+of the result of the current transaction.  But the IN/OUT transaction of data
+or status phase is attempted immediately after the SETUP transaction for a
+control endpoint. If a NAK is received for this transaction, the control
+transfer is resumed next time when the control endpoint is encountered in the
+asynchronous schedule list. This is to give the control transfers priority
+over the bulk transfers.
+
+The endpoint is marked as halted when a URB is finished due to transaction
+errors or stall condition. The halted endpoint is removed from the asynchronous
+schedule list.  It will be added again next time when a URB is enqueued on this
+endpoint.
+
+This driver provides debugfs interface and exports a file called "command" under
+<debugfs root>/ice40 directory.  The following strings can be echoed to this
+file.
+
+"poll": If the device is connected after the module is loaded, it will not be
+detected automatically. The bus is sampled when this string is echoed. If a
+device is connected, port flags are updated and core is notified about the
+device connect event.
+
+"rwtest": Function Address register is written and read back to validate the
+contents. This should NOT be used while the usb device is connected. This is
+strictly for debugging purpose.
+
+"dump": Dumps all the register values to the kernel log buffer.
+
+Design Goals:
+=============
+
+- Handle errors gracefully. Implement retry mechanism for transaction errors,
+memory failures. Mark HCD as dead for serious errors like SPI transaction
+errors to avoid further interactions with the attached USB device.
+- Keep the asynchronous schedule algorithm simple and efficient. Take advantage
+of the static configuration of the USB device. UICC cards has only CCID and Mass
+storage interfaces. These interface protocol allows only 1 active transfer on
+either in or out endpoint.
+- Add trace points to capture USB transactions.
+
+Driver parameters
+=================
+
+The driver is compiled as a module and it accepts the configuration data file
+name as a module param called "firmware". The default configuration file name
+is "ice40.bin".
+
+Config options
+==============
+
+Set CONFIG_USB_SL811_HCD to m to compile this driver as a module.  The driver
+should not be compiled statically, because the configuration data is not
+available during kernel boot.
+
+To do
+=====
+
+- The bridge chip has 2 IN FIFO and 2 OUT FIFO.  Implement double buffering.
+- The bridge chip has an interrupt to indicate the transaction (IN/OUT)
+completion. The current implementation uses polling for simplicity and to avoid
+interrupt latencies.  Evaluate interrupt approach.
+- The bridge chip can be completely power collapsed during suspend to avoid
+leakage currents. As the bridge chip does not have any non-volatile memory,
+the configuration data needs to be loaded during resume. This method has higher
+power savings with higher resume latencies. Evaluate this approach.
+- Implement Interrupt transfers if required.
+- The request_firmware() API copies the configuration data file to the kernel
+virtual memory. This memory can't be used for DMA. The current implementation
+copies this data into contiguous physical memory which is allocated via
+kmalloc. If this memory allocation fails, try to allocate multiple pages
+and submit the SPI message with multiple transfers.
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 90e8fd6..43cd7c6 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -606,6 +606,7 @@
 		qcom,gpio-miso = <&msmgpio 87 0>;
 		qcom,gpio-clk  = <&msmgpio 89 0>;
 		qcom,gpio-cs0  = <&msmgpio 88 0>;
+		qcom,gpio-cs2  = <&msmgpio 85 0>;
 
 		qcom,infinite-mode = <0>;
 		qcom,use-bam;
@@ -613,6 +614,21 @@
 		qcom,bam-consumer-pipe-index = <18>;
 		qcom,bam-producer-pipe-index = <19>;
 		qcom,master-id = <86>;
+
+		lattice,spi-usb@2 {
+			compatible = "lattice,ice40-spi-usb";
+			reg = <2>;
+			spi-max-frequency = <50000000>;
+			spi-cpol = <1>;
+			spi-cpha = <1>;
+			core-vcc-supply = <&pm8110_l2>;
+			spi-vcc-supply = <&pm8110_l6>;
+			gpio-supply = <&pm8110_l22>;
+			lattice,reset-gpio = <&msmgpio 95 0>;
+			lattice,slave-select-gpio = <&msmgpio 85 0>;
+			lattice,config-done-gpio = <&msmgpio 94 0>;
+			lattice,vcc-en-gpio = <&msmgpio 96 0>;
+		};
 	};
 
 	qcom,pronto@fb21b000 {
diff --git a/arch/arm/boot/dts/msm8974pro.dtsi b/arch/arm/boot/dts/msm8974pro.dtsi
index a72ebb2..813ecaa 100644
--- a/arch/arm/boot/dts/msm8974pro.dtsi
+++ b/arch/arm/boot/dts/msm8974pro.dtsi
@@ -1578,13 +1578,13 @@
 		/* Off */
 		<26 512 0 0>, <89 604 0 0>,
 		/* Sub-SVS / SVS */
-		<26 512 0 1600000>, <89 604 0 3200000>,
+		<26 512 1200000 2456000>, <89 604 0 3200000>,
 		/* SVS */
-		<26 512 0 2456000>, <89 604 0 3200000>,
+		<26 512 1200000 2456000>, <89 604 0 3200000>,
 		/* low Nominal / SVS */
 		<26 512 0 3680000>, <89 604 0 3200000>,
 		/* SVS / low Nominal */
-		<26 512 0 2456000>, <89 604 0 5280000>,
+		<26 512 1200000 2456000>, <89 604 0 5280000>,
 		/* low Nominal / low Nominal */
 		<26 512 0 3680000>, <89 604 0 5280000>,
 		/* Nominal / low Nominal */
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index 1ba8527..ede654d 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -212,6 +212,13 @@
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_QSEECOM=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
 CONFIG_MD=y
 CONFIG_BLK_DEV_DM=y
 CONFIG_DM_CRYPT=y
@@ -335,6 +342,12 @@
 CONFIG_HID_MAGICMOUSE=y
 CONFIG_HID_MICROSOFT=y
 CONFIG_HID_ELECOM=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_ICE40_HCD=m
+CONFIG_USB_CCID_BRIDGE=y
+CONFIG_USB_STORAGE=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_DEBUG_FILES=y
 CONFIG_USB_GADGET_DEBUG_FS=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 458faac..4f60013 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -213,6 +213,13 @@
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_QSEECOM=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
 CONFIG_MD=y
 CONFIG_BLK_DEV_DM=y
 CONFIG_DM_CRYPT=y
@@ -357,6 +364,12 @@
 CONFIG_HID_MAGICMOUSE=y
 CONFIG_HID_MICROSOFT=y
 CONFIG_HID_ELECOM=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_SUSPEND=y
+CONFIG_USB_ICE40_HCD=m
+CONFIG_USB_CCID_BRIDGE=y
+CONFIG_USB_STORAGE=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_DEBUG_FILES=y
 CONFIG_USB_GADGET_DEBUG_FS=y
diff --git a/arch/arm/include/asm/system_misc.h b/arch/arm/include/asm/system_misc.h
index 71f4827..0827df7 100644
--- a/arch/arm/include/asm/system_misc.h
+++ b/arch/arm/include/asm/system_misc.h
@@ -24,6 +24,7 @@
 extern void disable_hlt(void);
 extern void enable_hlt(void);
 extern int get_hlt(void);
+extern char* (*arch_read_hardware_id)(void);
 
 #endif /* !__ASSEMBLY__ */
 
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 7298f9a..c110f0f 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -110,6 +110,9 @@
 unsigned int cold_boot;
 EXPORT_SYMBOL(cold_boot);
 
+char* (*arch_read_hardware_id)(void);
+EXPORT_SYMBOL(arch_read_hardware_id);
+
 #ifdef MULTI_CPU
 struct processor processor __read_mostly;
 #endif
@@ -1108,7 +1111,10 @@
 
 	seq_puts(m, "\n");
 
-	seq_printf(m, "Hardware\t: %s\n", machine_name);
+	if (!arch_read_hardware_id)
+		seq_printf(m, "Hardware\t: %s\n", machine_name);
+	else
+		seq_printf(m, "Hardware\t: %s\n", arch_read_hardware_id());
 	seq_printf(m, "Revision\t: %04x\n", system_rev);
 	seq_printf(m, "Serial\t\t: %08x%08x\n",
 		   system_serial_high, system_serial_low);
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index 4234f2a..c91deb2 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -730,6 +730,61 @@
 	},
 };
 
+static struct gpiomux_setting ice40_spi_cs_act_config = {
+	.func = GPIOMUX_FUNC_1,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting ice40_spi_cs_susp_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_6MA,
+	.pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting ice40_act_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting ice40_susp_config = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+};
+
+static struct msm_gpiomux_config ice40_spi_usb_configs[] __initdata = {
+	{
+		.gpio = 85,
+		.settings = {
+			[GPIOMUX_ACTIVE] = &ice40_spi_cs_act_config,
+			[GPIOMUX_SUSPENDED] = &ice40_spi_cs_susp_config,
+		},
+	},
+	{
+		.gpio = 94,
+		.settings = {
+			[GPIOMUX_ACTIVE] = &ice40_act_config,
+			[GPIOMUX_SUSPENDED] = &ice40_susp_config,
+		},
+	},
+	{
+		.gpio = 95,
+		.settings = {
+			[GPIOMUX_ACTIVE] = &ice40_act_config,
+			[GPIOMUX_SUSPENDED] = &ice40_susp_config,
+		},
+	},
+	{
+		.gpio = 96,
+		.settings = {
+			[GPIOMUX_ACTIVE] = &ice40_act_config,
+			[GPIOMUX_SUSPENDED] = &ice40_susp_config,
+		},
+	},
+};
+
 void __init msm8610_init_gpiomux(void)
 {
 	int rc;
@@ -770,6 +825,10 @@
 	if (of_board_is_cdp())
 		msm_gpiomux_install(msm_cdc_dmic_configs,
 			ARRAY_SIZE(msm_cdc_dmic_configs));
+
+	if (of_board_is_cdp())
+		msm_gpiomux_install(ice40_spi_usb_configs,
+			ARRAY_SIZE(ice40_spi_usb_configs));
 }
 
 static void wcnss_switch_to_gpio(void)
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index aeb32f8..24b5181 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -138,6 +138,11 @@
 	MSM_CPU_SAMARIUM,
 };
 
+struct msm_soc_info {
+	enum msm_cpu generic_soc_type;
+	char *soc_id_string;
+};
+
 enum pmic_model {
 	PMIC_MODEL_PM8058	= 13,
 	PMIC_MODEL_PM8028	= 14,
diff --git a/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c b/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
index 399e073..df7760a 100644
--- a/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
+++ b/arch/arm/mach-msm/qdsp6v2/msm_audio_ion.c
@@ -344,7 +344,7 @@
 		pr_err("%s: ion import dma buffer failed\n",
 			__func__);
 		rc = -EINVAL;
-		goto err_destroy_client;
+		goto err;
 	}
 
 	if (ionflag != NULL) {
@@ -380,10 +380,6 @@
 
 err_ion_handle:
 	ion_free(client, *handle);
-err_destroy_client:
-	msm_audio_ion_client_destroy(client);
-	client = NULL;
-	*handle = NULL;
 err:
 	return rc;
 }
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index ab03712..8e7adba 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -21,10 +21,12 @@
 #include <linux/sys_soc.h>
 #include <linux/slab.h>
 #include <linux/stat.h>
+#include <linux/string.h>
 #include <linux/sysdev.h>
 #include <linux/types.h>
 
 #include <asm/mach-types.h>
+#include <asm/system_misc.h>
 
 #include <mach/socinfo.h>
 #include <mach/msm_smem.h>
@@ -185,246 +187,247 @@
 	struct socinfo_v8 v8;
 } *socinfo;
 
-static enum msm_cpu cpu_of_id[] = {
+static struct msm_soc_info cpu_of_id[] = {
 
 	/* 7x01 IDs */
-	[1]  = MSM_CPU_7X01,
-	[16] = MSM_CPU_7X01,
-	[17] = MSM_CPU_7X01,
-	[18] = MSM_CPU_7X01,
-	[19] = MSM_CPU_7X01,
-	[23] = MSM_CPU_7X01,
-	[25] = MSM_CPU_7X01,
-	[26] = MSM_CPU_7X01,
-	[32] = MSM_CPU_7X01,
-	[33] = MSM_CPU_7X01,
-	[34] = MSM_CPU_7X01,
-	[35] = MSM_CPU_7X01,
+	[0]  = {MSM_CPU_UNKNOWN, "Unknown CPU"},
+	[1]  = {MSM_CPU_7X01, "MSM7X01"},
+	[16] = {MSM_CPU_7X01, "MSM7X01"},
+	[17] = {MSM_CPU_7X01, "MSM7X01"},
+	[18] = {MSM_CPU_7X01, "MSM7X01"},
+	[19] = {MSM_CPU_7X01, "MSM7X01"},
+	[23] = {MSM_CPU_7X01, "MSM7X01"},
+	[25] = {MSM_CPU_7X01, "MSM7X01"},
+	[26] = {MSM_CPU_7X01, "MSM7X01"},
+	[32] = {MSM_CPU_7X01, "MSM7X01"},
+	[33] = {MSM_CPU_7X01, "MSM7X01"},
+	[34] = {MSM_CPU_7X01, "MSM7X01"},
+	[35] = {MSM_CPU_7X01, "MSM7X01"},
 
 	/* 7x25 IDs */
-	[20] = MSM_CPU_7X25,
-	[21] = MSM_CPU_7X25, /* 7225 */
-	[24] = MSM_CPU_7X25, /* 7525 */
-	[27] = MSM_CPU_7X25, /* 7625 */
-	[39] = MSM_CPU_7X25,
-	[40] = MSM_CPU_7X25,
-	[41] = MSM_CPU_7X25,
-	[42] = MSM_CPU_7X25,
-	[62] = MSM_CPU_7X25, /* 7625-1 */
-	[63] = MSM_CPU_7X25, /* 7225-1 */
-	[66] = MSM_CPU_7X25, /* 7225-2 */
+	[20] = {MSM_CPU_7X25, "MSM7X25"},
+	[21] = {MSM_CPU_7X25, "MSM7X25"},
+	[24] = {MSM_CPU_7X25, "MSM7X25"},
+	[27] = {MSM_CPU_7X25, "MSM7X25"},
+	[39] = {MSM_CPU_7X25, "MSM7X25"},
+	[40] = {MSM_CPU_7X25, "MSM7X25"},
+	[41] = {MSM_CPU_7X25, "MSM7X25"},
+	[42] = {MSM_CPU_7X25, "MSM7X25"},
+	[62] = {MSM_CPU_7X25, "MSM7X25"},
+	[63] = {MSM_CPU_7X25, "MSM7X25"},
+	[66] = {MSM_CPU_7X25, "MSM7X25"},
 
 
 	/* 7x27 IDs */
-	[43] = MSM_CPU_7X27,
-	[44] = MSM_CPU_7X27,
-	[61] = MSM_CPU_7X27,
-	[67] = MSM_CPU_7X27, /* 7227-1 */
-	[68] = MSM_CPU_7X27, /* 7627-1 */
-	[69] = MSM_CPU_7X27, /* 7627-2 */
+	[43] = {MSM_CPU_7X27, "MSM7X27"},
+	[44] = {MSM_CPU_7X27, "MSM7X27"},
+	[61] = {MSM_CPU_7X27, "MSM7X27"},
+	[67] = {MSM_CPU_7X27, "MSM7X27"},
+	[68] = {MSM_CPU_7X27, "MSM7X27"},
+	[69] = {MSM_CPU_7X27, "MSM7X27"},
 
 
 	/* 8x50 IDs */
-	[30] = MSM_CPU_8X50,
-	[36] = MSM_CPU_8X50,
-	[37] = MSM_CPU_8X50,
-	[38] = MSM_CPU_8X50,
+	[30] = {MSM_CPU_8X50, "MSM8X50"},
+	[36] = {MSM_CPU_8X50, "MSM8X50"},
+	[37] = {MSM_CPU_8X50, "MSM8X50"},
+	[38] = {MSM_CPU_8X50, "MSM8X50"},
 
 	/* 7x30 IDs */
-	[59] = MSM_CPU_7X30,
-	[60] = MSM_CPU_7X30,
+	[59] = {MSM_CPU_7X30, "MSM7X30"},
+	[60] = {MSM_CPU_7X30, "MSM7X30"},
 
 	/* 8x55 IDs */
-	[74] = MSM_CPU_8X55,
-	[75] = MSM_CPU_8X55,
-	[85] = MSM_CPU_8X55,
+	[74] = {MSM_CPU_8X55, "MSM8X55"},
+	[75] = {MSM_CPU_8X55, "MSM8X55"},
+	[85] = {MSM_CPU_8X55, "MSM8X55"},
 
 	/* 8x60 IDs */
-	[70] = MSM_CPU_8X60,
-	[71] = MSM_CPU_8X60,
-	[86] = MSM_CPU_8X60,
+	[70] = {MSM_CPU_8X60, "MSM8X60"},
+	[71] = {MSM_CPU_8X60, "MSM8X60"},
+	[86] = {MSM_CPU_8X60, "MSM8X60"},
 
 	/* 8960 IDs */
-	[87] = MSM_CPU_8960,
+	[87] = {MSM_CPU_8960, "MSM8960"},
 
 	/* 7x25A IDs */
-	[88] = MSM_CPU_7X25A,
-	[89] = MSM_CPU_7X25A,
-	[96] = MSM_CPU_7X25A,
+	[88] = {MSM_CPU_7X25A, "MSM7X25A"},
+	[89] = {MSM_CPU_7X25A, "MSM7X25A"},
+	[96] = {MSM_CPU_7X25A, "MSM7X25A"},
 
 	/* 7x27A IDs */
-	[90] = MSM_CPU_7X27A,
-	[91] = MSM_CPU_7X27A,
-	[92] = MSM_CPU_7X27A,
-	[97] = MSM_CPU_7X27A,
+	[90] = {MSM_CPU_7X27A, "MSM7X27A"},
+	[91] = {MSM_CPU_7X27A, "MSM7X27A"},
+	[92] = {MSM_CPU_7X27A, "MSM7X27A"},
+	[97] = {MSM_CPU_7X27A, "MSM7X27A"},
 
 	/* FSM9xxx ID */
-	[94] = FSM_CPU_9XXX,
-	[95] = FSM_CPU_9XXX,
+	[94] = {FSM_CPU_9XXX, "FSM9XXX"},
+	[95] = {FSM_CPU_9XXX, "FSM9XXX"},
 
 	/*  7x25AA ID */
-	[98] = MSM_CPU_7X25AA,
-	[99] = MSM_CPU_7X25AA,
-	[100] = MSM_CPU_7X25AA,
+	[98] = {MSM_CPU_7X25AA, "MSM7X25AA"},
+	[99] = {MSM_CPU_7X25AA, "MSM7X25AA"},
+	[100] = {MSM_CPU_7X25AA, "MSM7X25AA"},
 
 	/*  7x27AA ID */
-	[101] = MSM_CPU_7X27AA,
-	[102] = MSM_CPU_7X27AA,
-	[103] = MSM_CPU_7X27AA,
-	[136] = MSM_CPU_7X27AA,
+	[101] = {MSM_CPU_7X27AA, "MSM7X27AA"},
+	[102] = {MSM_CPU_7X27AA, "MSM7X27AA"},
+	[103] = {MSM_CPU_7X27AA, "MSM7X27AA"},
+	[136] = {MSM_CPU_7X27AA, "MSM7X27AA"},
 
 	/* 9x15 ID */
-	[104] = MSM_CPU_9615,
-	[105] = MSM_CPU_9615,
-	[106] = MSM_CPU_9615,
-	[107] = MSM_CPU_9615,
-	[171] = MSM_CPU_9615,
+	[104] = {MSM_CPU_9615, "MSM9615"},
+	[105] = {MSM_CPU_9615, "MSM9615"},
+	[106] = {MSM_CPU_9615, "MSM9615"},
+	[107] = {MSM_CPU_9615, "MSM9615"},
+	[171] = {MSM_CPU_9615, "MSM9615"},
 
 	/* 8064 IDs */
-	[109] = MSM_CPU_8064,
+	[109] = {MSM_CPU_8064, "APQ8064"},
 
 	/* 8930 IDs */
-	[116] = MSM_CPU_8930,
-	[117] = MSM_CPU_8930,
-	[118] = MSM_CPU_8930,
-	[119] = MSM_CPU_8930,
-	[179] = MSM_CPU_8930,
+	[116] = {MSM_CPU_8930, "MSM8930"},
+	[117] = {MSM_CPU_8930, "MSM8930"},
+	[118] = {MSM_CPU_8930, "MSM8930"},
+	[119] = {MSM_CPU_8930, "MSM8930"},
+	[179] = {MSM_CPU_8930, "MSM8930"},
 
 	/* 8627 IDs */
-	[120] = MSM_CPU_8627,
-	[121] = MSM_CPU_8627,
+	[120] = {MSM_CPU_8627, "MSM8627"},
+	[121] = {MSM_CPU_8627, "MSM8627"},
 
 	/* 8660A ID */
-	[122] = MSM_CPU_8960,
+	[122] = {MSM_CPU_8960, "MSM8960"},
 
 	/* 8260A ID */
-	[123] = MSM_CPU_8960,
+	[123] = {MSM_CPU_8960, "MSM8960"},
 
 	/* 8060A ID */
-	[124] = MSM_CPU_8960,
+	[124] = {MSM_CPU_8960, "MSM8960"},
 
 	/* 8974 IDs */
-	[126] = MSM_CPU_8974,
-	[184] = MSM_CPU_8974,
-	[185] = MSM_CPU_8974,
-	[186] = MSM_CPU_8974,
+	[126] = {MSM_CPU_8974, "MSM8974"},
+	[184] = {MSM_CPU_8974, "MSM8974"},
+	[185] = {MSM_CPU_8974, "MSM8974"},
+	[186] = {MSM_CPU_8974, "MSM8974"},
 
 	/* 8974AA IDs */
-	[208] = MSM_CPU_8974PRO_AA,
-	[211] = MSM_CPU_8974PRO_AA,
-	[214] = MSM_CPU_8974PRO_AA,
-	[217] = MSM_CPU_8974PRO_AA,
+	[208] = {MSM_CPU_8974PRO_AA, "MSM8974PRO-AA"},
+	[211] = {MSM_CPU_8974PRO_AA, "MSM8974PRO-AA"},
+	[214] = {MSM_CPU_8974PRO_AA, "MSM8974PRO-AA"},
+	[217] = {MSM_CPU_8974PRO_AA, "MSM8974PRO-AA"},
 
 	/* 8974AB IDs */
-	[209] = MSM_CPU_8974PRO_AB,
-	[212] = MSM_CPU_8974PRO_AB,
-	[215] = MSM_CPU_8974PRO_AB,
-	[218] = MSM_CPU_8974PRO_AB,
+	[209] = {MSM_CPU_8974PRO_AB, "MSM8974PRO-AB"},
+	[212] = {MSM_CPU_8974PRO_AB, "MSM8974PRO-AB"},
+	[215] = {MSM_CPU_8974PRO_AB, "MSM8974PRO-AB"},
+	[218] = {MSM_CPU_8974PRO_AB, "MSM8974PRO-AB"},
 
 	/* 8974AC IDs */
-	[194] = MSM_CPU_8974PRO_AC,
-	[210] = MSM_CPU_8974PRO_AC,
-	[213] = MSM_CPU_8974PRO_AC,
-	[216] = MSM_CPU_8974PRO_AC,
+	[194] = {MSM_CPU_8974PRO_AC, "MSM8974PRO-AC"},
+	[210] = {MSM_CPU_8974PRO_AC, "MSM8974PRO-AC"},
+	[213] = {MSM_CPU_8974PRO_AC, "MSM8974PRO-AC"},
+	[216] = {MSM_CPU_8974PRO_AC, "MSM8974PRO-AC"},
 
 	/* 8625 IDs */
-	[127] = MSM_CPU_8625,
-	[128] = MSM_CPU_8625,
-	[129] = MSM_CPU_8625,
-	[137] = MSM_CPU_8625,
-	[167] = MSM_CPU_8625,
+	[127] = {MSM_CPU_8625, "MSM8625"},
+	[128] = {MSM_CPU_8625, "MSM8625"},
+	[129] = {MSM_CPU_8625, "MSM8625"},
+	[137] = {MSM_CPU_8625, "MSM8625"},
+	[167] = {MSM_CPU_8625, "MSM8625"},
 
 	/* 8064 MPQ ID */
-	[130] = MSM_CPU_8064,
+	[130] = {MSM_CPU_8064, "APQ8064"},
 
 	/* 7x25AB IDs */
-	[131] = MSM_CPU_7X25AB,
-	[132] = MSM_CPU_7X25AB,
-	[133] = MSM_CPU_7X25AB,
-	[135] = MSM_CPU_7X25AB,
+	[131] = {MSM_CPU_7X25AB, "MSM7X25AB"},
+	[132] = {MSM_CPU_7X25AB, "MSM7X25AB"},
+	[133] = {MSM_CPU_7X25AB, "MSM7X25AB"},
+	[135] = {MSM_CPU_7X25AB, "MSM7X25AB"},
 
 	/* 9625 IDs */
-	[134] = MSM_CPU_9625,
-	[148] = MSM_CPU_9625,
-	[149] = MSM_CPU_9625,
-	[150] = MSM_CPU_9625,
-	[151] = MSM_CPU_9625,
-	[152] = MSM_CPU_9625,
-	[173] = MSM_CPU_9625,
-	[174] = MSM_CPU_9625,
-	[175] = MSM_CPU_9625,
+	[134] = {MSM_CPU_9625, "MSM9625"},
+	[148] = {MSM_CPU_9625, "MSM9625"},
+	[149] = {MSM_CPU_9625, "MSM9625"},
+	[150] = {MSM_CPU_9625, "MSM9625"},
+	[151] = {MSM_CPU_9625, "MSM9625"},
+	[152] = {MSM_CPU_9625, "MSM9625"},
+	[173] = {MSM_CPU_9625, "MSM9625"},
+	[174] = {MSM_CPU_9625, "MSM9625"},
+	[175] = {MSM_CPU_9625, "MSM9625"},
 
 	/* 8960AB IDs */
-	[138] = MSM_CPU_8960AB,
-	[139] = MSM_CPU_8960AB,
-	[140] = MSM_CPU_8960AB,
-	[141] = MSM_CPU_8960AB,
+	[138] = {MSM_CPU_8960AB, "MSM8960AB"},
+	[139] = {MSM_CPU_8960AB, "MSM8960AB"},
+	[140] = {MSM_CPU_8960AB, "MSM8960AB"},
+	[141] = {MSM_CPU_8960AB, "MSM8960AB"},
 
 	/* 8930AA IDs */
-	[142] = MSM_CPU_8930AA,
-	[143] = MSM_CPU_8930AA,
-	[144] = MSM_CPU_8930AA,
-	[160] = MSM_CPU_8930AA,
-	[180] = MSM_CPU_8930AA,
+	[142] = {MSM_CPU_8930AA, "MSM8930AA"},
+	[143] = {MSM_CPU_8930AA, "MSM8930AA"},
+	[144] = {MSM_CPU_8930AA, "MSM8930AA"},
+	[160] = {MSM_CPU_8930AA, "MSM8930AA"},
+	[180] = {MSM_CPU_8930AA, "MSM8930AA"},
 
 	/* 8226 IDs */
-	[145] = MSM_CPU_8226,
-	[158] = MSM_CPU_8226,
-	[159] = MSM_CPU_8226,
-	[198] = MSM_CPU_8226,
-	[199] = MSM_CPU_8226,
-	[200] = MSM_CPU_8226,
-	[205] = MSM_CPU_8226,
-	[219] = MSM_CPU_8226,
-	[220] = MSM_CPU_8226,
-	[221] = MSM_CPU_8226,
-	[222] = MSM_CPU_8226,
-	[223] = MSM_CPU_8226,
-	[224] = MSM_CPU_8226,
+	[145] = {MSM_CPU_8226, "MSM8626"},
+	[158] = {MSM_CPU_8226, "MSM8226"},
+	[159] = {MSM_CPU_8226, "MSM8526"},
+	[198] = {MSM_CPU_8226, "MSM8126"},
+	[199] = {MSM_CPU_8226, "APQ8026"},
+	[200] = {MSM_CPU_8226, "MSM8926"},
+	[205] = {MSM_CPU_8226, "MSM8326"},
+	[219] = {MSM_CPU_8226, "APQ8028"},
+	[220] = {MSM_CPU_8226, "MSM8128"},
+	[221] = {MSM_CPU_8226, "MSM8228"},
+	[222] = {MSM_CPU_8226, "MSM8528"},
+	[223] = {MSM_CPU_8226, "MSM8628"},
+	[224] = {MSM_CPU_8226, "MSM8928"},
 
 	/* 8092 IDs */
-	[146] = MSM_CPU_8092,
+	[146] = {MSM_CPU_8092, "MSM8092"},
 
 	/* 8610 IDs */
-	[147] = MSM_CPU_8610,
-	[161] = MSM_CPU_8610,
-	[162] = MSM_CPU_8610,
-	[163] = MSM_CPU_8610,
-	[164] = MSM_CPU_8610,
-	[165] = MSM_CPU_8610,
-	[166] = MSM_CPU_8610,
-	[225] = MSM_CPU_8610,
-	[226] = MSM_CPU_8610,
+	[147] = {MSM_CPU_8610, "MSM8610"},
+	[161] = {MSM_CPU_8610, "MSM8110"},
+	[162] = {MSM_CPU_8610, "MSM8210"},
+	[163] = {MSM_CPU_8610, "MSM8810"},
+	[164] = {MSM_CPU_8610, "MSM8212"},
+	[165] = {MSM_CPU_8610, "MSM8612"},
+	[166] = {MSM_CPU_8610, "MSM8112"},
+	[225] = {MSM_CPU_8610, "MSM8510"},
+	[226] = {MSM_CPU_8610, "MSM8512"},
 
 	/* 8064AB IDs */
-	[153] = MSM_CPU_8064AB,
+	[153] = {MSM_CPU_8064AB, "APQ8064AB"},
 
 	/* 8930AB IDs */
-	[154] = MSM_CPU_8930AB,
-	[155] = MSM_CPU_8930AB,
-	[156] = MSM_CPU_8930AB,
-	[157] = MSM_CPU_8930AB,
-	[181] = MSM_CPU_8930AB,
+	[154] = {MSM_CPU_8930AB, "MSM8930AB"},
+	[155] = {MSM_CPU_8930AB, "MSM8930AB"},
+	[156] = {MSM_CPU_8930AB, "MSM8930AB"},
+	[157] = {MSM_CPU_8930AB, "MSM8930AB"},
+	[181] = {MSM_CPU_8930AB, "MSM8930AB"},
 
 	/* 8625Q IDs */
-	[168] = MSM_CPU_8625Q,
-	[169] = MSM_CPU_8625Q,
-	[170] = MSM_CPU_8625Q,
+	[168] = {MSM_CPU_8625Q, "MSM8225Q"},
+	[169] = {MSM_CPU_8625Q, "MSM8625Q"},
+	[170] = {MSM_CPU_8625Q, "MSM8125Q"},
 
 	/* 8064AA IDs */
-	[172] = MSM_CPU_8064AA,
+	[172] = {MSM_CPU_8064AA, "APQ8064AA"},
 
 	/* 8084 IDs */
-	[178] = MSM_CPU_8084,
+	[178] = {MSM_CPU_8084, "APQ8084"},
 
 	/* krypton IDs */
-	[187] = MSM_CPU_KRYPTON,
+	[187] = {MSM_CPU_KRYPTON, "MSMKRYPTON"},
 
 	/* FSM9900 ID */
-	[188] = FSM_CPU_9900,
+	[188] = {FSM_CPU_9900, "FSM9900"},
 
 	/* Samarium IDs */
-	[195] = MSM_CPU_SAMARIUM,
+	[195] = {MSM_CPU_SAMARIUM, "MSMSAMARIUM"},
 
 	/* Uninitialized IDs are not known to run Linux.
 	   MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
@@ -455,6 +458,25 @@
 	return (socinfo) ? socinfo->v1.build_id : NULL;
 }
 
+static char *msm_read_hardware_id(void)
+{
+	static char msm_soc_str[128] = "Qualcomm ";
+	static bool string_generated = false;
+
+	if (string_generated)
+		return msm_soc_str;
+	if (!socinfo)
+		goto err_path;
+	if (!cpu_of_id[socinfo->v1.id].soc_id_string)
+		goto err_path;
+
+	string_generated = true;
+	return strncat(msm_soc_str, cpu_of_id[socinfo->v1.id].soc_id_string,
+			sizeof(msm_soc_str) - strlen(msm_soc_str));
+err_path:
+	return "UNKNOWN SOC TYPE";
+}
+
 uint32_t socinfo_get_raw_id(void)
 {
 	return socinfo ?
@@ -1437,14 +1459,16 @@
 	}
 
 	WARN(!socinfo_get_id(), "Unknown SOC ID!\n");
-	WARN(socinfo_get_id() >= ARRAY_SIZE(cpu_of_id),
-		"New IDs added! ID => CPU mapping might need an update.\n");
 
-	if (socinfo->v1.id < ARRAY_SIZE(cpu_of_id))
-		cur_cpu = cpu_of_id[socinfo->v1.id];
+	if (socinfo_get_id() >= ARRAY_SIZE(cpu_of_id))
+		BUG_ON("New IDs added! ID => CPU mapping might need an update.\n");
+
+	else
+		cur_cpu = cpu_of_id[socinfo->v1.id].generic_soc_type;
 
 	boot_stats_init();
 	socinfo_print();
+	arch_read_hardware_id = msm_read_hardware_id;
 
 	return 0;
 }
diff --git a/drivers/gpu/ion/ion_cma_secure_heap.c b/drivers/gpu/ion/ion_cma_secure_heap.c
index d375c00..0aef596 100644
--- a/drivers/gpu/ion/ion_cma_secure_heap.c
+++ b/drivers/gpu/ion/ion_cma_secure_heap.c
@@ -446,6 +446,7 @@
 	if (ret) {
 		ret = ion_secure_cma_add_to_pool(sheap, len);
 		if (ret) {
+			mutex_unlock(&sheap->alloc_lock);
 			dev_err(sheap->dev, "Fail to allocate buffer\n");
 			goto err;
 		}
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index 2af8d27..e87c670 100755
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -514,6 +514,9 @@
 	else
 		/* something went wrong with the event handling mechanism */
 		BUG_ON(1);
+
+	/* Free param we are done using it */
+	kfree(param);
 }
 
 /*
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index 7b39645e..eba5ca8 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -710,7 +710,6 @@
 			}
 		}
 		if (led->mpp_cfg->pwm_mode == PWM_MODE) {
-			pwm_disable(led->mpp_cfg->pwm_cfg->pwm_dev);
 			/*config pwm for brightness scaling*/
 			period_us = led->mpp_cfg->pwm_cfg->pwm_period_us;
 			if (period_us > INT_MAX / NSEC_PER_USEC) {
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index eaa5beb..008407d 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -2053,6 +2053,10 @@
 
 	new_session = (struct hal_session *)
 		kzalloc(sizeof(struct hal_session), GFP_KERNEL);
+	if (!new_session) {
+		dprintk(VIDC_ERR, "new session fail: Out of memory\n");
+		return NULL;
+	}
 	new_session->session_id = (u32) session_id;
 	if (session_type == 1)
 		new_session->is_decoder = 0;
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index 9b00b4b..a3e88b4 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -146,6 +146,20 @@
 #define MSM_PRONTO_PLL_BASE				0xfb21b1c0
 #define PRONTO_PLL_STATUS_OFFSET		0x1c
 
+#define MSM_PRONTO_MCU_BASE			0xfb080c00
+#define MCU_CBR_CCAHB_ERR_OFFSET		0x380
+#define MCU_CBR_CAHB_ERR_OFFSET			0x384
+#define MCU_CBR_CCAHB_TIMEOUT_OFFSET		0x388
+#define MCU_CBR_CAHB_TIMEOUT_OFFSET		0x38c
+#define MCU_DBR_CDAHB_ERR_OFFSET		0x390
+#define MCU_DBR_DAHB_ERR_OFFSET			0x394
+#define MCU_DBR_CDAHB_TIMEOUT_OFFSET		0x398
+#define MCU_DBR_DAHB_TIMEOUT_OFFSET		0x39c
+#define MCU_FDBR_CDAHB_ERR_OFFSET		0x3a0
+#define MCU_FDBR_FDAHB_ERR_OFFSET		0x3a4
+#define MCU_FDBR_CDAHB_TIMEOUT_OFFSET		0x3a8
+#define MCU_FDBR_FDAHB_TIMEOUT_OFFSET		0x3ac
+
 #define MSM_PRONTO_TXP_STATUS           0xfb08040c
 #define MSM_PRONTO_TXP_PHY_ABORT        0xfb080488
 #define MSM_PRONTO_BRDG_ERR_SRC         0xfb080fb0
@@ -363,6 +377,7 @@
 	void __iomem *pronto_ccpu_base;
 	void __iomem *pronto_saw2_base;
 	void __iomem *pronto_pll_base;
+	void __iomem *pronto_mcu_base;
 	void __iomem *wlan_tx_status;
 	void __iomem *wlan_tx_phy_aborts;
 	void __iomem *wlan_brdg_err_source;
@@ -565,35 +580,31 @@
 
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_SPARE_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s:  PRONTO_PMU_SPARE %08x\n", __func__, reg);
+	pr_err("PRONTO_PMU_SPARE %08x\n", reg);
 
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_CPU_CBCR_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s:  PRONTO_PMU_COM_CPU_CBCR %08x\n",
-						__func__, reg);
+	pr_err("PRONTO_PMU_COM_CPU_CBCR %08x\n", reg);
 
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_AHB_CBCR_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s:  PRONTO_PMU_COM_AHB_CBCR %08x\n",
-						__func__, reg);
+	pr_err("PRONTO_PMU_COM_AHB_CBCR %08x\n", reg);
 
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_CFG_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s:  PRONTO_PMU_CFG %08x\n", __func__, reg);
+	pr_err("PRONTO_PMU_CFG %08x\n", reg);
 
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_CSR_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s:  PRONTO_PMU_COM_CSR %08x\n",
-						__func__, reg);
+	pr_err("PRONTO_PMU_COM_CSR %08x\n", reg);
 
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_SOFT_RESET_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s:  PRONTO_PMU_SOFT_RESET %08x\n",
-						__func__, reg);
+	pr_err("PRONTO_PMU_SOFT_RESET %08x\n", reg);
 
 	reg_addr = penv->pronto_saw2_base + PRONTO_SAW2_SPM_STS_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s: PRONTO_SAW2_SPM_STS %08x\n", __func__, reg);
+	pr_err("PRONTO_SAW2_SPM_STS %08x\n", reg);
 
 	reg_addr = penv->pronto_pll_base + PRONTO_PLL_STATUS_OFFSET;
 	reg = readl_relaxed(reg_addr);
@@ -605,13 +616,11 @@
 
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_GDSCR_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s:  PRONTO_PMU_COM_GDSCR %08x\n",
-						__func__, reg);
+	pr_err("PRONTO_PMU_COM_GDSCR %08x\n", reg);
 	reg >>= 31;
 
 	if (!reg) {
-		pr_info_ratelimited("%s:  Cannot log, Pronto common SS is power collapsed\n",
-				__func__);
+		pr_err("Cannot log, Pronto common SS is power collapsed\n");
 		return;
 	}
 	reg &= ~(PRONTO_PMU_COM_GDSCR_SW_COLLAPSE
@@ -625,31 +634,31 @@
 
 	reg_addr = penv->pronto_a2xb_base + A2XB_CFG_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s: A2XB_CFG_OFFSET %08x\n", __func__, reg);
+	pr_err("A2XB_CFG_OFFSET %08x\n", reg);
 
 	reg_addr = penv->pronto_a2xb_base + A2XB_INT_SRC_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s: A2XB_INT_SRC_OFFSET %08x\n", __func__, reg);
+	pr_err("A2XB_INT_SRC_OFFSET %08x\n", reg);
 
 	reg_addr = penv->pronto_a2xb_base + A2XB_ERR_INFO_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s: A2XB_ERR_INFO_OFFSET %08x\n", __func__, reg);
+	pr_err("A2XB_ERR_INFO_OFFSET %08x\n", reg);
 
 	reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_INVALID_ADDR_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s: CCU_CCPU_INVALID_ADDR %08x\n", __func__, reg);
+	pr_err("CCU_CCPU_INVALID_ADDR %08x\n", reg);
 
 	reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_LAST_ADDR0_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR0 %08x\n", __func__, reg);
+	pr_err("CCU_CCPU_LAST_ADDR0 %08x\n", reg);
 
 	reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_LAST_ADDR1_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR1 %08x\n", __func__, reg);
+	pr_err("CCU_CCPU_LAST_ADDR1 %08x\n", reg);
 
 	reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_LAST_ADDR2_OFFSET;
 	reg = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR2 %08x\n", __func__, reg);
+	pr_err("CCU_CCPU_LAST_ADDR2 %08x\n", reg);
 
 	tst_addr = penv->pronto_a2xb_base + A2XB_TSTBUS_OFFSET;
 	tst_ctrl_addr = penv->pronto_a2xb_base + A2XB_TSTBUS_CTRL_OFFSET;
@@ -659,24 +668,21 @@
 	reg = reg | WCNSS_TSTBUS_CTRL_EN | WCNSS_TSTBUS_CTRL_RDFIFO;
 	writel_relaxed(reg, tst_ctrl_addr);
 	reg = readl_relaxed(tst_addr);
-	pr_info_ratelimited("%s:  Read data FIFO testbus %08x\n",
-					__func__, reg);
+	pr_err("Read data FIFO testbus %08x\n", reg);
 
 	/*  command FIFO */
 	reg = 0;
 	reg = reg | WCNSS_TSTBUS_CTRL_EN | WCNSS_TSTBUS_CTRL_CMDFIFO;
 	writel_relaxed(reg, tst_ctrl_addr);
 	reg = readl_relaxed(tst_addr);
-	pr_info_ratelimited("%s:  Command FIFO testbus %08x\n",
-					__func__, reg);
+	pr_err("Command FIFO testbus %08x\n", reg);
 
 	/*  write data FIFO */
 	reg = 0;
 	reg = reg | WCNSS_TSTBUS_CTRL_EN | WCNSS_TSTBUS_CTRL_WRFIFO;
 	writel_relaxed(reg, tst_ctrl_addr);
 	reg = readl_relaxed(tst_addr);
-	pr_info_ratelimited("%s:  Rrite data FIFO testbus %08x\n",
-					__func__, reg);
+	pr_err("Rrite data FIFO testbus %08x\n", reg);
 
 	/*   AXIM SEL CFG0 */
 	reg = 0;
@@ -684,8 +690,7 @@
 				WCNSS_TSTBUS_CTRL_AXIM_CFG0;
 	writel_relaxed(reg, tst_ctrl_addr);
 	reg = readl_relaxed(tst_addr);
-	pr_info_ratelimited("%s:  AXIM SEL CFG0 testbus %08x\n",
-					__func__, reg);
+	pr_err("AXIM SEL CFG0 testbus %08x\n", reg);
 
 	/*   AXIM SEL CFG1 */
 	reg = 0;
@@ -693,8 +698,7 @@
 				WCNSS_TSTBUS_CTRL_AXIM_CFG1;
 	writel_relaxed(reg, tst_ctrl_addr);
 	reg = readl_relaxed(tst_addr);
-	pr_info_ratelimited("%s:  AXIM SEL CFG1 testbus %08x\n",
-					__func__, reg);
+	pr_err("AXIM SEL CFG1 testbus %08x\n", reg);
 
 	/*   CTRL SEL CFG0 */
 	reg = 0;
@@ -702,8 +706,7 @@
 		WCNSS_TSTBUS_CTRL_CTRL_CFG0;
 	writel_relaxed(reg, tst_ctrl_addr);
 	reg = readl_relaxed(tst_addr);
-	pr_info_ratelimited("%s:  CTRL SEL CFG0 testbus %08x\n",
-					__func__, reg);
+	pr_err("CTRL SEL CFG0 testbus %08x\n", reg);
 
 	/*   CTRL SEL CFG1 */
 	reg = 0;
@@ -711,7 +714,7 @@
 		WCNSS_TSTBUS_CTRL_CTRL_CFG1;
 	writel_relaxed(reg, tst_ctrl_addr);
 	reg = readl_relaxed(tst_addr);
-	pr_info_ratelimited("%s:  CTRL SEL CFG1 testbus %08x\n", __func__, reg);
+	pr_err("CTRL SEL CFG1 testbus %08x\n", reg);
 
 
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_WLAN_BCR_OFFSET;
@@ -722,26 +725,75 @@
 
 	reg_addr = penv->msm_wcnss_base + PRONTO_PMU_WLAN_AHB_CBCR_OFFSET;
 	reg3 = readl_relaxed(reg_addr);
-	pr_info_ratelimited("%s:  PMU_WLAN_AHB_CBCR %08x\n", __func__, reg3);
+	pr_err("PMU_WLAN_AHB_CBCR %08x\n", reg3);
 
 	if ((reg & PRONTO_PMU_WLAN_BCR_BLK_ARES) ||
 		(reg2 & PRONTO_PMU_WLAN_GDSCR_SW_COLLAPSE) ||
 		(!(reg4 & PRONTO_PMU_CPU_AHB_CMD_RCGR_ROOT_EN)) ||
 		(reg3 & PRONTO_PMU_WLAN_AHB_CBCR_CLK_OFF) ||
 		(!(reg3 & PRONTO_PMU_WLAN_AHB_CBCR_CLK_EN))) {
-		pr_info_ratelimited("%s:  Cannot log, wlan domain is power collapsed\n",
-				__func__);
+		pr_err("Cannot log, wlan domain is power collapsed\n");
 		return;
 	}
 
+	msleep(50);
+
 	reg = readl_relaxed(penv->wlan_tx_phy_aborts);
-	pr_info_ratelimited("%s: WLAN_TX_PHY_ABORTS %08x\n", __func__, reg);
+	pr_err("WLAN_TX_PHY_ABORTS %08x\n", reg);
+
+	reg_addr = penv->pronto_mcu_base + MCU_CBR_CCAHB_ERR_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_err("MCU_CBR_CCAHB_ERR %08x\n", reg);
+
+	reg_addr = penv->pronto_mcu_base + MCU_CBR_CAHB_ERR_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_err("MCU_CBR_CAHB_ERR %08x\n", reg);
+
+	reg_addr = penv->pronto_mcu_base + MCU_CBR_CCAHB_TIMEOUT_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_err("MCU_CBR_CCAHB_TIMEOUT %08x\n", reg);
+
+	reg_addr = penv->pronto_mcu_base + MCU_CBR_CAHB_TIMEOUT_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_err("MCU_CBR_CAHB_TIMEOUT %08x\n", reg);
+
+	reg_addr = penv->pronto_mcu_base + MCU_DBR_CDAHB_ERR_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_err("MCU_DBR_CDAHB_ERR %08x\n", reg);
+
+	reg_addr = penv->pronto_mcu_base + MCU_DBR_DAHB_ERR_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_err("MCU_DBR_DAHB_ERR %08x\n", reg);
+
+	reg_addr = penv->pronto_mcu_base + MCU_DBR_CDAHB_TIMEOUT_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_err("MCU_DBR_CDAHB_TIMEOUT %08x\n", reg);
+
+	reg_addr = penv->pronto_mcu_base + MCU_DBR_DAHB_TIMEOUT_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_err("MCU_DBR_DAHB_TIMEOUT %08x\n", reg);
+
+	reg_addr = penv->pronto_mcu_base + MCU_FDBR_CDAHB_ERR_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_err("MCU_FDBR_CDAHB_ERR %08x\n", reg);
+
+	reg_addr = penv->pronto_mcu_base + MCU_FDBR_FDAHB_ERR_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_err("MCU_FDBR_FDAHB_ERR %08x\n", reg);
+
+	reg_addr = penv->pronto_mcu_base + MCU_FDBR_CDAHB_TIMEOUT_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_err("MCU_FDBR_CDAHB_TIMEOUT %08x\n", reg);
+
+	reg_addr = penv->pronto_mcu_base + MCU_FDBR_FDAHB_TIMEOUT_OFFSET;
+	reg = readl_relaxed(reg_addr);
+	pr_err("MCU_FDBR_FDAHB_TIMEOUT %08x\n", reg);
 
 	reg = readl_relaxed(penv->wlan_brdg_err_source);
-	pr_info_ratelimited("%s: WLAN_BRDG_ERR_SOURCE %08x\n", __func__, reg);
+	pr_err("WLAN_BRDG_ERR_SOURCE %08x\n", reg);
 
 	reg = readl_relaxed(penv->wlan_tx_status);
-	pr_info_ratelimited("%s: WLAN_TX_STATUS %08x\n", __func__, reg);
+	pr_err("WLAN_TXP_STATUS %08x\n", reg);
 
 	reg = readl_relaxed(penv->alarms_txctl);
 	pr_err("ALARMS_TXCTL %08x\n", reg);
@@ -2253,6 +2305,13 @@
 			pr_err("%s: ioremap alarms TACTL failed\n", __func__);
 			goto fail_ioremap11;
 		}
+		penv->pronto_mcu_base = ioremap(MSM_PRONTO_MCU_BASE, SZ_1K);
+		if (!penv->pronto_mcu_base) {
+			ret = -ENOMEM;
+			pr_err("%s: ioremap wcnss physical(mcu) failed\n",
+				__func__);
+			goto fail_ioremap12;
+		}
 	}
 	penv->adc_tm_dev = qpnp_get_adc_tm(&penv->pdev->dev, "wcnss");
 	if (IS_ERR(penv->adc_tm_dev)) {
@@ -2283,6 +2342,9 @@
 fail_pil:
 	if (penv->riva_ccu_base)
 		iounmap(penv->riva_ccu_base);
+	if (penv->pronto_mcu_base)
+		iounmap(penv->pronto_mcu_base);
+fail_ioremap12:
 	if (penv->alarms_tactl)
 		iounmap(penv->alarms_tactl);
 fail_ioremap11:
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 2003b69..82c61c9 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -2418,8 +2418,13 @@
 	}
 	mutex_unlock(&chip->soc_invalidation_mutex);
 
-	pr_debug("SOC before adjustment = %d\n", soc);
-	new_calculated_soc = adjust_soc(chip, &params, soc, batt_temp);
+	if (chip->first_time_calc_soc && !chip->shutdown_soc_invalid) {
+		pr_debug("Skip adjustment when shutdown SOC has been forced\n");
+		new_calculated_soc = soc;
+	} else {
+		pr_debug("SOC before adjustment = %d\n", soc);
+		new_calculated_soc = adjust_soc(chip, &params, soc, batt_temp);
+	}
 
 	/* always clamp soc due to BMS hw/sw immaturities */
 	new_calculated_soc = clamp_soc_based_on_voltage(chip,
diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c
index 0f8f1dd..496b31d 100644
--- a/drivers/slimbus/slim-msm-ngd.c
+++ b/drivers/slimbus/slim-msm-ngd.c
@@ -27,7 +27,6 @@
 #include <linux/timer.h>
 #include <mach/sps.h>
 #include "slim-msm.h"
-#include <mach/qdsp6v2/apr.h>
 
 #define NGD_SLIM_NAME	"ngd_msm_ctrl"
 #define SLIM_LA_MGR	0xFF
@@ -857,7 +856,7 @@
 					prev_state);
 			/* ADSP SSR, send device_up notifications */
 			if (prev_state == MSM_CTRL_DOWN)
-				schedule_work(&dev->slave_notify);
+				complete(&dev->qmi.slave_notify);
 		} else if (ret == -EIO) {
 			pr_info("capability message NACKed, retrying");
 			if (retries < INIT_MX_RETRIES) {
@@ -1108,31 +1107,54 @@
 	return 0;
 }
 
-static void ngd_laddr_lookup(struct work_struct *work)
+static int ngd_notify_slaves(void *data)
 {
-	struct msm_slim_ctrl *dev =
-		container_of(work, struct msm_slim_ctrl, slave_notify);
+	struct msm_slim_ctrl *dev = (struct msm_slim_ctrl *)data;
 	struct slim_controller *ctrl = &dev->ctrl;
 	struct slim_device *sbdev;
 	struct list_head *pos, *next;
-	int i;
-	slim_framer_booted(ctrl);
-	mutex_lock(&ctrl->m_ctrl);
-	list_for_each_safe(pos, next, &ctrl->devs) {
-		int ret = 0;
-		sbdev = list_entry(pos, struct slim_device, dev_list);
-		mutex_unlock(&ctrl->m_ctrl);
-		for (i = 0; i < LADDR_RETRY; i++) {
-			ret = slim_get_logical_addr(sbdev, sbdev->e_addr,
-					6, &sbdev->laddr);
-			if (!ret)
-				break;
-			else /* time for ADSP to assign LA */
-				msleep(20);
+	int ret, i = 0;
+	while (!kthread_should_stop()) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		ret = wait_for_completion_timeout(&dev->qmi.slave_notify,
+								HZ);
+		if (!ret) {
+			dev_err(dev->dev, "slave thread wait err:%d", ret);
+			continue;
 		}
+		/* Probe devices for first notification */
+		if (!i) {
+			dev->err = 0;
+			if (dev->dev->of_node)
+				of_register_slim_devices(&dev->ctrl);
+
+			/*
+			 * Add devices registered with board-info now that
+			 * controller is up
+			 */
+			slim_ctrl_add_boarddevs(&dev->ctrl);
+		} else {
+			slim_framer_booted(ctrl);
+		}
+		i++;
 		mutex_lock(&ctrl->m_ctrl);
+		list_for_each_safe(pos, next, &ctrl->devs) {
+			sbdev = list_entry(pos, struct slim_device, dev_list);
+			mutex_unlock(&ctrl->m_ctrl);
+			for (i = 0; i < LADDR_RETRY; i++) {
+				ret = slim_get_logical_addr(sbdev,
+						sbdev->e_addr,
+						6, &sbdev->laddr);
+				if (!ret)
+					break;
+				else /* time for ADSP to assign LA */
+					msleep(20);
+			}
+			mutex_lock(&ctrl->m_ctrl);
+		}
+		mutex_unlock(&ctrl->m_ctrl);
 	}
-	mutex_unlock(&ctrl->m_ctrl);
+	return 0;
 }
 
 static void ngd_adsp_down(struct work_struct *work)
@@ -1173,18 +1195,9 @@
 	struct resource		*bam_mem;
 	struct resource		*slim_mem;
 	struct resource		*irq, *bam_irq;
-	enum apr_subsys_state q6_state;
 	bool			rxreg_access = false;
 	bool			slim_mdm = false;
 
-	q6_state = apr_get_q6_state();
-	if (q6_state == APR_SUBSYS_DOWN) {
-		dev_dbg(&pdev->dev, "defering %s, adsp_state %d\n", __func__,
-			q6_state);
-		return -EPROBE_DEFER;
-	} else
-		dev_dbg(&pdev->dev, "adsp is ready\n");
-
 	slim_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 						"slimbus_physical");
 	if (!slim_mem) {
@@ -1290,6 +1303,7 @@
 	dev->use_tx_msgqs = MSM_MSGQ_RESET;
 
 	init_completion(&dev->rx_msgq_notify);
+	init_completion(&dev->qmi.slave_notify);
 
 	/* Register with framework */
 	ret = slim_add_numbered_controller(&dev->ctrl);
@@ -1311,6 +1325,7 @@
 	}
 
 	init_completion(&dev->qmi.qmi_comp);
+	dev->err = -EPROBE_DEFER;
 	pm_runtime_use_autosuspend(dev->dev);
 	pm_runtime_set_autosuspend_delay(dev->dev, MSM_SLIM_AUTOSUSPEND);
 	pm_runtime_set_suspended(dev->dev);
@@ -1326,7 +1341,6 @@
 				dev->mdm.ssr);
 	}
 
-	INIT_WORK(&dev->slave_notify, ngd_laddr_lookup);
 	INIT_WORK(&dev->qmi.ssr_down, ngd_adsp_down);
 	INIT_WORK(&dev->qmi.ssr_up, ngd_adsp_up);
 	dev->qmi.nb.notifier_call = ngd_qmi_available;
@@ -1342,23 +1356,27 @@
 
 	/* Fire up the Rx message queue thread */
 	dev->rx_msgq_thread = kthread_run(ngd_slim_rx_msgq_thread, dev,
-					NGD_SLIM_NAME "_ngd_msgq_thread");
+					"ngd_rx_thread%d", dev->ctrl.nr);
 	if (IS_ERR(dev->rx_msgq_thread)) {
 		ret = PTR_ERR(dev->rx_msgq_thread);
-		dev_err(dev->dev, "Failed to start Rx message queue thread\n");
-		goto err_thread_create_failed;
+		dev_err(dev->dev, "Failed to start Rx thread:%d\n", ret);
+		goto err_rx_thread_create_failed;
 	}
 
-	if (pdev->dev.of_node)
-		of_register_slim_devices(&dev->ctrl);
-
-	/* Add devices registered with board-info now that controller is up */
-	slim_ctrl_add_boarddevs(&dev->ctrl);
-
+	/* Start thread to probe, and notify slaves */
+	dev->qmi.slave_thread = kthread_run(ngd_notify_slaves, dev,
+					"ngd_notify_sl%d", dev->ctrl.nr);
+	if (IS_ERR(dev->qmi.slave_thread)) {
+		ret = PTR_ERR(dev->qmi.slave_thread);
+		dev_err(dev->dev, "Failed to start notifier thread:%d\n", ret);
+		goto err_notify_thread_create_failed;
+	}
 	dev_dbg(dev->dev, "NGD SB controller is up!\n");
 	return 0;
 
-err_thread_create_failed:
+err_notify_thread_create_failed:
+	kthread_stop(dev->rx_msgq_thread);
+err_rx_thread_create_failed:
 	qmi_svc_event_notifier_unregister(SLIMBUS_QMI_SVC_ID,
 				SLIMBUS_QMI_SVC_V1,
 				SLIMBUS_QMI_INS_ID, &dev->qmi.nb);
diff --git a/drivers/slimbus/slim-msm.h b/drivers/slimbus/slim-msm.h
index 2327b38..63178cc 100644
--- a/drivers/slimbus/slim-msm.h
+++ b/drivers/slimbus/slim-msm.h
@@ -203,6 +203,8 @@
 struct msm_slim_qmi {
 	struct qmi_handle		*handle;
 	struct task_struct		*task;
+	struct task_struct		*slave_thread;
+	struct completion		slave_notify;
 	struct kthread_work		kwork;
 	struct kthread_worker		kworker;
 	struct completion		qmi_comp;
@@ -261,7 +263,6 @@
 	struct completion	ctrl_up;
 	int			nsats;
 	u32			ver;
-	struct work_struct	slave_notify;
 	struct msm_slim_qmi	qmi;
 	struct msm_slim_pdata	pdata;
 	struct msm_slim_mdm	mdm;
diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c
index 7ca247a..41ebc1c 100644
--- a/drivers/staging/android/ashmem.c
+++ b/drivers/staging/android/ashmem.c
@@ -365,7 +365,9 @@
 	if (!sc->nr_to_scan)
 		return lru_count;
 
-	mutex_lock(&ashmem_mutex);
+	if (!mutex_trylock(&ashmem_mutex))
+		return -1;
+
 	list_for_each_entry_safe(range, next, &ashmem_lru_list, lru) {
 		struct inode *inode = range->asma->file->f_dentry->d_inode;
 		loff_t start = range->pgstart * PAGE_SIZE;
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index b1ec3fc..2a66c4c 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -28,6 +28,7 @@
 obj-$(CONFIG_USB_IMX21_HCD)	+= host/
 obj-$(CONFIG_USB_FSL_MPH_DR_OF)	+= host/
 obj-$(CONFIG_USB_PEHCI_HCD)	+= host/
+obj-$(CONFIG_USB_ICE40_HCD)	+= host/
 
 obj-$(CONFIG_USB_C67X00_HCD)	+= c67x00/
 
@@ -37,6 +38,7 @@
 obj-$(CONFIG_USB_PRINTER)	+= class/
 obj-$(CONFIG_USB_WDM)		+= class/
 obj-$(CONFIG_USB_TMC)		+= class/
+obj-$(CONFIG_USB_CCID_BRIDGE)	+= class/
 
 obj-$(CONFIG_USB_STORAGE)	+= storage/
 obj-$(CONFIG_USB)		+= storage/
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 4357867..2a24bec 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -693,3 +693,16 @@
 config USB_OCTEON2_COMMON
 	bool
 	default y if USB_OCTEON_EHCI || USB_OCTEON_OHCI
+
+config USB_ICE40_HCD
+	tristate "ICE40 FPGA based SPI to Inter-Chip USB host controller"
+	depends on USB && SPI
+	help
+	  A driver for ICE40 FPGA based SPI to Inter-Chip USB host
+	  controller. This driver registers as a SPI protocol driver
+	  and interacts with the SPI subsystem on one side and interacts
+	  with the USB core on the other side. Control and Bulk transfers
+	  are supported.
+
+	  To compile this driver a module, choose M here: the module
+	  will be called "ice40-hcd".
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 7d35f5b..7c5b452 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -42,3 +42,4 @@
 obj-$(CONFIG_USB_FSL_MPH_DR_OF)	+= fsl-mph-dr-of.o
 obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o
 obj-$(CONFIG_MIPS_ALCHEMY)	+= alchemy-common.o
+obj-$(CONFIG_USB_ICE40_HCD)	+= ice40-hcd.o
diff --git a/drivers/usb/host/ice40-hcd.c b/drivers/usb/host/ice40-hcd.c
new file mode 100644
index 0000000..4d62a3e
--- /dev/null
+++ b/drivers/usb/host/ice40-hcd.c
@@ -0,0 +1,2092 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2001-2004 by David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ *
+ */
+
+/*
+ * Root HUB management and Asynchronous scheduling traversal
+ * Based on ehci-hub.c and ehci-q.c
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/ktime.h>
+#include <linux/uaccess.h>
+#include <linux/debugfs.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/spinlock.h>
+#include <linux/firmware.h>
+#include <linux/spi/spi.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/ch11.h>
+
+#include <asm/unaligned.h>
+#include <mach/gpiomux.h>
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/ice40.h>
+
+#define FADDR_REG 0x00 /* R/W: Device address */
+#define HCMD_REG 0x01 /* R/W: Host transfer command */
+#define XFRST_REG 0x02 /* R: Transfer status */
+#define IRQ_REG 0x03 /* R/C: IRQ status */
+#define IEN_REG 0x04 /* R/W: IRQ enable */
+#define CTRL0_REG 0x05 /* R/W: Host control command */
+#define CTRL1_REG 0x06 /* R/W: Host control command */
+#define WBUF0_REG 0x10 /* W: Tx fifo 0 */
+#define WBUF1_REG 0x11 /* W: Tx fifo 1 */
+#define SUBUF_REG 0x12 /* W: SETUP fifo */
+#define WBLEN_REG 0x13 /* W: Tx fifo size */
+#define RBUF0_REG 0x18 /* R: Rx fifo 0 */
+#define RBUF1_REG 0x19 /* R: Rx fifo 1 */
+#define RBLEN_REG 0x1B /* R: Rx fifo size */
+
+#define WRITE_CMD(addr) ((addr << 3) | 1)
+#define READ_CMD(addr) ((addr << 3) | 0)
+
+/* Host controller command register definitions */
+#define HCMD_EP(ep) (ep & 0xF)
+#define HCMD_BSEL(sel) (sel << 4)
+#define HCMD_TOGV(toggle) (toggle << 5)
+#define HCMD_PT(token) (token << 6)
+
+/* Transfer status register definitions */
+#define XFR_MASK(xfr) (xfr & 0xF)
+#define XFR_SUCCESS 0x0
+#define XFR_BUSY 0x1
+#define XFR_PKTERR 0x2
+#define XFR_PIDERR 0x3
+#define XFR_NAK 0x4
+#define XFR_STALL 0x5
+#define XFR_WRONGPID 0x6
+#define XFR_CRCERR 0x7
+#define XFR_TOGERR 0x8
+#define XFR_BADLEN 0x9
+#define XFR_TIMEOUT 0xA
+
+#define LINE_STATE(xfr) ((xfr & 0x30) >> 4) /* D+, D- */
+#define DPST	BIT(5)
+#define DMST	BIT(4)
+#define PLLOK	BIT(6)
+#define R64B	BIT(7)
+
+/* Interrupt enable/status register definitions */
+#define RESET_IRQ BIT(0)
+#define RESUME_IRQ BIT(1)
+#define SUSP_IRQ BIT(3)
+#define DISCONNECT_IRQ BIT(4)
+#define CONNECT_IRQ BIT(5)
+#define FRAME_IRQ BIT(6)
+#define XFR_IRQ BIT(7)
+
+/* Control 0 register definitions */
+#define RESET_CTRL BIT(0)
+#define FRAME_RESET_CTRL BIT(1)
+#define DET_BUS_CTRL BIT(2)
+#define RESUME_CTRL BIT(3)
+#define SOFEN_CTRL BIT(4)
+#define DM_PD_CTRL BIT(6)
+#define DP_PD_CTRL BIT(7)
+#define HRST_CTRL  BIT(5)
+
+/* Control 1 register definitions */
+#define INT_EN_CTRL BIT(0)
+
+enum ice40_xfr_type {
+	FIRMWARE_XFR,
+	REG_WRITE_XFR,
+	REG_READ_XFR,
+	SETUP_XFR,
+	DATA_IN_XFR,
+	DATA_OUT_XFR,
+};
+
+enum ice40_ep_phase {
+	SETUP_PHASE = 1,
+	DATA_PHASE,
+	STATUS_PHASE,
+};
+
+struct ice40_ep {
+	u8 xcat_err;
+	bool unlinking;
+	bool halted;
+	struct usb_host_endpoint *ep;
+	struct list_head ep_list;
+};
+
+struct ice40_hcd {
+	spinlock_t lock;
+
+	struct mutex wlock;
+	struct mutex rlock;
+
+	u8 devnum;
+	u32 port_flags;
+	u8 ctrl0;
+	u8 wblen0;
+
+	enum ice40_ep_phase ep0_state;
+	struct usb_hcd *hcd;
+
+	struct list_head async_list;
+	struct workqueue_struct *wq;
+	struct work_struct async_work;
+
+	int reset_gpio;
+	int slave_select_gpio;
+	int config_done_gpio;
+	int vcc_en_gpio;
+	int clk_en_gpio;
+
+	struct regulator *core_vcc;
+	struct regulator *spi_vcc;
+	struct regulator *gpio_vcc;
+	bool powered;
+
+	struct dentry *dbg_root;
+	bool pcd_pending;
+
+	/* SPI stuff later */
+	struct spi_device *spi;
+
+	struct spi_message *fmsg;
+	struct spi_transfer *fmsg_xfr; /* size 1 */
+
+	struct spi_message *wmsg;
+	struct spi_transfer *wmsg_xfr; /* size 1 */
+	u8 *w_tx_buf;
+	u8 *w_rx_buf;
+
+	struct spi_message *rmsg;
+	struct spi_transfer *rmsg_xfr; /* size 1 */
+	u8 *r_tx_buf;
+	u8 *r_rx_buf;
+
+	struct spi_message *setup_msg;
+	struct spi_transfer *setup_xfr; /* size 2 */
+	u8 *setup_buf; /* size 1 for SUBUF */
+
+	struct spi_message *in_msg;
+	struct spi_transfer *in_xfr; /* size 2 */
+	u8 *in_buf; /* size 2 for reading from RBUF0 */
+
+	struct spi_message *out_msg;
+	struct spi_transfer *out_xfr; /* size 2 */
+	u8 *out_buf; /* size 1 for writing WBUF0 */
+};
+
+static char fw_name[16] = "ice40.bin";
+module_param_string(fw, fw_name, sizeof(fw_name), S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(fw, "firmware blob file name");
+
+static bool debugger;
+module_param(debugger, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debugger, "true to use the debug port");
+
+static inline struct ice40_hcd *hcd_to_ihcd(struct usb_hcd *hcd)
+{
+	return *((struct ice40_hcd **) hcd->hcd_priv);
+}
+
+static void ice40_spi_reg_write(struct ice40_hcd *ihcd, u8 val, u8 addr)
+{
+	int ret;
+
+	/*
+	 * Register Write Pattern:
+	 * TX: 1st byte is CMD (register + write), 2nd byte is value
+	 * RX: Ignore
+	 *
+	 * The Mutex is to protect concurrent register writes as
+	 * we have only 1 SPI message struct.
+	 */
+
+	mutex_lock(&ihcd->wlock);
+
+	ihcd->w_tx_buf[0] = WRITE_CMD(addr);
+	ihcd->w_tx_buf[1] = val;
+	ret = spi_sync(ihcd->spi, ihcd->wmsg);
+	if (ret < 0) /* should not happen */
+		pr_err("failed. val = %d addr = %d\n", val, addr);
+
+	trace_ice40_reg_write(addr, val, ihcd->w_tx_buf[0],
+			ihcd->w_tx_buf[1], ret);
+
+	mutex_unlock(&ihcd->wlock);
+}
+
+static int ice40_spi_reg_read(struct ice40_hcd *ihcd, u8 addr)
+{
+	int ret;
+
+	/*
+	 * Register Read Pattern:
+	 * TX: 1st byte is CMD (register + read)
+	 * RX: 1st, 2nd byte Ignore, 3rd byte value.
+	 *
+	 * The Mutex is to protect concurrent register reads as
+	 * we have only 1 SPI message struct.
+	 */
+
+	mutex_lock(&ihcd->rlock);
+
+	ihcd->r_tx_buf[0] = READ_CMD(addr);
+	ret = spi_sync(ihcd->spi, ihcd->rmsg);
+	if (ret < 0)
+		pr_err("failed. addr = %d\n", addr);
+	else
+		ret = ihcd->r_rx_buf[2];
+
+	trace_ice40_reg_read(addr, ihcd->r_tx_buf[0], ret);
+
+	mutex_unlock(&ihcd->rlock);
+
+	return ret;
+}
+
+static int ice40_poll_xfer(struct ice40_hcd *ihcd, int usecs)
+{
+	ktime_t start = ktime_get();
+	u8 val, retry = 0;
+	u8 ret = ~0; /* time out */
+
+again:
+
+	/*
+	 * The SPI transaction may take tens of usec. Use ktime
+	 * based checks rather than loop count.
+	 */
+	do {
+		val = ice40_spi_reg_read(ihcd, XFRST_REG);
+
+		if (XFR_MASK(val) != XFR_BUSY)
+			return val;
+
+	} while (ktime_us_delta(ktime_get(), start) < usecs);
+
+	/*
+	 * The SPI transaction involves a context switch. For any
+	 * reason, if we are scheduled out more than usecs after
+	 * the 1st read, this extra read will help.
+	 */
+	if (!retry) {
+		retry = 1;
+		goto again;
+	}
+
+	return ret;
+}
+
+static int
+ice40_handshake(struct ice40_hcd *ihcd, u8 reg, u8 mask, u8 done, int usecs)
+{
+	ktime_t start = ktime_get();
+	u8 val, retry = 0;
+
+again:
+	do {
+		val = ice40_spi_reg_read(ihcd, reg);
+		val &= mask;
+
+		if (val == done)
+			return 0;
+
+	} while (ktime_us_delta(ktime_get(), start) < usecs);
+
+	if (!retry) {
+		retry = 1;
+		goto again;
+	}
+
+	return -ETIMEDOUT;
+}
+
+
+static const char hcd_name[] = "ice40-hcd";
+
+static int ice40_reset(struct usb_hcd *hcd)
+{
+	struct ice40_hcd *ihcd = hcd_to_ihcd(hcd);
+	u8 ctrl, status;
+	int ret = 0;
+
+	/*
+	 * Program the defualt address 0. The device address is
+	 * re-programmed after SET_ADDRESS in URB handling path.
+	 */
+	ihcd->devnum = 0;
+	ice40_spi_reg_write(ihcd, 0, FADDR_REG);
+
+	ihcd->wblen0 = ~0;
+	/*
+	 * Read the line state. This driver is loaded after the
+	 * UICC card insertion. So the line state should indicate
+	 * that a Full-speed device is connected. Return error
+	 * if there is no device connected.
+	 *
+	 * There can be no device connected during debug. A debugfs
+	 * file is provided to sample the bus line and update the
+	 * port flags accordingly.
+	 */
+
+	if (debugger)
+		goto out;
+
+	ctrl = ice40_spi_reg_read(ihcd, CTRL0_REG);
+	ice40_spi_reg_write(ihcd, ctrl | DET_BUS_CTRL, CTRL0_REG);
+
+	ret = ice40_handshake(ihcd, CTRL0_REG, DET_BUS_CTRL, 0, 5000);
+	if (ret) {
+		pr_err("bus detection failed\n");
+		goto out;
+	}
+
+	status = ice40_spi_reg_read(ihcd, XFRST_REG);
+	pr_debug("line state (D+, D-) is %d\n", LINE_STATE(status));
+
+	if (status & DPST) {
+		pr_debug("Full speed device connected\n");
+		ihcd->port_flags |= USB_PORT_STAT_CONNECTION;
+	} else {
+		pr_err("No device connected\n");
+		ret = -ENODEV;
+	}
+out:
+	return ret;
+}
+
+static int ice40_run(struct usb_hcd *hcd)
+{
+	struct ice40_hcd *ihcd = hcd_to_ihcd(hcd);
+
+	/*
+	 * HCD_FLAG_POLL_RH flag is not set by us. Core will not poll
+	 * for the port status periodically. This uses_new_polling
+	 * flag tells core that this hcd will call usb_hcd_poll_rh_status
+	 * upon port change.
+	 */
+	hcd->uses_new_polling = 1;
+
+	/*
+	 * Cache the ctrl0 register to avoid multiple reads. This register
+	 * is written during reset and resume.
+	 */
+	ihcd->ctrl0 = ice40_spi_reg_read(ihcd, CTRL0_REG);
+	ihcd->ctrl0 |= SOFEN_CTRL;
+	ice40_spi_reg_write(ihcd, ihcd->ctrl0, CTRL0_REG);
+
+	return 0;
+}
+
+static void ice40_stop(struct usb_hcd *hcd)
+{
+	struct ice40_hcd *ihcd = hcd_to_ihcd(hcd);
+
+	cancel_work_sync(&ihcd->async_work);
+}
+
+/*
+ * The _Error looks odd. But very helpful when looking for
+ * any errors in logs.
+ */
+static char __maybe_unused *xfr_status_string(int status)
+{
+	switch (XFR_MASK(status)) {
+	case XFR_SUCCESS:
+		return "Ack";
+	case XFR_BUSY:
+		return "Busy_Error";
+	case XFR_PKTERR:
+		return "Pkt_Error";
+	case XFR_PIDERR:
+		return "PID_Error";
+	case XFR_NAK:
+		return "Nak";
+	case XFR_STALL:
+		return "Stall_Error";
+	case XFR_WRONGPID:
+		return "WrongPID_Error";
+	case XFR_CRCERR:
+		return "CRC_Error";
+	case XFR_TOGERR:
+		return "Togg_Error";
+	case XFR_BADLEN:
+		return "BadLen_Error";
+	case XFR_TIMEOUT:
+		return "Timeout_Error";
+	default:
+		return "Unknown_Error";
+	}
+}
+
+static int ice40_xfer_setup(struct ice40_hcd *ihcd, struct urb *urb)
+{
+	struct usb_host_endpoint *ep = urb->ep;
+	struct ice40_ep *iep = ep->hcpriv;
+	void *buf = urb->setup_packet;
+	int ret, status;
+	u8 cmd;
+
+	/*
+	 * SETUP transaction Handling:
+	 * - copy the setup buffer to SUBUF fifo
+	 * - Program HCMD register to initiate the SETP transaction.
+	 * - poll for completion by reading XFRST register.
+	 * - Interpret the result.
+	 */
+
+	ihcd->setup_buf[0] = WRITE_CMD(SUBUF_REG);
+	ihcd->setup_xfr[1].tx_buf = buf;
+	ihcd->setup_xfr[1].len = sizeof(struct usb_ctrlrequest);
+
+	ret = spi_sync(ihcd->spi, ihcd->setup_msg);
+	if (ret < 0) {
+		pr_err("SPI transfer failed\n");
+		status = ret = -EIO;
+		goto out;
+	}
+
+	cmd = HCMD_PT(2) | HCMD_TOGV(0) | HCMD_BSEL(0) | HCMD_EP(0);
+	ice40_spi_reg_write(ihcd, cmd, HCMD_REG);
+
+	status = ice40_poll_xfer(ihcd, 1000);
+	switch (XFR_MASK(status)) {
+	case XFR_SUCCESS:
+		iep->xcat_err = 0;
+		ret = 0;
+		break;
+	case XFR_NAK: /* Device should not return Nak for SETUP */
+	case XFR_STALL:
+		iep->xcat_err = 0;
+		ret = -EPIPE;
+		break;
+	case XFR_PKTERR:
+	case XFR_PIDERR:
+	case XFR_WRONGPID:
+	case XFR_CRCERR:
+	case XFR_TIMEOUT:
+		if (++iep->xcat_err < 8)
+			ret = -EINPROGRESS;
+		else
+			ret = -EPROTO;
+		break;
+	default:
+		pr_err("transaction timed out\n");
+		ret = -EIO;
+	}
+
+out:
+	trace_ice40_setup(xfr_status_string(status), ret);
+	return ret;
+}
+
+static int ice40_xfer_in(struct ice40_hcd *ihcd, struct urb *urb)
+{
+	struct usb_host_endpoint *ep = urb->ep;
+	struct usb_device *udev = urb->dev;
+	u32 total_len = urb->transfer_buffer_length;
+	u16 maxpacket = usb_endpoint_maxp(&ep->desc);
+	u8 epnum = usb_pipeendpoint(urb->pipe);
+	bool is_out = usb_pipeout(urb->pipe);
+	struct ice40_ep *iep = ep->hcpriv;
+	u8 cmd, status, len = 0, t, expected_len;
+	void *buf;
+	int ret;
+	bool short_packet = true;
+
+	if (epnum == 0 && ihcd->ep0_state == STATUS_PHASE) {
+		expected_len = 0;
+		buf = NULL;
+		t = 1; /* STATUS PHASE is always DATA1 */
+	} else {
+		expected_len = min_t(u32, maxpacket,
+				total_len - urb->actual_length);
+		buf = urb->transfer_buffer + urb->actual_length;
+		t = usb_gettoggle(udev, epnum, is_out);
+	}
+
+	/*
+	 * IN transaction Handling:
+	 * - Program HCMD register to initiate the IN transaction.
+	 * - poll for completion by reading XFRST register.
+	 * - Interpret the result.
+	 * - If ACK is received and we expect some data, read RBLEN
+	 * - Read the data from RBUF
+	 */
+
+	cmd = HCMD_PT(0) | HCMD_TOGV(t) | HCMD_BSEL(0) | HCMD_EP(epnum);
+	ice40_spi_reg_write(ihcd, cmd, HCMD_REG);
+
+	status = ice40_poll_xfer(ihcd, 1000);
+	switch (XFR_MASK(status)) {
+	case XFR_SUCCESS:
+		usb_dotoggle(udev, epnum, is_out);
+		iep->xcat_err = 0;
+		ret = 0;
+		if ((expected_len == 64) && (status & R64B))
+			short_packet = false;
+		break;
+	case XFR_NAK:
+		iep->xcat_err = 0;
+		ret = -EINPROGRESS;
+		break;
+	case XFR_TOGERR:
+		/*
+		 * Peripheral had missed the previous Ack and sent
+		 * the same packet again. Ack is sent by the hardware.
+		 * As the data is received already, ignore this
+		 * event.
+		 */
+		ret = -EINPROGRESS;
+		break;
+	case XFR_PKTERR:
+	case XFR_PIDERR:
+	case XFR_WRONGPID:
+	case XFR_CRCERR:
+	case XFR_TIMEOUT:
+		if (++iep->xcat_err < 8)
+			ret = -EINPROGRESS;
+		else
+			ret = -EPROTO;
+		break;
+	case XFR_STALL:
+		ret = -EPIPE;
+		break;
+	case XFR_BADLEN:
+		ret = -EOVERFLOW;
+		break;
+	default:
+		pr_err("transaction timed out\n");
+		ret = -EIO;
+	}
+
+	/*
+	 * Proceed further only if Ack is received and
+	 * we are expecting some data.
+	 */
+	if (ret || !expected_len)
+		goto out;
+
+	if (short_packet)
+		len = ice40_spi_reg_read(ihcd, RBLEN_REG);
+	else
+		len = 64;
+
+	/* babble condition */
+	if (len > expected_len) {
+		pr_err("overflow condition\n");
+		ret = -EOVERFLOW;
+		goto out;
+	}
+
+	/*
+	 * zero len packet received. nothing to read from
+	 * FIFO.
+	 */
+	if (len == 0) {
+		ret = 0;
+		goto out;
+	}
+
+	ihcd->in_buf[0] = READ_CMD(RBUF0_REG);
+
+	ihcd->in_xfr[1].rx_buf = buf;
+	ihcd->in_xfr[1].len = len;
+
+	ret = spi_sync(ihcd->spi, ihcd->in_msg);
+	if (ret < 0) {
+		pr_err("SPI transfer failed\n");
+		ret = -EIO;
+		goto out;
+	}
+
+	urb->actual_length += len;
+	if ((urb->actual_length == total_len) ||
+			(len < expected_len))
+		ret = 0; /* URB completed */
+	else
+		ret = -EINPROGRESS; /* still pending */
+out:
+	trace_ice40_in(epnum, xfr_status_string(status), len,
+			expected_len, ret);
+	return ret;
+}
+
+static int ice40_xfer_out(struct ice40_hcd *ihcd, struct urb *urb)
+{
+	struct usb_host_endpoint *ep = urb->ep;
+	struct usb_device *udev = urb->dev;
+	u32 total_len = urb->transfer_buffer_length;
+	u16 maxpacket = usb_endpoint_maxp(&ep->desc);
+	u8 epnum = usb_pipeendpoint(urb->pipe);
+	bool is_out = usb_pipeout(urb->pipe);
+	struct ice40_ep *iep = ep->hcpriv;
+	u8 cmd, status, len, t;
+	void *buf;
+	int ret;
+
+	if (epnum == 0 && ihcd->ep0_state == STATUS_PHASE) {
+		len = 0;
+		buf = NULL;
+		t = 1; /* STATUS PHASE is always DATA1 */
+	} else {
+		len = min_t(u32, maxpacket, total_len - urb->actual_length);
+		buf = urb->transfer_buffer + urb->actual_length;
+		t = usb_gettoggle(udev, epnum, is_out);
+	}
+
+	/*
+	 * OUT transaction Handling:
+	 * - If we need to send data, write the data to WBUF Fifo
+	 * - Program the WBLEN register
+	 * - Program HCMD register to initiate the OUT transaction.
+	 * - poll for completion by reading XFRST register.
+	 * - Interpret the result.
+	 */
+
+
+	if (!len)
+		goto no_data;
+
+	ihcd->out_buf[0] = WRITE_CMD(WBUF0_REG);
+
+	ihcd->out_xfr[1].tx_buf = buf;
+	ihcd->out_xfr[1].len = len;
+
+	ret = spi_sync(ihcd->spi, ihcd->out_msg);
+	if (ret < 0) {
+		pr_err("SPI transaction failed\n");
+		status = ret = -EIO;
+		goto out;
+	}
+
+no_data:
+	/*
+	 * Cache the WBLEN register and update it only if it
+	 * is changed from the previous value.
+	 */
+	if (len != ihcd->wblen0) {
+		ice40_spi_reg_write(ihcd, len, WBLEN_REG);
+		ihcd->wblen0 = len;
+	}
+
+	cmd = HCMD_PT(1) | HCMD_TOGV(t) | HCMD_BSEL(0) | HCMD_EP(epnum);
+	ice40_spi_reg_write(ihcd, cmd, HCMD_REG);
+
+	status = ice40_poll_xfer(ihcd, 1000);
+	switch (XFR_MASK(status)) {
+	case XFR_SUCCESS:
+		usb_dotoggle(udev, epnum, is_out);
+		urb->actual_length += len;
+		iep->xcat_err = 0;
+		if (!len || (urb->actual_length == total_len))
+			ret = 0; /* URB completed */
+		else
+			ret = -EINPROGRESS; /* pending */
+		break;
+	case XFR_NAK:
+		iep->xcat_err = 0;
+		ret = -EINPROGRESS;
+		break;
+	case XFR_PKTERR:
+	case XFR_PIDERR:
+	case XFR_WRONGPID:
+	case XFR_CRCERR:
+	case XFR_TIMEOUT:
+		if (++iep->xcat_err < 8)
+			ret = -EINPROGRESS;
+		else
+			ret = -EPROTO;
+		break;
+	case XFR_STALL:
+		ret = -EPIPE;
+		break;
+	case XFR_BADLEN:
+		ret = -EOVERFLOW;
+		break;
+	default:
+		pr_err("transaction timed out\n");
+		ret = -EIO;
+	}
+
+out:
+	trace_ice40_out(epnum, xfr_status_string(status), len, ret);
+	return ret;
+}
+
+static int ice40_process_urb(struct ice40_hcd *ihcd, struct urb *urb)
+{
+	struct usb_device *udev = urb->dev;
+	u8 devnum = usb_pipedevice(urb->pipe);
+	bool is_out = usb_pipeout(urb->pipe);
+	u32 total_len = urb->transfer_buffer_length;
+	int ret = 0;
+
+	/*
+	 * The USB device address can be reset to 0 by core temporarily
+	 * during reset recovery process. Don't assume anything about
+	 * device address. The device address is programmed as 0 by
+	 * default. If the device address is different to the previous
+	 * cached value, re-program it here before proceeding. The device
+	 * address register (FADDR) holds the value across multiple
+	 * transactions and we support only one device.
+	 */
+	if (ihcd->devnum != devnum) {
+		ice40_spi_reg_write(ihcd, devnum, FADDR_REG);
+		ihcd->devnum = devnum;
+	}
+
+	switch (usb_pipetype(urb->pipe)) {
+	case PIPE_CONTROL:
+		switch (ihcd->ep0_state) {
+		case SETUP_PHASE:
+			trace_ice40_ep0("SETUP");
+			ret = ice40_xfer_setup(ihcd, urb);
+			if (ret)
+				break;
+			if (total_len) {
+				ihcd->ep0_state = DATA_PHASE;
+				/*
+				 * Data stage always begin with
+				 * DATA1 PID.
+				 */
+				usb_settoggle(udev, 0, is_out, 1);
+			} else {
+				ihcd->ep0_state = STATUS_PHASE;
+				goto do_status;
+			}
+			/* fall through */
+		case DATA_PHASE:
+			trace_ice40_ep0("DATA");
+			if (is_out)
+				ret = ice40_xfer_out(ihcd, urb);
+			else
+				ret = ice40_xfer_in(ihcd, urb);
+			if (ret)
+				break;
+			/* DATA Phase is completed successfully */
+			ihcd->ep0_state = STATUS_PHASE;
+			/* fall through */
+		case STATUS_PHASE:
+do_status:
+			trace_ice40_ep0("STATUS");
+			/* zero len DATA transfers have IN status */
+			if (!total_len || is_out)
+				ret = ice40_xfer_in(ihcd, urb);
+			else
+				ret = ice40_xfer_out(ihcd, urb);
+			if (ret)
+				break;
+			ihcd->ep0_state = SETUP_PHASE;
+			break;
+		default:
+			pr_err("unknown stage for a control transfer\n");
+			break;
+		}
+		break;
+	case PIPE_BULK:
+		if (is_out)
+			ret = ice40_xfer_out(ihcd, urb);
+		else
+			ret = ice40_xfer_in(ihcd, urb);
+		/*
+		 * We may have to support zero len packet terminations
+		 * for URB_ZERO_PACKET URBs.
+		 */
+		break;
+	default:
+		pr_err("IN/ISO transfers not supported\n");
+		break;
+	}
+
+	return ret;
+}
+
+/* Must be called with spin lock and interrupts disabled */
+static void ice40_complete_urb(struct usb_hcd *hcd, struct urb *urb, int status)
+{
+	struct ice40_hcd *ihcd = hcd_to_ihcd(hcd);
+	struct usb_host_endpoint *ep = urb->ep;
+	struct ice40_ep *iep = ep->hcpriv;
+	struct urb *first_urb;
+	bool needs_update = false;
+	bool control = usb_pipecontrol(urb->pipe);
+
+	/*
+	 * If the active URB i.e the first URB in the ep list is being
+	 * removed, clear the transaction error count. If it is a control
+	 * URB ep0_state needs to be reset to SETUP_PHASE.
+	 */
+	first_urb = list_first_entry(&ep->urb_list, struct urb, urb_list);
+	if (urb == first_urb)
+		needs_update = true;
+
+	usb_hcd_unlink_urb_from_ep(hcd, urb);
+	spin_unlock(&ihcd->lock);
+	trace_ice40_urb_done(urb, status);
+	usb_hcd_giveback_urb(ihcd->hcd, urb, status);
+	spin_lock(&ihcd->lock);
+
+	if (needs_update) {
+		iep->xcat_err = 0;
+		if (control)
+			ihcd->ep0_state = SETUP_PHASE;
+	}
+}
+
+static void ice40_async_work(struct work_struct *work)
+{
+	struct ice40_hcd *ihcd = container_of(work,
+			struct ice40_hcd, async_work);
+	struct usb_hcd *hcd = ihcd->hcd;
+	struct list_head *tmp, *uent, *utmp;
+	struct ice40_ep *iep;
+	struct usb_host_endpoint *ep;
+	struct urb *urb;
+	unsigned long flags;
+	int status;
+
+	/*
+	 * Traverse the active endpoints circularly and process URBs.
+	 * If any endpoint is marked for unlinking, the URBs are
+	 * completed here. The endpoint is removed from active list
+	 * if a URB is retired with -EPIPE/-EPROTO errors.
+	 */
+
+	spin_lock_irqsave(&ihcd->lock, flags);
+
+	if (list_empty(&ihcd->async_list))
+		goto out;
+
+	iep = list_first_entry(&ihcd->async_list, struct ice40_ep, ep_list);
+	while (1) {
+		ep = iep->ep;
+
+		urb = list_first_entry(&ep->urb_list, struct urb, urb_list);
+		if (urb->unlinked) {
+			status = urb->unlinked;
+		} else {
+			spin_unlock_irqrestore(&ihcd->lock, flags);
+			status = ice40_process_urb(ihcd, urb);
+			spin_lock_irqsave(&ihcd->lock, flags);
+		}
+
+		if ((status == -EPIPE) || (status == -EPROTO))
+			iep->halted = true;
+
+		if (status != -EINPROGRESS)
+			ice40_complete_urb(hcd, urb, status);
+
+		if (iep->unlinking) {
+			list_for_each_safe(uent, utmp, &ep->urb_list) {
+				urb = list_entry(uent, struct urb, urb_list);
+				if (urb->unlinked)
+					ice40_complete_urb(hcd, urb, 0);
+			}
+			iep->unlinking = false;
+		}
+
+		tmp = iep->ep_list.next;
+		if (list_empty(&ep->urb_list) || iep->halted) {
+			list_del_init(&iep->ep_list);
+
+			if (list_empty(&ihcd->async_list))
+				break;
+		}
+
+		if (tmp == &ihcd->async_list)
+			tmp = tmp->next;
+		iep = list_entry(tmp, struct ice40_ep, ep_list);
+	}
+out:
+	spin_unlock_irqrestore(&ihcd->lock, flags);
+}
+
+static int
+ice40_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
+{
+	struct ice40_hcd *ihcd = hcd_to_ihcd(hcd);
+	struct usb_device *udev = urb->dev;
+	struct usb_host_endpoint *ep = urb->ep;
+	bool is_out = usb_pipeout(urb->pipe);
+	u8 epnum = usb_pipeendpoint(urb->pipe);
+	struct ice40_ep *iep;
+	unsigned long flags;
+	int ret;
+
+	/*
+	 * This bridge chip supports only Full-speed. So ISO is not
+	 * supported. Interrupt support is not implemented as there
+	 * is no use case.
+	 */
+	if (usb_pipeisoc(urb->pipe) || usb_pipeint(urb->pipe)) {
+		pr_debug("iso and int xfers not supported\n");
+		ret = -ENOTSUPP;
+		goto out;
+	}
+
+	spin_lock_irqsave(&ihcd->lock, flags);
+
+	ret = usb_hcd_link_urb_to_ep(hcd, urb);
+	if (ret)
+		goto rel_lock;
+
+	trace_ice40_urb_enqueue(urb);
+
+	iep = ep->hcpriv;
+	if (!iep) {
+		iep = kzalloc(sizeof(struct ice40_ep), GFP_ATOMIC);
+		if (!iep) {
+			pr_debug("fail to allocate iep\n");
+			ret = -ENOMEM;
+			goto unlink;
+		}
+		ep->hcpriv = iep;
+		INIT_LIST_HEAD(&iep->ep_list);
+		iep->ep = ep;
+		usb_settoggle(udev, epnum, is_out, 0);
+		if (usb_pipecontrol(urb->pipe))
+			ihcd->ep0_state = SETUP_PHASE;
+	}
+
+	/*
+	 * We expect the interface driver to clear the stall condition
+	 * before queueing another URB. For example mass storage
+	 * device may STALL a bulk endpoint for un-supported command.
+	 * The storage driver clear the STALL condition before queueing
+	 * another URB.
+	 */
+	iep->halted = false;
+	if (list_empty(&iep->ep_list))
+		list_add_tail(&iep->ep_list, &ihcd->async_list);
+
+	queue_work(ihcd->wq, &ihcd->async_work);
+
+	spin_unlock_irqrestore(&ihcd->lock, flags);
+
+	return 0;
+unlink:
+	usb_hcd_unlink_urb_from_ep(hcd, urb);
+rel_lock:
+	spin_unlock_irqrestore(&ihcd->lock, flags);
+out:
+	return ret;
+}
+
+static int
+ice40_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+{
+	struct ice40_hcd *ihcd = hcd_to_ihcd(hcd);
+	struct usb_host_endpoint *ep = urb->ep;
+	struct ice40_ep *iep;
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&ihcd->lock, flags);
+
+	ret = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (ret)
+		goto rel_lock;
+
+	trace_ice40_urb_dequeue(urb);
+	iep = ep->hcpriv;
+
+	/*
+	 * If the endpoint is not in asynchronous schedule, complete
+	 * the URB immediately. Otherwise mark it as being unlinked.
+	 * The asynchronous schedule work will take care of completing
+	 * the URB when this endpoint is encountered during traversal.
+	 */
+	if (list_empty(&iep->ep_list))
+		ice40_complete_urb(hcd, urb, status);
+	else
+		iep->unlinking = true;
+
+rel_lock:
+	spin_unlock_irqrestore(&ihcd->lock, flags);
+	return ret;
+}
+
+static void
+ice40_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
+{
+	struct ice40_ep	*iep = ep->hcpriv;
+
+	/*
+	 * If there is no I/O on this endpoint before, ep->hcpriv
+	 * will be NULL. nothing to do in this case.
+	 */
+	if (!iep)
+		return;
+
+	if (!list_empty(&ep->urb_list))
+		pr_err("trying to disable an non-empty endpoint\n");
+
+	kfree(iep);
+	ep->hcpriv = NULL;
+}
+
+
+static int ice40_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+	struct ice40_hcd *ihcd = hcd_to_ihcd(hcd);
+	int ret = 0;
+
+	/*
+	 * core calls hub_status_method during suspend/resume.
+	 * return 0 if there is no port change. pcd_pending
+	 * is set to true when a device is connected and line
+	 * state is sampled via debugfs command. clear this
+	 * flag after returning the port change status.
+	 */
+	if (ihcd->pcd_pending) {
+		*buf = (1 << 1);
+		ret = 1;
+		ihcd->pcd_pending = false;
+	}
+
+	return ret;
+}
+
+static void ice40_hub_descriptor(struct usb_hub_descriptor *desc)
+{
+	/* There is nothing special about us!! */
+	desc->bDescLength = 9;
+	desc->bDescriptorType = 0x29;
+	desc->bNbrPorts = 1;
+	desc->wHubCharacteristics = cpu_to_le16(HUB_CHAR_NO_LPSM |
+				HUB_CHAR_NO_OCPM);
+	desc->bPwrOn2PwrGood = 0;
+	desc->bHubContrCurrent = 0;
+	desc->u.hs.DeviceRemovable[0] = 0;
+	desc->u.hs.DeviceRemovable[1] = ~0;
+}
+
+static int
+ice40_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+			u16 wIndex, char *buf, u16 wLength)
+{
+	int ret = 0;
+	u8 ctrl;
+	struct ice40_hcd *ihcd = hcd_to_ihcd(hcd);
+
+	/*
+	 * We have only 1 port. No special locking is required while
+	 * handling root hub commands. The bridge chip does not maintain
+	 * any port states. Maintain different port states in software.
+	 */
+	switch (typeReq) {
+	case ClearPortFeature:
+		if (wIndex != 1 || wLength != 0)
+			goto error;
+		switch (wValue) {
+		case USB_PORT_FEAT_SUSPEND:
+			/*
+			 * The device is resumed as part of the root hub
+			 * resume to simplify the resume sequence. so
+			 * we may simply return from here. If device is
+			 * resumed before root hub is suspended, this
+			 * flags will be cleared here.
+			 */
+			if (!(ihcd->port_flags & USB_PORT_STAT_SUSPEND))
+				break;
+			ihcd->port_flags &= ~USB_PORT_STAT_SUSPEND;
+			break;
+		case USB_PORT_FEAT_ENABLE:
+			ihcd->port_flags &= ~USB_PORT_STAT_ENABLE;
+			break;
+		case USB_PORT_FEAT_POWER:
+			ihcd->port_flags &= ~USB_PORT_STAT_POWER;
+			break;
+		case USB_PORT_FEAT_C_CONNECTION:
+			ihcd->port_flags &= ~(USB_PORT_STAT_C_CONNECTION << 16);
+			break;
+		case USB_PORT_FEAT_C_ENABLE:
+		case USB_PORT_FEAT_C_SUSPEND:
+		case USB_PORT_FEAT_C_OVER_CURRENT:
+		case USB_PORT_FEAT_C_RESET:
+			/* nothing special here */
+			break;
+		default:
+			goto error;
+		}
+		break;
+	case GetHubDescriptor:
+		ice40_hub_descriptor((struct usb_hub_descriptor *) buf);
+		break;
+	case GetHubStatus:
+		put_unaligned_le32(0, buf);
+		break;
+	case GetPortStatus:
+		if (wIndex != 1)
+			goto error;
+
+		/*
+		 * Core resets the device and requests port status to
+		 * stop the reset signaling. If there is a reset in
+		 * progress, finish it here.
+		 */
+		ctrl = ice40_spi_reg_read(ihcd, CTRL0_REG);
+		if (!(ctrl & RESET_CTRL))
+			ihcd->port_flags &= ~USB_PORT_STAT_RESET;
+
+		put_unaligned_le32(ihcd->port_flags, buf);
+		break;
+	case SetPortFeature:
+		if (wIndex != 1 || wLength != 0)
+			goto error;
+		switch (wValue) {
+		case USB_PORT_FEAT_SUSPEND:
+			if (ihcd->port_flags & USB_PORT_STAT_RESET)
+				goto error;
+			if (!(ihcd->port_flags & USB_PORT_STAT_ENABLE))
+				goto error;
+			/* SOFs will be stopped during root hub suspend */
+			ihcd->port_flags |= USB_PORT_STAT_SUSPEND;
+			break;
+		case USB_PORT_FEAT_POWER:
+			ihcd->port_flags |= USB_PORT_STAT_POWER;
+			break;
+		case USB_PORT_FEAT_RESET:
+			/* Good time to enable the port */
+			ice40_spi_reg_write(ihcd, ihcd->ctrl0 |
+					RESET_CTRL, CTRL0_REG);
+			ihcd->port_flags |= USB_PORT_STAT_RESET;
+			ihcd->port_flags |= USB_PORT_STAT_ENABLE;
+			break;
+		default:
+			goto error;
+		}
+		break;
+	default:
+error:
+		/* "protocol stall" on error */
+		ret = -EPIPE;
+	}
+
+	trace_ice40_hub_control(typeReq, wValue, wIndex, wLength, ret);
+	return ret;
+}
+
+static void ice40_spi_power_off(struct ice40_hcd *ihcd);
+static int ice40_bus_suspend(struct usb_hcd *hcd)
+{
+	struct ice40_hcd *ihcd = hcd_to_ihcd(hcd);
+
+	trace_ice40_bus_suspend(0); /* start */
+
+	/* This happens only during debugging */
+	if (!ihcd->devnum) {
+		pr_debug("device still not connected. abort suspend\n");
+		trace_ice40_bus_suspend(2); /* failure */
+		return -EAGAIN;
+	}
+	/*
+	 * Stop sending the SOFs on downstream port. The device
+	 * finds the bus idle and enter suspend. The device
+	 * takes ~3 msec to enter suspend.
+	 */
+	ihcd->ctrl0 &= ~SOFEN_CTRL;
+	ice40_spi_reg_write(ihcd, ihcd->ctrl0, CTRL0_REG);
+	usleep_range(4500, 5000);
+
+	/*
+	 * Power collapse the bridge chip to avoid the leakage
+	 * current.
+	 */
+	ice40_spi_power_off(ihcd);
+
+	trace_ice40_bus_suspend(1); /* successful */
+	pm_relax(&ihcd->spi->dev);
+	return 0;
+}
+
+static int ice40_spi_load_fw(struct ice40_hcd *ihcd);
+static int ice40_bus_resume(struct usb_hcd *hcd)
+{
+	struct ice40_hcd *ihcd = hcd_to_ihcd(hcd);
+	u8 ctrl0;
+	int ret;
+
+	pm_stay_awake(&ihcd->spi->dev);
+	trace_ice40_bus_resume(0); /* start */
+	/*
+	 * Power up the bridge chip and load the configuration file.
+	 * Re-program the previous settings. For now we need to
+	 * update the device address only.
+	 */
+	ice40_spi_load_fw(ihcd);
+	ice40_spi_reg_write(ihcd, ihcd->devnum, FADDR_REG);
+	ihcd->wblen0 = ~0;
+
+	/*
+	 * Program the bridge chip to drive resume signaling. The SOFs
+	 * are automatically transmitted after resume completion. It
+	 * will take ~20 msec for resume completion.
+	 */
+	ice40_spi_reg_write(ihcd, ihcd->ctrl0 | RESUME_CTRL, CTRL0_REG);
+	usleep_range(20000, 21000);
+	ret = ice40_handshake(ihcd, CTRL0_REG, RESUME_CTRL, 0, 5000);
+	if (ret) {
+		pr_err("resume failed\n");
+		trace_ice40_bus_resume(2); /* failure */
+		return -ENODEV;
+	}
+
+	ctrl0 = ice40_spi_reg_read(ihcd, CTRL0_REG);
+	if (!(ctrl0 & SOFEN_CTRL)) {
+		pr_err("SOFs are not transmitted after resume\n");
+		trace_ice40_bus_resume(3); /* failure */
+		return -ENODEV;
+	}
+
+	ihcd->port_flags &= ~USB_PORT_STAT_SUSPEND;
+	ihcd->ctrl0 |= SOFEN_CTRL;
+
+	trace_ice40_bus_resume(1); /* success */
+	return 0;
+}
+
+static void ice40_set_autosuspend_delay(struct usb_device *dev)
+{
+	/*
+	 * Immediate suspend for root hub and 500 msec auto-suspend
+	 * timeout for the card.
+	 */
+	if (!dev->parent)
+		pm_runtime_set_autosuspend_delay(&dev->dev, 0);
+	else
+		pm_runtime_set_autosuspend_delay(&dev->dev, 500);
+}
+
+static const struct hc_driver ice40_hc_driver = {
+	.description = hcd_name,
+	.product_desc = "ICE40 SPI Host Controller",
+	.hcd_priv_size = sizeof(struct ice40_hcd *),
+	.flags = HCD_USB11,
+
+	/* setup and clean up */
+	.reset = ice40_reset,
+	.start = ice40_run,
+	.stop = ice40_stop,
+
+	/* endpoint and I/O routines */
+	.urb_enqueue = ice40_urb_enqueue,
+	.urb_dequeue = ice40_urb_dequeue,
+	.endpoint_disable = ice40_endpoint_disable,
+
+	/* Root hub operations */
+	.hub_status_data = ice40_hub_status_data,
+	.hub_control = ice40_hub_control,
+	.bus_suspend = ice40_bus_suspend,
+	.bus_resume = ice40_bus_resume,
+
+	.set_autosuspend_delay = ice40_set_autosuspend_delay,
+};
+
+static int ice40_spi_parse_dt(struct ice40_hcd *ihcd)
+{
+	struct device_node *node = ihcd->spi->dev.of_node;
+	int ret = 0;
+
+	if (!node) {
+		pr_err("device specific info missing\n");
+		ret = -ENODEV;
+		goto out;
+	}
+
+	ihcd->reset_gpio = of_get_named_gpio(node, "lattice,reset-gpio", 0);
+	if (ihcd->reset_gpio < 0) {
+		pr_err("reset gpio is missing\n");
+		ret = ihcd->reset_gpio;
+		goto out;
+	}
+
+	ihcd->slave_select_gpio = of_get_named_gpio(node,
+				"lattice,slave-select-gpio", 0);
+	if (ihcd->slave_select_gpio < 0) {
+		pr_err("slave select gpio is missing\n");
+		ret = ihcd->slave_select_gpio;
+		goto out;
+	}
+
+	ihcd->config_done_gpio = of_get_named_gpio(node,
+				"lattice,config-done-gpio", 0);
+	if (ihcd->config_done_gpio < 0) {
+		pr_err("config done gpio is missing\n");
+		ret = ihcd->config_done_gpio;
+		goto out;
+	}
+
+	ihcd->vcc_en_gpio = of_get_named_gpio(node, "lattice,vcc-en-gpio", 0);
+	if (ihcd->vcc_en_gpio < 0) {
+		pr_err("vcc enable gpio is missing\n");
+		ret = ihcd->vcc_en_gpio;
+		goto out;
+	}
+
+	/*
+	 * When clk-en-gpio is present, it is used to enable the 19.2 MHz
+	 * clock from MSM to the bridge chip. Otherwise on-board clock
+	 * is used.
+	 */
+	ihcd->clk_en_gpio = of_get_named_gpio(node, "lattice,clk-en-gpio", 0);
+	if (ihcd->clk_en_gpio < 0)
+		ihcd->clk_en_gpio = 0;
+out:
+	return ret;
+}
+
+static void ice40_spi_power_off(struct ice40_hcd *ihcd)
+{
+	if (!ihcd->powered)
+		return;
+
+	gpio_direction_output(ihcd->vcc_en_gpio, 0);
+	regulator_disable(ihcd->core_vcc);
+	regulator_disable(ihcd->spi_vcc);
+	if (ihcd->gpio_vcc)
+		regulator_disable(ihcd->gpio_vcc);
+	if (ihcd->clk_en_gpio)
+		gpio_direction_output(ihcd->clk_en_gpio, 0);
+
+	ihcd->powered = false;
+}
+
+static int ice40_spi_power_up(struct ice40_hcd *ihcd)
+{
+	int ret;
+
+	if (ihcd->clk_en_gpio) {
+		ret = gpio_direction_output(ihcd->clk_en_gpio, 1);
+		if (ret < 0) {
+			pr_err("fail to enabel clk %d\n", ret);
+			goto out;
+		}
+	}
+
+	if (ihcd->gpio_vcc) {
+		ret = regulator_enable(ihcd->gpio_vcc); /* 1.8 V */
+		if (ret < 0) {
+			pr_err("fail to enable gpio vcc\n");
+			goto disable_clk;
+		}
+	}
+
+	ret = regulator_enable(ihcd->spi_vcc); /* 1.8 V */
+	if (ret < 0) {
+		pr_err("fail to enable spi vcc\n");
+		goto disable_gpio_vcc;
+	}
+
+	ret = regulator_enable(ihcd->core_vcc); /* 1.2 V */
+	if (ret < 0) {
+		pr_err("fail to enable core vcc\n");
+		goto disable_spi_vcc;
+	}
+
+	ret = gpio_direction_output(ihcd->vcc_en_gpio, 1);
+	if (ret < 0) {
+		pr_err("fail to assert vcc gpio\n");
+		goto disable_core_vcc;
+	}
+
+	ihcd->powered = true;
+
+	return 0;
+
+disable_core_vcc:
+	regulator_disable(ihcd->core_vcc);
+disable_spi_vcc:
+	regulator_disable(ihcd->spi_vcc);
+disable_gpio_vcc:
+	if (ihcd->gpio_vcc)
+		regulator_disable(ihcd->gpio_vcc);
+disable_clk:
+	if (ihcd->clk_en_gpio)
+		gpio_direction_output(ihcd->clk_en_gpio, 0);
+out:
+	return ret;
+}
+
+static struct gpiomux_setting slave_select_setting = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_NONE,
+	.dir = GPIOMUX_OUT_LOW,
+};
+
+static int ice40_spi_cache_fw(struct ice40_hcd *ihcd)
+{
+	const struct firmware *fw;
+	void *buf;
+	size_t buf_len;
+	int ret;
+
+	ret = request_firmware(&fw, fw_name, &ihcd->spi->dev);
+	if (ret < 0) {
+		pr_err("fail to get the firmware\n");
+		goto out;
+	}
+
+	pr_debug("received firmware size = %zu\n", fw->size);
+
+	/*
+	 * The bridge expects additional clock cycles after
+	 * receiving the configuration data. We don't have a
+	 * direct control over SPI clock. Add extra bytes
+	 * to the confiration data.
+	 */
+	buf_len = fw->size + 16;
+	buf = devm_kzalloc(&ihcd->spi->dev, buf_len, GFP_KERNEL);
+	if (!buf) {
+		pr_err("fail to allocate firmware buffer\n");
+		ret = -ENOMEM;
+		goto release;
+	}
+
+	/*
+	 * The firmware buffer can not be used for DMA as it
+	 * is not physically contiguous. We copy the data
+	 * in kmalloc buffer. This buffer will be freed only
+	 * during unbind or rmmod.
+	 */
+	memcpy(buf, fw->data, fw->size);
+	release_firmware(fw);
+
+	/*
+	 * The bridge supports only 25 MHz during configuration
+	 * file loading.
+	 */
+	ihcd->fmsg_xfr[0].tx_buf = buf;
+	ihcd->fmsg_xfr[0].len = buf_len;
+	ihcd->fmsg_xfr[0].speed_hz = 25000000;
+
+	return 0;
+
+release:
+	release_firmware(fw);
+out:
+	return ret;
+}
+
+static int ice40_spi_load_fw(struct ice40_hcd *ihcd)
+{
+	int ret, i;
+	struct gpiomux_setting old_setting;
+
+	ret = gpio_direction_output(ihcd->reset_gpio, 0);
+	if (ret  < 0) {
+		pr_err("fail to assert reset %d\n", ret);
+		goto out;
+	}
+
+	ret = gpio_direction_output(ihcd->vcc_en_gpio, 0);
+	if (ret < 0) {
+		pr_err("fail to de-assert vcc_en gpio %d\n", ret);
+		goto out;
+	}
+
+	/*
+	 * The bridge chip samples the chip select signal during
+	 * power-up. If it is low, it enters SPI slave mode and
+	 * accepts the configuration data from us. The chip
+	 * select signal is managed by the SPI controller driver.
+	 * We temporarily override the chip select config to
+	 * drive it low. The SPI bus needs to be locked down during
+	 * this period to avoid other slave data going to our
+	 * bridge chip.
+	 *
+	 */
+	spi_bus_lock(ihcd->spi->master);
+
+	ret = msm_gpiomux_write(ihcd->slave_select_gpio, GPIOMUX_SUSPENDED,
+			&slave_select_setting, &old_setting);
+	if (ret < 0) {
+		pr_err("fail to select the slave %d\n", ret);
+		goto out;
+	}
+
+	ret = ice40_spi_power_up(ihcd);
+	if (ret < 0) {
+		pr_err("fail to power up the chip\n");
+		goto out;
+	}
+
+
+	/*
+	 * The databook says 1200 usec is required before the
+	 * chip becomes ready for the SPI transfer.
+	 */
+	usleep_range(1200, 1250);
+
+	ret = msm_gpiomux_write(ihcd->slave_select_gpio, GPIOMUX_SUSPENDED,
+			&old_setting, NULL);
+	if (ret < 0) {
+		pr_err("fail to de-select the slave %d\n", ret);
+		goto power_off;
+	}
+
+	ret = spi_sync_locked(ihcd->spi, ihcd->fmsg);
+
+	spi_bus_unlock(ihcd->spi->master);
+
+	if (ret < 0) {
+		pr_err("spi write failed\n");
+		goto power_off;
+	}
+
+	for (i = 0; i < 1000; i++) {
+		ret = gpio_get_value(ihcd->config_done_gpio);
+		if (ret) {
+			pr_debug("config done asserted %d\n", i);
+			break;
+		}
+		udelay(1);
+	}
+
+	if (ret <= 0) {
+		pr_err("config done not asserted\n");
+		ret = -ENODEV;
+		goto power_off;
+	}
+
+	ret = gpio_direction_output(ihcd->reset_gpio, 1);
+	if (ret  < 0) {
+		pr_err("fail to assert reset %d\n", ret);
+		goto power_off;
+	}
+	udelay(50);
+
+	ret = ice40_spi_reg_read(ihcd, XFRST_REG);
+	pr_debug("XFRST val is %x\n", ret);
+	if (!(ret & PLLOK)) {
+		pr_err("The PLL2 is not synchronized\n");
+		goto power_off;
+	}
+
+	pr_info("Firmware load success\n");
+
+	return 0;
+
+power_off:
+	ice40_spi_power_off(ihcd);
+out:
+	return ret;
+}
+
+static int ice40_spi_init_regulators(struct ice40_hcd *ihcd)
+{
+	int ret;
+
+	ihcd->spi_vcc = devm_regulator_get(&ihcd->spi->dev, "spi-vcc");
+	if (IS_ERR(ihcd->spi_vcc)) {
+		ret = PTR_ERR(ihcd->spi_vcc);
+		if (ret != -EPROBE_DEFER)
+			pr_err("fail to get spi-vcc %d\n", ret);
+		goto out;
+	}
+
+	ret = regulator_set_voltage(ihcd->spi_vcc, 1800000, 1800000);
+	if (ret < 0) {
+		pr_err("fail to set spi-vcc %d\n", ret);
+		goto out;
+	}
+
+	ihcd->core_vcc = devm_regulator_get(&ihcd->spi->dev, "core-vcc");
+	if (IS_ERR(ihcd->core_vcc)) {
+		ret = PTR_ERR(ihcd->core_vcc);
+		if (ret != -EPROBE_DEFER)
+			pr_err("fail to get core-vcc %d\n", ret);
+		goto out;
+	}
+
+	ret = regulator_set_voltage(ihcd->core_vcc, 1200000, 1200000);
+	if (ret < 0) {
+		pr_err("fail to set core-vcc %d\n", ret);
+		goto out;
+	}
+
+	if (!of_get_property(ihcd->spi->dev.of_node, "gpio-supply", NULL))
+		goto out;
+
+	ihcd->gpio_vcc = devm_regulator_get(&ihcd->spi->dev, "gpio");
+	if (IS_ERR(ihcd->gpio_vcc)) {
+		ret = PTR_ERR(ihcd->gpio_vcc);
+		if (ret != -EPROBE_DEFER)
+			pr_err("fail to get gpio_vcc %d\n", ret);
+		goto out;
+	}
+
+	ret = regulator_set_voltage(ihcd->gpio_vcc, 1800000, 1800000);
+	if (ret < 0) {
+		pr_err("fail to set gpio_vcc %d\n", ret);
+		goto out;
+	}
+
+out:
+	return ret;
+}
+
+static int ice40_spi_request_gpios(struct ice40_hcd *ihcd)
+{
+	int ret;
+
+	ret = devm_gpio_request(&ihcd->spi->dev, ihcd->reset_gpio,
+				"ice40_reset");
+	if (ret < 0) {
+		pr_err("fail to request reset gpio\n");
+		goto out;
+	}
+
+	ret = devm_gpio_request(&ihcd->spi->dev, ihcd->config_done_gpio,
+				"ice40_config_done");
+	if (ret < 0) {
+		pr_err("fail to request config_done gpio\n");
+		goto out;
+	}
+
+	ret = devm_gpio_request(&ihcd->spi->dev, ihcd->vcc_en_gpio,
+				"ice40_vcc_en");
+	if (ret < 0) {
+		pr_err("fail to request vcc_en gpio\n");
+		goto out;
+	}
+
+	if (ihcd->clk_en_gpio) {
+
+		ret = devm_gpio_request(&ihcd->spi->dev, ihcd->clk_en_gpio,
+					"ice40_clk_en");
+		if (ret < 0)
+			pr_err("fail to request clk_en gpio\n");
+	}
+
+out:
+	return ret;
+}
+
+static int
+ice40_spi_init_one_xfr(struct ice40_hcd *ihcd, enum ice40_xfr_type type)
+{
+	struct spi_message **m;
+	struct spi_transfer **t;
+	int n;
+
+	switch (type) {
+	case FIRMWARE_XFR:
+		m = &ihcd->fmsg;
+		t = &ihcd->fmsg_xfr;
+		n = 1;
+		break;
+	case REG_WRITE_XFR:
+		m = &ihcd->wmsg;
+		t = &ihcd->wmsg_xfr;
+		n = 1;
+		break;
+	case REG_READ_XFR:
+		m = &ihcd->rmsg;
+		t = &ihcd->rmsg_xfr;
+		n = 1;
+		break;
+	case SETUP_XFR:
+		m = &ihcd->setup_msg;
+		t = &ihcd->setup_xfr;
+		n = 2;
+		break;
+	case DATA_IN_XFR:
+		m = &ihcd->in_msg;
+		t = &ihcd->in_xfr;
+		n = 2;
+		break;
+	case DATA_OUT_XFR:
+		m = &ihcd->out_msg;
+		t = &ihcd->out_xfr;
+		n = 2;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	*m = devm_kzalloc(&ihcd->spi->dev, sizeof(**m), GFP_KERNEL);
+	if (*m == NULL)
+		goto out;
+
+	*t = devm_kzalloc(&ihcd->spi->dev, n * sizeof(**t), GFP_KERNEL);
+	if (*t == NULL)
+		goto out;
+
+	spi_message_init_with_transfers(*m, *t, n);
+
+	return 0;
+out:
+	return -ENOMEM;
+}
+
+static int ice40_spi_init_xfrs(struct ice40_hcd *ihcd)
+{
+	int ret = -ENOMEM;
+
+	ret = ice40_spi_init_one_xfr(ihcd, FIRMWARE_XFR);
+	if (ret < 0)
+		goto out;
+
+	ret = ice40_spi_init_one_xfr(ihcd, REG_WRITE_XFR);
+	if (ret < 0)
+		goto out;
+
+	ihcd->w_tx_buf = devm_kzalloc(&ihcd->spi->dev, 2, GFP_KERNEL);
+	if (!ihcd->w_tx_buf)
+		goto out;
+
+	ihcd->w_rx_buf = devm_kzalloc(&ihcd->spi->dev, 2, GFP_KERNEL);
+	if (!ihcd->w_rx_buf)
+		goto out;
+
+	ihcd->wmsg_xfr[0].tx_buf = ihcd->w_tx_buf;
+	ihcd->wmsg_xfr[0].rx_buf = ihcd->w_rx_buf;
+	ihcd->wmsg_xfr[0].len = 2;
+
+	ret = ice40_spi_init_one_xfr(ihcd, REG_READ_XFR);
+	if (ret < 0)
+		goto out;
+
+	ihcd->r_tx_buf = devm_kzalloc(&ihcd->spi->dev, 3, GFP_KERNEL);
+	if (!ihcd->r_tx_buf)
+		goto out;
+
+	ihcd->r_rx_buf = devm_kzalloc(&ihcd->spi->dev, 3, GFP_KERNEL);
+	if (!ihcd->r_rx_buf)
+		goto out;
+
+	ihcd->rmsg_xfr[0].tx_buf = ihcd->r_tx_buf;
+	ihcd->rmsg_xfr[0].rx_buf = ihcd->r_rx_buf;
+	ihcd->rmsg_xfr[0].len = 3;
+
+	ret = ice40_spi_init_one_xfr(ihcd, SETUP_XFR);
+	if (ret < 0)
+		goto out;
+
+	ihcd->setup_buf = devm_kzalloc(&ihcd->spi->dev, 1, GFP_KERNEL);
+	if (!ihcd->setup_buf)
+		goto out;
+	ihcd->setup_xfr[0].tx_buf = ihcd->setup_buf;
+	ihcd->setup_xfr[0].len = 1;
+
+	ret = ice40_spi_init_one_xfr(ihcd, DATA_IN_XFR);
+	if (ret < 0)
+		goto out;
+	ihcd->in_buf = devm_kzalloc(&ihcd->spi->dev, 2, GFP_KERNEL);
+	if (!ihcd->in_buf)
+		goto out;
+	ihcd->in_xfr[0].tx_buf = ihcd->in_buf;
+	ihcd->in_xfr[0].len = 2;
+
+	ret = ice40_spi_init_one_xfr(ihcd, DATA_OUT_XFR);
+	if (ret < 0)
+		goto out;
+	ihcd->out_buf = devm_kzalloc(&ihcd->spi->dev, 1, GFP_KERNEL);
+	if (!ihcd->out_buf)
+		goto out;
+	ihcd->out_xfr[0].tx_buf = ihcd->out_buf;
+	ihcd->out_xfr[0].len = 1;
+
+	return 0;
+
+out:
+	return -ENOMEM;
+}
+
+static int ice40_dbg_cmd_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, NULL, inode->i_private);
+}
+
+static ssize_t ice40_dbg_cmd_write(struct file *file, const char __user *ubuf,
+				size_t count, loff_t *ppos)
+{
+	struct seq_file *s = file->private_data;
+	struct ice40_hcd *ihcd = s->private;
+	char buf[32];
+	int ret;
+	u8 status, addr;
+
+	memset(buf, 0x00, sizeof(buf));
+
+	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) {
+		ret = -EFAULT;
+		goto out;
+	}
+
+	if (!strcmp(buf, "poll")) {
+		if (!HCD_RH_RUNNING(ihcd->hcd)) {
+			ret = -EAGAIN;
+			goto out;
+		}
+		/*
+		 * The bridge chip supports interrupt for device
+		 * connect and disconnect. We don;t have a real
+		 * use case of connect/disconnect. This debugfs
+		 * interface provides a way to enumerate the
+		 * attached device.
+		 */
+		ice40_spi_reg_write(ihcd, ihcd->ctrl0 |
+				DET_BUS_CTRL, CTRL0_REG);
+		ice40_handshake(ihcd, CTRL0_REG, DET_BUS_CTRL, 0, 5000);
+		status = ice40_spi_reg_read(ihcd, XFRST_REG);
+		if ((status & DPST)) {
+			ihcd->port_flags |= USB_PORT_STAT_CONNECTION;
+			ihcd->port_flags |= USB_PORT_STAT_C_CONNECTION << 16;
+			ihcd->pcd_pending = true;
+			usb_hcd_poll_rh_status(ihcd->hcd);
+		} else if (ihcd->port_flags & USB_PORT_STAT_CONNECTION) {
+			ihcd->port_flags &= ~USB_PORT_STAT_ENABLE;
+			ihcd->port_flags &= ~USB_PORT_STAT_CONNECTION;
+			ihcd->port_flags |= (USB_PORT_STAT_C_CONNECTION << 16);
+			ihcd->pcd_pending = true;
+			usb_hcd_poll_rh_status(ihcd->hcd);
+		}
+	} else if (!strcmp(buf, "rwtest")) {
+		ihcd->devnum = 1;
+		ice40_spi_reg_write(ihcd, 0x1, FADDR_REG);
+		addr = ice40_spi_reg_read(ihcd, FADDR_REG);
+		pr_info("addr written was 0x1 read as %x\n", addr);
+	} else if (!strcmp(buf, "force_disconnect")) {
+		if (!HCD_RH_RUNNING(ihcd->hcd)) {
+			ret = -EAGAIN;
+			goto out;
+		}
+		/*
+		 * Forcfully disconnect the device. This is required
+		 * for simulating the disconnect on a USB port which
+		 * does not have pull-down resistors.
+		 */
+		ihcd->port_flags &= ~USB_PORT_STAT_ENABLE;
+		ihcd->port_flags &= ~USB_PORT_STAT_CONNECTION;
+		ihcd->port_flags |= (USB_PORT_STAT_C_CONNECTION << 16);
+		ihcd->pcd_pending = true;
+		usb_hcd_poll_rh_status(ihcd->hcd);
+	} else {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = count;
+out:
+	return ret;
+}
+
+const struct file_operations ice40_dbg_cmd_ops = {
+	.open = ice40_dbg_cmd_open,
+	.write = ice40_dbg_cmd_write,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static int ice40_debugfs_init(struct ice40_hcd *ihcd)
+{
+	struct dentry *dir;
+	int ret = 0;
+
+	dir = debugfs_create_dir("ice40_hcd", NULL);
+
+	if (!dir || IS_ERR(dir)) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	ihcd->dbg_root = dir;
+
+	dir = debugfs_create_file("command", S_IWUSR, ihcd->dbg_root, ihcd,
+			&ice40_dbg_cmd_ops);
+
+	if (!dir) {
+		debugfs_remove_recursive(ihcd->dbg_root);
+		ihcd->dbg_root = NULL;
+		ret = -ENODEV;
+	}
+
+out:
+	return ret;
+}
+
+static int ice40_spi_probe(struct spi_device *spi)
+{
+	struct ice40_hcd *ihcd;
+	int ret;
+
+	ihcd = devm_kzalloc(&spi->dev, sizeof(*ihcd), GFP_KERNEL);
+	if (!ihcd) {
+		pr_err("fail to allocate ihcd\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+	ihcd->spi = spi;
+
+	ret = ice40_spi_parse_dt(ihcd);
+	if (ret) {
+		pr_err("fail to parse dt node\n");
+		goto out;
+	}
+
+	ret = ice40_spi_init_regulators(ihcd);
+	if (ret) {
+		pr_err("fail to init regulators\n");
+		goto out;
+	}
+
+	ret = ice40_spi_request_gpios(ihcd);
+	if (ret) {
+		pr_err("fail to request gpios\n");
+		goto out;
+	}
+
+	spin_lock_init(&ihcd->lock);
+	INIT_LIST_HEAD(&ihcd->async_list);
+	INIT_WORK(&ihcd->async_work, ice40_async_work);
+	mutex_init(&ihcd->wlock);
+	mutex_init(&ihcd->rlock);
+
+	/*
+	 * Enable all our trace points. Useful in debugging card
+	 * enumeration issues.
+	 */
+	ret = trace_set_clr_event(__stringify(TRACE_SYSTEM), NULL, 1);
+	if (ret < 0)
+		pr_err("fail to enable trace points with %d\n", ret);
+
+	ihcd->wq = create_singlethread_workqueue("ice40_wq");
+	if (!ihcd->wq) {
+		pr_err("fail to create workqueue\n");
+		ret = -ENOMEM;
+		goto destroy_mutex;
+	}
+
+	ret = ice40_spi_init_xfrs(ihcd);
+	if (ret) {
+		pr_err("fail to init spi xfrs %d\n", ret);
+		goto destroy_wq;
+	}
+
+	ret = ice40_spi_cache_fw(ihcd);
+	if (ret) {
+		pr_err("fail to cache fw %d\n", ret);
+		goto destroy_wq;
+	}
+
+	ret = ice40_spi_load_fw(ihcd);
+	if (ret) {
+		pr_err("fail to load fw %d\n", ret);
+		goto destroy_wq;
+	}
+
+	ihcd->hcd = usb_create_hcd(&ice40_hc_driver, &spi->dev, "ice40");
+	if (!ihcd->hcd) {
+		pr_err("fail to alloc hcd\n");
+		ret = -ENOMEM;
+		goto power_off;
+	}
+	*((struct ice40_hcd **) ihcd->hcd->hcd_priv) = ihcd;
+
+	ret = usb_add_hcd(ihcd->hcd, 0, 0);
+
+	if (ret < 0) {
+		pr_err("fail to add HCD\n");
+		goto put_hcd;
+	}
+
+	ice40_debugfs_init(ihcd);
+
+	/*
+	 * We manage the power states of the bridge chip
+	 * as part of root hub suspend/resume. We don't
+	 * need to implement any additional runtime PM
+	 * methods.
+	 */
+	pm_runtime_no_callbacks(&spi->dev);
+	pm_runtime_set_active(&spi->dev);
+	pm_runtime_enable(&spi->dev);
+
+	/*
+	 * This does not mean bridge chip can wakeup the
+	 * system from sleep. It's activity can prevent
+	 * or abort the system sleep. The device_init_wakeup
+	 * creates the wakeup source for us which we will
+	 * use to control system sleep.
+	 */
+	device_init_wakeup(&spi->dev, 1);
+	pm_stay_awake(&spi->dev);
+
+	pr_debug("success\n");
+
+	return 0;
+
+put_hcd:
+	usb_put_hcd(ihcd->hcd);
+power_off:
+	ice40_spi_power_off(ihcd);
+destroy_wq:
+	destroy_workqueue(ihcd->wq);
+destroy_mutex:
+	mutex_destroy(&ihcd->rlock);
+	mutex_destroy(&ihcd->wlock);
+out:
+	pr_info("ice40_spi_probe failed\n");
+	return ret;
+}
+
+static int ice40_spi_remove(struct spi_device *spi)
+{
+	struct usb_hcd *hcd = spi_get_drvdata(spi);
+	struct ice40_hcd *ihcd = hcd_to_ihcd(hcd);
+
+	debugfs_remove_recursive(ihcd->dbg_root);
+
+	usb_remove_hcd(hcd);
+	usb_put_hcd(hcd);
+	destroy_workqueue(ihcd->wq);
+	ice40_spi_power_off(ihcd);
+
+	pm_runtime_disable(&spi->dev);
+	pm_relax(&spi->dev);
+
+	return 0;
+}
+
+static struct of_device_id ice40_spi_of_match_table[] = {
+	{ .compatible = "lattice,ice40-spi-usb", },
+	{},
+};
+
+static struct spi_driver ice40_spi_driver = {
+	.driver = {
+		.name =		"ice40_spi",
+		.owner =	THIS_MODULE,
+		.of_match_table = ice40_spi_of_match_table,
+	},
+	.probe =	ice40_spi_probe,
+	.remove =	ice40_spi_remove,
+};
+
+module_spi_driver(ice40_spi_driver);
+
+MODULE_DESCRIPTION("ICE40 FPGA based SPI-USB bridge HCD");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index fa702ae..9d13091 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -588,6 +588,26 @@
 	list_del(&t->transfer_list);
 }
 
+/**
+ * spi_message_init_with_transfers - Initialize spi_message and append transfers
+ * @m: spi_message to be initialized
+ * @xfers: An array of spi transfers
+ * @num_xfers: Number of items in the xfer array
+ *
+ * This function initializes the given spi_message and adds each spi_transfer in
+ * the given array to the message.
+ */
+static inline void
+spi_message_init_with_transfers(struct spi_message *m,
+struct spi_transfer *xfers, unsigned int num_xfers)
+{
+	unsigned int i;
+
+	spi_message_init(m);
+	for (i = 0; i < num_xfers; ++i)
+		spi_message_add_tail(&xfers[i], m);
+}
+
 /* It's fine to embed message and transaction structures in other data
  * structures so long as you don't free them while they're in use.
  */
@@ -680,6 +700,30 @@
 	return spi_sync(spi, &m);
 }
 
+/**
+ * spi_sync_transfer - synchronous SPI data transfer
+ * @spi: device with which data will be exchanged
+ * @xfers: An array of spi_transfers
+ * @num_xfers: Number of items in the xfer array
+ * Context: can sleep
+ *
+ * Does a synchronous SPI data transfer of the given spi_transfer array.
+ *
+ * For more specific semantics see spi_sync().
+ *
+ * It returns zero on success, else a negative error code.
+ */
+static inline int
+spi_sync_transfer(struct spi_device *spi, struct spi_transfer *xfers,
+	unsigned int num_xfers)
+{
+	struct spi_message msg;
+
+	spi_message_init_with_transfers(&msg, xfers, num_xfers);
+
+	return spi_sync(spi, &msg);
+}
+
 /* this copies txbuf and rxbuf data; for small transfers only! */
 extern int spi_write_then_read(struct spi_device *spi,
 		const void *txbuf, unsigned n_tx,
diff --git a/include/trace/events/ice40.h b/include/trace/events/ice40.h
new file mode 100644
index 0000000..c0649a8
--- /dev/null
+++ b/include/trace/events/ice40.h
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM ice40
+
+#if !defined(_TRACE_ICE40_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_ICE40_H
+
+#include <linux/tracepoint.h>
+#include <linux/usb.h>
+
+TRACE_EVENT(ice40_reg_write,
+
+	TP_PROTO(u8 addr, u8 val, u8 cmd0, u8 cmd1, int ret),
+
+	TP_ARGS(addr, val, cmd0, cmd1, ret),
+
+	TP_STRUCT__entry(
+		__field(u8, addr)
+		__field(u8, val)
+		__field(u8, cmd0)
+		__field(u8, cmd1)
+		__field(int, ret)
+	),
+
+	TP_fast_assign(
+		__entry->addr = addr;
+		__entry->val = val;
+		__entry->cmd0 = cmd0;
+		__entry->cmd1 = cmd1;
+		__entry->ret = ret;
+	),
+
+	TP_printk("addr = %x val = %x cmd0 = %x cmd1 = %x ret = %d",
+			__entry->addr, __entry->val, __entry->cmd0,
+			__entry->cmd1, __entry->ret)
+);
+
+TRACE_EVENT(ice40_reg_read,
+
+	TP_PROTO(u8 addr, u8 cmd0, int ret),
+
+	TP_ARGS(addr, cmd0, ret),
+
+	TP_STRUCT__entry(
+		__field(u8, addr)
+		__field(u8, cmd0)
+		__field(int, ret)
+	),
+
+	TP_fast_assign(
+		__entry->addr = addr;
+		__entry->cmd0 = cmd0;
+		__entry->ret = ret;
+	),
+
+	TP_printk("addr = %x cmd0 = %x ret = %x", __entry->addr,
+			__entry->cmd0, __entry->ret)
+);
+
+TRACE_EVENT(ice40_hub_control,
+
+	TP_PROTO(u16 req, u16 val, u16 index, u16 len, int ret),
+
+	TP_ARGS(req, val, index, len, ret),
+
+	TP_STRUCT__entry(
+		__field(u16, req)
+		__field(u16, val)
+		__field(u16, index)
+		__field(u16, len)
+		__field(int, ret)
+	),
+
+	TP_fast_assign(
+		__entry->req = req;
+		__entry->val = val;
+		__entry->index = index;
+		__entry->len = len;
+		__entry->ret = ret;
+	),
+
+	TP_printk("req = %x val = %x index = %x len = %x ret = %d",
+			__entry->req, __entry->val, __entry->index,
+			__entry->len, __entry->ret)
+);
+
+TRACE_EVENT(ice40_ep0,
+
+	TP_PROTO(const char *state),
+
+	TP_ARGS(state),
+
+	TP_STRUCT__entry(
+		__string(state, state)
+	),
+
+	TP_fast_assign(
+		__assign_str(state, state);
+	),
+
+	TP_printk("ep0 state: %s", __get_str(state))
+);
+
+TRACE_EVENT(ice40_urb_enqueue,
+
+	TP_PROTO(struct urb *urb),
+
+	TP_ARGS(urb),
+
+	TP_STRUCT__entry(
+		__field(u16, epnum)
+		__field(u8, dir)
+		__field(u8, type)
+		__field(u32, len)
+	),
+
+	TP_fast_assign(
+		__entry->epnum = usb_pipeendpoint(urb->pipe);
+		__entry->dir = usb_urb_dir_in(urb);
+		__entry->type = usb_pipebulk(urb->pipe);
+		__entry->len = urb->transfer_buffer_length;
+	),
+
+	TP_printk("URB_LOG: E: ep %d %s %s len %d", __entry->epnum,
+			__entry->dir ? "In" : "Out",
+			__entry->type ? "Bulk" : "ctrl",
+			__entry->len)
+);
+
+TRACE_EVENT(ice40_urb_dequeue,
+
+	TP_PROTO(struct urb *urb),
+
+	TP_ARGS(urb),
+
+	TP_STRUCT__entry(
+		__field(u16, epnum)
+		__field(u8, dir)
+		__field(u8, type)
+		__field(u32, len)
+		__field(int, reason)
+	),
+
+	TP_fast_assign(
+		__entry->epnum = usb_pipeendpoint(urb->pipe);
+		__entry->dir = usb_urb_dir_in(urb);
+		__entry->type = usb_pipebulk(urb->pipe);
+		__entry->len = urb->transfer_buffer_length;
+		__entry->reason = urb->unlinked;
+	),
+
+	TP_printk("URB_LOG: D: ep %d %s %s len %d reason %d",
+			__entry->epnum,
+			__entry->dir ? "In" : "Out",
+			__entry->type ? "Bulk" : "ctrl",
+			__entry->len, __entry->reason)
+);
+
+TRACE_EVENT(ice40_urb_done,
+
+	TP_PROTO(struct urb *urb, int result),
+
+	TP_ARGS(urb, result),
+
+	TP_STRUCT__entry(
+		__field(int, result)
+		__field(u16, epnum)
+		__field(u8, dir)
+		__field(u8, type)
+		__field(u32, len)
+		__field(u32, actual)
+	),
+
+	TP_fast_assign(
+		__entry->result = result;
+		__entry->epnum = usb_pipeendpoint(urb->pipe);
+		__entry->dir = usb_urb_dir_in(urb);
+		__entry->type = usb_pipebulk(urb->pipe);
+		__entry->len = urb->transfer_buffer_length;
+		__entry->actual = urb->actual_length;
+	),
+
+	TP_printk("URB_LOG: C: ep %d %s %s len %d actual %d result %d",
+			__entry->epnum, __entry->dir ? "In" : "Out",
+			__entry->type ? "Bulk" : "ctrl", __entry->len,
+			__entry->actual, __entry->result)
+);
+
+TRACE_EVENT(ice40_bus_suspend,
+
+	TP_PROTO(u8 status),
+
+	TP_ARGS(status),
+
+	TP_STRUCT__entry(
+		__field(u8, status)
+	),
+
+	TP_fast_assign(
+		__entry->status = status;
+	),
+
+	TP_printk("bus_suspend status %d", __entry->status)
+);
+
+TRACE_EVENT(ice40_bus_resume,
+
+	TP_PROTO(u8 status),
+
+	TP_ARGS(status),
+
+	TP_STRUCT__entry(
+		__field(u8, status)
+	),
+
+	TP_fast_assign(
+		__entry->status = status;
+	),
+
+	TP_printk("bus_resume status %d", __entry->status)
+);
+
+TRACE_EVENT(ice40_setup,
+
+	TP_PROTO(const char *token, int ret),
+
+	TP_ARGS(token, ret),
+
+	TP_STRUCT__entry(
+		__string(token, token)
+		__field(int, ret)
+	),
+
+	TP_fast_assign(
+		__assign_str(token, token);
+		__entry->ret = ret;
+	),
+
+	TP_printk("Trace: SETUP %s ret %d",
+		__get_str(token), __entry->ret)
+);
+
+TRACE_EVENT(ice40_in,
+
+	TP_PROTO(u16 ep, const char *token, u8 len, u8 expected, int ret),
+
+	TP_ARGS(ep, token, len, expected, ret),
+
+	TP_STRUCT__entry(
+		__field(u16, ep)
+		__string(token, token)
+		__field(u8, len)
+		__field(u8, expected)
+		__field(int, ret)
+	),
+
+	TP_fast_assign(
+		__entry->ep = ep;
+		__assign_str(token, token);
+		__entry->len = len;
+		__entry->expected = expected;
+		__entry->ret = ret;
+	),
+
+	TP_printk("Trace: %d IN %s len %d expected %d ret %d",
+			__entry->ep, __get_str(token),
+			__entry->len, __entry->expected,
+			__entry->ret)
+);
+
+TRACE_EVENT(ice40_out,
+
+	TP_PROTO(u16 ep, const char *token, u8 len, int ret),
+
+	TP_ARGS(ep, token, len, ret),
+
+	TP_STRUCT__entry(
+		__field(u16, ep)
+		__string(token, token)
+		__field(u8, len)
+		__field(int, ret)
+	),
+
+	TP_fast_assign(
+		__entry->ep = ep;
+		__assign_str(token, token);
+		__entry->len = len;
+		__entry->ret = ret;
+	),
+
+	TP_printk("Trace: %d OUT %s len %d ret %d",
+			__entry->ep, __get_str(token),
+			__entry->len, __entry->ret)
+);
+#endif /* if !defined(_TRACE_ICE40_H) || defined(TRACE_HEADER_MULTI_READ) */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/mm/compaction.c b/mm/compaction.c
index 673142d..35bb243 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -243,7 +243,6 @@
 {
 	int nr_scanned = 0, total_isolated = 0;
 	struct page *cursor, *valid_page = NULL;
-	unsigned long nr_strict_required = end_pfn - blockpfn;
 	unsigned long flags;
 	bool locked = false;
 
@@ -256,11 +255,12 @@
 
 		nr_scanned++;
 		if (!pfn_valid_within(blockpfn))
-			continue;
+			goto isolate_fail;
+
 		if (!valid_page)
 			valid_page = page;
 		if (!PageBuddy(page))
-			continue;
+			goto isolate_fail;
 
 		/*
 		 * The zone lock must be held to isolate freepages.
@@ -281,12 +281,10 @@
 
 		/* Recheck this is a buddy page under lock */
 		if (!PageBuddy(page))
-			continue;
+			goto isolate_fail;
 
 		/* Found a free page, break it into order-0 pages */
 		isolated = split_free_page(page);
-		if (!isolated && strict)
-			break;
 		total_isolated += isolated;
 		for (i = 0; i < isolated; i++) {
 			list_add(&page->lru, freelist);
@@ -297,7 +295,13 @@
 		if (isolated) {
 			blockpfn += isolated - 1;
 			cursor += isolated - 1;
+			continue;
 		}
+
+isolate_fail:
+		if (strict)
+			break;
+
 	}
 
 	trace_mm_compaction_isolate_freepages(nr_scanned, total_isolated);
@@ -307,7 +311,7 @@
 	 * pages requested were isolated. If there were any failures, 0 is
 	 * returned and CMA will fail.
 	 */
-	if (strict && nr_strict_required > total_isolated)
+	if (strict && blockpfn < end_pfn)
 		total_isolated = 0;
 
 	if (locked)
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
index e3c8944..6b32064 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
@@ -47,8 +47,27 @@
 #define MODE_AMR_WB		0xD
 #define MODE_PCM		0xC
 #define MODE_4GV_NW		0xE
+#define MODE_G711		0xA
+#define MODE_G711A		0xF
 
-#define VOIP_MODE_MAX		MODE_4GV_NW
+enum msm_audio_g711a_frame_type {
+	MVS_G711A_SPEECH_GOOD,
+	MVS_G711A_SID,
+	MVS_G711A_NO_DATA,
+	MVS_G711A_ERASURE
+};
+
+enum msm_audio_g711a_mode {
+	MVS_G711A_MODE_MULAW,
+	MVS_G711A_MODE_ALAW
+};
+
+enum msm_audio_g711_mode {
+	MVS_G711_MODE_MULAW,
+	MVS_G711_MODE_ALAW
+};
+
+#define VOIP_MODE_MAX		MODE_G711A
 #define VOIP_RATE_MAX		23850
 
 enum format {
@@ -153,7 +172,7 @@
 	uint32_t evrc_max_rate;
 };
 
-static int voip_get_media_type(uint32_t mode,
+static int voip_get_media_type(uint32_t mode, uint32_t rate_type,
 				unsigned int samp_rate,
 				unsigned int *media_type);
 static int voip_get_rate_type(uint32_t mode,
@@ -358,6 +377,81 @@
 			list_add_tail(&buf_node->list, &prtd->out_queue);
 			break;
 		}
+		case MODE_G711:
+		case MODE_G711A:{
+			/* G711 frames are 10ms each, but the DSP works with
+			 * 20ms frames and sends two 10ms frames per buffer.
+			 * Extract the two frames and put them in separate
+			 * buffers.
+			 */
+			/* Remove the first DSP frame info header.
+			 * Header format: G711A
+			 * Bits 0-1: Frame type
+			 * Bits 2-3: Frame rate
+			 *
+			 * Header format: G711
+			 * Bits 2-3: Frame rate
+			 */
+			if (prtd->mode == MODE_G711A)
+				buf_node->frame.frm_hdr.frame_type =
+							(*voc_pkt) & 0x03;
+			buf_node->frame.frm_hdr.timestamp = timestamp;
+			voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+			/* There are two frames in the buffer. Length of the
+			 * first frame:
+			 */
+			buf_node->frame.pktlen = (pkt_len -
+						  2 * DSP_FRAME_HDR_LEN) / 2;
+
+			memcpy(&buf_node->frame.voc_pkt[0],
+			       voc_pkt,
+			       buf_node->frame.pktlen);
+			voc_pkt = voc_pkt + buf_node->frame.pktlen;
+
+			list_add_tail(&buf_node->list, &prtd->out_queue);
+
+			/* Get another buffer from the free Q and fill in the
+			 * second frame.
+			 */
+			if (!list_empty(&prtd->free_out_queue)) {
+				buf_node =
+					list_first_entry(&prtd->free_out_queue,
+							 struct voip_buf_node,
+							 list);
+				list_del(&buf_node->list);
+
+				/* Remove the second DSP frame info header.
+				 * Header format:
+				 * Bits 0-1: Frame type
+				 * Bits 2-3: Frame rate
+				 */
+
+				if (prtd->mode == MODE_G711A)
+					buf_node->frame.frm_hdr.frame_type =
+							(*voc_pkt) & 0x03;
+				buf_node->frame.frm_hdr.timestamp = timestamp;
+				voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+				/* There are two frames in the buffer. Length
+				 * of the second frame:
+				 */
+				buf_node->frame.pktlen = (pkt_len -
+						2 * DSP_FRAME_HDR_LEN) / 2;
+
+				memcpy(&buf_node->frame.voc_pkt[0],
+				       voc_pkt,
+				       buf_node->frame.pktlen);
+
+				list_add_tail(&buf_node->list,
+					      &prtd->out_queue);
+			} else {
+				/* Drop the second frame */
+				pr_err("%s: UL data dropped, read is slow\n",
+				       __func__);
+			}
+			break;
+		}
 		default: {
 			buf_node->frame.frm_hdr.timestamp = timestamp;
 			buf_node->frame.pktlen = pkt_len;
@@ -389,6 +483,8 @@
 	unsigned long dsp_flags;
 	uint32_t rate_type;
 	uint32_t frame_rate;
+	u32 pkt_len;
+	u8 *voc_addr = NULL;
 
 	if (prtd->playback_substream == NULL)
 		return;
@@ -454,6 +550,70 @@
 			list_add_tail(&buf_node->list, &prtd->free_in_queue);
 			break;
 		}
+		case MODE_G711:
+		case MODE_G711A:{
+			/* G711 frames are 10ms each but the DSP expects 20ms
+			 * worth of data, so send two 10ms frames per buffer.
+			 */
+			/* Add the first DSP frame info header. Header format:
+			 * Bits 0-1: Frame type
+			 * Bits 2-3: Frame rate
+			 */
+			voc_addr = voc_pkt;
+			voc_pkt = voc_pkt + sizeof(uint32_t);
+
+			*voc_pkt = ((prtd->rate_type  & 0x0F) << 2) |
+				    (buf_node->frame.frm_hdr.frame_type & 0x03);
+			voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+			pkt_len = buf_node->frame.pktlen + DSP_FRAME_HDR_LEN;
+
+			memcpy(voc_pkt,
+			       &buf_node->frame.voc_pkt[0],
+			       buf_node->frame.pktlen);
+			voc_pkt = voc_pkt + buf_node->frame.pktlen;
+
+			list_add_tail(&buf_node->list, &prtd->free_in_queue);
+
+			if (!list_empty(&prtd->in_queue)) {
+				/* Get the second buffer. */
+				buf_node = list_first_entry(&prtd->in_queue,
+							struct voip_buf_node,
+							list);
+				list_del(&buf_node->list);
+
+				/* Add the second DSP frame info header.
+				 * Header format:
+				 * Bits 0-1: Frame type
+				 * Bits 2-3: Frame rate
+				 */
+				*voc_pkt = ((prtd->rate_type & 0x0F) << 2) |
+				(buf_node->frame.frm_hdr.frame_type & 0x03);
+				voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+				pkt_len = pkt_len + buf_node->frame.pktlen +
+					   DSP_FRAME_HDR_LEN;
+
+				memcpy(voc_pkt,
+				       &buf_node->frame.voc_pkt[0],
+				       buf_node->frame.pktlen);
+
+				list_add_tail(&buf_node->list,
+					      &prtd->free_in_queue);
+			} else {
+				/* Only 10ms worth of data is available, signal
+				 * erasure frame.
+				 */
+				*voc_pkt = ((prtd->rate_type & 0x0F) << 2) |
+					    (MVS_G711A_ERASURE & 0x03);
+
+				pkt_len = pkt_len + DSP_FRAME_HDR_LEN;
+				pr_debug("%s, Only 10ms read, erase 2nd frame\n",
+					 __func__);
+			}
+			*((uint32_t *)voc_addr) = pkt_len;
+			break;
+		}
 		default: {
 			*((uint32_t *)voc_pkt) = buf_node->frame.pktlen;
 			voc_pkt = voc_pkt + sizeof(uint32_t);
@@ -829,10 +989,12 @@
         pr_debug("%s(): mode=%d, playback sample rate=%d, capture sample rate=%d\n",
                   __func__, prtd->mode, prtd->play_samp_rate, prtd->cap_samp_rate);
 
-	if ((runtime->format != FORMAT_S16_LE) && ((prtd->mode == MODE_PCM) ||
-	    (prtd->mode == MODE_AMR) || (prtd->mode == MODE_AMR_WB) ||
+	if ((runtime->format != FORMAT_S16_LE &&
+	     runtime->format != FORMAT_SPECIAL) &&
+	    ((prtd->mode == MODE_AMR) || (prtd->mode == MODE_AMR_WB) ||
 	    (prtd->mode == MODE_IS127) || (prtd->mode == MODE_4GV_NB) ||
-	    (prtd->mode == MODE_4GV_WB) || (prtd->mode == MODE_4GV_NW))) {
+	    (prtd->mode == MODE_4GV_WB) || (prtd->mode == MODE_4GV_NW) ||
+	    (prtd->mode == MODE_G711) || (prtd->mode == MODE_G711A))) {
 		pr_err("%s(): mode:%d and format:%u are not matched\n",
 			__func__, prtd->mode, (uint32_t)runtime->format);
 
@@ -840,21 +1002,19 @@
 		goto done;
 	}
 
-	ret = voip_get_media_type(prtd->mode,
-				  prtd->play_samp_rate,
-				  &media_type);
-	if (ret < 0) {
-		pr_err("%s(): fail at getting media_type, ret=%d\n",
-			__func__, ret);
+	if (runtime->format != FORMAT_S16_LE && (prtd->mode == MODE_PCM)) {
+		pr_err("%s(): mode:%d and format:%u are not matched\n",
+		       __func__, prtd->mode, runtime->format);
 
-		ret = -EINVAL;
+		ret =  -EINVAL;
 		goto done;
 	}
-	pr_debug("%s(): media_type=%d\n", __func__, media_type);
 
 	if ((prtd->mode == MODE_PCM) ||
 	    (prtd->mode == MODE_AMR) ||
-	    (prtd->mode == MODE_AMR_WB)) {
+	    (prtd->mode == MODE_AMR_WB) ||
+	    (prtd->mode == MODE_G711) ||
+	    (prtd->mode == MODE_G711A)) {
 		ret = voip_get_rate_type(prtd->mode,
 					 prtd->rate,
 					 &rate_type);
@@ -909,6 +1069,19 @@
 		pr_debug("%s(): min rate=%d, max rate=%d\n",
 			  __func__, evrc_min_rate_type, evrc_max_rate_type);
 	}
+	ret = voip_get_media_type(prtd->mode,
+				  prtd->rate_type,
+				  prtd->play_samp_rate,
+				  &media_type);
+	if (ret < 0) {
+		pr_err("%s(): fail at getting media_type, ret=%d\n",
+		       __func__, ret);
+
+		ret = -EINVAL;
+		goto done;
+	}
+	pr_debug("%s(): media_type=%d\n", __func__, media_type);
+
 	if ((prtd->play_samp_rate == 8000) &&
 	    (prtd->cap_samp_rate == 8000))
 		voc_config_vocoder(media_type, rate_type,
@@ -1285,6 +1458,10 @@
 		}
 		break;
 	}
+	case MODE_G711:
+	case MODE_G711A:
+		*rate_type = rate;
+		break;
 	default:
 		pr_err("wrong mode type.\n");
 		ret = -EINVAL;
@@ -1294,9 +1471,9 @@
 	return ret;
 }
 
-static int voip_get_media_type(uint32_t mode,
-				unsigned int samp_rate,
-				unsigned int *media_type)
+static int voip_get_media_type(uint32_t mode, uint32_t rate_type,
+			       unsigned int samp_rate,
+			       unsigned int *media_type)
 {
 	int ret = 0;
 
@@ -1327,6 +1504,13 @@
 	case MODE_4GV_NW: /* EVRC-NW */
 		*media_type = VSS_MEDIA_ID_4GV_NW_MODEM;
 		break;
+	case MODE_G711:
+	case MODE_G711A:
+		if (rate_type == MVS_G711A_MODE_MULAW)
+			*media_type = VSS_MEDIA_ID_G711_MULAW;
+		else
+			*media_type = VSS_MEDIA_ID_G711_ALAW;
+		break;
 	default:
 		pr_debug(" input mode is not supported\n");
 		ret = -EINVAL;
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index c36b53a..badc3c3 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -453,7 +453,7 @@
 	q6asm_add_hdr_custom_topology(ac, &asm_top.hdr,
 				      APR_PKT_SIZE(APR_HDR_SIZE,
 					sizeof(asm_top)), TRUE);
-
+	atomic_set(&ac->cmd_state, 1);
 	asm_top.hdr.opcode = ASM_CMD_ADD_TOPOLOGIES;
 	asm_top.payload_addr_lsw = cal_block.cal_paddr;
 	asm_top.payload_addr_msw = 0;
@@ -1626,7 +1626,6 @@
 	hdr->dest_port = ((ac->session << 8) & 0xFF00) | (stream_id);
 	if (cmd_flg) {
 		hdr->token = ac->session;
-		atomic_set(&ac->cmd_state, 1);
 	}
 	hdr->pkt_size  = pkt_size;
 	mutex_unlock(&ac->cmd_lock);
@@ -1667,7 +1666,6 @@
 	hdr->dest_port = ((ac->session << 8) & 0xFF00) | (stream_id);
 	if (cmd_flg) {
 		hdr->token = ac->session;
-		atomic_set(&ac->cmd_state, 1);
 	}
 	hdr->pkt_size  = pkt_size;
 	return;
@@ -1711,7 +1709,6 @@
 	hdr->dest_port = 0;
 	if (cmd_flg) {
 		hdr->token = ((ac->session << 8) | 0x0001) ;
-		atomic_set(&ac->cmd_state, 1);
 	}
 	hdr->pkt_size  = pkt_size;
 	mutex_unlock(&ac->cmd_lock);
@@ -1728,7 +1725,6 @@
 	hdr->dest_port = 0;
 	if (cmd_flg) {
 		hdr->token = token;
-		atomic_set(&ac->cmd_state, 1);
 	}
 	hdr->pkt_size  = pkt_size;
 	return;
@@ -1748,6 +1744,7 @@
 	pr_debug("%s:session[%d]", __func__, ac->session);
 
 	q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 	open.hdr.opcode = ASM_STREAM_CMD_OPEN_READ_V3;
 	/* Stream prio : High, provide meta info with encoded frames */
 	open.src_endpointype = ASM_END_POINT_DEVICE_MATRIX;
@@ -1841,7 +1838,7 @@
 		format);
 
 	q6asm_stream_add_hdr(ac, &open.hdr, sizeof(open), TRUE, stream_id);
-
+	atomic_set(&ac->cmd_state, 1);
 	/*
 	 * Updated the token field with stream/session for compressed playback
 	 * Platform driver must know the the stream with which the command is
@@ -1959,6 +1956,7 @@
 
 	ac->io_mode |= NT_MODE;
 	q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 	open.hdr.opcode = ASM_STREAM_CMD_OPEN_READWRITE_V2;
 
 	open.mode_flags = BUFFER_META_ENABLE;
@@ -2068,6 +2066,7 @@
 	pr_debug("%s: session[%d]", __func__, ac->session);
 
 	q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 	open.hdr.opcode = ASM_STREAM_CMD_OPEN_LOOPBACK_V2;
 
 	open.mode_flags = 0;
@@ -2110,6 +2109,7 @@
 	}
 	pr_debug("%s session[%d]", __func__, ac->session);
 	q6asm_add_hdr(ac, &run.hdr, sizeof(run), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 
 	run.hdr.opcode = ASM_SESSION_CMD_RUN_V2;
 	run.flags    = flags;
@@ -2147,7 +2147,7 @@
 	}
 	pr_debug("session[%d]", ac->session);
 	q6asm_stream_add_hdr_async(ac, &run.hdr, sizeof(run), TRUE, stream_id);
-
+	atomic_set(&ac->cmd_state, 1);
 	run.hdr.opcode = ASM_SESSION_CMD_RUN_V2;
 	run.flags    = flags;
 	run.time_lsw = lsw_ts;
@@ -2189,6 +2189,7 @@
 		sample_rate, channels, bit_rate, mode, format);
 
 	q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 
 	enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
 	enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
@@ -2229,6 +2230,7 @@
 	pr_debug("%s: Session %d, num_channels = %d\n",
 			 __func__, ac->session, num_channels);
 	q6asm_add_hdr(ac, &chan_map.hdr, sizeof(chan_map), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 	chan_map.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
 	chan_map.encdec.param_id = ASM_PARAM_ID_DEC_OUTPUT_CHAN_MAP;
 	chan_map.encdec.param_size = sizeof(struct asm_dec_out_chan_map_param) -
@@ -2273,6 +2275,7 @@
 			 ac->session, rate, channels);
 
 	q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 	enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
 	enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
 	enc_cfg.encdec.param_size = sizeof(enc_cfg) - sizeof(enc_cfg.hdr) -
@@ -2334,7 +2337,7 @@
 			 ac->session, rate, channels);
 
 	q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
-
+	atomic_set(&ac->cmd_state, 1);
 	enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
 	enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
 	enc_cfg.encdec.param_size = sizeof(enc_cfg) - sizeof(enc_cfg.hdr) -
@@ -2433,6 +2436,7 @@
 	pr_debug("%s: Session %d\n", __func__, ac->session);
 
 	q6asm_add_hdr(ac, &sbrps.hdr, sizeof(sbrps), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 
 	sbrps.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
 	sbrps.encdec.param_id = ASM_PARAM_ID_AAC_SBR_PS_FLAG;
@@ -2474,6 +2478,7 @@
 			 __func__, ac->session, sce_left, sce_right);
 
 	q6asm_add_hdr(ac, &dual_mono.hdr, sizeof(dual_mono), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 
 	dual_mono.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
 	dual_mono.encdec.param_id = ASM_PARAM_ID_AAC_DUAL_MONO_MAPPING;
@@ -2509,6 +2514,7 @@
 	int rc = 0;
 
 	q6asm_add_hdr(ac, &aac_mix_coeff.hdr, sizeof(aac_mix_coeff), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 	aac_mix_coeff.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
 	aac_mix_coeff.param_id =
 		ASM_PARAM_ID_AAC_STEREO_MIX_COEFF_SELECTION_FLAG_V2;
@@ -2549,6 +2555,7 @@
 		reduced_rate_level, rate_modulation_cmd);
 
 	q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 	enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
 	enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
 	enc_cfg.encdec.param_size = sizeof(struct asm_v13k_enc_cfg) -
@@ -2590,6 +2597,7 @@
 		frames_per_buf,	min_rate, max_rate, rate_modulation_cmd);
 
 	q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 	enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
 	enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
 	enc_cfg.encdec.param_size = sizeof(struct asm_evrc_enc_cfg) -
@@ -2629,6 +2637,7 @@
 		__func__, ac->session, frames_per_buf, band_mode, dtx_enable);
 
 	q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 	enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
 	enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
 	enc_cfg.encdec.param_size = sizeof(struct asm_amrnb_enc_cfg) -
@@ -2666,6 +2675,7 @@
 		__func__, ac->session, frames_per_buf, band_mode, dtx_enable);
 
 	q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 	enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
 	enc_cfg.encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2;
 	enc_cfg.encdec.param_size = sizeof(struct asm_amrwb_enc_cfg) -
@@ -2706,6 +2716,7 @@
 		channels);
 
 	q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 
 	fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
 	fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
@@ -2766,6 +2777,7 @@
 		channels);
 
 	q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 
 	fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
 	fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
@@ -2834,7 +2846,7 @@
 		cfg->sample_rate, cfg->ch_cfg);
 
 	q6asm_stream_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE, stream_id);
-
+	atomic_set(&ac->cmd_state, 1);
 	/*
 	 * Updated the token field with stream/session for compressed playback
 	 * Platform driver must know the the stream with which the command is
@@ -2910,6 +2922,7 @@
 		wma_cfg->ch_mask, wma_cfg->encode_opt);
 
 	q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 
 	fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
 	fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
@@ -2955,6 +2968,7 @@
 		wmapro_cfg->adv_encode_opt, wmapro_cfg->adv_encode_opt2);
 
 	q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 
 	fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
 	fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
@@ -3002,6 +3016,7 @@
 		cfg->num_channels);
 
 	q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 
 	fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
 	fmt.fmtblk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
@@ -3033,6 +3048,7 @@
 	pr_debug("%s: session[%d]param_id[%d]param_value[%d]", __func__,
 			ac->session, param_id, param_value);
 	q6asm_add_hdr(ac, &ddp_cfg.hdr, sizeof(ddp_cfg), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 	ddp_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
 	ddp_cfg.encdec.param_id = param_id;
 	ddp_cfg.encdec.param_size = sizeof(struct asm_dec_ddp_endp_param_v2) -
@@ -3093,6 +3109,7 @@
 							mmap_region_cmd;
 	q6asm_add_mmaphdr(ac, &mmap_regions->hdr, cmd_size,
 			TRUE, ((ac->session << 8) | dir));
+	atomic_set(&ac->cmd_state, 1);
 	mmap_regions->hdr.opcode = ASM_CMD_SHARED_MEM_MAP_REGIONS;
 	mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL;
 	mmap_regions->num_regions = bufcnt & 0x00ff;
@@ -3156,7 +3173,7 @@
 	q6asm_add_mmaphdr(ac, &mem_unmap.hdr,
 			sizeof(struct avs_cmd_shared_mem_unmap_regions),
 			TRUE, ((ac->session << 8) | dir));
-
+	atomic_set(&ac->cmd_state, 1);
 	mem_unmap.hdr.opcode = ASM_CMD_SHARED_MEM_UNMAP_REGIONS;
 	list_for_each_safe(ptr, next, &ac->port[dir].mem_map_handle) {
 		buf_node = list_entry(ptr, struct asm_buffer_node,
@@ -3254,6 +3271,7 @@
 							mmap_region_cmd;
 	q6asm_add_mmaphdr(ac, &mmap_regions->hdr, cmd_size, TRUE,
 					((ac->session << 8) | dir));
+	atomic_set(&ac->cmd_state, 1);
 	pr_debug("mmap_region=0x%p token=0x%x\n",
 		mmap_regions, ((ac->session << 8) | dir));
 
@@ -3335,6 +3353,7 @@
 	cmd_size = sizeof(struct avs_cmd_shared_mem_unmap_regions);
 	q6asm_add_mmaphdr(ac, &mem_unmap.hdr, cmd_size,
 			TRUE, ((ac->session << 8) | dir));
+	atomic_set(&ac->cmd_state, 1);
 	port = &ac->port[dir];
 	buf_add = (uint32_t)port->buf->phys;
 	mem_unmap.hdr.opcode = ASM_CMD_SHARED_MEM_UNMAP_REGIONS;
@@ -3392,6 +3411,7 @@
 
 	sz = sizeof(struct asm_volume_ctrl_lr_chan_gain);
 	q6asm_add_hdr_async(ac, &lrgain.hdr, sz, TRUE);
+	atomic_set(&ac->cmd_state, 1);
 	lrgain.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
 	lrgain.param.data_payload_addr_lsw = 0;
 	lrgain.param.data_payload_addr_msw = 0;
@@ -3440,6 +3460,7 @@
 
 	sz = sizeof(struct asm_volume_ctrl_mute_config);
 	q6asm_add_hdr_async(ac, &mute.hdr, sz, TRUE);
+	atomic_set(&ac->cmd_state, 1);
 	mute.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
 	mute.param.data_payload_addr_lsw = 0;
 	mute.param.data_payload_addr_msw = 0;
@@ -3487,6 +3508,7 @@
 
 	sz = sizeof(struct asm_volume_ctrl_master_gain);
 	q6asm_add_hdr_async(ac, &vol.hdr, sz, TRUE);
+	atomic_set(&ac->cmd_state, 1);
 	vol.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
 	vol.param.data_payload_addr_lsw = 0;
 	vol.param.data_payload_addr_msw = 0;
@@ -3535,6 +3557,7 @@
 
 	sz = sizeof(struct asm_soft_pause_params);
 	q6asm_add_hdr_async(ac, &softpause.hdr, sz, TRUE);
+	atomic_set(&ac->cmd_state, 1);
 	softpause.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
 
 	softpause.param.data_payload_addr_lsw = 0;
@@ -3588,6 +3611,7 @@
 
 	sz = sizeof(struct asm_soft_step_volume_params);
 	q6asm_add_hdr_async(ac, &softvol.hdr, sz, TRUE);
+	atomic_set(&ac->cmd_state, 1);
 	softvol.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
 	softvol.param.data_payload_addr_lsw = 0;
 	softvol.param.data_payload_addr_msw = 0;
@@ -3646,6 +3670,7 @@
 	sz = sizeof(struct asm_eq_params);
 	eq_params = (struct msm_audio_eq_stream_config *) eq_p;
 	q6asm_add_hdr(ac, &eq.hdr, sz, TRUE);
+	atomic_set(&ac->cmd_state, 1);
 
 	eq.hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
 	eq.param.data_payload_addr_lsw = 0;
@@ -3848,7 +3873,6 @@
 
 	q6asm_stream_add_hdr_async(
 			ac, &write.hdr, sizeof(write), FALSE, ac->stream_id);
-
 	port = &ac->port[IN];
 	ab = &port->buf[port->dsp_buf];
 
@@ -4157,6 +4181,7 @@
 	q6asm_add_hdr_async(ac, &hdr, (sizeof(struct apr_hdr) +
 			    sizeof(struct asm_stream_cmd_set_pp_params_v2) +
 			    params_length), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 	hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS_V2;
 	payload_params.data_payload_addr_lsw = 0;
 	payload_params.data_payload_addr_msw = 0;
@@ -4197,7 +4222,7 @@
 		return -EINVAL;
 	}
 	q6asm_stream_add_hdr(ac, &hdr, sizeof(hdr), TRUE, stream_id);
-
+	atomic_set(&ac->cmd_state, 1);
 	/*
 	 * Updated the token field with stream/session for compressed playback
 	 * Platform driver must know the the stream with which the command is
@@ -4306,7 +4331,7 @@
 		return -EINVAL;
 	}
 	q6asm_stream_add_hdr_async(ac, &hdr, sizeof(hdr), TRUE, stream_id);
-
+	atomic_set(&ac->cmd_state, 1);
 	/*
 	 * Updated the token field with stream/session for compressed playback
 	 * Platform driver must know the the stream with which the command is
@@ -4464,6 +4489,7 @@
 	pr_debug("%s:session[%d]enable[%d]\n", __func__,
 						ac->session, enable);
 	q6asm_add_hdr(ac, &tx_overflow.hdr, sizeof(tx_overflow), TRUE);
+	atomic_set(&ac->cmd_state, 1);
 
 	tx_overflow.hdr.opcode = \
 			ASM_SESSION_CMD_REGISTER_FORX_OVERFLOW_EVENTS;
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 2f9e319..56efb97 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -2308,6 +2308,7 @@
 		if (ret < 0) {
 			dev_err(dapm->dev, "Failed to add route %s->%s\n",
 				route->source, route->sink);
+			mutex_unlock(&dapm->card->dapm_mutex);
 			return ret;
 		}
 		route++;
@@ -3017,6 +3018,7 @@
 			dev_err(dapm->dev,
 				"ASoC: Failed to create DAPM control %s: %d\n",
 				widget->name, ret);
+			mutex_unlock(&dapm->card->dapm_mutex);
 			return ret;
 		}
 		widget++;