Commit ea5aee6d 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 framework updates from Stephen Boyd:
 "We have a couple new features and changes in the core clk framework
  this time around because we've finally gotten around to fixing some
  long standing issues. There's still work to do though, so this pull
  request is largely laying down the foundation for all the driver
  changes to come in the next merge window.

  The first problem we're alleviating is how parents of clks are
  specified. With the new method, we should see lots of drivers migrate
  away from the current design of string comparisons on the entire clk
  tree to a more direct method where they can use clk_hw pointers or
  more localized names specified in DT or via clkdev. This should reduce
  our reliance on string comparisons for all the topology description
  logic that we've been using for years and hopefully speed some things
  up while avoiding problems we have with generating clk names.

  Beyond that we also got rid of the CLK_IS_BASIC flag because it wasn't
  really helping anyone and we introduced big-endian versions of the
  basic clk types so that we can get rid of clk_{readl,writel}(). Both
  of these are things that driver developers have tried to use over the
  years that I typically bat away during code reviews because they're
  not useful. It's great to see these two things go away so maintainers
  can save time not worrying about these things.

  On the driver side we got the usual collection of new SoC support and
  non-critical fixes and updates to existing code. The big topics that
  stand out are the new driver support for Mediatek MT8183 and MT8516
  SoCs, Amlogic Meson8b and G12a SoCs, and the SiFive FU540 SoC. The
  other patches in the driver pile are mostly fixes for things that are
  being used for the first time or additions for clks that couldn't be
  tested before because there wasn't a consumer driver that exercised
  them. Details are below and also in the sub-maintainer tags.

  Core:
   - Remove clk_readl() and introduce BE versions of basic clk types
   - Rewrite how clk parents can be specified to allow DT/clkdev lookups
   - Removal of the CLK_IS_BASIC clk flag
   - Framework documentation updates and fixes

  New Drivers:
   - Support for STM32F769
   - AT91 sam9x60 PMC support
   - SiFive FU540 PRCI and PLL support
   - Qualcomm QCS404 CDSP clk support
   - Qualcomm QCS404 Turing clk support
   - Mediatek MT8183 clock support
   - Mediatek MT8516 clock support
   - Milbeaut M10V clk controller support
   - Support for Cirrus Logic Lochnagar clks

  Updates:
   - Rework AT91 sckc DT bindings
   - Fix slow RC oscillator issue on sama5d3
   - Mark UFS clk as critical on Hi-Silicon hi3660 SoCs
   - Various static analysis fixes/finds and const markings
   - Video Engine (ECLK) support on Aspeed SoCs
   - Xilinx ZynqMP Versal platform support
   - Convert Xilinx ZynqMP driver to be struct oriented
   - Fixes for Rockchip rk3328 and rk3288 SoCs
   - Sub-type for Rockchip SoCs where mux and divider aren't a single register
   - Remove SNVS clock from i.MX7UPL clock driver and bindings
   - Improve i.MX5 clock driver for i.MX50 support
   - Addition of ADC clock definition for Exynos 5410 SoC (Odroid XU)
   - Export a new clock for the MBUS controller on the A13
   - Allwinner H6 fixes to support a finer clocking of the video and VPU engines
   - Add g12a support in the Amlogic axg audio clock controller
   - Add missing PCI USB clock on Rensas RZ/N1
   - Add Z2 (Cortex-A53) clocks on Rensas R-Car E3 and RZ/G2E
   - A new helper DIV64_U64_ROUND_CLOSEST() in <linux/math64.h>
   - VPU and Video Decoder clocks on Amlogic Meson8b
   - Finally remove the wrong ABP Meson8b clock id
   - Add Video Decoder, PCIe PLL, and CPU Clocks on Amlogic G12A
   - Re-expose SAR_ADC_SEL and CTS_OSCIN on Amlogic G12A AO clock controller
   - Un-expose some Amlogic AXG-Audio input clocks IDs"

* tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (172 commits)
  clk: Cache core in clk_fetch_parent_index() without names
  clk: imx: correct pfdv2 gate_bit/vld_bit operations
  clk: sifive: add a driver for the SiFive FU540 PRCI IP block
  clk: analogbits: add Wide-Range PLL library
  clk: imx: clk-pllv3: mark expected switch fall-throughs
  clk: imx8mq: Add dsi_ipg_div
  clk: imx: pllv4: add fractional-N pll support
  clk: sunxi-ng: Use the correct style for SPDX License Identifier
  clk: sprd: Use the correct style for SPDX License Identifier
  clk: renesas: Use the correct style for SPDX License Identifier
  clk: qcom: Use the correct style for SPDX License Identifier
  clk: davinci: Use the correct style for SPDX License Identifier
  clk: actions: Use the correct style for SPDX License Identifier
  clk: imx: keep uart clock on during system boot
  clk: imx: correct i.MX7D AV PLL num/denom offset
  dt-bindings: clk: add documentation for the SiFive PRCI driver
  clk: stm32mp1: Add ddrperfm clock
  clk: Remove CLK_IS_BASIC clk flag
  clock: milbeaut: Add Milbeaut M10V clock controller
  dt-bindings: clock: milbeaut: add Milbeaut clock description
  ...
