This commit is contained in:
Mark Brown 2019-12-25 18:18:54 +00:00
commit 790514ed77
No known key found for this signature in database
GPG key ID: 24D68B725D5487D0
10 changed files with 81 additions and 26 deletions

View file

@ -23,6 +23,29 @@
#include "gpiolib.h" #include "gpiolib.h"
#include "gpiolib-of.h" #include "gpiolib-of.h"
/**
* of_gpio_spi_cs_get_count() - special GPIO counting for SPI
* Some elder GPIO controllers need special quirks. Currently we handle
* the Freescale GPIO controller with bindings that doesn't use the
* established "cs-gpios" for chip selects but instead rely on
* "gpios" for the chip select lines. If we detect this, we redirect
* the counting of "cs-gpios" to count "gpios" transparent to the
* driver.
*/
static int of_gpio_spi_cs_get_count(struct device *dev, const char *con_id)
{
struct device_node *np = dev->of_node;
if (!IS_ENABLED(CONFIG_SPI_MASTER))
return 0;
if (!con_id || strcmp(con_id, "cs"))
return 0;
if (!of_device_is_compatible(np, "fsl,spi") &&
!of_device_is_compatible(np, "aeroflexgaisler,spictrl"))
return 0;
return of_gpio_named_count(np, "gpios");
}
/* /*
* This is used by external users of of_gpio_count() from <linux/of_gpio.h> * This is used by external users of of_gpio_count() from <linux/of_gpio.h>
* *
@ -35,6 +58,10 @@ int of_gpio_get_count(struct device *dev, const char *con_id)
char propname[32]; char propname[32];
unsigned int i; unsigned int i;
ret = of_gpio_spi_cs_get_count(dev, con_id);
if (ret > 0)
return ret;
for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) { for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
if (con_id) if (con_id)
snprintf(propname, sizeof(propname), "%s-%s", snprintf(propname, sizeof(propname), "%s-%s",

View file

@ -168,16 +168,16 @@ static void cdns_spi_init_hw(struct cdns_spi *xspi)
/** /**
* cdns_spi_chipselect - Select or deselect the chip select line * cdns_spi_chipselect - Select or deselect the chip select line
* @spi: Pointer to the spi_device structure * @spi: Pointer to the spi_device structure
* @enable: Select (1) or deselect (0) the chip select line * @is_high: Select(0) or deselect (1) the chip select line
*/ */
static void cdns_spi_chipselect(struct spi_device *spi, bool enable) static void cdns_spi_chipselect(struct spi_device *spi, bool is_high)
{ {
struct cdns_spi *xspi = spi_master_get_devdata(spi->master); struct cdns_spi *xspi = spi_master_get_devdata(spi->master);
u32 ctrl_reg; u32 ctrl_reg;
ctrl_reg = cdns_spi_read(xspi, CDNS_SPI_CR); ctrl_reg = cdns_spi_read(xspi, CDNS_SPI_CR);
if (!enable) { if (is_high) {
/* Deselect the slave */ /* Deselect the slave */
ctrl_reg |= CDNS_SPI_CR_SSCTRL; ctrl_reg |= CDNS_SPI_CR_SSCTRL;
} else { } else {

View file

@ -82,6 +82,7 @@ static int thunderx_spi_probe(struct pci_dev *pdev,
error: error:
clk_disable_unprepare(p->clk); clk_disable_unprepare(p->clk);
pci_release_regions(pdev);
spi_master_put(master); spi_master_put(master);
return ret; return ret;
} }
@ -96,6 +97,7 @@ static void thunderx_spi_remove(struct pci_dev *pdev)
return; return;
clk_disable_unprepare(p->clk); clk_disable_unprepare(p->clk);
pci_release_regions(pdev);
/* Put everything in a known state. */ /* Put everything in a known state. */
writeq(0, p->register_base + OCTEON_SPI_CFG(p)); writeq(0, p->register_base + OCTEON_SPI_CFG(p));
} }

View file

@ -129,10 +129,11 @@ void dw_spi_set_cs(struct spi_device *spi, bool enable)
struct dw_spi *dws = spi_controller_get_devdata(spi->controller); struct dw_spi *dws = spi_controller_get_devdata(spi->controller);
struct chip_data *chip = spi_get_ctldata(spi); struct chip_data *chip = spi_get_ctldata(spi);
/* Chip select logic is inverted from spi_set_cs() */
if (chip && chip->cs_control) if (chip && chip->cs_control)
chip->cs_control(enable); chip->cs_control(!enable);
if (enable) if (!enable)
dw_writel(dws, DW_SPI_SER, BIT(spi->chip_select)); dw_writel(dws, DW_SPI_SER, BIT(spi->chip_select));
else if (dws->cs_override) else if (dws->cs_override)
dw_writel(dws, DW_SPI_SER, 0); dw_writel(dws, DW_SPI_SER, 0);

View file

@ -611,6 +611,7 @@ static struct spi_master * fsl_spi_probe(struct device *dev,
master->setup = fsl_spi_setup; master->setup = fsl_spi_setup;
master->cleanup = fsl_spi_cleanup; master->cleanup = fsl_spi_cleanup;
master->transfer_one_message = fsl_spi_do_one_msg; master->transfer_one_message = fsl_spi_do_one_msg;
master->use_gpio_descriptors = true;
mpc8xxx_spi = spi_master_get_devdata(master); mpc8xxx_spi = spi_master_get_devdata(master);
mpc8xxx_spi->max_bits_per_word = 32; mpc8xxx_spi->max_bits_per_word = 32;
@ -727,17 +728,27 @@ static int of_fsl_spi_probe(struct platform_device *ofdev)
} }
} }
#endif #endif
/*
pdata->cs_control = fsl_spi_cs_control; * Handle the case where we have one hardwired (always selected)
* device on the first "chipselect". Else we let the core code
* handle any GPIOs or native chip selects and assign the
* appropriate callback for dealing with the CS lines. This isn't
* supported on the GRLIB variant.
*/
ret = gpiod_count(dev, "cs");
if (ret <= 0)
pdata->max_chipselect = 1;
else
pdata->cs_control = fsl_spi_cs_control;
} }
ret = of_address_to_resource(np, 0, &mem); ret = of_address_to_resource(np, 0, &mem);
if (ret) if (ret)
goto err; goto err;
irq = irq_of_parse_and_map(np, 0); irq = platform_get_irq(ofdev, 0);
if (!irq) { if (irq < 0) {
ret = -EINVAL; ret = irq;
goto err; goto err;
} }
@ -750,7 +761,6 @@ static int of_fsl_spi_probe(struct platform_device *ofdev)
return 0; return 0;
err: err:
irq_dispose_mapping(irq);
return ret; return ret;
} }

