mirror of
https://github.com/torvalds/linux.git
synced 2024-12-01 08:31:37 +00:00
Merge branch 'for-5.5' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi into spi-5.6
This commit is contained in:
commit
790514ed77
@ -23,6 +23,29 @@
|
||||
#include "gpiolib.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>
|
||||
*
|
||||
@ -35,6 +58,10 @@ int of_gpio_get_count(struct device *dev, const char *con_id)
|
||||
char propname[32];
|
||||
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++) {
|
||||
if (con_id)
|
||||
snprintf(propname, sizeof(propname), "%s-%s",
|
||||
|
@ -168,16 +168,16 @@ static void cdns_spi_init_hw(struct cdns_spi *xspi)
|
||||
/**
|
||||
* cdns_spi_chipselect - Select or deselect the chip select line
|
||||
* @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);
|
||||
u32 ctrl_reg;
|
||||
|
||||
ctrl_reg = cdns_spi_read(xspi, CDNS_SPI_CR);
|
||||
|
||||
if (!enable) {
|
||||
if (is_high) {
|
||||
/* Deselect the slave */
|
||||
ctrl_reg |= CDNS_SPI_CR_SSCTRL;
|
||||
} else {
|
||||
|
@ -82,6 +82,7 @@ static int thunderx_spi_probe(struct pci_dev *pdev,
|
||||
|
||||
error:
|
||||
clk_disable_unprepare(p->clk);
|
||||
pci_release_regions(pdev);
|
||||
spi_master_put(master);
|
||||
return ret;
|
||||
}
|
||||
@ -96,6 +97,7 @@ static void thunderx_spi_remove(struct pci_dev *pdev)
|
||||
return;
|
||||
|
||||
clk_disable_unprepare(p->clk);
|
||||
pci_release_regions(pdev);
|
||||
/* Put everything in a known state. */
|
||||
writeq(0, p->register_base + OCTEON_SPI_CFG(p));
|
||||
}
|
||||
|
@ -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 chip_data *chip = spi_get_ctldata(spi);
|
||||
|
||||
/* Chip select logic is inverted from spi_set_cs() */
|
||||
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));
|
||||
else if (dws->cs_override)
|
||||
dw_writel(dws, DW_SPI_SER, 0);
|
||||
|
@ -611,6 +611,7 @@ static struct spi_master * fsl_spi_probe(struct device *dev,
|
||||
master->setup = fsl_spi_setup;
|
||||
master->cleanup = fsl_spi_cleanup;
|
||||
master->transfer_one_message = fsl_spi_do_one_msg;
|
||||
master->use_gpio_descriptors = true;
|
||||
|
||||
mpc8xxx_spi = spi_master_get_devdata(master);
|
||||
mpc8xxx_spi->max_bits_per_word = 32;
|
||||
@ -727,17 +728,27 @@ static int of_fsl_spi_probe(struct platform_device *ofdev)
|
||||
}
|
||||
}
|
||||
#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);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
irq = irq_of_parse_and_map(np, 0);
|
||||
if (!irq) {
|
||||
ret = -EINVAL;
|
||||
irq = platform_get_irq(ofdev, 0);
|
||||
if (irq < 0) {
|
||||
ret = irq;
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -750,7 +761,6 @@ static int of_fsl_spi_probe(struct platform_device *ofdev)
|
||||
return 0;
|
||||
|
||||
err:
|
||||
irq_dispose_mapping(irq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -439,7 +439,7 @@ static bool nxp_fspi_supports_op(struct spi_mem *mem,
|
||||
op->data.nbytes > f->devtype_data->txfifo)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return spi_mem_default_supports_op(mem, op);
|
||||
}
|
||||
|
||||
/* Instead of busy looping invoke readl_poll_timeout functionality. */
|
||||
|
@ -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, 0x4b2b), 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 */
|
||||
{ PCI_VDEVICE(INTEL, 0x5ac2), LPSS_BXT_SSP },
|
||||
{ PCI_VDEVICE(INTEL, 0x5ac4), LPSS_BXT_SSP },
|
||||
|
@ -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)
|
||||
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);
|
||||
/* Set default chip selection, clock phase and clock polarity */
|
||||
val |= ss->hw_mode & SPI_CPHA ? SPRD_SPI_NG_RX : SPRD_SPI_NG_TX;
|
||||
|
@ -62,6 +62,7 @@ struct ti_qspi {
|
||||
u32 dc;
|
||||
|
||||
bool mmap_enabled;
|
||||
int current_cs;
|
||||
};
|
||||
|
||||
#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));
|
||||
}
|
||||
qspi->mmap_enabled = true;
|
||||
qspi->current_cs = spi->chip_select;
|
||||
}
|
||||
|
||||
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,
|
||||
MEM_CS_MASK, 0);
|
||||
qspi->mmap_enabled = false;
|
||||
qspi->current_cs = -1;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (!qspi->mmap_enabled)
|
||||
if (!qspi->mmap_enabled || qspi->current_cs != mem->spi->chip_select)
|
||||
ti_qspi_enable_memory_map(mem->spi);
|
||||
ti_qspi_setup_mmap_read(mem->spi, op->cmd.opcode, op->data.buswidth,
|
||||
op->addr.nbytes, op->dummy.nbytes);
|
||||
@ -797,6 +800,7 @@ no_dma:
|
||||
}
|
||||
}
|
||||
qspi->mmap_enabled = false;
|
||||
qspi->current_cs = -1;
|
||||
|
||||
ret = devm_spi_register_master(&pdev->dev, master);
|
||||
if (!ret)
|
||||
|
@ -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;
|
||||
|
||||
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 &= ~(SSI_FC_TXFTH_MASK | SSI_FC_RXFTH_MASK);
|
||||
val |= FIELD_PREP(SSI_FC_TXFTH_MASK, fifo_threshold);
|
||||
val |= FIELD_PREP(SSI_FC_RXFTH_MASK, fifo_threshold);
|
||||
val |= FIELD_PREP(SSI_FC_TXFTH_MASK, SSI_FIFO_DEPTH - threshold);
|
||||
val |= FIELD_PREP(SSI_FC_RXFTH_MASK, threshold);
|
||||
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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user