Commit 1056c9bd authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'clk-for-linus-4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux

Pull clk updates from Michael Turquette:
 "The bulk of the changes are updates and fixes to existing clk provider
  drivers, along with a pretty standard number of new drivers.  The core
  recieved a small number of updates as well.

  Core changes of note:
   - removed CLK_IS_ROOT flag

  New clk provider drivers:
   - Renesas r8a7796 clock pulse generator / module standby and
     software reset
   - Allwinner sun8i H3 clock controller unit
   - AmLogic meson8b clock controller (rewritten)
   - AmLogic gxbb clock controller
   - support for some new ICs was added by simple changes to static
     data tables for chips sharing the same family

  Driver updates of note:
   - the Allwinner sunxi clock driver infrastucture was rewritten to
     comform to the state of the art at drivers/clk/sunxi-ng.  The old
     implementation is still supported for backwards compatibility with
     the DT ABI"

* tag 'clk-for-linus-4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (162 commits)
  clk: Makefile: re-sort and clean up
  Revert "clk: gxbb: expose CLKID_MMC_PCLK"
  clk: samsung: Allow modular build of the Audio Subsystem CLKCON driver
  clk: samsung: make clk-s5pv210-audss explicitly non-modular
  clk: exynos5433: remove CLK_IGNORE_UNUSED flag from SPI clocks
  clk: oxnas: Add hardware dependencies
  clk: imx7d: do not set parent of ethernet time/ref clocks
  ARM: dt: sun8i: switch the H3 to the new CCU driver
  clk: sunxi-ng: h3: Fix Kconfig symbol typo
  clk: sunxi-ng: h3: Fix audio clock divider offset
  clk: sunxi-ng: Add H3 clocks
  clk: sunxi-ng: Add N-K-M-P factor clock
  clk: sunxi-ng: Add N-K-M Factor clock
  clk: sunxi-ng: Add N-M-factor clock support
  clk: sunxi-ng: Add N-K-factor clock support
  clk: sunxi-ng: Add M-P factor clock support
  clk: sunxi-ng: Add divider
  clk: sunxi-ng: Add phase clock support
  clk: sunxi-ng: Add mux clock support
  clk: sunxi-ng: Add gate clock support
  ...
