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
1728ddb2
Commit
1728ddb2
authored
Jun 26, 2013
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'spi/topic/omap' into spi-next
parents
13a62169
0b9e49e6
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
213 additions
and
51 deletions
+213
-51
Documentation/devicetree/bindings/spi/omap-spi.txt
Documentation/devicetree/bindings/spi/omap-spi.txt
+26
-1
drivers/spi/spi-omap2-mcspi.c
drivers/spi/spi-omap2-mcspi.c
+187
-50
No files found.
Documentation/devicetree/bindings/spi/omap-spi.txt
View file @
1728ddb2
...
...
@@ -10,7 +10,18 @@ Required properties:
input. The default is D0 as input and
D1 as output.
Example:
Optional properties:
- dmas: List of DMA specifiers with the controller specific format
as described in the generic DMA client binding. A tx and rx
specifier is required for each chip select.
- dma-names: List of DMA request names. These strings correspond
1:1 with the DMA specifiers listed in dmas. The string naming
is to be "rxN" and "txN" for RX and TX requests,
respectively, where N equals the chip select number.
Examples:
[hwmod populated DMA resources]
mcspi1: mcspi@1 {
#address-cells = <1>;
...
...
@@ -20,3 +31,17 @@ mcspi1: mcspi@1 {
ti,spi-num-cs = <4>;
};
[generic DMA request binding]
mcspi1: mcspi@1 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "ti,omap4-mcspi";
ti,hwmods = "mcspi1";
ti,spi-num-cs = <2>;
dmas = <&edma 42
&edma 43
&edma 44
&edma 45>;
dma-names = "tx0", "rx0", "tx1", "rx1";
};
drivers/spi/spi-omap2-mcspi.c
View file @
1728ddb2
...
...
@@ -38,13 +38,15 @@
#include <linux/pm_runtime.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/
pinctrl/consumer
.h>
#include <linux/
gcd
.h>
#include <linux/spi/spi.h>
#include <linux/platform_data/spi-omap2-mcspi.h>
#define OMAP2_MCSPI_MAX_FREQ 48000000
#define OMAP2_MCSPI_MAX_FIFODEPTH 64
#define OMAP2_MCSPI_MAX_FIFOWCNT 0xFFFF
#define SPI_AUTOSUSPEND_TIMEOUT 2000
#define OMAP2_MCSPI_REVISION 0x00
...
...
@@ -54,6 +56,7 @@
#define OMAP2_MCSPI_WAKEUPENABLE 0x20
#define OMAP2_MCSPI_SYST 0x24
#define OMAP2_MCSPI_MODULCTRL 0x28
#define OMAP2_MCSPI_XFERLEVEL 0x7c
/* per-channel banks, 0x14 bytes each, first is: */
#define OMAP2_MCSPI_CHCONF0 0x2c
...
...
@@ -63,6 +66,7 @@
#define OMAP2_MCSPI_RX0 0x3c
/* per-register bitmasks: */
#define OMAP2_MCSPI_IRQSTATUS_EOW BIT(17)
#define OMAP2_MCSPI_MODULCTRL_SINGLE BIT(0)
#define OMAP2_MCSPI_MODULCTRL_MS BIT(2)
...
...
@@ -83,10 +87,13 @@
#define OMAP2_MCSPI_CHCONF_IS BIT(18)
#define OMAP2_MCSPI_CHCONF_TURBO BIT(19)
#define OMAP2_MCSPI_CHCONF_FORCE BIT(20)
#define OMAP2_MCSPI_CHCONF_FFET BIT(27)
#define OMAP2_MCSPI_CHCONF_FFER BIT(28)
#define OMAP2_MCSPI_CHSTAT_RXS BIT(0)
#define OMAP2_MCSPI_CHSTAT_TXS BIT(1)
#define OMAP2_MCSPI_CHSTAT_EOT BIT(2)
#define OMAP2_MCSPI_CHSTAT_TXFFE BIT(3)
#define OMAP2_MCSPI_CHCTRL_EN BIT(0)
...
...
@@ -102,6 +109,9 @@ struct omap2_mcspi_dma {
struct
completion
dma_tx_completion
;
struct
completion
dma_rx_completion
;
char
dma_rx_ch_name
[
14
];
char
dma_tx_ch_name
[
14
];
};
/* use PIO for small transfers, avoiding DMA setup/teardown overhead and
...
...
@@ -129,6 +139,7 @@ struct omap2_mcspi {
struct
omap2_mcspi_dma
*
dma_channels
;
struct
device
*
dev
;
struct
omap2_mcspi_regs
ctx
;
int
fifo_depth
;
unsigned
int
pin_dir
:
1
;
};
...
...
@@ -187,6 +198,16 @@ static inline void mcspi_write_chconf0(const struct spi_device *spi, u32 val)
mcspi_read_cs_reg
(
spi
,
OMAP2_MCSPI_CHCONF0
);
}
static
inline
int
mcspi_bytes_per_word
(
int
word_len
)
{
if
(
word_len
<=
8
)
return
1
;
else
if
(
word_len
<=
16
)
return
2
;
else
/* word_len <= 32 */
return
4
;
}
static
void
omap2_mcspi_set_dma_req
(
const
struct
spi_device
*
spi
,
int
is_read
,
int
enable
)
{
...
...
@@ -248,6 +269,58 @@ static void omap2_mcspi_set_master_mode(struct spi_master *master)
ctx
->
modulctrl
=
l
;
}
static
void
omap2_mcspi_set_fifo
(
const
struct
spi_device
*
spi
,
struct
spi_transfer
*
t
,
int
enable
)
{
struct
spi_master
*
master
=
spi
->
master
;
struct
omap2_mcspi_cs
*
cs
=
spi
->
controller_state
;
struct
omap2_mcspi
*
mcspi
;
unsigned
int
wcnt
;
int
fifo_depth
,
bytes_per_word
;
u32
chconf
,
xferlevel
;
mcspi
=
spi_master_get_devdata
(
master
);
chconf
=
mcspi_cached_chconf0
(
spi
);
if
(
enable
)
{
bytes_per_word
=
mcspi_bytes_per_word
(
cs
->
word_len
);
if
(
t
->
len
%
bytes_per_word
!=
0
)
goto
disable_fifo
;
fifo_depth
=
gcd
(
t
->
len
,
OMAP2_MCSPI_MAX_FIFODEPTH
);
if
(
fifo_depth
<
2
||
fifo_depth
%
bytes_per_word
!=
0
)
goto
disable_fifo
;
wcnt
=
t
->
len
/
bytes_per_word
;
if
(
wcnt
>
OMAP2_MCSPI_MAX_FIFOWCNT
)
goto
disable_fifo
;
xferlevel
=
wcnt
<<
16
;
if
(
t
->
rx_buf
!=
NULL
)
{
chconf
|=
OMAP2_MCSPI_CHCONF_FFER
;
xferlevel
|=
(
fifo_depth
-
1
)
<<
8
;
}
else
{
chconf
|=
OMAP2_MCSPI_CHCONF_FFET
;
xferlevel
|=
fifo_depth
-
1
;
}
mcspi_write_reg
(
master
,
OMAP2_MCSPI_XFERLEVEL
,
xferlevel
);
mcspi_write_chconf0
(
spi
,
chconf
);
mcspi
->
fifo_depth
=
fifo_depth
;
return
;
}
disable_fifo:
if
(
t
->
rx_buf
!=
NULL
)
chconf
&=
~
OMAP2_MCSPI_CHCONF_FFER
;
else
chconf
&=
~
OMAP2_MCSPI_CHCONF_FFET
;
mcspi_write_chconf0
(
spi
,
chconf
);
mcspi
->
fifo_depth
=
0
;
}
static
void
omap2_mcspi_restore_ctx
(
struct
omap2_mcspi
*
mcspi
)
{
struct
spi_master
*
spi_cntrl
=
mcspi
->
master
;
...
...
@@ -364,7 +437,7 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
{
struct
omap2_mcspi
*
mcspi
;
struct
omap2_mcspi_dma
*
mcspi_dma
;
unsigned
int
count
;
unsigned
int
count
,
dma_count
;
u32
l
;
int
elements
=
0
;
int
word_len
,
element_count
;
...
...
@@ -372,6 +445,11 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
mcspi
=
spi_master_get_devdata
(
spi
->
master
);
mcspi_dma
=
&
mcspi
->
dma_channels
[
spi
->
chip_select
];
count
=
xfer
->
len
;
dma_count
=
xfer
->
len
;
if
(
mcspi
->
fifo_depth
==
0
)
dma_count
-=
es
;
word_len
=
cs
->
word_len
;
l
=
mcspi_cached_chconf0
(
spi
);
...
...
@@ -385,16 +463,15 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
if
(
mcspi_dma
->
dma_rx
)
{
struct
dma_async_tx_descriptor
*
tx
;
struct
scatterlist
sg
;
size_t
len
=
xfer
->
len
-
es
;
dmaengine_slave_config
(
mcspi_dma
->
dma_rx
,
&
cfg
);
if
(
l
&
OMAP2_MCSPI_CHCONF_TURBO
)
len
-=
es
;
if
(
(
l
&
OMAP2_MCSPI_CHCONF_TURBO
)
&&
mcspi
->
fifo_depth
==
0
)
dma_count
-=
es
;
sg_init_table
(
&
sg
,
1
);
sg_dma_address
(
&
sg
)
=
xfer
->
rx_dma
;
sg_dma_len
(
&
sg
)
=
len
;
sg_dma_len
(
&
sg
)
=
dma_count
;
tx
=
dmaengine_prep_slave_sg
(
mcspi_dma
->
dma_rx
,
&
sg
,
1
,
DMA_DEV_TO_MEM
,
DMA_PREP_INTERRUPT
|
...
...
@@ -414,6 +491,10 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
wait_for_completion
(
&
mcspi_dma
->
dma_rx_completion
);
dma_unmap_single
(
mcspi
->
dev
,
xfer
->
rx_dma
,
count
,
DMA_FROM_DEVICE
);
if
(
mcspi
->
fifo_depth
>
0
)
return
count
;
omap2_mcspi_set_enable
(
spi
,
0
);
elements
=
element_count
-
1
;
...
...
@@ -433,10 +514,9 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
else
/* word_len <= 32 */
((
u32
*
)
xfer
->
rx_buf
)[
elements
++
]
=
w
;
}
else
{
int
bytes_per_word
=
mcspi_bytes_per_word
(
word_len
);
dev_err
(
&
spi
->
dev
,
"DMA RX penultimate word empty"
);
count
-=
(
word_len
<=
8
)
?
2
:
(
word_len
<=
16
)
?
4
:
/* word_len <= 32 */
8
;
count
-=
(
bytes_per_word
<<
1
);
omap2_mcspi_set_enable
(
spi
,
1
);
return
count
;
}
...
...
@@ -454,9 +534,7 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
((
u32
*
)
xfer
->
rx_buf
)[
elements
]
=
w
;
}
else
{
dev_err
(
&
spi
->
dev
,
"DMA RX last word empty"
);
count
-=
(
word_len
<=
8
)
?
1
:
(
word_len
<=
16
)
?
2
:
/* word_len <= 32 */
4
;
count
-=
mcspi_bytes_per_word
(
word_len
);
}
omap2_mcspi_set_enable
(
spi
,
1
);
return
count
;
...
...
@@ -475,7 +553,10 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
struct
dma_slave_config
cfg
;
enum
dma_slave_buswidth
width
;
unsigned
es
;
u32
burst
;
void
__iomem
*
chstat_reg
;
void
__iomem
*
irqstat_reg
;
int
wait_res
;
mcspi
=
spi_master_get_devdata
(
spi
->
master
);
mcspi_dma
=
&
mcspi
->
dma_channels
[
spi
->
chip_select
];
...
...
@@ -493,19 +574,27 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
es
=
4
;
}
count
=
xfer
->
len
;
burst
=
1
;
if
(
mcspi
->
fifo_depth
>
0
)
{
if
(
count
>
mcspi
->
fifo_depth
)
burst
=
mcspi
->
fifo_depth
/
es
;
else
burst
=
count
/
es
;
}
memset
(
&
cfg
,
0
,
sizeof
(
cfg
));
cfg
.
src_addr
=
cs
->
phys
+
OMAP2_MCSPI_RX0
;
cfg
.
dst_addr
=
cs
->
phys
+
OMAP2_MCSPI_TX0
;
cfg
.
src_addr_width
=
width
;
cfg
.
dst_addr_width
=
width
;
cfg
.
src_maxburst
=
1
;
cfg
.
dst_maxburst
=
1
;
cfg
.
src_maxburst
=
burst
;
cfg
.
dst_maxburst
=
burst
;
rx
=
xfer
->
rx_buf
;
tx
=
xfer
->
tx_buf
;
count
=
xfer
->
len
;
if
(
tx
!=
NULL
)
omap2_mcspi_tx_dma
(
spi
,
xfer
,
cfg
);
...
...
@@ -513,18 +602,38 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
count
=
omap2_mcspi_rx_dma
(
spi
,
xfer
,
cfg
,
es
);
if
(
tx
!=
NULL
)
{
chstat_reg
=
cs
->
base
+
OMAP2_MCSPI_CHSTAT0
;
wait_for_completion
(
&
mcspi_dma
->
dma_tx_completion
);
dma_unmap_single
(
mcspi
->
dev
,
xfer
->
tx_dma
,
xfer
->
len
,
DMA_TO_DEVICE
);
if
(
mcspi
->
fifo_depth
>
0
)
{
irqstat_reg
=
mcspi
->
base
+
OMAP2_MCSPI_IRQSTATUS
;
if
(
mcspi_wait_for_reg_bit
(
irqstat_reg
,
OMAP2_MCSPI_IRQSTATUS_EOW
)
<
0
)
dev_err
(
&
spi
->
dev
,
"EOW timed out
\n
"
);
mcspi_write_reg
(
mcspi
->
master
,
OMAP2_MCSPI_IRQSTATUS
,
OMAP2_MCSPI_IRQSTATUS_EOW
);
}
/* for TX_ONLY mode, be sure all words have shifted out */
if
(
rx
==
NULL
)
{
if
(
mcspi_wait_for_reg_bit
(
chstat_reg
,
OMAP2_MCSPI_CHSTAT_TXS
)
<
0
)
dev_err
(
&
spi
->
dev
,
"TXS timed out
\n
"
);
else
if
(
mcspi_wait_for_reg_bit
(
chstat_reg
,
OMAP2_MCSPI_CHSTAT_EOT
)
<
0
)
chstat_reg
=
cs
->
base
+
OMAP2_MCSPI_CHSTAT0
;
if
(
mcspi
->
fifo_depth
>
0
)
{
wait_res
=
mcspi_wait_for_reg_bit
(
chstat_reg
,
OMAP2_MCSPI_CHSTAT_TXFFE
);
if
(
wait_res
<
0
)
dev_err
(
&
spi
->
dev
,
"TXFFE timed out
\n
"
);
}
else
{
wait_res
=
mcspi_wait_for_reg_bit
(
chstat_reg
,
OMAP2_MCSPI_CHSTAT_TXS
);
if
(
wait_res
<
0
)
dev_err
(
&
spi
->
dev
,
"TXS timed out
\n
"
);
}
if
(
wait_res
>=
0
&&
(
mcspi_wait_for_reg_bit
(
chstat_reg
,
OMAP2_MCSPI_CHSTAT_EOT
)
<
0
))
dev_err
(
&
spi
->
dev
,
"EOT timed out
\n
"
);
}
}
...
...
@@ -830,12 +939,20 @@ static int omap2_mcspi_request_dma(struct spi_device *spi)
dma_cap_zero
(
mask
);
dma_cap_set
(
DMA_SLAVE
,
mask
);
sig
=
mcspi_dma
->
dma_rx_sync_dev
;
mcspi_dma
->
dma_rx
=
dma_request_channel
(
mask
,
omap_dma_filter_fn
,
&
sig
);
mcspi_dma
->
dma_rx
=
dma_request_slave_channel_compat
(
mask
,
omap_dma_filter_fn
,
&
sig
,
&
master
->
dev
,
mcspi_dma
->
dma_rx_ch_name
);
if
(
!
mcspi_dma
->
dma_rx
)
goto
no_dma
;
sig
=
mcspi_dma
->
dma_tx_sync_dev
;
mcspi_dma
->
dma_tx
=
dma_request_channel
(
mask
,
omap_dma_filter_fn
,
&
sig
);
mcspi_dma
->
dma_tx
=
dma_request_slave_channel_compat
(
mask
,
omap_dma_filter_fn
,
&
sig
,
&
master
->
dev
,
mcspi_dma
->
dma_tx_ch_name
);
if
(
!
mcspi_dma
->
dma_tx
)
{
dma_release_channel
(
mcspi_dma
->
dma_rx
);
mcspi_dma
->
dma_rx
=
NULL
;
...
...
@@ -945,7 +1062,7 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
cs
=
spi
->
controller_state
;
cd
=
spi
->
controller_data
;
omap2_mcspi_set_enable
(
spi
,
1
);
omap2_mcspi_set_enable
(
spi
,
0
);
list_for_each_entry
(
t
,
&
m
->
transfers
,
transfer_list
)
{
if
(
t
->
tx_buf
==
NULL
&&
t
->
rx_buf
==
NULL
&&
t
->
len
)
{
status
=
-
EINVAL
;
...
...
@@ -993,6 +1110,12 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
if
(
t
->
len
)
{
unsigned
count
;
if
((
mcspi_dma
->
dma_rx
&&
mcspi_dma
->
dma_tx
)
&&
(
m
->
is_dma_mapped
||
t
->
len
>=
DMA_MIN_BYTES
))
omap2_mcspi_set_fifo
(
spi
,
t
,
1
);
omap2_mcspi_set_enable
(
spi
,
1
);
/* RX_ONLY mode needs dummy data in TX reg */
if
(
t
->
tx_buf
==
NULL
)
__raw_writel
(
0
,
cs
->
base
...
...
@@ -1019,6 +1142,11 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
omap2_mcspi_force_cs
(
spi
,
0
);
cs_active
=
0
;
}
omap2_mcspi_set_enable
(
spi
,
0
);
if
(
mcspi
->
fifo_depth
>
0
)
omap2_mcspi_set_fifo
(
spi
,
t
,
0
);
}
/* Restore defaults if they were overriden */
if
(
par_override
)
{
...
...
@@ -1039,8 +1167,10 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
omap2_mcspi_set_enable
(
spi
,
0
);
m
->
status
=
status
;
if
(
mcspi
->
fifo_depth
>
0
&&
t
)
omap2_mcspi_set_fifo
(
spi
,
t
,
0
);
m
->
status
=
status
;
}
static
int
omap2_mcspi_transfer_one_message
(
struct
spi_master
*
master
,
...
...
@@ -1177,7 +1307,6 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
static
int
bus_num
=
1
;
struct
device_node
*
node
=
pdev
->
dev
.
of_node
;
const
struct
of_device_id
*
match
;
struct
pinctrl
*
pinctrl
;
master
=
spi_alloc_master
(
&
pdev
->
dev
,
sizeof
*
mcspi
);
if
(
master
==
NULL
)
{
...
...
@@ -1247,39 +1376,47 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
goto
free_master
;
for
(
i
=
0
;
i
<
master
->
num_chipselect
;
i
++
)
{
char
dma_ch_name
[
14
];
char
*
dma_rx_ch_name
=
mcspi
->
dma_channels
[
i
].
dma_rx_ch_name
;
char
*
dma_tx_ch_name
=
mcspi
->
dma_channels
[
i
].
dma_tx_ch_name
;
struct
resource
*
dma_res
;
sprintf
(
dma_ch_name
,
"rx%d"
,
i
);
dma_res
=
platform_get_resource_byname
(
pdev
,
IORESOURCE_DMA
,
dma_ch_name
);
if
(
!
dma_res
)
{
dev_dbg
(
&
pdev
->
dev
,
"cannot get DMA RX channel
\n
"
);
status
=
-
ENODEV
;
break
;
}
sprintf
(
dma_rx_ch_name
,
"rx%d"
,
i
);
if
(
!
pdev
->
dev
.
of_node
)
{
dma_res
=
platform_get_resource_byname
(
pdev
,
IORESOURCE_DMA
,
dma_rx_ch_name
);
if
(
!
dma_res
)
{
dev_dbg
(
&
pdev
->
dev
,
"cannot get DMA RX channel
\n
"
);
status
=
-
ENODEV
;
break
;
}
mcspi
->
dma_channels
[
i
].
dma_rx_sync_dev
=
dma_res
->
start
;
sprintf
(
dma_ch_name
,
"tx%d"
,
i
);
dma_res
=
platform_get_resource_byname
(
pdev
,
IORESOURCE_DMA
,
dma_ch_name
);
if
(
!
dma_res
)
{
dev_dbg
(
&
pdev
->
dev
,
"cannot get DMA TX channel
\n
"
);
status
=
-
ENODEV
;
break
;
mcspi
->
dma_channels
[
i
].
dma_rx_sync_dev
=
dma_res
->
start
;
}
sprintf
(
dma_tx_ch_name
,
"tx%d"
,
i
);
if
(
!
pdev
->
dev
.
of_node
)
{
dma_res
=
platform_get_resource_byname
(
pdev
,
IORESOURCE_DMA
,
dma_tx_ch_name
);
if
(
!
dma_res
)
{
dev_dbg
(
&
pdev
->
dev
,
"cannot get DMA TX channel
\n
"
);
status
=
-
ENODEV
;
break
;
}
mcspi
->
dma_channels
[
i
].
dma_tx_sync_dev
=
dma_res
->
start
;
mcspi
->
dma_channels
[
i
].
dma_tx_sync_dev
=
dma_res
->
start
;
}
}
if
(
status
<
0
)
goto
dma_chnl_free
;
pinctrl
=
devm_pinctrl_get_select_default
(
&
pdev
->
dev
);
if
(
IS_ERR
(
pinctrl
))
dev_warn
(
&
pdev
->
dev
,
"pins are not configured from the driver
\n
"
);
pm_runtime_use_autosuspend
(
&
pdev
->
dev
);
pm_runtime_set_autosuspend_delay
(
&
pdev
->
dev
,
SPI_AUTOSUSPEND_TIMEOUT
);
pm_runtime_enable
(
&
pdev
->
dev
);
...
...
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