Merge remote-tracking branches 'spi/topic/s3c64xx', 'spi/topic/sc18is602', 'spi/topic/sh-hspi', 'spi/topic/sh-msiof', 'spi/topic/sh-sci', 'spi/topic/sirf' and 'spi/topic/spidev' into spi-next

This commit is contained in:
Mark Brown 2014-03-30 00:51:34 +00:00
15 changed files with 448 additions and 533 deletions

View File

@ -1,7 +1,29 @@
Renesas HSPI. Renesas HSPI.
Required properties: Required properties:
- compatible : "renesas,hspi" - compatible : "renesas,hspi-<soctype>", "renesas,hspi" as fallback.
- reg : Offset and length of the register set for the device Examples with soctypes are:
- interrupts : interrupt line used by HSPI - "renesas,hspi-r8a7778" (R-Car M1)
- "renesas,hspi-r8a7779" (R-Car H1)
- reg : Offset and length of the register set for the device
- interrupt-parent : The phandle for the interrupt controller that
services interrupts for this device
- interrupts : Interrupt specifier
- #address-cells : Must be <1>
- #size-cells : Must be <0>
Pinctrl properties might be needed, too. See
Documentation/devicetree/bindings/pinctrl/renesas,*.
Example:
hspi0: spi@fffc7000 {
compatible = "renesas,hspi-r8a7778", "renesas,hspi";
reg = <0xfffc7000 0x18>;
interrupt-parent = <&gic>;
interrupts = <0 63 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
};

View File

@ -1,12 +1,40 @@
Renesas MSIOF spi controller Renesas MSIOF spi controller
Required properties: Required properties:
- compatible : "renesas,sh-msiof" for SuperH or - compatible : "renesas,msiof-<soctype>" for SoCs,
"renesas,sh-mobile-msiof" for SH Mobile series "renesas,sh-msiof" for SuperH, or
- reg : Offset and length of the register set for the device "renesas,sh-mobile-msiof" for SH Mobile series.
- interrupts : interrupt line used by MSIOF 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
- interrupt-parent : The phandle for the interrupt controller that
services interrupts for this device
- interrupts : Interrupt specifier
- #address-cells : Must be <1>
- #size-cells : Must be <0>
Optional properties: Optional properties:
- num-cs : total number of chip-selects - clocks : Must contain a reference to the functional clock.
- renesas,tx-fifo-size : Overrides the default tx fifo size given in words - num-cs : Total number of chip-selects (default is 1)
- renesas,rx-fifo-size : Overrides the default rx fifo size given in words
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)
Pinctrl properties might be needed, too. See
Documentation/devicetree/bindings/pinctrl/renesas,*.
Example:
msiof0: spi@e6e20000 {
compatible = "renesas,msiof-r8a7791";
reg = <0 0xe6e20000 0 0x0064>;
interrupts = <0 156 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp0_clks R8A7791_CLK_MSIOF0>;
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
};

View File

@ -85,6 +85,12 @@ settings for data transfer parameters:
SPI_MODE_0..SPI_MODE_3; or if you prefer you can combine SPI_CPOL SPI_MODE_0..SPI_MODE_3; or if you prefer you can combine SPI_CPOL
(clock polarity, idle high iff this is set) or SPI_CPHA (clock phase, (clock polarity, idle high iff this is set) or SPI_CPHA (clock phase,
sample on trailing edge iff this is set) flags. sample on trailing edge iff this is set) flags.
Note that this request is limited to SPI mode flags that fit in a
single byte.
SPI_IOC_RD_MODE32, SPI_IOC_WR_MODE32 ... pass a pointer to a uin32_t
which will return (RD) or assign (WR) the full SPI transfer mode,
not limited to the bits that fit in one byte.
SPI_IOC_RD_LSB_FIRST, SPI_IOC_WR_LSB_FIRST ... pass a pointer to a byte SPI_IOC_RD_LSB_FIRST, SPI_IOC_WR_LSB_FIRST ... pass a pointer to a byte
which will return (RD) or assign (WR) the bit justification used to which will return (RD) or assign (WR) the bit justification used to

View File

@ -78,10 +78,10 @@ static void do_msg(int fd, int len)
static void dumpstat(const char *name, int fd) static void dumpstat(const char *name, int fd)
{ {
__u8 mode, lsb, bits; __u8 lsb, bits;
__u32 speed; __u32 mode, speed;
if (ioctl(fd, SPI_IOC_RD_MODE, &mode) < 0) { if (ioctl(fd, SPI_IOC_RD_MODE32, &mode) < 0) {
perror("SPI rd_mode"); perror("SPI rd_mode");
return; return;
} }
@ -98,7 +98,7 @@ static void dumpstat(const char *name, int fd)
return; return;
} }
printf("%s: spi mode %d, %d bits %sper word, %d Hz max\n", printf("%s: spi mode 0x%x, %d bits %sper word, %d Hz max\n",
name, mode, bits, lsb ? "(lsb first) " : "", speed); name, mode, bits, lsb ? "(lsb first) " : "", speed);
} }

View File

@ -30,7 +30,7 @@ static void pabort(const char *s)
} }
static const char *device = "/dev/spidev1.1"; static const char *device = "/dev/spidev1.1";
static uint8_t mode; static uint32_t mode;
static uint8_t bits = 8; static uint8_t bits = 8;
static uint32_t speed = 500000; static uint32_t speed = 500000;
static uint16_t delay; static uint16_t delay;
@ -57,6 +57,21 @@ static void transfer(int fd)
.bits_per_word = bits, .bits_per_word = bits,
}; };
if (mode & SPI_TX_QUAD)
tr.tx_nbits = 4;
else if (mode & SPI_TX_DUAL)
tr.tx_nbits = 2;
if (mode & SPI_RX_QUAD)
tr.rx_nbits = 4;
else if (mode & SPI_RX_DUAL)
tr.rx_nbits = 2;
if (!(mode & SPI_LOOP)) {
if (mode & (SPI_TX_QUAD | SPI_TX_DUAL))
tr.rx_buf = 0;
else if (mode & (SPI_RX_QUAD | SPI_RX_DUAL))
tr.tx_buf = 0;
}
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr); ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1) if (ret < 1)
pabort("can't send spi message"); pabort("can't send spi message");
@ -81,7 +96,11 @@ static void print_usage(const char *prog)
" -O --cpol clock polarity\n" " -O --cpol clock polarity\n"
" -L --lsb least significant bit first\n" " -L --lsb least significant bit first\n"
" -C --cs-high chip select active high\n" " -C --cs-high chip select active high\n"
" -3 --3wire SI/SO signals shared\n"); " -3 --3wire SI/SO signals shared\n"
" -N --no-cs no chip select\n"
" -R --ready slave pulls low to pause\n"
" -2 --dual dual transfer\n"
" -4 --quad quad transfer\n");
exit(1); exit(1);
} }
@ -101,11 +120,13 @@ static void parse_opts(int argc, char *argv[])
{ "3wire", 0, 0, '3' }, { "3wire", 0, 0, '3' },
{ "no-cs", 0, 0, 'N' }, { "no-cs", 0, 0, 'N' },
{ "ready", 0, 0, 'R' }, { "ready", 0, 0, 'R' },
{ "dual", 0, 0, '2' },
{ "quad", 0, 0, '4' },
{ NULL, 0, 0, 0 }, { NULL, 0, 0, 0 },
}; };
int c; int c;
c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", lopts, NULL); c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR24", lopts, NULL);
if (c == -1) if (c == -1)
break; break;
@ -147,11 +168,23 @@ static void parse_opts(int argc, char *argv[])
case 'R': case 'R':
mode |= SPI_READY; mode |= SPI_READY;
break; break;
case '2':
mode |= SPI_TX_DUAL;
break;
case '4':
mode |= SPI_TX_QUAD;
break;
default: default:
print_usage(argv[0]); print_usage(argv[0]);
break; break;
} }
} }
if (mode & SPI_LOOP) {
if (mode & SPI_TX_DUAL)
mode |= SPI_RX_DUAL;
if (mode & SPI_TX_QUAD)
mode |= SPI_RX_QUAD;
}
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])
@ -168,11 +201,11 @@ int main(int argc, char *argv[])
/* /*
* spi mode * spi mode
*/ */
ret = ioctl(fd, SPI_IOC_WR_MODE, &mode); ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode);
if (ret == -1) if (ret == -1)
pabort("can't set spi mode"); pabort("can't set spi mode");
ret = ioctl(fd, SPI_IOC_RD_MODE, &mode); ret = ioctl(fd, SPI_IOC_RD_MODE32, &mode);
if (ret == -1) if (ret == -1)
pabort("can't get spi mode"); pabort("can't get spi mode");
@ -198,7 +231,7 @@ int main(int argc, char *argv[])
if (ret == -1) if (ret == -1)
pabort("can't get max speed hz"); pabort("can't get max speed hz");
printf("spi mode: %d\n", mode); printf("spi mode: 0x%x\n", mode);
printf("bits per word: %d\n", bits); printf("bits per word: %d\n", bits);
printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000); printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);

View File

@ -429,7 +429,6 @@ config SPI_SH_MSIOF
tristate "SuperH MSIOF SPI controller" tristate "SuperH MSIOF SPI controller"
depends on HAVE_CLK depends on HAVE_CLK
depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
select SPI_BITBANG
help help
SPI driver for SuperH and SH Mobile MSIOF blocks. SPI driver for SuperH and SH Mobile MSIOF blocks.

View File

@ -34,10 +34,6 @@
#include <linux/platform_data/spi-s3c64xx.h> #include <linux/platform_data/spi-s3c64xx.h>
#ifdef CONFIG_S3C_DMA
#include <mach/dma.h>
#endif
#define MAX_SPI_PORTS 3 #define MAX_SPI_PORTS 3
#define S3C64XX_SPI_QUIRK_POLL (1 << 0) #define S3C64XX_SPI_QUIRK_POLL (1 << 0)
@ -200,9 +196,6 @@ struct s3c64xx_spi_driver_data {
unsigned cur_speed; unsigned cur_speed;
struct s3c64xx_spi_dma_data rx_dma; struct s3c64xx_spi_dma_data rx_dma;
struct s3c64xx_spi_dma_data tx_dma; struct s3c64xx_spi_dma_data tx_dma;
#ifdef CONFIG_S3C_DMA
struct samsung_dma_ops *ops;
#endif
struct s3c64xx_spi_port_config *port_conf; struct s3c64xx_spi_port_config *port_conf;
unsigned int port_id; unsigned int port_id;
bool cs_gpio; bool cs_gpio;
@ -284,102 +277,6 @@ static void s3c64xx_spi_dmacb(void *data)
spin_unlock_irqrestore(&sdd->lock, flags); spin_unlock_irqrestore(&sdd->lock, flags);
} }
#ifdef CONFIG_S3C_DMA
/* FIXME: remove this section once arch/arm/mach-s3c64xx uses dmaengine */
static struct s3c2410_dma_client s3c64xx_spi_dma_client = {
.name = "samsung-spi-dma",
};
static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
unsigned len, dma_addr_t buf)
{
struct s3c64xx_spi_driver_data *sdd;
struct samsung_dma_prep info;
struct samsung_dma_config config;
if (dma->direction == DMA_DEV_TO_MEM) {
sdd = container_of((void *)dma,
struct s3c64xx_spi_driver_data, rx_dma);
config.direction = sdd->rx_dma.direction;
config.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA;
config.width = sdd->cur_bpw / 8;
sdd->ops->config((enum dma_ch)sdd->rx_dma.ch, &config);
} else {
sdd = container_of((void *)dma,
struct s3c64xx_spi_driver_data, tx_dma);
config.direction = sdd->tx_dma.direction;
config.fifo = sdd->sfr_start + S3C64XX_SPI_TX_DATA;
config.width = sdd->cur_bpw / 8;
sdd->ops->config((enum dma_ch)sdd->tx_dma.ch, &config);
}
info.cap = DMA_SLAVE;
info.len = len;
info.fp = s3c64xx_spi_dmacb;
info.fp_param = dma;
info.direction = dma->direction;
info.buf = buf;
sdd->ops->prepare((enum dma_ch)dma->ch, &info);
sdd->ops->trigger((enum dma_ch)dma->ch);
}
static int acquire_dma(struct s3c64xx_spi_driver_data *sdd)
{
struct samsung_dma_req req;
struct device *dev = &sdd->pdev->dev;
sdd->ops = samsung_dma_get_ops();
req.cap = DMA_SLAVE;
req.client = &s3c64xx_spi_dma_client;
sdd->rx_dma.ch = (struct dma_chan *)(unsigned long)sdd->ops->request(
sdd->rx_dma.dmach, &req, dev, "rx");
sdd->tx_dma.ch = (struct dma_chan *)(unsigned long)sdd->ops->request(
sdd->tx_dma.dmach, &req, dev, "tx");
return 1;
}
static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
{
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
/*
* If DMA resource was not available during
* probe, no need to continue with dma requests
* else Acquire DMA channels
*/
while (!is_polling(sdd) && !acquire_dma(sdd))
usleep_range(10000, 11000);
return 0;
}
static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
{
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
/* Free DMA channels */
if (!is_polling(sdd)) {
sdd->ops->release((enum dma_ch)sdd->rx_dma.ch,
&s3c64xx_spi_dma_client);
sdd->ops->release((enum dma_ch)sdd->tx_dma.ch,
&s3c64xx_spi_dma_client);
}
return 0;
}
static void s3c64xx_spi_dma_stop(struct s3c64xx_spi_driver_data *sdd,
struct s3c64xx_spi_dma_data *dma)
{
sdd->ops->stop((enum dma_ch)dma->ch);
}
#else
static void prepare_dma(struct s3c64xx_spi_dma_data *dma, static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
struct sg_table *sgt) struct sg_table *sgt)
{ {
@ -437,6 +334,7 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
ret = -EBUSY; ret = -EBUSY;
goto out; goto out;
} }
spi->dma_rx = sdd->rx_dma.ch;
sdd->tx_dma.ch = dma_request_slave_channel_compat(mask, filter, sdd->tx_dma.ch = dma_request_slave_channel_compat(mask, filter,
(void *)sdd->tx_dma.dmach, dev, "tx"); (void *)sdd->tx_dma.dmach, dev, "tx");
@ -445,6 +343,7 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
ret = -EBUSY; ret = -EBUSY;
goto out_rx; goto out_rx;
} }
spi->dma_tx = sdd->tx_dma.ch;
} }
ret = pm_runtime_get_sync(&sdd->pdev->dev); ret = pm_runtime_get_sync(&sdd->pdev->dev);
@ -477,12 +376,14 @@ static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
return 0; return 0;
} }
static void s3c64xx_spi_dma_stop(struct s3c64xx_spi_driver_data *sdd, static bool s3c64xx_spi_can_dma(struct spi_master *master,
struct s3c64xx_spi_dma_data *dma) struct spi_device *spi,
struct spi_transfer *xfer)
{ {
dmaengine_terminate_all(dma->ch); struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
return xfer->len > (FIFO_LVL_MASK(sdd) >> 1) + 1;
} }
#endif
static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
struct spi_device *spi, struct spi_device *spi,
@ -515,11 +416,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
chcfg |= S3C64XX_SPI_CH_TXCH_ON; chcfg |= S3C64XX_SPI_CH_TXCH_ON;
if (dma_mode) { if (dma_mode) {
modecfg |= S3C64XX_SPI_MODE_TXDMA_ON; modecfg |= S3C64XX_SPI_MODE_TXDMA_ON;
#ifndef CONFIG_S3C_DMA
prepare_dma(&sdd->tx_dma, &xfer->tx_sg); prepare_dma(&sdd->tx_dma, &xfer->tx_sg);
#else
prepare_dma(&sdd->tx_dma, xfer->len, xfer->tx_dma);
#endif
} else { } else {
switch (sdd->cur_bpw) { switch (sdd->cur_bpw) {
case 32: case 32:
@ -551,11 +448,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff) writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff)
| S3C64XX_SPI_PACKET_CNT_EN, | S3C64XX_SPI_PACKET_CNT_EN,
regs + S3C64XX_SPI_PACKET_CNT); regs + S3C64XX_SPI_PACKET_CNT);
#ifndef CONFIG_S3C_DMA
prepare_dma(&sdd->rx_dma, &xfer->rx_sg); prepare_dma(&sdd->rx_dma, &xfer->rx_sg);
#else
prepare_dma(&sdd->rx_dma, xfer->len, xfer->rx_dma);
#endif
} }
} }
@ -764,81 +657,6 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
#define XFER_DMAADDR_INVALID DMA_BIT_MASK(32) #define XFER_DMAADDR_INVALID DMA_BIT_MASK(32)
static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd,
struct spi_message *msg)
{
struct device *dev = &sdd->pdev->dev;
struct spi_transfer *xfer;
if (is_polling(sdd) || msg->is_dma_mapped)
return 0;
/* First mark all xfer unmapped */
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
xfer->rx_dma = XFER_DMAADDR_INVALID;
xfer->tx_dma = XFER_DMAADDR_INVALID;
}
/* Map until end or first fail */
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
if (xfer->len <= ((FIFO_LVL_MASK(sdd) >> 1) + 1))
continue;
if (xfer->tx_buf != NULL) {
xfer->tx_dma = dma_map_single(dev,
(void *)xfer->tx_buf, xfer->len,
DMA_TO_DEVICE);
if (dma_mapping_error(dev, xfer->tx_dma)) {
dev_err(dev, "dma_map_single Tx failed\n");
xfer->tx_dma = XFER_DMAADDR_INVALID;
return -ENOMEM;
}
}
if (xfer->rx_buf != NULL) {
xfer->rx_dma = dma_map_single(dev, xfer->rx_buf,
xfer->len, DMA_FROM_DEVICE);
if (dma_mapping_error(dev, xfer->rx_dma)) {
dev_err(dev, "dma_map_single Rx failed\n");
dma_unmap_single(dev, xfer->tx_dma,
xfer->len, DMA_TO_DEVICE);
xfer->tx_dma = XFER_DMAADDR_INVALID;
xfer->rx_dma = XFER_DMAADDR_INVALID;
return -ENOMEM;
}
}
}
return 0;
}
static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd,
struct spi_message *msg)
{
struct device *dev = &sdd->pdev->dev;
struct spi_transfer *xfer;
if (is_polling(sdd) || msg->is_dma_mapped)
return;
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
if (xfer->len <= ((FIFO_LVL_MASK(sdd) >> 1) + 1))
continue;
if (xfer->rx_buf != NULL
&& xfer->rx_dma != XFER_DMAADDR_INVALID)
dma_unmap_single(dev, xfer->rx_dma,
xfer->len, DMA_FROM_DEVICE);
if (xfer->tx_buf != NULL
&& xfer->tx_dma != XFER_DMAADDR_INVALID)
dma_unmap_single(dev, xfer->tx_dma,
xfer->len, DMA_TO_DEVICE);
}
}
static int s3c64xx_spi_prepare_message(struct spi_master *master, static int s3c64xx_spi_prepare_message(struct spi_master *master,
struct spi_message *msg) struct spi_message *msg)
{ {
@ -856,13 +674,6 @@ static int s3c64xx_spi_prepare_message(struct spi_master *master,
s3c64xx_spi_config(sdd); s3c64xx_spi_config(sdd);
} }
/* Map all the transfers if needed */
if (s3c64xx_spi_map_mssg(sdd, msg)) {
dev_err(&spi->dev,
"Xfer: Unable to map message buffers!\n");
return -ENOMEM;
}
/* Configure feedback delay */ /* Configure feedback delay */
writel(cs->fb_delay & 0x3, sdd->regs + S3C64XX_SPI_FB_CLK); writel(cs->fb_delay & 0x3, sdd->regs + S3C64XX_SPI_FB_CLK);
@ -886,13 +697,6 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
bpw = xfer->bits_per_word; bpw = xfer->bits_per_word;
speed = xfer->speed_hz ? : spi->max_speed_hz; speed = xfer->speed_hz ? : spi->max_speed_hz;
if (xfer->len % (bpw / 8)) {
dev_err(&spi->dev,
"Xfer length(%u) not a multiple of word size(%u)\n",
xfer->len, bpw / 8);
return -EIO;
}
if (bpw != sdd->cur_bpw || speed != sdd->cur_speed) { if (bpw != sdd->cur_bpw || speed != sdd->cur_speed) {
sdd->cur_bpw = bpw; sdd->cur_bpw = bpw;
sdd->cur_speed = speed; sdd->cur_speed = speed;
@ -934,10 +738,10 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
if (use_dma) { if (use_dma) {
if (xfer->tx_buf != NULL if (xfer->tx_buf != NULL
&& (sdd->state & TXBUSY)) && (sdd->state & TXBUSY))
s3c64xx_spi_dma_stop(sdd, &sdd->tx_dma); dmaengine_terminate_all(sdd->tx_dma.ch);
if (xfer->rx_buf != NULL if (xfer->rx_buf != NULL
&& (sdd->state & RXBUSY)) && (sdd->state & RXBUSY))
s3c64xx_spi_dma_stop(sdd, &sdd->rx_dma); dmaengine_terminate_all(sdd->rx_dma.ch);
} }
} else { } else {
flush_fifo(sdd); flush_fifo(sdd);
@ -946,16 +750,6 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
return status; return status;
} }
static int s3c64xx_spi_unprepare_message(struct spi_master *master,
struct spi_message *msg)
{
struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
s3c64xx_spi_unmap_mssg(sdd, msg);
return 0;
}
static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata( static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata(
struct spi_device *spi) struct spi_device *spi)
{ {
@ -1329,7 +1123,6 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
master->prepare_transfer_hardware = s3c64xx_spi_prepare_transfer; master->prepare_transfer_hardware = s3c64xx_spi_prepare_transfer;
master->prepare_message = s3c64xx_spi_prepare_message; master->prepare_message = s3c64xx_spi_prepare_message;
master->transfer_one = s3c64xx_spi_transfer_one; master->transfer_one = s3c64xx_spi_transfer_one;
master->unprepare_message = s3c64xx_spi_unprepare_message;
master->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer; master->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer;
master->num_chipselect = sci->num_cs; master->num_chipselect = sci->num_cs;
master->dma_alignment = 8; master->dma_alignment = 8;
@ -1338,6 +1131,8 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
/* the spi->mode bits understood by this driver: */ /* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->auto_runtime_pm = true; master->auto_runtime_pm = true;
if (!is_polling(sdd))
master->can_dma = s3c64xx_spi_can_dma;
sdd->regs = devm_ioremap_resource(&pdev->dev, mem_res); sdd->regs = devm_ioremap_resource(&pdev->dev, mem_res);
if (IS_ERR(sdd->regs)) { if (IS_ERR(sdd->regs)) {

View File

@ -183,17 +183,9 @@ static int sc18is602_setup_transfer(struct sc18is602 *hw, u32 hz, u8 mode)
static int sc18is602_check_transfer(struct spi_device *spi, static int sc18is602_check_transfer(struct spi_device *spi,
struct spi_transfer *t, int tlen) struct spi_transfer *t, int tlen)
{ {
uint32_t hz;
if (t && t->len + tlen > SC18IS602_BUFSIZ) if (t && t->len + tlen > SC18IS602_BUFSIZ)
return -EINVAL; return -EINVAL;
hz = spi->max_speed_hz;
if (t && t->speed_hz)
hz = t->speed_hz;
if (hz == 0)
return -EINVAL;
return 0; return 0;
} }
@ -205,22 +197,15 @@ static int sc18is602_transfer_one(struct spi_master *master,
struct spi_transfer *t; struct spi_transfer *t;
int status = 0; int status = 0;
/* SC18IS602 does not support CS2 */
if (hw->id == sc18is602 && spi->chip_select == 2) {
status = -ENXIO;
goto error;
}
hw->tlen = 0; hw->tlen = 0;
list_for_each_entry(t, &m->transfers, transfer_list) { list_for_each_entry(t, &m->transfers, transfer_list) {
u32 hz = t->speed_hz ? : spi->max_speed_hz;
bool do_transfer; bool do_transfer;
status = sc18is602_check_transfer(spi, t, hw->tlen); status = sc18is602_check_transfer(spi, t, hw->tlen);
if (status < 0) if (status < 0)
break; break;
status = sc18is602_setup_transfer(hw, hz, spi->mode); status = sc18is602_setup_transfer(hw, t->speed_hz, spi->mode);
if (status < 0) if (status < 0)
break; break;
@ -238,7 +223,6 @@ static int sc18is602_transfer_one(struct spi_master *master,
if (t->delay_usecs) if (t->delay_usecs)
udelay(t->delay_usecs); udelay(t->delay_usecs);
} }
error:
m->status = status; m->status = status;
spi_finalize_current_message(master); spi_finalize_current_message(master);
@ -247,10 +231,13 @@ error:
static int sc18is602_setup(struct spi_device *spi) static int sc18is602_setup(struct spi_device *spi)
{ {
if (spi->mode & ~(SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST)) struct sc18is602 *hw = spi_master_get_devdata(spi->master);
return -EINVAL;
return sc18is602_check_transfer(spi, NULL, 0); /* SC18IS602 does not support CS2 */
if (hw->id == sc18is602 && spi->chip_select == 2)
return -ENXIO;
return 0;
} }
static int sc18is602_probe(struct i2c_client *client, static int sc18is602_probe(struct i2c_client *client,
@ -309,6 +296,8 @@ static int sc18is602_probe(struct i2c_client *client,
master->setup = sc18is602_setup; master->setup = sc18is602_setup;
master->transfer_one_message = sc18is602_transfer_one; master->transfer_one_message = sc18is602_transfer_one;
master->dev.of_node = np; master->dev.of_node = np;
master->min_speed_hz = hw->freq / 128;
master->max_speed_hz = hw->freq / 4;
error = devm_spi_register_master(dev, master); error = devm_spi_register_master(dev, master);
if (error) if (error)

View File

@ -46,8 +46,6 @@
/* SPSR */ /* SPSR */
#define RXFL (1 << 2) #define RXFL (1 << 2)
#define hspi2info(h) (h->dev->platform_data)
struct hspi_priv { struct hspi_priv {
void __iomem *addr; void __iomem *addr;
struct spi_master *master; struct spi_master *master;
@ -113,14 +111,9 @@ static void hspi_hw_setup(struct hspi_priv *hspi,
{ {
struct spi_device *spi = msg->spi; struct spi_device *spi = msg->spi;
struct device *dev = hspi->dev; struct device *dev = hspi->dev;
u32 target_rate;
u32 spcr, idiv_clk; u32 spcr, idiv_clk;
u32 rate, best_rate, min, tmp; u32 rate, best_rate, min, tmp;
target_rate = t ? t->speed_hz : 0;
if (!target_rate)
target_rate = spi->max_speed_hz;
/* /*
* find best IDIV/CLKCx settings * find best IDIV/CLKCx settings
*/ */
@ -140,7 +133,7 @@ static void hspi_hw_setup(struct hspi_priv *hspi,
rate /= (((idiv_clk & 0x1F) + 1) * 2); rate /= (((idiv_clk & 0x1F) + 1) * 2);
/* save best settings */ /* save best settings */
tmp = abs(target_rate - rate); tmp = abs(t->speed_hz - rate);
if (tmp < min) { if (tmp < min) {
min = tmp; min = tmp;
spcr = idiv_clk; spcr = idiv_clk;
@ -153,7 +146,7 @@ static void hspi_hw_setup(struct hspi_priv *hspi,
if (spi->mode & SPI_CPOL) if (spi->mode & SPI_CPOL)
spcr |= 1 << 6; spcr |= 1 << 6;
dev_dbg(dev, "speed %d/%d\n", target_rate, best_rate); dev_dbg(dev, "speed %d/%d\n", t->speed_hz, best_rate);
hspi_write(hspi, SPCR, spcr); hspi_write(hspi, SPCR, spcr);
hspi_write(hspi, SPSR, 0x0); hspi_write(hspi, SPSR, 0x0);
@ -230,29 +223,6 @@ static int hspi_transfer_one_message(struct spi_master *master,
return ret; return ret;
} }
static int hspi_setup(struct spi_device *spi)
{
struct hspi_priv *hspi = spi_master_get_devdata(spi->master);
struct device *dev = hspi->dev;
if (8 != spi->bits_per_word) {
dev_err(dev, "bits_per_word should be 8\n");
return -EIO;
}
dev_dbg(dev, "%s setup\n", spi->modalias);
return 0;
}
static void hspi_cleanup(struct spi_device *spi)
{
struct hspi_priv *hspi = spi_master_get_devdata(spi->master);
struct device *dev = hspi->dev;
dev_dbg(dev, "%s cleanup\n", spi->modalias);
}
static int hspi_probe(struct platform_device *pdev) static int hspi_probe(struct platform_device *pdev)
{ {
struct resource *res; struct resource *res;
@ -299,20 +269,22 @@ static int hspi_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev);
master->bus_num = pdev->id; master->bus_num = pdev->id;
master->setup = hspi_setup;
master->cleanup = hspi_cleanup;
master->mode_bits = SPI_CPOL | SPI_CPHA; master->mode_bits = SPI_CPOL | SPI_CPHA;
master->dev.of_node = pdev->dev.of_node; master->dev.of_node = pdev->dev.of_node;
master->auto_runtime_pm = true; master->auto_runtime_pm = true;
master->transfer_one_message = hspi_transfer_one_message; master->transfer_one_message = hspi_transfer_one_message;
master->bits_per_word_mask = SPI_BPW_MASK(8);
ret = devm_spi_register_master(&pdev->dev, master); ret = devm_spi_register_master(&pdev->dev, master);
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, "spi_register_master error.\n"); dev_err(&pdev->dev, "spi_register_master error.\n");
goto error1; goto error2;
} }
return 0; return 0;
error2:
pm_runtime_disable(&pdev->dev);
error1: error1:
clk_put(clk); clk_put(clk);
error0: error0:

View File

@ -20,53 +20,103 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/spi/sh_msiof.h> #include <linux/spi/sh_msiof.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
struct sh_msiof_chipdata {
u16 tx_fifo_size;
u16 rx_fifo_size;
u16 master_flags;
};
struct sh_msiof_spi_priv { struct sh_msiof_spi_priv {
struct spi_bitbang bitbang; /* must be first for spi_bitbang.c */
void __iomem *mapbase; void __iomem *mapbase;
struct clk *clk; struct clk *clk;
struct platform_device *pdev; struct platform_device *pdev;
const struct sh_msiof_chipdata *chipdata;
struct sh_msiof_spi_info *info; struct sh_msiof_spi_info *info;
struct completion done; struct completion done;
unsigned long flags;
int tx_fifo_size; int tx_fifo_size;
int rx_fifo_size; int rx_fifo_size;
}; };
#define TMDR1 0x00 #define TMDR1 0x00 /* Transmit Mode Register 1 */
#define TMDR2 0x04 #define TMDR2 0x04 /* Transmit Mode Register 2 */
#define TMDR3 0x08 #define TMDR3 0x08 /* Transmit Mode Register 3 */
#define RMDR1 0x10 #define RMDR1 0x10 /* Receive Mode Register 1 */
#define RMDR2 0x14 #define RMDR2 0x14 /* Receive Mode Register 2 */
#define RMDR3 0x18 #define RMDR3 0x18 /* Receive Mode Register 3 */
#define TSCR 0x20 #define TSCR 0x20 /* Transmit Clock Select Register */
#define RSCR 0x22 #define RSCR 0x22 /* Receive Clock Select Register (SH, A1, APE6) */
#define CTR 0x28 #define CTR 0x28 /* Control Register */
#define FCTR 0x30 #define FCTR 0x30 /* FIFO Control Register */
#define STR 0x40 #define STR 0x40 /* Status Register */
#define IER 0x44 #define IER 0x44 /* Interrupt Enable Register */
#define TDR1 0x48 #define TDR1 0x48 /* Transmit Control Data Register 1 (SH, A1) */
#define TDR2 0x4c #define TDR2 0x4c /* Transmit Control Data Register 2 (SH, A1) */
#define TFDR 0x50 #define TFDR 0x50 /* Transmit FIFO Data Register */
#define RDR1 0x58 #define RDR1 0x58 /* Receive Control Data Register 1 (SH, A1) */
#define RDR2 0x5c #define RDR2 0x5c /* Receive Control Data Register 2 (SH, A1) */
#define RFDR 0x60 #define RFDR 0x60 /* Receive FIFO Data Register */
#define CTR_TSCKE (1 << 15) /* TMDR1 and RMDR1 */
#define CTR_TFSE (1 << 14) #define MDR1_TRMD 0x80000000 /* Transfer Mode (1 = Master mode) */
#define CTR_TXE (1 << 9) #define MDR1_SYNCMD_MASK 0x30000000 /* SYNC Mode */
#define CTR_RXE (1 << 8) #define MDR1_SYNCMD_SPI 0x20000000 /* Level mode/SPI */
#define MDR1_SYNCMD_LR 0x30000000 /* L/R mode */
#define MDR1_SYNCAC_SHIFT 25 /* Sync Polarity (1 = Active-low) */
#define MDR1_BITLSB_SHIFT 24 /* MSB/LSB First (1 = LSB first) */
#define MDR1_FLD_MASK 0x000000c0 /* Frame Sync Signal Interval (0-3) */
#define MDR1_FLD_SHIFT 2
#define MDR1_XXSTP 0x00000001 /* Transmission/Reception Stop on FIFO */
/* TMDR1 */
#define TMDR1_PCON 0x40000000 /* Transfer Signal Connection */
/* TMDR2 and RMDR2 */
#define MDR2_BITLEN1(i) (((i) - 1) << 24) /* Data Size (8-32 bits) */
#define MDR2_WDLEN1(i) (((i) - 1) << 16) /* Word Count (1-64/256 (SH, A1))) */
#define MDR2_GRPMASK1 0x00000001 /* Group Output Mask 1 (SH, A1) */
/* TSCR and RSCR */
#define SCR_BRPS_MASK 0x1f00 /* Prescaler Setting (1-32) */
#define SCR_BRPS(i) (((i) - 1) << 8)
#define SCR_BRDV_MASK 0x0007 /* Baud Rate Generator's Division Ratio */
#define SCR_BRDV_DIV_2 0x0000
#define SCR_BRDV_DIV_4 0x0001
#define SCR_BRDV_DIV_8 0x0002
#define SCR_BRDV_DIV_16 0x0003
#define SCR_BRDV_DIV_32 0x0004
#define SCR_BRDV_DIV_1 0x0007
/* CTR */
#define CTR_TSCKIZ_MASK 0xc0000000 /* Transmit Clock I/O Polarity Select */
#define CTR_TSCKIZ_SCK 0x80000000 /* Disable SCK when TX disabled */
#define CTR_TSCKIZ_POL_SHIFT 30 /* Transmit Clock Polarity */
#define CTR_RSCKIZ_MASK 0x30000000 /* Receive Clock Polarity Select */
#define CTR_RSCKIZ_SCK 0x20000000 /* Must match CTR_TSCKIZ_SCK */
#define CTR_RSCKIZ_POL_SHIFT 28 /* Receive Clock Polarity */
#define CTR_TEDG_SHIFT 27 /* Transmit Timing (1 = falling edge) */
#define CTR_REDG_SHIFT 26 /* Receive Timing (1 = falling edge) */
#define CTR_TXDIZ_MASK 0x00c00000 /* Pin Output When TX is Disabled */
#define CTR_TXDIZ_LOW 0x00000000 /* 0 */
#define CTR_TXDIZ_HIGH 0x00400000 /* 1 */
#define CTR_TXDIZ_HIZ 0x00800000 /* High-impedance */
#define CTR_TSCKE 0x00008000 /* Transmit Serial Clock Output Enable */
#define CTR_TFSE 0x00004000 /* Transmit Frame Sync Signal Output Enable */
#define CTR_TXE 0x00000200 /* Transmit Enable */
#define CTR_RXE 0x00000100 /* Receive Enable */
/* STR and IER */
#define STR_TEOF 0x00800000 /* Frame Transmission End */
#define STR_REOF 0x00000080 /* Frame Reception End */
#define STR_TEOF (1 << 23)
#define STR_REOF (1 << 7)
static u32 sh_msiof_read(struct sh_msiof_spi_priv *p, int reg_offs) static u32 sh_msiof_read(struct sh_msiof_spi_priv *p, int reg_offs)
{ {
@ -130,22 +180,21 @@ static struct {
unsigned short div; unsigned short div;
unsigned short scr; unsigned short scr;
} const sh_msiof_spi_clk_table[] = { } const sh_msiof_spi_clk_table[] = {
{ 1, 0x0007 }, { 1, SCR_BRPS( 1) | SCR_BRDV_DIV_1 },
{ 2, 0x0000 }, { 2, SCR_BRPS( 1) | SCR_BRDV_DIV_2 },
{ 4, 0x0001 }, { 4, SCR_BRPS( 1) | SCR_BRDV_DIV_4 },
{ 8, 0x0002 }, { 8, SCR_BRPS( 1) | SCR_BRDV_DIV_8 },
{ 16, 0x0003 }, { 16, SCR_BRPS( 1) | SCR_BRDV_DIV_16 },
{ 32, 0x0004 }, { 32, SCR_BRPS( 1) | SCR_BRDV_DIV_32 },
{ 64, 0x1f00 }, { 64, SCR_BRPS(32) | SCR_BRDV_DIV_2 },
{ 128, 0x1f01 }, { 128, SCR_BRPS(32) | SCR_BRDV_DIV_4 },
{ 256, 0x1f02 }, { 256, SCR_BRPS(32) | SCR_BRDV_DIV_8 },
{ 512, 0x1f03 }, { 512, SCR_BRPS(32) | SCR_BRDV_DIV_16 },
{ 1024, 0x1f04 }, { 1024, SCR_BRPS(32) | SCR_BRDV_DIV_32 },
}; };
static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p, static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p,
unsigned long parent_rate, unsigned long parent_rate, u32 spi_hz)
unsigned long spi_hz)
{ {
unsigned long div = 1024; unsigned long div = 1024;
size_t k; size_t k;
@ -163,7 +212,8 @@ static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p,
k = min_t(int, k, ARRAY_SIZE(sh_msiof_spi_clk_table) - 1); k = min_t(int, k, ARRAY_SIZE(sh_msiof_spi_clk_table) - 1);
sh_msiof_write(p, TSCR, sh_msiof_spi_clk_table[k].scr); sh_msiof_write(p, TSCR, sh_msiof_spi_clk_table[k].scr);
sh_msiof_write(p, RSCR, sh_msiof_spi_clk_table[k].scr); if (!(p->chipdata->master_flags & SPI_MASTER_MUST_TX))
sh_msiof_write(p, RSCR, sh_msiof_spi_clk_table[k].scr);
} }
static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p, static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p,
@ -182,21 +232,25 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p,
*/ */
sh_msiof_write(p, FCTR, 0); sh_msiof_write(p, FCTR, 0);
tmp = 0; tmp = MDR1_SYNCMD_SPI | 1 << MDR1_FLD_SHIFT | MDR1_XXSTP;
tmp |= !cs_high << 25; tmp |= !cs_high << MDR1_SYNCAC_SHIFT;
tmp |= lsb_first << 24; tmp |= lsb_first << MDR1_BITLSB_SHIFT;
sh_msiof_write(p, TMDR1, 0xe0000005 | tmp); sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON);
sh_msiof_write(p, RMDR1, 0x20000005 | tmp); if (p->chipdata->master_flags & SPI_MASTER_MUST_TX) {
/* These bits are reserved if RX needs TX */
tmp &= ~0x0000ffff;
}
sh_msiof_write(p, RMDR1, tmp);
tmp = 0xa0000000; tmp = 0;
tmp |= cpol << 30; /* TSCKIZ */ tmp |= CTR_TSCKIZ_SCK | cpol << CTR_TSCKIZ_POL_SHIFT;
tmp |= cpol << 28; /* RSCKIZ */ tmp |= CTR_RSCKIZ_SCK | cpol << CTR_RSCKIZ_POL_SHIFT;
edge = cpol ^ !cpha; edge = cpol ^ !cpha;
tmp |= edge << 27; /* TEDG */ tmp |= edge << CTR_TEDG_SHIFT;
tmp |= edge << 26; /* REDG */ tmp |= edge << CTR_REDG_SHIFT;
tmp |= (tx_hi_z ? 2 : 0) << 22; /* TXDIZ */ tmp |= tx_hi_z ? CTR_TXDIZ_HIZ : CTR_TXDIZ_LOW;
sh_msiof_write(p, CTR, tmp); sh_msiof_write(p, CTR, tmp);
} }
@ -204,12 +258,12 @@ static void sh_msiof_spi_set_mode_regs(struct sh_msiof_spi_priv *p,
const void *tx_buf, void *rx_buf, const void *tx_buf, void *rx_buf,
u32 bits, u32 words) u32 bits, u32 words)
{ {
u32 dr2 = ((bits - 1) << 24) | ((words - 1) << 16); u32 dr2 = MDR2_BITLEN1(bits) | MDR2_WDLEN1(words);
if (tx_buf) if (tx_buf || (p->chipdata->master_flags & SPI_MASTER_MUST_TX))
sh_msiof_write(p, TMDR2, dr2); sh_msiof_write(p, TMDR2, dr2);
else else
sh_msiof_write(p, TMDR2, dr2 | 1); sh_msiof_write(p, TMDR2, dr2 | MDR2_GRPMASK1);
if (rx_buf) if (rx_buf)
sh_msiof_write(p, RMDR2, dr2); sh_msiof_write(p, RMDR2, dr2);
@ -362,77 +416,45 @@ static void sh_msiof_spi_read_fifo_s32u(struct sh_msiof_spi_priv *p,
put_unaligned(swab32(sh_msiof_read(p, RFDR) >> fs), &buf_32[k]); put_unaligned(swab32(sh_msiof_read(p, RFDR) >> fs), &buf_32[k]);
} }
static int sh_msiof_spi_bits(struct spi_device *spi, struct spi_transfer *t) static int sh_msiof_spi_setup(struct spi_device *spi)
{
int bits;
bits = t ? t->bits_per_word : 0;
if (!bits)
bits = spi->bits_per_word;
return bits;
}
static unsigned long sh_msiof_spi_hz(struct spi_device *spi,
struct spi_transfer *t)
{
unsigned long hz;
hz = t ? t->speed_hz : 0;
if (!hz)
hz = spi->max_speed_hz;
return hz;
}
static int sh_msiof_spi_setup_transfer(struct spi_device *spi,
struct spi_transfer *t)
{
int bits;
/* noting to check hz values against since parent clock is disabled */
bits = sh_msiof_spi_bits(spi, t);
if (bits < 8)
return -EINVAL;
if (bits > 32)
return -EINVAL;
return spi_bitbang_setup_transfer(spi, t);
}
static void sh_msiof_spi_chipselect(struct spi_device *spi, int is_on)
{ {
struct device_node *np = spi->master->dev.of_node;
struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master); struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master);
int value;
/* chip select is active low unless SPI_CS_HIGH is set */ if (!np) {
if (spi->mode & SPI_CS_HIGH) /*
value = (is_on == BITBANG_CS_ACTIVE) ? 1 : 0; * Use spi->controller_data for CS (same strategy as spi_gpio),
else * if any. otherwise let HW control CS
value = (is_on == BITBANG_CS_ACTIVE) ? 0 : 1; */
spi->cs_gpio = (uintptr_t)spi->controller_data;
if (is_on == BITBANG_CS_ACTIVE) {
if (!test_and_set_bit(0, &p->flags)) {
pm_runtime_get_sync(&p->pdev->dev);
clk_enable(p->clk);
}
/* Configure pins before asserting CS */
sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL),
!!(spi->mode & SPI_CPHA),
!!(spi->mode & SPI_3WIRE),
!!(spi->mode & SPI_LSB_FIRST),
!!(spi->mode & SPI_CS_HIGH));
} }
/* use spi->controller data for CS (same strategy as spi_gpio) */ /* Configure pins before deasserting CS */
gpio_set_value((uintptr_t)spi->controller_data, value); sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL),
!!(spi->mode & SPI_CPHA),
!!(spi->mode & SPI_3WIRE),
!!(spi->mode & SPI_LSB_FIRST),
!!(spi->mode & SPI_CS_HIGH));
if (is_on == BITBANG_CS_INACTIVE) { if (spi->cs_gpio >= 0)
if (test_and_clear_bit(0, &p->flags)) { gpio_set_value(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
clk_disable(p->clk);
pm_runtime_put(&p->pdev->dev); return 0;
} }
}
static int sh_msiof_prepare_message(struct spi_master *master,
struct spi_message *msg)
{
struct sh_msiof_spi_priv *p = spi_master_get_devdata(master);
const struct spi_device *spi = msg->spi;
/* Configure pins before asserting CS */
sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL),
!!(spi->mode & SPI_CPHA),
!!(spi->mode & SPI_3WIRE),
!!(spi->mode & SPI_LSB_FIRST),
!!(spi->mode & SPI_CS_HIGH));
return 0;
} }
static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p,
@ -486,7 +508,7 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p,
/* clear status bits */ /* clear status bits */
sh_msiof_reset_str(p); sh_msiof_reset_str(p);
/* shut down frame, tx/tx and clock signals */ /* shut down frame, rx/tx and clock signals */
ret = sh_msiof_modify_ctr_wait(p, CTR_TFSE, 0); ret = sh_msiof_modify_ctr_wait(p, CTR_TFSE, 0);
ret = ret ? ret : sh_msiof_modify_ctr_wait(p, CTR_TXE, 0); ret = ret ? ret : sh_msiof_modify_ctr_wait(p, CTR_TXE, 0);
if (rx_buf) if (rx_buf)
@ -504,9 +526,11 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p,
return ret; return ret;
} }
static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t) static int sh_msiof_transfer_one(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *t)
{ {
struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master); struct sh_msiof_spi_priv *p = spi_master_get_devdata(master);
void (*tx_fifo)(struct sh_msiof_spi_priv *, const void *, int, int); void (*tx_fifo)(struct sh_msiof_spi_priv *, const void *, int, int);
void (*rx_fifo)(struct sh_msiof_spi_priv *, void *, int, int); void (*rx_fifo)(struct sh_msiof_spi_priv *, void *, int, int);
int bits; int bits;
@ -516,7 +540,7 @@ static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
int n; int n;
bool swab; bool swab;
bits = sh_msiof_spi_bits(spi, t); bits = t->bits_per_word;
if (bits <= 8 && t->len > 15 && !(t->len & 3)) { if (bits <= 8 && t->len > 15 && !(t->len & 3)) {
bits = 32; bits = 32;
@ -566,8 +590,7 @@ static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
} }
/* setup clocks (clock already enabled in chipselect()) */ /* setup clocks (clock already enabled in chipselect()) */
sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk), sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk), t->speed_hz);
sh_msiof_spi_hz(spi, t));
/* transfer in fifo sized chunks */ /* transfer in fifo sized chunks */
words = t->len / bytes_per_word; words = t->len / bytes_per_word;
@ -587,22 +610,36 @@ static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
words -= n; words -= n;
} }
return bytes_done;
}
static u32 sh_msiof_spi_txrx_word(struct spi_device *spi, unsigned nsecs,
u32 word, u8 bits)
{
BUG(); /* unused but needed by bitbang code */
return 0; return 0;
} }
static const struct sh_msiof_chipdata sh_data = {
.tx_fifo_size = 64,
.rx_fifo_size = 64,
.master_flags = 0,
};
static const struct sh_msiof_chipdata r8a779x_data = {
.tx_fifo_size = 64,
.rx_fifo_size = 256,
.master_flags = SPI_MASTER_MUST_TX,
};
static const struct of_device_id sh_msiof_match[] = {
{ .compatible = "renesas,sh-msiof", .data = &sh_data },
{ .compatible = "renesas,sh-mobile-msiof", .data = &sh_data },
{ .compatible = "renesas,msiof-r8a7790", .data = &r8a779x_data },
{ .compatible = "renesas,msiof-r8a7791", .data = &r8a779x_data },
{},
};
MODULE_DEVICE_TABLE(of, sh_msiof_match);
#ifdef CONFIG_OF #ifdef CONFIG_OF
static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev) static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev)
{ {
struct sh_msiof_spi_info *info; struct sh_msiof_spi_info *info;
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
u32 num_cs = 0; u32 num_cs = 1;
info = devm_kzalloc(dev, sizeof(struct sh_msiof_spi_info), GFP_KERNEL); info = devm_kzalloc(dev, sizeof(struct sh_msiof_spi_info), GFP_KERNEL);
if (!info) { if (!info) {
@ -632,6 +669,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
{ {
struct resource *r; struct resource *r;
struct spi_master *master; struct spi_master *master;
const struct of_device_id *of_id;
struct sh_msiof_spi_priv *p; struct sh_msiof_spi_priv *p;
int i; int i;
int ret; int ret;
@ -645,10 +683,15 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
p = spi_master_get_devdata(master); p = spi_master_get_devdata(master);
platform_set_drvdata(pdev, p); platform_set_drvdata(pdev, p);
if (pdev->dev.of_node)
of_id = of_match_device(sh_msiof_match, &pdev->dev);
if (of_id) {
p->chipdata = of_id->data;
p->info = sh_msiof_spi_parse_dt(&pdev->dev); p->info = sh_msiof_spi_parse_dt(&pdev->dev);
else } else {
p->chipdata = (const void *)pdev->id_entry->driver_data;
p->info = dev_get_platdata(&pdev->dev); p->info = dev_get_platdata(&pdev->dev);
}
if (!p->info) { if (!p->info) {
dev_err(&pdev->dev, "failed to obtain device info\n"); dev_err(&pdev->dev, "failed to obtain device info\n");
@ -686,49 +729,40 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
goto err1; goto err1;
} }
ret = clk_prepare(p->clk);
if (ret < 0) {
dev_err(&pdev->dev, "unable to prepare clock\n");
goto err1;
}
p->pdev = pdev; p->pdev = pdev;
pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev);
/* The standard version of MSIOF use 64 word FIFOs */
p->tx_fifo_size = 64;
p->rx_fifo_size = 64;
/* Platform data may override FIFO sizes */ /* Platform data may override FIFO sizes */
p->tx_fifo_size = p->chipdata->tx_fifo_size;
p->rx_fifo_size = p->chipdata->rx_fifo_size;
if (p->info->tx_fifo_override) if (p->info->tx_fifo_override)
p->tx_fifo_size = p->info->tx_fifo_override; p->tx_fifo_size = p->info->tx_fifo_override;
if (p->info->rx_fifo_override) if (p->info->rx_fifo_override)
p->rx_fifo_size = p->info->rx_fifo_override; p->rx_fifo_size = p->info->rx_fifo_override;
/* init master and bitbang code */ /* init master code */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->mode_bits |= SPI_LSB_FIRST | SPI_3WIRE; master->mode_bits |= SPI_LSB_FIRST | SPI_3WIRE;
master->flags = 0; master->flags = p->chipdata->master_flags;
master->bus_num = pdev->id; master->bus_num = pdev->id;
master->dev.of_node = pdev->dev.of_node;
master->num_chipselect = p->info->num_chipselect; master->num_chipselect = p->info->num_chipselect;
master->setup = spi_bitbang_setup; master->setup = sh_msiof_spi_setup;
master->cleanup = spi_bitbang_cleanup; master->prepare_message = sh_msiof_prepare_message;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32);
master->auto_runtime_pm = true;
master->transfer_one = sh_msiof_transfer_one;
p->bitbang.master = master; ret = devm_spi_register_master(&pdev->dev, master);
p->bitbang.chipselect = sh_msiof_spi_chipselect; if (ret < 0) {
p->bitbang.setup_transfer = sh_msiof_spi_setup_transfer; dev_err(&pdev->dev, "spi_register_master error.\n");
p->bitbang.txrx_bufs = sh_msiof_spi_txrx; goto err2;
p->bitbang.txrx_word[SPI_MODE_0] = sh_msiof_spi_txrx_word; }
p->bitbang.txrx_word[SPI_MODE_1] = sh_msiof_spi_txrx_word;
p->bitbang.txrx_word[SPI_MODE_2] = sh_msiof_spi_txrx_word;
p->bitbang.txrx_word[SPI_MODE_3] = sh_msiof_spi_txrx_word;
ret = spi_bitbang_start(&p->bitbang); return 0;
if (ret == 0)
return 0;
err2:
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
clk_unprepare(p->clk);
err1: err1:
spi_master_put(master); spi_master_put(master);
return ret; return ret;
@ -736,30 +770,22 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
static int sh_msiof_spi_remove(struct platform_device *pdev) static int sh_msiof_spi_remove(struct platform_device *pdev)
{ {
struct sh_msiof_spi_priv *p = platform_get_drvdata(pdev); pm_runtime_disable(&pdev->dev);
int ret; return 0;
ret = spi_bitbang_stop(&p->bitbang);
if (!ret) {
pm_runtime_disable(&pdev->dev);
clk_unprepare(p->clk);
spi_master_put(p->bitbang.master);
}
return ret;
} }
#ifdef CONFIG_OF static struct platform_device_id spi_driver_ids[] = {
static const struct of_device_id sh_msiof_match[] = { { "spi_sh_msiof", (kernel_ulong_t)&sh_data },
{ .compatible = "renesas,sh-msiof", }, { "spi_r8a7790_msiof", (kernel_ulong_t)&r8a779x_data },
{ .compatible = "renesas,sh-mobile-msiof", }, { "spi_r8a7791_msiof", (kernel_ulong_t)&r8a779x_data },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, sh_msiof_match); MODULE_DEVICE_TABLE(platform, spi_driver_ids);
#endif
static struct platform_driver sh_msiof_spi_drv = { static struct platform_driver sh_msiof_spi_drv = {
.probe = sh_msiof_spi_probe, .probe = sh_msiof_spi_probe,
.remove = sh_msiof_spi_remove, .remove = sh_msiof_spi_remove,
.id_table = spi_driver_ids,
.driver = { .driver = {
.name = "spi_sh_msiof", .name = "spi_sh_msiof",
.owner = THIS_MODULE, .owner = THIS_MODULE,

View File

@ -108,7 +108,7 @@ static void sh_sci_spi_chipselect(struct spi_device *dev, int value)
{ {
struct sh_sci_spi *sp = spi_master_get_devdata(dev->master); struct sh_sci_spi *sp = spi_master_get_devdata(dev->master);
if (sp->info && sp->info->chip_select) if (sp->info->chip_select)
(sp->info->chip_select)(sp->info, dev->chip_select, value); (sp->info->chip_select)(sp->info, dev->chip_select, value);
} }
@ -130,6 +130,11 @@ static int sh_sci_spi_probe(struct platform_device *dev)
platform_set_drvdata(dev, sp); platform_set_drvdata(dev, sp);
sp->info = dev_get_platdata(&dev->dev); sp->info = dev_get_platdata(&dev->dev);
if (!sp->info) {
dev_err(&dev->dev, "platform data is missing\n");
ret = -ENOENT;
goto err1;
}
/* setup spi bitbang adaptor */ /* setup spi bitbang adaptor */
sp->bitbang.master = master; sp->bitbang.master = master;

View File

@ -22,7 +22,6 @@
#include <linux/dmaengine.h> #include <linux/dmaengine.h>
#include <linux/dma-direction.h> #include <linux/dma-direction.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/sirfsoc_dma.h>
#define DRIVER_NAME "sirfsoc_spi" #define DRIVER_NAME "sirfsoc_spi"
@ -132,6 +131,8 @@
#define IS_DMA_VALID(x) (x && ALIGNED(x->tx_buf) && ALIGNED(x->rx_buf) && \ #define IS_DMA_VALID(x) (x && ALIGNED(x->tx_buf) && ALIGNED(x->rx_buf) && \
ALIGNED(x->len) && (x->len < 2 * PAGE_SIZE)) ALIGNED(x->len) && (x->len < 2 * PAGE_SIZE))
#define SIRFSOC_MAX_CMD_BYTES 4
struct sirfsoc_spi { struct sirfsoc_spi {
struct spi_bitbang bitbang; struct spi_bitbang bitbang;
struct completion rx_done; struct completion rx_done;
@ -162,6 +163,12 @@ struct sirfsoc_spi {
void *dummypage; void *dummypage;
int word_width; /* in bytes */ int word_width; /* in bytes */
/*
* if tx size is not more than 4 and rx size is NULL, use
* command model
*/
bool tx_by_cmd;
int chipselect[0]; int chipselect[0];
}; };
@ -260,6 +267,12 @@ static irqreturn_t spi_sirfsoc_irq(int irq, void *dev_id)
writel(spi_stat, sspi->base + SIRFSOC_SPI_INT_STATUS); writel(spi_stat, sspi->base + SIRFSOC_SPI_INT_STATUS);
if (sspi->tx_by_cmd && (spi_stat & SIRFSOC_SPI_FRM_END)) {
complete(&sspi->tx_done);
writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN);
return IRQ_HANDLED;
}
/* Error Conditions */ /* Error Conditions */
if (spi_stat & SIRFSOC_SPI_RX_OFLOW || if (spi_stat & SIRFSOC_SPI_RX_OFLOW ||
spi_stat & SIRFSOC_SPI_TX_UFLOW) { spi_stat & SIRFSOC_SPI_TX_UFLOW) {
@ -310,6 +323,34 @@ static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t)
writel(SIRFSOC_SPI_INT_MASK_ALL, sspi->base + SIRFSOC_SPI_INT_STATUS); writel(SIRFSOC_SPI_INT_MASK_ALL, sspi->base + SIRFSOC_SPI_INT_STATUS);
/*
* fill tx_buf into command register and wait for its completion
*/
if (sspi->tx_by_cmd) {
u32 cmd;
memcpy(&cmd, sspi->tx, t->len);
if (sspi->word_width == 1 && !(spi->mode & SPI_LSB_FIRST))
cmd = cpu_to_be32(cmd) >>
((SIRFSOC_MAX_CMD_BYTES - t->len) * 8);
if (sspi->word_width == 2 && t->len == 4 &&
(!(spi->mode & SPI_LSB_FIRST)))
cmd = ((cmd & 0xffff) << 16) | (cmd >> 16);
writel(cmd, sspi->base + SIRFSOC_SPI_CMD);
writel(SIRFSOC_SPI_FRM_END_INT_EN,
sspi->base + SIRFSOC_SPI_INT_EN);
writel(SIRFSOC_SPI_CMD_TX_EN,
sspi->base + SIRFSOC_SPI_TX_RX_EN);
if (wait_for_completion_timeout(&sspi->tx_done, timeout) == 0) {
dev_err(&spi->dev, "transfer timeout\n");
return 0;
}
return t->len;
}
if (sspi->left_tx_word == 1) { if (sspi->left_tx_word == 1) {
writel(readl(sspi->base + SIRFSOC_SPI_CTRL) | writel(readl(sspi->base + SIRFSOC_SPI_CTRL) |
SIRFSOC_SPI_ENA_AUTO_CLR, SIRFSOC_SPI_ENA_AUTO_CLR,
@ -459,11 +500,6 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
regval |= SIRFSOC_SPI_TRAN_DAT_FORMAT_8; regval |= SIRFSOC_SPI_TRAN_DAT_FORMAT_8;
sspi->rx_word = spi_sirfsoc_rx_word_u8; sspi->rx_word = spi_sirfsoc_rx_word_u8;
sspi->tx_word = spi_sirfsoc_tx_word_u8; sspi->tx_word = spi_sirfsoc_tx_word_u8;
txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
SIRFSOC_SPI_FIFO_WIDTH_BYTE;
rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
SIRFSOC_SPI_FIFO_WIDTH_BYTE;
sspi->word_width = 1;
break; break;
case 12: case 12:
case 16: case 16:
@ -471,26 +507,22 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
SIRFSOC_SPI_TRAN_DAT_FORMAT_16; SIRFSOC_SPI_TRAN_DAT_FORMAT_16;
sspi->rx_word = spi_sirfsoc_rx_word_u16; sspi->rx_word = spi_sirfsoc_rx_word_u16;
sspi->tx_word = spi_sirfsoc_tx_word_u16; sspi->tx_word = spi_sirfsoc_tx_word_u16;
txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
SIRFSOC_SPI_FIFO_WIDTH_WORD;
rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
SIRFSOC_SPI_FIFO_WIDTH_WORD;
sspi->word_width = 2;
break; break;
case 32: case 32:
regval |= SIRFSOC_SPI_TRAN_DAT_FORMAT_32; regval |= SIRFSOC_SPI_TRAN_DAT_FORMAT_32;
sspi->rx_word = spi_sirfsoc_rx_word_u32; sspi->rx_word = spi_sirfsoc_rx_word_u32;
sspi->tx_word = spi_sirfsoc_tx_word_u32; sspi->tx_word = spi_sirfsoc_tx_word_u32;
txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
SIRFSOC_SPI_FIFO_WIDTH_DWORD;
rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
SIRFSOC_SPI_FIFO_WIDTH_DWORD;
sspi->word_width = 4;
break; break;
default: default:
BUG(); BUG();
} }
sspi->word_width = DIV_ROUND_UP(bits_per_word, 8);
txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
sspi->word_width;
rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) |
sspi->word_width;
if (!(spi->mode & SPI_CS_HIGH)) if (!(spi->mode & SPI_CS_HIGH))
regval |= SIRFSOC_SPI_CS_IDLE_STAT; regval |= SIRFSOC_SPI_CS_IDLE_STAT;
if (!(spi->mode & SPI_LSB_FIRST)) if (!(spi->mode & SPI_LSB_FIRST))
@ -519,6 +551,14 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
writel(txfifo_ctrl, sspi->base + SIRFSOC_SPI_TXFIFO_CTRL); writel(txfifo_ctrl, sspi->base + SIRFSOC_SPI_TXFIFO_CTRL);
writel(rxfifo_ctrl, sspi->base + SIRFSOC_SPI_RXFIFO_CTRL); writel(rxfifo_ctrl, sspi->base + SIRFSOC_SPI_RXFIFO_CTRL);
if (t && t->tx_buf && !t->rx_buf && (t->len <= SIRFSOC_MAX_CMD_BYTES)) {
regval |= (SIRFSOC_SPI_CMD_BYTE_NUM((t->len - 1)) |
SIRFSOC_SPI_CMD_MODE);
sspi->tx_by_cmd = true;
} else {
regval &= ~SIRFSOC_SPI_CMD_MODE;
sspi->tx_by_cmd = false;
}
writel(regval, sspi->base + SIRFSOC_SPI_CTRL); writel(regval, sspi->base + SIRFSOC_SPI_CTRL);
if (IS_DMA_VALID(t)) { if (IS_DMA_VALID(t)) {
@ -548,8 +588,6 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
struct spi_master *master; struct spi_master *master;
struct resource *mem_res; struct resource *mem_res;
int num_cs, cs_gpio, irq; int num_cs, cs_gpio, irq;
u32 rx_dma_ch, tx_dma_ch;
dma_cap_mask_t dma_cap_mask;
int i; int i;
int ret; int ret;
@ -560,20 +598,6 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
goto err_cs; goto err_cs;
} }
ret = of_property_read_u32(pdev->dev.of_node,
"sirf,spi-dma-rx-channel", &rx_dma_ch);
if (ret < 0) {
dev_err(&pdev->dev, "Unable to get rx dma channel\n");
goto err_cs;
}
ret = of_property_read_u32(pdev->dev.of_node,
"sirf,spi-dma-tx-channel", &tx_dma_ch);
if (ret < 0) {
dev_err(&pdev->dev, "Unable to get tx dma channel\n");
goto err_cs;
}
master = spi_alloc_master(&pdev->dev, sizeof(*sspi) + sizeof(int) * num_cs); master = spi_alloc_master(&pdev->dev, sizeof(*sspi) + sizeof(int) * num_cs);
if (!master) { if (!master) {
dev_err(&pdev->dev, "Unable to allocate SPI master\n"); dev_err(&pdev->dev, "Unable to allocate SPI master\n");
@ -637,18 +661,13 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
sspi->bitbang.master->dev.of_node = pdev->dev.of_node; sspi->bitbang.master->dev.of_node = pdev->dev.of_node;
/* request DMA channels */ /* request DMA channels */
dma_cap_zero(dma_cap_mask); sspi->rx_chan = dma_request_slave_channel(&pdev->dev, "rx");
dma_cap_set(DMA_INTERLEAVE, dma_cap_mask);
sspi->rx_chan = dma_request_channel(dma_cap_mask, (dma_filter_fn)sirfsoc_dma_filter_id,
(void *)rx_dma_ch);
if (!sspi->rx_chan) { if (!sspi->rx_chan) {
dev_err(&pdev->dev, "can not allocate rx dma channel\n"); dev_err(&pdev->dev, "can not allocate rx dma channel\n");
ret = -ENODEV; ret = -ENODEV;
goto free_master; goto free_master;
} }
sspi->tx_chan = dma_request_channel(dma_cap_mask, (dma_filter_fn)sirfsoc_dma_filter_id, sspi->tx_chan = dma_request_slave_channel(&pdev->dev, "tx");
(void *)tx_dma_ch);
if (!sspi->tx_chan) { if (!sspi->tx_chan) {
dev_err(&pdev->dev, "can not allocate tx dma channel\n"); dev_err(&pdev->dev, "can not allocate tx dma channel\n");
ret = -ENODEV; ret = -ENODEV;
@ -724,11 +743,16 @@ static int spi_sirfsoc_remove(struct platform_device *pdev)
return 0; return 0;
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP
static int spi_sirfsoc_suspend(struct device *dev) static int spi_sirfsoc_suspend(struct device *dev)
{ {
struct spi_master *master = dev_get_drvdata(dev); struct spi_master *master = dev_get_drvdata(dev);
struct sirfsoc_spi *sspi = spi_master_get_devdata(master); struct sirfsoc_spi *sspi = spi_master_get_devdata(master);
int ret;
ret = spi_master_suspend(master);
if (ret)
return ret;
clk_disable(sspi->clk); clk_disable(sspi->clk);
return 0; return 0;
@ -745,15 +769,13 @@ static int spi_sirfsoc_resume(struct device *dev)
writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_RXFIFO_OP); writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_RXFIFO_OP);
writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_TXFIFO_OP); writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_TXFIFO_OP);
return 0; return spi_master_resume(master);
} }
static const struct dev_pm_ops spi_sirfsoc_pm_ops = {
.suspend = spi_sirfsoc_suspend,
.resume = spi_sirfsoc_resume,
};
#endif #endif
static SIMPLE_DEV_PM_OPS(spi_sirfsoc_pm_ops, spi_sirfsoc_suspend,
spi_sirfsoc_resume);
static const struct of_device_id spi_sirfsoc_of_match[] = { static const struct of_device_id spi_sirfsoc_of_match[] = {
{ .compatible = "sirf,prima2-spi", }, { .compatible = "sirf,prima2-spi", },
{ .compatible = "sirf,marco-spi", }, { .compatible = "sirf,marco-spi", },
@ -765,9 +787,7 @@ static struct platform_driver spi_sirfsoc_driver = {
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.owner = THIS_MODULE, .owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &spi_sirfsoc_pm_ops, .pm = &spi_sirfsoc_pm_ops,
#endif
.of_match_table = spi_sirfsoc_of_match, .of_match_table = spi_sirfsoc_of_match,
}, },
.probe = spi_sirfsoc_probe, .probe = spi_sirfsoc_probe,

View File

@ -73,7 +73,8 @@ static DECLARE_BITMAP(minors, N_SPI_MINORS);
*/ */
#define SPI_MODE_MASK (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH \ #define SPI_MODE_MASK (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH \
| SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP \ | SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP \
| SPI_NO_CS | SPI_READY) | SPI_NO_CS | SPI_READY | SPI_TX_DUAL \
| SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD)
struct spidev_data { struct spidev_data {
dev_t devt; dev_t devt;
@ -265,6 +266,8 @@ static int spidev_message(struct spidev_data *spidev,
buf += k_tmp->len; buf += k_tmp->len;
k_tmp->cs_change = !!u_tmp->cs_change; k_tmp->cs_change = !!u_tmp->cs_change;
k_tmp->tx_nbits = u_tmp->tx_nbits;
k_tmp->rx_nbits = u_tmp->rx_nbits;
k_tmp->bits_per_word = u_tmp->bits_per_word; k_tmp->bits_per_word = u_tmp->bits_per_word;
k_tmp->delay_usecs = u_tmp->delay_usecs; k_tmp->delay_usecs = u_tmp->delay_usecs;
k_tmp->speed_hz = u_tmp->speed_hz; k_tmp->speed_hz = u_tmp->speed_hz;
@ -359,6 +362,10 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = __put_user(spi->mode & SPI_MODE_MASK, retval = __put_user(spi->mode & SPI_MODE_MASK,
(__u8 __user *)arg); (__u8 __user *)arg);
break; break;
case SPI_IOC_RD_MODE32:
retval = __put_user(spi->mode & SPI_MODE_MASK,
(__u32 __user *)arg);
break;
case SPI_IOC_RD_LSB_FIRST: case SPI_IOC_RD_LSB_FIRST:
retval = __put_user((spi->mode & SPI_LSB_FIRST) ? 1 : 0, retval = __put_user((spi->mode & SPI_LSB_FIRST) ? 1 : 0,
(__u8 __user *)arg); (__u8 __user *)arg);
@ -372,9 +379,13 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
/* write requests */ /* write requests */
case SPI_IOC_WR_MODE: case SPI_IOC_WR_MODE:
retval = __get_user(tmp, (u8 __user *)arg); case SPI_IOC_WR_MODE32:
if (cmd == SPI_IOC_WR_MODE)
retval = __get_user(tmp, (u8 __user *)arg);
else
retval = __get_user(tmp, (u32 __user *)arg);
if (retval == 0) { if (retval == 0) {
u8 save = spi->mode; u32 save = spi->mode;
if (tmp & ~SPI_MODE_MASK) { if (tmp & ~SPI_MODE_MASK) {
retval = -EINVAL; retval = -EINVAL;
@ -382,18 +393,18 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
} }
tmp |= spi->mode & ~SPI_MODE_MASK; tmp |= spi->mode & ~SPI_MODE_MASK;
spi->mode = (u8)tmp; spi->mode = (u16)tmp;
retval = spi_setup(spi); retval = spi_setup(spi);
if (retval < 0) if (retval < 0)
spi->mode = save; spi->mode = save;
else else
dev_dbg(&spi->dev, "spi mode %02x\n", tmp); dev_dbg(&spi->dev, "spi mode %x\n", tmp);
} }
break; break;
case SPI_IOC_WR_LSB_FIRST: case SPI_IOC_WR_LSB_FIRST:
retval = __get_user(tmp, (__u8 __user *)arg); retval = __get_user(tmp, (__u8 __user *)arg);
if (retval == 0) { if (retval == 0) {
u8 save = spi->mode; u32 save = spi->mode;
if (tmp) if (tmp)
spi->mode |= SPI_LSB_FIRST; spi->mode |= SPI_LSB_FIRST;

View File

@ -1,5 +1,4 @@
/* linux/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h /*
*
* Copyright (C) 2009 Samsung Electronics Ltd. * Copyright (C) 2009 Samsung Electronics Ltd.
* Jaswinder Singh <jassi.brar@samsung.com> * Jaswinder Singh <jassi.brar@samsung.com>
* *
@ -8,8 +7,8 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#ifndef __S3C64XX_PLAT_SPI_H #ifndef __SPI_S3C64XX_H
#define __S3C64XX_PLAT_SPI_H #define __SPI_S3C64XX_H
#include <linux/dmaengine.h> #include <linux/dmaengine.h>
@ -68,4 +67,4 @@ extern int s3c64xx_spi2_cfg_gpio(void);
extern struct s3c64xx_spi_info s3c64xx_spi0_pdata; extern struct s3c64xx_spi_info s3c64xx_spi0_pdata;
extern struct s3c64xx_spi_info s3c64xx_spi1_pdata; extern struct s3c64xx_spi_info s3c64xx_spi1_pdata;
extern struct s3c64xx_spi_info s3c64xx_spi2_pdata; extern struct s3c64xx_spi_info s3c64xx_spi2_pdata;
#endif /* __S3C64XX_PLAT_SPI_H */ #endif /*__SPI_S3C64XX_H */

View File

@ -42,6 +42,10 @@
#define SPI_LOOP 0x20 #define SPI_LOOP 0x20
#define SPI_NO_CS 0x40 #define SPI_NO_CS 0x40
#define SPI_READY 0x80 #define SPI_READY 0x80
#define SPI_TX_DUAL 0x100
#define SPI_TX_QUAD 0x200
#define SPI_RX_DUAL 0x400
#define SPI_RX_QUAD 0x800
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
@ -92,7 +96,9 @@ struct spi_ioc_transfer {
__u16 delay_usecs; __u16 delay_usecs;
__u8 bits_per_word; __u8 bits_per_word;
__u8 cs_change; __u8 cs_change;
__u32 pad; __u8 tx_nbits;
__u8 rx_nbits;
__u16 pad;
/* If the contents of 'struct spi_ioc_transfer' ever change /* If the contents of 'struct spi_ioc_transfer' ever change
* incompatibly, then the ioctl number (currently 0) must change; * incompatibly, then the ioctl number (currently 0) must change;
@ -110,7 +116,7 @@ struct spi_ioc_transfer {
#define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)]) #define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)])
/* Read / Write of SPI mode (SPI_MODE_0..SPI_MODE_3) */ /* Read / Write of SPI mode (SPI_MODE_0..SPI_MODE_3) (limited to 8 bits) */
#define SPI_IOC_RD_MODE _IOR(SPI_IOC_MAGIC, 1, __u8) #define SPI_IOC_RD_MODE _IOR(SPI_IOC_MAGIC, 1, __u8)
#define SPI_IOC_WR_MODE _IOW(SPI_IOC_MAGIC, 1, __u8) #define SPI_IOC_WR_MODE _IOW(SPI_IOC_MAGIC, 1, __u8)
@ -126,6 +132,10 @@ struct spi_ioc_transfer {
#define SPI_IOC_RD_MAX_SPEED_HZ _IOR(SPI_IOC_MAGIC, 4, __u32) #define SPI_IOC_RD_MAX_SPEED_HZ _IOR(SPI_IOC_MAGIC, 4, __u32)
#define SPI_IOC_WR_MAX_SPEED_HZ _IOW(SPI_IOC_MAGIC, 4, __u32) #define SPI_IOC_WR_MAX_SPEED_HZ _IOW(SPI_IOC_MAGIC, 4, __u32)
/* Read / Write of the SPI mode field */
#define SPI_IOC_RD_MODE32 _IOR(SPI_IOC_MAGIC, 5, __u32)
#define SPI_IOC_WR_MODE32 _IOW(SPI_IOC_MAGIC, 5, __u32)
#endif /* SPIDEV_H */ #endif /* SPIDEV_H */