mirror of
https://github.com/torvalds/linux.git
synced 2024-12-14 23:25:54 +00:00
a56f489502
Another quiet release for SPI, almost entirely driver specific changes with the diffstat dominated by two new drivers which are about two thirds of it in terms of lines of code: - New drivers for PIC32 standard and SQI controllers. - The Cadence driver has had runtime PM support added and quite a few fixes and cleanups. - The flash-specific accelerated path support now has a feature query interface. - The pxa2xx driver has been moved to use the core DMA mapping support. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJXQufEAAoJECTWi3JdVIfQXeEH/3PZVHvwQBqpN6S0AunlJQoM s1bScKYeH2ukx9iw86M/upSCOVt4TGlPrdwzcYCUYll9IJuO/ChDio7PoVlxQeJB kYUrFi6dzE/bCNzWtrGtyvNlSDsrRccbRBhmKTFQ9DokcJHgzdzhuCuXUR6OKDDw CxlvDrLwapzOpHIncrhh6dvv1NoZgusOTMzVQAPvLbuiH9WpdnD9MjySklIqd0XU bp+J4J5+jyBVykOZ2MdYpXf1dRhg0c0kmKXOKuX9woiJhvBFrtZX2GfCw1MXchKZ /obHOyD7ff+MBCY2nFN95s3rl9Vxn8IAfNWsuQvZaFK0nz1bypaQ6aXIbXXgj/8= =QO1T -----END PGP SIGNATURE----- Merge tag 'spi-v4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi Pull spi updates from Mark Brown: "Another quiet release for SPI, almost entirely driver specific changes with the diffstat dominated by two new drivers which are about two thirds of it in terms of lines of code: - new drivers for PIC32 standard and SQI controllers - the Cadence driver has had runtime PM support added and quite a few fixes and cleanups - flash-specific accelerated path support now has a feature query interface - the pxa2xx driver has been moved to use the core DMA mapping support" * tag 'spi-v4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (48 commits) spi: pic32-sqi: Fix linker error, undefined reference to `bad_dma_ops' spi: dw-pci: Spelling s/paltforms/platforms/g spi: pic32-sqi: Remove pic32_sqi_setup and pic32_sqi_cleanup spi: Fix simple typo s/impelment/implement spi: rockchip: potential NULL dereference on error spi: zynqmp: disable clocks in error paths spi: Drop unnecessary dependencies on relaxed I/O accessors spi: qup: Add spi_master_put in remove function spi: qup: Handle clocks in pm_runtime suspend and resume spi: st-ssc4: Fix missing spi_master_put in spi_st_probe error paths spi: st-ssc4: Allow compile test build spi: omap2-mcspi: Use dma_request_chan() for requesting DMA channel spi: davinci: Use dma_request_chan() for requesting DMA channel spi: pic32: Fix checking return value of devm_ioremap_resource spi: spi-fsl-dspi: Update DT binding documentation spi: Drop duplicate code to set master->dev.parent spi: pic32: Set proper bits_per_word_mask spi: return error if kmap'd buffers passed to spi_map_buf() spi: core: add hook flash_read_supported to spi_master spi: pic32-sqi: silence array overflow warning ...
234 lines
5.5 KiB
C
234 lines
5.5 KiB
C
/*
|
|
* CE4100's SPI device is more or less the same one as found on PXA
|
|
*
|
|
*/
|
|
#include <linux/pci.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/of_device.h>
|
|
#include <linux/module.h>
|
|
#include <linux/spi/pxa2xx_spi.h>
|
|
#include <linux/clk-provider.h>
|
|
|
|
#include <linux/dmaengine.h>
|
|
#include <linux/platform_data/dma-dw.h>
|
|
|
|
enum {
|
|
PORT_CE4100,
|
|
PORT_BYT,
|
|
PORT_BSW0,
|
|
PORT_BSW1,
|
|
PORT_BSW2,
|
|
PORT_QUARK_X1000,
|
|
PORT_LPT,
|
|
};
|
|
|
|
struct pxa_spi_info {
|
|
enum pxa_ssp_type type;
|
|
int port_id;
|
|
int num_chipselect;
|
|
unsigned long max_clk_rate;
|
|
|
|
/* DMA channel request parameters */
|
|
void *tx_param;
|
|
void *rx_param;
|
|
};
|
|
|
|
static struct dw_dma_slave byt_tx_param = { .dst_id = 0 };
|
|
static struct dw_dma_slave byt_rx_param = { .src_id = 1 };
|
|
|
|
static struct dw_dma_slave bsw0_tx_param = { .dst_id = 0 };
|
|
static struct dw_dma_slave bsw0_rx_param = { .src_id = 1 };
|
|
static struct dw_dma_slave bsw1_tx_param = { .dst_id = 6 };
|
|
static struct dw_dma_slave bsw1_rx_param = { .src_id = 7 };
|
|
static struct dw_dma_slave bsw2_tx_param = { .dst_id = 8 };
|
|
static struct dw_dma_slave bsw2_rx_param = { .src_id = 9 };
|
|
|
|
static struct dw_dma_slave lpt_tx_param = { .dst_id = 0 };
|
|
static struct dw_dma_slave lpt_rx_param = { .src_id = 1 };
|
|
|
|
static bool lpss_dma_filter(struct dma_chan *chan, void *param)
|
|
{
|
|
struct dw_dma_slave *dws = param;
|
|
|
|
if (dws->dma_dev != chan->device->dev)
|
|
return false;
|
|
|
|
chan->private = dws;
|
|
return true;
|
|
}
|
|
|
|
static struct pxa_spi_info spi_info_configs[] = {
|
|
[PORT_CE4100] = {
|
|
.type = PXA25x_SSP,
|
|
.port_id = -1,
|
|
.num_chipselect = -1,
|
|
.max_clk_rate = 3686400,
|
|
},
|
|
[PORT_BYT] = {
|
|
.type = LPSS_BYT_SSP,
|
|
.port_id = 0,
|
|
.num_chipselect = 1,
|
|
.max_clk_rate = 50000000,
|
|
.tx_param = &byt_tx_param,
|
|
.rx_param = &byt_rx_param,
|
|
},
|
|
[PORT_BSW0] = {
|
|
.type = LPSS_BYT_SSP,
|
|
.port_id = 0,
|
|
.num_chipselect = 1,
|
|
.max_clk_rate = 50000000,
|
|
.tx_param = &bsw0_tx_param,
|
|
.rx_param = &bsw0_rx_param,
|
|
},
|
|
[PORT_BSW1] = {
|
|
.type = LPSS_BYT_SSP,
|
|
.port_id = 1,
|
|
.num_chipselect = 1,
|
|
.max_clk_rate = 50000000,
|
|
.tx_param = &bsw1_tx_param,
|
|
.rx_param = &bsw1_rx_param,
|
|
},
|
|
[PORT_BSW2] = {
|
|
.type = LPSS_BYT_SSP,
|
|
.port_id = 2,
|
|
.num_chipselect = 1,
|
|
.max_clk_rate = 50000000,
|
|
.tx_param = &bsw2_tx_param,
|
|
.rx_param = &bsw2_rx_param,
|
|
},
|
|
[PORT_QUARK_X1000] = {
|
|
.type = QUARK_X1000_SSP,
|
|
.port_id = -1,
|
|
.num_chipselect = 1,
|
|
.max_clk_rate = 50000000,
|
|
},
|
|
[PORT_LPT] = {
|
|
.type = LPSS_LPT_SSP,
|
|
.port_id = 0,
|
|
.num_chipselect = 1,
|
|
.max_clk_rate = 50000000,
|
|
.tx_param = &lpt_tx_param,
|
|
.rx_param = &lpt_rx_param,
|
|
},
|
|
};
|
|
|
|
static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
|
|
const struct pci_device_id *ent)
|
|
{
|
|
struct platform_device_info pi;
|
|
int ret;
|
|
struct platform_device *pdev;
|
|
struct pxa2xx_spi_master spi_pdata;
|
|
struct ssp_device *ssp;
|
|
struct pxa_spi_info *c;
|
|
char buf[40];
|
|
struct pci_dev *dma_dev;
|
|
|
|
ret = pcim_enable_device(dev);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ret = pcim_iomap_regions(dev, 1 << 0, "PXA2xx SPI");
|
|
if (ret)
|
|
return ret;
|
|
|
|
c = &spi_info_configs[ent->driver_data];
|
|
|
|
memset(&spi_pdata, 0, sizeof(spi_pdata));
|
|
spi_pdata.num_chipselect = (c->num_chipselect > 0) ?
|
|
c->num_chipselect : dev->devfn;
|
|
|
|
dma_dev = pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn), 0));
|
|
|
|
if (c->tx_param) {
|
|
struct dw_dma_slave *slave = c->tx_param;
|
|
|
|
slave->dma_dev = &dma_dev->dev;
|
|
slave->m_master = 0;
|
|
slave->p_master = 1;
|
|
}
|
|
|
|
if (c->rx_param) {
|
|
struct dw_dma_slave *slave = c->rx_param;
|
|
|
|
slave->dma_dev = &dma_dev->dev;
|
|
slave->m_master = 0;
|
|
slave->p_master = 1;
|
|
}
|
|
|
|
spi_pdata.dma_filter = lpss_dma_filter;
|
|
spi_pdata.tx_param = c->tx_param;
|
|
spi_pdata.rx_param = c->rx_param;
|
|
spi_pdata.enable_dma = c->rx_param && c->tx_param;
|
|
|
|
ssp = &spi_pdata.ssp;
|
|
ssp->phys_base = pci_resource_start(dev, 0);
|
|
ssp->mmio_base = pcim_iomap_table(dev)[0];
|
|
if (!ssp->mmio_base) {
|
|
dev_err(&dev->dev, "failed to ioremap() registers\n");
|
|
return -EIO;
|
|
}
|
|
ssp->irq = dev->irq;
|
|
ssp->port_id = (c->port_id >= 0) ? c->port_id : dev->devfn;
|
|
ssp->type = c->type;
|
|
|
|
snprintf(buf, sizeof(buf), "pxa2xx-spi.%d", ssp->port_id);
|
|
ssp->clk = clk_register_fixed_rate(&dev->dev, buf , NULL, 0,
|
|
c->max_clk_rate);
|
|
if (IS_ERR(ssp->clk))
|
|
return PTR_ERR(ssp->clk);
|
|
|
|
memset(&pi, 0, sizeof(pi));
|
|
pi.parent = &dev->dev;
|
|
pi.name = "pxa2xx-spi";
|
|
pi.id = ssp->port_id;
|
|
pi.data = &spi_pdata;
|
|
pi.size_data = sizeof(spi_pdata);
|
|
|
|
pdev = platform_device_register_full(&pi);
|
|
if (IS_ERR(pdev)) {
|
|
clk_unregister(ssp->clk);
|
|
return PTR_ERR(pdev);
|
|
}
|
|
|
|
pci_set_drvdata(dev, pdev);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void pxa2xx_spi_pci_remove(struct pci_dev *dev)
|
|
{
|
|
struct platform_device *pdev = pci_get_drvdata(dev);
|
|
struct pxa2xx_spi_master *spi_pdata;
|
|
|
|
spi_pdata = dev_get_platdata(&pdev->dev);
|
|
|
|
platform_device_unregister(pdev);
|
|
clk_unregister(spi_pdata->ssp.clk);
|
|
}
|
|
|
|
static const struct pci_device_id pxa2xx_spi_pci_devices[] = {
|
|
{ PCI_VDEVICE(INTEL, 0x2e6a), PORT_CE4100 },
|
|
{ PCI_VDEVICE(INTEL, 0x0935), PORT_QUARK_X1000 },
|
|
{ PCI_VDEVICE(INTEL, 0x0f0e), PORT_BYT },
|
|
{ PCI_VDEVICE(INTEL, 0x228e), PORT_BSW0 },
|
|
{ PCI_VDEVICE(INTEL, 0x2290), PORT_BSW1 },
|
|
{ PCI_VDEVICE(INTEL, 0x22ac), PORT_BSW2 },
|
|
{ PCI_VDEVICE(INTEL, 0x9ce6), PORT_LPT },
|
|
{ },
|
|
};
|
|
MODULE_DEVICE_TABLE(pci, pxa2xx_spi_pci_devices);
|
|
|
|
static struct pci_driver pxa2xx_spi_pci_driver = {
|
|
.name = "pxa2xx_spi_pci",
|
|
.id_table = pxa2xx_spi_pci_devices,
|
|
.probe = pxa2xx_spi_pci_probe,
|
|
.remove = pxa2xx_spi_pci_remove,
|
|
};
|
|
|
|
module_pci_driver(pxa2xx_spi_pci_driver);
|
|
|
|
MODULE_DESCRIPTION("CE4100/LPSS PCI-SPI glue code for PXA's driver");
|
|
MODULE_LICENSE("GPL v2");
|
|
MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");
|