Merge branches 'clk-pile' and 'clk-microchip' into clk-next

* clk-pile: (111 commits)
  clk: microchip: mpfs: fix regmap_update_bits() mask/val order
  clk: visconti: Make sure clk_init_data is fully initialized
  clk: ti: Make sure clk_init_data is fully initialized
  MAINTAINERS: Add Brian Masney and Jerome Brunet as co-maintainers for clk subsystem
  Drop Michael Turquette's clk maintainer entry
  clk: ti: composite: resolve parent clocks by DT index, not by name
  clk: ti: mux: resolve parent clocks by DT index, not by name
  clk: devres: fix cleanup in devm_clk_get_optional_enabled_with_rate()
  dt-bindings: clock: ti,keystone-gate: Convert to DT schema
  dt-bindings: clock: ti: Convert APLL clock to DT schema
  clk: zynq: pll: Fix kernel-doc after determine_rate() conversion
  dt-bindings: clock: ti,clockdomain: Convert to DT schema
  dt-bindings: clock: Correct white-space style
  clk: tegra: set up proper EMC clock implementation for Tegra114
  clk: clocking-wizard: remove 20kHz restriction
  clk: clocking-wizard: optimize clock search
  clk: clocking-wizard: fix clock difference detection
  clk: mediatek: mt8135: Fix inverted gate control for devapc_ck
  clk: clocking-wizard: Program PLL CP/RES and lock parameters on reconfig
  clk: tegra: support 48MHz clock for pll_p_out1
  ...

* clk-microchip:
  clk: at91: Read "reg" with helper
