Merge "spi: spi-geni-qcom: Allow clients to specify SPI slave parameters"

This commit is contained in:
Linux Build Service Account 2017-09-28 16:52:54 -07:00 • committed by Gerrit - the friendly Code Review server
commit c9d621a420
2 changed files with 72 additions and 5 deletions

View file

@ -24,6 +24,7 @@
#include <linux/qcom-geni-se.h>
#include <linux/msm_gpi.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi-geni-qcom.h>
#define SPI_NUM_CHIPSELECT (4)
#define SPI_XFER_TIMEOUT_MS (250)
@ -67,6 +68,11 @@
/* SPI_TX/SPI_RX_TRANS_LEN fields */
#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 */
#define SPI_TX_ONLY (1)
#define SPI_RX_ONLY (2)
@ -229,6 +235,8 @@ static int setup_fifo_params(struct spi_device *spi_slv,
int ret = 0;
int idx;
int div;
struct spi_geni_qcom_ctrl_data *delay_params = NULL;
u32 spi_delay_params = 0;
loopback_cfg &= ~LOOPBACK_MSK;
cpol &= ~CPOL;
@ -246,6 +254,22 @@ static int setup_fifo_params(struct spi_device *spi_slv,
if (spi_slv->mode & SPI_CS_HIGH)
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;
mas->cur_speed_hz = spi_slv->max_speed_hz;
mas->cur_word_len = spi_slv->bits_per_word;
@ -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(clk_sel, mas->base, SE_GENI_CLK_SEL);
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,
"%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);
GENI_SE_DBG(mas->ipc, false, mas->dev,
"%s:clk_sel 0x%x cpol %d cpha %d\n", __func__,
clk_sel, cpol, cpha);
"%s:clk_sel 0x%x cpol %d cpha %d delay 0x%x\n", __func__,
clk_sel, cpol, cpha, spi_delay_params);
/* Ensure message level attributes are written before returning */
mb();
setup_fifo_params_exit:
@ -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,
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;
u8 flags = 0;
@ -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,
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[3] = MSM_GPI_SPI_CONFIG0_TRE_DWORD3(0, 0, 0, 1);
GENI_SE_DBG(mas->ipc, false, mas->dev,
"%s: flags 0x%x word %d pack %d idx %d div %d\n",
__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;
}
@ -503,13 +533,27 @@ static int setup_gsi_xfer(struct spi_transfer *xfer,
u32 rx_len = 0;
int go_flags = 0;
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) ||
(xfer->speed_hz != mas->cur_speed_hz)) {
mas->cur_word_len = xfer->bits_per_word;
mas->cur_speed_hz = xfer->speed_hz;
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)) {
dev_err(mas->dev, "%s:Err setting c0tre:%d\n",
__func__, ret);

View file

@ -0,0 +1,23 @@
/*
* 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___*/