Merge tag 'clk-misc-for-v7.3' of ssh://github.com/masneyb/linux into clk-pile

Pull clk patches picked up by Brian Masney:

Here's various improvements and fixes for the clk subsystem that was posted prior
to the opening of the last merge window.

- Add spread spectrum clock (SSC) support to the clk framework, including a new
  assigned-clock-sscs devicetree property and clk_hw_set_spread_spectrum()
  API with KUnit tests (Peng Fan)
- Add SCMI clock OEM extensions for the i.MX95 clock driver and introduce a
  common SCMI clock header (Peng Fan)
- Add clock, reset, and devicetree bindings for the ESWIN EIC7700 HSP clock and
  reset generator (Xuyang Dong)
- Add clk_determine_rate_noop() helper for clock drivers that can do any rate,
  and convert existing open-coded implementations across hisilicon, imx, qcom,
  renesas, rp1, samsung, scpi, sprd, mediatek phy, and mediatek pmdomain
  drivers (Brian Masney)
- Add kernel-doc documentation for struct clk_core and the core clock flags,
  and wire up clk identifiers into the documentation build (Brian Masney)
- Fix clk_divider_bestdiv() returning the minimum rate instead of the maximum
  rate for large rate requests, with KUnit tests (Lad Prabhakar)
- Fix Nuvoton MA35D1 PLL frequency calculation including ignored div_u64
  return values, incorrect PLL_CTL1_FRAC bit field width, and broken
  determine_rate logic (Joey Lu)
- Support unique clock names for multi-socket Tegra platforms (Jon Hunter)
- Allow COMPILE_TEST builds for HiSilicon clock drivers (Rosen Penev)
- Various fixes and cleanups from Akari Tsuyukusa, Alexander A. Klimov,
  Brian Masney, David Carlier, David Laight, Min zhang, Myeonghun Pak,
  Pavel Löbl, Randy Dunlap, Rob Herring, Rosen Penev, Uwe Kleine-König,
  William Theesfeld, Xuyang Dong, and Yu-Chun Lin

Signed-off-by: Brian Masney <bmasney@redhat.com>
[sboyd@kernel.org: Fix allmodconfig modpost failure in scmi]

* tag 'clk-misc-for-v7.3' of ssh://github.com/masneyb/linux: (53 commits)
  pmdomain: mediatek: mtk-mfg: use clk_determine_rate_noop()
  pmdomain: mediatek: airoha: use clk_determine_rate_noop()
  phy: mediatek: phy-mtk-hdmi-mt2701: use clk_determine_rate_noop()
  clk: sprd: use clk_determine_rate_noop()
  clk: scpi: use clk_determine_rate_noop()
  clk: samsung: acpm: use clk_determine_rate_noop()
  clk: rp1: use clk_determine_rate_noop()
  clk: renesas: rzg2l-cpg: use clk_determine_rate_noop()
  clk: qcom: smd-rpm: use clk_determine_rate_noop()
  clk: qcom: rpmh: use clk_determine_rate_noop()
  clk: qcom: rpm: use clk_determine_rate_noop()
  clk: imx: scu: use clk_determine_rate_noop()
  clk: hisilicon: hi3660-stub: use clk_determine_rate_noop()
  clk: add clk_determine_rate_noop()
  clk: imx: scu: drop redundant init.ops variable assignment
  clk: test: convert constants to use HZ_PER_MHZ
  docs: clk: include some identifiers to keep documentation up to date
  clk: add kernel docs for struct clk_core
  clk: add kernel docs for the core flags
  clk: hisilicon: allow COMPILE_TEST builds
  ...
