A busy release for both cleanups and new drivers this time along with
 further factoring out of replicated code into the core:
 
  - Provide support in the core for DMA mapping transfers - essentially
    all drivers weren't implementing this properly, now there's no
    excuse.
  - Dual and quad mode support for spidev.
  - Fix handling of cs_change in the generic implementation.
  - Remove the S3C_DMA code from the s3c64xx driver now that all the
    platforms using it have been converted to dmaengine.
  - Lots of improvements to the Renesas SPI controllers.
  - Drivers for Allwinner A10 and A31, Qualcomm QUP and Xylinx xtfpga.
  - Removal of the bitrotted ti-ssp driver.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJTOUttAAoJELSic+t+oim9NqMQAI3zR6K5e7o/GJhxWMOBDkdo
 hN0ZSt6NEYGHQqXZ0kR0Azj7I3PO/Bj0US2gYx1myfggV/++rZwgGI97fsF9dBoN
 IbOm+xBx5nmMkr0/oxZD/ETbM74iVm7xM274OKHLD1spiozqwGNV4voEvt/JVQ8W
 ux+8SFa8HC0GoDqm6Ha51RstiBGFpuvKYUpeRmSEvsRl9DpyHhnQeZg/gwiQm/ON
 n74twLTXTIBO7oVxTpffsZgRPfvZtIcNmwwL+gyYBrjb5DZ1+qCTPGYx0/R18wfr
 NrXIYv8Ka6qbDiwWhmf6m5qrNsYNq95t2J6ulxor1LVcAIZODBpcEfdQ51fwYd3f
 +xZuCTzPRZ2w8Mha2II6LvOjk0640MBa/nQnOEup8dTWX0jARPKnKcjb84tuhlna
 ZGolHABLUhzZIAQjkZjbVSw0HL6lAQ/mk8sZevcCmB2zCln+HneeFCVCEWjy+i2I
 zejhFJMT3/MqLqZNav+MzkkYB1aW3q/RQz7OwzwPK7Rlw0IRwd64c0D9r9Qj2/Gl
 uWVOnLmgDwKgeq7464kA4ELPTW0i9gG7SIQe18xzkL2SY9wzQN0S1ERx3aDCCAw2
 lyuh/Cdz7nnCyDBmuqNUfvp8XAX1d0d12vTbHcW1VHMw68fE4OBVNxn4jUXHZt5O
 OmOoox/sn/1I+Ce30C70
 =qoZY
 -----END PGP SIGNATURE-----

Merge tag 'spi-v3.15' into spi-linus

spi: Updates for v3.15

A busy release for both cleanups and new drivers this time along with
further factoring out of replicated code into the core:

 - Provide support in the core for DMA mapping transfers - essentially
   all drivers weren't implementing this properly, now there's no
   excuse.
 - Dual and quad mode support for spidev.
 - Fix handling of cs_change in the generic implementation.
 - Remove the S3C_DMA code from the s3c64xx driver now that all the
   platforms using it have been converted to dmaengine.
 - Lots of improvements to the Renesas SPI controllers.
 - Drivers for Allwinner A10 and A31, Qualcomm QUP and Xylinx xtfpga.
 - Removal of the bitrotted ti-ssp driver.

# gpg: Signature made Mon 31 Mar 2014 12:03:09 BST using RSA key ID 7EA229BD
# gpg: Good signature from "Mark Brown <broonie@sirena.org.uk>"
# gpg:                 aka "Mark Brown <broonie@debian.org>"
# gpg:                 aka "Mark Brown <broonie@kernel.org>"
# gpg:                 aka "Mark Brown <broonie@tardis.ed.ac.uk>"
# gpg:                 aka "Mark Brown <broonie@linaro.org>"
# gpg:                 aka "Mark Brown <Mark.Brown@linaro.org>"
This commit is contained in:
Mark Brown 2014-04-10 23:39:52 +01:00
Родитель 455c6fdbd2 45b15d98a9
Коммит 09c0998efc
87 изменённых файлов: 4138 добавлений и 2307 удалений

Просмотреть файл

@ -3,24 +3,24 @@
Required properties:
- #address-cells: see spi-bus.txt
- #size-cells: see spi-bus.txt
- compatible: should be "efm32,spi"
- compatible: should be "energymicro,efm32-spi"
- reg: Offset and length of the register set for the controller
- interrupts: pair specifying rx and tx irq
- clocks: phandle to the spi clock
- cs-gpios: see spi-bus.txt
- location: Value to write to the ROUTE register's LOCATION bitfield to configure the pinmux for the device, see datasheet for values.
- efm32,location: Value to write to the ROUTE register's LOCATION bitfield to configure the pinmux for the device, see datasheet for values.
Example:
spi1: spi@0x4000c400 { /* USART1 */
#address-cells = <1>;
#size-cells = <0>;
compatible = "efm32,spi";
compatible = "energymicro,efm32-spi";
reg = <0x4000c400 0x400>;
interrupts = <15 16>;
clocks = <&cmu 20>;
cs-gpios = <&gpio 51 1>; // D3
location = <1>;
efm32,location = <1>;
status = "ok";
ks8851@0 {

Просмотреть файл

@ -0,0 +1,85 @@
Qualcomm Universal Peripheral (QUP) Serial Peripheral Interface (SPI)
The QUP core is an AHB slave that provides a common data path (an output FIFO
and an input FIFO) for serial peripheral interface (SPI) mini-core.
SPI in master mode supports up to 50MHz, up to four chip selects, programmable
data path from 4 bits to 32 bits and numerous protocol variants.
Required properties:
- compatible: Should contain "qcom,spi-qup-v2.1.1" or "qcom,spi-qup-v2.2.1"
- reg: Should contain base register location and length
- interrupts: Interrupt number used by this controller
- clocks: Should contain the core clock and the AHB clock.
- clock-names: Should be "core" for the core clock and "iface" for the
AHB clock.
- #address-cells: Number of cells required to define a chip select
address on the SPI bus. Should be set to 1.
- #size-cells: Should be zero.
Optional properties:
- spi-max-frequency: Specifies maximum SPI clock frequency,
Units - Hz. Definition as per
Documentation/devicetree/bindings/spi/spi-bus.txt
SPI slave nodes must be children of the SPI master node and can contain
properties described in Documentation/devicetree/bindings/spi/spi-bus.txt
Example:
spi_8: spi@f9964000 { /* BLSP2 QUP2 */
compatible = "qcom,spi-qup-v2";
#address-cells = <1>;
#size-cells = <0>;
reg = <0xf9964000 0x1000>;
interrupts = <0 102 0>;
spi-max-frequency = <19200000>;
clocks = <&gcc GCC_BLSP2_QUP2_SPI_APPS_CLK>, <&gcc GCC_BLSP2_AHB_CLK>;
clock-names = "core", "iface";
pinctrl-names = "default";
pinctrl-0 = <&spi8_default>;
device@0 {
compatible = "arm,pl022-dummy";
#address-cells = <1>;
#size-cells = <1>;
reg = <0>; /* Chip select 0 */
spi-max-frequency = <19200000>;
spi-cpol;
};
device@1 {
compatible = "arm,pl022-dummy";
#address-cells = <1>;
#size-cells = <1>;
reg = <1>; /* Chip select 1 */
spi-max-frequency = <9600000>;
spi-cpha;
};
device@2 {
compatible = "arm,pl022-dummy";
#address-cells = <1>;
#size-cells = <1>;
reg = <2>; /* Chip select 2 */
spi-max-frequency = <19200000>;
spi-cpol;
spi-cpha;
};
device@3 {
compatible = "arm,pl022-dummy";
#address-cells = <1>;
#size-cells = <1>;
reg = <3>; /* Chip select 3 */
spi-max-frequency = <19200000>;
spi-cpol;
spi-cpha;
spi-cs-high;
};
};

Просмотреть файл

@ -1,7 +1,29 @@
Renesas HSPI.
Required properties:
- compatible : "renesas,hspi"
- reg : Offset and length of the register set for the device
- interrupts : interrupt line used by HSPI
- compatible : "renesas,hspi-<soctype>", "renesas,hspi" as fallback.
Examples with soctypes are:
- "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";
};

Просмотреть файл

@ -1,12 +1,40 @@
Renesas MSIOF spi controller
Required properties:
- compatible : "renesas,sh-msiof" for SuperH or
"renesas,sh-mobile-msiof" for SH Mobile series
- reg : Offset and length of the register set for the device
- interrupts : interrupt line used by MSIOF
- compatible : "renesas,msiof-<soctype>" for SoCs,
"renesas,sh-msiof" for SuperH, or
"renesas,sh-mobile-msiof" for SH Mobile series.
Examples with soctypes are:
"renesas,msiof-r8a7790" (R-Car H2)
"renesas,msiof-r8a7791" (R-Car M2)
- reg : Offset and length of the register set for the device
- 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:
- num-cs : total number of chip-selects
- renesas,tx-fifo-size : Overrides the default tx fifo size given in words
- renesas,rx-fifo-size : Overrides the default rx fifo size given in words
- clocks : Must contain a reference to the functional clock.
- num-cs : Total number of chip-selects (default is 1)
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";
};

Просмотреть файл

@ -10,6 +10,7 @@ Required properties:
- pinctrl-names: must contain a "default" entry.
- spi-num-chipselects : the number of the chipselect signals.
- bus-num : the slave chip chipselect signal number.
- big-endian : if DSPI modudle is big endian, the bool will be set in node.
Example:
dspi0@4002c000 {
@ -24,6 +25,7 @@ dspi0@4002c000 {
bus-num = <0>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_dspi0_1>;
big-endian;
status = "okay";
sflash: at26df081a@0 {

Просмотреть файл

@ -0,0 +1,61 @@
Device tree configuration for Renesas RSPI/QSPI driver
Required properties:
- compatible : For Renesas Serial Peripheral Interface on legacy SH:
"renesas,rspi-<soctype>", "renesas,rspi" as fallback.
For Renesas Serial Peripheral Interface on RZ/A1H:
"renesas,rspi-<soctype>", "renesas,rspi-rz" as fallback.
For Quad Serial Peripheral Interface on R-Car Gen2:
"renesas,qspi-<soctype>", "renesas,qspi" as fallback.
Examples with soctypes are:
- "renesas,rspi-sh7757" (SH)
- "renesas,rspi-r7s72100" (RZ/A1H)
- "renesas,qspi-r8a7790" (R-Car H2)
- "renesas,qspi-r8a7791" (R-Car M2)
- reg : Address start and address range size of the device
- interrupts : A list of interrupt-specifiers, one for each entry in
interrupt-names.
If interrupt-names is not present, an interrupt specifier
for a single muxed interrupt.
- interrupt-names : A list of interrupt names. Should contain (if present):
- "error" for SPEI,
- "rx" for SPRI,
- "tx" to SPTI,
- "mux" for a single muxed interrupt.
- interrupt-parent : The phandle for the interrupt controller that
services interrupts for this device.
- num-cs : Number of chip selects. Some RSPI cores have more than 1.
- #address-cells : Must be <1>
- #size-cells : Must be <0>
Optional properties:
- clocks : Must contain a reference to the functional clock.
Pinctrl properties might be needed, too. See
Documentation/devicetree/bindings/pinctrl/renesas,*.
Examples:
spi0: spi@e800c800 {
compatible = "renesas,rspi-r7s72100", "renesas,rspi-rz";
reg = <0xe800c800 0x24>;
interrupts = <0 238 IRQ_TYPE_LEVEL_HIGH>,
<0 239 IRQ_TYPE_LEVEL_HIGH>,
<0 240 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "error", "rx", "tx";
interrupt-parent = <&gic>;
num-cs = <1>;
#address-cells = <1>;
#size-cells = <0>;
};
spi: spi@e6b10000 {
compatible = "renesas,qspi-r8a7791", "renesas,qspi";
reg = <0 0xe6b10000 0 0x2c>;
interrupt-parent = <&gic>;
interrupts = <0 184 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp9_clks R8A7791_CLK_QSPI_MOD>;
num-cs = <1>;
#address-cells = <1>;
#size-cells = <0>;
};

Просмотреть файл

@ -0,0 +1,24 @@
Allwinner A10 SPI controller
Required properties:
- compatible: Should be "allwinner,sun4-a10-spi".
- reg: Should contain register location and length.
- interrupts: Should contain interrupt.
- clocks: phandle to the clocks feeding the SPI controller. Two are
needed:
- "ahb": the gated AHB parent clock
- "mod": the parent module clock
- clock-names: Must contain the clock names described just above
Example:
spi1: spi@01c06000 {
compatible = "allwinner,sun4i-a10-spi";
reg = <0x01c06000 0x1000>;
interrupts = <11>;
clocks = <&ahb_gates 21>, <&spi1_clk>;
clock-names = "ahb", "mod";
status = "disabled";
#address-cells = <1>;
#size-cells = <0>;
};

Просмотреть файл

@ -0,0 +1,24 @@
Allwinner A31 SPI controller
Required properties:
- compatible: Should be "allwinner,sun6i-a31-spi".
- reg: Should contain register location and length.
- interrupts: Should contain interrupt.
- clocks: phandle to the clocks feeding the SPI controller. Two are
needed:
- "ahb": the gated AHB parent clock
- "mod": the parent module clock
- clock-names: Must contain the clock names described just above
- resets: phandle to the reset controller asserting this device in
reset
Example:
spi1: spi@01c69000 {
compatible = "allwinner,sun6i-a31-spi";
reg = <0x01c69000 0x1000>;
interrupts = <0 66 4>;
clocks = <&ahb1_gates 21>, <&spi1_clk>;
clock-names = "ahb", "mod";
resets = <&ahb1_rst 21>;
};

Просмотреть файл

@ -0,0 +1,9 @@
Cadence Xtensa XTFPGA platform SPI controller.
This simple SPI master controller is built into xtfpga bitstreams and is used
to control daughterboard audio codec.
Required properties:
- compatible: should be "cdns,xtfpga-spi".
- reg: physical base address of the controller and length of memory mapped
region.

Просмотреть файл

@ -85,6 +85,12 @@ settings for data transfer parameters:
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,
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
which will return (RD) or assign (WR) the bit justification used to

Просмотреть файл

@ -78,10 +78,10 @@ static void do_msg(int fd, int len)
static void dumpstat(const char *name, int fd)
{
__u8 mode, lsb, bits;
__u32 speed;
__u8 lsb, bits;
__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");
return;
}
@ -98,7 +98,7 @@ static void dumpstat(const char *name, int fd)
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);
}

Просмотреть файл

@ -30,7 +30,7 @@ static void pabort(const char *s)
}
static const char *device = "/dev/spidev1.1";
static uint8_t mode;
static uint32_t mode;
static uint8_t bits = 8;
static uint32_t speed = 500000;
static uint16_t delay;
@ -57,6 +57,21 @@ static void transfer(int fd)
.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);
if (ret < 1)
pabort("can't send spi message");
@ -81,7 +96,11 @@ static void print_usage(const char *prog)
" -O --cpol clock polarity\n"
" -L --lsb least significant bit first\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);
}
@ -101,11 +120,13 @@ static void parse_opts(int argc, char *argv[])
{ "3wire", 0, 0, '3' },
{ "no-cs", 0, 0, 'N' },
{ "ready", 0, 0, 'R' },
{ "dual", 0, 0, '2' },
{ "quad", 0, 0, '4' },
{ NULL, 0, 0, 0 },
};
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)
break;
@ -147,11 +168,23 @@ static void parse_opts(int argc, char *argv[])
case 'R':
mode |= SPI_READY;
break;
case '2':
mode |= SPI_TX_DUAL;
break;
case '4':
mode |= SPI_TX_QUAD;
break;
default:
print_usage(argv[0]);
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[])
@ -168,11 +201,11 @@ int main(int argc, char *argv[])
/*
* spi mode
*/
ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode);
if (ret == -1)
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)
pabort("can't get spi mode");
@ -198,7 +231,7 @@ int main(int argc, char *argv[])
if (ret == -1)
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("max speed: %d Hz (%d KHz)\n", speed, speed/1000);

Просмотреть файл

@ -9783,6 +9783,12 @@ L: linux-serial@vger.kernel.org
S: Maintained
F: drivers/tty/serial/uartlite.c
XTENSA XTFPGA PLATFORM SUPPORT
M: Max Filippov <jcmvbkbc@gmail.com>
L: linux-xtensa@linux-xtensa.org
S: Maintained
F: drivers/spi/spi-xtensa-xtfpga.c
YAM DRIVER FOR AX.25
M: Jean-Paul Roubelat <jpr@f6fbb.org>
L: linux-hams@vger.kernel.org

Просмотреть файл

@ -1,6 +1,5 @@
obj-$(CONFIG_PM) += sysfs.o generic_ops.o common.o qos.o
obj-$(CONFIG_PM) += sysfs.o generic_ops.o common.o qos.o runtime.o
obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o
obj-$(CONFIG_PM_RUNTIME) += runtime.o
obj-$(CONFIG_PM_TRACE_RTC) += trace.o
obj-$(CONFIG_PM_OPP) += opp.o
obj-$(CONFIG_PM_GENERIC_DOMAINS) += domain.o domain_governor.o

Просмотреть файл

@ -13,6 +13,43 @@
#include <trace/events/rpm.h>
#include "power.h"
#define RPM_GET_CALLBACK(dev, cb) \
({ \
int (*__rpm_cb)(struct device *__d); \
\
if (dev->pm_domain) \
__rpm_cb = dev->pm_domain->ops.cb; \
else if (dev->type && dev->type->pm) \
__rpm_cb = dev->type->pm->cb; \
else if (dev->class && dev->class->pm) \
__rpm_cb = dev->class->pm->cb; \
else if (dev->bus && dev->bus->pm) \
__rpm_cb = dev->bus->pm->cb; \
else \
__rpm_cb = NULL; \
\
if (!__rpm_cb && dev->driver && dev->driver->pm) \
__rpm_cb = dev->driver->pm->cb; \
\
__rpm_cb; \
})
static int (*rpm_get_suspend_cb(struct device *dev))(struct device *)
{
return RPM_GET_CALLBACK(dev, runtime_suspend);
}
static int (*rpm_get_resume_cb(struct device *dev))(struct device *)
{
return RPM_GET_CALLBACK(dev, runtime_resume);
}
#ifdef CONFIG_PM_RUNTIME
static int (*rpm_get_idle_cb(struct device *dev))(struct device *)
{
return RPM_GET_CALLBACK(dev, runtime_idle);
}
static int rpm_resume(struct device *dev, int rpmflags);
static int rpm_suspend(struct device *dev, int rpmflags);
@ -310,19 +347,7 @@ static int rpm_idle(struct device *dev, int rpmflags)
dev->power.idle_notification = true;
if (dev->pm_domain)
callback = dev->pm_domain->ops.runtime_idle;
else if (dev->type && dev->type->pm)
callback = dev->type->pm->runtime_idle;
else if (dev->class && dev->class->pm)
callback = dev->class->pm->runtime_idle;
else if (dev->bus && dev->bus->pm)
callback = dev->bus->pm->runtime_idle;
else
callback = NULL;
if (!callback && dev->driver && dev->driver->pm)
callback = dev->driver->pm->runtime_idle;
callback = rpm_get_idle_cb(dev);
if (callback)
retval = __rpm_callback(callback, dev);
@ -492,19 +517,7 @@ static int rpm_suspend(struct device *dev, int rpmflags)
__update_runtime_status(dev, RPM_SUSPENDING);
if (dev->pm_domain)
callback = dev->pm_domain->ops.runtime_suspend;
else if (dev->type && dev->type->pm)
callback = dev->type->pm->runtime_suspend;
else if (dev->class && dev->class->pm)
callback = dev->class->pm->runtime_suspend;
else if (dev->bus && dev->bus->pm)
callback = dev->bus->pm->runtime_suspend;
else
callback = NULL;
if (!callback && dev->driver && dev->driver->pm)
callback = dev->driver->pm->runtime_suspend;
callback = rpm_get_suspend_cb(dev);
retval = rpm_callback(callback, dev);
if (retval)
@ -724,19 +737,7 @@ static int rpm_resume(struct device *dev, int rpmflags)
__update_runtime_status(dev, RPM_RESUMING);
if (dev->pm_domain)
callback = dev->pm_domain->ops.runtime_resume;
else if (dev->type && dev->type->pm)
callback = dev->type->pm->runtime_resume;
else if (dev->class && dev->class->pm)
callback = dev->class->pm->runtime_resume;
else if (dev->bus && dev->bus->pm)
callback = dev->bus->pm->runtime_resume;
else
callback = NULL;
if (!callback && dev->driver && dev->driver->pm)
callback = dev->driver->pm->runtime_resume;
callback = rpm_get_resume_cb(dev);
retval = rpm_callback(callback, dev);
if (retval) {
@ -1401,3 +1402,86 @@ void pm_runtime_remove(struct device *dev)
if (dev->power.irq_safe && dev->parent)
pm_runtime_put(dev->parent);
}
#endif
/**
* pm_runtime_force_suspend - Force a device into suspend state if needed.
* @dev: Device to suspend.
*
* Disable runtime PM so we safely can check the device's runtime PM status and
* if it is active, invoke it's .runtime_suspend callback to bring it into
* suspend state. Keep runtime PM disabled to preserve the state unless we
* encounter errors.
*
* Typically this function may be invoked from a system suspend callback to make
* sure the device is put into low power state.
*/
int pm_runtime_force_suspend(struct device *dev)
{
int (*callback)(struct device *);
int ret = 0;
pm_runtime_disable(dev);
/*
* Note that pm_runtime_status_suspended() returns false while
* !CONFIG_PM_RUNTIME, which means the device will be put into low
* power state.
*/
if (pm_runtime_status_suspended(dev))
return 0;
callback = rpm_get_suspend_cb(dev);
if (!callback) {
ret = -ENOSYS;
goto err;
}
ret = callback(dev);
if (ret)
goto err;
pm_runtime_set_suspended(dev);
return 0;
err:
pm_runtime_enable(dev);
return ret;
}
EXPORT_SYMBOL_GPL(pm_runtime_force_suspend);
/**
* pm_runtime_force_resume - Force a device into resume state.
* @dev: Device to resume.
*
* Prior invoking this function we expect the user to have brought the device
* into low power state by a call to pm_runtime_force_suspend(). Here we reverse
* those actions and brings the device into full power. We update the runtime PM
* status and re-enables runtime PM.
*
* Typically this function may be invoked from a system resume callback to make
* sure the device is put into full power state.
*/
int pm_runtime_force_resume(struct device *dev)
{
int (*callback)(struct device *);
int ret = 0;
callback = rpm_get_resume_cb(dev);
if (!callback) {
ret = -ENOSYS;
goto out;
}
ret = callback(dev);
if (ret)
goto out;
pm_runtime_set_active(dev);
pm_runtime_mark_last_busy(dev);
out:
pm_runtime_enable(dev);
return ret;
}
EXPORT_SYMBOL_GPL(pm_runtime_force_resume);

Просмотреть файл

@ -150,7 +150,7 @@ config SPI_BUTTERFLY
config SPI_CLPS711X
tristate "CLPS711X host SPI controller"
depends on ARCH_CLPS711X
depends on ARCH_CLPS711X || COMPILE_TEST
help
This enables dedicated general purpose SPI/Microwire1-compatible
master mode interface (SSI1) for CLPS711X-based CPUs.
@ -212,7 +212,6 @@ config SPI_IMX
tristate "Freescale i.MX SPI controllers"
depends on ARCH_MXC || COMPILE_TEST
select SPI_BITBANG
default m if IMX_HAVE_PLATFORM_SPI_IMX
help
This enables using the Freescale i.MX SPI controllers in master
mode.
@ -270,6 +269,7 @@ config SPI_FSL_SPI
config SPI_FSL_DSPI
tristate "Freescale DSPI controller"
select SPI_BITBANG
select REGMAP_MMIO
depends on SOC_VF610 || COMPILE_TEST
help
This enables support for the Freescale DSPI controller in master
@ -307,7 +307,7 @@ config SPI_OMAP_UWIRE
config SPI_OMAP24XX
tristate "McSPI driver for OMAP"
depends on ARM || ARM64 || AVR32 || HEXAGON || MIPS || SH
depends on ARM || ARM64 || AVR32 || HEXAGON || MIPS || SUPERH
depends on ARCH_OMAP2PLUS || COMPILE_TEST
help
SPI master controller for OMAP24XX and later Multichannel SPI
@ -381,6 +381,19 @@ config SPI_RSPI
help
SPI driver for Renesas RSPI and QSPI blocks.
config SPI_QUP
tristate "Qualcomm SPI controller with QUP interface"
depends on ARCH_MSM_DT || (ARM && COMPILE_TEST)
help
Qualcomm Universal Peripheral (QUP) core is an AHB slave that
provides a common data path (an output FIFO and an input FIFO)
for serial peripheral interface (SPI) mini-core. SPI in master
mode supports up to 50MHz, up to four chip selects, programmable
data path from 4 bits to 32 bits and numerous protocol variants.
This driver can also be built as a module. If so, the module
will be called spi_qup.
config SPI_S3C24XX
tristate "Samsung S3C24XX series SPI"
depends on ARCH_S3C24XX
@ -416,7 +429,6 @@ config SPI_SH_MSIOF
tristate "SuperH MSIOF SPI controller"
depends on HAVE_CLK
depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
select SPI_BITBANG
help
SPI driver for SuperH and SH Mobile MSIOF blocks.
@ -446,6 +458,19 @@ config SPI_SIRF
help
SPI driver for CSR SiRFprimaII SoCs
config SPI_SUN4I
tristate "Allwinner A10 SoCs SPI controller"
depends on ARCH_SUNXI || COMPILE_TEST
help
SPI driver for Allwinner sun4i, sun5i and sun7i SoCs
config SPI_SUN6I
tristate "Allwinner A31 SPI controller"
depends on ARCH_SUNXI || COMPILE_TEST
depends on RESET_CONTROLLER
help
This enables using the SPI controller on the Allwinner A31 SoCs.
config SPI_MXS
tristate "Freescale MXS SPI controller"
depends on ARCH_MXS
@ -478,13 +503,6 @@ config SPI_TEGRA20_SLINK
help
SPI driver for Nvidia Tegra20/Tegra30 SLINK Controller interface.
config SPI_TI_SSP
tristate "TI Sequencer Serial Port - SPI Support"
depends on MFD_TI_SSP
help
This selects an SPI master implementation using a TI sequencer
serial port.
config SPI_TOPCLIFF_PCH
tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) SPI"
depends on PCI
@ -520,6 +538,19 @@ config SPI_XILINX
Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.00b)"
config SPI_XTENSA_XTFPGA
tristate "Xtensa SPI controller for xtfpga"
depends on (XTENSA && XTENSA_PLATFORM_XTFPGA) || COMPILE_TEST
select SPI_BITBANG
help
SPI driver for xtfpga SPI master controller.
This simple SPI master controller is built into xtfpga bitstreams
and is used to control daughterboard audio codec. It always transfers
16 bit words in SPI mode 0, automatically asserting CS on transfer
start and deasserting on end.
config SPI_NUC900
tristate "Nuvoton NUC900 series SPI"
depends on ARCH_W90X900
@ -546,7 +577,7 @@ config SPI_DW_MID_DMA
config SPI_DW_MMIO
tristate "Memory-mapped io interface driver for DW SPI core"
depends on SPI_DESIGNWARE && HAVE_CLK
depends on SPI_DESIGNWARE
#
# There are lots of SPI device types, with sensors and memory

Просмотреть файл

@ -59,6 +59,7 @@ spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_PXADMA) += spi-pxa2xx-pxadma.o
spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_DMA) += spi-pxa2xx-dma.o
obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-platform.o
obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o
obj-$(CONFIG_SPI_QUP) += spi-qup.o
obj-$(CONFIG_SPI_RSPI) += spi-rspi.o
obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o
spi-s3c24xx-hw-y := spi-s3c24xx.o
@ -70,12 +71,14 @@ obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o
obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o
obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o
obj-$(CONFIG_SPI_SIRF) += spi-sirf.o
obj-$(CONFIG_SPI_SUN4I) += spi-sun4i.o
obj-$(CONFIG_SPI_SUN6I) += spi-sun6i.o
obj-$(CONFIG_SPI_TEGRA114) += spi-tegra114.o
obj-$(CONFIG_SPI_TEGRA20_SFLASH) += spi-tegra20-sflash.o
obj-$(CONFIG_SPI_TEGRA20_SLINK) += spi-tegra20-slink.o
obj-$(CONFIG_SPI_TI_SSP) += spi-ti-ssp.o
obj-$(CONFIG_SPI_TLE62X0) += spi-tle62x0.o
obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o
obj-$(CONFIG_SPI_TXX9) += spi-txx9.o
obj-$(CONFIG_SPI_XCOMM) += spi-xcomm.o
obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o
obj-$(CONFIG_SPI_XTENSA_XTFPGA) += spi-xtensa-xtfpga.o

Просмотреть файл

@ -13,7 +13,6 @@
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/errno.h>
#include <linux/module.h>
@ -200,7 +199,6 @@ static irqreturn_t altera_spi_irq(int irq, void *dev)
static int altera_spi_probe(struct platform_device *pdev)
{
struct altera_spi_platform_data *platp = dev_get_platdata(&pdev->dev);
struct altera_spi *hw;
struct spi_master *master;
struct resource *res;
@ -214,6 +212,8 @@ static int altera_spi_probe(struct platform_device *pdev)
master->bus_num = pdev->id;
master->num_chipselect = 16;
master->mode_bits = SPI_CS_HIGH;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
master->dev.of_node = pdev->dev.of_node;
hw = spi_master_get_devdata(master);
platform_set_drvdata(pdev, hw);
@ -245,9 +245,6 @@ static int altera_spi_probe(struct platform_device *pdev)
if (err)
goto exit;
}
/* find platform data */
if (!platp)
hw->bitbang.master->dev.of_node = pdev->dev.of_node;
/* register our spi controller */
err = spi_bitbang_start(&hw->bitbang);

Просмотреть файл

@ -14,7 +14,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>

Просмотреть файл

@ -9,7 +9,6 @@
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/platform_device.h>
@ -26,6 +25,7 @@
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/pinctrl/consumer.h>
/* SPI register offsets */
#define SPI_CR 0x0000
@ -993,13 +993,6 @@ static int atmel_spi_setup(struct spi_device *spi)
as = spi_master_get_devdata(spi->master);
if (spi->chip_select > spi->master->num_chipselect) {
dev_dbg(&spi->dev,
"setup: invalid chipselect %u (%u defined)\n",
spi->chip_select, spi->master->num_chipselect);
return -EINVAL;
}
/* see notes above re chipselect */
if (!atmel_spi_is_v2(as)
&& spi->chip_select == 0
@ -1087,14 +1080,6 @@ static int atmel_spi_one_transfer(struct spi_master *master,
}
}
if (xfer->bits_per_word > 8) {
if (xfer->len % 2) {
dev_dbg(&spi->dev,
"buffer len should be 16 bits aligned\n");
return -EINVAL;
}
}
/*
* DMA map early, for performance (empties dcache ASAP) and
* better fault reporting.
@ -1221,9 +1206,6 @@ static int atmel_spi_transfer_one_message(struct spi_master *master,
dev_dbg(&spi->dev, "new message %p submitted for %s\n",
msg, dev_name(&spi->dev));
if (unlikely(list_empty(&msg->transfers)))
return -EINVAL;
atmel_spi_lock(as);
cs_activate(as, spi);
@ -1244,10 +1226,10 @@ static int atmel_spi_transfer_one_message(struct spi_master *master,
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
dev_dbg(&spi->dev,
" xfer %p: len %u tx %p/%08x rx %p/%08x\n",
" xfer %p: len %u tx %p/%pad rx %p/%pad\n",
xfer, xfer->len,
xfer->tx_buf, xfer->tx_dma,
xfer->rx_buf, xfer->rx_dma);
xfer->tx_buf, &xfer->tx_dma,
xfer->rx_buf, &xfer->rx_dma);
}
msg_done:
@ -1303,6 +1285,9 @@ static int atmel_spi_probe(struct platform_device *pdev)
struct spi_master *master;
struct atmel_spi *as;
/* Select default pin state */
pinctrl_pm_select_default_state(&pdev->dev);
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs)
return -ENXIO;
@ -1465,6 +1450,9 @@ static int atmel_spi_suspend(struct device *dev)
}
clk_disable_unprepare(as->clk);
pinctrl_pm_select_sleep_state(dev);
return 0;
}
@ -1474,6 +1462,8 @@ static int atmel_spi_resume(struct device *dev)
struct atmel_spi *as = spi_master_get_devdata(master);
int ret;
pinctrl_pm_select_default_state(dev);
clk_prepare_enable(as->clk);
/* Start the queue running */

