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
4374f332
Commit
4374f332
authored
Sep 01, 2013
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'spi/topic/omap-100k' into spi-next
parents
45bb5065
2d0c6148
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
78 additions
and
198 deletions
+78
-198
drivers/spi/spi-omap-100k.c
drivers/spi/spi-omap-100k.c
+78
-198
No files found.
drivers/spi/spi-omap-100k.c
View file @
4374f332
...
@@ -83,11 +83,6 @@
...
@@ -83,11 +83,6 @@
#define SPI_SHUTDOWN 1
#define SPI_SHUTDOWN 1
struct
omap1_spi100k
{
struct
omap1_spi100k
{
struct
work_struct
work
;
/* lock protects queue and registers */
spinlock_t
lock
;
struct
list_head
msg_queue
;
struct
spi_master
*
master
;
struct
spi_master
*
master
;
struct
clk
*
ick
;
struct
clk
*
ick
;
struct
clk
*
fck
;
struct
clk
*
fck
;
...
@@ -104,8 +99,6 @@ struct omap1_spi100k_cs {
...
@@ -104,8 +99,6 @@ struct omap1_spi100k_cs {
int
word_len
;
int
word_len
;
};
};
static
struct
workqueue_struct
*
omap1_spi100k_wq
;
#define MOD_REG_BIT(val, mask, set) do { \
#define MOD_REG_BIT(val, mask, set) do { \
if (set) \
if (set) \
val |= mask; \
val |= mask; \
...
@@ -310,170 +303,102 @@ static int omap1_spi100k_setup(struct spi_device *spi)
...
@@ -310,170 +303,102 @@ static int omap1_spi100k_setup(struct spi_device *spi)
spi100k_open
(
spi
->
master
);
spi100k_open
(
spi
->
master
);
clk_enable
(
spi100k
->
ick
);
clk_
prepare_
enable
(
spi100k
->
ick
);
clk_enable
(
spi100k
->
fck
);
clk_
prepare_
enable
(
spi100k
->
fck
);
ret
=
omap1_spi100k_setup_transfer
(
spi
,
NULL
);
ret
=
omap1_spi100k_setup_transfer
(
spi
,
NULL
);
clk_disable
(
spi100k
->
ick
);
clk_disable
_unprepare
(
spi100k
->
ick
);
clk_disable
(
spi100k
->
fck
);
clk_disable
_unprepare
(
spi100k
->
fck
);
return
ret
;
return
ret
;
}
}
static
void
omap1_spi100k_work
(
struct
work_struct
*
work
)
static
int
omap1_spi100k_prepare_hardware
(
struct
spi_master
*
master
)
{
{
struct
omap1_spi100k
*
spi100k
;
struct
omap1_spi100k
*
spi100k
=
spi_master_get_devdata
(
master
);
int
status
=
0
;
spi100k
=
container_of
(
work
,
struct
omap1_spi100k
,
wor
k
);
clk_prepare_enable
(
spi100k
->
ic
k
);
spin_lock_irq
(
&
spi100k
->
lo
ck
);
clk_prepare_enable
(
spi100k
->
f
ck
);
clk_enable
(
spi100k
->
ick
)
;
return
0
;
clk_enable
(
spi100k
->
fck
);
}
/* We only enable one channel at a time -- the one whose message is
static
int
omap1_spi100k_transfer_one_message
(
struct
spi_master
*
master
,
* at the head of the queue -- although this controller would gladly
struct
spi_message
*
m
)
* arbitrate among multiple channels. This corresponds to "single
{
* channel" master mode. As a side effect, we need to manage the
struct
omap1_spi100k
*
spi100k
=
spi_master_get_devdata
(
master
);
* chipselect with the FORCE bit ... CS != channel enable.
struct
spi_device
*
spi
=
m
->
spi
;
*/
struct
spi_transfer
*
t
=
NULL
;
while
(
!
list_empty
(
&
spi100k
->
msg_queue
))
{
int
cs_active
=
0
;
struct
spi_message
*
m
;
int
par_override
=
0
;
struct
spi_device
*
spi
;
int
status
=
0
;
struct
spi_transfer
*
t
=
NULL
;
int
cs_active
=
0
;
list_for_each_entry
(
t
,
&
m
->
transfers
,
transfer_list
)
{
struct
omap1_spi100k_cs
*
cs
;
if
(
t
->
tx_buf
==
NULL
&&
t
->
rx_buf
==
NULL
&&
t
->
len
)
{
int
par_override
=
0
;
status
=
-
EINVAL
;
break
;
m
=
container_of
(
spi100k
->
msg_queue
.
next
,
struct
spi_message
,
}
queue
);
if
(
par_override
||
t
->
speed_hz
||
t
->
bits_per_word
)
{
par_override
=
1
;
list_del_init
(
&
m
->
queue
);
status
=
omap1_spi100k_setup_transfer
(
spi
,
t
);
spin_unlock_irq
(
&
spi100k
->
lock
);
if
(
status
<
0
)
spi
=
m
->
spi
;
cs
=
spi
->
controller_state
;
list_for_each_entry
(
t
,
&
m
->
transfers
,
transfer_list
)
{
if
(
t
->
tx_buf
==
NULL
&&
t
->
rx_buf
==
NULL
&&
t
->
len
)
{
status
=
-
EINVAL
;
break
;
break
;
}
if
(
!
t
->
speed_hz
&&
!
t
->
bits_per_word
)
if
(
par_override
||
t
->
speed_hz
||
t
->
bits_per_word
)
{
par_override
=
0
;
par_override
=
1
;
}
status
=
omap1_spi100k_setup_transfer
(
spi
,
t
);
if
(
status
<
0
)
break
;
if
(
!
t
->
speed_hz
&&
!
t
->
bits_per_word
)
par_override
=
0
;
}
if
(
!
cs_active
)
{
if
(
!
cs_active
)
{
omap1_spi100k_force_cs
(
spi100k
,
1
);
omap1_spi100k_force_cs
(
spi100k
,
1
);
cs_active
=
1
;
cs_active
=
1
;
}
}
if
(
t
->
len
)
{
if
(
t
->
len
)
{
unsigned
count
;
unsigned
count
;
count
=
omap1_spi100k_txrx_pio
(
spi
,
t
);
count
=
omap1_spi100k_txrx_pio
(
spi
,
t
);
m
->
actual_length
+=
count
;
m
->
actual_length
+=
count
;
if
(
count
!=
t
->
len
)
{
if
(
count
!=
t
->
len
)
{
status
=
-
EIO
;
status
=
-
EIO
;
break
;
break
;
}
}
}
}
if
(
t
->
delay_usecs
)
if
(
t
->
delay_usecs
)
udelay
(
t
->
delay_usecs
);
udelay
(
t
->
delay_usecs
);
/* ignore the "leave it on after last xfer" hint */
/* ignore the "leave it on after last xfer" hint */
if
(
t
->
cs_change
)
{
if
(
t
->
cs_change
)
{
omap1_spi100k_force_cs
(
spi100k
,
0
);
omap1_spi100k_force_cs
(
spi100k
,
0
);
cs_active
=
0
;
cs_active
=
0
;
}
}
/* Restore defaults if they were overriden */
if
(
par_override
)
{
par_override
=
0
;
status
=
omap1_spi100k_setup_transfer
(
spi
,
NULL
);
}
}
}
if
(
cs_active
)
/* Restore defaults if they were overriden */
omap1_spi100k_force_cs
(
spi100k
,
0
);
if
(
par_override
)
{
par_override
=
0
;
status
=
omap1_spi100k_setup_transfer
(
spi
,
NULL
);
}
m
->
status
=
status
;
if
(
cs_active
)
m
->
complete
(
m
->
context
);
omap1_spi100k_force_cs
(
spi100k
,
0
);
spin_lock_irq
(
&
spi100k
->
lock
);
m
->
status
=
status
;
}
clk_disable
(
spi100k
->
ick
);
spi_finalize_current_message
(
master
);
clk_disable
(
spi100k
->
fck
);
spin_unlock_irq
(
&
spi100k
->
lock
);
if
(
status
<
0
)
return
status
;
printk
(
KERN_WARNING
"spi transfer failed with %d
\n
"
,
status
);
}
}
static
int
omap1_spi100k_
transfer
(
struct
spi_device
*
spi
,
struct
spi_message
*
m
)
static
int
omap1_spi100k_
unprepare_hardware
(
struct
spi_master
*
master
)
{
{
struct
omap1_spi100k
*
spi100k
;
struct
omap1_spi100k
*
spi100k
=
spi_master_get_devdata
(
master
);
unsigned
long
flags
;
struct
spi_transfer
*
t
;
m
->
actual_length
=
0
;
m
->
status
=
-
EINPROGRESS
;
spi100k
=
spi_master_get_devdata
(
spi
->
master
);
/* Don't accept new work if we're shutting down */
if
(
spi100k
->
state
==
SPI_SHUTDOWN
)
return
-
ESHUTDOWN
;
/* reject invalid messages and transfers */
if
(
list_empty
(
&
m
->
transfers
)
||
!
m
->
complete
)
return
-
EINVAL
;
list_for_each_entry
(
t
,
&
m
->
transfers
,
transfer_list
)
{
const
void
*
tx_buf
=
t
->
tx_buf
;
void
*
rx_buf
=
t
->
rx_buf
;
unsigned
len
=
t
->
len
;
if
(
t
->
speed_hz
>
OMAP1_SPI100K_MAX_FREQ
||
(
len
&&
!
(
rx_buf
||
tx_buf
)))
{
dev_dbg
(
&
spi
->
dev
,
"transfer: %d Hz, %d %s%s, %d bpw
\n
"
,
t
->
speed_hz
,
len
,
tx_buf
?
"tx"
:
""
,
rx_buf
?
"rx"
:
""
,
t
->
bits_per_word
);
return
-
EINVAL
;
}
if
(
t
->
speed_hz
&&
t
->
speed_hz
<
OMAP1_SPI100K_MAX_FREQ
/
(
1
<<
16
))
{
dev_dbg
(
&
spi
->
dev
,
"%d Hz max exceeds %d
\n
"
,
t
->
speed_hz
,
OMAP1_SPI100K_MAX_FREQ
/
(
1
<<
16
));
return
-
EINVAL
;
}
}
spin_lock_irqsave
(
&
spi100k
->
lock
,
flags
);
list_add_tail
(
&
m
->
queue
,
&
spi100k
->
msg_queue
);
queue_work
(
omap1_spi100k_wq
,
&
spi100k
->
work
);
spin_unlock_irqrestore
(
&
spi100k
->
lock
,
flags
);
return
0
;
clk_disable_unprepare
(
spi100k
->
ick
)
;
}
clk_disable_unprepare
(
spi100k
->
fck
);
static
int
omap1_spi100k_reset
(
struct
omap1_spi100k
*
spi100k
)
{
return
0
;
return
0
;
}
}
...
@@ -496,11 +421,15 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
...
@@ -496,11 +421,15 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
master
->
bus_num
=
pdev
->
id
;
master
->
bus_num
=
pdev
->
id
;
master
->
setup
=
omap1_spi100k_setup
;
master
->
setup
=
omap1_spi100k_setup
;
master
->
transfer
=
omap1_spi100k_transfer
;
master
->
transfer_one_message
=
omap1_spi100k_transfer_one_message
;
master
->
prepare_transfer_hardware
=
omap1_spi100k_prepare_hardware
;
master
->
unprepare_transfer_hardware
=
omap1_spi100k_unprepare_hardware
;
master
->
cleanup
=
NULL
;
master
->
cleanup
=
NULL
;
master
->
num_chipselect
=
2
;
master
->
num_chipselect
=
2
;
master
->
mode_bits
=
MODEBITS
;
master
->
mode_bits
=
MODEBITS
;
master
->
bits_per_word_mask
=
SPI_BPW_RANGE_MASK
(
4
,
32
);
master
->
bits_per_word_mask
=
SPI_BPW_RANGE_MASK
(
4
,
32
);
master
->
min_speed_hz
=
OMAP1_SPI100K_MAX_FREQ
/
(
1
<<
16
);
master
->
max_speed_hz
=
OMAP1_SPI100K_MAX_FREQ
;
platform_set_drvdata
(
pdev
,
master
);
platform_set_drvdata
(
pdev
,
master
);
...
@@ -514,40 +443,29 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
...
@@ -514,40 +443,29 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
*/
*/
spi100k
->
base
=
(
void
__iomem
*
)
pdev
->
dev
.
platform_data
;
spi100k
->
base
=
(
void
__iomem
*
)
pdev
->
dev
.
platform_data
;
INIT_WORK
(
&
spi100k
->
work
,
omap1_spi100k_work
);
spi100k
->
ick
=
devm_clk_get
(
&
pdev
->
dev
,
"ick"
);
spin_lock_init
(
&
spi100k
->
lock
);
INIT_LIST_HEAD
(
&
spi100k
->
msg_queue
);
spi100k
->
ick
=
clk_get
(
&
pdev
->
dev
,
"ick"
);
if
(
IS_ERR
(
spi100k
->
ick
))
{
if
(
IS_ERR
(
spi100k
->
ick
))
{
dev_dbg
(
&
pdev
->
dev
,
"can't get spi100k_ick
\n
"
);
dev_dbg
(
&
pdev
->
dev
,
"can't get spi100k_ick
\n
"
);
status
=
PTR_ERR
(
spi100k
->
ick
);
status
=
PTR_ERR
(
spi100k
->
ick
);
goto
err
1
;
goto
err
;
}
}
spi100k
->
fck
=
clk_get
(
&
pdev
->
dev
,
"fck"
);
spi100k
->
fck
=
devm_
clk_get
(
&
pdev
->
dev
,
"fck"
);
if
(
IS_ERR
(
spi100k
->
fck
))
{
if
(
IS_ERR
(
spi100k
->
fck
))
{
dev_dbg
(
&
pdev
->
dev
,
"can't get spi100k_fck
\n
"
);
dev_dbg
(
&
pdev
->
dev
,
"can't get spi100k_fck
\n
"
);
status
=
PTR_ERR
(
spi100k
->
fck
);
status
=
PTR_ERR
(
spi100k
->
fck
);
goto
err
2
;
goto
err
;
}
}
if
(
omap1_spi100k_reset
(
spi100k
)
<
0
)
goto
err3
;
status
=
spi_register_master
(
master
);
status
=
spi_register_master
(
master
);
if
(
status
<
0
)
if
(
status
<
0
)
goto
err
3
;
goto
err
;
spi100k
->
state
=
SPI_RUNNING
;
spi100k
->
state
=
SPI_RUNNING
;
return
status
;
return
status
;
err3:
err:
clk_put
(
spi100k
->
fck
);
err2:
clk_put
(
spi100k
->
ick
);
err1:
spi_master_put
(
master
);
spi_master_put
(
master
);
return
status
;
return
status
;
}
}
...
@@ -557,33 +475,14 @@ static int omap1_spi100k_remove(struct platform_device *pdev)
...
@@ -557,33 +475,14 @@ static int omap1_spi100k_remove(struct platform_device *pdev)
struct
spi_master
*
master
;
struct
spi_master
*
master
;
struct
omap1_spi100k
*
spi100k
;
struct
omap1_spi100k
*
spi100k
;
struct
resource
*
r
;
struct
resource
*
r
;
unsigned
limit
=
500
;
unsigned
long
flags
;
int
status
=
0
;
int
status
=
0
;
master
=
platform_get_drvdata
(
pdev
);
master
=
platform_get_drvdata
(
pdev
);
spi100k
=
spi_master_get_devdata
(
master
);
spi100k
=
spi_master_get_devdata
(
master
);
spin_lock_irqsave
(
&
spi100k
->
lock
,
flags
);
spi100k
->
state
=
SPI_SHUTDOWN
;
while
(
!
list_empty
(
&
spi100k
->
msg_queue
)
&&
limit
--
)
{
spin_unlock_irqrestore
(
&
spi100k
->
lock
,
flags
);
msleep
(
10
);
spin_lock_irqsave
(
&
spi100k
->
lock
,
flags
);
}
if
(
!
list_empty
(
&
spi100k
->
msg_queue
))
status
=
-
EBUSY
;
spin_unlock_irqrestore
(
&
spi100k
->
lock
,
flags
);
if
(
status
!=
0
)
if
(
status
!=
0
)
return
status
;
return
status
;
clk_put
(
spi100k
->
fck
);
clk_put
(
spi100k
->
ick
);
r
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
r
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
spi_unregister_master
(
master
);
spi_unregister_master
(
master
);
...
@@ -596,30 +495,11 @@ static struct platform_driver omap1_spi100k_driver = {
...
@@ -596,30 +495,11 @@ static struct platform_driver omap1_spi100k_driver = {
.
name
=
"omap1_spi100k"
,
.
name
=
"omap1_spi100k"
,
.
owner
=
THIS_MODULE
,
.
owner
=
THIS_MODULE
,
},
},
.
probe
=
omap1_spi100k_probe
,
.
remove
=
omap1_spi100k_remove
,
.
remove
=
omap1_spi100k_remove
,
};
};
module_platform_driver
(
omap1_spi100k_driver
);
static
int
__init
omap1_spi100k_init
(
void
)
{
omap1_spi100k_wq
=
create_singlethread_workqueue
(
omap1_spi100k_driver
.
driver
.
name
);
if
(
omap1_spi100k_wq
==
NULL
)
return
-
1
;
return
platform_driver_probe
(
&
omap1_spi100k_driver
,
omap1_spi100k_probe
);
}
static
void
__exit
omap1_spi100k_exit
(
void
)
{
platform_driver_unregister
(
&
omap1_spi100k_driver
);
destroy_workqueue
(
omap1_spi100k_wq
);
}
module_init
(
omap1_spi100k_init
);
module_exit
(
omap1_spi100k_exit
);
MODULE_DESCRIPTION
(
"OMAP7xx SPI 100k controller driver"
);
MODULE_DESCRIPTION
(
"OMAP7xx SPI 100k controller driver"
);
MODULE_AUTHOR
(
"Fabrice Crohas <fcrohas@gmail.com>"
);
MODULE_AUTHOR
(
"Fabrice Crohas <fcrohas@gmail.com>"
);
...
...
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