This commit is contained in:
Stephen Boyd
2026-08-17 09:27:10 -07:00
83 changed files with 1813 additions and 398 deletions
@@ -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>;
};
+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
============================
+3 -2
View File
@@ -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>
+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
+8
View File
@@ -579,4 +579,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
+14 -2
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
@@ -121,7 +133,7 @@ obj-y += bcm/
obj-$(CONFIG_ARCH_BERLIN) += berlin/
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/
+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,
+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);
+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;
+2 -2
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);
+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");
+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);
+10 -17
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;
@@ -1405,7 +1398,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 +1546,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);
+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);
+3 -3
View File
@@ -479,9 +479,9 @@ static int si544_probe(struct i2c_client *client)
}
static const struct i2c_device_id si544_id[] = {
{ "si544a", 1500000000 },
{ "si544b", 800000000 },
{ "si544c", 350000000 },
{ .name = "si544a", .driver_data = 1500000000 },
{ .name = "si544b", .driver_data = 800000000 },
{ .name = "si544c", .driver_data = 350000000 },
{ }
};
MODULE_DEVICE_TABLE(i2c, si544_id);
+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,
+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.
+1 -11
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,
};
+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>;
};
};
+1
View File
@@ -1006,6 +1006,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.
+8 -13
View File
@@ -253,8 +253,8 @@ struct clk_muxing_soc_desc {
struct clk_muxing_ctrl {
spinlock_t *lock;
struct clk **muxes;
int num_muxes;
struct clk *muxes[] __counted_by(num_muxes);
};
static const char *powersave_parents[] = {
@@ -297,21 +297,18 @@ static void __init kirkwood_clk_muxing_setup(struct device_node *np,
if (WARN_ON(!base))
return;
ctrl = kzalloc_obj(*ctrl);
if (WARN_ON(!ctrl))
goto ctrl_out;
/* lock must already be initialized */
ctrl->lock = &ctrl_gating_lock;
/* Count, allocate, and register clock muxes */
for (n = 0; desc[n].name;)
n++;
ctrl = kzalloc_flex(*ctrl, muxes, n);
if (WARN_ON(!ctrl))
goto ctrl_out;
ctrl->num_muxes = n;
ctrl->muxes = kzalloc_objs(struct clk *, ctrl->num_muxes);
if (WARN_ON(!ctrl->muxes))
goto muxes_out;
/* lock must already be initialized */
ctrl->lock = &ctrl_gating_lock;
for (n = 0; n < ctrl->num_muxes; n++) {
ctrl->muxes[n] = clk_register_mux(NULL, desc[n].name,
@@ -324,8 +321,6 @@ static void __init kirkwood_clk_muxing_setup(struct device_node *np,
of_clk_add_provider(np, clk_muxing_get_src, ctrl);
return;
muxes_out:
kfree(ctrl);
ctrl_out:
iounmap(base);
}
+21 -21
View File
@@ -48,7 +48,7 @@
#define PLL_CTL1_PD BIT(0)
#define PLL_CTL1_BP BIT(1)
#define PLL_CTL1_OUTDIV GENMASK(6, 4)
#define PLL_CTL1_FRAC GENMASK(31, 24)
#define PLL_CTL1_FRAC GENMASK(31, 8)
#define PLL_CTL2_SLOPE GENMASK(23, 0)
#define INDIV_MIN 1
@@ -92,7 +92,7 @@ static unsigned long ma35d1_calc_smic_pll_freq(u32 pll0_ctl0,
p = FIELD_GET(SPLL0_CTL0_OUTDIV, pll0_ctl0);
outdiv = 1 << p;
pll_freq = (u64)parent_rate * n;
div_u64(pll_freq, m * outdiv);
pll_freq = div_u64(pll_freq, m * outdiv);
return pll_freq;
}
@@ -110,12 +110,12 @@ static unsigned long ma35d1_calc_pll_freq(u8 mode, u32 *reg_ctl, unsigned long p
if (mode == PLL_MODE_INT) {
pll_freq = (u64)parent_rate * n;
div_u64(pll_freq, m * p);
pll_freq = div_u64(pll_freq, m * p);
} else {
x = FIELD_GET(PLL_CTL1_FRAC, reg_ctl[1]);
/* 2 decimal places floating to integer (ex. 1.23 to 123) */
n = n * 100 + ((x * 100) / FIELD_MAX(PLL_CTL1_FRAC));
pll_freq = div_u64(parent_rate * n, 100 * m * p);
/* convert 24-bit fraction to 3 decimal digits, rounding to closest */
n = n * 1000 + DIV_ROUND_CLOSEST_ULL((u64)x * 1000, 1ULL << 24);
pll_freq = div_u64((u64)parent_rate * n, 1000 * m * p);
}
return pll_freq;
}
@@ -255,32 +255,32 @@ static int ma35d1_clk_pll_determine_rate(struct clk_hw *hw,
if (req->best_parent_rate < PLL_FREF_MIN_FREQ || req->best_parent_rate > PLL_FREF_MAX_FREQ)
return -EINVAL;
ret = ma35d1_pll_find_closest(pll, req->rate, req->best_parent_rate,
reg_ctl, &pll_freq);
if (ret < 0)
return ret;
switch (pll->id) {
case CAPLL:
reg_ctl[0] = readl_relaxed(pll->ctl0_base);
pll_freq = ma35d1_calc_smic_pll_freq(reg_ctl[0], req->best_parent_rate);
req->rate = pll_freq;
return 0;
case DDRPLL:
/* Read-only PLLs: return current rate */
reg_ctl[0] = readl_relaxed(pll->ctl0_base);
if (pll->id == CAPLL) {
pll_freq = ma35d1_calc_smic_pll_freq(reg_ctl[0], req->best_parent_rate);
} else {
reg_ctl[1] = readl_relaxed(pll->ctl1_base);
pll_freq = ma35d1_calc_pll_freq(pll->mode, reg_ctl, req->best_parent_rate);
}
req->rate = pll_freq;
return 0;
case APLL:
case EPLL:
case VPLL:
reg_ctl[0] = readl_relaxed(pll->ctl0_base);
reg_ctl[1] = readl_relaxed(pll->ctl1_base);
pll_freq = ma35d1_calc_pll_freq(pll->mode, reg_ctl, req->best_parent_rate);
/* Configurable PLLs: find closest achievable rate */
ret = ma35d1_pll_find_closest(pll, req->rate, req->best_parent_rate,
reg_ctl, &pll_freq);
if (ret < 0)
return ret;
req->rate = pll_freq;
return 0;
}
req->rate = 0;
return 0;
}
+2 -13
View File
@@ -351,17 +351,6 @@ static int clk_rpm_set_rate(struct clk_hw *hw,
return 0;
}
static int clk_rpm_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
/*
* RPM handles rate rounding and we don't have a way to
* know what the rate will be, so just return whatever
* rate is requested.
*/
return 0;
}
static unsigned long clk_rpm_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
@@ -383,7 +372,7 @@ static const struct clk_ops clk_rpm_xo_ops = {
static const struct clk_ops clk_rpm_fixed_ops = {
.prepare = clk_rpm_fixed_prepare,
.unprepare = clk_rpm_fixed_unprepare,
.determine_rate = clk_rpm_determine_rate,
.determine_rate = clk_determine_rate_noop,
.recalc_rate = clk_rpm_recalc_rate,
};
@@ -391,7 +380,7 @@ static const struct clk_ops clk_rpm_ops = {
.prepare = clk_rpm_prepare,
.unprepare = clk_rpm_unprepare,
.set_rate = clk_rpm_set_rate,
.determine_rate = clk_rpm_determine_rate,
.determine_rate = clk_determine_rate_noop,
.recalc_rate = clk_rpm_recalc_rate,
};
+1 -7
View File
@@ -319,12 +319,6 @@ static int clk_rpmh_bcm_set_rate(struct clk_hw *hw, unsigned long rate,
return 0;
}
static int clk_rpmh_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
return 0;
}
static unsigned long clk_rpmh_bcm_recalc_rate(struct clk_hw *hw,
unsigned long prate)
{
@@ -337,7 +331,7 @@ static const struct clk_ops clk_rpmh_bcm_ops = {
.prepare = clk_rpmh_bcm_prepare,
.unprepare = clk_rpmh_bcm_unprepare,
.set_rate = clk_rpmh_bcm_set_rate,
.determine_rate = clk_rpmh_determine_rate,
.determine_rate = clk_determine_rate_noop,
.recalc_rate = clk_rpmh_bcm_recalc_rate,
};
+1 -12
View File
@@ -370,17 +370,6 @@ static int clk_smd_rpm_set_rate(struct clk_hw *hw, unsigned long rate,
return 0;
}
static int clk_smd_rpm_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
/*
* RPM handles rate rounding and we don't have a way to
* know what the rate will be, so just return whatever
* rate is requested.
*/
return 0;
}
static unsigned long clk_smd_rpm_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
@@ -427,7 +416,7 @@ static const struct clk_ops clk_smd_rpm_ops = {
.prepare = clk_smd_rpm_prepare,
.unprepare = clk_smd_rpm_unprepare,
.set_rate = clk_smd_rpm_set_rate,
.determine_rate = clk_smd_rpm_determine_rate,
.determine_rate = clk_determine_rate_noop,
.recalc_rate = clk_smd_rpm_recalc_rate,
};
+1 -7
View File
@@ -944,12 +944,6 @@ static unsigned long rzg2l_cpg_sipll5_recalc_rate(struct clk_hw *hw,
return pll5_rate;
}
static int rzg2l_cpg_sipll5_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
return 0;
}
static int rzg2l_cpg_sipll5_set_rate(struct clk_hw *hw,
unsigned long rate,
unsigned long parent_rate)
@@ -1021,7 +1015,7 @@ static int rzg2l_cpg_sipll5_set_rate(struct clk_hw *hw,
static const struct clk_ops rzg2l_cpg_sipll5_ops = {
.recalc_rate = rzg2l_cpg_sipll5_recalc_rate,
.determine_rate = rzg2l_cpg_sipll5_determine_rate,
.determine_rate = clk_determine_rate_noop,
.set_rate = rzg2l_cpg_sipll5_set_rate,
};
+3 -15
View File
@@ -72,18 +72,6 @@ static unsigned long acpm_clk_recalc_rate(struct clk_hw *hw,
clk->id);
}
static int acpm_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. acpm_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 acpm_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
@@ -95,7 +83,7 @@ static int acpm_clk_set_rate(struct clk_hw *hw, unsigned long rate,
static const struct clk_ops acpm_clk_ops = {
.recalc_rate = acpm_clk_recalc_rate,
.determine_rate = acpm_clk_determine_rate,
.determine_rate = clk_determine_rate_noop,
.set_rate = acpm_clk_set_rate,
};
@@ -166,8 +154,8 @@ static int acpm_clk_probe(struct platform_device *pdev)
}
static const struct platform_device_id acpm_clk_id[] = {
{ "gs101-acpm-clk" },
{}
{ .name = "gs101-acpm-clk" },
{ }
};
MODULE_DEVICE_TABLE(platform, acpm_clk_id);
+1 -7
View File
@@ -254,16 +254,10 @@ static int sprd_pll_clk_prepare(struct clk_hw *hw)
return 0;
}
static int sprd_pll_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
return 0;
}
const struct clk_ops sprd_pll_ops = {
.prepare = sprd_pll_clk_prepare,
.recalc_rate = sprd_pll_recalc_rate,
.determine_rate = sprd_pll_determine_rate,
.determine_rate = clk_determine_rate_noop,
.set_rate = sprd_pll_set_rate,
};
EXPORT_SYMBOL_GPL(sprd_pll_ops);
+1
View File
@@ -4,6 +4,7 @@
* Author: Gabriel Fernandez <gabriel.fernandez@foss.st.com> for STMicroelectronics.
*/
#include <linux/bitfield.h>
#include <linux/bus/stm32_firewall_device.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
+1
View File
@@ -4,6 +4,7 @@
* Author: Gabriel Fernandez <gabriel.fernandez@foss.st.com> for STMicroelectronics.
*/
#include <linux/bitfield.h>
#include <linux/bus/stm32_firewall_device.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
+9 -1
View File
@@ -367,7 +367,15 @@ static int tegra_bpmp_clk_get_info(struct tegra_bpmp *bpmp, unsigned int id,
if (err < 0)
return err;
strscpy(info->name, response.name, MRQ_CLK_NAME_MAXLEN);
if (dev_to_node(bpmp->dev) == NUMA_NO_NODE) {
strscpy(info->name, response.name, sizeof(info->name));
} else {
err = snprintf(info->name, sizeof(info->name), "%d-%s",
dev_to_node(bpmp->dev), response.name);
if (WARN_ON(err >= sizeof(info->name)))
return -E2BIG;
}
info->num_parents = response.num_parents;
for (i = 0; i < info->num_parents; i++)
+2 -2
View File
@@ -663,8 +663,8 @@ static int clk_wzrd_determine_rate_all(struct clk_hw *hw,
d = divider->d;
o = divider->o;
req->rate = div_u64(req->best_parent_rate * (m * 1000 + divider->m_frac),
d * (o * 1000 + divider->o_frac));
req->rate = mult_frac(req->best_parent_rate, m * 1000 + divider->m_frac,
d * (o * 1000 + divider->o_frac));
return 0;
}
+8
View File
@@ -186,7 +186,11 @@ static void __init zynq_clk_register_periph_clk(enum zynq_clk clk0,
spin_lock_init(lock);
mux_name = kasprintf(GFP_KERNEL, "%s_mux", clk_name0);
if (!mux_name)
goto err_mux_name;
div_name = kasprintf(GFP_KERNEL, "%s_div", clk_name0);
if (!div_name)
goto err_div_name;
clk_register_mux(NULL, mux_name, parents, 4,
CLK_SET_RATE_NO_REPARENT, clk_ctrl, 4, 2, 0, lock);
@@ -205,6 +209,10 @@ static void __init zynq_clk_register_periph_clk(enum zynq_clk clk0,
return;
err_div_name:
kfree(mux_name);
err_mux_name:
kfree(lock);
err:
clks[clk0] = ERR_PTR(-ENOMEM);
if (two_gates)
+1 -7
View File
@@ -90,12 +90,6 @@ static void mtk_hdmi_pll_unprepare(struct clk_hw *hw)
usleep_range(80, 100);
}
static int mtk_hdmi_pll_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
return 0;
}
static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
@@ -170,7 +164,7 @@ static const struct clk_ops mtk_hdmi_phy_pll_ops = {
.prepare = mtk_hdmi_pll_prepare,
.unprepare = mtk_hdmi_pll_unprepare,
.set_rate = mtk_hdmi_pll_set_rate,
.determine_rate = mtk_hdmi_pll_determine_rate,
.determine_rate = clk_determine_rate_noop,
.recalc_rate = mtk_hdmi_pll_recalc_rate,
};
@@ -21,12 +21,6 @@ struct airoha_cpu_pmdomain_priv {
struct generic_pm_domain pd;
};
static int airoha_cpu_pmdomain_clk_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
return 0;
}
static unsigned long airoha_cpu_pmdomain_clk_get(struct clk_hw *hw,
unsigned long parent_rate)
{
@@ -48,7 +42,7 @@ static int airoha_cpu_pmdomain_clk_is_enabled(struct clk_hw *hw)
static const struct clk_ops airoha_cpu_pmdomain_clk_ops = {
.recalc_rate = airoha_cpu_pmdomain_clk_get,
.is_enabled = airoha_cpu_pmdomain_clk_is_enabled,
.determine_rate = airoha_cpu_pmdomain_clk_determine_rate,
.determine_rate = clk_determine_rate_noop,
};
static int airoha_cpu_pmdomain_set_performance_state(struct generic_pm_domain *domain,
+2 -21
View File
@@ -310,25 +310,6 @@ static unsigned long mtk_mfg_recalc_rate_gpu(struct clk_hw *hw,
return readl(mfg->shared_mem + GF_REG_FREQ_OUT_GPU) * HZ_PER_KHZ;
}
static int mtk_mfg_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
/*
* The determine_rate callback needs to be implemented to avoid returning
* the current clock frequency, rather than something even remotely
* close to the frequency that was asked for.
*
* Instead of writing considerable amounts of possibly slow code just to
* somehow figure out which of the three PLLs to round for, or even to
* do a search through one of two OPP tables in order to find the closest
* OPP of a frequency, just return the rate as-is. This avoids devfreq
* "rounding" a request for the lowest frequency to the possibly very
* high current frequency, breaking the powersave governor in the process.
*/
return 0;
}
static unsigned long mtk_mfg_recalc_rate_stack(struct clk_hw *hw,
unsigned long parent_rate)
{
@@ -339,12 +320,12 @@ static unsigned long mtk_mfg_recalc_rate_stack(struct clk_hw *hw,
static const struct clk_ops mtk_mfg_clk_gpu_ops = {
.recalc_rate = mtk_mfg_recalc_rate_gpu,
.determine_rate = mtk_mfg_determine_rate,
.determine_rate = clk_determine_rate_noop,
};
static const struct clk_ops mtk_mfg_clk_stack_ops = {
.recalc_rate = mtk_mfg_recalc_rate_stack,
.determine_rate = mtk_mfg_determine_rate,
.determine_rate = clk_determine_rate_noop,
};
static const struct clk_init_data mtk_mfg_clk_gpu_init = {
+11
View File
@@ -83,6 +83,17 @@ config RESET_EIC7700
The driver supports eic7700 series chips and provides functionality for
asserting and deasserting resets on the chip.
config RESET_EIC7700_HSP
tristate "EIC7700 HSP Reset controller"
depends on ARCH_ESWIN || COMPILE_TEST
select AUXILIARY_BUS
help
This enables the HSP reset controller driver for ESWIN SoCs. This
driver is specific to ESWIN SoCs and should only be enabled if using
such hardware.
The driver supports EIC7700 series chips and provides functionality
for asserting and deasserting resets on the chip.
config RESET_EYEQ
bool "Mobileye EyeQ reset controller"
depends on EYEQ || COMPILE_TEST
+1
View File
@@ -15,6 +15,7 @@ obj-$(CONFIG_RESET_BERLIN) += reset-berlin.o
obj-$(CONFIG_RESET_BRCMSTB) += reset-brcmstb.o
obj-$(CONFIG_RESET_BRCMSTB_RESCAL) += reset-brcmstb-rescal.o
obj-$(CONFIG_RESET_EIC7700) += reset-eic7700.o
obj-$(CONFIG_RESET_EIC7700_HSP) += reset-eic7700-hsp.o
obj-$(CONFIG_RESET_EYEQ) += reset-eyeq.o
obj-$(CONFIG_RESET_GPIO) += reset-gpio.o
obj-$(CONFIG_RESET_HSDK) += reset-hsdk.o
+113
View File
@@ -0,0 +1,113 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2026, Beijing ESWIN Computing Technology Co., Ltd..
* All rights reserved.
*
* ESWIN EIC7700 HSP Reset Driver
*
* Authors: Xuyang Dong <dongxuyang@eswincomputing.com>
*/
#include <linux/auxiliary_bus.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/reset-controller.h>
#include <dt-bindings/reset/eswin,eic7700-hspcrg.h>
/**
* struct eic7700_hsp_reset_data - reset controller information structure
* @rcdev: reset controller entity
* @regmap: regmap handle containing the memory-mapped reset registers
*/
struct eic7700_hsp_reset_data {
struct reset_controller_dev rcdev;
struct regmap *regmap;
};
struct eic7700_hsp_reg {
u32 reg;
u32 bit;
bool active_low;
};
static inline struct eic7700_hsp_reset_data *
to_eic7700_hsp_reset(struct reset_controller_dev *rcdev)
{
return container_of(rcdev, struct eic7700_hsp_reset_data, rcdev);
}
static const struct eic7700_hsp_reg eic7700_hsp_reset[] = {
[EIC7700_HSP_RST_SATA_P0] = {0x340, BIT(0), false},
[EIC7700_HSP_RST_SATA_PHY] = {0x340, BIT(1), false},
[EIC7700_HSP_RST_USB0] = {0x800, BIT(24), true},
[EIC7700_HSP_RST_USB1] = {0x900, BIT(24), true},
[EIC7700_HSP_RST_USB0_PHY] = {0x800, BIT(25), false},
[EIC7700_HSP_RST_USB1_PHY] = {0x900, BIT(25), false},
};
static int eic7700_hsp_reset_assert(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct eic7700_hsp_reset_data *data = to_eic7700_hsp_reset(rcdev);
return regmap_assign_bits(data->regmap, eic7700_hsp_reset[id].reg,
eic7700_hsp_reset[id].bit,
!eic7700_hsp_reset[id].active_low);
}
static int eic7700_hsp_reset_deassert(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct eic7700_hsp_reset_data *data = to_eic7700_hsp_reset(rcdev);
return regmap_assign_bits(data->regmap, eic7700_hsp_reset[id].reg,
eic7700_hsp_reset[id].bit,
eic7700_hsp_reset[id].active_low);
}
static const struct reset_control_ops eic7700_hsp_reset_ops = {
.assert = eic7700_hsp_reset_assert,
.deassert = eic7700_hsp_reset_deassert,
};
static int eic7700_hsp_reset_probe(struct auxiliary_device *adev,
const struct auxiliary_device_id *id)
{
struct eic7700_hsp_reset_data *data;
struct device *dev = &adev->dev;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->regmap = dev_get_regmap(dev->parent, NULL);
if (!data->regmap)
return dev_err_probe(dev, -ENODEV, "failed to get regmap!\n");
data->rcdev.owner = THIS_MODULE;
data->rcdev.ops = &eic7700_hsp_reset_ops;
data->rcdev.of_node = dev->parent->of_node;
data->rcdev.dev = dev;
data->rcdev.nr_resets = ARRAY_SIZE(eic7700_hsp_reset);
return devm_reset_controller_register(dev, &data->rcdev);
}
static const struct auxiliary_device_id eic7700_hsp_reset_ids[] = {
{ .name = "clk_eic7700_hsp.hsp-reset", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(auxiliary, eic7700_hsp_reset_ids);
static struct auxiliary_driver eic7700_hsp_reset_driver = {
.probe = eic7700_hsp_reset_probe,
.id_table = eic7700_hsp_reset_ids,
};
module_auxiliary_driver(eic7700_hsp_reset_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Xuyang Dong <dongxuyang@eswincomputing.com>");
MODULE_DESCRIPTION("ESWIN EIC7700 HSP Reset Controller Driver");
+14
View File
@@ -0,0 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
/*
* Copyright 2025 NXP
*/
#ifndef __DT_BINDINGS_CLOCK_H
#define __DT_BINDINGS_CLOCK_H
#define CLK_SSC_NO_SPREAD 0
#define CLK_SSC_CENTER_SPREAD 1
#define CLK_SSC_UP_SPREAD 2
#define CLK_SSC_DOWN_SPREAD 3
#endif /* __DT_BINDINGS_CLOCK_H */
@@ -0,0 +1,33 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
/*
* Copyright 2026, Beijing ESWIN Computing Technology Co., Ltd..
* All rights reserved.
*
* Device Tree binding constants for EIC7700 HSP clock controller.
*
* Authors: Xuyang Dong <dongxuyang@eswincomputing.com>
*/
#ifndef _DT_BINDINGS_ESWIN_EIC7700_HSPCRG_CLOCK_H_
#define _DT_BINDINGS_ESWIN_EIC7700_HSPCRG_CLOCK_H_
#define EIC7700_HSP_CLK_FAC_CFG_DIV2 0
#define EIC7700_HSP_CLK_FAC_CFG_DIV4 1
#define EIC7700_HSP_CLK_FAC_MMC_DIV10 2
#define EIC7700_HSP_CLK_MUX_EMMC_3MUX1 3
#define EIC7700_HSP_CLK_MUX_SD0_3MUX1 4
#define EIC7700_HSP_CLK_MUX_SD1_3MUX1 5
#define EIC7700_HSP_CLK_MUX_EMMC_CQE_2MUX1 6
#define EIC7700_HSP_CLK_MUX_SD0_CQE_2MUX1 7
#define EIC7700_HSP_CLK_MUX_SD1_CQE_2MUX1 8
#define EIC7700_HSP_CLK_GATE_MSHC0_TMR 9
#define EIC7700_HSP_CLK_GATE_EMMC 10
#define EIC7700_HSP_CLK_GATE_MSHC1_TMR 11
#define EIC7700_HSP_CLK_GATE_SD0 12
#define EIC7700_HSP_CLK_GATE_MSHC2_TMR 13
#define EIC7700_HSP_CLK_GATE_SD1 14
#define EIC7700_HSP_CLK_GATE_USB0 15
#define EIC7700_HSP_CLK_GATE_USB1 16
#define EIC7700_HSP_CLK_GATE_SATA 17
#endif /* _DT_BINDINGS_ESWIN_EIC7700_HSPCRG_CLOCK_H_ */
@@ -0,0 +1,21 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
/*
* Copyright 2026, Beijing ESWIN Computing Technology Co., Ltd..
* All rights reserved.
*
* Device Tree binding constants for EIC7700 HSP reset controller.
*
* Authors: Xuyang Dong <dongxuyang@eswincomputing.com>
*/
#ifndef _DT_BINDINGS_ESWIN_EIC7700_HSPCRG_RESET_H_
#define _DT_BINDINGS_ESWIN_EIC7700_HSPCRG_RESET_H_
#define EIC7700_HSP_RST_SATA_P0 0
#define EIC7700_HSP_RST_SATA_PHY 1
#define EIC7700_HSP_RST_USB0 2
#define EIC7700_HSP_RST_USB1 3
#define EIC7700_HSP_RST_USB0_PHY 4
#define EIC7700_HSP_RST_USB1_PHY 5
#endif /* _DT_BINDINGS_ESWIN_EIC7700_HSPCRG_RESET_H_ */
+61 -17
View File
@@ -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);
@@ -1431,11 +1472,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)
{