Просмотреть файл

@ -55,8 +55,6 @@ struct au1550_spi {
volatile psc_spi_t __iomem *regs;
int irq;
unsigned freq_max;
unsigned freq_min;
unsigned len;
unsigned tx_count;
@ -248,11 +246,8 @@ static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
hz = t->speed_hz;
}
if (hz > spi->max_speed_hz || hz > hw->freq_max || hz < hw->freq_min) {
dev_err(&spi->dev, "setupxfer: clock rate=%d out of range\n",
hz);
if (!hz)
return -EINVAL;
}
au1550_spi_bits_handlers_set(hw, spi->bits_per_word);
@ -287,23 +282,6 @@ static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
return 0;
}
static int au1550_spi_setup(struct spi_device *spi)
{
struct au1550_spi *hw = spi_master_get_devdata(spi->master);
if (spi->max_speed_hz == 0)
spi->max_speed_hz = hw->freq_max;
if (spi->max_speed_hz > hw->freq_max
|| spi->max_speed_hz < hw->freq_min)
return -EINVAL;
/*
* NOTE: cannot change speed and other hw settings immediately,
* otherwise sharing of spi bus is not possible,
* so do not call setupxfer(spi, NULL) here
*/
return 0;
}
/*
* for dma spi transfers, we have to setup rx channel, otherwise there is
* no reliable way how to recognize that spi transfer is done
@ -838,7 +816,6 @@ static int au1550_spi_probe(struct platform_device *pdev)
hw->bitbang.master = hw->master;
hw->bitbang.setup_transfer = au1550_spi_setupxfer;
hw->bitbang.chipselect = au1550_spi_chipsel;
hw->bitbang.master->setup = au1550_spi_setup;
hw->bitbang.txrx_bufs = au1550_spi_txrx_bufs;
if (hw->usedma) {
@ -909,8 +886,9 @@ static int au1550_spi_probe(struct platform_device *pdev)
{
int min_div = (2 << 0) * (2 * (4 + 1));
int max_div = (2 << 3) * (2 * (63 + 1));
hw->freq_max = hw->pdata->mainclk_hz / min_div;
hw->freq_min = hw->pdata->mainclk_hz / (max_div + 1) + 1;
master->max_speed_hz = hw->pdata->mainclk_hz / min_div;
master->min_speed_hz =
hw->pdata->mainclk_hz / (max_div + 1) + 1;
}
au1550_spi_setup_psc_as_spi(hw);

Просмотреть файл

@ -315,7 +315,6 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
master->mode_bits = BCM2835_SPI_MODE_BITS;
master->bits_per_word_mask = SPI_BPW_MASK(8);
master->bus_num = -1;
master->num_chipselect = 3;
master->transfer_one_message = bcm2835_spi_transfer_one;
master->dev.of_node = pdev->dev.of_node;

Просмотреть файл

@ -180,7 +180,7 @@ static int bcm63xx_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t)
while (pending > 0) {
int curr_step = min_t(int, step_size, pending);
init_completion(&bs->done);
reinit_completion(&bs->done);
if (tx) {
memcpy_toio(bs->fifo + HSSPI_OPCODE_LEN, tx, curr_step);
tx += curr_step;
@ -369,6 +369,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
bs->fifo = (u8 __iomem *)(bs->regs + HSSPI_FIFO_REG(0));
mutex_init(&bs->bus_mutex);
init_completion(&bs->done);
master->bus_num = HSSPI_BUS_NUM;
master->num_chipselect = 8;
@ -453,9 +454,8 @@ static int bcm63xx_hsspi_resume(struct device *dev)
}
#endif
static const struct dev_pm_ops bcm63xx_hsspi_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(bcm63xx_hsspi_suspend, bcm63xx_hsspi_resume)
};
static SIMPLE_DEV_PM_OPS(bcm63xx_hsspi_pm_ops, bcm63xx_hsspi_suspend,
bcm63xx_hsspi_resume);
static struct platform_driver bcm63xx_hsspi_driver = {
.driver = {

Просмотреть файл

@ -20,7 +20,6 @@
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/module.h>
@ -35,8 +34,6 @@
#include <bcm63xx_dev_spi.h>
#define PFX KBUILD_MODNAME
#define BCM63XX_SPI_MAX_PREPEND 15
struct bcm63xx_spi {
@ -169,7 +166,7 @@ static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *first,
transfer_list);
}
init_completion(&bs->done);
reinit_completion(&bs->done);
/* Fill in the Message control register */
msg_ctl = (len << SPI_BYTE_CNT_SHIFT);
@ -353,6 +350,7 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
}
bs = spi_master_get_devdata(master);
init_completion(&bs->done);
platform_set_drvdata(pdev, master);
bs->pdev = pdev;

Просмотреть файл

@ -8,7 +8,6 @@
* Licensed under the GPL-2 or later.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/device.h>

Просмотреть файл

@ -822,7 +822,8 @@ static int bfin_spi_probe(struct platform_device *pdev)
master->cleanup = bfin_spi_cleanup;
master->setup = bfin_spi_setup;
master->transfer_one_message = bfin_spi_transfer_one_message;
master->bits_per_word_mask = BIT(32 - 1) | BIT(16 - 1) | BIT(8 - 1);
master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) |
SPI_BPW_MASK(8);
drv_data = spi_master_get_devdata(master);
drv_data->master = master;

Просмотреть файл

@ -350,7 +350,6 @@ static void *bfin_spi_next_transfer(struct bfin_spi_master_data *drv_data)
static void bfin_spi_giveback(struct bfin_spi_master_data *drv_data)
{
struct bfin_spi_slave_data *chip = drv_data->cur_chip;
struct spi_transfer *last_transfer;
unsigned long flags;
struct spi_message *msg;
@ -362,9 +361,6 @@ static void bfin_spi_giveback(struct bfin_spi_master_data *drv_data)
queue_work(drv_data->workqueue, &drv_data->pump_messages);
spin_unlock_irqrestore(&drv_data->lock, flags);
last_transfer = list_entry(msg->transfers.prev,
struct spi_transfer, transfer_list);
msg->state = NULL;
if (!drv_data->cs_change)
@ -1030,10 +1026,6 @@ static int bfin_spi_setup(struct spi_device *spi)
}
/* translate common spi framework into our register */
if (spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST)) {
dev_err(&spi->dev, "unsupported spi modes detected\n");
goto error;
}
if (spi->mode & SPI_CPOL)
chip->ctl_reg |= BIT_CTL_CPOL;
if (spi->mode & SPI_CPHA)

Просмотреть файл

@ -16,7 +16,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
@ -467,11 +466,9 @@ EXPORT_SYMBOL_GPL(spi_bitbang_start);
/**
* spi_bitbang_stop - stops the task providing spi communication
*/
int spi_bitbang_stop(struct spi_bitbang *bitbang)
void spi_bitbang_stop(struct spi_bitbang *bitbang)
{
spi_unregister_master(bitbang->master);
return 0;
}
EXPORT_SYMBOL_GPL(spi_bitbang_stop);

Просмотреть файл

