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
Kirill Smelkov
linux
Commits
8211e6b8
Commit
8211e6b8
authored
Oct 25, 2013
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'spi/topic/loop' into spi-next
parents
c25b2c9e
0732a9d2
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
428 additions
and
128 deletions
+428
-128
drivers/spi/Kconfig
drivers/spi/Kconfig
+1
-1
drivers/spi/spi-s3c64xx.c
drivers/spi/spi-s3c64xx.c
+112
-124
drivers/spi/spi.c
drivers/spi/spi.c
+129
-1
include/linux/spi/spi.h
include/linux/spi/spi.h
+30
-2
include/trace/events/spi.h
include/trace/events/spi.h
+156
-0
No files found.
drivers/spi/Kconfig
View file @
8211e6b8
...
...
@@ -394,7 +394,7 @@ config SPI_S3C24XX_FIQ
config SPI_S3C64XX
tristate "Samsung S3C64XX series type SPI"
depends on
(ARCH_S3C24XX || ARCH_S3C64XX || ARCH_S5P64X0 || ARCH_EXYNOS)
depends on
PLAT_SAMSUNG
select S3C64XX_DMA if ARCH_S3C64XX
help
SPI driver for Samsung S3C64XX and newer SoCs.
...
...
drivers/spi/spi-s3c64xx.c
View file @
8211e6b8
...
...
@@ -205,7 +205,6 @@ struct s3c64xx_spi_driver_data {
#endif
struct
s3c64xx_spi_port_config
*
port_conf
;
unsigned
int
port_id
;
unsigned
long
gpios
[
4
];
bool
cs_gpio
;
};
...
...
@@ -559,25 +558,18 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
static
inline
void
enable_cs
(
struct
s3c64xx_spi_driver_data
*
sdd
,
struct
spi_device
*
spi
)
{
struct
s3c64xx_spi_csinfo
*
cs
;
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 */
cs
=
sdd
->
tgl_spi
->
controller_data
;
if
(
sdd
->
cs_gpio
)
gpio_set_value
(
cs
->
line
,
if
(
spi
->
cs_gpio
>=
0
)
gpio_set_value
(
spi
->
cs_gpio
,
spi
->
mode
&
SPI_CS_HIGH
?
0
:
1
);
}
sdd
->
tgl_spi
=
NULL
;
}
cs
=
spi
->
controller_data
;
if
(
sdd
->
cs_gpio
)
gpio_set_value
(
cs
->
line
,
spi
->
mode
&
SPI_CS_HIGH
?
1
:
0
);
/* Start the signals */
writel
(
0
,
sdd
->
regs
+
S3C64XX_SPI_SLAVE_SEL
);
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
,
...
...
@@ -702,16 +694,11 @@ static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd,
static
inline
void
disable_cs
(
struct
s3c64xx_spi_driver_data
*
sdd
,
struct
spi_device
*
spi
)
{
struct
s3c64xx_spi_csinfo
*
cs
=
spi
->
controller_data
;
if
(
sdd
->
tgl_spi
==
spi
)
sdd
->
tgl_spi
=
NULL
;
if
(
sdd
->
cs_gpio
)
gpio_set_value
(
cs
->
line
,
spi
->
mode
&
SPI_CS_HIGH
?
0
:
1
);
/* Quiese the signals */
writel
(
S3C64XX_SPI_SLAVE_SIG_INACT
,
sdd
->
regs
+
S3C64XX_SPI_SLAVE_SEL
);
if
(
spi
->
cs_gpio
>=
0
)
gpio_set_value
(
spi
->
cs_gpio
,
spi
->
mode
&
SPI_CS_HIGH
?
0
:
1
);
}
static
void
s3c64xx_spi_config
(
struct
s3c64xx_spi_driver_data
*
sdd
)
...
...
@@ -862,16 +849,12 @@ static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd,
}
}
static
int
s3c64xx_spi_
transfer_on
e_message
(
struct
spi_master
*
master
,
static
int
s3c64xx_spi_
prepar
e_message
(
struct
spi_master
*
master
,
struct
spi_message
*
msg
)
{
struct
s3c64xx_spi_driver_data
*
sdd
=
spi_master_get_devdata
(
master
);
struct
spi_device
*
spi
=
msg
->
spi
;
struct
s3c64xx_spi_csinfo
*
cs
=
spi
->
controller_data
;
struct
spi_transfer
*
xfer
;
int
status
=
0
,
cs_toggle
=
0
;
u32
speed
;
u8
bpw
;
/* If Master's(controller) state differs from that needed by Slave */
if
(
sdd
->
cur_speed
!=
spi
->
max_speed_hz
...
...
@@ -887,15 +870,23 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master,
if
(
s3c64xx_spi_map_mssg
(
sdd
,
msg
))
{
dev_err
(
&
spi
->
dev
,
"Xfer: Unable to map message buffers!
\n
"
);
status
=
-
ENOMEM
;
goto
out
;
return
-
ENOMEM
;
}
/* Configure feedback delay */
writel
(
cs
->
fb_delay
&
0x3
,
sdd
->
regs
+
S3C64XX_SPI_FB_CLK
);
list_for_each_entry
(
xfer
,
&
msg
->
transfers
,
transfer_list
)
{
return
0
;
}
static
int
s3c64xx_spi_transfer_one
(
struct
spi_master
*
master
,
struct
spi_device
*
spi
,
struct
spi_transfer
*
xfer
)
{
struct
s3c64xx_spi_driver_data
*
sdd
=
spi_master_get_devdata
(
master
);
int
status
;
u32
speed
;
u8
bpw
;
unsigned
long
flags
;
int
use_dma
;
...
...
@@ -909,8 +900,7 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master,
dev_err
(
&
spi
->
dev
,
"Xfer length(%u) not a multiple of word size(%u)
\n
"
,
xfer
->
len
,
bpw
/
8
);
status
=
-
EIO
;
goto
out
;
return
-
EIO
;
}
if
(
bpw
!=
sdd
->
cur_bpw
||
speed
!=
sdd
->
cur_speed
)
{
...
...
@@ -934,8 +924,11 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master,
enable_datapath
(
sdd
,
spi
,
xfer
,
use_dma
);
/* Slave Select */
enable_cs
(
sdd
,
spi
);
/* Start the signals */
writel
(
0
,
sdd
->
regs
+
S3C64XX_SPI_SLAVE_SEL
);
/* Start the signals */
writel
(
0
,
sdd
->
regs
+
S3C64XX_SPI_SLAVE_SEL
);
spin_unlock_irqrestore
(
&
sdd
->
lock
,
flags
);
...
...
@@ -956,37 +949,19 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master,
&&
(
sdd
->
state
&
RXBUSY
))
s3c64xx_spi_dma_stop
(
sdd
,
&
sdd
->
rx_dma
);
}
goto
out
;
}
if
(
xfer
->
delay_usecs
)
udelay
(
xfer
->
delay_usecs
);
if
(
xfer
->
cs_change
)
{
/* Hint that the next mssg is gonna be
for the same device */
if
(
list_is_last
(
&
xfer
->
transfer_list
,
&
msg
->
transfers
))
cs_toggle
=
1
;
}
msg
->
actual_length
+=
xfer
->
len
;
}
else
{
flush_fifo
(
sdd
);
}
out:
if
(
!
cs_toggle
||
status
)
disable_cs
(
sdd
,
spi
);
else
sdd
->
tgl_spi
=
spi
;
s3c64xx_spi_unmap_mssg
(
sdd
,
msg
);
return
status
;
}
msg
->
status
=
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
);
s
pi_finalize_current_message
(
master
);
s
3c64xx_spi_unmap_mssg
(
sdd
,
msg
);
return
0
;
}
...
...
@@ -1071,6 +1046,8 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
cs
->
line
,
err
);
goto
err_gpio_req
;
}
spi
->
cs_gpio
=
cs
->
line
;
}
spi_set_ctldata
(
spi
,
cs
);
...
...
@@ -1117,12 +1094,14 @@ 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
);
...
...
@@ -1141,8 +1120,8 @@ static void s3c64xx_spi_cleanup(struct spi_device *spi)
struct
s3c64xx_spi_driver_data
*
sdd
;
sdd
=
spi_master_get_devdata
(
spi
->
master
);
if
(
cs
&&
sdd
->
cs_gpio
)
{
gpio_free
(
cs
->
line
);
if
(
spi
->
cs_gpio
)
{
gpio_free
(
spi
->
cs_gpio
);
if
(
spi
->
dev
.
of_node
)
kfree
(
cs
);
}
...
...
@@ -1360,7 +1339,9 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
master
->
setup
=
s3c64xx_spi_setup
;
master
->
cleanup
=
s3c64xx_spi_cleanup
;
master
->
prepare_transfer_hardware
=
s3c64xx_spi_prepare_transfer
;
master
->
transfer_one_message
=
s3c64xx_spi_transfer_one_message
;
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
;
...
...
@@ -1432,9 +1413,9 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
pm_runtime_set_active
(
&
pdev
->
dev
);
pm_runtime_enable
(
&
pdev
->
dev
);
if
(
spi_register_master
(
master
))
{
dev_err
(
&
pdev
->
dev
,
"cannot register SPI master
\n
"
);
ret
=
-
EBUSY
;
ret
=
devm_spi_register_master
(
&
pdev
->
dev
,
master
);
if
(
ret
!=
0
)
{
dev_err
(
&
pdev
->
dev
,
"cannot register SPI master: %d
\n
"
,
ret
)
;
goto
err3
;
}
...
...
@@ -1463,16 +1444,12 @@ static int s3c64xx_spi_remove(struct platform_device *pdev)
pm_runtime_disable
(
&
pdev
->
dev
);
spi_unregister_master
(
master
);
writel
(
0
,
sdd
->
regs
+
S3C64XX_SPI_INT_EN
);
clk_disable_unprepare
(
sdd
->
src_clk
);
clk_disable_unprepare
(
sdd
->
clk
);
spi_master_put
(
master
);
return
0
;
}
...
...
@@ -1530,9 +1507,17 @@ static int s3c64xx_spi_runtime_resume(struct device *dev)
{
struct
spi_master
*
master
=
dev_get_drvdata
(
dev
);
struct
s3c64xx_spi_driver_data
*
sdd
=
spi_master_get_devdata
(
master
);
int
ret
;
clk_prepare_enable
(
sdd
->
src_clk
);
clk_prepare_enable
(
sdd
->
clk
);
ret
=
clk_prepare_enable
(
sdd
->
src_clk
);
if
(
ret
!=
0
)
return
ret
;
ret
=
clk_prepare_enable
(
sdd
->
clk
);
if
(
ret
!=
0
)
{
clk_disable_unprepare
(
sdd
->
src_clk
);
return
ret
;
}
return
0
;
}
...
...
@@ -1618,6 +1603,18 @@ static struct platform_device_id s3c64xx_spi_driver_ids[] = {
};
static
const
struct
of_device_id
s3c64xx_spi_dt_match
[]
=
{
{
.
compatible
=
"samsung,s3c2443-spi"
,
.
data
=
(
void
*
)
&
s3c2443_spi_port_config
,
},
{
.
compatible
=
"samsung,s3c6410-spi"
,
.
data
=
(
void
*
)
&
s3c6410_spi_port_config
,
},
{
.
compatible
=
"samsung,s5pc100-spi"
,
.
data
=
(
void
*
)
&
s5pc100_spi_port_config
,
},
{
.
compatible
=
"samsung,s5pv210-spi"
,
.
data
=
(
void
*
)
&
s5pv210_spi_port_config
,
},
{
.
compatible
=
"samsung,exynos4210-spi"
,
.
data
=
(
void
*
)
&
exynos4_spi_port_config
,
},
...
...
@@ -1635,22 +1632,13 @@ static struct platform_driver s3c64xx_spi_driver = {
.
pm
=
&
s3c64xx_spi_pm
,
.
of_match_table
=
of_match_ptr
(
s3c64xx_spi_dt_match
),
},
.
probe
=
s3c64xx_spi_probe
,
.
remove
=
s3c64xx_spi_remove
,
.
id_table
=
s3c64xx_spi_driver_ids
,
};
MODULE_ALIAS
(
"platform:s3c64xx-spi"
);
static
int
__init
s3c64xx_spi_init
(
void
)
{
return
platform_driver_probe
(
&
s3c64xx_spi_driver
,
s3c64xx_spi_probe
);
}
subsys_initcall
(
s3c64xx_spi_init
);
static
void
__exit
s3c64xx_spi_exit
(
void
)
{
platform_driver_unregister
(
&
s3c64xx_spi_driver
);
}
module_exit
(
s3c64xx_spi_exit
);
module_platform_driver
(
s3c64xx_spi_driver
);
MODULE_AUTHOR
(
"Jaswinder Singh <jassi.brar@samsung.com>"
);
MODULE_DESCRIPTION
(
"S3C64XX SPI Controller Driver"
);
...
...
drivers/spi/spi.c
View file @
8211e6b8
...
...
@@ -39,6 +39,9 @@
#include <linux/ioport.h>
#include <linux/acpi.h>
#define CREATE_TRACE_POINTS
#include <trace/events/spi.h>
static
void
spidev_release
(
struct
device
*
dev
)
{
struct
spi_device
*
spi
=
to_spi_device
(
dev
);
...
...
@@ -525,6 +528,95 @@ int spi_register_board_info(struct spi_board_info const *info, unsigned n)
/*-------------------------------------------------------------------------*/
static
void
spi_set_cs
(
struct
spi_device
*
spi
,
bool
enable
)
{
if
(
spi
->
mode
&
SPI_CS_HIGH
)
enable
=
!
enable
;
if
(
spi
->
cs_gpio
>=
0
)
gpio_set_value
(
spi
->
cs_gpio
,
!
enable
);
else
if
(
spi
->
master
->
set_cs
)
spi
->
master
->
set_cs
(
spi
,
!
enable
);
}
/*
* spi_transfer_one_message - Default implementation of transfer_one_message()
*
* This is a standard implementation of transfer_one_message() for
* drivers which impelment a transfer_one() operation. It provides
* standard handling of delays and chip select management.
*/
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
;
spi_set_cs
(
msg
->
spi
,
true
);
list_for_each_entry
(
xfer
,
&
msg
->
transfers
,
transfer_list
)
{
trace_spi_transfer_start
(
msg
,
xfer
);
INIT_COMPLETION
(
master
->
xfer_completion
);
ret
=
master
->
transfer_one
(
master
,
msg
->
spi
,
xfer
);
if
(
ret
<
0
)
{
dev_err
(
&
msg
->
spi
->
dev
,
"SPI transfer failed: %d
\n
"
,
ret
);
goto
out
;
}
if
(
ret
>
0
)
wait_for_completion
(
&
master
->
xfer_completion
);
trace_spi_transfer_stop
(
msg
,
xfer
);
if
(
msg
->
status
!=
-
EINPROGRESS
)
goto
out
;
if
(
xfer
->
delay_usecs
)
udelay
(
xfer
->
delay_usecs
);
if
(
xfer
->
cs_change
)
{
if
(
list_is_last
(
&
xfer
->
transfer_list
,
&
msg
->
transfers
))
{
keep_cs
=
true
;
}
else
{
cur_cs
=
!
cur_cs
;
spi_set_cs
(
msg
->
spi
,
cur_cs
);
}
}
msg
->
actual_length
+=
xfer
->
len
;
}
out:
if
(
ret
!=
0
||
!
keep_cs
)
spi_set_cs
(
msg
->
spi
,
false
);
if
(
msg
->
status
==
-
EINPROGRESS
)
msg
->
status
=
ret
;
spi_finalize_current_message
(
master
);
return
ret
;
}
/**
* spi_finalize_current_transfer - report completion of a transfer
*
* Called by SPI drivers using the core transfer_one_message()
* implementation to notify it that the current interrupt driven
* transfer has finised and the next one may be scheduled.
*/
void
spi_finalize_current_transfer
(
struct
spi_master
*
master
)
{
complete
(
&
master
->
xfer_completion
);
}
EXPORT_SYMBOL_GPL
(
spi_finalize_current_transfer
);
/**
* spi_pump_messages - kthread work function which processes spi message queue
* @work: pointer to kthread work struct contained in the master struct
...
...
@@ -559,6 +651,7 @@ static void spi_pump_messages(struct kthread_work *work)
pm_runtime_mark_last_busy
(
master
->
dev
.
parent
);
pm_runtime_put_autosuspend
(
master
->
dev
.
parent
);
}
trace_spi_master_idle
(
master
);
return
;
}
...
...
@@ -587,6 +680,9 @@ static void spi_pump_messages(struct kthread_work *work)
}
}
if
(
!
was_busy
)
trace_spi_master_busy
(
master
);
if
(
!
was_busy
&&
master
->
prepare_transfer_hardware
)
{
ret
=
master
->
prepare_transfer_hardware
(
master
);
if
(
ret
)
{
...
...
@@ -599,6 +695,20 @@ static void spi_pump_messages(struct kthread_work *work)
}
}
trace_spi_message_start
(
master
->
cur_msg
);
if
(
master
->
prepare_message
)
{
ret
=
master
->
prepare_message
(
master
,
master
->
cur_msg
);
if
(
ret
)
{
dev_err
(
&
master
->
dev
,
"failed to prepare message: %d
\n
"
,
ret
);
master
->
cur_msg
->
status
=
ret
;
spi_finalize_current_message
(
master
);
return
;
}
master
->
cur_msg_prepared
=
true
;
}
ret
=
master
->
transfer_one_message
(
master
,
master
->
cur_msg
);
if
(
ret
)
{
dev_err
(
&
master
->
dev
,
...
...
@@ -680,6 +790,7 @@ void spi_finalize_current_message(struct spi_master *master)
{
struct
spi_message
*
mesg
;
unsigned
long
flags
;
int
ret
;
spin_lock_irqsave
(
&
master
->
queue_lock
,
flags
);
mesg
=
master
->
cur_msg
;
...
...
@@ -688,9 +799,20 @@ void spi_finalize_current_message(struct spi_master *master)
queue_kthread_work
(
&
master
->
kworker
,
&
master
->
pump_messages
);
spin_unlock_irqrestore
(
&
master
->
queue_lock
,
flags
);
if
(
master
->
cur_msg_prepared
&&
master
->
unprepare_message
)
{
ret
=
master
->
unprepare_message
(
master
,
mesg
);
if
(
ret
)
{
dev_err
(
&
master
->
dev
,
"failed to unprepare message: %d
\n
"
,
ret
);
}
}
master
->
cur_msg_prepared
=
false
;
mesg
->
state
=
NULL
;
if
(
mesg
->
complete
)
mesg
->
complete
(
mesg
->
context
);
trace_spi_message_done
(
mesg
);
}
EXPORT_SYMBOL_GPL
(
spi_finalize_current_message
);
...
...
@@ -805,6 +927,8 @@ static int spi_master_initialize_queue(struct spi_master *master)
master
->
queued
=
true
;
master
->
transfer
=
spi_queued_transfer
;
if
(
!
master
->
transfer_one_message
)
master
->
transfer_one_message
=
spi_transfer_one_message
;
/* Initialize and start queue */
ret
=
spi_init_queue
(
master
);
...
...
@@ -1205,6 +1329,7 @@ int spi_register_master(struct spi_master *master)
spin_lock_init
(
&
master
->
bus_lock_spinlock
);
mutex_init
(
&
master
->
bus_lock_mutex
);
master
->
bus_lock_flag
=
0
;
init_completion
(
&
master
->
xfer_completion
);
/* register the device, then userspace will see it.
* registration fails if the bus ID is in use.
...
...
@@ -1451,6 +1576,10 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message)
struct
spi_master
*
master
=
spi
->
master
;
struct
spi_transfer
*
xfer
;
message
->
spi
=
spi
;
trace_spi_message_submit
(
message
);
if
(
list_empty
(
&
message
->
transfers
))
return
-
EINVAL
;
if
(
!
message
->
complete
)
...
...
@@ -1550,7 +1679,6 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message)
}
}
message
->
spi
=
spi
;
message
->
status
=
-
EINPROGRESS
;
return
master
->
transfer
(
spi
,
message
);
}
...
...
include/linux/spi/spi.h
View file @
8211e6b8
...
...
@@ -23,6 +23,7 @@
#include <linux/mod_devicetable.h>
#include <linux/slab.h>
#include <linux/kthread.h>
#include <linux/completion.h>
/*
* INTERFACES between SPI master-side drivers and SPI infrastructure.
...
...
@@ -150,8 +151,7 @@ static inline void *spi_get_drvdata(struct spi_device *spi)
}
struct
spi_message
;
struct
spi_transfer
;
/**
* struct spi_driver - Host side "protocol" driver
...
...
@@ -257,6 +257,9 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
* @queue_lock: spinlock to syncronise access to message queue
* @queue: message queue
* @cur_msg: the currently in-flight message
* @cur_msg_prepared: spi_prepare_message was called for the currently
* in-flight message
* @xfer_completion: used by core tranfer_one_message()
* @busy: message pump is busy
* @running: message pump is running
* @rt: whether this queue is set to run as a realtime task
...
...
@@ -274,6 +277,16 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
* @unprepare_transfer_hardware: there are currently no more messages on the
* queue so the subsystem notifies the driver that it may relax the
* hardware by issuing this call
* @set_cs: assert or deassert chip select, true to assert. May be called
* from interrupt context.
* @prepare_message: set up the controller to transfer a single message,
* for example doing DMA mapping. Called from threaded
* context.
* @transfer_one: transfer a single spi_transfer. When the
* driver is finished with this transfer it must call
* spi_finalize_current_transfer() so the subsystem can issue
* the next transfer
* @unprepare_message: undo any work done by prepare_message().
* @cs_gpios: Array of GPIOs to use as chip select lines; one per CS
* number. Any individual value may be -ENOENT for CS lines that
* are not GPIOs (driven by the SPI controller itself).
...
...
@@ -388,11 +401,25 @@ struct spi_master {
bool
running
;
bool
rt
;
bool
auto_runtime_pm
;
bool
cur_msg_prepared
;
struct
completion
xfer_completion
;
int
(
*
prepare_transfer_hardware
)(
struct
spi_master
*
master
);
int
(
*
transfer_one_message
)(
struct
spi_master
*
master
,
struct
spi_message
*
mesg
);
int
(
*
unprepare_transfer_hardware
)(
struct
spi_master
*
master
);
int
(
*
prepare_message
)(
struct
spi_master
*
master
,
struct
spi_message
*
message
);
int
(
*
unprepare_message
)(
struct
spi_master
*
master
,
struct
spi_message
*
message
);
/*
* These hooks are for drivers that use a generic implementation
* of transfer_one_message() provied by the core.
*/
void
(
*
set_cs
)(
struct
spi_device
*
spi
,
bool
enable
);
int
(
*
transfer_one
)(
struct
spi_master
*
master
,
struct
spi_device
*
spi
,
struct
spi_transfer
*
transfer
);
/* gpio chip select */
int
*
cs_gpios
;
...
...
@@ -428,6 +455,7 @@ extern int spi_master_resume(struct spi_master *master);
/* Calls the driver make to interact with the message queue */
extern
struct
spi_message
*
spi_get_next_queued_message
(
struct
spi_master
*
master
);
extern
void
spi_finalize_current_message
(
struct
spi_master
*
master
);
extern
void
spi_finalize_current_transfer
(
struct
spi_master
*
master
);
/* the spi driver core manages memory for the spi_master classdev */
extern
struct
spi_master
*
...
...
include/trace/events/spi.h
0 → 100644
View file @
8211e6b8
#undef TRACE_SYSTEM
#define TRACE_SYSTEM spi
#if !defined(_TRACE_SPI_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_SPI_H
#include <linux/ktime.h>
#include <linux/tracepoint.h>
DECLARE_EVENT_CLASS
(
spi_master
,
TP_PROTO
(
struct
spi_master
*
master
),
TP_ARGS
(
master
),
TP_STRUCT__entry
(
__field
(
int
,
bus_num
)
),
TP_fast_assign
(
__entry
->
bus_num
=
master
->
bus_num
;
),
TP_printk
(
"spi%d"
,
(
int
)
__entry
->
bus_num
)
);
DEFINE_EVENT
(
spi_master
,
spi_master_idle
,
TP_PROTO
(
struct
spi_master
*
master
),
TP_ARGS
(
master
)
);
DEFINE_EVENT
(
spi_master
,
spi_master_busy
,
TP_PROTO
(
struct
spi_master
*
master
),
TP_ARGS
(
master
)
);
DECLARE_EVENT_CLASS
(
spi_message
,
TP_PROTO
(
struct
spi_message
*
msg
),
TP_ARGS
(
msg
),
TP_STRUCT__entry
(
__field
(
int
,
bus_num
)
__field
(
int
,
chip_select
)
__field
(
struct
spi_message
*
,
msg
)
),
TP_fast_assign
(
__entry
->
bus_num
=
msg
->
spi
->
master
->
bus_num
;
__entry
->
chip_select
=
msg
->
spi
->
chip_select
;
__entry
->
msg
=
msg
;
),
TP_printk
(
"spi%d.%d %p"
,
(
int
)
__entry
->
bus_num
,
(
int
)
__entry
->
chip_select
,
(
struct
spi_message
*
)
__entry
->
msg
)
);
DEFINE_EVENT
(
spi_message
,
spi_message_submit
,
TP_PROTO
(
struct
spi_message
*
msg
),
TP_ARGS
(
msg
)
);
DEFINE_EVENT
(
spi_message
,
spi_message_start
,
TP_PROTO
(
struct
spi_message
*
msg
),
TP_ARGS
(
msg
)
);
TRACE_EVENT
(
spi_message_done
,
TP_PROTO
(
struct
spi_message
*
msg
),
TP_ARGS
(
msg
),
TP_STRUCT__entry
(
__field
(
int
,
bus_num
)
__field
(
int
,
chip_select
)
__field
(
struct
spi_message
*
,
msg
)
__field
(
unsigned
,
frame
)
__field
(
unsigned
,
actual
)
),
TP_fast_assign
(
__entry
->
bus_num
=
msg
->
spi
->
master
->
bus_num
;
__entry
->
chip_select
=
msg
->
spi
->
chip_select
;
__entry
->
msg
=
msg
;
__entry
->
frame
=
msg
->
frame_length
;
__entry
->
actual
=
msg
->
actual_length
;
),
TP_printk
(
"spi%d.%d %p len=%u/%u"
,
(
int
)
__entry
->
bus_num
,
(
int
)
__entry
->
chip_select
,
(
struct
spi_message
*
)
__entry
->
msg
,
(
unsigned
)
__entry
->
actual
,
(
unsigned
)
__entry
->
frame
)
);
DECLARE_EVENT_CLASS
(
spi_transfer
,
TP_PROTO
(
struct
spi_message
*
msg
,
struct
spi_transfer
*
xfer
),
TP_ARGS
(
msg
,
xfer
),
TP_STRUCT__entry
(
__field
(
int
,
bus_num
)
__field
(
int
,
chip_select
)
__field
(
struct
spi_transfer
*
,
xfer
)
__field
(
int
,
len
)
),
TP_fast_assign
(
__entry
->
bus_num
=
msg
->
spi
->
master
->
bus_num
;
__entry
->
chip_select
=
msg
->
spi
->
chip_select
;
__entry
->
xfer
=
xfer
;
__entry
->
len
=
xfer
->
len
;
),
TP_printk
(
"spi%d.%d %p len=%d"
,
(
int
)
__entry
->
bus_num
,
(
int
)
__entry
->
chip_select
,
(
struct
spi_message
*
)
__entry
->
xfer
,
(
int
)
__entry
->
len
)
);
DEFINE_EVENT
(
spi_transfer
,
spi_transfer_start
,
TP_PROTO
(
struct
spi_message
*
msg
,
struct
spi_transfer
*
xfer
),
TP_ARGS
(
msg
,
xfer
)
);
DEFINE_EVENT
(
spi_transfer
,
spi_transfer_stop
,
TP_PROTO
(
struct
spi_message
*
msg
,
struct
spi_transfer
*
xfer
),
TP_ARGS
(
msg
,
xfer
)
);
#endif
/* _TRACE_POWER_H */
/* This part must be outside protection */
#include <trace/define_trace.h>
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