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
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