Commit dc2535be authored by Linus Torvalds's avatar Linus Torvalds

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

Pull clk subsystem updates from Stephen Boyd:
 "We have a fairly balanced mix of clk driver updates and clk framework
  updates this time around. It's the usual pile of new drivers for new
  hardware out there and the normal small fixes and updates, but then we
  have some core framework changes too.

  In the core framework, we introduce support for a clk_get_optional()
  API to get clks that may not always be populated and a way to devm
  manage clkdev lookups registered by provider drivers. We also do some
  refactoring to simplify the interface between clkdev and the common
  clk framework so we can reuse the DT parsing and clk_get() path in
  provider drivers in the future. This work will continue in the next
  few cycles while we convert how providers specify clk parents.

  On the driver side, the biggest part of the dirstat is the Amlogic clk
  driver that got support for the G12A SoC. It dominates with almost
  half the overall diff, while the second largest part of the diff is in
  the i.MX clk driver that gained support for imx8mm SoCs. After that,
  we have the Actions Semiconductor and Qualcomm drivers rounding out
  the big part of the dirstat because they both got new hardware support
  for SoCs. The rest is just various updates and non-critical fixes for
  existing drivers.

  Core:
   - Convert a few clk bindings to JSON schema format
   - Add a {devm_}clk_get_optional() API
   - Add devm_clk_hw_register_clkdev() API to manage clkdev lookups
   - Start rewriting clk parent registration and supporting device links
     by moving around code that supports clk_get() and DT parsing of the
     'clocks' property

  New Drivers:
   - Add Qualcomm MSM8998 RPM managed clks
   - IPA clk support on Qualcomm RPMh clk controllers
   - Actions Semi S500 SoC clk support
   - Support for fixed rate clks populated from an MMIO register
   - Add RPC (QSPI/HyperFLASH) clocks on Renesas R-Car V3H
   - Add TMU (timer) clocks on Renesas RZ/G2E
   - Add Amlogic G12A Always-On Clock Controller
   - Add 32k clock generation for Amlogic AXG
   - Add support for the Mali GPU clocks on Amlogic Meson8
   - Add Amlogic G12A EE clock controller driver
   - Add missing CANFD clocks on Renesas RZ/G2M and RZ/G2E
   - Add i.MX8MM SoC clk driver support

  Removed Drivers:
   - Remove clps711x driver as the board support is gone

  Updates:
   - 3rd ECO fix for Mediatek MT2712 SoCs
   - Updates for Qualcomm MSM8998 GCC clks
   - Random static analysis fixes for clk drivers
   - Support for sleeping gpios in the clk-gpio type
   - Minor fixes for STM32MP1 clk driver (parents, critical flag, etc.)
   - Split LCDC into two clks on the Marvell MMP2 SoC
   - Various DT of_node refcount fixes
   - Get rid of CLK_IS_BASIC from TI code (yay!)
   - TI Autoidle clk support
   - Fix Amlogic Meson8 APB clock ID name
   - Claim input clocks through DT for Amlogic AXG and GXBB
   - Correct the DU (display unit) parent clock on Renesas RZ/G2E
   - Exynos5433 IMEM CMU crypto clk support (SlimSS)
   - Fix for the PLL-MIPI on the Allwinner A23
   - Fix Rockchip rk3328 PLL rate calculation
   - Add SET_RATE_PARENT flag on display clk of Rockhip rk3066
   - i.MX SCU clk driver clk_set_parent() and cpufreq support"

* tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (150 commits)
  dt-bindings: clock: imx8mq: Fix numbering overlaps and gaps
  clk: ti: clkctrl: Fix clkdm_name regression for TI_CLK_CLKCTRL_COMPAT
  clk: fixup default index for of_clk_get_by_name()
  clk: Move of_clk_*() APIs into clk.c from clkdev.c
  clk: Inform the core about consumer devices
  clk: Introduce of_clk_get_hw_from_clkspec()
  clk: core: clarify the check for runtime PM
  clk: Combine __clk_get() and __clk_create_clk()
  clk: imx8mq: add GPIO clocks to clock tree
  clk: mediatek: correct cpu clock name for MT8173 SoC
  clk: imx: Refactor entire sccg pll clk
  clk: imx: scu: add cpu frequency scaling support
  clk: mediatek: Mark bus and DRAM related clocks as critical
  clk: mediatek: Add flags to mtk_gate
  clk: mediatek: Add MUX_FLAGS macro
  clk: qcom: gcc-sdm845: Define parent of PCIe PIPE clocks
  clk: ingenic: Remove set but not used variable 'enable'
  clk: at91: programmable: remove unneeded register read
  clk: mediatek: using CLK_MUX_ROUND_CLOSEST for the clock of dpi1_sel
  clk: mediatek: add MUX_GATE_FLAGS_2
  ...
parents fa3d493f 010d5166
......@@ -2,13 +2,14 @@
The Actions Semi Owl Clock Management Unit generates and supplies clock
to various controllers within the SoC. The clock binding described here is
applicable to S900 and S700 SoC's.
applicable to S900, S700 and S500 SoC's.
Required Properties:
- compatible: should be one of the following,
"actions,s900-cmu"
"actions,s700-cmu"
"actions,s500-cmu"
- reg: physical base address of the controller and length of memory mapped
region.
- clocks: Reference to the parent clocks ("hosc", "losc")
......@@ -19,8 +20,8 @@ Each clock is assigned an identifier, and client nodes can use this identifier
to specify the clock which they consume.
All available clocks are defined as preprocessor macros in corresponding
dt-bindings/clock/actions,s900-cmu.h or actions,s700-cmu.h header and can be
used in device tree sources.
dt-bindings/clock/actions,s900-cmu.h or actions,s700-cmu.h or
actions,s500-cmu.h header and can be used in device tree sources.
External clocks:
......
......@@ -10,6 +10,7 @@ Required Properties:
- GXL (S905X, S905D) : "amlogic,meson-gxl-aoclkc"
- GXM (S912) : "amlogic,meson-gxm-aoclkc"
- AXG (A113D, A113X) : "amlogic,meson-axg-aoclkc"
- G12A (S905X2, S905D2, S905Y2) : "amlogic,meson-g12a-aoclkc"
followed by the common "amlogic,meson-gx-aoclkc"
- clocks: list of clock phandle, one for each entry clock-names.
- clock-names: should contain the following:
......
......@@ -9,6 +9,7 @@ Required Properties:
"amlogic,gxbb-clkc" for GXBB SoC,
"amlogic,gxl-clkc" for GXL and GXM SoC,
"amlogic,axg-clkc" for AXG SoC.
"amlogic,g12a-clkc" for G12A SoC.
- clocks : list of clock phandle, one for each entry clock-names.
- clock-names : should contain the following:
* "xtal": the platform xtal
......
......@@ -50,6 +50,8 @@ Required Properties:
IPs.
- "samsung,exynos5433-cmu-cam1" - clock controller compatible for CMU_CAM1
which generates clocks for Cortex-A5/MIPI_CSIS2/FIMC-LITE_C/FIMC-FD IPs.
- "samsung,exynos5433-cmu-imem" - clock controller compatible for CMU_IMEM
which generates clocks for SSS (Security SubSystem) and SlimSSS IPs.
- reg: physical base address of the controller and length of memory mapped
region.
......@@ -168,6 +170,12 @@ Required Properties:
- aclk_cam1_400
- aclk_cam1_552
Input clocks for imem clock controller:
- oscclk
- aclk_imem_sssx_266
- aclk_imem_266
- aclk_imem_200
Optional properties:
- power-domains: a phandle to respective power domain node as described by
generic PM domain bindings (see power/power_domain.txt for more
......@@ -469,6 +477,21 @@ Example 2: Examples of clock controller nodes are listed below.
power-domains = <&pd_cam1>;
};
cmu_imem: clock-controller@11060000 {
compatible = "samsung,exynos5433-cmu-imem";
reg = <0x11060000 0x1000>;
#clock-cells = <1>;
clock-names = "oscclk",
"aclk_imem_sssx_266",
"aclk_imem_266",
"aclk_imem_200";
clocks = <&xxti>,
<&cmu_top CLK_DIV_ACLK_IMEM_SSSX_266>,
<&cmu_top CLK_DIV_ACLK_IMEM_266>,
<&cmu_top CLK_DIV_ACLK_IMEM_200>;
};
Example 3: UART controller node that consumes the clock generated by the clock
controller.
......
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/fixed-clock.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Binding for simple fixed-rate clock sources
maintainers:
- Michael Turquette <mturquette@baylibre.com>
- Stephen Boyd <sboyd@kernel.org>
properties:
compatible:
const: fixed-clock
"#clock-cells":
const: 0
clock-frequency: true
clock-accuracy:
description: accuracy of clock in ppb (parts per billion).
$ref: /schemas/types.yaml#/definitions/uint32
clock-output-names:
maxItems: 1
required:
- compatible
- "#clock-cells"
- clock-frequency
additionalProperties: false
examples:
- |
clock {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <1000000000>;
clock-accuracy = <100>;
};
...
Binding for simple fixed factor rate clock sources.
This binding uses the common clock binding[1].
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
Required properties:
- compatible : shall be "fixed-factor-clock".
- #clock-cells : from common clock binding; shall be set to 0.
- clock-div: fixed divider.
- clock-mult: fixed multiplier.
- clocks: parent clock.
Optional properties:
- clock-output-names : From common clock binding.
Some clocks that require special treatments are also handled by that
driver, with the compatibles:
- allwinner,sun4i-a10-pll3-2x-clk
Example:
clock {
compatible = "fixed-factor-clock";
clocks = <&parentclk>;
#clock-cells = <0>;
clock-div = <2>;
clock-mult = <1>;
};
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/clock/fixed-factor-clock.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Binding for simple fixed factor rate clock sources
maintainers:
- Michael Turquette <mturquette@baylibre.com>
- Stephen Boyd <sboyd@kernel.org>
properties:
compatible:
enum:
- allwinner,sun4i-a10-pll3-2x-clk
- fixed-factor-clock
"#clock-cells":
const: 0
clocks:
maxItems: 1
clock-div:
description: Fixed divider
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
- minimum: 1
clock-mult:
description: Fixed multiplier
$ref: /schemas/types.yaml#/definitions/uint32
clock-output-names:
maxItems: 1
required:
- compatible
- clocks
- "#clock-cells"
- clock-div
- clock-mult
additionalProperties: false
examples:
- |
clock {
compatible = "fixed-factor-clock";
clocks = <&parentclk>;
#clock-cells = <0>;
clock-div = <2>;
clock-mult = <1>;
};
...
Binding for simple fixed-rate clock sources.
Binding for simple memory mapped io fixed-rate clock sources.
The driver reads a clock frequency value from a single 32-bit memory mapped
I/O register and registers it as a fixed rate clock.
It was designed for test systems, like FPGA, not for complete, finished SoCs.
This binding uses the common clock binding[1].
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
Required properties:
- compatible : shall be "fixed-clock".
- compatible : shall be "fixed-mmio-clock".
- #clock-cells : from common clock binding; shall be set to 0.
- clock-frequency : frequency of clock in Hz. Should be a single cell.
- reg : Address and length of the clock value register set.
Optional properties:
- clock-accuracy : accuracy of clock in ppb (parts per billion).
Should be a single cell.
- clock-output-names : From common clock binding.
Example:
clock {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <1000000000>;
clock-accuracy = <100>;
};
sysclock: sysclock@fd020004 {
#clock-cells = <0>;
compatible = "fixed-mmio-clock";
reg = <0xfd020004 0x4>;
};
* Clock bindings for NXP i.MX8M Mini
Required properties:
- compatible: Should be "fsl,imx8mm-ccm"
- reg: Address and length of the register set
- #clock-cells: Should be <1>
- clocks: list of clock specifiers, must contain an entry for each required
entry in clock-names
- clock-names: should include the following entries:
- "osc_32k"
- "osc_24m"
- "clk_ext1"
- "clk_ext2"
- "clk_ext3"
- "clk_ext4"
clk: clock-controller@30380000 {
compatible = "fsl,imx8mm-ccm";
reg = <0x0 0x30380000 0x0 0x10000>;
#clock-cells = <1>;
clocks = <&osc_32k>, <&osc_24m>, <&clk_ext1>, <&clk_ext2>,
<&clk_ext3>, <&clk_ext4>;
clock-names = "osc_32k", "osc_24m", "clk_ext1", "clk_ext2",
"clk_ext3", "clk_ext4";
};
The clock consumer should specify the desired clock by having the clock
ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx8mm-clock.h
for the full list of i.MX8M Mini clock IDs.
......@@ -16,6 +16,7 @@ Required properties :
"qcom,rpmcc-msm8974", "qcom,rpmcc"
"qcom,rpmcc-apq8064", "qcom,rpmcc"
"qcom,rpmcc-msm8996", "qcom,rpmcc"
"qcom,rpmcc-msm8998", "qcom,rpmcc"
"qcom,rpmcc-qcs404", "qcom,rpmcc"
- #clock-cells : shall contain 1
......
......@@ -242,9 +242,11 @@ certainly invest a bit more effort into libata core layer).
CLOCK
devm_clk_get()
devm_clk_get_optional()
devm_clk_put()
devm_clk_hw_register()
devm_of_clk_add_hw_provider()
devm_clk_hw_register_clkdev()
DMA
dmaenginem_async_device_register()
......
......@@ -1002,8 +1002,10 @@ static int _enable_clocks(struct omap_hwmod *oh)
clk_enable(oh->_clk);
list_for_each_entry(os, &oh->slave_ports, node) {
if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE))
if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE)) {
omap2_clk_deny_idle(os->_clk);
clk_enable(os->_clk);
}
}
/* The opt clocks are controlled by the device driver. */
......@@ -1055,8 +1057,10 @@ static int _disable_clocks(struct omap_hwmod *oh)
clk_disable(oh->_clk);
list_for_each_entry(os, &oh->slave_ports, node) {
if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE))
if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE)) {
clk_disable(os->_clk);
omap2_clk_allow_idle(os->_clk);
}
}
if (oh->flags & HWMOD_OPT_CLKS_NEEDED)
......@@ -2436,9 +2440,13 @@ static void _setup_iclk_autoidle(struct omap_hwmod *oh)
continue;
if (os->flags & OCPIF_SWSUP_IDLE) {
/* XXX omap_iclk_deny_idle(c); */
/*
* we might have multiple users of one iclk with
* different requirements, disable autoidle when
* the module is enabled, e.g. dss iclk
*/
} else {
/* XXX omap_iclk_allow_idle(c); */
/* we are enabling autoidle afterwards anyways */
clk_enable(os->_clk);
}
}
......
......@@ -18,7 +18,7 @@
#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/platform_data/clk-lpss.h>
#include <linux/platform_data/x86/clk-lpss.h>
#include <linux/platform_data/x86/pmc_atom.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
......
......@@ -290,6 +290,12 @@ config COMMON_CLK_BD718XX
This driver supports ROHM BD71837 and ROHM BD71847
PMICs clock gates.
config COMMON_CLK_FIXED_MMIO
bool "Clock driver for Memory Mapped Fixed values"
depends on COMMON_CLK && OF
help
Support for Memory Mapped IO Fixed clocks
source "drivers/clk/actions/Kconfig"
source "drivers/clk/bcm/Kconfig"
source "drivers/clk/hisilicon/Kconfig"
......
......@@ -27,6 +27,7 @@ obj-$(CONFIG_COMMON_CLK_CDCE925) += clk-cdce925.o
obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o
obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o
obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o
obj-$(CONFIG_COMMON_CLK_FIXED_MMIO) += clk-fixed-mmio.o
obj-$(CONFIG_COMMON_CLK_GEMINI) += clk-gemini.o
obj-$(CONFIG_COMMON_CLK_ASPEED) += clk-aspeed.o
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
......@@ -78,7 +79,7 @@ obj-$(CONFIG_ARCH_K3) += keystone/
obj-$(CONFIG_ARCH_KEYSTONE) += keystone/
obj-$(CONFIG_MACH_LOONGSON32) += loongson1/
obj-y += mediatek/
obj-$(CONFIG_COMMON_CLK_AMLOGIC) += meson/
obj-$(CONFIG_ARCH_MESON) += meson/
obj-$(CONFIG_MACH_PIC32) += microchip/
ifeq ($(CONFIG_COMMON_CLK), y)
obj-$(CONFIG_ARCH_MMP) += mmp/
......
......@@ -9,6 +9,11 @@ if CLK_ACTIONS
# SoC Drivers
config CLK_OWL_S500
bool "Support for the Actions Semi OWL S500 clocks"
depends on ARCH_ACTIONS || COMPILE_TEST
default ARCH_ACTIONS
config CLK_OWL_S700
bool "Support for the Actions Semi OWL S700 clocks"
depends on (ARM64 && ARCH_ACTIONS) || COMPILE_TEST
......
......@@ -10,5 +10,6 @@ clk-owl-y += owl-pll.o
clk-owl-y += owl-reset.o
# SoC support
obj-$(CONFIG_CLK_OWL_S500) += owl-s500.o
obj-$(CONFIG_CLK_OWL_S700) += owl-s700.o
obj-$(CONFIG_CLK_OWL_S900) += owl-s900.o
......@@ -179,7 +179,7 @@ static int owl_pll_set_rate(struct clk_hw *hw, unsigned long rate,
regmap_write(common->regmap, pll_hw->reg, reg);
udelay(PLL_STABILITY_WAIT_US);
udelay(pll_hw->delay);
return 0;
}
......
......@@ -13,6 +13,8 @@
#include "owl-common.h"
#define OWL_PLL_DEF_DELAY 50
/* last entry should have rate = 0 */
struct clk_pll_table {
unsigned int val;
......@@ -27,6 +29,7 @@ struct owl_pll_hw {
u8 width;
u8 min_mul;
u8 max_mul;
u8 delay;
const struct clk_pll_table *table;
};
......@@ -36,7 +39,7 @@ struct owl_pll {
};
#define OWL_PLL_HW(_reg, _bfreq, _bit_idx, _shift, \
_width, _min_mul, _max_mul, _table) \
_width, _min_mul, _max_mul, _delay, _table) \
{ \
.reg = _reg, \
.bfreq = _bfreq, \
......@@ -45,6 +48,7 @@ struct owl_pll {
.width = _width, \
.min_mul = _min_mul, \
.max_mul = _max_mul, \
.delay = _delay, \
.table = _table, \
}
......@@ -52,8 +56,8 @@ struct owl_pll {
_shift, _width, _min_mul, _max_mul, _table, _flags) \
struct owl_pll _struct = { \
.pll_hw = OWL_PLL_HW(_reg, _bfreq, _bit_idx, _shift, \
_width, _min_mul, \
_max_mul, _table), \
_width, _min_mul, _max_mul, \
OWL_PLL_DEF_DELAY, _table), \
.common = { \
.regmap = NULL, \
.hw.init = CLK_HW_INIT(_name, \
......@@ -67,8 +71,23 @@ struct owl_pll {
_shift, _width, _min_mul, _max_mul, _table, _flags) \
struct owl_pll _struct = { \
.pll_hw = OWL_PLL_HW(_reg, _bfreq, _bit_idx, _shift, \
_width, _min_mul, \
_max_mul, _table), \
_width, _min_mul, _max_mul, \
OWL_PLL_DEF_DELAY, _table), \
.common = { \
.regmap = NULL, \
.hw.init = CLK_HW_INIT_NO_PARENT(_name, \
&owl_pll_ops, \
_flags), \
}, \
}
#define OWL_PLL_NO_PARENT_DELAY(_struct, _name, _reg, _bfreq, _bit_idx, \
_shift, _width, _min_mul, _max_mul, _delay, _table, \
_flags) \
struct owl_pll _struct = { \
.pll_hw = OWL_PLL_HW(_reg, _bfreq, _bit_idx, _shift, \
_width, _min_mul, _max_mul, \
_delay, _table), \
.common = { \
.regmap = NULL, \
.hw.init = CLK_HW_INIT_NO_PARENT(_name, \
......@@ -78,7 +97,6 @@ struct owl_pll {
}
#define mul_mask(m) ((1 << ((m)->width)) - 1)
#define PLL_STABILITY_WAIT_US (50)
static inline struct owl_pll *hw_to_owl_pll(const struct clk_hw *hw)
{
......
This diff is collapsed.
......@@ -340,7 +340,12 @@ static long clk_audio_pll_pmc_round_rate(struct clk_hw *hw, unsigned long rate,
pr_debug("A PLL/PMC: %s, rate = %lu (parent_rate = %lu)\n", __func__,
rate, *parent_rate);
for (div = 1; div <= AUDIO_PLL_QDPMC_MAX; div++) {
if (!rate)
return 0;
best_parent_rate = clk_round_rate(pclk->clk, 1);
div = max(best_parent_rate / rate, 1UL);
for (; div <= AUDIO_PLL_QDPMC_MAX; div++) {
best_parent_rate = clk_round_rate(pclk->clk, rate * div);
tmp_rate = best_parent_rate / div;
tmp_diff = abs(rate - tmp_rate);
......@@ -350,6 +355,8 @@ static long clk_audio_pll_pmc_round_rate(struct clk_hw *hw, unsigned long rate,
best_rate = tmp_rate;
best_diff = tmp_diff;
tmp_qd = div;
if (!best_diff)
break; /* got exact match */
}
}
......
......@@ -132,11 +132,8 @@ static int clk_programmable_set_rate(struct clk_hw *hw, unsigned long rate,
struct clk_programmable *prog = to_clk_programmable(hw);
const struct clk_programmable_layout *layout = prog->layout;
unsigned long div = parent_rate / rate;
unsigned int pckr;
int shift = 0;
regmap_read(prog->regmap, AT91_PMC_PCKR(prog->id), &pckr);
if (!div)
return -EINVAL;
......
......@@ -241,13 +241,14 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
parent_names[2] = "plladivck";
parent_names[3] = "utmick";
parent_names[4] = "masterck";
parent_names[5] = "audiopll_pmcck";
for (i = 0; i < 3; i++) {
char name[6];
snprintf(name, sizeof(name), "prog%d", i);
hw = at91_clk_register_programmable(regmap, name,
parent_names, 5, i,
parent_names, 6, i,
&at91sam9x5_programmable_layout);
if (IS_ERR(hw))
goto err_free;
......
......@@ -44,21 +44,21 @@ struct clps711x_clk {
struct clk_hw_onecell_data clk_data;
};
static struct clps711x_clk * __init _clps711x_clk_init(void __iomem *base,
u32 fref)
static void __init clps711x_clk_init_dt(struct device_node *np)
{
u32 tmp, f_cpu, f_pll, f_bus, f_tim, f_pwm, f_spi;
u32 tmp, f_cpu, f_pll, f_bus, f_tim, f_pwm, f_spi, fref = 0;
struct clps711x_clk *clps711x_clk;
unsigned i;
void __iomem *base;
WARN_ON(of_property_read_u32(np, "startup-frequency", &fref));
if (!base)
return ERR_PTR(-ENOMEM);
base = of_iomap(np, 0);
BUG_ON(!base);
clps711x_clk = kzalloc(struct_size(clps711x_clk, clk_data.hws,
CLPS711X_CLK_MAX),
GFP_KERNEL);
if (!clps711x_clk)
return ERR_PTR(-ENOMEM);
BUG_ON(!clps711x_clk);
spin_lock_init(&clps711x_clk->lock);
......@@ -137,52 +137,13 @@ static struct clps711x_clk * __init _clps711x_clk_init(void __iomem *base,
clk_hw_register_fixed_factor(NULL, "uart", "bus", 0, 1, 10);
clps711x_clk->clk_data.hws[CLPS711X_CLK_TICK] =
clk_hw_register_fixed_rate(NULL, "tick", NULL, 0, 64);
for (i = 0; i < CLPS711X_CLK_MAX; i++)
if (IS_ERR(clps711x_clk->clk_data.hws[i]))
for (tmp = 0; tmp < CLPS711X_CLK_MAX; tmp++)
if (IS_ERR(clps711x_clk->clk_data.hws[tmp]))
pr_err("clk %i: register failed with %ld\n",
i, PTR_ERR(clps711x_clk->clk_data.hws[i]));
return clps711x_clk;
}
void __init clps711x_clk_init(void __iomem *base)
{
struct clps711x_clk *clps711x_clk;
clps711x_clk = _clps711x_clk_init(base, 73728000);
BUG_ON(IS_ERR(clps711x_clk));
/* Clocksource */
clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_TIMER1],
NULL, "clps711x-timer.0");
clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_TIMER2],
NULL, "clps711x-timer.1");
/* Drivers */
clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_PWM],
NULL, "clps711x-pwm");
clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_UART],
NULL, "clps711x-uart.0");
clk_hw_register_clkdev(clps711x_clk->clk_data.hws[CLPS711X_CLK_UART],
NULL, "clps711x-uart.1");
}
#ifdef CONFIG_OF
static void __init clps711x_clk_init_dt(struct device_node *np)
{
void __iomem *base = of_iomap(np, 0);
struct clps711x_clk *clps711x_clk;
u32 fref = 0;
WARN_ON(of_property_read_u32(np, "startup-frequency", &fref));
clps711x_clk = _clps711x_clk_init(base, fref);
BUG_ON(IS_ERR(clps711x_clk));
tmp, PTR_ERR(clps711x_clk->clk_data.hws[tmp]));
clps711x_clk->clk_data.num = CLPS711X_CLK_MAX;
of_clk_add_hw_provider(np, of_clk_hw_onecell_get,
&clps711x_clk->clk_data);
}
CLK_OF_DECLARE(clps711x, "cirrus,ep7209-clk", clps711x_clk_init_dt);
#endif
......@@ -29,6 +29,17 @@ struct clk *devm_clk_get(struct device *dev, const char *id)
}
EXPORT_SYMBOL(devm_clk_get);
struct clk *devm_clk_get_optional(struct device *dev, const char *id)
{
struct clk *clk = devm_clk_get(dev, id);
if (clk == ERR_PTR(-ENOENT))
return NULL;
return clk;
}
EXPORT_SYMBOL(devm_clk_get_optional);
struct clk_bulk_devres {
struct clk_bulk_data *clks;
int num_clks;
......
// SPDX-License-Identifier: GPL-2.0
/*
* Memory Mapped IO Fixed clock driver
*
* Copyright (C) 2018 Cadence Design Systems, Inc.
*
* Authors:
* Jan Kotas <jank@cadence.com>
*/
#include <linux/clk-provider.h>
#include <linux/of_address.h>
#include <linux/module.h>
#include <linux/platform_device.h>
static struct clk_hw *fixed_mmio_clk_setup(struct device_node *node)
{
struct clk_hw *clk;
const char *clk_name = node->name;
void __iomem *base;
u32 freq;
int ret;
base = of_iomap(node, 0);
if (!base) {
pr_err("%pOFn: failed to map address\n", node);
return ERR_PTR(-EIO);
}
freq = readl(base);
iounmap(base);
of_property_read_string(node, "clock-output-names", &clk_name);
clk = clk_hw_register_fixed_rate(NULL, clk_name, NULL, 0, freq);
if (IS_ERR(clk)) {
pr_err("%pOFn: failed to register fixed rate clock\n", node);
return clk;
}
ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, clk);
if (ret) {
pr_err("%pOFn: failed to add clock provider\n", node);
clk_hw_unregister(clk);
clk = ERR_PTR(ret);
}
return clk;
}
static void __init of_fixed_mmio_clk_setup(struct device_node *node)
{
fixed_mmio_clk_setup(node);
}
CLK_OF_DECLARE(fixed_mmio_clk, "fixed-mmio-clock", of_fixed_mmio_clk_setup);
/**
* This is not executed when of_fixed_mmio_clk_setup succeeded.
*/
static int of_fixed_mmio_clk_probe(struct platform_device *pdev)
{
struct clk_hw *clk;
clk = fixed_mmio_clk_setup(pdev->dev.of_node);
if (IS_ERR(clk))
return PTR_ERR(clk);
platform_set_drvdata(pdev, clk);
return 0;
}
static int of_fixed_mmio_clk_remove(struct platform_device *pdev)
{
struct clk_hw *clk = platform_get_drvdata(pdev);
of_clk_del_provider(pdev->dev.of_node);
clk_hw_unregister_fixed_rate(clk);
return 0;
}
static const struct of_device_id of_fixed_mmio_clk_ids[] = {
{ .compatible = "fixed-mmio-clock" },
{ }
};
MODULE_DEVICE_TABLE(of, of_fixed_mmio_clk_ids);
static struct platform_driver of_fixed_mmio_clk_driver = {
.driver = {
.name = "of_fixed_mmio_clk",
.of_match_table = of_fixed_mmio_clk_ids,
},
.probe = of_fixed_mmio_clk_probe,
.remove = of_fixed_mmio_clk_remove,
};
module_platform_driver(of_fixed_mmio_clk_driver);
MODULE_AUTHOR("Jan Kotas <jank@cadence.com>");
MODULE_DESCRIPTION("Memory Mapped IO Fixed clock driver");
MODULE_LICENSE("GPL v2");
......@@ -79,7 +79,7 @@ static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long m, n;
u64 ret;
if (!rate || rate >= *parent_rate)
if (!rate || (!clk_hw_can_set_rate_parent(hw) && rate >= *parent_rate))
return *parent_rate;
if (fd->approximation)
......
......@@ -58,6 +58,35 @@ const struct clk_ops clk_gpio_gate_ops = {
};
EXPORT_SYMBOL_GPL(clk_gpio_gate_ops);
static int clk_sleeping_gpio_gate_prepare(struct clk_hw *hw)
{
struct clk_gpio *clk = to_clk_gpio(hw);
gpiod_set_value_cansleep(clk->gpiod, 1);
return 0;
}
static void clk_sleeping_gpio_gate_unprepare(struct clk_hw *hw)
{
struct clk_gpio *clk = to_clk_gpio(hw);
gpiod_set_value_cansleep(clk->gpiod, 0);
}
static int clk_sleeping_gpio_gate_is_prepared(struct clk_hw *hw)
{
struct clk_gpio *clk = to_clk_gpio(hw);
return gpiod_get_value_cansleep(clk->gpiod);
}
static const struct clk_ops clk_sleeping_gpio_gate_ops = {
.prepare = clk_sleeping_gpio_gate_prepare,
.unprepare = clk_sleeping_gpio_gate_unprepare,
.is_prepared = clk_sleeping_gpio_gate_is_prepared,
};
/**
* DOC: basic clock multiplexer which can be controlled with a gpio output
* Traits of this clock:
......@@ -144,10 +173,16 @@ struct clk_hw *clk_hw_register_gpio_gate(struct device *dev, const char *name,
const char *parent_name, struct gpio_desc *gpiod,
unsigned long flags)
{
const struct clk_ops *ops;
if (gpiod_cansleep(gpiod))
ops = &clk_sleeping_gpio_gate_ops;
else
ops = &clk_gpio_gate_ops;
return clk_register_gpio(dev, name,
(parent_name ? &parent_name : NULL),
(parent_name ? 1 : 0), gpiod, flags,
&clk_gpio_gate_ops);
(parent_name ? 1 : 0), gpiod, flags, ops);
}
EXPORT_SYMBOL_GPL(clk_hw_register_gpio_gate);
......
......@@ -293,6 +293,7 @@ static __init struct clk *hb_clk_init(struct device_node *node, const struct clk
/* Map system registers */
srnp = of_find_compatible_node(NULL, NULL, "calxeda,hb-sregs");
hb_clk->reg = of_iomap(srnp, 0);
of_node_put(srnp);
BUG_ON(!hb_clk->reg);
hb_clk->reg += reg;
......
......@@ -235,8 +235,9 @@ static int max77686_clk_probe(struct platform_device *pdev)
return ret;
}
ret = clk_hw_register_clkdev(&max_clk_data->hw,
max_clk_data->clk_idata.name, NULL);
ret = devm_clk_hw_register_clkdev(dev, &max_clk_data->hw,
max_clk_data->clk_idata.name,
NULL);
if (ret < 0) {
dev_err(dev, "Failed to clkdev register: %d\n", ret);
return ret;
......@@ -244,8 +245,8 @@ static int max77686_clk_probe(struct platform_device *pdev)
}
if (parent->of_node) {
ret = of_clk_add_hw_provider(parent->of_node, of_clk_max77686_get,
drv_data);
ret = devm_of_clk_add_hw_provider(dev, of_clk_max77686_get,
drv_data);
if (ret < 0) {
dev_err(dev, "Failed to register OF clock provider: %d\n",
......@@ -261,27 +262,11 @@ static int max77686_clk_probe(struct platform_device *pdev)
1 << MAX77802_CLOCK_LOW_JITTER_SHIFT);
if (ret < 0) {
dev_err(dev, "Failed to config low-jitter: %d\n", ret);
goto remove_of_clk_provider;
return ret;
}
}
return 0;
remove_of_clk_provider:
if (parent->of_node)
of_clk_del_provider(parent->of_node);
return ret;
}
static int max77686_clk_remove(struct platform_device *pdev)
{
struct device *parent = pdev->dev.parent;
if (parent->of_node)
of_clk_del_provider(parent->of_node);
return 0;
}
static const struct platform_device_id max77686_clk_id[] = {
......@@ -297,7 +282,6 @@ static struct platform_driver max77686_clk_driver = {
.name = "max77686-clk",
},
.probe = max77686_clk_probe,
.remove = max77686_clk_remove,
.id_table = max77686_clk_id,
};
......
......@@ -1148,8 +1148,8 @@ static void __init create_one_pll(struct clockgen *cg, int idx)
pll->div[i].clk = clk;
ret = clk_register_clkdev(clk, pll->div[i].name, NULL);
if (ret != 0)
pr_err("%s: %s: register to lookup table failed %ld\n",
__func__, pll->div[i].name, PTR_ERR(clk));
pr_err("%s: %s: register to lookup table failed %d\n",
__func__, pll->div[i].name, ret);
}
}
......@@ -1389,6 +1389,7 @@ static void __init clockgen_init(struct device_node *np)
pr_err("%s: Couldn't map %pOF regs\n", __func__,
guts);
}
of_node_put(guts);
}
}
......
......@@ -121,7 +121,7 @@ static const char * const cpu_src[] = {
};
static const char * const axi_src[] = {
"ck_hsi", "ck_hse", "pll2_p", "pll3_p"
"ck_hsi", "ck_hse", "pll2_p"
};
static const char * const per_src[] = {
......@@ -225,19 +225,19 @@ static const char * const usart6_src[] = {
};
static const char * const fdcan_src[] = {
"ck_hse", "pll3_q", "pll4_q"
"ck_hse", "pll3_q", "pll4_q", "pll4_r"
};
static const char * const sai_src[] = {
"pll4_q", "pll3_q", "i2s_ckin", "ck_per"
"pll4_q", "pll3_q", "i2s_ckin", "ck_per", "pll3_r"
};
static const char * const sai2_src[] = {
"pll4_q", "pll3_q", "i2s_ckin", "ck_per", "spdif_ck_symb"
"pll4_q", "pll3_q", "i2s_ckin", "ck_per", "spdif_ck_symb", "pll3_r"
};
static const char * const adc12_src[] = {
"pll4_q", "ck_per"
"pll4_r", "ck_per", "pll3_q"
};
static const char * const dsi_src[] = {
......@@ -269,7 +269,7 @@ static const struct clk_div_table axi_div_table[] = {
static const struct clk_div_table mcu_div_table[] = {
{ 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 8 },
{ 4, 16 }, { 5, 32 }, { 6, 64 }, { 7, 128 },
{ 8, 512 }, { 9, 512 }, { 10, 512}, { 11, 512 },
{ 8, 256 }, { 9, 512 }, { 10, 512}, { 11, 512 },
{ 12, 512 }, { 13, 512 }, { 14, 512}, { 15, 512 },
{ 0 },
};
......@@ -1286,10 +1286,11 @@ _clk_stm32_register_composite(struct device *dev,
MGATE_MP1(_id, _name, _parent, _flags, _mgate)
#define KCLK(_id, _name, _parents, _flags, _mgate, _mmux)\
COMPOSITE(_id, _name, _parents, CLK_OPS_PARENT_ENABLE | _flags,\
_MGATE_MP1(_mgate),\
_MMUX(_mmux),\
_NO_DIV)
COMPOSITE(_id, _name, _parents, CLK_OPS_PARENT_ENABLE |\
CLK_SET_RATE_NO_REPARENT | _flags,\
_MGATE_MP1(_mgate),\
_MMUX(_mmux),\
_NO_DIV)
enum {
G_SAI1,
......@@ -1655,12 +1656,14 @@ static const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = {
static const struct clock_config stm32mp1_clock_cfg[] = {
/* Oscillator divider */
DIV(NO_ID, "clk-hsi-div", "clk-hsi", 0, RCC_HSICFGR, 0, 2,
CLK_DIVIDER_READ_ONLY),
DIV(NO_ID, "clk-hsi-div", "clk-hsi", CLK_DIVIDER_POWER_OF_TWO,
RCC_HSICFGR, 0, 2, CLK_DIVIDER_READ_ONLY),
/* External / Internal Oscillators */
GATE_MP1(CK_HSE, "ck_hse", "clk-hse", 0, RCC_OCENSETR, 8, 0),
GATE_MP1(CK_CSI, "ck_csi", "clk-csi", 0, RCC_OCENSETR, 4, 0),
/* ck_csi is used by IO compensation and should be critical */
GATE_MP1(CK_CSI, "ck_csi", "clk-csi", CLK_IS_CRITICAL,
RCC_OCENSETR, 4, 0),
GATE_MP1(CK_HSI, "ck_hsi", "clk-hsi-div", 0, RCC_OCENSETR, 0, 0),
GATE(CK_LSI, "ck_lsi", "clk-lsi", 0, RCC_RDLSICR, 0, 0),
GATE(CK_LSE, "ck_lse", "clk-lse", 0, RCC_BDCR, 0, 0),
......@@ -1952,14 +1955,14 @@ static const struct clock_config stm32mp1_clock_cfg[] = {
MGATE_MP1(GPU_K, "gpu_k", "pll2_q", 0, G_GPU),
MGATE_MP1(DAC12_K, "dac12_k", "ck_lsi", 0, G_DAC12),
COMPOSITE(ETHPTP_K, "ethptp_k", eth_src, CLK_OPS_PARENT_ENABLE,
COMPOSITE(ETHPTP_K, "ethptp_k", eth_src, CLK_OPS_PARENT_ENABLE |
CLK_SET_RATE_NO_REPARENT,
_NO_GATE,
_MMUX(M_ETHCK),
_DIV(RCC_ETHCKSELR, 4, 4, CLK_DIVIDER_ALLOW_ZERO, NULL)),
_DIV(RCC_ETHCKSELR, 4, 4, 0, NULL)),
/* RTC clock */
DIV(NO_ID, "ck_hse_rtc", "ck_hse", 0, RCC_RTCDIVR, 0, 7,
CLK_DIVIDER_ALLOW_ZERO),
DIV(NO_ID, "ck_hse_rtc", "ck_hse", 0, RCC_RTCDIVR, 0, 6, 0),
COMPOSITE(RTC, "ck_rtc", rtc_src, CLK_OPS_PARENT_ENABLE |
CLK_SET_RATE_PARENT,
......
......@@ -41,6 +41,43 @@ static int twl6040_pdmclk_is_prepared(struct clk_hw *hw)
return pdmclk->enabled;
}
static int twl6040_pdmclk_reset_one_clock(struct twl6040_pdmclk *pdmclk,
unsigned int reg)
{
const u8 reset_mask = TWL6040_HPLLRST; /* Same for HPPLL and LPPLL */
int ret;
ret = twl6040_set_bits(pdmclk->twl6040, reg, reset_mask);
if (ret < 0)
return ret;
ret = twl6040_clear_bits(pdmclk->twl6040, reg, reset_mask);
if (ret < 0)
return ret;
return 0;
}
/*
* TWL6040A2 Phoenix Audio IC erratum #6: "PDM Clock Generation Issue At
* Cold Temperature". This affects cold boot and deeper idle states it
* seems. The workaround consists of resetting HPPLL and LPPLL.
*/
static int twl6040_pdmclk_quirk_reset_clocks(struct twl6040_pdmclk *pdmclk)
{
int ret;
ret = twl6040_pdmclk_reset_one_clock(pdmclk, TWL6040_REG_HPPLLCTL);
if (ret)
return ret;
ret = twl6040_pdmclk_reset_one_clock(pdmclk, TWL6040_REG_LPPLLCTL);
if (ret)
return ret;
return 0;
}
static int twl6040_pdmclk_prepare(struct clk_hw *hw)
{
struct twl6040_pdmclk *pdmclk = container_of(hw, struct twl6040_pdmclk,
......@@ -48,8 +85,20 @@ static int twl6040_pdmclk_prepare(struct clk_hw *hw)
int ret;
ret = twl6040_power(pdmclk->twl6040, 1);
if (!ret)
pdmclk->enabled = 1;
if (ret)
return ret;
ret = twl6040_pdmclk_quirk_reset_clocks(pdmclk);
if (ret)
goto out_err;
pdmclk->enabled = 1;
return 0;
out_err:
dev_err(pdmclk->dev, "%s: error %i\n", __func__, ret);
twl6040_power(pdmclk->twl6040, 0);
return ret;
}
......
This diff is collapsed.
......@@ -5,31 +5,36 @@
*/
struct clk_hw;
struct device;
struct of_phandle_args;
#if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK)
struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec,
const char *dev_id, const char *con_id);
struct clk_hw *of_clk_get_hw(struct device_node *np,
int index, const char *con_id);
#else /* !CONFIG_COMMON_CLK || !CONFIG_OF */
static inline struct clk_hw *of_clk_get_hw(struct device_node *np,
int index, const char *con_id)
{
return ERR_PTR(-ENOENT);
}
#endif
#ifdef CONFIG_COMMON_CLK
struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id,
const char *con_id);
void __clk_free_clk(struct clk *clk);
int __clk_get(struct clk *clk);
struct clk *clk_hw_create_clk(struct device *dev, struct clk_hw *hw,
const char *dev_id, const char *con_id);
void __clk_put(struct clk *clk);
#else
/* All these casts to avoid ifdefs in clkdev... */
static inline struct clk *
__clk_create_clk(struct clk_hw *hw, const char *dev_id, const char *con_id)
clk_hw_create_clk(struct device *dev, struct clk_hw *hw, const char *dev_id,
const char *con_id)
{
return (struct clk *)hw;
}
static inline void __clk_free_clk(struct clk *clk) { }
static struct clk_hw *__clk_get_hw(struct clk *clk)
{
return (struct clk_hw *)clk;
}
static inline int __clk_get(struct clk *clk) { return 1; }
static inline void __clk_put(struct clk *clk) { }
#endif
......@@ -27,99 +27,6 @@
static LIST_HEAD(clocks);
static DEFINE_MUTEX(clocks_mutex);
#if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK)
static struct clk *__of_clk_get(struct device_node *np, int index,
const char *dev_id, const char *con_id)
{
struct of_phandle_args clkspec;
struct clk *clk;
int rc;
rc = of_parse_phandle_with_args(np, "clocks", "#clock-cells", index,
&clkspec);
if (rc)
return ERR_PTR(rc);
clk = __of_clk_get_from_provider(&clkspec, dev_id, con_id);
of_node_put(clkspec.np);
return clk;
}
struct clk *of_clk_get(struct device_node *np, int index)
{
return __of_clk_get(np, index, np->full_name, NULL);
}
EXPORT_SYMBOL(of_clk_get);
static struct clk *__of_clk_get_by_name(struct device_node *np,
const char *dev_id,
const char *name)
{
struct clk *clk = ERR_PTR(-ENOENT);
/* Walk up the tree of devices looking for a clock that matches */
while (np) {
int index = 0;
/*
* For named clocks, first look up the name in the
* "clock-names" property. If it cannot be found, then
* index will be an error code, and of_clk_get() will fail.
*/
if (name)
index = of_property_match_string(np, "clock-names", name);
clk = __of_clk_get(np, index, dev_id, name);
if (!IS_ERR(clk)) {
break;
} else if (name && index >= 0) {
if (PTR_ERR(clk) != -EPROBE_DEFER)
pr_err("ERROR: could not get clock %pOF:%s(%i)\n",
np, name ? name : "", index);
return clk;
}
/*
* No matching clock found on this node. If the parent node
* has a "clock-ranges" property, then we can try one of its
* clocks.
*/
np = np->parent;
if (np && !of_get_property(np, "clock-ranges", NULL))
break;
}
return clk;
}
/**
* of_clk_get_by_name() - Parse and lookup a clock referenced by a device node
* @np: pointer to clock consumer node
* @name: name of consumer's clock input, or NULL for the first clock reference
*
* This function parses the clocks and clock-names properties,
* and uses them to look up the struct clk from the registered list of clock
* providers.
*/
struct clk *of_clk_get_by_name(struct device_node *np, const char *name)
{
if (!np)
return ERR_PTR(-ENOENT);
return __of_clk_get_by_name(np, np->full_name, name);
}
EXPORT_SYMBOL(of_clk_get_by_name);
#else /* defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK) */
static struct clk *__of_clk_get_by_name(struct device_node *np,
const char *dev_id,
const char *name)
{
return ERR_PTR(-ENOENT);
}
#endif
/*
* Find the correct struct clk for the device and connection ID.
* We do slightly fuzzy matching here:
......@@ -163,7 +70,8 @@ static struct clk_lookup *clk_find(const char *dev_id, const char *con_id)
return cl;
}
struct clk *clk_get_sys(const char *dev_id, const char *con_id)
static struct clk *__clk_get_sys(struct device *dev, const char *dev_id,
const char *con_id)
{
struct clk_lookup *cl;
struct clk *clk = NULL;
......@@ -174,35 +82,33 @@ struct clk *clk_get_sys(const char *dev_id, const char *con_id)
if (!cl)
goto out;
clk = __clk_create_clk(cl->clk_hw, dev_id, con_id);
clk = clk_hw_create_clk(dev, cl->clk_hw, dev_id, con_id);
if (IS_ERR(clk))
goto out;
if (!__clk_get(clk)) {
__clk_free_clk(clk);
cl = NULL;
goto out;
}
out:
mutex_unlock(&clocks_mutex);
return cl ? clk : ERR_PTR(-ENOENT);
}
struct clk *clk_get_sys(const char *dev_id, const char *con_id)
{
return __clk_get_sys(NULL, dev_id, con_id);
}
EXPORT_SYMBOL(clk_get_sys);
struct clk *clk_get(struct device *dev, const char *con_id)
{
const char *dev_id = dev ? dev_name(dev) : NULL;
struct clk *clk;
struct clk_hw *hw;
if (dev && dev->of_node) {
clk = __of_clk_get_by_name(dev->of_node, dev_id, con_id);
if (!IS_ERR(clk) || PTR_ERR(clk) == -EPROBE_DEFER)
return clk;
hw = of_clk_get_hw(dev->of_node, 0, con_id);
if (!IS_ERR(hw) || PTR_ERR(hw) == -EPROBE_DEFER)
return clk_hw_create_clk(dev, hw, dev_id, con_id);
}
return clk_get_sys(dev_id, con_id);
return __clk_get_sys(dev, dev_id, con_id);
}
EXPORT_SYMBOL(clk_get);
......@@ -401,6 +307,23 @@ static struct clk_lookup *__clk_register_clkdev(struct clk_hw *hw,
return cl;
}
static int do_clk_register_clkdev(struct clk_hw *hw,
struct clk_lookup **cl, const char *con_id, const char *dev_id)
{
if (IS_ERR(hw))
return PTR_ERR(hw);
/*
* Since dev_id can be NULL, and NULL is handled specially, we must
* pass it as either a NULL format string, or with "%s".
*/
if (dev_id)
*cl = __clk_register_clkdev(hw, con_id, "%s", dev_id);
else
*cl = __clk_register_clkdev(hw, con_id, NULL);
return *cl ? 0 : -ENOMEM;
}
/**
* clk_register_clkdev - register one clock lookup for a struct clk
* @clk: struct clk to associate with all clk_lookups
......@@ -423,17 +346,8 @@ int clk_register_clkdev(struct clk *clk, const char *con_id,
if (IS_ERR(clk))
return PTR_ERR(clk);
/*
* Since dev_id can be NULL, and NULL is handled specially, we must
* pass it as either a NULL format string, or with "%s".
*/
if (dev_id)
cl = __clk_register_clkdev(__clk_get_hw(clk), con_id, "%s",
dev_id);
else
cl = __clk_register_clkdev(__clk_get_hw(clk), con_id, NULL);
return cl ? 0 : -ENOMEM;
return do_clk_register_clkdev(__clk_get_hw(clk), &cl, con_id,
dev_id);
}
EXPORT_SYMBOL(clk_register_clkdev);
......@@ -456,18 +370,75 @@ int clk_hw_register_clkdev(struct clk_hw *hw, const char *con_id,
{
struct clk_lookup *cl;
if (IS_ERR(hw))
return PTR_ERR(hw);
return do_clk_register_clkdev(hw, &cl, con_id, dev_id);
}
EXPORT_SYMBOL(clk_hw_register_clkdev);
/*
* Since dev_id can be NULL, and NULL is handled specially, we must
* pass it as either a NULL format string, or with "%s".
*/
if (dev_id)
cl = __clk_register_clkdev(hw, con_id, "%s", dev_id);
else
cl = __clk_register_clkdev(hw, con_id, NULL);
static void devm_clkdev_release(struct device *dev, void *res)
{
clkdev_drop(*(struct clk_lookup **)res);
}
static int devm_clk_match_clkdev(struct device *dev, void *res, void *data)
{
struct clk_lookup **l = res;
return cl ? 0 : -ENOMEM;
return *l == data;
}
EXPORT_SYMBOL(clk_hw_register_clkdev);
/**
* devm_clk_release_clkdev - Resource managed clkdev lookup release
* @dev: device this lookup is bound
* @con_id: connection ID string on device
* @dev_id: format string describing device name
*
* Drop the clkdev lookup created with devm_clk_hw_register_clkdev.
* Normally this function will not need to be called and the resource
* management code will ensure that the resource is freed.
*/
void devm_clk_release_clkdev(struct device *dev, const char *con_id,
const char *dev_id)
{
struct clk_lookup *cl;
int rval;
cl = clk_find(dev_id, con_id);
WARN_ON(!cl);
rval = devres_release(dev, devm_clkdev_release,
devm_clk_match_clkdev, cl);
WARN_ON(rval);
}
EXPORT_SYMBOL(devm_clk_release_clkdev);
/**
* devm_clk_hw_register_clkdev - managed clk lookup registration for clk_hw
* @dev: device this lookup is bound
* @hw: struct clk_hw to associate with all clk_lookups
* @con_id: connection ID string on device
* @dev_id: format string describing device name
*
* con_id or dev_id may be NULL as a wildcard, just as in the rest of
* clkdev.
*
* To make things easier for mass registration, we detect error clk_hws
* from a previous clk_hw_register_*() call, and return the error code for
* those. This is to permit this function to be called immediately
* after clk_hw_register_*().
*/
int devm_clk_hw_register_clkdev(struct device *dev, struct clk_hw *hw,
const char *con_id, const char *dev_id)
{
int rval = -ENOMEM;
struct clk_lookup **cl;
cl = devres_alloc(devm_clkdev_release, sizeof(*cl), GFP_KERNEL);
if (cl) {
rval = do_clk_register_clkdev(hw, cl, con_id, dev_id);
if (!rval)
devres_add(dev, cl);
else
devres_free(cl);
}
return rval;
}
EXPORT_SYMBOL(devm_clk_hw_register_clkdev);
......@@ -8,6 +8,12 @@ config MXC_CLK_SCU
bool
depends on IMX_SCU
config CLK_IMX8MM
bool "IMX8MM CCM Clock Driver"
depends on ARCH_MXC && ARM64
help
Build the driver for i.MX8MM CCM Clock Driver
config CLK_IMX8MQ
bool "IMX8MQ CCM Clock Driver"
depends on ARCH_MXC && ARM64
......
......@@ -18,12 +18,14 @@ obj-$(CONFIG_MXC_CLK) += \
clk-pllv2.o \
clk-pllv3.o \
clk-pllv4.o \
clk-sccg-pll.o
clk-sccg-pll.o \
clk-pll14xx.o
obj-$(CONFIG_MXC_CLK_SCU) += \
clk-scu.o \
clk-lpcg-scu.o
obj-$(CONFIG_CLK_IMX8MM) += clk-imx8mm.o
obj-$(CONFIG_CLK_IMX8MQ) += clk-imx8mq.o
obj-$(CONFIG_CLK_IMX8QXP) += clk-imx8qxp.o clk-imx8qxp-lpcg.o
......
......@@ -123,7 +123,7 @@ static const struct clk_ops imx8m_clk_composite_divider_ops = {
};
struct clk *imx8m_clk_composite_flags(const char *name,
const char **parent_names,
const char * const *parent_names,
int num_parents, void __iomem *reg,
unsigned long flags)
{
......
......@@ -428,6 +428,7 @@ static void __init mx51_clocks_init(struct device_node *np)
clk[IMX5_CLK_ESDHC4_PER_GATE] = imx_clk_gate2("esdhc4_per_gate", "esdhc_d_sel", MXC_CCM_CCGR3, 14);
clk[IMX5_CLK_USB_PHY_GATE] = imx_clk_gate2("usb_phy_gate", "usb_phy_sel", MXC_CCM_CCGR2, 0);
clk[IMX5_CLK_HSI2C_GATE] = imx_clk_gate2("hsi2c_gate", "ipg", MXC_CCM_CCGR1, 22);
clk[IMX5_CLK_SCC2_IPG_GATE] = imx_clk_gate2("scc2_gate", "ipg", MXC_CCM_CCGR1, 30);
clk[IMX5_CLK_MIPI_HSC1_GATE] = imx_clk_gate2_flags("mipi_hsc1_gate", "ipg", MXC_CCM_CCGR4, 6, CLK_IS_CRITICAL);
clk[IMX5_CLK_MIPI_HSC2_GATE] = imx_clk_gate2_flags("mipi_hsc2_gate", "ipg", MXC_CCM_CCGR4, 8, CLK_IS_CRITICAL);
clk[IMX5_CLK_MIPI_ESC_GATE] = imx_clk_gate2_flags("mipi_esc_gate", "ipg", MXC_CCM_CCGR4, 10, CLK_IS_CRITICAL);
......
......@@ -471,6 +471,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
anatop_base = base = of_iomap(np, 0);
WARN_ON(!base);
of_node_put(np);
/* Audio/video PLL post dividers do not work on i.MX6q revision 1.0 */
if (clk_on_imx6q() && imx_get_soc_revision() == IMX_CHIP_REVISION_1_0) {
......
......@@ -151,6 +151,7 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
np = of_find_compatible_node(NULL, NULL, "fsl,imx6sx-anatop");
base = of_iomap(np, 0);
WARN_ON(!base);
of_node_put(np);
clks[IMX6SX_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
clks[IMX6SX_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
......
......@@ -404,6 +404,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
np = of_find_compatible_node(NULL, NULL, "fsl,imx7d-anatop");
base = of_iomap(np, 0);
WARN_ON(!base);
of_node_put(np);
clks[IMX7D_PLL_ARM_MAIN_SRC] = imx_clk_mux("pll_arm_main_src", base + 0x60, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
clks[IMX7D_PLL_DRAM_MAIN_SRC] = imx_clk_mux("pll_dram_main_src", base + 0x70, 14, 2, pll_bypass_src_sel, ARRAY_SIZE(pll_bypass_src_sel));
......
......@@ -48,8 +48,8 @@ static void __init imx7ulp_clk_scg1_init(struct device_node *np)
struct clk_hw **clks;
void __iomem *base;
clk_data = kzalloc(sizeof(*clk_data) + sizeof(*clk_data->hws) *
IMX7ULP_CLK_SCG1_END, GFP_KERNEL);
clk_data = kzalloc(struct_size(clk_data, hws, IMX7ULP_CLK_SCG1_END),
GFP_KERNEL);
if (!clk_data)
return;
......@@ -136,8 +136,8 @@ static void __init imx7ulp_clk_pcc2_init(struct device_node *np)
struct clk_hw **clks;
void __iomem *base;
clk_data = kzalloc(sizeof(*clk_data) + sizeof(*clk_data->hws) *
IMX7ULP_CLK_PCC2_END, GFP_KERNEL);
clk_data = kzalloc(struct_size(clk_data, hws, IMX7ULP_CLK_PCC2_END),
GFP_KERNEL);
if (!clk_data)
return;
......@@ -183,8 +183,8 @@ static void __init imx7ulp_clk_pcc3_init(struct device_node *np)
struct clk_hw **clks;
void __iomem *base;
clk_data = kzalloc(sizeof(*clk_data) + sizeof(*clk_data->hws) *
IMX7ULP_CLK_PCC3_END, GFP_KERNEL);
clk_data = kzalloc(struct_size(clk_data, hws, IMX7ULP_CLK_PCC3_END),
GFP_KERNEL);
if (!clk_data)
return;
......@@ -228,8 +228,8 @@ static void __init imx7ulp_clk_smc1_init(struct device_node *np)
struct clk_hw **clks;
void __iomem *base;
clk_data = kzalloc(sizeof(*clk_data) + sizeof(*clk_data->hws) *
IMX7ULP_CLK_SMC1_END, GFP_KERNEL);
clk_data = kzalloc(struct_size(clk_data, hws, IMX7ULP_CLK_SMC1_END),
GFP_KERNEL);
if (!clk_data)
return;
......
This diff is collapsed.
This diff is collapsed.
......@@ -138,6 +138,7 @@ static int imx8qxp_clk_probe(struct platform_device *pdev)
}
static const struct of_device_id imx8qxp_match[] = {
{ .compatible = "fsl,scu-clk", },
{ .compatible = "fsl,imx8qxp-clk", },
{ /* sentinel */ }
};
......
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2017-2018 NXP.
*/
#include <linux/bitops.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include "clk.h"
#define GNRL_CTL 0x0
#define DIV_CTL 0x4
#define LOCK_STATUS BIT(31)
#define LOCK_SEL_MASK BIT(29)
#define CLKE_MASK BIT(11)
#define RST_MASK BIT(9)
#define BYPASS_MASK BIT(4)
#define MDIV_SHIFT 12
#define MDIV_MASK GENMASK(21, 12)
#define PDIV_SHIFT 4
#define PDIV_MASK GENMASK(9, 4)
#define SDIV_SHIFT 0
#define SDIV_MASK GENMASK(2, 0)
#define KDIV_SHIFT 0
#define KDIV_MASK GENMASK(15, 0)
#define LOCK_TIMEOUT_US 10000
struct clk_pll14xx {
struct clk_hw hw;
void __iomem *base;
enum imx_pll14xx_type type;
const struct imx_pll14xx_rate_table *rate_table;
int rate_count;
};
#define to_clk_pll14xx(_hw) container_of(_hw, struct clk_pll14xx, hw)
static const struct imx_pll14xx_rate_table *imx_get_pll_settings(
struct clk_pll14xx *pll, unsigned long rate)
{
const struct imx_pll14xx_rate_table *rate_table = pll->rate_table;
int i;
for (i = 0; i < pll->rate_count; i++)
if (rate == rate_table[i].rate)
return &rate_table[i];
return NULL;
}
static long clk_pll14xx_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
struct clk_pll14xx *pll = to_clk_pll14xx(hw);
const struct imx_pll14xx_rate_table *rate_table = pll->rate_table;
int i;
/* Assumming rate_table is in descending order */
for (i = 0; i < pll->rate_count; i++)
if (rate >= rate_table[i].rate)
return rate_table[i].rate;
/* return minimum supported value */
return rate_table[i - 1].rate;
}
static unsigned long clk_pll1416x_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_pll14xx *pll = to_clk_pll14xx(hw);
u32 mdiv, pdiv, sdiv, pll_gnrl, pll_div;
u64 fvco = parent_rate;
pll_gnrl = readl_relaxed(pll->base);
pll_div = readl_relaxed(pll->base + 4);
mdiv = (pll_div & MDIV_MASK) >> MDIV_SHIFT;
pdiv = (pll_div & PDIV_MASK) >> PDIV_SHIFT;
sdiv = (pll_div & SDIV_MASK) >> SDIV_SHIFT;
fvco *= mdiv;
do_div(fvco, pdiv << sdiv);
return fvco;
}
static unsigned long clk_pll1443x_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_pll14xx *pll = to_clk_pll14xx(hw);
u32 mdiv, pdiv, sdiv, pll_gnrl, pll_div_ctl0, pll_div_ctl1;
short int kdiv;
u64 fvco = parent_rate;
pll_gnrl = readl_relaxed(pll->base);
pll_div_ctl0 = readl_relaxed(pll->base + 4);
pll_div_ctl1 = readl_relaxed(pll->base + 8);
mdiv = (pll_div_ctl0 & MDIV_MASK) >> MDIV_SHIFT;
pdiv = (pll_div_ctl0 & PDIV_MASK) >> PDIV_SHIFT;
sdiv = (pll_div_ctl0 & SDIV_MASK) >> SDIV_SHIFT;
kdiv = pll_div_ctl1 & KDIV_MASK;
/* fvco = (m * 65536 + k) * Fin / (p * 65536) */
fvco *= (mdiv * 65536 + kdiv);
pdiv *= 65536;
do_div(fvco, pdiv << sdiv);
return fvco;
}
static inline bool clk_pll1416x_mp_change(const struct imx_pll14xx_rate_table *rate,
u32 pll_div)
{
u32 old_mdiv, old_pdiv;
old_mdiv = (pll_div >> MDIV_SHIFT) & MDIV_MASK;
old_pdiv = (pll_div >> PDIV_SHIFT) & PDIV_MASK;
return rate->mdiv != old_mdiv || rate->pdiv != old_pdiv;
}
static inline bool clk_pll1443x_mpk_change(const struct imx_pll14xx_rate_table *rate,
u32 pll_div_ctl0, u32 pll_div_ctl1)
{
u32 old_mdiv, old_pdiv, old_kdiv;
old_mdiv = (pll_div_ctl0 >> MDIV_SHIFT) & MDIV_MASK;
old_pdiv = (pll_div_ctl0 >> PDIV_SHIFT) & PDIV_MASK;
old_kdiv = (pll_div_ctl1 >> KDIV_SHIFT) & KDIV_MASK;
return rate->mdiv != old_mdiv || rate->pdiv != old_pdiv ||
rate->kdiv != old_kdiv;
}
static inline bool clk_pll1443x_mp_change(const struct imx_pll14xx_rate_table *rate,
u32 pll_div_ctl0, u32 pll_div_ctl1)
{
u32 old_mdiv, old_pdiv, old_kdiv;
old_mdiv = (pll_div_ctl0 >> MDIV_SHIFT) & MDIV_MASK;
old_pdiv = (pll_div_ctl0 >> PDIV_SHIFT) & PDIV_MASK;
old_kdiv = (pll_div_ctl1 >> KDIV_SHIFT) & KDIV_MASK;
return rate->mdiv != old_mdiv || rate->pdiv != old_pdiv ||
rate->kdiv != old_kdiv;
}
static int clk_pll14xx_wait_lock(struct clk_pll14xx *pll)
{
u32 val;
return readl_poll_timeout(pll->base, val, val & LOCK_TIMEOUT_US, 0,
LOCK_TIMEOUT_US);
}
static int clk_pll1416x_set_rate(struct clk_hw *hw, unsigned long drate,
unsigned long prate)
{
struct clk_pll14xx *pll = to_clk_pll14xx(hw);
const struct imx_pll14xx_rate_table *rate;
u32 tmp, div_val;
int ret;
rate = imx_get_pll_settings(pll, drate);
if (!rate) {
pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
drate, clk_hw_get_name(hw));
return -EINVAL;
}
tmp = readl_relaxed(pll->base + 4);
if (!clk_pll1416x_mp_change(rate, tmp)) {
tmp &= ~(SDIV_MASK) << SDIV_SHIFT;
tmp |= rate->sdiv << SDIV_SHIFT;
writel_relaxed(tmp, pll->base + 4);
return 0;
}
/* Bypass clock and set lock to pll output lock */
tmp = readl_relaxed(pll->base);
tmp |= LOCK_SEL_MASK;
writel_relaxed(tmp, pll->base);
/* Enable RST */
tmp &= ~RST_MASK;
writel_relaxed(tmp, pll->base);
div_val = (rate->mdiv << MDIV_SHIFT) | (rate->pdiv << PDIV_SHIFT) |
(rate->sdiv << SDIV_SHIFT);
writel_relaxed(div_val, pll->base + 0x4);
/*
* According to SPEC, t3 - t2 need to be greater than
* 1us and 1/FREF, respectively.
* FREF is FIN / Prediv, the prediv is [1, 63], so choose
* 3us.
*/
udelay(3);
/* Disable RST */
tmp |= RST_MASK;
writel_relaxed(tmp, pll->base);
/* Wait Lock */
ret = clk_pll14xx_wait_lock(pll);
if (ret)
return ret;
/* Bypass */
tmp &= ~BYPASS_MASK;
writel_relaxed(tmp, pll->base);
return 0;
}
static int clk_pll1443x_set_rate(struct clk_hw *hw, unsigned long drate,
unsigned long prate)
{
struct clk_pll14xx *pll = to_clk_pll14xx(hw);
const struct imx_pll14xx_rate_table *rate;
u32 tmp, div_val;
int ret;
rate = imx_get_pll_settings(pll, drate);
if (!rate) {
pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
drate, clk_hw_get_name(hw));
return -EINVAL;
}
tmp = readl_relaxed(pll->base + 4);
div_val = readl_relaxed(pll->base + 8);
if (!clk_pll1443x_mpk_change(rate, tmp, div_val)) {
tmp &= ~(SDIV_MASK) << SDIV_SHIFT;
tmp |= rate->sdiv << SDIV_SHIFT;
writel_relaxed(tmp, pll->base + 4);
return 0;
}
/* Enable RST */
tmp = readl_relaxed(pll->base);
tmp &= ~RST_MASK;
writel_relaxed(tmp, pll->base);
div_val = (rate->mdiv << MDIV_SHIFT) | (rate->pdiv << PDIV_SHIFT) |
(rate->sdiv << SDIV_SHIFT);
writel_relaxed(div_val, pll->base + 0x4);
writel_relaxed(rate->kdiv << KDIV_SHIFT, pll->base + 0x8);
/*
* According to SPEC, t3 - t2 need to be greater than
* 1us and 1/FREF, respectively.
* FREF is FIN / Prediv, the prediv is [1, 63], so choose
* 3us.
*/
udelay(3);
/* Disable RST */
tmp |= RST_MASK;
writel_relaxed(tmp, pll->base);
/* Wait Lock*/
ret = clk_pll14xx_wait_lock(pll);
if (ret)
return ret;
/* Bypass */
tmp &= ~BYPASS_MASK;
writel_relaxed(tmp, pll->base);
return 0;
}
static int clk_pll14xx_prepare(struct clk_hw *hw)
{
struct clk_pll14xx *pll = to_clk_pll14xx(hw);
u32 val;
/*
* RESETB = 1 from 0, PLL starts its normal
* operation after lock time
*/
val = readl_relaxed(pll->base + GNRL_CTL);
val |= RST_MASK;
writel_relaxed(val, pll->base + GNRL_CTL);
return clk_pll14xx_wait_lock(pll);
}
static int clk_pll14xx_is_prepared(struct clk_hw *hw)
{
struct clk_pll14xx *pll = to_clk_pll14xx(hw);
u32 val;
val = readl_relaxed(pll->base + GNRL_CTL);
return (val & RST_MASK) ? 1 : 0;
}
static void clk_pll14xx_unprepare(struct clk_hw *hw)
{
struct clk_pll14xx *pll = to_clk_pll14xx(hw);
u32 val;
/*
* Set RST to 0, power down mode is enabled and
* every digital block is reset
*/
val = readl_relaxed(pll->base + GNRL_CTL);
val &= ~RST_MASK;
writel_relaxed(val, pll->base + GNRL_CTL);
}
static const struct clk_ops clk_pll1416x_ops = {
.prepare = clk_pll14xx_prepare,
.unprepare = clk_pll14xx_unprepare,
.is_prepared = clk_pll14xx_is_prepared,
.recalc_rate = clk_pll1416x_recalc_rate,
.round_rate = clk_pll14xx_round_rate,
.set_rate = clk_pll1416x_set_rate,
};
static const struct clk_ops clk_pll1416x_min_ops = {
.recalc_rate = clk_pll1416x_recalc_rate,
};
static const struct clk_ops clk_pll1443x_ops = {
.prepare = clk_pll14xx_prepare,
.unprepare = clk_pll14xx_unprepare,
.is_prepared = clk_pll14xx_is_prepared,
.recalc_rate = clk_pll1443x_recalc_rate,
.round_rate = clk_pll14xx_round_rate,
.set_rate = clk_pll1443x_set_rate,
};
struct clk *imx_clk_pll14xx(const char *name, const char *parent_name,
void __iomem *base,
const struct imx_pll14xx_clk *pll_clk)
{
struct clk_pll14xx *pll;
struct clk *clk;
struct clk_init_data init;
pll = kzalloc(sizeof(*pll), GFP_KERNEL);
if (!pll)
return ERR_PTR(-ENOMEM);
init.name = name;
init.flags = pll_clk->flags;
init.parent_names = &parent_name;
init.num_parents = 1;
switch (pll_clk->type) {
case PLL_1416X:
if (!pll->rate_table)
init.ops = &clk_pll1416x_min_ops;
else
init.ops = &clk_pll1416x_ops;
break;
case PLL_1443X:
init.ops = &clk_pll1443x_ops;
break;
default:
pr_err("%s: Unknown pll type for pll clk %s\n",
__func__, name);
};
pll->base = base;
pll->hw.init = &init;
pll->type = pll_clk->type;
pll->rate_table = pll_clk->rate_table;
pll->rate_count = pll_clk->rate_count;
clk = clk_register(NULL, &pll->hw);
if (IS_ERR(clk)) {
pr_err("%s: failed to register pll %s %lu\n",
__func__, name, PTR_ERR(clk));
kfree(pll);
}
return clk;
}
This diff is collapsed.
......@@ -4,12 +4,17 @@
* Dong Aisheng <aisheng.dong@nxp.com>
*/
#include <dt-bindings/firmware/imx/rsrc.h>
#include <linux/arm-smccc.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/slab.h>
#include "clk-scu.h"
#define IMX_SIP_CPUFREQ 0xC2000001
#define IMX_SIP_SET_CPUFREQ 0x00
static struct imx_sc_ipc *ccm_ipc_handle;
/*
......@@ -65,6 +70,41 @@ struct imx_sc_msg_get_clock_rate {
} data;
};
/*
* struct imx_sc_msg_get_clock_parent - clock get parent protocol
* @hdr: SCU protocol header
* @req: get parent request protocol
* @resp: get parent response protocol
*
* This structure describes the SCU protocol of clock get parent
*/
struct imx_sc_msg_get_clock_parent {
struct imx_sc_rpc_msg hdr;
union {
struct req_get_clock_parent {
__le16 resource;
u8 clk;
} __packed req;
struct resp_get_clock_parent {
u8 parent;
} resp;
} data;
};
/*
* struct imx_sc_msg_set_clock_parent - clock set parent protocol
* @hdr: SCU protocol header
* @req: set parent request protocol
*
* This structure describes the SCU protocol of clock set parent
*/
struct imx_sc_msg_set_clock_parent {
struct imx_sc_rpc_msg hdr;
__le16 resource;
u8 clk;
u8 parent;
} __packed;
/*
* struct imx_sc_msg_req_clock_enable - clock gate protocol
* @hdr: SCU protocol header
......@@ -145,6 +185,25 @@ static long clk_scu_round_rate(struct clk_hw *hw, unsigned long rate,
return rate;
}
static int clk_scu_atf_set_cpu_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_scu *clk = to_clk_scu(hw);
struct arm_smccc_res res;
unsigned long cluster_id;
if (clk->rsrc_id == IMX_SC_R_A35)
cluster_id = 0;
else
return -EINVAL;
/* CPU frequency scaling can ONLY be done by ARM-Trusted-Firmware */
arm_smccc_smc(IMX_SIP_CPUFREQ, IMX_SIP_SET_CPUFREQ,
cluster_id, rate, 0, 0, 0, 0, &res);
return 0;
}
/*
* clk_scu_set_rate - Set rate for a SCU clock
* @hw: clock to change rate for
......@@ -173,6 +232,49 @@ static int clk_scu_set_rate(struct clk_hw *hw, unsigned long rate,
return imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
}
static u8 clk_scu_get_parent(struct clk_hw *hw)
{
struct clk_scu *clk = to_clk_scu(hw);
struct imx_sc_msg_get_clock_parent msg;
struct imx_sc_rpc_msg *hdr = &msg.hdr;
int ret;
hdr->ver = IMX_SC_RPC_VERSION;
hdr->svc = IMX_SC_RPC_SVC_PM;
hdr->func = IMX_SC_PM_FUNC_GET_CLOCK_PARENT;
hdr->size = 2;
msg.data.req.resource = cpu_to_le16(clk->rsrc_id);
msg.data.req.clk = clk->clk_type;
ret = imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
if (ret) {
pr_err("%s: failed to get clock parent %d\n",
clk_hw_get_name(hw), ret);
return 0;
}
return msg.data.resp.parent;
}
static int clk_scu_set_parent(struct clk_hw *hw, u8 index)
{
struct clk_scu *clk = to_clk_scu(hw);
struct imx_sc_msg_set_clock_parent msg;
struct imx_sc_rpc_msg *hdr = &msg.hdr;
hdr->ver = IMX_SC_RPC_VERSION;
hdr->svc = IMX_SC_RPC_SVC_PM;
hdr->func = IMX_SC_PM_FUNC_SET_CLOCK_PARENT;
hdr->size = 2;
msg.resource = cpu_to_le16(clk->rsrc_id);
msg.clk = clk->clk_type;
msg.parent = index;
return imx_scu_call_rpc(ccm_ipc_handle, &msg, true);
}
static int sc_pm_clock_enable(struct imx_sc_ipc *ipc, u16 resource,
u8 clk, bool enable, bool autog)
{
......@@ -228,11 +330,22 @@ static const struct clk_ops clk_scu_ops = {
.recalc_rate = clk_scu_recalc_rate,
.round_rate = clk_scu_round_rate,
.set_rate = clk_scu_set_rate,
.get_parent = clk_scu_get_parent,
.set_parent = clk_scu_set_parent,
.prepare = clk_scu_prepare,
.unprepare = clk_scu_unprepare,
};
static const struct clk_ops clk_scu_cpu_ops = {
.recalc_rate = clk_scu_recalc_rate,
.round_rate = clk_scu_round_rate,
.set_rate = clk_scu_atf_set_cpu_rate,
.prepare = clk_scu_prepare,
.unprepare = clk_scu_unprepare,
};
struct clk_hw *imx_clk_scu(const char *name, u32 rsrc_id, u8 clk_type)
struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents,
int num_parents, u32 rsrc_id, u8 clk_type)
{
struct clk_init_data init;
struct clk_scu *clk;
......@@ -248,7 +361,13 @@ struct clk_hw *imx_clk_scu(const char *name, u32 rsrc_id, u8 clk_type)
init.name = name;
init.ops = &clk_scu_ops;
init.num_parents = 0;
if (rsrc_id == IMX_SC_R_A35)
init.ops = &clk_scu_cpu_ops;
else
init.ops = &clk_scu_ops;
init.parent_names = parents;
init.num_parents = num_parents;
/*
* Note on MX8, the clocks are tightly coupled with power domain
* that once the power domain is off, the clock status may be
......
......@@ -10,7 +10,21 @@
#include <linux/firmware/imx/sci.h>
int imx_clk_scu_init(void);
struct clk_hw *imx_clk_scu(const char *name, u32 rsrc_id, u8 clk_type);
struct clk_hw *__imx_clk_scu(const char *name, const char * const *parents,
int num_parents, u32 rsrc_id, u8 clk_type);
static inline struct clk_hw *imx_clk_scu(const char *name, u32 rsrc_id,
u8 clk_type)
{
return __imx_clk_scu(name, NULL, 0, rsrc_id, clk_type);
}
static inline struct clk_hw *imx_clk_scu2(const char *name, const char * const *parents,
int num_parents, u32 rsrc_id, u8 clk_type)
{
return __imx_clk_scu(name, parents, num_parents, rsrc_id, clk_type);
}
struct clk_hw *imx_clk_lpcg_scu(const char *name, const char *parent_name,
unsigned long flags, void __iomem *reg,
......
......@@ -203,6 +203,7 @@ static void __init vf610_clocks_init(struct device_node *ccm_node)
np = of_find_compatible_node(NULL, NULL, "fsl,vf610-anatop");
anatop_base = of_iomap(np, 0);
BUG_ON(!anatop_base);
of_node_put(np);
np = ccm_node;
ccm_base = of_iomap(np, 0);
......
......@@ -27,6 +27,30 @@ enum imx_sccg_pll_type {
SCCG_PLL2,
};
enum imx_pll14xx_type {
PLL_1416X,
PLL_1443X,
};
/* NOTE: Rate table should be kept sorted in descending order. */
struct imx_pll14xx_rate_table {
unsigned int rate;
unsigned int pdiv;
unsigned int mdiv;
unsigned int sdiv;
unsigned int kdiv;
};
struct imx_pll14xx_clk {
enum imx_pll14xx_type type;
const struct imx_pll14xx_rate_table *rate_table;
int rate_count;
int flags;
};
struct clk *imx_clk_pll14xx(const char *name, const char *parent_name,
void __iomem *base, const struct imx_pll14xx_clk *pll_clk);
struct clk *imx_clk_pllv1(enum imx_pllv1_type type, const char *name,
const char *parent, void __iomem *base);
......@@ -36,9 +60,12 @@ struct clk *imx_clk_pllv2(const char *name, const char *parent,
struct clk *imx_clk_frac_pll(const char *name, const char *parent_name,
void __iomem *base);
struct clk *imx_clk_sccg_pll(const char *name, const char *parent_name,
void __iomem *base,
enum imx_sccg_pll_type pll_type);
struct clk *imx_clk_sccg_pll(const char *name,
const char * const *parent_names,
u8 num_parents,
u8 parent, u8 bypass1, u8 bypass2,
void __iomem *base,
unsigned long flags);
enum imx_pllv3_type {
IMX_PLLV3_GENERIC,
......@@ -329,7 +356,8 @@ static inline struct clk *imx_clk_mux_flags(const char *name,
}
static inline struct clk *imx_clk_mux2_flags(const char *name,
void __iomem *reg, u8 shift, u8 width, const char **parents,
void __iomem *reg, u8 shift, u8 width,
const char * const *parents,
int num_parents, unsigned long flags)
{
return clk_register_mux(NULL, name, parents, num_parents,
......@@ -354,7 +382,7 @@ struct clk *imx_clk_cpu(const char *name, const char *parent_name,
struct clk *step);
struct clk *imx8m_clk_composite_flags(const char *name,
const char **parent_names,
const char * const *parent_names,
int num_parents, void __iomem *reg,
unsigned long flags);
......
......@@ -83,7 +83,7 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
const struct ingenic_cgu_clk_info *clk_info;
const struct ingenic_cgu_pll_info *pll_info;
unsigned m, n, od_enc, od;
bool bypass, enable;
bool bypass;
unsigned long flags;
u32 ctl;
......@@ -103,7 +103,6 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
od_enc &= GENMASK(pll_info->od_bits - 1, 0);
bypass = !pll_info->no_bypass_bit &&
!!(ctl & BIT(pll_info->bypass_bit));
enable = !!(ctl & BIT(pll_info->enable_bit));
if (bypass)
return parent_rate;
......@@ -426,16 +425,16 @@ ingenic_clk_round_rate(struct clk_hw *hw, unsigned long req_rate,
struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
struct ingenic_cgu *cgu = ingenic_clk->cgu;
const struct ingenic_cgu_clk_info *clk_info;
long rate = *parent_rate;
unsigned int div = 1;
clk_info = &cgu->clock_info[ingenic_clk->idx];
if (clk_info->type & CGU_CLK_DIV)
rate /= ingenic_clk_calc_div(clk_info, *parent_rate, req_rate);
div = ingenic_clk_calc_div(clk_info, *parent_rate, req_rate);
else if (clk_info->type & CGU_CLK_FIXDIV)
rate /= clk_info->fixdiv.div;
div = clk_info->fixdiv.div;
return rate;
return DIV_ROUND_UP(*parent_rate, div);
}
static int
......@@ -455,7 +454,7 @@ ingenic_clk_set_rate(struct clk_hw *hw, unsigned long req_rate,
if (clk_info->type & CGU_CLK_DIV) {
div = ingenic_clk_calc_div(clk_info, parent_rate, req_rate);
rate = parent_rate / div;
rate = DIV_ROUND_UP(parent_rate, div);
if (rate != req_rate)
return -EINVAL;
......
......@@ -80,7 +80,7 @@ struct ingenic_cgu_mux_info {
* @reg: offset of the divider control register within the CGU
* @shift: number of bits to left shift the divide value by (ie. the index of
* the lowest bit of the divide value within its control register)
* @div: number of bits to divide the divider value by (i.e. if the
* @div: number to divide the divider value by (i.e. if the
* effective divider value is the value written to the register
* multiplied by some constant)
* @bits: the size of the divide value in bits
......
......@@ -165,7 +165,7 @@ static const struct ingenic_cgu_clk_info jz4740_cgu_clocks[] = {
.parents = { JZ4740_CLK_EXT, JZ4740_CLK_PLL_HALF, -1, -1 },
.mux = { CGU_REG_CPCCR, 29, 1 },
.div = { CGU_REG_CPCCR, 23, 1, 6, -1, -1, -1 },
.gate = { CGU_REG_SCR, 6 },
.gate = { CGU_REG_SCR, 6, true },
},
/* Gate-only clocks */
......
......@@ -157,7 +157,8 @@ struct clk *mtk_clk_register_gate(
int clr_ofs,
int sta_ofs,
u8 bit,
const struct clk_ops *ops)
const struct clk_ops *ops,
unsigned long flags)
{
struct mtk_clk_gate *cg;
struct clk *clk;
......@@ -172,6 +173,7 @@ struct clk *mtk_clk_register_gate(
init.parent_names = parent_name ? &parent_name : NULL;
init.num_parents = parent_name ? 1 : 0;
init.ops = ops;
init.flags = flags;
cg->regmap = regmap;
cg->set_ofs = set_ofs;
......
......@@ -47,6 +47,7 @@ struct clk *mtk_clk_register_gate(
int clr_ofs,
int sta_ofs,
u8 bit,
const struct clk_ops *ops);
const struct clk_ops *ops,
unsigned long flags);
#endif /* __DRV_CLK_GATE_H */
......@@ -535,8 +535,8 @@ static const struct mtk_composite top_muxes[] = {
0x0080, 8, 2, 15),
MUX_GATE(CLK_TOP_DPI0_SEL, "dpi0_sel", dpi0_parents,
0x0080, 16, 3, 23),
MUX_GATE(CLK_TOP_DPI1_SEL, "dpi1_sel", dpi1_parents,
0x0080, 24, 2, 31),
MUX_GATE_FLAGS_2(CLK_TOP_DPI1_SEL, "dpi1_sel", dpi1_parents,
0x0080, 24, 2, 31, 0, CLK_MUX_ROUND_CLOSEST),
MUX_GATE(CLK_TOP_TVE_SEL, "tve_sel", tve_parents,
0x0090, 0, 3, 7),
......
......@@ -223,6 +223,8 @@ static const struct mtk_fixed_factor top_divs[] = {
4),
FACTOR(CLK_TOP_APLL1_D3, "apll1_d3", "apll1_ck", 1,
3),
FACTOR(CLK_TOP_APLL2_D3, "apll2_d3", "apll2_ck", 1,
3),
};
static const char * const axi_parents[] = {
......@@ -594,7 +596,8 @@ static const char * const a1sys_hp_parents[] = {
"apll1_ck",
"apll1_d2",
"apll1_d4",
"apll1_d8"
"apll1_d8",
"apll1_d3"
};
static const char * const a2sys_hp_parents[] = {
......@@ -602,7 +605,8 @@ static const char * const a2sys_hp_parents[] = {
"apll2_ck",
"apll2_d2",
"apll2_d4",
"apll2_d8"
"apll2_d8",
"apll2_d3"
};
static const char * const asm_l_parents[] = {
......@@ -1463,7 +1467,6 @@ static struct platform_driver clk_mt2712_drv = {
.probe = clk_mt2712_probe,
.driver = {
.name = "clk-mt2712",
.owner = THIS_MODULE,
.of_match_table = of_match_clk_mt2712,
},
};
......
This diff is collapsed.
......@@ -533,7 +533,7 @@ static const char * const ca53_parents[] __initconst = {
"univpll"
};
static const char * const ca57_parents[] __initconst = {
static const char * const ca72_parents[] __initconst = {
"clk26m",
"armca15pll",
"mainpll",
......@@ -542,7 +542,7 @@ static const char * const ca57_parents[] __initconst = {
static const struct mtk_composite cpu_muxes[] __initconst = {
MUX(CLK_INFRA_CA53SEL, "infra_ca53_sel", ca53_parents, 0x0000, 0, 2),
MUX(CLK_INFRA_CA57SEL, "infra_ca57_sel", ca57_parents, 0x0000, 2, 2),
MUX(CLK_INFRA_CA72SEL, "infra_ca72_sel", ca72_parents, 0x0000, 2, 2),
};
static const struct mtk_composite top_muxes[] __initconst = {
......
......@@ -130,7 +130,7 @@ int mtk_clk_register_gates(struct device_node *node,
gate->regs->set_ofs,
gate->regs->clr_ofs,
gate->regs->sta_ofs,
gate->shift, gate->ops);
gate->shift, gate->ops, gate->flags);
if (IS_ERR(clk)) {
pr_err("Failed to register clk %s: %ld\n",
......@@ -167,7 +167,7 @@ struct clk *mtk_clk_register_composite(const struct mtk_composite *mc,
mux->mask = BIT(mc->mux_width) - 1;
mux->shift = mc->mux_shift;
mux->lock = lock;
mux->flags = mc->mux_flags;
mux_hw = &mux->hw;
mux_ops = &clk_mux_ops;
......
This diff is collapsed.
This diff is collapsed.
#
# Makefile for Meson specific clk
#
# Amlogic clock drivers
obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-phase.o vid-pll-div.o
obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-input.o
obj-$(CONFIG_COMMON_CLK_AMLOGIC_AUDIO) += clk-triphase.o sclk-div.o
obj-$(CONFIG_COMMON_CLK_MESON_AO) += meson-aoclk.o
obj-$(CONFIG_COMMON_CLK_MESON_AO_CLKC) += meson-aoclk.o
obj-$(CONFIG_COMMON_CLK_MESON_DUALDIV) += clk-dualdiv.o
obj-$(CONFIG_COMMON_CLK_MESON_EE_CLKC) += meson-eeclk.o
obj-$(CONFIG_COMMON_CLK_MESON_INPUT) += clk-input.o
obj-$(CONFIG_COMMON_CLK_MESON_MPLL) += clk-mpll.o
obj-$(CONFIG_COMMON_CLK_MESON_PHASE) += clk-phase.o
obj-$(CONFIG_COMMON_CLK_MESON_PLL) += clk-pll.o
obj-$(CONFIG_COMMON_CLK_MESON_REGMAP) += clk-regmap.o
obj-$(CONFIG_COMMON_CLK_MESON_SCLK_DIV) += sclk-div.o
obj-$(CONFIG_COMMON_CLK_MESON_VID_PLL_DIV) += vid-pll-div.o
# Amlogic Clock controllers
obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
obj-$(CONFIG_COMMON_CLK_G12A) += g12a.o g12a-aoclk.o
obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o
obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
obj-$(CONFIG_COMMON_CLK_REGMAP_MESON) += clk-regmap.o
This diff is collapsed.
......@@ -10,18 +10,7 @@
#ifndef __AXG_AOCLKC_H
#define __AXG_AOCLKC_H
#define NR_CLKS 11
/* AO Configuration Clock registers offsets
* Register offsets from the data sheet must be multiplied by 4.
*/
#define AO_RTI_PWR_CNTL_REG1 0x0C
#define AO_RTI_PWR_CNTL_REG0 0x10
#define AO_RTI_GEN_CNTL_REG0 0x40
#define AO_OSCIN_CNTL 0x58
#define AO_CRT_CLK_CNTL1 0x68
#define AO_SAR_CLK 0x90
#define AO_RTC_ALT_CLK_CNTL0 0x94
#define AO_RTC_ALT_CLK_CNTL1 0x98
#define NR_CLKS 17
#include <dt-bindings/clock/axg-aoclkc.h>
#include <dt-bindings/reset/axg-aoclkc.h>
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment