Loading drivers/spi/spi-geni-qcom.c +49 −5 Original line number Original line Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <linux/qcom-geni-se.h> #include <linux/qcom-geni-se.h> #include <linux/msm_gpi.h> #include <linux/msm_gpi.h> #include <linux/spi/spi.h> #include <linux/spi/spi.h> #include <linux/spi/spi-geni-qcom.h> #define SPI_NUM_CHIPSELECT (4) #define SPI_NUM_CHIPSELECT (4) #define SPI_XFER_TIMEOUT_MS (250) #define SPI_XFER_TIMEOUT_MS (250) Loading Loading @@ -67,6 +68,11 @@ /* SPI_TX/SPI_RX_TRANS_LEN fields */ /* SPI_TX/SPI_RX_TRANS_LEN fields */ #define TRANS_LEN_MSK (GENMASK(23, 0)) #define TRANS_LEN_MSK (GENMASK(23, 0)) /* SE_SPI_DELAY_COUNTERS */ #define SPI_INTER_WORDS_DELAY_MSK (GENMASK(9, 0)) #define SPI_CS_CLK_DELAY_MSK (GENMASK(19, 10)) #define SPI_CS_CLK_DELAY_SHFT (10) /* M_CMD OP codes for SPI */ /* M_CMD OP codes for SPI */ #define SPI_TX_ONLY (1) #define SPI_TX_ONLY (1) #define SPI_RX_ONLY (2) #define SPI_RX_ONLY (2) Loading Loading @@ -229,6 +235,8 @@ static int setup_fifo_params(struct spi_device *spi_slv, int ret = 0; int ret = 0; int idx; int idx; int div; int div; struct spi_geni_qcom_ctrl_data *delay_params = NULL; u32 spi_delay_params = 0; loopback_cfg &= ~LOOPBACK_MSK; loopback_cfg &= ~LOOPBACK_MSK; cpol &= ~CPOL; cpol &= ~CPOL; Loading @@ -246,6 +254,22 @@ static int setup_fifo_params(struct spi_device *spi_slv, if (spi_slv->mode & SPI_CS_HIGH) if (spi_slv->mode & SPI_CS_HIGH) demux_output_inv |= BIT(spi_slv->chip_select); demux_output_inv |= BIT(spi_slv->chip_select); if (spi_slv->controller_data) { u32 cs_clk_delay = 0; u32 inter_words_delay = 0; delay_params = (struct spi_geni_qcom_ctrl_data *) spi_slv->controller_data; cs_clk_delay = (delay_params->spi_cs_clk_delay << SPI_CS_CLK_DELAY_SHFT) & SPI_CS_CLK_DELAY_MSK; inter_words_delay = delay_params->spi_inter_words_delay & SPI_INTER_WORDS_DELAY_MSK; spi_delay_params = (inter_words_delay | cs_clk_delay); } demux_sel = spi_slv->chip_select; demux_sel = spi_slv->chip_select; mas->cur_speed_hz = spi_slv->max_speed_hz; mas->cur_speed_hz = spi_slv->max_speed_hz; mas->cur_word_len = spi_slv->bits_per_word; mas->cur_word_len = spi_slv->bits_per_word; Loading @@ -267,12 +291,13 @@ static int setup_fifo_params(struct spi_device *spi_slv, geni_write_reg(demux_output_inv, mas->base, SE_SPI_DEMUX_OUTPUT_INV); geni_write_reg(demux_output_inv, mas->base, SE_SPI_DEMUX_OUTPUT_INV); geni_write_reg(clk_sel, mas->base, SE_GENI_CLK_SEL); geni_write_reg(clk_sel, mas->base, SE_GENI_CLK_SEL); geni_write_reg(m_clk_cfg, mas->base, GENI_SER_M_CLK_CFG); geni_write_reg(m_clk_cfg, mas->base, GENI_SER_M_CLK_CFG); geni_write_reg(spi_delay_params, mas->base, SE_SPI_DELAY_COUNTERS); GENI_SE_DBG(mas->ipc, false, mas->dev, GENI_SE_DBG(mas->ipc, false, mas->dev, "%s:Loopback%d demux_sel0x%x demux_op_inv 0x%x clk_cfg 0x%x\n", "%s:Loopback%d demux_sel0x%x demux_op_inv 0x%x clk_cfg 0x%x\n", __func__, loopback_cfg, demux_sel, demux_output_inv, m_clk_cfg); __func__, loopback_cfg, demux_sel, demux_output_inv, m_clk_cfg); GENI_SE_DBG(mas->ipc, false, mas->dev, GENI_SE_DBG(mas->ipc, false, mas->dev, "%s:clk_sel 0x%x cpol %d cpha %d\n", __func__, "%s:clk_sel 0x%x cpol %d cpha %d delay 0x%x\n", __func__, clk_sel, cpol, cpha); clk_sel, cpol, cpha, spi_delay_params); /* Ensure message level attributes are written before returning */ /* Ensure message level attributes are written before returning */ mb(); mb(); setup_fifo_params_exit: setup_fifo_params_exit: Loading Loading @@ -306,7 +331,8 @@ static int select_xfer_mode(struct spi_master *spi, } } static struct msm_gpi_tre *setup_config0_tre(struct spi_transfer *xfer, static struct msm_gpi_tre *setup_config0_tre(struct spi_transfer *xfer, struct spi_geni_master *mas, u16 mode) struct spi_geni_master *mas, u16 mode, u32 cs_clk_delay, u32 inter_words_delay) { { struct msm_gpi_tre *c0_tre = &mas->gsi[mas->num_xfers].config0_tre; struct msm_gpi_tre *c0_tre = &mas->gsi[mas->num_xfers].config0_tre; u8 flags = 0; u8 flags = 0; Loading Loading @@ -340,12 +366,16 @@ static struct msm_gpi_tre *setup_config0_tre(struct spi_transfer *xfer, } } c0_tre->dword[0] = MSM_GPI_SPI_CONFIG0_TRE_DWORD0(pack, flags, c0_tre->dword[0] = MSM_GPI_SPI_CONFIG0_TRE_DWORD0(pack, flags, word_len); word_len); c0_tre->dword[1] = MSM_GPI_SPI_CONFIG0_TRE_DWORD1(0, 0, 0); c0_tre->dword[1] = MSM_GPI_SPI_CONFIG0_TRE_DWORD1(0, cs_clk_delay, inter_words_delay); c0_tre->dword[2] = MSM_GPI_SPI_CONFIG0_TRE_DWORD2(idx, div); c0_tre->dword[2] = MSM_GPI_SPI_CONFIG0_TRE_DWORD2(idx, div); c0_tre->dword[3] = MSM_GPI_SPI_CONFIG0_TRE_DWORD3(0, 0, 0, 1); c0_tre->dword[3] = MSM_GPI_SPI_CONFIG0_TRE_DWORD3(0, 0, 0, 1); GENI_SE_DBG(mas->ipc, false, mas->dev, GENI_SE_DBG(mas->ipc, false, mas->dev, "%s: flags 0x%x word %d pack %d idx %d div %d\n", "%s: flags 0x%x word %d pack %d idx %d div %d\n", __func__, flags, word_len, pack, idx, div); __func__, flags, word_len, pack, idx, div); GENI_SE_DBG(mas->ipc, false, mas->dev, "%s: cs_clk_delay %d inter_words_delay %d\n", __func__, cs_clk_delay, inter_words_delay); return c0_tre; return c0_tre; } } Loading Loading @@ -503,13 +533,27 @@ static int setup_gsi_xfer(struct spi_transfer *xfer, u32 rx_len = 0; u32 rx_len = 0; int go_flags = 0; int go_flags = 0; unsigned long flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK; unsigned long flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK; struct spi_geni_qcom_ctrl_data *delay_params = NULL; u32 cs_clk_delay = 0; u32 inter_words_delay = 0; if (spi_slv->controller_data) { delay_params = (struct spi_geni_qcom_ctrl_data *) spi_slv->controller_data; cs_clk_delay = delay_params->spi_cs_clk_delay; inter_words_delay = delay_params->spi_inter_words_delay; } if ((xfer->bits_per_word != mas->cur_word_len) || if ((xfer->bits_per_word != mas->cur_word_len) || (xfer->speed_hz != mas->cur_speed_hz)) { (xfer->speed_hz != mas->cur_speed_hz)) { mas->cur_word_len = xfer->bits_per_word; mas->cur_word_len = xfer->bits_per_word; mas->cur_speed_hz = xfer->speed_hz; mas->cur_speed_hz = xfer->speed_hz; tx_nent++; tx_nent++; c0_tre = setup_config0_tre(xfer, mas, spi_slv->mode); c0_tre = setup_config0_tre(xfer, mas, spi_slv->mode, cs_clk_delay, inter_words_delay); if (IS_ERR_OR_NULL(c0_tre)) { if (IS_ERR_OR_NULL(c0_tre)) { dev_err(mas->dev, "%s:Err setting c0tre:%d\n", dev_err(mas->dev, "%s:Err setting c0tre:%d\n", __func__, ret); __func__, ret); Loading include/linux/spi/spi-geni-qcom.h 0 → 100644 +23 −0 Original line number Original line Diff line number Diff line /* * Copyright (c) 2017, 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. * */ #ifndef __SPI_GENI_QCOM_HEADER___ #define __SPI_GENI_QCOM_HEADER___ struct spi_geni_qcom_ctrl_data { u32 spi_cs_clk_delay; u32 spi_inter_words_delay; }; #endif /*__SPI_GENI_QCOM_HEADER___*/ Loading
drivers/spi/spi-geni-qcom.c +49 −5 Original line number Original line Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <linux/qcom-geni-se.h> #include <linux/qcom-geni-se.h> #include <linux/msm_gpi.h> #include <linux/msm_gpi.h> #include <linux/spi/spi.h> #include <linux/spi/spi.h> #include <linux/spi/spi-geni-qcom.h> #define SPI_NUM_CHIPSELECT (4) #define SPI_NUM_CHIPSELECT (4) #define SPI_XFER_TIMEOUT_MS (250) #define SPI_XFER_TIMEOUT_MS (250) Loading Loading @@ -67,6 +68,11 @@ /* SPI_TX/SPI_RX_TRANS_LEN fields */ /* SPI_TX/SPI_RX_TRANS_LEN fields */ #define TRANS_LEN_MSK (GENMASK(23, 0)) #define TRANS_LEN_MSK (GENMASK(23, 0)) /* SE_SPI_DELAY_COUNTERS */ #define SPI_INTER_WORDS_DELAY_MSK (GENMASK(9, 0)) #define SPI_CS_CLK_DELAY_MSK (GENMASK(19, 10)) #define SPI_CS_CLK_DELAY_SHFT (10) /* M_CMD OP codes for SPI */ /* M_CMD OP codes for SPI */ #define SPI_TX_ONLY (1) #define SPI_TX_ONLY (1) #define SPI_RX_ONLY (2) #define SPI_RX_ONLY (2) Loading Loading @@ -229,6 +235,8 @@ static int setup_fifo_params(struct spi_device *spi_slv, int ret = 0; int ret = 0; int idx; int idx; int div; int div; struct spi_geni_qcom_ctrl_data *delay_params = NULL; u32 spi_delay_params = 0; loopback_cfg &= ~LOOPBACK_MSK; loopback_cfg &= ~LOOPBACK_MSK; cpol &= ~CPOL; cpol &= ~CPOL; Loading @@ -246,6 +254,22 @@ static int setup_fifo_params(struct spi_device *spi_slv, if (spi_slv->mode & SPI_CS_HIGH) if (spi_slv->mode & SPI_CS_HIGH) demux_output_inv |= BIT(spi_slv->chip_select); demux_output_inv |= BIT(spi_slv->chip_select); if (spi_slv->controller_data) { u32 cs_clk_delay = 0; u32 inter_words_delay = 0; delay_params = (struct spi_geni_qcom_ctrl_data *) spi_slv->controller_data; cs_clk_delay = (delay_params->spi_cs_clk_delay << SPI_CS_CLK_DELAY_SHFT) & SPI_CS_CLK_DELAY_MSK; inter_words_delay = delay_params->spi_inter_words_delay & SPI_INTER_WORDS_DELAY_MSK; spi_delay_params = (inter_words_delay | cs_clk_delay); } demux_sel = spi_slv->chip_select; demux_sel = spi_slv->chip_select; mas->cur_speed_hz = spi_slv->max_speed_hz; mas->cur_speed_hz = spi_slv->max_speed_hz; mas->cur_word_len = spi_slv->bits_per_word; mas->cur_word_len = spi_slv->bits_per_word; Loading @@ -267,12 +291,13 @@ static int setup_fifo_params(struct spi_device *spi_slv, geni_write_reg(demux_output_inv, mas->base, SE_SPI_DEMUX_OUTPUT_INV); geni_write_reg(demux_output_inv, mas->base, SE_SPI_DEMUX_OUTPUT_INV); geni_write_reg(clk_sel, mas->base, SE_GENI_CLK_SEL); geni_write_reg(clk_sel, mas->base, SE_GENI_CLK_SEL); geni_write_reg(m_clk_cfg, mas->base, GENI_SER_M_CLK_CFG); geni_write_reg(m_clk_cfg, mas->base, GENI_SER_M_CLK_CFG); geni_write_reg(spi_delay_params, mas->base, SE_SPI_DELAY_COUNTERS); GENI_SE_DBG(mas->ipc, false, mas->dev, GENI_SE_DBG(mas->ipc, false, mas->dev, "%s:Loopback%d demux_sel0x%x demux_op_inv 0x%x clk_cfg 0x%x\n", "%s:Loopback%d demux_sel0x%x demux_op_inv 0x%x clk_cfg 0x%x\n", __func__, loopback_cfg, demux_sel, demux_output_inv, m_clk_cfg); __func__, loopback_cfg, demux_sel, demux_output_inv, m_clk_cfg); GENI_SE_DBG(mas->ipc, false, mas->dev, GENI_SE_DBG(mas->ipc, false, mas->dev, "%s:clk_sel 0x%x cpol %d cpha %d\n", __func__, "%s:clk_sel 0x%x cpol %d cpha %d delay 0x%x\n", __func__, clk_sel, cpol, cpha); clk_sel, cpol, cpha, spi_delay_params); /* Ensure message level attributes are written before returning */ /* Ensure message level attributes are written before returning */ mb(); mb(); setup_fifo_params_exit: setup_fifo_params_exit: Loading Loading @@ -306,7 +331,8 @@ static int select_xfer_mode(struct spi_master *spi, } } static struct msm_gpi_tre *setup_config0_tre(struct spi_transfer *xfer, static struct msm_gpi_tre *setup_config0_tre(struct spi_transfer *xfer, struct spi_geni_master *mas, u16 mode) struct spi_geni_master *mas, u16 mode, u32 cs_clk_delay, u32 inter_words_delay) { { struct msm_gpi_tre *c0_tre = &mas->gsi[mas->num_xfers].config0_tre; struct msm_gpi_tre *c0_tre = &mas->gsi[mas->num_xfers].config0_tre; u8 flags = 0; u8 flags = 0; Loading Loading @@ -340,12 +366,16 @@ static struct msm_gpi_tre *setup_config0_tre(struct spi_transfer *xfer, } } c0_tre->dword[0] = MSM_GPI_SPI_CONFIG0_TRE_DWORD0(pack, flags, c0_tre->dword[0] = MSM_GPI_SPI_CONFIG0_TRE_DWORD0(pack, flags, word_len); word_len); c0_tre->dword[1] = MSM_GPI_SPI_CONFIG0_TRE_DWORD1(0, 0, 0); c0_tre->dword[1] = MSM_GPI_SPI_CONFIG0_TRE_DWORD1(0, cs_clk_delay, inter_words_delay); c0_tre->dword[2] = MSM_GPI_SPI_CONFIG0_TRE_DWORD2(idx, div); c0_tre->dword[2] = MSM_GPI_SPI_CONFIG0_TRE_DWORD2(idx, div); c0_tre->dword[3] = MSM_GPI_SPI_CONFIG0_TRE_DWORD3(0, 0, 0, 1); c0_tre->dword[3] = MSM_GPI_SPI_CONFIG0_TRE_DWORD3(0, 0, 0, 1); GENI_SE_DBG(mas->ipc, false, mas->dev, GENI_SE_DBG(mas->ipc, false, mas->dev, "%s: flags 0x%x word %d pack %d idx %d div %d\n", "%s: flags 0x%x word %d pack %d idx %d div %d\n", __func__, flags, word_len, pack, idx, div); __func__, flags, word_len, pack, idx, div); GENI_SE_DBG(mas->ipc, false, mas->dev, "%s: cs_clk_delay %d inter_words_delay %d\n", __func__, cs_clk_delay, inter_words_delay); return c0_tre; return c0_tre; } } Loading Loading @@ -503,13 +533,27 @@ static int setup_gsi_xfer(struct spi_transfer *xfer, u32 rx_len = 0; u32 rx_len = 0; int go_flags = 0; int go_flags = 0; unsigned long flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK; unsigned long flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK; struct spi_geni_qcom_ctrl_data *delay_params = NULL; u32 cs_clk_delay = 0; u32 inter_words_delay = 0; if (spi_slv->controller_data) { delay_params = (struct spi_geni_qcom_ctrl_data *) spi_slv->controller_data; cs_clk_delay = delay_params->spi_cs_clk_delay; inter_words_delay = delay_params->spi_inter_words_delay; } if ((xfer->bits_per_word != mas->cur_word_len) || if ((xfer->bits_per_word != mas->cur_word_len) || (xfer->speed_hz != mas->cur_speed_hz)) { (xfer->speed_hz != mas->cur_speed_hz)) { mas->cur_word_len = xfer->bits_per_word; mas->cur_word_len = xfer->bits_per_word; mas->cur_speed_hz = xfer->speed_hz; mas->cur_speed_hz = xfer->speed_hz; tx_nent++; tx_nent++; c0_tre = setup_config0_tre(xfer, mas, spi_slv->mode); c0_tre = setup_config0_tre(xfer, mas, spi_slv->mode, cs_clk_delay, inter_words_delay); if (IS_ERR_OR_NULL(c0_tre)) { if (IS_ERR_OR_NULL(c0_tre)) { dev_err(mas->dev, "%s:Err setting c0tre:%d\n", dev_err(mas->dev, "%s:Err setting c0tre:%d\n", __func__, ret); __func__, ret); Loading
include/linux/spi/spi-geni-qcom.h 0 → 100644 +23 −0 Original line number Original line Diff line number Diff line /* * Copyright (c) 2017, 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. * */ #ifndef __SPI_GENI_QCOM_HEADER___ #define __SPI_GENI_QCOM_HEADER___ struct spi_geni_qcom_ctrl_data { u32 spi_cs_clk_delay; u32 spi_inter_words_delay; }; #endif /*__SPI_GENI_QCOM_HEADER___*/