Merge "platform: msm8909: Initial support for QUP SPI"
diff --git a/platform/msm8909/acpuclock.c b/platform/msm8909/acpuclock.c
old mode 100644
new mode 100755
index ed2cbfc..48e25ac
--- a/platform/msm8909/acpuclock.c
+++ b/platform/msm8909/acpuclock.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2015,2018, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -474,3 +474,37 @@
 		return;
 	}
 }
+
+/* Configure spi clock */
+void clock_config_blsp_spi(uint8_t blsp_id, uint8_t qup_id)
+{
+	uint8_t ret = 0;
+	char clk_name[64];
+
+	struct clk *qup_clk;
+	qup_id = qup_id + 1;
+
+	if((blsp_id != BLSP_ID_1)) {
+		dprintf(CRITICAL, "Incorrect BLSP-%d configuration\n", blsp_id);
+		ASSERT(0);
+	}
+
+	snprintf(clk_name, sizeof(clk_name), "blsp1_ahb_iface_clk");
+
+	ret = clk_get_set_enable(clk_name, 0 , 1);
+
+	if (ret) {
+		dprintf(CRITICAL, "%s: Failed to enable %s clock\n", __func__, clk_name);
+		return;
+	}
+
+	snprintf(clk_name, sizeof(clk_name), "gcc_blsp1_qup%u_spi_apps_clk", qup_id);
+
+	/* Set the highest clk frequency by default for good performance. */
+	ret = clk_get_set_enable(clk_name, 50000000, 1);
+
+	if (ret) {
+		dprintf(CRITICAL, "%s: Failed to enable %s\n", __func__, clk_name);
+		return;
+	}
+}
diff --git a/platform/msm8909/gpio.c b/platform/msm8909/gpio.c
old mode 100644
new mode 100755
index 7621bb8..4bd9172
--- a/platform/msm8909/gpio.c
+++ b/platform/msm8909/gpio.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014,2018, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -141,3 +141,62 @@
 		ASSERT(0);
 	}
 }
+
+void gpio_config_blsp_spi(uint8_t blsp_id, uint8_t qup_id)
+{
+	if(blsp_id == BLSP_ID_1) {
+		switch (qup_id) {
+
+			case QUP_ID_3:
+				/* configure SPI MOSI gpio */
+				gpio_tlmm_config(12, 1, GPIO_OUTPUT, GPIO_NO_PULL,
+					GPIO_16MA, GPIO_DISABLE);
+
+					/* configure SPI MISO gpio */
+				gpio_tlmm_config(13, 1, GPIO_OUTPUT, GPIO_NO_PULL,
+					GPIO_16MA, GPIO_DISABLE);
+
+				/* configure SPI CS_N gpio */
+				gpio_tlmm_config(14, 1, GPIO_OUTPUT, GPIO_NO_PULL,
+					GPIO_16MA, GPIO_DISABLE);
+
+				/* configure SPI CLK gpio */
+				gpio_tlmm_config(15, 1, GPIO_OUTPUT, GPIO_NO_PULL,
+					GPIO_16MA, GPIO_DISABLE);
+			break;
+
+			case QUP_ID_4:
+				/* configure SPI MOSI gpio */
+				gpio_tlmm_config(16, 1, GPIO_OUTPUT, GPIO_NO_PULL,
+					GPIO_16MA, GPIO_DISABLE);
+
+					/* configure SPI MISO gpio */
+				gpio_tlmm_config(17, 1, GPIO_OUTPUT, GPIO_NO_PULL,
+					GPIO_16MA, GPIO_DISABLE);
+
+				/* configure SPI CS_N gpio */
+				gpio_tlmm_config(18, 1, GPIO_OUTPUT, GPIO_NO_PULL,
+					GPIO_16MA, GPIO_DISABLE);
+
+				/* configure SPI CLK gpio */
+				gpio_tlmm_config(19, 1, GPIO_OUTPUT, GPIO_NO_PULL,
+					GPIO_16MA, GPIO_DISABLE);
+			break;
+
+			case QUP_ID_0:
+			case QUP_ID_1:
+
+			case QUP_ID_2:
+
+
+
+			case QUP_ID_5:
+			default:
+				dprintf(CRITICAL, "Incorrect QUP id %d\n",qup_id);
+				ASSERT(0);
+		};
+	} else {
+		dprintf(CRITICAL, "Incorrect BLSP id %d\n",blsp_id);
+		ASSERT(0);
+	}
+}
diff --git a/platform/msm8909/include/platform/clock.h b/platform/msm8909/include/platform/clock.h
index ce98437..da0f673 100644
--- a/platform/msm8909/include/platform/clock.h
+++ b/platform/msm8909/include/platform/clock.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014,2018, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -76,4 +76,5 @@
 void mdp_clock_enable(void);
 void mdp_clock_disable(void);
 void mdp_gdsc_ctrl(uint8_t enable);
+void clock_config_blsp_spi(uint8_t blsp_id, uint8_t qup_id);
 #endif
diff --git a/platform/msm8909/include/platform/gpio.h b/platform/msm8909/include/platform/gpio.h
old mode 100644
new mode 100755
index da40c1e..7101bfd
--- a/platform/msm8909/include/platform/gpio.h
+++ b/platform/msm8909/include/platform/gpio.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014, 2017-2018, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -61,4 +61,5 @@
 #define GPIO_OUT        BIT(1)
 
 void gpio_config_uart_dm(uint8_t id);
+void gpio_config_blsp_spi(uint8_t blsp_id, uint8_t qup_id);
 #endif
