mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-04-13 09:59:31 +00:00
Merge branches 'clk-mobileye', 'clk-twl', 'clk-nuvoton', 'clk-renesas' and 'clk-bindings' into clk-next
- Mobileye EyeQ5, EyeQ6L and EyeQ6H clk driver - TWL6030 clk driver - Nuvoton Arbel BMC NPCM8XX SoC clks - Convert more clk bindings to YAML * clk-mobileye: clk: eyeq: add EyeQ6H west fixed factor clocks clk: eyeq: add EyeQ6H central fixed factor clocks clk: eyeq: add EyeQ5 fixed factor clocks clk: eyeq: add fixed factor clocks infrastructure clk: eyeq: require clock index with phandle in all cases clk: fixed-factor: add clk_hw_register_fixed_factor_index() function dt-bindings: clock: eyeq: add more Mobileye EyeQ5/EyeQ6H clocks dt-bindings: soc: mobileye: set `#clock-cells = <1>` for all compatibles clk: eyeq: add driver clk: divider: Introduce CLK_DIVIDER_EVEN_INTEGERS flag dt-bindings: clock: add Mobileye EyeQ6L/EyeQ6H clock indexes Revert "dt-bindings: clock: mobileye,eyeq5-clk: add bindings" * clk-twl: clk: twl: add TWL6030 support clk: twl: remove is_prepared * clk-nuvoton: clk: npcm8xx: add clock controller reset: npcm: register npcm8xx clock auxiliary bus device dt-bindings: reset: npcm: add clock properties * clk-renesas: clk: renesas: vbattb: Add VBATTB clock driver clk: Add devm_clk_hw_register_gate_parent_hw() clk: renesas: rzg2l: Fix FOUTPOSTDIV clk dt-bindings: clock: renesas,r9a08g045-vbattb: Document VBATTB clk: renesas: r9a08g045: Add power domain for RTC clk: renesas: r9a08g045: Mark the watchdog and always-on PM domains as IRQ safe clk: renesas: rzg2l-cpg: Use GENPD_FLAG_* flags instead of local ones clk: renesas: rzg2l-cpg: Move PM domain power on in rzg2l_cpg_pd_setup() dt-bindings: clock: r9a08g045-cpg: Add power domain ID for RTC clk: renesas: r8a779h0: Drop CLK_PLL2_DIV2 to clarify ZCn clocks clk: renesas: r9a09g057: Add clock and reset entries for ICU clk: renesas: r9a09g057: Add CA55 core clocks clk: renesas: Remove duplicate and trailing empty lines * clk-bindings: dt-bindings: clock: actions,owl-cmu: convert to YAML dt-bindings: clock: ti: Convert mux.txt to json-schema dt-bindings: clock: ti: Convert divider.txt to json-schema dt-bindings: clock: ti: Convert interface.txt to json-schema dt-bindings: clock: convert rockchip,rk3328-cru.txt to YAML
This commit is contained in:
commit
b2f8240153
46 changed files with 2491 additions and 561 deletions
|
@ -1,52 +0,0 @@
|
|||
* Actions Semi Owl Clock Management Unit (CMU)
|
||||
|
||||
The Actions Semi Owl Clock Management Unit generates and supplies clock
|
||||
to various controllers within the SoC. The clock binding described here is
|
||||
applicable to S900, S700 and S500 SoC's.
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: should be one of the following,
|
||||
"actions,s900-cmu"
|
||||
"actions,s700-cmu"
|
||||
"actions,s500-cmu"
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- clocks: Reference to the parent clocks ("hosc", "losc")
|
||||
- #clock-cells: should be 1.
|
||||
- #reset-cells: should be 1.
|
||||
|
||||
Each clock is assigned an identifier, and client nodes can use this identifier
|
||||
to specify the clock which they consume.
|
||||
|
||||
All available clocks are defined as preprocessor macros in corresponding
|
||||
dt-bindings/clock/actions,s900-cmu.h or actions,s700-cmu.h or
|
||||
actions,s500-cmu.h header and can be used in device tree sources.
|
||||
|
||||
External clocks:
|
||||
|
||||
The hosc clock used as input for the plls is generated outside the SoC. It is
|
||||
expected that it is defined using standard clock bindings as "hosc".
|
||||
|
||||
Actions Semi S900 CMU also requires one more clock:
|
||||
- "losc" - internal low frequency oscillator
|
||||
|
||||
Example: Clock Management Unit node:
|
||||
|
||||
cmu: clock-controller@e0160000 {
|
||||
compatible = "actions,s900-cmu";
|
||||
reg = <0x0 0xe0160000 0x0 0x1000>;
|
||||
clocks = <&hosc>, <&losc>;
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
|
||||
Example: UART controller node that consumes clock generated by the clock
|
||||
management unit:
|
||||
|
||||
uart: serial@e012a000 {
|
||||
compatible = "actions,s900-uart", "actions,owl-uart";
|
||||
reg = <0x0 0xe012a000 0x0 0x2000>;
|
||||
interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cmu CLK_UART5>;
|
||||
};
|
60
Documentation/devicetree/bindings/clock/actions,owl-cmu.yaml
Normal file
60
Documentation/devicetree/bindings/clock/actions,owl-cmu.yaml
Normal file
|
@ -0,0 +1,60 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/actions,owl-cmu.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Actions Semi Owl Clock Management Unit (CMU)
|
||||
|
||||
maintainers:
|
||||
- Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
|
||||
description: |
|
||||
The Actions Semi Owl Clock Management Unit generates and supplies clock
|
||||
to various controllers within the SoC.
|
||||
|
||||
See also:
|
||||
include/dt-bindings/clock/actions,s500-cmu.h
|
||||
include/dt-bindings/clock/actions,s700-cmu.h
|
||||
include/dt-bindings/clock/actions,s900-cmu.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- actions,s500-cmu
|
||||
- actions,s700-cmu
|
||||
- actions,s900-cmu
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Host oscillator source
|
||||
- description: Internal low frequency oscillator source
|
||||
|
||||
"#clock-cells":
|
||||
const: 1
|
||||
|
||||
"#reset-cells":
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- "#clock-cells"
|
||||
- "#reset-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
clock-controller@e0160000 {
|
||||
compatible = "actions,s900-cmu";
|
||||
reg = <0xe0160000 0x1000>;
|
||||
clocks = <&hosc>, <&losc>;
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
...
|
|
@ -1,51 +0,0 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/mobileye,eyeq5-clk.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Mobileye EyeQ5 clock controller
|
||||
|
||||
description:
|
||||
The EyeQ5 clock controller handles 10 read-only PLLs derived from the main
|
||||
crystal clock. It also exposes one divider clock, a child of one of the PLLs.
|
||||
Its registers live in a shared region called OLB.
|
||||
|
||||
maintainers:
|
||||
- Grégory Clement <gregory.clement@bootlin.com>
|
||||
- Théo Lebrun <theo.lebrun@bootlin.com>
|
||||
- Vladimir Kondratiev <vladimir.kondratiev@mobileye.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: mobileye,eyeq5-clk
|
||||
|
||||
reg:
|
||||
maxItems: 2
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: plls
|
||||
- const: ospi
|
||||
|
||||
"#clock-cells":
|
||||
const: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
description:
|
||||
Input parent clock to all PLLs. Expected to be the main crystal.
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: ref
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reg-names
|
||||
- "#clock-cells"
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
additionalProperties: false
|
|
@ -0,0 +1,84 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/renesas,r9a08g045-vbattb.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Renesas Battery Backup Function (VBATTB)
|
||||
|
||||
description:
|
||||
Renesas VBATTB is an always on powered module (backed by battery) which
|
||||
controls the RTC clock (VBATTCLK), tamper detection logic and a small
|
||||
general usage memory (128B).
|
||||
|
||||
maintainers:
|
||||
- Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: renesas,r9a08g045-vbattb
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
items:
|
||||
- description: tamper detector interrupt
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: VBATTB module clock
|
||||
- description: RTC input clock (crystal or external clock device)
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: bclk
|
||||
- const: rtx
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
resets:
|
||||
items:
|
||||
- description: VBATTB module reset
|
||||
|
||||
quartz-load-femtofarads:
|
||||
description: load capacitance of the on board crystal
|
||||
enum: [ 4000, 7000, 9000, 12500 ]
|
||||
default: 4000
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
- '#clock-cells'
|
||||
- power-domains
|
||||
- resets
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/r9a08g045-cpg.h>
|
||||
#include <dt-bindings/clock/renesas,r9a08g045-vbattb.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
clock-controller@1005c000 {
|
||||
compatible = "renesas,r9a08g045-vbattb";
|
||||
reg = <0x1005c000 0x1000>;
|
||||
interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cpg CPG_MOD R9A08G045_VBAT_BCLK>, <&vbattb_xtal>;
|
||||
clock-names = "bclk", "rtx";
|
||||
assigned-clocks = <&vbattb VBATTB_MUX>;
|
||||
assigned-clock-parents = <&vbattb VBATTB_XC>;
|
||||
#clock-cells = <1>;
|
||||
power-domains = <&cpg>;
|
||||
resets = <&cpg R9A08G045_VBAT_BRESETN>;
|
||||
quartz-load-femtofarads = <12500>;
|
||||
};
|
|
@ -1,58 +0,0 @@
|
|||
* Rockchip RK3328 Clock and Reset Unit
|
||||
|
||||
The RK3328 clock controller generates and supplies clock to various
|
||||
controllers within the SoC and also implements a reset controller for SoC
|
||||
peripherals.
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: should be "rockchip,rk3328-cru"
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- #clock-cells: should be 1.
|
||||
- #reset-cells: should be 1.
|
||||
|
||||
Optional Properties:
|
||||
|
||||
- rockchip,grf: phandle to the syscon managing the "general register files"
|
||||
If missing pll rates are not changeable, due to the missing pll lock status.
|
||||
|
||||
Each clock is assigned an identifier and client nodes can use this identifier
|
||||
to specify the clock which they consume. All available clocks are defined as
|
||||
preprocessor macros in the dt-bindings/clock/rk3328-cru.h headers and can be
|
||||
used in device tree sources. Similar macros exist for the reset sources in
|
||||
these files.
|
||||
|
||||
External clocks:
|
||||
|
||||
There are several clocks that are generated outside the SoC. It is expected
|
||||
that they are defined using standard clock bindings with following
|
||||
clock-output-names:
|
||||
- "xin24m" - crystal input - required,
|
||||
- "clkin_i2s" - external I2S clock - optional,
|
||||
- "gmac_clkin" - external GMAC clock - optional
|
||||
- "phy_50m_out" - output clock of the pll in the mac phy
|
||||
- "hdmi_phy" - output clock of the hdmi phy pll - optional
|
||||
|
||||
Example: Clock controller node:
|
||||
|
||||
cru: clock-controller@ff440000 {
|
||||
compatible = "rockchip,rk3328-cru";
|
||||
reg = <0x0 0xff440000 0x0 0x1000>;
|
||||
rockchip,grf = <&grf>;
|
||||
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
|
||||
Example: UART controller node that consumes the clock generated by the clock
|
||||
controller:
|
||||
|
||||
uart0: serial@ff120000 {
|
||||
compatible = "snps,dw-apb-uart";
|
||||
reg = <0xff120000 0x100>;
|
||||
interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>;
|
||||
reg-shift = <2>;
|
||||
reg-io-width = <4>;
|
||||
clocks = <&cru SCLK_UART0>;
|
||||
};
|
|
@ -0,0 +1,74 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/rockchip,rk3328-cru.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Rockchip RK3328 Clock and Reset Unit (CRU)
|
||||
|
||||
maintainers:
|
||||
- Elaine Zhang <zhangqing@rock-chips.com>
|
||||
- Heiko Stuebner <heiko@sntech.de>
|
||||
|
||||
description: |
|
||||
The RK3328 clock controller generates and supplies clocks to various
|
||||
controllers within the SoC and also implements a reset controller for SoC
|
||||
peripherals.
|
||||
Each clock is assigned an identifier and client nodes can use this identifier
|
||||
to specify the clock which they consume. All available clocks are defined as
|
||||
preprocessor macros in the dt-bindings/clock/rk3328-cru.h headers and can be
|
||||
used in device tree sources. Similar macros exist for the reset sources in
|
||||
these files.
|
||||
There are several clocks that are generated outside the SoC. It is expected
|
||||
that they are defined using standard clock bindings with following
|
||||
clock-output-names:
|
||||
- "xin24m" - crystal input - required,
|
||||
- "clkin_i2s" - external I2S clock - optional,
|
||||
- "gmac_clkin" - external GMAC clock - optional
|
||||
- "phy_50m_out" - output clock of the pll in the mac phy
|
||||
- "hdmi_phy" - output clock of the hdmi phy pll - optional
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- rockchip,rk3328-cru
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#clock-cells":
|
||||
const: 1
|
||||
|
||||
"#reset-cells":
|
||||
const: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
const: xin24m
|
||||
|
||||
rockchip,grf:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
Phandle to the syscon managing the "general register files" (GRF),
|
||||
if missing pll rates are not changeable, due to the missing pll
|
||||
lock status.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- "#clock-cells"
|
||||
- "#reset-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
cru: clock-controller@ff440000 {
|
||||
compatible = "rockchip,rk3328-cru";
|
||||
reg = <0xff440000 0x1000>;
|
||||
rockchip,grf = <&grf>;
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
};
|
|
@ -16,8 +16,8 @@ merged to this clock. The component clocks shall be of one of the
|
|||
"ti,*composite*-clock" types.
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
[2] Documentation/devicetree/bindings/clock/ti/mux.txt
|
||||
[3] Documentation/devicetree/bindings/clock/ti/divider.txt
|
||||
[2] Documentation/devicetree/bindings/clock/ti/ti,mux-clock.yaml
|
||||
[3] Documentation/devicetree/bindings/clock/ti/ti,divider-clock.yaml
|
||||
[4] Documentation/devicetree/bindings/clock/ti/gate.txt
|
||||
|
||||
Required properties:
|
||||
|
|
|
@ -1,115 +0,0 @@
|
|||
Binding for TI divider clock
|
||||
|
||||
This binding uses the common clock binding[1]. It assumes a
|
||||
register-mapped adjustable clock rate divider that does not gate and has
|
||||
only one input clock or parent. By default the value programmed into
|
||||
the register is one less than the actual divisor value. E.g:
|
||||
|
||||
register value actual divisor value
|
||||
0 1
|
||||
1 2
|
||||
2 3
|
||||
|
||||
This assumption may be modified by the following optional properties:
|
||||
|
||||
ti,index-starts-at-one - valid divisor values start at 1, not the default
|
||||
of 0. E.g:
|
||||
register value actual divisor value
|
||||
1 1
|
||||
2 2
|
||||
3 3
|
||||
|
||||
ti,index-power-of-two - valid divisor values are powers of two. E.g:
|
||||
register value actual divisor value
|
||||
0 1
|
||||
1 2
|
||||
2 4
|
||||
|
||||
Additionally an array of valid dividers may be supplied like so:
|
||||
|
||||
ti,dividers = <4>, <8>, <0>, <16>;
|
||||
|
||||
Which will map the resulting values to a divisor table by their index:
|
||||
register value actual divisor value
|
||||
0 4
|
||||
1 8
|
||||
2 <invalid divisor, skipped>
|
||||
3 16
|
||||
|
||||
Any zero value in this array means the corresponding bit-value is invalid
|
||||
and must not be used.
|
||||
|
||||
The binding must also provide the register to control the divider and
|
||||
unless the divider array is provided, min and max dividers. Optionally
|
||||
the number of bits to shift that mask, if necessary. If the shift value
|
||||
is missing it is the same as supplying a zero shift.
|
||||
|
||||
This binding can also optionally provide support to the hardware autoidle
|
||||
feature, see [2].
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
[2] Documentation/devicetree/bindings/clock/ti/autoidle.txt
|
||||
|
||||
Required properties:
|
||||
- compatible : shall be "ti,divider-clock" or "ti,composite-divider-clock".
|
||||
- #clock-cells : from common clock binding; shall be set to 0.
|
||||
- clocks : link to phandle of parent clock
|
||||
- reg : offset for register controlling adjustable divider
|
||||
|
||||
Optional properties:
|
||||
- clock-output-names : from common clock binding.
|
||||
- ti,dividers : array of integers defining divisors
|
||||
- ti,bit-shift : number of bits to shift the divider value, defaults to 0
|
||||
- ti,min-div : min divisor for dividing the input clock rate, only
|
||||
needed if the first divisor is offset from the default value (1)
|
||||
- ti,max-div : max divisor for dividing the input clock rate, only needed
|
||||
if ti,dividers is not defined.
|
||||
- ti,index-starts-at-one : valid divisor programming starts at 1, not zero,
|
||||
only valid if ti,dividers is not defined.
|
||||
- ti,index-power-of-two : valid divisor programming must be a power of two,
|
||||
only valid if ti,dividers is not defined.
|
||||
- ti,autoidle-shift : bit shift of the autoidle enable bit for the clock,
|
||||
see [2]
|
||||
- ti,invert-autoidle-bit : autoidle is enabled by setting the bit to 0,
|
||||
see [2]
|
||||
- ti,set-rate-parent : clk_set_rate is propagated to parent
|
||||
- ti,latch-bit : latch the divider value to HW, only needed if the register
|
||||
access requires this. As an example dra76x DPLL_GMAC H14 divider implements
|
||||
such behavior.
|
||||
|
||||
Examples:
|
||||
dpll_usb_m2_ck: dpll_usb_m2_ck@4a008190 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "ti,divider-clock";
|
||||
clocks = <&dpll_usb_ck>;
|
||||
ti,max-div = <127>;
|
||||
reg = <0x190>;
|
||||
ti,index-starts-at-one;
|
||||
};
|
||||
|
||||
aess_fclk: aess_fclk@4a004528 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "ti,divider-clock";
|
||||
clocks = <&abe_clk>;
|
||||
ti,bit-shift = <24>;
|
||||
reg = <0x528>;
|
||||
ti,max-div = <2>;
|
||||
};
|
||||
|
||||
dpll_core_m3x2_div_ck: dpll_core_m3x2_div_ck {
|
||||
#clock-cells = <0>;
|
||||
compatible = "ti,composite-divider-clock";
|
||||
clocks = <&dpll_core_x2_ck>;
|
||||
ti,max-div = <31>;
|
||||
reg = <0x0134>;
|
||||
ti,index-starts-at-one;
|
||||
};
|
||||
|
||||
ssi_ssr_div_fck_3430es2: ssi_ssr_div_fck_3430es2 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "ti,composite-divider-clock";
|
||||
clocks = <&corex2_fck>;
|
||||
ti,bit-shift = <8>;
|
||||
reg = <0x0a40>;
|
||||
ti,dividers = <0>, <1>, <2>, <3>, <4>, <0>, <6>, <0>, <8>;
|
||||
};
|
|
@ -1,55 +0,0 @@
|
|||
Binding for Texas Instruments interface clock.
|
||||
|
||||
This binding uses the common clock binding[1]. This clock is
|
||||
quite much similar to the basic gate-clock [2], however,
|
||||
it supports a number of additional features, including
|
||||
companion clock finding (match corresponding functional gate
|
||||
clock) and hardware autoidle enable / disable.
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
[2] Documentation/devicetree/bindings/clock/gpio-gate-clock.yaml
|
||||
|
||||
Required properties:
|
||||
- compatible : shall be one of:
|
||||
"ti,omap3-interface-clock" - basic OMAP3 interface clock
|
||||
"ti,omap3-no-wait-interface-clock" - interface clock which has no hardware
|
||||
capability for waiting clock to be ready
|
||||
"ti,omap3-hsotgusb-interface-clock" - interface clock with USB specific HW
|
||||
handling
|
||||
"ti,omap3-dss-interface-clock" - interface clock with DSS specific HW handling
|
||||
"ti,omap3-ssi-interface-clock" - interface clock with SSI specific HW handling
|
||||
"ti,am35xx-interface-clock" - interface clock with AM35xx specific HW handling
|
||||
"ti,omap2430-interface-clock" - interface clock with OMAP2430 specific HW
|
||||
handling
|
||||
- #clock-cells : from common clock binding; shall be set to 0
|
||||
- clocks : link to phandle of parent clock
|
||||
- reg : base address for the control register
|
||||
|
||||
Optional properties:
|
||||
- clock-output-names : from common clock binding.
|
||||
- ti,bit-shift : bit shift for the bit enabling/disabling the clock (default 0)
|
||||
|
||||
Examples:
|
||||
aes1_ick: aes1_ick@48004a14 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "ti,omap3-interface-clock";
|
||||
clocks = <&security_l4_ick2>;
|
||||
reg = <0x48004a14 0x4>;
|
||||
ti,bit-shift = <3>;
|
||||
};
|
||||
|
||||
cam_ick: cam_ick@48004f10 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "ti,omap3-no-wait-interface-clock";
|
||||
clocks = <&l4_ick>;
|
||||
reg = <0x48004f10 0x4>;
|
||||
ti,bit-shift = <0>;
|
||||
};
|
||||
|
||||
ssi_ick_3430es2: ssi_ick_3430es2@48004a10 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "ti,omap3-ssi-interface-clock";
|
||||
clocks = <&ssi_l4_ick>;
|
||||
reg = <0x48004a10 0x4>;
|
||||
ti,bit-shift = <0>;
|
||||
};
|
|
@ -1,78 +0,0 @@
|
|||
Binding for TI mux clock.
|
||||
|
||||
This binding uses the common clock binding[1]. It assumes a
|
||||
register-mapped multiplexer with multiple input clock signals or
|
||||
parents, one of which can be selected as output. This clock does not
|
||||
gate or adjust the parent rate via a divider or multiplier.
|
||||
|
||||
By default the "clocks" property lists the parents in the same order
|
||||
as they are programmed into the register. E.g:
|
||||
|
||||
clocks = <&foo_clock>, <&bar_clock>, <&baz_clock>;
|
||||
|
||||
results in programming the register as follows:
|
||||
|
||||
register value selected parent clock
|
||||
0 foo_clock
|
||||
1 bar_clock
|
||||
2 baz_clock
|
||||
|
||||
Some clock controller IPs do not allow a value of zero to be programmed
|
||||
into the register, instead indexing begins at 1. The optional property
|
||||
"index-starts-at-one" modified the scheme as follows:
|
||||
|
||||
register value selected clock parent
|
||||
1 foo_clock
|
||||
2 bar_clock
|
||||
3 baz_clock
|
||||
|
||||
The binding must provide the register to control the mux. Optionally
|
||||
the number of bits to shift the control field in the register can be
|
||||
supplied. If the shift value is missing it is the same as supplying
|
||||
a zero shift.
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
|
||||
Required properties:
|
||||
- compatible : shall be "ti,mux-clock" or "ti,composite-mux-clock".
|
||||
- #clock-cells : from common clock binding; shall be set to 0.
|
||||
- clocks : link phandles of parent clocks
|
||||
- reg : register offset for register controlling adjustable mux
|
||||
|
||||
Optional properties:
|
||||
- clock-output-names : from common clock binding.
|
||||
- ti,bit-shift : number of bits to shift the bit-mask, defaults to
|
||||
0 if not present
|
||||
- ti,index-starts-at-one : valid input select programming starts at 1, not
|
||||
zero
|
||||
- ti,set-rate-parent : clk_set_rate is propagated to parent clock,
|
||||
not supported by the composite-mux-clock subtype
|
||||
- ti,latch-bit : latch the mux value to HW, only needed if the register
|
||||
access requires this. As an example, dra7x DPLL_GMAC H14 muxing
|
||||
implements such behavior.
|
||||
|
||||
Examples:
|
||||
|
||||
sys_clkin_ck: sys_clkin_ck@4a306110 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "ti,mux-clock";
|
||||
clocks = <&virt_12000000_ck>, <&virt_13000000_ck>, <&virt_16800000_ck>, <&virt_19200000_ck>, <&virt_26000000_ck>, <&virt_27000000_ck>, <&virt_38400000_ck>;
|
||||
reg = <0x0110>;
|
||||
ti,index-starts-at-one;
|
||||
};
|
||||
|
||||
abe_dpll_bypass_clk_mux_ck: abe_dpll_bypass_clk_mux_ck@4a306108 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "ti,mux-clock";
|
||||
clocks = <&sys_clkin_ck>, <&sys_32k_ck>;
|
||||
ti,bit-shift = <24>;
|
||||
reg = <0x0108>;
|
||||
};
|
||||
|
||||
mcbsp5_mux_fck: mcbsp5_mux_fck {
|
||||
#clock-cells = <0>;
|
||||
compatible = "ti,composite-mux-clock";
|
||||
clocks = <&core_96m_fck>, <&mcbsp_clks>;
|
||||
ti,bit-shift = <4>;
|
||||
reg = <0x02d8>;
|
||||
};
|
193
Documentation/devicetree/bindings/clock/ti/ti,divider-clock.yaml
Normal file
193
Documentation/devicetree/bindings/clock/ti/ti,divider-clock.yaml
Normal file
|
@ -0,0 +1,193 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/ti/ti,divider-clock.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments divider clock
|
||||
|
||||
maintainers:
|
||||
- Tero Kristo <kristo@kernel.org>
|
||||
|
||||
description: |
|
||||
This clock It assumes a register-mapped adjustable clock rate divider
|
||||
that does not gate and has only one input clock or parent. By default the
|
||||
value programmed into the register is one less than the actual divisor value.
|
||||
E.g:
|
||||
|
||||
register value actual divisor value
|
||||
0 1
|
||||
1 2
|
||||
2 3
|
||||
|
||||
This assumption may be modified by the following optional properties:
|
||||
|
||||
ti,index-starts-at-one - valid divisor values start at 1, not the default
|
||||
of 0. E.g:
|
||||
register value actual divisor value
|
||||
1 1
|
||||
2 2
|
||||
3 3
|
||||
|
||||
ti,index-power-of-two - valid divisor values are powers of two. E.g:
|
||||
register value actual divisor value
|
||||
0 1
|
||||
1 2
|
||||
2 4
|
||||
|
||||
Additionally an array of valid dividers may be supplied like so:
|
||||
|
||||
ti,dividers = <4>, <8>, <0>, <16>;
|
||||
|
||||
Which will map the resulting values to a divisor table by their index:
|
||||
register value actual divisor value
|
||||
0 4
|
||||
1 8
|
||||
2 <invalid divisor, skipped>
|
||||
3 16
|
||||
|
||||
Any zero value in this array means the corresponding bit-value is invalid
|
||||
and must not be used.
|
||||
|
||||
The binding must also provide the register to control the divider and
|
||||
unless the divider array is provided, min and max dividers. Optionally
|
||||
the number of bits to shift that mask, if necessary. If the shift value
|
||||
is missing it is the same as supplying a zero shift.
|
||||
|
||||
This binding can also optionally provide support to the hardware autoidle
|
||||
feature, see [1].
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/ti/autoidle.txt
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,divider-clock
|
||||
- ti,composite-divider-clock
|
||||
|
||||
"#clock-cells":
|
||||
const: 0
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-output-names:
|
||||
maxItems: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
ti,dividers:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
description:
|
||||
array of integers defining divisors
|
||||
|
||||
ti,bit-shift:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
number of bits to shift the divider value
|
||||
maximum: 31
|
||||
default: 0
|
||||
|
||||
ti,min-div:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
min divisor for dividing the input clock rate, only
|
||||
needed if the first divisor is offset from the default value (1)
|
||||
minimum: 1
|
||||
default: 1
|
||||
|
||||
|
||||
ti,max-div:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
max divisor for dividing the input clock rate, only needed
|
||||
if ti,dividers is not defined.
|
||||
|
||||
ti,index-starts-at-one:
|
||||
type: boolean
|
||||
description:
|
||||
valid divisor programming starts at 1, not zero,
|
||||
only valid if ti,dividers is not defined
|
||||
|
||||
ti,index-power-of-two:
|
||||
type: boolean
|
||||
description:
|
||||
valid divisor programming must be a power of two,
|
||||
only valid if ti,dividers is not defined.
|
||||
|
||||
ti,autoidle-shift:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
bit shift of the autoidle enable bit for the clock,
|
||||
see [1].
|
||||
maximum: 31
|
||||
default: 0
|
||||
|
||||
ti,invert-autoidle-bit:
|
||||
type: boolean
|
||||
description:
|
||||
autoidle is enabled by setting the bit to 0,
|
||||
see [1]
|
||||
|
||||
ti,set-rate-parent:
|
||||
type: boolean
|
||||
description:
|
||||
clk_set_rate is propagated to parent |
|
||||
|
||||
ti,latch-bit:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
latch the divider value to HW, only needed if the register
|
||||
compatible access requires this. As an example dra76x DPLL_GMAC
|
||||
H14 divider implements such behavior.
|
||||
|
||||
dependentSchemas:
|
||||
ti,dividers:
|
||||
properties:
|
||||
ti,min-div: false
|
||||
ti,max-div: false
|
||||
ti,index-power-of-two: false
|
||||
ti,index-starts-at-one: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- "#clock-cells"
|
||||
- clocks
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
bus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
clock-controller@190 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "ti,divider-clock";
|
||||
clocks = <&dpll_usb_ck>;
|
||||
ti,max-div = <127>;
|
||||
reg = <0x190>;
|
||||
ti,index-starts-at-one;
|
||||
};
|
||||
|
||||
clock-controller@528 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "ti,divider-clock";
|
||||
clocks = <&abe_clk>;
|
||||
ti,bit-shift = <24>;
|
||||
reg = <0x528>;
|
||||
ti,max-div = <2>;
|
||||
};
|
||||
|
||||
clock-controller@a40 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "ti,composite-divider-clock";
|
||||
clocks = <&corex2_fck>;
|
||||
ti,bit-shift = <8>;
|
||||
reg = <0x0a40>;
|
||||
ti,dividers = <0>, <1>, <2>, <3>, <4>, <0>, <6>, <0>, <8>;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,71 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/ti/ti,interface-clock.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments interface clock.
|
||||
|
||||
maintainers:
|
||||
- Tero Kristo <kristo@kernel.org>
|
||||
|
||||
description: |
|
||||
This clock is quite much similar to the basic gate-clock[1], however,
|
||||
it supports a number of additional features, including
|
||||
companion clock finding (match corresponding functional gate
|
||||
clock) and hardware autoidle enable / disable.
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/gpio-gate-clock.yaml
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,omap3-interface-clock # basic OMAP3 interface clock
|
||||
- ti,omap3-no-wait-interface-clock # interface clock which has no hardware
|
||||
# capability for waiting clock to be ready
|
||||
- ti,omap3-hsotgusb-interface-clock # interface clock with USB specific HW handling
|
||||
- ti,omap3-dss-interface-clock # interface clock with DSS specific HW handling
|
||||
- ti,omap3-ssi-interface-clock # interface clock with SSI specific HW handling
|
||||
- ti,am35xx-interface-clock # interface clock with AM35xx specific HW handling
|
||||
- ti,omap2430-interface-clock # interface clock with OMAP2430 specific HW handling
|
||||
|
||||
"#clock-cells":
|
||||
const: 0
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-output-names:
|
||||
maxItems: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
ti,bit-shift:
|
||||
description:
|
||||
bit shift for the bit enabling/disabling the clock
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
default: 0
|
||||
maximum: 31
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- clocks
|
||||
- '#clock-cells'
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
bus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
aes1_ick: clock-controller@3 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "ti,omap3-interface-clock";
|
||||
clocks = <&security_l4_ick2>;
|
||||
reg = <3>;
|
||||
};
|
||||
};
|
125
Documentation/devicetree/bindings/clock/ti/ti,mux-clock.yaml
Normal file
125
Documentation/devicetree/bindings/clock/ti/ti,mux-clock.yaml
Normal file
|
@ -0,0 +1,125 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/ti/ti,mux-clock.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments mux clock
|
||||
|
||||
maintainers:
|
||||
- Tero Kristo <kristo@kernel.org>
|
||||
|
||||
description: |
|
||||
This clock assumes a register-mapped multiplexer with multiple inpt clock
|
||||
signals or parents, one of which can be selected as output. This clock does
|
||||
not gate or adjust the parent rate via a divider or multiplier.
|
||||
|
||||
By default the "clocks" property lists the parents in the same order
|
||||
as they are programmed into the register. E.g:
|
||||
|
||||
clocks = <&foo_clock>, <&bar_clock>, <&baz_clock>;
|
||||
|
||||
Results in programming the register as follows:
|
||||
|
||||
register value selected parent clock
|
||||
0 foo_clock
|
||||
1 bar_clock
|
||||
2 baz_clock
|
||||
|
||||
Some clock controller IPs do not allow a value of zero to be programmed
|
||||
into the register, instead indexing begins at 1. The optional property
|
||||
"index-starts-at-one" modified the scheme as follows:
|
||||
|
||||
register value selected clock parent
|
||||
1 foo_clock
|
||||
2 bar_clock
|
||||
3 baz_clock
|
||||
|
||||
The binding must provide the register to control the mux. Optionally
|
||||
the number of bits to shift the control field in the register can be
|
||||
supplied. If the shift value is missing it is the same as supplying
|
||||
a zero shift.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,mux-clock
|
||||
- ti,composite-mux-clock
|
||||
|
||||
"#clock-cells":
|
||||
const: 0
|
||||
|
||||
clocks: true
|
||||
|
||||
clock-output-names:
|
||||
maxItems: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
ti,bit-shift:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
Number of bits to shift the bit-mask
|
||||
maximum: 31
|
||||
default: 0
|
||||
|
||||
ti,index-starts-at-one:
|
||||
type: boolean
|
||||
description:
|
||||
Valid input select programming starts at 1, not zero
|
||||
|
||||
ti,set-rate-parent:
|
||||
type: boolean
|
||||
description:
|
||||
clk_set_rate is propagated to parent clock,
|
||||
not supported by the composite-mux-clock subtype.
|
||||
|
||||
ti,latch-bit:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
Latch the mux value to HW, only needed if the register
|
||||
access requires this. As an example, dra7x DPLL_GMAC H14 muxing
|
||||
implements such behavior.
|
||||
maximum: 31
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: ti,composite-mux-clock
|
||||
then:
|
||||
properties:
|
||||
ti,set-rate-parent: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- "#clock-cells"
|
||||
- clocks
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
bus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
clock-controller@110 {
|
||||
compatible = "ti,mux-clock";
|
||||
reg = <0x0110>;
|
||||
#clock-cells = <0>;
|
||||
clocks = <&virt_12000000_ck>, <&virt_13000000_ck>, <&virt_16800000_ck>;
|
||||
ti,index-starts-at-one;
|
||||
ti,set-rate-parent;
|
||||
};
|
||||
|
||||
clock-controller@120 {
|
||||
compatible = "ti,composite-mux-clock";
|
||||
reg = <0x0120>;
|
||||
#clock-cells = <0>;
|
||||
clocks = <&core_96m_fck>, <&mcbsp_clks>;
|
||||
ti,bit-shift = <4>;
|
||||
};
|
||||
};
|
|
@ -21,6 +21,13 @@ properties:
|
|||
'#reset-cells':
|
||||
const: 2
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: specify external 25MHz reference clock.
|
||||
|
||||
nuvoton,sysgcr:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: a phandle to access GCR registers.
|
||||
|
@ -39,6 +46,17 @@ required:
|
|||
- '#reset-cells'
|
||||
- nuvoton,sysgcr
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- nuvoton,npcm845-reset
|
||||
then:
|
||||
required:
|
||||
- '#clock-cells'
|
||||
- clocks
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
|
|
|
@ -41,9 +41,7 @@ properties:
|
|||
enum: [ 1, 2 ]
|
||||
|
||||
'#clock-cells':
|
||||
description:
|
||||
Cell is clock index. Optional if compatible has a single clock.
|
||||
enum: [ 0, 1 ]
|
||||
const: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
@ -312,26 +310,6 @@ allOf:
|
|||
properties:
|
||||
'#reset-cells': false
|
||||
|
||||
# Compatibles exposing a single clock.
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- mobileye,eyeq6h-central-olb
|
||||
- mobileye,eyeq6h-east-olb
|
||||
- mobileye,eyeq6h-west-olb
|
||||
- mobileye,eyeq6h-ddr0-olb
|
||||
- mobileye,eyeq6h-ddr1-olb
|
||||
then:
|
||||
properties:
|
||||
'#clock-cells':
|
||||
const: 0
|
||||
else:
|
||||
properties:
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
# Only EyeQ5 has pinctrl in OLB.
|
||||
- if:
|
||||
not:
|
||||
|
|
|
@ -1996,7 +1996,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
|||
L: linux-actions@lists.infradead.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/arm/actions.yaml
|
||||
F: Documentation/devicetree/bindings/clock/actions,owl-cmu.txt
|
||||
F: Documentation/devicetree/bindings/clock/actions,owl-cmu.yaml
|
||||
F: Documentation/devicetree/bindings/dma/owl-dma.yaml
|
||||
F: Documentation/devicetree/bindings/i2c/i2c-owl.yaml
|
||||
F: Documentation/devicetree/bindings/interrupt-controller/actions,owl-sirq.yaml
|
||||
|
|
|
@ -226,6 +226,17 @@ config COMMON_CLK_EP93XX
|
|||
help
|
||||
This driver supports the SoC clocks on the Cirrus Logic ep93xx.
|
||||
|
||||
config COMMON_CLK_EYEQ
|
||||
bool "Clock driver for the Mobileye EyeQ platform"
|
||||
depends on MACH_EYEQ5 || MACH_EYEQ6H || COMPILE_TEST
|
||||
select AUXILIARY_BUS
|
||||
default MACH_EYEQ5 || MACH_EYEQ6H
|
||||
help
|
||||
This driver provides clocks found on Mobileye EyeQ5, EyeQ6L and Eye6H
|
||||
SoCs. Controllers live in shared register regions called OLB. Driver
|
||||
provides read-only PLLs, derived from the main crystal clock (which
|
||||
must be constant). It also exposes some divider clocks.
|
||||
|
||||
config COMMON_CLK_FSL_FLEXSPI
|
||||
tristate "Clock driver for FlexSPI on Layerscape SoCs"
|
||||
depends on ARCH_LAYERSCAPE || COMPILE_TEST
|
||||
|
@ -291,7 +302,7 @@ config CLK_TWL
|
|||
help
|
||||
Enable support for controlling the clock resources on TWL family
|
||||
PMICs. These devices have some 32K clock outputs which can be
|
||||
controlled by software. For now, only the TWL6032 clocks are
|
||||
controlled by software. For now, the TWL6032 and TWL6030 clocks are
|
||||
supported.
|
||||
|
||||
config CLK_TWL6040
|
||||
|
@ -342,6 +353,14 @@ config COMMON_CLK_LOCHNAGAR
|
|||
This driver supports the clocking features of the Cirrus Logic
|
||||
Lochnagar audio development board.
|
||||
|
||||
config COMMON_CLK_NPCM8XX
|
||||
tristate "Clock driver for the NPCM8XX SoC Family"
|
||||
depends on ARCH_NPCM || COMPILE_TEST
|
||||
help
|
||||
This driver supports the clocks on the Nuvoton BMC NPCM8XX SoC Family,
|
||||
all the clocks are initialized by the bootloader, so this driver
|
||||
allows only reading of current settings directly from the hardware.
|
||||
|
||||
config COMMON_CLK_LOONGSON2
|
||||
bool "Clock driver for Loongson-2 SoC"
|
||||
depends on LOONGARCH || COMPILE_TEST
|
||||
|
|
|
@ -56,6 +56,7 @@ obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o
|
|||
obj-$(CONFIG_COMMON_CLK_EP93XX) += clk-ep93xx.o
|
||||
obj-$(CONFIG_ARCH_SPARX5) += clk-sparx5.o
|
||||
obj-$(CONFIG_COMMON_CLK_EN7523) += clk-en7523.o
|
||||
obj-$(CONFIG_COMMON_CLK_EYEQ) += clk-eyeq.o
|
||||
obj-$(CONFIG_COMMON_CLK_FIXED_MMIO) += clk-fixed-mmio.o
|
||||
obj-$(CONFIG_COMMON_CLK_FSL_FLEXSPI) += clk-fsl-flexspi.o
|
||||
obj-$(CONFIG_COMMON_CLK_FSL_SAI) += clk-fsl-sai.o
|
||||
|
@ -76,6 +77,7 @@ 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
|
||||
obj-$(CONFIG_COMMON_CLK_NPCM8XX) += clk-npcm8xx.o
|
||||
obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o
|
||||
obj-$(CONFIG_COMMON_CLK_PALMAS) += clk-palmas.o
|
||||
obj-$(CONFIG_CLK_LS1028A_PLLDIG) += clk-plldig.o
|
||||
|
|
|
@ -72,6 +72,8 @@ static unsigned int _get_maxdiv(const struct clk_div_table *table, u8 width,
|
|||
return clk_div_mask(width);
|
||||
if (flags & CLK_DIVIDER_POWER_OF_TWO)
|
||||
return 1 << clk_div_mask(width);
|
||||
if (flags & CLK_DIVIDER_EVEN_INTEGERS)
|
||||
return 2 * (clk_div_mask(width) + 1);
|
||||
if (table)
|
||||
return _get_table_maxdiv(table, width);
|
||||
return clk_div_mask(width) + 1;
|
||||
|
@ -97,6 +99,8 @@ static unsigned int _get_div(const struct clk_div_table *table,
|
|||
return 1 << val;
|
||||
if (flags & CLK_DIVIDER_MAX_AT_ZERO)
|
||||
return val ? val : clk_div_mask(width) + 1;
|
||||
if (flags & CLK_DIVIDER_EVEN_INTEGERS)
|
||||
return 2 * (val + 1);
|
||||
if (table)
|
||||
return _get_table_div(table, val);
|
||||
return val + 1;
|
||||
|
@ -122,6 +126,8 @@ static unsigned int _get_val(const struct clk_div_table *table,
|
|||
return __ffs(div);
|
||||
if (flags & CLK_DIVIDER_MAX_AT_ZERO)
|
||||
return (div == clk_div_mask(width) + 1) ? 0 : div;
|
||||
if (flags & CLK_DIVIDER_EVEN_INTEGERS)
|
||||
return (div >> 1) - 1;
|
||||
if (table)
|
||||
return _get_table_val(table, div);
|
||||
return div - 1;
|
||||
|
@ -538,7 +544,8 @@ struct clk_hw *__clk_hw_register_divider(struct device *dev,
|
|||
struct device_node *np, const char *name,
|
||||
const char *parent_name, const struct clk_hw *parent_hw,
|
||||
const struct clk_parent_data *parent_data, unsigned long flags,
|
||||
void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags,
|
||||
void __iomem *reg, u8 shift, u8 width,
|
||||
unsigned long clk_divider_flags,
|
||||
const struct clk_div_table *table, spinlock_t *lock)
|
||||
{
|
||||
struct clk_divider *div;
|
||||
|
@ -610,8 +617,8 @@ EXPORT_SYMBOL_GPL(__clk_hw_register_divider);
|
|||
struct clk *clk_register_divider_table(struct device *dev, const char *name,
|
||||
const char *parent_name, unsigned long flags,
|
||||
void __iomem *reg, u8 shift, u8 width,
|
||||
u8 clk_divider_flags, const struct clk_div_table *table,
|
||||
spinlock_t *lock)
|
||||
unsigned long clk_divider_flags,
|
||||
const struct clk_div_table *table, spinlock_t *lock)
|
||||
{
|
||||
struct clk_hw *hw;
|
||||
|
||||
|
@ -664,7 +671,8 @@ struct clk_hw *__devm_clk_hw_register_divider(struct device *dev,
|
|||
struct device_node *np, const char *name,
|
||||
const char *parent_name, const struct clk_hw *parent_hw,
|
||||
const struct clk_parent_data *parent_data, unsigned long flags,
|
||||
void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags,
|
||||
void __iomem *reg, u8 shift, u8 width,
|
||||
unsigned long clk_divider_flags,
|
||||
const struct clk_div_table *table, spinlock_t *lock)
|
||||
{
|
||||
struct clk_hw **ptr, *hw;
|
||||
|
|
859
drivers/clk/clk-eyeq.c
Normal file
859
drivers/clk/clk-eyeq.c
Normal file
|
@ -0,0 +1,859 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* PLL clock driver for the Mobileye EyeQ5, EyeQ6L and EyeQ6H platforms.
|
||||
*
|
||||
* This controller handles:
|
||||
* - Read-only PLLs, all derived from the same main crystal clock.
|
||||
* - It also exposes divider clocks, those are children to PLLs.
|
||||
* - Fixed factor clocks, children to PLLs.
|
||||
*
|
||||
* Parent clock is expected to be constant. This driver's registers live in a
|
||||
* shared region called OLB. Some PLLs and fixed-factors are initialised early
|
||||
* by of_clk_init(); if so, two clk providers are registered.
|
||||
*
|
||||
* We use eqc_ as prefix, as-in "EyeQ Clock", but way shorter.
|
||||
*
|
||||
* Copyright (C) 2024 Mobileye Vision Technologies Ltd.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Set pr_fmt() for printing from eqc_early_init().
|
||||
* It is called at of_clk_init() stage (read: really early).
|
||||
*/
|
||||
#define pr_fmt(fmt) "clk-eyeq: " fmt
|
||||
|
||||
#include <linux/array_size.h>
|
||||
#include <linux/auxiliary_bus.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io-64-nonatomic-hi-lo.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/overflow.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <dt-bindings/clock/mobileye,eyeq5-clk.h>
|
||||
|
||||
/* In frac mode, it enables fractional noise canceling DAC. Else, no function. */
|
||||
#define PCSR0_DAC_EN BIT(0)
|
||||
/* Fractional or integer mode */
|
||||
#define PCSR0_DSM_EN BIT(1)
|
||||
#define PCSR0_PLL_EN BIT(2)
|
||||
/* All clocks output held at 0 */
|
||||
#define PCSR0_FOUTPOSTDIV_EN BIT(3)
|
||||
#define PCSR0_POST_DIV1 GENMASK(6, 4)
|
||||
#define PCSR0_POST_DIV2 GENMASK(9, 7)
|
||||
#define PCSR0_REF_DIV GENMASK(15, 10)
|
||||
#define PCSR0_INTIN GENMASK(27, 16)
|
||||
#define PCSR0_BYPASS BIT(28)
|
||||
/* Bits 30..29 are reserved */
|
||||
#define PCSR0_PLL_LOCKED BIT(31)
|
||||
|
||||
#define PCSR1_RESET BIT(0)
|
||||
#define PCSR1_SSGC_DIV GENMASK(4, 1)
|
||||
/* Spread amplitude (% = 0.1 * SPREAD[4:0]) */
|
||||
#define PCSR1_SPREAD GENMASK(9, 5)
|
||||
#define PCSR1_DIS_SSCG BIT(10)
|
||||
/* Down-spread or center-spread */
|
||||
#define PCSR1_DOWN_SPREAD BIT(11)
|
||||
#define PCSR1_FRAC_IN GENMASK(31, 12)
|
||||
|
||||
struct eqc_pll {
|
||||
unsigned int index;
|
||||
const char *name;
|
||||
unsigned int reg64;
|
||||
};
|
||||
|
||||
/*
|
||||
* Divider clock. Divider is 2*(v+1), with v the register value.
|
||||
* Min divider is 2, max is 2*(2^width).
|
||||
*/
|
||||
struct eqc_div {
|
||||
unsigned int index;
|
||||
const char *name;
|
||||
unsigned int parent;
|
||||
unsigned int reg;
|
||||
u8 shift;
|
||||
u8 width;
|
||||
};
|
||||
|
||||
struct eqc_fixed_factor {
|
||||
unsigned int index;
|
||||
const char *name;
|
||||
unsigned int mult;
|
||||
unsigned int div;
|
||||
unsigned int parent;
|
||||
};
|
||||
|
||||
struct eqc_match_data {
|
||||
unsigned int pll_count;
|
||||
const struct eqc_pll *plls;
|
||||
|
||||
unsigned int div_count;
|
||||
const struct eqc_div *divs;
|
||||
|
||||
unsigned int fixed_factor_count;
|
||||
const struct eqc_fixed_factor *fixed_factors;
|
||||
|
||||
const char *reset_auxdev_name;
|
||||
const char *pinctrl_auxdev_name;
|
||||
|
||||
unsigned int early_clk_count;
|
||||
};
|
||||
|
||||
struct eqc_early_match_data {
|
||||
unsigned int early_pll_count;
|
||||
const struct eqc_pll *early_plls;
|
||||
|
||||
unsigned int early_fixed_factor_count;
|
||||
const struct eqc_fixed_factor *early_fixed_factors;
|
||||
|
||||
/*
|
||||
* We want our of_xlate callback to EPROBE_DEFER instead of dev_err()
|
||||
* and EINVAL. For that, we must know the total clock count.
|
||||
*/
|
||||
unsigned int late_clk_count;
|
||||
};
|
||||
|
||||
/*
|
||||
* Both factors (mult and div) must fit in 32 bits. When an operation overflows,
|
||||
* this function throws away low bits so that factors still fit in 32 bits.
|
||||
*
|
||||
* Precision loss depends on amplitude of mult and div. Worst theorical
|
||||
* loss is: (UINT_MAX+1) / UINT_MAX - 1 = 2.3e-10.
|
||||
* This is 1Hz every 4.3GHz.
|
||||
*/
|
||||
static void eqc_pll_downshift_factors(unsigned long *mult, unsigned long *div)
|
||||
{
|
||||
unsigned long biggest;
|
||||
unsigned int shift;
|
||||
|
||||
/* This function can be removed if mult/div switch to unsigned long. */
|
||||
static_assert(sizeof_field(struct clk_fixed_factor, mult) == sizeof(unsigned int));
|
||||
static_assert(sizeof_field(struct clk_fixed_factor, div) == sizeof(unsigned int));
|
||||
|
||||
/* No overflow, nothing to be done. */
|
||||
if (*mult <= UINT_MAX && *div <= UINT_MAX)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Compute the shift required to bring the biggest factor into unsigned
|
||||
* int range. That is, shift its highest set bit to the unsigned int
|
||||
* most significant bit.
|
||||
*/
|
||||
biggest = max(*mult, *div);
|
||||
shift = __fls(biggest) - (BITS_PER_BYTE * sizeof(unsigned int)) + 1;
|
||||
|
||||
*mult >>= shift;
|
||||
*div >>= shift;
|
||||
}
|
||||
|
||||
static int eqc_pll_parse_registers(u32 r0, u32 r1, unsigned long *mult,
|
||||
unsigned long *div, unsigned long *acc)
|
||||
{
|
||||
u32 spread;
|
||||
|
||||
if (r0 & PCSR0_BYPASS) {
|
||||
*mult = 1;
|
||||
*div = 1;
|
||||
*acc = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(r0 & PCSR0_PLL_LOCKED))
|
||||
return -EINVAL;
|
||||
|
||||
*mult = FIELD_GET(PCSR0_INTIN, r0);
|
||||
*div = FIELD_GET(PCSR0_REF_DIV, r0);
|
||||
if (r0 & PCSR0_FOUTPOSTDIV_EN)
|
||||
*div *= FIELD_GET(PCSR0_POST_DIV1, r0) * FIELD_GET(PCSR0_POST_DIV2, r0);
|
||||
|
||||
/* Fractional mode, in 2^20 (0x100000) parts. */
|
||||
if (r0 & PCSR0_DSM_EN) {
|
||||
*div *= (1ULL << 20);
|
||||
*mult = *mult * (1ULL << 20) + FIELD_GET(PCSR1_FRAC_IN, r1);
|
||||
}
|
||||
|
||||
if (!*mult || !*div)
|
||||
return -EINVAL;
|
||||
|
||||
if (r1 & (PCSR1_RESET | PCSR1_DIS_SSCG)) {
|
||||
*acc = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Spread spectrum.
|
||||
*
|
||||
* Spread is 1/1000 parts of frequency, accuracy is half of
|
||||
* that. To get accuracy, convert to ppb (parts per billion).
|
||||
*
|
||||
* acc = spread * 1e6 / 2
|
||||
* with acc in parts per billion and,
|
||||
* spread in parts per thousand.
|
||||
*/
|
||||
spread = FIELD_GET(PCSR1_SPREAD, r1);
|
||||
*acc = spread * 500000;
|
||||
|
||||
if (r1 & PCSR1_DOWN_SPREAD) {
|
||||
/*
|
||||
* Downspreading: the central frequency is half a
|
||||
* spread lower.
|
||||
*/
|
||||
*mult *= 2000 - spread;
|
||||
*div *= 2000;
|
||||
|
||||
/*
|
||||
* Previous operation might overflow 32 bits. If it
|
||||
* does, throw away the least amount of low bits.
|
||||
*/
|
||||
eqc_pll_downshift_factors(mult, div);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void eqc_probe_init_plls(struct device *dev, const struct eqc_match_data *data,
|
||||
void __iomem *base, struct clk_hw_onecell_data *cells)
|
||||
{
|
||||
unsigned long mult, div, acc;
|
||||
const struct eqc_pll *pll;
|
||||
struct clk_hw *hw;
|
||||
unsigned int i;
|
||||
u32 r0, r1;
|
||||
u64 val;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < data->pll_count; i++) {
|
||||
pll = &data->plls[i];
|
||||
|
||||
val = readq(base + pll->reg64);
|
||||
r0 = val;
|
||||
r1 = val >> 32;
|
||||
|
||||
ret = eqc_pll_parse_registers(r0, r1, &mult, &div, &acc);
|
||||
if (ret) {
|
||||
dev_warn(dev, "failed parsing state of %s\n", pll->name);
|
||||
cells->hws[pll->index] = ERR_PTR(ret);
|
||||
continue;
|
||||
}
|
||||
|
||||
hw = clk_hw_register_fixed_factor_with_accuracy_fwname(dev,
|
||||
dev->of_node, pll->name, "ref", 0, mult, div, acc);
|
||||
cells->hws[pll->index] = hw;
|
||||
if (IS_ERR(hw))
|
||||
dev_warn(dev, "failed registering %s: %pe\n", pll->name, hw);
|
||||
}
|
||||
}
|
||||
|
||||
static void eqc_probe_init_divs(struct device *dev, const struct eqc_match_data *data,
|
||||
void __iomem *base, struct clk_hw_onecell_data *cells)
|
||||
{
|
||||
struct clk_parent_data parent_data = { };
|
||||
const struct eqc_div *div;
|
||||
struct clk_hw *parent;
|
||||
void __iomem *reg;
|
||||
struct clk_hw *hw;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < data->div_count; i++) {
|
||||
div = &data->divs[i];
|
||||
reg = base + div->reg;
|
||||
parent = cells->hws[div->parent];
|
||||
|
||||
if (IS_ERR(parent)) {
|
||||
/* Parent is in early clk provider. */
|
||||
parent_data.index = div->parent;
|
||||
parent_data.hw = NULL;
|
||||
} else {
|
||||
/* Avoid clock lookup when we already have the hw reference. */
|
||||
parent_data.index = 0;
|
||||
parent_data.hw = parent;
|
||||
}
|
||||
|
||||
hw = clk_hw_register_divider_table_parent_data(dev, div->name,
|
||||
&parent_data, 0, reg, div->shift, div->width,
|
||||
CLK_DIVIDER_EVEN_INTEGERS, NULL, NULL);
|
||||
cells->hws[div->index] = hw;
|
||||
if (IS_ERR(hw))
|
||||
dev_warn(dev, "failed registering %s: %pe\n",
|
||||
div->name, hw);
|
||||
}
|
||||
}
|
||||
|
||||
static void eqc_probe_init_fixed_factors(struct device *dev,
|
||||
const struct eqc_match_data *data,
|
||||
struct clk_hw_onecell_data *cells)
|
||||
{
|
||||
const struct eqc_fixed_factor *ff;
|
||||
struct clk_hw *hw, *parent_hw;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < data->fixed_factor_count; i++) {
|
||||
ff = &data->fixed_factors[i];
|
||||
parent_hw = cells->hws[ff->parent];
|
||||
|
||||
if (IS_ERR(parent_hw)) {
|
||||
/* Parent is in early clk provider. */
|
||||
hw = clk_hw_register_fixed_factor_index(dev, ff->name,
|
||||
ff->parent, 0, ff->mult, ff->div);
|
||||
} else {
|
||||
/* Avoid clock lookup when we already have the hw reference. */
|
||||
hw = clk_hw_register_fixed_factor_parent_hw(dev, ff->name,
|
||||
parent_hw, 0, ff->mult, ff->div);
|
||||
}
|
||||
|
||||
cells->hws[ff->index] = hw;
|
||||
if (IS_ERR(hw))
|
||||
dev_warn(dev, "failed registering %s: %pe\n",
|
||||
ff->name, hw);
|
||||
}
|
||||
}
|
||||
|
||||
static void eqc_auxdev_release(struct device *dev)
|
||||
{
|
||||
struct auxiliary_device *adev = to_auxiliary_dev(dev);
|
||||
|
||||
kfree(adev);
|
||||
}
|
||||
|
||||
static int eqc_auxdev_create(struct device *dev, void __iomem *base,
|
||||
const char *name, u32 id)
|
||||
{
|
||||
struct auxiliary_device *adev;
|
||||
int ret;
|
||||
|
||||
adev = kzalloc(sizeof(*adev), GFP_KERNEL);
|
||||
if (!adev)
|
||||
return -ENOMEM;
|
||||
|
||||
adev->name = name;
|
||||
adev->dev.parent = dev;
|
||||
adev->dev.platform_data = (void __force *)base;
|
||||
adev->dev.release = eqc_auxdev_release;
|
||||
adev->id = id;
|
||||
|
||||
ret = auxiliary_device_init(adev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = auxiliary_device_add(adev);
|
||||
if (ret)
|
||||
auxiliary_device_uninit(adev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int eqc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
const struct eqc_match_data *data;
|
||||
struct clk_hw_onecell_data *cells;
|
||||
unsigned int i, clk_count;
|
||||
struct resource *res;
|
||||
void __iomem *base;
|
||||
int ret;
|
||||
|
||||
data = device_get_match_data(dev);
|
||||
if (!data)
|
||||
return 0; /* No clocks nor auxdevs, we are done. */
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -ENODEV;
|
||||
|
||||
base = ioremap(res->start, resource_size(res));
|
||||
if (!base)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Init optional reset auxiliary device. */
|
||||
if (data->reset_auxdev_name) {
|
||||
ret = eqc_auxdev_create(dev, base, data->reset_auxdev_name, 0);
|
||||
if (ret)
|
||||
dev_warn(dev, "failed creating auxiliary device %s.%s: %d\n",
|
||||
KBUILD_MODNAME, data->reset_auxdev_name, ret);
|
||||
}
|
||||
|
||||
/* Init optional pinctrl auxiliary device. */
|
||||
if (data->pinctrl_auxdev_name) {
|
||||
ret = eqc_auxdev_create(dev, base, data->pinctrl_auxdev_name, 0);
|
||||
if (ret)
|
||||
dev_warn(dev, "failed creating auxiliary device %s.%s: %d\n",
|
||||
KBUILD_MODNAME, data->pinctrl_auxdev_name, ret);
|
||||
}
|
||||
|
||||
if (data->pll_count + data->div_count + data->fixed_factor_count == 0)
|
||||
return 0; /* Zero clocks, we are done. */
|
||||
|
||||
clk_count = data->pll_count + data->div_count +
|
||||
data->fixed_factor_count + data->early_clk_count;
|
||||
cells = kzalloc(struct_size(cells, hws, clk_count), GFP_KERNEL);
|
||||
if (!cells)
|
||||
return -ENOMEM;
|
||||
|
||||
cells->num = clk_count;
|
||||
|
||||
/* Early PLLs are marked as errors: the early provider will get queried. */
|
||||
for (i = 0; i < clk_count; i++)
|
||||
cells->hws[i] = ERR_PTR(-EINVAL);
|
||||
|
||||
eqc_probe_init_plls(dev, data, base, cells);
|
||||
|
||||
eqc_probe_init_divs(dev, data, base, cells);
|
||||
|
||||
eqc_probe_init_fixed_factors(dev, data, cells);
|
||||
|
||||
return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, cells);
|
||||
}
|
||||
|
||||
/* Required early for GIC timer (pll-cpu) and UARTs (pll-per). */
|
||||
static const struct eqc_pll eqc_eyeq5_early_plls[] = {
|
||||
{ .index = EQ5C_PLL_CPU, .name = "pll-cpu", .reg64 = 0x02C },
|
||||
{ .index = EQ5C_PLL_PER, .name = "pll-per", .reg64 = 0x05C },
|
||||
};
|
||||
|
||||
static const struct eqc_pll eqc_eyeq5_plls[] = {
|
||||
{ .index = EQ5C_PLL_VMP, .name = "pll-vmp", .reg64 = 0x034 },
|
||||
{ .index = EQ5C_PLL_PMA, .name = "pll-pma", .reg64 = 0x03C },
|
||||
{ .index = EQ5C_PLL_VDI, .name = "pll-vdi", .reg64 = 0x044 },
|
||||
{ .index = EQ5C_PLL_DDR0, .name = "pll-ddr0", .reg64 = 0x04C },
|
||||
{ .index = EQ5C_PLL_PCI, .name = "pll-pci", .reg64 = 0x054 },
|
||||
{ .index = EQ5C_PLL_PMAC, .name = "pll-pmac", .reg64 = 0x064 },
|
||||
{ .index = EQ5C_PLL_MPC, .name = "pll-mpc", .reg64 = 0x06C },
|
||||
{ .index = EQ5C_PLL_DDR1, .name = "pll-ddr1", .reg64 = 0x074 },
|
||||
};
|
||||
|
||||
enum {
|
||||
/*
|
||||
* EQ5C_PLL_CPU children.
|
||||
* EQ5C_PER_OCC_PCI is the last clock exposed in dt-bindings.
|
||||
*/
|
||||
EQ5C_CPU_OCC = EQ5C_PER_OCC_PCI + 1,
|
||||
EQ5C_CPU_SI_CSS0,
|
||||
EQ5C_CPU_CPC,
|
||||
EQ5C_CPU_CM,
|
||||
EQ5C_CPU_MEM,
|
||||
EQ5C_CPU_OCC_ISRAM,
|
||||
EQ5C_CPU_ISRAM,
|
||||
EQ5C_CPU_OCC_DBU,
|
||||
EQ5C_CPU_SI_DBU_TP,
|
||||
|
||||
/*
|
||||
* EQ5C_PLL_VDI children.
|
||||
*/
|
||||
EQ5C_VDI_OCC_VDI,
|
||||
EQ5C_VDI_VDI,
|
||||
EQ5C_VDI_OCC_CAN_SER,
|
||||
EQ5C_VDI_CAN_SER,
|
||||
EQ5C_VDI_I2C_SER,
|
||||
|
||||
/*
|
||||
* EQ5C_PLL_PER children.
|
||||
*/
|
||||
EQ5C_PER_PERIPH,
|
||||
EQ5C_PER_CAN,
|
||||
EQ5C_PER_TIMER,
|
||||
EQ5C_PER_CCF,
|
||||
EQ5C_PER_OCC_MJPEG,
|
||||
EQ5C_PER_HSM,
|
||||
EQ5C_PER_MJPEG,
|
||||
EQ5C_PER_FCMU_A,
|
||||
};
|
||||
|
||||
static const struct eqc_fixed_factor eqc_eyeq5_early_fixed_factors[] = {
|
||||
/* EQ5C_PLL_CPU children */
|
||||
{ EQ5C_CPU_OCC, "occ-cpu", 1, 1, EQ5C_PLL_CPU },
|
||||
{ EQ5C_CPU_SI_CSS0, "si-css0", 1, 1, EQ5C_CPU_OCC },
|
||||
{ EQ5C_CPU_CORE0, "core0", 1, 1, EQ5C_CPU_SI_CSS0 },
|
||||
{ EQ5C_CPU_CORE1, "core1", 1, 1, EQ5C_CPU_SI_CSS0 },
|
||||
{ EQ5C_CPU_CORE2, "core2", 1, 1, EQ5C_CPU_SI_CSS0 },
|
||||
{ EQ5C_CPU_CORE3, "core3", 1, 1, EQ5C_CPU_SI_CSS0 },
|
||||
|
||||
/* EQ5C_PLL_PER children */
|
||||
{ EQ5C_PER_OCC, "occ-periph", 1, 16, EQ5C_PLL_PER },
|
||||
{ EQ5C_PER_UART, "uart", 1, 1, EQ5C_PER_OCC },
|
||||
};
|
||||
|
||||
static const struct eqc_fixed_factor eqc_eyeq5_fixed_factors[] = {
|
||||
/* EQ5C_PLL_CPU children */
|
||||
{ EQ5C_CPU_CPC, "cpc", 1, 1, EQ5C_CPU_SI_CSS0 },
|
||||
{ EQ5C_CPU_CM, "cm", 1, 1, EQ5C_CPU_SI_CSS0 },
|
||||
{ EQ5C_CPU_MEM, "mem", 1, 1, EQ5C_CPU_SI_CSS0 },
|
||||
{ EQ5C_CPU_OCC_ISRAM, "occ-isram", 1, 2, EQ5C_PLL_CPU },
|
||||
{ EQ5C_CPU_ISRAM, "isram", 1, 1, EQ5C_CPU_OCC_ISRAM },
|
||||
{ EQ5C_CPU_OCC_DBU, "occ-dbu", 1, 10, EQ5C_PLL_CPU },
|
||||
{ EQ5C_CPU_SI_DBU_TP, "si-dbu-tp", 1, 1, EQ5C_CPU_OCC_DBU },
|
||||
|
||||
/* EQ5C_PLL_VDI children */
|
||||
{ EQ5C_VDI_OCC_VDI, "occ-vdi", 1, 2, EQ5C_PLL_VDI },
|
||||
{ EQ5C_VDI_VDI, "vdi", 1, 1, EQ5C_VDI_OCC_VDI },
|
||||
{ EQ5C_VDI_OCC_CAN_SER, "occ-can-ser", 1, 16, EQ5C_PLL_VDI },
|
||||
{ EQ5C_VDI_CAN_SER, "can-ser", 1, 1, EQ5C_VDI_OCC_CAN_SER },
|
||||
{ EQ5C_VDI_I2C_SER, "i2c-ser", 1, 20, EQ5C_PLL_VDI },
|
||||
|
||||
/* EQ5C_PLL_PER children */
|
||||
{ EQ5C_PER_PERIPH, "periph", 1, 1, EQ5C_PER_OCC },
|
||||
{ EQ5C_PER_CAN, "can", 1, 1, EQ5C_PER_OCC },
|
||||
{ EQ5C_PER_SPI, "spi", 1, 1, EQ5C_PER_OCC },
|
||||
{ EQ5C_PER_I2C, "i2c", 1, 1, EQ5C_PER_OCC },
|
||||
{ EQ5C_PER_TIMER, "timer", 1, 1, EQ5C_PER_OCC },
|
||||
{ EQ5C_PER_GPIO, "gpio", 1, 1, EQ5C_PER_OCC },
|
||||
{ EQ5C_PER_EMMC, "emmc-sys", 1, 10, EQ5C_PLL_PER },
|
||||
{ EQ5C_PER_CCF, "ccf-ctrl", 1, 4, EQ5C_PLL_PER },
|
||||
{ EQ5C_PER_OCC_MJPEG, "occ-mjpeg", 1, 2, EQ5C_PLL_PER },
|
||||
{ EQ5C_PER_HSM, "hsm", 1, 1, EQ5C_PER_OCC_MJPEG },
|
||||
{ EQ5C_PER_MJPEG, "mjpeg", 1, 1, EQ5C_PER_OCC_MJPEG },
|
||||
{ EQ5C_PER_FCMU_A, "fcmu-a", 1, 20, EQ5C_PLL_PER },
|
||||
{ EQ5C_PER_OCC_PCI, "occ-pci-sys", 1, 8, EQ5C_PLL_PER },
|
||||
};
|
||||
|
||||
static const struct eqc_div eqc_eyeq5_divs[] = {
|
||||
{
|
||||
.index = EQ5C_DIV_OSPI,
|
||||
.name = "div-ospi",
|
||||
.parent = EQ5C_PLL_PER,
|
||||
.reg = 0x11C,
|
||||
.shift = 0,
|
||||
.width = 4,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct eqc_early_match_data eqc_eyeq5_early_match_data __initconst = {
|
||||
.early_pll_count = ARRAY_SIZE(eqc_eyeq5_early_plls),
|
||||
.early_plls = eqc_eyeq5_early_plls,
|
||||
|
||||
.early_fixed_factor_count = ARRAY_SIZE(eqc_eyeq5_early_fixed_factors),
|
||||
.early_fixed_factors = eqc_eyeq5_early_fixed_factors,
|
||||
|
||||
.late_clk_count = ARRAY_SIZE(eqc_eyeq5_plls) + ARRAY_SIZE(eqc_eyeq5_divs) +
|
||||
ARRAY_SIZE(eqc_eyeq5_fixed_factors),
|
||||
};
|
||||
|
||||
static const struct eqc_match_data eqc_eyeq5_match_data = {
|
||||
.pll_count = ARRAY_SIZE(eqc_eyeq5_plls),
|
||||
.plls = eqc_eyeq5_plls,
|
||||
|
||||
.div_count = ARRAY_SIZE(eqc_eyeq5_divs),
|
||||
.divs = eqc_eyeq5_divs,
|
||||
|
||||
.fixed_factor_count = ARRAY_SIZE(eqc_eyeq5_fixed_factors),
|
||||
.fixed_factors = eqc_eyeq5_fixed_factors,
|
||||
|
||||
.reset_auxdev_name = "reset",
|
||||
.pinctrl_auxdev_name = "pinctrl",
|
||||
|
||||
.early_clk_count = ARRAY_SIZE(eqc_eyeq5_early_plls) +
|
||||
ARRAY_SIZE(eqc_eyeq5_early_fixed_factors),
|
||||
};
|
||||
|
||||
static const struct eqc_pll eqc_eyeq6l_plls[] = {
|
||||
{ .index = EQ6LC_PLL_DDR, .name = "pll-ddr", .reg64 = 0x02C },
|
||||
{ .index = EQ6LC_PLL_CPU, .name = "pll-cpu", .reg64 = 0x034 }, /* also acc */
|
||||
{ .index = EQ6LC_PLL_PER, .name = "pll-per", .reg64 = 0x03C },
|
||||
{ .index = EQ6LC_PLL_VDI, .name = "pll-vdi", .reg64 = 0x044 },
|
||||
};
|
||||
|
||||
static const struct eqc_match_data eqc_eyeq6l_match_data = {
|
||||
.pll_count = ARRAY_SIZE(eqc_eyeq6l_plls),
|
||||
.plls = eqc_eyeq6l_plls,
|
||||
|
||||
.reset_auxdev_name = "reset",
|
||||
};
|
||||
|
||||
static const struct eqc_match_data eqc_eyeq6h_west_match_data = {
|
||||
.reset_auxdev_name = "reset_west",
|
||||
};
|
||||
|
||||
static const struct eqc_pll eqc_eyeq6h_east_plls[] = {
|
||||
{ .index = 0, .name = "pll-east", .reg64 = 0x074 },
|
||||
};
|
||||
|
||||
static const struct eqc_match_data eqc_eyeq6h_east_match_data = {
|
||||
.pll_count = ARRAY_SIZE(eqc_eyeq6h_east_plls),
|
||||
.plls = eqc_eyeq6h_east_plls,
|
||||
|
||||
.reset_auxdev_name = "reset_east",
|
||||
};
|
||||
|
||||
static const struct eqc_pll eqc_eyeq6h_south_plls[] = {
|
||||
{ .index = EQ6HC_SOUTH_PLL_VDI, .name = "pll-vdi", .reg64 = 0x000 },
|
||||
{ .index = EQ6HC_SOUTH_PLL_PCIE, .name = "pll-pcie", .reg64 = 0x008 },
|
||||
{ .index = EQ6HC_SOUTH_PLL_PER, .name = "pll-per", .reg64 = 0x010 },
|
||||
{ .index = EQ6HC_SOUTH_PLL_ISP, .name = "pll-isp", .reg64 = 0x018 },
|
||||
};
|
||||
|
||||
static const struct eqc_div eqc_eyeq6h_south_divs[] = {
|
||||
{
|
||||
.index = EQ6HC_SOUTH_DIV_EMMC,
|
||||
.name = "div-emmc",
|
||||
.parent = EQ6HC_SOUTH_PLL_PER,
|
||||
.reg = 0x070,
|
||||
.shift = 4,
|
||||
.width = 4,
|
||||
},
|
||||
{
|
||||
.index = EQ6HC_SOUTH_DIV_OSPI_REF,
|
||||
.name = "div-ospi-ref",
|
||||
.parent = EQ6HC_SOUTH_PLL_PER,
|
||||
.reg = 0x090,
|
||||
.shift = 4,
|
||||
.width = 4,
|
||||
},
|
||||
{
|
||||
.index = EQ6HC_SOUTH_DIV_OSPI_SYS,
|
||||
.name = "div-ospi-sys",
|
||||
.parent = EQ6HC_SOUTH_PLL_PER,
|
||||
.reg = 0x090,
|
||||
.shift = 8,
|
||||
.width = 1,
|
||||
},
|
||||
{
|
||||
.index = EQ6HC_SOUTH_DIV_TSU,
|
||||
.name = "div-tsu",
|
||||
.parent = EQ6HC_SOUTH_PLL_PCIE,
|
||||
.reg = 0x098,
|
||||
.shift = 4,
|
||||
.width = 8,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct eqc_match_data eqc_eyeq6h_south_match_data = {
|
||||
.pll_count = ARRAY_SIZE(eqc_eyeq6h_south_plls),
|
||||
.plls = eqc_eyeq6h_south_plls,
|
||||
|
||||
.div_count = ARRAY_SIZE(eqc_eyeq6h_south_divs),
|
||||
.divs = eqc_eyeq6h_south_divs,
|
||||
};
|
||||
|
||||
static const struct eqc_pll eqc_eyeq6h_ddr0_plls[] = {
|
||||
{ .index = 0, .name = "pll-ddr0", .reg64 = 0x074 },
|
||||
};
|
||||
|
||||
static const struct eqc_match_data eqc_eyeq6h_ddr0_match_data = {
|
||||
.pll_count = ARRAY_SIZE(eqc_eyeq6h_ddr0_plls),
|
||||
.plls = eqc_eyeq6h_ddr0_plls,
|
||||
};
|
||||
|
||||
static const struct eqc_pll eqc_eyeq6h_ddr1_plls[] = {
|
||||
{ .index = 0, .name = "pll-ddr1", .reg64 = 0x074 },
|
||||
};
|
||||
|
||||
static const struct eqc_match_data eqc_eyeq6h_ddr1_match_data = {
|
||||
.pll_count = ARRAY_SIZE(eqc_eyeq6h_ddr1_plls),
|
||||
.plls = eqc_eyeq6h_ddr1_plls,
|
||||
};
|
||||
|
||||
static const struct eqc_pll eqc_eyeq6h_acc_plls[] = {
|
||||
{ .index = EQ6HC_ACC_PLL_XNN, .name = "pll-xnn", .reg64 = 0x040 },
|
||||
{ .index = EQ6HC_ACC_PLL_VMP, .name = "pll-vmp", .reg64 = 0x050 },
|
||||
{ .index = EQ6HC_ACC_PLL_PMA, .name = "pll-pma", .reg64 = 0x05C },
|
||||
{ .index = EQ6HC_ACC_PLL_MPC, .name = "pll-mpc", .reg64 = 0x068 },
|
||||
{ .index = EQ6HC_ACC_PLL_NOC, .name = "pll-noc", .reg64 = 0x070 },
|
||||
};
|
||||
|
||||
static const struct eqc_match_data eqc_eyeq6h_acc_match_data = {
|
||||
.pll_count = ARRAY_SIZE(eqc_eyeq6h_acc_plls),
|
||||
.plls = eqc_eyeq6h_acc_plls,
|
||||
|
||||
.reset_auxdev_name = "reset_acc",
|
||||
};
|
||||
|
||||
static const struct of_device_id eqc_match_table[] = {
|
||||
{ .compatible = "mobileye,eyeq5-olb", .data = &eqc_eyeq5_match_data },
|
||||
{ .compatible = "mobileye,eyeq6l-olb", .data = &eqc_eyeq6l_match_data },
|
||||
{ .compatible = "mobileye,eyeq6h-west-olb", .data = &eqc_eyeq6h_west_match_data },
|
||||
{ .compatible = "mobileye,eyeq6h-east-olb", .data = &eqc_eyeq6h_east_match_data },
|
||||
{ .compatible = "mobileye,eyeq6h-south-olb", .data = &eqc_eyeq6h_south_match_data },
|
||||
{ .compatible = "mobileye,eyeq6h-ddr0-olb", .data = &eqc_eyeq6h_ddr0_match_data },
|
||||
{ .compatible = "mobileye,eyeq6h-ddr1-olb", .data = &eqc_eyeq6h_ddr1_match_data },
|
||||
{ .compatible = "mobileye,eyeq6h-acc-olb", .data = &eqc_eyeq6h_acc_match_data },
|
||||
{}
|
||||
};
|
||||
|
||||
static struct platform_driver eqc_driver = {
|
||||
.probe = eqc_probe,
|
||||
.driver = {
|
||||
.name = "clk-eyeq",
|
||||
.of_match_table = eqc_match_table,
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
};
|
||||
builtin_platform_driver(eqc_driver);
|
||||
|
||||
/* Required early for GIC timer. */
|
||||
static const struct eqc_pll eqc_eyeq6h_central_early_plls[] = {
|
||||
{ .index = EQ6HC_CENTRAL_PLL_CPU, .name = "pll-cpu", .reg64 = 0x02C },
|
||||
};
|
||||
|
||||
static const struct eqc_fixed_factor eqc_eyeq6h_central_early_fixed_factors[] = {
|
||||
{ EQ6HC_CENTRAL_CPU_OCC, "occ-cpu", 1, 1, EQ6HC_CENTRAL_PLL_CPU },
|
||||
};
|
||||
|
||||
static const struct eqc_early_match_data eqc_eyeq6h_central_early_match_data __initconst = {
|
||||
.early_pll_count = ARRAY_SIZE(eqc_eyeq6h_central_early_plls),
|
||||
.early_plls = eqc_eyeq6h_central_early_plls,
|
||||
|
||||
.early_fixed_factor_count = ARRAY_SIZE(eqc_eyeq6h_central_early_fixed_factors),
|
||||
.early_fixed_factors = eqc_eyeq6h_central_early_fixed_factors,
|
||||
};
|
||||
|
||||
/* Required early for UART. */
|
||||
static const struct eqc_pll eqc_eyeq6h_west_early_plls[] = {
|
||||
{ .index = EQ6HC_WEST_PLL_PER, .name = "pll-west", .reg64 = 0x074 },
|
||||
};
|
||||
|
||||
static const struct eqc_fixed_factor eqc_eyeq6h_west_early_fixed_factors[] = {
|
||||
{ EQ6HC_WEST_PER_OCC, "west-per-occ", 1, 10, EQ6HC_WEST_PLL_PER },
|
||||
{ EQ6HC_WEST_PER_UART, "west-per-uart", 1, 1, EQ6HC_WEST_PER_OCC },
|
||||
};
|
||||
|
||||
static const struct eqc_early_match_data eqc_eyeq6h_west_early_match_data __initconst = {
|
||||
.early_pll_count = ARRAY_SIZE(eqc_eyeq6h_west_early_plls),
|
||||
.early_plls = eqc_eyeq6h_west_early_plls,
|
||||
|
||||
.early_fixed_factor_count = ARRAY_SIZE(eqc_eyeq6h_west_early_fixed_factors),
|
||||
.early_fixed_factors = eqc_eyeq6h_west_early_fixed_factors,
|
||||
};
|
||||
|
||||
static void __init eqc_early_init(struct device_node *np,
|
||||
const struct eqc_early_match_data *early_data)
|
||||
{
|
||||
struct clk_hw_onecell_data *cells;
|
||||
unsigned int i, clk_count;
|
||||
void __iomem *base;
|
||||
int ret;
|
||||
|
||||
clk_count = early_data->early_pll_count + early_data->early_fixed_factor_count +
|
||||
early_data->late_clk_count;
|
||||
cells = kzalloc(struct_size(cells, hws, clk_count), GFP_KERNEL);
|
||||
if (!cells) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
cells->num = clk_count;
|
||||
|
||||
/*
|
||||
* Mark all clocks as deferred; some are registered here, the rest at
|
||||
* platform device probe.
|
||||
*
|
||||
* Once the platform device is probed, its provider will take priority
|
||||
* when looking up clocks.
|
||||
*/
|
||||
for (i = 0; i < clk_count; i++)
|
||||
cells->hws[i] = ERR_PTR(-EPROBE_DEFER);
|
||||
|
||||
/* Offsets (reg64) of early PLLs are relative to OLB block. */
|
||||
base = of_iomap(np, 0);
|
||||
if (!base) {
|
||||
ret = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (i = 0; i < early_data->early_pll_count; i++) {
|
||||
const struct eqc_pll *pll = &early_data->early_plls[i];
|
||||
unsigned long mult, div, acc;
|
||||
struct clk_hw *hw;
|
||||
u32 r0, r1;
|
||||
u64 val;
|
||||
|
||||
val = readq(base + pll->reg64);
|
||||
r0 = val;
|
||||
r1 = val >> 32;
|
||||
|
||||
ret = eqc_pll_parse_registers(r0, r1, &mult, &div, &acc);
|
||||
if (ret) {
|
||||
pr_err("failed parsing state of %s\n", pll->name);
|
||||
goto err;
|
||||
}
|
||||
|
||||
hw = clk_hw_register_fixed_factor_with_accuracy_fwname(NULL,
|
||||
np, pll->name, "ref", 0, mult, div, acc);
|
||||
cells->hws[pll->index] = hw;
|
||||
if (IS_ERR(hw)) {
|
||||
pr_err("failed registering %s: %pe\n", pll->name, hw);
|
||||
ret = PTR_ERR(hw);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < early_data->early_fixed_factor_count; i++) {
|
||||
const struct eqc_fixed_factor *ff = &early_data->early_fixed_factors[i];
|
||||
struct clk_hw *parent_hw = cells->hws[ff->parent];
|
||||
struct clk_hw *hw;
|
||||
|
||||
hw = clk_hw_register_fixed_factor_parent_hw(NULL, ff->name,
|
||||
parent_hw, 0, ff->mult, ff->div);
|
||||
cells->hws[ff->index] = hw;
|
||||
if (IS_ERR(hw)) {
|
||||
pr_err("failed registering %s: %pe\n", ff->name, hw);
|
||||
ret = PTR_ERR(hw);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, cells);
|
||||
if (ret) {
|
||||
pr_err("failed registering clk provider: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
err:
|
||||
/*
|
||||
* We are doomed. The system will not be able to boot.
|
||||
*
|
||||
* Let's still try to be good citizens by freeing resources and print
|
||||
* a last error message that might help debugging.
|
||||
*/
|
||||
|
||||
pr_err("failed clk init: %d\n", ret);
|
||||
|
||||
if (cells) {
|
||||
of_clk_del_provider(np);
|
||||
|
||||
for (i = 0; i < early_data->early_pll_count; i++) {
|
||||
const struct eqc_pll *pll = &early_data->early_plls[i];
|
||||
struct clk_hw *hw = cells->hws[pll->index];
|
||||
|
||||
if (!IS_ERR_OR_NULL(hw))
|
||||
clk_hw_unregister_fixed_factor(hw);
|
||||
}
|
||||
|
||||
kfree(cells);
|
||||
}
|
||||
}
|
||||
|
||||
static void __init eqc_eyeq5_early_init(struct device_node *np)
|
||||
{
|
||||
eqc_early_init(np, &eqc_eyeq5_early_match_data);
|
||||
}
|
||||
CLK_OF_DECLARE_DRIVER(eqc_eyeq5, "mobileye,eyeq5-olb", eqc_eyeq5_early_init);
|
||||
|
||||
static void __init eqc_eyeq6h_central_early_init(struct device_node *np)
|
||||
{
|
||||
eqc_early_init(np, &eqc_eyeq6h_central_early_match_data);
|
||||
}
|
||||
CLK_OF_DECLARE_DRIVER(eqc_eyeq6h_central, "mobileye,eyeq6h-central-olb",
|
||||
eqc_eyeq6h_central_early_init);
|
||||
|
||||
static void __init eqc_eyeq6h_west_early_init(struct device_node *np)
|
||||
{
|
||||
eqc_early_init(np, &eqc_eyeq6h_west_early_match_data);
|
||||
}
|
||||
CLK_OF_DECLARE_DRIVER(eqc_eyeq6h_west, "mobileye,eyeq6h-west-olb",
|
||||
eqc_eyeq6h_west_early_init);
|
|
@ -241,6 +241,17 @@ struct clk_hw *clk_hw_register_fixed_factor_with_accuracy_fwname(struct device *
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(clk_hw_register_fixed_factor_with_accuracy_fwname);
|
||||
|
||||
struct clk_hw *clk_hw_register_fixed_factor_index(struct device *dev,
|
||||
const char *name, unsigned int index, unsigned long flags,
|
||||
unsigned int mult, unsigned int div)
|
||||
{
|
||||
const struct clk_parent_data pdata = { .index = index };
|
||||
|
||||
return __clk_hw_register_fixed_factor(dev, NULL, name, NULL, NULL, &pdata,
|
||||
flags, mult, div, 0, 0, false);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_hw_register_fixed_factor_index);
|
||||
|
||||
struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
|
||||
const char *parent_name, unsigned long flags,
|
||||
unsigned int mult, unsigned int div)
|
||||
|
|
430
drivers/clk/clk-npcm8xx.c
Normal file
430
drivers/clk/clk-npcm8xx.c
Normal file
|
@ -0,0 +1,430 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Nuvoton NPCM8xx Clock Generator
|
||||
* All the clocks are initialized by the bootloader, so this driver allows only
|
||||
* reading of current settings directly from the hardware.
|
||||
*
|
||||
* Copyright (C) 2020 Nuvoton Technologies
|
||||
* Author: Tomer Maimon <tomer.maimon@nuvoton.com>
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "npcm8xx_clk: " fmt
|
||||
|
||||
#include <linux/auxiliary_bus.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <dt-bindings/clock/nuvoton,npcm845-clk.h>
|
||||
#include <soc/nuvoton/clock-npcm8xx.h>
|
||||
|
||||
/* npcm8xx clock registers*/
|
||||
#define NPCM8XX_CLKSEL 0x04
|
||||
#define NPCM8XX_CLKDIV1 0x08
|
||||
#define NPCM8XX_CLKDIV2 0x2C
|
||||
#define NPCM8XX_CLKDIV3 0x58
|
||||
#define NPCM8XX_CLKDIV4 0x7C
|
||||
#define NPCM8XX_PLLCON0 0x0C
|
||||
#define NPCM8XX_PLLCON1 0x10
|
||||
#define NPCM8XX_PLLCON2 0x54
|
||||
#define NPCM8XX_PLLCONG 0x60
|
||||
#define NPCM8XX_THRTL_CNT 0xC0
|
||||
|
||||
#define PLLCON_LOKI BIT(31)
|
||||
#define PLLCON_LOKS BIT(30)
|
||||
#define PLLCON_FBDV GENMASK(27, 16)
|
||||
#define PLLCON_OTDV2 GENMASK(15, 13)
|
||||
#define PLLCON_PWDEN BIT(12)
|
||||
#define PLLCON_OTDV1 GENMASK(10, 8)
|
||||
#define PLLCON_INDV GENMASK(5, 0)
|
||||
|
||||
static void __iomem *clk_base;
|
||||
|
||||
struct npcm8xx_clk_pll {
|
||||
void __iomem *pllcon;
|
||||
unsigned int id;
|
||||
const char *name;
|
||||
unsigned long flags;
|
||||
struct clk_hw hw;
|
||||
};
|
||||
|
||||
#define to_npcm8xx_clk_pll(_hw) container_of(_hw, struct npcm8xx_clk_pll, hw)
|
||||
|
||||
struct npcm8xx_clk_pll_data {
|
||||
const char *name;
|
||||
struct clk_parent_data parent;
|
||||
unsigned int reg;
|
||||
unsigned long flags;
|
||||
struct clk_hw hw;
|
||||
};
|
||||
|
||||
struct npcm8xx_clk_div_data {
|
||||
u32 reg;
|
||||
u8 shift;
|
||||
u8 width;
|
||||
const char *name;
|
||||
const struct clk_hw *parent_hw;
|
||||
unsigned long clk_divider_flags;
|
||||
unsigned long flags;
|
||||
int onecell_idx;
|
||||
struct clk_hw hw;
|
||||
};
|
||||
|
||||
struct npcm8xx_clk_mux_data {
|
||||
u8 shift;
|
||||
u32 mask;
|
||||
const u32 *table;
|
||||
const char *name;
|
||||
const struct clk_parent_data *parent_data;
|
||||
u8 num_parents;
|
||||
unsigned long flags;
|
||||
struct clk_hw hw;
|
||||
};
|
||||
|
||||
static struct clk_hw hw_pll1_div2, hw_pll2_div2, hw_gfx_div2, hw_pre_clk;
|
||||
static struct npcm8xx_clk_pll_data npcm8xx_pll_clks[] = {
|
||||
{ "pll0", { .index = 0 }, NPCM8XX_PLLCON0, 0 },
|
||||
{ "pll1", { .index = 0 }, NPCM8XX_PLLCON1, 0 },
|
||||
{ "pll2", { .index = 0 }, NPCM8XX_PLLCON2, 0 },
|
||||
{ "pll_gfx", { .index = 0 }, NPCM8XX_PLLCONG, 0 },
|
||||
};
|
||||
|
||||
static const u32 cpuck_mux_table[] = { 0, 1, 2, 7 };
|
||||
static const struct clk_parent_data cpuck_mux_parents[] = {
|
||||
{ .hw = &npcm8xx_pll_clks[0].hw },
|
||||
{ .hw = &npcm8xx_pll_clks[1].hw },
|
||||
{ .index = 0 },
|
||||
{ .hw = &npcm8xx_pll_clks[2].hw }
|
||||
};
|
||||
|
||||
static const u32 pixcksel_mux_table[] = { 0, 2 };
|
||||
static const struct clk_parent_data pixcksel_mux_parents[] = {
|
||||
{ .hw = &npcm8xx_pll_clks[3].hw },
|
||||
{ .index = 0 }
|
||||
};
|
||||
|
||||
static const u32 default_mux_table[] = { 0, 1, 2, 3 };
|
||||
static const struct clk_parent_data default_mux_parents[] = {
|
||||
{ .hw = &npcm8xx_pll_clks[0].hw },
|
||||
{ .hw = &npcm8xx_pll_clks[1].hw },
|
||||
{ .index = 0 },
|
||||
{ .hw = &hw_pll2_div2 }
|
||||
};
|
||||
|
||||
static const u32 sucksel_mux_table[] = { 2, 3 };
|
||||
static const struct clk_parent_data sucksel_mux_parents[] = {
|
||||
{ .index = 0 },
|
||||
{ .hw = &hw_pll2_div2 }
|
||||
};
|
||||
|
||||
static const u32 mccksel_mux_table[] = { 0, 2 };
|
||||
static const struct clk_parent_data mccksel_mux_parents[] = {
|
||||
{ .hw = &hw_pll1_div2 },
|
||||
{ .index = 0 }
|
||||
};
|
||||
|
||||
static const u32 clkoutsel_mux_table[] = { 0, 1, 2, 3, 4 };
|
||||
static const struct clk_parent_data clkoutsel_mux_parents[] = {
|
||||
{ .hw = &npcm8xx_pll_clks[0].hw },
|
||||
{ .hw = &npcm8xx_pll_clks[1].hw },
|
||||
{ .index = 0 },
|
||||
{ .hw = &hw_gfx_div2 },
|
||||
{ .hw = &hw_pll2_div2 }
|
||||
};
|
||||
|
||||
static const u32 gfxmsel_mux_table[] = { 2, 3 };
|
||||
static const struct clk_parent_data gfxmsel_mux_parents[] = {
|
||||
{ .index = 0 },
|
||||
{ .hw = &npcm8xx_pll_clks[2].hw }
|
||||
};
|
||||
|
||||
static const u32 dvcssel_mux_table[] = { 2, 3 };
|
||||
static const struct clk_parent_data dvcssel_mux_parents[] = {
|
||||
{ .index = 0 },
|
||||
{ .hw = &npcm8xx_pll_clks[2].hw }
|
||||
};
|
||||
|
||||
static const u32 default3_mux_table[] = { 0, 1, 2 };
|
||||
static const struct clk_parent_data default3_mux_parents[] = {
|
||||
{ .hw = &npcm8xx_pll_clks[0].hw },
|
||||
{ .hw = &npcm8xx_pll_clks[1].hw },
|
||||
{ .index = 0 }
|
||||
};
|
||||
|
||||
static struct npcm8xx_clk_mux_data npcm8xx_muxes[] = {
|
||||
{ 0, 3, cpuck_mux_table, "cpu_mux", cpuck_mux_parents,
|
||||
ARRAY_SIZE(cpuck_mux_parents), CLK_IS_CRITICAL },
|
||||
{ 4, 2, pixcksel_mux_table, "gfx_pixel_mux", pixcksel_mux_parents,
|
||||
ARRAY_SIZE(pixcksel_mux_parents), 0 },
|
||||
{ 6, 2, default_mux_table, "sd_mux", default_mux_parents,
|
||||
ARRAY_SIZE(default_mux_parents), 0 },
|
||||
{ 8, 2, default_mux_table, "uart_mux", default_mux_parents,
|
||||
ARRAY_SIZE(default_mux_parents), 0 },
|
||||
{ 10, 2, sucksel_mux_table, "serial_usb_mux", sucksel_mux_parents,
|
||||
ARRAY_SIZE(sucksel_mux_parents), 0 },
|
||||
{ 12, 2, mccksel_mux_table, "mc_mux", mccksel_mux_parents,
|
||||
ARRAY_SIZE(mccksel_mux_parents), 0 },
|
||||
{ 14, 2, default_mux_table, "adc_mux", default_mux_parents,
|
||||
ARRAY_SIZE(default_mux_parents), 0 },
|
||||
{ 16, 2, default_mux_table, "gfx_mux", default_mux_parents,
|
||||
ARRAY_SIZE(default_mux_parents), 0 },
|
||||
{ 18, 3, clkoutsel_mux_table, "clkout_mux", clkoutsel_mux_parents,
|
||||
ARRAY_SIZE(clkoutsel_mux_parents), 0 },
|
||||
{ 21, 2, gfxmsel_mux_table, "gfxm_mux", gfxmsel_mux_parents,
|
||||
ARRAY_SIZE(gfxmsel_mux_parents), 0 },
|
||||
{ 23, 2, dvcssel_mux_table, "dvc_mux", dvcssel_mux_parents,
|
||||
ARRAY_SIZE(dvcssel_mux_parents), 0 },
|
||||
{ 25, 2, default3_mux_table, "rg_mux", default3_mux_parents,
|
||||
ARRAY_SIZE(default3_mux_parents), 0 },
|
||||
{ 27, 2, default3_mux_table, "rcp_mux", default3_mux_parents,
|
||||
ARRAY_SIZE(default3_mux_parents), 0 },
|
||||
};
|
||||
|
||||
/* configurable pre dividers: */
|
||||
static struct npcm8xx_clk_div_data npcm8xx_pre_divs[] = {
|
||||
{ NPCM8XX_CLKDIV1, 21, 5, "pre_adc", &npcm8xx_muxes[6].hw, CLK_DIVIDER_READ_ONLY, 0, -1 },
|
||||
{ NPCM8XX_CLKDIV1, 26, 2, "ahb", &hw_pre_clk, CLK_DIVIDER_READ_ONLY, CLK_IS_CRITICAL, NPCM8XX_CLK_AHB },
|
||||
};
|
||||
|
||||
/* configurable dividers: */
|
||||
static struct npcm8xx_clk_div_data npcm8xx_divs[] = {
|
||||
{ NPCM8XX_CLKDIV1, 28, 3, "adc", &npcm8xx_pre_divs[0].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_ADC },
|
||||
{ NPCM8XX_CLKDIV1, 16, 5, "uart", &npcm8xx_muxes[3].hw, 0, 0, NPCM8XX_CLK_UART },
|
||||
{ NPCM8XX_CLKDIV1, 11, 5, "mmc", &npcm8xx_muxes[2].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_MMC },
|
||||
{ NPCM8XX_CLKDIV1, 6, 5, "spi3", &npcm8xx_pre_divs[1].hw, 0, 0, NPCM8XX_CLK_SPI3 },
|
||||
{ NPCM8XX_CLKDIV1, 2, 4, "pci", &npcm8xx_muxes[7].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_PCI },
|
||||
|
||||
{ NPCM8XX_CLKDIV2, 30, 2, "apb4", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_APB4 },
|
||||
{ NPCM8XX_CLKDIV2, 28, 2, "apb3", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_APB3 },
|
||||
{ NPCM8XX_CLKDIV2, 26, 2, "apb2", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_APB2 },
|
||||
{ NPCM8XX_CLKDIV2, 24, 2, "apb1", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_APB1 },
|
||||
{ NPCM8XX_CLKDIV2, 22, 2, "apb5", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_APB5 },
|
||||
{ NPCM8XX_CLKDIV2, 16, 5, "clkout", &npcm8xx_muxes[8].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_CLKOUT },
|
||||
{ NPCM8XX_CLKDIV2, 13, 3, "gfx", &npcm8xx_muxes[7].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_GFX },
|
||||
{ NPCM8XX_CLKDIV2, 8, 5, "usb_bridge", &npcm8xx_muxes[4].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_SU },
|
||||
{ NPCM8XX_CLKDIV2, 4, 4, "usb_host", &npcm8xx_muxes[4].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_SU48 },
|
||||
{ NPCM8XX_CLKDIV2, 0, 4, "sdhc", &npcm8xx_muxes[2].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_SDHC },
|
||||
|
||||
{ NPCM8XX_CLKDIV3, 16, 8, "spi1", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_SPI1 },
|
||||
{ NPCM8XX_CLKDIV3, 11, 5, "uart2", &npcm8xx_muxes[3].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_UART2 },
|
||||
{ NPCM8XX_CLKDIV3, 6, 5, "spi0", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_SPI0 },
|
||||
{ NPCM8XX_CLKDIV3, 1, 5, "spix", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_SPIX },
|
||||
|
||||
{ NPCM8XX_CLKDIV4, 28, 4, "rg", &npcm8xx_muxes[11].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_RG },
|
||||
{ NPCM8XX_CLKDIV4, 12, 4, "rcp", &npcm8xx_muxes[12].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_RCP },
|
||||
|
||||
{ NPCM8XX_THRTL_CNT, 0, 2, "th", &npcm8xx_muxes[0].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_TH },
|
||||
};
|
||||
|
||||
static unsigned long npcm8xx_clk_pll_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct npcm8xx_clk_pll *pll = to_npcm8xx_clk_pll(hw);
|
||||
unsigned long fbdv, indv, otdv1, otdv2;
|
||||
unsigned int val;
|
||||
u64 ret;
|
||||
|
||||
if (parent_rate == 0) {
|
||||
pr_debug("%s: parent rate is zero\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
val = readl_relaxed(pll->pllcon);
|
||||
|
||||
indv = FIELD_GET(PLLCON_INDV, val);
|
||||
fbdv = FIELD_GET(PLLCON_FBDV, val);
|
||||
otdv1 = FIELD_GET(PLLCON_OTDV1, val);
|
||||
otdv2 = FIELD_GET(PLLCON_OTDV2, val);
|
||||
|
||||
ret = (u64)parent_rate * fbdv;
|
||||
do_div(ret, indv * otdv1 * otdv2);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct clk_ops npcm8xx_clk_pll_ops = {
|
||||
.recalc_rate = npcm8xx_clk_pll_recalc_rate,
|
||||
};
|
||||
|
||||
static struct clk_hw *
|
||||
npcm8xx_clk_register_pll(struct device *dev, void __iomem *pllcon,
|
||||
const char *name, const struct clk_parent_data *parent,
|
||||
unsigned long flags)
|
||||
{
|
||||
struct npcm8xx_clk_pll *pll;
|
||||
struct clk_init_data init = {};
|
||||
int ret;
|
||||
|
||||
pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL);
|
||||
if (!pll)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init.name = name;
|
||||
init.ops = &npcm8xx_clk_pll_ops;
|
||||
init.parent_data = parent;
|
||||
init.num_parents = 1;
|
||||
init.flags = flags;
|
||||
|
||||
pll->pllcon = pllcon;
|
||||
pll->hw.init = &init;
|
||||
|
||||
ret = devm_clk_hw_register(dev, &pll->hw);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return &pll->hw;
|
||||
}
|
||||
|
||||
static DEFINE_SPINLOCK(npcm8xx_clk_lock);
|
||||
|
||||
static int npcm8xx_clk_probe(struct auxiliary_device *adev,
|
||||
const struct auxiliary_device_id *id)
|
||||
{
|
||||
struct npcm_clock_adev *rdev = to_npcm_clock_adev(adev);
|
||||
struct clk_hw_onecell_data *npcm8xx_clk_data;
|
||||
struct device *dev = &adev->dev;
|
||||
struct clk_hw *hw;
|
||||
unsigned int i;
|
||||
|
||||
npcm8xx_clk_data = devm_kzalloc(dev, struct_size(npcm8xx_clk_data, hws,
|
||||
NPCM8XX_NUM_CLOCKS),
|
||||
GFP_KERNEL);
|
||||
if (!npcm8xx_clk_data)
|
||||
return -ENOMEM;
|
||||
|
||||
clk_base = rdev->base;
|
||||
|
||||
npcm8xx_clk_data->num = NPCM8XX_NUM_CLOCKS;
|
||||
|
||||
for (i = 0; i < NPCM8XX_NUM_CLOCKS; i++)
|
||||
npcm8xx_clk_data->hws[i] = ERR_PTR(-EPROBE_DEFER);
|
||||
|
||||
/* Register plls */
|
||||
for (i = 0; i < ARRAY_SIZE(npcm8xx_pll_clks); i++) {
|
||||
struct npcm8xx_clk_pll_data *pll_clk = &npcm8xx_pll_clks[i];
|
||||
|
||||
hw = npcm8xx_clk_register_pll(dev, clk_base + pll_clk->reg,
|
||||
pll_clk->name, &pll_clk->parent,
|
||||
pll_clk->flags);
|
||||
if (IS_ERR(hw))
|
||||
return dev_err_probe(dev, PTR_ERR(hw), "Can't register pll\n");
|
||||
pll_clk->hw = *hw;
|
||||
}
|
||||
|
||||
/* Register fixed dividers */
|
||||
hw = devm_clk_hw_register_fixed_factor(dev, "pll1_div2", "pll1", 0, 1, 2);
|
||||
if (IS_ERR(hw))
|
||||
return dev_err_probe(dev, PTR_ERR(hw), "Can't register fixed div\n");
|
||||
hw_pll1_div2 = *hw;
|
||||
|
||||
hw = devm_clk_hw_register_fixed_factor(dev, "pll2_div2", "pll2", 0, 1, 2);
|
||||
if (IS_ERR(hw))
|
||||
return dev_err_probe(dev, PTR_ERR(hw), "Can't register pll2 div2\n");
|
||||
hw_pll2_div2 = *hw;
|
||||
|
||||
hw = devm_clk_hw_register_fixed_factor(dev, "pll_gfx_div2", "pll_gfx", 0, 1, 2);
|
||||
if (IS_ERR(hw))
|
||||
return dev_err_probe(dev, PTR_ERR(hw), "Can't register gfx div2\n");
|
||||
hw_gfx_div2 = *hw;
|
||||
|
||||
/* Register muxes */
|
||||
for (i = 0; i < ARRAY_SIZE(npcm8xx_muxes); i++) {
|
||||
struct npcm8xx_clk_mux_data *mux_data = &npcm8xx_muxes[i];
|
||||
|
||||
hw = devm_clk_hw_register_mux_parent_data_table(dev,
|
||||
mux_data->name,
|
||||
mux_data->parent_data,
|
||||
mux_data->num_parents,
|
||||
mux_data->flags,
|
||||
clk_base + NPCM8XX_CLKSEL,
|
||||
mux_data->shift,
|
||||
mux_data->mask,
|
||||
0,
|
||||
mux_data->table,
|
||||
&npcm8xx_clk_lock);
|
||||
if (IS_ERR(hw))
|
||||
return dev_err_probe(dev, PTR_ERR(hw), "Can't register mux\n");
|
||||
mux_data->hw = *hw;
|
||||
}
|
||||
|
||||
hw = devm_clk_hw_register_fixed_factor(dev, "pre_clk", "cpu_mux", 0, 1, 2);
|
||||
if (IS_ERR(hw))
|
||||
return dev_err_probe(dev, PTR_ERR(hw), "Can't register pre clk div2\n");
|
||||
hw_pre_clk = *hw;
|
||||
|
||||
hw = devm_clk_hw_register_fixed_factor(dev, "axi", "th", 0, 1, 2);
|
||||
if (IS_ERR(hw))
|
||||
return dev_err_probe(dev, PTR_ERR(hw), "Can't register axi div2\n");
|
||||
npcm8xx_clk_data->hws[NPCM8XX_CLK_AXI] = hw;
|
||||
|
||||
hw = devm_clk_hw_register_fixed_factor(dev, "atb", "axi", 0, 1, 2);
|
||||
if (IS_ERR(hw))
|
||||
return dev_err_probe(dev, PTR_ERR(hw), "Can't register atb div2\n");
|
||||
npcm8xx_clk_data->hws[NPCM8XX_CLK_ATB] = hw;
|
||||
|
||||
/* Register pre dividers */
|
||||
for (i = 0; i < ARRAY_SIZE(npcm8xx_pre_divs); i++) {
|
||||
struct npcm8xx_clk_div_data *div_data = &npcm8xx_pre_divs[i];
|
||||
|
||||
hw = devm_clk_hw_register_divider_parent_hw(dev, div_data->name,
|
||||
div_data->parent_hw,
|
||||
div_data->flags,
|
||||
clk_base + div_data->reg,
|
||||
div_data->shift,
|
||||
div_data->width,
|
||||
div_data->clk_divider_flags,
|
||||
&npcm8xx_clk_lock);
|
||||
if (IS_ERR(hw))
|
||||
return dev_err_probe(dev, PTR_ERR(hw), "Can't register pre div\n");
|
||||
div_data->hw = *hw;
|
||||
|
||||
if (div_data->onecell_idx >= 0)
|
||||
npcm8xx_clk_data->hws[div_data->onecell_idx] = hw;
|
||||
}
|
||||
|
||||
/* Register dividers */
|
||||
for (i = 0; i < ARRAY_SIZE(npcm8xx_divs); i++) {
|
||||
struct npcm8xx_clk_div_data *div_data = &npcm8xx_divs[i];
|
||||
|
||||
hw = devm_clk_hw_register_divider_parent_hw(dev, div_data->name,
|
||||
div_data->parent_hw,
|
||||
div_data->flags,
|
||||
clk_base + div_data->reg,
|
||||
div_data->shift,
|
||||
div_data->width,
|
||||
div_data->clk_divider_flags,
|
||||
&npcm8xx_clk_lock);
|
||||
if (IS_ERR(hw))
|
||||
return dev_err_probe(dev, PTR_ERR(hw), "Can't register div\n");
|
||||
|
||||
if (div_data->onecell_idx >= 0)
|
||||
npcm8xx_clk_data->hws[div_data->onecell_idx] = hw;
|
||||
}
|
||||
|
||||
return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
|
||||
npcm8xx_clk_data);
|
||||
}
|
||||
|
||||
static const struct auxiliary_device_id npcm8xx_clock_ids[] = {
|
||||
{
|
||||
.name = "reset_npcm.clk-npcm8xx",
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(auxiliary, npcm8xx_clock_ids);
|
||||
|
||||
static struct auxiliary_driver npcm8xx_clock_driver = {
|
||||
.probe = npcm8xx_clk_probe,
|
||||
.id_table = npcm8xx_clock_ids,
|
||||
};
|
||||
module_auxiliary_driver(npcm8xx_clock_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Clock driver for Nuvoton NPCM8XX BMC SoC");
|
||||
MODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
@ -11,13 +11,29 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define VREG_STATE 2
|
||||
#define VREG_STATE 2
|
||||
#define VREG_GRP 0
|
||||
#define TWL6030_CFG_STATE_OFF 0x00
|
||||
#define TWL6030_CFG_STATE_ON 0x01
|
||||
#define TWL6030_CFG_STATE_MASK 0x03
|
||||
#define TWL6030_CFG_STATE_GRP_SHIFT 5
|
||||
#define TWL6030_CFG_STATE_APP_SHIFT 2
|
||||
#define TWL6030_CFG_STATE_APP_MASK (0x03 << TWL6030_CFG_STATE_APP_SHIFT)
|
||||
#define TWL6030_CFG_STATE_APP(v) (((v) & TWL6030_CFG_STATE_APP_MASK) >>\
|
||||
TWL6030_CFG_STATE_APP_SHIFT)
|
||||
#define P1_GRP BIT(0) /* processor power group */
|
||||
#define P2_GRP BIT(1)
|
||||
#define P3_GRP BIT(2)
|
||||
#define ALL_GRP (P1_GRP | P2_GRP | P3_GRP)
|
||||
|
||||
enum twl_type {
|
||||
TWL_TYPE_6030,
|
||||
TWL_TYPE_6032,
|
||||
};
|
||||
|
||||
struct twl_clock_info {
|
||||
struct device *dev;
|
||||
enum twl_type type;
|
||||
u8 base;
|
||||
struct clk_hw hw;
|
||||
};
|
||||
|
@ -56,14 +72,21 @@ static unsigned long twl_clks_recalc_rate(struct clk_hw *hw,
|
|||
static int twl6032_clks_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct twl_clock_info *cinfo = to_twl_clks_info(hw);
|
||||
int ret;
|
||||
|
||||
ret = twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE,
|
||||
TWL6030_CFG_STATE_ON);
|
||||
if (ret < 0)
|
||||
dev_err(cinfo->dev, "clk prepare failed\n");
|
||||
if (cinfo->type == TWL_TYPE_6030) {
|
||||
int grp;
|
||||
|
||||
return ret;
|
||||
grp = twlclk_read(cinfo, TWL_MODULE_PM_RECEIVER, VREG_GRP);
|
||||
if (grp < 0)
|
||||
return grp;
|
||||
|
||||
return twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE,
|
||||
grp << TWL6030_CFG_STATE_GRP_SHIFT |
|
||||
TWL6030_CFG_STATE_ON);
|
||||
}
|
||||
|
||||
return twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE,
|
||||
TWL6030_CFG_STATE_ON);
|
||||
}
|
||||
|
||||
static void twl6032_clks_unprepare(struct clk_hw *hw)
|
||||
|
@ -71,32 +94,21 @@ static void twl6032_clks_unprepare(struct clk_hw *hw)
|
|||
struct twl_clock_info *cinfo = to_twl_clks_info(hw);
|
||||
int ret;
|
||||
|
||||
ret = twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE,
|
||||
TWL6030_CFG_STATE_OFF);
|
||||
if (cinfo->type == TWL_TYPE_6030)
|
||||
ret = twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE,
|
||||
ALL_GRP << TWL6030_CFG_STATE_GRP_SHIFT |
|
||||
TWL6030_CFG_STATE_OFF);
|
||||
else
|
||||
ret = twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE,
|
||||
TWL6030_CFG_STATE_OFF);
|
||||
|
||||
if (ret < 0)
|
||||
dev_err(cinfo->dev, "clk unprepare failed\n");
|
||||
}
|
||||
|
||||
static int twl6032_clks_is_prepared(struct clk_hw *hw)
|
||||
{
|
||||
struct twl_clock_info *cinfo = to_twl_clks_info(hw);
|
||||
int val;
|
||||
|
||||
val = twlclk_read(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE);
|
||||
if (val < 0) {
|
||||
dev_err(cinfo->dev, "clk read failed\n");
|
||||
return val;
|
||||
}
|
||||
|
||||
val &= TWL6030_CFG_STATE_MASK;
|
||||
|
||||
return val == TWL6030_CFG_STATE_ON;
|
||||
}
|
||||
|
||||
static const struct clk_ops twl6032_clks_ops = {
|
||||
.prepare = twl6032_clks_prepare,
|
||||
.unprepare = twl6032_clks_unprepare,
|
||||
.is_prepared = twl6032_clks_is_prepared,
|
||||
.recalc_rate = twl_clks_recalc_rate,
|
||||
};
|
||||
|
||||
|
@ -155,6 +167,7 @@ static int twl_clks_probe(struct platform_device *pdev)
|
|||
for (i = 0; i < count; i++) {
|
||||
cinfo[i].base = hw_data[i].base;
|
||||
cinfo[i].dev = &pdev->dev;
|
||||
cinfo[i].type = platform_get_device_id(pdev)->driver_data;
|
||||
cinfo[i].hw.init = &hw_data[i].init;
|
||||
ret = devm_clk_hw_register(&pdev->dev, &cinfo[i].hw);
|
||||
if (ret) {
|
||||
|
@ -176,7 +189,11 @@ static int twl_clks_probe(struct platform_device *pdev)
|
|||
|
||||
static const struct platform_device_id twl_clks_id[] = {
|
||||
{
|
||||
.name = "twl6030-clk",
|
||||
.driver_data = TWL_TYPE_6030,
|
||||
}, {
|
||||
.name = "twl6032-clk",
|
||||
.driver_data = TWL_TYPE_6032,
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
|
|
|
@ -237,6 +237,11 @@ config CLK_RZV2H
|
|||
bool "RZ/V2H(P) family clock support" if COMPILE_TEST
|
||||
select RESET_CONTROLLER
|
||||
|
||||
config CLK_RENESAS_VBATTB
|
||||
tristate "Renesas VBATTB clock controller"
|
||||
depends on ARCH_RZG2L || COMPILE_TEST
|
||||
select RESET_CONTROLLER
|
||||
|
||||
# Generic
|
||||
config CLK_RENESAS_CPG_MSSR
|
||||
bool "CPG/MSSR clock support" if COMPILE_TEST
|
||||
|
|
|
@ -53,3 +53,4 @@ obj-$(CONFIG_CLK_RZV2H) += rzv2h-cpg.o
|
|||
obj-$(CONFIG_CLK_RENESAS_CPG_MSSR) += renesas-cpg-mssr.o
|
||||
obj-$(CONFIG_CLK_RENESAS_CPG_MSTP) += clk-mstp.o
|
||||
obj-$(CONFIG_CLK_RENESAS_DIV6) += clk-div6.o
|
||||
obj-$(CONFIG_CLK_RENESAS_VBATTB) += clk-vbattb.o
|
||||
|
|
|
@ -64,7 +64,6 @@ r8a73a4_cpg_register_clock(struct device_node *np, struct r8a73a4_cpg *cpg,
|
|||
unsigned int mult = 1;
|
||||
unsigned int div = 1;
|
||||
|
||||
|
||||
if (!strcmp(name, "main")) {
|
||||
u32 ckscr = readl(base + CPG_CKSCR);
|
||||
|
||||
|
|
|
@ -67,7 +67,6 @@ r8a7778_cpg_register_clock(struct device_node *np, const char *name)
|
|||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
|
||||
static void __init r8a7778_cpg_clocks_init(struct device_node *np)
|
||||
{
|
||||
struct clk_onecell_data *data;
|
||||
|
|
205
drivers/clk/renesas/clk-vbattb.c
Normal file
205
drivers/clk/renesas/clk-vbattb.c
Normal file
|
@ -0,0 +1,205 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* VBATTB clock driver
|
||||
*
|
||||
* Copyright (C) 2024 Renesas Electronics Corp.
|
||||
*/
|
||||
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#include <dt-bindings/clock/renesas,r9a08g045-vbattb.h>
|
||||
|
||||
#define VBATTB_BKSCCR 0x1c
|
||||
#define VBATTB_BKSCCR_SOSEL 6
|
||||
#define VBATTB_SOSCCR2 0x24
|
||||
#define VBATTB_SOSCCR2_SOSTP2 0
|
||||
#define VBATTB_XOSCCR 0x30
|
||||
#define VBATTB_XOSCCR_OUTEN 16
|
||||
#define VBATTB_XOSCCR_XSEL GENMASK(1, 0)
|
||||
#define VBATTB_XOSCCR_XSEL_4_PF 0x0
|
||||
#define VBATTB_XOSCCR_XSEL_7_PF 0x1
|
||||
#define VBATTB_XOSCCR_XSEL_9_PF 0x2
|
||||
#define VBATTB_XOSCCR_XSEL_12_5_PF 0x3
|
||||
|
||||
/**
|
||||
* struct vbattb_clk - VBATTB clock data structure
|
||||
* @base: base address
|
||||
* @lock: lock
|
||||
*/
|
||||
struct vbattb_clk {
|
||||
void __iomem *base;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
static int vbattb_clk_validate_load_capacitance(u32 *reg_lc, u32 of_lc)
|
||||
{
|
||||
switch (of_lc) {
|
||||
case 4000:
|
||||
*reg_lc = VBATTB_XOSCCR_XSEL_4_PF;
|
||||
break;
|
||||
case 7000:
|
||||
*reg_lc = VBATTB_XOSCCR_XSEL_7_PF;
|
||||
break;
|
||||
case 9000:
|
||||
*reg_lc = VBATTB_XOSCCR_XSEL_9_PF;
|
||||
break;
|
||||
case 12500:
|
||||
*reg_lc = VBATTB_XOSCCR_XSEL_12_5_PF;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vbattb_clk_action(void *data)
|
||||
{
|
||||
struct device *dev = data;
|
||||
struct reset_control *rstc = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = reset_control_assert(rstc);
|
||||
if (ret)
|
||||
dev_err(dev, "Failed to de-assert reset!");
|
||||
|
||||
ret = pm_runtime_put_sync(dev);
|
||||
if (ret < 0)
|
||||
dev_err(dev, "Failed to runtime suspend!");
|
||||
|
||||
of_clk_del_provider(dev->of_node);
|
||||
}
|
||||
|
||||
static int vbattb_clk_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct clk_parent_data parent_data = {};
|
||||
struct clk_hw_onecell_data *clk_data;
|
||||
const struct clk_hw *parent_hws[2];
|
||||
struct device *dev = &pdev->dev;
|
||||
struct reset_control *rstc;
|
||||
struct vbattb_clk *vbclk;
|
||||
u32 of_lc, reg_lc;
|
||||
struct clk_hw *hw;
|
||||
/* 4 clocks are exported: VBATTB_XC, VBATTB_XBYP, VBATTB_MUX, VBATTB_VBATTCLK. */
|
||||
u8 num_clks = 4;
|
||||
int ret;
|
||||
|
||||
/* Default to 4pF as this is not needed if external clock device is connected. */
|
||||
of_lc = 4000;
|
||||
of_property_read_u32(np, "quartz-load-femtofarads", &of_lc);
|
||||
|
||||
ret = vbattb_clk_validate_load_capacitance(®_lc, of_lc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
vbclk = devm_kzalloc(dev, sizeof(*vbclk), GFP_KERNEL);
|
||||
if (!vbclk)
|
||||
return -ENOMEM;
|
||||
|
||||
clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, num_clks), GFP_KERNEL);
|
||||
if (!clk_data)
|
||||
return -ENOMEM;
|
||||
clk_data->num = num_clks;
|
||||
|
||||
vbclk->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(vbclk->base))
|
||||
return PTR_ERR(vbclk->base);
|
||||
|
||||
ret = devm_pm_runtime_enable(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rstc = devm_reset_control_get_shared(dev, NULL);
|
||||
if (IS_ERR(rstc))
|
||||
return PTR_ERR(rstc);
|
||||
|
||||
ret = pm_runtime_resume_and_get(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = reset_control_deassert(rstc);
|
||||
if (ret) {
|
||||
pm_runtime_put_sync(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_set_drvdata(dev, rstc);
|
||||
ret = devm_add_action_or_reset(dev, vbattb_clk_action, dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
spin_lock_init(&vbclk->lock);
|
||||
|
||||
parent_data.fw_name = "rtx";
|
||||
hw = devm_clk_hw_register_gate_parent_data(dev, "xc", &parent_data, 0,
|
||||
vbclk->base + VBATTB_SOSCCR2,
|
||||
VBATTB_SOSCCR2_SOSTP2,
|
||||
CLK_GATE_SET_TO_DISABLE, &vbclk->lock);
|
||||
if (IS_ERR(hw))
|
||||
return PTR_ERR(hw);
|
||||
clk_data->hws[VBATTB_XC] = hw;
|
||||
|
||||
hw = devm_clk_hw_register_fixed_factor_fwname(dev, np, "xbyp", "rtx", 0, 1, 1);
|
||||
if (IS_ERR(hw))
|
||||
return PTR_ERR(hw);
|
||||
clk_data->hws[VBATTB_XBYP] = hw;
|
||||
|
||||
parent_hws[0] = clk_data->hws[VBATTB_XC];
|
||||
parent_hws[1] = clk_data->hws[VBATTB_XBYP];
|
||||
hw = devm_clk_hw_register_mux_parent_hws(dev, "mux", parent_hws, 2, 0,
|
||||
vbclk->base + VBATTB_BKSCCR,
|
||||
VBATTB_BKSCCR_SOSEL,
|
||||
1, 0, &vbclk->lock);
|
||||
if (IS_ERR(hw))
|
||||
return PTR_ERR(hw);
|
||||
clk_data->hws[VBATTB_MUX] = hw;
|
||||
|
||||
/* Set load capacitance before registering the VBATTCLK clock. */
|
||||
scoped_guard(spinlock, &vbclk->lock) {
|
||||
u32 val = readl_relaxed(vbclk->base + VBATTB_XOSCCR);
|
||||
|
||||
val &= ~VBATTB_XOSCCR_XSEL;
|
||||
val |= reg_lc;
|
||||
writel_relaxed(val, vbclk->base + VBATTB_XOSCCR);
|
||||
}
|
||||
|
||||
/* This feeds the RTC counter clock and it needs to stay on. */
|
||||
hw = devm_clk_hw_register_gate_parent_hw(dev, "vbattclk", hw, CLK_IS_CRITICAL,
|
||||
vbclk->base + VBATTB_XOSCCR,
|
||||
VBATTB_XOSCCR_OUTEN, 0,
|
||||
&vbclk->lock);
|
||||
|
||||
if (IS_ERR(hw))
|
||||
return PTR_ERR(hw);
|
||||
clk_data->hws[VBATTB_VBATTCLK] = hw;
|
||||
|
||||
return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
|
||||
}
|
||||
|
||||
static const struct of_device_id vbattb_clk_match[] = {
|
||||
{ .compatible = "renesas,r9a08g045-vbattb" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, vbattb_clk_match);
|
||||
|
||||
static struct platform_driver vbattb_clk_driver = {
|
||||
.driver = {
|
||||
.name = "renesas-vbattb-clk",
|
||||
.of_match_table = vbattb_clk_match,
|
||||
},
|
||||
.probe = vbattb_clk_probe,
|
||||
};
|
||||
module_platform_driver(vbattb_clk_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Renesas VBATTB Clock Driver");
|
||||
MODULE_AUTHOR("Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -266,7 +266,6 @@ static const struct rcar_gen4_cpg_pll_config cpg_pll_configs[4] __initconst = {
|
|||
{ 2, 128, 1, 192, 1, 32, },
|
||||
};
|
||||
|
||||
|
||||
static int __init r8a779a0_cpg_mssr_init(struct device *dev)
|
||||
{
|
||||
const struct rcar_gen4_cpg_pll_config *cpg_pll_config;
|
||||
|
|
|
@ -37,7 +37,6 @@ enum clk_ids {
|
|||
CLK_PLL5,
|
||||
CLK_PLL6,
|
||||
CLK_PLL1_DIV2,
|
||||
CLK_PLL2_DIV2,
|
||||
CLK_PLL3_DIV2,
|
||||
CLK_PLL4_DIV2,
|
||||
CLK_PLL4_DIV5,
|
||||
|
@ -78,7 +77,6 @@ static const struct cpg_core_clk r8a779h0_core_clks[] __initconst = {
|
|||
DEF_GEN4_PLL_V8_25(".pll6", 6, CLK_PLL6, CLK_MAIN),
|
||||
|
||||
DEF_FIXED(".pll1_div2", CLK_PLL1_DIV2, CLK_PLL1, 2, 1),
|
||||
DEF_FIXED(".pll2_div2", CLK_PLL2_DIV2, CLK_PLL2, 2, 1),
|
||||
DEF_FIXED(".pll3_div2", CLK_PLL3_DIV2, CLK_PLL3, 2, 1),
|
||||
DEF_FIXED(".pll4_div2", CLK_PLL4_DIV2, CLK_PLL4, 2, 1),
|
||||
DEF_FIXED(".pll4_div5", CLK_PLL4_DIV5, CLK_PLL4, 5, 1),
|
||||
|
@ -101,10 +99,10 @@ static const struct cpg_core_clk r8a779h0_core_clks[] __initconst = {
|
|||
DEF_RATE(".oco", CLK_OCO, 32768),
|
||||
|
||||
/* Core Clock Outputs */
|
||||
DEF_GEN4_Z("zc0", R8A779H0_CLK_ZC0, CLK_TYPE_GEN4_Z, CLK_PLL2_DIV2, 2, 0),
|
||||
DEF_GEN4_Z("zc1", R8A779H0_CLK_ZC1, CLK_TYPE_GEN4_Z, CLK_PLL2_DIV2, 2, 8),
|
||||
DEF_GEN4_Z("zc2", R8A779H0_CLK_ZC2, CLK_TYPE_GEN4_Z, CLK_PLL2_DIV2, 2, 32),
|
||||
DEF_GEN4_Z("zc3", R8A779H0_CLK_ZC3, CLK_TYPE_GEN4_Z, CLK_PLL2_DIV2, 2, 40),
|
||||
DEF_GEN4_Z("zc0", R8A779H0_CLK_ZC0, CLK_TYPE_GEN4_Z, CLK_PLL2, 4, 0),
|
||||
DEF_GEN4_Z("zc1", R8A779H0_CLK_ZC1, CLK_TYPE_GEN4_Z, CLK_PLL2, 4, 8),
|
||||
DEF_GEN4_Z("zc2", R8A779H0_CLK_ZC2, CLK_TYPE_GEN4_Z, CLK_PLL2, 4, 32),
|
||||
DEF_GEN4_Z("zc3", R8A779H0_CLK_ZC3, CLK_TYPE_GEN4_Z, CLK_PLL2, 4, 40),
|
||||
DEF_FIXED("s0d2", R8A779H0_CLK_S0D2, CLK_S0, 2, 1),
|
||||
DEF_FIXED("s0d3", R8A779H0_CLK_S0D3, CLK_S0, 3, 1),
|
||||
DEF_FIXED("s0d4", R8A779H0_CLK_S0D4, CLK_S0, 4, 1),
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/pm_domain.h>
|
||||
|
||||
#include <dt-bindings/clock/r9a08g045-cpg.h>
|
||||
|
||||
|
@ -266,61 +267,50 @@ static const struct rzg2l_cpg_pm_domain_init_data r9a08g045_pm_domains[] = {
|
|||
/* Keep always-on domain on the first position for proper domains registration. */
|
||||
DEF_PD("always-on", R9A08G045_PD_ALWAYS_ON,
|
||||
DEF_REG_CONF(0, 0),
|
||||
RZG2L_PD_F_ALWAYS_ON),
|
||||
GENPD_FLAG_ALWAYS_ON | GENPD_FLAG_IRQ_SAFE),
|
||||
DEF_PD("gic", R9A08G045_PD_GIC,
|
||||
DEF_REG_CONF(CPG_BUS_ACPU_MSTOP, BIT(3)),
|
||||
RZG2L_PD_F_ALWAYS_ON),
|
||||
GENPD_FLAG_ALWAYS_ON),
|
||||
DEF_PD("ia55", R9A08G045_PD_IA55,
|
||||
DEF_REG_CONF(CPG_BUS_PERI_CPU_MSTOP, BIT(13)),
|
||||
RZG2L_PD_F_ALWAYS_ON),
|
||||
GENPD_FLAG_ALWAYS_ON),
|
||||
DEF_PD("dmac", R9A08G045_PD_DMAC,
|
||||
DEF_REG_CONF(CPG_BUS_REG1_MSTOP, GENMASK(3, 0)),
|
||||
RZG2L_PD_F_ALWAYS_ON),
|
||||
GENPD_FLAG_ALWAYS_ON),
|
||||
DEF_PD("wdt0", R9A08G045_PD_WDT0,
|
||||
DEF_REG_CONF(CPG_BUS_REG0_MSTOP, BIT(0)),
|
||||
RZG2L_PD_F_NONE),
|
||||
GENPD_FLAG_IRQ_SAFE),
|
||||
DEF_PD("sdhi0", R9A08G045_PD_SDHI0,
|
||||
DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(0)),
|
||||
RZG2L_PD_F_NONE),
|
||||
DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(0)), 0),
|
||||
DEF_PD("sdhi1", R9A08G045_PD_SDHI1,
|
||||
DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(1)),
|
||||
RZG2L_PD_F_NONE),
|
||||
DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(1)), 0),
|
||||
DEF_PD("sdhi2", R9A08G045_PD_SDHI2,
|
||||
DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(11)),
|
||||
RZG2L_PD_F_NONE),
|
||||
DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(11)), 0),
|
||||
DEF_PD("usb0", R9A08G045_PD_USB0,
|
||||
DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, GENMASK(6, 5)),
|
||||
RZG2L_PD_F_NONE),
|
||||
DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, GENMASK(6, 5)), 0),
|
||||
DEF_PD("usb1", R9A08G045_PD_USB1,
|
||||
DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(7)),
|
||||
RZG2L_PD_F_NONE),
|
||||
DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(7)), 0),
|
||||
DEF_PD("usb-phy", R9A08G045_PD_USB_PHY,
|
||||
DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(4)),
|
||||
RZG2L_PD_F_NONE),
|
||||
DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(4)), 0),
|
||||
DEF_PD("eth0", R9A08G045_PD_ETHER0,
|
||||
DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(2)),
|
||||
RZG2L_PD_F_NONE),
|
||||
DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(2)), 0),
|
||||
DEF_PD("eth1", R9A08G045_PD_ETHER1,
|
||||
DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(3)),
|
||||
RZG2L_PD_F_NONE),
|
||||
DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(3)), 0),
|
||||
DEF_PD("i2c0", R9A08G045_PD_I2C0,
|
||||
DEF_REG_CONF(CPG_BUS_MCPU2_MSTOP, BIT(10)),
|
||||
RZG2L_PD_F_NONE),
|
||||
DEF_REG_CONF(CPG_BUS_MCPU2_MSTOP, BIT(10)), 0),
|
||||
DEF_PD("i2c1", R9A08G045_PD_I2C1,
|
||||
DEF_REG_CONF(CPG_BUS_MCPU2_MSTOP, BIT(11)),
|
||||
RZG2L_PD_F_NONE),
|
||||
DEF_REG_CONF(CPG_BUS_MCPU2_MSTOP, BIT(11)), 0),
|
||||
DEF_PD("i2c2", R9A08G045_PD_I2C2,
|
||||
DEF_REG_CONF(CPG_BUS_MCPU2_MSTOP, BIT(12)),
|
||||
RZG2L_PD_F_NONE),
|
||||
DEF_REG_CONF(CPG_BUS_MCPU2_MSTOP, BIT(12)), 0),
|
||||
DEF_PD("i2c3", R9A08G045_PD_I2C3,
|
||||
DEF_REG_CONF(CPG_BUS_MCPU2_MSTOP, BIT(13)),
|
||||
RZG2L_PD_F_NONE),
|
||||
DEF_REG_CONF(CPG_BUS_MCPU2_MSTOP, BIT(13)), 0),
|
||||
DEF_PD("scif0", R9A08G045_PD_SCIF0,
|
||||
DEF_REG_CONF(CPG_BUS_MCPU2_MSTOP, BIT(1)),
|
||||
RZG2L_PD_F_NONE),
|
||||
DEF_REG_CONF(CPG_BUS_MCPU2_MSTOP, BIT(1)), 0),
|
||||
DEF_PD("vbat", R9A08G045_PD_VBAT,
|
||||
DEF_REG_CONF(CPG_BUS_MCPU3_MSTOP, BIT(8)),
|
||||
RZG2L_PD_F_ALWAYS_ON),
|
||||
GENPD_FLAG_ALWAYS_ON),
|
||||
DEF_PD("rtc", R9A08G045_PD_RTC,
|
||||
DEF_REG_CONF(CPG_BUS_MCPU3_MSTOP, BIT(7)), 0),
|
||||
};
|
||||
|
||||
const struct rzg2l_cpg_info r9a08g045_cpg_info = {
|
||||
|
|
|
@ -98,7 +98,6 @@ static const struct clk_div_table dtable_divd[] = {
|
|||
{0, 0},
|
||||
};
|
||||
|
||||
|
||||
static const struct clk_div_table dtable_divw[] = {
|
||||
{0, 6},
|
||||
{1, 7},
|
||||
|
|
|
@ -41,6 +41,14 @@ enum clk_ids {
|
|||
MOD_CLK_BASE,
|
||||
};
|
||||
|
||||
static const struct clk_div_table dtable_1_8[] = {
|
||||
{0, 1},
|
||||
{1, 2},
|
||||
{2, 4},
|
||||
{3, 8},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
static const struct clk_div_table dtable_2_64[] = {
|
||||
{0, 2},
|
||||
{1, 4},
|
||||
|
@ -74,10 +82,19 @@ static const struct cpg_core_clk r9a09g057_core_clks[] __initconst = {
|
|||
|
||||
/* Core Clocks */
|
||||
DEF_FIXED("sys_0_pclk", R9A09G057_SYS_0_PCLK, CLK_QEXTAL, 1, 1),
|
||||
DEF_DDIV("ca55_0_coreclk0", R9A09G057_CA55_0_CORE_CLK0, CLK_PLLCA55,
|
||||
CDDIV1_DIVCTL0, dtable_1_8),
|
||||
DEF_DDIV("ca55_0_coreclk1", R9A09G057_CA55_0_CORE_CLK1, CLK_PLLCA55,
|
||||
CDDIV1_DIVCTL1, dtable_1_8),
|
||||
DEF_DDIV("ca55_0_coreclk2", R9A09G057_CA55_0_CORE_CLK2, CLK_PLLCA55,
|
||||
CDDIV1_DIVCTL2, dtable_1_8),
|
||||
DEF_DDIV("ca55_0_coreclk3", R9A09G057_CA55_0_CORE_CLK3, CLK_PLLCA55,
|
||||
CDDIV1_DIVCTL3, dtable_1_8),
|
||||
DEF_FIXED("iotop_0_shclk", R9A09G057_IOTOP_0_SHCLK, CLK_PLLCM33_DIV16, 1, 1),
|
||||
};
|
||||
|
||||
static const struct rzv2h_mod_clk r9a09g057_mod_clks[] __initconst = {
|
||||
DEF_MOD_CRITICAL("icu_0_pclk_i", CLK_PLLCM33_DIV16, 0, 5, 0, 5),
|
||||
DEF_MOD("gtm_0_pclk", CLK_PLLCM33_DIV16, 4, 3, 2, 3),
|
||||
DEF_MOD("gtm_1_pclk", CLK_PLLCM33_DIV16, 4, 4, 2, 4),
|
||||
DEF_MOD("gtm_2_pclk", CLK_PLLCLN_DIV16, 4, 5, 2, 5),
|
||||
|
@ -119,6 +136,7 @@ static const struct rzv2h_mod_clk r9a09g057_mod_clks[] __initconst = {
|
|||
};
|
||||
|
||||
static const struct rzv2h_reset r9a09g057_resets[] __initconst = {
|
||||
DEF_RST(3, 6, 1, 7), /* ICU_0_PRESETN_I */
|
||||
DEF_RST(6, 13, 2, 30), /* GTM_0_PRESETZ */
|
||||
DEF_RST(6, 14, 2, 31), /* GTM_1_PRESETZ */
|
||||
DEF_RST(6, 15, 3, 0), /* GTM_2_PRESETZ */
|
||||
|
|
|
@ -206,4 +206,3 @@ struct clk * __init cpg_rpcd2_clk_register(const char *name,
|
|||
|
||||
return clk;
|
||||
}
|
||||
|
||||
|
|
|
@ -335,7 +335,6 @@ static u32 cpg_quirks __initdata;
|
|||
|
||||
#define RCKCR_CKSEL BIT(1) /* Manual RCLK parent selection */
|
||||
|
||||
|
||||
static const struct soc_device_attribute cpg_quirks_match[] __initconst = {
|
||||
{
|
||||
.soc_id = "r8a7796", .revision = "ES1.0",
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
#define WARN_DEBUG(x) do { } while (0)
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Module Standby and Software Reset register offets.
|
||||
*
|
||||
|
@ -716,7 +715,6 @@ static inline int cpg_mssr_reset_controller_register(struct cpg_mssr_priv *priv)
|
|||
}
|
||||
#endif /* !CONFIG_RESET_CONTROLLER */
|
||||
|
||||
|
||||
static const struct of_device_id cpg_mssr_match[] = {
|
||||
#ifdef CONFIG_CLK_R7S9210
|
||||
{
|
||||
|
|
|
@ -548,7 +548,7 @@ static unsigned long
|
|||
rzg2l_cpg_get_foutpostdiv_rate(struct rzg2l_pll5_param *params,
|
||||
unsigned long rate)
|
||||
{
|
||||
unsigned long foutpostdiv_rate;
|
||||
unsigned long foutpostdiv_rate, foutvco_rate;
|
||||
|
||||
params->pl5_intin = rate / MEGA;
|
||||
params->pl5_fracin = div_u64(((u64)rate % MEGA) << 24, MEGA);
|
||||
|
@ -557,10 +557,11 @@ rzg2l_cpg_get_foutpostdiv_rate(struct rzg2l_pll5_param *params,
|
|||
params->pl5_postdiv2 = 1;
|
||||
params->pl5_spread = 0x16;
|
||||
|
||||
foutpostdiv_rate =
|
||||
EXTAL_FREQ_IN_MEGA_HZ * MEGA / params->pl5_refdiv *
|
||||
((((params->pl5_intin << 24) + params->pl5_fracin)) >> 24) /
|
||||
(params->pl5_postdiv1 * params->pl5_postdiv2);
|
||||
foutvco_rate = div_u64(mul_u32_u32(EXTAL_FREQ_IN_MEGA_HZ * MEGA,
|
||||
(params->pl5_intin << 24) + params->pl5_fracin),
|
||||
params->pl5_refdiv) >> 24;
|
||||
foutpostdiv_rate = DIV_ROUND_CLOSEST_ULL(foutvco_rate,
|
||||
params->pl5_postdiv1 * params->pl5_postdiv2);
|
||||
|
||||
return foutpostdiv_rate;
|
||||
}
|
||||
|
@ -1680,23 +1681,31 @@ static int rzg2l_cpg_power_off(struct generic_pm_domain *domain)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __init rzg2l_cpg_pd_setup(struct rzg2l_cpg_pd *pd, bool always_on)
|
||||
static int __init rzg2l_cpg_pd_setup(struct rzg2l_cpg_pd *pd)
|
||||
{
|
||||
bool always_on = !!(pd->genpd.flags & GENPD_FLAG_ALWAYS_ON);
|
||||
struct dev_power_governor *governor;
|
||||
int ret;
|
||||
|
||||
if (always_on)
|
||||
governor = &pm_domain_always_on_gov;
|
||||
else
|
||||
governor = &simple_qos_governor;
|
||||
|
||||
pd->genpd.flags |= GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP;
|
||||
pd->genpd.attach_dev = rzg2l_cpg_attach_dev;
|
||||
pd->genpd.detach_dev = rzg2l_cpg_detach_dev;
|
||||
if (always_on) {
|
||||
pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON;
|
||||
governor = &pm_domain_always_on_gov;
|
||||
} else {
|
||||
pd->genpd.power_on = rzg2l_cpg_power_on;
|
||||
pd->genpd.power_off = rzg2l_cpg_power_off;
|
||||
governor = &simple_qos_governor;
|
||||
}
|
||||
pd->genpd.power_on = rzg2l_cpg_power_on;
|
||||
pd->genpd.power_off = rzg2l_cpg_power_off;
|
||||
|
||||
return pm_genpd_init(&pd->genpd, governor, !always_on);
|
||||
ret = pm_genpd_init(&pd->genpd, governor, !always_on);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (always_on)
|
||||
ret = rzg2l_cpg_power_on(&pd->genpd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __init rzg2l_cpg_add_clk_domain(struct rzg2l_cpg_priv *priv)
|
||||
|
@ -1711,8 +1720,9 @@ static int __init rzg2l_cpg_add_clk_domain(struct rzg2l_cpg_priv *priv)
|
|||
return -ENOMEM;
|
||||
|
||||
pd->genpd.name = np->name;
|
||||
pd->genpd.flags = GENPD_FLAG_ALWAYS_ON;
|
||||
pd->priv = priv;
|
||||
ret = rzg2l_cpg_pd_setup(pd, true);
|
||||
ret = rzg2l_cpg_pd_setup(pd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -1777,7 +1787,6 @@ static int __init rzg2l_cpg_add_pm_domains(struct rzg2l_cpg_priv *priv)
|
|||
return ret;
|
||||
|
||||
for (unsigned int i = 0; i < info->num_pm_domains; i++) {
|
||||
bool always_on = !!(info->pm_domains[i].flags & RZG2L_PD_F_ALWAYS_ON);
|
||||
struct rzg2l_cpg_pd *pd;
|
||||
|
||||
pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
|
||||
|
@ -1785,20 +1794,15 @@ static int __init rzg2l_cpg_add_pm_domains(struct rzg2l_cpg_priv *priv)
|
|||
return -ENOMEM;
|
||||
|
||||
pd->genpd.name = info->pm_domains[i].name;
|
||||
pd->genpd.flags = info->pm_domains[i].genpd_flags;
|
||||
pd->conf = info->pm_domains[i].conf;
|
||||
pd->id = info->pm_domains[i].id;
|
||||
pd->priv = priv;
|
||||
|
||||
ret = rzg2l_cpg_pd_setup(pd, always_on);
|
||||
ret = rzg2l_cpg_pd_setup(pd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (always_on) {
|
||||
ret = rzg2l_cpg_power_on(&pd->genpd);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
domains->domains[i] = &pd->genpd;
|
||||
/* Parent should be on the very first entry of info->pm_domains[]. */
|
||||
if (!i) {
|
||||
|
|
|
@ -270,14 +270,14 @@ struct rzg2l_cpg_pm_domain_conf {
|
|||
* struct rzg2l_cpg_pm_domain_init_data - PM domain init data
|
||||
* @name: PM domain name
|
||||
* @conf: PM domain configuration
|
||||
* @flags: RZG2L PM domain flags (see RZG2L_PD_F_*)
|
||||
* @genpd_flags: genpd flags (see GENPD_FLAG_*)
|
||||
* @id: PM domain ID (similar to the ones defined in
|
||||
* include/dt-bindings/clock/<soc-id>-cpg.h)
|
||||
*/
|
||||
struct rzg2l_cpg_pm_domain_init_data {
|
||||
const char * const name;
|
||||
struct rzg2l_cpg_pm_domain_conf conf;
|
||||
u32 flags;
|
||||
u32 genpd_flags;
|
||||
u16 id;
|
||||
};
|
||||
|
||||
|
@ -288,13 +288,9 @@ struct rzg2l_cpg_pm_domain_init_data {
|
|||
.conf = { \
|
||||
.mstop = (_mstop_conf), \
|
||||
}, \
|
||||
.flags = (_flags), \
|
||||
.genpd_flags = (_flags), \
|
||||
}
|
||||
|
||||
/* Power domain flags. */
|
||||
#define RZG2L_PD_F_ALWAYS_ON BIT(0)
|
||||
#define RZG2L_PD_F_NONE (0)
|
||||
|
||||
/**
|
||||
* struct rzg2l_cpg_info - SoC-specific CPG Description
|
||||
*
|
||||
|
|
|
@ -32,8 +32,13 @@ struct ddiv {
|
|||
})
|
||||
|
||||
#define CPG_CDDIV0 (0x400)
|
||||
#define CPG_CDDIV1 (0x404)
|
||||
|
||||
#define CDDIV0_DIVCTL2 DDIV_PACK(CPG_CDDIV0, 8, 3, 2)
|
||||
#define CDDIV1_DIVCTL0 DDIV_PACK(CPG_CDDIV1, 0, 2, 4)
|
||||
#define CDDIV1_DIVCTL1 DDIV_PACK(CPG_CDDIV1, 4, 2, 5)
|
||||
#define CDDIV1_DIVCTL2 DDIV_PACK(CPG_CDDIV1, 8, 2, 6)
|
||||
#define CDDIV1_DIVCTL3 DDIV_PACK(CPG_CDDIV1, 12, 2, 7)
|
||||
|
||||
/**
|
||||
* Definitions of CPG Core Clocks
|
||||
|
|
|
@ -170,6 +170,7 @@ config RESET_MESON_AUDIO_ARB
|
|||
config RESET_NPCM
|
||||
bool "NPCM BMC Reset Driver" if COMPILE_TEST
|
||||
default ARCH_NPCM
|
||||
select AUXILIARY_BUS
|
||||
help
|
||||
This enables the reset controller driver for Nuvoton NPCM
|
||||
BMC SoCs.
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2019 Nuvoton Technology corporation.
|
||||
|
||||
#include <linux/auxiliary_bus.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
|
@ -10,11 +11,14 @@
|
|||
#include <linux/property.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/reset-controller.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/of_address.h>
|
||||
|
||||
#include <soc/nuvoton/clock-npcm8xx.h>
|
||||
|
||||
/* NPCM7xx GCR registers */
|
||||
#define NPCM_MDLR_OFFSET 0x7C
|
||||
#define NPCM7XX_MDLR_USBD0 BIT(9)
|
||||
|
@ -89,6 +93,7 @@ struct npcm_rc_data {
|
|||
const struct npcm_reset_info *info;
|
||||
struct regmap *gcr_regmap;
|
||||
u32 sw_reset_number;
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
@ -372,6 +377,67 @@ static const struct reset_control_ops npcm_rc_ops = {
|
|||
.status = npcm_rc_status,
|
||||
};
|
||||
|
||||
static void npcm_clock_unregister_adev(void *_adev)
|
||||
{
|
||||
struct auxiliary_device *adev = _adev;
|
||||
|
||||
auxiliary_device_delete(adev);
|
||||
auxiliary_device_uninit(adev);
|
||||
}
|
||||
|
||||
static void npcm_clock_adev_release(struct device *dev)
|
||||
{
|
||||
struct auxiliary_device *adev = to_auxiliary_dev(dev);
|
||||
struct npcm_clock_adev *rdev = to_npcm_clock_adev(adev);
|
||||
|
||||
kfree(rdev);
|
||||
}
|
||||
|
||||
static struct auxiliary_device *npcm_clock_adev_alloc(struct npcm_rc_data *rst_data, char *clk_name)
|
||||
{
|
||||
struct npcm_clock_adev *rdev;
|
||||
struct auxiliary_device *adev;
|
||||
int ret;
|
||||
|
||||
rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
|
||||
if (!rdev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
rdev->base = rst_data->base;
|
||||
|
||||
adev = &rdev->adev;
|
||||
adev->name = clk_name;
|
||||
adev->dev.parent = rst_data->dev;
|
||||
adev->dev.release = npcm_clock_adev_release;
|
||||
adev->id = 555u;
|
||||
|
||||
ret = auxiliary_device_init(adev);
|
||||
if (ret) {
|
||||
kfree(rdev);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return adev;
|
||||
}
|
||||
|
||||
static int npcm8xx_clock_controller_register(struct npcm_rc_data *rst_data, char *clk_name)
|
||||
{
|
||||
struct auxiliary_device *adev;
|
||||
int ret;
|
||||
|
||||
adev = npcm_clock_adev_alloc(rst_data, clk_name);
|
||||
if (IS_ERR(adev))
|
||||
return PTR_ERR(adev);
|
||||
|
||||
ret = auxiliary_device_add(adev);
|
||||
if (ret) {
|
||||
auxiliary_device_uninit(adev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return devm_add_action_or_reset(rst_data->dev, npcm_clock_unregister_adev, adev);
|
||||
}
|
||||
|
||||
static int npcm_rc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct npcm_rc_data *rc;
|
||||
|
@ -392,6 +458,7 @@ static int npcm_rc_probe(struct platform_device *pdev)
|
|||
rc->rcdev.of_node = pdev->dev.of_node;
|
||||
rc->rcdev.of_reset_n_cells = 2;
|
||||
rc->rcdev.of_xlate = npcm_reset_xlate;
|
||||
rc->dev = &pdev->dev;
|
||||
|
||||
ret = devm_reset_controller_register(&pdev->dev, &rc->rcdev);
|
||||
if (ret) {
|
||||
|
@ -408,12 +475,19 @@ static int npcm_rc_probe(struct platform_device *pdev)
|
|||
rc->restart_nb.priority = 192,
|
||||
rc->restart_nb.notifier_call = npcm_rc_restart,
|
||||
ret = register_restart_handler(&rc->restart_nb);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
dev_warn(&pdev->dev, "failed to register restart handler\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
switch (rc->info->bmc_id) {
|
||||
case BMC_NPCM8XX:
|
||||
return npcm8xx_clock_controller_register(rc, "clk-npcm8xx");
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static struct platform_driver npcm_rc_driver = {
|
||||
|
|
|
@ -6,17 +6,60 @@
|
|||
#ifndef _DT_BINDINGS_CLOCK_MOBILEYE_EYEQ5_CLK_H
|
||||
#define _DT_BINDINGS_CLOCK_MOBILEYE_EYEQ5_CLK_H
|
||||
|
||||
#define EQ5C_PLL_CPU 0
|
||||
#define EQ5C_PLL_VMP 1
|
||||
#define EQ5C_PLL_PMA 2
|
||||
#define EQ5C_PLL_VDI 3
|
||||
#define EQ5C_PLL_DDR0 4
|
||||
#define EQ5C_PLL_PCI 5
|
||||
#define EQ5C_PLL_PER 6
|
||||
#define EQ5C_PLL_PMAC 7
|
||||
#define EQ5C_PLL_MPC 8
|
||||
#define EQ5C_PLL_DDR1 9
|
||||
#define EQ5C_PLL_CPU 0
|
||||
#define EQ5C_PLL_VMP 1
|
||||
#define EQ5C_PLL_PMA 2
|
||||
#define EQ5C_PLL_VDI 3
|
||||
#define EQ5C_PLL_DDR0 4
|
||||
#define EQ5C_PLL_PCI 5
|
||||
#define EQ5C_PLL_PER 6
|
||||
#define EQ5C_PLL_PMAC 7
|
||||
#define EQ5C_PLL_MPC 8
|
||||
#define EQ5C_PLL_DDR1 9
|
||||
|
||||
#define EQ5C_DIV_OSPI 10
|
||||
#define EQ5C_DIV_OSPI 10
|
||||
|
||||
/* EQ5C_PLL_CPU children */
|
||||
#define EQ5C_CPU_CORE0 11
|
||||
#define EQ5C_CPU_CORE1 12
|
||||
#define EQ5C_CPU_CORE2 13
|
||||
#define EQ5C_CPU_CORE3 14
|
||||
|
||||
/* EQ5C_PLL_PER children */
|
||||
#define EQ5C_PER_OCC 15
|
||||
#define EQ5C_PER_UART 16
|
||||
#define EQ5C_PER_SPI 17
|
||||
#define EQ5C_PER_I2C 18
|
||||
#define EQ5C_PER_GPIO 19
|
||||
#define EQ5C_PER_EMMC 20
|
||||
#define EQ5C_PER_OCC_PCI 21
|
||||
|
||||
#define EQ6LC_PLL_DDR 0
|
||||
#define EQ6LC_PLL_CPU 1
|
||||
#define EQ6LC_PLL_PER 2
|
||||
#define EQ6LC_PLL_VDI 3
|
||||
|
||||
#define EQ6HC_CENTRAL_PLL_CPU 0
|
||||
#define EQ6HC_CENTRAL_CPU_OCC 1
|
||||
|
||||
#define EQ6HC_WEST_PLL_PER 0
|
||||
#define EQ6HC_WEST_PER_OCC 1
|
||||
#define EQ6HC_WEST_PER_UART 2
|
||||
|
||||
#define EQ6HC_SOUTH_PLL_VDI 0
|
||||
#define EQ6HC_SOUTH_PLL_PCIE 1
|
||||
#define EQ6HC_SOUTH_PLL_PER 2
|
||||
#define EQ6HC_SOUTH_PLL_ISP 3
|
||||
|
||||
#define EQ6HC_SOUTH_DIV_EMMC 4
|
||||
#define EQ6HC_SOUTH_DIV_OSPI_REF 5
|
||||
#define EQ6HC_SOUTH_DIV_OSPI_SYS 6
|
||||
#define EQ6HC_SOUTH_DIV_TSU 7
|
||||
|
||||
#define EQ6HC_ACC_PLL_XNN 0
|
||||
#define EQ6HC_ACC_PLL_VMP 1
|
||||
#define EQ6HC_ACC_PLL_PMA 2
|
||||
#define EQ6HC_ACC_PLL_MPC 3
|
||||
#define EQ6HC_ACC_PLL_NOC 4
|
||||
|
||||
#endif
|
||||
|
|
|
@ -308,5 +308,6 @@
|
|||
#define R9A08G045_PD_DDR 64
|
||||
#define R9A08G045_PD_TZCDDR 65
|
||||
#define R9A08G045_PD_OTFDE_DDR 66
|
||||
#define R9A08G045_PD_RTC 67
|
||||
|
||||
#endif /* __DT_BINDINGS_CLOCK_R9A08G045_CPG_H__ */
|
||||
|
|
13
include/dt-bindings/clock/renesas,r9a08g045-vbattb.h
Normal file
13
include/dt-bindings/clock/renesas,r9a08g045-vbattb.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
*
|
||||
* Copyright (C) 2024 Renesas Electronics Corp.
|
||||
*/
|
||||
#ifndef __DT_BINDINGS_CLOCK_R9A08G045_VBATTB_H__
|
||||
#define __DT_BINDINGS_CLOCK_R9A08G045_VBATTB_H__
|
||||
|
||||
#define VBATTB_XC 0
|
||||
#define VBATTB_XBYP 1
|
||||
#define VBATTB_MUX 2
|
||||
#define VBATTB_VBATTCLK 3
|
||||
|
||||
#endif /* __DT_BINDINGS_CLOCK_R9A08G045_VBATTB_H__ */
|
|
@ -622,6 +622,24 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
|
|||
__devm_clk_hw_register_gate((dev), NULL, (name), (parent_name), NULL, \
|
||||
NULL, (flags), (reg), (bit_idx), \
|
||||
(clk_gate_flags), (lock))
|
||||
/**
|
||||
* devm_clk_hw_register_gate_parent_hw - register a gate clock with the clock
|
||||
* framework
|
||||
* @dev: device that is registering this clock
|
||||
* @name: name of this clock
|
||||
* @parent_hw: pointer to parent clk
|
||||
* @flags: framework-specific flags for this clock
|
||||
* @reg: register address to control gating of this clock
|
||||
* @bit_idx: which bit in the register controls gating of this clock
|
||||
* @clk_gate_flags: gate-specific flags for this clock
|
||||
* @lock: shared register lock for this clock
|
||||
*/
|
||||
#define devm_clk_hw_register_gate_parent_hw(dev, name, parent_hw, flags, \
|
||||
reg, bit_idx, clk_gate_flags, \
|
||||
lock) \
|
||||
__devm_clk_hw_register_gate((dev), NULL, (name), NULL, (parent_hw), \
|
||||
NULL, (flags), (reg), (bit_idx), \
|
||||
(clk_gate_flags), (lock))
|
||||
/**
|
||||
* devm_clk_hw_register_gate_parent_data - register a gate clock with the
|
||||
* clock framework
|
||||
|
@ -689,13 +707,15 @@ struct clk_div_table {
|
|||
* CLK_DIVIDER_BIG_ENDIAN - By default little endian register accesses are used
|
||||
* for the divider register. Setting this flag makes the register accesses
|
||||
* big endian.
|
||||
* CLK_DIVIDER_EVEN_INTEGERS - clock divisor is 2, 4, 6, 8, 10, etc.
|
||||
* Formula is 2 * (value read from hardware + 1).
|
||||
*/
|
||||
struct clk_divider {
|
||||
struct clk_hw hw;
|
||||
void __iomem *reg;
|
||||
u8 shift;
|
||||
u8 width;
|
||||
u8 flags;
|
||||
u16 flags;
|
||||
const struct clk_div_table *table;
|
||||
spinlock_t *lock;
|
||||
};
|
||||
|
@ -711,6 +731,7 @@ struct clk_divider {
|
|||
#define CLK_DIVIDER_READ_ONLY BIT(5)
|
||||
#define CLK_DIVIDER_MAX_AT_ZERO BIT(6)
|
||||
#define CLK_DIVIDER_BIG_ENDIAN BIT(7)
|
||||
#define CLK_DIVIDER_EVEN_INTEGERS BIT(8)
|
||||
|
||||
extern const struct clk_ops clk_divider_ops;
|
||||
extern const struct clk_ops clk_divider_ro_ops;
|
||||
|
@ -740,19 +761,21 @@ struct clk_hw *__clk_hw_register_divider(struct device *dev,
|
|||
struct device_node *np, const char *name,
|
||||
const char *parent_name, const struct clk_hw *parent_hw,
|
||||
const struct clk_parent_data *parent_data, unsigned long flags,
|
||||
void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags,
|
||||
void __iomem *reg, u8 shift, u8 width,
|
||||
unsigned long clk_divider_flags,
|
||||
const struct clk_div_table *table, spinlock_t *lock);
|
||||
struct clk_hw *__devm_clk_hw_register_divider(struct device *dev,
|
||||
struct device_node *np, const char *name,
|
||||
const char *parent_name, const struct clk_hw *parent_hw,
|
||||
const struct clk_parent_data *parent_data, unsigned long flags,
|
||||
void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags,
|
||||
void __iomem *reg, u8 shift, u8 width,
|
||||
unsigned long clk_divider_flags,
|
||||
const struct clk_div_table *table, spinlock_t *lock);
|
||||
struct clk *clk_register_divider_table(struct device *dev, const char *name,
|
||||
const char *parent_name, unsigned long flags,
|
||||
void __iomem *reg, u8 shift, u8 width,
|
||||
u8 clk_divider_flags, const struct clk_div_table *table,
|
||||
spinlock_t *lock);
|
||||
unsigned long clk_divider_flags,
|
||||
const struct clk_div_table *table, spinlock_t *lock);
|
||||
/**
|
||||
* clk_register_divider - register a divider clock with the clock framework
|
||||
* @dev: device registering this clock
|
||||
|
@ -1137,6 +1160,9 @@ struct clk_hw *clk_hw_register_fixed_factor_with_accuracy_fwname(struct device *
|
|||
struct device_node *np, const char *name, const char *fw_name,
|
||||
unsigned long flags, unsigned int mult, unsigned int div,
|
||||
unsigned long acc);
|
||||
struct clk_hw *clk_hw_register_fixed_factor_index(struct device *dev,
|
||||
const char *name, unsigned int index, unsigned long flags,
|
||||
unsigned int mult, unsigned int div);
|
||||
void clk_hw_unregister_fixed_factor(struct clk_hw *hw);
|
||||
struct clk_hw *devm_clk_hw_register_fixed_factor(struct device *dev,
|
||||
const char *name, const char *parent_name, unsigned long flags,
|
||||
|
|
18
include/soc/nuvoton/clock-npcm8xx.h
Normal file
18
include/soc/nuvoton/clock-npcm8xx.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __SOC_NPCM8XX_CLOCK_H
|
||||
#define __SOC_NPCM8XX_CLOCK_H
|
||||
|
||||
#include <linux/auxiliary_bus.h>
|
||||
#include <linux/container_of.h>
|
||||
|
||||
struct npcm_clock_adev {
|
||||
void __iomem *base;
|
||||
struct auxiliary_device adev;
|
||||
};
|
||||
|
||||
static inline struct npcm_clock_adev *to_npcm_clock_adev(struct auxiliary_device *_adev)
|
||||
{
|
||||
return container_of(_adev, struct npcm_clock_adev, adev);
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Add table
Reference in a new issue