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