This commit is contained in:
Stephen Boyd
2026-08-20 16:51:47 -07:00
148 changed files with 5271 additions and 830 deletions
+4
View File
@@ -4085,6 +4085,10 @@ S: 4226 Landgreen Street
S: Rockville, Maryland 20853
S: USA
N: Michael Turquette
E: mturquette@baylibre.com
D: common clk maintenance
N: Stephen Tweedie
E: sct@redhat.com
P: 1024/E7A417AD E2 FE A4 20 34 EC ED FC 7D 7E 67 8D E0 31 D1 69
@@ -0,0 +1,63 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/eswin,eic7700-hspcrg.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ESWIN EIC7700 HSP Clock and Reset Generator
maintainers:
- Xuyang Dong <dongxuyang@eswincomputing.com>
description:
Clock and reset generator for the ESWIN EIC7700 HSP (high-speed peripherals).
properties:
compatible:
const: eswin,eic7700-hspcrg
reg:
maxItems: 1
clocks:
items:
- description: HSP configuration top clock
- description: MMC top clock
- description: SATA top clock
clock-names:
items:
- const: cfg
- const: mmc
- const: sata
'#clock-cells':
const: 1
description:
See <dt-bindings/clock/eswin,eic7700-hspcrg.h> for valid indices.
'#reset-cells':
const: 1
description:
See <dt-bindings/reset/eswin,eic7700-hspcrg.h> for valid indices.
required:
- compatible
- reg
- clocks
- clock-names
- '#clock-cells'
- '#reset-cells'
additionalProperties: false
examples:
- |
clock-controller@50440000 {
compatible = "eswin,eic7700-hspcrg";
reg = <0x50440000 0x2000>;
clocks = <&clock 171>, <&clock 254>, <&clock 187>;
clock-names = "cfg", "mmc", "sata";
#clock-cells = <1>;
#reset-cells = <1>;
};
@@ -1,27 +0,0 @@
Binding for Keystone gate control driver which uses PSC controller IP.
This binding uses the common clock binding[1].
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
Required properties:
- compatible : shall be "ti,keystone,psc-clock".
- #clock-cells : from common clock binding; shall be set to 0.
- clocks : parent clock phandle
- reg : psc control and domain address address space
- reg-names : psc control and domain registers
- domain-id : psc domain id needed to check the transition state register
Optional properties:
- clock-output-names : From common clock binding to override the
default output clock name
Example:
clkusb: clkusb {
#clock-cells = <0>;
compatible = "ti,keystone,psc-clock";
clocks = <&chipclk16>;
clock-output-names = "usb";
reg = <0x02350008 0xb00>, <0x02350000 0x400>;
reg-names = "control", "domain";
domain-id = <0>;
};
@@ -0,0 +1,70 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/mediatek,mt8173-mfgtop.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek MT8173 MFG TOP controller
maintainers:
- AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
description:
The MFG TOP glue layer controls various signals going to the MFG (GPU)
block on the MT8173.
properties:
compatible:
const: mediatek,mt8173-mfgtop
reg:
maxItems: 1
clocks:
maxItems: 4
clock-names:
items:
- const: sys
- const: mem
- const: core
- const: clk26m
power-domains:
maxItems: 1
'#clock-cells':
const: 1
'#power-domain-cells':
const: 0
required:
- compatible
- reg
- clocks
- clock-names
- power-domains
- '#clock-cells'
- '#power-domain-cells'
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/mt8173-clk.h>
#include <dt-bindings/power/mt8173-power.h>
clock-controller@13fff000 {
compatible = "mediatek,mt8173-mfgtop";
reg = <0x13fff000 0x1000>;
clocks = <&topckgen CLK_TOP_AXI_MFG_IN_SEL>,
<&topckgen CLK_TOP_MEM_MFG_IN_SEL>,
<&topckgen CLK_TOP_MFG_SEL>,
<&clk26m>;
clock-names = "sys", "mem", "core", "clk26m";
power-domains = <&spm MT8173_POWER_DOMAIN_MFG>;
#clock-cells = <1>;
#power-domain-cells = <0>;
};
@@ -65,7 +65,7 @@ examples:
- |
pericfg@10003000 {
compatible = "mediatek,mt7623-pericfg", "mediatek,mt2701-pericfg", "syscon";
compatible = "mediatek,mt7623-pericfg", "mediatek,mt2701-pericfg", "syscon";
reg = <0x10003000 0x1000>;
#clock-cells = <1>;
#reset-cells = <1>;
@@ -4,7 +4,7 @@
$id: http://devicetree.org/schemas/clock/silabs,si544.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Silicon Labs SI514/SI544 clock generator
title: Silicon Labs SI514/SI544/SI549 clock generator
maintainers:
- Mike Looijmans <mike.looijmans@topic.nl>
@@ -13,8 +13,9 @@ description: >
Silicon Labs 514/544 programmable I2C clock generator. Details about the device
can be found in the datasheet:
https://www.silabs.com/Support%20Documents/TechnicalDocs/si514.pdf
https://www.silabs.com/documents/public/data-sheets/si544-datasheet.pdf
https://www.skyworksinc.com/-/media/Skyworks/SL/documents/public/data-sheets/Si514.pdf
https://www.skyworksinc.com/-/media/Skyworks/SL/documents/public/data-sheets/si544-datasheet.pdf
https://www.skyworksinc.com/-/media/Skyworks/SL/documents/public/data-sheets/si549-datasheet.pdf
properties:
compatible:
@@ -23,6 +24,9 @@ properties:
- silabs,si544a
- silabs,si544b
- silabs,si544c
- silabs,si549a
- silabs,si549b
- silabs,si549c
reg:
maxItems: 1
@@ -125,75 +125,75 @@ examples:
reg = <0x44200000 0x10000>;
#clock-cells = <1>;
#reset-cells = <1>;
clocks = <&scmi_clk CK_SCMI_HSE>,
<&scmi_clk CK_SCMI_HSI>,
<&scmi_clk CK_SCMI_MSI>,
<&scmi_clk CK_SCMI_LSE>,
<&scmi_clk CK_SCMI_LSI>,
<&scmi_clk CK_SCMI_HSE_DIV2>,
<&scmi_clk CK_SCMI_ICN_HS_MCU>,
<&scmi_clk CK_SCMI_ICN_LS_MCU>,
<&scmi_clk CK_SCMI_ICN_SDMMC>,
<&scmi_clk CK_SCMI_ICN_DDR>,
<&scmi_clk CK_SCMI_ICN_DISPLAY>,
<&scmi_clk CK_SCMI_ICN_HSL>,
<&scmi_clk CK_SCMI_ICN_NIC>,
<&scmi_clk CK_SCMI_FLEXGEN_07>,
<&scmi_clk CK_SCMI_FLEXGEN_08>,
<&scmi_clk CK_SCMI_FLEXGEN_09>,
<&scmi_clk CK_SCMI_FLEXGEN_10>,
<&scmi_clk CK_SCMI_FLEXGEN_11>,
<&scmi_clk CK_SCMI_FLEXGEN_12>,
<&scmi_clk CK_SCMI_FLEXGEN_13>,
<&scmi_clk CK_SCMI_FLEXGEN_14>,
<&scmi_clk CK_SCMI_FLEXGEN_16>,
<&scmi_clk CK_SCMI_FLEXGEN_17>,
<&scmi_clk CK_SCMI_FLEXGEN_18>,
<&scmi_clk CK_SCMI_FLEXGEN_19>,
<&scmi_clk CK_SCMI_FLEXGEN_20>,
<&scmi_clk CK_SCMI_FLEXGEN_21>,
<&scmi_clk CK_SCMI_FLEXGEN_22>,
<&scmi_clk CK_SCMI_FLEXGEN_23>,
<&scmi_clk CK_SCMI_FLEXGEN_24>,
<&scmi_clk CK_SCMI_FLEXGEN_25>,
<&scmi_clk CK_SCMI_FLEXGEN_26>,
<&scmi_clk CK_SCMI_FLEXGEN_27>,
<&scmi_clk CK_SCMI_FLEXGEN_29>,
<&scmi_clk CK_SCMI_FLEXGEN_30>,
<&scmi_clk CK_SCMI_FLEXGEN_31>,
<&scmi_clk CK_SCMI_FLEXGEN_33>,
<&scmi_clk CK_SCMI_FLEXGEN_36>,
<&scmi_clk CK_SCMI_FLEXGEN_37>,
<&scmi_clk CK_SCMI_FLEXGEN_38>,
<&scmi_clk CK_SCMI_FLEXGEN_39>,
<&scmi_clk CK_SCMI_FLEXGEN_40>,
<&scmi_clk CK_SCMI_FLEXGEN_41>,
<&scmi_clk CK_SCMI_FLEXGEN_42>,
<&scmi_clk CK_SCMI_FLEXGEN_43>,
<&scmi_clk CK_SCMI_FLEXGEN_44>,
<&scmi_clk CK_SCMI_FLEXGEN_45>,
<&scmi_clk CK_SCMI_FLEXGEN_46>,
<&scmi_clk CK_SCMI_FLEXGEN_47>,
<&scmi_clk CK_SCMI_FLEXGEN_48>,
<&scmi_clk CK_SCMI_FLEXGEN_50>,
<&scmi_clk CK_SCMI_FLEXGEN_51>,
<&scmi_clk CK_SCMI_FLEXGEN_52>,
<&scmi_clk CK_SCMI_FLEXGEN_53>,
<&scmi_clk CK_SCMI_FLEXGEN_54>,
<&scmi_clk CK_SCMI_FLEXGEN_55>,
<&scmi_clk CK_SCMI_FLEXGEN_56>,
<&scmi_clk CK_SCMI_FLEXGEN_57>,
<&scmi_clk CK_SCMI_FLEXGEN_58>,
<&scmi_clk CK_SCMI_FLEXGEN_61>,
<&scmi_clk CK_SCMI_FLEXGEN_62>,
<&scmi_clk CK_SCMI_FLEXGEN_63>,
<&scmi_clk CK_SCMI_ICN_APB1>,
<&scmi_clk CK_SCMI_ICN_APB2>,
<&scmi_clk CK_SCMI_ICN_APB3>,
<&scmi_clk CK_SCMI_ICN_APB4>,
<&scmi_clk CK_SCMI_ICN_APB5>,
<&scmi_clk CK_SCMI_ICN_APBDBG>,
<&scmi_clk CK_SCMI_TIMG1>,
<&scmi_clk CK_SCMI_TIMG2>;
clocks = <&scmi_clk CK_SCMI_HSE>,
<&scmi_clk CK_SCMI_HSI>,
<&scmi_clk CK_SCMI_MSI>,
<&scmi_clk CK_SCMI_LSE>,
<&scmi_clk CK_SCMI_LSI>,
<&scmi_clk CK_SCMI_HSE_DIV2>,
<&scmi_clk CK_SCMI_ICN_HS_MCU>,
<&scmi_clk CK_SCMI_ICN_LS_MCU>,
<&scmi_clk CK_SCMI_ICN_SDMMC>,
<&scmi_clk CK_SCMI_ICN_DDR>,
<&scmi_clk CK_SCMI_ICN_DISPLAY>,
<&scmi_clk CK_SCMI_ICN_HSL>,
<&scmi_clk CK_SCMI_ICN_NIC>,
<&scmi_clk CK_SCMI_FLEXGEN_07>,
<&scmi_clk CK_SCMI_FLEXGEN_08>,
<&scmi_clk CK_SCMI_FLEXGEN_09>,
<&scmi_clk CK_SCMI_FLEXGEN_10>,
<&scmi_clk CK_SCMI_FLEXGEN_11>,
<&scmi_clk CK_SCMI_FLEXGEN_12>,
<&scmi_clk CK_SCMI_FLEXGEN_13>,
<&scmi_clk CK_SCMI_FLEXGEN_14>,
<&scmi_clk CK_SCMI_FLEXGEN_16>,
<&scmi_clk CK_SCMI_FLEXGEN_17>,
<&scmi_clk CK_SCMI_FLEXGEN_18>,
<&scmi_clk CK_SCMI_FLEXGEN_19>,
<&scmi_clk CK_SCMI_FLEXGEN_20>,
<&scmi_clk CK_SCMI_FLEXGEN_21>,
<&scmi_clk CK_SCMI_FLEXGEN_22>,
<&scmi_clk CK_SCMI_FLEXGEN_23>,
<&scmi_clk CK_SCMI_FLEXGEN_24>,
<&scmi_clk CK_SCMI_FLEXGEN_25>,
<&scmi_clk CK_SCMI_FLEXGEN_26>,
<&scmi_clk CK_SCMI_FLEXGEN_27>,
<&scmi_clk CK_SCMI_FLEXGEN_29>,
<&scmi_clk CK_SCMI_FLEXGEN_30>,
<&scmi_clk CK_SCMI_FLEXGEN_31>,
<&scmi_clk CK_SCMI_FLEXGEN_33>,
<&scmi_clk CK_SCMI_FLEXGEN_36>,
<&scmi_clk CK_SCMI_FLEXGEN_37>,
<&scmi_clk CK_SCMI_FLEXGEN_38>,
<&scmi_clk CK_SCMI_FLEXGEN_39>,
<&scmi_clk CK_SCMI_FLEXGEN_40>,
<&scmi_clk CK_SCMI_FLEXGEN_41>,
<&scmi_clk CK_SCMI_FLEXGEN_42>,
<&scmi_clk CK_SCMI_FLEXGEN_43>,
<&scmi_clk CK_SCMI_FLEXGEN_44>,
<&scmi_clk CK_SCMI_FLEXGEN_45>,
<&scmi_clk CK_SCMI_FLEXGEN_46>,
<&scmi_clk CK_SCMI_FLEXGEN_47>,
<&scmi_clk CK_SCMI_FLEXGEN_48>,
<&scmi_clk CK_SCMI_FLEXGEN_50>,
<&scmi_clk CK_SCMI_FLEXGEN_51>,
<&scmi_clk CK_SCMI_FLEXGEN_52>,
<&scmi_clk CK_SCMI_FLEXGEN_53>,
<&scmi_clk CK_SCMI_FLEXGEN_54>,
<&scmi_clk CK_SCMI_FLEXGEN_55>,
<&scmi_clk CK_SCMI_FLEXGEN_56>,
<&scmi_clk CK_SCMI_FLEXGEN_57>,
<&scmi_clk CK_SCMI_FLEXGEN_58>,
<&scmi_clk CK_SCMI_FLEXGEN_61>,
<&scmi_clk CK_SCMI_FLEXGEN_62>,
<&scmi_clk CK_SCMI_FLEXGEN_63>,
<&scmi_clk CK_SCMI_ICN_APB1>,
<&scmi_clk CK_SCMI_ICN_APB2>,
<&scmi_clk CK_SCMI_ICN_APB3>,
<&scmi_clk CK_SCMI_ICN_APB4>,
<&scmi_clk CK_SCMI_ICN_APB5>,
<&scmi_clk CK_SCMI_ICN_APBDBG>,
<&scmi_clk CK_SCMI_TIMG1>,
<&scmi_clk CK_SCMI_TIMG2>;
};
...
@@ -135,85 +135,85 @@ examples:
reg = <0x44200000 0x10000>;
#clock-cells = <1>;
#reset-cells = <1>;
clocks = <&scmi_clk CK_SCMI_HSE>,
<&scmi_clk CK_SCMI_HSI>,
<&scmi_clk CK_SCMI_MSI>,
<&scmi_clk CK_SCMI_LSE>,
<&scmi_clk CK_SCMI_LSI>,
<&scmi_clk CK_SCMI_HSE_DIV2>,
<&scmi_clk CK_SCMI_ICN_HS_MCU>,
<&scmi_clk CK_SCMI_ICN_LS_MCU>,
<&scmi_clk CK_SCMI_ICN_SDMMC>,
<&scmi_clk CK_SCMI_ICN_DDR>,
<&scmi_clk CK_SCMI_ICN_DISPLAY>,
<&scmi_clk CK_SCMI_ICN_HSL>,
<&scmi_clk CK_SCMI_ICN_NIC>,
<&scmi_clk CK_SCMI_ICN_VID>,
<&scmi_clk CK_SCMI_FLEXGEN_07>,
<&scmi_clk CK_SCMI_FLEXGEN_08>,
<&scmi_clk CK_SCMI_FLEXGEN_09>,
<&scmi_clk CK_SCMI_FLEXGEN_10>,
<&scmi_clk CK_SCMI_FLEXGEN_11>,
<&scmi_clk CK_SCMI_FLEXGEN_12>,
<&scmi_clk CK_SCMI_FLEXGEN_13>,
<&scmi_clk CK_SCMI_FLEXGEN_14>,
<&scmi_clk CK_SCMI_FLEXGEN_15>,
<&scmi_clk CK_SCMI_FLEXGEN_16>,
<&scmi_clk CK_SCMI_FLEXGEN_17>,
<&scmi_clk CK_SCMI_FLEXGEN_18>,
<&scmi_clk CK_SCMI_FLEXGEN_19>,
<&scmi_clk CK_SCMI_FLEXGEN_20>,
<&scmi_clk CK_SCMI_FLEXGEN_21>,
<&scmi_clk CK_SCMI_FLEXGEN_22>,
<&scmi_clk CK_SCMI_FLEXGEN_23>,
<&scmi_clk CK_SCMI_FLEXGEN_24>,
<&scmi_clk CK_SCMI_FLEXGEN_25>,
<&scmi_clk CK_SCMI_FLEXGEN_26>,
<&scmi_clk CK_SCMI_FLEXGEN_27>,
<&scmi_clk CK_SCMI_FLEXGEN_28>,
<&scmi_clk CK_SCMI_FLEXGEN_29>,
<&scmi_clk CK_SCMI_FLEXGEN_30>,
<&scmi_clk CK_SCMI_FLEXGEN_31>,
<&scmi_clk CK_SCMI_FLEXGEN_32>,
<&scmi_clk CK_SCMI_FLEXGEN_33>,
<&scmi_clk CK_SCMI_FLEXGEN_34>,
<&scmi_clk CK_SCMI_FLEXGEN_35>,
<&scmi_clk CK_SCMI_FLEXGEN_36>,
<&scmi_clk CK_SCMI_FLEXGEN_37>,
<&scmi_clk CK_SCMI_FLEXGEN_38>,
<&scmi_clk CK_SCMI_FLEXGEN_39>,
<&scmi_clk CK_SCMI_FLEXGEN_40>,
<&scmi_clk CK_SCMI_FLEXGEN_41>,
<&scmi_clk CK_SCMI_FLEXGEN_42>,
<&scmi_clk CK_SCMI_FLEXGEN_43>,
<&scmi_clk CK_SCMI_FLEXGEN_44>,
<&scmi_clk CK_SCMI_FLEXGEN_45>,
<&scmi_clk CK_SCMI_FLEXGEN_46>,
<&scmi_clk CK_SCMI_FLEXGEN_47>,
<&scmi_clk CK_SCMI_FLEXGEN_48>,
<&scmi_clk CK_SCMI_FLEXGEN_49>,
<&scmi_clk CK_SCMI_FLEXGEN_50>,
<&scmi_clk CK_SCMI_FLEXGEN_51>,
<&scmi_clk CK_SCMI_FLEXGEN_52>,
<&scmi_clk CK_SCMI_FLEXGEN_53>,
<&scmi_clk CK_SCMI_FLEXGEN_54>,
<&scmi_clk CK_SCMI_FLEXGEN_55>,
<&scmi_clk CK_SCMI_FLEXGEN_56>,
<&scmi_clk CK_SCMI_FLEXGEN_57>,
<&scmi_clk CK_SCMI_FLEXGEN_58>,
<&scmi_clk CK_SCMI_FLEXGEN_59>,
<&scmi_clk CK_SCMI_FLEXGEN_60>,
<&scmi_clk CK_SCMI_FLEXGEN_61>,
<&scmi_clk CK_SCMI_FLEXGEN_62>,
<&scmi_clk CK_SCMI_FLEXGEN_63>,
<&scmi_clk CK_SCMI_ICN_APB1>,
<&scmi_clk CK_SCMI_ICN_APB2>,
<&scmi_clk CK_SCMI_ICN_APB3>,
<&scmi_clk CK_SCMI_ICN_APB4>,
<&scmi_clk CK_SCMI_ICN_APBDBG>,
<&scmi_clk CK_SCMI_TIMG1>,
<&scmi_clk CK_SCMI_TIMG2>,
<&scmi_clk CK_SCMI_PLL3>,
<&clk_dsi_txbyte>;
clocks = <&scmi_clk CK_SCMI_HSE>,
<&scmi_clk CK_SCMI_HSI>,
<&scmi_clk CK_SCMI_MSI>,
<&scmi_clk CK_SCMI_LSE>,
<&scmi_clk CK_SCMI_LSI>,
<&scmi_clk CK_SCMI_HSE_DIV2>,
<&scmi_clk CK_SCMI_ICN_HS_MCU>,
<&scmi_clk CK_SCMI_ICN_LS_MCU>,
<&scmi_clk CK_SCMI_ICN_SDMMC>,
<&scmi_clk CK_SCMI_ICN_DDR>,
<&scmi_clk CK_SCMI_ICN_DISPLAY>,
<&scmi_clk CK_SCMI_ICN_HSL>,
<&scmi_clk CK_SCMI_ICN_NIC>,
<&scmi_clk CK_SCMI_ICN_VID>,
<&scmi_clk CK_SCMI_FLEXGEN_07>,
<&scmi_clk CK_SCMI_FLEXGEN_08>,
<&scmi_clk CK_SCMI_FLEXGEN_09>,
<&scmi_clk CK_SCMI_FLEXGEN_10>,
<&scmi_clk CK_SCMI_FLEXGEN_11>,
<&scmi_clk CK_SCMI_FLEXGEN_12>,
<&scmi_clk CK_SCMI_FLEXGEN_13>,
<&scmi_clk CK_SCMI_FLEXGEN_14>,
<&scmi_clk CK_SCMI_FLEXGEN_15>,
<&scmi_clk CK_SCMI_FLEXGEN_16>,
<&scmi_clk CK_SCMI_FLEXGEN_17>,
<&scmi_clk CK_SCMI_FLEXGEN_18>,
<&scmi_clk CK_SCMI_FLEXGEN_19>,
<&scmi_clk CK_SCMI_FLEXGEN_20>,
<&scmi_clk CK_SCMI_FLEXGEN_21>,
<&scmi_clk CK_SCMI_FLEXGEN_22>,
<&scmi_clk CK_SCMI_FLEXGEN_23>,
<&scmi_clk CK_SCMI_FLEXGEN_24>,
<&scmi_clk CK_SCMI_FLEXGEN_25>,
<&scmi_clk CK_SCMI_FLEXGEN_26>,
<&scmi_clk CK_SCMI_FLEXGEN_27>,
<&scmi_clk CK_SCMI_FLEXGEN_28>,
<&scmi_clk CK_SCMI_FLEXGEN_29>,
<&scmi_clk CK_SCMI_FLEXGEN_30>,
<&scmi_clk CK_SCMI_FLEXGEN_31>,
<&scmi_clk CK_SCMI_FLEXGEN_32>,
<&scmi_clk CK_SCMI_FLEXGEN_33>,
<&scmi_clk CK_SCMI_FLEXGEN_34>,
<&scmi_clk CK_SCMI_FLEXGEN_35>,
<&scmi_clk CK_SCMI_FLEXGEN_36>,
<&scmi_clk CK_SCMI_FLEXGEN_37>,
<&scmi_clk CK_SCMI_FLEXGEN_38>,
<&scmi_clk CK_SCMI_FLEXGEN_39>,
<&scmi_clk CK_SCMI_FLEXGEN_40>,
<&scmi_clk CK_SCMI_FLEXGEN_41>,
<&scmi_clk CK_SCMI_FLEXGEN_42>,
<&scmi_clk CK_SCMI_FLEXGEN_43>,
<&scmi_clk CK_SCMI_FLEXGEN_44>,
<&scmi_clk CK_SCMI_FLEXGEN_45>,
<&scmi_clk CK_SCMI_FLEXGEN_46>,
<&scmi_clk CK_SCMI_FLEXGEN_47>,
<&scmi_clk CK_SCMI_FLEXGEN_48>,
<&scmi_clk CK_SCMI_FLEXGEN_49>,
<&scmi_clk CK_SCMI_FLEXGEN_50>,
<&scmi_clk CK_SCMI_FLEXGEN_51>,
<&scmi_clk CK_SCMI_FLEXGEN_52>,
<&scmi_clk CK_SCMI_FLEXGEN_53>,
<&scmi_clk CK_SCMI_FLEXGEN_54>,
<&scmi_clk CK_SCMI_FLEXGEN_55>,
<&scmi_clk CK_SCMI_FLEXGEN_56>,
<&scmi_clk CK_SCMI_FLEXGEN_57>,
<&scmi_clk CK_SCMI_FLEXGEN_58>,
<&scmi_clk CK_SCMI_FLEXGEN_59>,
<&scmi_clk CK_SCMI_FLEXGEN_60>,
<&scmi_clk CK_SCMI_FLEXGEN_61>,
<&scmi_clk CK_SCMI_FLEXGEN_62>,
<&scmi_clk CK_SCMI_FLEXGEN_63>,
<&scmi_clk CK_SCMI_ICN_APB1>,
<&scmi_clk CK_SCMI_ICN_APB2>,
<&scmi_clk CK_SCMI_ICN_APB3>,
<&scmi_clk CK_SCMI_ICN_APB4>,
<&scmi_clk CK_SCMI_ICN_APBDBG>,
<&scmi_clk CK_SCMI_TIMG1>,
<&scmi_clk CK_SCMI_TIMG2>,
<&scmi_clk CK_SCMI_PLL3>,
<&clk_dsi_txbyte>;
};
...
@@ -0,0 +1,60 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/ti,keystone,psc-clock.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: TI Keystone PSC clock
maintainers:
- Santosh Shilimkar <santosh.shilimkar@ti.com>
- Murali Karicheri <m-karicheri2@ti.com>
properties:
compatible:
const: ti,keystone,psc-clock
reg:
items:
- description: PSC control
- description: Domain
reg-names:
items:
- const: control
- const: domain
domain-id:
$ref: /schemas/types.yaml#/definitions/uint32
description: PSC domain id needed to check the transition state register
clocks:
maxItems: 1
clock-output-names:
maxItems: 1
"#clock-cells":
const: 0
required:
- compatible
- reg
- reg-names
- domain-id
- clocks
- "#clock-cells"
additionalProperties: false
examples:
- |
clkusb@2350008 {
compatible = "ti,keystone,psc-clock";
reg = <0x02350008 0xb00>, <0x02350000 0x400>;
reg-names = "control", "domain";
domain-id = <0>;
clocks = <&chipclk16>;
clock-output-names = "usb";
#clock-cells = <0>;
};
@@ -1,43 +0,0 @@
Binding for Texas Instruments APLL clock.
This binding uses the common clock binding[1]. It assumes a
register-mapped APLL with usually two selectable input clocks
(reference clock and bypass clock), with analog phase locked
loop logic for multiplying the input clock to a desired output
clock. This clock also typically supports different operation
modes (locked, low power stop etc.) APLL mostly behaves like
a subtype of a DPLL [2], although a simplified one at that.
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
[2] Documentation/devicetree/bindings/clock/ti/dpll.txt
Required properties:
- compatible : shall be "ti,dra7-apll-clock" or "ti,omap2-apll-clock"
- #clock-cells : from common clock binding; shall be set to 0.
- clocks : link phandles of parent clocks (clk-ref and clk-bypass)
- reg : address and length of the register set for controlling the APLL.
It contains the information of registers in the following order:
"control" - contains the control register offset
"idlest" - contains the idlest register offset
"autoidle" - contains the autoidle register offset (OMAP2 only)
- ti,clock-frequency : static clock frequency for the clock (OMAP2 only)
- ti,idlest-shift : bit-shift for the idlest field (OMAP2 only)
- ti,bit-shift : bit-shift for enable and autoidle fields (OMAP2 only)
Examples:
apll_pcie_ck: apll_pcie_ck {
#clock-cells = <0>;
clocks = <&apll_pcie_in_clk_mux>, <&dpll_pcie_ref_ck>;
reg = <0x021c>, <0x0220>;
compatible = "ti,dra7-apll-clock";
};
apll96_ck: apll96_ck {
#clock-cells = <0>;
compatible = "ti,omap2-apll-clock";
clocks = <&sys_ck>;
ti,bit-shift = <2>;
ti,idlest-shift = <8>;
ti,clock-frequency = <96000000>;
reg = <0x0500>, <0x0530>, <0x0520>;
};
@@ -1,25 +0,0 @@
Binding for Texas Instruments clockdomain.
This binding uses the common clock binding[1] in consumer role.
Every clock on TI SoC belongs to one clockdomain, but software
only needs this information for specific clocks which require
their parent clockdomain to be controlled when the clock is
enabled/disabled. This binding doesn't define a new clock
binding type, it is used to group existing clock nodes under
hardware hierarchy.
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
Required properties:
- compatible : shall be "ti,clockdomain"
- #clock-cells : from common clock binding; shall be set to 0.
- clocks : link phandles of clocks within this domain
Optional properties:
- clock-output-names : from common clock binding.
Examples:
dss_clkdm: dss_clkdm {
compatible = "ti,clockdomain";
clocks = <&dss1_alwon_fck_3430es2>, <&dss_ick_3430es2>;
};
@@ -0,0 +1,89 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/ti/ti,apll-clock.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments APLL clock
maintainers:
- Eduard Bostina <egbostina@gmail.com>
allOf:
- $ref: /schemas/clock/clock.yaml#
description:
This binding assumes a register-mapped APLL with usually two selectable
input clocks (reference clock and bypass clock), with analog phase locked
loop logic for multiplying the input clock to a desired output clock.
This clock also typically supports different operation modes (locked, low
power stop etc.) APLL mostly behaves like a subtype of a DPLL, although
a simplified one at that.
properties:
compatible:
enum:
- ti,dra7-apll-clock
- ti,omap2-apll-clock
"#clock-cells":
const: 0
clocks:
minItems: 1
maxItems: 2
description: Link phandles of parent clocks (clk-ref and clk-bypass)
reg:
minItems: 2
maxItems: 3
description: |
Address and length of the register set for controlling the APLL.
It contains the information of registers in the following order:
"control" - contains the control register offset
"idlest" - contains the idlest register offset
"autoidle" - contains the autoidle register offset (OMAP2 only)
ti,clock-frequency:
$ref: /schemas/types.yaml#/definitions/uint32
description: static clock frequency for the clock (OMAP2 only)
ti,idlest-shift:
$ref: /schemas/types.yaml#/definitions/uint32
description: bit-shift for the idlest field (OMAP2 only)
ti,bit-shift:
$ref: /schemas/types.yaml#/definitions/uint32
description: bit-shift for enable and autoidle fields (OMAP2 only)
required:
- compatible
- "#clock-cells"
- clocks
- reg
unevaluatedProperties: false
examples:
- |
bus {
#address-cells = <1>;
#size-cells = <0>;
clock@21c {
#clock-cells = <0>;
compatible = "ti,dra7-apll-clock";
clocks = <&apll_pcie_in_clk_mux>, <&dpll_pcie_ref_ck>;
reg = <0x021c>, <0x0220>;
};
clock@500 {
#clock-cells = <0>;
compatible = "ti,omap2-apll-clock";
clocks = <&sys_ck>;
ti,bit-shift = <2>;
ti,idlest-shift = <8>;
ti,clock-frequency = <96000000>;
reg = <0x0500>, <0x0530>, <0x0520>;
};
};
@@ -0,0 +1,44 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/ti/ti,clockdomain.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments clockdomain
maintainers:
- Tero Kristo <kristo@kernel.org>
description:
This binding uses the common clock binding in consumer role. Every clock on TI
SoC belongs to one clockdomain, but software only needs this information for
specific clocks which require their parent clockdomain to be controlled when
the clock is enabled/disabled. This binding doesn't define a new clock binding
type, it is used to group existing clock nodes under hardware hierarchy.
properties:
compatible:
const: ti,clockdomain
"#clock-cells":
const: 0
clocks:
minItems: 1
maxItems: 64
clock-output-names:
maxItems: 1
required:
- compatible
- clocks
additionalProperties: false
examples:
- |
dss_clkdm {
compatible = "ti,clockdomain";
clocks = <&dss1_alwon_fck_3430es2>, <&dss_ick_3430es2>;
};
@@ -19,7 +19,7 @@ description: |
that is used.
[1] Documentation/devicetree/bindings/clock/gpio-gate-clock.yaml
[2] Documentation/devicetree/bindings/clock/ti/clockdomain.txt
[2] Documentation/devicetree/bindings/clock/ti/ti,clockdomain.yaml
properties:
compatible:
@@ -0,0 +1,60 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/ultrarisc,dp1000-clk.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: UltraRISC DP1000 Clock Controller
maintainers:
- Jia Wang <wangjia@ultrarisc.com>
description: |
The UltraRISC DP1000 clock controller is driven from a single external
oscillator input. It provides a system PLL with fractional multiplier
and post-divider stages, several fixed-ratio derived clocks for
the on-chip subsystem, Clock Configuration Register (CCR) divider
outputs for GMAC and the UART, I2C, and SPI root clocks, and
per-instance gate clocks for UART0-3, I2C0-3, and SPI0-1.
All available clocks are defined as preprocessor macros in
include/dt-bindings/clock/ultrarisc,dp1000-clk.h
properties:
compatible:
const: ultrarisc,dp1000-clk
reg:
maxItems: 1
clocks:
maxItems: 1
description:
External oscillator input clock used as the parent of the PLLs.
"#clock-cells":
const: 1
required:
- compatible
- reg
- clocks
- "#clock-cells"
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/ultrarisc,dp1000-clk.h>
soc {
#address-cells = <2>;
#size-cells = <2>;
clock-controller@11080000 {
compatible = "ultrarisc,dp1000-clk";
reg = <0x0 0x11080000 0x0 0x1000>;
clocks = <&osc>;
#clock-cells = <1>;
};
};
@@ -70,7 +70,7 @@ additionalProperties: false
examples:
- |
clock-controller@b0000000 {
clock-controller@b0000000 {
compatible = "xlnx,clocking-wizard";
reg = <0xb0000000 0x10000>;
#clock-cells = <1>;
@@ -75,7 +75,7 @@ SoCs only:
- clocks: Should contain the device's input clock, and should be
defined as per the bindings in,
Documentation/devicetree/bindings/clock/keystone-gate.txt
Documentation/devicetree/bindings/clock/ti,keystone,psc-clock.yaml
The following are mandatory properties for Keystone 2 66AK2G SoCs only:
@@ -0,0 +1,92 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/soc/cix/cix,sky1-audss-cru.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Cix Sky1 audio subsystem clock and reset unit
maintainers:
- Joakim Zhang <joakim.zhang@cixtech.com>
description: |
The Cix Sky1 Audio Subsystem (AUDSS) Clock and Reset Unit (CRU) groups
audio-related clock muxing, gating and block-level software reset control
in a single register block.
A single device node exposes both the clock controller and software reset
lines. The clock driver registers as a platform driver; the reset controller
is registered by an auxiliary driver bound from the clock driver.
Four SoC-level reference clocks listed in clocks/clock-names feed the AUDSS
clock tree. Internal AUDSS clocks are exposed via #clock-cells; indices are
defined in include/dt-bindings/clock/cix,sky1-audss-cru.h.
Block-level software reset indices are exposed via #reset-cells; indices
are defined in include/dt-bindings/reset/cix,sky1-audss-cru.h.
The SoC syscon NoC (or bus) reset is described via resets. The audio
subsystem power domain is described via power-domains.
properties:
compatible:
const: cix,sky1-audss-cru
reg:
maxItems: 1
'#clock-cells':
const: 1
description:
Clock indices are defined in include/dt-bindings/clock/cix,sky1-audss-cru.h.
'#reset-cells':
const: 1
description:
Reset indices are defined in include/dt-bindings/reset/cix,sky1-audss-cru.h.
clocks:
items:
- description: I2S parent clock for sampling rates multiple of 8kHz.
- description: I2S parent clock for sampling rates multiple of 11.025kHz.
- description: Clock feeding most devices in AUDSS (NOC, DSP, SRAM, HDA, DMAC, I2S, and mailbox).
- description: Clock feeding HDA, timer and watchdog, which is a dedicated 48 MHz clock.
clock-names:
items:
- const: x8k
- const: x11k
- const: sys
- const: 48m
power-domains:
maxItems: 1
resets:
maxItems: 1
required:
- compatible
- reg
- '#clock-cells'
- '#reset-cells'
- clocks
- clock-names
- power-domains
- resets
additionalProperties: false
examples:
- |
audss_cru: clock-controller@7110000 {
compatible = "cix,sky1-audss-cru";
reg = <0x7110000 0x10000>;
#clock-cells = <1>;
#reset-cells = <1>;
clocks = <&scmi_clk 76>, <&scmi_clk 78>,
<&scmi_clk 70>, <&scmi_clk 71>;
clock-names = "x8k", "x11k", "sys", "48m";
power-domains = <&smc_devpd 0>;
resets = <&s5_syscon 31>;
};
+12 -46
View File
@@ -42,21 +42,8 @@ clock interface.
Common data structures and api
==============================
Below is the common struct clk_core definition from
drivers/clk/clk.c, modified for brevity::
struct clk_core {
const char *name;
const struct clk_ops *ops;
struct clk_hw *hw;
struct module *owner;
struct clk_core *parent;
const char **parent_names;
struct clk_core **parents;
u8 num_parents;
u8 new_parent_index;
...
};
.. kernel-doc:: drivers/clk/clk.c
:identifiers: struct clk_core
The members above make up the core of the clk tree topology. The clk
api itself defines several driver-facing functions which operate on
@@ -64,38 +51,17 @@ struct clk. That api is documented in include/linux/clk.h.
Platforms and devices utilizing the common struct clk_core use the struct
clk_ops pointer in struct clk_core to perform the hardware-specific parts of
the operations defined in clk-provider.h::
the operations defined in clk-provider.h, and can set one or more
framework-level flags documented below.
struct clk_ops {
int (*prepare)(struct clk_hw *hw);
void (*unprepare)(struct clk_hw *hw);
int (*is_prepared)(struct clk_hw *hw);
void (*unprepare_unused)(struct clk_hw *hw);
int (*enable)(struct clk_hw *hw);
void (*disable)(struct clk_hw *hw);
int (*is_enabled)(struct clk_hw *hw);
void (*disable_unused)(struct clk_hw *hw);
unsigned long (*recalc_rate)(struct clk_hw *hw,
unsigned long parent_rate);
int (*determine_rate)(struct clk_hw *hw,
struct clk_rate_request *req);
int (*set_parent)(struct clk_hw *hw, u8 index);
u8 (*get_parent)(struct clk_hw *hw);
int (*set_rate)(struct clk_hw *hw,
unsigned long rate,
unsigned long parent_rate);
int (*set_rate_and_parent)(struct clk_hw *hw,
unsigned long rate,
unsigned long parent_rate,
u8 index);
unsigned long (*recalc_accuracy)(struct clk_hw *hw,
unsigned long parent_accuracy);
int (*get_phase)(struct clk_hw *hw);
int (*set_phase)(struct clk_hw *hw, int degrees);
void (*init)(struct clk_hw *hw);
void (*debug_init)(struct clk_hw *hw,
struct dentry *dentry);
};
.. kernel-doc:: include/linux/clk-provider.h
:identifiers: struct clk_ops
Core flags
==========
.. kernel-doc:: include/linux/clk-provider.h
:doc: clk framework flags
Hardware clk implementations
============================
@@ -248,6 +248,7 @@ CLOCK
devm_clk_put()
devm_clk_bulk_get()
devm_clk_bulk_get_all()
devm_clk_bulk_get_enable()
devm_clk_bulk_get_optional()
devm_get_clk_from_child()
devm_clk_hw_register()
+13 -4
View File
@@ -6447,9 +6447,9 @@ F: include/linux/comedi/
F: include/uapi/linux/comedi.h
COMMON CLK FRAMEWORK
M: Michael Turquette <mturquette@baylibre.com>
M: Stephen Boyd <sboyd@kernel.org>
R: Brian Masney <bmasney@redhat.com>
M: Brian Masney <bmasney+clk@redhat.com>
M: Jerome Brunet <jbrunet+clk@baylibre.com>
L: linux-clk@vger.kernel.org
S: Maintained
Q: http://patchwork.kernel.org/project/linux-clk/list/
@@ -9660,9 +9660,10 @@ ESWIN EIC7700 CLOCK DRIVER
M: Yifeng Huang <huangyifeng@eswincomputing.com>
M: Xuyang Dong <dongxuyang@eswincomputing.com>
S: Maintained
F: Documentation/devicetree/bindings/clock/eswin,eic7700-clock.yaml
F: Documentation/devicetree/bindings/clock/eswin,eic7700*
F: drivers/clk/eswin/
F: include/dt-bindings/clock/eswin,eic7700-clock.h
F: include/dt-bindings/clock/eswin,eic7700*
F: include/dt-bindings/reset/eswin,eic7700-hspcrg.h
ET131X NETWORK DRIVER
M: Mark Einon <mark.einon@gmail.com>
@@ -27672,6 +27673,14 @@ S: Maintained
F: drivers/usb/common/ulpi.c
F: include/linux/ulpi/
ULTRARISC DP1000 CLOCK DRIVER
M: Jia Wang <wangjia@ultrarisc.com>
L: linux-clk@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/clock/ultrarisc,dp1000-clk.yaml
F: drivers/clk/ultrarisc/*
F: include/dt-bindings/clock/ultrarisc,dp1000-clk.h
ULTRARISC DP1000 PINCTRL DRIVER
M: Jia Wang <wangjia@ultrarisc.com>
L: linux-gpio@vger.kernel.org
+18
View File
@@ -6,6 +6,10 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/cix,sky1.h>
#include <dt-bindings/clock/cix,sky1-audss-cru.h>
#include <dt-bindings/reset/cix,sky1-system-control.h>
#include <dt-bindings/reset/cix,sky1-s5-system-control.h>
#include <dt-bindings/reset/cix,sky1-audss-cru.h>
#include "sky1-power.h"
/ {
@@ -558,6 +562,20 @@
cix,mbox-dir = "rx";
};
audss_cru: clock-controller@7110000 {
compatible = "cix,sky1-audss-cru";
reg = <0x0 0x07110000 0x0 0x10000>;
#clock-cells = <1>;
#reset-cells = <1>;
clocks = <&scmi_clk CLK_TREE_AUDIO_CLK0>,
<&scmi_clk CLK_TREE_AUDIO_CLK2>,
<&scmi_clk CLK_TREE_AUDIO_CLK4>,
<&scmi_clk CLK_TREE_AUDIO_CLK5>;
clock-names = "x8k", "x11k", "sys", "48m";
power-domains = <&smc_devpd SKY1_PD_AUDIO>;
resets = <&s5_syscon SKY1_AUDIO_HIFI5_NOC_RESET_N>;
};
mbox_sfh2ap: mailbox@8090000 {
compatible = "cix,sky1-mbox";
reg = <0x0 0x08090000 0x0 0x10000>;
+1
View File
@@ -4,6 +4,7 @@ CONFIG_OF=y
CONFIG_OF_OVERLAY=y
CONFIG_COMMON_CLK=y
CONFIG_CLK_KUNIT_TEST=y
CONFIG_CLK_DIVIDER_KUNIT_TEST=y
CONFIG_CLK_FIXED_RATE_KUNIT_TEST=y
CONFIG_CLK_GATE_KUNIT_TEST=y
CONFIG_CLK_FD_KUNIT_TEST=y
+14 -4
View File
@@ -155,12 +155,12 @@ config COMMON_CLK_SI514
generator.
config COMMON_CLK_SI544
tristate "Clock driver for SiLabs 544 devices"
tristate "Clock driver for SiLabs 544 and compatible devices"
depends on I2C
select REGMAP_I2C
help
This driver supports the Silicon Labs 544 programmable clock
generator.
This driver supports the Silicon Labs 544/549 programmable clock
generators.
config COMMON_CLK_SI570
tristate "Clock driver for SiLabs 570 and compatible devices"
@@ -278,7 +278,7 @@ config COMMON_CLK_LAN966X
tristate "Generic Clock Controller driver for LAN966X SoC"
depends on HAS_IOMEM
depends on OF
depends on SOC_LAN966 || ARCH_LAN969X || COMPILE_TEST
depends on SOC_LAN966 || ARCH_LAN969X || MCHP_LAN966X_PCI || COMPILE_TEST
help
This driver provides support for Generic Clock Controller(GCK) on
LAN966X SoC. GCK generates and supplies clock to various peripherals
@@ -509,6 +509,7 @@ source "drivers/clk/actions/Kconfig"
source "drivers/clk/analogbits/Kconfig"
source "drivers/clk/aspeed/Kconfig"
source "drivers/clk/bcm/Kconfig"
source "drivers/clk/cix/Kconfig"
source "drivers/clk/eswin/Kconfig"
source "drivers/clk/hisilicon/Kconfig"
source "drivers/clk/imgtec/Kconfig"
@@ -541,6 +542,7 @@ source "drivers/clk/tenstorrent/Kconfig"
source "drivers/clk/thead/Kconfig"
source "drivers/clk/stm32/Kconfig"
source "drivers/clk/ti/Kconfig"
source "drivers/clk/ultrarisc/Kconfig"
source "drivers/clk/uniphier/Kconfig"
source "drivers/clk/visconti/Kconfig"
source "drivers/clk/x86/Kconfig"
@@ -579,4 +581,12 @@ config CLK_FD_KUNIT_TEST
help
Kunit test for the clk-fractional-divider type.
config CLK_DIVIDER_KUNIT_TEST
tristate "KUnit tests for clk divider bestdiv" if !KUNIT_ALL_TESTS
depends on KUNIT
depends on !S390
default KUNIT_ALL_TESTS
help
Kunit test for the clk-divider type.
endif
+17 -3
View File
@@ -18,9 +18,20 @@ clk-test-y := clk_test.o \
kunit_clk_assigned_rates_without_consumer.dtbo.o \
kunit_clk_assigned_rates_zero.dtbo.o \
kunit_clk_assigned_rates_zero_consumer.dtbo.o \
kunit_clk_assigned_sscs_one.dtbo.o \
kunit_clk_assigned_sscs_one_consumer.dtbo.o \
kunit_clk_assigned_sscs_multiple.dtbo.o \
kunit_clk_assigned_sscs_multiple_consumer.dtbo.o \
kunit_clk_assigned_sscs_null.dtbo.o \
kunit_clk_assigned_sscs_null_consumer.dtbo.o \
kunit_clk_assigned_sscs_without.dtbo.o \
kunit_clk_assigned_sscs_without_consumer.dtbo.o \
kunit_clk_assigned_sscs_zero.dtbo.o \
kunit_clk_assigned_sscs_zero_consumer.dtbo.o \
kunit_clk_hw_get_dev_of_node.dtbo.o \
kunit_clk_parent_data_test.dtbo.o
obj-$(CONFIG_COMMON_CLK) += clk-divider.o
obj-$(CONFIG_CLK_DIVIDER_KUNIT_TEST) += clk-divider_test.o
obj-$(CONFIG_COMMON_CLK) += clk-fixed-factor.o
obj-$(CONFIG_COMMON_CLK) += clk-fixed-rate.o
obj-$(CONFIG_CLK_FIXED_RATE_KUNIT_TEST) += clk-fixed-rate-test.o
@@ -88,7 +99,8 @@ obj-$(CONFIG_COMMON_CLK_RP1) += clk-rp1.o
obj-$(CONFIG_COMMON_CLK_RPMI) += clk-rpmi.o
obj-$(CONFIG_COMMON_CLK_HI655X) += clk-hi655x.o
obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o
obj-$(CONFIG_COMMON_CLK_SCMI) += clk-scmi.o
scmi-clk-y := clk-scmi.o clk-scmi-oem.o
obj-$(CONFIG_COMMON_CLK_SCMI) += scmi-clk.o
obj-$(CONFIG_COMMON_CLK_SCPI) += clk-scpi.o
obj-$(CONFIG_COMMON_CLK_SI5341) += clk-si5341.o
obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o
@@ -119,9 +131,10 @@ obj-$(CONFIG_ARCH_ARTPEC) += axis/
obj-$(CONFIG_ARC_PLAT_AXS10X) += axs10x/
obj-y += bcm/
obj-$(CONFIG_ARCH_BERLIN) += berlin/
obj-y += cix/
obj-$(CONFIG_ARCH_DAVINCI) += davinci/
obj-$(CONFIG_COMMON_CLK_ESWIN) += eswin/
obj-$(CONFIG_ARCH_HISI) += hisilicon/
obj-$(CONFIG_COMMON_CLK_HISI) += hisilicon/
obj-y += imgtec/
obj-y += imx/
obj-y += ingenic/
@@ -151,7 +164,7 @@ obj-y += spacemit/
obj-$(CONFIG_PLAT_SPEAR) += spear/
obj-y += sprd/
obj-$(CONFIG_ARCH_STI) += st/
obj-$(CONFIG_ARCH_STM32) += stm32/
obj-$(CONFIG_COMMON_CLK_STM32MP) += stm32/
obj-y += starfive/
obj-$(CONFIG_ARCH_SUNXI) += sunxi/
obj-y += sunxi-ng/
@@ -159,6 +172,7 @@ obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-y += tenstorrent/
obj-y += thead/
obj-y += ti/
obj-y += ultrarisc/
obj-$(CONFIG_CLK_UNIPHIER) += uniphier/
obj-$(CONFIG_ARCH_U8500) += ux500/
obj-y += versatile/
+10
View File
@@ -272,6 +272,13 @@ static const unsigned int sdclk_parent_ids[] = {
static const struct clk_hw *sdclk_parent_hws[ARRAY_SIZE(sdclk_parent_ids)];
static const unsigned int peciclk_parent_ids[] = {
SCU1_CLKIN,
SCU1_CLK_HPLL_DIV4
};
static const struct clk_hw *peciclk_parent_hws[ARRAY_SIZE(peciclk_parent_ids)];
#define FIXED_CLK(_id, _name, _rate) \
{ \
.id = _id, \
@@ -457,6 +464,7 @@ static const struct ast2700_clk_info ast2700_scu1_clk_info[] __initconst = {
PLL_CLK(SCU1_CLK_HPLL, CLK_PLL, "soc1-hpll", SCU1_CLKIN, SCU1_HPLL_PARAM),
PLL_CLK(SCU1_CLK_APLL, CLK_PLL, "soc1-apll", SCU1_CLKIN, SCU1_APLL_PARAM),
PLL_CLK(SCU1_CLK_DPLL, CLK_PLL, "soc1-dpll", SCU1_CLKIN, SCU1_DPLL_PARAM),
FIXED_FACTOR_CLK(SCU1_CLK_HPLL_DIV4, "soc1-hpll_div4", SCU1_CLK_HPLL, 1, 4),
FIXED_FACTOR_CLK(SCU1_CLK_APLL_DIV2, "soc1-apll_div2", SCU1_CLK_APLL, 1, 2),
FIXED_FACTOR_CLK(SCU1_CLK_APLL_DIV4, "soc1-apll_div4", SCU1_CLK_APLL, 1, 4),
FIXED_FACTOR_CLK(SCU1_CLK_CAN, "canclk", SCU1_CLK_APLL, 1, 10),
@@ -480,6 +488,8 @@ static const struct ast2700_clk_info ast2700_scu1_clk_info[] __initconst = {
uxclk_parent_hws, SCU1_CLK_SEL2, 0, 2),
MUX_CLK(SCU1_CLK_HUXCLK, "huxclk", uxclk_parent_ids, ARRAY_SIZE(uxclk_parent_ids),
uxclk_parent_hws, SCU1_CLK_SEL2, 3, 2),
MUX_CLK(SCU1_CLK_PECI, "peciclk", peciclk_parent_ids, ARRAY_SIZE(peciclk_parent_ids),
peciclk_parent_hws, SCU1_CLK_SEL2, 16, 1),
DIVIDER_CLK(SCU1_CLK_SDCLK, "sdclk", SCU1_CLK_SDMUX,
SCU1_CLK_SEL1, 14, 3, ast2700_clk_div_table),
PLL_CLK(SCU1_CLK_UARTX, CLK_UART_PLL, "uartxclk", SCU1_CLK_UXCLK, SCU1_UXCLK_CTRL),
+3 -2
View File
@@ -2,6 +2,7 @@
#include <linux/clk-provider.h>
#include <linux/clk/at91_pmc.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <linux/slab.h>
@@ -217,7 +218,7 @@ CLK_OF_DECLARE(of_sama5d4_clk_h32mx_setup, "atmel,sama5d4-clk-h32mx",
static void __init of_sama5d2_clk_i2s_mux_setup(struct device_node *np)
{
struct regmap *regmap_sfr;
u8 bus_id;
u64 bus_id;
const char *parent_names[2];
struct device_node *i2s_mux_np;
struct clk_hw *hw;
@@ -228,7 +229,7 @@ static void __init of_sama5d2_clk_i2s_mux_setup(struct device_node *np)
return;
for_each_child_of_node(np, i2s_mux_np) {
if (of_property_read_u8(i2s_mux_np, "reg", &bus_id))
if (of_property_read_reg(i2s_mux_np, 0, &bus_id, NULL))
continue;
if (bus_id > I2S_BUS_NR)
+1 -2
View File
@@ -1098,8 +1098,7 @@ static u8 kona_peri_clk_get_parent(struct clk_hw *hw)
index = selector_read_index(bcm_clk->ccu, &data->sel);
/* Not all callers would handle an out-of-range value gracefully */
return index == BAD_CLK_INDEX ? 0 : index;
return index;
}
static int kona_peri_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+16
View File
@@ -0,0 +1,16 @@
# SPDX-License-Identifier: GPL-2.0
# Audio subsystem clock support for Cixtech SoC family
menu "Cixtech Audio Subsystem Clock Driver"
config CLK_SKY1_AUDSS
tristate "Cixtech Sky1 Audio Subsystem Clock Driver"
depends on ARCH_CIX || COMPILE_TEST
select AUXILIARY_BUS
select REGMAP_MMIO
select RESET_CONTROLLER
help
Support for the Audio Subsystem clock controller present on
Cixtech Sky1 SoC. This driver provides mux, divider and gate
clocks for DSP, I2S, HDA and related blocks in the audio
subsystem. Say M or Y here if you want to build this driver.
endmenu
+3
View File
@@ -0,0 +1,3 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_CLK_SKY1_AUDSS) += clk-sky1-audss.o
File diff suppressed because it is too large Load Diff
+6 -6
View File
@@ -147,12 +147,12 @@ static int bd71837_clk_probe(struct platform_device *pdev)
}
static const struct platform_device_id bd718x7_clk_id[] = {
{ "bd71837-clk", ROHM_CHIP_TYPE_BD71837 },
{ "bd71847-clk", ROHM_CHIP_TYPE_BD71847 },
{ "bd71828-clk", ROHM_CHIP_TYPE_BD71828 },
{ "bd71815-clk", ROHM_CHIP_TYPE_BD71815 },
{ "bd72720-clk", ROHM_CHIP_TYPE_BD72720 },
{ },
{ .name = "bd71837-clk", .driver_data = ROHM_CHIP_TYPE_BD71837 },
{ .name = "bd71847-clk", .driver_data = ROHM_CHIP_TYPE_BD71847 },
{ .name = "bd71828-clk", .driver_data = ROHM_CHIP_TYPE_BD71828 },
{ .name = "bd71815-clk", .driver_data = ROHM_CHIP_TYPE_BD71815 },
{ .name = "bd72720-clk", .driver_data = ROHM_CHIP_TYPE_BD72720 },
{ }
};
MODULE_DEVICE_TABLE(platform, bd718x7_clk_id);
+1 -1
View File
@@ -679,7 +679,7 @@ MODULE_DEVICE_TABLE(of, cdce706_dt_match);
#endif
static const struct i2c_device_id cdce706_id[] = {
{ "cdce706" },
{ .name = "cdce706" },
{ }
};
MODULE_DEVICE_TABLE(i2c, cdce706_id);
+4 -4
View File
@@ -826,10 +826,10 @@ static const struct clk_cdce925_chip_info clk_cdce949_info = {
};
static const struct i2c_device_id cdce925_id[] = {
{ "cdce913", (kernel_ulong_t)&clk_cdce913_info },
{ "cdce925", (kernel_ulong_t)&clk_cdce925_info },
{ "cdce937", (kernel_ulong_t)&clk_cdce937_info },
{ "cdce949", (kernel_ulong_t)&clk_cdce949_info },
{ .name = "cdce913", .driver_data = (kernel_ulong_t)&clk_cdce913_info },
{ .name = "cdce925", .driver_data = (kernel_ulong_t)&clk_cdce925_info },
{ .name = "cdce937", .driver_data = (kernel_ulong_t)&clk_cdce937_info },
{ .name = "cdce949", .driver_data = (kernel_ulong_t)&clk_cdce949_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, cdce925_id);
+1
View File
@@ -462,3 +462,4 @@ struct clk_hw *devm_clk_hw_register_composite_pdata(struct device *dev,
rate_hw, rate_ops, gate_hw,
gate_ops, flags);
}
EXPORT_SYMBOL_GPL(devm_clk_hw_register_composite_pdata);
+76
View File
@@ -155,6 +155,78 @@ static int __set_clk_rates(struct device_node *node, bool clk_supplier)
return 0;
}
static int __set_clk_spread_spectrum(struct device_node *node, bool clk_supplier)
{
u32 elem_size = sizeof(struct clk_spread_spectrum);
struct clk_spread_spectrum *sscs;
struct of_phandle_args clkspec;
int rc, count, index;
struct clk *clk;
/* modfreq, spreadPercent, modmethod */
count = of_property_count_elems_of_size(node, "assigned-clock-sscs", elem_size);
if (count <= 0)
return 0;
sscs = kcalloc(count, elem_size, GFP_KERNEL);
if (!sscs)
return -ENOMEM;
rc = of_property_read_u32_array(node, "assigned-clock-sscs", (u32 *)sscs,
count * 3);
if (rc)
goto free_sscs;
for (index = 0; index < count; index++) {
struct clk_spread_spectrum *conf = &sscs[index];
struct clk_hw *hw;
if (!conf->modfreq_hz && !conf->spread_bp && !conf->method)
continue;
rc = of_parse_phandle_with_args(node, "assigned-clocks", "#clock-cells",
index, &clkspec);
if (rc < 0) {
/* skip empty (null) phandles */
if (rc == -ENOENT) {
rc = 0;
continue;
} else
goto free_sscs;
}
if (clkspec.np == node && !clk_supplier) {
of_node_put(clkspec.np);
goto free_sscs;
}
clk = of_clk_get_from_provider(&clkspec);
of_node_put(clkspec.np);
if (IS_ERR(clk)) {
if (PTR_ERR(clk) != -EPROBE_DEFER)
pr_warn("clk: couldn't get clock %d for %pOF\n",
index, node);
rc = PTR_ERR(clk);
goto free_sscs;
}
hw = __clk_get_hw(clk);
rc = clk_hw_set_spread_spectrum(hw, conf);
if (rc < 0) {
pr_err("clk: couldn't set %s clk spread spectrum %u %u %u: %d\n",
__clk_get_name(clk), conf->modfreq_hz, conf->spread_bp,
conf->method, rc);
/* Do not fail */
rc = 0;
}
clk_put(clk);
}
free_sscs:
kfree(sscs);
return rc;
}
/**
* of_clk_set_defaults() - parse and set assigned clocks configuration
* @node: device node to apply clock settings for
@@ -174,6 +246,10 @@ int of_clk_set_defaults(struct device_node *node, bool clk_supplier)
if (!node)
return 0;
rc = __set_clk_spread_spectrum(node, clk_supplier);
if (rc < 0)
return rc;
rc = __set_clk_parents(node, clk_supplier);
if (rc < 0)
return rc;
+3 -7
View File
@@ -122,8 +122,8 @@ static const struct of_device_id cs2000_of_match[] = {
MODULE_DEVICE_TABLE(of, cs2000_of_match);
static const struct i2c_device_id cs2000_id[] = {
{ "cs2000-cp", },
{}
{ .name = "cs2000-cp" },
{ }
};
MODULE_DEVICE_TABLE(i2c, cs2000_id);
@@ -404,11 +404,7 @@ static int cs2000_enable(struct clk_hw *hw)
if (ret < 0)
return ret;
ret = cs2000_wait_pll_lock(priv);
if (ret < 0)
return ret;
return ret;
return cs2000_wait_pll_lock(priv);
}
static void cs2000_disable(struct clk_hw *hw)
+17 -2
View File
@@ -99,6 +99,11 @@ struct clk *devm_clk_get_optional_enabled(struct device *dev, const char *id)
}
EXPORT_SYMBOL_GPL(devm_clk_get_optional_enabled);
static void devm_clk_disable_unprepare(void *data)
{
clk_disable_unprepare(data);
}
struct clk *devm_clk_get_optional_enabled_with_rate(struct device *dev,
const char *id,
unsigned long rate)
@@ -106,8 +111,7 @@ struct clk *devm_clk_get_optional_enabled_with_rate(struct device *dev,
struct clk *clk;
int ret;
clk = __devm_clk_get(dev, id, clk_get_optional, NULL,
clk_disable_unprepare);
clk = devm_clk_get_optional(dev, id);
if (IS_ERR(clk))
return ERR_CAST(clk);
@@ -119,6 +123,10 @@ struct clk *devm_clk_get_optional_enabled_with_rate(struct device *dev,
if (ret)
goto out_put_clk;
ret = devm_add_action_or_reset(dev, devm_clk_disable_unprepare, clk);
if (ret)
goto out_put_clk;
return clk;
out_put_clk:
@@ -222,6 +230,13 @@ err_clk_get:
return ret;
}
int __must_check devm_clk_bulk_get_enable(struct device *dev, int num_clks,
struct clk_bulk_data *clks)
{
return __devm_clk_bulk_get_enable(dev, num_clks, clks, false);
}
EXPORT_SYMBOL_GPL(devm_clk_bulk_get_enable);
int __must_check devm_clk_bulk_get_optional_enable(struct device *dev, int num_clks,
struct clk_bulk_data *clks)
{
+17 -8
View File
@@ -15,6 +15,7 @@
#include <linux/err.h>
#include <linux/string.h>
#include <linux/log2.h>
#include <linux/overflow.h>
/*
* DOC: basic adjustable divider clock that cannot gate
@@ -301,6 +302,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, struct clk_hw *parent,
int i, bestdiv = 0;
unsigned long parent_rate, best = 0, now, maxdiv;
unsigned long parent_rate_saved = *best_parent_rate;
unsigned long target_parent_rate;
if (!rate)
rate = 1;
@@ -315,15 +317,11 @@ static int clk_divider_bestdiv(struct clk_hw *hw, struct clk_hw *parent,
return bestdiv;
}
/*
* The maximum divider we can use without overflowing
* unsigned long in rate * i below
*/
maxdiv = min(ULONG_MAX / rate, maxdiv);
for (i = _next_div(table, 0, flags); i <= maxdiv;
i = _next_div(table, i, flags)) {
if (rate * i == parent_rate_saved) {
bool overflow = check_mul_overflow(rate, (unsigned long)i, &target_parent_rate);
if (!overflow && target_parent_rate == parent_rate_saved) {
/*
* It's the most ideal case if the requested rate can be
* divided from parent clock without needing to change
@@ -332,13 +330,24 @@ static int clk_divider_bestdiv(struct clk_hw *hw, struct clk_hw *parent,
*best_parent_rate = parent_rate_saved;
return i;
}
parent_rate = clk_hw_round_rate(parent, rate * i);
/*
* Clamp target_parent_rate to ULONG_MAX on overflow. The true
* required parent rate exceeds what can be represented, so ask
* the parent for the highest rate it can produce. There is no
* point continuing the loop past this since larger dividers
* only move further from the requested rate.
*/
if (overflow)
target_parent_rate = ULONG_MAX;
parent_rate = clk_hw_round_rate(parent, target_parent_rate);
now = DIV_ROUND_UP_ULL((u64)parent_rate, i);
if (_is_best_div(rate, now, best, flags)) {
bestdiv = i;
best = now;
*best_parent_rate = parent_rate;
}
if (overflow)
break;
}
if (!bestdiv) {
+153
View File
@@ -0,0 +1,153 @@
// SPDX-License-Identifier: GPL-2.0
/*
* KUnit tests for clk_divider_bestdiv()
*/
#include <kunit/test.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/limits.h>
#include <linux/units.h>
#define PARENT_RATE_1GHZ GIGA
#define PARENT_RATE_2GHZ (2 * GIGA)
#define PARENT_RATE_4GHZ (4 * GIGA)
KUNIT_DEFINE_ACTION_WRAPPER(clk_hw_unregister_fixed_rate_wrapper,
clk_hw_unregister_fixed_rate, struct clk_hw *);
KUNIT_DEFINE_ACTION_WRAPPER(clk_hw_unregister_divider_wrapper,
clk_hw_unregister_divider, struct clk_hw *);
KUNIT_DEFINE_ACTION_WRAPPER(clk_hw_unregister_mux_wrapper,
clk_hw_unregister_mux, struct clk_hw *);
static const struct clk_div_table bestdiv_table[] = {
{ .val = 0, .div = 2 },
{ .val = 1, .div = 4 },
{ .val = 2, .div = 8 },
{ /* sentinel */ }
};
/*
* Test that clk_round_rate(clk, ULONG_MAX) returns the maximum achievable
* rate for a divider clock.
*/
static void clk_divider_bestdiv_ulong_max_returns_max_rate(struct kunit *test)
{
struct clk_hw *parent_hw, *div_hw;
unsigned long rate;
u32 *fake_reg;
fake_reg = kunit_kzalloc(test, sizeof(*fake_reg), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fake_reg);
parent_hw = clk_hw_register_fixed_rate(NULL, "bestdiv-parent",
NULL, 0, PARENT_RATE_1GHZ);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent_hw);
KUNIT_ASSERT_EQ(test, 0,
kunit_add_action_or_reset(test, clk_hw_unregister_fixed_rate_wrapper,
parent_hw));
div_hw = clk_hw_register_divider_table(NULL, "bestdiv-div",
"bestdiv-parent",
CLK_SET_RATE_PARENT,
(void __iomem __force *)fake_reg,
0, 2, 0, bestdiv_table, NULL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, div_hw);
KUNIT_ASSERT_EQ(test, 0,
kunit_add_action_or_reset(test, clk_hw_unregister_divider_wrapper,
div_hw));
/*
* ULONG_MAX is the canonical way to probe the maximum rate a clock
* can produce.
*/
rate = clk_hw_round_rate(div_hw, ULONG_MAX);
KUNIT_EXPECT_EQ(test, rate, PARENT_RATE_1GHZ / 2);
}
/*
* Test that clk_round_rate(clk, ULONG_MAX) returns the correct maximum rate
* when a mux clock sits between a divider and its parent candidates.
*
* Topology:
*
* [fixed 4 GHz] --\
* +--> [mux CLK_SET_RATE_PARENT] --> [div {2,4,8} CLK_SET_RATE_PARENT]
* [fixed 2 GHz] --/
*
*/
static void clk_divider_bestdiv_mux_ulong_max_returns_max_rate(struct kunit *test)
{
static const char * const mux_parents[] = {
"bestdiv-mux-parent-a",
"bestdiv-mux-parent-b",
};
struct clk_hw *parent_a_hw, *parent_b_hw, *mux_hw, *div_hw;
u32 *fake_reg_mux, *fake_reg_div;
unsigned long rate;
fake_reg_mux = kunit_kzalloc(test, sizeof(*fake_reg_mux), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fake_reg_mux);
fake_reg_div = kunit_kzalloc(test, sizeof(*fake_reg_div), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fake_reg_div);
/* Higher-rate parent: the mux should select this for ULONG_MAX. */
parent_a_hw = clk_hw_register_fixed_rate(NULL, "bestdiv-mux-parent-a",
NULL, 0, PARENT_RATE_4GHZ);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent_a_hw);
KUNIT_ASSERT_EQ(test, 0,
kunit_add_action_or_reset(test, clk_hw_unregister_fixed_rate_wrapper,
parent_a_hw));
/* Lower-rate parent: should not be selected. */
parent_b_hw = clk_hw_register_fixed_rate(NULL, "bestdiv-mux-parent-b",
NULL, 0, PARENT_RATE_2GHZ);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent_b_hw);
KUNIT_ASSERT_EQ(test, 0,
kunit_add_action_or_reset(test, clk_hw_unregister_fixed_rate_wrapper,
parent_b_hw));
/*
* 1-bit mux register selects between the two parents.
* CLK_SET_RATE_PARENT allows the divider's rate request to
* propagate into clk_mux_determine_rate().
*/
mux_hw = clk_hw_register_mux(NULL, "bestdiv-mux",
mux_parents, ARRAY_SIZE(mux_parents),
CLK_SET_RATE_PARENT,
(void __iomem __force *)fake_reg_mux,
0, 1, 0, NULL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mux_hw);
KUNIT_ASSERT_EQ(test, 0,
kunit_add_action_or_reset(test, clk_hw_unregister_mux_wrapper,
mux_hw));
div_hw = clk_hw_register_divider_table(NULL, "bestdiv-mux-div",
"bestdiv-mux",
CLK_SET_RATE_PARENT,
(void __iomem __force *)fake_reg_div,
0, 2, 0, bestdiv_table, NULL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, div_hw);
KUNIT_ASSERT_EQ(test, 0,
kunit_add_action_or_reset(test, clk_hw_unregister_divider_wrapper,
div_hw));
rate = clk_hw_round_rate(div_hw, ULONG_MAX);
KUNIT_EXPECT_EQ(test, rate, PARENT_RATE_4GHZ / 2);
}
static struct kunit_case clk_divider_bestdiv_test_cases[] = {
KUNIT_CASE(clk_divider_bestdiv_ulong_max_returns_max_rate),
KUNIT_CASE(clk_divider_bestdiv_mux_ulong_max_returns_max_rate),
{}
};
static struct kunit_suite clk_divider_bestdiv_test_suite = {
.name = "clk_divider_bestdiv",
.test_cases = clk_divider_bestdiv_test_cases,
};
kunit_test_suite(clk_divider_bestdiv_test_suite);
MODULE_DESCRIPTION("KUnit tests for clk divider");
MODULE_LICENSE("GPL");
+33 -10
View File
@@ -57,6 +57,7 @@
#define REG_RST_CTRL2 0x830
#define REG_RST_CTRL1 0x834
#define REG_PCIE_HB_RST BIT(29)
#define EN751221_REG_RST_DMT 0x84
#define EN751221_REG_RST_USB 0xec
@@ -338,6 +339,7 @@ static const struct en_clk_desc en7581_base_clks[] = {
static const u16 en7581_rst_ofs[] = {
REG_RST_CTRL2,
REG_RST_CTRL1,
REG_NP_SCU_PCIC,
};
static const u16 en751221_rst_ofs[] = {
@@ -450,6 +452,11 @@ static const u16 en7581_rst_map[] = {
[EN7581_CPU_TIMER_RST] = RST_NR_PER_BANK + 28,
[EN7581_PCIE_HB_RST] = RST_NR_PER_BANK + 29,
[EN7581_XPON_MAC_RST] = RST_NR_PER_BANK + 31,
/* RST_PCIC */
[EN7581_PCIC_PERSTOUT0_RST] = 2 * RST_NR_PER_BANK + 29,
[EN7581_PCIC_PERSTOUT1_RST] = 2 * RST_NR_PER_BANK + 26,
[EN7581_PCIC_PERSTOUT2_RST] = 2 * RST_NR_PER_BANK + 16,
};
static const u16 en751221_rst_map[] = {
@@ -635,9 +642,7 @@ static int en7581_pci_enable(struct clk_hw *hw)
void __iomem *np_base = cg->base;
u32 val, mask;
mask = REG_PCI_CONTROL_REFCLK_EN0 | REG_PCI_CONTROL_REFCLK_EN1 |
REG_PCI_CONTROL_PERSTOUT1 | REG_PCI_CONTROL_PERSTOUT2 |
REG_PCI_CONTROL_PERSTOUT;
mask = REG_PCI_CONTROL_REFCLK_EN0 | REG_PCI_CONTROL_REFCLK_EN1;
val = readl(np_base + REG_PCI_CONTROL);
writel(val | mask, np_base + REG_PCI_CONTROL);
@@ -650,9 +655,7 @@ static void en7581_pci_disable(struct clk_hw *hw)
void __iomem *np_base = cg->base;
u32 val, mask;
mask = REG_PCI_CONTROL_REFCLK_EN0 | REG_PCI_CONTROL_REFCLK_EN1 |
REG_PCI_CONTROL_PERSTOUT1 | REG_PCI_CONTROL_PERSTOUT2 |
REG_PCI_CONTROL_PERSTOUT;
mask = REG_PCI_CONTROL_REFCLK_EN0 | REG_PCI_CONTROL_REFCLK_EN1;
val = readl(np_base + REG_PCI_CONTROL);
writel(val & ~mask, np_base + REG_PCI_CONTROL);
usleep_range(1000, 2000);
@@ -754,11 +757,17 @@ static int en7523_reset_update(struct reset_controller_dev *rcdev,
unsigned long id, bool assert)
{
struct en_rst_data *rst_data = container_of(rcdev, struct en_rst_data, rcdev);
void __iomem *addr = rst_data->base + rst_data->bank_ofs[id / RST_NR_PER_BANK];
u32 offset = rst_data->bank_ofs[id / RST_NR_PER_BANK];
void __iomem *addr = rst_data->base + offset;
bool inverted = false;
u32 val;
/* For PCIC reset logic is inverted, 0:assert 1:deassert */
if (offset == REG_NP_SCU_PCIC)
inverted = true;
val = readl(addr);
if (assert)
if (assert ^ inverted)
val |= BIT(id % RST_NR_PER_BANK);
else
val &= ~BIT(id % RST_NR_PER_BANK);
@@ -783,9 +792,17 @@ static int en7523_reset_status(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct en_rst_data *rst_data = container_of(rcdev, struct en_rst_data, rcdev);
void __iomem *addr = rst_data->base + rst_data->bank_ofs[id / RST_NR_PER_BANK];
u32 offset = rst_data->bank_ofs[id / RST_NR_PER_BANK];
void __iomem *addr = rst_data->base + offset;
bool inverted = false;
u32 val;
return !!(readl(addr) & BIT(id % RST_NR_PER_BANK));
/* For PCIC reset logic is inverted, 0:assert 1:deassert */
if (offset == REG_NP_SCU_PCIC)
inverted = true;
val = readl(addr) & BIT(id % RST_NR_PER_BANK);
return inverted ? !val : !!val;
}
static int en7523_reset_xlate(struct reset_controller_dev *rcdev,
@@ -853,6 +870,12 @@ static int en7581_clk_hw_init(struct platform_device *pdev,
val = readl(base + REG_NP_SCU_PCIC);
writel(val | 3, base + REG_NP_SCU_PCIC);
val = readl(base + REG_RST_CTRL1);
val |= REG_PCIE_HB_RST;
writel(val, base + REG_RST_CTRL1);
val &= ~REG_PCIE_HB_RST;
writel(val, base + REG_RST_CTRL1);
return en7581_reset_register(&pdev->dev, base, en7581_rst_map,
ARRAY_SIZE(en7581_rst_map),
en7581_rst_ofs);
+4
View File
@@ -2227,6 +2227,7 @@ static int k230_clk_set_rate_mul(struct clk_hw *hw, unsigned long rate,
guard(spinlock)(rate_self->lock);
mul_reg = readl(rate_self->reg + clk->mul_reg_off);
mul_reg &= ~(rate_self->mul_mask << rate_self->mul_shift);
mul_reg |= ((mul - 1) & rate_self->mul_mask) << (rate_self->mul_shift);
mul_reg |= BIT(rate_self->write_enable_bit);
writel(mul_reg, rate_self->reg + clk->mul_reg_off);
@@ -2257,6 +2258,7 @@ static int k230_clk_set_rate_div(struct clk_hw *hw, unsigned long rate,
guard(spinlock)(rate_self->lock);
div_reg = readl(rate_self->reg + clk->div_reg_off);
div_reg &= ~(rate_self->div_mask << rate_self->div_shift);
div_reg |= ((div - 1) & rate_self->div_mask) << (rate_self->div_shift);
div_reg |= BIT(rate_self->write_enable_bit);
writel(div_reg, rate_self->reg + clk->div_reg_off);
@@ -2287,11 +2289,13 @@ static int k230_clk_set_rate_mul_div(struct clk_hw *hw, unsigned long rate,
guard(spinlock)(rate_self->lock);
div_reg = readl(rate_self->reg + clk->div_reg_off);
div_reg &= ~(rate_self->div_mask << rate_self->div_shift);
div_reg |= ((div - 1) & rate_self->div_mask) << (rate_self->div_shift);
div_reg |= BIT(rate_self->write_enable_bit);
writel(div_reg, rate_self->reg + clk->div_reg_off);
mul_reg = readl(rate_self->reg + clk->mul_reg_off);
mul_reg &= ~(rate_self->mul_mask << rate_self->mul_shift);
mul_reg |= ((mul - 1) & rate_self->mul_mask) << (rate_self->mul_shift);
mul_reg |= BIT(rate_self->write_enable_bit);
writel(mul_reg, rate_self->reg + clk->mul_reg_off);
+14 -25
View File
@@ -175,10 +175,6 @@
#define LMK04832_REG_RB_HOLDOVER 0x188
#define LMK04832_REG_SPI_LOCK 0x555
enum lmk04832_device_types {
LMK04832,
};
/**
* struct lmk04832_device_info - Holds static device information that is
* specific to the chip revision
@@ -197,14 +193,12 @@ struct lmk04832_device_info {
unsigned int vco1_range[2];
};
static const struct lmk04832_device_info lmk04832_device_info[] = {
[LMK04832] = {
.pid = 0x63d1, /* WARNING PROD_ID is inverted in the datasheet */
.maskrev = 0x70,
.num_channels = 14,
.vco0_range = { 2440, 2580 },
.vco1_range = { 2945, 3255 },
},
static const struct lmk04832_device_info lmk04832_device_info = {
.pid = 0x63d1, /* WARNING PROD_ID is inverted in the datasheet */
.maskrev = 0x70,
.num_channels = 14,
.vco0_range = { 2440, 2580 },
.vco1_range = { 2945, 3255 },
};
enum lmk04832_rdbk_type {
@@ -422,11 +416,10 @@ static unsigned long lmk04832_vco_recalc_rate(struct clk_hw *hw,
*/
static int lmk04832_check_vco_ranges(struct lmk04832 *lmk, unsigned long rate)
{
struct spi_device *spi = to_spi_device(lmk->dev);
const struct lmk04832_device_info *info;
unsigned long mhz = rate / 1000000;
info = &lmk04832_device_info[spi_get_device_id(spi)->driver_data];
info = &lmk04832_device_info;
if (mhz >= info->vco0_range[0] && mhz <= info->vco0_range[1])
return LMK04832_VAL_VCO_MUX_VCO0;
@@ -822,13 +815,6 @@ static int lmk04832_sclk_sync_sequence(struct lmk04832 *lmk)
if (ret)
return ret;
ret = regmap_update_bits(lmk->regmap, LMK04832_REG_SYNC,
LMK04832_BIT_SYNC_MODE,
FIELD_PREP(LMK04832_BIT_SYNC_MODE,
lmk->sync_mode));
if (ret)
return ret;
/*
* 9. (optional) if SCLKx_y_DIS_MODE was used to mute SYSREF outputs
* during the SYNC event, restore SCLKx_y_DIS_MODE=0 for active state,
@@ -843,7 +829,10 @@ static int lmk04832_sclk_sync_sequence(struct lmk04832 *lmk)
* SYNC pulse to delay the output by some number of VCO counts).
*/
return ret;
return regmap_update_bits(lmk->regmap, LMK04832_REG_SYNC,
LMK04832_BIT_SYNC_MODE,
FIELD_PREP(LMK04832_BIT_SYNC_MODE,
lmk->sync_mode));
}
static int lmk04832_sclk_is_enabled(struct clk_hw *hw)
@@ -1405,7 +1394,7 @@ static int lmk04832_probe(struct spi_device *spi)
int ret;
int i;
info = &lmk04832_device_info[spi_get_device_id(spi)->driver_data];
info = &lmk04832_device_info;
lmk = devm_kzalloc(&spi->dev, sizeof(struct lmk04832), GFP_KERNEL);
if (!lmk)
@@ -1553,8 +1542,8 @@ static int lmk04832_probe(struct spi_device *spi)
}
static const struct spi_device_id lmk04832_id[] = {
{ "lmk04832", LMK04832 },
{}
{ .name = "lmk04832" },
{ }
};
MODULE_DEVICE_TABLE(spi, lmk04832_id);
+4 -4
View File
@@ -264,10 +264,10 @@ static int max77686_clk_probe(struct platform_device *pdev)
}
static const struct platform_device_id max77686_clk_id[] = {
{ "max77686-clk", .driver_data = CHIP_MAX77686, },
{ "max77802-clk", .driver_data = CHIP_MAX77802, },
{ "max77620-clock", .driver_data = CHIP_MAX77620, },
{},
{ .name = "max77686-clk", .driver_data = CHIP_MAX77686 },
{ .name = "max77802-clk", .driver_data = CHIP_MAX77802 },
{ .name = "max77620-clock", .driver_data = CHIP_MAX77620 },
{ }
};
MODULE_DEVICE_TABLE(platform, max77686_clk_id);
-14
View File
@@ -17,7 +17,6 @@ static void __init moxart_of_pll_clk_init(struct device_node *node)
{
void __iomem *base;
struct clk_hw *hw;
struct clk *ref_clk;
unsigned int mul;
const char *name = node->name;
const char *parent_name;
@@ -34,12 +33,6 @@ static void __init moxart_of_pll_clk_init(struct device_node *node)
mul = readl(base + 0x30) >> 3 & 0x3f;
iounmap(base);
ref_clk = of_clk_get(node, 0);
if (IS_ERR(ref_clk)) {
pr_err("%pOF: of_clk_get failed\n", node);
return;
}
hw = clk_hw_register_fixed_factor(NULL, name, parent_name, 0, mul, 1);
if (IS_ERR(hw)) {
pr_err("%pOF: failed to register clock\n", node);
@@ -56,7 +49,6 @@ static void __init moxart_of_apb_clk_init(struct device_node *node)
{
void __iomem *base;
struct clk_hw *hw;
struct clk *pll_clk;
unsigned int div, val;
unsigned int div_idx[] = { 2, 3, 4, 6, 8};
const char *name = node->name;
@@ -78,12 +70,6 @@ static void __init moxart_of_apb_clk_init(struct device_node *node)
val = 0;
div = div_idx[val] * 2;
pll_clk = of_clk_get(node, 0);
if (IS_ERR(pll_clk)) {
pr_err("%pOF: of_clk_get failed\n", node);
return;
}
hw = clk_hw_register_fixed_factor(NULL, name, parent_name, 0, 1, div);
if (IS_ERR(hw)) {
pr_err("%pOF: failed to register clock\n", node);
+15 -9
View File
@@ -194,6 +194,13 @@ static void palmas_clks_get_clk_data(struct platform_device *pdev,
cinfo->ext_control_pin = prop;
}
static void palmas_clks_unprepare_ext_control(void *data)
{
struct palmas_clock_info *cinfo = data;
clk_unprepare(cinfo->hw.clk);
}
static int palmas_clks_init_configure(struct palmas_clock_info *cinfo)
{
int ret;
@@ -214,13 +221,18 @@ static int palmas_clks_init_configure(struct palmas_clock_info *cinfo)
return ret;
}
ret = devm_add_action_or_reset(cinfo->dev,
palmas_clks_unprepare_ext_control,
cinfo);
if (ret)
return ret;
ret = palmas_ext_control_req_config(cinfo->palmas,
cinfo->clk_desc->sleep_reqstr_id,
cinfo->ext_control_pin, true);
if (ret < 0) {
dev_err(cinfo->dev, "Ext config for %s failed, %d\n",
cinfo->clk_desc->clk_name, ret);
clk_unprepare(cinfo->hw.clk);
return ret;
}
}
@@ -230,7 +242,6 @@ static int palmas_clks_init_configure(struct palmas_clock_info *cinfo)
static int palmas_clks_probe(struct platform_device *pdev)
{
struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
struct device_node *node = pdev->dev.of_node;
const struct palmas_clks_of_match_data *match_data;
struct palmas_clock_info *cinfo;
int ret;
@@ -264,24 +275,19 @@ static int palmas_clks_probe(struct platform_device *pdev)
return ret;
}
ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, &cinfo->hw);
ret = devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_simple_get,
&cinfo->hw);
if (ret < 0)
dev_err(&pdev->dev, "Fail to add clock driver, %d\n", ret);
return ret;
}
static void palmas_clks_remove(struct platform_device *pdev)
{
of_clk_del_provider(pdev->dev.of_node);
}
static struct platform_driver palmas_clks_driver = {
.driver = {
.name = "palmas-clk",
.of_match_table = palmas_clks_of_match,
},
.probe = palmas_clks_probe,
.remove = palmas_clks_remove,
};
module_platform_driver(palmas_clks_driver);
+3 -3
View File
@@ -394,9 +394,9 @@ static const struct rs9_chip_info renesas_9fgv0841_info = {
};
static const struct i2c_device_id rs9_id[] = {
{ "9fgv0241", .driver_data = (kernel_ulong_t)&renesas_9fgv0241_info },
{ "9fgv0441", .driver_data = (kernel_ulong_t)&renesas_9fgv0441_info },
{ "9fgv0841", .driver_data = (kernel_ulong_t)&renesas_9fgv0841_info },
{ .name = "9fgv0241", .driver_data = (kernel_ulong_t)&renesas_9fgv0241_info },
{ .name = "9fgv0441", .driver_data = (kernel_ulong_t)&renesas_9fgv0441_info },
{ .name = "9fgv0841", .driver_data = (kernel_ulong_t)&renesas_9fgv0841_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, rs9_id);
+1 -7
View File
@@ -1174,12 +1174,6 @@ static unsigned long rp1_varsrc_recalc_rate(struct clk_hw *hw,
return clock->cached_rate;
}
static int rp1_varsrc_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
return 0;
}
static const struct clk_ops rp1_pll_core_ops = {
.is_prepared = rp1_pll_core_is_on,
.prepare = rp1_pll_core_on,
@@ -1227,7 +1221,7 @@ static const struct clk_ops rp1_clk_ops = {
static const struct clk_ops rp1_varsrc_ops = {
.set_rate = rp1_varsrc_set_rate,
.recalc_rate = rp1_varsrc_recalc_rate,
.determine_rate = rp1_varsrc_determine_rate,
.determine_rate = clk_determine_rate_noop,
};
static struct clk_hw *rp1_register_pll(struct rp1_clockman *clockman,
+6 -6
View File
@@ -225,12 +225,12 @@ static void s2mps11_clk_remove(struct platform_device *pdev)
}
static const struct platform_device_id s2mps11_clk_id[] = {
{ "s2mpg10-clk", S2MPG10},
{ "s2mps11-clk", S2MPS11X},
{ "s2mps13-clk", S2MPS13X},
{ "s2mps14-clk", S2MPS14X},
{ "s5m8767-clk", S5M8767X},
{ },
{ .name = "s2mpg10-clk", .driver_data = S2MPG10 },
{ .name = "s2mps11-clk", .driver_data = S2MPS11X },
{ .name = "s2mps13-clk", .driver_data = S2MPS13X },
{ .name = "s2mps14-clk", .driver_data = S2MPS14X },
{ .name = "s5m8767-clk", .driver_data = S5M8767X },
{ }
};
MODULE_DEVICE_TABLE(platform, s2mps11_clk_id);
+108
View File
@@ -0,0 +1,108 @@
// SPDX-License-Identifier: GPL-2.0
/*
* The Vendor OEM extension for System Control and Power Interface (SCMI)
* Protocol based clock driver
*
* Copyright 2025 NXP
*/
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/scmi_imx_protocol.h>
#include <linux/scmi_protocol.h>
#include "clk-scmi.h"
#define SCMI_CLOCK_CFG_IMX_SSC 0x80
#define SCMI_CLOCK_IMX_SS_PERCENTAGE_MASK GENMASK(7, 0)
#define SCMI_CLOCK_IMX_SS_MOD_FREQ_MASK GENMASK(23, 8)
#define SCMI_CLOCK_IMX_SS_ENABLE_MASK BIT(24)
/*
* Selection is based on SCMI vendor_id/sub_vendor_id and optional machine
* compatible string, without involving impl_ver. impl_verspecific behavior
* should be considered a bug and handled via SCMI Quirk framework.
*/
struct scmi_clk_oem_info {
char *vendor_id;
char *sub_vendor_id;
char *compatible;
const void *data;
};
static int
scmi_clk_imx_set_spread_spectrum(struct clk_hw *hw,
const struct clk_spread_spectrum *ss_conf)
{
struct scmi_clk *clk = to_scmi_clk(hw);
int ret;
u32 val;
/*
* extConfigValue[7:0] - spread percentage (%)
* extConfigValue[23:8] - Modulation Frequency
* extConfigValue[24] - Enable/Disable
* extConfigValue[31:25] - Reserved
*/
val = FIELD_PREP(SCMI_CLOCK_IMX_SS_PERCENTAGE_MASK, ss_conf->spread_bp / 10000);
val |= FIELD_PREP(SCMI_CLOCK_IMX_SS_MOD_FREQ_MASK, ss_conf->modfreq_hz);
if (ss_conf->method != CLK_SPREAD_NO)
val |= SCMI_CLOCK_IMX_SS_ENABLE_MASK;
ret = scmi_proto_clk_ops->config_oem_set(clk->ph, clk->id,
SCMI_CLOCK_CFG_IMX_SSC,
val, false);
if (ret)
dev_warn(clk->dev,
"Failed to set spread spectrum(%u,%u,%u) for clock ID %d\n",
ss_conf->modfreq_hz, ss_conf->spread_bp, ss_conf->method,
clk->id);
return ret;
}
static int
scmi_clk_imx_query_oem_feats(const struct scmi_protocol_handle *ph, u32 id,
unsigned int *feats_key)
{
int ret;
u32 val;
ret = scmi_proto_clk_ops->config_oem_get(ph, id,
SCMI_CLOCK_CFG_IMX_SSC,
&val, NULL, false);
if (!ret)
*feats_key |= BIT(SCMI_CLK_EXT_OEM_SSC_SUPPORTED);
return 0;
}
static const struct scmi_clk_oem scmi_clk_oem_imx = {
.query_ext_oem_feats = scmi_clk_imx_query_oem_feats,
.set_spread_spectrum = scmi_clk_imx_set_spread_spectrum,
};
static const struct scmi_clk_oem_info info[] = {
{ SCMI_IMX_VENDOR, SCMI_IMX_SUBVENDOR, NULL, &scmi_clk_oem_imx },
};
int scmi_clk_oem_init(struct scmi_device *sdev)
{
const struct scmi_handle *handle = sdev->handle;
int i, size = ARRAY_SIZE(info);
for (i = 0; i < size; i++) {
if (strcmp(handle->version->vendor_id, info[i].vendor_id) ||
strcmp(handle->version->sub_vendor_id, info[i].sub_vendor_id))
continue;
if (info[i].compatible &&
!of_machine_is_compatible(info[i].compatible))
continue;
break;
}
if (i < size)
dev_set_drvdata(&sdev->dev, (void *)info[i].data);
return 0;
}
+16 -28
View File
@@ -13,32 +13,9 @@
#include <linux/module.h>
#include <linux/scmi_protocol.h>
#define NOT_ATOMIC false
#define ATOMIC true
#include "clk-scmi.h"
enum scmi_clk_feats {
SCMI_CLK_ATOMIC_SUPPORTED,
SCMI_CLK_STATE_CTRL_SUPPORTED,
SCMI_CLK_RATE_CTRL_SUPPORTED,
SCMI_CLK_PARENT_CTRL_SUPPORTED,
SCMI_CLK_DUTY_CYCLE_SUPPORTED,
SCMI_CLK_FEATS_COUNT
};
#define SCMI_MAX_CLK_OPS BIT(SCMI_CLK_FEATS_COUNT)
static const struct scmi_clk_proto_ops *scmi_proto_clk_ops;
struct scmi_clk {
u32 id;
struct device *dev;
struct clk_hw hw;
const struct scmi_clock_info *info;
const struct scmi_protocol_handle *ph;
struct clk_parent_data *parent_data;
};
#define to_scmi_clk(clk) container_of(clk, struct scmi_clk, hw)
const struct scmi_clk_proto_ops *scmi_proto_clk_ops;
static unsigned long scmi_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
@@ -235,6 +212,7 @@ static int scmi_clk_ops_init(struct device *dev, struct scmi_clk *sclk,
static const struct clk_ops *
scmi_clk_ops_alloc(struct device *dev, unsigned long feats_key)
{
struct scmi_clk_oem *oem_data = dev_get_drvdata(dev);
struct clk_ops *ops;
ops = devm_kzalloc(dev, sizeof(*ops), GFP_KERNEL);
@@ -281,11 +259,15 @@ scmi_clk_ops_alloc(struct device *dev, unsigned long feats_key)
ops->set_duty_cycle = scmi_clk_set_duty_cycle;
}
if (oem_data && (feats_key & BIT(SCMI_CLK_EXT_OEM_SSC_SUPPORTED)))
ops->set_spread_spectrum = oem_data->set_spread_spectrum;
return ops;
}
/**
* scmi_clk_ops_select() - Select a proper set of clock operations
* @sdev: pointer to the SCMI device
* @sclk: A reference to an SCMI clock descriptor
* @atomic_capable: A flag to indicate if atomic mode is supported by the
* transport
@@ -310,8 +292,8 @@ scmi_clk_ops_alloc(struct device *dev, unsigned long feats_key)
* NULL otherwise.
*/
static const struct clk_ops *
scmi_clk_ops_select(struct scmi_clk *sclk, bool atomic_capable,
unsigned int atomic_threshold_us,
scmi_clk_ops_select(struct scmi_device *sdev, struct scmi_clk *sclk,
bool atomic_capable, unsigned int atomic_threshold_us,
const struct clk_ops **clk_ops_db, size_t db_size)
{
int ret;
@@ -319,6 +301,7 @@ scmi_clk_ops_select(struct scmi_clk *sclk, bool atomic_capable,
const struct scmi_clock_info *ci = sclk->info;
unsigned int feats_key = 0;
const struct clk_ops *ops;
struct scmi_clk_oem *oem_data = dev_get_drvdata(&sdev->dev);
/*
* Note that when transport is atomic but SCMI protocol did not
@@ -343,6 +326,9 @@ scmi_clk_ops_select(struct scmi_clk *sclk, bool atomic_capable,
&val, NULL, false);
if (!ret)
feats_key |= BIT(SCMI_CLK_DUTY_CYCLE_SUPPORTED);
if (oem_data && oem_data->query_ext_oem_feats)
oem_data->query_ext_oem_feats(sclk->ph, sclk->id, &feats_key);
}
if (WARN_ON(feats_key >= db_size))
@@ -400,6 +386,8 @@ static int scmi_clocks_probe(struct scmi_device *sdev)
clk_data->num = count;
hws = clk_data->hws;
scmi_clk_oem_init(sdev);
transport_is_atomic = handle->is_transport_atomic(handle,
&atomic_threshold_us);
@@ -431,7 +419,7 @@ static int scmi_clocks_probe(struct scmi_device *sdev)
* to avoid sharing the devm_ allocated clk_ops between multiple
* SCMI clk driver instances.
*/
scmi_ops = scmi_clk_ops_select(sclk, transport_is_atomic,
scmi_ops = scmi_clk_ops_select(sdev, sclk, transport_is_atomic,
atomic_threshold_us,
scmi_clk_ops_db,
ARRAY_SIZE(scmi_clk_ops_db));
+51
View File
@@ -0,0 +1,51 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright 2025 NXP
*/
#ifndef __SCMI_CLK_H
#define __SCMI_CLK_H
#include <linux/bits.h>
#include <linux/clk-provider.h>
#include <linux/scmi_protocol.h>
#include <linux/types.h>
#define NOT_ATOMIC false
#define ATOMIC true
enum scmi_clk_feats {
SCMI_CLK_ATOMIC_SUPPORTED,
SCMI_CLK_STATE_CTRL_SUPPORTED,
SCMI_CLK_RATE_CTRL_SUPPORTED,
SCMI_CLK_PARENT_CTRL_SUPPORTED,
SCMI_CLK_DUTY_CYCLE_SUPPORTED,
SCMI_CLK_EXT_OEM_SSC_SUPPORTED,
SCMI_CLK_FEATS_COUNT
};
#define SCMI_MAX_CLK_OPS BIT(SCMI_CLK_FEATS_COUNT)
struct scmi_clk {
u32 id;
struct device *dev;
struct clk_hw hw;
const struct scmi_clock_info *info;
const struct scmi_protocol_handle *ph;
struct clk_parent_data *parent_data;
};
#define to_scmi_clk(clk) container_of(clk, struct scmi_clk, hw)
extern const struct scmi_clk_proto_ops *scmi_proto_clk_ops;
struct scmi_clk_oem {
int (*query_ext_oem_feats)(const struct scmi_protocol_handle *ph,
u32 id, unsigned int *feats_key);
int (*set_spread_spectrum)(struct clk_hw *hw,
const struct clk_spread_spectrum *ss_conf);
};
int scmi_clk_oem_init(struct scmi_device *dev);
#endif
+1 -13
View File
@@ -32,18 +32,6 @@ static unsigned long scpi_clk_recalc_rate(struct clk_hw *hw,
return clk->scpi_ops->clk_get_val(clk->id);
}
static int scpi_clk_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
/*
* We can't figure out what rate it will be, so just return the
* rate back to the caller. scpi_clk_recalc_rate() will be called
* after the rate is set and we'll know what rate the clock is
* running at then.
*/
return 0;
}
static int scpi_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
@@ -54,7 +42,7 @@ static int scpi_clk_set_rate(struct clk_hw *hw, unsigned long rate,
static const struct clk_ops scpi_clk_ops = {
.recalc_rate = scpi_clk_recalc_rate,
.determine_rate = scpi_clk_determine_rate,
.determine_rate = clk_determine_rate_noop,
.set_rate = scpi_clk_set_rate,
};
+1 -1
View File
@@ -379,7 +379,7 @@ static int si514_probe(struct i2c_client *client)
}
static const struct i2c_device_id si514_id[] = {
{ "si514" },
{ .name = "si514" },
{ }
};
MODULE_DEVICE_TABLE(i2c, si514_id);
+3 -3
View File
@@ -364,9 +364,9 @@ static int __maybe_unused si521xx_resume(struct device *dev)
}
static const struct i2c_device_id si521xx_id[] = {
{ "si52144", .driver_data = SI521XX_OE_MAP(0x5, 0xc0) },
{ "si52146", .driver_data = SI521XX_OE_MAP(0x15, 0xe0) },
{ "si52147", .driver_data = SI521XX_OE_MAP(0x17, 0xf8) },
{ .name = "si52144", .driver_data = SI521XX_OE_MAP(0x5, 0xc0) },
{ .name = "si52146", .driver_data = SI521XX_OE_MAP(0x15, 0xe0) },
{ .name = "si52147", .driver_data = SI521XX_OE_MAP(0x17, 0xf8) },
{ }
};
MODULE_DEVICE_TABLE(i2c, si521xx_id);
+5 -5
View File
@@ -1825,11 +1825,11 @@ static void si5341_remove(struct i2c_client *client)
}
static const struct i2c_device_id si5341_id[] = {
{ "si5340", 0 },
{ "si5341", 1 },
{ "si5342", 2 },
{ "si5344", 4 },
{ "si5345", 5 },
{ .name = "si5340" },
{ .name = "si5341" },
{ .name = "si5342" },
{ .name = "si5344" },
{ .name = "si5345" },
{ }
};
MODULE_DEVICE_TABLE(i2c, si5341_id);
+4 -4
View File
@@ -1425,10 +1425,10 @@ si53351_of_clk_get(struct of_phandle_args *clkspec, void *data)
#endif /* CONFIG_OF */
static const struct i2c_device_id si5351_i2c_ids[] = {
{ "si5351a", SI5351_VARIANT_A },
{ "si5351a-msop", SI5351_VARIANT_A3 },
{ "si5351b", SI5351_VARIANT_B },
{ "si5351c", SI5351_VARIANT_C },
{ .name = "si5351a", .driver_data = SI5351_VARIANT_A },
{ .name = "si5351a-msop", .driver_data = SI5351_VARIANT_A3 },
{ .name = "si5351b", .driver_data = SI5351_VARIANT_B },
{ .name = "si5351c", .driver_data = SI5351_VARIANT_C },
{ }
};
MODULE_DEVICE_TABLE(i2c, si5351_i2c_ids);
+65 -17
View File
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Driver for Silicon Labs Si544 Programmable Oscillator
* Driver for Silicon Labs Si544/Si549 Programmable Oscillator
* Copyright (C) 2018 Topic Embedded Products
* Author: Mike Looijmans <mike.looijmans@topic.nl>
*/
@@ -40,7 +40,9 @@
#define SI544_MIN_FREQ 200000U
/* Si544 Internal oscillator runs at 55.05 MHz */
#define FXO 55050000U
#define SI544_XO_FREQ 55050000U
/* Si549 Internal oscilator runs at 152.60 MHz */
#define SI549_XO_FREQ 152600000U
/* VCO range is 10.8 .. 12.1 GHz, max depends on speed grade */
#define FVCO_MIN 10800000000ULL
@@ -56,11 +58,16 @@
#define DELTA_M_FRAC_NUM 19
#define DELTA_M_FRAC_DEN 20000
struct si544_clk_desc {
unsigned long max_freq;
unsigned long xo_freq;
};
struct clk_si544 {
struct clk_hw hw;
struct regmap *regmap;
struct i2c_client *i2c_client;
unsigned long max_freq;
const struct si544_clk_desc *chip_info;
};
#define to_clk_si544(_hw) container_of(_hw, struct clk_si544, hw)
@@ -79,6 +86,7 @@ struct clk_si544_muldiv {
u16 hs_div;
u8 ls_div_bits;
s32 delta_m;
u32 xo_freq;
};
/* Enables or disables the output driver */
@@ -145,6 +153,8 @@ static int si544_get_muldiv(struct clk_si544 *data,
settings->delta_m = reg[0] << 8 | reg[1] << 16 | reg[2] << 24;
settings->delta_m >>= 8;
settings->xo_freq = data->chip_info->xo_freq;
return 0;
}
@@ -193,7 +203,7 @@ static bool is_valid_frequency(const struct clk_si544 *data,
if (frequency < SI544_MIN_FREQ)
return false;
return frequency <= data->max_freq;
return frequency <= data->chip_info->max_freq;
}
/* Calculate divider settings for a given frequency */
@@ -201,6 +211,7 @@ static int si544_calc_muldiv(struct clk_si544_muldiv *settings,
unsigned long frequency)
{
u64 vco;
u32 fxo = settings->xo_freq;
u32 ls_freq;
u32 tmp;
u8 res;
@@ -238,13 +249,13 @@ static int si544_calc_muldiv(struct clk_si544_muldiv *settings,
vco = (u64)ls_freq * settings->hs_div;
/* Calculate the integer part of the feedback divider */
tmp = do_div(vco, FXO);
tmp = do_div(vco, fxo);
settings->fb_div_int = vco;
/* And the fractional bits using the remainder */
vco = (u64)tmp << 32;
vco += FXO / 2; /* Round to nearest multiple */
do_div(vco, FXO);
vco += fxo / 2; /* Round to nearest multiple */
do_div(vco, fxo);
settings->fb_div_frac = vco;
/* Reset the frequency adjustment */
@@ -258,15 +269,16 @@ static unsigned long si544_calc_center_rate(
const struct clk_si544_muldiv *settings)
{
u32 d = settings->hs_div * BIT(settings->ls_div_bits);
u32 fxo = settings->xo_freq;
u64 vco;
/* Calculate VCO from the fractional part */
vco = (u64)settings->fb_div_frac * FXO;
vco += (FXO / 2);
vco = (u64)settings->fb_div_frac * fxo;
vco += (fxo / 2);
vco >>= 32;
/* Add the integer part of the VCO frequency */
vco += (u64)settings->fb_div_int * FXO;
vco += (u64)settings->fb_div_int * fxo;
/* Apply divider to obtain the generated frequency */
do_div(vco, d);
@@ -446,7 +458,7 @@ static int si544_probe(struct i2c_client *client)
init.num_parents = 0;
data->hw.init = &init;
data->i2c_client = client;
data->max_freq = (uintptr_t)i2c_get_match_data(client);
data->chip_info = i2c_get_match_data(client);
if (of_property_read_string(client->dev.of_node, "clock-output-names",
&init.name))
@@ -478,18 +490,54 @@ static int si544_probe(struct i2c_client *client)
return 0;
}
static const struct si544_clk_desc clk_si544a_info = {
.xo_freq = SI544_XO_FREQ,
.max_freq = 1500000000,
};
static const struct si544_clk_desc clk_si544b_info = {
.xo_freq = SI544_XO_FREQ,
.max_freq = 800000000,
};
static const struct si544_clk_desc clk_si544c_info = {
.xo_freq = SI544_XO_FREQ,
.max_freq = 325000000,
};
static const struct si544_clk_desc clk_si549a_info = {
.xo_freq = SI549_XO_FREQ,
.max_freq = 1500000000,
};
static const struct si544_clk_desc clk_si549b_info = {
.xo_freq = SI549_XO_FREQ,
.max_freq = 800000000,
};
static const struct si544_clk_desc clk_si549c_info = {
.xo_freq = SI549_XO_FREQ,
.max_freq = 325000000,
};
static const struct i2c_device_id si544_id[] = {
{ "si544a", 1500000000 },
{ "si544b", 800000000 },
{ "si544c", 350000000 },
{ .name = "si544a", .driver_data = (kernel_ulong_t)&clk_si544a_info },
{ .name = "si544b", .driver_data = (kernel_ulong_t)&clk_si544b_info },
{ .name = "si544c", .driver_data = (kernel_ulong_t)&clk_si544c_info },
{ .name = "si549a", .driver_data = (kernel_ulong_t)&clk_si549a_info },
{ .name = "si549b", .driver_data = (kernel_ulong_t)&clk_si549b_info },
{ .name = "si549c", .driver_data = (kernel_ulong_t)&clk_si549c_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, si544_id);
static const struct of_device_id clk_si544_of_match[] = {
{ .compatible = "silabs,si544a", .data = (void *)1500000000 },
{ .compatible = "silabs,si544b", .data = (void *)800000000 },
{ .compatible = "silabs,si544c", .data = (void *)350000000 },
{ .compatible = "silabs,si544a", .data = &clk_si544a_info },
{ .compatible = "silabs,si544b", .data = &clk_si544b_info },
{ .compatible = "silabs,si544c", .data = &clk_si544c_info },
{ .compatible = "silabs,si549a", .data = &clk_si549a_info },
{ .compatible = "silabs,si549b", .data = &clk_si549b_info },
{ .compatible = "silabs,si549c", .data = &clk_si549c_info },
{ }
};
MODULE_DEVICE_TABLE(of, clk_si544_of_match);
+4 -4
View File
@@ -503,10 +503,10 @@ static const struct clk_si570_info clk_si590_info = {
};
static const struct i2c_device_id si570_id[] = {
{ "si570", (kernel_ulong_t)&clk_si570_info },
{ "si571", (kernel_ulong_t)&clk_si570_info },
{ "si598", (kernel_ulong_t)&clk_si590_info },
{ "si599", (kernel_ulong_t)&clk_si590_info },
{ .name = "si570", .driver_data = (kernel_ulong_t)&clk_si570_info },
{ .name = "si571", .driver_data = (kernel_ulong_t)&clk_si570_info },
{ .name = "si598", .driver_data = (kernel_ulong_t)&clk_si590_info },
{ .name = "si599", .driver_data = (kernel_ulong_t)&clk_si590_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, si570_id);
+8 -8
View File
@@ -1310,14 +1310,14 @@ static const struct vc5_chip_info idt_5p49v6975_info = {
};
static const struct i2c_device_id vc5_id[] = {
{ "5p49v5923", .driver_data = (kernel_ulong_t)&idt_5p49v5923_info },
{ "5p49v5925", .driver_data = (kernel_ulong_t)&idt_5p49v5925_info },
{ "5p49v5933", .driver_data = (kernel_ulong_t)&idt_5p49v5933_info },
{ "5p49v5935", .driver_data = (kernel_ulong_t)&idt_5p49v5935_info },
{ "5p49v60", .driver_data = (kernel_ulong_t)&idt_5p49v60_info },
{ "5p49v6901", .driver_data = (kernel_ulong_t)&idt_5p49v6901_info },
{ "5p49v6965", .driver_data = (kernel_ulong_t)&idt_5p49v6965_info },
{ "5p49v6975", .driver_data = (kernel_ulong_t)&idt_5p49v6975_info },
{ .name = "5p49v5923", .driver_data = (kernel_ulong_t)&idt_5p49v5923_info },
{ .name = "5p49v5925", .driver_data = (kernel_ulong_t)&idt_5p49v5925_info },
{ .name = "5p49v5933", .driver_data = (kernel_ulong_t)&idt_5p49v5933_info },
{ .name = "5p49v5935", .driver_data = (kernel_ulong_t)&idt_5p49v5935_info },
{ .name = "5p49v60", .driver_data = (kernel_ulong_t)&idt_5p49v60_info },
{ .name = "5p49v6901", .driver_data = (kernel_ulong_t)&idt_5p49v6901_info },
{ .name = "5p49v6965", .driver_data = (kernel_ulong_t)&idt_5p49v6965_info },
{ .name = "5p49v6975", .driver_data = (kernel_ulong_t)&idt_5p49v6975_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, vc5_id);
+3 -3
View File
@@ -1197,7 +1197,7 @@ static int vc7_probe(struct i2c_client *client)
if (ret) {
dev_err_probe(&client->dev, ret,
"unable to register output %d\n", i);
return ret;
goto err_clk;
}
switch (bank_src_map.type) {
@@ -1288,8 +1288,8 @@ static const struct regmap_config vc7_regmap_config = {
};
static const struct i2c_device_id vc7_i2c_id[] = {
{ "rc21008a", .driver_data = (kernel_ulong_t)&vc7_rc21008a_info },
{}
{ .name = "rc21008a", .driver_data = (kernel_ulong_t)&vc7_rc21008a_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, vc7_i2c_id);
+104 -8
View File
@@ -63,6 +63,57 @@ struct clk_parent_map {
int index;
};
/**
* struct clk_core - The internal state of a clk in the clk tree.
* @name: Unique name of the clk for identification.
* @ops: Pointer to hardware-specific operations for this clk.
* @hw: Pointer for traversing from a struct clk to its
* corresponding hardware-specific structure.
* @owner: Kernel module owning this clk (for reference counting).
* @dev: Device associated with this clk (optional)
* @rpm_node: Node for runtime power management list management.
* @of_node: Device tree node associated with this clk (if applicable)
* @parent: Pointer to the current parent in the clock tree.
* @parents: Array of possible parents (for muxes/selectable parents).
* @num_parents: Number of possible parents.
* @new_parent_index: Index of the new parent during parent change operations.
* @rate: Current cached clock rate (Hz).
* @req_rate: The last rate requested by a call to clk_set_rate(). It's
* initialized to clk_core->rate. It's also updated to
* clk_core->rate every time the clock is reparented, and
* when we're doing the orphan -> !orphan transition.
* @new_rate: New rate to be set during a rate change operation.
* @new_parent: Pointer to new parent during parent change. This is also
* used when a clk's rate is changed.
* @new_child: Pointer to new child during reparenting. This is also
* used when a clk's rate is changed.
* @flags: Clock property and capability flags. See
* `clk framework flags`.
* @orphan: True if this clk is currently orphaned.
* @rpm_enabled: True if runtime power management is enabled for this clk.
* @enable_count: Reference count of enables.
* @prepare_count: Reference count of prepares.
* @protect_count: Protection reference count against disable.
* @min_rate: Minimum supported clock rate (Hz).
* @max_rate: Maximum supported clock rate (Hz).
* @accuracy: Accuracy of the clock rate (parts per billion).
* @phase: Current phase (degrees).
* @duty: Current duty cycle configuration (as ratio: num/den).
* @children: All of the children of this clk.
* @child_node: Node for linking as a child in the parent's list.
* @hashtable_node: Node for hash table that allows fast clk lookup by name.
* @clks: All of the clk consumers registered.
* @notifier_count: Number of notifiers registered for this clk.
* @dentry: DebugFS entry for this clk.
* @debug_node: DebugFS node for this clk.
* @ref: Reference count for structure lifetime management.
*
* Managed by the clk framework. Clk providers and consumers do not interact
* with this structure directly. Instead, clk operations flow through the
* framework and the framework manipulates this structure to keep track of
* parent/child relationships, rate, enable state, etc.
*
*/
struct clk_core {
const char *name;
const struct clk_ops *ops;
@@ -882,6 +933,24 @@ int clk_hw_determine_rate_no_reparent(struct clk_hw *hw,
}
EXPORT_SYMBOL_GPL(clk_hw_determine_rate_no_reparent);
/**
* clk_determine_rate_noop - clk_ops::determine_rate noop implementation
* @hw: clk to determine rate on
* @req: rate request
*
* Noop determine rate for clocks where the rate rounding is handled by the
* firmware/hardware, or the clock is capable of any rate. The requested rate is
* passed through unchanged, and the actual rate will be learned via
* recalc_rate() after the rate is set.
*
* Returns: 0 always
*/
int clk_determine_rate_noop(struct clk_hw *hw, struct clk_rate_request *req)
{
return 0;
}
EXPORT_SYMBOL_GPL(clk_determine_rate_noop);
/*** clk api ***/
static void clk_core_rate_unprotect(struct clk_core *core)
@@ -1846,10 +1915,10 @@ static int __clk_notify(struct clk_core *core, unsigned long msg,
}
/**
* __clk_recalc_accuracies
* __clk_recalc_accuracies - recalculate all accuracies in the clk subtree
* @core: first clk in the subtree
*
* Walks the subtree of clks starting with clk and recalculates accuracies as
* Walks the subtree of clks starting with @core and recalculates accuracies as
* it goes. Note that if a clk does not implement the .recalc_accuracy
* callback then it is assumed that the clock will take on the accuracy of its
* parent.
@@ -1919,16 +1988,16 @@ static unsigned long clk_recalc(struct clk_core *core,
}
/**
* __clk_recalc_rates
* __clk_recalc_rates - recalculate all rates in the clk subtree
* @core: first clk in the subtree
* @update_req: Whether req_rate should be updated with the new rate
* @msg: notification type (see include/linux/clk.h)
*
* Walks the subtree of clks starting with clk and recalculates rates as it
* Walks the subtree of clks starting with @core and recalculates rates as it
* goes. Note that if a clk does not implement the .recalc_rate callback then
* it is assumed that the clock will take on the rate of its parent.
*
* clk_recalc_rates also propagates the POST_RATE_CHANGE notification,
* __clk_recalc_rates also propagates the POST_RATE_CHANGE notification,
* if necessary.
*/
static void __clk_recalc_rates(struct clk_core *core, bool update_req,
@@ -2191,14 +2260,14 @@ static int __clk_set_parent(struct clk_core *core, struct clk_core *parent,
}
/**
* __clk_speculate_rates
* __clk_speculate_rates - speculate all rates in the clk subtree
* @core: first clk in the subtree
* @parent_rate: the "future" rate of clk's parent
*
* Walks the subtree of clks starting with clk, speculating rates as it
* Walks the subtree of clks starting with @core, speculating rates as it
* goes and firing off PRE_RATE_CHANGE notifications as necessary.
*
* Unlike clk_recalc_rates, clk_speculate_rates exists only for sending
* Unlike __clk_recalc_rates, __clk_speculate_rates exists only for sending
* pre-rate change notifications and returns early if no clks in the
* subtree have subscribed to the notifications. Note that if a clk does not
* implement the .recalc_rate callback then it is assumed that the clock will
@@ -2774,6 +2843,33 @@ int clk_set_max_rate(struct clk *clk, unsigned long rate)
}
EXPORT_SYMBOL_GPL(clk_set_max_rate);
int clk_hw_set_spread_spectrum(struct clk_hw *hw, const struct clk_spread_spectrum *ss_conf)
{
struct clk_core *core;
int ret;
if (!hw)
return 0;
core = hw->core;
clk_prepare_lock();
ret = clk_pm_runtime_get(core);
if (ret)
goto fail;
if (core->ops->set_spread_spectrum)
ret = core->ops->set_spread_spectrum(hw, ss_conf);
clk_pm_runtime_put(core);
fail:
clk_prepare_unlock();
return ret;
}
EXPORT_SYMBOL_GPL(clk_hw_set_spread_spectrum);
/**
* clk_get_parent - return the parent of a clk
* @clk: the clk whose parent gets returned
+206 -8
View File
@@ -7,6 +7,7 @@
#include <linux/clk/clk-conf.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/units.h>
/* Needed for clk_hw_get_clk() */
#include "clk.h"
@@ -21,13 +22,14 @@
static const struct clk_ops empty_clk_ops = { };
#define DUMMY_CLOCK_INIT_RATE (42 * 1000 * 1000)
#define DUMMY_CLOCK_RATE_1 (142 * 1000 * 1000)
#define DUMMY_CLOCK_RATE_2 (242 * 1000 * 1000)
#define DUMMY_CLOCK_INIT_RATE (42 * HZ_PER_MHZ)
#define DUMMY_CLOCK_RATE_1 (142 * HZ_PER_MHZ)
#define DUMMY_CLOCK_RATE_2 (242 * HZ_PER_MHZ)
struct clk_dummy_context {
struct clk_hw hw;
unsigned long rate;
struct clk_spread_spectrum sscs;
};
static unsigned long clk_dummy_recalc_rate(struct clk_hw *hw,
@@ -83,6 +85,17 @@ static int clk_dummy_set_rate(struct clk_hw *hw,
return 0;
}
static int clk_dummy_set_spread_spectrum(struct clk_hw *hw,
const struct clk_spread_spectrum *ss_conf)
{
struct clk_dummy_context *ctx =
container_of(hw, struct clk_dummy_context, hw);
ctx->sscs = *ss_conf;
return 0;
}
static int clk_dummy_single_set_parent(struct clk_hw *hw, u8 index)
{
if (index >= clk_hw_get_num_parents(hw))
@@ -100,18 +113,21 @@ static const struct clk_ops clk_dummy_rate_ops = {
.recalc_rate = clk_dummy_recalc_rate,
.determine_rate = clk_dummy_determine_rate,
.set_rate = clk_dummy_set_rate,
.set_spread_spectrum = clk_dummy_set_spread_spectrum,
};
static const struct clk_ops clk_dummy_maximize_rate_ops = {
.recalc_rate = clk_dummy_recalc_rate,
.determine_rate = clk_dummy_maximize_rate,
.set_rate = clk_dummy_set_rate,
.set_spread_spectrum = clk_dummy_set_spread_spectrum,
};
static const struct clk_ops clk_dummy_minimize_rate_ops = {
.recalc_rate = clk_dummy_recalc_rate,
.determine_rate = clk_dummy_minimize_rate,
.set_rate = clk_dummy_set_rate,
.set_spread_spectrum = clk_dummy_set_spread_spectrum,
};
static const struct clk_ops clk_dummy_single_parent_ops = {
@@ -2232,7 +2248,7 @@ static void
clk_leaf_mux_set_rate_parent_determine_rate_test_case_to_desc(
const struct clk_leaf_mux_set_rate_parent_determine_rate_test_case *t, char *desc)
{
strcpy(desc, t->desc);
strscpy(desc, t->desc, KUNIT_PARAM_DESC_SIZE);
}
static const struct clk_leaf_mux_set_rate_parent_determine_rate_test_case
@@ -2644,7 +2660,7 @@ static void
clk_register_clk_parent_data_test_case_to_desc(
const struct clk_register_clk_parent_data_test_case *t, char *desc)
{
strcpy(desc, t->desc);
strscpy(desc, t->desc, KUNIT_PARAM_DESC_SIZE);
}
static const struct clk_register_clk_parent_data_test_case
@@ -3097,6 +3113,7 @@ struct clk_assigned_rates_context {
* @overlay_end: Pointer to end of DT overlay to apply for test
* @rate0: Initial rate of first clk
* @rate1: Initial rate of second clk
* @sscs: Initial spread spectrum settings
* @consumer_test: true if a consumer is being tested
*/
struct clk_assigned_rates_test_param {
@@ -3105,6 +3122,7 @@ struct clk_assigned_rates_test_param {
u8 *overlay_end;
unsigned long rate0;
unsigned long rate1;
struct clk_spread_spectrum sscs;
bool consumer_test;
};
@@ -3116,7 +3134,7 @@ static void
clk_assigned_rates_register_clk(struct kunit *test,
struct clk_dummy_context *ctx,
struct device_node *np, const char *name,
unsigned long rate)
unsigned long rate, const struct clk_spread_spectrum *sscs)
{
struct clk_init_data init = { };
@@ -3124,6 +3142,7 @@ clk_assigned_rates_register_clk(struct kunit *test,
init.ops = &clk_dummy_rate_ops;
ctx->hw.init = &init;
ctx->rate = rate;
ctx->sscs = *sscs;
KUNIT_ASSERT_EQ(test, 0, of_clk_hw_register_kunit(test, np, &ctx->hw));
KUNIT_ASSERT_EQ(test, ctx->rate, rate);
@@ -3167,14 +3186,16 @@ static int clk_assigned_rates_test_init(struct kunit *test)
KUNIT_ASSERT_LT(test, clk_cells, 2);
clk_assigned_rates_register_clk(test, &ctx->clk0, np,
"test_assigned_rate0", test_param->rate0);
"test_assigned_rate0", test_param->rate0,
&test_param->sscs);
if (clk_cells == 0) {
KUNIT_ASSERT_EQ(test, 0,
of_clk_add_hw_provider_kunit(test, np, of_clk_hw_simple_get,
&ctx->clk0.hw));
} else if (clk_cells == 1) {
clk_assigned_rates_register_clk(test, &ctx->clk1, np,
"test_assigned_rate1", test_param->rate1);
"test_assigned_rate1", test_param->rate1,
&test_param->sscs);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test,
data = kunit_kzalloc(test, struct_size(data, hws, 2), GFP_KERNEL));
@@ -3403,6 +3424,182 @@ static struct kunit_suite clk_assigned_rates_suite = {
.init = clk_assigned_rates_test_init,
};
OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_one);
OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_one_consumer);
OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_multiple);
OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_multiple_consumer);
OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_without);
OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_without_consumer);
OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_zero);
OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_zero_consumer);
OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_null);
OF_OVERLAY_DECLARE(kunit_clk_assigned_sscs_null_consumer);
static void clk_assigned_sscs_assigns_one(struct kunit *test)
{
struct clk_assigned_rates_context *ctx = test->priv;
KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.modfreq_hz, ASSIGNED_SSCS_0_MODFREQ);
KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.spread_bp, ASSIGNED_SSCS_0_SPREAD);
KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.method, ASSIGNED_SSCS_0_METHOD);
}
/* Test cases that assign sscs for one clk */
static const struct clk_assigned_rates_test_param clk_assigned_sscs_assigns_one_test_params[] = {
{
/*
* Test that a single cell assigned-clock-sscs property
* assigns the sscs when the property is in the provider.
*/
.desc = "provider assigns",
TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_one),
},
{
/*
* Test that a single cell assigned-clock-sscs property
* assigns the sscs when the property is in the consumer.
*/
.desc = "consumer assigns",
TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_one_consumer),
.consumer_test = true,
},
};
KUNIT_ARRAY_PARAM_DESC(clk_assigned_sscs_assigns_one,
clk_assigned_sscs_assigns_one_test_params, desc)
static void clk_assigned_sscs_assigns_multiple(struct kunit *test)
{
struct clk_assigned_rates_context *ctx = test->priv;
KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.modfreq_hz, ASSIGNED_SSCS_0_MODFREQ);
KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.spread_bp, ASSIGNED_SSCS_0_SPREAD);
KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.method, ASSIGNED_SSCS_0_METHOD);
KUNIT_EXPECT_EQ(test, ctx->clk1.sscs.modfreq_hz, ASSIGNED_SSCS_1_MODFREQ);
KUNIT_EXPECT_EQ(test, ctx->clk1.sscs.spread_bp, ASSIGNED_SSCS_1_SPREAD);
KUNIT_EXPECT_EQ(test, ctx->clk1.sscs.method, ASSIGNED_SSCS_1_METHOD);
}
/* Test cases that assign sscs for multiple clks */
static const
struct clk_assigned_rates_test_param clk_assigned_sscs_assigns_multiple_test_params[] = {
{
/*
* Test that a multiple cell assigned-clock-sscs property
* assigns the sscs when the property is in the provider.
*/
.desc = "provider assigns",
TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_multiple),
},
{
/*
* Test that a multiple cell assigned-clock-sscs property
* assigns the sscs when the property is in the consumer.
*/
.desc = "consumer assigns",
TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_multiple_consumer),
.consumer_test = true,
},
};
KUNIT_ARRAY_PARAM_DESC(clk_assigned_sscs_assigns_multiple,
clk_assigned_sscs_assigns_multiple_test_params,
desc)
static void clk_assigned_sscs_skips(struct kunit *test)
{
struct clk_assigned_rates_context *ctx = test->priv;
const struct clk_assigned_rates_test_param *test_param = test->param_value;
KUNIT_EXPECT_NE(test, ctx->clk0.sscs.modfreq_hz, ASSIGNED_SSCS_0_MODFREQ);
KUNIT_EXPECT_NE(test, ctx->clk0.sscs.spread_bp, ASSIGNED_SSCS_0_SPREAD);
KUNIT_EXPECT_NE(test, ctx->clk0.sscs.method, ASSIGNED_SSCS_0_METHOD);
KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.modfreq_hz, test_param->sscs.modfreq_hz);
KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.spread_bp, test_param->sscs.spread_bp);
KUNIT_EXPECT_EQ(test, ctx->clk0.sscs.method, test_param->sscs.method);
}
/* Test cases that skip changing the sscs due to malformed DT */
static const struct clk_assigned_rates_test_param clk_assigned_sscs_skips_test_params[] = {
{
/*
* Test that an assigned-clock-sscs property without an assigned-clocks
* property fails when the property is in the provider.
*/
.desc = "provider missing assigned-clocks",
TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_without),
.sscs = {50000, 60000, 3},
},
{
/*
* Test that an assigned-clock-sscs property without an assigned-clocks
* property fails when the property is in the consumer.
*/
.desc = "consumer missing assigned-clocks",
TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_without_consumer),
.sscs = {50000, 60000, 3},
.consumer_test = true,
},
{
/*
* Test that an assigned-clock-sscs property of zero doesn't
* set sscs when the property is in the provider.
*/
.desc = "provider assigned-clock-sscs of zero",
TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_zero),
.sscs = {50000, 60000, 3},
},
{
/*
* Test that an assigned-clock-sscs property of zero doesn't
* set sscs when the property is in the consumer.
*/
.desc = "consumer assigned-clock-sscs of zero",
TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_zero_consumer),
.sscs = {50000, 60000, 3},
.consumer_test = true,
},
{
/*
* Test that an assigned-clocks property with a null phandle
* doesn't set sscs when the property is in the provider.
*/
.desc = "provider assigned-clocks null phandle",
TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_null),
.sscs = {50000, 60000, 3},
},
{
/*
* Test that an assigned-clocks property with a null phandle
* doesn't set sscs when the property is in the consumer.
*/
.desc = "consumer assigned-clocks null phandle",
TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_null_consumer),
.sscs = {50000, 60000, 3},
.consumer_test = true,
},
};
KUNIT_ARRAY_PARAM_DESC(clk_assigned_sscs_skips,
clk_assigned_sscs_skips_test_params,
desc)
static struct kunit_case clk_assigned_sscs_test_cases[] = {
KUNIT_CASE_PARAM(clk_assigned_sscs_assigns_one,
clk_assigned_sscs_assigns_one_gen_params),
KUNIT_CASE_PARAM(clk_assigned_sscs_assigns_multiple,
clk_assigned_sscs_assigns_multiple_gen_params),
KUNIT_CASE_PARAM(clk_assigned_sscs_skips,
clk_assigned_sscs_skips_gen_params),
{}
};
/*
* Test suite for assigned-clock-sscs DT property.
*/
static struct kunit_suite clk_assigned_sscs_suite = {
.name = "clk_assigned_sscs",
.test_cases = clk_assigned_sscs_test_cases,
.init = clk_assigned_rates_test_init,
};
static const struct clk_init_data clk_hw_get_dev_of_node_init_data = {
.name = "clk_hw_get_dev_of_node",
.ops = &empty_clk_ops,
@@ -3544,6 +3741,7 @@ static struct kunit_suite clk_hw_get_dev_of_node_test_suite = {
kunit_test_suites(
&clk_assigned_rates_suite,
&clk_assigned_sscs_suite,
&clk_hw_get_dev_of_node_test_suite,
&clk_leaf_mux_set_rate_parent_test_suite,
&clk_test_suite,
+13
View File
@@ -13,3 +13,16 @@ config COMMON_CLK_EIC7700
SoC. The clock controller generates and supplies clocks to various
peripherals within the SoC.
Say yes here to support the clock controller on the EIC7700 SoC.
config COMMON_CLK_EIC7700_HSP
tristate "EIC7700 HSP Clock Driver"
depends on ARCH_ESWIN || COMPILE_TEST
select AUXILIARY_BUS
select COMMON_CLK_EIC7700
select RESET_EIC7700_HSP if RESET_CONTROLLER
select REGMAP_MMIO
help
This driver provides support for clock controller on ESWIN EIC7700
HSP. The clock controller generates and supplies clocks to high
speed peripherals within the SoC.
Say yes here to support the clock controller on the EIC7700 HSP.
+1
View File
@@ -6,3 +6,4 @@
obj-$(CONFIG_COMMON_CLK_ESWIN) += clk.o
obj-$(CONFIG_COMMON_CLK_EIC7700) += clk-eic7700.o
obj-$(CONFIG_COMMON_CLK_EIC7700_HSP) += clk-eic7700-hsp.o
+345
View File
@@ -0,0 +1,345 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2026, Beijing ESWIN Computing Technology Co., Ltd..
* All rights reserved.
*
* ESWIN EIC7700 HSP Clock Driver
*
* Authors: Xuyang Dong <dongxuyang@eswincomputing.com>
*/
#include <linux/auxiliary_bus.h>
#include <linux/clk-provider.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <dt-bindings/clock/eswin,eic7700-hspcrg.h>
#include "common.h"
#define EIC7700_HSP_SATA_REG 0x300
#define EIC7700_HSP_MSHC0_REG 0x510
#define EIC7700_HSP_MSHC1_REG 0x610
#define EIC7700_HSP_MSHC2_REG 0x710
#define EIC7700_HSP_USB0_REG 0x800
#define EIC7700_HSP_USB0_REF_REG 0x83c
#define EIC7700_HSP_USB1_REG 0x900
#define EIC7700_HSP_USB1_REF_REG 0x93c
#define USB_REF_XTAL24M 0x2a
#define EIC7700_HSP_NR_CLKS (EIC7700_HSP_CLK_GATE_SATA + 1)
struct eic7700_hsp_clk_gate {
struct clk_hw hw;
unsigned int id;
struct regmap *regmap;
unsigned int reg;
unsigned int ref_reg;
const char *name;
const struct clk_parent_data *parent_data;
unsigned long flags;
unsigned int offset;
unsigned int ref_offset;
u8 bit_idx;
};
static const struct regmap_config eic7700_hsp_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.max_register = 0x1ffc,
.reg_stride = 4,
.fast_io = true,
.use_raw_spinlock = true,
};
static inline struct eic7700_hsp_clk_gate *to_gate_clk(struct clk_hw *hw)
{
return container_of(hw, struct eic7700_hsp_clk_gate, hw);
}
#define EIC7700_HSP_GATE(_id, _name, _pdata, _flags, _offset, _idx, \
_ref_offset) \
{ \
.id = _id, \
.name = _name, \
.parent_data = _pdata, \
.flags = _flags, \
.offset = _offset, \
.ref_offset = _ref_offset, \
.bit_idx = _idx, \
}
static void hsp_clk_gate_endisable(struct clk_hw *hw, bool enable)
{
struct eic7700_hsp_clk_gate *gate = to_gate_clk(hw);
if (enable) {
/*
* Hardware bug: The USB reference clock must be 24MHz.
* The default register value after reset is invalid.
* Workaround: Rewrite the correct value before enabling
* the USB gate clock.
*/
regmap_update_bits(gate->regmap, gate->ref_reg, 0x3f,
USB_REF_XTAL24M);
}
regmap_assign_bits(gate->regmap, gate->reg, BIT(gate->bit_idx), enable);
}
static int hsp_clk_gate_enable(struct clk_hw *hw)
{
hsp_clk_gate_endisable(hw, true);
return 0;
}
static void hsp_clk_gate_disable(struct clk_hw *hw)
{
hsp_clk_gate_endisable(hw, false);
}
static int hsp_clk_gate_is_enabled(struct clk_hw *hw)
{
struct eic7700_hsp_clk_gate *gate = to_gate_clk(hw);
unsigned int val;
int ret;
ret = regmap_read(gate->regmap, gate->reg, &val);
if (ret != 0)
return ret;
return !!(val & BIT(gate->bit_idx));
}
static const struct clk_ops hsp_clk_gate_ops = {
.enable = hsp_clk_gate_enable,
.disable = hsp_clk_gate_disable,
.is_enabled = hsp_clk_gate_is_enabled,
};
static struct clk_hw *
hsp_clk_register_gate(struct device *dev, unsigned int id, const char *name,
const struct clk_parent_data *parent_data,
unsigned long flags, struct regmap *regmap,
unsigned int reg, unsigned int ref_reg, u8 bit_idx)
{
struct eic7700_hsp_clk_gate *gate;
struct clk_init_data init = {};
struct clk_hw *hw;
int ret;
gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL);
if (!gate)
return ERR_PTR(-ENOMEM);
init.name = name;
init.ops = &hsp_clk_gate_ops;
init.flags = flags;
init.parent_data = parent_data;
init.num_parents = 1;
gate->id = id;
gate->regmap = regmap;
gate->reg = reg;
gate->ref_reg = ref_reg;
gate->bit_idx = bit_idx;
gate->hw.init = &init;
hw = &gate->hw;
ret = devm_clk_hw_register(dev, hw);
if (ret)
hw = ERR_PTR(ret);
return hw;
}
static const struct clk_parent_data hsp_cfg[] = {
{ .index = 0 }
};
static const struct clk_parent_data hsp_mmc[] = {
{ .index = 1 }
};
static const struct clk_parent_data hsp_usb_sata[] = {
{ .index = 2 }
};
static struct eswin_fixed_factor_clock eic7700_hsp_factor_clks[] = {
ESWIN_FACTOR(EIC7700_HSP_CLK_FAC_CFG_DIV2, "factor_hsp_cfg_div2",
hsp_cfg, 1, 2, 0),
ESWIN_FACTOR(EIC7700_HSP_CLK_FAC_CFG_DIV4, "factor_hsp_cfg_div4",
hsp_cfg, 1, 4, 0),
ESWIN_FACTOR(EIC7700_HSP_CLK_FAC_MMC_DIV10, "factor_hsp_mmc_div10",
hsp_mmc, 1, 10, 0),
};
static struct eswin_gate_clock eic7700_hsp_gate_clks[] = {
ESWIN_GATE(EIC7700_HSP_CLK_GATE_SATA, "gate_clk_hsp_sata", hsp_usb_sata,
CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
EIC7700_HSP_SATA_REG, 28, 0),
ESWIN_GATE(EIC7700_HSP_CLK_GATE_MSHC0_TMR, "gate_clk_hsp_mshc0_tmr",
hsp_mmc, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
EIC7700_HSP_MSHC0_REG, 8, 0),
ESWIN_GATE(EIC7700_HSP_CLK_GATE_MSHC1_TMR, "gate_clk_hsp_mshc1_tmr",
hsp_mmc, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
EIC7700_HSP_MSHC1_REG, 8, 0),
ESWIN_GATE(EIC7700_HSP_CLK_GATE_MSHC2_TMR, "gate_clk_hsp_mshc2_tmr",
hsp_mmc, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
EIC7700_HSP_MSHC2_REG, 8, 0),
};
static struct eic7700_hsp_clk_gate eic7700_hsp_spec_gate_clks[] = {
EIC7700_HSP_GATE(EIC7700_HSP_CLK_GATE_USB0, "gate_clk_hsp_usb0",
hsp_usb_sata, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
EIC7700_HSP_USB0_REG, 28, EIC7700_HSP_USB0_REF_REG),
EIC7700_HSP_GATE(EIC7700_HSP_CLK_GATE_USB1, "gate_clk_hsp_usb1",
hsp_usb_sata, CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
EIC7700_HSP_USB1_REG, 28, EIC7700_HSP_USB1_REF_REG),
};
static const struct clk_parent_data mux_mmc_3mux1_p[] = {
{ .fw_name = "cfg" },
{ .hw = &eic7700_hsp_factor_clks[0].hw },
{ .hw = &eic7700_hsp_factor_clks[1].hw },
};
static const struct clk_parent_data mux_mmc_2mux1_p[] = {
{ .fw_name = "mmc" },
{ .hw = &eic7700_hsp_factor_clks[2].hw },
};
static u32 mux_mmc_3mux1_tbl[] = { 0x0, 0x1, 0x3 };
static struct eswin_mux_clock eic7700_hsp_mux_clks[] = {
ESWIN_MUX_TBL(EIC7700_HSP_CLK_MUX_EMMC_3MUX1, "mux_hsp_emmc_3mux1",
mux_mmc_3mux1_p, ARRAY_SIZE(mux_mmc_3mux1_p),
CLK_SET_RATE_PARENT, EIC7700_HSP_MSHC0_REG, 16, 2, 0,
mux_mmc_3mux1_tbl),
ESWIN_MUX_TBL(EIC7700_HSP_CLK_MUX_SD0_3MUX1, "mux_hsp_sd0_3mux1",
mux_mmc_3mux1_p, ARRAY_SIZE(mux_mmc_3mux1_p),
CLK_SET_RATE_PARENT, EIC7700_HSP_MSHC1_REG, 16, 2, 0,
mux_mmc_3mux1_tbl),
ESWIN_MUX_TBL(EIC7700_HSP_CLK_MUX_SD1_3MUX1, "mux_hsp_sd1_3mux1",
mux_mmc_3mux1_p, ARRAY_SIZE(mux_mmc_3mux1_p),
CLK_SET_RATE_PARENT, EIC7700_HSP_MSHC2_REG, 16, 2, 0,
mux_mmc_3mux1_tbl),
ESWIN_MUX(EIC7700_HSP_CLK_MUX_EMMC_CQE_2MUX1, "mux_hsp_emmc_cqe_2mux1",
mux_mmc_2mux1_p, ARRAY_SIZE(mux_mmc_2mux1_p),
CLK_SET_RATE_PARENT, EIC7700_HSP_MSHC0_REG, 0, 1, 0),
ESWIN_MUX(EIC7700_HSP_CLK_MUX_SD0_CQE_2MUX1, "mux_hsp_sd0_cqe_2mux1",
mux_mmc_2mux1_p, ARRAY_SIZE(mux_mmc_2mux1_p),
CLK_SET_RATE_PARENT, EIC7700_HSP_MSHC1_REG, 0, 1, 0),
ESWIN_MUX(EIC7700_HSP_CLK_MUX_SD1_CQE_2MUX1, "mux_hsp_sd1_cqe_2mux1",
mux_mmc_2mux1_p, ARRAY_SIZE(mux_mmc_2mux1_p),
CLK_SET_RATE_PARENT, EIC7700_HSP_MSHC2_REG, 0, 1, 0),
};
static struct eswin_clk_info eic7700_hsp_clks[] = {
ESWIN_GATE_TYPE(EIC7700_HSP_CLK_GATE_EMMC, "gate_clk_hsp_emmc",
EIC7700_HSP_CLK_MUX_EMMC_3MUX1,
CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
EIC7700_HSP_MSHC0_REG, 24, 0),
ESWIN_GATE_TYPE(EIC7700_HSP_CLK_GATE_SD0, "gate_clk_hsp_sd0",
EIC7700_HSP_CLK_MUX_SD0_3MUX1,
CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
EIC7700_HSP_MSHC1_REG, 24, 0),
ESWIN_GATE_TYPE(EIC7700_HSP_CLK_GATE_SD1, "gate_clk_hsp_sd1",
EIC7700_HSP_CLK_MUX_SD1_3MUX1,
CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
EIC7700_HSP_MSHC2_REG, 24, 0),
};
static int eic7700_hsp_clk_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct auxiliary_device *adev;
struct eswin_clock_data *data;
struct regmap *regmap;
struct clk_hw *hw;
int i, ret;
data = eswin_clk_init(pdev, EIC7700_HSP_NR_CLKS);
if (IS_ERR(data))
return dev_err_probe(dev, PTR_ERR(data),
"failed to get clk data!\n");
regmap = devm_regmap_init_mmio(dev, data->base,
&eic7700_hsp_regmap_config);
if (IS_ERR(regmap))
return dev_err_probe(dev, PTR_ERR(regmap),
"failed to get regmap!\n");
ret = eswin_clk_register_fixed_factor(dev, eic7700_hsp_factor_clks,
ARRAY_SIZE(eic7700_hsp_factor_clks),
data);
if (ret)
return dev_err_probe(dev, ret,
"failed to register fixed factor clock\n");
ret = eswin_clk_register_gate(dev, eic7700_hsp_gate_clks,
ARRAY_SIZE(eic7700_hsp_gate_clks), data);
if (ret)
return dev_err_probe(dev, ret,
"failed to register gate clock\n");
ret = eswin_clk_register_mux(dev, eic7700_hsp_mux_clks,
ARRAY_SIZE(eic7700_hsp_mux_clks),
data);
if (ret)
return dev_err_probe(dev, ret,
"failed to register mux clock\n");
ret = eswin_clk_register_clks(dev, eic7700_hsp_clks,
ARRAY_SIZE(eic7700_hsp_clks), data);
if (ret)
return dev_err_probe(dev, ret,
"failed to register clock\n");
for (i = 0; i < ARRAY_SIZE(eic7700_hsp_spec_gate_clks); i++) {
struct eic7700_hsp_clk_gate *gate;
gate = &eic7700_hsp_spec_gate_clks[i];
hw = hsp_clk_register_gate(dev, gate->id, gate->name,
gate->parent_data, gate->flags,
regmap, gate->offset,
gate->ref_offset, gate->bit_idx);
if (IS_ERR(hw))
return dev_err_probe(dev, PTR_ERR(hw),
"failed to register gate clock\n");
data->clk_data.hws[gate->id] = hw;
}
ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
&data->clk_data);
if (ret)
return dev_err_probe(dev, ret, "add clk provider failed\n");
adev = devm_auxiliary_device_create(dev, "hsp-reset", NULL);
if (!adev)
return dev_err_probe(dev, -ENODEV,
"register hsp-reset device failed\n");
return 0;
}
static const struct of_device_id eic7700_hsp_clock_dt_ids[] = {
{ .compatible = "eswin,eic7700-hspcrg", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, eic7700_hsp_clock_dt_ids);
static struct platform_driver eic7700_hsp_clock_driver = {
.probe = eic7700_hsp_clk_probe,
.driver = {
.name = "eic7700-hsp-clock",
.of_match_table = eic7700_hsp_clock_dt_ids,
},
};
module_platform_driver(eic7700_hsp_clock_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Xuyang Dong <dongxuyang@eswincomputing.com>");
MODULE_DESCRIPTION("ESWIN EIC7700 HSP clock controller driver");
+2 -1
View File
@@ -791,7 +791,8 @@ static struct eswin_clk_info eic7700_clks[] = {
EIC7700_CLK_MUX_CPU_ROOT_3MUX1_GFREE,
CLK_SET_RATE_PARENT, EIC7700_REG_OFFSET_U84, 27, 0),
ESWIN_GATE_TYPE(EIC7700_CLK_GATE_NOC_NSP_CLK, "gate_noc_nsp_clk",
EIC7700_CLK_DIV_NOC_NSP_DYNM, CLK_SET_RATE_PARENT,
EIC7700_CLK_DIV_NOC_NSP_DYNM,
CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
EIC7700_REG_OFFSET_NOC, 31, 0),
ESWIN_GATE_TYPE(EIC7700_CLK_GATE_BOOTSPI, "gate_clk_bootspi",
EIC7700_CLK_MUX_BOOTSPI_CLK_2MUX1_GFREE,
+2 -2
View File
@@ -204,7 +204,7 @@ int eswin_clk_register_pll(struct device *dev, struct eswin_pll_clock *clks,
int nums, struct eswin_clock_data *data)
{
struct eswin_clk_pll *p_clk = NULL;
struct clk_init_data init;
struct clk_init_data init = {};
struct clk_hw *clk_hw;
int i, ret;
@@ -419,7 +419,7 @@ struct clk_hw *eswin_register_clkdiv(struct device *dev, unsigned int id,
unsigned long priv_flag, spinlock_t *lock)
{
struct eswin_divider_clock *dclk;
struct clk_init_data init;
struct clk_init_data init = {};
struct clk_hw *clk_hw;
int ret;
+14
View File
@@ -1,8 +1,13 @@
# SPDX-License-Identifier: GPL-2.0-only
config COMMON_CLK_HISI
bool
default ARCH_HISI
config COMMON_CLK_HI3516CV300
tristate "HI3516CV300 Clock Driver"
depends on ARCH_HISI || COMPILE_TEST
select RESET_HISI
select COMMON_CLK_HISI
default ARCH_HISI
help
Build the clock driver for hi3516cv300.
@@ -11,6 +16,7 @@ config COMMON_CLK_HI3519
tristate "Hi3519 Clock Driver"
depends on ARCH_HISI || COMPILE_TEST
select RESET_HISI
select COMMON_CLK_HISI
default ARCH_HISI
help
Build the clock driver for hi3519.
@@ -19,6 +25,7 @@ config COMMON_CLK_HI3559A
bool "Hi3559A Clock Driver"
depends on ARCH_HISI || COMPILE_TEST
select RESET_HISI
select COMMON_CLK_HISI
default ARCH_HISI
help
Build the clock driver for hi3559a.
@@ -26,6 +33,7 @@ config COMMON_CLK_HI3559A
config COMMON_CLK_HI3660
bool "Hi3660 Clock Driver"
depends on ARCH_HISI || COMPILE_TEST
select COMMON_CLK_HISI
default ARCH_HISI
help
Build the clock driver for hi3660.
@@ -33,6 +41,7 @@ config COMMON_CLK_HI3660
config COMMON_CLK_HI3670
bool "Hi3670 Clock Driver"
depends on ARCH_HISI || COMPILE_TEST
select COMMON_CLK_HISI
default ARCH_HISI
help
Build the clock driver for hi3670.
@@ -41,6 +50,7 @@ config COMMON_CLK_HI3798CV200
tristate "Hi3798CV200 Clock Driver"
depends on ARCH_HISI || COMPILE_TEST
select RESET_HISI
select COMMON_CLK_HISI
default ARCH_HISI
help
Build the clock driver for hi3798cv200.
@@ -48,6 +58,7 @@ config COMMON_CLK_HI3798CV200
config COMMON_CLK_HI6220
bool "Hi6220 Clock Driver"
depends on ARCH_HISI || COMPILE_TEST
select COMMON_CLK_HISI
default ARCH_HISI
help
Build the Hisilicon Hi6220 clock driver based on the common clock framework.
@@ -55,6 +66,7 @@ config COMMON_CLK_HI6220
config RESET_HISI
bool "HiSilicon Reset Controller Driver"
depends on ARCH_HISI || COMPILE_TEST
select COMMON_CLK_HISI
select RESET_CONTROLLER
help
Build reset controller driver for HiSilicon device chipsets.
@@ -63,6 +75,7 @@ config STUB_CLK_HI6220
bool "Hi6220 Stub Clock Driver" if EXPERT
depends on (COMMON_CLK_HI6220 || COMPILE_TEST)
depends on MAILBOX
select COMMON_CLK_HISI
default COMMON_CLK_HI6220
help
Build the Hisilicon Hi6220 stub clock driver.
@@ -71,6 +84,7 @@ config STUB_CLK_HI3660
bool "Hi3660 Stub Clock Driver" if EXPERT
depends on (COMMON_CLK_HI3660 || COMPILE_TEST)
depends on MAILBOX
select COMMON_CLK_HISI
default COMMON_CLK_HI3660
help
Build the Hisilicon Hi3660 stub clock driver.
+4 -18
View File
@@ -67,16 +67,6 @@ static unsigned long hi3660_stub_clk_recalc_rate(struct clk_hw *hw,
return stub_clk->rate;
}
static int hi3660_stub_clk_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
/*
* LPM3 handles rate rounding so just return whatever
* rate is requested.
*/
return 0;
}
static int hi3660_stub_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
@@ -97,7 +87,7 @@ static int hi3660_stub_clk_set_rate(struct clk_hw *hw, unsigned long rate,
static const struct clk_ops hi3660_stub_clk_ops = {
.recalc_rate = hi3660_stub_clk_recalc_rate,
.determine_rate = hi3660_stub_clk_determine_rate,
.determine_rate = clk_determine_rate_noop,
.set_rate = hi3660_stub_clk_set_rate,
};
@@ -124,7 +114,6 @@ static struct clk_hw *hi3660_stub_clk_hw_get(struct of_phandle_args *clkspec,
static int hi3660_stub_clk_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *res;
unsigned int i;
int ret;
@@ -139,12 +128,9 @@ static int hi3660_stub_clk_probe(struct platform_device *pdev)
if (IS_ERR(stub_clk_chan.mbox))
return PTR_ERR(stub_clk_chan.mbox);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -EINVAL;
freq_reg = devm_ioremap(dev, res->start, resource_size(res));
if (!freq_reg)
return -ENOMEM;
freq_reg = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(freq_reg))
return PTR_ERR(freq_reg);
freq_reg += HI3660_STUB_CLOCK_DATA;
+1 -1
View File
@@ -91,7 +91,7 @@ struct hisi_reset_controller *hisi_reset_init(struct platform_device *pdev)
{
struct hisi_reset_controller *rstc;
rstc = devm_kmalloc(&pdev->dev, sizeof(*rstc), GFP_KERNEL);
rstc = devm_kzalloc(&pdev->dev, sizeof(*rstc), GFP_KERNEL);
if (!rstc)
return NULL;
+3 -21
View File
@@ -262,23 +262,6 @@ static unsigned long clk_scu_recalc_rate(struct clk_hw *hw,
return le32_to_cpu(msg.data.resp.rate);
}
/*
* clk_scu_determine_rate - Returns the closest rate for a SCU clock
* @hw: clock to round rate for
* @req: clock rate request
*
* Returns 0 on success, a negative error on failure
*/
static int clk_scu_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
/*
* Assume we support all the requested rate and let the SCU firmware
* to handle the left work
*/
return 0;
}
static int clk_scu_atf_set_cpu_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
@@ -436,7 +419,7 @@ static void clk_scu_unprepare(struct clk_hw *hw)
static const struct clk_ops clk_scu_ops = {
.recalc_rate = clk_scu_recalc_rate,
.determine_rate = clk_scu_determine_rate,
.determine_rate = clk_determine_rate_noop,
.set_rate = clk_scu_set_rate,
.get_parent = clk_scu_get_parent,
.set_parent = clk_scu_set_parent,
@@ -446,7 +429,7 @@ static const struct clk_ops clk_scu_ops = {
static const struct clk_ops clk_scu_cpu_ops = {
.recalc_rate = clk_scu_recalc_rate,
.determine_rate = clk_scu_determine_rate,
.determine_rate = clk_determine_rate_noop,
.set_rate = clk_scu_atf_set_cpu_rate,
.prepare = clk_scu_prepare,
.unprepare = clk_scu_unprepare,
@@ -454,7 +437,7 @@ static const struct clk_ops clk_scu_cpu_ops = {
static const struct clk_ops clk_scu_pi_ops = {
.recalc_rate = clk_scu_recalc_rate,
.determine_rate = clk_scu_determine_rate,
.determine_rate = clk_determine_rate_noop,
.set_rate = clk_scu_set_rate,
};
@@ -475,7 +458,6 @@ struct clk_hw *__imx_clk_scu(struct device *dev, const char *name,
clk->clk_type = clk_type;
init.name = name;
init.ops = &clk_scu_ops;
if (rsrc_id == IMX_SC_R_A35 || rsrc_id == IMX_SC_R_A53 || rsrc_id == IMX_SC_R_A72)
init.ops = &clk_scu_cpu_ops;
else if (rsrc_id == IMX_SC_R_PI_0_PLL)
+10
View File
@@ -1,8 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <dt-bindings/clock/clock.h>
#ifndef _KUNIT_CLK_ASSIGNED_RATES_H
#define _KUNIT_CLK_ASSIGNED_RATES_H
#define ASSIGNED_RATES_0_RATE 1600000
#define ASSIGNED_RATES_1_RATE 9700000
#define ASSIGNED_SSCS_0_MODFREQ 10000
#define ASSIGNED_SSCS_0_SPREAD 30000
#define ASSIGNED_SSCS_0_METHOD CLK_SSC_CENTER_SPREAD
#define ASSIGNED_SSCS_1_MODFREQ 20000
#define ASSIGNED_SSCS_1_SPREAD 40000
#define ASSIGNED_SSCS_1_METHOD CLK_SSC_UP_SPREAD
#endif
@@ -12,5 +12,11 @@
<&clk 1>;
assigned-clock-rates-u64 = /bits/ 64 <ASSIGNED_RATES_0_RATE>,
/bits/ 64 <ASSIGNED_RATES_1_RATE>;
assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
ASSIGNED_SSCS_0_SPREAD
ASSIGNED_SSCS_0_METHOD>,
<ASSIGNED_SSCS_1_MODFREQ
ASSIGNED_SSCS_1_SPREAD
ASSIGNED_SSCS_1_METHOD>;
};
};
@@ -16,5 +16,11 @@
<&clk 1>;
assigned-clock-rates-u64 = /bits/ 64 <ASSIGNED_RATES_0_RATE>,
/bits/ 64 <ASSIGNED_RATES_1_RATE>;
assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
ASSIGNED_SSCS_0_SPREAD
ASSIGNED_SSCS_0_METHOD>,
<ASSIGNED_SSCS_1_MODFREQ
ASSIGNED_SSCS_1_SPREAD
ASSIGNED_SSCS_1_METHOD>;
};
};
@@ -10,5 +10,8 @@
#clock-cells = <0>;
assigned-clocks = <&clk>;
assigned-clock-rates-u64 = /bits/ 64 <ASSIGNED_RATES_0_RATE>;
assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
ASSIGNED_SSCS_0_SPREAD
ASSIGNED_SSCS_0_METHOD>;
};
};
@@ -14,5 +14,8 @@
compatible = "test,clk-consumer";
assigned-clocks = <&clk>;
assigned-clock-rates-u64 = /bits/ 64 <ASSIGNED_RATES_0_RATE>;
assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
ASSIGNED_SSCS_0_SPREAD
ASSIGNED_SSCS_0_METHOD>;
};
};
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
/plugin/;
#include "kunit_clk_assigned_rates.h"
&{/} {
clk: kunit-clock {
compatible = "test,clk-assigned-rates";
#clock-cells = <1>;
assigned-clocks = <&clk 0>,
<&clk 1>;
assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
ASSIGNED_SSCS_0_SPREAD
ASSIGNED_SSCS_0_METHOD>,
<ASSIGNED_SSCS_1_MODFREQ
ASSIGNED_SSCS_1_SPREAD
ASSIGNED_SSCS_1_METHOD>;
};
};
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
/plugin/;
#include "kunit_clk_assigned_rates.h"
&{/} {
clk: kunit-clock {
compatible = "test,clk-assigned-rates";
#clock-cells = <1>;
};
kunit-clock-consumer {
compatible = "test,clk-consumer";
assigned-clocks = <&clk 0>,
<&clk 1>;
assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
ASSIGNED_SSCS_0_SPREAD
ASSIGNED_SSCS_0_METHOD>,
<ASSIGNED_SSCS_1_MODFREQ
ASSIGNED_SSCS_1_SPREAD
ASSIGNED_SSCS_1_METHOD>;
};
};
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
/plugin/;
#include "kunit_clk_assigned_rates.h"
&{/} {
clk: kunit-clock {
compatible = "test,clk-assigned-rates";
#clock-cells = <0>;
assigned-clocks = <0>;
assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
ASSIGNED_SSCS_0_SPREAD
ASSIGNED_SSCS_0_METHOD>;
};
};
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
/plugin/;
#include "kunit_clk_assigned_rates.h"
&{/} {
clk: kunit-clock {
compatible = "test,clk-assigned-rates";
#clock-cells = <0>;
};
kunit-clock-consumer {
compatible = "test,clk-consumer";
assigned-clocks = <0>;
assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
ASSIGNED_SSCS_0_SPREAD
ASSIGNED_SSCS_0_METHOD>;
};
};
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
/plugin/;
#include "kunit_clk_assigned_rates.h"
&{/} {
clk: kunit-clock {
compatible = "test,clk-assigned-rates";
#clock-cells = <0>;
assigned-clocks = <&clk>;
assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
ASSIGNED_SSCS_0_SPREAD
ASSIGNED_SSCS_0_METHOD>;
};
};
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
/plugin/;
#include "kunit_clk_assigned_rates.h"
&{/} {
clk: kunit-clock {
compatible = "test,clk-assigned-rates";
#clock-cells = <0>;
};
kunit-clock-consumer {
compatible = "test,clk-consumer";
assigned-clocks = <&clk>;
assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
ASSIGNED_SSCS_0_SPREAD
ASSIGNED_SSCS_0_METHOD>;
};
};
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
/plugin/;
#include "kunit_clk_assigned_rates.h"
&{/} {
clk: kunit-clock {
compatible = "test,clk-assigned-rates";
#clock-cells = <0>;
assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
ASSIGNED_SSCS_0_SPREAD
ASSIGNED_SSCS_0_METHOD>;
};
};
@@ -0,0 +1,19 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
/plugin/;
#include "kunit_clk_assigned_rates.h"
&{/} {
clk: kunit-clock {
compatible = "test,clk-assigned-rates";
#clock-cells = <0>;
};
kunit-clock-consumer {
compatible = "test,clk-consumer";
assigned-clock-sscs = <ASSIGNED_SSCS_0_MODFREQ
ASSIGNED_SSCS_0_SPREAD
ASSIGNED_SSCS_0_METHOD>;
};
};
@@ -0,0 +1,12 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
/plugin/;
&{/} {
clk: kunit-clock {
compatible = "test,clk-assigned-rates";
#clock-cells = <0>;
assigned-clocks = <&clk>;
assigned-clock-sscs = <0 0 0>;
};
};
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
/plugin/;
&{/} {
clk: kunit-clock {
compatible = "test,clk-assigned-rates";
#clock-cells = <0>;
};
kunit-clock-consumer {
compatible = "test,clk-consumer";
assigned-clocks = <&clk>;
assigned-clock-sscs = <0 0 0>;
};
};
+11
View File
@@ -537,6 +537,16 @@ config COMMON_CLK_MT8173_IMGSYS
help
This driver supports MediaTek MT8173 imgsys clocks.
config COMMON_CLK_MT8173_MFGTOP
tristate "Clock and power driver for MediaTek MT8173 mfgtop"
depends on COMMON_CLK_MT8173
depends on PM
default COMMON_CLK_MT8173
select PM_GENERIC_DOMAINS
select PM_GENERIC_DOMAINS_OF
help
This driver supports MediaTek MT8173 mfgtop clocks and power domain.
config COMMON_CLK_MT8173_MMSYS
tristate "Clock driver for MediaTek MT8173 mmsys"
depends on COMMON_CLK_MT8173
@@ -1006,6 +1016,7 @@ config COMMON_CLK_MT8196
tristate "Clock driver for MediaTek MT8196"
depends on ARM64 || COMPILE_TEST
select COMMON_CLK_MEDIATEK
select REGMAP_MMIO
default ARCH_MEDIATEK
help
This driver supports MediaTek MT8196 basic clocks.
+1
View File
@@ -82,6 +82,7 @@ obj-$(CONFIG_COMMON_CLK_MT8167_VDECSYS) += clk-mt8167-vdec.o
obj-$(CONFIG_COMMON_CLK_MT8173) += clk-mt8173-apmixedsys.o clk-mt8173-infracfg.o \
clk-mt8173-pericfg.o clk-mt8173-topckgen.o
obj-$(CONFIG_COMMON_CLK_MT8173_IMGSYS) += clk-mt8173-img.o
obj-$(CONFIG_COMMON_CLK_MT8173_MFGTOP) += clk-mt8173-mfgtop.o
obj-$(CONFIG_COMMON_CLK_MT8173_MMSYS) += clk-mt8173-mm.o
obj-$(CONFIG_COMMON_CLK_MT8173_VDECSYS) += clk-mt8173-vdecsys.o
obj-$(CONFIG_COMMON_CLK_MT8173_VENCSYS) += clk-mt8173-vencsys.o
+4 -1
View File
@@ -102,9 +102,12 @@ static int clk_mt6735_apmixed_probe(struct platform_device *pdev)
ret = devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_onecell_get,
clk_data);
if (ret)
if (ret) {
dev_err(&pdev->dev,
"Failed to register clock provider: %d\n", ret);
mtk_clk_unregister_plls(apmixedsys_plls, ARRAY_SIZE(apmixedsys_plls),
clk_data);
}
return ret;
}
@@ -63,6 +63,7 @@ static const struct of_device_id of_match_mt6735_vdecsys[] = {
{ .compatible = "mediatek,mt6735-vdecsys", .data = &vdecsys_clks },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, of_match_mt6735_vdecsys);
static struct platform_driver clk_mt6735_vdecsys = {
.probe = mtk_clk_simple_probe,
@@ -37,6 +37,7 @@ static const struct of_device_id of_match_mt6735_vencsys[] = {
{ .compatible = "mediatek,mt6735-vencsys", .data = &vencsys_clks },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, of_match_mt6735_vencsys);
static struct platform_driver clk_mt6735_vencsys = {
.probe = mtk_clk_simple_probe,
+4 -1
View File
@@ -409,6 +409,9 @@ static const struct mtk_gate_regs infra_cg_regs = {
GATE_MTK_FLAGS(_id, _name, _parent, &infra_cg_regs, _shift, \
&mtk_clk_gate_ops_setclr, CLK_IS_CRITICAL)
#define GATE_ICG_INV(_id, _name, _parent, _shift) \
GATE_MTK(_id, _name, _parent, &infra_cg_regs, _shift, &mtk_clk_gate_ops_setclr_inv)
static const struct mtk_gate infra_clks[] = {
GATE_DUMMY(CLK_DUMMY, "infra_dummy"),
GATE_ICG(CLK_INFRA_PMIC_WRAP, "pmic_wrap_ck", "axi_sel", 23),
@@ -419,7 +422,7 @@ static const struct mtk_gate infra_clks[] = {
GATE_ICG(CLK_INFRA_CPUM, "cpum_ck", "cpum_tck_in", 15),
GATE_ICG_AO(CLK_INFRA_M4U, "m4u_ck", "mem_sel", 8),
GATE_ICG(CLK_INFRA_MFGAXI, "mfgaxi_ck", "axi_sel", 7),
GATE_ICG(CLK_INFRA_DEVAPC, "devapc_ck", "axi_sel", 6),
GATE_ICG_INV(CLK_INFRA_DEVAPC, "devapc_ck", "axi_sel", 6),
GATE_ICG(CLK_INFRA_AUDIO, "audio_ck", "aud_intbus_sel", 5),
GATE_ICG(CLK_INFRA_MFG_BUS, "mfg_bus_ck", "axi_sel", 2),
GATE_ICG(CLK_INFRA_SMI, "smi_ck", "smi_sel", 1),
+242
View File
@@ -0,0 +1,242 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2024 Google LLC
* Author: Chen-Yu Tsai <wenst@chromium.org>
*
* Based on driver in downstream ChromeOS v5.15 kernel.
*
* Copyright (c) 2014 MediaTek Inc.
* Author: Chiawen Lee <chiawen.lee@mediatek.com>
*/
#include <dt-bindings/clock/mt8173-clk.h>
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include "clk-gate.h"
#include "clk-mtk.h"
static const struct mtk_gate_regs mfg_cg_regs = {
.sta_ofs = 0x0000,
.clr_ofs = 0x0008,
.set_ofs = 0x0004,
};
#define GATE_MFG(_id, _name, _parent, _shift, _flags) \
GATE_MTK_FLAGS(_id, _name, _parent, &mfg_cg_regs, _shift, &mtk_clk_gate_ops_setclr, _flags)
/* TODO: The block actually has dividers for the core and mem clocks. */
static const struct mtk_gate mfg_clks[] = {
GATE_MFG(CLK_MFG_AXI, "mfg_axi", "axi_mfg_in_sel", 0, CLK_SET_RATE_PARENT),
GATE_MFG(CLK_MFG_MEM, "mfg_mem", "mem_mfg_in_sel", 1, CLK_SET_RATE_PARENT),
GATE_MFG(CLK_MFG_G3D, "mfg_g3d", "mfg_sel", 2, CLK_SET_RATE_PARENT),
GATE_MFG(CLK_MFG_26M, "mfg_26m", "clk26m", 3, 0),
};
struct mt8173_mfgtop_data {
struct clk_hw_onecell_data *clk_data;
struct regmap *regmap;
struct generic_pm_domain genpd;
struct of_phandle_args parent_pd, child_pd;
struct clk *clk_26m;
};
/* Delay count in clock cycles */
#define MFG_ACTIVE_POWER_CON0 0x24
#define RST_B_DELAY_CNT GENMASK(7, 0) /* pwr_rst_b de-assert delay during power-up */
#define CLK_EN_DELAY_CNT GENMASK(15, 8) /* CLK_DIS deassert delay during power-up */
#define CLK_DIS_DELAY_CNT GENMASK(23, 16) /* CLK_DIS assert delay during power-down */
#define FORCE_ABORT BIT(30) /* write 1 to force abort a power event */
#define ACTIVE_PWRCTL_EN BIT(31) /* enable ACTIVE_POWER */
#define MFG_ACTIVE_POWER_CON1 0x28
#define PWR_ON_S_DELAY_CNT GENMASK(7, 0) /* pwr_on_s assert delay during power-up */
#define ISO_DELAY_CNT GENMASK(15, 8) /* ISO assert delay during power-down */
#define ISOOFF_DELAY_CNT GENMASK(23, 16) /* ISO de-assert delay during power-up */
#define RST_DELAY_CNT GENMASK(31, 24) /* pwr_rsb_b assert delay during power-down */
static int clk_mt8173_mfgtop_power_on(struct generic_pm_domain *domain)
{
struct mt8173_mfgtop_data *data = container_of(domain, struct mt8173_mfgtop_data, genpd);
int ret;
/* drives internal power management */
ret = clk_prepare_enable(data->clk_26m);
if (ret)
return ret;
/* Power on/off delays for various signals */
regmap_write(data->regmap, MFG_ACTIVE_POWER_CON0,
FIELD_PREP(RST_B_DELAY_CNT, 77) |
FIELD_PREP(CLK_EN_DELAY_CNT, 61) |
FIELD_PREP(CLK_DIS_DELAY_CNT, 60) |
FIELD_PREP(ACTIVE_PWRCTL_EN, 0));
regmap_write(data->regmap, MFG_ACTIVE_POWER_CON1,
FIELD_PREP(PWR_ON_S_DELAY_CNT, 11) |
FIELD_PREP(ISO_DELAY_CNT, 68) |
FIELD_PREP(ISOOFF_DELAY_CNT, 69) |
FIELD_PREP(RST_DELAY_CNT, 77));
/* Magic numbers related to core switch sequence and delays */
regmap_write(data->regmap, 0xe0, 0x7a710184);
regmap_write(data->regmap, 0xe4, 0x835f6856);
regmap_write(data->regmap, 0xe8, 0x002b0234);
regmap_write(data->regmap, 0xec, 0x80000000);
regmap_write(data->regmap, 0xa0, 0x08000000);
return 0;
}
static int clk_mt8173_mfgtop_power_off(struct generic_pm_domain *domain)
{
struct mt8173_mfgtop_data *data = container_of(domain, struct mt8173_mfgtop_data, genpd);
/* Magic numbers related to core switch sequence and delays */
regmap_write(data->regmap, 0xec, 0);
/* drives internal power management */
clk_disable_unprepare(data->clk_26m);
return 0;
}
static int clk_mt8173_mfgtop_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
struct mt8173_mfgtop_data *data;
int ret;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
platform_set_drvdata(pdev, data);
data->clk_data = mtk_devm_alloc_clk_data(dev, ARRAY_SIZE(mfg_clks));
if (!data->clk_data)
return -ENOMEM;
/* MTK clock gates also uses regmap */
data->regmap = device_node_to_regmap(node);
if (IS_ERR(data->regmap))
return dev_err_probe(dev, PTR_ERR(data->regmap), "Failed to get regmap\n");
data->child_pd.np = node;
data->child_pd.args_count = 0;
ret = of_parse_phandle_with_args(node, "power-domains", "#power-domain-cells", 0,
&data->parent_pd);
if (ret)
return dev_err_probe(dev, ret, "Failed to parse power domain\n");
devm_pm_runtime_enable(dev);
/*
* Do a pm_runtime_resume_and_get() to workaround a possible
* deadlock between clk_register() and the genpd framework.
*/
ret = pm_runtime_resume_and_get(dev);
if (ret) {
dev_err_probe(dev, ret, "Failed to runtime resume device\n");
goto put_of_node;
}
ret = mtk_clk_register_gates(dev, node, mfg_clks, ARRAY_SIZE(mfg_clks),
data->clk_data);
if (ret) {
dev_err_probe(dev, ret, "Failed to register clock gates\n");
goto put_pm_runtime;
}
data->clk_26m = clk_hw_get_clk(data->clk_data->hws[CLK_MFG_26M], "26m");
if (IS_ERR(data->clk_26m)) {
ret = dev_err_probe(dev, PTR_ERR(data->clk_26m), "Failed to get 26 MHz clock\n");
goto unregister_clks;
}
ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, data->clk_data);
if (ret) {
dev_err_probe(dev, ret, "Failed to add clk OF provider\n");
goto put_26m_clk;
}
data->genpd.name = "mfg-top";
data->genpd.power_on = clk_mt8173_mfgtop_power_on;
data->genpd.power_off = clk_mt8173_mfgtop_power_off;
ret = pm_genpd_init(&data->genpd, NULL, true);
if (ret) {
dev_err_probe(dev, ret, "Failed to add power domain\n");
goto del_clk_provider;
}
ret = of_genpd_add_provider_simple(node, &data->genpd);
if (ret) {
dev_err_probe(dev, ret, "Failed to add power domain OF provider\n");
goto remove_pd;
}
ret = of_genpd_add_subdomain(&data->parent_pd, &data->child_pd);
if (ret) {
dev_err_probe(dev, ret, "Failed to link PM domains\n");
goto del_pd_provider;
}
pm_runtime_put(dev);
return 0;
del_pd_provider:
of_genpd_del_provider(node);
remove_pd:
pm_genpd_remove(&data->genpd);
del_clk_provider:
of_clk_del_provider(node);
put_26m_clk:
clk_put(data->clk_26m);
unregister_clks:
mtk_clk_unregister_gates(mfg_clks, ARRAY_SIZE(mfg_clks), data->clk_data);
put_pm_runtime:
pm_runtime_put_sync(dev);
put_of_node:
of_node_put(data->parent_pd.np);
return ret;
}
static void clk_mt8173_mfgtop_remove(struct platform_device *pdev)
{
struct mt8173_mfgtop_data *data = platform_get_drvdata(pdev);
struct device_node *node = pdev->dev.of_node;
of_genpd_remove_subdomain(&data->parent_pd, &data->child_pd);
of_genpd_del_provider(node);
pm_genpd_remove(&data->genpd);
of_clk_del_provider(node);
clk_put(data->clk_26m);
mtk_clk_unregister_gates(mfg_clks, ARRAY_SIZE(mfg_clks), data->clk_data);
of_node_put(data->parent_pd.np);
}
static const struct of_device_id of_match_clk_mt8173_mfgtop[] = {
{ .compatible = "mediatek,mt8173-mfgtop" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, of_match_clk_mt8173_mfgtop);
static struct platform_driver clk_mt8173_mfgtop_drv = {
.probe = clk_mt8173_mfgtop_probe,
.remove = clk_mt8173_mfgtop_remove,
.driver = {
.name = "clk-mt8173-mfgtop",
.of_match_table = of_match_clk_mt8173_mfgtop,
},
};
module_platform_driver(clk_mt8173_mfgtop_drv);
MODULE_DESCRIPTION("MediaTek MT8173 mfgtop clock driver");
MODULE_LICENSE("GPL");
@@ -629,7 +629,6 @@ static const struct regmap_config vlpckgen_regmap_config = {
.val_bits = 32,
.reg_stride = 4,
.max_register = 0x1000,
.fast_io = true,
};
static int clk_mt8196_vlp_probe(struct platform_device *pdev)
+49 -49
View File
@@ -197,12 +197,56 @@ static void mtk_clk_unregister_pllfh(struct clk_hw *hw)
kfree(fh);
}
static void mtk_clk_cleanup_pllfhs(void __iomem *iomem_base,
const struct mtk_pll_data *plls, int num_plls,
void __iomem *iomem_fhctl_base,
struct mtk_pllfh_data *pllfhs, int num_fhs,
struct clk_hw_onecell_data *clk_data)
{
void __iomem *base = iomem_base;
void __iomem *fhctl_base = iomem_fhctl_base;
int i;
for (i = num_plls - 1; i >= 0; i--) {
const struct mtk_pll_data *pll = &plls[i];
struct mtk_pllfh_data *pllfh;
bool use_fhctl;
if (IS_ERR_OR_NULL(clk_data->hws[pll->id]))
continue;
pllfh = get_pllfh_by_id(pllfhs, num_fhs, pll->id);
use_fhctl = fhctl_is_supported_and_enabled(pllfh);
if (!base)
base = mtk_clk_pll_get_base(clk_data->hws[pll->id],
pll);
if (use_fhctl) {
if (!fhctl_base)
fhctl_base = pllfh->state.base;
mtk_clk_unregister_pllfh(clk_data->hws[pll->id]);
} else {
mtk_clk_unregister_pll(clk_data->hws[pll->id]);
}
clk_data->hws[pll->id] = ERR_PTR(-ENOENT);
}
if (fhctl_base)
iounmap(fhctl_base);
if (base)
iounmap(base);
}
int mtk_clk_register_pllfhs(struct device *dev,
const struct mtk_pll_data *plls, int num_plls,
struct mtk_pllfh_data *pllfhs, int num_fhs,
struct clk_hw_onecell_data *clk_data)
{
void __iomem *base;
void __iomem *base, *fhctl_base = NULL;
int i;
struct clk_hw *hw;
@@ -238,24 +282,8 @@ int mtk_clk_register_pllfhs(struct device *dev,
return 0;
err:
while (--i >= 0) {
const struct mtk_pll_data *pll = &plls[i];
struct mtk_pllfh_data *pllfh;
bool use_fhctl;
pllfh = get_pllfh_by_id(pllfhs, num_fhs, pll->id);
use_fhctl = fhctl_is_supported_and_enabled(pllfh);
if (use_fhctl)
mtk_clk_unregister_pllfh(clk_data->hws[pll->id]);
else
mtk_clk_unregister_pll(clk_data->hws[pll->id]);
clk_data->hws[pll->id] = ERR_PTR(-ENOENT);
}
iounmap(base);
mtk_clk_cleanup_pllfhs(base, plls, i, fhctl_base, pllfhs, num_fhs,
clk_data);
return PTR_ERR(hw);
}
EXPORT_SYMBOL_GPL(mtk_clk_register_pllfhs);
@@ -264,38 +292,10 @@ void mtk_clk_unregister_pllfhs(const struct mtk_pll_data *plls, int num_plls,
struct mtk_pllfh_data *pllfhs, int num_fhs,
struct clk_hw_onecell_data *clk_data)
{
void __iomem *base = NULL, *fhctl_base = NULL;
int i;
if (!clk_data)
return;
for (i = num_plls; i > 0; i--) {
const struct mtk_pll_data *pll = &plls[i - 1];
struct mtk_pllfh_data *pllfh;
bool use_fhctl;
if (IS_ERR_OR_NULL(clk_data->hws[pll->id]))
continue;
pllfh = get_pllfh_by_id(pllfhs, num_fhs, pll->id);
use_fhctl = fhctl_is_supported_and_enabled(pllfh);
if (use_fhctl) {
fhctl_base = pllfh->state.base;
mtk_clk_unregister_pllfh(clk_data->hws[pll->id]);
} else {
base = mtk_clk_pll_get_base(clk_data->hws[pll->id],
pll);
mtk_clk_unregister_pll(clk_data->hws[pll->id]);
}
clk_data->hws[pll->id] = ERR_PTR(-ENOENT);
}
if (fhctl_base)
iounmap(fhctl_base);
iounmap(base);
mtk_clk_cleanup_pllfhs(NULL, plls, num_plls, NULL, pllfhs,
num_fhs, clk_data);
}
EXPORT_SYMBOL_GPL(mtk_clk_unregister_pllfhs);
+1 -1
View File
@@ -285,7 +285,7 @@ static int mpfs_cfg_clk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned
mask = clk_div_mask(cfg->width) << cfg->shift;
val = divider_setting << cfg->shift;
regmap_update_bits(cfg->map, cfg->map_offset, val, mask);
regmap_update_bits(cfg->map, cfg->map_offset, mask, val);
return 0;
}
+1 -1
View File
@@ -114,7 +114,7 @@ static void pxa1908_clk_reset_init(struct device_node *np,
cells[i].bits = BIT(2);
cells[i].flags = 0;
cells[i].lock = apbc_gate_clks[i].lock;
};
}
mmp_clk_reset_register(np, cells, nr_cells);
}
+1 -1
View File
@@ -61,7 +61,7 @@ static void pxa1908_clk_reset_init(struct device_node *np,
cells[i].bits = BIT(2);
cells[i].flags = 0;
cells[i].lock = apbcp_gate_clks[i].lock;
};
}
mmp_clk_reset_register(np, cells, nr_cells);
}
+1 -1
View File
@@ -153,7 +153,7 @@ static int clk_cpu_on_set_rate(struct clk_hw *hwclk, unsigned long rate,
static int clk_cpu_set_rate(struct clk_hw *hwclk, unsigned long rate,
unsigned long parent_rate)
{
if (__clk_is_enabled(hwclk->clk))
if (clk_hw_is_enabled(hwclk))
return clk_cpu_on_set_rate(hwclk, rate, parent_rate);
else
return clk_cpu_off_set_rate(hwclk, rate, parent_rate);

Some files were not shown because too many files have changed in this diff Show More