diff --git a/platform/msm8909/include/platform/iomap.h b/platform/msm8909/include/platform/iomap.h
old mode 100644
new mode 100755
index 4361afd..f860274
--- a/platform/msm8909/include/platform/iomap.h
+++ b/platform/msm8909/include/platform/iomap.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2015, 2017-2018, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -131,6 +131,27 @@
 #define GCC_BLSP1_QUP6_CFG_RCGR     (CLK_CTL_BASE + 0x7004)
 #define GCC_BLSP1_QUP6_CMD_RCGR     (CLK_CTL_BASE + 0x7000)
 
+#define GCC_BLSP1_QUP3_SPI_APPS_CBCR        (CLK_CTL_BASE + 0x401C)
+#define GCC_BLSP1_QUP3_SPI_APPS_CMD_RCGR    (CLK_CTL_BASE + 0x4024)
+#define GCC_BLSP1_QUP3_SPI_CFG_RCGR         (CLK_CTL_BASE + 0x4028)
+#define GCC_BLSP1_QUP3_SPI_APPS_M           (CLK_CTL_BASE + 0x402C)
+#define GCC_BLSP1_QUP3_SPI_APPS_N           (CLK_CTL_BASE + 0x4030)
+#define GCC_BLSP1_QUP3_SPI_APPS_D           (CLK_CTL_BASE + 0x4034)
+
+#define GCC_BLSP1_QUP4_SPI_APPS_CBCR        (CLK_CTL_BASE + 0x501C)
+#define GCC_BLSP1_QUP4_SPI_APPS_CMD_RCGR    (CLK_CTL_BASE + 0x5024)
+#define GCC_BLSP1_QUP4_SPI_CFG_RCGR         (CLK_CTL_BASE + 0x5028)
+#define GCC_BLSP1_QUP4_SPI_APPS_M           (CLK_CTL_BASE + 0x502C)
+#define GCC_BLSP1_QUP4_SPI_APPS_N           (CLK_CTL_BASE + 0x5030)
+#define GCC_BLSP1_QUP4_SPI_APPS_D           (CLK_CTL_BASE + 0x5034)
+
+#define GCC_BLSP1_QUP5_SPI_APPS_CBCR        (CLK_CTL_BASE + 0x601C)
+#define GCC_BLSP1_QUP5_SPI_APPS_CMD_RCGR    (CLK_CTL_BASE + 0x6024)
+#define GCC_BLSP1_QUP5_SPI_CFG_RCGR         (CLK_CTL_BASE + 0x6028)
+#define GCC_BLSP1_QUP5_SPI_APPS_M           (CLK_CTL_BASE + 0x602C)
+#define GCC_BLSP1_QUP5_SPI_APPS_N           (CLK_CTL_BASE + 0x6030)
+#define GCC_BLSP1_QUP5_SPI_APPS_D           (CLK_CTL_BASE + 0x6034)
+
 /* GPLL */
 #define GPLL0_STATUS                (CLK_CTL_BASE + 0x21024)
 #define GPLL0_MODE                  (CLK_CTL_BASE + 0x21000)
diff --git a/platform/msm8909/msm8909-clock.c b/platform/msm8909/msm8909-clock.c
index 04a7a42..433d18e 100644
--- a/platform/msm8909/msm8909-clock.c
+++ b/platform/msm8909/msm8909-clock.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014,2018, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -564,6 +564,99 @@
 	},
 };
 
