diff options
-rw-r--r-- | drivers/clk/clk-si514.c | 38 | ||||
-rw-r--r-- | drivers/clk/clk-si544.c | 38 | ||||
-rw-r--r-- | drivers/clk/clk.c | 16 | ||||
-rw-r--r-- | drivers/clk/imx/clk-imx6ul.c | 28 | ||||
-rw-r--r-- | drivers/clk/qcom/gcc-ipq806x.c | 3 | ||||
-rw-r--r-- | drivers/clk/qcom/gcc-mdm9615.c | 2 | ||||
-rw-r--r-- | drivers/clk/qcom/gcc-msm8660.c | 5 | ||||
-rw-r--r-- | drivers/clk/qcom/gcc-msm8960.c | 5 | ||||
-rw-r--r-- | include/dt-bindings/clock/imx6ul-clock.h | 46 |
9 files changed, 123 insertions, 58 deletions
diff --git a/drivers/clk/clk-si514.c b/drivers/clk/clk-si514.c index 09b6718956bd..153b3a2b5857 100644 --- a/drivers/clk/clk-si514.c +++ b/drivers/clk/clk-si514.c @@ -74,6 +74,33 @@ static int si514_enable_output(struct clk_si514 *data, bool enable) SI514_CONTROL_OE, enable ? SI514_CONTROL_OE : 0); } +static int si514_prepare(struct clk_hw *hw) +{ + struct clk_si514 *data = to_clk_si514(hw); + + return si514_enable_output(data, true); +} + +static void si514_unprepare(struct clk_hw *hw) +{ + struct clk_si514 *data = to_clk_si514(hw); + + si514_enable_output(data, false); +} + +static int si514_is_prepared(struct clk_hw *hw) +{ + struct clk_si514 *data = to_clk_si514(hw); + unsigned int val; + int err; + + err = regmap_read(data->regmap, SI514_REG_CONTROL, &val); + if (err < 0) + return err; + + return !!(val & SI514_CONTROL_OE); +} + /* Retrieve clock multiplier and dividers from hardware */ static int si514_get_muldiv(struct clk_si514 *data, struct clk_si514_muldiv *settings) @@ -235,12 +262,17 @@ static int si514_set_rate(struct clk_hw *hw, unsigned long rate, { struct clk_si514 *data = to_clk_si514(hw); struct clk_si514_muldiv settings; + unsigned int old_oe_state; int err; err = si514_calc_muldiv(&settings, rate); if (err) return err; + err = regmap_read(data->regmap, SI514_REG_CONTROL, &old_oe_state); + if (err) + return err; + si514_enable_output(data, false); err = si514_set_muldiv(data, &settings); @@ -255,12 +287,16 @@ static int si514_set_rate(struct clk_hw *hw, unsigned long rate, /* Applying a new frequency can take up to 10ms */ usleep_range(10000, 12000); - si514_enable_output(data, true); + if (old_oe_state & SI514_CONTROL_OE) + si514_enable_output(data, true); return err; } static const struct clk_ops si514_clk_ops = { + .prepare = si514_prepare, + .unprepare = si514_unprepare, + .is_prepared = si514_is_prepared, .recalc_rate = si514_recalc_rate, .round_rate = si514_round_rate, .set_rate = si514_set_rate, diff --git a/drivers/clk/clk-si544.c b/drivers/clk/clk-si544.c index 1e2a3b8f9454..64e607f3232a 100644 --- a/drivers/clk/clk-si544.c +++ b/drivers/clk/clk-si544.c @@ -86,6 +86,33 @@ static int si544_enable_output(struct clk_si544 *data, bool enable) SI544_OE_STATE_ODC_OE, enable ? SI544_OE_STATE_ODC_OE : 0); } +static int si544_prepare(struct clk_hw *hw) +{ + struct clk_si544 *data = to_clk_si544(hw); + + return si544_enable_output(data, true); +} + +static void si544_unprepare(struct clk_hw *hw) +{ + struct clk_si544 *data = to_clk_si544(hw); + + si544_enable_output(data, false); +} + +static int si544_is_prepared(struct clk_hw *hw) +{ + struct clk_si544 *data = to_clk_si544(hw); + unsigned int val; + int err; + + err = regmap_read(data->regmap, SI544_REG_OE_STATE, &val); + if (err < 0) + return err; + + return !!(val & SI544_OE_STATE_ODC_OE); +} + /* Retrieve clock multiplier and dividers from hardware */ static int si544_get_muldiv(struct clk_si544 *data, struct clk_si544_muldiv *settings) @@ -273,6 +300,7 @@ static int si544_set_rate(struct clk_hw *hw, unsigned long rate, { struct clk_si544 *data = to_clk_si544(hw); struct clk_si544_muldiv settings; + unsigned int old_oe_state; int err; if (!is_valid_frequency(data, rate)) @@ -282,6 +310,10 @@ static int si544_set_rate(struct clk_hw *hw, unsigned long rate, if (err) return err; + err = regmap_read(data->regmap, SI544_REG_OE_STATE, &old_oe_state); + if (err) + return err; + si544_enable_output(data, false); /* Allow FCAL for this frequency update */ @@ -303,12 +335,16 @@ static int si544_set_rate(struct clk_hw *hw, unsigned long rate, /* Applying a new frequency can take up to 10ms */ usleep_range(10000, 12000); - si544_enable_output(data, true); + if (old_oe_state & SI544_OE_STATE_ODC_OE) + si544_enable_output(data, true); return err; } static const struct clk_ops si544_clk_ops = { + .prepare = si544_prepare, + .unprepare = si544_unprepare, + .is_prepared = si544_is_prepared, .recalc_rate = si544_recalc_rate, .round_rate = si544_round_rate, .set_rate = si544_set_rate, diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index b0a2719d86f3..e108f591d84a 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -692,6 +692,9 @@ static void clk_core_unprepare(struct clk_core *core) "Unpreparing critical %s\n", core->name)) return; + if (core->flags & CLK_SET_RATE_GATE) + clk_core_rate_unprotect(core); + if (--core->prepare_count > 0) return; @@ -766,6 +769,16 @@ static int clk_core_prepare(struct clk_core *core) core->prepare_count++; + /* + * CLK_SET_RATE_GATE is a special case of clock protection + * Instead of a consumer claiming exclusive rate control, it is + * actually the provider which prevents any consumer from making any + * operation which could result in a rate change or rate glitch while + * the clock is prepared. + */ + if (core->flags & CLK_SET_RATE_GATE) + clk_core_rate_protect(core); + return 0; unprepare: clk_core_unprepare(core->parent); @@ -1889,9 +1902,6 @@ static int clk_core_set_rate_nolock(struct clk_core *core, if (clk_core_rate_is_protected(core)) return -EBUSY; - if ((core->flags & CLK_SET_RATE_GATE) && core->prepare_count) - return -EBUSY; - /* calculate new rates and get the topmost changed clock */ top = clk_calc_new_rates(core, req_rate); if (!top) diff --git a/drivers/clk/imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c index ba563ba50b40..d3f7f4db80af 100644 --- a/drivers/clk/imx/clk-imx6ul.c +++ b/drivers/clk/imx/clk-imx6ul.c @@ -79,12 +79,6 @@ static const char *cko_sels[] = { "cko1", "cko2", }; static struct clk *clks[IMX6UL_CLK_END]; static struct clk_onecell_data clk_data; -static int const clks_init_on[] __initconst = { - IMX6UL_CLK_AIPSTZ1, IMX6UL_CLK_AIPSTZ2, - IMX6UL_CLK_AXI, IMX6UL_CLK_ARM, IMX6UL_CLK_ROM, - IMX6UL_CLK_MMDC_P0_FAST, IMX6UL_CLK_MMDC_P0_IPG, -}; - static const struct clk_div_table clk_enet_ref_table[] = { { .val = 0, .div = 20, }, { .val = 1, .div = 10, }, @@ -129,7 +123,6 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) { struct device_node *np; void __iomem *base; - int i; clks[IMX6UL_CLK_DUMMY] = imx_clk_fixed("dummy", 0); @@ -336,8 +329,8 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clks[IMX6UL_CLK_AHB] = imx_clk_busy_divider("ahb", "periph", base + 0x14, 10, 3, base + 0x48, 1); /* CCGR0 */ - clks[IMX6UL_CLK_AIPSTZ1] = imx_clk_gate2("aips_tz1", "ahb", base + 0x68, 0); - clks[IMX6UL_CLK_AIPSTZ2] = imx_clk_gate2("aips_tz2", "ahb", base + 0x68, 2); + clks[IMX6UL_CLK_AIPSTZ1] = imx_clk_gate2_flags("aips_tz1", "ahb", base + 0x68, 0, CLK_IS_CRITICAL); + clks[IMX6UL_CLK_AIPSTZ2] = imx_clk_gate2_flags("aips_tz2", "ahb", base + 0x68, 2, CLK_IS_CRITICAL); clks[IMX6UL_CLK_APBHDMA] = imx_clk_gate2("apbh_dma", "bch_podf", base + 0x68, 4); clks[IMX6UL_CLK_ASRC_IPG] = imx_clk_gate2_shared("asrc_ipg", "ahb", base + 0x68, 6, &share_count_asrc); clks[IMX6UL_CLK_ASRC_MEM] = imx_clk_gate2_shared("asrc_mem", "ahb", base + 0x68, 6, &share_count_asrc); @@ -360,6 +353,7 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clks[IMX6UL_CLK_UART2_SERIAL] = imx_clk_gate2("uart2_serial", "uart_podf", base + 0x68, 28); if (clk_on_imx6ull()) clks[IMX6UL_CLK_AIPSTZ3] = imx_clk_gate2("aips_tz3", "ahb", base + 0x80, 18); + clks[IMX6UL_CLK_GPIO2] = imx_clk_gate2("gpio2", "ipg", base + 0x68, 30); /* CCGR1 */ clks[IMX6UL_CLK_ECSPI1] = imx_clk_gate2("ecspi1", "ecspi_podf", base + 0x6c, 0); @@ -376,6 +370,8 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clks[IMX6UL_CLK_GPT1_SERIAL] = imx_clk_gate2("gpt1_serial", "perclk", base + 0x6c, 22); clks[IMX6UL_CLK_UART4_IPG] = imx_clk_gate2("uart4_ipg", "ipg", base + 0x6c, 24); clks[IMX6UL_CLK_UART4_SERIAL] = imx_clk_gate2("uart4_serial", "uart_podf", base + 0x6c, 24); + clks[IMX6UL_CLK_GPIO1] = imx_clk_gate2("gpio1", "ipg", base + 0x6c, 26); + clks[IMX6UL_CLK_GPIO5] = imx_clk_gate2("gpio5", "ipg", base + 0x6c, 30); /* CCGR2 */ if (clk_on_imx6ull()) { @@ -389,6 +385,7 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clks[IMX6UL_CLK_I2C3] = imx_clk_gate2("i2c3", "perclk", base + 0x70, 10); clks[IMX6UL_CLK_OCOTP] = imx_clk_gate2("ocotp", "ipg", base + 0x70, 12); clks[IMX6UL_CLK_IOMUXC] = imx_clk_gate2("iomuxc", "lcdif_podf", base + 0x70, 14); + clks[IMX6UL_CLK_GPIO3] = imx_clk_gate2("gpio3", "ipg", base + 0x70, 26); clks[IMX6UL_CLK_LCDIF_APB] = imx_clk_gate2("lcdif_apb", "axi", base + 0x70, 28); clks[IMX6UL_CLK_PXP] = imx_clk_gate2("pxp", "axi", base + 0x70, 30); @@ -405,11 +402,12 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clks[IMX6UL_CLK_UART6_IPG] = imx_clk_gate2("uart6_ipg", "ipg", base + 0x74, 6); clks[IMX6UL_CLK_UART6_SERIAL] = imx_clk_gate2("uart6_serial", "uart_podf", base + 0x74, 6); clks[IMX6UL_CLK_LCDIF_PIX] = imx_clk_gate2("lcdif_pix", "lcdif_podf", base + 0x74, 10); + clks[IMX6UL_CLK_GPIO4] = imx_clk_gate2("gpio4", "ipg", base + 0x74, 12); clks[IMX6UL_CLK_QSPI] = imx_clk_gate2("qspi1", "qspi1_podf", base + 0x74, 14); clks[IMX6UL_CLK_WDOG1] = imx_clk_gate2("wdog1", "ipg", base + 0x74, 16); - clks[IMX6UL_CLK_MMDC_P0_FAST] = imx_clk_gate("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20); - clks[IMX6UL_CLK_MMDC_P0_IPG] = imx_clk_gate2("mmdc_p0_ipg", "ipg", base + 0x74, 24); - clks[IMX6UL_CLK_AXI] = imx_clk_gate("axi", "axi_podf", base + 0x74, 28); + clks[IMX6UL_CLK_MMDC_P0_FAST] = imx_clk_gate_flags("mmdc_p0_fast", "mmdc_podf", base + 0x74, 20, CLK_IS_CRITICAL); + clks[IMX6UL_CLK_MMDC_P0_IPG] = imx_clk_gate2_flags("mmdc_p0_ipg", "ipg", base + 0x74, 24, CLK_IS_CRITICAL); + clks[IMX6UL_CLK_AXI] = imx_clk_gate_flags("axi", "axi_podf", base + 0x74, 28, CLK_IS_CRITICAL); /* CCGR4 */ clks[IMX6UL_CLK_PER_BCH] = imx_clk_gate2("per_bch", "bch_podf", base + 0x78, 12); @@ -423,7 +421,7 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clks[IMX6UL_CLK_GPMI_APB] = imx_clk_gate2("gpmi_apb", "bch_podf", base + 0x78, 30); /* CCGR5 */ - clks[IMX6UL_CLK_ROM] = imx_clk_gate2("rom", "ahb", base + 0x7c, 0); + clks[IMX6UL_CLK_ROM] = imx_clk_gate2_flags("rom", "ahb", base + 0x7c, 0, CLK_IS_CRITICAL); clks[IMX6UL_CLK_SDMA] = imx_clk_gate2("sdma", "ahb", base + 0x7c, 6); clks[IMX6UL_CLK_KPP] = imx_clk_gate2("kpp", "ipg", base + 0x7c, 8); clks[IMX6UL_CLK_WDOG2] = imx_clk_gate2("wdog2", "ipg", base + 0x7c, 10); @@ -497,10 +495,6 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clk_set_rate(clks[IMX6UL_CLK_ENET2_REF], 50000000); clk_set_rate(clks[IMX6UL_CLK_CSI], 24000000); - /* keep all the clks on just for bringup */ - for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) - clk_prepare_enable(clks[clks_init_on[i]]); - if (clk_on_imx6ull()) clk_prepare_enable(clks[IMX6UL_CLK_AIPSTZ3]); diff --git a/drivers/clk/qcom/gcc-ipq806x.c b/drivers/clk/qcom/gcc-ipq806x.c index 28eb200d0f1e..5f61225657ab 100644 --- a/drivers/clk/qcom/gcc-ipq806x.c +++ b/drivers/clk/qcom/gcc-ipq806x.c @@ -1220,7 +1220,6 @@ static struct clk_rcg sdc1_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; @@ -1269,7 +1268,6 @@ static struct clk_rcg sdc3_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; @@ -1353,7 +1351,6 @@ static struct clk_rcg tsif_ref_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; diff --git a/drivers/clk/qcom/gcc-mdm9615.c b/drivers/clk/qcom/gcc-mdm9615.c index b99dd406e907..849046fbed6d 100644 --- a/drivers/clk/qcom/gcc-mdm9615.c +++ b/drivers/clk/qcom/gcc-mdm9615.c @@ -947,7 +947,6 @@ static struct clk_rcg sdc1_src = { .parent_names = gcc_cxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; @@ -996,7 +995,6 @@ static struct clk_rcg sdc2_src = { .parent_names = gcc_cxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; diff --git a/drivers/clk/qcom/gcc-msm8660.c b/drivers/clk/qcom/gcc-msm8660.c index c347a0d44bc8..7e930e25c79f 100644 --- a/drivers/clk/qcom/gcc-msm8660.c +++ b/drivers/clk/qcom/gcc-msm8660.c @@ -1558,7 +1558,6 @@ static struct clk_rcg sdc1_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; @@ -1607,7 +1606,6 @@ static struct clk_rcg sdc2_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; @@ -1656,7 +1654,6 @@ static struct clk_rcg sdc3_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; @@ -1705,7 +1702,6 @@ static struct clk_rcg sdc4_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; @@ -1754,7 +1750,6 @@ static struct clk_rcg sdc5_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; diff --git a/drivers/clk/qcom/gcc-msm8960.c b/drivers/clk/qcom/gcc-msm8960.c index eb551c75fba6..fd495e0471bb 100644 --- a/drivers/clk/qcom/gcc-msm8960.c +++ b/drivers/clk/qcom/gcc-msm8960.c @@ -1628,7 +1628,6 @@ static struct clk_rcg sdc1_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; @@ -1677,7 +1676,6 @@ static struct clk_rcg sdc2_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; @@ -1726,7 +1724,6 @@ static struct clk_rcg sdc3_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; @@ -1775,7 +1772,6 @@ static struct clk_rcg sdc4_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; @@ -1824,7 +1820,6 @@ static struct clk_rcg sdc5_src = { .parent_names = gcc_pxo_pll8, .num_parents = 2, .ops = &clk_rcg_ops, - .flags = CLK_SET_RATE_GATE, }, } }; diff --git a/include/dt-bindings/clock/imx6ul-clock.h b/include/dt-bindings/clock/imx6ul-clock.h index 9564597cbfac..f8e0476a3a0e 100644 --- a/include/dt-bindings/clock/imx6ul-clock.h +++ b/include/dt-bindings/clock/imx6ul-clock.h @@ -235,27 +235,31 @@ #define IMX6UL_CLK_CSI_PODF 222 #define IMX6UL_CLK_PLL3_120M 223 #define IMX6UL_CLK_KPP 224 -#define IMX6UL_CLK_CKO1_SEL 225 -#define IMX6UL_CLK_CKO1_PODF 226 -#define IMX6UL_CLK_CKO1 227 -#define IMX6UL_CLK_CKO2_SEL 228 -#define IMX6UL_CLK_CKO2_PODF 229 -#define IMX6UL_CLK_CKO2 230 -#define IMX6UL_CLK_CKO 231 +#define IMX6ULL_CLK_ESAI_PRED 225 +#define IMX6ULL_CLK_ESAI_PODF 226 +#define IMX6ULL_CLK_ESAI_EXTAL 227 +#define IMX6ULL_CLK_ESAI_MEM 228 +#define IMX6ULL_CLK_ESAI_IPG 229 +#define IMX6ULL_CLK_DCP_CLK 230 +#define IMX6ULL_CLK_EPDC_PRE_SEL 231 +#define IMX6ULL_CLK_EPDC_SEL 232 +#define IMX6ULL_CLK_EPDC_PODF 233 +#define IMX6ULL_CLK_EPDC_ACLK 234 +#define IMX6ULL_CLK_EPDC_PIX 235 +#define IMX6ULL_CLK_ESAI_SEL 236 +#define IMX6UL_CLK_CKO1_SEL 237 +#define IMX6UL_CLK_CKO1_PODF 238 +#define IMX6UL_CLK_CKO1 239 +#define IMX6UL_CLK_CKO2_SEL 240 +#define IMX6UL_CLK_CKO2_PODF 241 +#define IMX6UL_CLK_CKO2 242 +#define IMX6UL_CLK_CKO 243 +#define IMX6UL_CLK_GPIO1 244 +#define IMX6UL_CLK_GPIO2 245 +#define IMX6UL_CLK_GPIO3 246 +#define IMX6UL_CLK_GPIO4 247 +#define IMX6UL_CLK_GPIO5 248 -/* For i.MX6ULL */ -#define IMX6ULL_CLK_ESAI_PRED 232 -#define IMX6ULL_CLK_ESAI_PODF 233 -#define IMX6ULL_CLK_ESAI_EXTAL 234 -#define IMX6ULL_CLK_ESAI_MEM 235 -#define IMX6ULL_CLK_ESAI_IPG 236 -#define IMX6ULL_CLK_DCP_CLK 237 -#define IMX6ULL_CLK_EPDC_PRE_SEL 238 -#define IMX6ULL_CLK_EPDC_SEL 239 -#define IMX6ULL_CLK_EPDC_PODF 240 -#define IMX6ULL_CLK_EPDC_ACLK 241 -#define IMX6ULL_CLK_EPDC_PIX 242 -#define IMX6ULL_CLK_ESAI_SEL 243 -#define IMX6UL_CLK_END 244 +#define IMX6UL_CLK_END 249 #endif /* __DT_BINDINGS_CLOCK_IMX6UL_H */ |