Commit 6f630784 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 clk updates from Stephen Boyd:
 "This time around we have four lines of diff in the core framework,
  removing a function that isn't used anymore. Otherwise the main new
  thing for the common clk framework is that it is selectable in the
  Kconfig language now. Hopefully this will let clk drivers and clk
  consumers be testable on more than the architectures that support the
  clk framework. The goal is to introduce some Kunit tests for the
  framework.

  Outside of the core framework we have the usual set of various driver
  updates and non-critical fixes. The dirstat shows that the new
  Baikal-T1 driver is the largest addition this time around in terms of
  lines of code. After that the x86 (Intel), Qualcomm, and Mediatek
  drivers introduce many lines to support new or upcoming SoCs. After
  that the dirstat shows the usual suspects working on their SoC support
  by fixing minor bugs, correcting data and converting some of their DT
  bindings to YAML.

  Core:
   - Allow the COMMON_CLK config to be selectable

  New Drivers:
   - Clk driver for Baikal-T1 SoCs
   - Mediatek MT6765 clock support
   - Support for Intel Agilex clks
   - Add support for X1830 and X1000 Ingenic SoC clk controllers
   - Add support for the new Renesas RZ/G1H (R8A7742) SoC
   - Add support for Qualcomm's MSM8939 Generic Clock Controller

  Updates:
   - Support IDT VersaClock 5P49V5925
   - Bunch of updates for HSDK clock generation unit (CGU) driver
   - Start making audio and GPU clks work on Marvell MMP2/MMP3 SoCs
   - Add some GPU, NPU, and UFS clks to Qualcomm SM8150 driver
   - Enable supply regulators for GPU gdscs on Qualcomm SoCs
   - Add support for Si5342, Si5344 and Si5345 chips
   - Support custom flags in Xilinx zynq firmware
   - Various small fixes to the Xilinx clk driver
   - A single minor rounding fix for the legacy Allwinner clock support
   - A few patches from Abel Vesa as preparation of adding audiomix
     clock support on i.MX
   - A couple of cleanups from Anson Huang for i.MX clk-sscg-pll and
     clk-pllv3 drivers
   - Drop dependency on ARM64 for i.MX8M clock driver, to support
     aarch32 mode on aarch64 hardware
   - A series from Peng Fan to improve i.MX8M clock drivers, using
     composite clock for core and bus clk slice
   - Set a better parent clock for flexcan on i.MX6UL to support CiA102
     defined bit rates
   - A couple changes for EMC frequency scaling on Tegra210
   - Support for CPU frequency scaling on Tegra20/Tegra30
   - New clk gate for CSI test pattern generator on Tegra210
   - Regression fixes for Samsung exynos542x and exynos5433 SoCs
   - Use of fallthrough; attribute for Samsung s3c24xx
   - Updates and fixup HDMI and video clocks on Meson8b
   - Fixup reset polarity on Meson8b
   - Fix GPU glitch free mux switch on Meson gx and g12
   - A minor fix for the currently unused suspend/resume handling on
     Renesas RZ/A1 and RZ/A2
   - Two more conversions of Renesas DT bindings to json-schema
   - Add support for the USB 2.0 clock selector on Renesas R-Car M3-W+"

* tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (155 commits)
  clk: mediatek: Remove ifr{0,1}_cfg_regs structures
  clk: baikal-t1: remove redundant assignment to variable 'divider'
  clk: baikal-t1: fix spelling mistake "Uncompatible" -> "Incompatible"
  dt-bindings: clock: Add a missing include to MMP Audio Clock binding
  dt: Add bindings for IDT VersaClock 5P49V5925
  clk: vc5: Add support for IDT VersaClock 5P49V6965
  clk: Add Baikal-T1 CCU Dividers driver
  clk: Add Baikal-T1 CCU PLLs driver
  dt-bindings: clk: Add Baikal-T1 CCU Dividers binding
  dt-bindings: clk: Add Baikal-T1 CCU PLLs binding
  clk: mediatek: assign the initial value to clk_init_data of mtk_mux
  clk: mediatek: Add MT6765 clock support
  clk: mediatek: add mt6765 clock IDs
  dt-bindings: clock: mediatek: document clk bindings vcodecsys for Mediatek MT6765 SoC
  dt-bindings: clock: mediatek: document clk bindings mipi0a for Mediatek MT6765 SoC
  dt-bindings: clock: mediatek: document clk bindings for Mediatek MT6765 SoC
  CLK: HSDK: CGU: add support for 148.5MHz clock
  CLK: HSDK: CGU: support PLL bypassing
  CLK: HSDK: CGU: check if PLL is bypassed first
  clk: clk-si5341: Add support for the Si5345 series
  ...
parents 3a2a8751 9ac1eafa
......@@ -8,6 +8,7 @@ Required Properties:
- compatible: Should be one of:
- "mediatek,mt2701-apmixedsys"
- "mediatek,mt2712-apmixedsys", "syscon"
- "mediatek,mt6765-apmixedsys", "syscon"
- "mediatek,mt6779-apmixedsys", "syscon"
- "mediatek,mt6797-apmixedsys"
- "mediatek,mt7622-apmixedsys"
......
......@@ -7,6 +7,7 @@ Required Properties:
- compatible: Should be one of:
- "mediatek,mt2701-audsys", "syscon"
- "mediatek,mt6765-audsys", "syscon"
- "mediatek,mt6779-audio", "syscon"
- "mediatek,mt7622-audsys", "syscon"
- "mediatek,mt7623-audsys", "mediatek,mt2701-audsys", "syscon"
......
......@@ -6,6 +6,7 @@ The MediaTek camsys controller provides various clocks to the system.
Required Properties:
- compatible: Should be one of:
- "mediatek,mt6765-camsys", "syscon"
- "mediatek,mt6779-camsys", "syscon"
- "mediatek,mt8183-camsys", "syscon"
- #clock-cells: Must be 1
......
......@@ -8,6 +8,7 @@ Required Properties:
- compatible: Should be one of:
- "mediatek,mt2701-imgsys", "syscon"
- "mediatek,mt2712-imgsys", "syscon"
- "mediatek,mt6765-imgsys", "syscon"
- "mediatek,mt6779-imgsys", "syscon"
- "mediatek,mt6797-imgsys", "syscon"
- "mediatek,mt7623-imgsys", "mediatek,mt2701-imgsys", "syscon"
......
......@@ -9,6 +9,7 @@ Required Properties:
- compatible: Should be one of:
- "mediatek,mt2701-infracfg", "syscon"
- "mediatek,mt2712-infracfg", "syscon"
- "mediatek,mt6765-infracfg", "syscon"
- "mediatek,mt6779-infracfg_ao", "syscon"
- "mediatek,mt6797-infracfg", "syscon"
- "mediatek,mt7622-infracfg", "syscon"
......
Mediatek mipi0a (mipi_rx_ana_csi0a) controller
============================
The Mediatek mipi0a controller provides various clocks
to the system.
Required Properties:
- compatible: Should be one of:
- "mediatek,mt6765-mipi0a", "syscon"
- #clock-cells: Must be 1
The mipi0a controller uses the common clk binding from
Documentation/devicetree/bindings/clock/clock-bindings.txt
The available clocks are defined in dt-bindings/clock/mt*-clk.h.
The mipi0a controller also uses the common power domain from
Documentation/devicetree/bindings/soc/mediatek/scpsys.txt
The available power doamins are defined in dt-bindings/power/mt*-power.h.
Example:
mipi0a: clock-controller@11c10000 {
compatible = "mediatek,mt6765-mipi0a", "syscon";
reg = <0 0x11c10000 0 0x1000>;
power-domains = <&scpsys MT6765_POWER_DOMAIN_CAM>;
#clock-cells = <1>;
};
......@@ -9,6 +9,7 @@ Required Properties:
- compatible: Should be one of:
- "mediatek,mt2701-mmsys", "syscon"
- "mediatek,mt2712-mmsys", "syscon"
- "mediatek,mt6765-mmsys", "syscon"
- "mediatek,mt6779-mmsys", "syscon"
- "mediatek,mt6797-mmsys", "syscon"
- "mediatek,mt7623-mmsys", "mediatek,mt2701-mmsys", "syscon"
......
......@@ -20,6 +20,7 @@ properties:
- enum:
- mediatek,mt2701-pericfg
- mediatek,mt2712-pericfg
- mediatek,mt6765-pericfg
- mediatek,mt7622-pericfg
- mediatek,mt7629-pericfg
- mediatek,mt8135-pericfg
......
......@@ -8,6 +8,7 @@ Required Properties:
- compatible: Should be one of:
- "mediatek,mt2701-topckgen"
- "mediatek,mt2712-topckgen", "syscon"
- "mediatek,mt6765-topckgen", "syscon"
- "mediatek,mt6779-topckgen", "syscon"
- "mediatek,mt6797-topckgen"
- "mediatek,mt7622-topckgen"
......
Mediatek vcodecsys controller
============================
The Mediatek vcodecsys controller provides various clocks to the system.
Required Properties:
- compatible: Should be one of:
- "mediatek,mt6765-vcodecsys", "syscon"
- #clock-cells: Must be 1
The vcodecsys controller uses the common clk binding from
Documentation/devicetree/bindings/clock/clock-bindings.txt
The available clocks are defined in dt-bindings/clock/mt*-clk.h.
The vcodecsys controller also uses the common power domain from
Documentation/devicetree/bindings/soc/mediatek/scpsys.txt
The available power doamins are defined in dt-bindings/power/mt*-power.h.
Example:
venc_gcon: clock-controller@17000000 {
compatible = "mediatek,mt6765-vcodecsys", "syscon";
reg = <0 0x17000000 0 0x10000>;
power-domains = <&scpsys MT6765_POWER_DOMAIN_VCODEC>;
#clock-cells = <1>;
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (C) 2020 BAIKAL ELECTRONICS, JSC
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/baikal,bt1-ccu-div.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Baikal-T1 Clock Control Unit Dividers
maintainers:
- Serge Semin <fancer.lancer@gmail.com>
description: |
Clocks Control Unit is the core of Baikal-T1 SoC System Controller
responsible for the chip subsystems clocking and resetting. The CCU is
connected with an external fixed rate oscillator, which signal is transformed
into clocks of various frequencies and then propagated to either individual
IP-blocks or to groups of blocks (clock domains). The transformation is done
by means of an embedded into CCU PLLs and gateable/non-gateable dividers. The
later ones are described in this binding. Each clock domain can be also
individually reset by using the domain clocks divider configuration
registers. Baikal-T1 CCU is logically divided into the next components:
1) External oscillator (normally XTAL's 25 MHz crystal oscillator, but
in general can provide any frequency supported by the CCU PLLs).
2) PLLs clocks generators (PLLs).
3) AXI-bus clock dividers (AXI) - described in this binding file.
4) System devices reference clock dividers (SYS) - described in this binding
file.
which are connected with each other as shown on the next figure:
+---------------+
| Baikal-T1 CCU |
| +----+------|- MIPS P5600 cores
| +-|PLLs|------|- DDR controller
| | +----+ |
+----+ | | | | |
|XTAL|--|-+ | | +---+-|
+----+ | | | +-|AXI|-|- AXI-bus
| | | +---+-|
| | | |
| | +----+---+-|- APB-bus
| +-------|SYS|-|- Low-speed Devices
| +---+-|- High-speed Devices
+---------------+
Each sub-block is represented as a separate DT node and has an individual
driver to be bound with.
In order to create signals of wide range frequencies the external oscillator
output is primarily connected to a set of CCU PLLs. Some of PLLs CLKOUT are
then passed over CCU dividers to create signals required for the target clock
domain (like AXI-bus or System Device consumers). The dividers have the
following structure:
+--------------+
CLKIN --|->+----+ 1|\ |
SETCLK--|--|/DIV|->| | |
CLKDIV--|--| | | |-|->CLKLOUT
LOCK----|--+----+ | | |
| |/ |
| | |
EN------|-----------+ |
RST-----|--------------|->RSTOUT
+--------------+
where CLKIN is the reference clock coming either from CCU PLLs or from an
external clock oscillator, SETCLK - a command to update the output clock in
accordance with a set divider, CLKDIV - clocks divider, LOCK - a signal of
the output clock stabilization, EN - enable/disable the divider block,
RST/RSTOUT - reset clocks domain signal. Depending on the consumer IP-core
peculiarities the dividers may lack of some functionality depicted on the
figure above (like EN, CLKDIV/LOCK/SETCLK). In this case the corresponding
clock provider just doesn't expose either switching functions, or the rate
configuration, or both of them.
The clock dividers, which output clock is then consumed by the SoC individual
devices, are united into a single clocks provider called System Devices CCU.
Similarly the dividers with output clocks utilized as AXI-bus reference clocks
are called AXI-bus CCU. Both of them use the common clock bindings with no
custom properties. The list of exported clocks and reset signals can be found
in the files: 'include/dt-bindings/clock/bt1-ccu.h' and
'include/dt-bindings/reset/bt1-ccu.h'. Since System Devices and AXI-bus CCU
are a part of the Baikal-T1 SoC System Controller their DT nodes are supposed
to be a children of later one.
if:
properties:
compatible:
contains:
const: baikal,bt1-ccu-axi
then:
properties:
clocks:
items:
- description: CCU SATA PLL output clock
- description: CCU PCIe PLL output clock
- description: CCU Ethernet PLL output clock
clock-names:
items:
- const: sata_clk
- const: pcie_clk
- const: eth_clk
else:
properties:
clocks:
items:
- description: External reference clock
- description: CCU SATA PLL output clock
- description: CCU PCIe PLL output clock
- description: CCU Ethernet PLL output clock
clock-names:
items:
- const: ref_clk
- const: sata_clk
- const: pcie_clk
- const: eth_clk
properties:
compatible:
enum:
- baikal,bt1-ccu-axi
- baikal,bt1-ccu-sys
reg:
maxItems: 1
"#clock-cells":
const: 1
"#reset-cells":
const: 1
unevaluatedProperties: false
required:
- compatible
- "#clock-cells"
- clocks
- clock-names
examples:
# AXI-bus Clock Control Unit node:
- |
#include <dt-bindings/clock/bt1-ccu.h>
clock-controller@1f04d030 {
compatible = "baikal,bt1-ccu-axi";
reg = <0x1f04d030 0x030>;
#clock-cells = <1>;
#reset-cells = <1>;
clocks = <&ccu_pll CCU_SATA_PLL>,
<&ccu_pll CCU_PCIE_PLL>,
<&ccu_pll CCU_ETH_PLL>;
clock-names = "sata_clk", "pcie_clk", "eth_clk";
};
# System Devices Clock Control Unit node:
- |
#include <dt-bindings/clock/bt1-ccu.h>
clock-controller@1f04d060 {
compatible = "baikal,bt1-ccu-sys";
reg = <0x1f04d060 0x0a0>;
#clock-cells = <1>;
#reset-cells = <1>;
clocks = <&clk25m>,
<&ccu_pll CCU_SATA_PLL>,
<&ccu_pll CCU_PCIE_PLL>,
<&ccu_pll CCU_ETH_PLL>;
clock-names = "ref_clk", "sata_clk", "pcie_clk",
"eth_clk";
};
# Required Clock Control Unit PLL node:
- |
ccu_pll: clock-controller@1f04d000 {
compatible = "baikal,bt1-ccu-pll";
reg = <0x1f04d000 0x028>;
#clock-cells = <1>;
clocks = <&clk25m>;
clock-names = "ref_clk";
};
...
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (C) 2020 BAIKAL ELECTRONICS, JSC
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/baikal,bt1-ccu-pll.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Baikal-T1 Clock Control Unit PLL
maintainers:
- Serge Semin <fancer.lancer@gmail.com>
description: |
Clocks Control Unit is the core of Baikal-T1 SoC System Controller
responsible for the chip subsystems clocking and resetting. The CCU is
connected with an external fixed rate oscillator, which signal is transformed
into clocks of various frequencies and then propagated to either individual
IP-blocks or to groups of blocks (clock domains). The transformation is done
by means of PLLs and gateable/non-gateable dividers embedded into the CCU.
It's logically divided into the next components:
1) External oscillator (normally XTAL's 25 MHz crystal oscillator, but
in general can provide any frequency supported by the CCU PLLs).
2) PLLs clocks generators (PLLs) - described in this binding file.
3) AXI-bus clock dividers (AXI).
4) System devices reference clock dividers (SYS).
which are connected with each other as shown on the next figure:
+---------------+
| Baikal-T1 CCU |
| +----+------|- MIPS P5600 cores
| +-|PLLs|------|- DDR controller
| | +----+ |
+----+ | | | | |
|XTAL|--|-+ | | +---+-|
+----+ | | | +-|AXI|-|- AXI-bus
| | | +---+-|
| | | |
| | +----+---+-|- APB-bus
| +-------|SYS|-|- Low-speed Devices
| +---+-|- High-speed Devices
+---------------+
Each CCU sub-block is represented as a separate dts-node and has an
individual driver to be bound with.
In order to create signals of wide range frequencies the external oscillator
output is primarily connected to a set of CCU PLLs. There are five PLLs
to create a clock for the MIPS P5600 cores, the embedded DDR controller,
SATA, Ethernet and PCIe domains. The last three domains though named by the
biggest system interfaces in fact include nearly all of the rest SoC
peripherals. Each of the PLLs is based on True Circuits TSMC CLN28HPM core
with an interface wrapper (so called safe PLL' clocks switcher) to simplify
the PLL configuration procedure. The PLLs work as depicted on the next
diagram:
+--------------------------+
| |
+-->+---+ +---+ +---+ | +---+ 0|\
CLKF--->|/NF|--->|PFD|...|VCO|-+->|/OD|--->| |
+---+ +->+---+ +---+ /->+---+ | |--->CLKOUT
CLKOD---------C----------------+ 1| |
+--------C--------------------------->|/
| | ^
Rclk-+->+---+ | |
CLKR--->|/NR|-+ |
+---+ |
BYPASS--------------------------------------+
BWADJ--->
where Rclk is the reference clock coming from XTAL, NR - reference clock
divider, NF - PLL clock multiplier, OD - VCO output clock divider, CLKOUT -
output clock, BWADJ is the PLL bandwidth adjustment parameter. At this moment
the binding supports the PLL dividers configuration in accordance with a
requested rate, while bypassing and bandwidth adjustment settings can be
added in future if it gets to be necessary.
The PLLs CLKOUT is then either directly connected with the corresponding
clocks consumer (like P5600 cores or DDR controller) or passed over a CCU
divider to create a signal required for the clock domain.
The CCU PLL dts-node uses the common clock bindings with no custom
parameters. The list of exported clocks can be found in
'include/dt-bindings/clock/bt1-ccu.h'. Since CCU PLL is a part of the
Baikal-T1 SoC System Controller its DT node is supposed to be a child of
later one.
properties:
compatible:
const: baikal,bt1-ccu-pll
reg:
maxItems: 1
"#clock-cells":
const: 1
clocks:
description: External reference clock
maxItems: 1
clock-names:
const: ref_clk
unevaluatedProperties: false
required:
- compatible
- "#clock-cells"
- clocks
- clock-names
examples:
# Clock Control Unit PLL node:
- |
clock-controller@1f04d000 {
compatible = "baikal,bt1-ccu-pll";
reg = <0x1f04d000 0x028>;
#clock-cells = <1>;
clocks = <&clk25m>;
clock-names = "ref_clk";
};
# Required external oscillator:
- |
clk25m: clock-oscillator-25m {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <25000000>;
clock-output-names = "clk25m";
};
...
......@@ -12,6 +12,7 @@ Required properties:
"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,
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/intel,agilex.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Intel SoCFPGA Agilex platform clock controller binding
maintainers:
- Dinh Nguyen <dinguyen@kernel.org>
description:
The Intel Agilex Clock controller is an integrated clock controller, which
generates and supplies to all modules.
properties:
compatible:
const: intel,agilex-clkmgr
'#clock-cells':
const: 1
reg:
maxItems: 1
clocks:
maxItems: 1
required:
- compatible
- reg
- clocks
- '#clock-cells'
additionalProperties: false
examples:
# Clock controller node:
- |
clkmgr: clock-controller@ffd10000 {
compatible = "intel,agilex-clkmgr";
reg = <0xffd10000 0x1000>;
clocks = <&osc1>;
#clock-cells = <1>;
};
...
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/intel,cgu-lgm.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Intel Lightning Mountain SoC's Clock Controller(CGU) Binding
maintainers:
- Rahul Tanwar <rahul.tanwar@linux.intel.com>
description: |
Lightning Mountain(LGM) SoC's Clock Generation Unit(CGU) driver provides
all means to access the CGU hardware module in order to generate a series
of clocks for the whole system and individual peripherals.
Please refer to include/dt-bindings/clock/intel,lgm-clk.h header file, it
defines all available clocks as macros. These macros can be used in device
tree sources.
properties:
compatible:
const: intel,cgu-lgm
reg:
maxItems: 1
'#clock-cells':
const: 1
required:
- compatible
- reg
- '#clock-cells'
examples:
- |
cgu: clock-controller@e0200000 {
compatible = "intel,cgu-lgm";
reg = <0xe0200000 0x33c>;
#clock-cells = <1>;
};
...
# SPDX-License-Identifier: (GPL-2.0+ OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/marvell,mmp2-audio-clock.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Marvell MMP2 Audio Clock Controller
maintainers:
- Lubomir Rintel <lkundrak@v3.sk>
description: |
The audio clock controller generates and supplies the clocks to the audio
codec.
Each clock is assigned an identifier and client nodes use this identifier
to specify the clock which they consume.
All these identifiers could be found in
<dt-bindings/clock/marvell,mmp2-audio.h>.
properties:
compatible:
enum:
- marvell,mmp2-audio-clock
reg:
maxItems: 1
clocks:
items:
- description: Audio subsystem clock
- description: The crystal oscillator clock
- description: First I2S clock
- description: Second I2S clock
clock-names:
items:
- const: audio
- const: vctcxo
- const: i2s0
- const: i2s1
'#clock-cells':
const: 1
power-domains:
maxItems: 1
required:
- compatible
- reg
- clocks
- clock-names
- '#clock-cells'
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/marvell,mmp2-audio.h>
#include <dt-bindings/clock/marvell,mmp2.h>
#include <dt-bindings/power/marvell,mmp2.h>
clock-controller@d42a0c30 {
compatible = "marvell,mmp2-audio-clock";
reg = <0xd42a0c30 0x10>;
clock-names = "audio", "vctcxo", "i2s0", "i2s1";
clocks = <&soc_clocks MMP2_CLK_AUDIO>,
<&soc_clocks MMP2_CLK_VCTCXO>,
<&soc_clocks MMP2_CLK_I2S0>,
<&soc_clocks MMP2_CLK_I2S1>;
power-domains = <&soc_clocks MMP2_POWER_DOMAIN_AUDIO>;
#clock-cells = <1>;
};
......@@ -42,12 +42,16 @@ properties:
'#reset-cells':
const: 1
'#power-domain-cells':
const: 1
required:
- compatible
- reg
- reg-names
- '#clock-cells'
- '#reset-cells'
- '#power-domain-cells'
additionalProperties: false
......@@ -61,4 +65,5 @@ examples:
reg-names = "mpmu", "apmu", "apbc";
#clock-cells = <1>;
#reset-cells = <1>;
#power-domain-cells = <1>;
};
Qualcomm MSM8916 A53 PLL Binding
--------------------------------
The A53 PLL on MSM8916 platforms is the main CPU PLL used used for frequencies
above 1GHz.
Required properties :
- compatible : Shall contain only one of the following:
"qcom,msm8916-a53pll"
- reg : shall contain base register location and length
- #clock-cells : must be set to <0>
Example:
a53pll: clock@b016000 {
compatible = "qcom,msm8916-a53pll";
reg = <0xb016000 0x40>;
#clock-cells = <0>;
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/qcom,a53pll.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm A53 PLL Binding
maintainers:
- Sivaprakash Murugesan <sivaprak@codeaurora.org>
description:
The A53 PLL on few Qualcomm platforms is the main CPU PLL used used for
frequencies above 1GHz.
properties:
compatible:
const: qcom,msm8916-a53pll
reg:
maxItems: 1
'#clock-cells':
const: 0
required:
- compatible
- reg
- '#clock-cells'
additionalProperties: false
examples:
#Example 1 - A53 PLL found on MSM8916 devices
- |
a53pll: clock@b016000 {
compatible = "qcom,msm8916-a53pll";
reg = <0xb016000 0x40>;
#clock-cells = <0>;
};
......@@ -22,6 +22,8 @@ description: |
- dt-bindings/reset/qcom,gcc-ipq6018.h
- dt-bindings/clock/qcom,gcc-ipq806x.h (qcom,gcc-ipq8064)
- dt-bindings/reset/qcom,gcc-ipq806x.h (qcom,gcc-ipq8064)
- dt-bindings/clock/qcom,gcc-msm8939.h
- dt-bindings/reset/qcom,gcc-msm8939.h
- dt-bindings/clock/qcom,gcc-msm8660.h
- dt-bindings/reset/qcom,gcc-msm8660.h
- dt-bindings/clock/qcom,gcc-msm8974.h
......@@ -41,6 +43,7 @@ properties:
- qcom,gcc-ipq8064
- qcom,gcc-msm8660
- qcom,gcc-msm8916
- qcom,gcc-msm8939
- qcom,gcc-msm8960
- qcom,gcc-msm8974
- qcom,gcc-msm8974pro
......
......@@ -67,6 +67,10 @@ properties:
description:
Protected clock specifier list as per common clock binding
vdd-gfx-supply:
description:
Regulator supply for the GPU_GX GDSC
required:
- compatible
- reg
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/renesas,cpg-div6-clock.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas CPG DIV6 Clock
maintainers:
- Geert Uytterhoeven <geert+renesas@glider.be>
description:
The CPG DIV6 clocks are variable factor clocks provided by the Clock Pulse
Generator (CPG). Their clock input is divided by a configurable factor from 1
to 64.
properties:
compatible:
items:
- enum:
- renesas,r8a73a4-div6-clock # R-Mobile APE6
- renesas,r8a7740-div6-clock # R-Mobile A1
- renesas,sh73a0-div6-clock # SH-Mobile AG5
- const: renesas,cpg-div6-clock
reg:
maxItems: 1
clocks:
oneOf:
- maxItems: 1
- maxItems: 4
- maxItems: 8
description:
For clocks with multiple parents, invalid settings must be specified as
"<0>".
'#clock-cells':
const: 0
clock-output-names: true
required:
- compatible
- reg
- clocks
- '#clock-cells'
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/r8a73a4-clock.h>
sdhi2_clk: sdhi2_clk@e615007c {
compatible = "renesas,r8a73a4-div6-clock", "renesas,cpg-div6-clock";
reg = <0xe615007c 4>;
clocks = <&pll1_div2_clk>, <&cpg_clocks R8A73A4_CLK_PLL2S>, <0>,
<&extal2_clk>;
#clock-cells = <0>;
};
* Renesas CPG DIV6 Clock
The CPG DIV6 clocks are variable factor clocks provided by the Clock Pulse
Generator (CPG). Their clock input is divided by a configurable factor from 1
to 64.
Required Properties:
- compatible: Must be one of the following
- "renesas,r8a73a4-div6-clock" for R8A73A4 (R-Mobile APE6) DIV6 clocks
- "renesas,r8a7740-div6-clock" for R8A7740 (R-Mobile A1) DIV6 clocks
- "renesas,r8a7790-div6-clock" for R8A7790 (R-Car H2) DIV6 clocks
- "renesas,r8a7791-div6-clock" for R8A7791 (R-Car M2-W) DIV6 clocks
- "renesas,r8a7793-div6-clock" for R8A7793 (R-Car M2-N) DIV6 clocks
- "renesas,r8a7794-div6-clock" for R8A7794 (R-Car E2) DIV6 clocks
- "renesas,sh73a0-div6-clock" for SH73A0 (SH-Mobile AG5) DIV6 clocks
and "renesas,cpg-div6-clock" as a fallback.
- reg: Base address and length of the memory resource used by the DIV6 clock
- clocks: Reference to the parent clock(s); either one, four, or eight
clocks must be specified. For clocks with multiple parents, invalid
settings must be specified as "<0>".
- #clock-cells: Must be 0
Optional Properties:
- clock-output-names: The name of the clock as a free-form string
Example
-------
sdhi2_clk: sdhi2_clk@e615007c {
compatible = "renesas,r8a73a4-div6-clock", "renesas,cpg-div6-clock";
reg = <0 0xe615007c 0 4>;
clocks = <&pll1_div2_clk>, <&cpg_clocks R8A73A4_CLK_PLL2S>,
<0>, <&extal2_clk>;
#clock-cells = <0>;
clock-output-names = "sdhi2ck";
};
......@@ -25,6 +25,7 @@ properties:
compatible:
enum:
- renesas,r7s9210-cpg-mssr # RZ/A2
- renesas,r8a7742-cpg-mssr # RZ/G1H
- renesas,r8a7743-cpg-mssr # RZ/G1M
- renesas,r8a7744-cpg-mssr # RZ/G1N
- renesas,r8a7745-cpg-mssr # RZ/G1E
......
* Renesas CPG Module Stop (MSTP) Clocks
The CPG can gate SoC device clocks. The gates are organized in groups of up to
32 gates.
This device tree binding describes a single 32 gate clocks group per node.
Clocks are referenced by user nodes by the MSTP node phandle and the clock
index in the group, from 0 to 31.
Required Properties:
- compatible: Must be one of the following
- "renesas,r7s72100-mstp-clocks" for R7S72100 (RZ) MSTP gate clocks
- "renesas,r8a73a4-mstp-clocks" for R8A73A4 (R-Mobile APE6) MSTP gate clocks
- "renesas,r8a7740-mstp-clocks" for R8A7740 (R-Mobile A1) MSTP gate clocks
- "renesas,r8a7778-mstp-clocks" for R8A7778 (R-Car M1) MSTP gate clocks
- "renesas,r8a7779-mstp-clocks" for R8A7779 (R-Car H1) MSTP gate clocks
- "renesas,r8a7790-mstp-clocks" for R8A7790 (R-Car H2) MSTP gate clocks
- "renesas,r8a7791-mstp-clocks" for R8A7791 (R-Car M2-W) MSTP gate clocks
- "renesas,r8a7792-mstp-clocks" for R8A7792 (R-Car V2H) MSTP gate clocks
- "renesas,r8a7793-mstp-clocks" for R8A7793 (R-Car M2-N) MSTP gate clocks
- "renesas,r8a7794-mstp-clocks" for R8A7794 (R-Car E2) MSTP gate clocks
- "renesas,sh73a0-mstp-clocks" for SH73A0 (SH-MobileAG5) MSTP gate clocks
and "renesas,cpg-mstp-clocks" as a fallback.
- reg: Base address and length of the I/O mapped registers used by the MSTP
clocks. The first register is the clock control register and is mandatory.
The second register is the clock status register and is optional when not
implemented in hardware.
- clocks: Reference to the parent clocks, one per output clock. The parents
must appear in the same order as the output clocks.
- #clock-cells: Must be 1
- clock-output-names: The name of the clocks as free-form strings
- clock-indices: Indices of the gate clocks into the group (0 to 31)
The clocks, clock-output-names and clock-indices properties contain one entry
per gate clock. The MSTP groups are sparsely populated. Unimplemented gate
clocks must not be declared.
Example
-------
#include <dt-bindings/clock/r8a7790-clock.h>
mstp3_clks: mstp3_clks@e615013c {
compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks";
reg = <0 0xe615013c 0 4>, <0 0xe6150048 0 4>;
clocks = <&cp_clk>, <&mmc1_clk>, <&sd3_clk>, <&sd2_clk>,
<&cpg_clocks R8A7790_CLK_SD1>, <&cpg_clocks R8A7790_CLK_SD0>,
<&mmc0_clk>;
#clock-cells = <1>;
clock-output-names =
"tpu0", "mmcif1", "sdhi3", "sdhi2",
"sdhi1", "sdhi0", "mmcif0";
clock-indices = <
R8A7790_CLK_TPU0 R8A7790_CLK_MMCIF1 R8A7790_CLK_SDHI3
R8A7790_CLK_SDHI2 R8A7790_CLK_SDHI1 R8A7790_CLK_SDHI0
R8A7790_CLK_MMCIF0
>;
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/renesas,cpg-mstp-clocks.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas Clock Pulse Generator (CPG) Module Stop (MSTP) Clocks
maintainers:
- Geert Uytterhoeven <geert+renesas@glider.be>
description:
The Clock Pulse Generator (CPG) can gate SoC device clocks. The gates are
organized in groups of up to 32 gates.
This device tree binding describes a single 32 gate clocks group per node.
Clocks are referenced by user nodes by the Module Stop (MSTP) node phandle
and the clock index in the group, from 0 to 31.
properties:
compatible:
items:
- enum:
- renesas,r7s72100-mstp-clocks # RZ/A1
- renesas,r8a73a4-mstp-clocks # R-Mobile APE6
- renesas,r8a7740-mstp-clocks # R-Mobile A1
- renesas,r8a7778-mstp-clocks # R-Car M1
- renesas,r8a7779-mstp-clocks # R-Car H1
- renesas,sh73a0-mstp-clocks # SH-Mobile AG5
- const: renesas,cpg-mstp-clocks
reg:
minItems: 1
items:
- description: Module Stop Control Register (MSTPCR)
- description: Module Stop Status Register (MSTPSR)
clocks:
minItems: 1
maxItems: 32
'#clock-cells':
const: 1
clock-indices:
minItems: 1
maxItems: 32
clock-output-names:
minItems: 1
maxItems: 32
required:
- compatible
- reg
- clocks
- '#clock-cells'
- clock-indices
- clock-output-names
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/r8a73a4-clock.h>
mstp2_clks: mstp2_clks@e6150138 {
compatible = "renesas,r8a73a4-mstp-clocks",
"renesas,cpg-mstp-clocks";
reg = <0xe6150138 4>, <0xe6150040 4>;
clocks = <&mp_clk>, <&mp_clk>, <&mp_clk>, <&mp_clk>, <&mp_clk>,
<&mp_clk>, <&cpg_clocks R8A73A4_CLK_HP>;
#clock-cells = <1>;
clock-indices = <
R8A73A4_CLK_SCIFA0 R8A73A4_CLK_SCIFA1
R8A73A4_CLK_SCIFB0 R8A73A4_CLK_SCIFB1
R8A73A4_CLK_SCIFB2 R8A73A4_CLK_SCIFB3
R8A73A4_CLK_DMAC
>;
clock-output-names =
"scifa0", "scifa1", "scifb0", "scifb1", "scifb2", "scifb3",
"dmac";
};
......@@ -27,7 +27,9 @@ Required properties:
- compatible: "renesas,r8a7795-rcar-usb2-clock-sel" if the device is a part of
an R8A7795 SoC.
"renesas,r8a7796-rcar-usb2-clock-sel" if the device if a part of
an R8A7796 SoC.
an R8A77960 SoC.
"renesas,r8a77961-rcar-usb2-clock-sel" if the device if a part of
an R8A77961 SoC.
"renesas,rcar-gen3-usb2-clock-sel" for a generic R-Car Gen3
compatible device.
......
Binding for Silicon Labs Si5341 and Si5340 programmable i2c clock generator.
Binding for Silicon Labs Si5340, Si5341 Si5342, Si5344 and Si5345 programmable
i2c clock generator.
Reference
[1] Si5341 Data Sheet
https://www.silabs.com/documents/public/data-sheets/Si5341-40-D-DataSheet.pdf
[2] Si5341 Reference Manual
https://www.silabs.com/documents/public/reference-manuals/Si5341-40-D-RM.pdf
[3] Si5345 Reference Manual
https://www.silabs.com/documents/public/reference-manuals/Si5345-44-42-D-RM.pdf
The Si5341 and Si5340 are programmable i2c clock generators with up to 10 output
clocks. The chip contains a PLL that sources 5 (or 4) multisynth clocks, which
in turn can be directed to any of the 10 (or 4) outputs through a divider.
The internal structure of the clock generators can be found in [2].
The Si5345 is similar to the Si5341 with the addition of fractional input
dividers and automatic input selection, as described in [3].
The Si5342 and Si5344 are smaller versions of the Si5345, with 2 or 4 outputs.
The driver can be used in "as is" mode, reading the current settings from the
chip at boot, in case you have a (pre-)programmed device. If the PLL is not
......@@ -28,6 +34,9 @@ Required properties:
- compatible: shall be one of the following:
"silabs,si5340" - Si5340 A/B/C/D
"silabs,si5341" - Si5341 A/B/C/D
"silabs,si5342" - Si5342 A/B/C/D
"silabs,si5344" - Si5344 A/B/C/D
"silabs,si5345" - Si5345 A/B/C/D
- reg: i2c device address, usually 0x74
- #clock-cells: from common clock binding; shall be set to 2.
The first value is "0" for outputs, "1" for synthesizers.
......
......@@ -28,6 +28,7 @@ properties:
- sprd,sc9863a-rpll
- sprd,sc9863a-dpll
- sprd,sc9863a-mm-gate
- sprd,sc9863a-mm-clk
- sprd,sc9863a-apapb-gate
clocks:
......
......@@ -14493,6 +14493,7 @@ M: Geert Uytterhoeven <geert+renesas@glider.be>
L: linux-renesas-soc@vger.kernel.org
S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers.git clk-renesas
F: Documentation/devicetree/bindings/clock/renesas,*
F: drivers/clk/renesas/
RENESAS EMEV2 I2C DRIVER
......
......@@ -328,12 +328,6 @@ config HAVE_FUNCTION_ARG_ACCESS_API
the API needed to access function arguments from pt_regs,
declared in asm/ptrace.h
config HAVE_CLK
bool
help
The <linux/clk.h> calls support software clock gating and
thus are a key power management tool on many systems.
config HAVE_HW_BREAKPOINT
bool
depends on PERF_EVENTS
......
......@@ -367,6 +367,7 @@ config ARCH_EP93XX
select CPU_ARM920T
select GENERIC_CLOCKEVENTS
select GPIOLIB
select HAVE_LEGACY_CLK
help
This enables support for the Cirrus EP93xx series of CPUs.
......@@ -438,7 +439,6 @@ config ARCH_PXA
select ARM_CPU_SUSPEND if PM
select AUTO_ZRELADDR
select COMMON_CLK
select CLKDEV_LOOKUP
select CLKSRC_PXA
select CLKSRC_MMIO
select TIMER_OF
......@@ -477,7 +477,6 @@ config ARCH_SA1100
bool "SA1100-based"
select ARCH_MTD_XIP
select ARCH_SPARSEMEM_ENABLE
select CLKDEV_LOOKUP
select CLKSRC_MMIO
select CLKSRC_PXA
select TIMER_OF if OF
......@@ -498,7 +497,6 @@ config ARCH_SA1100
config ARCH_S3C24XX
bool "Samsung S3C24XX SoCs"
select ATAGS
select CLKDEV_LOOKUP
select CLKSRC_SAMSUNG_PWM
select GENERIC_CLOCKEVENTS
select GPIO_SAMSUNG
......@@ -528,6 +526,7 @@ config ARCH_OMAP1
select GENERIC_IRQ_MULTI_HANDLER
select GPIOLIB
select HAVE_IDE
select HAVE_LEGACY_CLK
select IRQ_DOMAIN
select NEED_MACH_IO_H if PCCARD
select NEED_MACH_MEMORY_H
......
......@@ -124,6 +124,8 @@ config MACH_MMP2_DT
select PINCTRL_SINGLE
select ARCH_HAS_RESET_CONTROLLER
select CPU_PJ4
select PM_GENERIC_DOMAINS if PM
select PM_GENERIC_DOMAINS_OF if PM && OF
help
Include support for Marvell MMP2 based platforms using
the device tree.
......
......@@ -12,12 +12,6 @@ obj-$(CONFIG_CPU_PXA910) += pxa910.o
obj-$(CONFIG_CPU_MMP2) += mmp2.o
obj-$(CONFIG_MMP_SRAM) += sram.o
ifeq ($(CONFIG_COMMON_CLK), )
obj-y += clock.o
obj-$(CONFIG_CPU_PXA168) += clock-pxa168.o
obj-$(CONFIG_CPU_PXA910) += clock-pxa910.o
obj-$(CONFIG_CPU_MMP2) += clock-mmp2.o
endif
ifeq ($(CONFIG_PM),y)
obj-$(CONFIG_CPU_PXA910) += pm-pxa910.o
obj-$(CONFIG_CPU_MMP2) += pm-mmp2.o
......
// SPDX-License-Identifier: GPL-2.0
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/clk/mmp.h>
#include "addr-map.h"
#include "common.h"
#include "clock.h"
/*
* APB Clock register offsets for MMP2
*/
#define APBC_RTC APBC_REG(0x000)
#define APBC_TWSI1 APBC_REG(0x004)
#define APBC_TWSI2 APBC_REG(0x008)
#define APBC_TWSI3 APBC_REG(0x00c)
#define APBC_TWSI4 APBC_REG(0x010)
#define APBC_KPC APBC_REG(0x018)
#define APBC_UART1 APBC_REG(0x02c)
#define APBC_UART2 APBC_REG(0x030)
#define APBC_UART3 APBC_REG(0x034)
#define APBC_GPIO APBC_REG(0x038)
#define APBC_PWM0 APBC_REG(0x03c)
#define APBC_PWM1 APBC_REG(0x040)
#define APBC_PWM2 APBC_REG(0x044)
#define APBC_PWM3 APBC_REG(0x048)
#define APBC_SSP0 APBC_REG(0x04c)
#define APBC_SSP1 APBC_REG(0x050)
#define APBC_SSP2 APBC_REG(0x054)
#define APBC_SSP3 APBC_REG(0x058)
#define APBC_SSP4 APBC_REG(0x05c)
#define APBC_SSP5 APBC_REG(0x060)
#define APBC_TWSI5 APBC_REG(0x07c)
#define APBC_TWSI6 APBC_REG(0x080)
#define APBC_UART4 APBC_REG(0x088)
#define APMU_USB APMU_REG(0x05c)
#define APMU_NAND APMU_REG(0x060)
#define APMU_SDH0 APMU_REG(0x054)
#define APMU_SDH1 APMU_REG(0x058)
#define APMU_SDH2 APMU_REG(0x0e8)
#define APMU_SDH3 APMU_REG(0x0ec)
static void sdhc_clk_enable(struct clk *clk)
{
uint32_t clk_rst;
clk_rst = __raw_readl(clk->clk_rst);
clk_rst |= clk->enable_val;
__raw_writel(clk_rst, clk->clk_rst);
}
static void sdhc_clk_disable(struct clk *clk)
{
uint32_t clk_rst;
clk_rst = __raw_readl(clk->clk_rst);
clk_rst &= ~clk->enable_val;
__raw_writel(clk_rst, clk->clk_rst);
}
struct clkops sdhc_clk_ops = {
.enable = sdhc_clk_enable,
.disable = sdhc_clk_disable,
};
/* APB peripheral clocks */
static APBC_CLK(uart1, UART1, 1, 26000000);
static APBC_CLK(uart2, UART2, 1, 26000000);
static APBC_CLK(uart3, UART3, 1, 26000000);
static APBC_CLK(uart4, UART4, 1, 26000000);
static APBC_CLK(twsi1, TWSI1, 0, 26000000);
static APBC_CLK(twsi2, TWSI2, 0, 26000000);
static APBC_CLK(twsi3, TWSI3, 0, 26000000);
static APBC_CLK(twsi4, TWSI4, 0, 26000000);
static APBC_CLK(twsi5, TWSI5, 0, 26000000);
static APBC_CLK(twsi6, TWSI6, 0, 26000000);
static APBC_CLK(gpio, GPIO, 0, 26000000);
static APMU_CLK(nand, NAND, 0xbf, 100000000);
static APMU_CLK_OPS(sdh0, SDH0, 0x1b, 200000000, &sdhc_clk_ops);
static APMU_CLK_OPS(sdh1, SDH1, 0x1b, 200000000, &sdhc_clk_ops);
static APMU_CLK_OPS(sdh2, SDH2, 0x1b, 200000000, &sdhc_clk_ops);
static APMU_CLK_OPS(sdh3, SDH3, 0x1b, 200000000, &sdhc_clk_ops);
static struct clk_lookup mmp2_clkregs[] = {
INIT_CLKREG(&clk_uart1, "pxa2xx-uart.0", NULL),
INIT_CLKREG(&clk_uart2, "pxa2xx-uart.1", NULL),
INIT_CLKREG(&clk_uart3, "pxa2xx-uart.2", NULL),
INIT_CLKREG(&clk_uart4, "pxa2xx-uart.3", NULL),
INIT_CLKREG(&clk_twsi1, "pxa2xx-i2c.0", NULL),
INIT_CLKREG(&clk_twsi2, "pxa2xx-i2c.1", NULL),
INIT_CLKREG(&clk_twsi3, "pxa2xx-i2c.2", NULL),
INIT_CLKREG(&clk_twsi4, "pxa2xx-i2c.3", NULL),
INIT_CLKREG(&clk_twsi5, "pxa2xx-i2c.4", NULL),
INIT_CLKREG(&clk_twsi6, "pxa2xx-i2c.5", NULL),
INIT_CLKREG(&clk_nand, "pxa3xx-nand", NULL),
INIT_CLKREG(&clk_gpio, "mmp2-gpio", NULL),
INIT_CLKREG(&clk_sdh0, "sdhci-pxav3.0", "PXA-SDHCLK"),
INIT_CLKREG(&clk_sdh1, "sdhci-pxav3.1", "PXA-SDHCLK"),
INIT_CLKREG(&clk_sdh2, "sdhci-pxav3.2", "PXA-SDHCLK"),
INIT_CLKREG(&clk_sdh3, "sdhci-pxav3.3", "PXA-SDHCLK"),
};
void __init mmp2_clk_init(phys_addr_t mpmu_phys, phys_addr_t apmu_phys,
phys_addr_t apbc_phys)
{
clkdev_add_table(ARRAY_AND_SIZE(mmp2_clkregs));
}
// SPDX-License-Identifier: GPL-2.0
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/clk/mmp.h>
#include "addr-map.h"
#include "common.h"
#include "clock.h"
/*
* APB clock register offsets for PXA168
*/
#define APBC_UART1 APBC_REG(0x000)
#define APBC_UART2 APBC_REG(0x004)
#define APBC_GPIO APBC_REG(0x008)
#define APBC_PWM1 APBC_REG(0x00c)
#define APBC_PWM2 APBC_REG(0x010)
#define APBC_PWM3 APBC_REG(0x014)
#define APBC_PWM4 APBC_REG(0x018)
#define APBC_RTC APBC_REG(0x028)
#define APBC_TWSI0 APBC_REG(0x02c)
#define APBC_KPC APBC_REG(0x030)
#define APBC_TWSI1 APBC_REG(0x06c)
#define APBC_UART3 APBC_REG(0x070)
#define APBC_SSP1 APBC_REG(0x81c)
#define APBC_SSP2 APBC_REG(0x820)
#define APBC_SSP3 APBC_REG(0x84c)
#define APBC_SSP4 APBC_REG(0x858)
#define APBC_SSP5 APBC_REG(0x85c)
#define APMU_NAND APMU_REG(0x060)
#define APMU_LCD APMU_REG(0x04c)
#define APMU_ETH APMU_REG(0x0fc)
#define APMU_USB APMU_REG(0x05c)
/* APB peripheral clocks */
static APBC_CLK(uart1, UART1, 1, 14745600);
static APBC_CLK(uart2, UART2, 1, 14745600);
static APBC_CLK(uart3, UART3, 1, 14745600);
static APBC_CLK(twsi0, TWSI0, 1, 33000000);
static APBC_CLK(twsi1, TWSI1, 1, 33000000);
static APBC_CLK(pwm1, PWM1, 1, 13000000);
static APBC_CLK(pwm2, PWM2, 1, 13000000);
static APBC_CLK(pwm3, PWM3, 1, 13000000);
static APBC_CLK(pwm4, PWM4, 1, 13000000);
static APBC_CLK(ssp1, SSP1, 4, 0);
static APBC_CLK(ssp2, SSP2, 4, 0);
static APBC_CLK(ssp3, SSP3, 4, 0);
static APBC_CLK(ssp4, SSP4, 4, 0);
static APBC_CLK(ssp5, SSP5, 4, 0);
static APBC_CLK(gpio, GPIO, 0, 13000000);
static APBC_CLK(keypad, KPC, 0, 32000);
static APBC_CLK(rtc, RTC, 8, 32768);
static APMU_CLK(nand, NAND, 0x19b, 156000000);
static APMU_CLK(lcd, LCD, 0x7f, 312000000);
static APMU_CLK(eth, ETH, 0x09, 0);
static APMU_CLK(usb, USB, 0x12, 0);
/* device and clock bindings */
static struct clk_lookup pxa168_clkregs[] = {
INIT_CLKREG(&clk_uart1, "pxa2xx-uart.0", NULL),
INIT_CLKREG(&clk_uart2, "pxa2xx-uart.1", NULL),
INIT_CLKREG(&clk_uart3, "pxa2xx-uart.2", NULL),
INIT_CLKREG(&clk_twsi0, "pxa2xx-i2c.0", NULL),
INIT_CLKREG(&clk_twsi1, "pxa2xx-i2c.1", NULL),
INIT_CLKREG(&clk_pwm1, "pxa168-pwm.0", NULL),
INIT_CLKREG(&clk_pwm2, "pxa168-pwm.1", NULL),
INIT_CLKREG(&clk_pwm3, "pxa168-pwm.2", NULL),
INIT_CLKREG(&clk_pwm4, "pxa168-pwm.3", NULL),
INIT_CLKREG(&clk_ssp1, "pxa168-ssp.0", NULL),
INIT_CLKREG(&clk_ssp2, "pxa168-ssp.1", NULL),
INIT_CLKREG(&clk_ssp3, "pxa168-ssp.2", NULL),
INIT_CLKREG(&clk_ssp4, "pxa168-ssp.3", NULL),
INIT_CLKREG(&clk_ssp5, "pxa168-ssp.4", NULL),
INIT_CLKREG(&clk_nand, "pxa3xx-nand", NULL),
INIT_CLKREG(&clk_lcd, "pxa168-fb", NULL),
INIT_CLKREG(&clk_gpio, "mmp-gpio", NULL),
INIT_CLKREG(&clk_keypad, "pxa27x-keypad", NULL),
INIT_CLKREG(&clk_eth, "pxa168-eth", "MFUCLK"),
INIT_CLKREG(&clk_usb, NULL, "PXA168-USBCLK"),
INIT_CLKREG(&clk_rtc, "sa1100-rtc", NULL),
};
void __init pxa168_clk_init(phys_addr_t mpmu_phys, phys_addr_t apmu_phys,
phys_addr_t apbc_phys)
{
clkdev_add_table(ARRAY_AND_SIZE(pxa168_clkregs));
}
// SPDX-License-Identifier: GPL-2.0
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/clk/mmp.h>
#include "addr-map.h"
#include "common.h"
#include "clock.h"
/*
* APB Clock register offsets for PXA910
*/
#define APBC_UART0 APBC_REG(0x000)
#define APBC_UART1 APBC_REG(0x004)
#define APBC_GPIO APBC_REG(0x008)
#define APBC_PWM1 APBC_REG(0x00c)
#define APBC_PWM2 APBC_REG(0x010)
#define APBC_PWM3 APBC_REG(0x014)
#define APBC_PWM4 APBC_REG(0x018)
#define APBC_SSP1 APBC_REG(0x01c)
#define APBC_SSP2 APBC_REG(0x020)
#define APBC_RTC APBC_REG(0x028)
#define APBC_TWSI0 APBC_REG(0x02c)
#define APBC_KPC APBC_REG(0x030)
#define APBC_SSP3 APBC_REG(0x04c)
#define APBC_TWSI1 APBC_REG(0x06c)
#define APMU_NAND APMU_REG(0x060)
#define APMU_USB APMU_REG(0x05c)
static APBC_CLK(uart1, UART0, 1, 14745600);
static APBC_CLK(uart2, UART1, 1, 14745600);
static APBC_CLK(twsi0, TWSI0, 1, 33000000);
static APBC_CLK(twsi1, TWSI1, 1, 33000000);
static APBC_CLK(pwm1, PWM1, 1, 13000000);
static APBC_CLK(pwm2, PWM2, 1, 13000000);
static APBC_CLK(pwm3, PWM3, 1, 13000000);
static APBC_CLK(pwm4, PWM4, 1, 13000000);
static APBC_CLK(gpio, GPIO, 0, 13000000);
static APBC_CLK(rtc, RTC, 8, 32768);
static APMU_CLK(nand, NAND, 0x19b, 156000000);
static APMU_CLK(u2o, USB, 0x1b, 480000000);
/* device and clock bindings */
static struct clk_lookup pxa910_clkregs[] = {
INIT_CLKREG(&clk_uart1, "pxa2xx-uart.0", NULL),
INIT_CLKREG(&clk_uart2, "pxa2xx-uart.1", NULL),
INIT_CLKREG(&clk_twsi0, "pxa2xx-i2c.0", NULL),
INIT_CLKREG(&clk_twsi1, "pxa2xx-i2c.1", NULL),
INIT_CLKREG(&clk_pwm1, "pxa910-pwm.0", NULL),
INIT_CLKREG(&clk_pwm2, "pxa910-pwm.1", NULL),
INIT_CLKREG(&clk_pwm3, "pxa910-pwm.2", NULL),
INIT_CLKREG(&clk_pwm4, "pxa910-pwm.3", NULL),
INIT_CLKREG(&clk_nand, "pxa3xx-nand", NULL),
INIT_CLKREG(&clk_gpio, "mmp-gpio", NULL),
INIT_CLKREG(&clk_u2o, NULL, "U2OCLK"),
INIT_CLKREG(&clk_rtc, "sa1100-rtc", NULL),
};
void __init pxa910_clk_init(phys_addr_t mpmu_phys, phys_addr_t apmu_phys,
phys_addr_t apbc_phys, phys_addr_t apbcp_phys)
{
clkdev_add_table(ARRAY_AND_SIZE(pxa910_clkregs));
}
// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/arch/arm/mach-mmp/clock.c
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/clk.h>
#include <linux/io.h>
#include "regs-apbc.h"
#include "clock.h"
static void apbc_clk_enable(struct clk *clk)
{
uint32_t clk_rst;
clk_rst = APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(clk->fnclksel);
__raw_writel(clk_rst, clk->clk_rst);
}
static void apbc_clk_disable(struct clk *clk)
{
__raw_writel(0, clk->clk_rst);
}
struct clkops apbc_clk_ops = {
.enable = apbc_clk_enable,
.disable = apbc_clk_disable,
};
static void apmu_clk_enable(struct clk *clk)
{
__raw_writel(clk->enable_val, clk->clk_rst);
}
static void apmu_clk_disable(struct clk *clk)
{
__raw_writel(0, clk->clk_rst);
}
struct clkops apmu_clk_ops = {
.enable = apmu_clk_enable,
.disable = apmu_clk_disable,
};
static DEFINE_SPINLOCK(clocks_lock);
int clk_enable(struct clk *clk)
{
unsigned long flags;
spin_lock_irqsave(&clocks_lock, flags);
if (clk->enabled++ == 0)
clk->ops->enable(clk);
spin_unlock_irqrestore(&clocks_lock, flags);
return 0;
}
EXPORT_SYMBOL(clk_enable);
void clk_disable(struct clk *clk)
{
unsigned long flags;
if (!clk)
return;
WARN_ON(clk->enabled == 0);
spin_lock_irqsave(&clocks_lock, flags);
if (--clk->enabled == 0)
clk->ops->disable(clk);
spin_unlock_irqrestore(&clocks_lock, flags);
}
EXPORT_SYMBOL(clk_disable);
unsigned long clk_get_rate(struct clk *clk)
{
unsigned long rate;
if (clk->ops->getrate)
rate = clk->ops->getrate(clk);
else
rate = clk->rate;
return rate;
}
EXPORT_SYMBOL(clk_get_rate);
int clk_set_rate(struct clk *clk, unsigned long rate)
{
unsigned long flags;
int ret = -EINVAL;
if (clk->ops->setrate) {
spin_lock_irqsave(&clocks_lock, flags);
ret = clk->ops->setrate(clk, rate);
spin_unlock_irqrestore(&clocks_lock, flags);
}
return ret;
}
EXPORT_SYMBOL(clk_set_rate);
/* SPDX-License-Identifier: GPL-2.0-only */
#include <linux/clkdev.h>
struct clkops {
void (*enable)(struct clk *);
void (*disable)(struct clk *);
unsigned long (*getrate)(struct clk *);
int (*setrate)(struct clk *, unsigned long);
};
struct clk {
const struct clkops *ops;
void __iomem *clk_rst; /* clock reset control register */
int fnclksel; /* functional clock select (APBC) */
uint32_t enable_val; /* value for clock enable (APMU) */
unsigned long rate;
int enabled;
};
extern struct clkops apbc_clk_ops;
extern struct clkops apmu_clk_ops;
#define APBC_CLK(_name, _reg, _fnclksel, _rate) \
struct clk clk_##_name = { \
.clk_rst = APBC_##_reg, \
.fnclksel = _fnclksel, \
.rate = _rate, \
.ops = &apbc_clk_ops, \
}
#define APBC_CLK_OPS(_name, _reg, _fnclksel, _rate, _ops) \
struct clk clk_##_name = { \
.clk_rst = APBC_##_reg, \
.fnclksel = _fnclksel, \
.rate = _rate, \
.ops = _ops, \
}
#define APMU_CLK(_name, _reg, _eval, _rate) \
struct clk clk_##_name = { \
.clk_rst = APMU_##_reg, \
.enable_val = _eval, \
.rate = _rate, \
.ops = &apmu_clk_ops, \
}
#define APMU_CLK_OPS(_name, _reg, _eval, _rate, _ops) \
struct clk clk_##_name = { \
.clk_rst = APMU_##_reg, \
.enable_val = _eval, \
.rate = _rate, \
.ops = _ops, \
}
#define INIT_CLKREG(_clk, _devname, _conname) \
{ \
.clk = _clk, \
.dev_id = _devname, \
.con_id = _conname, \
}
extern struct clk clk_pxa168_gpio;
extern struct clk clk_pxa168_timers;
......@@ -19,7 +19,6 @@
#include <asm/system_misc.h>
#include "addr-map.h"
#include "clock.h"
#include "common.h"
#include <linux/soc/mmp/cputype.h>
#include "devices.h"
......
......@@ -34,7 +34,6 @@
#include "regs-apbc.h"
#include "irqs.h"
#include <linux/soc/mmp/cputype.h>
#include "clock.h"
#define TIMERS_VIRT_BASE TIMERS1_VIRT_BASE
......
......@@ -2,7 +2,6 @@
config ARCH_VT8500
bool
select GPIOLIB
select CLKDEV_LOOKUP
select VT8500_TIMER
select PINCTRL
help
......
......@@ -235,7 +235,6 @@ config ARCH_TEGRA
bool "NVIDIA Tegra SoC Family"
select ARCH_HAS_RESET_CONTROLLER
select ARM_GIC_PM
select CLKDEV_LOOKUP
select CLKSRC_MMIO
select TIMER_OF
select GENERIC_CLOCKEVENTS
......
......@@ -11,6 +11,7 @@ config C6X
select ARCH_HAS_SYNC_DMA_FOR_CPU
select ARCH_HAS_SYNC_DMA_FOR_DEVICE
select CLKDEV_LOOKUP
select HAVE_LEGACY_CLK
select GENERIC_ATOMIC64
select GENERIC_IRQ_SHOW
select HAVE_ARCH_TRACEHOOK
......
......@@ -13,7 +13,6 @@ config H8300
select GENERIC_CPU_DEVICES
select MODULES_USE_ELF_RELA
select GENERIC_CLOCKEVENTS
select CLKDEV_LOOKUP
select COMMON_CLK
select ARCH_WANT_FRAME_POINTERS
select OF
......
......@@ -28,7 +28,7 @@ config COLDFIRE
select CPU_HAS_NO_MULDIV64
select GENERIC_CSUM
select GPIOLIB
select HAVE_CLK
select HAVE_LEGACY_CLK
endchoice
......
......@@ -184,7 +184,7 @@ config AR7
select SYS_SUPPORTS_ZBOOT_UART16550
select GPIOLIB
select VLYNQ
select HAVE_CLK
select HAVE_LEGACY_CLK
help
Support for the Texas Instruments AR7 System-on-a-Chip
family: TNETD7100, 7200 and 7300.
......@@ -212,9 +212,7 @@ config ATH79
select DMA_NONCOHERENT
select GPIOLIB
select PINCTRL
select HAVE_CLK
select COMMON_CLK
select CLKDEV_LOOKUP
select IRQ_MIPS_CPU
select SYS_HAS_CPU_MIPS32_R2
select SYS_HAS_EARLY_PRINTK
......@@ -301,9 +299,9 @@ config BCM63XX
select SYS_HAS_EARLY_PRINTK
select SWAP_IO_SPACE
select GPIOLIB
select HAVE_CLK
select MIPS_L1_CACHE_SHIFT_4
select CLKDEV_LOOKUP
select HAVE_LEGACY_CLK
help
Support for BCM63XX based boards
......@@ -424,6 +422,7 @@ config LANTIQ
select SWAP_IO_SPACE
select BOOT_RAW
select CLKDEV_LOOKUP
select HAVE_LEGACY_CLK
select USE_OF
select PINCTRL
select PINCTRL_LANTIQ
......
......@@ -27,18 +27,22 @@ choice
config SOC_RT288X
bool "RT288x"
select MIPS_L1_CACHE_SHIFT_4
select HAVE_LEGACY_CLK
select HAVE_PCI
config SOC_RT305X
bool "RT305x"
select HAVE_LEGACY_CLK
config SOC_RT3883
bool "RT3883"
select HAVE_LEGACY_CLK
select HAVE_PCI
config SOC_MT7620
bool "MT7620/8"
select CPU_MIPSR2_IRQ_VI
select HAVE_LEGACY_CLK
select HAVE_PCI
config SOC_MT7621
......
......@@ -7,6 +7,11 @@ config SOLUTION_ENGINE
config SH_ALPHA_BOARD
bool
config SH_CUSTOM_CLK
def_bool y
depends on !SH_DEVICE_TREE
select HAVE_LEGACY_CLK
config SH_DEVICE_TREE
bool
select OF
......
......@@ -70,7 +70,7 @@ config ARCH_PUV3
def_bool y
select CPU_UCV2
select GENERIC_CLOCKEVENTS
select HAVE_CLK
select HAVE_LEGACY_CLK
select GPIOLIB
# CONFIGs for ARCH_PUV3
......
# SPDX-License-Identifier: GPL-2.0
config HAVE_CLK
bool
help
The <linux/clk.h> calls support software clock gating and
thus are a key power management tool on many systems.
config CLKDEV_LOOKUP
bool
select HAVE_CLK
......@@ -7,8 +13,18 @@ config CLKDEV_LOOKUP
config HAVE_CLK_PREPARE
bool
config COMMON_CLK
config HAVE_LEGACY_CLK # TODO: Remove once all legacy users are migrated
bool
select HAVE_CLK
help
Select this option when the clock API in <linux/clk.h> is implemented
by platform/architecture code. This method is deprecated. Modern
code should select COMMON_CLK instead and not define a custom
'struct clk'.
menuconfig COMMON_CLK
bool "Common Clock Framework"
depends on !HAVE_LEGACY_CLK
select HAVE_CLK_PREPARE
select CLKDEV_LOOKUP
select SRCU
......@@ -20,8 +36,7 @@ config COMMON_CLK
Architectures utilizing the common struct clk should select
this option.
menu "Common Clock Framework"
depends on COMMON_CLK
if COMMON_CLK
config COMMON_CLK_WM831X
tristate "Clock driver for WM831x/2x PMICs"
......@@ -252,7 +267,7 @@ config COMMON_CLK_XGENE
default ARCH_XGENE
depends on ARM64 || COMPILE_TEST
---help---
Sypport for the APM X-Gene SoC reference, PLL, and device clocks.
Support for the APM X-Gene SoC reference, PLL, and device clocks.
config COMMON_CLK_LOCHNAGAR
tristate "Cirrus Logic Lochnagar clock driver"
......@@ -326,6 +341,12 @@ config COMMON_CLK_MMP2
help
Support for Marvell MMP2 and MMP3 SoC clocks
config COMMON_CLK_MMP2_AUDIO
tristate "Clock driver for MMP2 Audio subsystem"
depends on COMMON_CLK_MMP2 || COMPILE_TEST
help
This driver supports clocks for Audio subsystem on MMP2 SoC.
config COMMON_CLK_BD718XX
tristate "Clock driver for 32K clk gates on ROHM PMICs"
depends on MFD_ROHM_BD718XX || MFD_ROHM_BD70528 || MFD_ROHM_BD71828
......@@ -341,6 +362,7 @@ config COMMON_CLK_FIXED_MMIO
source "drivers/clk/actions/Kconfig"
source "drivers/clk/analogbits/Kconfig"
source "drivers/clk/baikal-t1/Kconfig"
source "drivers/clk/bcm/Kconfig"
source "drivers/clk/hisilicon/Kconfig"
source "drivers/clk/imgtec/Kconfig"
......@@ -360,6 +382,7 @@ source "drivers/clk/sunxi-ng/Kconfig"
source "drivers/clk/tegra/Kconfig"
source "drivers/clk/ti/Kconfig"
source "drivers/clk/uniphier/Kconfig"
source "drivers/clk/x86/Kconfig"
source "drivers/clk/zynqmp/Kconfig"
endmenu
endif
......@@ -75,6 +75,7 @@ obj-y += analogbits/
obj-$(CONFIG_COMMON_CLK_AT91) += at91/
obj-$(CONFIG_ARCH_ARTPEC) += axis/
obj-$(CONFIG_ARC_PLAT_AXS10X) += axs10x/
obj-$(CONFIG_CLK_BAIKAL_T1) += baikal-t1/
obj-y += bcm/
obj-$(CONFIG_ARCH_BERLIN) += berlin/
obj-$(CONFIG_ARCH_DAVINCI) += davinci/
......@@ -104,10 +105,11 @@ obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/
obj-$(CONFIG_CLK_SIFIVE) += sifive/
obj-$(CONFIG_ARCH_SIRF) += sirf/
obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/
obj-$(CONFIG_ARCH_AGILEX) += socfpga/
obj-$(CONFIG_ARCH_STRATIX10) += socfpga/
obj-$(CONFIG_PLAT_SPEAR) += spear/
obj-y += sprd/
obj-$(CONFIG_ARCH_STI) += st/
obj-$(CONFIG_ARCH_STRATIX10) += socfpga/
obj-$(CONFIG_ARCH_SUNXI) += sunxi/
obj-$(CONFIG_SUNXI_CCU) += sunxi-ng/
obj-$(CONFIG_ARCH_TEGRA) += tegra/
......
......@@ -98,9 +98,9 @@ static void __init at91rm9200_pmc_setup(struct device_node *np)
if (IS_ERR(regmap))
return;
at91rm9200_pmc = pmc_data_allocate(PMC_MAIN + 1,
at91rm9200_pmc = pmc_data_allocate(PMC_PLLBCK + 1,
nck(at91rm9200_systemck),
nck(at91rm9200_periphck), 0);
nck(at91rm9200_periphck), 0, 4);
if (!at91rm9200_pmc)
return;
......@@ -123,12 +123,16 @@ static void __init at91rm9200_pmc_setup(struct device_node *np)
if (IS_ERR(hw))
goto err_free;
at91rm9200_pmc->chws[PMC_PLLACK] = hw;
hw = at91_clk_register_pll(regmap, "pllbck", "mainck", 1,
&at91rm9200_pll_layout,
&rm9200_pll_characteristics);
if (IS_ERR(hw))
goto err_free;
at91rm9200_pmc->chws[PMC_PLLBCK] = hw;
parent_names[0] = slowxtal_name;
parent_names[1] = "mainck";
parent_names[2] = "pllack";
......@@ -159,6 +163,8 @@ static void __init at91rm9200_pmc_setup(struct device_node *np)
&at91rm9200_programmable_layout);
if (IS_ERR(hw))
goto err_free;
at91rm9200_pmc->pchws[i] = hw;
}
for (i = 0; i < ARRAY_SIZE(at91rm9200_systemck); i++) {
......@@ -187,7 +193,7 @@ static void __init at91rm9200_pmc_setup(struct device_node *np)
return;
err_free:
pmc_data_free(at91rm9200_pmc);
kfree(at91rm9200_pmc);
}
/*
* While the TCB can be used as the clocksource, the system timer is most likely
......
......@@ -352,9 +352,10 @@ static void __init at91sam926x_pmc_setup(struct device_node *np,
if (IS_ERR(regmap))
return;
at91sam9260_pmc = pmc_data_allocate(PMC_MAIN + 1,
at91sam9260_pmc = pmc_data_allocate(PMC_PLLBCK + 1,
ndck(data->sck, data->num_sck),
ndck(data->pck, data->num_pck), 0);
ndck(data->pck, data->num_pck),
0, data->num_progck);
if (!at91sam9260_pmc)
return;
......@@ -398,12 +399,16 @@ static void __init at91sam926x_pmc_setup(struct device_node *np,
if (IS_ERR(hw))
goto err_free;
at91sam9260_pmc->chws[PMC_PLLACK] = hw;
hw = at91_clk_register_pll(regmap, "pllbck", "mainck", 1,
data->pllb_layout,
data->pllb_characteristics);
if (IS_ERR(hw))
goto err_free;
at91sam9260_pmc->chws[PMC_PLLBCK] = hw;
parent_names[0] = slck_name;
parent_names[1] = "mainck";
parent_names[2] = "pllack";
......@@ -434,6 +439,8 @@ static void __init at91sam926x_pmc_setup(struct device_node *np,
&at91rm9200_programmable_layout);
if (IS_ERR(hw))
goto err_free;
at91sam9260_pmc->pchws[i] = hw;
}
for (i = 0; i < data->num_sck; i++) {
......@@ -462,7 +469,7 @@ static void __init at91sam926x_pmc_setup(struct device_node *np,
return;
err_free:
pmc_data_free(at91sam9260_pmc);
kfree(at91sam9260_pmc);
}
static void __init at91sam9260_pmc_setup(struct device_node *np)
......
......@@ -115,9 +115,9 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np)
if (IS_ERR(regmap))
return;
at91sam9g45_pmc = pmc_data_allocate(PMC_MAIN + 1,
at91sam9g45_pmc = pmc_data_allocate(PMC_PLLACK + 1,
nck(at91sam9g45_systemck),
nck(at91sam9g45_periphck), 0);
nck(at91sam9g45_periphck), 0, 2);
if (!at91sam9g45_pmc)
return;
......@@ -143,6 +143,8 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np)
if (IS_ERR(hw))
goto err_free;
at91sam9g45_pmc->chws[PMC_PLLACK] = hw;
hw = at91_clk_register_utmi(regmap, NULL, "utmick", "mainck");
if (IS_ERR(hw))
goto err_free;
......@@ -182,6 +184,8 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np)
&at91sam9g45_programmable_layout);
if (IS_ERR(hw))
goto err_free;
at91sam9g45_pmc->pchws[i] = hw;
}
for (i = 0; i < ARRAY_SIZE(at91sam9g45_systemck); i++) {
......@@ -210,7 +214,7 @@ static void __init at91sam9g45_pmc_setup(struct device_node *np)
return;
err_free:
pmc_data_free(at91sam9g45_pmc);
kfree(at91sam9g45_pmc);
}
/*
* The TCB is used as the clocksource so its clock is needed early. This means
......
......@@ -128,8 +128,8 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np)
if (IS_ERR(regmap))
return;
at91sam9n12_pmc = pmc_data_allocate(PMC_MAIN + 1,
nck(at91sam9n12_systemck), 31, 0);
at91sam9n12_pmc = pmc_data_allocate(PMC_PLLBCK + 1,
nck(at91sam9n12_systemck), 31, 0, 2);
if (!at91sam9n12_pmc)
return;
......@@ -162,11 +162,15 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np)
if (IS_ERR(hw))
goto err_free;
at91sam9n12_pmc->chws[PMC_PLLACK] = hw;
hw = at91_clk_register_pll(regmap, "pllbck", "mainck", 1,
&at91rm9200_pll_layout, &pllb_characteristics);
if (IS_ERR(hw))
goto err_free;
at91sam9n12_pmc->chws[PMC_PLLBCK] = hw;
parent_names[0] = slck_name;
parent_names[1] = "mainck";
parent_names[2] = "plladivck";
......@@ -198,6 +202,8 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np)
&at91sam9x5_programmable_layout);
if (IS_ERR(hw))
goto err_free;
at91sam9n12_pmc->pchws[i] = hw;
}
for (i = 0; i < ARRAY_SIZE(at91sam9n12_systemck); i++) {
......@@ -228,7 +234,7 @@ static void __init at91sam9n12_pmc_setup(struct device_node *np)
return;
err_free:
pmc_data_free(at91sam9n12_pmc);
kfree(at91sam9n12_pmc);
}
/*
* The TCB is used as the clocksource so its clock is needed early. This means
......
......@@ -87,9 +87,9 @@ static void __init at91sam9rl_pmc_setup(struct device_node *np)
if (IS_ERR(regmap))
return;
at91sam9rl_pmc = pmc_data_allocate(PMC_MAIN + 1,
at91sam9rl_pmc = pmc_data_allocate(PMC_PLLACK + 1,
nck(at91sam9rl_systemck),
nck(at91sam9rl_periphck), 0);
nck(at91sam9rl_periphck), 0, 2);
if (!at91sam9rl_pmc)
return;
......@@ -105,6 +105,8 @@ static void __init at91sam9rl_pmc_setup(struct device_node *np)
if (IS_ERR(hw))
goto err_free;
at91sam9rl_pmc->chws[PMC_PLLACK] = hw;
hw = at91_clk_register_utmi(regmap, NULL, "utmick", "mainck");
if (IS_ERR(hw))
goto err_free;
......@@ -138,6 +140,8 @@ static void __init at91sam9rl_pmc_setup(struct device_node *np)
&at91rm9200_programmable_layout);
if (IS_ERR(hw))
goto err_free;
at91sam9rl_pmc->pchws[i] = hw;
}
for (i = 0; i < ARRAY_SIZE(at91sam9rl_systemck); i++) {
......@@ -166,6 +170,6 @@ static void __init at91sam9rl_pmc_setup(struct device_node *np)
return;
err_free:
pmc_data_free(at91sam9rl_pmc);
kfree(at91sam9rl_pmc);
}
CLK_OF_DECLARE_DRIVER(at91sam9rl_pmc, "atmel,at91sam9rl-pmc", at91sam9rl_pmc_setup);
......@@ -150,8 +150,8 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
if (IS_ERR(regmap))
return;
at91sam9x5_pmc = pmc_data_allocate(PMC_MAIN + 1,
nck(at91sam9x5_systemck), 31, 0);
at91sam9x5_pmc = pmc_data_allocate(PMC_PLLACK + 1,
nck(at91sam9x5_systemck), 31, 0, 2);
if (!at91sam9x5_pmc)
return;
......@@ -184,6 +184,8 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
if (IS_ERR(hw))
goto err_free;
at91sam9x5_pmc->chws[PMC_PLLACK] = hw;
hw = at91_clk_register_utmi(regmap, NULL, "utmick", "mainck");
if (IS_ERR(hw))
goto err_free;
......@@ -227,6 +229,8 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
&at91sam9x5_programmable_layout);
if (IS_ERR(hw))
goto err_free;
at91sam9x5_pmc->pchws[i] = hw;
}
for (i = 0; i < ARRAY_SIZE(at91sam9x5_systemck); i++) {
......@@ -278,7 +282,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
return;
err_free:
pmc_data_free(at91sam9x5_pmc);
kfree(at91sam9x5_pmc);
}
static void __init at91sam9g15_pmc_setup(struct device_node *np)
......
......@@ -67,6 +67,10 @@ struct clk_hw *of_clk_hw_pmc_get(struct of_phandle_args *clkspec, void *data)
if (idx < pmc_data->ngck)
return pmc_data->ghws[idx];
break;
case PMC_TYPE_PROGRAMMABLE:
if (idx < pmc_data->npck)
return pmc_data->pchws[idx];
break;
default:
break;
}
......@@ -76,48 +80,34 @@ struct clk_hw *of_clk_hw_pmc_get(struct of_phandle_args *clkspec, void *data)
return ERR_PTR(-EINVAL);
}
void pmc_data_free(struct pmc_data *pmc_data)
{
kfree(pmc_data->chws);
kfree(pmc_data->shws);
kfree(pmc_data->phws);
kfree(pmc_data->ghws);
}
struct pmc_data *pmc_data_allocate(unsigned int ncore, unsigned int nsystem,
unsigned int nperiph, unsigned int ngck)
unsigned int nperiph, unsigned int ngck,
unsigned int npck)
{
struct pmc_data *pmc_data = kzalloc(sizeof(*pmc_data), GFP_KERNEL);
unsigned int num_clks = ncore + nsystem + nperiph + ngck + npck;
struct pmc_data *pmc_data;
pmc_data = kzalloc(struct_size(pmc_data, hwtable, num_clks),
GFP_KERNEL);
if (!pmc_data)
return NULL;
pmc_data->ncore = ncore;
pmc_data->chws = kcalloc(ncore, sizeof(struct clk_hw *), GFP_KERNEL);
if (!pmc_data->chws)
goto err;
pmc_data->chws = pmc_data->hwtable;
pmc_data->nsystem = nsystem;
pmc_data->shws = kcalloc(nsystem, sizeof(struct clk_hw *), GFP_KERNEL);
if (!pmc_data->shws)
goto err;
pmc_data->shws = pmc_data->chws + ncore;
pmc_data->nperiph = nperiph;
pmc_data->phws = kcalloc(nperiph, sizeof(struct clk_hw *), GFP_KERNEL);
if (!pmc_data->phws)
goto err;
pmc_data->phws = pmc_data->shws + nsystem;
pmc_data->ngck = ngck;
pmc_data->ghws = kcalloc(ngck, sizeof(struct clk_hw *), GFP_KERNEL);
if (!pmc_data->ghws)
goto err;
pmc_data->ghws = pmc_data->phws + nperiph;
return pmc_data;
err:
pmc_data_free(pmc_data);
pmc_data->npck = npck;
pmc_data->pchws = pmc_data->ghws + ngck;
return NULL;
return pmc_data;
}
#ifdef CONFIG_PM
......@@ -274,8 +264,11 @@ static int __init pmc_register_ops(void)
struct device_node *np;
np = of_find_matching_node(NULL, sama5d2_pmc_dt_ids);
if (!np)
return -ENODEV;
pmcreg = device_node_to_regmap(np);
of_node_put(np);
if (IS_ERR(pmcreg))
return PTR_ERR(pmcreg);
......
......@@ -24,6 +24,10 @@ struct pmc_data {
struct clk_hw **phws;
unsigned int ngck;
struct clk_hw **ghws;
unsigned int npck;
struct clk_hw **pchws;
struct clk_hw *hwtable[];
};
struct clk_range {
......@@ -94,8 +98,8 @@ struct clk_pcr_layout {
#define ndck(a, s) (a[s - 1].id + 1)
#define nck(a) (a[ARRAY_SIZE(a) - 1].id + 1)
struct pmc_data *pmc_data_allocate(unsigned int ncore, unsigned int nsystem,
unsigned int nperiph, unsigned int ngck);
void pmc_data_free(struct pmc_data *pmc_data);
unsigned int nperiph, unsigned int ngck,
unsigned int npck);
int of_at91_get_clk_range(struct device_node *np, const char *propname,
struct clk_range *range);
......
......@@ -182,10 +182,10 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
if (IS_ERR(regmap))
return;
sam9x60_pmc = pmc_data_allocate(PMC_MAIN + 1,
sam9x60_pmc = pmc_data_allocate(PMC_PLLACK + 1,
nck(sam9x60_systemck),
nck(sam9x60_periphck),
nck(sam9x60_gck));
nck(sam9x60_gck), 8);
if (!sam9x60_pmc)
return;
......@@ -214,6 +214,8 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
if (IS_ERR(hw))
goto err_free;
sam9x60_pmc->chws[PMC_PLLACK] = hw;
hw = sam9x60_clk_register_pll(regmap, &pmc_pll_lock, "upllck",
"main_osc", 1, &upll_characteristics);
if (IS_ERR(hw))
......@@ -255,6 +257,8 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
&sam9x60_programmable_layout);
if (IS_ERR(hw))
goto err_free;
sam9x60_pmc->pchws[i] = hw;
}
for (i = 0; i < ARRAY_SIZE(sam9x60_systemck); i++) {
......@@ -299,7 +303,7 @@ static void __init sam9x60_pmc_setup(struct device_node *np)
return;
err_free:
pmc_data_free(sam9x60_pmc);
kfree(sam9x60_pmc);
}
/* Some clks are used for a clocksource */
CLK_OF_DECLARE(sam9x60_pmc, "microchip,sam9x60-pmc", sam9x60_pmc_setup);
......@@ -89,6 +89,7 @@ static const struct {
{ .n = "i2s1_clk", .id = 55, .r = { .min = 0, .max = 83000000 }, },
{ .n = "can0_clk", .id = 56, .r = { .min = 0, .max = 83000000 }, },
{ .n = "can1_clk", .id = 57, .r = { .min = 0, .max = 83000000 }, },
{ .n = "ptc_clk", .id = 58, .r = { .min = 0, .max = 83000000 }, },
{ .n = "classd_clk", .id = 59, .r = { .min = 0, .max = 83000000 }, },
};
......@@ -166,10 +167,10 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
if (IS_ERR(regmap))
return;
sama5d2_pmc = pmc_data_allocate(PMC_I2S1_MUX + 1,
sama5d2_pmc = pmc_data_allocate(PMC_AUDIOPLLCK + 1,
nck(sama5d2_systemck),
nck(sama5d2_periph32ck),
nck(sama5d2_gck));
nck(sama5d2_gck), 3);
if (!sama5d2_pmc)
return;
......@@ -202,6 +203,8 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
if (IS_ERR(hw))
goto err_free;
sama5d2_pmc->chws[PMC_PLLACK] = hw;
hw = at91_clk_register_audio_pll_frac(regmap, "audiopll_fracck",
"mainck");
if (IS_ERR(hw))
......@@ -217,6 +220,8 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
if (IS_ERR(hw))
goto err_free;
sama5d2_pmc->chws[PMC_AUDIOPLLCK] = hw;
regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr");
if (IS_ERR(regmap_sfr))
regmap_sfr = NULL;
......@@ -267,6 +272,8 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
&sama5d2_programmable_layout);
if (IS_ERR(hw))
goto err_free;
sama5d2_pmc->pchws[i] = hw;
}
for (i = 0; i < ARRAY_SIZE(sama5d2_systemck); i++) {
......@@ -350,6 +357,6 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
return;
err_free:
pmc_data_free(sama5d2_pmc);
kfree(sama5d2_pmc);
}
CLK_OF_DECLARE_DRIVER(sama5d2_pmc, "atmel,sama5d2-pmc", sama5d2_pmc_setup);
......@@ -125,9 +125,9 @@ static void __init sama5d3_pmc_setup(struct device_node *np)
if (IS_ERR(regmap))
return;
sama5d3_pmc = pmc_data_allocate(PMC_MAIN + 1,
sama5d3_pmc = pmc_data_allocate(PMC_PLLACK + 1,
nck(sama5d3_systemck),
nck(sama5d3_periphck), 0);
nck(sama5d3_periphck), 0, 3);
if (!sama5d3_pmc)
return;
......@@ -158,6 +158,8 @@ static void __init sama5d3_pmc_setup(struct device_node *np)
if (IS_ERR(hw))
goto err_free;
sama5d3_pmc->chws[PMC_PLLACK] = hw;
hw = at91_clk_register_utmi(regmap, NULL, "utmick", "mainck");
if (IS_ERR(hw))
goto err_free;
......@@ -201,6 +203,8 @@ static void __init sama5d3_pmc_setup(struct device_node *np)
&at91sam9x5_programmable_layout);
if (IS_ERR(hw))
goto err_free;
sama5d3_pmc->pchws[i] = hw;
}
for (i = 0; i < ARRAY_SIZE(sama5d3_systemck); i++) {
......@@ -231,7 +235,7 @@ static void __init sama5d3_pmc_setup(struct device_node *np)
return;
err_free:
pmc_data_free(sama5d3_pmc);
kfree(sama5d3_pmc);
}
/*
* The TCB is used as the clocksource so its clock is needed early. This means
......
......@@ -140,9 +140,9 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
if (IS_ERR(regmap))
return;
sama5d4_pmc = pmc_data_allocate(PMC_MCK2 + 1,
sama5d4_pmc = pmc_data_allocate(PMC_PLLACK + 1,
nck(sama5d4_systemck),
nck(sama5d4_periph32ck), 0);
nck(sama5d4_periph32ck), 0, 3);
if (!sama5d4_pmc)
return;
......@@ -173,6 +173,8 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
if (IS_ERR(hw))
goto err_free;
sama5d4_pmc->chws[PMC_PLLACK] = hw;
hw = at91_clk_register_utmi(regmap, NULL, "utmick", "mainck");
if (IS_ERR(hw))
goto err_free;
......@@ -224,6 +226,8 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
&at91sam9x5_programmable_layout);
if (IS_ERR(hw))
goto err_free;
sama5d4_pmc->pchws[i] = hw;
}
for (i = 0; i < ARRAY_SIZE(sama5d4_systemck); i++) {
......@@ -267,6 +271,6 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
return;
err_free:
pmc_data_free(sama5d4_pmc);
kfree(sama5d4_pmc);
}
CLK_OF_DECLARE_DRIVER(sama5d4_pmc, "atmel,sama5d4-pmc", sama5d4_pmc_setup);
# SPDX-License-Identifier: GPL-2.0-only
config CLK_BAIKAL_T1
bool "Baikal-T1 Clocks Control Unit interface"
depends on (MIPS_BAIKAL_T1 && OF) || COMPILE_TEST
default MIPS_BAIKAL_T1
help
Clocks Control Unit is the core of Baikal-T1 SoC System Controller
responsible for the chip subsystems clocking and resetting. It
consists of multiple global clock domains, which can be reset by
means of the CCU control registers. These domains and devices placed
in them are fed with clocks generated by a hierarchy of PLLs,
configurable and fixed clock dividers. Enable this option to be able
to select Baikal-T1 CCU PLLs and Dividers drivers.
if CLK_BAIKAL_T1
config CLK_BT1_CCU_PLL
bool "Baikal-T1 CCU PLLs support"
select MFD_SYSCON
default MIPS_BAIKAL_T1
help
Enable this to support the PLLs embedded into the Baikal-T1 SoC
System Controller. These are five PLLs placed at the root of the
clocks hierarchy, right after an external reference oscillator
(normally of 25MHz). They are used to generate high frequency
signals, which are either directly wired to the consumers (like
CPUs, DDR, etc.) or passed over the clock dividers to be only
then used as an individual reference clock of a target device.
config CLK_BT1_CCU_DIV
bool "Baikal-T1 CCU Dividers support"
select RESET_CONTROLLER
select MFD_SYSCON
default MIPS_BAIKAL_T1
help
Enable this to support the CCU dividers used to distribute clocks
between AXI-bus and system devices coming from CCU PLLs of Baikal-T1
SoC. CCU dividers can be either configurable or with fixed divider,
either gateable or ungateable. Some of the CCU dividers can be as well
used to reset the domains they're supplying clock to.
endif
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_CLK_BT1_CCU_PLL) += ccu-pll.o clk-ccu-pll.o
obj-$(CONFIG_CLK_BT1_CCU_DIV) += ccu-div.o clk-ccu-div.o
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2020 BAIKAL ELECTRONICS, JSC
*
* Baikal-T1 CCU Dividers interface driver
*/
#ifndef __CLK_BT1_CCU_DIV_H__
#define __CLK_BT1_CCU_DIV_H__
#include <linux/clk-provider.h>
#include <linux/spinlock.h>
#include <linux/regmap.h>
#include <linux/bits.h>
#include <linux/of.h>
/*
* CCU Divider private flags
* @CCU_DIV_SKIP_ONE: Due to some reason divider can't be set to 1.
* It can be 0 though, which is functionally the same.
* @CCU_DIV_SKIP_ONE_TO_THREE: For some reason divider can't be within [1,3].
* It can be either 0 or greater than 3.
* @CCU_DIV_LOCK_SHIFTED: Find lock-bit at non-standard position.
* @CCU_DIV_RESET_DOMAIN: Provide reset clock domain method.
*/
#define CCU_DIV_SKIP_ONE BIT(1)
#define CCU_DIV_SKIP_ONE_TO_THREE BIT(2)
#define CCU_DIV_LOCK_SHIFTED BIT(3)
#define CCU_DIV_RESET_DOMAIN BIT(4)
/*
* enum ccu_div_type - CCU Divider types
* @CCU_DIV_VAR: Clocks gate with variable divider.
* @CCU_DIV_GATE: Clocks gate with fixed divider.
* @CCU_DIV_FIXED: Ungateable clock with fixed divider.
*/
enum ccu_div_type {
CCU_DIV_VAR,
CCU_DIV_GATE,
CCU_DIV_FIXED
};
/*
* struct ccu_div_init_data - CCU Divider initialization data
* @id: Clocks private identifier.
* @name: Clocks name.
* @parent_name: Parent clocks name in a fw node.
* @base: Divider register base address with respect to the sys_regs base.
* @sys_regs: Baikal-T1 System Controller registers map.
* @np: Pointer to the node describing the CCU Dividers.
* @type: CCU divider type (variable, fixed with and without gate).
* @width: Divider width if it's variable.
* @divider: Divider fixed value.
* @flags: CCU Divider clock flags.
* @features: CCU Divider private features.
*/
struct ccu_div_init_data {
unsigned int id;
const char *name;
const char *parent_name;
unsigned int base;
struct regmap *sys_regs;
struct device_node *np;
enum ccu_div_type type;
union {
unsigned int width;
unsigned int divider;
};
unsigned long flags;
unsigned long features;
};
/*
* struct ccu_div - CCU Divider descriptor
* @hw: clk_hw of the divider.
* @id: Clock private identifier.
* @reg_ctl: Divider control register base address.
* @sys_regs: Baikal-T1 System Controller registers map.
* @lock: Divider state change spin-lock.
* @mask: Divider field mask.
* @divider: Divider fixed value.
* @flags: Divider clock flags.
* @features: CCU Divider private features.
*/
struct ccu_div {
struct clk_hw hw;
unsigned int id;
unsigned int reg_ctl;
struct regmap *sys_regs;
spinlock_t lock;
union {
u32 mask;
unsigned int divider;
};
unsigned long flags;
unsigned long features;
};
#define to_ccu_div(_hw) container_of(_hw, struct ccu_div, hw)
static inline struct clk_hw *ccu_div_get_clk_hw(struct ccu_div *div)
{
return div ? &div->hw : NULL;
}
struct ccu_div *ccu_div_hw_register(const struct ccu_div_init_data *init);
void ccu_div_hw_unregister(struct ccu_div *div);
int ccu_div_reset_domain(struct ccu_div *div);
#endif /* __CLK_BT1_CCU_DIV_H__ */
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2020 BAIKAL ELECTRONICS, JSC
*
* Baikal-T1 CCU PLL interface driver
*/
#ifndef __CLK_BT1_CCU_PLL_H__
#define __CLK_BT1_CCU_PLL_H__
#include <linux/clk-provider.h>
#include <linux/spinlock.h>
#include <linux/regmap.h>
#include <linux/bits.h>
#include <linux/of.h>
/*
* struct ccu_pll_init_data - CCU PLL initialization data
* @id: Clock private identifier.
* @name: Clocks name.
* @parent_name: Clocks parent name in a fw node.
* @base: PLL registers base address with respect to the sys_regs base.
* @sys_regs: Baikal-T1 System Controller registers map.
* @np: Pointer to the node describing the CCU PLLs.
* @flags: PLL clock flags.
*/
struct ccu_pll_init_data {
unsigned int id;
const char *name;
const char *parent_name;
unsigned int base;
struct regmap *sys_regs;
struct device_node *np;
unsigned long flags;
};
/*
* struct ccu_pll - CCU PLL descriptor
* @hw: clk_hw of the PLL.
* @id: Clock private identifier.
* @reg_ctl: PLL control register base.
* @reg_ctl1: PLL control1 register base.
* @sys_regs: Baikal-T1 System Controller registers map.
* @lock: PLL state change spin-lock.
*/
struct ccu_pll {
struct clk_hw hw;
unsigned int id;
unsigned int reg_ctl;
unsigned int reg_ctl1;
struct regmap *sys_regs;
spinlock_t lock;
};
#define to_ccu_pll(_hw) container_of(_hw, struct ccu_pll, hw)
static inline struct clk_hw *ccu_pll_get_clk_hw(struct ccu_pll *pll)
{
return pll ? &pll->hw : NULL;
}
struct ccu_pll *ccu_pll_hw_register(const struct ccu_pll_init_data *init);
void ccu_pll_hw_unregister(struct ccu_pll *pll);
#endif /* __CLK_BT1_CCU_PLL_H__ */
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2020 BAIKAL ELECTRONICS, JSC
*
* Authors:
* Serge Semin <Sergey.Semin@baikalelectronics.ru>
* Dmitry Dunaev <dmitry.dunaev@baikalelectronics.ru>
*
* Baikal-T1 CCU PLL clocks driver
*/
#define pr_fmt(fmt) "bt1-ccu-pll: " fmt
#include <linux/kernel.h>
#include <linux/printk.h>
#include <linux/slab.h>
#include <linux/clk-provider.h>
#include <linux/mfd/syscon.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/ioport.h>
#include <linux/regmap.h>
#include <dt-bindings/clock/bt1-ccu.h>
#include "ccu-pll.h"
#define CCU_CPU_PLL_BASE 0x000
#define CCU_SATA_PLL_BASE 0x008
#define CCU_DDR_PLL_BASE 0x010
#define CCU_PCIE_PLL_BASE 0x018
#define CCU_ETH_PLL_BASE 0x020
#define CCU_PLL_INFO(_id, _name, _pname, _base, _flags) \
{ \
.id = _id, \
.name = _name, \
.parent_name = _pname, \
.base = _base, \
.flags = _flags \
}
#define CCU_PLL_NUM ARRAY_SIZE(pll_info)
struct ccu_pll_info {
unsigned int id;
const char *name;
const char *parent_name;
unsigned int base;
unsigned long flags;
};
/*
* Mark as critical all PLLs except Ethernet one. CPU and DDR PLLs are sources
* of CPU cores and DDR controller reference clocks, due to which they
* obviously shouldn't be ever gated. SATA and PCIe PLLs are the parents of
* APB-bus and DDR controller AXI-bus clocks. If they are gated the system will
* be unusable.
*/
static const struct ccu_pll_info pll_info[] = {
CCU_PLL_INFO(CCU_CPU_PLL, "cpu_pll", "ref_clk", CCU_CPU_PLL_BASE,
CLK_IS_CRITICAL),
CCU_PLL_INFO(CCU_SATA_PLL, "sata_pll", "ref_clk", CCU_SATA_PLL_BASE,
CLK_IS_CRITICAL | CLK_SET_RATE_GATE),
CCU_PLL_INFO(CCU_DDR_PLL, "ddr_pll", "ref_clk", CCU_DDR_PLL_BASE,
CLK_IS_CRITICAL | CLK_SET_RATE_GATE),
CCU_PLL_INFO(CCU_PCIE_PLL, "pcie_pll", "ref_clk", CCU_PCIE_PLL_BASE,
CLK_IS_CRITICAL),
CCU_PLL_INFO(CCU_ETH_PLL, "eth_pll", "ref_clk", CCU_ETH_PLL_BASE,
CLK_SET_RATE_GATE)
};
struct ccu_pll_data {
struct device_node *np;
struct regmap *sys_regs;
struct ccu_pll *plls[CCU_PLL_NUM];
};
static struct ccu_pll *ccu_pll_find_desc(struct ccu_pll_data *data,
unsigned int clk_id)
{
struct ccu_pll *pll;
int idx;
for (idx = 0; idx < CCU_PLL_NUM; ++idx) {
pll = data->plls[idx];
if (pll && pll->id == clk_id)
return pll;
}
return ERR_PTR(-EINVAL);
}
static struct ccu_pll_data *ccu_pll_create_data(struct device_node *np)
{
struct ccu_pll_data *data;
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return ERR_PTR(-ENOMEM);
data->np = np;
return data;
}
static void ccu_pll_free_data(struct ccu_pll_data *data)
{
kfree(data);
}
static int ccu_pll_find_sys_regs(struct ccu_pll_data *data)
{
data->sys_regs = syscon_node_to_regmap(data->np->parent);
if (IS_ERR(data->sys_regs)) {
pr_err("Failed to find syscon regs for '%s'\n",
of_node_full_name(data->np));
return PTR_ERR(data->sys_regs);
}
return 0;
}
static struct clk_hw *ccu_pll_of_clk_hw_get(struct of_phandle_args *clkspec,
void *priv)
{
struct ccu_pll_data *data = priv;
struct ccu_pll *pll;
unsigned int clk_id;
clk_id = clkspec->args[0];
pll = ccu_pll_find_desc(data, clk_id);
if (IS_ERR(pll)) {
pr_info("Invalid PLL clock ID %d specified\n", clk_id);
return ERR_CAST(pll);
}
return ccu_pll_get_clk_hw(pll);
}
static int ccu_pll_clk_register(struct ccu_pll_data *data)
{
int idx, ret;
for (idx = 0; idx < CCU_PLL_NUM; ++idx) {
const struct ccu_pll_info *info = &pll_info[idx];
struct ccu_pll_init_data init = {0};
init.id = info->id;
init.name = info->name;
init.parent_name = info->parent_name;
init.base = info->base;
init.sys_regs = data->sys_regs;
init.np = data->np;
init.flags = info->flags;
data->plls[idx] = ccu_pll_hw_register(&init);
if (IS_ERR(data->plls[idx])) {
ret = PTR_ERR(data->plls[idx]);
pr_err("Couldn't register PLL hw '%s'\n",
init.name);
goto err_hw_unregister;
}
}
ret = of_clk_add_hw_provider(data->np, ccu_pll_of_clk_hw_get, data);
if (ret) {
pr_err("Couldn't register PLL provider of '%s'\n",
of_node_full_name(data->np));
goto err_hw_unregister;
}
return 0;
err_hw_unregister:
for (--idx; idx >= 0; --idx)
ccu_pll_hw_unregister(data->plls[idx]);
return ret;
}
static __init void ccu_pll_init(struct device_node *np)
{
struct ccu_pll_data *data;
int ret;
data = ccu_pll_create_data(np);
if (IS_ERR(data))
return;
ret = ccu_pll_find_sys_regs(data);
if (ret)
goto err_free_data;
ret = ccu_pll_clk_register(data);
if (ret)
goto err_free_data;
return;
err_free_data:
ccu_pll_free_data(data);
}
CLK_OF_DECLARE(ccu_pll, "baikal,bt1-ccu-pll", ccu_pll_init);
......@@ -396,8 +396,8 @@ static unsigned long bcm2835_measure_tcnt_mux(struct bcm2835_cprman *cprman,
}
static void bcm2835_debugfs_regset(struct bcm2835_cprman *cprman, u32 base,
struct debugfs_reg32 *regs, size_t nregs,
struct dentry *dentry)
const struct debugfs_reg32 *regs,
size_t nregs, struct dentry *dentry)
{
struct debugfs_regset32 *regset;
......@@ -1240,7 +1240,7 @@ static u8 bcm2835_clock_get_parent(struct clk_hw *hw)
return (src & CM_SRC_MASK) >> CM_SRC_SHIFT;
}
static struct debugfs_reg32 bcm2835_debugfs_clock_reg32[] = {
static const struct debugfs_reg32 bcm2835_debugfs_clock_reg32[] = {
{
.name = "ctl",
.offset = 0,
......@@ -1296,8 +1296,9 @@ static const struct clk_ops bcm2835_vpu_clock_clk_ops = {
};
static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman,
const struct bcm2835_pll_data *data)
const void *data)
{
const struct bcm2835_pll_data *pll_data = data;
struct bcm2835_pll *pll;
struct clk_init_data init;
int ret;
......@@ -1307,7 +1308,7 @@ static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman,
/* All of the PLLs derive from the external oscillator. */
init.parent_names = &cprman->real_parent_names[0];
init.num_parents = 1;
init.name = data->name;
init.name = pll_data->name;
init.ops = &bcm2835_pll_clk_ops;
init.flags = CLK_IGNORE_UNUSED;
......@@ -1316,7 +1317,7 @@ static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman,
return NULL;
pll->cprman = cprman;
pll->data = data;
pll->data = pll_data;
pll->hw.init = &init;
ret = devm_clk_hw_register(cprman->dev, &pll->hw);
......@@ -1327,35 +1328,36 @@ static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman,
static struct clk_hw *
bcm2835_register_pll_divider(struct bcm2835_cprman *cprman,
const struct bcm2835_pll_divider_data *data)
const void *data)
{
const struct bcm2835_pll_divider_data *divider_data = data;
struct bcm2835_pll_divider *divider;
struct clk_init_data init;
const char *divider_name;
int ret;
if (data->fixed_divider != 1) {
if (divider_data->fixed_divider != 1) {
divider_name = devm_kasprintf(cprman->dev, GFP_KERNEL,
"%s_prediv", data->name);
"%s_prediv", divider_data->name);
if (!divider_name)
return NULL;
} else {
divider_name = data->name;
divider_name = divider_data->name;
}
memset(&init, 0, sizeof(init));
init.parent_names = &data->source_pll;
init.parent_names = &divider_data->source_pll;
init.num_parents = 1;
init.name = divider_name;
init.ops = &bcm2835_pll_divider_clk_ops;
init.flags = data->flags | CLK_IGNORE_UNUSED;
init.flags = divider_data->flags | CLK_IGNORE_UNUSED;
divider = devm_kzalloc(cprman->dev, sizeof(*divider), GFP_KERNEL);
if (!divider)
return NULL;
divider->div.reg = cprman->regs + data->a2w_reg;
divider->div.reg = cprman->regs + divider_data->a2w_reg;
divider->div.shift = A2W_PLL_DIV_SHIFT;
divider->div.width = A2W_PLL_DIV_BITS;
divider->div.flags = CLK_DIVIDER_MAX_AT_ZERO;
......@@ -1364,7 +1366,7 @@ bcm2835_register_pll_divider(struct bcm2835_cprman *cprman,
divider->div.table = NULL;
divider->cprman = cprman;
divider->data = data;
divider->data = divider_data;
ret = devm_clk_hw_register(cprman->dev, &divider->div.hw);
if (ret)
......@@ -1374,20 +1376,22 @@ bcm2835_register_pll_divider(struct bcm2835_cprman *cprman,
* PLLH's channels have a fixed divide by 10 afterwards, which
* is what our consumers are actually using.
*/
if (data->fixed_divider != 1) {
return clk_hw_register_fixed_factor(cprman->dev, data->name,
if (divider_data->fixed_divider != 1) {
return clk_hw_register_fixed_factor(cprman->dev,
divider_data->name,
divider_name,
CLK_SET_RATE_PARENT,
1,
data->fixed_divider);
divider_data->fixed_divider);
}
return &divider->div.hw;
}
static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman,
const struct bcm2835_clock_data *data)
const void *data)
{
const struct bcm2835_clock_data *clock_data = data;
struct bcm2835_clock *clock;
struct clk_init_data init;
const char *parents[1 << CM_SRC_BITS];
......@@ -1398,8 +1402,8 @@ static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman,
* Replace our strings referencing parent clocks with the
* actual clock-output-name of the parent.
*/
for (i = 0; i < data->num_mux_parents; i++) {
parents[i] = data->parents[i];
for (i = 0; i < clock_data->num_mux_parents; i++) {
parents[i] = clock_data->parents[i];
ret = match_string(cprman_parent_names,
ARRAY_SIZE(cprman_parent_names),
......@@ -1410,18 +1414,18 @@ static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman,
memset(&init, 0, sizeof(init));
init.parent_names = parents;
init.num_parents = data->num_mux_parents;
init.name = data->name;
init.flags = data->flags | CLK_IGNORE_UNUSED;
init.num_parents = clock_data->num_mux_parents;
init.name = clock_data->name;
init.flags = clock_data->flags | CLK_IGNORE_UNUSED;
/*
* Pass the CLK_SET_RATE_PARENT flag if we are allowed to propagate
* rate changes on at least of the parents.
*/
if (data->set_rate_parent)
if (clock_data->set_rate_parent)
init.flags |= CLK_SET_RATE_PARENT;
if (data->is_vpu_clock) {
if (clock_data->is_vpu_clock) {
init.ops = &bcm2835_vpu_clock_clk_ops;
} else {
init.ops = &bcm2835_clock_clk_ops;
......@@ -1430,7 +1434,7 @@ static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman,
/* If the clock wasn't actually enabled at boot, it's not
* critical.
*/
if (!(cprman_read(cprman, data->ctl_reg) & CM_ENABLE))
if (!(cprman_read(cprman, clock_data->ctl_reg) & CM_ENABLE))
init.flags &= ~CLK_IS_CRITICAL;
}
......@@ -1439,7 +1443,7 @@ static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman,
return NULL;
clock->cprman = cprman;
clock->data = data;
clock->data = clock_data;
clock->hw.init = &init;
ret = devm_clk_hw_register(cprman->dev, &clock->hw);
......@@ -1448,25 +1452,27 @@ static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman,
return &clock->hw;
}
static struct clk *bcm2835_register_gate(struct bcm2835_cprman *cprman,
const struct bcm2835_gate_data *data)
static struct clk_hw *bcm2835_register_gate(struct bcm2835_cprman *cprman,
const void *data)
{
return clk_register_gate(cprman->dev, data->name, data->parent,
CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE,
cprman->regs + data->ctl_reg,
CM_GATE_BIT, 0, &cprman->regs_lock);
const struct bcm2835_gate_data *gate_data = data;
return clk_hw_register_gate(cprman->dev, gate_data->name,
gate_data->parent,
CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE,
cprman->regs + gate_data->ctl_reg,
CM_GATE_BIT, 0, &cprman->regs_lock);
}
typedef struct clk_hw *(*bcm2835_clk_register)(struct bcm2835_cprman *cprman,
const void *data);
struct bcm2835_clk_desc {
bcm2835_clk_register clk_register;
struct clk_hw *(*clk_register)(struct bcm2835_cprman *cprman,
const void *data);
unsigned int supported;
const void *data;
};
/* assignment helper macros for different clock types */
#define _REGISTER(f, s, ...) { .clk_register = (bcm2835_clk_register)f, \
#define _REGISTER(f, s, ...) { .clk_register = f, \
.supported = s, \
.data = __VA_ARGS__ }
#define REGISTER_PLL(s, ...) _REGISTER(&bcm2835_register_pll, \
......
......@@ -642,14 +642,22 @@ static const u32 ast2600_a0_axi_ahb_div_table[] = {
2, 2, 3, 5,
};
static const u32 ast2600_a1_axi_ahb_div_table[] = {
4, 6, 2, 4,
static const u32 ast2600_a1_axi_ahb_div0_tbl[] = {
3, 2, 3, 4,
};
static const u32 ast2600_a1_axi_ahb_div1_tbl[] = {
3, 4, 6, 8,
};
static const u32 ast2600_a1_axi_ahb200_tbl[] = {
3, 4, 3, 4, 2, 2, 2, 2,
};
static void __init aspeed_g6_cc(struct regmap *map)
{
struct clk_hw *hw;
u32 val, div, chip_id, axi_div, ahb_div;
u32 val, div, divbits, chip_id, axi_div, ahb_div;
clk_hw_register_fixed_rate(NULL, "clkin", NULL, 0, 25000000);
......@@ -679,11 +687,22 @@ static void __init aspeed_g6_cc(struct regmap *map)
else
axi_div = 2;
divbits = (val >> 11) & 0x3;
regmap_read(map, ASPEED_G6_SILICON_REV, &chip_id);
if (chip_id & BIT(16))
ahb_div = ast2600_a1_axi_ahb_div_table[(val >> 11) & 0x3];
else
if (chip_id & BIT(16)) {
if (!divbits) {
ahb_div = ast2600_a1_axi_ahb200_tbl[(val >> 8) & 0x3];
if (val & BIT(16))
ahb_div *= 2;
} else {
if (val & BIT(16))
ahb_div = ast2600_a1_axi_ahb_div1_tbl[divbits];
else
ahb_div = ast2600_a1_axi_ahb_div0_tbl[divbits];
}
} else {
ahb_div = ast2600_a0_axi_ahb_div_table[(val >> 11) & 0x3];
}
hw = clk_hw_register_fixed_factor(NULL, "ahb", "hpll", 0, 1, axi_div * ahb_div);
aspeed_g6_clk_data->hws[ASPEED_CLK_AHB] = hw;
......
......@@ -53,35 +53,38 @@ struct hsdk_pll_cfg {
u32 fbdiv;
u32 odiv;
u32 band;
u32 bypass;
};
static const struct hsdk_pll_cfg asdt_pll_cfg[] = {
{ 100000000, 0, 11, 3, 0 },
{ 133000000, 0, 15, 3, 0 },
{ 200000000, 1, 47, 3, 0 },
{ 233000000, 1, 27, 2, 0 },
{ 300000000, 1, 35, 2, 0 },
{ 333000000, 1, 39, 2, 0 },
{ 400000000, 1, 47, 2, 0 },
{ 500000000, 0, 14, 1, 0 },
{ 600000000, 0, 17, 1, 0 },
{ 700000000, 0, 20, 1, 0 },
{ 800000000, 0, 23, 1, 0 },
{ 900000000, 1, 26, 0, 0 },
{ 1000000000, 1, 29, 0, 0 },
{ 1100000000, 1, 32, 0, 0 },
{ 1200000000, 1, 35, 0, 0 },
{ 1300000000, 1, 38, 0, 0 },
{ 1400000000, 1, 41, 0, 0 },
{ 1500000000, 1, 44, 0, 0 },
{ 1600000000, 1, 47, 0, 0 },
{ 100000000, 0, 11, 3, 0, 0 },
{ 133000000, 0, 15, 3, 0, 0 },
{ 200000000, 1, 47, 3, 0, 0 },
{ 233000000, 1, 27, 2, 0, 0 },
{ 300000000, 1, 35, 2, 0, 0 },
{ 333000000, 1, 39, 2, 0, 0 },
{ 400000000, 1, 47, 2, 0, 0 },
{ 500000000, 0, 14, 1, 0, 0 },
{ 600000000, 0, 17, 1, 0, 0 },
{ 700000000, 0, 20, 1, 0, 0 },
{ 800000000, 0, 23, 1, 0, 0 },
{ 900000000, 1, 26, 0, 0, 0 },
{ 1000000000, 1, 29, 0, 0, 0 },
{ 1100000000, 1, 32, 0, 0, 0 },
{ 1200000000, 1, 35, 0, 0, 0 },
{ 1300000000, 1, 38, 0, 0, 0 },
{ 1400000000, 1, 41, 0, 0, 0 },
{ 1500000000, 1, 44, 0, 0, 0 },
{ 1600000000, 1, 47, 0, 0, 0 },
{}
};
static const struct hsdk_pll_cfg hdmi_pll_cfg[] = {
{ 297000000, 0, 21, 2, 0 },
{ 540000000, 0, 19, 1, 0 },
{ 594000000, 0, 21, 1, 0 },
{ 27000000, 0, 0, 0, 0, 1 },
{ 148500000, 0, 21, 3, 0, 0 },
{ 297000000, 0, 21, 2, 0, 0 },
{ 540000000, 0, 19, 1, 0, 0 },
{ 594000000, 0, 21, 1, 0, 0 },
{}
};
......@@ -134,11 +137,16 @@ static inline void hsdk_pll_set_cfg(struct hsdk_pll_clk *clk,
{
u32 val = 0;
/* Powerdown and Bypass bits should be cleared */
val |= cfg->idiv << CGU_PLL_CTRL_IDIV_SHIFT;
val |= cfg->fbdiv << CGU_PLL_CTRL_FBDIV_SHIFT;
val |= cfg->odiv << CGU_PLL_CTRL_ODIV_SHIFT;
val |= cfg->band << CGU_PLL_CTRL_BAND_SHIFT;
if (cfg->bypass) {
val = hsdk_pll_read(clk, CGU_PLL_CTRL);
val |= CGU_PLL_CTRL_BYPASS;
} else {
/* Powerdown and Bypass bits should be cleared */
val |= cfg->idiv << CGU_PLL_CTRL_IDIV_SHIFT;
val |= cfg->fbdiv << CGU_PLL_CTRL_FBDIV_SHIFT;
val |= cfg->odiv << CGU_PLL_CTRL_ODIV_SHIFT;
val |= cfg->band << CGU_PLL_CTRL_BAND_SHIFT;
}
dev_dbg(clk->dev, "write configuration: %#x\n", val);
......@@ -172,14 +180,14 @@ static unsigned long hsdk_pll_recalc_rate(struct clk_hw *hw,
dev_dbg(clk->dev, "current configuration: %#x\n", val);
/* Check if PLL is disabled */
if (val & CGU_PLL_CTRL_PD)
return 0;
/* Check if PLL is bypassed */
if (val & CGU_PLL_CTRL_BYPASS)
return parent_rate;
/* Check if PLL is disabled */
if (val & CGU_PLL_CTRL_PD)
return 0;
/* input divider = reg.idiv + 1 */
idiv = 1 + ((val & CGU_PLL_CTRL_IDIV_MASK) >> CGU_PLL_CTRL_IDIV_SHIFT);
/* fb divider = 2*(reg.fbdiv + 1) */
......
// SPDX-License-Identifier: GPL-2.0
/*
* Driver for Silicon Labs Si5341/Si5340 Clock generator
* Driver for Silicon Labs Si5340, Si5341, Si5342, Si5344 and Si5345
* Copyright (C) 2019 Topic Embedded Products
* Author: Mike Looijmans <mike.looijmans@topic.nl>
*
* The Si5341 has 10 outputs and 5 synthesizers.
* The Si5340 is a smaller version of the Si5341 with only 4 outputs.
* The Si5345 is similar to the Si5341, with the addition of fractional input
* dividers and automatic input selection.
* The Si5342 and Si5344 are smaller versions of the Si5345.
*/
#include <linux/clk.h>
......@@ -18,11 +24,17 @@
#define SI5341_NUM_INPUTS 4
#define SI5341_MAX_NUM_OUTPUTS 10
#define SI5340_MAX_NUM_OUTPUTS 4
#define SI5341_MAX_NUM_OUTPUTS 10
#define SI5342_MAX_NUM_OUTPUTS 2
#define SI5344_MAX_NUM_OUTPUTS 4
#define SI5345_MAX_NUM_OUTPUTS 10
#define SI5341_NUM_SYNTH 5
#define SI5340_NUM_SYNTH 4
#define SI5341_NUM_SYNTH 5
#define SI5342_NUM_SYNTH 2
#define SI5344_NUM_SYNTH 4
#define SI5345_NUM_SYNTH 5
/* Range of the synthesizer fractional divider */
#define SI5341_SYNTH_N_MIN 10
......@@ -65,6 +77,7 @@ struct clk_si5341 {
u64 freq_vco; /* 13500–14256 MHz */
u8 num_outputs;
u8 num_synth;
u16 chip_id;
};
#define to_clk_si5341(_hw) container_of(_hw, struct clk_si5341, hw)
......@@ -142,6 +155,7 @@ static const char * const si5341_input_clock_names[] = {
};
/* Output configuration registers 0..9 are not quite logically organized */
/* Also for si5345 */
static const u16 si5341_reg_output_offset[] = {
0x0108,
0x010D,
......@@ -155,6 +169,7 @@ static const u16 si5341_reg_output_offset[] = {
0x013A,
};
/* for si5340, si5342 and si5344 */
static const u16 si5340_reg_output_offset[] = {
0x0112,
0x0117,
......@@ -974,12 +989,32 @@ static int si5341_probe_chip_id(struct clk_si5341 *data)
data->reg_output_offset = si5341_reg_output_offset;
data->reg_rdiv_offset = si5341_reg_rdiv_offset;
break;
case 0x5342:
data->num_outputs = SI5342_MAX_NUM_OUTPUTS;
data->num_synth = SI5342_NUM_SYNTH;
data->reg_output_offset = si5340_reg_output_offset;
data->reg_rdiv_offset = si5340_reg_rdiv_offset;
break;
case 0x5344:
data->num_outputs = SI5344_MAX_NUM_OUTPUTS;
data->num_synth = SI5344_NUM_SYNTH;
data->reg_output_offset = si5340_reg_output_offset;
data->reg_rdiv_offset = si5340_reg_rdiv_offset;
break;
case 0x5345:
data->num_outputs = SI5345_MAX_NUM_OUTPUTS;
data->num_synth = SI5345_NUM_SYNTH;
data->reg_output_offset = si5341_reg_output_offset;
data->reg_rdiv_offset = si5341_reg_rdiv_offset;
break;
default:
dev_err(&data->i2c_client->dev, "Model '%x' not supported\n",
model);
return -EINVAL;
}
data->chip_id = model;
return 0;
}
......@@ -1054,6 +1089,11 @@ static const struct si5341_reg_default si5341_preamble[] = {
{ 0x0B4E, 0x1A },
};
static const struct si5341_reg_default si5345_preamble[] = {
{ 0x0B25, 0x00 },
{ 0x0540, 0x01 },
};
static int si5341_send_preamble(struct clk_si5341 *data)
{
int res;
......@@ -1068,8 +1108,14 @@ static int si5341_send_preamble(struct clk_si5341 *data)
res = regmap_write(data->regmap, 0xB24, revision < 2 ? 0xD8 : 0xC0);
if (res < 0)
return res;
res = si5341_write_multiple(data,
si5341_preamble, ARRAY_SIZE(si5341_preamble));
/* The si5342..si5345 require a different preamble */
if (data->chip_id > 0x5341)
res = si5341_write_multiple(data,
si5345_preamble, ARRAY_SIZE(si5345_preamble));
else
res = si5341_write_multiple(data,
si5341_preamble, ARRAY_SIZE(si5341_preamble));
if (res < 0)
return res;
......@@ -1095,6 +1141,13 @@ static int si5341_finalize_defaults(struct clk_si5341 *data)
if (res < 0)
return res;
/* The si5342..si5345 have an additional post-amble */
if (data->chip_id > 0x5341) {
res = regmap_write(data->regmap, 0x540, 0x0);
if (res < 0)
return res;
}
/* Datasheet does not explain these nameless registers */
res = regmap_write(data->regmap, 0xB24, revision < 2 ? 0xDB : 0xC3);
if (res < 0)
......@@ -1499,6 +1552,9 @@ static int si5341_probe(struct i2c_client *client,
static const struct i2c_device_id si5341_id[] = {
{ "si5340", 0 },
{ "si5341", 1 },
{ "si5342", 2 },
{ "si5344", 4 },
{ "si5345", 5 },
{ }
};
MODULE_DEVICE_TABLE(i2c, si5341_id);
......@@ -1506,6 +1562,9 @@ MODULE_DEVICE_TABLE(i2c, si5341_id);
static const struct of_device_id clk_si5341_of_match[] = {
{ .compatible = "silabs,si5340" },
{ .compatible = "silabs,si5341" },
{ .compatible = "silabs,si5342" },
{ .compatible = "silabs,si5344" },
{ .compatible = "silabs,si5345" },
{ }
};
MODULE_DEVICE_TABLE(of, clk_si5341_of_match);
......
......@@ -124,6 +124,7 @@ enum vc5_model {
IDT_VC5_5P49V5933,
IDT_VC5_5P49V5935,
IDT_VC6_5P49V6901,
IDT_VC6_5P49V6965,
};
/* Structure to describe features of a particular VC5 model */
......@@ -683,6 +684,7 @@ static int vc5_map_index_to_output(const enum vc5_model model,
case IDT_VC5_5P49V5925:
case IDT_VC5_5P49V5935:
case IDT_VC6_5P49V6901:
case IDT_VC6_5P49V6965:
default:
return n;
}
......@@ -956,12 +958,20 @@ static const struct vc5_chip_info idt_5p49v6901_info = {
.flags = VC5_HAS_PFD_FREQ_DBL,
};
static const struct vc5_chip_info idt_5p49v6965_info = {
.model = IDT_VC6_5P49V6965,
.clk_fod_cnt = 4,
.clk_out_cnt = 5,
.flags = 0,
};
static const struct i2c_device_id vc5_id[] = {
{ "5p49v5923", .driver_data = IDT_VC5_5P49V5923 },
{ "5p49v5925", .driver_data = IDT_VC5_5P49V5925 },
{ "5p49v5933", .driver_data = IDT_VC5_5P49V5933 },
{ "5p49v5935", .driver_data = IDT_VC5_5P49V5935 },
{ "5p49v6901", .driver_data = IDT_VC6_5P49V6901 },
{ "5p49v6965", .driver_data = IDT_VC6_5P49V6965 },
{ }
};
MODULE_DEVICE_TABLE(i2c, vc5_id);
......@@ -972,6 +982,7 @@ static const struct of_device_id clk_vc5_of_match[] = {
{ .compatible = "idt,5p49v5933", .data = &idt_5p49v5933_info },
{ .compatible = "idt,5p49v5935", .data = &idt_5p49v5935_info },
{ .compatible = "idt,5p49v6901", .data = &idt_5p49v6901_info },
{ .compatible = "idt,5p49v6965", .data = &idt_5p49v6965_info },
{ },
};
MODULE_DEVICE_TABLE(of, clk_vc5_of_match);
......
......@@ -3299,10 +3299,6 @@ static int __init clk_debug_init(void)
late_initcall(clk_debug_init);
#else
static inline void clk_debug_register(struct clk_core *core) { }
static inline void clk_debug_reparent(struct clk_core *core,
struct clk_core *new_parent)
{
}
static inline void clk_debug_unregister(struct clk_core *core)
{
}
......
......@@ -10,25 +10,25 @@ config MXC_CLK_SCU
config CLK_IMX8MM
bool "IMX8MM CCM Clock Driver"
depends on ARCH_MXC && ARM64
depends on ARCH_MXC
help
Build the driver for i.MX8MM CCM Clock Driver
config CLK_IMX8MN
bool "IMX8MN CCM Clock Driver"
depends on ARCH_MXC && ARM64
depends on ARCH_MXC
help
Build the driver for i.MX8MN CCM Clock Driver
config CLK_IMX8MP
bool "IMX8MP CCM Clock Driver"
depends on ARCH_MXC && ARM64
depends on ARCH_MXC
help
Build the driver for i.MX8MP CCM Clock Driver
config CLK_IMX8MQ
bool "IMX8MQ CCM Clock Driver"
depends on ARCH_MXC && ARM64
depends on ARCH_MXC
help
Build the driver for i.MX8MQ CCM Clock Driver
......
......@@ -124,6 +124,52 @@ static const struct clk_ops imx8m_clk_composite_divider_ops = {
.set_rate = imx8m_clk_composite_divider_set_rate,
};
static u8 imx8m_clk_composite_mux_get_parent(struct clk_hw *hw)
{
return clk_mux_ops.get_parent(hw);
}
static int imx8m_clk_composite_mux_set_parent(struct clk_hw *hw, u8 index)
{
struct clk_mux *mux = to_clk_mux(hw);
u32 val = clk_mux_index_to_val(mux->table, mux->flags, index);
unsigned long flags = 0;
u32 reg;
if (mux->lock)
spin_lock_irqsave(mux->lock, flags);
reg = readl(mux->reg);
reg &= ~(mux->mask << mux->shift);
val = val << mux->shift;
reg |= val;
/*
* write twice to make sure non-target interface
* SEL_A/B point the same clk input.
*/
writel(reg, mux->reg);
writel(reg, mux->reg);
if (mux->lock)
spin_unlock_irqrestore(mux->lock, flags);
return 0;
}
static int
imx8m_clk_composite_mux_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
return clk_mux_ops.determine_rate(hw, req);
}
static const struct clk_ops imx8m_clk_composite_mux_ops = {
.get_parent = imx8m_clk_composite_mux_get_parent,
.set_parent = imx8m_clk_composite_mux_set_parent,
.determine_rate = imx8m_clk_composite_mux_determine_rate,
};
struct clk_hw *imx8m_clk_hw_composite_flags(const char *name,
const char * const *parent_names,
int num_parents, void __iomem *reg,
......@@ -136,6 +182,7 @@ struct clk_hw *imx8m_clk_hw_composite_flags(const char *name,
struct clk_gate *gate = NULL;
struct clk_mux *mux = NULL;
const struct clk_ops *divider_ops;
const struct clk_ops *mux_ops;
mux = kzalloc(sizeof(*mux), GFP_KERNEL);
if (!mux)
......@@ -157,10 +204,17 @@ struct clk_hw *imx8m_clk_hw_composite_flags(const char *name,
div->shift = PCG_DIV_SHIFT;
div->width = PCG_CORE_DIV_WIDTH;
divider_ops = &clk_divider_ops;
mux_ops = &imx8m_clk_composite_mux_ops;
} else if (composite_flags & IMX_COMPOSITE_BUS) {
div->shift = PCG_PREDIV_SHIFT;
div->width = PCG_PREDIV_WIDTH;
divider_ops = &imx8m_clk_composite_divider_ops;
mux_ops = &imx8m_clk_composite_mux_ops;
} else {
div->shift = PCG_PREDIV_SHIFT;
div->width = PCG_PREDIV_WIDTH;
divider_ops = &imx8m_clk_composite_divider_ops;
mux_ops = &clk_mux_ops;
}
div->lock = &imx_ccm_lock;
......@@ -176,7 +230,7 @@ struct clk_hw *imx8m_clk_hw_composite_flags(const char *name,
gate->lock = &imx_ccm_lock;
hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
mux_hw, &clk_mux_ops, div_hw,
mux_hw, mux_ops, div_hw,
divider_ops, gate_hw, &clk_gate_ops, flags);
if (IS_ERR(hw))
goto fail;
......
This diff is collapsed.
......@@ -503,7 +503,7 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
clk_prepare_enable(hws[IMX6UL_CLK_USBPHY2_GATE]->clk);
}
clk_set_parent(hws[IMX6UL_CLK_CAN_SEL]->clk, hws[IMX6UL_CLK_PLL3_60M]->clk);
clk_set_parent(hws[IMX6UL_CLK_CAN_SEL]->clk, hws[IMX6UL_CLK_PLL3_80M]->clk);
if (clk_on_imx6ul())
clk_set_parent(hws[IMX6UL_CLK_SIM_PRE_SEL]->clk, hws[IMX6UL_CLK_PLL3_USB_OTG]->clk);
else if (clk_on_imx6ull())
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -378,9 +378,9 @@ static const struct clk_ops clk_pll1443x_ops = {
.set_rate = clk_pll1443x_set_rate,
};
struct clk_hw *imx_clk_hw_pll14xx(const char *name, const char *parent_name,
void __iomem *base,
const struct imx_pll14xx_clk *pll_clk)
struct clk_hw *imx_dev_clk_hw_pll14xx(struct device *dev, const char *name,
const char *parent_name, void __iomem *base,
const struct imx_pll14xx_clk *pll_clk)
{
struct clk_pll14xx *pll;
struct clk_hw *hw;
......@@ -426,7 +426,7 @@ struct clk_hw *imx_clk_hw_pll14xx(const char *name, const char *parent_name,
hw = &pll->hw;
ret = clk_hw_register(NULL, hw);
ret = clk_hw_register(dev, hw);
if (ret) {
pr_err("%s: failed to register pll %s %d\n",
__func__, name, ret);
......
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.
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.
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.
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