forked from Minki/linux
i.MX7ULP device tree for 4.21:
- It includes the initial device tree for i.MX7ULP SoC and EVK board support. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJcDd7aAAoJEFBXWFqHsHzOgNEIAKc4dqYzWmfJTMnJGO+Bb1Rc BPkENpRWk6rWVBuxXwN4MTupXIgj96bBHWsg3kplgcthMRAl2wgomHTpNWXk8R9m Fn6sH9yIoeqr+xs6BzzQ8COrFBXg8CEZgKLgy+9nhfFi3xNf6pN6IQLgqrGF17MC zFH+sM0rqlh1l3BfHXMuwHvbhw+ms6Qo6z68OGSXmu0bUPThm2FV/Akivqp+INSI CeFyZ8RMTkEKVSkFEryZaprKgqlIYW2Kl54yeALjvG03mtn1onaZKqsNV7YonYMC X+mZPLnwjBUnLi2HbKrStmTR0ePQjg5x1tMT+Eco7Cjj4h6H6uBu0IYMi4PiN7o= =aOId -----END PGP SIGNATURE----- Merge tag 'imx7ulp-dt-4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux into next/dt i.MX7ULP device tree for 4.21: - It includes the initial device tree for i.MX7ULP SoC and EVK board support. * tag 'imx7ulp-dt-4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux: ARM: dts: imx: add imx7ulp evk support ARM: dts: imx: add common imx7ulp dtsi support dt-bindings: fsl: add imx7ulp pm related components bindings dt-bindings: fsl: add compatible for imx7ulp evk clk: imx: add imx7ulp clk driver clk: imx: implement new clk_hw based APIs clk: imx: make mux parent strings const dt-bindings: clock: add imx7ulp clock binding doc clk: imx: add imx7ulp composite clk support clk: imx: add pfdv2 support clk: imx: add pllv4 support clk: fractional-divider: add CLK_FRAC_DIVIDER_ZERO_BASED flag support clk: imx: add gatable clock divider support Signed-off-by: Olof Johansson <olof@lixom.net>
This commit is contained in:
commit
fafda335f8
@ -0,0 +1,23 @@
|
||||
Freescale i.MX7ULP Power Management Components
|
||||
----------------------------------------------
|
||||
|
||||
The Multi-System Mode Controller (MSMC) is responsible for sequencing
|
||||
the MCU into and out of all stop and run power modes. Specifically, it
|
||||
monitors events to trigger transitions between power modes while
|
||||
controlling the power, clocks, and memories of the MCU to achieve the
|
||||
power consumption and functionality of that mode.
|
||||
|
||||
The WFI or WFE instruction is used to invoke a Sleep, Deep Sleep or
|
||||
Standby modes for either Cortex family. Run, Wait, and Stop are the
|
||||
common terms used for the primary operating modes of Kinetis
|
||||
microcontrollers.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "fsl,imx7ulp-smc1".
|
||||
- reg: Specifies base physical address and size of the register sets.
|
||||
|
||||
Example:
|
||||
smc1: smc1@40410000 {
|
||||
compatible = "fsl,imx7ulp-smc1";
|
||||
reg = <0x40410000 0x1000>;
|
||||
};
|
@ -101,6 +101,10 @@ i.MX7 SabreSD Board
|
||||
Required root node properties:
|
||||
- compatible = "fsl,imx7d-sdb", "fsl,imx7d";
|
||||
|
||||
i.MX7ULP Evaluation Kit
|
||||
Required root node properties:
|
||||
- compatible = "fsl,imx7ulp-evk", "fsl,imx7ulp";
|
||||
|
||||
Generic i.MX boards
|
||||
-------------------
|
||||
|
||||
@ -123,6 +127,10 @@ i.MX6q generic board
|
||||
Required root node properties:
|
||||
- compatible = "fsl,imx6q";
|
||||
|
||||
i.MX7ULP generic board
|
||||
Required root node properties:
|
||||
- compatible = "fsl,imx7ulp";
|
||||
|
||||
Freescale Vybrid Platform Device Tree Bindings
|
||||
----------------------------------------------
|
||||
|
||||
|
104
Documentation/devicetree/bindings/clock/imx7ulp-clock.txt
Normal file
104
Documentation/devicetree/bindings/clock/imx7ulp-clock.txt
Normal file
@ -0,0 +1,104 @@
|
||||
* Clock bindings for Freescale i.MX7ULP
|
||||
|
||||
i.MX7ULP Clock functions are under joint control of the System
|
||||
Clock Generation (SCG) modules, Peripheral Clock Control (PCC)
|
||||
modules, and Core Mode Controller (CMC)1 blocks
|
||||
|
||||
The clocking scheme provides clear separation between M4 domain
|
||||
and A7 domain. Except for a few clock sources shared between two
|
||||
domains, such as the System Oscillator clock, the Slow IRC (SIRC),
|
||||
and and the Fast IRC clock (FIRCLK), clock sources and clock
|
||||
management are separated and contained within each domain.
|
||||
|
||||
M4 clock management consists of SCG0, PCC0, PCC1, and CMC0 modules.
|
||||
A7 clock management consists of SCG1, PCC2, PCC3, and CMC1 modules.
|
||||
|
||||
Note: this binding doc is only for A7 clock domain.
|
||||
|
||||
System Clock Generation (SCG) modules:
|
||||
---------------------------------------------------------------------
|
||||
The System Clock Generation (SCG) is responsible for clock generation
|
||||
and distribution across this device. Functions performed by the SCG
|
||||
include: clock reference selection, generation of clock used to derive
|
||||
processor, system, peripheral bus and external memory interface clocks,
|
||||
source selection for peripheral clocks and control of power saving
|
||||
clock gating mode.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: Should be "fsl,imx7ulp-scg1".
|
||||
- reg : Should contain registers location and length.
|
||||
- #clock-cells: Should be <1>.
|
||||
- clocks: Should contain the fixed input clocks.
|
||||
- clock-names: Should contain the following clock names:
|
||||
"rosc", "sosc", "sirc", "firc", "upll", "mpll".
|
||||
|
||||
Peripheral Clock Control (PCC) modules:
|
||||
---------------------------------------------------------------------
|
||||
The Peripheral Clock Control (PCC) is responsible for clock selection,
|
||||
optional division and clock gating mode for peripherals in their
|
||||
respected power domain
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be one of:
|
||||
"fsl,imx7ulp-pcc2",
|
||||
"fsl,imx7ulp-pcc3".
|
||||
- reg : Should contain registers location and length.
|
||||
- #clock-cells: Should be <1>.
|
||||
- clocks: Should contain the fixed input clocks.
|
||||
- clock-names: Should contain the following clock names:
|
||||
"nic1_bus_clk", "nic1_clk", "ddr_clk", "apll_pfd2",
|
||||
"apll_pfd1", "apll_pfd0", "upll", "sosc_bus_clk",
|
||||
"mpll", "firc_bus_clk", "rosc", "spll_bus_clk";
|
||||
|
||||
The clock consumer should specify the desired clock by having the clock
|
||||
ID in its "clocks" phandle cell.
|
||||
See include/dt-bindings/clock/imx7ulp-clock.h
|
||||
for the full list of i.MX7ULP clock IDs of each module.
|
||||
|
||||
Examples:
|
||||
|
||||
#include <dt-bindings/clock/imx7ulp-clock.h>
|
||||
|
||||
scg1: scg1@403e0000 {
|
||||
compatible = "fsl,imx7ulp-scg1;
|
||||
reg = <0x403e0000 0x10000>;
|
||||
clocks = <&rosc>, <&sosc>, <&sirc>,
|
||||
<&firc>, <&upll>, <&mpll>;
|
||||
clock-names = "rosc", "sosc", "sirc",
|
||||
"firc", "upll", "mpll";
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
pcc2: pcc2@403f0000 {
|
||||
compatible = "fsl,imx7ulp-pcc2";
|
||||
reg = <0x403f0000 0x10000>;
|
||||
#clock-cells = <1>;
|
||||
clocks = <&scg1 IMX7ULP_CLK_NIC1_BUS_DIV>,
|
||||
<&scg1 IMX7ULP_CLK_NIC1_DIV>,
|
||||
<&scg1 IMX7ULP_CLK_DDR_DIV>,
|
||||
<&scg1 IMX7ULP_CLK_APLL_PFD2>,
|
||||
<&scg1 IMX7ULP_CLK_APLL_PFD1>,
|
||||
<&scg1 IMX7ULP_CLK_APLL_PFD0>,
|
||||
<&scg1 IMX7ULP_CLK_UPLL>,
|
||||
<&scg1 IMX7ULP_CLK_SOSC_BUS_CLK>,
|
||||
<&scg1 IMX7ULP_CLK_MIPI_PLL>,
|
||||
<&scg1 IMX7ULP_CLK_FIRC_BUS_CLK>,
|
||||
<&scg1 IMX7ULP_CLK_ROSC>,
|
||||
<&scg1 IMX7ULP_CLK_SPLL_BUS_CLK>;
|
||||
clock-names = "nic1_bus_clk", "nic1_clk", "ddr_clk",
|
||||
"apll_pfd2", "apll_pfd1", "apll_pfd0",
|
||||
"upll", "sosc_bus_clk", "mpll",
|
||||
"firc_bus_clk", "rosc", "spll_bus_clk";
|
||||
};
|
||||
|
||||
usdhc1: usdhc@40380000 {
|
||||
compatible = "fsl,imx7ulp-usdhc";
|
||||
reg = <0x40380000 0x10000>;
|
||||
interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&scg1 IMX7ULP_CLK_NIC1_BUS_DIV>,
|
||||
<&scg1 IMX7ULP_CLK_NIC1_DIV>,
|
||||
<&pcc2 IMX7ULP_CLK_USDHC1>;
|
||||
clock-names ="ipg", "ahb", "per";
|
||||
bus-width = <4>;
|
||||
};
|
@ -581,6 +581,8 @@ dtb-$(CONFIG_SOC_IMX7D) += \
|
||||
imx7d-sdb-sht11.dtb \
|
||||
imx7s-colibri-eval-v3.dtb \
|
||||
imx7s-warp.dtb
|
||||
dtb-$(CONFIG_SOC_IMX7ULP) += \
|
||||
imx7ulp-evk.dtb
|
||||
dtb-$(CONFIG_SOC_LS1021A) += \
|
||||
ls1021a-moxa-uc-8410a.dtb \
|
||||
ls1021a-qds.dtb \
|
||||
|
77
arch/arm/boot/dts/imx7ulp-evk.dts
Normal file
77
arch/arm/boot/dts/imx7ulp-evk.dts
Normal file
@ -0,0 +1,77 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2016 Freescale Semiconductor, Inc.
|
||||
* Copyright 2017-2018 NXP
|
||||
* Dong Aisheng <aisheng.dong@nxp.com>
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
#include "imx7ulp.dtsi"
|
||||
|
||||
/ {
|
||||
model = "NXP i.MX7ULP EVK";
|
||||
compatible = "fsl,imx7ulp-evk", "fsl,imx7ulp";
|
||||
|
||||
chosen {
|
||||
stdout-path = &lpuart4;
|
||||
};
|
||||
|
||||
memory@60000000 {
|
||||
device_type = "memory";
|
||||
reg = <0x60000000 0x40000000>;
|
||||
};
|
||||
|
||||
reg_vsd_3v3: regulator-vsd-3v3 {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "VSD_3V3";
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_usdhc0_rst>;
|
||||
gpio = <&gpio_ptd 0 GPIO_ACTIVE_HIGH>;
|
||||
enable-active-high;
|
||||
};
|
||||
};
|
||||
|
||||
&lpuart4 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_lpuart4>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usdhc0 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_usdhc0>;
|
||||
cd-gpios = <&gpio_ptc 10 GPIO_ACTIVE_LOW>;
|
||||
vmmc-supply = <®_vsd_3v3>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&iomuxc1 {
|
||||
pinctrl_lpuart4: lpuart4grp {
|
||||
fsl,pins = <
|
||||
IMX7ULP_PAD_PTC3__LPUART4_RX 0x3
|
||||
IMX7ULP_PAD_PTC2__LPUART4_TX 0x3
|
||||
>;
|
||||
bias-pull-up;
|
||||
};
|
||||
|
||||
pinctrl_usdhc0: usdhc0grp {
|
||||
fsl,pins = <
|
||||
IMX7ULP_PAD_PTD1__SDHC0_CMD 0x43
|
||||
IMX7ULP_PAD_PTD2__SDHC0_CLK 0x40
|
||||
IMX7ULP_PAD_PTD7__SDHC0_D3 0x43
|
||||
IMX7ULP_PAD_PTD8__SDHC0_D2 0x43
|
||||
IMX7ULP_PAD_PTD9__SDHC0_D1 0x43
|
||||
IMX7ULP_PAD_PTD10__SDHC0_D0 0x43
|
||||
IMX7ULP_PAD_PTC10__PTC10 0x3 /* CD */
|
||||
>;
|
||||
};
|
||||
|
||||
pinctrl_usdhc0_rst: usdhc0-gpio-rst-grp {
|
||||
fsl,pins = <
|
||||
IMX7ULP_PAD_PTD0__PTD0 0x3
|
||||
>;
|
||||
};
|
||||
};
|
346
arch/arm/boot/dts/imx7ulp.dtsi
Normal file
346
arch/arm/boot/dts/imx7ulp.dtsi
Normal file
@ -0,0 +1,346 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2016 Freescale Semiconductor, Inc.
|
||||
* Copyright 2017-2018 NXP
|
||||
* Dong Aisheng <aisheng.dong@nxp.com>
|
||||
*/
|
||||
|
||||
#include <dt-bindings/clock/imx7ulp-clock.h>
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
#include "imx7ulp-pinfunc.h"
|
||||
|
||||
/ {
|
||||
interrupt-parent = <&intc>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
aliases {
|
||||
gpio0 = &gpio_ptc;
|
||||
gpio1 = &gpio_ptd;
|
||||
gpio2 = &gpio_pte;
|
||||
gpio3 = &gpio_ptf;
|
||||
i2c0 = &lpi2c6;
|
||||
i2c1 = &lpi2c7;
|
||||
mmc0 = &usdhc0;
|
||||
mmc1 = &usdhc1;
|
||||
serial0 = &lpuart4;
|
||||
serial1 = &lpuart5;
|
||||
serial2 = &lpuart6;
|
||||
serial3 = &lpuart7;
|
||||
};
|
||||
|
||||
cpus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
cpu0: cpu@0 {
|
||||
compatible = "arm,cortex-a7";
|
||||
device_type = "cpu";
|
||||
reg = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
intc: interrupt-controller@40021000 {
|
||||
compatible = "arm,cortex-a7-gic";
|
||||
#interrupt-cells = <3>;
|
||||
interrupt-controller;
|
||||
reg = <0x40021000 0x1000>,
|
||||
<0x40022000 0x1000>;
|
||||
};
|
||||
|
||||
rosc: clock-rosc {
|
||||
compatible = "fixed-clock";
|
||||
clock-frequency = <32768>;
|
||||
clock-output-names = "rosc";
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
|
||||
sosc: clock-sosc {
|
||||
compatible = "fixed-clock";
|
||||
clock-frequency = <24000000>;
|
||||
clock-output-names = "sosc";
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
|
||||
sirc: clock-sirc {
|
||||
compatible = "fixed-clock";
|
||||
clock-frequency = <16000000>;
|
||||
clock-output-names = "sirc";
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
|
||||
firc: clock-firc {
|
||||
compatible = "fixed-clock";
|
||||
clock-frequency = <48000000>;
|
||||
clock-output-names = "firc";
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
|
||||
upll: clock-upll {
|
||||
compatible = "fixed-clock";
|
||||
clock-frequency = <480000000>;
|
||||
clock-output-names = "upll";
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
|
||||
mpll: clock-mpll {
|
||||
compatible = "fixed-clock";
|
||||
clock-frequency = <480000000>;
|
||||
clock-output-names = "mpll";
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
|
||||
ahbbridge0: bus@40000000 {
|
||||
compatible = "simple-bus";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
reg = <0x40000000 0x800000>;
|
||||
ranges;
|
||||
|
||||
lpuart4: serial@402d0000 {
|
||||
compatible = "fsl,imx7ulp-lpuart";
|
||||
reg = <0x402d0000 0x1000>;
|
||||
interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&pcc2 IMX7ULP_CLK_LPUART4>;
|
||||
clock-names = "ipg";
|
||||
assigned-clocks = <&pcc2 IMX7ULP_CLK_LPUART4>;
|
||||
assigned-clock-parents = <&scg1 IMX7ULP_CLK_SOSC_BUS_CLK>;
|
||||
assigned-clock-rates = <24000000>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
lpuart5: serial@402e0000 {
|
||||
compatible = "fsl,imx7ulp-lpuart";
|
||||
reg = <0x402e0000 0x1000>;
|
||||
interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&pcc2 IMX7ULP_CLK_LPUART5>;
|
||||
clock-names = "ipg";
|
||||
assigned-clocks = <&pcc2 IMX7ULP_CLK_LPUART5>;
|
||||
assigned-clock-parents = <&scg1 IMX7ULP_CLK_FIRC>;
|
||||
assigned-clock-rates = <48000000>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
tpm5: tpm@40260000 {
|
||||
compatible = "fsl,imx7ulp-tpm";
|
||||
reg = <0x40260000 0x1000>;
|
||||
interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&scg1 IMX7ULP_CLK_NIC1_BUS_DIV>,
|
||||
<&pcc2 IMX7ULP_CLK_LPTPM5>;
|
||||
clock-names = "ipg", "per";
|
||||
};
|
||||
|
||||
usdhc0: mmc@40370000 {
|
||||
compatible = "fsl,imx7ulp-usdhc", "fsl,imx6sx-usdhc";
|
||||
reg = <0x40370000 0x10000>;
|
||||
interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&scg1 IMX7ULP_CLK_NIC1_BUS_DIV>,
|
||||
<&scg1 IMX7ULP_CLK_NIC1_DIV>,
|
||||
<&pcc2 IMX7ULP_CLK_USDHC0>;
|
||||
clock-names ="ipg", "ahb", "per";
|
||||
assigned-clocks = <&pcc2 IMX7ULP_CLK_USDHC0>;
|
||||
assigned-clock-parents = <&scg1 IMX7ULP_CLK_NIC1_DIV>;
|
||||
bus-width = <4>;
|
||||
fsl,tuning-start-tap = <20>;
|
||||
fsl,tuning-step= <2>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
usdhc1: mmc@40380000 {
|
||||
compatible = "fsl,imx7ulp-usdhc", "fsl,imx6sx-usdhc";
|
||||
reg = <0x40380000 0x10000>;
|
||||
interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&scg1 IMX7ULP_CLK_NIC1_BUS_DIV>,
|
||||
<&scg1 IMX7ULP_CLK_NIC1_DIV>,
|
||||
<&pcc2 IMX7ULP_CLK_USDHC1>;
|
||||
clock-names ="ipg", "ahb", "per";
|
||||
assigned-clocks = <&pcc2 IMX7ULP_CLK_USDHC1>;
|
||||
assigned-clock-parents = <&scg1 IMX7ULP_CLK_NIC1_DIV>;
|
||||
bus-width = <4>;
|
||||
fsl,tuning-start-tap = <20>;
|
||||
fsl,tuning-step= <2>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
scg1: clock-controller@403e0000 {
|
||||
compatible = "fsl,imx7ulp-scg1";
|
||||
reg = <0x403e0000 0x10000>;
|
||||
clocks = <&rosc>, <&sosc>, <&sirc>,
|
||||
<&firc>, <&upll>, <&mpll>;
|
||||
clock-names = "rosc", "sosc", "sirc",
|
||||
"firc", "upll", "mpll";
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
pcc2: clock-controller@403f0000 {
|
||||
compatible = "fsl,imx7ulp-pcc2";
|
||||
reg = <0x403f0000 0x10000>;
|
||||
#clock-cells = <1>;
|
||||
clocks = <&scg1 IMX7ULP_CLK_NIC1_BUS_DIV>,
|
||||
<&scg1 IMX7ULP_CLK_NIC1_DIV>,
|
||||
<&scg1 IMX7ULP_CLK_DDR_DIV>,
|
||||
<&scg1 IMX7ULP_CLK_APLL_PFD2>,
|
||||
<&scg1 IMX7ULP_CLK_APLL_PFD1>,
|
||||
<&scg1 IMX7ULP_CLK_APLL_PFD0>,
|
||||
<&scg1 IMX7ULP_CLK_UPLL>,
|
||||
<&scg1 IMX7ULP_CLK_SOSC_BUS_CLK>,
|
||||
<&scg1 IMX7ULP_CLK_MIPI_PLL>,
|
||||
<&scg1 IMX7ULP_CLK_FIRC_BUS_CLK>,
|
||||
<&scg1 IMX7ULP_CLK_ROSC>,
|
||||
<&scg1 IMX7ULP_CLK_SPLL_BUS_CLK>;
|
||||
clock-names = "nic1_bus_clk", "nic1_clk", "ddr_clk",
|
||||
"apll_pfd2", "apll_pfd1", "apll_pfd0",
|
||||
"upll", "sosc_bus_clk", "mpll",
|
||||
"firc_bus_clk", "rosc", "spll_bus_clk";
|
||||
assigned-clocks = <&pcc2 IMX7ULP_CLK_LPTPM5>;
|
||||
assigned-clock-parents = <&scg1 IMX7ULP_CLK_SOSC_BUS_CLK>;
|
||||
};
|
||||
|
||||
smc1: smc1@40410000 {
|
||||
compatible = "fsl,imx7ulp-smc1";
|
||||
reg = <0x40410000 0x1000>;
|
||||
};
|
||||
|
||||
pcc3: clock-controller@40b30000 {
|
||||
compatible = "fsl,imx7ulp-pcc3";
|
||||
reg = <0x40b30000 0x10000>;
|
||||
#clock-cells = <1>;
|
||||
clocks = <&scg1 IMX7ULP_CLK_NIC1_BUS_DIV>,
|
||||
<&scg1 IMX7ULP_CLK_NIC1_DIV>,
|
||||
<&scg1 IMX7ULP_CLK_DDR_DIV>,
|
||||
<&scg1 IMX7ULP_CLK_APLL_PFD2>,
|
||||
<&scg1 IMX7ULP_CLK_APLL_PFD1>,
|
||||
<&scg1 IMX7ULP_CLK_APLL_PFD0>,
|
||||
<&scg1 IMX7ULP_CLK_UPLL>,
|
||||
<&scg1 IMX7ULP_CLK_SOSC_BUS_CLK>,
|
||||
<&scg1 IMX7ULP_CLK_MIPI_PLL>,
|
||||
<&scg1 IMX7ULP_CLK_FIRC_BUS_CLK>,
|
||||
<&scg1 IMX7ULP_CLK_ROSC>,
|
||||
<&scg1 IMX7ULP_CLK_SPLL_BUS_CLK>;
|
||||
clock-names = "nic1_bus_clk", "nic1_clk", "ddr_clk",
|
||||
"apll_pfd2", "apll_pfd1", "apll_pfd0",
|
||||
"upll", "sosc_bus_clk", "mpll",
|
||||
"firc_bus_clk", "rosc", "spll_bus_clk";
|
||||
};
|
||||
};
|
||||
|
||||
ahbbridge1: bus@40800000 {
|
||||
compatible = "simple-bus";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
reg = <0x40800000 0x800000>;
|
||||
ranges;
|
||||
|
||||
lpi2c6: i2c@40a40000 {
|
||||
compatible = "fsl,imx7ulp-lpi2c";
|
||||
reg = <0x40a40000 0x10000>;
|
||||
interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&pcc3 IMX7ULP_CLK_LPI2C6>;
|
||||
clock-names = "ipg";
|
||||
assigned-clocks = <&pcc3 IMX7ULP_CLK_LPI2C6>;
|
||||
assigned-clock-parents = <&scg1 IMX7ULP_CLK_FIRC>;
|
||||
assigned-clock-rates = <48000000>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
lpi2c7: i2c@40a50000 {
|
||||
compatible = "fsl,imx7ulp-lpi2c";
|
||||
reg = <0x40a50000 0x10000>;
|
||||
interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&pcc3 IMX7ULP_CLK_LPI2C7>;
|
||||
clock-names = "ipg";
|
||||
assigned-clocks = <&pcc3 IMX7ULP_CLK_LPI2C7>;
|
||||
assigned-clock-parents = <&scg1 IMX7ULP_CLK_FIRC>;
|
||||
assigned-clock-rates = <48000000>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
lpuart6: serial@40a60000 {
|
||||
compatible = "fsl,imx7ulp-lpuart";
|
||||
reg = <0x40a60000 0x1000>;
|
||||
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&pcc3 IMX7ULP_CLK_LPUART6>;
|
||||
clock-names = "ipg";
|
||||
assigned-clocks = <&pcc3 IMX7ULP_CLK_LPUART6>;
|
||||
assigned-clock-parents = <&scg1 IMX7ULP_CLK_FIRC>;
|
||||
assigned-clock-rates = <48000000>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
lpuart7: serial@40a70000 {
|
||||
compatible = "fsl,imx7ulp-lpuart";
|
||||
reg = <0x40a70000 0x1000>;
|
||||
interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&pcc3 IMX7ULP_CLK_LPUART7>;
|
||||
clock-names = "ipg";
|
||||
assigned-clocks = <&pcc3 IMX7ULP_CLK_LPUART7>;
|
||||
assigned-clock-parents = <&scg1 IMX7ULP_CLK_FIRC>;
|
||||
assigned-clock-rates = <48000000>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
iomuxc1: pinctrl@40ac0000 {
|
||||
compatible = "fsl,imx7ulp-iomuxc1";
|
||||
reg = <0x40ac0000 0x1000>;
|
||||
};
|
||||
|
||||
gpio_ptc: gpio@40ae0000 {
|
||||
compatible = "fsl,imx7ulp-gpio", "fsl,vf610-gpio";
|
||||
reg = <0x40ae0000 0x1000 0x400f0000 0x40>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
clocks = <&pcc2 IMX7ULP_CLK_RGPIO2P1>,
|
||||
<&pcc3 IMX7ULP_CLK_PCTLC>;
|
||||
clock-names = "gpio", "port";
|
||||
gpio-ranges = <&iomuxc1 0 0 32>;
|
||||
};
|
||||
|
||||
gpio_ptd: gpio@40af0000 {
|
||||
compatible = "fsl,imx7ulp-gpio", "fsl,vf610-gpio";
|
||||
reg = <0x40af0000 0x1000 0x400f0040 0x40>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
clocks = <&pcc2 IMX7ULP_CLK_RGPIO2P1>,
|
||||
<&pcc3 IMX7ULP_CLK_PCTLD>;
|
||||
clock-names = "gpio", "port";
|
||||
gpio-ranges = <&iomuxc1 0 32 32>;
|
||||
};
|
||||
|
||||
gpio_pte: gpio@40b00000 {
|
||||
compatible = "fsl,imx7ulp-gpio", "fsl,vf610-gpio";
|
||||
reg = <0x40b00000 0x1000 0x400f0080 0x40>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
clocks = <&pcc2 IMX7ULP_CLK_RGPIO2P1>,
|
||||
<&pcc3 IMX7ULP_CLK_PCTLE>;
|
||||
clock-names = "gpio", "port";
|
||||
gpio-ranges = <&iomuxc1 0 64 32>;
|
||||
};
|
||||
|
||||
gpio_ptf: gpio@40b10000 {
|
||||
compatible = "fsl,imx7ulp-gpio", "fsl,vf610-gpio";
|
||||
reg = <0x40b10000 0x1000 0x400f00c0 0x40>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
clocks = <&pcc2 IMX7ULP_CLK_RGPIO2P1>,
|
||||
<&pcc3 IMX7ULP_CLK_PCTLF>;
|
||||
clock-names = "gpio", "port";
|
||||
gpio-ranges = <&iomuxc1 0 96 32>;
|
||||
};
|
||||
};
|
||||
};
|
@ -40,6 +40,11 @@ static unsigned long clk_fd_recalc_rate(struct clk_hw *hw,
|
||||
m = (val & fd->mmask) >> fd->mshift;
|
||||
n = (val & fd->nmask) >> fd->nshift;
|
||||
|
||||
if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) {
|
||||
m++;
|
||||
n++;
|
||||
}
|
||||
|
||||
if (!n || !m)
|
||||
return parent_rate;
|
||||
|
||||
@ -103,6 +108,11 @@ static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0),
|
||||
&m, &n);
|
||||
|
||||
if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) {
|
||||
m--;
|
||||
n--;
|
||||
}
|
||||
|
||||
if (fd->lock)
|
||||
spin_lock_irqsave(fd->lock, flags);
|
||||
else
|
||||
|
@ -4,6 +4,8 @@ obj-y += \
|
||||
clk.o \
|
||||
clk-busy.o \
|
||||
clk-cpu.o \
|
||||
clk-composite-7ulp.o \
|
||||
clk-divider-gate.o \
|
||||
clk-fixup-div.o \
|
||||
clk-fixup-mux.o \
|
||||
clk-gate-exclusive.o \
|
||||
@ -11,7 +13,9 @@ obj-y += \
|
||||
clk-pllv1.o \
|
||||
clk-pllv2.o \
|
||||
clk-pllv3.o \
|
||||
clk-pfd.o
|
||||
clk-pllv4.o \
|
||||
clk-pfd.o \
|
||||
clk-pfdv2.o
|
||||
|
||||
obj-$(CONFIG_SOC_IMX1) += clk-imx1.o
|
||||
obj-$(CONFIG_SOC_IMX21) += clk-imx21.o
|
||||
@ -26,4 +30,5 @@ obj-$(CONFIG_SOC_IMX6SLL) += clk-imx6sll.o
|
||||
obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o
|
||||
obj-$(CONFIG_SOC_IMX6UL) += clk-imx6ul.o
|
||||
obj-$(CONFIG_SOC_IMX7D) += clk-imx7d.o
|
||||
obj-$(CONFIG_SOC_IMX7ULP) += clk-imx7ulp.o
|
||||
obj-$(CONFIG_SOC_VF610) += clk-vf610.o
|
||||
|
@ -154,7 +154,7 @@ static const struct clk_ops clk_busy_mux_ops = {
|
||||
|
||||
struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift,
|
||||
u8 width, void __iomem *busy_reg, u8 busy_shift,
|
||||
const char **parent_names, int num_parents)
|
||||
const char * const *parent_names, int num_parents)
|
||||
{
|
||||
struct clk_busy_mux *busy;
|
||||
struct clk *clk;
|
||||
|
87
drivers/clk/imx/clk-composite-7ulp.c
Normal file
87
drivers/clk/imx/clk-composite-7ulp.c
Normal file
@ -0,0 +1,87 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2016 Freescale Semiconductor, Inc.
|
||||
* Copyright 2017~2018 NXP
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
#define PCG_PCS_SHIFT 24
|
||||
#define PCG_PCS_MASK 0x7
|
||||
#define PCG_CGC_SHIFT 30
|
||||
#define PCG_FRAC_SHIFT 3
|
||||
#define PCG_FRAC_WIDTH 1
|
||||
#define PCG_FRAC_MASK BIT(3)
|
||||
#define PCG_PCD_SHIFT 0
|
||||
#define PCG_PCD_WIDTH 3
|
||||
#define PCG_PCD_MASK 0x7
|
||||
|
||||
struct clk_hw *imx7ulp_clk_composite(const char *name,
|
||||
const char * const *parent_names,
|
||||
int num_parents, bool mux_present,
|
||||
bool rate_present, bool gate_present,
|
||||
void __iomem *reg)
|
||||
{
|
||||
struct clk_hw *mux_hw = NULL, *fd_hw = NULL, *gate_hw = NULL;
|
||||
struct clk_fractional_divider *fd = NULL;
|
||||
struct clk_gate *gate = NULL;
|
||||
struct clk_mux *mux = NULL;
|
||||
struct clk_hw *hw;
|
||||
|
||||
if (mux_present) {
|
||||
mux = kzalloc(sizeof(*mux), GFP_KERNEL);
|
||||
if (!mux)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
mux_hw = &mux->hw;
|
||||
mux->reg = reg;
|
||||
mux->shift = PCG_PCS_SHIFT;
|
||||
mux->mask = PCG_PCS_MASK;
|
||||
}
|
||||
|
||||
if (rate_present) {
|
||||
fd = kzalloc(sizeof(*fd), GFP_KERNEL);
|
||||
if (!fd) {
|
||||
kfree(mux);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
fd_hw = &fd->hw;
|
||||
fd->reg = reg;
|
||||
fd->mshift = PCG_FRAC_SHIFT;
|
||||
fd->mwidth = PCG_FRAC_WIDTH;
|
||||
fd->mmask = PCG_FRAC_MASK;
|
||||
fd->nshift = PCG_PCD_SHIFT;
|
||||
fd->nwidth = PCG_PCD_WIDTH;
|
||||
fd->nmask = PCG_PCD_MASK;
|
||||
fd->flags = CLK_FRAC_DIVIDER_ZERO_BASED;
|
||||
}
|
||||
|
||||
if (gate_present) {
|
||||
gate = kzalloc(sizeof(*gate), GFP_KERNEL);
|
||||
if (!gate) {
|
||||
kfree(mux);
|
||||
kfree(fd);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
gate_hw = &gate->hw;
|
||||
gate->reg = reg;
|
||||
gate->bit_idx = PCG_CGC_SHIFT;
|
||||
}
|
||||
|
||||
hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
|
||||
mux_hw, &clk_mux_ops, fd_hw,
|
||||
&clk_fractional_divider_ops, gate_hw,
|
||||
&clk_gate_ops, CLK_SET_RATE_GATE |
|
||||
CLK_SET_PARENT_GATE);
|
||||
if (IS_ERR(hw)) {
|
||||
kfree(mux);
|
||||
kfree(fd);
|
||||
kfree(gate);
|
||||
}
|
||||
|
||||
return hw;
|
||||
}
|
221
drivers/clk/imx/clk-divider-gate.c
Normal file
221
drivers/clk/imx/clk-divider-gate.c
Normal file
@ -0,0 +1,221 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2018 NXP.
|
||||
* Dong Aisheng <aisheng.dong@nxp.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
struct clk_divider_gate {
|
||||
struct clk_divider divider;
|
||||
u32 cached_val;
|
||||
};
|
||||
|
||||
static inline struct clk_divider_gate *to_clk_divider_gate(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_divider *div = to_clk_divider(hw);
|
||||
|
||||
return container_of(div, struct clk_divider_gate, divider);
|
||||
}
|
||||
|
||||
static unsigned long clk_divider_gate_recalc_rate_ro(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_divider *div = to_clk_divider(hw);
|
||||
unsigned int val;
|
||||
|
||||
val = clk_readl(div->reg) >> div->shift;
|
||||
val &= clk_div_mask(div->width);
|
||||
if (!val)
|
||||
return 0;
|
||||
|
||||
return divider_recalc_rate(hw, parent_rate, val, div->table,
|
||||
div->flags, div->width);
|
||||
}
|
||||
|
||||
static unsigned long clk_divider_gate_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_divider_gate *div_gate = to_clk_divider_gate(hw);
|
||||
struct clk_divider *div = to_clk_divider(hw);
|
||||
unsigned long flags = 0;
|
||||
unsigned int val;
|
||||
|
||||
spin_lock_irqsave(div->lock, flags);
|
||||
|
||||
if (!clk_hw_is_enabled(hw)) {
|
||||
val = div_gate->cached_val;
|
||||
} else {
|
||||
val = clk_readl(div->reg) >> div->shift;
|
||||
val &= clk_div_mask(div->width);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(div->lock, flags);
|
||||
|
||||
if (!val)
|
||||
return 0;
|
||||
|
||||
return divider_recalc_rate(hw, parent_rate, val, div->table,
|
||||
div->flags, div->width);
|
||||
}
|
||||
|
||||
static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
return clk_divider_ops.round_rate(hw, rate, prate);
|
||||
}
|
||||
|
||||
static int clk_divider_gate_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_divider_gate *div_gate = to_clk_divider_gate(hw);
|
||||
struct clk_divider *div = to_clk_divider(hw);
|
||||
unsigned long flags = 0;
|
||||
int value;
|
||||
u32 val;
|
||||
|
||||
value = divider_get_val(rate, parent_rate, div->table,
|
||||
div->width, div->flags);
|
||||
if (value < 0)
|
||||
return value;
|
||||
|
||||
spin_lock_irqsave(div->lock, flags);
|
||||
|
||||
if (clk_hw_is_enabled(hw)) {
|
||||
val = clk_readl(div->reg);
|
||||
val &= ~(clk_div_mask(div->width) << div->shift);
|
||||
val |= (u32)value << div->shift;
|
||||
clk_writel(val, div->reg);
|
||||
} else {
|
||||
div_gate->cached_val = value;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(div->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_divider_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_divider_gate *div_gate = to_clk_divider_gate(hw);
|
||||
struct clk_divider *div = to_clk_divider(hw);
|
||||
unsigned long flags = 0;
|
||||
u32 val;
|
||||
|
||||
if (!div_gate->cached_val) {
|
||||
pr_err("%s: no valid preset rate\n", clk_hw_get_name(hw));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(div->lock, flags);
|
||||
/* restore div val */
|
||||
val = clk_readl(div->reg);
|
||||
val |= div_gate->cached_val << div->shift;
|
||||
clk_writel(val, div->reg);
|
||||
|
||||
spin_unlock_irqrestore(div->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clk_divider_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_divider_gate *div_gate = to_clk_divider_gate(hw);
|
||||
struct clk_divider *div = to_clk_divider(hw);
|
||||
unsigned long flags = 0;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(div->lock, flags);
|
||||
|
||||
/* store the current div val */
|
||||
val = clk_readl(div->reg) >> div->shift;
|
||||
val &= clk_div_mask(div->width);
|
||||
div_gate->cached_val = val;
|
||||
clk_writel(0, div->reg);
|
||||
|
||||
spin_unlock_irqrestore(div->lock, flags);
|
||||
}
|
||||
|
||||
static int clk_divider_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_divider *div = to_clk_divider(hw);
|
||||
u32 val;
|
||||
|
||||
val = clk_readl(div->reg) >> div->shift;
|
||||
val &= clk_div_mask(div->width);
|
||||
|
||||
return val ? 1 : 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops clk_divider_gate_ro_ops = {
|
||||
.recalc_rate = clk_divider_gate_recalc_rate_ro,
|
||||
.round_rate = clk_divider_round_rate,
|
||||
};
|
||||
|
||||
static const struct clk_ops clk_divider_gate_ops = {
|
||||
.recalc_rate = clk_divider_gate_recalc_rate,
|
||||
.round_rate = clk_divider_round_rate,
|
||||
.set_rate = clk_divider_gate_set_rate,
|
||||
.enable = clk_divider_enable,
|
||||
.disable = clk_divider_disable,
|
||||
.is_enabled = clk_divider_is_enabled,
|
||||
};
|
||||
|
||||
/*
|
||||
* NOTE: In order to resue the most code from the common divider,
|
||||
* we also design our divider following the way that provids an extra
|
||||
* clk_divider_flags, however it's fixed to CLK_DIVIDER_ONE_BASED by
|
||||
* default as our HW is. Besides that it supports only CLK_DIVIDER_READ_ONLY
|
||||
* flag which can be specified by user flexibly.
|
||||
*/
|
||||
struct clk_hw *imx_clk_divider_gate(const char *name, const char *parent_name,
|
||||
unsigned long flags, void __iomem *reg,
|
||||
u8 shift, u8 width, u8 clk_divider_flags,
|
||||
const struct clk_div_table *table,
|
||||
spinlock_t *lock)
|
||||
{
|
||||
struct clk_init_data init;
|
||||
struct clk_divider_gate *div_gate;
|
||||
struct clk_hw *hw;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
div_gate = kzalloc(sizeof(*div_gate), GFP_KERNEL);
|
||||
if (!div_gate)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init.name = name;
|
||||
if (clk_divider_flags & CLK_DIVIDER_READ_ONLY)
|
||||
init.ops = &clk_divider_gate_ro_ops;
|
||||
else
|
||||
init.ops = &clk_divider_gate_ops;
|
||||
init.flags = flags;
|
||||
init.parent_names = parent_name ? &parent_name : NULL;
|
||||
init.num_parents = parent_name ? 1 : 0;
|
||||
|
||||
div_gate->divider.reg = reg;
|
||||
div_gate->divider.shift = shift;
|
||||
div_gate->divider.width = width;
|
||||
div_gate->divider.lock = lock;
|
||||
div_gate->divider.table = table;
|
||||
div_gate->divider.hw.init = &init;
|
||||
div_gate->divider.flags = CLK_DIVIDER_ONE_BASED | clk_divider_flags;
|
||||
/* cache gate status */
|
||||
val = clk_readl(reg) >> shift;
|
||||
val &= clk_div_mask(width);
|
||||
div_gate->cached_val = val;
|
||||
|
||||
hw = &div_gate->divider.hw;
|
||||
ret = clk_hw_register(NULL, hw);
|
||||
if (ret) {
|
||||
kfree(div_gate);
|
||||
hw = ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return hw;
|
||||
}
|
@ -70,7 +70,7 @@ static const struct clk_ops clk_fixup_mux_ops = {
|
||||
};
|
||||
|
||||
struct clk *imx_clk_fixup_mux(const char *name, void __iomem *reg,
|
||||
u8 shift, u8 width, const char **parents,
|
||||
u8 shift, u8 width, const char * const *parents,
|
||||
int num_parents, void (*fixup)(u32 *val))
|
||||
{
|
||||
struct clk_fixup_mux *fixup_mux;
|
||||
|
220
drivers/clk/imx/clk-imx7ulp.c
Normal file
220
drivers/clk/imx/clk-imx7ulp.c
Normal file
@ -0,0 +1,220 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2016 Freescale Semiconductor, Inc.
|
||||
* Copyright 2017~2018 NXP
|
||||
*
|
||||
* Author: Dong Aisheng <aisheng.dong@nxp.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <dt-bindings/clock/imx7ulp-clock.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
static const char * const pll_pre_sels[] = { "sosc", "firc", };
|
||||
static const char * const spll_pfd_sels[] = { "spll_pfd0", "spll_pfd1", "spll_pfd2", "spll_pfd3", };
|
||||
static const char * const spll_sels[] = { "spll", "spll_pfd_sel", };
|
||||
static const char * const apll_pfd_sels[] = { "apll_pfd0", "apll_pfd1", "apll_pfd2", "apll_pfd3", };
|
||||
static const char * const apll_sels[] = { "apll", "apll_pfd_sel", };
|
||||
static const char * const scs_sels[] = { "dummy", "sosc", "sirc", "firc", "dummy", "apll_sel", "spll_sel", "upll", };
|
||||
static const char * const ddr_sels[] = { "apll_pfd_sel", "upll", };
|
||||
static const char * const nic_sels[] = { "firc", "ddr_clk", };
|
||||
static const char * const periph_plat_sels[] = { "dummy", "nic1_bus_clk", "nic1_clk", "ddr_clk", "apll_pfd2", "apll_pfd1", "apll_pfd0", "upll", };
|
||||
static const char * const periph_bus_sels[] = { "dummy", "sosc_bus_clk", "mpll", "firc_bus_clk", "rosc", "nic1_bus_clk", "nic1_clk", "spll_bus_clk", };
|
||||
|
||||
/* used by sosc/sirc/firc/ddr/spll/apll dividers */
|
||||
static const struct clk_div_table ulp_div_table[] = {
|
||||
{ .val = 1, .div = 1, },
|
||||
{ .val = 2, .div = 2, },
|
||||
{ .val = 3, .div = 4, },
|
||||
{ .val = 4, .div = 8, },
|
||||
{ .val = 5, .div = 16, },
|
||||
{ .val = 6, .div = 32, },
|
||||
{ .val = 7, .div = 64, },
|
||||
};
|
||||
|
||||
static void __init imx7ulp_clk_scg1_init(struct device_node *np)
|
||||
{
|
||||
struct clk_hw_onecell_data *clk_data;
|
||||
struct clk_hw **clks;
|
||||
void __iomem *base;
|
||||
|
||||
clk_data = kzalloc(sizeof(*clk_data) + sizeof(*clk_data->hws) *
|
||||
IMX7ULP_CLK_SCG1_END, GFP_KERNEL);
|
||||
if (!clk_data)
|
||||
return;
|
||||
|
||||
clk_data->num = IMX7ULP_CLK_SCG1_END;
|
||||
clks = clk_data->hws;
|
||||
|
||||
clks[IMX7ULP_CLK_DUMMY] = imx_clk_hw_fixed("dummy", 0);
|
||||
|
||||
clks[IMX7ULP_CLK_ROSC] = imx_obtain_fixed_clk_hw(np, "rosc");
|
||||
clks[IMX7ULP_CLK_SOSC] = imx_obtain_fixed_clk_hw(np, "sosc");
|
||||
clks[IMX7ULP_CLK_SIRC] = imx_obtain_fixed_clk_hw(np, "sirc");
|
||||
clks[IMX7ULP_CLK_FIRC] = imx_obtain_fixed_clk_hw(np, "firc");
|
||||
clks[IMX7ULP_CLK_MIPI_PLL] = imx_obtain_fixed_clk_hw(np, "mpll");
|
||||
clks[IMX7ULP_CLK_UPLL] = imx_obtain_fixed_clk_hw(np, "upll");
|
||||
|
||||
/* SCG1 */
|
||||
base = of_iomap(np, 0);
|
||||
WARN_ON(!base);
|
||||
|
||||
/* NOTE: xPLL config can't be changed when xPLL is enabled */
|
||||
clks[IMX7ULP_CLK_APLL_PRE_SEL] = imx_clk_hw_mux_flags("apll_pre_sel", base + 0x508, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels), CLK_SET_PARENT_GATE);
|
||||
clks[IMX7ULP_CLK_SPLL_PRE_SEL] = imx_clk_hw_mux_flags("spll_pre_sel", base + 0x608, 0, 1, pll_pre_sels, ARRAY_SIZE(pll_pre_sels), CLK_SET_PARENT_GATE);
|
||||
|
||||
/* name parent_name reg shift width flags */
|
||||
clks[IMX7ULP_CLK_APLL_PRE_DIV] = imx_clk_hw_divider_flags("apll_pre_div", "apll_pre_sel", base + 0x508, 8, 3, CLK_SET_RATE_GATE);
|
||||
clks[IMX7ULP_CLK_SPLL_PRE_DIV] = imx_clk_hw_divider_flags("spll_pre_div", "spll_pre_sel", base + 0x608, 8, 3, CLK_SET_RATE_GATE);
|
||||
|
||||
/* name parent_name base */
|
||||
clks[IMX7ULP_CLK_APLL] = imx_clk_pllv4("apll", "apll_pre_div", base + 0x500);
|
||||
clks[IMX7ULP_CLK_SPLL] = imx_clk_pllv4("spll", "spll_pre_div", base + 0x600);
|
||||
|
||||
/* APLL PFDs */
|
||||
clks[IMX7ULP_CLK_APLL_PFD0] = imx_clk_pfdv2("apll_pfd0", "apll", base + 0x50c, 0);
|
||||
clks[IMX7ULP_CLK_APLL_PFD1] = imx_clk_pfdv2("apll_pfd1", "apll", base + 0x50c, 1);
|
||||
clks[IMX7ULP_CLK_APLL_PFD2] = imx_clk_pfdv2("apll_pfd2", "apll", base + 0x50c, 2);
|
||||
clks[IMX7ULP_CLK_APLL_PFD3] = imx_clk_pfdv2("apll_pfd3", "apll", base + 0x50c, 3);
|
||||
|
||||
/* SPLL PFDs */
|
||||
clks[IMX7ULP_CLK_SPLL_PFD0] = imx_clk_pfdv2("spll_pfd0", "spll", base + 0x60C, 0);
|
||||
clks[IMX7ULP_CLK_SPLL_PFD1] = imx_clk_pfdv2("spll_pfd1", "spll", base + 0x60C, 1);
|
||||
clks[IMX7ULP_CLK_SPLL_PFD2] = imx_clk_pfdv2("spll_pfd2", "spll", base + 0x60C, 2);
|
||||
clks[IMX7ULP_CLK_SPLL_PFD3] = imx_clk_pfdv2("spll_pfd3", "spll", base + 0x60C, 3);
|
||||
|
||||
/* PLL Mux */
|
||||
clks[IMX7ULP_CLK_APLL_PFD_SEL] = imx_clk_hw_mux_flags("apll_pfd_sel", base + 0x508, 14, 2, apll_pfd_sels, ARRAY_SIZE(apll_pfd_sels), CLK_SET_RATE_PARENT | CLK_SET_PARENT_GATE);
|
||||
clks[IMX7ULP_CLK_SPLL_PFD_SEL] = imx_clk_hw_mux_flags("spll_pfd_sel", base + 0x608, 14, 2, spll_pfd_sels, ARRAY_SIZE(spll_pfd_sels), CLK_SET_RATE_PARENT | CLK_SET_PARENT_GATE);
|
||||
clks[IMX7ULP_CLK_APLL_SEL] = imx_clk_hw_mux_flags("apll_sel", base + 0x508, 1, 1, apll_sels, ARRAY_SIZE(apll_sels), CLK_SET_RATE_PARENT | CLK_SET_PARENT_GATE);
|
||||
clks[IMX7ULP_CLK_SPLL_SEL] = imx_clk_hw_mux_flags("spll_sel", base + 0x608, 1, 1, spll_sels, ARRAY_SIZE(spll_sels), CLK_SET_RATE_PARENT | CLK_SET_PARENT_GATE);
|
||||
|
||||
clks[IMX7ULP_CLK_SPLL_BUS_CLK] = imx_clk_divider_gate("spll_bus_clk", "spll_sel", CLK_SET_RATE_GATE, base + 0x604, 8, 3, 0, ulp_div_table, &imx_ccm_lock);
|
||||
|
||||
/* scs/ddr/nic select different clock source requires that clock to be enabled first */
|
||||
clks[IMX7ULP_CLK_SYS_SEL] = imx_clk_hw_mux2("scs_sel", base + 0x14, 24, 4, scs_sels, ARRAY_SIZE(scs_sels));
|
||||
clks[IMX7ULP_CLK_NIC_SEL] = imx_clk_hw_mux2("nic_sel", base + 0x40, 28, 1, nic_sels, ARRAY_SIZE(nic_sels));
|
||||
clks[IMX7ULP_CLK_DDR_SEL] = imx_clk_hw_mux_flags("ddr_sel", base + 0x30, 24, 1, ddr_sels, ARRAY_SIZE(ddr_sels), CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE);
|
||||
|
||||
clks[IMX7ULP_CLK_CORE_DIV] = imx_clk_hw_divider_flags("divcore", "scs_sel", base + 0x14, 16, 4, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
|
||||
|
||||
clks[IMX7ULP_CLK_DDR_DIV] = imx_clk_divider_gate("ddr_clk", "ddr_sel", CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, base + 0x30, 0, 3,
|
||||
0, ulp_div_table, &imx_ccm_lock);
|
||||
|
||||
clks[IMX7ULP_CLK_NIC0_DIV] = imx_clk_hw_divider_flags("nic0_clk", "nic_sel", base + 0x40, 24, 4, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
|
||||
clks[IMX7ULP_CLK_NIC1_DIV] = imx_clk_hw_divider_flags("nic1_clk", "nic0_clk", base + 0x40, 16, 4, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
|
||||
clks[IMX7ULP_CLK_NIC1_BUS_DIV] = imx_clk_hw_divider_flags("nic1_bus_clk", "nic1_clk", base + 0x40, 4, 4, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
|
||||
|
||||
clks[IMX7ULP_CLK_GPU_DIV] = imx_clk_hw_divider("gpu_clk", "nic0_clk", base + 0x40, 20, 4);
|
||||
|
||||
clks[IMX7ULP_CLK_SOSC_BUS_CLK] = imx_clk_divider_gate("sosc_bus_clk", "sosc", 0, base + 0x104, 8, 3,
|
||||
CLK_DIVIDER_READ_ONLY, ulp_div_table, &imx_ccm_lock);
|
||||
clks[IMX7ULP_CLK_FIRC_BUS_CLK] = imx_clk_divider_gate("firc_bus_clk", "firc", 0, base + 0x304, 8, 3,
|
||||
CLK_DIVIDER_READ_ONLY, ulp_div_table, &imx_ccm_lock);
|
||||
|
||||
imx_check_clk_hws(clks, clk_data->num);
|
||||
|
||||
of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
|
||||
}
|
||||
CLK_OF_DECLARE(imx7ulp_clk_scg1, "fsl,imx7ulp-scg1", imx7ulp_clk_scg1_init);
|
||||
|
||||
static void __init imx7ulp_clk_pcc2_init(struct device_node *np)
|
||||
{
|
||||
struct clk_hw_onecell_data *clk_data;
|
||||
struct clk_hw **clks;
|
||||
void __iomem *base;
|
||||
|
||||
clk_data = kzalloc(sizeof(*clk_data) + sizeof(*clk_data->hws) *
|
||||
IMX7ULP_CLK_PCC2_END, GFP_KERNEL);
|
||||
if (!clk_data)
|
||||
return;
|
||||
|
||||
clk_data->num = IMX7ULP_CLK_PCC2_END;
|
||||
clks = clk_data->hws;
|
||||
|
||||
/* PCC2 */
|
||||
base = of_iomap(np, 0);
|
||||
WARN_ON(!base);
|
||||
|
||||
clks[IMX7ULP_CLK_DMA1] = imx_clk_hw_gate("dma1", "nic1_clk", base + 0x20, 30);
|
||||
clks[IMX7ULP_CLK_RGPIO2P1] = imx_clk_hw_gate("rgpio2p1", "nic1_bus_clk", base + 0x3c, 30);
|
||||
clks[IMX7ULP_CLK_DMA_MUX1] = imx_clk_hw_gate("dma_mux1", "nic1_bus_clk", base + 0x84, 30);
|
||||
clks[IMX7ULP_CLK_SNVS] = imx_clk_hw_gate("snvs", "nic1_bus_clk", base + 0x8c, 30);
|
||||
clks[IMX7ULP_CLK_CAAM] = imx_clk_hw_gate("caam", "nic1_clk", base + 0x90, 30);
|
||||
clks[IMX7ULP_CLK_LPTPM4] = imx7ulp_clk_composite("lptpm4", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x94);
|
||||
clks[IMX7ULP_CLK_LPTPM5] = imx7ulp_clk_composite("lptpm5", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x98);
|
||||
clks[IMX7ULP_CLK_LPIT1] = imx7ulp_clk_composite("lpit1", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x9c);
|
||||
clks[IMX7ULP_CLK_LPSPI2] = imx7ulp_clk_composite("lpspi2", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xa4);
|
||||
clks[IMX7ULP_CLK_LPSPI3] = imx7ulp_clk_composite("lpspi3", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xa8);
|
||||
clks[IMX7ULP_CLK_LPI2C4] = imx7ulp_clk_composite("lpi2c4", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xac);
|
||||
clks[IMX7ULP_CLK_LPI2C5] = imx7ulp_clk_composite("lpi2c5", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xb0);
|
||||
clks[IMX7ULP_CLK_LPUART4] = imx7ulp_clk_composite("lpuart4", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xb4);
|
||||
clks[IMX7ULP_CLK_LPUART5] = imx7ulp_clk_composite("lpuart5", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xb8);
|
||||
clks[IMX7ULP_CLK_FLEXIO1] = imx7ulp_clk_composite("flexio1", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0xc4);
|
||||
clks[IMX7ULP_CLK_USB0] = imx7ulp_clk_composite("usb0", periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, true, true, base + 0xcc);
|
||||
clks[IMX7ULP_CLK_USB1] = imx7ulp_clk_composite("usb1", periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, true, true, base + 0xd0);
|
||||
clks[IMX7ULP_CLK_USB_PHY] = imx_clk_hw_gate("usb_phy", "nic1_bus_clk", base + 0xd4, 30);
|
||||
clks[IMX7ULP_CLK_USDHC0] = imx7ulp_clk_composite("usdhc0", periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, true, true, base + 0xdc);
|
||||
clks[IMX7ULP_CLK_USDHC1] = imx7ulp_clk_composite("usdhc1", periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, true, true, base + 0xe0);
|
||||
clks[IMX7ULP_CLK_WDG1] = imx7ulp_clk_composite("wdg1", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, true, true, base + 0xf4);
|
||||
clks[IMX7ULP_CLK_WDG2] = imx7ulp_clk_composite("sdg2", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, true, true, base + 0x10c);
|
||||
|
||||
imx_check_clk_hws(clks, clk_data->num);
|
||||
|
||||
of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
|
||||
}
|
||||
CLK_OF_DECLARE(imx7ulp_clk_pcc2, "fsl,imx7ulp-pcc2", imx7ulp_clk_pcc2_init);
|
||||
|
||||
static void __init imx7ulp_clk_pcc3_init(struct device_node *np)
|
||||
{
|
||||
struct clk_hw_onecell_data *clk_data;
|
||||
struct clk_hw **clks;
|
||||
void __iomem *base;
|
||||
|
||||
clk_data = kzalloc(sizeof(*clk_data) + sizeof(*clk_data->hws) *
|
||||
IMX7ULP_CLK_PCC3_END, GFP_KERNEL);
|
||||
if (!clk_data)
|
||||
return;
|
||||
|
||||
clk_data->num = IMX7ULP_CLK_PCC3_END;
|
||||
clks = clk_data->hws;
|
||||
|
||||
/* PCC3 */
|
||||
base = of_iomap(np, 0);
|
||||
WARN_ON(!base);
|
||||
|
||||
clks[IMX7ULP_CLK_LPTPM6] = imx7ulp_clk_composite("lptpm6", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x84);
|
||||
clks[IMX7ULP_CLK_LPTPM7] = imx7ulp_clk_composite("lptpm7", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x88);
|
||||
|
||||
clks[IMX7ULP_CLK_MMDC] = clk_hw_register_gate(NULL, "mmdc", "nic1_clk", CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
|
||||
base + 0xac, 30, 0, &imx_ccm_lock);
|
||||
clks[IMX7ULP_CLK_LPI2C6] = imx7ulp_clk_composite("lpi2c6", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x90);
|
||||
clks[IMX7ULP_CLK_LPI2C7] = imx7ulp_clk_composite("lpi2c7", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x94);
|
||||
clks[IMX7ULP_CLK_LPUART6] = imx7ulp_clk_composite("lpuart6", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x98);
|
||||
clks[IMX7ULP_CLK_LPUART7] = imx7ulp_clk_composite("lpuart7", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, false, true, base + 0x9c);
|
||||
clks[IMX7ULP_CLK_DSI] = imx7ulp_clk_composite("dsi", periph_bus_sels, ARRAY_SIZE(periph_bus_sels), true, true, true, base + 0xa4);
|
||||
clks[IMX7ULP_CLK_LCDIF] = imx7ulp_clk_composite("lcdif", periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, true, true, base + 0xa8);
|
||||
|
||||
clks[IMX7ULP_CLK_VIU] = imx_clk_hw_gate("viu", "nic1_clk", base + 0xa0, 30);
|
||||
clks[IMX7ULP_CLK_PCTLC] = imx_clk_hw_gate("pctlc", "nic1_bus_clk", base + 0xb8, 30);
|
||||
clks[IMX7ULP_CLK_PCTLD] = imx_clk_hw_gate("pctld", "nic1_bus_clk", base + 0xbc, 30);
|
||||
clks[IMX7ULP_CLK_PCTLE] = imx_clk_hw_gate("pctle", "nic1_bus_clk", base + 0xc0, 30);
|
||||
clks[IMX7ULP_CLK_PCTLF] = imx_clk_hw_gate("pctlf", "nic1_bus_clk", base + 0xc4, 30);
|
||||
|
||||
clks[IMX7ULP_CLK_GPU3D] = imx7ulp_clk_composite("gpu3d", periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, false, true, base + 0x140);
|
||||
clks[IMX7ULP_CLK_GPU2D] = imx7ulp_clk_composite("gpu2d", periph_plat_sels, ARRAY_SIZE(periph_plat_sels), true, false, true, base + 0x144);
|
||||
|
||||
imx_check_clk_hws(clks, clk_data->num);
|
||||
|
||||
of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
|
||||
}
|
||||
CLK_OF_DECLARE(imx7ulp_clk_pcc3, "fsl,imx7ulp-pcc3", imx7ulp_clk_pcc3_init);
|
203
drivers/clk/imx/clk-pfdv2.c
Normal file
203
drivers/clk/imx/clk-pfdv2.c
Normal file
@ -0,0 +1,203 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2016 Freescale Semiconductor, Inc.
|
||||
* Copyright 2017~2018 NXP
|
||||
*
|
||||
* Author: Dong Aisheng <aisheng.dong@nxp.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
/**
|
||||
* struct clk_pfdv2 - IMX PFD clock
|
||||
* @clk_hw: clock source
|
||||
* @reg: PFD register address
|
||||
* @gate_bit: Gate bit offset
|
||||
* @vld_bit: Valid bit offset
|
||||
* @frac_off: PLL Fractional Divider offset
|
||||
*/
|
||||
|
||||
struct clk_pfdv2 {
|
||||
struct clk_hw hw;
|
||||
void __iomem *reg;
|
||||
u8 gate_bit;
|
||||
u8 vld_bit;
|
||||
u8 frac_off;
|
||||
};
|
||||
|
||||
#define to_clk_pfdv2(_hw) container_of(_hw, struct clk_pfdv2, hw)
|
||||
|
||||
#define CLK_PFDV2_FRAC_MASK 0x3f
|
||||
|
||||
#define LOCK_TIMEOUT_US USEC_PER_MSEC
|
||||
|
||||
static DEFINE_SPINLOCK(pfd_lock);
|
||||
|
||||
static int clk_pfdv2_wait(struct clk_pfdv2 *pfd)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
return readl_poll_timeout(pfd->reg, val, val & pfd->vld_bit,
|
||||
0, LOCK_TIMEOUT_US);
|
||||
}
|
||||
|
||||
static int clk_pfdv2_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_pfdv2 *pfd = to_clk_pfdv2(hw);
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&pfd_lock, flags);
|
||||
val = readl_relaxed(pfd->reg);
|
||||
val &= ~pfd->gate_bit;
|
||||
writel_relaxed(val, pfd->reg);
|
||||
spin_unlock_irqrestore(&pfd_lock, flags);
|
||||
|
||||
return clk_pfdv2_wait(pfd);
|
||||
}
|
||||
|
||||
static void clk_pfdv2_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_pfdv2 *pfd = to_clk_pfdv2(hw);
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&pfd_lock, flags);
|
||||
val = readl_relaxed(pfd->reg);
|
||||
val |= pfd->gate_bit;
|
||||
writel_relaxed(val, pfd->reg);
|
||||
spin_unlock_irqrestore(&pfd_lock, flags);
|
||||
}
|
||||
|
||||
static unsigned long clk_pfdv2_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_pfdv2 *pfd = to_clk_pfdv2(hw);
|
||||
u64 tmp = parent_rate;
|
||||
u8 frac;
|
||||
|
||||
frac = (readl_relaxed(pfd->reg) >> pfd->frac_off)
|
||||
& CLK_PFDV2_FRAC_MASK;
|
||||
|
||||
if (!frac) {
|
||||
pr_debug("clk_pfdv2: %s invalid pfd frac value 0\n",
|
||||
clk_hw_get_name(hw));
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmp *= 18;
|
||||
do_div(tmp, frac);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static long clk_pfdv2_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
u64 tmp = *prate;
|
||||
u8 frac;
|
||||
|
||||
tmp = tmp * 18 + rate / 2;
|
||||
do_div(tmp, rate);
|
||||
frac = tmp;
|
||||
|
||||
if (frac < 12)
|
||||
frac = 12;
|
||||
else if (frac > 35)
|
||||
frac = 35;
|
||||
|
||||
tmp = *prate;
|
||||
tmp *= 18;
|
||||
do_div(tmp, frac);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static int clk_pfdv2_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_pfdv2 *pfd = to_clk_pfdv2(hw);
|
||||
|
||||
if (readl_relaxed(pfd->reg) & pfd->gate_bit)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int clk_pfdv2_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_pfdv2 *pfd = to_clk_pfdv2(hw);
|
||||
unsigned long flags;
|
||||
u64 tmp = parent_rate;
|
||||
u32 val;
|
||||
u8 frac;
|
||||
|
||||
tmp = tmp * 18 + rate / 2;
|
||||
do_div(tmp, rate);
|
||||
frac = tmp;
|
||||
if (frac < 12)
|
||||
frac = 12;
|
||||
else if (frac > 35)
|
||||
frac = 35;
|
||||
|
||||
spin_lock_irqsave(&pfd_lock, flags);
|
||||
val = readl_relaxed(pfd->reg);
|
||||
val &= ~(CLK_PFDV2_FRAC_MASK << pfd->frac_off);
|
||||
val |= frac << pfd->frac_off;
|
||||
writel_relaxed(val, pfd->reg);
|
||||
spin_unlock_irqrestore(&pfd_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops clk_pfdv2_ops = {
|
||||
.enable = clk_pfdv2_enable,
|
||||
.disable = clk_pfdv2_disable,
|
||||
.recalc_rate = clk_pfdv2_recalc_rate,
|
||||
.round_rate = clk_pfdv2_round_rate,
|
||||
.set_rate = clk_pfdv2_set_rate,
|
||||
.is_enabled = clk_pfdv2_is_enabled,
|
||||
};
|
||||
|
||||
struct clk_hw *imx_clk_pfdv2(const char *name, const char *parent_name,
|
||||
void __iomem *reg, u8 idx)
|
||||
{
|
||||
struct clk_init_data init;
|
||||
struct clk_pfdv2 *pfd;
|
||||
struct clk_hw *hw;
|
||||
int ret;
|
||||
|
||||
WARN_ON(idx > 3);
|
||||
|
||||
pfd = kzalloc(sizeof(*pfd), GFP_KERNEL);
|
||||
if (!pfd)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
pfd->reg = reg;
|
||||
pfd->gate_bit = 1 << ((idx + 1) * 8 - 1);
|
||||
pfd->vld_bit = pfd->gate_bit - 1;
|
||||
pfd->frac_off = idx * 8;
|
||||
|
||||
init.name = name;
|
||||
init.ops = &clk_pfdv2_ops;
|
||||
init.parent_names = &parent_name;
|
||||
init.num_parents = 1;
|
||||
init.flags = CLK_SET_RATE_GATE;
|
||||
|
||||
pfd->hw.init = &init;
|
||||
|
||||
hw = &pfd->hw;
|
||||
ret = clk_hw_register(NULL, hw);
|
||||
if (ret) {
|
||||
kfree(pfd);
|
||||
hw = ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return hw;
|
||||
}
|
184
drivers/clk/imx/clk-pllv4.c
Normal file
184
drivers/clk/imx/clk-pllv4.c
Normal file
@ -0,0 +1,184 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2016 Freescale Semiconductor, Inc.
|
||||
* Copyright 2017~2018 NXP
|
||||
*
|
||||
* Author: Dong Aisheng <aisheng.dong@nxp.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
/* PLL Control Status Register (xPLLCSR) */
|
||||
#define PLL_CSR_OFFSET 0x0
|
||||
#define PLL_VLD BIT(24)
|
||||
#define PLL_EN BIT(0)
|
||||
|
||||
/* PLL Configuration Register (xPLLCFG) */
|
||||
#define PLL_CFG_OFFSET 0x08
|
||||
#define BP_PLL_MULT 16
|
||||
#define BM_PLL_MULT (0x7f << 16)
|
||||
|
||||
/* PLL Numerator Register (xPLLNUM) */
|
||||
#define PLL_NUM_OFFSET 0x10
|
||||
|
||||
/* PLL Denominator Register (xPLLDENOM) */
|
||||
#define PLL_DENOM_OFFSET 0x14
|
||||
|
||||
struct clk_pllv4 {
|
||||
struct clk_hw hw;
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
/* Valid PLL MULT Table */
|
||||
static const int pllv4_mult_table[] = {33, 27, 22, 20, 17, 16};
|
||||
|
||||
#define to_clk_pllv4(__hw) container_of(__hw, struct clk_pllv4, hw)
|
||||
|
||||
#define LOCK_TIMEOUT_US USEC_PER_MSEC
|
||||
|
||||
static inline int clk_pllv4_wait_lock(struct clk_pllv4 *pll)
|
||||
{
|
||||
u32 csr;
|
||||
|
||||
return readl_poll_timeout(pll->base + PLL_CSR_OFFSET,
|
||||
csr, csr & PLL_VLD, 0, LOCK_TIMEOUT_US);
|
||||
}
|
||||
|
||||
static int clk_pllv4_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_pllv4 *pll = to_clk_pllv4(hw);
|
||||
|
||||
if (readl_relaxed(pll->base) & PLL_EN)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long clk_pllv4_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_pllv4 *pll = to_clk_pllv4(hw);
|
||||
u32 div;
|
||||
|
||||
div = readl_relaxed(pll->base + PLL_CFG_OFFSET);
|
||||
div &= BM_PLL_MULT;
|
||||
div >>= BP_PLL_MULT;
|
||||
|
||||
return parent_rate * div;
|
||||
}
|
||||
|
||||
static long clk_pllv4_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
unsigned long parent_rate = *prate;
|
||||
unsigned long round_rate, i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) {
|
||||
round_rate = parent_rate * pllv4_mult_table[i];
|
||||
if (rate >= round_rate)
|
||||
return round_rate;
|
||||
}
|
||||
|
||||
return round_rate;
|
||||
}
|
||||
|
||||
static bool clk_pllv4_is_valid_mult(unsigned int mult)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* check if mult is in valid MULT table */
|
||||
for (i = 0; i < ARRAY_SIZE(pllv4_mult_table); i++) {
|
||||
if (pllv4_mult_table[i] == mult)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int clk_pllv4_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_pllv4 *pll = to_clk_pllv4(hw);
|
||||
u32 val, mult;
|
||||
|
||||
mult = rate / parent_rate;
|
||||
|
||||
if (!clk_pllv4_is_valid_mult(mult))
|
||||
return -EINVAL;
|
||||
|
||||
val = readl_relaxed(pll->base + PLL_CFG_OFFSET);
|
||||
val &= ~BM_PLL_MULT;
|
||||
val |= mult << BP_PLL_MULT;
|
||||
writel_relaxed(val, pll->base + PLL_CFG_OFFSET);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_pllv4_enable(struct clk_hw *hw)
|
||||
{
|
||||
u32 val;
|
||||
struct clk_pllv4 *pll = to_clk_pllv4(hw);
|
||||
|
||||
val = readl_relaxed(pll->base);
|
||||
val |= PLL_EN;
|
||||
writel_relaxed(val, pll->base);
|
||||
|
||||
return clk_pllv4_wait_lock(pll);
|
||||
}
|
||||
|
||||
static void clk_pllv4_disable(struct clk_hw *hw)
|
||||
{
|
||||
u32 val;
|
||||
struct clk_pllv4 *pll = to_clk_pllv4(hw);
|
||||
|
||||
val = readl_relaxed(pll->base);
|
||||
val &= ~PLL_EN;
|
||||
writel_relaxed(val, pll->base);
|
||||
}
|
||||
|
||||
static const struct clk_ops clk_pllv4_ops = {
|
||||
.recalc_rate = clk_pllv4_recalc_rate,
|
||||
.round_rate = clk_pllv4_round_rate,
|
||||
.set_rate = clk_pllv4_set_rate,
|
||||
.enable = clk_pllv4_enable,
|
||||
.disable = clk_pllv4_disable,
|
||||
.is_enabled = clk_pllv4_is_enabled,
|
||||
};
|
||||
|
||||
struct clk_hw *imx_clk_pllv4(const char *name, const char *parent_name,
|
||||
void __iomem *base)
|
||||
{
|
||||
struct clk_pllv4 *pll;
|
||||
struct clk_hw *hw;
|
||||
struct clk_init_data init;
|
||||
int ret;
|
||||
|
||||
pll = kzalloc(sizeof(*pll), GFP_KERNEL);
|
||||
if (!pll)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
pll->base = base;
|
||||
|
||||
init.name = name;
|
||||
init.ops = &clk_pllv4_ops;
|
||||
init.parent_names = &parent_name;
|
||||
init.num_parents = 1;
|
||||
init.flags = CLK_SET_RATE_GATE;
|
||||
|
||||
pll->hw.init = &init;
|
||||
|
||||
hw = &pll->hw;
|
||||
ret = clk_hw_register(NULL, hw);
|
||||
if (ret) {
|
||||
kfree(pll);
|
||||
hw = ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return hw;
|
||||
}
|
@ -18,6 +18,16 @@ void __init imx_check_clocks(struct clk *clks[], unsigned int count)
|
||||
i, PTR_ERR(clks[i]));
|
||||
}
|
||||
|
||||
void imx_check_clk_hws(struct clk_hw *clks[], unsigned int count)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
if (IS_ERR(clks[i]))
|
||||
pr_err("i.MX clk %u: register failed with %ld\n",
|
||||
i, PTR_ERR(clks[i]));
|
||||
}
|
||||
|
||||
static struct clk * __init imx_obtain_fixed_clock_from_dt(const char *name)
|
||||
{
|
||||
struct of_phandle_args phandle;
|
||||
@ -49,6 +59,18 @@ struct clk * __init imx_obtain_fixed_clock(
|
||||
return clk;
|
||||
}
|
||||
|
||||
struct clk_hw * __init imx_obtain_fixed_clk_hw(struct device_node *np,
|
||||
const char *name)
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
clk = of_clk_get_by_name(np, name);
|
||||
if (IS_ERR(clk))
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
return __clk_get_hw(clk);
|
||||
}
|
||||
|
||||
/*
|
||||
* This fixups the register CCM_CSCMR1 write value.
|
||||
* The write/read/divider values of the aclk_podf field
|
||||
|
@ -8,6 +8,7 @@
|
||||
extern spinlock_t imx_ccm_lock;
|
||||
|
||||
void imx_check_clocks(struct clk *clks[], unsigned int count);
|
||||
void imx_check_clk_hws(struct clk_hw *clks[], unsigned int count);
|
||||
void imx_register_uart_clocks(struct clk ** const clks[]);
|
||||
|
||||
extern void imx_cscmr1_fixup(u32 *val);
|
||||
@ -42,6 +43,9 @@ enum imx_pllv3_type {
|
||||
struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
|
||||
const char *parent_name, void __iomem *base, u32 div_mask);
|
||||
|
||||
struct clk_hw *imx_clk_pllv4(const char *name, const char *parent_name,
|
||||
void __iomem *base);
|
||||
|
||||
struct clk *clk_register_gate2(struct device *dev, const char *name,
|
||||
const char *parent_name, unsigned long flags,
|
||||
void __iomem *reg, u8 bit_idx, u8 cgr_val,
|
||||
@ -51,26 +55,38 @@ struct clk *clk_register_gate2(struct device *dev, const char *name,
|
||||
struct clk * imx_obtain_fixed_clock(
|
||||
const char *name, unsigned long rate);
|
||||
|
||||
struct clk_hw *imx_obtain_fixed_clk_hw(struct device_node *np,
|
||||
const char *name);
|
||||
|
||||
struct clk *imx_clk_gate_exclusive(const char *name, const char *parent,
|
||||
void __iomem *reg, u8 shift, u32 exclusive_mask);
|
||||
|
||||
struct clk *imx_clk_pfd(const char *name, const char *parent_name,
|
||||
void __iomem *reg, u8 idx);
|
||||
|
||||
struct clk_hw *imx_clk_pfdv2(const char *name, const char *parent_name,
|
||||
void __iomem *reg, u8 idx);
|
||||
|
||||
struct clk *imx_clk_busy_divider(const char *name, const char *parent_name,
|
||||
void __iomem *reg, u8 shift, u8 width,
|
||||
void __iomem *busy_reg, u8 busy_shift);
|
||||
|
||||
struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift,
|
||||
u8 width, void __iomem *busy_reg, u8 busy_shift,
|
||||
const char **parent_names, int num_parents);
|
||||
const char * const *parent_names, int num_parents);
|
||||
|
||||
struct clk_hw *imx7ulp_clk_composite(const char *name,
|
||||
const char * const *parent_names,
|
||||
int num_parents, bool mux_present,
|
||||
bool rate_present, bool gate_present,
|
||||
void __iomem *reg);
|
||||
|
||||
struct clk *imx_clk_fixup_divider(const char *name, const char *parent,
|
||||
void __iomem *reg, u8 shift, u8 width,
|
||||
void (*fixup)(u32 *val));
|
||||
|
||||
struct clk *imx_clk_fixup_mux(const char *name, void __iomem *reg,
|
||||
u8 shift, u8 width, const char **parents,
|
||||
u8 shift, u8 width, const char * const *parents,
|
||||
int num_parents, void (*fixup)(u32 *val));
|
||||
|
||||
static inline struct clk *imx_clk_fixed(const char *name, int rate)
|
||||
@ -78,8 +94,19 @@ static inline struct clk *imx_clk_fixed(const char *name, int rate)
|
||||
return clk_register_fixed_rate(NULL, name, NULL, 0, rate);
|
||||
}
|
||||
|
||||
static inline struct clk_hw *imx_clk_hw_fixed(const char *name, int rate)
|
||||
{
|
||||
return clk_hw_register_fixed_rate(NULL, name, NULL, 0, rate);
|
||||
}
|
||||
|
||||
static inline struct clk_hw *imx_get_clk_hw_fixed(const char *name, int rate)
|
||||
{
|
||||
return clk_hw_register_fixed_rate(NULL, name, NULL, 0, rate);
|
||||
}
|
||||
|
||||
static inline struct clk *imx_clk_mux_ldb(const char *name, void __iomem *reg,
|
||||
u8 shift, u8 width, const char **parents, int num_parents)
|
||||
u8 shift, u8 width, const char * const *parents,
|
||||
int num_parents)
|
||||
{
|
||||
return clk_register_mux(NULL, name, parents, num_parents,
|
||||
CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, reg,
|
||||
@ -100,6 +127,15 @@ static inline struct clk *imx_clk_divider(const char *name, const char *parent,
|
||||
reg, shift, width, 0, &imx_ccm_lock);
|
||||
}
|
||||
|
||||
static inline struct clk_hw *imx_clk_hw_divider(const char *name,
|
||||
const char *parent,
|
||||
void __iomem *reg, u8 shift,
|
||||
u8 width)
|
||||
{
|
||||
return clk_hw_register_divider(NULL, name, parent, CLK_SET_RATE_PARENT,
|
||||
reg, shift, width, 0, &imx_ccm_lock);
|
||||
}
|
||||
|
||||
static inline struct clk *imx_clk_divider_flags(const char *name,
|
||||
const char *parent, void __iomem *reg, u8 shift, u8 width,
|
||||
unsigned long flags)
|
||||
@ -108,6 +144,15 @@ static inline struct clk *imx_clk_divider_flags(const char *name,
|
||||
reg, shift, width, 0, &imx_ccm_lock);
|
||||
}
|
||||
|
||||
static inline struct clk_hw *imx_clk_hw_divider_flags(const char *name,
|
||||
const char *parent,
|
||||
void __iomem *reg, u8 shift,
|
||||
u8 width, unsigned long flags)
|
||||
{
|
||||
return clk_hw_register_divider(NULL, name, parent, flags,
|
||||
reg, shift, width, 0, &imx_ccm_lock);
|
||||
}
|
||||
|
||||
static inline struct clk *imx_clk_divider2(const char *name, const char *parent,
|
||||
void __iomem *reg, u8 shift, u8 width)
|
||||
{
|
||||
@ -130,6 +175,13 @@ static inline struct clk *imx_clk_gate_flags(const char *name, const char *paren
|
||||
shift, 0, &imx_ccm_lock);
|
||||
}
|
||||
|
||||
static inline struct clk_hw *imx_clk_hw_gate(const char *name, const char *parent,
|
||||
void __iomem *reg, u8 shift)
|
||||
{
|
||||
return clk_hw_register_gate(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
|
||||
shift, 0, &imx_ccm_lock);
|
||||
}
|
||||
|
||||
static inline struct clk *imx_clk_gate_dis(const char *name, const char *parent,
|
||||
void __iomem *reg, u8 shift)
|
||||
{
|
||||
@ -199,7 +251,8 @@ static inline struct clk *imx_clk_gate4(const char *name, const char *parent,
|
||||
}
|
||||
|
||||
static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg,
|
||||
u8 shift, u8 width, const char **parents, int num_parents)
|
||||
u8 shift, u8 width, const char * const *parents,
|
||||
int num_parents)
|
||||
{
|
||||
return clk_register_mux(NULL, name, parents, num_parents,
|
||||
CLK_SET_RATE_NO_REPARENT, reg, shift,
|
||||
@ -207,24 +260,53 @@ static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg,
|
||||
}
|
||||
|
||||
static inline struct clk *imx_clk_mux2(const char *name, void __iomem *reg,
|
||||
u8 shift, u8 width, const char **parents, int num_parents)
|
||||
u8 shift, u8 width, const char * const *parents,
|
||||
int num_parents)
|
||||
{
|
||||
return clk_register_mux(NULL, name, parents, num_parents,
|
||||
CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE,
|
||||
reg, shift, width, 0, &imx_ccm_lock);
|
||||
}
|
||||
|
||||
static inline struct clk_hw *imx_clk_hw_mux2(const char *name, void __iomem *reg,
|
||||
u8 shift, u8 width,
|
||||
const char * const *parents,
|
||||
int num_parents)
|
||||
{
|
||||
return clk_hw_register_mux(NULL, name, parents, num_parents,
|
||||
CLK_SET_RATE_NO_REPARENT |
|
||||
CLK_OPS_PARENT_ENABLE,
|
||||
reg, shift, width, 0, &imx_ccm_lock);
|
||||
}
|
||||
|
||||
static inline struct clk *imx_clk_mux_flags(const char *name,
|
||||
void __iomem *reg, u8 shift, u8 width, const char **parents,
|
||||
int num_parents, unsigned long flags)
|
||||
void __iomem *reg, u8 shift, u8 width,
|
||||
const char * const *parents, int num_parents,
|
||||
unsigned long flags)
|
||||
{
|
||||
return clk_register_mux(NULL, name, parents, num_parents,
|
||||
flags | CLK_SET_RATE_NO_REPARENT, reg, shift, width, 0,
|
||||
&imx_ccm_lock);
|
||||
}
|
||||
|
||||
static inline struct clk_hw *imx_clk_hw_mux_flags(const char *name,
|
||||
void __iomem *reg, u8 shift,
|
||||
u8 width,
|
||||
const char * const *parents,
|
||||
int num_parents,
|
||||
unsigned long flags)
|
||||
{
|
||||
return clk_hw_register_mux(NULL, name, parents, num_parents,
|
||||
flags | CLK_SET_RATE_NO_REPARENT,
|
||||
reg, shift, width, 0, &imx_ccm_lock);
|
||||
}
|
||||
|
||||
struct clk *imx_clk_cpu(const char *name, const char *parent_name,
|
||||
struct clk *div, struct clk *mux, struct clk *pll,
|
||||
struct clk *step);
|
||||
|
||||
struct clk_hw *imx_clk_divider_gate(const char *name, const char *parent_name,
|
||||
unsigned long flags, void __iomem *reg, u8 shift, u8 width,
|
||||
u8 clk_divider_flags, const struct clk_div_table *table,
|
||||
spinlock_t *lock);
|
||||
#endif
|
||||
|
109
include/dt-bindings/clock/imx7ulp-clock.h
Normal file
109
include/dt-bindings/clock/imx7ulp-clock.h
Normal file
@ -0,0 +1,109 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright (C) 2016 Freescale Semiconductor, Inc.
|
||||
* Copyright 2017~2018 NXP
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __DT_BINDINGS_CLOCK_IMX7ULP_H
|
||||
#define __DT_BINDINGS_CLOCK_IMX7ULP_H
|
||||
|
||||
/* SCG1 */
|
||||
|
||||
#define IMX7ULP_CLK_DUMMY 0
|
||||
#define IMX7ULP_CLK_ROSC 1
|
||||
#define IMX7ULP_CLK_SOSC 2
|
||||
#define IMX7ULP_CLK_FIRC 3
|
||||
#define IMX7ULP_CLK_SPLL_PRE_SEL 4
|
||||
#define IMX7ULP_CLK_SPLL_PRE_DIV 5
|
||||
#define IMX7ULP_CLK_SPLL 6
|
||||
#define IMX7ULP_CLK_SPLL_POST_DIV1 7
|
||||
#define IMX7ULP_CLK_SPLL_POST_DIV2 8
|
||||
#define IMX7ULP_CLK_SPLL_PFD0 9
|
||||
#define IMX7ULP_CLK_SPLL_PFD1 10
|
||||
#define IMX7ULP_CLK_SPLL_PFD2 11
|
||||
#define IMX7ULP_CLK_SPLL_PFD3 12
|
||||
#define IMX7ULP_CLK_SPLL_PFD_SEL 13
|
||||
#define IMX7ULP_CLK_SPLL_SEL 14
|
||||
#define IMX7ULP_CLK_APLL_PRE_SEL 15
|
||||
#define IMX7ULP_CLK_APLL_PRE_DIV 16
|
||||
#define IMX7ULP_CLK_APLL 17
|
||||
#define IMX7ULP_CLK_APLL_POST_DIV1 18
|
||||
#define IMX7ULP_CLK_APLL_POST_DIV2 19
|
||||
#define IMX7ULP_CLK_APLL_PFD0 20
|
||||
#define IMX7ULP_CLK_APLL_PFD1 21
|
||||
#define IMX7ULP_CLK_APLL_PFD2 22
|
||||
#define IMX7ULP_CLK_APLL_PFD3 23
|
||||
#define IMX7ULP_CLK_APLL_PFD_SEL 24
|
||||
#define IMX7ULP_CLK_APLL_SEL 25
|
||||
#define IMX7ULP_CLK_UPLL 26
|
||||
#define IMX7ULP_CLK_SYS_SEL 27
|
||||
#define IMX7ULP_CLK_CORE_DIV 28
|
||||
#define IMX7ULP_CLK_BUS_DIV 29
|
||||
#define IMX7ULP_CLK_PLAT_DIV 30
|
||||
#define IMX7ULP_CLK_DDR_SEL 31
|
||||
#define IMX7ULP_CLK_DDR_DIV 32
|
||||
#define IMX7ULP_CLK_NIC_SEL 33
|
||||
#define IMX7ULP_CLK_NIC0_DIV 34
|
||||
#define IMX7ULP_CLK_GPU_DIV 35
|
||||
#define IMX7ULP_CLK_NIC1_DIV 36
|
||||
#define IMX7ULP_CLK_NIC1_BUS_DIV 37
|
||||
#define IMX7ULP_CLK_NIC1_EXT_DIV 38
|
||||
#define IMX7ULP_CLK_MIPI_PLL 39
|
||||
#define IMX7ULP_CLK_SIRC 40
|
||||
#define IMX7ULP_CLK_SOSC_BUS_CLK 41
|
||||
#define IMX7ULP_CLK_FIRC_BUS_CLK 42
|
||||
#define IMX7ULP_CLK_SPLL_BUS_CLK 43
|
||||
|
||||
#define IMX7ULP_CLK_SCG1_END 44
|
||||
|
||||
/* PCC2 */
|
||||
#define IMX7ULP_CLK_DMA1 0
|
||||
#define IMX7ULP_CLK_RGPIO2P1 1
|
||||
#define IMX7ULP_CLK_FLEXBUS 2
|
||||
#define IMX7ULP_CLK_SEMA42_1 3
|
||||
#define IMX7ULP_CLK_DMA_MUX1 4
|
||||
#define IMX7ULP_CLK_SNVS 5
|
||||
#define IMX7ULP_CLK_CAAM 6
|
||||
#define IMX7ULP_CLK_LPTPM4 7
|
||||
#define IMX7ULP_CLK_LPTPM5 8
|
||||
#define IMX7ULP_CLK_LPIT1 9
|
||||
#define IMX7ULP_CLK_LPSPI2 10
|
||||
#define IMX7ULP_CLK_LPSPI3 11
|
||||
#define IMX7ULP_CLK_LPI2C4 12
|
||||
#define IMX7ULP_CLK_LPI2C5 13
|
||||
#define IMX7ULP_CLK_LPUART4 14
|
||||
#define IMX7ULP_CLK_LPUART5 15
|
||||
#define IMX7ULP_CLK_FLEXIO1 16
|
||||
#define IMX7ULP_CLK_USB0 17
|
||||
#define IMX7ULP_CLK_USB1 18
|
||||
#define IMX7ULP_CLK_USB_PHY 19
|
||||
#define IMX7ULP_CLK_USB_PL301 20
|
||||
#define IMX7ULP_CLK_USDHC0 21
|
||||
#define IMX7ULP_CLK_USDHC1 22
|
||||
#define IMX7ULP_CLK_WDG1 23
|
||||
#define IMX7ULP_CLK_WDG2 24
|
||||
|
||||
#define IMX7ULP_CLK_PCC2_END 25
|
||||
|
||||
/* PCC3 */
|
||||
#define IMX7ULP_CLK_LPTPM6 0
|
||||
#define IMX7ULP_CLK_LPTPM7 1
|
||||
#define IMX7ULP_CLK_LPI2C6 2
|
||||
#define IMX7ULP_CLK_LPI2C7 3
|
||||
#define IMX7ULP_CLK_LPUART6 4
|
||||
#define IMX7ULP_CLK_LPUART7 5
|
||||
#define IMX7ULP_CLK_VIU 6
|
||||
#define IMX7ULP_CLK_DSI 7
|
||||
#define IMX7ULP_CLK_LCDIF 8
|
||||
#define IMX7ULP_CLK_MMDC 9
|
||||
#define IMX7ULP_CLK_PCTLC 10
|
||||
#define IMX7ULP_CLK_PCTLD 11
|
||||
#define IMX7ULP_CLK_PCTLE 12
|
||||
#define IMX7ULP_CLK_PCTLF 13
|
||||
#define IMX7ULP_CLK_GPU3D 14
|
||||
#define IMX7ULP_CLK_GPU2D 15
|
||||
|
||||
#define IMX7ULP_CLK_PCC3_END 16
|
||||
|
||||
#endif /* __DT_BINDINGS_CLOCK_IMX7ULP_H */
|
@ -601,6 +601,12 @@ void clk_hw_unregister_fixed_factor(struct clk_hw *hw);
|
||||
* @lock: register lock
|
||||
*
|
||||
* Clock with adjustable fractional divider affecting its output frequency.
|
||||
*
|
||||
* Flags:
|
||||
* CLK_FRAC_DIVIDER_ZERO_BASED - by default the numerator and denominator
|
||||
* is the value read from the register. If CLK_FRAC_DIVIDER_ZERO_BASED
|
||||
* is set then the numerator and denominator are both the value read
|
||||
* plus one.
|
||||
*/
|
||||
struct clk_fractional_divider {
|
||||
struct clk_hw hw;
|
||||
@ -620,6 +626,8 @@ struct clk_fractional_divider {
|
||||
|
||||
#define to_clk_fd(_hw) container_of(_hw, struct clk_fractional_divider, hw)
|
||||
|
||||
#define CLK_FRAC_DIVIDER_ZERO_BASED BIT(0)
|
||||
|
||||
extern const struct clk_ops clk_fractional_divider_ops;
|
||||
struct clk *clk_register_fractional_divider(struct device *dev,
|
||||
const char *name, const char *parent_name, unsigned long flags,
|
||||
|
Loading…
Reference in New Issue
Block a user