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
2cc6e2e0
Commit
2cc6e2e0
authored
Oct 11, 2013
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'spi/topic/s3c64xx' into spi-loop
parents
b158935f
ebd805cc
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
98 additions
and
50 deletions
+98
-50
Documentation/driver-model/devres.txt
Documentation/driver-model/devres.txt
+3
-0
drivers/spi/Kconfig
drivers/spi/Kconfig
+1
-1
drivers/spi/spi-s3c64xx.c
drivers/spi/spi-s3c64xx.c
+57
-49
drivers/spi/spi.c
drivers/spi/spi.c
+35
-0
include/linux/spi/spi.h
include/linux/spi/spi.h
+2
-0
No files found.
Documentation/driver-model/devres.txt
View file @
2cc6e2e0
...
...
@@ -302,3 +302,6 @@ PHY
SLAVE DMA ENGINE
devm_acpi_dma_controller_register()
SPI
devm_spi_register_master()
drivers/spi/Kconfig
View file @
2cc6e2e0
...
...
@@ -393,7 +393,7 @@ config SPI_S3C24XX_FIQ
config SPI_S3C64XX
tristate "Samsung S3C64XX series type SPI"
depends on
(ARCH_S3C24XX || ARCH_S3C64XX || ARCH_S5P64X0 || ARCH_EXYNOS)
depends on
PLAT_SAMSUNG
select S3C64XX_DMA if ARCH_S3C64XX
help
SPI driver for Samsung S3C64XX and newer SoCs.
...
...
drivers/spi/spi-s3c64xx.c
View file @
2cc6e2e0
...
...
@@ -205,7 +205,6 @@ struct s3c64xx_spi_driver_data {
#endif
struct
s3c64xx_spi_port_config
*
port_conf
;
unsigned
int
port_id
;
unsigned
long
gpios
[
4
];
bool
cs_gpio
;
};
...
...
@@ -559,25 +558,18 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
static
inline
void
enable_cs
(
struct
s3c64xx_spi_driver_data
*
sdd
,
struct
spi_device
*
spi
)
{
struct
s3c64xx_spi_csinfo
*
cs
;
if
(
sdd
->
tgl_spi
!=
NULL
)
{
/* If last device toggled after mssg */
if
(
sdd
->
tgl_spi
!=
spi
)
{
/* if last mssg on diff device */
/* Deselect the last toggled device */
cs
=
sdd
->
tgl_spi
->
controller_data
;
if
(
sdd
->
cs_gpio
)
gpio_set_value
(
cs
->
line
,
if
(
spi
->
cs_gpio
>=
0
)
gpio_set_value
(
spi
->
cs_gpio
,
spi
->
mode
&
SPI_CS_HIGH
?
0
:
1
);
}
sdd
->
tgl_spi
=
NULL
;
}
cs
=
spi
->
controller_data
;
if
(
sdd
->
cs_gpio
)
gpio_set_value
(
cs
->
line
,
spi
->
mode
&
SPI_CS_HIGH
?
1
:
0
);
/* Start the signals */
writel
(
0
,
sdd
->
regs
+
S3C64XX_SPI_SLAVE_SEL
);
if
(
spi
->
cs_gpio
>=
0
)
gpio_set_value
(
spi
->
cs_gpio
,
spi
->
mode
&
SPI_CS_HIGH
?
1
:
0
);
}
static
u32
s3c64xx_spi_wait_for_timeout
(
struct
s3c64xx_spi_driver_data
*
sdd
,
...
...
@@ -702,16 +694,11 @@ static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd,
static
inline
void
disable_cs
(
struct
s3c64xx_spi_driver_data
*
sdd
,
struct
spi_device
*
spi
)
{
struct
s3c64xx_spi_csinfo
*
cs
=
spi
->
controller_data
;
if
(
sdd
->
tgl_spi
==
spi
)
sdd
->
tgl_spi
=
NULL
;
if
(
sdd
->
cs_gpio
)
gpio_set_value
(
cs
->
line
,
spi
->
mode
&
SPI_CS_HIGH
?
0
:
1
);
/* Quiese the signals */
writel
(
S3C64XX_SPI_SLAVE_SIG_INACT
,
sdd
->
regs
+
S3C64XX_SPI_SLAVE_SEL
);
if
(
spi
->
cs_gpio
>=
0
)
gpio_set_value
(
spi
->
cs_gpio
,
spi
->
mode
&
SPI_CS_HIGH
?
0
:
1
);
}
static
void
s3c64xx_spi_config
(
struct
s3c64xx_spi_driver_data
*
sdd
)
...
...
@@ -927,6 +914,9 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master,
s3c64xx_spi_config
(
sdd
);
}
/* Slave Select */
enable_cs
(
sdd
,
spi
);
/* Polling method for xfers not bigger than FIFO capacity */
use_dma
=
0
;
if
(
!
is_polling
(
sdd
)
&&
...
...
@@ -942,8 +932,11 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master,
enable_datapath
(
sdd
,
spi
,
xfer
,
use_dma
);
/* Slave Select */
enable_cs
(
sdd
,
spi
);
/* Start the signals */
writel
(
0
,
sdd
->
regs
+
S3C64XX_SPI_SLAVE_SEL
);
/* Start the signals */
writel
(
0
,
sdd
->
regs
+
S3C64XX_SPI_SLAVE_SEL
);
spin_unlock_irqrestore
(
&
sdd
->
lock
,
flags
);
...
...
@@ -968,6 +961,8 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master,
goto
out
;
}
flush_fifo
(
sdd
);
if
(
xfer
->
delay_usecs
)
udelay
(
xfer
->
delay_usecs
);
...
...
@@ -980,15 +975,17 @@ static int s3c64xx_spi_transfer_one_message(struct spi_master *master,
}
msg
->
actual_length
+=
xfer
->
len
;
flush_fifo
(
sdd
);
}
out:
if
(
!
cs_toggle
||
status
)
if
(
!
cs_toggle
||
status
)
{
/* Quiese the signals */
writel
(
S3C64XX_SPI_SLAVE_SIG_INACT
,
sdd
->
regs
+
S3C64XX_SPI_SLAVE_SEL
);
disable_cs
(
sdd
,
spi
);
else
}
else
{
sdd
->
tgl_spi
=
spi
;
}
s3c64xx_spi_unmap_mssg
(
sdd
,
msg
);
...
...
@@ -1089,6 +1086,8 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
cs
->
line
,
err
);
goto
err_gpio_req
;
}
spi
->
cs_gpio
=
cs
->
line
;
}
spi_set_ctldata
(
spi
,
cs
);
...
...
@@ -1135,11 +1134,13 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
}
pm_runtime_put
(
&
sdd
->
pdev
->
dev
);
writel
(
S3C64XX_SPI_SLAVE_SIG_INACT
,
sdd
->
regs
+
S3C64XX_SPI_SLAVE_SEL
);
disable_cs
(
sdd
,
spi
);
return
0
;
setup_exit:
/* setup() returns with device de-selected */
writel
(
S3C64XX_SPI_SLAVE_SIG_INACT
,
sdd
->
regs
+
S3C64XX_SPI_SLAVE_SEL
);
disable_cs
(
sdd
,
spi
);
gpio_free
(
cs
->
line
);
...
...
@@ -1158,8 +1159,8 @@ static void s3c64xx_spi_cleanup(struct spi_device *spi)
struct
s3c64xx_spi_driver_data
*
sdd
;
sdd
=
spi_master_get_devdata
(
spi
->
master
);
if
(
cs
&&
sdd
->
cs_gpio
)
{
gpio_free
(
cs
->
line
);
if
(
spi
->
cs_gpio
)
{
gpio_free
(
spi
->
cs_gpio
);
if
(
spi
->
dev
.
of_node
)
kfree
(
cs
);
}
...
...
@@ -1448,9 +1449,11 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
S3C64XX_SPI_INT_TX_OVERRUN_EN
|
S3C64XX_SPI_INT_TX_UNDERRUN_EN
,
sdd
->
regs
+
S3C64XX_SPI_INT_EN
);
if
(
spi_register_master
(
master
))
{
dev_err
(
&
pdev
->
dev
,
"cannot register SPI master
\n
"
);
ret
=
-
EBUSY
;
pm_runtime_enable
(
&
pdev
->
dev
);
ret
=
devm_spi_register_master
(
&
pdev
->
dev
,
master
);
if
(
ret
!=
0
)
{
dev_err
(
&
pdev
->
dev
,
"cannot register SPI master: %d
\n
"
,
ret
);
goto
err3
;
}
...
...
@@ -1460,8 +1463,6 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
mem_res
,
sdd
->
rx_dma
.
dmach
,
sdd
->
tx_dma
.
dmach
);
pm_runtime_enable
(
&
pdev
->
dev
);
return
0
;
err3:
...
...
@@ -1481,16 +1482,12 @@ static int s3c64xx_spi_remove(struct platform_device *pdev)
pm_runtime_disable
(
&
pdev
->
dev
);
spi_unregister_master
(
master
);
writel
(
0
,
sdd
->
regs
+
S3C64XX_SPI_INT_EN
);
clk_disable_unprepare
(
sdd
->
src_clk
);
clk_disable_unprepare
(
sdd
->
clk
);
spi_master_put
(
master
);
return
0
;
}
...
...
@@ -1548,9 +1545,17 @@ static int s3c64xx_spi_runtime_resume(struct device *dev)
{
struct
spi_master
*
master
=
dev_get_drvdata
(
dev
);
struct
s3c64xx_spi_driver_data
*
sdd
=
spi_master_get_devdata
(
master
);
int
ret
;
clk_prepare_enable
(
sdd
->
src_clk
);
clk_prepare_enable
(
sdd
->
clk
);
ret
=
clk_prepare_enable
(
sdd
->
src_clk
);
if
(
ret
!=
0
)
return
ret
;
ret
=
clk_prepare_enable
(
sdd
->
clk
);
if
(
ret
!=
0
)
{
clk_disable_unprepare
(
sdd
->
src_clk
);
return
ret
;
}
return
0
;
}
...
...
@@ -1636,6 +1641,18 @@ static struct platform_device_id s3c64xx_spi_driver_ids[] = {
};
static
const
struct
of_device_id
s3c64xx_spi_dt_match
[]
=
{
{
.
compatible
=
"samsung,s3c2443-spi"
,
.
data
=
(
void
*
)
&
s3c2443_spi_port_config
,
},
{
.
compatible
=
"samsung,s3c6410-spi"
,
.
data
=
(
void
*
)
&
s3c6410_spi_port_config
,
},
{
.
compatible
=
"samsung,s5pc100-spi"
,
.
data
=
(
void
*
)
&
s5pc100_spi_port_config
,
},
{
.
compatible
=
"samsung,s5pv210-spi"
,
.
data
=
(
void
*
)
&
s5pv210_spi_port_config
,
},
{
.
compatible
=
"samsung,exynos4210-spi"
,
.
data
=
(
void
*
)
&
exynos4_spi_port_config
,
},
...
...
@@ -1653,22 +1670,13 @@ static struct platform_driver s3c64xx_spi_driver = {
.
pm
=
&
s3c64xx_spi_pm
,
.
of_match_table
=
of_match_ptr
(
s3c64xx_spi_dt_match
),
},
.
probe
=
s3c64xx_spi_probe
,
.
remove
=
s3c64xx_spi_remove
,
.
id_table
=
s3c64xx_spi_driver_ids
,
};
MODULE_ALIAS
(
"platform:s3c64xx-spi"
);
static
int
__init
s3c64xx_spi_init
(
void
)
{
return
platform_driver_probe
(
&
s3c64xx_spi_driver
,
s3c64xx_spi_probe
);
}
subsys_initcall
(
s3c64xx_spi_init
);
static
void
__exit
s3c64xx_spi_exit
(
void
)
{
platform_driver_unregister
(
&
s3c64xx_spi_driver
);
}
module_exit
(
s3c64xx_spi_exit
);
module_platform_driver
(
s3c64xx_spi_driver
);
MODULE_AUTHOR
(
"Jaswinder Singh <jassi.brar@samsung.com>"
);
MODULE_DESCRIPTION
(
"S3C64XX SPI Controller Driver"
);
...
...
drivers/spi/spi.c
View file @
2cc6e2e0
...
...
@@ -1370,6 +1370,41 @@ int spi_register_master(struct spi_master *master)
}
EXPORT_SYMBOL_GPL
(
spi_register_master
);
static
void
devm_spi_unregister
(
struct
device
*
dev
,
void
*
res
)
{
spi_unregister_master
(
*
(
struct
spi_master
**
)
res
);
}
/**
* dev_spi_register_master - register managed SPI master controller
* @dev: device managing SPI master
* @master: initialized master, originally from spi_alloc_master()
* Context: can sleep
*
* Register a SPI device as with spi_register_master() which will
* automatically be unregister
*/
int
devm_spi_register_master
(
struct
device
*
dev
,
struct
spi_master
*
master
)
{
struct
spi_master
**
ptr
;
int
ret
;
ptr
=
devres_alloc
(
devm_spi_unregister
,
sizeof
(
*
ptr
),
GFP_KERNEL
);
if
(
!
ptr
)
return
-
ENOMEM
;
ret
=
spi_register_master
(
master
);
if
(
ret
!=
0
)
{
*
ptr
=
master
;
devres_add
(
dev
,
ptr
);
}
else
{
devres_free
(
ptr
);
}
return
ret
;
}
EXPORT_SYMBOL_GPL
(
devm_spi_register_master
);
static
int
__unregister
(
struct
device
*
dev
,
void
*
null
)
{
spi_unregister_device
(
to_spi_device
(
dev
));
...
...
include/linux/spi/spi.h
View file @
2cc6e2e0
...
...
@@ -462,6 +462,8 @@ extern struct spi_master *
spi_alloc_master
(
struct
device
*
host
,
unsigned
size
);
extern
int
spi_register_master
(
struct
spi_master
*
master
);
extern
int
devm_spi_register_master
(
struct
device
*
dev
,
struct
spi_master
*
master
);
extern
void
spi_unregister_master
(
struct
spi_master
*
master
);
extern
struct
spi_master
*
spi_busnum_to_master
(
u16
busnum
);
...
...
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