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
19655dd0
Commit
19655dd0
authored
Apr 11, 2015
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'spi/topic/img-spfi' into spi-next
parents
e897f795
8c2c8c03
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
101 additions
and
83 deletions
+101
-83
Documentation/devicetree/bindings/spi/spi-img-spfi.txt
Documentation/devicetree/bindings/spi/spi-img-spfi.txt
+1
-0
drivers/spi/spi-img-spfi.c
drivers/spi/spi-img-spfi.c
+100
-83
No files found.
Documentation/devicetree/bindings/spi/spi-img-spfi.txt
View file @
19655dd0
...
...
@@ -14,6 +14,7 @@ Required properties:
- dma-names: Must include the following entries:
- rx
- tx
- cs-gpios: Must specify the GPIOs used for chipselect lines.
- #address-cells: Must be 1.
- #size-cells: Must be 0.
...
...
drivers/spi/spi-img-spfi.c
View file @
19655dd0
...
...
@@ -12,6 +12,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dmaengine.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
...
...
@@ -122,36 +123,31 @@ static inline void spfi_start(struct img_spfi *spfi)
spfi_writel
(
spfi
,
val
,
SPFI_CONTROL
);
}
static
inline
void
spfi_stop
(
struct
img_spfi
*
spfi
)
{
u32
val
;
val
=
spfi_readl
(
spfi
,
SPFI_CONTROL
);
val
&=
~
SPFI_CONTROL_SPFI_EN
;
spfi_writel
(
spfi
,
val
,
SPFI_CONTROL
);
}
static
inline
void
spfi_reset
(
struct
img_spfi
*
spfi
)
{
spfi_writel
(
spfi
,
SPFI_CONTROL_SOFT_RESET
,
SPFI_CONTROL
);
udelay
(
1
);
spfi_writel
(
spfi
,
0
,
SPFI_CONTROL
);
}
static
void
spfi_flush_tx_fifo
(
struct
img_spfi
*
spfi
)
static
int
spfi_wait_all_done
(
struct
img_spfi
*
spfi
)
{
unsigned
long
timeout
=
jiffies
+
msecs_to_jiffies
(
1
0
);
unsigned
long
timeout
=
jiffies
+
msecs_to_jiffies
(
5
0
);
spfi_writel
(
spfi
,
SPFI_INTERRUPT_SDE
,
SPFI_INTERRUPT_CLEAR
);
while
(
time_before
(
jiffies
,
timeout
))
{
if
(
spfi_readl
(
spfi
,
SPFI_INTERRUPT_STATUS
)
&
SPFI_INTERRUPT_SDE
)
return
;
u32
status
=
spfi_readl
(
spfi
,
SPFI_INTERRUPT_STATUS
);
if
(
status
&
SPFI_INTERRUPT_ALLDONETRIG
)
{
spfi_writel
(
spfi
,
SPFI_INTERRUPT_ALLDONETRIG
,
SPFI_INTERRUPT_CLEAR
);
return
0
;
}
cpu_relax
();
}
dev_err
(
spfi
->
dev
,
"Timed out waiting for
FIFO to drain
\n
"
);
dev_err
(
spfi
->
dev
,
"Timed out waiting for
transaction to complete
\n
"
);
spfi_reset
(
spfi
);
return
-
ETIMEDOUT
;
}
static
unsigned
int
spfi_pio_write32
(
struct
img_spfi
*
spfi
,
const
u32
*
buf
,
...
...
@@ -237,6 +233,7 @@ static int img_spfi_start_pio(struct spi_master *master,
const
void
*
tx_buf
=
xfer
->
tx_buf
;
void
*
rx_buf
=
xfer
->
rx_buf
;
unsigned
long
timeout
;
int
ret
;
if
(
tx_buf
)
tx_bytes
=
xfer
->
len
;
...
...
@@ -269,16 +266,15 @@ static int img_spfi_start_pio(struct spi_master *master,
cpu_relax
();
}
ret
=
spfi_wait_all_done
(
spfi
);
if
(
ret
<
0
)
return
ret
;
if
(
rx_bytes
>
0
||
tx_bytes
>
0
)
{
dev_err
(
spfi
->
dev
,
"PIO transfer timed out
\n
"
);
spfi_reset
(
spfi
);
return
-
ETIMEDOUT
;
}
if
(
tx_buf
)
spfi_flush_tx_fifo
(
spfi
);
spfi_stop
(
spfi
);
return
0
;
}
...
...
@@ -287,14 +283,12 @@ static void img_spfi_dma_rx_cb(void *data)
struct
img_spfi
*
spfi
=
data
;
unsigned
long
flags
;
sp
in_lock_irqsave
(
&
spfi
->
lock
,
flags
);
sp
fi_wait_all_done
(
spfi
);
spin_lock_irqsave
(
&
spfi
->
lock
,
flags
);
spfi
->
rx_dma_busy
=
false
;
if
(
!
spfi
->
tx_dma_busy
)
{
spfi_stop
(
spfi
);
if
(
!
spfi
->
tx_dma_busy
)
spi_finalize_current_transfer
(
spfi
->
master
);
}
spin_unlock_irqrestore
(
&
spfi
->
lock
,
flags
);
}
...
...
@@ -303,16 +297,12 @@ static void img_spfi_dma_tx_cb(void *data)
struct
img_spfi
*
spfi
=
data
;
unsigned
long
flags
;
spfi_
flush_tx_fifo
(
spfi
);
spfi_
wait_all_done
(
spfi
);
spin_lock_irqsave
(
&
spfi
->
lock
,
flags
);
spfi
->
tx_dma_busy
=
false
;
if
(
!
spfi
->
rx_dma_busy
)
{
spfi_stop
(
spfi
);
if
(
!
spfi
->
rx_dma_busy
)
spi_finalize_current_transfer
(
spfi
->
master
);
}
spin_unlock_irqrestore
(
&
spfi
->
lock
,
flags
);
}
...
...
@@ -397,6 +387,75 @@ static int img_spfi_start_dma(struct spi_master *master,
return
-
EIO
;
}
static
void
img_spfi_handle_err
(
struct
spi_master
*
master
,
struct
spi_message
*
msg
)
{
struct
img_spfi
*
spfi
=
spi_master_get_devdata
(
master
);
unsigned
long
flags
;
/*
* Stop all DMA and reset the controller if the previous transaction
* timed-out and never completed it's DMA.
*/
spin_lock_irqsave
(
&
spfi
->
lock
,
flags
);
if
(
spfi
->
tx_dma_busy
||
spfi
->
rx_dma_busy
)
{
spfi
->
tx_dma_busy
=
false
;
spfi
->
rx_dma_busy
=
false
;
dmaengine_terminate_all
(
spfi
->
tx_ch
);
dmaengine_terminate_all
(
spfi
->
rx_ch
);
}
spin_unlock_irqrestore
(
&
spfi
->
lock
,
flags
);
}
static
int
img_spfi_prepare
(
struct
spi_master
*
master
,
struct
spi_message
*
msg
)
{
struct
img_spfi
*
spfi
=
spi_master_get_devdata
(
master
);
u32
val
;
val
=
spfi_readl
(
spfi
,
SPFI_PORT_STATE
);
if
(
msg
->
spi
->
mode
&
SPI_CPHA
)
val
|=
SPFI_PORT_STATE_CK_PHASE
(
msg
->
spi
->
chip_select
);
else
val
&=
~
SPFI_PORT_STATE_CK_PHASE
(
msg
->
spi
->
chip_select
);
if
(
msg
->
spi
->
mode
&
SPI_CPOL
)
val
|=
SPFI_PORT_STATE_CK_POL
(
msg
->
spi
->
chip_select
);
else
val
&=
~
SPFI_PORT_STATE_CK_POL
(
msg
->
spi
->
chip_select
);
spfi_writel
(
spfi
,
val
,
SPFI_PORT_STATE
);
return
0
;
}
static
int
img_spfi_unprepare
(
struct
spi_master
*
master
,
struct
spi_message
*
msg
)
{
struct
img_spfi
*
spfi
=
spi_master_get_devdata
(
master
);
spfi_reset
(
spfi
);
return
0
;
}
static
int
img_spfi_setup
(
struct
spi_device
*
spi
)
{
int
ret
;
ret
=
gpio_request_one
(
spi
->
cs_gpio
,
(
spi
->
mode
&
SPI_CS_HIGH
)
?
GPIOF_OUT_INIT_LOW
:
GPIOF_OUT_INIT_HIGH
,
dev_name
(
&
spi
->
dev
));
if
(
ret
)
dev_err
(
&
spi
->
dev
,
"can't request chipselect gpio %d
\n
"
,
spi
->
cs_gpio
);
return
ret
;
}
static
void
img_spfi_cleanup
(
struct
spi_device
*
spi
)
{
gpio_free
(
spi
->
cs_gpio
);
}
static
void
img_spfi_config
(
struct
spi_master
*
master
,
struct
spi_device
*
spi
,
struct
spi_transfer
*
xfer
)
{
...
...
@@ -416,6 +475,9 @@ static void img_spfi_config(struct spi_master *master, struct spi_device *spi,
val
|=
div
<<
SPFI_DEVICE_PARAMETER_BITCLK_SHIFT
;
spfi_writel
(
spfi
,
val
,
SPFI_DEVICE_PARAMETER
(
spi
->
chip_select
));
spfi_writel
(
spfi
,
xfer
->
len
<<
SPFI_TRANSACTION_TSIZE_SHIFT
,
SPFI_TRANSACTION
);
val
=
spfi_readl
(
spfi
,
SPFI_CONTROL
);
val
&=
~
(
SPFI_CONTROL_SEND_DMA
|
SPFI_CONTROL_GET_DMA
);
if
(
xfer
->
tx_buf
)
...
...
@@ -429,25 +491,7 @@ static void img_spfi_config(struct spi_master *master, struct spi_device *spi,
else
if
(
xfer
->
tx_nbits
==
SPI_NBITS_QUAD
&&
xfer
->
rx_nbits
==
SPI_NBITS_QUAD
)
val
|=
SPFI_CONTROL_TMODE_QUAD
<<
SPFI_CONTROL_TMODE_SHIFT
;
val
&=
~
SPFI_CONTROL_CONTINUE
;
if
(
!
xfer
->
cs_change
&&
!
list_is_last
(
&
xfer
->
transfer_list
,
&
master
->
cur_msg
->
transfers
))
val
|=
SPFI_CONTROL_CONTINUE
;
spfi_writel
(
spfi
,
val
,
SPFI_CONTROL
);
val
=
spfi_readl
(
spfi
,
SPFI_PORT_STATE
);
if
(
spi
->
mode
&
SPI_CPHA
)
val
|=
SPFI_PORT_STATE_CK_PHASE
(
spi
->
chip_select
);
else
val
&=
~
SPFI_PORT_STATE_CK_PHASE
(
spi
->
chip_select
);
if
(
spi
->
mode
&
SPI_CPOL
)
val
|=
SPFI_PORT_STATE_CK_POL
(
spi
->
chip_select
);
else
val
&=
~
SPFI_PORT_STATE_CK_POL
(
spi
->
chip_select
);
spfi_writel
(
spfi
,
val
,
SPFI_PORT_STATE
);
spfi_writel
(
spfi
,
xfer
->
len
<<
SPFI_TRANSACTION_TSIZE_SHIFT
,
SPFI_TRANSACTION
);
}
static
int
img_spfi_transfer_one
(
struct
spi_master
*
master
,
...
...
@@ -455,8 +499,6 @@ static int img_spfi_transfer_one(struct spi_master *master,
struct
spi_transfer
*
xfer
)
{
struct
img_spfi
*
spfi
=
spi_master_get_devdata
(
spi
->
master
);
bool
dma_reset
=
false
;
unsigned
long
flags
;
int
ret
;
if
(
xfer
->
len
>
SPFI_TRANSACTION_TSIZE_MASK
)
{
...
...
@@ -466,23 +508,6 @@ static int img_spfi_transfer_one(struct spi_master *master,
return
-
EINVAL
;
}
/*
* Stop all DMA and reset the controller if the previous transaction
* timed-out and never completed it's DMA.
*/
spin_lock_irqsave
(
&
spfi
->
lock
,
flags
);
if
(
spfi
->
tx_dma_busy
||
spfi
->
rx_dma_busy
)
{
dev_err
(
spfi
->
dev
,
"SPI DMA still busy
\n
"
);
dma_reset
=
true
;
}
spin_unlock_irqrestore
(
&
spfi
->
lock
,
flags
);
if
(
dma_reset
)
{
dmaengine_terminate_all
(
spfi
->
tx_ch
);
dmaengine_terminate_all
(
spfi
->
rx_ch
);
spfi_reset
(
spfi
);
}
img_spfi_config
(
master
,
spi
,
xfer
);
if
(
master
->
can_dma
&&
master
->
can_dma
(
master
,
spi
,
xfer
))
ret
=
img_spfi_start_dma
(
master
,
spi
,
xfer
);
...
...
@@ -492,17 +517,6 @@ static int img_spfi_transfer_one(struct spi_master *master,
return
ret
;
}
static
void
img_spfi_set_cs
(
struct
spi_device
*
spi
,
bool
enable
)
{
struct
img_spfi
*
spfi
=
spi_master_get_devdata
(
spi
->
master
);
u32
val
;
val
=
spfi_readl
(
spfi
,
SPFI_PORT_STATE
);
val
&=
~
(
SPFI_PORT_STATE_DEV_SEL_MASK
<<
SPFI_PORT_STATE_DEV_SEL_SHIFT
);
val
|=
spi
->
chip_select
<<
SPFI_PORT_STATE_DEV_SEL_SHIFT
;
spfi_writel
(
spfi
,
val
,
SPFI_PORT_STATE
);
}
static
bool
img_spfi_can_dma
(
struct
spi_master
*
master
,
struct
spi_device
*
spi
,
struct
spi_transfer
*
xfer
)
{
...
...
@@ -591,14 +605,17 @@ static int img_spfi_probe(struct platform_device *pdev)
master
->
mode_bits
=
SPI_CPOL
|
SPI_CPHA
|
SPI_TX_DUAL
|
SPI_RX_DUAL
;
if
(
of_property_read_bool
(
spfi
->
dev
->
of_node
,
"img,supports-quad-mode"
))
master
->
mode_bits
|=
SPI_TX_QUAD
|
SPI_RX_QUAD
;
master
->
num_chipselect
=
5
;
master
->
dev
.
of_node
=
pdev
->
dev
.
of_node
;
master
->
bits_per_word_mask
=
SPI_BPW_MASK
(
32
)
|
SPI_BPW_MASK
(
8
);
master
->
max_speed_hz
=
clk_get_rate
(
spfi
->
spfi_clk
)
/
4
;
master
->
min_speed_hz
=
clk_get_rate
(
spfi
->
spfi_clk
)
/
512
;
master
->
set_cs
=
img_spfi_set_cs
;
master
->
setup
=
img_spfi_setup
;
master
->
cleanup
=
img_spfi_cleanup
;
master
->
transfer_one
=
img_spfi_transfer_one
;
master
->
prepare_message
=
img_spfi_prepare
;
master
->
unprepare_message
=
img_spfi_unprepare
;
master
->
handle_err
=
img_spfi_handle_err
;
spfi
->
tx_ch
=
dma_request_slave_channel
(
spfi
->
dev
,
"tx"
);
spfi
->
rx_ch
=
dma_request_slave_channel
(
spfi
->
dev
,
"rx"
);
...
...
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