@ -309,7 +309,6 @@ done:
static void butterfly_detach(struct parport *p)
{
struct butterfly *pp;
int status;
/* FIXME this global is ugly ... but, how to quickly get from
* the parport to the "struct butterfly" associated with it?
@ -321,7 +320,7 @@ static void butterfly_detach(struct parport *p)
butterfly = NULL;
/* stop() unregisters child devices too */
status = spi_bitbang_stop(&pp->bitbang);
spi_bitbang_stop(&pp->bitbang);
/* turn off VCC */
parport_write_data(pp->port, 0);

Просмотреть файл

@ -11,158 +11,125 @@
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/clps711x.h>
#include <linux/spi/spi.h>
#include <linux/platform_data/spi-clps711x.h>
#include <mach/hardware.h>
#define DRIVER_NAME "spi-clps711x"
struct spi_clps711x_data {
struct completion done;
#define SYNCIO_FRMLEN(x) ((x) << 8)
#define SYNCIO_TXFRMEN (1 << 14)
struct spi_clps711x_data {
void __iomem *syncio;
struct regmap *syscon;
struct regmap *syscon1;
struct clk *spi_clk;
u32 max_speed_hz;
u8 *tx_buf;
u8 *rx_buf;
int count;
unsigned int bpw;
int len;
int chipselect[0];
};
static int spi_clps711x_setup(struct spi_device *spi)
{
struct spi_clps711x_data *hw = spi_master_get_devdata(spi->master);
/* We are expect that SPI-device is not selected */
gpio_direction_output(hw->chipselect[spi->chip_select],
!(spi->mode & SPI_CS_HIGH));
gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
return 0;
}
static void spi_clps711x_setup_mode(struct spi_device *spi)
static void spi_clps711x_setup_xfer(struct spi_device *spi,
struct spi_transfer *xfer)
{
/* Setup edge for transfer */
if (spi->mode & SPI_CPHA)
clps_writew(clps_readw(SYSCON3) | SYSCON3_ADCCKNSEN, SYSCON3);
else
clps_writew(clps_readw(SYSCON3) & ~SYSCON3_ADCCKNSEN, SYSCON3);
}
static int spi_clps711x_setup_xfer(struct spi_device *spi,
struct spi_transfer *xfer)
{
u32 speed = xfer->speed_hz ? : spi->max_speed_hz;
u8 bpw = xfer->bits_per_word;
struct spi_clps711x_data *hw = spi_master_get_devdata(spi->master);
if (bpw != 8) {
dev_err(&spi->dev, "Unsupported master bus width %i\n", bpw);
return -EINVAL;
}
struct spi_master *master = spi->master;
struct spi_clps711x_data *hw = spi_master_get_devdata(master);
/* Setup SPI frequency divider */
if (!speed || (speed >= hw->max_speed_hz))
clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) |
SYSCON1_ADCKSEL(3), SYSCON1);
else if (speed >= (hw->max_speed_hz / 2))
clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) |
SYSCON1_ADCKSEL(2), SYSCON1);
else if (speed >= (hw->max_speed_hz / 8))
clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) |
SYSCON1_ADCKSEL(1), SYSCON1);
if (xfer->speed_hz >= master->max_speed_hz)
regmap_update_bits(hw->syscon1, SYSCON_OFFSET,
SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(3));
else if (xfer->speed_hz >= (master->max_speed_hz / 2))
regmap_update_bits(hw->syscon1, SYSCON_OFFSET,
SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(2));
else if (xfer->speed_hz >= (master->max_speed_hz / 8))
regmap_update_bits(hw->syscon1, SYSCON_OFFSET,
SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(1));
else
clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) |
SYSCON1_ADCKSEL(0), SYSCON1);
return 0;
regmap_update_bits(hw->syscon1, SYSCON_OFFSET,
SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(0));
}
static int spi_clps711x_transfer_one_message(struct spi_master *master,
struct spi_message *msg)
static int spi_clps711x_prepare_message(struct spi_master *master,
struct spi_message *msg)
{
struct spi_clps711x_data *hw = spi_master_get_devdata(master);
struct spi_transfer *xfer;
int status = 0, cs = hw->chipselect[msg->spi->chip_select];
u32 data;
struct spi_device *spi = msg->spi;
spi_clps711x_setup_mode(msg->spi);
/* Setup mode for transfer */
return regmap_update_bits(hw->syscon, SYSCON_OFFSET, SYSCON3_ADCCKNSEN,
(spi->mode & SPI_CPHA) ?
SYSCON3_ADCCKNSEN : 0);
}
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
if (spi_clps711x_setup_xfer(msg->spi, xfer)) {
status = -EINVAL;
goto out_xfr;
}
static int spi_clps711x_transfer_one(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *xfer)
{
struct spi_clps711x_data *hw = spi_master_get_devdata(master);
u8 data;
gpio_set_value(cs, !!(msg->spi->mode & SPI_CS_HIGH));
spi_clps711x_setup_xfer(spi, xfer);
reinit_completion(&hw->done);
hw->len = xfer->len;
hw->bpw = xfer->bits_per_word;
hw->tx_buf = (u8 *)xfer->tx_buf;
hw->rx_buf = (u8 *)xfer->rx_buf;
hw->count = 0;
hw->len = xfer->len;
hw->tx_buf = (u8 *)xfer->tx_buf;
hw->rx_buf = (u8 *)xfer->rx_buf;
/* Initiate transfer */
data = hw->tx_buf ? *hw->tx_buf++ : 0;
writel(data | SYNCIO_FRMLEN(hw->bpw) | SYNCIO_TXFRMEN, hw->syncio);
/* Initiate transfer */
data = hw->tx_buf ? hw->tx_buf[hw->count] : 0;
clps_writel(data | SYNCIO_FRMLEN(8) | SYNCIO_TXFRMEN, SYNCIO);
wait_for_completion(&hw->done);
if (xfer->delay_usecs)
udelay(xfer->delay_usecs);
if (xfer->cs_change ||
list_is_last(&xfer->transfer_list, &msg->transfers))
gpio_set_value(cs, !(msg->spi->mode & SPI_CS_HIGH));
msg->actual_length += xfer->len;
}
out_xfr:
msg->status = status;
spi_finalize_current_message(master);
return 0;
return 1;
}
static irqreturn_t spi_clps711x_isr(int irq, void *dev_id)
{
struct spi_clps711x_data *hw = (struct spi_clps711x_data *)dev_id;
u32 data;
struct spi_master *master = dev_id;
struct spi_clps711x_data *hw = spi_master_get_devdata(master);
u8 data;
/* Handle RX */
data = clps_readb(SYNCIO);
data = readb(hw->syncio);
if (hw->rx_buf)
hw->rx_buf[hw->count] = (u8)data;
hw->count++;
*hw->rx_buf++ = data;
/* Handle TX */
if (hw->count < hw->len) {
data = hw->tx_buf ? hw->tx_buf[hw->count] : 0;
clps_writel(data | SYNCIO_FRMLEN(8) | SYNCIO_TXFRMEN, SYNCIO);
if (--hw->len > 0) {
data = hw->tx_buf ? *hw->tx_buf++ : 0;
writel(data | SYNCIO_FRMLEN(hw->bpw) | SYNCIO_TXFRMEN,
hw->syncio);
} else
complete(&hw->done);
spi_finalize_current_transfer(master);
return IRQ_HANDLED;
}
static int spi_clps711x_probe(struct platform_device *pdev)
{
int i, ret;
struct spi_master *master;
struct spi_clps711x_data *hw;
struct spi_clps711x_pdata *pdata = dev_get_platdata(&pdev->dev);
struct spi_master *master;
struct resource *res;
int i, irq, ret;
if (!pdata) {
dev_err(&pdev->dev, "No platform data supplied\n");
@ -174,33 +141,37 @@ static int spi_clps711x_probe(struct platform_device *pdev)
return -EINVAL;
}
master = spi_alloc_master(&pdev->dev,
sizeof(struct spi_clps711x_data) +
sizeof(int) * pdata->num_chipselect);
if (!master) {
dev_err(&pdev->dev, "SPI allocating memory error\n");
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
master = spi_alloc_master(&pdev->dev, sizeof(*hw));
if (!master)
return -ENOMEM;
master->cs_gpios = devm_kzalloc(&pdev->dev, sizeof(int) *
pdata->num_chipselect, GFP_KERNEL);
if (!master->cs_gpios) {
ret = -ENOMEM;
goto err_out;
}
master->bus_num = pdev->id;
master->mode_bits = SPI_CPHA | SPI_CS_HIGH;
master->bits_per_word_mask = SPI_BPW_MASK(8);
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 8);
master->num_chipselect = pdata->num_chipselect;
master->setup = spi_clps711x_setup;
master->transfer_one_message = spi_clps711x_transfer_one_message;
master->prepare_message = spi_clps711x_prepare_message;
master->transfer_one = spi_clps711x_transfer_one;
hw = spi_master_get_devdata(master);
for (i = 0; i < master->num_chipselect; i++) {
hw->chipselect[i] = pdata->chipselect[i];
if (!gpio_is_valid(hw->chipselect[i])) {
dev_err(&pdev->dev, "Invalid CS GPIO %i\n", i);
ret = -EINVAL;
goto err_out;
}
if (devm_gpio_request(&pdev->dev, hw->chipselect[i], NULL)) {
master->cs_gpios[i] = pdata->chipselect[i];
ret = devm_gpio_request(&pdev->dev, master->cs_gpios[i],
DRIVER_NAME);
if (ret) {
dev_err(&pdev->dev, "Can't get CS GPIO %i\n", i);
ret = -EINVAL;
goto err_out;
}
}
@ -211,29 +182,45 @@ static int spi_clps711x_probe(struct platform_device *pdev)
ret = PTR_ERR(hw->spi_clk);
goto err_out;
}
hw->max_speed_hz = clk_get_rate(hw->spi_clk);
master->max_speed_hz = clk_get_rate(hw->spi_clk);
init_completion(&hw->done);
platform_set_drvdata(pdev, master);
/* Disable extended mode due hardware problems */
clps_writew(clps_readw(SYSCON3) & ~SYSCON3_ADCCON, SYSCON3);
/* Clear possible pending interrupt */
clps_readl(SYNCIO);
ret = devm_request_irq(&pdev->dev, IRQ_SSEOTI, spi_clps711x_isr, 0,
dev_name(&pdev->dev), hw);
if (ret) {
dev_err(&pdev->dev, "Can't request IRQ\n");
hw->syscon = syscon_regmap_lookup_by_pdevname("syscon.3");
if (IS_ERR(hw->syscon)) {
ret = PTR_ERR(hw->syscon);
goto err_out;
}
hw->syscon1 = syscon_regmap_lookup_by_pdevname("syscon.1");
if (IS_ERR(hw->syscon1)) {
ret = PTR_ERR(hw->syscon1);
goto err_out;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hw->syncio = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(hw->syncio)) {
ret = PTR_ERR(hw->syncio);
goto err_out;
}
/* Disable extended mode due hardware problems */
regmap_update_bits(hw->syscon, SYSCON_OFFSET, SYSCON3_ADCCON, 0);
/* Clear possible pending interrupt */
readl(hw->syncio);
ret = devm_request_irq(&pdev->dev, irq, spi_clps711x_isr, 0,
dev_name(&pdev->dev), master);
if (ret)
goto err_out;
ret = devm_spi_register_master(&pdev->dev, master);
if (!ret) {
dev_info(&pdev->dev,
"SPI bus driver initialized. Master clock %u Hz\n",
hw->max_speed_hz);
master->max_speed_hz);
return 0;
}

Просмотреть файл

@ -77,8 +77,6 @@ struct mcfqspi {
struct mcfqspi_cs_control *cs_control;
wait_queue_head_t waitq;
struct device *dev;
};
static void mcfqspi_wr_qmr(struct mcfqspi *mcfqspi, u16 val)
@ -135,13 +133,13 @@ static void mcfqspi_cs_deselect(struct mcfqspi *mcfqspi, u8 chip_select,
static int mcfqspi_cs_setup(struct mcfqspi *mcfqspi)
{
return (mcfqspi->cs_control && mcfqspi->cs_control->setup) ?
return (mcfqspi->cs_control->setup) ?
mcfqspi->cs_control->setup(mcfqspi->cs_control) : 0;
}
static void mcfqspi_cs_teardown(struct mcfqspi *mcfqspi)
{
if (mcfqspi->cs_control && mcfqspi->cs_control->teardown)
if (mcfqspi->cs_control->teardown)
mcfqspi->cs_control->teardown(mcfqspi->cs_control);
}
@ -300,68 +298,45 @@ static void mcfqspi_transfer_msg16(struct mcfqspi *mcfqspi, unsigned count,
}
}
static int mcfqspi_transfer_one_message(struct spi_master *master,
struct spi_message *msg)
static void mcfqspi_set_cs(struct spi_device *spi, bool enable)
{
struct mcfqspi *mcfqspi = spi_master_get_devdata(spi->master);
bool cs_high = spi->mode & SPI_CS_HIGH;
if (enable)
mcfqspi_cs_select(mcfqspi, spi->chip_select, cs_high);
else
mcfqspi_cs_deselect(mcfqspi, spi->chip_select, cs_high);
}
static int mcfqspi_transfer_one(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *t)
{
struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
struct spi_device *spi = msg->spi;
struct spi_transfer *t;
int status = 0;
u16 qmr = MCFQSPI_QMR_MSTR;
list_for_each_entry(t, &msg->transfers, transfer_list) {
bool cs_high = spi->mode & SPI_CS_HIGH;
u16 qmr = MCFQSPI_QMR_MSTR;
qmr |= t->bits_per_word << 10;
if (spi->mode & SPI_CPHA)
qmr |= MCFQSPI_QMR_CPHA;
if (spi->mode & SPI_CPOL)
qmr |= MCFQSPI_QMR_CPOL;
qmr |= mcfqspi_qmr_baud(t->speed_hz);
mcfqspi_wr_qmr(mcfqspi, qmr);
qmr |= t->bits_per_word << 10;
if (spi->mode & SPI_CPHA)
qmr |= MCFQSPI_QMR_CPHA;
if (spi->mode & SPI_CPOL)
qmr |= MCFQSPI_QMR_CPOL;
if (t->speed_hz)
qmr |= mcfqspi_qmr_baud(t->speed_hz);
else
qmr |= mcfqspi_qmr_baud(spi->max_speed_hz);
mcfqspi_wr_qmr(mcfqspi, qmr);
mcfqspi_cs_select(mcfqspi, spi->chip_select, cs_high);
mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE);
if (t->bits_per_word == 8)
mcfqspi_transfer_msg8(mcfqspi, t->len, t->tx_buf,
t->rx_buf);
else
mcfqspi_transfer_msg16(mcfqspi, t->len / 2, t->tx_buf,
t->rx_buf);
mcfqspi_wr_qir(mcfqspi, 0);
if (t->delay_usecs)
udelay(t->delay_usecs);
if (t->cs_change) {
if (!list_is_last(&t->transfer_list, &msg->transfers))
mcfqspi_cs_deselect(mcfqspi, spi->chip_select,
cs_high);
} else {
if (list_is_last(&t->transfer_list, &msg->transfers))
mcfqspi_cs_deselect(mcfqspi, spi->chip_select,
cs_high);
}
msg->actual_length += t->len;
}
msg->status = status;
spi_finalize_current_message(master);
return status;
mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE);
if (t->bits_per_word == 8)
mcfqspi_transfer_msg8(mcfqspi, t->len, t->tx_buf, t->rx_buf);
else
mcfqspi_transfer_msg16(mcfqspi, t->len / 2, t->tx_buf,
t->rx_buf);
mcfqspi_wr_qir(mcfqspi, 0);
return 0;
}
static int mcfqspi_setup(struct spi_device *spi)
{
if (spi->chip_select >= spi->master->num_chipselect) {
dev_dbg(&spi->dev, "%d chip select is out of range\n",
spi->chip_select);
return -EINVAL;
}
mcfqspi_cs_deselect(spi_master_get_devdata(spi->master),
spi->chip_select, spi->mode & SPI_CS_HIGH);
@ -388,6 +363,11 @@ static int mcfqspi_probe(struct platform_device *pdev)
return -ENOENT;
}
if (!pdata->cs_control) {
dev_dbg(&pdev->dev, "pdata->cs_control is NULL\n");
return -EINVAL;
}
master = spi_alloc_master(&pdev->dev, sizeof(*mcfqspi));
if (master == NULL) {
dev_dbg(&pdev->dev, "spi_alloc_master failed\n");
@ -436,12 +416,12 @@ static int mcfqspi_probe(struct platform_device *pdev)
}
init_waitqueue_head(&mcfqspi->waitq);
mcfqspi->dev = &pdev->dev;
master->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16);
master->setup = mcfqspi_setup;
master->transfer_one_message = mcfqspi_transfer_one_message;
master->set_cs = mcfqspi_set_cs;
master->transfer_one = mcfqspi_transfer_one;
master->auto_runtime_pm = true;
platform_set_drvdata(pdev, master);
@ -451,7 +431,7 @@ static int mcfqspi_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "spi_register_master failed\n");
goto fail2;
}
pm_runtime_enable(mcfqspi->dev);
pm_runtime_enable(&pdev->dev);
dev_info(&pdev->dev, "Coldfire QSPI bus driver\n");
@ -473,9 +453,8 @@ static int mcfqspi_remove(struct platform_device *pdev)
{
struct spi_master *master = platform_get_drvdata(pdev);
struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
pm_runtime_disable(mcfqspi->dev);
pm_runtime_disable(&pdev->dev);
/* disable the hardware (set the baud rate to 0) */
mcfqspi_wr_qmr(mcfqspi, MCFQSPI_QMR_MSTR);
@ -490,8 +469,11 @@ static int mcfqspi_suspend(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
int ret;
spi_master_suspend(master);
ret = spi_master_suspend(master);
if (ret)
return ret;
clk_disable(mcfqspi->clk);
@ -503,11 +485,9 @@ static int mcfqspi_resume(struct device *dev)
struct spi_master *master = dev_get_drvdata(dev);
struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
spi_master_resume(master);
clk_enable(mcfqspi->clk);
return 0;
return spi_master_resume(master);
}
#endif

Просмотреть файл

@ -802,8 +802,7 @@ static int spi_davinci_get_pdata(struct platform_device *pdev,
pdata = &dspi->pdata;
pdata->version = SPI_VERSION_1;
match = of_match_device(of_match_ptr(davinci_spi_of_match),
&pdev->dev);
match = of_match_device(davinci_spi_of_match, &pdev->dev);
if (!match)
return -ENODEV;
@ -824,7 +823,6 @@ static int spi_davinci_get_pdata(struct platform_device *pdev,
return 0;
}
#else
#define davinci_spi_of_match NULL
static struct davinci_spi_platform_data
*spi_davinci_get_pdata(struct platform_device *pdev,
struct davinci_spi *dspi)
@ -864,10 +862,6 @@ static int davinci_spi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, master);
dspi = spi_master_get_devdata(master);
if (dspi == NULL) {
ret = -ENOENT;
goto free_master;
}
if (dev_get_platdata(&pdev->dev)) {
pdata = dev_get_platdata(&pdev->dev);
@ -908,10 +902,6 @@ static int davinci_spi_probe(struct platform_device *pdev)
goto free_master;
dspi->bitbang.master = master;
if (dspi->bitbang.master == NULL) {
ret = -ENODEV;
goto free_master;
}
dspi->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(dspi->clk)) {
@ -1040,7 +1030,7 @@ static struct platform_driver davinci_spi_driver = {
.driver = {
.name = "spi_davinci",
.owner = THIS_MODULE,
.of_match_table = davinci_spi_of_match,
.of_match_table = of_match_ptr(davinci_spi_of_match),
},
.probe = davinci_spi_probe,
.remove = davinci_spi_remove,

Просмотреть файл

@ -66,7 +66,7 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
if (ret)
return ret;
dws->bus_num = 0;
dws->bus_num = pdev->id;
dws->num_cs = 4;
dws->max_freq = clk_get_rate(dwsmmio->clk);

Просмотреть файл

@ -276,8 +276,7 @@ static void giveback(struct dw_spi *dws)
queue_work(dws->workqueue, &dws->pump_messages);
spin_unlock_irqrestore(&dws->lock, flags);
last_transfer = list_entry(msg->transfers.prev,
struct spi_transfer,
last_transfer = list_last_entry(&msg->transfers, struct spi_transfer,
transfer_list);
if (!last_transfer->cs_change && dws->cs_control)
@ -439,12 +438,6 @@ static void pump_transfers(unsigned long data)
if (transfer->speed_hz != speed) {
speed = transfer->speed_hz;
if (speed > dws->max_freq) {
printk(KERN_ERR "MRST SPI0: unsupported"
"freq: %dHz\n", speed);
message->status = -EIO;
goto early_exit;
}
/* clk_div doesn't support odd number */
clk_div = dws->max_freq / speed;
@ -671,12 +664,6 @@ static int dw_spi_setup(struct spi_device *spi)
return 0;
}
static void dw_spi_cleanup(struct spi_device *spi)
{
struct chip_data *chip = spi_get_ctldata(spi);
kfree(chip);
}
static int init_queue(struct dw_spi *dws)
{
INIT_LIST_HEAD(&dws->queue);
@ -806,9 +793,9 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
master->bus_num = dws->bus_num;
master->num_chipselect = dws->num_cs;
master->cleanup = dw_spi_cleanup;
master->setup = dw_spi_setup;
master->transfer = dw_spi_transfer;
master->max_speed_hz = dws->max_freq;
/* Basic HW init */
spi_hw_init(dws);

Просмотреть файл

@ -198,7 +198,7 @@ static int efm32_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
efm32_spi_filltx(ddata);
init_completion(&ddata->done);
reinit_completion(&ddata->done);
efm32_spi_write32(ddata, REG_IF_TXBL | REG_IF_RXDATAV, REG_IEN);
@ -287,17 +287,17 @@ static u32 efm32_spi_get_configured_location(struct efm32_spi_ddata *ddata)
return (reg & REG_ROUTE_LOCATION__MASK) >> __ffs(REG_ROUTE_LOCATION__MASK);
}
static int efm32_spi_probe_dt(struct platform_device *pdev,
static void efm32_spi_probe_dt(struct platform_device *pdev,
struct spi_master *master, struct efm32_spi_ddata *ddata)
{
struct device_node *np = pdev->dev.of_node;
u32 location;
int ret;
if (!np)
return 1;
ret = of_property_read_u32(np, "location", &location);
ret = of_property_read_u32(np, "efm32,location", &location);
if (ret)
/* fall back to old and (wrongly) generic property "location" */
ret = of_property_read_u32(np, "location", &location);
if (!ret) {
dev_dbg(&pdev->dev, "using location %u\n", location);
} else {
@ -308,11 +308,6 @@ static int efm32_spi_probe_dt(struct platform_device *pdev,
}
ddata->pdata.location = location;
/* spi core takes care about the bus number using an alias */
master->bus_num = -1;
return 0;
}
static int efm32_spi_probe(struct platform_device *pdev)
@ -322,9 +317,14 @@ static int efm32_spi_probe(struct platform_device *pdev)
int ret;
struct spi_master *master;
struct device_node *np = pdev->dev.of_node;
unsigned int num_cs, i;
int num_cs, i;
if (!np)
return -EINVAL;
num_cs = of_gpio_named_count(np, "cs-gpios");
if (num_cs < 0)
return num_cs;
master = spi_alloc_master(&pdev->dev,
sizeof(*ddata) + num_cs * sizeof(unsigned));
@ -349,6 +349,7 @@ static int efm32_spi_probe(struct platform_device *pdev)
ddata->bitbang.txrx_bufs = efm32_spi_txrx_bufs;
spin_lock_init(&ddata->lock);
init_completion(&ddata->done);
ddata->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(ddata->clk)) {
@ -415,23 +416,7 @@ static int efm32_spi_probe(struct platform_device *pdev)
goto err;
}
ret = efm32_spi_probe_dt(pdev, master, ddata);
if (ret > 0) {
/* not created by device tree */
const struct efm32_spi_pdata *pdata =
dev_get_platdata(&pdev->dev);
if (pdata)
ddata->pdata = *pdata;
else
ddata->pdata.location =
efm32_spi_get_configured_location(ddata);
master->bus_num = pdev->id;
} else if (ret < 0) {
goto err_disable_clk;
}
efm32_spi_probe_dt(pdev, master, ddata);
efm32_spi_write32(ddata, 0, REG_IEN);
efm32_spi_write32(ddata, REG_ROUTE_TXPEN | REG_ROUTE_RXPEN |
@ -487,6 +472,9 @@ static int efm32_spi_remove(struct platform_device *pdev)
static const struct of_device_id efm32_spi_dt_ids[] = {
{
.compatible = "energymicro,efm32-spi",
}, {
/* doesn't follow the "vendor,device" scheme, don't use */
.compatible = "efm32,spi",
}, {
/* sentinel */

Просмотреть файл

@ -73,8 +73,6 @@
* @clk: clock for the controller
* @regs_base: pointer to ioremap()'d registers
* @sspdr_phys: physical address of the SSPDR register
* @min_rate: minimum clock rate (in Hz) supported by the controller
* @max_rate: maximum clock rate (in Hz) supported by the controller
* @wait: wait here until given transfer is completed
* @current_msg: message that is currently processed (or %NULL if none)
* @tx: current byte in transfer to transmit
@ -95,8 +93,6 @@ struct ep93xx_spi {
struct clk *clk;
void __iomem *regs_base;
unsigned long sspdr_phys;
unsigned long min_rate;
unsigned long max_rate;
struct completion wait;
struct spi_message *current_msg;
size_t tx;
@ -199,9 +195,9 @@ static void ep93xx_spi_disable_interrupts(const struct ep93xx_spi *espi)
* @div_scr: pointer to return the scr divider
*/
static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi,
unsigned long rate,
u8 *div_cpsr, u8 *div_scr)
u32 rate, u8 *div_cpsr, u8 *div_scr)
{
struct spi_master *master = platform_get_drvdata(espi->pdev);
unsigned long spi_clk_rate = clk_get_rate(espi->clk);
int cpsr, scr;
@ -210,7 +206,7 @@ static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi,
* controller. Note that minimum value is already checked in
* ep93xx_spi_transfer_one_message().
*/
rate = clamp(rate, espi->min_rate, espi->max_rate);
rate = clamp(rate, master->min_speed_hz, master->max_speed_hz);
/*
* Calculate divisors so that we can get speed according the
@ -735,13 +731,6 @@ static int ep93xx_spi_transfer_one_message(struct spi_master *master,
struct spi_message *msg)
{
struct ep93xx_spi *espi = spi_master_get_devdata(master);
struct spi_transfer *t;
/* first validate each transfer */
list_for_each_entry(t, &msg->transfers, transfer_list) {
if (t->speed_hz < espi->min_rate)
return -EINVAL;
}
msg->state = NULL;
msg->status = 0;
@ -917,8 +906,8 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
* Calculate maximum and minimum supported clock rates
* for the controller.
*/
espi->max_rate = clk_get_rate(espi->clk) / 2;
espi->min_rate = clk_get_rate(espi->clk) / (254 * 256);
master->max_speed_hz = clk_get_rate(espi->clk) / 2;
master->min_speed_hz = clk_get_rate(espi->clk) / (254 * 256);
espi->pdev = pdev;
espi->sspdr_phys = res->start + SSPDR;

Просмотреть файл

@ -312,9 +312,6 @@ static int falcon_sflash_setup(struct spi_device *spi)
unsigned int i;
unsigned long flags;
if (spi->chip_select > 0)
return -ENODEV;
spin_lock_irqsave(&ebu_lock, flags);
if (spi->max_speed_hz >= CLOCK_100M) {
@ -422,9 +419,7 @@ static int falcon_sflash_probe(struct platform_device *pdev)
priv->master = master;
master->mode_bits = SPI_MODE_3;
master->num_chipselect = 1;
master->flags = SPI_MASTER_HALF_DUPLEX;
master->bus_num = -1;
master->setup = falcon_sflash_setup;
master->prepare_transfer_hardware = falcon_sflash_prepare_xfer;
master->transfer_one_message = falcon_sflash_xfer_one;

Просмотреть файл

@ -18,6 +18,7 @@
#include <linux/interrupt.h>
#include <linux/errno.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/io.h>
@ -108,11 +109,11 @@ struct fsl_dspi {
struct spi_bitbang bitbang;
struct platform_device *pdev;
void __iomem *base;
struct regmap *regmap;
int irq;
struct clk *clk;
struct clk *clk;
struct spi_transfer *cur_transfer;
struct spi_transfer *cur_transfer;
struct chip_data *cur_chip;
size_t len;
void *tx;
@ -123,24 +124,17 @@ struct fsl_dspi {
u8 cs;
u16 void_write_data;
wait_queue_head_t waitq;
u32 waitflags;
wait_queue_head_t waitq;
u32 waitflags;
};
static inline int is_double_byte_mode(struct fsl_dspi *dspi)
{
return ((readl(dspi->base + SPI_CTAR(dspi->cs)) & SPI_FRAME_BITS_MASK)
== SPI_FRAME_BITS(8)) ? 0 : 1;
}
unsigned int val;
static void set_bit_mode(struct fsl_dspi *dspi, unsigned char bits)
{
u32 temp;
regmap_read(dspi->regmap, SPI_CTAR(dspi->cs), &val);
temp = readl(dspi->base + SPI_CTAR(dspi->cs));
temp &= ~SPI_FRAME_BITS_MASK;
temp |= SPI_FRAME_BITS(bits);
writel(temp, dspi->base + SPI_CTAR(dspi->cs));
return ((val & SPI_FRAME_BITS_MASK) == SPI_FRAME_BITS(8)) ? 0 : 1;
}
static void hz_to_spi_baud(char *pbr, char *br, int speed_hz,
@ -188,7 +182,8 @@ static int dspi_transfer_write(struct fsl_dspi *dspi)
*/
if (tx_word && (dspi->len == 1)) {
dspi->dataflags |= TRAN_STATE_WORD_ODD_NUM;
set_bit_mode(dspi, 8);
regmap_update_bits(dspi->regmap, SPI_CTAR(dspi->cs),
SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(8));
tx_word = 0;
}
@ -238,7 +233,8 @@ static int dspi_transfer_write(struct fsl_dspi *dspi)
dspi_pushr |= SPI_PUSHR_CTCNT; /* clear counter */
}
writel(dspi_pushr, dspi->base + SPI_PUSHR);
regmap_write(dspi->regmap, SPI_PUSHR, dspi_pushr);
tx_count++;
}
@ -253,17 +249,23 @@ static int dspi_transfer_read(struct fsl_dspi *dspi)
while ((dspi->rx < dspi->rx_end)
&& (rx_count < DSPI_FIFO_SIZE)) {
if (rx_word) {
unsigned int val;
if ((dspi->rx_end - dspi->rx) == 1)
break;
d = SPI_POPR_RXDATA(readl(dspi->base + SPI_POPR));
regmap_read(dspi->regmap, SPI_POPR, &val);
d = SPI_POPR_RXDATA(val);
if (!(dspi->dataflags & TRAN_STATE_RX_VOID))
*(u16 *)dspi->rx = d;
dspi->rx += 2;
} else {
d = SPI_POPR_RXDATA(readl(dspi->base + SPI_POPR));
unsigned int val;
regmap_read(dspi->regmap, SPI_POPR, &val);
d = SPI_POPR_RXDATA(val);
if (!(dspi->dataflags & TRAN_STATE_RX_VOID))
*(u8 *)dspi->rx = d;
dspi->rx++;
@ -295,13 +297,13 @@ static int dspi_txrx_transfer(struct spi_device *spi, struct spi_transfer *t)
if (!dspi->tx)
dspi->dataflags |= TRAN_STATE_TX_VOID;
writel(dspi->cur_chip->mcr_val, dspi->base + SPI_MCR);
writel(dspi->cur_chip->ctar_val, dspi->base + SPI_CTAR(dspi->cs));
writel(SPI_RSER_EOQFE, dspi->base + SPI_RSER);
regmap_write(dspi->regmap, SPI_MCR, dspi->cur_chip->mcr_val);
regmap_write(dspi->regmap, SPI_CTAR(dspi->cs), dspi->cur_chip->ctar_val);
regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_EOQFE);
if (t->speed_hz)
writel(dspi->cur_chip->ctar_val,
dspi->base + SPI_CTAR(dspi->cs));
regmap_write(dspi->regmap, SPI_CTAR(dspi->cs),
dspi->cur_chip->ctar_val);
dspi_transfer_write(dspi);
@ -315,7 +317,9 @@ static int dspi_txrx_transfer(struct spi_device *spi, struct spi_transfer *t)
static void dspi_chipselect(struct spi_device *spi, int value)
{
struct fsl_dspi *dspi = spi_master_get_devdata(spi->master);
u32 pushr = readl(dspi->base + SPI_PUSHR);
unsigned int pushr;
regmap_read(dspi->regmap, SPI_PUSHR, &pushr);
switch (value) {
case BITBANG_CS_ACTIVE:
@ -326,7 +330,7 @@ static void dspi_chipselect(struct spi_device *spi, int value)
break;
}
writel(pushr, dspi->base + SPI_PUSHR);
regmap_write(dspi->regmap, SPI_PUSHR, pushr);
}
static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
@ -338,7 +342,8 @@ static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
/* Only alloc on first setup */
chip = spi_get_ctldata(spi);
if (chip == NULL) {
chip = kcalloc(1, sizeof(struct chip_data), GFP_KERNEL);
chip = devm_kzalloc(&spi->dev, sizeof(struct chip_data),
GFP_KERNEL);
if (!chip)
return -ENOMEM;
}
@ -349,7 +354,6 @@ static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
fmsz = spi->bits_per_word - 1;
} else {
pr_err("Invalid wordsize\n");
kfree(chip);
return -ENODEV;
}
@ -382,13 +386,15 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id)
{
struct fsl_dspi *dspi = (struct fsl_dspi *)dev_id;
writel(SPI_SR_EOQF, dspi->base + SPI_SR);
regmap_write(dspi->regmap, SPI_SR, SPI_SR_EOQF);
dspi_transfer_read(dspi);
if (!dspi->len) {
if (dspi->dataflags & TRAN_STATE_WORD_ODD_NUM)
set_bit_mode(dspi, 16);
regmap_update_bits(dspi->regmap, SPI_CTAR(dspi->cs),
SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(16));
dspi->waitflags = 1;
wake_up_interruptible(&dspi->waitq);
} else {
@ -430,8 +436,13 @@ static int dspi_resume(struct device *dev)
}
#endif /* CONFIG_PM_SLEEP */
static const struct dev_pm_ops dspi_pm = {
SET_SYSTEM_SLEEP_PM_OPS(dspi_suspend, dspi_resume)
static SIMPLE_DEV_PM_OPS(dspi_pm, dspi_suspend, dspi_resume);
static struct regmap_config dspi_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.max_register = 0x88,
};
static int dspi_probe(struct platform_device *pdev)
@ -440,6 +451,7 @@ static int dspi_probe(struct platform_device *pdev)
struct spi_master *master;
struct fsl_dspi *dspi;
struct resource *res;
void __iomem *base;
int ret = 0, cs_num, bus_num;
master = spi_alloc_master(&pdev->dev, sizeof(struct fsl_dspi));
@ -474,12 +486,24 @@ static int dspi_probe(struct platform_device *pdev)
master->bus_num = bus_num;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dspi->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(dspi->base)) {
ret = PTR_ERR(dspi->base);
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base)) {
ret = PTR_ERR(base);
goto out_master_put;
}
dspi_regmap_config.lock_arg = dspi;
dspi_regmap_config.val_format_endian =
of_property_read_bool(np, "big-endian")
? REGMAP_ENDIAN_BIG : REGMAP_ENDIAN_DEFAULT;
dspi->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "dspi", base,
&dspi_regmap_config);
if (IS_ERR(dspi->regmap)) {
dev_err(&pdev->dev, "failed to init regmap: %ld\n",
PTR_ERR(dspi->regmap));
return PTR_ERR(dspi->regmap);
}
dspi->irq = platform_get_irq(pdev, 0);
if (dspi->irq < 0) {
dev_err(&pdev->dev, "can't get platform irq\n");

Просмотреть файл

@ -219,13 +219,8 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
struct fsl_espi_reg *reg_base = mpc8xxx_spi->reg_base;
unsigned int len = t->len;
u8 bits_per_word;
int ret;
bits_per_word = spi->bits_per_word;
if (t->bits_per_word)
bits_per_word = t->bits_per_word;
mpc8xxx_spi->len = t->len;
len = roundup(len, 4) / 4;

Просмотреть файл

@ -200,7 +200,7 @@ int of_mpc8xxx_spi_probe(struct platform_device *ofdev)
const void *prop;
int ret = -ENOMEM;
pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
pinfo = devm_kzalloc(&ofdev->dev, sizeof(*pinfo), GFP_KERNEL);
if (!pinfo)
return -ENOMEM;
@ -215,15 +215,13 @@ int of_mpc8xxx_spi_probe(struct platform_device *ofdev)
pdata->sysclk = get_brgfreq();
if (pdata->sysclk == -1) {
pdata->sysclk = fsl_get_sys_freq();
if (pdata->sysclk == -1) {
ret = -ENODEV;
goto err;
}
if (pdata->sysclk == -1)
return -ENODEV;
}
#else
ret = of_property_read_u32(np, "clock-frequency", &pdata->sysclk);
if (ret)
goto err;
return ret;
#endif
prop = of_get_property(np, "mode", NULL);
@ -237,8 +235,4 @@ int of_mpc8xxx_spi_probe(struct platform_device *ofdev)
pdata->flags = SPI_CPM_MODE | SPI_CPM1;
return 0;
err:
kfree(pinfo);
return ret;
}

Просмотреть файл

@ -239,12 +239,6 @@ static int fsl_spi_setup_transfer(struct spi_device *spi,
if (!bits_per_word)
bits_per_word = spi->bits_per_word;
/* Make sure its a bit width we support [4..16, 32] */
if ((bits_per_word < 4)
|| ((bits_per_word > 16) && (bits_per_word != 32))
|| (bits_per_word > mpc8xxx_spi->max_bits_per_word))
return -EINVAL;
if (!hz)
hz = spi->max_speed_hz;
@ -362,18 +356,28 @@ static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
static void fsl_spi_do_one_msg(struct spi_message *m)
{
struct spi_device *spi = m->spi;
struct spi_transfer *t;
struct spi_transfer *t, *first;
unsigned int cs_change;
const int nsecs = 50;
int status;
/* Don't allow changes if CS is active */
first = list_first_entry(&m->transfers, struct spi_transfer,
transfer_list);
list_for_each_entry(t, &m->transfers, transfer_list) {
if ((first->bits_per_word != t->bits_per_word) ||
(first->speed_hz != t->speed_hz)) {
status = -EINVAL;
dev_err(&spi->dev,
"bits_per_word/speed_hz should be same for the same SPI transfer\n");
return;
}
}
cs_change = 1;
status = 0;
status = -EINVAL;
list_for_each_entry(t, &m->transfers, transfer_list) {
if (t->bits_per_word || t->speed_hz) {
/* Don't allow changes if CS is active */
status = -EINVAL;
if (cs_change)
status = fsl_spi_setup_transfer(spi, t);
if (status < 0)
@ -641,6 +645,10 @@ static struct spi_master * fsl_spi_probe(struct device *dev,
if (mpc8xxx_spi->type == TYPE_GRLIB)
fsl_spi_grlib_probe(dev);
master->bits_per_word_mask =
(SPI_BPW_RANGE_MASK(4, 16) | SPI_BPW_MASK(32)) &
SPI_BPW_RANGE_MASK(1, mpc8xxx_spi->max_bits_per_word);
if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE)
mpc8xxx_spi->set_shifts = fsl_spi_qe_cpu_set_shifts;

Просмотреть файл

@ -19,7 +19,6 @@
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/of.h>
@ -250,7 +249,7 @@ static int spi_gpio_setup(struct spi_device *spi)
/*
* ... otherwise, take it from spi->controller_data
*/
cs = (unsigned int) spi->controller_data;
cs = (unsigned int)(uintptr_t) spi->controller_data;
}
if (!spi->controller_state) {
@ -503,13 +502,12 @@ static int spi_gpio_remove(struct platform_device *pdev)
{
struct spi_gpio *spi_gpio;
struct spi_gpio_platform_data *pdata;
int status;
spi_gpio = platform_get_drvdata(pdev);
pdata = dev_get_platdata(&pdev->dev);
/* stop() unregisters child devices too */
status = spi_bitbang_stop(&spi_gpio->bitbang);
spi_bitbang_stop(&spi_gpio->bitbang);
if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO)
gpio_free(SPI_MISO_GPIO);
@ -518,7 +516,7 @@ static int spi_gpio_remove(struct platform_device *pdev)
gpio_free(SPI_SCK_GPIO);
spi_master_put(spi_gpio->bitbang.master);
return status;
return 0;
}
MODULE_ALIAS("platform:" DRIVER_NAME);

Просмотреть файл

@ -23,7 +23,6 @@
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
@ -741,7 +740,7 @@ static int spi_imx_transfer(struct spi_device *spi,
spi_imx->count = transfer->len;
spi_imx->txfifo = 0;
init_completion(&spi_imx->xfer_done);
reinit_completion(&spi_imx->xfer_done);
spi_imx_push(spi_imx);
@ -880,12 +879,12 @@ static int spi_imx_probe(struct platform_device *pdev)
spi_imx->irq = platform_get_irq(pdev, 0);
if (spi_imx->irq < 0) {
ret = -EINVAL;
ret = spi_imx->irq;
goto out_master_put;
}
ret = devm_request_irq(&pdev->dev, spi_imx->irq, spi_imx_isr, 0,
DRIVER_NAME, spi_imx);
dev_name(&pdev->dev), spi_imx);
if (ret) {
dev_err(&pdev->dev, "can't get irq%d: %d\n", spi_imx->irq, ret);
goto out_master_put;

Просмотреть файл

@ -16,7 +16,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/of_address.h>
@ -466,10 +465,8 @@ static void mpc512x_spi_cs_control(struct spi_device *spi, bool onoff)
gpio_set_value(spi->cs_gpio, onoff);
}
/* bus_num is used only for the case dev->platform_data == NULL */
static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
u32 size, unsigned int irq,
s16 bus_num)
u32 size, unsigned int irq)
{
struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
struct mpc512x_psc_spi *mps;
@ -488,7 +485,6 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
if (pdata == NULL) {
mps->cs_control = mpc512x_spi_cs_control;
master->bus_num = bus_num;
} else {
mps->cs_control = pdata->cs_control;
master->bus_num = pdata->bus_num;
@ -574,7 +570,6 @@ static int mpc512x_psc_spi_of_probe(struct platform_device *op)
{
const u32 *regaddr_p;
u64 regaddr64, size64;
s16 id = -1;
regaddr_p = of_get_address(op->dev.of_node, 0, &size64, NULL);
if (!regaddr_p) {
@ -583,16 +578,8 @@ static int mpc512x_psc_spi_of_probe(struct platform_device *op)
}
regaddr64 = of_translate_address(op->dev.of_node, regaddr_p);
/* get PSC id (0..11, used by port_config) */
id = of_alias_get_id(op->dev.of_node, "spi");
if (id < 0) {
dev_err(&op->dev, "no alias id for %s\n",
op->dev.of_node->full_name);
return id;
}
return mpc512x_psc_spi_do_probe(&op->dev, (u32) regaddr64, (u32) size64,
irq_of_parse_and_map(op->dev.of_node, 0), id);
irq_of_parse_and_map(op->dev.of_node, 0));
}
static int mpc512x_psc_spi_of_remove(struct platform_device *op)

Просмотреть файл

@ -12,7 +12,6 @@
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/interrupt.h>

Просмотреть файл

@ -12,7 +12,6 @@
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/of_platform.h>
#include <linux/interrupt.h>
@ -357,20 +356,6 @@ static void mpc52xx_spi_wq(struct work_struct *work)
* spi_master ops
*/
static int mpc52xx_spi_setup(struct spi_device *spi)
{
if (spi->bits_per_word % 8)
return -EINVAL;
if (spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST))
return -EINVAL;
if (spi->chip_select >= spi->master->num_chipselect)
return -EINVAL;
return 0;
}
static int mpc52xx_spi_transfer(struct spi_device *spi, struct spi_message *m)
{
struct mpc52xx_spi *ms = spi_master_get_devdata(spi->master);
@ -433,9 +418,9 @@ static int mpc52xx_spi_probe(struct platform_device *op)
goto err_alloc;
}
master->setup = mpc52xx_spi_setup;
master->transfer = mpc52xx_spi_transfer;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
master->bits_per_word_mask = SPI_BPW_MASK(8);
master->dev.of_node = op->dev.of_node;
platform_set_drvdata(op, master);

Просмотреть файл

@ -29,7 +29,6 @@
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/of.h>
#include <linux/of_device.h>
@ -371,7 +370,7 @@ static int mxs_spi_transfer_one(struct spi_master *master,
{
struct mxs_spi *spi = spi_master_get_devdata(master);
struct mxs_ssp *ssp = &spi->ssp;
struct spi_transfer *t, *tmp_t;
struct spi_transfer *t;
unsigned int flag;
int status = 0;
@ -381,7 +380,7 @@ static int mxs_spi_transfer_one(struct spi_master *master,
writel(mxs_spi_cs_to_reg(m->spi->chip_select),
ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET);
list_for_each_entry_safe(t, tmp_t, &m->transfers, transfer_list) {
list_for_each_entry(t, &m->transfers, transfer_list) {
status = mxs_spi_setup_transfer(m->spi, t);
if (status)
@ -473,7 +472,7 @@ static int mxs_spi_probe(struct platform_device *pdev)
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq_err = platform_get_irq(pdev, 0);
if (irq_err < 0)
return -EINVAL;
return irq_err;
base = devm_ioremap_resource(&pdev->dev, iores);
if (IS_ERR(base))

Просмотреть файл

@ -9,7 +9,6 @@
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
@ -38,7 +37,9 @@
/* usi register bit */
#define ENINT (0x01 << 17)
#define ENFLG (0x01 << 16)
#define SLEEP (0x0f << 12)
#define TXNUM (0x03 << 8)
#define TXBITLEN (0x1f << 3)
#define TXNEG (0x01 << 2)
#define RXNEG (0x01 << 1)
#define LSB (0x01 << 10)
@ -58,11 +59,8 @@ struct nuc900_spi {
unsigned char *rx;
struct clk *clk;
struct spi_master *master;
struct spi_device *curdev;
struct device *dev;
struct nuc900_spi_info *pdata;
spinlock_t lock;
struct resource *res;
};
static inline struct nuc900_spi *to_hw(struct spi_device *sdev)
@ -119,19 +117,16 @@ static void nuc900_spi_chipsel(struct spi_device *spi, int value)
}
}
static void nuc900_spi_setup_txnum(struct nuc900_spi *hw,
unsigned int txnum)
static void nuc900_spi_setup_txnum(struct nuc900_spi *hw, unsigned int txnum)
{
unsigned int val;
unsigned long flags;
spin_lock_irqsave(&hw->lock, flags);
val = __raw_readl(hw->regs + USI_CNT);
val = __raw_readl(hw->regs + USI_CNT) & ~TXNUM;
if (!txnum)
val &= ~TXNUM;
else
if (txnum)
val |= txnum << 0x08;
__raw_writel(val, hw->regs + USI_CNT);
@ -148,7 +143,7 @@ static void nuc900_spi_setup_txbitlen(struct nuc900_spi *hw,
spin_lock_irqsave(&hw->lock, flags);
val = __raw_readl(hw->regs + USI_CNT);
val = __raw_readl(hw->regs + USI_CNT) & ~TXBITLEN;
val |= (txbitlen << 0x03);
@ -287,12 +282,11 @@ static void nuc900_set_sleep(struct nuc900_spi *hw, unsigned int sleep)
spin_lock_irqsave(&hw->lock, flags);
val = __raw_readl(hw->regs + USI_CNT);
val = __raw_readl(hw->regs + USI_CNT) & ~SLEEP;
if (sleep)
val |= (sleep << 12);
else
val &= ~(0x0f << 12);
__raw_writel(val, hw->regs + USI_CNT);
spin_unlock_irqrestore(&hw->lock, flags);
@ -338,6 +332,7 @@ static int nuc900_spi_probe(struct platform_device *pdev)
{
struct nuc900_spi *hw;
struct spi_master *master;
struct resource *res;
int err = 0;
master = spi_alloc_master(&pdev->dev, sizeof(struct nuc900_spi));
@ -349,7 +344,6 @@ static int nuc900_spi_probe(struct platform_device *pdev)
hw = spi_master_get_devdata(master);
hw->master = master;
hw->pdata = dev_get_platdata(&pdev->dev);
hw->dev = &pdev->dev;
if (hw->pdata == NULL) {
dev_err(&pdev->dev, "No platform data supplied\n");
@ -369,8 +363,8 @@ static int nuc900_spi_probe(struct platform_device *pdev)
hw->bitbang.chipselect = nuc900_spi_chipsel;
hw->bitbang.txrx_bufs = nuc900_spi_txrx;
hw->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hw->regs = devm_ioremap_resource(&pdev->dev, hw->res);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hw->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(hw->regs)) {
err = PTR_ERR(hw->regs);
goto err_pdata;

Просмотреть файл

@ -15,7 +15,6 @@
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/errno.h>
#include <linux/module.h>
@ -267,8 +266,6 @@ static int tiny_spi_probe(struct platform_device *pdev)
/* setup the state for the bitbang driver */
hw->bitbang.master = master;
if (!hw->bitbang.master)
return err;
hw->bitbang.setup_transfer = tiny_spi_setup_transfer;
hw->bitbang.chipselect = tiny_spi_chipselect;
hw->bitbang.txrx_bufs = tiny_spi_txrx_bufs;

Просмотреть файл

@ -11,7 +11,6 @@
#include <linux/spi/spi.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/of.h>
@ -33,13 +32,6 @@ struct octeon_spi {
u64 cs_enax;
};
struct octeon_spi_setup {
u32 max_speed_hz;
u8 chip_select;
u8 mode;
u8 bits_per_word;
};
static void octeon_spi_wait_ready(struct octeon_spi *p)
{
union cvmx_mpi_sts mpi_sts;
@ -57,6 +49,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
struct spi_transfer *xfer,
bool last_xfer)
{
struct spi_device *spi = msg->spi;
union cvmx_mpi_cfg mpi_cfg;
union cvmx_mpi_tx mpi_tx;
unsigned int clkdiv;
@ -68,18 +61,11 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
int len;
int i;
struct octeon_spi_setup *msg_setup = spi_get_ctldata(msg->spi);
speed_hz = msg_setup->max_speed_hz;
mode = msg_setup->mode;
mode = spi->mode;
cpha = mode & SPI_CPHA;
cpol = mode & SPI_CPOL;
if (xfer->speed_hz)
speed_hz = xfer->speed_hz;
if (speed_hz > OCTEON_SPI_MAX_CLOCK_HZ)
speed_hz = OCTEON_SPI_MAX_CLOCK_HZ;
speed_hz = xfer->speed_hz ? : spi->max_speed_hz;
clkdiv = octeon_get_io_clock_rate() / (2 * speed_hz);
@ -93,8 +79,8 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
mpi_cfg.s.cslate = cpha ? 1 : 0;
mpi_cfg.s.enable = 1;
if (msg_setup->chip_select < 4)
p->cs_enax |= 1ull << (12 + msg_setup->chip_select);
if (spi->chip_select < 4)
p->cs_enax |= 1ull << (12 + spi->chip_select);
mpi_cfg.u64 |= p->cs_enax;
if (mpi_cfg.u64 != p->last_cfg) {
@ -114,7 +100,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
cvmx_write_csr(p->register_base + OCTEON_SPI_DAT0 + (8 * i), d);
}
mpi_tx.u64 = 0;
mpi_tx.s.csid = msg_setup->chip_select;
mpi_tx.s.csid = spi->chip_select;
mpi_tx.s.leavecs = 1;
mpi_tx.s.txnum = tx_buf ? OCTEON_SPI_MAX_BYTES : 0;
mpi_tx.s.totnum = OCTEON_SPI_MAX_BYTES;
@ -139,7 +125,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p,
}
mpi_tx.u64 = 0;
mpi_tx.s.csid = msg_setup->chip_select;
mpi_tx.s.csid = spi->chip_select;
if (last_xfer)
mpi_tx.s.leavecs = xfer->cs_change;
else
@ -169,17 +155,9 @@ static int octeon_spi_transfer_one_message(struct spi_master *master,
int status = 0;
struct spi_transfer *xfer;
/*
* We better have set the configuration via a call to .setup
* before we get here.
*/
if (spi_get_ctldata(msg->spi) == NULL) {
status = -EINVAL;
goto err;
}
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
bool last_xfer = &xfer->transfer_list == msg->transfers.prev;
bool last_xfer = list_is_last(&xfer->transfer_list,
&msg->transfers);
int r = octeon_spi_do_transfer(p, msg, xfer, last_xfer);
if (r < 0) {
status = r;
@ -194,41 +172,6 @@ err:
return status;
}
static struct octeon_spi_setup *octeon_spi_new_setup(struct spi_device *spi)
{
struct octeon_spi_setup *setup = kzalloc(sizeof(*setup), GFP_KERNEL);
if (!setup)
return NULL;
setup->max_speed_hz = spi->max_speed_hz;
setup->chip_select = spi->chip_select;
setup->mode = spi->mode;
setup->bits_per_word = spi->bits_per_word;
return setup;
}
static int octeon_spi_setup(struct spi_device *spi)
{
struct octeon_spi_setup *new_setup;
struct octeon_spi_setup *old_setup = spi_get_ctldata(spi);
new_setup = octeon_spi_new_setup(spi);
if (!new_setup)
return -ENOMEM;
spi_set_ctldata(spi, new_setup);
kfree(old_setup);
return 0;
}
static void octeon_spi_cleanup(struct spi_device *spi)
{
struct octeon_spi_setup *old_setup = spi_get_ctldata(spi);
spi_set_ctldata(spi, NULL);
kfree(old_setup);
}
static int octeon_spi_probe(struct platform_device *pdev)
{
struct resource *res_mem;
@ -257,8 +200,6 @@ static int octeon_spi_probe(struct platform_device *pdev)
p->register_base = (u64)devm_ioremap(&pdev->dev, res_mem->start,
resource_size(res_mem));
/* Dynamic bus numbering */
master->bus_num = -1;
master->num_chipselect = 4;
master->mode_bits = SPI_CPHA |
SPI_CPOL |
@ -266,10 +207,9 @@ static int octeon_spi_probe(struct platform_device *pdev)
SPI_LSB_FIRST |
SPI_3WIRE;
master->setup = octeon_spi_setup;
master->cleanup = octeon_spi_cleanup;
master->transfer_one_message = octeon_spi_transfer_one_message;
master->bits_per_word_mask = SPI_BPW_MASK(8);
master->max_speed_hz = OCTEON_SPI_MAX_CLOCK_HZ;
master->dev.of_node = pdev->dev.of_node;
err = devm_spi_register_master(&pdev->dev, master);

Просмотреть файл

@ -83,15 +83,11 @@
#define SPI_SHUTDOWN 1
struct omap1_spi100k {
struct spi_master *master;
struct clk *ick;
struct clk *fck;
/* Virtual base address of the controller */
void __iomem *base;
/* State of the SPI */
unsigned int state;
};
struct omap1_spi100k_cs {
@ -99,13 +95,6 @@ struct omap1_spi100k_cs {
int word_len;
};
#define MOD_REG_BIT(val, mask, set) do { \
if (set) \
val |= mask; \
else \
val &= ~mask; \
} while (0)
static void spi100k_enable_clock(struct spi_master *master)
{
unsigned int val;
@ -139,7 +128,7 @@ static void spi100k_write_data(struct spi_master *master, int len, int data)
}
spi100k_enable_clock(master);
writew( data , spi100k->base + SPI_TX_MSB);
writew(data , spi100k->base + SPI_TX_MSB);
writew(SPI_CTRL_SEN(0) |
SPI_CTRL_WORD_SIZE(len) |
@ -147,7 +136,8 @@ static void spi100k_write_data(struct spi_master *master, int len, int data)
spi100k->base + SPI_CTRL);
/* Wait for bit ack send change */
while((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_WE) != SPI_STATUS_WE);
while ((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_WE) != SPI_STATUS_WE)
;
udelay(1000);
spi100k_disable_clock(master);
@ -155,7 +145,7 @@ static void spi100k_write_data(struct spi_master *master, int len, int data)
static int spi100k_read_data(struct spi_master *master, int len)
{
int dataH,dataL;
int dataH, dataL;
struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
/* Always do at least 16 bits */
@ -168,7 +158,8 @@ static int spi100k_read_data(struct spi_master *master, int len)
SPI_CTRL_RD,
spi100k->base + SPI_CTRL);
while((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_RD) != SPI_STATUS_RD);
while ((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_RD) != SPI_STATUS_RD)
;
udelay(1000);
dataL = readw(spi100k->base + SPI_RX_LSB);
@ -204,12 +195,10 @@ static void omap1_spi100k_force_cs(struct omap1_spi100k *spi100k, int enable)
static unsigned
omap1_spi100k_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
{
struct omap1_spi100k *spi100k;
struct omap1_spi100k_cs *cs = spi->controller_state;
unsigned int count, c;
int word_len;
spi100k = spi_master_get_devdata(spi->master);
count = xfer->len;
c = count;
word_len = cs->word_len;
@ -221,12 +210,12 @@ omap1_spi100k_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
rx = xfer->rx_buf;
tx = xfer->tx_buf;
do {
c-=1;
c -= 1;
if (xfer->tx_buf != NULL)
spi100k_write_data(spi->master, word_len, *tx++);
if (xfer->rx_buf != NULL)
*rx++ = spi100k_read_data(spi->master, word_len);
} while(c);
} while (c);
} else if (word_len <= 16) {
u16 *rx;
const u16 *tx;
@ -234,12 +223,12 @@ omap1_spi100k_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
rx = xfer->rx_buf;
tx = xfer->tx_buf;
do {
c-=2;
c -= 2;
if (xfer->tx_buf != NULL)
spi100k_write_data(spi->master,word_len, *tx++);
spi100k_write_data(spi->master, word_len, *tx++);
if (xfer->rx_buf != NULL)
*rx++ = spi100k_read_data(spi->master,word_len);
} while(c);
*rx++ = spi100k_read_data(spi->master, word_len);
} while (c);
} else if (word_len <= 32) {
u32 *rx;
const u32 *tx;
@ -247,12 +236,12 @@ omap1_spi100k_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
rx = xfer->rx_buf;
tx = xfer->tx_buf;
do {
c-=4;
c -= 4;
if (xfer->tx_buf != NULL)
spi100k_write_data(spi->master,word_len, *tx);
spi100k_write_data(spi->master, word_len, *tx);
if (xfer->rx_buf != NULL)
*rx = spi100k_read_data(spi->master,word_len);
} while(c);
*rx = spi100k_read_data(spi->master, word_len);
} while (c);
}
return count - c;
}
@ -294,7 +283,7 @@ static int omap1_spi100k_setup(struct spi_device *spi)
spi100k = spi_master_get_devdata(spi->master);
if (!cs) {
cs = kzalloc(sizeof *cs, GFP_KERNEL);
cs = devm_kzalloc(&spi->dev, sizeof(*cs), GFP_KERNEL);
if (!cs)
return -ENOMEM;
cs->base = spi100k->base + spi->chip_select * 0x14;
@ -411,14 +400,14 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
if (!pdev->id)
return -EINVAL;
master = spi_alloc_master(&pdev->dev, sizeof *spi100k);
master = spi_alloc_master(&pdev->dev, sizeof(*spi100k));
if (master == NULL) {
dev_dbg(&pdev->dev, "master allocation failed\n");
return -ENOMEM;
}
if (pdev->id != -1)
master->bus_num = pdev->id;
master->bus_num = pdev->id;
master->setup = omap1_spi100k_setup;
master->transfer_one_message = omap1_spi100k_transfer_one_message;
@ -434,7 +423,6 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, master);
spi100k = spi_master_get_devdata(master);
spi100k->master = master;
/*
* The memory region base address is taken as the platform_data.
@ -461,8 +449,6 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
if (status < 0)
goto err;
spi100k->state = SPI_RUNNING;
return status;
err:

Просмотреть файл

@ -99,7 +99,6 @@ struct uwire_spi {
};
struct uwire_state {
unsigned bits_per_word;
unsigned div1_idx;
};
@ -210,9 +209,8 @@ static void uwire_chipselect(struct spi_device *spi, int value)
static int uwire_txrx(struct spi_device *spi, struct spi_transfer *t)
{
struct uwire_state *ust = spi->controller_state;
unsigned len = t->len;
unsigned bits = ust->bits_per_word;
unsigned bits = t->bits_per_word ? : spi->bits_per_word;
unsigned bytes;
u16 val, w;
int status = 0;
@ -220,10 +218,6 @@ static int uwire_txrx(struct spi_device *spi, struct spi_transfer *t)
if (!t->tx_buf && !t->rx_buf)
return 0;
/* Microwire doesn't read and write concurrently */
if (t->tx_buf && t->rx_buf)
return -EPERM;
w = spi->chip_select << 10;
w |= CS_CMD;
@ -322,7 +316,6 @@ static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
struct uwire_state *ust = spi->controller_state;
struct uwire_spi *uwire;
unsigned flags = 0;
unsigned bits;
unsigned hz;
unsigned long rate;
int div1_idx;
@ -332,23 +325,6 @@ static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
uwire = spi_master_get_devdata(spi->master);
if (spi->chip_select > 3) {
pr_debug("%s: cs%d?\n", dev_name(&spi->dev), spi->chip_select);
status = -ENODEV;
goto done;
}
bits = spi->bits_per_word;
if (t != NULL && t->bits_per_word)
bits = t->bits_per_word;
if (bits > 16) {
pr_debug("%s: wordsize %d?\n", dev_name(&spi->dev), bits);
status = -ENODEV;
goto done;
}
ust->bits_per_word = bits;
/* mode 0..3, clock inverted separately;
* standard nCS signaling;
* don't treat DI=high as "not ready"
@ -502,6 +478,7 @@ static int uwire_probe(struct platform_device *pdev)
status = PTR_ERR(uwire->ck);
dev_dbg(&pdev->dev, "no functional clock?\n");
spi_master_put(master);
iounmap(uwire_base);
return status;
}
clk_enable(uwire->ck);
@ -515,7 +492,7 @@ static int uwire_probe(struct platform_device *pdev)
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
master->flags = SPI_MASTER_HALF_DUPLEX;
master->bus_num = 2; /* "official" */
@ -539,14 +516,13 @@ static int uwire_probe(struct platform_device *pdev)
static int uwire_remove(struct platform_device *pdev)
{
struct uwire_spi *uwire = platform_get_drvdata(pdev);
int status;
// FIXME remove all child devices, somewhere ...
status = spi_bitbang_stop(&uwire->bitbang);
spi_bitbang_stop(&uwire->bitbang);
uwire_off(uwire);
iounmap(uwire_base);
return status;
return 0;
}
/* work with hotplug and coldplug */

Просмотреть файл

@ -22,7 +22,6 @@
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/device.h>
@ -45,6 +44,7 @@
#include <linux/platform_data/spi-omap2-mcspi.h>
#define OMAP2_MCSPI_MAX_FREQ 48000000
#define OMAP2_MCSPI_MAX_DIVIDER 4096
#define OMAP2_MCSPI_MAX_FIFODEPTH 64
#define OMAP2_MCSPI_MAX_FIFOWCNT 0xFFFF
#define SPI_AUTOSUSPEND_TIMEOUT 2000
@ -89,6 +89,7 @@
#define OMAP2_MCSPI_CHCONF_FORCE BIT(20)
#define OMAP2_MCSPI_CHCONF_FFET BIT(27)
#define OMAP2_MCSPI_CHCONF_FFER BIT(28)
#define OMAP2_MCSPI_CHCONF_CLKG BIT(29)
#define OMAP2_MCSPI_CHSTAT_RXS BIT(0)
#define OMAP2_MCSPI_CHSTAT_TXS BIT(1)
@ -96,6 +97,7 @@
#define OMAP2_MCSPI_CHSTAT_TXFFE BIT(3)
#define OMAP2_MCSPI_CHCTRL_EN BIT(0)
#define OMAP2_MCSPI_CHCTRL_EXTCLK_MASK (0xff << 8)
#define OMAP2_MCSPI_WAKEUPENABLE_WKEN BIT(0)
@ -149,7 +151,7 @@ struct omap2_mcspi_cs {
int word_len;
struct list_head node;
/* Context save and restore shadow register */
u32 chconf0;
u32 chconf0, chctrl0;
};
static inline void mcspi_write_reg(struct spi_master *master,
@ -230,10 +232,16 @@ static void omap2_mcspi_set_dma_req(const struct spi_device *spi,
static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable)
{
struct omap2_mcspi_cs *cs = spi->controller_state;
u32 l;
l = enable ? OMAP2_MCSPI_CHCTRL_EN : 0;
mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, l);
l = cs->chctrl0;
if (enable)
l |= OMAP2_MCSPI_CHCTRL_EN;
else
l &= ~OMAP2_MCSPI_CHCTRL_EN;
cs->chctrl0 = l;
mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, cs->chctrl0);
/* Flash post-writes */
mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCTRL0);
}
@ -840,7 +848,7 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
struct omap2_mcspi_cs *cs = spi->controller_state;
struct omap2_mcspi *mcspi;
struct spi_master *spi_cntrl;
u32 l = 0, div = 0;
u32 l = 0, clkd = 0, div, extclk = 0, clkg = 0;
u8 word_len = spi->bits_per_word;
u32 speed_hz = spi->max_speed_hz;
@ -856,7 +864,17 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
speed_hz = t->speed_hz;
speed_hz = min_t(u32, speed_hz, OMAP2_MCSPI_MAX_FREQ);
div = omap2_mcspi_calc_divisor(speed_hz);
if (speed_hz < (OMAP2_MCSPI_MAX_FREQ / OMAP2_MCSPI_MAX_DIVIDER)) {
clkd = omap2_mcspi_calc_divisor(speed_hz);
speed_hz = OMAP2_MCSPI_MAX_FREQ >> clkd;
clkg = 0;
} else {
div = (OMAP2_MCSPI_MAX_FREQ + speed_hz - 1) / speed_hz;
speed_hz = OMAP2_MCSPI_MAX_FREQ / div;
clkd = (div - 1) & 0xf;
extclk = (div - 1) >> 4;
clkg = OMAP2_MCSPI_CHCONF_CLKG;
}
l = mcspi_cached_chconf0(spi);
@ -885,7 +903,16 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
/* set clock divisor */
l &= ~OMAP2_MCSPI_CHCONF_CLKD_MASK;
l |= div << 2;
l |= clkd << 2;
/* set clock granularity */
l &= ~OMAP2_MCSPI_CHCONF_CLKG;
l |= clkg;
if (clkg) {
cs->chctrl0 &= ~OMAP2_MCSPI_CHCTRL_EXTCLK_MASK;
cs->chctrl0 |= extclk << 8;
mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, cs->chctrl0);
}
/* set SPI mode 0..3 */
if (spi->mode & SPI_CPOL)
@ -900,7 +927,7 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
mcspi_write_chconf0(spi, l);
dev_dbg(&spi->dev, "setup: speed %d, sample %s edge, clk %s\n",
OMAP2_MCSPI_MAX_FREQ >> div,
speed_hz,
(spi->mode & SPI_CPHA) ? "trailing" : "leading",
(spi->mode & SPI_CPOL) ? "inverted" : "normal");
@ -972,6 +999,7 @@ static int omap2_mcspi_setup(struct spi_device *spi)
cs->base = mcspi->base + spi->chip_select * 0x14;
cs->phys = mcspi->phys + spi->chip_select * 0x14;
cs->chconf0 = 0;
cs->chctrl0 = 0;
spi->controller_state = cs;
/* Link this to context save list */
list_add_tail(&cs->node, &ctx->cs);
@ -1057,12 +1085,15 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
status = -EINVAL;
break;
}
if (par_override || t->speed_hz || t->bits_per_word) {
if (par_override ||
(t->speed_hz != spi->max_speed_hz) ||
(t->bits_per_word != spi->bits_per_word)) {
par_override = 1;
status = omap2_mcspi_setup_transfer(spi, t);
if (status < 0)
break;
if (!t->speed_hz && !t->bits_per_word)
if (t->speed_hz == spi->max_speed_hz &&
t->bits_per_word == spi->bits_per_word)
par_override = 0;
}
if (cd && cd->cs_per_word) {
@ -1176,16 +1207,12 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master,
m->actual_length = 0;
m->status = 0;
/* reject invalid messages and transfers */
if (list_empty(&m->transfers))
return -EINVAL;
list_for_each_entry(t, &m->transfers, transfer_list) {
const void *tx_buf = t->tx_buf;
void *rx_buf = t->rx_buf;
unsigned len = t->len;
if (t->speed_hz > OMAP2_MCSPI_MAX_FREQ
|| (len && !(rx_buf || tx_buf))) {
if ((len && !(rx_buf || tx_buf))) {
dev_dbg(mcspi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
t->speed_hz,
len,
@ -1194,12 +1221,6 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master,
t->bits_per_word);
return -EINVAL;
}
if (t->speed_hz && t->speed_hz < (OMAP2_MCSPI_MAX_FREQ >> 15)) {
dev_dbg(mcspi->dev, "speed_hz %d below minimum %d Hz\n",
t->speed_hz,
OMAP2_MCSPI_MAX_FREQ >> 15);
return -EINVAL;
}
if (m->is_dma_mapped || len < DMA_MIN_BYTES)
continue;
@ -1311,6 +1332,8 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
master->transfer_one_message = omap2_mcspi_transfer_one_message;
master->cleanup = omap2_mcspi_cleanup;
master->dev.of_node = node;
master->max_speed_hz = OMAP2_MCSPI_MAX_FREQ;
master->min_speed_hz = OMAP2_MCSPI_MAX_FREQ >> 15;
platform_set_drvdata(pdev, master);

Просмотреть файл

@ -9,7 +9,6 @@
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
@ -43,8 +42,6 @@
struct orion_spi {
struct spi_master *master;
void __iomem *base;
unsigned int max_speed;
unsigned int min_speed;
struct clk *clk;
};
@ -75,23 +72,6 @@ orion_spi_clrbits(struct orion_spi *orion_spi, u32 reg, u32 mask)
writel(val, reg_addr);
}
static int orion_spi_set_transfer_size(struct orion_spi *orion_spi, int size)
{
if (size == 16) {
orion_spi_setbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
ORION_SPI_IF_8_16_BIT_MODE);
} else if (size == 8) {
orion_spi_clrbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
ORION_SPI_IF_8_16_BIT_MODE);
} else {
pr_debug("Bad bits per word value %d (only 8 or 16 are allowed).\n",
size);
return -EINVAL;
}
return 0;
}
static int orion_spi_baudrate_set(struct spi_device *spi, unsigned int speed)
{
u32 tclk_hz;
@ -170,7 +150,14 @@ orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
if (rc)
return rc;
return orion_spi_set_transfer_size(orion_spi, bits_per_word);
if (bits_per_word == 16)
orion_spi_setbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
ORION_SPI_IF_8_16_BIT_MODE);
else
orion_spi_clrbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
ORION_SPI_IF_8_16_BIT_MODE);
return 0;
}
static void orion_spi_set_cs(struct orion_spi *orion_spi, int enable)
@ -260,11 +247,9 @@ orion_spi_write_read_16bit(struct spi_device *spi,
static unsigned int
orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
{
struct orion_spi *orion_spi;
unsigned int count;
int word_len;
orion_spi = spi_master_get_devdata(spi->master);
word_len = spi->bits_per_word;
count = xfer->len;
@ -310,27 +295,6 @@ static int orion_spi_transfer_one_message(struct spi_master *master,
goto msg_done;
list_for_each_entry(t, &m->transfers, transfer_list) {
/* make sure buffer length is even when working in 16
* bit mode*/
if ((t->bits_per_word == 16) && (t->len & 1)) {
dev_err(&spi->dev,
"message rejected : "
"odd data length %d while in 16 bit mode\n",
t->len);
status = -EIO;
goto msg_done;
}
if (t->speed_hz && t->speed_hz < orion_spi->min_speed) {
dev_err(&spi->dev,
"message rejected : "
"device min speed (%d Hz) exceeds "
"required transfer speed (%d Hz)\n",
orion_spi->min_speed, t->speed_hz);
status = -EIO;
goto msg_done;
}
if (par_override || t->speed_hz || t->bits_per_word) {
par_override = 1;
status = orion_spi_setup_transfer(spi, t);
@ -375,28 +339,6 @@ static int orion_spi_reset(struct orion_spi *orion_spi)
return 0;
}
static int orion_spi_setup(struct spi_device *spi)
{
struct orion_spi *orion_spi;
orion_spi = spi_master_get_devdata(spi->master);
if ((spi->max_speed_hz == 0)
|| (spi->max_speed_hz > orion_spi->max_speed))
spi->max_speed_hz = orion_spi->max_speed;
if (spi->max_speed_hz < orion_spi->min_speed) {
dev_err(&spi->dev, "setup: requested speed too low %d Hz\n",
spi->max_speed_hz);
return -EINVAL;
}
/*
* baudrate & width will be set orion_spi_setup_transfer
*/
return 0;
}
static int orion_spi_probe(struct platform_device *pdev)
{
struct spi_master *master;
@ -425,9 +367,9 @@ static int orion_spi_probe(struct platform_device *pdev)
/* we support only mode 0, and no options */
master->mode_bits = SPI_CPHA | SPI_CPOL;
master->setup = orion_spi_setup;
master->transfer_one_message = orion_spi_transfer_one_message;
master->num_chipselect = ORION_NUM_CHIPSELECTS;
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
platform_set_drvdata(pdev, master);
@ -443,8 +385,8 @@ static int orion_spi_probe(struct platform_device *pdev)
clk_prepare(spi->clk);
clk_enable(spi->clk);
tclk_hz = clk_get_rate(spi->clk);
spi->max_speed = DIV_ROUND_UP(tclk_hz, 4);
spi->min_speed = DIV_ROUND_UP(tclk_hz, 30);
master->max_speed_hz = DIV_ROUND_UP(tclk_hz, 4);
master->min_speed_hz = DIV_ROUND_UP(tclk_hz, 30);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
spi->base = devm_ioremap_resource(&pdev->dev, r);

Просмотреть файл

@ -459,9 +459,8 @@ static void giveback(struct pl022 *pl022)
struct spi_transfer *last_transfer;
pl022->next_msg_cs_active = false;
last_transfer = list_entry(pl022->cur_msg->transfers.prev,
struct spi_transfer,
transfer_list);
last_transfer = list_last_entry(&pl022->cur_msg->transfers,
struct spi_transfer, transfer_list);
/* Delay if requested before any change in chip select */
if (last_transfer->delay_usecs)
@ -2109,8 +2108,6 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
pl022->chipselects = devm_kzalloc(dev, num_cs * sizeof(int),
GFP_KERNEL);
pinctrl_pm_select_default_state(dev);
/*
* Bus Number Which has been Assigned to this SSP controller
* on this board
@ -2183,13 +2180,7 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
goto err_no_clk;
}
status = clk_prepare(pl022->clk);
if (status) {
dev_err(&adev->dev, "could not prepare SSP/SPI bus clock\n");
goto err_clk_prep;
}
status = clk_enable(pl022->clk);
status = clk_prepare_enable(pl022->clk);
if (status) {
dev_err(&adev->dev, "could not enable SSP/SPI bus clock\n");
goto err_no_clk_en;
@ -2250,10 +2241,8 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
if (platform_info->enable_dma)
pl022_dma_remove(pl022);
err_no_irq:
clk_disable(pl022->clk);
clk_disable_unprepare(pl022->clk);
err_no_clk_en:
clk_unprepare(pl022->clk);
err_clk_prep:
err_no_clk:
err_no_ioremap:
amba_release_regions(adev);
@ -2281,42 +2270,13 @@ pl022_remove(struct amba_device *adev)
if (pl022->master_info->enable_dma)
pl022_dma_remove(pl022);
clk_disable(pl022->clk);
clk_unprepare(pl022->clk);
clk_disable_unprepare(pl022->clk);
amba_release_regions(adev);
tasklet_disable(&pl022->pump_transfers);
return 0;
}
#if defined(CONFIG_SUSPEND) || defined(CONFIG_PM_RUNTIME)
/*
* These two functions are used from both suspend/resume and
* the runtime counterparts to handle external resources like
* clocks, pins and regulators when going to sleep.
*/
static void pl022_suspend_resources(struct pl022 *pl022, bool runtime)
{
clk_disable(pl022->clk);
if (runtime)
pinctrl_pm_select_idle_state(&pl022->adev->dev);
else
pinctrl_pm_select_sleep_state(&pl022->adev->dev);
}
static void pl022_resume_resources(struct pl022 *pl022, bool runtime)
{
/* First go to the default state */
pinctrl_pm_select_default_state(&pl022->adev->dev);
if (!runtime)
/* Then let's idle the pins until the next transfer happens */
pinctrl_pm_select_idle_state(&pl022->adev->dev);
clk_enable(pl022->clk);
}
#endif
#ifdef CONFIG_SUSPEND
#ifdef CONFIG_PM_SLEEP
static int pl022_suspend(struct device *dev)
{
struct pl022 *pl022 = dev_get_drvdata(dev);
@ -2328,8 +2288,13 @@ static int pl022_suspend(struct device *dev)
return ret;
}
pm_runtime_get_sync(dev);
pl022_suspend_resources(pl022, false);
ret = pm_runtime_force_suspend(dev);
if (ret) {
spi_master_resume(pl022->master);
return ret;
}
pinctrl_pm_select_sleep_state(dev);
dev_dbg(dev, "suspended\n");
return 0;
@ -2340,8 +2305,9 @@ static int pl022_resume(struct device *dev)
struct pl022 *pl022 = dev_get_drvdata(dev);
int ret;
pl022_resume_resources(pl022, false);
pm_runtime_put(dev);
ret = pm_runtime_force_resume(dev);
if (ret)
dev_err(dev, "problem resuming\n");
/* Start the queue running */
ret = spi_master_resume(pl022->master);
@ -2352,14 +2318,16 @@ static int pl022_resume(struct device *dev)
return ret;
}
#endif /* CONFIG_PM */
#endif
#ifdef CONFIG_PM_RUNTIME
#ifdef CONFIG_PM
static int pl022_runtime_suspend(struct device *dev)
{
struct pl022 *pl022 = dev_get_drvdata(dev);
pl022_suspend_resources(pl022, true);
clk_disable_unprepare(pl022->clk);
pinctrl_pm_select_idle_state(dev);
return 0;
}
@ -2367,14 +2335,16 @@ static int pl022_runtime_resume(struct device *dev)
{
struct pl022 *pl022 = dev_get_drvdata(dev);
pl022_resume_resources(pl022, true);
pinctrl_pm_select_default_state(dev);
clk_prepare_enable(pl022->clk);
return 0;
}
#endif
static const struct dev_pm_ops pl022_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pl022_suspend, pl022_resume)
SET_RUNTIME_PM_OPS(pl022_runtime_suspend, pl022_runtime_resume, NULL)
SET_PM_RUNTIME_PM_OPS(pl022_runtime_suspend, pl022_runtime_resume, NULL)
};
static struct vendor_data vendor_arm = {

Просмотреть файл

@ -24,7 +24,6 @@
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/errno.h>

Просмотреть файл

@ -9,7 +9,6 @@
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>

Просмотреть файл

@ -18,7 +18,6 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>

Просмотреть файл

@ -362,8 +362,7 @@ static void giveback(struct driver_data *drv_data)
drv_data->cur_msg = NULL;
drv_data->cur_transfer = NULL;
last_transfer = list_entry(msg->transfers.prev,
struct spi_transfer,
last_transfer = list_last_entry(&msg->transfers, struct spi_transfer,
transfer_list);
/* Delay if requested before any change in chip select */

779
drivers/spi/spi-qup.c Normal file
Просмотреть файл

@ -0,0 +1,779 @@
/*
* Copyright (c) 2008-2014, The Linux foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License rev 2 and
* only rev 2 as published by the free Software foundation.
*
* 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.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/spi/spi.h>
#define QUP_CONFIG 0x0000
#define QUP_STATE 0x0004
#define QUP_IO_M_MODES 0x0008
#define QUP_SW_RESET 0x000c
#define QUP_OPERATIONAL 0x0018
#define QUP_ERROR_FLAGS 0x001c
#define QUP_ERROR_FLAGS_EN 0x0020
#define QUP_OPERATIONAL_MASK 0x0028
#define QUP_HW_VERSION 0x0030
#define QUP_MX_OUTPUT_CNT 0x0100
#define QUP_OUTPUT_FIFO 0x0110
#define QUP_MX_WRITE_CNT 0x0150
#define QUP_MX_INPUT_CNT 0x0200
#define QUP_MX_READ_CNT 0x0208
#define QUP_INPUT_FIFO 0x0218
#define SPI_CONFIG 0x0300
#define SPI_IO_CONTROL 0x0304
#define SPI_ERROR_FLAGS 0x0308
#define SPI_ERROR_FLAGS_EN 0x030c
/* QUP_CONFIG fields */
#define QUP_CONFIG_SPI_MODE (1 << 8)
#define QUP_CONFIG_CLOCK_AUTO_GATE BIT(13)
#define QUP_CONFIG_NO_INPUT BIT(7)
#define QUP_CONFIG_NO_OUTPUT BIT(6)
#define QUP_CONFIG_N 0x001f
/* QUP_STATE fields */
#define QUP_STATE_VALID BIT(2)
#define QUP_STATE_RESET 0
#define QUP_STATE_RUN 1
#define QUP_STATE_PAUSE 3
#define QUP_STATE_MASK 3
#define QUP_STATE_CLEAR 2
#define QUP_HW_VERSION_2_1_1 0x20010001
/* QUP_IO_M_MODES fields */
#define QUP_IO_M_PACK_EN BIT(15)
#define QUP_IO_M_UNPACK_EN BIT(14)
#define QUP_IO_M_INPUT_MODE_MASK_SHIFT 12
#define QUP_IO_M_OUTPUT_MODE_MASK_SHIFT 10
#define QUP_IO_M_INPUT_MODE_MASK (3 << QUP_IO_M_INPUT_MODE_MASK_SHIFT)
#define QUP_IO_M_OUTPUT_MODE_MASK (3 << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT)
#define QUP_IO_M_OUTPUT_BLOCK_SIZE(x) (((x) & (0x03 << 0)) >> 0)
#define QUP_IO_M_OUTPUT_FIFO_SIZE(x) (((x) & (0x07 << 2)) >> 2)
#define QUP_IO_M_INPUT_BLOCK_SIZE(x) (((x) & (0x03 << 5)) >> 5)
#define QUP_IO_M_INPUT_FIFO_SIZE(x) (((x) & (0x07 << 7)) >> 7)
#define QUP_IO_M_MODE_FIFO 0
#define QUP_IO_M_MODE_BLOCK 1
#define QUP_IO_M_MODE_DMOV 2
#define QUP_IO_M_MODE_BAM 3
/* QUP_OPERATIONAL fields */
#define QUP_OP_MAX_INPUT_DONE_FLAG BIT(11)
#define QUP_OP_MAX_OUTPUT_DONE_FLAG BIT(10)
#define QUP_OP_IN_SERVICE_FLAG BIT(9)
#define QUP_OP_OUT_SERVICE_FLAG BIT(8)
#define QUP_OP_IN_FIFO_FULL BIT(7)
#define QUP_OP_OUT_FIFO_FULL BIT(6)
#define QUP_OP_IN_FIFO_NOT_EMPTY BIT(5)
#define QUP_OP_OUT_FIFO_NOT_EMPTY BIT(4)
/* QUP_ERROR_FLAGS and QUP_ERROR_FLAGS_EN fields */
#define QUP_ERROR_OUTPUT_OVER_RUN BIT(5)
#define QUP_ERROR_INPUT_UNDER_RUN BIT(4)
#define QUP_ERROR_OUTPUT_UNDER_RUN BIT(3)
#define QUP_ERROR_INPUT_OVER_RUN BIT(2)
/* SPI_CONFIG fields */
#define SPI_CONFIG_HS_MODE BIT(10)
#define SPI_CONFIG_INPUT_FIRST BIT(9)
#define SPI_CONFIG_LOOPBACK BIT(8)
/* SPI_IO_CONTROL fields */
#define SPI_IO_C_FORCE_CS BIT(11)
#define SPI_IO_C_CLK_IDLE_HIGH BIT(10)
#define SPI_IO_C_MX_CS_MODE BIT(8)
#define SPI_IO_C_CS_N_POLARITY_0 BIT(4)
#define SPI_IO_C_CS_SELECT(x) (((x) & 3) << 2)
#define SPI_IO_C_CS_SELECT_MASK 0x000c
#define SPI_IO_C_TRISTATE_CS BIT(1)
#define SPI_IO_C_NO_TRI_STATE BIT(0)
/* SPI_ERROR_FLAGS and SPI_ERROR_FLAGS_EN fields */
#define SPI_ERROR_CLK_OVER_RUN BIT(1)
#define SPI_ERROR_CLK_UNDER_RUN BIT(0)
#define SPI_NUM_CHIPSELECTS 4
/* high speed mode is when bus rate is greater then 26MHz */
#define SPI_HS_MIN_RATE 26000000
#define SPI_MAX_RATE 50000000
#define SPI_DELAY_THRESHOLD 1
#define SPI_DELAY_RETRY 10
struct spi_qup {
void __iomem *base;
struct device *dev;
struct clk *cclk; /* core clock */
struct clk *iclk; /* interface clock */
int irq;
spinlock_t lock;
int in_fifo_sz;
int out_fifo_sz;
int in_blk_sz;
int out_blk_sz;
struct spi_transfer *xfer;
struct completion done;
int error;
int w_size; /* bytes per SPI word */
int tx_bytes;
int rx_bytes;
};
static inline bool spi_qup_is_valid_state(struct spi_qup *controller)
{
u32 opstate = readl_relaxed(controller->base + QUP_STATE);
return opstate & QUP_STATE_VALID;
}
static int spi_qup_set_state(struct spi_qup *controller, u32 state)
{
unsigned long loop;
u32 cur_state;
loop = 0;
while (!spi_qup_is_valid_state(controller)) {
usleep_range(SPI_DELAY_THRESHOLD, SPI_DELAY_THRESHOLD * 2);
if (++loop > SPI_DELAY_RETRY)
return -EIO;
}
if (loop)
dev_dbg(controller->dev, "invalid state for %ld,us %d\n",
loop, state);
cur_state = readl_relaxed(controller->base + QUP_STATE);
/*
* Per spec: for PAUSE_STATE to RESET_STATE, two writes
* of (b10) are required
*/
if (((cur_state & QUP_STATE_MASK) == QUP_STATE_PAUSE) &&
(state == QUP_STATE_RESET)) {
writel_relaxed(QUP_STATE_CLEAR, controller->base + QUP_STATE);
writel_relaxed(QUP_STATE_CLEAR, controller->base + QUP_STATE);
} else {
cur_state &= ~QUP_STATE_MASK;
cur_state |= state;
writel_relaxed(cur_state, controller->base + QUP_STATE);
}
loop = 0;
while (!spi_qup_is_valid_state(controller)) {
usleep_range(SPI_DELAY_THRESHOLD, SPI_DELAY_THRESHOLD * 2);
if (++loop > SPI_DELAY_RETRY)
return -EIO;
}
return 0;
}
static void spi_qup_fifo_read(struct spi_qup *controller,
struct spi_transfer *xfer)
{
u8 *rx_buf = xfer->rx_buf;
u32 word, state;
int idx, shift, w_size;
w_size = controller->w_size;
while (controller->rx_bytes < xfer->len) {
state = readl_relaxed(controller->base + QUP_OPERATIONAL);
if (0 == (state & QUP_OP_IN_FIFO_NOT_EMPTY))
break;
word = readl_relaxed(controller->base + QUP_INPUT_FIFO);
if (!rx_buf) {
controller->rx_bytes += w_size;
continue;
}
for (idx = 0; idx < w_size; idx++, controller->rx_bytes++) {
/*
* The data format depends on bytes per SPI word:
* 4 bytes: 0x12345678
* 2 bytes: 0x00001234
* 1 byte : 0x00000012
*/
shift = BITS_PER_BYTE;
shift *= (w_size - idx - 1);
rx_buf[controller->rx_bytes] = word >> shift;
}
}
}
static void spi_qup_fifo_write(struct spi_qup *controller,
struct spi_transfer *xfer)
{
const u8 *tx_buf = xfer->tx_buf;
u32 word, state, data;
int idx, w_size;
w_size = controller->w_size;
while (controller->tx_bytes < xfer->len) {
state = readl_relaxed(controller->base + QUP_OPERATIONAL);
if (state & QUP_OP_OUT_FIFO_FULL)
break;
word = 0;
for (idx = 0; idx < w_size; idx++, controller->tx_bytes++) {
if (!tx_buf) {
controller->tx_bytes += w_size;
break;
}
data = tx_buf[controller->tx_bytes];
word |= data << (BITS_PER_BYTE * (3 - idx));
}
writel_relaxed(word, controller->base + QUP_OUTPUT_FIFO);
}
}
static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
{
struct spi_qup *controller = dev_id;
struct spi_transfer *xfer;
u32 opflags, qup_err, spi_err;
unsigned long flags;
int error = 0;
spin_lock_irqsave(&controller->lock, flags);
xfer = controller->xfer;
controller->xfer = NULL;
spin_unlock_irqrestore(&controller->lock, flags);
qup_err = readl_relaxed(controller->base + QUP_ERROR_FLAGS);
spi_err = readl_relaxed(controller->base + SPI_ERROR_FLAGS);
opflags = readl_relaxed(controller->base + QUP_OPERATIONAL);
writel_relaxed(qup_err, controller->base + QUP_ERROR_FLAGS);
writel_relaxed(spi_err, controller->base + SPI_ERROR_FLAGS);
writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
if (!xfer) {
dev_err_ratelimited(controller->dev, "unexpected irq %x08 %x08 %x08\n",
qup_err, spi_err, opflags);
return IRQ_HANDLED;
}
if (qup_err) {
if (qup_err & QUP_ERROR_OUTPUT_OVER_RUN)
dev_warn(controller->dev, "OUTPUT_OVER_RUN\n");
if (qup_err & QUP_ERROR_INPUT_UNDER_RUN)
dev_warn(controller->dev, "INPUT_UNDER_RUN\n");
if (qup_err & QUP_ERROR_OUTPUT_UNDER_RUN)
dev_warn(controller->dev, "OUTPUT_UNDER_RUN\n");
if (qup_err & QUP_ERROR_INPUT_OVER_RUN)
dev_warn(controller->dev, "INPUT_OVER_RUN\n");
error = -EIO;
}
if (spi_err) {
if (spi_err & SPI_ERROR_CLK_OVER_RUN)
dev_warn(controller->dev, "CLK_OVER_RUN\n");
if (spi_err & SPI_ERROR_CLK_UNDER_RUN)
dev_warn(controller->dev, "CLK_UNDER_RUN\n");
error = -EIO;
}
if (opflags & QUP_OP_IN_SERVICE_FLAG)
spi_qup_fifo_read(controller, xfer);
if (opflags & QUP_OP_OUT_SERVICE_FLAG)
spi_qup_fifo_write(controller, xfer);
spin_lock_irqsave(&controller->lock, flags);
controller->error = error;
controller->xfer = xfer;
spin_unlock_irqrestore(&controller->lock, flags);
if (controller->rx_bytes == xfer->len || error)
complete(&controller->done);
return IRQ_HANDLED;
}
/* set clock freq ... bits per word */
static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
{
struct spi_qup *controller = spi_master_get_devdata(spi->master);
u32 config, iomode, mode;
int ret, n_words, w_size;
if (spi->mode & SPI_LOOP && xfer->len > controller->in_fifo_sz) {
dev_err(controller->dev, "too big size for loopback %d > %d\n",
xfer->len, controller->in_fifo_sz);
return -EIO;
}
ret = clk_set_rate(controller->cclk, xfer->speed_hz);
if (ret) {
dev_err(controller->dev, "fail to set frequency %d",
xfer->speed_hz);
return -EIO;
}
if (spi_qup_set_state(controller, QUP_STATE_RESET)) {
dev_err(controller->dev, "cannot set RESET state\n");
return -EIO;
}
w_size = 4;
if (xfer->bits_per_word <= 8)
w_size = 1;
else if (xfer->bits_per_word <= 16)
w_size = 2;
n_words = xfer->len / w_size;
controller->w_size = w_size;
if (n_words <= controller->in_fifo_sz) {
mode = QUP_IO_M_MODE_FIFO;
writel_relaxed(n_words, controller->base + QUP_MX_READ_CNT);
writel_relaxed(n_words, controller->base + QUP_MX_WRITE_CNT);
/* must be zero for FIFO */
writel_relaxed(0, controller->base + QUP_MX_INPUT_CNT);
writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT);
} else {
mode = QUP_IO_M_MODE_BLOCK;
writel_relaxed(n_words, controller->base + QUP_MX_INPUT_CNT);
writel_relaxed(n_words, controller->base + QUP_MX_OUTPUT_CNT);
/* must be zero for BLOCK and BAM */
writel_relaxed(0, controller->base + QUP_MX_READ_CNT);
writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
}
iomode = readl_relaxed(controller->base + QUP_IO_M_MODES);
/* Set input and output transfer mode */
iomode &= ~(QUP_IO_M_INPUT_MODE_MASK | QUP_IO_M_OUTPUT_MODE_MASK);
iomode &= ~(QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN);
iomode |= (mode << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT);
iomode |= (mode << QUP_IO_M_INPUT_MODE_MASK_SHIFT);
writel_relaxed(iomode, controller->base + QUP_IO_M_MODES);
config = readl_relaxed(controller->base + SPI_CONFIG);
if (spi->mode & SPI_LOOP)
config |= SPI_CONFIG_LOOPBACK;
else
config &= ~SPI_CONFIG_LOOPBACK;
if (spi->mode & SPI_CPHA)
config &= ~SPI_CONFIG_INPUT_FIRST;
else
config |= SPI_CONFIG_INPUT_FIRST;
/*
* HS_MODE improves signal stability for spi-clk high rates,
* but is invalid in loop back mode.
*/
if ((xfer->speed_hz >= SPI_HS_MIN_RATE) && !(spi->mode & SPI_LOOP))
config |= SPI_CONFIG_HS_MODE;
else
config &= ~SPI_CONFIG_HS_MODE;
writel_relaxed(config, controller->base + SPI_CONFIG);
config = readl_relaxed(controller->base + QUP_CONFIG);
config &= ~(QUP_CONFIG_NO_INPUT | QUP_CONFIG_NO_OUTPUT | QUP_CONFIG_N);
config |= xfer->bits_per_word - 1;
config |= QUP_CONFIG_SPI_MODE;
writel_relaxed(config, controller->base + QUP_CONFIG);
writel_relaxed(0, controller->base + QUP_OPERATIONAL_MASK);
return 0;
}
static void spi_qup_set_cs(struct spi_device *spi, bool enable)
{
struct spi_qup *controller = spi_master_get_devdata(spi->master);
u32 iocontol, mask;
iocontol = readl_relaxed(controller->base + SPI_IO_CONTROL);
/* Disable auto CS toggle and use manual */
iocontol &= ~SPI_IO_C_MX_CS_MODE;
iocontol |= SPI_IO_C_FORCE_CS;
iocontol &= ~SPI_IO_C_CS_SELECT_MASK;
iocontol |= SPI_IO_C_CS_SELECT(spi->chip_select);
mask = SPI_IO_C_CS_N_POLARITY_0 << spi->chip_select;
if (enable)
iocontol |= mask;
else
iocontol &= ~mask;
writel_relaxed(iocontol, controller->base + SPI_IO_CONTROL);
}
static int spi_qup_transfer_one(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *xfer)
{
struct spi_qup *controller = spi_master_get_devdata(master);
unsigned long timeout, flags;
int ret = -EIO;
ret = spi_qup_io_config(spi, xfer);
if (ret)
return ret;
timeout = DIV_ROUND_UP(xfer->speed_hz, MSEC_PER_SEC);
timeout = DIV_ROUND_UP(xfer->len * 8, timeout);
timeout = 100 * msecs_to_jiffies(timeout);
reinit_completion(&controller->done);
spin_lock_irqsave(&controller->lock, flags);
controller->xfer = xfer;
controller->error = 0;
controller->rx_bytes = 0;
controller->tx_bytes = 0;
spin_unlock_irqrestore(&controller->lock, flags);
if (spi_qup_set_state(controller, QUP_STATE_RUN)) {
dev_warn(controller->dev, "cannot set RUN state\n");
goto exit;
}
if (spi_qup_set_state(controller, QUP_STATE_PAUSE)) {
dev_warn(controller->dev, "cannot set PAUSE state\n");
goto exit;
}
spi_qup_fifo_write(controller, xfer);
if (spi_qup_set_state(controller, QUP_STATE_RUN)) {
dev_warn(controller->dev, "cannot set EXECUTE state\n");
goto exit;
}
if (!wait_for_completion_timeout(&controller->done, timeout))
ret = -ETIMEDOUT;
exit:
spi_qup_set_state(controller, QUP_STATE_RESET);
spin_lock_irqsave(&controller->lock, flags);
controller->xfer = NULL;
if (!ret)
ret = controller->error;
spin_unlock_irqrestore(&controller->lock, flags);
return ret;
}
static int spi_qup_probe(struct platform_device *pdev)
{
struct spi_master *master;
struct clk *iclk, *cclk;
struct spi_qup *controller;
struct resource *res;
struct device *dev;
void __iomem *base;
u32 data, max_freq, iomode;
int ret, irq, size;
dev = &pdev->dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
cclk = devm_clk_get(dev, "core");
if (IS_ERR(cclk))
return PTR_ERR(cclk);
iclk = devm_clk_get(dev, "iface");
if (IS_ERR(iclk))
return PTR_ERR(iclk);
/* This is optional parameter */
if (of_property_read_u32(dev->of_node, "spi-max-frequency", &max_freq))
max_freq = SPI_MAX_RATE;
if (!max_freq || max_freq > SPI_MAX_RATE) {
dev_err(dev, "invalid clock frequency %d\n", max_freq);
return -ENXIO;
}
ret = clk_prepare_enable(cclk);
if (ret) {
dev_err(dev, "cannot enable core clock\n");
return ret;
}
ret = clk_prepare_enable(iclk);
if (ret) {
clk_disable_unprepare(cclk);
dev_err(dev, "cannot enable iface clock\n");
return ret;
}
data = readl_relaxed(base + QUP_HW_VERSION);
if (data < QUP_HW_VERSION_2_1_1) {
clk_disable_unprepare(cclk);
clk_disable_unprepare(iclk);
dev_err(dev, "v.%08x is not supported\n", data);
return -ENXIO;
}
master = spi_alloc_master(dev, sizeof(struct spi_qup));
if (!master) {
clk_disable_unprepare(cclk);
clk_disable_unprepare(iclk);
dev_err(dev, "cannot allocate master\n");
return -ENOMEM;
}
master->bus_num = pdev->id;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
master->num_chipselect = SPI_NUM_CHIPSELECTS;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
master->max_speed_hz = max_freq;
master->set_cs = spi_qup_set_cs;
master->transfer_one = spi_qup_transfer_one;
master->dev.of_node = pdev->dev.of_node;
master->auto_runtime_pm = true;
platform_set_drvdata(pdev, master);
controller = spi_master_get_devdata(master);
controller->dev = dev;
controller->base = base;
controller->iclk = iclk;
controller->cclk = cclk;
controller->irq = irq;
spin_lock_init(&controller->lock);
init_completion(&controller->done);
iomode = readl_relaxed(base + QUP_IO_M_MODES);
size = QUP_IO_M_OUTPUT_BLOCK_SIZE(iomode);
if (size)
controller->out_blk_sz = size * 16;
else
controller->out_blk_sz = 4;
size = QUP_IO_M_INPUT_BLOCK_SIZE(iomode);
if (size)
controller->in_blk_sz = size * 16;
else
controller->in_blk_sz = 4;
size = QUP_IO_M_OUTPUT_FIFO_SIZE(iomode);
controller->out_fifo_sz = controller->out_blk_sz * (2 << size);
size = QUP_IO_M_INPUT_FIFO_SIZE(iomode);
controller->in_fifo_sz = controller->in_blk_sz * (2 << size);
dev_info(dev, "v.%08x IN:block:%d, fifo:%d, OUT:block:%d, fifo:%d\n",
data, controller->in_blk_sz, controller->in_fifo_sz,
controller->out_blk_sz, controller->out_fifo_sz);
writel_relaxed(1, base + QUP_SW_RESET);
ret = spi_qup_set_state(controller, QUP_STATE_RESET);
if (ret) {
dev_err(dev, "cannot set RESET state\n");
goto error;
}
writel_relaxed(0, base + QUP_OPERATIONAL);
writel_relaxed(0, base + QUP_IO_M_MODES);
writel_relaxed(0, base + QUP_OPERATIONAL_MASK);
writel_relaxed(SPI_ERROR_CLK_UNDER_RUN | SPI_ERROR_CLK_OVER_RUN,
base + SPI_ERROR_FLAGS_EN);
writel_relaxed(0, base + SPI_CONFIG);
writel_relaxed(SPI_IO_C_NO_TRI_STATE, base + SPI_IO_CONTROL);
ret = devm_request_irq(dev, irq, spi_qup_qup_irq,
IRQF_TRIGGER_HIGH, pdev->name, controller);
if (ret)
goto error;
ret = devm_spi_register_master(dev, master);
if (ret)
goto error;
pm_runtime_set_autosuspend_delay(dev, MSEC_PER_SEC);
pm_runtime_use_autosuspend(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
return 0;
error:
clk_disable_unprepare(cclk);
clk_disable_unprepare(iclk);
spi_master_put(master);
return ret;
}
#ifdef CONFIG_PM_RUNTIME
static int spi_qup_pm_suspend_runtime(struct device *device)
{
struct spi_master *master = dev_get_drvdata(device);
struct spi_qup *controller = spi_master_get_devdata(master);
u32 config;
/* Enable clocks auto gaiting */
config = readl(controller->base + QUP_CONFIG);
config |= QUP_CONFIG_CLOCK_AUTO_GATE;
writel_relaxed(config, controller->base + QUP_CONFIG);
return 0;
}
static int spi_qup_pm_resume_runtime(struct device *device)
{
struct spi_master *master = dev_get_drvdata(device);
struct spi_qup *controller = spi_master_get_devdata(master);
u32 config;
/* Disable clocks auto gaiting */
config = readl_relaxed(controller->base + QUP_CONFIG);
config &= ~QUP_CONFIG_CLOCK_AUTO_GATE;
writel_relaxed(config, controller->base + QUP_CONFIG);
return 0;
}
#endif /* CONFIG_PM_RUNTIME */
#ifdef CONFIG_PM_SLEEP
static int spi_qup_suspend(struct device *device)
{
struct spi_master *master = dev_get_drvdata(device);
struct spi_qup *controller = spi_master_get_devdata(master);
int ret;
ret = spi_master_suspend(master);
if (ret)
return ret;
ret = spi_qup_set_state(controller, QUP_STATE_RESET);
if (ret)
return ret;
clk_disable_unprepare(controller->cclk);
clk_disable_unprepare(controller->iclk);
return 0;
}
static int spi_qup_resume(struct device *device)
{
struct spi_master *master = dev_get_drvdata(device);
struct spi_qup *controller = spi_master_get_devdata(master);
int ret;
ret = clk_prepare_enable(controller->iclk);
if (ret)
return ret;
ret = clk_prepare_enable(controller->cclk);
if (ret)
return ret;
ret = spi_qup_set_state(controller, QUP_STATE_RESET);
if (ret)
return ret;
return spi_master_resume(master);
}
#endif /* CONFIG_PM_SLEEP */
static int spi_qup_remove(struct platform_device *pdev)
{
struct spi_master *master = dev_get_drvdata(&pdev->dev);
struct spi_qup *controller = spi_master_get_devdata(master);
int ret;
ret = pm_runtime_get_sync(&pdev->dev);
if (ret)
return ret;
ret = spi_qup_set_state(controller, QUP_STATE_RESET);
if (ret)
return ret;
clk_disable_unprepare(controller->cclk);
clk_disable_unprepare(controller->iclk);
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_disable(&pdev->dev);
return 0;
}
static struct of_device_id spi_qup_dt_match[] = {
{ .compatible = "qcom,spi-qup-v2.1.1", },
{ .compatible = "qcom,spi-qup-v2.2.1", },
{ }
};
MODULE_DEVICE_TABLE(of, spi_qup_dt_match);
static const struct dev_pm_ops spi_qup_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(spi_qup_suspend, spi_qup_resume)
SET_RUNTIME_PM_OPS(spi_qup_pm_suspend_runtime,
spi_qup_pm_resume_runtime,
NULL)
};
static struct platform_driver spi_qup_driver = {
.driver = {
.name = "spi_qup",
.owner = THIS_MODULE,
.pm = &spi_qup_dev_pm_ops,
.of_match_table = spi_qup_dt_match,
},
.probe = spi_qup_probe,
.remove = spi_qup_remove,
};
module_platform_driver(spi_qup_driver);
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:spi_qup");

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -9,7 +9,6 @@
*
*/
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
@ -123,25 +122,15 @@ static int s3c24xx_spi_update_state(struct spi_device *spi,
{
struct s3c24xx_spi *hw = to_hw(spi);
struct s3c24xx_spi_devstate *cs = spi->controller_state;
unsigned int bpw;
unsigned int hz;
unsigned int div;
unsigned long clk;
bpw = t ? t->bits_per_word : spi->bits_per_word;
hz = t ? t->speed_hz : spi->max_speed_hz;
if (!bpw)
bpw = 8;
if (!hz)
hz = spi->max_speed_hz;
if (bpw != 8) {
dev_err(&spi->dev, "invalid bits-per-word (%d)\n", bpw);
return -EINVAL;
}
if (spi->mode != cs->mode) {
u8 spcon = SPCON_DEFAULT | S3C2410_SPCON_ENSCK;
@ -544,6 +533,7 @@ static int s3c24xx_spi_probe(struct platform_device *pdev)
master->num_chipselect = hw->pdata->num_cs;
master->bus_num = pdata->bus_num;
master->bits_per_word_mask = SPI_BPW_MASK(8);
/* setup the state for the bitbang driver */
@ -643,6 +633,11 @@ static int s3c24xx_spi_remove(struct platform_device *dev)
static int s3c24xx_spi_suspend(struct device *dev)
{
struct s3c24xx_spi *hw = dev_get_drvdata(dev);
int ret;
ret = spi_master_suspend(hw->master);
if (ret)
return ret;
if (hw->pdata && hw->pdata->gpio_setup)
hw->pdata->gpio_setup(hw->pdata, 0);
@ -656,7 +651,7 @@ static int s3c24xx_spi_resume(struct device *dev)
struct s3c24xx_spi *hw = dev_get_drvdata(dev);
s3c24xx_spi_initialsetup(hw);
return 0;
return spi_master_resume(hw->master);
}
static const struct dev_pm_ops s3c24xx_spi_pmops = {

Просмотреть файл

@ -34,10 +34,6 @@
#include <linux/platform_data/spi-s3c64xx.h>
#ifdef CONFIG_S3C_DMA
#include <mach/dma.h>
#endif
#define MAX_SPI_PORTS 3
#define S3C64XX_SPI_QUIRK_POLL (1 << 0)
@ -200,9 +196,6 @@ struct s3c64xx_spi_driver_data {
unsigned cur_speed;
struct s3c64xx_spi_dma_data rx_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;
unsigned int port_id;
bool cs_gpio;
@ -284,104 +277,8 @@ static void s3c64xx_spi_dmacb(void *data)
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,
unsigned len, dma_addr_t buf)
struct sg_table *sgt)
{
struct s3c64xx_spi_driver_data *sdd;
struct dma_slave_config config;
@ -407,8 +304,8 @@ static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
dmaengine_slave_config(dma->ch, &config);
}
desc = dmaengine_prep_slave_single(dma->ch, buf, len,
dma->direction, DMA_PREP_INTERRUPT);
desc = dmaengine_prep_slave_sg(dma->ch, sgt->sgl, sgt->nents,
dma->direction, DMA_PREP_INTERRUPT);
desc->callback = s3c64xx_spi_dmacb;
desc->callback_param = dma;
@ -437,6 +334,7 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
ret = -EBUSY;
goto out;
}
spi->dma_rx = sdd->rx_dma.ch;
sdd->tx_dma.ch = dma_request_slave_channel_compat(mask, filter,
(void *)sdd->tx_dma.dmach, dev, "tx");
@ -445,6 +343,7 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
ret = -EBUSY;
goto out_rx;
}
spi->dma_tx = sdd->tx_dma.ch;
}
ret = pm_runtime_get_sync(&sdd->pdev->dev);
@ -477,12 +376,14 @@ static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
return 0;
}
static void s3c64xx_spi_dma_stop(struct s3c64xx_spi_driver_data *sdd,
struct s3c64xx_spi_dma_data *dma)
static bool s3c64xx_spi_can_dma(struct spi_master *master,
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,
struct spi_device *spi,
@ -515,7 +416,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
chcfg |= S3C64XX_SPI_CH_TXCH_ON;
if (dma_mode) {
modecfg |= S3C64XX_SPI_MODE_TXDMA_ON;
prepare_dma(&sdd->tx_dma, xfer->len, xfer->tx_dma);
prepare_dma(&sdd->tx_dma, &xfer->tx_sg);
} else {
switch (sdd->cur_bpw) {
case 32:
@ -547,7 +448,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff)
| S3C64XX_SPI_PACKET_CNT_EN,
regs + S3C64XX_SPI_PACKET_CNT);
prepare_dma(&sdd->rx_dma, xfer->len, xfer->rx_dma);
prepare_dma(&sdd->rx_dma, &xfer->rx_sg);
}
}
@ -555,23 +456,6 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
writel(chcfg, regs + S3C64XX_SPI_CH_CFG);
}
static inline void enable_cs(struct s3c64xx_spi_driver_data *sdd,
struct spi_device *spi)
{
if (sdd->tgl_spi != NULL) { /* If last device toggled after mssg */
if (sdd->tgl_spi != spi) { /* if last mssg on diff device */
/* Deselect the last toggled device */
if (spi->cs_gpio >= 0)
gpio_set_value(spi->cs_gpio,
spi->mode & SPI_CS_HIGH ? 0 : 1);
}
sdd->tgl_spi = NULL;
}
if (spi->cs_gpio >= 0)
gpio_set_value(spi->cs_gpio, spi->mode & SPI_CS_HIGH ? 1 : 0);
}
static u32 s3c64xx_spi_wait_for_timeout(struct s3c64xx_spi_driver_data *sdd,
int timeout_ms)
{
@ -593,112 +477,111 @@ static u32 s3c64xx_spi_wait_for_timeout(struct s3c64xx_spi_driver_data *sdd,
return RX_FIFO_LVL(status, sdd);
}
static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd,
struct spi_transfer *xfer, int dma_mode)
static int wait_for_dma(struct s3c64xx_spi_driver_data *sdd,
struct spi_transfer *xfer)
{
void __iomem *regs = sdd->regs;
unsigned long val;
u32 status;
int ms;
/* millisecs to xfer 'len' bytes @ 'cur_speed' */
ms = xfer->len * 8 * 1000 / sdd->cur_speed;
ms += 10; /* some tolerance */
if (dma_mode) {
val = msecs_to_jiffies(ms) + 10;
val = wait_for_completion_timeout(&sdd->xfer_completion, val);
} else {
u32 status;
val = msecs_to_loops(ms);
do {
val = msecs_to_jiffies(ms) + 10;
val = wait_for_completion_timeout(&sdd->xfer_completion, val);
/*
* If the previous xfer was completed within timeout, then
* proceed further else return -EIO.
* DmaTx returns after simply writing data in the FIFO,
* w/o waiting for real transmission on the bus to finish.
* DmaRx returns only after Dma read data from FIFO which
* needs bus transmission to finish, so we don't worry if
* Xfer involved Rx(with or without Tx).
*/
if (val && !xfer->rx_buf) {
val = msecs_to_loops(10);
status = readl(regs + S3C64XX_SPI_STATUS);
while ((TX_FIFO_LVL(status, sdd)
|| !S3C64XX_SPI_ST_TX_DONE(status, sdd))
&& --val) {
cpu_relax();
status = readl(regs + S3C64XX_SPI_STATUS);
} while (RX_FIFO_LVL(status, sdd) < xfer->len && --val);
}
if (dma_mode) {
u32 status;
/*
* If the previous xfer was completed within timeout, then
* proceed further else return -EIO.
* DmaTx returns after simply writing data in the FIFO,
* w/o waiting for real transmission on the bus to finish.
* DmaRx returns only after Dma read data from FIFO which
* needs bus transmission to finish, so we don't worry if
* Xfer involved Rx(with or without Tx).
*/
if (val && !xfer->rx_buf) {
val = msecs_to_loops(10);
status = readl(regs + S3C64XX_SPI_STATUS);
while ((TX_FIFO_LVL(status, sdd)
|| !S3C64XX_SPI_ST_TX_DONE(status, sdd))
&& --val) {
cpu_relax();
status = readl(regs + S3C64XX_SPI_STATUS);
}
}
/* If timed out while checking rx/tx status return error */
if (!val)
return -EIO;
} else {
int loops;
u32 cpy_len;
u8 *buf;
/* If it was only Tx */
if (!xfer->rx_buf) {
sdd->state &= ~TXBUSY;
return 0;
}
/*
* If the receive length is bigger than the controller fifo
* size, calculate the loops and read the fifo as many times.
* loops = length / max fifo size (calculated by using the
* fifo mask).
* For any size less than the fifo size the below code is
* executed atleast once.
*/
loops = xfer->len / ((FIFO_LVL_MASK(sdd) >> 1) + 1);
buf = xfer->rx_buf;
do {
/* wait for data to be received in the fifo */
cpy_len = s3c64xx_spi_wait_for_timeout(sdd,
(loops ? ms : 0));
switch (sdd->cur_bpw) {
case 32:
ioread32_rep(regs + S3C64XX_SPI_RX_DATA,
buf, cpy_len / 4);
break;
case 16:
ioread16_rep(regs + S3C64XX_SPI_RX_DATA,
buf, cpy_len / 2);
break;
default:
ioread8_rep(regs + S3C64XX_SPI_RX_DATA,
buf, cpy_len);
break;
}
buf = buf + cpy_len;
} while (loops--);
sdd->state &= ~RXBUSY;
}
/* If timed out while checking rx/tx status return error */
if (!val)
return -EIO;
return 0;
}
static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd,
struct spi_device *spi)
static int wait_for_pio(struct s3c64xx_spi_driver_data *sdd,
struct spi_transfer *xfer)
{
if (sdd->tgl_spi == spi)
sdd->tgl_spi = NULL;
void __iomem *regs = sdd->regs;
unsigned long val;
u32 status;
int loops;
u32 cpy_len;
u8 *buf;
int ms;
if (spi->cs_gpio >= 0)
gpio_set_value(spi->cs_gpio, spi->mode & SPI_CS_HIGH ? 0 : 1);
/* millisecs to xfer 'len' bytes @ 'cur_speed' */
ms = xfer->len * 8 * 1000 / sdd->cur_speed;
ms += 10; /* some tolerance */
val = msecs_to_loops(ms);
do {
status = readl(regs + S3C64XX_SPI_STATUS);
} while (RX_FIFO_LVL(status, sdd) < xfer->len && --val);
/* If it was only Tx */
if (!xfer->rx_buf) {
sdd->state &= ~TXBUSY;
return 0;
}
/*
* If the receive length is bigger than the controller fifo
* size, calculate the loops and read the fifo as many times.
* loops = length / max fifo size (calculated by using the
* fifo mask).
* For any size less than the fifo size the below code is
* executed atleast once.
*/
loops = xfer->len / ((FIFO_LVL_MASK(sdd) >> 1) + 1);
buf = xfer->rx_buf;
do {
/* wait for data to be received in the fifo */
cpy_len = s3c64xx_spi_wait_for_timeout(sdd,
(loops ? ms : 0));
switch (sdd->cur_bpw) {
case 32:
ioread32_rep(regs + S3C64XX_SPI_RX_DATA,
buf, cpy_len / 4);
break;
case 16:
ioread16_rep(regs + S3C64XX_SPI_RX_DATA,
buf, cpy_len / 2);
break;
default:
ioread8_rep(regs + S3C64XX_SPI_RX_DATA,
buf, cpy_len);
break;
}
buf = buf + cpy_len;
} while (loops--);
sdd->state &= ~RXBUSY;
return 0;
}
static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
@ -774,81 +657,6 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
#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,
struct spi_message *msg)
{
@ -866,13 +674,6 @@ static int s3c64xx_spi_prepare_message(struct spi_master *master,
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 */
writel(cs->fb_delay & 0x3, sdd->regs + S3C64XX_SPI_FB_CLK);
@ -896,13 +697,6 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
bpw = xfer->bits_per_word;
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) {
sdd->cur_bpw = bpw;
sdd->cur_speed = speed;
@ -929,7 +723,10 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
spin_unlock_irqrestore(&sdd->lock, flags);
status = wait_for_xfer(sdd, xfer, use_dma);
if (use_dma)
status = wait_for_dma(sdd, xfer);
else
status = wait_for_pio(sdd, xfer);
if (status) {
dev_err(&spi->dev, "I/O Error: rx-%d tx-%d res:rx-%c tx-%c len-%d\n",
@ -941,10 +738,10 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
if (use_dma) {
if (xfer->tx_buf != NULL
&& (sdd->state & TXBUSY))
s3c64xx_spi_dma_stop(sdd, &sdd->tx_dma);
dmaengine_terminate_all(sdd->tx_dma.ch);
if (xfer->rx_buf != NULL
&& (sdd->state & RXBUSY))
s3c64xx_spi_dma_stop(sdd, &sdd->rx_dma);
dmaengine_terminate_all(sdd->rx_dma.ch);
}
} else {
flush_fifo(sdd);
@ -953,16 +750,6 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
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(
struct spi_device *spi)
{
@ -1092,14 +879,12 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
pm_runtime_put(&sdd->pdev->dev);
writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
disable_cs(sdd, spi);
return 0;
setup_exit:
pm_runtime_put(&sdd->pdev->dev);
/* setup() returns with device de-selected */
writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
disable_cs(sdd, spi);
gpio_free(cs->line);
spi_set_ctldata(spi, NULL);
@ -1338,7 +1123,6 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
master->prepare_transfer_hardware = s3c64xx_spi_prepare_transfer;
master->prepare_message = s3c64xx_spi_prepare_message;
master->transfer_one = s3c64xx_spi_transfer_one;
master->unprepare_message = s3c64xx_spi_unprepare_message;
master->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer;
master->num_chipselect = sci->num_cs;
master->dma_alignment = 8;
@ -1347,6 +1131,8 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
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);
if (IS_ERR(sdd->regs)) {

Просмотреть файл

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

Просмотреть файл

@ -46,8 +46,6 @@
/* SPSR */
#define RXFL (1 << 2)
#define hspi2info(h) (h->dev->platform_data)
struct hspi_priv {
void __iomem *addr;
struct spi_master *master;
@ -113,14 +111,9 @@ static void hspi_hw_setup(struct hspi_priv *hspi,
{
struct spi_device *spi = msg->spi;
struct device *dev = hspi->dev;
u32 target_rate;
u32 spcr, idiv_clk;
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
*/
@ -140,7 +133,7 @@ static void hspi_hw_setup(struct hspi_priv *hspi,
rate /= (((idiv_clk & 0x1F) + 1) * 2);
/* save best settings */
tmp = abs(target_rate - rate);
tmp = abs(t->speed_hz - rate);
if (tmp < min) {
min = tmp;
spcr = idiv_clk;
@ -153,7 +146,7 @@ static void hspi_hw_setup(struct hspi_priv *hspi,
if (spi->mode & SPI_CPOL)
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, SPSR, 0x0);
@ -230,29 +223,6 @@ static int hspi_transfer_one_message(struct spi_master *master,
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)
{
struct resource *res;
@ -298,22 +268,23 @@ static int hspi_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
master->num_chipselect = 1;
master->bus_num = pdev->id;
master->setup = hspi_setup;
master->cleanup = hspi_cleanup;
master->mode_bits = SPI_CPOL | SPI_CPHA;
master->dev.of_node = pdev->dev.of_node;
master->auto_runtime_pm = true;
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);
if (ret < 0) {
dev_err(&pdev->dev, "spi_register_master error.\n");
goto error1;
goto error2;
}
return 0;
error2:
pm_runtime_disable(&pdev->dev);
error1:
clk_put(clk);
error0:

Просмотреть файл

@ -15,59 +15,108 @@
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/spi/sh_msiof.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.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 spi_bitbang bitbang; /* must be first for spi_bitbang.c */
void __iomem *mapbase;
struct clk *clk;
struct platform_device *pdev;
const struct sh_msiof_chipdata *chipdata;
struct sh_msiof_spi_info *info;
struct completion done;
unsigned long flags;
int tx_fifo_size;
int rx_fifo_size;
};
#define TMDR1 0x00
#define TMDR2 0x04
#define TMDR3 0x08
#define RMDR1 0x10
#define RMDR2 0x14
#define RMDR3 0x18
#define TSCR 0x20
#define RSCR 0x22
#define CTR 0x28
#define FCTR 0x30
#define STR 0x40
#define IER 0x44
#define TDR1 0x48
#define TDR2 0x4c
#define TFDR 0x50
#define RDR1 0x58
#define RDR2 0x5c
#define RFDR 0x60
#define TMDR1 0x00 /* Transmit Mode Register 1 */
#define TMDR2 0x04 /* Transmit Mode Register 2 */
#define TMDR3 0x08 /* Transmit Mode Register 3 */
#define RMDR1 0x10 /* Receive Mode Register 1 */
#define RMDR2 0x14 /* Receive Mode Register 2 */
#define RMDR3 0x18 /* Receive Mode Register 3 */
#define TSCR 0x20 /* Transmit Clock Select Register */
#define RSCR 0x22 /* Receive Clock Select Register (SH, A1, APE6) */
#define CTR 0x28 /* Control Register */
#define FCTR 0x30 /* FIFO Control Register */
#define STR 0x40 /* Status Register */
#define IER 0x44 /* Interrupt Enable Register */
#define TDR1 0x48 /* Transmit Control Data Register 1 (SH, A1) */
#define TDR2 0x4c /* Transmit Control Data Register 2 (SH, A1) */
#define TFDR 0x50 /* Transmit FIFO Data Register */
#define RDR1 0x58 /* Receive Control Data Register 1 (SH, A1) */
#define RDR2 0x5c /* Receive Control Data Register 2 (SH, A1) */
#define RFDR 0x60 /* Receive FIFO Data Register */
#define CTR_TSCKE (1 << 15)
#define CTR_TFSE (1 << 14)
#define CTR_TXE (1 << 9)
#define CTR_RXE (1 << 8)
/* TMDR1 and RMDR1 */
#define MDR1_TRMD 0x80000000 /* Transfer Mode (1 = Master mode) */
#define MDR1_SYNCMD_MASK 0x30000000 /* SYNC Mode */
#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)
{
@ -131,22 +180,21 @@ static struct {
unsigned short div;
unsigned short scr;
} const sh_msiof_spi_clk_table[] = {
{ 1, 0x0007 },
{ 2, 0x0000 },
{ 4, 0x0001 },
{ 8, 0x0002 },
{ 16, 0x0003 },
{ 32, 0x0004 },
{ 64, 0x1f00 },
{ 128, 0x1f01 },
{ 256, 0x1f02 },
{ 512, 0x1f03 },
{ 1024, 0x1f04 },
{ 1, SCR_BRPS( 1) | SCR_BRDV_DIV_1 },
{ 2, SCR_BRPS( 1) | SCR_BRDV_DIV_2 },
{ 4, SCR_BRPS( 1) | SCR_BRDV_DIV_4 },
{ 8, SCR_BRPS( 1) | SCR_BRDV_DIV_8 },
{ 16, SCR_BRPS( 1) | SCR_BRDV_DIV_16 },
{ 32, SCR_BRPS( 1) | SCR_BRDV_DIV_32 },
{ 64, SCR_BRPS(32) | SCR_BRDV_DIV_2 },
{ 128, SCR_BRPS(32) | SCR_BRDV_DIV_4 },
{ 256, SCR_BRPS(32) | SCR_BRDV_DIV_8 },
{ 512, SCR_BRPS(32) | SCR_BRDV_DIV_16 },
{ 1024, SCR_BRPS(32) | SCR_BRDV_DIV_32 },
};
static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p,
unsigned long parent_rate,
unsigned long spi_hz)
unsigned long parent_rate, u32 spi_hz)
{
unsigned long div = 1024;
size_t k;
@ -164,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);
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,
@ -183,21 +232,25 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p,
*/
sh_msiof_write(p, FCTR, 0);
tmp = 0;
tmp |= !cs_high << 25;
tmp |= lsb_first << 24;
sh_msiof_write(p, TMDR1, 0xe0000005 | tmp);
sh_msiof_write(p, RMDR1, 0x20000005 | tmp);
tmp = MDR1_SYNCMD_SPI | 1 << MDR1_FLD_SHIFT | MDR1_XXSTP;
tmp |= !cs_high << MDR1_SYNCAC_SHIFT;
tmp |= lsb_first << MDR1_BITLSB_SHIFT;
sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON);
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 |= cpol << 30; /* TSCKIZ */
tmp |= cpol << 28; /* RSCKIZ */
tmp = 0;
tmp |= CTR_TSCKIZ_SCK | cpol << CTR_TSCKIZ_POL_SHIFT;
tmp |= CTR_RSCKIZ_SCK | cpol << CTR_RSCKIZ_POL_SHIFT;
edge = cpol ^ !cpha;
tmp |= edge << 27; /* TEDG */
tmp |= edge << 26; /* REDG */
tmp |= (tx_hi_z ? 2 : 0) << 22; /* TXDIZ */
tmp |= edge << CTR_TEDG_SHIFT;
tmp |= edge << CTR_REDG_SHIFT;
tmp |= tx_hi_z ? CTR_TXDIZ_HIZ : CTR_TXDIZ_LOW;
sh_msiof_write(p, CTR, tmp);
}
@ -205,12 +258,12 @@ static void sh_msiof_spi_set_mode_regs(struct sh_msiof_spi_priv *p,
const void *tx_buf, void *rx_buf,
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);
else
sh_msiof_write(p, TMDR2, dr2 | 1);
sh_msiof_write(p, TMDR2, dr2 | MDR2_GRPMASK1);
if (rx_buf)
sh_msiof_write(p, RMDR2, dr2);
@ -363,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]);
}
static int sh_msiof_spi_bits(struct spi_device *spi, struct spi_transfer *t)
{
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)
static int sh_msiof_spi_setup(struct spi_device *spi)
{
struct device_node *np = spi->master->dev.of_node;
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 (spi->mode & SPI_CS_HIGH)
value = (is_on == BITBANG_CS_ACTIVE) ? 1 : 0;
else
value = (is_on == BITBANG_CS_ACTIVE) ? 0 : 1;
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));
if (!np) {
/*
* Use spi->controller_data for CS (same strategy as spi_gpio),
* if any. otherwise let HW control CS
*/
spi->cs_gpio = (uintptr_t)spi->controller_data;
}
/* use spi->controller data for CS (same strategy as spi_gpio) */
gpio_set_value((uintptr_t)spi->controller_data, value);
/* Configure pins before deasserting 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));
if (is_on == BITBANG_CS_INACTIVE) {
if (test_and_clear_bit(0, &p->flags)) {
clk_disable(p->clk);
pm_runtime_put(&p->pdev->dev);
}
}
if (spi->cs_gpio >= 0)
gpio_set_value(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
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,
@ -487,7 +508,7 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p,
/* clear status bits */
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 = ret ? ret : sh_msiof_modify_ctr_wait(p, CTR_TXE, 0);
if (rx_buf)
@ -505,9 +526,11 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p,
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 (*rx_fifo)(struct sh_msiof_spi_priv *, void *, int, int);
int bits;
@ -517,7 +540,7 @@ static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
int n;
bool swab;
bits = sh_msiof_spi_bits(spi, t);
bits = t->bits_per_word;
if (bits <= 8 && t->len > 15 && !(t->len & 3)) {
bits = 32;
@ -567,8 +590,7 @@ static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
}
/* setup clocks (clock already enabled in chipselect()) */
sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk),
sh_msiof_spi_hz(spi, t));
sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk), t->speed_hz);
/* transfer in fifo sized chunks */
words = t->len / bytes_per_word;
@ -588,22 +610,36 @@ static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
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;
}
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
static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev)
{
struct sh_msiof_spi_info *info;
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);
if (!info) {
@ -633,6 +669,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
{
struct resource *r;
struct spi_master *master;
const struct of_device_id *of_id;
struct sh_msiof_spi_priv *p;
int i;
int ret;
@ -646,10 +683,15 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
p = spi_master_get_devdata(master);
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);
else
} else {
p->chipdata = (const void *)pdev->id_entry->driver_data;
p->info = dev_get_platdata(&pdev->dev);
}
if (!p->info) {
dev_err(&pdev->dev, "failed to obtain device info\n");
@ -687,49 +729,40 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
goto err1;
}
ret = clk_prepare(p->clk);
if (ret < 0) {
dev_err(&pdev->dev, "unable to prepare clock\n");
goto err1;
}
p->pdev = pdev;
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 */
p->tx_fifo_size = p->chipdata->tx_fifo_size;
p->rx_fifo_size = p->chipdata->rx_fifo_size;
if (p->info->tx_fifo_override)
p->tx_fifo_size = p->info->tx_fifo_override;
if (p->info->rx_fifo_override)
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_LSB_FIRST | SPI_3WIRE;
master->flags = 0;
master->flags = p->chipdata->master_flags;
master->bus_num = pdev->id;
master->dev.of_node = pdev->dev.of_node;
master->num_chipselect = p->info->num_chipselect;
master->setup = spi_bitbang_setup;
master->cleanup = spi_bitbang_cleanup;
master->setup = sh_msiof_spi_setup;
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;
p->bitbang.chipselect = sh_msiof_spi_chipselect;
p->bitbang.setup_transfer = sh_msiof_spi_setup_transfer;
p->bitbang.txrx_bufs = sh_msiof_spi_txrx;
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 = devm_spi_register_master(&pdev->dev, master);
if (ret < 0) {
dev_err(&pdev->dev, "spi_register_master error.\n");
goto err2;
}
ret = spi_bitbang_start(&p->bitbang);
if (ret == 0)
return 0;
return 0;
err2:
pm_runtime_disable(&pdev->dev);
clk_unprepare(p->clk);
err1:
spi_master_put(master);
return ret;
@ -737,30 +770,22 @@ static int sh_msiof_spi_probe(struct platform_device *pdev)
static int sh_msiof_spi_remove(struct platform_device *pdev)
{
struct sh_msiof_spi_priv *p = platform_get_drvdata(pdev);
int ret;
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;
pm_runtime_disable(&pdev->dev);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id sh_msiof_match[] = {
{ .compatible = "renesas,sh-msiof", },
{ .compatible = "renesas,sh-mobile-msiof", },
static struct platform_device_id spi_driver_ids[] = {
{ "spi_sh_msiof", (kernel_ulong_t)&sh_data },
{ "spi_r8a7790_msiof", (kernel_ulong_t)&r8a779x_data },
{ "spi_r8a7791_msiof", (kernel_ulong_t)&r8a779x_data },
{},
};
MODULE_DEVICE_TABLE(of, sh_msiof_match);
#endif
MODULE_DEVICE_TABLE(platform, spi_driver_ids);
static struct platform_driver sh_msiof_spi_drv = {
.probe = sh_msiof_spi_probe,
.remove = sh_msiof_spi_remove,
.id_table = spi_driver_ids,
.driver = {
.name = "spi_sh_msiof",
.owner = THIS_MODULE,

Просмотреть файл

@ -14,7 +14,6 @@
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
@ -109,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);
if (sp->info && sp->info->chip_select)
if (sp->info->chip_select)
(sp->info->chip_select)(sp->info, dev->chip_select, value);
}
@ -131,6 +130,11 @@ static int sh_sci_spi_probe(struct platform_device *dev)
platform_set_drvdata(dev, sp);
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 */
sp->bitbang.master = master;

Просмотреть файл

@ -22,7 +22,6 @@
#include <linux/dmaengine.h>
#include <linux/dma-direction.h>
#include <linux/dma-mapping.h>
#include <linux/sirfsoc_dma.h>
#define DRIVER_NAME "sirfsoc_spi"
@ -132,6 +131,8 @@
#define IS_DMA_VALID(x) (x && ALIGNED(x->tx_buf) && ALIGNED(x->rx_buf) && \
ALIGNED(x->len) && (x->len < 2 * PAGE_SIZE))
#define SIRFSOC_MAX_CMD_BYTES 4
struct sirfsoc_spi {
struct spi_bitbang bitbang;
struct completion rx_done;
@ -162,6 +163,12 @@ struct sirfsoc_spi {
void *dummypage;
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];
};
@ -260,6 +267,12 @@ static irqreturn_t spi_sirfsoc_irq(int irq, void *dev_id)
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 */
if (spi_stat & SIRFSOC_SPI_RX_OFLOW ||
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);
/*
* 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) {
writel(readl(sspi->base + SIRFSOC_SPI_CTRL) |
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;
sspi->rx_word = spi_sirfsoc_rx_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;
case 12:
case 16:
@ -471,26 +507,22 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
SIRFSOC_SPI_TRAN_DAT_FORMAT_16;
sspi->rx_word = spi_sirfsoc_rx_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;
case 32:
regval |= SIRFSOC_SPI_TRAN_DAT_FORMAT_32;
sspi->rx_word = spi_sirfsoc_rx_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;
default:
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))
regval |= SIRFSOC_SPI_CS_IDLE_STAT;
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(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);
if (IS_DMA_VALID(t)) {
@ -548,8 +588,6 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
struct spi_master *master;
struct resource *mem_res;
int num_cs, cs_gpio, irq;
u32 rx_dma_ch, tx_dma_ch;
dma_cap_mask_t dma_cap_mask;
int i;
int ret;
@ -560,20 +598,6 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
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);
if (!master) {
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;
/* request DMA channels */
dma_cap_zero(dma_cap_mask);
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);
sspi->rx_chan = dma_request_slave_channel(&pdev->dev, "rx");
if (!sspi->rx_chan) {
dev_err(&pdev->dev, "can not allocate rx dma channel\n");
ret = -ENODEV;
goto free_master;
}
sspi->tx_chan = dma_request_channel(dma_cap_mask, (dma_filter_fn)sirfsoc_dma_filter_id,
(void *)tx_dma_ch);
sspi->tx_chan = dma_request_slave_channel(&pdev->dev, "tx");
if (!sspi->tx_chan) {
dev_err(&pdev->dev, "can not allocate tx dma channel\n");
ret = -ENODEV;
@ -724,11 +743,16 @@ static int spi_sirfsoc_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP
static int spi_sirfsoc_suspend(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct sirfsoc_spi *sspi = spi_master_get_devdata(master);
int ret;
ret = spi_master_suspend(master);
if (ret)
return ret;
clk_disable(sspi->clk);
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_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
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[] = {
{ .compatible = "sirf,prima2-spi", },
{ .compatible = "sirf,marco-spi", },
@ -765,9 +787,7 @@ static struct platform_driver spi_sirfsoc_driver = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &spi_sirfsoc_pm_ops,
#endif
.of_match_table = spi_sirfsoc_of_match,
},
.probe = spi_sirfsoc_probe,

478
drivers/spi/spi-sun4i.c Normal file
Просмотреть файл

@ -0,0 +1,478 @@
/*
* Copyright (C) 2012 - 2014 Allwinner Tech
* Pan Nan <pannan@allwinnertech.com>
*
* Copyright (C) 2014 Maxime Ripard
* Maxime Ripard <maxime.ripard@free-electrons.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; either version 2 of
* the License, or (at your option) any later version.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/workqueue.h>
#include <linux/spi/spi.h>
#define SUN4I_FIFO_DEPTH 64
#define SUN4I_RXDATA_REG 0x00
#define SUN4I_TXDATA_REG 0x04
#define SUN4I_CTL_REG 0x08
#define SUN4I_CTL_ENABLE BIT(0)
#define SUN4I_CTL_MASTER BIT(1)
#define SUN4I_CTL_CPHA BIT(2)
#define SUN4I_CTL_CPOL BIT(3)
#define SUN4I_CTL_CS_ACTIVE_LOW BIT(4)
#define SUN4I_CTL_LMTF BIT(6)
#define SUN4I_CTL_TF_RST BIT(8)
#define SUN4I_CTL_RF_RST BIT(9)
#define SUN4I_CTL_XCH BIT(10)
#define SUN4I_CTL_CS_MASK 0x3000
#define SUN4I_CTL_CS(cs) (((cs) << 12) & SUN4I_CTL_CS_MASK)
#define SUN4I_CTL_DHB BIT(15)
#define SUN4I_CTL_CS_MANUAL BIT(16)
#define SUN4I_CTL_CS_LEVEL BIT(17)
#define SUN4I_CTL_TP BIT(18)
#define SUN4I_INT_CTL_REG 0x0c
#define SUN4I_INT_CTL_TC BIT(16)
#define SUN4I_INT_STA_REG 0x10
#define SUN4I_DMA_CTL_REG 0x14
#define SUN4I_WAIT_REG 0x18
#define SUN4I_CLK_CTL_REG 0x1c
#define SUN4I_CLK_CTL_CDR2_MASK 0xff
#define SUN4I_CLK_CTL_CDR2(div) ((div) & SUN4I_CLK_CTL_CDR2_MASK)
#define SUN4I_CLK_CTL_CDR1_MASK 0xf
#define SUN4I_CLK_CTL_CDR1(div) (((div) & SUN4I_CLK_CTL_CDR1_MASK) << 8)
#define SUN4I_CLK_CTL_DRS BIT(12)
#define SUN4I_BURST_CNT_REG 0x20
#define SUN4I_BURST_CNT(cnt) ((cnt) & 0xffffff)
#define SUN4I_XMIT_CNT_REG 0x24
#define SUN4I_XMIT_CNT(cnt) ((cnt) & 0xffffff)
#define SUN4I_FIFO_STA_REG 0x28
#define SUN4I_FIFO_STA_RF_CNT_MASK 0x7f
#define SUN4I_FIFO_STA_RF_CNT_BITS 0
#define SUN4I_FIFO_STA_TF_CNT_MASK 0x7f
#define SUN4I_FIFO_STA_TF_CNT_BITS 16
struct sun4i_spi {
struct spi_master *master;
void __iomem *base_addr;
struct clk *hclk;
struct clk *mclk;
struct completion done;
const u8 *tx_buf;
u8 *rx_buf;
int len;
};
static inline u32 sun4i_spi_read(struct sun4i_spi *sspi, u32 reg)
{
return readl(sspi->base_addr + reg);
}
static inline void sun4i_spi_write(struct sun4i_spi *sspi, u32 reg, u32 value)
{
writel(value, sspi->base_addr + reg);
}
static inline void sun4i_spi_drain_fifo(struct sun4i_spi *sspi, int len)
{
u32 reg, cnt;
u8 byte;
/* See how much data is available */
reg = sun4i_spi_read(sspi, SUN4I_FIFO_STA_REG);
reg &= SUN4I_FIFO_STA_RF_CNT_MASK;
cnt = reg >> SUN4I_FIFO_STA_RF_CNT_BITS;
if (len > cnt)
len = cnt;
while (len--) {
byte = readb(sspi->base_addr + SUN4I_RXDATA_REG);
if (sspi->rx_buf)
*sspi->rx_buf++ = byte;
}
}
static inline void sun4i_spi_fill_fifo(struct sun4i_spi *sspi, int len)
{
u8 byte;
if (len > sspi->len)
len = sspi->len;
while (len--) {
byte = sspi->tx_buf ? *sspi->tx_buf++ : 0;
writeb(byte, sspi->base_addr + SUN4I_TXDATA_REG);
sspi->len--;
}
}
static void sun4i_spi_set_cs(struct spi_device *spi, bool enable)
{
struct sun4i_spi *sspi = spi_master_get_devdata(spi->master);
u32 reg;
reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
reg &= ~SUN4I_CTL_CS_MASK;
reg |= SUN4I_CTL_CS(spi->chip_select);
if (enable)
reg |= SUN4I_CTL_CS_LEVEL;
else
reg &= ~SUN4I_CTL_CS_LEVEL;
/*
* Even though this looks irrelevant since we are supposed to
* be controlling the chip select manually, this bit also
* controls the levels of the chip select for inactive
* devices.
*
* If we don't set it, the chip select level will go low by
* default when the device is idle, which is not really
* expected in the common case where the chip select is active
* low.
*/
if (spi->mode & SPI_CS_HIGH)
reg &= ~SUN4I_CTL_CS_ACTIVE_LOW;
else
reg |= SUN4I_CTL_CS_ACTIVE_LOW;
sun4i_spi_write(sspi, SUN4I_CTL_REG, reg);
}
static int sun4i_spi_transfer_one(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *tfr)
{
struct sun4i_spi *sspi = spi_master_get_devdata(master);
unsigned int mclk_rate, div, timeout;
unsigned int tx_len = 0;
int ret = 0;
u32 reg;
/* We don't support transfer larger than the FIFO */
if (tfr->len > SUN4I_FIFO_DEPTH)
return -EINVAL;
reinit_completion(&sspi->done);
sspi->tx_buf = tfr->tx_buf;
sspi->rx_buf = tfr->rx_buf;
sspi->len = tfr->len;
/* Clear pending interrupts */
sun4i_spi_write(sspi, SUN4I_INT_STA_REG, ~0);
reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
/* Reset FIFOs */
sun4i_spi_write(sspi, SUN4I_CTL_REG,
reg | SUN4I_CTL_RF_RST | SUN4I_CTL_TF_RST);
/*
* Setup the transfer control register: Chip Select,
* polarities, etc.
*/
if (spi->mode & SPI_CPOL)
reg |= SUN4I_CTL_CPOL;
else
reg &= ~SUN4I_CTL_CPOL;
if (spi->mode & SPI_CPHA)
reg |= SUN4I_CTL_CPHA;
else
reg &= ~SUN4I_CTL_CPHA;
if (spi->mode & SPI_LSB_FIRST)
reg |= SUN4I_CTL_LMTF;
else
reg &= ~SUN4I_CTL_LMTF;
/*
* If it's a TX only transfer, we don't want to fill the RX
* FIFO with bogus data
*/
if (sspi->rx_buf)
reg &= ~SUN4I_CTL_DHB;
else
reg |= SUN4I_CTL_DHB;
/* We want to control the chip select manually */
reg |= SUN4I_CTL_CS_MANUAL;
sun4i_spi_write(sspi, SUN4I_CTL_REG, reg);
/* Ensure that we have a parent clock fast enough */
mclk_rate = clk_get_rate(sspi->mclk);
if (mclk_rate < (2 * spi->max_speed_hz)) {
clk_set_rate(sspi->mclk, 2 * spi->max_speed_hz);
mclk_rate = clk_get_rate(sspi->mclk);
}
/*
* Setup clock divider.
*
* We have two choices there. Either we can use the clock
* divide rate 1, which is calculated thanks to this formula:
* SPI_CLK = MOD_CLK / (2 ^ (cdr + 1))
* Or we can use CDR2, which is calculated with the formula:
* SPI_CLK = MOD_CLK / (2 * (cdr + 1))
* Wether we use the former or the latter is set through the
* DRS bit.
*
* First try CDR2, and if we can't reach the expected
* frequency, fall back to CDR1.
*/
div = mclk_rate / (2 * spi->max_speed_hz);
if (div <= (SUN4I_CLK_CTL_CDR2_MASK + 1)) {
if (div > 0)
div--;
reg = SUN4I_CLK_CTL_CDR2(div) | SUN4I_CLK_CTL_DRS;
} else {
div = ilog2(mclk_rate) - ilog2(spi->max_speed_hz);
reg = SUN4I_CLK_CTL_CDR1(div);
}
sun4i_spi_write(sspi, SUN4I_CLK_CTL_REG, reg);
/* Setup the transfer now... */
if (sspi->tx_buf)
tx_len = tfr->len;
/* Setup the counters */
sun4i_spi_write(sspi, SUN4I_BURST_CNT_REG, SUN4I_BURST_CNT(tfr->len));
sun4i_spi_write(sspi, SUN4I_XMIT_CNT_REG, SUN4I_XMIT_CNT(tx_len));
/* Fill the TX FIFO */
sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH);
/* Enable the interrupts */
sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, SUN4I_INT_CTL_TC);
/* Start the transfer */
reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
sun4i_spi_write(sspi, SUN4I_CTL_REG, reg | SUN4I_CTL_XCH);
timeout = wait_for_completion_timeout(&sspi->done,
msecs_to_jiffies(1000));
if (!timeout) {
ret = -ETIMEDOUT;
goto out;
}
sun4i_spi_drain_fifo(sspi, SUN4I_FIFO_DEPTH);
out:
sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, 0);
return ret;
}
static irqreturn_t sun4i_spi_handler(int irq, void *dev_id)
{
struct sun4i_spi *sspi = dev_id;
u32 status = sun4i_spi_read(sspi, SUN4I_INT_STA_REG);
/* Transfer complete */
if (status & SUN4I_INT_CTL_TC) {
sun4i_spi_write(sspi, SUN4I_INT_STA_REG, SUN4I_INT_CTL_TC);
complete(&sspi->done);
return IRQ_HANDLED;
}
return IRQ_NONE;
}
static int sun4i_spi_runtime_resume(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct sun4i_spi *sspi = spi_master_get_devdata(master);
int ret;
ret = clk_prepare_enable(sspi->hclk);
if (ret) {
dev_err(dev, "Couldn't enable AHB clock\n");
goto out;
}
ret = clk_prepare_enable(sspi->mclk);
if (ret) {
dev_err(dev, "Couldn't enable module clock\n");
goto err;
}
sun4i_spi_write(sspi, SUN4I_CTL_REG,
SUN4I_CTL_ENABLE | SUN4I_CTL_MASTER | SUN4I_CTL_TP);
return 0;
err:
clk_disable_unprepare(sspi->hclk);
out:
return ret;
}
static int sun4i_spi_runtime_suspend(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct sun4i_spi *sspi = spi_master_get_devdata(master);
clk_disable_unprepare(sspi->mclk);
clk_disable_unprepare(sspi->hclk);
return 0;
}
static int sun4i_spi_probe(struct platform_device *pdev)
{
struct spi_master *master;
struct sun4i_spi *sspi;
struct resource *res;
int ret = 0, irq;
master = spi_alloc_master(&pdev->dev, sizeof(struct sun4i_spi));
if (!master) {
dev_err(&pdev->dev, "Unable to allocate SPI Master\n");
return -ENOMEM;
}
platform_set_drvdata(pdev, master);
sspi = spi_master_get_devdata(master);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
sspi->base_addr = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(sspi->base_addr)) {
ret = PTR_ERR(sspi->base_addr);
goto err_free_master;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "No spi IRQ specified\n");
ret = -ENXIO;
goto err_free_master;
}
ret = devm_request_irq(&pdev->dev, irq, sun4i_spi_handler,
0, "sun4i-spi", sspi);
if (ret) {
dev_err(&pdev->dev, "Cannot request IRQ\n");
goto err_free_master;
}
sspi->master = master;
master->set_cs = sun4i_spi_set_cs;
master->transfer_one = sun4i_spi_transfer_one;
master->num_chipselect = 4;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
master->bits_per_word_mask = SPI_BPW_MASK(8);
master->dev.of_node = pdev->dev.of_node;
master->auto_runtime_pm = true;
sspi->hclk = devm_clk_get(&pdev->dev, "ahb");
if (IS_ERR(sspi->hclk)) {
dev_err(&pdev->dev, "Unable to acquire AHB clock\n");
ret = PTR_ERR(sspi->hclk);
goto err_free_master;
}
sspi->mclk = devm_clk_get(&pdev->dev, "mod");
if (IS_ERR(sspi->mclk)) {
dev_err(&pdev->dev, "Unable to acquire module clock\n");
ret = PTR_ERR(sspi->mclk);
goto err_free_master;
}
init_completion(&sspi->done);
/*
* This wake-up/shutdown pattern is to be able to have the
* device woken up, even if runtime_pm is disabled
*/
ret = sun4i_spi_runtime_resume(&pdev->dev);
if (ret) {
dev_err(&pdev->dev, "Couldn't resume the device\n");
goto err_free_master;
}
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
pm_runtime_idle(&pdev->dev);
ret = devm_spi_register_master(&pdev->dev, master);
if (ret) {
dev_err(&pdev->dev, "cannot register SPI master\n");
goto err_pm_disable;
}
return 0;
err_pm_disable:
pm_runtime_disable(&pdev->dev);
sun4i_spi_runtime_suspend(&pdev->dev);
err_free_master:
spi_master_put(master);
return ret;
}
static int sun4i_spi_remove(struct platform_device *pdev)
{
pm_runtime_disable(&pdev->dev);
return 0;
}
static const struct of_device_id sun4i_spi_match[] = {
{ .compatible = "allwinner,sun4i-a10-spi", },
{}
};
MODULE_DEVICE_TABLE(of, sun4i_spi_match);
static const struct dev_pm_ops sun4i_spi_pm_ops = {
.runtime_resume = sun4i_spi_runtime_resume,
.runtime_suspend = sun4i_spi_runtime_suspend,
};
static struct platform_driver sun4i_spi_driver = {
.probe = sun4i_spi_probe,
.remove = sun4i_spi_remove,
.driver = {
.name = "sun4i-spi",
.owner = THIS_MODULE,
.of_match_table = sun4i_spi_match,
.pm = &sun4i_spi_pm_ops,
},
};
module_platform_driver(sun4i_spi_driver);
MODULE_AUTHOR("Pan Nan <pannan@allwinnertech.com>");
MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
MODULE_DESCRIPTION("Allwinner A1X/A20 SPI controller driver");
MODULE_LICENSE("GPL");

