Commit 05a5b5d8 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux

Pull more clk updates from Stephen Boyd:
 "Here's some more updates that missed the last pull request because I
  happened to tag the tree at an earlier point in the history of
  clk-next. I must have fat fingered it and checked out an older version
  of clk-next on this second computer I'm using.

  This time it actually includes more code for Qualcomm SoCs, the AT91
  major updates, and some Rockchip SoC clk driver updates as well. I've
  corrected this flow so this shouldn't happen again"

* tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (83 commits)
  clk: bcm2835: Do not use prediv with bcm2711's PLLs
  clk: drop unused function __clk_get_flags
  clk: hsdk: Fix bad dependency on IOMEM
  dt-bindings: clock: Fix YAML schemas for LPASS clocks on SC7180
  clk: mmp: avoid missing prototype warning
  clk: sparx5: Add Sparx5 SoC DPLL clock driver
  dt-bindings: clock: sparx5: Add bindings include file
  clk: qoriq: add LS1021A core pll mux options
  clk: clk-atlas6: fix return value check in atlas6_clk_init()
  clk: tegra: pll: Improve PLLM enable-state detection
  clk: X1000: Add support for calculat REFCLK of USB PHY.
  clk: JZ4780: Reformat the code to align it.
  clk: JZ4780: Add functions for enable and disable USB PHY.
  clk: Ingenic: Add RTC related clocks for Ingenic SoCs.
  dt-bindings: clock: Add tabs to align code.
  dt-bindings: clock: Add RTC related clocks for Ingenic SoCs.
  clk: davinci: Use fallthrough pseudo-keyword
  clk: imx: Use fallthrough pseudo-keyword
  clk: qcom: gcc-sdm660: Fix up gcc_mss_mnoc_bimc_axi_clk
  clk: qcom: gcc-sdm660: Add missing modem reset
  ...
