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
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
Show 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
)
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
"
);
else
if
(
mcspi_wait_for_reg_bit
(
chstat_reg
,
OMAP2_MCSPI_CHSTAT_EOT
)
<
0
)
}
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
);
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
"
);
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
);
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
"
);
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