484
drivers/spi/spi-sun6i.c Normal file
Просмотреть файл

@ -0,0 +1,484 @@
/*
* Copyright (C) 2012 - 2014 Allwinner Tech
* Pan Nan <pannan@allwinnertech.com>
*
* Copyright (C) 2014 Maxime Ripard
* Maxime Ripard <maxime.ripard@free-electrons.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; either version 2 of
* the License, or (at your option) any later version.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <linux/workqueue.h>
#include <linux/spi/spi.h>
#define SUN6I_FIFO_DEPTH 128
#define SUN6I_GBL_CTL_REG 0x04
#define SUN6I_GBL_CTL_BUS_ENABLE BIT(0)
#define SUN6I_GBL_CTL_MASTER BIT(1)
#define SUN6I_GBL_CTL_TP BIT(7)
#define SUN6I_GBL_CTL_RST BIT(31)
#define SUN6I_TFR_CTL_REG 0x08
#define SUN6I_TFR_CTL_CPHA BIT(0)
#define SUN6I_TFR_CTL_CPOL BIT(1)
#define SUN6I_TFR_CTL_SPOL BIT(2)
#define SUN6I_TFR_CTL_CS_MASK 0x30
#define SUN6I_TFR_CTL_CS(cs) (((cs) << 4) & SUN6I_TFR_CTL_CS_MASK)
#define SUN6I_TFR_CTL_CS_MANUAL BIT(6)
#define SUN6I_TFR_CTL_CS_LEVEL BIT(7)
#define SUN6I_TFR_CTL_DHB BIT(8)
#define SUN6I_TFR_CTL_FBS BIT(12)
#define SUN6I_TFR_CTL_XCH BIT(31)
#define SUN6I_INT_CTL_REG 0x10
#define SUN6I_INT_CTL_RF_OVF BIT(8)
#define SUN6I_INT_CTL_TC BIT(12)
#define SUN6I_INT_STA_REG 0x14
#define SUN6I_FIFO_CTL_REG 0x18
#define SUN6I_FIFO_CTL_RF_RST BIT(15)
#define SUN6I_FIFO_CTL_TF_RST BIT(31)
#define SUN6I_FIFO_STA_REG 0x1c
#define SUN6I_FIFO_STA_RF_CNT_MASK 0x7f
#define SUN6I_FIFO_STA_RF_CNT_BITS 0
#define SUN6I_FIFO_STA_TF_CNT_MASK 0x7f
#define SUN6I_FIFO_STA_TF_CNT_BITS 16
#define SUN6I_CLK_CTL_REG 0x24
#define SUN6I_CLK_CTL_CDR2_MASK 0xff
#define SUN6I_CLK_CTL_CDR2(div) (((div) & SUN6I_CLK_CTL_CDR2_MASK) << 0)
#define SUN6I_CLK_CTL_CDR1_MASK 0xf
#define SUN6I_CLK_CTL_CDR1(div) (((div) & SUN6I_CLK_CTL_CDR1_MASK) << 8)
#define SUN6I_CLK_CTL_DRS BIT(12)
#define SUN6I_BURST_CNT_REG 0x30
#define SUN6I_BURST_CNT(cnt) ((cnt) & 0xffffff)
#define SUN6I_XMIT_CNT_REG 0x34
#define SUN6I_XMIT_CNT(cnt) ((cnt) & 0xffffff)
#define SUN6I_BURST_CTL_CNT_REG 0x38
#define SUN6I_BURST_CTL_CNT_STC(cnt) ((cnt) & 0xffffff)
#define SUN6I_TXDATA_REG 0x200
#define SUN6I_RXDATA_REG 0x300
struct sun6i_spi {
struct spi_master *master;
void __iomem *base_addr;
struct clk *hclk;
struct clk *mclk;
struct reset_control *rstc;
struct completion done;
const u8 *tx_buf;
u8 *rx_buf;
int len;
};
static inline u32 sun6i_spi_read(struct sun6i_spi *sspi, u32 reg)
{
return readl(sspi->base_addr + reg);
}
static inline void sun6i_spi_write(struct sun6i_spi *sspi, u32 reg, u32 value)
{
writel(value, sspi->base_addr + reg);
}
static inline void sun6i_spi_drain_fifo(struct sun6i_spi *sspi, int len)
{
u32 reg, cnt;
u8 byte;
/* See how much data is available */
reg = sun6i_spi_read(sspi, SUN6I_FIFO_STA_REG);
reg &= SUN6I_FIFO_STA_RF_CNT_MASK;
cnt = reg >> SUN6I_FIFO_STA_RF_CNT_BITS;
if (len > cnt)
len = cnt;
while (len--) {
byte = readb(sspi->base_addr + SUN6I_RXDATA_REG);
if (sspi->rx_buf)
*sspi->rx_buf++ = byte;
}
}
static inline void sun6i_spi_fill_fifo(struct sun6i_spi *sspi, int len)
{
u8 byte;
if (len > sspi->len)
len = sspi->len;
while (len--) {
byte = sspi->tx_buf ? *sspi->tx_buf++ : 0;
writeb(byte, sspi->base_addr + SUN6I_TXDATA_REG);
sspi->len--;
}
}
static void sun6i_spi_set_cs(struct spi_device *spi, bool enable)
{
struct sun6i_spi *sspi = spi_master_get_devdata(spi->master);
u32 reg;
reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
reg &= ~SUN6I_TFR_CTL_CS_MASK;
reg |= SUN6I_TFR_CTL_CS(spi->chip_select);
if (enable)
reg |= SUN6I_TFR_CTL_CS_LEVEL;
else
reg &= ~SUN6I_TFR_CTL_CS_LEVEL;
sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
}
static int sun6i_spi_transfer_one(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *tfr)
{
struct sun6i_spi *sspi = spi_master_get_devdata(master);
unsigned int mclk_rate, div, timeout;
unsigned int tx_len = 0;
int ret = 0;
u32 reg;
/* We don't support transfer larger than the FIFO */
if (tfr->len > SUN6I_FIFO_DEPTH)
return -EINVAL;
reinit_completion(&sspi->done);
sspi->tx_buf = tfr->tx_buf;
sspi->rx_buf = tfr->rx_buf;
sspi->len = tfr->len;
/* Clear pending interrupts */
sun6i_spi_write(sspi, SUN6I_INT_STA_REG, ~0);
/* Reset FIFO */
sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG,
SUN6I_FIFO_CTL_RF_RST | SUN6I_FIFO_CTL_TF_RST);
/*
* Setup the transfer control register: Chip Select,
* polarities, etc.
*/
reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
if (spi->mode & SPI_CPOL)
reg |= SUN6I_TFR_CTL_CPOL;
else
reg &= ~SUN6I_TFR_CTL_CPOL;
if (spi->mode & SPI_CPHA)
reg |= SUN6I_TFR_CTL_CPHA;
else
reg &= ~SUN6I_TFR_CTL_CPHA;
if (spi->mode & SPI_LSB_FIRST)
reg |= SUN6I_TFR_CTL_FBS;
else
reg &= ~SUN6I_TFR_CTL_FBS;
/*
* If it's a TX only transfer, we don't want to fill the RX
* FIFO with bogus data
*/
if (sspi->rx_buf)
reg &= ~SUN6I_TFR_CTL_DHB;
else
reg |= SUN6I_TFR_CTL_DHB;
/* We want to control the chip select manually */
reg |= SUN6I_TFR_CTL_CS_MANUAL;
sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
/* Ensure that we have a parent clock fast enough */
mclk_rate = clk_get_rate(sspi->mclk);
if (mclk_rate < (2 * spi->max_speed_hz)) {
clk_set_rate(sspi->mclk, 2 * spi->max_speed_hz);
mclk_rate = clk_get_rate(sspi->mclk);
}
/*
* Setup clock divider.
*
* We have two choices there. Either we can use the clock
* divide rate 1, which is calculated thanks to this formula:
* SPI_CLK = MOD_CLK / (2 ^ cdr)
* Or we can use CDR2, which is calculated with the formula:
* SPI_CLK = MOD_CLK / (2 * (cdr + 1))
* Wether we use the former or the latter is set through the
* DRS bit.
*
* First try CDR2, and if we can't reach the expected
* frequency, fall back to CDR1.
*/
div = mclk_rate / (2 * spi->max_speed_hz);
if (div <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) {
if (div > 0)
div--;
reg = SUN6I_CLK_CTL_CDR2(div) | SUN6I_CLK_CTL_DRS;
} else {
div = ilog2(mclk_rate) - ilog2(spi->max_speed_hz);
reg = SUN6I_CLK_CTL_CDR1(div);
}
sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg);
/* Setup the transfer now... */
if (sspi->tx_buf)
tx_len = tfr->len;
/* Setup the counters */
sun6i_spi_write(sspi, SUN6I_BURST_CNT_REG, SUN6I_BURST_CNT(tfr->len));
sun6i_spi_write(sspi, SUN6I_XMIT_CNT_REG, SUN6I_XMIT_CNT(tx_len));
sun6i_spi_write(sspi, SUN6I_BURST_CTL_CNT_REG,
SUN6I_BURST_CTL_CNT_STC(tx_len));
/* Fill the TX FIFO */
sun6i_spi_fill_fifo(sspi, SUN6I_FIFO_DEPTH);
/* Enable the interrupts */
sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, SUN6I_INT_CTL_TC);
/* Start the transfer */
reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg | SUN6I_TFR_CTL_XCH);
timeout = wait_for_completion_timeout(&sspi->done,
msecs_to_jiffies(1000));
if (!timeout) {
ret = -ETIMEDOUT;
goto out;
}
sun6i_spi_drain_fifo(sspi, SUN6I_FIFO_DEPTH);
out:
sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, 0);
return ret;
}
static irqreturn_t sun6i_spi_handler(int irq, void *dev_id)
{
struct sun6i_spi *sspi = dev_id;
u32 status = sun6i_spi_read(sspi, SUN6I_INT_STA_REG);
/* Transfer complete */
if (status & SUN6I_INT_CTL_TC) {
sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_TC);
complete(&sspi->done);
return IRQ_HANDLED;
}
return IRQ_NONE;
}
static int sun6i_spi_runtime_resume(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct sun6i_spi *sspi = spi_master_get_devdata(master);
int ret;
ret = clk_prepare_enable(sspi->hclk);
if (ret) {
dev_err(dev, "Couldn't enable AHB clock\n");
goto out;
}
ret = clk_prepare_enable(sspi->mclk);
if (ret) {
dev_err(dev, "Couldn't enable module clock\n");
goto err;
}
ret = reset_control_deassert(sspi->rstc);
if (ret) {
dev_err(dev, "Couldn't deassert the device from reset\n");
goto err2;
}
sun6i_spi_write(sspi, SUN6I_GBL_CTL_REG,
SUN6I_GBL_CTL_BUS_ENABLE | SUN6I_GBL_CTL_MASTER | SUN6I_GBL_CTL_TP);
return 0;
err2:
clk_disable_unprepare(sspi->mclk);
err:
clk_disable_unprepare(sspi->hclk);
out:
return ret;
}
static int sun6i_spi_runtime_suspend(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct sun6i_spi *sspi = spi_master_get_devdata(master);
reset_control_assert(sspi->rstc);
clk_disable_unprepare(sspi->mclk);
clk_disable_unprepare(sspi->hclk);
return 0;
}
static int sun6i_spi_probe(struct platform_device *pdev)
{
struct spi_master *master;
struct sun6i_spi *sspi;
struct resource *res;
int ret = 0, irq;
master = spi_alloc_master(&pdev->dev, sizeof(struct sun6i_spi));
if (!master) {
dev_err(&pdev->dev, "Unable to allocate SPI Master\n");
return -ENOMEM;
}
platform_set_drvdata(pdev, master);
sspi = spi_master_get_devdata(master);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
sspi->base_addr = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(sspi->base_addr)) {
ret = PTR_ERR(sspi->base_addr);
goto err_free_master;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "No spi IRQ specified\n");
ret = -ENXIO;
goto err_free_master;
}
ret = devm_request_irq(&pdev->dev, irq, sun6i_spi_handler,
0, "sun6i-spi", sspi);
if (ret) {
dev_err(&pdev->dev, "Cannot request IRQ\n");
goto err_free_master;
}
sspi->master = master;
master->set_cs = sun6i_spi_set_cs;
master->transfer_one = sun6i_spi_transfer_one;
master->num_chipselect = 4;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
master->bits_per_word_mask = SPI_BPW_MASK(8);
master->dev.of_node = pdev->dev.of_node;
master->auto_runtime_pm = true;
sspi->hclk = devm_clk_get(&pdev->dev, "ahb");
if (IS_ERR(sspi->hclk)) {
dev_err(&pdev->dev, "Unable to acquire AHB clock\n");
ret = PTR_ERR(sspi->hclk);
goto err_free_master;
}
sspi->mclk = devm_clk_get(&pdev->dev, "mod");
if (IS_ERR(sspi->mclk)) {
dev_err(&pdev->dev, "Unable to acquire module clock\n");
ret = PTR_ERR(sspi->mclk);
goto err_free_master;
}
init_completion(&sspi->done);
sspi->rstc = devm_reset_control_get(&pdev->dev, NULL);
if (IS_ERR(sspi->rstc)) {
dev_err(&pdev->dev, "Couldn't get reset controller\n");
ret = PTR_ERR(sspi->rstc);
goto err_free_master;
}
/*
* This wake-up/shutdown pattern is to be able to have the
* device woken up, even if runtime_pm is disabled
*/
ret = sun6i_spi_runtime_resume(&pdev->dev);
if (ret) {
dev_err(&pdev->dev, "Couldn't resume the device\n");
goto err_free_master;
}
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
pm_runtime_idle(&pdev->dev);
ret = devm_spi_register_master(&pdev->dev, master);
if (ret) {
dev_err(&pdev->dev, "cannot register SPI master\n");
goto err_pm_disable;
}
return 0;
err_pm_disable:
pm_runtime_disable(&pdev->dev);
sun6i_spi_runtime_suspend(&pdev->dev);
err_free_master:
spi_master_put(master);
return ret;
}
static int sun6i_spi_remove(struct platform_device *pdev)
{
pm_runtime_disable(&pdev->dev);
return 0;
}
static const struct of_device_id sun6i_spi_match[] = {
{ .compatible = "allwinner,sun6i-a31-spi", },
{}
};
MODULE_DEVICE_TABLE(of, sun6i_spi_match);
static const struct dev_pm_ops sun6i_spi_pm_ops = {
.runtime_resume = sun6i_spi_runtime_resume,
.runtime_suspend = sun6i_spi_runtime_suspend,
};
static struct platform_driver sun6i_spi_driver = {
.probe = sun6i_spi_probe,
.remove = sun6i_spi_remove,
.driver = {
.name = "sun6i-spi",
.owner = THIS_MODULE,
.of_match_table = sun6i_spi_match,
.pm = &sun6i_spi_pm_ops,
},
};
module_platform_driver(sun6i_spi_driver);
MODULE_AUTHOR("Pan Nan <pannan@allwinnertech.com>");
MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
MODULE_DESCRIPTION("Allwinner A31 SPI controller driver");
MODULE_LICENSE("GPL");

