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
72521014
Commit
72521014
authored
Dec 19, 2013
by
Simon Horman
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'mike-turquette/clk-next-shmobile' into dt3-base
parents
8a1a3b1d
f94859c2
Changes
9
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
850 additions
and
0 deletions
+850
-0
Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt
...ion/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt
+28
-0
Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt
...ion/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt
+51
-0
Documentation/devicetree/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt
...evicetree/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt
+32
-0
drivers/clk/Makefile
drivers/clk/Makefile
+1
-0
drivers/clk/shmobile/Makefile
drivers/clk/shmobile/Makefile
+7
-0
drivers/clk/shmobile/clk-div6.c
drivers/clk/shmobile/clk-div6.c
+185
-0
drivers/clk/shmobile/clk-mstp.c
drivers/clk/shmobile/clk-mstp.c
+229
-0
drivers/clk/shmobile/clk-rcar-gen2.c
drivers/clk/shmobile/clk-rcar-gen2.c
+298
-0
include/linux/clk/shmobile.h
include/linux/clk/shmobile.h
+19
-0
No files found.
Documentation/devicetree/bindings/clock/renesas,cpg-div6-clocks.txt
0 → 100644
View file @
72521014
* Renesas CPG DIV6 Clock
The CPG DIV6 clocks are variable factor clocks provided by the Clock Pulse
Generator (CPG). They clock input is divided by a configurable factor from 1
to 64.
Required Properties:
- compatible: Must be one of the following
- "renesas,r8a7790-div6-clock" for R8A7790 (R-Car H2) DIV6 clocks
- "renesas,r8a7791-div6-clock" for R8A7791 (R-Car M2) DIV6 clocks
- "renesas,cpg-div6-clock" for generic DIV6 clocks
- reg: Base address and length of the memory resource used by the DIV6 clock
- clocks: Reference to the parent clock
- #clock-cells: Must be 0
- clock-output-names: The name of the clock as a free-form string
Example
-------
sd2_clk: sd2_clk@e6150078 {
compatible = "renesas,r8a7790-div6-clock", "renesas,cpg-div6-clock";
reg = <0 0xe6150078 0 4>;
clocks = <&pll1_div2_clk>;
#clock-cells = <0>;
clock-output-names = "sd2";
};
Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt
0 → 100644
View file @
72521014
* Renesas CPG Module Stop (MSTP) Clocks
The CPG can gate SoC device clocks. The gates are organized in groups of up to
32 gates.
This device tree binding describes a single 32 gate clocks group per node.
Clocks are referenced by user nodes by the MSTP node phandle and the clock
index in the group, from 0 to 31.
Required Properties:
- compatible: Must be one of the following
- "renesas,r8a7790-mstp-clocks" for R8A7790 (R-Car H2) MSTP gate clocks
- "renesas,r8a7791-mstp-clocks" for R8A7791 (R-Car M2) MSTP gate clocks
- "renesas,cpg-mstp-clock" for generic MSTP gate clocks
- reg: Base address and length of the I/O mapped registers used by the MSTP
clocks. The first register is the clock control register and is mandatory.
The second register is the clock status register and is optional when not
implemented in hardware.
- clocks: Reference to the parent clocks, one per output clock. The parents
must appear in the same order as the output clocks.
- #clock-cells: Must be 1
- clock-output-names: The name of the clocks as free-form strings
- renesas,indices: Indices of the gate clocks into the group (0 to 31)
The clocks, clock-output-names and renesas,indices properties contain one
entry per gate clock. The MSTP groups are sparsely populated. Unimplemented
gate clocks must not be declared.
Example
-------
#include <dt-bindings/clock/r8a7790-clock.h>
mstp3_clks: mstp3_clks@e615013c {
compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks";
reg = <0 0xe615013c 0 4>, <0 0xe6150048 0 4>;
clocks = <&cp_clk>, <&mmc1_clk>, <&sd3_clk>, <&sd2_clk>,
<&cpg_clocks R8A7790_CLK_SD1>, <&cpg_clocks R8A7790_CLK_SD0>,
<&mmc0_clk>;
#clock-cells = <1>;
clock-output-names =
"tpu0", "mmcif1", "sdhi3", "sdhi2",
"sdhi1", "sdhi0", "mmcif0";
renesas,clock-indices = <
R8A7790_CLK_TPU0 R8A7790_CLK_MMCIF1 R8A7790_CLK_SDHI3
R8A7790_CLK_SDHI2 R8A7790_CLK_SDHI1 R8A7790_CLK_SDHI0
R8A7790_CLK_MMCIF0
>;
};
Documentation/devicetree/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt
0 → 100644
View file @
72521014
* Renesas R-Car Gen2 Clock Pulse Generator (CPG)
The CPG generates core clocks for the R-Car Gen2 SoCs. It includes three PLLs
and several fixed ratio dividers.
Required Properties:
- compatible: Must be one of
- "renesas,r8a7790-cpg-clocks" for the r8a7790 CPG
- "renesas,r8a7791-cpg-clocks" for the r8a7791 CPG
- "renesas,rcar-gen2-cpg-clocks" for the generic R-Car Gen2 CPG
- reg: Base address and length of the memory resource used by the CPG
- clocks: Reference to the parent clock
- #clock-cells: Must be 1
- clock-output-names: The names of the clocks. Supported clocks are "main",
"pll0", "pll1", "pll3", "lb", "qspi", "sdh", "sd0", "sd1" and "z"
Example
-------
cpg_clocks: cpg_clocks@e6150000 {
compatible = "renesas,r8a7790-cpg-clocks",
"renesas,rcar-gen2-cpg-clocks";
reg = <0 0xe6150000 0 0x1000>;
clocks = <&extal_clk>;
#clock-cells = <1>;
clock-output-names = "main", "pll0, "pll1", "pll3",
"lb", "qspi", "sdh", "sd0", "sd1", "z";
};
drivers/clk/Makefile
View file @
72521014
...
...
@@ -35,6 +35,7 @@ obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-$(CONFIG_PLAT_SAMSUNG)
+=
samsung/
obj-$(CONFIG_COMMON_CLK_XGENE)
+=
clk-xgene.o
obj-$(CONFIG_COMMON_CLK_KEYSTONE)
+=
keystone/
obj-$(CONFIG_ARCH_SHMOBILE_MULTI)
+=
shmobile/
obj-$(CONFIG_X86)
+=
x86/
...
...
drivers/clk/shmobile/Makefile
0 → 100644
View file @
72521014
obj-$(CONFIG_ARCH_R8A7790)
+=
clk-rcar-gen2.o
obj-$(CONFIG_ARCH_R8A7791)
+=
clk-rcar-gen2.o
obj-$(CONFIG_ARCH_SHMOBILE_MULTI)
+=
clk-div6.o
obj-$(CONFIG_ARCH_SHMOBILE_MULTI)
+=
clk-mstp.o
# for emply built-in.o
obj-n
:=
dummy
drivers/clk/shmobile/clk-div6.c
0 → 100644
View file @
72521014
/*
* r8a7790 Common Clock Framework support
*
* Copyright (C) 2013 Renesas Solutions Corp.
*
* Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.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; version 2 of the License.
*/
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_address.h>
#define CPG_DIV6_CKSTP BIT(8)
#define CPG_DIV6_DIV(d) ((d) & 0x3f)
#define CPG_DIV6_DIV_MASK 0x3f
/**
* struct div6_clock - MSTP gating clock
* @hw: handle between common and hardware-specific interfaces
* @reg: IO-remapped register
* @div: divisor value (1-64)
*/
struct
div6_clock
{
struct
clk_hw
hw
;
void
__iomem
*
reg
;
unsigned
int
div
;
};
#define to_div6_clock(_hw) container_of(_hw, struct div6_clock, hw)
static
int
cpg_div6_clock_enable
(
struct
clk_hw
*
hw
)
{
struct
div6_clock
*
clock
=
to_div6_clock
(
hw
);
clk_writel
(
CPG_DIV6_DIV
(
clock
->
div
-
1
),
clock
->
reg
);
return
0
;
}
static
void
cpg_div6_clock_disable
(
struct
clk_hw
*
hw
)
{
struct
div6_clock
*
clock
=
to_div6_clock
(
hw
);
/* DIV6 clocks require the divisor field to be non-zero when stopping
* the clock.
*/
clk_writel
(
CPG_DIV6_CKSTP
|
CPG_DIV6_DIV
(
CPG_DIV6_DIV_MASK
),
clock
->
reg
);
}
static
int
cpg_div6_clock_is_enabled
(
struct
clk_hw
*
hw
)
{
struct
div6_clock
*
clock
=
to_div6_clock
(
hw
);
return
!
(
clk_readl
(
clock
->
reg
)
&
CPG_DIV6_CKSTP
);
}
static
unsigned
long
cpg_div6_clock_recalc_rate
(
struct
clk_hw
*
hw
,
unsigned
long
parent_rate
)
{
struct
div6_clock
*
clock
=
to_div6_clock
(
hw
);
unsigned
int
div
=
(
clk_readl
(
clock
->
reg
)
&
CPG_DIV6_DIV_MASK
)
+
1
;
return
parent_rate
/
div
;
}
static
unsigned
int
cpg_div6_clock_calc_div
(
unsigned
long
rate
,
unsigned
long
parent_rate
)
{
unsigned
int
div
;
div
=
DIV_ROUND_CLOSEST
(
parent_rate
,
rate
);
return
clamp_t
(
unsigned
int
,
div
,
1
,
64
);
}
static
long
cpg_div6_clock_round_rate
(
struct
clk_hw
*
hw
,
unsigned
long
rate
,
unsigned
long
*
parent_rate
)
{
unsigned
int
div
=
cpg_div6_clock_calc_div
(
rate
,
*
parent_rate
);
return
*
parent_rate
/
div
;
}
static
int
cpg_div6_clock_set_rate
(
struct
clk_hw
*
hw
,
unsigned
long
rate
,
unsigned
long
parent_rate
)
{
struct
div6_clock
*
clock
=
to_div6_clock
(
hw
);
unsigned
int
div
=
cpg_div6_clock_calc_div
(
rate
,
parent_rate
);
clock
->
div
=
div
;
/* Only program the new divisor if the clock isn't stopped. */
if
(
!
(
clk_readl
(
clock
->
reg
)
&
CPG_DIV6_CKSTP
))
clk_writel
(
CPG_DIV6_DIV
(
clock
->
div
-
1
),
clock
->
reg
);
return
0
;
}
static
const
struct
clk_ops
cpg_div6_clock_ops
=
{
.
enable
=
cpg_div6_clock_enable
,
.
disable
=
cpg_div6_clock_disable
,
.
is_enabled
=
cpg_div6_clock_is_enabled
,
.
recalc_rate
=
cpg_div6_clock_recalc_rate
,
.
round_rate
=
cpg_div6_clock_round_rate
,
.
set_rate
=
cpg_div6_clock_set_rate
,
};
static
void
__init
cpg_div6_clock_init
(
struct
device_node
*
np
)
{
struct
clk_init_data
init
;
struct
div6_clock
*
clock
;
const
char
*
parent_name
;
const
char
*
name
;
struct
clk
*
clk
;
int
ret
;
clock
=
kzalloc
(
sizeof
(
*
clock
),
GFP_KERNEL
);
if
(
!
clock
)
{
pr_err
(
"%s: failed to allocate %s DIV6 clock
\n
"
,
__func__
,
np
->
name
);
return
;
}
/* Remap the clock register and read the divisor. Disabling the
* clock overwrites the divisor, so we need to cache its value for the
* enable operation.
*/
clock
->
reg
=
of_iomap
(
np
,
0
);
if
(
clock
->
reg
==
NULL
)
{
pr_err
(
"%s: failed to map %s DIV6 clock register
\n
"
,
__func__
,
np
->
name
);
goto
error
;
}
clock
->
div
=
(
clk_readl
(
clock
->
reg
)
&
CPG_DIV6_DIV_MASK
)
+
1
;
/* Parse the DT properties. */
ret
=
of_property_read_string
(
np
,
"clock-output-names"
,
&
name
);
if
(
ret
<
0
)
{
pr_err
(
"%s: failed to get %s DIV6 clock output name
\n
"
,
__func__
,
np
->
name
);
goto
error
;
}
parent_name
=
of_clk_get_parent_name
(
np
,
0
);
if
(
parent_name
==
NULL
)
{
pr_err
(
"%s: failed to get %s DIV6 clock parent name
\n
"
,
__func__
,
np
->
name
);
goto
error
;
}
/* Register the clock. */
init
.
name
=
name
;
init
.
ops
=
&
cpg_div6_clock_ops
;
init
.
flags
=
CLK_IS_BASIC
;
init
.
parent_names
=
&
parent_name
;
init
.
num_parents
=
1
;
clock
->
hw
.
init
=
&
init
;
clk
=
clk_register
(
NULL
,
&
clock
->
hw
);
if
(
IS_ERR
(
clk
))
{
pr_err
(
"%s: failed to register %s DIV6 clock (%ld)
\n
"
,
__func__
,
np
->
name
,
PTR_ERR
(
clk
));
goto
error
;
}
of_clk_add_provider
(
np
,
of_clk_src_simple_get
,
clk
);
return
;
error:
if
(
clock
->
reg
)
iounmap
(
clock
->
reg
);
kfree
(
clock
);
}
CLK_OF_DECLARE
(
cpg_div6_clk
,
"renesas,cpg-div6-clock"
,
cpg_div6_clock_init
);
drivers/clk/shmobile/clk-mstp.c
0 → 100644
View file @
72521014
/*
* R-Car MSTP clocks
*
* Copyright (C) 2013 Ideas On Board SPRL
*
* Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.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; version 2 of the License.
*/
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/spinlock.h>
/*
* MSTP clocks. We can't use standard gate clocks as we need to poll on the
* status register when enabling the clock.
*/
#define MSTP_MAX_CLOCKS 32
/**
* struct mstp_clock_group - MSTP gating clocks group
*
* @data: clocks in this group
* @smstpcr: module stop control register
* @mstpsr: module stop status register (optional)
* @lock: protects writes to SMSTPCR
*/
struct
mstp_clock_group
{
struct
clk_onecell_data
data
;
void
__iomem
*
smstpcr
;
void
__iomem
*
mstpsr
;
spinlock_t
lock
;
};
/**
* struct mstp_clock - MSTP gating clock
* @hw: handle between common and hardware-specific interfaces
* @bit_index: control bit index
* @group: MSTP clocks group
*/
struct
mstp_clock
{
struct
clk_hw
hw
;
u32
bit_index
;
struct
mstp_clock_group
*
group
;
};
#define to_mstp_clock(_hw) container_of(_hw, struct mstp_clock, hw)
static
int
cpg_mstp_clock_endisable
(
struct
clk_hw
*
hw
,
bool
enable
)
{
struct
mstp_clock
*
clock
=
to_mstp_clock
(
hw
);
struct
mstp_clock_group
*
group
=
clock
->
group
;
u32
bitmask
=
BIT
(
clock
->
bit_index
);
unsigned
long
flags
;
unsigned
int
i
;
u32
value
;
spin_lock_irqsave
(
&
group
->
lock
,
flags
);
value
=
clk_readl
(
group
->
smstpcr
);
if
(
enable
)
value
&=
~
bitmask
;
else
value
|=
bitmask
;
clk_writel
(
value
,
group
->
smstpcr
);
spin_unlock_irqrestore
(
&
group
->
lock
,
flags
);
if
(
!
enable
||
!
group
->
mstpsr
)
return
0
;
for
(
i
=
1000
;
i
>
0
;
--
i
)
{
if
(
!
(
clk_readl
(
group
->
mstpsr
)
&
bitmask
))
break
;
cpu_relax
();
}
if
(
!
i
)
{
pr_err
(
"%s: failed to enable %p[%d]
\n
"
,
__func__
,
group
->
smstpcr
,
clock
->
bit_index
);
return
-
ETIMEDOUT
;
}
return
0
;
}
static
int
cpg_mstp_clock_enable
(
struct
clk_hw
*
hw
)
{
return
cpg_mstp_clock_endisable
(
hw
,
true
);
}
static
void
cpg_mstp_clock_disable
(
struct
clk_hw
*
hw
)
{
cpg_mstp_clock_endisable
(
hw
,
false
);
}
static
int
cpg_mstp_clock_is_enabled
(
struct
clk_hw
*
hw
)
{
struct
mstp_clock
*
clock
=
to_mstp_clock
(
hw
);
struct
mstp_clock_group
*
group
=
clock
->
group
;
u32
value
;
if
(
group
->
mstpsr
)
value
=
clk_readl
(
group
->
mstpsr
);
else
value
=
clk_readl
(
group
->
smstpcr
);
return
!!
(
value
&
BIT
(
clock
->
bit_index
));
}
static
const
struct
clk_ops
cpg_mstp_clock_ops
=
{
.
enable
=
cpg_mstp_clock_enable
,
.
disable
=
cpg_mstp_clock_disable
,
.
is_enabled
=
cpg_mstp_clock_is_enabled
,
};
static
struct
clk
*
__init
cpg_mstp_clock_register
(
const
char
*
name
,
const
char
*
parent_name
,
unsigned
int
index
,
struct
mstp_clock_group
*
group
)
{
struct
clk_init_data
init
;
struct
mstp_clock
*
clock
;
struct
clk
*
clk
;
clock
=
kzalloc
(
sizeof
(
*
clock
),
GFP_KERNEL
);
if
(
!
clock
)
{
pr_err
(
"%s: failed to allocate MSTP clock.
\n
"
,
__func__
);
return
ERR_PTR
(
-
ENOMEM
);
}
init
.
name
=
name
;
init
.
ops
=
&
cpg_mstp_clock_ops
;
init
.
flags
=
CLK_IS_BASIC
;
init
.
parent_names
=
&
parent_name
;
init
.
num_parents
=
1
;
clock
->
bit_index
=
index
;
clock
->
group
=
group
;
clock
->
hw
.
init
=
&
init
;
clk
=
clk_register
(
NULL
,
&
clock
->
hw
);
if
(
IS_ERR
(
clk
))
kfree
(
clock
);
return
clk
;
}
static
void
__init
cpg_mstp_clocks_init
(
struct
device_node
*
np
)
{
struct
mstp_clock_group
*
group
;
struct
clk
**
clks
;
unsigned
int
i
;
group
=
kzalloc
(
sizeof
(
*
group
),
GFP_KERNEL
);
clks
=
kzalloc
(
MSTP_MAX_CLOCKS
*
sizeof
(
*
clks
),
GFP_KERNEL
);
if
(
group
==
NULL
||
clks
==
NULL
)
{
kfree
(
group
);
kfree
(
clks
);
pr_err
(
"%s: failed to allocate group
\n
"
,
__func__
);
return
;
}
spin_lock_init
(
&
group
->
lock
);
group
->
data
.
clks
=
clks
;
group
->
smstpcr
=
of_iomap
(
np
,
0
);
group
->
mstpsr
=
of_iomap
(
np
,
1
);
if
(
group
->
smstpcr
==
NULL
)
{
pr_err
(
"%s: failed to remap SMSTPCR
\n
"
,
__func__
);
kfree
(
group
);
kfree
(
clks
);
return
;
}
for
(
i
=
0
;
i
<
MSTP_MAX_CLOCKS
;
++
i
)
{
const
char
*
parent_name
;
const
char
*
name
;
u32
clkidx
;
int
ret
;
/* Skip clocks with no name. */
ret
=
of_property_read_string_index
(
np
,
"clock-output-names"
,
i
,
&
name
);
if
(
ret
<
0
||
strlen
(
name
)
==
0
)
continue
;
parent_name
=
of_clk_get_parent_name
(
np
,
i
);
ret
=
of_property_read_u32_index
(
np
,
"renesas,clock-indices"
,
i
,
&
clkidx
);
if
(
parent_name
==
NULL
||
ret
<
0
)
break
;
if
(
clkidx
>=
MSTP_MAX_CLOCKS
)
{
pr_err
(
"%s: invalid clock %s %s index %u)
\n
"
,
__func__
,
np
->
name
,
name
,
clkidx
);
continue
;
}
clks
[
clkidx
]
=
cpg_mstp_clock_register
(
name
,
parent_name
,
i
,
group
);
if
(
!
IS_ERR
(
clks
[
clkidx
]))
{
group
->
data
.
clk_num
=
max
(
group
->
data
.
clk_num
,
clkidx
);
/*
* Register a clkdev to let board code retrieve the
* clock by name and register aliases for non-DT
* devices.
*
* FIXME: Remove this when all devices that require a
* clock will be instantiated from DT.
*/
clk_register_clkdev
(
clks
[
clkidx
],
name
,
NULL
);
}
else
{
pr_err
(
"%s: failed to register %s %s clock (%ld)
\n
"
,
__func__
,
np
->
name
,
name
,
PTR_ERR
(
clks
[
clkidx
]));
}
}
of_clk_add_provider
(
np
,
of_clk_src_onecell_get
,
&
group
->
data
);
}
CLK_OF_DECLARE
(
cpg_mstp_clks
,
"renesas,cpg-mstp-clocks"
,
cpg_mstp_clocks_init
);
drivers/clk/shmobile/clk-rcar-gen2.c
0 → 100644
View file @
72521014
/*
* rcar_gen2 Core CPG Clocks
*
* Copyright (C) 2013 Ideas On Board SPRL
*
* Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.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; version 2 of the License.
*/
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/clk/shmobile.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/math64.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/spinlock.h>
struct
rcar_gen2_cpg
{
struct
clk_onecell_data
data
;
spinlock_t
lock
;
void
__iomem
*
reg
;
};
#define CPG_SDCKCR 0x00000074
#define CPG_PLL0CR 0x000000d8
#define CPG_FRQCRC 0x000000e0
#define CPG_FRQCRC_ZFC_MASK (0x1f << 8)
#define CPG_FRQCRC_ZFC_SHIFT 8
/* -----------------------------------------------------------------------------
* Z Clock
*
* Traits of this clock:
* prepare - clk_prepare only ensures that parents are prepared
* enable - clk_enable only ensures that parents are enabled
* rate - rate is adjustable. clk->rate = parent->rate * mult / 32
* parent - fixed parent. No clk_set_parent support
*/
struct
cpg_z_clk
{
struct
clk_hw
hw
;
void
__iomem
*
reg
;
};
#define to_z_clk(_hw) container_of(_hw, struct cpg_z_clk, hw)
static
unsigned
long
cpg_z_clk_recalc_rate
(
struct
clk_hw
*
hw
,
unsigned
long
parent_rate
)
{
struct
cpg_z_clk
*
zclk
=
to_z_clk
(
hw
);
unsigned
int
mult
;
unsigned
int
val
;
val
=
(
clk_readl
(
zclk
->
reg
)
&
CPG_FRQCRC_ZFC_MASK
)
>>
CPG_FRQCRC_ZFC_SHIFT
;
mult
=
32
-
val
;
return
div_u64
((
u64
)
parent_rate
*
mult
,
32
);
}
static
long
cpg_z_clk_round_rate
(
struct
clk_hw
*
hw
,
unsigned
long
rate
,
unsigned
long
*
parent_rate
)
{
unsigned
long
prate
=
*
parent_rate
;
unsigned
int
mult
;
if
(
!
prate
)
prate
=
1
;
mult
=
div_u64
((
u64
)
rate
*
32
,
prate
);
mult
=
clamp
(
mult
,
1U
,
32U
);
return
*
parent_rate
/
32
*
mult
;
}
static
int
cpg_z_clk_set_rate
(
struct
clk_hw
*
hw
,
unsigned
long
rate
,
unsigned
long
parent_rate
)
{
struct
cpg_z_clk
*
zclk
=
to_z_clk
(
hw
);
unsigned
int
mult
;
u32
val
;
mult
=
div_u64
((
u64
)
rate
*
32
,
parent_rate
);
mult
=
clamp
(
mult
,
1U
,
32U
);
val
=
clk_readl
(
zclk
->
reg
);
val
&=
~
CPG_FRQCRC_ZFC_MASK
;
val
|=
(
32
-
mult
)
<<
CPG_FRQCRC_ZFC_SHIFT
;
clk_writel
(
val
,
zclk
->
reg
);
return
0
;
}
static
const
struct
clk_ops
cpg_z_clk_ops
=
{
.
recalc_rate
=
cpg_z_clk_recalc_rate
,
.
round_rate
=
cpg_z_clk_round_rate
,
.
set_rate
=
cpg_z_clk_set_rate
,
};
static
struct
clk
*
__init
cpg_z_clk_register
(
struct
rcar_gen2_cpg
*
cpg
)
{
static
const
char
*
parent_name
=
"pll0"
;
struct
clk_init_data
init
;
struct
cpg_z_clk
*
zclk
;
struct
clk
*
clk
;
zclk
=
kzalloc
(
sizeof
(
*
zclk
),
GFP_KERNEL
);
if
(
!
zclk
)
return
ERR_PTR
(
-
ENOMEM
);
init
.
name
=
"z"
;
init
.
ops
=
&
cpg_z_clk_ops
;
init
.
flags
=
0
;
init
.
parent_names
=
&
parent_name
;
init
.
num_parents
=
1
;
zclk
->
reg
=
cpg
->
reg
+
CPG_FRQCRC
;
zclk
->
hw
.
init
=
&
init
;
clk
=
clk_register
(
NULL
,
&
zclk
->
hw
);
if
(
IS_ERR
(
clk
))
kfree
(
zclk
);
return
clk
;
}
/* -----------------------------------------------------------------------------
* CPG Clock Data
*/
/*
* MD EXTAL PLL0 PLL1 PLL3
* 14 13 19 (MHz) *1 *1
*---------------------------------------------------
* 0 0 0 15 x 1 x172/2 x208/2 x106
* 0 0 1 15 x 1 x172/2 x208/2 x88
* 0 1 0 20 x 1 x130/2 x156/2 x80
* 0 1 1 20 x 1 x130/2 x156/2 x66
* 1 0 0 26 / 2 x200/2 x240/2 x122
* 1 0 1 26 / 2 x200/2 x240/2 x102
* 1 1 0 30 / 2 x172/2 x208/2 x106
* 1 1 1 30 / 2 x172/2 x208/2 x88
*
* *1 : Table 7.6 indicates VCO ouput (PLLx = VCO/2)
*/
#define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 12) | \
(((md) & BIT(13)) >> 12) | \
(((md) & BIT(19)) >> 19))
struct
cpg_pll_config
{
unsigned
int
extal_div
;
unsigned
int
pll1_mult
;
unsigned
int
pll3_mult
;
};
static
const
struct
cpg_pll_config
cpg_pll_configs
[
8
]
__initconst
=
{
{
1
,
208
,
106
},
{
1
,
208
,
88
},
{
1
,
156
,
80
},
{
1
,
156
,
66
},
{
2
,
240
,
122
},
{
2
,
240
,
102
},
{
2
,
208
,
106
},
{
2
,
208
,
88
},
};
/* SDHI divisors */
static
const
struct
clk_div_table
cpg_sdh_div_table
[]
=
{
{
0
,
2
},
{
1
,
3
},
{
2
,
4
},
{
3
,
6
},
{
4
,
8
},
{
5
,
12
},
{
6
,
16
},
{
7
,
18
},
{
8
,
24
},
{
10
,
36
},
{
11
,
48
},
{
0
,
0
},
};
static
const
struct
clk_div_table
cpg_sd01_div_table
[]
=
{
{
5
,
12
},
{
6
,
16
},
{
7
,
18
},
{
8
,
24
},
{
10
,
36
},
{
11
,
48
},
{
12
,
10
},
{
0
,
0
},
};
/* -----------------------------------------------------------------------------
* Initialization
*/
static
u32
cpg_mode
__initdata
;
static
struct
clk
*
__init
rcar_gen2_cpg_register_clock
(
struct
device_node
*
np
,
struct
rcar_gen2_cpg
*
cpg
,
const
struct
cpg_pll_config
*
config
,
const
char
*
name
)
{
const
struct
clk_div_table
*
table
=
NULL
;
const
char
*
parent_name
=
"main"
;
unsigned
int
shift
;
unsigned
int
mult
=
1
;
unsigned
int
div
=
1
;
if
(
!
strcmp
(
name
,
"main"
))
{
parent_name
=
of_clk_get_parent_name
(
np
,
0
);
div
=
config
->
extal_div
;
}
else
if
(
!
strcmp
(
name
,
"pll0"
))
{
/* PLL0 is a configurable multiplier clock. Register it as a
* fixed factor clock for now as there's no generic multiplier
* clock implementation and we currently have no need to change
* the multiplier value.
*/
u32
value
=
clk_readl
(
cpg
->
reg
+
CPG_PLL0CR
);
mult
=
((
value
>>
24
)
&
((
1
<<
7
)
-
1
))
+
1
;
}
else
if
(
!
strcmp
(
name
,
"pll1"
))
{
mult
=
config
->
pll1_mult
/
2
;
}
else
if
(
!
strcmp
(
name
,
"pll3"
))
{
mult
=
config
->
pll3_mult
;
}
else
if
(
!
strcmp
(
name
,
"lb"
))
{
div
=
cpg_mode
&
BIT
(
18
)
?
36
:
24
;
}
else
if
(
!
strcmp
(
name
,
"qspi"
))
{
div
=
(
cpg_mode
&
(
BIT
(
3
)
|
BIT
(
2
)
|
BIT
(
1
)))
==
BIT
(
2
)
?
16
:
20
;
}
else
if
(
!
strcmp
(
name
,
"sdh"
))
{
table
=
cpg_sdh_div_table
;
shift
=
8
;
}
else
if
(
!
strcmp
(
name
,
"sd0"
))
{
table
=
cpg_sd01_div_table
;
shift
=
4
;
}
else
if
(
!
strcmp
(
name
,
"sd1"
))
{
table
=
cpg_sd01_div_table
;
shift
=
0
;
}
else
if
(
!
strcmp
(
name
,
"z"
))
{
return
cpg_z_clk_register
(
cpg
);
}
else
{
return
ERR_PTR
(
-
EINVAL
);
}
if
(
!
table
)
return
clk_register_fixed_factor
(
NULL
,
name
,
parent_name
,
0
,
mult
,
div
);
else
return
clk_register_divider_table
(
NULL
,
name
,
parent_name
,
0
,
cpg
->
reg
+
CPG_SDCKCR
,
shift
,
4
,
0
,
table
,
&
cpg
->
lock
);
}
static
void
__init
rcar_gen2_cpg_clocks_init
(
struct
device_node
*
np
)
{
const
struct
cpg_pll_config
*
config
;
struct
rcar_gen2_cpg
*
cpg
;
struct
clk
**
clks
;
unsigned
int
i
;
int
num_clks
;
num_clks
=
of_property_count_strings
(
np
,
"clock-output-names"
);
if
(
num_clks
<
0
)
{
pr_err
(
"%s: failed to count clocks
\n
"
,
__func__
);
return
;
}
cpg
=
kzalloc
(
sizeof
(
*
cpg
),
GFP_KERNEL
);
clks
=
kzalloc
(
num_clks
*
sizeof
(
*
clks
),
GFP_KERNEL
);
if
(
cpg
==
NULL
||
clks
==
NULL
)
{
/* We're leaking memory on purpose, there's no point in cleaning
* up as the system won't boot anyway.
*/
pr_err
(
"%s: failed to allocate cpg
\n
"
,
__func__
);
return
;
}
spin_lock_init
(
&
cpg
->
lock
);
cpg
->
data
.
clks
=
clks
;
cpg
->
data
.
clk_num
=
num_clks
;
cpg
->
reg
=
of_iomap
(
np
,
0
);
if
(
WARN_ON
(
cpg
->
reg
==
NULL
))
return
;
config
=
&
cpg_pll_configs
[
CPG_PLL_CONFIG_INDEX
(
cpg_mode
)];
for
(
i
=
0
;
i
<
num_clks
;
++
i
)
{
const
char
*
name
;
struct
clk
*
clk
;
of_property_read_string_index
(
np
,
"clock-output-names"
,
i
,
&
name
);
clk
=
rcar_gen2_cpg_register_clock
(
np
,
cpg
,
config
,
name
);
if
(
IS_ERR
(
clk
))
pr_err
(
"%s: failed to register %s %s clock (%ld)
\n
"
,
__func__
,
np
->
name
,
name
,
PTR_ERR
(
clk
));
else
cpg
->
data
.
clks
[
i
]
=
clk
;
}
of_clk_add_provider
(
np
,
of_clk_src_onecell_get
,
&
cpg
->
data
);
}
CLK_OF_DECLARE
(
rcar_gen2_cpg_clks
,
"renesas,rcar-gen2-cpg-clocks"
,
rcar_gen2_cpg_clocks_init
);
void
__init
rcar_gen2_clocks_init
(
u32
mode
)
{
cpg_mode
=
mode
;
of_clk_init
(
NULL
);
}
include/linux/clk/shmobile.h
0 → 100644
View file @
72521014
/*
* Copyright 2013 Ideas On Board SPRL
*
* Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.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.
*/
#ifndef __LINUX_CLK_SHMOBILE_H_
#define __LINUX_CLK_SHMOBILE_H_
#include <linux/types.h>
void
rcar_gen2_clocks_init
(
u32
mode
);
#endif
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