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
ad14ad73
Commit
ad14ad73
authored
Oct 25, 2013
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'spi/topic/rspi' into spi-next
parents
b3d6c800
cb52c673
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
234 additions
and
40 deletions
+234
-40
drivers/spi/Kconfig
drivers/spi/Kconfig
+1
-1
drivers/spi/spi-rspi.c
drivers/spi/spi-rspi.c
+231
-39
include/linux/spi/rspi.h
include/linux/spi/rspi.h
+2
-0
No files found.
drivers/spi/Kconfig
View file @
ad14ad73
...
...
@@ -370,7 +370,7 @@ config SPI_PXA2XX_PCI
config SPI_RSPI
tristate "Renesas RSPI controller"
depends on
SUPERH
&& SH_DMAE_BASE
depends on
(SUPERH || ARCH_SHMOBILE)
&& SH_DMAE_BASE
help
SPI driver for Renesas RSPI blocks.
...
...
drivers/spi/spi-rspi.c
View file @
ad14ad73
...
...
@@ -59,6 +59,14 @@
#define RSPI_SPCMD6 0x1c
#define RSPI_SPCMD7 0x1e
/*qspi only */
#define QSPI_SPBFCR 0x18
#define QSPI_SPBDCR 0x1a
#define QSPI_SPBMUL0 0x1c
#define QSPI_SPBMUL1 0x20
#define QSPI_SPBMUL2 0x24
#define QSPI_SPBMUL3 0x28
/* SPCR */
#define SPCR_SPRIE 0x80
#define SPCR_SPE 0x40
...
...
@@ -126,6 +134,8 @@
#define SPCMD_LSBF 0x1000
#define SPCMD_SPB_MASK 0x0f00
#define SPCMD_SPB_8_TO_16(bit) (((bit - 1) << 8) & SPCMD_SPB_MASK)
#define SPCMD_SPB_8BIT 0x0000
/* qspi only */
#define SPCMD_SPB_16BIT 0x0100
#define SPCMD_SPB_20BIT 0x0000
#define SPCMD_SPB_24BIT 0x0100
#define SPCMD_SPB_32BIT 0x0200
...
...
@@ -135,6 +145,10 @@
#define SPCMD_CPOL 0x0002
#define SPCMD_CPHA 0x0001
/* SPBFCR */
#define SPBFCR_TXRST 0x80
/* qspi only */
#define SPBFCR_RXRST 0x40
/* qspi only */
struct
rspi_data
{
void
__iomem
*
addr
;
u32
max_speed_hz
;
...
...
@@ -145,6 +159,7 @@ struct rspi_data {
spinlock_t
lock
;
struct
clk
*
clk
;
unsigned
char
spsr
;
const
struct
spi_ops
*
ops
;
/* for dmaengine */
struct
dma_chan
*
chan_tx
;
...
...
@@ -165,6 +180,11 @@ static void rspi_write16(struct rspi_data *rspi, u16 data, u16 offset)
iowrite16
(
data
,
rspi
->
addr
+
offset
);
}
static
void
rspi_write32
(
struct
rspi_data
*
rspi
,
u32
data
,
u16
offset
)
{
iowrite32
(
data
,
rspi
->
addr
+
offset
);
}
static
u8
rspi_read8
(
struct
rspi_data
*
rspi
,
u16
offset
)
{
return
ioread8
(
rspi
->
addr
+
offset
);
...
...
@@ -175,17 +195,103 @@ static u16 rspi_read16(struct rspi_data *rspi, u16 offset)
return
ioread16
(
rspi
->
addr
+
offset
);
}
static
unsigned
char
rspi_calc_spbr
(
struct
rspi_data
*
rspi
)
/* optional functions */
struct
spi_ops
{
int
(
*
set_config_register
)(
struct
rspi_data
*
rspi
,
int
access_size
);
int
(
*
send_pio
)(
struct
rspi_data
*
rspi
,
struct
spi_message
*
mesg
,
struct
spi_transfer
*
t
);
int
(
*
receive_pio
)(
struct
rspi_data
*
rspi
,
struct
spi_message
*
mesg
,
struct
spi_transfer
*
t
);
};
/*
* functions for RSPI
*/
static
int
rspi_set_config_register
(
struct
rspi_data
*
rspi
,
int
access_size
)
{
int
spbr
;
/* Sets output mode(CMOS) and MOSI signal(from previous transfer) */
rspi_write8
(
rspi
,
0x00
,
RSPI_SPPCR
);
/* Sets transfer bit rate */
spbr
=
clk_get_rate
(
rspi
->
clk
)
/
(
2
*
rspi
->
max_speed_hz
)
-
1
;
rspi_write8
(
rspi
,
clamp
(
spbr
,
0
,
255
),
RSPI_SPBR
);
/* Sets number of frames to be used: 1 frame */
rspi_write8
(
rspi
,
0x00
,
RSPI_SPDCR
);
/* Sets RSPCK, SSL, next-access delay value */
rspi_write8
(
rspi
,
0x00
,
RSPI_SPCKD
);
rspi_write8
(
rspi
,
0x00
,
RSPI_SSLND
);
rspi_write8
(
rspi
,
0x00
,
RSPI_SPND
);
/* Sets parity, interrupt mask */
rspi_write8
(
rspi
,
0x00
,
RSPI_SPCR2
);
/* Sets SPCMD */
rspi_write16
(
rspi
,
SPCMD_SPB_8_TO_16
(
access_size
)
|
SPCMD_SSLKP
,
RSPI_SPCMD0
);
/* Sets RSPI mode */
rspi_write8
(
rspi
,
SPCR_MSTR
,
RSPI_SPCR
);
return
0
;
}
/*
* functions for QSPI
*/
static
int
qspi_set_config_register
(
struct
rspi_data
*
rspi
,
int
access_size
)
{
int
tmp
;
unsigned
char
spbr
;
u16
spcmd
;
int
spbr
;
/* Sets output mode(CMOS) and MOSI signal(from previous transfer) */
rspi_write8
(
rspi
,
0x00
,
RSPI_SPPCR
);
/* Sets transfer bit rate */
spbr
=
clk_get_rate
(
rspi
->
clk
)
/
(
2
*
rspi
->
max_speed_hz
);
rspi_write8
(
rspi
,
clamp
(
spbr
,
0
,
255
),
RSPI_SPBR
);
/* Sets number of frames to be used: 1 frame */
rspi_write8
(
rspi
,
0x00
,
RSPI_SPDCR
);
/* Sets RSPCK, SSL, next-access delay value */
rspi_write8
(
rspi
,
0x00
,
RSPI_SPCKD
);
rspi_write8
(
rspi
,
0x00
,
RSPI_SSLND
);
rspi_write8
(
rspi
,
0x00
,
RSPI_SPND
);
/* Data Length Setting */
if
(
access_size
==
8
)
spcmd
=
SPCMD_SPB_8BIT
;
else
if
(
access_size
==
16
)
spcmd
=
SPCMD_SPB_16BIT
;
else
if
(
access_size
==
32
)
spcmd
=
SPCMD_SPB_32BIT
;
spcmd
|=
SPCMD_SCKDEN
|
SPCMD_SLNDEN
|
SPCMD_SSLKP
|
SPCMD_SPNDEN
;
/* Resets transfer data length */
rspi_write32
(
rspi
,
0
,
QSPI_SPBMUL0
);
/* Resets transmit and receive buffer */
rspi_write8
(
rspi
,
SPBFCR_TXRST
|
SPBFCR_RXRST
,
QSPI_SPBFCR
);
/* Sets buffer to allow normal operation */
rspi_write8
(
rspi
,
0x00
,
QSPI_SPBFCR
);
/* Sets SPCMD */
rspi_write16
(
rspi
,
spcmd
,
RSPI_SPCMD0
);
tmp
=
clk_get_rate
(
rspi
->
clk
)
/
(
2
*
rspi
->
max_speed_hz
)
-
1
;
spbr
=
clamp
(
tmp
,
0
,
255
);
/* Enables SPI function in a master mode */
rspi_write8
(
rspi
,
SPCR_SPE
|
SPCR_MSTR
,
RSPI_SPCR
);
return
spbr
;
return
0
;
}
#define set_config_register(spi, n) spi->ops->set_config_register(spi, n)
static
void
rspi_enable_irq
(
struct
rspi_data
*
rspi
,
u8
enable
)
{
rspi_write8
(
rspi
,
rspi_read8
(
rspi
,
RSPI_SPCR
)
|
enable
,
RSPI_SPCR
);
...
...
@@ -220,54 +326,60 @@ static void rspi_negate_ssl(struct rspi_data *rspi)
rspi_write8
(
rspi
,
rspi_read8
(
rspi
,
RSPI_SPCR
)
&
~
SPCR_SPE
,
RSPI_SPCR
);
}
static
int
rspi_set_config_register
(
struct
rspi_data
*
rspi
,
int
access_size
)
static
int
rspi_send_pio
(
struct
rspi_data
*
rspi
,
struct
spi_message
*
mesg
,
struct
spi_transfer
*
t
)
{
/* Sets output mode(CMOS) and MOSI signal(from previous transfer) */
rspi_write8
(
rspi
,
0x00
,
RSPI_SPPCR
);
/* Sets transfer bit rate */
rspi_write8
(
rspi
,
rspi_calc_spbr
(
rspi
),
RSPI_SPBR
);
/* Sets number of frames to be used: 1 frame */
rspi_write8
(
rspi
,
0x00
,
RSPI_SPDCR
);
int
remain
=
t
->
len
;
u8
*
data
;
/* Sets RSPCK, SSL, next-access delay value */
rspi_write8
(
rspi
,
0x00
,
RSPI_SPCKD
);
rspi_write8
(
rspi
,
0x00
,
RSPI_SSLND
);
rspi_write8
(
rspi
,
0x00
,
RSPI_SPND
);
data
=
(
u8
*
)
t
->
tx_buf
;
while
(
remain
>
0
)
{
rspi_write8
(
rspi
,
rspi_read8
(
rspi
,
RSPI_SPCR
)
|
SPCR_TXMD
,
RSPI_SPCR
);
/* Sets parity, interrupt mask */
rspi_write8
(
rspi
,
0x00
,
RSPI_SPCR2
);
if
(
rspi_wait_for_interrupt
(
rspi
,
SPSR_SPTEF
,
SPCR_SPTIE
)
<
0
)
{
dev_err
(
&
rspi
->
master
->
dev
,
"%s: tx empty timeout
\n
"
,
__func__
);
return
-
ETIMEDOUT
;
}
/* Sets SPCMD */
rspi_write16
(
rspi
,
SPCMD_SPB_8_TO_16
(
access_size
)
|
SPCMD_SSLKP
,
RSPI_SPCMD0
);
rspi_write16
(
rspi
,
*
data
,
RSPI_SPDR
);
data
++
;
remain
--
;
}
/*
Sets RSPI mode
*/
rspi_w
rite8
(
rspi
,
SPCR_MSTR
,
RSPI_SPCR
);
/*
Waiting for the last transmition
*/
rspi_w
ait_for_interrupt
(
rspi
,
SPSR_SPTEF
,
SPCR_SPTIE
);
return
0
;
}
static
int
r
spi_send_pio
(
struct
rspi_data
*
rspi
,
struct
spi_message
*
mesg
,
static
int
q
spi_send_pio
(
struct
rspi_data
*
rspi
,
struct
spi_message
*
mesg
,
struct
spi_transfer
*
t
)
{
int
remain
=
t
->
len
;
u8
*
data
;
rspi_write8
(
rspi
,
SPBFCR_TXRST
,
QSPI_SPBFCR
);
rspi_write8
(
rspi
,
0x00
,
QSPI_SPBFCR
);
data
=
(
u8
*
)
t
->
tx_buf
;
while
(
remain
>
0
)
{
rspi_write8
(
rspi
,
rspi_read8
(
rspi
,
RSPI_SPCR
)
|
SPCR_TXMD
,
RSPI_SPCR
);
if
(
rspi_wait_for_interrupt
(
rspi
,
SPSR_SPTEF
,
SPCR_SPTIE
)
<
0
)
{
dev_err
(
&
rspi
->
master
->
dev
,
"%s: tx empty timeout
\n
"
,
__func__
);
return
-
ETIMEDOUT
;
}
rspi_write8
(
rspi
,
*
data
++
,
RSPI_SPDR
);
if
(
rspi_wait_for_interrupt
(
rspi
,
SPSR_SPRF
,
SPCR_SPRIE
)
<
0
)
{
dev_err
(
&
rspi
->
master
->
dev
,
"%s: receive timeout
\n
"
,
__func__
);
return
-
ETIMEDOUT
;
}
rspi_read8
(
rspi
,
RSPI_SPDR
);
rspi_write16
(
rspi
,
*
data
,
RSPI_SPDR
);
data
++
;
remain
--
;
}
...
...
@@ -277,6 +389,8 @@ static int rspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg,
return
0
;
}
#define send_pio(spi, mesg, t) spi->ops->send_pio(spi, mesg, t)
static
void
rspi_dma_complete
(
void
*
arg
)
{
struct
rspi_data
*
rspi
=
arg
;
...
...
@@ -442,6 +556,51 @@ static int rspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg,
return
0
;
}
static
void
qspi_receive_init
(
struct
rspi_data
*
rspi
)
{
unsigned
char
spsr
;
spsr
=
rspi_read8
(
rspi
,
RSPI_SPSR
);
if
(
spsr
&
SPSR_SPRF
)
rspi_read8
(
rspi
,
RSPI_SPDR
);
/* dummy read */
rspi_write8
(
rspi
,
SPBFCR_TXRST
|
SPBFCR_RXRST
,
QSPI_SPBFCR
);
rspi_write8
(
rspi
,
0x00
,
QSPI_SPBFCR
);
}
static
int
qspi_receive_pio
(
struct
rspi_data
*
rspi
,
struct
spi_message
*
mesg
,
struct
spi_transfer
*
t
)
{
int
remain
=
t
->
len
;
u8
*
data
;
qspi_receive_init
(
rspi
);
data
=
(
u8
*
)
t
->
rx_buf
;
while
(
remain
>
0
)
{
if
(
rspi_wait_for_interrupt
(
rspi
,
SPSR_SPTEF
,
SPCR_SPTIE
)
<
0
)
{
dev_err
(
&
rspi
->
master
->
dev
,
"%s: tx empty timeout
\n
"
,
__func__
);
return
-
ETIMEDOUT
;
}
/* dummy write for generate clock */
rspi_write8
(
rspi
,
0x00
,
RSPI_SPDR
);
if
(
rspi_wait_for_interrupt
(
rspi
,
SPSR_SPRF
,
SPCR_SPRIE
)
<
0
)
{
dev_err
(
&
rspi
->
master
->
dev
,
"%s: receive timeout
\n
"
,
__func__
);
return
-
ETIMEDOUT
;
}
/* SPDR allows 8, 16 or 32-bit access */
*
data
++
=
rspi_read8
(
rspi
,
RSPI_SPDR
);
remain
--
;
}
return
0
;
}
#define receive_pio(spi, mesg, t) spi->ops->receive_pio(spi, mesg, t)
static
int
rspi_receive_dma
(
struct
rspi_data
*
rspi
,
struct
spi_transfer
*
t
)
{
struct
scatterlist
sg
,
sg_dummy
;
...
...
@@ -581,7 +740,7 @@ static void rspi_work(struct work_struct *work)
if
(
rspi_is_dma
(
rspi
,
t
))
ret
=
rspi_send_dma
(
rspi
,
t
);
else
ret
=
rspi_
send_pio
(
rspi
,
mesg
,
t
);
ret
=
send_pio
(
rspi
,
mesg
,
t
);
if
(
ret
<
0
)
goto
error
;
}
...
...
@@ -589,7 +748,7 @@ static void rspi_work(struct work_struct *work)
if
(
rspi_is_dma
(
rspi
,
t
))
ret
=
rspi_receive_dma
(
rspi
,
t
);
else
ret
=
r
spi_r
eceive_pio
(
rspi
,
mesg
,
t
);
ret
=
receive_pio
(
rspi
,
mesg
,
t
);
if
(
ret
<
0
)
goto
error
;
}
...
...
@@ -616,7 +775,7 @@ static int rspi_setup(struct spi_device *spi)
spi
->
bits_per_word
=
8
;
rspi
->
max_speed_hz
=
spi
->
max_speed_hz
;
rspi_
set_config_register
(
rspi
,
8
);
set_config_register
(
rspi
,
8
);
return
0
;
}
...
...
@@ -745,7 +904,16 @@ static int rspi_probe(struct platform_device *pdev)
struct
rspi_data
*
rspi
;
int
ret
,
irq
;
char
clk_name
[
16
];
struct
rspi_plat_data
*
rspi_pd
=
pdev
->
dev
.
platform_data
;
const
struct
spi_ops
*
ops
;
const
struct
platform_device_id
*
id_entry
=
pdev
->
id_entry
;
ops
=
(
struct
spi_ops
*
)
id_entry
->
driver_data
;
/* ops parameter check */
if
(
!
ops
->
set_config_register
)
{
dev_err
(
&
pdev
->
dev
,
"there is no set_config_register
\n
"
);
return
-
ENODEV
;
}
/* get base addr */
res
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
if
(
unlikely
(
res
==
NULL
))
{
...
...
@@ -767,7 +935,7 @@ static int rspi_probe(struct platform_device *pdev)
rspi
=
spi_master_get_devdata
(
master
);
platform_set_drvdata
(
pdev
,
rspi
);
rspi
->
ops
=
ops
;
rspi
->
master
=
master
;
rspi
->
addr
=
ioremap
(
res
->
start
,
resource_size
(
res
));
if
(
rspi
->
addr
==
NULL
)
{
...
...
@@ -776,7 +944,7 @@ static int rspi_probe(struct platform_device *pdev)
goto
error1
;
}
snprintf
(
clk_name
,
sizeof
(
clk_name
),
"
rspi%d"
,
pdev
->
id
);
snprintf
(
clk_name
,
sizeof
(
clk_name
),
"
%s%d"
,
id_entry
->
name
,
pdev
->
id
);
rspi
->
clk
=
clk_get
(
&
pdev
->
dev
,
clk_name
);
if
(
IS_ERR
(
rspi
->
clk
))
{
dev_err
(
&
pdev
->
dev
,
"cannot get clock
\n
"
);
...
...
@@ -790,7 +958,10 @@ static int rspi_probe(struct platform_device *pdev)
INIT_WORK
(
&
rspi
->
ws
,
rspi_work
);
init_waitqueue_head
(
&
rspi
->
wait
);
master
->
num_chipselect
=
2
;
master
->
num_chipselect
=
rspi_pd
->
num_chipselect
;
if
(
!
master
->
num_chipselect
)
master
->
num_chipselect
=
2
;
/* default */
master
->
bus_num
=
pdev
->
id
;
master
->
setup
=
rspi_setup
;
master
->
transfer
=
rspi_transfer
;
...
...
@@ -832,11 +1003,32 @@ static int rspi_probe(struct platform_device *pdev)
return
ret
;
}
static
struct
spi_ops
rspi_ops
=
{
.
set_config_register
=
rspi_set_config_register
,
.
send_pio
=
rspi_send_pio
,
.
receive_pio
=
rspi_receive_pio
,
};
static
struct
spi_ops
qspi_ops
=
{
.
set_config_register
=
qspi_set_config_register
,
.
send_pio
=
qspi_send_pio
,
.
receive_pio
=
qspi_receive_pio
,
};
static
struct
platform_device_id
spi_driver_ids
[]
=
{
{
"rspi"
,
(
kernel_ulong_t
)
&
rspi_ops
},
{
"qspi"
,
(
kernel_ulong_t
)
&
qspi_ops
},
{},
};
MODULE_DEVICE_TABLE
(
platform
,
spi_driver_ids
);
static
struct
platform_driver
rspi_driver
=
{
.
probe
=
rspi_probe
,
.
remove
=
rspi_remove
,
.
id_table
=
spi_driver_ids
,
.
driver
=
{
.
name
=
"rspi"
,
.
name
=
"r
enesas_
spi"
,
.
owner
=
THIS_MODULE
,
},
};
...
...
include/linux/spi/rspi.h
View file @
ad14ad73
...
...
@@ -26,6 +26,8 @@ struct rspi_plat_data {
unsigned
int
dma_rx_id
;
unsigned
dma_width_16bit
:
1
;
/* DMAC read/write width = 16-bit */
u16
num_chipselect
;
};
#endif
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