summaryrefslogtreecommitdiff
path: root/include/linux
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-08-26 11:14:30 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-08-26 11:14:30 -0700
commit502d45774af09f1c681c754c4b7cdfb5d7f72fd9 (patch)
treee754285eab60be2faaef31d68a2e249588d37010 /include/linux
parent8fefe68784ae1606e11a5c65c04167c3b95051a0 (diff)
parentdd8eb789f18c4c600f28e61176a02bcf3b790117 (diff)
Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux
Pull clk updates from Stephen Boyd: "Mostly the usual clk driver updates and new SoC additions plus non-critical data fixes for things that weren't used yet. One thing that's new here in the core is SSC spread spectrum support (SSC) in the clk provider API. The idea is that DT authors will configure SSC for certain clks and they'll be configured at clk provider registration time or when a consumer device is probed, similar to how we handle assigned clk rates or parents. On the clk driver side we have Qualcomm adding almost half the diff because they add support for 4 different SoCs and then a long tail of other SoCs like Mediatek, Renesas, Rockchip, SpaceMiT, etc. add more SoC support this time around. Luckily it's mostly clk data for these new SoCs because the actual clk_ops are already there. Beyond the new drivers we get all the little fixups for more compilation coverage or usage of more modern APIs. That all looks normal. Finally, I kinda buried the lede, I'm bringing on Brian and Jerome to help out with maintaining the clk subsystem. The current working model is already semi-distributed in that silicon vendors typically take care of their drivers and send me pull requests but I'm becoming a bottleneck for new drivers and core framework review because this has become a 100% volunteer effort on my part. Mike is stepping down after all these years (thanks Mike!) and that jump started the conversation around finding co-maintainers. Brian and Jerome have graciously offered to help me with the work load, meaning in the future they'll be sending pull requests and committing directly to the clk.git tree. They've both been around on the list for a while, I've met them both in person, and they've been making changes to the core clk framework along with helping review patches so I'm pretty confident this will work well. Core: - devm_clk_bulk_get_enable() consumer API - devm_clk_hw_register_composite_pdata() provider API - Spread Spectrum Clock (SSC) support via DT bindings and provider APIs - Divider clk rounding improved (and tested) New Drivers: - Cix Sky1 audio subsystem (AUDSS) - UltraRISC DP1000 - MediaTek MT8173 MFG_TOP - Si549 - Aspeed AST2700 PECI - Airoha EN7523 PCIe - Rockchip RV1106 - Mobileye EyeQ7H - Qualcomm Maili GCC, TCSR, RPMh, and video clks - Qualcomm Shikra GCC, RPM, GPU, display, and audio clks - Qualcomm Nord display and graphics clks - Qualcomm Glymur camera and EVA clks - Qualcomm Hawi video clks - Amlogic A9 AO and peripheral clks - Renesas R-Car X5H (R8A78000) CPG" * tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (269 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: samsung: Don't include <linux/mod_devicetable.h> clk: at91: Read "reg" with helper clk: renesas: Add R-Car X5H CPG driver clk: rockchip: rk3576: fix source muxes for SPI0..SPI4 clk: rockchip: Add clock controller for the RV1106 dt-bindings: clock: rockchip: Add RV1106 CRU support dt-bindings: clock: Document Renesas R-Car X5H Clock Pulse Generator ...
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/clk-provider.h136
-rw-r--r--include/linux/clk.h27
-rw-r--r--include/linux/clk/qcom.h67
-rw-r--r--include/linux/clk/renesas.h34
4 files changed, 219 insertions, 45 deletions
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index b01a38fef8cf..dc8e161f9c2c 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -6,31 +6,44 @@
#ifndef __LINUX_CLK_PROVIDER_H
#define __LINUX_CLK_PROVIDER_H
+#include <dt-bindings/clock/clock.h>
#include <linux/of.h>
#include <linux/of_clk.h>
-/*
- * flags used across common struct clk. these flags should only affect the
- * top-level framework. custom flags for dealing with hardware specifics
- * belong in struct clk_foo
+/**
+ * DOC: clk framework flags
*
- * Please update clk_flags[] in drivers/clk/clk.c when making changes here!
+ * Flags used across common struct clk. These flags should only affect the
+ * top-level framework. Custom flags for dealing with hardware specifics
+ * belong in struct clk_foo.
+ *
+ * * CLK_SET_RATE_GATE - must be gated across rate change
+ * * CLK_SET_PARENT_GATE - must be gated across re-parent
+ * * CLK_SET_RATE_PARENT - propagate rate change up one level
+ * * CLK_IGNORE_UNUSED - do not gate even if unused
+ * * CLK_GET_RATE_NOCACHE - do not use the cached clk rate
+ * * CLK_SET_RATE_NO_REPARENT - don't re-parent on rate change
+ * * CLK_GET_ACCURACY_NOCACHE - do not use the cached clk accuracy
+ * * CLK_RECALC_NEW_RATES - recalc rates after notifications
+ * * CLK_SET_RATE_UNGATE - clock needs to run to set rate
+ * * CLK_IS_CRITICAL - do not gate, ever
+ * * CLK_OPS_PARENT_ENABLE - parents need enable during gate/ungate, set rate and re-parent
+ * * CLK_DUTY_CYCLE_PARENT - duty cycle call may be forwarded to the parent clock
*/
-#define CLK_SET_RATE_GATE BIT(0) /* must be gated across rate change */
-#define CLK_SET_PARENT_GATE BIT(1) /* must be gated across re-parent */
-#define CLK_SET_RATE_PARENT BIT(2) /* propagate rate change up one level */
-#define CLK_IGNORE_UNUSED BIT(3) /* do not gate even if unused */
+/* Please update clk_flags[] in drivers/clk/clk.c when making changes here! */
+#define CLK_SET_RATE_GATE BIT(0)
+#define CLK_SET_PARENT_GATE BIT(1)
+#define CLK_SET_RATE_PARENT BIT(2)
+#define CLK_IGNORE_UNUSED BIT(3)
/* unused */
/* unused */
-#define CLK_GET_RATE_NOCACHE BIT(6) /* do not use the cached clk rate */
-#define CLK_SET_RATE_NO_REPARENT BIT(7) /* don't re-parent on rate change */
-#define CLK_GET_ACCURACY_NOCACHE BIT(8) /* do not use the cached clk accuracy */
-#define CLK_RECALC_NEW_RATES BIT(9) /* recalc rates after notifications */
-#define CLK_SET_RATE_UNGATE BIT(10) /* clock needs to run to set rate */
-#define CLK_IS_CRITICAL BIT(11) /* do not gate, ever */
-/* parents need enable during gate/ungate, set rate and re-parent */
+#define CLK_GET_RATE_NOCACHE BIT(6)
+#define CLK_SET_RATE_NO_REPARENT BIT(7)
+#define CLK_GET_ACCURACY_NOCACHE BIT(8)
+#define CLK_RECALC_NEW_RATES BIT(9)
+#define CLK_SET_RATE_UNGATE BIT(10)
+#define CLK_IS_CRITICAL BIT(11)
#define CLK_OPS_PARENT_ENABLE BIT(12)
-/* duty cycle call may be forwarded to the parent clock */
#define CLK_DUTY_CYCLE_PARENT BIT(13)
struct clk;
@@ -84,6 +97,26 @@ struct clk_duty {
unsigned int den;
};
+enum clk_ssc_method {
+ CLK_SPREAD_NO = CLK_SSC_NO_SPREAD,
+ CLK_SPREAD_CENTER = CLK_SSC_CENTER_SPREAD,
+ CLK_SPREAD_UP = CLK_SSC_UP_SPREAD,
+ CLK_SPREAD_DOWN = CLK_SSC_DOWN_SPREAD,
+};
+
+/**
+ * struct clk_spread_spectrum - Structure encoding spread spectrum of a clock
+ *
+ * @modfreq_hz: Modulation frequency
+ * @spread_bp: Modulation percent in permyriad
+ * @method: Modulation method
+ */
+struct clk_spread_spectrum {
+ u32 modfreq_hz;
+ u32 spread_bp;
+ enum clk_ssc_method method;
+};
+
/**
* struct clk_ops - Callback operations for hardware clocks; these are to
* be provided by the clock implementation, and will be called by drivers
@@ -174,6 +207,12 @@ struct clk_duty {
* separately via calls to .set_parent and .set_rate.
* Returns 0 on success, -EERROR otherwise.
*
+ * @set_spread_spectrum: Optional callback used to configure the spread
+ * spectrum modulation frequency, percentage, and method
+ * to reduce EMI by spreading the clock frequency over a
+ * wider range.
+ * Returns 0 on success, -EERROR otherwise.
+ *
* @recalc_accuracy: Recalculate the accuracy of this clock. The clock accuracy
* is expressed in ppb (parts per billion). The parent accuracy is
* an input parameter.
@@ -249,6 +288,8 @@ struct clk_ops {
int (*set_rate_and_parent)(struct clk_hw *hw,
unsigned long rate,
unsigned long parent_rate, u8 index);
+ int (*set_spread_spectrum)(struct clk_hw *hw,
+ const struct clk_spread_spectrum *ss_conf);
unsigned long (*recalc_accuracy)(struct clk_hw *hw,
unsigned long parent_accuracy);
int (*get_phase)(struct clk_hw *hw);
@@ -1152,13 +1193,16 @@ struct clk_fixed_factor {
#define to_clk_fixed_factor(_hw) container_of(_hw, struct clk_fixed_factor, hw)
extern const struct clk_ops clk_fixed_factor_ops;
+struct clk_hw *
+__clk_hw_register_fixed_factor(struct device *dev, struct device_node *np,
+ const char *name, const char *parent_name,
+ const struct clk_hw *parent_hw, const struct clk_parent_data *pdata,
+ unsigned long flags, unsigned int mult, unsigned int div,
+ unsigned long acc, unsigned int fixflags, bool devm);
struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
unsigned int mult, unsigned int div);
void clk_unregister_fixed_factor(struct clk *clk);
-struct clk_hw *clk_hw_register_fixed_factor(struct device *dev,
- const char *name, const char *parent_name, unsigned long flags,
- unsigned int mult, unsigned int div);
struct clk_hw *clk_hw_register_fixed_factor_fwname(struct device *dev,
struct device_node *np, const char *name, const char *fw_name,
unsigned long flags, unsigned int mult, unsigned int div);
@@ -1170,9 +1214,6 @@ struct clk_hw *clk_hw_register_fixed_factor_index(struct device *dev,
const char *name, unsigned int index, unsigned long flags,
unsigned int mult, unsigned int div);
void clk_hw_unregister_fixed_factor(struct clk_hw *hw);
-struct clk_hw *devm_clk_hw_register_fixed_factor(struct device *dev,
- const char *name, const char *parent_name, unsigned long flags,
- unsigned int mult, unsigned int div);
struct clk_hw *devm_clk_hw_register_fixed_factor_fwname(struct device *dev,
struct device_node *np, const char *name, const char *fw_name,
unsigned long flags, unsigned int mult, unsigned int div);
@@ -1184,13 +1225,45 @@ struct clk_hw *devm_clk_hw_register_fixed_factor_index(struct device *dev,
const char *name, unsigned int index, unsigned long flags,
unsigned int mult, unsigned int div);
-struct clk_hw *devm_clk_hw_register_fixed_factor_parent_hw(struct device *dev,
- const char *name, const struct clk_hw *parent_hw,
- unsigned long flags, unsigned int mult, unsigned int div);
-
-struct clk_hw *clk_hw_register_fixed_factor_parent_hw(struct device *dev,
- const char *name, const struct clk_hw *parent_hw,
- unsigned long flags, unsigned int mult, unsigned int div);
+#define clk_hw_register_fixed_factor(dev, name, parent_name, \
+ flags, mult, div) \
+ __clk_hw_register_fixed_factor((dev), NULL, (name), (parent_name), \
+ NULL, NULL, (flags), (mult), (div), \
+ 0, 0, false)
+#define clk_hw_register_fixed_factor_pdata(dev, np, name, pdata, \
+ flags, mult, div, acc, fixflags) \
+ __clk_hw_register_fixed_factor((dev), (np), (name), NULL, NULL, \
+ (pdata), (flags), (mult), (div), \
+ (acc), (fixflags), false)
+#define devm_clk_hw_register_fixed_factor(dev, name, parent_name, flags, \
+ mult, div) \
+ __clk_hw_register_fixed_factor((dev), NULL, (name), (parent_name), \
+ NULL, NULL, (flags), (mult), (div), 0, \
+ 0, true)
+/**
+ * devm_clk_hw_register_fixed_factor_parent_hw - Register a fixed factor clock with
+ * pointer to parent clock
+ * @dev: device that is registering this clock
+ * @name: name of this clock
+ * @parent_hw: pointer to parent clk
+ * @flags: fixed factor flags
+ * @mult: multiplier
+ * @div: divider
+ *
+ * Return: Pointer to fixed factor clk_hw structure that was registered or
+ * an error pointer.
+ */
+#define devm_clk_hw_register_fixed_factor_parent_hw(dev, name, parent_hw, \
+ flags, mult, div) \
+ __clk_hw_register_fixed_factor((dev), NULL, (name), NULL, \
+ (parent_hw), NULL, (flags), (mult), \
+ (div), 0, 0, true)
+
+#define clk_hw_register_fixed_factor_parent_hw(dev, name, parent_hw, flags, \
+ mult, div) \
+ __clk_hw_register_fixed_factor((dev), NULL, (name), NULL, \
+ (parent_hw), NULL, (flags), (mult), \
+ (div), 0, 0, false)
/**
* struct clk_fractional_divider - adjustable fractional divider clock
*
@@ -1431,11 +1504,14 @@ int clk_mux_determine_rate_flags(struct clk_hw *hw,
unsigned long flags);
int clk_hw_determine_rate_no_reparent(struct clk_hw *hw,
struct clk_rate_request *req);
+int clk_determine_rate_noop(struct clk_hw *hw, struct clk_rate_request *req);
void clk_hw_reparent(struct clk_hw *hw, struct clk_hw *new_parent);
void clk_hw_get_rate_range(struct clk_hw *hw, unsigned long *min_rate,
unsigned long *max_rate);
void clk_hw_set_rate_range(struct clk_hw *hw, unsigned long min_rate,
unsigned long max_rate);
+int clk_hw_set_spread_spectrum(struct clk_hw *hw,
+ const struct clk_spread_spectrum *ss_conf);
static inline void __clk_hw_set_clk(struct clk_hw *dst, struct clk_hw *src)
{
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 998ba3f261da..db9cf184fd99 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -503,6 +503,22 @@ int __must_check devm_clk_bulk_get(struct device *dev, int num_clks,
int __must_check devm_clk_bulk_get_optional(struct device *dev, int num_clks,
struct clk_bulk_data *clks);
/**
+ * devm_clk_bulk_get_enable - Get and enable bulk clocks (managed)
+ * @dev: device for clock "consumer"
+ * @num_clks: the number of clk_bulk_data
+ * @clks: pointer to the clk_bulk_data table of consumer
+ *
+ * Behaves the same as devm_clk_bulk_get() but also prepares and enables the
+ * clocks in one operation with management. The clks will automatically be
+ * disabled, unprepared and freed when the device is unbound.
+ *
+ * Return: 0 if all clocks specified in clk_bulk_data table are obtained and
+ * enabled successfully. Otherwise returns valid IS_ERR() condition containing
+ * errno.
+ */
+int __must_check devm_clk_bulk_get_enable(struct device *dev, int num_clks,
+ struct clk_bulk_data *clks);
+/**
* devm_clk_bulk_get_optional_enable - Get and enable optional bulk clocks (managed)
* @dev: device for clock "consumer"
* @num_clks: the number of clk_bulk_data
@@ -951,8 +967,8 @@ int clk_set_parent(struct clk *clk, struct clk *parent);
* clk_get_parent - get the parent clock source for this clock
* @clk: clock source
*
- * Returns struct clk corresponding to parent clock source, or
- * valid IS_ERR() condition containing errno.
+ * Returns struct clk corresponding to parent clock source, or NULL
+ * if clk is NULL.
*/
struct clk *clk_get_parent(struct clk *clk);
@@ -1052,6 +1068,13 @@ static inline int __must_check devm_clk_bulk_get_optional(struct device *dev,
return 0;
}
+static inline int __must_check devm_clk_bulk_get_enable(struct device *dev,
+ int num_clks,
+ struct clk_bulk_data *clks)
+{
+ return 0;
+}
+
static inline int __must_check devm_clk_bulk_get_optional_enable(struct device *dev,
int num_clks,
struct clk_bulk_data *clks)
diff --git a/include/linux/clk/qcom.h b/include/linux/clk/qcom.h
new file mode 100644
index 000000000000..11ac2d42ff9e
--- /dev/null
+++ b/include/linux/clk/qcom.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef __LINUX_CLK_QCOM_H
+#define __LINUX_CLK_QCOM_H
+
+#include <linux/clk-provider.h>
+#include <linux/errno.h>
+#include <linux/kconfig.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+struct device;
+struct platform_device;
+struct regulator_bulk_data;
+
+/**
+ * struct qcom_clk_ref_desc - descriptor for a clkref_en gate clock
+ * @name: clock name exposed to the common clock framework
+ * @offset: clkref_en register offset from the block base
+ * @regulator_names: optional supply names enabled while preparing the clock
+ * @num_regulators: number of entries in @regulator_names
+ */
+struct qcom_clk_ref_desc {
+ const char *name;
+ u32 offset;
+ const char * const *regulator_names;
+ unsigned int num_regulators;
+};
+
+/**
+ * struct qcom_clk_ref - per-clock data for a clkref_en gate clock
+ * @hw: common clock framework hardware clock handle
+ * @regmap: register map backing the clkref_en register
+ * @desc: clock descriptor copied at registration time
+ * @regulators: optional bulk regulator handles for @desc.regulator_names
+ */
+struct qcom_clk_ref {
+ struct clk_hw hw;
+ struct regmap *regmap;
+ struct qcom_clk_ref_desc desc;
+ struct regulator_bulk_data *regulators;
+};
+
+#if IS_ENABLED(CONFIG_COMMON_CLK_QCOM)
+
+int qcom_clk_ref_probe(struct platform_device *pdev,
+ const struct regmap_config *config,
+ const struct qcom_clk_ref_desc * const *descs,
+ size_t num_clk_refs);
+
+#else
+
+static inline int
+qcom_clk_ref_probe(struct platform_device *pdev,
+ const struct regmap_config *config,
+ const struct qcom_clk_ref_desc * const *descs,
+ size_t num_clk_refs)
+{
+ return -EOPNOTSUPP;
+}
+
+#endif
+
+#endif
diff --git a/include/linux/clk/renesas.h b/include/linux/clk/renesas.h
index 0949400f44de..c9495558cd5c 100644
--- a/include/linux/clk/renesas.h
+++ b/include/linux/clk/renesas.h
@@ -53,6 +53,9 @@ static inline void rzg2l_cpg_dsi_div_set_divider(u8 divider, int target) { }
* various parameters used to configure a PLL. These limits ensure
* the PLL operates within valid and stable ranges.
*
+ * @input_fref: Reference input frequency to the PLL (in Hz). If set
+ * to 0, a default value of 24MHz is used.
+ *
* @fout: Output frequency range (in MHz)
* @fout.min: Minimum allowed output frequency
* @fout.max: Maximum allowed output frequency
@@ -78,6 +81,8 @@ static inline void rzg2l_cpg_dsi_div_set_divider(u8 divider, int target) { }
* @k.max: Maximum delta-sigma value
*/
struct rzv2h_pll_limits {
+ u32 input_fref;
+
struct {
u32 min;
u32 max;
@@ -184,28 +189,31 @@ struct rzv2h_pll_div_pars {
.k = { .min = -32768, .max = 32767 }, \
} \
-#ifdef CONFIG_CLK_RZV2H
-bool rzv2h_get_pll_pars(const struct rzv2h_pll_limits *limits,
- struct rzv2h_pll_pars *pars, u64 freq_millihz);
+#ifdef CONFIG_CLK_RZV2H_CPG_LIB
+bool rzv2h_cpg_get_pll_pars(const struct rzv2h_pll_limits *limits,
+ struct rzv2h_pll_pars *pars, u64 freq_millihz);
-bool rzv2h_get_pll_divs_pars(const struct rzv2h_pll_limits *limits,
- struct rzv2h_pll_div_pars *pars,
- const u8 *table, u8 table_size, u64 freq_millihz);
+bool rzv2h_cpg_get_pll_divs_pars(const struct rzv2h_pll_limits *limits,
+ struct rzv2h_pll_div_pars *pars,
+ const u8 *table, u8 table_size, u64 freq_millihz);
#else
-static inline bool rzv2h_get_pll_pars(const struct rzv2h_pll_limits *limits,
- struct rzv2h_pll_pars *pars,
- u64 freq_millihz)
+static inline bool rzv2h_cpg_get_pll_pars(const struct rzv2h_pll_limits *limits,
+ struct rzv2h_pll_pars *pars,
+ u64 freq_millihz)
{
return false;
}
-static inline bool rzv2h_get_pll_divs_pars(const struct rzv2h_pll_limits *limits,
- struct rzv2h_pll_div_pars *pars,
- const u8 *table, u8 table_size,
- u64 freq_millihz)
+static inline bool rzv2h_cpg_get_pll_divs_pars(const struct rzv2h_pll_limits *limits,
+ struct rzv2h_pll_div_pars *pars,
+ const u8 *table, u8 table_size,
+ u64 freq_millihz)
{
return false;
}
#endif
+#define rzv2h_get_pll_pars rzv2h_cpg_get_pll_pars
+#define rzv2h_get_pll_divs_pars rzv2h_cpg_get_pll_divs_pars
+
#endif