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:
Stephen Boyd 2024-11-18 20:00:28 -08:00
46 changed files with 2491 additions and 561 deletions

View file

@ -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>;
};

View 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>;
};
...

View file

@ -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

View file

@ -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>;
};

View file

@ -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>;
};

View file

@ -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>;
};

View file

@ -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:

View file

@ -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>;
};

View file

@ -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>;
};

View file

@ -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>;
};

View 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>;
};
};

View file

@ -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>;
};
};

View 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>;
};
};

View file

@ -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:

View file

@ -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:

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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
View 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);

View file

@ -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
View 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");

View file

@ -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 */
}

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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;

View 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(&reg_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");

View file

@ -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;

View file

@ -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),

View file

@ -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 = {

View file

@ -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},

View file

@ -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 */

View file

@ -206,4 +206,3 @@ struct clk * __init cpg_rpcd2_clk_register(const char *name,
return clk;
}

View file

@ -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",

View file

@ -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
{

View file

@ -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) {

View file

@ -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
*

View file

@ -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

View file

@ -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.

View file

@ -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 = {

View file

@ -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

View file

@ -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__ */

View 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__ */

View file

@ -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,

View 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