Commit 0055dc5b authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'spi-v4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi

Pull spi updates from Mark Brown:
 "Only one framework update this time around, a change from Lars-Peter
  to move full to pm_ops and remove the legacy bus PM ops.  Otherwise
  it's all driver updates:

   - make the spidev driver complain loudly if registered as spidev with
     DT rather than with a compatible string, hopefully helping people
     avoid making that mistake.

   - error handling and robustness fixes for the Designware and Intel
     MID drivers from Andy Shevchenko.

   - substantial performance improvements for the Raspberry Pi driver
     from Martin Sperl.

   - several new features for spidev_test from Adrian Remonda and Ian
     Abbott"

* tag 'spi-v4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (75 commits)
  spi: bcm2835: enabling polling mode for transfers shorter than 30us
  spi: bcm2835: transform native-cs to gpio-cs on first spi_setup
  spi: img-spfi: Control CS lines with GPIO
  spi: img-spfi: Reset controller after each message
  spi: img-spfi: Implement a handle_err() callback
  spi: img-spfi: Setup TRANSACTION register before CONTROL register
  spi: Make master->handle_err() callback optional to avoid crashes
  spi: img-spfi: Limit bit clock to 1/4th of input clock
  spi: img-spfi: Implement a prepare_message() callback
  spi: fsl-dspi: Add ~50ns delay between cs and sck
  spi: fsl-dspi: Add cs-sck delays
  spi: fsl-dspi: Fix clock rate scale values
  spi: signedness bug in qspi_trigger_transfer_out_int()
  spi: imx: read back the RX/TX watermark levels earlier
  spi: spi-bfin5xx: Initialize cr_width in bfin_spi_pump_transfers()
  spi: bitbang: only toggle bitchanges
  spi: pxa2xx: missing break in pxa2xx_ssp_get_clk_div()
  spi: fsl-dspi: Fix clock rate scale values
  spi: Using Trigger number to transmit/receive data
  spi: bcm2835: fill FIFO before enabling interrupts to reduce interrupts/message
  ...
parents 1b57c7c2 56afdb70
...@@ -2,11 +2,21 @@ ...@@ -2,11 +2,21 @@
(CSPI/eCSPI) for i.MX (CSPI/eCSPI) for i.MX
Required properties: Required properties:
- compatible : Should be "fsl,<soc>-cspi" or "fsl,<soc>-ecspi" - compatible :
- "fsl,imx1-cspi" for SPI compatible with the one integrated on i.MX1
- "fsl,imx21-cspi" for SPI compatible with the one integrated on i.MX21
- "fsl,imx27-cspi" for SPI compatible with the one integrated on i.MX27
- "fsl,imx31-cspi" for SPI compatible with the one integrated on i.MX31
- "fsl,imx35-cspi" for SPI compatible with the one integrated on i.MX35
- "fsl,imx51-ecspi" for SPI compatible with the one integrated on i.MX51
- reg : Offset and length of the register set for the device - reg : Offset and length of the register set for the device
- interrupts : Should contain CSPI/eCSPI interrupt - interrupts : Should contain CSPI/eCSPI interrupt
- fsl,spi-num-chipselects : Contains the number of the chipselect - fsl,spi-num-chipselects : Contains the number of the chipselect
- cs-gpios : Specifies the gpio pins to be used for chipselects. - cs-gpios : Specifies the gpio pins to be used for chipselects.
- clocks : Clock specifiers for both ipg and per clocks.
- clock-names : Clock names should include both "ipg" and "per"
See the clock consumer binding,
Documentation/devicetree/bindings/clock/clock-bindings.txt
- dmas: DMA specifiers for tx and rx dma. See the DMA client binding, - dmas: DMA specifiers for tx and rx dma. See the DMA client binding,
Documentation/devicetree/bindings/dma/dma.txt Documentation/devicetree/bindings/dma/dma.txt
- dma-names: DMA request names should include "tx" and "rx" if present. - dma-names: DMA request names should include "tx" and "rx" if present.
......
...@@ -33,6 +33,11 @@ Optional properties: ...@@ -33,6 +33,11 @@ Optional properties:
nodes. If unspecified, a single SPI device without a chip nodes. If unspecified, a single SPI device without a chip
select can be used. select can be used.
- dmas: Two DMA channel specifiers following the convention outlined
in bindings/dma/dma.txt
- dma-names: Names for the dma channels, if present. There must be at
least one channel named "tx" for transmit and named "rx" for
receive.
SPI slave nodes must be children of the SPI master node and can contain SPI slave nodes must be children of the SPI master node and can contain
properties described in Documentation/devicetree/bindings/spi/spi-bus.txt properties described in Documentation/devicetree/bindings/spi/spi-bus.txt
...@@ -51,6 +56,9 @@ Example: ...@@ -51,6 +56,9 @@ Example:
clocks = <&gcc GCC_BLSP2_QUP2_SPI_APPS_CLK>, <&gcc GCC_BLSP2_AHB_CLK>; clocks = <&gcc GCC_BLSP2_QUP2_SPI_APPS_CLK>, <&gcc GCC_BLSP2_AHB_CLK>;
clock-names = "core", "iface"; clock-names = "core", "iface";
dmas = <&blsp1_bam 13>, <&blsp1_bam 12>;
dma-names = "rx", "tx";
pinctrl-names = "default"; pinctrl-names = "default";
pinctrl-0 = <&spi8_default>; pinctrl-0 = <&spi8_default>;
......
...@@ -16,6 +16,12 @@ Optional property: ...@@ -16,6 +16,12 @@ Optional property:
in big endian mode, otherwise in native mode(same with CPU), for more in big endian mode, otherwise in native mode(same with CPU), for more
detail please see: Documentation/devicetree/bindings/regmap/regmap.txt. detail please see: Documentation/devicetree/bindings/regmap/regmap.txt.
Optional SPI slave node properties:
- fsl,spi-cs-sck-delay: a delay in nanoseconds between activating chip
select and the start of clock signal, at the start of a transfer.
- fsl,spi-sck-cs-delay: a delay in nanoseconds between stopping the clock
signal and deactivating chip select, at the end of a transfer.
Example: Example:
dspi0@4002c000 { dspi0@4002c000 {
...@@ -43,6 +49,8 @@ dspi0@4002c000 { ...@@ -43,6 +49,8 @@ dspi0@4002c000 {
reg = <0>; reg = <0>;
linux,modalias = "m25p80"; linux,modalias = "m25p80";
modal = "at26df081a"; modal = "at26df081a";
fsl,spi-cs-sck-delay = <100>;
fsl,spi-sck-cs-delay = <50>;
}; };
}; };
......
...@@ -14,6 +14,7 @@ Required properties: ...@@ -14,6 +14,7 @@ Required properties:
- dma-names: Must include the following entries: - dma-names: Must include the following entries:
- rx - rx
- tx - tx
- cs-gpios: Must specify the GPIOs used for chipselect lines.
- #address-cells: Must be 1. - #address-cells: Must be 1.
- #size-cells: Must be 0. - #size-cells: Must be 0.
......
...@@ -24,6 +24,9 @@ Optional Properties: ...@@ -24,6 +24,9 @@ Optional Properties:
- dmas: DMA specifiers for tx and rx dma. See the DMA client binding, - dmas: DMA specifiers for tx and rx dma. See the DMA client binding,
Documentation/devicetree/bindings/dma/dma.txt Documentation/devicetree/bindings/dma/dma.txt
- dma-names: DMA request names should include "tx" and "rx" if present. - dma-names: DMA request names should include "tx" and "rx" if present.
- rx-sample-delay-ns: nanoseconds to delay after the SCLK edge before sampling
Rx data (may need to be fine tuned for high capacitance lines).
No delay (0) by default.
Example: Example:
...@@ -33,6 +36,7 @@ Example: ...@@ -33,6 +36,7 @@ Example:
reg = <0xff110000 0x1000>; reg = <0xff110000 0x1000>;
dmas = <&pdma1 11>, <&pdma1 12>; dmas = <&pdma1 11>, <&pdma1 12>;
dma-names = "tx", "rx"; dma-names = "tx", "rx";
rx-sample-delay-ns = <10>;
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
......
...@@ -342,12 +342,11 @@ SPI protocol drivers somewhat resemble platform device drivers: ...@@ -342,12 +342,11 @@ SPI protocol drivers somewhat resemble platform device drivers:
.driver = { .driver = {
.name = "CHIP", .name = "CHIP",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.pm = &CHIP_pm_ops,
}, },
.probe = CHIP_probe, .probe = CHIP_probe,
.remove = CHIP_remove, .remove = CHIP_remove,
.suspend = CHIP_suspend,
.resume = CHIP_resume,
}; };
The driver core will automatically attempt to bind this driver to any SPI The driver core will automatically attempt to bind this driver to any SPI
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <unistd.h> #include <unistd.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <getopt.h> #include <getopt.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
...@@ -34,24 +35,79 @@ static uint32_t mode; ...@@ -34,24 +35,79 @@ 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;
static int verbose;
static void transfer(int fd) uint8_t default_tx[] = {
{
int ret;
uint8_t tx[] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x40, 0x00, 0x00, 0x00, 0x00, 0x95, 0x40, 0x00, 0x00, 0x00, 0x00, 0x95,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xAD,
0xF0, 0x0D, 0xF0, 0x0D,
}; };
uint8_t rx[ARRAY_SIZE(tx)] = {0, };
uint8_t default_rx[ARRAY_SIZE(default_tx)] = {0, };
char *input_tx;
static void hex_dump(const void *src, size_t length, size_t line_size, char *prefix)
{
int i = 0;
const unsigned char *address = src;
const unsigned char *line = address;
unsigned char c;
printf("%s | ", prefix);
while (length-- > 0) {
printf("%02X ", *address++);
if (!(++i % line_size) || (length == 0 && i % line_size)) {
if (length == 0) {
while (i++ % line_size)
printf("__ ");
}
printf(" | "); /* right close */
while (line < address) {
c = *line++;
printf("%c", (c < 33 || c == 255) ? 0x2E : c);
}
printf("\n");
if (length > 0)
printf("%s | ", prefix);
}
}
}
/*
* Unescape - process hexadecimal escape character
* converts shell input "\x23" -> 0x23
*/
int unespcape(char *_dst, char *_src, size_t len)
{
int ret = 0;
char *src = _src;
char *dst = _dst;
unsigned int ch;
while (*src) {
if (*src == '\\' && *(src+1) == 'x') {
sscanf(src + 2, "%2x", &ch);
src += 4;
*dst++ = (unsigned char)ch;
} else {
*dst++ = *src++;
}
ret++;
}
return ret;
}
static void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len)
{
int ret;
struct spi_ioc_transfer tr = { struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)tx, .tx_buf = (unsigned long)tx,
.rx_buf = (unsigned long)rx, .rx_buf = (unsigned long)rx,
.len = ARRAY_SIZE(tx), .len = len,
.delay_usecs = delay, .delay_usecs = delay,
.speed_hz = speed, .speed_hz = speed,
.bits_per_word = bits, .bits_per_word = bits,
...@@ -76,12 +132,9 @@ static void transfer(int fd) ...@@ -76,12 +132,9 @@ static void transfer(int fd)
if (ret < 1) if (ret < 1)
pabort("can't send spi message"); pabort("can't send spi message");
for (ret = 0; ret < ARRAY_SIZE(tx); ret++) { if (verbose)
if (!(ret % 6)) hex_dump(tx, len, 32, "TX");
puts(""); hex_dump(rx, len, 32, "RX");
printf("%.2X ", rx[ret]);
}
puts("");
} }
static void print_usage(const char *prog) static void print_usage(const char *prog)
...@@ -97,6 +150,8 @@ static void print_usage(const char *prog) ...@@ -97,6 +150,8 @@ static void print_usage(const char *prog)
" -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"
" -v --verbose Verbose (show tx buffer)\n"
" -p Send data (e.g. \"1234\\xde\\xad\")\n"
" -N --no-cs no chip select\n" " -N --no-cs no chip select\n"
" -R --ready slave pulls low to pause\n" " -R --ready slave pulls low to pause\n"
" -2 --dual dual transfer\n" " -2 --dual dual transfer\n"
...@@ -121,12 +176,13 @@ static void parse_opts(int argc, char *argv[]) ...@@ -121,12 +176,13 @@ static void parse_opts(int argc, char *argv[])
{ "no-cs", 0, 0, 'N' }, { "no-cs", 0, 0, 'N' },
{ "ready", 0, 0, 'R' }, { "ready", 0, 0, 'R' },
{ "dual", 0, 0, '2' }, { "dual", 0, 0, '2' },
{ "verbose", 0, 0, 'v' },
{ "quad", 0, 0, '4' }, { "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:lHOLC3NR24", lopts, NULL); c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR24p:v", lopts, NULL);
if (c == -1) if (c == -1)
break; break;
...@@ -165,9 +221,15 @@ static void parse_opts(int argc, char *argv[]) ...@@ -165,9 +221,15 @@ static void parse_opts(int argc, char *argv[])
case 'N': case 'N':
mode |= SPI_NO_CS; mode |= SPI_NO_CS;
break; break;
case 'v':
verbose = 1;
break;
case 'R': case 'R':
mode |= SPI_READY; mode |= SPI_READY;
break; break;
case 'p':
input_tx = optarg;
break;
case '2': case '2':
mode |= SPI_TX_DUAL; mode |= SPI_TX_DUAL;
break; break;
...@@ -191,6 +253,9 @@ int main(int argc, char *argv[]) ...@@ -191,6 +253,9 @@ int main(int argc, char *argv[])
{ {
int ret = 0; int ret = 0;
int fd; int fd;
uint8_t *tx;
uint8_t *rx;
int size;
parse_opts(argc, argv); parse_opts(argc, argv);
...@@ -235,7 +300,17 @@ int main(int argc, char *argv[]) ...@@ -235,7 +300,17 @@ int main(int argc, char *argv[])
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);
transfer(fd); if (input_tx) {
size = strlen(input_tx+1);
tx = malloc(size);
rx = malloc(size);
size = unespcape((char *)tx, input_tx, size);
transfer(fd, tx, rx, size);
free(rx);
free(tx);
} else {
transfer(fd, default_tx, default_rx, sizeof(default_tx));
}
close(fd); close(fd);
......
...@@ -51,19 +51,6 @@ config INTEL_MIC_X100_DMA ...@@ -51,19 +51,6 @@ config INTEL_MIC_X100_DMA
OS and tools for MIC to use with this driver are available from OS and tools for MIC to use with this driver are available from
<http://software.intel.com/en-us/mic-developer>. <http://software.intel.com/en-us/mic-developer>.
config INTEL_MID_DMAC
tristate "Intel MID DMA support for Peripheral DMA controllers"
depends on PCI && X86
select DMA_ENGINE
default n
help
Enable support for the Intel(R) MID DMA engine present
in Intel MID chipsets.
Say Y here if you have such a chipset.
If unsure, say N.
config ASYNC_TX_ENABLE_CHANNEL_SWITCH config ASYNC_TX_ENABLE_CHANNEL_SWITCH
bool bool
......
...@@ -6,7 +6,6 @@ obj-$(CONFIG_DMA_VIRTUAL_CHANNELS) += virt-dma.o ...@@ -6,7 +6,6 @@ obj-$(CONFIG_DMA_VIRTUAL_CHANNELS) += virt-dma.o
obj-$(CONFIG_DMA_ACPI) += acpi-dma.o obj-$(CONFIG_DMA_ACPI) += acpi-dma.o
obj-$(CONFIG_DMA_OF) += of-dma.o obj-$(CONFIG_DMA_OF) += of-dma.o
obj-$(CONFIG_INTEL_MID_DMAC) += intel_mid_dma.o
obj-$(CONFIG_DMATEST) += dmatest.o obj-$(CONFIG_DMATEST) += dmatest.o
obj-$(CONFIG_INTEL_IOATDMA) += ioat/ obj-$(CONFIG_INTEL_IOATDMA) += ioat/
obj-$(CONFIG_INTEL_IOP_ADMA) += iop-adma.o obj-$(CONFIG_INTEL_IOP_ADMA) += iop-adma.o
......
This diff is collapsed.
/*
* intel_mid_dma_regs.h - Intel MID DMA Drivers
*
* Copyright (C) 2008-10 Intel Corp
* Author: Vinod Koul <vinod.koul@intel.com>
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
*
*/
#ifndef __INTEL_MID_DMAC_REGS_H__
#define __INTEL_MID_DMAC_REGS_H__
#include <linux/dmaengine.h>
#include <linux/dmapool.h>
#include <linux/pci_ids.h>
#define INTEL_MID_DMA_DRIVER_VERSION "1.1.0"
#define REG_BIT0 0x00000001
#define REG_BIT8 0x00000100
#define INT_MASK_WE 0x8
#define CLEAR_DONE 0xFFFFEFFF
#define UNMASK_INTR_REG(chan_num) \
((REG_BIT0 << chan_num) | (REG_BIT8 << chan_num))
#define MASK_INTR_REG(chan_num) (REG_BIT8 << chan_num)
#define ENABLE_CHANNEL(chan_num) \
((REG_BIT0 << chan_num) | (REG_BIT8 << chan_num))
#define DISABLE_CHANNEL(chan_num) \
(REG_BIT8 << chan_num)
#define DESCS_PER_CHANNEL 16
/*DMA Registers*/
/*registers associated with channel programming*/
#define DMA_REG_SIZE 0x400
#define DMA_CH_SIZE 0x58
/*CH X REG = (DMA_CH_SIZE)*CH_NO + REG*/
#define SAR 0x00 /* Source Address Register*/
#define DAR 0x08 /* Destination Address Register*/
#define LLP 0x10 /* Linked List Pointer Register*/
#define CTL_LOW 0x18 /* Control Register*/
#define CTL_HIGH 0x1C /* Control Register*/
#define CFG_LOW 0x40 /* Configuration Register Low*/
#define CFG_HIGH 0x44 /* Configuration Register high*/
#define STATUS_TFR 0x2E8
#define STATUS_BLOCK 0x2F0
#define STATUS_ERR 0x308
#define RAW_TFR 0x2C0
#define RAW_BLOCK 0x2C8
#define RAW_ERR 0x2E0
#define MASK_TFR 0x310
#define MASK_BLOCK 0x318
#define MASK_SRC_TRAN 0x320
#define MASK_DST_TRAN 0x328
#define MASK_ERR 0x330
#define CLEAR_TFR 0x338
#define CLEAR_BLOCK 0x340
#define CLEAR_SRC_TRAN 0x348
#define CLEAR_DST_TRAN 0x350
#define CLEAR_ERR 0x358
#define INTR_STATUS 0x360
#define DMA_CFG 0x398
#define DMA_CHAN_EN 0x3A0
/*DMA channel control registers*/
union intel_mid_dma_ctl_lo {
struct {
u32 int_en:1; /*enable or disable interrupts*/
/*should be 0*/
u32 dst_tr_width:3; /*destination transfer width*/
/*usually 32 bits = 010*/
u32 src_tr_width:3; /*source transfer width*/
/*usually 32 bits = 010*/
u32 dinc:2; /*destination address inc/dec*/
/*For mem:INC=00, Periphral NoINC=11*/
u32 sinc:2; /*source address inc or dec, as above*/
u32 dst_msize:3; /*destination burst transaction length*/
/*always = 16 ie 011*/
u32 src_msize:3; /*source burst transaction length*/
/*always = 16 ie 011*/
u32 reser1:3;
u32 tt_fc:3; /*transfer type and flow controller*/
/*M-M = 000
P-M = 010
M-P = 001*/
u32 dms:2; /*destination master select = 0*/
u32 sms:2; /*source master select = 0*/
u32 llp_dst_en:1; /*enable/disable destination LLP = 0*/
u32 llp_src_en:1; /*enable/disable source LLP = 0*/
u32 reser2:3;
} ctlx;
u32 ctl_lo;
};
union intel_mid_dma_ctl_hi {
struct {
u32 block_ts:12; /*block transfer size*/
u32 done:1; /*Done - updated by DMAC*/
u32 reser:19; /*configured by DMAC*/
} ctlx;
u32 ctl_hi;
};
/*DMA channel configuration registers*/
union intel_mid_dma_cfg_lo {
struct {
u32 reser1:5;
u32 ch_prior:3; /*channel priority = 0*/
u32 ch_susp:1; /*channel suspend = 0*/
u32 fifo_empty:1; /*FIFO empty or not R bit = 0*/
u32 hs_sel_dst:1; /*select HW/SW destn handshaking*/
/*HW = 0, SW = 1*/
u32 hs_sel_src:1; /*select HW/SW src handshaking*/
u32 reser2:6;
u32 dst_hs_pol:1; /*dest HS interface polarity*/
u32 src_hs_pol:1; /*src HS interface polarity*/
u32 max_abrst:10; /*max AMBA burst len = 0 (no sw limit*/
u32 reload_src:1; /*auto reload src addr =1 if src is P*/
u32 reload_dst:1; /*AR destn addr =1 if dstn is P*/
} cfgx;
u32 cfg_lo;
};
union intel_mid_dma_cfg_hi {
struct {
u32 fcmode:1; /*flow control mode = 1*/
u32 fifo_mode:1; /*FIFO mode select = 1*/
u32 protctl:3; /*protection control = 0*/
u32 rsvd:2;
u32 src_per:4; /*src hw HS interface*/
u32 dst_per:4; /*dstn hw HS interface*/
u32 reser2:17;
} cfgx;
u32 cfg_hi;
};
/**
* struct intel_mid_dma_chan - internal mid representation of a DMA channel
* @chan: dma_chan strcture represetation for mid chan
* @ch_regs: MMIO register space pointer to channel register
* @dma_base: MMIO register space DMA engine base pointer
* @ch_id: DMA channel id
* @lock: channel spinlock
* @active_list: current active descriptors
* @queue: current queued up descriptors
* @free_list: current free descriptors
* @slave: dma slave structure
* @descs_allocated: total number of descriptors allocated
* @dma: dma device structure pointer
* @busy: bool representing if ch is busy (active txn) or not
* @in_use: bool representing if ch is in use or not
* @raw_tfr: raw trf interrupt received
* @raw_block: raw block interrupt received
*/
struct intel_mid_dma_chan {
struct dma_chan chan;
void __iomem *ch_regs;
void __iomem *dma_base;
int ch_id;
spinlock_t lock;
struct list_head active_list;
struct list_head queue;
struct list_head free_list;
unsigned int descs_allocated;
struct middma_device *dma;
bool busy;
bool in_use;
u32 raw_tfr;
u32 raw_block;
struct intel_mid_dma_slave *mid_slave;
};
static inline struct intel_mid_dma_chan *to_intel_mid_dma_chan(
struct dma_chan *chan)
{
return container_of(chan, struct intel_mid_dma_chan, chan);
}
enum intel_mid_dma_state {
RUNNING = 0,
SUSPENDED,
};
/**
* struct middma_device - internal representation of a DMA device
* @pdev: PCI device
* @dma_base: MMIO register space pointer of DMA
* @dma_pool: for allocating DMA descriptors
* @common: embedded struct dma_device
* @tasklet: dma tasklet for processing interrupts
* @ch: per channel data
* @pci_id: DMA device PCI ID
* @intr_mask: Interrupt mask to be used
* @mask_reg: MMIO register for periphral mask
* @chan_base: Base ch index (read from driver data)
* @max_chan: max number of chs supported (from drv_data)
* @block_size: Block size of DMA transfer supported (from drv_data)
* @pimr_mask: MMIO register addr for periphral interrupt (from drv_data)
* @state: dma PM device state
*/
struct middma_device {
struct pci_dev *pdev;
void __iomem *dma_base;
struct pci_pool *dma_pool;
struct dma_device common;
struct tasklet_struct tasklet;
struct intel_mid_dma_chan ch[MAX_CHAN];
unsigned int pci_id;
unsigned int intr_mask;
void __iomem *mask_reg;
int chan_base;
int max_chan;
int block_size;
unsigned int pimr_mask;
enum intel_mid_dma_state state;
};
static inline struct middma_device *to_middma_device(struct dma_device *common)
{
return container_of(common, struct middma_device, common);
}
struct intel_mid_dma_desc {
void __iomem *block; /*ch ptr*/
struct list_head desc_node;
struct dma_async_tx_descriptor txd;
size_t len;
dma_addr_t sar;
dma_addr_t dar;
u32 cfg_hi;
u32 cfg_lo;
u32 ctl_lo;
u32 ctl_hi;
struct pci_pool *lli_pool;
struct intel_mid_dma_lli *lli;
dma_addr_t lli_phys;
unsigned int lli_length;
unsigned int current_lli;
dma_addr_t next;
enum dma_transfer_direction dirn;
enum dma_status status;
enum dma_slave_buswidth width; /*width of DMA txn*/
enum intel_mid_dma_mode cfg_mode; /*mode configuration*/
};
struct intel_mid_dma_lli {
dma_addr_t sar;
dma_addr_t dar;
dma_addr_t llp;
u32 ctl_lo;
u32 ctl_hi;
} __attribute__ ((packed));
static inline int test_ch_en(void __iomem *dma, u32 ch_no)
{
u32 en_reg = ioread32(dma + DMA_CHAN_EN);
return (en_reg >> ch_no) & 0x1;
}
static inline struct intel_mid_dma_desc *to_intel_mid_dma_desc
(struct dma_async_tx_descriptor *txd)
{
return container_of(txd, struct intel_mid_dma_desc, txd);
}
static inline struct intel_mid_dma_slave *to_intel_mid_dma_slave
(struct dma_slave_config *slave)
{
return container_of(slave, struct intel_mid_dma_slave, dma_slave);
}
int dma_resume(struct device *dev);
#endif /*__INTEL_MID_DMAC_REGS_H__*/
...@@ -159,10 +159,9 @@ config SPI_BUTTERFLY ...@@ -159,10 +159,9 @@ config SPI_BUTTERFLY
config SPI_CADENCE config SPI_CADENCE
tristate "Cadence SPI controller" tristate "Cadence SPI controller"
depends on ARM
help help
This selects the Cadence SPI controller master driver This selects the Cadence SPI controller master driver
used by Xilinx Zynq. used by Xilinx Zynq and ZynqMP.
config SPI_CLPS711X config SPI_CLPS711X
tristate "CLPS711X host SPI controller" tristate "CLPS711X host SPI controller"
...@@ -632,7 +631,7 @@ config SPI_DW_PCI ...@@ -632,7 +631,7 @@ config SPI_DW_PCI
config SPI_DW_MID_DMA config SPI_DW_MID_DMA
bool "DMA support for DW SPI controller on Intel MID platform" bool "DMA support for DW SPI controller on Intel MID platform"
depends on SPI_DW_PCI && INTEL_MID_DMAC depends on SPI_DW_PCI && DW_DMAC_PCI
config SPI_DW_MMIO config SPI_DW_MMIO
tristate "Memory-mapped io interface driver for DW SPI core" tristate "Memory-mapped io interface driver for DW SPI core"
......
...@@ -180,11 +180,17 @@ ...@@ -180,11 +180,17 @@
| SPI_BF(name, value)) | SPI_BF(name, value))
/* Register access macros */ /* Register access macros */
#ifdef CONFIG_AVR32
#define spi_readl(port, reg) \ #define spi_readl(port, reg) \
__raw_readl((port)->regs + SPI_##reg) __raw_readl((port)->regs + SPI_##reg)
#define spi_writel(port, reg, value) \ #define spi_writel(port, reg, value) \
__raw_writel((value), (port)->regs + SPI_##reg) __raw_writel((value), (port)->regs + SPI_##reg)
#else
#define spi_readl(port, reg) \
readl_relaxed((port)->regs + SPI_##reg)
#define spi_writel(port, reg, value) \
writel_relaxed((value), (port)->regs + SPI_##reg)
#endif
/* use PIO for small transfers, avoiding DMA setup/teardown overhead and /* use PIO for small transfers, avoiding DMA setup/teardown overhead and
* cache operations; better heuristics consider wordsize and bitrate. * cache operations; better heuristics consider wordsize and bitrate.
*/ */
......
This diff is collapsed.
...@@ -44,7 +44,7 @@ static int bcm53xxspi_wait(struct bcm53xxspi *b53spi, unsigned int timeout_ms) ...@@ -44,7 +44,7 @@ static int bcm53xxspi_wait(struct bcm53xxspi *b53spi, unsigned int timeout_ms)
u32 tmp; u32 tmp;
/* SPE bit has to be 0 before we read MSPI STATUS */ /* SPE bit has to be 0 before we read MSPI STATUS */
deadline = jiffies + BCM53XXSPI_SPE_TIMEOUT_MS * HZ / 1000; deadline = jiffies + msecs_to_jiffies(BCM53XXSPI_SPE_TIMEOUT_MS);
do { do {
tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_SPCR2); tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_SPCR2);
if (!(tmp & B53SPI_MSPI_SPCR2_SPE)) if (!(tmp & B53SPI_MSPI_SPCR2_SPE))
...@@ -56,7 +56,7 @@ static int bcm53xxspi_wait(struct bcm53xxspi *b53spi, unsigned int timeout_ms) ...@@ -56,7 +56,7 @@ static int bcm53xxspi_wait(struct bcm53xxspi *b53spi, unsigned int timeout_ms)
goto spi_timeout; goto spi_timeout;
/* Check status */ /* Check status */
deadline = jiffies + timeout_ms * HZ / 1000; deadline = jiffies + msecs_to_jiffies(timeout_ms);
do { do {
tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_MSPI_STATUS); tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_MSPI_STATUS);
if (tmp & B53SPI_MSPI_MSPI_STATUS_SPIF) { if (tmp & B53SPI_MSPI_MSPI_STATUS_SPIF) {
......
...@@ -559,7 +559,7 @@ static void bfin_spi_pump_transfers(unsigned long data) ...@@ -559,7 +559,7 @@ static void bfin_spi_pump_transfers(unsigned long data)
struct spi_transfer *previous = NULL; struct spi_transfer *previous = NULL;
struct bfin_spi_slave_data *chip = NULL; struct bfin_spi_slave_data *chip = NULL;
unsigned int bits_per_word; unsigned int bits_per_word;
u16 cr, cr_width, dma_width, dma_config; u16 cr, cr_width = 0, dma_width, dma_config;
u32 tranf_success = 1; u32 tranf_success = 1;
u8 full_duplex = 0; u8 full_duplex = 0;
...@@ -648,7 +648,6 @@ static void bfin_spi_pump_transfers(unsigned long data) ...@@ -648,7 +648,6 @@ static void bfin_spi_pump_transfers(unsigned long data)
} else if (bits_per_word == 8) { } else if (bits_per_word == 8) {
drv_data->n_bytes = bits_per_word/8; drv_data->n_bytes = bits_per_word/8;
drv_data->len = transfer->len; drv_data->len = transfer->len;
cr_width = 0;
drv_data->ops = &bfin_bfin_spi_transfer_ops_u8; drv_data->ops = &bfin_bfin_spi_transfer_ops_u8;
} }
cr = bfin_read(&drv_data->regs->ctl) & ~(BIT_CTL_TIMOD | BIT_CTL_WORDSIZE); cr = bfin_read(&drv_data->regs->ctl) & ~(BIT_CTL_TIMOD | BIT_CTL_WORDSIZE);
......
...@@ -49,12 +49,17 @@ bitbang_txrx_be_cpha0(struct spi_device *spi, ...@@ -49,12 +49,17 @@ bitbang_txrx_be_cpha0(struct spi_device *spi,
{ {
/* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */ /* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */
bool oldbit = !(word & 1);
/* clock starts at inactive polarity */ /* clock starts at inactive polarity */
for (word <<= (32 - bits); likely(bits); bits--) { for (word <<= (32 - bits); likely(bits); bits--) {
/* setup MSB (to slave) on trailing edge */ /* setup MSB (to slave) on trailing edge */
if ((flags & SPI_MASTER_NO_TX) == 0) if ((flags & SPI_MASTER_NO_TX) == 0) {
if ((word & (1 << 31)) != oldbit) {
setmosi(spi, word & (1 << 31)); setmosi(spi, word & (1 << 31));
oldbit = word & (1 << 31);
}
}
spidelay(nsecs); /* T(setup) */ spidelay(nsecs); /* T(setup) */
setsck(spi, !cpol); setsck(spi, !cpol);
...@@ -76,13 +81,18 @@ bitbang_txrx_be_cpha1(struct spi_device *spi, ...@@ -76,13 +81,18 @@ bitbang_txrx_be_cpha1(struct spi_device *spi,
{ {
/* if (cpol == 0) this is SPI_MODE_1; else this is SPI_MODE_3 */ /* if (cpol == 0) this is SPI_MODE_1; else this is SPI_MODE_3 */
bool oldbit = !(word & (1 << 31));
/* clock starts at inactive polarity */ /* clock starts at inactive polarity */
for (word <<= (32 - bits); likely(bits); bits--) { for (word <<= (32 - bits); likely(bits); bits--) {
/* setup MSB (to slave) on leading edge */ /* setup MSB (to slave) on leading edge */
setsck(spi, !cpol); setsck(spi, !cpol);
if ((flags & SPI_MASTER_NO_TX) == 0) if ((flags & SPI_MASTER_NO_TX) == 0) {
if ((word & (1 << 31)) != oldbit) {
setmosi(spi, word & (1 << 31)); setmosi(spi, word & (1 << 31));
oldbit = word & (1 << 31);
}
}
spidelay(nsecs); /* T(setup) */ spidelay(nsecs); /* T(setup) */
setsck(spi, cpol); setsck(spi, cpol);
......
...@@ -23,29 +23,31 @@ ...@@ -23,29 +23,31 @@
#include "spi-dw.h" #include "spi-dw.h"
#ifdef CONFIG_SPI_DW_MID_DMA #ifdef CONFIG_SPI_DW_MID_DMA
#include <linux/intel_mid_dma.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/platform_data/dma-dw.h>
#define RX_BUSY 0 #define RX_BUSY 0
#define TX_BUSY 1 #define TX_BUSY 1
struct mid_dma { static struct dw_dma_slave mid_dma_tx = { .dst_id = 1 };
struct intel_mid_dma_slave dmas_tx; static struct dw_dma_slave mid_dma_rx = { .src_id = 0 };
struct intel_mid_dma_slave dmas_rx;
};
static bool mid_spi_dma_chan_filter(struct dma_chan *chan, void *param) static bool mid_spi_dma_chan_filter(struct dma_chan *chan, void *param)
{ {
struct dw_spi *dws = param; struct dw_dma_slave *s = param;
if (s->dma_dev != chan->device->dev)
return false;
return dws->dma_dev == chan->device->dev; chan->private = s;
return true;
} }
static int mid_spi_dma_init(struct dw_spi *dws) static int mid_spi_dma_init(struct dw_spi *dws)
{ {
struct mid_dma *dw_dma = dws->dma_priv;
struct pci_dev *dma_dev; struct pci_dev *dma_dev;
struct intel_mid_dma_slave *rxs, *txs; struct dw_dma_slave *tx = dws->dma_tx;
struct dw_dma_slave *rx = dws->dma_rx;
dma_cap_mask_t mask; dma_cap_mask_t mask;
/* /*
...@@ -56,28 +58,22 @@ static int mid_spi_dma_init(struct dw_spi *dws) ...@@ -56,28 +58,22 @@ static int mid_spi_dma_init(struct dw_spi *dws)
if (!dma_dev) if (!dma_dev)
return -ENODEV; return -ENODEV;
dws->dma_dev = &dma_dev->dev;
dma_cap_zero(mask); dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask); dma_cap_set(DMA_SLAVE, mask);
/* 1. Init rx channel */ /* 1. Init rx channel */
dws->rxchan = dma_request_channel(mask, mid_spi_dma_chan_filter, dws); rx->dma_dev = &dma_dev->dev;
dws->rxchan = dma_request_channel(mask, mid_spi_dma_chan_filter, rx);
if (!dws->rxchan) if (!dws->rxchan)
goto err_exit; goto err_exit;
rxs = &dw_dma->dmas_rx; dws->master->dma_rx = dws->rxchan;
rxs->hs_mode = LNW_DMA_HW_HS;
rxs->cfg_mode = LNW_DMA_PER_TO_MEM;
dws->rxchan->private = rxs;
/* 2. Init tx channel */ /* 2. Init tx channel */
dws->txchan = dma_request_channel(mask, mid_spi_dma_chan_filter, dws); tx->dma_dev = &dma_dev->dev;
dws->txchan = dma_request_channel(mask, mid_spi_dma_chan_filter, tx);
if (!dws->txchan) if (!dws->txchan)
goto free_rxchan; goto free_rxchan;
txs = &dw_dma->dmas_tx; dws->master->dma_tx = dws->txchan;
txs->hs_mode = LNW_DMA_HW_HS;
txs->cfg_mode = LNW_DMA_MEM_TO_PER;
dws->txchan->private = txs;
dws->dma_inited = 1; dws->dma_inited = 1;
return 0; return 0;
...@@ -100,6 +96,42 @@ static void mid_spi_dma_exit(struct dw_spi *dws) ...@@ -100,6 +96,42 @@ static void mid_spi_dma_exit(struct dw_spi *dws)
dma_release_channel(dws->rxchan); dma_release_channel(dws->rxchan);
} }
static irqreturn_t dma_transfer(struct dw_spi *dws)
{
u16 irq_status = dw_readl(dws, DW_SPI_ISR);
if (!irq_status)
return IRQ_NONE;
dw_readl(dws, DW_SPI_ICR);
spi_reset_chip(dws);
dev_err(&dws->master->dev, "%s: FIFO overrun/underrun\n", __func__);
dws->master->cur_msg->status = -EIO;
spi_finalize_current_transfer(dws->master);
return IRQ_HANDLED;
}
static bool mid_spi_can_dma(struct spi_master *master, struct spi_device *spi,
struct spi_transfer *xfer)
{
struct dw_spi *dws = spi_master_get_devdata(master);
if (!dws->dma_inited)
return false;
return xfer->len > dws->fifo_len;
}
static enum dma_slave_buswidth convert_dma_width(u32 dma_width) {
if (dma_width == 1)
return DMA_SLAVE_BUSWIDTH_1_BYTE;
else if (dma_width == 2)
return DMA_SLAVE_BUSWIDTH_2_BYTES;
return DMA_SLAVE_BUSWIDTH_UNDEFINED;
}
/* /*
* dws->dma_chan_busy is set before the dma transfer starts, callback for tx * dws->dma_chan_busy is set before the dma transfer starts, callback for tx
* channel will clear a corresponding bit. * channel will clear a corresponding bit.
...@@ -111,33 +143,30 @@ static void dw_spi_dma_tx_done(void *arg) ...@@ -111,33 +143,30 @@ static void dw_spi_dma_tx_done(void *arg)
clear_bit(TX_BUSY, &dws->dma_chan_busy); clear_bit(TX_BUSY, &dws->dma_chan_busy);
if (test_bit(RX_BUSY, &dws->dma_chan_busy)) if (test_bit(RX_BUSY, &dws->dma_chan_busy))
return; return;
dw_spi_xfer_done(dws); spi_finalize_current_transfer(dws->master);
} }
static struct dma_async_tx_descriptor *dw_spi_dma_prepare_tx(struct dw_spi *dws) static struct dma_async_tx_descriptor *dw_spi_dma_prepare_tx(struct dw_spi *dws,
struct spi_transfer *xfer)
{ {
struct dma_slave_config txconf; struct dma_slave_config txconf;
struct dma_async_tx_descriptor *txdesc; struct dma_async_tx_descriptor *txdesc;
if (!dws->tx_dma) if (!xfer->tx_buf)
return NULL; return NULL;
txconf.direction = DMA_MEM_TO_DEV; txconf.direction = DMA_MEM_TO_DEV;
txconf.dst_addr = dws->dma_addr; txconf.dst_addr = dws->dma_addr;
txconf.dst_maxburst = LNW_DMA_MSIZE_16; txconf.dst_maxburst = 16;
txconf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; txconf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
txconf.dst_addr_width = dws->dma_width; txconf.dst_addr_width = convert_dma_width(dws->dma_width);
txconf.device_fc = false; txconf.device_fc = false;
dmaengine_slave_config(dws->txchan, &txconf); dmaengine_slave_config(dws->txchan, &txconf);
memset(&dws->tx_sgl, 0, sizeof(dws->tx_sgl));
dws->tx_sgl.dma_address = dws->tx_dma;
dws->tx_sgl.length = dws->len;
txdesc = dmaengine_prep_slave_sg(dws->txchan, txdesc = dmaengine_prep_slave_sg(dws->txchan,
&dws->tx_sgl, xfer->tx_sg.sgl,
1, xfer->tx_sg.nents,
DMA_MEM_TO_DEV, DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK); DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!txdesc) if (!txdesc)
...@@ -160,33 +189,30 @@ static void dw_spi_dma_rx_done(void *arg) ...@@ -160,33 +189,30 @@ static void dw_spi_dma_rx_done(void *arg)
clear_bit(RX_BUSY, &dws->dma_chan_busy); clear_bit(RX_BUSY, &dws->dma_chan_busy);
if (test_bit(TX_BUSY, &dws->dma_chan_busy)) if (test_bit(TX_BUSY, &dws->dma_chan_busy))
return; return;
dw_spi_xfer_done(dws); spi_finalize_current_transfer(dws->master);
} }
static struct dma_async_tx_descriptor *dw_spi_dma_prepare_rx(struct dw_spi *dws) static struct dma_async_tx_descriptor *dw_spi_dma_prepare_rx(struct dw_spi *dws,
struct spi_transfer *xfer)
{ {
struct dma_slave_config rxconf; struct dma_slave_config rxconf;
struct dma_async_tx_descriptor *rxdesc; struct dma_async_tx_descriptor *rxdesc;
if (!dws->rx_dma) if (!xfer->rx_buf)
return NULL; return NULL;
rxconf.direction = DMA_DEV_TO_MEM; rxconf.direction = DMA_DEV_TO_MEM;
rxconf.src_addr = dws->dma_addr; rxconf.src_addr = dws->dma_addr;
rxconf.src_maxburst = LNW_DMA_MSIZE_16; rxconf.src_maxburst = 16;
rxconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; rxconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
rxconf.src_addr_width = dws->dma_width; rxconf.src_addr_width = convert_dma_width(dws->dma_width);
rxconf.device_fc = false; rxconf.device_fc = false;
dmaengine_slave_config(dws->rxchan, &rxconf); dmaengine_slave_config(dws->rxchan, &rxconf);
memset(&dws->rx_sgl, 0, sizeof(dws->rx_sgl));
dws->rx_sgl.dma_address = dws->rx_dma;
dws->rx_sgl.length = dws->len;
rxdesc = dmaengine_prep_slave_sg(dws->rxchan, rxdesc = dmaengine_prep_slave_sg(dws->rxchan,
&dws->rx_sgl, xfer->rx_sg.sgl,
1, xfer->rx_sg.nents,
DMA_DEV_TO_MEM, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK); DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!rxdesc) if (!rxdesc)
...@@ -198,37 +224,36 @@ static struct dma_async_tx_descriptor *dw_spi_dma_prepare_rx(struct dw_spi *dws) ...@@ -198,37 +224,36 @@ static struct dma_async_tx_descriptor *dw_spi_dma_prepare_rx(struct dw_spi *dws)
return rxdesc; return rxdesc;
} }
static void dw_spi_dma_setup(struct dw_spi *dws) static int mid_spi_dma_setup(struct dw_spi *dws, struct spi_transfer *xfer)
{ {
u16 dma_ctrl = 0; u16 dma_ctrl = 0;
spi_enable_chip(dws, 0); dw_writel(dws, DW_SPI_DMARDLR, 0xf);
dw_writel(dws, DW_SPI_DMATDLR, 0x10);
dw_writew(dws, DW_SPI_DMARDLR, 0xf);
dw_writew(dws, DW_SPI_DMATDLR, 0x10);
if (dws->tx_dma) if (xfer->tx_buf)
dma_ctrl |= SPI_DMA_TDMAE; dma_ctrl |= SPI_DMA_TDMAE;
if (dws->rx_dma) if (xfer->rx_buf)
dma_ctrl |= SPI_DMA_RDMAE; dma_ctrl |= SPI_DMA_RDMAE;
dw_writew(dws, DW_SPI_DMACR, dma_ctrl); dw_writel(dws, DW_SPI_DMACR, dma_ctrl);
/* Set the interrupt mask */
spi_umask_intr(dws, SPI_INT_TXOI | SPI_INT_RXUI | SPI_INT_RXOI);
dws->transfer_handler = dma_transfer;
spi_enable_chip(dws, 1); return 0;
} }
static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change) static int mid_spi_dma_transfer(struct dw_spi *dws, struct spi_transfer *xfer)
{ {
struct dma_async_tx_descriptor *txdesc, *rxdesc; struct dma_async_tx_descriptor *txdesc, *rxdesc;
/* 1. setup DMA related registers */ /* Prepare the TX dma transfer */
if (cs_change) txdesc = dw_spi_dma_prepare_tx(dws, xfer);
dw_spi_dma_setup(dws);
/* 2. Prepare the TX dma transfer */
txdesc = dw_spi_dma_prepare_tx(dws);
/* 3. Prepare the RX dma transfer */ /* Prepare the RX dma transfer */
rxdesc = dw_spi_dma_prepare_rx(dws); rxdesc = dw_spi_dma_prepare_rx(dws, xfer);
/* rx must be started before tx due to spi instinct */ /* rx must be started before tx due to spi instinct */
if (rxdesc) { if (rxdesc) {
...@@ -246,10 +271,25 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change) ...@@ -246,10 +271,25 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
return 0; return 0;
} }
static void mid_spi_dma_stop(struct dw_spi *dws)
{
if (test_bit(TX_BUSY, &dws->dma_chan_busy)) {
dmaengine_terminate_all(dws->txchan);
clear_bit(TX_BUSY, &dws->dma_chan_busy);
}
if (test_bit(RX_BUSY, &dws->dma_chan_busy)) {
dmaengine_terminate_all(dws->rxchan);
clear_bit(RX_BUSY, &dws->dma_chan_busy);
}
}
static struct dw_spi_dma_ops mid_dma_ops = { static struct dw_spi_dma_ops mid_dma_ops = {
.dma_init = mid_spi_dma_init, .dma_init = mid_spi_dma_init,
.dma_exit = mid_spi_dma_exit, .dma_exit = mid_spi_dma_exit,
.dma_setup = mid_spi_dma_setup,
.can_dma = mid_spi_can_dma,
.dma_transfer = mid_spi_dma_transfer, .dma_transfer = mid_spi_dma_transfer,
.dma_stop = mid_spi_dma_stop,
}; };
#endif #endif
...@@ -282,9 +322,8 @@ int dw_spi_mid_init(struct dw_spi *dws) ...@@ -282,9 +322,8 @@ int dw_spi_mid_init(struct dw_spi *dws)
iounmap(clk_reg); iounmap(clk_reg);
#ifdef CONFIG_SPI_DW_MID_DMA #ifdef CONFIG_SPI_DW_MID_DMA
dws->dma_priv = kzalloc(sizeof(struct mid_dma), GFP_KERNEL); dws->dma_tx = &mid_dma_tx;
if (!dws->dma_priv) dws->dma_rx = &mid_dma_rx;
return -ENOMEM;
dws->dma_ops = &mid_dma_ops; dws->dma_ops = &mid_dma_ops;
#endif #endif
return 0; return 0;
......
This diff is collapsed.
...@@ -91,12 +91,15 @@ struct dw_spi; ...@@ -91,12 +91,15 @@ struct dw_spi;
struct dw_spi_dma_ops { struct dw_spi_dma_ops {
int (*dma_init)(struct dw_spi *dws); int (*dma_init)(struct dw_spi *dws);
void (*dma_exit)(struct dw_spi *dws); void (*dma_exit)(struct dw_spi *dws);
int (*dma_transfer)(struct dw_spi *dws, int cs_change); int (*dma_setup)(struct dw_spi *dws, struct spi_transfer *xfer);
bool (*can_dma)(struct spi_master *master, struct spi_device *spi,
struct spi_transfer *xfer);
int (*dma_transfer)(struct dw_spi *dws, struct spi_transfer *xfer);
void (*dma_stop)(struct dw_spi *dws);
}; };
struct dw_spi { struct dw_spi {
struct spi_master *master; struct spi_master *master;
struct spi_device *cur_dev;
enum dw_ssi_type type; enum dw_ssi_type type;
char name[16]; char name[16];
...@@ -109,41 +112,26 @@ struct dw_spi { ...@@ -109,41 +112,26 @@ struct dw_spi {
u16 bus_num; u16 bus_num;
u16 num_cs; /* supported slave numbers */ u16 num_cs; /* supported slave numbers */
/* Message Transfer pump */
struct tasklet_struct pump_transfers;
/* Current message transfer state info */ /* Current message transfer state info */
struct spi_message *cur_msg;
struct spi_transfer *cur_transfer;
struct chip_data *cur_chip;
struct chip_data *prev_chip;
size_t len; size_t len;
void *tx; void *tx;
void *tx_end; void *tx_end;
void *rx; void *rx;
void *rx_end; void *rx_end;
int dma_mapped; int dma_mapped;
dma_addr_t rx_dma;
dma_addr_t tx_dma;
size_t rx_map_len;
size_t tx_map_len;
u8 n_bytes; /* current is a 1/2 bytes op */ u8 n_bytes; /* current is a 1/2 bytes op */
u8 max_bits_per_word; /* maxim is 16b */
u32 dma_width; u32 dma_width;
irqreturn_t (*transfer_handler)(struct dw_spi *dws); irqreturn_t (*transfer_handler)(struct dw_spi *dws);
void (*cs_control)(u32 command);
/* Dma info */ /* DMA info */
int dma_inited; int dma_inited;
struct dma_chan *txchan; struct dma_chan *txchan;
struct scatterlist tx_sgl;
struct dma_chan *rxchan; struct dma_chan *rxchan;
struct scatterlist rx_sgl;
unsigned long dma_chan_busy; unsigned long dma_chan_busy;
struct device *dma_dev;
dma_addr_t dma_addr; /* phy address of the Data register */ dma_addr_t dma_addr; /* phy address of the Data register */
struct dw_spi_dma_ops *dma_ops; struct dw_spi_dma_ops *dma_ops;
void *dma_priv; /* platform relate info */ void *dma_tx;
void *dma_rx;
/* Bus interface info */ /* Bus interface info */
void *priv; void *priv;
...@@ -162,16 +150,6 @@ static inline void dw_writel(struct dw_spi *dws, u32 offset, u32 val) ...@@ -162,16 +150,6 @@ static inline void dw_writel(struct dw_spi *dws, u32 offset, u32 val)
__raw_writel(val, dws->regs + offset); __raw_writel(val, dws->regs + offset);
} }
static inline u16 dw_readw(struct dw_spi *dws, u32 offset)
{
return __raw_readw(dws->regs + offset);
}
static inline void dw_writew(struct dw_spi *dws, u32 offset, u16 val)
{
__raw_writew(val, dws->regs + offset);
}
static inline void spi_enable_chip(struct dw_spi *dws, int enable) static inline void spi_enable_chip(struct dw_spi *dws, int enable)
{ {
dw_writel(dws, DW_SPI_SSIENR, (enable ? 1 : 0)); dw_writel(dws, DW_SPI_SSIENR, (enable ? 1 : 0));
...@@ -182,22 +160,6 @@ static inline void spi_set_clk(struct dw_spi *dws, u16 div) ...@@ -182,22 +160,6 @@ static inline void spi_set_clk(struct dw_spi *dws, u16 div)
dw_writel(dws, DW_SPI_BAUDR, div); dw_writel(dws, DW_SPI_BAUDR, div);
} }
static inline void spi_chip_sel(struct dw_spi *dws, struct spi_device *spi,
int active)
{
u16 cs = spi->chip_select;
int gpio_val = active ? (spi->mode & SPI_CS_HIGH) :
!(spi->mode & SPI_CS_HIGH);
if (dws->cs_control)
dws->cs_control(active);
if (gpio_is_valid(spi->cs_gpio))
gpio_set_value(spi->cs_gpio, gpio_val);
if (active)
dw_writel(dws, DW_SPI_SER, 1 << cs);
}
/* Disable IRQ bits */ /* Disable IRQ bits */
static inline void spi_mask_intr(struct dw_spi *dws, u32 mask) static inline void spi_mask_intr(struct dw_spi *dws, u32 mask)
{ {
...@@ -216,16 +178,27 @@ static inline void spi_umask_intr(struct dw_spi *dws, u32 mask) ...@@ -216,16 +178,27 @@ static inline void spi_umask_intr(struct dw_spi *dws, u32 mask)
dw_writel(dws, DW_SPI_IMR, new_mask); dw_writel(dws, DW_SPI_IMR, new_mask);
} }
/*
* This does disable the SPI controller, interrupts, and re-enable the
* controller back. Transmit and receive FIFO buffers are cleared when the
* device is disabled.
*/
static inline void spi_reset_chip(struct dw_spi *dws)
{
spi_enable_chip(dws, 0);
spi_mask_intr(dws, 0xff);
spi_enable_chip(dws, 1);
}
/* /*
* Each SPI slave device to work with dw_api controller should * Each SPI slave device to work with dw_api controller should
* has such a structure claiming its working mode (PIO/DMA etc), * has such a structure claiming its working mode (poll or PIO/DMA),
* which can be save in the "controller_data" member of the * which can be save in the "controller_data" member of the
* struct spi_device. * struct spi_device.
*/ */
struct dw_spi_chip { struct dw_spi_chip {
u8 poll_mode; /* 1 for controller polling mode */ u8 poll_mode; /* 1 for controller polling mode */
u8 type; /* SPI/SSP/MicroWire */ u8 type; /* SPI/SSP/MicroWire */
u8 enable_dma;
void (*cs_control)(u32 command); void (*cs_control)(u32 command);
}; };
...@@ -233,7 +206,6 @@ extern int dw_spi_add_host(struct device *dev, struct dw_spi *dws); ...@@ -233,7 +206,6 @@ extern int dw_spi_add_host(struct device *dev, struct dw_spi *dws);
extern void dw_spi_remove_host(struct dw_spi *dws); extern void dw_spi_remove_host(struct dw_spi *dws);
extern int dw_spi_suspend_host(struct dw_spi *dws); extern int dw_spi_suspend_host(struct dw_spi *dws);
extern int dw_spi_resume_host(struct dw_spi *dws); extern int dw_spi_resume_host(struct dw_spi *dws);
extern void dw_spi_xfer_done(struct dw_spi *dws);
/* platform related setup */ /* platform related setup */
extern int dw_spi_mid_init(struct dw_spi *dws); /* Intel MID platforms */ extern int dw_spi_mid_init(struct dw_spi *dws); /* Intel MID platforms */
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/math64.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
...@@ -29,6 +30,7 @@ ...@@ -29,6 +30,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h> #include <linux/spi/spi_bitbang.h>
#include <linux/time.h>
#define DRIVER_NAME "fsl-dspi" #define DRIVER_NAME "fsl-dspi"
...@@ -51,7 +53,7 @@ ...@@ -51,7 +53,7 @@
#define SPI_CTAR_CPOL(x) ((x) << 26) #define SPI_CTAR_CPOL(x) ((x) << 26)
#define SPI_CTAR_CPHA(x) ((x) << 25) #define SPI_CTAR_CPHA(x) ((x) << 25)
#define SPI_CTAR_LSBFE(x) ((x) << 24) #define SPI_CTAR_LSBFE(x) ((x) << 24)
#define SPI_CTAR_PCSSCR(x) (((x) & 0x00000003) << 22) #define SPI_CTAR_PCSSCK(x) (((x) & 0x00000003) << 22)
#define SPI_CTAR_PASC(x) (((x) & 0x00000003) << 20) #define SPI_CTAR_PASC(x) (((x) & 0x00000003) << 20)
#define SPI_CTAR_PDT(x) (((x) & 0x00000003) << 18) #define SPI_CTAR_PDT(x) (((x) & 0x00000003) << 18)
#define SPI_CTAR_PBR(x) (((x) & 0x00000003) << 16) #define SPI_CTAR_PBR(x) (((x) & 0x00000003) << 16)
...@@ -59,6 +61,7 @@ ...@@ -59,6 +61,7 @@
#define SPI_CTAR_ASC(x) (((x) & 0x0000000f) << 8) #define SPI_CTAR_ASC(x) (((x) & 0x0000000f) << 8)
#define SPI_CTAR_DT(x) (((x) & 0x0000000f) << 4) #define SPI_CTAR_DT(x) (((x) & 0x0000000f) << 4)
#define SPI_CTAR_BR(x) ((x) & 0x0000000f) #define SPI_CTAR_BR(x) ((x) & 0x0000000f)
#define SPI_CTAR_SCALE_BITS 0xf
#define SPI_CTAR0_SLAVE 0x0c #define SPI_CTAR0_SLAVE 0x0c
...@@ -148,23 +151,66 @@ static void hz_to_spi_baud(char *pbr, char *br, int speed_hz, ...@@ -148,23 +151,66 @@ static void hz_to_spi_baud(char *pbr, char *br, int speed_hz,
16, 32, 64, 128, 16, 32, 64, 128,
256, 512, 1024, 2048, 256, 512, 1024, 2048,
4096, 8192, 16384, 32768 }; 4096, 8192, 16384, 32768 };
int temp, i = 0, j = 0; int scale_needed, scale, minscale = INT_MAX;
int i, j;
temp = clkrate / 2 / speed_hz;
scale_needed = clkrate / speed_hz;
for (i = 0; i < ARRAY_SIZE(pbr_tbl); i++) if (clkrate % speed_hz)
for (j = 0; j < ARRAY_SIZE(brs); j++) { scale_needed++;
if (pbr_tbl[i] * brs[j] >= temp) {
*pbr = i; for (i = 0; i < ARRAY_SIZE(brs); i++)
*br = j; for (j = 0; j < ARRAY_SIZE(pbr_tbl); j++) {
return; scale = brs[i] * pbr_tbl[j];
if (scale >= scale_needed) {
if (scale < minscale) {
minscale = scale;
*br = i;
*pbr = j;
}
break;
} }
} }
pr_warn("Can not find valid baud rate,speed_hz is %d,clkrate is %ld\ if (minscale == INT_MAX) {
,we use the max prescaler value.\n", speed_hz, clkrate); pr_warn("Can not find valid baud rate,speed_hz is %d,clkrate is %ld, we use the max prescaler value.\n",
speed_hz, clkrate);
*pbr = ARRAY_SIZE(pbr_tbl) - 1; *pbr = ARRAY_SIZE(pbr_tbl) - 1;
*br = ARRAY_SIZE(brs) - 1; *br = ARRAY_SIZE(brs) - 1;
}
}
static void ns_delay_scale(char *psc, char *sc, int delay_ns,
unsigned long clkrate)
{
int pscale_tbl[4] = {1, 3, 5, 7};
int scale_needed, scale, minscale = INT_MAX;
int i, j;
u32 remainder;
scale_needed = div_u64_rem((u64)delay_ns * clkrate, NSEC_PER_SEC,
&remainder);
if (remainder)
scale_needed++;
for (i = 0; i < ARRAY_SIZE(pscale_tbl); i++)
for (j = 0; j <= SPI_CTAR_SCALE_BITS; j++) {
scale = pscale_tbl[i] * (2 << j);
if (scale >= scale_needed) {
if (scale < minscale) {
minscale = scale;
*psc = i;
*sc = j;
}
break;
}
}
if (minscale == INT_MAX) {
pr_warn("Cannot find correct scale values for %dns delay at clkrate %ld, using max prescaler value",
delay_ns, clkrate);
*psc = ARRAY_SIZE(pscale_tbl) - 1;
*sc = SPI_CTAR_SCALE_BITS;
}
} }
static int dspi_transfer_write(struct fsl_dspi *dspi) static int dspi_transfer_write(struct fsl_dspi *dspi)
...@@ -345,7 +391,10 @@ static int dspi_setup(struct spi_device *spi) ...@@ -345,7 +391,10 @@ static int dspi_setup(struct spi_device *spi)
{ {
struct chip_data *chip; struct chip_data *chip;
struct fsl_dspi *dspi = spi_master_get_devdata(spi->master); struct fsl_dspi *dspi = spi_master_get_devdata(spi->master);
unsigned char br = 0, pbr = 0, fmsz = 0; u32 cs_sck_delay = 0, sck_cs_delay = 0;
unsigned char br = 0, pbr = 0, pcssck = 0, cssck = 0;
unsigned char pasc = 0, asc = 0, fmsz = 0;
unsigned long clkrate;
if ((spi->bits_per_word >= 4) && (spi->bits_per_word <= 16)) { if ((spi->bits_per_word >= 4) && (spi->bits_per_word <= 16)) {
fmsz = spi->bits_per_word - 1; fmsz = spi->bits_per_word - 1;
...@@ -362,18 +411,34 @@ static int dspi_setup(struct spi_device *spi) ...@@ -362,18 +411,34 @@ static int dspi_setup(struct spi_device *spi)
return -ENOMEM; return -ENOMEM;
} }
of_property_read_u32(spi->dev.of_node, "fsl,spi-cs-sck-delay",
&cs_sck_delay);
of_property_read_u32(spi->dev.of_node, "fsl,spi-sck-cs-delay",
&sck_cs_delay);
chip->mcr_val = SPI_MCR_MASTER | SPI_MCR_PCSIS | chip->mcr_val = SPI_MCR_MASTER | SPI_MCR_PCSIS |
SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF; SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF;
chip->void_write_data = 0; chip->void_write_data = 0;
hz_to_spi_baud(&pbr, &br, clkrate = clk_get_rate(dspi->clk);
spi->max_speed_hz, clk_get_rate(dspi->clk)); hz_to_spi_baud(&pbr, &br, spi->max_speed_hz, clkrate);
/* Set PCS to SCK delay scale values */
ns_delay_scale(&pcssck, &cssck, cs_sck_delay, clkrate);
/* Set After SCK delay scale values */
ns_delay_scale(&pasc, &asc, sck_cs_delay, clkrate);
chip->ctar_val = SPI_CTAR_FMSZ(fmsz) chip->ctar_val = SPI_CTAR_FMSZ(fmsz)
| SPI_CTAR_CPOL(spi->mode & SPI_CPOL ? 1 : 0) | SPI_CTAR_CPOL(spi->mode & SPI_CPOL ? 1 : 0)
| SPI_CTAR_CPHA(spi->mode & SPI_CPHA ? 1 : 0) | SPI_CTAR_CPHA(spi->mode & SPI_CPHA ? 1 : 0)
| SPI_CTAR_LSBFE(spi->mode & SPI_LSB_FIRST ? 1 : 0) | SPI_CTAR_LSBFE(spi->mode & SPI_LSB_FIRST ? 1 : 0)
| SPI_CTAR_PCSSCK(pcssck)
| SPI_CTAR_CSSCK(cssck)
| SPI_CTAR_PASC(pasc)
| SPI_CTAR_ASC(asc)
| SPI_CTAR_PBR(pbr) | SPI_CTAR_PBR(pbr)
| SPI_CTAR_BR(br); | SPI_CTAR_BR(br);
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/dmaengine.h> #include <linux/dmaengine.h>
#include <linux/gpio.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/irq.h> #include <linux/irq.h>
...@@ -122,36 +123,31 @@ static inline void spfi_start(struct img_spfi *spfi) ...@@ -122,36 +123,31 @@ static inline void spfi_start(struct img_spfi *spfi)
spfi_writel(spfi, val, SPFI_CONTROL); spfi_writel(spfi, val, SPFI_CONTROL);
} }
static inline void spfi_stop(struct img_spfi *spfi)
{
u32 val;
val = spfi_readl(spfi, SPFI_CONTROL);
val &= ~SPFI_CONTROL_SPFI_EN;
spfi_writel(spfi, val, SPFI_CONTROL);
}
static inline void spfi_reset(struct img_spfi *spfi) static inline void spfi_reset(struct img_spfi *spfi)
{ {
spfi_writel(spfi, SPFI_CONTROL_SOFT_RESET, SPFI_CONTROL); spfi_writel(spfi, SPFI_CONTROL_SOFT_RESET, SPFI_CONTROL);
udelay(1);
spfi_writel(spfi, 0, SPFI_CONTROL); spfi_writel(spfi, 0, SPFI_CONTROL);
} }
static void spfi_flush_tx_fifo(struct img_spfi *spfi) static int spfi_wait_all_done(struct img_spfi *spfi)
{ {
unsigned long timeout = jiffies + msecs_to_jiffies(10); unsigned long timeout = jiffies + msecs_to_jiffies(50);
spfi_writel(spfi, SPFI_INTERRUPT_SDE, SPFI_INTERRUPT_CLEAR);
while (time_before(jiffies, timeout)) { while (time_before(jiffies, timeout)) {
if (spfi_readl(spfi, SPFI_INTERRUPT_STATUS) & u32 status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS);
SPFI_INTERRUPT_SDE)
return; if (status & SPFI_INTERRUPT_ALLDONETRIG) {
spfi_writel(spfi, SPFI_INTERRUPT_ALLDONETRIG,
SPFI_INTERRUPT_CLEAR);
return 0;
}
cpu_relax(); cpu_relax();
} }
dev_err(spfi->dev, "Timed out waiting for FIFO to drain\n"); dev_err(spfi->dev, "Timed out waiting for transaction to complete\n");
spfi_reset(spfi); spfi_reset(spfi);
return -ETIMEDOUT;
} }
static unsigned int spfi_pio_write32(struct img_spfi *spfi, const u32 *buf, static unsigned int spfi_pio_write32(struct img_spfi *spfi, const u32 *buf,
...@@ -237,6 +233,7 @@ static int img_spfi_start_pio(struct spi_master *master, ...@@ -237,6 +233,7 @@ static int img_spfi_start_pio(struct spi_master *master,
const void *tx_buf = xfer->tx_buf; const void *tx_buf = xfer->tx_buf;
void *rx_buf = xfer->rx_buf; void *rx_buf = xfer->rx_buf;
unsigned long timeout; unsigned long timeout;
int ret;
if (tx_buf) if (tx_buf)
tx_bytes = xfer->len; tx_bytes = xfer->len;
...@@ -269,16 +266,15 @@ static int img_spfi_start_pio(struct spi_master *master, ...@@ -269,16 +266,15 @@ static int img_spfi_start_pio(struct spi_master *master,
cpu_relax(); cpu_relax();
} }
ret = spfi_wait_all_done(spfi);
if (ret < 0)
return ret;
if (rx_bytes > 0 || tx_bytes > 0) { if (rx_bytes > 0 || tx_bytes > 0) {
dev_err(spfi->dev, "PIO transfer timed out\n"); dev_err(spfi->dev, "PIO transfer timed out\n");
spfi_reset(spfi);
return -ETIMEDOUT; return -ETIMEDOUT;
} }
if (tx_buf)
spfi_flush_tx_fifo(spfi);
spfi_stop(spfi);
return 0; return 0;
} }
...@@ -287,14 +283,12 @@ static void img_spfi_dma_rx_cb(void *data) ...@@ -287,14 +283,12 @@ static void img_spfi_dma_rx_cb(void *data)
struct img_spfi *spfi = data; struct img_spfi *spfi = data;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&spfi->lock, flags); spfi_wait_all_done(spfi);
spin_lock_irqsave(&spfi->lock, flags);
spfi->rx_dma_busy = false; spfi->rx_dma_busy = false;
if (!spfi->tx_dma_busy) { if (!spfi->tx_dma_busy)
spfi_stop(spfi);
spi_finalize_current_transfer(spfi->master); spi_finalize_current_transfer(spfi->master);
}
spin_unlock_irqrestore(&spfi->lock, flags); spin_unlock_irqrestore(&spfi->lock, flags);
} }
...@@ -303,16 +297,12 @@ static void img_spfi_dma_tx_cb(void *data) ...@@ -303,16 +297,12 @@ static void img_spfi_dma_tx_cb(void *data)
struct img_spfi *spfi = data; struct img_spfi *spfi = data;
unsigned long flags; unsigned long flags;
spfi_flush_tx_fifo(spfi); spfi_wait_all_done(spfi);
spin_lock_irqsave(&spfi->lock, flags); spin_lock_irqsave(&spfi->lock, flags);
spfi->tx_dma_busy = false; spfi->tx_dma_busy = false;
if (!spfi->rx_dma_busy) { if (!spfi->rx_dma_busy)
spfi_stop(spfi);
spi_finalize_current_transfer(spfi->master); spi_finalize_current_transfer(spfi->master);
}
spin_unlock_irqrestore(&spfi->lock, flags); spin_unlock_irqrestore(&spfi->lock, flags);
} }
...@@ -397,6 +387,75 @@ static int img_spfi_start_dma(struct spi_master *master, ...@@ -397,6 +387,75 @@ static int img_spfi_start_dma(struct spi_master *master,
return -EIO; return -EIO;
} }
static void img_spfi_handle_err(struct spi_master *master,
struct spi_message *msg)
{
struct img_spfi *spfi = spi_master_get_devdata(master);
unsigned long flags;
/*
* Stop all DMA and reset the controller if the previous transaction
* timed-out and never completed it's DMA.
*/
spin_lock_irqsave(&spfi->lock, flags);
if (spfi->tx_dma_busy || spfi->rx_dma_busy) {
spfi->tx_dma_busy = false;
spfi->rx_dma_busy = false;
dmaengine_terminate_all(spfi->tx_ch);
dmaengine_terminate_all(spfi->rx_ch);
}
spin_unlock_irqrestore(&spfi->lock, flags);
}
static int img_spfi_prepare(struct spi_master *master, struct spi_message *msg)
{
struct img_spfi *spfi = spi_master_get_devdata(master);
u32 val;
val = spfi_readl(spfi, SPFI_PORT_STATE);
if (msg->spi->mode & SPI_CPHA)
val |= SPFI_PORT_STATE_CK_PHASE(msg->spi->chip_select);
else
val &= ~SPFI_PORT_STATE_CK_PHASE(msg->spi->chip_select);
if (msg->spi->mode & SPI_CPOL)
val |= SPFI_PORT_STATE_CK_POL(msg->spi->chip_select);
else
val &= ~SPFI_PORT_STATE_CK_POL(msg->spi->chip_select);
spfi_writel(spfi, val, SPFI_PORT_STATE);
return 0;
}
static int img_spfi_unprepare(struct spi_master *master,
struct spi_message *msg)
{
struct img_spfi *spfi = spi_master_get_devdata(master);
spfi_reset(spfi);
return 0;
}
static int img_spfi_setup(struct spi_device *spi)
{
int ret;
ret = gpio_request_one(spi->cs_gpio, (spi->mode & SPI_CS_HIGH) ?
GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
dev_name(&spi->dev));
if (ret)
dev_err(&spi->dev, "can't request chipselect gpio %d\n",
spi->cs_gpio);
return ret;
}
static void img_spfi_cleanup(struct spi_device *spi)
{
gpio_free(spi->cs_gpio);
}
static void img_spfi_config(struct spi_master *master, struct spi_device *spi, static void img_spfi_config(struct spi_master *master, struct spi_device *spi,
struct spi_transfer *xfer) struct spi_transfer *xfer)
{ {
...@@ -405,10 +464,10 @@ static void img_spfi_config(struct spi_master *master, struct spi_device *spi, ...@@ -405,10 +464,10 @@ static void img_spfi_config(struct spi_master *master, struct spi_device *spi,
/* /*
* output = spfi_clk * (BITCLK / 512), where BITCLK must be a * output = spfi_clk * (BITCLK / 512), where BITCLK must be a
* power of 2 up to 256 (where 255 == 256 since BITCLK is 8 bits) * power of 2 up to 128
*/ */
div = DIV_ROUND_UP(master->max_speed_hz, xfer->speed_hz); div = DIV_ROUND_UP(clk_get_rate(spfi->spfi_clk), xfer->speed_hz);
div = clamp(512 / (1 << get_count_order(div)), 1, 255); div = clamp(512 / (1 << get_count_order(div)), 1, 128);
val = spfi_readl(spfi, SPFI_DEVICE_PARAMETER(spi->chip_select)); val = spfi_readl(spfi, SPFI_DEVICE_PARAMETER(spi->chip_select));
val &= ~(SPFI_DEVICE_PARAMETER_BITCLK_MASK << val &= ~(SPFI_DEVICE_PARAMETER_BITCLK_MASK <<
...@@ -416,6 +475,9 @@ static void img_spfi_config(struct spi_master *master, struct spi_device *spi, ...@@ -416,6 +475,9 @@ static void img_spfi_config(struct spi_master *master, struct spi_device *spi,
val |= div << SPFI_DEVICE_PARAMETER_BITCLK_SHIFT; val |= div << SPFI_DEVICE_PARAMETER_BITCLK_SHIFT;
spfi_writel(spfi, val, SPFI_DEVICE_PARAMETER(spi->chip_select)); spfi_writel(spfi, val, SPFI_DEVICE_PARAMETER(spi->chip_select));
spfi_writel(spfi, xfer->len << SPFI_TRANSACTION_TSIZE_SHIFT,
SPFI_TRANSACTION);
val = spfi_readl(spfi, SPFI_CONTROL); val = spfi_readl(spfi, SPFI_CONTROL);
val &= ~(SPFI_CONTROL_SEND_DMA | SPFI_CONTROL_GET_DMA); val &= ~(SPFI_CONTROL_SEND_DMA | SPFI_CONTROL_GET_DMA);
if (xfer->tx_buf) if (xfer->tx_buf)
...@@ -429,25 +491,7 @@ static void img_spfi_config(struct spi_master *master, struct spi_device *spi, ...@@ -429,25 +491,7 @@ static void img_spfi_config(struct spi_master *master, struct spi_device *spi,
else if (xfer->tx_nbits == SPI_NBITS_QUAD && else if (xfer->tx_nbits == SPI_NBITS_QUAD &&
xfer->rx_nbits == SPI_NBITS_QUAD) xfer->rx_nbits == SPI_NBITS_QUAD)
val |= SPFI_CONTROL_TMODE_QUAD << SPFI_CONTROL_TMODE_SHIFT; val |= SPFI_CONTROL_TMODE_QUAD << SPFI_CONTROL_TMODE_SHIFT;
val &= ~SPFI_CONTROL_CONTINUE;
if (!xfer->cs_change && !list_is_last(&xfer->transfer_list,
&master->cur_msg->transfers))
val |= SPFI_CONTROL_CONTINUE;
spfi_writel(spfi, val, SPFI_CONTROL); spfi_writel(spfi, val, SPFI_CONTROL);
val = spfi_readl(spfi, SPFI_PORT_STATE);
if (spi->mode & SPI_CPHA)
val |= SPFI_PORT_STATE_CK_PHASE(spi->chip_select);
else
val &= ~SPFI_PORT_STATE_CK_PHASE(spi->chip_select);
if (spi->mode & SPI_CPOL)
val |= SPFI_PORT_STATE_CK_POL(spi->chip_select);
else
val &= ~SPFI_PORT_STATE_CK_POL(spi->chip_select);
spfi_writel(spfi, val, SPFI_PORT_STATE);
spfi_writel(spfi, xfer->len << SPFI_TRANSACTION_TSIZE_SHIFT,
SPFI_TRANSACTION);
} }
static int img_spfi_transfer_one(struct spi_master *master, static int img_spfi_transfer_one(struct spi_master *master,
...@@ -455,8 +499,6 @@ static int img_spfi_transfer_one(struct spi_master *master, ...@@ -455,8 +499,6 @@ static int img_spfi_transfer_one(struct spi_master *master,
struct spi_transfer *xfer) struct spi_transfer *xfer)
{ {
struct img_spfi *spfi = spi_master_get_devdata(spi->master); struct img_spfi *spfi = spi_master_get_devdata(spi->master);
bool dma_reset = false;
unsigned long flags;
int ret; int ret;
if (xfer->len > SPFI_TRANSACTION_TSIZE_MASK) { if (xfer->len > SPFI_TRANSACTION_TSIZE_MASK) {
...@@ -466,23 +508,6 @@ static int img_spfi_transfer_one(struct spi_master *master, ...@@ -466,23 +508,6 @@ static int img_spfi_transfer_one(struct spi_master *master,
return -EINVAL; return -EINVAL;
} }
/*
* Stop all DMA and reset the controller if the previous transaction
* timed-out and never completed it's DMA.
*/
spin_lock_irqsave(&spfi->lock, flags);
if (spfi->tx_dma_busy || spfi->rx_dma_busy) {
dev_err(spfi->dev, "SPI DMA still busy\n");
dma_reset = true;
}
spin_unlock_irqrestore(&spfi->lock, flags);
if (dma_reset) {
dmaengine_terminate_all(spfi->tx_ch);
dmaengine_terminate_all(spfi->rx_ch);
spfi_reset(spfi);
}
img_spfi_config(master, spi, xfer); img_spfi_config(master, spi, xfer);
if (master->can_dma && master->can_dma(master, spi, xfer)) if (master->can_dma && master->can_dma(master, spi, xfer))
ret = img_spfi_start_dma(master, spi, xfer); ret = img_spfi_start_dma(master, spi, xfer);
...@@ -492,17 +517,6 @@ static int img_spfi_transfer_one(struct spi_master *master, ...@@ -492,17 +517,6 @@ static int img_spfi_transfer_one(struct spi_master *master,
return ret; return ret;
} }
static void img_spfi_set_cs(struct spi_device *spi, bool enable)
{
struct img_spfi *spfi = spi_master_get_devdata(spi->master);
u32 val;
val = spfi_readl(spfi, SPFI_PORT_STATE);
val &= ~(SPFI_PORT_STATE_DEV_SEL_MASK << SPFI_PORT_STATE_DEV_SEL_SHIFT);
val |= spi->chip_select << SPFI_PORT_STATE_DEV_SEL_SHIFT;
spfi_writel(spfi, val, SPFI_PORT_STATE);
}
static bool img_spfi_can_dma(struct spi_master *master, struct spi_device *spi, static bool img_spfi_can_dma(struct spi_master *master, struct spi_device *spi,
struct spi_transfer *xfer) struct spi_transfer *xfer)
{ {
...@@ -591,14 +605,17 @@ static int img_spfi_probe(struct platform_device *pdev) ...@@ -591,14 +605,17 @@ static int img_spfi_probe(struct platform_device *pdev)
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_DUAL | SPI_RX_DUAL; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_DUAL | SPI_RX_DUAL;
if (of_property_read_bool(spfi->dev->of_node, "img,supports-quad-mode")) if (of_property_read_bool(spfi->dev->of_node, "img,supports-quad-mode"))
master->mode_bits |= SPI_TX_QUAD | SPI_RX_QUAD; master->mode_bits |= SPI_TX_QUAD | SPI_RX_QUAD;
master->num_chipselect = 5;
master->dev.of_node = pdev->dev.of_node; master->dev.of_node = pdev->dev.of_node;
master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(8); master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(8);
master->max_speed_hz = clk_get_rate(spfi->spfi_clk); master->max_speed_hz = clk_get_rate(spfi->spfi_clk) / 4;
master->min_speed_hz = master->max_speed_hz / 512; master->min_speed_hz = clk_get_rate(spfi->spfi_clk) / 512;
master->set_cs = img_spfi_set_cs; master->setup = img_spfi_setup;
master->cleanup = img_spfi_cleanup;
master->transfer_one = img_spfi_transfer_one; master->transfer_one = img_spfi_transfer_one;
master->prepare_message = img_spfi_prepare;
master->unprepare_message = img_spfi_unprepare;
master->handle_err = img_spfi_handle_err;
spfi->tx_ch = dma_request_slave_channel(spfi->dev, "tx"); spfi->tx_ch = dma_request_slave_channel(spfi->dev, "tx");
spfi->rx_ch = dma_request_slave_channel(spfi->dev, "rx"); spfi->rx_ch = dma_request_slave_channel(spfi->dev, "rx");
......
...@@ -370,8 +370,6 @@ static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx, ...@@ -370,8 +370,6 @@ static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx,
if (spi_imx->dma_is_inited) { if (spi_imx->dma_is_inited) {
dma = readl(spi_imx->base + MX51_ECSPI_DMA); dma = readl(spi_imx->base + MX51_ECSPI_DMA);
spi_imx->tx_wml = spi_imx_get_fifosize(spi_imx) / 2;
spi_imx->rx_wml = spi_imx_get_fifosize(spi_imx) / 2;
spi_imx->rxt_wml = spi_imx_get_fifosize(spi_imx) / 2; spi_imx->rxt_wml = spi_imx_get_fifosize(spi_imx) / 2;
rx_wml_cfg = spi_imx->rx_wml << MX51_ECSPI_DMA_RX_WML_OFFSET; rx_wml_cfg = spi_imx->rx_wml << MX51_ECSPI_DMA_RX_WML_OFFSET;
tx_wml_cfg = spi_imx->tx_wml << MX51_ECSPI_DMA_TX_WML_OFFSET; tx_wml_cfg = spi_imx->tx_wml << MX51_ECSPI_DMA_TX_WML_OFFSET;
...@@ -868,6 +866,8 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx, ...@@ -868,6 +866,8 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
master->max_dma_len = MAX_SDMA_BD_BYTES; master->max_dma_len = MAX_SDMA_BD_BYTES;
spi_imx->bitbang.master->flags = SPI_MASTER_MUST_RX | spi_imx->bitbang.master->flags = SPI_MASTER_MUST_RX |
SPI_MASTER_MUST_TX; SPI_MASTER_MUST_TX;
spi_imx->tx_wml = spi_imx_get_fifosize(spi_imx) / 2;
spi_imx->rx_wml = spi_imx_get_fifosize(spi_imx) / 2;
spi_imx->dma_is_inited = 1; spi_imx->dma_is_inited = 1;
return 0; return 0;
...@@ -903,7 +903,7 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx, ...@@ -903,7 +903,7 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
if (tx) { if (tx) {
desc_tx = dmaengine_prep_slave_sg(master->dma_tx, desc_tx = dmaengine_prep_slave_sg(master->dma_tx,
tx->sgl, tx->nents, DMA_TO_DEVICE, tx->sgl, tx->nents, DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK); DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc_tx) if (!desc_tx)
goto no_dma; goto no_dma;
...@@ -915,7 +915,7 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx, ...@@ -915,7 +915,7 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
if (rx) { if (rx) {
desc_rx = dmaengine_prep_slave_sg(master->dma_rx, desc_rx = dmaengine_prep_slave_sg(master->dma_rx,
rx->sgl, rx->nents, DMA_FROM_DEVICE, rx->sgl, rx->nents, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK); DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc_rx) if (!desc_rx)
goto no_dma; goto no_dma;
......
...@@ -588,7 +588,7 @@ static int mpc512x_psc_spi_of_remove(struct platform_device *op) ...@@ -588,7 +588,7 @@ static int mpc512x_psc_spi_of_remove(struct platform_device *op)
return mpc512x_psc_spi_do_remove(&op->dev); return mpc512x_psc_spi_do_remove(&op->dev);
} }
static struct of_device_id mpc512x_psc_spi_of_match[] = { static const struct of_device_id mpc512x_psc_spi_of_match[] = {
{ .compatible = "fsl,mpc5121-psc-spi", }, { .compatible = "fsl,mpc5121-psc-spi", },
{}, {},
}; };
......
...@@ -238,7 +238,7 @@ static int octeon_spi_remove(struct platform_device *pdev) ...@@ -238,7 +238,7 @@ static int octeon_spi_remove(struct platform_device *pdev)
return 0; return 0;
} }
static struct of_device_id octeon_spi_match[] = { static const struct of_device_id octeon_spi_match[] = {
{ .compatible = "cavium,octeon-3010-spi", }, { .compatible = "cavium,octeon-3010-spi", },
{}, {},
}; };
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/io.h> #include <linux/io.h>
...@@ -294,16 +295,6 @@ static int omap1_spi100k_setup(struct spi_device *spi) ...@@ -294,16 +295,6 @@ static int omap1_spi100k_setup(struct spi_device *spi)
return ret; return ret;
} }
static int omap1_spi100k_prepare_hardware(struct spi_master *master)
{
struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
clk_prepare_enable(spi100k->ick);
clk_prepare_enable(spi100k->fck);
return 0;
}
static int omap1_spi100k_transfer_one_message(struct spi_master *master, static int omap1_spi100k_transfer_one_message(struct spi_master *master,
struct spi_message *m) struct spi_message *m)
{ {
...@@ -372,16 +363,6 @@ static int omap1_spi100k_transfer_one_message(struct spi_master *master, ...@@ -372,16 +363,6 @@ static int omap1_spi100k_transfer_one_message(struct spi_master *master,
return status; return status;
} }
static int omap1_spi100k_unprepare_hardware(struct spi_master *master)
{
struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
clk_disable_unprepare(spi100k->ick);
clk_disable_unprepare(spi100k->fck);
return 0;
}
static int omap1_spi100k_probe(struct platform_device *pdev) static int omap1_spi100k_probe(struct platform_device *pdev)
{ {
struct spi_master *master; struct spi_master *master;
...@@ -402,14 +383,12 @@ static int omap1_spi100k_probe(struct platform_device *pdev) ...@@ -402,14 +383,12 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
master->setup = omap1_spi100k_setup; master->setup = omap1_spi100k_setup;
master->transfer_one_message = omap1_spi100k_transfer_one_message; master->transfer_one_message = omap1_spi100k_transfer_one_message;
master->prepare_transfer_hardware = omap1_spi100k_prepare_hardware;
master->unprepare_transfer_hardware = omap1_spi100k_unprepare_hardware;
master->cleanup = NULL;
master->num_chipselect = 2; master->num_chipselect = 2;
master->mode_bits = MODEBITS; master->mode_bits = MODEBITS;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
master->min_speed_hz = OMAP1_SPI100K_MAX_FREQ/(1<<16); master->min_speed_hz = OMAP1_SPI100K_MAX_FREQ/(1<<16);
master->max_speed_hz = OMAP1_SPI100K_MAX_FREQ; master->max_speed_hz = OMAP1_SPI100K_MAX_FREQ;
master->auto_runtime_pm = true;
spi100k = spi_master_get_devdata(master); spi100k = spi_master_get_devdata(master);
...@@ -434,22 +413,96 @@ static int omap1_spi100k_probe(struct platform_device *pdev) ...@@ -434,22 +413,96 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
goto err; goto err;
} }
status = clk_prepare_enable(spi100k->ick);
if (status != 0) {
dev_err(&pdev->dev, "failed to enable ick: %d\n", status);
goto err;
}
status = clk_prepare_enable(spi100k->fck);
if (status != 0) {
dev_err(&pdev->dev, "failed to enable fck: %d\n", status);
goto err_ick;
}
pm_runtime_enable(&pdev->dev);
pm_runtime_set_active(&pdev->dev);
status = devm_spi_register_master(&pdev->dev, master); status = devm_spi_register_master(&pdev->dev, master);
if (status < 0) if (status < 0)
goto err; goto err_fck;
return status; return status;
err_fck:
clk_disable_unprepare(spi100k->fck);
err_ick:
clk_disable_unprepare(spi100k->ick);
err: err:
spi_master_put(master); spi_master_put(master);
return status; return status;
} }
static int omap1_spi100k_remove(struct platform_device *pdev)
{
struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
pm_runtime_disable(&pdev->dev);
clk_disable_unprepare(spi100k->fck);
clk_disable_unprepare(spi100k->ick);
return 0;
}
#ifdef CONFIG_PM
static int omap1_spi100k_runtime_suspend(struct device *dev)
{
struct spi_master *master = spi_master_get(dev_get_drvdata(dev));
struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
clk_disable_unprepare(spi100k->ick);
clk_disable_unprepare(spi100k->fck);
return 0;
}
static int omap1_spi100k_runtime_resume(struct device *dev)
{
struct spi_master *master = spi_master_get(dev_get_drvdata(dev));
struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
int ret;
ret = clk_prepare_enable(spi100k->ick);
if (ret != 0) {
dev_err(dev, "Failed to enable ick: %d\n", ret);
return ret;
}
ret = clk_prepare_enable(spi100k->fck);
if (ret != 0) {
dev_err(dev, "Failed to enable fck: %d\n", ret);
clk_disable_unprepare(spi100k->ick);
return ret;
}
return 0;
}
#endif
static const struct dev_pm_ops omap1_spi100k_pm = {
SET_RUNTIME_PM_OPS(omap1_spi100k_runtime_suspend,
omap1_spi100k_runtime_resume, NULL)
};
static struct platform_driver omap1_spi100k_driver = { static struct platform_driver omap1_spi100k_driver = {
.driver = { .driver = {
.name = "omap1_spi100k", .name = "omap1_spi100k",
.pm = &omap1_spi100k_pm,
}, },
.probe = omap1_spi100k_probe, .probe = omap1_spi100k_probe,
.remove = omap1_spi100k_remove,
}; };
module_platform_driver(omap1_spi100k_driver); module_platform_driver(omap1_spi100k_driver);
......
...@@ -44,7 +44,6 @@ ...@@ -44,7 +44,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/io.h> #include <linux/io.h>
#include <asm/irq.h>
#include <mach/hardware.h> #include <mach/hardware.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
......
...@@ -285,7 +285,12 @@ ...@@ -285,7 +285,12 @@
*/ */
#define DEFAULT_SSP_REG_IMSC 0x0UL #define DEFAULT_SSP_REG_IMSC 0x0UL
#define DISABLE_ALL_INTERRUPTS DEFAULT_SSP_REG_IMSC #define DISABLE_ALL_INTERRUPTS DEFAULT_SSP_REG_IMSC
#define ENABLE_ALL_INTERRUPTS (~DEFAULT_SSP_REG_IMSC) #define ENABLE_ALL_INTERRUPTS ( \
SSP_IMSC_MASK_RORIM | \
SSP_IMSC_MASK_RTIM | \
SSP_IMSC_MASK_RXIM | \
SSP_IMSC_MASK_TXIM \
)
#define CLEAR_ALL_INTERRUPTS 0x3 #define CLEAR_ALL_INTERRUPTS 0x3
...@@ -1251,7 +1256,6 @@ static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id) ...@@ -1251,7 +1256,6 @@ static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id)
struct pl022 *pl022 = dev_id; struct pl022 *pl022 = dev_id;
struct spi_message *msg = pl022->cur_msg; struct spi_message *msg = pl022->cur_msg;
u16 irq_status = 0; u16 irq_status = 0;
u16 flag = 0;
if (unlikely(!msg)) { if (unlikely(!msg)) {
dev_err(&pl022->adev->dev, dev_err(&pl022->adev->dev,
...@@ -1280,9 +1284,6 @@ static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id) ...@@ -1280,9 +1284,6 @@ static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id)
if (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RFF) if (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RFF)
dev_err(&pl022->adev->dev, dev_err(&pl022->adev->dev,
"RXFIFO is full\n"); "RXFIFO is full\n");
if (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_TNF)
dev_err(&pl022->adev->dev,
"TXFIFO is full\n");
/* /*
* Disable and clear interrupts, disable SSP, * Disable and clear interrupts, disable SSP,
...@@ -1303,8 +1304,7 @@ static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id) ...@@ -1303,8 +1304,7 @@ static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id)
readwriter(pl022); readwriter(pl022);
if ((pl022->tx == pl022->tx_end) && (flag == 0)) { if (pl022->tx == pl022->tx_end) {
flag = 1;
/* Disable Transmit interrupt, enable receive interrupt */ /* Disable Transmit interrupt, enable receive interrupt */
writew((readw(SSP_IMSC(pl022->virtbase)) & writew((readw(SSP_IMSC(pl022->virtbase)) &
~SSP_IMSC_MASK_TXIM) | SSP_IMSC_MASK_RXIM, ~SSP_IMSC_MASK_TXIM) | SSP_IMSC_MASK_RXIM,
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/spi/pxa2xx_spi.h> #include <linux/spi/pxa2xx_spi.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
...@@ -30,10 +31,6 @@ ...@@ -30,10 +31,6 @@
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/delay.h>
#include "spi-pxa2xx.h" #include "spi-pxa2xx.h"
MODULE_AUTHOR("Stephen Street"); MODULE_AUTHOR("Stephen Street");
...@@ -67,54 +64,6 @@ MODULE_ALIAS("platform:pxa2xx-spi"); ...@@ -67,54 +64,6 @@ MODULE_ALIAS("platform:pxa2xx-spi");
#define LPSS_TX_LOTHRESH_DFLT 160 #define LPSS_TX_LOTHRESH_DFLT 160
#define LPSS_TX_HITHRESH_DFLT 224 #define LPSS_TX_HITHRESH_DFLT 224
struct quark_spi_rate {
u32 bitrate;
u32 dds_clk_rate;
u32 clk_div;
};
/*
* 'rate', 'dds', 'clk_div' lookup table, which is defined in
* the Quark SPI datasheet.
*/
static const struct quark_spi_rate quark_spi_rate_table[] = {
/* bitrate, dds_clk_rate, clk_div */
{50000000, 0x800000, 0},
{40000000, 0x666666, 0},
{25000000, 0x400000, 0},
{20000000, 0x666666, 1},
{16667000, 0x800000, 2},
{13333000, 0x666666, 2},
{12500000, 0x200000, 0},
{10000000, 0x800000, 4},
{8000000, 0x666666, 4},
{6250000, 0x400000, 3},
{5000000, 0x400000, 4},
{4000000, 0x666666, 9},
{3125000, 0x80000, 0},
{2500000, 0x400000, 9},
{2000000, 0x666666, 19},
{1563000, 0x40000, 0},
{1250000, 0x200000, 9},
{1000000, 0x400000, 24},
{800000, 0x666666, 49},
{781250, 0x20000, 0},
{625000, 0x200000, 19},
{500000, 0x400000, 49},
{400000, 0x666666, 99},
{390625, 0x10000, 0},
{250000, 0x400000, 99},
{200000, 0x666666, 199},
{195313, 0x8000, 0},
{125000, 0x100000, 49},
{100000, 0x200000, 124},
{50000, 0x100000, 124},
{25000, 0x80000, 124},
{10016, 0x20000, 77},
{5040, 0x20000, 154},
{1002, 0x8000, 194},
};
/* Offset from drv_data->lpss_base */ /* Offset from drv_data->lpss_base */
#define GENERAL_REG 0x08 #define GENERAL_REG 0x08
#define GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24) #define GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24)
...@@ -701,25 +650,124 @@ static irqreturn_t ssp_int(int irq, void *dev_id) ...@@ -701,25 +650,124 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
} }
/* /*
* The Quark SPI data sheet gives a table, and for the given 'rate', * The Quark SPI has an additional 24 bit register (DDS_CLK_RATE) to multiply
* the 'dds' and 'clk_div' can be found in the table. * input frequency by fractions of 2^24. It also has a divider by 5.
*
* There are formulas to get baud rate value for given input frequency and
* divider parameters, such as DDS_CLK_RATE and SCR:
*
* Fsys = 200MHz
*
* Fssp = Fsys * DDS_CLK_RATE / 2^24 (1)
* Baud rate = Fsclk = Fssp / (2 * (SCR + 1)) (2)
*
* DDS_CLK_RATE either 2^n or 2^n / 5.
* SCR is in range 0 .. 255
*
* Divisor = 5^i * 2^j * 2 * k
* i = [0, 1] i = 1 iff j = 0 or j > 3
* j = [0, 23] j = 0 iff i = 1
* k = [1, 256]
* Special case: j = 0, i = 1: Divisor = 2 / 5
*
* Accordingly to the specification the recommended values for DDS_CLK_RATE
* are:
* Case 1: 2^n, n = [0, 23]
* Case 2: 2^24 * 2 / 5 (0x666666)
* Case 3: less than or equal to 2^24 / 5 / 16 (0x33333)
*
* In all cases the lowest possible value is better.
*
* The function calculates parameters for all cases and chooses the one closest
* to the asked baud rate.
*/ */
static u32 quark_x1000_set_clk_regvals(u32 rate, u32 *dds, u32 *clk_div) static unsigned int quark_x1000_get_clk_div(int rate, u32 *dds)
{ {
unsigned int i; unsigned long xtal = 200000000;
unsigned long fref = xtal / 2; /* mandatory division by 2,
see (2) */
/* case 3 */
unsigned long fref1 = fref / 2; /* case 1 */
unsigned long fref2 = fref * 2 / 5; /* case 2 */
unsigned long scale;
unsigned long q, q1, q2;
long r, r1, r2;
u32 mul;
/* Case 1 */
/* Set initial value for DDS_CLK_RATE */
mul = (1 << 24) >> 1;
/* Calculate initial quot */
q1 = DIV_ROUND_CLOSEST(fref1, rate);
/* Scale q1 if it's too big */
if (q1 > 256) {
/* Scale q1 to range [1, 512] */
scale = fls_long(q1 - 1);
if (scale > 9) {
q1 >>= scale - 9;
mul >>= scale - 9;
}
for (i = 0; i < ARRAY_SIZE(quark_spi_rate_table); i++) { /* Round the result if we have a remainder */
if (rate >= quark_spi_rate_table[i].bitrate) { q1 += q1 & 1;
*dds = quark_spi_rate_table[i].dds_clk_rate;
*clk_div = quark_spi_rate_table[i].clk_div;
return quark_spi_rate_table[i].bitrate;
} }
/* Decrease DDS_CLK_RATE as much as we can without loss in precision */
scale = __ffs(q1);
q1 >>= scale;
mul >>= scale;
/* Get the remainder */
r1 = abs(fref1 / (1 << (24 - fls_long(mul))) / q1 - rate);
/* Case 2 */
q2 = DIV_ROUND_CLOSEST(fref2, rate);
r2 = abs(fref2 / q2 - rate);
/*
* Choose the best between two: less remainder we have the better. We
* can't go case 2 if q2 is greater than 256 since SCR register can
* hold only values 0 .. 255.
*/
if (r2 >= r1 || q2 > 256) {
/* case 1 is better */
r = r1;
q = q1;
} else {
/* case 2 is better */
r = r2;
q = q2;
mul = (1 << 24) * 2 / 5;
} }
*dds = quark_spi_rate_table[i-1].dds_clk_rate; /* Check case 3 only If the divisor is big enough */
*clk_div = quark_spi_rate_table[i-1].clk_div; if (fref / rate >= 80) {
u64 fssp;
u32 m;
/* Calculate initial quot */
q1 = DIV_ROUND_CLOSEST(fref, rate);
m = (1 << 24) / q1;
return quark_spi_rate_table[i-1].bitrate; /* Get the remainder */
fssp = (u64)fref * m;
do_div(fssp, 1 << 24);
r1 = abs(fssp - rate);
/* Choose this one if it suits better */
if (r1 < r) {
/* case 3 is better */
q = 1;
mul = m;
}
}
*dds = mul;
return q - 1;
} }
static unsigned int ssp_get_clk_div(struct driver_data *drv_data, int rate) static unsigned int ssp_get_clk_div(struct driver_data *drv_data, int rate)
...@@ -730,23 +778,25 @@ static unsigned int ssp_get_clk_div(struct driver_data *drv_data, int rate) ...@@ -730,23 +778,25 @@ static unsigned int ssp_get_clk_div(struct driver_data *drv_data, int rate)
rate = min_t(int, ssp_clk, rate); rate = min_t(int, ssp_clk, rate);
if (ssp->type == PXA25x_SSP || ssp->type == CE4100_SSP) if (ssp->type == PXA25x_SSP || ssp->type == CE4100_SSP)
return ((ssp_clk / (2 * rate) - 1) & 0xff) << 8; return (ssp_clk / (2 * rate) - 1) & 0xff;
else else
return ((ssp_clk / rate - 1) & 0xfff) << 8; return (ssp_clk / rate - 1) & 0xfff;
} }
static unsigned int pxa2xx_ssp_get_clk_div(struct driver_data *drv_data, static unsigned int pxa2xx_ssp_get_clk_div(struct driver_data *drv_data,
struct chip_data *chip, int rate) struct chip_data *chip, int rate)
{ {
u32 clk_div; unsigned int clk_div;
switch (drv_data->ssp_type) { switch (drv_data->ssp_type) {
case QUARK_X1000_SSP: case QUARK_X1000_SSP:
quark_x1000_set_clk_regvals(rate, &chip->dds_rate, &clk_div); clk_div = quark_x1000_get_clk_div(rate, &chip->dds_rate);
return clk_div << 8; break;
default: default:
return ssp_get_clk_div(drv_data, rate); clk_div = ssp_get_clk_div(drv_data, rate);
break;
} }
return clk_div << 8;
} }
static void pump_transfers(unsigned long data) static void pump_transfers(unsigned long data)
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -286,7 +286,7 @@ static int sc18is602_probe(struct i2c_client *client, ...@@ -286,7 +286,7 @@ static int sc18is602_probe(struct i2c_client *client,
hw->freq = SC18IS602_CLOCK; hw->freq = SC18IS602_CLOCK;
break; break;
} }
master->bus_num = client->adapter->nr; master->bus_num = np ? -1 : client->adapter->nr;
master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST; master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST;
master->bits_per_word_mask = SPI_BPW_MASK(8); master->bits_per_word_mask = SPI_BPW_MASK(8);
master->setup = sc18is602_setup; master->setup = sc18is602_setup;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment