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
f7867cff
Commit
f7867cff
authored
Mar 16, 2020
by
Daniel Lezcano
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'timers/drivers/timer-ti-dm' into timers/drivers/next
parents
05852445
02e6d546
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
119 additions
and
82 deletions
+119
-82
drivers/clocksource/timer-ti-dm.c
drivers/clocksource/timer-ti-dm.c
+109
-74
drivers/pwm/pwm-omap-dmtimer.c
drivers/pwm/pwm-omap-dmtimer.c
+5
-3
include/clocksource/timer-ti-dm.h
include/clocksource/timer-ti-dm.h
+2
-2
include/linux/platform_data/dmtimer-omap.h
include/linux/platform_data/dmtimer-omap.h
+3
-3
No files found.
drivers/clocksource/timer-ti-dm.c
View file @
f7867cff
// SPDX-License-Identifier: GPL-2.0+
/*
* linux/arch/arm/plat-omap/dmtimer.c
*
...
...
@@ -15,28 +16,11 @@
*
* Copyright (C) 2009 Texas Instruments
* Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/cpu_pm.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/device.h>
...
...
@@ -109,6 +93,47 @@ static void omap_timer_restore_context(struct omap_dm_timer *timer)
timer
->
context
.
tclr
);
}
static
void
omap_timer_save_context
(
struct
omap_dm_timer
*
timer
)
{
timer
->
context
.
tclr
=
omap_dm_timer_read_reg
(
timer
,
OMAP_TIMER_CTRL_REG
);
timer
->
context
.
twer
=
omap_dm_timer_read_reg
(
timer
,
OMAP_TIMER_WAKEUP_EN_REG
);
timer
->
context
.
tldr
=
omap_dm_timer_read_reg
(
timer
,
OMAP_TIMER_LOAD_REG
);
timer
->
context
.
tmar
=
omap_dm_timer_read_reg
(
timer
,
OMAP_TIMER_MATCH_REG
);
timer
->
context
.
tier
=
readl_relaxed
(
timer
->
irq_ena
);
timer
->
context
.
tsicr
=
omap_dm_timer_read_reg
(
timer
,
OMAP_TIMER_IF_CTRL_REG
);
}
static
int
omap_timer_context_notifier
(
struct
notifier_block
*
nb
,
unsigned
long
cmd
,
void
*
v
)
{
struct
omap_dm_timer
*
timer
;
timer
=
container_of
(
nb
,
struct
omap_dm_timer
,
nb
);
switch
(
cmd
)
{
case
CPU_CLUSTER_PM_ENTER
:
if
((
timer
->
capability
&
OMAP_TIMER_ALWON
)
||
!
atomic_read
(
&
timer
->
enabled
))
break
;
omap_timer_save_context
(
timer
);
break
;
case
CPU_CLUSTER_PM_ENTER_FAILED
:
case
CPU_CLUSTER_PM_EXIT
:
if
((
timer
->
capability
&
OMAP_TIMER_ALWON
)
||
!
atomic_read
(
&
timer
->
enabled
))
break
;
omap_timer_restore_context
(
timer
);
break
;
}
return
NOTIFY_OK
;
}
static
int
omap_dm_timer_reset
(
struct
omap_dm_timer
*
timer
)
{
u32
l
,
timeout
=
100000
;
...
...
@@ -196,21 +221,7 @@ static int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
static
void
omap_dm_timer_enable
(
struct
omap_dm_timer
*
timer
)
{
int
c
;
pm_runtime_get_sync
(
&
timer
->
pdev
->
dev
);
if
(
!
(
timer
->
capability
&
OMAP_TIMER_ALWON
))
{
if
(
timer
->
get_context_loss_count
)
{
c
=
timer
->
get_context_loss_count
(
&
timer
->
pdev
->
dev
);
if
(
c
!=
timer
->
ctx_loss_count
)
{
omap_timer_restore_context
(
timer
);
timer
->
ctx_loss_count
=
c
;
}
}
else
{
omap_timer_restore_context
(
timer
);
}
}
}
static
void
omap_dm_timer_disable
(
struct
omap_dm_timer
*
timer
)
...
...
@@ -477,7 +488,7 @@ __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
int
omap_dm_timer_trigger
(
struct
omap_dm_timer
*
timer
)
{
if
(
unlikely
(
!
timer
||
pm_runtime_suspended
(
&
timer
->
pdev
->
dev
)))
{
if
(
unlikely
(
!
timer
||
!
atomic_read
(
&
timer
->
enabled
)))
{
pr_err
(
"%s: timer not available or enabled.
\n
"
,
__func__
);
return
-
EINVAL
;
}
...
...
@@ -501,8 +512,6 @@ static int omap_dm_timer_start(struct omap_dm_timer *timer)
omap_dm_timer_write_reg
(
timer
,
OMAP_TIMER_CTRL_REG
,
l
);
}
/* Save the context */
timer
->
context
.
tclr
=
l
;
return
0
;
}
...
...
@@ -518,37 +527,19 @@ static int omap_dm_timer_stop(struct omap_dm_timer *timer)
__omap_dm_timer_stop
(
timer
,
timer
->
posted
,
rate
);
/*
* Since the register values are computed and written within
* __omap_dm_timer_stop, we need to use read to retrieve the
* context.
*/
timer
->
context
.
tclr
=
omap_dm_timer_read_reg
(
timer
,
OMAP_TIMER_CTRL_REG
);
omap_dm_timer_disable
(
timer
);
return
0
;
}
static
int
omap_dm_timer_set_load
(
struct
omap_dm_timer
*
timer
,
int
autoreload
,
static
int
omap_dm_timer_set_load
(
struct
omap_dm_timer
*
timer
,
unsigned
int
load
)
{
u32
l
;
if
(
unlikely
(
!
timer
))
return
-
EINVAL
;
omap_dm_timer_enable
(
timer
);
l
=
omap_dm_timer_read_reg
(
timer
,
OMAP_TIMER_CTRL_REG
);
if
(
autoreload
)
l
|=
OMAP_TIMER_CTRL_AR
;
else
l
&=
~
OMAP_TIMER_CTRL_AR
;
omap_dm_timer_write_reg
(
timer
,
OMAP_TIMER_CTRL_REG
,
l
);
omap_dm_timer_write_reg
(
timer
,
OMAP_TIMER_LOAD_REG
,
load
);
/* Save the context */
timer
->
context
.
tclr
=
l
;
timer
->
context
.
tldr
=
load
;
omap_dm_timer_disable
(
timer
);
return
0
;
}
...
...
@@ -570,15 +561,12 @@ static int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
omap_dm_timer_write_reg
(
timer
,
OMAP_TIMER_MATCH_REG
,
match
);
omap_dm_timer_write_reg
(
timer
,
OMAP_TIMER_CTRL_REG
,
l
);
/* Save the context */
timer
->
context
.
tclr
=
l
;
timer
->
context
.
tmar
=
match
;
omap_dm_timer_disable
(
timer
);
return
0
;
}
static
int
omap_dm_timer_set_pwm
(
struct
omap_dm_timer
*
timer
,
int
def_on
,
int
toggle
,
int
trigger
)
int
toggle
,
int
trigger
,
int
autoreload
)
{
u32
l
;
...
...
@@ -588,20 +576,34 @@ static int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
omap_dm_timer_enable
(
timer
);
l
=
omap_dm_timer_read_reg
(
timer
,
OMAP_TIMER_CTRL_REG
);
l
&=
~
(
OMAP_TIMER_CTRL_GPOCFG
|
OMAP_TIMER_CTRL_SCPWM
|
OMAP_TIMER_CTRL_PT
|
(
0x03
<<
10
));
OMAP_TIMER_CTRL_PT
|
(
0x03
<<
10
)
|
OMAP_TIMER_CTRL_AR
);
if
(
def_on
)
l
|=
OMAP_TIMER_CTRL_SCPWM
;
if
(
toggle
)
l
|=
OMAP_TIMER_CTRL_PT
;
l
|=
trigger
<<
10
;
if
(
autoreload
)
l
|=
OMAP_TIMER_CTRL_AR
;
omap_dm_timer_write_reg
(
timer
,
OMAP_TIMER_CTRL_REG
,
l
);
/* Save the context */
timer
->
context
.
tclr
=
l
;
omap_dm_timer_disable
(
timer
);
return
0
;
}
static
int
omap_dm_timer_get_pwm_status
(
struct
omap_dm_timer
*
timer
)
{
u32
l
;
if
(
unlikely
(
!
timer
))
return
-
EINVAL
;
omap_dm_timer_enable
(
timer
);
l
=
omap_dm_timer_read_reg
(
timer
,
OMAP_TIMER_CTRL_REG
);
omap_dm_timer_disable
(
timer
);
return
l
;
}
static
int
omap_dm_timer_set_prescaler
(
struct
omap_dm_timer
*
timer
,
int
prescaler
)
{
...
...
@@ -619,8 +621,6 @@ static int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer,
}
omap_dm_timer_write_reg
(
timer
,
OMAP_TIMER_CTRL_REG
,
l
);
/* Save the context */
timer
->
context
.
tclr
=
l
;
omap_dm_timer_disable
(
timer
);
return
0
;
}
...
...
@@ -634,9 +634,6 @@ static int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
omap_dm_timer_enable
(
timer
);
__omap_dm_timer_int_enable
(
timer
,
value
);
/* Save the context */
timer
->
context
.
tier
=
value
;
timer
->
context
.
twer
=
value
;
omap_dm_timer_disable
(
timer
);
return
0
;
}
...
...
@@ -664,9 +661,6 @@ static int omap_dm_timer_set_int_disable(struct omap_dm_timer *timer, u32 mask)
l
=
omap_dm_timer_read_reg
(
timer
,
OMAP_TIMER_WAKEUP_EN_REG
)
&
~
mask
;
omap_dm_timer_write_reg
(
timer
,
OMAP_TIMER_WAKEUP_EN_REG
,
l
);
/* Save the context */
timer
->
context
.
tier
&=
~
mask
;
timer
->
context
.
twer
&=
~
mask
;
omap_dm_timer_disable
(
timer
);
return
0
;
}
...
...
@@ -675,7 +669,7 @@ static unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
{
unsigned
int
l
;
if
(
unlikely
(
!
timer
||
pm_runtime_suspended
(
&
timer
->
pdev
->
dev
)))
{
if
(
unlikely
(
!
timer
||
!
atomic_read
(
&
timer
->
enabled
)))
{
pr_err
(
"%s: timer not available or enabled.
\n
"
,
__func__
);
return
0
;
}
...
...
@@ -687,7 +681,7 @@ static unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
static
int
omap_dm_timer_write_status
(
struct
omap_dm_timer
*
timer
,
unsigned
int
value
)
{
if
(
unlikely
(
!
timer
||
pm_runtime_suspended
(
&
timer
->
pdev
->
dev
)))
if
(
unlikely
(
!
timer
||
!
atomic_read
(
&
timer
->
enabled
)))
return
-
EINVAL
;
__omap_dm_timer_write_status
(
timer
,
value
);
...
...
@@ -697,7 +691,7 @@ static int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int
static
unsigned
int
omap_dm_timer_read_counter
(
struct
omap_dm_timer
*
timer
)
{
if
(
unlikely
(
!
timer
||
pm_runtime_suspended
(
&
timer
->
pdev
->
dev
)))
{
if
(
unlikely
(
!
timer
||
!
atomic_read
(
&
timer
->
enabled
)))
{
pr_err
(
"%s: timer not iavailable or enabled.
\n
"
,
__func__
);
return
0
;
}
...
...
@@ -707,7 +701,7 @@ static unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
static
int
omap_dm_timer_write_counter
(
struct
omap_dm_timer
*
timer
,
unsigned
int
value
)
{
if
(
unlikely
(
!
timer
||
pm_runtime_suspended
(
&
timer
->
pdev
->
dev
)))
{
if
(
unlikely
(
!
timer
||
!
atomic_read
(
&
timer
->
enabled
)))
{
pr_err
(
"%s: timer not available or enabled.
\n
"
,
__func__
);
return
-
EINVAL
;
}
...
...
@@ -735,6 +729,37 @@ int omap_dm_timers_active(void)
return
0
;
}
static
int
__maybe_unused
omap_dm_timer_runtime_suspend
(
struct
device
*
dev
)
{
struct
omap_dm_timer
*
timer
=
dev_get_drvdata
(
dev
);
atomic_set
(
&
timer
->
enabled
,
0
);
if
(
timer
->
capability
&
OMAP_TIMER_ALWON
||
!
timer
->
func_base
)
return
0
;
omap_timer_save_context
(
timer
);
return
0
;
}
static
int
__maybe_unused
omap_dm_timer_runtime_resume
(
struct
device
*
dev
)
{
struct
omap_dm_timer
*
timer
=
dev_get_drvdata
(
dev
);
if
(
!
(
timer
->
capability
&
OMAP_TIMER_ALWON
)
&&
timer
->
func_base
)
omap_timer_restore_context
(
timer
);
atomic_set
(
&
timer
->
enabled
,
1
);
return
0
;
}
static
const
struct
dev_pm_ops
omap_dm_timer_pm_ops
=
{
SET_RUNTIME_PM_OPS
(
omap_dm_timer_runtime_suspend
,
omap_dm_timer_runtime_resume
,
NULL
)
};
static
const
struct
of_device_id
omap_timer_match
[];
/**
...
...
@@ -776,6 +801,8 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
if
(
IS_ERR
(
timer
->
io_base
))
return
PTR_ERR
(
timer
->
io_base
);
platform_set_drvdata
(
pdev
,
timer
);
if
(
dev
->
of_node
)
{
if
(
of_find_property
(
dev
->
of_node
,
"ti,timer-alwon"
,
NULL
))
timer
->
capability
|=
OMAP_TIMER_ALWON
;
...
...
@@ -789,7 +816,11 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
timer
->
id
=
pdev
->
id
;
timer
->
capability
=
pdata
->
timer_capability
;
timer
->
reserved
=
omap_dm_timer_reserved_systimer
(
timer
->
id
);
timer
->
get_context_loss_count
=
pdata
->
get_context_loss_count
;
}
if
(
!
(
timer
->
capability
&
OMAP_TIMER_ALWON
))
{
timer
->
nb
.
notifier_call
=
omap_timer_context_notifier
;
cpu_pm_register_notifier
(
&
timer
->
nb
);
}
if
(
pdata
)
...
...
@@ -843,6 +874,8 @@ static int omap_dm_timer_remove(struct platform_device *pdev)
list_for_each_entry
(
timer
,
&
omap_timer_list
,
node
)
if
(
!
strcmp
(
dev_name
(
&
timer
->
pdev
->
dev
),
dev_name
(
&
pdev
->
dev
)))
{
if
(
!
(
timer
->
capability
&
OMAP_TIMER_ALWON
))
cpu_pm_unregister_notifier
(
&
timer
->
nb
);
list_del
(
&
timer
->
node
);
ret
=
0
;
break
;
...
...
@@ -871,6 +904,7 @@ static const struct omap_dm_timer_ops dmtimer_ops = {
.
set_load
=
omap_dm_timer_set_load
,
.
set_match
=
omap_dm_timer_set_match
,
.
set_pwm
=
omap_dm_timer_set_pwm
,
.
get_pwm_status
=
omap_dm_timer_get_pwm_status
,
.
set_prescaler
=
omap_dm_timer_set_prescaler
,
.
read_counter
=
omap_dm_timer_read_counter
,
.
write_counter
=
omap_dm_timer_write_counter
,
...
...
@@ -921,6 +955,7 @@ static struct platform_driver omap_dm_timer_driver = {
.
driver
=
{
.
name
=
"omap_timer"
,
.
of_match_table
=
of_match_ptr
(
omap_timer_match
),
.
pm
=
&
omap_dm_timer_pm_ops
,
},
};
...
...
drivers/pwm/pwm-omap-dmtimer.c
View file @
f7867cff
...
...
@@ -183,7 +183,7 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
if
(
timer_active
)
omap
->
pdata
->
stop
(
omap
->
dm_timer
);
omap
->
pdata
->
set_load
(
omap
->
dm_timer
,
true
,
load_value
);
omap
->
pdata
->
set_load
(
omap
->
dm_timer
,
load_value
);
omap
->
pdata
->
set_match
(
omap
->
dm_timer
,
true
,
match_value
);
dev_dbg
(
chip
->
dev
,
"load value: %#08x (%d), match value: %#08x (%d)
\n
"
,
...
...
@@ -192,7 +192,8 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
omap
->
pdata
->
set_pwm
(
omap
->
dm_timer
,
pwm_get_polarity
(
pwm
)
==
PWM_POLARITY_INVERSED
,
true
,
PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE
);
PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE
,
true
);
/* If config was called while timer was running it must be reenabled. */
if
(
timer_active
)
...
...
@@ -222,7 +223,8 @@ static int pwm_omap_dmtimer_set_polarity(struct pwm_chip *chip,
omap
->
pdata
->
set_pwm
(
omap
->
dm_timer
,
polarity
==
PWM_POLARITY_INVERSED
,
true
,
PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE
);
PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE
,
true
);
mutex_unlock
(
&
omap
->
mutex
);
return
0
;
...
...
include/clocksource/timer-ti-dm.h
View file @
f7867cff
...
...
@@ -105,17 +105,17 @@ struct omap_dm_timer {
void
__iomem
*
pend
;
/* write pending */
void
__iomem
*
func_base
;
/* function register base */
atomic_t
enabled
;
unsigned
long
rate
;
unsigned
reserved
:
1
;
unsigned
posted
:
1
;
struct
timer_regs
context
;
int
(
*
get_context_loss_count
)(
struct
device
*
);
int
ctx_loss_count
;
int
revision
;
u32
capability
;
u32
errata
;
struct
platform_device
*
pdev
;
struct
list_head
node
;
struct
notifier_block
nb
;
};
int
omap_dm_timer_reserve_systimer
(
int
id
);
...
...
include/linux/platform_data/dmtimer-omap.h
View file @
f7867cff
...
...
@@ -30,12 +30,12 @@ struct omap_dm_timer_ops {
int
(
*
stop
)(
struct
omap_dm_timer
*
timer
);
int
(
*
set_source
)(
struct
omap_dm_timer
*
timer
,
int
source
);
int
(
*
set_load
)(
struct
omap_dm_timer
*
timer
,
int
autoreload
,
unsigned
int
value
);
int
(
*
set_load
)(
struct
omap_dm_timer
*
timer
,
unsigned
int
value
);
int
(
*
set_match
)(
struct
omap_dm_timer
*
timer
,
int
enable
,
unsigned
int
match
);
int
(
*
set_pwm
)(
struct
omap_dm_timer
*
timer
,
int
def_on
,
int
toggle
,
int
trigger
);
int
toggle
,
int
trigger
,
int
autoreload
);
int
(
*
get_pwm_status
)(
struct
omap_dm_timer
*
timer
);
int
(
*
set_prescaler
)(
struct
omap_dm_timer
*
timer
,
int
prescaler
);
unsigned
int
(
*
read_counter
)(
struct
omap_dm_timer
*
timer
);
...
...
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