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
bc266185
Commit
bc266185
authored
Jan 30, 2012
by
Grant Likely
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'spi/s3c64xx' of
git://git.kernel.org/pub/scm/linux/kernel/git/broonie/misc
Conflicts: drivers/spi/spi-s3c64xx.c
parents
dcd6c922
b97b6621
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
103 additions
and
11 deletions
+103
-11
drivers/spi/spi-s3c64xx.c
drivers/spi/spi-s3c64xx.c
+103
-11
No files found.
drivers/spi/spi-s3c64xx.c
View file @
bc266185
...
@@ -20,10 +20,12 @@
...
@@ -20,10 +20,12 @@
#include <linux/init.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/workqueue.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi.h>
#include <mach/dma.h>
#include <mach/dma.h>
...
@@ -153,6 +155,7 @@ struct s3c64xx_spi_dma_data {
...
@@ -153,6 +155,7 @@ struct s3c64xx_spi_dma_data {
* @tx_dmach: Controller's DMA channel for Tx.
* @tx_dmach: Controller's DMA channel for Tx.
* @sfr_start: BUS address of SPI controller regs.
* @sfr_start: BUS address of SPI controller regs.
* @regs: Pointer to ioremap'ed controller registers.
* @regs: Pointer to ioremap'ed controller registers.
* @irq: interrupt
* @xfer_completion: To indicate completion of xfer task.
* @xfer_completion: To indicate completion of xfer task.
* @cur_mode: Stores the active configuration of the controller.
* @cur_mode: Stores the active configuration of the controller.
* @cur_bpw: Stores the active bits per word settings.
* @cur_bpw: Stores the active bits per word settings.
...
@@ -780,6 +783,8 @@ static void s3c64xx_spi_work(struct work_struct *work)
...
@@ -780,6 +783,8 @@ static void s3c64xx_spi_work(struct work_struct *work)
while
(
!
acquire_dma
(
sdd
))
while
(
!
acquire_dma
(
sdd
))
msleep
(
10
);
msleep
(
10
);
pm_runtime_get_sync
(
&
sdd
->
pdev
->
dev
);
spin_lock_irqsave
(
&
sdd
->
lock
,
flags
);
spin_lock_irqsave
(
&
sdd
->
lock
,
flags
);
while
(
!
list_empty
(
&
sdd
->
queue
)
while
(
!
list_empty
(
&
sdd
->
queue
)
...
@@ -808,6 +813,8 @@ static void s3c64xx_spi_work(struct work_struct *work)
...
@@ -808,6 +813,8 @@ static void s3c64xx_spi_work(struct work_struct *work)
/* Free DMA channels */
/* Free DMA channels */
sdd
->
ops
->
release
(
sdd
->
rx_dma
.
ch
,
&
s3c64xx_spi_dma_client
);
sdd
->
ops
->
release
(
sdd
->
rx_dma
.
ch
,
&
s3c64xx_spi_dma_client
);
sdd
->
ops
->
release
(
sdd
->
tx_dma
.
ch
,
&
s3c64xx_spi_dma_client
);
sdd
->
ops
->
release
(
sdd
->
tx_dma
.
ch
,
&
s3c64xx_spi_dma_client
);
pm_runtime_put
(
&
sdd
->
pdev
->
dev
);
}
}
static
int
s3c64xx_spi_transfer
(
struct
spi_device
*
spi
,
static
int
s3c64xx_spi_transfer
(
struct
spi_device
*
spi
,
...
@@ -890,6 +897,8 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
...
@@ -890,6 +897,8 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
goto
setup_exit
;
goto
setup_exit
;
}
}
pm_runtime_get_sync
(
&
sdd
->
pdev
->
dev
);
/* Check if we can provide the requested rate */
/* Check if we can provide the requested rate */
if
(
!
sci
->
clk_from_cmu
)
{
if
(
!
sci
->
clk_from_cmu
)
{
u32
psr
,
speed
;
u32
psr
,
speed
;
...
@@ -922,6 +931,8 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
...
@@ -922,6 +931,8 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
err
=
-
EINVAL
;
err
=
-
EINVAL
;
}
}
pm_runtime_put
(
&
sdd
->
pdev
->
dev
);
setup_exit:
setup_exit:
/* setup() returns with device de-selected */
/* setup() returns with device de-selected */
...
@@ -930,6 +941,33 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
...
@@ -930,6 +941,33 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
return
err
;
return
err
;
}
}
static
irqreturn_t
s3c64xx_spi_irq
(
int
irq
,
void
*
data
)
{
struct
s3c64xx_spi_driver_data
*
sdd
=
data
;
struct
spi_master
*
spi
=
sdd
->
master
;
unsigned
int
val
;
val
=
readl
(
sdd
->
regs
+
S3C64XX_SPI_PENDING_CLR
);
val
&=
S3C64XX_SPI_PND_RX_OVERRUN_CLR
|
S3C64XX_SPI_PND_RX_UNDERRUN_CLR
|
S3C64XX_SPI_PND_TX_OVERRUN_CLR
|
S3C64XX_SPI_PND_TX_UNDERRUN_CLR
;
writel
(
val
,
sdd
->
regs
+
S3C64XX_SPI_PENDING_CLR
);
if
(
val
&
S3C64XX_SPI_PND_RX_OVERRUN_CLR
)
dev_err
(
&
spi
->
dev
,
"RX overrun
\n
"
);
if
(
val
&
S3C64XX_SPI_PND_RX_UNDERRUN_CLR
)
dev_err
(
&
spi
->
dev
,
"RX underrun
\n
"
);
if
(
val
&
S3C64XX_SPI_PND_TX_OVERRUN_CLR
)
dev_err
(
&
spi
->
dev
,
"TX overrun
\n
"
);
if
(
val
&
S3C64XX_SPI_PND_TX_UNDERRUN_CLR
)
dev_err
(
&
spi
->
dev
,
"TX underrun
\n
"
);
return
IRQ_HANDLED
;
}
static
void
s3c64xx_spi_hwinit
(
struct
s3c64xx_spi_driver_data
*
sdd
,
int
channel
)
static
void
s3c64xx_spi_hwinit
(
struct
s3c64xx_spi_driver_data
*
sdd
,
int
channel
)
{
{
struct
s3c64xx_spi_info
*
sci
=
sdd
->
cntrlr_info
;
struct
s3c64xx_spi_info
*
sci
=
sdd
->
cntrlr_info
;
...
@@ -970,7 +1008,7 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
...
@@ -970,7 +1008,7 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
struct
s3c64xx_spi_driver_data
*
sdd
;
struct
s3c64xx_spi_driver_data
*
sdd
;
struct
s3c64xx_spi_info
*
sci
;
struct
s3c64xx_spi_info
*
sci
;
struct
spi_master
*
master
;
struct
spi_master
*
master
;
int
ret
;
int
ret
,
irq
;
char
clk_name
[
16
];
char
clk_name
[
16
];
if
(
pdev
->
id
<
0
)
{
if
(
pdev
->
id
<
0
)
{
...
@@ -1006,6 +1044,12 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
...
@@ -1006,6 +1044,12 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
return
-
ENXIO
;
return
-
ENXIO
;
}
}
irq
=
platform_get_irq
(
pdev
,
0
);
if
(
irq
<
0
)
{
dev_warn
(
&
pdev
->
dev
,
"Failed to get IRQ: %d
\n
"
,
irq
);
return
irq
;
}
master
=
spi_alloc_master
(
&
pdev
->
dev
,
master
=
spi_alloc_master
(
&
pdev
->
dev
,
sizeof
(
struct
s3c64xx_spi_driver_data
));
sizeof
(
struct
s3c64xx_spi_driver_data
));
if
(
master
==
NULL
)
{
if
(
master
==
NULL
)
{
...
@@ -1100,10 +1144,21 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
...
@@ -1100,10 +1144,21 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
INIT_WORK
(
&
sdd
->
work
,
s3c64xx_spi_work
);
INIT_WORK
(
&
sdd
->
work
,
s3c64xx_spi_work
);
INIT_LIST_HEAD
(
&
sdd
->
queue
);
INIT_LIST_HEAD
(
&
sdd
->
queue
);
ret
=
request_irq
(
irq
,
s3c64xx_spi_irq
,
0
,
"spi-s3c64xx"
,
sdd
);
if
(
ret
!=
0
)
{
dev_err
(
&
pdev
->
dev
,
"Failed to request IRQ %d: %d
\n
"
,
irq
,
ret
);
goto
err8
;
}
writel
(
S3C64XX_SPI_INT_RX_OVERRUN_EN
|
S3C64XX_SPI_INT_RX_UNDERRUN_EN
|
S3C64XX_SPI_INT_TX_OVERRUN_EN
|
S3C64XX_SPI_INT_TX_UNDERRUN_EN
,
sdd
->
regs
+
S3C64XX_SPI_INT_EN
);
if
(
spi_register_master
(
master
))
{
if
(
spi_register_master
(
master
))
{
dev_err
(
&
pdev
->
dev
,
"cannot register SPI master
\n
"
);
dev_err
(
&
pdev
->
dev
,
"cannot register SPI master
\n
"
);
ret
=
-
EBUSY
;
ret
=
-
EBUSY
;
goto
err
8
;
goto
err
9
;
}
}
dev_dbg
(
&
pdev
->
dev
,
"Samsung SoC SPI Driver loaded for Bus SPI-%d "
dev_dbg
(
&
pdev
->
dev
,
"Samsung SoC SPI Driver loaded for Bus SPI-%d "
...
@@ -1113,8 +1168,12 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
...
@@ -1113,8 +1168,12 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
mem_res
->
end
,
mem_res
->
start
,
mem_res
->
end
,
mem_res
->
start
,
sdd
->
rx_dma
.
dmach
,
sdd
->
tx_dma
.
dmach
);
sdd
->
rx_dma
.
dmach
,
sdd
->
tx_dma
.
dmach
);
pm_runtime_enable
(
&
pdev
->
dev
);
return
0
;
return
0
;
err9:
free_irq
(
irq
,
sdd
);
err8:
err8:
destroy_workqueue
(
sdd
->
workqueue
);
destroy_workqueue
(
sdd
->
workqueue
);
err7:
err7:
...
@@ -1144,6 +1203,8 @@ static int s3c64xx_spi_remove(struct platform_device *pdev)
...
@@ -1144,6 +1203,8 @@ static int s3c64xx_spi_remove(struct platform_device *pdev)
struct
resource
*
mem_res
;
struct
resource
*
mem_res
;
unsigned
long
flags
;
unsigned
long
flags
;
pm_runtime_disable
(
&
pdev
->
dev
);
spin_lock_irqsave
(
&
sdd
->
lock
,
flags
);
spin_lock_irqsave
(
&
sdd
->
lock
,
flags
);
sdd
->
state
|=
SUSPND
;
sdd
->
state
|=
SUSPND
;
spin_unlock_irqrestore
(
&
sdd
->
lock
,
flags
);
spin_unlock_irqrestore
(
&
sdd
->
lock
,
flags
);
...
@@ -1153,6 +1214,10 @@ static int s3c64xx_spi_remove(struct platform_device *pdev)
...
@@ -1153,6 +1214,10 @@ static int s3c64xx_spi_remove(struct platform_device *pdev)
spi_unregister_master
(
master
);
spi_unregister_master
(
master
);
writel
(
0
,
sdd
->
regs
+
S3C64XX_SPI_INT_EN
);
free_irq
(
platform_get_irq
(
pdev
,
0
),
sdd
);
destroy_workqueue
(
sdd
->
workqueue
);
destroy_workqueue
(
sdd
->
workqueue
);
clk_disable
(
sdd
->
src_clk
);
clk_disable
(
sdd
->
src_clk
);
...
@@ -1174,9 +1239,9 @@ static int s3c64xx_spi_remove(struct platform_device *pdev)
...
@@ -1174,9 +1239,9 @@ static int s3c64xx_spi_remove(struct platform_device *pdev)
}
}
#ifdef CONFIG_PM
#ifdef CONFIG_PM
static
int
s3c64xx_spi_suspend
(
struct
platform_device
*
pdev
,
pm_message_t
state
)
static
int
s3c64xx_spi_suspend
(
struct
device
*
dev
)
{
{
struct
spi_master
*
master
=
spi_master_get
(
platform_get_drvdata
(
p
dev
));
struct
spi_master
*
master
=
spi_master_get
(
dev_get_drvdata
(
dev
));
struct
s3c64xx_spi_driver_data
*
sdd
=
spi_master_get_devdata
(
master
);
struct
s3c64xx_spi_driver_data
*
sdd
=
spi_master_get_devdata
(
master
);
unsigned
long
flags
;
unsigned
long
flags
;
...
@@ -1196,9 +1261,10 @@ static int s3c64xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
...
@@ -1196,9 +1261,10 @@ static int s3c64xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
return
0
;
return
0
;
}
}
static
int
s3c64xx_spi_resume
(
struct
platform_device
*
p
dev
)
static
int
s3c64xx_spi_resume
(
struct
device
*
dev
)
{
{
struct
spi_master
*
master
=
spi_master_get
(
platform_get_drvdata
(
pdev
));
struct
platform_device
*
pdev
=
to_platform_device
(
dev
);
struct
spi_master
*
master
=
spi_master_get
(
dev_get_drvdata
(
dev
));
struct
s3c64xx_spi_driver_data
*
sdd
=
spi_master_get_devdata
(
master
);
struct
s3c64xx_spi_driver_data
*
sdd
=
spi_master_get_devdata
(
master
);
struct
s3c64xx_spi_info
*
sci
=
sdd
->
cntrlr_info
;
struct
s3c64xx_spi_info
*
sci
=
sdd
->
cntrlr_info
;
unsigned
long
flags
;
unsigned
long
flags
;
...
@@ -1217,19 +1283,45 @@ static int s3c64xx_spi_resume(struct platform_device *pdev)
...
@@ -1217,19 +1283,45 @@ static int s3c64xx_spi_resume(struct platform_device *pdev)
return
0
;
return
0
;
}
}
#else
#define s3c64xx_spi_suspend NULL
#define s3c64xx_spi_resume NULL
#endif
/* CONFIG_PM */
#endif
/* CONFIG_PM */
#ifdef CONFIG_PM_RUNTIME
static
int
s3c64xx_spi_runtime_suspend
(
struct
device
*
dev
)
{
struct
spi_master
*
master
=
spi_master_get
(
dev_get_drvdata
(
dev
));
struct
s3c64xx_spi_driver_data
*
sdd
=
spi_master_get_devdata
(
master
);
clk_disable
(
sdd
->
clk
);
clk_disable
(
sdd
->
src_clk
);
return
0
;
}
static
int
s3c64xx_spi_runtime_resume
(
struct
device
*
dev
)
{
struct
spi_master
*
master
=
spi_master_get
(
dev_get_drvdata
(
dev
));
struct
s3c64xx_spi_driver_data
*
sdd
=
spi_master_get_devdata
(
master
);
clk_enable
(
sdd
->
src_clk
);
clk_enable
(
sdd
->
clk
);
return
0
;
}
#endif
/* CONFIG_PM_RUNTIME */
static
const
struct
dev_pm_ops
s3c64xx_spi_pm
=
{
SET_SYSTEM_SLEEP_PM_OPS
(
s3c64xx_spi_suspend
,
s3c64xx_spi_resume
)
SET_RUNTIME_PM_OPS
(
s3c64xx_spi_runtime_suspend
,
s3c64xx_spi_runtime_resume
,
NULL
)
};
static
struct
platform_driver
s3c64xx_spi_driver
=
{
static
struct
platform_driver
s3c64xx_spi_driver
=
{
.
driver
=
{
.
driver
=
{
.
name
=
"s3c64xx-spi"
,
.
name
=
"s3c64xx-spi"
,
.
owner
=
THIS_MODULE
,
.
owner
=
THIS_MODULE
,
.
pm
=
&
s3c64xx_spi_pm
,
},
},
.
remove
=
s3c64xx_spi_remove
,
.
remove
=
s3c64xx_spi_remove
,
.
suspend
=
s3c64xx_spi_suspend
,
.
resume
=
s3c64xx_spi_resume
,
};
};
MODULE_ALIAS
(
"platform:s3c64xx-spi"
);
MODULE_ALIAS
(
"platform:s3c64xx-spi"
);
...
...
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