summaryrefslogtreecommitdiff
path: root/drivers/clk/ti
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-12-01 16:06:02 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2019-12-01 16:06:02 -0800
commitddebe839c6013ab42f376bdeaaaf66bd0c0d68d6 (patch)
treea70880a70a6b2b96b71de7d64c0b7b94239ff3e7 /drivers/clk/ti
parentceb307474506f888e8f16dab183405ff01dffa08 (diff)
parentec16ffe36d80b18a1f98d126a865d5557ab27c30 (diff)
Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux
Pull clk updates from Stephen Boyd: "This merge window we have one small clk provider API in the core framework and then a bunch of driver updates and a handful of new drivers. In terms of diffstat the Qualcomm and Amlogic drivers are high up there because of all the clk data introcued by new drivers. The Nvidia Tegra driver had a lot of work done this cycle too to support suspend/resume and memory controllers. And the OMAP clk driver got proper clk and reset handling in place. Rounding out the patches are various updates to remove unused data, mark things static, correct incorrect data in drivers, etc. All the little things that improve drivers and maintain code health. I will point out that there's a patch in here for the GPIO clk driver, that almost nobody uses, which changes behavior and causes clk_set_rate() to try to change the GPIO gate clk's parent. Other than that things are fairly well SoC specific here. Core: - Add a clk provider API to get current parent index - Plug a memory leak in clk_unregister() path New Drivers: - CGU in Ingenix X1000 - Bitmain BM1880 clks - Qualcomm MSM8998 GPU clk controllers - Qualcomm SC7180 GCC and RPMH clk controllers - Qualcomm QCS404 Q6SSTOP clk controllers - Add support for the Renesas R-Car M3-W+ (r8a77961) SoC - Add support for the Renesas RZ/G2N (r8a774b1) SoC - Add Tegra20/30 External Memory Clock (EMC) support Updates: - Make gpio gate clks propagate rate setting up to parent - Prepare Armada 3700 for suspend to RAM by moving PCIe suspend/resume priority - Drop unused variables, enums, etc. in various clk drivers - Convert various drivers to use devm_platform_ioremap_resource() - Use struct_size() some more in various clk drivers - Improve Rockchip px30 clk tree - Add suspend/resume support to Tegra210 clk driver - Reimplement SOR clks on earlier Tegra SoCs, helping HDMI and DP - Allwinner DT exports and H6 clk tree fixes - Proper clk and reset handling for OMAP SoCs - Revamped TI divider clk to clamp max divider - Make 1443X/1416X PLL clock structure common for reusing among i.MX8 SoCs - Drop IMX7ULP_CLK_MIPI_PLL clock, it shouldn't be used - Add VIDEO2_PLL clock for imx8mq - Add missing gate clock for pll1/2 fixed dividers on i.MX8 SoCs - Add sm1 support in the Amlogic audio clock controller - Switch some clocks on R-Car Gen2/3 to .determine_rate() - Remove Renesas R-Car Gen2 legacy DT clock support - Improve arithmetic divisions on Renesas R-Car Gen2 and Gen3 - Improve Renesas R-Car Gen3 SD clock handling - Add rate table for Samsung exynos542x GPU and VPLL clks - Fix potential CPU performance degradation after system suspend/resume cycle on exynos542x SoCs" * tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (160 commits) clk: aspeed: Add RMII RCLK gates for both AST2500 MACs MAINTAINERS: Add entry for BM1880 SoC clock driver clk: Add common clock driver for BM1880 SoC dt-bindings: clock: Add devicetree binding for BM1880 SoC clk: Add clk_hw_unregister_composite helper function definition clk: Zero init clk_init_data in helpers clk: ingenic: Allow drivers to be built with COMPILE_TEST MAINTAINERS: Update section for Ux500 clock drivers clk: mark clk_disable_unused() as __init clk: Fix memory leak in clk_unregister() clk: Ingenic: Add CGU driver for X1000. dt-bindings: clock: Add X1000 bindings. clk: tegra: Use match_string() helper to simplify the code clk: pxa: fix one of the pxa RTC clocks clk: sprd: Use IS_ERR() to validate the return value of syscon_regmap_lookup_by_phandle() clk: armada-xp: remove unused code clk: tegra: Fix build error without CONFIG_PM_SLEEP clk: tegra: Add missing stubs for the case of !CONFIG_PM_SLEEP clk: tegra: Optimize PLLX restore on Tegra20/30 clk: tegra: Add suspend and resume support on Tegra210 ...
Diffstat (limited to 'drivers/clk/ti')
-rw-r--r--drivers/clk/ti/adpll.c11
-rw-r--r--drivers/clk/ti/clk-33xx.c4
-rw-r--r--drivers/clk/ti/clk-43xx.c4
-rw-r--r--drivers/clk/ti/clk-44xx.c4
-rw-r--r--drivers/clk/ti/clk-54xx.c11
-rw-r--r--drivers/clk/ti/clk-7xx.c8
-rw-r--r--drivers/clk/ti/clkctrl.c45
-rw-r--r--drivers/clk/ti/clock.h7
-rw-r--r--drivers/clk/ti/divider.c282
9 files changed, 178 insertions, 198 deletions
diff --git a/drivers/clk/ti/adpll.c b/drivers/clk/ti/adpll.c
index fdfb90058504..bb2f2836dab2 100644
--- a/drivers/clk/ti/adpll.c
+++ b/drivers/clk/ti/adpll.c
@@ -194,15 +194,8 @@ static const char *ti_adpll_clk_get_name(struct ti_adpll_data *d,
if (err)
return NULL;
} else {
- const char *base_name = "adpll";
- char *buf;
-
- buf = devm_kzalloc(d->dev, 8 + 1 + strlen(base_name) + 1 +
- strlen(postfix), GFP_KERNEL);
- if (!buf)
- return NULL;
- sprintf(buf, "%08lx.%s.%s", d->pa, base_name, postfix);
- name = buf;
+ name = devm_kasprintf(d->dev, GFP_KERNEL, "%08lx.adpll.%s",
+ d->pa, postfix);
}
return name;
diff --git a/drivers/clk/ti/clk-33xx.c b/drivers/clk/ti/clk-33xx.c
index a360d3109555..e001b9bcb6bf 100644
--- a/drivers/clk/ti/clk-33xx.c
+++ b/drivers/clk/ti/clk-33xx.c
@@ -107,7 +107,7 @@ static const struct omap_clkctrl_reg_data am3_l4hs_clkctrl_regs[] __initconst =
};
static const struct omap_clkctrl_reg_data am3_pruss_ocp_clkctrl_regs[] __initconst = {
- { AM3_PRUSS_OCP_PRUSS_CLKCTRL, NULL, CLKF_SW_SUP, "pruss_ocp_gclk" },
+ { AM3_PRUSS_OCP_PRUSS_CLKCTRL, NULL, CLKF_SW_SUP | CLKF_NO_IDLEST, "pruss_ocp_gclk" },
{ 0 },
};
@@ -217,7 +217,7 @@ static const struct omap_clkctrl_reg_data am3_l4_rtc_clkctrl_regs[] __initconst
};
static const struct omap_clkctrl_reg_data am3_gfx_l3_clkctrl_regs[] __initconst = {
- { AM3_GFX_L3_GFX_CLKCTRL, NULL, CLKF_SW_SUP, "gfx_fck_div_ck" },
+ { AM3_GFX_L3_GFX_CLKCTRL, NULL, CLKF_SW_SUP | CLKF_NO_IDLEST, "gfx_fck_div_ck" },
{ 0 },
};
diff --git a/drivers/clk/ti/clk-43xx.c b/drivers/clk/ti/clk-43xx.c
index 2782d91838ac..af3e7805769e 100644
--- a/drivers/clk/ti/clk-43xx.c
+++ b/drivers/clk/ti/clk-43xx.c
@@ -73,7 +73,7 @@ static const struct omap_clkctrl_reg_data am4_mpu_clkctrl_regs[] __initconst = {
};
static const struct omap_clkctrl_reg_data am4_gfx_l3_clkctrl_regs[] __initconst = {
- { AM4_GFX_L3_GFX_CLKCTRL, NULL, CLKF_SW_SUP, "gfx_fck_div_ck" },
+ { AM4_GFX_L3_GFX_CLKCTRL, NULL, CLKF_SW_SUP | CLKF_NO_IDLEST, "gfx_fck_div_ck" },
{ 0 },
};
@@ -126,7 +126,7 @@ static const struct omap_clkctrl_reg_data am4_l3s_clkctrl_regs[] __initconst = {
};
static const struct omap_clkctrl_reg_data am4_pruss_ocp_clkctrl_regs[] __initconst = {
- { AM4_PRUSS_OCP_PRUSS_CLKCTRL, NULL, CLKF_SW_SUP, "pruss_ocp_gclk" },
+ { AM4_PRUSS_OCP_PRUSS_CLKCTRL, NULL, CLKF_SW_SUP | CLKF_NO_IDLEST, "pruss_ocp_gclk" },
{ 0 },
};
diff --git a/drivers/clk/ti/clk-44xx.c b/drivers/clk/ti/clk-44xx.c
index b10ed0429091..2b4dab632318 100644
--- a/drivers/clk/ti/clk-44xx.c
+++ b/drivers/clk/ti/clk-44xx.c
@@ -37,7 +37,7 @@ static const struct omap_clkctrl_reg_data omap4_mpuss_clkctrl_regs[] __initconst
};
static const struct omap_clkctrl_reg_data omap4_tesla_clkctrl_regs[] __initconst = {
- { OMAP4_DSP_CLKCTRL, NULL, CLKF_HW_SUP, "dpll_iva_m4x2_ck" },
+ { OMAP4_DSP_CLKCTRL, NULL, CLKF_HW_SUP | CLKF_NO_IDLEST, "dpll_iva_m4x2_ck" },
{ 0 },
};
@@ -219,7 +219,7 @@ static const struct omap_clkctrl_reg_data omap4_l3_2_clkctrl_regs[] __initconst
};
static const struct omap_clkctrl_reg_data omap4_ducati_clkctrl_regs[] __initconst = {
- { OMAP4_IPU_CLKCTRL, NULL, CLKF_HW_SUP, "ducati_clk_mux_ck" },
+ { OMAP4_IPU_CLKCTRL, NULL, CLKF_HW_SUP | CLKF_NO_IDLEST, "ducati_clk_mux_ck" },
{ 0 },
};
diff --git a/drivers/clk/ti/clk-54xx.c b/drivers/clk/ti/clk-54xx.c
index e675e27f1203..c9608e5d993a 100644
--- a/drivers/clk/ti/clk-54xx.c
+++ b/drivers/clk/ti/clk-54xx.c
@@ -31,7 +31,7 @@ static const struct omap_clkctrl_reg_data omap5_mpu_clkctrl_regs[] __initconst =
};
static const struct omap_clkctrl_reg_data omap5_dsp_clkctrl_regs[] __initconst = {
- { OMAP5_MMU_DSP_CLKCTRL, NULL, CLKF_HW_SUP, "dpll_iva_h11x2_ck" },
+ { OMAP5_MMU_DSP_CLKCTRL, NULL, CLKF_HW_SUP | CLKF_NO_IDLEST, "dpll_iva_h11x2_ck" },
{ 0 },
};
@@ -145,7 +145,7 @@ static const struct omap_clkctrl_reg_data omap5_l3main2_clkctrl_regs[] __initcon
};
static const struct omap_clkctrl_reg_data omap5_ipu_clkctrl_regs[] __initconst = {
- { OMAP5_MMU_IPU_CLKCTRL, NULL, CLKF_HW_SUP, "dpll_core_h22x2_ck" },
+ { OMAP5_MMU_IPU_CLKCTRL, NULL, CLKF_HW_SUP | CLKF_NO_IDLEST, "dpll_core_h22x2_ck" },
{ 0 },
};
@@ -286,6 +286,12 @@ static const struct omap_clkctrl_reg_data omap5_l4per_clkctrl_regs[] __initconst
{ 0 },
};
+static const struct omap_clkctrl_reg_data omap5_iva_clkctrl_regs[] __initconst = {
+ { OMAP5_IVA_CLKCTRL, NULL, CLKF_HW_SUP, "dpll_iva_h12x2_ck" },
+ { OMAP5_SL2IF_CLKCTRL, NULL, CLKF_HW_SUP, "dpll_iva_h12x2_ck" },
+ { 0 },
+};
+
static const char * const omap5_dss_dss_clk_parents[] __initconst = {
"dpll_per_h12x2_ck",
NULL,
@@ -502,6 +508,7 @@ const struct omap_clkctrl_data omap5_clkctrl_data[] __initconst = {
{ 0x4a008d20, omap5_l4cfg_clkctrl_regs },
{ 0x4a008e20, omap5_l3instr_clkctrl_regs },
{ 0x4a009020, omap5_l4per_clkctrl_regs },
+ { 0x4a009220, omap5_iva_clkctrl_regs },
{ 0x4a009420, omap5_dss_clkctrl_regs },
{ 0x4a009520, omap5_gpu_clkctrl_regs },
{ 0x4a009620, omap5_l3init_clkctrl_regs },
diff --git a/drivers/clk/ti/clk-7xx.c b/drivers/clk/ti/clk-7xx.c
index 9dd6185a4b4e..5f46782cebeb 100644
--- a/drivers/clk/ti/clk-7xx.c
+++ b/drivers/clk/ti/clk-7xx.c
@@ -25,7 +25,7 @@ static const struct omap_clkctrl_reg_data dra7_mpu_clkctrl_regs[] __initconst =
};
static const struct omap_clkctrl_reg_data dra7_dsp1_clkctrl_regs[] __initconst = {
- { DRA7_DSP1_MMU0_DSP1_CLKCTRL, NULL, CLKF_HW_SUP, "dpll_dsp_m2_ck" },
+ { DRA7_DSP1_MMU0_DSP1_CLKCTRL, NULL, CLKF_HW_SUP | CLKF_NO_IDLEST, "dpll_dsp_m2_ck" },
{ 0 },
};
@@ -41,7 +41,7 @@ static const struct omap_clkctrl_bit_data dra7_mmu_ipu1_bit_data[] __initconst =
};
static const struct omap_clkctrl_reg_data dra7_ipu1_clkctrl_regs[] __initconst = {
- { DRA7_IPU1_MMU_IPU1_CLKCTRL, dra7_mmu_ipu1_bit_data, CLKF_HW_SUP, "ipu1-clkctrl:0000:24" },
+ { DRA7_IPU1_MMU_IPU1_CLKCTRL, dra7_mmu_ipu1_bit_data, CLKF_HW_SUP | CLKF_NO_IDLEST, "ipu1-clkctrl:0000:24" },
{ 0 },
};
@@ -137,7 +137,7 @@ static const struct omap_clkctrl_reg_data dra7_ipu_clkctrl_regs[] __initconst =
};
static const struct omap_clkctrl_reg_data dra7_dsp2_clkctrl_regs[] __initconst = {
- { DRA7_DSP2_MMU0_DSP2_CLKCTRL, NULL, CLKF_HW_SUP, "dpll_dsp_m2_ck" },
+ { DRA7_DSP2_MMU0_DSP2_CLKCTRL, NULL, CLKF_HW_SUP | CLKF_NO_IDLEST, "dpll_dsp_m2_ck" },
{ 0 },
};
@@ -164,7 +164,7 @@ static const struct omap_clkctrl_reg_data dra7_l3main1_clkctrl_regs[] __initcons
};
static const struct omap_clkctrl_reg_data dra7_ipu2_clkctrl_regs[] __initconst = {
- { DRA7_IPU2_MMU_IPU2_CLKCTRL, NULL, CLKF_HW_SUP, "dpll_core_h22x2_ck" },
+ { DRA7_IPU2_MMU_IPU2_CLKCTRL, NULL, CLKF_HW_SUP | CLKF_NO_IDLEST, "dpll_core_h22x2_ck" },
{ 0 },
};
diff --git a/drivers/clk/ti/clkctrl.c b/drivers/clk/ti/clkctrl.c
index b0c0690a5a12..17b9a761242f 100644
--- a/drivers/clk/ti/clkctrl.c
+++ b/drivers/clk/ti/clkctrl.c
@@ -24,7 +24,7 @@
#include <linux/timekeeping.h>
#include "clock.h"
-#define NO_IDLEST 0x1
+#define NO_IDLEST 0
#define OMAP4_MODULEMODE_MASK 0x3
@@ -34,6 +34,9 @@
#define OMAP4_IDLEST_MASK (0x3 << 16)
#define OMAP4_IDLEST_SHIFT 16
+#define OMAP4_STBYST_MASK BIT(18)
+#define OMAP4_STBYST_SHIFT 18
+
#define CLKCTRL_IDLEST_FUNCTIONAL 0x0
#define CLKCTRL_IDLEST_INTERFACE_IDLE 0x2
#define CLKCTRL_IDLEST_DISABLED 0x3
@@ -159,7 +162,7 @@ static int _omap4_clkctrl_clk_enable(struct clk_hw *hw)
ti_clk_ll_ops->clk_writel(val, &clk->enable_reg);
- if (clk->flags & NO_IDLEST)
+ if (test_bit(NO_IDLEST, &clk->flags))
return 0;
/* Wait until module is enabled */
@@ -188,7 +191,7 @@ static void _omap4_clkctrl_clk_disable(struct clk_hw *hw)
ti_clk_ll_ops->clk_writel(val, &clk->enable_reg);
- if (clk->flags & NO_IDLEST)
+ if (test_bit(NO_IDLEST, &clk->flags))
goto exit;
/* Wait until module is disabled */
@@ -381,7 +384,7 @@ _ti_clkctrl_setup_div(struct omap_clkctrl_provider *provider,
if (ti_clk_parse_divider_data((int *)div_data->dividers, 0,
div_data->max_div, div_flags,
- &div->width, &div->table)) {
+ div)) {
pr_err("%s: Data parsing for %pOF:%04x:%d failed\n", __func__,
node, offset, data->bit);
kfree(div);
@@ -597,7 +600,7 @@ static void __init _ti_omap4_clkctrl_setup(struct device_node *node)
if (reg_data->flags & CLKF_HW_SUP)
hw->enable_bit = MODULEMODE_HWCTRL;
if (reg_data->flags & CLKF_NO_IDLEST)
- hw->flags |= NO_IDLEST;
+ set_bit(NO_IDLEST, &hw->flags);
if (reg_data->clkdm_name)
hw->clkdm_name = reg_data->clkdm_name;
@@ -623,7 +626,7 @@ static void __init _ti_omap4_clkctrl_setup(struct device_node *node)
init.ops = &omap4_clkctrl_clk_ops;
hw->hw.init = &init;
- clk = ti_clk_register(NULL, &hw->hw, init.name);
+ clk = ti_clk_register_omap_hw(NULL, &hw->hw, init.name);
if (IS_ERR_OR_NULL(clk))
goto cleanup;
@@ -648,3 +651,33 @@ cleanup:
}
CLK_OF_DECLARE(ti_omap4_clkctrl_clock, "ti,clkctrl",
_ti_omap4_clkctrl_setup);
+
+/**
+ * ti_clk_is_in_standby - Check if clkctrl clock is in standby or not
+ * @clk: clock to check standby status for
+ *
+ * Finds whether the provided clock is in standby mode or not. Returns
+ * true if the provided clock is a clkctrl type clock and it is in standby,
+ * false otherwise.
+ */
+bool ti_clk_is_in_standby(struct clk *clk)
+{
+ struct clk_hw *hw;
+ struct clk_hw_omap *hwclk;
+ u32 val;
+
+ hw = __clk_get_hw(clk);
+
+ if (!omap2_clk_is_hw_omap(hw))
+ return false;
+
+ hwclk = to_clk_hw_omap(hw);
+
+ val = ti_clk_ll_ops->clk_readl(&hwclk->enable_reg);
+
+ if (val & OMAP4_STBYST_MASK)
+ return true;
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(ti_clk_is_in_standby);
diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h
index e4b8392ff63c..e6995c04001e 100644
--- a/drivers/clk/ti/clock.h
+++ b/drivers/clk/ti/clock.h
@@ -20,9 +20,11 @@ struct clk_omap_divider {
struct clk_hw hw;
struct clk_omap_reg reg;
u8 shift;
- u8 width;
u8 flags;
s8 latch;
+ u16 min;
+ u16 max;
+ u16 mask;
const struct clk_div_table *table;
u32 context;
};
@@ -220,8 +222,7 @@ void ti_clk_latch(struct clk_omap_reg *reg, s8 shift);
struct clk_hw *ti_clk_build_component_mux(struct ti_clk_mux *setup);
int ti_clk_parse_divider_data(int *div_table, int num_dividers, int max_div,
- u8 flags, u8 *width,
- const struct clk_div_table **table);
+ u8 flags, struct clk_omap_divider *div);
int ti_clk_get_reg_addr(struct device_node *node, int index,
struct clk_omap_reg *reg);
diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c
index 6cb863c13648..28080df92f72 100644
--- a/drivers/clk/ti/divider.c
+++ b/drivers/clk/ti/divider.c
@@ -26,30 +26,6 @@
#undef pr_fmt
#define pr_fmt(fmt) "%s: " fmt, __func__
-#define div_mask(d) ((1 << ((d)->width)) - 1)
-
-static unsigned int _get_table_maxdiv(const struct clk_div_table *table)
-{
- unsigned int maxdiv = 0;
- const struct clk_div_table *clkt;
-
- for (clkt = table; clkt->div; clkt++)
- if (clkt->div > maxdiv)
- maxdiv = clkt->div;
- return maxdiv;
-}
-
-static unsigned int _get_maxdiv(struct clk_omap_divider *divider)
-{
- if (divider->flags & CLK_DIVIDER_ONE_BASED)
- return div_mask(divider);
- if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
- return 1 << div_mask(divider);
- if (divider->table)
- return _get_table_maxdiv(divider->table);
- return div_mask(divider) + 1;
-}
-
static unsigned int _get_table_div(const struct clk_div_table *table,
unsigned int val)
{
@@ -61,6 +37,34 @@ static unsigned int _get_table_div(const struct clk_div_table *table,
return 0;
}
+static void _setup_mask(struct clk_omap_divider *divider)
+{
+ u16 mask;
+ u32 max_val;
+ const struct clk_div_table *clkt;
+
+ if (divider->table) {
+ max_val = 0;
+
+ for (clkt = divider->table; clkt->div; clkt++)
+ if (clkt->val > max_val)
+ max_val = clkt->val;
+ } else {
+ max_val = divider->max;
+
+ if (!(divider->flags & CLK_DIVIDER_ONE_BASED) &&
+ !(divider->flags & CLK_DIVIDER_POWER_OF_TWO))
+ max_val--;
+ }
+
+ if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
+ mask = fls(max_val) - 1;
+ else
+ mask = max_val;
+
+ divider->mask = (1 << fls(mask)) - 1;
+}
+
static unsigned int _get_div(struct clk_omap_divider *divider, unsigned int val)
{
if (divider->flags & CLK_DIVIDER_ONE_BASED)
@@ -101,7 +105,7 @@ static unsigned long ti_clk_divider_recalc_rate(struct clk_hw *hw,
unsigned int div, val;
val = ti_clk_ll_ops->clk_readl(&divider->reg) >> divider->shift;
- val &= div_mask(divider);
+ val &= divider->mask;
div = _get_div(divider, val);
if (!div) {
@@ -180,7 +184,7 @@ static int ti_clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
if (!rate)
rate = 1;
- maxdiv = _get_maxdiv(divider);
+ maxdiv = divider->max;
if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
parent_rate = *best_parent_rate;
@@ -219,7 +223,7 @@ static int ti_clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
}
if (!bestdiv) {
- bestdiv = _get_maxdiv(divider);
+ bestdiv = divider->max;
*best_parent_rate =
clk_hw_round_rate(clk_hw_get_parent(hw), 1);
}
@@ -249,17 +253,16 @@ static int ti_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
divider = to_clk_omap_divider(hw);
div = DIV_ROUND_UP(parent_rate, rate);
- value = _get_val(divider, div);
- if (value > div_mask(divider))
- value = div_mask(divider);
+ if (div > divider->max)
+ div = divider->max;
+ if (div < divider->min)
+ div = divider->min;
- if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
- val = div_mask(divider) << (divider->shift + 16);
- } else {
- val = ti_clk_ll_ops->clk_readl(&divider->reg);
- val &= ~(div_mask(divider) << divider->shift);
- }
+ value = _get_val(divider, div);
+
+ val = ti_clk_ll_ops->clk_readl(&divider->reg);
+ val &= ~(divider->mask << divider->shift);
val |= value << divider->shift;
ti_clk_ll_ops->clk_writel(val, &divider->reg);
@@ -280,7 +283,7 @@ static int clk_divider_save_context(struct clk_hw *hw)
u32 val;
val = ti_clk_ll_ops->clk_readl(&divider->reg) >> divider->shift;
- divider->context = val & div_mask(divider);
+ divider->context = val & divider->mask;
return 0;
}
@@ -297,7 +300,7 @@ static void clk_divider_restore_context(struct clk_hw *hw)
u32 val;
val = ti_clk_ll_ops->clk_readl(&divider->reg);
- val &= ~(div_mask(divider) << divider->shift);
+ val &= ~(divider->mask << divider->shift);
val |= divider->context << divider->shift;
ti_clk_ll_ops->clk_writel(val, &divider->reg);
}
@@ -310,47 +313,26 @@ const struct clk_ops ti_clk_divider_ops = {
.restore_context = clk_divider_restore_context,
};
-static struct clk *_register_divider(struct device *dev, const char *name,
- const char *parent_name,
- unsigned long flags,
- struct clk_omap_reg *reg,
- u8 shift, u8 width, s8 latch,
- u8 clk_divider_flags,
- const struct clk_div_table *table)
+static struct clk *_register_divider(struct device_node *node,
+ u32 flags,
+ struct clk_omap_divider *div)
{
- struct clk_omap_divider *div;
struct clk *clk;
struct clk_init_data init;
+ const char *parent_name;
- if (clk_divider_flags & CLK_DIVIDER_HIWORD_MASK) {
- if (width + shift > 16) {
- pr_warn("divider value exceeds LOWORD field\n");
- return ERR_PTR(-EINVAL);
- }
- }
-
- /* allocate the divider */
- div = kzalloc(sizeof(*div), GFP_KERNEL);
- if (!div)
- return ERR_PTR(-ENOMEM);
+ parent_name = of_clk_get_parent_name(node, 0);
- init.name = name;
+ init.name = node->name;
init.ops = &ti_clk_divider_ops;
init.flags = flags;
init.parent_names = (parent_name ? &parent_name : NULL);
init.num_parents = (parent_name ? 1 : 0);
- /* struct clk_divider assignments */
- memcpy(&div->reg, reg, sizeof(*reg));
- div->shift = shift;
- div->width = width;
- div->latch = latch;
- div->flags = clk_divider_flags;
div->hw.init = &init;
- div->table = table;
/* register the clock */
- clk = ti_clk_register(dev, &div->hw, name);
+ clk = ti_clk_register(NULL, &div->hw, node->name);
if (IS_ERR(clk))
kfree(div);
@@ -359,34 +341,17 @@ static struct clk *_register_divider(struct device *dev, const char *name,
}
int ti_clk_parse_divider_data(int *div_table, int num_dividers, int max_div,
- u8 flags, u8 *width,
- const struct clk_div_table **table)
+ u8 flags, struct clk_omap_divider *divider)
{
int valid_div = 0;
- u32 val;
- int div;
int i;
struct clk_div_table *tmp;
+ u16 min_div = 0;
if (!div_table) {
- if (flags & CLKF_INDEX_STARTS_AT_ONE)
- val = 1;
- else
- val = 0;
-
- div = 1;
-
- while (div < max_div) {
- if (flags & CLKF_INDEX_POWER_OF_TWO)
- div <<= 1;
- else
- div++;
- val++;
- }
-
- *width = fls(val);
- *table = NULL;
-
+ divider->min = 1;
+ divider->max = max_div;
+ _setup_mask(divider);
return 0;
}
@@ -403,30 +368,32 @@ int ti_clk_parse_divider_data(int *div_table, int num_dividers, int max_div,
num_dividers = i;
tmp = kcalloc(valid_div + 1, sizeof(*tmp), GFP_KERNEL);
- if (!tmp) {
- *table = ERR_PTR(-ENOMEM);
+ if (!tmp)
return -ENOMEM;
- }
valid_div = 0;
- *width = 0;
for (i = 0; i < num_dividers; i++)
if (div_table[i] > 0) {
tmp[valid_div].div = div_table[i];
tmp[valid_div].val = i;
valid_div++;
- *width = i;
+ if (div_table[i] > max_div)
+ max_div = div_table[i];
+ if (!min_div || div_table[i] < min_div)
+ min_div = div_table[i];
}
- *width = fls(*width);
- *table = tmp;
+ divider->min = min_div;
+ divider->max = max_div;
+ divider->table = tmp;
+ _setup_mask(divider);
return 0;
}
-static struct clk_div_table *
-__init ti_clk_get_div_table(struct device_node *node)
+static int __init ti_clk_get_div_table(struct device_node *node,
+ struct clk_omap_divider *div)
{
struct clk_div_table *table;
const __be32 *divspec;
@@ -438,7 +405,7 @@ __init ti_clk_get_div_table(struct device_node *node)
divspec = of_get_property(node, "ti,dividers", &num_div);
if (!divspec)
- return NULL;
+ return 0;
num_div /= 4;
@@ -453,13 +420,12 @@ __init ti_clk_get_div_table(struct device_node *node)
if (!valid_div) {
pr_err("no valid dividers for %pOFn table\n", node);
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
}
table = kcalloc(valid_div + 1, sizeof(*table), GFP_KERNEL);
-
if (!table)
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
valid_div = 0;
@@ -472,19 +438,20 @@ __init ti_clk_get_div_table(struct device_node *node)
}
}
- return table;
+ div->table = table;
+
+ return 0;
}
-static int _get_divider_width(struct device_node *node,
- const struct clk_div_table *table,
- u8 flags)
+static int _populate_divider_min_max(struct device_node *node,
+ struct clk_omap_divider *divider)
{
- u32 min_div;
- u32 max_div;
- u32 val = 0;
- u32 div;
+ u32 min_div = 0;
+ u32 max_div = 0;
+ u32 val;
+ const struct clk_div_table *clkt;
- if (!table) {
+ if (!divider->table) {
/* Clk divider table not provided, determine min/max divs */
if (of_property_read_u32(node, "ti,min-div", &min_div))
min_div = 1;
@@ -493,75 +460,62 @@ static int _get_divider_width(struct device_node *node,
pr_err("no max-div for %pOFn!\n", node);
return -EINVAL;
}
-
- /* Determine bit width for the field */
- if (flags & CLK_DIVIDER_ONE_BASED)
- val = 1;
-
- div = min_div;
-
- while (div < max_div) {
- if (flags & CLK_DIVIDER_POWER_OF_TWO)
- div <<= 1;
- else
- div++;
- val++;
- }
} else {
- div = 0;
- while (table[div].div) {
- val = table[div].val;
- div++;
+ for (clkt = divider->table; clkt->div; clkt++) {
+ val = clkt->div;
+ if (val > max_div)
+ max_div = val;
+ if (!min_div || val < min_div)
+ min_div = val;
}
}
- return fls(val);
+ divider->min = min_div;
+ divider->max = max_div;
+ _setup_mask(divider);
+
+ return 0;
}
static int __init ti_clk_divider_populate(struct device_node *node,
- struct clk_omap_reg *reg, const struct clk_div_table **table,
- u32 *flags, u8 *div_flags, u8 *width, u8 *shift, s8 *latch)
+ struct clk_omap_divider *div,
+ u32 *flags)
{
u32 val;
int ret;
- ret = ti_clk_get_reg_addr(node, 0, reg);
+ ret = ti_clk_get_reg_addr(node, 0, &div->reg);
if (ret)
return ret;
if (!of_property_read_u32(node, "ti,bit-shift", &val))
- *shift = val;
+ div->shift = val;
else
- *shift = 0;
+ div->shift = 0;
- if (latch) {
- if (!of_property_read_u32(node, "ti,latch-bit", &val))
- *latch = val;
- else
- *latch = -EINVAL;
- }
+ if (!of_property_read_u32(node, "ti,latch-bit", &val))
+ div->latch = val;
+ else
+ div->latch = -EINVAL;
*flags = 0;
- *div_flags = 0;
+ div->flags = 0;
if (of_property_read_bool(node, "ti,index-starts-at-one"))
- *div_flags |= CLK_DIVIDER_ONE_BASED;
+ div->flags |= CLK_DIVIDER_ONE_BASED;
if (of_property_read_bool(node, "ti,index-power-of-two"))
- *div_flags |= CLK_DIVIDER_POWER_OF_TWO;
+ div->flags |= CLK_DIVIDER_POWER_OF_TWO;
if (of_property_read_bool(node, "ti,set-rate-parent"))
*flags |= CLK_SET_RATE_PARENT;
- *table = ti_clk_get_div_table(node);
-
- if (IS_ERR(*table))
- return PTR_ERR(*table);
-
- *width = _get_divider_width(node, *table, *div_flags);
+ ret = ti_clk_get_div_table(node, div);
+ if (ret)
+ return ret;
- return 0;
+ return _populate_divider_min_max(node, div);
}
/**
@@ -573,24 +527,17 @@ static int __init ti_clk_divider_populate(struct device_node *node,
static void __init of_ti_divider_clk_setup(struct device_node *node)
{
struct clk *clk;
- const char *parent_name;
- struct clk_omap_reg reg;
- u8 clk_divider_flags = 0;
- u8 width = 0;
- u8 shift = 0;
- s8 latch = -EINVAL;
- const struct clk_div_table *table = NULL;
u32 flags = 0;
+ struct clk_omap_divider *div;
- parent_name = of_clk_get_parent_name(node, 0);
+ div = kzalloc(sizeof(*div), GFP_KERNEL);
+ if (!div)
+ return;
- if (ti_clk_divider_populate(node, &reg, &table, &flags,
- &clk_divider_flags, &width, &shift, &latch))
+ if (ti_clk_divider_populate(node, div, &flags))
goto cleanup;
- clk = _register_divider(NULL, node->name, parent_name, flags, &reg,
- shift, width, latch, clk_divider_flags, table);
-
+ clk = _register_divider(node, flags, div);
if (!IS_ERR(clk)) {
of_clk_add_provider(node, of_clk_src_simple_get, clk);
of_ti_clk_autoidle_setup(node);
@@ -598,22 +545,21 @@ static void __init of_ti_divider_clk_setup(struct device_node *node)
}
cleanup:
- kfree(table);
+ kfree(div->table);
+ kfree(div);
}
CLK_OF_DECLARE(divider_clk, "ti,divider-clock", of_ti_divider_clk_setup);
static void __init of_ti_composite_divider_clk_setup(struct device_node *node)
{
struct clk_omap_divider *div;
- u32 val;
+ u32 tmp;
div = kzalloc(sizeof(*div), GFP_KERNEL);
if (!div)
return;
- if (ti_clk_divider_populate(node, &div->reg, &div->table, &val,
- &div->flags, &div->width, &div->shift,
- NULL) < 0)
+ if (ti_clk_divider_populate(node, div, &tmp))
goto cleanup;
if (!ti_clk_add_component(node, &div->hw, CLK_COMPONENT_TYPE_DIVIDER))