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