From mboxrd@z Thu Jan 1 00:00:00 1970 From: Pankaj Dubey Subject: Re: [PATCH 1/4] clk: samsung: out: Add infrastructure to register CLKOUT Date: Sat, 10 May 2014 12:51:31 +0900 Message-ID: <536DA243.6000600@samsung.com> References: <1399640410-30957-1-git-send-email-tushar.behera@linaro.org> <1399640410-30957-2-git-send-email-tushar.behera@linaro.org> Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Return-path: Received: from mailout4.samsung.com ([203.254.224.34]:20248 "EHLO mailout4.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754497AbaEJDdM (ORCPT ); Fri, 9 May 2014 23:33:12 -0400 In-reply-to: <1399640410-30957-2-git-send-email-tushar.behera@linaro.org> Sender: linux-samsung-soc-owner@vger.kernel.org List-Id: linux-samsung-soc@vger.kernel.org To: Tushar Behera Cc: linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, linux-samsung-soc@vger.kernel.org, linux-arm-kernel@lists.infradead.org, mturquette@linaro.org, t.figa@samsung.com, kgene.kim@samsung.com, galak@codeaurora.org, ijc+devicetree@hellion.org.uk, mark.rutland@arm.com, pawel.moll@arm.com, robh+dt@kernel.org 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 > CC: Tomasz Figa > --- > 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 > +#include > +#include > + > +#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); > -- Best Regards, Pankaj Dubey From mboxrd@z Thu Jan 1 00:00:00 1970 From: pankaj.dubey@samsung.com (Pankaj Dubey) Date: Sat, 10 May 2014 12:51:31 +0900 Subject: [PATCH 1/4] clk: samsung: out: Add infrastructure to register CLKOUT In-Reply-To: <1399640410-30957-2-git-send-email-tushar.behera@linaro.org> References: <1399640410-30957-1-git-send-email-tushar.behera@linaro.org> <1399640410-30957-2-git-send-email-tushar.behera@linaro.org> Message-ID: <536DA243.6000600@samsung.com> To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org 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 > CC: Tomasz Figa > --- > 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 > +#include > +#include > + > +#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); > -- Best Regards, Pankaj Dubey