Просмотреть файл

@ -23,7 +23,6 @@
#include <linux/dma-mapping.h>
#include <linux/dmapool.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
@ -172,7 +171,6 @@ struct tegra_spi_data {
void __iomem *base;
phys_addr_t phys;
unsigned irq;
u32 spi_max_frequency;
u32 cur_speed;
struct spi_device *cur_spi;
@ -761,11 +759,6 @@ static int tegra_spi_setup(struct spi_device *spi)
spi->mode & SPI_CPHA ? "" : "~",
spi->max_speed_hz);
BUG_ON(spi->chip_select >= MAX_CHIP_SELECT);
/* Set speed to the spi max fequency if spi device has not set */
spi->max_speed_hz = spi->max_speed_hz ? : tspi->spi_max_frequency;
ret = pm_runtime_get_sync(tspi->dev);
if (ret < 0) {
dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret);
@ -853,8 +846,8 @@ complete_xfer:
SPI_COMMAND1);
tegra_spi_transfer_delay(xfer->delay_usecs);
goto exit;
} else if (msg->transfers.prev == &xfer->transfer_list) {
/* This is the last transfer in message */
} else if (list_is_last(&xfer->transfer_list,
&msg->transfers)) {
if (xfer->cs_change)
tspi->cs_control = spi;
else {
@ -1019,16 +1012,6 @@ static irqreturn_t tegra_spi_isr(int irq, void *context_data)
return IRQ_WAKE_THREAD;
}
static void tegra_spi_parse_dt(struct platform_device *pdev,
struct tegra_spi_data *tspi)
{
struct device_node *np = pdev->dev.of_node;
if (of_property_read_u32(np, "spi-max-frequency",
&tspi->spi_max_frequency))
tspi->spi_max_frequency = 25000000; /* 25MHz */
}
static struct of_device_id tegra_spi_of_match[] = {
{ .compatible = "nvidia,tegra114-spi", },
{}
@ -1050,15 +1033,15 @@ static int tegra_spi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, master);
tspi = spi_master_get_devdata(master);
/* Parse DT */
tegra_spi_parse_dt(pdev, tspi);
if (of_property_read_u32(pdev->dev.of_node, "spi-max-frequency",
&master->max_speed_hz))
master->max_speed_hz = 25000000; /* 25MHz */
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->setup = tegra_spi_setup;
master->transfer_one_message = tegra_spi_transfer_one_message;
master->num_chipselect = MAX_CHIP_SELECT;
master->bus_num = -1;
master->auto_runtime_pm = true;
tspi->master = master;

Просмотреть файл

@ -22,7 +22,6 @@
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
@ -121,7 +120,6 @@ struct tegra_sflash_data {
struct reset_control *rst;
void __iomem *base;
unsigned irq;
u32 spi_max_frequency;
u32 cur_speed;
struct spi_device *cur_spi;
@ -315,15 +313,6 @@ static int tegra_sflash_start_transfer_one(struct spi_device *spi,
return tegra_sflash_start_cpu_based_transfer(tsd, t);
}
static int tegra_sflash_setup(struct spi_device *spi)
{
struct tegra_sflash_data *tsd = spi_master_get_devdata(spi->master);
/* Set speed to the spi max fequency if spi device has not set */
spi->max_speed_hz = spi->max_speed_hz ? : tsd->spi_max_frequency;
return 0;
}
static int tegra_sflash_transfer_one_message(struct spi_master *master,
struct spi_message *msg)
{
@ -430,15 +419,6 @@ static irqreturn_t tegra_sflash_isr(int irq, void *context_data)
return handle_cpu_based_xfer(tsd);
}
static void tegra_sflash_parse_dt(struct tegra_sflash_data *tsd)
{
struct device_node *np = tsd->dev->of_node;
if (of_property_read_u32(np, "spi-max-frequency",
&tsd->spi_max_frequency))
tsd->spi_max_frequency = 25000000; /* 25MHz */
}
static struct of_device_id tegra_sflash_of_match[] = {
{ .compatible = "nvidia,tegra20-sflash", },
{}
@ -467,11 +447,9 @@ static int tegra_sflash_probe(struct platform_device *pdev)
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA;
master->setup = tegra_sflash_setup;
master->transfer_one_message = tegra_sflash_transfer_one_message;
master->auto_runtime_pm = true;
master->num_chipselect = MAX_CHIP_SELECT;
master->bus_num = -1;
platform_set_drvdata(pdev, master);
tsd = spi_master_get_devdata(master);
@ -479,7 +457,9 @@ static int tegra_sflash_probe(struct platform_device *pdev)
tsd->dev = &pdev->dev;
spin_lock_init(&tsd->lock);
tegra_sflash_parse_dt(tsd);
if (of_property_read_u32(tsd->dev->of_node, "spi-max-frequency",
&master->max_speed_hz))
master->max_speed_hz = 25000000; /* 25MHz */
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
tsd->base = devm_ioremap_resource(&pdev->dev, r);

Просмотреть файл

@ -23,7 +23,6 @@
#include <linux/dma-mapping.h>
#include <linux/dmapool.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
@ -171,7 +170,6 @@ struct tegra_slink_data {
void __iomem *base;
phys_addr_t phys;
unsigned irq;
u32 spi_max_frequency;
u32 cur_speed;
struct spi_device *cur_spi;
@ -761,10 +759,6 @@ static int tegra_slink_setup(struct spi_device *spi)
spi->mode & SPI_CPHA ? "" : "~",
spi->max_speed_hz);
BUG_ON(spi->chip_select >= MAX_CHIP_SELECT);
/* Set speed to the spi max fequency if spi device has not set */
spi->max_speed_hz = spi->max_speed_hz ? : tspi->spi_max_frequency;
ret = pm_runtime_get_sync(tspi->dev);
if (ret < 0) {
dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret);
@ -999,15 +993,6 @@ static irqreturn_t tegra_slink_isr(int irq, void *context_data)
return IRQ_WAKE_THREAD;
}
static void tegra_slink_parse_dt(struct tegra_slink_data *tspi)
{
struct device_node *np = tspi->dev->of_node;
if (of_property_read_u32(np, "spi-max-frequency",
&tspi->spi_max_frequency))
tspi->spi_max_frequency = 25000000; /* 25MHz */
}
static const struct tegra_slink_chip_data tegra30_spi_cdata = {
.cs_hold_time = true,
};
@ -1053,7 +1038,6 @@ static int tegra_slink_probe(struct platform_device *pdev)
master->unprepare_message = tegra_slink_unprepare_message;
master->auto_runtime_pm = true;
master->num_chipselect = MAX_CHIP_SELECT;
master->bus_num = -1;
platform_set_drvdata(pdev, master);
tspi = spi_master_get_devdata(master);
@ -1062,7 +1046,9 @@ static int tegra_slink_probe(struct platform_device *pdev)
tspi->chip_data = cdata;
spin_lock_init(&tspi->lock);
tegra_slink_parse_dt(tspi);
if (of_property_read_u32(tspi->dev->of_node, "spi-max-frequency",
&master->max_speed_hz))
master->max_speed_hz = 25000000; /* 25MHz */
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) {

Просмотреть файл

@ -429,13 +429,13 @@ static int ti_qspi_probe(struct platform_device *pdev)
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD;
master->bus_num = -1;
master->flags = SPI_MASTER_HALF_DUPLEX;
master->setup = ti_qspi_setup;
master->auto_runtime_pm = true;
master->transfer_one_message = ti_qspi_start_transfer_one;
master->dev.of_node = pdev->dev.of_node;
master->bits_per_word_mask = BIT(32 - 1) | BIT(16 - 1) | BIT(8 - 1);
master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) |
SPI_BPW_MASK(8);
if (!of_property_read_u32(np, "num-cs", &num_cs))
master->num_chipselect = num_cs;
@ -461,7 +461,6 @@ static int ti_qspi_probe(struct platform_device *pdev)
if (res_mmap == NULL) {
dev_err(&pdev->dev,
"memory mapped resource not required\n");
return -ENODEV;
}
}

