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
66886337
Commit
66886337
authored
Feb 08, 2015
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'spi/topic/xilinx' into spi-next
parents
30b9278b
34093cb9
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
163 additions
and
135 deletions
+163
-135
drivers/spi/spi-xilinx.c
drivers/spi/spi-xilinx.c
+163
-135
No files found.
drivers/spi/spi-xilinx.c
View file @
66886337
...
...
@@ -22,6 +22,8 @@
#include <linux/spi/xilinx_spi.h>
#include <linux/io.h>
#define XILINX_SPI_MAX_CS 32
#define XILINX_SPI_NAME "xilinx_spi"
/* Register definitions as per "OPB Serial Peripheral Interface (SPI) (v1.00e)
...
...
@@ -34,7 +36,8 @@
#define XSPI_CR_MASTER_MODE 0x04
#define XSPI_CR_CPOL 0x08
#define XSPI_CR_CPHA 0x10
#define XSPI_CR_MODE_MASK (XSPI_CR_CPHA | XSPI_CR_CPOL)
#define XSPI_CR_MODE_MASK (XSPI_CR_CPHA | XSPI_CR_CPOL | \
XSPI_CR_LSB_FIRST | XSPI_CR_LOOP)
#define XSPI_CR_TXFIFO_RESET 0x20
#define XSPI_CR_RXFIFO_RESET 0x40
#define XSPI_CR_MANUAL_SSELECT 0x80
...
...
@@ -85,12 +88,11 @@ struct xilinx_spi {
u8
*
rx_ptr
;
/* pointer in the Tx buffer */
const
u8
*
tx_ptr
;
/* pointer in the Rx buffer */
int
remaining_bytes
;
/* the number of bytes left to transfer */
u8
bits_per_word
;
u8
bytes_per_word
;
int
buffer_size
;
/* buffer size in words */
u32
cs_inactive
;
/* Level of the CS pins when inactive*/
unsigned
int
(
*
read_fn
)(
void
__iomem
*
);
void
(
*
write_fn
)(
u32
,
void
__iomem
*
);
void
(
*
tx_fn
)(
struct
xilinx_spi
*
);
void
(
*
rx_fn
)(
struct
xilinx_spi
*
);
};
static
void
xspi_write32
(
u32
val
,
void
__iomem
*
addr
)
...
...
@@ -113,49 +115,51 @@ static unsigned int xspi_read32_be(void __iomem *addr)
return
ioread32be
(
addr
);
}
static
void
x
spi_tx8
(
struct
xilinx_spi
*
xspi
)
static
void
x
ilinx_spi_tx
(
struct
xilinx_spi
*
xspi
)
{
xspi
->
write_fn
(
*
xspi
->
tx_ptr
,
xspi
->
regs
+
XSPI_TXD_OFFSET
);
xspi
->
tx_ptr
++
;
}
static
void
xspi_tx16
(
struct
xilinx_spi
*
xspi
)
{
xspi
->
write_fn
(
*
(
u16
*
)(
xspi
->
tx_ptr
),
xspi
->
regs
+
XSPI_TXD_OFFSET
);
xspi
->
tx_ptr
+=
2
;
}
u32
data
=
0
;
static
void
xspi_tx32
(
struct
xilinx_spi
*
xspi
)
{
xspi
->
write_fn
(
*
(
u32
*
)(
xspi
->
tx_ptr
),
xspi
->
regs
+
XSPI_TXD_OFFSET
);
xspi
->
tx_ptr
+=
4
;
}
static
void
xspi_rx8
(
struct
xilinx_spi
*
xspi
)
{
u32
data
=
xspi
->
read_fn
(
xspi
->
regs
+
XSPI_RXD_OFFSET
);
if
(
xspi
->
rx_ptr
)
{
*
xspi
->
rx_ptr
=
data
&
0xff
;
xspi
->
rx_ptr
++
;
if
(
!
xspi
->
tx_ptr
)
{
xspi
->
write_fn
(
0
,
xspi
->
regs
+
XSPI_TXD_OFFSET
);
return
;
}
}
static
void
xspi_rx16
(
struct
xilinx_spi
*
xspi
)
{
u32
data
=
xspi
->
read_fn
(
xspi
->
regs
+
XSPI_RXD_OFFSET
);
if
(
xspi
->
rx_ptr
)
{
*
(
u16
*
)(
xspi
->
rx_ptr
)
=
data
&
0xffff
;
xspi
->
rx_ptr
+=
2
;
switch
(
xspi
->
bytes_per_word
)
{
case
1
:
data
=
*
(
u8
*
)(
xspi
->
tx_ptr
);
break
;
case
2
:
data
=
*
(
u16
*
)(
xspi
->
tx_ptr
);
break
;
case
4
:
data
=
*
(
u32
*
)(
xspi
->
tx_ptr
);
break
;
}
xspi
->
write_fn
(
data
,
xspi
->
regs
+
XSPI_TXD_OFFSET
);
xspi
->
tx_ptr
+=
xspi
->
bytes_per_word
;
}
static
void
x
spi_rx32
(
struct
xilinx_spi
*
xspi
)
static
void
x
ilinx_spi_rx
(
struct
xilinx_spi
*
xspi
)
{
u32
data
=
xspi
->
read_fn
(
xspi
->
regs
+
XSPI_RXD_OFFSET
);
if
(
xspi
->
rx_ptr
)
{
if
(
!
xspi
->
rx_ptr
)
return
;
switch
(
xspi
->
bytes_per_word
)
{
case
1
:
*
(
u8
*
)(
xspi
->
rx_ptr
)
=
data
;
break
;
case
2
:
*
(
u16
*
)(
xspi
->
rx_ptr
)
=
data
;
break
;
case
4
:
*
(
u32
*
)(
xspi
->
rx_ptr
)
=
data
;
xspi
->
rx_ptr
+=
4
;
break
;
}
xspi
->
rx_ptr
+=
xspi
->
bytes_per_word
;
}
static
void
xspi_init_hw
(
struct
xilinx_spi
*
xspi
)
...
...
@@ -165,46 +169,56 @@ static void xspi_init_hw(struct xilinx_spi *xspi)
/* Reset the SPI device */
xspi
->
write_fn
(
XIPIF_V123B_RESET_MASK
,
regs_base
+
XIPIF_V123B_RESETR_OFFSET
);
/* Disable all the interrupts just in case */
xspi
->
write_fn
(
0
,
regs_base
+
XIPIF_V123B_IIER_OFFSET
);
/* Enable the global IPIF interrupt */
xspi
->
write_fn
(
XIPIF_V123B_GINTR_ENABLE
,
regs_base
+
XIPIF_V123B_DGIER_OFFSET
);
/* Enable the transmit empty interrupt, which we use to determine
* progress on the transmission.
*/
xspi
->
write_fn
(
XSPI_INTR_TX_EMPTY
,
regs_base
+
XIPIF_V123B_IIER_OFFSET
);
/* Disable the global IPIF interrupt */
xspi
->
write_fn
(
0
,
regs_base
+
XIPIF_V123B_DGIER_OFFSET
);
/* Deselect the slave on the SPI bus */
xspi
->
write_fn
(
0xffff
,
regs_base
+
XSPI_SSR_OFFSET
);
/* Disable the transmitter, enable Manual Slave Select Assertion,
* put SPI controller into master mode, and enable it */
xspi
->
write_fn
(
XSPI_CR_
TRANS_INHIBIT
|
XSPI_CR_MANUAL_SSELECT
|
XSPI_CR_
MASTER_MODE
|
XSPI_CR_ENABLE
|
XSPI_CR_TXFIFO_RESET
|
XSPI_CR_RXFIFO_RESET
,
regs_base
+
XSPI_CR_OFFSET
);
xspi
->
write_fn
(
XSPI_CR_
MANUAL_SSELECT
|
XSPI_CR_MASTER_MODE
|
XSPI_CR_
ENABLE
|
XSPI_CR_TXFIFO_RESET
|
XSPI_CR_RXFIFO_RESET
,
regs_base
+
XSPI_CR_OFFSET
);
}
static
void
xilinx_spi_chipselect
(
struct
spi_device
*
spi
,
int
is_on
)
{
struct
xilinx_spi
*
xspi
=
spi_master_get_devdata
(
spi
->
master
);
u16
cr
;
u32
cs
;
if
(
is_on
==
BITBANG_CS_INACTIVE
)
{
/* Deselect the slave on the SPI bus */
xspi
->
write_fn
(
0xffff
,
xspi
->
regs
+
XSPI_SSR_OFFSET
);
}
else
if
(
is_on
==
BITBANG_CS_ACTIVE
)
{
/* Set the SPI clock phase and polarity */
u16
cr
=
xspi
->
read_fn
(
xspi
->
regs
+
XSPI_CR_OFFSET
)
&
~
XSPI_CR_MODE_MASK
;
if
(
spi
->
mode
&
SPI_CPHA
)
cr
|=
XSPI_CR_CPHA
;
if
(
spi
->
mode
&
SPI_CPOL
)
cr
|=
XSPI_CR_CPOL
;
xspi
->
write_fn
(
cr
,
xspi
->
regs
+
XSPI_CR_OFFSET
);
/* We do not check spi->max_speed_hz here as the SPI clock
* frequency is not software programmable (the IP block design
* parameter)
*/
/* Activate the chip select */
xspi
->
write_fn
(
~
(
0x0001
<<
spi
->
chip_select
),
xspi
->
regs
+
XSPI_SSR_OFFSET
);
xspi
->
write_fn
(
xspi
->
cs_inactive
,
xspi
->
regs
+
XSPI_SSR_OFFSET
);
return
;
}
/* Set the SPI clock phase and polarity */
cr
=
xspi
->
read_fn
(
xspi
->
regs
+
XSPI_CR_OFFSET
)
&
~
XSPI_CR_MODE_MASK
;
if
(
spi
->
mode
&
SPI_CPHA
)
cr
|=
XSPI_CR_CPHA
;
if
(
spi
->
mode
&
SPI_CPOL
)
cr
|=
XSPI_CR_CPOL
;
if
(
spi
->
mode
&
SPI_LSB_FIRST
)
cr
|=
XSPI_CR_LSB_FIRST
;
if
(
spi
->
mode
&
SPI_LOOP
)
cr
|=
XSPI_CR_LOOP
;
xspi
->
write_fn
(
cr
,
xspi
->
regs
+
XSPI_CR_OFFSET
);
/* We do not check spi->max_speed_hz here as the SPI clock
* frequency is not software programmable (the IP block design
* parameter)
*/
cs
=
xspi
->
cs_inactive
;
cs
^=
BIT
(
spi
->
chip_select
);
/* Activate the chip select */
xspi
->
write_fn
(
cs
,
xspi
->
regs
+
XSPI_SSR_OFFSET
);
}
/* spi_bitbang requires custom setup_transfer() to be defined if there is a
...
...
@@ -213,85 +227,85 @@ static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
static
int
xilinx_spi_setup_transfer
(
struct
spi_device
*
spi
,
struct
spi_transfer
*
t
)
{
return
0
;
}
struct
xilinx_spi
*
xspi
=
spi_master_get_devdata
(
spi
->
master
);
static
void
xilinx_spi_fill_tx_fifo
(
struct
xilinx_spi
*
xspi
)
{
u8
sr
;
if
(
spi
->
mode
&
SPI_CS_HIGH
)
xspi
->
cs_inactive
&=
~
BIT
(
spi
->
chip_select
);
else
xspi
->
cs_inactive
|=
BIT
(
spi
->
chip_select
);
/* Fill the Tx FIFO with as many bytes as possible */
sr
=
xspi
->
read_fn
(
xspi
->
regs
+
XSPI_SR_OFFSET
);
while
((
sr
&
XSPI_SR_TX_FULL_MASK
)
==
0
&&
xspi
->
remaining_bytes
>
0
)
{
if
(
xspi
->
tx_ptr
)
xspi
->
tx_fn
(
xspi
);
else
xspi
->
write_fn
(
0
,
xspi
->
regs
+
XSPI_TXD_OFFSET
);
xspi
->
remaining_bytes
-=
xspi
->
bits_per_word
/
8
;
sr
=
xspi
->
read_fn
(
xspi
->
regs
+
XSPI_SR_OFFSET
);
}
return
0
;
}
static
int
xilinx_spi_txrx_bufs
(
struct
spi_device
*
spi
,
struct
spi_transfer
*
t
)
{
struct
xilinx_spi
*
xspi
=
spi_master_get_devdata
(
spi
->
master
);
u32
ipif_ier
;
int
remaining_words
;
/* the number of words left to transfer */
bool
use_irq
=
false
;
u16
cr
=
0
;
/* We get here with transmitter inhibited */
xspi
->
tx_ptr
=
t
->
tx_buf
;
xspi
->
rx_ptr
=
t
->
rx_buf
;
xspi
->
remaining_bytes
=
t
->
len
;
remaining_words
=
t
->
len
/
xspi
->
bytes_per_word
;
reinit_completion
(
&
xspi
->
done
);
if
(
xspi
->
irq
>=
0
&&
remaining_words
>
xspi
->
buffer_size
)
{
use_irq
=
true
;
xspi
->
write_fn
(
XSPI_INTR_TX_EMPTY
,
xspi
->
regs
+
XIPIF_V123B_IISR_OFFSET
);
/* Enable the global IPIF interrupt */
xspi
->
write_fn
(
XIPIF_V123B_GINTR_ENABLE
,
xspi
->
regs
+
XIPIF_V123B_DGIER_OFFSET
);
/* Inhibit irq to avoid spurious irqs on tx_empty*/
cr
=
xspi
->
read_fn
(
xspi
->
regs
+
XSPI_CR_OFFSET
);
xspi
->
write_fn
(
cr
|
XSPI_CR_TRANS_INHIBIT
,
xspi
->
regs
+
XSPI_CR_OFFSET
);
}
/* Enable the transmit empty interrupt, which we use to determine
* progress on the transmission.
*/
ipif_ier
=
xspi
->
read_fn
(
xspi
->
regs
+
XIPIF_V123B_IIER_OFFSET
);
xspi
->
write_fn
(
ipif_ier
|
XSPI_INTR_TX_EMPTY
,
xspi
->
regs
+
XIPIF_V123B_IIER_OFFSET
);
while
(
remaining_words
)
{
int
n_words
,
tx_words
,
rx_words
;
for
(;;)
{
u16
cr
;
u8
sr
;
n_words
=
min
(
remaining_words
,
xspi
->
buffer_size
);
xilinx_spi_fill_tx_fifo
(
xspi
);
tx_words
=
n_words
;
while
(
tx_words
--
)
xilinx_spi_tx
(
xspi
);
/* Start the transfer by not inhibiting the transmitter any
* longer
*/
cr
=
xspi
->
read_fn
(
xspi
->
regs
+
XSPI_CR_OFFSET
)
&
~
XSPI_CR_TRANS_INHIBIT
;
xspi
->
write_fn
(
cr
,
xspi
->
regs
+
XSPI_CR_OFFSET
);
wait_for_completion
(
&
xspi
->
done
);
if
(
use_irq
)
{
xspi
->
write_fn
(
cr
,
xspi
->
regs
+
XSPI_CR_OFFSET
);
wait_for_completion
(
&
xspi
->
done
);
}
else
while
(
!
(
xspi
->
read_fn
(
xspi
->
regs
+
XSPI_SR_OFFSET
)
&
XSPI_SR_TX_EMPTY_MASK
))
;
/* A transmit has just completed. Process received data and
* check for more data to transmit. Always inhibit the
* transmitter while the Isr refills the transmit register/FIFO,
* or make sure it is stopped if we're done.
*/
cr
=
xspi
->
read_fn
(
xspi
->
regs
+
XSPI_CR_OFFSET
);
xspi
->
write_fn
(
cr
|
XSPI_CR_TRANS_INHIBIT
,
if
(
use_irq
)
xspi
->
write_fn
(
cr
|
XSPI_CR_TRANS_INHIBIT
,
xspi
->
regs
+
XSPI_CR_OFFSET
);
/* Read out all the data from the Rx FIFO */
sr
=
xspi
->
read_fn
(
xspi
->
regs
+
XSPI_SR_OFFSET
);
while
((
sr
&
XSPI_SR_RX_EMPTY_MASK
)
==
0
)
{
xspi
->
rx_fn
(
xspi
);
sr
=
xspi
->
read_fn
(
xspi
->
regs
+
XSPI_SR_OFFSET
);
}
/* See if there is more data to send */
if
(
xspi
->
remaining_bytes
<=
0
)
break
;
rx_words
=
n_words
;
while
(
rx_words
--
)
xilinx_spi_rx
(
xspi
);
remaining_words
-=
n_words
;
}
/* Disable the transmit empty interrupt */
xspi
->
write_fn
(
ipif_ier
,
xspi
->
regs
+
XIPIF_V123B_I
IER_OFFSET
);
if
(
use_irq
)
xspi
->
write_fn
(
0
,
xspi
->
regs
+
XIPIF_V123B_DG
IER_OFFSET
);
return
t
->
len
-
xspi
->
remaining_bytes
;
return
t
->
len
;
}
...
...
@@ -316,6 +330,28 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
return
IRQ_HANDLED
;
}
static
int
xilinx_spi_find_buffer_size
(
struct
xilinx_spi
*
xspi
)
{
u8
sr
;
int
n_words
=
0
;
/*
* Before the buffer_size detection we reset the core
* to make sure we start with a clean state.
*/
xspi
->
write_fn
(
XIPIF_V123B_RESET_MASK
,
xspi
->
regs
+
XIPIF_V123B_RESETR_OFFSET
);
/* Fill the Tx FIFO with as many words as possible */
do
{
xspi
->
write_fn
(
0
,
xspi
->
regs
+
XSPI_TXD_OFFSET
);
sr
=
xspi
->
read_fn
(
xspi
->
regs
+
XSPI_SR_OFFSET
);
n_words
++
;
}
while
(
!
(
sr
&
XSPI_SR_TX_FULL_MASK
));
return
n_words
;
}
static
const
struct
of_device_id
xilinx_spi_of_match
[]
=
{
{
.
compatible
=
"xlnx,xps-spi-2.00.a"
,
},
{
.
compatible
=
"xlnx,xps-spi-2.00.b"
,
},
...
...
@@ -348,14 +384,21 @@ static int xilinx_spi_probe(struct platform_device *pdev)
return
-
EINVAL
;
}
if
(
num_cs
>
XILINX_SPI_MAX_CS
)
{
dev_err
(
&
pdev
->
dev
,
"Invalid number of spi slaves
\n
"
);
return
-
EINVAL
;
}
master
=
spi_alloc_master
(
&
pdev
->
dev
,
sizeof
(
struct
xilinx_spi
));
if
(
!
master
)
return
-
ENODEV
;
/* the spi->mode bits understood by this driver: */
master
->
mode_bits
=
SPI_CPOL
|
SPI_CPHA
;
master
->
mode_bits
=
SPI_CPOL
|
SPI_CPHA
|
SPI_LSB_FIRST
|
SPI_LOOP
|
SPI_CS_HIGH
;
xspi
=
spi_master_get_devdata
(
master
);
xspi
->
cs_inactive
=
0xffffffff
;
xspi
->
bitbang
.
master
=
master
;
xspi
->
bitbang
.
chipselect
=
xilinx_spi_chipselect
;
xspi
->
bitbang
.
setup_transfer
=
xilinx_spi_setup_transfer
;
...
...
@@ -392,35 +435,20 @@ static int xilinx_spi_probe(struct platform_device *pdev)
}
master
->
bits_per_word_mask
=
SPI_BPW_MASK
(
bits_per_word
);
xspi
->
bits_per_word
=
bits_per_word
;
if
(
xspi
->
bits_per_word
==
8
)
{
xspi
->
tx_fn
=
xspi_tx8
;
xspi
->
rx_fn
=
xspi_rx8
;
}
else
if
(
xspi
->
bits_per_word
==
16
)
{
xspi
->
tx_fn
=
xspi_tx16
;
xspi
->
rx_fn
=
xspi_rx16
;
}
else
if
(
xspi
->
bits_per_word
==
32
)
{
xspi
->
tx_fn
=
xspi_tx32
;
xspi
->
rx_fn
=
xspi_rx32
;
}
else
{
ret
=
-
EINVAL
;
goto
put_master
;
}
/* SPI controller initializations */
xspi_init_hw
(
xspi
);
xspi
->
bytes_per_word
=
bits_per_word
/
8
;
xspi
->
buffer_size
=
xilinx_spi_find_buffer_size
(
xspi
);
xspi
->
irq
=
platform_get_irq
(
pdev
,
0
);
if
(
xspi
->
irq
<
0
)
{
ret
=
xspi
->
irq
;
goto
put_master
;
if
(
xspi
->
irq
>=
0
)
{
/* Register for SPI Interrupt */
ret
=
devm_request_irq
(
&
pdev
->
dev
,
xspi
->
irq
,
xilinx_spi_irq
,
0
,
dev_name
(
&
pdev
->
dev
),
xspi
);
if
(
ret
)
goto
put_master
;
}
/* Register for SPI Interrupt */
ret
=
devm_request_irq
(
&
pdev
->
dev
,
xspi
->
irq
,
xilinx_spi_irq
,
0
,
dev_name
(
&
pdev
->
dev
),
xspi
);
if
(
ret
)
goto
put_master
;
/* SPI controller initializations */
xspi_init_hw
(
xspi
);
ret
=
spi_bitbang_start
(
&
xspi
->
bitbang
);
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