Merge f9ae180416 ("Merge tag 'for-v6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply") into android-mainline
Steps on the way to 6.7-rc1 Change-Id: Iae7da0e2896ffd72e214d44b4453218c90abdf75 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
@@ -383,6 +383,36 @@ Description:
|
||||
Note that any changes to this attribute requires a reboot
|
||||
for changes to take effect.
|
||||
|
||||
What: /sys/class/firmware-attributes/*/attributes/save_settings
|
||||
Date: August 2023
|
||||
KernelVersion: 6.6
|
||||
Contact: Mark Pearson <mpearson-lenovo@squebb.ca>
|
||||
Description:
|
||||
On Lenovo platforms there is a limitation in the number of times an attribute can be
|
||||
saved. This is an architectural limitation and it limits the number of attributes
|
||||
that can be modified to 48.
|
||||
A solution for this is instead of the attribute being saved after every modification,
|
||||
to allow a user to bulk set the attributes, and then trigger a final save. This allows
|
||||
unlimited attributes.
|
||||
|
||||
Read the attribute to check what save mode is enabled (single or bulk).
|
||||
E.g:
|
||||
# cat /sys/class/firmware-attributes/thinklmi/attributes/save_settings
|
||||
single
|
||||
|
||||
Write the attribute with 'bulk' to enable bulk save mode.
|
||||
Write the attribute with 'single' to enable saving, after every attribute set.
|
||||
The default setting is single mode.
|
||||
E.g:
|
||||
# echo bulk > /sys/class/firmware-attributes/thinklmi/attributes/save_settings
|
||||
|
||||
When in bulk mode write 'save' to trigger a save of all currently modified attributes.
|
||||
Note, once a save has been triggered, in bulk mode, attributes can no longer be set and
|
||||
will return a permissions error. This is to prevent users hitting the 48+ save limitation
|
||||
(which requires entering the BIOS to clear the error condition)
|
||||
E.g:
|
||||
# echo save > /sys/class/firmware-attributes/thinklmi/attributes/save_settings
|
||||
|
||||
What: /sys/class/firmware-attributes/*/attributes/debug_cmd
|
||||
Date: July 2021
|
||||
KernelVersion: 5.14
|
||||
|
||||
@@ -53,6 +53,7 @@ detailed description):
|
||||
- Lap mode sensor
|
||||
- Setting keyboard language
|
||||
- WWAN Antenna type
|
||||
- Auxmac
|
||||
|
||||
A compatibility table by model and feature is maintained on the web
|
||||
site, http://ibm-acpi.sf.net/. I appreciate any success or failure
|
||||
@@ -1511,6 +1512,25 @@ Currently 2 antenna types are supported as mentioned below:
|
||||
The property is read-only. If the platform doesn't have support the sysfs
|
||||
class is not created.
|
||||
|
||||
Auxmac
|
||||
------
|
||||
|
||||
sysfs: auxmac
|
||||
|
||||
Some newer Thinkpads have a feature called MAC Address Pass-through. This
|
||||
feature is implemented by the system firmware to provide a system unique MAC,
|
||||
that can override a dock or USB ethernet dongle MAC, when connected to a
|
||||
network. This property enables user-space to easily determine the MAC address
|
||||
if the feature is enabled.
|
||||
|
||||
The values of this auxiliary MAC are:
|
||||
|
||||
cat /sys/devices/platform/thinkpad_acpi/auxmac
|
||||
|
||||
If the feature is disabled, the value will be 'disabled'.
|
||||
|
||||
This property is read-only.
|
||||
|
||||
Adaptive keyboard
|
||||
-----------------
|
||||
|
||||
|
||||
@@ -41,6 +41,24 @@ In-kernel integration:
|
||||
* Locking across callers is taken care by the driver.
|
||||
|
||||
|
||||
HSMP sysfs interface
|
||||
====================
|
||||
|
||||
1. Metrics table binary sysfs
|
||||
|
||||
AMD MI300A MCM provides GET_METRICS_TABLE message to retrieve
|
||||
most of the system management information from SMU in one go.
|
||||
|
||||
The metrics table is made available as hexadecimal sysfs binary file
|
||||
under per socket sysfs directory created at
|
||||
/sys/devices/platform/amd_hsmp/socket%d/metrics_bin
|
||||
|
||||
Note: lseek() is not supported as entire metrics table is read.
|
||||
|
||||
Metrics table definitions will be documented as part of Public PPR.
|
||||
The same is defined in the amd_hsmp.h header.
|
||||
|
||||
|
||||
An example
|
||||
==========
|
||||
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright (C) 2022-2023 Amlogic, Inc. All rights reserved
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/amlogic,s4-peripherals-clkc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Amlogic S4 Peripherals Clock Controller
|
||||
|
||||
maintainers:
|
||||
- Yu Tu <yu.tu@amlogic.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: amlogic,s4-peripherals-clkc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 14
|
||||
items:
|
||||
- description: input fixed pll div2
|
||||
- description: input fixed pll div2p5
|
||||
- description: input fixed pll div3
|
||||
- description: input fixed pll div4
|
||||
- description: input fixed pll div5
|
||||
- description: input fixed pll div7
|
||||
- description: input hifi pll
|
||||
- description: input gp0 pll
|
||||
- description: input mpll0
|
||||
- description: input mpll1
|
||||
- description: input mpll2
|
||||
- description: input mpll3
|
||||
- description: input hdmi pll
|
||||
- description: input oscillator (usually at 24MHz)
|
||||
- description: input external 32kHz reference (optional)
|
||||
|
||||
clock-names:
|
||||
minItems: 14
|
||||
items:
|
||||
- const: fclk_div2
|
||||
- const: fclk_div2p5
|
||||
- const: fclk_div3
|
||||
- const: fclk_div4
|
||||
- const: fclk_div5
|
||||
- const: fclk_div7
|
||||
- const: hifi_pll
|
||||
- const: gp0_pll
|
||||
- const: mpll0
|
||||
- const: mpll1
|
||||
- const: mpll2
|
||||
- const: mpll3
|
||||
- const: hdmi_pll
|
||||
- const: xtal
|
||||
- const: ext_32k
|
||||
|
||||
"#clock-cells":
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- "#clock-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/amlogic,s4-peripherals-clkc.h>
|
||||
|
||||
clkc_periphs: clock-controller@fe000000 {
|
||||
compatible = "amlogic,s4-peripherals-clkc";
|
||||
reg = <0xfe000000 0x49c>;
|
||||
clocks = <&clkc_pll 3>,
|
||||
<&clkc_pll 13>,
|
||||
<&clkc_pll 5>,
|
||||
<&clkc_pll 7>,
|
||||
<&clkc_pll 9>,
|
||||
<&clkc_pll 11>,
|
||||
<&clkc_pll 17>,
|
||||
<&clkc_pll 15>,
|
||||
<&clkc_pll 25>,
|
||||
<&clkc_pll 27>,
|
||||
<&clkc_pll 29>,
|
||||
<&clkc_pll 31>,
|
||||
<&clkc_pll 20>,
|
||||
<&xtal>;
|
||||
clock-names = "fclk_div2", "fclk_div2p5", "fclk_div3", "fclk_div4",
|
||||
"fclk_div5", "fclk_div7", "hifi_pll", "gp0_pll",
|
||||
"mpll0", "mpll1", "mpll2", "mpll3", "hdmi_pll", "xtal";
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
...
|
||||
@@ -0,0 +1,49 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
# Copyright (C) 2022-2023 Amlogic, Inc. All rights reserved
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/amlogic,s4-pll-clkc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Amlogic S4 PLL Clock Controller
|
||||
|
||||
maintainers:
|
||||
- Yu Tu <yu.tu@amlogic.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: amlogic,s4-pll-clkc
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: xtal
|
||||
|
||||
"#clock-cells":
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- "#clock-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
clkc_pll: clock-controller@fe008000 {
|
||||
compatible = "amlogic,s4-pll-clkc";
|
||||
reg = <0xfe008000 0x1e8>;
|
||||
clocks = <&xtal>;
|
||||
clock-names = "xtal";
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
...
|
||||
@@ -12,6 +12,9 @@ PROPERTIES
|
||||
"qcom,hfpll-apq8064", "qcom,hfpll"
|
||||
"qcom,hfpll-msm8974", "qcom,hfpll"
|
||||
"qcom,hfpll-msm8960", "qcom,hfpll"
|
||||
"qcom,msm8976-hfpll-a53", "qcom,hfpll"
|
||||
"qcom,msm8976-hfpll-a72", "qcom,hfpll"
|
||||
"qcom,msm8976-hfpll-cci", "qcom,hfpll"
|
||||
|
||||
- reg:
|
||||
Usage: required
|
||||
|
||||
@@ -28,6 +28,7 @@ properties:
|
||||
- qcom,sdx55-rpmh-clk
|
||||
- qcom,sdx65-rpmh-clk
|
||||
- qcom,sdx75-rpmh-clk
|
||||
- qcom,sm4450-rpmh-clk
|
||||
- qcom,sm6350-rpmh-clk
|
||||
- qcom,sm8150-rpmh-clk
|
||||
- qcom,sm8250-rpmh-clk
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/qcom,sm4450-gcc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Global Clock & Reset Controller on SM4450
|
||||
|
||||
maintainers:
|
||||
- Ajit Pandey <quic_ajipan@quicinc.com>
|
||||
- Taniya Das <quic_tdas@quicinc.com>
|
||||
|
||||
description: |
|
||||
Qualcomm global clock control module provides the clocks, resets and power
|
||||
domains on SM4450
|
||||
|
||||
See also:: include/dt-bindings/clock/qcom,sm4450-gcc.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,sm4450-gcc
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Board XO source
|
||||
- description: Sleep clock source
|
||||
- description: UFS Phy Rx symbol 0 clock source
|
||||
- description: UFS Phy Rx symbol 1 clock source
|
||||
- description: UFS Phy Tx symbol 0 clock source
|
||||
- description: USB3 Phy wrapper pipe clock source
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- clocks
|
||||
|
||||
allOf:
|
||||
- $ref: qcom,gcc.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,rpmh.h>
|
||||
clock-controller@100000 {
|
||||
compatible = "qcom,sm4450-gcc";
|
||||
reg = <0x00100000 0x001f4200>;
|
||||
clocks = <&rpmhcc RPMH_CXO_CLK>, <&sleep_clk>,
|
||||
<&ufs_mem_phy 0>, <&ufs_mem_phy 1>,
|
||||
<&ufs_mem_phy 2>, <&usb_1_qmpphy>;
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
|
||||
...
|
||||
@@ -13,11 +13,15 @@ description: |
|
||||
Qualcomm camera clock control module provides the clocks, resets and power
|
||||
domains on SM8450.
|
||||
|
||||
See also:: include/dt-bindings/clock/qcom,sm8450-camcc.h
|
||||
See also::
|
||||
include/dt-bindings/clock/qcom,sm8450-camcc.h
|
||||
include/dt-bindings/clock/qcom,sm8550-camcc.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,sm8450-camcc
|
||||
enum:
|
||||
- qcom,sm8450-camcc
|
||||
- qcom,sm8550-camcc
|
||||
|
||||
clocks:
|
||||
items:
|
||||
|
||||
@@ -27,6 +27,7 @@ properties:
|
||||
- renesas,r9a07g043-cpg # RZ/G2UL{Type-1,Type-2} and RZ/Five
|
||||
- renesas,r9a07g044-cpg # RZ/G2{L,LC}
|
||||
- renesas,r9a07g054-cpg # RZ/V2L
|
||||
- renesas,r9a08g045-cpg # RZ/G3S
|
||||
- renesas,r9a09g011-cpg # RZ/V2M
|
||||
|
||||
reg:
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
|
||||
$id: http://devicetree.org/schemas/hwmon/adi,ltc2991.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Analog Devices LTC2991 Octal I2C Voltage, Current and Temperature Monitor
|
||||
|
||||
maintainers:
|
||||
- Antoniu Miclaus <antoniu.miclaus@analog.com>
|
||||
|
||||
description: |
|
||||
The LTC2991 is used to monitor system temperatures, voltages and currents.
|
||||
Through the I2C serial interface, the eight monitors can individually measure
|
||||
supply voltages and can be paired for differential measurements of current
|
||||
sense resistors or temperature sensing transistors.
|
||||
|
||||
Datasheet:
|
||||
https://www.analog.com/en/products/ltc2991.html
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: adi,ltc2991
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
'#address-cells':
|
||||
const: 1
|
||||
|
||||
'#size-cells':
|
||||
const: 0
|
||||
|
||||
vcc-supply: true
|
||||
|
||||
patternProperties:
|
||||
"^channel@[0-3]$":
|
||||
type: object
|
||||
description:
|
||||
Represents the differential/temperature channels.
|
||||
|
||||
properties:
|
||||
reg:
|
||||
description:
|
||||
The channel number. LTC2991 can monitor 4 currents/temperatures.
|
||||
items:
|
||||
minimum: 0
|
||||
maximum: 3
|
||||
|
||||
shunt-resistor-micro-ohms:
|
||||
description:
|
||||
The value of curent sense resistor in micro ohms. Pin configuration is
|
||||
set for differential input pair.
|
||||
|
||||
adi,temperature-enable:
|
||||
description:
|
||||
Enables temperature readings. Pin configuration is set for remote
|
||||
diode temperature measurement.
|
||||
type: boolean
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
required:
|
||||
- shunt-resistor-micro-ohms
|
||||
then:
|
||||
properties:
|
||||
adi,temperature-enable: false
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vcc-supply
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
hwmon@48 {
|
||||
compatible = "adi,ltc2991";
|
||||
reg = <0x48>;
|
||||
vcc-supply = <&vcc>;
|
||||
};
|
||||
};
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
hwmon@48 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
compatible = "adi,ltc2991";
|
||||
reg = <0x48>;
|
||||
vcc-supply = <&vcc>;
|
||||
|
||||
channel@0 {
|
||||
reg = <0x0>;
|
||||
shunt-resistor-micro-ohms = <100000>;
|
||||
};
|
||||
|
||||
channel@1 {
|
||||
reg = <0x1>;
|
||||
shunt-resistor-micro-ohms = <100000>;
|
||||
};
|
||||
|
||||
channel@2 {
|
||||
reg = <0x2>;
|
||||
adi,temperature-enable;
|
||||
};
|
||||
|
||||
channel@3 {
|
||||
reg = <0x3>;
|
||||
adi,temperature-enable;
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
||||
@@ -32,6 +32,68 @@ properties:
|
||||
Must have values in the interval (1.6V; 3.6V) in order for the device to
|
||||
function correctly.
|
||||
|
||||
adi,comp-int:
|
||||
description:
|
||||
If present interrupt mode is used. If not present comparator mode is used
|
||||
(default).
|
||||
type: boolean
|
||||
|
||||
adi,alarm-pol:
|
||||
description:
|
||||
Sets the alarms active state.
|
||||
- 0 = active low
|
||||
- 1 = active high
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [0, 1]
|
||||
|
||||
adi,fault-q:
|
||||
description:
|
||||
Select how many consecutive temperature faults must occur before
|
||||
overtemperature or undertemperature faults are indicated in the
|
||||
corresponding status bits.
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [1, 2, 4, 8]
|
||||
|
||||
adi,timeout-enable:
|
||||
description:
|
||||
Enables timeout. Bus timeout resets the I2C-compatible interface when SCL
|
||||
is low for more than 30ms (nominal).
|
||||
type: boolean
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: adi,max31829
|
||||
|
||||
then:
|
||||
properties:
|
||||
adi,alarm-pol:
|
||||
default: 1
|
||||
|
||||
else:
|
||||
properties:
|
||||
adi,alarm-pol:
|
||||
default: 0
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: adi,max31827
|
||||
|
||||
then:
|
||||
properties:
|
||||
adi,fault-q:
|
||||
default: 1
|
||||
|
||||
else:
|
||||
properties:
|
||||
adi,fault-q:
|
||||
default: 4
|
||||
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
@@ -49,6 +111,10 @@ examples:
|
||||
compatible = "adi,max31827";
|
||||
reg = <0x42>;
|
||||
vref-supply = <®_vdd>;
|
||||
adi,comp-int;
|
||||
adi,alarm-pol = <0>;
|
||||
adi,fault-q = <1>;
|
||||
adi,timeout-enable;
|
||||
};
|
||||
};
|
||||
...
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
Texas Instruments INA3221 Device Tree Bindings
|
||||
|
||||
1) ina3221 node
|
||||
Required properties:
|
||||
- compatible: Must be "ti,ina3221"
|
||||
- reg: I2C address
|
||||
|
||||
Optional properties:
|
||||
- ti,single-shot: This chip has two power modes: single-shot (chip takes one
|
||||
measurement and then shuts itself down) and continuous (
|
||||
chip takes continuous measurements). The continuous mode is
|
||||
more reliable and suitable for hardware monitor type device,
|
||||
but the single-shot mode is more power-friendly and useful
|
||||
for battery-powered device which cares power consumptions
|
||||
while still needs some measurements occasionally.
|
||||
If this property is present, the single-shot mode will be
|
||||
used, instead of the default continuous one for monitoring.
|
||||
|
||||
= The node contains optional child nodes for three channels =
|
||||
= Each child node describes the information of input source =
|
||||
|
||||
- #address-cells: Required only if a child node is present. Must be 1.
|
||||
- #size-cells: Required only if a child node is present. Must be 0.
|
||||
|
||||
2) child nodes
|
||||
Required properties:
|
||||
- reg: Must be 0, 1 or 2, corresponding to IN1, IN2 or IN3 port of INA3221
|
||||
|
||||
Optional properties:
|
||||
- label: Name of the input source
|
||||
- shunt-resistor-micro-ohms: Shunt resistor value in micro-Ohm
|
||||
|
||||
Example:
|
||||
|
||||
ina3221@40 {
|
||||
compatible = "ti,ina3221";
|
||||
reg = <0x40>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
input@0 {
|
||||
reg = <0x0>;
|
||||
status = "disabled";
|
||||
};
|
||||
input@1 {
|
||||
reg = <0x1>;
|
||||
shunt-resistor-micro-ohms = <5000>;
|
||||
};
|
||||
input@2 {
|
||||
reg = <0x2>;
|
||||
label = "VDD_5V";
|
||||
shunt-resistor-micro-ohms = <5000>;
|
||||
};
|
||||
};
|
||||
@@ -1,12 +1,16 @@
|
||||
Nuvoton NPCM7xx PWM and Fan Tacho controller device
|
||||
Nuvoton NPCM PWM and Fan Tacho controller device
|
||||
|
||||
The Nuvoton BMC NPCM7XX supports 8 Pulse-width modulation (PWM)
|
||||
controller outputs and 16 Fan tachometer controller inputs.
|
||||
|
||||
The Nuvoton BMC NPCM8XX supports 12 Pulse-width modulation (PWM)
|
||||
controller outputs and 16 Fan tachometer controller inputs.
|
||||
|
||||
Required properties for pwm-fan node
|
||||
- #address-cells : should be 1.
|
||||
- #size-cells : should be 0.
|
||||
- compatible : "nuvoton,npcm750-pwm-fan" for Poleg NPCM7XX.
|
||||
: "nuvoton,npcm845-pwm-fan" for Arbel NPCM8XX.
|
||||
- reg : specifies physical base address and size of the registers.
|
||||
- reg-names : must contain:
|
||||
* "pwm" for the PWM registers.
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
|
||||
$id: http://devicetree.org/schemas/hwmon/pmbus/infineon,tda38640.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Infineon TDA38640 Synchronous Buck Regulator with SVID and I2C
|
||||
|
||||
maintainers:
|
||||
- Naresh Solanki <naresh.solanki@9elements.com>
|
||||
|
||||
description: |
|
||||
The Infineon TDA38640 is a 40A Single-voltage Synchronous Buck
|
||||
Regulator with SVID and I2C designed for Industrial use.
|
||||
|
||||
Datasheet: https://www.infineon.com/dgdl/Infineon-TDA38640-0000-DataSheet-v02_04-EN.pdf?fileId=8ac78c8c80027ecd018042f2337f00c9
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- infineon,tda38640
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
infineon,en-pin-fixed-level:
|
||||
description:
|
||||
Indicates that the chip EN pin is at fixed level or left
|
||||
unconnected(has internal pull-down).
|
||||
type: boolean
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
tda38640@40 {
|
||||
compatible = "infineon,tda38640";
|
||||
reg = <0x40>;
|
||||
};
|
||||
};
|
||||
@@ -26,6 +26,7 @@ properties:
|
||||
- ti,ina226
|
||||
- ti,ina230
|
||||
- ti,ina231
|
||||
- ti,ina237
|
||||
- ti,ina238
|
||||
|
||||
reg:
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/hwmon/ti,ina3221.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments INA3221 Current and Voltage Monitor
|
||||
|
||||
maintainers:
|
||||
- Jean Delvare <jdelvare@suse.com>
|
||||
- Guenter Roeck <linux@roeck-us.net>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: ti,ina3221
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
ti,single-shot:
|
||||
description: |
|
||||
This chip has two power modes: single-shot (chip takes one measurement
|
||||
and then shuts itself down) and continuous (chip takes continuous
|
||||
measurements). The continuous mode is more reliable and suitable for
|
||||
hardware monitor type device, but the single-shot mode is more power-
|
||||
friendly and useful for battery-powered device which cares power
|
||||
consumptions while still needs some measurements occasionally.
|
||||
|
||||
If this property is present, the single-shot mode will be used, instead
|
||||
of the default continuous one for monitoring.
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
|
||||
"#address-cells":
|
||||
description: Required only if a child node is present.
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
description: Required only if a child node is present.
|
||||
const: 0
|
||||
|
||||
patternProperties:
|
||||
"^input@[0-2]$":
|
||||
description: The node contains optional child nodes for three channels.
|
||||
Each child node describes the information of input source. Input channels
|
||||
default to enabled in the chip. Unless channels are explicitly disabled
|
||||
in device-tree, input channels will be enabled.
|
||||
type: object
|
||||
additionalProperties: false
|
||||
properties:
|
||||
reg:
|
||||
description: Must be 0, 1 and 2, corresponding to the IN1, IN2 or IN3
|
||||
ports of the INA3221, respectively.
|
||||
enum: [ 0, 1, 2 ]
|
||||
|
||||
label:
|
||||
description: name of the input source
|
||||
|
||||
shunt-resistor-micro-ohms:
|
||||
description: shunt resistor value in micro-Ohm
|
||||
|
||||
ti,summation-disable:
|
||||
description: |
|
||||
The INA3221 has a critical alert pin that can be controlled by the
|
||||
summation control function. This function adds the single
|
||||
shunt-voltage conversions for the desired channels in order to
|
||||
compare the combined sum to the programmed limit. The Shunt-Voltage
|
||||
Sum Limit register contains the programmed value that is compared
|
||||
to the value in the Shunt-Voltage Sum register in order to
|
||||
determine if the total summed limit is exceeded. If the
|
||||
shunt-voltage sum limit value is exceeded, the critical alert pin
|
||||
is asserted.
|
||||
|
||||
For the summation limit to have a meaningful value, it is necessary
|
||||
to use the same shunt-resistor value on all enabled channels. If
|
||||
this is not the case or if a channel should not be used for
|
||||
triggering the critical alert pin, then this property can be used
|
||||
exclude specific channels from the summation control function.
|
||||
type: boolean
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
power-sensor@40 {
|
||||
compatible = "ti,ina3221";
|
||||
reg = <0x40>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
input@0 {
|
||||
reg = <0x0>;
|
||||
/*
|
||||
* Input channels are enabled by default in the device and so
|
||||
* to disable, must be explicitly disabled in device-tree.
|
||||
*/
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
input@1 {
|
||||
reg = <0x1>;
|
||||
shunt-resistor-micro-ohms = <5000>;
|
||||
};
|
||||
|
||||
input@2 {
|
||||
reg = <0x2>;
|
||||
label = "VDD_5V";
|
||||
shunt-resistor-micro-ohms = <5000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -18,6 +18,9 @@ description: >
|
||||
Finally the operating system assumes the power off failed if
|
||||
the system is still running after waiting some time (timeout-ms).
|
||||
|
||||
allOf:
|
||||
- $ref: restart-handler.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: gpio-poweroff
|
||||
@@ -40,6 +43,9 @@ properties:
|
||||
default: 100
|
||||
description: Delay to wait after driving gpio inactive
|
||||
|
||||
priority:
|
||||
default: 0
|
||||
|
||||
timeout-ms:
|
||||
default: 3000
|
||||
description: Time to wait before assuming the power off sequence failed.
|
||||
|
||||
@@ -15,6 +15,9 @@ description: |+
|
||||
defined by the register map pointed by syscon reference plus the offset
|
||||
with the value and mask defined in the poweroff node.
|
||||
Default will be little endian mode, 32 bit access only.
|
||||
The SYSCON register map is normally retrieved from the parental dt-node. So
|
||||
the SYSCON poweroff node should be represented as a sub-node of a "syscon",
|
||||
"simple-mfd" node.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
@@ -30,7 +33,10 @@ properties:
|
||||
|
||||
regmap:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: Phandle to the register map node.
|
||||
deprecated: true
|
||||
description:
|
||||
Phandle to the register map node. This property is deprecated in favor of
|
||||
the syscon-poweroff node being a child of a system controller node.
|
||||
|
||||
value:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
@@ -38,7 +44,6 @@ properties:
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- regmap
|
||||
- offset
|
||||
|
||||
additionalProperties: false
|
||||
@@ -56,7 +61,6 @@ examples:
|
||||
- |
|
||||
poweroff {
|
||||
compatible = "syscon-poweroff";
|
||||
regmap = <®mapnode>;
|
||||
offset = <0x0>;
|
||||
mask = <0x7a>;
|
||||
};
|
||||
|
||||
@@ -55,6 +55,14 @@ properties:
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
io-channels:
|
||||
items:
|
||||
- description: battery temperature
|
||||
|
||||
io-channel-names:
|
||||
items:
|
||||
- const: temp
|
||||
|
||||
wakeup-source:
|
||||
type: boolean
|
||||
description: |
|
||||
@@ -95,3 +103,26 @@ examples:
|
||||
wakeup-source;
|
||||
};
|
||||
};
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
fuel-gauge@36 {
|
||||
compatible = "maxim,max17043";
|
||||
reg = <0x36>;
|
||||
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <144 IRQ_TYPE_EDGE_FALLING>;
|
||||
|
||||
monitored-battery = <&battery>;
|
||||
power-supplies = <&charger>;
|
||||
|
||||
io-channels = <&adc 8>;
|
||||
io-channel-names = "temp";
|
||||
|
||||
maxim,alert-low-soc-level = <10>;
|
||||
wakeup-source;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/power/supply/mitsumi,mm8013.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Mitsumi MM8013 fuel gauge
|
||||
|
||||
maintainers:
|
||||
- Konrad Dybcio <konradybcio@kernel.org>
|
||||
|
||||
allOf:
|
||||
- $ref: power-supply.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: mitsumi,mm8013
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
fuel-gauge@55 {
|
||||
compatible = "mitsumi,mm8013";
|
||||
reg = <0x55>;
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,83 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/power/supply/qcom,pm8916-bms-vm.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Voltage Mode BMS
|
||||
|
||||
maintainers:
|
||||
- Nikita Travkin <nikita@trvn.ru>
|
||||
|
||||
description:
|
||||
Voltage Mode BMS is a hardware block found in some Qualcomm PMICs
|
||||
such as pm8916. This block performs battery voltage monitoring.
|
||||
|
||||
allOf:
|
||||
- $ref: power-supply.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,pm8916-bms-vm
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
items:
|
||||
- description: BMS FSM left S3 mode
|
||||
- description: BMS FSM entered S2 mode
|
||||
- description: OCV measured in S3 mode
|
||||
- description: OCV below threshold
|
||||
- description: FIFO update done
|
||||
- description: BMS FSM switched state
|
||||
|
||||
interrupt-names:
|
||||
items:
|
||||
- const: cv_leave
|
||||
- const: cv_enter
|
||||
- const: ocv_good
|
||||
- const: ocv_thr
|
||||
- const: fifo
|
||||
- const: state_chg
|
||||
|
||||
monitored-battery: true
|
||||
|
||||
power-supplies: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- interrupt-names
|
||||
- monitored-battery
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
pmic {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
battery@4000 {
|
||||
compatible = "qcom,pm8916-bms-vm";
|
||||
reg = <0x4000>;
|
||||
interrupts = <0x0 0x40 0 IRQ_TYPE_EDGE_RISING>,
|
||||
<0x0 0x40 1 IRQ_TYPE_EDGE_RISING>,
|
||||
<0x0 0x40 2 IRQ_TYPE_EDGE_RISING>,
|
||||
<0x0 0x40 3 IRQ_TYPE_EDGE_RISING>,
|
||||
<0x0 0x40 4 IRQ_TYPE_EDGE_RISING>,
|
||||
<0x0 0x40 5 IRQ_TYPE_EDGE_RISING>;
|
||||
interrupt-names = "cv_leave",
|
||||
"cv_enter",
|
||||
"ocv_good",
|
||||
"ocv_thr",
|
||||
"fifo",
|
||||
"state_chg";
|
||||
|
||||
monitored-battery = <&battery>;
|
||||
power-supplies = <&pm8916_charger>;
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,128 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/power/supply/qcom,pm8916-lbc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Linear Battery Charger
|
||||
|
||||
maintainers:
|
||||
- Nikita Travkin <nikita@trvn.ru>
|
||||
|
||||
description:
|
||||
Linear Battery Charger hardware block, found in some Qualcomm PMICs
|
||||
such as pm8916. Implements a simple, autonomous CC/CV charger.
|
||||
|
||||
allOf:
|
||||
- $ref: power-supply.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,pm8916-lbc
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: Charger
|
||||
- description: Battery
|
||||
- description: USB
|
||||
- description: MISC
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: chgr
|
||||
- const: bat_if
|
||||
- const: usb
|
||||
- const: misc
|
||||
|
||||
interrupts:
|
||||
items:
|
||||
- description: Battery detection
|
||||
- description: Fast charging
|
||||
- description: Charging failed
|
||||
- description: Charging done
|
||||
- description: Battery present
|
||||
- description: Battery temperature OK
|
||||
- description: USB coarse detection
|
||||
- description: USB IN valid
|
||||
- description: Charger gone
|
||||
- description: Overtemperature
|
||||
|
||||
interrupt-names:
|
||||
items:
|
||||
- const: vbat_det
|
||||
- const: fast_chg
|
||||
- const: chg_fail
|
||||
- const: chg_done
|
||||
- const: bat_pres
|
||||
- const: temp_ok
|
||||
- const: coarse_det
|
||||
- const: usb_vbus
|
||||
- const: chg_gone
|
||||
- const: overtemp
|
||||
|
||||
qcom,fast-charge-safe-voltage:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 4000000
|
||||
maximum: 4775000
|
||||
description:
|
||||
Maximum safe battery voltage in uV; May be pre-set by bootloader,
|
||||
in which case, setting this will harmlessly fail.
|
||||
|
||||
qcom,fast-charge-safe-current:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 90000
|
||||
maximum: 1440000
|
||||
description:
|
||||
Maximum safe battery charge current in uA; May be pre-set by
|
||||
bootloader, in which case setting this will harmlessly fail.
|
||||
|
||||
monitored-battery: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- interrupt-names
|
||||
- qcom,fast-charge-safe-voltage
|
||||
- qcom,fast-charge-safe-current
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
pmic {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
charger@1000 {
|
||||
compatible = "qcom,pm8916-lbc";
|
||||
reg = <0x1000>, <0x1200>, <0x1300>, <0x1600>;
|
||||
reg-names = "chgr", "bat_if", "usb", "misc";
|
||||
|
||||
interrupts = <0x0 0x10 0 IRQ_TYPE_EDGE_BOTH>,
|
||||
<0x0 0x10 5 IRQ_TYPE_EDGE_BOTH>,
|
||||
<0x0 0x10 6 IRQ_TYPE_EDGE_BOTH>,
|
||||
<0x0 0x10 7 IRQ_TYPE_EDGE_BOTH>,
|
||||
<0x0 0x12 0 IRQ_TYPE_EDGE_BOTH>,
|
||||
<0x0 0x12 1 IRQ_TYPE_EDGE_BOTH>,
|
||||
<0x0 0x13 0 IRQ_TYPE_EDGE_BOTH>,
|
||||
<0x0 0x13 1 IRQ_TYPE_EDGE_BOTH>,
|
||||
<0x0 0x13 2 IRQ_TYPE_EDGE_BOTH>,
|
||||
<0x0 0x13 4 IRQ_TYPE_EDGE_BOTH>;
|
||||
interrupt-names = "vbat_det",
|
||||
"fast_chg",
|
||||
"chg_fail",
|
||||
"chg_done",
|
||||
"bat_pres",
|
||||
"temp_ok",
|
||||
"coarse_det",
|
||||
"usb_vbus",
|
||||
"chg_gone",
|
||||
"overtemp";
|
||||
monitored-battery = <&battery>;
|
||||
|
||||
qcom,fast-charge-safe-current = <900000>;
|
||||
qcom,fast-charge-safe-voltage = <4300000>;
|
||||
};
|
||||
};
|
||||
@@ -47,6 +47,12 @@ patternProperties:
|
||||
"^i2c@[1-4]$":
|
||||
type: object
|
||||
$ref: /schemas/i2c/i2c-controller.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
reg:
|
||||
minimum: 1
|
||||
maximum: 4
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
AB85000 PMIC contains a node, which contains shared
|
||||
information about the battery connected to the PMIC.
|
||||
The node has no compatible property.
|
||||
|
||||
Properties of this node are:
|
||||
|
||||
thermistor-on-batctrl:
|
||||
A boolean value indicating thermistor interface to battery
|
||||
|
||||
Note:
|
||||
'btemp' and 'batctrl' are the pins interfaced for battery temperature
|
||||
measurement, 'btemp' signal is used when NTC(negative temperature
|
||||
coefficient) resister is interfaced external to battery whereas
|
||||
'batctrl' pin is used when NTC resister is internal to battery.
|
||||
|
||||
Example:
|
||||
ab8500_battery: ab8500_battery {
|
||||
thermistor-on-batctrl;
|
||||
};
|
||||
indicates: NTC resister is internal to battery, 'batctrl' is used
|
||||
for thermal measurement.
|
||||
|
||||
The absence of property 'thermal-on-batctrl' indicates
|
||||
NTC resister is external to battery and 'btemp' signal is used
|
||||
for thermal measurement.
|
||||
|
||||
battery-type:
|
||||
This shall be the battery manufacturing technology type,
|
||||
allowed types are:
|
||||
"UNKNOWN" "NiMH" "LION" "LIPO" "LiFe" "NiCd" "LiMn"
|
||||
Example:
|
||||
ab8500_battery: ab8500_battery {
|
||||
stericsson,battery-type = "LIPO";
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/regulator/mps,mpq2286.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Monolithic Power System MPQ2286 PMIC
|
||||
|
||||
maintainers:
|
||||
- Saravanan Sekar <saravanan@linumiz.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- mps,mpq2286
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
regulators:
|
||||
type: object
|
||||
|
||||
properties:
|
||||
buck:
|
||||
type: object
|
||||
$ref: regulator.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- regulators
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
pmic@3 {
|
||||
compatible = "mps,mpq2286";
|
||||
reg = <0x3>;
|
||||
|
||||
regulators {
|
||||
buck {
|
||||
regulator-name = "buck";
|
||||
regulator-min-microvolt = <1600000>;
|
||||
regulator-max-microvolt = <1800000>;
|
||||
regulator-boot-on;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
||||
@@ -151,8 +151,6 @@ properties:
|
||||
- infineon,slb9645tt
|
||||
# Infineon SLB9673 I2C TPM 2.0
|
||||
- infineon,slb9673
|
||||
# Infineon TDA38640 Voltage Regulator
|
||||
- infineon,tda38640
|
||||
# Infineon TLV493D-A1B6 I2C 3D Magnetic Sensor
|
||||
- infineon,tlv493d-a1b6
|
||||
# Infineon Multi-phase Digital VR Controller xdpe11280
|
||||
|
||||
@@ -871,6 +871,8 @@ patternProperties:
|
||||
description: MiraMEMS Sensing Technology Co., Ltd.
|
||||
"^mitsubishi,.*":
|
||||
description: Mitsubishi Electric Corporation
|
||||
"^mitsumi,.*":
|
||||
description: Mitsumi Electric Co., Ltd.
|
||||
"^mixel,.*":
|
||||
description: Mixel, Inc.
|
||||
"^miyoo,.*":
|
||||
|
||||
@@ -90,7 +90,7 @@ ADT7476:
|
||||
|
||||
ADT7490:
|
||||
* 6 voltage inputs
|
||||
* 1 Imon input (not implemented)
|
||||
* 1 Imon input
|
||||
* PECI support (not implemented)
|
||||
* 2 GPIO pins (not implemented)
|
||||
* system acoustics optimizations (not implemented)
|
||||
@@ -107,6 +107,7 @@ in2 VCC (4) VCC (4) VCC (4) VCC (3)
|
||||
in3 5VIN (20) 5VIN (20)
|
||||
in4 12VIN (21) 12VIN (21)
|
||||
in5 VTT (8)
|
||||
in6 Imon (19)
|
||||
==== =========== =========== ========= ==========
|
||||
|
||||
Special Features
|
||||
|
||||
@@ -16,6 +16,8 @@ Supported devices:
|
||||
* Aquacomputer Aquastream XT watercooling pump
|
||||
* Aquacomputer Aquastream Ultimate watercooling pump
|
||||
* Aquacomputer Poweradjust 3 fan controller
|
||||
* Aquacomputer High Flow USB flow meter
|
||||
* Aquacomputer MPS Flow devices
|
||||
|
||||
Author: Aleksa Savic
|
||||
|
||||
@@ -73,6 +75,11 @@ It also exposes pressure and flow speed readings.
|
||||
|
||||
The Poweradjust 3 controller exposes a single external temperature sensor.
|
||||
|
||||
The High Flow USB exposes an internal and external temperature sensor, and a flow meter.
|
||||
|
||||
The MPS Flow devices expose the same entries as the High Flow USB because they have
|
||||
the same USB product ID and report sensors equivalently.
|
||||
|
||||
Depending on the device, not all sysfs and debugfs entries will be available.
|
||||
Writing to virtual temperature sensors is not currently supported.
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ Supported boards:
|
||||
* ROG CROSSHAIR VIII HERO
|
||||
* ROG CROSSHAIR VIII IMPACT
|
||||
* ROG CROSSHAIR X670E HERO
|
||||
* ROG CROSSHAIR X670E GENE
|
||||
* ROG MAXIMUS XI HERO
|
||||
* ROG MAXIMUS XI HERO (WI-FI)
|
||||
* ROG STRIX B550-E GAMING
|
||||
|
||||
@@ -121,6 +121,7 @@ Hardware Monitoring Kernel Drivers
|
||||
ltc2947
|
||||
ltc2978
|
||||
ltc2990
|
||||
ltc2991
|
||||
ltc3815
|
||||
ltc4151
|
||||
ltc4215
|
||||
@@ -178,6 +179,7 @@ Hardware Monitoring Kernel Drivers
|
||||
peci-cputemp
|
||||
peci-dimmtemp
|
||||
pmbus
|
||||
powerz
|
||||
powr1220
|
||||
pxe1610
|
||||
pwm-fan
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
Kernel driver ltc2991
|
||||
=====================
|
||||
|
||||
Supported chips:
|
||||
|
||||
* Analog Devices LTC2991
|
||||
|
||||
Prefix: 'ltc2991'
|
||||
|
||||
Addresses scanned: I2C 0x48 - 0x4f
|
||||
|
||||
Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/2991ff.pdf
|
||||
|
||||
Authors:
|
||||
|
||||
- Antoniu Miclaus <antoniu.miclaus@analog.com>
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver supports hardware monitoring for Analog Devices LTC2991 Octal I2C
|
||||
Voltage, Current and Temperature Monitor.
|
||||
|
||||
The LTC2991 is used to monitor system temperatures, voltages and currents.
|
||||
Through the I2C serial interface, the eight monitors can individually measure
|
||||
supply voltages and can be paired for differential measurements of current sense
|
||||
resistors or temperature sensing transistors. Additional measurements include
|
||||
internal temperatureand internal VCC.
|
||||
|
||||
|
||||
sysfs-Interface
|
||||
---------------
|
||||
|
||||
The following attributes are supported. Limits are read-only.
|
||||
|
||||
=============== =================
|
||||
inX_input: voltage input
|
||||
currX_input: current input
|
||||
tempX_input: temperature input
|
||||
=============== =================
|
||||
@@ -73,8 +73,8 @@ the conversion frequency to 1 conv/s. The conversion time varies depending on
|
||||
the resolution. The conversion time doubles with every bit of increased
|
||||
resolution. For 10 bit resolution 35ms are needed, while for 12 bit resolution
|
||||
(default) 140ms. When chip is in shutdown mode and a read operation is
|
||||
requested, one-shot is triggered, the device waits for 140 (conversion time) + 1
|
||||
(error) ms, and only after that is the temperature value register read.
|
||||
requested, one-shot is triggered, the device waits for 140 (conversion time) ms,
|
||||
and only after that is the temperature value register read.
|
||||
|
||||
The LSB of the temperature values is 0.0625 degrees Celsius, but the values of
|
||||
the temperatures are displayed in milli-degrees. This means, that some data is
|
||||
|
||||
@@ -62,5 +62,6 @@ Intel DH87RL NCT6683D EC firmware version 1.0 build 04/03/13
|
||||
Intel DH87MC NCT6683D EC firmware version 1.0 build 04/03/13
|
||||
Intel DB85FL NCT6683D EC firmware version 1.0 build 04/03/13
|
||||
ASRock X570 NCT6683D EC firmware version 1.0 build 06/28/19
|
||||
ASRock X670E NCT6686D EC firmware version 1.0 build 05/19/22
|
||||
MSI B550 NCT6687D EC firmware version 1.0 build 05/07/20
|
||||
=============== ===============================================
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
Kernel driver POWERZ
|
||||
====================
|
||||
|
||||
Supported chips:
|
||||
|
||||
* ChargerLAB POWER-Z KM003C
|
||||
|
||||
Prefix: 'powerz'
|
||||
|
||||
Addresses scanned: -
|
||||
|
||||
Author:
|
||||
|
||||
- Thomas Weißschuh <linux@weissschuh.net>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver implements support for the ChargerLAB POWER-Z USB-C power testing
|
||||
family.
|
||||
|
||||
The device communicates with the custom protocol over USB.
|
||||
|
||||
The channel labels exposed via hwmon match the labels used by the on-device
|
||||
display and the official POWER-Z PC software.
|
||||
|
||||
As current can flow in both directions through the tester the sign of the
|
||||
channel "curr1_input" (label "IBUS") indicates the direction.
|
||||
@@ -33,3 +33,13 @@ The hardware monitoring part of the SMSC SCH5627 is accessed by talking
|
||||
through an embedded microcontroller. An application note describing the
|
||||
protocol for communicating with the microcontroller is available upon
|
||||
request. Please mail me if you want a copy.
|
||||
|
||||
|
||||
Controlling fan speed
|
||||
---------------------
|
||||
|
||||
The SCH5627 allows for partially controlling the fan speed. If a temperature
|
||||
channel excedes tempX_max, all fans are forced to maximum speed. The same is not
|
||||
true for tempX_crit, presumably some other measures to cool down the system are
|
||||
take in this case.
|
||||
In which way the value of fanX_min affects the fan speed is currently unknown.
|
||||
|
||||
+21
@@ -4828,6 +4828,13 @@ X: drivers/char/ipmi/
|
||||
X: drivers/char/random.c
|
||||
X: drivers/char/tpm/
|
||||
|
||||
CHARGERLAB POWER-Z HARDWARE MONITOR DRIVER
|
||||
M: Thomas Weißschuh <linux@weissschuh.net>
|
||||
L: linux-hwmon@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/hwmon/powerz.rst
|
||||
F: drivers/hwmon/powerz.c
|
||||
|
||||
CHECKPATCH
|
||||
M: Andy Whitcroft <apw@canonical.com>
|
||||
M: Joe Perches <joe@perches.com>
|
||||
@@ -12498,6 +12505,14 @@ F: drivers/hwmon/ltc2947-i2c.c
|
||||
F: drivers/hwmon/ltc2947-spi.c
|
||||
F: drivers/hwmon/ltc2947.h
|
||||
|
||||
LTC2991 HARDWARE MONITOR DRIVER
|
||||
M: Antoniu Miclaus <antoniu.miclaus@analog.com>
|
||||
L: linux-hwmon@vger.kernel.org
|
||||
S: Supported
|
||||
W: https://ez.analog.com/linux-software-drivers
|
||||
F: Documentation/devicetree/bindings/hwmon/adi,ltc2991.yaml
|
||||
F: drivers/hwmon/ltc2991.c
|
||||
|
||||
LTC2983 IIO TEMPERATURE DRIVER
|
||||
M: Nuno Sá <nuno.sa@analog.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
@@ -14425,6 +14440,11 @@ W: https://linuxtv.org
|
||||
T: git git://linuxtv.org/media_tree.git
|
||||
F: drivers/media/radio/radio-miropcm20*
|
||||
|
||||
MITSUMI MM8013 FG DRIVER
|
||||
M: Konrad Dybcio <konradybcio@kernel.org>
|
||||
F: Documentation/devicetree/bindings/power/supply/mitsumi,mm8013.yaml
|
||||
F: drivers/power/supply/mm8013.c
|
||||
|
||||
MMP SUPPORT
|
||||
R: Lubomir Rintel <lkundrak@v3.sk>
|
||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
@@ -19448,6 +19468,7 @@ F: drivers/net/ethernet/sfc/
|
||||
|
||||
SFCTEMP HWMON DRIVER
|
||||
M: Emil Renner Berthing <kernel@esmil.dk>
|
||||
M: Hal Feng <hal.feng@starfivetech.com>
|
||||
L: linux-hwmon@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/hwmon/starfive,jh71x0-temp.yaml
|
||||
|
||||
@@ -222,6 +222,7 @@
|
||||
#define MSR_INTEGRITY_CAPS_ARRAY_BIST BIT(MSR_INTEGRITY_CAPS_ARRAY_BIST_BIT)
|
||||
#define MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT 4
|
||||
#define MSR_INTEGRITY_CAPS_PERIODIC_BIST BIT(MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT)
|
||||
#define MSR_INTEGRITY_CAPS_SAF_GEN_MASK GENMASK_ULL(10, 9)
|
||||
|
||||
#define MSR_LBR_NHM_FROM 0x00000680
|
||||
#define MSR_LBR_NHM_TO 0x000006c0
|
||||
|
||||
@@ -47,6 +47,9 @@ enum hsmp_message_ids {
|
||||
HSMP_SET_PCI_RATE, /* 20h Control link rate on PCIe devices */
|
||||
HSMP_SET_POWER_MODE, /* 21h Select power efficiency profile policy */
|
||||
HSMP_SET_PSTATE_MAX_MIN, /* 22h Set the max and min DF P-State */
|
||||
HSMP_GET_METRIC_TABLE_VER, /* 23h Get metrics table version */
|
||||
HSMP_GET_METRIC_TABLE, /* 24h Get metrics table */
|
||||
HSMP_GET_METRIC_TABLE_DRAM_ADDR,/* 25h Get metrics table dram address */
|
||||
HSMP_MSG_ID_MAX,
|
||||
};
|
||||
|
||||
@@ -64,6 +67,14 @@ enum hsmp_msg_type {
|
||||
HSMP_GET = 1,
|
||||
};
|
||||
|
||||
enum hsmp_proto_versions {
|
||||
HSMP_PROTO_VER2 = 2,
|
||||
HSMP_PROTO_VER3,
|
||||
HSMP_PROTO_VER4,
|
||||
HSMP_PROTO_VER5,
|
||||
HSMP_PROTO_VER6
|
||||
};
|
||||
|
||||
struct hsmp_msg_desc {
|
||||
int num_args;
|
||||
int response_sz;
|
||||
@@ -295,6 +306,104 @@ static const struct hsmp_msg_desc hsmp_msg_desc_table[] = {
|
||||
* input: args[0] = min df pstate[15:8] + max df pstate[7:0]
|
||||
*/
|
||||
{1, 0, HSMP_SET},
|
||||
|
||||
/*
|
||||
* HSMP_GET_METRIC_TABLE_VER, num_args = 0, response_sz = 1
|
||||
* output: args[0] = metrics table version
|
||||
*/
|
||||
{0, 1, HSMP_GET},
|
||||
|
||||
/*
|
||||
* HSMP_GET_METRIC_TABLE, num_args = 0, response_sz = 0
|
||||
*/
|
||||
{0, 0, HSMP_GET},
|
||||
|
||||
/*
|
||||
* HSMP_GET_METRIC_TABLE_DRAM_ADDR, num_args = 0, response_sz = 2
|
||||
* output: args[0] = lower 32 bits of the address
|
||||
* output: args[1] = upper 32 bits of the address
|
||||
*/
|
||||
{0, 2, HSMP_GET},
|
||||
};
|
||||
|
||||
/* Metrics table (supported only with proto version 6) */
|
||||
struct hsmp_metric_table {
|
||||
__u32 accumulation_counter;
|
||||
|
||||
/* TEMPERATURE */
|
||||
__u32 max_socket_temperature;
|
||||
__u32 max_vr_temperature;
|
||||
__u32 max_hbm_temperature;
|
||||
__u64 max_socket_temperature_acc;
|
||||
__u64 max_vr_temperature_acc;
|
||||
__u64 max_hbm_temperature_acc;
|
||||
|
||||
/* POWER */
|
||||
__u32 socket_power_limit;
|
||||
__u32 max_socket_power_limit;
|
||||
__u32 socket_power;
|
||||
|
||||
/* ENERGY */
|
||||
__u64 timestamp;
|
||||
__u64 socket_energy_acc;
|
||||
__u64 ccd_energy_acc;
|
||||
__u64 xcd_energy_acc;
|
||||
__u64 aid_energy_acc;
|
||||
__u64 hbm_energy_acc;
|
||||
|
||||
/* FREQUENCY */
|
||||
__u32 cclk_frequency_limit;
|
||||
__u32 gfxclk_frequency_limit;
|
||||
__u32 fclk_frequency;
|
||||
__u32 uclk_frequency;
|
||||
__u32 socclk_frequency[4];
|
||||
__u32 vclk_frequency[4];
|
||||
__u32 dclk_frequency[4];
|
||||
__u32 lclk_frequency[4];
|
||||
__u64 gfxclk_frequency_acc[8];
|
||||
__u64 cclk_frequency_acc[96];
|
||||
|
||||
/* FREQUENCY RANGE */
|
||||
__u32 max_cclk_frequency;
|
||||
__u32 min_cclk_frequency;
|
||||
__u32 max_gfxclk_frequency;
|
||||
__u32 min_gfxclk_frequency;
|
||||
__u32 fclk_frequency_table[4];
|
||||
__u32 uclk_frequency_table[4];
|
||||
__u32 socclk_frequency_table[4];
|
||||
__u32 vclk_frequency_table[4];
|
||||
__u32 dclk_frequency_table[4];
|
||||
__u32 lclk_frequency_table[4];
|
||||
__u32 max_lclk_dpm_range;
|
||||
__u32 min_lclk_dpm_range;
|
||||
|
||||
/* XGMI */
|
||||
__u32 xgmi_width;
|
||||
__u32 xgmi_bitrate;
|
||||
__u64 xgmi_read_bandwidth_acc[8];
|
||||
__u64 xgmi_write_bandwidth_acc[8];
|
||||
|
||||
/* ACTIVITY */
|
||||
__u32 socket_c0_residency;
|
||||
__u32 socket_gfx_busy;
|
||||
__u32 dram_bandwidth_utilization;
|
||||
__u64 socket_c0_residency_acc;
|
||||
__u64 socket_gfx_busy_acc;
|
||||
__u64 dram_bandwidth_acc;
|
||||
__u32 max_dram_bandwidth;
|
||||
__u64 dram_bandwidth_utilization_acc;
|
||||
__u64 pcie_bandwidth_acc[4];
|
||||
|
||||
/* THROTTLERS */
|
||||
__u32 prochot_residency_acc;
|
||||
__u32 ppt_residency_acc;
|
||||
__u32 socket_thm_residency_acc;
|
||||
__u32 vr_thm_residency_acc;
|
||||
__u32 hbm_thm_residency_acc;
|
||||
__u32 spare;
|
||||
|
||||
/* New items at the end to maintain driver compatibility */
|
||||
__u32 gfxclk_frequency[8];
|
||||
};
|
||||
|
||||
/* Reset to default packing */
|
||||
|
||||
@@ -2,4 +2,5 @@ CONFIG_KUNIT=y
|
||||
CONFIG_COMMON_CLK=y
|
||||
CONFIG_CLK_KUNIT_TEST=y
|
||||
CONFIG_CLK_GATE_KUNIT_TEST=y
|
||||
CONFIG_CLK_FD_KUNIT_TEST=y
|
||||
CONFIG_UML_PCI_OVER_VIRTIO=n
|
||||
|
||||
@@ -277,6 +277,15 @@ config COMMON_CLK_S2MPS11
|
||||
clock. These multi-function devices have two (S2MPS14) or three
|
||||
(S2MPS11, S5M8767) fixed-rate oscillators, clocked at 32KHz each.
|
||||
|
||||
config CLK_TWL
|
||||
tristate "Clock driver for the TWL PMIC family"
|
||||
depends on TWL4030_CORE
|
||||
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
|
||||
supported.
|
||||
|
||||
config CLK_TWL6040
|
||||
tristate "External McPDM functional clock from twl6040"
|
||||
depends on TWL6040_CORE
|
||||
@@ -517,4 +526,11 @@ config CLK_GATE_KUNIT_TEST
|
||||
help
|
||||
Kunit test for the basic clk gate type.
|
||||
|
||||
config CLK_FD_KUNIT_TEST
|
||||
tristate "Basic fractional divider type Kunit test" if !KUNIT_ALL_TESTS
|
||||
depends on KUNIT
|
||||
default KUNIT_ALL_TESTS
|
||||
help
|
||||
Kunit test for the clk-fractional-divider type.
|
||||
|
||||
endif
|
||||
|
||||
@@ -12,6 +12,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-multiplier.o
|
||||
obj-$(CONFIG_COMMON_CLK) += clk-mux.o
|
||||
obj-$(CONFIG_COMMON_CLK) += clk-composite.o
|
||||
obj-$(CONFIG_COMMON_CLK) += clk-fractional-divider.o
|
||||
obj-$(CONFIG_CLK_FD_KUNIT_TEST) += clk-fractional-divider_test.o
|
||||
obj-$(CONFIG_COMMON_CLK) += clk-gpio.o
|
||||
ifeq ($(CONFIG_OF), y)
|
||||
obj-$(CONFIG_COMMON_CLK) += clk-conf.o
|
||||
@@ -72,6 +73,7 @@ obj-$(CONFIG_COMMON_CLK_STM32H7) += clk-stm32h7.o
|
||||
obj-$(CONFIG_COMMON_CLK_STM32MP157) += clk-stm32mp1.o
|
||||
obj-$(CONFIG_COMMON_CLK_TPS68470) += clk-tps68470.o
|
||||
obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o
|
||||
obj-$(CONFIG_CLK_TWL) += clk-twl.o
|
||||
obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o
|
||||
obj-$(CONFIG_COMMON_CLK_RS9_PCIE) += clk-renesas-pcie.o
|
||||
obj-$(CONFIG_COMMON_CLK_SI521XX) += clk-si521xx.o
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
config CLK_ANALOGBITS_WRPLL_CLN28HPC
|
||||
bool
|
||||
tristate
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <linux/math64.h>
|
||||
#include <linux/math.h>
|
||||
#include <linux/minmax.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/clk/analogbits-wrpll-cln28hpc.h>
|
||||
|
||||
@@ -312,6 +313,7 @@ int wrpll_configure_for_rate(struct wrpll_cfg *c, u32 target_rate,
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wrpll_configure_for_rate);
|
||||
|
||||
/**
|
||||
* wrpll_calc_output_rate() - calculate the PLL's target output rate
|
||||
@@ -349,6 +351,7 @@ unsigned long wrpll_calc_output_rate(const struct wrpll_cfg *c,
|
||||
|
||||
return n;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wrpll_calc_output_rate);
|
||||
|
||||
/**
|
||||
* wrpll_calc_max_lock_us() - return the time for the PLL to lock
|
||||
@@ -366,3 +369,8 @@ unsigned int wrpll_calc_max_lock_us(const struct wrpll_cfg *c)
|
||||
{
|
||||
return MAX_LOCK_US;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wrpll_calc_max_lock_us);
|
||||
|
||||
MODULE_AUTHOR("Paul Walmsley <paul.walmsley@sifive.com>");
|
||||
MODULE_DESCRIPTION("Analog Bits Wide-Range PLL library");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -161,13 +161,11 @@ at91_clk_register_utmi_internal(struct regmap *regmap_pmc,
|
||||
|
||||
init.name = name;
|
||||
init.ops = ops;
|
||||
if (parent_hw) {
|
||||
init.parent_hws = parent_hw ? (const struct clk_hw **)&parent_hw : NULL;
|
||||
init.num_parents = parent_hw ? 1 : 0;
|
||||
} else {
|
||||
init.parent_names = parent_name ? &parent_name : NULL;
|
||||
init.num_parents = parent_name ? 1 : 0;
|
||||
}
|
||||
if (parent_hw)
|
||||
init.parent_hws = (const struct clk_hw **)&parent_hw;
|
||||
else
|
||||
init.parent_names = &parent_name;
|
||||
init.num_parents = 1;
|
||||
init.flags = flags;
|
||||
|
||||
utmi->hw.init = &init;
|
||||
|
||||
@@ -255,7 +255,7 @@ static struct asm9260_mux_clock asm9260_mux_clks[] __initdata = {
|
||||
|
||||
static void __init asm9260_acc_init(struct device_node *np)
|
||||
{
|
||||
struct clk_hw *hw, *pll_hw;
|
||||
struct clk_hw *pll_hw;
|
||||
struct clk_hw **hws;
|
||||
const char *pll_clk = "pll";
|
||||
struct clk_parent_data pll_parent_data = { .index = 0 };
|
||||
@@ -283,7 +283,7 @@ static void __init asm9260_acc_init(struct device_node *np)
|
||||
for (n = 0; n < ARRAY_SIZE(asm9260_mux_clks); n++) {
|
||||
const struct asm9260_mux_clock *mc = &asm9260_mux_clks[n];
|
||||
|
||||
hw = clk_hw_register_mux_table_parent_data(NULL, mc->name, mc->parent_data,
|
||||
clk_hw_register_mux_table_parent_data(NULL, mc->name, mc->parent_data,
|
||||
mc->num_parents, mc->flags, base + mc->offset,
|
||||
0, mc->mask, 0, mc->table, &asm9260_clk_lock);
|
||||
}
|
||||
@@ -292,7 +292,7 @@ static void __init asm9260_acc_init(struct device_node *np)
|
||||
for (n = 0; n < ARRAY_SIZE(asm9260_mux_gates); n++) {
|
||||
const struct asm9260_gate_data *gd = &asm9260_mux_gates[n];
|
||||
|
||||
hw = clk_hw_register_gate(NULL, gd->name,
|
||||
clk_hw_register_gate(NULL, gd->name,
|
||||
gd->parent_name, gd->flags | CLK_SET_RATE_PARENT,
|
||||
base + gd->reg, gd->bit_idx, 0, &asm9260_clk_lock);
|
||||
}
|
||||
|
||||
+36
-31
@@ -25,25 +25,11 @@
|
||||
* Model this as 2 PLL clocks which are parents to the outputs.
|
||||
*/
|
||||
|
||||
enum {
|
||||
CDCE913,
|
||||
CDCE925,
|
||||
CDCE937,
|
||||
CDCE949,
|
||||
};
|
||||
|
||||
struct clk_cdce925_chip_info {
|
||||
int num_plls;
|
||||
int num_outputs;
|
||||
};
|
||||
|
||||
static const struct clk_cdce925_chip_info clk_cdce925_chip_info_tbl[] = {
|
||||
[CDCE913] = { .num_plls = 1, .num_outputs = 3 },
|
||||
[CDCE925] = { .num_plls = 2, .num_outputs = 5 },
|
||||
[CDCE937] = { .num_plls = 3, .num_outputs = 7 },
|
||||
[CDCE949] = { .num_plls = 4, .num_outputs = 9 },
|
||||
};
|
||||
|
||||
#define MAX_NUMBER_OF_PLLS 4
|
||||
#define MAX_NUMBER_OF_OUTPUTS 9
|
||||
|
||||
@@ -621,20 +607,10 @@ static struct regmap_bus regmap_cdce925_bus = {
|
||||
.read = cdce925_regmap_i2c_read,
|
||||
};
|
||||
|
||||
static const struct i2c_device_id cdce925_id[] = {
|
||||
{ "cdce913", CDCE913 },
|
||||
{ "cdce925", CDCE925 },
|
||||
{ "cdce937", CDCE937 },
|
||||
{ "cdce949", CDCE949 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, cdce925_id);
|
||||
|
||||
static int cdce925_probe(struct i2c_client *client)
|
||||
{
|
||||
struct clk_cdce925_chip *data;
|
||||
struct device_node *node = client->dev.of_node;
|
||||
const struct i2c_device_id *id = i2c_match_id(cdce925_id, client);
|
||||
const char *parent_name;
|
||||
const char *pll_clk_name[MAX_NUMBER_OF_PLLS] = {NULL,};
|
||||
struct clk_init_data init;
|
||||
@@ -647,7 +623,7 @@ static int cdce925_probe(struct i2c_client *client)
|
||||
.name = "configuration0",
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.cache_type = REGCACHE_MAPLE,
|
||||
};
|
||||
|
||||
dev_dbg(&client->dev, "%s\n", __func__);
|
||||
@@ -665,7 +641,7 @@ static int cdce925_probe(struct i2c_client *client)
|
||||
return -ENOMEM;
|
||||
|
||||
data->i2c_client = client;
|
||||
data->chip_info = &clk_cdce925_chip_info_tbl[id->driver_data];
|
||||
data->chip_info = i2c_get_match_data(client);
|
||||
config.max_register = CDCE925_OFFSET_PLL +
|
||||
data->chip_info->num_plls * 0x10 - 1;
|
||||
data->regmap = devm_regmap_init(&client->dev, ®map_cdce925_bus,
|
||||
@@ -822,12 +798,41 @@ error:
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct clk_cdce925_chip_info clk_cdce913_info = {
|
||||
.num_plls = 1,
|
||||
.num_outputs = 3,
|
||||
};
|
||||
|
||||
static const struct clk_cdce925_chip_info clk_cdce925_info = {
|
||||
.num_plls = 2,
|
||||
.num_outputs = 5,
|
||||
};
|
||||
|
||||
static const struct clk_cdce925_chip_info clk_cdce937_info = {
|
||||
.num_plls = 3,
|
||||
.num_outputs = 7,
|
||||
};
|
||||
|
||||
static const struct clk_cdce925_chip_info clk_cdce949_info = {
|
||||
.num_plls = 4,
|
||||
.num_outputs = 9,
|
||||
};
|
||||
|
||||
static const struct i2c_device_id cdce925_id[] = {
|
||||
{ "cdce913", (kernel_ulong_t)&clk_cdce913_info },
|
||||
{ "cdce925", (kernel_ulong_t)&clk_cdce925_info },
|
||||
{ "cdce937", (kernel_ulong_t)&clk_cdce937_info },
|
||||
{ "cdce949", (kernel_ulong_t)&clk_cdce949_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, cdce925_id);
|
||||
|
||||
static const struct of_device_id clk_cdce925_of_match[] = {
|
||||
{ .compatible = "ti,cdce913" },
|
||||
{ .compatible = "ti,cdce925" },
|
||||
{ .compatible = "ti,cdce937" },
|
||||
{ .compatible = "ti,cdce949" },
|
||||
{ },
|
||||
{ .compatible = "ti,cdce913", .data = &clk_cdce913_info },
|
||||
{ .compatible = "ti,cdce925", .data = &clk_cdce925_info },
|
||||
{ .compatible = "ti,cdce937", .data = &clk_cdce937_info },
|
||||
{ .compatible = "ti,cdce949", .data = &clk_cdce949_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, clk_cdce925_of_match);
|
||||
|
||||
|
||||
@@ -123,6 +123,7 @@ void clk_fractional_divider_general_approximation(struct clk_hw *hw,
|
||||
unsigned long *m, unsigned long *n)
|
||||
{
|
||||
struct clk_fractional_divider *fd = to_clk_fd(hw);
|
||||
unsigned long max_m, max_n;
|
||||
|
||||
/*
|
||||
* Get rate closer to *parent_rate to guarantee there is no overflow
|
||||
@@ -138,10 +139,17 @@ void clk_fractional_divider_general_approximation(struct clk_hw *hw,
|
||||
rate <<= scale - fd->nwidth;
|
||||
}
|
||||
|
||||
rational_best_approximation(rate, *parent_rate,
|
||||
GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0),
|
||||
m, n);
|
||||
if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) {
|
||||
max_m = 1 << fd->mwidth;
|
||||
max_n = 1 << fd->nwidth;
|
||||
} else {
|
||||
max_m = GENMASK(fd->mwidth - 1, 0);
|
||||
max_n = GENMASK(fd->nwidth - 1, 0);
|
||||
}
|
||||
|
||||
rational_best_approximation(rate, *parent_rate, max_m, max_n, m, n);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_fractional_divider_general_approximation);
|
||||
|
||||
static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
@@ -169,13 +177,18 @@ static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
{
|
||||
struct clk_fractional_divider *fd = to_clk_fd(hw);
|
||||
unsigned long flags = 0;
|
||||
unsigned long m, n;
|
||||
unsigned long m, n, max_m, max_n;
|
||||
u32 mmask, nmask;
|
||||
u32 val;
|
||||
|
||||
rational_best_approximation(rate, parent_rate,
|
||||
GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0),
|
||||
&m, &n);
|
||||
if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) {
|
||||
max_m = 1 << fd->mwidth;
|
||||
max_n = 1 << fd->nwidth;
|
||||
} else {
|
||||
max_m = GENMASK(fd->mwidth - 1, 0);
|
||||
max_n = GENMASK(fd->nwidth - 1, 0);
|
||||
}
|
||||
rational_best_approximation(rate, parent_rate, max_m, max_n, &m, &n);
|
||||
|
||||
if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) {
|
||||
m--;
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Kunit test for clock fractional divider
|
||||
*/
|
||||
#include <linux/clk-provider.h>
|
||||
#include <kunit/test.h>
|
||||
|
||||
#include "clk-fractional-divider.h"
|
||||
|
||||
/*
|
||||
* Test the maximum denominator case for fd clock without flags.
|
||||
*
|
||||
* Expect the highest possible denominator to be used in order to get as close as possible to the
|
||||
* requested rate.
|
||||
*/
|
||||
static void clk_fd_test_approximation_max_denominator(struct kunit *test)
|
||||
{
|
||||
struct clk_fractional_divider *fd;
|
||||
unsigned long rate, parent_rate, parent_rate_before, m, n, max_n;
|
||||
|
||||
fd = kunit_kzalloc(test, sizeof(*fd), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, fd);
|
||||
|
||||
fd->mwidth = 3;
|
||||
fd->nwidth = 3;
|
||||
max_n = 7;
|
||||
|
||||
rate = 240000000;
|
||||
parent_rate = (max_n + 1) * rate; /* so that it exceeds the maximum divisor */
|
||||
parent_rate_before = parent_rate;
|
||||
|
||||
clk_fractional_divider_general_approximation(&fd->hw, rate, &parent_rate, &m, &n);
|
||||
KUNIT_ASSERT_EQ(test, parent_rate, parent_rate_before);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, m, 1);
|
||||
KUNIT_EXPECT_EQ(test, n, max_n);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test the maximum numerator case for fd clock without flags.
|
||||
*
|
||||
* Expect the highest possible numerator to be used in order to get as close as possible to the
|
||||
* requested rate.
|
||||
*/
|
||||
static void clk_fd_test_approximation_max_numerator(struct kunit *test)
|
||||
{
|
||||
struct clk_fractional_divider *fd;
|
||||
unsigned long rate, parent_rate, parent_rate_before, m, n, max_m;
|
||||
|
||||
fd = kunit_kzalloc(test, sizeof(*fd), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, fd);
|
||||
|
||||
fd->mwidth = 3;
|
||||
max_m = 7;
|
||||
fd->nwidth = 3;
|
||||
|
||||
rate = 240000000;
|
||||
parent_rate = rate / (max_m + 1); /* so that it exceeds the maximum numerator */
|
||||
parent_rate_before = parent_rate;
|
||||
|
||||
clk_fractional_divider_general_approximation(&fd->hw, rate, &parent_rate, &m, &n);
|
||||
KUNIT_ASSERT_EQ(test, parent_rate, parent_rate_before);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, m, max_m);
|
||||
KUNIT_EXPECT_EQ(test, n, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test the maximum denominator case for zero based fd clock.
|
||||
*
|
||||
* Expect the highest possible denominator to be used in order to get as close as possible to the
|
||||
* requested rate.
|
||||
*/
|
||||
static void clk_fd_test_approximation_max_denominator_zero_based(struct kunit *test)
|
||||
{
|
||||
struct clk_fractional_divider *fd;
|
||||
unsigned long rate, parent_rate, parent_rate_before, m, n, max_n;
|
||||
|
||||
fd = kunit_kzalloc(test, sizeof(*fd), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, fd);
|
||||
|
||||
fd->flags = CLK_FRAC_DIVIDER_ZERO_BASED;
|
||||
fd->mwidth = 3;
|
||||
fd->nwidth = 3;
|
||||
max_n = 8;
|
||||
|
||||
rate = 240000000;
|
||||
parent_rate = (max_n + 1) * rate; /* so that it exceeds the maximum divisor */
|
||||
parent_rate_before = parent_rate;
|
||||
|
||||
clk_fractional_divider_general_approximation(&fd->hw, rate, &parent_rate, &m, &n);
|
||||
KUNIT_ASSERT_EQ(test, parent_rate, parent_rate_before);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, m, 1);
|
||||
KUNIT_EXPECT_EQ(test, n, max_n);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test the maximum numerator case for zero based fd clock.
|
||||
*
|
||||
* Expect the highest possible numerator to be used in order to get as close as possible to the
|
||||
* requested rate.
|
||||
*/
|
||||
static void clk_fd_test_approximation_max_numerator_zero_based(struct kunit *test)
|
||||
{
|
||||
struct clk_fractional_divider *fd;
|
||||
unsigned long rate, parent_rate, parent_rate_before, m, n, max_m;
|
||||
|
||||
fd = kunit_kzalloc(test, sizeof(*fd), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, fd);
|
||||
|
||||
fd->flags = CLK_FRAC_DIVIDER_ZERO_BASED;
|
||||
fd->mwidth = 3;
|
||||
max_m = 8;
|
||||
fd->nwidth = 3;
|
||||
|
||||
rate = 240000000;
|
||||
parent_rate = rate / (max_m + 1); /* so that it exceeds the maximum numerator */
|
||||
parent_rate_before = parent_rate;
|
||||
|
||||
clk_fractional_divider_general_approximation(&fd->hw, rate, &parent_rate, &m, &n);
|
||||
KUNIT_ASSERT_EQ(test, parent_rate, parent_rate_before);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, m, max_m);
|
||||
KUNIT_EXPECT_EQ(test, n, 1);
|
||||
}
|
||||
|
||||
static struct kunit_case clk_fd_approximation_test_cases[] = {
|
||||
KUNIT_CASE(clk_fd_test_approximation_max_denominator),
|
||||
KUNIT_CASE(clk_fd_test_approximation_max_numerator),
|
||||
KUNIT_CASE(clk_fd_test_approximation_max_denominator_zero_based),
|
||||
KUNIT_CASE(clk_fd_test_approximation_max_numerator_zero_based),
|
||||
{}
|
||||
};
|
||||
|
||||
/*
|
||||
* Test suite for clk_fractional_divider_general_approximation().
|
||||
*/
|
||||
static struct kunit_suite clk_fd_approximation_suite = {
|
||||
.name = "clk-fd-approximation",
|
||||
.test_cases = clk_fd_approximation_test_cases,
|
||||
};
|
||||
|
||||
kunit_test_suites(
|
||||
&clk_fd_approximation_suite
|
||||
);
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -15,7 +15,7 @@
|
||||
#include <linux/string.h>
|
||||
|
||||
/**
|
||||
* DOC: basic gatable clock which can gate and ungate it's ouput
|
||||
* DOC: basic gatable clock which can gate and ungate its output
|
||||
*
|
||||
* Traits of this clock:
|
||||
* prepare - clk_(un)prepare only ensures parent is (un)prepared
|
||||
|
||||
+15
-15
@@ -131,7 +131,7 @@ struct clk_gate_test_context {
|
||||
void __iomem *fake_mem;
|
||||
struct clk_hw *hw;
|
||||
struct clk_hw *parent;
|
||||
u32 fake_reg; /* Keep at end, KASAN can detect out of bounds */
|
||||
__le32 fake_reg; /* Keep at end, KASAN can detect out of bounds */
|
||||
};
|
||||
|
||||
static struct clk_gate_test_context *clk_gate_test_alloc_ctx(struct kunit *test)
|
||||
@@ -166,7 +166,7 @@ static void clk_gate_test_enable(struct kunit *test)
|
||||
|
||||
KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, enable_val, ctx->fake_reg);
|
||||
KUNIT_EXPECT_EQ(test, enable_val, le32_to_cpu(ctx->fake_reg));
|
||||
KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(hw));
|
||||
KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(hw));
|
||||
KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(parent));
|
||||
@@ -183,10 +183,10 @@ static void clk_gate_test_disable(struct kunit *test)
|
||||
u32 disable_val = 0;
|
||||
|
||||
KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0);
|
||||
KUNIT_ASSERT_EQ(test, enable_val, ctx->fake_reg);
|
||||
KUNIT_ASSERT_EQ(test, enable_val, le32_to_cpu(ctx->fake_reg));
|
||||
|
||||
clk_disable_unprepare(clk);
|
||||
KUNIT_EXPECT_EQ(test, disable_val, ctx->fake_reg);
|
||||
KUNIT_EXPECT_EQ(test, disable_val, le32_to_cpu(ctx->fake_reg));
|
||||
KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(hw));
|
||||
KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(hw));
|
||||
KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(parent));
|
||||
@@ -246,7 +246,7 @@ static void clk_gate_test_invert_enable(struct kunit *test)
|
||||
|
||||
KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, enable_val, ctx->fake_reg);
|
||||
KUNIT_EXPECT_EQ(test, enable_val, le32_to_cpu(ctx->fake_reg));
|
||||
KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(hw));
|
||||
KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(hw));
|
||||
KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(parent));
|
||||
@@ -263,10 +263,10 @@ static void clk_gate_test_invert_disable(struct kunit *test)
|
||||
u32 disable_val = BIT(15);
|
||||
|
||||
KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0);
|
||||
KUNIT_ASSERT_EQ(test, enable_val, ctx->fake_reg);
|
||||
KUNIT_ASSERT_EQ(test, enable_val, le32_to_cpu(ctx->fake_reg));
|
||||
|
||||
clk_disable_unprepare(clk);
|
||||
KUNIT_EXPECT_EQ(test, disable_val, ctx->fake_reg);
|
||||
KUNIT_EXPECT_EQ(test, disable_val, le32_to_cpu(ctx->fake_reg));
|
||||
KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(hw));
|
||||
KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(hw));
|
||||
KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(parent));
|
||||
@@ -290,7 +290,7 @@ static int clk_gate_test_invert_init(struct kunit *test)
|
||||
2000000);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent);
|
||||
|
||||
ctx->fake_reg = BIT(15); /* Default to off */
|
||||
ctx->fake_reg = cpu_to_le32(BIT(15)); /* Default to off */
|
||||
hw = clk_hw_register_gate_parent_hw(NULL, "test_gate", parent, 0,
|
||||
ctx->fake_mem, 15,
|
||||
CLK_GATE_SET_TO_DISABLE, NULL);
|
||||
@@ -319,7 +319,7 @@ static void clk_gate_test_hiword_enable(struct kunit *test)
|
||||
|
||||
KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, enable_val, ctx->fake_reg);
|
||||
KUNIT_EXPECT_EQ(test, enable_val, le32_to_cpu(ctx->fake_reg));
|
||||
KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(hw));
|
||||
KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(hw));
|
||||
KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(parent));
|
||||
@@ -336,10 +336,10 @@ static void clk_gate_test_hiword_disable(struct kunit *test)
|
||||
u32 disable_val = BIT(9 + 16);
|
||||
|
||||
KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0);
|
||||
KUNIT_ASSERT_EQ(test, enable_val, ctx->fake_reg);
|
||||
KUNIT_ASSERT_EQ(test, enable_val, le32_to_cpu(ctx->fake_reg));
|
||||
|
||||
clk_disable_unprepare(clk);
|
||||
KUNIT_EXPECT_EQ(test, disable_val, ctx->fake_reg);
|
||||
KUNIT_EXPECT_EQ(test, disable_val, le32_to_cpu(ctx->fake_reg));
|
||||
KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(hw));
|
||||
KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(hw));
|
||||
KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(parent));
|
||||
@@ -387,7 +387,7 @@ static void clk_gate_test_is_enabled(struct kunit *test)
|
||||
struct clk_gate_test_context *ctx;
|
||||
|
||||
ctx = clk_gate_test_alloc_ctx(test);
|
||||
ctx->fake_reg = BIT(7);
|
||||
ctx->fake_reg = cpu_to_le32(BIT(7));
|
||||
hw = clk_hw_register_gate(NULL, "test_gate", NULL, 0, ctx->fake_mem, 7,
|
||||
0, NULL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
|
||||
@@ -402,7 +402,7 @@ static void clk_gate_test_is_disabled(struct kunit *test)
|
||||
struct clk_gate_test_context *ctx;
|
||||
|
||||
ctx = clk_gate_test_alloc_ctx(test);
|
||||
ctx->fake_reg = BIT(4);
|
||||
ctx->fake_reg = cpu_to_le32(BIT(4));
|
||||
hw = clk_hw_register_gate(NULL, "test_gate", NULL, 0, ctx->fake_mem, 7,
|
||||
0, NULL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
|
||||
@@ -417,7 +417,7 @@ static void clk_gate_test_is_enabled_inverted(struct kunit *test)
|
||||
struct clk_gate_test_context *ctx;
|
||||
|
||||
ctx = clk_gate_test_alloc_ctx(test);
|
||||
ctx->fake_reg = BIT(31);
|
||||
ctx->fake_reg = cpu_to_le32(BIT(31));
|
||||
hw = clk_hw_register_gate(NULL, "test_gate", NULL, 0, ctx->fake_mem, 2,
|
||||
CLK_GATE_SET_TO_DISABLE, NULL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
|
||||
@@ -432,7 +432,7 @@ static void clk_gate_test_is_disabled_inverted(struct kunit *test)
|
||||
struct clk_gate_test_context *ctx;
|
||||
|
||||
ctx = clk_gate_test_alloc_ctx(test);
|
||||
ctx->fake_reg = BIT(29);
|
||||
ctx->fake_reg = cpu_to_le32(BIT(29));
|
||||
hw = clk_hw_register_gate(NULL, "test_gate", NULL, 0, ctx->fake_mem, 29,
|
||||
CLK_GATE_SET_TO_DISABLE, NULL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include <linux/mfd/lochnagar1_regs.h>
|
||||
@@ -242,22 +242,17 @@ static int lochnagar_clk_probe(struct platform_device *pdev)
|
||||
};
|
||||
struct device *dev = &pdev->dev;
|
||||
struct lochnagar_clk_priv *priv;
|
||||
const struct of_device_id *of_id;
|
||||
struct lochnagar_clk *lclk;
|
||||
struct lochnagar_config *conf;
|
||||
int ret, i;
|
||||
|
||||
of_id = of_match_device(lochnagar_of_match, dev);
|
||||
if (!of_id)
|
||||
return -EINVAL;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->dev = dev;
|
||||
priv->regmap = dev_get_regmap(dev->parent, NULL);
|
||||
conf = (struct lochnagar_config *)of_id->data;
|
||||
conf = (struct lochnagar_config *)device_get_match_data(dev);
|
||||
|
||||
memcpy(priv->lclks, conf->clks, sizeof(priv->lclks));
|
||||
|
||||
|
||||
@@ -510,7 +510,7 @@ static void __init npcm7xx_clk_init(struct device_node *clk_np)
|
||||
return;
|
||||
|
||||
npcm7xx_init_fail:
|
||||
kfree(npcm7xx_clk_data->hws);
|
||||
kfree(npcm7xx_clk_data);
|
||||
npcm7xx_init_np_err:
|
||||
iounmap(clk_base);
|
||||
npcm7xx_init_error:
|
||||
|
||||
@@ -298,7 +298,7 @@ static int rs9_probe(struct i2c_client *client)
|
||||
|
||||
i2c_set_clientdata(client, rs9);
|
||||
rs9->client = client;
|
||||
rs9->chip_info = device_get_match_data(&client->dev);
|
||||
rs9->chip_info = i2c_get_match_data(client);
|
||||
if (!rs9->chip_info)
|
||||
return -EINVAL;
|
||||
|
||||
|
||||
@@ -321,7 +321,7 @@ static bool si514_regmap_is_writeable(struct device *dev, unsigned int reg)
|
||||
static const struct regmap_config si514_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.cache_type = REGCACHE_MAPLE,
|
||||
.max_register = SI514_REG_CONTROL,
|
||||
.writeable_reg = si514_regmap_is_writeable,
|
||||
.volatile_reg = si514_regmap_is_volatile,
|
||||
|
||||
@@ -279,10 +279,10 @@ si521xx_of_clk_get(struct of_phandle_args *clkspec, void *data)
|
||||
|
||||
static int si521xx_probe(struct i2c_client *client)
|
||||
{
|
||||
const u16 chip_info = (u16)(uintptr_t)device_get_match_data(&client->dev);
|
||||
const u16 chip_info = (u16)(uintptr_t)i2c_get_match_data(client);
|
||||
const struct clk_parent_data clk_parent_data = { .index = 0 };
|
||||
const u8 data[3] = { SI521XX_REG_BC, 1, 1 };
|
||||
unsigned char name[6] = "DIFF0";
|
||||
unsigned char name[16] = "DIFF0";
|
||||
struct clk_init_data init = {};
|
||||
struct si521xx *si;
|
||||
int i, ret;
|
||||
@@ -316,7 +316,7 @@ static int si521xx_probe(struct i2c_client *client)
|
||||
/* Register clock */
|
||||
for (i = 0; i < hweight16(chip_info); i++) {
|
||||
memset(&init, 0, sizeof(init));
|
||||
snprintf(name, 6, "DIFF%d", i);
|
||||
snprintf(name, sizeof(name), "DIFF%d", i);
|
||||
init.name = name;
|
||||
init.ops = &si521xx_diff_clk_ops;
|
||||
init.parent_data = &clk_parent_data;
|
||||
|
||||
@@ -1260,7 +1260,7 @@ static int si5341_wait_device_ready(struct i2c_client *client)
|
||||
static const struct regmap_config si5341_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.cache_type = REGCACHE_MAPLE,
|
||||
.ranges = si5341_regmap_ranges,
|
||||
.num_ranges = ARRAY_SIZE(si5341_regmap_ranges),
|
||||
.max_register = SI5341_REGISTER_MAX,
|
||||
|
||||
@@ -206,7 +206,7 @@ static bool si5351_regmap_is_writeable(struct device *dev, unsigned int reg)
|
||||
static const struct regmap_config si5351_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.cache_type = REGCACHE_MAPLE,
|
||||
.max_register = 187,
|
||||
.writeable_reg = si5351_regmap_is_writeable,
|
||||
.volatile_reg = si5351_regmap_is_volatile,
|
||||
@@ -1385,8 +1385,7 @@ MODULE_DEVICE_TABLE(i2c, si5351_i2c_ids);
|
||||
|
||||
static int si5351_i2c_probe(struct i2c_client *client)
|
||||
{
|
||||
const struct i2c_device_id *id = i2c_match_id(si5351_i2c_ids, client);
|
||||
enum si5351_variant variant = (enum si5351_variant)id->driver_data;
|
||||
enum si5351_variant variant;
|
||||
struct si5351_platform_data *pdata;
|
||||
struct si5351_driver_data *drvdata;
|
||||
struct clk_init_data init;
|
||||
@@ -1394,6 +1393,7 @@ static int si5351_i2c_probe(struct i2c_client *client)
|
||||
u8 num_parents, num_clocks;
|
||||
int ret, n;
|
||||
|
||||
variant = (enum si5351_variant)(uintptr_t)i2c_get_match_data(client);
|
||||
ret = si5351_dt_parse(client, variant);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
+16
-37
@@ -56,17 +56,11 @@
|
||||
#define DELTA_M_FRAC_NUM 19
|
||||
#define DELTA_M_FRAC_DEN 20000
|
||||
|
||||
enum si544_speed_grade {
|
||||
si544a,
|
||||
si544b,
|
||||
si544c,
|
||||
};
|
||||
|
||||
struct clk_si544 {
|
||||
struct clk_hw hw;
|
||||
struct regmap *regmap;
|
||||
struct i2c_client *i2c_client;
|
||||
enum si544_speed_grade speed_grade;
|
||||
unsigned long max_freq;
|
||||
};
|
||||
#define to_clk_si544(_hw) container_of(_hw, struct clk_si544, hw)
|
||||
|
||||
@@ -196,24 +190,10 @@ static int si544_set_muldiv(struct clk_si544 *data,
|
||||
static bool is_valid_frequency(const struct clk_si544 *data,
|
||||
unsigned long frequency)
|
||||
{
|
||||
unsigned long max_freq = 0;
|
||||
|
||||
if (frequency < SI544_MIN_FREQ)
|
||||
return false;
|
||||
|
||||
switch (data->speed_grade) {
|
||||
case si544a:
|
||||
max_freq = 1500000000;
|
||||
break;
|
||||
case si544b:
|
||||
max_freq = 800000000;
|
||||
break;
|
||||
case si544c:
|
||||
max_freq = 350000000;
|
||||
break;
|
||||
}
|
||||
|
||||
return frequency <= max_freq;
|
||||
return frequency <= data->max_freq;
|
||||
}
|
||||
|
||||
/* Calculate divider settings for a given frequency */
|
||||
@@ -446,24 +426,15 @@ static bool si544_regmap_is_volatile(struct device *dev, unsigned int reg)
|
||||
static const struct regmap_config si544_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.cache_type = REGCACHE_MAPLE,
|
||||
.max_register = SI544_REG_PAGE_SELECT,
|
||||
.volatile_reg = si544_regmap_is_volatile,
|
||||
};
|
||||
|
||||
static const struct i2c_device_id si544_id[] = {
|
||||
{ "si544a", si544a },
|
||||
{ "si544b", si544b },
|
||||
{ "si544c", si544c },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, si544_id);
|
||||
|
||||
static int si544_probe(struct i2c_client *client)
|
||||
{
|
||||
struct clk_si544 *data;
|
||||
struct clk_init_data init;
|
||||
const struct i2c_device_id *id = i2c_match_id(si544_id, client);
|
||||
int err;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
|
||||
@@ -475,7 +446,7 @@ static int si544_probe(struct i2c_client *client)
|
||||
init.num_parents = 0;
|
||||
data->hw.init = &init;
|
||||
data->i2c_client = client;
|
||||
data->speed_grade = id->driver_data;
|
||||
data->max_freq = (uintptr_t)i2c_get_match_data(client);
|
||||
|
||||
if (of_property_read_string(client->dev.of_node, "clock-output-names",
|
||||
&init.name))
|
||||
@@ -507,11 +478,19 @@ static int si544_probe(struct i2c_client *client)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id si544_id[] = {
|
||||
{ "si544a", 1500000000 },
|
||||
{ "si544b", 800000000 },
|
||||
{ "si544c", 350000000 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, si544_id);
|
||||
|
||||
static const struct of_device_id clk_si544_of_match[] = {
|
||||
{ .compatible = "silabs,si544a" },
|
||||
{ .compatible = "silabs,si544b" },
|
||||
{ .compatible = "silabs,si544c" },
|
||||
{ },
|
||||
{ .compatible = "silabs,si544a", .data = (void *)1500000000 },
|
||||
{ .compatible = "silabs,si544b", .data = (void *)800000000 },
|
||||
{ .compatible = "silabs,si544c", .data = (void *)350000000 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, clk_si544_of_match);
|
||||
|
||||
|
||||
+39
-30
@@ -49,12 +49,22 @@
|
||||
|
||||
#define SI570_FREEZE_DCO (1 << 4)
|
||||
|
||||
/**
|
||||
* struct clk_si570_info:
|
||||
* @max_freq: Maximum frequency for this device
|
||||
* @has_temperature_stability: Device support temperature stability
|
||||
*/
|
||||
struct clk_si570_info {
|
||||
u64 max_freq;
|
||||
bool has_temperature_stability;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct clk_si570:
|
||||
* @hw: Clock hw struct
|
||||
* @regmap: Device's regmap
|
||||
* @div_offset: Rgister offset for dividers
|
||||
* @max_freq: Maximum frequency for this device
|
||||
* @info: Device info
|
||||
* @fxtal: Factory xtal frequency
|
||||
* @n1: Clock divider N1
|
||||
* @hs_div: Clock divider HSDIV
|
||||
@@ -66,7 +76,7 @@ struct clk_si570 {
|
||||
struct clk_hw hw;
|
||||
struct regmap *regmap;
|
||||
unsigned int div_offset;
|
||||
u64 max_freq;
|
||||
const struct clk_si570_info *info;
|
||||
u64 fxtal;
|
||||
unsigned int n1;
|
||||
unsigned int hs_div;
|
||||
@@ -76,11 +86,6 @@ struct clk_si570 {
|
||||
};
|
||||
#define to_clk_si570(_hw) container_of(_hw, struct clk_si570, hw)
|
||||
|
||||
enum clk_si570_variant {
|
||||
si57x,
|
||||
si59x
|
||||
};
|
||||
|
||||
/**
|
||||
* si570_get_divs() - Read clock dividers from HW
|
||||
* @data: Pointer to struct clk_si570
|
||||
@@ -341,7 +346,7 @@ static int si570_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
struct i2c_client *client = data->i2c_client;
|
||||
int err;
|
||||
|
||||
if (rate < SI570_MIN_FREQ || rate > data->max_freq) {
|
||||
if (rate < SI570_MIN_FREQ || rate > data->info->max_freq) {
|
||||
dev_err(&client->dev,
|
||||
"requested frequency %lu Hz is out of range\n", rate);
|
||||
return -EINVAL;
|
||||
@@ -392,30 +397,19 @@ static bool si570_regmap_is_writeable(struct device *dev, unsigned int reg)
|
||||
static const struct regmap_config si570_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.cache_type = REGCACHE_MAPLE,
|
||||
.max_register = 137,
|
||||
.writeable_reg = si570_regmap_is_writeable,
|
||||
.volatile_reg = si570_regmap_is_volatile,
|
||||
};
|
||||
|
||||
static const struct i2c_device_id si570_id[] = {
|
||||
{ "si570", si57x },
|
||||
{ "si571", si57x },
|
||||
{ "si598", si59x },
|
||||
{ "si599", si59x },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, si570_id);
|
||||
|
||||
static int si570_probe(struct i2c_client *client)
|
||||
{
|
||||
struct clk_si570 *data;
|
||||
struct clk_init_data init;
|
||||
const struct i2c_device_id *id = i2c_match_id(si570_id, client);
|
||||
u32 initial_fout, factory_fout, stability;
|
||||
bool skip_recall;
|
||||
int err;
|
||||
enum clk_si570_variant variant = id->driver_data;
|
||||
|
||||
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
@@ -427,7 +421,8 @@ static int si570_probe(struct i2c_client *client)
|
||||
data->hw.init = &init;
|
||||
data->i2c_client = client;
|
||||
|
||||
if (variant == si57x) {
|
||||
data->info = i2c_get_match_data(client);
|
||||
if (data->info->has_temperature_stability) {
|
||||
err = of_property_read_u32(client->dev.of_node,
|
||||
"temperature-stability", &stability);
|
||||
if (err) {
|
||||
@@ -438,10 +433,6 @@ static int si570_probe(struct i2c_client *client)
|
||||
/* adjust register offsets for 7ppm devices */
|
||||
if (stability == 7)
|
||||
data->div_offset = SI570_DIV_OFFSET_7PPM;
|
||||
|
||||
data->max_freq = SI570_MAX_FREQ;
|
||||
} else {
|
||||
data->max_freq = SI598_MAX_FREQ;
|
||||
}
|
||||
|
||||
if (of_property_read_string(client->dev.of_node, "clock-output-names",
|
||||
@@ -496,12 +487,30 @@ static int si570_probe(struct i2c_client *client)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct clk_si570_info clk_si570_info = {
|
||||
.max_freq = SI570_MAX_FREQ,
|
||||
.has_temperature_stability = true,
|
||||
};
|
||||
|
||||
static const struct clk_si570_info clk_si590_info = {
|
||||
.max_freq = SI598_MAX_FREQ,
|
||||
};
|
||||
|
||||
static const struct i2c_device_id si570_id[] = {
|
||||
{ "si570", (kernel_ulong_t)&clk_si570_info },
|
||||
{ "si571", (kernel_ulong_t)&clk_si570_info },
|
||||
{ "si598", (kernel_ulong_t)&clk_si590_info },
|
||||
{ "si599", (kernel_ulong_t)&clk_si590_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, si570_id);
|
||||
|
||||
static const struct of_device_id clk_si570_of_match[] = {
|
||||
{ .compatible = "silabs,si570" },
|
||||
{ .compatible = "silabs,si571" },
|
||||
{ .compatible = "silabs,si598" },
|
||||
{ .compatible = "silabs,si599" },
|
||||
{ },
|
||||
{ .compatible = "silabs,si570", .data = &clk_si570_info },
|
||||
{ .compatible = "silabs,si571", .data = &clk_si570_info },
|
||||
{ .compatible = "silabs,si598", .data = &clk_si590_info },
|
||||
{ .compatible = "silabs,si599", .data = &clk_si590_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, clk_si570_of_match);
|
||||
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Clock driver for twl device.
|
||||
*
|
||||
* inspired by the driver for the Palmas device
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/mfd/twl.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define VREG_STATE 2
|
||||
#define TWL6030_CFG_STATE_OFF 0x00
|
||||
#define TWL6030_CFG_STATE_ON 0x01
|
||||
#define TWL6030_CFG_STATE_MASK 0x03
|
||||
|
||||
struct twl_clock_info {
|
||||
struct device *dev;
|
||||
u8 base;
|
||||
struct clk_hw hw;
|
||||
};
|
||||
|
||||
static inline int
|
||||
twlclk_read(struct twl_clock_info *info, unsigned int slave_subgp,
|
||||
unsigned int offset)
|
||||
{
|
||||
u8 value;
|
||||
int status;
|
||||
|
||||
status = twl_i2c_read_u8(slave_subgp, &value,
|
||||
info->base + offset);
|
||||
return (status < 0) ? status : value;
|
||||
}
|
||||
|
||||
static inline int
|
||||
twlclk_write(struct twl_clock_info *info, unsigned int slave_subgp,
|
||||
unsigned int offset, u8 value)
|
||||
{
|
||||
return twl_i2c_write_u8(slave_subgp, value,
|
||||
info->base + offset);
|
||||
}
|
||||
|
||||
static inline struct twl_clock_info *to_twl_clks_info(struct clk_hw *hw)
|
||||
{
|
||||
return container_of(hw, struct twl_clock_info, hw);
|
||||
}
|
||||
|
||||
static unsigned long twl_clks_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
return 32768;
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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 (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,
|
||||
};
|
||||
|
||||
struct twl_clks_data {
|
||||
struct clk_init_data init;
|
||||
u8 base;
|
||||
};
|
||||
|
||||
static const struct twl_clks_data twl6032_clks[] = {
|
||||
{
|
||||
.init = {
|
||||
.name = "clk32kg",
|
||||
.ops = &twl6032_clks_ops,
|
||||
.flags = CLK_IGNORE_UNUSED,
|
||||
},
|
||||
.base = 0x8C,
|
||||
},
|
||||
{
|
||||
.init = {
|
||||
.name = "clk32kaudio",
|
||||
.ops = &twl6032_clks_ops,
|
||||
.flags = CLK_IGNORE_UNUSED,
|
||||
},
|
||||
.base = 0x8F,
|
||||
},
|
||||
{
|
||||
/* sentinel */
|
||||
}
|
||||
};
|
||||
|
||||
static int twl_clks_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct clk_hw_onecell_data *clk_data;
|
||||
const struct twl_clks_data *hw_data;
|
||||
|
||||
struct twl_clock_info *cinfo;
|
||||
int ret;
|
||||
int i;
|
||||
int count;
|
||||
|
||||
hw_data = twl6032_clks;
|
||||
for (count = 0; hw_data[count].init.name; count++)
|
||||
;
|
||||
|
||||
clk_data = devm_kzalloc(&pdev->dev,
|
||||
struct_size(clk_data, hws, count),
|
||||
GFP_KERNEL);
|
||||
if (!clk_data)
|
||||
return -ENOMEM;
|
||||
|
||||
clk_data->num = count;
|
||||
cinfo = devm_kcalloc(&pdev->dev, count, sizeof(*cinfo), GFP_KERNEL);
|
||||
if (!cinfo)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
cinfo[i].base = hw_data[i].base;
|
||||
cinfo[i].dev = &pdev->dev;
|
||||
cinfo[i].hw.init = &hw_data[i].init;
|
||||
ret = devm_clk_hw_register(&pdev->dev, &cinfo[i].hw);
|
||||
if (ret) {
|
||||
return dev_err_probe(&pdev->dev, ret,
|
||||
"Fail to register clock %s\n",
|
||||
hw_data[i].init.name);
|
||||
}
|
||||
clk_data->hws[i] = &cinfo[i].hw;
|
||||
}
|
||||
|
||||
ret = devm_of_clk_add_hw_provider(&pdev->dev,
|
||||
of_clk_hw_onecell_get, clk_data);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&pdev->dev, ret,
|
||||
"Fail to add clock driver\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct platform_device_id twl_clks_id[] = {
|
||||
{
|
||||
.name = "twl6032-clk",
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, twl_clks_id);
|
||||
|
||||
static struct platform_driver twl_clks_driver = {
|
||||
.driver = {
|
||||
.name = "twl-clk",
|
||||
},
|
||||
.probe = twl_clks_probe,
|
||||
.id_table = twl_clks_id,
|
||||
};
|
||||
|
||||
module_platform_driver(twl_clks_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Clock driver for TWL Series Devices");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -585,17 +585,11 @@ static const struct clk_ops vc3_clk_mux_ops = {
|
||||
.get_parent = vc3_clk_mux_get_parent,
|
||||
};
|
||||
|
||||
static bool vc3_regmap_is_writeable(struct device *dev, unsigned int reg)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static const struct regmap_config vc3_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.cache_type = REGCACHE_MAPLE,
|
||||
.max_register = 0x24,
|
||||
.writeable_reg = vc3_regmap_is_writeable,
|
||||
};
|
||||
|
||||
static struct vc3_hw_data clk_div[5];
|
||||
|
||||
@@ -217,7 +217,7 @@ static bool vc5_regmap_is_writeable(struct device *dev, unsigned int reg)
|
||||
static const struct regmap_config vc5_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.cache_type = REGCACHE_MAPLE,
|
||||
.max_register = 0x76,
|
||||
.writeable_reg = vc5_regmap_is_writeable,
|
||||
};
|
||||
|
||||
@@ -1275,7 +1275,7 @@ static const struct regmap_config vc7_regmap_config = {
|
||||
.ranges = vc7_range_cfg,
|
||||
.num_ranges = ARRAY_SIZE(vc7_range_cfg),
|
||||
.volatile_reg = vc7_volatile_reg,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.cache_type = REGCACHE_MAPLE,
|
||||
.can_multi_write = true,
|
||||
.reg_format_endian = REGMAP_ENDIAN_LITTLE,
|
||||
.val_format_endian = REGMAP_ENDIAN_LITTLE,
|
||||
|
||||
+54
-11
@@ -3267,28 +3267,41 @@ static void clk_summary_show_one(struct seq_file *s, struct clk_core *c,
|
||||
int level)
|
||||
{
|
||||
int phase;
|
||||
struct clk *clk_user;
|
||||
int multi_node = 0;
|
||||
|
||||
seq_printf(s, "%*s%-*s %7d %8d %8d %11lu %10lu ",
|
||||
seq_printf(s, "%*s%-*s %-7d %-8d %-8d %-11lu %-10lu ",
|
||||
level * 3 + 1, "",
|
||||
30 - level * 3, c->name,
|
||||
35 - level * 3, c->name,
|
||||
c->enable_count, c->prepare_count, c->protect_count,
|
||||
clk_core_get_rate_recalc(c),
|
||||
clk_core_get_accuracy_recalc(c));
|
||||
|
||||
phase = clk_core_get_phase(c);
|
||||
if (phase >= 0)
|
||||
seq_printf(s, "%5d", phase);
|
||||
seq_printf(s, "%-5d", phase);
|
||||
else
|
||||
seq_puts(s, "-----");
|
||||
|
||||
seq_printf(s, " %6d", clk_core_get_scaled_duty_cycle(c, 100000));
|
||||
seq_printf(s, " %-6d", clk_core_get_scaled_duty_cycle(c, 100000));
|
||||
|
||||
if (c->ops->is_enabled)
|
||||
seq_printf(s, " %9c\n", clk_core_is_enabled(c) ? 'Y' : 'N');
|
||||
seq_printf(s, " %5c ", clk_core_is_enabled(c) ? 'Y' : 'N');
|
||||
else if (!c->ops->enable)
|
||||
seq_printf(s, " %9c\n", 'Y');
|
||||
seq_printf(s, " %5c ", 'Y');
|
||||
else
|
||||
seq_printf(s, " %9c\n", '?');
|
||||
seq_printf(s, " %5c ", '?');
|
||||
|
||||
hlist_for_each_entry(clk_user, &c->clks, clks_node) {
|
||||
seq_printf(s, "%*s%-*s %-25s\n",
|
||||
level * 3 + 2 + 105 * multi_node, "",
|
||||
30,
|
||||
clk_user->dev_id ? clk_user->dev_id : "deviceless",
|
||||
clk_user->con_id ? clk_user->con_id : "no_connection_id");
|
||||
|
||||
multi_node = 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c,
|
||||
@@ -3309,9 +3322,10 @@ static int clk_summary_show(struct seq_file *s, void *data)
|
||||
struct clk_core *c;
|
||||
struct hlist_head **lists = s->private;
|
||||
|
||||
seq_puts(s, " enable prepare protect duty hardware\n");
|
||||
seq_puts(s, " clock count count count rate accuracy phase cycle enable\n");
|
||||
seq_puts(s, "-------------------------------------------------------------------------------------------------------\n");
|
||||
seq_puts(s, " enable prepare protect duty hardware connection\n");
|
||||
seq_puts(s, " clock count count count rate accuracy phase cycle enable consumer id\n");
|
||||
seq_puts(s, "---------------------------------------------------------------------------------------------------------------------------------------------\n");
|
||||
|
||||
|
||||
clk_prepare_lock();
|
||||
|
||||
@@ -3408,6 +3422,21 @@ static int clk_rate_set(void *data, u64 val)
|
||||
|
||||
#define clk_rate_mode 0644
|
||||
|
||||
static int clk_phase_set(void *data, u64 val)
|
||||
{
|
||||
struct clk_core *core = data;
|
||||
int degrees = do_div(val, 360);
|
||||
int ret;
|
||||
|
||||
clk_prepare_lock();
|
||||
ret = clk_core_set_phase_nolock(core, degrees);
|
||||
clk_prepare_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define clk_phase_mode 0644
|
||||
|
||||
static int clk_prepare_enable_set(void *data, u64 val)
|
||||
{
|
||||
struct clk_core *core = data;
|
||||
@@ -3435,6 +3464,9 @@ DEFINE_DEBUGFS_ATTRIBUTE(clk_prepare_enable_fops, clk_prepare_enable_get,
|
||||
#else
|
||||
#define clk_rate_set NULL
|
||||
#define clk_rate_mode 0444
|
||||
|
||||
#define clk_phase_set NULL
|
||||
#define clk_phase_mode 0644
|
||||
#endif
|
||||
|
||||
static int clk_rate_get(void *data, u64 *val)
|
||||
@@ -3450,6 +3482,16 @@ static int clk_rate_get(void *data, u64 *val)
|
||||
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(clk_rate_fops, clk_rate_get, clk_rate_set, "%llu\n");
|
||||
|
||||
static int clk_phase_get(void *data, u64 *val)
|
||||
{
|
||||
struct clk_core *core = data;
|
||||
|
||||
*val = core->phase;
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_DEBUGFS_ATTRIBUTE(clk_phase_fops, clk_phase_get, clk_phase_set, "%llu\n");
|
||||
|
||||
static const struct {
|
||||
unsigned long flag;
|
||||
const char *name;
|
||||
@@ -3643,7 +3685,8 @@ static void clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
|
||||
debugfs_create_file("clk_min_rate", 0444, root, core, &clk_min_rate_fops);
|
||||
debugfs_create_file("clk_max_rate", 0444, root, core, &clk_max_rate_fops);
|
||||
debugfs_create_ulong("clk_accuracy", 0444, root, &core->accuracy);
|
||||
debugfs_create_u32("clk_phase", 0444, root, &core->phase);
|
||||
debugfs_create_file("clk_phase", clk_phase_mode, root, core,
|
||||
&clk_phase_fops);
|
||||
debugfs_create_file("clk_flags", 0444, root, core, &clk_flags_fops);
|
||||
debugfs_create_u32("clk_prepare_count", 0444, root, &core->prepare_count);
|
||||
debugfs_create_u32("clk_enable_count", 0444, root, &core->enable_count);
|
||||
|
||||
+113
-17
@@ -10,6 +10,8 @@
|
||||
|
||||
#include <kunit/test.h>
|
||||
|
||||
static const struct clk_ops empty_clk_ops = { };
|
||||
|
||||
#define DUMMY_CLOCK_INIT_RATE (42 * 1000 * 1000)
|
||||
#define DUMMY_CLOCK_RATE_1 (142 * 1000 * 1000)
|
||||
#define DUMMY_CLOCK_RATE_2 (242 * 1000 * 1000)
|
||||
@@ -2155,6 +2157,31 @@ static struct kunit_suite clk_range_minimize_test_suite = {
|
||||
struct clk_leaf_mux_ctx {
|
||||
struct clk_multiple_parent_ctx mux_ctx;
|
||||
struct clk_hw hw;
|
||||
struct clk_hw parent;
|
||||
struct clk_rate_request *req;
|
||||
int (*determine_rate_func)(struct clk_hw *hw, struct clk_rate_request *req);
|
||||
};
|
||||
|
||||
static int clk_leaf_mux_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_leaf_mux_ctx *ctx = container_of(hw, struct clk_leaf_mux_ctx, hw);
|
||||
int ret;
|
||||
struct clk_rate_request *parent_req = ctx->req;
|
||||
|
||||
clk_hw_forward_rate_request(hw, req, req->best_parent_hw, parent_req, req->rate);
|
||||
ret = ctx->determine_rate_func(req->best_parent_hw, parent_req);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
req->rate = parent_req->rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops clk_leaf_mux_set_rate_parent_ops = {
|
||||
.determine_rate = clk_leaf_mux_determine_rate,
|
||||
.set_parent = clk_dummy_single_set_parent,
|
||||
.get_parent = clk_dummy_single_get_parent,
|
||||
};
|
||||
|
||||
static int
|
||||
@@ -2193,8 +2220,14 @@ clk_leaf_mux_set_rate_parent_test_init(struct kunit *test)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ctx->hw.init = CLK_HW_INIT_HW("test-clock", &ctx->mux_ctx.hw,
|
||||
&clk_dummy_single_parent_ops,
|
||||
ctx->parent.init = CLK_HW_INIT_HW("test-parent", &ctx->mux_ctx.hw,
|
||||
&empty_clk_ops, CLK_SET_RATE_PARENT);
|
||||
ret = clk_hw_register(NULL, &ctx->parent);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ctx->hw.init = CLK_HW_INIT_HW("test-clock", &ctx->parent,
|
||||
&clk_leaf_mux_set_rate_parent_ops,
|
||||
CLK_SET_RATE_PARENT);
|
||||
ret = clk_hw_register(NULL, &ctx->hw);
|
||||
if (ret)
|
||||
@@ -2208,32 +2241,94 @@ static void clk_leaf_mux_set_rate_parent_test_exit(struct kunit *test)
|
||||
struct clk_leaf_mux_ctx *ctx = test->priv;
|
||||
|
||||
clk_hw_unregister(&ctx->hw);
|
||||
clk_hw_unregister(&ctx->parent);
|
||||
clk_hw_unregister(&ctx->mux_ctx.hw);
|
||||
clk_hw_unregister(&ctx->mux_ctx.parents_ctx[0].hw);
|
||||
clk_hw_unregister(&ctx->mux_ctx.parents_ctx[1].hw);
|
||||
}
|
||||
|
||||
struct clk_leaf_mux_set_rate_parent_determine_rate_test_case {
|
||||
const char *desc;
|
||||
int (*determine_rate_func)(struct clk_hw *hw, struct clk_rate_request *req);
|
||||
};
|
||||
|
||||
static void
|
||||
clk_leaf_mux_set_rate_parent_determine_rate_test_case_to_desc(
|
||||
const struct clk_leaf_mux_set_rate_parent_determine_rate_test_case *t, char *desc)
|
||||
{
|
||||
strcpy(desc, t->desc);
|
||||
}
|
||||
|
||||
static const struct clk_leaf_mux_set_rate_parent_determine_rate_test_case
|
||||
clk_leaf_mux_set_rate_parent_determine_rate_test_cases[] = {
|
||||
{
|
||||
/*
|
||||
* Test that __clk_determine_rate() on the parent that can't
|
||||
* change rate doesn't return a clk_rate_request structure with
|
||||
* the best_parent_hw pointer pointing to the parent.
|
||||
*/
|
||||
.desc = "clk_leaf_mux_set_rate_parent__clk_determine_rate_proper_parent",
|
||||
.determine_rate_func = __clk_determine_rate,
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Test that __clk_mux_determine_rate() on the parent that
|
||||
* can't change rate doesn't return a clk_rate_request
|
||||
* structure with the best_parent_hw pointer pointing to
|
||||
* the parent.
|
||||
*/
|
||||
.desc = "clk_leaf_mux_set_rate_parent__clk_mux_determine_rate_proper_parent",
|
||||
.determine_rate_func = __clk_mux_determine_rate,
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Test that __clk_mux_determine_rate_closest() on the parent
|
||||
* that can't change rate doesn't return a clk_rate_request
|
||||
* structure with the best_parent_hw pointer pointing to
|
||||
* the parent.
|
||||
*/
|
||||
.desc = "clk_leaf_mux_set_rate_parent__clk_mux_determine_rate_closest_proper_parent",
|
||||
.determine_rate_func = __clk_mux_determine_rate_closest,
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Test that clk_hw_determine_rate_no_reparent() on the parent
|
||||
* that can't change rate doesn't return a clk_rate_request
|
||||
* structure with the best_parent_hw pointer pointing to
|
||||
* the parent.
|
||||
*/
|
||||
.desc = "clk_leaf_mux_set_rate_parent_clk_hw_determine_rate_no_reparent_proper_parent",
|
||||
.determine_rate_func = clk_hw_determine_rate_no_reparent,
|
||||
},
|
||||
};
|
||||
|
||||
KUNIT_ARRAY_PARAM(clk_leaf_mux_set_rate_parent_determine_rate_test,
|
||||
clk_leaf_mux_set_rate_parent_determine_rate_test_cases,
|
||||
clk_leaf_mux_set_rate_parent_determine_rate_test_case_to_desc)
|
||||
|
||||
/*
|
||||
* Test that, for a clock that will forward any rate request to its
|
||||
* parent, the rate request structure returned by __clk_determine_rate
|
||||
* is sane and will be what we expect.
|
||||
* Test that when a clk that can't change rate itself calls a function like
|
||||
* __clk_determine_rate() on its parent it doesn't get back a clk_rate_request
|
||||
* structure that has the best_parent_hw pointer point to the clk_hw passed
|
||||
* into the determine rate function. See commit 262ca38f4b6e ("clk: Stop
|
||||
* forwarding clk_rate_requests to the parent") for more background.
|
||||
*/
|
||||
static void clk_leaf_mux_set_rate_parent_determine_rate(struct kunit *test)
|
||||
static void clk_leaf_mux_set_rate_parent_determine_rate_test(struct kunit *test)
|
||||
{
|
||||
struct clk_leaf_mux_ctx *ctx = test->priv;
|
||||
struct clk_hw *hw = &ctx->hw;
|
||||
struct clk *clk = clk_hw_get_clk(hw, NULL);
|
||||
struct clk_rate_request req;
|
||||
unsigned long rate;
|
||||
int ret;
|
||||
const struct clk_leaf_mux_set_rate_parent_determine_rate_test_case *test_param;
|
||||
|
||||
test_param = test->param_value;
|
||||
ctx->determine_rate_func = test_param->determine_rate_func;
|
||||
|
||||
ctx->req = &req;
|
||||
rate = clk_get_rate(clk);
|
||||
KUNIT_ASSERT_EQ(test, rate, DUMMY_CLOCK_RATE_1);
|
||||
|
||||
clk_hw_init_rate_request(hw, &req, DUMMY_CLOCK_RATE_2);
|
||||
|
||||
ret = __clk_determine_rate(hw, &req);
|
||||
KUNIT_ASSERT_EQ(test, ret, 0);
|
||||
KUNIT_ASSERT_EQ(test, DUMMY_CLOCK_RATE_2, clk_round_rate(clk, DUMMY_CLOCK_RATE_2));
|
||||
|
||||
KUNIT_EXPECT_EQ(test, req.rate, DUMMY_CLOCK_RATE_2);
|
||||
KUNIT_EXPECT_EQ(test, req.best_parent_rate, DUMMY_CLOCK_RATE_2);
|
||||
@@ -2243,15 +2338,16 @@ static void clk_leaf_mux_set_rate_parent_determine_rate(struct kunit *test)
|
||||
}
|
||||
|
||||
static struct kunit_case clk_leaf_mux_set_rate_parent_test_cases[] = {
|
||||
KUNIT_CASE(clk_leaf_mux_set_rate_parent_determine_rate),
|
||||
KUNIT_CASE_PARAM(clk_leaf_mux_set_rate_parent_determine_rate_test,
|
||||
clk_leaf_mux_set_rate_parent_determine_rate_test_gen_params),
|
||||
{}
|
||||
};
|
||||
|
||||
/*
|
||||
* Test suite for a clock whose parent is a mux with multiple parents.
|
||||
* The leaf clock has CLK_SET_RATE_PARENT, and will forward rate
|
||||
* requests to the mux, which will then select which parent is the best
|
||||
* fit for a given rate.
|
||||
* Test suite for a clock whose parent is a pass-through clk whose parent is a
|
||||
* mux with multiple parents. The leaf and pass-through clocks have the
|
||||
* CLK_SET_RATE_PARENT flag, and will forward rate requests to the mux, which
|
||||
* will then select which parent is the best fit for a given rate.
|
||||
*
|
||||
* These tests exercise the behaviour of muxes, and the proper selection
|
||||
* of parents.
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/mfd/da8xx-cfgchip.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_data/clk-da8xx-cfgchip.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
@@ -744,15 +744,13 @@ static int da8xx_cfgchip_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct da8xx_cfgchip_clk_platform_data *pdata = dev->platform_data;
|
||||
const struct of_device_id *of_id;
|
||||
da8xx_cfgchip_init clk_init = NULL;
|
||||
struct regmap *regmap = NULL;
|
||||
|
||||
of_id = of_match_device(da8xx_cfgchip_of_match, dev);
|
||||
if (of_id) {
|
||||
clk_init = device_get_match_data(dev);
|
||||
if (clk_init) {
|
||||
struct device_node *parent;
|
||||
|
||||
clk_init = of_id->data;
|
||||
parent = of_get_parent(dev->of_node);
|
||||
regmap = syscon_node_to_regmap(parent);
|
||||
of_node_put(parent);
|
||||
|
||||
@@ -18,11 +18,10 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_data/clk-davinci-pll.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
@@ -892,14 +891,11 @@ static int davinci_pll_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct davinci_pll_platform_data *pdata;
|
||||
const struct of_device_id *of_id;
|
||||
davinci_pll_init pll_init = NULL;
|
||||
void __iomem *base;
|
||||
|
||||
of_id = of_match_device(davinci_pll_of_match, dev);
|
||||
if (of_id)
|
||||
pll_init = of_id->data;
|
||||
else if (pdev->id_entry)
|
||||
pll_init = device_get_match_data(dev);
|
||||
if (!pll_init && pdev->id_entry)
|
||||
pll_init = (void *)pdev->id_entry->driver_data;
|
||||
|
||||
if (!pll_init) {
|
||||
|
||||
@@ -18,10 +18,9 @@
|
||||
#include <linux/clk/davinci.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/pm_clock.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/regmap.h>
|
||||
@@ -517,15 +516,12 @@ static const struct platform_device_id davinci_psc_id_table[] = {
|
||||
static int davinci_psc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
const struct of_device_id *of_id;
|
||||
const struct davinci_psc_init_data *init_data = NULL;
|
||||
void __iomem *base;
|
||||
int ret;
|
||||
|
||||
of_id = of_match_device(davinci_psc_of_match, dev);
|
||||
if (of_id)
|
||||
init_data = of_id->data;
|
||||
else if (pdev->id_entry)
|
||||
init_data = device_get_match_data(dev);
|
||||
if (!init_data && pdev->id_entry)
|
||||
init_data = (void *)pdev->id_entry->driver_data;
|
||||
|
||||
if (!init_data) {
|
||||
|
||||
@@ -96,6 +96,7 @@ config CLK_IMX8QXP
|
||||
depends on (ARCH_MXC && ARM64) || COMPILE_TEST
|
||||
depends on IMX_SCU && HAVE_ARM_SMCCC
|
||||
select MXC_CLK_SCU
|
||||
select MXC_CLK
|
||||
help
|
||||
Build the driver for IMX8QXP SCU based clocks.
|
||||
|
||||
|
||||
@@ -121,6 +121,7 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
|
||||
{
|
||||
struct device_node *np;
|
||||
void __iomem *base;
|
||||
bool lcdif1_assigned_clk;
|
||||
|
||||
clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
|
||||
IMX6SX_CLK_CLK_END), GFP_KERNEL);
|
||||
@@ -498,9 +499,16 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
|
||||
clk_set_parent(hws[IMX6SX_CLK_EIM_SLOW_SEL]->clk, hws[IMX6SX_CLK_PLL2_PFD2]->clk);
|
||||
clk_set_rate(hws[IMX6SX_CLK_EIM_SLOW]->clk, 132000000);
|
||||
|
||||
/* set parent clock for LCDIF1 pixel clock */
|
||||
clk_set_parent(hws[IMX6SX_CLK_LCDIF1_PRE_SEL]->clk, hws[IMX6SX_CLK_PLL5_VIDEO_DIV]->clk);
|
||||
clk_set_parent(hws[IMX6SX_CLK_LCDIF1_SEL]->clk, hws[IMX6SX_CLK_LCDIF1_PODF]->clk);
|
||||
np = of_find_node_by_path("/soc/bus@2200000/spba-bus@2240000/lcdif@2220000");
|
||||
lcdif1_assigned_clk = of_find_property(np, "assigned-clock-parents", NULL);
|
||||
|
||||
/* Set parent clock for LCDIF1 pixel clock if not done via devicetree */
|
||||
if (!lcdif1_assigned_clk) {
|
||||
clk_set_parent(hws[IMX6SX_CLK_LCDIF1_PRE_SEL]->clk,
|
||||
hws[IMX6SX_CLK_PLL5_VIDEO_DIV]->clk);
|
||||
clk_set_parent(hws[IMX6SX_CLK_LCDIF1_SEL]->clk,
|
||||
hws[IMX6SX_CLK_LCDIF1_PODF]->clk);
|
||||
}
|
||||
|
||||
/* Set the parent clks of PCIe lvds1 and pcie_axi to be pcie ref, axi */
|
||||
if (clk_set_parent(hws[IMX6SX_CLK_LVDS1_SEL]->clk, hws[IMX6SX_CLK_PCIE_REF_125M]->clk))
|
||||
|
||||
@@ -77,7 +77,7 @@ struct imx8_acm_priv {
|
||||
static const struct clk_parent_data imx8qm_aud_clk_sels[] = {
|
||||
{ .fw_name = "aud_rec_clk0_lpcg_clk" },
|
||||
{ .fw_name = "aud_rec_clk1_lpcg_clk" },
|
||||
{ .fw_name = "mlb_clk" },
|
||||
{ .fw_name = "dummy" },
|
||||
{ .fw_name = "hdmi_rx_mclk" },
|
||||
{ .fw_name = "ext_aud_mclk0" },
|
||||
{ .fw_name = "ext_aud_mclk1" },
|
||||
@@ -103,7 +103,7 @@ static const struct clk_parent_data imx8qm_aud_clk_sels[] = {
|
||||
static const struct clk_parent_data imx8qm_mclk_out_sels[] = {
|
||||
{ .fw_name = "aud_rec_clk0_lpcg_clk" },
|
||||
{ .fw_name = "aud_rec_clk1_lpcg_clk" },
|
||||
{ .fw_name = "mlb_clk" },
|
||||
{ .fw_name = "dummy" },
|
||||
{ .fw_name = "hdmi_rx_mclk" },
|
||||
{ .fw_name = "spdif0_rx" },
|
||||
{ .fw_name = "spdif1_rx" },
|
||||
@@ -122,7 +122,7 @@ static const struct clk_parent_data imx8qm_asrc_mux_clk_sels[] = {
|
||||
{ .fw_name = "sai4_rx_bclk" },
|
||||
{ .fw_name = "sai5_tx_bclk" },
|
||||
{ .index = -1 },
|
||||
{ .fw_name = "mlb_clk" },
|
||||
{ .fw_name = "dummy" },
|
||||
|
||||
};
|
||||
|
||||
@@ -279,8 +279,10 @@ static int clk_imx_acm_attach_pm_domains(struct device *dev,
|
||||
|
||||
for (i = 0; i < dev_pm->num_domains; i++) {
|
||||
dev_pm->pd_dev[i] = dev_pm_domain_attach_by_id(dev, i);
|
||||
if (IS_ERR(dev_pm->pd_dev[i]))
|
||||
return PTR_ERR(dev_pm->pd_dev[i]);
|
||||
if (IS_ERR(dev_pm->pd_dev[i])) {
|
||||
ret = PTR_ERR(dev_pm->pd_dev[i]);
|
||||
goto detach_pm;
|
||||
}
|
||||
|
||||
dev_pm->pd_dev_link[i] = device_link_add(dev,
|
||||
dev_pm->pd_dev[i],
|
||||
@@ -308,20 +310,18 @@ detach_pm:
|
||||
* @dev: deivice pointer
|
||||
* @dev_pm: multi power domain for device
|
||||
*/
|
||||
static int clk_imx_acm_detach_pm_domains(struct device *dev,
|
||||
struct clk_imx_acm_pm_domains *dev_pm)
|
||||
static void clk_imx_acm_detach_pm_domains(struct device *dev,
|
||||
struct clk_imx_acm_pm_domains *dev_pm)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (dev_pm->num_domains <= 1)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
for (i = 0; i < dev_pm->num_domains; i++) {
|
||||
device_link_del(dev_pm->pd_dev_link[i]);
|
||||
dev_pm_domain_detach(dev_pm->pd_dev[i], false);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx8_acm_clk_probe(struct platform_device *pdev)
|
||||
@@ -371,22 +371,25 @@ static int imx8_acm_clk_probe(struct platform_device *pdev)
|
||||
sels[i].shift, sels[i].width,
|
||||
0, NULL, NULL);
|
||||
if (IS_ERR(hws[sels[i].clkid])) {
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
ret = PTR_ERR(hws[sels[i].clkid]);
|
||||
imx_check_clk_hws(hws, IMX_ADMA_ACM_CLK_END);
|
||||
goto err_clk_register;
|
||||
}
|
||||
}
|
||||
|
||||
imx_check_clk_hws(hws, IMX_ADMA_ACM_CLK_END);
|
||||
|
||||
ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_hw_data);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to register hws for ACM\n");
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
goto err_clk_register;
|
||||
}
|
||||
|
||||
err_clk_register:
|
||||
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
return 0;
|
||||
|
||||
err_clk_register:
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
clk_imx_acm_detach_pm_domains(&pdev->dev, &priv->dev_pm);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -47,11 +47,10 @@ static u32 imx8dxl_clk_scu_rsrc_table[] = {
|
||||
IMX_SC_R_SDHC_2,
|
||||
IMX_SC_R_ENET_0,
|
||||
IMX_SC_R_ENET_1,
|
||||
IMX_SC_R_MLB_0,
|
||||
IMX_SC_R_USB_1,
|
||||
IMX_SC_R_NAND,
|
||||
IMX_SC_R_M4_0_I2C,
|
||||
IMX_SC_R_M4_0_UART,
|
||||
IMX_SC_R_M4_0_I2C,
|
||||
IMX_SC_R_ELCDIF_PLL,
|
||||
IMX_SC_R_AUDIO_PLL_0,
|
||||
IMX_SC_R_AUDIO_PLL_1,
|
||||
|
||||
@@ -288,8 +288,7 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
|
||||
void __iomem *base;
|
||||
int err;
|
||||
|
||||
clk_hw_data = kzalloc(struct_size(clk_hw_data, hws,
|
||||
IMX8MQ_CLK_END), GFP_KERNEL);
|
||||
clk_hw_data = devm_kzalloc(dev, struct_size(clk_hw_data, hws, IMX8MQ_CLK_END), GFP_KERNEL);
|
||||
if (WARN_ON(!clk_hw_data))
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -306,10 +305,12 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
|
||||
hws[IMX8MQ_CLK_EXT4] = imx_get_clk_hw_by_name(np, "clk_ext4");
|
||||
|
||||
np = of_find_compatible_node(NULL, NULL, "fsl,imx8mq-anatop");
|
||||
base = of_iomap(np, 0);
|
||||
base = devm_of_iomap(dev, np, 0, NULL);
|
||||
of_node_put(np);
|
||||
if (WARN_ON(!base))
|
||||
return -ENOMEM;
|
||||
if (WARN_ON(IS_ERR(base))) {
|
||||
err = PTR_ERR(base);
|
||||
goto unregister_hws;
|
||||
}
|
||||
|
||||
hws[IMX8MQ_ARM_PLL_REF_SEL] = imx_clk_hw_mux("arm_pll_ref_sel", base + 0x28, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
|
||||
hws[IMX8MQ_GPU_PLL_REF_SEL] = imx_clk_hw_mux("gpu_pll_ref_sel", base + 0x18, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels));
|
||||
@@ -395,8 +396,10 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
|
||||
|
||||
np = dev->of_node;
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (WARN_ON(IS_ERR(base)))
|
||||
return PTR_ERR(base);
|
||||
if (WARN_ON(IS_ERR(base))) {
|
||||
err = PTR_ERR(base);
|
||||
goto unregister_hws;
|
||||
}
|
||||
|
||||
/* CORE */
|
||||
hws[IMX8MQ_CLK_A53_DIV] = imx8m_clk_hw_composite_core("arm_a53_div", imx8mq_a53_sels, base + 0x8000);
|
||||
|
||||
@@ -43,6 +43,8 @@ static const u32 imx8qm_clk_scu_rsrc_table[] = {
|
||||
IMX_SC_R_FTM_0,
|
||||
IMX_SC_R_FTM_1,
|
||||
IMX_SC_R_CAN_0,
|
||||
IMX_SC_R_CAN_1,
|
||||
IMX_SC_R_CAN_2,
|
||||
IMX_SC_R_GPU_0_PID0,
|
||||
IMX_SC_R_GPU_1_PID0,
|
||||
IMX_SC_R_PWM_0,
|
||||
@@ -65,7 +67,6 @@ static const u32 imx8qm_clk_scu_rsrc_table[] = {
|
||||
IMX_SC_R_SDHC_2,
|
||||
IMX_SC_R_ENET_0,
|
||||
IMX_SC_R_ENET_1,
|
||||
IMX_SC_R_MLB_0,
|
||||
IMX_SC_R_USB_2,
|
||||
IMX_SC_R_NAND,
|
||||
IMX_SC_R_LVDS_0,
|
||||
@@ -79,8 +80,6 @@ static const u32 imx8qm_clk_scu_rsrc_table[] = {
|
||||
IMX_SC_R_M4_0_I2C,
|
||||
IMX_SC_R_M4_1_I2C,
|
||||
IMX_SC_R_AUDIO_PLL_0,
|
||||
IMX_SC_R_VPU_UART,
|
||||
IMX_SC_R_VPUCORE,
|
||||
IMX_SC_R_MIPI_0,
|
||||
IMX_SC_R_MIPI_0_PWM_0,
|
||||
IMX_SC_R_MIPI_0_I2C_0,
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
#define CONN_ENET_0_LPCG 0x30000
|
||||
#define CONN_ENET_1_LPCG 0x40000
|
||||
#define CONN_DTCP_LPCG 0x50000
|
||||
#define CONN_MLB_LPCG 0x60000
|
||||
#define CONN_USB_2_LPCG 0x70000
|
||||
#define CONN_USB_3_LPCG 0x80000
|
||||
#define CONN_NAND_LPCG 0x90000
|
||||
|
||||
@@ -54,15 +54,17 @@ static const u32 imx8qxp_clk_scu_rsrc_table[] = {
|
||||
IMX_SC_R_SDHC_2,
|
||||
IMX_SC_R_ENET_0,
|
||||
IMX_SC_R_ENET_1,
|
||||
IMX_SC_R_MLB_0,
|
||||
IMX_SC_R_USB_2,
|
||||
IMX_SC_R_NAND,
|
||||
IMX_SC_R_LVDS_0,
|
||||
IMX_SC_R_LVDS_1,
|
||||
IMX_SC_R_M4_0_UART,
|
||||
IMX_SC_R_M4_0_I2C,
|
||||
IMX_SC_R_ELCDIF_PLL,
|
||||
IMX_SC_R_AUDIO_PLL_0,
|
||||
IMX_SC_R_PI_0,
|
||||
IMX_SC_R_PI_0_PWM_0,
|
||||
IMX_SC_R_PI_0_I2C_0,
|
||||
IMX_SC_R_PI_0_PLL,
|
||||
IMX_SC_R_MIPI_0,
|
||||
IMX_SC_R_MIPI_0_PWM_0,
|
||||
|
||||
@@ -90,6 +90,11 @@ static const char * const pi_pll0_sels[] = {
|
||||
"clk_dummy",
|
||||
};
|
||||
|
||||
static inline bool clk_on_imx8dxl(struct device_node *node)
|
||||
{
|
||||
return of_device_is_compatible(node, "fsl,imx8dxl-clk");
|
||||
}
|
||||
|
||||
static int imx8qxp_clk_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *ccm_node = pdev->dev.of_node;
|
||||
@@ -147,10 +152,10 @@ static int imx8qxp_clk_probe(struct platform_device *pdev)
|
||||
imx_clk_scu("adc0_clk", IMX_SC_R_ADC_0, IMX_SC_PM_CLK_PER);
|
||||
imx_clk_scu("adc1_clk", IMX_SC_R_ADC_1, IMX_SC_PM_CLK_PER);
|
||||
imx_clk_scu("pwm_clk", IMX_SC_R_LCD_0_PWM_0, IMX_SC_PM_CLK_PER);
|
||||
imx_clk_scu("elcdif_pll", IMX_SC_R_ELCDIF_PLL, IMX_SC_PM_CLK_PLL);
|
||||
imx_clk_scu2("lcd_clk", lcd_sels, ARRAY_SIZE(lcd_sels), IMX_SC_R_LCD_0, IMX_SC_PM_CLK_PER);
|
||||
imx_clk_scu2("lcd_pxl_clk", lcd_pxl_sels, ARRAY_SIZE(lcd_pxl_sels), IMX_SC_R_LCD_0, IMX_SC_PM_CLK_MISC0);
|
||||
imx_clk_scu("lcd_pxl_bypass_div_clk", IMX_SC_R_LCD_0, IMX_SC_PM_CLK_BYPASS);
|
||||
imx_clk_scu("elcdif_pll", IMX_SC_R_ELCDIF_PLL, IMX_SC_PM_CLK_PLL);
|
||||
|
||||
/* Audio SS */
|
||||
imx_clk_scu("audio_pll0_clk", IMX_SC_R_AUDIO_PLL_0, IMX_SC_PM_CLK_PLL);
|
||||
@@ -169,13 +174,15 @@ static int imx8qxp_clk_probe(struct platform_device *pdev)
|
||||
imx_clk_mux_gpr_scu("enet0_rgmii_txc_sel", enet0_rgmii_txc_sels, ARRAY_SIZE(enet0_rgmii_txc_sels), IMX_SC_R_ENET_0, IMX_SC_C_TXCLK);
|
||||
imx_clk_scu("enet0_bypass_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_BYPASS);
|
||||
imx_clk_gate_gpr_scu("enet0_ref_50_clk", "clk_dummy", IMX_SC_R_ENET_0, IMX_SC_C_DISABLE_50, true);
|
||||
imx_clk_scu("enet0_rgmii_rx_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_MISC0);
|
||||
if (!clk_on_imx8dxl(ccm_node)) {
|
||||
imx_clk_scu("enet0_rgmii_rx_clk", IMX_SC_R_ENET_0, IMX_SC_PM_CLK_MISC0);
|
||||
imx_clk_scu("enet1_rgmii_rx_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_MISC0);
|
||||
}
|
||||
imx_clk_scu("enet1_root_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_PER);
|
||||
imx_clk_divider_gpr_scu("enet1_ref_div", "enet1_root_clk", IMX_SC_R_ENET_1, IMX_SC_C_CLKDIV);
|
||||
imx_clk_mux_gpr_scu("enet1_rgmii_txc_sel", enet1_rgmii_txc_sels, ARRAY_SIZE(enet1_rgmii_txc_sels), IMX_SC_R_ENET_1, IMX_SC_C_TXCLK);
|
||||
imx_clk_scu("enet1_bypass_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_BYPASS);
|
||||
imx_clk_gate_gpr_scu("enet1_ref_50_clk", "clk_dummy", IMX_SC_R_ENET_1, IMX_SC_C_DISABLE_50, true);
|
||||
imx_clk_scu("enet1_rgmii_rx_clk", IMX_SC_R_ENET_1, IMX_SC_PM_CLK_MISC0);
|
||||
imx_clk_scu("gpmi_io_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_MST_BUS);
|
||||
imx_clk_scu("gpmi_bch_clk", IMX_SC_R_NAND, IMX_SC_PM_CLK_PER);
|
||||
imx_clk_scu("usb3_aclk_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_PER);
|
||||
|
||||
@@ -10,10 +10,12 @@
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/firmware/imx/svc/rm.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/slab.h>
|
||||
#include <xen/xen.h>
|
||||
|
||||
#include "clk-scu.h"
|
||||
|
||||
@@ -670,6 +672,18 @@ static int imx_clk_scu_attach_pd(struct device *dev, u32 rsrc_id)
|
||||
return of_genpd_add_device(&genpdspec, dev);
|
||||
}
|
||||
|
||||
static bool imx_clk_is_resource_owned(u32 rsrc)
|
||||
{
|
||||
/*
|
||||
* A-core resources are special. SCFW reports they are not "owned" by
|
||||
* current partition but linux can still adjust them for cpufreq.
|
||||
*/
|
||||
if (rsrc == IMX_SC_R_A53 || rsrc == IMX_SC_R_A72 || rsrc == IMX_SC_R_A35)
|
||||
return true;
|
||||
|
||||
return imx_sc_rm_is_resource_owned(ccm_ipc_handle, rsrc);
|
||||
}
|
||||
|
||||
struct clk_hw *imx_clk_scu_alloc_dev(const char *name,
|
||||
const char * const *parents,
|
||||
int num_parents, u32 rsrc_id, u8 clk_type)
|
||||
@@ -687,6 +701,9 @@ struct clk_hw *imx_clk_scu_alloc_dev(const char *name,
|
||||
if (!imx_scu_clk_is_valid(rsrc_id))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (!imx_clk_is_resource_owned(rsrc_id))
|
||||
return NULL;
|
||||
|
||||
pdev = platform_device_alloc(name, PLATFORM_DEVID_NONE);
|
||||
if (!pdev) {
|
||||
pr_err("%s: failed to allocate scu clk dev rsrc %d type %d\n",
|
||||
@@ -869,6 +886,9 @@ struct clk_hw *__imx_clk_gpr_scu(const char *name, const char * const *parent_na
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
if (!imx_clk_is_resource_owned(rsrc_id))
|
||||
return NULL;
|
||||
|
||||
clk = kzalloc(sizeof(*clk), GFP_KERNEL);
|
||||
if (!clk) {
|
||||
kfree(clk_node);
|
||||
|
||||
@@ -281,12 +281,13 @@ static void __init of_pll_div_clk_init(struct device_node *node)
|
||||
|
||||
clk = clk_register_divider(NULL, clk_name, parent_name, 0, reg, shift,
|
||||
mask, 0, NULL);
|
||||
if (clk) {
|
||||
of_clk_add_provider(node, of_clk_src_simple_get, clk);
|
||||
} else {
|
||||
if (IS_ERR(clk)) {
|
||||
pr_err("%s: error registering divider %s\n", __func__, clk_name);
|
||||
iounmap(reg);
|
||||
return;
|
||||
}
|
||||
|
||||
of_clk_add_provider(node, of_clk_src_simple_get, clk);
|
||||
}
|
||||
CLK_OF_DECLARE(pll_divider_clock, "ti,keystone,pll-divider-clock", of_pll_div_clk_init);
|
||||
|
||||
@@ -328,10 +329,12 @@ static void __init of_pll_mux_clk_init(struct device_node *node)
|
||||
clk = clk_register_mux(NULL, clk_name, (const char **)&parents,
|
||||
ARRAY_SIZE(parents) , 0, reg, shift, mask,
|
||||
0, NULL);
|
||||
if (clk)
|
||||
of_clk_add_provider(node, of_clk_src_simple_get, clk);
|
||||
else
|
||||
if (IS_ERR(clk)) {
|
||||
pr_err("%s: error registering mux %s\n", __func__, clk_name);
|
||||
return;
|
||||
}
|
||||
|
||||
of_clk_add_provider(node, of_clk_src_simple_get, clk);
|
||||
}
|
||||
CLK_OF_DECLARE(pll_mux_clock, "ti,keystone,pll-mux-clock", of_pll_mux_clk_init);
|
||||
|
||||
|
||||
@@ -667,6 +667,8 @@ static int mtk_topckgen_init(struct platform_device *pdev)
|
||||
return PTR_ERR(base);
|
||||
|
||||
clk_data = mtk_alloc_clk_data(CLK_TOP_NR);
|
||||
if (!clk_data)
|
||||
return -ENOMEM;
|
||||
|
||||
mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks),
|
||||
clk_data);
|
||||
@@ -747,6 +749,8 @@ static void __init mtk_infrasys_init_early(struct device_node *node)
|
||||
|
||||
if (!infra_clk_data) {
|
||||
infra_clk_data = mtk_alloc_clk_data(CLK_INFRA_NR);
|
||||
if (!infra_clk_data)
|
||||
return;
|
||||
|
||||
for (i = 0; i < CLK_INFRA_NR; i++)
|
||||
infra_clk_data->hws[i] = ERR_PTR(-EPROBE_DEFER);
|
||||
@@ -774,6 +778,8 @@ static int mtk_infrasys_init(struct platform_device *pdev)
|
||||
|
||||
if (!infra_clk_data) {
|
||||
infra_clk_data = mtk_alloc_clk_data(CLK_INFRA_NR);
|
||||
if (!infra_clk_data)
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
for (i = 0; i < CLK_INFRA_NR; i++) {
|
||||
if (infra_clk_data->hws[i] == ERR_PTR(-EPROBE_DEFER))
|
||||
@@ -890,6 +896,8 @@ static int mtk_pericfg_init(struct platform_device *pdev)
|
||||
return PTR_ERR(base);
|
||||
|
||||
clk_data = mtk_alloc_clk_data(CLK_PERI_NR);
|
||||
if (!clk_data)
|
||||
return -ENOMEM;
|
||||
|
||||
mtk_clk_register_gates(&pdev->dev, node, peri_clks,
|
||||
ARRAY_SIZE(peri_clks), clk_data);
|
||||
|
||||
@@ -737,6 +737,8 @@ static int clk_mt6765_apmixed_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(base);
|
||||
|
||||
clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK);
|
||||
if (!clk_data)
|
||||
return -ENOMEM;
|
||||
|
||||
mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
|
||||
|
||||
@@ -769,6 +771,8 @@ static int clk_mt6765_top_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(base);
|
||||
|
||||
clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK);
|
||||
if (!clk_data)
|
||||
return -ENOMEM;
|
||||
|
||||
mtk_clk_register_fixed_clks(fixed_clks, ARRAY_SIZE(fixed_clks),
|
||||
clk_data);
|
||||
@@ -807,6 +811,8 @@ static int clk_mt6765_ifr_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(base);
|
||||
|
||||
clk_data = mtk_alloc_clk_data(CLK_IFR_NR_CLK);
|
||||
if (!clk_data)
|
||||
return -ENOMEM;
|
||||
|
||||
mtk_clk_register_gates(&pdev->dev, node, ifr_clks,
|
||||
ARRAY_SIZE(ifr_clks), clk_data);
|
||||
|
||||
@@ -1217,6 +1217,8 @@ static int clk_mt6779_apmixed_probe(struct platform_device *pdev)
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
|
||||
clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK);
|
||||
if (!clk_data)
|
||||
return -ENOMEM;
|
||||
|
||||
mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data);
|
||||
|
||||
@@ -1237,6 +1239,8 @@ static int clk_mt6779_top_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(base);
|
||||
|
||||
clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK);
|
||||
if (!clk_data)
|
||||
return -ENOMEM;
|
||||
|
||||
mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks),
|
||||
clk_data);
|
||||
|
||||
@@ -390,6 +390,8 @@ static int mtk_topckgen_init(struct platform_device *pdev)
|
||||
return PTR_ERR(base);
|
||||
|
||||
clk_data = mtk_alloc_clk_data(CLK_TOP_NR);
|
||||
if (!clk_data)
|
||||
return -ENOMEM;
|
||||
|
||||
mtk_clk_register_factors(top_fixed_divs, ARRAY_SIZE(top_fixed_divs),
|
||||
clk_data);
|
||||
@@ -545,6 +547,8 @@ static void mtk_infrasys_init_early(struct device_node *node)
|
||||
|
||||
if (!infra_clk_data) {
|
||||
infra_clk_data = mtk_alloc_clk_data(CLK_INFRA_NR);
|
||||
if (!infra_clk_data)
|
||||
return;
|
||||
|
||||
for (i = 0; i < CLK_INFRA_NR; i++)
|
||||
infra_clk_data->hws[i] = ERR_PTR(-EPROBE_DEFER);
|
||||
@@ -570,6 +574,8 @@ static int mtk_infrasys_init(struct platform_device *pdev)
|
||||
|
||||
if (!infra_clk_data) {
|
||||
infra_clk_data = mtk_alloc_clk_data(CLK_INFRA_NR);
|
||||
if (!infra_clk_data)
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
for (i = 0; i < CLK_INFRA_NR; i++) {
|
||||
if (infra_clk_data->hws[i] == ERR_PTR(-EPROBE_DEFER))
|
||||
|
||||
@@ -77,6 +77,8 @@ static int clk_mt7629_ethsys_init(struct platform_device *pdev)
|
||||
int r;
|
||||
|
||||
clk_data = mtk_alloc_clk_data(CLK_ETH_NR_CLK);
|
||||
if (!clk_data)
|
||||
return -ENOMEM;
|
||||
|
||||
mtk_clk_register_gates(&pdev->dev, node, eth_clks,
|
||||
CLK_ETH_NR_CLK, clk_data);
|
||||
@@ -100,6 +102,8 @@ static int clk_mt7629_sgmiisys_init(struct platform_device *pdev)
|
||||
int r;
|
||||
|
||||
clk_data = mtk_alloc_clk_data(CLK_SGMII_NR_CLK);
|
||||
if (!clk_data)
|
||||
return -ENOMEM;
|
||||
|
||||
mtk_clk_register_gates(&pdev->dev, node, sgmii_clks[id++],
|
||||
CLK_SGMII_NR_CLK, clk_data);
|
||||
|
||||
@@ -555,6 +555,8 @@ static int mtk_topckgen_init(struct platform_device *pdev)
|
||||
return PTR_ERR(base);
|
||||
|
||||
clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK);
|
||||
if (!clk_data)
|
||||
return -ENOMEM;
|
||||
|
||||
mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks),
|
||||
clk_data);
|
||||
@@ -579,6 +581,8 @@ static int mtk_infrasys_init(struct platform_device *pdev)
|
||||
struct clk_hw_onecell_data *clk_data;
|
||||
|
||||
clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK);
|
||||
if (!clk_data)
|
||||
return -ENOMEM;
|
||||
|
||||
mtk_clk_register_gates(&pdev->dev, node, infra_clks,
|
||||
ARRAY_SIZE(infra_clks), clk_data);
|
||||
@@ -602,6 +606,8 @@ static int mtk_pericfg_init(struct platform_device *pdev)
|
||||
return PTR_ERR(base);
|
||||
|
||||
clk_data = mtk_alloc_clk_data(CLK_PERI_NR_CLK);
|
||||
if (!clk_data)
|
||||
return -ENOMEM;
|
||||
|
||||
mtk_clk_register_gates(&pdev->dev, node, peri_clks,
|
||||
ARRAY_SIZE(peri_clks), clk_data);
|
||||
|
||||
@@ -321,10 +321,8 @@ struct clk_hw *mtk_clk_register_pll_ops(struct mtk_clk_pll *pll,
|
||||
|
||||
ret = clk_hw_register(NULL, &pll->hw);
|
||||
|
||||
if (ret) {
|
||||
kfree(pll);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return &pll->hw;
|
||||
}
|
||||
@@ -340,6 +338,8 @@ struct clk_hw *mtk_clk_register_pll(const struct mtk_pll_data *data,
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
hw = mtk_clk_register_pll_ops(pll, data, base, &mtk_pll_ops);
|
||||
if (IS_ERR(hw))
|
||||
kfree(pll);
|
||||
|
||||
return hw;
|
||||
}
|
||||
|
||||
@@ -144,4 +144,29 @@ config COMMON_CLK_G12A
|
||||
help
|
||||
Support for the clock controller on Amlogic S905D2, S905X2 and S905Y2
|
||||
devices, aka g12a. Say Y if you want peripherals to work.
|
||||
|
||||
config COMMON_CLK_S4_PLL
|
||||
tristate "S4 SoC PLL clock controllers support"
|
||||
depends on ARM64
|
||||
default y
|
||||
select COMMON_CLK_MESON_CLKC_UTILS
|
||||
select COMMON_CLK_MESON_MPLL
|
||||
select COMMON_CLK_MESON_PLL
|
||||
select COMMON_CLK_MESON_REGMAP
|
||||
help
|
||||
Support for the PLL clock controller on Amlogic S805X2 and S905Y4 devices,
|
||||
AKA S4. Say Y if you want the board to work, because PLLs are the parent of
|
||||
most peripherals.
|
||||
|
||||
config COMMON_CLK_S4_PERIPHERALS
|
||||
tristate "S4 SoC peripherals clock controllers support"
|
||||
depends on ARM64
|
||||
default y
|
||||
select COMMON_CLK_MESON_CLKC_UTILS
|
||||
select COMMON_CLK_MESON_REGMAP
|
||||
select COMMON_CLK_MESON_DUALDIV
|
||||
select COMMON_CLK_MESON_VID_PLL_DIV
|
||||
help
|
||||
Support for the peripherals clock controller on Amlogic S805X2 and S905Y4
|
||||
devices, AKA S4. Say Y if you want S4 peripherals clock controller to work.
|
||||
endmenu
|
||||
|
||||
@@ -22,3 +22,5 @@ obj-$(CONFIG_COMMON_CLK_A1_PERIPHERALS) += a1-peripherals.o
|
||||
obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
|
||||
obj-$(CONFIG_COMMON_CLK_G12A) += g12a.o g12a-aoclk.o
|
||||
obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o meson8-ddr.o
|
||||
obj-$(CONFIG_COMMON_CLK_S4_PLL) += s4-pll.o
|
||||
obj-$(CONFIG_COMMON_CLK_S4_PERIPHERALS) += s4-peripherals.o
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,56 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */
|
||||
/*
|
||||
* Copyright (c) 2022-2023 Amlogic, inc. All rights reserved
|
||||
* Author: Yu Tu <yu.tu@amlogic.com>
|
||||
*/
|
||||
|
||||
#ifndef __MESON_S4_PERIPHERALS_H__
|
||||
#define __MESON_S4_PERIPHERALS_H__
|
||||
|
||||
#define CLKCTRL_RTC_BY_OSCIN_CTRL0 0x008
|
||||
#define CLKCTRL_RTC_BY_OSCIN_CTRL1 0x00c
|
||||
#define CLKCTRL_RTC_CTRL 0x010
|
||||
#define CLKCTRL_SYS_CLK_CTRL0 0x040
|
||||
#define CLKCTRL_SYS_CLK_EN0_REG0 0x044
|
||||
#define CLKCTRL_SYS_CLK_EN0_REG1 0x048
|
||||
#define CLKCTRL_SYS_CLK_EN0_REG2 0x04c
|
||||
#define CLKCTRL_SYS_CLK_EN0_REG3 0x050
|
||||
#define CLKCTRL_CECA_CTRL0 0x088
|
||||
#define CLKCTRL_CECA_CTRL1 0x08c
|
||||
#define CLKCTRL_CECB_CTRL0 0x090
|
||||
#define CLKCTRL_CECB_CTRL1 0x094
|
||||
#define CLKCTRL_SC_CLK_CTRL 0x098
|
||||
#define CLKCTRL_CLK12_24_CTRL 0x0a8
|
||||
#define CLKCTRL_VID_CLK_CTRL 0x0c0
|
||||
#define CLKCTRL_VID_CLK_CTRL2 0x0c4
|
||||
#define CLKCTRL_VID_CLK_DIV 0x0c8
|
||||
#define CLKCTRL_VIID_CLK_DIV 0x0cc
|
||||
#define CLKCTRL_VIID_CLK_CTRL 0x0d0
|
||||
#define CLKCTRL_HDMI_CLK_CTRL 0x0e0
|
||||
#define CLKCTRL_VID_PLL_CLK_DIV 0x0e4
|
||||
#define CLKCTRL_VPU_CLK_CTRL 0x0e8
|
||||
#define CLKCTRL_VPU_CLKB_CTRL 0x0ec
|
||||
#define CLKCTRL_VPU_CLKC_CTRL 0x0f0
|
||||
#define CLKCTRL_VID_LOCK_CLK_CTRL 0x0f4
|
||||
#define CLKCTRL_VDIN_MEAS_CLK_CTRL 0x0f8
|
||||
#define CLKCTRL_VAPBCLK_CTRL 0x0fc
|
||||
#define CLKCTRL_HDCP22_CTRL 0x100
|
||||
#define CLKCTRL_VDEC_CLK_CTRL 0x140
|
||||
#define CLKCTRL_VDEC2_CLK_CTRL 0x144
|
||||
#define CLKCTRL_VDEC3_CLK_CTRL 0x148
|
||||
#define CLKCTRL_VDEC4_CLK_CTRL 0x14c
|
||||
#define CLKCTRL_TS_CLK_CTRL 0x158
|
||||
#define CLKCTRL_MALI_CLK_CTRL 0x15c
|
||||
#define CLKCTRL_NAND_CLK_CTRL 0x168
|
||||
#define CLKCTRL_SD_EMMC_CLK_CTRL 0x16c
|
||||
#define CLKCTRL_SPICC_CLK_CTRL 0x174
|
||||
#define CLKCTRL_GEN_CLK_CTRL 0x178
|
||||
#define CLKCTRL_SAR_CLK_CTRL 0x17c
|
||||
#define CLKCTRL_PWM_CLK_AB_CTRL 0x180
|
||||
#define CLKCTRL_PWM_CLK_CD_CTRL 0x184
|
||||
#define CLKCTRL_PWM_CLK_EF_CTRL 0x188
|
||||
#define CLKCTRL_PWM_CLK_GH_CTRL 0x18c
|
||||
#define CLKCTRL_PWM_CLK_IJ_CTRL 0x190
|
||||
#define CLKCTRL_DEMOD_CLK_CTRL 0x200
|
||||
|
||||
#endif /* __MESON_S4_PERIPHERALS_H__ */
|
||||
@@ -0,0 +1,867 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0-only OR MIT)
|
||||
/*
|
||||
* Amlogic S4 PLL Clock Controller Driver
|
||||
*
|
||||
* Copyright (c) 2022-2023 Amlogic, inc. All rights reserved
|
||||
* Author: Yu Tu <yu.tu@amlogic.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "clk-mpll.h"
|
||||
#include "clk-pll.h"
|
||||
#include "clk-regmap.h"
|
||||
#include "s4-pll.h"
|
||||
#include "meson-clkc-utils.h"
|
||||
#include <dt-bindings/clock/amlogic,s4-pll-clkc.h>
|
||||
|
||||
static DEFINE_SPINLOCK(meson_clk_lock);
|
||||
|
||||
/*
|
||||
* These clock are a fixed value (fixed_pll is 2GHz) that is initialized by ROMcode.
|
||||
* The chip was changed fixed pll for security reasons. Fixed PLL registers are not writable
|
||||
* in the kernel phase. Write of fixed PLL-related register will cause the system to crash.
|
||||
* Meanwhile, these clock won't ever change at runtime.
|
||||
* For the above reasons, we can only use ro_ops for fixed PLL related clocks.
|
||||
*/
|
||||
static struct clk_regmap s4_fixed_pll_dco = {
|
||||
.data = &(struct meson_clk_pll_data){
|
||||
.en = {
|
||||
.reg_off = ANACTRL_FIXPLL_CTRL0,
|
||||
.shift = 28,
|
||||
.width = 1,
|
||||
},
|
||||
.m = {
|
||||
.reg_off = ANACTRL_FIXPLL_CTRL0,
|
||||
.shift = 0,
|
||||
.width = 8,
|
||||
},
|
||||
.n = {
|
||||
.reg_off = ANACTRL_FIXPLL_CTRL0,
|
||||
.shift = 10,
|
||||
.width = 5,
|
||||
},
|
||||
.l = {
|
||||
.reg_off = ANACTRL_FIXPLL_CTRL0,
|
||||
.shift = 31,
|
||||
.width = 1,
|
||||
},
|
||||
.rst = {
|
||||
.reg_off = ANACTRL_FIXPLL_CTRL0,
|
||||
.shift = 29,
|
||||
.width = 1,
|
||||
},
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "fixed_pll_dco",
|
||||
.ops = &meson_clk_pll_ro_ops,
|
||||
.parent_data = (const struct clk_parent_data []) {
|
||||
{ .fw_name = "xtal", }
|
||||
},
|
||||
.num_parents = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap s4_fixed_pll = {
|
||||
.data = &(struct clk_regmap_div_data){
|
||||
.offset = ANACTRL_FIXPLL_CTRL0,
|
||||
.shift = 16,
|
||||
.width = 2,
|
||||
.flags = CLK_DIVIDER_POWER_OF_TWO,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "fixed_pll",
|
||||
.ops = &clk_regmap_divider_ro_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&s4_fixed_pll_dco.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
/*
|
||||
* This clock won't ever change at runtime so
|
||||
* CLK_SET_RATE_PARENT is not required
|
||||
*/
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_fixed_factor s4_fclk_div2_div = {
|
||||
.mult = 1,
|
||||
.div = 2,
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "fclk_div2_div",
|
||||
.ops = &clk_fixed_factor_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &s4_fixed_pll.hw },
|
||||
.num_parents = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap s4_fclk_div2 = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = ANACTRL_FIXPLL_CTRL1,
|
||||
.bit_idx = 24,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "fclk_div2",
|
||||
.ops = &clk_regmap_gate_ro_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&s4_fclk_div2_div.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_fixed_factor s4_fclk_div3_div = {
|
||||
.mult = 1,
|
||||
.div = 3,
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "fclk_div3_div",
|
||||
.ops = &clk_fixed_factor_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &s4_fixed_pll.hw },
|
||||
.num_parents = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap s4_fclk_div3 = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = ANACTRL_FIXPLL_CTRL1,
|
||||
.bit_idx = 20,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "fclk_div3",
|
||||
.ops = &clk_regmap_gate_ro_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&s4_fclk_div3_div.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_fixed_factor s4_fclk_div4_div = {
|
||||
.mult = 1,
|
||||
.div = 4,
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "fclk_div4_div",
|
||||
.ops = &clk_fixed_factor_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &s4_fixed_pll.hw },
|
||||
.num_parents = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap s4_fclk_div4 = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = ANACTRL_FIXPLL_CTRL1,
|
||||
.bit_idx = 21,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "fclk_div4",
|
||||
.ops = &clk_regmap_gate_ro_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&s4_fclk_div4_div.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_fixed_factor s4_fclk_div5_div = {
|
||||
.mult = 1,
|
||||
.div = 5,
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "fclk_div5_div",
|
||||
.ops = &clk_fixed_factor_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &s4_fixed_pll.hw },
|
||||
.num_parents = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap s4_fclk_div5 = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = ANACTRL_FIXPLL_CTRL1,
|
||||
.bit_idx = 22,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "fclk_div5",
|
||||
.ops = &clk_regmap_gate_ro_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&s4_fclk_div5_div.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_fixed_factor s4_fclk_div7_div = {
|
||||
.mult = 1,
|
||||
.div = 7,
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "fclk_div7_div",
|
||||
.ops = &clk_fixed_factor_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &s4_fixed_pll.hw },
|
||||
.num_parents = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap s4_fclk_div7 = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = ANACTRL_FIXPLL_CTRL1,
|
||||
.bit_idx = 23,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "fclk_div7",
|
||||
.ops = &clk_regmap_gate_ro_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&s4_fclk_div7_div.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_fixed_factor s4_fclk_div2p5_div = {
|
||||
.mult = 2,
|
||||
.div = 5,
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "fclk_div2p5_div",
|
||||
.ops = &clk_fixed_factor_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&s4_fixed_pll.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap s4_fclk_div2p5 = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = ANACTRL_FIXPLL_CTRL1,
|
||||
.bit_idx = 25,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "fclk_div2p5",
|
||||
.ops = &clk_regmap_gate_ro_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&s4_fclk_div2p5_div.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct pll_mult_range s4_gp0_pll_mult_range = {
|
||||
.min = 125,
|
||||
.max = 250,
|
||||
};
|
||||
|
||||
/*
|
||||
* Internal gp0 pll emulation configuration parameters
|
||||
*/
|
||||
static const struct reg_sequence s4_gp0_init_regs[] = {
|
||||
{ .reg = ANACTRL_GP0PLL_CTRL1, .def = 0x00000000 },
|
||||
{ .reg = ANACTRL_GP0PLL_CTRL2, .def = 0x00000000 },
|
||||
{ .reg = ANACTRL_GP0PLL_CTRL3, .def = 0x48681c00 },
|
||||
{ .reg = ANACTRL_GP0PLL_CTRL4, .def = 0x88770290 },
|
||||
{ .reg = ANACTRL_GP0PLL_CTRL5, .def = 0x39272000 },
|
||||
{ .reg = ANACTRL_GP0PLL_CTRL6, .def = 0x56540000 }
|
||||
};
|
||||
|
||||
static struct clk_regmap s4_gp0_pll_dco = {
|
||||
.data = &(struct meson_clk_pll_data){
|
||||
.en = {
|
||||
.reg_off = ANACTRL_GP0PLL_CTRL0,
|
||||
.shift = 28,
|
||||
.width = 1,
|
||||
},
|
||||
.m = {
|
||||
.reg_off = ANACTRL_GP0PLL_CTRL0,
|
||||
.shift = 0,
|
||||
.width = 8,
|
||||
},
|
||||
.n = {
|
||||
.reg_off = ANACTRL_GP0PLL_CTRL0,
|
||||
.shift = 10,
|
||||
.width = 5,
|
||||
},
|
||||
.l = {
|
||||
.reg_off = ANACTRL_GP0PLL_CTRL0,
|
||||
.shift = 31,
|
||||
.width = 1,
|
||||
},
|
||||
.rst = {
|
||||
.reg_off = ANACTRL_GP0PLL_CTRL0,
|
||||
.shift = 29,
|
||||
.width = 1,
|
||||
},
|
||||
.range = &s4_gp0_pll_mult_range,
|
||||
.init_regs = s4_gp0_init_regs,
|
||||
.init_count = ARRAY_SIZE(s4_gp0_init_regs),
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "gp0_pll_dco",
|
||||
.ops = &meson_clk_pll_ops,
|
||||
.parent_data = (const struct clk_parent_data []) {
|
||||
{ .fw_name = "xtal", }
|
||||
},
|
||||
.num_parents = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap s4_gp0_pll = {
|
||||
.data = &(struct clk_regmap_div_data){
|
||||
.offset = ANACTRL_GP0PLL_CTRL0,
|
||||
.shift = 16,
|
||||
.width = 3,
|
||||
.flags = (CLK_DIVIDER_POWER_OF_TWO |
|
||||
CLK_DIVIDER_ROUND_CLOSEST),
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "gp0_pll",
|
||||
.ops = &clk_regmap_divider_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&s4_gp0_pll_dco.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* Internal hifi pll emulation configuration parameters
|
||||
*/
|
||||
static const struct reg_sequence s4_hifi_init_regs[] = {
|
||||
{ .reg = ANACTRL_HIFIPLL_CTRL1, .def = 0x00010e56 },
|
||||
{ .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00000000 },
|
||||
{ .reg = ANACTRL_HIFIPLL_CTRL3, .def = 0x6a285c00 },
|
||||
{ .reg = ANACTRL_HIFIPLL_CTRL4, .def = 0x65771290 },
|
||||
{ .reg = ANACTRL_HIFIPLL_CTRL5, .def = 0x39272000 },
|
||||
{ .reg = ANACTRL_HIFIPLL_CTRL6, .def = 0x56540000 }
|
||||
};
|
||||
|
||||
static struct clk_regmap s4_hifi_pll_dco = {
|
||||
.data = &(struct meson_clk_pll_data){
|
||||
.en = {
|
||||
.reg_off = ANACTRL_HIFIPLL_CTRL0,
|
||||
.shift = 28,
|
||||
.width = 1,
|
||||
},
|
||||
.m = {
|
||||
.reg_off = ANACTRL_HIFIPLL_CTRL0,
|
||||
.shift = 0,
|
||||
.width = 8,
|
||||
},
|
||||
.n = {
|
||||
.reg_off = ANACTRL_HIFIPLL_CTRL0,
|
||||
.shift = 10,
|
||||
.width = 5,
|
||||
},
|
||||
.l = {
|
||||
.reg_off = ANACTRL_HIFIPLL_CTRL0,
|
||||
.shift = 31,
|
||||
.width = 1,
|
||||
},
|
||||
.rst = {
|
||||
.reg_off = ANACTRL_HIFIPLL_CTRL0,
|
||||
.shift = 29,
|
||||
.width = 1,
|
||||
},
|
||||
.range = &s4_gp0_pll_mult_range,
|
||||
.init_regs = s4_hifi_init_regs,
|
||||
.init_count = ARRAY_SIZE(s4_hifi_init_regs),
|
||||
.flags = CLK_MESON_PLL_ROUND_CLOSEST,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "hifi_pll_dco",
|
||||
.ops = &meson_clk_pll_ops,
|
||||
.parent_data = (const struct clk_parent_data []) {
|
||||
{ .fw_name = "xtal", }
|
||||
},
|
||||
.num_parents = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap s4_hifi_pll = {
|
||||
.data = &(struct clk_regmap_div_data){
|
||||
.offset = ANACTRL_HIFIPLL_CTRL0,
|
||||
.shift = 16,
|
||||
.width = 2,
|
||||
.flags = (CLK_DIVIDER_POWER_OF_TWO |
|
||||
CLK_DIVIDER_ROUND_CLOSEST),
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "hifi_pll",
|
||||
.ops = &clk_regmap_divider_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&s4_hifi_pll_dco.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap s4_hdmi_pll_dco = {
|
||||
.data = &(struct meson_clk_pll_data){
|
||||
.en = {
|
||||
.reg_off = ANACTRL_HDMIPLL_CTRL0,
|
||||
.shift = 28,
|
||||
.width = 1,
|
||||
},
|
||||
.m = {
|
||||
.reg_off = ANACTRL_HDMIPLL_CTRL0,
|
||||
.shift = 0,
|
||||
.width = 8,
|
||||
},
|
||||
.n = {
|
||||
.reg_off = ANACTRL_HDMIPLL_CTRL0,
|
||||
.shift = 10,
|
||||
.width = 5,
|
||||
},
|
||||
.l = {
|
||||
.reg_off = ANACTRL_HDMIPLL_CTRL0,
|
||||
.shift = 31,
|
||||
.width = 1,
|
||||
},
|
||||
.rst = {
|
||||
.reg_off = ANACTRL_HDMIPLL_CTRL0,
|
||||
.shift = 29,
|
||||
.width = 1,
|
||||
},
|
||||
.range = &s4_gp0_pll_mult_range,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "hdmi_pll_dco",
|
||||
.ops = &meson_clk_pll_ops,
|
||||
.parent_data = (const struct clk_parent_data []) {
|
||||
{ .fw_name = "xtal", }
|
||||
},
|
||||
.num_parents = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap s4_hdmi_pll_od = {
|
||||
.data = &(struct clk_regmap_div_data){
|
||||
.offset = ANACTRL_HDMIPLL_CTRL0,
|
||||
.shift = 16,
|
||||
.width = 4,
|
||||
.flags = CLK_DIVIDER_POWER_OF_TWO,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "hdmi_pll_od",
|
||||
.ops = &clk_regmap_divider_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&s4_hdmi_pll_dco.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap s4_hdmi_pll = {
|
||||
.data = &(struct clk_regmap_div_data){
|
||||
.offset = ANACTRL_HDMIPLL_CTRL0,
|
||||
.shift = 20,
|
||||
.width = 2,
|
||||
.flags = CLK_DIVIDER_POWER_OF_TWO,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "hdmi_pll",
|
||||
.ops = &clk_regmap_divider_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&s4_hdmi_pll_od.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_fixed_factor s4_mpll_50m_div = {
|
||||
.mult = 1,
|
||||
.div = 80,
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "mpll_50m_div",
|
||||
.ops = &clk_fixed_factor_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&s4_fixed_pll_dco.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap s4_mpll_50m = {
|
||||
.data = &(struct clk_regmap_mux_data){
|
||||
.offset = ANACTRL_FIXPLL_CTRL3,
|
||||
.mask = 0x1,
|
||||
.shift = 5,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "mpll_50m",
|
||||
.ops = &clk_regmap_mux_ro_ops,
|
||||
.parent_data = (const struct clk_parent_data []) {
|
||||
{ .fw_name = "xtal", },
|
||||
{ .hw = &s4_mpll_50m_div.hw },
|
||||
},
|
||||
.num_parents = 2,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_fixed_factor s4_mpll_prediv = {
|
||||
.mult = 1,
|
||||
.div = 2,
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "mpll_prediv",
|
||||
.ops = &clk_fixed_factor_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&s4_fixed_pll_dco.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct reg_sequence s4_mpll0_init_regs[] = {
|
||||
{ .reg = ANACTRL_MPLL_CTRL2, .def = 0x40000033 }
|
||||
};
|
||||
|
||||
static struct clk_regmap s4_mpll0_div = {
|
||||
.data = &(struct meson_clk_mpll_data){
|
||||
.sdm = {
|
||||
.reg_off = ANACTRL_MPLL_CTRL1,
|
||||
.shift = 0,
|
||||
.width = 14,
|
||||
},
|
||||
.sdm_en = {
|
||||
.reg_off = ANACTRL_MPLL_CTRL1,
|
||||
.shift = 30,
|
||||
.width = 1,
|
||||
},
|
||||
.n2 = {
|
||||
.reg_off = ANACTRL_MPLL_CTRL1,
|
||||
.shift = 20,
|
||||
.width = 9,
|
||||
},
|
||||
.ssen = {
|
||||
.reg_off = ANACTRL_MPLL_CTRL1,
|
||||
.shift = 29,
|
||||
.width = 1,
|
||||
},
|
||||
.lock = &meson_clk_lock,
|
||||
.init_regs = s4_mpll0_init_regs,
|
||||
.init_count = ARRAY_SIZE(s4_mpll0_init_regs),
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "mpll0_div",
|
||||
.ops = &meson_clk_mpll_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&s4_mpll_prediv.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap s4_mpll0 = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = ANACTRL_MPLL_CTRL1,
|
||||
.bit_idx = 31,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "mpll0",
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &s4_mpll0_div.hw },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct reg_sequence s4_mpll1_init_regs[] = {
|
||||
{ .reg = ANACTRL_MPLL_CTRL4, .def = 0x40000033 }
|
||||
};
|
||||
|
||||
static struct clk_regmap s4_mpll1_div = {
|
||||
.data = &(struct meson_clk_mpll_data){
|
||||
.sdm = {
|
||||
.reg_off = ANACTRL_MPLL_CTRL3,
|
||||
.shift = 0,
|
||||
.width = 14,
|
||||
},
|
||||
.sdm_en = {
|
||||
.reg_off = ANACTRL_MPLL_CTRL3,
|
||||
.shift = 30,
|
||||
.width = 1,
|
||||
},
|
||||
.n2 = {
|
||||
.reg_off = ANACTRL_MPLL_CTRL3,
|
||||
.shift = 20,
|
||||
.width = 9,
|
||||
},
|
||||
.ssen = {
|
||||
.reg_off = ANACTRL_MPLL_CTRL3,
|
||||
.shift = 29,
|
||||
.width = 1,
|
||||
},
|
||||
.lock = &meson_clk_lock,
|
||||
.init_regs = s4_mpll1_init_regs,
|
||||
.init_count = ARRAY_SIZE(s4_mpll1_init_regs),
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "mpll1_div",
|
||||
.ops = &meson_clk_mpll_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&s4_mpll_prediv.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap s4_mpll1 = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = ANACTRL_MPLL_CTRL3,
|
||||
.bit_idx = 31,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "mpll1",
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &s4_mpll1_div.hw },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct reg_sequence s4_mpll2_init_regs[] = {
|
||||
{ .reg = ANACTRL_MPLL_CTRL6, .def = 0x40000033 }
|
||||
};
|
||||
|
||||
static struct clk_regmap s4_mpll2_div = {
|
||||
.data = &(struct meson_clk_mpll_data){
|
||||
.sdm = {
|
||||
.reg_off = ANACTRL_MPLL_CTRL5,
|
||||
.shift = 0,
|
||||
.width = 14,
|
||||
},
|
||||
.sdm_en = {
|
||||
.reg_off = ANACTRL_MPLL_CTRL5,
|
||||
.shift = 30,
|
||||
.width = 1,
|
||||
},
|
||||
.n2 = {
|
||||
.reg_off = ANACTRL_MPLL_CTRL5,
|
||||
.shift = 20,
|
||||
.width = 9,
|
||||
},
|
||||
.ssen = {
|
||||
.reg_off = ANACTRL_MPLL_CTRL5,
|
||||
.shift = 29,
|
||||
.width = 1,
|
||||
},
|
||||
.lock = &meson_clk_lock,
|
||||
.init_regs = s4_mpll2_init_regs,
|
||||
.init_count = ARRAY_SIZE(s4_mpll2_init_regs),
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "mpll2_div",
|
||||
.ops = &meson_clk_mpll_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&s4_mpll_prediv.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap s4_mpll2 = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = ANACTRL_MPLL_CTRL5,
|
||||
.bit_idx = 31,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "mpll2",
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &s4_mpll2_div.hw },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct reg_sequence s4_mpll3_init_regs[] = {
|
||||
{ .reg = ANACTRL_MPLL_CTRL8, .def = 0x40000033 }
|
||||
};
|
||||
|
||||
static struct clk_regmap s4_mpll3_div = {
|
||||
.data = &(struct meson_clk_mpll_data){
|
||||
.sdm = {
|
||||
.reg_off = ANACTRL_MPLL_CTRL7,
|
||||
.shift = 0,
|
||||
.width = 14,
|
||||
},
|
||||
.sdm_en = {
|
||||
.reg_off = ANACTRL_MPLL_CTRL7,
|
||||
.shift = 30,
|
||||
.width = 1,
|
||||
},
|
||||
.n2 = {
|
||||
.reg_off = ANACTRL_MPLL_CTRL7,
|
||||
.shift = 20,
|
||||
.width = 9,
|
||||
},
|
||||
.ssen = {
|
||||
.reg_off = ANACTRL_MPLL_CTRL7,
|
||||
.shift = 29,
|
||||
.width = 1,
|
||||
},
|
||||
.lock = &meson_clk_lock,
|
||||
.init_regs = s4_mpll3_init_regs,
|
||||
.init_count = ARRAY_SIZE(s4_mpll3_init_regs),
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "mpll3_div",
|
||||
.ops = &meson_clk_mpll_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) {
|
||||
&s4_mpll_prediv.hw
|
||||
},
|
||||
.num_parents = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_regmap s4_mpll3 = {
|
||||
.data = &(struct clk_regmap_gate_data){
|
||||
.offset = ANACTRL_MPLL_CTRL7,
|
||||
.bit_idx = 31,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "mpll3",
|
||||
.ops = &clk_regmap_gate_ops,
|
||||
.parent_hws = (const struct clk_hw *[]) { &s4_mpll3_div.hw },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
/* Array of all clocks provided by this provider */
|
||||
static struct clk_hw *s4_pll_hw_clks[] = {
|
||||
[CLKID_FIXED_PLL_DCO] = &s4_fixed_pll_dco.hw,
|
||||
[CLKID_FIXED_PLL] = &s4_fixed_pll.hw,
|
||||
[CLKID_FCLK_DIV2_DIV] = &s4_fclk_div2_div.hw,
|
||||
[CLKID_FCLK_DIV2] = &s4_fclk_div2.hw,
|
||||
[CLKID_FCLK_DIV3_DIV] = &s4_fclk_div3_div.hw,
|
||||
[CLKID_FCLK_DIV3] = &s4_fclk_div3.hw,
|
||||
[CLKID_FCLK_DIV4_DIV] = &s4_fclk_div4_div.hw,
|
||||
[CLKID_FCLK_DIV4] = &s4_fclk_div4.hw,
|
||||
[CLKID_FCLK_DIV5_DIV] = &s4_fclk_div5_div.hw,
|
||||
[CLKID_FCLK_DIV5] = &s4_fclk_div5.hw,
|
||||
[CLKID_FCLK_DIV7_DIV] = &s4_fclk_div7_div.hw,
|
||||
[CLKID_FCLK_DIV7] = &s4_fclk_div7.hw,
|
||||
[CLKID_FCLK_DIV2P5_DIV] = &s4_fclk_div2p5_div.hw,
|
||||
[CLKID_FCLK_DIV2P5] = &s4_fclk_div2p5.hw,
|
||||
[CLKID_GP0_PLL_DCO] = &s4_gp0_pll_dco.hw,
|
||||
[CLKID_GP0_PLL] = &s4_gp0_pll.hw,
|
||||
[CLKID_HIFI_PLL_DCO] = &s4_hifi_pll_dco.hw,
|
||||
[CLKID_HIFI_PLL] = &s4_hifi_pll.hw,
|
||||
[CLKID_HDMI_PLL_DCO] = &s4_hdmi_pll_dco.hw,
|
||||
[CLKID_HDMI_PLL_OD] = &s4_hdmi_pll_od.hw,
|
||||
[CLKID_HDMI_PLL] = &s4_hdmi_pll.hw,
|
||||
[CLKID_MPLL_50M_DIV] = &s4_mpll_50m_div.hw,
|
||||
[CLKID_MPLL_50M] = &s4_mpll_50m.hw,
|
||||
[CLKID_MPLL_PREDIV] = &s4_mpll_prediv.hw,
|
||||
[CLKID_MPLL0_DIV] = &s4_mpll0_div.hw,
|
||||
[CLKID_MPLL0] = &s4_mpll0.hw,
|
||||
[CLKID_MPLL1_DIV] = &s4_mpll1_div.hw,
|
||||
[CLKID_MPLL1] = &s4_mpll1.hw,
|
||||
[CLKID_MPLL2_DIV] = &s4_mpll2_div.hw,
|
||||
[CLKID_MPLL2] = &s4_mpll2.hw,
|
||||
[CLKID_MPLL3_DIV] = &s4_mpll3_div.hw,
|
||||
[CLKID_MPLL3] = &s4_mpll3.hw,
|
||||
};
|
||||
|
||||
static struct clk_regmap *const s4_pll_clk_regmaps[] = {
|
||||
&s4_fixed_pll_dco,
|
||||
&s4_fixed_pll,
|
||||
&s4_fclk_div2,
|
||||
&s4_fclk_div3,
|
||||
&s4_fclk_div4,
|
||||
&s4_fclk_div5,
|
||||
&s4_fclk_div7,
|
||||
&s4_fclk_div2p5,
|
||||
&s4_gp0_pll_dco,
|
||||
&s4_gp0_pll,
|
||||
&s4_hifi_pll_dco,
|
||||
&s4_hifi_pll,
|
||||
&s4_hdmi_pll_dco,
|
||||
&s4_hdmi_pll_od,
|
||||
&s4_hdmi_pll,
|
||||
&s4_mpll_50m,
|
||||
&s4_mpll0_div,
|
||||
&s4_mpll0,
|
||||
&s4_mpll1_div,
|
||||
&s4_mpll1,
|
||||
&s4_mpll2_div,
|
||||
&s4_mpll2,
|
||||
&s4_mpll3_div,
|
||||
&s4_mpll3,
|
||||
};
|
||||
|
||||
static const struct reg_sequence s4_init_regs[] = {
|
||||
{ .reg = ANACTRL_MPLL_CTRL0, .def = 0x00000543 },
|
||||
};
|
||||
|
||||
static struct regmap_config clkc_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
};
|
||||
|
||||
static struct meson_clk_hw_data s4_pll_clks = {
|
||||
.hws = s4_pll_hw_clks,
|
||||
.num = ARRAY_SIZE(s4_pll_hw_clks),
|
||||
};
|
||||
|
||||
static int meson_s4_pll_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct regmap *regmap;
|
||||
void __iomem *base;
|
||||
int ret, i;
|
||||
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base))
|
||||
return dev_err_probe(dev, PTR_ERR(base),
|
||||
"can't ioremap resource\n");
|
||||
|
||||
regmap = devm_regmap_init_mmio(dev, base, &clkc_regmap_config);
|
||||
if (IS_ERR(regmap))
|
||||
return dev_err_probe(dev, PTR_ERR(regmap),
|
||||
"can't init regmap mmio region\n");
|
||||
|
||||
ret = regmap_multi_reg_write(regmap, s4_init_regs, ARRAY_SIZE(s4_init_regs));
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to init registers\n");
|
||||
|
||||
/* Populate regmap for the regmap backed clocks */
|
||||
for (i = 0; i < ARRAY_SIZE(s4_pll_clk_regmaps); i++)
|
||||
s4_pll_clk_regmaps[i]->map = regmap;
|
||||
|
||||
/* Register clocks */
|
||||
for (i = 0; i < s4_pll_clks.num; i++) {
|
||||
/* array might be sparse */
|
||||
if (!s4_pll_clks.hws[i])
|
||||
continue;
|
||||
|
||||
ret = devm_clk_hw_register(dev, s4_pll_clks.hws[i]);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"clock[%d] registration failed\n", i);
|
||||
}
|
||||
|
||||
return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get,
|
||||
&s4_pll_clks);
|
||||
}
|
||||
|
||||
static const struct of_device_id clkc_match_table[] = {
|
||||
{
|
||||
.compatible = "amlogic,s4-pll-clkc",
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static struct platform_driver s4_driver = {
|
||||
.probe = meson_s4_pll_probe,
|
||||
.driver = {
|
||||
.name = "s4-pll-clkc",
|
||||
.of_match_table = clkc_match_table,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(s4_driver);
|
||||
MODULE_AUTHOR("Yu Tu <yu.tu@amlogic.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -0,0 +1,38 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */
|
||||
/*
|
||||
* Copyright (c) 2022-2023 Amlogic, inc. All rights reserved
|
||||
* Author: Yu Tu <yu.tu@amlogic.com>
|
||||
*/
|
||||
|
||||
#ifndef __MESON_S4_PLL_H__
|
||||
#define __MESON_S4_PLL_H__
|
||||
|
||||
#define ANACTRL_FIXPLL_CTRL0 0x040
|
||||
#define ANACTRL_FIXPLL_CTRL1 0x044
|
||||
#define ANACTRL_FIXPLL_CTRL3 0x04c
|
||||
#define ANACTRL_GP0PLL_CTRL0 0x080
|
||||
#define ANACTRL_GP0PLL_CTRL1 0x084
|
||||
#define ANACTRL_GP0PLL_CTRL2 0x088
|
||||
#define ANACTRL_GP0PLL_CTRL3 0x08c
|
||||
#define ANACTRL_GP0PLL_CTRL4 0x090
|
||||
#define ANACTRL_GP0PLL_CTRL5 0x094
|
||||
#define ANACTRL_GP0PLL_CTRL6 0x098
|
||||
#define ANACTRL_HIFIPLL_CTRL0 0x100
|
||||
#define ANACTRL_HIFIPLL_CTRL1 0x104
|
||||
#define ANACTRL_HIFIPLL_CTRL2 0x108
|
||||
#define ANACTRL_HIFIPLL_CTRL3 0x10c
|
||||
#define ANACTRL_HIFIPLL_CTRL4 0x110
|
||||
#define ANACTRL_HIFIPLL_CTRL5 0x114
|
||||
#define ANACTRL_HIFIPLL_CTRL6 0x118
|
||||
#define ANACTRL_MPLL_CTRL0 0x180
|
||||
#define ANACTRL_MPLL_CTRL1 0x184
|
||||
#define ANACTRL_MPLL_CTRL2 0x188
|
||||
#define ANACTRL_MPLL_CTRL3 0x18c
|
||||
#define ANACTRL_MPLL_CTRL4 0x190
|
||||
#define ANACTRL_MPLL_CTRL5 0x194
|
||||
#define ANACTRL_MPLL_CTRL6 0x198
|
||||
#define ANACTRL_MPLL_CTRL7 0x19c
|
||||
#define ANACTRL_MPLL_CTRL8 0x1a0
|
||||
#define ANACTRL_HDMIPLL_CTRL0 0x1c0
|
||||
|
||||
#endif /* __MESON_S4_PLL_H__ */
|
||||
@@ -131,6 +131,7 @@ config IPQ_APSS_6018
|
||||
tristate "IPQ APSS Clock Controller"
|
||||
select IPQ_APSS_PLL
|
||||
depends on QCOM_APCS_IPC || COMPILE_TEST
|
||||
depends on QCOM_SMEM
|
||||
help
|
||||
Support for APSS clock controller on IPQ platforms. The
|
||||
APSS clock controller manages the Mux and enable block that feeds the
|
||||
@@ -764,6 +765,13 @@ config SM_CAMCC_8450
|
||||
Support for the camera clock controller on SM8450 devices.
|
||||
Say Y if you want to support camera devices and camera functionality.
|
||||
|
||||
config SM_CAMCC_8550
|
||||
tristate "SM8550 Camera Clock Controller"
|
||||
select SM_GCC_8550
|
||||
help
|
||||
Support for the camera clock controller on SM8550 devices.
|
||||
Say Y if you want to support camera devices and camera functionality.
|
||||
|
||||
config SM_DISPCC_6115
|
||||
tristate "SM6115 Display Clock Controller"
|
||||
depends on ARM64 || COMPILE_TEST
|
||||
@@ -834,6 +842,15 @@ config SM_DISPCC_8550
|
||||
Say Y if you want to support display devices and functionality such as
|
||||
splash screen.
|
||||
|
||||
config SM_GCC_4450
|
||||
tristate "SM4450 Global Clock Controller"
|
||||
depends on ARM64 || COMPILE_TEST
|
||||
select QCOM_GDSC
|
||||
help
|
||||
Support for the global clock controller on SM4450 devices.
|
||||
Say Y if you want to use peripheral devices such as UART, SPI,
|
||||
I2C, USB, SD/UFS, PCIe, etc.
|
||||
|
||||
config SM_GCC_6115
|
||||
tristate "SM6115 and SM4250 Global Clock Controller"
|
||||
depends on ARM64 || COMPILE_TEST
|
||||
|
||||
@@ -102,6 +102,7 @@ obj-$(CONFIG_SDX_GCC_75) += gcc-sdx75.o
|
||||
obj-$(CONFIG_SM_CAMCC_6350) += camcc-sm6350.o
|
||||
obj-$(CONFIG_SM_CAMCC_8250) += camcc-sm8250.o
|
||||
obj-$(CONFIG_SM_CAMCC_8450) += camcc-sm8450.o
|
||||
obj-$(CONFIG_SM_CAMCC_8550) += camcc-sm8550.o
|
||||
obj-$(CONFIG_SM_DISPCC_6115) += dispcc-sm6115.o
|
||||
obj-$(CONFIG_SM_DISPCC_6125) += dispcc-sm6125.o
|
||||
obj-$(CONFIG_SM_DISPCC_6350) += dispcc-sm6350.o
|
||||
@@ -109,6 +110,7 @@ obj-$(CONFIG_SM_DISPCC_6375) += dispcc-sm6375.o
|
||||
obj-$(CONFIG_SM_DISPCC_8250) += dispcc-sm8250.o
|
||||
obj-$(CONFIG_SM_DISPCC_8450) += dispcc-sm8450.o
|
||||
obj-$(CONFIG_SM_DISPCC_8550) += dispcc-sm8550.o
|
||||
obj-$(CONFIG_SM_GCC_4450) += gcc-sm4450.o
|
||||
obj-$(CONFIG_SM_GCC_6115) += gcc-sm6115.o
|
||||
obj-$(CONFIG_SM_GCC_6125) += gcc-sm6125.o
|
||||
obj-$(CONFIG_SM_GCC_6350) += gcc-sm6350.o
|
||||
|
||||
@@ -68,13 +68,13 @@ static struct clk_alpha_pll ipq_pll_stromer_plus = {
|
||||
.fw_name = "xo",
|
||||
},
|
||||
.num_parents = 1,
|
||||
.ops = &clk_alpha_pll_stromer_ops,
|
||||
.ops = &clk_alpha_pll_stromer_plus_ops,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static const struct alpha_pll_config ipq5332_pll_config = {
|
||||
.l = 0x3e,
|
||||
.l = 0x2d,
|
||||
.config_ctl_val = 0x4001075b,
|
||||
.config_ctl_hi_val = 0x304,
|
||||
.main_output_mask = BIT(0),
|
||||
|
||||
@@ -9,8 +9,11 @@
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/soc/qcom/smem.h>
|
||||
|
||||
#include <dt-bindings/clock/qcom,apss-ipq.h>
|
||||
#include <dt-bindings/arm/qcom,ids.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "clk-regmap.h"
|
||||
@@ -20,16 +23,19 @@
|
||||
|
||||
enum {
|
||||
P_XO,
|
||||
P_GPLL0,
|
||||
P_APSS_PLL_EARLY,
|
||||
};
|
||||
|
||||
static const struct clk_parent_data parents_apcs_alias0_clk_src[] = {
|
||||
{ .fw_name = "xo" },
|
||||
{ .fw_name = "gpll0" },
|
||||
{ .fw_name = "pll" },
|
||||
};
|
||||
|
||||
static const struct parent_map parents_apcs_alias0_clk_src_map[] = {
|
||||
{ P_XO, 0 },
|
||||
{ P_GPLL0, 4 },
|
||||
{ P_APSS_PLL_EARLY, 5 },
|
||||
};
|
||||
|
||||
@@ -81,15 +87,68 @@ static const struct qcom_cc_desc apss_ipq6018_desc = {
|
||||
.num_clks = ARRAY_SIZE(apss_ipq6018_clks),
|
||||
};
|
||||
|
||||
static int cpu_clk_notifier_fn(struct notifier_block *nb, unsigned long action,
|
||||
void *data)
|
||||
{
|
||||
struct clk_hw *hw;
|
||||
u8 index;
|
||||
int err;
|
||||
|
||||
if (action == PRE_RATE_CHANGE)
|
||||
index = P_GPLL0;
|
||||
else if (action == POST_RATE_CHANGE || action == ABORT_RATE_CHANGE)
|
||||
index = P_APSS_PLL_EARLY;
|
||||
else
|
||||
return NOTIFY_OK;
|
||||
|
||||
hw = &apcs_alias0_clk_src.clkr.hw;
|
||||
err = clk_rcg2_mux_closest_ops.set_parent(hw, index);
|
||||
|
||||
return notifier_from_errno(err);
|
||||
}
|
||||
|
||||
static int apss_ipq6018_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct clk_hw *hw = &apcs_alias0_clk_src.clkr.hw;
|
||||
struct notifier_block *cpu_clk_notifier;
|
||||
struct regmap *regmap;
|
||||
u32 soc_id;
|
||||
int ret;
|
||||
|
||||
ret = qcom_smem_get_soc_id(&soc_id);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
regmap = dev_get_regmap(pdev->dev.parent, NULL);
|
||||
if (!regmap)
|
||||
return -ENODEV;
|
||||
|
||||
return qcom_cc_really_probe(pdev, &apss_ipq6018_desc, regmap);
|
||||
ret = qcom_cc_really_probe(pdev, &apss_ipq6018_desc, regmap);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (soc_id) {
|
||||
/* Only below variants of IPQ53xx support scaling */
|
||||
case QCOM_ID_IPQ5332:
|
||||
case QCOM_ID_IPQ5322:
|
||||
case QCOM_ID_IPQ5300:
|
||||
cpu_clk_notifier = devm_kzalloc(&pdev->dev,
|
||||
sizeof(*cpu_clk_notifier),
|
||||
GFP_KERNEL);
|
||||
if (!cpu_clk_notifier)
|
||||
return -ENOMEM;
|
||||
|
||||
cpu_clk_notifier->notifier_call = cpu_clk_notifier_fn;
|
||||
|
||||
ret = devm_clk_notifier_register(&pdev->dev, hw->clk, cpu_clk_notifier);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver apss_ipq6018_driver = {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -271,6 +271,7 @@ EXPORT_SYMBOL_GPL(clk_alpha_pll_regs);
|
||||
#define LUCID_EVO_ENABLE_VOTE_RUN BIT(25)
|
||||
#define LUCID_EVO_PLL_L_VAL_MASK GENMASK(15, 0)
|
||||
#define LUCID_EVO_PLL_CAL_L_VAL_SHIFT 16
|
||||
#define LUCID_OLE_PLL_RINGOSC_CAL_L_VAL_SHIFT 24
|
||||
|
||||
/* ZONDA PLL specific */
|
||||
#define ZONDA_PLL_OUT_MASK 0xf
|
||||
@@ -2119,6 +2120,34 @@ void clk_lucid_evo_pll_configure(struct clk_alpha_pll *pll, struct regmap *regma
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_lucid_evo_pll_configure);
|
||||
|
||||
void clk_lucid_ole_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
|
||||
const struct alpha_pll_config *config)
|
||||
{
|
||||
u32 lval = config->l;
|
||||
|
||||
lval |= TRION_PLL_CAL_VAL << LUCID_EVO_PLL_CAL_L_VAL_SHIFT;
|
||||
lval |= TRION_PLL_CAL_VAL << LUCID_OLE_PLL_RINGOSC_CAL_L_VAL_SHIFT;
|
||||
clk_alpha_pll_write_config(regmap, PLL_L_VAL(pll), lval);
|
||||
clk_alpha_pll_write_config(regmap, PLL_ALPHA_VAL(pll), config->alpha);
|
||||
clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL(pll), config->config_ctl_val);
|
||||
clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL_U(pll), config->config_ctl_hi_val);
|
||||
clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL_U1(pll), config->config_ctl_hi1_val);
|
||||
clk_alpha_pll_write_config(regmap, PLL_USER_CTL(pll), config->user_ctl_val);
|
||||
clk_alpha_pll_write_config(regmap, PLL_USER_CTL_U(pll), config->user_ctl_hi_val);
|
||||
clk_alpha_pll_write_config(regmap, PLL_TEST_CTL(pll), config->test_ctl_val);
|
||||
clk_alpha_pll_write_config(regmap, PLL_TEST_CTL_U(pll), config->test_ctl_hi_val);
|
||||
clk_alpha_pll_write_config(regmap, PLL_TEST_CTL_U1(pll), config->test_ctl_hi1_val);
|
||||
clk_alpha_pll_write_config(regmap, PLL_TEST_CTL_U2(pll), config->test_ctl_hi2_val);
|
||||
|
||||
/* Disable PLL output */
|
||||
regmap_update_bits(regmap, PLL_MODE(pll), PLL_OUTCTRL, 0);
|
||||
|
||||
/* Set operation mode to STANDBY and de-assert the reset */
|
||||
regmap_write(regmap, PLL_OPMODE(pll), PLL_STANDBY);
|
||||
regmap_update_bits(regmap, PLL_MODE(pll), PLL_RESET_N, PLL_RESET_N);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_lucid_ole_pll_configure);
|
||||
|
||||
static int alpha_pll_lucid_evo_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
|
||||
@@ -2479,3 +2508,66 @@ const struct clk_ops clk_alpha_pll_stromer_ops = {
|
||||
.set_rate = clk_alpha_pll_stromer_set_rate,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_alpha_pll_stromer_ops);
|
||||
|
||||
static int clk_alpha_pll_stromer_plus_set_rate(struct clk_hw *hw,
|
||||
unsigned long rate,
|
||||
unsigned long prate)
|
||||
{
|
||||
struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
|
||||
u32 l, alpha_width = pll_alpha_width(pll);
|
||||
int ret, pll_mode;
|
||||
u64 a;
|
||||
|
||||
rate = alpha_pll_round_rate(rate, prate, &l, &a, alpha_width);
|
||||
|
||||
ret = regmap_read(pll->clkr.regmap, PLL_MODE(pll), &pll_mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
regmap_write(pll->clkr.regmap, PLL_MODE(pll), 0);
|
||||
|
||||
/* Delay of 2 output clock ticks required until output is disabled */
|
||||
udelay(1);
|
||||
|
||||
regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l);
|
||||
|
||||
if (alpha_width > ALPHA_BITWIDTH)
|
||||
a <<= alpha_width - ALPHA_BITWIDTH;
|
||||
|
||||
regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll), a);
|
||||
regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL_U(pll),
|
||||
a >> ALPHA_BITWIDTH);
|
||||
|
||||
regmap_write(pll->clkr.regmap, PLL_MODE(pll), PLL_BYPASSNL);
|
||||
|
||||
/* Wait five micro seconds or more */
|
||||
udelay(5);
|
||||
regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_RESET_N,
|
||||
PLL_RESET_N);
|
||||
|
||||
/* The lock time should be less than 50 micro seconds worst case */
|
||||
usleep_range(50, 60);
|
||||
|
||||
ret = wait_for_pll_enable_lock(pll);
|
||||
if (ret) {
|
||||
pr_err("Wait for PLL enable lock failed [%s] %d\n",
|
||||
clk_hw_get_name(hw), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pll_mode & PLL_OUTCTRL)
|
||||
regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_OUTCTRL,
|
||||
PLL_OUTCTRL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct clk_ops clk_alpha_pll_stromer_plus_ops = {
|
||||
.prepare = clk_alpha_pll_enable,
|
||||
.unprepare = clk_alpha_pll_disable,
|
||||
.is_enabled = clk_alpha_pll_is_enabled,
|
||||
.recalc_rate = clk_alpha_pll_recalc_rate,
|
||||
.determine_rate = clk_alpha_pll_stromer_determine_rate,
|
||||
.set_rate = clk_alpha_pll_stromer_plus_set_rate,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_alpha_pll_stromer_plus_ops);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user