parents 8e4ff713 c1157f60
......@@ -14,6 +14,8 @@ Required Properties:
- "mediatek,mt7629-apmixedsys"
- "mediatek,mt8135-apmixedsys"
- "mediatek,mt8173-apmixedsys"
- "mediatek,mt8183-apmixedsys", "syscon"
- "mediatek,mt8516-apmixedsys"
- #clock-cells: Must be 1
The apmixedsys controller uses the common clk binding from
......
......@@ -9,6 +9,7 @@ Required Properties:
- "mediatek,mt2701-audsys", "syscon"
- "mediatek,mt7622-audsys", "syscon"
- "mediatek,mt7623-audsys", "mediatek,mt2701-audsys", "syscon"
- "mediatek,mt8183-audiosys", "syscon"
- #clock-cells: Must be 1
The AUDSYS controller uses the common clk binding from
......
MediaTek CAMSYS controller
============================
The MediaTek camsys controller provides various clocks to the system.
Required Properties:
- compatible: Should be one of:
- "mediatek,mt8183-camsys", "syscon"
- #clock-cells: Must be 1
The camsys controller uses the common clk binding from
Documentation/devicetree/bindings/clock/clock-bindings.txt
The available clocks are defined in dt-bindings/clock/mt*-clk.h.
Example:
camsys: camsys@1a000000 {
compatible = "mediatek,mt8183-camsys", "syscon";
reg = <0 0x1a000000 0 0x1000>;
#clock-cells = <1>;
};
......@@ -11,6 +11,7 @@ Required Properties:
- "mediatek,mt6797-imgsys", "syscon"
- "mediatek,mt7623-imgsys", "mediatek,mt2701-imgsys", "syscon"
- "mediatek,mt8173-imgsys", "syscon"
- "mediatek,mt8183-imgsys", "syscon"
- #clock-cells: Must be 1
The imgsys controller uses the common clk binding from
......
......@@ -15,6 +15,8 @@ Required Properties:
- "mediatek,mt7629-infracfg", "syscon"
- "mediatek,mt8135-infracfg", "syscon"
- "mediatek,mt8173-infracfg", "syscon"
- "mediatek,mt8183-infracfg", "syscon"
- "mediatek,mt8516-infracfg", "syscon"
- #clock-cells: Must be 1
- #reset-cells: Must be 1
......
Mediatek IPU controller
============================
The Mediatek ipu controller provides various clocks to the system.
Required Properties:
- compatible: Should be one of:
- "mediatek,mt8183-ipu_conn", "syscon"
- "mediatek,mt8183-ipu_adl", "syscon"
- "mediatek,mt8183-ipu_core0", "syscon"
- "mediatek,mt8183-ipu_core1", "syscon"
- #clock-cells: Must be 1
The ipu controller uses the common clk binding from
Documentation/devicetree/bindings/clock/clock-bindings.txt
The available clocks are defined in dt-bindings/clock/mt*-clk.h.
Example:
ipu_conn: syscon@19000000 {
compatible = "mediatek,mt8183-ipu_conn", "syscon";
reg = <0 0x19000000 0 0x1000>;
#clock-cells = <1>;
};
ipu_adl: syscon@19010000 {
compatible = "mediatek,mt8183-ipu_adl", "syscon";
reg = <0 0x19010000 0 0x1000>;
#clock-cells = <1>;
};
ipu_core0: syscon@19180000 {
compatible = "mediatek,mt8183-ipu_core0", "syscon";
reg = <0 0x19180000 0 0x1000>;
#clock-cells = <1>;
};
ipu_core1: syscon@19280000 {
compatible = "mediatek,mt8183-ipu_core1", "syscon";
reg = <0 0x19280000 0 0x1000>;
#clock-cells = <1>;
};
......@@ -7,6 +7,7 @@ Required Properties:
- compatible: Should be one of:
- "mediatek,mt2712-mcucfg", "syscon"
- "mediatek,mt8183-mcucfg", "syscon"
- #clock-cells: Must be 1
The mcucfg controller uses the common clk binding from
......
......@@ -7,6 +7,7 @@ Required Properties:
- compatible: Should be one of:
- "mediatek,mt2712-mfgcfg", "syscon"
- "mediatek,mt8183-mfgcfg", "syscon"
- #clock-cells: Must be 1
The mfgcfg controller uses the common clk binding from
......
......@@ -11,6 +11,7 @@ Required Properties:
- "mediatek,mt6797-mmsys", "syscon"
- "mediatek,mt7623-mmsys", "mediatek,mt2701-mmsys", "syscon"
- "mediatek,mt8173-mmsys", "syscon"
- "mediatek,mt8183-mmsys", "syscon"
- #clock-cells: Must be 1
The mmsys controller uses the common clk binding from
......
......@@ -14,6 +14,8 @@ Required Properties:
- "mediatek,mt7629-topckgen"
- "mediatek,mt8135-topckgen"
- "mediatek,mt8173-topckgen"
- "mediatek,mt8183-topckgen", "syscon"
- "mediatek,mt8516-topckgen"
- #clock-cells: Must be 1
The topckgen controller uses the common clk binding from
......
......@@ -11,6 +11,7 @@ Required Properties:
- "mediatek,mt6797-vdecsys", "syscon"
- "mediatek,mt7623-vdecsys", "mediatek,mt2701-vdecsys", "syscon"
- "mediatek,mt8173-vdecsys", "syscon"
- "mediatek,mt8183-vdecsys", "syscon"
- #clock-cells: Must be 1
The vdecsys controller uses the common clk binding from
......
......@@ -9,6 +9,7 @@ Required Properties:
- "mediatek,mt2712-vencsys", "syscon"
- "mediatek,mt6797-vencsys", "syscon"
- "mediatek,mt8173-vencsys", "syscon"
- "mediatek,mt8183-vencsys", "syscon"
- #clock-cells: Must be 1
The vencsys controller uses the common clk binding from
......
......@@ -6,7 +6,8 @@ devices.
Required Properties:
- compatible : should be "amlogic,axg-audio-clkc" for the A113X and A113D
- compatible : should be "amlogic,axg-audio-clkc" for the A113X and A113D,
"amlogic,g12a-audio-clkc" for G12A.
- reg : physical base address of the clock controller and length of
memory mapped region.
- clocks : a list of phandle + clock-specifier pairs for the clocks listed
......
......@@ -8,35 +8,30 @@ Slow Clock controller:
Required properties:
- compatible : shall be one of the following:
"atmel,at91sam9x5-sckc" or
"atmel,at91sam9x5-sckc",
"atmel,sama5d3-sckc" or
"atmel,sama5d4-sckc":
at91 SCKC (Slow Clock Controller)
This node contains the slow clock definitions.
"atmel,at91sam9x5-clk-slow-osc":
at91 slow oscillator
"atmel,at91sam9x5-clk-slow-rc-osc":
at91 internal slow RC oscillator
- reg : defines the IO memory reserved for the SCKC.
- #size-cells : shall be 0 (reg is used to encode clk id).
- #address-cells : shall be 1 (reg is used to encode clk id).
- #clock-cells : shall be 0.
- clocks : shall be the input parent clock phandle for the clock.
Optional properties:
- atmel,osc-bypass : boolean property. Set this when a clock signal is directly
provided on XIN.
For example:
sckc: sckc@fffffe50 {
compatible = "atmel,sama5d3-pmc";
reg = <0xfffffe50 0x4>
#size-cells = <0>;
#address-cells = <1>;
/* put at91 slow clocks here */
sckc@fffffe50 {
compatible = "atmel,at91sam9x5-sckc";
reg = <0xfffffe50 0x4>;
clocks = <&slow_xtal>;
#clock-cells = <0>;
};
Power Management Controller (PMC):
Required properties:
- compatible : shall be "atmel,<chip>-pmc", "syscon":
- compatible : shall be "atmel,<chip>-pmc", "syscon" or
"microchip,sam9x60-pmc"
<chip> can be: at91rm9200, at91sam9260, at91sam9261,
at91sam9263, at91sam9g45, at91sam9n12, at91sam9rl, at91sam9g15,
at91sam9g25, at91sam9g35, at91sam9x25, at91sam9x35, at91sam9x5,
......
Cirrus Logic Lochnagar Audio Development Board
Lochnagar is an evaluation and development board for Cirrus Logic
Smart CODEC and Amp devices. It allows the connection of most Cirrus
Logic devices on mini-cards, as well as allowing connection of
various application processor systems to provide a full evaluation
platform. Audio system topology, clocking and power can all be
controlled through the Lochnagar, allowing the device under test
to be used in a variety of possible use cases.
This binding document describes the binding for the clock portion of
the driver.
Also see these documents for generic binding information:
[1] Clock : ../clock/clock-bindings.txt
And these for relevant defines:
[2] include/dt-bindings/clock/lochnagar.h
This binding must be part of the Lochnagar MFD binding:
[3] ../mfd/cirrus,lochnagar.txt
Required properties:
- compatible : One of the following strings:
"cirrus,lochnagar1-clk"
"cirrus,lochnagar2-clk"
- #clock-cells : Must be 1. The first cell indicates the clock
number, see [2] for available clocks and [1].
Optional properties:
- clocks : Must contain an entry for each clock in clock-names.
- clock-names : May contain entries for each of the following
clocks:
- ln-cdc-clkout : Output clock from CODEC card.
- ln-dsp-clkout : Output clock from DSP card.
- ln-gf-mclk1,ln-gf-mclk2,ln-gf-mclk3,ln-gf-mclk4 : Optional
input audio clocks from host system.
- ln-psia1-mclk, ln-psia2-mclk : Optional input audio clocks from
external connector.
- ln-spdif-clkout : Optional input audio clock from SPDIF.
- ln-adat-mclk : Optional input audio clock from ADAT.
- ln-pmic-32k : On board fixed clock.
- ln-clk-12m : On board fixed clock.
- ln-clk-11m : On board fixed clock.
- ln-clk-24m : On board fixed clock.
- ln-clk-22m : On board fixed clock.
- ln-clk-8m : On board fixed clock.
- ln-usb-clk-24m : On board fixed clock.
- ln-usb-clk-12m : On board fixed clock.
- assigned-clocks : A list of Lochnagar clocks to be reparented, see
[2] for available clocks.
- assigned-clock-parents : Parents to be assigned to the clocks
listed in "assigned-clocks".
Optional nodes:
- fixed-clock nodes may be registered for the following on board clocks:
- ln-pmic-32k : 32768 Hz
- ln-clk-12m : 12288000 Hz
- ln-clk-11m : 11298600 Hz
- ln-clk-24m : 24576000 Hz
- ln-clk-22m : 22579200 Hz
- ln-clk-8m : 8192000 Hz
- ln-usb-clk-24m : 24576000 Hz
- ln-usb-clk-12m : 12288000 Hz
Example:
lochnagar {
lochnagar-clk {
compatible = "cirrus,lochnagar2-clk";
#clock-cells = <1>;
clocks = <&clk-audio>, <&clk_pmic>;
clock-names = "ln-gf-mclk2", "ln-pmic-32k";
assigned-clocks = <&lochnagar-clk LOCHNAGAR_CDC_MCLK1>,
<&lochnagar-clk LOCHNAGAR_CDC_MCLK2>;
assigned-clock-parents = <&clk-audio>,
<&clk-pmic>;
};
clk-pmic: clk-pmic {
compatible = "fixed-clock";
clock-cells = <0>;
clock-frequency = <32768>;
};
};
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/bindings/clock/milbeaut-clock.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Milbeaut SoCs Clock Controller Binding
maintainers:
- Taichi Sugaya <sugaya.taichi@socionext.com>
description: |
Milbeaut SoCs Clock controller is an integrated clock controller, which
generates and supplies to all modules.
This binding uses common clock bindings
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
properties:
compatible:
oneOf:
- items:
- enum:
- socionext,milbeaut-m10v-ccu
clocks:
maxItems: 1
description: external clock
'#clock-cells':
const: 1
required:
- compatible
- reg
- clocks
- '#clock-cells'
examples:
# Clock controller node:
- |
m10v-clk-ctrl@1d021000 {
compatible = "socionext,milbeaut-m10v-clk-ccu";
reg = <0x1d021000 0x4000>;
#clock-cells = <1>;
clocks = <&clki40mhz>;
};
# Required an external clock for Clock controller node:
- |
clocks {
clki40mhz: clki40mhz {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <40000000>;
};
/* other clocks */
};
# The clock consumer shall specify the desired clock-output of the clock
# controller as below by specifying output-id in its "clk" phandle cell.
# 2: uart
# 4: 32-bit timer
# 7: UHS-I/II
- |
serial@1e700010 {
compatible = "socionext,milbeaut-usio-uart";
reg = <0x1e700010 0x10>;
interrupts = <0 141 0x4>, <0 149 0x4>;
interrupt-names = "rx", "tx";
clocks = <&clk 2>;
};
...
Qualcomm Turing Clock & Reset Controller Binding
------------------------------------------------
Required properties :
- compatible: shall contain "qcom,qcs404-turingcc".
- reg: shall contain base register location and length.
- clocks: ahb clock for the TuringCC
- #clock-cells: from common clock binding, shall contain 1.
- #reset-cells: from common reset binding, shall contain 1.
Example:
turingcc: clock-controller@800000 {
compatible = "qcom,qcs404-turingcc";
reg = <0x00800000 0x30000>;
clocks = <&gcc GCC_CDSP_CFG_AHB_CLK>;
#clock-cells = <1>;
#reset-cells = <1>;
};
......@@ -39,6 +39,7 @@ Required properties:
* "fsl,b4860-clockgen"
* "fsl,ls1012a-clockgen"
* "fsl,ls1021a-clockgen"
* "fsl,ls1028a-clockgen"
* "fsl,ls1043a-clockgen"
* "fsl,ls1046a-clockgen"
* "fsl,ls1088a-clockgen"
......@@ -83,8 +84,8 @@ second cell is the clock index for the specified type.
1 cmux index (n in CLKCnCSR)
2 hwaccel index (n in CLKCGnHWACSR)
3 fman 0 for fm1, 1 for fm2
4 platform pll 0=pll, 1=pll/2, 2=pll/3, 3=pll/4
4=pll/5, 5=pll/6, 6=pll/7, 7=pll/8
4 platform pll n=pll/(n+1). For example, when n=1,
that means output_freq=PLL_freq/2.
5 coreclk must be 0
3. Example
......
SiFive FU540 PRCI bindings
On the FU540 family of SoCs, most system-wide clock and reset integration
is via the PRCI IP block.
Required properties:
- compatible: Should be "sifive,<chip>-prci". Only one value is
supported: "sifive,fu540-c000-prci"
- reg: Should describe the PRCI's register target physical address region
- clocks: Should point to the hfclk device tree node and the rtcclk
device tree node. The RTC clock here is not a time-of-day clock,
but is instead a high-stability clock source for system timers
and cycle counters.
- #clock-cells: Should be <1>
The clock consumer should specify the desired clock via the clock ID
macros defined in include/dt-bindings/clock/sifive-fu540-prci.h.
These macros begin with PRCI_CLK_.
The hfclk and rtcclk nodes are required, and represent physical
crystals or resonators located on the PCB. These nodes should be present
underneath /, rather than /soc.
Examples:
/* under /, in PCB-specific DT data */
hfclk: hfclk {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <33333333>;
clock-output-names = "hfclk";
};
rtcclk: rtcclk {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <1000000>;
clock-output-names = "rtcclk";
};
/* under /soc, in SoC-specific DT data */
prci: clock-controller@10000000 {
compatible = "sifive,fu540-c000-prci";
reg = <0x0 0x10000000 0x0 0x1000>;
clocks = <&hfclk>, <&rtcclk>;
#clock-cells = <1>;
};
......@@ -11,6 +11,8 @@ Required properties:
"st,stm32f42xx-rcc"
"st,stm32f469-rcc"
"st,stm32f746-rcc"
"st,stm32f769-rcc"
- reg: should be register base and length as documented in the
datasheet
- #reset-cells: 1, see below
......@@ -102,6 +104,10 @@ The secondary index is bound with the following magic numbers:
28 CLK_I2C3
29 CLK_I2C4
30 CLK_LPTIMER (LPTimer1 clock)
31 CLK_PLL_SRC
32 CLK_DFSDM1
33 CLK_ADFSDM1
34 CLK_F769_DSI
)
Example:
......
......@@ -979,6 +979,12 @@ F: drivers/iio/adc/ltc2497*
X: drivers/iio/*/adjd*
F: drivers/staging/iio/*/ad*
ANALOGBITS PLL LIBRARIES
M: Paul Walmsley <paul.walmsley@sifive.com>
S: Supported
F: drivers/clk/analogbits/*
F: include/linux/clk/analogbits*
ANDES ARCHITECTURE
M: Greentime Hu <green.hu@gmail.com>
M: Vincent Chen <deanbo422@gmail.com>
......
......@@ -119,6 +119,9 @@ void __init ti_clk_init_features(void)
if (cpu_is_omap343x())
features.flags |= TI_CLK_DPLL_HAS_FREQSEL;
if (omap_type() == OMAP2_DEVICE_TYPE_GP)
features.flags |= TI_CLK_DEVICE_TYPE_GP;
/* Idlest value for interface clocks.
* 24xx uses 0 to indicate not ready, and 1 to indicate ready.
* 34xx reverses this, just to keep us on our toes
......
......@@ -648,10 +648,10 @@ static struct clockdomain *_get_clkdm(struct omap_hwmod *oh)
if (oh->clkdm) {
return oh->clkdm;
} else if (oh->_clk) {
if (__clk_get_flags(oh->_clk) & CLK_IS_BASIC)
if (!omap2_clk_is_hw_omap(__clk_get_hw(oh->_clk)))
return NULL;
clk = to_clk_hw_omap(__clk_get_hw(oh->_clk));
return clk->clkdm;
return clk->clkdm;
}
return NULL;
}
......
......@@ -160,7 +160,7 @@ static struct clk __init *alchemy_clk_setup_cpu(const char *parent_name,
id.name = ALCHEMY_CPU_CLK;
id.parent_names = &parent_name;
id.num_parents = 1;
id.flags = CLK_IS_BASIC;
id.flags = 0;
id.ops = &alchemy_clkops_cpu;
h->init = &id;
......
......@@ -239,6 +239,7 @@ static inline struct clk *mpc512x_clk_divider(
const char *name, const char *parent_name, u8 clkflags,
u32 __iomem *reg, u8 pos, u8 len, int divflags)
{
divflags |= CLK_DIVIDER_BIG_ENDIAN;
return clk_register_divider(NULL, name, parent_name, clkflags,
reg, pos, len, divflags, &clklock);
}
......@@ -250,7 +251,7 @@ static inline struct clk *mpc512x_clk_divtable(
{
u8 divflags;
divflags = 0;
divflags = CLK_DIVIDER_BIG_ENDIAN;
return clk_register_divider_table(NULL, name, parent_name, 0,
reg, pos, len, divflags,
divtab, &clklock);
......@@ -261,10 +262,12 @@ static inline struct clk *mpc512x_clk_gated(
u32 __iomem *reg, u8 pos)
{
int clkflags;
u8 gateflags;
clkflags = CLK_SET_RATE_PARENT;
gateflags = CLK_GATE_BIG_ENDIAN;
return clk_register_gate(NULL, name, parent_name, clkflags,
reg, pos, 0, &clklock);
reg, pos, gateflags, &clklock);
}
static inline struct clk *mpc512x_clk_muxed(const char *name,
......@@ -275,7 +278,7 @@ static inline struct clk *mpc512x_clk_muxed(const char *name,
u8 muxflags;
clkflags = CLK_SET_RATE_PARENT;
muxflags = 0;
muxflags = CLK_MUX_BIG_ENDIAN;
return clk_register_mux(NULL, name,
parent_names, parent_count, clkflags,
reg, pos, len, muxflags, &clklock);
......
# SPDX-License-Identifier: GPL-2.0
config CLKDEV_LOOKUP
bool
......@@ -219,6 +220,13 @@ config COMMON_CLK_XGENE
---help---
Sypport for the APM X-Gene SoC reference, PLL, and device clocks.
config COMMON_CLK_LOCHNAGAR
tristate "Cirrus Logic Lochnagar clock driver"
depends on MFD_LOCHNAGAR
help
This driver supports the clocking features of the Cirrus Logic
Lochnagar audio development board.
config COMMON_CLK_NXP
def_bool COMMON_CLK && (ARCH_LPC18XX || ARCH_LPC32XX)
select REGMAP_MMIO if ARCH_LPC32XX
......@@ -297,6 +305,7 @@ config COMMON_CLK_FIXED_MMIO
Support for Memory Mapped IO Fixed clocks
source "drivers/clk/actions/Kconfig"
source "drivers/clk/analogbits/Kconfig"
source "drivers/clk/bcm/Kconfig"
source "drivers/clk/hisilicon/Kconfig"
source "drivers/clk/imgtec/Kconfig"
......@@ -309,7 +318,9 @@ source "drivers/clk/mvebu/Kconfig"
source "drivers/clk/qcom/Kconfig"
source "drivers/clk/renesas/Kconfig"
source "drivers/clk/samsung/Kconfig"
source "drivers/clk/sifive/Kconfig"
source "drivers/clk/sprd/Kconfig"
source "drivers/clk/sunxi/Kconfig"
source "drivers/clk/sunxi-ng/Kconfig"
source "drivers/clk/tegra/Kconfig"
source "drivers/clk/ti/Kconfig"
......
......@@ -32,8 +32,10 @@ obj-$(CONFIG_COMMON_CLK_GEMINI) += clk-gemini.o
obj-$(CONFIG_COMMON_CLK_ASPEED) += clk-aspeed.o
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
obj-$(CONFIG_CLK_HSDK) += clk-hsdk-pll.o
obj-$(CONFIG_COMMON_CLK_LOCHNAGAR) += clk-lochnagar.o
obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
obj-$(CONFIG_COMMON_CLK_MAX9485) += clk-max9485.o
obj-$(CONFIG_ARCH_MILBEAUT_M10V) += clk-milbeaut.o
obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o
obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o
obj-$(CONFIG_ARCH_NPCM7XX) += clk-npcm7xx.o
......@@ -64,6 +66,7 @@ obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o
# please keep this section sorted lexicographically by directory path name
obj-y += actions/
obj-y += analogbits/
obj-$(CONFIG_COMMON_CLK_AT91) += at91/
obj-$(CONFIG_ARCH_ARTPEC) += axis/
obj-$(CONFIG_ARC_PLAT_AXS10X) += axs10x/
......@@ -93,6 +96,7 @@ obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/
obj-y += renesas/
obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/
obj-$(CONFIG_CLK_SIFIVE) += sifive/
obj-$(CONFIG_ARCH_SIRF) += sirf/
obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/
obj-$(CONFIG_PLAT_SPEAR) += spear/
......
// SPDX-License-Identifier: GPL-2.0+
/* SPDX-License-Identifier: GPL-2.0+ */
//
// OWL common clock driver
//
......
// SPDX-License-Identifier: GPL-2.0+
/* SPDX-License-Identifier: GPL-2.0+ */
//
// OWL composite clock driver
//
......
// SPDX-License-Identifier: GPL-2.0+
/* SPDX-License-Identifier: GPL-2.0+ */
//
// OWL divider clock driver
//
......
// SPDX-License-Identifier: GPL-2.0+
/* SPDX-License-Identifier: GPL-2.0+ */
//
// OWL factor clock driver
//
......
// SPDX-License-Identifier: GPL-2.0+
/* SPDX-License-Identifier: GPL-2.0+ */
//
// OWL fixed factor clock driver
//
......
// SPDX-License-Identifier: GPL-2.0+
/* SPDX-License-Identifier: GPL-2.0+ */
//
// OWL gate clock driver
//
......
// SPDX-License-Identifier: GPL-2.0+
/* SPDX-License-Identifier: GPL-2.0+ */
//
// OWL mux clock driver
//
......
// SPDX-License-Identifier: GPL-2.0+
/* SPDX-License-Identifier: GPL-2.0+ */
//
// OWL pll clock driver
//
......
// SPDX-License-Identifier: GPL-2.0-or-later
/* SPDX-License-Identifier: GPL-2.0-or-later */
//
// Actions Semi Owl SoCs Reset Management Unit driver
//
......
config CLK_ANALOGBITS_WRPLL_CLN28HPC
bool
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_CLK_ANALOGBITS_WRPLL_CLN28HPC) += wrpll-cln28hpc.o
This diff is collapsed.
......@@ -14,6 +14,8 @@ obj-$(CONFIG_HAVE_AT91_SMD) += clk-smd.o
obj-$(CONFIG_HAVE_AT91_H32MX) += clk-h32mx.o
obj-$(CONFIG_HAVE_AT91_GENERATED_CLK) += clk-generated.o
obj-$(CONFIG_HAVE_AT91_I2S_MUX_CLK) += clk-i2s-mux.o
obj-$(CONFIG_HAVE_AT91_SAM9X60_PLL) += clk-sam9x60-pll.o
obj-$(CONFIG_SOC_AT91SAM9) += at91sam9260.o at91sam9rl.o at91sam9x5.o
obj-$(CONFIG_SOC_SAM9X60) += sam9x60.o
obj-$(CONFIG_SOC_SAMA5D4) += sama5d4.o
obj-$(CONFIG_SOC_SAMA5D2) += sama5d2.o
......@@ -41,7 +41,7 @@ static u8 sam9260_plla_out[] = { 0, 2 };
static u16 sam9260_plla_icpll[] = { 1, 1 };
static struct clk_range sam9260_plla_outputs[] = {
static const struct clk_range sam9260_plla_outputs[] = {
{ .min = 80000000, .max = 160000000 },
{ .min = 150000000, .max = 240000000 },
};
......@@ -58,7 +58,7 @@ static u8 sam9260_pllb_out[] = { 1 };
static u16 sam9260_pllb_icpll[] = { 1 };
static struct clk_range sam9260_pllb_outputs[] = {
static const struct clk_range sam9260_pllb_outputs[] = {
{ .min = 70000000, .max = 130000000 },
};
......@@ -128,7 +128,7 @@ static u8 sam9g20_plla_out[] = { 0, 1, 2, 3, 0, 1, 2, 3 };
static u16 sam9g20_plla_icpll[] = { 0, 0, 0, 0, 1, 1, 1, 1 };
static struct clk_range sam9g20_plla_outputs[] = {
static const struct clk_range sam9g20_plla_outputs[] = {
{ .min = 745000000, .max = 800000000 },
{ .min = 695000000, .max = 750000000 },
{ .min = 645000000, .max = 700000000 },
......@@ -151,7 +151,7 @@ static u8 sam9g20_pllb_out[] = { 0 };
static u16 sam9g20_pllb_icpll[] = { 0 };
static struct clk_range sam9g20_pllb_outputs[] = {
static const struct clk_range sam9g20_pllb_outputs[] = {
{ .min = 30000000, .max = 100000000 },
};
......@@ -182,7 +182,7 @@ static const struct clk_master_characteristics sam9261_mck_characteristics = {
.divisors = { 1, 2, 4, 0 },
};
static struct clk_range sam9261_plla_outputs[] = {
static const struct clk_range sam9261_plla_outputs[] = {
{ .min = 80000000, .max = 200000000 },
{ .min = 190000000, .max = 240000000 },
};
......@@ -199,7 +199,7 @@ static u8 sam9261_pllb_out[] = { 1 };
static u16 sam9261_pllb_icpll[] = { 1 };
static struct clk_range sam9261_pllb_outputs[] = {
static const struct clk_range sam9261_pllb_outputs[] = {
{ .min = 70000000, .max = 130000000 },
};
......@@ -262,7 +262,7 @@ static const struct clk_master_characteristics sam9263_mck_characteristics = {
.divisors = { 1, 2, 4, 0 },
};
static struct clk_range sam9263_pll_outputs[] = {
static const struct clk_range sam9263_pll_outputs[] = {
{ .min = 80000000, .max = 200000000 },
{ .min = 190000000, .max = 240000000 },
};
......
......@@ -14,7 +14,7 @@ static const struct clk_master_characteristics sam9rl_mck_characteristics = {
static u8 sam9rl_plla_out[] = { 0, 2 };
static struct clk_range sam9rl_plla_outputs[] = {
static const struct clk_range sam9rl_plla_outputs[] = {
{ .min = 80000000, .max = 200000000 },
{ .min = 190000000, .max = 240000000 },
};
......
......@@ -17,7 +17,7 @@ static u8 plla_out[] = { 0, 1, 2, 3, 0, 1, 2, 3 };
static u16 plla_icpll[] = { 0, 0, 0, 0, 1, 1, 1, 1 };
static struct clk_range plla_outputs[] = {
static const struct clk_range plla_outputs[] = {
{ .min = 745000000, .max = 800000000 },
{ .min = 695000000, .max = 750000000 },
{ .min = 645000000, .max = 700000000 },
......@@ -49,6 +49,13 @@ static const struct {
{ .n = "pck1", .p = "prog1", .id = 9 },
};
static const struct clk_pcr_layout at91sam9x5_pcr_layout = {
.offset = 0x10c,
.cmd = BIT(12),
.pid_mask = GENMASK(5, 0),
.div_mask = GENMASK(17, 16),
};
struct pck {
char *n;
u8 id;
......@@ -242,6 +249,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
for (i = 0; i < ARRAY_SIZE(at91sam9x5_periphck); i++) {
hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
&at91sam9x5_pcr_layout,
at91sam9x5_periphck[i].n,
"masterck",
at91sam9x5_periphck[i].id,
......@@ -254,6 +262,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
for (i = 0; extra_pcks[i].id; i++) {
hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
&at91sam9x5_pcr_layout,
extra_pcks[i].n,
"masterck",
extra_pcks[i].id,
......
......@@ -11,6 +11,7 @@
*
*/
#include <linux/bitfield.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/clk/at91_pmc.h>
......@@ -31,6 +32,7 @@ struct clk_generated {
spinlock_t *lock;
u32 id;
u32 gckdiv;
const struct clk_pcr_layout *layout;
u8 parent_id;
bool audio_pll_allowed;
};
......@@ -47,14 +49,14 @@ static int clk_generated_enable(struct clk_hw *hw)
__func__, gck->gckdiv, gck->parent_id);
spin_lock_irqsave(gck->lock, flags);
regmap_write(gck->regmap, AT91_PMC_PCR,
(gck->id & AT91_PMC_PCR_PID_MASK));
regmap_update_bits(gck->regmap, AT91_PMC_PCR,
AT91_PMC_PCR_GCKDIV_MASK | AT91_PMC_PCR_GCKCSS_MASK |
AT91_PMC_PCR_CMD | AT91_PMC_PCR_GCKEN,
AT91_PMC_PCR_GCKCSS(gck->parent_id) |
AT91_PMC_PCR_CMD |
AT91_PMC_PCR_GCKDIV(gck->gckdiv) |
regmap_write(gck->regmap, gck->layout->offset,
(gck->id & gck->layout->pid_mask));
regmap_update_bits(gck->regmap, gck->layout->offset,
AT91_PMC_PCR_GCKDIV_MASK | gck->layout->gckcss_mask |
gck->layout->cmd | AT91_PMC_PCR_GCKEN,
field_prep(gck->layout->gckcss_mask, gck->parent_id) |
gck->layout->cmd |
FIELD_PREP(AT91_PMC_PCR_GCKDIV_MASK, gck->gckdiv) |
AT91_PMC_PCR_GCKEN);
spin_unlock_irqrestore(gck->lock, flags);
return 0;
......@@ -66,11 +68,11 @@ static void clk_generated_disable(struct clk_hw *hw)
unsigned long flags;
spin_lock_irqsave(gck->lock, flags);
regmap_write(gck->regmap, AT91_PMC_PCR,
(gck->id & AT91_PMC_PCR_PID_MASK));
regmap_update_bits(gck->regmap, AT91_PMC_PCR,
AT91_PMC_PCR_CMD | AT91_PMC_PCR_GCKEN,
AT91_PMC_PCR_CMD);
regmap_write(gck->regmap, gck->layout->offset,
(gck->id & gck->layout->pid_mask));
regmap_update_bits(gck->regmap, gck->layout->offset,
gck->layout->cmd | AT91_PMC_PCR_GCKEN,
gck->layout->cmd);
spin_unlock_irqrestore(gck->lock, flags);
}
......@@ -81,9 +83,9 @@ static int clk_generated_is_enabled(struct clk_hw *hw)
unsigned int status;
spin_lock_irqsave(gck->lock, flags);
regmap_write(gck->regmap, AT91_PMC_PCR,
(gck->id & AT91_PMC_PCR_PID_MASK));
regmap_read(gck->regmap, AT91_PMC_PCR, &status);
regmap_write(gck->regmap, gck->layout->offset,
(gck->id & gck->layout->pid_mask));
regmap_read(gck->regmap, gck->layout->offset, &status);
spin_unlock_irqrestore(gck->lock, flags);
return status & AT91_PMC_PCR_GCKEN ? 1 : 0;
......@@ -259,19 +261,18 @@ static void clk_generated_startup(struct clk_generated *gck)
unsigned long flags;
spin_lock_irqsave(gck->lock, flags);
regmap_write(gck->regmap, AT91_PMC_PCR,
(gck->id & AT91_PMC_PCR_PID_MASK));
regmap_read(gck->regmap, AT91_PMC_PCR, &tmp);
regmap_write(gck->regmap, gck->layout->offset,
(gck->id & gck->layout->pid_mask));
regmap_read(gck->regmap, gck->layout->offset, &tmp);
spin_unlock_irqrestore(gck->lock, flags);
gck->parent_id = (tmp & AT91_PMC_PCR_GCKCSS_MASK)
>> AT91_PMC_PCR_GCKCSS_OFFSET;
gck->gckdiv = (tmp & AT91_PMC_PCR_GCKDIV_MASK)
>> AT91_PMC_PCR_GCKDIV_OFFSET;
gck->parent_id = field_get(gck->layout->gckcss_mask, tmp);
gck->gckdiv = FIELD_GET(AT91_PMC_PCR_GCKDIV_MASK, tmp);
}
struct clk_hw * __init
at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,
const struct clk_pcr_layout *layout,
const char *name, const char **parent_names,
u8 num_parents, u8 id, bool pll_audio,
const struct clk_range *range)
......@@ -298,6 +299,7 @@ at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,
gck->lock = lock;
gck->range = *range;
gck->audio_pll_allowed = pll_audio;
gck->layout = layout;
clk_generated_startup(gck);
hw = &gck->hw;
......
......@@ -29,6 +29,7 @@ struct clk_master {
struct regmap *regmap;
const struct clk_master_layout *layout;
const struct clk_master_characteristics *characteristics;
u32 mckr;
};
static inline bool clk_master_ready(struct regmap *regmap)
......@@ -69,7 +70,7 @@ static unsigned long clk_master_recalc_rate(struct clk_hw *hw,
master->characteristics;
unsigned int mckr;
regmap_read(master->regmap, AT91_PMC_MCKR, &mckr);
regmap_read(master->regmap, master->layout->offset, &mckr);
mckr &= layout->mask;
pres = (mckr >> layout->pres_shift) & MASTER_PRES_MASK;
......@@ -95,7 +96,7 @@ static u8 clk_master_get_parent(struct clk_hw *hw)
struct clk_master *master = to_clk_master(hw);
unsigned int mckr;
regmap_read(master->regmap, AT91_PMC_MCKR, &mckr);
regmap_read(master->regmap, master->layout->offset, &mckr);
return mckr & AT91_PMC_CSS;
}
......@@ -147,13 +148,14 @@ at91_clk_register_master(struct regmap *regmap,
return hw;
}
const struct clk_master_layout at91rm9200_master_layout = {
.mask = 0x31F,
.pres_shift = 2,
.offset = AT91_PMC_MCKR,
};
const struct clk_master_layout at91sam9x5_master_layout = {
.mask = 0x373,
.pres_shift = 4,
.offset = AT91_PMC_MCKR,
};
......@@ -8,6 +8,7 @@
*
*/
#include <linux/bitops.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/clk/at91_pmc.h>
......@@ -23,9 +24,6 @@ DEFINE_SPINLOCK(pmc_pcr_lock);
#define PERIPHERAL_ID_MAX 31
#define PERIPHERAL_MASK(id) (1 << ((id) & PERIPHERAL_ID_MAX))
#define PERIPHERAL_RSHIFT_MASK 0x3
#define PERIPHERAL_RSHIFT(val) (((val) >> 16) & PERIPHERAL_RSHIFT_MASK)
#define PERIPHERAL_MAX_SHIFT 3
struct clk_peripheral {
......@@ -43,6 +41,7 @@ struct clk_sam9x5_peripheral {
spinlock_t *lock;
u32 id;
u32 div;
const struct clk_pcr_layout *layout;
bool auto_div;
};
......@@ -169,13 +168,13 @@ static int clk_sam9x5_peripheral_enable(struct clk_hw *hw)
return 0;
spin_lock_irqsave(periph->lock, flags);
regmap_write(periph->regmap, AT91_PMC_PCR,
(periph->id & AT91_PMC_PCR_PID_MASK));
regmap_update_bits(periph->regmap, AT91_PMC_PCR,
AT91_PMC_PCR_DIV_MASK | AT91_PMC_PCR_CMD |
regmap_write(periph->regmap, periph->layout->offset,
(periph->id & periph->layout->pid_mask));
regmap_update_bits(periph->regmap, periph->layout->offset,
periph->layout->div_mask | periph->layout->cmd |
AT91_PMC_PCR_EN,
AT91_PMC_PCR_DIV(periph->div) |
AT91_PMC_PCR_CMD |
field_prep(periph->layout->div_mask, periph->div) |
periph->layout->cmd |
AT91_PMC_PCR_EN);
spin_unlock_irqrestore(periph->lock, flags);
......@@ -191,11 +190,11 @@ static void clk_sam9x5_peripheral_disable(struct clk_hw *hw)
return;
spin_lock_irqsave(periph->lock, flags);
regmap_write(periph->regmap, AT91_PMC_PCR,
(periph->id & AT91_PMC_PCR_PID_MASK));
regmap_update_bits(periph->regmap, AT91_PMC_PCR,
AT91_PMC_PCR_EN | AT91_PMC_PCR_CMD,
AT91_PMC_PCR_CMD);
regmap_write(periph->regmap, periph->layout->offset,
(periph->id & periph->layout->pid_mask));
regmap_update_bits(periph->regmap, periph->layout->offset,
AT91_PMC_PCR_EN | periph->layout->cmd,
periph->layout->cmd);
spin_unlock_irqrestore(periph->lock, flags);
}
......@@ -209,9 +208,9 @@ static int clk_sam9x5_peripheral_is_enabled(struct clk_hw *hw)
return 1;
spin_lock_irqsave(periph->lock, flags);
regmap_write(periph->regmap, AT91_PMC_PCR,
(periph->id & AT91_PMC_PCR_PID_MASK));
regmap_read(periph->regmap, AT91_PMC_PCR, &status);
regmap_write(periph->regmap, periph->layout->offset,
(periph->id & periph->layout->pid_mask));
regmap_read(periph->regmap, periph->layout->offset, &status);
spin_unlock_irqrestore(periph->lock, flags);
return status & AT91_PMC_PCR_EN ? 1 : 0;
......@@ -229,13 +228,13 @@ clk_sam9x5_peripheral_recalc_rate(struct clk_hw *hw,
return parent_rate;
spin_lock_irqsave(periph->lock, flags);
regmap_write(periph->regmap, AT91_PMC_PCR,
(periph->id & AT91_PMC_PCR_PID_MASK));
regmap_read(periph->regmap, AT91_PMC_PCR, &status);
regmap_write(periph->regmap, periph->layout->offset,
(periph->id & periph->layout->pid_mask));
regmap_read(periph->regmap, periph->layout->offset, &status);
spin_unlock_irqrestore(periph->lock, flags);
if (status & AT91_PMC_PCR_EN) {
periph->div = PERIPHERAL_RSHIFT(status);
periph->div = field_get(periph->layout->div_mask, status);
periph->auto_div = false;
} else {
clk_sam9x5_peripheral_autodiv(periph);
......@@ -328,6 +327,7 @@ static const struct clk_ops sam9x5_peripheral_ops = {
struct clk_hw * __init
at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
const struct clk_pcr_layout *layout,
const char *name, const char *parent_name,
u32 id, const struct clk_range *range)
{
......@@ -354,7 +354,9 @@ at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
periph->div = 0;
periph->regmap = regmap;
periph->lock = lock;
periph->auto_div = true;
if (layout->div_mask)
periph->auto_div = true;
periph->layout = layout;
periph->range = *range;
hw = &periph->hw;
......
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2019 Microchip Technology Inc.
*
*/
#include <linux/bitfield.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/clk/at91_pmc.h>
#include <linux/of.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include "pmc.h"
#define PMC_PLL_CTRL0 0xc
#define PMC_PLL_CTRL0_DIV_MSK GENMASK(7, 0)
#define PMC_PLL_CTRL0_ENPLL BIT(28)
#define PMC_PLL_CTRL0_ENPLLCK BIT(29)
#define PMC_PLL_CTRL0_ENLOCK BIT(31)
#define PMC_PLL_CTRL1 0x10
#define PMC_PLL_CTRL1_FRACR_MSK GENMASK(21, 0)
#define PMC_PLL_CTRL1_MUL_MSK GENMASK(30, 24)
#define PMC_PLL_ACR 0x18
#define PMC_PLL_ACR_DEFAULT 0x1b040010UL
#define PMC_PLL_ACR_UTMIVR BIT(12)
#define PMC_PLL_ACR_UTMIBG BIT(13)
#define PMC_PLL_ACR_LOOP_FILTER_MSK GENMASK(31, 24)
#define PMC_PLL_UPDT 0x1c
#define PMC_PLL_UPDT_UPDATE BIT(8)
#define PMC_PLL_ISR0 0xec
#define PLL_DIV_MAX (FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, UINT_MAX) + 1)
#define UPLL_DIV 2
#define PLL_MUL_MAX (FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, UINT_MAX) + 1)
#define PLL_MAX_ID 1
struct sam9x60_pll {
struct clk_hw hw;
struct regmap *regmap;
spinlock_t *lock;
const struct clk_pll_characteristics *characteristics;
u32 frac;
u8 id;
u8 div;
u16 mul;
};
#define to_sam9x60_pll(hw) container_of(hw, struct sam9x60_pll, hw)
static inline bool sam9x60_pll_ready(struct regmap *regmap, int id)
{
unsigned int status;
regmap_read(regmap, PMC_PLL_ISR0, &status);
return !!(status & BIT(id));
}
static int sam9x60_pll_prepare(struct clk_hw *hw)
{
struct sam9x60_pll *pll = to_sam9x60_pll(hw);
struct regmap *regmap = pll->regmap;
unsigned long flags;
u8 div;
u16 mul;
u32 val;
spin_lock_irqsave(pll->lock, flags);
regmap_write(regmap, PMC_PLL_UPDT, pll->id);
regmap_read(regmap, PMC_PLL_CTRL0, &val);
div = FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, val);
regmap_read(regmap, PMC_PLL_CTRL1, &val);
mul = FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, val);
if (sam9x60_pll_ready(regmap, pll->id) &&
(div == pll->div && mul == pll->mul)) {
spin_unlock_irqrestore(pll->lock, flags);
return 0;
}
/* Recommended value for PMC_PLL_ACR */
val = PMC_PLL_ACR_DEFAULT;
regmap_write(regmap, PMC_PLL_ACR, val);
regmap_write(regmap, PMC_PLL_CTRL1,
FIELD_PREP(PMC_PLL_CTRL1_MUL_MSK, pll->mul));
if (pll->characteristics->upll) {
/* Enable the UTMI internal bandgap */
val |= PMC_PLL_ACR_UTMIBG;
regmap_write(regmap, PMC_PLL_ACR, val);
udelay(10);
/* Enable the UTMI internal regulator */
val |= PMC_PLL_ACR_UTMIVR;
regmap_write(regmap, PMC_PLL_ACR, val);
udelay(10);
}
regmap_update_bits(regmap, PMC_PLL_UPDT,
PMC_PLL_UPDT_UPDATE, PMC_PLL_UPDT_UPDATE);
regmap_write(regmap, PMC_PLL_CTRL0,
PMC_PLL_CTRL0_ENLOCK | PMC_PLL_CTRL0_ENPLL |
PMC_PLL_CTRL0_ENPLLCK | pll->div);
regmap_update_bits(regmap, PMC_PLL_UPDT,
PMC_PLL_UPDT_UPDATE, PMC_PLL_UPDT_UPDATE);
while (!sam9x60_pll_ready(regmap, pll->id))
cpu_relax();
spin_unlock_irqrestore(pll->lock, flags);
return 0;
}
static int sam9x60_pll_is_prepared(struct clk_hw *hw)
{
struct sam9x60_pll *pll = to_sam9x60_pll(hw);
return sam9x60_pll_ready(pll->regmap, pll->id);
}
static void sam9x60_pll_unprepare(struct clk_hw *hw)
{
struct sam9x60_pll *pll = to_sam9x60_pll(hw);
unsigned long flags;
spin_lock_irqsave(pll->lock, flags);
regmap_write(pll->regmap, PMC_PLL_UPDT, pll->id);
regmap_update_bits(pll->regmap, PMC_PLL_CTRL0,
PMC_PLL_CTRL0_ENPLLCK, 0);
regmap_update_bits(pll->regmap, PMC_PLL_UPDT,
PMC_PLL_UPDT_UPDATE, PMC_PLL_UPDT_UPDATE);
regmap_update_bits(pll->regmap, PMC_PLL_CTRL0, PMC_PLL_CTRL0_ENPLL, 0);
if (pll->characteristics->upll)
regmap_update_bits(pll->regmap, PMC_PLL_ACR,
PMC_PLL_ACR_UTMIBG | PMC_PLL_ACR_UTMIVR, 0);
regmap_update_bits(pll->regmap, PMC_PLL_UPDT,
PMC_PLL_UPDT_UPDATE, PMC_PLL_UPDT_UPDATE);
spin_unlock_irqrestore(pll->lock, flags);
}
static unsigned long sam9x60_pll_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct sam9x60_pll *pll = to_sam9x60_pll(hw);
return (parent_rate * (pll->mul + 1)) / (pll->div + 1);
}
static long sam9x60_pll_get_best_div_mul(struct sam9x60_pll *pll,
unsigned long rate,
unsigned long parent_rate,
bool update)
{
const struct clk_pll_characteristics *characteristics =
pll->characteristics;
unsigned long bestremainder = ULONG_MAX;
unsigned long maxdiv, mindiv, tmpdiv;
long bestrate = -ERANGE;
unsigned long bestdiv = 0;
unsigned long bestmul = 0;
unsigned long bestfrac = 0;
if (rate < characteristics->output[0].min ||
rate > characteristics->output[0].max)
return -ERANGE;
if (!pll->characteristics->upll) {
mindiv = parent_rate / rate;
if (mindiv < 2)
mindiv = 2;
maxdiv = DIV_ROUND_UP(parent_rate * PLL_MUL_MAX, rate);
if (maxdiv > PLL_DIV_MAX)
maxdiv = PLL_DIV_MAX;
} else {
mindiv = maxdiv = UPLL_DIV;
}
for (tmpdiv = mindiv; tmpdiv <= maxdiv; tmpdiv++) {
unsigned long remainder;
unsigned long tmprate;
unsigned long tmpmul;
unsigned long tmpfrac = 0;
/*
* Calculate the multiplier associated with the current
* divider that provide the closest rate to the requested one.
*/
tmpmul = mult_frac(rate, tmpdiv, parent_rate);
tmprate = mult_frac(parent_rate, tmpmul, tmpdiv);
remainder = rate - tmprate;
if (remainder) {
tmpfrac = DIV_ROUND_CLOSEST_ULL((u64)remainder * tmpdiv * (1 << 22),
parent_rate);
tmprate += DIV_ROUND_CLOSEST_ULL((u64)tmpfrac * parent_rate,
tmpdiv * (1 << 22));
if (tmprate > rate)
remainder = tmprate - rate;
else
remainder = rate - tmprate;
}
/*
* Compare the remainder with the best remainder found until
* now and elect a new best multiplier/divider pair if the
* current remainder is smaller than the best one.
*/
if (remainder < bestremainder) {
bestremainder = remainder;
bestdiv = tmpdiv;
bestmul = tmpmul;
bestrate = tmprate;
bestfrac = tmpfrac;
}
/* We've found a perfect match! */
if (!remainder)
break;
}
/* Check if bestrate is a valid output rate */
if (bestrate < characteristics->output[0].min &&
bestrate > characteristics->output[0].max)
return -ERANGE;
if (update) {
pll->div = bestdiv - 1;
pll->mul = bestmul - 1;
pll->frac = bestfrac;
}
return bestrate;
}
static long sam9x60_pll_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
struct sam9x60_pll *pll = to_sam9x60_pll(hw);
return sam9x60_pll_get_best_div_mul(pll, rate, *parent_rate, false);
}
static int sam9x60_pll_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct sam9x60_pll *pll = to_sam9x60_pll(hw);
return sam9x60_pll_get_best_div_mul(pll, rate, parent_rate, true);
}
static const struct clk_ops pll_ops = {
.prepare = sam9x60_pll_prepare,
.unprepare = sam9x60_pll_unprepare,
.is_prepared = sam9x60_pll_is_prepared,
.recalc_rate = sam9x60_pll_recalc_rate,
.round_rate = sam9x60_pll_round_rate,
.set_rate = sam9x60_pll_set_rate,
};
struct clk_hw * __init
sam9x60_clk_register_pll(struct regmap *regmap, spinlock_t *lock,
const char *name, const char *parent_name, u8 id,
const struct clk_pll_characteristics *characteristics)
{
struct sam9x60_pll *pll;
struct clk_hw *hw;
struct clk_init_data init;
unsigned int pllr;
int ret;
if (id > PLL_MAX_ID)
return ERR_PTR(-EINVAL);
pll = kzalloc(sizeof(*pll), GFP_KERNEL);
if (!pll)
return ERR_PTR(-ENOMEM);
init.name = name;
init.ops = &pll_ops;
init.parent_names = &parent_name;
init.num_parents = 1;
init.flags = CLK_SET_RATE_GATE;
pll->id = id;
pll->hw.init = &init;
pll->characteristics = characteristics;
pll->regmap = regmap;
pll->lock = lock;
regmap_write(regmap, PMC_PLL_UPDT, id);
regmap_read(regmap, PMC_PLL_CTRL0, &pllr);
pll->div = FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, pllr);
regmap_read(regmap, PMC_PLL_CTRL1, &pllr);
pll->mul = FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, pllr);
hw = &pll->hw;
ret = clk_hw_register(NULL, hw);
if (ret) {
kfree(pll);
hw = ERR_PTR(ret);
}
return hw;
}
......@@ -23,9 +23,13 @@
#define RM9200_USB_DIV_SHIFT 28
#define RM9200_USB_DIV_TAB_SIZE 4
#define SAM9X5_USBS_MASK GENMASK(0, 0)
#define SAM9X60_USBS_MASK GENMASK(1, 0)
struct at91sam9x5_clk_usb {
struct clk_hw hw;
struct regmap *regmap;
u32 usbs_mask;
};
#define to_at91sam9x5_clk_usb(hw) \
......@@ -111,8 +115,7 @@ static int at91sam9x5_clk_usb_set_parent(struct clk_hw *hw, u8 index)
if (index > 1)
return -EINVAL;
regmap_update_bits(usb->regmap, AT91_PMC_USB, AT91_PMC_USBS,
index ? AT91_PMC_USBS : 0);
regmap_update_bits(usb->regmap, AT91_PMC_USB, usb->usbs_mask, index);
return 0;
}
......@@ -124,7 +127,7 @@ static u8 at91sam9x5_clk_usb_get_parent(struct clk_hw *hw)
regmap_read(usb->regmap, AT91_PMC_USB, &usbr);
return usbr & AT91_PMC_USBS;
return usbr & usb->usbs_mask;
}
static int at91sam9x5_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,
......@@ -190,9 +193,10 @@ static const struct clk_ops at91sam9n12_usb_ops = {
.set_rate = at91sam9x5_clk_usb_set_rate,
};
struct clk_hw * __init
at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name,
const char **parent_names, u8 num_parents)
static struct clk_hw * __init
_at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name,
const char **parent_names, u8 num_parents,
u32 usbs_mask)
{
struct at91sam9x5_clk_usb *usb;
struct clk_hw *hw;
......@@ -212,6 +216,7 @@ at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name,
usb->hw.init = &init;
usb->regmap = regmap;
usb->usbs_mask = SAM9X5_USBS_MASK;
hw = &usb->hw;
ret = clk_hw_register(NULL, &usb->hw);
......@@ -223,6 +228,22 @@ at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name,
return hw;
}
struct clk_hw * __init
at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name,
const char **parent_names, u8 num_parents)
{
return _at91sam9x5_clk_register_usb(regmap, name, parent_names,
num_parents, SAM9X5_USBS_MASK);
}
struct clk_hw * __init
sam9x60_clk_register_usb(struct regmap *regmap, const char *name,
const char **parent_names, u8 num_parents)
{
return _at91sam9x5_clk_register_usb(regmap, name, parent_names,
num_parents, SAM9X60_USBS_MASK);
}
struct clk_hw * __init
at91sam9n12_clk_register_usb(struct regmap *regmap, const char *name,
const char *parent_name)
......
......@@ -93,6 +93,14 @@ CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pmc_setup,
of_sama5d2_clk_audio_pll_pmc_setup);
#endif /* CONFIG_HAVE_AT91_AUDIO_PLL */
static const struct clk_pcr_layout dt_pcr_layout = {
.offset = 0x10c,
.cmd = BIT(12),
.pid_mask = GENMASK(5, 0),
.div_mask = GENMASK(17, 16),
.gckcss_mask = GENMASK(10, 8),
};
#ifdef CONFIG_HAVE_AT91_GENERATED_CLK
#define GENERATED_SOURCE_MAX 6
......@@ -146,7 +154,8 @@ static void __init of_sama5d2_clk_generated_setup(struct device_node *np)
id == GCK_ID_CLASSD))
pll_audio = true;
hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, name,
hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
&dt_pcr_layout, name,
parent_names, num_parents,
id, pll_audio, &range);
if (IS_ERR(hw))
......@@ -448,6 +457,7 @@ of_at91_clk_periph_setup(struct device_node *np, u8 type)
hw = at91_clk_register_sam9x5_peripheral(regmap,
&pmc_pcr_lock,
&dt_pcr_layout,
name,
parent_name,
id, &range);
......
......@@ -38,6 +38,7 @@ struct clk_range {
#define CLK_RANGE(MIN, MAX) {.min = MIN, .max = MAX,}
struct clk_master_layout {
u32 offset;
u32 mask;
u8 pres_shift;
};
......@@ -65,9 +66,10 @@ extern const struct clk_pll_layout sama5d3_pll_layout;
struct clk_pll_characteristics {
struct clk_range input;
int num_output;
struct clk_range *output;
const struct clk_range *output;
u16 *icpll;
u8 *out;
u8 upll : 1;
};
struct clk_programmable_layout {
......@@ -82,6 +84,17 @@ extern const struct clk_programmable_layout at91rm9200_programmable_layout;
extern const struct clk_programmable_layout at91sam9g45_programmable_layout;
extern const struct clk_programmable_layout at91sam9x5_programmable_layout;
struct clk_pcr_layout {
u32 offset;
u32 cmd;
u32 div_mask;
u32 gckcss_mask;
u32 pid_mask;
};
#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1))
#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask))
#define ndck(a, s) (a[s - 1].id + 1)
#define nck(a) (a[ARRAY_SIZE(a) - 1].id + 1)
struct pmc_data *pmc_data_allocate(unsigned int ncore, unsigned int nsystem,
......@@ -107,6 +120,7 @@ at91_clk_register_audio_pll_pmc(struct regmap *regmap, const char *name,
struct clk_hw * __init
at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,
const struct clk_pcr_layout *layout,
const char *name, const char **parent_names,
u8 num_parents, u8 id, bool pll_audio,
const struct clk_range *range);
......@@ -145,6 +159,7 @@ at91_clk_register_peripheral(struct regmap *regmap, const char *name,
const char *parent_name, u32 id);
struct clk_hw * __init
at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
const struct clk_pcr_layout *layout,
const char *name, const char *parent_name,
u32 id, const struct clk_range *range);
......@@ -157,6 +172,11 @@ struct clk_hw * __init
at91_clk_register_plldiv(struct regmap *regmap, const char *name,
const char *parent_name);
struct clk_hw * __init
sam9x60_clk_register_pll(struct regmap *regmap, spinlock_t *lock,
const char *name, const char *parent_name, u8 id,
const struct clk_pll_characteristics *characteristics);
struct clk_hw * __init
at91_clk_register_programmable(struct regmap *regmap, const char *name,
const char **parent_names, u8 num_parents, u8 id,
......@@ -183,6 +203,9 @@ struct clk_hw * __init
at91sam9n12_clk_register_usb(struct regmap *regmap, const char *name,
const char *parent_name);
struct clk_hw * __init
sam9x60_clk_register_usb(struct regmap *regmap, const char *name,
const char **parent_names, u8 num_parents);
struct clk_hw * __init
at91rm9200_clk_register_usb(struct regmap *regmap, const char *name,
const char *parent_name, const u32 *divisors);
......
// SPDX-License-Identifier: GPL-2.0
#include <linux/clk-provider.h>
#include <linux/mfd/syscon.h>
#include <linux/slab.h>
#include <dt-bindings/clock/at91.h>
#include "pmc.h"
static DEFINE_SPINLOCK(pmc_pll_lock);
static const struct clk_master_characteristics mck_characteristics = {
.output = { .min = 140000000, .max = 200000000 },
.divisors = { 1, 2, 4, 3 },
.have_div3_pres = 1,
};
static const struct clk_master_layout sam9x60_master_layout = {
.mask = 0x373,
.pres_shift = 4,
.offset = 0x28,
};
static const struct clk_range plla_outputs[] = {
{ .min = 300000000, .max = 600000000 },
};
static const struct clk_pll_characteristics plla_characteristics = {
.input = { .min = 12000000, .max = 48000000 },
.num_output = ARRAY_SIZE(plla_outputs),
.output = plla_outputs,
};
static const struct clk_range upll_outputs[] = {
{ .min = 300000000, .max = 500000000 },
};
static const struct clk_pll_characteristics upll_characteristics = {
.input = { .min = 12000000, .max = 48000000 },
.num_output = ARRAY_SIZE(upll_outputs),
.output = upll_outputs,
.upll = true,
};
static const struct clk_programmable_layout sam9x60_programmable_layout = {
.pres_shift = 8,
.css_mask = 0x1f,
.have_slck_mck = 0,
};
static const struct clk_pcr_layout sam9x60_pcr_layout = {
.offset = 0x88,
.cmd = BIT(31),
.gckcss_mask = GENMASK(12, 8),
.pid_mask = GENMASK(6, 0),
};
static const struct {
char *n;
char *p;
u8 id;
} sam9x60_systemck[] = {
{ .n = "ddrck", .p = "masterck", .id = 2 },
{ .n = "uhpck", .p = "usbck", .id = 6 },
{ .n = "pck0", .p = "prog0", .id = 8 },
{ .n = "pck1", .p = "prog1", .id = 9 },
{ .n = "qspick", .p = "masterck", .id = 19 },
};
static const struct {
char *n;
u8 id;
} sam9x60_periphck[] = {
{ .n = "pioA_clk", .id = 2, },
{ .n = "pioB_clk", .id = 3, },
{ .n = "pioC_clk", .id = 4, },
{ .n = "flex0_clk", .id = 5, },
{ .n = "flex1_clk", .id = 6, },
{ .n = "flex2_clk", .id = 7, },
{ .n = "flex3_clk", .id = 8, },
{ .n = "flex6_clk", .id = 9, },
{ .n = "flex7_clk", .id = 10, },
{ .n = "flex8_clk", .id = 11, },
{ .n = "sdmmc0_clk", .id = 12, },
{ .n = "flex4_clk", .id = 13, },
{ .n = "flex5_clk", .id = 14, },
{ .n = "flex9_clk", .id = 15, },
{ .n = "flex10_clk", .id = 16, },
{ .n = "tcb0_clk", .id = 17, },
{ .n = "pwm_clk", .id = 18, },
{ .n = "adc_clk", .id = 19, },
{ .n = "dma0_clk", .id = 20, },
{ .n = "matrix_clk", .id = 21, },
{ .n = "uhphs_clk", .id = 22, },
{ .n = "udphs_clk", .id = 23, },
{ .n = "macb0_clk", .id = 24, },
{ .n = "lcd_clk", .id = 25, },
{ .n = "sdmmc1_clk", .id = 26, },
{ .n = "macb1_clk", .id = 27, },
{ .n = "ssc_clk", .id = 28, },
{ .n = "can0_clk", .id = 29, },
{ .n = "can1_clk", .id = 30, },
{ .n = "flex11_clk", .id = 32, },
{ .n = "flex12_clk", .id = 33, },
{ .n = "i2s_clk", .id = 34, },
{ .n = "qspi_clk", .id = 35, },
{ .n = "gfx2d_clk", .id = 36, },
{ .n = "pit64b_clk", .id = 37, },
{ .n = "trng_clk", .id = 38, },
{ .n = "aes_clk", .id = 39, },
{ .n = "tdes_clk", .id = 40, },
{ .n = "sha_clk", .id = 41, },
{ .n = "classd_clk", .id = 42, },
{ .n = "isi_clk", .id = 43, },
{ .n = "pioD_clk", .id = 44, },
{ .n = "tcb1_clk", .id = 45, },
{ .n = "dbgu_clk", .id = 47, },
{ .n = "mpddr_clk", .id = 49, },
};
static const struct {
char *n;
u8 id;
struct clk_range r;
bool pll;
} sam9x60_gck[] = {
{ .n = "flex0_gclk", .id = 5, },
{ .n = "flex1_gclk", .id = 6, },
{ .n = "flex2_gclk", .id = 7, },
{ .n = "flex3_gclk", .id = 8, },
{ .n = "flex6_gclk", .id = 9, },
{ .n = "flex7_gclk", .id = 10, },
{ .n = "flex8_gclk", .id = 11, },
{ .n = "sdmmc0_gclk", .id = 12, .r = { .min = 0, .max = 105000000 }, },
{ .n = "flex4_gclk", .id = 13, },
{ .n = "flex5_gclk", .id = 14, },
{ .n = "flex9_gclk", .id = 15, },
{ .n = "flex10_gclk", .id = 16, },
{ .n = "tcb0_gclk", .id = 17, },
{ .n = "adc_gclk", .id = 19, },
{ .n = "lcd_gclk", .id = 25, .r = { .min = 0, .max = 140000000 }, },
{ .n = "sdmmc1_gclk", .id = 26, .r = { .min = 0, .max = 105000000 }, },
{ .n = "flex11_gclk", .id = 32, },
{ .n = "flex12_gclk", .id = 33, },
{ .n = "i2s_gclk", .id = 34, .r = { .min = 0, .max = 105000000 },
.pll = true, },
{ .n = "pit64b_gclk", .id = 37, },
{ .n = "classd_gclk", .id = 42, .r = { .min = 0, .max = 100000000 },
.pll = true, },
{ .n = "tcb1_gclk", .id = 45, },
{ .n = "dbgu_gclk", .id = 47, },
};
static void __init sam9x60_pmc_setup(struct device_node *np)
{
struct clk_range range = CLK_RANGE(0, 0);
const char *td_slck_name, *md_slck_name, *mainxtal_name;
struct pmc_data *sam9x60_pmc;
const char *parent_names[6];
struct regmap *regmap;
struct clk_hw *hw;
int i;
bool bypass;
i = of_property_match_string(np, "clock-names", "td_slck");
if (i < 0)
return;
td_slck_name = of_clk_get_parent_name(np, i);
i = of_property_match_string(np, "clock-names", "md_slck");
if (i < 0)
return;
md_slck_name = of_clk_get_parent_name(np, i);
i = of_property_match_string(np, "clock-names", "main_xtal");
if (i < 0)
return;
mainxtal_name = of_clk_get_parent_name(np, i);
regmap = syscon_node_to_regmap(np);
if (IS_ERR(regmap))
return;
sam9x60_pmc = pmc_data_allocate(PMC_MAIN + 1,
nck(sam9x60_systemck),
nck(sam9x60_periphck),
nck(sam9x60_gck));
if (!sam9x60_pmc)
return;
hw = at91_clk_register_main_rc_osc(regmap, "main_rc_osc", 24000000,
50000000);
if (IS_ERR(hw))
goto err_free;
bypass = of_property_read_bool(np, "atmel,osc-bypass");
hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name,
bypass);
if (IS_ERR(hw))
goto err_free;
parent_names[0] = "main_rc_osc";
parent_names[1] = "main_osc";
hw = at91_clk_register_sam9x5_main(regmap, "mainck", parent_names, 2);
if (IS_ERR(hw))
goto err_free;
sam9x60_pmc->chws[PMC_MAIN] = hw;
hw = sam9x60_clk_register_pll(regmap, &pmc_pll_lock, "pllack",
"mainck", 0, &plla_characteristics);
if (IS_ERR(hw))
goto err_free;
hw = sam9x60_clk_register_pll(regmap, &pmc_pll_lock, "upllck",
"main_osc", 1, &upll_characteristics);
if (IS_ERR(hw))
goto err_free;
sam9x60_pmc->chws[PMC_UTMI] = hw;
parent_names[0] = md_slck_name;
parent_names[1] = "mainck";
parent_names[2] = "pllack";
hw = at91_clk_register_master(regmap, "masterck", 3, parent_names,
&sam9x60_master_layout,
&mck_characteristics);
if (IS_ERR(hw))
goto err_free;
sam9x60_pmc->chws[PMC_MCK] = hw;
parent_names[0] = "pllack";
parent_names[1] = "upllck";
parent_names[2] = "mainck";
parent_names[3] = "mainck";
hw = sam9x60_clk_register_usb(regmap, "usbck", parent_names, 4);
if (IS_ERR(hw))
goto err_free;
parent_names[0] = md_slck_name;
parent_names[1] = td_slck_name;
parent_names[2] = "mainck";
parent_names[3] = "masterck";
parent_names[4] = "pllack";
parent_names[5] = "upllck";
for (i = 0; i < 8; i++) {
char name[6];
snprintf(name, sizeof(name), "prog%d", i);
hw = at91_clk_register_programmable(regmap, name,
parent_names, 6, i,
&sam9x60_programmable_layout);
if (IS_ERR(hw))
goto err_free;
}
for (i = 0; i < ARRAY_SIZE(sam9x60_systemck); i++) {
hw = at91_clk_register_system(regmap, sam9x60_systemck[i].n,
sam9x60_systemck[i].p,
sam9x60_systemck[i].id);
if (IS_ERR(hw))
goto err_free;
sam9x60_pmc->shws[sam9x60_systemck[i].id] = hw;
}
for (i = 0; i < ARRAY_SIZE(sam9x60_periphck); i++) {
hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
&sam9x60_pcr_layout,
sam9x60_periphck[i].n,
"masterck",
sam9x60_periphck[i].id,
&range);
if (IS_ERR(hw))
goto err_free;
sam9x60_pmc->phws[sam9x60_periphck[i].id] = hw;
}
for (i = 0; i < ARRAY_SIZE(sam9x60_gck); i++) {
hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
&sam9x60_pcr_layout,
sam9x60_gck[i].n,
parent_names, 6,
sam9x60_gck[i].id,
sam9x60_gck[i].pll,
&sam9x60_gck[i].r);
if (IS_ERR(hw))
goto err_free;
sam9x60_pmc->ghws[sam9x60_gck[i].id] = hw;
}
of_clk_add_hw_provider(np, of_clk_hw_pmc_get, sam9x60_pmc);
return;
err_free:
pmc_data_free(sam9x60_pmc);
}
/* Some clks are used for a clocksource */
CLK_OF_DECLARE(sam9x60_pmc, "microchip,sam9x60-pmc", sam9x60_pmc_setup);
......@@ -16,7 +16,7 @@ static u8 plla_out[] = { 0 };
static u16 plla_icpll[] = { 0 };
static struct clk_range plla_outputs[] = {
static const struct clk_range plla_outputs[] = {
{ .min = 600000000, .max = 1200000000 },
};
......@@ -28,6 +28,13 @@ static const struct clk_pll_characteristics plla_characteristics = {
.out = plla_out,
};
static const struct clk_pcr_layout sama5d2_pcr_layout = {
.offset = 0x10c,
.cmd = BIT(12),
.gckcss_mask = GENMASK(10, 8),
.pid_mask = GENMASK(6, 0),
};
static const struct {
char *n;
char *p;
......@@ -274,6 +281,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
for (i = 0; i < ARRAY_SIZE(sama5d2_periphck); i++) {
hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
&sama5d2_pcr_layout,
sama5d2_periphck[i].n,
"masterck",
sama5d2_periphck[i].id,
......@@ -286,6 +294,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
for (i = 0; i < ARRAY_SIZE(sama5d2_periph32ck); i++) {
hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
&sama5d2_pcr_layout,
sama5d2_periph32ck[i].n,
"h32mxck",
sama5d2_periph32ck[i].id,
......@@ -304,6 +313,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
parent_names[5] = "audiopll_pmcck";
for (i = 0; i < ARRAY_SIZE(sama5d2_gck); i++) {
hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
&sama5d2_pcr_layout,
sama5d2_gck[i].n,
parent_names, 6,
sama5d2_gck[i].id,
......
......@@ -16,7 +16,7 @@ static u8 plla_out[] = { 0 };
static u16 plla_icpll[] = { 0 };
static struct clk_range plla_outputs[] = {
static const struct clk_range plla_outputs[] = {
{ .min = 600000000, .max = 1200000000 },
};
......@@ -28,6 +28,12 @@ static const struct clk_pll_characteristics plla_characteristics = {
.out = plla_out,
};
static const struct clk_pcr_layout sama5d4_pcr_layout = {
.offset = 0x10c,
.cmd = BIT(12),
.pid_mask = GENMASK(6, 0),
};
static const struct {
char *n;
char *p;
......@@ -232,6 +238,7 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
for (i = 0; i < ARRAY_SIZE(sama5d4_periphck); i++) {
hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
&sama5d4_pcr_layout,
sama5d4_periphck[i].n,
"masterck",
sama5d4_periphck[i].id,
......@@ -244,6 +251,7 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
for (i = 0; i < ARRAY_SIZE(sama5d4_periph32ck); i++) {
hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
&sama5d4_pcr_layout,
sama5d4_periph32ck[i].n,
"h32mxck",
sama5d4_periph32ck[i].id,
......
......@@ -152,28 +152,6 @@ at91_clk_register_slow_osc(void __iomem *sckcr,
return hw;
}
static void __init
of_at91sam9x5_clk_slow_osc_setup(struct device_node *np, void __iomem *sckcr)
{
struct clk_hw *hw;
const char *parent_name;
const char *name = np->name;
u32 startup;
bool bypass;
parent_name = of_clk_get_parent_name(np, 0);
of_property_read_string(np, "clock-output-names", &name);
of_property_read_u32(np, "atmel,startup-time-usec", &startup);
bypass = of_property_read_bool(np, "atmel,osc-bypass");
hw = at91_clk_register_slow_osc(sckcr, name, parent_name, startup,
bypass);
if (IS_ERR(hw))
return;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
static unsigned long clk_slow_rc_osc_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
......@@ -266,28 +244,6 @@ at91_clk_register_slow_rc_osc(void __iomem *sckcr,
return hw;
}
static void __init
of_at91sam9x5_clk_slow_rc_osc_setup(struct device_node *np, void __iomem *sckcr)
{
struct clk_hw *hw;
u32 frequency = 0;
u32 accuracy = 0;
u32 startup = 0;
const char *name = np->name;
of_property_read_string(np, "clock-output-names", &name);
of_property_read_u32(np, "clock-frequency", &frequency);
of_property_read_u32(np, "clock-accuracy", &accuracy);
of_property_read_u32(np, "atmel,startup-time-usec", &startup);
hw = at91_clk_register_slow_rc_osc(sckcr, name, frequency, accuracy,
startup);
if (IS_ERR(hw))
return;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index)
{
struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw);
......@@ -365,68 +321,72 @@ at91_clk_register_sam9x5_slow(void __iomem *sckcr,
return hw;
}
static void __init
of_at91sam9x5_clk_slow_setup(struct device_node *np, void __iomem *sckcr)
static void __init at91sam9x5_sckc_register(struct device_node *np,
unsigned int rc_osc_startup_us)
{
const char *parent_names[2] = { "slow_rc_osc", "slow_osc" };
void __iomem *regbase = of_iomap(np, 0);
struct device_node *child = NULL;
const char *xtal_name;
struct clk_hw *hw;
const char *parent_names[2];
unsigned int num_parents;
const char *name = np->name;
bool bypass;
num_parents = of_clk_get_parent_count(np);
if (num_parents == 0 || num_parents > 2)
if (!regbase)
return;
hw = at91_clk_register_slow_rc_osc(regbase, parent_names[0], 32768,
50000000, rc_osc_startup_us);
if (IS_ERR(hw))
return;
of_clk_parent_fill(np, parent_names, num_parents);
xtal_name = of_clk_get_parent_name(np, 0);
if (!xtal_name) {
/* DT backward compatibility */
child = of_get_compatible_child(np, "atmel,at91sam9x5-clk-slow-osc");
if (!child)
return;
xtal_name = of_clk_get_parent_name(child, 0);
bypass = of_property_read_bool(child, "atmel,osc-bypass");
child = of_get_compatible_child(np, "atmel,at91sam9x5-clk-slow");
} else {
bypass = of_property_read_bool(np, "atmel,osc-bypass");
}
if (!xtal_name)
return;
of_property_read_string(np, "clock-output-names", &name);
hw = at91_clk_register_slow_osc(regbase, parent_names[1], xtal_name,
1200000, bypass);
if (IS_ERR(hw))
return;
hw = at91_clk_register_sam9x5_slow(sckcr, name, parent_names,
num_parents);
hw = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names, 2);
if (IS_ERR(hw))
return;
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
static const struct of_device_id sckc_clk_ids[] __initconst = {
/* Slow clock */
{
.compatible = "atmel,at91sam9x5-clk-slow-osc",
.data = of_at91sam9x5_clk_slow_osc_setup,
},
{
.compatible = "atmel,at91sam9x5-clk-slow-rc-osc",
.data = of_at91sam9x5_clk_slow_rc_osc_setup,
},
{
.compatible = "atmel,at91sam9x5-clk-slow",
.data = of_at91sam9x5_clk_slow_setup,
},
{ /*sentinel*/ }
};
/* DT backward compatibility */
if (child)
of_clk_add_hw_provider(child, of_clk_hw_simple_get, hw);
}
static void __init of_at91sam9x5_sckc_setup(struct device_node *np)
{
struct device_node *childnp;
void (*clk_setup)(struct device_node *, void __iomem *);
const struct of_device_id *clk_id;
void __iomem *regbase = of_iomap(np, 0);
if (!regbase)
return;
for_each_child_of_node(np, childnp) {
clk_id = of_match_node(sckc_clk_ids, childnp);
if (!clk_id)
continue;
clk_setup = clk_id->data;
clk_setup(childnp, regbase);
}
at91sam9x5_sckc_register(np, 75);
}
CLK_OF_DECLARE(at91sam9x5_clk_sckc, "atmel,at91sam9x5-sckc",
of_at91sam9x5_sckc_setup);
static void __init of_sama5d3_sckc_setup(struct device_node *np)
{
at91sam9x5_sckc_register(np, 500);
}
CLK_OF_DECLARE(sama5d3_clk_sckc, "atmel,sama5d3-sckc",
of_sama5d3_sckc_setup);
static int clk_sama5d4_slow_osc_prepare(struct clk_hw *hw)
{
struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw);
......
......@@ -87,10 +87,10 @@ struct aspeed_clk_gate {
/* TODO: ask Aspeed about the actual parent data */
static const struct aspeed_gate_data aspeed_gates[] = {
/* clk rst name parent flags */
[ASPEED_CLK_GATE_ECLK] = { 0, -1, "eclk-gate", "eclk", 0 }, /* Video Engine */
[ASPEED_CLK_GATE_ECLK] = { 0, 6, "eclk-gate", "eclk", 0 }, /* Video Engine */
[ASPEED_CLK_GATE_GCLK] = { 1, 7, "gclk-gate", NULL, 0 }, /* 2D engine */
[ASPEED_CLK_GATE_MCLK] = { 2, -1, "mclk-gate", "mpll", CLK_IS_CRITICAL }, /* SDRAM */
[ASPEED_CLK_GATE_VCLK] = { 3, 6, "vclk-gate", NULL, 0 }, /* Video Capture */
[ASPEED_CLK_GATE_VCLK] = { 3, -1, "vclk-gate", NULL, 0 }, /* Video Capture */
[ASPEED_CLK_GATE_BCLK] = { 4, 8, "bclk-gate", "bclk", CLK_IS_CRITICAL }, /* PCIe/PCI */
[ASPEED_CLK_GATE_DCLK] = { 5, -1, "dclk-gate", NULL, CLK_IS_CRITICAL }, /* DAC */
[ASPEED_CLK_GATE_REFCLK] = { 6, -1, "refclk-gate", "clkin", CLK_IS_CRITICAL },
......@@ -113,6 +113,24 @@ static const struct aspeed_gate_data aspeed_gates[] = {
[ASPEED_CLK_GATE_LHCCLK] = { 28, -1, "lhclk-gate", "lhclk", 0 }, /* LPC master/LPC+ */
};
static const char * const eclk_parent_names[] = {
"mpll",
"hpll",
"dpll",
};
static const struct clk_div_table ast2500_eclk_div_table[] = {
{ 0x0, 2 },
{ 0x1, 2 },
{ 0x2, 3 },
{ 0x3, 4 },
{ 0x4, 5 },
{ 0x5, 6 },
{ 0x6, 7 },
{ 0x7, 8 },
{ 0 }
};
static const struct clk_div_table ast2500_mac_div_table[] = {
{ 0x0, 4 }, /* Yep, really. Aspeed confirmed this is correct */
{ 0x1, 4 },
......@@ -192,18 +210,21 @@ static struct clk_hw *aspeed_ast2500_calc_pll(const char *name, u32 val)
struct aspeed_clk_soc_data {
const struct clk_div_table *div_table;
const struct clk_div_table *eclk_div_table;
const struct clk_div_table *mac_div_table;
struct clk_hw *(*calc_pll)(const char *name, u32 val);
};
static const struct aspeed_clk_soc_data ast2500_data = {
.div_table = ast2500_div_table,
.eclk_div_table = ast2500_eclk_div_table,
.mac_div_table = ast2500_mac_div_table,
.calc_pll = aspeed_ast2500_calc_pll,
};
static const struct aspeed_clk_soc_data ast2400_data = {
.div_table = ast2400_div_table,
.eclk_div_table = ast2400_div_table,
.mac_div_table = ast2400_div_table,
.calc_pll = aspeed_ast2400_calc_pll,
};
......@@ -522,6 +543,22 @@ static int aspeed_clk_probe(struct platform_device *pdev)
return PTR_ERR(hw);
aspeed_clk_data->hws[ASPEED_CLK_24M] = hw;
hw = clk_hw_register_mux(dev, "eclk-mux", eclk_parent_names,
ARRAY_SIZE(eclk_parent_names), 0,
scu_base + ASPEED_CLK_SELECTION, 2, 0x3, 0,
&aspeed_clk_lock);
if (IS_ERR(hw))
return PTR_ERR(hw);
aspeed_clk_data->hws[ASPEED_CLK_ECLK_MUX] = hw;
hw = clk_hw_register_divider_table(dev, "eclk", "eclk-mux", 0,
scu_base + ASPEED_CLK_SELECTION, 28,
3, 0, soc_data->eclk_div_table,
&aspeed_clk_lock);
if (IS_ERR(hw))
return PTR_ERR(hw);
aspeed_clk_data->hws[ASPEED_CLK_ECLK] = hw;
/*
* TODO: There are a number of clocks that not included in this driver
* as more information is required:
......@@ -531,7 +568,6 @@ static int aspeed_clk_probe(struct platform_device *pdev)
* RGMII
* RMII
* UART[1..5] clock source mux
* Video Engine (ECLK) mux and clock divider
*/
for (i = 0; i < ARRAY_SIZE(aspeed_gates); i++) {
......
......@@ -218,7 +218,7 @@ struct clk_hw *clk_hw_register_composite(struct device *dev, const char *name,
return ERR_PTR(-ENOMEM);
init.name = name;
init.flags = flags | CLK_IS_BASIC;
init.flags = flags;
init.parent_names = parent_names;
init.num_parents = num_parents;
hw = &composite->hw;
......
......@@ -25,6 +25,22 @@
* parent - fixed parent. No clk_set_parent support
*/
static inline u32 clk_div_readl(struct clk_divider *divider)
{
if (divider->flags & CLK_DIVIDER_BIG_ENDIAN)
return ioread32be(divider->reg);
return readl(divider->reg);
}
static inline void clk_div_writel(struct clk_divider *divider, u32 val)
{
if (divider->flags & CLK_DIVIDER_BIG_ENDIAN)
iowrite32be(val, divider->reg);
else
writel(val, divider->reg);
}
static unsigned int _get_table_maxdiv(const struct clk_div_table *table,
u8 width)
{
......@@ -135,7 +151,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
struct clk_divider *divider = to_clk_divider(hw);
unsigned int val;
val = clk_readl(divider->reg) >> divider->shift;
val = clk_div_readl(divider) >> divider->shift;
val &= clk_div_mask(divider->width);
return divider_recalc_rate(hw, parent_rate, val, divider->table,
......@@ -370,7 +386,7 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
if (divider->flags & CLK_DIVIDER_READ_ONLY) {
u32 val;
val = clk_readl(divider->reg) >> divider->shift;
val = clk_div_readl(divider) >> divider->shift;
val &= clk_div_mask(divider->width);
return divider_ro_round_rate(hw, rate, prate, divider->table,
......@@ -420,11 +436,11 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
val = clk_div_mask(divider->width) << (divider->shift + 16);
} else {
val = clk_readl(divider->reg);
val = clk_div_readl(divider);
val &= ~(clk_div_mask(divider->width) << divider->shift);
}
val |= (u32)value << divider->shift;
clk_writel(val, divider->reg);
clk_div_writel(divider, val);
if (divider->lock)
spin_unlock_irqrestore(divider->lock, flags);
......@@ -475,7 +491,7 @@ static struct clk_hw *_register_divider(struct device *dev, const char *name,
init.ops = &clk_divider_ro_ops;
else
init.ops = &clk_divider_ops;
init.flags = flags | CLK_IS_BASIC;
init.flags = flags;
init.parent_names = (parent_name ? &parent_name: NULL);
init.num_parents = (parent_name ? 1 : 0);
......
......@@ -64,12 +64,14 @@ const struct clk_ops clk_fixed_factor_ops = {
};
EXPORT_SYMBOL_GPL(clk_fixed_factor_ops);
struct clk_hw *clk_hw_register_fixed_factor(struct device *dev,
const char *name, const char *parent_name, unsigned long flags,
unsigned int mult, unsigned int div)
static struct clk_hw *
__clk_hw_register_fixed_factor(struct device *dev, struct device_node *np,
const char *name, const char *parent_name, int index,
unsigned long flags, unsigned int mult, unsigned int div)
{
struct clk_fixed_factor *fix;
struct clk_init_data init;
struct clk_init_data init = { };
struct clk_parent_data pdata = { .index = index };
struct clk_hw *hw;
int ret;
......@@ -84,12 +86,18 @@ struct clk_hw *clk_hw_register_fixed_factor(struct device *dev,
init.name = name;
init.ops = &clk_fixed_factor_ops;
init.flags = flags | CLK_IS_BASIC;
init.parent_names = &parent_name;
init.flags = flags;
if (parent_name)
init.parent_names = &parent_name;
else
init.parent_data = &pdata;
init.num_parents = 1;
hw = &fix->hw;
ret = clk_hw_register(dev, hw);
if (dev)
ret = clk_hw_register(dev, hw);
else
ret = of_clk_hw_register(np, hw);
if (ret) {
kfree(fix);
hw = ERR_PTR(ret);
......@@ -97,6 +105,14 @@ struct clk_hw *clk_hw_register_fixed_factor(struct device *dev,
return hw;
}
struct clk_hw *clk_hw_register_fixed_factor(struct device *dev,
const char *name, const char *parent_name, unsigned long flags,
unsigned int mult, unsigned int div)
{
return __clk_hw_register_fixed_factor(dev, NULL, name, parent_name, -1,
flags, mult, div);
}
EXPORT_SYMBOL_GPL(clk_hw_register_fixed_factor);
struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
......@@ -143,11 +159,10 @@ static const struct of_device_id set_rate_parent_matches[] = {
{ /* Sentinel */ },
};
static struct clk *_of_fixed_factor_clk_setup(struct device_node *node)
static struct clk_hw *_of_fixed_factor_clk_setup(struct device_node *node)
{
struct clk *clk;
struct clk_hw *hw;
const char *clk_name = node->name;
const char *parent_name;
unsigned long flags = 0;
u32 div, mult;
int ret;
......@@ -165,30 +180,28 @@ static struct clk *_of_fixed_factor_clk_setup(struct device_node *node)
}
of_property_read_string(node, "clock-output-names", &clk_name);
parent_name = of_clk_get_parent_name(node, 0);
if (of_match_node(set_rate_parent_matches, node))
flags |= CLK_SET_RATE_PARENT;
clk = clk_register_fixed_factor(NULL, clk_name, parent_name, flags,
mult, div);
if (IS_ERR(clk)) {
hw = __clk_hw_register_fixed_factor(NULL, node, clk_name, NULL, 0,
flags, mult, div);
if (IS_ERR(hw)) {
/*
* If parent clock is not registered, registration would fail.
* Clear OF_POPULATED flag so that clock registration can be
* attempted again from probe function.
*/
of_node_clear_flag(node, OF_POPULATED);
return clk;
return ERR_CAST(hw);
}
ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw);
if (ret) {
clk_unregister(clk);
clk_hw_unregister_fixed_factor(hw);
return ERR_PTR(ret);
}
return clk;
return hw;
}
/**
......@@ -203,17 +216,17 @@ CLK_OF_DECLARE(fixed_factor_clk, "fixed-factor-clock",
static int of_fixed_factor_clk_remove(struct platform_device *pdev)
{
struct clk *clk = platform_get_drvdata(pdev);
struct clk_hw *clk = platform_get_drvdata(pdev);
of_clk_del_provider(pdev->dev.of_node);
clk_unregister_fixed_factor(clk);
clk_hw_unregister_fixed_factor(clk);
return 0;
}
static int of_fixed_factor_clk_probe(struct platform_device *pdev)
{
struct clk *clk;
struct clk_hw *clk;
/*
* This function is not executed when of_fixed_factor_clk_setup
......
......@@ -68,7 +68,7 @@ struct clk_hw *clk_hw_register_fixed_rate_with_accuracy(struct device *dev,
init.name = name;
init.ops = &clk_fixed_rate_ops;
init.flags = flags | CLK_IS_BASIC;
init.flags = flags;
init.parent_names = (parent_name ? &parent_name: NULL);
init.num_parents = (parent_name ? 1 : 0);
......
......@@ -13,6 +13,22 @@
#include <linux/slab.h>
#include <linux/rational.h>
static inline u32 clk_fd_readl(struct clk_fractional_divider *fd)
{
if (fd->flags & CLK_FRAC_DIVIDER_BIG_ENDIAN)
return ioread32be(fd->reg);
return readl(fd->reg);
}
static inline void clk_fd_writel(struct clk_fractional_divider *fd, u32 val)
{
if (fd->flags & CLK_FRAC_DIVIDER_BIG_ENDIAN)
iowrite32be(val, fd->reg);
else
writel(val, fd->reg);
}
static unsigned long clk_fd_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
......@@ -27,7 +43,7 @@ static unsigned long clk_fd_recalc_rate(struct clk_hw *hw,
else
__acquire(fd->lock);
val = clk_readl(fd->reg);
val = clk_fd_readl(fd);
if (fd->lock)
spin_unlock_irqrestore(fd->lock, flags);
......@@ -115,10 +131,10 @@ static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate,
else
__acquire(fd->lock);
val = clk_readl(fd->reg);
val = clk_fd_readl(fd);
val &= ~(fd->mmask | fd->nmask);
val |= (m << fd->mshift) | (n << fd->nshift);
clk_writel(val, fd->reg);
clk_fd_writel(fd, val);
if (fd->lock)
spin_unlock_irqrestore(fd->lock, flags);
......@@ -151,7 +167,7 @@ struct clk_hw *clk_hw_register_fractional_divider(struct device *dev,
init.name = name;
init.ops = &clk_fractional_divider_ops;
init.flags = flags | CLK_IS_BASIC;
init.flags = flags;
init.parent_names = parent_name ? &parent_name : NULL;
init.num_parents = parent_name ? 1 : 0;
......
......@@ -23,6 +23,22 @@
* parent - fixed parent. No clk_set_parent support
*/
static inline u32 clk_gate_readl(struct clk_gate *gate)
{
if (gate->flags & CLK_GATE_BIG_ENDIAN)
return ioread32be(gate->reg);
return readl(gate->reg);
}
static inline void clk_gate_writel(struct clk_gate *gate, u32 val)
{
if (gate->flags & CLK_GATE_BIG_ENDIAN)
iowrite32be(val, gate->reg);
else
writel(val, gate->reg);
}
/*
* It works on following logic:
*
......@@ -55,7 +71,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
if (set)
reg |= BIT(gate->bit_idx);
} else {
reg = clk_readl(gate->reg);
reg = clk_gate_readl(gate);
if (set)
reg |= BIT(gate->bit_idx);
......@@ -63,7 +79,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
reg &= ~BIT(gate->bit_idx);
}
clk_writel(reg, gate->reg);
clk_gate_writel(gate, reg);
if (gate->lock)
spin_unlock_irqrestore(gate->lock, flags);
......@@ -88,7 +104,7 @@ int clk_gate_is_enabled(struct clk_hw *hw)
u32 reg;
struct clk_gate *gate = to_clk_gate(hw);
reg = clk_readl(gate->reg);
reg = clk_gate_readl(gate);
/* if a set bit disables this clk, flip it before masking */
if (gate->flags & CLK_GATE_SET_TO_DISABLE)
......@@ -142,7 +158,7 @@ struct clk_hw *clk_hw_register_gate(struct device *dev, const char *name,
init.name = name;
init.ops = &clk_gate_ops;
init.flags = flags | CLK_IS_BASIC;
init.flags = flags;
init.parent_names = parent_name ? &parent_name : NULL;
init.num_parents = parent_name ? 1 : 0;
......
......@@ -137,7 +137,7 @@ static struct clk_hw *clk_register_gpio(struct device *dev, const char *name,
init.name = name;
init.ops = clk_gpio_ops;
init.flags = flags | CLK_IS_BASIC;
init.flags = flags;
init.parent_names = parent_names;
init.num_parents = num_parents;
......
......@@ -17,7 +17,6 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/of.h>
......@@ -272,7 +271,7 @@ static const struct clk_ops periclk_ops = {
.set_rate = clk_periclk_set_rate,
};
static __init struct clk *hb_clk_init(struct device_node *node, const struct clk_ops *ops)
static void __init hb_clk_init(struct device_node *node, const struct clk_ops *ops, unsigned long clkflags)
{
u32 reg;
struct hb_clk *hb_clk;
......@@ -284,11 +283,11 @@ static __init struct clk *hb_clk_init(struct device_node *node, const struct clk
rc = of_property_read_u32(node, "reg", &reg);
if (WARN_ON(rc))
return NULL;
return;
hb_clk = kzalloc(sizeof(*hb_clk), GFP_KERNEL);
if (WARN_ON(!hb_clk))
return NULL;
return;
/* Map system registers */
srnp = of_find_compatible_node(NULL, NULL, "calxeda,hb-sregs");
......@@ -301,7 +300,7 @@ static __init struct clk *hb_clk_init(struct device_node *node, const struct clk
init.name = clk_name;
init.ops = ops;
init.flags = 0;
init.flags = clkflags;
parent_name = of_clk_get_parent_name(node, 0);
init.parent_names = &parent_name;
init.num_parents = 1;
......@@ -311,33 +310,31 @@ static __init struct clk *hb_clk_init(struct device_node *node, const struct clk
rc = clk_hw_register(NULL, &hb_clk->hw);
if (WARN_ON(rc)) {
kfree(hb_clk);
return NULL;
return;
}
rc = of_clk_add_hw_provider(node, of_clk_hw_simple_get, &hb_clk->hw);
return hb_clk->hw.clk;
of_clk_add_hw_provider(node, of_clk_hw_simple_get, &hb_clk->hw);
}
static void __init hb_pll_init(struct device_node *node)
{
hb_clk_init(node, &clk_pll_ops);
hb_clk_init(node, &clk_pll_ops, 0);
}
CLK_OF_DECLARE(hb_pll, "calxeda,hb-pll-clock", hb_pll_init);
static void __init hb_a9periph_init(struct device_node *node)
{
hb_clk_init(node, &a9periphclk_ops);
hb_clk_init(node, &a9periphclk_ops, 0);
}
CLK_OF_DECLARE(hb_a9periph, "calxeda,hb-a9periph-clock", hb_a9periph_init);
static void __init hb_a9bus_init(struct device_node *node)
{
struct clk *clk = hb_clk_init(node, &a9bclk_ops);
clk_prepare_enable(clk);
hb_clk_init(node, &a9bclk_ops, CLK_IS_CRITICAL);
}
CLK_OF_DECLARE(hb_a9bus, "calxeda,hb-a9bus-clock", hb_a9bus_init);
static void __init hb_emmc_init(struct device_node *node)
{
hb_clk_init(node, &periclk_ops);
hb_clk_init(node, &periclk_ops, 0);
}
CLK_OF_DECLARE(hb_emmc, "calxeda,hb-emmc-clock", hb_emmc_init);
// SPDX-License-Identifier: GPL-2.0
/*
* Lochnagar clock control
*
* Copyright (c) 2017-2018 Cirrus Logic, Inc. and
* Cirrus Logic International Semiconductor Ltd.
*
* Author: Charles Keepax <ckeepax@opensource.cirrus.com>
*/
#include <linux/clk-provider.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/mfd/lochnagar.h>
#include <linux/mfd/lochnagar1_regs.h>
#include <linux/mfd/lochnagar2_regs.h>
#include <dt-bindings/clk/lochnagar.h>
#define LOCHNAGAR_NUM_CLOCKS (LOCHNAGAR_SPDIF_CLKOUT + 1)
struct lochnagar_clk {
const char * const name;
struct clk_hw hw;
struct lochnagar_clk_priv *priv;
u16 cfg_reg;
u16 ena_mask;
u16 src_reg;
u16 src_mask;
};
struct lochnagar_clk_priv {
struct device *dev;
struct regmap *regmap;
enum lochnagar_type type;
const char **parents;
unsigned int nparents;
struct lochnagar_clk lclks[LOCHNAGAR_NUM_CLOCKS];
};
static const char * const lochnagar1_clk_parents[] = {
"ln-none",
"ln-spdif-mclk",
"ln-psia1-mclk",
"ln-psia2-mclk",
"ln-cdc-clkout",
"ln-dsp-clkout",
"ln-pmic-32k",
"ln-gf-mclk1",
"ln-gf-mclk3",
"ln-gf-mclk2",
"ln-gf-mclk4",
};
static const char * const lochnagar2_clk_parents[] = {
"ln-none",
"ln-cdc-clkout",
"ln-dsp-clkout",
"ln-pmic-32k",
"ln-spdif-mclk",
"ln-clk-12m",
"ln-clk-11m",
"ln-clk-24m",
"ln-clk-22m",
"ln-clk-8m",
"ln-usb-clk-24m",
"ln-gf-mclk1",
"ln-gf-mclk3",
"ln-gf-mclk2",
"ln-psia1-mclk",
"ln-psia2-mclk",
"ln-spdif-clkout",
"ln-adat-mclk",
"ln-usb-clk-12m",
};
#define LN1_CLK(ID, NAME, REG) \
[LOCHNAGAR_##ID] = { \
.name = NAME, \
.cfg_reg = LOCHNAGAR1_##REG, \
.ena_mask = LOCHNAGAR1_##ID##_ENA_MASK, \
.src_reg = LOCHNAGAR1_##ID##_SEL, \
.src_mask = LOCHNAGAR1_SRC_MASK, \
}
#define LN2_CLK(ID, NAME) \
[LOCHNAGAR_##ID] = { \
.name = NAME, \
.cfg_reg = LOCHNAGAR2_##ID##_CTRL, \
.src_reg = LOCHNAGAR2_##ID##_CTRL, \
.ena_mask = LOCHNAGAR2_CLK_ENA_MASK, \
.src_mask = LOCHNAGAR2_CLK_SRC_MASK, \
}
static const struct lochnagar_clk lochnagar1_clks[LOCHNAGAR_NUM_CLOCKS] = {
LN1_CLK(CDC_MCLK1, "ln-cdc-mclk1", CDC_AIF_CTRL2),
LN1_CLK(CDC_MCLK2, "ln-cdc-mclk2", CDC_AIF_CTRL2),
LN1_CLK(DSP_CLKIN, "ln-dsp-clkin", DSP_AIF),
LN1_CLK(GF_CLKOUT1, "ln-gf-clkout1", GF_AIF1),
};
static const struct lochnagar_clk lochnagar2_clks[LOCHNAGAR_NUM_CLOCKS] = {
LN2_CLK(CDC_MCLK1, "ln-cdc-mclk1"),
LN2_CLK(CDC_MCLK2, "ln-cdc-mclk2"),
LN2_CLK(DSP_CLKIN, "ln-dsp-clkin"),
LN2_CLK(GF_CLKOUT1, "ln-gf-clkout1"),
LN2_CLK(GF_CLKOUT2, "ln-gf-clkout2"),
LN2_CLK(PSIA1_MCLK, "ln-psia1-mclk"),
LN2_CLK(PSIA2_MCLK, "ln-psia2-mclk"),
LN2_CLK(SPDIF_MCLK, "ln-spdif-mclk"),
LN2_CLK(ADAT_MCLK, "ln-adat-mclk"),
LN2_CLK(SOUNDCARD_MCLK, "ln-soundcard-mclk"),
};
static inline struct lochnagar_clk *lochnagar_hw_to_lclk(struct clk_hw *hw)
{
return container_of(hw, struct lochnagar_clk, hw);
}
static int lochnagar_clk_prepare(struct clk_hw *hw)
{
struct lochnagar_clk *lclk = lochnagar_hw_to_lclk(hw);
struct lochnagar_clk_priv *priv = lclk->priv;
struct regmap *regmap = priv->regmap;
int ret;
ret = regmap_update_bits(regmap, lclk->cfg_reg,
lclk->ena_mask, lclk->ena_mask);
if (ret < 0)
dev_dbg(priv->dev, "Failed to prepare %s: %d\n",
lclk->name, ret);
return ret;
}
static void lochnagar_clk_unprepare(struct clk_hw *hw)
{
struct lochnagar_clk *lclk = lochnagar_hw_to_lclk(hw);
struct lochnagar_clk_priv *priv = lclk->priv;
struct regmap *regmap = priv->regmap;
int ret;
ret = regmap_update_bits(regmap, lclk->cfg_reg, lclk->ena_mask, 0);
if (ret < 0)
dev_dbg(priv->dev, "Failed to unprepare %s: %d\n",
lclk->name, ret);
}
static int lochnagar_clk_set_parent(struct clk_hw *hw, u8 index)
{
struct lochnagar_clk *lclk = lochnagar_hw_to_lclk(hw);
struct lochnagar_clk_priv *priv = lclk->priv;
struct regmap *regmap = priv->regmap;
int ret;
ret = regmap_update_bits(regmap, lclk->src_reg, lclk->src_mask, index);
if (ret < 0)
dev_dbg(priv->dev, "Failed to reparent %s: %d\n",
lclk->name, ret);
return ret;
}
static u8 lochnagar_clk_get_parent(struct clk_hw *hw)
{
struct lochnagar_clk *lclk = lochnagar_hw_to_lclk(hw);
struct lochnagar_clk_priv *priv = lclk->priv;
struct regmap *regmap = priv->regmap;
unsigned int val;
int ret;
ret = regmap_read(regmap, lclk->src_reg, &val);
if (ret < 0) {
dev_dbg(priv->dev, "Failed to read parent of %s: %d\n",
lclk->name, ret);
return priv->nparents;
}
val &= lclk->src_mask;
return val;
}
static const struct clk_ops lochnagar_clk_ops = {
.prepare = lochnagar_clk_prepare,
.unprepare = lochnagar_clk_unprepare,
.set_parent = lochnagar_clk_set_parent,
.get_parent = lochnagar_clk_get_parent,
};
static int lochnagar_init_parents(struct lochnagar_clk_priv *priv)
{
struct device_node *np = priv->dev->of_node;
int i, j;
switch (priv->type) {
case LOCHNAGAR1:
memcpy(priv->lclks, lochnagar1_clks, sizeof(lochnagar1_clks));
priv->nparents = ARRAY_SIZE(lochnagar1_clk_parents);
priv->parents = devm_kmemdup(priv->dev, lochnagar1_clk_parents,
sizeof(lochnagar1_clk_parents),
GFP_KERNEL);
break;
case LOCHNAGAR2:
memcpy(priv->lclks, lochnagar2_clks, sizeof(lochnagar2_clks));
priv->nparents = ARRAY_SIZE(lochnagar2_clk_parents);
priv->parents = devm_kmemdup(priv->dev, lochnagar2_clk_parents,
sizeof(lochnagar2_clk_parents),
GFP_KERNEL);
break;
default:
dev_err(priv->dev, "Unknown Lochnagar type: %d\n", priv->type);
return -EINVAL;
}
if (!priv->parents)
return -ENOMEM;
for (i = 0; i < priv->nparents; i++) {
j = of_property_match_string(np, "clock-names",
priv->parents[i]);
if (j >= 0)
priv->parents[i] = of_clk_get_parent_name(np, j);
}
return 0;
}
static struct clk_hw *
lochnagar_of_clk_hw_get(struct of_phandle_args *clkspec, void *data)
{
struct lochnagar_clk_priv *priv = data;
unsigned int idx = clkspec->args[0];
if (idx >= ARRAY_SIZE(priv->lclks)) {
dev_err(priv->dev, "Invalid index %u\n", idx);
return ERR_PTR(-EINVAL);
}
return &priv->lclks[idx].hw;
}
static int lochnagar_init_clks(struct lochnagar_clk_priv *priv)
{
struct clk_init_data clk_init = {
.ops = &lochnagar_clk_ops,
.parent_names = priv->parents,
.num_parents = priv->nparents,
};
struct lochnagar_clk *lclk;
int ret, i;
for (i = 0; i < ARRAY_SIZE(priv->lclks); i++) {
lclk = &priv->lclks[i];
if (!lclk->name)
continue;
clk_init.name = lclk->name;
lclk->priv = priv;
lclk->hw.init = &clk_init;
ret = devm_clk_hw_register(priv->dev, &lclk->hw);
if (ret) {
dev_err(priv->dev, "Failed to register %s: %d\n",
lclk->name, ret);
return ret;
}
}
ret = devm_of_clk_add_hw_provider(priv->dev, lochnagar_of_clk_hw_get,
priv);
if (ret < 0)
dev_err(priv->dev, "Failed to register provider: %d\n", ret);
return ret;
}
static const struct of_device_id lochnagar_of_match[] = {
{ .compatible = "cirrus,lochnagar1-clk", .data = (void *)LOCHNAGAR1 },
{ .compatible = "cirrus,lochnagar2-clk", .data = (void *)LOCHNAGAR2 },
{}
};
MODULE_DEVICE_TABLE(of, lochnagar_of_match);
static int lochnagar_clk_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct lochnagar_clk_priv *priv;
const struct of_device_id *of_id;
int ret;
of_id = of_match_device(lochnagar_of_match, dev);
if (!of_id)
return -EINVAL;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->dev = dev;
priv->regmap = dev_get_regmap(dev->parent, NULL);
priv->type = (enum lochnagar_type)of_id->data;
ret = lochnagar_init_parents(priv);
if (ret)
return ret;
return lochnagar_init_clks(priv);
}
static struct platform_driver lochnagar_clk_driver = {
.driver = {
.name = "lochnagar-clk",
.of_match_table = lochnagar_of_match,
},
.probe = lochnagar_clk_probe,
};
module_platform_driver(lochnagar_clk_driver);
MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>");
MODULE_DESCRIPTION("Clock driver for Cirrus Logic Lochnagar Board");
MODULE_LICENSE("GPL v2");
This diff is collapsed.
......@@ -11,6 +11,22 @@
#include <linux/of.h>
#include <linux/slab.h>
static inline u32 clk_mult_readl(struct clk_multiplier *mult)
{
if (mult->flags & CLK_MULTIPLIER_BIG_ENDIAN)
return ioread32be(mult->reg);
return readl(mult->reg);
}
static inline void clk_mult_writel(struct clk_multiplier *mult, u32 val)
{
if (mult->flags & CLK_MULTIPLIER_BIG_ENDIAN)
iowrite32be(val, mult->reg);
else
writel(val, mult->reg);
}
static unsigned long __get_mult(struct clk_multiplier *mult,
unsigned long rate,
unsigned long parent_rate)
......@@ -27,7 +43,7 @@ static unsigned long clk_multiplier_recalc_rate(struct clk_hw *hw,
struct clk_multiplier *mult = to_clk_multiplier(hw);
unsigned long val;
val = clk_readl(mult->reg) >> mult->shift;
val = clk_mult_readl(mult) >> mult->shift;
val &= GENMASK(mult->width - 1, 0);
if (!val && mult->flags & CLK_MULTIPLIER_ZERO_BYPASS)
......@@ -118,10 +134,10 @@ static int clk_multiplier_set_rate(struct clk_hw *hw, unsigned long rate,
else
__acquire(mult->lock);
val = clk_readl(mult->reg);
val = clk_mult_readl(mult);
val &= ~GENMASK(mult->width + mult->shift - 1, mult->shift);
val |= factor << mult->shift;
clk_writel(val, mult->reg);
clk_mult_writel(mult, val);
if (mult->lock)
spin_unlock_irqrestore(mult->lock, flags);
......
......@@ -23,6 +23,22 @@
* parent - parent is adjustable through clk_set_parent
*/
static inline u32 clk_mux_readl(struct clk_mux *mux)
{
if (mux->flags & CLK_MUX_BIG_ENDIAN)
return ioread32be(mux->reg);
return readl(mux->reg);
}
static inline void clk_mux_writel(struct clk_mux *mux, u32 val)
{
if (mux->flags & CLK_MUX_BIG_ENDIAN)
iowrite32be(val, mux->reg);
else
writel(val, mux->reg);
}
int clk_mux_val_to_index(struct clk_hw *hw, u32 *table, unsigned int flags,
unsigned int val)
{
......@@ -73,7 +89,7 @@ static u8 clk_mux_get_parent(struct clk_hw *hw)
struct clk_mux *mux = to_clk_mux(hw);
u32 val;
val = clk_readl(mux->reg) >> mux->shift;
val = clk_mux_readl(mux) >> mux->shift;
val &= mux->mask;
return clk_mux_val_to_index(hw, mux->table, mux->flags, val);
......@@ -94,12 +110,12 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
if (mux->flags & CLK_MUX_HIWORD_MASK) {
reg = mux->mask << (mux->shift + 16);
} else {
reg = clk_readl(mux->reg);
reg = clk_mux_readl(mux);
reg &= ~(mux->mask << mux->shift);
}
val = val << mux->shift;
reg |= val;
clk_writel(reg, mux->reg);
clk_mux_writel(mux, reg);
if (mux->lock)
spin_unlock_irqrestore(mux->lock, flags);
......@@ -159,7 +175,7 @@ struct clk_hw *clk_hw_register_mux_table(struct device *dev, const char *name,
init.ops = &clk_mux_ro_ops;
else
init.ops = &clk_mux_ops;
init.flags = flags | CLK_IS_BASIC;
init.flags = flags;
init.parent_names = parent_names;
init.num_parents = num_parents;
......
......@@ -101,7 +101,7 @@ static int clk_pwm_probe(struct platform_device *pdev)
init.name = clk_name;
init.ops = &clk_pwm_ops;
init.flags = CLK_IS_BASIC;
init.flags = 0;
init.num_parents = 0;
clk_pwm->pwm = pwm;
......
......@@ -34,6 +34,7 @@
#define CGA_PLL4 4 /* only on clockgen-1.0, which lacks CGB */
#define CGB_PLL1 4
#define CGB_PLL2 5
#define MAX_PLL_DIV 16
struct clockgen_pll_div {
struct clk *clk;
......@@ -41,7 +42,7 @@ struct clockgen_pll_div {
};
struct clockgen_pll {
struct clockgen_pll_div div[8];
struct clockgen_pll_div div[MAX_PLL_DIV];
};
#define CLKSEL_VALID 1
......@@ -79,7 +80,7 @@ struct clockgen_chipinfo {
const struct clockgen_muxinfo *cmux_groups[2];
const struct clockgen_muxinfo *hwaccel[NUM_HWACCEL];
void (*init_periph)(struct clockgen *cg);
int cmux_to_group[NUM_CMUX]; /* -1 terminates if fewer than NUM_CMUX */
int cmux_to_group[NUM_CMUX + 1]; /* array should be -1 terminated */
u32 pll_mask; /* 1 << n bit set if PLL n is valid */
u32 flags; /* CG_xxx */
};
......@@ -245,6 +246,58 @@ static const struct clockgen_muxinfo clockgen2_cmux_cgb = {
},
};
static const struct clockgen_muxinfo ls1028a_hwa1 = {
{
{ CLKSEL_VALID, PLATFORM_PLL, PLL_DIV1 },
{ CLKSEL_VALID, CGA_PLL1, PLL_DIV1 },
{ CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
{ CLKSEL_VALID, CGA_PLL1, PLL_DIV3 },
{ CLKSEL_VALID, CGA_PLL1, PLL_DIV4 },
{},
{ CLKSEL_VALID, CGA_PLL2, PLL_DIV2 },
{ CLKSEL_VALID, CGA_PLL2, PLL_DIV3 },
},
};
static const struct clockgen_muxinfo ls1028a_hwa2 = {
{
{ CLKSEL_VALID, PLATFORM_PLL, PLL_DIV1 },
{ CLKSEL_VALID, CGA_PLL2, PLL_DIV1 },
{ CLKSEL_VALID, CGA_PLL2, PLL_DIV2 },
{ CLKSEL_VALID, CGA_PLL2, PLL_DIV3 },
{ CLKSEL_VALID, CGA_PLL2, PLL_DIV4 },
{},
{ CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
{ CLKSEL_VALID, CGA_PLL1, PLL_DIV3 },
},
};
static const struct clockgen_muxinfo ls1028a_hwa3 = {
{
{ CLKSEL_VALID, PLATFORM_PLL, PLL_DIV1 },
{ CLKSEL_VALID, CGA_PLL1, PLL_DIV1 },
{ CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
{ CLKSEL_VALID, CGA_PLL1, PLL_DIV3 },
{ CLKSEL_VALID, CGA_PLL1, PLL_DIV4 },
{},
{ CLKSEL_VALID, CGA_PLL2, PLL_DIV2 },
{ CLKSEL_VALID, CGA_PLL2, PLL_DIV3 },
},
};
static const struct clockgen_muxinfo ls1028a_hwa4 = {
{
{ CLKSEL_VALID, PLATFORM_PLL, PLL_DIV1 },
{ CLKSEL_VALID, CGA_PLL2, PLL_DIV1 },
{ CLKSEL_VALID, CGA_PLL2, PLL_DIV2 },
{ CLKSEL_VALID, CGA_PLL2, PLL_DIV3 },
{ CLKSEL_VALID, CGA_PLL2, PLL_DIV4 },
{},
{ CLKSEL_VALID, CGA_PLL1, PLL_DIV2 },
{ CLKSEL_VALID, CGA_PLL1, PLL_DIV3 },
},
};
static const struct clockgen_muxinfo ls1043a_hwa1 = {
{
{},
......@@ -507,6 +560,21 @@ static const struct clockgen_chipinfo chipinfo[] = {
},
.pll_mask = 0x03,
},
{
.compat = "fsl,ls1028a-clockgen",
.cmux_groups = {
&clockgen2_cmux_cga12
},
.hwaccel = {
&ls1028a_hwa1, &ls1028a_hwa2,
&ls1028a_hwa3, &ls1028a_hwa4
},
.cmux_to_group = {
0, 0, 0, 0, -1
},
.pll_mask = 0x07,
.flags = CG_VER3 | CG_LITTLE_ENDIAN,
},
{
.compat = "fsl,ls1043a-clockgen",
.init_periph = t2080_init_periph,
......@@ -601,7 +669,7 @@ static const struct clockgen_chipinfo chipinfo[] = {
&p4080_cmux_grp1, &p4080_cmux_grp2
},
.cmux_to_group = {
0, 0, 0, 0, 1, 1, 1, 1
0, 0, 0, 0, 1, 1, 1, 1, -1
},
.pll_mask = 0x1f,
},
......@@ -1128,7 +1196,7 @@ static void __init create_one_pll(struct clockgen *cg, int idx)
int ret;
/*
* For platform PLL, there are 8 divider clocks.
* For platform PLL, there are MAX_PLL_DIV divider clocks.
* For core PLL, there are 4 divider clocks at most.
*/
if (idx != PLATFORM_PLL && i >= 4)
......@@ -1423,6 +1491,7 @@ CLK_OF_DECLARE(qoriq_clockgen_b4420, "fsl,b4420-clockgen", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_b4860, "fsl,b4860-clockgen", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_ls1012a, "fsl,ls1012a-clockgen", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_ls1021a, "fsl,ls1021a-clockgen", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_ls1028a, "fsl,ls1028a-clockgen", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_ls1043a, "fsl,ls1043a-clockgen", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_ls1046a, "fsl,ls1046a-clockgen", clockgen_init);
CLK_OF_DECLARE(qoriq_clockgen_ls1088a, "fsl,ls1088a-clockgen", clockgen_init);
......
This diff is collapsed.
......@@ -1402,6 +1402,7 @@ enum {
G_CRYP1,
G_HASH1,
G_BKPSRAM,
G_DDRPERFM,
G_LAST
};
......@@ -1488,6 +1489,7 @@ static struct stm32_gate_cfg per_gate_cfg[G_LAST] = {
K_GATE(G_STGENRO, RCC_APB4ENSETR, 20, 0),
K_MGATE(G_USBPHY, RCC_APB4ENSETR, 16, 0),
K_GATE(G_IWDG2, RCC_APB4ENSETR, 15, 0),
K_GATE(G_DDRPERFM, RCC_APB4ENSETR, 8, 0),
K_MGATE(G_DSI, RCC_APB4ENSETR, 4, 0),
K_MGATE(G_LTDC, RCC_APB4ENSETR, 0, 0),
......@@ -1899,6 +1901,7 @@ static const struct clock_config stm32mp1_clock_cfg[] = {
PCLK(CRC1, "crc1", "ck_axi", 0, G_CRC1),
PCLK(USBH, "usbh", "ck_axi", 0, G_USBH),
PCLK(ETHSTP, "ethstp", "ck_axi", 0, G_ETHSTP),
PCLK(DDRPERFM, "ddrperfm", "pclk4", 0, G_DDRPERFM),
/* Kernel clocks */
KCLK(SDMMC1_K, "sdmmc1_k", sdmmc12_src, 0, G_SDMMC1, M_SDMMC12),
......
......@@ -262,7 +262,7 @@ static unsigned long xgene_clk_pmd_recalc_rate(struct clk_hw *hw,
else
__acquire(fd->lock);
val = clk_readl(fd->reg);
val = readl(fd->reg);
if (fd->lock)
spin_unlock_irqrestore(fd->lock, flags);
......@@ -333,10 +333,10 @@ static int xgene_clk_pmd_set_rate(struct clk_hw *hw, unsigned long rate,
else
__acquire(fd->lock);
val = clk_readl(fd->reg);
val = readl(fd->reg);
val &= ~fd->mask;
val |= (scale << fd->shift);
clk_writel(val, fd->reg);
writel(val, fd->reg);
if (fd->lock)
spin_unlock_irqrestore(fd->lock, flags);
......
This diff is collapsed.
......@@ -19,6 +19,8 @@ static inline struct clk_hw *of_clk_get_hw(struct device_node *np,
}
#endif
struct clk_hw *clk_find_hw(const char *dev_id, const char *con_id);
#ifdef CONFIG_COMMON_CLK
struct clk *clk_hw_create_clk(struct device *dev, struct clk_hw *hw,
const char *dev_id, const char *con_id);
......
......@@ -72,25 +72,26 @@ static struct clk_lookup *clk_find(const char *dev_id, const char *con_id)
return cl;
}
static struct clk *__clk_get_sys(struct device *dev, const char *dev_id,
const char *con_id)
struct clk_hw *clk_find_hw(const char *dev_id, const char *con_id)
{
struct clk_lookup *cl;
struct clk *clk = NULL;
struct clk_hw *hw = ERR_PTR(-ENOENT);
mutex_lock(&clocks_mutex);
cl = clk_find(dev_id, con_id);
if (!cl)
goto out;
clk = clk_hw_create_clk(dev, cl->clk_hw, dev_id, con_id);
if (IS_ERR(clk))
cl = NULL;
out:
if (cl)
hw = cl->clk_hw;
mutex_unlock(&clocks_mutex);
return cl ? clk : ERR_PTR(-ENOENT);
return hw;
}
static struct clk *__clk_get_sys(struct device *dev, const char *dev_id,
const char *con_id)
{
struct clk_hw *hw = clk_find_hw(dev_id, con_id);
return clk_hw_create_clk(dev, hw, dev_id, con_id);
}
struct clk *clk_get_sys(const char *dev_id, const char *con_id)
......
......@@ -160,10 +160,8 @@ static int __init da8xx_cfgchip_register_div4p5(struct device *dev,
struct da8xx_cfgchip_gate_clk *gate;
gate = da8xx_cfgchip_gate_clk_register(dev, &da8xx_div4p5ena_info, regmap);
if (IS_ERR(gate))
return PTR_ERR(gate);
return 0;
return PTR_ERR_OR_ZERO(gate);
}
static int __init
......
// SPDX-License-Identifier: GPL-2.0
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Clock driver for TI Davinci PSC controllers
*
......
// SPDX-License-Identifier: GPL-2.0
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Clock driver for TI Davinci PSC controllers
*
......
......@@ -163,8 +163,12 @@ static const struct hisi_gate_clock hi3660_crgctrl_gate_sep_clks[] = {
"clk_isp_snclk_mux", CLK_SET_RATE_PARENT, 0x50, 17, 0, },
{ HI3660_CLK_GATE_ISP_SNCLK2, "clk_gate_isp_snclk2",
"clk_isp_snclk_mux", CLK_SET_RATE_PARENT, 0x50, 18, 0, },
/*
* clk_gate_ufs_subsys is a system bus clock, mark it as critical
* clock and keep it on for system suspend and resume.
*/
{ HI3660_CLK_GATE_UFS_SUBSYS, "clk_gate_ufs_subsys", "clk_div_sysbus",
CLK_SET_RATE_PARENT, 0x50, 21, 0, },
CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, 0x50, 21, 0, },
{ HI3660_PCLK_GATE_DSI0, "pclk_gate_dsi0", "clk_div_cfgbus",
CLK_SET_RATE_PARENT, 0x50, 28, 0, },
{ HI3660_PCLK_GATE_DSI1, "pclk_gate_dsi1", "clk_div_cfgbus",
......
......@@ -75,10 +75,10 @@ static int hisi_clk_set_phase(struct clk_hw *hw, int degrees)
spin_lock_irqsave(phase->lock, flags);
val = clk_readl(phase->reg);
val = readl(phase->reg);
val &= ~phase->mask;
val |= regval << phase->shift;
clk_writel(val, phase->reg);
writel(val, phase->reg);
spin_unlock_irqrestore(phase->lock, flags);
......
......@@ -35,7 +35,7 @@ obj-$(CONFIG_SOC_IMX25) += clk-imx25.o
obj-$(CONFIG_SOC_IMX27) += clk-imx27.o
obj-$(CONFIG_SOC_IMX31) += clk-imx31.o
obj-$(CONFIG_SOC_IMX35) += clk-imx35.o
obj-$(CONFIG_SOC_IMX5) += clk-imx51-imx53.o
obj-$(CONFIG_SOC_IMX5) += clk-imx5.o
obj-$(CONFIG_SOC_IMX6Q) += clk-imx6q.o
obj-$(CONFIG_SOC_IMX6SL) += clk-imx6sl.o
obj-$(CONFIG_SOC_IMX6SLL) += clk-imx6sll.o
......
......@@ -29,7 +29,7 @@ static unsigned long clk_divider_gate_recalc_rate_ro(struct clk_hw *hw,
struct clk_divider *div = to_clk_divider(hw);
unsigned int val;
val = clk_readl(div->reg) >> div->shift;
val = readl(div->reg) >> div->shift;
val &= clk_div_mask(div->width);
if (!val)
return 0;
......@@ -51,7 +51,7 @@ static unsigned long clk_divider_gate_recalc_rate(struct clk_hw *hw,
if (!clk_hw_is_enabled(hw)) {
val = div_gate->cached_val;
} else {
val = clk_readl(div->reg) >> div->shift;
val = readl(div->reg) >> div->shift;
val &= clk_div_mask(div->width);
}
......@@ -87,10 +87,10 @@ static int clk_divider_gate_set_rate(struct clk_hw *hw, unsigned long rate,
spin_lock_irqsave(div->lock, flags);
if (clk_hw_is_enabled(hw)) {
val = clk_readl(div->reg);
val = readl(div->reg);
val &= ~(clk_div_mask(div->width) << div->shift);
val |= (u32)value << div->shift;
clk_writel(val, div->reg);
writel(val, div->reg);
} else {
div_gate->cached_val = value;
}
......@@ -114,9 +114,9 @@ static int clk_divider_enable(struct clk_hw *hw)
spin_lock_irqsave(div->lock, flags);
/* restore div val */
val = clk_readl(div->reg);
val = readl(div->reg);
val |= div_gate->cached_val << div->shift;
clk_writel(val, div->reg);
writel(val, div->reg);
spin_unlock_irqrestore(div->lock, flags);
......@@ -133,10 +133,10 @@ static void clk_divider_disable(struct clk_hw *hw)
spin_lock_irqsave(div->lock, flags);
/* store the current div val */
val = clk_readl(div->reg) >> div->shift;
val = readl(div->reg) >> div->shift;
val &= clk_div_mask(div->width);
div_gate->cached_val = val;
clk_writel(0, div->reg);
writel(0, div->reg);
spin_unlock_irqrestore(div->lock, flags);
}
......@@ -146,7 +146,7 @@ static int clk_divider_is_enabled(struct clk_hw *hw)
struct clk_divider *div = to_clk_divider(hw);
u32 val;
val = clk_readl(div->reg) >> div->shift;
val = readl(div->reg) >> div->shift;
val &= clk_div_mask(div->width);
return val ? 1 : 0;
......@@ -206,7 +206,7 @@ struct clk_hw *imx_clk_divider_gate(const char *name, const char *parent_name,
div_gate->divider.hw.init = &init;
div_gate->divider.flags = CLK_DIVIDER_ONE_BASED | clk_divider_flags;
/* cache gate status */
val = clk_readl(reg) >> shift;
val = readl(reg) >> shift;
val &= clk_div_mask(width);
div_gate->cached_val = val;
......
......@@ -164,10 +164,6 @@ static void __init mx5_clocks_common_init(void __iomem *ccm_base)
clk[IMX5_CLK_CKIH1] = imx_obtain_fixed_clock("ckih1", 0);
clk[IMX5_CLK_CKIH2] = imx_obtain_fixed_clock("ckih2", 0);
clk[IMX5_CLK_PERIPH_APM] = imx_clk_mux("periph_apm", MXC_CCM_CBCMR, 12, 2,
periph_apm_sel, ARRAY_SIZE(periph_apm_sel));
clk[IMX5_CLK_MAIN_BUS] = imx_clk_mux("main_bus", MXC_CCM_CBCDR, 25, 1,
main_bus_sel, ARRAY_SIZE(main_bus_sel));
clk[IMX5_CLK_PER_LP_APM] = imx_clk_mux("per_lp_apm", MXC_CCM_CBCMR, 1, 1,
per_lp_apm_sel, ARRAY_SIZE(per_lp_apm_sel));
clk[IMX5_CLK_PER_PRED1] = imx_clk_divider("per_pred1", "per_lp_apm", MXC_CCM_CBCDR, 6, 2);
......@@ -191,16 +187,10 @@ static void __init mx5_clocks_common_init(void __iomem *ccm_base)
clk[IMX5_CLK_UART_PRED] = imx_clk_divider("uart_pred", "uart_sel", MXC_CCM_CSCDR1, 3, 3);
clk[IMX5_CLK_UART_ROOT] = imx_clk_divider("uart_root", "uart_pred", MXC_CCM_CSCDR1, 0, 3);
clk[IMX5_CLK_ESDHC_A_SEL] = imx_clk_mux("esdhc_a_sel", MXC_CCM_CSCMR1, 20, 2,
standard_pll_sel, ARRAY_SIZE(standard_pll_sel));
clk[IMX5_CLK_ESDHC_B_SEL] = imx_clk_mux("esdhc_b_sel", MXC_CCM_CSCMR1, 16, 2,
standard_pll_sel, ARRAY_SIZE(standard_pll_sel));
clk[IMX5_CLK_ESDHC_A_PRED] = imx_clk_divider("esdhc_a_pred", "esdhc_a_sel", MXC_CCM_CSCDR1, 16, 3);
clk[IMX5_CLK_ESDHC_A_PODF] = imx_clk_divider("esdhc_a_podf", "esdhc_a_pred", MXC_CCM_CSCDR1, 11, 3);
clk[IMX5_CLK_ESDHC_B_PRED] = imx_clk_divider("esdhc_b_pred", "esdhc_b_sel", MXC_CCM_CSCDR1, 22, 3);
clk[IMX5_CLK_ESDHC_B_PODF] = imx_clk_divider("esdhc_b_podf", "esdhc_b_pred", MXC_CCM_CSCDR1, 19, 3);
clk[IMX5_CLK_ESDHC_C_SEL] = imx_clk_mux("esdhc_c_sel", MXC_CCM_CSCMR1, 19, 1, esdhc_c_sel, ARRAY_SIZE(esdhc_c_sel));
clk[IMX5_CLK_ESDHC_D_SEL] = imx_clk_mux("esdhc_d_sel", MXC_CCM_CSCMR1, 18, 1, esdhc_d_sel, ARRAY_SIZE(esdhc_d_sel));
clk[IMX5_CLK_EMI_SEL] = imx_clk_mux("emi_sel", MXC_CCM_CBCDR, 26, 1,
emi_slow_sel, ARRAY_SIZE(emi_slow_sel));
......@@ -311,10 +301,6 @@ static void __init mx5_clocks_common_init(void __iomem *ccm_base)
clk_register_clkdev(clk[IMX5_CLK_CPU_PODF], NULL, "cpu0");
clk_register_clkdev(clk[IMX5_CLK_GPC_DVFS], "gpc_dvfs", NULL);
/* Set SDHC parents to be PLL2 */
clk_set_parent(clk[IMX5_CLK_ESDHC_A_SEL], clk[IMX5_CLK_PLL2_SW]);
clk_set_parent(clk[IMX5_CLK_ESDHC_B_SEL], clk[IMX5_CLK_PLL2_SW]);
/* move usb phy clk to 24MHz */
clk_set_parent(clk[IMX5_CLK_USB_PHY_SEL], clk[IMX5_CLK_OSC]);
}
......@@ -342,8 +328,21 @@ static void __init mx50_clocks_init(struct device_node *np)
mx5_clocks_common_init(ccm_base);
/*
* This clock is called periph_clk in the i.MX50 Reference Manual, but
* it comes closest in scope to the main_bus_clk of i.MX51 and i.MX53
*/
clk[IMX5_CLK_MAIN_BUS] = imx_clk_mux("main_bus", MXC_CCM_CBCDR, 25, 2,
standard_pll_sel, ARRAY_SIZE(standard_pll_sel));
clk[IMX5_CLK_LP_APM] = imx_clk_mux("lp_apm", MXC_CCM_CCSR, 10, 1,
lp_apm_sel, ARRAY_SIZE(lp_apm_sel));
clk[IMX5_CLK_ESDHC_A_SEL] = imx_clk_mux("esdhc_a_sel", MXC_CCM_CSCMR1, 21, 2,
standard_pll_sel, ARRAY_SIZE(standard_pll_sel));
clk[IMX5_CLK_ESDHC_B_SEL] = imx_clk_mux("esdhc_b_sel", MXC_CCM_CSCMR1, 16, 2,
standard_pll_sel, ARRAY_SIZE(standard_pll_sel));
clk[IMX5_CLK_ESDHC_C_SEL] = imx_clk_mux("esdhc_c_sel", MXC_CCM_CSCMR1, 20, 1, esdhc_c_sel, ARRAY_SIZE(esdhc_c_sel));
clk[IMX5_CLK_ESDHC_D_SEL] = imx_clk_mux("esdhc_d_sel", MXC_CCM_CSCMR1, 19, 1, esdhc_d_sel, ARRAY_SIZE(esdhc_d_sel));
clk[IMX5_CLK_ESDHC1_PER_GATE] = imx_clk_gate2("esdhc1_per_gate", "esdhc_a_podf", MXC_CCM_CCGR3, 2);
clk[IMX5_CLK_ESDHC2_PER_GATE] = imx_clk_gate2("esdhc2_per_gate", "esdhc_c_sel", MXC_CCM_CCGR3, 6);
clk[IMX5_CLK_ESDHC3_PER_GATE] = imx_clk_gate2("esdhc3_per_gate", "esdhc_b_podf", MXC_CCM_CCGR3, 10);
......@@ -372,6 +371,10 @@ static void __init mx50_clocks_init(struct device_node *np)
clk_data.clk_num = ARRAY_SIZE(clk);
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
/* Set SDHC parents to be PLL2 */
clk_set_parent(clk[IMX5_CLK_ESDHC_A_SEL], clk[IMX5_CLK_PLL2_SW]);
clk_set_parent(clk[IMX5_CLK_ESDHC_B_SEL], clk[IMX5_CLK_PLL2_SW]);
/* set SDHC root clock to 200MHZ*/
clk_set_rate(clk[IMX5_CLK_ESDHC_A_PODF], 200000000);
clk_set_rate(clk[IMX5_CLK_ESDHC_B_PODF], 200000000);
......@@ -410,6 +413,10 @@ static void __init mx51_clocks_init(struct device_node *np)
mx5_clocks_common_init(ccm_base);
clk[IMX5_CLK_PERIPH_APM] = imx_clk_mux("periph_apm", MXC_CCM_CBCMR, 12, 2,
periph_apm_sel, ARRAY_SIZE(periph_apm_sel));
clk[IMX5_CLK_MAIN_BUS] = imx_clk_mux("main_bus", MXC_CCM_CBCDR, 25, 1,
main_bus_sel, ARRAY_SIZE(main_bus_sel));
clk[IMX5_CLK_LP_APM] = imx_clk_mux("lp_apm", MXC_CCM_CCSR, 9, 1,
lp_apm_sel, ARRAY_SIZE(lp_apm_sel));
clk[IMX5_CLK_IPU_DI0_SEL] = imx_clk_mux_flags("ipu_di0_sel", MXC_CCM_CSCMR2, 26, 3,
......@@ -422,6 +429,12 @@ static void __init mx51_clocks_init(struct device_node *np)
mx51_tve_sel, ARRAY_SIZE(mx51_tve_sel));
clk[IMX5_CLK_TVE_GATE] = imx_clk_gate2("tve_gate", "tve_sel", MXC_CCM_CCGR2, 30);
clk[IMX5_CLK_TVE_PRED] = imx_clk_divider("tve_pred", "pll3_sw", MXC_CCM_CDCDR, 28, 3);
clk[IMX5_CLK_ESDHC_A_SEL] = imx_clk_mux("esdhc_a_sel", MXC_CCM_CSCMR1, 20, 2,
standard_pll_sel, ARRAY_SIZE(standard_pll_sel));
clk[IMX5_CLK_ESDHC_B_SEL] = imx_clk_mux("esdhc_b_sel", MXC_CCM_CSCMR1, 16, 2,
standard_pll_sel, ARRAY_SIZE(standard_pll_sel));
clk[IMX5_CLK_ESDHC_C_SEL] = imx_clk_mux("esdhc_c_sel", MXC_CCM_CSCMR1, 19, 1, esdhc_c_sel, ARRAY_SIZE(esdhc_c_sel));
clk[IMX5_CLK_ESDHC_D_SEL] = imx_clk_mux("esdhc_d_sel", MXC_CCM_CSCMR1, 18, 1, esdhc_d_sel, ARRAY_SIZE(esdhc_d_sel));
clk[IMX5_CLK_ESDHC1_PER_GATE] = imx_clk_gate2("esdhc1_per_gate", "esdhc_a_podf", MXC_CCM_CCGR3, 2);
clk[IMX5_CLK_ESDHC2_PER_GATE] = imx_clk_gate2("esdhc2_per_gate", "esdhc_b_podf", MXC_CCM_CCGR3, 6);
clk[IMX5_CLK_ESDHC3_PER_GATE] = imx_clk_gate2("esdhc3_per_gate", "esdhc_c_sel", MXC_CCM_CCGR3, 10);
......@@ -452,6 +465,10 @@ static void __init mx51_clocks_init(struct device_node *np)
/* set the usboh3 parent to pll2_sw */
clk_set_parent(clk[IMX5_CLK_USBOH3_SEL], clk[IMX5_CLK_PLL2_SW]);
/* Set SDHC parents to be PLL2 */
clk_set_parent(clk[IMX5_CLK_ESDHC_A_SEL], clk[IMX5_CLK_PLL2_SW]);
clk_set_parent(clk[IMX5_CLK_ESDHC_B_SEL], clk[IMX5_CLK_PLL2_SW]);
/* set SDHC root clock to 166.25MHZ*/
clk_set_rate(clk[IMX5_CLK_ESDHC_A_PODF], 166250000);
clk_set_rate(clk[IMX5_CLK_ESDHC_B_PODF], 166250000);
......@@ -506,6 +523,10 @@ static void __init mx53_clocks_init(struct device_node *np)
mx5_clocks_common_init(ccm_base);
clk[IMX5_CLK_PERIPH_APM] = imx_clk_mux("periph_apm", MXC_CCM_CBCMR, 12, 2,
periph_apm_sel, ARRAY_SIZE(periph_apm_sel));
clk[IMX5_CLK_MAIN_BUS] = imx_clk_mux("main_bus", MXC_CCM_CBCDR, 25, 1,
main_bus_sel, ARRAY_SIZE(main_bus_sel));
clk[IMX5_CLK_LP_APM] = imx_clk_mux("lp_apm", MXC_CCM_CCSR, 10, 1,
lp_apm_sel, ARRAY_SIZE(lp_apm_sel));
clk[IMX5_CLK_LDB_DI1_DIV_3_5] = imx_clk_fixed_factor("ldb_di1_div_3_5", "ldb_di1_sel", 2, 7);
......@@ -527,6 +548,12 @@ static void __init mx53_clocks_init(struct device_node *np)
mx53_tve_ext_sel, ARRAY_SIZE(mx53_tve_ext_sel), CLK_SET_RATE_PARENT);
clk[IMX5_CLK_TVE_GATE] = imx_clk_gate2("tve_gate", "tve_pred", MXC_CCM_CCGR2, 30);
clk[IMX5_CLK_TVE_PRED] = imx_clk_divider("tve_pred", "tve_ext_sel", MXC_CCM_CDCDR, 28, 3);
clk[IMX5_CLK_ESDHC_A_SEL] = imx_clk_mux("esdhc_a_sel", MXC_CCM_CSCMR1, 20, 2,
standard_pll_sel, ARRAY_SIZE(standard_pll_sel));
clk[IMX5_CLK_ESDHC_B_SEL] = imx_clk_mux("esdhc_b_sel", MXC_CCM_CSCMR1, 16, 2,
standard_pll_sel, ARRAY_SIZE(standard_pll_sel));
clk[IMX5_CLK_ESDHC_C_SEL] = imx_clk_mux("esdhc_c_sel", MXC_CCM_CSCMR1, 19, 1, esdhc_c_sel, ARRAY_SIZE(esdhc_c_sel));
clk[IMX5_CLK_ESDHC_D_SEL] = imx_clk_mux("esdhc_d_sel", MXC_CCM_CSCMR1, 18, 1, esdhc_d_sel, ARRAY_SIZE(esdhc_d_sel));
clk[IMX5_CLK_ESDHC1_PER_GATE] = imx_clk_gate2("esdhc1_per_gate", "esdhc_a_podf", MXC_CCM_CCGR3, 2);
clk[IMX5_CLK_ESDHC2_PER_GATE] = imx_clk_gate2("esdhc2_per_gate", "esdhc_c_sel", MXC_CCM_CCGR3, 6);
clk[IMX5_CLK_ESDHC3_PER_GATE] = imx_clk_gate2("esdhc3_per_gate", "esdhc_b_podf", MXC_CCM_CCGR3, 10);
......@@ -589,6 +616,10 @@ static void __init mx53_clocks_init(struct device_node *np)
clk_data.clk_num = ARRAY_SIZE(clk);
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
/* Set SDHC parents to be PLL2 */
clk_set_parent(clk[IMX5_CLK_ESDHC_A_SEL], clk[IMX5_CLK_PLL2_SW]);
clk_set_parent(clk[IMX5_CLK_ESDHC_B_SEL], clk[IMX5_CLK_PLL2_SW]);
/* set SDHC root clock to 200MHZ*/
clk_set_rate(clk[IMX5_CLK_ESDHC_A_PODF], 200000000);
clk_set_rate(clk[IMX5_CLK_ESDHC_B_PODF], 200000000);
......
......@@ -76,6 +76,20 @@ static u32 share_count_ssi1;
static u32 share_count_ssi2;
static u32 share_count_ssi3;
static struct clk ** const uart_clks[] __initconst = {
&clks[IMX6SLL_CLK_UART1_IPG],
&clks[IMX6SLL_CLK_UART1_SERIAL],
&clks[IMX6SLL_CLK_UART2_IPG],
&clks[IMX6SLL_CLK_UART2_SERIAL],
&clks[IMX6SLL_CLK_UART3_IPG],
&clks[IMX6SLL_CLK_UART3_SERIAL],
&clks[IMX6SLL_CLK_UART4_IPG],
&clks[IMX6SLL_CLK_UART4_SERIAL],
&clks[IMX6SLL_CLK_UART5_IPG],
&clks[IMX6SLL_CLK_UART5_SERIAL],
NULL
};
static void __init imx6sll_clocks_init(struct device_node *ccm_node)
{
struct device_node *np;
......@@ -268,7 +282,7 @@ static void __init imx6sll_clocks_init(struct device_node *ccm_node)
clks[IMX6SLL_CLK_GPT_BUS] = imx_clk_gate2("gpt1_bus", "perclk", base + 0x6c, 20);
clks[IMX6SLL_CLK_GPT_SERIAL] = imx_clk_gate2("gpt1_serial", "perclk", base + 0x6c, 22);
clks[IMX6SLL_CLK_UART4_IPG] = imx_clk_gate2("uart4_ipg", "ipg", base + 0x6c, 24);
clks[IMX6SLL_CLK_UART4_SERIAL] = imx_clk_gate2("uart4_serail", "uart_podf", base + 0x6c, 24);
clks[IMX6SLL_CLK_UART4_SERIAL] = imx_clk_gate2("uart4_serial", "uart_podf", base + 0x6c, 24);
clks[IMX6SLL_CLK_GPIO1] = imx_clk_gate2("gpio1", "ipg", base + 0x6c, 26);
clks[IMX6SLL_CLK_GPIO5] = imx_clk_gate2("gpio5", "ipg", base + 0x6c, 30);
......@@ -334,6 +348,8 @@ static void __init imx6sll_clocks_init(struct device_node *ccm_node)
clk_data.clk_num = ARRAY_SIZE(clks);
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
imx_register_uart_clocks(uart_clks);
/* Lower the AHB clock rate before changing the clock source. */
clk_set_rate(clks[IMX6SLL_CLK_AHB], 99000000);
......
......@@ -417,8 +417,8 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
clks[IMX7D_PLL_DRAM_MAIN] = imx_clk_pllv3(IMX_PLLV3_DDR_IMX7, "pll_dram_main", "osc", base + 0x70, 0x7f);
clks[IMX7D_PLL_SYS_MAIN] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll_sys_main", "osc", base + 0xb0, 0x1);
clks[IMX7D_PLL_ENET_MAIN] = imx_clk_pllv3(IMX_PLLV3_ENET_IMX7, "pll_enet_main", "osc", base + 0xe0, 0x0);
clks[IMX7D_PLL_AUDIO_MAIN] = imx_clk_pllv3(IMX_PLLV3_AV, "pll_audio_main", "osc", base + 0xf0, 0x7f);
clks[IMX7D_PLL_VIDEO_MAIN] = imx_clk_pllv3(IMX_PLLV3_AV, "pll_video_main", "osc", base + 0x130, 0x7f);
clks[IMX7D_PLL_AUDIO_MAIN] = imx_clk_pllv3(IMX_PLLV3_AV_IMX7, "pll_audio_main", "osc", base + 0xf0, 0x7f);
clks[IMX7D_PLL_VIDEO_MAIN] = imx_clk_pllv3(IMX_PLLV3_AV_IMX7, "pll_video_main", "osc", base + 0x130, 0x7f);
clks[IMX7D_PLL_ARM_MAIN_BYPASS] = imx_clk_mux_flags("pll_arm_main_bypass", base + 0x60, 16, 1, pll_arm_bypass_sel, ARRAY_SIZE(pll_arm_bypass_sel), CLK_SET_RATE_PARENT);
clks[IMX7D_PLL_DRAM_MAIN_BYPASS] = imx_clk_mux_flags("pll_dram_main_bypass", base + 0x70, 16, 1, pll_dram_bypass_sel, ARRAY_SIZE(pll_dram_bypass_sel), CLK_SET_RATE_PARENT);
......
......@@ -151,7 +151,6 @@ static void __init imx7ulp_clk_pcc2_init(struct device_node *np)
clks[IMX7ULP_CLK_DMA1] = imx_clk_hw_gate("dma1", "nic1_clk", base + 0x20, 30);
clks[IMX7ULP_CLK_RGPIO2P1] = imx_clk_hw_gate("rgpio2p1", "nic1_bus_clk", base + 0x3c, 30);
clks[IMX7ULP_CLK_DMA_MUX1] = imx_clk_hw_gate("dma_mux1", "nic1_bus_clk", base + 0x84, 30);
clks[IMX7ULP_CLK_SNVS] = imx_clk_hw_gate("snvs", "nic1_bus_clk", base + 0x8c, 30);
clks[IMX7ULP_CLK_CAAM] = imx_clk_hw_gate("caam", "nic1_clk", base + 0x90, 30);
clks[IMX7ULP_CLK_LPTPM4] = imx7ulp_clk_composite("lptpm4", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x94);
clks[IMX7ULP_CLK_LPTPM5] = imx7ulp_clk_composite("lptpm5", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x98);
......
......@@ -458,6 +458,7 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
clks[IMX8MQ_CLK_DSI_DBI] = imx8m_clk_composite("dsi_dbi", imx8mq_dsi_dbi_sels, base + 0xbc00);
clks[IMX8MQ_CLK_DSI_ESC] = imx8m_clk_composite("dsi_esc", imx8mq_dsi_esc_sels, base + 0xbc80);
clks[IMX8MQ_CLK_DSI_AHB] = imx8m_clk_composite("dsi_ahb", imx8mq_dsi_ahb_sels, base + 0x9200);
clks[IMX8MQ_CLK_DSI_IPG_DIV] = imx_clk_divider2("dsi_ipg_div", "dsi_ahb", base + 0x9280, 0, 6);
clks[IMX8MQ_CLK_CSI1_CORE] = imx8m_clk_composite("csi1_core", imx8mq_csi1_core_sels, base + 0xbd00);
clks[IMX8MQ_CLK_CSI1_PHY_REF] = imx8m_clk_composite("csi1_phy_ref", imx8mq_csi1_phy_sels, base + 0xbd80);
clks[IMX8MQ_CLK_CSI1_ESC] = imx8m_clk_composite("csi1_esc", imx8mq_csi1_esc_sels, base + 0xbe00);
......
......@@ -43,7 +43,7 @@ static int clk_pfdv2_wait(struct clk_pfdv2 *pfd)
{
u32 val;
return readl_poll_timeout(pfd->reg, val, val & pfd->vld_bit,
return readl_poll_timeout(pfd->reg, val, val & (1 << pfd->vld_bit),
0, LOCK_TIMEOUT_US);
}
......@@ -55,7 +55,7 @@ static int clk_pfdv2_enable(struct clk_hw *hw)
spin_lock_irqsave(&pfd_lock, flags);
val = readl_relaxed(pfd->reg);
val &= ~pfd->gate_bit;
val &= ~(1 << pfd->gate_bit);
writel_relaxed(val, pfd->reg);
spin_unlock_irqrestore(&pfd_lock, flags);
......@@ -70,7 +70,7 @@ static void clk_pfdv2_disable(struct clk_hw *hw)
spin_lock_irqsave(&pfd_lock, flags);
val = readl_relaxed(pfd->reg);
val |= pfd->gate_bit;
val |= (1 << pfd->gate_bit);
writel_relaxed(val, pfd->reg);
spin_unlock_irqrestore(&pfd_lock, flags);
}
......@@ -123,7 +123,7 @@ static int clk_pfdv2_is_enabled(struct clk_hw *hw)
{
struct clk_pfdv2 *pfd = to_clk_pfdv2(hw);
if (readl_relaxed(pfd->reg) & pfd->gate_bit)
if (readl_relaxed(pfd->reg) & (1 << pfd->gate_bit))
return 0;
return 1;
......@@ -180,7 +180,7 @@ struct clk_hw *imx_clk_pfdv2(const char *name, const char *parent_name,
return ERR_PTR(-ENOMEM);
pfd->reg = reg;
pfd->gate_bit = 1 << ((idx + 1) * 8 - 1);
pfd->gate_bit = (idx + 1) * 8 - 1;
pfd->vld_bit = pfd->gate_bit - 1;
pfd->frac_off = idx * 8;
......
......@@ -74,10 +74,9 @@ 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;
u32 mdiv, pdiv, sdiv, 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;
......@@ -93,11 +92,10 @@ 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;
u32 mdiv, pdiv, sdiv, 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;
......
This diff is collapsed.
This diff is collapsed.
......@@ -348,7 +348,7 @@ static unsigned long clk_sccg_pll_recalc_rate(struct clk_hw *hw,
temp64 = parent_rate;
val = clk_readl(pll->base + PLL_CFG0);
val = readl(pll->base + PLL_CFG0);
if (val & SSCG_PLL_BYPASS2_MASK) {
temp64 = parent_rate;
} else if (val & SSCG_PLL_BYPASS1_MASK) {
......@@ -371,10 +371,10 @@ static int clk_sccg_pll_set_rate(struct clk_hw *hw, unsigned long rate,
u32 val;
/* set bypass here too since the parent might be the same */
val = clk_readl(pll->base + PLL_CFG0);
val = readl(pll->base + PLL_CFG0);
val &= ~SSCG_PLL_BYPASS_MASK;
val |= FIELD_PREP(SSCG_PLL_BYPASS_MASK, setup->bypass);
clk_writel(val, pll->base + PLL_CFG0);
writel(val, pll->base + PLL_CFG0);
val = readl_relaxed(pll->base + PLL_CFG2);
val &= ~(PLL_DIVF1_MASK | PLL_DIVF2_MASK);
......@@ -395,7 +395,7 @@ static u8 clk_sccg_pll_get_parent(struct clk_hw *hw)
u32 val;
u8 ret = pll->parent;
val = clk_readl(pll->base + PLL_CFG0);
val = readl(pll->base + PLL_CFG0);
if (val & SSCG_PLL_BYPASS2_MASK)
ret = pll->bypass2;
else if (val & SSCG_PLL_BYPASS1_MASK)
......@@ -408,10 +408,10 @@ static int clk_sccg_pll_set_parent(struct clk_hw *hw, u8 index)
struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
u32 val;
val = clk_readl(pll->base + PLL_CFG0);
val = readl(pll->base + PLL_CFG0);
val &= ~SSCG_PLL_BYPASS_MASK;
val |= FIELD_PREP(SSCG_PLL_BYPASS_MASK, pll->setup.bypass);
clk_writel(val, pll->base + PLL_CFG0);
writel(val, pll->base + PLL_CFG0);
return clk_sccg_pll_wait_lock(pll);
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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