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
d4f2016f
Commit
d4f2016f
authored
Nov 18, 2014
by
Michael Turquette
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'clk-next-shmobile' into clk-next
parents
40ba3f0f
bfadcadf
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
113 additions
and
18 deletions
+113
-18
Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt
...ion/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt
+12
-6
drivers/clk/shmobile/clk-div6.c
drivers/clk/shmobile/clk-div6.c
+101
-12
No files found.
Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt
View file @
d4f2016f
...
@@ -7,11 +7,16 @@ to 64.
...
@@ -7,11 +7,16 @@ to 64.
Required Properties:
Required Properties:
- compatible: Must be one of the following
- compatible: Must be one of the following
- "renesas,r8a73a4-div6-clock" for R8A73A4 (R-Mobile APE6) DIV6 clocks
- "renesas,r8a7740-div6-clock" for R8A7740 (R-Mobile A1) DIV6 clocks
- "renesas,r8a7790-div6-clock" for R8A7790 (R-Car H2) DIV6 clocks
- "renesas,r8a7790-div6-clock" for R8A7790 (R-Car H2) DIV6 clocks
- "renesas,r8a7791-div6-clock" for R8A7791 (R-Car M2) DIV6 clocks
- "renesas,r8a7791-div6-clock" for R8A7791 (R-Car M2) DIV6 clocks
- "renesas,sh73a0-div6-clock" for SH73A0 (SH-Mobile AG5) DIV6 clocks
- "renesas,cpg-div6-clock" for generic DIV6 clocks
- "renesas,cpg-div6-clock" for generic DIV6 clocks
- reg: Base address and length of the memory resource used by the DIV6 clock
- reg: Base address and length of the memory resource used by the DIV6 clock
- clocks: Reference to the parent clock
- clocks: Reference to the parent clock(s); either one, four, or eight
clocks must be specified. For clocks with multiple parents, invalid
settings must be specified as "<0>".
- #clock-cells: Must be 0
- #clock-cells: Must be 0
- clock-output-names: The name of the clock as a free-form string
- clock-output-names: The name of the clock as a free-form string
...
@@ -19,10 +24,11 @@ Required Properties:
...
@@ -19,10 +24,11 @@ Required Properties:
Example
Example
-------
-------
sd2_clk: sd2_clk@e6150078 {
sdhi2_clk: sdhi2_clk@e615007c {
compatible = "renesas,r8a7790-div6-clock", "renesas,cpg-div6-clock";
compatible = "renesas,r8a73a4-div6-clock", "renesas,cpg-div6-clock";
reg = <0 0xe6150078 0 4>;
reg = <0 0xe615007c 0 4>;
clocks = <&pll1_div2_clk>;
clocks = <&pll1_div2_clk>, <&cpg_clocks R8A73A4_CLK_PLL2S>,
<0>, <&extal2_clk>;
#clock-cells = <0>;
#clock-cells = <0>;
clock-output-names = "sd
2
";
clock-output-names = "sd
hi2ck
";
};
};
drivers/clk/shmobile/clk-div6.c
View file @
d4f2016f
...
@@ -32,6 +32,9 @@ struct div6_clock {
...
@@ -32,6 +32,9 @@ struct div6_clock {
struct
clk_hw
hw
;
struct
clk_hw
hw
;
void
__iomem
*
reg
;
void
__iomem
*
reg
;
unsigned
int
div
;
unsigned
int
div
;
u32
src_shift
;
u32
src_width
;
u8
*
parents
;
};
};
#define to_div6_clock(_hw) container_of(_hw, struct div6_clock, hw)
#define to_div6_clock(_hw) container_of(_hw, struct div6_clock, hw)
...
@@ -39,8 +42,11 @@ struct div6_clock {
...
@@ -39,8 +42,11 @@ struct div6_clock {
static
int
cpg_div6_clock_enable
(
struct
clk_hw
*
hw
)
static
int
cpg_div6_clock_enable
(
struct
clk_hw
*
hw
)
{
{
struct
div6_clock
*
clock
=
to_div6_clock
(
hw
);
struct
div6_clock
*
clock
=
to_div6_clock
(
hw
);
u32
val
;
clk_writel
(
CPG_DIV6_DIV
(
clock
->
div
-
1
),
clock
->
reg
);
val
=
(
clk_readl
(
clock
->
reg
)
&
~
(
CPG_DIV6_DIV_MASK
|
CPG_DIV6_CKSTP
))
|
CPG_DIV6_DIV
(
clock
->
div
-
1
);
clk_writel
(
val
,
clock
->
reg
);
return
0
;
return
0
;
}
}
...
@@ -52,7 +58,7 @@ static void cpg_div6_clock_disable(struct clk_hw *hw)
...
@@ -52,7 +58,7 @@ static void cpg_div6_clock_disable(struct clk_hw *hw)
/* DIV6 clocks require the divisor field to be non-zero when stopping
/* DIV6 clocks require the divisor field to be non-zero when stopping
* the clock.
* the clock.
*/
*/
clk_writel
(
CPG_DIV6_CKSTP
|
CPG_DIV6_DIV
(
CPG_DIV6_DIV_MASK
)
,
clk_writel
(
clk_readl
(
clock
->
reg
)
|
CPG_DIV6_CKSTP
|
CPG_DIV6_DIV_MASK
,
clock
->
reg
);
clock
->
reg
);
}
}
...
@@ -94,12 +100,53 @@ static int cpg_div6_clock_set_rate(struct clk_hw *hw, unsigned long rate,
...
@@ -94,12 +100,53 @@ static int cpg_div6_clock_set_rate(struct clk_hw *hw, unsigned long rate,
{
{
struct
div6_clock
*
clock
=
to_div6_clock
(
hw
);
struct
div6_clock
*
clock
=
to_div6_clock
(
hw
);
unsigned
int
div
=
cpg_div6_clock_calc_div
(
rate
,
parent_rate
);
unsigned
int
div
=
cpg_div6_clock_calc_div
(
rate
,
parent_rate
);
u32
val
;
clock
->
div
=
div
;
clock
->
div
=
div
;
val
=
clk_readl
(
clock
->
reg
)
&
~
CPG_DIV6_DIV_MASK
;
/* Only program the new divisor if the clock isn't stopped. */
/* Only program the new divisor if the clock isn't stopped. */
if
(
!
(
clk_readl
(
clock
->
reg
)
&
CPG_DIV6_CKSTP
))
if
(
!
(
val
&
CPG_DIV6_CKSTP
))
clk_writel
(
CPG_DIV6_DIV
(
clock
->
div
-
1
),
clock
->
reg
);
clk_writel
(
val
|
CPG_DIV6_DIV
(
clock
->
div
-
1
),
clock
->
reg
);
return
0
;
}
static
u8
cpg_div6_clock_get_parent
(
struct
clk_hw
*
hw
)
{
struct
div6_clock
*
clock
=
to_div6_clock
(
hw
);
unsigned
int
i
;
u8
hw_index
;
if
(
clock
->
src_width
==
0
)
return
0
;
hw_index
=
(
clk_readl
(
clock
->
reg
)
>>
clock
->
src_shift
)
&
(
BIT
(
clock
->
src_width
)
-
1
);
for
(
i
=
0
;
i
<
__clk_get_num_parents
(
hw
->
clk
);
i
++
)
{
if
(
clock
->
parents
[
i
]
==
hw_index
)
return
i
;
}
pr_err
(
"%s: %s DIV6 clock set to invalid parent %u
\n
"
,
__func__
,
__clk_get_name
(
hw
->
clk
),
hw_index
);
return
0
;
}
static
int
cpg_div6_clock_set_parent
(
struct
clk_hw
*
hw
,
u8
index
)
{
struct
div6_clock
*
clock
=
to_div6_clock
(
hw
);
u8
hw_index
;
u32
mask
;
if
(
index
>=
__clk_get_num_parents
(
hw
->
clk
))
return
-
EINVAL
;
mask
=
~
((
BIT
(
clock
->
src_width
)
-
1
)
<<
clock
->
src_shift
);
hw_index
=
clock
->
parents
[
index
];
clk_writel
((
clk_readl
(
clock
->
reg
)
&
mask
)
|
(
hw_index
<<
clock
->
src_shift
),
clock
->
reg
);
return
0
;
return
0
;
}
}
...
@@ -108,6 +155,8 @@ static const struct clk_ops cpg_div6_clock_ops = {
...
@@ -108,6 +155,8 @@ static const struct clk_ops cpg_div6_clock_ops = {
.
enable
=
cpg_div6_clock_enable
,
.
enable
=
cpg_div6_clock_enable
,
.
disable
=
cpg_div6_clock_disable
,
.
disable
=
cpg_div6_clock_disable
,
.
is_enabled
=
cpg_div6_clock_is_enabled
,
.
is_enabled
=
cpg_div6_clock_is_enabled
,
.
get_parent
=
cpg_div6_clock_get_parent
,
.
set_parent
=
cpg_div6_clock_set_parent
,
.
recalc_rate
=
cpg_div6_clock_recalc_rate
,
.
recalc_rate
=
cpg_div6_clock_recalc_rate
,
.
round_rate
=
cpg_div6_clock_round_rate
,
.
round_rate
=
cpg_div6_clock_round_rate
,
.
set_rate
=
cpg_div6_clock_set_rate
,
.
set_rate
=
cpg_div6_clock_set_rate
,
...
@@ -115,20 +164,33 @@ static const struct clk_ops cpg_div6_clock_ops = {
...
@@ -115,20 +164,33 @@ static const struct clk_ops cpg_div6_clock_ops = {
static
void
__init
cpg_div6_clock_init
(
struct
device_node
*
np
)
static
void
__init
cpg_div6_clock_init
(
struct
device_node
*
np
)
{
{
unsigned
int
num_parents
,
valid_parents
;
const
char
**
parent_names
;
struct
clk_init_data
init
;
struct
clk_init_data
init
;
struct
div6_clock
*
clock
;
struct
div6_clock
*
clock
;
const
char
*
parent_name
;
const
char
*
name
;
const
char
*
name
;
struct
clk
*
clk
;
struct
clk
*
clk
;
unsigned
int
i
;
int
ret
;
int
ret
;
clock
=
kzalloc
(
sizeof
(
*
clock
),
GFP_KERNEL
);
clock
=
kzalloc
(
sizeof
(
*
clock
),
GFP_KERNEL
);
if
(
!
clock
)
{
if
(
!
clock
)
pr_err
(
"%s: failed to allocate %s DIV6 clock
\n
"
,
return
;
num_parents
=
of_clk_get_parent_count
(
np
);
if
(
num_parents
<
1
)
{
pr_err
(
"%s: no parent found for %s DIV6 clock
\n
"
,
__func__
,
np
->
name
);
__func__
,
np
->
name
);
return
;
return
;
}
}
clock
->
parents
=
kmalloc_array
(
num_parents
,
sizeof
(
*
clock
->
parents
),
GFP_KERNEL
);
parent_names
=
kmalloc_array
(
num_parents
,
sizeof
(
*
parent_names
),
GFP_KERNEL
);
if
(
!
parent_names
)
return
;
/* Remap the clock register and read the divisor. Disabling the
/* Remap the clock register and read the divisor. Disabling the
* clock overwrites the divisor, so we need to cache its value for the
* clock overwrites the divisor, so we need to cache its value for the
* enable operation.
* enable operation.
...
@@ -150,9 +212,34 @@ static void __init cpg_div6_clock_init(struct device_node *np)
...
@@ -150,9 +212,34 @@ static void __init cpg_div6_clock_init(struct device_node *np)
goto
error
;
goto
error
;
}
}
parent_name
=
of_clk_get_parent_name
(
np
,
0
);
if
(
parent_name
==
NULL
)
{
for
(
i
=
0
,
valid_parents
=
0
;
i
<
num_parents
;
i
++
)
{
pr_err
(
"%s: failed to get %s DIV6 clock parent name
\n
"
,
const
char
*
name
=
of_clk_get_parent_name
(
np
,
i
);
if
(
name
)
{
parent_names
[
valid_parents
]
=
name
;
clock
->
parents
[
valid_parents
]
=
i
;
valid_parents
++
;
}
}
switch
(
num_parents
)
{
case
1
:
/* fixed parent clock */
clock
->
src_shift
=
clock
->
src_width
=
0
;
break
;
case
4
:
/* clock with EXSRC bits 6-7 */
clock
->
src_shift
=
6
;
clock
->
src_width
=
2
;
break
;
case
8
:
/* VCLK with EXSRC bits 12-14 */
clock
->
src_shift
=
12
;
clock
->
src_width
=
3
;
break
;
default:
pr_err
(
"%s: invalid number of parents for DIV6 clock %s
\n
"
,
__func__
,
np
->
name
);
__func__
,
np
->
name
);
goto
error
;
goto
error
;
}
}
...
@@ -161,8 +248,8 @@ static void __init cpg_div6_clock_init(struct device_node *np)
...
@@ -161,8 +248,8 @@ static void __init cpg_div6_clock_init(struct device_node *np)
init
.
name
=
name
;
init
.
name
=
name
;
init
.
ops
=
&
cpg_div6_clock_ops
;
init
.
ops
=
&
cpg_div6_clock_ops
;
init
.
flags
=
CLK_IS_BASIC
;
init
.
flags
=
CLK_IS_BASIC
;
init
.
parent_names
=
&
parent_name
;
init
.
parent_names
=
parent_names
;
init
.
num_parents
=
1
;
init
.
num_parents
=
valid_parents
;
clock
->
hw
.
init
=
&
init
;
clock
->
hw
.
init
=
&
init
;
...
@@ -175,11 +262,13 @@ static void __init cpg_div6_clock_init(struct device_node *np)
...
@@ -175,11 +262,13 @@ static void __init cpg_div6_clock_init(struct device_node *np)
of_clk_add_provider
(
np
,
of_clk_src_simple_get
,
clk
);
of_clk_add_provider
(
np
,
of_clk_src_simple_get
,
clk
);
kfree
(
parent_names
);
return
;
return
;
error:
error:
if
(
clock
->
reg
)
if
(
clock
->
reg
)
iounmap
(
clock
->
reg
);
iounmap
(
clock
->
reg
);
kfree
(
parent_names
);
kfree
(
clock
);
kfree
(
clock
);
}
}
CLK_OF_DECLARE
(
cpg_div6_clk
,
"renesas,cpg-div6-clock"
,
cpg_div6_clock_init
);
CLK_OF_DECLARE
(
cpg_div6_clk
,
"renesas,cpg-div6-clock"
,
cpg_div6_clock_init
);
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