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;
+}