Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c9d621a4 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

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

parents 7f868741 b06fe0e7
Loading
Loading
Loading
Loading
+49 −5
Original line number Original line Diff line number Diff line
@@ -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)
@@ -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)
@@ -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;
@@ -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;
@@ -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:
@@ -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;
@@ -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;
}
}


@@ -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);
+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___*/