qcom audio clock control drivers
v2 cover qcom audio clock control drivers
This patchset adds support for the low power audio subsystem (LPASS) clock controller hardware. I split out the #define patch for IPQ so that it can go through the clock tree and the arm-soc tree in parallel if desired. New in this version is the msm8960/apq8064 support.
Change since v1:
* Renamed clk-cdiv to clk-regmap-divider
* Added msm8960/apq8064 support
* Split out dividers and branches to check for halt bits
Josh Cartwright (1):
clk: qcom: Add support for regmap divider clocks
Rajendra Nayak (3):
dt-bindings: Add #defines for IPQ806x lpass clock control
clk: qcom: Add IPQ806X LPASS clock controller (LCC) driver
devicetree: bindings: Document qcom,lcc
Stephen Boyd (4):
clk: Add __clk_mux_determine_rate_closest
clk: divider: Make generic for usage elsewhere
clk: qcom: Add simple regmap based muxes
clk: qcom: Add MSM8960/APQ8064 LPASS clock controller (LCC) driver
.../devicetree/bindings/clock/qcom,lcc.txt | 21 + drivers/clk/clk-divider.c | 195 ++++--- drivers/clk/clk.c | 47 +- drivers/clk/qcom/Kconfig | 18 + drivers/clk/qcom/Makefile | 4 + drivers/clk/qcom/clk-regmap-divider.c | 70 +++ drivers/clk/qcom/clk-regmap-divider.h | 29 + drivers/clk/qcom/clk-regmap-mux.c | 59 +++ drivers/clk/qcom/clk-regmap-mux.h | 29 + drivers/clk/qcom/gcc-ipq806x.c | 12 + drivers/clk/qcom/lcc-ipq806x.c | 473 +++++++++++++++++ drivers/clk/qcom/lcc-msm8960.c | 585 +++++++++++++++++++++ include/dt-bindings/clock/qcom,gcc-ipq806x.h | 1 - include/dt-bindings/clock/qcom,lcc-ipq806x.h | 30 ++ include/dt-bindings/clock/qcom,lcc-msm8960.h | 50 ++ include/linux/clk-provider.h | 20 +- 16 files changed, 1555 insertions(+), 88 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/qcom,lcc.txt create mode 100644 drivers/clk/qcom/clk-regmap-divider.c create mode 100644 drivers/clk/qcom/clk-regmap-divider.h create mode 100644 drivers/clk/qcom/clk-regmap-mux.c create mode 100644 drivers/clk/qcom/clk-regmap-mux.h create mode 100644 drivers/clk/qcom/lcc-ipq806x.c create mode 100644 drivers/clk/qcom/lcc-msm8960.c create mode 100644 include/dt-bindings/clock/qcom,lcc-ipq806x.h create mode 100644 include/dt-bindings/clock/qcom,lcc-msm8960.h
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH v2 1/8 clk: Add __clk_mux_determine_rate_closest
Some clock drivers want to find the closest rate on the input of a mux instead of a rate that's less than or equal to the desired rate. Add a generic mux function to support this.
--- drivers/clk/clk.c | 47 +++++++++++++++++++++++++++++++++++--------- include/linux/clk-provider.h | 9 +++++++-- 2 files changed, 45 insertions(+), 11 deletions(-)
drivers/clk/clk.c +38 -9
@@ -700,14 +700,20 @@ struct clk *__clk_lookup(const char *name)return NULL ; } -/* -* Helper for finding best parent to provide a given frequency. This can be used -* directly as a determine_rate callback (e.g. for a mux), or from a more -* complex clock that may combine a mux with other operations. -*/ -long __clk_mux_determine_rate (struct clk_hw *hw,unsigned long rate, -unsigned long *best_parent_rate, -struct clk **best_parent_p) +static bool mux_is_better_rate (unsigned long rate,unsigned long now, +unsigned long best,unsigned long flags) +{ +if (flags &CLK_MUX_ROUND_CLOSEST ) +return abs (now - rate) <abs (best - rate); + +return now <= rate && now > best; +} + +static long +clk_mux_determine_rate_flags (struct clk_hw *hw,unsigned long rate, +unsigned long *best_parent_rate, +struct clk **best_parent_p, +unsigned long flags) {struct clk *clk = hw->clk, *parent, *best_parent =NULL ;int i, num_parents;
@@ -735,7 +741,7 @@ long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate, parent_rate =__clk_round_rate (parent, rate); else parent_rate =__clk_get_rate (parent); -if (parent_rate <= rate && parent_rate > best) { +if (mux_is_better_rate (rate, parent_rate, best, flags)) { best_parent = parent; best = parent_rate; }
@@ -748,8 +754,31 @@ out:return best; } + +/* +* Helper for finding best parent to provide a given frequency. This can be used +* directly as a determine_rate callback (e.g. for a mux), or from a more +* complex clock that may combine a mux with other operations. +*/ +long __clk_mux_determine_rate (struct clk_hw *hw,unsigned long rate, +unsigned long *best_parent_rate, +struct clk **best_parent_p) +{ +return clk_mux_determine_rate_flags (hw, rate, best_parent_rate, + best_parent_p,0 ); +}EXPORT_SYMBOL_GPL (__clk_mux_determine_rate); +long __clk_mux_determine_rate_closest (struct clk_hw *hw,unsigned long rate, +unsigned long *best_parent_rate, +struct clk **best_parent_p) +{ +return clk_mux_determine_rate_flags (hw, rate, best_parent_rate, + best_parent_p, +CLK_MUX_ROUND_CLOSEST ); +} +EXPORT_SYMBOL_GPL (__clk_mux_determine_rate_closest); +/*** clk api ***/ void __clk_unprepare (struct clk *clk)
include/linux/clk-provider.h +7 -2
@@ -383,6 +383,8 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name,* register, and mask of mux bits are in higher 16-bit of this register. * While setting the mux bits, higher 16-bit should also be updated to * indicate changing mux bits. +* CLK_MUX_ROUND_CLOSEST - Use the parent rate that is closest to the desired +* frequency. */ struct clk_mux {struct clk_hw hw;
@@ -397,7 +399,8 @@ struct clk_mux {#define CLK_MUX_INDEX_ONE BIT(0)#define CLK_MUX_INDEX_BIT BIT(1)#define CLK_MUX_HIWORD_MASK BIT(2) -#define CLK_MUX_READ_ONLY BIT(3)/* mux setting cannot be changed */ +#define CLK_MUX_READ_ONLY BIT(3)/* mux can't be changed */ +#define CLK_MUX_ROUND_CLOSEST BIT(4)extern const struct clk_ops clk_mux_ops;extern const struct clk_ops clk_mux_ro_ops;
@@ -555,7 +558,9 @@ struct clk *__clk_lookup(const char *name);long __clk_mux_determine_rate (struct clk_hw *hw,unsigned long rate,unsigned long *best_parent_rate,struct clk **best_parent_p); - +long __clk_mux_determine_rate_closest (struct clk_hw *hw,unsigned long rate, +unsigned long *best_parent_rate, +struct clk **best_parent_p);/* * FIXME clock api without lock protection */
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH v2 2/8 clk: divider: Make generic for usage elsewhere
In reply to Stephen BoydSome devices don't use mmio to interact with dividers. Split out the logic from the register read/write parts so that we can reuse the division logic elsewhere.
--- drivers/clk/clk-divider.c | 195 ++++++++++++++++++++++++++----------------- include/linux/clk-provider.h | 11 +++ 2 files changed, 130 insertions(+), 76 deletions(-)
drivers/clk/clk-divider.c +119 -76
@@ -30,7 +30,7 @@#define to_clk_divider (_hw) container_of(_hw, struct clk_divider, hw) -#define div_mask (d) ((1 << ((d)->width)) - 1) +#define div_mask (width) (BIT(width) - 1)static unsigned int _get_table_maxdiv (const struct clk_div_table *table) {
@@ -54,15 +54,16 @@ static unsigned int _get_table_mindiv(const struct clk_div_table *table)return mindiv; } -static unsigned int _get_maxdiv (struct clk_divider *divider) +static unsigned int _get_maxdiv (const struct clk_div_table *table,u8 width, +unsigned long flags) { -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 ; +if (flags &CLK_DIVIDER_ONE_BASED ) +return div_mask (width); +if (flags &CLK_DIVIDER_POWER_OF_TWO ) +return 1 <<div_mask (width); +if (table) +return _get_table_maxdiv (table); +return div_mask (width) +1 ; } static unsigned int _get_table_div(const struct clk_div_table *table,
@@ -76,14 +77,15 @@ static unsigned int _get_table_div(const struct clk_div_table *table,return 0 ; } -static unsigned int _get_div (struct clk_divider *divider,unsigned int val) +static unsigned int _get_div (const struct clk_div_table *table, +unsigned int val,unsigned long flags) { -if (divider->flags &CLK_DIVIDER_ONE_BASED ) +if (flags &CLK_DIVIDER_ONE_BASED )return val; -if (divider->flags &CLK_DIVIDER_POWER_OF_TWO ) +if (flags &CLK_DIVIDER_POWER_OF_TWO )return 1 << val; -if (divider->table) -return _get_table_div (divider->table, val); +if (table) +return _get_table_div (table, val);return val +1 ; }
@@ -98,29 +100,28 @@ static unsigned int _get_table_val(const struct clk_div_table *table,return 0 ; } -static unsigned int _get_val (struct clk_divider *divider,unsigned int div) +static unsigned int _get_val (const struct clk_div_table *table, +unsigned int div,unsigned long flags) { -if (divider->flags &CLK_DIVIDER_ONE_BASED ) +if (flags &CLK_DIVIDER_ONE_BASED )return div; -if (divider->flags &CLK_DIVIDER_POWER_OF_TWO ) +if (flags &CLK_DIVIDER_POWER_OF_TWO )return __ffs (div); -if (divider->table) -return _get_table_val (divider->table, div); +if (table) +return _get_table_val (table, div);return div -1 ; } -static unsigned long clk_divider_recalc_rate (struct clk_hw *hw, -unsigned long parent_rate) +unsigned long divider_recalc_rate (struct clk_hw *hw,unsigned long parent_rate, +unsigned int val, +const struct clk_div_table *table, +unsigned long flags) { -struct clk_divider *divider =to_clk_divider (hw); -unsigned int div, val; - - val =clk_readl (divider->reg) >> divider->shift; - val &=div_mask (divider); +unsigned int div; - div =_get_div (divider, val); + div =_get_div (table, val, flags);if (!div) { -WARN (!(divider->flags &CLK_DIVIDER_ALLOW_ZERO ), +WARN (!(flags &CLK_DIVIDER_ALLOW_ZERO ),"%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n" ,__clk_get_name (hw->clk));return parent_rate;
@@ -128,6 +129,20 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,return DIV_ROUND_UP (parent_rate, div); } +EXPORT_SYMBOL_GPL (divider_recalc_rate); + +static unsigned long clk_divider_recalc_rate (struct clk_hw *hw, +unsigned long parent_rate) +{ +struct clk_divider *divider =to_clk_divider (hw); +unsigned int val; + + val =clk_readl (divider->reg) >> divider->shift; + val &=div_mask (divider->width); + +return divider_recalc_rate (hw, parent_rate, val, divider->table, + divider->flags); +}/* * The reverse of DIV_ROUND_UP: The maximum number which
@@ -146,12 +161,13 @@ static bool _is_valid_table_div(const struct clk_div_table *table,return false; } -static bool _is_valid_div (struct clk_divider *divider,unsigned int div) +static bool _is_valid_div (const struct clk_div_table *table,unsigned int div, +unsigned long flags) { -if (divider->flags &CLK_DIVIDER_POWER_OF_TWO ) +if (flags &CLK_DIVIDER_POWER_OF_TWO )return is_power_of_2 (div); -if (divider->table) -return _is_valid_table_div (divider->table, div); +if (table) +return _is_valid_table_div (table, div);return true; }
@@ -191,71 +207,76 @@ static int _round_down_table(const struct clk_div_table *table, int div)return down; } -static int _div_round_up (struct clk_divider *divider, -unsigned long parent_rate,unsigned long rate) +static int _div_round_up (const struct clk_div_table *table, +unsigned long parent_rate,unsigned long rate, +unsigned long flags) {int div =DIV_ROUND_UP (parent_rate, rate); -if (divider->flags &CLK_DIVIDER_POWER_OF_TWO ) +if (flags &CLK_DIVIDER_POWER_OF_TWO ) div =__roundup_pow_of_two (div); -if (divider->table) - div =_round_up_table (divider->table, div); +if (table) + div =_round_up_table (table, div);return div; } -static int _div_round_closest (struct clk_divider *divider, -unsigned long parent_rate,unsigned long rate) +static int _div_round_closest (const struct clk_div_table *table, +unsigned long parent_rate,unsigned long rate, +unsigned long flags) {int up, down, div; up = down = div =DIV_ROUND_CLOSEST (parent_rate, rate); -if (divider->flags &CLK_DIVIDER_POWER_OF_TWO ) { +if (flags &CLK_DIVIDER_POWER_OF_TWO ) { up =__roundup_pow_of_two (div); down =__rounddown_pow_of_two (div); - }else if (divider->table) { - up =_round_up_table (divider->table, div); - down =_round_down_table (divider->table, div); + }else if (table) { + up =_round_up_table (table, div); + down =_round_down_table (table, div); }return (up - div) <= (div - down) ? up : down; } -static int _div_round (struct clk_divider *divider,unsigned long parent_rate, -unsigned long rate) +static int _div_round (const struct clk_div_table *table, +unsigned long parent_rate,unsigned long rate, +unsigned long flags) { -if (divider->flags &CLK_DIVIDER_ROUND_CLOSEST ) -return _div_round_closest (divider, parent_rate, rate); +if (flags &CLK_DIVIDER_ROUND_CLOSEST ) +return _div_round_closest (table, parent_rate, rate, flags); -return _div_round_up (divider, parent_rate, rate); +return _div_round_up (table, parent_rate, rate, flags); } -static bool _is_best_div (struct clk_divider *divider, -unsigned long rate,unsigned long now,unsigned long best) +static bool _is_best_div (unsigned long rate,unsigned long now, +unsigned long best,unsigned long flags) { -if (divider->flags &CLK_DIVIDER_ROUND_CLOSEST ) +if (flags &CLK_DIVIDER_ROUND_CLOSEST )return abs (rate - now) <abs (rate - best);return now <= rate && now > best; } -static int _next_div (struct clk_divider *divider,int div) +static int _next_div (const struct clk_div_table *table,int div, +unsigned long flags) { div++; -if (divider->flags &CLK_DIVIDER_POWER_OF_TWO ) +if (flags &CLK_DIVIDER_POWER_OF_TWO )return __roundup_pow_of_two (div); -if (divider->table) -return _round_up_table (divider->table, div); +if (table) +return _round_up_table (table, div);return div; }static int clk_divider_bestdiv (struct clk_hw *hw,unsigned long rate, -unsigned long *best_parent_rate) +unsigned long *best_parent_rate, +const struct clk_div_table *table,u8 width, +unsigned long flags) { -struct clk_divider *divider =to_clk_divider (hw);int i, bestdiv =0 ;unsigned long parent_rate, best =0 , now, maxdiv;unsigned long parent_rate_saved = *best_parent_rate;
@@ -263,11 +284,11 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,if (!rate) rate =1 ; - maxdiv =_get_maxdiv (divider); + maxdiv =_get_maxdiv (table, width, flags);if (!(__clk_get_flags (hw->clk) &CLK_SET_RATE_PARENT )) { parent_rate = *best_parent_rate; - bestdiv =_div_round (divider, parent_rate, rate); + bestdiv =_div_round (table, parent_rate, rate, flags); bestdiv = bestdiv ==0 ?1 : bestdiv; bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv;return bestdiv;
@@ -279,8 +300,8 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,*/ maxdiv =min (ULONG_MAX / rate, maxdiv); -for (i =1 ; i <= maxdiv; i =_next_div (divider, i)) { -if (!_is_valid_div (divider, i)) +for (i =1 ; i <= maxdiv; i =_next_div (table, i, flags)) { +if (!_is_valid_div (table, i, flags))continue ;if (rate * i == parent_rate_saved) {/*
@@ -294,7 +315,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, parent_rate =__clk_round_rate (__clk_get_parent (hw->clk),MULT_ROUND_UP (rate, i)); now =DIV_ROUND_UP (parent_rate, i); -if (_is_best_div (divider, rate, now, best)) { +if (_is_best_div (rate, now, best, flags)) { bestdiv = i; best = now; *best_parent_rate = parent_rate;
@@ -302,48 +323,70 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, }if (!bestdiv) { - bestdiv =_get_maxdiv (divider); + bestdiv =_get_maxdiv (table, width, flags); *best_parent_rate =__clk_round_rate (__clk_get_parent (hw->clk),1 ); }return bestdiv; } -static long clk_divider_round_rate (struct clk_hw *hw,unsigned long rate, -unsigned long *prate) +long divider_round_rate (struct clk_hw *hw,unsigned long rate, +unsigned long *prate,const struct clk_div_table *table, +u8 width,unsigned long flags) {int div; - div =clk_divider_bestdiv (hw, rate, prate); + + div =clk_divider_bestdiv (hw, rate, prate, table, width, flags);return DIV_ROUND_UP (*prate, div); } +EXPORT_SYMBOL_GPL (divider_round_rate); -static int clk_divider_set_rate (struct clk_hw *hw,unsigned long rate, -unsigned long parent_rate) +static long clk_divider_round_rate (struct clk_hw *hw,unsigned long rate, +unsigned long *prate) {struct clk_divider *divider =to_clk_divider (hw); + +return divider_round_rate (hw, rate, prate, divider->table, + divider->width, divider->flags); +} + +int divider_get_val (unsigned long rate,unsigned long parent_rate, +const struct clk_div_table *table,u8 width, +unsigned long flags) +{unsigned int div, value; -unsigned long flags =0 ; -u32 val; div =DIV_ROUND_UP (parent_rate, rate); -if (!_is_valid_div (divider, div)) +if (!_is_valid_div (table, div, flags))return -EINVAL ; - value =_get_val (divider, div); + value =_get_val (table, div, flags); + + return min_t(unsigned int, value, div_mask(width)); +} +EXPORT_SYMBOL_GPL (divider_get_val); + +static int clk_divider_set_rate (struct clk_hw *hw,unsigned long rate, +unsigned long parent_rate) +{ +struct clk_divider *divider =to_clk_divider (hw); +unsigned int value; +unsigned long flags =0 ; +u32 val; -if (value >div_mask (divider)) - value =div_mask (divider); + value =divider_get_val (rate, parent_rate, divider->table, + divider->width, divider->flags);if (divider->lock)spin_lock_irqsave (divider->lock, flags);if (divider->flags &CLK_DIVIDER_HIWORD_MASK ) { - val =div_mask (divider) << (divider->shift +16 ); + val =div_mask (divider->width) << (divider->shift +16 ); }else { val =clk_readl (divider->reg); - val &= ~(div_mask (divider) << divider->shift); + val &= ~(div_mask (divider->width) << divider->shift); } val |= value << divider->shift;clk_writel (val, divider->reg);
include/linux/clk-provider.h +11 -0
@@ -353,6 +353,17 @@ struct clk_divider {extern const struct clk_ops clk_divider_ops;extern const struct clk_ops clk_divider_ro_ops; + +unsigned long divider_recalc_rate (struct clk_hw *hw,unsigned long parent_rate, +unsigned int val,const struct clk_div_table *table, +unsigned long flags); +long divider_round_rate (struct clk_hw *hw,unsigned long rate, +unsigned long *prate,const struct clk_div_table *table, +u8 width,unsigned long flags); +int divider_get_val (unsigned long rate,unsigned long parent_rate, +const struct clk_div_table *table,u8 width, +unsigned long flags); + struct clk *clk_register_divider(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 shift, u8 width,
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH v2 3/8 clk: qcom: Add support for regmap divider clocks
In reply to Stephen BoydFrom: Josh Cartwright <[email protected]>
Add support for dividers that use regmap instead of readl/writel.
[sboyd at codeaurora.org: Switch to using generic divider code, drop enable/disable, reword commit text]
--- drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/clk-regmap-divider.c | 70 +++++++++++++++++++++++++++++++++++ drivers/clk/qcom/clk-regmap-divider.h | 29 +++++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 drivers/clk/qcom/clk-regmap-divider.c create mode 100644 drivers/clk/qcom/clk-regmap-divider.h
drivers/clk/qcom/Makefile +1 -0
@@ -6,6 +6,7 @@ clk-qcom-y += clk-pll.o clk-qcom-y += clk-rcg.o clk-qcom-y += clk-rcg2.o clk-qcom-y += clk-branch.o +clk-qcom-y += clk-regmap-divider.o clk-qcom-y += reset.o obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o
drivers/clk/qcom/clk-regmap-divider.c new file +70 -0
70 lines not on this page · raw message
drivers/clk/qcom/clk-regmap-divider.h new file +29 -0
@@ -0,0 +1,29 @@ +/* +* Copyright (c) 2014, The Linux Foundation. All rights reserved. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* 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. +*/ + +#ifndef __QCOM_CLK_REGMAP_DIVIDER_H__ +#define __QCOM_CLK_REGMAP_DIVIDER_H__ + +#include <linux/clk-provider.h> +#include "clk-regmap.h" + +struct clk_regmap_div { +u32 reg; +u32 shift; +u32 width; +struct clk_regmap clkr; +}; + +extern const struct clk_ops clk_regmap_div_ops; + +#endif
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH v2 4/8 clk: qcom: Add simple regmap based muxes
In reply to Stephen BoydAdd support for muxes that use regmap instead of readl/writel directly. We don't support as many features as clk-mux.c, but this is good enough to support getting and setting parents. Adding a table based lookup can be added in the future if needed.
--- drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/clk-regmap-mux.c | 59 +++++++++++++++++++++++++++++++++++++++ drivers/clk/qcom/clk-regmap-mux.h | 29 +++++++++++++++++++ 3 files changed, 89 insertions(+) create mode 100644 drivers/clk/qcom/clk-regmap-mux.c create mode 100644 drivers/clk/qcom/clk-regmap-mux.h
drivers/clk/qcom/Makefile +1 -0
@@ -7,6 +7,7 @@ clk-qcom-y += clk-rcg.o clk-qcom-y += clk-rcg2.o clk-qcom-y += clk-branch.o clk-qcom-y += clk-regmap-divider.o +clk-qcom-y += clk-regmap-mux.o clk-qcom-y += reset.o obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o
drivers/clk/qcom/clk-regmap-mux.c new file +59 -0
59 lines not on this page · raw message
drivers/clk/qcom/clk-regmap-mux.h new file +29 -0
@@ -0,0 +1,29 @@ +/* +* Copyright (c) 2014, The Linux Foundation. All rights reserved. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* 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. +*/ + +#ifndef __QCOM_CLK_REGMAP_MUX_H__ +#define __QCOM_CLK_REGMAP_MUX_H__ + +#include <linux/clk-provider.h> +#include "clk-regmap.h" + +struct clk_regmap_mux { +u32 reg; +u32 shift; +u32 width; +struct clk_regmap clkr; +}; + +extern const struct clk_ops clk_regmap_mux_closest_ops; + +#endif
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH v2 5/8 dt-bindings: Add #defines for IPQ806x lpass clock control
In reply to Stephen BoydFrom: Rajendra Nayak <[email protected]>
Add defines to make more human readable numbers for the lpass clock controller found on IPQ806x SoCs. Also remove the PLL4 define in gcc to avoid #define conflicts because that clock doesn't exist in gcc, instead it lives in lcc.
--- include/dt-bindings/clock/qcom,gcc-ipq806x.h | 1 - include/dt-bindings/clock/qcom,lcc-ipq806x.h | 30 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 include/dt-bindings/clock/qcom,lcc-ipq806x.h
include/dt-bindings/clock/qcom,gcc-ipq806x.h +0 -1
@@ -238,7 +238,6 @@#define PLL0_VOTE 221#define PLL3 222#define PLL3_VOTE 223 -#define PLL4 224#define PLL4_VOTE 225#define PLL8 226#define PLL8_VOTE 227
include/dt-bindings/clock/qcom,lcc-ipq806x.h new file +30 -0
@@ -0,0 +1,30 @@ +/* +* Copyright (c) 2014, The Linux Foundation. All rights reserved. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* 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. +*/ + +#ifndef _DT_BINDINGS_CLK_LCC_IPQ806X_H +#define _DT_BINDINGS_CLK_LCC_IPQ806X_H + +#define PLL4 0 +#define MI2S_OSR_SRC 1 +#define MI2S_OSR_CLK 2 +#define MI2S_DIV_CLK 3 +#define MI2S_BIT_DIV_CLK 4 +#define MI2S_BIT_CLK 5 +#define PCM_SRC 6 +#define PCM_CLK_OUT 7 +#define PCM_CLK 8 +#define SPDIF_SRC 9 +#define SPDIF_CLK 10 +#define AHBIX_CLK 11 + +#endif
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH v2 6/8 clk: qcom: Add IPQ806X LPASS clock controller (LCC) driver
In reply to Stephen BoydFrom: Rajendra Nayak <[email protected]>
Add an LCC driver for IPQ806x that supports the i2s, S/PDIF, and pcm clocks.
[sboyd at codeaurora.org: Reworded commit text, added Kconfig select, fleshed out Kconfig description a bit more, added pll4 configuration and reworked probe for it, added muxes, split out dt-binding file]
Change-Id: Idf4d008306a98d75d914c5625b46d15c6f7921b4
--- drivers/clk/qcom/Kconfig | 9 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/gcc-ipq806x.c | 12 ++ drivers/clk/qcom/lcc-ipq806x.c | 473 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 495 insertions(+) create mode 100644 drivers/clk/qcom/lcc-ipq806x.c
drivers/clk/qcom/Kconfig +9 -0
@@ -29,6 +29,15 @@ config IPQ_GCC_806X Say Y if you want to use peripheral devices such as UART, SPI, i2c, USB, SD/eMMC, etc. +config IPQ_LCC_806X + tristate "IPQ806x LPASS Clock Controller" + select IPQ_GCC_806X + depends on COMMON_CLK_QCOM + help + Support for the LPASS clock controller on ipq806x devices. + Say Y if you want to use audio devices such as i2s, pcm, + S/PDIF, etc. + config MSM_GCC_8660 tristate "MSM8660 Global Clock Controller" depends on COMMON_CLK_QCOM
drivers/clk/qcom/Makefile +1 -0
@@ -13,6 +13,7 @@ clk-qcom-y += reset.o obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o obj-$(CONFIG_IPQ_GCC_806X) += gcc-ipq806x.o +obj-$(CONFIG_IPQ_LCC_806X) += lcc-ipq806x.o obj-$(CONFIG_MSM_GCC_8660) += gcc-msm8660.o obj-$(CONFIG_MSM_GCC_8960) += gcc-msm8960.o obj-$(CONFIG_MSM_GCC_8974) += gcc-msm8974.o
drivers/clk/qcom/gcc-ipq806x.c +12 -0
@@ -75,6 +75,17 @@ static struct clk_pll pll3 = { }, }; +static struct clk_regmap pll4_vote = { + .enable_reg =0x34c0 , + .enable_mask =BIT (4 ), + .hw.init = &(struct clk_init_data ){ + .name ="pll4_vote" , + .parent_names = (const char *[]){"pll4" }, + .num_parents =1 , + .ops = &clk_pll_vote_ops, + }, +}; +static struct clk_pll pll8 = { .l_reg =0x3144 , .m_reg =0x3148 ,
@@ -2163,6 +2174,7 @@ static struct clk_regmap *gcc_ipq806x_clks[] = { [PLL0] = &pll0.clkr, [PLL0_VOTE] = &pll0_vote, [PLL3] = &pll3.clkr, + [PLL4_VOTE] = &pll4_vote, [PLL8] = &pll8.clkr, [PLL8_VOTE] = &pll8_vote, [PLL14] = &pll14.clkr,
drivers/clk/qcom/lcc-ipq806x.c new file +473 -0
473 lines not on this page · raw message
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
Re: [PATCH v2 6/8] clk: qcom: Add IPQ806X LPASS clock controller (LCC) driver
Quoted 4 lines · Stephen Boyd
(quoted diff) +4
-0+ +static struct clk_regmap_div mi2s_div_clk = { + .reg = 0x48, + .shift = 10,
Review
Quoted 10 lines
(quoted diff) +10
-0+ .width = 4, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "mi2s_div_clk", + .parent_names = lcc_mi2s_parents, + .num_parents = 1, + .ops = &clk_regmap_div_ops, + }, + }, +};
Oops this is wrong. Let's fold in this patch.
drivers/clk/qcom/lcc-ipq806x.c +1 -1
@@ -188,7 +188,7 @@ static struct clk_branch mi2s_bit_div_clk = { .enable_mask = BIT(15), .hw.init = &(struct clk_init_data ){ .name ="mi2s_bit_div_clk" , - .parent_names = lcc_mi2s_parents, + .parent_names = (const char *[]){"mi2s_div_clk" }, .num_parents =1 , .ops = &clk_branch_ops, .flags =CLK_SET_RATE_PARENT ,
Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH v2 7/8 clk: qcom: Add MSM8960/APQ8064 LPASS clock controller (LCC) driver
In reply to Stephen BoydAdd an LCC driver for IPQ806x that supports the i2s, slimbus, and pcm clocks.
--- drivers/clk/qcom/Kconfig | 9 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/lcc-msm8960.c | 585 +++++++++++++++++++++++++++ include/dt-bindings/clock/qcom,lcc-msm8960.h | 50 +++ 4 files changed, 645 insertions(+) create mode 100644 drivers/clk/qcom/lcc-msm8960.c create mode 100644 include/dt-bindings/clock/qcom,lcc-msm8960.h
drivers/clk/qcom/Kconfig +9 -0
@@ -54,6 +54,15 @@ config MSM_GCC_8960 Say Y if you want to use peripheral devices such as UART, SPI, i2c, USB, SD/eMMC, SATA, PCIe, etc. +config MSM_LCC_8960 + tristate "APQ8064/MSM8960 LPASS Clock Controller" + select MSM_GCC_8960 + depends on COMMON_CLK_QCOM + help + Support for the LPASS clock controller on apq8064/msm8960 devices. + Say Y if you want to use audio devices such as i2s, pcm, + SLIMBus, etc. + config MSM_MMCC_8960 tristate "MSM8960 Multimedia Clock Controller" select MSM_GCC_8960
drivers/clk/qcom/Makefile +1 -0
@@ -16,6 +16,7 @@ obj-$(CONFIG_IPQ_GCC_806X) += gcc-ipq806x.o obj-$(CONFIG_IPQ_LCC_806X) += lcc-ipq806x.o obj-$(CONFIG_MSM_GCC_8660) += gcc-msm8660.o obj-$(CONFIG_MSM_GCC_8960) += gcc-msm8960.o +obj-$(CONFIG_MSM_LCC_8960) += lcc-msm8960.o obj-$(CONFIG_MSM_GCC_8974) += gcc-msm8974.o obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o
drivers/clk/qcom/lcc-msm8960.c new file +585 -0
585 lines not on this page · raw message
include/dt-bindings/clock/qcom,lcc-msm8960.h new file +50 -0
50 lines not on this page · raw message
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
PATCH v2 8/8 devicetree: bindings: Document qcom,lcc
In reply to Stephen BoydFrom: Rajendra Nayak <[email protected]>
Document the LPASS (low power audio subsystem) clock controller found on Qualcomm devices.
--- .../devicetree/bindings/clock/qcom,lcc.txt | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/qcom,lcc.txt
Documentation/devicetree/bindings/clock/qcom,lcc.txt new file +21 -0
@@ -0,0 +1,21 @@ +Qualcomm LPASS Clock & Reset Controller Binding +------------------------------------------------ + +Required properties : +- compatible : shall contain only one of the following: + + "qcom,lcc-msm8960" + "qcom,lcc-apq8064" + "qcom,lcc-ipq8064" + +- reg : shall contain base register location and length +- #clock-cells : shall contain 1 +- #reset-cells : shall contain 1 + +Example: + clock-controller at 28000000 { + compatible = "qcom,lcc-ipq8064"; + reg = <0x28000000 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + };
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project