+
+static struct clk_freq_tbl ftbl_gcc_blsp1_qup1_spi_apps_clk[] = {
+	F( 960000,	cxo,	10,	1,	2),
+	F( 4800000,	cxo,	4,	0,	0),
+	F( 9600000,	cxo,	2,	0,	0),
+	F( 16000000,	gpll0,	10,	1,	5),
+	F( 19200000,	cxo,	1,	0,	0),
+	F( 25000000,	gpll0,	16,	1,	2),
+	F( 50000000,	gpll0,	16,	0,	0),
+	F_END
+};
+
+static struct rcg_clk gcc_blsp1_qup3_spi_apps_clk_src =
+{
+	.cmd_reg      = (uint32_t *) GCC_BLSP1_QUP3_SPI_APPS_CMD_RCGR,
+	.cfg_reg      = (uint32_t *) GCC_BLSP1_QUP3_SPI_CFG_RCGR,
+	.m_reg        = (uint32_t *) GCC_BLSP1_QUP3_SPI_APPS_M,
+	.n_reg        = (uint32_t *) GCC_BLSP1_QUP3_SPI_APPS_N,
+	.d_reg        = (uint32_t *) GCC_BLSP1_QUP3_SPI_APPS_D,
+	.set_rate     = clock_lib2_rcg_set_rate_mnd,
+	.freq_tbl     = ftbl_gcc_blsp1_qup1_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+
+	.c = {
+		.dbg_name = "gcc_blsp1_qup3_spi_apps_clk_src",
+		.ops      = &clk_ops_rcg,
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup3_spi_apps_clk = {
+	.cbcr_reg = GCC_BLSP1_QUP3_SPI_APPS_CBCR,
+	.parent   = &gcc_blsp1_qup3_spi_apps_clk_src.c,
+
+	.c = {
+		.dbg_name = "gcc_blsp1_qup3_spi_apps_clk",
+		.ops      = &clk_ops_branch,
+	},
+};
+
+static struct rcg_clk gcc_blsp1_qup4_spi_apps_clk_src =
+{
+	.cmd_reg      = (uint32_t *) GCC_BLSP1_QUP4_SPI_APPS_CMD_RCGR,
+	.cfg_reg      = (uint32_t *) GCC_BLSP1_QUP4_SPI_CFG_RCGR,
+	.m_reg        = (uint32_t *) GCC_BLSP1_QUP4_SPI_APPS_M,
+	.n_reg        = (uint32_t *) GCC_BLSP1_QUP4_SPI_APPS_N,
+	.d_reg        = (uint32_t *) GCC_BLSP1_QUP4_SPI_APPS_D,
+	.set_rate     = clock_lib2_rcg_set_rate_mnd,
+	.freq_tbl     = ftbl_gcc_blsp1_qup1_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+
+	.c = {
+		.dbg_name = "gcc_blsp1_qup4_spi_apps_clk_src",
+		.ops      = &clk_ops_rcg,
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup4_spi_apps_clk = {
+	.cbcr_reg = GCC_BLSP1_QUP4_SPI_APPS_CBCR,
+	.parent   = &gcc_blsp1_qup4_spi_apps_clk_src.c,
+
+	.c = {
+		.dbg_name = "gcc_blsp1_qup4_spi_apps_clk",
+		.ops      = &clk_ops_branch,
+	},
+};
+
+static struct rcg_clk gcc_blsp1_qup5_spi_apps_clk_src =
+{
+	.cmd_reg      = (uint32_t *) GCC_BLSP1_QUP5_SPI_APPS_CMD_RCGR,
+	.cfg_reg      = (uint32_t *) GCC_BLSP1_QUP5_SPI_CFG_RCGR,
+	.m_reg        = (uint32_t *) GCC_BLSP1_QUP5_SPI_APPS_M,
+	.n_reg        = (uint32_t *) GCC_BLSP1_QUP5_SPI_APPS_N,
+	.d_reg        = (uint32_t *) GCC_BLSP1_QUP5_SPI_APPS_D,
+	.set_rate     = clock_lib2_rcg_set_rate_mnd,
+	.freq_tbl     = ftbl_gcc_blsp1_qup1_spi_apps_clk,
+	.current_freq = &rcg_dummy_freq,
+
+	.c = {
+		.dbg_name = "gcc_blsp1_qup5_spi_apps_clk_src",
+		.ops      = &clk_ops_rcg,
+	},
+};
+
+static struct branch_clk gcc_blsp1_qup5_spi_apps_clk = {
+	.cbcr_reg = GCC_BLSP1_QUP5_SPI_APPS_CBCR,
+	.parent   = &gcc_blsp1_qup5_spi_apps_clk_src.c,
+
+	.c = {
+		.dbg_name = "gcc_blsp1_qup5_spi_apps_clk",
+		.ops      = &clk_ops_branch,
+	},
+};
+
 /* Display clocks */
 static struct clk_freq_tbl ftbl_mdss_esc0_1_clk[] = {
 	F_MM(19200000,    cxo,   1,   0,   0),
@@ -714,6 +807,13 @@
 	CLK_LOOKUP("gcc_blsp1_qup5_i2c_apps_clk", gcc_blsp1_qup5_i2c_apps_clk.c),
 	CLK_LOOKUP("gcc_blsp1_qup6_i2c_apps_clk_src", gcc_blsp1_qup5_i2c_apps_clk_src.c),
 	CLK_LOOKUP("gcc_blsp1_qup6_i2c_apps_clk", gcc_blsp1_qup5_i2c_apps_clk.c),
+	CLK_LOOKUP("blsp1_ahb_iface_clk", gcc_blsp1_ahb_clk.c),
+	CLK_LOOKUP("gcc_blsp1_qup3_spi_apps_clk_src", gcc_blsp1_qup3_spi_apps_clk_src.c),
+	CLK_LOOKUP("gcc_blsp1_qup3_spi_apps_clk", gcc_blsp1_qup3_spi_apps_clk.c),
+	CLK_LOOKUP("gcc_blsp1_qup4_spi_apps_clk_src", gcc_blsp1_qup4_spi_apps_clk_src.c),
+	CLK_LOOKUP("gcc_blsp1_qup4_spi_apps_clk", gcc_blsp1_qup4_spi_apps_clk.c),
+	CLK_LOOKUP("gcc_blsp1_qup5_spi_apps_clk_src", gcc_blsp1_qup5_spi_apps_clk_src.c),
+	CLK_LOOKUP("gcc_blsp1_qup5_spi_apps_clk", gcc_blsp1_qup5_spi_apps_clk.c),
 
 	CLK_LOOKUP("mdp_ahb_clk", mdp_ahb_clk.c),
 	CLK_LOOKUP("mdss_esc0_clk", mdss_esc0_clk.c),
diff --git a/platform/msm_shared/include/qup.h b/platform/msm_shared/include/qup.h
new file mode 100755
index 0000000..8a1a825
--- /dev/null
+++ b/platform/msm_shared/include/qup.h
@@ -0,0 +1,141 @@
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation, Inc. nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef  __QUP__
+#define  __QUP__
+
+#include <stdint.h>
+
+/* QUP_IO_MODES fields */
+#define QUP_IO_MODES_OUTPUT_BIT_SHIFT_EN  0x00010000
+#define QUP_IO_MODES_PACK_EN              0x00008000
+#define QUP_IO_MODES_UNPACK_EN            0x00004000
+#define QUP_IO_MODES_INPUT_MODE           0x00003000
+#define QUP_IO_MODES_OUTPUT_MODE          0x00000C00
+#define QUP_IO_MODES_INPUT_FIFO_SIZE      0x00000380
+#define QUP_IO_MODES_INPUT_BLOCK_SIZE     0x00000060
+#define QUP_IO_MODES_OUTPUT_FIFO_SIZE     0x0000001C
+#define QUP_IO_MODES_OUTPUT_BLOCK_SIZE    0x00000003
+
+#define INPUT_BLOCK_SZ_SHIFT		5
+#define INPUT_FIFO_SZ_SHIFT			7
+#define OUTPUT_BLOCK_SZ_SHIFT		0
+#define OUTPUT_FIFO_SZ_SHIFT		2
+#define OUTPUT_MODE_SHIFT			10
+#define INPUT_MODE_SHIFT			12
+#define INPUT_MODE_MASK		(3 << INPUT_MODE_SHIFT)
+#define OUTPUT_MODE_MASK	(3 << OUTPUT_MODE_SHIFT)
+
+/* QUP_STATE fields */
+#define QUP_STATE_CLEAR_BITS		0x2
+
+/* QUP_ERROR_FLAGS fields */
+#define QUP_ERROR_OUTPUT_OVER_RUN	BIT(5)
+#define QUP_ERROR_INPUT_UNDER_RUN	BIT(4)
+#define QUP_ERROR_OUTPUT_UNDER_RUN	BIT(3)
+#define QUP_ERROR_INPUT_OVER_RUN	BIT(2)
+
+/* QUP_OPERATIONAL fields */
+#define QUP_OP_MAX_INPUT_DONE_FLAG	BIT(11)
+#define QUP_OP_MAX_OUTPUT_DONE_FLAG	BIT(10)
+#define QUP_OP_IN_SERVICE_FLAG		BIT(9)
+#define QUP_OP_OUT_SERVICE_FLAG		BIT(8)
+#define QUP_OP_IN_FIFO_FULL			BIT(7)
+#define QUP_OP_OUT_FIFO_FULL		BIT(6)
+#define QUP_OP_IN_FIFO_NOT_EMPTY	BIT(5)
+#define QUP_OP_OUT_FIFO_NOT_EMPTY	BIT(4)
+
+/* QUP_IO_MODES fields */
+#define QUP_IO_MODES_FIFO		0
+#define QUP_IO_MODES_BLOCK		1
+#define QUP_IO_MODES_DMOV		2
+#define QUP_IO_MODES_BAM		3
+
+/* QUP_CONFIG fields */
+#define QUP_CONFIG_SPI_MODE			(1 << 8)
+#define QUP_CONFIG_CLOCK_AUTO_GATE	BIT(13)
+#define QUP_CONFIG_NO_INPUT			BIT(7)
+#define QUP_CONFIG_NO_OUTPUT		BIT(6)
+#define QUP_CONFIG_N				0x001f
+
+/* QUP_MX_OUTPUT_CNT only supports
+ * 0:15 bits as Number of writes of
+ * size N to the mini-core per RUN state.
+ * And make the count be multiple of max bytes per word.
+ */
+#define MAX_QUP_MX_OUTPUT_COUNT 0xFFF8
+
+/* QUP Registers */
+enum {
+	QUP_CONFIG = 0x0,
+	QUP_STATE = 0x4,
+	QUP_IO_MODES = 0x8,
+	QUP_SW_RESET = 0xC,
+	QUP_OPERATIONAL = 0x18,
+	QUP_ERROR_FLAGS = 0x1C,
+	QUP_ERROR_FLAGS_EN = 0x20,
+	QUP_TEST_CTRL = 0x24,
+	QUP_OPERATIONAL_MASK = 0x28,
+	QUP_HW_VERSION = 0x30,
+	QUP_MX_READ_CNT = 0x208,
+	QUP_MX_INPUT_CNT = 0x200,
+	QUP_MX_OUTPUT_CNT = 0x100,
+	QUP_MX_OUTPUT_CNT_CURRENT = 0x104,
+	QUP_OUTPUT_DEBUG = 0x108,
+	QUP_OUTPUT_FIFO_WORD_CNT = 0x10C,
+	QUP_OUTPUT_FIFO_BASE = 0x110,
+	QUP_MX_WRITE_CNT = 0x150,
+	QUP_MX_WRITE_CNT_CURRENT = 0x154,
+	QUP_INPUT_READ_CUR = 0x20C,
+	QUP_INPUT_DEBUG = 0x210,
+	QUP_INPUT_FIFO_CNT = 0x214,
+	QUP_INPUT_FIFO_BASE = 0x218,
+	QUP_I2C_CLK_CTL = 0x400,
+	QUP_I2C_STATUS = 0x404,
+};
+
+/* QUP States and reset values */
+enum qup_state{
+	QUP_RESET_STATE = 0,
+	QUP_RUN_STATE = 1U,
+	QUP_STATE_MASK = 3U,
+	QUP_PAUSE_STATE = 3U,
+	QUP_STATE_VALID = 1U << 2,
+	QUP_I2C_MAST_GEN = 1U << 4,
+	QUP_OPERATIONAL_RESET = 0xFF0,
+	QUP_I2C_STATUS_RESET = 0xFFFFFC,
+};
+
+/* QUP OPERATIONAL FLAGS */
+enum {
+	QUP_OUT_SVC_FLAG = 1U << 8,
+	QUP_IN_SVC_FLAG = 1U << 9,
+	QUP_MX_INPUT_DONE = 1U << 11,
+};
+
+#endif				/* __QUP__ */
diff --git a/platform/msm_shared/include/spi_qup.h b/platform/msm_shared/include/spi_qup.h
new file mode 100755
index 0000000..27731d7
--- /dev/null
+++ b/platform/msm_shared/include/spi_qup.h
@@ -0,0 +1,113 @@
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation, Inc. nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef  __SPI_QUP__
+#define  __SPI_QUP__
+
+#include <stdint.h>
+#include <qup.h>
+
+/* SPI_ERROR_FLAGS and SPI_ERROR_FLAGS_EN fields */
+#define SPI_ERROR_CLK_OVER_RUN		BIT(1)
+#define SPI_ERROR_CLK_UNDER_RUN		BIT(0)
+
+#define SPI_CONFIG                    0x0300
+#define SPI_IO_CONTROL                0x0304
+#define SPI_IO_MODES                  0x0008
+#define SPI_SW_RESET                  0x000C
+#define SPI_TIME_OUT_CURRENT          0x0014
+#define SPI_MX_OUTPUT_COUNT           0x0100
+#define SPI_MX_OUTPUT_CNT_CURRENT     0x0104
+#define SPI_MX_INPUT_COUNT            0x0200
+#define SPI_MX_INPUT_CNT_CURRENT      0x0204
+#define SPI_MX_READ_COUNT             0x0208
+#define SPI_MX_READ_CNT_CURRENT       0x020C
+#define SPI_OPERATIONAL               0x0018
+#define SPI_ERROR_FLAGS               0x001C
+#define SPI_ERROR_FLAGS_EN            0x0020
+#define SPI_DEASSERT_WAIT             0x0310
+#define SPI_OUTPUT_DEBUG              0x0108
+#define SPI_INPUT_DEBUG               0x0210
+#define SPI_TEST_CTRL                 0x0024
+#define SPI_OUTPUT_FIFO               0x0110
+#define SPI_INPUT_FIFO                0x0218
+#define SPI_STATE                     0x0004
+
+#define SPI_IO_C_NO_TRI_STATE		BIT(0)
+#define SPI_IO_C_CLK_ALWAYS_ON		BIT(9)
+#define SPI_IO_C_MX_CS_MODE			BIT(8)
+#define SPI_IO_C_CS0_ACTIVE_HIGH	BIT(4)
+#define SPI_IO_C_CS_SELECT_CS0		00 << 2
+#define SPI_IO_C_CLK_IDLE_HIGH		BIT(10)
+
+/* SPI_CONFIG fields */
+#define SPI_CONFIG_HS_MODE			BIT(10)
+#define SPI_CONFIG_INPUT_FIRST		BIT(9)
+#define SPI_CONFIG_LOOPBACK			BIT(8)
+
+#define DEFAULT_BYTES_PER_WORD	0x2
+
+#define BITS_PER_BYTE 	8
+
+#define EIO         5
+#define ENOMEM      12
+#define EBUSY       16
+#define ENODEV      19
+#define ENOSYS      38
+#define EPROTONOSUPPORT 93
+#define ETIMEDOUT   110
+
+struct spi_transfer {
+	const unsigned char	*tx_buf;
+	int	len;
+};
+
+/**
+ * qup_spi_dev - spi device config structure
+ * @ qup_base - base register address of QUP.
+ * @ qup_irq - irq number of QUP.
+ * @ tx_bytes - current transfered output data length in bytes
+ * @ bytes_per_word - bytes number per word write to FIFO, valid range [1-4]
+ * @ xfer - pointer to SPI transfer contents structure.
+ */
+struct qup_spi_dev {
+	unsigned int qup_base;
+	int qup_irq;
+	int tx_bytes;
+	unsigned int bytes_per_word;
+	unsigned int bit_shift_en;
+	unsigned int unpack_en;
+	struct spi_transfer *xfer;
+};
+
+/* Function Definitions */
+struct qup_spi_dev *qup_blsp_spi_init(uint8_t blsp_id, uint8_t qup_id);
+int qup_spi_deinit(struct qup_spi_dev *dev);
+int spi_qup_transfer(struct qup_spi_dev *dev, const unsigned char * tx_buf, unsigned int data_size);
+
+#endif				/* __SPI_QUP__ */
diff --git a/platform/msm_shared/rules.mk b/platform/msm_shared/rules.mk
index bac3f47..69a0b15 100755
--- a/platform/msm_shared/rules.mk
+++ b/platform/msm_shared/rules.mk
@@ -524,7 +524,8 @@
 			$(LOCAL_DIR)/certificate.o \
 			$(LOCAL_DIR)/image_verify.o \
 			$(LOCAL_DIR)/i2c_qup.o \
-			$(LOCAL_DIR)/qseecom_lk.o \
+			$(LOCAL_DIR)/spi_qup.o \
+            $(LOCAL_DIR)/qseecom_lk.o \
 			$(LOCAL_DIR)/mdp3.o \
 			$(LOCAL_DIR)/display.o \
 			$(LOCAL_DIR)/mipi_dsi.o \
diff --git a/platform/msm_shared/spi_qup.c b/platform/msm_shared/spi_qup.c
new file mode 100755
index 0000000..c43aabc
--- /dev/null
+++ b/platform/msm_shared/spi_qup.c
@@ -0,0 +1,449 @@
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of The Linux Foundation, Inc. nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * QUP spi driver for Qualcomm MSM platforms
+ *
+ */
+
+#include <debug.h>
+#include <arch/arm.h>
+#include <reg.h>
+#include <kernel/thread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gsbi.h>
+#include <spi_qup.h>
+#include <platform/irqs.h>
+#include <platform/iomap.h>
+#include <platform/gpio.h>
+#include <platform/clock.h>
+#include <platform/timer.h>
+#include <platform/interrupts.h>
+
+//#define DEBUGLEVEL 3
+
+static unsigned int spi_get_qup_hw_ver(struct qup_spi_dev *dev)
+{
+	unsigned int data = readl_relaxed(dev->qup_base + QUP_HW_VERSION);
+
+	dprintf(SPEW, "Qup hardware version is 0x%x\n", data);
+	return data;
+}
+
+static void qup_print_status(struct qup_spi_dev *dev)
+{
+	unsigned val;
+	val = readl(dev->qup_base + QUP_CONFIG);
+	dprintf(SPEW, "Qup config is :0x%x\n", val);
+	val = readl(dev->qup_base + QUP_STATE);
+	dprintf(SPEW, "Qup state is :0x%x\n", val);
+	val = readl(dev->qup_base + QUP_IO_MODES);
+	dprintf(SPEW, "Qup mode is :0x%x\n", val);
+	val = readl(dev->qup_base + SPI_IO_CONTROL);
+	dprintf(SPEW, "SPI_IO_CONTROL is :0x%x\n", val);
+	val = readl(dev->qup_base + SPI_CONFIG);
+	dprintf(SPEW, "SPI_CONFIG is :0x%x\n", val);
+	val = readl(dev->qup_base + QUP_MX_WRITE_CNT_CURRENT);
+	dprintf(SPEW, "QUP_MX_WRITE_CNT_CURRENT is :0x%x\n", val);
+	val = readl(dev->qup_base + QUP_MX_WRITE_CNT);
+	dprintf(SPEW, "QUP_MX_WRITE_CNT is :0x%x\n", val);
+	val = readl(dev->qup_base + QUP_MX_OUTPUT_CNT_CURRENT);
+	dprintf(SPEW, "QUP_MX_OUTPUT_CNT_CURRENT is :0x%x\n", val);
+	val = readl(dev->qup_base + QUP_MX_OUTPUT_CNT);
+	dprintf(SPEW, "QUP_MX_OUTPUT_CNT is :0x%x\n", val);
+	val = readl(dev->qup_base + QUP_OPERATIONAL);
+	dprintf(SPEW, "QUP_OPERATIONAL is :0x%x\n", val);
+	val = readl(dev->qup_base + QUP_OUTPUT_FIFO_WORD_CNT);
+	dprintf(SPEW, "QUP_OUTPUT_FIFO_WORD_CNT is :0x%x\n", val);
+}
+
+static inline bool qup_state_is_valid(struct qup_spi_dev *dev)
+{
+	unsigned int st = readl_relaxed(dev->qup_base + QUP_STATE);
+
+	return st & QUP_STATE_VALID;
+}
+
+static inline int qup_wait_state_valid(struct qup_spi_dev *dev)
+{
+	unsigned retries = 0xFFFF;
+
+	while (!qup_state_is_valid(dev) && (--retries != 0));
+
+	if(!retries)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static int qup_poll_state(struct qup_spi_dev *dev, unsigned state)
+{
+	int ret = 0;
+	unsigned int status;
+
+	ret = qup_wait_state_valid(dev);
+
+	if(ret)
+		goto exit;
+
+	status = readl(dev->qup_base + QUP_STATE);
+	if ((status & (QUP_STATE_VALID | state)) ==
+		(QUP_STATE_VALID | state))
+			return 0;
+
+exit:
+	dprintf(SPEW, "Polling fail for state:0x%x\n", state);
+	qup_print_status(dev);
+	return ret;
+}
+
+static inline int qup_set_state(struct qup_spi_dev *dev,
+				    enum qup_state state)
+{
+	enum qup_state cur_state;
+
+	if (qup_wait_state_valid(dev)) {
+		qup_print_status(dev);
+		return -EIO;
+	}
+
+	cur_state = readl_relaxed(dev->qup_base + QUP_STATE);
+
+	/* For PAUSE_STATE to RESET_STATE,
+	 * two writes of (0b10) are required.
+	 */
+	if (((cur_state & QUP_STATE_MASK) == QUP_PAUSE_STATE) &&
+			(state == QUP_RESET_STATE)) {
+		writel(QUP_STATE_CLEAR_BITS, dev->qup_base + QUP_STATE);
+		writel(QUP_STATE_CLEAR_BITS, dev->qup_base + QUP_STATE);
+	} else {
+		writel((cur_state & ~QUP_STATE_MASK) | state,
+		       dev->qup_base + QUP_STATE);
+	}
+
+	if (qup_poll_state(dev, state)) {
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static inline void qup_register_init(struct qup_spi_dev *dev)
+{
+	/* Initialize QUP registers */
+	qup_set_state(dev, QUP_RESET_STATE);
+	writel(0x00000001, dev->qup_base + QUP_SW_RESET);
+	qup_wait_state_valid(dev);
+	qup_set_state(dev, QUP_RESET_STATE);
+
+	writel(0x00000000, dev->qup_base + QUP_CONFIG);
+	writel(0x00000000, dev->qup_base + QUP_IO_MODES);
+	writel(0xfff0, dev->qup_base + QUP_OPERATIONAL);
+	writel(0x7e, dev->qup_base + QUP_ERROR_FLAGS);
+	writel(0x00000000, dev->qup_base + QUP_TEST_CTRL);
+	writel(0x00000000, dev->qup_base + QUP_OPERATIONAL_MASK);
+	writel(0x0, dev->qup_base + QUP_MX_INPUT_CNT);
+	writel(0x1, dev->qup_base + QUP_MX_OUTPUT_CNT);
+	writel(0x0, dev->qup_base + QUP_MX_READ_CNT);
+}
+
+static inline void spi_register_init(struct qup_spi_dev *dev)
+{
+	/* Set SPI mini core to QUP config */
+	writel(QUP_CONFIG_SPI_MODE | QUP_CONFIG_NO_INPUT, dev->qup_base + QUP_CONFIG);
+
+	/* Initialize SPI mini core registers */
+	writel(0, dev->qup_base + SPI_CONFIG);
+	writel(SPI_IO_C_NO_TRI_STATE | SPI_IO_C_CS_SELECT_CS0 | SPI_IO_C_CLK_IDLE_HIGH,
+		dev->qup_base + SPI_IO_CONTROL);
+	writel(SPI_ERROR_CLK_OVER_RUN | SPI_ERROR_CLK_UNDER_RUN, dev->qup_base + SPI_ERROR_FLAGS_EN);
+	writel(0, dev->qup_base + SPI_DEASSERT_WAIT);
+
+	qup_print_status(dev);
+}
+
+static void spi_qup_io_config_block(struct qup_spi_dev *dev, int len)
+{
+	unsigned int config, iomode, mode;
+	unsigned int bits_per_word;
+
+	qup_register_init(dev);
+	spi_register_init(dev);
+
+	/* bytes_per_word valid range is [1-4].
+	 * Other value may not working as expected.
+	 */
+	dev->bytes_per_word = dev->bytes_per_word % 5;
+
+	/* If bytes_per_word not given, use DEFAULT_BYTES_PER_WORD.
+	 */
+	if(!dev->bytes_per_word)
+		dev->bytes_per_word = DEFAULT_BYTES_PER_WORD;
+
+	bits_per_word = dev->bytes_per_word * 8 - 1;
+
+	writel(len / dev->bytes_per_word, dev->qup_base + QUP_MX_OUTPUT_CNT);
+	writel(0, dev->qup_base + QUP_MX_INPUT_CNT);
+	writel(0, dev->qup_base + QUP_MX_READ_CNT);
+	writel(0, dev->qup_base + QUP_MX_WRITE_CNT);
+
+	mode = QUP_IO_MODES_BLOCK;
+	iomode = readl_relaxed(dev->qup_base + QUP_IO_MODES);
+	iomode &= ~(INPUT_MODE_MASK | OUTPUT_MODE_MASK);
+	if(dev->unpack_en)
+		iomode |= QUP_IO_MODES_UNPACK_EN;
+	else
+		iomode &= ~QUP_IO_MODES_UNPACK_EN;
+	iomode |= (mode << OUTPUT_MODE_SHIFT);
+	iomode |= (mode << INPUT_MODE_SHIFT);
+	if(dev->bit_shift_en)
+		iomode |= QUP_IO_MODES_OUTPUT_BIT_SHIFT_EN;
+	else
+		iomode &= ~QUP_IO_MODES_OUTPUT_BIT_SHIFT_EN;
+	writel(iomode, dev->qup_base + QUP_IO_MODES);
+
+	config = readl_relaxed(dev->qup_base + QUP_CONFIG);
+	config |= QUP_CONFIG_NO_INPUT;
+	config |= QUP_CONFIG_SPI_MODE;
+	config |= bits_per_word;
+	writel(config, dev->qup_base + QUP_CONFIG);
+
+	writel(0, dev->qup_base + QUP_OPERATIONAL_MASK);
+
+	unmask_interrupt(dev->qup_irq);
+}
+
+static void spi_qup_fifo_write(struct qup_spi_dev *dev, struct spi_transfer *xfer)
+{
+	const unsigned char *tx_buf = xfer->tx_buf;
+	unsigned int word, state, data;
+	unsigned int idx;
+
+	while (dev->tx_bytes < xfer->len) {
+
+		state = readl_relaxed(dev->qup_base + QUP_OPERATIONAL);
+		if (state & QUP_OP_OUT_FIFO_FULL)
+		{
+			dprintf(SPEW, "%s: oper QUP_OP_OUT_FIFO_FULL: 0x%x"
+				"dev->tx_bytes:0x%x, xfer->len:0x%x\n",
+				__func__, state, dev->tx_bytes, xfer->len);
+			break;
+		}
+
+		word = 0;
+		for (idx = 0; idx < dev->bytes_per_word; idx++, dev->tx_bytes++) {
+
+			if (!tx_buf) {
+				dprintf(CRITICAL, "%s: tx_buf null error.\n", __func__);
+				dev->tx_bytes += dev->bytes_per_word;
+				break;
+			}
+			data = dev->tx_bytes < xfer->len ? tx_buf[dev->tx_bytes] : 0;
+			word |= data << (BITS_PER_BYTE * idx);
+		}
+
+		writel(word, dev->qup_base + QUP_OUTPUT_FIFO_BASE);
+	}
+}
+
+int _spi_qup_transfer(struct qup_spi_dev *dev, struct spi_transfer *xfer)
+{
+	int ret = -EIO;
+	int retries = 0xFF;
+	unsigned val;
+
+	dev->xfer     = xfer;
+	dev->tx_bytes = 0;
+
+	spi_qup_io_config_block(dev, xfer->len);
+
+	ret = qup_set_state(dev, QUP_RUN_STATE);
+	if (ret) {
+		dprintf(CRITICAL, "%s: cannot set first RUN state\n", __func__);
+		goto exit;
+	}
+
+	while((readl(dev->qup_base + QUP_MX_OUTPUT_CNT)
+		!= readl(dev->qup_base + QUP_MX_OUTPUT_CNT_CURRENT))
+		&& retries--);
+
+	while(readl(dev->qup_base + QUP_MX_OUTPUT_CNT_CURRENT) ) {
+		val = readl(dev->qup_base + QUP_OPERATIONAL);
+		val &= ~QUP_OP_OUT_SERVICE_FLAG;
+		writel(val, dev->qup_base + QUP_OPERATIONAL);
+
+		ret = qup_set_state(dev, QUP_PAUSE_STATE);
+		if (ret) {
+			dprintf(CRITICAL, "%s: cannot set PAUSE state\n", __func__);
+			goto exit;
+		}
+
+		spi_qup_fifo_write(dev, xfer);
+
+		ret = qup_set_state(dev, QUP_RUN_STATE);
+		if (ret) {
+			dprintf(CRITICAL, "%s: cannot set RUN state\n", __func__);
+			goto exit;
+		}
+	}
+	dprintf(SPEW, "dev->tx_bytes:0x%x, xfer->len:0x%x\n",
+		dev->tx_bytes, xfer->len);
+
+exit:
+	qup_set_state(dev, QUP_RESET_STATE);
+	dev->xfer = NULL;
+	return ret;
+}
+
+/**
+ * @brief Transfer data_size bytes data from tx_buf via spi
+ * @param dev		SPI config structure initialized from qup_blsp_spi_init
+ * @param tx_buf	output buffer pointer
+ * @param data_size	Should be multiple of max bytes per word
+ */
+int spi_qup_transfer(struct qup_spi_dev *dev, const unsigned char * tx_buf, unsigned int data_size)
+{
+	unsigned int cur = 0;
+	struct spi_transfer s_xfer;
+	int ret = -EIO;
+
+	if(!tx_buf)
+		return ret;
+
+	while(data_size > MAX_QUP_MX_OUTPUT_COUNT + cur) {
+		s_xfer.len = MAX_QUP_MX_OUTPUT_COUNT;
+		s_xfer.tx_buf = tx_buf + cur;
+
+		ret = _spi_qup_transfer(dev, &s_xfer);
+		if (ret)
+			goto exit;
+
+		cur += MAX_QUP_MX_OUTPUT_COUNT;
+	}
+
+	s_xfer.len = data_size - cur;
+	s_xfer.tx_buf = tx_buf + cur;
+	ret = _spi_qup_transfer(dev, &s_xfer);
+	if (ret)
+			goto exit;
+	return ret;
+
+exit:
+	dprintf(CRITICAL, "%s: transfer error!\n", __func__);
+	return ret;
+}
+
+static enum handler_return qup_spi_interrupt(void *arg)
+{
+	struct qup_spi_dev *dev = (struct qup_spi_dev *)arg;
+	unsigned int opflags, qup_err, spi_err;
+
+	if (!dev) {
+		dprintf(CRITICAL,
+			"dev_addr is NULL, that means spi_qup_init failed...\n");
+		return INT_NO_RESCHEDULE;
+	}
+
+	qup_err = readl_relaxed(dev->qup_base + QUP_ERROR_FLAGS);
+	spi_err = readl_relaxed(dev->qup_base + SPI_ERROR_FLAGS);
+	opflags = readl_relaxed(dev->qup_base + QUP_OPERATIONAL);
+
+	/* Writing a 'one' to the error bit to clear it. */
+	writel(qup_err, dev->qup_base + QUP_ERROR_FLAGS);
+	writel(spi_err, dev->qup_base + SPI_ERROR_FLAGS);
+	writel(opflags, dev->qup_base + QUP_OPERATIONAL);
+
+	if (qup_err) {
+		if (qup_err & QUP_ERROR_OUTPUT_OVER_RUN)
+			dprintf(SPEW, "OUTPUT_OVER_RUN\n");
+		if (qup_err & QUP_ERROR_INPUT_UNDER_RUN)
+			dprintf(SPEW, "INPUT_UNDER_RUN\n");
+		if (qup_err & QUP_ERROR_OUTPUT_UNDER_RUN)
+			dprintf(SPEW, "OUTPUT_UNDER_RUN\n");
+		if (qup_err & QUP_ERROR_INPUT_OVER_RUN)
+			dprintf(SPEW, "INPUT_OVER_RUN\n");
+	}
+
+	if (spi_err) {
+		if (spi_err & SPI_ERROR_CLK_OVER_RUN)
+			dprintf(SPEW, "CLK_OVER_RUN\n");
+		if (spi_err & SPI_ERROR_CLK_UNDER_RUN)
+			dprintf(SPEW, "CLK_UNDER_RUN\n");
+	}
+
+	return INT_NO_RESCHEDULE;
+}
+
+static void qup_spi_sec_init(struct qup_spi_dev *dev)
+{
+	/* Get qup hw version */
+	spi_get_qup_hw_ver(dev);
+
+	qup_register_init(dev);
+	spi_register_init(dev);
+
+	/* Register the GSBIn QUP IRQ */
+	register_int_handler(dev->qup_irq, qup_spi_interrupt, dev);
+
+	/* Then disable it */
+	mask_interrupt(dev->qup_irq);
+}
+
+struct qup_spi_dev *qup_blsp_spi_init(uint8_t blsp_id, uint8_t qup_id)
+{
+	struct qup_spi_dev *dev;
+
+	dev = malloc(sizeof(struct qup_spi_dev));
+	if (!dev) {
+		return NULL;
+	}
+	dev = memset(dev, 0, sizeof(struct qup_spi_dev));
+
+	/* Platform uses BLSP */
+	dev->qup_irq = BLSP_QUP_IRQ(blsp_id, qup_id);
+	dev->qup_base = BLSP_QUP_BASE(blsp_id, qup_id);
+
+	/* Initialize the GPIO for BLSP spi */
+	gpio_config_blsp_spi(blsp_id, qup_id);
+
+	clock_config_blsp_spi(blsp_id, qup_id);
+
+	qup_spi_sec_init(dev);
+
+	return dev;
+}
+
+int qup_spi_deinit(struct qup_spi_dev *dev)
+{
+	/* Disable the qup_irq */
+	mask_interrupt(dev->qup_irq);
+	/* Free the memory used for dev */
+	free(dev);
+	return 0;
+}