Просмотреть файл

@ -1,378 +0,0 @@
/*
* Sequencer Serial Port (SSP) based SPI master driver
*
* Copyright (C) 2010 Texas Instruments Inc
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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
*/
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/mfd/ti_ssp.h>
#define MODE_BITS (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH)
struct ti_ssp_spi {
struct spi_master *master;
struct device *dev;
spinlock_t lock;
struct list_head msg_queue;
struct completion complete;
bool shutdown;
struct workqueue_struct *workqueue;
struct work_struct work;
u8 mode, bpw;
int cs_active;
u32 pc_en, pc_dis, pc_wr, pc_rd;
void (*select)(int cs);
};
static u32 ti_ssp_spi_rx(struct ti_ssp_spi *hw)
{
u32 ret;
ti_ssp_run(hw->dev, hw->pc_rd, 0, &ret);
return ret;
}
static void ti_ssp_spi_tx(struct ti_ssp_spi *hw, u32 data)
{
ti_ssp_run(hw->dev, hw->pc_wr, data << (32 - hw->bpw), NULL);
}
static int ti_ssp_spi_txrx(struct ti_ssp_spi *hw, struct spi_message *msg,
struct spi_transfer *t)
{
int count;
if (hw->bpw <= 8) {
u8 *rx = t->rx_buf;
const u8 *tx = t->tx_buf;
for (count = 0; count < t->len; count += 1) {
if (t->tx_buf)
ti_ssp_spi_tx(hw, *tx++);
if (t->rx_buf)
*rx++ = ti_ssp_spi_rx(hw);
}
} else if (hw->bpw <= 16) {
u16 *rx = t->rx_buf;
const u16 *tx = t->tx_buf;
for (count = 0; count < t->len; count += 2) {
if (t->tx_buf)
ti_ssp_spi_tx(hw, *tx++);
if (t->rx_buf)
*rx++ = ti_ssp_spi_rx(hw);
}
} else {
u32 *rx = t->rx_buf;
const u32 *tx = t->tx_buf;
for (count = 0; count < t->len; count += 4) {
if (t->tx_buf)
ti_ssp_spi_tx(hw, *tx++);
if (t->rx_buf)
*rx++ = ti_ssp_spi_rx(hw);
}
}
msg->actual_length += count; /* bytes transferred */
dev_dbg(&msg->spi->dev, "xfer %s%s, %d bytes, %d bpw, count %d%s\n",
t->tx_buf ? "tx" : "", t->rx_buf ? "rx" : "", t->len,
hw->bpw, count, (count < t->len) ? " (under)" : "");
return (count < t->len) ? -EIO : 0; /* left over data */
}
static void ti_ssp_spi_chip_select(struct ti_ssp_spi *hw, int cs_active)
{
cs_active = !!cs_active;
if (cs_active == hw->cs_active)
return;
ti_ssp_run(hw->dev, cs_active ? hw->pc_en : hw->pc_dis, 0, NULL);
hw->cs_active = cs_active;
}
#define __SHIFT_OUT(bits) (SSP_OPCODE_SHIFT | SSP_OUT_MODE | \
cs_en | clk | SSP_COUNT((bits) * 2 - 1))
#define __SHIFT_IN(bits) (SSP_OPCODE_SHIFT | SSP_IN_MODE | \
cs_en | clk | SSP_COUNT((bits) * 2 - 1))
static int ti_ssp_spi_setup_transfer(struct ti_ssp_spi *hw, u8 bpw, u8 mode)
{
int error, idx = 0;
u32 seqram[16];
u32 cs_en, cs_dis, clk;
u32 topbits, botbits;
mode &= MODE_BITS;
if (mode == hw->mode && bpw == hw->bpw)
return 0;
cs_en = (mode & SPI_CS_HIGH) ? SSP_CS_HIGH : SSP_CS_LOW;
cs_dis = (mode & SPI_CS_HIGH) ? SSP_CS_LOW : SSP_CS_HIGH;
clk = (mode & SPI_CPOL) ? SSP_CLK_HIGH : SSP_CLK_LOW;
/* Construct instructions */
/* Disable Chip Select */
hw->pc_dis = idx;
seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_dis | clk;
seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_dis | clk;
/* Enable Chip Select */
hw->pc_en = idx;
seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_en | clk;
seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk;
/* Reads and writes need to be split for bpw > 16 */
topbits = (bpw > 16) ? 16 : bpw;
botbits = bpw - topbits;
/* Write */
hw->pc_wr = idx;
seqram[idx++] = __SHIFT_OUT(topbits) | SSP_ADDR_REG;
if (botbits)
seqram[idx++] = __SHIFT_OUT(botbits) | SSP_DATA_REG;
seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk;
/* Read */
hw->pc_rd = idx;
if (botbits)
seqram[idx++] = __SHIFT_IN(botbits) | SSP_ADDR_REG;
seqram[idx++] = __SHIFT_IN(topbits) | SSP_DATA_REG;
seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk;
error = ti_ssp_load(hw->dev, 0, seqram, idx);
if (error < 0)
return error;
error = ti_ssp_set_mode(hw->dev, ((mode & SPI_CPHA) ?
0 : SSP_EARLY_DIN));
if (error < 0)
return error;
hw->bpw = bpw;
hw->mode = mode;
return error;
}
static void ti_ssp_spi_work(struct work_struct *work)
{
struct ti_ssp_spi *hw = container_of(work, struct ti_ssp_spi, work);
spin_lock(&hw->lock);
while (!list_empty(&hw->msg_queue)) {
struct spi_message *m;
struct spi_device *spi;
struct spi_transfer *t = NULL;
int status = 0;
m = container_of(hw->msg_queue.next, struct spi_message,
queue);
list_del_init(&m->queue);
spin_unlock(&hw->lock);
spi = m->spi;
if (hw->select)
hw->select(spi->chip_select);
list_for_each_entry(t, &m->transfers, transfer_list) {
int bpw = spi->bits_per_word;
int xfer_status;
if (t->bits_per_word)
bpw = t->bits_per_word;
if (ti_ssp_spi_setup_transfer(hw, bpw, spi->mode) < 0)
break;
ti_ssp_spi_chip_select(hw, 1);
xfer_status = ti_ssp_spi_txrx(hw, m, t);
if (xfer_status < 0)
status = xfer_status;
if (t->delay_usecs)
udelay(t->delay_usecs);
if (t->cs_change)
ti_ssp_spi_chip_select(hw, 0);
}
ti_ssp_spi_chip_select(hw, 0);
m->status = status;
m->complete(m->context);
spin_lock(&hw->lock);
}
if (hw->shutdown)
complete(&hw->complete);
spin_unlock(&hw->lock);
}
static int ti_ssp_spi_transfer(struct spi_device *spi, struct spi_message *m)
{
struct ti_ssp_spi *hw;
struct spi_transfer *t;
int error = 0;
m->actual_length = 0;
m->status = -EINPROGRESS;
hw = spi_master_get_devdata(spi->master);
if (list_empty(&m->transfers) || !m->complete)
return -EINVAL;
list_for_each_entry(t, &m->transfers, transfer_list) {
if (t->len && !(t->rx_buf || t->tx_buf)) {
dev_err(&spi->dev, "invalid xfer, no buffer\n");
return -EINVAL;
}
if (t->len && t->rx_buf && t->tx_buf) {
dev_err(&spi->dev, "invalid xfer, full duplex\n");
return -EINVAL;
}
}
spin_lock(&hw->lock);
if (hw->shutdown) {
error = -ESHUTDOWN;
goto error_unlock;
}
list_add_tail(&m->queue, &hw->msg_queue);
queue_work(hw->workqueue, &hw->work);
error_unlock:
spin_unlock(&hw->lock);
return error;
}
static int ti_ssp_spi_probe(struct platform_device *pdev)
{
const struct ti_ssp_spi_data *pdata;
struct ti_ssp_spi *hw;
struct spi_master *master;
struct device *dev = &pdev->dev;
int error = 0;
pdata = dev_get_platdata(dev);
if (!pdata) {
dev_err(dev, "platform data not found\n");
return -EINVAL;
}
master = spi_alloc_master(dev, sizeof(struct ti_ssp_spi));
if (!master) {
dev_err(dev, "cannot allocate SPI master\n");
return -ENOMEM;
}
hw = spi_master_get_devdata(master);
platform_set_drvdata(pdev, hw);
hw->master = master;
hw->dev = dev;
hw->select = pdata->select;
spin_lock_init(&hw->lock);
init_completion(&hw->complete);
INIT_LIST_HEAD(&hw->msg_queue);
INIT_WORK(&hw->work, ti_ssp_spi_work);
hw->workqueue = create_singlethread_workqueue(dev_name(dev));
if (!hw->workqueue) {
error = -ENOMEM;
dev_err(dev, "work queue creation failed\n");
goto error_wq;
}
error = ti_ssp_set_iosel(hw->dev, pdata->iosel);
if (error < 0) {
dev_err(dev, "io setup failed\n");
goto error_iosel;
}
master->bus_num = pdev->id;
master->num_chipselect = pdata->num_cs;
master->mode_bits = MODE_BITS;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
master->flags = SPI_MASTER_HALF_DUPLEX;
master->transfer = ti_ssp_spi_transfer;
error = spi_register_master(master);
if (error) {
dev_err(dev, "master registration failed\n");
goto error_reg;
}
return 0;
error_reg:
error_iosel:
destroy_workqueue(hw->workqueue);
error_wq:
spi_master_put(master);
return error;
}
static int ti_ssp_spi_remove(struct platform_device *pdev)
{
struct ti_ssp_spi *hw = platform_get_drvdata(pdev);
int error;
hw->shutdown = 1;
while (!list_empty(&hw->msg_queue)) {
error = wait_for_completion_interruptible(&hw->complete);
if (error < 0) {
hw->shutdown = 0;
return error;
}
}
destroy_workqueue(hw->workqueue);
spi_unregister_master(hw->master);
return 0;
}
static struct platform_driver ti_ssp_spi_driver = {
.probe = ti_ssp_spi_probe,
.remove = ti_ssp_spi_remove,
.driver = {
.name = "ti-ssp-spi",
.owner = THIS_MODULE,
},
};
module_platform_driver(ti_ssp_spi_driver);
MODULE_DESCRIPTION("SSP SPI Master");
MODULE_AUTHOR("Cyril Chemparathy");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:ti-ssp-spi");

