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
6c99db1e
Commit
6c99db1e
authored
Oct 25, 2013
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'spi/topic/mxs' into spi-next
parents
8211e6b8
42e182f8
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
80 additions
and
109 deletions
+80
-109
drivers/spi/spi-mxs.c
drivers/spi/spi-mxs.c
+80
-109
No files found.
drivers/spi/spi-mxs.c
View file @
6c99db1e
...
...
@@ -57,34 +57,53 @@
#define SG_MAXLEN 0xff00
/*
* Flags for txrx functions. More efficient that using an argument register for
* each one.
*/
#define TXRX_WRITE (1<<0)
/* This is a write */
#define TXRX_DEASSERT_CS (1<<1)
/* De-assert CS at end of txrx */
struct
mxs_spi
{
struct
mxs_ssp
ssp
;
struct
completion
c
;
unsigned
int
sck
;
/* Rate requested (vs actual) */
};
static
int
mxs_spi_setup_transfer
(
struct
spi_device
*
dev
,
struct
spi_transfer
*
t
)
const
struct
spi_transfer
*
t
)
{
struct
mxs_spi
*
spi
=
spi_master_get_devdata
(
dev
->
master
);
struct
mxs_ssp
*
ssp
=
&
spi
->
ssp
;
uint32_t
hz
=
0
;
const
unsigned
int
hz
=
min
(
dev
->
max_speed_hz
,
t
->
speed_hz
)
;
hz
=
dev
->
max_speed_hz
;
if
(
t
&&
t
->
speed_hz
)
hz
=
min
(
hz
,
t
->
speed_hz
);
if
(
hz
==
0
)
{
dev_err
(
&
dev
->
dev
,
"
Cannot continue with zero clock
\n
"
);
dev_err
(
&
dev
->
dev
,
"
SPI clock rate of zero not allowed
\n
"
);
return
-
EINVAL
;
}
mxs_ssp_set_clk_rate
(
ssp
,
hz
);
if
(
hz
!=
spi
->
sck
)
{
mxs_ssp_set_clk_rate
(
ssp
,
hz
);
/*
* Save requested rate, hz, rather than the actual rate,
* ssp->clk_rate. Otherwise we would set the rate every trasfer
* when the actual rate is not quite the same as requested rate.
*/
spi
->
sck
=
hz
;
/*
* Perhaps we should return an error if the actual clock is
* nowhere close to what was requested?
*/
}
writel
(
BM_SSP_CTRL0_LOCK_CS
,
ssp
->
base
+
HW_SSP_CTRL0
+
STMP_OFFSET_REG_SET
);
writel
(
BF_SSP_CTRL1_SSP_MODE
(
BV_SSP_CTRL1_SSP_MODE__SPI
)
|
BF_SSP_CTRL1_WORD_LENGTH
(
BV_SSP_CTRL1_WORD_LENGTH__EIGHT_BITS
)
|
((
dev
->
mode
&
SPI_CPOL
)
?
BM_SSP_CTRL1_POLARITY
:
0
)
|
((
dev
->
mode
&
SPI_CPHA
)
?
BM_SSP_CTRL1_PHASE
:
0
),
ssp
->
base
+
HW_SSP_CTRL1
(
ssp
));
BF_SSP_CTRL1_WORD_LENGTH
(
BV_SSP_CTRL1_WORD_LENGTH__EIGHT_BITS
)
|
((
dev
->
mode
&
SPI_CPOL
)
?
BM_SSP_CTRL1_POLARITY
:
0
)
|
((
dev
->
mode
&
SPI_CPHA
)
?
BM_SSP_CTRL1_PHASE
:
0
),
ssp
->
base
+
HW_SSP_CTRL1
(
ssp
));
writel
(
0x0
,
ssp
->
base
+
HW_SSP_CMD0
);
writel
(
0x0
,
ssp
->
base
+
HW_SSP_CMD1
);
...
...
@@ -94,26 +113,15 @@ static int mxs_spi_setup_transfer(struct spi_device *dev,
static
int
mxs_spi_setup
(
struct
spi_device
*
dev
)
{
int
err
=
0
;
if
(
!
dev
->
bits_per_word
)
dev
->
bits_per_word
=
8
;
if
(
dev
->
mode
&
~
(
SPI_CPOL
|
SPI_CPHA
))
return
-
EINVAL
;
err
=
mxs_spi_setup_transfer
(
dev
,
NULL
);
if
(
err
)
{
dev_err
(
&
dev
->
dev
,
"Failed to setup transfer, error = %d
\n
"
,
err
);
}
return
err
;
return
0
;
}
static
u
int32_t
mxs_spi_cs_to_reg
(
unsigned
cs
)
static
u
32
mxs_spi_cs_to_reg
(
unsigned
cs
)
{
u
int32_t
select
=
0
;
u
32
select
=
0
;
/*
* i.MX28 Datasheet: 17.10.1: HW_SSP_CTRL0
...
...
@@ -131,43 +139,11 @@ static uint32_t mxs_spi_cs_to_reg(unsigned cs)
return
select
;
}
static
void
mxs_spi_set_cs
(
struct
mxs_spi
*
spi
,
unsigned
cs
)
{
const
uint32_t
mask
=
BM_SSP_CTRL0_WAIT_FOR_CMD
|
BM_SSP_CTRL0_WAIT_FOR_IRQ
;
uint32_t
select
;
struct
mxs_ssp
*
ssp
=
&
spi
->
ssp
;
writel
(
mask
,
ssp
->
base
+
HW_SSP_CTRL0
+
STMP_OFFSET_REG_CLR
);
select
=
mxs_spi_cs_to_reg
(
cs
);
writel
(
select
,
ssp
->
base
+
HW_SSP_CTRL0
+
STMP_OFFSET_REG_SET
);
}
static
inline
void
mxs_spi_enable
(
struct
mxs_spi
*
spi
)
{
struct
mxs_ssp
*
ssp
=
&
spi
->
ssp
;
writel
(
BM_SSP_CTRL0_LOCK_CS
,
ssp
->
base
+
HW_SSP_CTRL0
+
STMP_OFFSET_REG_SET
);
writel
(
BM_SSP_CTRL0_IGNORE_CRC
,
ssp
->
base
+
HW_SSP_CTRL0
+
STMP_OFFSET_REG_CLR
);
}
static
inline
void
mxs_spi_disable
(
struct
mxs_spi
*
spi
)
{
struct
mxs_ssp
*
ssp
=
&
spi
->
ssp
;
writel
(
BM_SSP_CTRL0_LOCK_CS
,
ssp
->
base
+
HW_SSP_CTRL0
+
STMP_OFFSET_REG_CLR
);
writel
(
BM_SSP_CTRL0_IGNORE_CRC
,
ssp
->
base
+
HW_SSP_CTRL0
+
STMP_OFFSET_REG_SET
);
}
static
int
mxs_ssp_wait
(
struct
mxs_spi
*
spi
,
int
offset
,
int
mask
,
bool
set
)
{
const
unsigned
long
timeout
=
jiffies
+
msecs_to_jiffies
(
SSP_TIMEOUT
);
struct
mxs_ssp
*
ssp
=
&
spi
->
ssp
;
u
int32_t
reg
;
u
32
reg
;
do
{
reg
=
readl_relaxed
(
ssp
->
base
+
offset
);
...
...
@@ -200,9 +176,9 @@ static irqreturn_t mxs_ssp_irq_handler(int irq, void *dev_id)
return
IRQ_HANDLED
;
}
static
int
mxs_spi_txrx_dma
(
struct
mxs_spi
*
spi
,
int
cs
,
static
int
mxs_spi_txrx_dma
(
struct
mxs_spi
*
spi
,
unsigned
char
*
buf
,
int
len
,
int
*
first
,
int
*
last
,
int
write
)
unsigned
int
flags
)
{
struct
mxs_ssp
*
ssp
=
&
spi
->
ssp
;
struct
dma_async_tx_descriptor
*
desc
=
NULL
;
...
...
@@ -211,11 +187,11 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, int cs,
const
int
sgs
=
DIV_ROUND_UP
(
len
,
desc_len
);
int
sg_count
;
int
min
,
ret
;
u
int32_t
ctrl0
;
u
32
ctrl0
;
struct
page
*
vm_page
;
void
*
sg_buf
;
struct
{
u
int32_t
pio
[
4
];
u
32
pio
[
4
];
struct
scatterlist
sg
;
}
*
dma_xfer
;
...
...
@@ -228,21 +204,25 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, int cs,
INIT_COMPLETION
(
spi
->
c
);
/* Chip select was already programmed into CTRL0 */
ctrl0
=
readl
(
ssp
->
base
+
HW_SSP_CTRL0
);
ctrl0
&=
~
BM_SSP_CTRL0_XFER_COUNT
;
ctrl0
|=
BM_SSP_CTRL0_DATA_XFER
|
mxs_spi_cs_to_reg
(
cs
);
ctrl0
&=
~
(
BM_SSP_CTRL0_XFER_COUNT
|
BM_SSP_CTRL0_IGNORE_CRC
|
BM_SSP_CTRL0_READ
);
ctrl0
|=
BM_SSP_CTRL0_DATA_XFER
;
if
(
*
first
)
ctrl0
|=
BM_SSP_CTRL0_LOCK_CS
;
if
(
!
write
)
if
(
!
(
flags
&
TXRX_WRITE
))
ctrl0
|=
BM_SSP_CTRL0_READ
;
/* Queue the DMA data transfer. */
for
(
sg_count
=
0
;
sg_count
<
sgs
;
sg_count
++
)
{
/* Prepare the transfer descriptor. */
min
=
min
(
len
,
desc_len
);
/* Prepare the transfer descriptor. */
if
((
sg_count
+
1
==
sgs
)
&&
*
last
)
/*
* De-assert CS on last segment if flag is set (i.e., no more
* transfers will follow)
*/
if
((
sg_count
+
1
==
sgs
)
&&
(
flags
&
TXRX_DEASSERT_CS
))
ctrl0
|=
BM_SSP_CTRL0_IGNORE_CRC
;
if
(
ssp
->
devid
==
IMX23_SSP
)
{
...
...
@@ -267,7 +247,7 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, int cs,
sg_init_one
(
&
dma_xfer
[
sg_count
].
sg
,
sg_buf
,
min
);
ret
=
dma_map_sg
(
ssp
->
dev
,
&
dma_xfer
[
sg_count
].
sg
,
1
,
write
?
DMA_TO_DEVICE
:
DMA_FROM_DEVICE
);
(
flags
&
TXRX_WRITE
)
?
DMA_TO_DEVICE
:
DMA_FROM_DEVICE
);
len
-=
min
;
buf
+=
min
;
...
...
@@ -287,7 +267,7 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, int cs,
desc
=
dmaengine_prep_slave_sg
(
ssp
->
dmach
,
&
dma_xfer
[
sg_count
].
sg
,
1
,
write
?
DMA_MEM_TO_DEV
:
DMA_DEV_TO_MEM
,
(
flags
&
TXRX_WRITE
)
?
DMA_MEM_TO_DEV
:
DMA_DEV_TO_MEM
,
DMA_PREP_INTERRUPT
|
DMA_CTRL_ACK
);
if
(
!
desc
)
{
...
...
@@ -324,7 +304,7 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, int cs,
while
(
--
sg_count
>=
0
)
{
err_mapped:
dma_unmap_sg
(
ssp
->
dev
,
&
dma_xfer
[
sg_count
].
sg
,
1
,
write
?
DMA_TO_DEVICE
:
DMA_FROM_DEVICE
);
(
flags
&
TXRX_WRITE
)
?
DMA_TO_DEVICE
:
DMA_FROM_DEVICE
);
}
kfree
(
dma_xfer
);
...
...
@@ -332,20 +312,19 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, int cs,
return
ret
;
}
static
int
mxs_spi_txrx_pio
(
struct
mxs_spi
*
spi
,
int
cs
,
static
int
mxs_spi_txrx_pio
(
struct
mxs_spi
*
spi
,
unsigned
char
*
buf
,
int
len
,
int
*
first
,
int
*
last
,
int
write
)
unsigned
int
flags
)
{
struct
mxs_ssp
*
ssp
=
&
spi
->
ssp
;
if
(
*
first
)
mxs_spi_enable
(
spi
);
mxs_spi_set_cs
(
spi
,
cs
);
writel
(
BM_SSP_CTRL0_IGNORE_CRC
,
ssp
->
base
+
HW_SSP_CTRL0
+
STMP_OFFSET_REG_CLR
);
while
(
len
--
)
{
if
(
*
last
&&
len
==
0
)
mxs_spi_disable
(
spi
);
if
(
len
==
0
&&
(
flags
&
TXRX_DEASSERT_CS
))
writel
(
BM_SSP_CTRL0_IGNORE_CRC
,
ssp
->
base
+
HW_SSP_CTRL0
+
STMP_OFFSET_REG_SET
);
if
(
ssp
->
devid
==
IMX23_SSP
)
{
writel
(
BM_SSP_CTRL0_XFER_COUNT
,
...
...
@@ -356,7 +335,7 @@ static int mxs_spi_txrx_pio(struct mxs_spi *spi, int cs,
writel
(
1
,
ssp
->
base
+
HW_SSP_XFER_SIZE
);
}
if
(
write
)
if
(
flags
&
TXRX_WRITE
)
writel
(
BM_SSP_CTRL0_READ
,
ssp
->
base
+
HW_SSP_CTRL0
+
STMP_OFFSET_REG_CLR
);
else
...
...
@@ -369,13 +348,13 @@ static int mxs_spi_txrx_pio(struct mxs_spi *spi, int cs,
if
(
mxs_ssp_wait
(
spi
,
HW_SSP_CTRL0
,
BM_SSP_CTRL0_RUN
,
1
))
return
-
ETIMEDOUT
;
if
(
write
)
if
(
flags
&
TXRX_WRITE
)
writel
(
*
buf
,
ssp
->
base
+
HW_SSP_DATA
(
ssp
));
writel
(
BM_SSP_CTRL0_DATA_XFER
,
ssp
->
base
+
HW_SSP_CTRL0
+
STMP_OFFSET_REG_SET
);
if
(
!
write
)
{
if
(
!
(
flags
&
TXRX_WRITE
)
)
{
if
(
mxs_ssp_wait
(
spi
,
HW_SSP_STATUS
(
ssp
),
BM_SSP_STATUS_FIFO_EMPTY
,
0
))
return
-
ETIMEDOUT
;
...
...
@@ -400,14 +379,15 @@ static int mxs_spi_transfer_one(struct spi_master *master,
{
struct
mxs_spi
*
spi
=
spi_master_get_devdata
(
master
);
struct
mxs_ssp
*
ssp
=
&
spi
->
ssp
;
int
first
,
last
;
struct
spi_transfer
*
t
,
*
tmp_t
;
unsigned
int
flag
;
int
status
=
0
;
int
cs
;
first
=
last
=
0
;
cs
=
m
->
spi
->
chip_select
;
/* Program CS register bits here, it will be used for all transfers. */
writel
(
BM_SSP_CTRL0_WAIT_FOR_CMD
|
BM_SSP_CTRL0_WAIT_FOR_IRQ
,
ssp
->
base
+
HW_SSP_CTRL0
+
STMP_OFFSET_REG_CLR
);
writel
(
mxs_spi_cs_to_reg
(
m
->
spi
->
chip_select
),
ssp
->
base
+
HW_SSP_CTRL0
+
STMP_OFFSET_REG_SET
);
list_for_each_entry_safe
(
t
,
tmp_t
,
&
m
->
transfers
,
transfer_list
)
{
...
...
@@ -415,16 +395,9 @@ static int mxs_spi_transfer_one(struct spi_master *master,
if
(
status
)
break
;
if
(
&
t
->
transfer_list
==
m
->
transfers
.
next
)
first
=
1
;
if
(
&
t
->
transfer_list
==
m
->
transfers
.
prev
)
last
=
1
;
if
((
t
->
rx_buf
&&
t
->
tx_buf
)
||
(
t
->
rx_dma
&&
t
->
tx_dma
))
{
dev_err
(
ssp
->
dev
,
"Cannot send and receive simultaneously
\n
"
);
status
=
-
EINVAL
;
break
;
}
/* De-assert on last transfer, inverted by cs_change flag */
flag
=
(
&
t
->
transfer_list
==
m
->
transfers
.
prev
)
^
t
->
cs_change
?
TXRX_DEASSERT_CS
:
0
;
/*
* Small blocks can be transfered via PIO.
...
...
@@ -441,26 +414,26 @@ static int mxs_spi_transfer_one(struct spi_master *master,
STMP_OFFSET_REG_CLR
);
if
(
t
->
tx_buf
)
status
=
mxs_spi_txrx_pio
(
spi
,
cs
,
status
=
mxs_spi_txrx_pio
(
spi
,
(
void
*
)
t
->
tx_buf
,
t
->
len
,
&
first
,
&
last
,
1
);
t
->
len
,
flag
|
TXRX_WRITE
);
if
(
t
->
rx_buf
)
status
=
mxs_spi_txrx_pio
(
spi
,
cs
,
status
=
mxs_spi_txrx_pio
(
spi
,
t
->
rx_buf
,
t
->
len
,
&
first
,
&
last
,
0
);
flag
);
}
else
{
writel
(
BM_SSP_CTRL1_DMA_ENABLE
,
ssp
->
base
+
HW_SSP_CTRL1
(
ssp
)
+
STMP_OFFSET_REG_SET
);
if
(
t
->
tx_buf
)
status
=
mxs_spi_txrx_dma
(
spi
,
cs
,
status
=
mxs_spi_txrx_dma
(
spi
,
(
void
*
)
t
->
tx_buf
,
t
->
len
,
&
first
,
&
last
,
1
);
flag
|
TXRX_WRITE
);
if
(
t
->
rx_buf
)
status
=
mxs_spi_txrx_dma
(
spi
,
cs
,
status
=
mxs_spi_txrx_dma
(
spi
,
t
->
rx_buf
,
t
->
len
,
&
first
,
&
last
,
0
);
flag
);
}
if
(
status
)
{
...
...
@@ -469,7 +442,6 @@ static int mxs_spi_transfer_one(struct spi_master *master,
}
m
->
actual_length
+=
t
->
len
;
first
=
last
=
0
;
}
m
->
status
=
status
;
...
...
@@ -563,7 +535,6 @@ static int mxs_spi_probe(struct platform_device *pdev)
goto
out_dma_release
;
clk_set_rate
(
ssp
->
clk
,
clk_freq
);
ssp
->
clk_rate
=
clk_get_rate
(
ssp
->
clk
)
/
1000
;
ret
=
stmp_reset_block
(
ssp
->
base
);
if
(
ret
)
...
...
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