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
Kirill Smelkov
linux
Commits
2eb2a01b
Commit
2eb2a01b
authored
Jul 09, 2018
by
Jerome Brunet
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'clk/clk-core-duty-cycle' into next/drivers
parents
e8dd9207
9fba738a
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
289 additions
and
5 deletions
+289
-5
drivers/clk/clk.c
drivers/clk/clk.c
+194
-5
include/linux/clk-provider.h
include/linux/clk-provider.h
+26
-0
include/linux/clk.h
include/linux/clk.h
+33
-0
include/trace/events/clk.h
include/trace/events/clk.h
+36
-0
No files found.
drivers/clk/clk.c
View file @
2eb2a01b
...
...
@@ -68,6 +68,7 @@ struct clk_core {
unsigned
long
max_rate
;
unsigned
long
accuracy
;
int
phase
;
struct
clk_duty
duty
;
struct
hlist_head
children
;
struct
hlist_node
child_node
;
struct
hlist_head
clks
;
...
...
@@ -2402,6 +2403,172 @@ int clk_get_phase(struct clk *clk)
}
EXPORT_SYMBOL_GPL
(
clk_get_phase
);
static
void
clk_core_reset_duty_cycle_nolock
(
struct
clk_core
*
core
)
{
/* Assume a default value of 50% */
core
->
duty
.
num
=
1
;
core
->
duty
.
den
=
2
;
}
static
int
clk_core_update_duty_cycle_parent_nolock
(
struct
clk_core
*
core
);
static
int
clk_core_update_duty_cycle_nolock
(
struct
clk_core
*
core
)
{
struct
clk_duty
*
duty
=
&
core
->
duty
;
int
ret
=
0
;
if
(
!
core
->
ops
->
get_duty_cycle
)
return
clk_core_update_duty_cycle_parent_nolock
(
core
);
ret
=
core
->
ops
->
get_duty_cycle
(
core
->
hw
,
duty
);
if
(
ret
)
goto
reset
;
/* Don't trust the clock provider too much */
if
(
duty
->
den
==
0
||
duty
->
num
>
duty
->
den
)
{
ret
=
-
EINVAL
;
goto
reset
;
}
return
0
;
reset:
clk_core_reset_duty_cycle_nolock
(
core
);
return
ret
;
}
static
int
clk_core_update_duty_cycle_parent_nolock
(
struct
clk_core
*
core
)
{
int
ret
=
0
;
if
(
core
->
parent
&&
core
->
flags
&
CLK_DUTY_CYCLE_PARENT
)
{
ret
=
clk_core_update_duty_cycle_nolock
(
core
->
parent
);
memcpy
(
&
core
->
duty
,
&
core
->
parent
->
duty
,
sizeof
(
core
->
duty
));
}
else
{
clk_core_reset_duty_cycle_nolock
(
core
);
}
return
ret
;
}
static
int
clk_core_set_duty_cycle_parent_nolock
(
struct
clk_core
*
core
,
struct
clk_duty
*
duty
);
static
int
clk_core_set_duty_cycle_nolock
(
struct
clk_core
*
core
,
struct
clk_duty
*
duty
)
{
int
ret
;
lockdep_assert_held
(
&
prepare_lock
);
if
(
clk_core_rate_is_protected
(
core
))
return
-
EBUSY
;
trace_clk_set_duty_cycle
(
core
,
duty
);
if
(
!
core
->
ops
->
set_duty_cycle
)
return
clk_core_set_duty_cycle_parent_nolock
(
core
,
duty
);
ret
=
core
->
ops
->
set_duty_cycle
(
core
->
hw
,
duty
);
if
(
!
ret
)
memcpy
(
&
core
->
duty
,
duty
,
sizeof
(
*
duty
));
trace_clk_set_duty_cycle_complete
(
core
,
duty
);
return
ret
;
}
static
int
clk_core_set_duty_cycle_parent_nolock
(
struct
clk_core
*
core
,
struct
clk_duty
*
duty
)
{
int
ret
=
0
;
if
(
core
->
parent
&&
core
->
flags
&
(
CLK_DUTY_CYCLE_PARENT
|
CLK_SET_RATE_PARENT
))
{
ret
=
clk_core_set_duty_cycle_nolock
(
core
->
parent
,
duty
);
memcpy
(
&
core
->
duty
,
&
core
->
parent
->
duty
,
sizeof
(
core
->
duty
));
}
return
ret
;
}
/**
* clk_set_duty_cycle - adjust the duty cycle ratio of a clock signal
* @clk: clock signal source
* @num: numerator of the duty cycle ratio to be applied
* @den: denominator of the duty cycle ratio to be applied
*
* Apply the duty cycle ratio if the ratio is valid and the clock can
* perform this operation
*
* Returns (0) on success, a negative errno otherwise.
*/
int
clk_set_duty_cycle
(
struct
clk
*
clk
,
unsigned
int
num
,
unsigned
int
den
)
{
int
ret
;
struct
clk_duty
duty
;
if
(
!
clk
)
return
0
;
/* sanity check the ratio */
if
(
den
==
0
||
num
>
den
)
return
-
EINVAL
;
duty
.
num
=
num
;
duty
.
den
=
den
;
clk_prepare_lock
();
if
(
clk
->
exclusive_count
)
clk_core_rate_unprotect
(
clk
->
core
);
ret
=
clk_core_set_duty_cycle_nolock
(
clk
->
core
,
&
duty
);
if
(
clk
->
exclusive_count
)
clk_core_rate_protect
(
clk
->
core
);
clk_prepare_unlock
();
return
ret
;
}
EXPORT_SYMBOL_GPL
(
clk_set_duty_cycle
);
static
int
clk_core_get_scaled_duty_cycle
(
struct
clk_core
*
core
,
unsigned
int
scale
)
{
struct
clk_duty
*
duty
=
&
core
->
duty
;
int
ret
;
clk_prepare_lock
();
ret
=
clk_core_update_duty_cycle_nolock
(
core
);
if
(
!
ret
)
ret
=
mult_frac
(
scale
,
duty
->
num
,
duty
->
den
);
clk_prepare_unlock
();
return
ret
;
}
/**
* clk_get_scaled_duty_cycle - return the duty cycle ratio of a clock signal
* @clk: clock signal source
* @scale: scaling factor to be applied to represent the ratio as an integer
*
* Returns the duty cycle ratio of a clock node multiplied by the provided
* scaling factor, or negative errno on error.
*/
int
clk_get_scaled_duty_cycle
(
struct
clk
*
clk
,
unsigned
int
scale
)
{
if
(
!
clk
)
return
0
;
return
clk_core_get_scaled_duty_cycle
(
clk
->
core
,
scale
);
}
EXPORT_SYMBOL_GPL
(
clk_get_scaled_duty_cycle
);
/**
* clk_is_match - check if two clk's point to the same hardware clock
* @p: clk compared against q
...
...
@@ -2455,12 +2622,13 @@ static void clk_summary_show_one(struct seq_file *s, struct clk_core *c,
if
(
!
c
)
return
;
seq_printf
(
s
,
"%*s%-*s %7d %8d %8d %11lu %10lu %
-3
d
\n
"
,
seq_printf
(
s
,
"%*s%-*s %7d %8d %8d %11lu %10lu %
5d %6
d
\n
"
,
level
*
3
+
1
,
""
,
30
-
level
*
3
,
c
->
name
,
c
->
enable_count
,
c
->
prepare_count
,
c
->
protect_count
,
clk_core_get_rate
(
c
),
clk_core_get_accuracy
(
c
),
clk_core_get_phase
(
c
));
clk_core_get_phase
(
c
),
clk_core_get_scaled_duty_cycle
(
c
,
100000
));
}
static
void
clk_summary_show_subtree
(
struct
seq_file
*
s
,
struct
clk_core
*
c
,
...
...
@@ -2482,9 +2650,9 @@ static int clk_summary_show(struct seq_file *s, void *data)
struct
clk_core
*
c
;
struct
hlist_head
**
lists
=
(
struct
hlist_head
**
)
s
->
private
;
seq_puts
(
s
,
" enable prepare protect
\n
"
);
seq_puts
(
s
,
" clock count count count rate accuracy
phas
e
\n
"
);
seq_puts
(
s
,
"----------------------------------------------------------------------------------------
\n
"
);
seq_puts
(
s
,
" enable prepare protect
duty
\n
"
);
seq_puts
(
s
,
" clock count count count rate accuracy
phase cycl
e
\n
"
);
seq_puts
(
s
,
"----------------------------------------------------------------------------------------
-----
\n
"
);
clk_prepare_lock
();
...
...
@@ -2511,6 +2679,8 @@ static void clk_dump_one(struct seq_file *s, struct clk_core *c, int level)
seq_printf
(
s
,
"
\"
rate
\"
: %lu,"
,
clk_core_get_rate
(
c
));
seq_printf
(
s
,
"
\"
accuracy
\"
: %lu,"
,
clk_core_get_accuracy
(
c
));
seq_printf
(
s
,
"
\"
phase
\"
: %d"
,
clk_core_get_phase
(
c
));
seq_printf
(
s
,
"
\"
duty_cycle
\"
: %u"
,
clk_core_get_scaled_duty_cycle
(
c
,
100000
));
}
static
void
clk_dump_subtree
(
struct
seq_file
*
s
,
struct
clk_core
*
c
,
int
level
)
...
...
@@ -2572,6 +2742,7 @@ static const struct {
ENTRY
(
CLK_SET_RATE_UNGATE
),
ENTRY
(
CLK_IS_CRITICAL
),
ENTRY
(
CLK_OPS_PARENT_ENABLE
),
ENTRY
(
CLK_DUTY_CYCLE_PARENT
),
#undef ENTRY
};
...
...
@@ -2610,6 +2781,17 @@ static int possible_parents_show(struct seq_file *s, void *data)
}
DEFINE_SHOW_ATTRIBUTE
(
possible_parents
);
static
int
clk_duty_cycle_show
(
struct
seq_file
*
s
,
void
*
data
)
{
struct
clk_core
*
core
=
s
->
private
;
struct
clk_duty
*
duty
=
&
core
->
duty
;
seq_printf
(
s
,
"%u/%u
\n
"
,
duty
->
num
,
duty
->
den
);
return
0
;
}
DEFINE_SHOW_ATTRIBUTE
(
clk_duty_cycle
);
static
void
clk_debug_create_one
(
struct
clk_core
*
core
,
struct
dentry
*
pdentry
)
{
struct
dentry
*
root
;
...
...
@@ -2628,6 +2810,8 @@ static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
debugfs_create_u32
(
"clk_enable_count"
,
0444
,
root
,
&
core
->
enable_count
);
debugfs_create_u32
(
"clk_protect_count"
,
0444
,
root
,
&
core
->
protect_count
);
debugfs_create_u32
(
"clk_notifier_count"
,
0444
,
root
,
&
core
->
notifier_count
);
debugfs_create_file
(
"clk_duty_cycle"
,
0444
,
root
,
core
,
&
clk_duty_cycle_fops
);
if
(
core
->
num_parents
>
1
)
debugfs_create_file
(
"clk_possible_parents"
,
0444
,
root
,
core
,
...
...
@@ -2845,6 +3029,11 @@ static int __clk_core_init(struct clk_core *core)
else
core
->
phase
=
0
;
/*
* Set clk's duty cycle.
*/
clk_core_update_duty_cycle_nolock
(
core
);
/*
* Set clk's rate. The preferred method is to use .recalc_rate. For
* simple clocks and lazy developers the default fallback is to use the
...
...
include/linux/clk-provider.h
View file @
2eb2a01b
...
...
@@ -38,6 +38,8 @@
#define CLK_IS_CRITICAL BIT(11)
/* do not gate, ever */
/* parents need enable during gate/ungate, set rate and re-parent */
#define CLK_OPS_PARENT_ENABLE BIT(12)
/* duty cycle call may be forwarded to the parent clock */
#define CLK_DUTY_CYCLE_PARENT BIT(13)
struct
clk
;
struct
clk_hw
;
...
...
@@ -66,6 +68,17 @@ struct clk_rate_request {
struct
clk_hw
*
best_parent_hw
;
};
/**
* struct clk_duty - Struture encoding the duty cycle ratio of a clock
*
* @num: Numerator of the duty cycle ratio
* @den: Denominator of the duty cycle ratio
*/
struct
clk_duty
{
unsigned
int
num
;
unsigned
int
den
;
};
/**
* struct clk_ops - Callback operations for hardware clocks; these are to
* be provided by the clock implementation, and will be called by drivers
...
...
@@ -169,6 +182,15 @@ struct clk_rate_request {
* by the second argument. Valid values for degrees are
* 0-359. Return 0 on success, otherwise -EERROR.
*
* @get_duty_cycle: Queries the hardware to get the current duty cycle ratio
* of a clock. Returned values denominator cannot be 0 and must be
* superior or equal to the numerator.
*
* @set_duty_cycle: Apply the duty cycle ratio to this clock signal specified by
* the numerator (2nd argurment) and denominator (3rd argument).
* Argument must be a valid ratio (denominator > 0
* and >= numerator) Return 0 on success, otherwise -EERROR.
*
* @init: Perform platform-specific initialization magic.
* This is not not used by any of the basic clock types.
* Please consider other ways of solving initialization problems
...
...
@@ -218,6 +240,10 @@ struct clk_ops {
unsigned
long
parent_accuracy
);
int
(
*
get_phase
)(
struct
clk_hw
*
hw
);
int
(
*
set_phase
)(
struct
clk_hw
*
hw
,
int
degrees
);
int
(
*
get_duty_cycle
)(
struct
clk_hw
*
hw
,
struct
clk_duty
*
duty
);
int
(
*
set_duty_cycle
)(
struct
clk_hw
*
hw
,
struct
clk_duty
*
duty
);
void
(
*
init
)(
struct
clk_hw
*
hw
);
void
(
*
debug_init
)(
struct
clk_hw
*
hw
,
struct
dentry
*
dentry
);
};
...
...
include/linux/clk.h
View file @
2eb2a01b
...
...
@@ -141,6 +141,27 @@ int clk_set_phase(struct clk *clk, int degrees);
*/
int
clk_get_phase
(
struct
clk
*
clk
);
/**
* clk_set_duty_cycle - adjust the duty cycle ratio of a clock signal
* @clk: clock signal source
* @num: numerator of the duty cycle ratio to be applied
* @den: denominator of the duty cycle ratio to be applied
*
* Adjust the duty cycle of a clock signal by the specified ratio. Returns 0 on
* success, -EERROR otherwise.
*/
int
clk_set_duty_cycle
(
struct
clk
*
clk
,
unsigned
int
num
,
unsigned
int
den
);
/**
* clk_get_duty_cycle - return the duty cycle ratio of a clock signal
* @clk: clock signal source
* @scale: scaling factor to be applied to represent the ratio as an integer
*
* Returns the duty cycle ratio multiplied by the scale provided, otherwise
* returns -EERROR.
*/
int
clk_get_scaled_duty_cycle
(
struct
clk
*
clk
,
unsigned
int
scale
);
/**
* clk_is_match - check if two clk's point to the same hardware clock
* @p: clk compared against q
...
...
@@ -183,6 +204,18 @@ static inline long clk_get_phase(struct clk *clk)
return
-
ENOTSUPP
;
}
static
inline
int
clk_set_duty_cycle
(
struct
clk
*
clk
,
unsigned
int
num
,
unsigned
int
den
)
{
return
-
ENOTSUPP
;
}
static
inline
unsigned
int
clk_get_scaled_duty_cycle
(
struct
clk
*
clk
,
unsigned
int
scale
)
{
return
0
;
}
static
inline
bool
clk_is_match
(
const
struct
clk
*
p
,
const
struct
clk
*
q
)
{
return
p
==
q
;
...
...
include/trace/events/clk.h
View file @
2eb2a01b
...
...
@@ -192,6 +192,42 @@ DEFINE_EVENT(clk_phase, clk_set_phase_complete,
TP_ARGS
(
core
,
phase
)
);
DECLARE_EVENT_CLASS
(
clk_duty_cycle
,
TP_PROTO
(
struct
clk_core
*
core
,
struct
clk_duty
*
duty
),
TP_ARGS
(
core
,
duty
),
TP_STRUCT__entry
(
__string
(
name
,
core
->
name
)
__field
(
unsigned
int
,
num
)
__field
(
unsigned
int
,
den
)
),
TP_fast_assign
(
__assign_str
(
name
,
core
->
name
);
__entry
->
num
=
duty
->
num
;
__entry
->
den
=
duty
->
den
;
),
TP_printk
(
"%s %u/%u"
,
__get_str
(
name
),
(
unsigned
int
)
__entry
->
num
,
(
unsigned
int
)
__entry
->
den
)
);
DEFINE_EVENT
(
clk_duty_cycle
,
clk_set_duty_cycle
,
TP_PROTO
(
struct
clk_core
*
core
,
struct
clk_duty
*
duty
),
TP_ARGS
(
core
,
duty
)
);
DEFINE_EVENT
(
clk_duty_cycle
,
clk_set_duty_cycle_complete
,
TP_PROTO
(
struct
clk_core
*
core
,
struct
clk_duty
*
duty
),
TP_ARGS
(
core
,
duty
)
);
#endif
/* _TRACE_CLK_H */
/* This part must be outside protection */
...
...
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