Просмотреть файл

@ -332,7 +332,7 @@ static void pch_spi_handler_sub(struct pch_spi_data *data, u32 reg_spsr_val,
data->transfer_active = false;
wake_up(&data->wait);
} else {
dev_err(&data->master->dev,
dev_vdbg(&data->master->dev,
"%s : Transfer is not completed",
__func__);
}
@ -464,20 +464,6 @@ static void pch_spi_reset(struct spi_master *master)
pch_spi_writereg(master, PCH_SRST, 0x0);
}
static int pch_spi_setup(struct spi_device *pspi)
{
/* Check baud rate setting */
/* if baud rate of chip is greater than
max we can support,return error */
if ((pspi->max_speed_hz) > PCH_MAX_BAUDRATE)
pspi->max_speed_hz = PCH_MAX_BAUDRATE;
dev_dbg(&pspi->dev, "%s MODE = %x\n", __func__,
(pspi->mode) & (SPI_CPOL | SPI_CPHA));
return 0;
}
static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg)
{
@ -486,23 +472,6 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg)
int retval;
unsigned long flags;
/* validate spi message and baud rate */
if (unlikely(list_empty(&pmsg->transfers) == 1)) {
dev_err(&pspi->dev, "%s list empty\n", __func__);
retval = -EINVAL;
goto err_out;
}
if (unlikely(pspi->max_speed_hz == 0)) {
dev_err(&pspi->dev, "%s pch_spi_transfer maxspeed=%d\n",
__func__, pspi->max_speed_hz);
retval = -EINVAL;
goto err_out;
}
dev_dbg(&pspi->dev,
"%s Transfer List not empty. Transfer Speed is set.\n", __func__);
spin_lock_irqsave(&data->lock, flags);
/* validate Tx/Rx buffers and Transfer length */
list_for_each_entry(transfer, &pmsg->transfers, transfer_list) {
@ -523,10 +492,6 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg)
dev_dbg(&pspi->dev,
"%s Tx/Rx buffer valid. Transfer length valid\n",
__func__);
/* if baud rate has been specified validate the same */
if (transfer->speed_hz > PCH_MAX_BAUDRATE)
transfer->speed_hz = PCH_MAX_BAUDRATE;
}
spin_unlock_irqrestore(&data->lock, flags);
@ -1151,8 +1116,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw)
dma->nent = num;
dma->desc_tx = desc_tx;
dev_dbg(&data->master->dev, "\n%s:Pulling down SSN low - writing "
"0x2 to SSNXCR\n", __func__);
dev_dbg(&data->master->dev, "%s:Pulling down SSN low - writing 0x2 to SSNXCR\n", __func__);
spin_lock_irqsave(&data->lock, flags);
pch_spi_writereg(data->master, PCH_SSNXCR, SSN_LOW);
@ -1418,10 +1382,10 @@ static int pch_spi_pd_probe(struct platform_device *plat_dev)
/* initialize members of SPI master */
master->num_chipselect = PCH_MAX_CS;
master->setup = pch_spi_setup;
master->transfer = pch_spi_transfer;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
master->max_speed_hz = PCH_MAX_BAUDRATE;
data->board_dat = board_dat;
data->plat_dev = plat_dev;
@ -1605,8 +1569,7 @@ static struct platform_driver pch_spi_pd_driver = {
.resume = pch_spi_pd_resume
};
static int pch_spi_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
static int pch_spi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct pch_spi_board_data *board_dat;
struct platform_device *pd_dev = NULL;
@ -1676,6 +1639,8 @@ static int pch_spi_probe(struct pci_dev *pdev,
return 0;
err_platform_device:
while (--i >= 0)
platform_device_unregister(pd_dev_save->pd_save[i]);
pci_disable_device(pdev);
pci_enable_device:
pci_release_regions(pdev);

Просмотреть файл

@ -80,7 +80,6 @@ struct txx9spi {
void __iomem *membase;
int baseclk;
struct clk *clk;
u32 max_speed_hz, min_speed_hz;
int last_chipselect;
int last_chipselect_val;
};
@ -117,9 +116,7 @@ static int txx9spi_setup(struct spi_device *spi)
{
struct txx9spi *c = spi_master_get_devdata(spi->master);
if (!spi->max_speed_hz
|| spi->max_speed_hz > c->max_speed_hz
|| spi->max_speed_hz < c->min_speed_hz)
if (!spi->max_speed_hz)
return -EINVAL;
if (gpio_direction_output(spi->chip_select,
@ -309,15 +306,8 @@ static int txx9spi_transfer(struct spi_device *spi, struct spi_message *m)
/* check each transfer's parameters */
list_for_each_entry(t, &m->transfers, transfer_list) {
u32 speed_hz = t->speed_hz ? : spi->max_speed_hz;
u8 bits_per_word = t->bits_per_word;
if (!t->tx_buf && !t->rx_buf && t->len)
return -EINVAL;
if (t->len & ((bits_per_word >> 3) - 1))
return -EINVAL;
if (speed_hz < c->min_speed_hz || speed_hz > c->max_speed_hz)
return -EINVAL;
}
spin_lock_irqsave(&c->lock, flags);
@ -360,17 +350,12 @@ static int txx9spi_probe(struct platform_device *dev)
goto exit;
}
c->baseclk = clk_get_rate(c->clk);
c->min_speed_hz = DIV_ROUND_UP(c->baseclk, SPI_MAX_DIVIDER + 1);
c->max_speed_hz = c->baseclk / (SPI_MIN_DIVIDER + 1);
master->min_speed_hz = DIV_ROUND_UP(c->baseclk, SPI_MAX_DIVIDER + 1);
master->max_speed_hz = c->baseclk / (SPI_MIN_DIVIDER + 1);
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!res)
goto exit_busy;
if (!devm_request_mem_region(&dev->dev, res->start, resource_size(res),
"spi_txx9"))
goto exit_busy;
c->membase = devm_ioremap(&dev->dev, res->start, resource_size(res));
if (!c->membase)
c->membase = devm_ioremap_resource(&dev->dev, res);
if (IS_ERR(c->membase))
goto exit_busy;
/* enter config mode */

Просмотреть файл

@ -8,7 +8,6 @@
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/i2c.h>
@ -74,15 +73,13 @@ static void spi_xcomm_chipselect(struct spi_xcomm *spi_xcomm,
static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm,
struct spi_device *spi, struct spi_transfer *t, unsigned int *settings)
{
unsigned int speed;
if (t->len > 62)
return -EINVAL;
speed = t->speed_hz ? t->speed_hz : spi->max_speed_hz;
if (t->speed_hz != spi_xcomm->current_speed) {
unsigned int divider;
if (speed != spi_xcomm->current_speed) {
unsigned int divider = DIV_ROUND_UP(SPI_XCOMM_CLOCK, speed);
divider = DIV_ROUND_UP(SPI_XCOMM_CLOCK, t->speed_hz);
if (divider >= 64)
*settings |= SPI_XCOMM_SETTINGS_CLOCK_DIV_64;
else if (divider >= 16)
@ -90,7 +87,7 @@ static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm,
else
*settings |= SPI_XCOMM_SETTINGS_CLOCK_DIV_4;
spi_xcomm->current_speed = speed;
spi_xcomm->current_speed = t->speed_hz;
}
if (spi->mode & SPI_CPOL)
@ -148,8 +145,6 @@ static int spi_xcomm_transfer_one(struct spi_master *master,
int status = 0;
bool is_last;
is_first = true;
spi_xcomm_chipselect(spi_xcomm, spi, true);
list_for_each_entry(t, &msg->transfers, transfer_list) {

Просмотреть файл

@ -14,7 +14,6 @@
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/platform_device.h>
@ -88,10 +87,10 @@ struct xilinx_spi {
const u8 *tx_ptr; /* pointer in the Rx buffer */
int remaining_bytes; /* the number of bytes left to transfer */
u8 bits_per_word;
unsigned int (*read_fn) (void __iomem *);
void (*write_fn) (u32, void __iomem *);
void (*tx_fn) (struct xilinx_spi *);
void (*rx_fn) (struct xilinx_spi *);
unsigned int (*read_fn)(void __iomem *);
void (*write_fn)(u32, void __iomem *);
void (*tx_fn)(struct xilinx_spi *);
void (*rx_fn)(struct xilinx_spi *);
};
static void xspi_write32(u32 val, void __iomem *addr)
@ -209,26 +208,11 @@ static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
}
/* spi_bitbang requires custom setup_transfer() to be defined if there is a
* custom txrx_bufs(). We have nothing to setup here as the SPI IP block
* supports 8 or 16 bits per word which cannot be changed in software.
* SPI clock can't be changed in software either.
* Check for correct bits per word. Chip select delay calculations could be
* added here as soon as bitbang_work() can be made aware of the delay value.
* custom txrx_bufs().
*/
static int xilinx_spi_setup_transfer(struct spi_device *spi,
struct spi_transfer *t)
{
struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
u8 bits_per_word;
bits_per_word = (t && t->bits_per_word)
? t->bits_per_word : spi->bits_per_word;
if (bits_per_word != xspi->bits_per_word) {
dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
__func__, bits_per_word);
return -EINVAL;
}
return 0;
}
@ -407,6 +391,7 @@ static int xilinx_spi_probe(struct platform_device *pdev)
xspi->write_fn = xspi_write32_be;
}
master->bits_per_word_mask = SPI_BPW_MASK(bits_per_word);
xspi->bits_per_word = bits_per_word;
if (xspi->bits_per_word == 8) {
xspi->tx_fn = xspi_tx8;

Просмотреть файл

@ -0,0 +1,170 @@
/*
* Xtensa xtfpga SPI controller driver
*
* Copyright (c) 2014 Cadence Design Systems Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#define XTFPGA_SPI_NAME "xtfpga_spi"
#define XTFPGA_SPI_START 0x0
#define XTFPGA_SPI_BUSY 0x4
#define XTFPGA_SPI_DATA 0x8
#define BUSY_WAIT_US 100
struct xtfpga_spi {
struct spi_bitbang bitbang;
void __iomem *regs;
u32 data;
unsigned data_sz;
};
static inline void xtfpga_spi_write32(const struct xtfpga_spi *spi,
unsigned addr, u32 val)
{
iowrite32(val, spi->regs + addr);
}
static inline unsigned int xtfpga_spi_read32(const struct xtfpga_spi *spi,
unsigned addr)
{
return ioread32(spi->regs + addr);
}
static inline void xtfpga_spi_wait_busy(struct xtfpga_spi *xspi)
{
unsigned i;
for (i = 0; xtfpga_spi_read32(xspi, XTFPGA_SPI_BUSY) &&
i < BUSY_WAIT_US; ++i)
udelay(1);
WARN_ON_ONCE(i == BUSY_WAIT_US);
}
static u32 xtfpga_spi_txrx_word(struct spi_device *spi, unsigned nsecs,
u32 v, u8 bits)
{
struct xtfpga_spi *xspi = spi_master_get_devdata(spi->master);
xspi->data = (xspi->data << bits) | (v & GENMASK(bits - 1, 0));
xspi->data_sz += bits;
if (xspi->data_sz >= 16) {
xtfpga_spi_write32(xspi, XTFPGA_SPI_DATA,
xspi->data >> (xspi->data_sz - 16));
xspi->data_sz -= 16;
xtfpga_spi_write32(xspi, XTFPGA_SPI_START, 1);
xtfpga_spi_wait_busy(xspi);
xtfpga_spi_write32(xspi, XTFPGA_SPI_START, 0);
}
return 0;
}
static void xtfpga_spi_chipselect(struct spi_device *spi, int is_on)
{
struct xtfpga_spi *xspi = spi_master_get_devdata(spi->master);
WARN_ON(xspi->data_sz != 0);
xspi->data_sz = 0;
}
static int xtfpga_spi_probe(struct platform_device *pdev)
{
struct xtfpga_spi *xspi;
struct resource *mem;
int ret;
struct spi_master *master;
master = spi_alloc_master(&pdev->dev, sizeof(struct xtfpga_spi));
if (!master)
return -ENOMEM;
master->flags = SPI_MASTER_NO_RX;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16);
master->bus_num = pdev->dev.id;
master->dev.of_node = pdev->dev.of_node;
xspi = spi_master_get_devdata(master);
xspi->bitbang.master = master;
xspi->bitbang.chipselect = xtfpga_spi_chipselect;
xspi->bitbang.txrx_word[SPI_MODE_0] = xtfpga_spi_txrx_word;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
dev_err(&pdev->dev, "No memory resource\n");
ret = -ENODEV;
goto err;
}
xspi->regs = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(xspi->regs)) {
ret = PTR_ERR(xspi->regs);
goto err;
}
xtfpga_spi_write32(xspi, XTFPGA_SPI_START, 0);
usleep_range(1000, 2000);
if (xtfpga_spi_read32(xspi, XTFPGA_SPI_BUSY)) {
dev_err(&pdev->dev, "Device stuck in busy state\n");
ret = -EBUSY;
goto err;
}
ret = spi_bitbang_start(&xspi->bitbang);
if (ret < 0) {
dev_err(&pdev->dev, "spi_bitbang_start failed\n");
goto err;
}
platform_set_drvdata(pdev, master);
return 0;
err:
spi_master_put(master);
return ret;
}
static int xtfpga_spi_remove(struct platform_device *pdev)
{
struct spi_master *master = platform_get_drvdata(pdev);
struct xtfpga_spi *xspi = spi_master_get_devdata(master);
spi_bitbang_stop(&xspi->bitbang);
spi_master_put(master);
return 0;
}
MODULE_ALIAS("platform:" XTFPGA_SPI_NAME);
#ifdef CONFIG_OF
static const struct of_device_id xtfpga_spi_of_match[] = {
{ .compatible = "cdns,xtfpga-spi", },
{}
};
MODULE_DEVICE_TABLE(of, xtfpga_spi_of_match);
#endif
static struct platform_driver xtfpga_spi_driver = {
.probe = xtfpga_spi_probe,
.remove = xtfpga_spi_remove,
.driver = {
.name = XTFPGA_SPI_NAME,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(xtfpga_spi_of_match),
},
};
module_platform_driver(xtfpga_spi_driver);
MODULE_AUTHOR("Max Filippov <jcmvbkbc@gmail.com>");
MODULE_DESCRIPTION("xtensa xtfpga SPI driver");
MODULE_LICENSE("GPL");

Просмотреть файл

@ -24,6 +24,8 @@
#include <linux/device.h>
#include <linux/init.h>
#include <linux/cache.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
@ -255,13 +257,12 @@ EXPORT_SYMBOL_GPL(spi_bus_type);
static int spi_drv_probe(struct device *dev)
{
const struct spi_driver *sdrv = to_spi_driver(dev->driver);
struct spi_device *spi = to_spi_device(dev);
int ret;
acpi_dev_pm_attach(&spi->dev, true);
ret = sdrv->probe(spi);
acpi_dev_pm_attach(dev, true);
ret = sdrv->probe(to_spi_device(dev));
if (ret)
acpi_dev_pm_detach(&spi->dev, true);
acpi_dev_pm_detach(dev, true);
return ret;
}
@ -269,11 +270,10 @@ static int spi_drv_probe(struct device *dev)
static int spi_drv_remove(struct device *dev)
{
const struct spi_driver *sdrv = to_spi_driver(dev->driver);
struct spi_device *spi = to_spi_device(dev);
int ret;
ret = sdrv->remove(spi);
acpi_dev_pm_detach(&spi->dev, true);
ret = sdrv->remove(to_spi_device(dev));
acpi_dev_pm_detach(dev, true);
return ret;
}
@ -580,6 +580,169 @@ static void spi_set_cs(struct spi_device *spi, bool enable)
spi->master->set_cs(spi, !enable);
}
static int spi_map_buf(struct spi_master *master, struct device *dev,
struct sg_table *sgt, void *buf, size_t len,
enum dma_data_direction dir)
{
const bool vmalloced_buf = is_vmalloc_addr(buf);
const int desc_len = vmalloced_buf ? PAGE_SIZE : master->max_dma_len;
const int sgs = DIV_ROUND_UP(len, desc_len);
struct page *vm_page;
void *sg_buf;
size_t min;
int i, ret;
ret = sg_alloc_table(sgt, sgs, GFP_KERNEL);
if (ret != 0)
return ret;
for (i = 0; i < sgs; i++) {
min = min_t(size_t, len, desc_len);
if (vmalloced_buf) {
vm_page = vmalloc_to_page(buf);
if (!vm_page) {
sg_free_table(sgt);
return -ENOMEM;
}
sg_buf = page_address(vm_page) +
((size_t)buf & ~PAGE_MASK);
} else {
sg_buf = buf;
}
sg_set_buf(&sgt->sgl[i], sg_buf, min);
buf += min;
len -= min;
}
ret = dma_map_sg(dev, sgt->sgl, sgt->nents, dir);
if (ret < 0) {
sg_free_table(sgt);
return ret;
}
sgt->nents = ret;
return 0;
}
static void spi_unmap_buf(struct spi_master *master, struct device *dev,
struct sg_table *sgt, enum dma_data_direction dir)
{
if (sgt->orig_nents) {
dma_unmap_sg(dev, sgt->sgl, sgt->orig_nents, dir);
sg_free_table(sgt);
}
}
static int spi_map_msg(struct spi_master *master, struct spi_message *msg)
{
struct device *tx_dev, *rx_dev;
struct spi_transfer *xfer;
void *tmp;
unsigned int max_tx, max_rx;
int ret;
if (master->flags & (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX)) {
max_tx = 0;
max_rx = 0;
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
if ((master->flags & SPI_MASTER_MUST_TX) &&
!xfer->tx_buf)
max_tx = max(xfer->len, max_tx);
if ((master->flags & SPI_MASTER_MUST_RX) &&
!xfer->rx_buf)
max_rx = max(xfer->len, max_rx);
}
if (max_tx) {
tmp = krealloc(master->dummy_tx, max_tx,
GFP_KERNEL | GFP_DMA);
if (!tmp)
return -ENOMEM;
master->dummy_tx = tmp;
memset(tmp, 0, max_tx);
}
if (max_rx) {
tmp = krealloc(master->dummy_rx, max_rx,
GFP_KERNEL | GFP_DMA);
if (!tmp)
return -ENOMEM;
master->dummy_rx = tmp;
}
if (max_tx || max_rx) {
list_for_each_entry(xfer, &msg->transfers,
transfer_list) {
if (!xfer->tx_buf)
xfer->tx_buf = master->dummy_tx;
if (!xfer->rx_buf)
xfer->rx_buf = master->dummy_rx;
}
}
}
if (!master->can_dma)
return 0;
tx_dev = &master->dma_tx->dev->device;
rx_dev = &master->dma_rx->dev->device;
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
if (!master->can_dma(master, msg->spi, xfer))
continue;
if (xfer->tx_buf != NULL) {
ret = spi_map_buf(master, tx_dev, &xfer->tx_sg,
(void *)xfer->tx_buf, xfer->len,
DMA_TO_DEVICE);
if (ret != 0)
return ret;
}
if (xfer->rx_buf != NULL) {
ret = spi_map_buf(master, rx_dev, &xfer->rx_sg,
xfer->rx_buf, xfer->len,
DMA_FROM_DEVICE);
if (ret != 0) {
spi_unmap_buf(master, tx_dev, &xfer->tx_sg,
DMA_TO_DEVICE);
return ret;
}
}
}
master->cur_msg_mapped = true;
return 0;
}
static int spi_unmap_msg(struct spi_master *master, struct spi_message *msg)
{
struct spi_transfer *xfer;
struct device *tx_dev, *rx_dev;
if (!master->cur_msg_mapped || !master->can_dma)
return 0;
tx_dev = &master->dma_tx->dev->device;
rx_dev = &master->dma_rx->dev->device;
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
if (!master->can_dma(master, msg->spi, xfer))
continue;
spi_unmap_buf(master, rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE);
spi_unmap_buf(master, tx_dev, &xfer->tx_sg, DMA_TO_DEVICE);
}
return 0;
}
/*
* spi_transfer_one_message - Default implementation of transfer_one_message()
*
@ -591,9 +754,9 @@ static int spi_transfer_one_message(struct spi_master *master,
struct spi_message *msg)
{
struct spi_transfer *xfer;
bool cur_cs = true;
bool keep_cs = false;
int ret = 0;
int ms = 1;
spi_set_cs(msg->spi, true);
@ -611,7 +774,16 @@ static int spi_transfer_one_message(struct spi_master *master,
if (ret > 0) {
ret = 0;
wait_for_completion(&master->xfer_completion);
ms = xfer->len * 8 * 1000 / xfer->speed_hz;
ms += 10; /* some tolerance */
ms = wait_for_completion_timeout(&master->xfer_completion,
msecs_to_jiffies(ms));
}
if (ms == 0) {
dev_err(&msg->spi->dev, "SPI transfer timed out\n");
msg->status = -ETIMEDOUT;
}
trace_spi_transfer_stop(msg, xfer);
@ -627,8 +799,9 @@ static int spi_transfer_one_message(struct spi_master *master,
&msg->transfers)) {
keep_cs = true;
} else {
cur_cs = !cur_cs;
spi_set_cs(msg->spi, cur_cs);
spi_set_cs(msg->spi, false);
udelay(10);
spi_set_cs(msg->spi, true);
}
}
@ -686,6 +859,10 @@ static void spi_pump_messages(struct kthread_work *work)
}
master->busy = false;
spin_unlock_irqrestore(&master->queue_lock, flags);
kfree(master->dummy_rx);
master->dummy_rx = NULL;
kfree(master->dummy_tx);
master->dummy_tx = NULL;
if (master->unprepare_transfer_hardware &&
master->unprepare_transfer_hardware(master))
dev_err(&master->dev,
@ -752,6 +929,13 @@ static void spi_pump_messages(struct kthread_work *work)
master->cur_msg_prepared = true;
}
ret = spi_map_msg(master, master->cur_msg);
if (ret) {
master->cur_msg->status = ret;
spi_finalize_current_message(master);
return;
}
ret = master->transfer_one_message(master, master->cur_msg);
if (ret) {
dev_err(&master->dev,
@ -839,6 +1023,8 @@ void spi_finalize_current_message(struct spi_master *master)
queue_kthread_work(&master->kworker, &master->pump_messages);
spin_unlock_irqrestore(&master->queue_lock, flags);
spi_unmap_msg(master, mesg);
if (master->cur_msg_prepared && master->unprepare_message) {
ret = master->unprepare_message(master, mesg);
if (ret) {
@ -892,7 +1078,7 @@ static int spi_stop_queue(struct spi_master *master)
*/
while ((!list_empty(&master->queue) || master->busy) && limit--) {
spin_unlock_irqrestore(&master->queue_lock, flags);
msleep(10);
usleep_range(10000, 11000);
spin_lock_irqsave(&master->queue_lock, flags);
}
@ -1372,6 +1558,8 @@ int spi_register_master(struct spi_master *master)
mutex_init(&master->bus_lock_mutex);
master->bus_lock_flag = 0;
init_completion(&master->xfer_completion);
if (!master->max_dma_len)
master->max_dma_len = INT_MAX;
/* register the device, then userspace will see it.
* registration fails if the bus ID is in use.
@ -1597,6 +1785,9 @@ int spi_setup(struct spi_device *spi)
if (!spi->bits_per_word)
spi->bits_per_word = 8;
if (!spi->max_speed_hz)
spi->max_speed_hz = spi->master->max_speed_hz;
if (spi->master->setup)
status = spi->master->setup(spi);
@ -1617,11 +1808,10 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
{
struct spi_master *master = spi->master;
struct spi_transfer *xfer;
int w_size;
if (list_empty(&message->transfers))
return -EINVAL;
if (!message->complete)
return -EINVAL;
/* Half-duplex links include original MicroWire, and ones with
* only one data pin like SPI_3WIRE (switches direction) or where
@ -1652,12 +1842,13 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
message->frame_length += xfer->len;
if (!xfer->bits_per_word)
xfer->bits_per_word = spi->bits_per_word;
if (!xfer->speed_hz) {
if (!xfer->speed_hz)
xfer->speed_hz = spi->max_speed_hz;
if (master->max_speed_hz &&
xfer->speed_hz > master->max_speed_hz)
xfer->speed_hz = master->max_speed_hz;
}
if (master->max_speed_hz &&
xfer->speed_hz > master->max_speed_hz)
xfer->speed_hz = master->max_speed_hz;
if (master->bits_per_word_mask) {
/* Only 32 bits fit in the mask */
@ -1668,12 +1859,24 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
return -EINVAL;
}
/*
* SPI transfer length should be multiple of SPI word size
* where SPI word size should be power-of-two multiple
*/
if (xfer->bits_per_word <= 8)
w_size = 1;
else if (xfer->bits_per_word <= 16)
w_size = 2;
else
w_size = 4;
/* No partial transfers accepted */
if (xfer->len % w_size)
return -EINVAL;
if (xfer->speed_hz && master->min_speed_hz &&
xfer->speed_hz < master->min_speed_hz)
return -EINVAL;
if (xfer->speed_hz && master->max_speed_hz &&
xfer->speed_hz > master->max_speed_hz)
return -EINVAL;
if (xfer->tx_buf && !xfer->tx_nbits)
xfer->tx_nbits = SPI_NBITS_SINGLE;

Просмотреть файл

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

Просмотреть файл

@ -1,5 +1,4 @@
/* linux/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h
*
/*
* Copyright (C) 2009 Samsung Electronics Ltd.
* Jaswinder Singh <jassi.brar@samsung.com>
*
@ -8,8 +7,8 @@
* published by the Free Software Foundation.
*/
#ifndef __S3C64XX_PLAT_SPI_H
#define __S3C64XX_PLAT_SPI_H
#ifndef __SPI_S3C64XX_H
#define __SPI_S3C64XX_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_spi1_pdata;
extern struct s3c64xx_spi_info s3c64xx_spi2_pdata;
#endif /* __S3C64XX_PLAT_SPI_H */
#endif /*__SPI_S3C64XX_H */

Просмотреть файл

@ -26,9 +26,13 @@
#ifdef CONFIG_PM
extern int pm_generic_runtime_suspend(struct device *dev);
extern int pm_generic_runtime_resume(struct device *dev);
extern int pm_runtime_force_suspend(struct device *dev);
extern int pm_runtime_force_resume(struct device *dev);
#else
static inline int pm_generic_runtime_suspend(struct device *dev) { return 0; }
static inline int pm_generic_runtime_resume(struct device *dev) { return 0; }
static inline int pm_runtime_force_suspend(struct device *dev) { return 0; }
static inline int pm_runtime_force_resume(struct device *dev) { return 0; }
#endif
#ifdef CONFIG_PM_RUNTIME

Просмотреть файл

@ -24,6 +24,9 @@
#include <linux/slab.h>
#include <linux/kthread.h>
#include <linux/completion.h>
#include <linux/scatterlist.h>
struct dma_chan;
/*
* INTERFACES between SPI master-side drivers and SPI infrastructure.
@ -266,6 +269,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
* @auto_runtime_pm: the core should ensure a runtime PM reference is held
* while the hardware is prepared, using the parent
* device for the spidev
* @max_dma_len: Maximum length of a DMA transfer for the device.
* @prepare_transfer_hardware: a message will soon arrive from the queue
* so the subsystem requests the driver to prepare the transfer hardware
* by issuing this call
@ -348,6 +352,8 @@ struct spi_master {
#define SPI_MASTER_HALF_DUPLEX BIT(0) /* can't do full duplex */
#define SPI_MASTER_NO_RX BIT(1) /* can't do buffer read */
#define SPI_MASTER_NO_TX BIT(2) /* can't do buffer write */
#define SPI_MASTER_MUST_RX BIT(3) /* requires rx */
#define SPI_MASTER_MUST_TX BIT(4) /* requires tx */
/* lock and mutex for SPI bus locking */
spinlock_t bus_lock_spinlock;
@ -389,6 +395,17 @@ struct spi_master {
/* called on release() to free memory provided by spi_master */
void (*cleanup)(struct spi_device *spi);
/*
* Used to enable core support for DMA handling, if can_dma()
* exists and returns true then the transfer will be mapped
* prior to transfer_one() being called. The driver should
* not modify or store xfer and dma_tx and dma_rx must be set
* while the device is prepared.
*/
bool (*can_dma)(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *xfer);
/*
* These hooks are for drivers that want to use the generic
* master transfer queueing mechanism. If these are used, the
@ -407,7 +424,9 @@ struct spi_master {
bool rt;
bool auto_runtime_pm;
bool cur_msg_prepared;
bool cur_msg_mapped;
struct completion xfer_completion;
size_t max_dma_len;
int (*prepare_transfer_hardware)(struct spi_master *master);
int (*transfer_one_message)(struct spi_master *master,
@ -428,6 +447,14 @@ struct spi_master {
/* gpio chip select */
int *cs_gpios;
/* DMA channels for use with core dmaengine helpers */
struct dma_chan *dma_tx;
struct dma_chan *dma_rx;
/* dummy data for full duplex devices */
void *dummy_rx;
void *dummy_tx;
};
static inline void *spi_master_get_devdata(struct spi_master *master)
@ -512,6 +539,8 @@ extern struct spi_master *spi_busnum_to_master(u16 busnum);
* (optionally) changing the chipselect status, then starting
* the next transfer or completing this @spi_message.
* @transfer_list: transfers are sequenced through @spi_message.transfers
* @tx_sg: Scatterlist for transmit, currently not for client use
* @rx_sg: Scatterlist for receive, currently not for client use
*
* SPI transfers always write the same number of bytes as they read.
* Protocol drivers should always provide @rx_buf and/or @tx_buf.
@ -579,6 +608,8 @@ struct spi_transfer {
dma_addr_t tx_dma;
dma_addr_t rx_dma;
struct sg_table tx_sg;
struct sg_table rx_sg;
unsigned cs_change:1;
unsigned tx_nbits:3;

Просмотреть файл

@ -42,6 +42,6 @@ extern int spi_bitbang_setup_transfer(struct spi_device *spi,
/* start or stop queue processing */
extern int spi_bitbang_start(struct spi_bitbang *spi);
extern int spi_bitbang_stop(struct spi_bitbang *spi);
extern void spi_bitbang_stop(struct spi_bitbang *spi);
#endif /* __SPI_BITBANG_H */

Просмотреть файл

@ -42,6 +42,10 @@
#define SPI_LOOP 0x20
#define SPI_NO_CS 0x40
#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;
__u8 bits_per_word;
__u8 cs_change;
__u32 pad;
__u8 tx_nbits;
__u8 rx_nbits;
__u16 pad;
/* If the contents of 'struct spi_ioc_transfer' ever 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)])
/* 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_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_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 */