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
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