View file

@ -439,7 +439,7 @@ static bool nxp_fspi_supports_op(struct spi_mem *mem,
op->data.nbytes > f->devtype_data->txfifo) op->data.nbytes > f->devtype_data->txfifo)
return false; return false;
return true; return spi_mem_default_supports_op(mem, op);
} }
/* Instead of busy looping invoke readl_poll_timeout functionality. */ /* Instead of busy looping invoke readl_poll_timeout functionality. */

View file

@ -1443,6 +1443,10 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = {
{ PCI_VDEVICE(INTEL, 0x4b2a), LPSS_BXT_SSP }, { PCI_VDEVICE(INTEL, 0x4b2a), LPSS_BXT_SSP },
{ PCI_VDEVICE(INTEL, 0x4b2b), LPSS_BXT_SSP }, { PCI_VDEVICE(INTEL, 0x4b2b), LPSS_BXT_SSP },
{ PCI_VDEVICE(INTEL, 0x4b37), LPSS_BXT_SSP }, { PCI_VDEVICE(INTEL, 0x4b37), LPSS_BXT_SSP },
/* JSL */
{ PCI_VDEVICE(INTEL, 0x4daa), LPSS_CNL_SSP },
{ PCI_VDEVICE(INTEL, 0x4dab), LPSS_CNL_SSP },
{ PCI_VDEVICE(INTEL, 0x4dfb), LPSS_CNL_SSP },
/* APL */ /* APL */
{ PCI_VDEVICE(INTEL, 0x5ac2), LPSS_BXT_SSP }, { PCI_VDEVICE(INTEL, 0x5ac2), LPSS_BXT_SSP },
{ PCI_VDEVICE(INTEL, 0x5ac4), LPSS_BXT_SSP }, { PCI_VDEVICE(INTEL, 0x5ac4), LPSS_BXT_SSP },

View file

@ -678,7 +678,7 @@ static int sprd_spi_init_hw(struct sprd_spi *ss, struct spi_transfer *t)
if (d->unit != SPI_DELAY_UNIT_SCK) if (d->unit != SPI_DELAY_UNIT_SCK)
return -EINVAL; return -EINVAL;
val = readl_relaxed(ss->base + SPRD_SPI_CTL7); val = readl_relaxed(ss->base + SPRD_SPI_CTL0);
val &= ~(SPRD_SPI_SCK_REV | SPRD_SPI_NG_TX | SPRD_SPI_NG_RX); val &= ~(SPRD_SPI_SCK_REV | SPRD_SPI_NG_TX | SPRD_SPI_NG_RX);
/* Set default chip selection, clock phase and clock polarity */ /* Set default chip selection, clock phase and clock polarity */
val |= ss->hw_mode & SPI_CPHA ? SPRD_SPI_NG_RX : SPRD_SPI_NG_TX; val |= ss->hw_mode & SPI_CPHA ? SPRD_SPI_NG_RX : SPRD_SPI_NG_TX;

View file

@ -62,6 +62,7 @@ struct ti_qspi {
u32 dc; u32 dc;
bool mmap_enabled; bool mmap_enabled;
int current_cs;
}; };
#define QSPI_PID (0x0) #define QSPI_PID (0x0)
@ -485,6 +486,7 @@ static void ti_qspi_enable_memory_map(struct spi_device *spi)
MEM_CS_EN(spi->chip_select)); MEM_CS_EN(spi->chip_select));
} }
qspi->mmap_enabled = true; qspi->mmap_enabled = true;
qspi->current_cs = spi->chip_select;
} }
static void ti_qspi_disable_memory_map(struct spi_device *spi) static void ti_qspi_disable_memory_map(struct spi_device *spi)
@ -496,6 +498,7 @@ static void ti_qspi_disable_memory_map(struct spi_device *spi)
regmap_update_bits(qspi->ctrl_base, qspi->ctrl_reg, regmap_update_bits(qspi->ctrl_base, qspi->ctrl_reg,
MEM_CS_MASK, 0); MEM_CS_MASK, 0);
qspi->mmap_enabled = false; qspi->mmap_enabled = false;
qspi->current_cs = -1;
} }
static void ti_qspi_setup_mmap_read(struct spi_device *spi, u8 opcode, static void ti_qspi_setup_mmap_read(struct spi_device *spi, u8 opcode,
@ -541,7 +544,7 @@ static int ti_qspi_exec_mem_op(struct spi_mem *mem,
mutex_lock(&qspi->list_lock); mutex_lock(&qspi->list_lock);
if (!qspi->mmap_enabled) if (!qspi->mmap_enabled || qspi->current_cs != mem->spi->chip_select)
ti_qspi_enable_memory_map(mem->spi); ti_qspi_enable_memory_map(mem->spi);
ti_qspi_setup_mmap_read(mem->spi, op->cmd.opcode, op->data.buswidth, ti_qspi_setup_mmap_read(mem->spi, op->cmd.opcode, op->data.buswidth,
op->addr.nbytes, op->dummy.nbytes); op->addr.nbytes, op->dummy.nbytes);
@ -797,6 +800,7 @@ static int ti_qspi_probe(struct platform_device *pdev)
} }
} }
qspi->mmap_enabled = false; qspi->mmap_enabled = false;
qspi->current_cs = -1;
ret = devm_spi_register_master(&pdev->dev, master); ret = devm_spi_register_master(&pdev->dev, master);
if (!ret) if (!ret)

