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
85cac431
Commit
85cac431
authored
Sep 01, 2013
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'spi/topic/qspi' into spi-next
parents
793b3cb6
b6460366
Changes
16
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
757 additions
and
136 deletions
+757
-136
Documentation/devicetree/bindings/spi/ti_qspi.txt
Documentation/devicetree/bindings/spi/ti_qspi.txt
+22
-0
drivers/spi/Kconfig
drivers/spi/Kconfig
+8
-0
drivers/spi/Makefile
drivers/spi/Makefile
+1
-0
drivers/spi/spi-bcm63xx.c
drivers/spi/spi-bcm63xx.c
+1
-20
drivers/spi/spi-coldfire-qspi.c
drivers/spi/spi-coldfire-qspi.c
+1
-20
drivers/spi/spi-omap2-mcspi.c
drivers/spi/spi-omap2-mcspi.c
+1
-19
drivers/spi/spi-pl022.c
drivers/spi/spi-pl022.c
+1
-20
drivers/spi/spi-pxa2xx.c
drivers/spi/spi-pxa2xx.c
+1
-11
drivers/spi/spi-s3c64xx.c
drivers/spi/spi-s3c64xx.c
+1
-3
drivers/spi/spi-sh-hspi.c
drivers/spi/spi-sh-hspi.c
+1
-17
drivers/spi/spi-tegra114.c
drivers/spi/spi-tegra114.c
+1
-9
drivers/spi/spi-tegra20-sflash.c
drivers/spi/spi-tegra20-sflash.c
+1
-7
drivers/spi/spi-tegra20-slink.c
drivers/spi/spi-tegra20-slink.c
+1
-7
drivers/spi/spi-ti-qspi.c
drivers/spi/spi-ti-qspi.c
+574
-0
drivers/spi/spi.c
drivers/spi/spi.c
+117
-1
include/linux/spi/spi.h
include/linux/spi/spi.h
+25
-2
No files found.
Documentation/devicetree/bindings/spi/ti_qspi.txt
0 → 100644
View file @
85cac431
TI QSPI controller.
Required properties:
- compatible : should be "ti,dra7xxx-qspi" or "ti,am4372-qspi".
- reg: Should contain QSPI registers location and length.
- #address-cells, #size-cells : Must be present if the device has sub-nodes
- ti,hwmods: Name of the hwmod associated to the QSPI
Recommended properties:
- spi-max-frequency: Definition as per
Documentation/devicetree/bindings/spi/spi-bus.txt
Example:
qspi: qspi@4b300000 {
compatible = "ti,dra7xxx-qspi";
reg = <0x4b300000 0x100>;
#address-cells = <1>;
#size-cells = <0>;
spi-max-frequency = <25000000>;
ti,hwmods = "qspi";
};
drivers/spi/Kconfig
View file @
85cac431
...
...
@@ -306,6 +306,14 @@ config SPI_OMAP24XX
SPI master controller for OMAP24XX and later Multichannel SPI
(McSPI) modules.
config SPI_TI_QSPI
tristate "DRA7xxx QSPI controller support"
depends on ARCH_OMAP2PLUS || COMPILE_TEST
help
QSPI master controller for DRA7xxx used for flash devices.
This device supports single, dual and quad read support, while
it only supports single write mode.
config SPI_OMAP_100K
tristate "OMAP SPI 100K"
depends on ARCH_OMAP850 || ARCH_OMAP730 || COMPILE_TEST
...
...
drivers/spi/Makefile
View file @
85cac431
...
...
@@ -49,6 +49,7 @@ obj-$(CONFIG_SPI_OCTEON) += spi-octeon.o
obj-$(CONFIG_SPI_OMAP_UWIRE)
+=
spi-omap-uwire.o
obj-$(CONFIG_SPI_OMAP_100K)
+=
spi-omap-100k.o
obj-$(CONFIG_SPI_OMAP24XX)
+=
spi-omap2-mcspi.o
obj-$(CONFIG_SPI_TI_QSPI)
+=
spi-ti-qspi.o
obj-$(CONFIG_SPI_ORION)
+=
spi-orion.o
obj-$(CONFIG_SPI_PL022)
+=
spi-pl022.o
obj-$(CONFIG_SPI_PPC4xx)
+=
spi-ppc4xx.o
...
...
drivers/spi/spi-bcm63xx.c
View file @
85cac431
...
...
@@ -231,24 +231,6 @@ static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *first,
return
0
;
}
static
int
bcm63xx_spi_prepare_transfer
(
struct
spi_master
*
master
)
{
struct
bcm63xx_spi
*
bs
=
spi_master_get_devdata
(
master
);
pm_runtime_get_sync
(
&
bs
->
pdev
->
dev
);
return
0
;
}
static
int
bcm63xx_spi_unprepare_transfer
(
struct
spi_master
*
master
)
{
struct
bcm63xx_spi
*
bs
=
spi_master_get_devdata
(
master
);
pm_runtime_put
(
&
bs
->
pdev
->
dev
);
return
0
;
}
static
int
bcm63xx_spi_transfer_one
(
struct
spi_master
*
master
,
struct
spi_message
*
m
)
{
...
...
@@ -406,11 +388,10 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
master
->
bus_num
=
pdata
->
bus_num
;
master
->
num_chipselect
=
pdata
->
num_chipselect
;
master
->
prepare_transfer_hardware
=
bcm63xx_spi_prepare_transfer
;
master
->
unprepare_transfer_hardware
=
bcm63xx_spi_unprepare_transfer
;
master
->
transfer_one_message
=
bcm63xx_spi_transfer_one
;
master
->
mode_bits
=
MODEBITS
;
master
->
bits_per_word_mask
=
SPI_BPW_MASK
(
8
);
master
->
auto_runtime_pm
=
true
;
bs
->
msg_type_shift
=
pdata
->
msg_type_shift
;
bs
->
msg_ctl_width
=
pdata
->
msg_ctl_width
;
bs
->
tx_io
=
(
u8
*
)(
bs
->
regs
+
bcm63xx_spireg
(
SPI_MSG_DATA
));
...
...
drivers/spi/spi-coldfire-qspi.c
View file @
85cac431
...
...
@@ -354,24 +354,6 @@ static int mcfqspi_transfer_one_message(struct spi_master *master,
}
static
int
mcfqspi_prepare_transfer_hw
(
struct
spi_master
*
master
)
{
struct
mcfqspi
*
mcfqspi
=
spi_master_get_devdata
(
master
);
pm_runtime_get_sync
(
mcfqspi
->
dev
);
return
0
;
}
static
int
mcfqspi_unprepare_transfer_hw
(
struct
spi_master
*
master
)
{
struct
mcfqspi
*
mcfqspi
=
spi_master_get_devdata
(
master
);
pm_runtime_put_sync
(
mcfqspi
->
dev
);
return
0
;
}
static
int
mcfqspi_setup
(
struct
spi_device
*
spi
)
{
if
(
spi
->
chip_select
>=
spi
->
master
->
num_chipselect
)
{
...
...
@@ -473,8 +455,7 @@ static int mcfqspi_probe(struct platform_device *pdev)
master
->
bits_per_word_mask
=
SPI_BPW_RANGE_MASK
(
8
,
16
);
master
->
setup
=
mcfqspi_setup
;
master
->
transfer_one_message
=
mcfqspi_transfer_one_message
;
master
->
prepare_transfer_hardware
=
mcfqspi_prepare_transfer_hw
;
master
->
unprepare_transfer_hardware
=
mcfqspi_unprepare_transfer_hw
;
master
->
auto_runtime_pm
=
true
;
platform_set_drvdata
(
pdev
,
master
);
...
...
drivers/spi/spi-omap2-mcspi.c
View file @
85cac431
...
...
@@ -335,23 +335,6 @@ static void omap2_mcspi_restore_ctx(struct omap2_mcspi *mcspi)
__raw_writel
(
cs
->
chconf0
,
cs
->
base
+
OMAP2_MCSPI_CHCONF0
);
}
static
int
omap2_prepare_transfer
(
struct
spi_master
*
master
)
{
struct
omap2_mcspi
*
mcspi
=
spi_master_get_devdata
(
master
);
pm_runtime_get_sync
(
mcspi
->
dev
);
return
0
;
}
static
int
omap2_unprepare_transfer
(
struct
spi_master
*
master
)
{
struct
omap2_mcspi
*
mcspi
=
spi_master_get_devdata
(
master
);
pm_runtime_mark_last_busy
(
mcspi
->
dev
);
pm_runtime_put_autosuspend
(
mcspi
->
dev
);
return
0
;
}
static
int
mcspi_wait_for_reg_bit
(
void
__iomem
*
reg
,
unsigned
long
bit
)
{
unsigned
long
timeout
;
...
...
@@ -1318,8 +1301,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
master
->
mode_bits
=
SPI_CPOL
|
SPI_CPHA
|
SPI_CS_HIGH
;
master
->
bits_per_word_mask
=
SPI_BPW_RANGE_MASK
(
4
,
32
);
master
->
setup
=
omap2_mcspi_setup
;
master
->
prepare_transfer_hardware
=
omap2_prepare_transfer
;
master
->
unprepare_transfer_hardware
=
omap2_unprepare_transfer
;
master
->
auto_runtime_pm
=
true
;
master
->
transfer_one_message
=
omap2_mcspi_transfer_one_message
;
master
->
cleanup
=
omap2_mcspi_cleanup
;
master
->
dev
.
of_node
=
node
;
...
...
drivers/spi/spi-pl022.c
View file @
85cac431
...
...
@@ -1555,18 +1555,6 @@ static int pl022_transfer_one_message(struct spi_master *master,
return
0
;
}
static
int
pl022_prepare_transfer_hardware
(
struct
spi_master
*
master
)
{
struct
pl022
*
pl022
=
spi_master_get_devdata
(
master
);
/*
* Just make sure we have all we need to run the transfer by syncing
* with the runtime PM framework.
*/
pm_runtime_get_sync
(
&
pl022
->
adev
->
dev
);
return
0
;
}
static
int
pl022_unprepare_transfer_hardware
(
struct
spi_master
*
master
)
{
struct
pl022
*
pl022
=
spi_master_get_devdata
(
master
);
...
...
@@ -1575,13 +1563,6 @@ static int pl022_unprepare_transfer_hardware(struct spi_master *master)
writew
((
readw
(
SSP_CR1
(
pl022
->
virtbase
))
&
(
~
SSP_CR1_MASK_SSE
)),
SSP_CR1
(
pl022
->
virtbase
));
if
(
pl022
->
master_info
->
autosuspend_delay
>
0
)
{
pm_runtime_mark_last_busy
(
&
pl022
->
adev
->
dev
);
pm_runtime_put_autosuspend
(
&
pl022
->
adev
->
dev
);
}
else
{
pm_runtime_put
(
&
pl022
->
adev
->
dev
);
}
return
0
;
}
...
...
@@ -2140,7 +2121,7 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
master
->
num_chipselect
=
num_cs
;
master
->
cleanup
=
pl022_cleanup
;
master
->
setup
=
pl022_setup
;
master
->
prepare_transfer_hardware
=
pl022_prepare_transfer_hardwar
e
;
master
->
auto_runtime_pm
=
tru
e
;
master
->
transfer_one_message
=
pl022_transfer_one_message
;
master
->
unprepare_transfer_hardware
=
pl022_unprepare_transfer_hardware
;
master
->
rt
=
platform_info
->
rt
;
...
...
drivers/spi/spi-pxa2xx.c
View file @
85cac431
...
...
@@ -811,14 +811,6 @@ static int pxa2xx_spi_transfer_one_message(struct spi_master *master,
return
0
;
}
static
int
pxa2xx_spi_prepare_transfer
(
struct
spi_master
*
master
)
{
struct
driver_data
*
drv_data
=
spi_master_get_devdata
(
master
);
pm_runtime_get_sync
(
&
drv_data
->
pdev
->
dev
);
return
0
;
}
static
int
pxa2xx_spi_unprepare_transfer
(
struct
spi_master
*
master
)
{
struct
driver_data
*
drv_data
=
spi_master_get_devdata
(
master
);
...
...
@@ -827,8 +819,6 @@ static int pxa2xx_spi_unprepare_transfer(struct spi_master *master)
write_SSCR0
(
read_SSCR0
(
drv_data
->
ioaddr
)
&
~
SSCR0_SSE
,
drv_data
->
ioaddr
);
pm_runtime_mark_last_busy
(
&
drv_data
->
pdev
->
dev
);
pm_runtime_put_autosuspend
(
&
drv_data
->
pdev
->
dev
);
return
0
;
}
...
...
@@ -1141,8 +1131,8 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
master
->
cleanup
=
cleanup
;
master
->
setup
=
setup
;
master
->
transfer_one_message
=
pxa2xx_spi_transfer_one_message
;
master
->
prepare_transfer_hardware
=
pxa2xx_spi_prepare_transfer
;
master
->
unprepare_transfer_hardware
=
pxa2xx_spi_unprepare_transfer
;
master
->
auto_runtime_pm
=
true
;
drv_data
->
ssp_type
=
ssp
->
type
;
drv_data
->
null_dma_buf
=
(
u32
*
)
PTR_ALIGN
(
&
drv_data
[
1
],
DMA_ALIGNMENT
);
...
...
drivers/spi/spi-s3c64xx.c
View file @
85cac431
...
...
@@ -356,8 +356,6 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
while
(
!
is_polling
(
sdd
)
&&
!
acquire_dma
(
sdd
))
usleep_range
(
10000
,
11000
);
pm_runtime_get_sync
(
&
sdd
->
pdev
->
dev
);
return
0
;
}
...
...
@@ -372,7 +370,6 @@ static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
sdd
->
ops
->
release
((
enum
dma_ch
)
sdd
->
tx_dma
.
ch
,
&
s3c64xx_spi_dma_client
);
}
pm_runtime_put
(
&
sdd
->
pdev
->
dev
);
return
0
;
}
...
...
@@ -1395,6 +1392,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
SPI_BPW_MASK
(
8
);
/* the spi->mode bits understood by this driver: */
master
->
mode_bits
=
SPI_CPOL
|
SPI_CPHA
|
SPI_CS_HIGH
;
master
->
auto_runtime_pm
=
true
;
sdd
->
regs
=
devm_ioremap_resource
(
&
pdev
->
dev
,
mem_res
);
if
(
IS_ERR
(
sdd
->
regs
))
{
...
...
drivers/spi/spi-sh-hspi.c
View file @
85cac431
...
...
@@ -99,21 +99,6 @@ static int hspi_status_check_timeout(struct hspi_priv *hspi, u32 mask, u32 val)
/*
* spi master function
*/
static
int
hspi_prepare_transfer
(
struct
spi_master
*
master
)
{
struct
hspi_priv
*
hspi
=
spi_master_get_devdata
(
master
);
pm_runtime_get_sync
(
hspi
->
dev
);
return
0
;
}
static
int
hspi_unprepare_transfer
(
struct
spi_master
*
master
)
{
struct
hspi_priv
*
hspi
=
spi_master_get_devdata
(
master
);
pm_runtime_put_sync
(
hspi
->
dev
);
return
0
;
}
#define hspi_hw_cs_enable(hspi) hspi_hw_cs_ctrl(hspi, 0)
#define hspi_hw_cs_disable(hspi) hspi_hw_cs_ctrl(hspi, 1)
...
...
@@ -316,9 +301,8 @@ static int hspi_probe(struct platform_device *pdev)
master
->
setup
=
hspi_setup
;
master
->
cleanup
=
hspi_cleanup
;
master
->
mode_bits
=
SPI_CPOL
|
SPI_CPHA
;
master
->
prepare_transfer_hardware
=
hspi_prepare_transfer
;
master
->
auto_runtime_pm
=
true
;
master
->
transfer_one_message
=
hspi_transfer_one_message
;
master
->
unprepare_transfer_hardware
=
hspi_unprepare_transfer
;
ret
=
spi_register_master
(
master
);
if
(
ret
<
0
)
{
dev_err
(
&
pdev
->
dev
,
"spi_register_master error.
\n
"
);
...
...
drivers/spi/spi-tegra114.c
View file @
85cac431
...
...
@@ -816,14 +816,6 @@ static int tegra_spi_transfer_one_message(struct spi_master *master,
msg
->
status
=
0
;
msg
->
actual_length
=
0
;
ret
=
pm_runtime_get_sync
(
tspi
->
dev
);
if
(
ret
<
0
)
{
dev_err
(
tspi
->
dev
,
"runtime PM get failed: %d
\n
"
,
ret
);
msg
->
status
=
ret
;
spi_finalize_current_message
(
master
);
return
ret
;
}
single_xfer
=
list_is_singular
(
&
msg
->
transfers
);
list_for_each_entry
(
xfer
,
&
msg
->
transfers
,
transfer_list
)
{
INIT_COMPLETION
(
tspi
->
xfer_completion
);
...
...
@@ -859,7 +851,6 @@ static int tegra_spi_transfer_one_message(struct spi_master *master,
ret
=
0
;
exit:
tegra_spi_writel
(
tspi
,
tspi
->
def_command1_reg
,
SPI_COMMAND1
);
pm_runtime_put
(
tspi
->
dev
);
msg
->
status
=
ret
;
spi_finalize_current_message
(
master
);
return
ret
;
...
...
@@ -1053,6 +1044,7 @@ static int tegra_spi_probe(struct platform_device *pdev)
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
;
tspi
->
dev
=
&
pdev
->
dev
;
...
...
drivers/spi/spi-tegra20-sflash.c
View file @
85cac431
...
...
@@ -335,12 +335,6 @@ static int tegra_sflash_transfer_one_message(struct spi_master *master,
struct
spi_device
*
spi
=
msg
->
spi
;
int
ret
;
ret
=
pm_runtime_get_sync
(
tsd
->
dev
);
if
(
ret
<
0
)
{
dev_err
(
tsd
->
dev
,
"pm_runtime_get() failed, err = %d
\n
"
,
ret
);
return
ret
;
}
msg
->
status
=
0
;
msg
->
actual_length
=
0
;
single_xfer
=
list_is_singular
(
&
msg
->
transfers
);
...
...
@@ -380,7 +374,6 @@ static int tegra_sflash_transfer_one_message(struct spi_master *master,
tegra_sflash_writel
(
tsd
,
tsd
->
def_command_reg
,
SPI_COMMAND
);
msg
->
status
=
ret
;
spi_finalize_current_message
(
master
);
pm_runtime_put
(
tsd
->
dev
);
return
ret
;
}
...
...
@@ -477,6 +470,7 @@ static int tegra_sflash_probe(struct platform_device *pdev)
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
;
...
...
drivers/spi/spi-tegra20-slink.c
View file @
85cac431
...
...
@@ -836,11 +836,6 @@ static int tegra_slink_transfer_one_message(struct spi_master *master,
msg
->
status
=
0
;
msg
->
actual_length
=
0
;
ret
=
pm_runtime_get_sync
(
tspi
->
dev
);
if
(
ret
<
0
)
{
dev_err
(
tspi
->
dev
,
"runtime get failed: %d
\n
"
,
ret
);
goto
done
;
}
single_xfer
=
list_is_singular
(
&
msg
->
transfers
);
list_for_each_entry
(
xfer
,
&
msg
->
transfers
,
transfer_list
)
{
...
...
@@ -878,8 +873,6 @@ static int tegra_slink_transfer_one_message(struct spi_master *master,
exit:
tegra_slink_writel
(
tspi
,
tspi
->
def_command_reg
,
SLINK_COMMAND
);
tegra_slink_writel
(
tspi
,
tspi
->
def_command2_reg
,
SLINK_COMMAND2
);
pm_runtime_put
(
tspi
->
dev
);
done:
msg
->
status
=
ret
;
spi_finalize_current_message
(
master
);
return
ret
;
...
...
@@ -1086,6 +1079,7 @@ static int tegra_slink_probe(struct platform_device *pdev)
master
->
mode_bits
=
SPI_CPOL
|
SPI_CPHA
|
SPI_CS_HIGH
;
master
->
setup
=
tegra_slink_setup
;
master
->
transfer_one_message
=
tegra_slink_transfer_one_message
;
master
->
auto_runtime_pm
=
true
;
master
->
num_chipselect
=
MAX_CHIP_SELECT
;
master
->
bus_num
=
-
1
;
...
...
drivers/spi/spi-ti-qspi.c
0 → 100644
View file @
85cac431
/*
* TI QSPI driver
*
* Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
* Author: Sourav Poddar <sourav.poddar@ti.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GPLv2.
*
* 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/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/omap-dma.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/spi/spi.h>
struct
ti_qspi_regs
{
u32
clkctrl
;
};
struct
ti_qspi
{
struct
completion
transfer_complete
;
/* IRQ synchronization */
spinlock_t
lock
;
/* list synchronization */
struct
mutex
list_lock
;
struct
spi_master
*
master
;
void
__iomem
*
base
;
struct
clk
*
fclk
;
struct
device
*
dev
;
struct
ti_qspi_regs
ctx_reg
;
u32
spi_max_frequency
;
u32
cmd
;
u32
dc
;
u32
stat
;
};
#define QSPI_PID (0x0)
#define QSPI_SYSCONFIG (0x10)
#define QSPI_INTR_STATUS_RAW_SET (0x20)
#define QSPI_INTR_STATUS_ENABLED_CLEAR (0x24)
#define QSPI_INTR_ENABLE_SET_REG (0x28)
#define QSPI_INTR_ENABLE_CLEAR_REG (0x2c)
#define QSPI_SPI_CLOCK_CNTRL_REG (0x40)
#define QSPI_SPI_DC_REG (0x44)
#define QSPI_SPI_CMD_REG (0x48)
#define QSPI_SPI_STATUS_REG (0x4c)
#define QSPI_SPI_DATA_REG (0x50)
#define QSPI_SPI_SETUP0_REG (0x54)
#define QSPI_SPI_SWITCH_REG (0x64)
#define QSPI_SPI_SETUP1_REG (0x58)
#define QSPI_SPI_SETUP2_REG (0x5c)
#define QSPI_SPI_SETUP3_REG (0x60)
#define QSPI_SPI_DATA_REG_1 (0x68)
#define QSPI_SPI_DATA_REG_2 (0x6c)
#define QSPI_SPI_DATA_REG_3 (0x70)
#define QSPI_COMPLETION_TIMEOUT msecs_to_jiffies(2000)
#define QSPI_FCLK 192000000
/* Clock Control */
#define QSPI_CLK_EN (1 << 31)
#define QSPI_CLK_DIV_MAX 0xffff
/* Command */
#define QSPI_EN_CS(n) (n << 28)
#define QSPI_WLEN(n) ((n - 1) << 19)
#define QSPI_3_PIN (1 << 18)
#define QSPI_RD_SNGL (1 << 16)
#define QSPI_WR_SNGL (2 << 16)
#define QSPI_RD_DUAL (3 << 16)
#define QSPI_RD_QUAD (7 << 16)
#define QSPI_INVAL (4 << 16)
#define QSPI_WC_CMD_INT_EN (1 << 14)
#define QSPI_FLEN(n) ((n - 1) << 0)
/* STATUS REGISTER */
#define WC 0x02
/* INTERRUPT REGISTER */
#define QSPI_WC_INT_EN (1 << 1)
#define QSPI_WC_INT_DISABLE (1 << 1)
/* Device Control */
#define QSPI_DD(m, n) (m << (3 + n * 8))
#define QSPI_CKPHA(n) (1 << (2 + n * 8))
#define QSPI_CSPOL(n) (1 << (1 + n * 8))
#define QSPI_CKPOL(n) (1 << (n * 8))
#define QSPI_FRAME 4096
#define QSPI_AUTOSUSPEND_TIMEOUT 2000
static
inline
unsigned
long
ti_qspi_read
(
struct
ti_qspi
*
qspi
,
unsigned
long
reg
)
{
return
readl
(
qspi
->
base
+
reg
);
}
static
inline
void
ti_qspi_write
(
struct
ti_qspi
*
qspi
,
unsigned
long
val
,
unsigned
long
reg
)
{
writel
(
val
,
qspi
->
base
+
reg
);
}
static
int
ti_qspi_setup
(
struct
spi_device
*
spi
)
{
struct
ti_qspi
*
qspi
=
spi_master_get_devdata
(
spi
->
master
);
struct
ti_qspi_regs
*
ctx_reg
=
&
qspi
->
ctx_reg
;
int
clk_div
=
0
,
ret
;
u32
clk_ctrl_reg
,
clk_rate
,
clk_mask
;
if
(
spi
->
master
->
busy
)
{
dev_dbg
(
qspi
->
dev
,
"master busy doing other trasnfers
\n
"
);
return
-
EBUSY
;
}
if
(
!
qspi
->
spi_max_frequency
)
{
dev_err
(
qspi
->
dev
,
"spi max frequency not defined
\n
"
);
return
-
EINVAL
;
}
clk_rate
=
clk_get_rate
(
qspi
->
fclk
);
clk_div
=
DIV_ROUND_UP
(
clk_rate
,
qspi
->
spi_max_frequency
)
-
1
;
if
(
clk_div
<
0
)
{
dev_dbg
(
qspi
->
dev
,
"clock divider < 0, using /1 divider
\n
"
);
return
-
EINVAL
;
}
if
(
clk_div
>
QSPI_CLK_DIV_MAX
)
{
dev_dbg
(
qspi
->
dev
,
"clock divider >%d , using /%d divider
\n
"
,
QSPI_CLK_DIV_MAX
,
QSPI_CLK_DIV_MAX
+
1
);
return
-
EINVAL
;
}
dev_dbg
(
qspi
->
dev
,
"hz: %d, clock divider %d
\n
"
,
qspi
->
spi_max_frequency
,
clk_div
);
ret
=
pm_runtime_get_sync
(
qspi
->
dev
);
if
(
ret
)
{
dev_err
(
qspi
->
dev
,
"pm_runtime_get_sync() failed
\n
"
);
return
ret
;
}
clk_ctrl_reg
=
ti_qspi_read
(
qspi
,
QSPI_SPI_CLOCK_CNTRL_REG
);
clk_ctrl_reg
&=
~
QSPI_CLK_EN
;
/* disable SCLK */
ti_qspi_write
(
qspi
,
clk_ctrl_reg
,
QSPI_SPI_CLOCK_CNTRL_REG
);
/* enable SCLK */
clk_mask
=
QSPI_CLK_EN
|
clk_div
;
ti_qspi_write
(
qspi
,
clk_mask
,
QSPI_SPI_CLOCK_CNTRL_REG
);
ctx_reg
->
clkctrl
=
clk_mask
;
pm_runtime_mark_last_busy
(
qspi
->
dev
);
ret
=
pm_runtime_put_autosuspend
(
qspi
->
dev
);
if
(
ret
<
0
)
{
dev_err
(
qspi
->
dev
,
"pm_runtime_put_autosuspend() failed
\n
"
);
return
ret
;
}
return
0
;
}
static
void
ti_qspi_restore_ctx
(
struct
ti_qspi
*
qspi
)
{
struct
ti_qspi_regs
*
ctx_reg
=
&
qspi
->
ctx_reg
;
ti_qspi_write
(
qspi
,
ctx_reg
->
clkctrl
,
QSPI_SPI_CLOCK_CNTRL_REG
);
}
static
int
qspi_write_msg
(
struct
ti_qspi
*
qspi
,
struct
spi_transfer
*
t
)
{
int
wlen
,
count
,
ret
;
unsigned
int
cmd
;
const
u8
*
txbuf
;
txbuf
=
t
->
tx_buf
;
cmd
=
qspi
->
cmd
|
QSPI_WR_SNGL
;
count
=
t
->
len
;
wlen
=
t
->
bits_per_word
;
while
(
count
)
{
switch
(
wlen
)
{
case
8
:
dev_dbg
(
qspi
->
dev
,
"tx cmd %08x dc %08x data %02x
\n
"
,
cmd
,
qspi
->
dc
,
*
txbuf
);
writeb
(
*
txbuf
,
qspi
->
base
+
QSPI_SPI_DATA_REG
);
ti_qspi_write
(
qspi
,
cmd
,
QSPI_SPI_CMD_REG
);
ret
=
wait_for_completion_timeout
(
&
qspi
->
transfer_complete
,
QSPI_COMPLETION_TIMEOUT
);
if
(
ret
==
0
)
{
dev_err
(
qspi
->
dev
,
"write timed out
\n
"
);
return
-
ETIMEDOUT
;
}
txbuf
+=
1
;
count
-=
1
;
break
;
case
16
:
dev_dbg
(
qspi
->
dev
,
"tx cmd %08x dc %08x data %04x
\n
"
,
cmd
,
qspi
->
dc
,
*
txbuf
);
writew
(
*
((
u16
*
)
txbuf
),
qspi
->
base
+
QSPI_SPI_DATA_REG
);
ti_qspi_write
(
qspi
,
cmd
,
QSPI_SPI_CMD_REG
);
ret
=
wait_for_completion_timeout
(
&
qspi
->
transfer_complete
,
QSPI_COMPLETION_TIMEOUT
);
if
(
ret
==
0
)
{
dev_err
(
qspi
->
dev
,
"write timed out
\n
"
);
return
-
ETIMEDOUT
;
}
txbuf
+=
2
;
count
-=
2
;
break
;
case
32
:
dev_dbg
(
qspi
->
dev
,
"tx cmd %08x dc %08x data %08x
\n
"
,
cmd
,
qspi
->
dc
,
*
txbuf
);
writel
(
*
((
u32
*
)
txbuf
),
qspi
->
base
+
QSPI_SPI_DATA_REG
);
ti_qspi_write
(
qspi
,
cmd
,
QSPI_SPI_CMD_REG
);
ret
=
wait_for_completion_timeout
(
&
qspi
->
transfer_complete
,
QSPI_COMPLETION_TIMEOUT
);
if
(
ret
==
0
)
{
dev_err
(
qspi
->
dev
,
"write timed out
\n
"
);
return
-
ETIMEDOUT
;
}
txbuf
+=
4
;
count
-=
4
;
break
;
}
}
return
0
;
}
static
int
qspi_read_msg
(
struct
ti_qspi
*
qspi
,
struct
spi_transfer
*
t
)
{
int
wlen
,
count
,
ret
;
unsigned
int
cmd
;
u8
*
rxbuf
;
rxbuf
=
t
->
rx_buf
;
cmd
=
qspi
->
cmd
;
switch
(
t
->
rx_nbits
)
{
case
SPI_NBITS_DUAL
:
cmd
|=
QSPI_RD_DUAL
;
break
;
case
SPI_NBITS_QUAD
:
cmd
|=
QSPI_RD_QUAD
;
break
;
default:
cmd
|=
QSPI_RD_SNGL
;
break
;
}
count
=
t
->
len
;
wlen
=
t
->
bits_per_word
;
while
(
count
)
{
dev_dbg
(
qspi
->
dev
,
"rx cmd %08x dc %08x
\n
"
,
cmd
,
qspi
->
dc
);
ti_qspi_write
(
qspi
,
cmd
,
QSPI_SPI_CMD_REG
);
ret
=
wait_for_completion_timeout
(
&
qspi
->
transfer_complete
,
QSPI_COMPLETION_TIMEOUT
);
if
(
ret
==
0
)
{
dev_err
(
qspi
->
dev
,
"read timed out
\n
"
);
return
-
ETIMEDOUT
;
}
switch
(
wlen
)
{
case
8
:
*
rxbuf
=
readb
(
qspi
->
base
+
QSPI_SPI_DATA_REG
);
rxbuf
+=
1
;
count
-=
1
;
break
;
case
16
:
*
((
u16
*
)
rxbuf
)
=
readw
(
qspi
->
base
+
QSPI_SPI_DATA_REG
);
rxbuf
+=
2
;
count
-=
2
;
break
;
case
32
:
*
((
u32
*
)
rxbuf
)
=
readl
(
qspi
->
base
+
QSPI_SPI_DATA_REG
);
rxbuf
+=
4
;
count
-=
4
;
break
;
}
}
return
0
;
}
static
int
qspi_transfer_msg
(
struct
ti_qspi
*
qspi
,
struct
spi_transfer
*
t
)
{
int
ret
;
if
(
t
->
tx_buf
)
{
ret
=
qspi_write_msg
(
qspi
,
t
);
if
(
ret
)
{
dev_dbg
(
qspi
->
dev
,
"Error while writing
\n
"
);
return
ret
;
}
}
if
(
t
->
rx_buf
)
{
ret
=
qspi_read_msg
(
qspi
,
t
);
if
(
ret
)
{
dev_dbg
(
qspi
->
dev
,
"Error while reading
\n
"
);
return
ret
;
}
}
return
0
;
}
static
int
ti_qspi_start_transfer_one
(
struct
spi_master
*
master
,
struct
spi_message
*
m
)
{
struct
ti_qspi
*
qspi
=
spi_master_get_devdata
(
master
);
struct
spi_device
*
spi
=
m
->
spi
;
struct
spi_transfer
*
t
;
int
status
=
0
,
ret
;
int
frame_length
;
/* setup device control reg */
qspi
->
dc
=
0
;
if
(
spi
->
mode
&
SPI_CPHA
)
qspi
->
dc
|=
QSPI_CKPHA
(
spi
->
chip_select
);
if
(
spi
->
mode
&
SPI_CPOL
)
qspi
->
dc
|=
QSPI_CKPOL
(
spi
->
chip_select
);
if
(
spi
->
mode
&
SPI_CS_HIGH
)
qspi
->
dc
|=
QSPI_CSPOL
(
spi
->
chip_select
);
frame_length
=
(
m
->
frame_length
<<
3
)
/
spi
->
bits_per_word
;
frame_length
=
clamp
(
frame_length
,
0
,
QSPI_FRAME
);
/* setup command reg */
qspi
->
cmd
=
0
;
qspi
->
cmd
|=
QSPI_EN_CS
(
spi
->
chip_select
);
qspi
->
cmd
|=
QSPI_FLEN
(
frame_length
);
qspi
->
cmd
|=
QSPI_WC_CMD_INT_EN
;
ti_qspi_write
(
qspi
,
QSPI_WC_INT_EN
,
QSPI_INTR_ENABLE_SET_REG
);
ti_qspi_write
(
qspi
,
qspi
->
dc
,
QSPI_SPI_DC_REG
);
mutex_lock
(
&
qspi
->
list_lock
);
list_for_each_entry
(
t
,
&
m
->
transfers
,
transfer_list
)
{
qspi
->
cmd
|=
QSPI_WLEN
(
t
->
bits_per_word
);
ret
=
qspi_transfer_msg
(
qspi
,
t
);
if
(
ret
)
{
dev_dbg
(
qspi
->
dev
,
"transfer message failed
\n
"
);
mutex_unlock
(
&
qspi
->
list_lock
);
return
-
EINVAL
;
}
m
->
actual_length
+=
t
->
len
;
}
mutex_unlock
(
&
qspi
->
list_lock
);
m
->
status
=
status
;
spi_finalize_current_message
(
master
);
ti_qspi_write
(
qspi
,
qspi
->
cmd
|
QSPI_INVAL
,
QSPI_SPI_CMD_REG
);
return
status
;
}
static
irqreturn_t
ti_qspi_isr
(
int
irq
,
void
*
dev_id
)
{
struct
ti_qspi
*
qspi
=
dev_id
;
u16
int_stat
;
irqreturn_t
ret
=
IRQ_HANDLED
;
spin_lock
(
&
qspi
->
lock
);
int_stat
=
ti_qspi_read
(
qspi
,
QSPI_INTR_STATUS_ENABLED_CLEAR
);
qspi
->
stat
=
ti_qspi_read
(
qspi
,
QSPI_SPI_STATUS_REG
);
if
(
!
int_stat
)
{
dev_dbg
(
qspi
->
dev
,
"No IRQ triggered
\n
"
);
ret
=
IRQ_NONE
;
goto
out
;
}
ret
=
IRQ_WAKE_THREAD
;
ti_qspi_write
(
qspi
,
QSPI_WC_INT_DISABLE
,
QSPI_INTR_ENABLE_CLEAR_REG
);
ti_qspi_write
(
qspi
,
QSPI_WC_INT_DISABLE
,
QSPI_INTR_STATUS_ENABLED_CLEAR
);
out:
spin_unlock
(
&
qspi
->
lock
);
return
ret
;
}
static
irqreturn_t
ti_qspi_threaded_isr
(
int
this_irq
,
void
*
dev_id
)
{
struct
ti_qspi
*
qspi
=
dev_id
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
qspi
->
lock
,
flags
);
if
(
qspi
->
stat
&
WC
)
complete
(
&
qspi
->
transfer_complete
);
spin_unlock_irqrestore
(
&
qspi
->
lock
,
flags
);
ti_qspi_write
(
qspi
,
QSPI_WC_INT_EN
,
QSPI_INTR_ENABLE_SET_REG
);
return
IRQ_HANDLED
;
}
static
int
ti_qspi_runtime_resume
(
struct
device
*
dev
)
{
struct
ti_qspi
*
qspi
;
struct
spi_master
*
master
;
master
=
dev_get_drvdata
(
dev
);
qspi
=
spi_master_get_devdata
(
master
);
ti_qspi_restore_ctx
(
qspi
);
return
0
;
}
static
const
struct
of_device_id
ti_qspi_match
[]
=
{
{.
compatible
=
"ti,dra7xxx-qspi"
},
{.
compatible
=
"ti,am4372-qspi"
},
{},
};
MODULE_DEVICE_TABLE
(
of
,
ti_qspi_match
);
static
int
ti_qspi_probe
(
struct
platform_device
*
pdev
)
{
struct
ti_qspi
*
qspi
;
struct
spi_master
*
master
;
struct
resource
*
r
;
struct
device_node
*
np
=
pdev
->
dev
.
of_node
;
u32
max_freq
;
int
ret
=
0
,
num_cs
,
irq
;
master
=
spi_alloc_master
(
&
pdev
->
dev
,
sizeof
(
*
qspi
));
if
(
!
master
)
return
-
ENOMEM
;
master
->
mode_bits
=
SPI_CPOL
|
SPI_CPHA
;
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
);
if
(
!
of_property_read_u32
(
np
,
"num-cs"
,
&
num_cs
))
master
->
num_chipselect
=
num_cs
;
platform_set_drvdata
(
pdev
,
master
);
qspi
=
spi_master_get_devdata
(
master
);
qspi
->
master
=
master
;
qspi
->
dev
=
&
pdev
->
dev
;
r
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
irq
=
platform_get_irq
(
pdev
,
0
);
if
(
irq
<
0
)
{
dev_err
(
&
pdev
->
dev
,
"no irq resource?
\n
"
);
return
irq
;
}
spin_lock_init
(
&
qspi
->
lock
);
mutex_init
(
&
qspi
->
list_lock
);
qspi
->
base
=
devm_ioremap_resource
(
&
pdev
->
dev
,
r
);
if
(
IS_ERR
(
qspi
->
base
))
{
ret
=
PTR_ERR
(
qspi
->
base
);
goto
free_master
;
}
ret
=
devm_request_threaded_irq
(
&
pdev
->
dev
,
irq
,
ti_qspi_isr
,
ti_qspi_threaded_isr
,
0
,
dev_name
(
&
pdev
->
dev
),
qspi
);
if
(
ret
<
0
)
{
dev_err
(
&
pdev
->
dev
,
"Failed to register ISR for IRQ %d
\n
"
,
irq
);
goto
free_master
;
}
qspi
->
fclk
=
devm_clk_get
(
&
pdev
->
dev
,
"fck"
);
if
(
IS_ERR
(
qspi
->
fclk
))
{
ret
=
PTR_ERR
(
qspi
->
fclk
);
dev_err
(
&
pdev
->
dev
,
"could not get clk: %d
\n
"
,
ret
);
}
init_completion
(
&
qspi
->
transfer_complete
);
pm_runtime_use_autosuspend
(
&
pdev
->
dev
);
pm_runtime_set_autosuspend_delay
(
&
pdev
->
dev
,
QSPI_AUTOSUSPEND_TIMEOUT
);
pm_runtime_enable
(
&
pdev
->
dev
);
if
(
!
of_property_read_u32
(
np
,
"spi-max-frequency"
,
&
max_freq
))
qspi
->
spi_max_frequency
=
max_freq
;
ret
=
spi_register_master
(
master
);
if
(
ret
)
goto
free_master
;
return
0
;
free_master:
spi_master_put
(
master
);
return
ret
;
}
static
int
ti_qspi_remove
(
struct
platform_device
*
pdev
)
{
struct
ti_qspi
*
qspi
=
platform_get_drvdata
(
pdev
);
spi_unregister_master
(
qspi
->
master
);
return
0
;
}
static
const
struct
dev_pm_ops
ti_qspi_pm_ops
=
{
.
runtime_resume
=
ti_qspi_runtime_resume
,
};
static
struct
platform_driver
ti_qspi_driver
=
{
.
probe
=
ti_qspi_probe
,
.
remove
=
ti_qspi_remove
,
.
driver
=
{
.
name
=
"ti,dra7xxx-qspi"
,
.
owner
=
THIS_MODULE
,
.
pm
=
&
ti_qspi_pm_ops
,
.
of_match_table
=
ti_qspi_match
,
}
};
module_platform_driver
(
ti_qspi_driver
);
MODULE_AUTHOR
(
"Sourav Poddar <sourav.poddar@ti.com>"
);
MODULE_LICENSE
(
"GPL v2"
);
MODULE_DESCRIPTION
(
"TI QSPI controller driver"
);
drivers/spi/spi.c
View file @
85cac431
...
...
@@ -553,6 +553,10 @@ static void spi_pump_messages(struct kthread_work *work)
master
->
unprepare_transfer_hardware
(
master
))
dev_err
(
&
master
->
dev
,
"failed to unprepare transfer hardware
\n
"
);
if
(
master
->
auto_runtime_pm
)
{
pm_runtime_mark_last_busy
(
master
->
dev
.
parent
);
pm_runtime_put_autosuspend
(
master
->
dev
.
parent
);
}
return
;
}
...
...
@@ -572,11 +576,23 @@ static void spi_pump_messages(struct kthread_work *work)
master
->
busy
=
true
;
spin_unlock_irqrestore
(
&
master
->
queue_lock
,
flags
);
if
(
!
was_busy
&&
master
->
auto_runtime_pm
)
{
ret
=
pm_runtime_get_sync
(
master
->
dev
.
parent
);
if
(
ret
<
0
)
{
dev_err
(
&
master
->
dev
,
"Failed to power device: %d
\n
"
,
ret
);
return
;
}
}
if
(
!
was_busy
&&
master
->
prepare_transfer_hardware
)
{
ret
=
master
->
prepare_transfer_hardware
(
master
);
if
(
ret
)
{
dev_err
(
&
master
->
dev
,
"failed to prepare transfer hardware
\n
"
);
if
(
master
->
auto_runtime_pm
)
pm_runtime_put
(
master
->
dev
.
parent
);
return
;
}
}
...
...
@@ -869,6 +885,51 @@ static void of_register_spi_devices(struct spi_master *master)
if
(
of_find_property
(
nc
,
"spi-3wire"
,
NULL
))
spi
->
mode
|=
SPI_3WIRE
;
/* Device DUAL/QUAD mode */
prop
=
of_get_property
(
nc
,
"spi-tx-nbits"
,
&
len
);
if
(
!
prop
||
len
<
sizeof
(
*
prop
))
{
dev_err
(
&
master
->
dev
,
"%s has no 'spi-tx-nbits' property
\n
"
,
nc
->
full_name
);
spi_dev_put
(
spi
);
continue
;
}
switch
(
be32_to_cpup
(
prop
))
{
case
SPI_NBITS_SINGLE
:
break
;
case
SPI_NBITS_DUAL
:
spi
->
mode
|=
SPI_TX_DUAL
;
break
;
case
SPI_NBITS_QUAD
:
spi
->
mode
|=
SPI_TX_QUAD
;
break
;
default:
dev_err
(
&
master
->
dev
,
"spi-tx-nbits value is not supported
\n
"
);
spi_dev_put
(
spi
);
continue
;
}
prop
=
of_get_property
(
nc
,
"spi-rx-nbits"
,
&
len
);
if
(
!
prop
||
len
<
sizeof
(
*
prop
))
{
dev_err
(
&
master
->
dev
,
"%s has no 'spi-rx-nbits' property
\n
"
,
nc
->
full_name
);
spi_dev_put
(
spi
);
continue
;
}
switch
(
be32_to_cpup
(
prop
))
{
case
SPI_NBITS_SINGLE
:
break
;
case
SPI_NBITS_DUAL
:
spi
->
mode
|=
SPI_RX_DUAL
;
break
;
case
SPI_NBITS_QUAD
:
spi
->
mode
|=
SPI_RX_QUAD
;
break
;
default:
dev_err
(
&
master
->
dev
,
"spi-rx-nbits value is not supported
\n
"
);
spi_dev_put
(
spi
);
continue
;
}
/* Device speed */
prop
=
of_get_property
(
nc
,
"spi-max-frequency"
,
&
len
);
if
(
!
prop
||
len
<
sizeof
(
*
prop
))
{
...
...
@@ -1316,6 +1377,19 @@ int spi_setup(struct spi_device *spi)
unsigned
bad_bits
;
int
status
=
0
;
/* check mode to prevent that DUAL and QUAD set at the same time
*/
if
(((
spi
->
mode
&
SPI_TX_DUAL
)
&&
(
spi
->
mode
&
SPI_TX_QUAD
))
||
((
spi
->
mode
&
SPI_RX_DUAL
)
&&
(
spi
->
mode
&
SPI_RX_QUAD
)))
{
dev_err
(
&
spi
->
dev
,
"setup: can not select dual and quad at the same time
\n
"
);
return
-
EINVAL
;
}
/* if it is SPI_3WIRE mode, DUAL and QUAD should be forbidden
*/
if
((
spi
->
mode
&
SPI_3WIRE
)
&&
(
spi
->
mode
&
(
SPI_TX_DUAL
|
SPI_TX_QUAD
|
SPI_RX_DUAL
|
SPI_RX_QUAD
)))
return
-
EINVAL
;
/* help drivers fail *cleanly* when they need options
* that aren't supported with their current master
*/
...
...
@@ -1378,6 +1452,8 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message)
/**
* Set transfer bits_per_word and max speed as spi device default if
* it is not set for this transfer.
* Set transfer tx_nbits and rx_nbits as single transfer default
* (SPI_NBITS_SINGLE) if it is not set for this transfer.
*/
list_for_each_entry
(
xfer
,
&
message
->
transfers
,
transfer_list
)
{
message
->
frame_length
+=
xfer
->
len
;
...
...
@@ -1404,7 +1480,47 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message)
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
;
if
(
xfer
->
rx_buf
&&
!
xfer
->
rx_nbits
)
xfer
->
rx_nbits
=
SPI_NBITS_SINGLE
;
/* check transfer tx/rx_nbits:
* 1. keep the value is not out of single, dual and quad
* 2. keep tx/rx_nbits is contained by mode in spi_device
* 3. if SPI_3WIRE, tx/rx_nbits should be in single
*/
if
(
xfer
->
tx_buf
)
{
if
(
xfer
->
tx_nbits
!=
SPI_NBITS_SINGLE
&&
xfer
->
tx_nbits
!=
SPI_NBITS_DUAL
&&
xfer
->
tx_nbits
!=
SPI_NBITS_QUAD
)
return
-
EINVAL
;
if
((
xfer
->
tx_nbits
==
SPI_NBITS_DUAL
)
&&
!
(
spi
->
mode
&
(
SPI_TX_DUAL
|
SPI_TX_QUAD
)))
return
-
EINVAL
;
if
((
xfer
->
tx_nbits
==
SPI_NBITS_QUAD
)
&&
!
(
spi
->
mode
&
SPI_TX_QUAD
))
return
-
EINVAL
;
if
((
spi
->
mode
&
SPI_3WIRE
)
&&
(
xfer
->
tx_nbits
!=
SPI_NBITS_SINGLE
))
return
-
EINVAL
;
}
/* check transfer rx_nbits */
if
(
xfer
->
rx_buf
)
{
if
(
xfer
->
rx_nbits
!=
SPI_NBITS_SINGLE
&&
xfer
->
rx_nbits
!=
SPI_NBITS_DUAL
&&
xfer
->
rx_nbits
!=
SPI_NBITS_QUAD
)
return
-
EINVAL
;
if
((
xfer
->
rx_nbits
==
SPI_NBITS_DUAL
)
&&
!
(
spi
->
mode
&
(
SPI_RX_DUAL
|
SPI_RX_QUAD
)))
return
-
EINVAL
;
if
((
xfer
->
rx_nbits
==
SPI_NBITS_QUAD
)
&&
!
(
spi
->
mode
&
SPI_RX_QUAD
))
return
-
EINVAL
;
if
((
spi
->
mode
&
SPI_3WIRE
)
&&
(
xfer
->
rx_nbits
!=
SPI_NBITS_SINGLE
))
return
-
EINVAL
;
}
}
message
->
spi
=
spi
;
...
...
include/linux/spi/spi.h
View file @
85cac431
...
...
@@ -74,7 +74,7 @@ struct spi_device {
struct
spi_master
*
master
;
u32
max_speed_hz
;
u8
chip_select
;
u
8
mode
;
u
16
mode
;
#define SPI_CPHA 0x01
/* clock phase */
#define SPI_CPOL 0x02
/* clock polarity */
#define SPI_MODE_0 (0|0)
/* (original MicroWire) */
...
...
@@ -87,6 +87,10 @@ struct spi_device {
#define SPI_LOOP 0x20
/* loopback mode */
#define SPI_NO_CS 0x40
/* 1 dev/bus, no chipselect */
#define SPI_READY 0x80
/* slave pulls low to pause */
#define SPI_TX_DUAL 0x100
/* transmit with 2 wires */
#define SPI_TX_QUAD 0x200
/* transmit with 4 wires */
#define SPI_RX_DUAL 0x400
/* receive with 2 wires */
#define SPI_RX_QUAD 0x800
/* receive with 4 wires */
u8
bits_per_word
;
int
irq
;
void
*
controller_state
;
...
...
@@ -256,6 +260,9 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
* @busy: message pump is busy
* @running: message pump is running
* @rt: whether this queue is set to run as a realtime task
* @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
* @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
...
...
@@ -380,11 +387,13 @@ struct spi_master {
bool
busy
;
bool
running
;
bool
rt
;
bool
auto_runtime_pm
;
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
);
/* gpio chip select */
int
*
cs_gpios
;
};
...
...
@@ -454,6 +463,10 @@ extern struct spi_master *spi_busnum_to_master(u16 busnum);
* @rx_buf: data to be read (dma-safe memory), or NULL
* @tx_dma: DMA address of tx_buf, if @spi_message.is_dma_mapped
* @rx_dma: DMA address of rx_buf, if @spi_message.is_dma_mapped
* @tx_nbits: number of bits used for writting. If 0 the default
* (SPI_NBITS_SINGLE) is used.
* @rx_nbits: number of bits used for reading. If 0 the default
* (SPI_NBITS_SINGLE) is used.
* @len: size of rx and tx buffers (in bytes)
* @speed_hz: Select a speed other than the device default for this
* transfer. If 0 the default (from @spi_device) is used.
...
...
@@ -508,6 +521,11 @@ extern struct spi_master *spi_busnum_to_master(u16 busnum);
* by the results of previous messages and where the whole transaction
* ends when the chipselect goes intactive.
*
* When SPI can transfer in 1x,2x or 4x. It can get this tranfer information
* from device through @tx_nbits and @rx_nbits. In Bi-direction, these
* two should both be set. User can set transfer mode with SPI_NBITS_SINGLE(1x)
* SPI_NBITS_DUAL(2x) and SPI_NBITS_QUAD(4x) to support these three transfer.
*
* The code that submits an spi_message (and its spi_transfers)
* to the lower layers is responsible for managing its memory.
* Zero-initialize every field you don't set up explicitly, to
...
...
@@ -528,6 +546,11 @@ struct spi_transfer {
dma_addr_t
rx_dma
;
unsigned
cs_change
:
1
;
u8
tx_nbits
;
u8
rx_nbits
;
#define SPI_NBITS_SINGLE 0x01
/* 1bit transfer */
#define SPI_NBITS_DUAL 0x02
/* 2bits transfer */
#define SPI_NBITS_QUAD 0x04
/* 4bits transfer */
u8
bits_per_word
;
u16
delay_usecs
;
u32
speed_hz
;
...
...
@@ -876,7 +899,7 @@ struct spi_board_info {
/* mode becomes spi_device.mode, and is essential for chips
* where the default of SPI_CS_HIGH = 0 is wrong.
*/
u
8
mode
;
u
16
mode
;
/* ... may need additional spi_device chip config data here.
* avoid stuff protocol drivers can set; but include stuff
...
...
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