The clk framework changes for 4.3 are mostly updates to existing drivers
and the addition of new clock drivers. Stephen Boyd has also done a lot of subsystem-wide driver clean-ups (thanks!). There are also fixes to the framework core and changes to better split clock provider drivers from clock consumer drivers. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJV5KelAAoJEKI6nJvDJaTUwaQP/RVb70v6XSgMIePuOq3iaECT bclCAyito3YFwykrPPmQ1DucHvEjlWopeFwKqEE9VjNl07TVIH/OMGeonb9yErIY aN+FMoA9RUGVexMhy004q5sSbOEihAqTgKWaOiYoY8zAfJfeTpYXUoy34FcrW7MB j/cDDJgigtWe9zzcdrW04oT454lXQaSQuGX39tDCR0s0S3soYU2JyjkyBGiO5Yid 1yIMq/nzI8SrCwxwD/nFwQNtg7lqiAN291Nbi4At1vvG5r4RhNveuLGv8uJ50XRB xwy0sdHLIVJrIJ8OUcs1sY8wxu7ghDS8u+vjTNO2RzBf3KZWbuXWX+yVM7JQi4Ty 0iL5hGbvERy5E9QSzzH+Ox2jVt5e/r/dyvRf3oBDPVrFXhKusYhn6JmdUVJkTZ83 GTw2sQdEpcmry4z/50/MaqpZuXVZ09VTOCTqp8ToseJjsz9jXxVhQ4HdAwLc8cmV txWGRXuBxCB+2o8M0oky3IKS69VFFH5u6QQ0KG8+JYOrDDG7GcnJsFeV7mQjlu8g 3evYUILNAUfJGBpkOeLs654KUBHwUyXc87cUIKwjGaPruWb2048+kdCVrL3IFwPb sS/7Qn3DQ90pHFUTssDnWLz3X0IWT3H0iV4zZyAqqdARugEo+mpykmXmMWcWc3VR MrD1l3GVxLegEf242Zpo =QAiQ -----END PGP SIGNATURE----- Merge tag 'clk-for-linus-4.3' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux Pull clk updates from Michael Turquette: "The clk framework changes for 4.3 are mostly updates to existing drivers and the addition of new clock drivers. Stephen Boyd has also done a lot of subsystem-wide driver clean-ups (thanks!). There are also fixes to the framework core and changes to better split clock provider drivers from clock consumer drivers" * tag 'clk-for-linus-4.3' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (227 commits) clk: s5pv210: add missing call to samsung_clk_of_add_provider() clk: pistachio: correct critical clock list clk: pistachio: Fix PLL rate calculation in integer mode clk: pistachio: Fix override of clk-pll settings from boot loader clk: pistachio: Fix 32bit integer overflows clk: tegra: Fix some static checker problems clk: qcom: Fix MSM8916 prng clock enable bit clk: Add missing header for 'bool' definition to clk-conf.h drivers/clk: appropriate __init annotation for const data clk: rockchip: register pll mux before pll itself clk: add bindings for the Ux500 clocks clk/ARM: move Ux500 PRCC bases to the device tree clk: remove duplicated code with __clk_set_parent_after clk: Convert __clk_get_name(hw->clk) to clk_hw_get_name(hw) clk: Constify clk_hw argument to provider APIs clk: Hi6220: add stub clock driver dt-bindings: clk: Hi6220: Document stub clock driver dt-bindings: arm: Hi6220: add doc for SRAM controller clk: atlas7: fix pll missed divide NR in fraction mode clk: atlas7: fix bit field and its root clk for coresight_tpiu ...
This commit is contained in:
commit
f36fc04e4c
|
@ -71,12 +71,8 @@ the operations defined in clk.h:
|
|||
long (*round_rate)(struct clk_hw *hw,
|
||||
unsigned long rate,
|
||||
unsigned long *parent_rate);
|
||||
long (*determine_rate)(struct clk_hw *hw,
|
||||
unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_clk);
|
||||
int (*determine_rate)(struct clk_hw *hw,
|
||||
struct clk_rate_request *req);
|
||||
int (*set_parent)(struct clk_hw *hw, u8 index);
|
||||
u8 (*get_parent)(struct clk_hw *hw);
|
||||
int (*set_rate)(struct clk_hw *hw,
|
||||
|
|
|
@ -127,6 +127,24 @@ Example:
|
|||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
|
||||
Hisilicon Hi6220 SRAM controller
|
||||
|
||||
Required properties:
|
||||
- compatible : "hisilicon,hi6220-sramctrl", "syscon"
|
||||
- reg : Register address and size
|
||||
|
||||
Hisilicon's SoCs use sram for multiple purpose; on Hi6220 there have several
|
||||
SRAM banks for power management, modem, security, etc. Further, use "syscon"
|
||||
managing the common sram which can be shared by multiple modules.
|
||||
|
||||
Example:
|
||||
/*for Hi6220*/
|
||||
sram: sram@fff80000 {
|
||||
compatible = "hisilicon,hi6220-sramctrl", "syscon";
|
||||
reg = <0x0 0xfff80000 0x0 0x12000>;
|
||||
};
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
Hisilicon HiP01 system controller
|
||||
|
||||
|
|
46
Documentation/devicetree/bindings/arm/sp810.txt
Normal file
46
Documentation/devicetree/bindings/arm/sp810.txt
Normal file
|
@ -0,0 +1,46 @@
|
|||
SP810 System Controller
|
||||
-----------------------
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: standard compatible string for a Primecell peripheral,
|
||||
see Documentation/devicetree/bindings/arm/primecell.txt
|
||||
for more details
|
||||
should be: "arm,sp810", "arm,primecell"
|
||||
|
||||
- reg: standard registers property, physical address and size
|
||||
of the control registers
|
||||
|
||||
- clock-names: from the common clock bindings, for more details see
|
||||
Documentation/devicetree/bindings/clock/clock-bindings.txt;
|
||||
should be: "refclk", "timclk", "apb_pclk"
|
||||
|
||||
- clocks: from the common clock bindings, phandle and clock
|
||||
specifier pairs for the entries of clock-names property
|
||||
|
||||
- #clock-cells: from the common clock bindings;
|
||||
should be: <1>
|
||||
|
||||
- clock-output-names: from the common clock bindings;
|
||||
should be: "timerclken0", "timerclken1", "timerclken2", "timerclken3"
|
||||
|
||||
- assigned-clocks: from the common clock binding;
|
||||
should be: clock specifier for each output clock of this
|
||||
provider node
|
||||
|
||||
- assigned-clock-parents: from the common clock binding;
|
||||
should be: phandle of input clock listed in clocks
|
||||
property with the highest frequency
|
||||
|
||||
Example:
|
||||
v2m_sysctl: sysctl@020000 {
|
||||
compatible = "arm,sp810", "arm,primecell";
|
||||
reg = <0x020000 0x1000>;
|
||||
clocks = <&v2m_refclk32khz>, <&v2m_refclk1mhz>, <&smbclk>;
|
||||
clock-names = "refclk", "timclk", "apb_pclk";
|
||||
#clock-cells = <1>;
|
||||
clock-output-names = "timerclken0", "timerclken1", "timerclken2", "timerclken3";
|
||||
assigned-clocks = <&v2m_sysctl 0>, <&v2m_sysctl 1>, <&v2m_sysctl 3>, <&v2m_sysctl 3>;
|
||||
assigned-clock-parents = <&v2m_refclk1mhz>, <&v2m_refclk1mhz>, <&v2m_refclk1mhz>, <&v2m_refclk1mhz>;
|
||||
|
||||
};
|
19
Documentation/devicetree/bindings/clock/gpio-mux-clock.txt
Normal file
19
Documentation/devicetree/bindings/clock/gpio-mux-clock.txt
Normal file
|
@ -0,0 +1,19 @@
|
|||
Binding for simple gpio clock multiplexer.
|
||||
|
||||
This binding uses the common clock binding[1].
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
|
||||
Required properties:
|
||||
- compatible : shall be "gpio-mux-clock".
|
||||
- clocks: list of two references to parent clocks.
|
||||
- #clock-cells : from common clock binding; shall be set to 0.
|
||||
- select-gpios : GPIO reference for selecting the parent clock.
|
||||
|
||||
Example:
|
||||
clock {
|
||||
compatible = "gpio-mux-clock";
|
||||
clocks = <&parentclk1>, <&parentclk2>;
|
||||
#clock-cells = <0>;
|
||||
select-gpios = <&gpio 1 GPIO_ACTIVE_HIGH>;
|
||||
};
|
|
@ -15,19 +15,36 @@ Required Properties:
|
|||
- "hisilicon,hi6220-sysctrl"
|
||||
- "hisilicon,hi6220-mediactrl"
|
||||
- "hisilicon,hi6220-pmctrl"
|
||||
- "hisilicon,hi6220-stub-clk"
|
||||
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
|
||||
- #clock-cells: should be 1.
|
||||
|
||||
For example:
|
||||
Optional Properties:
|
||||
|
||||
- hisilicon,hi6220-clk-sram: phandle to the syscon managing the SoC internal sram;
|
||||
the driver need use the sram to pass parameters for frequency change.
|
||||
|
||||
- mboxes: use the label reference for the mailbox as the first parameter, the
|
||||
second parameter is the channel number.
|
||||
|
||||
Example 1:
|
||||
sys_ctrl: sys_ctrl@f7030000 {
|
||||
compatible = "hisilicon,hi6220-sysctrl", "syscon";
|
||||
reg = <0x0 0xf7030000 0x0 0x2000>;
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
Example 2:
|
||||
stub_clock: stub_clock {
|
||||
compatible = "hisilicon,hi6220-stub-clk";
|
||||
hisilicon,hi6220-clk-sram = <&sram>;
|
||||
#clock-cells = <1>;
|
||||
mboxes = <&mailbox 1>;
|
||||
};
|
||||
|
||||
Each clock is assigned an identifier and client nodes use this identifier
|
||||
to specify the clock which they consume.
|
||||
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
NVIDIA Tegra124 DFLL FCPU clocksource
|
||||
|
||||
This binding uses the common clock binding:
|
||||
Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
|
||||
The DFLL IP block on Tegra is a root clocksource designed for clocking
|
||||
the fast CPU cluster. It consists of a free-running voltage controlled
|
||||
oscillator connected to the CPU voltage rail (VDD_CPU), and a closed loop
|
||||
control module that will automatically adjust the VDD_CPU voltage by
|
||||
communicating with an off-chip PMIC either via an I2C bus or via PWM signals.
|
||||
Currently only the I2C mode is supported by these bindings.
|
||||
|
||||
Required properties:
|
||||
- compatible : should be "nvidia,tegra124-dfll"
|
||||
- reg : Defines the following set of registers, in the order listed:
|
||||
- registers for the DFLL control logic.
|
||||
- registers for the I2C output logic.
|
||||
- registers for the integrated I2C master controller.
|
||||
- look-up table RAM for voltage register values.
|
||||
- interrupts: Should contain the DFLL block interrupt.
|
||||
- clocks: Must contain an entry for each entry in clock-names.
|
||||
See clock-bindings.txt for details.
|
||||
- clock-names: Must include the following entries:
|
||||
- soc: Clock source for the DFLL control logic.
|
||||
- ref: The closed loop reference clock
|
||||
- i2c: Clock source for the integrated I2C master.
|
||||
- resets: Must contain an entry for each entry in reset-names.
|
||||
See ../reset/reset.txt for details.
|
||||
- reset-names: Must include the following entries:
|
||||
- dvco: Reset control for the DFLL DVCO.
|
||||
- #clock-cells: Must be 0.
|
||||
- clock-output-names: Name of the clock output.
|
||||
- vdd-cpu-supply: Regulator for the CPU voltage rail that the DFLL
|
||||
hardware will start controlling. The regulator will be queried for
|
||||
the I2C register, control values and supported voltages.
|
||||
|
||||
Required properties for the control loop parameters:
|
||||
- nvidia,sample-rate: Sample rate of the DFLL control loop.
|
||||
- nvidia,droop-ctrl: See the register CL_DVFS_DROOP_CTRL in the TRM.
|
||||
- nvidia,force-mode: See the field DFLL_PARAMS_FORCE_MODE in the TRM.
|
||||
- nvidia,cf: Numeric value, see the field DFLL_PARAMS_CF_PARAM in the TRM.
|
||||
- nvidia,ci: Numeric value, see the field DFLL_PARAMS_CI_PARAM in the TRM.
|
||||
- nvidia,cg: Numeric value, see the field DFLL_PARAMS_CG_PARAM in the TRM.
|
||||
|
||||
Optional properties for the control loop parameters:
|
||||
- nvidia,cg-scale: Boolean value, see the field DFLL_PARAMS_CG_SCALE in the TRM.
|
||||
|
||||
Required properties for I2C mode:
|
||||
- nvidia,i2c-fs-rate: I2C transfer rate, if using full speed mode.
|
||||
|
||||
Example:
|
||||
|
||||
clock@0,70110000 {
|
||||
compatible = "nvidia,tegra124-dfll";
|
||||
reg = <0 0x70110000 0 0x100>, /* DFLL control */
|
||||
<0 0x70110000 0 0x100>, /* I2C output control */
|
||||
<0 0x70110100 0 0x100>, /* Integrated I2C controller */
|
||||
<0 0x70110200 0 0x100>; /* Look-up table RAM */
|
||||
interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&tegra_car TEGRA124_CLK_DFLL_SOC>,
|
||||
<&tegra_car TEGRA124_CLK_DFLL_REF>,
|
||||
<&tegra_car TEGRA124_CLK_I2C5>;
|
||||
clock-names = "soc", "ref", "i2c";
|
||||
resets = <&tegra_car TEGRA124_RST_DFLL_DVCO>;
|
||||
reset-names = "dvco";
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "dfllCPU_out";
|
||||
vdd-cpu-supply = <&vdd_cpu>;
|
||||
status = "okay";
|
||||
|
||||
nvidia,sample-rate = <12500>;
|
||||
nvidia,droop-ctrl = <0x00000f00>;
|
||||
nvidia,force-mode = <1>;
|
||||
nvidia,cf = <10>;
|
||||
nvidia,ci = <0>;
|
||||
nvidia,cg = <2>;
|
||||
|
||||
nvidia,i2c-fs-rate = <400000>;
|
||||
};
|
|
@ -0,0 +1,61 @@
|
|||
* Rockchip RK3368 Clock and Reset Unit
|
||||
|
||||
The RK3368 clock controller generates and supplies clock to various
|
||||
controllers within the SoC and also implements a reset controller for SoC
|
||||
peripherals.
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: should be "rockchip,rk3368-cru"
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- #clock-cells: should be 1.
|
||||
- #reset-cells: should be 1.
|
||||
|
||||
Optional Properties:
|
||||
|
||||
- rockchip,grf: phandle to the syscon managing the "general register files"
|
||||
If missing, pll rates are not changeable, due to the missing pll lock status.
|
||||
|
||||
Each clock is assigned an identifier and client nodes can use this identifier
|
||||
to specify the clock which they consume. All available clocks are defined as
|
||||
preprocessor macros in the dt-bindings/clock/rk3368-cru.h headers and can be
|
||||
used in device tree sources. Similar macros exist for the reset sources in
|
||||
these files.
|
||||
|
||||
External clocks:
|
||||
|
||||
There are several clocks that are generated outside the SoC. It is expected
|
||||
that they are defined using standard clock bindings with following
|
||||
clock-output-names:
|
||||
- "xin24m" - crystal input - required,
|
||||
- "xin32k" - rtc clock - optional,
|
||||
- "ext_i2s" - external I2S clock - optional,
|
||||
- "ext_gmac" - external GMAC clock - optional
|
||||
- "ext_hsadc" - external HSADC clock - optional,
|
||||
- "ext_isp" - external ISP clock - optional,
|
||||
- "ext_jtag" - external JTAG clock - optional
|
||||
- "ext_vip" - external VIP clock - optional,
|
||||
- "usbotg_out" - output clock of the pll in the otg phy
|
||||
|
||||
Example: Clock controller node:
|
||||
|
||||
cru: clock-controller@ff760000 {
|
||||
compatible = "rockchip,rk3368-cru";
|
||||
reg = <0x0 0xff760000 0x0 0x1000>;
|
||||
rockchip,grf = <&grf>;
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
|
||||
Example: UART controller node that consumes the clock generated by the clock
|
||||
controller:
|
||||
|
||||
uart0: serial@10124000 {
|
||||
compatible = "snps,dw-apb-uart";
|
||||
reg = <0x10124000 0x400>;
|
||||
interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
|
||||
reg-shift = <2>;
|
||||
reg-io-width = <1>;
|
||||
clocks = <&cru SCLK_UART0>;
|
||||
};
|
64
Documentation/devicetree/bindings/clock/ux500.txt
Normal file
64
Documentation/devicetree/bindings/clock/ux500.txt
Normal file
|
@ -0,0 +1,64 @@
|
|||
Clock bindings for ST-Ericsson Ux500 clocks
|
||||
|
||||
Required properties :
|
||||
- compatible : shall contain only one of the following:
|
||||
"stericsson,u8500-clks"
|
||||
"stericsson,u8540-clks"
|
||||
"stericsson,u9540-clks"
|
||||
- reg : shall contain base register location and length for
|
||||
CLKRST1, 2, 3, 5, and 6 in an array. Note the absence of
|
||||
CLKRST4, which does not exist.
|
||||
|
||||
Required subnodes:
|
||||
- prcmu-clock: a subnode with one clock cell for PRCMU (power,
|
||||
reset, control unit) clocks. The cell indicates which PRCMU
|
||||
clock in the prcmu-clock node the consumer wants to use.
|
||||
- prcc-periph-clock: a subnode with two clock cells for
|
||||
PRCC (programmable reset- and clock controller) peripheral clocks.
|
||||
The first cell indicates which PRCC block the consumer
|
||||
wants to use, possible values are 1, 2, 3, 5, 6. The second
|
||||
cell indicates which clock inside the PRCC block it wants,
|
||||
possible values are 0 thru 31.
|
||||
- prcc-kernel-clock: a subnode with two clock cells for
|
||||
PRCC (programmable reset- and clock controller) kernel clocks
|
||||
The first cell indicates which PRCC block the consumer
|
||||
wants to use, possible values are 1, 2, 3, 5, 6. The second
|
||||
cell indicates which clock inside the PRCC block it wants,
|
||||
possible values are 0 thru 31.
|
||||
- rtc32k-clock: a subnode with zero clock cells for the 32kHz
|
||||
RTC clock.
|
||||
- smp-twd-clock: a subnode for the ARM SMP Timer Watchdog cluster
|
||||
with zero clock cells.
|
||||
|
||||
Example:
|
||||
|
||||
clocks {
|
||||
compatible = "stericsson,u8500-clks";
|
||||
/*
|
||||
* Registers for the CLKRST block on peripheral
|
||||
* groups 1, 2, 3, 5, 6,
|
||||
*/
|
||||
reg = <0x8012f000 0x1000>, <0x8011f000 0x1000>,
|
||||
<0x8000f000 0x1000>, <0xa03ff000 0x1000>,
|
||||
<0xa03cf000 0x1000>;
|
||||
|
||||
prcmu_clk: prcmu-clock {
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
prcc_pclk: prcc-periph-clock {
|
||||
#clock-cells = <2>;
|
||||
};
|
||||
|
||||
prcc_kclk: prcc-kernel-clock {
|
||||
#clock-cells = <2>;
|
||||
};
|
||||
|
||||
rtc_clk: rtc32k-clock {
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
|
||||
smp_twd_clk: smp-twd-clock {
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
};
|
|
@ -220,6 +220,13 @@ pm_domains: pm_domains0 {
|
|||
|
||||
clocks {
|
||||
compatible = "stericsson,u8500-clks";
|
||||
/*
|
||||
* Registers for the CLKRST block on peripheral
|
||||
* groups 1, 2, 3, 5, 6,
|
||||
*/
|
||||
reg = <0x8012f000 0x1000>, <0x8011f000 0x1000>,
|
||||
<0x8000f000 0x1000>, <0xa03ff000 0x1000>,
|
||||
<0xa03cf000 0x1000>;
|
||||
|
||||
prcmu_clk: prcmu-clock {
|
||||
#clock-cells = <1>;
|
||||
|
|
|
@ -241,6 +241,7 @@ axi_gates: clk@01c2005c {
|
|||
compatible = "allwinner,sun4i-a10-axi-gates-clk";
|
||||
reg = <0x01c2005c 0x4>;
|
||||
clocks = <&axi>;
|
||||
clock-indices = <0>;
|
||||
clock-output-names = "axi_dram";
|
||||
};
|
||||
|
||||
|
@ -257,17 +258,36 @@ ahb_gates: clk@01c20060 {
|
|||
compatible = "allwinner,sun4i-a10-ahb-gates-clk";
|
||||
reg = <0x01c20060 0x8>;
|
||||
clocks = <&ahb>;
|
||||
clock-indices = <0>, <1>,
|
||||
<2>, <3>,
|
||||
<4>, <5>, <6>,
|
||||
<7>, <8>, <9>,
|
||||
<10>, <11>, <12>,
|
||||
<13>, <14>, <16>,
|
||||
<17>, <18>, <20>,
|
||||
<21>, <22>, <23>,
|
||||
<24>, <25>, <26>,
|
||||
<32>, <33>, <34>,
|
||||
<35>, <36>, <37>,
|
||||
<40>, <41>, <43>,
|
||||
<44>, <45>,
|
||||
<46>, <47>,
|
||||
<50>, <52>;
|
||||
clock-output-names = "ahb_usb0", "ahb_ehci0",
|
||||
"ahb_ohci0", "ahb_ehci1", "ahb_ohci1", "ahb_ss",
|
||||
"ahb_dma", "ahb_bist", "ahb_mmc0", "ahb_mmc1",
|
||||
"ahb_mmc2", "ahb_mmc3", "ahb_ms", "ahb_nand",
|
||||
"ahb_sdram", "ahb_ace", "ahb_emac", "ahb_ts",
|
||||
"ahb_spi0", "ahb_spi1", "ahb_spi2", "ahb_spi3",
|
||||
"ahb_pata", "ahb_sata", "ahb_gps", "ahb_ve",
|
||||
"ahb_tvd", "ahb_tve0", "ahb_tve1", "ahb_lcd0",
|
||||
"ahb_lcd1", "ahb_csi0", "ahb_csi1", "ahb_hdmi",
|
||||
"ahb_de_be0", "ahb_de_be1", "ahb_de_fe0",
|
||||
"ahb_de_fe1", "ahb_mp", "ahb_mali400";
|
||||
"ahb_ohci0", "ahb_ehci1",
|
||||
"ahb_ohci1", "ahb_ss", "ahb_dma",
|
||||
"ahb_bist", "ahb_mmc0", "ahb_mmc1",
|
||||
"ahb_mmc2", "ahb_mmc3", "ahb_ms",
|
||||
"ahb_nand", "ahb_sdram", "ahb_ace",
|
||||
"ahb_emac", "ahb_ts", "ahb_spi0",
|
||||
"ahb_spi1", "ahb_spi2", "ahb_spi3",
|
||||
"ahb_pata", "ahb_sata", "ahb_gps",
|
||||
"ahb_ve", "ahb_tvd", "ahb_tve0",
|
||||
"ahb_tve1", "ahb_lcd0", "ahb_lcd1",
|
||||
"ahb_csi0", "ahb_csi1", "ahb_hdmi",
|
||||
"ahb_de_be0", "ahb_de_be1",
|
||||
"ahb_de_fe0", "ahb_de_fe1",
|
||||
"ahb_mp", "ahb_mali400";
|
||||
};
|
||||
|
||||
apb0: apb0@01c20054 {
|
||||
|
@ -283,9 +303,14 @@ apb0_gates: clk@01c20068 {
|
|||
compatible = "allwinner,sun4i-a10-apb0-gates-clk";
|
||||
reg = <0x01c20068 0x4>;
|
||||
clocks = <&apb0>;
|
||||
clock-indices = <0>, <1>,
|
||||
<2>, <3>,
|
||||
<5>, <6>,
|
||||
<7>, <10>;
|
||||
clock-output-names = "apb0_codec", "apb0_spdif",
|
||||
"apb0_ac97", "apb0_iis", "apb0_pio", "apb0_ir0",
|
||||
"apb0_ir1", "apb0_keypad";
|
||||
"apb0_ac97", "apb0_iis",
|
||||
"apb0_pio", "apb0_ir0",
|
||||
"apb0_ir1", "apb0_keypad";
|
||||
};
|
||||
|
||||
apb1: clk@01c20058 {
|
||||
|
@ -301,12 +326,22 @@ apb1_gates: clk@01c2006c {
|
|||
compatible = "allwinner,sun4i-a10-apb1-gates-clk";
|
||||
reg = <0x01c2006c 0x4>;
|
||||
clocks = <&apb1>;
|
||||
clock-indices = <0>, <1>,
|
||||
<2>, <4>,
|
||||
<5>, <6>,
|
||||
<7>, <16>,
|
||||
<17>, <18>,
|
||||
<19>, <20>,
|
||||
<21>, <22>,
|
||||
<23>;
|
||||
clock-output-names = "apb1_i2c0", "apb1_i2c1",
|
||||
"apb1_i2c2", "apb1_can", "apb1_scr",
|
||||
"apb1_ps20", "apb1_ps21", "apb1_uart0",
|
||||
"apb1_uart1", "apb1_uart2", "apb1_uart3",
|
||||
"apb1_uart4", "apb1_uart5", "apb1_uart6",
|
||||
"apb1_uart7";
|
||||
"apb1_i2c2", "apb1_can",
|
||||
"apb1_scr", "apb1_ps20",
|
||||
"apb1_ps21", "apb1_uart0",
|
||||
"apb1_uart1", "apb1_uart2",
|
||||
"apb1_uart3", "apb1_uart4",
|
||||
"apb1_uart5", "apb1_uart6",
|
||||
"apb1_uart7";
|
||||
};
|
||||
|
||||
nand_clk: clk@01c20080 {
|
||||
|
|
|
@ -85,6 +85,17 @@ ahb_gates: clk@01c20060 {
|
|||
compatible = "allwinner,sun5i-a10s-ahb-gates-clk";
|
||||
reg = <0x01c20060 0x8>;
|
||||
clocks = <&ahb>;
|
||||
clock-indices = <0>, <1>,
|
||||
<2>, <5>, <6>,
|
||||
<7>, <8>, <9>,
|
||||
<10>, <13>,
|
||||
<14>, <17>, <18>,
|
||||
<20>, <21>, <22>,
|
||||
<26>, <28>, <32>,
|
||||
<34>, <36>, <40>,
|
||||
<43>, <44>,
|
||||
<46>, <51>,
|
||||
<52>;
|
||||
clock-output-names = "ahb_usbotg", "ahb_ehci",
|
||||
"ahb_ohci", "ahb_ss", "ahb_dma",
|
||||
"ahb_bist", "ahb_mmc0", "ahb_mmc1",
|
||||
|
@ -103,6 +114,9 @@ apb0_gates: clk@01c20068 {
|
|||
compatible = "allwinner,sun5i-a10s-apb0-gates-clk";
|
||||
reg = <0x01c20068 0x4>;
|
||||
clocks = <&apb0>;
|
||||
clock-indices = <0>, <3>,
|
||||
<5>, <6>,
|
||||
<10>;
|
||||
clock-output-names = "apb0_codec", "apb0_iis",
|
||||
"apb0_pio", "apb0_ir",
|
||||
"apb0_keypad";
|
||||
|
@ -113,9 +127,14 @@ apb1_gates: clk@01c2006c {
|
|||
compatible = "allwinner,sun5i-a10s-apb1-gates-clk";
|
||||
reg = <0x01c2006c 0x4>;
|
||||
clocks = <&apb1>;
|
||||
clock-indices = <0>, <1>,
|
||||
<2>, <16>,
|
||||
<17>, <18>,
|
||||
<19>;
|
||||
clock-output-names = "apb1_i2c0", "apb1_i2c1",
|
||||
"apb1_i2c2", "apb1_uart0", "apb1_uart1",
|
||||
"apb1_uart2", "apb1_uart3";
|
||||
"apb1_i2c2", "apb1_uart0",
|
||||
"apb1_uart1", "apb1_uart2",
|
||||
"apb1_uart3";
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -104,6 +104,16 @@ ahb_gates: clk@01c20060 {
|
|||
compatible = "allwinner,sun5i-a13-ahb-gates-clk";
|
||||
reg = <0x01c20060 0x8>;
|
||||
clocks = <&ahb>;
|
||||
clock-indices = <0>, <1>,
|
||||
<2>, <5>, <6>,
|
||||
<7>, <8>, <9>,
|
||||
<10>, <13>,
|
||||
<14>, <20>,
|
||||
<21>, <22>,
|
||||
<28>, <32>, <36>,
|
||||
<40>, <44>,
|
||||
<46>, <51>,
|
||||
<52>;
|
||||
clock-output-names = "ahb_usbotg", "ahb_ehci",
|
||||
"ahb_ohci", "ahb_ss", "ahb_dma",
|
||||
"ahb_bist", "ahb_mmc0", "ahb_mmc1",
|
||||
|
@ -121,6 +131,8 @@ apb0_gates: clk@01c20068 {
|
|||
compatible = "allwinner,sun5i-a13-apb0-gates-clk";
|
||||
reg = <0x01c20068 0x4>;
|
||||
clocks = <&apb0>;
|
||||
clock-indices = <0>, <5>,
|
||||
<6>;
|
||||
clock-output-names = "apb0_codec", "apb0_pio",
|
||||
"apb0_ir";
|
||||
};
|
||||
|
@ -130,8 +142,12 @@ apb1_gates: clk@01c2006c {
|
|||
compatible = "allwinner,sun5i-a13-apb1-gates-clk";
|
||||
reg = <0x01c2006c 0x4>;
|
||||
clocks = <&apb1>;
|
||||
clock-indices = <0>, <1>,
|
||||
<2>, <17>,
|
||||
<19>;
|
||||
clock-output-names = "apb1_i2c0", "apb1_i2c1",
|
||||
"apb1_i2c2", "apb1_uart1", "apb1_uart3";
|
||||
"apb1_i2c2", "apb1_uart1",
|
||||
"apb1_uart3";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -178,6 +178,7 @@ axi_gates: clk@01c2005c {
|
|||
compatible = "allwinner,sun4i-a10-axi-gates-clk";
|
||||
reg = <0x01c2005c 0x4>;
|
||||
clocks = <&axi>;
|
||||
clock-indices = <0>;
|
||||
clock-output-names = "axi_dram";
|
||||
};
|
||||
|
||||
|
|
|
@ -252,6 +252,20 @@ ahb1_gates: clk@01c20060 {
|
|||
compatible = "allwinner,sun6i-a31-ahb1-gates-clk";
|
||||
reg = <0x01c20060 0x8>;
|
||||
clocks = <&ahb1>;
|
||||
clock-indices = <1>, <5>,
|
||||
<6>, <8>, <9>,
|
||||
<10>, <11>, <12>,
|
||||
<13>, <14>,
|
||||
<17>, <18>, <19>,
|
||||
<20>, <21>, <22>,
|
||||
<23>, <24>, <26>,
|
||||
<27>, <29>,
|
||||
<30>, <31>, <32>,
|
||||
<36>, <37>, <40>,
|
||||
<43>, <44>, <45>,
|
||||
<46>, <47>, <50>,
|
||||
<52>, <55>, <56>,
|
||||
<57>, <58>;
|
||||
clock-output-names = "ahb1_mipidsi", "ahb1_ss",
|
||||
"ahb1_dma", "ahb1_mmc0", "ahb1_mmc1",
|
||||
"ahb1_mmc2", "ahb1_mmc3", "ahb1_nand1",
|
||||
|
@ -281,6 +295,9 @@ apb1_gates: clk@01c20068 {
|
|||
compatible = "allwinner,sun6i-a31-apb1-gates-clk";
|
||||
reg = <0x01c20068 0x4>;
|
||||
clocks = <&apb1>;
|
||||
clock-indices = <0>, <4>,
|
||||
<5>, <12>,
|
||||
<13>;
|
||||
clock-output-names = "apb1_codec", "apb1_digital_mic",
|
||||
"apb1_pio", "apb1_daudio0",
|
||||
"apb1_daudio1";
|
||||
|
@ -299,6 +316,10 @@ apb2_gates: clk@01c2006c {
|
|||
compatible = "allwinner,sun6i-a31-apb2-gates-clk";
|
||||
reg = <0x01c2006c 0x4>;
|
||||
clocks = <&apb2>;
|
||||
clock-indices = <0>, <1>,
|
||||
<2>, <3>, <16>,
|
||||
<17>, <18>, <19>,
|
||||
<20>, <21>;
|
||||
clock-output-names = "apb2_i2c0", "apb2_i2c1",
|
||||
"apb2_i2c2", "apb2_i2c3",
|
||||
"apb2_uart0", "apb2_uart1",
|
||||
|
@ -384,6 +405,9 @@ usb_clk: clk@01c200cc {
|
|||
compatible = "allwinner,sun6i-a31-usb-clk";
|
||||
reg = <0x01c200cc 0x4>;
|
||||
clocks = <&osc24M>;
|
||||
clock-indices = <8>, <9>, <10>,
|
||||
<16>, <17>,
|
||||
<18>;
|
||||
clock-output-names = "usb_phy0", "usb_phy1", "usb_phy2",
|
||||
"usb_ohci0", "usb_ohci1",
|
||||
"usb_ohci2";
|
||||
|
|
|
@ -267,6 +267,19 @@ ahb_gates: clk@01c20060 {
|
|||
compatible = "allwinner,sun7i-a20-ahb-gates-clk";
|
||||
reg = <0x01c20060 0x8>;
|
||||
clocks = <&ahb>;
|
||||
clock-indices = <0>, <1>,
|
||||
<2>, <3>, <4>,
|
||||
<5>, <6>, <7>, <8>,
|
||||
<9>, <10>, <11>, <12>,
|
||||
<13>, <14>, <16>,
|
||||
<17>, <18>, <20>, <21>,
|
||||
<22>, <23>, <25>,
|
||||
<28>, <32>, <33>, <34>,
|
||||
<35>, <36>, <37>, <40>,
|
||||
<41>, <42>, <43>,
|
||||
<44>, <45>, <46>,
|
||||
<47>, <49>, <50>,
|
||||
<52>;
|
||||
clock-output-names = "ahb_usb0", "ahb_ehci0",
|
||||
"ahb_ohci0", "ahb_ehci1", "ahb_ohci1",
|
||||
"ahb_ss", "ahb_dma", "ahb_bist", "ahb_mmc0",
|
||||
|
@ -295,6 +308,10 @@ apb0_gates: clk@01c20068 {
|
|||
compatible = "allwinner,sun7i-a20-apb0-gates-clk";
|
||||
reg = <0x01c20068 0x4>;
|
||||
clocks = <&apb0>;
|
||||
clock-indices = <0>, <1>,
|
||||
<2>, <3>, <4>,
|
||||
<5>, <6>, <7>,
|
||||
<8>, <10>;
|
||||
clock-output-names = "apb0_codec", "apb0_spdif",
|
||||
"apb0_ac97", "apb0_iis0", "apb0_iis1",
|
||||
"apb0_pio", "apb0_ir0", "apb0_ir1",
|
||||
|
@ -314,6 +331,12 @@ apb1_gates: clk@01c2006c {
|
|||
compatible = "allwinner,sun7i-a20-apb1-gates-clk";
|
||||
reg = <0x01c2006c 0x4>;
|
||||
clocks = <&apb1>;
|
||||
clock-indices = <0>, <1>,
|
||||
<2>, <3>, <4>,
|
||||
<5>, <6>, <7>,
|
||||
<15>, <16>, <17>,
|
||||
<18>, <19>, <20>,
|
||||
<21>, <22>, <23>;
|
||||
clock-output-names = "apb1_i2c0", "apb1_i2c1",
|
||||
"apb1_i2c2", "apb1_i2c3", "apb1_can",
|
||||
"apb1_scr", "apb1_ps20", "apb1_ps21",
|
||||
|
|
|
@ -180,6 +180,15 @@ ahb1_gates: clk@01c20060 {
|
|||
compatible = "allwinner,sun8i-a23-ahb1-gates-clk";
|
||||
reg = <0x01c20060 0x8>;
|
||||
clocks = <&ahb1>;
|
||||
clock-indices = <1>, <6>,
|
||||
<8>, <9>, <10>,
|
||||
<13>, <14>,
|
||||
<19>, <20>,
|
||||
<21>, <24>, <26>,
|
||||
<29>, <32>, <36>,
|
||||
<40>, <44>, <46>,
|
||||
<52>, <54>,
|
||||
<57>;
|
||||
clock-output-names = "ahb1_mipidsi", "ahb1_dma",
|
||||
"ahb1_mmc0", "ahb1_mmc1", "ahb1_mmc2",
|
||||
"ahb1_nand", "ahb1_sdram",
|
||||
|
@ -196,6 +205,8 @@ apb1_gates: clk@01c20068 {
|
|||
compatible = "allwinner,sun8i-a23-apb1-gates-clk";
|
||||
reg = <0x01c20068 0x4>;
|
||||
clocks = <&apb1>;
|
||||
clock-indices = <0>, <5>,
|
||||
<12>, <13>;
|
||||
clock-output-names = "apb1_codec", "apb1_pio",
|
||||
"apb1_daudio0", "apb1_daudio1";
|
||||
};
|
||||
|
@ -213,6 +224,10 @@ apb2_gates: clk@01c2006c {
|
|||
compatible = "allwinner,sun8i-a23-apb2-gates-clk";
|
||||
reg = <0x01c2006c 0x4>;
|
||||
clocks = <&apb2>;
|
||||
clock-indices = <0>, <1>,
|
||||
<2>, <16>,
|
||||
<17>, <18>,
|
||||
<19>, <20>;
|
||||
clock-output-names = "apb2_i2c0", "apb2_i2c1",
|
||||
"apb2_i2c2", "apb2_uart0",
|
||||
"apb2_uart1", "apb2_uart2",
|
||||
|
|
|
@ -277,9 +277,12 @@ ahb0_gates: clk@06000580 {
|
|||
compatible = "allwinner,sun9i-a80-ahb0-gates-clk";
|
||||
reg = <0x06000580 0x4>;
|
||||
clocks = <&ahb0>;
|
||||
clock-indices = <0>, <1>, <3>, <5>, <8>, <12>, <13>,
|
||||
<14>, <15>, <16>, <18>, <20>, <21>,
|
||||
<22>, <23>;
|
||||
clock-indices = <0>, <1>, <3>,
|
||||
<5>, <8>, <12>,
|
||||
<13>, <14>,
|
||||
<15>, <16>, <18>,
|
||||
<20>, <21>, <22>,
|
||||
<23>;
|
||||
clock-output-names = "ahb0_fd", "ahb0_ve", "ahb0_gpu",
|
||||
"ahb0_ss", "ahb0_sd", "ahb0_nand1",
|
||||
"ahb0_nand0", "ahb0_sdram",
|
||||
|
@ -293,7 +296,10 @@ ahb1_gates: clk@06000584 {
|
|||
compatible = "allwinner,sun9i-a80-ahb1-gates-clk";
|
||||
reg = <0x06000584 0x4>;
|
||||
clocks = <&ahb1>;
|
||||
clock-indices = <0>, <1>, <17>, <21>, <22>, <23>, <24>;
|
||||
clock-indices = <0>, <1>,
|
||||
<17>, <21>,
|
||||
<22>, <23>,
|
||||
<24>;
|
||||
clock-output-names = "ahb1_usbotg", "ahb1_usbhci",
|
||||
"ahb1_gmac", "ahb1_msgbox",
|
||||
"ahb1_spinlock", "ahb1_hstimer",
|
||||
|
@ -305,8 +311,9 @@ ahb2_gates: clk@06000588 {
|
|||
compatible = "allwinner,sun9i-a80-ahb2-gates-clk";
|
||||
reg = <0x06000588 0x4>;
|
||||
clocks = <&ahb2>;
|
||||
clock-indices = <0>, <1>, <2>, <4>, <5>, <7>, <8>,
|
||||
<11>;
|
||||
clock-indices = <0>, <1>,
|
||||
<2>, <4>, <5>,
|
||||
<7>, <8>, <11>;
|
||||
clock-output-names = "ahb2_lcd0", "ahb2_lcd1",
|
||||
"ahb2_edp", "ahb2_csi", "ahb2_hdmi",
|
||||
"ahb2_de", "ahb2_mp", "ahb2_mipi_dsi";
|
||||
|
@ -317,8 +324,10 @@ apb0_gates: clk@06000590 {
|
|||
compatible = "allwinner,sun9i-a80-apb0-gates-clk";
|
||||
reg = <0x06000590 0x4>;
|
||||
clocks = <&apb0>;
|
||||
clock-indices = <1>, <5>, <11>, <12>, <13>, <15>,
|
||||
<17>, <18>, <19>;
|
||||
clock-indices = <1>, <5>,
|
||||
<11>, <12>, <13>,
|
||||
<15>, <17>, <18>,
|
||||
<19>;
|
||||
clock-output-names = "apb0_spdif", "apb0_pio",
|
||||
"apb0_ac97", "apb0_i2s0", "apb0_i2s1",
|
||||
"apb0_lradc", "apb0_gpadc", "apb0_twd",
|
||||
|
@ -330,8 +339,11 @@ apb1_gates: clk@06000594 {
|
|||
compatible = "allwinner,sun9i-a80-apb1-gates-clk";
|
||||
reg = <0x06000594 0x4>;
|
||||
clocks = <&apb1>;
|
||||
clock-indices = <0>, <1>, <2>, <3>, <4>,
|
||||
<16>, <17>, <18>, <19>, <20>, <21>;
|
||||
clock-indices = <0>, <1>,
|
||||
<2>, <3>, <4>,
|
||||
<16>, <17>,
|
||||
<18>, <19>,
|
||||
<20>, <21>;
|
||||
clock-output-names = "apb1_i2c0", "apb1_i2c1",
|
||||
"apb1_i2c2", "apb1_i2c3", "apb1_i2c4",
|
||||
"apb1_uart0", "apb1_uart1",
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
* Licensed under GPLv2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/irqchip.h>
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pm_clock.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
static struct dev_pm_domain keystone_pm_domain = {
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_fdt.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
|
|
@ -12,8 +12,7 @@ obj-y := id.o io.o control.o mux.o devices.o fb.o serial.o timer.o pm.o \
|
|||
|
||||
hwmod-common = omap_hwmod.o omap_hwmod_reset.o \
|
||||
omap_hwmod_common_data.o
|
||||
clock-common = clock.o clock_common_data.o \
|
||||
clkt_dpll.o clkt_clksel.o
|
||||
clock-common = clock.o
|
||||
secure-common = omap-smc.o omap-secure.o
|
||||
|
||||
obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(hwmod-common)
|
||||
|
@ -182,24 +181,17 @@ obj-$(CONFIG_SOC_DRA7XX) += $(clockdomain-common)
|
|||
obj-$(CONFIG_SOC_DRA7XX) += clockdomains7xx_data.o
|
||||
|
||||
# Clock framework
|
||||
obj-$(CONFIG_ARCH_OMAP2) += $(clock-common) clock2xxx.o
|
||||
obj-$(CONFIG_ARCH_OMAP2) += $(clock-common)
|
||||
obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_dpllcore.o
|
||||
obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_virt_prcm_set.o
|
||||
obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_dpll.o clkt_iclk.o
|
||||
obj-$(CONFIG_SOC_OMAP2430) += clock2430.o
|
||||
obj-$(CONFIG_ARCH_OMAP3) += $(clock-common) clock3xxx.o
|
||||
obj-$(CONFIG_ARCH_OMAP3) += clock34xx.o clkt34xx_dpll3m2.o
|
||||
obj-$(CONFIG_ARCH_OMAP3) += clock3517.o clock36xx.o
|
||||
obj-$(CONFIG_ARCH_OMAP3) += dpll3xxx.o
|
||||
obj-$(CONFIG_ARCH_OMAP3) += clkt_iclk.o
|
||||
obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_dpll.o
|
||||
obj-$(CONFIG_ARCH_OMAP3) += $(clock-common)
|
||||
obj-$(CONFIG_ARCH_OMAP3) += clkt34xx_dpll3m2.o
|
||||
obj-$(CONFIG_ARCH_OMAP4) += $(clock-common)
|
||||
obj-$(CONFIG_ARCH_OMAP4) += dpll3xxx.o dpll44xx.o
|
||||
obj-$(CONFIG_SOC_AM33XX) += $(clock-common) dpll3xxx.o
|
||||
obj-$(CONFIG_SOC_AM33XX) += $(clock-common)
|
||||
obj-$(CONFIG_SOC_OMAP5) += $(clock-common)
|
||||
obj-$(CONFIG_SOC_OMAP5) += dpll3xxx.o dpll44xx.o
|
||||
obj-$(CONFIG_SOC_DRA7XX) += $(clock-common)
|
||||
obj-$(CONFIG_SOC_DRA7XX) += dpll3xxx.o dpll44xx.o
|
||||
obj-$(CONFIG_SOC_AM43XX) += $(clock-common) dpll3xxx.o
|
||||
obj-$(CONFIG_SOC_AM43XX) += $(clock-common)
|
||||
|
||||
# OMAP2 clock rate set data (old "OPP" data)
|
||||
obj-$(CONFIG_SOC_OMAP2420) += opp2420_data.o
|
||||
|
|
|
@ -23,12 +23,13 @@
|
|||
|
||||
#include "clock.h"
|
||||
#include "clock3xxx.h"
|
||||
#include "clock34xx.h"
|
||||
#include "sdrc.h"
|
||||
#include "sram.h"
|
||||
|
||||
#define CYCLES_PER_MHZ 1000000
|
||||
|
||||
struct clk *sdrc_ick_p, *arm_fck_p;
|
||||
|
||||
/*
|
||||
* CORE DPLL (DPLL3) M2 divider rate programming functions
|
||||
*
|
||||
|
@ -60,12 +61,14 @@ int omap3_core_dpll_m2_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
if (!clk || !rate)
|
||||
return -EINVAL;
|
||||
|
||||
validrate = omap2_clksel_round_rate_div(clk, rate, &new_div);
|
||||
new_div = DIV_ROUND_UP(parent_rate, rate);
|
||||
validrate = parent_rate / new_div;
|
||||
|
||||
if (validrate != rate)
|
||||
return -EINVAL;
|
||||
|
||||
sdrcrate = __clk_get_rate(sdrc_ick_p);
|
||||
clkrate = __clk_get_rate(hw->clk);
|
||||
sdrcrate = clk_get_rate(sdrc_ick_p);
|
||||
clkrate = clk_hw_get_rate(hw);
|
||||
if (rate > clkrate)
|
||||
sdrcrate <<= ((rate / clkrate) >> 1);
|
||||
else
|
||||
|
@ -83,7 +86,7 @@ int omap3_core_dpll_m2_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
/*
|
||||
* XXX This only needs to be done when the CPU frequency changes
|
||||
*/
|
||||
_mpurate = __clk_get_rate(arm_fck_p) / CYCLES_PER_MHZ;
|
||||
_mpurate = clk_get_rate(arm_fck_p) / CYCLES_PER_MHZ;
|
||||
c = (_mpurate << SDRC_MPURATE_SCALE) >> SDRC_MPURATE_BASE_SHIFT;
|
||||
c += 1; /* for safety */
|
||||
c *= SDRC_MPURATE_LOOPS;
|
||||
|
|
|
@ -1,466 +0,0 @@
|
|||
/*
|
||||
* clkt_clksel.c - OMAP2/3/4 clksel clock functions
|
||||
*
|
||||
* Copyright (C) 2005-2008 Texas Instruments, Inc.
|
||||
* Copyright (C) 2004-2010 Nokia Corporation
|
||||
*
|
||||
* Contacts:
|
||||
* Richard Woodruff <r-woodruff2@ti.com>
|
||||
* Paul Walmsley
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*
|
||||
* clksel clocks are clocks that do not have a fixed parent, or that
|
||||
* can divide their parent's rate, or possibly both at the same time, based
|
||||
* on the contents of a hardware register bitfield.
|
||||
*
|
||||
* All of the various mux and divider settings can be encoded into
|
||||
* struct clksel* data structures, and then these can be autogenerated
|
||||
* from some hardware database for each new chip generation. This
|
||||
* should avoid the need to write, review, and validate a lot of new
|
||||
* clock code for each new chip, since it can be exported from the SoC
|
||||
* design flow. This is now done on OMAP4.
|
||||
*
|
||||
* The fusion of mux and divider clocks is a software creation. In
|
||||
* hardware reality, the multiplexer (parent selection) and the
|
||||
* divider exist separately. XXX At some point these clksel clocks
|
||||
* should be split into "divider" clocks and "mux" clocks to better
|
||||
* match the hardware.
|
||||
*
|
||||
* (The name "clksel" comes from the name of the corresponding
|
||||
* register field in the OMAP2/3 family of SoCs.)
|
||||
*
|
||||
* XXX Currently these clocks are only used in the OMAP2/3/4 code, but
|
||||
* many of the OMAP1 clocks should be convertible to use this
|
||||
* mechanism.
|
||||
*/
|
||||
#undef DEBUG
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/bug.h>
|
||||
|
||||
#include "clock.h"
|
||||
|
||||
/* Private functions */
|
||||
|
||||
/**
|
||||
* _get_clksel_by_parent() - return clksel struct for a given clk & parent
|
||||
* @clk: OMAP struct clk ptr to inspect
|
||||
* @src_clk: OMAP struct clk ptr of the parent clk to search for
|
||||
*
|
||||
* Scan the struct clksel array associated with the clock to find
|
||||
* the element associated with the supplied parent clock address.
|
||||
* Returns a pointer to the struct clksel on success or NULL on error.
|
||||
*/
|
||||
static const struct clksel *_get_clksel_by_parent(struct clk_hw_omap *clk,
|
||||
struct clk *src_clk)
|
||||
{
|
||||
const struct clksel *clks;
|
||||
|
||||
if (!src_clk)
|
||||
return NULL;
|
||||
|
||||
for (clks = clk->clksel; clks->parent; clks++)
|
||||
if (clks->parent == src_clk)
|
||||
break; /* Found the requested parent */
|
||||
|
||||
if (!clks->parent) {
|
||||
/* This indicates a data problem */
|
||||
WARN(1, "clock: %s: could not find parent clock %s in clksel array\n",
|
||||
__clk_get_name(clk->hw.clk), __clk_get_name(src_clk));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return clks;
|
||||
}
|
||||
|
||||
/**
|
||||
* _write_clksel_reg() - program a clock's clksel register in hardware
|
||||
* @clk: struct clk * to program
|
||||
* @v: clksel bitfield value to program (with LSB at bit 0)
|
||||
*
|
||||
* Shift the clksel register bitfield value @v to its appropriate
|
||||
* location in the clksel register and write it in. This function
|
||||
* will ensure that the write to the clksel_reg reaches its
|
||||
* destination before returning -- important since PRM and CM register
|
||||
* accesses can be quite slow compared to ARM cycles -- but does not
|
||||
* take into account any time the hardware might take to switch the
|
||||
* clock source.
|
||||
*/
|
||||
static void _write_clksel_reg(struct clk_hw_omap *clk, u32 field_val)
|
||||
{
|
||||
u32 v;
|
||||
|
||||
v = omap2_clk_readl(clk, clk->clksel_reg);
|
||||
v &= ~clk->clksel_mask;
|
||||
v |= field_val << __ffs(clk->clksel_mask);
|
||||
omap2_clk_writel(v, clk, clk->clksel_reg);
|
||||
|
||||
v = omap2_clk_readl(clk, clk->clksel_reg); /* OCP barrier */
|
||||
}
|
||||
|
||||
/**
|
||||
* _clksel_to_divisor() - turn clksel field value into integer divider
|
||||
* @clk: OMAP struct clk to use
|
||||
* @field_val: register field value to find
|
||||
*
|
||||
* Given a struct clk of a rate-selectable clksel clock, and a register field
|
||||
* value to search for, find the corresponding clock divisor. The register
|
||||
* field value should be pre-masked and shifted down so the LSB is at bit 0
|
||||
* before calling. Returns 0 on error or returns the actual integer divisor
|
||||
* upon success.
|
||||
*/
|
||||
static u32 _clksel_to_divisor(struct clk_hw_omap *clk, u32 field_val)
|
||||
{
|
||||
const struct clksel *clks;
|
||||
const struct clksel_rate *clkr;
|
||||
struct clk *parent;
|
||||
|
||||
parent = __clk_get_parent(clk->hw.clk);
|
||||
|
||||
clks = _get_clksel_by_parent(clk, parent);
|
||||
if (!clks)
|
||||
return 0;
|
||||
|
||||
for (clkr = clks->rates; clkr->div; clkr++) {
|
||||
if (!(clkr->flags & cpu_mask))
|
||||
continue;
|
||||
|
||||
if (clkr->val == field_val)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!clkr->div) {
|
||||
/* This indicates a data error */
|
||||
WARN(1, "clock: %s: could not find fieldval %d for parent %s\n",
|
||||
__clk_get_name(clk->hw.clk), field_val,
|
||||
__clk_get_name(parent));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return clkr->div;
|
||||
}
|
||||
|
||||
/**
|
||||
* _divisor_to_clksel() - turn clksel integer divisor into a field value
|
||||
* @clk: OMAP struct clk to use
|
||||
* @div: integer divisor to search for
|
||||
*
|
||||
* Given a struct clk of a rate-selectable clksel clock, and a clock
|
||||
* divisor, find the corresponding register field value. Returns the
|
||||
* register field value _before_ left-shifting (i.e., LSB is at bit
|
||||
* 0); or returns 0xFFFFFFFF (~0) upon error.
|
||||
*/
|
||||
static u32 _divisor_to_clksel(struct clk_hw_omap *clk, u32 div)
|
||||
{
|
||||
const struct clksel *clks;
|
||||
const struct clksel_rate *clkr;
|
||||
struct clk *parent;
|
||||
|
||||
/* should never happen */
|
||||
WARN_ON(div == 0);
|
||||
|
||||
parent = __clk_get_parent(clk->hw.clk);
|
||||
clks = _get_clksel_by_parent(clk, parent);
|
||||
if (!clks)
|
||||
return ~0;
|
||||
|
||||
for (clkr = clks->rates; clkr->div; clkr++) {
|
||||
if (!(clkr->flags & cpu_mask))
|
||||
continue;
|
||||
|
||||
if (clkr->div == div)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!clkr->div) {
|
||||
pr_err("clock: %s: could not find divisor %d for parent %s\n",
|
||||
__clk_get_name(clk->hw.clk), div,
|
||||
__clk_get_name(parent));
|
||||
return ~0;
|
||||
}
|
||||
|
||||
return clkr->val;
|
||||
}
|
||||
|
||||
/**
|
||||
* _read_divisor() - get current divisor applied to parent clock (from hdwr)
|
||||
* @clk: OMAP struct clk to use.
|
||||
*
|
||||
* Read the current divisor register value for @clk that is programmed
|
||||
* into the hardware, convert it into the actual divisor value, and
|
||||
* return it; or return 0 on error.
|
||||
*/
|
||||
static u32 _read_divisor(struct clk_hw_omap *clk)
|
||||
{
|
||||
u32 v;
|
||||
|
||||
if (!clk->clksel || !clk->clksel_mask)
|
||||
return 0;
|
||||
|
||||
v = omap2_clk_readl(clk, clk->clksel_reg);
|
||||
v &= clk->clksel_mask;
|
||||
v >>= __ffs(clk->clksel_mask);
|
||||
|
||||
return _clksel_to_divisor(clk, v);
|
||||
}
|
||||
|
||||
/* Public functions */
|
||||
|
||||
/**
|
||||
* omap2_clksel_round_rate_div() - find divisor for the given clock and rate
|
||||
* @clk: OMAP struct clk to use
|
||||
* @target_rate: desired clock rate
|
||||
* @new_div: ptr to where we should store the divisor
|
||||
*
|
||||
* Finds 'best' divider value in an array based on the source and target
|
||||
* rates. The divider array must be sorted with smallest divider first.
|
||||
* This function is also used by the DPLL3 M2 divider code.
|
||||
*
|
||||
* Returns the rounded clock rate or returns 0xffffffff on error.
|
||||
*/
|
||||
u32 omap2_clksel_round_rate_div(struct clk_hw_omap *clk,
|
||||
unsigned long target_rate,
|
||||
u32 *new_div)
|
||||
{
|
||||
unsigned long test_rate;
|
||||
const struct clksel *clks;
|
||||
const struct clksel_rate *clkr;
|
||||
u32 last_div = 0;
|
||||
struct clk *parent;
|
||||
unsigned long parent_rate;
|
||||
const char *clk_name;
|
||||
|
||||
parent = __clk_get_parent(clk->hw.clk);
|
||||
clk_name = __clk_get_name(clk->hw.clk);
|
||||
parent_rate = __clk_get_rate(parent);
|
||||
|
||||
if (!clk->clksel || !clk->clksel_mask)
|
||||
return ~0;
|
||||
|
||||
pr_debug("clock: clksel_round_rate_div: %s target_rate %ld\n",
|
||||
clk_name, target_rate);
|
||||
|
||||
*new_div = 1;
|
||||
|
||||
clks = _get_clksel_by_parent(clk, parent);
|
||||
if (!clks)
|
||||
return ~0;
|
||||
|
||||
for (clkr = clks->rates; clkr->div; clkr++) {
|
||||
if (!(clkr->flags & cpu_mask))
|
||||
continue;
|
||||
|
||||
/* Sanity check */
|
||||
if (clkr->div <= last_div)
|
||||
pr_err("clock: %s: clksel_rate table not sorted\n",
|
||||
clk_name);
|
||||
|
||||
last_div = clkr->div;
|
||||
|
||||
test_rate = parent_rate / clkr->div;
|
||||
|
||||
if (test_rate <= target_rate)
|
||||
break; /* found it */
|
||||
}
|
||||
|
||||
if (!clkr->div) {
|
||||
pr_err("clock: %s: could not find divisor for target rate %ld for parent %s\n",
|
||||
clk_name, target_rate, __clk_get_name(parent));
|
||||
return ~0;
|
||||
}
|
||||
|
||||
*new_div = clkr->div;
|
||||
|
||||
pr_debug("clock: new_div = %d, new_rate = %ld\n", *new_div,
|
||||
(parent_rate / clkr->div));
|
||||
|
||||
return parent_rate / clkr->div;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clocktype interface functions to the OMAP clock code
|
||||
* (i.e., those used in struct clk field function pointers, etc.)
|
||||
*/
|
||||
|
||||
/**
|
||||
* omap2_clksel_find_parent_index() - return the array index of the current
|
||||
* hardware parent of @hw
|
||||
* @hw: struct clk_hw * to find the current hardware parent of
|
||||
*
|
||||
* Given a struct clk_hw pointer @hw to the 'hw' member of a struct
|
||||
* clk_hw_omap record representing a source-selectable hardware clock,
|
||||
* read the hardware register and determine what its parent is
|
||||
* currently set to. Intended to be called only by the common clock
|
||||
* framework struct clk_hw_ops.get_parent function pointer. Return
|
||||
* the array index of this parent clock upon success -- there is no
|
||||
* way to return an error, so if we encounter an error, just WARN()
|
||||
* and pretend that we know that we're doing.
|
||||
*/
|
||||
u8 omap2_clksel_find_parent_index(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
|
||||
const struct clksel *clks;
|
||||
const struct clksel_rate *clkr;
|
||||
u32 r, found = 0;
|
||||
struct clk *parent;
|
||||
const char *clk_name;
|
||||
int ret = 0, f = 0;
|
||||
|
||||
parent = __clk_get_parent(hw->clk);
|
||||
clk_name = __clk_get_name(hw->clk);
|
||||
|
||||
/* XXX should be able to return an error */
|
||||
WARN((!clk->clksel || !clk->clksel_mask),
|
||||
"clock: %s: attempt to call on a non-clksel clock", clk_name);
|
||||
|
||||
r = omap2_clk_readl(clk, clk->clksel_reg) & clk->clksel_mask;
|
||||
r >>= __ffs(clk->clksel_mask);
|
||||
|
||||
for (clks = clk->clksel; clks->parent && !found; clks++) {
|
||||
for (clkr = clks->rates; clkr->div && !found; clkr++) {
|
||||
if (!(clkr->flags & cpu_mask))
|
||||
continue;
|
||||
|
||||
if (clkr->val == r) {
|
||||
found = 1;
|
||||
ret = f;
|
||||
}
|
||||
}
|
||||
f++;
|
||||
}
|
||||
|
||||
/* This indicates a data error */
|
||||
WARN(!found, "clock: %s: init parent: could not find regval %0x\n",
|
||||
clk_name, r);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* omap2_clksel_recalc() - function ptr to pass via struct clk .recalc field
|
||||
* @clk: struct clk *
|
||||
*
|
||||
* This function is intended to be called only by the clock framework.
|
||||
* Each clksel clock should have its struct clk .recalc field set to this
|
||||
* function. Returns the clock's current rate, based on its parent's rate
|
||||
* and its current divisor setting in the hardware.
|
||||
*/
|
||||
unsigned long omap2_clksel_recalc(struct clk_hw *hw, unsigned long parent_rate)
|
||||
{
|
||||
unsigned long rate;
|
||||
u32 div = 0;
|
||||
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
|
||||
|
||||
if (!parent_rate)
|
||||
return 0;
|
||||
|
||||
div = _read_divisor(clk);
|
||||
if (!div)
|
||||
rate = parent_rate;
|
||||
else
|
||||
rate = parent_rate / div;
|
||||
|
||||
pr_debug("%s: recalc'd %s's rate to %lu (div %d)\n", __func__,
|
||||
__clk_get_name(hw->clk), rate, div);
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
/**
|
||||
* omap2_clksel_round_rate() - find rounded rate for the given clock and rate
|
||||
* @clk: OMAP struct clk to use
|
||||
* @target_rate: desired clock rate
|
||||
*
|
||||
* This function is intended to be called only by the clock framework.
|
||||
* Finds best target rate based on the source clock and possible dividers.
|
||||
* rates. The divider array must be sorted with smallest divider first.
|
||||
*
|
||||
* Returns the rounded clock rate or returns 0xffffffff on error.
|
||||
*/
|
||||
long omap2_clksel_round_rate(struct clk_hw *hw, unsigned long target_rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
|
||||
u32 new_div;
|
||||
|
||||
return omap2_clksel_round_rate_div(clk, target_rate, &new_div);
|
||||
}
|
||||
|
||||
/**
|
||||
* omap2_clksel_set_rate() - program clock rate in hardware
|
||||
* @clk: struct clk * to program rate
|
||||
* @rate: target rate to program
|
||||
*
|
||||
* This function is intended to be called only by the clock framework.
|
||||
* Program @clk's rate to @rate in the hardware. The clock can be
|
||||
* either enabled or disabled when this happens, although if the clock
|
||||
* is enabled, some downstream devices may glitch or behave
|
||||
* unpredictably when the clock rate is changed - this depends on the
|
||||
* hardware. This function does not currently check the usecount of
|
||||
* the clock, so if multiple drivers are using the clock, and the rate
|
||||
* is changed, they will all be affected without any notification.
|
||||
* Returns -EINVAL upon error, or 0 upon success.
|
||||
*/
|
||||
int omap2_clksel_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
|
||||
u32 field_val, validrate, new_div = 0;
|
||||
|
||||
if (!clk->clksel || !clk->clksel_mask)
|
||||
return -EINVAL;
|
||||
|
||||
validrate = omap2_clksel_round_rate_div(clk, rate, &new_div);
|
||||
if (validrate != rate)
|
||||
return -EINVAL;
|
||||
|
||||
field_val = _divisor_to_clksel(clk, new_div);
|
||||
if (field_val == ~0)
|
||||
return -EINVAL;
|
||||
|
||||
_write_clksel_reg(clk, field_val);
|
||||
|
||||
pr_debug("clock: %s: set rate to %ld\n", __clk_get_name(hw->clk),
|
||||
__clk_get_rate(hw->clk));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clksel parent setting function - not passed in struct clk function
|
||||
* pointer - instead, the OMAP clock code currently assumes that any
|
||||
* parent-setting clock is a clksel clock, and calls
|
||||
* omap2_clksel_set_parent() by default
|
||||
*/
|
||||
|
||||
/**
|
||||
* omap2_clksel_set_parent() - change a clock's parent clock
|
||||
* @clk: struct clk * of the child clock
|
||||
* @new_parent: struct clk * of the new parent clock
|
||||
*
|
||||
* This function is intended to be called only by the clock framework.
|
||||
* Change the parent clock of clock @clk to @new_parent. This is
|
||||
* intended to be used while @clk is disabled. This function does not
|
||||
* currently check the usecount of the clock, so if multiple drivers
|
||||
* are using the clock, and the parent is changed, they will all be
|
||||
* affected without any notification. Returns -EINVAL upon error, or
|
||||
* 0 upon success.
|
||||
*/
|
||||
int omap2_clksel_set_parent(struct clk_hw *hw, u8 field_val)
|
||||
{
|
||||
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
|
||||
|
||||
if (!clk->clksel || !clk->clksel_mask)
|
||||
return -EINVAL;
|
||||
|
||||
_write_clksel_reg(clk, field_val);
|
||||
return 0;
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
* OMAP2/3 interface clock control
|
||||
*
|
||||
* Copyright (C) 2011 Nokia Corporation
|
||||
* Paul Walmsley
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#undef DEBUG
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include "clock.h"
|
||||
|
||||
/* Register offsets */
|
||||
#define CM_AUTOIDLE 0x30
|
||||
#define CM_ICLKEN 0x10
|
||||
|
||||
/* Private functions */
|
||||
|
||||
/* XXX */
|
||||
void omap2_clkt_iclk_allow_idle(struct clk_hw_omap *clk)
|
||||
{
|
||||
u32 v;
|
||||
void __iomem *r;
|
||||
|
||||
r = (__force void __iomem *)
|
||||
((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN));
|
||||
|
||||
v = omap2_clk_readl(clk, r);
|
||||
v |= (1 << clk->enable_bit);
|
||||
omap2_clk_writel(v, clk, r);
|
||||
}
|
||||
|
||||
/* XXX */
|
||||
void omap2_clkt_iclk_deny_idle(struct clk_hw_omap *clk)
|
||||
{
|
||||
u32 v;
|
||||
void __iomem *r;
|
||||
|
||||
r = (__force void __iomem *)
|
||||
((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN));
|
||||
|
||||
v = omap2_clk_readl(clk, r);
|
||||
v &= ~(1 << clk->enable_bit);
|
||||
omap2_clk_writel(v, clk, r);
|
||||
}
|
||||
|
||||
/* Public data */
|
||||
|
||||
const struct clk_hw_omap_ops clkhwops_iclk = {
|
||||
.allow_idle = omap2_clkt_iclk_allow_idle,
|
||||
.deny_idle = omap2_clkt_iclk_deny_idle,
|
||||
};
|
||||
|
||||
const struct clk_hw_omap_ops clkhwops_iclk_wait = {
|
||||
.allow_idle = omap2_clkt_iclk_allow_idle,
|
||||
.deny_idle = omap2_clkt_iclk_deny_idle,
|
||||
.find_idlest = omap2_clk_dflt_find_idlest,
|
||||
.find_companion = omap2_clk_dflt_find_companion,
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -20,12 +20,11 @@
|
|||
#include <linux/errno.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/bootmem.h>
|
||||
#include <asm/cpu.h>
|
||||
|
||||
#include <trace/events/power.h>
|
||||
|
@ -40,19 +39,8 @@
|
|||
#include "cm-regbits-34xx.h"
|
||||
#include "common.h"
|
||||
|
||||
/*
|
||||
* MAX_MODULE_ENABLE_WAIT: maximum of number of microseconds to wait
|
||||
* for a module to indicate that it is no longer in idle
|
||||
*/
|
||||
#define MAX_MODULE_ENABLE_WAIT 100000
|
||||
|
||||
u16 cpu_mask;
|
||||
|
||||
/*
|
||||
* Clock features setup. Used instead of CPU type checks.
|
||||
*/
|
||||
struct ti_clk_features ti_clk_features;
|
||||
|
||||
/* DPLL valid Fint frequency band limits - from 34xx TRM Section 4.7.6.2 */
|
||||
#define OMAP3430_DPLL_FINT_BAND1_MIN 750000
|
||||
#define OMAP3430_DPLL_FINT_BAND1_MAX 2100000
|
||||
|
@ -66,119 +54,24 @@ struct ti_clk_features ti_clk_features;
|
|||
#define OMAP3PLUS_DPLL_FINT_MIN 32000
|
||||
#define OMAP3PLUS_DPLL_FINT_MAX 52000000
|
||||
|
||||
/*
|
||||
* clkdm_control: if true, then when a clock is enabled in the
|
||||
* hardware, its clockdomain will first be enabled; and when a clock
|
||||
* is disabled in the hardware, its clockdomain will be disabled
|
||||
* afterwards.
|
||||
*/
|
||||
static bool clkdm_control = true;
|
||||
|
||||
static LIST_HEAD(clk_hw_omap_clocks);
|
||||
|
||||
struct clk_iomap {
|
||||
struct regmap *regmap;
|
||||
void __iomem *mem;
|
||||
};
|
||||
|
||||
static struct clk_iomap *clk_memmaps[CLK_MAX_MEMMAPS];
|
||||
|
||||
static void clk_memmap_writel(u32 val, void __iomem *reg)
|
||||
{
|
||||
struct clk_omap_reg *r = (struct clk_omap_reg *)®
|
||||
struct clk_iomap *io = clk_memmaps[r->index];
|
||||
|
||||
if (io->regmap)
|
||||
regmap_write(io->regmap, r->offset, val);
|
||||
else
|
||||
writel_relaxed(val, io->mem + r->offset);
|
||||
}
|
||||
|
||||
static u32 clk_memmap_readl(void __iomem *reg)
|
||||
{
|
||||
u32 val;
|
||||
struct clk_omap_reg *r = (struct clk_omap_reg *)®
|
||||
struct clk_iomap *io = clk_memmaps[r->index];
|
||||
|
||||
if (io->regmap)
|
||||
regmap_read(io->regmap, r->offset, &val);
|
||||
else
|
||||
val = readl_relaxed(io->mem + r->offset);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void omap2_clk_writel(u32 val, struct clk_hw_omap *clk, void __iomem *reg)
|
||||
{
|
||||
if (WARN_ON_ONCE(!(clk->flags & MEMMAP_ADDRESSING)))
|
||||
writel_relaxed(val, reg);
|
||||
else
|
||||
clk_memmap_writel(val, reg);
|
||||
}
|
||||
|
||||
u32 omap2_clk_readl(struct clk_hw_omap *clk, void __iomem *reg)
|
||||
{
|
||||
if (WARN_ON_ONCE(!(clk->flags & MEMMAP_ADDRESSING)))
|
||||
return readl_relaxed(reg);
|
||||
else
|
||||
return clk_memmap_readl(reg);
|
||||
}
|
||||
|
||||
static struct ti_clk_ll_ops omap_clk_ll_ops = {
|
||||
.clk_readl = clk_memmap_readl,
|
||||
.clk_writel = clk_memmap_writel,
|
||||
.clkdm_clk_enable = clkdm_clk_enable,
|
||||
.clkdm_clk_disable = clkdm_clk_disable,
|
||||
.cm_wait_module_ready = omap_cm_wait_module_ready,
|
||||
.cm_split_idlest_reg = cm_split_idlest_reg,
|
||||
};
|
||||
|
||||
/**
|
||||
* omap2_clk_provider_init - initialize a clock provider
|
||||
* @match_table: DT device table to match for devices to init
|
||||
* @np: device node pointer for the this clock provider
|
||||
* @index: index for the clock provider
|
||||
+ @syscon: syscon regmap pointer
|
||||
* @mem: iomem pointer for the clock provider memory area, only used if
|
||||
* syscon is not provided
|
||||
* omap2_clk_setup_ll_ops - setup clock driver low-level ops
|
||||
*
|
||||
* Initializes a clock provider module (CM/PRM etc.), registering
|
||||
* the memory mapping at specified index and initializing the
|
||||
* low level driver infrastructure. Returns 0 in success.
|
||||
* Sets up clock driver low-level platform ops. These are needed
|
||||
* for register accesses and various other misc platform operations.
|
||||
* Returns 0 on success, -EBUSY if low level ops have been registered
|
||||
* already.
|
||||
*/
|
||||
int __init omap2_clk_provider_init(struct device_node *np, int index,
|
||||
struct regmap *syscon, void __iomem *mem)
|
||||
int __init omap2_clk_setup_ll_ops(void)
|
||||
{
|
||||
struct clk_iomap *io;
|
||||
|
||||
ti_clk_ll_ops = &omap_clk_ll_ops;
|
||||
|
||||
io = kzalloc(sizeof(*io), GFP_KERNEL);
|
||||
|
||||
io->regmap = syscon;
|
||||
io->mem = mem;
|
||||
|
||||
clk_memmaps[index] = io;
|
||||
|
||||
ti_dt_clk_init_provider(np, index);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* omap2_clk_legacy_provider_init - initialize a legacy clock provider
|
||||
* @index: index for the clock provider
|
||||
* @mem: iomem pointer for the clock provider memory area
|
||||
*
|
||||
* Initializes a legacy clock provider memory mapping.
|
||||
*/
|
||||
void __init omap2_clk_legacy_provider_init(int index, void __iomem *mem)
|
||||
{
|
||||
struct clk_iomap *io;
|
||||
|
||||
ti_clk_ll_ops = &omap_clk_ll_ops;
|
||||
|
||||
io = memblock_virt_alloc(sizeof(*io), 0);
|
||||
|
||||
io->mem = mem;
|
||||
|
||||
clk_memmaps[index] = io;
|
||||
return ti_clk_setup_ll_ops(&omap_clk_ll_ops);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -187,77 +80,6 @@ void __init omap2_clk_legacy_provider_init(int index, void __iomem *mem)
|
|||
|
||||
/* Private functions */
|
||||
|
||||
|
||||
/**
|
||||
* _wait_idlest_generic - wait for a module to leave the idle state
|
||||
* @clk: module clock to wait for (needed for register offsets)
|
||||
* @reg: virtual address of module IDLEST register
|
||||
* @mask: value to mask against to determine if the module is active
|
||||
* @idlest: idle state indicator (0 or 1) for the clock
|
||||
* @name: name of the clock (for printk)
|
||||
*
|
||||
* Wait for a module to leave idle, where its idle-status register is
|
||||
* not inside the CM module. Returns 1 if the module left idle
|
||||
* promptly, or 0 if the module did not leave idle before the timeout
|
||||
* elapsed. XXX Deprecated - should be moved into drivers for the
|
||||
* individual IP block that the IDLEST register exists in.
|
||||
*/
|
||||
static int _wait_idlest_generic(struct clk_hw_omap *clk, void __iomem *reg,
|
||||
u32 mask, u8 idlest, const char *name)
|
||||
{
|
||||
int i = 0, ena = 0;
|
||||
|
||||
ena = (idlest) ? 0 : mask;
|
||||
|
||||
omap_test_timeout(((omap2_clk_readl(clk, reg) & mask) == ena),
|
||||
MAX_MODULE_ENABLE_WAIT, i);
|
||||
|
||||
if (i < MAX_MODULE_ENABLE_WAIT)
|
||||
pr_debug("omap clock: module associated with clock %s ready after %d loops\n",
|
||||
name, i);
|
||||
else
|
||||
pr_err("omap clock: module associated with clock %s didn't enable in %d tries\n",
|
||||
name, MAX_MODULE_ENABLE_WAIT);
|
||||
|
||||
return (i < MAX_MODULE_ENABLE_WAIT) ? 1 : 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* _omap2_module_wait_ready - wait for an OMAP module to leave IDLE
|
||||
* @clk: struct clk * belonging to the module
|
||||
*
|
||||
* If the necessary clocks for the OMAP hardware IP block that
|
||||
* corresponds to clock @clk are enabled, then wait for the module to
|
||||
* indicate readiness (i.e., to leave IDLE). This code does not
|
||||
* belong in the clock code and will be moved in the medium term to
|
||||
* module-dependent code. No return value.
|
||||
*/
|
||||
static void _omap2_module_wait_ready(struct clk_hw_omap *clk)
|
||||
{
|
||||
void __iomem *companion_reg, *idlest_reg;
|
||||
u8 other_bit, idlest_bit, idlest_val, idlest_reg_id;
|
||||
s16 prcm_mod;
|
||||
int r;
|
||||
|
||||
/* Not all modules have multiple clocks that their IDLEST depends on */
|
||||
if (clk->ops->find_companion) {
|
||||
clk->ops->find_companion(clk, &companion_reg, &other_bit);
|
||||
if (!(omap2_clk_readl(clk, companion_reg) & (1 << other_bit)))
|
||||
return;
|
||||
}
|
||||
|
||||
clk->ops->find_idlest(clk, &idlest_reg, &idlest_bit, &idlest_val);
|
||||
r = cm_split_idlest_reg(idlest_reg, &prcm_mod, &idlest_reg_id);
|
||||
if (r) {
|
||||
/* IDLEST register not in the CM module */
|
||||
_wait_idlest_generic(clk, idlest_reg, (1 << idlest_bit),
|
||||
idlest_val, __clk_get_name(clk->hw.clk));
|
||||
} else {
|
||||
omap_cm_wait_module_ready(0, prcm_mod, idlest_reg_id,
|
||||
idlest_bit);
|
||||
};
|
||||
}
|
||||
|
||||
/* Public functions */
|
||||
|
||||
/**
|
||||
|
@ -290,279 +112,6 @@ void omap2_init_clk_clkdm(struct clk_hw *hw)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* omap2_clk_disable_clkdm_control - disable clkdm control on clk enable/disable
|
||||
*
|
||||
* Prevent the OMAP clock code from calling into the clockdomain code
|
||||
* when a hardware clock in that clockdomain is enabled or disabled.
|
||||
* Intended to be called at init time from omap*_clk_init(). No
|
||||
* return value.
|
||||
*/
|
||||
void __init omap2_clk_disable_clkdm_control(void)
|
||||
{
|
||||
clkdm_control = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* omap2_clk_dflt_find_companion - find companion clock to @clk
|
||||
* @clk: struct clk * to find the companion clock of
|
||||
* @other_reg: void __iomem ** to return the companion clock CM_*CLKEN va in
|
||||
* @other_bit: u8 ** to return the companion clock bit shift in
|
||||
*
|
||||
* Note: We don't need special code here for INVERT_ENABLE for the
|
||||
* time being since INVERT_ENABLE only applies to clocks enabled by
|
||||
* CM_CLKEN_PLL
|
||||
*
|
||||
* Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes it's
|
||||
* just a matter of XORing the bits.
|
||||
*
|
||||
* Some clocks don't have companion clocks. For example, modules with
|
||||
* only an interface clock (such as MAILBOXES) don't have a companion
|
||||
* clock. Right now, this code relies on the hardware exporting a bit
|
||||
* in the correct companion register that indicates that the
|
||||
* nonexistent 'companion clock' is active. Future patches will
|
||||
* associate this type of code with per-module data structures to
|
||||
* avoid this issue, and remove the casts. No return value.
|
||||
*/
|
||||
void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk,
|
||||
void __iomem **other_reg, u8 *other_bit)
|
||||
{
|
||||
u32 r;
|
||||
|
||||
/*
|
||||
* Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes
|
||||
* it's just a matter of XORing the bits.
|
||||
*/
|
||||
r = ((__force u32)clk->enable_reg ^ (CM_FCLKEN ^ CM_ICLKEN));
|
||||
|
||||
*other_reg = (__force void __iomem *)r;
|
||||
*other_bit = clk->enable_bit;
|
||||
}
|
||||
|
||||
/**
|
||||
* omap2_clk_dflt_find_idlest - find CM_IDLEST reg va, bit shift for @clk
|
||||
* @clk: struct clk * to find IDLEST info for
|
||||
* @idlest_reg: void __iomem ** to return the CM_IDLEST va in
|
||||
* @idlest_bit: u8 * to return the CM_IDLEST bit shift in
|
||||
* @idlest_val: u8 * to return the idle status indicator
|
||||
*
|
||||
* Return the CM_IDLEST register address and bit shift corresponding
|
||||
* to the module that "owns" this clock. This default code assumes
|
||||
* that the CM_IDLEST bit shift is the CM_*CLKEN bit shift, and that
|
||||
* the IDLEST register address ID corresponds to the CM_*CLKEN
|
||||
* register address ID (e.g., that CM_FCLKEN2 corresponds to
|
||||
* CM_IDLEST2). This is not true for all modules. No return value.
|
||||
*/
|
||||
void omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk,
|
||||
void __iomem **idlest_reg, u8 *idlest_bit, u8 *idlest_val)
|
||||
{
|
||||
u32 r;
|
||||
|
||||
r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20);
|
||||
*idlest_reg = (__force void __iomem *)r;
|
||||
*idlest_bit = clk->enable_bit;
|
||||
|
||||
/*
|
||||
* 24xx uses 0 to indicate not ready, and 1 to indicate ready.
|
||||
* 34xx reverses this, just to keep us on our toes
|
||||
* AM35xx uses both, depending on the module.
|
||||
*/
|
||||
*idlest_val = ti_clk_features.cm_idlest_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* omap2_dflt_clk_enable - enable a clock in the hardware
|
||||
* @hw: struct clk_hw * of the clock to enable
|
||||
*
|
||||
* Enable the clock @hw in the hardware. We first call into the OMAP
|
||||
* clockdomain code to "enable" the corresponding clockdomain if this
|
||||
* is the first enabled user of the clockdomain. Then program the
|
||||
* hardware to enable the clock. Then wait for the IP block that uses
|
||||
* this clock to leave idle (if applicable). Returns the error value
|
||||
* from clkdm_clk_enable() if it terminated with an error, or -EINVAL
|
||||
* if @hw has a null clock enable_reg, or zero upon success.
|
||||
*/
|
||||
int omap2_dflt_clk_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_hw_omap *clk;
|
||||
u32 v;
|
||||
int ret = 0;
|
||||
|
||||
clk = to_clk_hw_omap(hw);
|
||||
|
||||
if (clkdm_control && clk->clkdm) {
|
||||
ret = clkdm_clk_enable(clk->clkdm, hw->clk);
|
||||
if (ret) {
|
||||
WARN(1, "%s: could not enable %s's clockdomain %s: %d\n",
|
||||
__func__, __clk_get_name(hw->clk),
|
||||
clk->clkdm->name, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely(clk->enable_reg == NULL)) {
|
||||
pr_err("%s: %s missing enable_reg\n", __func__,
|
||||
__clk_get_name(hw->clk));
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* FIXME should not have INVERT_ENABLE bit here */
|
||||
v = omap2_clk_readl(clk, clk->enable_reg);
|
||||
if (clk->flags & INVERT_ENABLE)
|
||||
v &= ~(1 << clk->enable_bit);
|
||||
else
|
||||
v |= (1 << clk->enable_bit);
|
||||
omap2_clk_writel(v, clk, clk->enable_reg);
|
||||
v = omap2_clk_readl(clk, clk->enable_reg); /* OCP barrier */
|
||||
|
||||
if (clk->ops && clk->ops->find_idlest)
|
||||
_omap2_module_wait_ready(clk);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
if (clkdm_control && clk->clkdm)
|
||||
clkdm_clk_disable(clk->clkdm, hw->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* omap2_dflt_clk_disable - disable a clock in the hardware
|
||||
* @hw: struct clk_hw * of the clock to disable
|
||||
*
|
||||
* Disable the clock @hw in the hardware, and call into the OMAP
|
||||
* clockdomain code to "disable" the corresponding clockdomain if all
|
||||
* clocks/hwmods in that clockdomain are now disabled. No return
|
||||
* value.
|
||||
*/
|
||||
void omap2_dflt_clk_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_hw_omap *clk;
|
||||
u32 v;
|
||||
|
||||
clk = to_clk_hw_omap(hw);
|
||||
if (!clk->enable_reg) {
|
||||
/*
|
||||
* 'independent' here refers to a clock which is not
|
||||
* controlled by its parent.
|
||||
*/
|
||||
pr_err("%s: independent clock %s has no enable_reg\n",
|
||||
__func__, __clk_get_name(hw->clk));
|
||||
return;
|
||||
}
|
||||
|
||||
v = omap2_clk_readl(clk, clk->enable_reg);
|
||||
if (clk->flags & INVERT_ENABLE)
|
||||
v |= (1 << clk->enable_bit);
|
||||
else
|
||||
v &= ~(1 << clk->enable_bit);
|
||||
omap2_clk_writel(v, clk, clk->enable_reg);
|
||||
/* No OCP barrier needed here since it is a disable operation */
|
||||
|
||||
if (clkdm_control && clk->clkdm)
|
||||
clkdm_clk_disable(clk->clkdm, hw->clk);
|
||||
}
|
||||
|
||||
/**
|
||||
* omap2_clkops_enable_clkdm - increment usecount on clkdm of @hw
|
||||
* @hw: struct clk_hw * of the clock being enabled
|
||||
*
|
||||
* Increment the usecount of the clockdomain of the clock pointed to
|
||||
* by @hw; if the usecount is 1, the clockdomain will be "enabled."
|
||||
* Only needed for clocks that don't use omap2_dflt_clk_enable() as
|
||||
* their enable function pointer. Passes along the return value of
|
||||
* clkdm_clk_enable(), -EINVAL if @hw is not associated with a
|
||||
* clockdomain, or 0 if clock framework-based clockdomain control is
|
||||
* not implemented.
|
||||
*/
|
||||
int omap2_clkops_enable_clkdm(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_hw_omap *clk;
|
||||
int ret = 0;
|
||||
|
||||
clk = to_clk_hw_omap(hw);
|
||||
|
||||
if (unlikely(!clk->clkdm)) {
|
||||
pr_err("%s: %s: no clkdm set ?!\n", __func__,
|
||||
__clk_get_name(hw->clk));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (unlikely(clk->enable_reg))
|
||||
pr_err("%s: %s: should use dflt_clk_enable ?!\n", __func__,
|
||||
__clk_get_name(hw->clk));
|
||||
|
||||
if (!clkdm_control) {
|
||||
pr_err("%s: %s: clkfw-based clockdomain control disabled ?!\n",
|
||||
__func__, __clk_get_name(hw->clk));
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = clkdm_clk_enable(clk->clkdm, hw->clk);
|
||||
WARN(ret, "%s: could not enable %s's clockdomain %s: %d\n",
|
||||
__func__, __clk_get_name(hw->clk), clk->clkdm->name, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* omap2_clkops_disable_clkdm - decrement usecount on clkdm of @hw
|
||||
* @hw: struct clk_hw * of the clock being disabled
|
||||
*
|
||||
* Decrement the usecount of the clockdomain of the clock pointed to
|
||||
* by @hw; if the usecount is 0, the clockdomain will be "disabled."
|
||||
* Only needed for clocks that don't use omap2_dflt_clk_disable() as their
|
||||
* disable function pointer. No return value.
|
||||
*/
|
||||
void omap2_clkops_disable_clkdm(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_hw_omap *clk;
|
||||
|
||||
clk = to_clk_hw_omap(hw);
|
||||
|
||||
if (unlikely(!clk->clkdm)) {
|
||||
pr_err("%s: %s: no clkdm set ?!\n", __func__,
|
||||
__clk_get_name(hw->clk));
|
||||
return;
|
||||
}
|
||||
|
||||
if (unlikely(clk->enable_reg))
|
||||
pr_err("%s: %s: should use dflt_clk_disable ?!\n", __func__,
|
||||
__clk_get_name(hw->clk));
|
||||
|
||||
if (!clkdm_control) {
|
||||
pr_err("%s: %s: clkfw-based clockdomain control disabled ?!\n",
|
||||
__func__, __clk_get_name(hw->clk));
|
||||
return;
|
||||
}
|
||||
|
||||
clkdm_clk_disable(clk->clkdm, hw->clk);
|
||||
}
|
||||
|
||||
/**
|
||||
* omap2_dflt_clk_is_enabled - is clock enabled in the hardware?
|
||||
* @hw: struct clk_hw * to check
|
||||
*
|
||||
* Return 1 if the clock represented by @hw is enabled in the
|
||||
* hardware, or 0 otherwise. Intended for use in the struct
|
||||
* clk_ops.is_enabled function pointer.
|
||||
*/
|
||||
int omap2_dflt_clk_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
|
||||
u32 v;
|
||||
|
||||
v = omap2_clk_readl(clk, clk->enable_reg);
|
||||
|
||||
if (clk->flags & INVERT_ENABLE)
|
||||
v ^= BIT(clk->enable_bit);
|
||||
|
||||
v &= BIT(clk->enable_bit);
|
||||
|
||||
return v ? 1 : 0;
|
||||
}
|
||||
|
||||
static int __initdata mpurate;
|
||||
|
||||
/*
|
||||
|
@ -583,178 +132,6 @@ static int __init omap_clk_setup(char *str)
|
|||
}
|
||||
__setup("mpurate=", omap_clk_setup);
|
||||
|
||||
/**
|
||||
* omap2_init_clk_hw_omap_clocks - initialize an OMAP clock
|
||||
* @clk: struct clk * to initialize
|
||||
*
|
||||
* Add an OMAP clock @clk to the internal list of OMAP clocks. Used
|
||||
* temporarily for autoidle handling, until this support can be
|
||||
* integrated into the common clock framework code in some way. No
|
||||
* return value.
|
||||
*/
|
||||
void omap2_init_clk_hw_omap_clocks(struct clk *clk)
|
||||
{
|
||||
struct clk_hw_omap *c;
|
||||
|
||||
if (__clk_get_flags(clk) & CLK_IS_BASIC)
|
||||
return;
|
||||
|
||||
c = to_clk_hw_omap(__clk_get_hw(clk));
|
||||
list_add(&c->node, &clk_hw_omap_clocks);
|
||||
}
|
||||
|
||||
/**
|
||||
* omap2_clk_enable_autoidle_all - enable autoidle on all OMAP clocks that
|
||||
* support it
|
||||
*
|
||||
* Enable clock autoidle on all OMAP clocks that have allow_idle
|
||||
* function pointers associated with them. This function is intended
|
||||
* to be temporary until support for this is added to the common clock
|
||||
* code. Returns 0.
|
||||
*/
|
||||
int omap2_clk_enable_autoidle_all(void)
|
||||
{
|
||||
struct clk_hw_omap *c;
|
||||
|
||||
list_for_each_entry(c, &clk_hw_omap_clocks, node)
|
||||
if (c->ops && c->ops->allow_idle)
|
||||
c->ops->allow_idle(c);
|
||||
|
||||
of_ti_clk_allow_autoidle_all();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* omap2_clk_disable_autoidle_all - disable autoidle on all OMAP clocks that
|
||||
* support it
|
||||
*
|
||||
* Disable clock autoidle on all OMAP clocks that have allow_idle
|
||||
* function pointers associated with them. This function is intended
|
||||
* to be temporary until support for this is added to the common clock
|
||||
* code. Returns 0.
|
||||
*/
|
||||
int omap2_clk_disable_autoidle_all(void)
|
||||
{
|
||||
struct clk_hw_omap *c;
|
||||
|
||||
list_for_each_entry(c, &clk_hw_omap_clocks, node)
|
||||
if (c->ops && c->ops->deny_idle)
|
||||
c->ops->deny_idle(c);
|
||||
|
||||
of_ti_clk_deny_autoidle_all();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* omap2_clk_deny_idle - disable autoidle on an OMAP clock
|
||||
* @clk: struct clk * to disable autoidle for
|
||||
*
|
||||
* Disable autoidle on an OMAP clock.
|
||||
*/
|
||||
int omap2_clk_deny_idle(struct clk *clk)
|
||||
{
|
||||
struct clk_hw_omap *c;
|
||||
|
||||
if (__clk_get_flags(clk) & CLK_IS_BASIC)
|
||||
return -EINVAL;
|
||||
|
||||
c = to_clk_hw_omap(__clk_get_hw(clk));
|
||||
if (c->ops && c->ops->deny_idle)
|
||||
c->ops->deny_idle(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* omap2_clk_allow_idle - enable autoidle on an OMAP clock
|
||||
* @clk: struct clk * to enable autoidle for
|
||||
*
|
||||
* Enable autoidle on an OMAP clock.
|
||||
*/
|
||||
int omap2_clk_allow_idle(struct clk *clk)
|
||||
{
|
||||
struct clk_hw_omap *c;
|
||||
|
||||
if (__clk_get_flags(clk) & CLK_IS_BASIC)
|
||||
return -EINVAL;
|
||||
|
||||
c = to_clk_hw_omap(__clk_get_hw(clk));
|
||||
if (c->ops && c->ops->allow_idle)
|
||||
c->ops->allow_idle(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* omap2_clk_enable_init_clocks - prepare & enable a list of clocks
|
||||
* @clk_names: ptr to an array of strings of clock names to enable
|
||||
* @num_clocks: number of clock names in @clk_names
|
||||
*
|
||||
* Prepare and enable a list of clocks, named by @clk_names. No
|
||||
* return value. XXX Deprecated; only needed until these clocks are
|
||||
* properly claimed and enabled by the drivers or core code that uses
|
||||
* them. XXX What code disables & calls clk_put on these clocks?
|
||||
*/
|
||||
void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks)
|
||||
{
|
||||
struct clk *init_clk;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_clocks; i++) {
|
||||
init_clk = clk_get(NULL, clk_names[i]);
|
||||
if (WARN(IS_ERR(init_clk), "could not find init clock %s\n",
|
||||
clk_names[i]))
|
||||
continue;
|
||||
clk_prepare_enable(init_clk);
|
||||
}
|
||||
}
|
||||
|
||||
const struct clk_hw_omap_ops clkhwops_wait = {
|
||||
.find_idlest = omap2_clk_dflt_find_idlest,
|
||||
.find_companion = omap2_clk_dflt_find_companion,
|
||||
};
|
||||
|
||||
/**
|
||||
* omap2_clk_switch_mpurate_at_boot - switch ARM MPU rate by boot-time argument
|
||||
* @mpurate_ck_name: clk name of the clock to change rate
|
||||
*
|
||||
* Change the ARM MPU clock rate to the rate specified on the command
|
||||
* line, if one was specified. @mpurate_ck_name should be
|
||||
* "virt_prcm_set" on OMAP2xxx and "dpll1_ck" on OMAP34xx/OMAP36xx.
|
||||
* XXX Does not handle voltage scaling - on OMAP2xxx this is currently
|
||||
* handled by the virt_prcm_set clock, but this should be handled by
|
||||
* the OPP layer. XXX This is intended to be handled by the OPP layer
|
||||
* code in the near future and should be removed from the clock code.
|
||||
* Returns -EINVAL if 'mpurate' is zero or if clk_set_rate() rejects
|
||||
* the rate, -ENOENT if the struct clk referred to by @mpurate_ck_name
|
||||
* cannot be found, or 0 upon success.
|
||||
*/
|
||||
int __init omap2_clk_switch_mpurate_at_boot(const char *mpurate_ck_name)
|
||||
{
|
||||
struct clk *mpurate_ck;
|
||||
int r;
|
||||
|
||||
if (!mpurate)
|
||||
return -EINVAL;
|
||||
|
||||
mpurate_ck = clk_get(NULL, mpurate_ck_name);
|
||||
if (WARN(IS_ERR(mpurate_ck), "Failed to get %s.\n", mpurate_ck_name))
|
||||
return -ENOENT;
|
||||
|
||||
r = clk_set_rate(mpurate_ck, mpurate);
|
||||
if (r < 0) {
|
||||
WARN(1, "clock: %s: unable to set MPU rate to %d: %d\n",
|
||||
mpurate_ck_name, mpurate, r);
|
||||
clk_put(mpurate_ck);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
calibrate_delay();
|
||||
clk_put(mpurate_ck);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* omap2_clk_print_new_rates - print summary of current clock tree rates
|
||||
* @hfclkin_ck_name: clk name for the off-chip HF oscillator
|
||||
|
@ -801,29 +178,30 @@ void __init omap2_clk_print_new_rates(const char *hfclkin_ck_name,
|
|||
*/
|
||||
void __init ti_clk_init_features(void)
|
||||
{
|
||||
struct ti_clk_features features = { 0 };
|
||||
/* Fint setup for DPLLs */
|
||||
if (cpu_is_omap3430()) {
|
||||
ti_clk_features.fint_min = OMAP3430_DPLL_FINT_BAND1_MIN;
|
||||
ti_clk_features.fint_max = OMAP3430_DPLL_FINT_BAND2_MAX;
|
||||
ti_clk_features.fint_band1_max = OMAP3430_DPLL_FINT_BAND1_MAX;
|
||||
ti_clk_features.fint_band2_min = OMAP3430_DPLL_FINT_BAND2_MIN;
|
||||
features.fint_min = OMAP3430_DPLL_FINT_BAND1_MIN;
|
||||
features.fint_max = OMAP3430_DPLL_FINT_BAND2_MAX;
|
||||
features.fint_band1_max = OMAP3430_DPLL_FINT_BAND1_MAX;
|
||||
features.fint_band2_min = OMAP3430_DPLL_FINT_BAND2_MIN;
|
||||
} else {
|
||||
ti_clk_features.fint_min = OMAP3PLUS_DPLL_FINT_MIN;
|
||||
ti_clk_features.fint_max = OMAP3PLUS_DPLL_FINT_MAX;
|
||||
features.fint_min = OMAP3PLUS_DPLL_FINT_MIN;
|
||||
features.fint_max = OMAP3PLUS_DPLL_FINT_MAX;
|
||||
}
|
||||
|
||||
/* Bypass value setup for DPLLs */
|
||||
if (cpu_is_omap24xx()) {
|
||||
ti_clk_features.dpll_bypass_vals |=
|
||||
features.dpll_bypass_vals |=
|
||||
(1 << OMAP2XXX_EN_DPLL_LPBYPASS) |
|
||||
(1 << OMAP2XXX_EN_DPLL_FRBYPASS);
|
||||
} else if (cpu_is_omap34xx()) {
|
||||
ti_clk_features.dpll_bypass_vals |=
|
||||
features.dpll_bypass_vals |=
|
||||
(1 << OMAP3XXX_EN_DPLL_LPBYPASS) |
|
||||
(1 << OMAP3XXX_EN_DPLL_FRBYPASS);
|
||||
} else if (soc_is_am33xx() || cpu_is_omap44xx() || soc_is_am43xx() ||
|
||||
soc_is_omap54xx() || soc_is_dra7xx()) {
|
||||
ti_clk_features.dpll_bypass_vals |=
|
||||
features.dpll_bypass_vals |=
|
||||
(1 << OMAP4XXX_EN_DPLL_LPBYPASS) |
|
||||
(1 << OMAP4XXX_EN_DPLL_FRBYPASS) |
|
||||
(1 << OMAP4XXX_EN_DPLL_MNBYPASS);
|
||||
|
@ -831,7 +209,7 @@ void __init ti_clk_init_features(void)
|
|||
|
||||
/* Jitter correction only available on OMAP343X */
|
||||
if (cpu_is_omap343x())
|
||||
ti_clk_features.flags |= TI_CLK_DPLL_HAS_FREQSEL;
|
||||
features.flags |= TI_CLK_DPLL_HAS_FREQSEL;
|
||||
|
||||
/* Idlest value for interface clocks.
|
||||
* 24xx uses 0 to indicate not ready, and 1 to indicate ready.
|
||||
|
@ -839,11 +217,13 @@ void __init ti_clk_init_features(void)
|
|||
* AM35xx uses both, depending on the module.
|
||||
*/
|
||||
if (cpu_is_omap24xx())
|
||||
ti_clk_features.cm_idlest_val = OMAP24XX_CM_IDLEST_VAL;
|
||||
features.cm_idlest_val = OMAP24XX_CM_IDLEST_VAL;
|
||||
else if (cpu_is_omap34xx())
|
||||
ti_clk_features.cm_idlest_val = OMAP34XX_CM_IDLEST_VAL;
|
||||
features.cm_idlest_val = OMAP34XX_CM_IDLEST_VAL;
|
||||
|
||||
/* On OMAP3430 ES1.0, DPLL4 can't be re-programmed */
|
||||
if (omap_rev() == OMAP3430_REV_ES1_0)
|
||||
ti_clk_features.flags |= TI_CLK_DPLL4_DENY_REPROGRAM;
|
||||
features.flags |= TI_CLK_DPLL4_DENY_REPROGRAM;
|
||||
|
||||
ti_clk_setup_features(&features);
|
||||
}
|
||||
|
|
|
@ -23,90 +23,6 @@
|
|||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk/ti.h>
|
||||
|
||||
struct omap_clk {
|
||||
u16 cpu;
|
||||
struct clk_lookup lk;
|
||||
};
|
||||
|
||||
#define CLK(dev, con, ck) \
|
||||
{ \
|
||||
.lk = { \
|
||||
.dev_id = dev, \
|
||||
.con_id = con, \
|
||||
.clk = ck, \
|
||||
}, \
|
||||
}
|
||||
|
||||
struct clockdomain;
|
||||
|
||||
#define DEFINE_STRUCT_CLK(_name, _parent_array_name, _clkops_name) \
|
||||
static struct clk_core _name##_core = { \
|
||||
.name = #_name, \
|
||||
.hw = &_name##_hw.hw, \
|
||||
.parent_names = _parent_array_name, \
|
||||
.num_parents = ARRAY_SIZE(_parent_array_name), \
|
||||
.ops = &_clkops_name, \
|
||||
}; \
|
||||
static struct clk _name = { \
|
||||
.core = &_name##_core, \
|
||||
};
|
||||
|
||||
#define DEFINE_STRUCT_CLK_FLAGS(_name, _parent_array_name, \
|
||||
_clkops_name, _flags) \
|
||||
static struct clk_core _name##_core = { \
|
||||
.name = #_name, \
|
||||
.hw = &_name##_hw.hw, \
|
||||
.parent_names = _parent_array_name, \
|
||||
.num_parents = ARRAY_SIZE(_parent_array_name), \
|
||||
.ops = &_clkops_name, \
|
||||
.flags = _flags, \
|
||||
}; \
|
||||
static struct clk _name = { \
|
||||
.core = &_name##_core, \
|
||||
};
|
||||
|
||||
#define DEFINE_STRUCT_CLK_HW_OMAP(_name, _clkdm_name) \
|
||||
static struct clk_hw_omap _name##_hw = { \
|
||||
.hw = { \
|
||||
.clk = &_name, \
|
||||
}, \
|
||||
.clkdm_name = _clkdm_name, \
|
||||
};
|
||||
|
||||
#define DEFINE_CLK_OMAP_MUX(_name, _clkdm_name, _clksel, \
|
||||
_clksel_reg, _clksel_mask, \
|
||||
_parent_names, _ops) \
|
||||
static struct clk _name; \
|
||||
static struct clk_hw_omap _name##_hw = { \
|
||||
.hw = { \
|
||||
.clk = &_name, \
|
||||
}, \
|
||||
.clksel = _clksel, \
|
||||
.clksel_reg = _clksel_reg, \
|
||||
.clksel_mask = _clksel_mask, \
|
||||
.clkdm_name = _clkdm_name, \
|
||||
}; \
|
||||
DEFINE_STRUCT_CLK(_name, _parent_names, _ops);
|
||||
|
||||
#define DEFINE_CLK_OMAP_MUX_GATE(_name, _clkdm_name, _clksel, \
|
||||
_clksel_reg, _clksel_mask, \
|
||||
_enable_reg, _enable_bit, \
|
||||
_hwops, _parent_names, _ops) \
|
||||
static struct clk _name; \
|
||||
static struct clk_hw_omap _name##_hw = { \
|
||||
.hw = { \
|
||||
.clk = &_name, \
|
||||
}, \
|
||||
.ops = _hwops, \
|
||||
.enable_reg = _enable_reg, \
|
||||
.enable_bit = _enable_bit, \
|
||||
.clksel = _clksel, \
|
||||
.clksel_reg = _clksel_reg, \
|
||||
.clksel_mask = _clksel_mask, \
|
||||
.clkdm_name = _clkdm_name, \
|
||||
}; \
|
||||
DEFINE_STRUCT_CLK(_name, _parent_names, _ops);
|
||||
|
||||
/* struct clksel_rate.flags possibilities */
|
||||
#define RATE_IN_242X (1 << 0)
|
||||
#define RATE_IN_243X (1 << 1)
|
||||
|
@ -127,38 +43,6 @@ struct clockdomain;
|
|||
/* RATE_IN_3430ES2PLUS_36XX includes 34xx/35xx with ES >=2, and all 36xx/37xx */
|
||||
#define RATE_IN_3430ES2PLUS_36XX (RATE_IN_3430ES2PLUS | RATE_IN_36XX)
|
||||
|
||||
|
||||
/**
|
||||
* struct clksel_rate - register bitfield values corresponding to clk divisors
|
||||
* @val: register bitfield value (shifted to bit 0)
|
||||
* @div: clock divisor corresponding to @val
|
||||
* @flags: (see "struct clksel_rate.flags possibilities" above)
|
||||
*
|
||||
* @val should match the value of a read from struct clk.clksel_reg
|
||||
* AND'ed with struct clk.clksel_mask, shifted right to bit 0.
|
||||
*
|
||||
* @div is the divisor that should be applied to the parent clock's rate
|
||||
* to produce the current clock's rate.
|
||||
*/
|
||||
struct clksel_rate {
|
||||
u32 val;
|
||||
u8 div;
|
||||
u16 flags;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct clksel - available parent clocks, and a pointer to their divisors
|
||||
* @parent: struct clk * to a possible parent clock
|
||||
* @rates: available divisors for this parent clock
|
||||
*
|
||||
* A struct clksel is always associated with one or more struct clks
|
||||
* and one or more struct clksel_rates.
|
||||
*/
|
||||
struct clksel {
|
||||
struct clk *parent;
|
||||
const struct clksel_rate *rates;
|
||||
};
|
||||
|
||||
/* CM_CLKSEL2_PLL.CORE_CLK_SRC bits (2XXX) */
|
||||
#define CORE_CLK_SRC_32K 0x0
|
||||
#define CORE_CLK_SRC_DPLL 0x1
|
||||
|
@ -180,105 +64,18 @@ struct clksel {
|
|||
#define OMAP4XXX_EN_DPLL_FRBYPASS 0x6
|
||||
#define OMAP4XXX_EN_DPLL_LOCKED 0x7
|
||||
|
||||
u32 omap3_dpll_autoidle_read(struct clk_hw_omap *clk);
|
||||
void omap3_dpll_allow_idle(struct clk_hw_omap *clk);
|
||||
void omap3_dpll_deny_idle(struct clk_hw_omap *clk);
|
||||
void omap4_dpllmx_allow_gatectrl(struct clk_hw_omap *clk);
|
||||
void omap4_dpllmx_deny_gatectrl(struct clk_hw_omap *clk);
|
||||
|
||||
void __init omap2_clk_disable_clkdm_control(void);
|
||||
|
||||
/* clkt_clksel.c public functions */
|
||||
u32 omap2_clksel_round_rate_div(struct clk_hw_omap *clk,
|
||||
unsigned long target_rate,
|
||||
u32 *new_div);
|
||||
u8 omap2_clksel_find_parent_index(struct clk_hw *hw);
|
||||
unsigned long omap2_clksel_recalc(struct clk_hw *hw, unsigned long parent_rate);
|
||||
long omap2_clksel_round_rate(struct clk_hw *hw, unsigned long target_rate,
|
||||
unsigned long *parent_rate);
|
||||
int omap2_clksel_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate);
|
||||
int omap2_clksel_set_parent(struct clk_hw *hw, u8 field_val);
|
||||
|
||||
/* clkt_iclk.c public functions */
|
||||
extern void omap2_clkt_iclk_allow_idle(struct clk_hw_omap *clk);
|
||||
extern void omap2_clkt_iclk_deny_idle(struct clk_hw_omap *clk);
|
||||
|
||||
unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk);
|
||||
|
||||
void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk,
|
||||
void __iomem **other_reg,
|
||||
u8 *other_bit);
|
||||
void omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk,
|
||||
void __iomem **idlest_reg,
|
||||
u8 *idlest_bit, u8 *idlest_val);
|
||||
int omap2_clk_enable_autoidle_all(void);
|
||||
int omap2_clk_allow_idle(struct clk *clk);
|
||||
int omap2_clk_deny_idle(struct clk *clk);
|
||||
int omap2_clk_switch_mpurate_at_boot(const char *mpurate_ck_name);
|
||||
void omap2_clk_print_new_rates(const char *hfclkin_ck_name,
|
||||
const char *core_ck_name,
|
||||
const char *mpu_ck_name);
|
||||
|
||||
u32 omap2_clk_readl(struct clk_hw_omap *clk, void __iomem *reg);
|
||||
void omap2_clk_writel(u32 val, struct clk_hw_omap *clk, void __iomem *reg);
|
||||
|
||||
extern u16 cpu_mask;
|
||||
|
||||
/*
|
||||
* Clock features setup. Used instead of CPU type checks.
|
||||
*/
|
||||
struct ti_clk_features {
|
||||
u32 flags;
|
||||
long fint_min;
|
||||
long fint_max;
|
||||
long fint_band1_max;
|
||||
long fint_band2_min;
|
||||
u8 dpll_bypass_vals;
|
||||
u8 cm_idlest_val;
|
||||
};
|
||||
|
||||
#define TI_CLK_DPLL_HAS_FREQSEL (1 << 0)
|
||||
#define TI_CLK_DPLL4_DENY_REPROGRAM (1 << 1)
|
||||
|
||||
extern struct ti_clk_features ti_clk_features;
|
||||
|
||||
extern const struct clkops clkops_omap2_dflt_wait;
|
||||
extern const struct clkops clkops_omap2_dflt;
|
||||
|
||||
extern struct clk_functions omap2_clk_functions;
|
||||
|
||||
extern const struct clksel_rate gpt_32k_rates[];
|
||||
extern const struct clksel_rate gpt_sys_rates[];
|
||||
extern const struct clksel_rate gfx_l3_rates[];
|
||||
extern const struct clksel_rate dsp_ick_rates[];
|
||||
|
||||
extern const struct clk_hw_omap_ops clkhwops_iclk_wait;
|
||||
extern const struct clk_hw_omap_ops clkhwops_wait;
|
||||
extern const struct clk_hw_omap_ops clkhwops_omap3430es2_ssi_wait;
|
||||
extern const struct clk_hw_omap_ops clkhwops_omap3430es2_dss_usbhost_wait;
|
||||
extern const struct clk_hw_omap_ops clkhwops_omap3430es2_hsotgusb_wait;
|
||||
extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait;
|
||||
extern const struct clk_hw_omap_ops clkhwops_apll54;
|
||||
extern const struct clk_hw_omap_ops clkhwops_apll96;
|
||||
|
||||
/* clksel_rate blocks shared between OMAP44xx and AM33xx */
|
||||
extern const struct clksel_rate div_1_0_rates[];
|
||||
extern const struct clksel_rate div3_1to4_rates[];
|
||||
extern const struct clksel_rate div_1_1_rates[];
|
||||
extern const struct clksel_rate div_1_2_rates[];
|
||||
extern const struct clksel_rate div_1_3_rates[];
|
||||
extern const struct clksel_rate div_1_4_rates[];
|
||||
extern const struct clksel_rate div31_1to31_rates[];
|
||||
|
||||
extern int omap2_clkops_enable_clkdm(struct clk_hw *hw);
|
||||
extern void omap2_clkops_disable_clkdm(struct clk_hw *hw);
|
||||
|
||||
struct regmap;
|
||||
|
||||
int __init omap2_clk_provider_init(struct device_node *np, int index,
|
||||
struct regmap *syscon, void __iomem *mem);
|
||||
void __init omap2_clk_legacy_provider_init(int index, void __iomem *mem);
|
||||
int __init omap2_clk_setup_ll_ops(void);
|
||||
|
||||
void __init ti_clk_init_features(void);
|
||||
#endif
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
/*
|
||||
* clock2430.c - OMAP2430-specific clock integration code
|
||||
*
|
||||
* Copyright (C) 2005-2008 Texas Instruments, Inc.
|
||||
* Copyright (C) 2004-2010 Nokia Corporation
|
||||
*
|
||||
* Contacts:
|
||||
* Richard Woodruff <r-woodruff2@ti.com>
|
||||
* Paul Walmsley
|
||||
*
|
||||
* Based on earlier work by Tuukka Tikkanen, Tony Lindgren,
|
||||
* Gordon McNutt and RidgeRun, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#undef DEBUG
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include "soc.h"
|
||||
#include "iomap.h"
|
||||
#include "clock.h"
|
||||
#include "clock2xxx.h"
|
||||
#include "cm2xxx.h"
|
||||
#include "cm-regbits-24xx.h"
|
||||
|
||||
/**
|
||||
* omap2430_clk_i2chs_find_idlest - return CM_IDLEST info for 2430 I2CHS
|
||||
* @clk: struct clk * being enabled
|
||||
* @idlest_reg: void __iomem ** to store CM_IDLEST reg address into
|
||||
* @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into
|
||||
* @idlest_val: pointer to a u8 to store the CM_IDLEST indicator
|
||||
*
|
||||
* OMAP2430 I2CHS CM_IDLEST bits are in CM_IDLEST1_CORE, but the
|
||||
* CM_*CLKEN bits are in CM_{I,F}CLKEN2_CORE. This custom function
|
||||
* passes back the correct CM_IDLEST register address for I2CHS
|
||||
* modules. No return value.
|
||||
*/
|
||||
static void omap2430_clk_i2chs_find_idlest(struct clk_hw_omap *clk,
|
||||
void __iomem **idlest_reg,
|
||||
u8 *idlest_bit,
|
||||
u8 *idlest_val)
|
||||
{
|
||||
*idlest_reg = OMAP2430_CM_REGADDR(CORE_MOD, CM_IDLEST);
|
||||
*idlest_bit = clk->enable_bit;
|
||||
*idlest_val = OMAP24XX_CM_IDLEST_VAL;
|
||||
}
|
||||
|
||||
/* 2430 I2CHS has non-standard IDLEST register */
|
||||
const struct clk_hw_omap_ops clkhwops_omap2430_i2chs_wait = {
|
||||
.find_idlest = omap2430_clk_i2chs_find_idlest,
|
||||
.find_companion = omap2_clk_dflt_find_companion,
|
||||
};
|
|
@ -1,57 +0,0 @@
|
|||
/*
|
||||
* clock2xxx.c - OMAP2xxx-specific clock integration code
|
||||
*
|
||||
* Copyright (C) 2005-2008 Texas Instruments, Inc.
|
||||
* Copyright (C) 2004-2010 Nokia Corporation
|
||||
*
|
||||
* Contacts:
|
||||
* Richard Woodruff <r-woodruff2@ti.com>
|
||||
* Paul Walmsley
|
||||
*
|
||||
* Based on earlier work by Tuukka Tikkanen, Tony Lindgren,
|
||||
* Gordon McNutt and RidgeRun, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#undef DEBUG
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include "soc.h"
|
||||
#include "clock.h"
|
||||
#include "clock2xxx.h"
|
||||
#include "cm.h"
|
||||
#include "cm-regbits-24xx.h"
|
||||
|
||||
struct clk_hw *dclk_hw;
|
||||
/*
|
||||
* Omap24xx specific clock functions
|
||||
*/
|
||||
|
||||
/*
|
||||
* Switch the MPU rate if specified on cmdline. We cannot do this
|
||||
* early until cmdline is parsed. XXX This should be removed from the
|
||||
* clock code and handled by the OPP layer code in the near future.
|
||||
*/
|
||||
static int __init omap2xxx_clk_arch_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!cpu_is_omap24xx())
|
||||
return 0;
|
||||
|
||||
ret = omap2_clk_switch_mpurate_at_boot("virt_prcm_set");
|
||||
if (!ret)
|
||||
omap2_clk_print_new_rates("sys_ck", "dpll_ck", "mpu_ck");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
omap_arch_initcall(omap2xxx_clk_arch_init);
|
||||
|
||||
|
|
@ -1,138 +0,0 @@
|
|||
/*
|
||||
* OMAP3-specific clock framework functions
|
||||
*
|
||||
* Copyright (C) 2007-2008 Texas Instruments, Inc.
|
||||
* Copyright (C) 2007-2011 Nokia Corporation
|
||||
*
|
||||
* Paul Walmsley
|
||||
* Jouni Högander
|
||||
*
|
||||
* Parts of this code are based on code written by
|
||||
* Richard Woodruff, Tony Lindgren, Tuukka Tikkanen, Karthik Dasu,
|
||||
* Russell King
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#undef DEBUG
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include "clock.h"
|
||||
#include "clock34xx.h"
|
||||
#include "cm3xxx.h"
|
||||
#include "cm-regbits-34xx.h"
|
||||
|
||||
/**
|
||||
* omap3430es2_clk_ssi_find_idlest - return CM_IDLEST info for SSI
|
||||
* @clk: struct clk * being enabled
|
||||
* @idlest_reg: void __iomem ** to store CM_IDLEST reg address into
|
||||
* @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into
|
||||
* @idlest_val: pointer to a u8 to store the CM_IDLEST indicator
|
||||
*
|
||||
* The OMAP3430ES2 SSI target CM_IDLEST bit is at a different shift
|
||||
* from the CM_{I,F}CLKEN bit. Pass back the correct info via
|
||||
* @idlest_reg and @idlest_bit. No return value.
|
||||
*/
|
||||
static void omap3430es2_clk_ssi_find_idlest(struct clk_hw_omap *clk,
|
||||
void __iomem **idlest_reg,
|
||||
u8 *idlest_bit,
|
||||
u8 *idlest_val)
|
||||
{
|
||||
u32 r;
|
||||
|
||||
r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20);
|
||||
*idlest_reg = (__force void __iomem *)r;
|
||||
*idlest_bit = OMAP3430ES2_ST_SSI_IDLE_SHIFT;
|
||||
*idlest_val = OMAP34XX_CM_IDLEST_VAL;
|
||||
}
|
||||
const struct clk_hw_omap_ops clkhwops_omap3430es2_ssi_wait = {
|
||||
.find_idlest = omap3430es2_clk_ssi_find_idlest,
|
||||
.find_companion = omap2_clk_dflt_find_companion,
|
||||
};
|
||||
|
||||
const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_ssi_wait = {
|
||||
.allow_idle = omap2_clkt_iclk_allow_idle,
|
||||
.deny_idle = omap2_clkt_iclk_deny_idle,
|
||||
.find_idlest = omap3430es2_clk_ssi_find_idlest,
|
||||
.find_companion = omap2_clk_dflt_find_companion,
|
||||
};
|
||||
|
||||
/**
|
||||
* omap3430es2_clk_dss_usbhost_find_idlest - CM_IDLEST info for DSS, USBHOST
|
||||
* @clk: struct clk * being enabled
|
||||
* @idlest_reg: void __iomem ** to store CM_IDLEST reg address into
|
||||
* @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into
|
||||
* @idlest_val: pointer to a u8 to store the CM_IDLEST indicator
|
||||
*
|
||||
* Some OMAP modules on OMAP3 ES2+ chips have both initiator and
|
||||
* target IDLEST bits. For our purposes, we are concerned with the
|
||||
* target IDLEST bits, which exist at a different bit position than
|
||||
* the *CLKEN bit position for these modules (DSS and USBHOST) (The
|
||||
* default find_idlest code assumes that they are at the same
|
||||
* position.) No return value.
|
||||
*/
|
||||
static void omap3430es2_clk_dss_usbhost_find_idlest(struct clk_hw_omap *clk,
|
||||
void __iomem **idlest_reg,
|
||||
u8 *idlest_bit,
|
||||
u8 *idlest_val)
|
||||
{
|
||||
u32 r;
|
||||
|
||||
r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20);
|
||||
*idlest_reg = (__force void __iomem *)r;
|
||||
/* USBHOST_IDLE has same shift */
|
||||
*idlest_bit = OMAP3430ES2_ST_DSS_IDLE_SHIFT;
|
||||
*idlest_val = OMAP34XX_CM_IDLEST_VAL;
|
||||
}
|
||||
|
||||
const struct clk_hw_omap_ops clkhwops_omap3430es2_dss_usbhost_wait = {
|
||||
.find_idlest = omap3430es2_clk_dss_usbhost_find_idlest,
|
||||
.find_companion = omap2_clk_dflt_find_companion,
|
||||
};
|
||||
|
||||
const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_dss_usbhost_wait = {
|
||||
.allow_idle = omap2_clkt_iclk_allow_idle,
|
||||
.deny_idle = omap2_clkt_iclk_deny_idle,
|
||||
.find_idlest = omap3430es2_clk_dss_usbhost_find_idlest,
|
||||
.find_companion = omap2_clk_dflt_find_companion,
|
||||
};
|
||||
|
||||
/**
|
||||
* omap3430es2_clk_hsotgusb_find_idlest - return CM_IDLEST info for HSOTGUSB
|
||||
* @clk: struct clk * being enabled
|
||||
* @idlest_reg: void __iomem ** to store CM_IDLEST reg address into
|
||||
* @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into
|
||||
* @idlest_val: pointer to a u8 to store the CM_IDLEST indicator
|
||||
*
|
||||
* The OMAP3430ES2 HSOTGUSB target CM_IDLEST bit is at a different
|
||||
* shift from the CM_{I,F}CLKEN bit. Pass back the correct info via
|
||||
* @idlest_reg and @idlest_bit. No return value.
|
||||
*/
|
||||
static void omap3430es2_clk_hsotgusb_find_idlest(struct clk_hw_omap *clk,
|
||||
void __iomem **idlest_reg,
|
||||
u8 *idlest_bit,
|
||||
u8 *idlest_val)
|
||||
{
|
||||
u32 r;
|
||||
|
||||
r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20);
|
||||
*idlest_reg = (__force void __iomem *)r;
|
||||
*idlest_bit = OMAP3430ES2_ST_HSOTGUSB_IDLE_SHIFT;
|
||||
*idlest_val = OMAP34XX_CM_IDLEST_VAL;
|
||||
}
|
||||
|
||||
const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_hsotgusb_wait = {
|
||||
.allow_idle = omap2_clkt_iclk_allow_idle,
|
||||
.deny_idle = omap2_clkt_iclk_deny_idle,
|
||||
.find_idlest = omap3430es2_clk_hsotgusb_find_idlest,
|
||||
.find_companion = omap2_clk_dflt_find_companion,
|
||||
};
|
||||
|
||||
const struct clk_hw_omap_ops clkhwops_omap3430es2_hsotgusb_wait = {
|
||||
.find_idlest = omap3430es2_clk_hsotgusb_find_idlest,
|
||||
.find_companion = omap2_clk_dflt_find_companion,
|
||||
};
|
|
@ -1,18 +0,0 @@
|
|||
/*
|
||||
* OMAP34xx clock function prototypes and macros
|
||||
*
|
||||
* Copyright (C) 2007-2010 Texas Instruments, Inc.
|
||||
* Copyright (C) 2007-2011 Nokia Corporation
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_ARM_MACH_OMAP2_CLOCK34XX_H
|
||||
#define __ARCH_ARM_MACH_OMAP2_CLOCK34XX_H
|
||||
|
||||
extern const struct clkops clkops_omap3430es2_ssi_wait;
|
||||
extern const struct clkops clkops_omap3430es2_iclk_ssi_wait;
|
||||
extern const struct clkops clkops_omap3430es2_hsotgusb_wait;
|
||||
extern const struct clkops clkops_omap3430es2_iclk_hsotgusb_wait;
|
||||
extern const struct clkops clkops_omap3430es2_dss_usbhost_wait;
|
||||
extern const struct clkops clkops_omap3430es2_iclk_dss_usbhost_wait;
|
||||
|
||||
#endif
|
|
@ -1,118 +0,0 @@
|
|||
/*
|
||||
* OMAP3517/3505-specific clock framework functions
|
||||
*
|
||||
* Copyright (C) 2010 Texas Instruments, Inc.
|
||||
* Copyright (C) 2011 Nokia Corporation
|
||||
*
|
||||
* Ranjith Lohithakshan
|
||||
* Paul Walmsley
|
||||
*
|
||||
* Parts of this code are based on code written by
|
||||
* Richard Woodruff, Tony Lindgren, Tuukka Tikkanen, Karthik Dasu,
|
||||
* Russell King
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#undef DEBUG
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include "clock.h"
|
||||
#include "clock3517.h"
|
||||
#include "cm3xxx.h"
|
||||
#include "cm-regbits-34xx.h"
|
||||
|
||||
/*
|
||||
* In AM35xx IPSS, the {ICK,FCK} enable bits for modules are exported
|
||||
* in the same register at a bit offset of 0x8. The EN_ACK for ICK is
|
||||
* at an offset of 4 from ICK enable bit.
|
||||
*/
|
||||
#define AM35XX_IPSS_ICK_MASK 0xF
|
||||
#define AM35XX_IPSS_ICK_EN_ACK_OFFSET 0x4
|
||||
#define AM35XX_IPSS_ICK_FCK_OFFSET 0x8
|
||||
#define AM35XX_IPSS_CLK_IDLEST_VAL 0
|
||||
|
||||
/**
|
||||
* am35xx_clk_find_idlest - return clock ACK info for AM35XX IPSS
|
||||
* @clk: struct clk * being enabled
|
||||
* @idlest_reg: void __iomem ** to store CM_IDLEST reg address into
|
||||
* @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into
|
||||
* @idlest_val: pointer to a u8 to store the CM_IDLEST indicator
|
||||
*
|
||||
* The interface clocks on AM35xx IPSS reflects the clock idle status
|
||||
* in the enable register itsel at a bit offset of 4 from the enable
|
||||
* bit. A value of 1 indicates that clock is enabled.
|
||||
*/
|
||||
static void am35xx_clk_find_idlest(struct clk_hw_omap *clk,
|
||||
void __iomem **idlest_reg,
|
||||
u8 *idlest_bit,
|
||||
u8 *idlest_val)
|
||||
{
|
||||
*idlest_reg = (__force void __iomem *)(clk->enable_reg);
|
||||
*idlest_bit = clk->enable_bit + AM35XX_IPSS_ICK_EN_ACK_OFFSET;
|
||||
*idlest_val = AM35XX_IPSS_CLK_IDLEST_VAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* am35xx_clk_find_companion - find companion clock to @clk
|
||||
* @clk: struct clk * to find the companion clock of
|
||||
* @other_reg: void __iomem ** to return the companion clock CM_*CLKEN va in
|
||||
* @other_bit: u8 ** to return the companion clock bit shift in
|
||||
*
|
||||
* Some clocks don't have companion clocks. For example, modules with
|
||||
* only an interface clock (such as HECC) don't have a companion
|
||||
* clock. Right now, this code relies on the hardware exporting a bit
|
||||
* in the correct companion register that indicates that the
|
||||
* nonexistent 'companion clock' is active. Future patches will
|
||||
* associate this type of code with per-module data structures to
|
||||
* avoid this issue, and remove the casts. No return value.
|
||||
*/
|
||||
static void am35xx_clk_find_companion(struct clk_hw_omap *clk,
|
||||
void __iomem **other_reg,
|
||||
u8 *other_bit)
|
||||
{
|
||||
*other_reg = (__force void __iomem *)(clk->enable_reg);
|
||||
if (clk->enable_bit & AM35XX_IPSS_ICK_MASK)
|
||||
*other_bit = clk->enable_bit + AM35XX_IPSS_ICK_FCK_OFFSET;
|
||||
else
|
||||
*other_bit = clk->enable_bit - AM35XX_IPSS_ICK_FCK_OFFSET;
|
||||
}
|
||||
const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait = {
|
||||
.find_idlest = am35xx_clk_find_idlest,
|
||||
.find_companion = am35xx_clk_find_companion,
|
||||
};
|
||||
|
||||
/**
|
||||
* am35xx_clk_ipss_find_idlest - return CM_IDLEST info for IPSS
|
||||
* @clk: struct clk * being enabled
|
||||
* @idlest_reg: void __iomem ** to store CM_IDLEST reg address into
|
||||
* @idlest_bit: pointer to a u8 to store the CM_IDLEST bit shift into
|
||||
* @idlest_val: pointer to a u8 to store the CM_IDLEST indicator
|
||||
*
|
||||
* The IPSS target CM_IDLEST bit is at a different shift from the
|
||||
* CM_{I,F}CLKEN bit. Pass back the correct info via @idlest_reg
|
||||
* and @idlest_bit. No return value.
|
||||
*/
|
||||
static void am35xx_clk_ipss_find_idlest(struct clk_hw_omap *clk,
|
||||
void __iomem **idlest_reg,
|
||||
u8 *idlest_bit,
|
||||
u8 *idlest_val)
|
||||
{
|
||||
u32 r;
|
||||
|
||||
r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20);
|
||||
*idlest_reg = (__force void __iomem *)r;
|
||||
*idlest_bit = AM35XX_ST_IPSS_SHIFT;
|
||||
*idlest_val = OMAP34XX_CM_IDLEST_VAL;
|
||||
}
|
||||
|
||||
const struct clk_hw_omap_ops clkhwops_am35xx_ipss_wait = {
|
||||
.allow_idle = omap2_clkt_iclk_allow_idle,
|
||||
.deny_idle = omap2_clkt_iclk_deny_idle,
|
||||
.find_idlest = am35xx_clk_ipss_find_idlest,
|
||||
.find_companion = omap2_clk_dflt_find_companion,
|
||||
};
|
|
@ -1,14 +0,0 @@
|
|||
/*
|
||||
* OMAP3517/3505 clock function prototypes and macros
|
||||
*
|
||||
* Copyright (C) 2010 Texas Instruments, Inc.
|
||||
* Copyright (C) 2010 Nokia Corporation
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_ARM_MACH_OMAP2_CLOCK3517_H
|
||||
#define __ARCH_ARM_MACH_OMAP2_CLOCK3517_H
|
||||
|
||||
extern const struct clkops clkops_am35xx_ipss_module_wait;
|
||||
extern const struct clkops clkops_am35xx_ipss_wait;
|
||||
|
||||
#endif
|
|
@ -1,69 +0,0 @@
|
|||
/*
|
||||
* OMAP36xx-specific clkops
|
||||
*
|
||||
* Copyright (C) 2010 Texas Instruments, Inc.
|
||||
* Copyright (C) 2010 Nokia Corporation
|
||||
*
|
||||
* Mike Turquette
|
||||
* Vijaykumar GN
|
||||
* Paul Walmsley
|
||||
*
|
||||
* Parts of this code are based on code written by
|
||||
* Richard Woodruff, Tony Lindgren, Tuukka Tikkanen, Karthik Dasu,
|
||||
* Russell King
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#undef DEBUG
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include "clock.h"
|
||||
#include "clock36xx.h"
|
||||
#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
|
||||
|
||||
/**
|
||||
* omap36xx_pwrdn_clk_enable_with_hsdiv_restore - enable clocks suffering
|
||||
* from HSDivider PWRDN problem Implements Errata ID: i556.
|
||||
* @clk: DPLL output struct clk
|
||||
*
|
||||
* 3630 only: dpll3_m3_ck, dpll4_m2_ck, dpll4_m3_ck, dpll4_m4_ck,
|
||||
* dpll4_m5_ck & dpll4_m6_ck dividers gets loaded with reset
|
||||
* valueafter their respective PWRDN bits are set. Any dummy write
|
||||
* (Any other value different from the Read value) to the
|
||||
* corresponding CM_CLKSEL register will refresh the dividers.
|
||||
*/
|
||||
int omap36xx_pwrdn_clk_enable_with_hsdiv_restore(struct clk_hw *clk)
|
||||
{
|
||||
struct clk_divider *parent;
|
||||
struct clk_hw *parent_hw;
|
||||
u32 dummy_v, orig_v;
|
||||
struct clk_hw_omap *omap_clk = to_clk_hw_omap(clk);
|
||||
int ret;
|
||||
|
||||
/* Clear PWRDN bit of HSDIVIDER */
|
||||
ret = omap2_dflt_clk_enable(clk);
|
||||
|
||||
parent_hw = __clk_get_hw(__clk_get_parent(clk->clk));
|
||||
parent = to_clk_divider(parent_hw);
|
||||
|
||||
/* Restore the dividers */
|
||||
if (!ret) {
|
||||
orig_v = omap2_clk_readl(omap_clk, parent->reg);
|
||||
dummy_v = orig_v;
|
||||
|
||||
/* Write any other value different from the Read value */
|
||||
dummy_v ^= (1 << parent->shift);
|
||||
omap2_clk_writel(dummy_v, omap_clk, parent->reg);
|
||||
|
||||
/* Write the original divider */
|
||||
omap2_clk_writel(orig_v, omap_clk, parent->reg);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
/*
|
||||
* OMAP36xx clock function prototypes and macros
|
||||
*
|
||||
* Copyright (C) 2010 Texas Instruments, Inc.
|
||||
* Copyright (C) 2010 Nokia Corporation
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_ARM_MACH_OMAP2_CLOCK36XX_H
|
||||
#define __ARCH_ARM_MACH_OMAP2_CLOCK36XX_H
|
||||
|
||||
extern int omap36xx_pwrdn_clk_enable_with_hsdiv_restore(struct clk_hw *hw);
|
||||
|
||||
#endif
|
|
@ -1,135 +0,0 @@
|
|||
/*
|
||||
* OMAP3-specific clock framework functions
|
||||
*
|
||||
* Copyright (C) 2007-2008 Texas Instruments, Inc.
|
||||
* Copyright (C) 2007-2010 Nokia Corporation
|
||||
*
|
||||
* Paul Walmsley
|
||||
* Jouni Högander
|
||||
*
|
||||
* Parts of this code are based on code written by
|
||||
* Richard Woodruff, Tony Lindgren, Tuukka Tikkanen, Karthik Dasu
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#undef DEBUG
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include "soc.h"
|
||||
#include "clock.h"
|
||||
#include "clock3xxx.h"
|
||||
#include "prm2xxx_3xxx.h"
|
||||
#include "prm-regbits-34xx.h"
|
||||
#include "cm2xxx_3xxx.h"
|
||||
#include "cm-regbits-34xx.h"
|
||||
|
||||
/*
|
||||
* DPLL5_FREQ_FOR_USBHOST: USBHOST and USBTLL are the only clocks
|
||||
* that are sourced by DPLL5, and both of these require this clock
|
||||
* to be at 120 MHz for proper operation.
|
||||
*/
|
||||
#define DPLL5_FREQ_FOR_USBHOST 120000000
|
||||
|
||||
/* needed by omap3_core_dpll_m2_set_rate() */
|
||||
struct clk *sdrc_ick_p, *arm_fck_p;
|
||||
|
||||
/**
|
||||
* omap3_dpll4_set_rate - set rate for omap3 per-dpll
|
||||
* @hw: clock to change
|
||||
* @rate: target rate for clock
|
||||
* @parent_rate: rate of the parent clock
|
||||
*
|
||||
* Check if the current SoC supports the per-dpll reprogram operation
|
||||
* or not, and then do the rate change if supported. Returns -EINVAL
|
||||
* if not supported, 0 for success, and potential error codes from the
|
||||
* clock rate change.
|
||||
*/
|
||||
int omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
/*
|
||||
* According to the 12-5 CDP code from TI, "Limitation 2.5"
|
||||
* on 3430ES1 prevents us from changing DPLL multipliers or dividers
|
||||
* on DPLL4.
|
||||
*/
|
||||
if (ti_clk_features.flags & TI_CLK_DPLL4_DENY_REPROGRAM) {
|
||||
pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return omap3_noncore_dpll_set_rate(hw, rate, parent_rate);
|
||||
}
|
||||
|
||||
/**
|
||||
* omap3_dpll4_set_rate_and_parent - set rate and parent for omap3 per-dpll
|
||||
* @hw: clock to change
|
||||
* @rate: target rate for clock
|
||||
* @parent_rate: rate of the parent clock
|
||||
* @index: parent index, 0 - reference clock, 1 - bypass clock
|
||||
*
|
||||
* Check if the current SoC support the per-dpll reprogram operation
|
||||
* or not, and then do the rate + parent change if supported. Returns
|
||||
* -EINVAL if not supported, 0 for success, and potential error codes
|
||||
* from the clock rate change.
|
||||
*/
|
||||
int omap3_dpll4_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate, u8 index)
|
||||
{
|
||||
if (ti_clk_features.flags & TI_CLK_DPLL4_DENY_REPROGRAM) {
|
||||
pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return omap3_noncore_dpll_set_rate_and_parent(hw, rate, parent_rate,
|
||||
index);
|
||||
}
|
||||
|
||||
void __init omap3_clk_lock_dpll5(void)
|
||||
{
|
||||
struct clk *dpll5_clk;
|
||||
struct clk *dpll5_m2_clk;
|
||||
|
||||
dpll5_clk = clk_get(NULL, "dpll5_ck");
|
||||
clk_set_rate(dpll5_clk, DPLL5_FREQ_FOR_USBHOST);
|
||||
clk_prepare_enable(dpll5_clk);
|
||||
|
||||
/* Program dpll5_m2_clk divider for no division */
|
||||
dpll5_m2_clk = clk_get(NULL, "dpll5_m2_ck");
|
||||
clk_prepare_enable(dpll5_m2_clk);
|
||||
clk_set_rate(dpll5_m2_clk, DPLL5_FREQ_FOR_USBHOST);
|
||||
|
||||
clk_disable_unprepare(dpll5_m2_clk);
|
||||
clk_disable_unprepare(dpll5_clk);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Common clock code */
|
||||
|
||||
/*
|
||||
* Switch the MPU rate if specified on cmdline. We cannot do this
|
||||
* early until cmdline is parsed. XXX This should be removed from the
|
||||
* clock code and handled by the OPP layer code in the near future.
|
||||
*/
|
||||
static int __init omap3xxx_clk_arch_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!cpu_is_omap34xx())
|
||||
return 0;
|
||||
|
||||
ret = omap2_clk_switch_mpurate_at_boot("dpll1_ck");
|
||||
if (!ret)
|
||||
omap2_clk_print_new_rates("osc_sys_ck", "core_ck", "arm_fck");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
omap_arch_initcall(omap3xxx_clk_arch_init);
|
||||
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
* OMAP4 clock function prototypes and macros
|
||||
*
|
||||
* Copyright (C) 2009 Texas Instruments, Inc.
|
||||
* Copyright (C) 2010 Nokia Corporation
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_ARM_MACH_OMAP2_CLOCK44XX_H
|
||||
#define __ARCH_ARM_MACH_OMAP2_CLOCK44XX_H
|
||||
|
||||
/*
|
||||
* OMAP4430_REGM4XEN_MULT: If the CM_CLKMODE_DPLL_ABE.DPLL_REGM4XEN bit is
|
||||
* set, then the DPLL's lock frequency is multiplied by 4 (OMAP4430 TRM
|
||||
* vV Section 3.6.3.3.1 "DPLLs Output Clocks Parameters")
|
||||
*/
|
||||
#define OMAP4430_REGM4XEN_MULT 4
|
||||
|
||||
int omap4xxx_clk_init(void);
|
||||
|
||||
#endif
|
|
@ -1,115 +0,0 @@
|
|||
/*
|
||||
* linux/arch/arm/mach-omap2/clock_common_data.c
|
||||
*
|
||||
* Copyright (C) 2005-2009 Texas Instruments, Inc.
|
||||
* Copyright (C) 2004-2009 Nokia Corporation
|
||||
*
|
||||
* Contacts:
|
||||
* Richard Woodruff <r-woodruff2@ti.com>
|
||||
* Paul Walmsley
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This file contains clock data that is common to both the OMAP2xxx and
|
||||
* OMAP3xxx clock definition files.
|
||||
*/
|
||||
|
||||
#include "clock.h"
|
||||
|
||||
/* clksel_rate data common to 24xx/343x */
|
||||
const struct clksel_rate gpt_32k_rates[] = {
|
||||
{ .div = 1, .val = 0, .flags = RATE_IN_24XX | RATE_IN_3XXX },
|
||||
{ .div = 0 }
|
||||
};
|
||||
|
||||
const struct clksel_rate gpt_sys_rates[] = {
|
||||
{ .div = 1, .val = 1, .flags = RATE_IN_24XX | RATE_IN_3XXX },
|
||||
{ .div = 0 }
|
||||
};
|
||||
|
||||
const struct clksel_rate gfx_l3_rates[] = {
|
||||
{ .div = 1, .val = 1, .flags = RATE_IN_24XX | RATE_IN_3XXX },
|
||||
{ .div = 2, .val = 2, .flags = RATE_IN_24XX | RATE_IN_3XXX },
|
||||
{ .div = 3, .val = 3, .flags = RATE_IN_243X | RATE_IN_3XXX },
|
||||
{ .div = 4, .val = 4, .flags = RATE_IN_243X | RATE_IN_3XXX },
|
||||
{ .div = 0 }
|
||||
};
|
||||
|
||||
const struct clksel_rate dsp_ick_rates[] = {
|
||||
{ .div = 1, .val = 1, .flags = RATE_IN_24XX },
|
||||
{ .div = 2, .val = 2, .flags = RATE_IN_24XX },
|
||||
{ .div = 3, .val = 3, .flags = RATE_IN_243X },
|
||||
{ .div = 0 },
|
||||
};
|
||||
|
||||
|
||||
/* clksel_rate blocks shared between OMAP44xx and AM33xx */
|
||||
|
||||
const struct clksel_rate div_1_0_rates[] = {
|
||||
{ .div = 1, .val = 0, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 0 },
|
||||
};
|
||||
|
||||
const struct clksel_rate div3_1to4_rates[] = {
|
||||
{ .div = 1, .val = 0, .flags = RATE_IN_4430 },
|
||||
{ .div = 2, .val = 1, .flags = RATE_IN_4430 },
|
||||
{ .div = 4, .val = 2, .flags = RATE_IN_4430 },
|
||||
{ .div = 0 },
|
||||
};
|
||||
|
||||
const struct clksel_rate div_1_1_rates[] = {
|
||||
{ .div = 1, .val = 1, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 0 },
|
||||
};
|
||||
|
||||
const struct clksel_rate div_1_2_rates[] = {
|
||||
{ .div = 1, .val = 2, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 0 },
|
||||
};
|
||||
|
||||
const struct clksel_rate div_1_3_rates[] = {
|
||||
{ .div = 1, .val = 3, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 0 },
|
||||
};
|
||||
|
||||
const struct clksel_rate div_1_4_rates[] = {
|
||||
{ .div = 1, .val = 4, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 0 },
|
||||
};
|
||||
|
||||
const struct clksel_rate div31_1to31_rates[] = {
|
||||
{ .div = 1, .val = 1, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 2, .val = 2, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 3, .val = 3, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 4, .val = 4, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 5, .val = 5, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 6, .val = 6, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 7, .val = 7, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 8, .val = 8, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 9, .val = 9, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 10, .val = 10, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 11, .val = 11, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 12, .val = 12, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 13, .val = 13, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 14, .val = 14, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 15, .val = 15, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 16, .val = 16, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 17, .val = 17, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 18, .val = 18, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 19, .val = 19, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 20, .val = 20, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 21, .val = 21, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 22, .val = 22, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 23, .val = 23, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 24, .val = 24, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 25, .val = 25, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 26, .val = 26, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 27, .val = 27, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 28, .val = 28, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 29, .val = 29, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 30, .val = 30, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 31, .val = 31, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
|
||||
{ .div = 0 },
|
||||
};
|
|
@ -37,7 +37,6 @@
|
|||
#include "clock.h"
|
||||
#include "clock2xxx.h"
|
||||
#include "clock3xxx.h"
|
||||
#include "clock44xx.h"
|
||||
#include "omap-pm.h"
|
||||
#include "sdrc.h"
|
||||
#include "control.h"
|
||||
|
@ -723,6 +722,8 @@ int __init omap_clk_init(void)
|
|||
|
||||
ti_clk_init_features();
|
||||
|
||||
omap2_clk_setup_ll_ops();
|
||||
|
||||
if (of_have_populated_dt()) {
|
||||
ret = omap_control_init();
|
||||
if (ret)
|
||||
|
|
|
@ -130,6 +130,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <linux/sysfs.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/time.h>
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include <linux/of_platform.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/mbus.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clocksource.h>
|
||||
#include <asm/system_misc.h>
|
||||
#include <asm/mach/arch.h>
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/serial_core.h>
|
||||
|
|
|
@ -8,6 +8,7 @@ menuconfig ARCH_TEGRA
|
|||
select HAVE_ARM_SCU if SMP
|
||||
select HAVE_ARM_TWD if SMP
|
||||
select PINCTRL
|
||||
select PM_OPP
|
||||
select ARCH_HAS_RESET_CONTROLLER
|
||||
select RESET_CONTROLLER
|
||||
select SOC_BUS
|
||||
|
|
|
@ -72,21 +72,12 @@ void __init ux500_init_irq(void)
|
|||
* Init clocks here so that they are available for system timer
|
||||
* initialization.
|
||||
*/
|
||||
if (cpu_is_u8500_family()) {
|
||||
u8500_of_clk_init(U8500_CLKRST1_BASE,
|
||||
U8500_CLKRST2_BASE,
|
||||
U8500_CLKRST3_BASE,
|
||||
U8500_CLKRST5_BASE,
|
||||
U8500_CLKRST6_BASE);
|
||||
} else if (cpu_is_u9540()) {
|
||||
u9540_clk_init(U8500_CLKRST1_BASE, U8500_CLKRST2_BASE,
|
||||
U8500_CLKRST3_BASE, U8500_CLKRST5_BASE,
|
||||
U8500_CLKRST6_BASE);
|
||||
} else if (cpu_is_u8540()) {
|
||||
u8540_clk_init(U8500_CLKRST1_BASE, U8500_CLKRST2_BASE,
|
||||
U8500_CLKRST3_BASE, U8500_CLKRST5_BASE,
|
||||
U8500_CLKRST6_BASE);
|
||||
}
|
||||
if (cpu_is_u8500_family())
|
||||
u8500_clk_init();
|
||||
else if (cpu_is_u9540())
|
||||
u9540_clk_init();
|
||||
else if (cpu_is_u8540())
|
||||
u8540_clk_init();
|
||||
}
|
||||
|
||||
static const char * __init ux500_get_machine(void)
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
#include <linux/kexec.h>
|
||||
#include <linux/crash_dump.h>
|
||||
#include <linux/root_dev.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/smp.h>
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -389,12 +390,11 @@ static long alchemy_calc_div(unsigned long rate, unsigned long prate,
|
|||
return div1;
|
||||
}
|
||||
|
||||
static long alchemy_clk_fgcs_detr(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_clk,
|
||||
int scale, int maxdiv)
|
||||
static int alchemy_clk_fgcs_detr(struct clk_hw *hw,
|
||||
struct clk_rate_request *req,
|
||||
int scale, int maxdiv)
|
||||
{
|
||||
struct clk *pc, *bpc, *free;
|
||||
struct clk_hw *pc, *bpc, *free;
|
||||
long tdv, tpr, pr, nr, br, bpr, diff, lastdiff;
|
||||
int j;
|
||||
|
||||
|
@ -408,7 +408,7 @@ static long alchemy_clk_fgcs_detr(struct clk_hw *hw, unsigned long rate,
|
|||
* the one that gets closest to but not over the requested rate.
|
||||
*/
|
||||
for (j = 0; j < 7; j++) {
|
||||
pc = clk_get_parent_by_index(hw->clk, j);
|
||||
pc = clk_hw_get_parent_by_index(hw, j);
|
||||
if (!pc)
|
||||
break;
|
||||
|
||||
|
@ -416,20 +416,20 @@ static long alchemy_clk_fgcs_detr(struct clk_hw *hw, unsigned long rate,
|
|||
* XXX: we would actually want clk_has_active_children()
|
||||
* but this is a good-enough approximation for now.
|
||||
*/
|
||||
if (!__clk_is_prepared(pc)) {
|
||||
if (!clk_hw_is_prepared(pc)) {
|
||||
if (!free)
|
||||
free = pc;
|
||||
}
|
||||
|
||||
pr = clk_get_rate(pc);
|
||||
if (pr < rate)
|
||||
pr = clk_hw_get_rate(pc);
|
||||
if (pr < req->rate)
|
||||
continue;
|
||||
|
||||
/* what can hardware actually provide */
|
||||
tdv = alchemy_calc_div(rate, pr, scale, maxdiv, NULL);
|
||||
tdv = alchemy_calc_div(req->rate, pr, scale, maxdiv, NULL);
|
||||
nr = pr / tdv;
|
||||
diff = rate - nr;
|
||||
if (nr > rate)
|
||||
diff = req->rate - nr;
|
||||
if (nr > req->rate)
|
||||
continue;
|
||||
|
||||
if (diff < lastdiff) {
|
||||
|
@ -448,15 +448,16 @@ static long alchemy_clk_fgcs_detr(struct clk_hw *hw, unsigned long rate,
|
|||
*/
|
||||
if (lastdiff && free) {
|
||||
for (j = (maxdiv == 4) ? 1 : scale; j <= maxdiv; j += scale) {
|
||||
tpr = rate * j;
|
||||
tpr = req->rate * j;
|
||||
if (tpr < 0)
|
||||
break;
|
||||
pr = clk_round_rate(free, tpr);
|
||||
pr = clk_hw_round_rate(free, tpr);
|
||||
|
||||
tdv = alchemy_calc_div(rate, pr, scale, maxdiv, NULL);
|
||||
tdv = alchemy_calc_div(req->rate, pr, scale, maxdiv,
|
||||
NULL);
|
||||
nr = pr / tdv;
|
||||
diff = rate - nr;
|
||||
if (nr > rate)
|
||||
diff = req->rate - nr;
|
||||
if (nr > req->rate)
|
||||
continue;
|
||||
if (diff < lastdiff) {
|
||||
lastdiff = diff;
|
||||
|
@ -469,9 +470,14 @@ static long alchemy_clk_fgcs_detr(struct clk_hw *hw, unsigned long rate,
|
|||
}
|
||||
}
|
||||
|
||||
*best_parent_rate = bpr;
|
||||
*best_parent_clk = __clk_get_hw(bpc);
|
||||
return br;
|
||||
if (br < 0)
|
||||
return br;
|
||||
|
||||
req->best_parent_rate = bpr;
|
||||
req->best_parent_hw = bpc;
|
||||
req->rate = br;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int alchemy_clk_fgv1_en(struct clk_hw *hw)
|
||||
|
@ -562,14 +568,10 @@ static unsigned long alchemy_clk_fgv1_recalc(struct clk_hw *hw,
|
|||
return parent_rate / v;
|
||||
}
|
||||
|
||||
static long alchemy_clk_fgv1_detr(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_clk)
|
||||
static int alchemy_clk_fgv1_detr(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
return alchemy_clk_fgcs_detr(hw, rate, best_parent_rate,
|
||||
best_parent_clk, 2, 512);
|
||||
return alchemy_clk_fgcs_detr(hw, req, 2, 512);
|
||||
}
|
||||
|
||||
/* Au1000, Au1100, Au15x0, Au12x0 */
|
||||
|
@ -696,11 +698,8 @@ static unsigned long alchemy_clk_fgv2_recalc(struct clk_hw *hw,
|
|||
return t;
|
||||
}
|
||||
|
||||
static long alchemy_clk_fgv2_detr(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_clk)
|
||||
static int alchemy_clk_fgv2_detr(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct alchemy_fgcs_clk *c = to_fgcs_clk(hw);
|
||||
int scale, maxdiv;
|
||||
|
@ -713,8 +712,7 @@ static long alchemy_clk_fgv2_detr(struct clk_hw *hw, unsigned long rate,
|
|||
maxdiv = 512;
|
||||
}
|
||||
|
||||
return alchemy_clk_fgcs_detr(hw, rate, best_parent_rate,
|
||||
best_parent_clk, scale, maxdiv);
|
||||
return alchemy_clk_fgcs_detr(hw, req, scale, maxdiv);
|
||||
}
|
||||
|
||||
/* Au1300 larger input mux, no separate disable bit, flexible divider */
|
||||
|
@ -917,17 +915,13 @@ static int alchemy_clk_csrc_setr(struct clk_hw *hw, unsigned long rate,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static long alchemy_clk_csrc_detr(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_clk)
|
||||
static int alchemy_clk_csrc_detr(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct alchemy_fgcs_clk *c = to_fgcs_clk(hw);
|
||||
int scale = c->dt[2] == 3 ? 1 : 2; /* au1300 check */
|
||||
|
||||
return alchemy_clk_fgcs_detr(hw, rate, best_parent_rate,
|
||||
best_parent_clk, scale, 4);
|
||||
return alchemy_clk_fgcs_detr(hw, req, scale, 4);
|
||||
}
|
||||
|
||||
static struct clk_ops alchemy_clkops_csrc = {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/device.h>
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include <linux/clkdev.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/pm.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
|
|
|
@ -9,7 +9,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-gate.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_COMMON_CLK) += clk-gpio-gate.o
|
||||
obj-$(CONFIG_COMMON_CLK) += clk-gpio.o
|
||||
ifeq ($(CONFIG_OF), y)
|
||||
obj-$(CONFIG_COMMON_CLK) += clk-conf.o
|
||||
endif
|
||||
|
|
|
@ -614,17 +614,12 @@ void __init of_at91sam9x5_clk_main_setup(struct device_node *np,
|
|||
int num_parents;
|
||||
unsigned int irq;
|
||||
const char *name = np->name;
|
||||
int i;
|
||||
|
||||
num_parents = of_clk_get_parent_count(np);
|
||||
if (num_parents <= 0 || num_parents > 2)
|
||||
return;
|
||||
|
||||
for (i = 0; i < num_parents; ++i) {
|
||||
parent_names[i] = of_clk_get_parent_name(np, i);
|
||||
if (!parent_names[i])
|
||||
return;
|
||||
}
|
||||
of_clk_parent_fill(np, parent_names, num_parents);
|
||||
|
||||
of_property_read_string(np, "clock-output-names", &name);
|
||||
|
||||
|
|
|
@ -222,7 +222,6 @@ of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc,
|
|||
{
|
||||
struct clk *clk;
|
||||
int num_parents;
|
||||
int i;
|
||||
unsigned int irq;
|
||||
const char *parent_names[MASTER_SOURCE_MAX];
|
||||
const char *name = np->name;
|
||||
|
@ -232,11 +231,7 @@ of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc,
|
|||
if (num_parents <= 0 || num_parents > MASTER_SOURCE_MAX)
|
||||
return;
|
||||
|
||||
for (i = 0; i < num_parents; ++i) {
|
||||
parent_names[i] = of_clk_get_parent_name(np, i);
|
||||
if (!parent_names[i])
|
||||
return;
|
||||
}
|
||||
of_clk_parent_fill(np, parent_names, num_parents);
|
||||
|
||||
of_property_read_string(np, "clock-output-names", &name);
|
||||
|
||||
|
|
|
@ -134,7 +134,7 @@ at91_clk_register_peripheral(struct at91_pmc *pmc, const char *name,
|
|||
|
||||
static void clk_sam9x5_peripheral_autodiv(struct clk_sam9x5_peripheral *periph)
|
||||
{
|
||||
struct clk *parent;
|
||||
struct clk_hw *parent;
|
||||
unsigned long parent_rate;
|
||||
int shift = 0;
|
||||
|
||||
|
@ -142,8 +142,8 @@ static void clk_sam9x5_peripheral_autodiv(struct clk_sam9x5_peripheral *periph)
|
|||
return;
|
||||
|
||||
if (periph->range.max) {
|
||||
parent = clk_get_parent_by_index(periph->hw.clk, 0);
|
||||
parent_rate = __clk_get_rate(parent);
|
||||
parent = clk_hw_get_parent_by_index(&periph->hw, 0);
|
||||
parent_rate = clk_hw_get_rate(parent);
|
||||
if (!parent_rate)
|
||||
return;
|
||||
|
||||
|
|
|
@ -54,46 +54,47 @@ static unsigned long clk_programmable_recalc_rate(struct clk_hw *hw,
|
|||
return parent_rate >> pres;
|
||||
}
|
||||
|
||||
static long clk_programmable_determine_rate(struct clk_hw *hw,
|
||||
unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_hw)
|
||||
static int clk_programmable_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk *parent = NULL;
|
||||
struct clk_hw *parent;
|
||||
long best_rate = -EINVAL;
|
||||
unsigned long parent_rate;
|
||||
unsigned long tmp_rate;
|
||||
int shift;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < __clk_get_num_parents(hw->clk); i++) {
|
||||
parent = clk_get_parent_by_index(hw->clk, i);
|
||||
for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
|
||||
parent = clk_hw_get_parent_by_index(hw, i);
|
||||
if (!parent)
|
||||
continue;
|
||||
|
||||
parent_rate = __clk_get_rate(parent);
|
||||
parent_rate = clk_hw_get_rate(parent);
|
||||
for (shift = 0; shift < PROG_PRES_MASK; shift++) {
|
||||
tmp_rate = parent_rate >> shift;
|
||||
if (tmp_rate <= rate)
|
||||
if (tmp_rate <= req->rate)
|
||||
break;
|
||||
}
|
||||
|
||||
if (tmp_rate > rate)
|
||||
if (tmp_rate > req->rate)
|
||||
continue;
|
||||
|
||||
if (best_rate < 0 || (rate - tmp_rate) < (rate - best_rate)) {
|
||||
if (best_rate < 0 ||
|
||||
(req->rate - tmp_rate) < (req->rate - best_rate)) {
|
||||
best_rate = tmp_rate;
|
||||
*best_parent_rate = parent_rate;
|
||||
*best_parent_hw = __clk_get_hw(parent);
|
||||
req->best_parent_rate = parent_rate;
|
||||
req->best_parent_hw = parent;
|
||||
}
|
||||
|
||||
if (!best_rate)
|
||||
break;
|
||||
}
|
||||
|
||||
return best_rate;
|
||||
if (best_rate < 0)
|
||||
return best_rate;
|
||||
|
||||
req->rate = best_rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_programmable_set_parent(struct clk_hw *hw, u8 index)
|
||||
|
@ -230,7 +231,6 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc,
|
|||
{
|
||||
int num;
|
||||
u32 id;
|
||||
int i;
|
||||
struct clk *clk;
|
||||
int num_parents;
|
||||
const char *parent_names[PROG_SOURCE_MAX];
|
||||
|
@ -241,11 +241,7 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc,
|
|||
if (num_parents <= 0 || num_parents > PROG_SOURCE_MAX)
|
||||
return;
|
||||
|
||||
for (i = 0; i < num_parents; ++i) {
|
||||
parent_names[i] = of_clk_get_parent_name(np, i);
|
||||
if (!parent_names[i])
|
||||
return;
|
||||
}
|
||||
of_clk_parent_fill(np, parent_names, num_parents);
|
||||
|
||||
num = of_get_child_count(np);
|
||||
if (!num || num > (PROG_ID_MAX + 1))
|
||||
|
|
|
@ -10,8 +10,10 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk/at91_pmc.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/of.h>
|
||||
|
@ -371,17 +373,12 @@ void __init of_at91sam9x5_clk_slow_setup(struct device_node *np,
|
|||
const char *parent_names[2];
|
||||
int num_parents;
|
||||
const char *name = np->name;
|
||||
int i;
|
||||
|
||||
num_parents = of_clk_get_parent_count(np);
|
||||
if (num_parents <= 0 || num_parents > 2)
|
||||
return;
|
||||
|
||||
for (i = 0; i < num_parents; ++i) {
|
||||
parent_names[i] = of_clk_get_parent_name(np, i);
|
||||
if (!parent_names[i])
|
||||
return;
|
||||
}
|
||||
of_clk_parent_fill(np, parent_names, num_parents);
|
||||
|
||||
of_property_read_string(np, "clock-output-names", &name);
|
||||
|
||||
|
@ -449,17 +446,12 @@ void __init of_at91sam9260_clk_slow_setup(struct device_node *np,
|
|||
const char *parent_names[2];
|
||||
int num_parents;
|
||||
const char *name = np->name;
|
||||
int i;
|
||||
|
||||
num_parents = of_clk_get_parent_count(np);
|
||||
if (num_parents != 2)
|
||||
return;
|
||||
|
||||
for (i = 0; i < num_parents; ++i) {
|
||||
parent_names[i] = of_clk_get_parent_name(np, i);
|
||||
if (!parent_names[i])
|
||||
return;
|
||||
}
|
||||
of_clk_parent_fill(np, parent_names, num_parents);
|
||||
|
||||
of_property_read_string(np, "clock-output-names", &name);
|
||||
|
||||
|
|
|
@ -145,7 +145,6 @@ void __init of_at91sam9x5_clk_smd_setup(struct device_node *np,
|
|||
struct at91_pmc *pmc)
|
||||
{
|
||||
struct clk *clk;
|
||||
int i;
|
||||
int num_parents;
|
||||
const char *parent_names[SMD_SOURCE_MAX];
|
||||
const char *name = np->name;
|
||||
|
@ -154,11 +153,7 @@ void __init of_at91sam9x5_clk_smd_setup(struct device_node *np,
|
|||
if (num_parents <= 0 || num_parents > SMD_SOURCE_MAX)
|
||||
return;
|
||||
|
||||
for (i = 0; i < num_parents; i++) {
|
||||
parent_names[i] = of_clk_get_parent_name(np, i);
|
||||
if (!parent_names[i])
|
||||
return;
|
||||
}
|
||||
of_clk_parent_fill(np, parent_names, num_parents);
|
||||
|
||||
of_property_read_string(np, "clock-output-names", &name);
|
||||
|
||||
|
|
|
@ -56,47 +56,43 @@ static unsigned long at91sam9x5_clk_usb_recalc_rate(struct clk_hw *hw,
|
|||
return DIV_ROUND_CLOSEST(parent_rate, (usbdiv + 1));
|
||||
}
|
||||
|
||||
static long at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw,
|
||||
unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_hw)
|
||||
static int at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk *parent = NULL;
|
||||
struct clk_hw *parent;
|
||||
long best_rate = -EINVAL;
|
||||
unsigned long tmp_rate;
|
||||
int best_diff = -1;
|
||||
int tmp_diff;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < __clk_get_num_parents(hw->clk); i++) {
|
||||
for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
|
||||
int div;
|
||||
|
||||
parent = clk_get_parent_by_index(hw->clk, i);
|
||||
parent = clk_hw_get_parent_by_index(hw, i);
|
||||
if (!parent)
|
||||
continue;
|
||||
|
||||
for (div = 1; div < SAM9X5_USB_MAX_DIV + 2; div++) {
|
||||
unsigned long tmp_parent_rate;
|
||||
|
||||
tmp_parent_rate = rate * div;
|
||||
tmp_parent_rate = __clk_round_rate(parent,
|
||||
tmp_parent_rate = req->rate * div;
|
||||
tmp_parent_rate = clk_hw_round_rate(parent,
|
||||
tmp_parent_rate);
|
||||
tmp_rate = DIV_ROUND_CLOSEST(tmp_parent_rate, div);
|
||||
if (tmp_rate < rate)
|
||||
tmp_diff = rate - tmp_rate;
|
||||
if (tmp_rate < req->rate)
|
||||
tmp_diff = req->rate - tmp_rate;
|
||||
else
|
||||
tmp_diff = tmp_rate - rate;
|
||||
tmp_diff = tmp_rate - req->rate;
|
||||
|
||||
if (best_diff < 0 || best_diff > tmp_diff) {
|
||||
best_rate = tmp_rate;
|
||||
best_diff = tmp_diff;
|
||||
*best_parent_rate = tmp_parent_rate;
|
||||
*best_parent_hw = __clk_get_hw(parent);
|
||||
req->best_parent_rate = tmp_parent_rate;
|
||||
req->best_parent_hw = parent;
|
||||
}
|
||||
|
||||
if (!best_diff || tmp_rate < rate)
|
||||
if (!best_diff || tmp_rate < req->rate)
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -104,7 +100,11 @@ static long at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw,
|
|||
break;
|
||||
}
|
||||
|
||||
return best_rate;
|
||||
if (best_rate < 0)
|
||||
return best_rate;
|
||||
|
||||
req->rate = best_rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int at91sam9x5_clk_usb_set_parent(struct clk_hw *hw, u8 index)
|
||||
|
@ -273,7 +273,7 @@ static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||
unsigned long *parent_rate)
|
||||
{
|
||||
struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw);
|
||||
struct clk *parent = __clk_get_parent(hw->clk);
|
||||
struct clk_hw *parent = clk_hw_get_parent(hw);
|
||||
unsigned long bestrate = 0;
|
||||
int bestdiff = -1;
|
||||
unsigned long tmprate;
|
||||
|
@ -287,7 +287,7 @@ static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||
continue;
|
||||
|
||||
tmp_parent_rate = rate * usb->divisors[i];
|
||||
tmp_parent_rate = __clk_round_rate(parent, tmp_parent_rate);
|
||||
tmp_parent_rate = clk_hw_round_rate(parent, tmp_parent_rate);
|
||||
tmprate = DIV_ROUND_CLOSEST(tmp_parent_rate, usb->divisors[i]);
|
||||
if (tmprate < rate)
|
||||
tmpdiff = rate - tmprate;
|
||||
|
@ -373,7 +373,6 @@ void __init of_at91sam9x5_clk_usb_setup(struct device_node *np,
|
|||
struct at91_pmc *pmc)
|
||||
{
|
||||
struct clk *clk;
|
||||
int i;
|
||||
int num_parents;
|
||||
const char *parent_names[USB_SOURCE_MAX];
|
||||
const char *name = np->name;
|
||||
|
@ -382,11 +381,7 @@ void __init of_at91sam9x5_clk_usb_setup(struct device_node *np,
|
|||
if (num_parents <= 0 || num_parents > USB_SOURCE_MAX)
|
||||
return;
|
||||
|
||||
for (i = 0; i < num_parents; i++) {
|
||||
parent_names[i] = of_clk_get_parent_name(np, i);
|
||||
if (!parent_names[i])
|
||||
return;
|
||||
}
|
||||
of_clk_parent_fill(np, parent_names, num_parents);
|
||||
|
||||
of_property_read_string(np, "clock-output-names", &name);
|
||||
|
||||
|
|
|
@ -125,7 +125,6 @@ static int pmc_irq_map(struct irq_domain *h, unsigned int virq,
|
|||
|
||||
irq_set_chip_and_handler(virq, &pmc_irq,
|
||||
handle_level_irq);
|
||||
set_irq_flags(virq, IRQF_VALID);
|
||||
irq_set_chip_data(virq, pmc);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -59,71 +59,63 @@ static inline void pmc_write(struct at91_pmc *pmc, int offset, u32 value)
|
|||
int of_at91_get_clk_range(struct device_node *np, const char *propname,
|
||||
struct clk_range *range);
|
||||
|
||||
extern void __init of_at91sam9260_clk_slow_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91sam9260_clk_slow_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
|
||||
extern void __init of_at91rm9200_clk_main_osc_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
extern void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
extern void __init of_at91rm9200_clk_main_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
extern void __init of_at91sam9x5_clk_main_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91rm9200_clk_main_osc_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91rm9200_clk_main_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91sam9x5_clk_main_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
|
||||
extern void __init of_at91rm9200_clk_pll_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
extern void __init of_at91sam9g45_clk_pll_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
extern void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
extern void __init of_sama5d3_clk_pll_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
extern void __init of_at91sam9x5_clk_plldiv_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91rm9200_clk_pll_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91sam9g45_clk_pll_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91sam9g20_clk_pllb_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_sama5d3_clk_pll_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91sam9x5_clk_plldiv_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
|
||||
extern void __init of_at91rm9200_clk_master_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
extern void __init of_at91sam9x5_clk_master_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91rm9200_clk_master_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91sam9x5_clk_master_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
|
||||
extern void __init of_at91rm9200_clk_sys_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91rm9200_clk_sys_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
|
||||
extern void __init of_at91rm9200_clk_periph_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
extern void __init of_at91sam9x5_clk_periph_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91rm9200_clk_periph_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91sam9x5_clk_periph_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
|
||||
extern void __init of_at91rm9200_clk_prog_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
extern void __init of_at91sam9g45_clk_prog_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
extern void __init of_at91sam9x5_clk_prog_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91rm9200_clk_prog_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91sam9g45_clk_prog_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91sam9x5_clk_prog_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
|
||||
#if defined(CONFIG_HAVE_AT91_UTMI)
|
||||
extern void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
#endif
|
||||
void of_at91sam9x5_clk_utmi_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
|
||||
#if defined(CONFIG_HAVE_AT91_USB_CLK)
|
||||
extern void __init of_at91rm9200_clk_usb_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
extern void __init of_at91sam9x5_clk_usb_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
extern void __init of_at91sam9n12_clk_usb_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
#endif
|
||||
void of_at91rm9200_clk_usb_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91sam9x5_clk_usb_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
void of_at91sam9n12_clk_usb_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
|
||||
#if defined(CONFIG_HAVE_AT91_SMD)
|
||||
extern void __init of_at91sam9x5_clk_smd_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
#endif
|
||||
void of_at91sam9x5_clk_smd_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
|
||||
#if defined(CONFIG_HAVE_AT91_H32MX)
|
||||
extern void __init of_sama5d4_clk_h32mx_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
#endif
|
||||
void of_sama5d4_clk_h32mx_setup(struct device_node *np,
|
||||
struct at91_pmc *pmc);
|
||||
|
||||
#endif /* __PMC_H_ */
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
/*
|
||||
* "Policies" affect the frequencies of bus clocks provided by a
|
||||
|
@ -1010,25 +1011,23 @@ static long kona_peri_clk_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||
struct bcm_clk_div *div = &bcm_clk->u.peri->div;
|
||||
|
||||
if (!divider_exists(div))
|
||||
return __clk_get_rate(hw->clk);
|
||||
return clk_hw_get_rate(hw);
|
||||
|
||||
/* Quietly avoid a zero rate */
|
||||
return round_rate(bcm_clk->ccu, div, &bcm_clk->u.peri->pre_div,
|
||||
rate ? rate : 1, *parent_rate, NULL);
|
||||
}
|
||||
|
||||
static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate, struct clk_hw **best_parent)
|
||||
static int kona_peri_clk_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct kona_clk *bcm_clk = to_kona_clk(hw);
|
||||
struct clk *clk = hw->clk;
|
||||
struct clk *current_parent;
|
||||
struct clk_hw *current_parent;
|
||||
unsigned long parent_rate;
|
||||
unsigned long best_delta;
|
||||
unsigned long best_rate;
|
||||
u32 parent_count;
|
||||
long rate;
|
||||
u32 which;
|
||||
|
||||
/*
|
||||
|
@ -1037,18 +1036,25 @@ static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
|
|||
*/
|
||||
WARN_ON_ONCE(bcm_clk->init_data.flags & CLK_SET_RATE_NO_REPARENT);
|
||||
parent_count = (u32)bcm_clk->init_data.num_parents;
|
||||
if (parent_count < 2)
|
||||
return kona_peri_clk_round_rate(hw, rate, best_parent_rate);
|
||||
if (parent_count < 2) {
|
||||
rate = kona_peri_clk_round_rate(hw, req->rate,
|
||||
&req->best_parent_rate);
|
||||
if (rate < 0)
|
||||
return rate;
|
||||
|
||||
req->rate = rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Unless we can do better, stick with current parent */
|
||||
current_parent = clk_get_parent(clk);
|
||||
parent_rate = __clk_get_rate(current_parent);
|
||||
best_rate = kona_peri_clk_round_rate(hw, rate, &parent_rate);
|
||||
best_delta = abs(best_rate - rate);
|
||||
current_parent = clk_hw_get_parent(hw);
|
||||
parent_rate = clk_hw_get_rate(current_parent);
|
||||
best_rate = kona_peri_clk_round_rate(hw, req->rate, &parent_rate);
|
||||
best_delta = abs(best_rate - req->rate);
|
||||
|
||||
/* Check whether any other parent clock can produce a better result */
|
||||
for (which = 0; which < parent_count; which++) {
|
||||
struct clk *parent = clk_get_parent_by_index(clk, which);
|
||||
struct clk_hw *parent = clk_hw_get_parent_by_index(hw, which);
|
||||
unsigned long delta;
|
||||
unsigned long other_rate;
|
||||
|
||||
|
@ -1057,18 +1063,20 @@ static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
|
|||
continue;
|
||||
|
||||
/* We don't support CLK_SET_RATE_PARENT */
|
||||
parent_rate = __clk_get_rate(parent);
|
||||
other_rate = kona_peri_clk_round_rate(hw, rate, &parent_rate);
|
||||
delta = abs(other_rate - rate);
|
||||
parent_rate = clk_hw_get_rate(parent);
|
||||
other_rate = kona_peri_clk_round_rate(hw, req->rate,
|
||||
&parent_rate);
|
||||
delta = abs(other_rate - req->rate);
|
||||
if (delta < best_delta) {
|
||||
best_delta = delta;
|
||||
best_rate = other_rate;
|
||||
*best_parent = __clk_get_hw(parent);
|
||||
*best_parent_rate = parent_rate;
|
||||
req->best_parent_hw = parent;
|
||||
req->best_parent_rate = parent_rate;
|
||||
}
|
||||
}
|
||||
|
||||
return best_rate;
|
||||
req->rate = best_rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kona_peri_clk_set_parent(struct clk_hw *hw, u8 index)
|
||||
|
@ -1130,7 +1138,7 @@ static int kona_peri_clk_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
if (parent_rate > (unsigned long)LONG_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (rate == __clk_get_rate(hw->clk))
|
||||
if (rate == clk_hw_get_rate(hw))
|
||||
return 0;
|
||||
|
||||
if (!divider_exists(div))
|
||||
|
@ -1249,6 +1257,7 @@ bool __init kona_ccu_init(struct ccu_data *ccu)
|
|||
unsigned long flags;
|
||||
unsigned int which;
|
||||
struct clk **clks = ccu->clk_data.clks;
|
||||
struct kona_clk *kona_clks = ccu->kona_clks;
|
||||
bool success = true;
|
||||
|
||||
flags = ccu_lock(ccu);
|
||||
|
@ -1259,7 +1268,7 @@ bool __init kona_ccu_init(struct ccu_data *ccu)
|
|||
|
||||
if (!clks[which])
|
||||
continue;
|
||||
bcm_clk = to_kona_clk(__clk_get_hw(clks[which]));
|
||||
bcm_clk = &kona_clks[which];
|
||||
success &= __kona_clk_init(bcm_clk);
|
||||
}
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ berlin2_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
|
|||
fbdiv = (val >> map->fbdiv_shift) & FBDIV_MASK;
|
||||
rfdiv = (val >> map->rfdiv_shift) & RFDIV_MASK;
|
||||
if (rfdiv == 0) {
|
||||
pr_warn("%s has zero rfdiv\n", __clk_get_name(hw->clk));
|
||||
pr_warn("%s has zero rfdiv\n", clk_hw_get_name(hw));
|
||||
rfdiv = 1;
|
||||
}
|
||||
|
||||
|
@ -70,7 +70,7 @@ berlin2_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
|
|||
vcodiv = map->vcodiv[vcodivsel];
|
||||
if (vcodiv == 0) {
|
||||
pr_warn("%s has zero vcodiv (index %d)\n",
|
||||
__clk_get_name(hw->clk), vcodivsel);
|
||||
clk_hw_get_name(hw), vcodivsel);
|
||||
vcodiv = 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
|
|
|
@ -32,11 +32,6 @@ void __init bcm2835_init_clocks(void)
|
|||
struct clk *clk;
|
||||
int ret;
|
||||
|
||||
clk = clk_register_fixed_rate(NULL, "sys_pclk", NULL, CLK_IS_ROOT,
|
||||
250000000);
|
||||
if (IS_ERR(clk))
|
||||
pr_err("sys_pclk not registered\n");
|
||||
|
||||
clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT,
|
||||
126000000);
|
||||
if (IS_ERR(clk))
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
|
@ -309,7 +310,7 @@ static long cdce706_divider_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||
if (!mul)
|
||||
div = CDCE706_DIVIDER_DIVIDER_MAX;
|
||||
|
||||
if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) {
|
||||
if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
|
||||
unsigned long best_diff = rate;
|
||||
unsigned long best_div = 0;
|
||||
struct clk *gp_clk = cdce->clkin_clk[cdce->clkin[0].parent];
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* Copyright (C) 2014, Topic Embedded Products
|
||||
* Licenced under GPL
|
||||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/io.h>
|
||||
|
|
|
@ -55,78 +55,77 @@ static unsigned long clk_composite_recalc_rate(struct clk_hw *hw,
|
|||
return rate_ops->recalc_rate(rate_hw, parent_rate);
|
||||
}
|
||||
|
||||
static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_p)
|
||||
static int clk_composite_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_composite *composite = to_clk_composite(hw);
|
||||
const struct clk_ops *rate_ops = composite->rate_ops;
|
||||
const struct clk_ops *mux_ops = composite->mux_ops;
|
||||
struct clk_hw *rate_hw = composite->rate_hw;
|
||||
struct clk_hw *mux_hw = composite->mux_hw;
|
||||
struct clk *parent;
|
||||
struct clk_hw *parent;
|
||||
unsigned long parent_rate;
|
||||
long tmp_rate, best_rate = 0;
|
||||
unsigned long rate_diff;
|
||||
unsigned long best_rate_diff = ULONG_MAX;
|
||||
long rate;
|
||||
int i;
|
||||
|
||||
if (rate_hw && rate_ops && rate_ops->determine_rate) {
|
||||
__clk_hw_set_clk(rate_hw, hw);
|
||||
return rate_ops->determine_rate(rate_hw, rate, min_rate,
|
||||
max_rate,
|
||||
best_parent_rate,
|
||||
best_parent_p);
|
||||
return rate_ops->determine_rate(rate_hw, req);
|
||||
} else if (rate_hw && rate_ops && rate_ops->round_rate &&
|
||||
mux_hw && mux_ops && mux_ops->set_parent) {
|
||||
*best_parent_p = NULL;
|
||||
req->best_parent_hw = NULL;
|
||||
|
||||
if (__clk_get_flags(hw->clk) & CLK_SET_RATE_NO_REPARENT) {
|
||||
parent = clk_get_parent(mux_hw->clk);
|
||||
*best_parent_p = __clk_get_hw(parent);
|
||||
*best_parent_rate = __clk_get_rate(parent);
|
||||
if (clk_hw_get_flags(hw) & CLK_SET_RATE_NO_REPARENT) {
|
||||
parent = clk_hw_get_parent(mux_hw);
|
||||
req->best_parent_hw = parent;
|
||||
req->best_parent_rate = clk_hw_get_rate(parent);
|
||||
|
||||
return rate_ops->round_rate(rate_hw, rate,
|
||||
best_parent_rate);
|
||||
rate = rate_ops->round_rate(rate_hw, req->rate,
|
||||
&req->best_parent_rate);
|
||||
if (rate < 0)
|
||||
return rate;
|
||||
|
||||
req->rate = rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < __clk_get_num_parents(mux_hw->clk); i++) {
|
||||
parent = clk_get_parent_by_index(mux_hw->clk, i);
|
||||
for (i = 0; i < clk_hw_get_num_parents(mux_hw); i++) {
|
||||
parent = clk_hw_get_parent_by_index(mux_hw, i);
|
||||
if (!parent)
|
||||
continue;
|
||||
|
||||
parent_rate = __clk_get_rate(parent);
|
||||
parent_rate = clk_hw_get_rate(parent);
|
||||
|
||||
tmp_rate = rate_ops->round_rate(rate_hw, rate,
|
||||
tmp_rate = rate_ops->round_rate(rate_hw, req->rate,
|
||||
&parent_rate);
|
||||
if (tmp_rate < 0)
|
||||
continue;
|
||||
|
||||
rate_diff = abs(rate - tmp_rate);
|
||||
rate_diff = abs(req->rate - tmp_rate);
|
||||
|
||||
if (!rate_diff || !*best_parent_p
|
||||
if (!rate_diff || !req->best_parent_hw
|
||||
|| best_rate_diff > rate_diff) {
|
||||
*best_parent_p = __clk_get_hw(parent);
|
||||
*best_parent_rate = parent_rate;
|
||||
req->best_parent_hw = parent;
|
||||
req->best_parent_rate = parent_rate;
|
||||
best_rate_diff = rate_diff;
|
||||
best_rate = tmp_rate;
|
||||
}
|
||||
|
||||
if (!rate_diff)
|
||||
return rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return best_rate;
|
||||
req->rate = best_rate;
|
||||
return 0;
|
||||
} else if (mux_hw && mux_ops && mux_ops->determine_rate) {
|
||||
__clk_hw_set_clk(mux_hw, hw);
|
||||
return mux_ops->determine_rate(mux_hw, rate, min_rate,
|
||||
max_rate, best_parent_rate,
|
||||
best_parent_p);
|
||||
return mux_ops->determine_rate(mux_hw, req);
|
||||
} else {
|
||||
pr_err("clk: clk_composite_determine_rate function called, but no mux or rate callback set!\n");
|
||||
return 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -78,12 +78,14 @@ static unsigned int _get_table_div(const struct clk_div_table *table,
|
|||
}
|
||||
|
||||
static unsigned int _get_div(const struct clk_div_table *table,
|
||||
unsigned int val, unsigned long flags)
|
||||
unsigned int val, unsigned long flags, u8 width)
|
||||
{
|
||||
if (flags & CLK_DIVIDER_ONE_BASED)
|
||||
return val;
|
||||
if (flags & CLK_DIVIDER_POWER_OF_TWO)
|
||||
return 1 << val;
|
||||
if (flags & CLK_DIVIDER_MAX_AT_ZERO)
|
||||
return val ? val : div_mask(width) + 1;
|
||||
if (table)
|
||||
return _get_table_div(table, val);
|
||||
return val + 1;
|
||||
|
@ -101,12 +103,14 @@ static unsigned int _get_table_val(const struct clk_div_table *table,
|
|||
}
|
||||
|
||||
static unsigned int _get_val(const struct clk_div_table *table,
|
||||
unsigned int div, unsigned long flags)
|
||||
unsigned int div, unsigned long flags, u8 width)
|
||||
{
|
||||
if (flags & CLK_DIVIDER_ONE_BASED)
|
||||
return div;
|
||||
if (flags & CLK_DIVIDER_POWER_OF_TWO)
|
||||
return __ffs(div);
|
||||
if (flags & CLK_DIVIDER_MAX_AT_ZERO)
|
||||
return (div == div_mask(width) + 1) ? 0 : div;
|
||||
if (table)
|
||||
return _get_table_val(table, div);
|
||||
return div - 1;
|
||||
|
@ -117,13 +121,14 @@ unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate,
|
|||
const struct clk_div_table *table,
|
||||
unsigned long flags)
|
||||
{
|
||||
struct clk_divider *divider = to_clk_divider(hw);
|
||||
unsigned int div;
|
||||
|
||||
div = _get_div(table, val, flags);
|
||||
div = _get_div(table, val, flags, divider->width);
|
||||
if (!div) {
|
||||
WARN(!(flags & CLK_DIVIDER_ALLOW_ZERO),
|
||||
"%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n",
|
||||
__clk_get_name(hw->clk));
|
||||
clk_hw_get_name(hw));
|
||||
return parent_rate;
|
||||
}
|
||||
|
||||
|
@ -285,7 +290,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
|
|||
|
||||
maxdiv = _get_maxdiv(table, width, flags);
|
||||
|
||||
if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
|
||||
if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
|
||||
parent_rate = *best_parent_rate;
|
||||
bestdiv = _div_round(table, parent_rate, rate, flags);
|
||||
bestdiv = bestdiv == 0 ? 1 : bestdiv;
|
||||
|
@ -311,7 +316,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
|
|||
*best_parent_rate = parent_rate_saved;
|
||||
return i;
|
||||
}
|
||||
parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
|
||||
parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw),
|
||||
rate * i);
|
||||
now = DIV_ROUND_UP(parent_rate, i);
|
||||
if (_is_best_div(rate, now, best, flags)) {
|
||||
|
@ -323,7 +328,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
|
|||
|
||||
if (!bestdiv) {
|
||||
bestdiv = _get_maxdiv(table, width, flags);
|
||||
*best_parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 1);
|
||||
*best_parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), 1);
|
||||
}
|
||||
|
||||
return bestdiv;
|
||||
|
@ -351,7 +356,8 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||
if (divider->flags & CLK_DIVIDER_READ_ONLY) {
|
||||
bestdiv = readl(divider->reg) >> divider->shift;
|
||||
bestdiv &= div_mask(divider->width);
|
||||
bestdiv = _get_div(divider->table, bestdiv, divider->flags);
|
||||
bestdiv = _get_div(divider->table, bestdiv, divider->flags,
|
||||
divider->width);
|
||||
return DIV_ROUND_UP(*prate, bestdiv);
|
||||
}
|
||||
|
||||
|
@ -370,7 +376,7 @@ int divider_get_val(unsigned long rate, unsigned long parent_rate,
|
|||
if (!_is_valid_div(table, div, flags))
|
||||
return -EINVAL;
|
||||
|
||||
value = _get_val(table, div, flags);
|
||||
value = _get_val(table, div, flags, width);
|
||||
|
||||
return min_t(unsigned int, value, div_mask(width));
|
||||
}
|
||||
|
@ -389,6 +395,8 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
|
||||
if (divider->lock)
|
||||
spin_lock_irqsave(divider->lock, flags);
|
||||
else
|
||||
__acquire(divider->lock);
|
||||
|
||||
if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
|
||||
val = div_mask(divider->width) << (divider->shift + 16);
|
||||
|
@ -401,6 +409,8 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
|
||||
if (divider->lock)
|
||||
spin_unlock_irqrestore(divider->lock, flags);
|
||||
else
|
||||
__release(divider->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
* the terms of the GNU General Public License version 2 as published by the
|
||||
* Free Software Foundation.
|
||||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/of.h>
|
||||
|
|
|
@ -41,12 +41,11 @@ static long clk_factor_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||
{
|
||||
struct clk_fixed_factor *fix = to_clk_fixed_factor(hw);
|
||||
|
||||
if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) {
|
||||
if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
|
||||
unsigned long best_parent;
|
||||
|
||||
best_parent = (rate / fix->mult) * fix->div;
|
||||
*prate = __clk_round_rate(__clk_get_parent(hw->clk),
|
||||
best_parent);
|
||||
*prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent);
|
||||
}
|
||||
|
||||
return (*prate / fix->div) * fix->mult;
|
||||
|
|
|
@ -27,11 +27,15 @@ static unsigned long clk_fd_recalc_rate(struct clk_hw *hw,
|
|||
|
||||
if (fd->lock)
|
||||
spin_lock_irqsave(fd->lock, flags);
|
||||
else
|
||||
__acquire(fd->lock);
|
||||
|
||||
val = clk_readl(fd->reg);
|
||||
|
||||
if (fd->lock)
|
||||
spin_unlock_irqrestore(fd->lock, flags);
|
||||
else
|
||||
__release(fd->lock);
|
||||
|
||||
m = (val & fd->mmask) >> fd->mshift;
|
||||
n = (val & fd->nmask) >> fd->nshift;
|
||||
|
@ -80,6 +84,8 @@ static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
|
||||
if (fd->lock)
|
||||
spin_lock_irqsave(fd->lock, flags);
|
||||
else
|
||||
__acquire(fd->lock);
|
||||
|
||||
val = clk_readl(fd->reg);
|
||||
val &= ~(fd->mmask | fd->nmask);
|
||||
|
@ -88,6 +94,8 @@ static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
|
||||
if (fd->lock)
|
||||
spin_unlock_irqrestore(fd->lock, flags);
|
||||
else
|
||||
__release(fd->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -52,6 +52,8 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
|
|||
|
||||
if (gate->lock)
|
||||
spin_lock_irqsave(gate->lock, flags);
|
||||
else
|
||||
__acquire(gate->lock);
|
||||
|
||||
if (gate->flags & CLK_GATE_HIWORD_MASK) {
|
||||
reg = BIT(gate->bit_idx + 16);
|
||||
|
@ -70,6 +72,8 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
|
|||
|
||||
if (gate->lock)
|
||||
spin_unlock_irqrestore(gate->lock, flags);
|
||||
else
|
||||
__release(gate->lock);
|
||||
}
|
||||
|
||||
static int clk_gate_enable(struct clk_hw *hw)
|
||||
|
|
|
@ -1,207 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2013 - 2014 Texas Instruments Incorporated - http://www.ti.com
|
||||
* Author: Jyri Sarha <jsarha@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Gpio gated clock implementation
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
/**
|
||||
* DOC: basic gpio gated clock which can be enabled and disabled
|
||||
* with gpio output
|
||||
* Traits of this clock:
|
||||
* prepare - clk_(un)prepare only ensures parent is (un)prepared
|
||||
* enable - clk_enable and clk_disable are functional & control gpio
|
||||
* rate - inherits rate from parent. No clk_set_rate support
|
||||
* parent - fixed parent. No clk_set_parent support
|
||||
*/
|
||||
|
||||
#define to_clk_gpio(_hw) container_of(_hw, struct clk_gpio, hw)
|
||||
|
||||
static int clk_gpio_gate_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_gpio *clk = to_clk_gpio(hw);
|
||||
|
||||
gpiod_set_value(clk->gpiod, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clk_gpio_gate_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_gpio *clk = to_clk_gpio(hw);
|
||||
|
||||
gpiod_set_value(clk->gpiod, 0);
|
||||
}
|
||||
|
||||
static int clk_gpio_gate_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_gpio *clk = to_clk_gpio(hw);
|
||||
|
||||
return gpiod_get_value(clk->gpiod);
|
||||
}
|
||||
|
||||
const struct clk_ops clk_gpio_gate_ops = {
|
||||
.enable = clk_gpio_gate_enable,
|
||||
.disable = clk_gpio_gate_disable,
|
||||
.is_enabled = clk_gpio_gate_is_enabled,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_gpio_gate_ops);
|
||||
|
||||
/**
|
||||
* clk_register_gpio - register a gpip clock with the clock framework
|
||||
* @dev: device that is registering this clock
|
||||
* @name: name of this clock
|
||||
* @parent_name: name of this clock's parent
|
||||
* @gpio: gpio number to gate this clock
|
||||
* @active_low: true if gpio should be set to 0 to enable clock
|
||||
* @flags: clock flags
|
||||
*/
|
||||
struct clk *clk_register_gpio_gate(struct device *dev, const char *name,
|
||||
const char *parent_name, unsigned gpio, bool active_low,
|
||||
unsigned long flags)
|
||||
{
|
||||
struct clk_gpio *clk_gpio = NULL;
|
||||
struct clk *clk = ERR_PTR(-EINVAL);
|
||||
struct clk_init_data init = { NULL };
|
||||
unsigned long gpio_flags;
|
||||
int err;
|
||||
|
||||
if (active_low)
|
||||
gpio_flags = GPIOF_ACTIVE_LOW | GPIOF_OUT_INIT_HIGH;
|
||||
else
|
||||
gpio_flags = GPIOF_OUT_INIT_LOW;
|
||||
|
||||
if (dev)
|
||||
err = devm_gpio_request_one(dev, gpio, gpio_flags, name);
|
||||
else
|
||||
err = gpio_request_one(gpio, gpio_flags, name);
|
||||
|
||||
if (err) {
|
||||
pr_err("%s: %s: Error requesting clock control gpio %u\n",
|
||||
__func__, name, gpio);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
if (dev)
|
||||
clk_gpio = devm_kzalloc(dev, sizeof(struct clk_gpio),
|
||||
GFP_KERNEL);
|
||||
else
|
||||
clk_gpio = kzalloc(sizeof(struct clk_gpio), GFP_KERNEL);
|
||||
|
||||
if (!clk_gpio) {
|
||||
clk = ERR_PTR(-ENOMEM);
|
||||
goto clk_register_gpio_gate_err;
|
||||
}
|
||||
|
||||
init.name = name;
|
||||
init.ops = &clk_gpio_gate_ops;
|
||||
init.flags = flags | CLK_IS_BASIC;
|
||||
init.parent_names = (parent_name ? &parent_name : NULL);
|
||||
init.num_parents = (parent_name ? 1 : 0);
|
||||
|
||||
clk_gpio->gpiod = gpio_to_desc(gpio);
|
||||
clk_gpio->hw.init = &init;
|
||||
|
||||
clk = clk_register(dev, &clk_gpio->hw);
|
||||
|
||||
if (!IS_ERR(clk))
|
||||
return clk;
|
||||
|
||||
if (!dev)
|
||||
kfree(clk_gpio);
|
||||
|
||||
clk_register_gpio_gate_err:
|
||||
if (!dev)
|
||||
gpio_free(gpio);
|
||||
|
||||
return clk;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_register_gpio_gate);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
/**
|
||||
* The clk_register_gpio_gate has to be delayed, because the EPROBE_DEFER
|
||||
* can not be handled properly at of_clk_init() call time.
|
||||
*/
|
||||
|
||||
struct clk_gpio_gate_delayed_register_data {
|
||||
struct device_node *node;
|
||||
struct mutex lock;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
static struct clk *of_clk_gpio_gate_delayed_register_get(
|
||||
struct of_phandle_args *clkspec,
|
||||
void *_data)
|
||||
{
|
||||
struct clk_gpio_gate_delayed_register_data *data = _data;
|
||||
struct clk *clk;
|
||||
const char *clk_name = data->node->name;
|
||||
const char *parent_name;
|
||||
int gpio;
|
||||
enum of_gpio_flags of_flags;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
if (data->clk) {
|
||||
mutex_unlock(&data->lock);
|
||||
return data->clk;
|
||||
}
|
||||
|
||||
gpio = of_get_named_gpio_flags(data->node, "enable-gpios", 0,
|
||||
&of_flags);
|
||||
if (gpio < 0) {
|
||||
mutex_unlock(&data->lock);
|
||||
if (gpio != -EPROBE_DEFER)
|
||||
pr_err("%s: %s: Can't get 'enable-gpios' DT property\n",
|
||||
__func__, clk_name);
|
||||
return ERR_PTR(gpio);
|
||||
}
|
||||
|
||||
parent_name = of_clk_get_parent_name(data->node, 0);
|
||||
|
||||
clk = clk_register_gpio_gate(NULL, clk_name, parent_name, gpio,
|
||||
of_flags & OF_GPIO_ACTIVE_LOW, 0);
|
||||
if (IS_ERR(clk)) {
|
||||
mutex_unlock(&data->lock);
|
||||
return clk;
|
||||
}
|
||||
|
||||
data->clk = clk;
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
/**
|
||||
* of_gpio_gate_clk_setup() - Setup function for gpio controlled clock
|
||||
*/
|
||||
static void __init of_gpio_gate_clk_setup(struct device_node *node)
|
||||
{
|
||||
struct clk_gpio_gate_delayed_register_data *data;
|
||||
|
||||
data = kzalloc(sizeof(struct clk_gpio_gate_delayed_register_data),
|
||||
GFP_KERNEL);
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
data->node = node;
|
||||
mutex_init(&data->lock);
|
||||
|
||||
of_clk_add_provider(node, of_clk_gpio_gate_delayed_register_get, data);
|
||||
}
|
||||
CLK_OF_DECLARE(gpio_gate_clk, "gpio-gate-clock", of_gpio_gate_clk_setup);
|
||||
#endif
|
325
drivers/clk/clk-gpio.c
Normal file
325
drivers/clk/clk-gpio.c
Normal file
|
@ -0,0 +1,325 @@
|
|||
/*
|
||||
* Copyright (C) 2013 - 2014 Texas Instruments Incorporated - http://www.ti.com
|
||||
*
|
||||
* Authors:
|
||||
* Jyri Sarha <jsarha@ti.com>
|
||||
* Sergej Sawazki <ce3a@gmx.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Gpio controlled clock implementation
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
/**
|
||||
* DOC: basic gpio gated clock which can be enabled and disabled
|
||||
* with gpio output
|
||||
* Traits of this clock:
|
||||
* prepare - clk_(un)prepare only ensures parent is (un)prepared
|
||||
* enable - clk_enable and clk_disable are functional & control gpio
|
||||
* rate - inherits rate from parent. No clk_set_rate support
|
||||
* parent - fixed parent. No clk_set_parent support
|
||||
*/
|
||||
|
||||
#define to_clk_gpio(_hw) container_of(_hw, struct clk_gpio, hw)
|
||||
|
||||
static int clk_gpio_gate_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_gpio *clk = to_clk_gpio(hw);
|
||||
|
||||
gpiod_set_value(clk->gpiod, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clk_gpio_gate_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_gpio *clk = to_clk_gpio(hw);
|
||||
|
||||
gpiod_set_value(clk->gpiod, 0);
|
||||
}
|
||||
|
||||
static int clk_gpio_gate_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_gpio *clk = to_clk_gpio(hw);
|
||||
|
||||
return gpiod_get_value(clk->gpiod);
|
||||
}
|
||||
|
||||
const struct clk_ops clk_gpio_gate_ops = {
|
||||
.enable = clk_gpio_gate_enable,
|
||||
.disable = clk_gpio_gate_disable,
|
||||
.is_enabled = clk_gpio_gate_is_enabled,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_gpio_gate_ops);
|
||||
|
||||
/**
|
||||
* DOC: basic clock multiplexer which can be controlled with a gpio output
|
||||
* Traits of this clock:
|
||||
* prepare - clk_prepare only ensures that parents are prepared
|
||||
* rate - rate is only affected by parent switching. No clk_set_rate support
|
||||
* parent - parent is adjustable through clk_set_parent
|
||||
*/
|
||||
|
||||
static u8 clk_gpio_mux_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_gpio *clk = to_clk_gpio(hw);
|
||||
|
||||
return gpiod_get_value(clk->gpiod);
|
||||
}
|
||||
|
||||
static int clk_gpio_mux_set_parent(struct clk_hw *hw, u8 index)
|
||||
{
|
||||
struct clk_gpio *clk = to_clk_gpio(hw);
|
||||
|
||||
gpiod_set_value(clk->gpiod, index);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct clk_ops clk_gpio_mux_ops = {
|
||||
.get_parent = clk_gpio_mux_get_parent,
|
||||
.set_parent = clk_gpio_mux_set_parent,
|
||||
.determine_rate = __clk_mux_determine_rate,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(clk_gpio_mux_ops);
|
||||
|
||||
static struct clk *clk_register_gpio(struct device *dev, const char *name,
|
||||
const char * const *parent_names, u8 num_parents, unsigned gpio,
|
||||
bool active_low, unsigned long flags,
|
||||
const struct clk_ops *clk_gpio_ops)
|
||||
{
|
||||
struct clk_gpio *clk_gpio;
|
||||
struct clk *clk;
|
||||
struct clk_init_data init = {};
|
||||
unsigned long gpio_flags;
|
||||
int err;
|
||||
|
||||
if (dev)
|
||||
clk_gpio = devm_kzalloc(dev, sizeof(*clk_gpio), GFP_KERNEL);
|
||||
else
|
||||
clk_gpio = kzalloc(sizeof(*clk_gpio), GFP_KERNEL);
|
||||
|
||||
if (!clk_gpio)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
if (active_low)
|
||||
gpio_flags = GPIOF_ACTIVE_LOW | GPIOF_OUT_INIT_HIGH;
|
||||
else
|
||||
gpio_flags = GPIOF_OUT_INIT_LOW;
|
||||
|
||||
if (dev)
|
||||
err = devm_gpio_request_one(dev, gpio, gpio_flags, name);
|
||||
else
|
||||
err = gpio_request_one(gpio, gpio_flags, name);
|
||||
if (err) {
|
||||
if (err != -EPROBE_DEFER)
|
||||
pr_err("%s: %s: Error requesting clock control gpio %u\n",
|
||||
__func__, name, gpio);
|
||||
if (!dev)
|
||||
kfree(clk_gpio);
|
||||
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
init.name = name;
|
||||
init.ops = clk_gpio_ops;
|
||||
init.flags = flags | CLK_IS_BASIC;
|
||||
init.parent_names = parent_names;
|
||||
init.num_parents = num_parents;
|
||||
|
||||
clk_gpio->gpiod = gpio_to_desc(gpio);
|
||||
clk_gpio->hw.init = &init;
|
||||
|
||||
if (dev)
|
||||
clk = devm_clk_register(dev, &clk_gpio->hw);
|
||||
else
|
||||
clk = clk_register(NULL, &clk_gpio->hw);
|
||||
|
||||
if (!IS_ERR(clk))
|
||||
return clk;
|
||||
|
||||
if (!dev) {
|
||||
gpiod_put(clk_gpio->gpiod);
|
||||
kfree(clk_gpio);
|
||||
}
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
/**
|
||||
* clk_register_gpio_gate - register a gpio clock gate with the clock framework
|
||||
* @dev: device that is registering this clock
|
||||
* @name: name of this clock
|
||||
* @parent_name: name of this clock's parent
|
||||
* @gpio: gpio number to gate this clock
|
||||
* @active_low: true if gpio should be set to 0 to enable clock
|
||||
* @flags: clock flags
|
||||
*/
|
||||
struct clk *clk_register_gpio_gate(struct device *dev, const char *name,
|
||||
const char *parent_name, unsigned gpio, bool active_low,
|
||||
unsigned long flags)
|
||||
{
|
||||
return clk_register_gpio(dev, name,
|
||||
(parent_name ? &parent_name : NULL),
|
||||
(parent_name ? 1 : 0), gpio, active_low, flags,
|
||||
&clk_gpio_gate_ops);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_register_gpio_gate);
|
||||
|
||||
/**
|
||||
* clk_register_gpio_mux - register a gpio clock mux with the clock framework
|
||||
* @dev: device that is registering this clock
|
||||
* @name: name of this clock
|
||||
* @parent_names: names of this clock's parents
|
||||
* @num_parents: number of parents listed in @parent_names
|
||||
* @gpio: gpio number to gate this clock
|
||||
* @active_low: true if gpio should be set to 0 to enable clock
|
||||
* @flags: clock flags
|
||||
*/
|
||||
struct clk *clk_register_gpio_mux(struct device *dev, const char *name,
|
||||
const char * const *parent_names, u8 num_parents, unsigned gpio,
|
||||
bool active_low, unsigned long flags)
|
||||
{
|
||||
if (num_parents != 2) {
|
||||
pr_err("mux-clock %s must have 2 parents\n", name);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
return clk_register_gpio(dev, name, parent_names, num_parents,
|
||||
gpio, active_low, flags, &clk_gpio_mux_ops);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_register_gpio_mux);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
/**
|
||||
* clk_register_get() has to be delayed, because -EPROBE_DEFER
|
||||
* can not be handled properly at of_clk_init() call time.
|
||||
*/
|
||||
|
||||
struct clk_gpio_delayed_register_data {
|
||||
const char *gpio_name;
|
||||
struct device_node *node;
|
||||
struct mutex lock;
|
||||
struct clk *clk;
|
||||
struct clk *(*clk_register_get)(const char *name,
|
||||
const char * const *parent_names, u8 num_parents,
|
||||
unsigned gpio, bool active_low);
|
||||
};
|
||||
|
||||
static struct clk *of_clk_gpio_delayed_register_get(
|
||||
struct of_phandle_args *clkspec, void *_data)
|
||||
{
|
||||
struct clk_gpio_delayed_register_data *data = _data;
|
||||
struct clk *clk;
|
||||
const char **parent_names;
|
||||
int i, num_parents;
|
||||
int gpio;
|
||||
enum of_gpio_flags of_flags;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
|
||||
if (data->clk) {
|
||||
mutex_unlock(&data->lock);
|
||||
return data->clk;
|
||||
}
|
||||
|
||||
gpio = of_get_named_gpio_flags(data->node, data->gpio_name, 0,
|
||||
&of_flags);
|
||||
if (gpio < 0) {
|
||||
mutex_unlock(&data->lock);
|
||||
if (gpio == -EPROBE_DEFER)
|
||||
pr_debug("%s: %s: GPIOs not yet available, retry later\n",
|
||||
data->node->name, __func__);
|
||||
else
|
||||
pr_err("%s: %s: Can't get '%s' DT property\n",
|
||||
data->node->name, __func__,
|
||||
data->gpio_name);
|
||||
return ERR_PTR(gpio);
|
||||
}
|
||||
|
||||
num_parents = of_clk_get_parent_count(data->node);
|
||||
|
||||
parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL);
|
||||
if (!parent_names) {
|
||||
clk = ERR_PTR(-ENOMEM);
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_parents; i++)
|
||||
parent_names[i] = of_clk_get_parent_name(data->node, i);
|
||||
|
||||
clk = data->clk_register_get(data->node->name, parent_names,
|
||||
num_parents, gpio, of_flags & OF_GPIO_ACTIVE_LOW);
|
||||
if (IS_ERR(clk))
|
||||
goto out;
|
||||
|
||||
data->clk = clk;
|
||||
out:
|
||||
mutex_unlock(&data->lock);
|
||||
kfree(parent_names);
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
static struct clk *of_clk_gpio_gate_delayed_register_get(const char *name,
|
||||
const char * const *parent_names, u8 num_parents,
|
||||
unsigned gpio, bool active_low)
|
||||
{
|
||||
return clk_register_gpio_gate(NULL, name, parent_names[0],
|
||||
gpio, active_low, 0);
|
||||
}
|
||||
|
||||
static struct clk *of_clk_gpio_mux_delayed_register_get(const char *name,
|
||||
const char * const *parent_names, u8 num_parents, unsigned gpio,
|
||||
bool active_low)
|
||||
{
|
||||
return clk_register_gpio_mux(NULL, name, parent_names, num_parents,
|
||||
gpio, active_low, 0);
|
||||
}
|
||||
|
||||
static void __init of_gpio_clk_setup(struct device_node *node,
|
||||
const char *gpio_name,
|
||||
struct clk *(*clk_register_get)(const char *name,
|
||||
const char * const *parent_names,
|
||||
u8 num_parents,
|
||||
unsigned gpio, bool active_low))
|
||||
{
|
||||
struct clk_gpio_delayed_register_data *data;
|
||||
|
||||
data = kzalloc(sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
data->node = node;
|
||||
data->gpio_name = gpio_name;
|
||||
data->clk_register_get = clk_register_get;
|
||||
mutex_init(&data->lock);
|
||||
|
||||
of_clk_add_provider(node, of_clk_gpio_delayed_register_get, data);
|
||||
}
|
||||
|
||||
static void __init of_gpio_gate_clk_setup(struct device_node *node)
|
||||
{
|
||||
of_gpio_clk_setup(node, "enable-gpios",
|
||||
of_clk_gpio_gate_delayed_register_get);
|
||||
}
|
||||
CLK_OF_DECLARE(gpio_gate_clk, "gpio-gate-clock", of_gpio_gate_clk_setup);
|
||||
|
||||
void __init of_gpio_mux_clk_setup(struct device_node *node)
|
||||
{
|
||||
of_gpio_clk_setup(node, "select-gpios",
|
||||
of_clk_gpio_mux_delayed_register_get);
|
||||
}
|
||||
CLK_OF_DECLARE(gpio_mux_clk, "gpio-mux-clock", of_gpio_mux_clk_setup);
|
||||
#endif
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of_address.h>
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
* Simple multiplexer clock implementation
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -32,7 +31,7 @@
|
|||
static u8 clk_mux_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_mux *mux = to_clk_mux(hw);
|
||||
int num_parents = __clk_get_num_parents(hw->clk);
|
||||
int num_parents = clk_hw_get_num_parents(hw);
|
||||
u32 val;
|
||||
|
||||
/*
|
||||
|
@ -85,6 +84,8 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
|
|||
|
||||
if (mux->lock)
|
||||
spin_lock_irqsave(mux->lock, flags);
|
||||
else
|
||||
__acquire(mux->lock);
|
||||
|
||||
if (mux->flags & CLK_MUX_HIWORD_MASK) {
|
||||
val = mux->mask << (mux->shift + 16);
|
||||
|
@ -97,6 +98,8 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
|
|||
|
||||
if (mux->lock)
|
||||
spin_unlock_irqrestore(mux->lock, flags);
|
||||
else
|
||||
__release(mux->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -8,8 +8,7 @@
|
|||
#define pr_fmt(fmt) "Nomadik SRC clocks: " fmt
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk-provider.h>
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/mfd/palmas.h>
|
||||
#include <linux/module.h>
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
* more details.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
|
@ -58,21 +58,17 @@ static struct s2mps11_clk *to_s2mps11_clk(struct clk_hw *hw)
|
|||
static int s2mps11_clk_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct s2mps11_clk *s2mps11 = to_s2mps11_clk(hw);
|
||||
int ret;
|
||||
|
||||
ret = regmap_update_bits(s2mps11->iodev->regmap_pmic,
|
||||
return regmap_update_bits(s2mps11->iodev->regmap_pmic,
|
||||
s2mps11->reg,
|
||||
s2mps11->mask, s2mps11->mask);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void s2mps11_clk_unprepare(struct clk_hw *hw)
|
||||
{
|
||||
struct s2mps11_clk *s2mps11 = to_s2mps11_clk(hw);
|
||||
int ret;
|
||||
|
||||
ret = regmap_update_bits(s2mps11->iodev->regmap_pmic, s2mps11->reg,
|
||||
regmap_update_bits(s2mps11->iodev->regmap_pmic, s2mps11->reg,
|
||||
s2mps11->mask, ~s2mps11->mask);
|
||||
}
|
||||
|
||||
|
@ -186,15 +182,15 @@ static int s2mps11_clk_probe(struct platform_device *pdev)
|
|||
struct clk_init_data *clks_init;
|
||||
int i, ret = 0;
|
||||
|
||||
s2mps11_clks = devm_kzalloc(&pdev->dev, sizeof(*s2mps11_clk) *
|
||||
S2MPS11_CLKS_NUM, GFP_KERNEL);
|
||||
s2mps11_clks = devm_kcalloc(&pdev->dev, S2MPS11_CLKS_NUM,
|
||||
sizeof(*s2mps11_clk), GFP_KERNEL);
|
||||
if (!s2mps11_clks)
|
||||
return -ENOMEM;
|
||||
|
||||
s2mps11_clk = s2mps11_clks;
|
||||
|
||||
clk_table = devm_kzalloc(&pdev->dev, sizeof(struct clk *) *
|
||||
S2MPS11_CLKS_NUM, GFP_KERNEL);
|
||||
clk_table = devm_kcalloc(&pdev->dev, S2MPS11_CLKS_NUM,
|
||||
sizeof(struct clk *), GFP_KERNEL);
|
||||
if (!clk_table)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -246,7 +242,7 @@ static int s2mps11_clk_probe(struct platform_device *pdev)
|
|||
s2mps11_name(s2mps11_clk), NULL);
|
||||
if (!s2mps11_clk->lookup) {
|
||||
ret = -ENOMEM;
|
||||
goto err_lup;
|
||||
goto err_reg;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -265,16 +261,10 @@ static int s2mps11_clk_probe(struct platform_device *pdev)
|
|||
platform_set_drvdata(pdev, s2mps11_clks);
|
||||
|
||||
return ret;
|
||||
err_lup:
|
||||
devm_clk_unregister(&pdev->dev, s2mps11_clk->clk);
|
||||
|
||||
err_reg:
|
||||
while (s2mps11_clk > s2mps11_clks) {
|
||||
if (s2mps11_clk->lookup) {
|
||||
clkdev_drop(s2mps11_clk->lookup);
|
||||
devm_clk_unregister(&pdev->dev, s2mps11_clk->clk);
|
||||
}
|
||||
s2mps11_clk--;
|
||||
}
|
||||
while (--i >= 0)
|
||||
clkdev_drop(s2mps11_clks[i].lookup);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -322,7 +312,7 @@ static int __init s2mps11_clk_init(void)
|
|||
}
|
||||
subsys_initcall(s2mps11_clk_init);
|
||||
|
||||
static void __init s2mps11_clk_cleanup(void)
|
||||
static void __exit s2mps11_clk_cleanup(void)
|
||||
{
|
||||
platform_driver_unregister(&s2mps11_clk_driver);
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
|
@ -439,7 +439,7 @@ static unsigned long si5351_pll_recalc_rate(struct clk_hw *hw,
|
|||
|
||||
dev_dbg(&hwdata->drvdata->client->dev,
|
||||
"%s - %s: p1 = %lu, p2 = %lu, p3 = %lu, parent_rate = %lu, rate = %lu\n",
|
||||
__func__, __clk_get_name(hwdata->hw.clk),
|
||||
__func__, clk_hw_get_name(hw),
|
||||
hwdata->params.p1, hwdata->params.p2, hwdata->params.p3,
|
||||
parent_rate, (unsigned long)rate);
|
||||
|
||||
|
@ -497,7 +497,7 @@ static long si5351_pll_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||
|
||||
dev_dbg(&hwdata->drvdata->client->dev,
|
||||
"%s - %s: a = %lu, b = %lu, c = %lu, parent_rate = %lu, rate = %lu\n",
|
||||
__func__, __clk_get_name(hwdata->hw.clk), a, b, c,
|
||||
__func__, clk_hw_get_name(hw), a, b, c,
|
||||
*parent_rate, rate);
|
||||
|
||||
return rate;
|
||||
|
@ -521,7 +521,7 @@ static int si5351_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
|
||||
dev_dbg(&hwdata->drvdata->client->dev,
|
||||
"%s - %s: p1 = %lu, p2 = %lu, p3 = %lu, parent_rate = %lu, rate = %lu\n",
|
||||
__func__, __clk_get_name(hwdata->hw.clk),
|
||||
__func__, clk_hw_get_name(hw),
|
||||
hwdata->params.p1, hwdata->params.p2, hwdata->params.p3,
|
||||
parent_rate, rate);
|
||||
|
||||
|
@ -632,7 +632,7 @@ static unsigned long si5351_msynth_recalc_rate(struct clk_hw *hw,
|
|||
|
||||
dev_dbg(&hwdata->drvdata->client->dev,
|
||||
"%s - %s: p1 = %lu, p2 = %lu, p3 = %lu, m = %lu, parent_rate = %lu, rate = %lu\n",
|
||||
__func__, __clk_get_name(hwdata->hw.clk),
|
||||
__func__, clk_hw_get_name(hw),
|
||||
hwdata->params.p1, hwdata->params.p2, hwdata->params.p3,
|
||||
m, parent_rate, (unsigned long)rate);
|
||||
|
||||
|
@ -663,7 +663,7 @@ static long si5351_msynth_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||
divby4 = 1;
|
||||
|
||||
/* multisync can set pll */
|
||||
if (__clk_get_flags(hwdata->hw.clk) & CLK_SET_RATE_PARENT) {
|
||||
if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
|
||||
/*
|
||||
* find largest integer divider for max
|
||||
* vco frequency and given target rate
|
||||
|
@ -745,7 +745,7 @@ static long si5351_msynth_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||
|
||||
dev_dbg(&hwdata->drvdata->client->dev,
|
||||
"%s - %s: a = %lu, b = %lu, c = %lu, divby4 = %d, parent_rate = %lu, rate = %lu\n",
|
||||
__func__, __clk_get_name(hwdata->hw.clk), a, b, c, divby4,
|
||||
__func__, clk_hw_get_name(hw), a, b, c, divby4,
|
||||
*parent_rate, rate);
|
||||
|
||||
return rate;
|
||||
|
@ -777,7 +777,7 @@ static int si5351_msynth_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
|
||||
dev_dbg(&hwdata->drvdata->client->dev,
|
||||
"%s - %s: p1 = %lu, p2 = %lu, p3 = %lu, divby4 = %d, parent_rate = %lu, rate = %lu\n",
|
||||
__func__, __clk_get_name(hwdata->hw.clk),
|
||||
__func__, clk_hw_get_name(hw),
|
||||
hwdata->params.p1, hwdata->params.p2, hwdata->params.p3,
|
||||
divby4, parent_rate, rate);
|
||||
|
||||
|
@ -1013,7 +1013,7 @@ static long si5351_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||
rate = SI5351_CLKOUT_MIN_FREQ;
|
||||
|
||||
/* request frequency if multisync master */
|
||||
if (__clk_get_flags(hwdata->hw.clk) & CLK_SET_RATE_PARENT) {
|
||||
if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
|
||||
/* use r divider for frequencies below 1MHz */
|
||||
rdiv = SI5351_OUTPUT_CLK_DIV_1;
|
||||
while (rate < SI5351_MULTISYNTH_MIN_FREQ &&
|
||||
|
@ -1042,7 +1042,7 @@ static long si5351_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||
|
||||
dev_dbg(&hwdata->drvdata->client->dev,
|
||||
"%s - %s: rdiv = %u, parent_rate = %lu, rate = %lu\n",
|
||||
__func__, __clk_get_name(hwdata->hw.clk), (1 << rdiv),
|
||||
__func__, clk_hw_get_name(hw), (1 << rdiv),
|
||||
*parent_rate, rate);
|
||||
|
||||
return rate;
|
||||
|
@ -1093,7 +1093,7 @@ static int si5351_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
|
||||
dev_dbg(&hwdata->drvdata->client->dev,
|
||||
"%s - %s: rdiv = %u, parent_rate = %lu, rate = %lu\n",
|
||||
__func__, __clk_get_name(hwdata->hw.clk), (1 << rdiv),
|
||||
__func__, clk_hw_get_name(hw), (1 << rdiv),
|
||||
parent_rate, rate);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
|
|
|
@ -175,11 +175,10 @@ static long clk_apb_mul_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||
if (readl(base + STM32F4_RCC_CFGR) & BIT(am->bit_idx))
|
||||
mult = 2;
|
||||
|
||||
if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) {
|
||||
if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
|
||||
unsigned long best_parent = rate / mult;
|
||||
|
||||
*prate =
|
||||
__clk_round_rate(__clk_get_parent(hw->clk), best_parent);
|
||||
*prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent);
|
||||
}
|
||||
|
||||
return *prate * mult;
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
@ -91,7 +90,7 @@ static int twl6040_clk_probe(struct platform_device *pdev)
|
|||
clkdata->twl6040 = twl6040;
|
||||
|
||||
clkdata->mcpdm_fclk.init = &wm831x_clkout_init;
|
||||
clkdata->clk = clk_register(&pdev->dev, &clkdata->mcpdm_fclk);
|
||||
clkdata->clk = devm_clk_register(&pdev->dev, &clkdata->mcpdm_fclk);
|
||||
if (IS_ERR(clkdata->clk))
|
||||
return PTR_ERR(clkdata->clk);
|
||||
|
||||
|
@ -100,21 +99,11 @@ static int twl6040_clk_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int twl6040_clk_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct twl6040_clk *clkdata = platform_get_drvdata(pdev);
|
||||
|
||||
clk_unregister(clkdata->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver twl6040_clk_driver = {
|
||||
.driver = {
|
||||
.name = "twl6040-clk",
|
||||
},
|
||||
.probe = twl6040_clk_probe,
|
||||
.remove = twl6040_clk_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(twl6040_clk_driver);
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
* Author: Linus Walleij <linus.walleij@stericsson.com>
|
||||
* Author: Jonas Aaberg <jonas.aberg@stericsson.com>
|
||||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk-provider.h>
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
|
|
|
@ -60,7 +60,6 @@ enum xgene_pll_type {
|
|||
|
||||
struct xgene_clk_pll {
|
||||
struct clk_hw hw;
|
||||
const char *name;
|
||||
void __iomem *reg;
|
||||
spinlock_t *lock;
|
||||
u32 pll_offset;
|
||||
|
@ -75,7 +74,7 @@ static int xgene_clk_pll_is_enabled(struct clk_hw *hw)
|
|||
u32 data;
|
||||
|
||||
data = xgene_clk_read(pllclk->reg + pllclk->pll_offset);
|
||||
pr_debug("%s pll %s\n", pllclk->name,
|
||||
pr_debug("%s pll %s\n", clk_hw_get_name(hw),
|
||||
data & REGSPEC_RESET_F1_MASK ? "disabled" : "enabled");
|
||||
|
||||
return data & REGSPEC_RESET_F1_MASK ? 0 : 1;
|
||||
|
@ -113,7 +112,7 @@ static unsigned long xgene_clk_pll_recalc_rate(struct clk_hw *hw,
|
|||
fref = parent_rate / nref;
|
||||
fvco = fref * nfb;
|
||||
}
|
||||
pr_debug("%s pll recalc rate %ld parent %ld\n", pllclk->name,
|
||||
pr_debug("%s pll recalc rate %ld parent %ld\n", clk_hw_get_name(hw),
|
||||
fvco / nout, parent_rate);
|
||||
|
||||
return fvco / nout;
|
||||
|
@ -146,7 +145,6 @@ static struct clk *xgene_register_clk_pll(struct device *dev,
|
|||
init.parent_names = parent_name ? &parent_name : NULL;
|
||||
init.num_parents = parent_name ? 1 : 0;
|
||||
|
||||
apmclk->name = name;
|
||||
apmclk->reg = reg;
|
||||
apmclk->lock = lock;
|
||||
apmclk->pll_offset = pll_offset;
|
||||
|
@ -210,7 +208,6 @@ struct xgene_dev_parameters {
|
|||
|
||||
struct xgene_clk {
|
||||
struct clk_hw hw;
|
||||
const char *name;
|
||||
spinlock_t *lock;
|
||||
struct xgene_dev_parameters param;
|
||||
};
|
||||
|
@ -228,7 +225,7 @@ static int xgene_clk_enable(struct clk_hw *hw)
|
|||
spin_lock_irqsave(pclk->lock, flags);
|
||||
|
||||
if (pclk->param.csr_reg != NULL) {
|
||||
pr_debug("%s clock enabled\n", pclk->name);
|
||||
pr_debug("%s clock enabled\n", clk_hw_get_name(hw));
|
||||
reg = __pa(pclk->param.csr_reg);
|
||||
/* First enable the clock */
|
||||
data = xgene_clk_read(pclk->param.csr_reg +
|
||||
|
@ -237,7 +234,7 @@ static int xgene_clk_enable(struct clk_hw *hw)
|
|||
xgene_clk_write(data, pclk->param.csr_reg +
|
||||
pclk->param.reg_clk_offset);
|
||||
pr_debug("%s clock PADDR base %pa clk offset 0x%08X mask 0x%08X value 0x%08X\n",
|
||||
pclk->name, ®,
|
||||
clk_hw_get_name(hw), ®,
|
||||
pclk->param.reg_clk_offset, pclk->param.reg_clk_mask,
|
||||
data);
|
||||
|
||||
|
@ -248,7 +245,7 @@ static int xgene_clk_enable(struct clk_hw *hw)
|
|||
xgene_clk_write(data, pclk->param.csr_reg +
|
||||
pclk->param.reg_csr_offset);
|
||||
pr_debug("%s CSR RESET PADDR base %pa csr offset 0x%08X mask 0x%08X value 0x%08X\n",
|
||||
pclk->name, ®,
|
||||
clk_hw_get_name(hw), ®,
|
||||
pclk->param.reg_csr_offset, pclk->param.reg_csr_mask,
|
||||
data);
|
||||
}
|
||||
|
@ -269,7 +266,7 @@ static void xgene_clk_disable(struct clk_hw *hw)
|
|||
spin_lock_irqsave(pclk->lock, flags);
|
||||
|
||||
if (pclk->param.csr_reg != NULL) {
|
||||
pr_debug("%s clock disabled\n", pclk->name);
|
||||
pr_debug("%s clock disabled\n", clk_hw_get_name(hw));
|
||||
/* First put the CSR in reset */
|
||||
data = xgene_clk_read(pclk->param.csr_reg +
|
||||
pclk->param.reg_csr_offset);
|
||||
|
@ -295,10 +292,10 @@ static int xgene_clk_is_enabled(struct clk_hw *hw)
|
|||
u32 data = 0;
|
||||
|
||||
if (pclk->param.csr_reg != NULL) {
|
||||
pr_debug("%s clock checking\n", pclk->name);
|
||||
pr_debug("%s clock checking\n", clk_hw_get_name(hw));
|
||||
data = xgene_clk_read(pclk->param.csr_reg +
|
||||
pclk->param.reg_clk_offset);
|
||||
pr_debug("%s clock is %s\n", pclk->name,
|
||||
pr_debug("%s clock is %s\n", clk_hw_get_name(hw),
|
||||
data & pclk->param.reg_clk_mask ? "enabled" :
|
||||
"disabled");
|
||||
}
|
||||
|
@ -321,11 +318,13 @@ static unsigned long xgene_clk_recalc_rate(struct clk_hw *hw,
|
|||
data &= (1 << pclk->param.reg_divider_width) - 1;
|
||||
|
||||
pr_debug("%s clock recalc rate %ld parent %ld\n",
|
||||
pclk->name, parent_rate / data, parent_rate);
|
||||
clk_hw_get_name(hw),
|
||||
parent_rate / data, parent_rate);
|
||||
|
||||
return parent_rate / data;
|
||||
} else {
|
||||
pr_debug("%s clock recalc rate %ld parent %ld\n",
|
||||
pclk->name, parent_rate, parent_rate);
|
||||
clk_hw_get_name(hw), parent_rate, parent_rate);
|
||||
return parent_rate;
|
||||
}
|
||||
}
|
||||
|
@ -357,7 +356,7 @@ static int xgene_clk_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
data |= divider;
|
||||
xgene_clk_write(data, pclk->param.divider_reg +
|
||||
pclk->param.reg_divider_offset);
|
||||
pr_debug("%s clock set rate %ld\n", pclk->name,
|
||||
pr_debug("%s clock set rate %ld\n", clk_hw_get_name(hw),
|
||||
parent_rate / divider_save);
|
||||
} else {
|
||||
divider_save = 1;
|
||||
|
@ -419,7 +418,6 @@ static struct clk *xgene_register_clk(struct device *dev,
|
|||
init.parent_names = parent_name ? &parent_name : NULL;
|
||||
init.num_parents = parent_name ? 1 : 0;
|
||||
|
||||
apmclk->name = name;
|
||||
apmclk->lock = lock;
|
||||
apmclk->hw.init = &init;
|
||||
apmclk->param = *parameters;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
* Standard functionality for the common clock API. See Documentation/clk.txt
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk/clk-conf.h>
|
||||
#include <linux/module.h>
|
||||
|
@ -56,8 +57,11 @@ struct clk_core {
|
|||
struct clk_core *new_parent;
|
||||
struct clk_core *new_child;
|
||||
unsigned long flags;
|
||||
bool orphan;
|
||||
unsigned int enable_count;
|
||||
unsigned int prepare_count;
|
||||
unsigned long min_rate;
|
||||
unsigned long max_rate;
|
||||
unsigned long accuracy;
|
||||
int phase;
|
||||
struct hlist_head children;
|
||||
|
@ -111,12 +115,14 @@ static void clk_prepare_unlock(void)
|
|||
}
|
||||
|
||||
static unsigned long clk_enable_lock(void)
|
||||
__acquires(enable_lock)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (!spin_trylock_irqsave(&enable_lock, flags)) {
|
||||
if (enable_owner == current) {
|
||||
enable_refcnt++;
|
||||
__acquire(enable_lock);
|
||||
return flags;
|
||||
}
|
||||
spin_lock_irqsave(&enable_lock, flags);
|
||||
|
@ -129,12 +135,15 @@ static unsigned long clk_enable_lock(void)
|
|||
}
|
||||
|
||||
static void clk_enable_unlock(unsigned long flags)
|
||||
__releases(enable_lock)
|
||||
{
|
||||
WARN_ON_ONCE(enable_owner != current);
|
||||
WARN_ON_ONCE(enable_refcnt == 0);
|
||||
|
||||
if (--enable_refcnt)
|
||||
if (--enable_refcnt) {
|
||||
__release(enable_lock);
|
||||
return;
|
||||
}
|
||||
enable_owner = NULL;
|
||||
spin_unlock_irqrestore(&enable_lock, flags);
|
||||
}
|
||||
|
@ -269,27 +278,29 @@ const char *__clk_get_name(struct clk *clk)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(__clk_get_name);
|
||||
|
||||
const char *clk_hw_get_name(const struct clk_hw *hw)
|
||||
{
|
||||
return hw->core->name;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_hw_get_name);
|
||||
|
||||
struct clk_hw *__clk_get_hw(struct clk *clk)
|
||||
{
|
||||
return !clk ? NULL : clk->core->hw;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__clk_get_hw);
|
||||
|
||||
u8 __clk_get_num_parents(struct clk *clk)
|
||||
unsigned int clk_hw_get_num_parents(const struct clk_hw *hw)
|
||||
{
|
||||
return !clk ? 0 : clk->core->num_parents;
|
||||
return hw->core->num_parents;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__clk_get_num_parents);
|
||||
EXPORT_SYMBOL_GPL(clk_hw_get_num_parents);
|
||||
|
||||
struct clk *__clk_get_parent(struct clk *clk)
|
||||
struct clk_hw *clk_hw_get_parent(const struct clk_hw *hw)
|
||||
{
|
||||
if (!clk)
|
||||
return NULL;
|
||||
|
||||
/* TODO: Create a per-user clk and change callers to call clk_put */
|
||||
return !clk->core->parent ? NULL : clk->core->parent->hw->clk;
|
||||
return hw->core->parent ? hw->core->parent->hw : NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__clk_get_parent);
|
||||
EXPORT_SYMBOL_GPL(clk_hw_get_parent);
|
||||
|
||||
static struct clk_core *__clk_lookup_subtree(const char *name,
|
||||
struct clk_core *core)
|
||||
|
@ -348,18 +359,16 @@ static struct clk_core *clk_core_get_parent_by_index(struct clk_core *core,
|
|||
return core->parents[index];
|
||||
}
|
||||
|
||||
struct clk *clk_get_parent_by_index(struct clk *clk, u8 index)
|
||||
struct clk_hw *
|
||||
clk_hw_get_parent_by_index(const struct clk_hw *hw, unsigned int index)
|
||||
{
|
||||
struct clk_core *parent;
|
||||
|
||||
if (!clk)
|
||||
return NULL;
|
||||
parent = clk_core_get_parent_by_index(hw->core, index);
|
||||
|
||||
parent = clk_core_get_parent_by_index(clk->core, index);
|
||||
|
||||
return !parent ? NULL : parent->hw->clk;
|
||||
return !parent ? NULL : parent->hw;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_get_parent_by_index);
|
||||
EXPORT_SYMBOL_GPL(clk_hw_get_parent_by_index);
|
||||
|
||||
unsigned int __clk_get_enable_count(struct clk *clk)
|
||||
{
|
||||
|
@ -387,14 +396,11 @@ static unsigned long clk_core_get_rate_nolock(struct clk_core *core)
|
|||
return ret;
|
||||
}
|
||||
|
||||
unsigned long __clk_get_rate(struct clk *clk)
|
||||
unsigned long clk_hw_get_rate(const struct clk_hw *hw)
|
||||
{
|
||||
if (!clk)
|
||||
return 0;
|
||||
|
||||
return clk_core_get_rate_nolock(clk->core);
|
||||
return clk_core_get_rate_nolock(hw->core);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__clk_get_rate);
|
||||
EXPORT_SYMBOL_GPL(clk_hw_get_rate);
|
||||
|
||||
static unsigned long __clk_get_accuracy(struct clk_core *core)
|
||||
{
|
||||
|
@ -410,12 +416,15 @@ unsigned long __clk_get_flags(struct clk *clk)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(__clk_get_flags);
|
||||
|
||||
bool __clk_is_prepared(struct clk *clk)
|
||||
unsigned long clk_hw_get_flags(const struct clk_hw *hw)
|
||||
{
|
||||
if (!clk)
|
||||
return false;
|
||||
return hw->core->flags;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_hw_get_flags);
|
||||
|
||||
return clk_core_is_prepared(clk->core);
|
||||
bool clk_hw_is_prepared(const struct clk_hw *hw)
|
||||
{
|
||||
return clk_core_is_prepared(hw->core);
|
||||
}
|
||||
|
||||
bool __clk_is_enabled(struct clk *clk)
|
||||
|
@ -436,28 +445,31 @@ static bool mux_is_better_rate(unsigned long rate, unsigned long now,
|
|||
return now <= rate && now > best;
|
||||
}
|
||||
|
||||
static long
|
||||
clk_mux_determine_rate_flags(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_p,
|
||||
static int
|
||||
clk_mux_determine_rate_flags(struct clk_hw *hw, struct clk_rate_request *req,
|
||||
unsigned long flags)
|
||||
{
|
||||
struct clk_core *core = hw->core, *parent, *best_parent = NULL;
|
||||
int i, num_parents;
|
||||
unsigned long parent_rate, best = 0;
|
||||
int i, num_parents, ret;
|
||||
unsigned long best = 0;
|
||||
struct clk_rate_request parent_req = *req;
|
||||
|
||||
/* if NO_REPARENT flag set, pass through to current parent */
|
||||
if (core->flags & CLK_SET_RATE_NO_REPARENT) {
|
||||
parent = core->parent;
|
||||
if (core->flags & CLK_SET_RATE_PARENT)
|
||||
best = __clk_determine_rate(parent ? parent->hw : NULL,
|
||||
rate, min_rate, max_rate);
|
||||
else if (parent)
|
||||
if (core->flags & CLK_SET_RATE_PARENT) {
|
||||
ret = __clk_determine_rate(parent ? parent->hw : NULL,
|
||||
&parent_req);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
best = parent_req.rate;
|
||||
} else if (parent) {
|
||||
best = clk_core_get_rate_nolock(parent);
|
||||
else
|
||||
} else {
|
||||
best = clk_core_get_rate_nolock(core);
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -467,24 +479,33 @@ clk_mux_determine_rate_flags(struct clk_hw *hw, unsigned long rate,
|
|||
parent = clk_core_get_parent_by_index(core, i);
|
||||
if (!parent)
|
||||
continue;
|
||||
if (core->flags & CLK_SET_RATE_PARENT)
|
||||
parent_rate = __clk_determine_rate(parent->hw, rate,
|
||||
min_rate,
|
||||
max_rate);
|
||||
else
|
||||
parent_rate = clk_core_get_rate_nolock(parent);
|
||||
if (mux_is_better_rate(rate, parent_rate, best, flags)) {
|
||||
|
||||
if (core->flags & CLK_SET_RATE_PARENT) {
|
||||
parent_req = *req;
|
||||
ret = __clk_determine_rate(parent->hw, &parent_req);
|
||||
if (ret)
|
||||
continue;
|
||||
} else {
|
||||
parent_req.rate = clk_core_get_rate_nolock(parent);
|
||||
}
|
||||
|
||||
if (mux_is_better_rate(req->rate, parent_req.rate,
|
||||
best, flags)) {
|
||||
best_parent = parent;
|
||||
best = parent_rate;
|
||||
best = parent_req.rate;
|
||||
}
|
||||
}
|
||||
|
||||
if (!best_parent)
|
||||
return -EINVAL;
|
||||
|
||||
out:
|
||||
if (best_parent)
|
||||
*best_parent_p = best_parent->hw;
|
||||
*best_parent_rate = best;
|
||||
req->best_parent_hw = best_parent->hw;
|
||||
req->best_parent_rate = best;
|
||||
req->rate = best;
|
||||
|
||||
return best;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct clk *__clk_lookup(const char *name)
|
||||
|
@ -500,8 +521,8 @@ static void clk_core_get_boundaries(struct clk_core *core,
|
|||
{
|
||||
struct clk *clk_user;
|
||||
|
||||
*min_rate = 0;
|
||||
*max_rate = ULONG_MAX;
|
||||
*min_rate = core->min_rate;
|
||||
*max_rate = core->max_rate;
|
||||
|
||||
hlist_for_each_entry(clk_user, &core->clks, clks_node)
|
||||
*min_rate = max(*min_rate, clk_user->min_rate);
|
||||
|
@ -510,33 +531,30 @@ static void clk_core_get_boundaries(struct clk_core *core,
|
|||
*max_rate = min(*max_rate, clk_user->max_rate);
|
||||
}
|
||||
|
||||
void clk_hw_set_rate_range(struct clk_hw *hw, unsigned long min_rate,
|
||||
unsigned long max_rate)
|
||||
{
|
||||
hw->core->min_rate = min_rate;
|
||||
hw->core->max_rate = max_rate;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_hw_set_rate_range);
|
||||
|
||||
/*
|
||||
* Helper for finding best parent to provide a given frequency. This can be used
|
||||
* directly as a determine_rate callback (e.g. for a mux), or from a more
|
||||
* complex clock that may combine a mux with other operations.
|
||||
*/
|
||||
long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_p)
|
||||
int __clk_mux_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
return clk_mux_determine_rate_flags(hw, rate, min_rate, max_rate,
|
||||
best_parent_rate,
|
||||
best_parent_p, 0);
|
||||
return clk_mux_determine_rate_flags(hw, req, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__clk_mux_determine_rate);
|
||||
|
||||
long __clk_mux_determine_rate_closest(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_p)
|
||||
int __clk_mux_determine_rate_closest(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
return clk_mux_determine_rate_flags(hw, rate, min_rate, max_rate,
|
||||
best_parent_rate,
|
||||
best_parent_p,
|
||||
CLK_MUX_ROUND_CLOSEST);
|
||||
return clk_mux_determine_rate_flags(hw, req, CLK_MUX_ROUND_CLOSEST);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__clk_mux_determine_rate_closest);
|
||||
|
||||
|
@ -759,14 +777,11 @@ int clk_enable(struct clk *clk)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(clk_enable);
|
||||
|
||||
static unsigned long clk_core_round_rate_nolock(struct clk_core *core,
|
||||
unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate)
|
||||
static int clk_core_round_rate_nolock(struct clk_core *core,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
unsigned long parent_rate = 0;
|
||||
struct clk_core *parent;
|
||||
struct clk_hw *parent_hw;
|
||||
long rate;
|
||||
|
||||
lockdep_assert_held(&prepare_lock);
|
||||
|
||||
|
@ -774,21 +789,30 @@ static unsigned long clk_core_round_rate_nolock(struct clk_core *core,
|
|||
return 0;
|
||||
|
||||
parent = core->parent;
|
||||
if (parent)
|
||||
parent_rate = parent->rate;
|
||||
if (parent) {
|
||||
req->best_parent_hw = parent->hw;
|
||||
req->best_parent_rate = parent->rate;
|
||||
} else {
|
||||
req->best_parent_hw = NULL;
|
||||
req->best_parent_rate = 0;
|
||||
}
|
||||
|
||||
if (core->ops->determine_rate) {
|
||||
parent_hw = parent ? parent->hw : NULL;
|
||||
return core->ops->determine_rate(core->hw, rate,
|
||||
min_rate, max_rate,
|
||||
&parent_rate, &parent_hw);
|
||||
} else if (core->ops->round_rate)
|
||||
return core->ops->round_rate(core->hw, rate, &parent_rate);
|
||||
else if (core->flags & CLK_SET_RATE_PARENT)
|
||||
return clk_core_round_rate_nolock(core->parent, rate, min_rate,
|
||||
max_rate);
|
||||
else
|
||||
return core->rate;
|
||||
return core->ops->determine_rate(core->hw, req);
|
||||
} else if (core->ops->round_rate) {
|
||||
rate = core->ops->round_rate(core->hw, req->rate,
|
||||
&req->best_parent_rate);
|
||||
if (rate < 0)
|
||||
return rate;
|
||||
|
||||
req->rate = rate;
|
||||
} else if (core->flags & CLK_SET_RATE_PARENT) {
|
||||
return clk_core_round_rate_nolock(parent, req);
|
||||
} else {
|
||||
req->rate = core->rate;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -800,38 +824,32 @@ static unsigned long clk_core_round_rate_nolock(struct clk_core *core,
|
|||
*
|
||||
* Useful for clk_ops such as .set_rate and .determine_rate.
|
||||
*/
|
||||
unsigned long __clk_determine_rate(struct clk_hw *hw,
|
||||
unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate)
|
||||
int __clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
|
||||
{
|
||||
if (!hw)
|
||||
if (!hw) {
|
||||
req->rate = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return clk_core_round_rate_nolock(hw->core, rate, min_rate, max_rate);
|
||||
return clk_core_round_rate_nolock(hw->core, req);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__clk_determine_rate);
|
||||
|
||||
/**
|
||||
* __clk_round_rate - round the given rate for a clk
|
||||
* @clk: round the rate of this clock
|
||||
* @rate: the rate which is to be rounded
|
||||
*
|
||||
* Useful for clk_ops such as .set_rate
|
||||
*/
|
||||
unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
|
||||
unsigned long clk_hw_round_rate(struct clk_hw *hw, unsigned long rate)
|
||||
{
|
||||
unsigned long min_rate;
|
||||
unsigned long max_rate;
|
||||
int ret;
|
||||
struct clk_rate_request req;
|
||||
|
||||
if (!clk)
|
||||
clk_core_get_boundaries(hw->core, &req.min_rate, &req.max_rate);
|
||||
req.rate = rate;
|
||||
|
||||
ret = clk_core_round_rate_nolock(hw->core, &req);
|
||||
if (ret)
|
||||
return 0;
|
||||
|
||||
clk_core_get_boundaries(clk->core, &min_rate, &max_rate);
|
||||
|
||||
return clk_core_round_rate_nolock(clk->core, rate, min_rate, max_rate);
|
||||
return req.rate;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__clk_round_rate);
|
||||
EXPORT_SYMBOL_GPL(clk_hw_round_rate);
|
||||
|
||||
/**
|
||||
* clk_round_rate - round the given rate for a clk
|
||||
|
@ -844,16 +862,24 @@ EXPORT_SYMBOL_GPL(__clk_round_rate);
|
|||
*/
|
||||
long clk_round_rate(struct clk *clk, unsigned long rate)
|
||||
{
|
||||
unsigned long ret;
|
||||
struct clk_rate_request req;
|
||||
int ret;
|
||||
|
||||
if (!clk)
|
||||
return 0;
|
||||
|
||||
clk_prepare_lock();
|
||||
ret = __clk_round_rate(clk, rate);
|
||||
|
||||
clk_core_get_boundaries(clk->core, &req.min_rate, &req.max_rate);
|
||||
req.rate = rate;
|
||||
|
||||
ret = clk_core_round_rate_nolock(clk->core, &req);
|
||||
clk_prepare_unlock();
|
||||
|
||||
return ret;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return req.rate;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_round_rate);
|
||||
|
||||
|
@ -1064,18 +1090,40 @@ static int clk_fetch_parent_index(struct clk_core *core,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the orphan status of @core and all its children.
|
||||
*/
|
||||
static void clk_core_update_orphan_status(struct clk_core *core, bool is_orphan)
|
||||
{
|
||||
struct clk_core *child;
|
||||
|
||||
core->orphan = is_orphan;
|
||||
|
||||
hlist_for_each_entry(child, &core->children, child_node)
|
||||
clk_core_update_orphan_status(child, is_orphan);
|
||||
}
|
||||
|
||||
static void clk_reparent(struct clk_core *core, struct clk_core *new_parent)
|
||||
{
|
||||
bool was_orphan = core->orphan;
|
||||
|
||||
hlist_del(&core->child_node);
|
||||
|
||||
if (new_parent) {
|
||||
bool becomes_orphan = new_parent->orphan;
|
||||
|
||||
/* avoid duplicate POST_RATE_CHANGE notifications */
|
||||
if (new_parent->new_child == core)
|
||||
new_parent->new_child = NULL;
|
||||
|
||||
hlist_add_head(&core->child_node, &new_parent->children);
|
||||
|
||||
if (was_orphan != becomes_orphan)
|
||||
clk_core_update_orphan_status(core, becomes_orphan);
|
||||
} else {
|
||||
hlist_add_head(&core->child_node, &clk_orphan_list);
|
||||
if (!was_orphan)
|
||||
clk_core_update_orphan_status(core, true);
|
||||
}
|
||||
|
||||
core->parent = new_parent;
|
||||
|
@ -1160,14 +1208,8 @@ static int __clk_set_parent(struct clk_core *core, struct clk_core *parent,
|
|||
flags = clk_enable_lock();
|
||||
clk_reparent(core, old_parent);
|
||||
clk_enable_unlock(flags);
|
||||
__clk_set_parent_after(core, old_parent, parent);
|
||||
|
||||
if (core->prepare_count) {
|
||||
flags = clk_enable_lock();
|
||||
clk_core_disable(core);
|
||||
clk_core_disable(parent);
|
||||
clk_enable_unlock(flags);
|
||||
clk_core_unprepare(parent);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1249,7 +1291,6 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *core,
|
|||
{
|
||||
struct clk_core *top = core;
|
||||
struct clk_core *old_parent, *parent;
|
||||
struct clk_hw *parent_hw;
|
||||
unsigned long best_parent_rate = 0;
|
||||
unsigned long new_rate;
|
||||
unsigned long min_rate;
|
||||
|
@ -1270,20 +1311,29 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *core,
|
|||
|
||||
/* find the closest rate and parent clk/rate */
|
||||
if (core->ops->determine_rate) {
|
||||
parent_hw = parent ? parent->hw : NULL;
|
||||
ret = core->ops->determine_rate(core->hw, rate,
|
||||
min_rate,
|
||||
max_rate,
|
||||
&best_parent_rate,
|
||||
&parent_hw);
|
||||
struct clk_rate_request req;
|
||||
|
||||
req.rate = rate;
|
||||
req.min_rate = min_rate;
|
||||
req.max_rate = max_rate;
|
||||
if (parent) {
|
||||
req.best_parent_hw = parent->hw;
|
||||
req.best_parent_rate = parent->rate;
|
||||
} else {
|
||||
req.best_parent_hw = NULL;
|
||||
req.best_parent_rate = 0;
|
||||
}
|
||||
|
||||
ret = core->ops->determine_rate(core->hw, &req);
|
||||
if (ret < 0)
|
||||
return NULL;
|
||||
|
||||
new_rate = ret;
|
||||
parent = parent_hw ? parent_hw->core : NULL;
|
||||
best_parent_rate = req.best_parent_rate;
|
||||
new_rate = req.rate;
|
||||
parent = req.best_parent_hw ? req.best_parent_hw->core : NULL;
|
||||
} else if (core->ops->round_rate) {
|
||||
ret = core->ops->round_rate(core->hw, rate,
|
||||
&best_parent_rate);
|
||||
&best_parent_rate);
|
||||
if (ret < 0)
|
||||
return NULL;
|
||||
|
||||
|
@ -1592,8 +1642,12 @@ struct clk *clk_get_parent(struct clk *clk)
|
|||
{
|
||||
struct clk *parent;
|
||||
|
||||
if (!clk)
|
||||
return NULL;
|
||||
|
||||
clk_prepare_lock();
|
||||
parent = __clk_get_parent(clk);
|
||||
/* TODO: Create a per-user clk and change callers to call clk_put */
|
||||
parent = !clk->core->parent ? NULL : clk->core->parent->hw->clk;
|
||||
clk_prepare_unlock();
|
||||
|
||||
return parent;
|
||||
|
@ -2324,13 +2378,17 @@ static int __clk_init(struct device *dev, struct clk *clk_user)
|
|||
* clocks and re-parent any that are children of the clock currently
|
||||
* being clk_init'd.
|
||||
*/
|
||||
if (core->parent)
|
||||
if (core->parent) {
|
||||
hlist_add_head(&core->child_node,
|
||||
&core->parent->children);
|
||||
else if (core->flags & CLK_IS_ROOT)
|
||||
core->orphan = core->parent->orphan;
|
||||
} else if (core->flags & CLK_IS_ROOT) {
|
||||
hlist_add_head(&core->child_node, &clk_root_list);
|
||||
else
|
||||
core->orphan = false;
|
||||
} else {
|
||||
hlist_add_head(&core->child_node, &clk_orphan_list);
|
||||
core->orphan = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set clk's accuracy. The preferred method is to use
|
||||
|
@ -2479,6 +2537,8 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
|
|||
core->hw = hw;
|
||||
core->flags = hw->init->flags;
|
||||
core->num_parents = hw->init->num_parents;
|
||||
core->min_rate = 0;
|
||||
core->max_rate = ULONG_MAX;
|
||||
hw->core = core;
|
||||
|
||||
/* allocate local copy in case parent_names is __initdata */
|
||||
|
@ -3054,8 +3114,6 @@ struct clock_provider {
|
|||
struct list_head node;
|
||||
};
|
||||
|
||||
static LIST_HEAD(clk_provider_list);
|
||||
|
||||
/*
|
||||
* This function looks for a parent clock. If there is one, then it
|
||||
* checks that the provider for this parent clock was initialized, in
|
||||
|
@ -3106,14 +3164,24 @@ void __init of_clk_init(const struct of_device_id *matches)
|
|||
struct clock_provider *clk_provider, *next;
|
||||
bool is_init_done;
|
||||
bool force = false;
|
||||
LIST_HEAD(clk_provider_list);
|
||||
|
||||
if (!matches)
|
||||
matches = &__clk_of_table;
|
||||
|
||||
/* First prepare the list of the clocks providers */
|
||||
for_each_matching_node_and_match(np, matches, &match) {
|
||||
struct clock_provider *parent =
|
||||
kzalloc(sizeof(struct clock_provider), GFP_KERNEL);
|
||||
struct clock_provider *parent;
|
||||
|
||||
parent = kzalloc(sizeof(*parent), GFP_KERNEL);
|
||||
if (!parent) {
|
||||
list_for_each_entry_safe(clk_provider, next,
|
||||
&clk_provider_list, node) {
|
||||
list_del(&clk_provider->node);
|
||||
kfree(clk_provider);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
parent->clk_init_cb = match->data;
|
||||
parent->np = np;
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
* Copyright 2015 Yoshinori Sato <ysato@users.sourceforge.jp>
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
|
@ -15,7 +13,7 @@ static DEFINE_SPINLOCK(clklock);
|
|||
|
||||
static void __init h8300_div_clk_setup(struct device_node *node)
|
||||
{
|
||||
unsigned int num_parents;
|
||||
int num_parents;
|
||||
struct clk *clk;
|
||||
const char *clk_name = node->name;
|
||||
const char *parent_name;
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
* Copyright 2015 Yoshinori Sato <ysato@users.sourceforge.jp>
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/device.h>
|
||||
|
@ -28,7 +26,7 @@ static unsigned long pll_recalc_rate(struct clk_hw *hw,
|
|||
unsigned long parent_rate)
|
||||
{
|
||||
struct pll_clock *pll_clock = to_pll_clock(hw);
|
||||
int mul = 1 << (ctrl_inb((unsigned long)pll_clock->pllcr) & 3);
|
||||
int mul = 1 << (readb(pll_clock->pllcr) & 3);
|
||||
|
||||
return parent_rate * mul;
|
||||
}
|
||||
|
@ -65,13 +63,13 @@ static int pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
|
||||
pll = ((rate / parent_rate) / 2) & 0x03;
|
||||
spin_lock_irqsave(&clklock, flags);
|
||||
val = ctrl_inb((unsigned long)pll_clock->sckcr);
|
||||
val = readb(pll_clock->sckcr);
|
||||
val |= 0x08;
|
||||
ctrl_outb(val, (unsigned long)pll_clock->sckcr);
|
||||
val = ctrl_inb((unsigned long)pll_clock->pllcr);
|
||||
writeb(val, pll_clock->sckcr);
|
||||
val = readb(pll_clock->pllcr);
|
||||
val &= ~0x03;
|
||||
val |= pll;
|
||||
ctrl_outb(val, (unsigned long)pll_clock->pllcr);
|
||||
writeb(val, pll_clock->pllcr);
|
||||
spin_unlock_irqrestore(&clklock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
@ -84,7 +82,7 @@ static const struct clk_ops pll_ops = {
|
|||
|
||||
static void __init h8s2678_pll_clk_setup(struct device_node *node)
|
||||
{
|
||||
unsigned int num_parents;
|
||||
int num_parents;
|
||||
struct clk *clk;
|
||||
const char *clk_name = node->name;
|
||||
const char *parent_name;
|
||||
|
@ -98,11 +96,9 @@ static void __init h8s2678_pll_clk_setup(struct device_node *node)
|
|||
}
|
||||
|
||||
|
||||
pll_clock = kzalloc(sizeof(struct pll_clock), GFP_KERNEL);
|
||||
if (!pll_clock) {
|
||||
pr_err("%s: failed to alloc memory", clk_name);
|
||||
pll_clock = kzalloc(sizeof(*pll_clock), GFP_KERNEL);
|
||||
if (!pll_clock)
|
||||
return;
|
||||
}
|
||||
|
||||
pll_clock->sckcr = of_iomap(node, 0);
|
||||
if (pll_clock->sckcr == NULL) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
config COMMON_CLK_HI6220
|
||||
bool "Hi6220 Clock Driver"
|
||||
depends on ARCH_HISI || COMPILE_TEST
|
||||
depends on (ARCH_HISI || COMPILE_TEST) && MAILBOX
|
||||
default ARCH_HISI
|
||||
help
|
||||
Build the Hisilicon Hi6220 clock driver based on the common clock framework.
|
||||
|
|
|
@ -7,4 +7,4 @@ obj-y += clk.o clkgate-separated.o clkdivider-hi6220.o
|
|||
obj-$(CONFIG_ARCH_HI3xxx) += clk-hi3620.o
|
||||
obj-$(CONFIG_ARCH_HIP04) += clk-hip04.o
|
||||
obj-$(CONFIG_ARCH_HIX5HD2) += clk-hix5hd2.o
|
||||
obj-$(CONFIG_COMMON_CLK_HI6220) += clk-hi6220.o
|
||||
obj-$(CONFIG_COMMON_CLK_HI6220) += clk-hi6220.o clk-hi6220-stub.o
|
||||
|
|
|
@ -25,13 +25,11 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include <dt-bindings/clock/hi3620-clock.h>
|
||||
|
||||
|
@ -294,34 +292,29 @@ static unsigned long mmc_clk_recalc_rate(struct clk_hw *hw,
|
|||
}
|
||||
}
|
||||
|
||||
static long mmc_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long min_rate,
|
||||
unsigned long max_rate,
|
||||
unsigned long *best_parent_rate,
|
||||
struct clk_hw **best_parent_p)
|
||||
static int mmc_clk_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_mmc *mclk = to_mmc(hw);
|
||||
unsigned long best = 0;
|
||||
|
||||
if ((rate <= 13000000) && (mclk->id == HI3620_MMC_CIUCLK1)) {
|
||||
rate = 13000000;
|
||||
best = 26000000;
|
||||
} else if (rate <= 26000000) {
|
||||
rate = 25000000;
|
||||
best = 180000000;
|
||||
} else if (rate <= 52000000) {
|
||||
rate = 50000000;
|
||||
best = 360000000;
|
||||
} else if (rate <= 100000000) {
|
||||
rate = 100000000;
|
||||
best = 720000000;
|
||||
if ((req->rate <= 13000000) && (mclk->id == HI3620_MMC_CIUCLK1)) {
|
||||
req->rate = 13000000;
|
||||
req->best_parent_rate = 26000000;
|
||||
} else if (req->rate <= 26000000) {
|
||||
req->rate = 25000000;
|
||||
req->best_parent_rate = 180000000;
|
||||
} else if (req->rate <= 52000000) {
|
||||
req->rate = 50000000;
|
||||
req->best_parent_rate = 360000000;
|
||||
} else if (req->rate <= 100000000) {
|
||||
req->rate = 100000000;
|
||||
req->best_parent_rate = 720000000;
|
||||
} else {
|
||||
/* max is 180M */
|
||||
rate = 180000000;
|
||||
best = 1440000000;
|
||||
req->rate = 180000000;
|
||||
req->best_parent_rate = 1440000000;
|
||||
}
|
||||
*best_parent_rate = best;
|
||||
return rate;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static u32 mmc_clk_delay(u32 val, u32 para, u32 off, u32 len)
|
||||
|
|
276
drivers/clk/hisilicon/clk-hi6220-stub.c
Normal file
276
drivers/clk/hisilicon/clk-hi6220-stub.c
Normal file
|
@ -0,0 +1,276 @@
|
|||
/*
|
||||
* Hi6220 stub clock driver
|
||||
*
|
||||
* Copyright (c) 2015 Hisilicon Limited.
|
||||
* Copyright (c) 2015 Linaro Limited.
|
||||
*
|
||||
* Author: Leo Yan <leo.yan@linaro.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/mailbox_client.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
/* Stub clocks id */
|
||||
#define HI6220_STUB_ACPU0 0
|
||||
#define HI6220_STUB_ACPU1 1
|
||||
#define HI6220_STUB_GPU 2
|
||||
#define HI6220_STUB_DDR 5
|
||||
|
||||
/* Mailbox message */
|
||||
#define HI6220_MBOX_MSG_LEN 8
|
||||
|
||||
#define HI6220_MBOX_FREQ 0xA
|
||||
#define HI6220_MBOX_CMD_SET 0x3
|
||||
#define HI6220_MBOX_OBJ_AP 0x0
|
||||
|
||||
/* CPU dynamic frequency scaling */
|
||||
#define ACPU_DFS_FREQ_MAX 0x1724
|
||||
#define ACPU_DFS_CUR_FREQ 0x17CC
|
||||
#define ACPU_DFS_FLAG 0x1B30
|
||||
#define ACPU_DFS_FREQ_REQ 0x1B34
|
||||
#define ACPU_DFS_FREQ_LMT 0x1B38
|
||||
#define ACPU_DFS_LOCK_FLAG 0xAEAEAEAE
|
||||
|
||||
#define to_stub_clk(hw) container_of(hw, struct hi6220_stub_clk, hw)
|
||||
|
||||
struct hi6220_stub_clk {
|
||||
u32 id;
|
||||
|
||||
struct device *dev;
|
||||
struct clk_hw hw;
|
||||
|
||||
struct regmap *dfs_map;
|
||||
struct mbox_client cl;
|
||||
struct mbox_chan *mbox;
|
||||
};
|
||||
|
||||
struct hi6220_mbox_msg {
|
||||
unsigned char type;
|
||||
unsigned char cmd;
|
||||
unsigned char obj;
|
||||
unsigned char src;
|
||||
unsigned char para[4];
|
||||
};
|
||||
|
||||
union hi6220_mbox_data {
|
||||
unsigned int data[HI6220_MBOX_MSG_LEN];
|
||||
struct hi6220_mbox_msg msg;
|
||||
};
|
||||
|
||||
static unsigned int hi6220_acpu_get_freq(struct hi6220_stub_clk *stub_clk)
|
||||
{
|
||||
unsigned int freq;
|
||||
|
||||
regmap_read(stub_clk->dfs_map, ACPU_DFS_CUR_FREQ, &freq);
|
||||
return freq;
|
||||
}
|
||||
|
||||
static int hi6220_acpu_set_freq(struct hi6220_stub_clk *stub_clk,
|
||||
unsigned int freq)
|
||||
{
|
||||
union hi6220_mbox_data data;
|
||||
|
||||
/* set the frequency in sram */
|
||||
regmap_write(stub_clk->dfs_map, ACPU_DFS_FREQ_REQ, freq);
|
||||
|
||||
/* compound mailbox message */
|
||||
data.msg.type = HI6220_MBOX_FREQ;
|
||||
data.msg.cmd = HI6220_MBOX_CMD_SET;
|
||||
data.msg.obj = HI6220_MBOX_OBJ_AP;
|
||||
data.msg.src = HI6220_MBOX_OBJ_AP;
|
||||
|
||||
mbox_send_message(stub_clk->mbox, &data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hi6220_acpu_round_freq(struct hi6220_stub_clk *stub_clk,
|
||||
unsigned int freq)
|
||||
{
|
||||
unsigned int limit_flag, limit_freq = UINT_MAX;
|
||||
unsigned int max_freq;
|
||||
|
||||
/* check the constrained frequency */
|
||||
regmap_read(stub_clk->dfs_map, ACPU_DFS_FLAG, &limit_flag);
|
||||
if (limit_flag == ACPU_DFS_LOCK_FLAG)
|
||||
regmap_read(stub_clk->dfs_map, ACPU_DFS_FREQ_LMT, &limit_freq);
|
||||
|
||||
/* check the supported maximum frequency */
|
||||
regmap_read(stub_clk->dfs_map, ACPU_DFS_FREQ_MAX, &max_freq);
|
||||
|
||||
/* calculate the real maximum frequency */
|
||||
max_freq = min(max_freq, limit_freq);
|
||||
|
||||
if (WARN_ON(freq > max_freq))
|
||||
freq = max_freq;
|
||||
|
||||
return freq;
|
||||
}
|
||||
|
||||
static unsigned long hi6220_stub_clk_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
u32 rate = 0;
|
||||
struct hi6220_stub_clk *stub_clk = to_stub_clk(hw);
|
||||
|
||||
switch (stub_clk->id) {
|
||||
case HI6220_STUB_ACPU0:
|
||||
rate = hi6220_acpu_get_freq(stub_clk);
|
||||
|
||||
/* convert from kHz to Hz */
|
||||
rate *= 1000;
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(stub_clk->dev, "%s: un-supported clock id %d\n",
|
||||
__func__, stub_clk->id);
|
||||
break;
|
||||
}
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
static int hi6220_stub_clk_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct hi6220_stub_clk *stub_clk = to_stub_clk(hw);
|
||||
unsigned long new_rate = rate / 1000; /* kHz */
|
||||
int ret = 0;
|
||||
|
||||
switch (stub_clk->id) {
|
||||
case HI6220_STUB_ACPU0:
|
||||
ret = hi6220_acpu_set_freq(stub_clk, new_rate);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(stub_clk->dev, "%s: un-supported clock id %d\n",
|
||||
__func__, stub_clk->id);
|
||||
break;
|
||||
}
|
||||
|
||||
pr_debug("%s: set rate=%ldkHz\n", __func__, new_rate);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long hi6220_stub_clk_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
struct hi6220_stub_clk *stub_clk = to_stub_clk(hw);
|
||||
unsigned long new_rate = rate / 1000; /* kHz */
|
||||
|
||||
switch (stub_clk->id) {
|
||||
case HI6220_STUB_ACPU0:
|
||||
new_rate = hi6220_acpu_round_freq(stub_clk, new_rate);
|
||||
|
||||
/* convert from kHz to Hz */
|
||||
new_rate *= 1000;
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(stub_clk->dev, "%s: un-supported clock id %d\n",
|
||||
__func__, stub_clk->id);
|
||||
break;
|
||||
}
|
||||
|
||||
return new_rate;
|
||||
}
|
||||
|
||||
static const struct clk_ops hi6220_stub_clk_ops = {
|
||||
.recalc_rate = hi6220_stub_clk_recalc_rate,
|
||||
.round_rate = hi6220_stub_clk_round_rate,
|
||||
.set_rate = hi6220_stub_clk_set_rate,
|
||||
};
|
||||
|
||||
static int hi6220_stub_clk_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct clk_init_data init;
|
||||
struct hi6220_stub_clk *stub_clk;
|
||||
struct clk *clk;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
int ret;
|
||||
|
||||
stub_clk = devm_kzalloc(dev, sizeof(*stub_clk), GFP_KERNEL);
|
||||
if (!stub_clk)
|
||||
return -ENOMEM;
|
||||
|
||||
stub_clk->dfs_map = syscon_regmap_lookup_by_phandle(np,
|
||||
"hisilicon,hi6220-clk-sram");
|
||||
if (IS_ERR(stub_clk->dfs_map)) {
|
||||
dev_err(dev, "failed to get sram regmap\n");
|
||||
return PTR_ERR(stub_clk->dfs_map);
|
||||
}
|
||||
|
||||
stub_clk->hw.init = &init;
|
||||
stub_clk->dev = dev;
|
||||
stub_clk->id = HI6220_STUB_ACPU0;
|
||||
|
||||
/* Use mailbox client with blocking mode */
|
||||
stub_clk->cl.dev = dev;
|
||||
stub_clk->cl.tx_done = NULL;
|
||||
stub_clk->cl.tx_block = true;
|
||||
stub_clk->cl.tx_tout = 500;
|
||||
stub_clk->cl.knows_txdone = false;
|
||||
|
||||
/* Allocate mailbox channel */
|
||||
stub_clk->mbox = mbox_request_channel(&stub_clk->cl, 0);
|
||||
if (IS_ERR(stub_clk->mbox)) {
|
||||
dev_err(dev, "failed get mailbox channel\n");
|
||||
return PTR_ERR(stub_clk->mbox);
|
||||
};
|
||||
|
||||
init.name = "acpu0";
|
||||
init.ops = &hi6220_stub_clk_ops;
|
||||
init.num_parents = 0;
|
||||
init.flags = CLK_IS_ROOT;
|
||||
|
||||
clk = devm_clk_register(dev, &stub_clk->hw);
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
ret = of_clk_add_provider(np, of_clk_src_simple_get, clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to register OF clock provider\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* initialize buffer to zero */
|
||||
regmap_write(stub_clk->dfs_map, ACPU_DFS_FLAG, 0x0);
|
||||
regmap_write(stub_clk->dfs_map, ACPU_DFS_FREQ_REQ, 0x0);
|
||||
regmap_write(stub_clk->dfs_map, ACPU_DFS_FREQ_LMT, 0x0);
|
||||
|
||||
dev_dbg(dev, "Registered clock '%s'\n", init.name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id hi6220_stub_clk_of_match[] = {
|
||||
{ .compatible = "hisilicon,hi6220-stub-clk", },
|
||||
{}
|
||||
};
|
||||
|
||||
static struct platform_driver hi6220_stub_clk_driver = {
|
||||
.driver = {
|
||||
.name = "hi6220-stub-clk",
|
||||
.of_match_table = hi6220_stub_clk_of_match,
|
||||
},
|
||||
.probe = hi6220_stub_clk_probe,
|
||||
};
|
||||
|
||||
static int __init hi6220_stub_clk_init(void)
|
||||
{
|
||||
return platform_driver_register(&hi6220_stub_clk_driver);
|
||||
}
|
||||
subsys_initcall(hi6220_stub_clk_init);
|
|
@ -24,13 +24,11 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include <dt-bindings/clock/hip04-clock.h>
|
||||
|
||||
|
|
|
@ -24,15 +24,14 @@
|
|||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
|
@ -45,14 +44,9 @@ struct hisi_clock_data __init *hisi_clk_init(struct device_node *np,
|
|||
struct clk **clk_table;
|
||||
void __iomem *base;
|
||||
|
||||
if (np) {
|
||||
base = of_iomap(np, 0);
|
||||
if (!base) {
|
||||
pr_err("failed to map Hisilicon clock registers\n");
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
pr_err("failed to find Hisilicon clock node in DTS\n");
|
||||
base = of_iomap(np, 0);
|
||||
if (!base) {
|
||||
pr_err("%s: failed to map clock registers\n", __func__);
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,10 +25,8 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
|
|
|
@ -22,5 +22,6 @@ obj-$(CONFIG_SOC_IMX5) += clk-imx51-imx53.o
|
|||
obj-$(CONFIG_SOC_IMX6Q) += clk-imx6q.o
|
||||
obj-$(CONFIG_SOC_IMX6SL) += clk-imx6sl.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_VF610) += clk-vf610.o
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user