View file

@ -290,25 +290,32 @@ static void uniphier_spi_recv(struct uniphier_spi_priv *priv)
} }
} }
static void uniphier_spi_fill_tx_fifo(struct uniphier_spi_priv *priv) static void uniphier_spi_set_fifo_threshold(struct uniphier_spi_priv *priv,
unsigned int threshold)
{ {
unsigned int fifo_threshold, fill_bytes;
u32 val; u32 val;
fifo_threshold = DIV_ROUND_UP(priv->rx_bytes,
bytes_per_word(priv->bits_per_word));
fifo_threshold = min(fifo_threshold, SSI_FIFO_DEPTH);
fill_bytes = fifo_threshold - (priv->rx_bytes - priv->tx_bytes);
/* set fifo threshold */
val = readl(priv->base + SSI_FC); val = readl(priv->base + SSI_FC);
val &= ~(SSI_FC_TXFTH_MASK | SSI_FC_RXFTH_MASK); val &= ~(SSI_FC_TXFTH_MASK | SSI_FC_RXFTH_MASK);
val |= FIELD_PREP(SSI_FC_TXFTH_MASK, fifo_threshold); val |= FIELD_PREP(SSI_FC_TXFTH_MASK, SSI_FIFO_DEPTH - threshold);
val |= FIELD_PREP(SSI_FC_RXFTH_MASK, fifo_threshold); val |= FIELD_PREP(SSI_FC_RXFTH_MASK, threshold);
writel(val, priv->base + SSI_FC); writel(val, priv->base + SSI_FC);
}
while (fill_bytes--) static void uniphier_spi_fill_tx_fifo(struct uniphier_spi_priv *priv)
{
unsigned int fifo_threshold, fill_words;
unsigned int bpw = bytes_per_word(priv->bits_per_word);
fifo_threshold = DIV_ROUND_UP(priv->rx_bytes, bpw);
fifo_threshold = min(fifo_threshold, SSI_FIFO_DEPTH);
uniphier_spi_set_fifo_threshold(priv, fifo_threshold);
fill_words = fifo_threshold -
DIV_ROUND_UP(priv->rx_bytes - priv->tx_bytes, bpw);
while (fill_words--)
uniphier_spi_send(priv); uniphier_spi_send(priv);
} }