Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
9d540b0d
Commit
9d540b0d
authored
Jul 03, 2017
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'spi/topic/master' into spi-next
parents
096bf6b7
8caab75f
Changes
9
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
1201 additions
and
674 deletions
+1201
-674
Documentation/devicetree/bindings/spi/spi-bus.txt
Documentation/devicetree/bindings/spi/spi-bus.txt
+45
-31
Documentation/spi/spi-summary
Documentation/spi/spi-summary
+20
-7
drivers/spi/Kconfig
drivers/spi/Kconfig
+25
-1
drivers/spi/Makefile
drivers/spi/Makefile
+4
-0
drivers/spi/spi-slave-system-control.c
drivers/spi/spi-slave-system-control.c
+154
-0
drivers/spi/spi-slave-time.c
drivers/spi/spi-slave-time.c
+129
-0
drivers/spi/spi.c
drivers/spi/spi.c
+675
-541
include/linux/spi/spi.h
include/linux/spi/spi.h
+136
-81
include/trace/events/spi.h
include/trace/events/spi.h
+13
-13
No files found.
Documentation/devicetree/bindings/spi/spi-bus.txt
View file @
9d540b0d
SPI (Serial Peripheral Interface) busses
SPI busses can be described with a node for the SPI master device
and a set of child nodes for each SPI slave on the bus. For this
discussion, it is assumed that the system's SPI controller is in
SPI master mode. This binding does not describe SPI controllers
in slave mode.
SPI busses can be described with a node for the SPI controller device
and a set of child nodes for each SPI slave on the bus. The system's SPI
controller may be described for use in SPI master mode or in SPI slave mode,
but not for both at the same time.
The SPI master node requires the following properties:
The SPI controller node requires the following properties:
- compatible - Name of SPI bus controller following generic names
recommended practice.
In master mode, the SPI controller node requires the following additional
properties:
- #address-cells - number of cells required to define a chip select
address on the SPI bus.
- #size-cells - should be zero.
- compatible - name of SPI bus controller following generic names
recommended practice.
In slave mode, the SPI controller node requires one additional property:
- spi-slave - Empty property.
No other properties are required in the SPI bus node. It is assumed
that a driver for an SPI bus device will understand that it is an SPI bus.
However, the binding does not attempt to define the specific method for
...
...
@@ -21,7 +27,7 @@ assumption that board specific platform code will be used to manage
chip selects. Individual drivers can define additional properties to
support describing the chip select layout.
Optional properties:
Optional properties
(master mode only)
:
- cs-gpios - gpios chip select.
- num-cs - total number of chipselects.
...
...
@@ -41,28 +47,36 @@ cs1 : native
cs2 : &gpio1 1 0
cs3 : &gpio1 2 0
SPI slave nodes must be children of the SPI master node and can
contain the following properties.
- reg - (required) chip select address of device.
- compatible - (required) name of SPI device following generic names
recommended practice.
- spi-max-frequency - (required) Maximum SPI clocking speed of device in Hz.
- spi-cpol - (optional) Empty property indicating device requires
inverse clock polarity (CPOL) mode.
- spi-cpha - (optional) Empty property indicating device requires
shifted clock phase (CPHA) mode.
- spi-cs-high - (optional) Empty property indicating device requires
chip select active high.
- spi-3wire - (optional) Empty property indicating device requires
3-wire mode.
- spi-lsb-first - (optional) Empty property indicating device requires
LSB first mode.
- spi-tx-bus-width - (optional) The bus width (number of data wires) that is
used for MOSI. Defaults to 1 if not present.
- spi-rx-bus-width - (optional) The bus width (number of data wires) that is
used for MISO. Defaults to 1 if not present.
- spi-rx-delay-us - (optional) Microsecond delay after a read transfer.
- spi-tx-delay-us - (optional) Microsecond delay after a write transfer.
SPI slave nodes must be children of the SPI controller node.
In master mode, one or more slave nodes (up to the number of chip selects) can
be present. Required properties are:
- compatible - Name of SPI device following generic names recommended
practice.
- reg - Chip select address of device.
- spi-max-frequency - Maximum SPI clocking speed of device in Hz.
In slave mode, the (single) slave node is optional.
If present, it must be called "slave". Required properties are:
- compatible - Name of SPI device following generic names recommended
practice.
All slave nodes can contain the following optional properties:
- spi-cpol - Empty property indicating device requires inverse clock
polarity (CPOL) mode.
- spi-cpha - Empty property indicating device requires shifted clock
phase (CPHA) mode.
- spi-cs-high - Empty property indicating device requires chip select
active high.
- spi-3wire - Empty property indicating device requires 3-wire mode.
- spi-lsb-first - Empty property indicating device requires LSB first mode.
- spi-tx-bus-width - The bus width (number of data wires) that is used for MOSI.
Defaults to 1 if not present.
- spi-rx-bus-width - The bus width (number of data wires) that is used for MISO.
Defaults to 1 if not present.
- spi-rx-delay-us - Microsecond delay after a read transfer.
- spi-tx-delay-us - Microsecond delay after a write transfer.
Some SPI controllers and devices support Dual and Quad SPI transfer mode.
It allows data in the SPI system to be transferred using 2 wires (DUAL) or 4
...
...
Documentation/spi/spi-summary
View file @
9d540b0d
...
...
@@ -62,8 +62,8 @@ chips described as using "three wire" signaling: SCK, data, nCSx.
(That data line is sometimes called MOMI or SISO.)
Microcontrollers often support both master and slave sides of the SPI
protocol. This document (and Linux)
currently only supports the master
side of SPI interactions.
protocol. This document (and Linux)
supports both the master and slave
side
s
of SPI interactions.
Who uses it? On what kinds of systems?
...
...
@@ -154,9 +154,8 @@ control audio interfaces, present touchscreen sensors as input interfaces,
or monitor temperature and voltage levels during industrial processing.
And those might all be sharing the same controller driver.
A "struct spi_device" encapsulates the master-side interface between
those two types of driver. At this writing, Linux has no slave side
programming interface.
A "struct spi_device" encapsulates the controller-side interface between
those two types of drivers.
There is a minimal core of SPI programming interfaces, focussing on
using the driver model to connect controller and protocol drivers using
...
...
@@ -177,10 +176,24 @@ shows up in sysfs in several locations:
/sys/bus/spi/drivers/D ... driver for one or more spi*.* devices
/sys/class/spi_master/spiB ... symlink (or actual device node) to
a logical node which could hold class related state for the
controller managing bus "B". All spiB.* devices share one
a logical node which could hold class related state for the
SPI
master
controller managing bus "B". All spiB.* devices share one
physical SPI bus segment, with SCLK, MOSI, and MISO.
/sys/devices/.../CTLR/slave ... virtual file for (un)registering the
slave device for an SPI slave controller.
Writing the driver name of an SPI slave handler to this file
registers the slave device; writing "(null)" unregisters the slave
device.
Reading from this file shows the name of the slave device ("(null)"
if not registered).
/sys/class/spi_slave/spiB ... symlink (or actual device node) to
a logical node which could hold class related state for the SPI
slave controller on bus "B". When registered, a single spiB.*
device is present here, possible sharing the physical SPI bus
segment with other SPI slave devices.
Note that the actual location of the controller's class state depends
on whether you enabled CONFIG_SYSFS_DEPRECATED or not. At this time,
the only class-specific state is the bus number ("B" in "spiB"), so
...
...
drivers/spi/Kconfig
View file @
9d540b0d
...
...
@@ -785,6 +785,30 @@ config SPI_TLE62X0
endif # SPI_MASTER
# (slave support would go here)
#
# SLAVE side ... listening to other SPI masters
#
config SPI_SLAVE
bool "SPI slave protocol handlers"
help
If your system has a slave-capable SPI controller, you can enable
slave protocol handlers.
if SPI_SLAVE
config SPI_SLAVE_TIME
tristate "SPI slave handler reporting boot up time"
help
SPI slave handler responding with the time of reception of the last
SPI message.
config SPI_SLAVE_SYSTEM_CONTROL
tristate "SPI slave handler controlling system state"
help
SPI slave handler to allow remote control of system reboot, power
off, halt, and suspend.
endif # SPI_SLAVE
endif # SPI
drivers/spi/Makefile
View file @
9d540b0d
...
...
@@ -105,3 +105,7 @@ obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o
obj-$(CONFIG_SPI_XLP)
+=
spi-xlp.o
obj-$(CONFIG_SPI_XTENSA_XTFPGA)
+=
spi-xtensa-xtfpga.o
obj-$(CONFIG_SPI_ZYNQMP_GQSPI)
+=
spi-zynqmp-gqspi.o
# SPI slave protocol handlers
obj-$(CONFIG_SPI_SLAVE_TIME)
+=
spi-slave-time.o
obj-$(CONFIG_SPI_SLAVE_SYSTEM_CONTROL)
+=
spi-slave-system-control.o
drivers/spi/spi-slave-system-control.c
0 → 100644
View file @
9d540b0d
/*
* SPI slave handler controlling system state
*
* This SPI slave handler allows remote control of system reboot, power off,
* halt, and suspend.
*
* Copyright (C) 2016-2017 Glider bvba
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Usage (assuming /dev/spidev2.0 corresponds to the SPI master on the remote
* system):
*
* # reboot='\x7c\x50'
* # poweroff='\x71\x3f'
* # halt='\x38\x76'
* # suspend='\x1b\x1b'
* # spidev_test -D /dev/spidev2.0 -p $suspend # or $reboot, $poweroff, $halt
*/
#include <linux/completion.h>
#include <linux/module.h>
#include <linux/reboot.h>
#include <linux/suspend.h>
#include <linux/spi/spi.h>
/*
* The numbers are chosen to display something human-readable on two 7-segment
* displays connected to two 74HC595 shift registers
*/
#define CMD_REBOOT 0x7c50
/* rb */
#define CMD_POWEROFF 0x713f
/* OF */
#define CMD_HALT 0x3876
/* HL */
#define CMD_SUSPEND 0x1b1b
/* ZZ */
struct
spi_slave_system_control_priv
{
struct
spi_device
*
spi
;
struct
completion
finished
;
struct
spi_transfer
xfer
;
struct
spi_message
msg
;
__be16
cmd
;
};
static
int
spi_slave_system_control_submit
(
struct
spi_slave_system_control_priv
*
priv
);
static
void
spi_slave_system_control_complete
(
void
*
arg
)
{
struct
spi_slave_system_control_priv
*
priv
=
arg
;
u16
cmd
;
int
ret
;
if
(
priv
->
msg
.
status
)
goto
terminate
;
cmd
=
be16_to_cpu
(
priv
->
cmd
);
switch
(
cmd
)
{
case
CMD_REBOOT
:
dev_info
(
&
priv
->
spi
->
dev
,
"Rebooting system...
\n
"
);
kernel_restart
(
NULL
);
case
CMD_POWEROFF
:
dev_info
(
&
priv
->
spi
->
dev
,
"Powering off system...
\n
"
);
kernel_power_off
();
break
;
case
CMD_HALT
:
dev_info
(
&
priv
->
spi
->
dev
,
"Halting system...
\n
"
);
kernel_halt
();
break
;
case
CMD_SUSPEND
:
dev_info
(
&
priv
->
spi
->
dev
,
"Suspending system...
\n
"
);
pm_suspend
(
PM_SUSPEND_MEM
);
break
;
default:
dev_warn
(
&
priv
->
spi
->
dev
,
"Unknown command 0x%x
\n
"
,
cmd
);
break
;
}
ret
=
spi_slave_system_control_submit
(
priv
);
if
(
ret
)
goto
terminate
;
return
;
terminate:
dev_info
(
&
priv
->
spi
->
dev
,
"Terminating
\n
"
);
complete
(
&
priv
->
finished
);
}
static
int
spi_slave_system_control_submit
(
struct
spi_slave_system_control_priv
*
priv
)
{
int
ret
;
spi_message_init_with_transfers
(
&
priv
->
msg
,
&
priv
->
xfer
,
1
);
priv
->
msg
.
complete
=
spi_slave_system_control_complete
;
priv
->
msg
.
context
=
priv
;
ret
=
spi_async
(
priv
->
spi
,
&
priv
->
msg
);
if
(
ret
)
dev_err
(
&
priv
->
spi
->
dev
,
"spi_async() failed %d
\n
"
,
ret
);
return
ret
;
}
static
int
spi_slave_system_control_probe
(
struct
spi_device
*
spi
)
{
struct
spi_slave_system_control_priv
*
priv
;
int
ret
;
priv
=
devm_kzalloc
(
&
spi
->
dev
,
sizeof
(
*
priv
),
GFP_KERNEL
);
if
(
!
priv
)
return
-
ENOMEM
;
priv
->
spi
=
spi
;
init_completion
(
&
priv
->
finished
);
priv
->
xfer
.
rx_buf
=
&
priv
->
cmd
;
priv
->
xfer
.
len
=
sizeof
(
priv
->
cmd
);
ret
=
spi_slave_system_control_submit
(
priv
);
if
(
ret
)
return
ret
;
spi_set_drvdata
(
spi
,
priv
);
return
0
;
}
static
int
spi_slave_system_control_remove
(
struct
spi_device
*
spi
)
{
struct
spi_slave_system_control_priv
*
priv
=
spi_get_drvdata
(
spi
);
spi_slave_abort
(
spi
);
wait_for_completion
(
&
priv
->
finished
);
return
0
;
}
static
struct
spi_driver
spi_slave_system_control_driver
=
{
.
driver
=
{
.
name
=
"spi-slave-system-control"
,
},
.
probe
=
spi_slave_system_control_probe
,
.
remove
=
spi_slave_system_control_remove
,
};
module_spi_driver
(
spi_slave_system_control_driver
);
MODULE_AUTHOR
(
"Geert Uytterhoeven <geert+renesas@glider.be>"
);
MODULE_DESCRIPTION
(
"SPI slave handler controlling system state"
);
MODULE_LICENSE
(
"GPL v2"
);
drivers/spi/spi-slave-time.c
0 → 100644
View file @
9d540b0d
/*
* SPI slave handler reporting uptime at reception of previous SPI message
*
* This SPI slave handler sends the time of reception of the last SPI message
* as two 32-bit unsigned integers in binary format and in network byte order,
* representing the number of seconds and fractional seconds (in microseconds)
* since boot up.
*
* Copyright (C) 2016-2017 Glider bvba
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Usage (assuming /dev/spidev2.0 corresponds to the SPI master on the remote
* system):
*
* # spidev_test -D /dev/spidev2.0 -p dummy-8B
* spi mode: 0x0
* bits per word: 8
* max speed: 500000 Hz (500 KHz)
* RX | 00 00 04 6D 00 09 5B BB ...
* ^^^^^ ^^^^^^^^
* seconds microseconds
*/
#include <linux/completion.h>
#include <linux/module.h>
#include <linux/sched/clock.h>
#include <linux/spi/spi.h>
struct
spi_slave_time_priv
{
struct
spi_device
*
spi
;
struct
completion
finished
;
struct
spi_transfer
xfer
;
struct
spi_message
msg
;
__be32
buf
[
2
];
};
static
int
spi_slave_time_submit
(
struct
spi_slave_time_priv
*
priv
);
static
void
spi_slave_time_complete
(
void
*
arg
)
{
struct
spi_slave_time_priv
*
priv
=
arg
;
int
ret
;
ret
=
priv
->
msg
.
status
;
if
(
ret
)
goto
terminate
;
ret
=
spi_slave_time_submit
(
priv
);
if
(
ret
)
goto
terminate
;
return
;
terminate:
dev_info
(
&
priv
->
spi
->
dev
,
"Terminating
\n
"
);
complete
(
&
priv
->
finished
);
}
static
int
spi_slave_time_submit
(
struct
spi_slave_time_priv
*
priv
)
{
u32
rem_us
;
int
ret
;
u64
ts
;
ts
=
local_clock
();
rem_us
=
do_div
(
ts
,
1000000000
)
/
1000
;
priv
->
buf
[
0
]
=
cpu_to_be32
(
ts
);
priv
->
buf
[
1
]
=
cpu_to_be32
(
rem_us
);
spi_message_init_with_transfers
(
&
priv
->
msg
,
&
priv
->
xfer
,
1
);
priv
->
msg
.
complete
=
spi_slave_time_complete
;
priv
->
msg
.
context
=
priv
;
ret
=
spi_async
(
priv
->
spi
,
&
priv
->
msg
);
if
(
ret
)
dev_err
(
&
priv
->
spi
->
dev
,
"spi_async() failed %d
\n
"
,
ret
);
return
ret
;
}
static
int
spi_slave_time_probe
(
struct
spi_device
*
spi
)
{
struct
spi_slave_time_priv
*
priv
;
int
ret
;
priv
=
devm_kzalloc
(
&
spi
->
dev
,
sizeof
(
*
priv
),
GFP_KERNEL
);
if
(
!
priv
)
return
-
ENOMEM
;
priv
->
spi
=
spi
;
init_completion
(
&
priv
->
finished
);
priv
->
xfer
.
tx_buf
=
priv
->
buf
;
priv
->
xfer
.
len
=
sizeof
(
priv
->
buf
);
ret
=
spi_slave_time_submit
(
priv
);
if
(
ret
)
return
ret
;
spi_set_drvdata
(
spi
,
priv
);
return
0
;
}
static
int
spi_slave_time_remove
(
struct
spi_device
*
spi
)
{
struct
spi_slave_time_priv
*
priv
=
spi_get_drvdata
(
spi
);
spi_slave_abort
(
spi
);
wait_for_completion
(
&
priv
->
finished
);
return
0
;
}
static
struct
spi_driver
spi_slave_time_driver
=
{
.
driver
=
{
.
name
=
"spi-slave-time"
,
},
.
probe
=
spi_slave_time_probe
,
.
remove
=
spi_slave_time_remove
,
};
module_spi_driver
(
spi_slave_time_driver
);
MODULE_AUTHOR
(
"Geert Uytterhoeven <geert+renesas@glider.be>"
);
MODULE_DESCRIPTION
(
"SPI slave reporting uptime at previous SPI message"
);
MODULE_LICENSE
(
"GPL v2"
);
drivers/spi/spi.c
View file @
9d540b0d
This diff is collapsed.
Click to expand it.
include/linux/spi/spi.h
View file @
9d540b0d
This diff is collapsed.
Click to expand it.
include/trace/events/spi.h
View file @
9d540b0d
...
...
@@ -7,37 +7,37 @@
#include <linux/ktime.h>
#include <linux/tracepoint.h>
DECLARE_EVENT_CLASS
(
spi_
mast
er
,
DECLARE_EVENT_CLASS
(
spi_
controll
er
,
TP_PROTO
(
struct
spi_
master
*
mast
er
),
TP_PROTO
(
struct
spi_
controller
*
controll
er
),
TP_ARGS
(
mast
er
),
TP_ARGS
(
controll
er
),
TP_STRUCT__entry
(
__field
(
int
,
bus_num
)
),
TP_fast_assign
(
__entry
->
bus_num
=
mast
er
->
bus_num
;
__entry
->
bus_num
=
controll
er
->
bus_num
;
),
TP_printk
(
"spi%d"
,
(
int
)
__entry
->
bus_num
)
);
DEFINE_EVENT
(
spi_
master
,
spi_mast
er_idle
,
DEFINE_EVENT
(
spi_
controller
,
spi_controll
er_idle
,
TP_PROTO
(
struct
spi_
master
*
mast
er
),
TP_PROTO
(
struct
spi_
controller
*
controll
er
),
TP_ARGS
(
mast
er
)
TP_ARGS
(
controll
er
)
);
DEFINE_EVENT
(
spi_
master
,
spi_mast
er_busy
,
DEFINE_EVENT
(
spi_
controller
,
spi_controll
er_busy
,
TP_PROTO
(
struct
spi_
master
*
mast
er
),
TP_PROTO
(
struct
spi_
controller
*
controll
er
),
TP_ARGS
(
mast
er
)
TP_ARGS
(
controll
er
)
);
...
...
@@ -54,7 +54,7 @@ DECLARE_EVENT_CLASS(spi_message,
),
TP_fast_assign
(
__entry
->
bus_num
=
msg
->
spi
->
mast
er
->
bus_num
;
__entry
->
bus_num
=
msg
->
spi
->
controll
er
->
bus_num
;
__entry
->
chip_select
=
msg
->
spi
->
chip_select
;
__entry
->
msg
=
msg
;
),
...
...
@@ -95,7 +95,7 @@ TRACE_EVENT(spi_message_done,
),
TP_fast_assign
(
__entry
->
bus_num
=
msg
->
spi
->
mast
er
->
bus_num
;
__entry
->
bus_num
=
msg
->
spi
->
controll
er
->
bus_num
;
__entry
->
chip_select
=
msg
->
spi
->
chip_select
;
__entry
->
msg
=
msg
;
__entry
->
frame
=
msg
->
frame_length
;
...
...
@@ -122,7 +122,7 @@ DECLARE_EVENT_CLASS(spi_transfer,
),
TP_fast_assign
(
__entry
->
bus_num
=
msg
->
spi
->
mast
er
->
bus_num
;
__entry
->
bus_num
=
msg
->
spi
->
controll
er
->
bus_num
;
__entry
->
chip_select
=
msg
->
spi
->
chip_select
;
__entry
->
xfer
=
xfer
;
__entry
->
len
=
xfer
->
len
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment