Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
R
reform-boundary-uboot
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Jack Humbert
reform-boundary-uboot
Commits
2dc5165e
Commit
2dc5165e
authored
7 years ago
by
Tom Rini
Browse files
Options
Downloads
Plain Diff
Merge
git://git.denx.de/u-boot-spi
parents
f7c9e76f
63018a3e
No related branches found
No related tags found
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
drivers/spi/designware_spi.c
+85
-45
85 additions, 45 deletions
drivers/spi/designware_spi.c
drivers/spi/omap3_spi.c
+4
-2
4 additions, 2 deletions
drivers/spi/omap3_spi.c
with
89 additions
and
47 deletions
drivers/spi/designware_spi.c
+
85
−
45
View file @
2dc5165e
...
...
@@ -10,6 +10,7 @@
* SPDX-License-Identifier: GPL-2.0
*/
#include
<asm-generic/gpio.h>
#include
<common.h>
#include
<clk.h>
#include
<dm.h>
...
...
@@ -18,6 +19,7 @@
#include
<spi.h>
#include
<fdtdec.h>
#include
<linux/compat.h>
#include
<linux/iopoll.h>
#include
<asm/io.h>
DECLARE_GLOBAL_DATA_PTR
;
...
...
@@ -97,6 +99,8 @@ struct dw_spi_priv {
struct
clk
clk
;
unsigned
long
bus_clk_rate
;
struct
gpio_desc
cs_gpio
;
/* External chip-select gpio */
int
bits_per_word
;
u8
cs
;
/* chip select pin */
u8
tmode
;
/* TR/TO/RO/EEPROM */
...
...
@@ -110,24 +114,40 @@ struct dw_spi_priv {
void
*
rx_end
;
};
static
inline
u32
dw_read
l
(
struct
dw_spi_priv
*
priv
,
u32
offset
)
static
inline
u32
dw_read
(
struct
dw_spi_priv
*
priv
,
u32
offset
)
{
return
__raw_readl
(
priv
->
regs
+
offset
);
}
static
inline
void
dw_write
l
(
struct
dw_spi_priv
*
priv
,
u32
offset
,
u32
val
)
static
inline
void
dw_write
(
struct
dw_spi_priv
*
priv
,
u32
offset
,
u32
val
)
{
__raw_writel
(
val
,
priv
->
regs
+
offset
);
}
static
in
line
u16
dw_readw
(
struct
dw_spi_priv
*
priv
,
u32
offset
)
static
in
t
request_gpio_cs
(
struct
udevice
*
bus
)
{
return
__raw_readw
(
priv
->
regs
+
offset
);
}
#if defined(CONFIG_DM_GPIO) && !defined(CONFIG_SPL_BUILD)
struct
dw_spi_priv
*
priv
=
dev_get_priv
(
bus
);
int
ret
;
static
inline
void
dw_writew
(
struct
dw_spi_priv
*
priv
,
u32
offset
,
u16
val
)
{
__raw_writew
(
val
,
priv
->
regs
+
offset
);
/* External chip select gpio line is optional */
ret
=
gpio_request_by_name
(
bus
,
"cs-gpio"
,
0
,
&
priv
->
cs_gpio
,
0
);
if
(
ret
==
-
ENOENT
)
return
0
;
if
(
ret
<
0
)
{
printf
(
"Error: %d: Can't get %s gpio!
\n
"
,
ret
,
bus
->
name
);
return
ret
;
}
if
(
dm_gpio_is_valid
(
&
priv
->
cs_gpio
))
{
dm_gpio_set_dir_flags
(
&
priv
->
cs_gpio
,
GPIOD_IS_OUT
|
GPIOD_IS_OUT_ACTIVE
);
}
debug
(
"%s: used external gpio for CS management
\n
"
,
__func__
);
#endif
return
0
;
}
static
int
dw_spi_ofdata_to_platdata
(
struct
udevice
*
bus
)
...
...
@@ -144,19 +164,19 @@ static int dw_spi_ofdata_to_platdata(struct udevice *bus)
debug
(
"%s: regs=%p max-frequency=%d
\n
"
,
__func__
,
plat
->
regs
,
plat
->
frequency
);
return
0
;
return
request_gpio_cs
(
bus
)
;
}
static
inline
void
spi_enable_chip
(
struct
dw_spi_priv
*
priv
,
int
enable
)
{
dw_write
l
(
priv
,
DW_SPI_SSIENR
,
(
enable
?
1
:
0
));
dw_write
(
priv
,
DW_SPI_SSIENR
,
(
enable
?
1
:
0
));
}
/* Restart the controller, disable all interrupts, clean rx fifo */
static
void
spi_hw_init
(
struct
dw_spi_priv
*
priv
)
{
spi_enable_chip
(
priv
,
0
);
dw_write
l
(
priv
,
DW_SPI_IMR
,
0xff
);
dw_write
(
priv
,
DW_SPI_IMR
,
0xff
);
spi_enable_chip
(
priv
,
1
);
/*
...
...
@@ -167,13 +187,13 @@ static void spi_hw_init(struct dw_spi_priv *priv)
u32
fifo
;
for
(
fifo
=
1
;
fifo
<
256
;
fifo
++
)
{
dw_write
w
(
priv
,
DW_SPI_TXFLTR
,
fifo
);
if
(
fifo
!=
dw_read
w
(
priv
,
DW_SPI_TXFLTR
))
dw_write
(
priv
,
DW_SPI_TXFLTR
,
fifo
);
if
(
fifo
!=
dw_read
(
priv
,
DW_SPI_TXFLTR
))
break
;
}
priv
->
fifo_len
=
(
fifo
==
1
)
?
0
:
fifo
;
dw_write
w
(
priv
,
DW_SPI_TXFLTR
,
0
);
dw_write
(
priv
,
DW_SPI_TXFLTR
,
0
);
}
debug
(
"%s: fifo_len=%d
\n
"
,
__func__
,
priv
->
fifo_len
);
}
...
...
@@ -242,7 +262,7 @@ static inline u32 tx_max(struct dw_spi_priv *priv)
u32
tx_left
,
tx_room
,
rxtx_gap
;
tx_left
=
(
priv
->
tx_end
-
priv
->
tx
)
/
(
priv
->
bits_per_word
>>
3
);
tx_room
=
priv
->
fifo_len
-
dw_read
w
(
priv
,
DW_SPI_TXFLR
);
tx_room
=
priv
->
fifo_len
-
dw_read
(
priv
,
DW_SPI_TXFLR
);
/*
* Another concern is about the tx/rx mismatch, we
...
...
@@ -263,7 +283,7 @@ static inline u32 rx_max(struct dw_spi_priv *priv)
{
u32
rx_left
=
(
priv
->
rx_end
-
priv
->
rx
)
/
(
priv
->
bits_per_word
>>
3
);
return
min_t
(
u32
,
rx_left
,
dw_read
w
(
priv
,
DW_SPI_RXFLR
));
return
min_t
(
u32
,
rx_left
,
dw_read
(
priv
,
DW_SPI_RXFLR
));
}
static
void
dw_writer
(
struct
dw_spi_priv
*
priv
)
...
...
@@ -279,34 +299,22 @@ static void dw_writer(struct dw_spi_priv *priv)
else
txw
=
*
(
u16
*
)(
priv
->
tx
);
}
dw_write
w
(
priv
,
DW_SPI_DR
,
txw
);
dw_write
(
priv
,
DW_SPI_DR
,
txw
);
debug
(
"%s: tx=0x%02x
\n
"
,
__func__
,
txw
);
priv
->
tx
+=
priv
->
bits_per_word
>>
3
;
}
}
static
int
dw_reader
(
struct
dw_spi_priv
*
priv
)
static
void
dw_reader
(
struct
dw_spi_priv
*
priv
)
{
unsigned
start
=
get_timer
(
0
);
u32
max
;
u32
max
=
rx_max
(
priv
);
u16
rxw
;
/* Wait for rx data to be ready */
while
(
rx_max
(
priv
)
==
0
)
{
if
(
get_timer
(
start
)
>
RX_TIMEOUT
)
return
-
ETIMEDOUT
;
}
max
=
rx_max
(
priv
);
while
(
max
--
)
{
rxw
=
dw_read
w
(
priv
,
DW_SPI_DR
);
rxw
=
dw_read
(
priv
,
DW_SPI_DR
);
debug
(
"%s: rx=0x%02x
\n
"
,
__func__
,
rxw
);
/*
* Care about rx only if the transfer's original "rx" is
* not null
*/
/* Care about rx if the transfer's original "rx" is not null */
if
(
priv
->
rx_end
-
priv
->
len
)
{
if
(
priv
->
bits_per_word
==
8
)
*
(
u8
*
)(
priv
->
rx
)
=
rxw
;
...
...
@@ -315,24 +323,30 @@ static int dw_reader(struct dw_spi_priv *priv)
}
priv
->
rx
+=
priv
->
bits_per_word
>>
3
;
}
return
0
;
}
static
int
poll_transfer
(
struct
dw_spi_priv
*
priv
)
{
int
ret
;
do
{
dw_writer
(
priv
);
ret
=
dw_reader
(
priv
);
if
(
ret
<
0
)
return
ret
;
dw_reader
(
priv
);
}
while
(
priv
->
rx_end
>
priv
->
rx
);
return
0
;
}
static
void
external_cs_manage
(
struct
udevice
*
dev
,
bool
on
)
{
#if defined(CONFIG_DM_GPIO) && !defined(CONFIG_SPL_BUILD)
struct
dw_spi_priv
*
priv
=
dev_get_priv
(
dev
->
parent
);
if
(
!
dm_gpio_is_valid
(
&
priv
->
cs_gpio
))
return
;
dm_gpio_set_value
(
&
priv
->
cs_gpio
,
on
?
1
:
0
);
#endif
}
static
int
dw_spi_xfer
(
struct
udevice
*
dev
,
unsigned
int
bitlen
,
const
void
*
dout
,
void
*
din
,
unsigned
long
flags
)
{
...
...
@@ -342,6 +356,7 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
u8
*
rx
=
din
;
int
ret
=
0
;
u32
cr0
=
0
;
u32
val
;
u32
cs
;
/* spi core configured to do 8 bit transfers */
...
...
@@ -350,6 +365,10 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
return
-
1
;
}
/* Start the transaction if necessary. */
if
(
flags
&
SPI_XFER_BEGIN
)
external_cs_manage
(
dev
,
false
);
cr0
=
(
priv
->
bits_per_word
-
1
)
|
(
priv
->
type
<<
SPI_FRF_OFFSET
)
|
(
priv
->
mode
<<
SPI_MODE_OFFSET
)
|
(
priv
->
tmode
<<
SPI_TMOD_OFFSET
);
...
...
@@ -359,7 +378,11 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
else
if
(
rx
)
priv
->
tmode
=
SPI_TMOD_RO
;
else
priv
->
tmode
=
SPI_TMOD_TO
;
/*
* In transmit only mode (SPI_TMOD_TO) input FIFO never gets
* any data which breaks our logic in poll_transfer() above.
*/
priv
->
tmode
=
SPI_TMOD_TR
;
cr0
&=
~
SPI_TMOD_MASK
;
cr0
|=
(
priv
->
tmode
<<
SPI_TMOD_OFFSET
);
...
...
@@ -377,8 +400,8 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
debug
(
"%s: cr0=%08x
\n
"
,
__func__
,
cr0
);
/* Reprogram cr0 only if changed */
if
(
dw_read
w
(
priv
,
DW_SPI_CTRL0
)
!=
cr0
)
dw_write
w
(
priv
,
DW_SPI_CTRL0
,
cr0
);
if
(
dw_read
(
priv
,
DW_SPI_CTRL0
)
!=
cr0
)
dw_write
(
priv
,
DW_SPI_CTRL0
,
cr0
);
/*
* Configure the desired SS (slave select 0...3) in the controller
...
...
@@ -386,7 +409,7 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
* automatically. So no cs_activate() etc is needed in this driver.
*/
cs
=
spi_chip_select
(
dev
);
dw_write
l
(
priv
,
DW_SPI_SER
,
1
<<
cs
);
dw_write
(
priv
,
DW_SPI_SER
,
1
<<
cs
);
/* Enable controller after writing control registers */
spi_enable_chip
(
priv
,
1
);
...
...
@@ -394,6 +417,23 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
/* Start transfer in a polling loop */
ret
=
poll_transfer
(
priv
);
/*
* Wait for current transmit operation to complete.
* Otherwise if some data still exists in Tx FIFO it can be
* silently flushed, i.e. dropped on disabling of the controller,
* which happens when writing 0 to DW_SPI_SSIENR which happens
* in the beginning of new transfer.
*/
if
(
readl_poll_timeout
(
priv
->
regs
+
DW_SPI_SR
,
val
,
!
(
val
&
SR_TF_EMPT
)
||
(
val
&
SR_BUSY
),
RX_TIMEOUT
*
1000
))
{
ret
=
-
ETIMEDOUT
;
}
/* Stop the transaction if necessary */
if
(
flags
&
SPI_XFER_END
)
external_cs_manage
(
dev
,
true
);
return
ret
;
}
...
...
@@ -412,7 +452,7 @@ static int dw_spi_set_speed(struct udevice *bus, uint speed)
/* clk_div doesn't support odd number */
clk_div
=
priv
->
bus_clk_rate
/
speed
;
clk_div
=
(
clk_div
+
1
)
&
0xfffe
;
dw_write
l
(
priv
,
DW_SPI_BAUDR
,
clk_div
);
dw_write
(
priv
,
DW_SPI_BAUDR
,
clk_div
);
/* Enable controller after writing control registers */
spi_enable_chip
(
priv
,
1
);
...
...
This diff is collapsed.
Click to expand it.
drivers/spi/omap3_spi.c
+
4
−
2
View file @
2dc5165e
...
...
@@ -630,8 +630,10 @@ static int omap3_spi_probe(struct udevice *dev)
(
struct
omap2_mcspi_platform_config
*
)
dev_get_driver_data
(
dev
);
priv
->
regs
=
(
struct
mcspi
*
)(
devfdt_get_addr
(
dev
)
+
data
->
regs_offset
);
priv
->
pin_dir
=
fdtdec_get_uint
(
blob
,
node
,
"ti,pindir-d0-out-d1-in"
,
MCSPI_PINDIR_D0_IN_D1_OUT
);
if
(
fdtdec_get_bool
(
blob
,
node
,
"ti,pindir-d0-out-d1-in"
))
priv
->
pin_dir
=
MCSPI_PINDIR_D0_OUT_D1_IN
;
else
priv
->
pin_dir
=
MCSPI_PINDIR_D0_IN_D1_OUT
;
priv
->
wordlen
=
SPI_DEFAULT_WORDLEN
;
return
0
;
}
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment