mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 12:42:02 +00:00
Merge remote-tracking branches 'spi/topic/pl022', 'spi/topic/pxa2xx', 'spi/topic/rspi', 'spi/topic/sh-msiof' and 'spi/topic/sirf' into spi-next
This commit is contained in:
commit
bab4d751f7
@ -6,8 +6,17 @@ Required properties:
|
||||
"renesas,sh-mobile-msiof" for SH Mobile series.
|
||||
Examples with soctypes are:
|
||||
"renesas,msiof-r8a7790" (R-Car H2)
|
||||
"renesas,msiof-r8a7791" (R-Car M2)
|
||||
- reg : Offset and length of the register set for the device
|
||||
"renesas,msiof-r8a7791" (R-Car M2-W)
|
||||
"renesas,msiof-r8a7792" (R-Car V2H)
|
||||
"renesas,msiof-r8a7793" (R-Car M2-N)
|
||||
"renesas,msiof-r8a7794" (R-Car E2)
|
||||
- reg : A list of offsets and lengths of the register sets for
|
||||
the device.
|
||||
If only one register set is present, it is to be used
|
||||
by both the CPU and the DMA engine.
|
||||
If two register sets are present, the first is to be
|
||||
used by the CPU, and the second is to be used by the
|
||||
DMA engine.
|
||||
- interrupt-parent : The phandle for the interrupt controller that
|
||||
services interrupts for this device
|
||||
- interrupts : Interrupt specifier
|
||||
@ -17,12 +26,16 @@ Required properties:
|
||||
Optional properties:
|
||||
- clocks : Must contain a reference to the functional clock.
|
||||
- num-cs : Total number of chip-selects (default is 1)
|
||||
- dmas : Must contain a list of two references to DMA
|
||||
specifiers, one for transmission, and one for
|
||||
reception.
|
||||
- dma-names : Must contain a list of two DMA names, "tx" and "rx".
|
||||
|
||||
Optional properties, deprecated for soctype-specific bindings:
|
||||
- renesas,tx-fifo-size : Overrides the default tx fifo size given in words
|
||||
(default is 64)
|
||||
- renesas,rx-fifo-size : Overrides the default rx fifo size given in words
|
||||
(default is 64, or 256 on R-Car H2 and M2)
|
||||
(default is 64, or 256 on R-Car Gen2)
|
||||
|
||||
Pinctrl properties might be needed, too. See
|
||||
Documentation/devicetree/bindings/pinctrl/renesas,*.
|
||||
@ -31,9 +44,11 @@ Example:
|
||||
|
||||
msiof0: spi@e6e20000 {
|
||||
compatible = "renesas,msiof-r8a7791";
|
||||
reg = <0 0xe6e20000 0 0x0064>;
|
||||
reg = <0 0xe6e20000 0 0x0064>, <0 0xe7e20000 0 0x0064>;
|
||||
interrupts = <0 156 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&mstp0_clks R8A7791_CLK_MSIOF0>;
|
||||
dmas = <&dmac0 0x51>, <&dmac0 0x52>;
|
||||
dma-names = "tx", "rx";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "disabled";
|
||||
|
@ -11,7 +11,10 @@ Required properties:
|
||||
- "renesas,rspi-sh7757" (SH)
|
||||
- "renesas,rspi-r7s72100" (RZ/A1H)
|
||||
- "renesas,qspi-r8a7790" (R-Car H2)
|
||||
- "renesas,qspi-r8a7791" (R-Car M2)
|
||||
- "renesas,qspi-r8a7791" (R-Car M2-W)
|
||||
- "renesas,qspi-r8a7792" (R-Car V2H)
|
||||
- "renesas,qspi-r8a7793" (R-Car M2-N)
|
||||
- "renesas,qspi-r8a7794" (R-Car E2)
|
||||
- reg : Address start and address range size of the device
|
||||
- interrupts : A list of interrupt-specifiers, one for each entry in
|
||||
interrupt-names.
|
||||
@ -30,6 +33,9 @@ Required properties:
|
||||
|
||||
Optional properties:
|
||||
- clocks : Must contain a reference to the functional clock.
|
||||
- dmas : Must contain a list of two references to DMA specifiers,
|
||||
one for transmission, and one for reception.
|
||||
- dma-names : Must contain a list of two DMA names, "tx" and "rx".
|
||||
|
||||
Pinctrl properties might be needed, too. See
|
||||
Documentation/devicetree/bindings/pinctrl/renesas,*.
|
||||
@ -58,4 +64,6 @@ Examples:
|
||||
num-cs = <1>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
dmas = <&dmac0 0x17>, <&dmac0 0x18>;
|
||||
dma-names = "tx", "rx";
|
||||
};
|
||||
|
@ -391,7 +391,7 @@ config SPI_PXA2XX
|
||||
additional documentation can be found a Documentation/spi/pxa2xx.
|
||||
|
||||
config SPI_PXA2XX_PCI
|
||||
def_tristate SPI_PXA2XX && PCI
|
||||
def_tristate SPI_PXA2XX && PCI && COMMON_CLK
|
||||
|
||||
config SPI_ROCKCHIP
|
||||
tristate "Rockchip SPI controller driver"
|
||||
|
@ -82,6 +82,7 @@
|
||||
#define SSP_MIS(r) (r + 0x01C)
|
||||
#define SSP_ICR(r) (r + 0x020)
|
||||
#define SSP_DMACR(r) (r + 0x024)
|
||||
#define SSP_CSR(r) (r + 0x030) /* vendor extension */
|
||||
#define SSP_ITCR(r) (r + 0x080)
|
||||
#define SSP_ITIP(r) (r + 0x084)
|
||||
#define SSP_ITOP(r) (r + 0x088)
|
||||
@ -197,6 +198,12 @@
|
||||
/* Transmit DMA Enable bit */
|
||||
#define SSP_DMACR_MASK_TXDMAE (0x1UL << 1)
|
||||
|
||||
/*
|
||||
* SSP Chip Select Control Register - SSP_CSR
|
||||
* (vendor extension)
|
||||
*/
|
||||
#define SSP_CSR_CSVALUE_MASK (0x1FUL << 0)
|
||||
|
||||
/*
|
||||
* SSP Integration Test control Register - SSP_ITCR
|
||||
*/
|
||||
@ -313,6 +320,7 @@ enum ssp_writing {
|
||||
* @extended_cr: 32 bit wide control register 0 with extra
|
||||
* features and extra features in CR1 as found in the ST variants
|
||||
* @pl023: supports a subset of the ST extensions called "PL023"
|
||||
* @internal_cs_ctrl: supports chip select control register
|
||||
*/
|
||||
struct vendor_data {
|
||||
int fifodepth;
|
||||
@ -321,6 +329,7 @@ struct vendor_data {
|
||||
bool extended_cr;
|
||||
bool pl023;
|
||||
bool loopback;
|
||||
bool internal_cs_ctrl;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -440,9 +449,32 @@ static void null_cs_control(u32 command)
|
||||
pr_debug("pl022: dummy chip select control, CS=0x%x\n", command);
|
||||
}
|
||||
|
||||
/**
|
||||
* internal_cs_control - Control chip select signals via SSP_CSR.
|
||||
* @pl022: SSP driver private data structure
|
||||
* @command: select/delect the chip
|
||||
*
|
||||
* Used on controller with internal chip select control via SSP_CSR register
|
||||
* (vendor extension). Each of the 5 LSB in the register controls one chip
|
||||
* select signal.
|
||||
*/
|
||||
static void internal_cs_control(struct pl022 *pl022, u32 command)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
tmp = readw(SSP_CSR(pl022->virtbase));
|
||||
if (command == SSP_CHIP_SELECT)
|
||||
tmp &= ~BIT(pl022->cur_cs);
|
||||
else
|
||||
tmp |= BIT(pl022->cur_cs);
|
||||
writew(tmp, SSP_CSR(pl022->virtbase));
|
||||
}
|
||||
|
||||
static void pl022_cs_control(struct pl022 *pl022, u32 command)
|
||||
{
|
||||
if (gpio_is_valid(pl022->cur_cs))
|
||||
if (pl022->vendor->internal_cs_ctrl)
|
||||
internal_cs_control(pl022, command);
|
||||
else if (gpio_is_valid(pl022->cur_cs))
|
||||
gpio_set_value(pl022->cur_cs, command);
|
||||
else
|
||||
pl022->cur_chip->cs_control(command);
|
||||
@ -2100,6 +2132,10 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
pl022->vendor = id->data;
|
||||
pl022->chipselects = devm_kzalloc(dev, num_cs * sizeof(int),
|
||||
GFP_KERNEL);
|
||||
if (!pl022->chipselects) {
|
||||
status = -ENOMEM;
|
||||
goto err_no_mem;
|
||||
}
|
||||
|
||||
/*
|
||||
* Bus Number Which has been Assigned to this SSP controller
|
||||
@ -2118,6 +2154,9 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
if (platform_info->num_chipselect && platform_info->chipselects) {
|
||||
for (i = 0; i < num_cs; i++)
|
||||
pl022->chipselects[i] = platform_info->chipselects[i];
|
||||
} else if (pl022->vendor->internal_cs_ctrl) {
|
||||
for (i = 0; i < num_cs; i++)
|
||||
pl022->chipselects[i] = i;
|
||||
} else if (IS_ENABLED(CONFIG_OF)) {
|
||||
for (i = 0; i < num_cs; i++) {
|
||||
int cs_gpio = of_get_named_gpio(np, "cs-gpios", i);
|
||||
@ -2241,6 +2280,7 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
amba_release_regions(adev);
|
||||
err_no_ioregion:
|
||||
err_no_gpio:
|
||||
err_no_mem:
|
||||
spi_master_put(master);
|
||||
return status;
|
||||
}
|
||||
@ -2347,6 +2387,7 @@ static struct vendor_data vendor_arm = {
|
||||
.extended_cr = false,
|
||||
.pl023 = false,
|
||||
.loopback = true,
|
||||
.internal_cs_ctrl = false,
|
||||
};
|
||||
|
||||
static struct vendor_data vendor_st = {
|
||||
@ -2356,6 +2397,7 @@ static struct vendor_data vendor_st = {
|
||||
.extended_cr = true,
|
||||
.pl023 = false,
|
||||
.loopback = true,
|
||||
.internal_cs_ctrl = false,
|
||||
};
|
||||
|
||||
static struct vendor_data vendor_st_pl023 = {
|
||||
@ -2365,6 +2407,17 @@ static struct vendor_data vendor_st_pl023 = {
|
||||
.extended_cr = true,
|
||||
.pl023 = true,
|
||||
.loopback = false,
|
||||
.internal_cs_ctrl = false,
|
||||
};
|
||||
|
||||
static struct vendor_data vendor_lsi = {
|
||||
.fifodepth = 8,
|
||||
.max_bpw = 16,
|
||||
.unidir = false,
|
||||
.extended_cr = false,
|
||||
.pl023 = false,
|
||||
.loopback = true,
|
||||
.internal_cs_ctrl = true,
|
||||
};
|
||||
|
||||
static struct amba_id pl022_ids[] = {
|
||||
@ -2398,6 +2451,15 @@ static struct amba_id pl022_ids[] = {
|
||||
.mask = 0xffffffff,
|
||||
.data = &vendor_st_pl023,
|
||||
},
|
||||
{
|
||||
/*
|
||||
* PL022 variant that has a chip select control register whih
|
||||
* allows control of 5 output signals nCS[0:4].
|
||||
*/
|
||||
.id = 0x000b6022,
|
||||
.mask = 0x000fffff,
|
||||
.data = &vendor_lsi,
|
||||
},
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
|
@ -7,6 +7,8 @@
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/spi/pxa2xx_spi.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
|
||||
enum {
|
||||
PORT_CE4100,
|
||||
@ -21,6 +23,7 @@ struct pxa_spi_info {
|
||||
int tx_chan_id;
|
||||
int rx_slave_id;
|
||||
int rx_chan_id;
|
||||
unsigned long max_clk_rate;
|
||||
};
|
||||
|
||||
static struct pxa_spi_info spi_info_configs[] = {
|
||||
@ -32,6 +35,7 @@ static struct pxa_spi_info spi_info_configs[] = {
|
||||
.tx_chan_id = -1,
|
||||
.rx_slave_id = -1,
|
||||
.rx_chan_id = -1,
|
||||
.max_clk_rate = 3686400,
|
||||
},
|
||||
[PORT_BYT] = {
|
||||
.type = LPSS_SSP,
|
||||
@ -41,6 +45,7 @@ static struct pxa_spi_info spi_info_configs[] = {
|
||||
.tx_chan_id = 0,
|
||||
.rx_slave_id = 1,
|
||||
.rx_chan_id = 1,
|
||||
.max_clk_rate = 50000000,
|
||||
},
|
||||
};
|
||||
|
||||
@ -53,6 +58,7 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
|
||||
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)
|
||||
@ -84,6 +90,12 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
|
||||
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,
|
||||
CLK_IS_ROOT, 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";
|
||||
@ -92,8 +104,10 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
|
||||
pi.size_data = sizeof(spi_pdata);
|
||||
|
||||
pdev = platform_device_register_full(&pi);
|
||||
if (IS_ERR(pdev))
|
||||
if (IS_ERR(pdev)) {
|
||||
clk_unregister(ssp->clk);
|
||||
return PTR_ERR(pdev);
|
||||
}
|
||||
|
||||
pci_set_drvdata(dev, pdev);
|
||||
|
||||
@ -103,8 +117,12 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
|
||||
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[] = {
|
||||
|
@ -87,7 +87,7 @@
|
||||
/* RSPI on SH only */
|
||||
#define SPCR_TXMD 0x02 /* TX Only Mode (vs. Full Duplex) */
|
||||
#define SPCR_SPMS 0x01 /* 3-wire Mode (vs. 4-wire) */
|
||||
/* QSPI on R-Car M2 only */
|
||||
/* QSPI on R-Car Gen2 only */
|
||||
#define SPCR_WSWAP 0x02 /* Word Swap of read-data for DMAC */
|
||||
#define SPCR_BSWAP 0x01 /* Byte Swap of read-data for DMAC */
|
||||
|
||||
@ -909,20 +909,24 @@ static struct dma_chan *rspi_request_dma_chan(struct device *dev,
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
|
||||
chan = dma_request_channel(mask, shdma_chan_filter,
|
||||
(void *)(unsigned long)id);
|
||||
chan = dma_request_slave_channel_compat(mask, shdma_chan_filter,
|
||||
(void *)(unsigned long)id, dev,
|
||||
dir == DMA_MEM_TO_DEV ? "tx" : "rx");
|
||||
if (!chan) {
|
||||
dev_warn(dev, "dma_request_channel failed\n");
|
||||
dev_warn(dev, "dma_request_slave_channel_compat failed\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(&cfg, 0, sizeof(cfg));
|
||||
cfg.slave_id = id;
|
||||
cfg.direction = dir;
|
||||
if (dir == DMA_MEM_TO_DEV)
|
||||
if (dir == DMA_MEM_TO_DEV) {
|
||||
cfg.dst_addr = port_addr;
|
||||
else
|
||||
cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||
} else {
|
||||
cfg.src_addr = port_addr;
|
||||
cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||
}
|
||||
|
||||
ret = dmaengine_slave_config(chan, &cfg);
|
||||
if (ret) {
|
||||
@ -938,22 +942,30 @@ static int rspi_request_dma(struct device *dev, struct spi_master *master,
|
||||
const struct resource *res)
|
||||
{
|
||||
const struct rspi_plat_data *rspi_pd = dev_get_platdata(dev);
|
||||
unsigned int dma_tx_id, dma_rx_id;
|
||||
|
||||
if (!rspi_pd || !rspi_pd->dma_rx_id || !rspi_pd->dma_tx_id)
|
||||
return 0; /* The driver assumes no error. */
|
||||
if (dev->of_node) {
|
||||
/* In the OF case we will get the slave IDs from the DT */
|
||||
dma_tx_id = 0;
|
||||
dma_rx_id = 0;
|
||||
} else if (rspi_pd && rspi_pd->dma_tx_id && rspi_pd->dma_rx_id) {
|
||||
dma_tx_id = rspi_pd->dma_tx_id;
|
||||
dma_rx_id = rspi_pd->dma_rx_id;
|
||||
} else {
|
||||
/* The driver assumes no error. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
master->dma_rx = rspi_request_dma_chan(dev, DMA_DEV_TO_MEM,
|
||||
rspi_pd->dma_rx_id,
|
||||
master->dma_tx = rspi_request_dma_chan(dev, DMA_MEM_TO_DEV, dma_tx_id,
|
||||
res->start + RSPI_SPDR);
|
||||
if (!master->dma_rx)
|
||||
if (!master->dma_tx)
|
||||
return -ENODEV;
|
||||
|
||||
master->dma_tx = rspi_request_dma_chan(dev, DMA_MEM_TO_DEV,
|
||||
rspi_pd->dma_tx_id,
|
||||
master->dma_rx = rspi_request_dma_chan(dev, DMA_DEV_TO_MEM, dma_rx_id,
|
||||
res->start + RSPI_SPDR);
|
||||
if (!master->dma_tx) {
|
||||
dma_release_channel(master->dma_rx);
|
||||
master->dma_rx = NULL;
|
||||
if (!master->dma_rx) {
|
||||
dma_release_channel(master->dma_tx);
|
||||
master->dma_tx = NULL;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@ -1046,12 +1058,11 @@ static int rspi_request_irq(struct device *dev, unsigned int irq,
|
||||
irq_handler_t handler, const char *suffix,
|
||||
void *dev_id)
|
||||
{
|
||||
const char *base = dev_name(dev);
|
||||
size_t len = strlen(base) + strlen(suffix) + 2;
|
||||
char *name = devm_kzalloc(dev, len, GFP_KERNEL);
|
||||
const char *name = devm_kasprintf(dev, GFP_KERNEL, "%s:%s",
|
||||
dev_name(dev), suffix);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
snprintf(name, len, "%s:%s", base, suffix);
|
||||
|
||||
return devm_request_irq(dev, irq, handler, 0, name, dev_id);
|
||||
}
|
||||
|
||||
@ -1084,7 +1095,7 @@ static int rspi_probe(struct platform_device *pdev)
|
||||
master->num_chipselect = rspi_pd->num_chipselect;
|
||||
else
|
||||
master->num_chipselect = 2; /* default */
|
||||
};
|
||||
}
|
||||
|
||||
/* ops parameter check */
|
||||
if (!ops->set_config_register) {
|
||||
|
@ -642,18 +642,14 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
|
||||
desc_rx = dmaengine_prep_slave_single(p->master->dma_rx,
|
||||
p->rx_dma_addr, len, DMA_FROM_DEVICE,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (!desc_rx) {
|
||||
ret = -EAGAIN;
|
||||
goto no_dma_rx;
|
||||
}
|
||||
if (!desc_rx)
|
||||
return -EAGAIN;
|
||||
|
||||
desc_rx->callback = sh_msiof_dma_complete;
|
||||
desc_rx->callback_param = p;
|
||||
cookie = dmaengine_submit(desc_rx);
|
||||
if (dma_submit_error(cookie)) {
|
||||
ret = cookie;
|
||||
goto no_dma_rx;
|
||||
}
|
||||
if (dma_submit_error(cookie))
|
||||
return cookie;
|
||||
}
|
||||
|
||||
if (tx) {
|
||||
@ -738,7 +734,6 @@ no_dma_tx:
|
||||
if (rx)
|
||||
dmaengine_terminate_all(p->master->dma_rx);
|
||||
sh_msiof_write(p, IER, 0);
|
||||
no_dma_rx:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -933,6 +928,9 @@ static const struct of_device_id sh_msiof_match[] = {
|
||||
{ .compatible = "renesas,sh-mobile-msiof", .data = &sh_data },
|
||||
{ .compatible = "renesas,msiof-r8a7790", .data = &r8a779x_data },
|
||||
{ .compatible = "renesas,msiof-r8a7791", .data = &r8a779x_data },
|
||||
{ .compatible = "renesas,msiof-r8a7792", .data = &r8a779x_data },
|
||||
{ .compatible = "renesas,msiof-r8a7793", .data = &r8a779x_data },
|
||||
{ .compatible = "renesas,msiof-r8a7794", .data = &r8a779x_data },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sh_msiof_match);
|
||||
@ -977,20 +975,24 @@ static struct dma_chan *sh_msiof_request_dma_chan(struct device *dev,
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
|
||||
chan = dma_request_channel(mask, shdma_chan_filter,
|
||||
(void *)(unsigned long)id);
|
||||
chan = dma_request_slave_channel_compat(mask, shdma_chan_filter,
|
||||
(void *)(unsigned long)id, dev,
|
||||
dir == DMA_MEM_TO_DEV ? "tx" : "rx");
|
||||
if (!chan) {
|
||||
dev_warn(dev, "dma_request_channel failed\n");
|
||||
dev_warn(dev, "dma_request_slave_channel_compat failed\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(&cfg, 0, sizeof(cfg));
|
||||
cfg.slave_id = id;
|
||||
cfg.direction = dir;
|
||||
if (dir == DMA_MEM_TO_DEV)
|
||||
if (dir == DMA_MEM_TO_DEV) {
|
||||
cfg.dst_addr = port_addr;
|
||||
else
|
||||
cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
} else {
|
||||
cfg.src_addr = port_addr;
|
||||
cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
}
|
||||
|
||||
ret = dmaengine_slave_config(chan, &cfg);
|
||||
if (ret) {
|
||||
@ -1007,12 +1009,22 @@ static int sh_msiof_request_dma(struct sh_msiof_spi_priv *p)
|
||||
struct platform_device *pdev = p->pdev;
|
||||
struct device *dev = &pdev->dev;
|
||||
const struct sh_msiof_spi_info *info = dev_get_platdata(dev);
|
||||
unsigned int dma_tx_id, dma_rx_id;
|
||||
const struct resource *res;
|
||||
struct spi_master *master;
|
||||
struct device *tx_dev, *rx_dev;
|
||||
|
||||
if (!info || !info->dma_tx_id || !info->dma_rx_id)
|
||||
return 0; /* The driver assumes no error */
|
||||
if (dev->of_node) {
|
||||
/* In the OF case we will get the slave IDs from the DT */
|
||||
dma_tx_id = 0;
|
||||
dma_rx_id = 0;
|
||||
} else if (info && info->dma_tx_id && info->dma_rx_id) {
|
||||
dma_tx_id = info->dma_tx_id;
|
||||
dma_rx_id = info->dma_rx_id;
|
||||
} else {
|
||||
/* The driver assumes no error */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The DMA engine uses the second register set, if present */
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
@ -1021,13 +1033,13 @@ static int sh_msiof_request_dma(struct sh_msiof_spi_priv *p)
|
||||
|
||||
master = p->master;
|
||||
master->dma_tx = sh_msiof_request_dma_chan(dev, DMA_MEM_TO_DEV,
|
||||
info->dma_tx_id,
|
||||
dma_tx_id,
|
||||
res->start + TFDR);
|
||||
if (!master->dma_tx)
|
||||
return -ENODEV;
|
||||
|
||||
master->dma_rx = sh_msiof_request_dma_chan(dev, DMA_DEV_TO_MEM,
|
||||
info->dma_rx_id,
|
||||
dma_rx_id,
|
||||
res->start + RFDR);
|
||||
if (!master->dma_rx)
|
||||
goto free_tx_chan;
|
||||
@ -1210,6 +1222,9 @@ static struct platform_device_id spi_driver_ids[] = {
|
||||
{ "spi_sh_msiof", (kernel_ulong_t)&sh_data },
|
||||
{ "spi_r8a7790_msiof", (kernel_ulong_t)&r8a779x_data },
|
||||
{ "spi_r8a7791_msiof", (kernel_ulong_t)&r8a779x_data },
|
||||
{ "spi_r8a7792_msiof", (kernel_ulong_t)&r8a779x_data },
|
||||
{ "spi_r8a7793_msiof", (kernel_ulong_t)&r8a779x_data },
|
||||
{ "spi_r8a7794_msiof", (kernel_ulong_t)&r8a779x_data },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, spi_driver_ids);
|
||||
|
@ -62,15 +62,15 @@
|
||||
#define SIRFSOC_SPI_TRAN_DAT_FORMAT_12 (1 << 26)
|
||||
#define SIRFSOC_SPI_TRAN_DAT_FORMAT_16 (2 << 26)
|
||||
#define SIRFSOC_SPI_TRAN_DAT_FORMAT_32 (3 << 26)
|
||||
#define SIRFSOC_SPI_CMD_BYTE_NUM(x) ((x & 3) << 28)
|
||||
#define SIRFSOC_SPI_ENA_AUTO_CLR BIT(30)
|
||||
#define SIRFSOC_SPI_MUL_DAT_MODE BIT(31)
|
||||
#define SIRFSOC_SPI_CMD_BYTE_NUM(x) ((x & 3) << 28)
|
||||
#define SIRFSOC_SPI_ENA_AUTO_CLR BIT(30)
|
||||
#define SIRFSOC_SPI_MUL_DAT_MODE BIT(31)
|
||||
|
||||
/* Interrupt Enable */
|
||||
#define SIRFSOC_SPI_RX_DONE_INT_EN BIT(0)
|
||||
#define SIRFSOC_SPI_TX_DONE_INT_EN BIT(1)
|
||||
#define SIRFSOC_SPI_RX_OFLOW_INT_EN BIT(2)
|
||||
#define SIRFSOC_SPI_TX_UFLOW_INT_EN BIT(3)
|
||||
#define SIRFSOC_SPI_RX_DONE_INT_EN BIT(0)
|
||||
#define SIRFSOC_SPI_TX_DONE_INT_EN BIT(1)
|
||||
#define SIRFSOC_SPI_RX_OFLOW_INT_EN BIT(2)
|
||||
#define SIRFSOC_SPI_TX_UFLOW_INT_EN BIT(3)
|
||||
#define SIRFSOC_SPI_RX_IO_DMA_INT_EN BIT(4)
|
||||
#define SIRFSOC_SPI_TX_IO_DMA_INT_EN BIT(5)
|
||||
#define SIRFSOC_SPI_RXFIFO_FULL_INT_EN BIT(6)
|
||||
@ -79,7 +79,7 @@
|
||||
#define SIRFSOC_SPI_TXFIFO_THD_INT_EN BIT(9)
|
||||
#define SIRFSOC_SPI_FRM_END_INT_EN BIT(10)
|
||||
|
||||
#define SIRFSOC_SPI_INT_MASK_ALL 0x1FFF
|
||||
#define SIRFSOC_SPI_INT_MASK_ALL 0x1FFF
|
||||
|
||||
/* Interrupt status */
|
||||
#define SIRFSOC_SPI_RX_DONE BIT(0)
|
||||
@ -170,8 +170,7 @@ struct sirfsoc_spi {
|
||||
* command model
|
||||
*/
|
||||
bool tx_by_cmd;
|
||||
|
||||
int chipselect[0];
|
||||
bool hw_cs;
|
||||
};
|
||||
|
||||
static void spi_sirfsoc_rx_word_u8(struct sirfsoc_spi *sspi)
|
||||
@ -304,7 +303,7 @@ static void spi_sirfsoc_dma_fini_callback(void *data)
|
||||
complete(dma_complete);
|
||||
}
|
||||
|
||||
static int spi_sirfsoc_cmd_transfer(struct spi_device *spi,
|
||||
static void spi_sirfsoc_cmd_transfer(struct spi_device *spi,
|
||||
struct spi_transfer *t)
|
||||
{
|
||||
struct sirfsoc_spi *sspi;
|
||||
@ -328,10 +327,9 @@ static int spi_sirfsoc_cmd_transfer(struct spi_device *spi,
|
||||
sspi->base + SIRFSOC_SPI_TX_RX_EN);
|
||||
if (wait_for_completion_timeout(&sspi->tx_done, timeout) == 0) {
|
||||
dev_err(&spi->dev, "cmd transfer timeout\n");
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
return t->len;
|
||||
sspi->left_rx_word -= t->len;
|
||||
}
|
||||
|
||||
static void spi_sirfsoc_dma_transfer(struct spi_device *spi,
|
||||
@ -487,7 +485,7 @@ static void spi_sirfsoc_chipselect(struct spi_device *spi, int value)
|
||||
{
|
||||
struct sirfsoc_spi *sspi = spi_master_get_devdata(spi->master);
|
||||
|
||||
if (sspi->chipselect[spi->chip_select] == 0) {
|
||||
if (sspi->hw_cs) {
|
||||
u32 regval = readl(sspi->base + SIRFSOC_SPI_CTRL);
|
||||
switch (value) {
|
||||
case BITBANG_CS_ACTIVE:
|
||||
@ -505,14 +503,13 @@ static void spi_sirfsoc_chipselect(struct spi_device *spi, int value)
|
||||
}
|
||||
writel(regval, sspi->base + SIRFSOC_SPI_CTRL);
|
||||
} else {
|
||||
int gpio = sspi->chipselect[spi->chip_select];
|
||||
switch (value) {
|
||||
case BITBANG_CS_ACTIVE:
|
||||
gpio_direction_output(gpio,
|
||||
gpio_direction_output(spi->cs_gpio,
|
||||
spi->mode & SPI_CS_HIGH ? 1 : 0);
|
||||
break;
|
||||
case BITBANG_CS_INACTIVE:
|
||||
gpio_direction_output(gpio,
|
||||
gpio_direction_output(spi->cs_gpio,
|
||||
spi->mode & SPI_CS_HIGH ? 0 : 1);
|
||||
break;
|
||||
}
|
||||
@ -606,8 +603,8 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
|
||||
sspi->tx_by_cmd = false;
|
||||
}
|
||||
/*
|
||||
* set spi controller in RISC chipselect mode, we are controlling CS by
|
||||
* software BITBANG_CS_ACTIVE and BITBANG_CS_INACTIVE.
|
||||
* it should never set to hardware cs mode because in hardware cs mode,
|
||||
* cs signal can't controlled by driver.
|
||||
*/
|
||||
regval |= SIRFSOC_SPI_CS_IO_MODE;
|
||||
writel(regval, sspi->base + SIRFSOC_SPI_CTRL);
|
||||
@ -630,9 +627,17 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
|
||||
|
||||
static int spi_sirfsoc_setup(struct spi_device *spi)
|
||||
{
|
||||
struct sirfsoc_spi *sspi;
|
||||
|
||||
if (!spi->max_speed_hz)
|
||||
return -EINVAL;
|
||||
|
||||
sspi = spi_master_get_devdata(spi->master);
|
||||
|
||||
if (spi->cs_gpio == -ENOENT)
|
||||
sspi->hw_cs = true;
|
||||
else
|
||||
sspi->hw_cs = false;
|
||||
return spi_sirfsoc_setup_transfer(spi, NULL);
|
||||
}
|
||||
|
||||
@ -641,19 +646,10 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
|
||||
struct sirfsoc_spi *sspi;
|
||||
struct spi_master *master;
|
||||
struct resource *mem_res;
|
||||
int num_cs, cs_gpio, irq;
|
||||
int i;
|
||||
int ret;
|
||||
int irq;
|
||||
int i, ret;
|
||||
|
||||
ret = of_property_read_u32(pdev->dev.of_node,
|
||||
"sirf,spi-num-chipselects", &num_cs);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Unable to get chip select number\n");
|
||||
goto err_cs;
|
||||
}
|
||||
|
||||
master = spi_alloc_master(&pdev->dev,
|
||||
sizeof(*sspi) + sizeof(int) * num_cs);
|
||||
master = spi_alloc_master(&pdev->dev, sizeof(*sspi));
|
||||
if (!master) {
|
||||
dev_err(&pdev->dev, "Unable to allocate SPI master\n");
|
||||
return -ENOMEM;
|
||||
@ -661,32 +657,6 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, master);
|
||||
sspi = spi_master_get_devdata(master);
|
||||
|
||||
master->num_chipselect = num_cs;
|
||||
|
||||
for (i = 0; i < master->num_chipselect; i++) {
|
||||
cs_gpio = of_get_named_gpio(pdev->dev.of_node, "cs-gpios", i);
|
||||
if (cs_gpio < 0) {
|
||||
dev_err(&pdev->dev, "can't get cs gpio from DT\n");
|
||||
ret = -ENODEV;
|
||||
goto free_master;
|
||||
}
|
||||
|
||||
sspi->chipselect[i] = cs_gpio;
|
||||
if (cs_gpio == 0)
|
||||
continue; /* use cs from spi controller */
|
||||
|
||||
ret = gpio_request(cs_gpio, DRIVER_NAME);
|
||||
if (ret) {
|
||||
while (i > 0) {
|
||||
i--;
|
||||
if (sspi->chipselect[i] > 0)
|
||||
gpio_free(sspi->chipselect[i]);
|
||||
}
|
||||
dev_err(&pdev->dev, "fail to request cs gpios\n");
|
||||
goto free_master;
|
||||
}
|
||||
}
|
||||
|
||||
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
sspi->base = devm_ioremap_resource(&pdev->dev, mem_res);
|
||||
if (IS_ERR(sspi->base)) {
|
||||
@ -756,7 +726,21 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
|
||||
ret = spi_bitbang_start(&sspi->bitbang);
|
||||
if (ret)
|
||||
goto free_dummypage;
|
||||
|
||||
for (i = 0; master->cs_gpios && i < master->num_chipselect; i++) {
|
||||
if (master->cs_gpios[i] == -ENOENT)
|
||||
continue;
|
||||
if (!gpio_is_valid(master->cs_gpios[i])) {
|
||||
dev_err(&pdev->dev, "no valid gpio\n");
|
||||
ret = -EINVAL;
|
||||
goto free_dummypage;
|
||||
}
|
||||
ret = devm_gpio_request(&pdev->dev,
|
||||
master->cs_gpios[i], DRIVER_NAME);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to request gpio\n");
|
||||
goto free_dummypage;
|
||||
}
|
||||
}
|
||||
dev_info(&pdev->dev, "registerred, bus number = %d\n", master->bus_num);
|
||||
|
||||
return 0;
|
||||
@ -771,7 +755,7 @@ free_rx_dma:
|
||||
dma_release_channel(sspi->rx_chan);
|
||||
free_master:
|
||||
spi_master_put(master);
|
||||
err_cs:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -779,16 +763,11 @@ static int spi_sirfsoc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master;
|
||||
struct sirfsoc_spi *sspi;
|
||||
int i;
|
||||
|
||||
master = platform_get_drvdata(pdev);
|
||||
sspi = spi_master_get_devdata(master);
|
||||
|
||||
spi_bitbang_stop(&sspi->bitbang);
|
||||
for (i = 0; i < master->num_chipselect; i++) {
|
||||
if (sspi->chipselect[i] > 0)
|
||||
gpio_free(sspi->chipselect[i]);
|
||||
}
|
||||
kfree(sspi->dummypage);
|
||||
clk_disable_unprepare(sspi->clk);
|
||||
clk_put(sspi->clk);
|
||||
|
@ -44,10 +44,15 @@ struct amba_driver {
|
||||
const struct amba_id *id_table;
|
||||
};
|
||||
|
||||
/*
|
||||
* Constants for the designer field of the Peripheral ID register. When bit 7
|
||||
* is set to '1', bits [6:0] should be the JEP106 manufacturer identity code.
|
||||
*/
|
||||
enum amba_vendor {
|
||||
AMBA_VENDOR_ARM = 0x41,
|
||||
AMBA_VENDOR_ST = 0x80,
|
||||
AMBA_VENDOR_QCOM = 0x51,
|
||||
AMBA_VENDOR_LSI = 0xb6,
|
||||
};
|
||||
|
||||
extern struct bus_type amba_bustype;
|
||||
|
Loading…
Reference in New Issue
Block a user