Merge remote-tracking branches 'spi/topic/pxa2xx', 'spi/topic/rockchip', 'spi/topic/s3c64xx', 'spi/topic/sh' and 'spi/topic/sh-msiof' into spi-next
This commit is contained in:
commit
9a4506b60d
11 changed files with 347 additions and 362 deletions
|
@ -6,10 +6,13 @@ and display controllers using the SPI communication interface.
|
|||
Required Properties:
|
||||
|
||||
- compatible: should be one of the following.
|
||||
"rockchip,rk3066-spi" for rk3066.
|
||||
"rockchip,rk3188-spi", "rockchip,rk3066-spi" for rk3188.
|
||||
"rockchip,rk3288-spi", "rockchip,rk3066-spi" for rk3288.
|
||||
"rockchip,rk3399-spi", "rockchip,rk3066-spi" for rk3399.
|
||||
"rockchip,rk3036-spi" for rk3036 SoCS.
|
||||
"rockchip,rk3066-spi" for rk3066 SoCs.
|
||||
"rockchip,rk3188-spi" for rk3188 SoCs.
|
||||
"rockchip,rk3228-spi" for rk3228 SoCS.
|
||||
"rockchip,rk3288-spi" for rk3288 SoCs.
|
||||
"rockchip,rk3368-spi" for rk3368 SoCs.
|
||||
"rockchip,rk3399-spi" for rk3399 SoCs.
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- interrupts: The interrupt number to the cpu. The interrupt specifier format
|
||||
|
|
|
@ -9,7 +9,8 @@ Required SoC Specific Properties:
|
|||
- samsung,s3c2443-spi: for s3c2443, s3c2416 and s3c2450 platforms
|
||||
- samsung,s3c6410-spi: for s3c6410 platforms
|
||||
- samsung,s5pv210-spi: for s5pv210 and s5pc110 platforms
|
||||
- samsung,exynos7-spi: for exynos7 platforms
|
||||
- samsung,exynos5433-spi: for exynos5433 compatible controllers
|
||||
- samsung,exynos7-spi: for exynos7 platforms <DEPRECATED>
|
||||
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
|
@ -23,6 +24,15 @@ Required SoC Specific Properties:
|
|||
- dma-names: Names for the dma channels. There must be at least one channel
|
||||
named "tx" for transmit and named "rx" for receive.
|
||||
|
||||
- clocks: specifies the clock IDs provided to the SPI controller; they are
|
||||
required for interacting with the controller itself, for synchronizing the bus
|
||||
and as I/O clock (the latter is required by exynos5433 and exynos7).
|
||||
|
||||
- clock-names: string names of the clocks in the 'clocks' property; for all the
|
||||
the devices the names must be "spi", "spi_busclkN" (where N is determined by
|
||||
"samsung,spi-src-clk"), while Exynos5433 should specify a third clock
|
||||
"spi_ioclk" for the I/O clock.
|
||||
|
||||
Required Board Specific Properties:
|
||||
|
||||
- #address-cells: should be 1.
|
||||
|
@ -40,6 +50,9 @@ Optional Board Specific Properties:
|
|||
|
||||
- cs-gpios: should specify GPIOs used for chipselects (see spi-bus.txt)
|
||||
|
||||
- no-cs-readback: the CS line is disconnected, therefore the device should not
|
||||
operate based on CS signalling.
|
||||
|
||||
SPI Controller specific data in SPI slave nodes:
|
||||
|
||||
- The spi slave nodes should provide the following information which is required
|
||||
|
|
|
@ -20,79 +20,6 @@
|
|||
|
||||
#include "spi-pxa2xx.h"
|
||||
|
||||
static int pxa2xx_spi_map_dma_buffer(struct driver_data *drv_data,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
int i, nents, len = drv_data->len;
|
||||
struct scatterlist *sg;
|
||||
struct device *dmadev;
|
||||
struct sg_table *sgt;
|
||||
void *buf, *pbuf;
|
||||
|
||||
if (dir == DMA_TO_DEVICE) {
|
||||
dmadev = drv_data->tx_chan->device->dev;
|
||||
sgt = &drv_data->tx_sgt;
|
||||
buf = drv_data->tx;
|
||||
} else {
|
||||
dmadev = drv_data->rx_chan->device->dev;
|
||||
sgt = &drv_data->rx_sgt;
|
||||
buf = drv_data->rx;
|
||||
}
|
||||
|
||||
nents = DIV_ROUND_UP(len, SZ_2K);
|
||||
if (nents != sgt->nents) {
|
||||
int ret;
|
||||
|
||||
sg_free_table(sgt);
|
||||
ret = sg_alloc_table(sgt, nents, GFP_ATOMIC);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
pbuf = buf;
|
||||
for_each_sg(sgt->sgl, sg, sgt->nents, i) {
|
||||
size_t bytes = min_t(size_t, len, SZ_2K);
|
||||
|
||||
sg_set_buf(sg, pbuf, bytes);
|
||||
pbuf += bytes;
|
||||
len -= bytes;
|
||||
}
|
||||
|
||||
nents = dma_map_sg(dmadev, sgt->sgl, sgt->nents, dir);
|
||||
if (!nents)
|
||||
return -ENOMEM;
|
||||
|
||||
return nents;
|
||||
}
|
||||
|
||||
static void pxa2xx_spi_unmap_dma_buffer(struct driver_data *drv_data,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
struct device *dmadev;
|
||||
struct sg_table *sgt;
|
||||
|
||||
if (dir == DMA_TO_DEVICE) {
|
||||
dmadev = drv_data->tx_chan->device->dev;
|
||||
sgt = &drv_data->tx_sgt;
|
||||
} else {
|
||||
dmadev = drv_data->rx_chan->device->dev;
|
||||
sgt = &drv_data->rx_sgt;
|
||||
}
|
||||
|
||||
dma_unmap_sg(dmadev, sgt->sgl, sgt->nents, dir);
|
||||
}
|
||||
|
||||
static void pxa2xx_spi_unmap_dma_buffers(struct driver_data *drv_data)
|
||||
{
|
||||
if (!drv_data->dma_mapped)
|
||||
return;
|
||||
|
||||
pxa2xx_spi_unmap_dma_buffer(drv_data, DMA_FROM_DEVICE);
|
||||
pxa2xx_spi_unmap_dma_buffer(drv_data, DMA_TO_DEVICE);
|
||||
|
||||
drv_data->dma_mapped = 0;
|
||||
}
|
||||
|
||||
static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data,
|
||||
bool error)
|
||||
{
|
||||
|
@ -125,8 +52,6 @@ static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data,
|
|||
pxa2xx_spi_write(drv_data, SSTO, 0);
|
||||
|
||||
if (!error) {
|
||||
pxa2xx_spi_unmap_dma_buffers(drv_data);
|
||||
|
||||
msg->actual_length += drv_data->len;
|
||||
msg->state = pxa2xx_spi_next_transfer(drv_data);
|
||||
} else {
|
||||
|
@ -152,11 +77,12 @@ pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data,
|
|||
enum dma_transfer_direction dir)
|
||||
{
|
||||
struct chip_data *chip = drv_data->cur_chip;
|
||||
struct spi_transfer *xfer = drv_data->cur_transfer;
|
||||
enum dma_slave_buswidth width;
|
||||
struct dma_slave_config cfg;
|
||||
struct dma_chan *chan;
|
||||
struct sg_table *sgt;
|
||||
int nents, ret;
|
||||
int ret;
|
||||
|
||||
switch (drv_data->n_bytes) {
|
||||
case 1:
|
||||
|
@ -178,17 +104,15 @@ pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data,
|
|||
cfg.dst_addr_width = width;
|
||||
cfg.dst_maxburst = chip->dma_burst_size;
|
||||
|
||||
sgt = &drv_data->tx_sgt;
|
||||
nents = drv_data->tx_nents;
|
||||
chan = drv_data->tx_chan;
|
||||
sgt = &xfer->tx_sg;
|
||||
chan = drv_data->master->dma_tx;
|
||||
} else {
|
||||
cfg.src_addr = drv_data->ssdr_physical;
|
||||
cfg.src_addr_width = width;
|
||||
cfg.src_maxburst = chip->dma_burst_size;
|
||||
|
||||
sgt = &drv_data->rx_sgt;
|
||||
nents = drv_data->rx_nents;
|
||||
chan = drv_data->rx_chan;
|
||||
sgt = &xfer->rx_sg;
|
||||
chan = drv_data->master->dma_rx;
|
||||
}
|
||||
|
||||
ret = dmaengine_slave_config(chan, &cfg);
|
||||
|
@ -197,46 +121,10 @@ pxa2xx_spi_dma_prepare_one(struct driver_data *drv_data,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
return dmaengine_prep_slave_sg(chan, sgt->sgl, nents, dir,
|
||||
return dmaengine_prep_slave_sg(chan, sgt->sgl, sgt->nents, dir,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
}
|
||||
|
||||
bool pxa2xx_spi_dma_is_possible(size_t len)
|
||||
{
|
||||
return len <= MAX_DMA_LEN;
|
||||
}
|
||||
|
||||
int pxa2xx_spi_map_dma_buffers(struct driver_data *drv_data)
|
||||
{
|
||||
const struct chip_data *chip = drv_data->cur_chip;
|
||||
int ret;
|
||||
|
||||
if (!chip->enable_dma)
|
||||
return 0;
|
||||
|
||||
/* Don't bother with DMA if we can't do even a single burst */
|
||||
if (drv_data->len < chip->dma_burst_size)
|
||||
return 0;
|
||||
|
||||
ret = pxa2xx_spi_map_dma_buffer(drv_data, DMA_TO_DEVICE);
|
||||
if (ret <= 0) {
|
||||
dev_warn(&drv_data->pdev->dev, "failed to DMA map TX\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
drv_data->tx_nents = ret;
|
||||
|
||||
ret = pxa2xx_spi_map_dma_buffer(drv_data, DMA_FROM_DEVICE);
|
||||
if (ret <= 0) {
|
||||
pxa2xx_spi_unmap_dma_buffer(drv_data, DMA_TO_DEVICE);
|
||||
dev_warn(&drv_data->pdev->dev, "failed to DMA map RX\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
drv_data->rx_nents = ret;
|
||||
return 1;
|
||||
}
|
||||
|
||||
irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data)
|
||||
{
|
||||
u32 status;
|
||||
|
@ -245,8 +133,8 @@ irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data)
|
|||
if (status & SSSR_ROR) {
|
||||
dev_err(&drv_data->pdev->dev, "FIFO overrun\n");
|
||||
|
||||
dmaengine_terminate_async(drv_data->rx_chan);
|
||||
dmaengine_terminate_async(drv_data->tx_chan);
|
||||
dmaengine_terminate_async(drv_data->master->dma_rx);
|
||||
dmaengine_terminate_async(drv_data->master->dma_tx);
|
||||
|
||||
pxa2xx_spi_dma_transfer_complete(drv_data, true);
|
||||
return IRQ_HANDLED;
|
||||
|
@ -285,16 +173,15 @@ int pxa2xx_spi_dma_prepare(struct driver_data *drv_data, u32 dma_burst)
|
|||
return 0;
|
||||
|
||||
err_rx:
|
||||
dmaengine_terminate_async(drv_data->tx_chan);
|
||||
dmaengine_terminate_async(drv_data->master->dma_tx);
|
||||
err_tx:
|
||||
pxa2xx_spi_unmap_dma_buffers(drv_data);
|
||||
return err;
|
||||
}
|
||||
|
||||
void pxa2xx_spi_dma_start(struct driver_data *drv_data)
|
||||
{
|
||||
dma_async_issue_pending(drv_data->rx_chan);
|
||||
dma_async_issue_pending(drv_data->tx_chan);
|
||||
dma_async_issue_pending(drv_data->master->dma_rx);
|
||||
dma_async_issue_pending(drv_data->master->dma_tx);
|
||||
|
||||
atomic_set(&drv_data->dma_running, 1);
|
||||
}
|
||||
|
@ -303,21 +190,22 @@ int pxa2xx_spi_dma_setup(struct driver_data *drv_data)
|
|||
{
|
||||
struct pxa2xx_spi_master *pdata = drv_data->master_info;
|
||||
struct device *dev = &drv_data->pdev->dev;
|
||||
struct spi_master *master = drv_data->master;
|
||||
dma_cap_mask_t mask;
|
||||
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
|
||||
drv_data->tx_chan = dma_request_slave_channel_compat(mask,
|
||||
master->dma_tx = dma_request_slave_channel_compat(mask,
|
||||
pdata->dma_filter, pdata->tx_param, dev, "tx");
|
||||
if (!drv_data->tx_chan)
|
||||
if (!master->dma_tx)
|
||||
return -ENODEV;
|
||||
|
||||
drv_data->rx_chan = dma_request_slave_channel_compat(mask,
|
||||
master->dma_rx = dma_request_slave_channel_compat(mask,
|
||||
pdata->dma_filter, pdata->rx_param, dev, "rx");
|
||||
if (!drv_data->rx_chan) {
|
||||
dma_release_channel(drv_data->tx_chan);
|
||||
drv_data->tx_chan = NULL;
|
||||
if (!master->dma_rx) {
|
||||
dma_release_channel(master->dma_tx);
|
||||
master->dma_tx = NULL;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
@ -326,17 +214,17 @@ int pxa2xx_spi_dma_setup(struct driver_data *drv_data)
|
|||
|
||||
void pxa2xx_spi_dma_release(struct driver_data *drv_data)
|
||||
{
|
||||
if (drv_data->rx_chan) {
|
||||
dmaengine_terminate_sync(drv_data->rx_chan);
|
||||
dma_release_channel(drv_data->rx_chan);
|
||||
sg_free_table(&drv_data->rx_sgt);
|
||||
drv_data->rx_chan = NULL;
|
||||
struct spi_master *master = drv_data->master;
|
||||
|
||||
if (master->dma_rx) {
|
||||
dmaengine_terminate_sync(master->dma_rx);
|
||||
dma_release_channel(master->dma_rx);
|
||||
master->dma_rx = NULL;
|
||||
}
|
||||
if (drv_data->tx_chan) {
|
||||
dmaengine_terminate_sync(drv_data->tx_chan);
|
||||
dma_release_channel(drv_data->tx_chan);
|
||||
sg_free_table(&drv_data->tx_sgt);
|
||||
drv_data->tx_chan = NULL;
|
||||
if (master->dma_tx) {
|
||||
dmaengine_terminate_sync(master->dma_tx);
|
||||
dma_release_channel(master->dma_tx);
|
||||
master->dma_tx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,24 +1,26 @@
|
|||
/*
|
||||
* CE4100's SPI device is more or less the same one as found on PXA
|
||||
*
|
||||
* Copyright (C) 2016, Intel Corporation
|
||||
*/
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#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_QUARK_X1000,
|
||||
PORT_BYT,
|
||||
PORT_MRFLD,
|
||||
PORT_BSW0,
|
||||
PORT_BSW1,
|
||||
PORT_BSW2,
|
||||
PORT_QUARK_X1000,
|
||||
PORT_CE4100,
|
||||
PORT_LPT,
|
||||
};
|
||||
|
||||
|
@ -29,8 +31,11 @@ struct pxa_spi_info {
|
|||
unsigned long max_clk_rate;
|
||||
|
||||
/* DMA channel request parameters */
|
||||
bool (*dma_filter)(struct dma_chan *chan, void *param);
|
||||
void *tx_param;
|
||||
void *rx_param;
|
||||
|
||||
int (*setup)(struct pci_dev *pdev, struct pxa_spi_info *c);
|
||||
};
|
||||
|
||||
static struct dw_dma_slave byt_tx_param = { .dst_id = 0 };
|
||||
|
@ -57,86 +62,12 @@ static bool lpss_dma_filter(struct dma_chan *chan, void *param)
|
|||
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)
|
||||
static int lpss_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c)
|
||||
{
|
||||
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;
|
||||
c->num_chipselect = 1;
|
||||
c->max_clk_rate = 50000000;
|
||||
|
||||
dma_dev = pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn), 0));
|
||||
|
||||
|
@ -156,7 +87,115 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
|
|||
slave->p_master = 1;
|
||||
}
|
||||
|
||||
spi_pdata.dma_filter = lpss_dma_filter;
|
||||
c->dma_filter = lpss_dma_filter;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mrfld_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c)
|
||||
{
|
||||
switch (PCI_FUNC(dev->devfn)) {
|
||||
case 0:
|
||||
c->port_id = 3;
|
||||
c->num_chipselect = 1;
|
||||
break;
|
||||
case 1:
|
||||
c->port_id = 5;
|
||||
c->num_chipselect = 4;
|
||||
break;
|
||||
case 2:
|
||||
c->port_id = 6;
|
||||
c->num_chipselect = 1;
|
||||
break;
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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,
|
||||
.setup = lpss_spi_setup,
|
||||
.tx_param = &byt_tx_param,
|
||||
.rx_param = &byt_rx_param,
|
||||
},
|
||||
[PORT_BSW0] = {
|
||||
.type = LPSS_BSW_SSP,
|
||||
.port_id = 0,
|
||||
.setup = lpss_spi_setup,
|
||||
.tx_param = &bsw0_tx_param,
|
||||
.rx_param = &bsw0_rx_param,
|
||||
},
|
||||
[PORT_BSW1] = {
|
||||
.type = LPSS_BSW_SSP,
|
||||
.port_id = 1,
|
||||
.setup = lpss_spi_setup,
|
||||
.tx_param = &bsw1_tx_param,
|
||||
.rx_param = &bsw1_rx_param,
|
||||
},
|
||||
[PORT_BSW2] = {
|
||||
.type = LPSS_BSW_SSP,
|
||||
.port_id = 2,
|
||||
.setup = lpss_spi_setup,
|
||||
.tx_param = &bsw2_tx_param,
|
||||
.rx_param = &bsw2_rx_param,
|
||||
},
|
||||
[PORT_MRFLD] = {
|
||||
.type = PXA27x_SSP,
|
||||
.max_clk_rate = 25000000,
|
||||
.setup = mrfld_spi_setup,
|
||||
},
|
||||
[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,
|
||||
.setup = lpss_spi_setup,
|
||||
.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];
|
||||
|
||||
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];
|
||||
if (c->setup) {
|
||||
ret = c->setup(dev, c);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
memset(&spi_pdata, 0, sizeof(spi_pdata));
|
||||
spi_pdata.num_chipselect = (c->num_chipselect > 0) ? c->num_chipselect : dev->devfn;
|
||||
spi_pdata.dma_filter = c->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;
|
||||
|
@ -164,10 +203,6 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
|
|||
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;
|
||||
|
@ -208,12 +243,13 @@ static void pxa2xx_spi_pci_remove(struct pci_dev *dev)
|
|||
}
|
||||
|
||||
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, 0x1194), PORT_MRFLD },
|
||||
{ PCI_VDEVICE(INTEL, 0x228e), PORT_BSW0 },
|
||||
{ PCI_VDEVICE(INTEL, 0x2290), PORT_BSW1 },
|
||||
{ PCI_VDEVICE(INTEL, 0x22ac), PORT_BSW2 },
|
||||
{ PCI_VDEVICE(INTEL, 0x2e6a), PORT_CE4100 },
|
||||
{ PCI_VDEVICE(INTEL, 0x9ce6), PORT_LPT },
|
||||
{ },
|
||||
};
|
||||
|
|
|
@ -919,9 +919,21 @@ static unsigned int pxa2xx_ssp_get_clk_div(struct driver_data *drv_data,
|
|||
return clk_div << 8;
|
||||
}
|
||||
|
||||
static bool pxa2xx_spi_can_dma(struct spi_master *master,
|
||||
struct spi_device *spi,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
struct chip_data *chip = spi_get_ctldata(spi);
|
||||
|
||||
return chip->enable_dma &&
|
||||
xfer->len <= MAX_DMA_LEN &&
|
||||
xfer->len >= chip->dma_burst_size;
|
||||
}
|
||||
|
||||
static void pump_transfers(unsigned long data)
|
||||
{
|
||||
struct driver_data *drv_data = (struct driver_data *)data;
|
||||
struct spi_master *master = drv_data->master;
|
||||
struct spi_message *message = NULL;
|
||||
struct spi_transfer *transfer = NULL;
|
||||
struct spi_transfer *previous = NULL;
|
||||
|
@ -935,6 +947,7 @@ static void pump_transfers(unsigned long data)
|
|||
u32 dma_burst = drv_data->cur_chip->dma_burst_size;
|
||||
u32 change_mask = pxa2xx_spi_get_ssrc1_change_mask(drv_data);
|
||||
int err;
|
||||
int dma_mapped;
|
||||
|
||||
/* Get current state information */
|
||||
message = drv_data->cur_msg;
|
||||
|
@ -969,7 +982,7 @@ static void pump_transfers(unsigned long data)
|
|||
}
|
||||
|
||||
/* Check if we can DMA this transfer */
|
||||
if (!pxa2xx_spi_dma_is_possible(transfer->len) && chip->enable_dma) {
|
||||
if (transfer->len > MAX_DMA_LEN && chip->enable_dma) {
|
||||
|
||||
/* reject already-mapped transfers; PIO won't always work */
|
||||
if (message->is_dma_mapped
|
||||
|
@ -1046,10 +1059,10 @@ static void pump_transfers(unsigned long data)
|
|||
|
||||
message->state = RUNNING_STATE;
|
||||
|
||||
drv_data->dma_mapped = 0;
|
||||
if (pxa2xx_spi_dma_is_possible(drv_data->len))
|
||||
drv_data->dma_mapped = pxa2xx_spi_map_dma_buffers(drv_data);
|
||||
if (drv_data->dma_mapped) {
|
||||
dma_mapped = master->can_dma &&
|
||||
master->can_dma(master, message->spi, transfer) &&
|
||||
master->cur_msg_mapped;
|
||||
if (dma_mapped) {
|
||||
|
||||
/* Ensure we have the correct interrupt handler */
|
||||
drv_data->transfer_handler = pxa2xx_spi_dma_transfer;
|
||||
|
@ -1079,14 +1092,14 @@ static void pump_transfers(unsigned long data)
|
|||
cr0 = pxa2xx_configure_sscr0(drv_data, clk_div, bits);
|
||||
if (!pxa25x_ssp_comp(drv_data))
|
||||
dev_dbg(&message->spi->dev, "%u Hz actual, %s\n",
|
||||
drv_data->master->max_speed_hz
|
||||
master->max_speed_hz
|
||||
/ (1 + ((cr0 & SSCR0_SCR(0xfff)) >> 8)),
|
||||
drv_data->dma_mapped ? "DMA" : "PIO");
|
||||
dma_mapped ? "DMA" : "PIO");
|
||||
else
|
||||
dev_dbg(&message->spi->dev, "%u Hz actual, %s\n",
|
||||
drv_data->master->max_speed_hz / 2
|
||||
master->max_speed_hz / 2
|
||||
/ (1 + ((cr0 & SSCR0_SCR(0x0ff)) >> 8)),
|
||||
drv_data->dma_mapped ? "DMA" : "PIO");
|
||||
dma_mapped ? "DMA" : "PIO");
|
||||
|
||||
if (is_lpss_ssp(drv_data)) {
|
||||
if ((pxa2xx_spi_read(drv_data, SSIRF) & 0xff)
|
||||
|
@ -1247,7 +1260,7 @@ static int setup(struct spi_device *spi)
|
|||
chip->frm = spi->chip_select;
|
||||
} else
|
||||
chip->gpio_cs = -1;
|
||||
chip->enable_dma = 0;
|
||||
chip->enable_dma = drv_data->master_info->enable_dma;
|
||||
chip->timeout = TIMOUT_DFLT;
|
||||
}
|
||||
|
||||
|
@ -1266,17 +1279,9 @@ static int setup(struct spi_device *spi)
|
|||
tx_hi_thres = chip_info->tx_hi_threshold;
|
||||
if (chip_info->rx_threshold)
|
||||
rx_thres = chip_info->rx_threshold;
|
||||
chip->enable_dma = drv_data->master_info->enable_dma;
|
||||
chip->dma_threshold = 0;
|
||||
if (chip_info->enable_loopback)
|
||||
chip->cr1 = SSCR1_LBM;
|
||||
} else if (ACPI_HANDLE(&spi->dev)) {
|
||||
/*
|
||||
* Slave devices enumerated from ACPI namespace don't
|
||||
* usually have chip_info but we still might want to use
|
||||
* DMA with them.
|
||||
*/
|
||||
chip->enable_dma = drv_data->master_info->enable_dma;
|
||||
}
|
||||
|
||||
chip->lpss_rx_threshold = SSIRF_RxThresh(rx_thres);
|
||||
|
@ -1396,6 +1401,9 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = {
|
|||
/* SPT-H */
|
||||
{ PCI_VDEVICE(INTEL, 0xa129), LPSS_SPT_SSP },
|
||||
{ PCI_VDEVICE(INTEL, 0xa12a), LPSS_SPT_SSP },
|
||||
/* KBL-H */
|
||||
{ PCI_VDEVICE(INTEL, 0xa2a9), LPSS_SPT_SSP },
|
||||
{ PCI_VDEVICE(INTEL, 0xa2aa), LPSS_SPT_SSP },
|
||||
/* BXT A-Step */
|
||||
{ PCI_VDEVICE(INTEL, 0x0ac2), LPSS_BXT_SSP },
|
||||
{ PCI_VDEVICE(INTEL, 0x0ac4), LPSS_BXT_SSP },
|
||||
|
@ -1608,6 +1616,8 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
|
|||
if (status) {
|
||||
dev_dbg(dev, "no DMA channels available, using PIO\n");
|
||||
platform_info->enable_dma = false;
|
||||
} else {
|
||||
master->can_dma = pxa2xx_spi_can_dma;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -50,12 +50,6 @@ struct driver_data {
|
|||
struct tasklet_struct pump_transfers;
|
||||
|
||||
/* DMA engine support */
|
||||
struct dma_chan *rx_chan;
|
||||
struct dma_chan *tx_chan;
|
||||
struct sg_table rx_sgt;
|
||||
struct sg_table tx_sgt;
|
||||
int rx_nents;
|
||||
int tx_nents;
|
||||
atomic_t dma_running;
|
||||
|
||||
/* Current message transfer state info */
|
||||
|
@ -67,7 +61,6 @@ struct driver_data {
|
|||
void *tx_end;
|
||||
void *rx;
|
||||
void *rx_end;
|
||||
int dma_mapped;
|
||||
u8 n_bytes;
|
||||
int (*write)(struct driver_data *drv_data);
|
||||
int (*read)(struct driver_data *drv_data);
|
||||
|
@ -145,8 +138,6 @@ extern void *pxa2xx_spi_next_transfer(struct driver_data *drv_data);
|
|||
#define MAX_DMA_LEN SZ_64K
|
||||
#define DEFAULT_DMA_CR1 (SSCR1_TSRE | SSCR1_RSRE | SSCR1_TRAIL)
|
||||
|
||||
extern bool pxa2xx_spi_dma_is_possible(size_t len);
|
||||
extern int pxa2xx_spi_map_dma_buffers(struct driver_data *drv_data);
|
||||
extern irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data);
|
||||
extern int pxa2xx_spi_dma_prepare(struct driver_data *drv_data, u32 dma_burst);
|
||||
extern void pxa2xx_spi_dma_start(struct driver_data *drv_data);
|
||||
|
|
|
@ -911,9 +911,12 @@ static const struct dev_pm_ops rockchip_spi_pm = {
|
|||
};
|
||||
|
||||
static const struct of_device_id rockchip_spi_dt_match[] = {
|
||||
{ .compatible = "rockchip,rk3036-spi", },
|
||||
{ .compatible = "rockchip,rk3066-spi", },
|
||||
{ .compatible = "rockchip,rk3188-spi", },
|
||||
{ .compatible = "rockchip,rk3228-spi", },
|
||||
{ .compatible = "rockchip,rk3288-spi", },
|
||||
{ .compatible = "rockchip,rk3368-spi", },
|
||||
{ .compatible = "rockchip,rk3399-spi", },
|
||||
{ },
|
||||
};
|
||||
|
|
|
@ -156,12 +156,14 @@ struct s3c64xx_spi_port_config {
|
|||
int quirks;
|
||||
bool high_speed;
|
||||
bool clk_from_cmu;
|
||||
bool clk_ioclk;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct s3c64xx_spi_driver_data - Runtime info holder for SPI driver.
|
||||
* @clk: Pointer to the spi clock.
|
||||
* @src_clk: Pointer to the clock used to generate SPI signals.
|
||||
* @ioclk: Pointer to the i/o clock between master and slave
|
||||
* @master: Pointer to the SPI Protocol master.
|
||||
* @cntrlr_info: Platform specific data for the controller this driver manages.
|
||||
* @tgl_spi: Pointer to the last CS left untoggled by the cs_change hint.
|
||||
|
@ -181,6 +183,7 @@ struct s3c64xx_spi_driver_data {
|
|||
void __iomem *regs;
|
||||
struct clk *clk;
|
||||
struct clk *src_clk;
|
||||
struct clk *ioclk;
|
||||
struct platform_device *pdev;
|
||||
struct spi_master *master;
|
||||
struct s3c64xx_spi_info *cntrlr_info;
|
||||
|
@ -310,44 +313,63 @@ static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
|
|||
dma_async_issue_pending(dma->ch);
|
||||
}
|
||||
|
||||
static void s3c64xx_spi_set_cs(struct spi_device *spi, bool enable)
|
||||
{
|
||||
struct s3c64xx_spi_driver_data *sdd =
|
||||
spi_master_get_devdata(spi->master);
|
||||
|
||||
if (sdd->cntrlr_info->no_cs)
|
||||
return;
|
||||
|
||||
if (enable) {
|
||||
if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO)) {
|
||||
writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
|
||||
} else {
|
||||
u32 ssel = readl(sdd->regs + S3C64XX_SPI_SLAVE_SEL);
|
||||
|
||||
ssel |= (S3C64XX_SPI_SLAVE_AUTO |
|
||||
S3C64XX_SPI_SLAVE_NSC_CNT_2);
|
||||
writel(ssel, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
|
||||
}
|
||||
} else {
|
||||
if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO))
|
||||
writel(S3C64XX_SPI_SLAVE_SIG_INACT,
|
||||
sdd->regs + S3C64XX_SPI_SLAVE_SEL);
|
||||
}
|
||||
}
|
||||
|
||||
static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
|
||||
{
|
||||
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
|
||||
dma_filter_fn filter = sdd->cntrlr_info->filter;
|
||||
struct device *dev = &sdd->pdev->dev;
|
||||
dma_cap_mask_t mask;
|
||||
int ret;
|
||||
|
||||
if (!is_polling(sdd)) {
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
if (is_polling(sdd))
|
||||
return 0;
|
||||
|
||||
/* Acquire DMA channels */
|
||||
sdd->rx_dma.ch = dma_request_slave_channel_compat(mask, filter,
|
||||
sdd->cntrlr_info->dma_rx, dev, "rx");
|
||||
if (!sdd->rx_dma.ch) {
|
||||
dev_err(dev, "Failed to get RX DMA channel\n");
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
spi->dma_rx = sdd->rx_dma.ch;
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
|
||||
sdd->tx_dma.ch = dma_request_slave_channel_compat(mask, filter,
|
||||
sdd->cntrlr_info->dma_tx, dev, "tx");
|
||||
if (!sdd->tx_dma.ch) {
|
||||
dev_err(dev, "Failed to get TX DMA channel\n");
|
||||
ret = -EBUSY;
|
||||
goto out_rx;
|
||||
}
|
||||
spi->dma_tx = sdd->tx_dma.ch;
|
||||
/* Acquire DMA channels */
|
||||
sdd->rx_dma.ch = dma_request_slave_channel_compat(mask, filter,
|
||||
sdd->cntrlr_info->dma_rx, dev, "rx");
|
||||
if (!sdd->rx_dma.ch) {
|
||||
dev_err(dev, "Failed to get RX DMA channel\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
spi->dma_rx = sdd->rx_dma.ch;
|
||||
|
||||
sdd->tx_dma.ch = dma_request_slave_channel_compat(mask, filter,
|
||||
sdd->cntrlr_info->dma_tx, dev, "tx");
|
||||
if (!sdd->tx_dma.ch) {
|
||||
dev_err(dev, "Failed to get TX DMA channel\n");
|
||||
dma_release_channel(sdd->rx_dma.ch);
|
||||
return -EBUSY;
|
||||
}
|
||||
spi->dma_tx = sdd->tx_dma.ch;
|
||||
|
||||
return 0;
|
||||
|
||||
out_rx:
|
||||
dma_release_channel(sdd->rx_dma.ch);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
|
||||
|
@ -577,9 +599,7 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
|
|||
u32 val;
|
||||
|
||||
/* Disable Clock */
|
||||
if (sdd->port_conf->clk_from_cmu) {
|
||||
clk_disable_unprepare(sdd->src_clk);
|
||||
} else {
|
||||
if (!sdd->port_conf->clk_from_cmu) {
|
||||
val = readl(regs + S3C64XX_SPI_CLK_CFG);
|
||||
val &= ~S3C64XX_SPI_ENCLK_ENABLE;
|
||||
writel(val, regs + S3C64XX_SPI_CLK_CFG);
|
||||
|
@ -622,11 +642,8 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
|
|||
writel(val, regs + S3C64XX_SPI_MODE_CFG);
|
||||
|
||||
if (sdd->port_conf->clk_from_cmu) {
|
||||
/* Configure Clock */
|
||||
/* There is half-multiplier before the SPI */
|
||||
/* The src_clk clock is divided internally by 2 */
|
||||
clk_set_rate(sdd->src_clk, sdd->cur_speed * 2);
|
||||
/* Enable Clock */
|
||||
clk_prepare_enable(sdd->src_clk);
|
||||
} else {
|
||||
/* Configure Clock */
|
||||
val = readl(regs + S3C64XX_SPI_CLK_CFG);
|
||||
|
@ -651,16 +668,6 @@ static int s3c64xx_spi_prepare_message(struct spi_master *master,
|
|||
struct spi_device *spi = msg->spi;
|
||||
struct s3c64xx_spi_csinfo *cs = spi->controller_data;
|
||||
|
||||
/* If Master's(controller) state differs from that needed by Slave */
|
||||
if (sdd->cur_speed != spi->max_speed_hz
|
||||
|| sdd->cur_mode != spi->mode
|
||||
|| sdd->cur_bpw != spi->bits_per_word) {
|
||||
sdd->cur_bpw = spi->bits_per_word;
|
||||
sdd->cur_speed = spi->max_speed_hz;
|
||||
sdd->cur_mode = spi->mode;
|
||||
s3c64xx_spi_config(sdd);
|
||||
}
|
||||
|
||||
/* Configure feedback delay */
|
||||
writel(cs->fb_delay & 0x3, sdd->regs + S3C64XX_SPI_FB_CLK);
|
||||
|
||||
|
@ -687,6 +694,7 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
|
|||
if (bpw != sdd->cur_bpw || speed != sdd->cur_speed) {
|
||||
sdd->cur_bpw = bpw;
|
||||
sdd->cur_speed = speed;
|
||||
sdd->cur_mode = spi->mode;
|
||||
s3c64xx_spi_config(sdd);
|
||||
}
|
||||
|
||||
|
@ -706,12 +714,7 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
|
|||
enable_datapath(sdd, spi, xfer, use_dma);
|
||||
|
||||
/* Start the signals */
|
||||
if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO))
|
||||
writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
|
||||
else
|
||||
writel(readl(sdd->regs + S3C64XX_SPI_SLAVE_SEL)
|
||||
| S3C64XX_SPI_SLAVE_AUTO | S3C64XX_SPI_SLAVE_NSC_CNT_2,
|
||||
sdd->regs + S3C64XX_SPI_SLAVE_SEL);
|
||||
s3c64xx_spi_set_cs(spi, true);
|
||||
|
||||
spin_unlock_irqrestore(&sdd->lock, flags);
|
||||
|
||||
|
@ -861,16 +864,15 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
|
|||
|
||||
pm_runtime_mark_last_busy(&sdd->pdev->dev);
|
||||
pm_runtime_put_autosuspend(&sdd->pdev->dev);
|
||||
if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO))
|
||||
writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
|
||||
s3c64xx_spi_set_cs(spi, false);
|
||||
|
||||
return 0;
|
||||
|
||||
setup_exit:
|
||||
pm_runtime_mark_last_busy(&sdd->pdev->dev);
|
||||
pm_runtime_put_autosuspend(&sdd->pdev->dev);
|
||||
/* setup() returns with device de-selected */
|
||||
if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO))
|
||||
writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
|
||||
s3c64xx_spi_set_cs(spi, false);
|
||||
|
||||
if (gpio_is_valid(spi->cs_gpio))
|
||||
gpio_free(spi->cs_gpio);
|
||||
|
@ -944,7 +946,9 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel)
|
|||
|
||||
sdd->cur_speed = 0;
|
||||
|
||||
if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO))
|
||||
if (sci->no_cs)
|
||||
writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
|
||||
else if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO))
|
||||
writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
|
||||
|
||||
/* Disable Interrupts - we use Polling if not DMA mode */
|
||||
|
@ -999,6 +1003,8 @@ static struct s3c64xx_spi_info *s3c64xx_spi_parse_dt(struct device *dev)
|
|||
sci->num_cs = temp;
|
||||
}
|
||||
|
||||
sci->no_cs = of_property_read_bool(dev->of_node, "broken-cs");
|
||||
|
||||
return sci;
|
||||
}
|
||||
#else
|
||||
|
@ -1076,7 +1082,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
|
|||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to get alias id, errno %d\n",
|
||||
ret);
|
||||
goto err0;
|
||||
goto err_deref_master;
|
||||
}
|
||||
sdd->port_id = ret;
|
||||
} else {
|
||||
|
@ -1114,13 +1120,13 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
|
|||
sdd->regs = devm_ioremap_resource(&pdev->dev, mem_res);
|
||||
if (IS_ERR(sdd->regs)) {
|
||||
ret = PTR_ERR(sdd->regs);
|
||||
goto err0;
|
||||
goto err_deref_master;
|
||||
}
|
||||
|
||||
if (sci->cfg_gpio && sci->cfg_gpio()) {
|
||||
dev_err(&pdev->dev, "Unable to config gpio\n");
|
||||
ret = -EBUSY;
|
||||
goto err0;
|
||||
goto err_deref_master;
|
||||
}
|
||||
|
||||
/* Setup clocks */
|
||||
|
@ -1128,13 +1134,13 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(sdd->clk)) {
|
||||
dev_err(&pdev->dev, "Unable to acquire clock 'spi'\n");
|
||||
ret = PTR_ERR(sdd->clk);
|
||||
goto err0;
|
||||
goto err_deref_master;
|
||||
}
|
||||
|
||||
if (clk_prepare_enable(sdd->clk)) {
|
||||
ret = clk_prepare_enable(sdd->clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Couldn't enable clock 'spi'\n");
|
||||
ret = -EBUSY;
|
||||
goto err0;
|
||||
goto err_deref_master;
|
||||
}
|
||||
|
||||
sprintf(clk_name, "spi_busclk%d", sci->src_clk_nr);
|
||||
|
@ -1143,13 +1149,28 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
|
|||
dev_err(&pdev->dev,
|
||||
"Unable to acquire clock '%s'\n", clk_name);
|
||||
ret = PTR_ERR(sdd->src_clk);
|
||||
goto err2;
|
||||
goto err_disable_clk;
|
||||
}
|
||||
|
||||
if (clk_prepare_enable(sdd->src_clk)) {
|
||||
ret = clk_prepare_enable(sdd->src_clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Couldn't enable clock '%s'\n", clk_name);
|
||||
ret = -EBUSY;
|
||||
goto err2;
|
||||
goto err_disable_clk;
|
||||
}
|
||||
|
||||
if (sdd->port_conf->clk_ioclk) {
|
||||
sdd->ioclk = devm_clk_get(&pdev->dev, "spi_ioclk");
|
||||
if (IS_ERR(sdd->ioclk)) {
|
||||
dev_err(&pdev->dev, "Unable to acquire 'ioclk'\n");
|
||||
ret = PTR_ERR(sdd->ioclk);
|
||||
goto err_disable_src_clk;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(sdd->ioclk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Couldn't enable clock 'ioclk'\n");
|
||||
goto err_disable_src_clk;
|
||||
}
|
||||
}
|
||||
|
||||
pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_TIMEOUT);
|
||||
|
@ -1169,7 +1190,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
|
|||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Failed to request IRQ %d: %d\n",
|
||||
irq, ret);
|
||||
goto err3;
|
||||
goto err_pm_put;
|
||||
}
|
||||
|
||||
writel(S3C64XX_SPI_INT_RX_OVERRUN_EN | S3C64XX_SPI_INT_RX_UNDERRUN_EN |
|
||||
|
@ -1179,7 +1200,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
|
|||
ret = devm_spi_register_master(&pdev->dev, master);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "cannot register SPI master: %d\n", ret);
|
||||
goto err3;
|
||||
goto err_pm_put;
|
||||
}
|
||||
|
||||
dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d with %d Slaves attached\n",
|
||||
|
@ -1193,15 +1214,17 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
|
|||
|
||||
return 0;
|
||||
|
||||
err3:
|
||||
err_pm_put:
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
|
||||
clk_disable_unprepare(sdd->ioclk);
|
||||
err_disable_src_clk:
|
||||
clk_disable_unprepare(sdd->src_clk);
|
||||
err2:
|
||||
err_disable_clk:
|
||||
clk_disable_unprepare(sdd->clk);
|
||||
err0:
|
||||
err_deref_master:
|
||||
spi_master_put(master);
|
||||
|
||||
return ret;
|
||||
|
@ -1209,13 +1232,15 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
|
|||
|
||||
static int s3c64xx_spi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
|
||||
struct spi_master *master = platform_get_drvdata(pdev);
|
||||
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
|
||||
|
||||
pm_runtime_get_sync(&pdev->dev);
|
||||
|
||||
writel(0, sdd->regs + S3C64XX_SPI_INT_EN);
|
||||
|
||||
clk_disable_unprepare(sdd->ioclk);
|
||||
|
||||
clk_disable_unprepare(sdd->src_clk);
|
||||
|
||||
clk_disable_unprepare(sdd->clk);
|
||||
|
@ -1274,6 +1299,7 @@ static int s3c64xx_spi_runtime_suspend(struct device *dev)
|
|||
|
||||
clk_disable_unprepare(sdd->clk);
|
||||
clk_disable_unprepare(sdd->src_clk);
|
||||
clk_disable_unprepare(sdd->ioclk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1284,17 +1310,28 @@ static int s3c64xx_spi_runtime_resume(struct device *dev)
|
|||
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(sdd->src_clk);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(sdd->clk);
|
||||
if (ret != 0) {
|
||||
clk_disable_unprepare(sdd->src_clk);
|
||||
return ret;
|
||||
if (sdd->port_conf->clk_ioclk) {
|
||||
ret = clk_prepare_enable(sdd->ioclk);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(sdd->src_clk);
|
||||
if (ret != 0)
|
||||
goto err_disable_ioclk;
|
||||
|
||||
ret = clk_prepare_enable(sdd->clk);
|
||||
if (ret != 0)
|
||||
goto err_disable_src_clk;
|
||||
|
||||
return 0;
|
||||
|
||||
err_disable_src_clk:
|
||||
clk_disable_unprepare(sdd->src_clk);
|
||||
err_disable_ioclk:
|
||||
clk_disable_unprepare(sdd->ioclk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
|
@ -1350,6 +1387,16 @@ static struct s3c64xx_spi_port_config exynos7_spi_port_config = {
|
|||
.quirks = S3C64XX_SPI_QUIRK_CS_AUTO,
|
||||
};
|
||||
|
||||
static struct s3c64xx_spi_port_config exynos5433_spi_port_config = {
|
||||
.fifo_lvl_mask = { 0x1ff, 0x7f, 0x7f, 0x7f, 0x7f, 0x1ff},
|
||||
.rx_lvl_offset = 15,
|
||||
.tx_st_done = 25,
|
||||
.high_speed = true,
|
||||
.clk_from_cmu = true,
|
||||
.clk_ioclk = true,
|
||||
.quirks = S3C64XX_SPI_QUIRK_CS_AUTO,
|
||||
};
|
||||
|
||||
static const struct platform_device_id s3c64xx_spi_driver_ids[] = {
|
||||
{
|
||||
.name = "s3c2443-spi",
|
||||
|
@ -1380,6 +1427,9 @@ static const struct of_device_id s3c64xx_spi_dt_match[] = {
|
|||
{ .compatible = "samsung,exynos7-spi",
|
||||
.data = (void *)&exynos7_spi_port_config,
|
||||
},
|
||||
{ .compatible = "samsung,exynos5433-spi",
|
||||
.data = (void *)&exynos5433_spi_port_config,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, s3c64xx_spi_dt_match);
|
||||
|
|
|
@ -45,7 +45,6 @@ struct sh_msiof_spi_priv {
|
|||
void __iomem *mapbase;
|
||||
struct clk *clk;
|
||||
struct platform_device *pdev;
|
||||
const struct sh_msiof_chipdata *chipdata;
|
||||
struct sh_msiof_spi_info *info;
|
||||
struct completion done;
|
||||
unsigned int tx_fifo_size;
|
||||
|
@ -271,7 +270,7 @@ static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p,
|
|||
|
||||
scr = sh_msiof_spi_div_table[k].brdv | SCR_BRPS(brps);
|
||||
sh_msiof_write(p, TSCR, scr);
|
||||
if (!(p->chipdata->master_flags & SPI_MASTER_MUST_TX))
|
||||
if (!(p->master->flags & SPI_MASTER_MUST_TX))
|
||||
sh_msiof_write(p, RSCR, scr);
|
||||
}
|
||||
|
||||
|
@ -336,7 +335,7 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p,
|
|||
tmp |= lsb_first << MDR1_BITLSB_SHIFT;
|
||||
tmp |= sh_msiof_spi_get_dtdl_and_syncdl(p);
|
||||
sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON);
|
||||
if (p->chipdata->master_flags & SPI_MASTER_MUST_TX) {
|
||||
if (p->master->flags & SPI_MASTER_MUST_TX) {
|
||||
/* These bits are reserved if RX needs TX */
|
||||
tmp &= ~0x0000ffff;
|
||||
}
|
||||
|
@ -360,7 +359,7 @@ static void sh_msiof_spi_set_mode_regs(struct sh_msiof_spi_priv *p,
|
|||
{
|
||||
u32 dr2 = MDR2_BITLEN1(bits) | MDR2_WDLEN1(words);
|
||||
|
||||
if (tx_buf || (p->chipdata->master_flags & SPI_MASTER_MUST_TX))
|
||||
if (tx_buf || (p->master->flags & SPI_MASTER_MUST_TX))
|
||||
sh_msiof_write(p, TMDR2, dr2);
|
||||
else
|
||||
sh_msiof_write(p, TMDR2, dr2 | MDR2_GRPMASK1);
|
||||
|
@ -1152,6 +1151,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct resource *r;
|
||||
struct spi_master *master;
|
||||
const struct sh_msiof_chipdata *chipdata;
|
||||
const struct of_device_id *of_id;
|
||||
struct sh_msiof_spi_priv *p;
|
||||
int i;
|
||||
|
@ -1170,10 +1170,10 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
|
|||
|
||||
of_id = of_match_device(sh_msiof_match, &pdev->dev);
|
||||
if (of_id) {
|
||||
p->chipdata = of_id->data;
|
||||
chipdata = of_id->data;
|
||||
p->info = sh_msiof_spi_parse_dt(&pdev->dev);
|
||||
} else {
|
||||
p->chipdata = (const void *)pdev->id_entry->driver_data;
|
||||
chipdata = (const void *)pdev->id_entry->driver_data;
|
||||
p->info = dev_get_platdata(&pdev->dev);
|
||||
}
|
||||
|
||||
|
@ -1217,8 +1217,8 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
|
|||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
/* Platform data may override FIFO sizes */
|
||||
p->tx_fifo_size = p->chipdata->tx_fifo_size;
|
||||
p->rx_fifo_size = p->chipdata->rx_fifo_size;
|
||||
p->tx_fifo_size = chipdata->tx_fifo_size;
|
||||
p->rx_fifo_size = chipdata->rx_fifo_size;
|
||||
if (p->info->tx_fifo_override)
|
||||
p->tx_fifo_size = p->info->tx_fifo_override;
|
||||
if (p->info->rx_fifo_override)
|
||||
|
@ -1227,7 +1227,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
|
|||
/* init master code */
|
||||
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
|
||||
master->mode_bits |= SPI_LSB_FIRST | SPI_3WIRE;
|
||||
master->flags = p->chipdata->master_flags;
|
||||
master->flags = chipdata->master_flags;
|
||||
master->bus_num = pdev->id;
|
||||
master->dev.of_node = pdev->dev.of_node;
|
||||
master->num_chipselect = p->info->num_chipselect;
|
||||
|
|
|
@ -82,7 +82,6 @@ struct spi_sh_data {
|
|||
int irq;
|
||||
struct spi_master *master;
|
||||
struct list_head queue;
|
||||
struct workqueue_struct *workqueue;
|
||||
struct work_struct ws;
|
||||
unsigned long cr1;
|
||||
wait_queue_head_t wait;
|
||||
|
@ -380,7 +379,7 @@ static int spi_sh_transfer(struct spi_device *spi, struct spi_message *mesg)
|
|||
spi_sh_clear_bit(ss, SPI_SH_SSA, SPI_SH_CR1);
|
||||
|
||||
list_add_tail(&mesg->queue, &ss->queue);
|
||||
queue_work(ss->workqueue, &ss->ws);
|
||||
schedule_work(&ss->ws);
|
||||
|
||||
spin_unlock_irqrestore(&ss->lock, flags);
|
||||
|
||||
|
@ -425,7 +424,7 @@ static int spi_sh_remove(struct platform_device *pdev)
|
|||
struct spi_sh_data *ss = platform_get_drvdata(pdev);
|
||||
|
||||
spi_unregister_master(ss->master);
|
||||
destroy_workqueue(ss->workqueue);
|
||||
flush_work(&ss->ws);
|
||||
free_irq(ss->irq, ss);
|
||||
|
||||
return 0;
|
||||
|
@ -484,18 +483,11 @@ static int spi_sh_probe(struct platform_device *pdev)
|
|||
spin_lock_init(&ss->lock);
|
||||
INIT_WORK(&ss->ws, spi_sh_work);
|
||||
init_waitqueue_head(&ss->wait);
|
||||
ss->workqueue = create_singlethread_workqueue(
|
||||
dev_name(master->dev.parent));
|
||||
if (ss->workqueue == NULL) {
|
||||
dev_err(&pdev->dev, "create workqueue error\n");
|
||||
ret = -EBUSY;
|
||||
goto error1;
|
||||
}
|
||||
|
||||
ret = request_irq(irq, spi_sh_irq, 0, "spi_sh", ss);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "request_irq error\n");
|
||||
goto error2;
|
||||
goto error1;
|
||||
}
|
||||
|
||||
master->num_chipselect = 2;
|
||||
|
@ -514,8 +506,6 @@ static int spi_sh_probe(struct platform_device *pdev)
|
|||
|
||||
error3:
|
||||
free_irq(irq, ss);
|
||||
error2:
|
||||
destroy_workqueue(ss->workqueue);
|
||||
error1:
|
||||
spi_master_put(master);
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ struct s3c64xx_spi_csinfo {
|
|||
struct s3c64xx_spi_info {
|
||||
int src_clk_nr;
|
||||
int num_cs;
|
||||
bool no_cs;
|
||||
int (*cfg_gpio)(void);
|
||||
dma_filter_fn filter;
|
||||
void *dma_tx;
|
||||
|
|
Loading…
Reference in a new issue