parents 45860394 dd9c697a
...@@ -10,6 +10,15 @@ maintainers: ...@@ -10,6 +10,15 @@ maintainers:
- Eric Anholt <eric@anholt.net> - Eric Anholt <eric@anholt.net>
- Stefan Wahren <wahrenst@gmx.net> - Stefan Wahren <wahrenst@gmx.net>
select:
properties:
compatible:
contains:
const: raspberrypi,bcm2835-firmware
required:
- compatible
properties: properties:
compatible: compatible:
items: items:
......
Binding for IDT VersaClock 5,6 programmable i2c clock generators.
The IDT VersaClock 5 and VersaClock 6 are programmable i2c clock
generators providing from 3 to 12 output clocks.
==I2C device node==
Required properties:
- compatible: shall be one of
"idt,5p49v5923"
"idt,5p49v5925"
"idt,5p49v5933"
"idt,5p49v5935"
"idt,5p49v6901"
"idt,5p49v6965"
- reg: i2c device address, shall be 0x68 or 0x6a.
- #clock-cells: from common clock binding; shall be set to 1.
- clocks: from common clock binding; list of parent clock handles,
- 5p49v5923 and
5p49v5925 and
5p49v6901: (required) either or both of XTAL or CLKIN
reference clock.
- 5p49v5933 and
- 5p49v5935: (optional) property not present (internal
Xtal used) or CLKIN reference
clock.
- clock-names: from common clock binding; clock input names, can be
- 5p49v5923 and
5p49v5925 and
5p49v6901: (required) either or both of "xin", "clkin".
- 5p49v5933 and
- 5p49v5935: (optional) property not present or "clkin".
For all output ports, a corresponding, optional child node named OUT1,
OUT2, etc. can represent a each output, and the node can be used to
specify the following:
- itd,mode: can be one of the following:
- VC5_LVPECL
- VC5_CMOS
- VC5_HCSL33
- VC5_LVDS
- VC5_CMOS2
- VC5_CMOSD
- VC5_HCSL25
- idt,voltage-microvolts: can be one of the following
- 1800000
- 2500000
- 3300000
- idt,slew-percent: Percent of normal, can be one of
- 80
- 85
- 90
- 100
==Mapping between clock specifier and physical pins==
When referencing the provided clock in the DT using phandle and
clock specifier, the following mapping applies:
5P49V5923:
0 -- OUT0_SEL_I2CB
1 -- OUT1
2 -- OUT2
5P49V5933:
0 -- OUT0_SEL_I2CB
1 -- OUT1
2 -- OUT4
5P49V5925 and
5P49V5935:
0 -- OUT0_SEL_I2CB
1 -- OUT1
2 -- OUT2
3 -- OUT3
4 -- OUT4
5P49V6901:
0 -- OUT0_SEL_I2CB
1 -- OUT1
2 -- OUT2
3 -- OUT3
4 -- OUT4
==Example==
/* 25MHz reference crystal */
ref25: ref25m {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <25000000>;
};
i2c-master-node {
/* IDT 5P49V5923 i2c clock generator */
vc5: clock-generator@6a {
compatible = "idt,5p49v5923";
reg = <0x6a>;
#clock-cells = <1>;
/* Connect XIN input to 25MHz reference */
clocks = <&ref25m>;
clock-names = "xin";
OUT1 {
itd,mode = <VC5_CMOS>;
idt,voltage-microvolts = <1800000>;
idt,slew-percent = <80>;
};
OUT2 {
...
};
...
};
};
/* Consumer referencing the 5P49V5923 pin OUT1 */
consumer {
...
clocks = <&vc5 1>;
...
}
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/idt,versaclock5.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Binding for IDT VersaClock 5 and 6 programmable I2C clock generators
description: |
The IDT VersaClock 5 and VersaClock 6 are programmable I2C
clock generators providing from 3 to 12 output clocks.
When referencing the provided clock in the DT using phandle and clock
specifier, the following mapping applies:
- 5P49V5923:
0 -- OUT0_SEL_I2CB
1 -- OUT1
2 -- OUT2
- 5P49V5933:
0 -- OUT0_SEL_I2CB
1 -- OUT1
2 -- OUT4
- other parts:
0 -- OUT0_SEL_I2CB
1 -- OUT1
2 -- OUT2
3 -- OUT3
4 -- OUT4
maintainers:
- Luca Ceresoli <luca@lucaceresoli.net>
properties:
compatible:
enum:
- idt,5p49v5923
- idt,5p49v5925
- idt,5p49v5933
- idt,5p49v5935
- idt,5p49v6901
- idt,5p49v6965
reg:
description: I2C device address
enum: [ 0x68, 0x6a ]
'#clock-cells':
const: 1
patternProperties:
"^OUT[1-4]$":
type: object
description:
Description of one of the outputs (OUT1..OUT4). See "Clock1 Output
Configuration" in the Versaclock 5/6/6E Family Register Description
and Programming Guide.
properties:
idt,mode:
description:
The output drive mode. Values defined in dt-bindings/clk/versaclock.h
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 6
idt,voltage-microvolt:
description: The output drive voltage.
enum: [ 1800000, 2500000, 3300000 ]
idt,slew-percent:
description: The Slew rate control for CMOS single-ended.
$ref: /schemas/types.yaml#/definitions/uint32
enum: [ 80, 85, 90, 100 ]
required:
- compatible
- reg
- '#clock-cells'
allOf:
- if:
properties:
compatible:
enum:
- idt,5p49v5933
- idt,5p49v5935
then:
# Devices with builtin crystal + optional external input
properties:
clock-names:
const: clkin
clocks:
maxItems: 1
else:
# Devices without builtin crystal
properties:
clock-names:
minItems: 1
maxItems: 2
items:
enum: [ xin, clkin ]
clocks:
minItems: 1
maxItems: 2
required:
- clock-names
- clocks
examples:
- |
#include <dt-bindings/clk/versaclock.h>
/* 25MHz reference crystal */
ref25: ref25m {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <25000000>;
};
i2c@0 {
reg = <0x0 0x100>;
#address-cells = <1>;
#size-cells = <0>;
/* IDT 5P49V5923 I2C clock generator */
vc5: clock-generator@6a {
compatible = "idt,5p49v5923";
reg = <0x6a>;
#clock-cells = <1>;
/* Connect XIN input to 25MHz reference */
clocks = <&ref25m>;
clock-names = "xin";
OUT1 {
idt,drive-mode = <VC5_CMOSD>;
idt,voltage-microvolts = <1800000>;
idt,slew-percent = <80>;
};
OUT4 {
idt,drive-mode = <VC5_LVDS>;
};
};
};
/* Consumer referencing the 5P49V5923 pin OUT1 */
consumer {
/* ... */
clocks = <&vc5 1>;
/* ... */
};
...
# SPDX-License-Identifier: GPL-2.0-only # SPDX-License-Identifier: GPL-2.0-only
%YAML 1.2 %YAML 1.2
--- ---
$id: http://devicetree.org/schemas/clock/qcom,sdm845-gpucc.yaml# $id: http://devicetree.org/schemas/clock/qcom,gpucc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Graphics Clock & Reset Controller Binding for SDM845 title: Qualcomm Graphics Clock & Reset Controller Binding
maintainers: maintainers:
- Taniya Das <tdas@codeaurora.org> - Taniya Das <tdas@codeaurora.org>
description: | description: |
Qualcomm graphics clock control module which supports the clocks, resets and Qualcomm graphics clock control module which supports the clocks, resets and
power domains on SDM845. power domains on SDM845/SC7180/SM8150/SM8250.
See also dt-bindings/clock/qcom,gpucc-sdm845.h. See also:
dt-bindings/clock/qcom,gpucc-sdm845.h
dt-bindings/clock/qcom,gpucc-sc7180.h
dt-bindings/clock/qcom,gpucc-sm8150.h
dt-bindings/clock/qcom,gpucc-sm8250.h
properties: properties:
compatible: compatible:
const: qcom,sdm845-gpucc enum:
- qcom,sdm845-gpucc
- qcom,sc7180-gpucc
- qcom,sm8150-gpucc
- qcom,sm8250-gpucc
clocks: clocks:
items: items:
......
# SPDX-License-Identifier: GPL-2.0-only # SPDX-License-Identifier: GPL-2.0-only
%YAML 1.2 %YAML 1.2
--- ---
$id: http://devicetree.org/schemas/clock/qcom,kryocc.yaml# $id: http://devicetree.org/schemas/clock/qcom,msm8996-apcc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm clock controller for MSM8996 CPUs title: Qualcomm clock controller for MSM8996 CPUs
...@@ -46,11 +46,9 @@ required: ...@@ -46,11 +46,9 @@ required:
additionalProperties: false additionalProperties: false
examples: examples:
# Example for msm8996
- | - |
kryocc: clock-controller@6400000 { kryocc: clock-controller@6400000 {
compatible = "qcom,msm8996-apcc"; compatible = "qcom,msm8996-apcc";
reg = <0x6400000 0x90000>; reg = <0x6400000 0x90000>;
#clock-cells = <1>; #clock-cells = <1>;
}; };
...
# SPDX-License-Identifier: GPL-2.0-only
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/qcom,sc7180-gpucc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Graphics Clock & Reset Controller Binding for SC7180
maintainers:
- Taniya Das <tdas@codeaurora.org>
description: |
Qualcomm graphics clock control module which supports the clocks, resets and
power domains on SC7180.
See also dt-bindings/clock/qcom,gpucc-sc7180.h.
properties:
compatible:
const: qcom,sc7180-gpucc
clocks:
items:
- description: Board XO source
- description: GPLL0 main branch source
- description: GPLL0 div branch source
clock-names:
items:
- const: bi_tcxo
- const: gcc_gpu_gpll0_clk_src
- const: gcc_gpu_gpll0_div_clk_src
'#clock-cells':
const: 1
'#reset-cells':
const: 1
'#power-domain-cells':
const: 1
reg:
maxItems: 1
required:
- compatible
- reg
- clocks
- clock-names
- '#clock-cells'
- '#reset-cells'
- '#power-domain-cells'
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,gcc-sc7180.h>
#include <dt-bindings/clock/qcom,rpmh.h>
clock-controller@5090000 {
compatible = "qcom,sc7180-gpucc";
reg = <0x05090000 0x9000>;
clocks = <&rpmhcc RPMH_CXO_CLK>,
<&gcc GCC_GPU_GPLL0_CLK_SRC>,
<&gcc GCC_GPU_GPLL0_DIV_CLK_SRC>;
clock-names = "bi_tcxo",
"gcc_gpu_gpll0_clk_src",
"gcc_gpu_gpll0_div_clk_src";
#clock-cells = <1>;
#reset-cells = <1>;
#power-domain-cells = <1>;
};
...
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/qcom,sc7180-lpasscorecc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm LPASS Core Clock Controller Binding for SC7180
maintainers:
- Taniya Das <tdas@codeaurora.org>
description: |
Qualcomm LPASS core clock control module which supports the clocks and
power domains on SC7180.
See also:
- dt-bindings/clock/qcom,lpasscorecc-sc7180.h
properties:
compatible:
enum:
- qcom,sc7180-lpasshm
- qcom,sc7180-lpasscorecc
clocks:
items:
- description: gcc_lpass_sway clock from GCC
- description: Board XO source
clock-names:
items:
- const: iface
- const: bi_tcxo
power-domains:
maxItems: 1
'#clock-cells':
const: 1
'#power-domain-cells':
const: 1
reg:
minItems: 1
items:
- description: lpass core cc register
- description: lpass audio cc register
reg-names:
items:
- const: lpass_core_cc
- const: lpass_audio_cc
if:
properties:
compatible:
contains:
const: qcom,sc7180-lpasshm
then:
properties:
reg:
maxItems: 1
else:
properties:
reg:
minItems: 2
required:
- compatible
- reg
- clocks
- clock-names
- '#clock-cells'
- '#power-domain-cells'
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,rpmh.h>
#include <dt-bindings/clock/qcom,gcc-sc7180.h>
#include <dt-bindings/clock/qcom,lpasscorecc-sc7180.h>
clock-controller@63000000 {
compatible = "qcom,sc7180-lpasshm";
reg = <0x63000000 0x28>;
clocks = <&gcc GCC_LPASS_CFG_NOC_SWAY_CLK>, <&rpmhcc RPMH_CXO_CLK>;
clock-names = "iface", "bi_tcxo";
#clock-cells = <1>;
#power-domain-cells = <1>;
};
- |
#include <dt-bindings/clock/qcom,rpmh.h>
#include <dt-bindings/clock/qcom,gcc-sc7180.h>
#include <dt-bindings/clock/qcom,lpasscorecc-sc7180.h>
clock-controller@62d00000 {
compatible = "qcom,sc7180-lpasscorecc";
reg = <0x62d00000 0x50000>, <0x62780000 0x30000>;
reg-names = "lpass_core_cc", "lpass_audio_cc";
clocks = <&gcc GCC_LPASS_CFG_NOC_SWAY_CLK>, <&rpmhcc RPMH_CXO_CLK>;
clock-names = "iface", "bi_tcxo";
power-domains = <&lpass_hm LPASS_CORE_HM_GDSCR>;
#clock-cells = <1>;
#power-domain-cells = <1>;
};
...
...@@ -4,9 +4,15 @@ The RK3288 clock controller generates and supplies clock to various ...@@ -4,9 +4,15 @@ The RK3288 clock controller generates and supplies clock to various
controllers within the SoC and also implements a reset controller for SoC controllers within the SoC and also implements a reset controller for SoC
peripherals. peripherals.
A revision of this SoC is available: rk3288w. The clock tree is a bit
different so another dt-compatible is available. Noticed that it is only
setting the difference but there is no automatic revision detection. This
should be performed by bootloaders.
Required Properties: Required Properties:
- compatible: should be "rockchip,rk3288-cru" - compatible: should be "rockchip,rk3288-cru" or "rockchip,rk3288w-cru" in
case of this revision of Rockchip rk3288.
- reg: physical base address of the controller and length of memory mapped - reg: physical base address of the controller and length of memory mapped
region. region.
- #clock-cells: should be 1. - #clock-cells: should be 1.
......
...@@ -1540,6 +1540,7 @@ F: drivers/mmc/host/owl-mmc.c ...@@ -1540,6 +1540,7 @@ F: drivers/mmc/host/owl-mmc.c
F: drivers/pinctrl/actions/* F: drivers/pinctrl/actions/*
F: drivers/soc/actions/ F: drivers/soc/actions/
F: include/dt-bindings/power/owl-* F: include/dt-bindings/power/owl-*
F: include/dt-bindings/reset/actions,*
F: include/linux/soc/actions/ F: include/linux/soc/actions/
N: owl N: owl
...@@ -8409,8 +8410,9 @@ W: https://github.com/o2genum/ideapad-slidebar ...@@ -8409,8 +8410,9 @@ W: https://github.com/o2genum/ideapad-slidebar
F: drivers/input/misc/ideapad_slidebar.c F: drivers/input/misc/ideapad_slidebar.c
IDT VersaClock 5 CLOCK DRIVER IDT VersaClock 5 CLOCK DRIVER
M: Marek Vasut <marek.vasut@gmail.com> M: Luca Ceresoli <luca@lucaceresoli.net>
S: Maintained S: Maintained
F: Documentation/devicetree/bindings/clock/idt,versaclock5.yaml
F: drivers/clk/clk-versaclock5.c F: drivers/clk/clk-versaclock5.c
IEEE 802.15.4 SUBSYSTEM IEEE 802.15.4 SUBSYSTEM
......
...@@ -50,7 +50,7 @@ source "drivers/clk/versatile/Kconfig" ...@@ -50,7 +50,7 @@ source "drivers/clk/versatile/Kconfig"
config CLK_HSDK config CLK_HSDK
bool "PLL Driver for HSDK platform" bool "PLL Driver for HSDK platform"
depends on OF || COMPILE_TEST depends on OF || COMPILE_TEST
depends on IOMEM depends on HAS_IOMEM
help help
This driver supports the HSDK core, system, ddr, tunnel and hdmi PLLs This driver supports the HSDK core, system, ddr, tunnel and hdmi PLLs
control. control.
......
...@@ -28,6 +28,7 @@ obj-$(CONFIG_COMMON_CLK_CDCE925) += clk-cdce925.o ...@@ -28,6 +28,7 @@ obj-$(CONFIG_COMMON_CLK_CDCE925) += clk-cdce925.o
obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o
obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o
obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o
obj-$(CONFIG_ARCH_SPARX5) += clk-sparx5.o
obj-$(CONFIG_COMMON_CLK_FIXED_MMIO) += clk-fixed-mmio.o obj-$(CONFIG_COMMON_CLK_FIXED_MMIO) += clk-fixed-mmio.o
obj-$(CONFIG_COMMON_CLK_FSL_SAI) += clk-fsl-sai.o obj-$(CONFIG_COMMON_CLK_FSL_SAI) += clk-fsl-sai.o
obj-$(CONFIG_COMMON_CLK_GEMINI) += clk-gemini.o obj-$(CONFIG_COMMON_CLK_GEMINI) += clk-gemini.o
......
...@@ -23,8 +23,10 @@ ...@@ -23,8 +23,10 @@
#include "owl-gate.h" #include "owl-gate.h"
#include "owl-mux.h" #include "owl-mux.h"
#include "owl-pll.h" #include "owl-pll.h"
#include "owl-reset.h"
#include <dt-bindings/clock/actions,s500-cmu.h> #include <dt-bindings/clock/actions,s500-cmu.h>
#include <dt-bindings/reset/actions,s500-reset.h>
#define CMU_COREPLL (0x0000) #define CMU_COREPLL (0x0000)
#define CMU_DEVPLL (0x0004) #define CMU_DEVPLL (0x0004)
...@@ -175,6 +177,8 @@ static OWL_MUX(dev_clk, "dev_clk", dev_clk_mux_p, CMU_DEVPLL, 12, 1, CLK_SET_RAT ...@@ -175,6 +177,8 @@ static OWL_MUX(dev_clk, "dev_clk", dev_clk_mux_p, CMU_DEVPLL, 12, 1, CLK_SET_RAT
static OWL_MUX(ahbprediv_clk, "ahbprediv_clk", ahbprediv_clk_mux_p, CMU_BUSCLK1, 8, 3, CLK_SET_RATE_PARENT); static OWL_MUX(ahbprediv_clk, "ahbprediv_clk", ahbprediv_clk_mux_p, CMU_BUSCLK1, 8, 3, CLK_SET_RATE_PARENT);
/* gate clocks */ /* gate clocks */
static OWL_GATE(gpio_clk, "gpio_clk", "apb_clk", CMU_DEVCLKEN0, 18, 0, 0);
static OWL_GATE(dmac_clk, "dmac_clk", "h_clk", CMU_DEVCLKEN0, 1, 0, 0);
static OWL_GATE(spi0_clk, "spi0_clk", "ahb_clk", CMU_DEVCLKEN1, 10, 0, CLK_IGNORE_UNUSED); static OWL_GATE(spi0_clk, "spi0_clk", "ahb_clk", CMU_DEVCLKEN1, 10, 0, CLK_IGNORE_UNUSED);
static OWL_GATE(spi1_clk, "spi1_clk", "ahb_clk", CMU_DEVCLKEN1, 11, 0, CLK_IGNORE_UNUSED); static OWL_GATE(spi1_clk, "spi1_clk", "ahb_clk", CMU_DEVCLKEN1, 11, 0, CLK_IGNORE_UNUSED);
static OWL_GATE(spi2_clk, "spi2_clk", "ahb_clk", CMU_DEVCLKEN1, 12, 0, CLK_IGNORE_UNUSED); static OWL_GATE(spi2_clk, "spi2_clk", "ahb_clk", CMU_DEVCLKEN1, 12, 0, CLK_IGNORE_UNUSED);
...@@ -183,7 +187,8 @@ static OWL_GATE(timer_clk, "timer_clk", "hosc", CMU_DEVCLKEN1, 27, 0, 0); ...@@ -183,7 +187,8 @@ static OWL_GATE(timer_clk, "timer_clk", "hosc", CMU_DEVCLKEN1, 27, 0, 0);
static OWL_GATE(hdmi_clk, "hdmi_clk", "hosc", CMU_DEVCLKEN1, 3, 0, 0); static OWL_GATE(hdmi_clk, "hdmi_clk", "hosc", CMU_DEVCLKEN1, 3, 0, 0);
/* divider clocks */ /* divider clocks */
static OWL_DIVIDER(h_clk, "h_clk", "ahbprevdiv_clk", CMU_BUSCLK1, 12, 2, NULL, 0, 0); static OWL_DIVIDER(h_clk, "h_clk", "ahbprediv_clk", CMU_BUSCLK1, 12, 2, NULL, 0, 0);
static OWL_DIVIDER(apb_clk, "apb_clk", "ahb_clk", CMU_BUSCLK1, 14, 2, NULL, 0, 0);
static OWL_DIVIDER(rmii_ref_clk, "rmii_ref_clk", "ethernet_pll_clk", CMU_ETHERNETPLL, 1, 1, rmii_ref_div_table, 0, 0); static OWL_DIVIDER(rmii_ref_clk, "rmii_ref_clk", "ethernet_pll_clk", CMU_ETHERNETPLL, 1, 1, rmii_ref_div_table, 0, 0);
/* factor clocks */ /* factor clocks */
...@@ -428,6 +433,9 @@ static struct owl_clk_common *s500_clks[] = { ...@@ -428,6 +433,9 @@ static struct owl_clk_common *s500_clks[] = {
&spdif_clk.common, &spdif_clk.common,
&nand_clk.common, &nand_clk.common,
&ecc_clk.common, &ecc_clk.common,
&apb_clk.common,
&dmac_clk.common,
&gpio_clk.common,
}; };
static struct clk_hw_onecell_data s500_hw_clks = { static struct clk_hw_onecell_data s500_hw_clks = {
...@@ -484,24 +492,103 @@ static struct clk_hw_onecell_data s500_hw_clks = { ...@@ -484,24 +492,103 @@ static struct clk_hw_onecell_data s500_hw_clks = {
[CLK_SPDIF] = &spdif_clk.common.hw, [CLK_SPDIF] = &spdif_clk.common.hw,
[CLK_NAND] = &nand_clk.common.hw, [CLK_NAND] = &nand_clk.common.hw,
[CLK_ECC] = &ecc_clk.common.hw, [CLK_ECC] = &ecc_clk.common.hw,
[CLK_APB] = &apb_clk.common.hw,
[CLK_DMAC] = &dmac_clk.common.hw,
[CLK_GPIO] = &gpio_clk.common.hw,
}, },
.num = CLK_NR_CLKS, .num = CLK_NR_CLKS,
}; };
static const struct owl_reset_map s500_resets[] = {
[RESET_DMAC] = { CMU_DEVRST0, BIT(0) },
[RESET_NORIF] = { CMU_DEVRST0, BIT(1) },
[RESET_DDR] = { CMU_DEVRST0, BIT(2) },
[RESET_NANDC] = { CMU_DEVRST0, BIT(3) },
[RESET_SD0] = { CMU_DEVRST0, BIT(4) },
[RESET_SD1] = { CMU_DEVRST0, BIT(5) },
[RESET_PCM1] = { CMU_DEVRST0, BIT(6) },
[RESET_DE] = { CMU_DEVRST0, BIT(7) },
[RESET_LCD] = { CMU_DEVRST0, BIT(8) },
[RESET_SD2] = { CMU_DEVRST0, BIT(9) },
[RESET_DSI] = { CMU_DEVRST0, BIT(10) },
[RESET_CSI] = { CMU_DEVRST0, BIT(11) },
[RESET_BISP] = { CMU_DEVRST0, BIT(12) },
[RESET_KEY] = { CMU_DEVRST0, BIT(14) },
[RESET_GPIO] = { CMU_DEVRST0, BIT(15) },
[RESET_AUDIO] = { CMU_DEVRST0, BIT(17) },
[RESET_PCM0] = { CMU_DEVRST0, BIT(18) },
[RESET_VDE] = { CMU_DEVRST0, BIT(19) },
[RESET_VCE] = { CMU_DEVRST0, BIT(20) },
[RESET_GPU3D] = { CMU_DEVRST0, BIT(22) },
[RESET_NIC301] = { CMU_DEVRST0, BIT(23) },
[RESET_LENS] = { CMU_DEVRST0, BIT(26) },
[RESET_PERIPHRESET] = { CMU_DEVRST0, BIT(27) },
[RESET_USB2_0] = { CMU_DEVRST1, BIT(0) },
[RESET_TVOUT] = { CMU_DEVRST1, BIT(1) },
[RESET_HDMI] = { CMU_DEVRST1, BIT(2) },
[RESET_HDCP2TX] = { CMU_DEVRST1, BIT(3) },
[RESET_UART6] = { CMU_DEVRST1, BIT(4) },
[RESET_UART0] = { CMU_DEVRST1, BIT(5) },
[RESET_UART1] = { CMU_DEVRST1, BIT(6) },
[RESET_UART2] = { CMU_DEVRST1, BIT(7) },
[RESET_SPI0] = { CMU_DEVRST1, BIT(8) },
[RESET_SPI1] = { CMU_DEVRST1, BIT(9) },
[RESET_SPI2] = { CMU_DEVRST1, BIT(10) },
[RESET_SPI3] = { CMU_DEVRST1, BIT(11) },
[RESET_I2C0] = { CMU_DEVRST1, BIT(12) },
[RESET_I2C1] = { CMU_DEVRST1, BIT(13) },
[RESET_USB3] = { CMU_DEVRST1, BIT(14) },
[RESET_UART3] = { CMU_DEVRST1, BIT(15) },
[RESET_UART4] = { CMU_DEVRST1, BIT(16) },
[RESET_UART5] = { CMU_DEVRST1, BIT(17) },
[RESET_I2C2] = { CMU_DEVRST1, BIT(18) },
[RESET_I2C3] = { CMU_DEVRST1, BIT(19) },
[RESET_ETHERNET] = { CMU_DEVRST1, BIT(20) },
[RESET_CHIPID] = { CMU_DEVRST1, BIT(21) },
[RESET_USB2_1] = { CMU_DEVRST1, BIT(22) },
[RESET_WD0RESET] = { CMU_DEVRST1, BIT(24) },
[RESET_WD1RESET] = { CMU_DEVRST1, BIT(25) },
[RESET_WD2RESET] = { CMU_DEVRST1, BIT(26) },
[RESET_WD3RESET] = { CMU_DEVRST1, BIT(27) },
[RESET_DBG0RESET] = { CMU_DEVRST1, BIT(28) },
[RESET_DBG1RESET] = { CMU_DEVRST1, BIT(29) },
[RESET_DBG2RESET] = { CMU_DEVRST1, BIT(30) },
[RESET_DBG3RESET] = { CMU_DEVRST1, BIT(31) },
};
static struct owl_clk_desc s500_clk_desc = { static struct owl_clk_desc s500_clk_desc = {
.clks = s500_clks, .clks = s500_clks,
.num_clks = ARRAY_SIZE(s500_clks), .num_clks = ARRAY_SIZE(s500_clks),
.hw_clks = &s500_hw_clks, .hw_clks = &s500_hw_clks,
.resets = s500_resets,
.num_resets = ARRAY_SIZE(s500_resets),
}; };
static int s500_clk_probe(struct platform_device *pdev) static int s500_clk_probe(struct platform_device *pdev)
{ {
struct owl_clk_desc *desc; struct owl_clk_desc *desc;
struct owl_reset *reset;
int ret;
desc = &s500_clk_desc; desc = &s500_clk_desc;
owl_clk_regmap_init(pdev, desc); owl_clk_regmap_init(pdev, desc);
reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL);
if (!reset)
return -ENOMEM;
reset->rcdev.of_node = pdev->dev.of_node;
reset->rcdev.ops = &owl_reset_ops;
reset->rcdev.nr_resets = desc->num_resets;
reset->reset_map = desc->resets;
reset->regmap = desc->regmap;
ret = devm_reset_controller_register(&pdev->dev, &reset->rcdev);
if (ret)
dev_err(&pdev->dev, "Failed to register reset controller\n");
return owl_clk_probe(&pdev->dev, desc->hw_clks); return owl_clk_probe(&pdev->dev, desc->hw_clks);
} }
......
...@@ -23,3 +23,4 @@ obj-$(CONFIG_SOC_SAM9X60) += sam9x60.o ...@@ -23,3 +23,4 @@ obj-$(CONFIG_SOC_SAM9X60) += sam9x60.o
obj-$(CONFIG_SOC_SAMA5D3) += sama5d3.o obj-$(CONFIG_SOC_SAMA5D3) += sama5d3.o
obj-$(CONFIG_SOC_SAMA5D4) += sama5d4.o obj-$(CONFIG_SOC_SAMA5D4) += sama5d4.o
obj-$(CONFIG_SOC_SAMA5D2) += sama5d2.o obj-$(CONFIG_SOC_SAMA5D2) += sama5d2.o
obj-$(CONFIG_SOC_SAMA7G5) += sama7g5.o
...@@ -160,7 +160,8 @@ static void __init at91rm9200_pmc_setup(struct device_node *np) ...@@ -160,7 +160,8 @@ static void __init at91rm9200_pmc_setup(struct device_node *np)
hw = at91_clk_register_programmable(regmap, name, hw = at91_clk_register_programmable(regmap, name,
parent_names, 4, i, parent_names, 4, i,
&at91rm9200_programmable_layout); &at91rm9200_programmable_layout,
NULL);
if (IS_ERR(hw)) if (IS_ERR(hw))
goto err_free; goto err_free;
......
...@@ -436,7 +436,8 @@ static void __init at91sam926x_pmc_setup(struct device_node *np, ...@@ -436,7 +436,8 @@ static void __init at91sam926x_pmc_setup(struct device_node *np,
hw = at91_clk_register_programmable(regmap, name, hw = at91_clk_register_programmable(regmap, name,
parent_names, 4, i, parent_names, 4, i,
&at91rm9200_programmable_layout); &at91rm9200_programmable_layout,
NULL);
if (IS_ERR(hw)) if (IS_ERR(hw))
goto err_free; goto err_free;
......
...@@ -111,7 +111,7 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np) ...@@ -111,7 +111,7 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np)
return; return;
mainxtal_name = of_clk_get_parent_name(np, i); mainxtal_name = of_clk_get_parent_name(np, i);
regmap = syscon_node_to_regmap(np); regmap = device_node_to_regmap(np);
if (IS_ERR(regmap)) if (IS_ERR(regmap))
return; return;
...@@ -181,7 +181,8 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np) ...@@ -181,7 +181,8 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np)
hw = at91_clk_register_programmable(regmap, name, hw = at91_clk_register_programmable(regmap, name,
parent_names, 5, i, parent_names, 5, i,
&at91sam9g45_programmable_layout); &at91sam9g45_programmable_layout,
NULL);
if (IS_ERR(hw)) if (IS_ERR(hw))
goto err_free; goto err_free;
......
...@@ -124,7 +124,7 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np) ...@@ -124,7 +124,7 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np)
return; return;
mainxtal_name = of_clk_get_parent_name(np, i); mainxtal_name = of_clk_get_parent_name(np, i);
regmap = syscon_node_to_regmap(np); regmap = device_node_to_regmap(np);
if (IS_ERR(regmap)) if (IS_ERR(regmap))
return; return;
...@@ -199,7 +199,8 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np) ...@@ -199,7 +199,8 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np)
hw = at91_clk_register_programmable(regmap, name, hw = at91_clk_register_programmable(regmap, name,
parent_names, 5, i, parent_names, 5, i,
&at91sam9x5_programmable_layout); &at91sam9x5_programmable_layout,
NULL);
if (IS_ERR(hw)) if (IS_ERR(hw))
goto err_free; goto err_free;
...@@ -222,7 +223,7 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np) ...@@ -222,7 +223,7 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np)
at91sam9n12_periphck[i].n, at91sam9n12_periphck[i].n,
"masterck", "masterck",
at91sam9n12_periphck[i].id, at91sam9n12_periphck[i].id,
&range); &range, INT_MIN);
if (IS_ERR(hw)) if (IS_ERR(hw))
goto err_free; goto err_free;
......
...@@ -137,7 +137,8 @@ static void __init at91sam9rl_pmc_setup(struct device_node *np) ...@@ -137,7 +137,8 @@ static void __init at91sam9rl_pmc_setup(struct device_node *np)
hw = at91_clk_register_programmable(regmap, name, hw = at91_clk_register_programmable(regmap, name,
parent_names, 5, i, parent_names, 5, i,
&at91rm9200_programmable_layout); &at91rm9200_programmable_layout,
NULL);
if (IS_ERR(hw)) if (IS_ERR(hw))
goto err_free; goto err_free;
......
...@@ -226,7 +226,8 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np, ...@@ -226,7 +226,8 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
hw = at91_clk_register_programmable(regmap, name, hw = at91_clk_register_programmable(regmap, name,
parent_names, 5, i, parent_names, 5, i,
&at91sam9x5_programmable_layout); &at91sam9x5_programmable_layout,
NULL);
if (IS_ERR(hw)) if (IS_ERR(hw))
goto err_free; goto err_free;
...@@ -257,7 +258,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np, ...@@ -257,7 +258,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
at91sam9x5_periphck[i].n, at91sam9x5_periphck[i].n,
"masterck", "masterck",
at91sam9x5_periphck[i].id, at91sam9x5_periphck[i].id,
&range); &range, INT_MIN);
if (IS_ERR(hw)) if (IS_ERR(hw))
goto err_free; goto err_free;
...@@ -270,7 +271,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np, ...@@ -270,7 +271,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
extra_pcks[i].n, extra_pcks[i].n,
"masterck", "masterck",
extra_pcks[i].id, extra_pcks[i].id,
&range); &range, INT_MIN);
if (IS_ERR(hw)) if (IS_ERR(hw))
goto err_free; goto err_free;
......
...@@ -18,18 +18,17 @@ ...@@ -18,18 +18,17 @@
#define GENERATED_MAX_DIV 255 #define GENERATED_MAX_DIV 255
#define GCK_INDEX_DT_AUDIO_PLL 5
struct clk_generated { struct clk_generated {
struct clk_hw hw; struct clk_hw hw;
struct regmap *regmap; struct regmap *regmap;
struct clk_range range; struct clk_range range;
spinlock_t *lock; spinlock_t *lock;
u32 *mux_table;
u32 id; u32 id;
u32 gckdiv; u32 gckdiv;
const struct clk_pcr_layout *layout; const struct clk_pcr_layout *layout;
u8 parent_id; u8 parent_id;
bool audio_pll_allowed; int chg_pid;
}; };
#define to_clk_generated(hw) \ #define to_clk_generated(hw) \
...@@ -83,7 +82,7 @@ static int clk_generated_is_enabled(struct clk_hw *hw) ...@@ -83,7 +82,7 @@ static int clk_generated_is_enabled(struct clk_hw *hw)
regmap_read(gck->regmap, gck->layout->offset, &status); regmap_read(gck->regmap, gck->layout->offset, &status);
spin_unlock_irqrestore(gck->lock, flags); spin_unlock_irqrestore(gck->lock, flags);
return status & AT91_PMC_PCR_GCKEN ? 1 : 0; return !!(status & AT91_PMC_PCR_GCKEN);
} }
static unsigned long static unsigned long
...@@ -109,7 +108,7 @@ static void clk_generated_best_diff(struct clk_rate_request *req, ...@@ -109,7 +108,7 @@ static void clk_generated_best_diff(struct clk_rate_request *req,
tmp_rate = parent_rate / div; tmp_rate = parent_rate / div;
tmp_diff = abs(req->rate - tmp_rate); tmp_diff = abs(req->rate - tmp_rate);
if (*best_diff < 0 || *best_diff > tmp_diff) { if (*best_diff < 0 || *best_diff >= tmp_diff) {
*best_rate = tmp_rate; *best_rate = tmp_rate;
*best_diff = tmp_diff; *best_diff = tmp_diff;
req->best_parent_rate = parent_rate; req->best_parent_rate = parent_rate;
...@@ -129,7 +128,10 @@ static int clk_generated_determine_rate(struct clk_hw *hw, ...@@ -129,7 +128,10 @@ static int clk_generated_determine_rate(struct clk_hw *hw,
int i; int i;
u32 div; u32 div;
for (i = 0; i < clk_hw_get_num_parents(hw) - 1; i++) { for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
if (gck->chg_pid == i)
continue;
parent = clk_hw_get_parent_by_index(hw, i); parent = clk_hw_get_parent_by_index(hw, i);
if (!parent) if (!parent)
continue; continue;
...@@ -161,16 +163,17 @@ static int clk_generated_determine_rate(struct clk_hw *hw, ...@@ -161,16 +163,17 @@ static int clk_generated_determine_rate(struct clk_hw *hw,
* that the only clks able to modify gck rate are those of audio IPs. * that the only clks able to modify gck rate are those of audio IPs.
*/ */
if (!gck->audio_pll_allowed) if (gck->chg_pid < 0)
goto end; goto end;
parent = clk_hw_get_parent_by_index(hw, GCK_INDEX_DT_AUDIO_PLL); parent = clk_hw_get_parent_by_index(hw, gck->chg_pid);
if (!parent) if (!parent)
goto end; goto end;
for (div = 1; div < GENERATED_MAX_DIV + 2; div++) { for (div = 1; div < GENERATED_MAX_DIV + 2; div++) {
req_parent.rate = req->rate * div; req_parent.rate = req->rate * div;
__clk_determine_rate(parent, &req_parent); if (__clk_determine_rate(parent, &req_parent))
continue;
clk_generated_best_diff(req, parent, req_parent.rate, div, clk_generated_best_diff(req, parent, req_parent.rate, div,
&best_diff, &best_rate); &best_diff, &best_rate);
...@@ -184,8 +187,8 @@ static int clk_generated_determine_rate(struct clk_hw *hw, ...@@ -184,8 +187,8 @@ static int clk_generated_determine_rate(struct clk_hw *hw,
__clk_get_name((req->best_parent_hw)->clk), __clk_get_name((req->best_parent_hw)->clk),
req->best_parent_rate); req->best_parent_rate);
if (best_rate < 0) if (best_rate < 0 || (gck->range.max && best_rate > gck->range.max))
return best_rate; return -EINVAL;
req->rate = best_rate; req->rate = best_rate;
return 0; return 0;
...@@ -199,7 +202,11 @@ static int clk_generated_set_parent(struct clk_hw *hw, u8 index) ...@@ -199,7 +202,11 @@ static int clk_generated_set_parent(struct clk_hw *hw, u8 index)
if (index >= clk_hw_get_num_parents(hw)) if (index >= clk_hw_get_num_parents(hw))
return -EINVAL; return -EINVAL;
gck->parent_id = index; if (gck->mux_table)
gck->parent_id = clk_mux_index_to_val(gck->mux_table, 0, index);
else
gck->parent_id = index;
return 0; return 0;
} }
...@@ -271,8 +278,9 @@ struct clk_hw * __init ...@@ -271,8 +278,9 @@ struct clk_hw * __init
at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,
const struct clk_pcr_layout *layout, const struct clk_pcr_layout *layout,
const char *name, const char **parent_names, const char *name, const char **parent_names,
u8 num_parents, u8 id, bool pll_audio, u32 *mux_table, u8 num_parents, u8 id,
const struct clk_range *range) const struct clk_range *range,
int chg_pid)
{ {
struct clk_generated *gck; struct clk_generated *gck;
struct clk_init_data init; struct clk_init_data init;
...@@ -287,16 +295,18 @@ at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, ...@@ -287,16 +295,18 @@ at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,
init.ops = &generated_ops; init.ops = &generated_ops;
init.parent_names = parent_names; init.parent_names = parent_names;
init.num_parents = num_parents; init.num_parents = num_parents;
init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE | init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
CLK_SET_RATE_PARENT; if (chg_pid >= 0)
init.flags |= CLK_SET_RATE_PARENT;
gck->id = id; gck->id = id;
gck->hw.init = &init; gck->hw.init = &init;
gck->regmap = regmap; gck->regmap = regmap;
gck->lock = lock; gck->lock = lock;
gck->range = *range; gck->range = *range;
gck->audio_pll_allowed = pll_audio; gck->chg_pid = chg_pid;
gck->layout = layout; gck->layout = layout;
gck->mux_table = mux_table;
clk_generated_startup(gck); clk_generated_startup(gck);
hw = &gck->hw; hw = &gck->hw;
......
...@@ -175,7 +175,7 @@ static bool clk_main_rc_osc_ready(struct regmap *regmap) ...@@ -175,7 +175,7 @@ static bool clk_main_rc_osc_ready(struct regmap *regmap)
regmap_read(regmap, AT91_PMC_SR, &status); regmap_read(regmap, AT91_PMC_SR, &status);
return status & AT91_PMC_MOSCRCS; return !!(status & AT91_PMC_MOSCRCS);
} }
static int clk_main_rc_osc_prepare(struct clk_hw *hw) static int clk_main_rc_osc_prepare(struct clk_hw *hw)
...@@ -336,7 +336,7 @@ static int clk_rm9200_main_is_prepared(struct clk_hw *hw) ...@@ -336,7 +336,7 @@ static int clk_rm9200_main_is_prepared(struct clk_hw *hw)
regmap_read(clkmain->regmap, AT91_CKGR_MCFR, &status); regmap_read(clkmain->regmap, AT91_CKGR_MCFR, &status);
return status & AT91_PMC_MAINRDY ? 1 : 0; return !!(status & AT91_PMC_MAINRDY);
} }
static unsigned long clk_rm9200_main_recalc_rate(struct clk_hw *hw, static unsigned long clk_rm9200_main_recalc_rate(struct clk_hw *hw,
...@@ -398,7 +398,7 @@ static inline bool clk_sam9x5_main_ready(struct regmap *regmap) ...@@ -398,7 +398,7 @@ static inline bool clk_sam9x5_main_ready(struct regmap *regmap)
regmap_read(regmap, AT91_PMC_SR, &status); regmap_read(regmap, AT91_PMC_SR, &status);
return status & AT91_PMC_MOSCSELS ? 1 : 0; return !!(status & AT91_PMC_MOSCSELS);
} }
static int clk_sam9x5_main_prepare(struct clk_hw *hw) static int clk_sam9x5_main_prepare(struct clk_hw *hw)
......
...@@ -17,30 +17,49 @@ ...@@ -17,30 +17,49 @@
#define MASTER_DIV_SHIFT 8 #define MASTER_DIV_SHIFT 8
#define MASTER_DIV_MASK 0x3 #define MASTER_DIV_MASK 0x3
#define PMC_MCR 0x30
#define PMC_MCR_ID_MSK GENMASK(3, 0)
#define PMC_MCR_CMD BIT(7)
#define PMC_MCR_DIV GENMASK(10, 8)
#define PMC_MCR_CSS GENMASK(20, 16)
#define PMC_MCR_CSS_SHIFT (16)
#define PMC_MCR_EN BIT(28)
#define PMC_MCR_ID(x) ((x) & PMC_MCR_ID_MSK)
#define MASTER_MAX_ID 4
#define to_clk_master(hw) container_of(hw, struct clk_master, hw) #define to_clk_master(hw) container_of(hw, struct clk_master, hw)
struct clk_master { struct clk_master {
struct clk_hw hw; struct clk_hw hw;
struct regmap *regmap; struct regmap *regmap;
spinlock_t *lock;
const struct clk_master_layout *layout; const struct clk_master_layout *layout;
const struct clk_master_characteristics *characteristics; const struct clk_master_characteristics *characteristics;
u32 *mux_table;
u32 mckr; u32 mckr;
int chg_pid;
u8 id;
u8 parent;
u8 div;
}; };
static inline bool clk_master_ready(struct regmap *regmap) static inline bool clk_master_ready(struct clk_master *master)
{ {
unsigned int bit = master->id ? AT91_PMC_MCKXRDY : AT91_PMC_MCKRDY;
unsigned int status; unsigned int status;
regmap_read(regmap, AT91_PMC_SR, &status); regmap_read(master->regmap, AT91_PMC_SR, &status);
return status & AT91_PMC_MCKRDY ? 1 : 0; return !!(status & bit);
} }
static int clk_master_prepare(struct clk_hw *hw) static int clk_master_prepare(struct clk_hw *hw)
{ {
struct clk_master *master = to_clk_master(hw); struct clk_master *master = to_clk_master(hw);
while (!clk_master_ready(master->regmap)) while (!clk_master_ready(master))
cpu_relax(); cpu_relax();
return 0; return 0;
...@@ -50,7 +69,7 @@ static int clk_master_is_prepared(struct clk_hw *hw) ...@@ -50,7 +69,7 @@ static int clk_master_is_prepared(struct clk_hw *hw)
{ {
struct clk_master *master = to_clk_master(hw); struct clk_master *master = to_clk_master(hw);
return clk_master_ready(master->regmap); return clk_master_ready(master);
} }
static unsigned long clk_master_recalc_rate(struct clk_hw *hw, static unsigned long clk_master_recalc_rate(struct clk_hw *hw,
...@@ -143,6 +162,287 @@ at91_clk_register_master(struct regmap *regmap, ...@@ -143,6 +162,287 @@ at91_clk_register_master(struct regmap *regmap,
return hw; return hw;
} }
static unsigned long
clk_sama7g5_master_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_master *master = to_clk_master(hw);
return DIV_ROUND_CLOSEST_ULL(parent_rate, (1 << master->div));
}
static void clk_sama7g5_master_best_diff(struct clk_rate_request *req,
struct clk_hw *parent,
unsigned long parent_rate,
long *best_rate,
long *best_diff,
u32 div)
{
unsigned long tmp_rate, tmp_diff;
if (div == MASTER_PRES_MAX)
tmp_rate = parent_rate / 3;
else
tmp_rate = parent_rate >> div;
tmp_diff = abs(req->rate - tmp_rate);
if (*best_diff < 0 || *best_diff >= tmp_diff) {
*best_rate = tmp_rate;
*best_diff = tmp_diff;
req->best_parent_rate = parent_rate;
req->best_parent_hw = parent;
}
}
static int clk_sama7g5_master_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
struct clk_master *master = to_clk_master(hw);
struct clk_rate_request req_parent = *req;
struct clk_hw *parent;
long best_rate = LONG_MIN, best_diff = LONG_MIN;
unsigned long parent_rate;
unsigned int div, i;
/* First: check the dividers of MCR. */
for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
parent = clk_hw_get_parent_by_index(hw, i);
if (!parent)
continue;
parent_rate = clk_hw_get_rate(parent);
if (!parent_rate)
continue;
for (div = 0; div < MASTER_PRES_MAX + 1; div++) {
clk_sama7g5_master_best_diff(req, parent, parent_rate,
&best_rate, &best_diff,
div);
if (!best_diff)
break;
}
if (!best_diff)
break;
}
/* Second: try to request rate form changeable parent. */
if (master->chg_pid < 0)
goto end;
parent = clk_hw_get_parent_by_index(hw, master->chg_pid);
if (!parent)
goto end;
for (div = 0; div < MASTER_PRES_MAX + 1; div++) {
if (div == MASTER_PRES_MAX)
req_parent.rate = req->rate * 3;
else
req_parent.rate = req->rate << div;
if (__clk_determine_rate(parent, &req_parent))
continue;
clk_sama7g5_master_best_diff(req, parent, req_parent.rate,
&best_rate, &best_diff, div);
if (!best_diff)
break;
}
end:
pr_debug("MCK: %s, best_rate = %ld, parent clk: %s @ %ld\n",
__func__, best_rate,
__clk_get_name((req->best_parent_hw)->clk),
req->best_parent_rate);
if (best_rate < 0)
return -EINVAL;
req->rate = best_rate;
return 0;
}
static u8 clk_sama7g5_master_get_parent(struct clk_hw *hw)
{
struct clk_master *master = to_clk_master(hw);
unsigned long flags;
u8 index;
spin_lock_irqsave(master->lock, flags);
index = clk_mux_val_to_index(&master->hw, master->mux_table, 0,
master->parent);
spin_unlock_irqrestore(master->lock, flags);
return index;
}
static int clk_sama7g5_master_set_parent(struct clk_hw *hw, u8 index)
{
struct clk_master *master = to_clk_master(hw);
unsigned long flags;
if (index >= clk_hw_get_num_parents(hw))
return -EINVAL;
spin_lock_irqsave(master->lock, flags);
master->parent = clk_mux_index_to_val(master->mux_table, 0, index);
spin_unlock_irqrestore(master->lock, flags);
return 0;
}
static int clk_sama7g5_master_enable(struct clk_hw *hw)
{
struct clk_master *master = to_clk_master(hw);
unsigned long flags;
unsigned int val, cparent;
spin_lock_irqsave(master->lock, flags);
regmap_write(master->regmap, PMC_MCR, PMC_MCR_ID(master->id));
regmap_read(master->regmap, PMC_MCR, &val);
regmap_update_bits(master->regmap, PMC_MCR,
PMC_MCR_EN | PMC_MCR_CSS | PMC_MCR_DIV |
PMC_MCR_CMD | PMC_MCR_ID_MSK,
PMC_MCR_EN | (master->parent << PMC_MCR_CSS_SHIFT) |
(master->div << MASTER_DIV_SHIFT) |
PMC_MCR_CMD | PMC_MCR_ID(master->id));
cparent = (val & PMC_MCR_CSS) >> PMC_MCR_CSS_SHIFT;
/* Wait here only if parent is being changed. */
while ((cparent != master->parent) && !clk_master_ready(master))
cpu_relax();
spin_unlock_irqrestore(master->lock, flags);
return 0;
}
static void clk_sama7g5_master_disable(struct clk_hw *hw)
{
struct clk_master *master = to_clk_master(hw);
unsigned long flags;
spin_lock_irqsave(master->lock, flags);
regmap_write(master->regmap, PMC_MCR, master->id);
regmap_update_bits(master->regmap, PMC_MCR,
PMC_MCR_EN | PMC_MCR_CMD | PMC_MCR_ID_MSK,
PMC_MCR_CMD | PMC_MCR_ID(master->id));
spin_unlock_irqrestore(master->lock, flags);
}
static int clk_sama7g5_master_is_enabled(struct clk_hw *hw)
{
struct clk_master *master = to_clk_master(hw);
unsigned long flags;
unsigned int val;
spin_lock_irqsave(master->lock, flags);
regmap_write(master->regmap, PMC_MCR, master->id);
regmap_read(master->regmap, PMC_MCR, &val);
spin_unlock_irqrestore(master->lock, flags);
return !!(val & PMC_MCR_EN);
}
static int clk_sama7g5_master_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_master *master = to_clk_master(hw);
unsigned long div, flags;
div = DIV_ROUND_CLOSEST(parent_rate, rate);
if ((div > (1 << (MASTER_PRES_MAX - 1))) || (div & (div - 1)))
return -EINVAL;
if (div == 3)
div = MASTER_PRES_MAX;
else
div = ffs(div) - 1;
spin_lock_irqsave(master->lock, flags);
master->div = div;
spin_unlock_irqrestore(master->lock, flags);
return 0;
}
static const struct clk_ops sama7g5_master_ops = {
.enable = clk_sama7g5_master_enable,
.disable = clk_sama7g5_master_disable,
.is_enabled = clk_sama7g5_master_is_enabled,
.recalc_rate = clk_sama7g5_master_recalc_rate,
.determine_rate = clk_sama7g5_master_determine_rate,
.set_rate = clk_sama7g5_master_set_rate,
.get_parent = clk_sama7g5_master_get_parent,
.set_parent = clk_sama7g5_master_set_parent,
};
struct clk_hw * __init
at91_clk_sama7g5_register_master(struct regmap *regmap,
const char *name, int num_parents,
const char **parent_names,
u32 *mux_table,
spinlock_t *lock, u8 id,
bool critical, int chg_pid)
{
struct clk_master *master;
struct clk_hw *hw;
struct clk_init_data init;
unsigned long flags;
unsigned int val;
int ret;
if (!name || !num_parents || !parent_names || !mux_table ||
!lock || id > MASTER_MAX_ID)
return ERR_PTR(-EINVAL);
master = kzalloc(sizeof(*master), GFP_KERNEL);
if (!master)
return ERR_PTR(-ENOMEM);
init.name = name;
init.ops = &sama7g5_master_ops;
init.parent_names = parent_names;
init.num_parents = num_parents;
init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
if (chg_pid >= 0)
init.flags |= CLK_SET_RATE_PARENT;
if (critical)
init.flags |= CLK_IS_CRITICAL;
master->hw.init = &init;
master->regmap = regmap;
master->id = id;
master->chg_pid = chg_pid;
master->lock = lock;
master->mux_table = mux_table;
spin_lock_irqsave(master->lock, flags);
regmap_write(master->regmap, PMC_MCR, master->id);
regmap_read(master->regmap, PMC_MCR, &val);
master->parent = (val & PMC_MCR_CSS) >> PMC_MCR_CSS_SHIFT;
master->div = (val & PMC_MCR_DIV) >> MASTER_DIV_SHIFT;
spin_unlock_irqrestore(master->lock, flags);
hw = &master->hw;
ret = clk_hw_register(NULL, &master->hw);
if (ret) {
kfree(master);
hw = ERR_PTR(ret);
}
return hw;
}
const struct clk_master_layout at91rm9200_master_layout = { const struct clk_master_layout at91rm9200_master_layout = {
.mask = 0x31F, .mask = 0x31F,
.pres_shift = 2, .pres_shift = 2,
......
...@@ -38,6 +38,7 @@ struct clk_sam9x5_peripheral { ...@@ -38,6 +38,7 @@ struct clk_sam9x5_peripheral {
u32 div; u32 div;
const struct clk_pcr_layout *layout; const struct clk_pcr_layout *layout;
bool auto_div; bool auto_div;
int chg_pid;
}; };
#define to_clk_sam9x5_peripheral(hw) \ #define to_clk_sam9x5_peripheral(hw) \
...@@ -208,7 +209,7 @@ static int clk_sam9x5_peripheral_is_enabled(struct clk_hw *hw) ...@@ -208,7 +209,7 @@ static int clk_sam9x5_peripheral_is_enabled(struct clk_hw *hw)
regmap_read(periph->regmap, periph->layout->offset, &status); regmap_read(periph->regmap, periph->layout->offset, &status);
spin_unlock_irqrestore(periph->lock, flags); spin_unlock_irqrestore(periph->lock, flags);
return status & AT91_PMC_PCR_EN ? 1 : 0; return !!(status & AT91_PMC_PCR_EN);
} }
static unsigned long static unsigned long
...@@ -238,6 +239,87 @@ clk_sam9x5_peripheral_recalc_rate(struct clk_hw *hw, ...@@ -238,6 +239,87 @@ clk_sam9x5_peripheral_recalc_rate(struct clk_hw *hw,
return parent_rate >> periph->div; return parent_rate >> periph->div;
} }
static void clk_sam9x5_peripheral_best_diff(struct clk_rate_request *req,
struct clk_hw *parent,
unsigned long parent_rate,
u32 shift, long *best_diff,
long *best_rate)
{
unsigned long tmp_rate = parent_rate >> shift;
unsigned long tmp_diff = abs(req->rate - tmp_rate);
if (*best_diff < 0 || *best_diff >= tmp_diff) {
*best_rate = tmp_rate;
*best_diff = tmp_diff;
req->best_parent_rate = parent_rate;
req->best_parent_hw = parent;
}
}
static int clk_sam9x5_peripheral_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw);
struct clk_hw *parent = clk_hw_get_parent(hw);
struct clk_rate_request req_parent = *req;
unsigned long parent_rate = clk_hw_get_rate(parent);
unsigned long tmp_rate;
long best_rate = LONG_MIN;
long best_diff = LONG_MIN;
u32 shift;
if (periph->id < PERIPHERAL_ID_MIN || !periph->range.max)
return parent_rate;
/* Fist step: check the available dividers. */
for (shift = 0; shift <= PERIPHERAL_MAX_SHIFT; shift++) {
tmp_rate = parent_rate >> shift;
if (periph->range.max && tmp_rate > periph->range.max)
continue;
clk_sam9x5_peripheral_best_diff(req, parent, parent_rate,
shift, &best_diff, &best_rate);
if (!best_diff || best_rate <= req->rate)
break;
}
if (periph->chg_pid < 0)
goto end;
/* Step two: try to request rate from parent. */
parent = clk_hw_get_parent_by_index(hw, periph->chg_pid);
if (!parent)
goto end;
for (shift = 0; shift <= PERIPHERAL_MAX_SHIFT; shift++) {
req_parent.rate = req->rate << shift;
if (__clk_determine_rate(parent, &req_parent))
continue;
clk_sam9x5_peripheral_best_diff(req, parent, req_parent.rate,
shift, &best_diff, &best_rate);
if (!best_diff)
break;
}
end:
if (best_rate < 0 ||
(periph->range.max && best_rate > periph->range.max))
return -EINVAL;
pr_debug("PCK: %s, best_rate = %ld, parent clk: %s @ %ld\n",
__func__, best_rate,
__clk_get_name((req->best_parent_hw)->clk),
req->best_parent_rate);
req->rate = best_rate;
return 0;
}
static long clk_sam9x5_peripheral_round_rate(struct clk_hw *hw, static long clk_sam9x5_peripheral_round_rate(struct clk_hw *hw,
unsigned long rate, unsigned long rate,
unsigned long *parent_rate) unsigned long *parent_rate)
...@@ -320,11 +402,21 @@ static const struct clk_ops sam9x5_peripheral_ops = { ...@@ -320,11 +402,21 @@ static const struct clk_ops sam9x5_peripheral_ops = {
.set_rate = clk_sam9x5_peripheral_set_rate, .set_rate = clk_sam9x5_peripheral_set_rate,
}; };
static const struct clk_ops sam9x5_peripheral_chg_ops = {
.enable = clk_sam9x5_peripheral_enable,
.disable = clk_sam9x5_peripheral_disable,
.is_enabled = clk_sam9x5_peripheral_is_enabled,
.recalc_rate = clk_sam9x5_peripheral_recalc_rate,
.determine_rate = clk_sam9x5_peripheral_determine_rate,
.set_rate = clk_sam9x5_peripheral_set_rate,
};
struct clk_hw * __init struct clk_hw * __init
at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock, at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
const struct clk_pcr_layout *layout, const struct clk_pcr_layout *layout,
const char *name, const char *parent_name, const char *name, const char *parent_name,
u32 id, const struct clk_range *range) u32 id, const struct clk_range *range,
int chg_pid)
{ {
struct clk_sam9x5_peripheral *periph; struct clk_sam9x5_peripheral *periph;
struct clk_init_data init; struct clk_init_data init;
...@@ -339,10 +431,16 @@ at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock, ...@@ -339,10 +431,16 @@ at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
init.name = name; init.name = name;
init.ops = &sam9x5_peripheral_ops; init.parent_names = &parent_name;
init.parent_names = (parent_name ? &parent_name : NULL); init.num_parents = 1;
init.num_parents = (parent_name ? 1 : 0); if (chg_pid < 0) {
init.flags = 0; init.flags = 0;
init.ops = &sam9x5_peripheral_ops;
} else {
init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
CLK_SET_RATE_PARENT;
init.ops = &sam9x5_peripheral_chg_ops;
}
periph->id = id; periph->id = id;
periph->hw.init = &init; periph->hw.init = &init;
...@@ -353,6 +451,7 @@ at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock, ...@@ -353,6 +451,7 @@ at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
periph->auto_div = true; periph->auto_div = true;
periph->layout = layout; periph->layout = layout;
periph->range = *range; periph->range = *range;
periph->chg_pid = chg_pid;
hw = &periph->hw; hw = &periph->hw;
ret = clk_hw_register(NULL, &periph->hw); ret = clk_hw_register(NULL, &periph->hw);
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
struct clk_programmable { struct clk_programmable {
struct clk_hw hw; struct clk_hw hw;
struct regmap *regmap; struct regmap *regmap;
u32 *mux_table;
u8 id; u8 id;
const struct clk_programmable_layout *layout; const struct clk_programmable_layout *layout;
}; };
...@@ -108,6 +109,9 @@ static int clk_programmable_set_parent(struct clk_hw *hw, u8 index) ...@@ -108,6 +109,9 @@ static int clk_programmable_set_parent(struct clk_hw *hw, u8 index)
if (layout->have_slck_mck) if (layout->have_slck_mck)
mask |= AT91_PMC_CSSMCK_MCK; mask |= AT91_PMC_CSSMCK_MCK;
if (prog->mux_table)
pckr = clk_mux_index_to_val(prog->mux_table, 0, index);
if (index > layout->css_mask) { if (index > layout->css_mask) {
if (index > PROG_MAX_RM9200_CSS && !layout->have_slck_mck) if (index > PROG_MAX_RM9200_CSS && !layout->have_slck_mck)
return -EINVAL; return -EINVAL;
...@@ -134,6 +138,9 @@ static u8 clk_programmable_get_parent(struct clk_hw *hw) ...@@ -134,6 +138,9 @@ static u8 clk_programmable_get_parent(struct clk_hw *hw)
if (layout->have_slck_mck && (pckr & AT91_PMC_CSSMCK_MCK) && !ret) if (layout->have_slck_mck && (pckr & AT91_PMC_CSSMCK_MCK) && !ret)
ret = PROG_MAX_RM9200_CSS + 1; ret = PROG_MAX_RM9200_CSS + 1;
if (prog->mux_table)
ret = clk_mux_val_to_index(&prog->hw, prog->mux_table, 0, ret);
return ret; return ret;
} }
...@@ -182,7 +189,8 @@ struct clk_hw * __init ...@@ -182,7 +189,8 @@ struct clk_hw * __init
at91_clk_register_programmable(struct regmap *regmap, at91_clk_register_programmable(struct regmap *regmap,
const char *name, const char **parent_names, const char *name, const char **parent_names,
u8 num_parents, u8 id, u8 num_parents, u8 id,
const struct clk_programmable_layout *layout) const struct clk_programmable_layout *layout,
u32 *mux_table)
{ {
struct clk_programmable *prog; struct clk_programmable *prog;
struct clk_hw *hw; struct clk_hw *hw;
...@@ -206,6 +214,7 @@ at91_clk_register_programmable(struct regmap *regmap, ...@@ -206,6 +214,7 @@ at91_clk_register_programmable(struct regmap *regmap,
prog->layout = layout; prog->layout = layout;
prog->hw.init = &init; prog->hw.init = &init;
prog->regmap = regmap; prog->regmap = regmap;
prog->mux_table = mux_table;
hw = &prog->hw; hw = &prog->hw;
ret = clk_hw_register(NULL, &prog->hw); ret = clk_hw_register(NULL, &prog->hw);
......
This diff is collapsed.
...@@ -34,7 +34,7 @@ static inline bool clk_system_ready(struct regmap *regmap, int id) ...@@ -34,7 +34,7 @@ static inline bool clk_system_ready(struct regmap *regmap, int id)
regmap_read(regmap, AT91_PMC_SR, &status); regmap_read(regmap, AT91_PMC_SR, &status);
return status & (1 << id) ? 1 : 0; return !!(status & (1 << id));
} }
static int clk_system_prepare(struct clk_hw *hw) static int clk_system_prepare(struct clk_hw *hw)
...@@ -74,7 +74,7 @@ static int clk_system_is_prepared(struct clk_hw *hw) ...@@ -74,7 +74,7 @@ static int clk_system_is_prepared(struct clk_hw *hw)
regmap_read(sys->regmap, AT91_PMC_SR, &status); regmap_read(sys->regmap, AT91_PMC_SR, &status);
return status & (1 << sys->id) ? 1 : 0; return !!(status & (1 << sys->id));
} }
static const struct clk_ops system_ops = { static const struct clk_ops system_ops = {
......
...@@ -120,9 +120,11 @@ static const struct clk_ops utmi_ops = { ...@@ -120,9 +120,11 @@ static const struct clk_ops utmi_ops = {
.recalc_rate = clk_utmi_recalc_rate, .recalc_rate = clk_utmi_recalc_rate,
}; };
struct clk_hw * __init static struct clk_hw * __init
at91_clk_register_utmi(struct regmap *regmap_pmc, struct regmap *regmap_sfr, at91_clk_register_utmi_internal(struct regmap *regmap_pmc,
const char *name, const char *parent_name) struct regmap *regmap_sfr,
const char *name, const char *parent_name,
const struct clk_ops *ops, unsigned long flags)
{ {
struct clk_utmi *utmi; struct clk_utmi *utmi;
struct clk_hw *hw; struct clk_hw *hw;
...@@ -134,10 +136,10 @@ at91_clk_register_utmi(struct regmap *regmap_pmc, struct regmap *regmap_sfr, ...@@ -134,10 +136,10 @@ at91_clk_register_utmi(struct regmap *regmap_pmc, struct regmap *regmap_sfr,
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
init.name = name; init.name = name;
init.ops = &utmi_ops; init.ops = ops;
init.parent_names = parent_name ? &parent_name : NULL; init.parent_names = parent_name ? &parent_name : NULL;
init.num_parents = parent_name ? 1 : 0; init.num_parents = parent_name ? 1 : 0;
init.flags = CLK_SET_RATE_GATE; init.flags = flags;
utmi->hw.init = &init; utmi->hw.init = &init;
utmi->regmap_pmc = regmap_pmc; utmi->regmap_pmc = regmap_pmc;
...@@ -152,3 +154,94 @@ at91_clk_register_utmi(struct regmap *regmap_pmc, struct regmap *regmap_sfr, ...@@ -152,3 +154,94 @@ at91_clk_register_utmi(struct regmap *regmap_pmc, struct regmap *regmap_sfr,
return hw; return hw;
} }
struct clk_hw * __init
at91_clk_register_utmi(struct regmap *regmap_pmc, struct regmap *regmap_sfr,
const char *name, const char *parent_name)
{
return at91_clk_register_utmi_internal(regmap_pmc, regmap_sfr, name,
parent_name, &utmi_ops, CLK_SET_RATE_GATE);
}
static int clk_utmi_sama7g5_prepare(struct clk_hw *hw)
{
struct clk_utmi *utmi = to_clk_utmi(hw);
struct clk_hw *hw_parent;
unsigned long parent_rate;
unsigned int val;
hw_parent = clk_hw_get_parent(hw);
parent_rate = clk_hw_get_rate(hw_parent);
switch (parent_rate) {
case 16000000:
val = 0;
break;
case 20000000:
val = 2;
break;
case 24000000:
val = 3;
break;
case 32000000:
val = 5;
break;
default:
pr_err("UTMICK: unsupported main_xtal rate\n");
return -EINVAL;
}
regmap_write(utmi->regmap_pmc, AT91_PMC_XTALF, val);
return 0;
}
static int clk_utmi_sama7g5_is_prepared(struct clk_hw *hw)
{
struct clk_utmi *utmi = to_clk_utmi(hw);
struct clk_hw *hw_parent;
unsigned long parent_rate;
unsigned int val;
hw_parent = clk_hw_get_parent(hw);
parent_rate = clk_hw_get_rate(hw_parent);
regmap_read(utmi->regmap_pmc, AT91_PMC_XTALF, &val);
switch (val & 0x7) {
case 0:
if (parent_rate == 16000000)
return 1;
break;
case 2:
if (parent_rate == 20000000)
return 1;
break;
case 3:
if (parent_rate == 24000000)
return 1;
break;
case 5:
if (parent_rate == 32000000)
return 1;
break;
default:
break;
}
return 0;
}
static const struct clk_ops sama7g5_utmi_ops = {
.prepare = clk_utmi_sama7g5_prepare,
.is_prepared = clk_utmi_sama7g5_is_prepared,
.recalc_rate = clk_utmi_recalc_rate,
};
struct clk_hw * __init
at91_clk_sama7g5_register_utmi(struct regmap *regmap_pmc, const char *name,
const char *parent_name)
{
return at91_clk_register_utmi_internal(regmap_pmc, NULL, name,
parent_name, &sama7g5_utmi_ops, 0);
}
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
#define SYSTEM_MAX_ID 31 #define SYSTEM_MAX_ID 31
#define GCK_INDEX_DT_AUDIO_PLL 5
#ifdef CONFIG_HAVE_AT91_AUDIO_PLL #ifdef CONFIG_HAVE_AT91_AUDIO_PLL
static void __init of_sama5d2_clk_audio_pll_frac_setup(struct device_node *np) static void __init of_sama5d2_clk_audio_pll_frac_setup(struct device_node *np)
{ {
...@@ -135,7 +137,7 @@ static void __init of_sama5d2_clk_generated_setup(struct device_node *np) ...@@ -135,7 +137,7 @@ static void __init of_sama5d2_clk_generated_setup(struct device_node *np)
return; return;
for_each_child_of_node(np, gcknp) { for_each_child_of_node(np, gcknp) {
bool pll_audio = false; int chg_pid = INT_MIN;
if (of_property_read_u32(gcknp, "reg", &id)) if (of_property_read_u32(gcknp, "reg", &id))
continue; continue;
...@@ -152,12 +154,13 @@ static void __init of_sama5d2_clk_generated_setup(struct device_node *np) ...@@ -152,12 +154,13 @@ static void __init of_sama5d2_clk_generated_setup(struct device_node *np)
if (of_device_is_compatible(np, "atmel,sama5d2-clk-generated") && if (of_device_is_compatible(np, "atmel,sama5d2-clk-generated") &&
(id == GCK_ID_I2S0 || id == GCK_ID_I2S1 || (id == GCK_ID_I2S0 || id == GCK_ID_I2S1 ||
id == GCK_ID_CLASSD)) id == GCK_ID_CLASSD))
pll_audio = true; chg_pid = GCK_INDEX_DT_AUDIO_PLL;
hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
&dt_pcr_layout, name, &dt_pcr_layout, name,
parent_names, num_parents, parent_names, NULL,
id, pll_audio, &range); num_parents, id, &range,
chg_pid);
if (IS_ERR(hw)) if (IS_ERR(hw))
continue; continue;
...@@ -460,7 +463,8 @@ of_at91_clk_periph_setup(struct device_node *np, u8 type) ...@@ -460,7 +463,8 @@ of_at91_clk_periph_setup(struct device_node *np, u8 type)
&dt_pcr_layout, &dt_pcr_layout,
name, name,
parent_name, parent_name,
id, &range); id, &range,
INT_MIN);
} }
if (IS_ERR(hw)) if (IS_ERR(hw))
...@@ -673,7 +677,8 @@ CLK_OF_DECLARE(at91sam9x5_clk_plldiv, "atmel,at91sam9x5-clk-plldiv", ...@@ -673,7 +677,8 @@ CLK_OF_DECLARE(at91sam9x5_clk_plldiv, "atmel,at91sam9x5-clk-plldiv",
static void __init static void __init
of_at91_clk_prog_setup(struct device_node *np, of_at91_clk_prog_setup(struct device_node *np,
const struct clk_programmable_layout *layout) const struct clk_programmable_layout *layout,
u32 *mux_table)
{ {
int num; int num;
u32 id; u32 id;
...@@ -707,7 +712,7 @@ of_at91_clk_prog_setup(struct device_node *np, ...@@ -707,7 +712,7 @@ of_at91_clk_prog_setup(struct device_node *np,
hw = at91_clk_register_programmable(regmap, name, hw = at91_clk_register_programmable(regmap, name,
parent_names, num_parents, parent_names, num_parents,
id, layout); id, layout, mux_table);
if (IS_ERR(hw)) if (IS_ERR(hw))
continue; continue;
...@@ -717,21 +722,21 @@ of_at91_clk_prog_setup(struct device_node *np, ...@@ -717,21 +722,21 @@ of_at91_clk_prog_setup(struct device_node *np,
static void __init of_at91rm9200_clk_prog_setup(struct device_node *np) static void __init of_at91rm9200_clk_prog_setup(struct device_node *np)
{ {
of_at91_clk_prog_setup(np, &at91rm9200_programmable_layout); of_at91_clk_prog_setup(np, &at91rm9200_programmable_layout, NULL);
} }
CLK_OF_DECLARE(at91rm9200_clk_prog, "atmel,at91rm9200-clk-programmable", CLK_OF_DECLARE(at91rm9200_clk_prog, "atmel,at91rm9200-clk-programmable",
of_at91rm9200_clk_prog_setup); of_at91rm9200_clk_prog_setup);
static void __init of_at91sam9g45_clk_prog_setup(struct device_node *np) static void __init of_at91sam9g45_clk_prog_setup(struct device_node *np)
{ {
of_at91_clk_prog_setup(np, &at91sam9g45_programmable_layout); of_at91_clk_prog_setup(np, &at91sam9g45_programmable_layout, NULL);
} }
CLK_OF_DECLARE(at91sam9g45_clk_prog, "atmel,at91sam9g45-clk-programmable", CLK_OF_DECLARE(at91sam9g45_clk_prog, "atmel,at91sam9g45-clk-programmable",
of_at91sam9g45_clk_prog_setup); of_at91sam9g45_clk_prog_setup);
static void __init of_at91sam9x5_clk_prog_setup(struct device_node *np) static void __init of_at91sam9x5_clk_prog_setup(struct device_node *np)
{ {
of_at91_clk_prog_setup(np, &at91sam9x5_programmable_layout); of_at91_clk_prog_setup(np, &at91sam9x5_programmable_layout, NULL);
} }
CLK_OF_DECLARE(at91sam9x5_clk_prog, "atmel,at91sam9x5-clk-programmable", CLK_OF_DECLARE(at91sam9x5_clk_prog, "atmel,at91sam9x5-clk-programmable",
of_at91sam9x5_clk_prog_setup); of_at91sam9x5_clk_prog_setup);
......
...@@ -54,8 +54,14 @@ struct clk_master_characteristics { ...@@ -54,8 +54,14 @@ struct clk_master_characteristics {
struct clk_pll_layout { struct clk_pll_layout {
u32 pllr_mask; u32 pllr_mask;
u16 mul_mask; u32 mul_mask;
u32 frac_mask;
u32 div_mask;
u32 endiv_mask;
u8 mul_shift; u8 mul_shift;
u8 frac_shift;
u8 div_shift;
u8 endiv_shift;
}; };
extern const struct clk_pll_layout at91rm9200_pll_layout; extern const struct clk_pll_layout at91rm9200_pll_layout;
...@@ -122,8 +128,8 @@ struct clk_hw * __init ...@@ -122,8 +128,8 @@ struct clk_hw * __init
at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,
const struct clk_pcr_layout *layout, const struct clk_pcr_layout *layout,
const char *name, const char **parent_names, const char *name, const char **parent_names,
u8 num_parents, u8 id, bool pll_audio, u32 *mux_table, u8 num_parents, u8 id,
const struct clk_range *range); const struct clk_range *range, int chg_pid);
struct clk_hw * __init struct clk_hw * __init
at91_clk_register_h32mx(struct regmap *regmap, const char *name, at91_clk_register_h32mx(struct regmap *regmap, const char *name,
...@@ -154,6 +160,13 @@ at91_clk_register_master(struct regmap *regmap, const char *name, ...@@ -154,6 +160,13 @@ at91_clk_register_master(struct regmap *regmap, const char *name,
const struct clk_master_layout *layout, const struct clk_master_layout *layout,
const struct clk_master_characteristics *characteristics); const struct clk_master_characteristics *characteristics);
struct clk_hw * __init
at91_clk_sama7g5_register_master(struct regmap *regmap,
const char *name, int num_parents,
const char **parent_names, u32 *mux_table,
spinlock_t *lock, u8 id, bool critical,
int chg_pid);
struct clk_hw * __init struct clk_hw * __init
at91_clk_register_peripheral(struct regmap *regmap, const char *name, at91_clk_register_peripheral(struct regmap *regmap, const char *name,
const char *parent_name, u32 id); const char *parent_name, u32 id);
...@@ -161,7 +174,8 @@ struct clk_hw * __init ...@@ -161,7 +174,8 @@ struct clk_hw * __init
at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock, at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
const struct clk_pcr_layout *layout, const struct clk_pcr_layout *layout,
const char *name, const char *parent_name, const char *name, const char *parent_name,
u32 id, const struct clk_range *range); u32 id, const struct clk_range *range,
int chg_pid);
struct clk_hw * __init struct clk_hw * __init
at91_clk_register_pll(struct regmap *regmap, const char *name, at91_clk_register_pll(struct regmap *regmap, const char *name,
...@@ -173,14 +187,23 @@ at91_clk_register_plldiv(struct regmap *regmap, const char *name, ...@@ -173,14 +187,23 @@ at91_clk_register_plldiv(struct regmap *regmap, const char *name,
const char *parent_name); const char *parent_name);
struct clk_hw * __init struct clk_hw * __init
sam9x60_clk_register_pll(struct regmap *regmap, spinlock_t *lock, sam9x60_clk_register_div_pll(struct regmap *regmap, spinlock_t *lock,
const char *name, const char *parent_name, u8 id, const char *name, const char *parent_name, u8 id,
const struct clk_pll_characteristics *characteristics); const struct clk_pll_characteristics *characteristics,
const struct clk_pll_layout *layout, bool critical);
struct clk_hw * __init
sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock,
const char *name, const char *parent_name,
struct clk_hw *parent_hw, u8 id,
const struct clk_pll_characteristics *characteristics,
const struct clk_pll_layout *layout, bool critical);
struct clk_hw * __init struct clk_hw * __init
at91_clk_register_programmable(struct regmap *regmap, const char *name, at91_clk_register_programmable(struct regmap *regmap, const char *name,
const char **parent_names, u8 num_parents, u8 id, const char **parent_names, u8 num_parents, u8 id,
const struct clk_programmable_layout *layout); const struct clk_programmable_layout *layout,
u32 *mux_table);
struct clk_hw * __init struct clk_hw * __init
at91_clk_register_sam9260_slow(struct regmap *regmap, at91_clk_register_sam9260_slow(struct regmap *regmap,
...@@ -213,6 +236,10 @@ struct clk_hw * __init ...@@ -213,6 +236,10 @@ struct clk_hw * __init
at91_clk_register_utmi(struct regmap *regmap_pmc, struct regmap *regmap_sfr, at91_clk_register_utmi(struct regmap *regmap_pmc, struct regmap *regmap_sfr,
const char *name, const char *parent_name); const char *name, const char *parent_name);
struct clk_hw * __init
at91_clk_sama7g5_register_utmi(struct regmap *regmap, const char *name,
const char *parent_name);
#ifdef CONFIG_PM #ifdef CONFIG_PM
void pmc_register_id(u8 id); void pmc_register_id(u8 id);
void pmc_register_pck(u8 pck); void pmc_register_pck(u8 pck);
......
...@@ -22,7 +22,7 @@ static const struct clk_master_layout sam9x60_master_layout = { ...@@ -22,7 +22,7 @@ static const struct clk_master_layout sam9x60_master_layout = {
}; };
static const struct clk_range plla_outputs[] = { static const struct clk_range plla_outputs[] = {
{ .min = 300000000, .max = 600000000 }, { .min = 2343750, .max = 1200000000 },
}; };
static const struct clk_pll_characteristics plla_characteristics = { static const struct clk_pll_characteristics plla_characteristics = {
...@@ -42,6 +42,20 @@ static const struct clk_pll_characteristics upll_characteristics = { ...@@ -42,6 +42,20 @@ static const struct clk_pll_characteristics upll_characteristics = {
.upll = true, .upll = true,
}; };
static const struct clk_pll_layout pll_frac_layout = {
.mul_mask = GENMASK(31, 24),
.frac_mask = GENMASK(21, 0),
.mul_shift = 24,
.frac_shift = 0,
};
static const struct clk_pll_layout pll_div_layout = {
.div_mask = GENMASK(7, 0),
.endiv_mask = BIT(29),
.div_shift = 0,
.endiv_shift = 29,
};
static const struct clk_programmable_layout sam9x60_programmable_layout = { static const struct clk_programmable_layout sam9x60_programmable_layout = {
.pres_mask = 0xff, .pres_mask = 0xff,
.pres_shift = 8, .pres_shift = 8,
...@@ -156,6 +170,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np) ...@@ -156,6 +170,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
const char *td_slck_name, *md_slck_name, *mainxtal_name; const char *td_slck_name, *md_slck_name, *mainxtal_name;
struct pmc_data *sam9x60_pmc; struct pmc_data *sam9x60_pmc;
const char *parent_names[6]; const char *parent_names[6];
struct clk_hw *main_osc_hw;
struct regmap *regmap; struct regmap *regmap;
struct clk_hw *hw; struct clk_hw *hw;
int i; int i;
...@@ -178,7 +193,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np) ...@@ -178,7 +193,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
return; return;
mainxtal_name = of_clk_get_parent_name(np, i); mainxtal_name = of_clk_get_parent_name(np, i);
regmap = syscon_node_to_regmap(np); regmap = device_node_to_regmap(np);
if (IS_ERR(regmap)) if (IS_ERR(regmap))
return; return;
...@@ -189,7 +204,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np) ...@@ -189,7 +204,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
if (!sam9x60_pmc) if (!sam9x60_pmc)
return; return;
hw = at91_clk_register_main_rc_osc(regmap, "main_rc_osc", 24000000, hw = at91_clk_register_main_rc_osc(regmap, "main_rc_osc", 12000000,
50000000); 50000000);
if (IS_ERR(hw)) if (IS_ERR(hw))
goto err_free; goto err_free;
...@@ -200,6 +215,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np) ...@@ -200,6 +215,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
bypass); bypass);
if (IS_ERR(hw)) if (IS_ERR(hw))
goto err_free; goto err_free;
main_osc_hw = hw;
parent_names[0] = "main_rc_osc"; parent_names[0] = "main_rc_osc";
parent_names[1] = "main_osc"; parent_names[1] = "main_osc";
...@@ -209,15 +225,31 @@ static void __init sam9x60_pmc_setup(struct device_node *np) ...@@ -209,15 +225,31 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
sam9x60_pmc->chws[PMC_MAIN] = hw; sam9x60_pmc->chws[PMC_MAIN] = hw;
hw = sam9x60_clk_register_pll(regmap, &pmc_pll_lock, "pllack", hw = sam9x60_clk_register_frac_pll(regmap, &pmc_pll_lock, "pllack_fracck",
"mainck", 0, &plla_characteristics); "mainck", sam9x60_pmc->chws[PMC_MAIN],
0, &plla_characteristics,
&pll_frac_layout, true);
if (IS_ERR(hw))
goto err_free;
hw = sam9x60_clk_register_div_pll(regmap, &pmc_pll_lock, "pllack_divck",
"pllack_fracck", 0, &plla_characteristics,
&pll_div_layout, true);
if (IS_ERR(hw)) if (IS_ERR(hw))
goto err_free; goto err_free;
sam9x60_pmc->chws[PMC_PLLACK] = hw; sam9x60_pmc->chws[PMC_PLLACK] = hw;
hw = sam9x60_clk_register_pll(regmap, &pmc_pll_lock, "upllck", hw = sam9x60_clk_register_frac_pll(regmap, &pmc_pll_lock, "upllck_fracck",
"main_osc", 1, &upll_characteristics); "main_osc", main_osc_hw, 1,
&upll_characteristics,
&pll_frac_layout, false);
if (IS_ERR(hw))
goto err_free;
hw = sam9x60_clk_register_div_pll(regmap, &pmc_pll_lock, "upllck_divck",
"upllck_fracck", 1, &upll_characteristics,
&pll_div_layout, false);
if (IS_ERR(hw)) if (IS_ERR(hw))
goto err_free; goto err_free;
...@@ -225,7 +257,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np) ...@@ -225,7 +257,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
parent_names[0] = md_slck_name; parent_names[0] = md_slck_name;
parent_names[1] = "mainck"; parent_names[1] = "mainck";
parent_names[2] = "pllack"; parent_names[2] = "pllack_divck";
hw = at91_clk_register_master(regmap, "masterck", 3, parent_names, hw = at91_clk_register_master(regmap, "masterck", 3, parent_names,
&sam9x60_master_layout, &sam9x60_master_layout,
&mck_characteristics); &mck_characteristics);
...@@ -234,8 +266,8 @@ static void __init sam9x60_pmc_setup(struct device_node *np) ...@@ -234,8 +266,8 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
sam9x60_pmc->chws[PMC_MCK] = hw; sam9x60_pmc->chws[PMC_MCK] = hw;
parent_names[0] = "pllack"; parent_names[0] = "pllack_divck";
parent_names[1] = "upllck"; parent_names[1] = "upllck_divck";
parent_names[2] = "main_osc"; parent_names[2] = "main_osc";
hw = sam9x60_clk_register_usb(regmap, "usbck", parent_names, 3); hw = sam9x60_clk_register_usb(regmap, "usbck", parent_names, 3);
if (IS_ERR(hw)) if (IS_ERR(hw))
...@@ -245,8 +277,8 @@ static void __init sam9x60_pmc_setup(struct device_node *np) ...@@ -245,8 +277,8 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
parent_names[1] = td_slck_name; parent_names[1] = td_slck_name;
parent_names[2] = "mainck"; parent_names[2] = "mainck";
parent_names[3] = "masterck"; parent_names[3] = "masterck";
parent_names[4] = "pllack"; parent_names[4] = "pllack_divck";
parent_names[5] = "upllck"; parent_names[5] = "upllck_divck";
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
char name[6]; char name[6];
...@@ -254,7 +286,8 @@ static void __init sam9x60_pmc_setup(struct device_node *np) ...@@ -254,7 +286,8 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
hw = at91_clk_register_programmable(regmap, name, hw = at91_clk_register_programmable(regmap, name,
parent_names, 6, i, parent_names, 6, i,
&sam9x60_programmable_layout); &sam9x60_programmable_layout,
NULL);
if (IS_ERR(hw)) if (IS_ERR(hw))
goto err_free; goto err_free;
...@@ -277,7 +310,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np) ...@@ -277,7 +310,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
sam9x60_periphck[i].n, sam9x60_periphck[i].n,
"masterck", "masterck",
sam9x60_periphck[i].id, sam9x60_periphck[i].id,
&range); &range, INT_MIN);
if (IS_ERR(hw)) if (IS_ERR(hw))
goto err_free; goto err_free;
...@@ -288,10 +321,9 @@ static void __init sam9x60_pmc_setup(struct device_node *np) ...@@ -288,10 +321,9 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
&sam9x60_pcr_layout, &sam9x60_pcr_layout,
sam9x60_gck[i].n, sam9x60_gck[i].n,
parent_names, 6, parent_names, NULL, 6,
sam9x60_gck[i].id, sam9x60_gck[i].id,
false, &sam9x60_gck[i].r, INT_MIN);
&sam9x60_gck[i].r);
if (IS_ERR(hw)) if (IS_ERR(hw))
goto err_free; goto err_free;
......
...@@ -116,21 +116,20 @@ static const struct { ...@@ -116,21 +116,20 @@ static const struct {
char *n; char *n;
u8 id; u8 id;
struct clk_range r; struct clk_range r;
bool pll; int chg_pid;
} sama5d2_gck[] = { } sama5d2_gck[] = {
{ .n = "sdmmc0_gclk", .id = 31, }, { .n = "sdmmc0_gclk", .id = 31, .chg_pid = INT_MIN, },
{ .n = "sdmmc1_gclk", .id = 32, }, { .n = "sdmmc1_gclk", .id = 32, .chg_pid = INT_MIN, },
{ .n = "tcb0_gclk", .id = 35, .r = { .min = 0, .max = 83000000 }, }, { .n = "tcb0_gclk", .id = 35, .chg_pid = INT_MIN, .r = { .min = 0, .max = 83000000 }, },
{ .n = "tcb1_gclk", .id = 36, .r = { .min = 0, .max = 83000000 }, }, { .n = "tcb1_gclk", .id = 36, .chg_pid = INT_MIN, .r = { .min = 0, .max = 83000000 }, },
{ .n = "pwm_gclk", .id = 38, .r = { .min = 0, .max = 83000000 }, }, { .n = "pwm_gclk", .id = 38, .chg_pid = INT_MIN, .r = { .min = 0, .max = 83000000 }, },
{ .n = "isc_gclk", .id = 46, }, { .n = "isc_gclk", .id = 46, .chg_pid = INT_MIN, },
{ .n = "pdmic_gclk", .id = 48, }, { .n = "pdmic_gclk", .id = 48, .chg_pid = INT_MIN, },
{ .n = "i2s0_gclk", .id = 54, .pll = true }, { .n = "i2s0_gclk", .id = 54, .chg_pid = 5, },
{ .n = "i2s1_gclk", .id = 55, .pll = true }, { .n = "i2s1_gclk", .id = 55, .chg_pid = 5, },
{ .n = "can0_gclk", .id = 56, .r = { .min = 0, .max = 80000000 }, }, { .n = "can0_gclk", .id = 56, .chg_pid = INT_MIN, .r = { .min = 0, .max = 80000000 }, },
{ .n = "can1_gclk", .id = 57, .r = { .min = 0, .max = 80000000 }, }, { .n = "can1_gclk", .id = 57, .chg_pid = INT_MIN, .r = { .min = 0, .max = 80000000 }, },
{ .n = "classd_gclk", .id = 59, .r = { .min = 0, .max = 100000000 }, { .n = "classd_gclk", .id = 59, .chg_pid = 5, .r = { .min = 0, .max = 100000000 }, },
.pll = true },
}; };
static const struct clk_programmable_layout sama5d2_programmable_layout = { static const struct clk_programmable_layout sama5d2_programmable_layout = {
...@@ -269,7 +268,8 @@ static void __init sama5d2_pmc_setup(struct device_node *np) ...@@ -269,7 +268,8 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
hw = at91_clk_register_programmable(regmap, name, hw = at91_clk_register_programmable(regmap, name,
parent_names, 6, i, parent_names, 6, i,
&sama5d2_programmable_layout); &sama5d2_programmable_layout,
NULL);
if (IS_ERR(hw)) if (IS_ERR(hw))
goto err_free; goto err_free;
...@@ -292,7 +292,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np) ...@@ -292,7 +292,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
sama5d2_periphck[i].n, sama5d2_periphck[i].n,
"masterck", "masterck",
sama5d2_periphck[i].id, sama5d2_periphck[i].id,
&range); &range, INT_MIN);
if (IS_ERR(hw)) if (IS_ERR(hw))
goto err_free; goto err_free;
...@@ -305,7 +305,8 @@ static void __init sama5d2_pmc_setup(struct device_node *np) ...@@ -305,7 +305,8 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
sama5d2_periph32ck[i].n, sama5d2_periph32ck[i].n,
"h32mxck", "h32mxck",
sama5d2_periph32ck[i].id, sama5d2_periph32ck[i].id,
&sama5d2_periph32ck[i].r); &sama5d2_periph32ck[i].r,
INT_MIN);
if (IS_ERR(hw)) if (IS_ERR(hw))
goto err_free; goto err_free;
...@@ -322,10 +323,10 @@ static void __init sama5d2_pmc_setup(struct device_node *np) ...@@ -322,10 +323,10 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
&sama5d2_pcr_layout, &sama5d2_pcr_layout,
sama5d2_gck[i].n, sama5d2_gck[i].n,
parent_names, 6, parent_names, NULL, 6,
sama5d2_gck[i].id, sama5d2_gck[i].id,
sama5d2_gck[i].pll, &sama5d2_gck[i].r,
&sama5d2_gck[i].r); sama5d2_gck[i].chg_pid);
if (IS_ERR(hw)) if (IS_ERR(hw))
goto err_free; goto err_free;
......
...@@ -121,7 +121,7 @@ static void __init sama5d3_pmc_setup(struct device_node *np) ...@@ -121,7 +121,7 @@ static void __init sama5d3_pmc_setup(struct device_node *np)
return; return;
mainxtal_name = of_clk_get_parent_name(np, i); mainxtal_name = of_clk_get_parent_name(np, i);
regmap = syscon_node_to_regmap(np); regmap = device_node_to_regmap(np);
if (IS_ERR(regmap)) if (IS_ERR(regmap))
return; return;
...@@ -200,7 +200,8 @@ static void __init sama5d3_pmc_setup(struct device_node *np) ...@@ -200,7 +200,8 @@ static void __init sama5d3_pmc_setup(struct device_node *np)
hw = at91_clk_register_programmable(regmap, name, hw = at91_clk_register_programmable(regmap, name,
parent_names, 5, i, parent_names, 5, i,
&at91sam9x5_programmable_layout); &at91sam9x5_programmable_layout,
NULL);
if (IS_ERR(hw)) if (IS_ERR(hw))
goto err_free; goto err_free;
...@@ -223,7 +224,8 @@ static void __init sama5d3_pmc_setup(struct device_node *np) ...@@ -223,7 +224,8 @@ static void __init sama5d3_pmc_setup(struct device_node *np)
sama5d3_periphck[i].n, sama5d3_periphck[i].n,
"masterck", "masterck",
sama5d3_periphck[i].id, sama5d3_periphck[i].id,
&sama5d3_periphck[i].r); &sama5d3_periphck[i].r,
INT_MIN);
if (IS_ERR(hw)) if (IS_ERR(hw))
goto err_free; goto err_free;
......
...@@ -223,7 +223,8 @@ static void __init sama5d4_pmc_setup(struct device_node *np) ...@@ -223,7 +223,8 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
hw = at91_clk_register_programmable(regmap, name, hw = at91_clk_register_programmable(regmap, name,
parent_names, 5, i, parent_names, 5, i,
&at91sam9x5_programmable_layout); &at91sam9x5_programmable_layout,
NULL);
if (IS_ERR(hw)) if (IS_ERR(hw))
goto err_free; goto err_free;
...@@ -246,7 +247,7 @@ static void __init sama5d4_pmc_setup(struct device_node *np) ...@@ -246,7 +247,7 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
sama5d4_periphck[i].n, sama5d4_periphck[i].n,
"masterck", "masterck",
sama5d4_periphck[i].id, sama5d4_periphck[i].id,
&range); &range, INT_MIN);
if (IS_ERR(hw)) if (IS_ERR(hw))
goto err_free; goto err_free;
...@@ -259,7 +260,7 @@ static void __init sama5d4_pmc_setup(struct device_node *np) ...@@ -259,7 +260,7 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
sama5d4_periph32ck[i].n, sama5d4_periph32ck[i].n,
"h32mxck", "h32mxck",
sama5d4_periph32ck[i].id, sama5d4_periph32ck[i].id,
&range); &range, INT_MIN);
if (IS_ERR(hw)) if (IS_ERR(hw))
goto err_free; goto err_free;
......
This diff is collapsed.
...@@ -471,8 +471,9 @@ static void __init of_sam9x60_sckc_setup(struct device_node *np) ...@@ -471,8 +471,9 @@ static void __init of_sam9x60_sckc_setup(struct device_node *np)
if (!regbase) if (!regbase)
return; return;
slow_rc = clk_hw_register_fixed_rate(NULL, parent_names[0], NULL, 0, slow_rc = clk_hw_register_fixed_rate_with_accuracy(NULL, parent_names[0],
32768); NULL, 0, 32768,
93750000);
if (IS_ERR(slow_rc)) if (IS_ERR(slow_rc))
return; return;
......
...@@ -314,6 +314,7 @@ struct bcm2835_cprman { ...@@ -314,6 +314,7 @@ struct bcm2835_cprman {
struct device *dev; struct device *dev;
void __iomem *regs; void __iomem *regs;
spinlock_t regs_lock; /* spinlock for all clocks */ spinlock_t regs_lock; /* spinlock for all clocks */
unsigned int soc;
/* /*
* Real names of cprman clock parents looked up through * Real names of cprman clock parents looked up through
...@@ -526,6 +527,20 @@ static int bcm2835_pll_is_on(struct clk_hw *hw) ...@@ -526,6 +527,20 @@ static int bcm2835_pll_is_on(struct clk_hw *hw)
A2W_PLL_CTRL_PRST_DISABLE; A2W_PLL_CTRL_PRST_DISABLE;
} }
static u32 bcm2835_pll_get_prediv_mask(struct bcm2835_cprman *cprman,
const struct bcm2835_pll_data *data)
{
/*
* On BCM2711 there isn't a pre-divisor available in the PLL feedback
* loop. Bits 13:14 of ANA1 (PLLA,PLLB,PLLC,PLLD) have been re-purposed
* for to for VCO RANGE bits.
*/
if (cprman->soc & SOC_BCM2711)
return 0;
return data->ana->fb_prediv_mask;
}
static void bcm2835_pll_choose_ndiv_and_fdiv(unsigned long rate, static void bcm2835_pll_choose_ndiv_and_fdiv(unsigned long rate,
unsigned long parent_rate, unsigned long parent_rate,
u32 *ndiv, u32 *fdiv) u32 *ndiv, u32 *fdiv)
...@@ -583,7 +598,7 @@ static unsigned long bcm2835_pll_get_rate(struct clk_hw *hw, ...@@ -583,7 +598,7 @@ static unsigned long bcm2835_pll_get_rate(struct clk_hw *hw,
ndiv = (a2wctrl & A2W_PLL_CTRL_NDIV_MASK) >> A2W_PLL_CTRL_NDIV_SHIFT; ndiv = (a2wctrl & A2W_PLL_CTRL_NDIV_MASK) >> A2W_PLL_CTRL_NDIV_SHIFT;
pdiv = (a2wctrl & A2W_PLL_CTRL_PDIV_MASK) >> A2W_PLL_CTRL_PDIV_SHIFT; pdiv = (a2wctrl & A2W_PLL_CTRL_PDIV_MASK) >> A2W_PLL_CTRL_PDIV_SHIFT;
using_prediv = cprman_read(cprman, data->ana_reg_base + 4) & using_prediv = cprman_read(cprman, data->ana_reg_base + 4) &
data->ana->fb_prediv_mask; bcm2835_pll_get_prediv_mask(cprman, data);
if (using_prediv) { if (using_prediv) {
ndiv *= 2; ndiv *= 2;
...@@ -666,6 +681,7 @@ static int bcm2835_pll_set_rate(struct clk_hw *hw, ...@@ -666,6 +681,7 @@ static int bcm2835_pll_set_rate(struct clk_hw *hw,
struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw); struct bcm2835_pll *pll = container_of(hw, struct bcm2835_pll, hw);
struct bcm2835_cprman *cprman = pll->cprman; struct bcm2835_cprman *cprman = pll->cprman;
const struct bcm2835_pll_data *data = pll->data; const struct bcm2835_pll_data *data = pll->data;
u32 prediv_mask = bcm2835_pll_get_prediv_mask(cprman, data);
bool was_using_prediv, use_fb_prediv, do_ana_setup_first; bool was_using_prediv, use_fb_prediv, do_ana_setup_first;
u32 ndiv, fdiv, a2w_ctl; u32 ndiv, fdiv, a2w_ctl;
u32 ana[4]; u32 ana[4];
...@@ -683,7 +699,7 @@ static int bcm2835_pll_set_rate(struct clk_hw *hw, ...@@ -683,7 +699,7 @@ static int bcm2835_pll_set_rate(struct clk_hw *hw,
for (i = 3; i >= 0; i--) for (i = 3; i >= 0; i--)
ana[i] = cprman_read(cprman, data->ana_reg_base + i * 4); ana[i] = cprman_read(cprman, data->ana_reg_base + i * 4);
was_using_prediv = ana[1] & data->ana->fb_prediv_mask; was_using_prediv = ana[1] & prediv_mask;
ana[0] &= ~data->ana->mask0; ana[0] &= ~data->ana->mask0;
ana[0] |= data->ana->set0; ana[0] |= data->ana->set0;
...@@ -693,10 +709,10 @@ static int bcm2835_pll_set_rate(struct clk_hw *hw, ...@@ -693,10 +709,10 @@ static int bcm2835_pll_set_rate(struct clk_hw *hw,
ana[3] |= data->ana->set3; ana[3] |= data->ana->set3;
if (was_using_prediv && !use_fb_prediv) { if (was_using_prediv && !use_fb_prediv) {
ana[1] &= ~data->ana->fb_prediv_mask; ana[1] &= ~prediv_mask;
do_ana_setup_first = true; do_ana_setup_first = true;
} else if (!was_using_prediv && use_fb_prediv) { } else if (!was_using_prediv && use_fb_prediv) {
ana[1] |= data->ana->fb_prediv_mask; ana[1] |= prediv_mask;
do_ana_setup_first = false; do_ana_setup_first = false;
} else { } else {
do_ana_setup_first = true; do_ana_setup_first = true;
...@@ -2262,6 +2278,7 @@ static int bcm2835_clk_probe(struct platform_device *pdev) ...@@ -2262,6 +2278,7 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, cprman); platform_set_drvdata(pdev, cprman);
cprman->onecell.num = asize; cprman->onecell.num = asize;
cprman->soc = pdata->soc;
hws = cprman->onecell.hws; hws = cprman->onecell.hws;
for (i = 0; i < asize; i++) { for (i = 0; i < asize; i++) {
......
...@@ -119,7 +119,7 @@ static long iproc_asiu_clk_round_rate(struct clk_hw *hw, unsigned long rate, ...@@ -119,7 +119,7 @@ static long iproc_asiu_clk_round_rate(struct clk_hw *hw, unsigned long rate,
if (rate == *parent_rate) if (rate == *parent_rate)
return *parent_rate; return *parent_rate;
div = DIV_ROUND_UP(*parent_rate, rate); div = DIV_ROUND_CLOSEST(*parent_rate, rate);
if (div < 2) if (div < 2)
return *parent_rate; return *parent_rate;
...@@ -145,7 +145,7 @@ static int iproc_asiu_clk_set_rate(struct clk_hw *hw, unsigned long rate, ...@@ -145,7 +145,7 @@ static int iproc_asiu_clk_set_rate(struct clk_hw *hw, unsigned long rate,
return 0; return 0;
} }
div = DIV_ROUND_UP(parent_rate, rate); div = DIV_ROUND_CLOSEST(parent_rate, rate);
if (div < 2) if (div < 2)
return -EINVAL; return -EINVAL;
......
...@@ -244,6 +244,14 @@ static const struct clockgen_muxinfo clockgen2_cmux_cgb = { ...@@ -244,6 +244,14 @@ static const struct clockgen_muxinfo clockgen2_cmux_cgb = {
}, },
}; };
static const struct clockgen_muxinfo ls1021a_cmux = {
{
{ CLKSEL_VALID, CGA_PLL1, PLL_DIV1 },
{ CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
{ CLKSEL_VALID, CGA_PLL1, PLL_DIV4 },
}
};
static const struct clockgen_muxinfo ls1028a_hwa1 = { static const struct clockgen_muxinfo ls1028a_hwa1 = {
{ {
{ CLKSEL_VALID, PLATFORM_PLL, PLL_DIV1 }, { CLKSEL_VALID, PLATFORM_PLL, PLL_DIV1 },
...@@ -577,7 +585,7 @@ static const struct clockgen_chipinfo chipinfo[] = { ...@@ -577,7 +585,7 @@ static const struct clockgen_chipinfo chipinfo[] = {
{ {
.compat = "fsl,ls1021a-clockgen", .compat = "fsl,ls1021a-clockgen",
.cmux_groups = { .cmux_groups = {
&t1023_cmux &ls1021a_cmux
}, },
.cmux_to_group = { .cmux_to_group = {
0, -1 0, -1
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Microchip Sparx5 SoC Clock driver.
*
* Copyright (c) 2019 Microchip Inc.
*
* Author: Lars Povlsen <lars.povlsen@microchip.com>
*/
#include <linux/io.h>
#include <linux/module.h>
#include <linux/clk-provider.h>
#include <linux/bitfield.h>
#include <linux/of.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <dt-bindings/clock/microchip,sparx5.h>
#define PLL_DIV GENMASK(7, 0)
#define PLL_PRE_DIV GENMASK(10, 8)
#define PLL_ROT_DIR BIT(11)
#define PLL_ROT_SEL GENMASK(13, 12)
#define PLL_ROT_ENA BIT(14)
#define PLL_CLK_ENA BIT(15)
#define MAX_SEL 4
#define MAX_PRE BIT(3)
static const u8 sel_rates[MAX_SEL] = { 0, 2*8, 2*4, 2*2 };
static const char *clk_names[N_CLOCKS] = {
"core", "ddr", "cpu2", "arm2",
"aux1", "aux2", "aux3", "aux4",
"synce",
};
struct s5_hw_clk {
struct clk_hw hw;
void __iomem *reg;
};
struct s5_clk_data {
void __iomem *base;
struct s5_hw_clk s5_hw[N_CLOCKS];
};
struct s5_pll_conf {
unsigned long freq;
u8 div;
bool rot_ena;
u8 rot_sel;
u8 rot_dir;
u8 pre_div;
};
#define to_s5_pll(hw) container_of(hw, struct s5_hw_clk, hw)
static unsigned long s5_calc_freq(unsigned long parent_rate,
const struct s5_pll_conf *conf)
{
unsigned long rate = parent_rate / conf->div;
if (conf->rot_ena) {
int sign = conf->rot_dir ? -1 : 1;
int divt = sel_rates[conf->rot_sel] * (1 + conf->pre_div);
int divb = divt + sign;
rate = mult_frac(rate, divt, divb);
rate = roundup(rate, 1000);
}
return rate;
}
static void s5_search_fractional(unsigned long rate,
unsigned long parent_rate,
int div,
struct s5_pll_conf *conf)
{
struct s5_pll_conf best;
ulong cur_offset, best_offset = rate;
int d, i, j;
memset(conf, 0, sizeof(*conf));
conf->div = div;
conf->rot_ena = 1; /* Fractional rate */
for (d = 0; best_offset > 0 && d <= 1 ; d++) {
conf->rot_dir = !!d;
for (i = 0; best_offset > 0 && i < MAX_PRE; i++) {
conf->pre_div = i;
for (j = 1; best_offset > 0 && j < MAX_SEL; j++) {
conf->rot_sel = j;
conf->freq = s5_calc_freq(parent_rate, conf);
cur_offset = abs(rate - conf->freq);
if (cur_offset < best_offset) {
best_offset = cur_offset;
best = *conf;
}
}
}
}
/* Best match */
*conf = best;
}
static unsigned long s5_calc_params(unsigned long rate,
unsigned long parent_rate,
struct s5_pll_conf *conf)
{
if (parent_rate % rate) {
struct s5_pll_conf alt1, alt2;
int div;
div = DIV_ROUND_CLOSEST_ULL(parent_rate, rate);
s5_search_fractional(rate, parent_rate, div, &alt1);
/* Straight match? */
if (alt1.freq == rate) {
*conf = alt1;
} else {
/* Try without rounding divider */
div = parent_rate / rate;
if (div != alt1.div) {
s5_search_fractional(rate, parent_rate, div,
&alt2);
/* Select the better match */
if (abs(rate - alt1.freq) <
abs(rate - alt2.freq))
*conf = alt1;
else
*conf = alt2;
}
}
} else {
/* Straight fit */
memset(conf, 0, sizeof(*conf));
conf->div = parent_rate / rate;
}
return conf->freq;
}
static int s5_pll_enable(struct clk_hw *hw)
{
struct s5_hw_clk *pll = to_s5_pll(hw);
u32 val = readl(pll->reg);
val |= PLL_CLK_ENA;
writel(val, pll->reg);
return 0;
}
static void s5_pll_disable(struct clk_hw *hw)
{
struct s5_hw_clk *pll = to_s5_pll(hw);
u32 val = readl(pll->reg);
val &= ~PLL_CLK_ENA;
writel(val, pll->reg);
}
static int s5_pll_set_rate(struct clk_hw *hw,
unsigned long rate,
unsigned long parent_rate)
{
struct s5_hw_clk *pll = to_s5_pll(hw);
struct s5_pll_conf conf;
unsigned long eff_rate;
u32 val;
eff_rate = s5_calc_params(rate, parent_rate, &conf);
if (eff_rate != rate)
return -EOPNOTSUPP;
val = readl(pll->reg) & PLL_CLK_ENA;
val |= FIELD_PREP(PLL_DIV, conf.div);
if (conf.rot_ena) {
val |= PLL_ROT_ENA;
val |= FIELD_PREP(PLL_ROT_SEL, conf.rot_sel);
val |= FIELD_PREP(PLL_PRE_DIV, conf.pre_div);
if (conf.rot_dir)
val |= PLL_ROT_DIR;
}
writel(val, pll->reg);
return 0;
}
static unsigned long s5_pll_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct s5_hw_clk *pll = to_s5_pll(hw);
struct s5_pll_conf conf;
u32 val;
val = readl(pll->reg);
if (val & PLL_CLK_ENA) {
conf.div = FIELD_GET(PLL_DIV, val);
conf.pre_div = FIELD_GET(PLL_PRE_DIV, val);
conf.rot_ena = FIELD_GET(PLL_ROT_ENA, val);
conf.rot_dir = FIELD_GET(PLL_ROT_DIR, val);
conf.rot_sel = FIELD_GET(PLL_ROT_SEL, val);
conf.freq = s5_calc_freq(parent_rate, &conf);
} else {
conf.freq = 0;
}
return conf.freq;
}
static long s5_pll_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
struct s5_pll_conf conf;
return s5_calc_params(rate, *parent_rate, &conf);
}
static const struct clk_ops s5_pll_ops = {
.enable = s5_pll_enable,
.disable = s5_pll_disable,
.set_rate = s5_pll_set_rate,
.round_rate = s5_pll_round_rate,
.recalc_rate = s5_pll_recalc_rate,
};
static struct clk_hw *s5_clk_hw_get(struct of_phandle_args *clkspec, void *data)
{
struct s5_clk_data *s5_clk = data;
unsigned int idx = clkspec->args[0];
if (idx >= N_CLOCKS) {
pr_err("%s: invalid index %u\n", __func__, idx);
return ERR_PTR(-EINVAL);
}
return &s5_clk->s5_hw[idx].hw;
}
static int s5_clk_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
int i, ret;
struct s5_clk_data *s5_clk;
struct clk_parent_data pdata = { .index = 0 };
struct clk_init_data init = {
.ops = &s5_pll_ops,
.num_parents = 1,
.parent_data = &pdata,
};
s5_clk = devm_kzalloc(dev, sizeof(*s5_clk), GFP_KERNEL);
if (!s5_clk)
return -ENOMEM;
s5_clk->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(s5_clk->base))
return PTR_ERR(s5_clk->base);
for (i = 0; i < N_CLOCKS; i++) {
struct s5_hw_clk *s5_hw = &s5_clk->s5_hw[i];
init.name = clk_names[i];
s5_hw->reg = s5_clk->base + (i * 4);
s5_hw->hw.init = &init;
ret = devm_clk_hw_register(dev, &s5_hw->hw);
if (ret) {
dev_err(dev, "failed to register %s clock\n",
init.name);
return ret;
}
}
return devm_of_clk_add_hw_provider(dev, s5_clk_hw_get, s5_clk);
}
static const struct of_device_id s5_clk_dt_ids[] = {
{ .compatible = "microchip,sparx5-dpll", },
{ }
};
MODULE_DEVICE_TABLE(of, s5_clk_dt_ids);
static struct platform_driver s5_clk_driver = {
.probe = s5_clk_probe,
.driver = {
.name = "sparx5-clk",
.of_match_table = s5_clk_dt_ids,
},
};
builtin_platform_driver(s5_clk_driver);
...@@ -167,6 +167,12 @@ struct vc5_hw_data { ...@@ -167,6 +167,12 @@ struct vc5_hw_data {
u32 div_int; u32 div_int;
u32 div_frc; u32 div_frc;
unsigned int num; unsigned int num;
};
struct vc5_out_data {
struct clk_hw hw;
struct vc5_driver_data *vc5;
unsigned int num;
unsigned int clk_output_cfg0; unsigned int clk_output_cfg0;
unsigned int clk_output_cfg0_mask; unsigned int clk_output_cfg0_mask;
}; };
...@@ -184,7 +190,7 @@ struct vc5_driver_data { ...@@ -184,7 +190,7 @@ struct vc5_driver_data {
struct clk_hw clk_pfd; struct clk_hw clk_pfd;
struct vc5_hw_data clk_pll; struct vc5_hw_data clk_pll;
struct vc5_hw_data clk_fod[VC5_MAX_FOD_NUM]; struct vc5_hw_data clk_fod[VC5_MAX_FOD_NUM];
struct vc5_hw_data clk_out[VC5_MAX_CLK_OUT_NUM]; struct vc5_out_data clk_out[VC5_MAX_CLK_OUT_NUM];
}; };
/* /*
...@@ -567,7 +573,7 @@ static const struct clk_ops vc5_fod_ops = { ...@@ -567,7 +573,7 @@ static const struct clk_ops vc5_fod_ops = {
static int vc5_clk_out_prepare(struct clk_hw *hw) static int vc5_clk_out_prepare(struct clk_hw *hw)
{ {
struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw); struct vc5_out_data *hwdata = container_of(hw, struct vc5_out_data, hw);
struct vc5_driver_data *vc5 = hwdata->vc5; struct vc5_driver_data *vc5 = hwdata->vc5;
const u8 mask = VC5_OUT_DIV_CONTROL_SELB_NORM | const u8 mask = VC5_OUT_DIV_CONTROL_SELB_NORM |
VC5_OUT_DIV_CONTROL_SEL_EXT | VC5_OUT_DIV_CONTROL_SEL_EXT |
...@@ -609,7 +615,7 @@ static int vc5_clk_out_prepare(struct clk_hw *hw) ...@@ -609,7 +615,7 @@ static int vc5_clk_out_prepare(struct clk_hw *hw)
static void vc5_clk_out_unprepare(struct clk_hw *hw) static void vc5_clk_out_unprepare(struct clk_hw *hw)
{ {
struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw); struct vc5_out_data *hwdata = container_of(hw, struct vc5_out_data, hw);
struct vc5_driver_data *vc5 = hwdata->vc5; struct vc5_driver_data *vc5 = hwdata->vc5;
/* Disable the clock buffer */ /* Disable the clock buffer */
...@@ -619,7 +625,7 @@ static void vc5_clk_out_unprepare(struct clk_hw *hw) ...@@ -619,7 +625,7 @@ static void vc5_clk_out_unprepare(struct clk_hw *hw)
static unsigned char vc5_clk_out_get_parent(struct clk_hw *hw) static unsigned char vc5_clk_out_get_parent(struct clk_hw *hw)
{ {
struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw); struct vc5_out_data *hwdata = container_of(hw, struct vc5_out_data, hw);
struct vc5_driver_data *vc5 = hwdata->vc5; struct vc5_driver_data *vc5 = hwdata->vc5;
const u8 mask = VC5_OUT_DIV_CONTROL_SELB_NORM | const u8 mask = VC5_OUT_DIV_CONTROL_SELB_NORM |
VC5_OUT_DIV_CONTROL_SEL_EXT | VC5_OUT_DIV_CONTROL_SEL_EXT |
...@@ -649,7 +655,7 @@ static unsigned char vc5_clk_out_get_parent(struct clk_hw *hw) ...@@ -649,7 +655,7 @@ static unsigned char vc5_clk_out_get_parent(struct clk_hw *hw)
static int vc5_clk_out_set_parent(struct clk_hw *hw, u8 index) static int vc5_clk_out_set_parent(struct clk_hw *hw, u8 index)
{ {
struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw); struct vc5_out_data *hwdata = container_of(hw, struct vc5_out_data, hw);
struct vc5_driver_data *vc5 = hwdata->vc5; struct vc5_driver_data *vc5 = hwdata->vc5;
const u8 mask = VC5_OUT_DIV_CONTROL_RESET | const u8 mask = VC5_OUT_DIV_CONTROL_RESET |
VC5_OUT_DIV_CONTROL_SELB_NORM | VC5_OUT_DIV_CONTROL_SELB_NORM |
...@@ -704,7 +710,7 @@ static int vc5_map_index_to_output(const enum vc5_model model, ...@@ -704,7 +710,7 @@ static int vc5_map_index_to_output(const enum vc5_model model,
} }
static int vc5_update_mode(struct device_node *np_output, static int vc5_update_mode(struct device_node *np_output,
struct vc5_hw_data *clk_out) struct vc5_out_data *clk_out)
{ {
u32 value; u32 value;
...@@ -729,7 +735,7 @@ static int vc5_update_mode(struct device_node *np_output, ...@@ -729,7 +735,7 @@ static int vc5_update_mode(struct device_node *np_output,
} }
static int vc5_update_power(struct device_node *np_output, static int vc5_update_power(struct device_node *np_output,
struct vc5_hw_data *clk_out) struct vc5_out_data *clk_out)
{ {
u32 value; u32 value;
...@@ -754,7 +760,7 @@ static int vc5_update_power(struct device_node *np_output, ...@@ -754,7 +760,7 @@ static int vc5_update_power(struct device_node *np_output,
} }
static int vc5_update_slew(struct device_node *np_output, static int vc5_update_slew(struct device_node *np_output,
struct vc5_hw_data *clk_out) struct vc5_out_data *clk_out)
{ {
u32 value; u32 value;
...@@ -782,17 +788,20 @@ static int vc5_update_slew(struct device_node *np_output, ...@@ -782,17 +788,20 @@ static int vc5_update_slew(struct device_node *np_output,
} }
static int vc5_get_output_config(struct i2c_client *client, static int vc5_get_output_config(struct i2c_client *client,
struct vc5_hw_data *clk_out) struct vc5_out_data *clk_out)
{ {
struct device_node *np_output; struct device_node *np_output;
char *child_name; char *child_name;
int ret = 0; int ret = 0;
child_name = kasprintf(GFP_KERNEL, "OUT%d", clk_out->num + 1); child_name = kasprintf(GFP_KERNEL, "OUT%d", clk_out->num + 1);
if (!child_name)
return -ENOMEM;
np_output = of_get_child_by_name(client->dev.of_node, child_name); np_output = of_get_child_by_name(client->dev.of_node, child_name);
kfree(child_name); kfree(child_name);
if (!np_output) if (!np_output)
goto output_done; return 0;
ret = vc5_update_mode(np_output, clk_out); ret = vc5_update_mode(np_output, clk_out);
if (ret) if (ret)
...@@ -813,7 +822,6 @@ static int vc5_get_output_config(struct i2c_client *client, ...@@ -813,7 +822,6 @@ static int vc5_get_output_config(struct i2c_client *client,
of_node_put(np_output); of_node_put(np_output);
output_done:
return ret; return ret;
} }
...@@ -828,7 +836,7 @@ static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -828,7 +836,7 @@ static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id)
int ret; int ret;
vc5 = devm_kzalloc(&client->dev, sizeof(*vc5), GFP_KERNEL); vc5 = devm_kzalloc(&client->dev, sizeof(*vc5), GFP_KERNEL);
if (vc5 == NULL) if (!vc5)
return -ENOMEM; return -ENOMEM;
i2c_set_clientdata(client, vc5); i2c_set_clientdata(client, vc5);
...@@ -882,11 +890,9 @@ static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -882,11 +890,9 @@ static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id)
init.parent_names = parent_names; init.parent_names = parent_names;
vc5->clk_mux.init = &init; vc5->clk_mux.init = &init;
ret = devm_clk_hw_register(&client->dev, &vc5->clk_mux); ret = devm_clk_hw_register(&client->dev, &vc5->clk_mux);
if (ret)
goto err_clk_register;
kfree(init.name); /* clock framework made a copy of the name */ kfree(init.name); /* clock framework made a copy of the name */
if (ret) {
dev_err(&client->dev, "unable to register %s\n", init.name);
goto err_clk;
}
if (vc5->chip_info->flags & VC5_HAS_PFD_FREQ_DBL) { if (vc5->chip_info->flags & VC5_HAS_PFD_FREQ_DBL) {
/* Register frequency doubler */ /* Register frequency doubler */
...@@ -900,12 +906,9 @@ static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -900,12 +906,9 @@ static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id)
init.num_parents = 1; init.num_parents = 1;
vc5->clk_mul.init = &init; vc5->clk_mul.init = &init;
ret = devm_clk_hw_register(&client->dev, &vc5->clk_mul); ret = devm_clk_hw_register(&client->dev, &vc5->clk_mul);
if (ret)
goto err_clk_register;
kfree(init.name); /* clock framework made a copy of the name */ kfree(init.name); /* clock framework made a copy of the name */
if (ret) {
dev_err(&client->dev, "unable to register %s\n",
init.name);
goto err_clk;
}
} }
/* Register PFD */ /* Register PFD */
...@@ -921,11 +924,9 @@ static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -921,11 +924,9 @@ static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id)
init.num_parents = 1; init.num_parents = 1;
vc5->clk_pfd.init = &init; vc5->clk_pfd.init = &init;
ret = devm_clk_hw_register(&client->dev, &vc5->clk_pfd); ret = devm_clk_hw_register(&client->dev, &vc5->clk_pfd);
if (ret)
goto err_clk_register;
kfree(init.name); /* clock framework made a copy of the name */ kfree(init.name); /* clock framework made a copy of the name */
if (ret) {
dev_err(&client->dev, "unable to register %s\n", init.name);
goto err_clk;
}
/* Register PLL */ /* Register PLL */
memset(&init, 0, sizeof(init)); memset(&init, 0, sizeof(init));
...@@ -939,11 +940,9 @@ static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -939,11 +940,9 @@ static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id)
vc5->clk_pll.vc5 = vc5; vc5->clk_pll.vc5 = vc5;
vc5->clk_pll.hw.init = &init; vc5->clk_pll.hw.init = &init;
ret = devm_clk_hw_register(&client->dev, &vc5->clk_pll.hw); ret = devm_clk_hw_register(&client->dev, &vc5->clk_pll.hw);
if (ret)
goto err_clk_register;
kfree(init.name); /* clock framework made a copy of the name */ kfree(init.name); /* clock framework made a copy of the name */
if (ret) {
dev_err(&client->dev, "unable to register %s\n", init.name);
goto err_clk;
}
/* Register FODs */ /* Register FODs */
for (n = 0; n < vc5->chip_info->clk_fod_cnt; n++) { for (n = 0; n < vc5->chip_info->clk_fod_cnt; n++) {
...@@ -960,12 +959,9 @@ static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -960,12 +959,9 @@ static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id)
vc5->clk_fod[n].vc5 = vc5; vc5->clk_fod[n].vc5 = vc5;
vc5->clk_fod[n].hw.init = &init; vc5->clk_fod[n].hw.init = &init;
ret = devm_clk_hw_register(&client->dev, &vc5->clk_fod[n].hw); ret = devm_clk_hw_register(&client->dev, &vc5->clk_fod[n].hw);
if (ret)
goto err_clk_register;
kfree(init.name); /* clock framework made a copy of the name */ kfree(init.name); /* clock framework made a copy of the name */
if (ret) {
dev_err(&client->dev, "unable to register %s\n",
init.name);
goto err_clk;
}
} }
/* Register MUX-connected OUT0_I2C_SELB output */ /* Register MUX-connected OUT0_I2C_SELB output */
...@@ -981,11 +977,9 @@ static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -981,11 +977,9 @@ static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id)
vc5->clk_out[0].vc5 = vc5; vc5->clk_out[0].vc5 = vc5;
vc5->clk_out[0].hw.init = &init; vc5->clk_out[0].hw.init = &init;
ret = devm_clk_hw_register(&client->dev, &vc5->clk_out[0].hw); ret = devm_clk_hw_register(&client->dev, &vc5->clk_out[0].hw);
kfree(init.name); /* clock framework made a copy of the name */ if (ret)
if (ret) { goto err_clk_register;
dev_err(&client->dev, "unable to register %s\n", init.name); kfree(init.name); /* clock framework made a copy of the name */
goto err_clk;
}
/* Register FOD-connected OUTx outputs */ /* Register FOD-connected OUTx outputs */
for (n = 1; n < vc5->chip_info->clk_out_cnt; n++) { for (n = 1; n < vc5->chip_info->clk_out_cnt; n++) {
...@@ -1008,12 +1002,9 @@ static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -1008,12 +1002,9 @@ static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id)
vc5->clk_out[n].vc5 = vc5; vc5->clk_out[n].vc5 = vc5;
vc5->clk_out[n].hw.init = &init; vc5->clk_out[n].hw.init = &init;
ret = devm_clk_hw_register(&client->dev, &vc5->clk_out[n].hw); ret = devm_clk_hw_register(&client->dev, &vc5->clk_out[n].hw);
if (ret)
goto err_clk_register;
kfree(init.name); /* clock framework made a copy of the name */ kfree(init.name); /* clock framework made a copy of the name */
if (ret) {
dev_err(&client->dev, "unable to register %s\n",
init.name);
goto err_clk;
}
/* Fetch Clock Output configuration from DT (if specified) */ /* Fetch Clock Output configuration from DT (if specified) */
ret = vc5_get_output_config(client, &vc5->clk_out[n]); ret = vc5_get_output_config(client, &vc5->clk_out[n]);
...@@ -1029,6 +1020,9 @@ static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -1029,6 +1020,9 @@ static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id)
return 0; return 0;
err_clk_register:
dev_err(&client->dev, "unable to register %s\n", init.name);
kfree(init.name); /* clock framework made a copy of the name */
err_clk: err_clk:
if (vc5->chip_info->flags & VC5_HAS_INTERNAL_XTAL) if (vc5->chip_info->flags & VC5_HAS_INTERNAL_XTAL)
clk_unregister_fixed_rate(vc5->pin_xin); clk_unregister_fixed_rate(vc5->pin_xin);
......
...@@ -500,12 +500,6 @@ static unsigned long clk_core_get_accuracy_no_lock(struct clk_core *core) ...@@ -500,12 +500,6 @@ static unsigned long clk_core_get_accuracy_no_lock(struct clk_core *core)
return core->accuracy; return core->accuracy;
} }
unsigned long __clk_get_flags(struct clk *clk)
{
return !clk ? 0 : clk->core->flags;
}
EXPORT_SYMBOL_GPL(__clk_get_flags);
unsigned long clk_hw_get_flags(const struct clk_hw *hw) unsigned long clk_hw_get_flags(const struct clk_hw *hw)
{ {
return hw->core->flags; return hw->core->flags;
...@@ -3054,6 +3048,31 @@ static int clk_rate_set(void *data, u64 val) ...@@ -3054,6 +3048,31 @@ static int clk_rate_set(void *data, u64 val)
} }
#define clk_rate_mode 0644 #define clk_rate_mode 0644
static int clk_prepare_enable_set(void *data, u64 val)
{
struct clk_core *core = data;
int ret = 0;
if (val)
ret = clk_prepare_enable(core->hw->clk);
else
clk_disable_unprepare(core->hw->clk);
return ret;
}
static int clk_prepare_enable_get(void *data, u64 *val)
{
struct clk_core *core = data;
*val = core->enable_count && core->prepare_count;
return 0;
}
DEFINE_DEBUGFS_ATTRIBUTE(clk_prepare_enable_fops, clk_prepare_enable_get,
clk_prepare_enable_set, "%llu\n");
#else #else
#define clk_rate_set NULL #define clk_rate_set NULL
#define clk_rate_mode 0444 #define clk_rate_mode 0444
...@@ -3231,6 +3250,10 @@ static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry) ...@@ -3231,6 +3250,10 @@ static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
debugfs_create_u32("clk_notifier_count", 0444, root, &core->notifier_count); debugfs_create_u32("clk_notifier_count", 0444, root, &core->notifier_count);
debugfs_create_file("clk_duty_cycle", 0444, root, core, debugfs_create_file("clk_duty_cycle", 0444, root, core,
&clk_duty_cycle_fops); &clk_duty_cycle_fops);
#ifdef CLOCK_ALLOW_WRITE_DEBUGFS
debugfs_create_file("clk_prepare_enable", 0644, root, core,
&clk_prepare_enable_fops);
#endif
if (core->num_parents > 0) if (core->num_parents > 0)
debugfs_create_file("clk_parent", 0444, root, core, debugfs_create_file("clk_parent", 0444, root, core,
...@@ -4135,6 +4158,7 @@ static int devm_clk_hw_match(struct device *dev, void *res, void *data) ...@@ -4135,6 +4158,7 @@ static int devm_clk_hw_match(struct device *dev, void *res, void *data)
/** /**
* devm_clk_unregister - resource managed clk_unregister() * devm_clk_unregister - resource managed clk_unregister()
* @dev: device that is unregistering the clock data
* @clk: clock to unregister * @clk: clock to unregister
* *
* Deallocate a clock allocated with devm_clk_register(). Normally * Deallocate a clock allocated with devm_clk_register(). Normally
...@@ -4324,6 +4348,8 @@ static void clk_core_reparent_orphans(void) ...@@ -4324,6 +4348,8 @@ static void clk_core_reparent_orphans(void)
* @node: Pointer to device tree node of clock provider * @node: Pointer to device tree node of clock provider
* @get: Get clock callback. Returns NULL or a struct clk for the * @get: Get clock callback. Returns NULL or a struct clk for the
* given clock specifier * given clock specifier
* @get_hw: Get clk_hw callback. Returns NULL, ERR_PTR or a
* struct clk_hw for the given clock specifier
* @data: context pointer to be passed into @get callback * @data: context pointer to be passed into @get callback
*/ */
struct of_clk_provider { struct of_clk_provider {
......
...@@ -651,7 +651,7 @@ static int davinci_pll_sysclk_rate_change(struct notifier_block *nb, ...@@ -651,7 +651,7 @@ static int davinci_pll_sysclk_rate_change(struct notifier_block *nb,
pllcmd = readl(pll->base + PLLCMD); pllcmd = readl(pll->base + PLLCMD);
pllcmd |= PLLCMD_GOSET; pllcmd |= PLLCMD_GOSET;
writel(pllcmd, pll->base + PLLCMD); writel(pllcmd, pll->base + PLLCMD);
/* fallthrough */ fallthrough;
case PRE_RATE_CHANGE: case PRE_RATE_CHANGE:
/* Wait until for outstanding changes to take effect */ /* Wait until for outstanding changes to take effect */
do { do {
......
...@@ -433,7 +433,7 @@ struct clk_hw *imx_clk_hw_pllv3(enum imx_pllv3_type type, const char *name, ...@@ -433,7 +433,7 @@ struct clk_hw *imx_clk_hw_pllv3(enum imx_pllv3_type type, const char *name,
break; break;
case IMX_PLLV3_USB_VF610: case IMX_PLLV3_USB_VF610:
pll->div_shift = 1; pll->div_shift = 1;
/* fall through */ fallthrough;
case IMX_PLLV3_USB: case IMX_PLLV3_USB:
ops = &clk_pllv3_ops; ops = &clk_pllv3_ops;
pll->powerup_set = true; pll->powerup_set = true;
...@@ -441,7 +441,7 @@ struct clk_hw *imx_clk_hw_pllv3(enum imx_pllv3_type type, const char *name, ...@@ -441,7 +441,7 @@ struct clk_hw *imx_clk_hw_pllv3(enum imx_pllv3_type type, const char *name,
case IMX_PLLV3_AV_IMX7: case IMX_PLLV3_AV_IMX7:
pll->num_offset = PLL_IMX7_NUM_OFFSET; pll->num_offset = PLL_IMX7_NUM_OFFSET;
pll->denom_offset = PLL_IMX7_DENOM_OFFSET; pll->denom_offset = PLL_IMX7_DENOM_OFFSET;
/* fall through */ fallthrough;
case IMX_PLLV3_AV: case IMX_PLLV3_AV:
ops = &clk_pllv3_av_ops; ops = &clk_pllv3_av_ops;
break; break;
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
* *
* Copyright (c) 2013-2015 Imagination Technologies * Copyright (c) 2013-2015 Imagination Technologies
* Author: Paul Burton <paul.burton@mips.com> * Author: Paul Burton <paul.burton@mips.com>
* Copyright (c) 2020 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
*/ */
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
...@@ -19,49 +20,50 @@ ...@@ -19,49 +20,50 @@
/* CGU register offsets */ /* CGU register offsets */
#define CGU_REG_CLOCKCONTROL 0x00 #define CGU_REG_CLOCKCONTROL 0x00
#define CGU_REG_LCR 0x04 #define CGU_REG_LCR 0x04
#define CGU_REG_APLL 0x10 #define CGU_REG_APLL 0x10
#define CGU_REG_MPLL 0x14 #define CGU_REG_MPLL 0x14
#define CGU_REG_EPLL 0x18 #define CGU_REG_EPLL 0x18
#define CGU_REG_VPLL 0x1c #define CGU_REG_VPLL 0x1c
#define CGU_REG_CLKGR0 0x20 #define CGU_REG_CLKGR0 0x20
#define CGU_REG_OPCR 0x24 #define CGU_REG_OPCR 0x24
#define CGU_REG_CLKGR1 0x28 #define CGU_REG_CLKGR1 0x28
#define CGU_REG_DDRCDR 0x2c #define CGU_REG_DDRCDR 0x2c
#define CGU_REG_VPUCDR 0x30 #define CGU_REG_VPUCDR 0x30
#define CGU_REG_USBPCR 0x3c #define CGU_REG_USBPCR 0x3c
#define CGU_REG_USBRDT 0x40 #define CGU_REG_USBRDT 0x40
#define CGU_REG_USBVBFIL 0x44 #define CGU_REG_USBVBFIL 0x44
#define CGU_REG_USBPCR1 0x48 #define CGU_REG_USBPCR1 0x48
#define CGU_REG_LP0CDR 0x54 #define CGU_REG_LP0CDR 0x54
#define CGU_REG_I2SCDR 0x60 #define CGU_REG_I2SCDR 0x60
#define CGU_REG_LP1CDR 0x64 #define CGU_REG_LP1CDR 0x64
#define CGU_REG_MSC0CDR 0x68 #define CGU_REG_MSC0CDR 0x68
#define CGU_REG_UHCCDR 0x6c #define CGU_REG_UHCCDR 0x6c
#define CGU_REG_SSICDR 0x74 #define CGU_REG_SSICDR 0x74
#define CGU_REG_CIMCDR 0x7c #define CGU_REG_CIMCDR 0x7c
#define CGU_REG_PCMCDR 0x84 #define CGU_REG_PCMCDR 0x84
#define CGU_REG_GPUCDR 0x88 #define CGU_REG_GPUCDR 0x88
#define CGU_REG_HDMICDR 0x8c #define CGU_REG_HDMICDR 0x8c
#define CGU_REG_MSC1CDR 0xa4 #define CGU_REG_MSC1CDR 0xa4
#define CGU_REG_MSC2CDR 0xa8 #define CGU_REG_MSC2CDR 0xa8
#define CGU_REG_BCHCDR 0xac #define CGU_REG_BCHCDR 0xac
#define CGU_REG_CLOCKSTATUS 0xd4 #define CGU_REG_CLOCKSTATUS 0xd4
/* bits within the OPCR register */ /* bits within the OPCR register */
#define OPCR_SPENDN0 BIT(7) #define OPCR_SPENDN0 BIT(7)
#define OPCR_SPENDN1 BIT(6) #define OPCR_SPENDN1 BIT(6)
/* bits within the USBPCR register */ /* bits within the USBPCR register */
#define USBPCR_USB_MODE BIT(31) #define USBPCR_USB_MODE BIT(31)
#define USBPCR_IDPULLUP_MASK (0x3 << 28) #define USBPCR_IDPULLUP_MASK (0x3 << 28)
#define USBPCR_COMMONONN BIT(25) #define USBPCR_COMMONONN BIT(25)
#define USBPCR_VBUSVLDEXT BIT(24) #define USBPCR_VBUSVLDEXT BIT(24)
#define USBPCR_VBUSVLDEXTSEL BIT(23) #define USBPCR_VBUSVLDEXTSEL BIT(23)
#define USBPCR_POR BIT(22) #define USBPCR_POR BIT(22)
#define USBPCR_OTG_DISABLE BIT(20) #define USBPCR_SIDDQ BIT(21)
#define USBPCR_OTG_DISABLE BIT(20)
#define USBPCR_COMPDISTUNE_MASK (0x7 << 17) #define USBPCR_COMPDISTUNE_MASK (0x7 << 17)
#define USBPCR_OTGTUNE_MASK (0x7 << 14) #define USBPCR_OTGTUNE_MASK (0x7 << 14)
#define USBPCR_SQRXTUNE_MASK (0x7 << 11) #define USBPCR_SQRXTUNE_MASK (0x7 << 11)
#define USBPCR_TXFSLSTUNE_MASK (0xf << 7) #define USBPCR_TXFSLSTUNE_MASK (0xf << 7)
#define USBPCR_TXPREEMPHTUNE BIT(6) #define USBPCR_TXPREEMPHTUNE BIT(6)
...@@ -78,13 +80,13 @@ ...@@ -78,13 +80,13 @@
#define USBPCR1_REFCLKDIV_48 (0x2 << USBPCR1_REFCLKDIV_SHIFT) #define USBPCR1_REFCLKDIV_48 (0x2 << USBPCR1_REFCLKDIV_SHIFT)
#define USBPCR1_REFCLKDIV_24 (0x1 << USBPCR1_REFCLKDIV_SHIFT) #define USBPCR1_REFCLKDIV_24 (0x1 << USBPCR1_REFCLKDIV_SHIFT)
#define USBPCR1_REFCLKDIV_12 (0x0 << USBPCR1_REFCLKDIV_SHIFT) #define USBPCR1_REFCLKDIV_12 (0x0 << USBPCR1_REFCLKDIV_SHIFT)
#define USBPCR1_USB_SEL BIT(28) #define USBPCR1_USB_SEL BIT(28)
#define USBPCR1_WORD_IF0 BIT(19) #define USBPCR1_WORD_IF0 BIT(19)
#define USBPCR1_WORD_IF1 BIT(18) #define USBPCR1_WORD_IF1 BIT(18)
/* bits within the USBRDT register */ /* bits within the USBRDT register */
#define USBRDT_VBFIL_LD_EN BIT(25) #define USBRDT_VBFIL_LD_EN BIT(25)
#define USBRDT_USBRDT_MASK 0x7fffff #define USBRDT_USBRDT_MASK 0x7fffff
/* bits within the USBVBFIL register */ /* bits within the USBVBFIL register */
#define USBVBFIL_IDDIGFIL_SHIFT 16 #define USBVBFIL_IDDIGFIL_SHIFT 16
...@@ -92,40 +94,14 @@ ...@@ -92,40 +94,14 @@
#define USBVBFIL_USBVBFIL_MASK (0xffff) #define USBVBFIL_USBVBFIL_MASK (0xffff)
/* bits within the LCR register */ /* bits within the LCR register */
#define LCR_PD_SCPU BIT(31) #define LCR_PD_SCPU BIT(31)
#define LCR_SCPUS BIT(27) #define LCR_SCPUS BIT(27)
/* bits within the CLKGR1 register */ /* bits within the CLKGR1 register */
#define CLKGR1_CORE1 BIT(15) #define CLKGR1_CORE1 BIT(15)
static struct ingenic_cgu *cgu; static struct ingenic_cgu *cgu;
static u8 jz4780_otg_phy_get_parent(struct clk_hw *hw)
{
/* we only use CLKCORE, revisit if that ever changes */
return 0;
}
static int jz4780_otg_phy_set_parent(struct clk_hw *hw, u8 idx)
{
unsigned long flags;
u32 usbpcr1;
if (idx > 0)
return -EINVAL;
spin_lock_irqsave(&cgu->lock, flags);
usbpcr1 = readl(cgu->base + CGU_REG_USBPCR1);
usbpcr1 &= ~USBPCR1_REFCLKSEL_MASK;
/* we only use CLKCORE */
usbpcr1 |= USBPCR1_REFCLKSEL_CORE;
writel(usbpcr1, cgu->base + CGU_REG_USBPCR1);
spin_unlock_irqrestore(&cgu->lock, flags);
return 0;
}
static unsigned long jz4780_otg_phy_recalc_rate(struct clk_hw *hw, static unsigned long jz4780_otg_phy_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate) unsigned long parent_rate)
{ {
...@@ -149,7 +125,6 @@ static unsigned long jz4780_otg_phy_recalc_rate(struct clk_hw *hw, ...@@ -149,7 +125,6 @@ static unsigned long jz4780_otg_phy_recalc_rate(struct clk_hw *hw,
return 19200000; return 19200000;
} }
BUG();
return parent_rate; return parent_rate;
} }
...@@ -206,13 +181,43 @@ static int jz4780_otg_phy_set_rate(struct clk_hw *hw, unsigned long req_rate, ...@@ -206,13 +181,43 @@ static int jz4780_otg_phy_set_rate(struct clk_hw *hw, unsigned long req_rate,
return 0; return 0;
} }
static const struct clk_ops jz4780_otg_phy_ops = { static int jz4780_otg_phy_enable(struct clk_hw *hw)
.get_parent = jz4780_otg_phy_get_parent, {
.set_parent = jz4780_otg_phy_set_parent, void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
void __iomem *reg_usbpcr = cgu->base + CGU_REG_USBPCR;
writel(readl(reg_opcr) | OPCR_SPENDN0, reg_opcr);
writel(readl(reg_usbpcr) & ~USBPCR_OTG_DISABLE & ~USBPCR_SIDDQ, reg_usbpcr);
return 0;
}
static void jz4780_otg_phy_disable(struct clk_hw *hw)
{
void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
void __iomem *reg_usbpcr = cgu->base + CGU_REG_USBPCR;
writel(readl(reg_opcr) & ~OPCR_SPENDN0, reg_opcr);
writel(readl(reg_usbpcr) | USBPCR_OTG_DISABLE | USBPCR_SIDDQ, reg_usbpcr);
}
static int jz4780_otg_phy_is_enabled(struct clk_hw *hw)
{
void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
void __iomem *reg_usbpcr = cgu->base + CGU_REG_USBPCR;
return (readl(reg_opcr) & OPCR_SPENDN0) &&
!(readl(reg_usbpcr) & USBPCR_SIDDQ) &&
!(readl(reg_usbpcr) & USBPCR_OTG_DISABLE);
}
static const struct clk_ops jz4780_otg_phy_ops = {
.recalc_rate = jz4780_otg_phy_recalc_rate, .recalc_rate = jz4780_otg_phy_recalc_rate,
.round_rate = jz4780_otg_phy_round_rate, .round_rate = jz4780_otg_phy_round_rate,
.set_rate = jz4780_otg_phy_set_rate, .set_rate = jz4780_otg_phy_set_rate,
.enable = jz4780_otg_phy_enable,
.disable = jz4780_otg_phy_disable,
.is_enabled = jz4780_otg_phy_is_enabled,
}; };
static int jz4780_core1_enable(struct clk_hw *hw) static int jz4780_core1_enable(struct clk_hw *hw)
...@@ -516,6 +521,18 @@ static const struct ingenic_cgu_clk_info jz4780_cgu_clocks[] = { ...@@ -516,6 +521,18 @@ static const struct ingenic_cgu_clk_info jz4780_cgu_clocks[] = {
.gate = { CGU_REG_CLKGR0, 1 }, .gate = { CGU_REG_CLKGR0, 1 },
}, },
[JZ4780_CLK_EXCLK_DIV512] = {
"exclk_div512", CGU_CLK_FIXDIV,
.parents = { JZ4780_CLK_EXCLK },
.fixdiv = { 512 },
},
[JZ4780_CLK_RTC] = {
"rtc_ercs", CGU_CLK_MUX | CGU_CLK_GATE,
.parents = { JZ4780_CLK_EXCLK_DIV512, JZ4780_CLK_RTCLK },
.mux = { CGU_REG_OPCR, 2, 1},
},
/* Gate-only clocks */ /* Gate-only clocks */
[JZ4780_CLK_NEMC] = { [JZ4780_CLK_NEMC] = {
......
...@@ -48,8 +48,87 @@ ...@@ -48,8 +48,87 @@
#define USBPCR_SIDDQ BIT(21) #define USBPCR_SIDDQ BIT(21)
#define USBPCR_OTG_DISABLE BIT(20) #define USBPCR_OTG_DISABLE BIT(20)
/* bits within the USBPCR1 register */
#define USBPCR1_REFCLKSEL_SHIFT 26
#define USBPCR1_REFCLKSEL_MASK (0x3 << USBPCR1_REFCLKSEL_SHIFT)
#define USBPCR1_REFCLKSEL_CORE (0x2 << USBPCR1_REFCLKSEL_SHIFT)
#define USBPCR1_REFCLKDIV_SHIFT 24
#define USBPCR1_REFCLKDIV_MASK (0x3 << USBPCR1_REFCLKDIV_SHIFT)
#define USBPCR1_REFCLKDIV_48 (0x2 << USBPCR1_REFCLKDIV_SHIFT)
#define USBPCR1_REFCLKDIV_24 (0x1 << USBPCR1_REFCLKDIV_SHIFT)
#define USBPCR1_REFCLKDIV_12 (0x0 << USBPCR1_REFCLKDIV_SHIFT)
static struct ingenic_cgu *cgu; static struct ingenic_cgu *cgu;
static unsigned long x1000_otg_phy_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
u32 usbpcr1;
unsigned refclk_div;
usbpcr1 = readl(cgu->base + CGU_REG_USBPCR1);
refclk_div = usbpcr1 & USBPCR1_REFCLKDIV_MASK;
switch (refclk_div) {
case USBPCR1_REFCLKDIV_12:
return 12000000;
case USBPCR1_REFCLKDIV_24:
return 24000000;
case USBPCR1_REFCLKDIV_48:
return 48000000;
}
return parent_rate;
}
static long x1000_otg_phy_round_rate(struct clk_hw *hw, unsigned long req_rate,
unsigned long *parent_rate)
{
if (req_rate < 18000000)
return 12000000;
if (req_rate < 36000000)
return 24000000;
return 48000000;
}
static int x1000_otg_phy_set_rate(struct clk_hw *hw, unsigned long req_rate,
unsigned long parent_rate)
{
unsigned long flags;
u32 usbpcr1, div_bits;
switch (req_rate) {
case 12000000:
div_bits = USBPCR1_REFCLKDIV_12;
break;
case 24000000:
div_bits = USBPCR1_REFCLKDIV_24;
break;
case 48000000:
div_bits = USBPCR1_REFCLKDIV_48;
break;
default:
return -EINVAL;
}
spin_lock_irqsave(&cgu->lock, flags);
usbpcr1 = readl(cgu->base + CGU_REG_USBPCR1);
usbpcr1 &= ~USBPCR1_REFCLKDIV_MASK;
usbpcr1 |= div_bits;
writel(usbpcr1, cgu->base + CGU_REG_USBPCR1);
spin_unlock_irqrestore(&cgu->lock, flags);
return 0;
}
static int x1000_usb_phy_enable(struct clk_hw *hw) static int x1000_usb_phy_enable(struct clk_hw *hw)
{ {
void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR; void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
...@@ -80,6 +159,10 @@ static int x1000_usb_phy_is_enabled(struct clk_hw *hw) ...@@ -80,6 +159,10 @@ static int x1000_usb_phy_is_enabled(struct clk_hw *hw)
} }
static const struct clk_ops x1000_otg_phy_ops = { static const struct clk_ops x1000_otg_phy_ops = {
.recalc_rate = x1000_otg_phy_recalc_rate,
.round_rate = x1000_otg_phy_round_rate,
.set_rate = x1000_otg_phy_set_rate,
.enable = x1000_usb_phy_enable, .enable = x1000_usb_phy_enable,
.disable = x1000_usb_phy_disable, .disable = x1000_usb_phy_disable,
.is_enabled = x1000_usb_phy_is_enabled, .is_enabled = x1000_usb_phy_is_enabled,
...@@ -144,7 +227,6 @@ static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = { ...@@ -144,7 +227,6 @@ static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = {
}, },
}, },
/* Custom (SoC-specific) OTG PHY */ /* Custom (SoC-specific) OTG PHY */
[X1000_CLK_OTGPHY] = { [X1000_CLK_OTGPHY] = {
...@@ -278,6 +360,19 @@ static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = { ...@@ -278,6 +360,19 @@ static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = {
.mux = { CGU_REG_SSICDR, 30, 1 }, .mux = { CGU_REG_SSICDR, 30, 1 },
}, },
[X1000_CLK_EXCLK_DIV512] = {
"exclk_div512", CGU_CLK_FIXDIV,
.parents = { X1000_CLK_EXCLK },
.fixdiv = { 512 },
},
[X1000_CLK_RTC] = {
"rtc_ercs", CGU_CLK_MUX | CGU_CLK_GATE,
.parents = { X1000_CLK_EXCLK_DIV512, X1000_CLK_RTCLK },
.mux = { CGU_REG_OPCR, 2, 1},
.gate = { CGU_REG_CLKGR, 27 },
},
/* Gate-only clocks */ /* Gate-only clocks */
[X1000_CLK_EMC] = { [X1000_CLK_EMC] = {
......
...@@ -329,6 +329,19 @@ static const struct ingenic_cgu_clk_info x1830_cgu_clocks[] = { ...@@ -329,6 +329,19 @@ static const struct ingenic_cgu_clk_info x1830_cgu_clocks[] = {
.mux = { CGU_REG_SSICDR, 29, 1 }, .mux = { CGU_REG_SSICDR, 29, 1 },
}, },
[X1830_CLK_EXCLK_DIV512] = {
"exclk_div512", CGU_CLK_FIXDIV,
.parents = { X1830_CLK_EXCLK },
.fixdiv = { 512 },
},
[X1830_CLK_RTC] = {
"rtc_ercs", CGU_CLK_MUX | CGU_CLK_GATE,
.parents = { X1830_CLK_EXCLK_DIV512, X1830_CLK_RTCLK },
.mux = { CGU_REG_OPCR, 2, 1},
.gate = { CGU_REG_CLKGR0, 29 },
},
/* Gate-only clocks */ /* Gate-only clocks */
[X1830_CLK_EMC] = { [X1830_CLK_EMC] = {
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
*/ */
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/clk/mmp.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
*/ */
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/clk/mmp.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
......
...@@ -308,6 +308,15 @@ config SC_GCC_7180 ...@@ -308,6 +308,15 @@ config SC_GCC_7180
Say Y if you want to use peripheral devices such as UART, SPI, Say Y if you want to use peripheral devices such as UART, SPI,
I2C, USB, UFS, SDCC, etc. I2C, USB, UFS, SDCC, etc.
config SC_LPASS_CORECC_7180
tristate "SC7180 LPASS Core Clock Controller"
select SC_GCC_7180
help
Support for the LPASS(Low Power Audio Subsystem) core clock controller
on SC7180 devices.
Say Y if you want to use LPASS clocks and power domains of the LPASS
core clock controller.
config SC_GPUCC_7180 config SC_GPUCC_7180
tristate "SC7180 Graphics Clock Controller" tristate "SC7180 Graphics Clock Controller"
select SC_GCC_7180 select SC_GCC_7180
...@@ -419,6 +428,22 @@ config SM_GCC_8250 ...@@ -419,6 +428,22 @@ config SM_GCC_8250
Say Y if you want to use peripheral devices such as UART, Say Y if you want to use peripheral devices such as UART,
SPI, I2C, USB, SD/UFS, PCIe etc. SPI, I2C, USB, SD/UFS, PCIe etc.
config SM_GPUCC_8150
tristate "SM8150 Graphics Clock Controller"
select SM_GCC_8150
help
Support for the graphics clock controller on SM8150 devices.
Say Y if you want to support graphics controller devices and
functionality such as 3D graphics.
config SM_GPUCC_8250
tristate "SM8250 Graphics Clock Controller"
select SM_GCC_8250
help
Support for the graphics clock controller on SM8250 devices.
Say Y if you want to support graphics controller devices and
functionality such as 3D graphics.
config SPMI_PMIC_CLKDIV config SPMI_PMIC_CLKDIV
tristate "SPMI PMIC clkdiv Support" tristate "SPMI PMIC clkdiv Support"
depends on SPMI || COMPILE_TEST depends on SPMI || COMPILE_TEST
......
...@@ -54,6 +54,7 @@ obj-$(CONFIG_QCS_TURING_404) += turingcc-qcs404.o ...@@ -54,6 +54,7 @@ obj-$(CONFIG_QCS_TURING_404) += turingcc-qcs404.o
obj-$(CONFIG_SC_DISPCC_7180) += dispcc-sc7180.o obj-$(CONFIG_SC_DISPCC_7180) += dispcc-sc7180.o
obj-$(CONFIG_SC_GCC_7180) += gcc-sc7180.o obj-$(CONFIG_SC_GCC_7180) += gcc-sc7180.o
obj-$(CONFIG_SC_GPUCC_7180) += gpucc-sc7180.o obj-$(CONFIG_SC_GPUCC_7180) += gpucc-sc7180.o
obj-$(CONFIG_SC_LPASS_CORECC_7180) += lpasscorecc-sc7180.o
obj-$(CONFIG_SC_MSS_7180) += mss-sc7180.o obj-$(CONFIG_SC_MSS_7180) += mss-sc7180.o
obj-$(CONFIG_SC_VIDEOCC_7180) += videocc-sc7180.o obj-$(CONFIG_SC_VIDEOCC_7180) += videocc-sc7180.o
obj-$(CONFIG_SDM_CAMCC_845) += camcc-sdm845.o obj-$(CONFIG_SDM_CAMCC_845) += camcc-sdm845.o
...@@ -65,6 +66,8 @@ obj-$(CONFIG_SDM_LPASSCC_845) += lpasscc-sdm845.o ...@@ -65,6 +66,8 @@ obj-$(CONFIG_SDM_LPASSCC_845) += lpasscc-sdm845.o
obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o
obj-$(CONFIG_SM_GCC_8150) += gcc-sm8150.o obj-$(CONFIG_SM_GCC_8150) += gcc-sm8150.o
obj-$(CONFIG_SM_GCC_8250) += gcc-sm8250.o obj-$(CONFIG_SM_GCC_8250) += gcc-sm8250.o
obj-$(CONFIG_SM_GPUCC_8150) += gpucc-sm8150.o
obj-$(CONFIG_SM_GPUCC_8250) += gpucc-sm8250.o
obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o obj-$(CONFIG_SPMI_PMIC_CLKDIV) += clk-spmi-pmic-div.o
obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o
obj-$(CONFIG_QCOM_HFPLL) += hfpll.o obj-$(CONFIG_QCOM_HFPLL) += hfpll.o
......
This diff is collapsed.
...@@ -14,7 +14,7 @@ enum { ...@@ -14,7 +14,7 @@ enum {
CLK_ALPHA_PLL_TYPE_BRAMMO, CLK_ALPHA_PLL_TYPE_BRAMMO,
CLK_ALPHA_PLL_TYPE_FABIA, CLK_ALPHA_PLL_TYPE_FABIA,
CLK_ALPHA_PLL_TYPE_TRION, CLK_ALPHA_PLL_TYPE_TRION,
CLK_ALPHA_PLL_TYPE_LUCID, CLK_ALPHA_PLL_TYPE_LUCID = CLK_ALPHA_PLL_TYPE_TRION,
CLK_ALPHA_PLL_TYPE_MAX, CLK_ALPHA_PLL_TYPE_MAX,
}; };
...@@ -134,18 +134,23 @@ extern const struct clk_ops clk_alpha_pll_fabia_ops; ...@@ -134,18 +134,23 @@ extern const struct clk_ops clk_alpha_pll_fabia_ops;
extern const struct clk_ops clk_alpha_pll_fixed_fabia_ops; extern const struct clk_ops clk_alpha_pll_fixed_fabia_ops;
extern const struct clk_ops clk_alpha_pll_postdiv_fabia_ops; extern const struct clk_ops clk_alpha_pll_postdiv_fabia_ops;
extern const struct clk_ops clk_alpha_pll_trion_ops;
extern const struct clk_ops clk_alpha_pll_fixed_trion_ops;
extern const struct clk_ops clk_alpha_pll_postdiv_trion_ops;
extern const struct clk_ops clk_alpha_pll_lucid_ops; extern const struct clk_ops clk_alpha_pll_lucid_ops;
extern const struct clk_ops clk_alpha_pll_fixed_lucid_ops; #define clk_alpha_pll_fixed_lucid_ops clk_alpha_pll_fixed_trion_ops
extern const struct clk_ops clk_alpha_pll_postdiv_lucid_ops; extern const struct clk_ops clk_alpha_pll_postdiv_lucid_ops;
void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
const struct alpha_pll_config *config); const struct alpha_pll_config *config);
void clk_fabia_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, void clk_fabia_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
const struct alpha_pll_config *config); const struct alpha_pll_config *config);
void clk_lucid_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, void clk_trion_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
const struct alpha_pll_config *config); const struct alpha_pll_config *config);
#define clk_lucid_pll_configure(pll, regmap, config) \
clk_trion_pll_configure(pll, regmap, config)
extern const struct clk_ops clk_trion_fixed_pll_ops;
extern const struct clk_ops clk_trion_pll_postdiv_ops;
#endif #endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment