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
7adb7695
Commit
7adb7695
authored
Jul 08, 2016
by
Michael Turquette
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'clk-sunxi-ng' into clk-next
parents
a0649829
0577e485
Changes
34
Hide whitespace changes
Inline
Side-by-side
Showing
34 changed files
with
3669 additions
and
0 deletions
+3669
-0
Documentation/devicetree/bindings/clock/sunxi-ccu.txt
Documentation/devicetree/bindings/clock/sunxi-ccu.txt
+24
-0
drivers/clk/Kconfig
drivers/clk/Kconfig
+1
-0
drivers/clk/Makefile
drivers/clk/Makefile
+1
-0
drivers/clk/sunxi-ng/Kconfig
drivers/clk/sunxi-ng/Kconfig
+65
-0
drivers/clk/sunxi-ng/Makefile
drivers/clk/sunxi-ng/Makefile
+20
-0
drivers/clk/sunxi-ng/ccu-sun8i-h3.c
drivers/clk/sunxi-ng/ccu-sun8i-h3.c
+826
-0
drivers/clk/sunxi-ng/ccu-sun8i-h3.h
drivers/clk/sunxi-ng/ccu-sun8i-h3.h
+62
-0
drivers/clk/sunxi-ng/ccu_common.c
drivers/clk/sunxi-ng/ccu_common.c
+90
-0
drivers/clk/sunxi-ng/ccu_common.h
drivers/clk/sunxi-ng/ccu_common.h
+85
-0
drivers/clk/sunxi-ng/ccu_div.c
drivers/clk/sunxi-ng/ccu_div.c
+136
-0
drivers/clk/sunxi-ng/ccu_div.h
drivers/clk/sunxi-ng/ccu_div.h
+133
-0
drivers/clk/sunxi-ng/ccu_frac.c
drivers/clk/sunxi-ng/ccu_frac.c
+110
-0
drivers/clk/sunxi-ng/ccu_frac.h
drivers/clk/sunxi-ng/ccu_frac.h
+53
-0
drivers/clk/sunxi-ng/ccu_gate.c
drivers/clk/sunxi-ng/ccu_gate.c
+82
-0
drivers/clk/sunxi-ng/ccu_gate.h
drivers/clk/sunxi-ng/ccu_gate.h
+52
-0
drivers/clk/sunxi-ng/ccu_mp.c
drivers/clk/sunxi-ng/ccu_mp.c
+158
-0
drivers/clk/sunxi-ng/ccu_mp.h
drivers/clk/sunxi-ng/ccu_mp.h
+77
-0
drivers/clk/sunxi-ng/ccu_mult.h
drivers/clk/sunxi-ng/ccu_mult.h
+15
-0
drivers/clk/sunxi-ng/ccu_mux.c
drivers/clk/sunxi-ng/ccu_mux.c
+187
-0
drivers/clk/sunxi-ng/ccu_mux.h
drivers/clk/sunxi-ng/ccu_mux.h
+91
-0
drivers/clk/sunxi-ng/ccu_nk.c
drivers/clk/sunxi-ng/ccu_nk.c
+147
-0
drivers/clk/sunxi-ng/ccu_nk.h
drivers/clk/sunxi-ng/ccu_nk.h
+71
-0
drivers/clk/sunxi-ng/ccu_nkm.c
drivers/clk/sunxi-ng/ccu_nkm.c
+153
-0
drivers/clk/sunxi-ng/ccu_nkm.h
drivers/clk/sunxi-ng/ccu_nkm.h
+68
-0
drivers/clk/sunxi-ng/ccu_nkmp.c
drivers/clk/sunxi-ng/ccu_nkmp.c
+167
-0
drivers/clk/sunxi-ng/ccu_nkmp.h
drivers/clk/sunxi-ng/ccu_nkmp.h
+71
-0
drivers/clk/sunxi-ng/ccu_nm.c
drivers/clk/sunxi-ng/ccu_nm.c
+114
-0
drivers/clk/sunxi-ng/ccu_nm.h
drivers/clk/sunxi-ng/ccu_nm.h
+91
-0
drivers/clk/sunxi-ng/ccu_phase.c
drivers/clk/sunxi-ng/ccu_phase.c
+126
-0
drivers/clk/sunxi-ng/ccu_phase.h
drivers/clk/sunxi-ng/ccu_phase.h
+50
-0
drivers/clk/sunxi-ng/ccu_reset.c
drivers/clk/sunxi-ng/ccu_reset.c
+55
-0
drivers/clk/sunxi-ng/ccu_reset.h
drivers/clk/sunxi-ng/ccu_reset.h
+40
-0
include/dt-bindings/clock/sun8i-h3-ccu.h
include/dt-bindings/clock/sun8i-h3-ccu.h
+145
-0
include/dt-bindings/reset/sun8i-h3-ccu.h
include/dt-bindings/reset/sun8i-h3-ccu.h
+103
-0
No files found.
Documentation/devicetree/bindings/clock/sunxi-ccu.txt
0 → 100644
View file @
7adb7695
Allwinner Clock Control Unit Binding
------------------------------------
Required properties :
- compatible: must contain one of the following compatible:
- "allwinner,sun8i-h3-ccu"
- reg: Must contain the registers base address and length
- clocks: phandle to the oscillators feeding the CCU. Two are needed:
- "hosc": the high frequency oscillator (usually at 24MHz)
- "losc": the low frequency oscillator (usually at 32kHz)
- clock-names: Must contain the clock names described just above
- #clock-cells : must contain 1
- #reset-cells : must contain 1
Example:
ccu: clock@01c20000 {
compatible = "allwinner,sun8i-h3-ccu";
reg = <0x01c20000 0x400>;
clocks = <&osc24M>, <&osc32k>;
clock-names = "hosc", "losc";
#clock-cells = <1>;
#reset-cells = <1>;
};
drivers/clk/Kconfig
View file @
7adb7695
...
@@ -214,6 +214,7 @@ source "drivers/clk/mvebu/Kconfig"
...
@@ -214,6 +214,7 @@ source "drivers/clk/mvebu/Kconfig"
source "drivers/clk/qcom/Kconfig"
source "drivers/clk/qcom/Kconfig"
source "drivers/clk/renesas/Kconfig"
source "drivers/clk/renesas/Kconfig"
source "drivers/clk/samsung/Kconfig"
source "drivers/clk/samsung/Kconfig"
source "drivers/clk/sunxi-ng/Kconfig"
source "drivers/clk/tegra/Kconfig"
source "drivers/clk/tegra/Kconfig"
source "drivers/clk/ti/Kconfig"
source "drivers/clk/ti/Kconfig"
...
...
drivers/clk/Makefile
View file @
7adb7695
...
@@ -79,6 +79,7 @@ obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/
...
@@ -79,6 +79,7 @@ obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/
obj-$(CONFIG_PLAT_SPEAR)
+=
spear/
obj-$(CONFIG_PLAT_SPEAR)
+=
spear/
obj-$(CONFIG_ARCH_STI)
+=
st/
obj-$(CONFIG_ARCH_STI)
+=
st/
obj-$(CONFIG_ARCH_SUNXI)
+=
sunxi/
obj-$(CONFIG_ARCH_SUNXI)
+=
sunxi/
obj-$(CONFIG_ARCH_SUNXI)
+=
sunxi-ng/
obj-$(CONFIG_ARCH_TEGRA)
+=
tegra/
obj-$(CONFIG_ARCH_TEGRA)
+=
tegra/
obj-y
+=
ti/
obj-y
+=
ti/
obj-$(CONFIG_ARCH_U8500)
+=
ux500/
obj-$(CONFIG_ARCH_U8500)
+=
ux500/
...
...
drivers/clk/sunxi-ng/Kconfig
0 → 100644
View file @
7adb7695
config SUNXI_CCU
bool "Clock support for Allwinner SoCs"
default ARCH_SUNXI
if SUNXI_CCU
# Base clock types
config SUNXI_CCU_DIV
bool
select SUNXI_CCU_MUX
config SUNXI_CCU_FRAC
bool
config SUNXI_CCU_GATE
bool
config SUNXI_CCU_MUX
bool
config SUNXI_CCU_PHASE
bool
# Multi-factor clocks
config SUNXI_CCU_NK
bool
select SUNXI_CCU_GATE
config SUNXI_CCU_NKM
bool
select RATIONAL
select SUNXI_CCU_GATE
config SUNXI_CCU_NKMP
bool
select RATIONAL
select SUNXI_CCU_GATE
config SUNXI_CCU_NM
bool
select RATIONAL
select SUNXI_CCU_FRAC
select SUNXI_CCU_GATE
config SUNXI_CCU_MP
bool
select SUNXI_CCU_GATE
select SUNXI_CCU_MUX
# SoC Drivers
config SUN8I_H3_CCU
bool "Support for the Allwinner H3 CCU"
select SUNXI_CCU_DIV
select SUNXI_CCU_NK
select SUNXI_CCU_NKM
select SUNXI_CCU_NKMP
select SUNXI_CCU_NM
select SUNXI_CCU_MP
select SUNXI_CCU_PHASE
default ARCH_SUN8I
endif
drivers/clk/sunxi-ng/Makefile
0 → 100644
View file @
7adb7695
# Common objects
obj-$(CONFIG_SUNXI_CCU)
+=
ccu_common.o
obj-$(CONFIG_SUNXI_CCU)
+=
ccu_reset.o
# Base clock types
obj-$(CONFIG_SUNXI_CCU_DIV)
+=
ccu_div.o
obj-$(CONFIG_SUNXI_CCU_FRAC)
+=
ccu_frac.o
obj-$(CONFIG_SUNXI_CCU_GATE)
+=
ccu_gate.o
obj-$(CONFIG_SUNXI_CCU_MUX)
+=
ccu_mux.o
obj-$(CONFIG_SUNXI_CCU_PHASE)
+=
ccu_phase.o
# Multi-factor clocks
obj-$(CONFIG_SUNXI_CCU_NK)
+=
ccu_nk.o
obj-$(CONFIG_SUNXI_CCU_NKM)
+=
ccu_nkm.o
obj-$(CONFIG_SUNXI_CCU_NKMP)
+=
ccu_nkmp.o
obj-$(CONFIG_SUNXI_CCU_NM)
+=
ccu_nm.o
obj-$(CONFIG_SUNXI_CCU_MP)
+=
ccu_mp.o
# SoC support
obj-$(CONFIG_SUN8I_H3_CCU)
+=
ccu-sun8i-h3.o
drivers/clk/sunxi-ng/ccu-sun8i-h3.c
0 → 100644
View file @
7adb7695
/*
* Copyright (c) 2016 Maxime Ripard. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/clk-provider.h>
#include <linux/of_address.h>
#include "ccu_common.h"
#include "ccu_reset.h"
#include "ccu_div.h"
#include "ccu_gate.h"
#include "ccu_mp.h"
#include "ccu_mult.h"
#include "ccu_nk.h"
#include "ccu_nkm.h"
#include "ccu_nkmp.h"
#include "ccu_nm.h"
#include "ccu_phase.h"
#include "ccu-sun8i-h3.h"
static
SUNXI_CCU_NKMP_WITH_GATE_LOCK
(
pll_cpux_clk
,
"pll-cpux"
,
"osc24M"
,
0x000
,
8
,
5
,
/* N */
4
,
2
,
/* K */
0
,
2
,
/* M */
16
,
2
,
/* P */
BIT
(
31
),
/* gate */
BIT
(
28
),
/* lock */
0
);
/*
* The Audio PLL is supposed to have 4 outputs: 3 fixed factors from
* the base (2x, 4x and 8x), and one variable divider (the one true
* pll audio).
*
* We don't have any need for the variable divider for now, so we just
* hardcode it to match with the clock names
*/
#define SUN8I_H3_PLL_AUDIO_REG 0x008
static
SUNXI_CCU_NM_WITH_GATE_LOCK
(
pll_audio_base_clk
,
"pll-audio-base"
,
"osc24M"
,
0x008
,
8
,
7
,
/* N */
0
,
5
,
/* M */
BIT
(
31
),
/* gate */
BIT
(
28
),
/* lock */
0
);
static
SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK
(
pll_video_clk
,
"pll-video"
,
"osc24M"
,
0x0010
,
8
,
7
,
/* N */
0
,
4
,
/* M */
BIT
(
24
),
/* frac enable */
BIT
(
25
),
/* frac select */
270000000
,
/* frac rate 0 */
297000000
,
/* frac rate 1 */
BIT
(
31
),
/* gate */
BIT
(
28
),
/* lock */
0
);
static
SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK
(
pll_ve_clk
,
"pll-ve"
,
"osc24M"
,
0x0018
,
8
,
7
,
/* N */
0
,
4
,
/* M */
BIT
(
24
),
/* frac enable */
BIT
(
25
),
/* frac select */
270000000
,
/* frac rate 0 */
297000000
,
/* frac rate 1 */
BIT
(
31
),
/* gate */
BIT
(
28
),
/* lock */
0
);
static
SUNXI_CCU_NKM_WITH_GATE_LOCK
(
pll_ddr_clk
,
"pll-ddr"
,
"osc24M"
,
0x020
,
8
,
5
,
/* N */
4
,
2
,
/* K */
0
,
2
,
/* M */
BIT
(
31
),
/* gate */
BIT
(
28
),
/* lock */
0
);
static
SUNXI_CCU_NK_WITH_GATE_LOCK_POSTDIV
(
pll_periph0_clk
,
"pll-periph0"
,
"osc24M"
,
0x028
,
8
,
5
,
/* N */
4
,
2
,
/* K */
BIT
(
31
),
/* gate */
BIT
(
28
),
/* lock */
2
,
/* post-div */
0
);
static
SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK
(
pll_gpu_clk
,
"pll-gpu"
,
"osc24M"
,
0x0038
,
8
,
7
,
/* N */
0
,
4
,
/* M */
BIT
(
24
),
/* frac enable */
BIT
(
25
),
/* frac select */
270000000
,
/* frac rate 0 */
297000000
,
/* frac rate 1 */
BIT
(
31
),
/* gate */
BIT
(
28
),
/* lock */
0
);
static
SUNXI_CCU_NK_WITH_GATE_LOCK_POSTDIV
(
pll_periph1_clk
,
"pll-periph1"
,
"osc24M"
,
0x044
,
8
,
5
,
/* N */
4
,
2
,
/* K */
BIT
(
31
),
/* gate */
BIT
(
28
),
/* lock */
2
,
/* post-div */
0
);
static
SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK
(
pll_de_clk
,
"pll-de"
,
"osc24M"
,
0x0048
,
8
,
7
,
/* N */
0
,
4
,
/* M */
BIT
(
24
),
/* frac enable */
BIT
(
25
),
/* frac select */
270000000
,
/* frac rate 0 */
297000000
,
/* frac rate 1 */
BIT
(
31
),
/* gate */
BIT
(
28
),
/* lock */
0
);
static
const
char
*
const
cpux_parents
[]
=
{
"osc32k"
,
"osc24M"
,
"pll-cpux"
,
"pll-cpux"
};
static
SUNXI_CCU_MUX
(
cpux_clk
,
"cpux"
,
cpux_parents
,
0x050
,
16
,
2
,
CLK_IS_CRITICAL
);
static
SUNXI_CCU_M
(
axi_clk
,
"axi"
,
"cpux"
,
0x050
,
0
,
2
,
0
);
static
const
char
*
const
ahb1_parents
[]
=
{
"osc32k"
,
"osc24M"
,
"axi"
,
"pll-periph0"
};
static
struct
ccu_div
ahb1_clk
=
{
.
div
=
_SUNXI_CCU_DIV_FLAGS
(
4
,
2
,
CLK_DIVIDER_POWER_OF_TWO
),
.
mux
=
{
.
shift
=
12
,
.
width
=
2
,
.
variable_prediv
=
{
.
index
=
3
,
.
shift
=
6
,
.
width
=
2
,
},
},
.
common
=
{
.
reg
=
0x054
,
.
features
=
CCU_FEATURE_VARIABLE_PREDIV
,
.
hw
.
init
=
CLK_HW_INIT_PARENTS
(
"ahb1"
,
ahb1_parents
,
&
ccu_div_ops
,
0
),
},
};
static
struct
clk_div_table
apb1_div_table
[]
=
{
{
.
val
=
0
,
.
div
=
2
},
{
.
val
=
1
,
.
div
=
2
},
{
.
val
=
2
,
.
div
=
4
},
{
.
val
=
3
,
.
div
=
8
},
{
/* Sentinel */
},
};
static
SUNXI_CCU_DIV_TABLE
(
apb1_clk
,
"apb1"
,
"ahb1"
,
0x054
,
8
,
2
,
apb1_div_table
,
0
);
static
const
char
*
const
apb2_parents
[]
=
{
"osc32k"
,
"osc24M"
,
"pll-periph0"
,
"pll-periph0"
};
static
SUNXI_CCU_MP_WITH_MUX
(
apb2_clk
,
"apb2"
,
apb2_parents
,
0x058
,
0
,
5
,
/* M */
16
,
2
,
/* P */
24
,
2
,
/* mux */
0
);
static
const
char
*
const
ahb2_parents
[]
=
{
"ahb1"
,
"pll-periph0"
};
static
struct
ccu_mux
ahb2_clk
=
{
.
mux
=
{
.
shift
=
0
,
.
width
=
1
,
.
fixed_prediv
=
{
.
index
=
1
,
.
div
=
2
,
},
},
.
common
=
{
.
reg
=
0x05c
,
.
features
=
CCU_FEATURE_FIXED_PREDIV
,
.
hw
.
init
=
CLK_HW_INIT_PARENTS
(
"ahb2"
,
ahb2_parents
,
&
ccu_mux_ops
,
0
),
},
};
static
SUNXI_CCU_GATE
(
bus_ce_clk
,
"bus-ce"
,
"ahb1"
,
0x060
,
BIT
(
5
),
0
);
static
SUNXI_CCU_GATE
(
bus_dma_clk
,
"bus-dma"
,
"ahb1"
,
0x060
,
BIT
(
6
),
0
);
static
SUNXI_CCU_GATE
(
bus_mmc0_clk
,
"bus-mmc0"
,
"ahb1"
,
0x060
,
BIT
(
8
),
0
);
static
SUNXI_CCU_GATE
(
bus_mmc1_clk
,
"bus-mmc1"
,
"ahb1"
,
0x060
,
BIT
(
9
),
0
);
static
SUNXI_CCU_GATE
(
bus_mmc2_clk
,
"bus-mmc2"
,
"ahb1"
,
0x060
,
BIT
(
10
),
0
);
static
SUNXI_CCU_GATE
(
bus_nand_clk
,
"bus-nand"
,
"ahb1"
,
0x060
,
BIT
(
13
),
0
);
static
SUNXI_CCU_GATE
(
bus_dram_clk
,
"bus-dram"
,
"ahb1"
,
0x060
,
BIT
(
14
),
0
);
static
SUNXI_CCU_GATE
(
bus_emac_clk
,
"bus-emac"
,
"ahb2"
,
0x060
,
BIT
(
17
),
0
);
static
SUNXI_CCU_GATE
(
bus_ts_clk
,
"bus-ts"
,
"ahb1"
,
0x060
,
BIT
(
18
),
0
);
static
SUNXI_CCU_GATE
(
bus_hstimer_clk
,
"bus-hstimer"
,
"ahb1"
,
0x060
,
BIT
(
19
),
0
);
static
SUNXI_CCU_GATE
(
bus_spi0_clk
,
"bus-spi0"
,
"ahb1"
,
0x060
,
BIT
(
20
),
0
);
static
SUNXI_CCU_GATE
(
bus_spi1_clk
,
"bus-spi1"
,
"ahb1"
,
0x060
,
BIT
(
21
),
0
);
static
SUNXI_CCU_GATE
(
bus_otg_clk
,
"bus-otg"
,
"ahb1"
,
0x060
,
BIT
(
23
),
0
);
static
SUNXI_CCU_GATE
(
bus_ehci0_clk
,
"bus-ehci0"
,
"ahb1"
,
0x060
,
BIT
(
24
),
0
);
static
SUNXI_CCU_GATE
(
bus_ehci1_clk
,
"bus-ehci1"
,
"ahb2"
,
0x060
,
BIT
(
25
),
0
);
static
SUNXI_CCU_GATE
(
bus_ehci2_clk
,
"bus-ehci2"
,
"ahb2"
,
0x060
,
BIT
(
26
),
0
);
static
SUNXI_CCU_GATE
(
bus_ehci3_clk
,
"bus-ehci3"
,
"ahb2"
,
0x060
,
BIT
(
27
),
0
);
static
SUNXI_CCU_GATE
(
bus_ohci0_clk
,
"bus-ohci0"
,
"ahb1"
,
0x060
,
BIT
(
28
),
0
);
static
SUNXI_CCU_GATE
(
bus_ohci1_clk
,
"bus-ohci1"
,
"ahb2"
,
0x060
,
BIT
(
29
),
0
);
static
SUNXI_CCU_GATE
(
bus_ohci2_clk
,
"bus-ohci2"
,
"ahb2"
,
0x060
,
BIT
(
30
),
0
);
static
SUNXI_CCU_GATE
(
bus_ohci3_clk
,
"bus-ohci3"
,
"ahb2"
,
0x060
,
BIT
(
31
),
0
);
static
SUNXI_CCU_GATE
(
bus_ve_clk
,
"bus-ve"
,
"ahb1"
,
0x064
,
BIT
(
0
),
0
);
static
SUNXI_CCU_GATE
(
bus_tcon0_clk
,
"bus-tcon0"
,
"ahb1"
,
0x064
,
BIT
(
3
),
0
);
static
SUNXI_CCU_GATE
(
bus_tcon1_clk
,
"bus-tcon1"
,
"ahb1"
,
0x064
,
BIT
(
4
),
0
);
static
SUNXI_CCU_GATE
(
bus_deinterlace_clk
,
"bus-deinterlace"
,
"ahb1"
,
0x064
,
BIT
(
5
),
0
);
static
SUNXI_CCU_GATE
(
bus_csi_clk
,
"bus-csi"
,
"ahb1"
,
0x064
,
BIT
(
8
),
0
);
static
SUNXI_CCU_GATE
(
bus_tve_clk
,
"bus-tve"
,
"ahb1"
,
0x064
,
BIT
(
9
),
0
);
static
SUNXI_CCU_GATE
(
bus_hdmi_clk
,
"bus-hdmi"
,
"ahb1"
,
0x064
,
BIT
(
11
),
0
);
static
SUNXI_CCU_GATE
(
bus_de_clk
,
"bus-de"
,
"ahb1"
,
0x064
,
BIT
(
12
),
0
);
static
SUNXI_CCU_GATE
(
bus_gpu_clk
,
"bus-gpu"
,
"ahb1"
,
0x064
,
BIT
(
20
),
0
);
static
SUNXI_CCU_GATE
(
bus_msgbox_clk
,
"bus-msgbox"
,
"ahb1"
,
0x064
,
BIT
(
21
),
0
);
static
SUNXI_CCU_GATE
(
bus_spinlock_clk
,
"bus-spinlock"
,
"ahb1"
,
0x064
,
BIT
(
22
),
0
);
static
SUNXI_CCU_GATE
(
bus_codec_clk
,
"bus-codec"
,
"apb1"
,
0x068
,
BIT
(
0
),
0
);
static
SUNXI_CCU_GATE
(
bus_spdif_clk
,
"bus-spdif"
,
"apb1"
,
0x068
,
BIT
(
1
),
0
);
static
SUNXI_CCU_GATE
(
bus_pio_clk
,
"bus-pio"
,
"apb1"
,
0x068
,
BIT
(
5
),
0
);
static
SUNXI_CCU_GATE
(
bus_ths_clk
,
"bus-ths"
,
"apb1"
,
0x068
,
BIT
(
8
),
0
);
static
SUNXI_CCU_GATE
(
bus_i2s0_clk
,
"bus-i2s0"
,
"apb1"
,
0x068
,
BIT
(
12
),
0
);
static
SUNXI_CCU_GATE
(
bus_i2s1_clk
,
"bus-i2s1"
,
"apb1"
,
0x068
,
BIT
(
13
),
0
);
static
SUNXI_CCU_GATE
(
bus_i2s2_clk
,
"bus-i2s2"
,
"apb1"
,
0x068
,
BIT
(
14
),
0
);
static
SUNXI_CCU_GATE
(
bus_i2c0_clk
,
"bus-i2c0"
,
"apb2"
,
0x06c
,
BIT
(
0
),
0
);
static
SUNXI_CCU_GATE
(
bus_i2c1_clk
,
"bus-i2c1"
,
"apb2"
,
0x06c
,
BIT
(
1
),
0
);
static
SUNXI_CCU_GATE
(
bus_i2c2_clk
,
"bus-i2c2"
,
"apb2"
,
0x06c
,
BIT
(
2
),
0
);
static
SUNXI_CCU_GATE
(
bus_uart0_clk
,
"bus-uart0"
,
"apb2"
,
0x06c
,
BIT
(
16
),
0
);
static
SUNXI_CCU_GATE
(
bus_uart1_clk
,
"bus-uart1"
,
"apb2"
,
0x06c
,
BIT
(
17
),
0
);
static
SUNXI_CCU_GATE
(
bus_uart2_clk
,
"bus-uart2"
,
"apb2"
,
0x06c
,
BIT
(
18
),
0
);
static
SUNXI_CCU_GATE
(
bus_uart3_clk
,
"bus-uart3"
,
"apb2"
,
0x06c
,
BIT
(
19
),
0
);
static
SUNXI_CCU_GATE
(
bus_scr_clk
,
"bus-scr"
,
"apb2"
,
0x06c
,
BIT
(
20
),
0
);
static
SUNXI_CCU_GATE
(
bus_ephy_clk
,
"bus-ephy"
,
"ahb1"
,
0x070
,
BIT
(
0
),
0
);
static
SUNXI_CCU_GATE
(
bus_dbg_clk
,
"bus-dbg"
,
"ahb1"
,
0x070
,
BIT
(
7
),
0
);
static
struct
clk_div_table
ths_div_table
[]
=
{
{
.
val
=
0
,
.
div
=
1
},
{
.
val
=
1
,
.
div
=
2
},
{
.
val
=
2
,
.
div
=
4
},
{
.
val
=
3
,
.
div
=
6
},
};
static
SUNXI_CCU_DIV_TABLE_WITH_GATE
(
ths_clk
,
"ths"
,
"osc24M"
,
0x074
,
0
,
2
,
ths_div_table
,
BIT
(
31
),
0
);
static
const
char
*
const
mod0_default_parents
[]
=
{
"osc24M"
,
"pll-periph0"
,
"pll-periph1"
};
static
SUNXI_CCU_MP_WITH_MUX_GATE
(
nand_clk
,
"nand"
,
mod0_default_parents
,
0x080
,
0
,
4
,
/* M */
16
,
2
,
/* P */
24
,
2
,
/* mux */
BIT
(
31
),
/* gate */
0
);
static
SUNXI_CCU_MP_WITH_MUX_GATE
(
mmc0_clk
,
"mmc0"
,
mod0_default_parents
,
0x088
,
0
,
4
,
/* M */
16
,
2
,
/* P */
24
,
2
,
/* mux */
BIT
(
31
),
/* gate */
0
);
static
SUNXI_CCU_PHASE
(
mmc0_sample_clk
,
"mmc0_sample"
,
"mmc0"
,
0x088
,
20
,
3
,
0
);
static
SUNXI_CCU_PHASE
(
mmc0_output_clk
,
"mmc0_output"
,
"mmc0"
,
0x088
,
8
,
3
,
0
);
static
SUNXI_CCU_MP_WITH_MUX_GATE
(
mmc1_clk
,
"mmc1"
,
mod0_default_parents
,
0x08c
,
0
,
4
,
/* M */
16
,
2
,
/* P */
24
,
2
,
/* mux */
BIT
(
31
),
/* gate */
0
);
static
SUNXI_CCU_PHASE
(
mmc1_sample_clk
,
"mmc1_sample"
,
"mmc1"
,
0x08c
,
20
,
3
,
0
);
static
SUNXI_CCU_PHASE
(
mmc1_output_clk
,
"mmc1_output"
,
"mmc1"
,
0x08c
,
8
,
3
,
0
);
static
SUNXI_CCU_MP_WITH_MUX_GATE
(
mmc2_clk
,
"mmc2"
,
mod0_default_parents
,
0x090
,
0
,
4
,
/* M */
16
,
2
,
/* P */
24
,
2
,
/* mux */
BIT
(
31
),
/* gate */
0
);
static
SUNXI_CCU_PHASE
(
mmc2_sample_clk
,
"mmc2_sample"
,
"mmc2"
,
0x090
,
20
,
3
,
0
);
static
SUNXI_CCU_PHASE
(
mmc2_output_clk
,
"mmc2_output"
,
"mmc2"
,
0x090
,
8
,
3
,
0
);
static
const
char
*
const
ts_parents
[]
=
{
"osc24M"
,
"pll-periph0"
,
};
static
SUNXI_CCU_MP_WITH_MUX_GATE
(
ts_clk
,
"ts"
,
ts_parents
,
0x098
,
0
,
4
,
/* M */
16
,
2
,
/* P */
24
,
2
,
/* mux */
BIT
(
31
),
/* gate */
0
);
static
SUNXI_CCU_MP_WITH_MUX_GATE
(
ce_clk
,
"ce"
,
mod0_default_parents
,
0x09c
,
0
,
4
,
/* M */
16
,
2
,
/* P */
24
,
2
,
/* mux */
BIT
(
31
),
/* gate */
0
);
static
SUNXI_CCU_MP_WITH_MUX_GATE
(
spi0_clk
,
"spi0"
,
mod0_default_parents
,
0x0a0
,
0
,
4
,
/* M */
16
,
2
,
/* P */
24
,
2
,
/* mux */
BIT
(
31
),
/* gate */
0
);
static
SUNXI_CCU_MP_WITH_MUX_GATE
(
spi1_clk
,
"spi1"
,
mod0_default_parents
,
0x0a4
,
0
,
4
,
/* M */
16
,
2
,
/* P */
24
,
2
,
/* mux */
BIT
(
31
),
/* gate */
0
);
static
const
char
*
const
i2s_parents
[]
=
{
"pll-audio-8x"
,
"pll-audio-4x"
,
"pll-audio-2x"
,
"pll-audio"
};
static
SUNXI_CCU_MUX_WITH_GATE
(
i2s0_clk
,
"i2s0"
,
i2s_parents
,
0x0b0
,
16
,
2
,
BIT
(
31
),
0
);
static
SUNXI_CCU_MUX_WITH_GATE
(
i2s1_clk
,
"i2s1"
,
i2s_parents
,
0x0b4
,
16
,
2
,
BIT
(
31
),
0
);
static
SUNXI_CCU_MUX_WITH_GATE
(
i2s2_clk
,
"i2s2"
,
i2s_parents
,
0x0b8
,
16
,
2
,
BIT
(
31
),
0
);
static
SUNXI_CCU_M_WITH_GATE
(
spdif_clk
,
"spdif"
,
"pll-audio"
,
0x0c0
,
0
,
4
,
BIT
(
31
),
0
);
static
SUNXI_CCU_GATE
(
usb_phy0_clk
,
"usb-phy0"
,
"osc24M"
,
0x0cc
,
BIT
(
8
),
0
);
static
SUNXI_CCU_GATE
(
usb_phy1_clk
,
"usb-phy1"
,
"osc24M"
,
0x0cc
,
BIT
(
9
),
0
);
static
SUNXI_CCU_GATE
(
usb_phy2_clk
,
"usb-phy2"
,
"osc24M"
,
0x0cc
,
BIT
(
10
),
0
);
static
SUNXI_CCU_GATE
(
usb_phy3_clk
,
"usb-phy3"
,
"osc24M"
,
0x0cc
,
BIT
(
11
),
0
);
static
SUNXI_CCU_GATE
(
usb_ohci0_clk
,
"usb-ohci0"
,
"osc24M"
,
0x0cc
,
BIT
(
16
),
0
);
static
SUNXI_CCU_GATE
(
usb_ohci1_clk
,
"usb-ohci1"
,
"osc24M"
,
0x0cc
,
BIT
(
17
),
0
);
static
SUNXI_CCU_GATE
(
usb_ohci2_clk
,
"usb-ohci2"
,
"osc24M"
,
0x0cc
,
BIT
(
18
),
0
);
static
SUNXI_CCU_GATE
(
usb_ohci3_clk
,
"usb-ohci3"
,
"osc24M"
,
0x0cc
,
BIT
(
19
),
0
);
static
const
char
*
const
dram_parents
[]
=
{
"pll-ddr"
,
"pll-periph0-2x"
};
static
SUNXI_CCU_M_WITH_MUX
(
dram_clk
,
"dram"
,
dram_parents
,
0x0f4
,
0
,
4
,
20
,
2
,
CLK_IS_CRITICAL
);
static
SUNXI_CCU_GATE
(
dram_ve_clk
,
"dram-ve"
,
"dram"
,
0x100
,
BIT
(
0
),
0
);
static
SUNXI_CCU_GATE
(
dram_csi_clk
,
"dram-csi"
,
"dram"
,
0x100
,
BIT
(
1
),
0
);
static
SUNXI_CCU_GATE
(
dram_deinterlace_clk
,
"dram-deinterlace"
,
"dram"
,
0x100
,
BIT
(
2
),
0
);
static
SUNXI_CCU_GATE
(
dram_ts_clk
,
"dram-ts"
,
"dram"
,
0x100
,
BIT
(
3
),
0
);
static
const
char
*
const
de_parents
[]
=
{
"pll-periph0-2x"
,
"pll-de"
};
static
SUNXI_CCU_M_WITH_MUX_GATE
(
de_clk
,
"de"
,
de_parents
,
0x104
,
0
,
4
,
24
,
3
,
BIT
(
31
),
0
);
static
const
char
*
const
tcon_parents
[]
=
{
"pll-video"
};
static
SUNXI_CCU_M_WITH_MUX_GATE
(
tcon_clk
,
"tcon"
,
tcon_parents
,
0x118
,
0
,
4
,
24
,
3
,
BIT
(
31
),
0
);
static
const
char
*
const
tve_parents
[]
=
{
"pll-de"
,
"pll-periph1"
};
static
SUNXI_CCU_M_WITH_MUX_GATE
(
tve_clk
,
"tve"
,
tve_parents
,
0x120
,
0
,
4
,
24
,
3
,
BIT
(
31
),
0
);
static
const
char
*
const
deinterlace_parents
[]
=
{
"pll-periph0"
,
"pll-periph1"
};
static
SUNXI_CCU_M_WITH_MUX_GATE
(
deinterlace_clk
,
"deinterlace"
,
deinterlace_parents
,
0x124
,
0
,
4
,
24
,
3
,
BIT
(
31
),
0
);
static
SUNXI_CCU_GATE
(
csi_misc_clk
,
"csi-misc"
,
"osc24M"
,
0x130
,
BIT
(
31
),
0
);
static
const
char
*
const
csi_sclk_parents
[]
=
{
"pll-periph0"
,
"pll-periph1"
};
static
SUNXI_CCU_M_WITH_MUX_GATE
(
csi_sclk_clk
,
"csi-sclk"
,
csi_sclk_parents
,
0x134
,
16
,
4
,
24
,
3
,
BIT
(
31
),
0
);
static
const
char
*
const
csi_mclk_parents
[]
=
{
"osc24M"
,
"pll-video"
,
"pll-periph0"
};
static
SUNXI_CCU_M_WITH_MUX_GATE
(
csi_mclk_clk
,
"csi-mclk"
,
csi_mclk_parents
,
0x134
,
0
,
5
,
8
,
3
,
BIT
(
15
),
0
);
static
SUNXI_CCU_M_WITH_GATE
(
ve_clk
,
"ve"
,
"pll-ve"
,
0x13c
,
16
,
3
,
BIT
(
31
),
0
);
static
SUNXI_CCU_GATE
(
ac_dig_clk
,
"ac-dig"
,
"pll-audio"
,
0x140
,
BIT
(
31
),
0
);
static
SUNXI_CCU_GATE
(
avs_clk
,
"avs"
,
"osc24M"
,
0x144
,
BIT
(
31
),
0
);
static
const
char
*
const
hdmi_parents
[]
=
{
"pll-video"
};
static
SUNXI_CCU_M_WITH_MUX_GATE
(
hdmi_clk
,
"hdmi"
,
hdmi_parents
,
0x150
,
0
,
4
,
24
,
2
,
BIT
(
31
),
0
);
static
SUNXI_CCU_GATE
(
hdmi_ddc_clk
,
"hdmi-ddc"
,
"osc24M"
,
0x154
,
BIT
(
31
),
0
);
static
const
char
*
const
mbus_parents
[]
=
{
"osc24M"
,
"pll-periph0-2x"
,
"pll-ddr"
};
static
SUNXI_CCU_M_WITH_MUX_GATE
(
mbus_clk
,
"mbus"
,
mbus_parents
,
0x15c
,
0
,
3
,
24
,
2
,
BIT
(
31
),
CLK_IS_CRITICAL
);
static
SUNXI_CCU_M_WITH_GATE
(
gpu_clk
,
"gpu"
,
"pll-gpu"
,
0x1a0
,
0
,
3
,
BIT
(
31
),
0
);
static
struct
ccu_common
*
sun8i_h3_ccu_clks
[]
=
{
&
pll_cpux_clk
.
common
,
&
pll_audio_base_clk
.
common
,
&
pll_video_clk
.
common
,
&
pll_ve_clk
.
common
,
&
pll_ddr_clk
.
common
,
&
pll_periph0_clk
.
common
,
&
pll_gpu_clk
.
common
,
&
pll_periph1_clk
.
common
,
&
pll_de_clk
.
common
,
&
cpux_clk
.
common
,
&
axi_clk
.
common
,
&
ahb1_clk
.
common
,
&
apb1_clk
.
common
,
&
apb2_clk
.
common
,
&
ahb2_clk
.
common
,
&
bus_ce_clk
.
common
,
&
bus_dma_clk
.
common
,
&
bus_mmc0_clk
.
common
,
&
bus_mmc1_clk
.
common
,
&
bus_mmc2_clk
.
common
,
&
bus_nand_clk
.
common
,
&
bus_dram_clk
.
common
,
&
bus_emac_clk
.
common
,
&
bus_ts_clk
.
common
,
&
bus_hstimer_clk
.
common
,
&
bus_spi0_clk
.
common
,
&
bus_spi1_clk
.
common
,
&
bus_otg_clk
.
common
,
&
bus_ehci0_clk
.
common
,
&
bus_ehci1_clk
.
common
,
&
bus_ehci2_clk
.
common
,
&
bus_ehci3_clk
.
common
,
&
bus_ohci0_clk
.
common
,
&
bus_ohci1_clk
.
common
,
&
bus_ohci2_clk
.
common
,
&
bus_ohci3_clk
.
common
,
&
bus_ve_clk
.
common
,
&
bus_tcon0_clk
.
common
,
&
bus_tcon1_clk
.
common
,
&
bus_deinterlace_clk
.
common
,
&
bus_csi_clk
.
common
,
&
bus_tve_clk
.
common
,
&
bus_hdmi_clk
.
common
,
&
bus_de_clk
.
common
,
&
bus_gpu_clk
.
common
,
&
bus_msgbox_clk
.
common
,
&
bus_spinlock_clk
.
common
,
&
bus_codec_clk
.
common
,
&
bus_spdif_clk
.
common
,
&
bus_pio_clk
.
common
,
&
bus_ths_clk
.
common
,
&
bus_i2s0_clk
.
common
,
&
bus_i2s1_clk
.
common
,
&
bus_i2s2_clk
.
common
,
&
bus_i2c0_clk
.
common
,
&
bus_i2c1_clk
.
common
,
&
bus_i2c2_clk
.
common
,
&
bus_uart0_clk
.
common
,
&
bus_uart1_clk
.
common
,
&
bus_uart2_clk
.
common
,
&
bus_uart3_clk
.
common
,
&
bus_scr_clk
.
common
,
&
bus_ephy_clk
.
common
,
&
bus_dbg_clk
.
common
,
&
ths_clk
.
common
,
&
nand_clk
.
common
,
&
mmc0_clk
.
common
,
&
mmc0_sample_clk
.
common
,
&
mmc0_output_clk
.
common
,
&
mmc1_clk
.
common
,
&
mmc1_sample_clk
.
common
,
&
mmc1_output_clk
.
common
,
&
mmc2_clk
.
common
,
&
mmc2_sample_clk
.
common
,
&
mmc2_output_clk
.
common
,
&
ts_clk
.
common
,
&
ce_clk
.
common
,
&
spi0_clk
.
common
,
&
spi1_clk
.
common
,
&
i2s0_clk
.
common
,
&
i2s1_clk
.
common
,
&
i2s2_clk
.
common
,
&
spdif_clk
.
common
,
&
usb_phy0_clk
.
common
,
&
usb_phy1_clk
.
common
,
&
usb_phy2_clk
.
common
,
&
usb_phy3_clk
.
common
,
&
usb_ohci0_clk
.
common
,
&
usb_ohci1_clk
.
common
,
&
usb_ohci2_clk
.
common
,
&
usb_ohci3_clk
.
common
,
&
dram_clk
.
common
,
&
dram_ve_clk
.
common
,
&
dram_csi_clk
.
common
,
&
dram_deinterlace_clk
.
common
,
&
dram_ts_clk
.
common
,
&
de_clk
.
common
,
&
tcon_clk
.
common
,
&
tve_clk
.
common
,
&
deinterlace_clk
.
common
,
&
csi_misc_clk
.
common
,
&
csi_sclk_clk
.
common
,
&
csi_mclk_clk
.
common
,
&
ve_clk
.
common
,
&
ac_dig_clk
.
common
,
&
avs_clk
.
common
,
&
hdmi_clk
.
common
,
&
hdmi_ddc_clk
.
common
,
&
mbus_clk
.
common
,
&
gpu_clk
.
common
,
};
/* We hardcode the divider to 4 for now */
static
CLK_FIXED_FACTOR
(
pll_audio_clk
,
"pll-audio"
,
"pll-audio-base"
,
4
,
1
,
CLK_SET_RATE_PARENT
);
static
CLK_FIXED_FACTOR
(
pll_audio_2x_clk
,
"pll-audio-2x"
,
"pll-audio-base"
,
2
,
1
,
CLK_SET_RATE_PARENT
);
static
CLK_FIXED_FACTOR
(
pll_audio_4x_clk
,
"pll-audio-4x"
,
"pll-audio-base"
,
1
,
1
,
CLK_SET_RATE_PARENT
);
static
CLK_FIXED_FACTOR
(
pll_audio_8x_clk
,
"pll-audio-8x"
,
"pll-audio-base"
,
1
,
2
,
CLK_SET_RATE_PARENT
);
static
CLK_FIXED_FACTOR
(
pll_periph0_2x_clk
,
"pll-periph0-2x"
,
"pll-periph0"
,
1
,
2
,
0
);
static
struct
clk_hw_onecell_data
sun8i_h3_hw_clks
=
{
.
hws
=
{
[
CLK_PLL_CPUX
]
=
&
pll_cpux_clk
.
common
.
hw
,
[
CLK_PLL_AUDIO_BASE
]
=
&
pll_audio_base_clk
.
common
.
hw
,
[
CLK_PLL_AUDIO
]
=
&
pll_audio_clk
.
hw
,
[
CLK_PLL_AUDIO_2X
]
=
&
pll_audio_2x_clk
.
hw
,
[
CLK_PLL_AUDIO_4X
]
=
&
pll_audio_4x_clk
.
hw
,
[
CLK_PLL_AUDIO_8X
]
=
&
pll_audio_8x_clk
.
hw
,
[
CLK_PLL_VIDEO
]
=
&
pll_video_clk
.
common
.
hw
,
[
CLK_PLL_VE
]
=
&
pll_ve_clk
.
common
.
hw
,
[
CLK_PLL_DDR
]
=
&
pll_ddr_clk
.
common
.
hw
,
[
CLK_PLL_PERIPH0
]
=
&
pll_periph0_clk
.
common
.
hw
,
[
CLK_PLL_PERIPH0_2X
]
=
&
pll_periph0_2x_clk
.
hw
,
[
CLK_PLL_GPU
]
=
&
pll_gpu_clk
.
common
.
hw
,
[
CLK_PLL_PERIPH1
]
=
&
pll_periph1_clk
.
common
.
hw
,
[
CLK_PLL_DE
]
=
&
pll_de_clk
.
common
.
hw
,
[
CLK_CPUX
]
=
&
cpux_clk
.
common
.
hw
,
[
CLK_AXI
]
=
&
axi_clk
.
common
.
hw
,
[
CLK_AHB1
]
=
&
ahb1_clk
.
common
.
hw
,
[
CLK_APB1
]
=
&
apb1_clk
.
common
.
hw
,
[
CLK_APB2
]
=
&
apb2_clk
.
common
.
hw
,
[
CLK_AHB2
]
=
&
ahb2_clk
.
common
.
hw
,
[
CLK_BUS_CE
]
=
&
bus_ce_clk
.
common
.
hw
,
[
CLK_BUS_DMA
]
=
&
bus_dma_clk
.
common
.
hw
,
[
CLK_BUS_MMC0
]
=
&
bus_mmc0_clk
.
common
.
hw
,
[
CLK_BUS_MMC1
]
=
&
bus_mmc1_clk
.
common
.
hw
,
[
CLK_BUS_MMC2
]
=
&
bus_mmc2_clk
.
common
.
hw
,
[
CLK_BUS_NAND
]
=
&
bus_nand_clk
.
common
.
hw
,
[
CLK_BUS_DRAM
]
=
&
bus_dram_clk
.
common
.
hw
,
[
CLK_BUS_EMAC
]
=
&
bus_emac_clk
.
common
.
hw
,
[
CLK_BUS_TS
]
=
&
bus_ts_clk
.
common
.
hw
,
[
CLK_BUS_HSTIMER
]
=
&
bus_hstimer_clk
.
common
.
hw
,
[
CLK_BUS_SPI0
]
=
&
bus_spi0_clk
.
common
.
hw
,
[
CLK_BUS_SPI1
]
=
&
bus_spi1_clk
.
common
.
hw
,
[
CLK_BUS_OTG
]
=
&
bus_otg_clk
.
common
.
hw
,
[
CLK_BUS_EHCI0
]
=
&
bus_ehci0_clk
.
common
.
hw
,
[
CLK_BUS_EHCI1
]
=
&
bus_ehci1_clk
.
common
.
hw
,
[
CLK_BUS_EHCI2
]
=
&
bus_ehci2_clk
.
common
.
hw
,
[
CLK_BUS_EHCI3
]
=
&
bus_ehci3_clk
.
common
.
hw
,
[
CLK_BUS_OHCI0
]
=
&
bus_ohci0_clk
.
common
.
hw
,
[
CLK_BUS_OHCI1
]
=
&
bus_ohci1_clk
.
common
.
hw
,
[
CLK_BUS_OHCI2
]
=
&
bus_ohci2_clk
.
common
.
hw
,
[
CLK_BUS_OHCI3
]
=
&
bus_ohci3_clk
.
common
.
hw
,
[
CLK_BUS_VE
]
=
&
bus_ve_clk
.
common
.
hw
,
[
CLK_BUS_TCON0
]
=
&
bus_tcon0_clk
.
common
.
hw
,
[
CLK_BUS_TCON1
]
=
&
bus_tcon1_clk
.
common
.
hw
,
[
CLK_BUS_DEINTERLACE
]
=
&
bus_deinterlace_clk
.
common
.
hw
,
[
CLK_BUS_CSI
]
=
&
bus_csi_clk
.
common
.
hw
,
[
CLK_BUS_TVE
]
=
&
bus_tve_clk
.
common
.
hw
,
[
CLK_BUS_HDMI
]
=
&
bus_hdmi_clk
.
common
.
hw
,
[
CLK_BUS_DE
]
=
&
bus_de_clk
.
common
.
hw
,
[
CLK_BUS_GPU
]
=
&
bus_gpu_clk
.
common
.
hw
,
[
CLK_BUS_MSGBOX
]
=
&
bus_msgbox_clk
.
common
.
hw
,
[
CLK_BUS_SPINLOCK
]
=
&
bus_spinlock_clk
.
common
.
hw
,
[
CLK_BUS_CODEC
]
=
&
bus_codec_clk
.
common
.
hw
,
[
CLK_BUS_SPDIF
]
=
&
bus_spdif_clk
.
common
.
hw
,
[
CLK_BUS_PIO
]
=
&
bus_pio_clk
.
common
.
hw
,
[
CLK_BUS_THS
]
=
&
bus_ths_clk
.
common
.
hw
,
[
CLK_BUS_I2S0
]
=
&
bus_i2s0_clk
.
common
.
hw
,
[
CLK_BUS_I2S1
]
=
&
bus_i2s1_clk
.
common
.
hw
,
[
CLK_BUS_I2S2
]
=
&
bus_i2s2_clk
.
common
.
hw
,
[
CLK_BUS_I2C0
]
=
&
bus_i2c0_clk
.
common
.
hw
,
[
CLK_BUS_I2C1
]
=
&
bus_i2c1_clk
.
common
.
hw
,
[
CLK_BUS_I2C2
]
=
&
bus_i2c2_clk
.
common
.
hw
,
[
CLK_BUS_UART0
]
=
&
bus_uart0_clk
.
common
.
hw
,
[
CLK_BUS_UART1
]
=
&
bus_uart1_clk
.
common
.
hw
,
[
CLK_BUS_UART2
]
=
&
bus_uart2_clk
.
common
.
hw
,
[
CLK_BUS_UART3
]
=
&
bus_uart3_clk
.
common
.
hw
,
[
CLK_BUS_SCR
]
=
&
bus_scr_clk
.
common
.
hw
,
[
CLK_BUS_EPHY
]
=
&
bus_ephy_clk
.
common
.
hw
,
[
CLK_BUS_DBG
]
=
&
bus_dbg_clk
.
common
.
hw
,
[
CLK_THS
]
=
&
ths_clk
.
common
.
hw
,
[
CLK_NAND
]
=
&
nand_clk
.
common
.
hw
,
[
CLK_MMC0
]
=
&
mmc0_clk
.
common
.
hw
,
[
CLK_MMC0_SAMPLE
]
=
&
mmc0_sample_clk
.
common
.
hw
,
[
CLK_MMC0_OUTPUT
]
=
&
mmc0_output_clk
.
common
.
hw
,
[
CLK_MMC1
]
=
&
mmc1_clk
.
common
.
hw
,
[
CLK_MMC1_SAMPLE
]
=
&
mmc1_sample_clk
.
common
.
hw
,
[
CLK_MMC1_OUTPUT
]
=
&
mmc1_output_clk
.
common
.
hw
,
[
CLK_MMC2
]
=
&
mmc2_clk
.
common
.
hw
,
[
CLK_MMC2_SAMPLE
]
=
&
mmc2_sample_clk
.
common
.
hw
,
[
CLK_MMC2_OUTPUT
]
=
&
mmc2_output_clk
.
common
.
hw
,
[
CLK_TS
]
=
&
ts_clk
.
common
.
hw
,
[
CLK_CE
]
=
&
ce_clk
.
common
.
hw
,
[
CLK_SPI0
]
=
&
spi0_clk
.
common
.
hw
,
[
CLK_SPI1
]
=
&
spi1_clk
.
common
.
hw
,
[
CLK_I2S0
]
=
&
i2s0_clk
.
common
.
hw
,
[
CLK_I2S1
]
=
&
i2s1_clk
.
common
.
hw
,
[
CLK_I2S2
]
=
&
i2s2_clk
.
common
.
hw
,
[
CLK_SPDIF
]
=
&
spdif_clk
.
common
.
hw
,
[
CLK_USB_PHY0
]
=
&
usb_phy0_clk
.
common
.
hw
,
[
CLK_USB_PHY1
]
=
&
usb_phy1_clk
.
common
.
hw
,
[
CLK_USB_PHY2
]
=
&
usb_phy2_clk
.
common
.
hw
,
[
CLK_USB_PHY3
]
=
&
usb_phy3_clk
.
common
.
hw
,
[
CLK_USB_OHCI0
]
=
&
usb_ohci0_clk
.
common
.
hw
,
[
CLK_USB_OHCI1
]
=
&
usb_ohci1_clk
.
common
.
hw
,
[
CLK_USB_OHCI2
]
=
&
usb_ohci2_clk
.
common
.
hw
,
[
CLK_USB_OHCI3
]
=
&
usb_ohci3_clk
.
common
.
hw
,
[
CLK_DRAM
]
=
&
dram_clk
.
common
.
hw
,
[
CLK_DRAM_VE
]
=
&
dram_ve_clk
.
common
.
hw
,
[
CLK_DRAM_CSI
]
=
&
dram_csi_clk
.
common
.
hw
,
[
CLK_DRAM_DEINTERLACE
]
=
&
dram_deinterlace_clk
.
common
.
hw
,
[
CLK_DRAM_TS
]
=
&
dram_ts_clk
.
common
.
hw
,
[
CLK_DE
]
=
&
de_clk
.
common
.
hw
,
[
CLK_TCON0
]
=
&
tcon_clk
.
common
.
hw
,
[
CLK_TVE
]
=
&
tve_clk
.
common
.
hw
,
[
CLK_DEINTERLACE
]
=
&
deinterlace_clk
.
common
.
hw
,
[
CLK_CSI_MISC
]
=
&
csi_misc_clk
.
common
.
hw
,
[
CLK_CSI_SCLK
]
=
&
csi_sclk_clk
.
common
.
hw
,
[
CLK_CSI_MCLK
]
=
&
csi_mclk_clk
.
common
.
hw
,
[
CLK_VE
]
=
&
ve_clk
.
common
.
hw
,
[
CLK_AC_DIG
]
=
&
ac_dig_clk
.
common
.
hw
,
[
CLK_AVS
]
=
&
avs_clk
.
common
.
hw
,
[
CLK_HDMI
]
=
&
hdmi_clk
.
common
.
hw
,
[
CLK_HDMI_DDC
]
=
&
hdmi_ddc_clk
.
common
.
hw
,
[
CLK_MBUS
]
=
&
mbus_clk
.
common
.
hw
,
[
CLK_GPU
]
=
&
gpu_clk
.
common
.
hw
,
},
.
num
=
CLK_NUMBER
,
};
static
struct
ccu_reset_map
sun8i_h3_ccu_resets
[]
=
{
[
RST_USB_PHY0
]
=
{
0x0cc
,
BIT
(
0
)
},
[
RST_USB_PHY1
]
=
{
0x0cc
,
BIT
(
1
)
},
[
RST_USB_PHY2
]
=
{
0x0cc
,
BIT
(
2
)
},
[
RST_USB_PHY3
]
=
{
0x0cc
,
BIT
(
3
)
},
[
RST_MBUS
]
=
{
0x0fc
,
BIT
(
31
)
},
[
RST_BUS_CE
]
=
{
0x2c0
,
BIT
(
5
)
},
[
RST_BUS_DMA
]
=
{
0x2c0
,
BIT
(
6
)
},
[
RST_BUS_MMC0
]
=
{
0x2c0
,
BIT
(
8
)
},
[
RST_BUS_MMC1
]
=
{
0x2c0
,
BIT
(
9
)
},
[
RST_BUS_MMC2
]
=
{
0x2c0
,
BIT
(
10
)
},
[
RST_BUS_NAND
]
=
{
0x2c0
,
BIT
(
13
)
},
[
RST_BUS_DRAM
]
=
{
0x2c0
,
BIT
(
14
)
},
[
RST_BUS_EMAC
]
=
{
0x2c0
,
BIT
(
17
)
},
[
RST_BUS_TS
]
=
{
0x2c0
,
BIT
(
18
)
},
[
RST_BUS_HSTIMER
]
=
{
0x2c0
,
BIT
(
19
)
},
[
RST_BUS_SPI0
]
=
{
0x2c0
,
BIT
(
20
)
},
[
RST_BUS_SPI1
]
=
{
0x2c0
,
BIT
(
21
)
},
[
RST_BUS_OTG
]
=
{
0x2c0
,
BIT
(
23
)
},
[
RST_BUS_EHCI0
]
=
{
0x2c0
,
BIT
(
24
)
},
[
RST_BUS_EHCI1
]
=
{
0x2c0
,
BIT
(
25
)
},
[
RST_BUS_EHCI2
]
=
{
0x2c0
,
BIT
(
26
)
},
[
RST_BUS_EHCI3
]
=
{
0x2c0
,
BIT
(
27
)
},
[
RST_BUS_OHCI0
]
=
{
0x2c0
,
BIT
(
28
)
},
[
RST_BUS_OHCI1
]
=
{
0x2c0
,
BIT
(
29
)
},
[
RST_BUS_OHCI2
]
=
{
0x2c0
,
BIT
(
30
)
},
[
RST_BUS_OHCI3
]
=
{
0x2c0
,
BIT
(
31
)
},
[
RST_BUS_VE
]
=
{
0x2c4
,
BIT
(
0
)
},
[
RST_BUS_TCON0
]
=
{
0x2c4
,
BIT
(
3
)
},
[
RST_BUS_TCON1
]
=
{
0x2c4
,
BIT
(
4
)
},
[
RST_BUS_DEINTERLACE
]
=
{
0x2c4
,
BIT
(
5
)
},
[
RST_BUS_CSI
]
=
{
0x2c4
,
BIT
(
8
)
},
[
RST_BUS_TVE
]
=
{
0x2c4
,
BIT
(
9
)
},
[
RST_BUS_HDMI0
]
=
{
0x2c4
,
BIT
(
10
)
},
[
RST_BUS_HDMI1
]
=
{
0x2c4
,
BIT
(
11
)
},
[
RST_BUS_DE
]
=
{
0x2c4
,
BIT
(
12
)
},
[
RST_BUS_GPU
]
=
{
0x2c4
,
BIT
(
20
)
},
[
RST_BUS_MSGBOX
]
=
{
0x2c4
,
BIT
(
21
)
},
[
RST_BUS_SPINLOCK
]
=
{
0x2c4
,
BIT
(
22
)
},
[
RST_BUS_DBG
]
=
{
0x2c4
,
BIT
(
31
)
},
[
RST_BUS_EPHY
]
=
{
0x2c8
,
BIT
(
2
)
},
[
RST_BUS_CODEC
]
=
{
0x2d0
,
BIT
(
0
)
},
[
RST_BUS_SPDIF
]
=
{
0x2d0
,
BIT
(
1
)
},
[
RST_BUS_THS
]
=
{
0x2d0
,
BIT
(
8
)
},
[
RST_BUS_I2S0
]
=
{
0x2d0
,
BIT
(
12
)
},
[
RST_BUS_I2S1
]
=
{
0x2d0
,
BIT
(
13
)
},
[
RST_BUS_I2S2
]
=
{
0x2d0
,
BIT
(
14
)
},
[
RST_BUS_I2C0
]
=
{
0x2d4
,
BIT
(
0
)
},
[
RST_BUS_I2C1
]
=
{
0x2d4
,
BIT
(
1
)
},
[
RST_BUS_I2C2
]
=
{
0x2d4
,
BIT
(
2
)
},
[
RST_BUS_UART0
]
=
{
0x2d4
,
BIT
(
16
)
},
[
RST_BUS_UART1
]
=
{
0x2d4
,
BIT
(
17
)
},
[
RST_BUS_UART2
]
=
{
0x2d4
,
BIT
(
18
)
},
[
RST_BUS_UART3
]
=
{
0x2d4
,
BIT
(
19
)
},
[
RST_BUS_SCR
]
=
{
0x2d4
,
BIT
(
20
)
},
};
static
const
struct
sunxi_ccu_desc
sun8i_h3_ccu_desc
=
{
.
ccu_clks
=
sun8i_h3_ccu_clks
,
.
num_ccu_clks
=
ARRAY_SIZE
(
sun8i_h3_ccu_clks
),
.
hw_clks
=
&
sun8i_h3_hw_clks
,
.
resets
=
sun8i_h3_ccu_resets
,
.
num_resets
=
ARRAY_SIZE
(
sun8i_h3_ccu_resets
),
};
static
void
__init
sun8i_h3_ccu_setup
(
struct
device_node
*
node
)
{
void
__iomem
*
reg
;
u32
val
;
reg
=
of_io_request_and_map
(
node
,
0
,
of_node_full_name
(
node
));
if
(
IS_ERR
(
reg
))
{
pr_err
(
"%s: Could not map the clock registers
\n
"
,
of_node_full_name
(
node
));
return
;
}
/* Force the PLL-Audio-1x divider to 4 */
val
=
readl
(
reg
+
SUN8I_H3_PLL_AUDIO_REG
);
val
&=
~
GENMASK
(
4
,
0
);
writel
(
val
|
3
,
reg
+
SUN8I_H3_PLL_AUDIO_REG
);
sunxi_ccu_probe
(
node
,
reg
,
&
sun8i_h3_ccu_desc
);
}
CLK_OF_DECLARE
(
sun8i_h3_ccu
,
"allwinner,sun8i-h3-ccu"
,
sun8i_h3_ccu_setup
);
drivers/clk/sunxi-ng/ccu-sun8i-h3.h
0 → 100644
View file @
7adb7695
/*
* Copyright 2016 Maxime Ripard
*
* Maxime Ripard <maxime.ripard@free-electrons.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 program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _CCU_SUN8I_H3_H_
#define _CCU_SUN8I_H3_H_
#include <dt-bindings/clock/sun8i-h3-ccu.h>
#include <dt-bindings/reset/sun8i-h3-ccu.h>
#define CLK_PLL_CPUX 0
#define CLK_PLL_AUDIO_BASE 1
#define CLK_PLL_AUDIO 2
#define CLK_PLL_AUDIO_2X 3
#define CLK_PLL_AUDIO_4X 4
#define CLK_PLL_AUDIO_8X 5
#define CLK_PLL_VIDEO 6
#define CLK_PLL_VE 7
#define CLK_PLL_DDR 8
#define CLK_PLL_PERIPH0 9
#define CLK_PLL_PERIPH0_2X 10
#define CLK_PLL_GPU 11
#define CLK_PLL_PERIPH1 12
#define CLK_PLL_DE 13
/* The CPUX clock is exported */
#define CLK_AXI 15
#define CLK_AHB1 16
#define CLK_APB1 17
#define CLK_APB2 18
#define CLK_AHB2 19
/* All the bus gates are exported */
/* The first bunch of module clocks are exported */
#define CLK_DRAM 96
/* All the DRAM gates are exported */
/* Some more module clocks are exported */
#define CLK_MBUS 113
/* And the GPU module clock is exported */
#define CLK_NUMBER (CLK_GPU + 1)
#endif
/* _CCU_SUN8I_H3_H_ */
drivers/clk/sunxi-ng/ccu_common.c
0 → 100644
View file @
7adb7695
/*
* Copyright 2016 Maxime Ripard
*
* Maxime Ripard <maxime.ripard@free-electrons.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 program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/clk-provider.h>
#include <linux/iopoll.h>
#include <linux/slab.h>
#include "ccu_common.h"
#include "ccu_reset.h"
static
DEFINE_SPINLOCK
(
ccu_lock
);
void
ccu_helper_wait_for_lock
(
struct
ccu_common
*
common
,
u32
lock
)
{
u32
reg
;
if
(
!
lock
)
return
;
WARN_ON
(
readl_relaxed_poll_timeout
(
common
->
base
+
common
->
reg
,
reg
,
!
(
reg
&
lock
),
100
,
70000
));
}
int
sunxi_ccu_probe
(
struct
device_node
*
node
,
void
__iomem
*
reg
,
const
struct
sunxi_ccu_desc
*
desc
)
{
struct
ccu_reset
*
reset
;
int
i
,
ret
;
for
(
i
=
0
;
i
<
desc
->
num_ccu_clks
;
i
++
)
{
struct
ccu_common
*
cclk
=
desc
->
ccu_clks
[
i
];
if
(
!
cclk
)
continue
;
cclk
->
base
=
reg
;
cclk
->
lock
=
&
ccu_lock
;
}
for
(
i
=
0
;
i
<
desc
->
hw_clks
->
num
;
i
++
)
{
struct
clk_hw
*
hw
=
desc
->
hw_clks
->
hws
[
i
];
if
(
!
hw
)
continue
;
ret
=
clk_hw_register
(
NULL
,
hw
);
if
(
ret
)
{
pr_err
(
"Couldn't register clock %s
\n
"
,
clk_hw_get_name
(
hw
));
goto
err_clk_unreg
;
}
}
ret
=
of_clk_add_hw_provider
(
node
,
of_clk_hw_onecell_get
,
desc
->
hw_clks
);
if
(
ret
)
goto
err_clk_unreg
;
reset
=
kzalloc
(
sizeof
(
*
reset
),
GFP_KERNEL
);
reset
->
rcdev
.
of_node
=
node
;
reset
->
rcdev
.
ops
=
&
ccu_reset_ops
;
reset
->
rcdev
.
owner
=
THIS_MODULE
;
reset
->
rcdev
.
nr_resets
=
desc
->
num_resets
;
reset
->
base
=
reg
;
reset
->
lock
=
&
ccu_lock
;
reset
->
reset_map
=
desc
->
resets
;
ret
=
reset_controller_register
(
&
reset
->
rcdev
);
if
(
ret
)
goto
err_of_clk_unreg
;
return
0
;
err_of_clk_unreg:
err_clk_unreg:
return
ret
;
}
drivers/clk/sunxi-ng/ccu_common.h
0 → 100644
View file @
7adb7695
/*
* Copyright (c) 2016 Maxime Ripard. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _COMMON_H_
#define _COMMON_H_
#include <linux/compiler.h>
#include <linux/clk-provider.h>
#define CCU_FEATURE_FRACTIONAL BIT(0)
#define CCU_FEATURE_VARIABLE_PREDIV BIT(1)
#define CCU_FEATURE_FIXED_PREDIV BIT(2)
#define CCU_FEATURE_FIXED_POSTDIV BIT(3)
struct
device_node
;
#define CLK_HW_INIT(_name, _parent, _ops, _flags) \
&(struct clk_init_data) { \
.flags = _flags, \
.name = _name, \
.parent_names = (const char *[]) { _parent }, \
.num_parents = 1, \
.ops = _ops, \
}
#define CLK_HW_INIT_PARENTS(_name, _parents, _ops, _flags) \
&(struct clk_init_data) { \
.flags = _flags, \
.name = _name, \
.parent_names = _parents, \
.num_parents = ARRAY_SIZE(_parents), \
.ops = _ops, \
}
#define CLK_FIXED_FACTOR(_struct, _name, _parent, \
_div, _mult, _flags) \
struct clk_fixed_factor _struct = { \
.div = _div, \
.mult = _mult, \
.hw.init = CLK_HW_INIT(_name, \
_parent, \
&clk_fixed_factor_ops, \
_flags), \
}
struct
ccu_common
{
void
__iomem
*
base
;
u16
reg
;
unsigned
long
features
;
spinlock_t
*
lock
;
struct
clk_hw
hw
;
};
static
inline
struct
ccu_common
*
hw_to_ccu_common
(
struct
clk_hw
*
hw
)
{
return
container_of
(
hw
,
struct
ccu_common
,
hw
);
}
struct
sunxi_ccu_desc
{
struct
ccu_common
**
ccu_clks
;
unsigned
long
num_ccu_clks
;
struct
clk_hw_onecell_data
*
hw_clks
;
struct
ccu_reset_map
*
resets
;
unsigned
long
num_resets
;
};
void
ccu_helper_wait_for_lock
(
struct
ccu_common
*
common
,
u32
lock
);
int
sunxi_ccu_probe
(
struct
device_node
*
node
,
void
__iomem
*
reg
,
const
struct
sunxi_ccu_desc
*
desc
);
#endif
/* _COMMON_H_ */
drivers/clk/sunxi-ng/ccu_div.c
0 → 100644
View file @
7adb7695
/*
* Copyright (C) 2016 Maxime Ripard
* Maxime Ripard <maxime.ripard@free-electrons.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.
*/
#include <linux/clk-provider.h>
#include "ccu_gate.h"
#include "ccu_div.h"
static
unsigned
long
ccu_div_round_rate
(
struct
ccu_mux_internal
*
mux
,
unsigned
long
parent_rate
,
unsigned
long
rate
,
void
*
data
)
{
struct
ccu_div
*
cd
=
data
;
unsigned
long
val
;
/*
* We can't use divider_round_rate that assumes that there's
* several parents, while we might be called to evaluate
* several different parents.
*/
val
=
divider_get_val
(
rate
,
parent_rate
,
cd
->
div
.
table
,
cd
->
div
.
width
,
cd
->
div
.
flags
);
return
divider_recalc_rate
(
&
cd
->
common
.
hw
,
parent_rate
,
val
,
cd
->
div
.
table
,
cd
->
div
.
flags
);
}
static
void
ccu_div_disable
(
struct
clk_hw
*
hw
)
{
struct
ccu_div
*
cd
=
hw_to_ccu_div
(
hw
);
return
ccu_gate_helper_disable
(
&
cd
->
common
,
cd
->
enable
);
}
static
int
ccu_div_enable
(
struct
clk_hw
*
hw
)
{
struct
ccu_div
*
cd
=
hw_to_ccu_div
(
hw
);
return
ccu_gate_helper_enable
(
&
cd
->
common
,
cd
->
enable
);
}
static
int
ccu_div_is_enabled
(
struct
clk_hw
*
hw
)
{
struct
ccu_div
*
cd
=
hw_to_ccu_div
(
hw
);
return
ccu_gate_helper_is_enabled
(
&
cd
->
common
,
cd
->
enable
);
}
static
unsigned
long
ccu_div_recalc_rate
(
struct
clk_hw
*
hw
,
unsigned
long
parent_rate
)
{
struct
ccu_div
*
cd
=
hw_to_ccu_div
(
hw
);
unsigned
long
val
;
u32
reg
;
reg
=
readl
(
cd
->
common
.
base
+
cd
->
common
.
reg
);
val
=
reg
>>
cd
->
div
.
shift
;
val
&=
(
1
<<
cd
->
div
.
width
)
-
1
;
ccu_mux_helper_adjust_parent_for_prediv
(
&
cd
->
common
,
&
cd
->
mux
,
-
1
,
&
parent_rate
);
return
divider_recalc_rate
(
hw
,
parent_rate
,
val
,
cd
->
div
.
table
,
cd
->
div
.
flags
);
}
static
int
ccu_div_determine_rate
(
struct
clk_hw
*
hw
,
struct
clk_rate_request
*
req
)
{
struct
ccu_div
*
cd
=
hw_to_ccu_div
(
hw
);
return
ccu_mux_helper_determine_rate
(
&
cd
->
common
,
&
cd
->
mux
,
req
,
ccu_div_round_rate
,
cd
);
}
static
int
ccu_div_set_rate
(
struct
clk_hw
*
hw
,
unsigned
long
rate
,
unsigned
long
parent_rate
)
{
struct
ccu_div
*
cd
=
hw_to_ccu_div
(
hw
);
unsigned
long
flags
;
unsigned
long
val
;
u32
reg
;
ccu_mux_helper_adjust_parent_for_prediv
(
&
cd
->
common
,
&
cd
->
mux
,
-
1
,
&
parent_rate
);
val
=
divider_get_val
(
rate
,
parent_rate
,
cd
->
div
.
table
,
cd
->
div
.
width
,
cd
->
div
.
flags
);
spin_lock_irqsave
(
cd
->
common
.
lock
,
flags
);
reg
=
readl
(
cd
->
common
.
base
+
cd
->
common
.
reg
);
reg
&=
~
GENMASK
(
cd
->
div
.
width
+
cd
->
div
.
shift
-
1
,
cd
->
div
.
shift
);
writel
(
reg
|
(
val
<<
cd
->
div
.
shift
),
cd
->
common
.
base
+
cd
->
common
.
reg
);
spin_unlock_irqrestore
(
cd
->
common
.
lock
,
flags
);
return
0
;
}
static
u8
ccu_div_get_parent
(
struct
clk_hw
*
hw
)
{
struct
ccu_div
*
cd
=
hw_to_ccu_div
(
hw
);
return
ccu_mux_helper_get_parent
(
&
cd
->
common
,
&
cd
->
mux
);
}
static
int
ccu_div_set_parent
(
struct
clk_hw
*
hw
,
u8
index
)
{
struct
ccu_div
*
cd
=
hw_to_ccu_div
(
hw
);
return
ccu_mux_helper_set_parent
(
&
cd
->
common
,
&
cd
->
mux
,
index
);
}
const
struct
clk_ops
ccu_div_ops
=
{
.
disable
=
ccu_div_disable
,
.
enable
=
ccu_div_enable
,
.
is_enabled
=
ccu_div_is_enabled
,
.
get_parent
=
ccu_div_get_parent
,
.
set_parent
=
ccu_div_set_parent
,
.
determine_rate
=
ccu_div_determine_rate
,
.
recalc_rate
=
ccu_div_recalc_rate
,
.
set_rate
=
ccu_div_set_rate
,
};
drivers/clk/sunxi-ng/ccu_div.h
0 → 100644
View file @
7adb7695
/*
* Copyright (c) 2016 Maxime Ripard. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _CCU_DIV_H_
#define _CCU_DIV_H_
#include <linux/clk-provider.h>
#include "ccu_common.h"
#include "ccu_mux.h"
struct
_ccu_div
{
u8
shift
;
u8
width
;
u32
flags
;
struct
clk_div_table
*
table
;
};
#define _SUNXI_CCU_DIV_TABLE_FLAGS(_shift, _width, _table, _flags) \
{ \
.shift = _shift, \
.width = _width, \
.flags = _flags, \
.table = _table, \
}
#define _SUNXI_CCU_DIV_FLAGS(_shift, _width, _flags) \
_SUNXI_CCU_DIV_TABLE_FLAGS(_shift, _width, NULL, _flags)
#define _SUNXI_CCU_DIV_TABLE(_shift, _width, _table) \
_SUNXI_CCU_DIV_TABLE_FLAGS(_shift, _width, _table, 0)
#define _SUNXI_CCU_DIV(_shift, _width) \
_SUNXI_CCU_DIV_TABLE_FLAGS(_shift, _width, NULL, 0)
struct
ccu_div
{
u32
enable
;
struct
_ccu_div
div
;
struct
ccu_mux_internal
mux
;
struct
ccu_common
common
;
};
#define SUNXI_CCU_DIV_TABLE_WITH_GATE(_struct, _name, _parent, _reg, \
_shift, _width, \
_table, _gate, _flags) \
struct ccu_div _struct = { \
.div = _SUNXI_CCU_DIV_TABLE(_shift, _width, \
_table), \
.enable = _gate, \
.common = { \
.reg = _reg, \
.hw.init = CLK_HW_INIT(_name, \
_parent, \
&ccu_div_ops, \
_flags), \
} \
}
#define SUNXI_CCU_DIV_TABLE(_struct, _name, _parent, _reg, \
_shift, _width, \
_table, _flags) \
SUNXI_CCU_DIV_TABLE_WITH_GATE(_struct, _name, _parent, _reg, \
_shift, _width, _table, 0, \
_flags)
#define SUNXI_CCU_M_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
_mshift, _mwidth, _muxshift, _muxwidth, \
_gate, _flags) \
struct ccu_div _struct = { \
.enable = _gate, \
.div = _SUNXI_CCU_DIV(_mshift, _mwidth), \
.mux = SUNXI_CLK_MUX(_muxshift, _muxwidth), \
.common = { \
.reg = _reg, \
.hw.init = CLK_HW_INIT_PARENTS(_name, \
_parents, \
&ccu_div_ops, \
_flags), \
}, \
}
#define SUNXI_CCU_M_WITH_MUX(_struct, _name, _parents, _reg, \
_mshift, _mwidth, _muxshift, _muxwidth, \
_flags) \
SUNXI_CCU_M_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
_mshift, _mwidth, _muxshift, _muxwidth, \
0, _flags)
#define SUNXI_CCU_M_WITH_GATE(_struct, _name, _parent, _reg, \
_mshift, _mwidth, _gate, \
_flags) \
struct ccu_div _struct = { \
.enable = _gate, \
.div = _SUNXI_CCU_DIV(_mshift, _mwidth), \
.common = { \
.reg = _reg, \
.hw.init = CLK_HW_INIT(_name, \
_parent, \
&ccu_div_ops, \
_flags), \
}, \
}
#define SUNXI_CCU_M(_struct, _name, _parent, _reg, _mshift, _mwidth, \
_flags) \
SUNXI_CCU_M_WITH_GATE(_struct, _name, _parent, _reg, \
_mshift, _mwidth, 0, _flags)
static
inline
struct
ccu_div
*
hw_to_ccu_div
(
struct
clk_hw
*
hw
)
{
struct
ccu_common
*
common
=
hw_to_ccu_common
(
hw
);
return
container_of
(
common
,
struct
ccu_div
,
common
);
}
extern
const
struct
clk_ops
ccu_div_ops
;
#endif
/* _CCU_DIV_H_ */
drivers/clk/sunxi-ng/ccu_frac.c
0 → 100644
View file @
7adb7695
/*
* Copyright (C) 2016 Maxime Ripard
* Maxime Ripard <maxime.ripard@free-electrons.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.
*/
#include <linux/clk-provider.h>
#include <linux/spinlock.h>
#include "ccu_frac.h"
bool
ccu_frac_helper_is_enabled
(
struct
ccu_common
*
common
,
struct
_ccu_frac
*
cf
)
{
if
(
!
(
common
->
features
&
CCU_FEATURE_FRACTIONAL
))
return
false
;
return
!
(
readl
(
common
->
base
+
common
->
reg
)
&
cf
->
enable
);
}
void
ccu_frac_helper_enable
(
struct
ccu_common
*
common
,
struct
_ccu_frac
*
cf
)
{
unsigned
long
flags
;
u32
reg
;
if
(
!
(
common
->
features
&
CCU_FEATURE_FRACTIONAL
))
return
;
spin_lock_irqsave
(
common
->
lock
,
flags
);
reg
=
readl
(
common
->
base
+
common
->
reg
);
writel
(
reg
&
~
cf
->
enable
,
common
->
base
+
common
->
reg
);
spin_unlock_irqrestore
(
common
->
lock
,
flags
);
}
void
ccu_frac_helper_disable
(
struct
ccu_common
*
common
,
struct
_ccu_frac
*
cf
)
{
unsigned
long
flags
;
u32
reg
;
if
(
!
(
common
->
features
&
CCU_FEATURE_FRACTIONAL
))
return
;
spin_lock_irqsave
(
common
->
lock
,
flags
);
reg
=
readl
(
common
->
base
+
common
->
reg
);
writel
(
reg
|
cf
->
enable
,
common
->
base
+
common
->
reg
);
spin_unlock_irqrestore
(
common
->
lock
,
flags
);
}
bool
ccu_frac_helper_has_rate
(
struct
ccu_common
*
common
,
struct
_ccu_frac
*
cf
,
unsigned
long
rate
)
{
if
(
!
(
common
->
features
&
CCU_FEATURE_FRACTIONAL
))
return
false
;
return
(
cf
->
rates
[
0
]
==
rate
)
||
(
cf
->
rates
[
1
]
==
rate
);
}
unsigned
long
ccu_frac_helper_read_rate
(
struct
ccu_common
*
common
,
struct
_ccu_frac
*
cf
)
{
u32
reg
;
printk
(
"%s: Read fractional
\n
"
,
clk_hw_get_name
(
&
common
->
hw
));
if
(
!
(
common
->
features
&
CCU_FEATURE_FRACTIONAL
))
return
0
;
printk
(
"%s: clock is fractional (rates %lu and %lu)
\n
"
,
clk_hw_get_name
(
&
common
->
hw
),
cf
->
rates
[
0
],
cf
->
rates
[
1
]);
reg
=
readl
(
common
->
base
+
common
->
reg
);
printk
(
"%s: clock reg is 0x%x (select is 0x%x)
\n
"
,
clk_hw_get_name
(
&
common
->
hw
),
reg
,
cf
->
select
);
return
(
reg
&
cf
->
select
)
?
cf
->
rates
[
1
]
:
cf
->
rates
[
0
];
}
int
ccu_frac_helper_set_rate
(
struct
ccu_common
*
common
,
struct
_ccu_frac
*
cf
,
unsigned
long
rate
)
{
unsigned
long
flags
;
u32
reg
,
sel
;
if
(
!
(
common
->
features
&
CCU_FEATURE_FRACTIONAL
))
return
-
EINVAL
;
if
(
cf
->
rates
[
0
]
==
rate
)
sel
=
0
;
else
if
(
cf
->
rates
[
1
]
==
rate
)
sel
=
cf
->
select
;
else
return
-
EINVAL
;
spin_lock_irqsave
(
common
->
lock
,
flags
);
reg
=
readl
(
common
->
base
+
common
->
reg
);
reg
&=
~
cf
->
select
;
writel
(
reg
|
sel
,
common
->
base
+
common
->
reg
);
spin_unlock_irqrestore
(
common
->
lock
,
flags
);
return
0
;
}
drivers/clk/sunxi-ng/ccu_frac.h
0 → 100644
View file @
7adb7695
/*
* Copyright (c) 2016 Maxime Ripard. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _CCU_FRAC_H_
#define _CCU_FRAC_H_
#include <linux/clk-provider.h>
#include "ccu_common.h"
struct
_ccu_frac
{
u32
enable
;
u32
select
;
unsigned
long
rates
[
2
];
};
#define _SUNXI_CCU_FRAC(_enable, _select, _rate1, _rate2) \
{ \
.enable = _enable, \
.select = _select, \
.rates = { _rate1, _rate2 }, \
}
bool
ccu_frac_helper_is_enabled
(
struct
ccu_common
*
common
,
struct
_ccu_frac
*
cf
);
void
ccu_frac_helper_enable
(
struct
ccu_common
*
common
,
struct
_ccu_frac
*
cf
);
void
ccu_frac_helper_disable
(
struct
ccu_common
*
common
,
struct
_ccu_frac
*
cf
);
bool
ccu_frac_helper_has_rate
(
struct
ccu_common
*
common
,
struct
_ccu_frac
*
cf
,
unsigned
long
rate
);
unsigned
long
ccu_frac_helper_read_rate
(
struct
ccu_common
*
common
,
struct
_ccu_frac
*
cf
);
int
ccu_frac_helper_set_rate
(
struct
ccu_common
*
common
,
struct
_ccu_frac
*
cf
,
unsigned
long
rate
);
#endif
/* _CCU_FRAC_H_ */
drivers/clk/sunxi-ng/ccu_gate.c
0 → 100644
View file @
7adb7695
/*
* Copyright (C) 2016 Maxime Ripard
* Maxime Ripard <maxime.ripard@free-electrons.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.
*/
#include <linux/clk-provider.h>
#include "ccu_gate.h"
void
ccu_gate_helper_disable
(
struct
ccu_common
*
common
,
u32
gate
)
{
unsigned
long
flags
;
u32
reg
;
if
(
!
gate
)
return
;
spin_lock_irqsave
(
common
->
lock
,
flags
);
reg
=
readl
(
common
->
base
+
common
->
reg
);
writel
(
reg
&
~
gate
,
common
->
base
+
common
->
reg
);
spin_unlock_irqrestore
(
common
->
lock
,
flags
);
}
static
void
ccu_gate_disable
(
struct
clk_hw
*
hw
)
{
struct
ccu_gate
*
cg
=
hw_to_ccu_gate
(
hw
);
return
ccu_gate_helper_disable
(
&
cg
->
common
,
cg
->
enable
);
}
int
ccu_gate_helper_enable
(
struct
ccu_common
*
common
,
u32
gate
)
{
unsigned
long
flags
;
u32
reg
;
if
(
!
gate
)
return
0
;
spin_lock_irqsave
(
common
->
lock
,
flags
);
reg
=
readl
(
common
->
base
+
common
->
reg
);
writel
(
reg
|
gate
,
common
->
base
+
common
->
reg
);
spin_unlock_irqrestore
(
common
->
lock
,
flags
);
return
0
;
}
static
int
ccu_gate_enable
(
struct
clk_hw
*
hw
)
{
struct
ccu_gate
*
cg
=
hw_to_ccu_gate
(
hw
);
return
ccu_gate_helper_enable
(
&
cg
->
common
,
cg
->
enable
);
}
int
ccu_gate_helper_is_enabled
(
struct
ccu_common
*
common
,
u32
gate
)
{
if
(
!
gate
)
return
1
;
return
readl
(
common
->
base
+
common
->
reg
)
&
gate
;
}
static
int
ccu_gate_is_enabled
(
struct
clk_hw
*
hw
)
{
struct
ccu_gate
*
cg
=
hw_to_ccu_gate
(
hw
);
return
ccu_gate_helper_is_enabled
(
&
cg
->
common
,
cg
->
enable
);
}
const
struct
clk_ops
ccu_gate_ops
=
{
.
disable
=
ccu_gate_disable
,
.
enable
=
ccu_gate_enable
,
.
is_enabled
=
ccu_gate_is_enabled
,
};
drivers/clk/sunxi-ng/ccu_gate.h
0 → 100644
View file @
7adb7695
/*
* Copyright (c) 2016 Maxime Ripard. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _CCU_GATE_H_
#define _CCU_GATE_H_
#include <linux/clk-provider.h>
#include "ccu_common.h"
struct
ccu_gate
{
u32
enable
;
struct
ccu_common
common
;
};
#define SUNXI_CCU_GATE(_struct, _name, _parent, _reg, _gate, _flags) \
struct ccu_gate _struct = { \
.enable = _gate, \
.common = { \
.reg = _reg, \
.hw.init = CLK_HW_INIT(_name, \
_parent, \
&ccu_gate_ops, \
_flags), \
} \
}
static
inline
struct
ccu_gate
*
hw_to_ccu_gate
(
struct
clk_hw
*
hw
)
{
struct
ccu_common
*
common
=
hw_to_ccu_common
(
hw
);
return
container_of
(
common
,
struct
ccu_gate
,
common
);
}
void
ccu_gate_helper_disable
(
struct
ccu_common
*
common
,
u32
gate
);
int
ccu_gate_helper_enable
(
struct
ccu_common
*
common
,
u32
gate
);
int
ccu_gate_helper_is_enabled
(
struct
ccu_common
*
common
,
u32
gate
);
extern
const
struct
clk_ops
ccu_gate_ops
;
#endif
/* _CCU_GATE_H_ */
drivers/clk/sunxi-ng/ccu_mp.c
0 → 100644
View file @
7adb7695
/*
* Copyright (C) 2016 Maxime Ripard
* Maxime Ripard <maxime.ripard@free-electrons.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.
*/
#include <linux/clk-provider.h>
#include "ccu_gate.h"
#include "ccu_mp.h"
static
void
ccu_mp_find_best
(
unsigned
long
parent
,
unsigned
long
rate
,
unsigned
int
max_m
,
unsigned
int
max_p
,
unsigned
int
*
m
,
unsigned
int
*
p
)
{
unsigned
long
best_rate
=
0
;
unsigned
int
best_m
=
0
,
best_p
=
0
;
unsigned
int
_m
,
_p
;
for
(
_p
=
0
;
_p
<=
max_p
;
_p
++
)
{
for
(
_m
=
1
;
_m
<=
max_m
;
_m
++
)
{
unsigned
long
tmp_rate
=
(
parent
>>
_p
)
/
_m
;
if
(
tmp_rate
>
rate
)
continue
;
if
((
rate
-
tmp_rate
)
<
(
rate
-
best_rate
))
{
best_rate
=
tmp_rate
;
best_m
=
_m
;
best_p
=
_p
;
}
}
}
*
m
=
best_m
;
*
p
=
best_p
;
}
static
unsigned
long
ccu_mp_round_rate
(
struct
ccu_mux_internal
*
mux
,
unsigned
long
parent_rate
,
unsigned
long
rate
,
void
*
data
)
{
struct
ccu_mp
*
cmp
=
data
;
unsigned
int
m
,
p
;
ccu_mp_find_best
(
parent_rate
,
rate
,
1
<<
cmp
->
m
.
width
,
(
1
<<
cmp
->
p
.
width
)
-
1
,
&
m
,
&
p
);
return
(
parent_rate
>>
p
)
/
m
;
}
static
void
ccu_mp_disable
(
struct
clk_hw
*
hw
)
{
struct
ccu_mp
*
cmp
=
hw_to_ccu_mp
(
hw
);
return
ccu_gate_helper_disable
(
&
cmp
->
common
,
cmp
->
enable
);
}
static
int
ccu_mp_enable
(
struct
clk_hw
*
hw
)
{
struct
ccu_mp
*
cmp
=
hw_to_ccu_mp
(
hw
);
return
ccu_gate_helper_enable
(
&
cmp
->
common
,
cmp
->
enable
);
}
static
int
ccu_mp_is_enabled
(
struct
clk_hw
*
hw
)
{
struct
ccu_mp
*
cmp
=
hw_to_ccu_mp
(
hw
);
return
ccu_gate_helper_is_enabled
(
&
cmp
->
common
,
cmp
->
enable
);
}
static
unsigned
long
ccu_mp_recalc_rate
(
struct
clk_hw
*
hw
,
unsigned
long
parent_rate
)
{
struct
ccu_mp
*
cmp
=
hw_to_ccu_mp
(
hw
);
unsigned
int
m
,
p
;
u32
reg
;
reg
=
readl
(
cmp
->
common
.
base
+
cmp
->
common
.
reg
);
m
=
reg
>>
cmp
->
m
.
shift
;
m
&=
(
1
<<
cmp
->
m
.
width
)
-
1
;
p
=
reg
>>
cmp
->
p
.
shift
;
p
&=
(
1
<<
cmp
->
p
.
width
)
-
1
;
return
(
parent_rate
>>
p
)
/
(
m
+
1
);
}
static
int
ccu_mp_determine_rate
(
struct
clk_hw
*
hw
,
struct
clk_rate_request
*
req
)
{
struct
ccu_mp
*
cmp
=
hw_to_ccu_mp
(
hw
);
return
ccu_mux_helper_determine_rate
(
&
cmp
->
common
,
&
cmp
->
mux
,
req
,
ccu_mp_round_rate
,
cmp
);
}
static
int
ccu_mp_set_rate
(
struct
clk_hw
*
hw
,
unsigned
long
rate
,
unsigned
long
parent_rate
)
{
struct
ccu_mp
*
cmp
=
hw_to_ccu_mp
(
hw
);
unsigned
long
flags
;
unsigned
int
m
,
p
;
u32
reg
;
ccu_mp_find_best
(
parent_rate
,
rate
,
1
<<
cmp
->
m
.
width
,
(
1
<<
cmp
->
p
.
width
)
-
1
,
&
m
,
&
p
);
spin_lock_irqsave
(
cmp
->
common
.
lock
,
flags
);
reg
=
readl
(
cmp
->
common
.
base
+
cmp
->
common
.
reg
);
reg
&=
~
GENMASK
(
cmp
->
m
.
width
+
cmp
->
m
.
shift
-
1
,
cmp
->
m
.
shift
);
reg
&=
~
GENMASK
(
cmp
->
p
.
width
+
cmp
->
p
.
shift
-
1
,
cmp
->
p
.
shift
);
writel
(
reg
|
(
p
<<
cmp
->
p
.
shift
)
|
((
m
-
1
)
<<
cmp
->
m
.
shift
),
cmp
->
common
.
base
+
cmp
->
common
.
reg
);
spin_unlock_irqrestore
(
cmp
->
common
.
lock
,
flags
);
return
0
;
}
static
u8
ccu_mp_get_parent
(
struct
clk_hw
*
hw
)
{
struct
ccu_mp
*
cmp
=
hw_to_ccu_mp
(
hw
);
return
ccu_mux_helper_get_parent
(
&
cmp
->
common
,
&
cmp
->
mux
);
}
static
int
ccu_mp_set_parent
(
struct
clk_hw
*
hw
,
u8
index
)
{
struct
ccu_mp
*
cmp
=
hw_to_ccu_mp
(
hw
);
return
ccu_mux_helper_set_parent
(
&
cmp
->
common
,
&
cmp
->
mux
,
index
);
}
const
struct
clk_ops
ccu_mp_ops
=
{
.
disable
=
ccu_mp_disable
,
.
enable
=
ccu_mp_enable
,
.
is_enabled
=
ccu_mp_is_enabled
,
.
get_parent
=
ccu_mp_get_parent
,
.
set_parent
=
ccu_mp_set_parent
,
.
determine_rate
=
ccu_mp_determine_rate
,
.
recalc_rate
=
ccu_mp_recalc_rate
,
.
set_rate
=
ccu_mp_set_rate
,
};
drivers/clk/sunxi-ng/ccu_mp.h
0 → 100644
View file @
7adb7695
/*
* Copyright (c) 2016 Maxime Ripard. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _CCU_MP_H_
#define _CCU_MP_H_
#include <linux/clk-provider.h>
#include "ccu_common.h"
#include "ccu_div.h"
#include "ccu_mult.h"
#include "ccu_mux.h"
/*
* struct ccu_mp - Definition of an M-P clock
*
* Clocks based on the formula parent >> P / M
*/
struct
ccu_mp
{
u32
enable
;
struct
_ccu_div
m
;
struct
_ccu_div
p
;
struct
ccu_mux_internal
mux
;
struct
ccu_common
common
;
};
#define SUNXI_CCU_MP_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
_mshift, _mwidth, \
_pshift, _pwidth, \
_muxshift, _muxwidth, \
_gate, _flags) \
struct ccu_mp _struct = { \
.enable = _gate, \
.m = _SUNXI_CCU_DIV(_mshift, _mwidth), \
.p = _SUNXI_CCU_DIV(_pshift, _pwidth), \
.mux = SUNXI_CLK_MUX(_muxshift, _muxwidth), \
.common = { \
.reg = _reg, \
.hw.init = CLK_HW_INIT_PARENTS(_name, \
_parents, \
&ccu_mp_ops, \
_flags), \
} \
}
#define SUNXI_CCU_MP_WITH_MUX(_struct, _name, _parents, _reg, \
_mshift, _mwidth, \
_pshift, _pwidth, \
_muxshift, _muxwidth, \
_flags) \
SUNXI_CCU_MP_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
_mshift, _mwidth, \
_pshift, _pwidth, \
_muxshift, _muxwidth, \
0, _flags)
static
inline
struct
ccu_mp
*
hw_to_ccu_mp
(
struct
clk_hw
*
hw
)
{
struct
ccu_common
*
common
=
hw_to_ccu_common
(
hw
);
return
container_of
(
common
,
struct
ccu_mp
,
common
);
}
extern
const
struct
clk_ops
ccu_mp_ops
;
#endif
/* _CCU_MP_H_ */
drivers/clk/sunxi-ng/ccu_mult.h
0 → 100644
View file @
7adb7695
#ifndef _CCU_MULT_H_
#define _CCU_MULT_H_
struct
_ccu_mult
{
u8
shift
;
u8
width
;
};
#define _SUNXI_CCU_MULT(_shift, _width) \
{ \
.shift = _shift, \
.width = _width, \
}
#endif
/* _CCU_MULT_H_ */
drivers/clk/sunxi-ng/ccu_mux.c
0 → 100644
View file @
7adb7695
/*
* Copyright (C) 2016 Maxime Ripard
* Maxime Ripard <maxime.ripard@free-electrons.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.
*/
#include <linux/clk-provider.h>
#include "ccu_gate.h"
#include "ccu_mux.h"
void
ccu_mux_helper_adjust_parent_for_prediv
(
struct
ccu_common
*
common
,
struct
ccu_mux_internal
*
cm
,
int
parent_index
,
unsigned
long
*
parent_rate
)
{
u8
prediv
=
1
;
u32
reg
;
if
(
!
((
common
->
features
&
CCU_FEATURE_FIXED_PREDIV
)
||
(
common
->
features
&
CCU_FEATURE_VARIABLE_PREDIV
)))
return
;
reg
=
readl
(
common
->
base
+
common
->
reg
);
if
(
parent_index
<
0
)
{
parent_index
=
reg
>>
cm
->
shift
;
parent_index
&=
(
1
<<
cm
->
width
)
-
1
;
}
if
(
common
->
features
&
CCU_FEATURE_FIXED_PREDIV
)
if
(
parent_index
==
cm
->
fixed_prediv
.
index
)
prediv
=
cm
->
fixed_prediv
.
div
;
if
(
common
->
features
&
CCU_FEATURE_VARIABLE_PREDIV
)
if
(
parent_index
==
cm
->
variable_prediv
.
index
)
{
u8
div
;
div
=
reg
>>
cm
->
variable_prediv
.
shift
;
div
&=
(
1
<<
cm
->
variable_prediv
.
width
)
-
1
;
prediv
=
div
+
1
;
}
*
parent_rate
=
*
parent_rate
/
prediv
;
}
int
ccu_mux_helper_determine_rate
(
struct
ccu_common
*
common
,
struct
ccu_mux_internal
*
cm
,
struct
clk_rate_request
*
req
,
unsigned
long
(
*
round
)(
struct
ccu_mux_internal
*
,
unsigned
long
,
unsigned
long
,
void
*
),
void
*
data
)
{
unsigned
long
best_parent_rate
=
0
,
best_rate
=
0
;
struct
clk_hw
*
best_parent
,
*
hw
=
&
common
->
hw
;
unsigned
int
i
;
for
(
i
=
0
;
i
<
clk_hw_get_num_parents
(
hw
);
i
++
)
{
unsigned
long
tmp_rate
,
parent_rate
;
struct
clk_hw
*
parent
;
parent
=
clk_hw_get_parent_by_index
(
hw
,
i
);
if
(
!
parent
)
continue
;
parent_rate
=
clk_hw_get_rate
(
parent
);
ccu_mux_helper_adjust_parent_for_prediv
(
common
,
cm
,
i
,
&
parent_rate
);
tmp_rate
=
round
(
cm
,
clk_hw_get_rate
(
parent
),
req
->
rate
,
data
);
if
(
tmp_rate
==
req
->
rate
)
{
best_parent
=
parent
;
best_parent_rate
=
parent_rate
;
best_rate
=
tmp_rate
;
goto
out
;
}
if
((
req
->
rate
-
tmp_rate
)
<
(
req
->
rate
-
best_rate
))
{
best_rate
=
tmp_rate
;
best_parent_rate
=
parent_rate
;
best_parent
=
parent
;
}
}
if
(
best_rate
==
0
)
return
-
EINVAL
;
out:
req
->
best_parent_hw
=
best_parent
;
req
->
best_parent_rate
=
best_parent_rate
;
req
->
rate
=
best_rate
;
return
0
;
}
u8
ccu_mux_helper_get_parent
(
struct
ccu_common
*
common
,
struct
ccu_mux_internal
*
cm
)
{
u32
reg
;
u8
parent
;
reg
=
readl
(
common
->
base
+
common
->
reg
);
parent
=
reg
>>
cm
->
shift
;
parent
&=
(
1
<<
cm
->
width
)
-
1
;
return
parent
;
}
int
ccu_mux_helper_set_parent
(
struct
ccu_common
*
common
,
struct
ccu_mux_internal
*
cm
,
u8
index
)
{
unsigned
long
flags
;
u32
reg
;
spin_lock_irqsave
(
common
->
lock
,
flags
);
reg
=
readl
(
common
->
base
+
common
->
reg
);
reg
&=
~
GENMASK
(
cm
->
width
+
cm
->
shift
-
1
,
cm
->
shift
);
writel
(
reg
|
(
index
<<
cm
->
shift
),
common
->
base
+
common
->
reg
);
spin_unlock_irqrestore
(
common
->
lock
,
flags
);
return
0
;
}
static
void
ccu_mux_disable
(
struct
clk_hw
*
hw
)
{
struct
ccu_mux
*
cm
=
hw_to_ccu_mux
(
hw
);
return
ccu_gate_helper_disable
(
&
cm
->
common
,
cm
->
enable
);
}
static
int
ccu_mux_enable
(
struct
clk_hw
*
hw
)
{
struct
ccu_mux
*
cm
=
hw_to_ccu_mux
(
hw
);
return
ccu_gate_helper_enable
(
&
cm
->
common
,
cm
->
enable
);
}
static
int
ccu_mux_is_enabled
(
struct
clk_hw
*
hw
)
{
struct
ccu_mux
*
cm
=
hw_to_ccu_mux
(
hw
);
return
ccu_gate_helper_is_enabled
(
&
cm
->
common
,
cm
->
enable
);
}
static
u8
ccu_mux_get_parent
(
struct
clk_hw
*
hw
)
{
struct
ccu_mux
*
cm
=
hw_to_ccu_mux
(
hw
);
return
ccu_mux_helper_get_parent
(
&
cm
->
common
,
&
cm
->
mux
);
}
static
int
ccu_mux_set_parent
(
struct
clk_hw
*
hw
,
u8
index
)
{
struct
ccu_mux
*
cm
=
hw_to_ccu_mux
(
hw
);
return
ccu_mux_helper_set_parent
(
&
cm
->
common
,
&
cm
->
mux
,
index
);
}
static
unsigned
long
ccu_mux_recalc_rate
(
struct
clk_hw
*
hw
,
unsigned
long
parent_rate
)
{
struct
ccu_mux
*
cm
=
hw_to_ccu_mux
(
hw
);
ccu_mux_helper_adjust_parent_for_prediv
(
&
cm
->
common
,
&
cm
->
mux
,
-
1
,
&
parent_rate
);
return
parent_rate
;
}
const
struct
clk_ops
ccu_mux_ops
=
{
.
disable
=
ccu_mux_disable
,
.
enable
=
ccu_mux_enable
,
.
is_enabled
=
ccu_mux_is_enabled
,
.
get_parent
=
ccu_mux_get_parent
,
.
set_parent
=
ccu_mux_set_parent
,
.
determine_rate
=
__clk_mux_determine_rate
,
.
recalc_rate
=
ccu_mux_recalc_rate
,
};
drivers/clk/sunxi-ng/ccu_mux.h
0 → 100644
View file @
7adb7695
#ifndef _CCU_MUX_H_
#define _CCU_MUX_H_
#include <linux/clk-provider.h>
#include "ccu_common.h"
struct
ccu_mux_internal
{
u8
shift
;
u8
width
;
struct
{
u8
index
;
u8
div
;
}
fixed_prediv
;
struct
{
u8
index
;
u8
shift
;
u8
width
;
}
variable_prediv
;
};
#define SUNXI_CLK_MUX(_shift, _width) \
{ \
.shift = _shift, \
.width = _width, \
}
struct
ccu_mux
{
u16
reg
;
u32
enable
;
struct
ccu_mux_internal
mux
;
struct
ccu_common
common
;
};
#define SUNXI_CCU_MUX(_struct, _name, _parents, _reg, _shift, _width, _flags) \
struct ccu_mux _struct = { \
.mux = SUNXI_CLK_MUX(_shift, _width), \
.common = { \
.reg = _reg, \
.hw.init = CLK_HW_INIT_PARENTS(_name, \
_parents, \
&ccu_mux_ops, \
_flags), \
} \
}
#define SUNXI_CCU_MUX_WITH_GATE(_struct, _name, _parents, _reg, \
_shift, _width, _gate, _flags) \
struct ccu_mux _struct = { \
.enable = _gate, \
.mux = SUNXI_CLK_MUX(_shift, _width), \
.common = { \
.reg = _reg, \
.hw.init = CLK_HW_INIT_PARENTS(_name, \
_parents, \
&ccu_mux_ops, \
_flags), \
} \
}
static
inline
struct
ccu_mux
*
hw_to_ccu_mux
(
struct
clk_hw
*
hw
)
{
struct
ccu_common
*
common
=
hw_to_ccu_common
(
hw
);
return
container_of
(
common
,
struct
ccu_mux
,
common
);
}
extern
const
struct
clk_ops
ccu_mux_ops
;
void
ccu_mux_helper_adjust_parent_for_prediv
(
struct
ccu_common
*
common
,
struct
ccu_mux_internal
*
cm
,
int
parent_index
,
unsigned
long
*
parent_rate
);
int
ccu_mux_helper_determine_rate
(
struct
ccu_common
*
common
,
struct
ccu_mux_internal
*
cm
,
struct
clk_rate_request
*
req
,
unsigned
long
(
*
round
)(
struct
ccu_mux_internal
*
,
unsigned
long
,
unsigned
long
,
void
*
),
void
*
data
);
u8
ccu_mux_helper_get_parent
(
struct
ccu_common
*
common
,
struct
ccu_mux_internal
*
cm
);
int
ccu_mux_helper_set_parent
(
struct
ccu_common
*
common
,
struct
ccu_mux_internal
*
cm
,
u8
index
);
#endif
/* _CCU_MUX_H_ */
drivers/clk/sunxi-ng/ccu_nk.c
0 → 100644
View file @
7adb7695
/*
* Copyright (C) 2016 Maxime Ripard
* Maxime Ripard <maxime.ripard@free-electrons.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.
*/
#include <linux/clk-provider.h>
#include <linux/rational.h>
#include "ccu_gate.h"
#include "ccu_nk.h"
void
ccu_nk_find_best
(
unsigned
long
parent
,
unsigned
long
rate
,
unsigned
int
max_n
,
unsigned
int
max_k
,
unsigned
int
*
n
,
unsigned
int
*
k
)
{
unsigned
long
best_rate
=
0
;
unsigned
int
best_k
=
0
,
best_n
=
0
;
unsigned
int
_k
,
_n
;
for
(
_k
=
1
;
_k
<=
max_k
;
_k
++
)
{
for
(
_n
=
1
;
_n
<=
max_n
;
_n
++
)
{
unsigned
long
tmp_rate
=
parent
*
_n
*
_k
;
if
(
tmp_rate
>
rate
)
continue
;
if
((
rate
-
tmp_rate
)
<
(
rate
-
best_rate
))
{
best_rate
=
tmp_rate
;
best_k
=
_k
;
best_n
=
_n
;
}
}
}
*
k
=
best_k
;
*
n
=
best_n
;
}
static
void
ccu_nk_disable
(
struct
clk_hw
*
hw
)
{
struct
ccu_nk
*
nk
=
hw_to_ccu_nk
(
hw
);
return
ccu_gate_helper_disable
(
&
nk
->
common
,
nk
->
enable
);
}
static
int
ccu_nk_enable
(
struct
clk_hw
*
hw
)
{
struct
ccu_nk
*
nk
=
hw_to_ccu_nk
(
hw
);
return
ccu_gate_helper_enable
(
&
nk
->
common
,
nk
->
enable
);
}
static
int
ccu_nk_is_enabled
(
struct
clk_hw
*
hw
)
{
struct
ccu_nk
*
nk
=
hw_to_ccu_nk
(
hw
);
return
ccu_gate_helper_is_enabled
(
&
nk
->
common
,
nk
->
enable
);
}
static
unsigned
long
ccu_nk_recalc_rate
(
struct
clk_hw
*
hw
,
unsigned
long
parent_rate
)
{
struct
ccu_nk
*
nk
=
hw_to_ccu_nk
(
hw
);
unsigned
long
rate
,
n
,
k
;
u32
reg
;
reg
=
readl
(
nk
->
common
.
base
+
nk
->
common
.
reg
);
n
=
reg
>>
nk
->
n
.
shift
;
n
&=
(
1
<<
nk
->
n
.
width
)
-
1
;
k
=
reg
>>
nk
->
k
.
shift
;
k
&=
(
1
<<
nk
->
k
.
width
)
-
1
;
rate
=
parent_rate
*
(
n
+
1
)
*
(
k
+
1
);
if
(
nk
->
common
.
features
&
CCU_FEATURE_FIXED_POSTDIV
)
rate
/=
nk
->
fixed_post_div
;
return
rate
;
}
static
long
ccu_nk_round_rate
(
struct
clk_hw
*
hw
,
unsigned
long
rate
,
unsigned
long
*
parent_rate
)
{
struct
ccu_nk
*
nk
=
hw_to_ccu_nk
(
hw
);
unsigned
int
n
,
k
;
if
(
nk
->
common
.
features
&
CCU_FEATURE_FIXED_POSTDIV
)
rate
*=
nk
->
fixed_post_div
;
ccu_nk_find_best
(
*
parent_rate
,
rate
,
1
<<
nk
->
n
.
width
,
1
<<
nk
->
k
.
width
,
&
n
,
&
k
);
rate
=
*
parent_rate
*
n
*
k
;
if
(
nk
->
common
.
features
&
CCU_FEATURE_FIXED_POSTDIV
)
rate
=
rate
/
nk
->
fixed_post_div
;
return
rate
;
}
static
int
ccu_nk_set_rate
(
struct
clk_hw
*
hw
,
unsigned
long
rate
,
unsigned
long
parent_rate
)
{
struct
ccu_nk
*
nk
=
hw_to_ccu_nk
(
hw
);
unsigned
long
flags
;
unsigned
int
n
,
k
;
u32
reg
;
if
(
nk
->
common
.
features
&
CCU_FEATURE_FIXED_POSTDIV
)
rate
=
rate
*
nk
->
fixed_post_div
;
ccu_nk_find_best
(
parent_rate
,
rate
,
1
<<
nk
->
n
.
width
,
1
<<
nk
->
k
.
width
,
&
n
,
&
k
);
spin_lock_irqsave
(
nk
->
common
.
lock
,
flags
);
reg
=
readl
(
nk
->
common
.
base
+
nk
->
common
.
reg
);
reg
&=
~
GENMASK
(
nk
->
n
.
width
+
nk
->
n
.
shift
-
1
,
nk
->
n
.
shift
);
reg
&=
~
GENMASK
(
nk
->
k
.
width
+
nk
->
k
.
shift
-
1
,
nk
->
k
.
shift
);
writel
(
reg
|
((
k
-
1
)
<<
nk
->
k
.
shift
)
|
((
n
-
1
)
<<
nk
->
n
.
shift
),
nk
->
common
.
base
+
nk
->
common
.
reg
);
spin_unlock_irqrestore
(
nk
->
common
.
lock
,
flags
);
ccu_helper_wait_for_lock
(
&
nk
->
common
,
nk
->
lock
);
return
0
;
}
const
struct
clk_ops
ccu_nk_ops
=
{
.
disable
=
ccu_nk_disable
,
.
enable
=
ccu_nk_enable
,
.
is_enabled
=
ccu_nk_is_enabled
,
.
recalc_rate
=
ccu_nk_recalc_rate
,
.
round_rate
=
ccu_nk_round_rate
,
.
set_rate
=
ccu_nk_set_rate
,
};
drivers/clk/sunxi-ng/ccu_nk.h
0 → 100644
View file @
7adb7695
/*
* Copyright (c) 2016 Maxime Ripard. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _CCU_NK_H_
#define _CCU_NK_H_
#include <linux/clk-provider.h>
#include "ccu_common.h"
#include "ccu_div.h"
#include "ccu_mult.h"
/*
* struct ccu_nk - Definition of an N-K clock
*
* Clocks based on the formula parent * N * K
*/
struct
ccu_nk
{
u16
reg
;
u32
enable
;
u32
lock
;
struct
_ccu_mult
n
;
struct
_ccu_mult
k
;
unsigned
int
fixed_post_div
;
struct
ccu_common
common
;
};
#define SUNXI_CCU_NK_WITH_GATE_LOCK_POSTDIV(_struct, _name, _parent, _reg, \
_nshift, _nwidth, \
_kshift, _kwidth, \
_gate, _lock, _postdiv, \
_flags) \
struct ccu_nk _struct = { \
.enable = _gate, \
.lock = _lock, \
.k = _SUNXI_CCU_MULT(_kshift, _kwidth), \
.n = _SUNXI_CCU_MULT(_nshift, _nwidth), \
.fixed_post_div = _postdiv, \
.common = { \
.reg = _reg, \
.features = CCU_FEATURE_FIXED_POSTDIV, \
.hw.init = CLK_HW_INIT(_name, \
_parent, \
&ccu_nk_ops, \
_flags), \
}, \
}
static
inline
struct
ccu_nk
*
hw_to_ccu_nk
(
struct
clk_hw
*
hw
)
{
struct
ccu_common
*
common
=
hw_to_ccu_common
(
hw
);
return
container_of
(
common
,
struct
ccu_nk
,
common
);
}
extern
const
struct
clk_ops
ccu_nk_ops
;
#endif
/* _CCU_NK_H_ */
drivers/clk/sunxi-ng/ccu_nkm.c
0 → 100644
View file @
7adb7695
/*
* Copyright (C) 2016 Maxime Ripard
* Maxime Ripard <maxime.ripard@free-electrons.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.
*/
#include <linux/clk-provider.h>
#include <linux/rational.h>
#include "ccu_gate.h"
#include "ccu_nkm.h"
struct
_ccu_nkm
{
unsigned
long
n
,
max_n
;
unsigned
long
k
,
max_k
;
unsigned
long
m
,
max_m
;
};
static
void
ccu_nkm_find_best
(
unsigned
long
parent
,
unsigned
long
rate
,
struct
_ccu_nkm
*
nkm
)
{
unsigned
long
best_rate
=
0
;
unsigned
long
best_n
=
0
,
best_k
=
0
,
best_m
=
0
;
unsigned
long
_n
,
_k
,
_m
;
for
(
_k
=
1
;
_k
<=
nkm
->
max_k
;
_k
++
)
{
unsigned
long
tmp_rate
;
rational_best_approximation
(
rate
/
_k
,
parent
,
nkm
->
max_n
,
nkm
->
max_m
,
&
_n
,
&
_m
);
tmp_rate
=
parent
*
_n
*
_k
/
_m
;
if
(
tmp_rate
>
rate
)
continue
;
if
((
rate
-
tmp_rate
)
<
(
rate
-
best_rate
))
{
best_rate
=
tmp_rate
;
best_n
=
_n
;
best_k
=
_k
;
best_m
=
_m
;
}
}
nkm
->
n
=
best_n
;
nkm
->
k
=
best_k
;
nkm
->
m
=
best_m
;
}
static
void
ccu_nkm_disable
(
struct
clk_hw
*
hw
)
{
struct
ccu_nkm
*
nkm
=
hw_to_ccu_nkm
(
hw
);
return
ccu_gate_helper_disable
(
&
nkm
->
common
,
nkm
->
enable
);
}
static
int
ccu_nkm_enable
(
struct
clk_hw
*
hw
)
{
struct
ccu_nkm
*
nkm
=
hw_to_ccu_nkm
(
hw
);
return
ccu_gate_helper_enable
(
&
nkm
->
common
,
nkm
->
enable
);
}
static
int
ccu_nkm_is_enabled
(
struct
clk_hw
*
hw
)
{
struct
ccu_nkm
*
nkm
=
hw_to_ccu_nkm
(
hw
);
return
ccu_gate_helper_is_enabled
(
&
nkm
->
common
,
nkm
->
enable
);
}
static
unsigned
long
ccu_nkm_recalc_rate
(
struct
clk_hw
*
hw
,
unsigned
long
parent_rate
)
{
struct
ccu_nkm
*
nkm
=
hw_to_ccu_nkm
(
hw
);
unsigned
long
n
,
m
,
k
;
u32
reg
;
reg
=
readl
(
nkm
->
common
.
base
+
nkm
->
common
.
reg
);
n
=
reg
>>
nkm
->
n
.
shift
;
n
&=
(
1
<<
nkm
->
n
.
width
)
-
1
;
k
=
reg
>>
nkm
->
k
.
shift
;
k
&=
(
1
<<
nkm
->
k
.
width
)
-
1
;
m
=
reg
>>
nkm
->
m
.
shift
;
m
&=
(
1
<<
nkm
->
m
.
width
)
-
1
;
return
parent_rate
*
(
n
+
1
)
*
(
k
+
1
)
/
(
m
+
1
);
}
static
long
ccu_nkm_round_rate
(
struct
clk_hw
*
hw
,
unsigned
long
rate
,
unsigned
long
*
parent_rate
)
{
struct
ccu_nkm
*
nkm
=
hw_to_ccu_nkm
(
hw
);
struct
_ccu_nkm
_nkm
;
_nkm
.
max_n
=
1
<<
nkm
->
n
.
width
;
_nkm
.
max_k
=
1
<<
nkm
->
k
.
width
;
_nkm
.
max_m
=
1
<<
nkm
->
m
.
width
;
ccu_nkm_find_best
(
*
parent_rate
,
rate
,
&
_nkm
);
return
*
parent_rate
*
_nkm
.
n
*
_nkm
.
k
/
_nkm
.
m
;
}
static
int
ccu_nkm_set_rate
(
struct
clk_hw
*
hw
,
unsigned
long
rate
,
unsigned
long
parent_rate
)
{
struct
ccu_nkm
*
nkm
=
hw_to_ccu_nkm
(
hw
);
struct
_ccu_nkm
_nkm
;
unsigned
long
flags
;
u32
reg
;
_nkm
.
max_n
=
1
<<
nkm
->
n
.
width
;
_nkm
.
max_k
=
1
<<
nkm
->
k
.
width
;
_nkm
.
max_m
=
1
<<
nkm
->
m
.
width
;
ccu_nkm_find_best
(
parent_rate
,
rate
,
&
_nkm
);
spin_lock_irqsave
(
nkm
->
common
.
lock
,
flags
);
reg
=
readl
(
nkm
->
common
.
base
+
nkm
->
common
.
reg
);
reg
&=
~
GENMASK
(
nkm
->
n
.
width
+
nkm
->
n
.
shift
-
1
,
nkm
->
n
.
shift
);
reg
&=
~
GENMASK
(
nkm
->
k
.
width
+
nkm
->
k
.
shift
-
1
,
nkm
->
k
.
shift
);
reg
&=
~
GENMASK
(
nkm
->
m
.
width
+
nkm
->
m
.
shift
-
1
,
nkm
->
m
.
shift
);
reg
|=
(
_nkm
.
n
-
1
)
<<
nkm
->
n
.
shift
;
reg
|=
(
_nkm
.
k
-
1
)
<<
nkm
->
k
.
shift
;
reg
|=
(
_nkm
.
m
-
1
)
<<
nkm
->
m
.
shift
;
writel
(
reg
,
nkm
->
common
.
base
+
nkm
->
common
.
reg
);
spin_unlock_irqrestore
(
nkm
->
common
.
lock
,
flags
);
ccu_helper_wait_for_lock
(
&
nkm
->
common
,
nkm
->
lock
);
return
0
;
}
const
struct
clk_ops
ccu_nkm_ops
=
{
.
disable
=
ccu_nkm_disable
,
.
enable
=
ccu_nkm_enable
,
.
is_enabled
=
ccu_nkm_is_enabled
,
.
recalc_rate
=
ccu_nkm_recalc_rate
,
.
round_rate
=
ccu_nkm_round_rate
,
.
set_rate
=
ccu_nkm_set_rate
,
};
drivers/clk/sunxi-ng/ccu_nkm.h
0 → 100644
View file @
7adb7695
/*
* Copyright (c) 2016 Maxime Ripard. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _CCU_NKM_H_
#define _CCU_NKM_H_
#include <linux/clk-provider.h>
#include "ccu_common.h"
#include "ccu_div.h"
#include "ccu_mult.h"
/*
* struct ccu_nkm - Definition of an N-K-M clock
*
* Clocks based on the formula parent * N * K / M
*/
struct
ccu_nkm
{
u32
enable
;
u32
lock
;
struct
_ccu_mult
n
;
struct
_ccu_mult
k
;
struct
_ccu_div
m
;
struct
ccu_common
common
;
};
#define SUNXI_CCU_NKM_WITH_GATE_LOCK(_struct, _name, _parent, _reg, \
_nshift, _nwidth, \
_kshift, _kwidth, \
_mshift, _mwidth, \
_gate, _lock, _flags) \
struct ccu_nkm _struct = { \
.enable = _gate, \
.lock = _lock, \
.k = _SUNXI_CCU_MULT(_kshift, _kwidth), \
.n = _SUNXI_CCU_MULT(_nshift, _nwidth), \
.m = _SUNXI_CCU_DIV(_mshift, _mwidth), \
.common = { \
.reg = _reg, \
.hw.init = CLK_HW_INIT(_name, \
_parent, \
&ccu_nkm_ops, \
_flags), \
}, \
}
static
inline
struct
ccu_nkm
*
hw_to_ccu_nkm
(
struct
clk_hw
*
hw
)
{
struct
ccu_common
*
common
=
hw_to_ccu_common
(
hw
);
return
container_of
(
common
,
struct
ccu_nkm
,
common
);
}
extern
const
struct
clk_ops
ccu_nkm_ops
;
#endif
/* _CCU_NKM_H_ */
drivers/clk/sunxi-ng/ccu_nkmp.c
0 → 100644
View file @
7adb7695
/*
* Copyright (C) 2016 Maxime Ripard
* Maxime Ripard <maxime.ripard@free-electrons.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.
*/
#include <linux/clk-provider.h>
#include <linux/rational.h>
#include "ccu_gate.h"
#include "ccu_nkmp.h"
struct
_ccu_nkmp
{
unsigned
long
n
,
max_n
;
unsigned
long
k
,
max_k
;
unsigned
long
m
,
max_m
;
unsigned
long
p
,
max_p
;
};
static
void
ccu_nkmp_find_best
(
unsigned
long
parent
,
unsigned
long
rate
,
struct
_ccu_nkmp
*
nkmp
)
{
unsigned
long
best_rate
=
0
;
unsigned
long
best_n
=
0
,
best_k
=
0
,
best_m
=
0
,
best_p
=
0
;
unsigned
long
_n
,
_k
,
_m
,
_p
;
for
(
_k
=
1
;
_k
<=
nkmp
->
max_k
;
_k
++
)
{
for
(
_p
=
0
;
_p
<=
nkmp
->
max_p
;
_p
++
)
{
unsigned
long
tmp_rate
;
rational_best_approximation
(
rate
/
_k
,
parent
>>
_p
,
nkmp
->
max_n
,
nkmp
->
max_m
,
&
_n
,
&
_m
);
tmp_rate
=
(
parent
*
_n
*
_k
>>
_p
)
/
_m
;
if
(
tmp_rate
>
rate
)
continue
;
if
((
rate
-
tmp_rate
)
<
(
rate
-
best_rate
))
{
best_rate
=
tmp_rate
;
best_n
=
_n
;
best_k
=
_k
;
best_m
=
_m
;
best_p
=
_p
;
}
}
}
nkmp
->
n
=
best_n
;
nkmp
->
k
=
best_k
;
nkmp
->
m
=
best_m
;
nkmp
->
p
=
best_p
;
}
static
void
ccu_nkmp_disable
(
struct
clk_hw
*
hw
)
{
struct
ccu_nkmp
*
nkmp
=
hw_to_ccu_nkmp
(
hw
);
return
ccu_gate_helper_disable
(
&
nkmp
->
common
,
nkmp
->
enable
);
}
static
int
ccu_nkmp_enable
(
struct
clk_hw
*
hw
)
{
struct
ccu_nkmp
*
nkmp
=
hw_to_ccu_nkmp
(
hw
);
return
ccu_gate_helper_enable
(
&
nkmp
->
common
,
nkmp
->
enable
);
}
static
int
ccu_nkmp_is_enabled
(
struct
clk_hw
*
hw
)
{
struct
ccu_nkmp
*
nkmp
=
hw_to_ccu_nkmp
(
hw
);
return
ccu_gate_helper_is_enabled
(
&
nkmp
->
common
,
nkmp
->
enable
);
}
static
unsigned
long
ccu_nkmp_recalc_rate
(
struct
clk_hw
*
hw
,
unsigned
long
parent_rate
)
{
struct
ccu_nkmp
*
nkmp
=
hw_to_ccu_nkmp
(
hw
);
unsigned
long
n
,
m
,
k
,
p
;
u32
reg
;
reg
=
readl
(
nkmp
->
common
.
base
+
nkmp
->
common
.
reg
);
n
=
reg
>>
nkmp
->
n
.
shift
;
n
&=
(
1
<<
nkmp
->
n
.
width
)
-
1
;
k
=
reg
>>
nkmp
->
k
.
shift
;
k
&=
(
1
<<
nkmp
->
k
.
width
)
-
1
;
m
=
reg
>>
nkmp
->
m
.
shift
;
m
&=
(
1
<<
nkmp
->
m
.
width
)
-
1
;
p
=
reg
>>
nkmp
->
p
.
shift
;
p
&=
(
1
<<
nkmp
->
p
.
width
)
-
1
;
return
(
parent_rate
*
(
n
+
1
)
*
(
k
+
1
)
>>
p
)
/
(
m
+
1
);
}
static
long
ccu_nkmp_round_rate
(
struct
clk_hw
*
hw
,
unsigned
long
rate
,
unsigned
long
*
parent_rate
)
{
struct
ccu_nkmp
*
nkmp
=
hw_to_ccu_nkmp
(
hw
);
struct
_ccu_nkmp
_nkmp
;
_nkmp
.
max_n
=
1
<<
nkmp
->
n
.
width
;
_nkmp
.
max_k
=
1
<<
nkmp
->
k
.
width
;
_nkmp
.
max_m
=
1
<<
nkmp
->
m
.
width
;
_nkmp
.
max_p
=
(
1
<<
nkmp
->
p
.
width
)
-
1
;
ccu_nkmp_find_best
(
*
parent_rate
,
rate
,
&
_nkmp
);
return
(
*
parent_rate
*
_nkmp
.
n
*
_nkmp
.
k
>>
_nkmp
.
p
)
/
_nkmp
.
m
;
}
static
int
ccu_nkmp_set_rate
(
struct
clk_hw
*
hw
,
unsigned
long
rate
,
unsigned
long
parent_rate
)
{
struct
ccu_nkmp
*
nkmp
=
hw_to_ccu_nkmp
(
hw
);
struct
_ccu_nkmp
_nkmp
;
unsigned
long
flags
;
u32
reg
;
_nkmp
.
max_n
=
1
<<
nkmp
->
n
.
width
;
_nkmp
.
max_k
=
1
<<
nkmp
->
k
.
width
;
_nkmp
.
max_m
=
1
<<
nkmp
->
m
.
width
;
_nkmp
.
max_p
=
(
1
<<
nkmp
->
p
.
width
)
-
1
;
ccu_nkmp_find_best
(
parent_rate
,
rate
,
&
_nkmp
);
spin_lock_irqsave
(
nkmp
->
common
.
lock
,
flags
);
reg
=
readl
(
nkmp
->
common
.
base
+
nkmp
->
common
.
reg
);
reg
&=
~
GENMASK
(
nkmp
->
n
.
width
+
nkmp
->
n
.
shift
-
1
,
nkmp
->
n
.
shift
);
reg
&=
~
GENMASK
(
nkmp
->
k
.
width
+
nkmp
->
k
.
shift
-
1
,
nkmp
->
k
.
shift
);
reg
&=
~
GENMASK
(
nkmp
->
m
.
width
+
nkmp
->
m
.
shift
-
1
,
nkmp
->
m
.
shift
);
reg
&=
~
GENMASK
(
nkmp
->
p
.
width
+
nkmp
->
p
.
shift
-
1
,
nkmp
->
p
.
shift
);
reg
|=
(
_nkmp
.
n
-
1
)
<<
nkmp
->
n
.
shift
;
reg
|=
(
_nkmp
.
k
-
1
)
<<
nkmp
->
k
.
shift
;
reg
|=
(
_nkmp
.
m
-
1
)
<<
nkmp
->
m
.
shift
;
reg
|=
_nkmp
.
p
<<
nkmp
->
p
.
shift
;
writel
(
reg
,
nkmp
->
common
.
base
+
nkmp
->
common
.
reg
);
spin_unlock_irqrestore
(
nkmp
->
common
.
lock
,
flags
);
ccu_helper_wait_for_lock
(
&
nkmp
->
common
,
nkmp
->
lock
);
return
0
;
}
const
struct
clk_ops
ccu_nkmp_ops
=
{
.
disable
=
ccu_nkmp_disable
,
.
enable
=
ccu_nkmp_enable
,
.
is_enabled
=
ccu_nkmp_is_enabled
,
.
recalc_rate
=
ccu_nkmp_recalc_rate
,
.
round_rate
=
ccu_nkmp_round_rate
,
.
set_rate
=
ccu_nkmp_set_rate
,
};
drivers/clk/sunxi-ng/ccu_nkmp.h
0 → 100644
View file @
7adb7695
/*
* Copyright (c) 2016 Maxime Ripard. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _CCU_NKMP_H_
#define _CCU_NKMP_H_
#include <linux/clk-provider.h>
#include "ccu_common.h"
#include "ccu_div.h"
#include "ccu_mult.h"
/*
* struct ccu_nkmp - Definition of an N-K-M-P clock
*
* Clocks based on the formula parent * N * K >> P / M
*/
struct
ccu_nkmp
{
u32
enable
;
u32
lock
;
struct
_ccu_mult
n
;
struct
_ccu_mult
k
;
struct
_ccu_div
m
;
struct
_ccu_div
p
;
struct
ccu_common
common
;
};
#define SUNXI_CCU_NKMP_WITH_GATE_LOCK(_struct, _name, _parent, _reg, \
_nshift, _nwidth, \
_kshift, _kwidth, \
_mshift, _mwidth, \
_pshift, _pwidth, \
_gate, _lock, _flags) \
struct ccu_nkmp _struct = { \
.enable = _gate, \
.lock = _lock, \
.n = _SUNXI_CCU_MULT(_nshift, _nwidth), \
.k = _SUNXI_CCU_MULT(_kshift, _kwidth), \
.m = _SUNXI_CCU_DIV(_mshift, _mwidth), \
.p = _SUNXI_CCU_DIV(_pshift, _pwidth), \
.common = { \
.reg = _reg, \
.hw.init = CLK_HW_INIT(_name, \
_parent, \
&ccu_nkmp_ops, \
_flags), \
}, \
}
static
inline
struct
ccu_nkmp
*
hw_to_ccu_nkmp
(
struct
clk_hw
*
hw
)
{
struct
ccu_common
*
common
=
hw_to_ccu_common
(
hw
);
return
container_of
(
common
,
struct
ccu_nkmp
,
common
);
}
extern
const
struct
clk_ops
ccu_nkmp_ops
;
#endif
/* _CCU_NKMP_H_ */
drivers/clk/sunxi-ng/ccu_nm.c
0 → 100644
View file @
7adb7695
/*
* Copyright (C) 2016 Maxime Ripard
* Maxime Ripard <maxime.ripard@free-electrons.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.
*/
#include <linux/clk-provider.h>
#include <linux/rational.h>
#include "ccu_frac.h"
#include "ccu_gate.h"
#include "ccu_nm.h"
static
void
ccu_nm_disable
(
struct
clk_hw
*
hw
)
{
struct
ccu_nm
*
nm
=
hw_to_ccu_nm
(
hw
);
return
ccu_gate_helper_disable
(
&
nm
->
common
,
nm
->
enable
);
}
static
int
ccu_nm_enable
(
struct
clk_hw
*
hw
)
{
struct
ccu_nm
*
nm
=
hw_to_ccu_nm
(
hw
);
return
ccu_gate_helper_enable
(
&
nm
->
common
,
nm
->
enable
);
}
static
int
ccu_nm_is_enabled
(
struct
clk_hw
*
hw
)
{
struct
ccu_nm
*
nm
=
hw_to_ccu_nm
(
hw
);
return
ccu_gate_helper_is_enabled
(
&
nm
->
common
,
nm
->
enable
);
}
static
unsigned
long
ccu_nm_recalc_rate
(
struct
clk_hw
*
hw
,
unsigned
long
parent_rate
)
{
struct
ccu_nm
*
nm
=
hw_to_ccu_nm
(
hw
);
unsigned
long
n
,
m
;
u32
reg
;
if
(
ccu_frac_helper_is_enabled
(
&
nm
->
common
,
&
nm
->
frac
))
return
ccu_frac_helper_read_rate
(
&
nm
->
common
,
&
nm
->
frac
);
reg
=
readl
(
nm
->
common
.
base
+
nm
->
common
.
reg
);
n
=
reg
>>
nm
->
n
.
shift
;
n
&=
(
1
<<
nm
->
n
.
width
)
-
1
;
m
=
reg
>>
nm
->
m
.
shift
;
m
&=
(
1
<<
nm
->
m
.
width
)
-
1
;
return
parent_rate
*
(
n
+
1
)
/
(
m
+
1
);
}
static
long
ccu_nm_round_rate
(
struct
clk_hw
*
hw
,
unsigned
long
rate
,
unsigned
long
*
parent_rate
)
{
struct
ccu_nm
*
nm
=
hw_to_ccu_nm
(
hw
);
unsigned
long
n
,
m
;
rational_best_approximation
(
rate
,
*
parent_rate
,
1
<<
nm
->
n
.
width
,
1
<<
nm
->
m
.
width
,
&
n
,
&
m
);
return
*
parent_rate
*
n
/
m
;
}
static
int
ccu_nm_set_rate
(
struct
clk_hw
*
hw
,
unsigned
long
rate
,
unsigned
long
parent_rate
)
{
struct
ccu_nm
*
nm
=
hw_to_ccu_nm
(
hw
);
unsigned
long
flags
;
unsigned
long
n
,
m
;
u32
reg
;
if
(
ccu_frac_helper_has_rate
(
&
nm
->
common
,
&
nm
->
frac
,
rate
))
return
ccu_frac_helper_set_rate
(
&
nm
->
common
,
&
nm
->
frac
,
rate
);
else
ccu_frac_helper_disable
(
&
nm
->
common
,
&
nm
->
frac
);
rational_best_approximation
(
rate
,
parent_rate
,
1
<<
nm
->
n
.
width
,
1
<<
nm
->
m
.
width
,
&
n
,
&
m
);
spin_lock_irqsave
(
nm
->
common
.
lock
,
flags
);
reg
=
readl
(
nm
->
common
.
base
+
nm
->
common
.
reg
);
reg
&=
~
GENMASK
(
nm
->
n
.
width
+
nm
->
n
.
shift
-
1
,
nm
->
n
.
shift
);
reg
&=
~
GENMASK
(
nm
->
m
.
width
+
nm
->
m
.
shift
-
1
,
nm
->
m
.
shift
);
writel
(
reg
|
((
m
-
1
)
<<
nm
->
m
.
shift
)
|
((
n
-
1
)
<<
nm
->
n
.
shift
),
nm
->
common
.
base
+
nm
->
common
.
reg
);
spin_unlock_irqrestore
(
nm
->
common
.
lock
,
flags
);
ccu_helper_wait_for_lock
(
&
nm
->
common
,
nm
->
lock
);
return
0
;
}
const
struct
clk_ops
ccu_nm_ops
=
{
.
disable
=
ccu_nm_disable
,
.
enable
=
ccu_nm_enable
,
.
is_enabled
=
ccu_nm_is_enabled
,
.
recalc_rate
=
ccu_nm_recalc_rate
,
.
round_rate
=
ccu_nm_round_rate
,
.
set_rate
=
ccu_nm_set_rate
,
};
drivers/clk/sunxi-ng/ccu_nm.h
0 → 100644
View file @
7adb7695
/*
* Copyright (c) 2016 Maxime Ripard. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _CCU_NM_H_
#define _CCU_NM_H_
#include <linux/clk-provider.h>
#include "ccu_common.h"
#include "ccu_div.h"
#include "ccu_frac.h"
#include "ccu_mult.h"
/*
* struct ccu_nm - Definition of an N-M clock
*
* Clocks based on the formula parent * N / M
*/
struct
ccu_nm
{
u32
enable
;
u32
lock
;
struct
_ccu_mult
n
;
struct
_ccu_div
m
;
struct
_ccu_frac
frac
;
struct
ccu_common
common
;
};
#define SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(_struct, _name, _parent, _reg, \
_nshift, _nwidth, \
_mshift, _mwidth, \
_frac_en, _frac_sel, \
_frac_rate_0, _frac_rate_1, \
_gate, _lock, _flags) \
struct ccu_nm _struct = { \
.enable = _gate, \
.lock = _lock, \
.n = _SUNXI_CCU_MULT(_nshift, _nwidth), \
.m = _SUNXI_CCU_DIV(_mshift, _mwidth), \
.frac = _SUNXI_CCU_FRAC(_frac_en, _frac_sel, \
_frac_rate_0, \
_frac_rate_1), \
.common = { \
.reg = _reg, \
.features = CCU_FEATURE_FRACTIONAL, \
.hw.init = CLK_HW_INIT(_name, \
_parent, \
&ccu_nm_ops, \
_flags), \
}, \
}
#define SUNXI_CCU_NM_WITH_GATE_LOCK(_struct, _name, _parent, _reg, \
_nshift, _nwidth, \
_mshift, _mwidth, \
_gate, _lock, _flags) \
struct ccu_nm _struct = { \
.enable = _gate, \
.lock = _lock, \
.n = _SUNXI_CCU_MULT(_nshift, _nwidth), \
.m = _SUNXI_CCU_DIV(_mshift, _mwidth), \
.common = { \
.reg = _reg, \
.hw.init = CLK_HW_INIT(_name, \
_parent, \
&ccu_nm_ops, \
_flags), \
}, \
}
static
inline
struct
ccu_nm
*
hw_to_ccu_nm
(
struct
clk_hw
*
hw
)
{
struct
ccu_common
*
common
=
hw_to_ccu_common
(
hw
);
return
container_of
(
common
,
struct
ccu_nm
,
common
);
}
extern
const
struct
clk_ops
ccu_nm_ops
;
#endif
/* _CCU_NM_H_ */
drivers/clk/sunxi-ng/ccu_phase.c
0 → 100644
View file @
7adb7695
/*
* Copyright (C) 2016 Maxime Ripard
* Maxime Ripard <maxime.ripard@free-electrons.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.
*/
#include <linux/clk-provider.h>
#include <linux/spinlock.h>
#include "ccu_phase.h"
static
int
ccu_phase_get_phase
(
struct
clk_hw
*
hw
)
{
struct
ccu_phase
*
phase
=
hw_to_ccu_phase
(
hw
);
struct
clk_hw
*
parent
,
*
grandparent
;
unsigned
int
parent_rate
,
grandparent_rate
;
u16
step
,
parent_div
;
u32
reg
;
u8
delay
;
reg
=
readl
(
phase
->
common
.
base
+
phase
->
common
.
reg
);
delay
=
(
reg
>>
phase
->
shift
);
delay
&=
(
1
<<
phase
->
width
)
-
1
;
if
(
!
delay
)
return
180
;
/* Get our parent clock, it's the one that can adjust its rate */
parent
=
clk_hw_get_parent
(
hw
);
if
(
!
parent
)
return
-
EINVAL
;
/* And its rate */
parent_rate
=
clk_hw_get_rate
(
parent
);
if
(
!
parent_rate
)
return
-
EINVAL
;
/* Now, get our parent's parent (most likely some PLL) */
grandparent
=
clk_hw_get_parent
(
parent
);
if
(
!
grandparent
)
return
-
EINVAL
;
/* And its rate */
grandparent_rate
=
clk_hw_get_rate
(
grandparent
);
if
(
!
grandparent_rate
)
return
-
EINVAL
;
/* Get our parent clock divider */
parent_div
=
grandparent_rate
/
parent_rate
;
step
=
DIV_ROUND_CLOSEST
(
360
,
parent_div
);
return
delay
*
step
;
}
static
int
ccu_phase_set_phase
(
struct
clk_hw
*
hw
,
int
degrees
)
{
struct
ccu_phase
*
phase
=
hw_to_ccu_phase
(
hw
);
struct
clk_hw
*
parent
,
*
grandparent
;
unsigned
int
parent_rate
,
grandparent_rate
;
unsigned
long
flags
;
u32
reg
;
u8
delay
;
/* Get our parent clock, it's the one that can adjust its rate */
parent
=
clk_hw_get_parent
(
hw
);
if
(
!
parent
)
return
-
EINVAL
;
/* And its rate */
parent_rate
=
clk_hw_get_rate
(
parent
);
if
(
!
parent_rate
)
return
-
EINVAL
;
/* Now, get our parent's parent (most likely some PLL) */
grandparent
=
clk_hw_get_parent
(
parent
);
if
(
!
grandparent
)
return
-
EINVAL
;
/* And its rate */
grandparent_rate
=
clk_hw_get_rate
(
grandparent
);
if
(
!
grandparent_rate
)
return
-
EINVAL
;
if
(
degrees
!=
180
)
{
u16
step
,
parent_div
;
/* Get our parent divider */
parent_div
=
grandparent_rate
/
parent_rate
;
/*
* We can only outphase the clocks by multiple of the
* PLL's period.
*
* Since our parent clock is only a divider, and the
* formula to get the outphasing in degrees is deg =
* 360 * delta / period
*
* If we simplify this formula, we can see that the
* only thing that we're concerned about is the number
* of period we want to outphase our clock from, and
* the divider set by our parent clock.
*/
step
=
DIV_ROUND_CLOSEST
(
360
,
parent_div
);
delay
=
DIV_ROUND_CLOSEST
(
degrees
,
step
);
}
else
{
delay
=
0
;
}
spin_lock_irqsave
(
phase
->
common
.
lock
,
flags
);
reg
=
readl
(
phase
->
common
.
base
+
phase
->
common
.
reg
);
reg
&=
~
GENMASK
(
phase
->
width
+
phase
->
shift
-
1
,
phase
->
shift
);
writel
(
reg
|
(
delay
<<
phase
->
shift
),
phase
->
common
.
base
+
phase
->
common
.
reg
);
spin_unlock_irqrestore
(
phase
->
common
.
lock
,
flags
);
return
0
;
}
const
struct
clk_ops
ccu_phase_ops
=
{
.
get_phase
=
ccu_phase_get_phase
,
.
set_phase
=
ccu_phase_set_phase
,
};
drivers/clk/sunxi-ng/ccu_phase.h
0 → 100644
View file @
7adb7695
/*
* Copyright (c) 2016 Maxime Ripard. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _CCU_PHASE_H_
#define _CCU_PHASE_H_
#include <linux/clk-provider.h>
#include "ccu_common.h"
struct
ccu_phase
{
u8
shift
;
u8
width
;
struct
ccu_common
common
;
};
#define SUNXI_CCU_PHASE(_struct, _name, _parent, _reg, _shift, _width, _flags) \
struct ccu_phase _struct = { \
.shift = _shift, \
.width = _width, \
.common = { \
.reg = _reg, \
.hw.init = CLK_HW_INIT(_name, \
_parent, \
&ccu_phase_ops, \
_flags), \
} \
}
static
inline
struct
ccu_phase
*
hw_to_ccu_phase
(
struct
clk_hw
*
hw
)
{
struct
ccu_common
*
common
=
hw_to_ccu_common
(
hw
);
return
container_of
(
common
,
struct
ccu_phase
,
common
);
}
extern
const
struct
clk_ops
ccu_phase_ops
;
#endif
/* _CCU_PHASE_H_ */
drivers/clk/sunxi-ng/ccu_reset.c
0 → 100644
View file @
7adb7695
/*
* Copyright (C) 2016 Maxime Ripard
* Maxime Ripard <maxime.ripard@free-electrons.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.
*/
#include <linux/io.h>
#include <linux/reset-controller.h>
#include "ccu_reset.h"
static
int
ccu_reset_assert
(
struct
reset_controller_dev
*
rcdev
,
unsigned
long
id
)
{
struct
ccu_reset
*
ccu
=
rcdev_to_ccu_reset
(
rcdev
);
const
struct
ccu_reset_map
*
map
=
&
ccu
->
reset_map
[
id
];
unsigned
long
flags
;
u32
reg
;
spin_lock_irqsave
(
ccu
->
lock
,
flags
);
reg
=
readl
(
ccu
->
base
+
map
->
reg
);
writel
(
reg
&
~
map
->
bit
,
ccu
->
base
+
map
->
reg
);
spin_unlock_irqrestore
(
ccu
->
lock
,
flags
);
return
0
;
}
static
int
ccu_reset_deassert
(
struct
reset_controller_dev
*
rcdev
,
unsigned
long
id
)
{
struct
ccu_reset
*
ccu
=
rcdev_to_ccu_reset
(
rcdev
);
const
struct
ccu_reset_map
*
map
=
&
ccu
->
reset_map
[
id
];
unsigned
long
flags
;
u32
reg
;
spin_lock_irqsave
(
ccu
->
lock
,
flags
);
reg
=
readl
(
ccu
->
base
+
map
->
reg
);
writel
(
reg
|
map
->
bit
,
ccu
->
base
+
map
->
reg
);
spin_unlock_irqrestore
(
ccu
->
lock
,
flags
);
return
0
;
}
const
struct
reset_control_ops
ccu_reset_ops
=
{
.
assert
=
ccu_reset_assert
,
.
deassert
=
ccu_reset_deassert
,
};
drivers/clk/sunxi-ng/ccu_reset.h
0 → 100644
View file @
7adb7695
/*
* Copyright (c) 2016 Maxime Ripard. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _CCU_RESET_H_
#define _CCU_RESET_H_
#include <linux/reset-controller.h>
struct
ccu_reset_map
{
u16
reg
;
u32
bit
;
};
struct
ccu_reset
{
void
__iomem
*
base
;
struct
ccu_reset_map
*
reset_map
;
spinlock_t
*
lock
;
struct
reset_controller_dev
rcdev
;
};
static
inline
struct
ccu_reset
*
rcdev_to_ccu_reset
(
struct
reset_controller_dev
*
rcdev
)
{
return
container_of
(
rcdev
,
struct
ccu_reset
,
rcdev
);
}
extern
const
struct
reset_control_ops
ccu_reset_ops
;
#endif
/* _CCU_RESET_H_ */
include/dt-bindings/clock/sun8i-h3-ccu.h
0 → 100644
View file @
7adb7695
/*
* Copyright (C) 2016 Maxime Ripard <maxime.ripard@free-electrons.com>
*
* This file is dual-licensed: you can use it either under the terms
* of the GPL or the X11 license, at your option. Note that this dual
* licensing only applies to this file, and not this project as a
* whole.
*
* a) This file 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 file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Or, alternatively,
*
* b) Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _DT_BINDINGS_CLK_SUN8I_H3_H_
#define _DT_BINDINGS_CLK_SUN8I_H3_H_
#define CLK_CPUX 14
#define CLK_BUS_CE 20
#define CLK_BUS_DMA 21
#define CLK_BUS_MMC0 22
#define CLK_BUS_MMC1 23
#define CLK_BUS_MMC2 24
#define CLK_BUS_NAND 25
#define CLK_BUS_DRAM 26
#define CLK_BUS_EMAC 27
#define CLK_BUS_TS 28
#define CLK_BUS_HSTIMER 29
#define CLK_BUS_SPI0 30
#define CLK_BUS_SPI1 31
#define CLK_BUS_OTG 32
#define CLK_BUS_EHCI0 33
#define CLK_BUS_EHCI1 34
#define CLK_BUS_EHCI2 35
#define CLK_BUS_EHCI3 36
#define CLK_BUS_OHCI0 37
#define CLK_BUS_OHCI1 38
#define CLK_BUS_OHCI2 39
#define CLK_BUS_OHCI3 40
#define CLK_BUS_VE 41
#define CLK_BUS_TCON0 42
#define CLK_BUS_TCON1 43
#define CLK_BUS_DEINTERLACE 44
#define CLK_BUS_CSI 45
#define CLK_BUS_TVE 46
#define CLK_BUS_HDMI 47
#define CLK_BUS_DE 48
#define CLK_BUS_GPU 49
#define CLK_BUS_MSGBOX 50
#define CLK_BUS_SPINLOCK 51
#define CLK_BUS_CODEC 52
#define CLK_BUS_SPDIF 53
#define CLK_BUS_PIO 54
#define CLK_BUS_THS 55
#define CLK_BUS_I2S0 56
#define CLK_BUS_I2S1 57
#define CLK_BUS_I2S2 58
#define CLK_BUS_I2C0 59
#define CLK_BUS_I2C1 60
#define CLK_BUS_I2C2 61
#define CLK_BUS_UART0 62
#define CLK_BUS_UART1 63
#define CLK_BUS_UART2 64
#define CLK_BUS_UART3 65
#define CLK_BUS_SCR 66
#define CLK_BUS_EPHY 67
#define CLK_BUS_DBG 68
#define CLK_THS 69
#define CLK_NAND 70
#define CLK_MMC0 71
#define CLK_MMC0_SAMPLE 72
#define CLK_MMC0_OUTPUT 73
#define CLK_MMC1 74
#define CLK_MMC1_SAMPLE 75
#define CLK_MMC1_OUTPUT 76
#define CLK_MMC2 77
#define CLK_MMC2_SAMPLE 78
#define CLK_MMC2_OUTPUT 79
#define CLK_TS 80
#define CLK_CE 81
#define CLK_SPI0 82
#define CLK_SPI1 83
#define CLK_I2S0 84
#define CLK_I2S1 85
#define CLK_I2S2 86
#define CLK_SPDIF 87
#define CLK_USB_PHY0 88
#define CLK_USB_PHY1 89
#define CLK_USB_PHY2 90
#define CLK_USB_PHY3 91
#define CLK_USB_OHCI0 92
#define CLK_USB_OHCI1 93
#define CLK_USB_OHCI2 94
#define CLK_USB_OHCI3 95
#define CLK_DRAM_VE 97
#define CLK_DRAM_CSI 98
#define CLK_DRAM_DEINTERLACE 99
#define CLK_DRAM_TS 100
#define CLK_DE 101
#define CLK_TCON0 102
#define CLK_TVE 103
#define CLK_DEINTERLACE 104
#define CLK_CSI_MISC 105
#define CLK_CSI_SCLK 106
#define CLK_CSI_MCLK 107
#define CLK_VE 108
#define CLK_AC_DIG 109
#define CLK_AVS 110
#define CLK_HDMI 111
#define CLK_HDMI_DDC 112
#define CLK_GPU 114
#endif
/* _DT_BINDINGS_CLK_SUN8I_H3_H_ */
include/dt-bindings/reset/sun8i-h3-ccu.h
0 → 100644
View file @
7adb7695
/*
* Copyright (C) 2016 Maxime Ripard <maxime.ripard@free-electrons.com>
*
* This file is dual-licensed: you can use it either under the terms
* of the GPL or the X11 license, at your option. Note that this dual
* licensing only applies to this file, and not this project as a
* whole.
*
* a) This file 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 file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Or, alternatively,
*
* b) Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _DT_BINDINGS_RST_SUN8I_H3_H_
#define _DT_BINDINGS_RST_SUN8I_H3_H_
#define RST_USB_PHY0 0
#define RST_USB_PHY1 1
#define RST_USB_PHY2 2
#define RST_USB_PHY3 3
#define RST_MBUS 4
#define RST_BUS_CE 5
#define RST_BUS_DMA 6
#define RST_BUS_MMC0 7
#define RST_BUS_MMC1 8
#define RST_BUS_MMC2 9
#define RST_BUS_NAND 10
#define RST_BUS_DRAM 11
#define RST_BUS_EMAC 12
#define RST_BUS_TS 13
#define RST_BUS_HSTIMER 14
#define RST_BUS_SPI0 15
#define RST_BUS_SPI1 16
#define RST_BUS_OTG 17
#define RST_BUS_EHCI0 18
#define RST_BUS_EHCI1 19
#define RST_BUS_EHCI2 20
#define RST_BUS_EHCI3 21
#define RST_BUS_OHCI0 22
#define RST_BUS_OHCI1 23
#define RST_BUS_OHCI2 24
#define RST_BUS_OHCI3 25
#define RST_BUS_VE 26
#define RST_BUS_TCON0 27
#define RST_BUS_TCON1 28
#define RST_BUS_DEINTERLACE 29
#define RST_BUS_CSI 30
#define RST_BUS_TVE 31
#define RST_BUS_HDMI0 32
#define RST_BUS_HDMI1 33
#define RST_BUS_DE 34
#define RST_BUS_GPU 35
#define RST_BUS_MSGBOX 36
#define RST_BUS_SPINLOCK 37
#define RST_BUS_DBG 38
#define RST_BUS_EPHY 39
#define RST_BUS_CODEC 40
#define RST_BUS_SPDIF 41
#define RST_BUS_THS 42
#define RST_BUS_I2S0 43
#define RST_BUS_I2S1 44
#define RST_BUS_I2S2 45
#define RST_BUS_I2C0 46
#define RST_BUS_I2C1 47
#define RST_BUS_I2C2 48
#define RST_BUS_UART0 49
#define RST_BUS_UART1 50
#define RST_BUS_UART2 51
#define RST_BUS_UART3 52
#define RST_BUS_SCR 53
#endif
/* _DT_BINDINGS_RST_SUN8I_H3_H_ */
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