mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-09 21:59:12 -04:00
Merge "spi: spi-msm-geni: Propagate missing SPI Slave change from 4.14 to 5.4"
This commit is contained in:
commit
eda8988caf
2 changed files with 149 additions and 18 deletions
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/ipc_logging.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
|
@ -35,6 +36,8 @@
|
|||
#define SE_SPI_RX_TRANS_LEN (0x270)
|
||||
#define SE_SPI_PRE_POST_CMD_DLY (0x274)
|
||||
#define SE_SPI_DELAY_COUNTERS (0x278)
|
||||
#define SE_SPI_SLAVE_EN (0x2BC)
|
||||
#define SPI_SLAVE_EN BIT(0)
|
||||
|
||||
/* SE_SPI_CPHA register fields */
|
||||
#define CPHA (BIT(0))
|
||||
|
|
@ -169,8 +172,65 @@ struct spi_geni_master {
|
|||
u32 miso_sampling_ctrl_val;
|
||||
bool gpi_reset; /* GPI channel reset*/
|
||||
bool disable_dma;
|
||||
bool slave_setup;
|
||||
bool slave_state;
|
||||
bool slave_cross_connected;
|
||||
};
|
||||
|
||||
static void spi_slv_setup(struct spi_geni_master *mas);
|
||||
|
||||
static ssize_t spi_slave_state_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
ssize_t ret = 0;
|
||||
struct platform_device *pdev = container_of(dev, struct
|
||||
platform_device, dev);
|
||||
struct spi_master *spi = platform_get_drvdata(pdev);
|
||||
struct spi_geni_master *geni_mas;
|
||||
|
||||
geni_mas = spi_master_get_devdata(spi);
|
||||
|
||||
if (geni_mas)
|
||||
ret = scnprintf(buf, sizeof(int), "%d\n",
|
||||
geni_mas->slave_state);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t spi_slave_state_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(spi_slave_state);
|
||||
|
||||
static void spi_slv_setup(struct spi_geni_master *mas)
|
||||
{
|
||||
geni_write_reg(SPI_SLAVE_EN, mas->base, SE_SPI_SLAVE_EN);
|
||||
|
||||
if (mas->slave_cross_connected) {
|
||||
geni_write_reg(GENI_IO_MUX_1_EN, mas->base, GENI_OUTPUT_CTRL);
|
||||
geni_write_reg(IO1_SEL_TX | IO2_DATA_IN_SEL_PAD2 |
|
||||
IO3_DATA_IN_SEL_PAD2, mas->base, GENI_CFG_REG80);
|
||||
} else {
|
||||
geni_write_reg(GENI_IO_MUX_0_EN, mas->base, GENI_OUTPUT_CTRL);
|
||||
}
|
||||
geni_write_reg(START_TRIGGER, mas->base, SE_GENI_CFG_SEQ_START);
|
||||
/* ensure data is written to hardware register */
|
||||
wmb();
|
||||
dev_info(mas->dev, "spi slave setup done\n");
|
||||
}
|
||||
|
||||
static int spi_slv_abort(struct spi_master *spi)
|
||||
{
|
||||
struct spi_geni_master *mas = spi_master_get_devdata(spi);
|
||||
|
||||
complete_all(&mas->tx_cb);
|
||||
complete_all(&mas->rx_cb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_master *get_spi_master(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
|
|
@ -271,8 +331,18 @@ static int setup_fifo_params(struct spi_device *spi_slv,
|
|||
if (mode & SPI_CPOL)
|
||||
cpol |= CPOL;
|
||||
|
||||
if (mode & SPI_CPHA)
|
||||
cpha |= CPHA;
|
||||
if (!spi->slave) {
|
||||
if (mode & SPI_CPHA)
|
||||
cpha |= CPHA;
|
||||
}
|
||||
|
||||
/* SPI slave supports only mode 1, log unsuppoted mode and exit */
|
||||
if (spi->slave && !(cpol == 0 && cpha == 1)) {
|
||||
GENI_SE_DBG(mas->ipc, false, mas->dev,
|
||||
"%s: Unsupported SPI Slave mode cpol %d cpha %d\n",
|
||||
__func__, cpol, cpha);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (spi_slv->mode & SPI_CS_HIGH)
|
||||
demux_output_inv |= BIT(spi_slv->chip_select);
|
||||
|
|
@ -983,7 +1053,7 @@ static int spi_geni_unprepare_message(struct spi_master *spi_mas,
|
|||
GENI_SE_ERR(mas->ipc, false, NULL,
|
||||
"suspend usage count mismatch:%d",
|
||||
count);
|
||||
} else {
|
||||
} else if (!pm_runtime_suspended(mas->dev)) {
|
||||
pm_runtime_mark_last_busy(mas->dev);
|
||||
pm_runtime_put_autosuspend(mas->dev);
|
||||
}
|
||||
|
|
@ -1059,10 +1129,28 @@ static int spi_geni_mas_setup(struct spi_master *spi)
|
|||
int hw_ver;
|
||||
int ret = 0;
|
||||
|
||||
if (unlikely(proto != SPI)) {
|
||||
dev_err(mas->dev, "Invalid proto %d\n", proto);
|
||||
return -ENXIO;
|
||||
if (spi->slave) {
|
||||
if (mas->slave_setup)
|
||||
goto setup_ipc;
|
||||
proto = get_se_proto(mas->base);
|
||||
if (unlikely(proto != SPI_SLAVE)) {
|
||||
dev_err(mas->dev, "Invalid proto %d\n", proto);
|
||||
return -ENXIO;
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely(!mas->setup)) {
|
||||
proto = get_se_proto(mas->base);
|
||||
|
||||
if ((unlikely(proto != SPI)) && (!spi->slave)) {
|
||||
dev_err(mas->dev, "Invalid proto %d\n", proto);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
if (spi->slave)
|
||||
spi_slv_setup(mas);
|
||||
}
|
||||
|
||||
geni_se_init(mas->base, 0x0, (mas->tx_fifo_depth - 2));
|
||||
mas->tx_fifo_depth = get_tx_fifo_depth(mas->base);
|
||||
mas->rx_fifo_depth = get_rx_fifo_depth(mas->base);
|
||||
|
|
@ -1186,6 +1274,7 @@ static int spi_geni_prepare_transfer_hardware(struct spi_master *spi)
|
|||
u32 max_speed = spi->cur_msg->spi->max_speed_hz;
|
||||
struct se_geni_rsc *rsc = &mas->spi_rsc;
|
||||
|
||||
|
||||
/* Adjust the IB based on the max speed of the slave in kHz.*/
|
||||
rsc->ib = (max_speed * DEFAULT_BUS_WIDTH) / 1000;
|
||||
|
||||
|
|
@ -1316,7 +1405,9 @@ static int setup_fifo_xfer(struct spi_transfer *xfer,
|
|||
else if (xfer->rx_buf)
|
||||
m_cmd = SPI_RX_ONLY;
|
||||
|
||||
spi_tx_cfg &= ~CS_TOGGLE;
|
||||
if (!spi->slave)
|
||||
spi_tx_cfg &= ~CS_TOGGLE;
|
||||
|
||||
if (!(mas->cur_word_len % MIN_WORD_LEN)) {
|
||||
trans_len =
|
||||
((xfer->len << 3) / mas->cur_word_len) & TRANS_LEN_MSK;
|
||||
|
|
@ -1356,7 +1447,8 @@ static int setup_fifo_xfer(struct spi_transfer *xfer,
|
|||
mas->cur_xfer_mode = FIFO_MODE;
|
||||
geni_se_select_mode(mas->base, mas->cur_xfer_mode);
|
||||
|
||||
geni_write_reg(spi_tx_cfg, mas->base, SE_SPI_TRANS_CFG);
|
||||
if (!spi->slave)
|
||||
geni_write_reg(spi_tx_cfg, mas->base, SE_SPI_TRANS_CFG);
|
||||
geni_setup_m_cmd(mas->base, m_cmd, m_param);
|
||||
GENI_SE_DBG(mas->ipc, false, mas->dev,
|
||||
"%s: trans_len %d xferlen%d tx_cfg 0x%x cmd 0x%x cs%d mode%d\n",
|
||||
|
|
@ -1394,28 +1486,33 @@ static int setup_fifo_xfer(struct spi_transfer *xfer,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void handle_fifo_timeout(struct spi_geni_master *mas,
|
||||
static void handle_fifo_timeout(struct spi_master *spi,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
struct spi_geni_master *mas = spi_master_get_devdata(spi);
|
||||
unsigned long timeout;
|
||||
u32 rx_fifo_status;
|
||||
int rx_wc, i;
|
||||
|
||||
geni_se_dump_dbg_regs(&mas->spi_rsc, mas->base, mas->ipc);
|
||||
|
||||
if (mas->cur_xfer_mode == FIFO_MODE)
|
||||
geni_write_reg(0, mas->base, SE_GENI_TX_WATERMARK_REG);
|
||||
if (spi->slave)
|
||||
goto dma_unprep;
|
||||
|
||||
reinit_completion(&mas->xfer_done);
|
||||
|
||||
/* Dummy read the rx fifo for any spurious data*/
|
||||
if (xfer->rx_buf) {
|
||||
rx_fifo_status = geni_read_reg(mas->base,
|
||||
SE_GENI_RX_FIFO_STATUS);
|
||||
SE_GENI_RX_FIFO_STATUS);
|
||||
rx_wc = (rx_fifo_status & RX_FIFO_WC_MSK);
|
||||
for (i = 0; i < rx_wc; i++)
|
||||
geni_read_reg(mas->base, SE_GENI_RX_FIFOn);
|
||||
}
|
||||
|
||||
geni_cancel_m_cmd(mas->base);
|
||||
if (mas->cur_xfer_mode == FIFO_MODE)
|
||||
geni_write_reg(0, mas->base, SE_GENI_TX_WATERMARK_REG);
|
||||
|
||||
/* Ensure cmd cancel is written */
|
||||
mb();
|
||||
timeout = wait_for_completion_timeout(&mas->xfer_done, HZ);
|
||||
|
|
@ -1430,6 +1527,7 @@ static void handle_fifo_timeout(struct spi_geni_master *mas,
|
|||
dev_err(mas->dev,
|
||||
"Failed to cancel/abort m_cmd\n");
|
||||
}
|
||||
dma_unprep:
|
||||
if (mas->cur_xfer_mode == SE_DMA) {
|
||||
if (xfer->tx_buf && xfer->tx_dma) {
|
||||
reinit_completion(&mas->xfer_done);
|
||||
|
|
@ -1456,6 +1554,8 @@ static void handle_fifo_timeout(struct spi_geni_master *mas,
|
|||
xfer->rx_dma, xfer->len);
|
||||
}
|
||||
}
|
||||
if (spi->slave && !mas->dis_autosuspend)
|
||||
pm_runtime_put_sync_suspend(mas->dev);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1480,7 +1580,7 @@ static int spi_geni_transfer_one(struct spi_master *spi,
|
|||
|
||||
if (mas->cur_xfer_mode != GSI_DMA) {
|
||||
reinit_completion(&mas->xfer_done);
|
||||
ret = setup_fifo_xfer(xfer, mas, slv->mode, spi);
|
||||
ret = setup_fifo_xfer(xfer, mas, slv->mode, spi);
|
||||
if (ret) {
|
||||
GENI_SE_ERR(mas->ipc, true, mas->dev,
|
||||
"setup_fifo_xfer failed: %d\n", ret);
|
||||
|
|
@ -1488,8 +1588,13 @@ static int spi_geni_transfer_one(struct spi_master *spi,
|
|||
goto err_fifo_geni_transfer_one;
|
||||
}
|
||||
|
||||
if (spi->slave)
|
||||
mas->slave_state = true;
|
||||
timeout = wait_for_completion_timeout(&mas->xfer_done,
|
||||
msecs_to_jiffies(SPI_XFER_TIMEOUT_MS));
|
||||
if (spi->slave)
|
||||
mas->slave_state = false;
|
||||
|
||||
if (!timeout) {
|
||||
GENI_SE_ERR(mas->ipc, true, mas->dev,
|
||||
"Xfer[len %d tx %pK rx %pK n %d] timed out.\n",
|
||||
|
|
@ -1575,7 +1680,7 @@ err_gsi_geni_transfer_one:
|
|||
}
|
||||
return ret;
|
||||
err_fifo_geni_transfer_one:
|
||||
handle_fifo_timeout(mas, xfer);
|
||||
handle_fifo_timeout(spi, xfer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -1763,7 +1868,7 @@ static int spi_geni_probe(struct platform_device *pdev)
|
|||
struct resource *res;
|
||||
struct platform_device *wrapper_pdev;
|
||||
struct device_node *wrapper_ph_node;
|
||||
bool rt_pri;
|
||||
bool rt_pri, slave_en;
|
||||
|
||||
spi = spi_alloc_master(&pdev->dev, sizeof(struct spi_geni_master));
|
||||
if (!spi) {
|
||||
|
|
@ -1952,7 +2057,15 @@ static int spi_geni_probe(struct platform_device *pdev)
|
|||
geni_mas->disable_dma = of_property_read_bool(pdev->dev.of_node,
|
||||
"qcom,disable-dma");
|
||||
|
||||
slave_en = of_property_read_bool(pdev->dev.of_node,
|
||||
"qcom,slv-ctrl");
|
||||
if (slave_en) {
|
||||
spi->slave = true;
|
||||
spi->slave_abort = spi_slv_abort;
|
||||
}
|
||||
|
||||
geni_mas->slave_cross_connected =
|
||||
of_property_read_bool(pdev->dev.of_node, "slv-cross-connected");
|
||||
spi->mode_bits = (SPI_CPOL | SPI_CPHA | SPI_LOOP | SPI_CS_HIGH);
|
||||
spi->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
|
||||
spi->num_chipselect = SPI_NUM_CHIPSELECT;
|
||||
|
|
@ -1979,6 +2092,8 @@ static int spi_geni_probe(struct platform_device *pdev)
|
|||
dev_err(&pdev->dev, "Failed to register SPI master\n");
|
||||
goto spi_geni_probe_unmap;
|
||||
}
|
||||
ret = sysfs_create_file(&(geni_mas->dev->kobj),
|
||||
&dev_attr_spi_slave_state.attr);
|
||||
return ret;
|
||||
spi_geni_probe_unmap:
|
||||
devm_iounmap(&pdev->dev, geni_mas->base);
|
||||
|
|
@ -1992,6 +2107,7 @@ static int spi_geni_remove(struct platform_device *pdev)
|
|||
struct spi_master *master = platform_get_drvdata(pdev);
|
||||
struct spi_geni_master *geni_mas = spi_master_get_devdata(master);
|
||||
|
||||
sysfs_remove_file(&pdev->dev.kobj, &dev_attr_spi_slave_state.attr);
|
||||
se_geni_resources_off(&geni_mas->spi_rsc);
|
||||
spi_unregister_master(master);
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
|
|
@ -2006,6 +2122,7 @@ static int spi_geni_runtime_suspend(struct device *dev)
|
|||
struct spi_master *spi = get_spi_master(dev);
|
||||
struct spi_geni_master *geni_mas = spi_master_get_devdata(spi);
|
||||
|
||||
disable_irq(geni_mas->irq);
|
||||
if (geni_mas->is_le_vm) {
|
||||
spi_geni_unlock_bus(spi);
|
||||
return 0;
|
||||
|
|
@ -2067,6 +2184,7 @@ static int spi_geni_runtime_resume(struct device *dev)
|
|||
|
||||
exit_rt_resume:
|
||||
ret = se_geni_resources_on(&geni_mas->spi_rsc);
|
||||
enable_irq(geni_mas->irq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,8 @@ enum se_protocol_types {
|
|||
SPI,
|
||||
UART,
|
||||
I2C,
|
||||
I3C
|
||||
I3C,
|
||||
SPI_SLAVE
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -93,6 +94,9 @@ struct se_geni_rsc {
|
|||
#define GENI_FW_REVISION_RO (0x68)
|
||||
#define GENI_FW_S_REVISION_RO (0x6C)
|
||||
#define SE_GENI_CLK_SEL (0x7C)
|
||||
#define SE_GENI_CFG_SEQ_START (0x84)
|
||||
#define SE_GENI_CFG_REG (0x200)
|
||||
#define GENI_CFG_REG80 (0x240)
|
||||
#define SE_GENI_BYTE_GRAN (0x254)
|
||||
#define SE_GENI_DMA_MODE_EN (0x258)
|
||||
#define SE_GENI_TX_PACKING_CFG0 (0x260)
|
||||
|
|
@ -125,10 +129,19 @@ struct se_geni_rsc {
|
|||
#define SE_HW_PARAM_1 (0xE28)
|
||||
#define SE_DMA_GENERAL_CFG (0xE30)
|
||||
#define SE_DMA_DEBUG_REG0 (0xE40)
|
||||
#define SLAVE_MODE_EN (BIT(3))
|
||||
#define START_TRIGGER (BIT(0))
|
||||
#define QUPV3_HW_VER (0x4)
|
||||
|
||||
/* GENI_OUTPUT_CTRL fields */
|
||||
#define DEFAULT_IO_OUTPUT_CTRL_MSK (GENMASK(6, 0))
|
||||
#define DEFAULT_IO_OUTPUT_CTRL_MSK (GENMASK(6, 0))
|
||||
#define GENI_IO_MUX_0_EN BIT(0)
|
||||
#define GENI_IO_MUX_1_EN BIT(1)
|
||||
|
||||
/* GENI_CFG_REG80 fields */
|
||||
#define IO1_SEL_TX BIT(2)
|
||||
#define IO2_DATA_IN_SEL_PAD2 (GENMASK(11, 10))
|
||||
#define IO3_DATA_IN_SEL_PAD2 BIT(15)
|
||||
|
||||
/* GENI_FORCE_DEFAULT_REG fields */
|
||||
#define FORCE_DEFAULT (BIT(0))
|
||||
|
|
|
|||
Loading…
Reference in a new issue