parents 797cee98 d22527fe
* Amlogic GXBB Clock and Reset Unit
The Amlogic GXBB clock controller generates and supplies clock to various
controllers within the SoC.
Required Properties:
- compatible: should be "amlogic,gxbb-clkc"
- reg: physical base address of the clock controller and length of memory
mapped region.
- #clock-cells: should be 1.
Each clock is assigned an identifier and client nodes can use this identifier
to specify the clock which they consume. All available clocks are defined as
preprocessor macros in the dt-bindings/clock/gxbb-clkc.h header and can be
used in device tree sources.
Example: Clock controller node:
clkc: clock-controller@c883c000 {
#clock-cells = <1>;
compatible = "amlogic,gxbb-clkc";
reg = <0x0 0xc883c000 0x0 0x3db>;
};
Example: UART controller node that consumes the clock generated by the clock
controller:
uart_AO: serial@c81004c0 {
compatible = "amlogic,meson-uart";
reg = <0xc81004c0 0x14>;
interrupts = <0 90 1>;
clocks = <&clkc CLKID_CLK81>;
status = "disabled";
};
......@@ -14,6 +14,10 @@ Required properties:
Optional properties:
- clock-output-names : From common clock binding.
Some clocks that require special treatments are also handled by that
driver, with the compatibles:
- allwinner,sun4i-a10-pll3-2x-clk
Example:
clock {
compatible = "fixed-factor-clock";
......
......@@ -13,7 +13,8 @@ They provide the following functionalities:
Required Properties:
- compatible: Must be one of:
- "renesas,r8a7795-cpg-mssr" for the r8a7795 SoC
- "renesas,r8a7795-cpg-mssr" for the r8a7795 SoC (R-Car H3)
- "renesas,r8a7796-cpg-mssr" for the r8a7796 SoC (R-Car M3-W)
- reg: Base address and length of the memory resource used by the CPG/MSSR
block
......@@ -21,8 +22,8 @@ Required Properties:
- clocks: References to external parent clocks, one entry for each entry in
clock-names
- clock-names: List of external parent clock names. Valid names are:
- "extal" (r8a7795)
- "extalr" (r8a7795)
- "extal" (r8a7795, r8a7796)
- "extalr" (r8a7795, r8a7796)
- #clock-cells: Must be 2
- For CPG core clocks, the two clock specifier cells must be "CPG_CORE"
......
......@@ -17,6 +17,7 @@ Required Properties:
- "renesas,r8a7779-mstp-clocks" for R8A7779 (R-Car H1) MSTP gate clocks
- "renesas,r8a7790-mstp-clocks" for R8A7790 (R-Car H2) MSTP gate clocks
- "renesas,r8a7791-mstp-clocks" for R8A7791 (R-Car M2-W) MSTP gate clocks
- "renesas,r8a7792-mstp-clocks" for R8A7792 (R-Car V2H) MSTP gate clocks
- "renesas,r8a7793-mstp-clocks" for R8A7793 (R-Car M2-N) MSTP gate clocks
- "renesas,r8a7794-mstp-clocks" for R8A7794 (R-Car E2) MSTP gate clocks
- "renesas,sh73a0-mstp-clocks" for SH73A0 (SH-MobileAG5) MSTP gate clocks
......
......@@ -10,6 +10,7 @@ Required Properties:
- compatible: Must be one of
- "renesas,r8a7790-cpg-clocks" for the r8a7790 CPG
- "renesas,r8a7791-cpg-clocks" for the r8a7791 CPG
- "renesas,r8a7792-cpg-clocks" for the r8a7792 CPG
- "renesas,r8a7793-cpg-clocks" for the r8a7793 CPG
- "renesas,r8a7794-cpg-clocks" for the r8a7794 CPG
and "renesas,rcar-gen2-cpg-clocks" as a fallback.
......
Allwinner Clock Control Unit Binding
------------------------------------
Required properties :
- compatible: must contain one of the following compatible:
- "allwinner,sun8i-h3-ccu"
- reg: Must contain the registers base address and length
- clocks: phandle to the oscillators feeding the CCU. Two are needed:
- "hosc": the high frequency oscillator (usually at 24MHz)
- "losc": the low frequency oscillator (usually at 32kHz)
- clock-names: Must contain the clock names described just above
- #clock-cells : must contain 1
- #reset-cells : must contain 1
Example:
ccu: clock@01c20000 {
compatible = "allwinner,sun8i-h3-ccu";
reg = <0x01c20000 0x400>;
clocks = <&osc24M>, <&osc32k>;
clock-names = "hosc", "losc";
#clock-cells = <1>;
#reset-cells = <1>;
};
This diff is collapsed.
......@@ -49,10 +49,10 @@ config COMMON_CLK_MAX77802
This driver supports Maxim 77802 crystal oscillator clock.
config COMMON_CLK_RK808
tristate "Clock driver for RK808"
tristate "Clock driver for RK808/RK818"
depends on MFD_RK808
---help---
This driver supports RK808 crystal oscillator clock. These
This driver supports RK808 and RK818 crystal oscillator clock. These
multi-function devices have two fixed-rate oscillators,
clocked at 32KHz each. Clkout1 is always on, Clkout2 can off
by control register.
......@@ -203,16 +203,19 @@ config COMMON_CLK_PIC32
config COMMON_CLK_OXNAS
bool "Clock driver for the OXNAS SoC Family"
depends on ARCH_OXNAS || COMPILE_TEST
select MFD_SYSCON
---help---
Support for the OXNAS SoC Family clocks.
source "drivers/clk/bcm/Kconfig"
source "drivers/clk/hisilicon/Kconfig"
source "drivers/clk/meson/Kconfig"
source "drivers/clk/mvebu/Kconfig"
source "drivers/clk/qcom/Kconfig"
source "drivers/clk/renesas/Kconfig"
source "drivers/clk/samsung/Kconfig"
source "drivers/clk/sunxi-ng/Kconfig"
source "drivers/clk/tegra/Kconfig"
source "drivers/clk/ti/Kconfig"
......
......@@ -16,13 +16,14 @@ obj-$(CONFIG_COMMON_CLK) += clk-conf.o
endif
# hardware specific clock types
# please keep this section sorted lexicographically by file/directory path name
# please keep this section sorted lexicographically by file path name
obj-$(CONFIG_MACH_ASM9260) += clk-asm9260.o
obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o
obj-$(CONFIG_ARCH_AXXIA) += clk-axm5516.o
obj-$(CONFIG_COMMON_CLK_CDCE706) += clk-cdce706.o
obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o
obj-$(CONFIG_COMMON_CLK_CDCE925) += clk-cdce925.o
obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o
obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o
obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
obj-$(CONFIG_MACH_LOONGSON32) += clk-ls1x.o
......@@ -35,6 +36,7 @@ obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o
obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o
obj-$(CONFIG_COMMON_CLK_OXNAS) += clk-oxnas.o
obj-$(CONFIG_COMMON_CLK_PALMAS) += clk-palmas.o
obj-$(CONFIG_COMMON_CLK_PWM) += clk-pwm.o
obj-$(CONFIG_CLK_QORIQ) += clk-qoriq.o
obj-$(CONFIG_COMMON_CLK_RK808) += clk-rk808.o
obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o
......@@ -42,7 +44,6 @@ obj-$(CONFIG_COMMON_CLK_SCPI) += clk-scpi.o
obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o
obj-$(CONFIG_COMMON_CLK_SI514) += clk-si514.o
obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o
obj-$(CONFIG_COMMON_CLK_CDCE925) += clk-cdce925.o
obj-$(CONFIG_ARCH_STM32) += clk-stm32f4.o
obj-$(CONFIG_ARCH_TANGO) += clk-tango4.o
obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o
......@@ -50,35 +51,39 @@ obj-$(CONFIG_ARCH_U300) += clk-u300.o
obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o
obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o
obj-$(CONFIG_COMMON_CLK_PWM) += clk-pwm.o
# please keep this section sorted lexicographically by directory path name
obj-$(CONFIG_COMMON_CLK_AT91) += at91/
obj-$(CONFIG_ARCH_ARTPEC) += axis/
obj-$(CONFIG_ARC_PLAT_AXS10X) += axs10x/
obj-y += bcm/
obj-$(CONFIG_ARCH_BERLIN) += berlin/
obj-$(CONFIG_H8300) += h8300/
obj-$(CONFIG_ARCH_HISI) += hisilicon/
obj-$(CONFIG_ARCH_MXC) += imx/
obj-$(CONFIG_MACH_INGENIC) += ingenic/
obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/
obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/
obj-$(CONFIG_COMMON_CLK_AMLOGIC) += meson/
obj-$(CONFIG_MACH_PIC32) += microchip/
ifeq ($(CONFIG_COMMON_CLK), y)
obj-$(CONFIG_ARCH_MMP) += mmp/
endif
obj-y += mvebu/
obj-$(CONFIG_ARCH_MESON) += meson/
obj-$(CONFIG_ARCH_MXS) += mxs/
obj-$(CONFIG_MACH_PISTACHIO) += pistachio/
obj-$(CONFIG_COMMON_CLK_NXP) += nxp/
obj-$(CONFIG_MACH_PISTACHIO) += pistachio/
obj-$(CONFIG_COMMON_CLK_PXA) += pxa/
obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/
obj-$(CONFIG_ARCH_RENESAS) += renesas/
obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/
obj-$(CONFIG_ARCH_RENESAS) += renesas/
obj-$(CONFIG_ARCH_SIRF) += sirf/
obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/
obj-$(CONFIG_PLAT_SPEAR) += spear/
obj-$(CONFIG_ARCH_STI) += st/
obj-$(CONFIG_ARCH_SUNXI) += sunxi/
obj-$(CONFIG_ARCH_SUNXI) += sunxi-ng/
obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-y += ti/
obj-$(CONFIG_ARCH_U8500) += ux500/
......@@ -86,5 +91,3 @@ obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/
obj-$(CONFIG_X86) += x86/
obj-$(CONFIG_ARCH_ZX) += zte/
obj-$(CONFIG_ARCH_ZYNQ) += zynq/
obj-$(CONFIG_H8300) += h8300/
obj-$(CONFIG_ARC_PLAT_AXS10X) += axs10x/
......@@ -267,7 +267,7 @@ at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, const char
return clk;
}
void __init of_sama5d2_clk_generated_setup(struct device_node *np)
static void __init of_sama5d2_clk_generated_setup(struct device_node *np)
{
int num;
u32 id;
......
......@@ -20,6 +20,8 @@
#include <linux/clkdev.h>
#include <linux/of_address.h>
#include "clk-iproc.h"
#define IPROC_CLK_MAX_FREQ_POLICY 0x3
#define IPROC_CLK_POLICY_FREQ_OFFSET 0x008
#define IPROC_CLK_POLICY_FREQ_POLICY_FREQ_SHIFT 8
......@@ -242,7 +244,6 @@ static const struct clk_ops iproc_arm_pll_ops = {
void __init iproc_armpll_setup(struct device_node *node)
{
int ret;
struct clk *clk;
struct iproc_arm_pll *pll;
struct clk_init_data init;
const char *parent_name;
......@@ -263,18 +264,18 @@ void __init iproc_armpll_setup(struct device_node *node)
init.num_parents = (parent_name ? 1 : 0);
pll->hw.init = &init;
clk = clk_register(NULL, &pll->hw);
if (WARN_ON(IS_ERR(clk)))
ret = clk_hw_register(NULL, &pll->hw);
if (WARN_ON(ret))
goto err_iounmap;
ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, &pll->hw);
if (WARN_ON(ret))
goto err_clk_unregister;
return;
err_clk_unregister:
clk_unregister(clk);
clk_hw_unregister(&pll->hw);
err_iounmap:
iounmap(pll->base);
err_free_pll:
......
......@@ -37,7 +37,7 @@ struct iproc_asiu {
void __iomem *div_base;
void __iomem *gate_base;
struct clk_onecell_data clk_data;
struct clk_hw_onecell_data *clk_data;
struct iproc_asiu_clk *clks;
};
......@@ -197,11 +197,11 @@ void __init iproc_asiu_setup(struct device_node *node,
if (WARN_ON(!asiu))
return;
asiu->clk_data.clk_num = num_clks;
asiu->clk_data.clks = kcalloc(num_clks, sizeof(*asiu->clk_data.clks),
GFP_KERNEL);
if (WARN_ON(!asiu->clk_data.clks))
asiu->clk_data = kzalloc(sizeof(*asiu->clk_data->hws) * num_clks +
sizeof(*asiu->clk_data), GFP_KERNEL);
if (WARN_ON(!asiu->clk_data))
goto err_clks;
asiu->clk_data->num = num_clks;
asiu->clks = kcalloc(num_clks, sizeof(*asiu->clks), GFP_KERNEL);
if (WARN_ON(!asiu->clks))
......@@ -217,7 +217,6 @@ void __init iproc_asiu_setup(struct device_node *node,
for (i = 0; i < num_clks; i++) {
struct clk_init_data init;
struct clk *clk;
const char *parent_name;
struct iproc_asiu_clk *asiu_clk;
const char *clk_name;
......@@ -240,22 +239,22 @@ void __init iproc_asiu_setup(struct device_node *node,
init.num_parents = (parent_name ? 1 : 0);
asiu_clk->hw.init = &init;
clk = clk_register(NULL, &asiu_clk->hw);
if (WARN_ON(IS_ERR(clk)))
ret = clk_hw_register(NULL, &asiu_clk->hw);
if (WARN_ON(ret))
goto err_clk_register;
asiu->clk_data.clks[i] = clk;
asiu->clk_data->hws[i] = &asiu_clk->hw;
}
ret = of_clk_add_provider(node, of_clk_src_onecell_get,
&asiu->clk_data);
ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get,
asiu->clk_data);
if (WARN_ON(ret))
goto err_clk_register;
return;
err_clk_register:
for (i = 0; i < num_clks; i++)
clk_unregister(asiu->clk_data.clks[i]);
while (--i >= 0)
clk_hw_unregister(asiu->clk_data->hws[i]);
iounmap(asiu->gate_base);
err_iomap_gate:
......@@ -265,7 +264,7 @@ void __init iproc_asiu_setup(struct device_node *node,
kfree(asiu->clks);
err_asiu_clks:
kfree(asiu->clk_data.clks);
kfree(asiu->clk_data);
err_clks:
kfree(asiu);
......
......@@ -89,7 +89,7 @@ struct iproc_pll {
const struct iproc_pll_vco_param *vco_param;
unsigned int num_vco_entries;
struct clk_onecell_data clk_data;
struct clk_hw_onecell_data *clk_data;
struct iproc_clk *clks;
};
......@@ -625,7 +625,6 @@ void __init iproc_pll_clk_setup(struct device_node *node,
unsigned int num_clks)
{
int i, ret;
struct clk *clk;
struct iproc_pll *pll;
struct iproc_clk *iclk;
struct clk_init_data init;
......@@ -638,11 +637,11 @@ void __init iproc_pll_clk_setup(struct device_node *node,
if (WARN_ON(!pll))
return;
pll->clk_data.clk_num = num_clks;
pll->clk_data.clks = kcalloc(num_clks, sizeof(*pll->clk_data.clks),
GFP_KERNEL);
if (WARN_ON(!pll->clk_data.clks))
pll->clk_data = kzalloc(sizeof(*pll->clk_data->hws) * num_clks +
sizeof(*pll->clk_data), GFP_KERNEL);
if (WARN_ON(!pll->clk_data))
goto err_clk_data;
pll->clk_data->num = num_clks;
pll->clks = kcalloc(num_clks, sizeof(*pll->clks), GFP_KERNEL);
if (WARN_ON(!pll->clks))
......@@ -694,11 +693,11 @@ void __init iproc_pll_clk_setup(struct device_node *node,
iproc_pll_sw_cfg(pll);
clk = clk_register(NULL, &iclk->hw);
if (WARN_ON(IS_ERR(clk)))
ret = clk_hw_register(NULL, &iclk->hw);
if (WARN_ON(ret))
goto err_pll_register;
pll->clk_data.clks[0] = clk;
pll->clk_data->hws[0] = &iclk->hw;
/* now initialize and register all leaf clocks */
for (i = 1; i < num_clks; i++) {
......@@ -724,22 +723,23 @@ void __init iproc_pll_clk_setup(struct device_node *node,
init.num_parents = (parent_name ? 1 : 0);
iclk->hw.init = &init;
clk = clk_register(NULL, &iclk->hw);
if (WARN_ON(IS_ERR(clk)))
ret = clk_hw_register(NULL, &iclk->hw);
if (WARN_ON(ret))
goto err_clk_register;
pll->clk_data.clks[i] = clk;
pll->clk_data->hws[i] = &iclk->hw;
}
ret = of_clk_add_provider(node, of_clk_src_onecell_get, &pll->clk_data);
ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get,
pll->clk_data);
if (WARN_ON(ret))
goto err_clk_register;
return;
err_clk_register:
for (i = 0; i < num_clks; i++)
clk_unregister(pll->clk_data.clks[i]);
while (--i >= 0)
clk_hw_unregister(pll->clk_data->hws[i]);
err_pll_register:
if (pll->status_base != pll->control_base)
......@@ -759,7 +759,7 @@ void __init iproc_pll_clk_setup(struct device_node *node,
kfree(pll->clks);
err_clks:
kfree(pll->clk_data.clks);
kfree(pll->clk_data);
err_clk_data:
kfree(pll);
......
......@@ -55,7 +55,7 @@ static int __set_clk_parents(struct device_node *node, bool clk_supplier)
}
clk = of_clk_get_from_provider(&clkspec);
if (IS_ERR(clk)) {
pr_warn("clk: couldn't get parent clock %d for %s\n",
pr_warn("clk: couldn't get assigned clock %d for %s\n",
index, node->full_name);
rc = PTR_ERR(clk);
goto err;
......
......@@ -142,6 +142,11 @@ void clk_hw_unregister_fixed_factor(struct clk_hw *hw)
EXPORT_SYMBOL_GPL(clk_hw_unregister_fixed_factor);
#ifdef CONFIG_OF
static const struct of_device_id set_rate_parent_matches[] = {
{ .compatible = "allwinner,sun4i-a10-pll3-2x-clk" },
{ /* Sentinel */ },
};
/**
* of_fixed_factor_clk_setup() - Setup function for simple fixed factor clock
*/
......@@ -150,6 +155,7 @@ void __init of_fixed_factor_clk_setup(struct device_node *node)
struct clk *clk;
const char *clk_name = node->name;
const char *parent_name;
unsigned long flags = 0;
u32 div, mult;
if (of_property_read_u32(node, "clock-div", &div)) {
......@@ -167,7 +173,10 @@ void __init of_fixed_factor_clk_setup(struct device_node *node)
of_property_read_string(node, "clock-output-names", &clk_name);
parent_name = of_clk_get_parent_name(node, 0);
clk = clk_register_fixed_factor(NULL, clk_name, parent_name, 0,
if (of_match_node(set_rate_parent_matches, node))
flags |= CLK_SET_RATE_PARENT;
clk = clk_register_fixed_factor(NULL, clk_name, parent_name, flags,
mult, div);
if (!IS_ERR(clk))
of_clk_add_provider(node, of_clk_src_simple_get, clk);
......
......@@ -145,6 +145,17 @@ void clk_unregister_fixed_rate(struct clk *clk)
}
EXPORT_SYMBOL_GPL(clk_unregister_fixed_rate);
void clk_hw_unregister_fixed_rate(struct clk_hw *hw)
{
struct clk_fixed_rate *fixed;
fixed = to_clk_fixed_rate(hw);
clk_hw_unregister(hw);
kfree(fixed);
}
EXPORT_SYMBOL_GPL(clk_hw_unregister_fixed_rate);
#ifdef CONFIG_OF
/**
* of_fixed_clk_setup() - Setup function for simple fixed rate clock
......
......@@ -275,7 +275,6 @@ static const struct clk_ops periclk_ops = {
static __init struct clk *hb_clk_init(struct device_node *node, const struct clk_ops *ops)
{
u32 reg;
struct clk *clk;
struct hb_clk *hb_clk;
const char *clk_name = node->name;
const char *parent_name;
......@@ -308,13 +307,13 @@ static __init struct clk *hb_clk_init(struct device_node *node, const struct clk
hb_clk->hw.init = &init;
clk = clk_register(NULL, &hb_clk->hw);
if (WARN_ON(IS_ERR(clk))) {
rc = clk_hw_register(NULL, &hb_clk->hw);
if (WARN_ON(rc)) {
kfree(hb_clk);
return NULL;
}
rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
return clk;
rc = of_clk_add_hw_provider(node, of_clk_hw_simple_get, &hb_clk->hw);
return hb_clk->hw.clk;
}
static void __init hb_pll_init(struct device_node *node)
......
......@@ -52,14 +52,28 @@ static unsigned long __bestmult(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate,
u8 width, unsigned long flags)
{
struct clk_multiplier *mult = to_clk_multiplier(hw);
unsigned long orig_parent_rate = *best_parent_rate;
unsigned long parent_rate, current_rate, best_rate = ~0;
unsigned int i, bestmult = 0;
unsigned int maxmult = (1 << width) - 1;
if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
bestmult = rate / orig_parent_rate;
/* Make sure we don't end up with a 0 multiplier */
if ((bestmult == 0) &&
!(mult->flags & CLK_MULTIPLIER_ZERO_BYPASS))
bestmult = 1;
if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT))
return rate / *best_parent_rate;
/* Make sure we don't overflow the multiplier */
if (bestmult > maxmult)
bestmult = maxmult;
return bestmult;
}
for (i = 1; i < ((1 << width) - 1); i++) {
for (i = 1; i < maxmult; i++) {
if (rate == orig_parent_rate * i) {
/*
* This is the best case for us if we have a
......
......@@ -253,11 +253,11 @@ static const struct clk_ops pll_clk_ops = {
.recalc_rate = pll_clk_recalc_rate,
};
static struct clk * __init
static struct clk_hw * __init
pll_clk_register(struct device *dev, const char *name,
const char *parent_name, u32 id)
{
struct clk *clk;
int ret;
struct clk_pll *pll;
struct clk_init_data init;
......@@ -281,11 +281,13 @@ pll_clk_register(struct device *dev, const char *name,
pr_debug("register PLL1 clock \"%s\"\n", name);
clk = clk_register(dev, &pll->hw);
if (IS_ERR(clk))
ret = clk_hw_register(dev, &pll->hw);
if (ret) {
kfree(pll);
return ERR_PTR(ret);
}
return clk;
return &pll->hw;
}
/*
......@@ -345,11 +347,11 @@ static const struct clk_ops src_clk_ops = {
.recalc_rate = src_clk_recalc_rate,
};
static struct clk * __init
static struct clk_hw * __init
src_clk_register(struct device *dev, const char *name,
const char *parent_name, u8 id)
{
struct clk *clk;
int ret;
struct clk_src *sclk;
struct clk_init_data init;
......@@ -376,11 +378,13 @@ src_clk_register(struct device *dev, const char *name,
pr_debug("register clock \"%s\" ID: %d group: %d bits: %08x\n",
name, id, sclk->group1, sclk->clkbit);
clk = clk_register(dev, &sclk->hw);
if (IS_ERR(clk))
ret = clk_hw_register(dev, &sclk->hw);
if (ret) {
kfree(sclk);
return ERR_PTR(ret);
}
return clk;
return &sclk->hw;
}
#ifdef CONFIG_DEBUG_FS
......@@ -508,7 +512,7 @@ device_initcall(nomadik_src_clk_init_debugfs);
static void __init of_nomadik_pll_setup(struct device_node *np)
{
struct clk *clk = ERR_PTR(-EINVAL);
struct clk_hw *hw;
const char *clk_name = np->name;
const char *parent_name;
u32 pll_id;
......@@ -522,16 +526,16 @@ static void __init of_nomadik_pll_setup(struct device_node *np)
return;
}
parent_name = of_clk_get_parent_name(np, 0);
clk = pll_clk_register(NULL, clk_name, parent_name, pll_id);
if (!IS_ERR(clk))
of_clk_add_provider(np, of_clk_src_simple_get, clk);
hw = pll_clk_register(NULL, clk_name, parent_name, pll_id);
if (!IS_ERR(hw))
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
CLK_OF_DECLARE(nomadik_pll_clk,
"st,nomadik-pll-clock", of_nomadik_pll_setup);
static void __init of_nomadik_hclk_setup(struct device_node *np)
{
struct clk *clk = ERR_PTR(-EINVAL);
struct clk_hw *hw;
const char *clk_name = np->name;
const char *parent_name;
......@@ -542,20 +546,20 @@ static void __init of_nomadik_hclk_setup(struct device_node *np)
/*
* The HCLK divides PLL1 with 1 (passthru), 2, 3 or 4.
*/
clk = clk_register_divider(NULL, clk_name, parent_name,
hw = clk_hw_register_divider(NULL, clk_name, parent_name,
0, src_base + SRC_CR,
13, 2,
CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
&src_lock);
if (!IS_ERR(clk))
of_clk_add_provider(np, of_clk_src_simple_get, clk);
if (!IS_ERR(hw))
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
CLK_OF_DECLARE(nomadik_hclk_clk,
"st,nomadik-hclk-clock", of_nomadik_hclk_setup);
static void __init of_nomadik_src_clk_setup(struct device_node *np)
{
struct clk *clk = ERR_PTR(-EINVAL);
struct clk_hw *hw;
const char *clk_name = np->name;
const char *parent_name;
u32 clk_id;
......@@ -569,9 +573,9 @@ static void __init of_nomadik_src_clk_setup(struct device_node *np)
return;
}
parent_name = of_clk_get_parent_name(np, 0);
clk = src_clk_register(NULL, clk_name, parent_name, clk_id);
if (!IS_ERR(clk))
of_clk_add_provider(np, of_clk_src_simple_get, clk);
hw = src_clk_register(NULL, clk_name, parent_name, clk_id);
if (!IS_ERR(hw))
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
CLK_OF_DECLARE(nomadik_src_clk,
"st,nomadik-src-clock", of_nomadik_src_clk_setup);
......@@ -18,7 +18,7 @@
#include <linux/clk-provider.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/stringify.h>
......@@ -170,26 +170,17 @@ static int oxnas_stdclk_probe(struct platform_device *pdev)
clk_oxnas->onecell_data);
}
static int oxnas_stdclk_remove(struct platform_device *pdev)
{
of_clk_del_provider(pdev->dev.of_node);
return 0;
}
static const struct of_device_id oxnas_stdclk_dt_ids[] = {
{ .compatible = "oxsemi,ox810se-stdclk" },
{ }
};
MODULE_DEVICE_TABLE(of, oxnas_stdclk_dt_ids);
static struct platform_driver oxnas_stdclk_driver = {
.probe = oxnas_stdclk_probe,
.remove = oxnas_stdclk_remove,
.driver = {
.name = "oxnas-stdclk",
.suppress_bind_attrs = true,
.of_match_table = oxnas_stdclk_dt_ids,
},
};
module_platform_driver(oxnas_stdclk_driver);
builtin_platform_driver(oxnas_stdclk_driver);
......@@ -137,7 +137,7 @@ static int s2mps11_clk_probe(struct platform_device *pdev)
{
struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
struct s2mps11_clk *s2mps11_clks;
struct clk_onecell_data *clk_data;
struct clk_hw_onecell_data *clk_data;
unsigned int s2mps11_reg;
int i, ret = 0;
enum sec_device_type hwid = platform_get_device_id(pdev)->driver_data;
......@@ -147,15 +147,12 @@ static int s2mps11_clk_probe(struct platform_device *pdev)
if (!s2mps11_clks)
return -ENOMEM;
clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data), GFP_KERNEL);
clk_data = devm_kzalloc(&pdev->dev, sizeof(*clk_data) +
sizeof(*clk_data->hws) * S2MPS11_CLKS_NUM,
GFP_KERNEL);
if (!clk_data)
return -ENOMEM;
clk_data->clks = devm_kcalloc(&pdev->dev, S2MPS11_CLKS_NUM,
sizeof(struct clk *), GFP_KERNEL);
if (!clk_data->clks)
return -ENOMEM;
switch (hwid) {
case S2MPS11X:
s2mps11_reg = S2MPS11_REG_RTC_CTRL;
......@@ -196,18 +193,18 @@ static int s2mps11_clk_probe(struct platform_device *pdev)
goto err_reg;
}
s2mps11_clks[i].lookup = clkdev_create(s2mps11_clks[i].clk,
s2mps11_clks[i].lookup = clkdev_hw_create(&s2mps11_clks[i].hw,
s2mps11_clks_init[i].name, NULL);
if (!s2mps11_clks[i].lookup) {
ret = -ENOMEM;
goto err_reg;
}
clk_data->clks[i] = s2mps11_clks[i].clk;
clk_data->hws[i] = &s2mps11_clks[i].hw;
}
clk_data->clk_num = S2MPS11_CLKS_NUM;
of_clk_add_provider(s2mps11_clks->clk_np, of_clk_src_onecell_get,
clk_data);
clk_data->num = S2MPS11_CLKS_NUM;
of_clk_add_hw_provider(s2mps11_clks->clk_np, of_clk_hw_onecell_get,
clk_data);
platform_set_drvdata(pdev, s2mps11_clks);
......
......@@ -136,7 +136,7 @@ static const u64 stm32f42xx_gate_map[] = { 0x000000f17ef417ffull,
0x0000000000000001ull,
0x04777f33f6fec9ffull };
static struct clk *clks[MAX_CLKS];
static struct clk_hw *clks[MAX_CLKS];
static DEFINE_SPINLOCK(stm32f4_clk_lock);
static void __iomem *base;
......@@ -281,7 +281,7 @@ static int stm32f4_rcc_lookup_clk_idx(u8 primary, u8 secondary)
(BIT_ULL_WORD(secondary) >= 2 ? hweight64(table[2]) : 0);
}
static struct clk *
static struct clk_hw *
stm32f4_rcc_lookup_clk(struct of_phandle_args *clkspec, void *data)
{
int i = stm32f4_rcc_lookup_clk_idx(clkspec->args[0], clkspec->args[1]);
......@@ -346,9 +346,9 @@ static void __init stm32f4_rcc_init(struct device_node *np)
clk_register_apb_mul(NULL, "apb2_mul", "apb2_div",
CLK_SET_RATE_PARENT, 15);
clks[SYSTICK] = clk_register_fixed_factor(NULL, "systick", "ahb_div",
clks[SYSTICK] = clk_hw_register_fixed_factor(NULL, "systick", "ahb_div",
0, 1, 8);
clks[FCLK] = clk_register_fixed_factor(NULL, "fclk", "ahb_div",
clks[FCLK] = clk_hw_register_fixed_factor(NULL, "fclk", "ahb_div",
0, 1, 1);
for (n = 0; n < ARRAY_SIZE(stm32f4_gates); n++) {
......@@ -360,18 +360,18 @@ static void __init stm32f4_rcc_init(struct device_node *np)
if (idx < 0)
goto fail;
clks[idx] = clk_register_gate(
clks[idx] = clk_hw_register_gate(
NULL, gd->name, gd->parent_name, gd->flags,
base + gd->offset, gd->bit_idx, 0, &stm32f4_clk_lock);
if (IS_ERR(clks[n])) {
if (IS_ERR(clks[idx])) {
pr_err("%s: Unable to register leaf clock %s\n",
np->full_name, gd->name);
goto fail;
}
}
of_clk_add_provider(np, stm32f4_rcc_lookup_clk, NULL);
of_clk_add_hw_provider(np, stm32f4_rcc_lookup_clk, NULL);
return;
fail:
iounmap(base);
......
......@@ -689,7 +689,7 @@ static const struct clk_ops syscon_clk_ops = {
.set_rate = syscon_clk_set_rate,
};
static struct clk * __init
static struct clk_hw * __init
syscon_clk_register(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
bool hw_ctrld,
......@@ -697,9 +697,10 @@ syscon_clk_register(struct device *dev, const char *name,
void __iomem *en_reg, u8 en_bit,
u16 clk_val)
{
struct clk *clk;
struct clk_hw *hw;
struct clk_syscon *sclk;
struct clk_init_data init;
int ret;
sclk = kzalloc(sizeof(struct clk_syscon), GFP_KERNEL);
if (!sclk) {
......@@ -722,11 +723,14 @@ syscon_clk_register(struct device *dev, const char *name,
sclk->en_bit = en_bit;
sclk->clk_val = clk_val;
clk = clk_register(dev, &sclk->hw);
if (IS_ERR(clk))
hw = &sclk->hw;
ret = clk_hw_register(dev, hw);
if (ret) {
kfree(sclk);
hw = ERR_PTR(ret);
}
return clk;
return hw;
}
#define U300_CLK_TYPE_SLOW 0
......@@ -868,7 +872,7 @@ static struct u300_clock const u300_clk_lookup[] __initconst = {
static void __init of_u300_syscon_clk_init(struct device_node *np)
{
struct clk *clk = ERR_PTR(-EINVAL);
struct clk_hw *hw = ERR_PTR(-EINVAL);
const char *clk_name = np->name;
const char *parent_name;
void __iomem *res_reg;
......@@ -911,16 +915,15 @@ static void __init of_u300_syscon_clk_init(struct device_node *np)
const struct u300_clock *u3clk = &u300_clk_lookup[i];
if (u3clk->type == clk_type && u3clk->id == clk_id)
clk = syscon_clk_register(NULL,
clk_name, parent_name,
0, u3clk->hw_ctrld,
res_reg, u3clk->id,
en_reg, u3clk->id,
u3clk->clk_val);
hw = syscon_clk_register(NULL, clk_name, parent_name,
0, u3clk->hw_ctrld,
res_reg, u3clk->id,
en_reg, u3clk->id,
u3clk->clk_val);
}
if (!IS_ERR(clk)) {
of_clk_add_provider(np, of_clk_src_simple_get, clk);
if (!IS_ERR(hw)) {
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
/*
* Some few system clocks - device tree does not
......@@ -928,11 +931,11 @@ static void __init of_u300_syscon_clk_init(struct device_node *np)
* for now we add these three clocks here.
*/
if (clk_type == U300_CLK_TYPE_REST && clk_id == 5)
clk_register_clkdev(clk, NULL, "pl172");
clk_hw_register_clkdev(hw, NULL, "pl172");
if (clk_type == U300_CLK_TYPE_REST && clk_id == 9)
clk_register_clkdev(clk, NULL, "semi");
clk_hw_register_clkdev(hw, NULL, "semi");
if (clk_type == U300_CLK_TYPE_REST && clk_id == 12)
clk_register_clkdev(clk, NULL, "intcon");
clk_hw_register_clkdev(hw, NULL, "intcon");
}
}
......@@ -1111,13 +1114,14 @@ static const struct clk_ops mclk_ops = {
.set_rate = mclk_clk_set_rate,
};
static struct clk * __init
static struct clk_hw * __init
mclk_clk_register(struct device *dev, const char *name,
const char *parent_name, bool is_mspro)
{
struct clk *clk;
struct clk_hw *hw;
struct clk_mclk *mclk;
struct clk_init_data init;
int ret;
mclk = kzalloc(sizeof(struct clk_mclk), GFP_KERNEL);
if (!mclk) {
......@@ -1133,23 +1137,26 @@ mclk_clk_register(struct device *dev, const char *name,
mclk->hw.init = &init;
mclk->is_mspro = is_mspro;
clk = clk_register(dev, &mclk->hw);
if (IS_ERR(clk))
hw = &mclk->hw;
ret = clk_hw_register(dev, hw);
if (ret) {
kfree(mclk);
hw = ERR_PTR(ret);
}
return clk;
return hw;
}
static void __init of_u300_syscon_mclk_init(struct device_node *np)
{
struct clk *clk = ERR_PTR(-EINVAL);
struct clk_hw *hw;
const char *clk_name = np->name;
const char *parent_name;
parent_name = of_clk_get_parent_name(np, 0);
clk = mclk_clk_register(NULL, clk_name, parent_name, false);
if (!IS_ERR(clk))
of_clk_add_provider(np, of_clk_src_simple_get, clk);
hw = mclk_clk_register(NULL, clk_name, parent_name, false);
if (!IS_ERR(hw))
of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
}
static const struct of_device_id u300_clk_match[] __initconst = {
......
......@@ -383,51 +383,49 @@ static int vt8500_find_pll_bits(unsigned long rate, unsigned long parent_rate,
return 0;
}
static int wm8650_find_pll_bits(unsigned long rate, unsigned long parent_rate,
u32 *multiplier, u32 *divisor1, u32 *divisor2)
/*
* M * parent [O1] => / P [O2] => / D [O3]
* Where O1 is 900MHz...3GHz;
* O2 is 600MHz >= (M * parent) / P >= 300MHz;
* M is 36...120 [25MHz parent]; D is 1 or 2 or 4 or 8.
* Possible ranges (O3):
* D = 8: 37,5MHz...75MHz
* D = 4: 75MHz...150MHz
* D = 2: 150MHz...300MHz
* D = 1: 300MHz...600MHz
*/
static int wm8650_find_pll_bits(unsigned long rate,
unsigned long parent_rate, u32 *multiplier, u32 *divisor1,
u32 *divisor2)
{
u32 mul, div1;
int div2;
u32 best_mul, best_div1, best_div2;
unsigned long tclk, rate_err, best_err;
best_err = (unsigned long)-1;
unsigned long O1, min_err, rate_err;
/* Find the closest match (lower or equal to requested) */
for (div1 = 5; div1 >= 3; div1--)
for (div2 = 3; div2 >= 0; div2--)
for (mul = 3; mul <= 1023; mul++) {
tclk = parent_rate * mul / (div1 * (1 << div2));
if (tclk > rate)
continue;
/* error will always be +ve */
rate_err = rate - tclk;
if (rate_err == 0) {
*multiplier = mul;
*divisor1 = div1;
*divisor2 = div2;
return 0;
}
if (!parent_rate || (rate < 37500000) || (rate > 600000000))
return -EINVAL;
if (rate_err < best_err) {
best_err = rate_err;
best_mul = mul;
best_div1 = div1;
best_div2 = div2;
}
}
*divisor2 = rate <= 75000000 ? 3 : rate <= 150000000 ? 2 :
rate <= 300000000 ? 1 : 0;
/*
* Divisor P cannot be calculated. Test all divisors and find where M
* will be as close as possible to the requested rate.
*/
min_err = ULONG_MAX;
for (*divisor1 = 5; *divisor1 >= 3; (*divisor1)--) {
O1 = rate * *divisor1 * (1 << (*divisor2));
rate_err = O1 % parent_rate;
if (rate_err < min_err) {
*multiplier = O1 / parent_rate;
if (rate_err == 0)
return 0;
min_err = rate_err;
}
}
if (best_err == (unsigned long)-1) {
pr_warn("%s: impossible rate %lu\n", __func__, rate);
if ((*multiplier < 3) || (*multiplier > 1023))
return -EINVAL;
}
/* if we got here, it wasn't an exact match */
pr_warn("%s: requested rate %lu, found rate %lu\n", __func__, rate,
rate - best_err);
*multiplier = best_mul;
*divisor1 = best_div1;
*divisor2 = best_div2;
pr_warn("%s: rate error is %lu\n", __func__, min_err);
return 0;
}
......@@ -464,7 +462,6 @@ static int wm8750_find_pll_bits(unsigned long rate, unsigned long parent_rate,
{
u32 mul;
int div1, div2;
u32 best_mul, best_div1, best_div2;
unsigned long tclk, rate_err, best_err;
best_err = (unsigned long)-1;
......@@ -488,9 +485,9 @@ static int wm8750_find_pll_bits(unsigned long rate, unsigned long parent_rate,
if (rate_err < best_err) {
best_err = rate_err;
best_mul = mul;
best_div1 = div1;
best_div2 = div2;
*multiplier = mul;
*divisor1 = div1;
*divisor2 = div2;
}
}
......@@ -503,10 +500,7 @@ static int wm8750_find_pll_bits(unsigned long rate, unsigned long parent_rate,
pr_warn("%s: requested rate %lu, found rate %lu\n", __func__, rate,
rate - best_err);
*filter = wm8750_get_filter(parent_rate, best_div1);
*multiplier = best_mul;
*divisor1 = best_div1;
*divisor2 = best_div2;
*filter = wm8750_get_filter(parent_rate, *divisor1);
return 0;
}
......@@ -516,7 +510,6 @@ static int wm8850_find_pll_bits(unsigned long rate, unsigned long parent_rate,
{
u32 mul;
int div1, div2;
u32 best_mul, best_div1, best_div2;
unsigned long tclk, rate_err, best_err;
best_err = (unsigned long)-1;
......@@ -540,9 +533,9 @@ static int wm8850_find_pll_bits(unsigned long rate, unsigned long parent_rate,
if (rate_err < best_err) {
best_err = rate_err;
best_mul = mul;
best_div1 = div1;
best_div2 = div2;
*multiplier = mul;
*divisor1 = div1;
*divisor2 = div2;
}
}
......@@ -555,10 +548,6 @@ static int wm8850_find_pll_bits(unsigned long rate, unsigned long parent_rate,
pr_warn("%s: requested rate %lu, found rate %lu\n", __func__, rate,
rate - best_err);
*multiplier = best_mul;
*divisor1 = best_div1;
*divisor2 = best_div2;
return 0;
}
......
This diff is collapsed.
......@@ -38,6 +38,11 @@
#define HI3519_NR_CLKS 128
struct hi3519_crg_data {
struct hisi_clock_data *clk_data;
struct hisi_reset_controller *rstc;
};
static const struct hisi_fixed_rate_clock hi3519_fixed_rate_clks[] = {
{ HI3519_FIXED_24M, "24m", NULL, 0, 24000000, },
{ HI3519_FIXED_50M, "50m", NULL, 0, 50000000, },
......@@ -80,33 +85,105 @@ static const struct hisi_gate_clock hi3519_gate_clks[] = {
CLK_SET_RATE_PARENT, 0xe4, 18, 0, },
};
static int hi3519_clk_probe(struct platform_device *pdev)
static struct hisi_clock_data *hi3519_clk_register(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct hisi_clock_data *clk_data;
struct hisi_reset_controller *rstc;
int ret;
rstc = hisi_reset_init(np);
if (!rstc)
clk_data = hisi_clk_alloc(pdev, HI3519_NR_CLKS);
if (!clk_data)
return ERR_PTR(-ENOMEM);
ret = hisi_clk_register_fixed_rate(hi3519_fixed_rate_clks,
ARRAY_SIZE(hi3519_fixed_rate_clks),
clk_data);
if (ret)
return ERR_PTR(ret);
ret = hisi_clk_register_mux(hi3519_mux_clks,
ARRAY_SIZE(hi3519_mux_clks),
clk_data);
if (ret)
goto unregister_fixed_rate;
ret = hisi_clk_register_gate(hi3519_gate_clks,
ARRAY_SIZE(hi3519_gate_clks),
clk_data);
if (ret)
goto unregister_mux;
ret = of_clk_add_provider(pdev->dev.of_node,
of_clk_src_onecell_get, &clk_data->clk_data);
if (ret)
goto unregister_gate;
return clk_data;
unregister_fixed_rate:
hisi_clk_unregister_fixed_rate(hi3519_fixed_rate_clks,
ARRAY_SIZE(hi3519_fixed_rate_clks),
clk_data);
unregister_mux:
hisi_clk_unregister_mux(hi3519_mux_clks,
ARRAY_SIZE(hi3519_mux_clks),
clk_data);
unregister_gate:
hisi_clk_unregister_gate(hi3519_gate_clks,
ARRAY_SIZE(hi3519_gate_clks),
clk_data);
return ERR_PTR(ret);
}
static void hi3519_clk_unregister(struct platform_device *pdev)
{
struct hi3519_crg_data *crg = platform_get_drvdata(pdev);
of_clk_del_provider(pdev->dev.of_node);
hisi_clk_unregister_gate(hi3519_gate_clks,
ARRAY_SIZE(hi3519_mux_clks),
crg->clk_data);
hisi_clk_unregister_mux(hi3519_mux_clks,
ARRAY_SIZE(hi3519_mux_clks),
crg->clk_data);
hisi_clk_unregister_fixed_rate(hi3519_fixed_rate_clks,
ARRAY_SIZE(hi3519_fixed_rate_clks),
crg->clk_data);
}
static int hi3519_clk_probe(struct platform_device *pdev)
{
struct hi3519_crg_data *crg;
crg = devm_kmalloc(&pdev->dev, sizeof(*crg), GFP_KERNEL);
if (!crg)
return -ENOMEM;
crg->rstc = hisi_reset_init(pdev);
if (!crg->rstc)
return -ENOMEM;
clk_data = hisi_clk_init(np, HI3519_NR_CLKS);
if (!clk_data) {
hisi_reset_exit(rstc);
return -ENODEV;
crg->clk_data = hi3519_clk_register(pdev);
if (IS_ERR(crg->clk_data)) {
hisi_reset_exit(crg->rstc);
return PTR_ERR(crg->clk_data);
}
hisi_clk_register_fixed_rate(hi3519_fixed_rate_clks,
ARRAY_SIZE(hi3519_fixed_rate_clks),
clk_data);
hisi_clk_register_mux(hi3519_mux_clks, ARRAY_SIZE(hi3519_mux_clks),
clk_data);
hisi_clk_register_gate(hi3519_gate_clks,
ARRAY_SIZE(hi3519_gate_clks), clk_data);
platform_set_drvdata(pdev, crg);
return 0;
}
static int hi3519_clk_remove(struct platform_device *pdev)
{
struct hi3519_crg_data *crg = platform_get_drvdata(pdev);
hisi_reset_exit(crg->rstc);
hi3519_clk_unregister(pdev);
return 0;
}
static const struct of_device_id hi3519_clk_match_table[] = {
{ .compatible = "hisilicon,hi3519-crg" },
{ }
......@@ -115,6 +192,7 @@ MODULE_DEVICE_TABLE(of, hi3519_clk_match_table);
static struct platform_driver hi3519_clk_driver = {
.probe = hi3519_clk_probe,
.remove = hi3519_clk_remove,
.driver = {
.name = "hi3519-clk",
.of_match_table = hi3519_clk_match_table,
......@@ -127,5 +205,11 @@ static int __init hi3519_clk_init(void)
}
core_initcall(hi3519_clk_init);
static void __exit hi3519_clk_exit(void)
{
platform_driver_unregister(&hi3519_clk_driver);
}
module_exit(hi3519_clk_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("HiSilicon Hi3519 Clock Driver");
......@@ -34,8 +34,8 @@ static struct hisi_fixed_rate_clock hi6220_fixed_rate_clks[] __initdata = {
{ HI6220_PLL_BBP, "bbppll0", NULL, 0, 245760000, },
{ HI6220_PLL_GPU, "gpupll", NULL, 0, 1000000000,},
{ HI6220_PLL1_DDR, "ddrpll1", NULL, 0, 1066000000,},
{ HI6220_PLL_SYS, "syspll", NULL, 0, 1200000000,},
{ HI6220_PLL_SYS_MEDIA, "media_syspll", NULL, 0, 1200000000,},
{ HI6220_PLL_SYS, "syspll", NULL, 0, 1190400000,},
{ HI6220_PLL_SYS_MEDIA, "media_syspll", NULL, 0, 1190400000,},
{ HI6220_DDR_SRC, "ddr_sel_src", NULL, 0, 1200000000,},
{ HI6220_PLL_MEDIA, "media_pll", NULL, 0, 1440000000,},
{ HI6220_PLL_DDR, "ddrpll0", NULL, 0, 1600000000,},
......@@ -68,6 +68,8 @@ static struct hisi_gate_clock hi6220_separated_gate_clks_ao[] __initdata = {
{ HI6220_TIMER7_PCLK, "timer7_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 22, 0, },
{ HI6220_TIMER8_PCLK, "timer8_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 23, 0, },
{ HI6220_UART0_PCLK, "uart0_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 24, 0, },
{ HI6220_RTC0_PCLK, "rtc0_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 25, 0, },
{ HI6220_RTC1_PCLK, "rtc1_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 26, 0, },
};
static void __init hi6220_clk_ao_init(struct device_node *np)
......
......@@ -37,6 +37,35 @@
static DEFINE_SPINLOCK(hisi_clk_lock);
struct hisi_clock_data *hisi_clk_alloc(struct platform_device *pdev,
int nr_clks)
{
struct hisi_clock_data *clk_data;
struct resource *res;
struct clk **clk_table;
clk_data = devm_kmalloc(&pdev->dev, sizeof(*clk_data), GFP_KERNEL);
if (!clk_data)
return NULL;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
clk_data->base = devm_ioremap(&pdev->dev,
res->start, resource_size(res));
if (!clk_data->base)
return NULL;
clk_table = devm_kmalloc(&pdev->dev, sizeof(struct clk *) * nr_clks,
GFP_KERNEL);
if (!clk_table)
return NULL;
clk_data->clk_data.clks = clk_table;
clk_data->clk_data.clk_num = nr_clks;
return clk_data;
}
EXPORT_SYMBOL_GPL(hisi_clk_alloc);
struct hisi_clock_data *hisi_clk_init(struct device_node *np,
int nr_clks)
{
......@@ -73,7 +102,7 @@ struct hisi_clock_data *hisi_clk_init(struct device_node *np,
}
EXPORT_SYMBOL_GPL(hisi_clk_init);
void hisi_clk_register_fixed_rate(const struct hisi_fixed_rate_clock *clks,
int hisi_clk_register_fixed_rate(const struct hisi_fixed_rate_clock *clks,
int nums, struct hisi_clock_data *data)
{
struct clk *clk;
......@@ -87,14 +116,22 @@ void hisi_clk_register_fixed_rate(const struct hisi_fixed_rate_clock *clks,
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
continue;
goto err;
}
data->clk_data.clks[clks[i].id] = clk;
}
return 0;
err:
while (i--)
clk_unregister_fixed_rate(data->clk_data.clks[clks[i].id]);
return PTR_ERR(clk);
}
EXPORT_SYMBOL_GPL(hisi_clk_register_fixed_rate);
void hisi_clk_register_fixed_factor(const struct hisi_fixed_factor_clock *clks,
int hisi_clk_register_fixed_factor(const struct hisi_fixed_factor_clock *clks,
int nums,
struct hisi_clock_data *data)
{
......@@ -109,14 +146,22 @@ void hisi_clk_register_fixed_factor(const struct hisi_fixed_factor_clock *clks,
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
continue;
goto err;
}
data->clk_data.clks[clks[i].id] = clk;
}
return 0;
err:
while (i--)
clk_unregister_fixed_factor(data->clk_data.clks[clks[i].id]);
return PTR_ERR(clk);
}
EXPORT_SYMBOL_GPL(hisi_clk_register_fixed_factor);
void hisi_clk_register_mux(const struct hisi_mux_clock *clks,
int hisi_clk_register_mux(const struct hisi_mux_clock *clks,
int nums, struct hisi_clock_data *data)
{
struct clk *clk;
......@@ -135,7 +180,7 @@ void hisi_clk_register_mux(const struct hisi_mux_clock *clks,
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
continue;
goto err;
}
if (clks[i].alias)
......@@ -143,10 +188,18 @@ void hisi_clk_register_mux(const struct hisi_mux_clock *clks,
data->clk_data.clks[clks[i].id] = clk;
}
return 0;
err:
while (i--)
clk_unregister_mux(data->clk_data.clks[clks[i].id]);
return PTR_ERR(clk);
}
EXPORT_SYMBOL_GPL(hisi_clk_register_mux);
void hisi_clk_register_divider(const struct hisi_divider_clock *clks,
int hisi_clk_register_divider(const struct hisi_divider_clock *clks,
int nums, struct hisi_clock_data *data)
{
struct clk *clk;
......@@ -165,7 +218,7 @@ void hisi_clk_register_divider(const struct hisi_divider_clock *clks,
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
continue;
goto err;
}
if (clks[i].alias)
......@@ -173,10 +226,18 @@ void hisi_clk_register_divider(const struct hisi_divider_clock *clks,
data->clk_data.clks[clks[i].id] = clk;
}
return 0;
err:
while (i--)
clk_unregister_divider(data->clk_data.clks[clks[i].id]);
return PTR_ERR(clk);
}
EXPORT_SYMBOL_GPL(hisi_clk_register_divider);
void hisi_clk_register_gate(const struct hisi_gate_clock *clks,
int hisi_clk_register_gate(const struct hisi_gate_clock *clks,
int nums, struct hisi_clock_data *data)
{
struct clk *clk;
......@@ -194,7 +255,7 @@ void hisi_clk_register_gate(const struct hisi_gate_clock *clks,
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
continue;
goto err;
}
if (clks[i].alias)
......@@ -202,6 +263,14 @@ void hisi_clk_register_gate(const struct hisi_gate_clock *clks,
data->clk_data.clks[clks[i].id] = clk;
}
return 0;
err:
while (i--)
clk_unregister_gate(data->clk_data.clks[clks[i].id]);
return PTR_ERR(clk);
}
EXPORT_SYMBOL_GPL(hisi_clk_register_gate);
......
......@@ -30,6 +30,8 @@
#include <linux/io.h>
#include <linux/spinlock.h>
struct platform_device;
struct hisi_clock_data {
struct clk_onecell_data clk_data;
void __iomem *base;
......@@ -110,19 +112,41 @@ struct clk *hi6220_register_clkdiv(struct device *dev, const char *name,
const char *parent_name, unsigned long flags, void __iomem *reg,
u8 shift, u8 width, u32 mask_bit, spinlock_t *lock);
struct hisi_clock_data *hisi_clk_alloc(struct platform_device *, int);
struct hisi_clock_data *hisi_clk_init(struct device_node *, int);
void hisi_clk_register_fixed_rate(const struct hisi_fixed_rate_clock *,
int hisi_clk_register_fixed_rate(const struct hisi_fixed_rate_clock *,
int, struct hisi_clock_data *);
void hisi_clk_register_fixed_factor(const struct hisi_fixed_factor_clock *,
int hisi_clk_register_fixed_factor(const struct hisi_fixed_factor_clock *,
int, struct hisi_clock_data *);
void hisi_clk_register_mux(const struct hisi_mux_clock *, int,
int hisi_clk_register_mux(const struct hisi_mux_clock *, int,
struct hisi_clock_data *);
void hisi_clk_register_divider(const struct hisi_divider_clock *,
int hisi_clk_register_divider(const struct hisi_divider_clock *,
int, struct hisi_clock_data *);
void hisi_clk_register_gate(const struct hisi_gate_clock *,
int hisi_clk_register_gate(const struct hisi_gate_clock *,
int, struct hisi_clock_data *);
void hisi_clk_register_gate_sep(const struct hisi_gate_clock *,
int, struct hisi_clock_data *);
void hi6220_clk_register_divider(const struct hi6220_divider_clock *,
int, struct hisi_clock_data *);
#define hisi_clk_unregister(type) \
static inline \
void hisi_clk_unregister_##type(const struct hisi_##type##_clock *clks, \
int nums, struct hisi_clock_data *data) \
{ \
struct clk **clocks = data->clk_data.clks; \
int i; \
for (i = 0; i < nums; i++) { \
int id = clks[i].id; \
if (clocks[id]) \
clk_unregister_##type(clocks[id]); \
} \
}
hisi_clk_unregister(fixed_rate)
hisi_clk_unregister(fixed_factor)
hisi_clk_unregister(mux)
hisi_clk_unregister(divider)
hisi_clk_unregister(gate)
#endif /* __HISI_CLK_H */
......@@ -18,6 +18,8 @@
#include <linux/err.h>
#include <linux/spinlock.h>
#include "clk.h"
#define div_mask(width) ((1 << (width)) - 1)
/**
......
......@@ -19,6 +19,7 @@
#include <linux/io.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
......@@ -98,25 +99,25 @@ static const struct reset_control_ops hisi_reset_ops = {
.deassert = hisi_reset_deassert,
};
struct hisi_reset_controller *hisi_reset_init(struct device_node *np)
struct hisi_reset_controller *hisi_reset_init(struct platform_device *pdev)
{
struct hisi_reset_controller *rstc;
struct resource *res;
rstc = kzalloc(sizeof(*rstc), GFP_KERNEL);
rstc = devm_kmalloc(&pdev->dev, sizeof(*rstc), GFP_KERNEL);
if (!rstc)
return NULL;
rstc->membase = of_iomap(np, 0);
if (!rstc->membase) {
kfree(rstc);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
rstc->membase = devm_ioremap(&pdev->dev,
res->start, resource_size(res));
if (!rstc->membase)
return NULL;
}
spin_lock_init(&rstc->lock);
rstc->rcdev.owner = THIS_MODULE;
rstc->rcdev.ops = &hisi_reset_ops;
rstc->rcdev.of_node = np;
rstc->rcdev.of_node = pdev->dev.of_node;
rstc->rcdev.of_reset_n_cells = 2;
rstc->rcdev.of_xlate = hisi_reset_of_xlate;
reset_controller_register(&rstc->rcdev);
......@@ -128,7 +129,5 @@ EXPORT_SYMBOL_GPL(hisi_reset_init);
void hisi_reset_exit(struct hisi_reset_controller *rstc)
{
reset_controller_unregister(&rstc->rcdev);
iounmap(rstc->membase);
kfree(rstc);
}
EXPORT_SYMBOL_GPL(hisi_reset_exit);
......@@ -22,10 +22,11 @@ struct device_node;
struct hisi_reset_controller;
#ifdef CONFIG_RESET_CONTROLLER
struct hisi_reset_controller *hisi_reset_init(struct device_node *np);
struct hisi_reset_controller *hisi_reset_init(struct platform_device *pdev);
void hisi_reset_exit(struct hisi_reset_controller *rstc);
#else
static inline hisi_reset_controller *hisi_reset_init(struct device_node *np)
static inline
struct hisi_reset_controller *hisi_reset_init(struct platform_device *pdev)
{
return 0;
}
......
......@@ -192,13 +192,13 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
clk[IMX6QDL_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
/* type name parent_name base div_mask */
clk[IMX6QDL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "pll1_bypass_src", base + 0x00, 0x7f);
clk[IMX6QDL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", base + 0x30, 0x1);
clk[IMX6QDL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "pll3_bypass_src", base + 0x10, 0x3);
clk[IMX6QDL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "pll4_bypass_src", base + 0x70, 0x7f);
clk[IMX6QDL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "pll5_bypass_src", base + 0xa0, 0x7f);
clk[IMX6QDL_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6", "pll6_bypass_src", base + 0xe0, 0x3);
clk[IMX6QDL_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "pll7_bypass_src", base + 0x20, 0x3);
clk[IMX6QDL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "osc", base + 0x00, 0x7f);
clk[IMX6QDL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "osc", base + 0x30, 0x1);
clk[IMX6QDL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "osc", base + 0x10, 0x3);
clk[IMX6QDL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "osc", base + 0x70, 0x7f);
clk[IMX6QDL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "osc", base + 0xa0, 0x7f);
clk[IMX6QDL_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6", "osc", base + 0xe0, 0x3);
clk[IMX6QDL_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "osc", base + 0x20, 0x3);
clk[IMX6QDL_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
clk[IMX6QDL_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
......
......@@ -218,13 +218,13 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
clks[IMX6SL_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
/* type name parent_name base div_mask */
clks[IMX6SL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "pll1_bypass_src", base + 0x00, 0x7f);
clks[IMX6SL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", base + 0x30, 0x1);
clks[IMX6SL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "pll3_bypass_src", base + 0x10, 0x3);
clks[IMX6SL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "pll4_bypass_src", base + 0x70, 0x7f);
clks[IMX6SL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "pll5_bypass_src", base + 0xa0, 0x7f);
clks[IMX6SL_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6", "pll6_bypass_src", base + 0xe0, 0x3);
clks[IMX6SL_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "pll7_bypass_src", base + 0x20, 0x3);
clks[IMX6SL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "osc", base + 0x00, 0x7f);
clks[IMX6SL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "osc", base + 0x30, 0x1);
clks[IMX6SL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "osc", base + 0x10, 0x3);
clks[IMX6SL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "osc", base + 0x70, 0x7f);
clks[IMX6SL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "osc", base + 0xa0, 0x7f);
clks[IMX6SL_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6", "osc", base + 0xe0, 0x3);
clks[IMX6SL_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "osc", base + 0x20, 0x3);
clks[IMX6SL_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
clks[IMX6SL_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
......
......@@ -174,13 +174,13 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
clks[IMX6SX_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
/* type name parent_name base div_mask */
clks[IMX6SX_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "pll1_bypass_src", base + 0x00, 0x7f);
clks[IMX6SX_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", base + 0x30, 0x1);
clks[IMX6SX_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "pll3_bypass_src", base + 0x10, 0x3);
clks[IMX6SX_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "pll4_bypass_src", base + 0x70, 0x7f);
clks[IMX6SX_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "pll5_bypass_src", base + 0xa0, 0x7f);
clks[IMX6SX_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6", "pll6_bypass_src", base + 0xe0, 0x3);
clks[IMX6SX_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "pll7_bypass_src", base + 0x20, 0x3);
clks[IMX6SX_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "osc", base + 0x00, 0x7f);
clks[IMX6SX_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "osc", base + 0x30, 0x1);
clks[IMX6SX_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "osc", base + 0x10, 0x3);
clks[IMX6SX_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "osc", base + 0x70, 0x7f);
clks[IMX6SX_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "osc", base + 0xa0, 0x7f);
clks[IMX6SX_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6", "osc", base + 0xe0, 0x3);
clks[IMX6SX_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "osc", base + 0x20, 0x3);
clks[IMX6SX_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
clks[IMX6SX_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
......
......@@ -130,13 +130,13 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
clks[IMX6UL_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", base + 0xe0, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
clks[IMX6UL_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", base + 0x20, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
clks[IMX6UL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "pll1_bypass_src", base + 0x00, 0x7f);
clks[IMX6UL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", base + 0x30, 0x1);
clks[IMX6UL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "pll3_bypass_src", base + 0x10, 0x3);
clks[IMX6UL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "pll4_bypass_src", base + 0x70, 0x7f);
clks[IMX6UL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "pll5_bypass_src", base + 0xa0, 0x7f);
clks[IMX6UL_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6", "pll6_bypass_src", base + 0xe0, 0x3);
clks[IMX6UL_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "pll7_bypass_src", base + 0x20, 0x3);
clks[IMX6UL_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_SYS, "pll1", "osc", base + 0x00, 0x7f);
clks[IMX6UL_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "osc", base + 0x30, 0x1);
clks[IMX6UL_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB, "pll3", "osc", base + 0x10, 0x3);
clks[IMX6UL_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV, "pll4", "osc", base + 0x70, 0x7f);
clks[IMX6UL_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_AV, "pll5", "osc", base + 0xa0, 0x7f);
clks[IMX6UL_CLK_PLL6] = imx_clk_pllv3(IMX_PLLV3_ENET, "pll6", "osc", base + 0xe0, 0x3);
clks[IMX6UL_CLK_PLL7] = imx_clk_pllv3(IMX_PLLV3_USB, "pll7", "osc", base + 0x20, 0x3);
clks[IMX6UL_PLL1_BYPASS] = imx_clk_mux_flags("pll1_bypass", base + 0x00, 16, 1, pll1_bypass_sels, ARRAY_SIZE(pll1_bypass_sels), CLK_SET_RATE_PARENT);
clks[IMX6UL_PLL2_BYPASS] = imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), CLK_SET_RATE_PARENT);
......@@ -305,8 +305,8 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
clks[IMX6UL_CLK_CAN1_SERIAL] = imx_clk_gate2("can1_serial", "can_podf", base + 0x68, 16);
clks[IMX6UL_CLK_CAN2_IPG] = imx_clk_gate2("can2_ipg", "ipg", base + 0x68, 18);
clks[IMX6UL_CLK_CAN2_SERIAL] = imx_clk_gate2("can2_serial", "can_podf", base + 0x68, 20);
clks[IMX6UL_CLK_GPT2_BUS] = imx_clk_gate2("gpt_bus", "perclk", base + 0x68, 24);
clks[IMX6UL_CLK_GPT2_SERIAL] = imx_clk_gate2("gpt_serial", "perclk", base + 0x68, 26);
clks[IMX6UL_CLK_GPT2_BUS] = imx_clk_gate2("gpt2_bus", "perclk", base + 0x68, 24);
clks[IMX6UL_CLK_GPT2_SERIAL] = imx_clk_gate2("gpt2_serial", "perclk", base + 0x68, 26);
clks[IMX6UL_CLK_UART2_IPG] = imx_clk_gate2("uart2_ipg", "ipg", base + 0x68, 28);
clks[IMX6UL_CLK_UART2_SERIAL] = imx_clk_gate2("uart2_serial", "uart_podf", base + 0x68, 28);
clks[IMX6UL_CLK_AIPSTZ3] = imx_clk_gate2("aips_tz3", "ahb", base + 0x68, 30);
......
This diff is collapsed.
......@@ -29,8 +29,8 @@
* struct clk_pllv3 - IMX PLL clock version 3
* @clk_hw: clock source
* @base: base address of PLL registers
* @powerup_set: set POWER bit to power up the PLL
* @powerdown: pll powerdown offset bit
* @power_bit: pll power bit mask
* @powerup_set: set power_bit to power up the PLL
* @div_mask: mask of divider bits
* @div_shift: shift of divider bits
*
......@@ -40,8 +40,8 @@
struct clk_pllv3 {
struct clk_hw hw;
void __iomem *base;
u32 power_bit;
bool powerup_set;
u32 powerdown;
u32 div_mask;
u32 div_shift;
unsigned long ref_clock;
......@@ -52,7 +52,7 @@ struct clk_pllv3 {
static int clk_pllv3_wait_lock(struct clk_pllv3 *pll)
{
unsigned long timeout = jiffies + msecs_to_jiffies(10);
u32 val = readl_relaxed(pll->base) & pll->powerdown;
u32 val = readl_relaxed(pll->base) & pll->power_bit;
/* No need to wait for lock when pll is not powered up */
if ((pll->powerup_set && !val) || (!pll->powerup_set && val))
......@@ -77,9 +77,9 @@ static int clk_pllv3_prepare(struct clk_hw *hw)
val = readl_relaxed(pll->base);
if (pll->powerup_set)
val |= BM_PLL_POWER;
val |= pll->power_bit;
else
val &= ~BM_PLL_POWER;
val &= ~pll->power_bit;
writel_relaxed(val, pll->base);
return clk_pllv3_wait_lock(pll);
......@@ -92,9 +92,9 @@ static void clk_pllv3_unprepare(struct clk_hw *hw)
val = readl_relaxed(pll->base);
if (pll->powerup_set)
val &= ~BM_PLL_POWER;
val &= ~pll->power_bit;
else
val |= BM_PLL_POWER;
val |= pll->power_bit;
writel_relaxed(val, pll->base);
}
......@@ -218,8 +218,12 @@ static unsigned long clk_pllv3_av_recalc_rate(struct clk_hw *hw,
u32 mfn = readl_relaxed(pll->base + PLL_NUM_OFFSET);
u32 mfd = readl_relaxed(pll->base + PLL_DENOM_OFFSET);
u32 div = readl_relaxed(pll->base) & pll->div_mask;
u64 temp64 = (u64)parent_rate;
return (parent_rate * div) + ((parent_rate / mfd) * mfn);
temp64 *= mfn;
do_div(temp64, mfd);
return (parent_rate * div) + (u32)temp64;
}
static long clk_pllv3_av_round_rate(struct clk_hw *hw, unsigned long rate,
......@@ -243,7 +247,7 @@ static long clk_pllv3_av_round_rate(struct clk_hw *hw, unsigned long rate,
do_div(temp64, parent_rate);
mfn = temp64;
return parent_rate * div + parent_rate / mfd * mfn;
return parent_rate * div + parent_rate * mfn / mfd;
}
static int clk_pllv3_av_set_rate(struct clk_hw *hw, unsigned long rate,
......@@ -312,7 +316,7 @@ struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
if (!pll)
return ERR_PTR(-ENOMEM);
pll->powerdown = BM_PLL_POWER;
pll->power_bit = BM_PLL_POWER;
switch (type) {
case IMX_PLLV3_SYS:
......@@ -328,7 +332,7 @@ struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
ops = &clk_pllv3_av_ops;
break;
case IMX_PLLV3_ENET_IMX7:
pll->powerdown = IMX7_ENET_PLL_POWER;
pll->power_bit = IMX7_ENET_PLL_POWER;
pll->ref_clock = 1000000000;
ops = &clk_pllv3_enet_ops;
break;
......
......@@ -315,12 +315,12 @@ static void __init vf610_clocks_init(struct device_node *ccm_node)
clk[VF610_CLK_PIT] = imx_clk_gate2("pit", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(7));
clk[VF610_CLK_UART0] = imx_clk_gate2("uart0", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(7));
clk[VF610_CLK_UART1] = imx_clk_gate2("uart1", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(8));
clk[VF610_CLK_UART2] = imx_clk_gate2("uart2", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(9));
clk[VF610_CLK_UART3] = imx_clk_gate2("uart3", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(10));
clk[VF610_CLK_UART4] = imx_clk_gate2("uart4", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(9));
clk[VF610_CLK_UART5] = imx_clk_gate2("uart5", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(10));
clk[VF610_CLK_UART0] = imx_clk_gate2_cgr("uart0", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(7), 0x2);
clk[VF610_CLK_UART1] = imx_clk_gate2_cgr("uart1", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(8), 0x2);
clk[VF610_CLK_UART2] = imx_clk_gate2_cgr("uart2", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(9), 0x2);
clk[VF610_CLK_UART3] = imx_clk_gate2_cgr("uart3", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(10), 0x2);
clk[VF610_CLK_UART4] = imx_clk_gate2_cgr("uart4", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(9), 0x2);
clk[VF610_CLK_UART5] = imx_clk_gate2_cgr("uart5", "ipg_bus", CCM_CCGR6, CCM_CCGRx_CGn(10), 0x2);
clk[VF610_CLK_I2C0] = imx_clk_gate2("i2c0", "ipg_bus", CCM_CCGR4, CCM_CCGRx_CGn(6));
clk[VF610_CLK_I2C1] = imx_clk_gate2("i2c1", "ipg_bus", CCM_CCGR4, CCM_CCGRx_CGn(7));
......
......@@ -51,28 +51,6 @@ struct clk * imx_obtain_fixed_clock(
struct clk *imx_clk_gate_exclusive(const char *name, const char *parent,
void __iomem *reg, u8 shift, u32 exclusive_mask);
static inline struct clk *imx_clk_gate2(const char *name, const char *parent,
void __iomem *reg, u8 shift)
{
return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
shift, 0x3, 0, &imx_ccm_lock, NULL);
}
static inline struct clk *imx_clk_gate2_shared(const char *name,
const char *parent, void __iomem *reg, u8 shift,
unsigned int *share_count)
{
return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
shift, 0x3, 0, &imx_ccm_lock, share_count);
}
static inline struct clk *imx_clk_gate2_cgr(const char *name, const char *parent,
void __iomem *reg, u8 shift, u8 cgr_val)
{
return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
shift, cgr_val, 0, &imx_ccm_lock, NULL);
}
struct clk *imx_clk_pfd(const char *name, const char *parent_name,
void __iomem *reg, u8 idx);
......@@ -97,6 +75,13 @@ static inline struct clk *imx_clk_fixed(const char *name, int rate)
return clk_register_fixed_rate(NULL, name, NULL, 0, rate);
}
static inline struct clk *imx_clk_fixed_factor(const char *name,
const char *parent, unsigned int mult, unsigned int div)
{
return clk_register_fixed_factor(NULL, name, parent,
CLK_SET_RATE_PARENT, mult, div);
}
static inline struct clk *imx_clk_divider(const char *name, const char *parent,
void __iomem *reg, u8 shift, u8 width)
{
......@@ -112,6 +97,14 @@ static inline struct clk *imx_clk_divider_flags(const char *name,
reg, shift, width, 0, &imx_ccm_lock);
}
static inline struct clk *imx_clk_divider2(const char *name, const char *parent,
void __iomem *reg, u8 shift, u8 width)
{
return clk_register_divider(NULL, name, parent,
CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
reg, shift, width, 0, &imx_ccm_lock);
}
static inline struct clk *imx_clk_gate(const char *name, const char *parent,
void __iomem *reg, u8 shift)
{
......@@ -126,6 +119,44 @@ static inline struct clk *imx_clk_gate_dis(const char *name, const char *parent,
shift, CLK_GATE_SET_TO_DISABLE, &imx_ccm_lock);
}
static inline struct clk *imx_clk_gate2(const char *name, const char *parent,
void __iomem *reg, u8 shift)
{
return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
shift, 0x3, 0, &imx_ccm_lock, NULL);
}
static inline struct clk *imx_clk_gate2_shared(const char *name,
const char *parent, void __iomem *reg, u8 shift,
unsigned int *share_count)
{
return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
shift, 0x3, 0, &imx_ccm_lock, share_count);
}
static inline struct clk *imx_clk_gate2_cgr(const char *name,
const char *parent, void __iomem *reg, u8 shift, u8 cgr_val)
{
return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
shift, cgr_val, 0, &imx_ccm_lock, NULL);
}
static inline struct clk *imx_clk_gate3(const char *name, const char *parent,
void __iomem *reg, u8 shift)
{
return clk_register_gate(NULL, name, parent,
CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
reg, shift, 0, &imx_ccm_lock);
}
static inline struct clk *imx_clk_gate4(const char *name, const char *parent,
void __iomem *reg, u8 shift)
{
return clk_register_gate2(NULL, name, parent,
CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE,
reg, shift, 0x3, 0, &imx_ccm_lock, NULL);
}
static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg,
u8 shift, u8 width, const char **parents, int num_parents)
{
......@@ -134,6 +165,14 @@ static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg,
width, 0, &imx_ccm_lock);
}
static inline struct clk *imx_clk_mux2(const char *name, void __iomem *reg,
u8 shift, u8 width, const char **parents, int num_parents)
{
return clk_register_mux(NULL, name, parents, num_parents,
CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE,
reg, shift, width, 0, &imx_ccm_lock);
}
static inline struct clk *imx_clk_mux_flags(const char *name,
void __iomem *reg, u8 shift, u8 width, const char **parents,
int num_parents, unsigned long flags)
......@@ -143,13 +182,6 @@ static inline struct clk *imx_clk_mux_flags(const char *name,
&imx_ccm_lock);
}
static inline struct clk *imx_clk_fixed_factor(const char *name,
const char *parent, unsigned int mult, unsigned int div)
{
return clk_register_fixed_factor(NULL, name, parent,
CLK_SET_RATE_PARENT, mult, div);
}
struct clk *imx_clk_cpu(const char *name, const char *parent_name,
struct clk *div, struct clk *mux, struct clk *pll,
struct clk *step);
......
config COMMON_CLK_AMLOGIC
bool
depends on OF
depends on ARCH_MESON || COMPILE_TEST
config COMMON_CLK_MESON8B
bool
depends on COMMON_CLK_AMLOGIC
help
Support for the clock controller on AmLogic S805 devices, aka
meson8b. Say Y if you want peripherals and CPU frequency scaling to
work.
config COMMON_CLK_GXBB
bool
depends on COMMON_CLK_AMLOGIC
help
Support for the clock controller on AmLogic S905 devices, aka gxbb.
Say Y if you want peripherals and CPU frequency scaling to work.
......@@ -2,5 +2,6 @@
# Makefile for Meson specific clk
#
obj-y += clkc.o clk-pll.o clk-cpu.o
obj-y += meson8b-clkc.o
obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-cpu.o clk-mpll.o
obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b-clkc.o
obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o
......@@ -51,13 +51,6 @@
#include "clkc.h"
struct meson_clk_cpu {
struct notifier_block clk_nb;
const struct clk_div_table *div_table;
struct clk_hw hw;
void __iomem *base;
u16 reg_off;
};
#define to_meson_clk_cpu_hw(_hw) container_of(_hw, struct meson_clk_cpu, hw)
#define to_meson_clk_cpu_nb(_nb) container_of(_nb, struct meson_clk_cpu, clk_nb)
......@@ -119,6 +112,7 @@ static unsigned long meson_clk_cpu_recalc_rate(struct clk_hw *hw,
return parent_rate / div;
}
/* FIXME MUX1 & MUX2 should be struct clk_hw objects */
static int meson_clk_cpu_pre_rate_change(struct meson_clk_cpu *clk_cpu,
struct clk_notifier_data *ndata)
{
......@@ -140,6 +134,7 @@ static int meson_clk_cpu_pre_rate_change(struct meson_clk_cpu *clk_cpu,
return 0;
}
/* FIXME MUX1 & MUX2 should be struct clk_hw objects */
static int meson_clk_cpu_post_rate_change(struct meson_clk_cpu *clk_cpu,
struct clk_notifier_data *ndata)
{
......@@ -161,7 +156,7 @@ static int meson_clk_cpu_post_rate_change(struct meson_clk_cpu *clk_cpu,
* PLL clock is to be changed. We use the xtal input as temporary parent
* while the PLL frequency is stabilized.
*/
static int meson_clk_cpu_notifier_cb(struct notifier_block *nb,
int meson_clk_cpu_notifier_cb(struct notifier_block *nb,
unsigned long event, void *data)
{
struct clk_notifier_data *ndata = data;
......@@ -176,68 +171,8 @@ static int meson_clk_cpu_notifier_cb(struct notifier_block *nb,
return notifier_from_errno(ret);
}
static const struct clk_ops meson_clk_cpu_ops = {
const struct clk_ops meson_clk_cpu_ops = {
.recalc_rate = meson_clk_cpu_recalc_rate,
.round_rate = meson_clk_cpu_round_rate,
.set_rate = meson_clk_cpu_set_rate,
};
struct clk *meson_clk_register_cpu(const struct clk_conf *clk_conf,
void __iomem *reg_base,
spinlock_t *lock)
{
struct clk *clk;
struct clk *pclk;
struct meson_clk_cpu *clk_cpu;
struct clk_init_data init;
int ret;
clk_cpu = kzalloc(sizeof(*clk_cpu), GFP_KERNEL);
if (!clk_cpu)
return ERR_PTR(-ENOMEM);
clk_cpu->base = reg_base;
clk_cpu->reg_off = clk_conf->reg_off;
clk_cpu->div_table = clk_conf->conf.div_table;
clk_cpu->clk_nb.notifier_call = meson_clk_cpu_notifier_cb;
init.name = clk_conf->clk_name;
init.ops = &meson_clk_cpu_ops;
init.flags = clk_conf->flags | CLK_GET_RATE_NOCACHE;
init.flags |= CLK_SET_RATE_PARENT;
init.parent_names = clk_conf->clks_parent;
init.num_parents = 1;
clk_cpu->hw.init = &init;
pclk = __clk_lookup(clk_conf->clks_parent[0]);
if (!pclk) {
pr_err("%s: could not lookup parent clock %s\n",
__func__, clk_conf->clks_parent[0]);
ret = -EINVAL;
goto free_clk;
}
ret = clk_notifier_register(pclk, &clk_cpu->clk_nb);
if (ret) {
pr_err("%s: failed to register clock notifier for %s\n",
__func__, clk_conf->clk_name);
goto free_clk;
}
clk = clk_register(NULL, &clk_cpu->hw);
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
goto unregister_clk_nb;
}
return clk;
unregister_clk_nb:
clk_notifier_unregister(pclk, &clk_cpu->clk_nb);
free_clk:
kfree(clk_cpu);
return ERR_PTR(ret);
}
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* GPL LICENSE SUMMARY
*
* Copyright (c) 2016 AmLogic, Inc.
* Author: Michael Turquette <mturquette@baylibre.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
* The full GNU General Public License is included in this distribution
* in the file called COPYING
*
* BSD LICENSE
*
* Copyright (c) 2016 AmLogic, Inc.
* Author: Michael Turquette <mturquette@baylibre.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* MultiPhase Locked Loops are outputs from a PLL with additional frequency
* scaling capabilities. MPLL rates are calculated as:
*
* f(N2_integer, SDM_IN ) = 2.0G/(N2_integer + SDM_IN/16384)
*/
#include <linux/clk-provider.h>
#include "clkc.h"
#define SDM_MAX 16384
#define to_meson_clk_mpll(_hw) container_of(_hw, struct meson_clk_mpll, hw)
static unsigned long mpll_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw);
struct parm *p;
unsigned long rate = 0;
unsigned long reg, sdm, n2;
p = &mpll->sdm;
reg = readl(mpll->base + p->reg_off);
sdm = PARM_GET(p->width, p->shift, reg);
p = &mpll->n2;
reg = readl(mpll->base + p->reg_off);
n2 = PARM_GET(p->width, p->shift, reg);
rate = (parent_rate * SDM_MAX) / ((SDM_MAX * n2) + sdm);
return rate;
}
const struct clk_ops meson_clk_mpll_ro_ops = {
.recalc_rate = mpll_recalc_rate,
};
......@@ -44,13 +44,6 @@
#define MESON_PLL_RESET BIT(29)
#define MESON_PLL_LOCK BIT(31)
struct meson_clk_pll {
struct clk_hw hw;
void __iomem *base;
struct pll_conf *conf;
unsigned int rate_count;
spinlock_t *lock;
};
#define to_meson_clk_pll(_hw) container_of(_hw, struct meson_clk_pll, hw)
static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw,
......@@ -60,22 +53,36 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw,
struct parm *p;
unsigned long parent_rate_mhz = parent_rate / 1000000;
unsigned long rate_mhz;
u16 n, m, od;
u16 n, m, frac = 0, od, od2 = 0;
u32 reg;
p = &pll->conf->n;
p = &pll->n;
reg = readl(pll->base + p->reg_off);
n = PARM_GET(p->width, p->shift, reg);
p = &pll->conf->m;
p = &pll->m;
reg = readl(pll->base + p->reg_off);
m = PARM_GET(p->width, p->shift, reg);
p = &pll->conf->od;
p = &pll->od;
reg = readl(pll->base + p->reg_off);
od = PARM_GET(p->width, p->shift, reg);
rate_mhz = (parent_rate_mhz * m / n) >> od;
p = &pll->od2;
if (p->width) {
reg = readl(pll->base + p->reg_off);
od2 = PARM_GET(p->width, p->shift, reg);
}
p = &pll->frac;
if (p->width) {
reg = readl(pll->base + p->reg_off);
frac = PARM_GET(p->width, p->shift, reg);
rate_mhz = (parent_rate_mhz * m + \
(parent_rate_mhz * frac >> 12)) * 2 / n;
rate_mhz = rate_mhz >> od >> od2;
} else
rate_mhz = (parent_rate_mhz * m / n) >> od >> od2;
return rate_mhz * 1000000;
}
......@@ -84,7 +91,7 @@ static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
struct meson_clk_pll *pll = to_meson_clk_pll(hw);
const struct pll_rate_table *rate_table = pll->conf->rate_table;
const struct pll_rate_table *rate_table = pll->rate_table;
int i;
for (i = 0; i < pll->rate_count; i++) {
......@@ -99,7 +106,7 @@ static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
static const struct pll_rate_table *meson_clk_get_pll_settings(struct meson_clk_pll *pll,
unsigned long rate)
{
const struct pll_rate_table *rate_table = pll->conf->rate_table;
const struct pll_rate_table *rate_table = pll->rate_table;
int i;
for (i = 0; i < pll->rate_count; i++) {
......@@ -145,24 +152,38 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
return -EINVAL;
/* PLL reset */
p = &pll->conf->n;
p = &pll->n;
reg = readl(pll->base + p->reg_off);
writel(reg | MESON_PLL_RESET, pll->base + p->reg_off);
reg = PARM_SET(p->width, p->shift, reg, rate_set->n);
writel(reg, pll->base + p->reg_off);
p = &pll->conf->m;
p = &pll->m;
reg = readl(pll->base + p->reg_off);
reg = PARM_SET(p->width, p->shift, reg, rate_set->m);
writel(reg, pll->base + p->reg_off);
p = &pll->conf->od;
p = &pll->od;
reg = readl(pll->base + p->reg_off);
reg = PARM_SET(p->width, p->shift, reg, rate_set->od);
writel(reg, pll->base + p->reg_off);
p = &pll->conf->n;
p = &pll->od2;
if (p->width) {
reg = readl(pll->base + p->reg_off);
reg = PARM_SET(p->width, p->shift, reg, rate_set->od2);
writel(reg, pll->base + p->reg_off);
}
p = &pll->frac;
if (p->width) {
reg = readl(pll->base + p->reg_off);
reg = PARM_SET(p->width, p->shift, reg, rate_set->frac);
writel(reg, pll->base + p->reg_off);
}
p = &pll->n;
ret = meson_clk_pll_wait_lock(pll, p);
if (ret) {
pr_warn("%s: pll did not lock, trying to restore old rate %lu\n",
......@@ -173,55 +194,12 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
return ret;
}
static const struct clk_ops meson_clk_pll_ops = {
const struct clk_ops meson_clk_pll_ops = {
.recalc_rate = meson_clk_pll_recalc_rate,
.round_rate = meson_clk_pll_round_rate,
.set_rate = meson_clk_pll_set_rate,
};
static const struct clk_ops meson_clk_pll_ro_ops = {
const struct clk_ops meson_clk_pll_ro_ops = {
.recalc_rate = meson_clk_pll_recalc_rate,
};
struct clk *meson_clk_register_pll(const struct clk_conf *clk_conf,
void __iomem *reg_base,
spinlock_t *lock)
{
struct clk *clk;
struct meson_clk_pll *clk_pll;
struct clk_init_data init;
clk_pll = kzalloc(sizeof(*clk_pll), GFP_KERNEL);
if (!clk_pll)
return ERR_PTR(-ENOMEM);
clk_pll->base = reg_base + clk_conf->reg_off;
clk_pll->lock = lock;
clk_pll->conf = clk_conf->conf.pll;
init.name = clk_conf->clk_name;
init.flags = clk_conf->flags | CLK_GET_RATE_NOCACHE;
init.parent_names = &clk_conf->clks_parent[0];
init.num_parents = 1;
init.ops = &meson_clk_pll_ro_ops;
/* If no rate_table is specified we assume the PLL is read-only */
if (clk_pll->conf->rate_table) {
int len;
for (len = 0; clk_pll->conf->rate_table[len].rate != 0; )
len++;
clk_pll->rate_count = len;
init.ops = &meson_clk_pll_ops;
}
clk_pll->hw.init = &init;
clk = clk_register(NULL, &clk_pll->hw);
if (IS_ERR(clk))
kfree(clk_pll);
return clk;
}
/*
* Copyright (c) 2015 Endless Mobile, Inc.
* Author: Carlo Caione <carlo@endlessm.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/clk-provider.h>
#include <linux/mfd/syscon.h>
#include <linux/slab.h>
#include "clkc.h"
static DEFINE_SPINLOCK(clk_lock);
static struct clk **clks;
static struct clk_onecell_data clk_data;
struct clk ** __init meson_clk_init(struct device_node *np,
unsigned long nr_clks)
{
clks = kcalloc(nr_clks, sizeof(*clks), GFP_KERNEL);
if (!clks)
return ERR_PTR(-ENOMEM);
clk_data.clks = clks;
clk_data.clk_num = nr_clks;
of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
return clks;
}
static void meson_clk_add_lookup(struct clk *clk, unsigned int id)
{
if (clks && id)
clks[id] = clk;
}
static struct clk * __init
meson_clk_register_composite(const struct clk_conf *clk_conf,
void __iomem *clk_base)
{
struct clk *clk;
struct clk_mux *mux = NULL;
struct clk_divider *div = NULL;
struct clk_gate *gate = NULL;
const struct clk_ops *mux_ops = NULL;
const struct composite_conf *composite_conf;
composite_conf = clk_conf->conf.composite;
if (clk_conf->num_parents > 1) {
mux = kzalloc(sizeof(*mux), GFP_KERNEL);
if (!mux)
return ERR_PTR(-ENOMEM);
mux->reg = clk_base + clk_conf->reg_off
+ composite_conf->mux_parm.reg_off;
mux->shift = composite_conf->mux_parm.shift;
mux->mask = BIT(composite_conf->mux_parm.width) - 1;
mux->flags = composite_conf->mux_flags;
mux->lock = &clk_lock;
mux->table = composite_conf->mux_table;
mux_ops = (composite_conf->mux_flags & CLK_MUX_READ_ONLY) ?
&clk_mux_ro_ops : &clk_mux_ops;
}
if (MESON_PARM_APPLICABLE(&composite_conf->div_parm)) {
div = kzalloc(sizeof(*div), GFP_KERNEL);
if (!div) {
clk = ERR_PTR(-ENOMEM);
goto error;
}
div->reg = clk_base + clk_conf->reg_off
+ composite_conf->div_parm.reg_off;
div->shift = composite_conf->div_parm.shift;
div->width = composite_conf->div_parm.width;
div->lock = &clk_lock;
div->flags = composite_conf->div_flags;
div->table = composite_conf->div_table;
}
if (MESON_PARM_APPLICABLE(&composite_conf->gate_parm)) {
gate = kzalloc(sizeof(*gate), GFP_KERNEL);
if (!gate) {
clk = ERR_PTR(-ENOMEM);
goto error;
}
gate->reg = clk_base + clk_conf->reg_off
+ composite_conf->div_parm.reg_off;
gate->bit_idx = composite_conf->gate_parm.shift;
gate->flags = composite_conf->gate_flags;
gate->lock = &clk_lock;
}
clk = clk_register_composite(NULL, clk_conf->clk_name,
clk_conf->clks_parent,
clk_conf->num_parents,
mux ? &mux->hw : NULL, mux_ops,
div ? &div->hw : NULL, &clk_divider_ops,
gate ? &gate->hw : NULL, &clk_gate_ops,
clk_conf->flags);
if (IS_ERR(clk))
goto error;
return clk;
error:
kfree(gate);
kfree(div);
kfree(mux);
return clk;
}
static struct clk * __init
meson_clk_register_fixed_factor(const struct clk_conf *clk_conf,
void __iomem *clk_base)
{
struct clk *clk;
const struct fixed_fact_conf *fixed_fact_conf;
const struct parm *p;
unsigned int mult, div;
u32 reg;
fixed_fact_conf = &clk_conf->conf.fixed_fact;
mult = clk_conf->conf.fixed_fact.mult;
div = clk_conf->conf.fixed_fact.div;
if (!mult) {
mult = 1;
p = &fixed_fact_conf->mult_parm;
if (MESON_PARM_APPLICABLE(p)) {
reg = readl(clk_base + clk_conf->reg_off + p->reg_off);
mult = PARM_GET(p->width, p->shift, reg);
}
}
if (!div) {
div = 1;
p = &fixed_fact_conf->div_parm;
if (MESON_PARM_APPLICABLE(p)) {
reg = readl(clk_base + clk_conf->reg_off + p->reg_off);
mult = PARM_GET(p->width, p->shift, reg);
}
}
clk = clk_register_fixed_factor(NULL,
clk_conf->clk_name,
clk_conf->clks_parent[0],
clk_conf->flags,
mult, div);
return clk;
}
static struct clk * __init
meson_clk_register_fixed_rate(const struct clk_conf *clk_conf,
void __iomem *clk_base)
{
struct clk *clk;
const struct fixed_rate_conf *fixed_rate_conf;
const struct parm *r;
unsigned long rate;
u32 reg;
fixed_rate_conf = &clk_conf->conf.fixed_rate;
rate = fixed_rate_conf->rate;
if (!rate) {
r = &fixed_rate_conf->rate_parm;
reg = readl(clk_base + clk_conf->reg_off + r->reg_off);
rate = PARM_GET(r->width, r->shift, reg);
}
rate *= 1000000;
clk = clk_register_fixed_rate(NULL,
clk_conf->clk_name,
clk_conf->num_parents
? clk_conf->clks_parent[0] : NULL,
clk_conf->flags, rate);
return clk;
}
void __init meson_clk_register_clks(const struct clk_conf *clk_confs,
unsigned int nr_confs,
void __iomem *clk_base)
{
unsigned int i;
struct clk *clk = NULL;
for (i = 0; i < nr_confs; i++) {
const struct clk_conf *clk_conf = &clk_confs[i];
switch (clk_conf->clk_type) {
case CLK_FIXED_RATE:
clk = meson_clk_register_fixed_rate(clk_conf,
clk_base);
break;
case CLK_FIXED_FACTOR:
clk = meson_clk_register_fixed_factor(clk_conf,
clk_base);
break;
case CLK_COMPOSITE:
clk = meson_clk_register_composite(clk_conf,
clk_base);
break;
case CLK_CPU:
clk = meson_clk_register_cpu(clk_conf, clk_base,
&clk_lock);
break;
case CLK_PLL:
clk = meson_clk_register_pll(clk_conf, clk_base,
&clk_lock);
break;
default:
clk = NULL;
}
if (!clk) {
pr_err("%s: unknown clock type %d\n", __func__,
clk_conf->clk_type);
continue;
}
if (IS_ERR(clk)) {
pr_warn("%s: Unable to create %s clock\n", __func__,
clk_conf->clk_name);
continue;
}
meson_clk_add_lookup(clk, clk_conf->clk_id);
}
}
......@@ -34,19 +34,16 @@ struct parm {
u8 shift;
u8 width;
};
#define PARM(_r, _s, _w) \
{ \
.reg_off = (_r), \
.shift = (_s), \
.width = (_w), \
} \
struct pll_rate_table {
unsigned long rate;
u16 m;
u16 n;
u16 od;
u16 od2;
u16 frac;
};
#define PLL_RATE(_r, _m, _n, _od) \
{ \
.rate = (_r), \
......@@ -55,133 +52,69 @@ struct pll_rate_table {
.od = (_od), \
} \
struct pll_conf {
const struct pll_rate_table *rate_table;
struct parm m;
struct parm n;
struct parm od;
};
#define PLL_FRAC_RATE(_r, _m, _n, _od, _od2, _frac) \
{ \
.rate = (_r), \
.m = (_m), \
.n = (_n), \
.od = (_od), \
.od2 = (_od2), \
.frac = (_frac), \
} \
struct fixed_fact_conf {
unsigned int div;
unsigned int mult;
struct parm div_parm;
struct parm mult_parm;
struct meson_clk_pll {
struct clk_hw hw;
void __iomem *base;
struct parm m;
struct parm n;
struct parm frac;
struct parm od;
struct parm od2;
const struct pll_rate_table *rate_table;
unsigned int rate_count;
spinlock_t *lock;
};
struct fixed_rate_conf {
unsigned long rate;
struct parm rate_parm;
};
#define to_meson_clk_pll(_hw) container_of(_hw, struct meson_clk_pll, hw)
struct composite_conf {
struct parm mux_parm;
struct parm div_parm;
struct parm gate_parm;
struct clk_div_table *div_table;
u32 *mux_table;
u8 mux_flags;
u8 div_flags;
u8 gate_flags;
struct meson_clk_cpu {
struct clk_hw hw;
void __iomem *base;
u16 reg_off;
struct notifier_block clk_nb;
const struct clk_div_table *div_table;
};
#define PNAME(x) static const char *x[]
int meson_clk_cpu_notifier_cb(struct notifier_block *nb, unsigned long event,
void *data);
enum clk_type {
CLK_FIXED_FACTOR,
CLK_FIXED_RATE,
CLK_COMPOSITE,
CLK_CPU,
CLK_PLL,
struct meson_clk_mpll {
struct clk_hw hw;
void __iomem *base;
struct parm sdm;
struct parm n2;
/* FIXME ssen gate control? */
spinlock_t *lock;
};
struct clk_conf {
u16 reg_off;
enum clk_type clk_type;
unsigned int clk_id;
const char *clk_name;
const char **clks_parent;
int num_parents;
unsigned long flags;
union {
struct fixed_fact_conf fixed_fact;
struct fixed_rate_conf fixed_rate;
const struct composite_conf *composite;
struct pll_conf *pll;
const struct clk_div_table *div_table;
} conf;
#define MESON_GATE(_name, _reg, _bit) \
struct clk_gate gxbb_##_name = { \
.reg = (void __iomem *) _reg, \
.bit_idx = (_bit), \
.lock = &clk_lock, \
.hw.init = &(struct clk_init_data) { \
.name = #_name, \
.ops = &clk_gate_ops, \
.parent_names = (const char *[]){ "clk81" }, \
.num_parents = 1, \
.flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \
}, \
};
#define FIXED_RATE_P(_ro, _ci, _cn, _f, _c) \
{ \
.reg_off = (_ro), \
.clk_type = CLK_FIXED_RATE, \
.clk_id = (_ci), \
.clk_name = (_cn), \
.flags = (_f), \
.conf.fixed_rate.rate_parm = _c, \
} \
#define FIXED_RATE(_ci, _cn, _f, _r) \
{ \
.clk_type = CLK_FIXED_RATE, \
.clk_id = (_ci), \
.clk_name = (_cn), \
.flags = (_f), \
.conf.fixed_rate.rate = (_r), \
} \
#define PLL(_ro, _ci, _cn, _cp, _f, _c) \
{ \
.reg_off = (_ro), \
.clk_type = CLK_PLL, \
.clk_id = (_ci), \
.clk_name = (_cn), \
.clks_parent = (_cp), \
.num_parents = ARRAY_SIZE(_cp), \
.flags = (_f), \
.conf.pll = (_c), \
} \
#define FIXED_FACTOR_DIV(_ci, _cn, _cp, _f, _d) \
{ \
.clk_type = CLK_FIXED_FACTOR, \
.clk_id = (_ci), \
.clk_name = (_cn), \
.clks_parent = (_cp), \
.num_parents = ARRAY_SIZE(_cp), \
.conf.fixed_fact.div = (_d), \
} \
#define CPU(_ro, _ci, _cn, _cp, _dt) \
{ \
.reg_off = (_ro), \
.clk_type = CLK_CPU, \
.clk_id = (_ci), \
.clk_name = (_cn), \
.clks_parent = (_cp), \
.num_parents = ARRAY_SIZE(_cp), \
.conf.div_table = (_dt), \
} \
#define COMPOSITE(_ro, _ci, _cn, _cp, _f, _c) \
{ \
.reg_off = (_ro), \
.clk_type = CLK_COMPOSITE, \
.clk_id = (_ci), \
.clk_name = (_cn), \
.clks_parent = (_cp), \
.num_parents = ARRAY_SIZE(_cp), \
.flags = (_f), \
.conf.composite = (_c), \
} \
struct clk **meson_clk_init(struct device_node *np, unsigned long nr_clks);
void meson_clk_register_clks(const struct clk_conf *clk_confs,
unsigned int nr_confs, void __iomem *clk_base);
struct clk *meson_clk_register_cpu(const struct clk_conf *clk_conf,
void __iomem *reg_base, spinlock_t *lock);
struct clk *meson_clk_register_pll(const struct clk_conf *clk_conf,
void __iomem *reg_base, spinlock_t *lock);
/* clk_ops */
extern const struct clk_ops meson_clk_pll_ro_ops;
extern const struct clk_ops meson_clk_pll_ops;
extern const struct clk_ops meson_clk_cpu_ops;
extern const struct clk_ops meson_clk_mpll_ro_ops;
#endif /* __CLKC_H */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -87,7 +87,7 @@ enum {
enum {
/* Start from the last defined clock in dt bindings */
LPC32XX_CLK_ADC_DIV = LPC32XX_CLK_HCLK_PLL + 1,
LPC32XX_CLK_ADC_DIV = LPC32XX_CLK_PERIPH + 1,
LPC32XX_CLK_ADC_RTC,
LPC32XX_CLK_TEST1,
LPC32XX_CLK_TEST2,
......@@ -99,7 +99,6 @@ enum {
LPC32XX_CLK_HCLK_DIV_PERIPH,
LPC32XX_CLK_HCLK_DIV,
LPC32XX_CLK_HCLK,
LPC32XX_CLK_PERIPH,
LPC32XX_CLK_ARM,
LPC32XX_CLK_ARM_VFP,
......
......@@ -2290,6 +2290,32 @@ static struct clk_branch sdc5_h_clk = {
},
};
static struct clk_branch ebi2_2x_clk = {
.halt_reg = 0x2fcc,
.halt_bit = 18,
.clkr = {
.enable_reg = 0x2660,
.enable_mask = BIT(4),
.hw.init = &(struct clk_init_data){
.name = "ebi2_2x_clk",
.ops = &clk_branch_ops,
},
},
};
static struct clk_branch ebi2_clk = {
.halt_reg = 0x2fcc,
.halt_bit = 19,
.clkr = {
.enable_reg = 0x2664,
.enable_mask = BIT(4),
.hw.init = &(struct clk_init_data){
.name = "ebi2_clk",
.ops = &clk_branch_ops,
},
},
};
static struct clk_branch adm0_clk = {
.halt_reg = 0x2fdc,
.halt_check = BRANCH_HALT_VOTED,
......@@ -2533,6 +2559,8 @@ static struct clk_regmap *gcc_msm8660_clks[] = {
[SDC3_H_CLK] = &sdc3_h_clk.clkr,
[SDC4_H_CLK] = &sdc4_h_clk.clkr,
[SDC5_H_CLK] = &sdc5_h_clk.clkr,
[EBI2_2X_CLK] = &ebi2_2x_clk.clkr,
[EBI2_CLK] = &ebi2_clk.clkr,
[ADM0_CLK] = &adm0_clk.clkr,
[ADM0_PBUS_CLK] = &adm0_pbus_clk.clkr,
[ADM1_CLK] = &adm1_clk.clkr,
......
......@@ -2891,21 +2891,6 @@ static struct clk_branch gcc_smmu_aggre0_ahb_clk = {
},
};
static struct clk_branch gcc_aggre1_pnoc_ahb_clk = {
.halt_reg = 0x82014,
.clkr = {
.enable_reg = 0x82014,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_aggre1_pnoc_ahb_clk",
.parent_names = (const char *[]){ "periph_noc_clk_src" },
.num_parents = 1,
.flags = CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch gcc_aggre2_ufs_axi_clk = {
.halt_reg = 0x83014,
.clkr = {
......@@ -3308,7 +3293,6 @@ static struct clk_regmap *gcc_msm8996_clocks[] = {
[GCC_AGGRE0_CNOC_AHB_CLK] = &gcc_aggre0_cnoc_ahb_clk.clkr,
[GCC_SMMU_AGGRE0_AXI_CLK] = &gcc_smmu_aggre0_axi_clk.clkr,
[GCC_SMMU_AGGRE0_AHB_CLK] = &gcc_smmu_aggre0_ahb_clk.clkr,
[GCC_AGGRE1_PNOC_AHB_CLK] = &gcc_aggre1_pnoc_ahb_clk.clkr,
[GCC_AGGRE2_UFS_AXI_CLK] = &gcc_aggre2_ufs_axi_clk.clkr,
[GCC_AGGRE2_USB3_AXI_CLK] = &gcc_aggre2_usb3_axi_clk.clkr,
[GCC_QSPI_AHB_CLK] = &gcc_qspi_ahb_clk.clkr,
......
config CLK_RENESAS_CPG_MSSR
bool
default y if ARCH_R8A7795
default y if ARCH_R8A7796
config CLK_RENESAS_CPG_MSTP
bool
......@@ -11,6 +12,7 @@ config CLK_RENESAS_CPG_MSTP
default y if ARCH_R8A7779
default y if ARCH_R8A7790
default y if ARCH_R8A7791
default y if ARCH_R8A7792
default y if ARCH_R8A7793
default y if ARCH_R8A7794
default y if ARCH_SH73A0
......@@ -6,9 +6,11 @@ obj-$(CONFIG_ARCH_R8A7778) += clk-r8a7778.o
obj-$(CONFIG_ARCH_R8A7779) += clk-r8a7779.o
obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o clk-div6.o
obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o clk-div6.o
obj-$(CONFIG_ARCH_R8A7792) += clk-rcar-gen2.o clk-div6.o
obj-$(CONFIG_ARCH_R8A7793) += clk-rcar-gen2.o clk-div6.o
obj-$(CONFIG_ARCH_R8A7794) += clk-rcar-gen2.o clk-div6.o
obj-$(CONFIG_ARCH_R8A7795) += r8a7795-cpg-mssr.o
obj-$(CONFIG_ARCH_R8A7795) += r8a7795-cpg-mssr.o rcar-gen3-cpg.o
obj-$(CONFIG_ARCH_R8A7796) += r8a7796-cpg-mssr.o rcar-gen3-cpg.o
obj-$(CONFIG_ARCH_SH73A0) += clk-sh73a0.o clk-div6.o
obj-$(CONFIG_CLK_RENESAS_CPG_MSSR) += renesas-cpg-mssr.o clk-div6.o
......
This diff is collapsed.
/*
* r8a7796 Clock Pulse Generator / Module Standby and Software Reset
*
* Copyright (C) 2016 Glider bvba
*
* Based on r8a7795-cpg-mssr.c
*
* Copyright (C) 2015 Glider bvba
* Copyright (C) 2015 Renesas Electronics Corp.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*/
#include <linux/device.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <dt-bindings/clock/r8a7796-cpg-mssr.h>
#include "renesas-cpg-mssr.h"
#include "rcar-gen3-cpg.h"
enum clk_ids {
/* Core Clock Outputs exported to DT */
LAST_DT_CORE_CLK = R8A7796_CLK_OSC,
/* External Input Clocks */
CLK_EXTAL,
CLK_EXTALR,
/* Internal Core Clocks */
CLK_MAIN,
CLK_PLL0,
CLK_PLL1,
CLK_PLL2,
CLK_PLL3,
CLK_PLL4,
CLK_PLL1_DIV2,
CLK_PLL1_DIV4,
CLK_S0,
CLK_S1,
CLK_S2,
CLK_S3,
CLK_SDSRC,
CLK_SSPSRC,
/* Module Clocks */
MOD_CLK_BASE
};
static const struct cpg_core_clk r8a7796_core_clks[] __initconst = {
/* External Clock Inputs */
DEF_INPUT("extal", CLK_EXTAL),
DEF_INPUT("extalr", CLK_EXTALR),
/* Internal Core Clocks */
DEF_BASE(".main", CLK_MAIN, CLK_TYPE_GEN3_MAIN, CLK_EXTAL),
DEF_BASE(".pll0", CLK_PLL0, CLK_TYPE_GEN3_PLL0, CLK_MAIN),
DEF_BASE(".pll1", CLK_PLL1, CLK_TYPE_GEN3_PLL1, CLK_MAIN),
DEF_BASE(".pll2", CLK_PLL2, CLK_TYPE_GEN3_PLL2, CLK_MAIN),
DEF_BASE(".pll3", CLK_PLL3, CLK_TYPE_GEN3_PLL3, CLK_MAIN),
DEF_BASE(".pll4", CLK_PLL4, CLK_TYPE_GEN3_PLL4, CLK_MAIN),
DEF_FIXED(".pll1_div2", CLK_PLL1_DIV2, CLK_PLL1, 2, 1),
DEF_FIXED(".pll1_div4", CLK_PLL1_DIV4, CLK_PLL1_DIV2, 2, 1),
DEF_FIXED(".s0", CLK_S0, CLK_PLL1_DIV2, 2, 1),
DEF_FIXED(".s1", CLK_S1, CLK_PLL1_DIV2, 3, 1),
DEF_FIXED(".s2", CLK_S2, CLK_PLL1_DIV2, 4, 1),
DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1),
/* Core Clock Outputs */
DEF_FIXED("ztr", R8A7796_CLK_ZTR, CLK_PLL1_DIV2, 6, 1),
DEF_FIXED("ztrd2", R8A7796_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1),
DEF_FIXED("zt", R8A7796_CLK_ZT, CLK_PLL1_DIV2, 4, 1),
DEF_FIXED("zx", R8A7796_CLK_ZX, CLK_PLL1_DIV2, 2, 1),
DEF_FIXED("s0d1", R8A7796_CLK_S0D1, CLK_S0, 1, 1),
DEF_FIXED("s0d2", R8A7796_CLK_S0D2, CLK_S0, 2, 1),
DEF_FIXED("s0d3", R8A7796_CLK_S0D3, CLK_S0, 3, 1),
DEF_FIXED("s0d4", R8A7796_CLK_S0D4, CLK_S0, 4, 1),
DEF_FIXED("s0d6", R8A7796_CLK_S0D6, CLK_S0, 6, 1),
DEF_FIXED("s0d8", R8A7796_CLK_S0D8, CLK_S0, 8, 1),
DEF_FIXED("s0d12", R8A7796_CLK_S0D12, CLK_S0, 12, 1),
DEF_FIXED("s1d1", R8A7796_CLK_S1D1, CLK_S1, 1, 1),
DEF_FIXED("s1d2", R8A7796_CLK_S1D2, CLK_S1, 2, 1),
DEF_FIXED("s1d4", R8A7796_CLK_S1D4, CLK_S1, 4, 1),
DEF_FIXED("s2d1", R8A7796_CLK_S2D1, CLK_S2, 1, 1),
DEF_FIXED("s2d2", R8A7796_CLK_S2D2, CLK_S2, 2, 1),
DEF_FIXED("s2d4", R8A7796_CLK_S2D4, CLK_S2, 4, 1),
DEF_FIXED("s3d1", R8A7796_CLK_S3D1, CLK_S3, 1, 1),
DEF_FIXED("s3d2", R8A7796_CLK_S3D2, CLK_S3, 2, 1),
DEF_FIXED("s3d4", R8A7796_CLK_S3D4, CLK_S3, 4, 1),
DEF_FIXED("cl", R8A7796_CLK_CL, CLK_PLL1_DIV2, 48, 1),
DEF_FIXED("cp", R8A7796_CLK_CP, CLK_EXTAL, 2, 1),
};
static const struct mssr_mod_clk r8a7796_mod_clks[] __initconst = {
DEF_MOD("scif2", 310, R8A7796_CLK_S3D4),
DEF_MOD("intc-ap", 408, R8A7796_CLK_S3D1),
};
static const unsigned int r8a7796_crit_mod_clks[] __initconst = {
MOD_CLK_ID(408), /* INTC-AP (GIC) */
};
/*
* CPG Clock Data
*/
/*
* MD EXTAL PLL0 PLL1 PLL2 PLL3 PLL4
* 14 13 19 17 (MHz)
*-------------------------------------------------------------------
* 0 0 0 0 16.66 x 1 x180 x192 x144 x192 x144
* 0 0 0 1 16.66 x 1 x180 x192 x144 x128 x144
* 0 0 1 0 Prohibited setting
* 0 0 1 1 16.66 x 1 x180 x192 x144 x192 x144
* 0 1 0 0 20 x 1 x150 x160 x120 x160 x120
* 0 1 0 1 20 x 1 x150 x160 x120 x106 x120
* 0 1 1 0 Prohibited setting
* 0 1 1 1 20 x 1 x150 x160 x120 x160 x120
* 1 0 0 0 25 x 1 x120 x128 x96 x128 x96
* 1 0 0 1 25 x 1 x120 x128 x96 x84 x96
* 1 0 1 0 Prohibited setting
* 1 0 1 1 25 x 1 x120 x128 x96 x128 x96
* 1 1 0 0 33.33 / 2 x180 x192 x144 x192 x144
* 1 1 0 1 33.33 / 2 x180 x192 x144 x128 x144
* 1 1 1 0 Prohibited setting
* 1 1 1 1 33.33 / 2 x180 x192 x144 x192 x144
*/
#define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 11) | \
(((md) & BIT(13)) >> 11) | \
(((md) & BIT(19)) >> 18) | \
(((md) & BIT(17)) >> 17))
static const struct rcar_gen3_cpg_pll_config cpg_pll_configs[16] __initconst = {
/* EXTAL div PLL1 mult PLL3 mult */
{ 1, 192, 192, },
{ 1, 192, 128, },
{ 0, /* Prohibited setting */ },
{ 1, 192, 192, },
{ 1, 160, 160, },
{ 1, 160, 106, },
{ 0, /* Prohibited setting */ },
{ 1, 160, 160, },
{ 1, 128, 128, },
{ 1, 128, 84, },
{ 0, /* Prohibited setting */ },
{ 1, 128, 128, },
{ 2, 192, 192, },
{ 2, 192, 128, },
{ 0, /* Prohibited setting */ },
{ 2, 192, 192, },
};
static int __init r8a7796_cpg_mssr_init(struct device *dev)
{
const struct rcar_gen3_cpg_pll_config *cpg_pll_config;
u32 cpg_mode = rcar_gen3_read_mode_pins();
cpg_pll_config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)];
if (!cpg_pll_config->extal_div) {
dev_err(dev, "Prohibited setting (cpg_mode=0x%x)\n", cpg_mode);
return -EINVAL;
}
return rcar_gen3_cpg_init(cpg_pll_config, CLK_EXTALR);
}
const struct cpg_mssr_info r8a7796_cpg_mssr_info __initconst = {
/* Core Clocks */
.core_clks = r8a7796_core_clks,
.num_core_clks = ARRAY_SIZE(r8a7796_core_clks),
.last_dt_core_clk = LAST_DT_CORE_CLK,
.num_total_core_clks = MOD_CLK_BASE,
/* Module Clocks */
.mod_clks = r8a7796_mod_clks,
.num_mod_clks = ARRAY_SIZE(r8a7796_mod_clks),
.num_hw_mod_clks = 12 * 32,
/* Critical Module Clocks */
.crit_mod_clks = r8a7796_crit_mod_clks,
.num_crit_mod_clks = ARRAY_SIZE(r8a7796_crit_mod_clks),
/* Callbacks */
.init = r8a7796_cpg_mssr_init,
.cpg_clk_register = rcar_gen3_cpg_clk_register,
};
This diff is collapsed.
This diff is collapsed.
......@@ -508,6 +508,12 @@ static const struct of_device_id cpg_mssr_match[] = {
.compatible = "renesas,r8a7795-cpg-mssr",
.data = &r8a7795_cpg_mssr_info,
},
#endif
#ifdef CONFIG_ARCH_R8A7796
{
.compatible = "renesas,r8a7796-cpg-mssr",
.data = &r8a7796_cpg_mssr_info,
},
#endif
{ /* sentinel */ }
};
......
......@@ -131,4 +131,5 @@ struct cpg_mssr_info {
};
extern const struct cpg_mssr_info r8a7795_cpg_mssr_info;
extern const struct cpg_mssr_info r8a7796_cpg_mssr_info;
#endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment