Message ID | 1399640410-30957-2-git-send-email-tushar.behera@linaro.org (mailing list archive) |
---|---|
State | Not Applicable, archived |
Headers | show |
On 05/09/2014 10:00 PM, Tushar Behera wrote: > All SoC in Exynos-series have a clock with name XCLKOUT to provide > debug information about various clocks available in the SoC. The register > controlling the MUX and GATE of this clock is provided within PMU domain. > Since PMU domain can't be dedicatedly mapped by every driver, the register > needs to be handled through a regmap handle provided by PMU syscon > controller. Right now, CCF doesn't allow regmap based MUX and GATE clocks, > hence a dedicated clock provider for XCLKOUT is added here. > > Signed-off-by: Tushar Behera <tushar.behera@linaro.org> > CC: Tomasz Figa <t.figa@samsung.com> > --- > drivers/clk/samsung/Makefile | 2 +- > drivers/clk/samsung/clk-out.c | 181 +++++++++++++++++++++++++++++++++++++++++ > drivers/clk/samsung/clk.h | 33 ++++++++ > 3 files changed, 215 insertions(+), 1 deletion(-) > create mode 100644 drivers/clk/samsung/clk-out.c > > diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile > index 8eb4799..d23ad4f 100644 > --- a/drivers/clk/samsung/Makefile > +++ b/drivers/clk/samsung/Makefile > @@ -2,7 +2,7 @@ > # Samsung Clock specific Makefile > # > > -obj-$(CONFIG_COMMON_CLK) += clk.o clk-pll.o > +obj-$(CONFIG_COMMON_CLK) += clk.o clk-pll.o clk-out.o > obj-$(CONFIG_ARCH_EXYNOS4) += clk-exynos4.o > obj-$(CONFIG_SOC_EXYNOS5250) += clk-exynos5250.o > obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5420.o > diff --git a/drivers/clk/samsung/clk-out.c b/drivers/clk/samsung/clk-out.c > new file mode 100644 > index 0000000..76489b6 > --- /dev/null > +++ b/drivers/clk/samsung/clk-out.c > @@ -0,0 +1,181 @@ > +/* > + * Copyright (c) 2014 Samsung Electronics Co., Ltd. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + * > + * This file contains the utility functions to register the clkout clocks. > +*/ > + > +/** > + * All SoC in Exynos-series have a clock with name XCLKOUT to provide > + * debug information about various clocks available in the SoC. The register > + * controlling the MUX and GATE of this clock is provided within PMU domain. > + * Since PMU domain can't be dedicatedly mapped every driver, the register > + * needs to be handled through a regmap handle provided by PMU syscon > + * controller. Right now, CCF doesn't allow regmap based MUX and GATE clocks, > + * hence a dedicated clock provider for XCLKOUT is added here. > + */ > + > +#include <linux/errno.h> > +#include <linux/mfd/syscon.h> > +#include <linux/regmap.h> > + > +#include "clk.h" > + > +/** > + * struct samsung_clkout_soc_data: SoC specific register details > + * @reg: Offset of CLKOUT register from PMU base how about naming this variable as "offset" instead of "reg". > + * @mux_shift: Start-bit of MUX bit-field > + * @mux_width: Width of MUX bit-field > + * @enable_bit: The bit corresponding to gating of this clock > + */ > +struct samsung_clkout_soc_data { > + unsigned int reg; > + u8 mux_shift; > + u8 mux_width; > + u8 enable_bit; > +}; > + > +/** > + * struct samsung_clkout: Structure to store driver specific clock context > + * @hw: Handle to CCF clock > + * @soc_data: SoC specific register details > + * @regmap: Regmap handle of the PMU > + */ > +struct samsung_clkout { > + struct clk_hw hw; > + const struct samsung_clkout_soc_data *soc_data; > + struct regmap *regmap; > +}; > + > +#define to_clk_out(_hw) container_of(_hw, struct samsung_clkout, hw) > + > +int samsung_clkout_enable(struct clk_hw *hw) > +{ > + struct samsung_clkout *clkout = to_clk_out(hw); > + const struct samsung_clkout_soc_data *soc_data = clkout->soc_data; > + unsigned int enable_mask = BIT(soc_data->enable_bit); > + > + /* clkout is enabled if enable bit is low */ > + regmap_update_bits(clkout->regmap, soc_data->reg, enable_mask, 0); > + > + return 0; > +} > + > +void samsung_clkout_disable(struct clk_hw *hw) > +{ > + struct samsung_clkout *clkout = to_clk_out(hw); > + const struct samsung_clkout_soc_data *soc_data = clkout->soc_data; > + unsigned int enable_mask = BIT(soc_data->enable_bit); > + > + /* clkout is gated if enable bit is high */ > + regmap_update_bits(clkout->regmap, soc_data->reg, > + enable_mask, enable_mask); > + > + return; > +} > + > +int samsung_clkout_set_parent(struct clk_hw *hw, u8 index) > +{ > + struct samsung_clkout *clkout = to_clk_out(hw); > + const struct samsung_clkout_soc_data *soc_data = clkout->soc_data; > + unsigned int parent_mask = BIT(soc_data->mux_width) - 1; > + > + regmap_update_bits(clkout->regmap, soc_data->reg, > + parent_mask << soc_data->mux_shift, > + index << soc_data->mux_shift); > + > + return 0; > +} > + > +u8 samsung_clkout_get_parent(struct clk_hw *hw) > +{ > + struct samsung_clkout *clkout = to_clk_out(hw); > + const struct samsung_clkout_soc_data *soc_data = clkout->soc_data; > + unsigned int parent_mask = BIT(soc_data->mux_width) - 1; > + unsigned int val; > + int ret; > + > + ret = regmap_read(clkout->regmap, soc_data->reg, &val); Do we really need to keep return value in "ret" as I can't see you are using it anywhere? > + > + return (val >> soc_data->mux_shift) & parent_mask; > +} > + > +static const struct clk_ops samsung_clkout_clk_ops = { > + .enable = samsung_clkout_enable, > + .disable = samsung_clkout_disable, > + .set_parent = samsung_clkout_set_parent, > + .get_parent = samsung_clkout_get_parent, > +}; > + > +static void __init _samsung_clk_register_clkout( > + struct samsung_out_clock *out, > + const struct samsung_clkout_soc_data *soc_data, > + struct regmap *regmap) > +{ > + struct samsung_clkout *clkout; > + struct clk *clk; > + struct clk_init_data init; > + int ret; > + > + clkout = kzalloc(sizeof(*clkout), GFP_KERNEL); > + if (!clkout) { > + pr_err("%s: could not allocate out clk %s\n", > + __func__, out->name); > + return; > + } > + > + init.name = out->name; > + init.parent_names = out->parent_names; > + init.num_parents = out->num_parents; > + init.ops = &samsung_clkout_clk_ops; > + > + clkout->hw.init = &init; > + clkout->regmap = regmap; > + clkout->soc_data = soc_data; > + > + clk = clk_register(NULL, &clkout->hw); > + if (IS_ERR(clk)) { > + pr_err("%s: failed to register out clock %s : %ld\n", > + __func__, out->name, PTR_ERR(clk)); > + kfree(clkout); > + return; > + } > + > + samsung_clk_add_lookup(clk, out->id); > + > + if (!out->alias) > + return; > + > + ret = clk_register_clkdev(clk, out->alias, out->dev_name); > + if (ret) > + pr_err("%s: failed to register lookup for %s : %d", > + __func__, out->name, ret); > +} > + > +/* All existing Exynos serial of SoCs have common values for this offsets. */ typo: serial/series/ > +static const struct samsung_clkout_soc_data exynos_clkout_soc_data = { > + .reg = 0xa00, > + .mux_shift = 8, > + .mux_width = 5, > + .enable_bit = 0, > +}; > + > +void __init samsung_clk_register_clkout(struct device_node *np, > + struct samsung_out_clock *out_clk_list, unsigned int nr_out_clk) > +{ > + int cnt; > + struct regmap *reg; > + const struct samsung_clkout_soc_data *priv = &exynos_clkout_soc_data; > + > + reg = syscon_early_regmap_lookup_by_phandle(np, "samsung,pmu-syscon"); > + if (IS_ERR(reg)) { > + pr_err("Failed to get pmu-syscon handle for clkout\n"); > + return; > + } > + > + for (cnt = 0; cnt < nr_out_clk; cnt++) > + _samsung_clk_register_clkout(&out_clk_list[cnt], priv, reg); > +} > diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h > index c7141ba..b4b2122 100644 > --- a/drivers/clk/samsung/clk.h > +++ b/drivers/clk/samsung/clk.h > @@ -312,6 +312,37 @@ struct samsung_pll_clock { > __PLL(_typ, _id, NULL, _name, _pname, CLK_GET_RATE_NOCACHE, \ > _lock, _con, _rtable, _alias) > > +/** > + * struct samsung_out_clock: information about CLKOUT clock > + * @id: platform specific id of the clock. > + * @dev_name: name of the device to which this clock belongs. > + * @name: name of this mux clock. > + * @parent_names: array of pointer to parent clock names. > + * @num_parents: number of parents listed in @parent_names. > + * @alias: optional clock alias name to be assigned to this clock. > + */ > +struct samsung_out_clock { > + unsigned int id; > + const char *dev_name; > + const char *name; > + const char **parent_names; > + unsigned int num_parents; > + const char *alias; > +}; > + > +#define __CLKOUT(_id, dname, cname, pnames, a) \ > + { \ > + .id = _id, \ > + .dev_name = dname, \ > + .name = cname, \ > + .parent_names = pnames, \ > + .num_parents = ARRAY_SIZE(pnames), \ > + .alias = a, \ > + } > + > +#define CLKOUT(_id, cname, pnames) \ > + __CLKOUT(_id, NULL, cname, pnames, NULL) > + > extern void __init samsung_clk_init(struct device_node *np, void __iomem *base, > unsigned long nr_clks); > extern void __init samsung_clk_of_register_fixed_ext( > @@ -335,6 +366,8 @@ extern void __init samsung_clk_register_gate( > struct samsung_gate_clock *clk_list, unsigned int nr_clk); > extern void __init samsung_clk_register_pll(struct samsung_pll_clock *pll_list, > unsigned int nr_clk, void __iomem *base); > +extern void __init samsung_clk_register_clkout(struct device_node *np, > + struct samsung_out_clock *out_clk_list, unsigned int nr_out_clk); > > extern unsigned long _get_rate(const char *clk_name); >
On 05/10/2014 09:21 AM, Pankaj Dubey wrote: > On 05/09/2014 10:00 PM, Tushar Behera wrote: >> All SoC in Exynos-series have a clock with name XCLKOUT to provide >> debug information about various clocks available in the SoC. The register >> controlling the MUX and GATE of this clock is provided within PMU domain. >> Since PMU domain can't be dedicatedly mapped by every driver, the >> register >> needs to be handled through a regmap handle provided by PMU syscon >> controller. Right now, CCF doesn't allow regmap based MUX and GATE >> clocks, >> hence a dedicated clock provider for XCLKOUT is added here. >> >> Signed-off-by: Tushar Behera <tushar.behera@linaro.org> >> CC: Tomasz Figa <t.figa@samsung.com> >> --- >> drivers/clk/samsung/Makefile | 2 +- >> drivers/clk/samsung/clk-out.c | 181 >> +++++++++++++++++++++++++++++++++++++++++ >> drivers/clk/samsung/clk.h | 33 ++++++++ >> 3 files changed, 215 insertions(+), 1 deletion(-) >> create mode 100644 drivers/clk/samsung/clk-out.c >> [ ... ] >> +/** >> + * struct samsung_clkout_soc_data: SoC specific register details >> + * @reg: Offset of CLKOUT register from PMU base > > how about naming this variable as "offset" instead of "reg". > Okay, I will change that. [ ... ] >> +u8 samsung_clkout_get_parent(struct clk_hw *hw) >> +{ >> + struct samsung_clkout *clkout = to_clk_out(hw); >> + const struct samsung_clkout_soc_data *soc_data = clkout->soc_data; >> + unsigned int parent_mask = BIT(soc_data->mux_width) - 1; >> + unsigned int val; >> + int ret; >> + >> + ret = regmap_read(clkout->regmap, soc_data->reg, &val); > > Do we really need to keep return value in "ret" as I can't see you are > using it anywhere? > Right, we are not using that and can be removed. >> + >> + return (val >> soc_data->mux_shift) & parent_mask; >> +} >> + [ ... ] >> +/* All existing Exynos serial of SoCs have common values for this >> offsets. */ > typo: serial/series/ Sure. Thanks for your review.
Hi Tushar, Basically you are adding a new clock-type for Clkout. IMO clkout is not a special hardware. Existing clock types can be reused to support clkout. I see 3 major problem here: 1) Clkout -> (Mux + Gate). You clubbed mux and gate together, and exposing as a single clock which is something like a composite clock. IMO this is not a recommended way in CCF. 2) New Clock Type: Since clkout is just a combination of a simple mux and gate which are already supported, it is a unnecessary duplication. 3) Clkout registered along with CMU: which is not correct. Clkout is in PMU (Separate physical IP) and should be registered as a independent Clock provider which provides 1 mux and 1 gate clock (As if now). It should also be well connected with main CMU. I understand the challenge in using regmap interface for a clock provider. But we need to identify a clean solution. IMHO a independent clock provider with iomap, is relatively cleaner approach till CCF is not ready with regmap based reg access for clock registers. Experts!! please comment. Regards, Rahul Sharma. On 12 May 2014 10:16, Tushar Behera <tushar.behera@linaro.org> wrote: > On 05/10/2014 09:21 AM, Pankaj Dubey wrote: >> On 05/09/2014 10:00 PM, Tushar Behera wrote: >>> All SoC in Exynos-series have a clock with name XCLKOUT to provide >>> debug information about various clocks available in the SoC. The register >>> controlling the MUX and GATE of this clock is provided within PMU domain. >>> Since PMU domain can't be dedicatedly mapped by every driver, the >>> register >>> needs to be handled through a regmap handle provided by PMU syscon >>> controller. Right now, CCF doesn't allow regmap based MUX and GATE >>> clocks, >>> hence a dedicated clock provider for XCLKOUT is added here. >>> >>> Signed-off-by: Tushar Behera <tushar.behera@linaro.org> >>> CC: Tomasz Figa <t.figa@samsung.com> >>> --- >>> drivers/clk/samsung/Makefile | 2 +- >>> drivers/clk/samsung/clk-out.c | 181 >>> +++++++++++++++++++++++++++++++++++++++++ >>> drivers/clk/samsung/clk.h | 33 ++++++++ >>> 3 files changed, 215 insertions(+), 1 deletion(-) >>> create mode 100644 drivers/clk/samsung/clk-out.c >>> > > [ ... ] > >>> +/** >>> + * struct samsung_clkout_soc_data: SoC specific register details >>> + * @reg: Offset of CLKOUT register from PMU base >> >> how about naming this variable as "offset" instead of "reg". >> > > Okay, I will change that. > > [ ... ] > >>> +u8 samsung_clkout_get_parent(struct clk_hw *hw) >>> +{ >>> + struct samsung_clkout *clkout = to_clk_out(hw); >>> + const struct samsung_clkout_soc_data *soc_data = clkout->soc_data; >>> + unsigned int parent_mask = BIT(soc_data->mux_width) - 1; >>> + unsigned int val; >>> + int ret; >>> + >>> + ret = regmap_read(clkout->regmap, soc_data->reg, &val); >> >> Do we really need to keep return value in "ret" as I can't see you are >> using it anywhere? >> > > Right, we are not using that and can be removed. > >>> + >>> + return (val >> soc_data->mux_shift) & parent_mask; >>> +} >>> + > > [ ... ] > >>> +/* All existing Exynos serial of SoCs have common values for this >>> offsets. */ >> typo: serial/series/ > > Sure. Thanks for your review. > > -- > Tushar Behera > -- > To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Rahul, Tushar, On 15.05.2014 15:44, Rahul Sharma wrote: > Hi Tushar, > > Basically you are adding a new clock-type for Clkout. IMO clkout > is not a special hardware. Existing clock types can be reused to > support clkout. I see 3 major problem here: > > 1) Clkout -> (Mux + Gate). You clubbed mux and gate together, and > exposing as a single clock which is something like a composite clock. > IMO this is not a recommended way in CCF. > > 2) New Clock Type: Since clkout is just a combination of a simple > mux and gate which are already supported, it is a unnecessary > duplication. > > 3) Clkout registered along with CMU: which is not correct. Clkout is in PMU > (Separate physical IP) and should be registered as a independent Clock > provider which provides 1 mux and 1 gate clock (As if now). It should also be > well connected with main CMU. > > I understand the challenge in using regmap interface for a clock provider. But > we need to identify a clean solution. IMHO a independent clock provider with > iomap, is relatively cleaner approach till CCF is not ready with regmap based > reg access for clock registers. > > Experts!! please comment. It's quite unfortunate that Tushar has duplicated the effort to create a clkout driver, considering the fact that we did have such driver internally at SRPOL and it was quite nice and simple. I will post a cleaned-up version today, that is about 2 times smaller in terms of lines of added code and provides the same functionality, without introducing custom clock types. In addition, it models the clkout properly as a feature of PMU, not CMU (CMU only provides outputs of particular sub-blocks that are fed into the PMU). Best regards, Tomasz -- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 15 May 2014 19:37, Tomasz Figa <t.figa@samsung.com> wrote: > Hi Rahul, Tushar, > > On 15.05.2014 15:44, Rahul Sharma wrote: >> Hi Tushar, >> >> Basically you are adding a new clock-type for Clkout. IMO clkout >> is not a special hardware. Existing clock types can be reused to >> support clkout. I see 3 major problem here: >> >> 1) Clkout -> (Mux + Gate). You clubbed mux and gate together, and >> exposing as a single clock which is something like a composite clock. >> IMO this is not a recommended way in CCF. >> >> 2) New Clock Type: Since clkout is just a combination of a simple >> mux and gate which are already supported, it is a unnecessary >> duplication. >> >> 3) Clkout registered along with CMU: which is not correct. Clkout is in PMU >> (Separate physical IP) and should be registered as a independent Clock >> provider which provides 1 mux and 1 gate clock (As if now). It should also be >> well connected with main CMU. >> >> I understand the challenge in using regmap interface for a clock provider. But >> we need to identify a clean solution. IMHO a independent clock provider with >> iomap, is relatively cleaner approach till CCF is not ready with regmap based >> reg access for clock registers. >> >> Experts!! please comment. > > It's quite unfortunate that Tushar has duplicated the effort to create a > clkout driver, considering the fact that we did have such driver > internally at SRPOL and it was quite nice and simple. > > I will post a cleaned-up version today, that is about 2 times smaller in > terms of lines of added code and provides the same functionality, > without introducing custom clock types. In addition, it models the > clkout properly as a feature of PMU, not CMU (CMU only provides outputs > of particular sub-blocks that are fed into the PMU). oh.. thats nice. Please share the implementation. Regards, Rahul Sharma. > > Best regards, > Tomasz > > _______________________________________________ > linux-arm-kernel mailing list > linux-arm-kernel@lists.infradead.org > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel -- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 15 May 2014 19:37, Tomasz Figa <t.figa@samsung.com> wrote: > Hi Rahul, Tushar, > > On 15.05.2014 15:44, Rahul Sharma wrote: >> Hi Tushar, >> >> Basically you are adding a new clock-type for Clkout. IMO clkout >> is not a special hardware. Existing clock types can be reused to >> support clkout. I see 3 major problem here: >> >> 1) Clkout -> (Mux + Gate). You clubbed mux and gate together, and >> exposing as a single clock which is something like a composite clock. >> IMO this is not a recommended way in CCF. >> >> 2) New Clock Type: Since clkout is just a combination of a simple >> mux and gate which are already supported, it is a unnecessary >> duplication. >> >> 3) Clkout registered along with CMU: which is not correct. Clkout is in PMU >> (Separate physical IP) and should be registered as a independent Clock >> provider which provides 1 mux and 1 gate clock (As if now). It should also be >> well connected with main CMU. >> >> I understand the challenge in using regmap interface for a clock provider. But >> we need to identify a clean solution. IMHO a independent clock provider with >> iomap, is relatively cleaner approach till CCF is not ready with regmap based >> reg access for clock registers. >> >> Experts!! please comment. > > It's quite unfortunate that Tushar has duplicated the effort to create a > clkout driver, considering the fact that we did have such driver > internally at SRPOL and it was quite nice and simple. > I had no idea that you had some solutions to this available to be posted :( Now that the new series is posted, I will test that at my end and update you later. > I will post a cleaned-up version today, that is about 2 times smaller in > terms of lines of added code and provides the same functionality, > without introducing custom clock types. In addition, it models the > clkout properly as a feature of PMU, not CMU (CMU only provides outputs > of particular sub-blocks that are fed into the PMU). > > Best regards, > Tomasz
On 19.05.2014 05:30, Tushar Behera wrote: > On 15 May 2014 19:37, Tomasz Figa <t.figa@samsung.com> wrote: >> Hi Rahul, Tushar, >> >> On 15.05.2014 15:44, Rahul Sharma wrote: >>> Hi Tushar, >>> >>> Basically you are adding a new clock-type for Clkout. IMO clkout >>> is not a special hardware. Existing clock types can be reused to >>> support clkout. I see 3 major problem here: >>> >>> 1) Clkout -> (Mux + Gate). You clubbed mux and gate together, and >>> exposing as a single clock which is something like a composite clock. >>> IMO this is not a recommended way in CCF. >>> >>> 2) New Clock Type: Since clkout is just a combination of a simple >>> mux and gate which are already supported, it is a unnecessary >>> duplication. >>> >>> 3) Clkout registered along with CMU: which is not correct. Clkout is in PMU >>> (Separate physical IP) and should be registered as a independent Clock >>> provider which provides 1 mux and 1 gate clock (As if now). It should also be >>> well connected with main CMU. >>> >>> I understand the challenge in using regmap interface for a clock provider. But >>> we need to identify a clean solution. IMHO a independent clock provider with >>> iomap, is relatively cleaner approach till CCF is not ready with regmap based >>> reg access for clock registers. >>> >>> Experts!! please comment. >> >> It's quite unfortunate that Tushar has duplicated the effort to create a >> clkout driver, considering the fact that we did have such driver >> internally at SRPOL and it was quite nice and simple. >> > > I had no idea that you had some solutions to this available to be posted :( > > Now that the new series is posted, I will test that at my end and > update you later. Again, sorry for this duplicated effort. The biggest problem is that we (SRPOL and Linaro) don't have a way to share our upstream TODO lists and say "hey, we have this working, if you need it, we can upstream it \o/" or "we need it too, but don't have resources right now to work on it :(". Maybe we should set up some wiki or any other semi-public site for this purpose? I need to talk with other people from my team and my manager to see what we can do. Other guys (other Samsung teams, Chromium folks, hobbyists) could also benefit from it. Anyway, thanks for your understanding and testing. Best regards, Tomasz -- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile index 8eb4799..d23ad4f 100644 --- a/drivers/clk/samsung/Makefile +++ b/drivers/clk/samsung/Makefile @@ -2,7 +2,7 @@ # Samsung Clock specific Makefile # -obj-$(CONFIG_COMMON_CLK) += clk.o clk-pll.o +obj-$(CONFIG_COMMON_CLK) += clk.o clk-pll.o clk-out.o obj-$(CONFIG_ARCH_EXYNOS4) += clk-exynos4.o obj-$(CONFIG_SOC_EXYNOS5250) += clk-exynos5250.o obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5420.o diff --git a/drivers/clk/samsung/clk-out.c b/drivers/clk/samsung/clk-out.c new file mode 100644 index 0000000..76489b6 --- /dev/null +++ b/drivers/clk/samsung/clk-out.c @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This file contains the utility functions to register the clkout clocks. +*/ + +/** + * All SoC in Exynos-series have a clock with name XCLKOUT to provide + * debug information about various clocks available in the SoC. The register + * controlling the MUX and GATE of this clock is provided within PMU domain. + * Since PMU domain can't be dedicatedly mapped every driver, the register + * needs to be handled through a regmap handle provided by PMU syscon + * controller. Right now, CCF doesn't allow regmap based MUX and GATE clocks, + * hence a dedicated clock provider for XCLKOUT is added here. + */ + +#include <linux/errno.h> +#include <linux/mfd/syscon.h> +#include <linux/regmap.h> + +#include "clk.h" + +/** + * struct samsung_clkout_soc_data: SoC specific register details + * @reg: Offset of CLKOUT register from PMU base + * @mux_shift: Start-bit of MUX bit-field + * @mux_width: Width of MUX bit-field + * @enable_bit: The bit corresponding to gating of this clock + */ +struct samsung_clkout_soc_data { + unsigned int reg; + u8 mux_shift; + u8 mux_width; + u8 enable_bit; +}; + +/** + * struct samsung_clkout: Structure to store driver specific clock context + * @hw: Handle to CCF clock + * @soc_data: SoC specific register details + * @regmap: Regmap handle of the PMU + */ +struct samsung_clkout { + struct clk_hw hw; + const struct samsung_clkout_soc_data *soc_data; + struct regmap *regmap; +}; + +#define to_clk_out(_hw) container_of(_hw, struct samsung_clkout, hw) + +int samsung_clkout_enable(struct clk_hw *hw) +{ + struct samsung_clkout *clkout = to_clk_out(hw); + const struct samsung_clkout_soc_data *soc_data = clkout->soc_data; + unsigned int enable_mask = BIT(soc_data->enable_bit); + + /* clkout is enabled if enable bit is low */ + regmap_update_bits(clkout->regmap, soc_data->reg, enable_mask, 0); + + return 0; +} + +void samsung_clkout_disable(struct clk_hw *hw) +{ + struct samsung_clkout *clkout = to_clk_out(hw); + const struct samsung_clkout_soc_data *soc_data = clkout->soc_data; + unsigned int enable_mask = BIT(soc_data->enable_bit); + + /* clkout is gated if enable bit is high */ + regmap_update_bits(clkout->regmap, soc_data->reg, + enable_mask, enable_mask); + + return; +} + +int samsung_clkout_set_parent(struct clk_hw *hw, u8 index) +{ + struct samsung_clkout *clkout = to_clk_out(hw); + const struct samsung_clkout_soc_data *soc_data = clkout->soc_data; + unsigned int parent_mask = BIT(soc_data->mux_width) - 1; + + regmap_update_bits(clkout->regmap, soc_data->reg, + parent_mask << soc_data->mux_shift, + index << soc_data->mux_shift); + + return 0; +} + +u8 samsung_clkout_get_parent(struct clk_hw *hw) +{ + struct samsung_clkout *clkout = to_clk_out(hw); + const struct samsung_clkout_soc_data *soc_data = clkout->soc_data; + unsigned int parent_mask = BIT(soc_data->mux_width) - 1; + unsigned int val; + int ret; + + ret = regmap_read(clkout->regmap, soc_data->reg, &val); + + return (val >> soc_data->mux_shift) & parent_mask; +} + +static const struct clk_ops samsung_clkout_clk_ops = { + .enable = samsung_clkout_enable, + .disable = samsung_clkout_disable, + .set_parent = samsung_clkout_set_parent, + .get_parent = samsung_clkout_get_parent, +}; + +static void __init _samsung_clk_register_clkout( + struct samsung_out_clock *out, + const struct samsung_clkout_soc_data *soc_data, + struct regmap *regmap) +{ + struct samsung_clkout *clkout; + struct clk *clk; + struct clk_init_data init; + int ret; + + clkout = kzalloc(sizeof(*clkout), GFP_KERNEL); + if (!clkout) { + pr_err("%s: could not allocate out clk %s\n", + __func__, out->name); + return; + } + + init.name = out->name; + init.parent_names = out->parent_names; + init.num_parents = out->num_parents; + init.ops = &samsung_clkout_clk_ops; + + clkout->hw.init = &init; + clkout->regmap = regmap; + clkout->soc_data = soc_data; + + clk = clk_register(NULL, &clkout->hw); + if (IS_ERR(clk)) { + pr_err("%s: failed to register out clock %s : %ld\n", + __func__, out->name, PTR_ERR(clk)); + kfree(clkout); + return; + } + + samsung_clk_add_lookup(clk, out->id); + + if (!out->alias) + return; + + ret = clk_register_clkdev(clk, out->alias, out->dev_name); + if (ret) + pr_err("%s: failed to register lookup for %s : %d", + __func__, out->name, ret); +} + +/* All existing Exynos serial of SoCs have common values for this offsets. */ +static const struct samsung_clkout_soc_data exynos_clkout_soc_data = { + .reg = 0xa00, + .mux_shift = 8, + .mux_width = 5, + .enable_bit = 0, +}; + +void __init samsung_clk_register_clkout(struct device_node *np, + struct samsung_out_clock *out_clk_list, unsigned int nr_out_clk) +{ + int cnt; + struct regmap *reg; + const struct samsung_clkout_soc_data *priv = &exynos_clkout_soc_data; + + reg = syscon_early_regmap_lookup_by_phandle(np, "samsung,pmu-syscon"); + if (IS_ERR(reg)) { + pr_err("Failed to get pmu-syscon handle for clkout\n"); + return; + } + + for (cnt = 0; cnt < nr_out_clk; cnt++) + _samsung_clk_register_clkout(&out_clk_list[cnt], priv, reg); +} diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h index c7141ba..b4b2122 100644 --- a/drivers/clk/samsung/clk.h +++ b/drivers/clk/samsung/clk.h @@ -312,6 +312,37 @@ struct samsung_pll_clock { __PLL(_typ, _id, NULL, _name, _pname, CLK_GET_RATE_NOCACHE, \ _lock, _con, _rtable, _alias) +/** + * struct samsung_out_clock: information about CLKOUT clock + * @id: platform specific id of the clock. + * @dev_name: name of the device to which this clock belongs. + * @name: name of this mux clock. + * @parent_names: array of pointer to parent clock names. + * @num_parents: number of parents listed in @parent_names. + * @alias: optional clock alias name to be assigned to this clock. + */ +struct samsung_out_clock { + unsigned int id; + const char *dev_name; + const char *name; + const char **parent_names; + unsigned int num_parents; + const char *alias; +}; + +#define __CLKOUT(_id, dname, cname, pnames, a) \ + { \ + .id = _id, \ + .dev_name = dname, \ + .name = cname, \ + .parent_names = pnames, \ + .num_parents = ARRAY_SIZE(pnames), \ + .alias = a, \ + } + +#define CLKOUT(_id, cname, pnames) \ + __CLKOUT(_id, NULL, cname, pnames, NULL) + extern void __init samsung_clk_init(struct device_node *np, void __iomem *base, unsigned long nr_clks); extern void __init samsung_clk_of_register_fixed_ext( @@ -335,6 +366,8 @@ extern void __init samsung_clk_register_gate( struct samsung_gate_clock *clk_list, unsigned int nr_clk); extern void __init samsung_clk_register_pll(struct samsung_pll_clock *pll_list, unsigned int nr_clk, void __iomem *base); +extern void __init samsung_clk_register_clkout(struct device_node *np, + struct samsung_out_clock *out_clk_list, unsigned int nr_out_clk); extern unsigned long _get_rate(const char *clk_name);
All SoC in Exynos-series have a clock with name XCLKOUT to provide debug information about various clocks available in the SoC. The register controlling the MUX and GATE of this clock is provided within PMU domain. Since PMU domain can't be dedicatedly mapped by every driver, the register needs to be handled through a regmap handle provided by PMU syscon controller. Right now, CCF doesn't allow regmap based MUX and GATE clocks, hence a dedicated clock provider for XCLKOUT is added here. Signed-off-by: Tushar Behera <tushar.behera@linaro.org> CC: Tomasz Figa <t.figa@samsung.com> --- drivers/clk/samsung/Makefile | 2 +- drivers/clk/samsung/clk-out.c | 181 +++++++++++++++++++++++++++++++++++++++++ drivers/clk/samsung/clk.h | 33 ++++++++ 3 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/samsung/clk-out.c