Message ID | 1347977875-16855-6-git-send-email-pawel.moll@arm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Quoting Pawel Moll (2012-09-18 07:17:47) > This driver provides a common clock framework hardware driver > for Versatile Express clock generators (a.k.a "osc") controlled > via the config bus. > > Signed-off-by: Pawel Moll <pawel.moll@arm.com> > --- > drivers/clk/versatile/Makefile | 1 + > drivers/clk/versatile/clk-vexpress-osc.c | 146 ++++++++++++++++++++++++++++++ > 2 files changed, 147 insertions(+) > create mode 100644 drivers/clk/versatile/clk-vexpress-osc.c > > Hi Mike, > > As agreed - this patch and the next one ("clk: Common clocks > implementation for Versatile Express") are all yours. > Taken into clk-next. Thanks, Mike > Regards > > Pawel > > diff --git a/drivers/clk/versatile/Makefile b/drivers/clk/versatile/Makefile > index c0a0f64..1e49a7a 100644 > --- a/drivers/clk/versatile/Makefile > +++ b/drivers/clk/versatile/Makefile > @@ -2,3 +2,4 @@ > obj-$(CONFIG_ICST) += clk-icst.o > obj-$(CONFIG_ARCH_INTEGRATOR) += clk-integrator.o > obj-$(CONFIG_ARCH_REALVIEW) += clk-realview.o > +obj-$(CONFIG_VEXPRESS_CONFIG) += clk-vexpress-osc.o > diff --git a/drivers/clk/versatile/clk-vexpress-osc.c b/drivers/clk/versatile/clk-vexpress-osc.c > new file mode 100644 > index 0000000..dcb6ae0 > --- /dev/null > +++ b/drivers/clk/versatile/clk-vexpress-osc.c > @@ -0,0 +1,146 @@ > +/* > + * 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 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. > + * > + * Copyright (C) 2012 ARM Limited > + */ > + > +#define pr_fmt(fmt) "vexpress-osc: " fmt > + > +#include <linux/clkdev.h> > +#include <linux/clk-provider.h> > +#include <linux/err.h> > +#include <linux/of.h> > +#include <linux/platform_device.h> > +#include <linux/slab.h> > +#include <linux/vexpress.h> > + > +struct vexpress_osc { > + struct vexpress_config_func *func; > + struct clk_hw hw; > + unsigned long rate_min; > + unsigned long rate_max; > +}; > + > +#define to_vexpress_osc(osc) container_of(osc, struct vexpress_osc, hw) > + > +static unsigned long vexpress_osc_recalc_rate(struct clk_hw *hw, > + unsigned long parent_rate) > +{ > + struct vexpress_osc *osc = to_vexpress_osc(hw); > + u32 rate; > + > + vexpress_config_read(osc->func, 0, &rate); > + > + return rate; > +} > + > +static long vexpress_osc_round_rate(struct clk_hw *hw, unsigned long rate, > + unsigned long *parent_rate) > +{ > + struct vexpress_osc *osc = to_vexpress_osc(hw); > + > + if (WARN_ON(osc->rate_min && rate < osc->rate_min)) > + rate = osc->rate_min; > + > + if (WARN_ON(osc->rate_max && rate > osc->rate_max)) > + rate = osc->rate_max; > + > + return rate; > +} > + > +static int vexpress_osc_set_rate(struct clk_hw *hw, unsigned long rate, > + unsigned long parent_rate) > +{ > + struct vexpress_osc *osc = to_vexpress_osc(hw); > + > + return vexpress_config_write(osc->func, 0, rate); > +} > + > +static struct clk_ops vexpress_osc_ops = { > + .recalc_rate = vexpress_osc_recalc_rate, > + .round_rate = vexpress_osc_round_rate, > + .set_rate = vexpress_osc_set_rate, > +}; > + > + > +struct clk * __init vexpress_osc_setup(struct device *dev) > +{ > + struct clk_init_data init; > + struct vexpress_osc *osc = kzalloc(sizeof(*osc), GFP_KERNEL); > + > + if (!osc) > + return NULL; > + > + osc->func = vexpress_config_func_get_by_dev(dev); > + if (!osc->func) { > + kfree(osc); > + return NULL; > + } > + > + init.name = dev_name(dev); > + init.ops = &vexpress_osc_ops; > + init.flags = CLK_IS_ROOT; > + init.num_parents = 0; > + osc->hw.init = &init; > + > + return clk_register(NULL, &osc->hw); > +} > + > +void __init vexpress_osc_of_setup(struct device_node *node) > +{ > + struct clk_init_data init; > + struct vexpress_osc *osc; > + struct clk *clk; > + u32 range[2]; > + > + osc = kzalloc(sizeof(*osc), GFP_KERNEL); > + if (!osc) > + goto error; > + > + osc->func = vexpress_config_func_get_by_node(node); > + if (!osc->func) { > + pr_err("Failed to obtain config func for node '%s'!\n", > + node->name); > + goto error; > + } > + > + if (of_property_read_u32_array(node, "freq-range", range, > + ARRAY_SIZE(range)) == 0) { > + osc->rate_min = range[0]; > + osc->rate_max = range[1]; > + } > + > + of_property_read_string(node, "clock-output-names", &init.name); > + if (!init.name) > + init.name = node->name; > + > + init.ops = &vexpress_osc_ops; > + init.flags = CLK_IS_ROOT; > + init.num_parents = 0; > + > + osc->hw.init = &init; > + > + clk = clk_register(NULL, &osc->hw); > + if (IS_ERR(clk)) { > + pr_err("Failed to register clock '%s'!\n", init.name); > + goto error; > + } > + > + of_clk_add_provider(node, of_clk_src_simple_get, clk); > + > + pr_debug("Registered clock '%s'\n", init.name); > + > + return; > + > +error: > + if (osc->func) > + vexpress_config_func_put(osc->func); > + kfree(osc); > +} > -- > 1.7.9.5
diff --git a/drivers/clk/versatile/Makefile b/drivers/clk/versatile/Makefile index c0a0f64..1e49a7a 100644 --- a/drivers/clk/versatile/Makefile +++ b/drivers/clk/versatile/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_ICST) += clk-icst.o obj-$(CONFIG_ARCH_INTEGRATOR) += clk-integrator.o obj-$(CONFIG_ARCH_REALVIEW) += clk-realview.o +obj-$(CONFIG_VEXPRESS_CONFIG) += clk-vexpress-osc.o diff --git a/drivers/clk/versatile/clk-vexpress-osc.c b/drivers/clk/versatile/clk-vexpress-osc.c new file mode 100644 index 0000000..dcb6ae0 --- /dev/null +++ b/drivers/clk/versatile/clk-vexpress-osc.c @@ -0,0 +1,146 @@ +/* + * 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 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. + * + * Copyright (C) 2012 ARM Limited + */ + +#define pr_fmt(fmt) "vexpress-osc: " fmt + +#include <linux/clkdev.h> +#include <linux/clk-provider.h> +#include <linux/err.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/vexpress.h> + +struct vexpress_osc { + struct vexpress_config_func *func; + struct clk_hw hw; + unsigned long rate_min; + unsigned long rate_max; +}; + +#define to_vexpress_osc(osc) container_of(osc, struct vexpress_osc, hw) + +static unsigned long vexpress_osc_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct vexpress_osc *osc = to_vexpress_osc(hw); + u32 rate; + + vexpress_config_read(osc->func, 0, &rate); + + return rate; +} + +static long vexpress_osc_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct vexpress_osc *osc = to_vexpress_osc(hw); + + if (WARN_ON(osc->rate_min && rate < osc->rate_min)) + rate = osc->rate_min; + + if (WARN_ON(osc->rate_max && rate > osc->rate_max)) + rate = osc->rate_max; + + return rate; +} + +static int vexpress_osc_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct vexpress_osc *osc = to_vexpress_osc(hw); + + return vexpress_config_write(osc->func, 0, rate); +} + +static struct clk_ops vexpress_osc_ops = { + .recalc_rate = vexpress_osc_recalc_rate, + .round_rate = vexpress_osc_round_rate, + .set_rate = vexpress_osc_set_rate, +}; + + +struct clk * __init vexpress_osc_setup(struct device *dev) +{ + struct clk_init_data init; + struct vexpress_osc *osc = kzalloc(sizeof(*osc), GFP_KERNEL); + + if (!osc) + return NULL; + + osc->func = vexpress_config_func_get_by_dev(dev); + if (!osc->func) { + kfree(osc); + return NULL; + } + + init.name = dev_name(dev); + init.ops = &vexpress_osc_ops; + init.flags = CLK_IS_ROOT; + init.num_parents = 0; + osc->hw.init = &init; + + return clk_register(NULL, &osc->hw); +} + +void __init vexpress_osc_of_setup(struct device_node *node) +{ + struct clk_init_data init; + struct vexpress_osc *osc; + struct clk *clk; + u32 range[2]; + + osc = kzalloc(sizeof(*osc), GFP_KERNEL); + if (!osc) + goto error; + + osc->func = vexpress_config_func_get_by_node(node); + if (!osc->func) { + pr_err("Failed to obtain config func for node '%s'!\n", + node->name); + goto error; + } + + if (of_property_read_u32_array(node, "freq-range", range, + ARRAY_SIZE(range)) == 0) { + osc->rate_min = range[0]; + osc->rate_max = range[1]; + } + + of_property_read_string(node, "clock-output-names", &init.name); + if (!init.name) + init.name = node->name; + + init.ops = &vexpress_osc_ops; + init.flags = CLK_IS_ROOT; + init.num_parents = 0; + + osc->hw.init = &init; + + clk = clk_register(NULL, &osc->hw); + if (IS_ERR(clk)) { + pr_err("Failed to register clock '%s'!\n", init.name); + goto error; + } + + of_clk_add_provider(node, of_clk_src_simple_get, clk); + + pr_debug("Registered clock '%s'\n", init.name); + + return; + +error: + if (osc->func) + vexpress_config_func_put(osc->func); + kfree(osc); +}
This driver provides a common clock framework hardware driver for Versatile Express clock generators (a.k.a "osc") controlled via the config bus. Signed-off-by: Pawel Moll <pawel.moll@arm.com> --- drivers/clk/versatile/Makefile | 1 + drivers/clk/versatile/clk-vexpress-osc.c | 146 ++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 drivers/clk/versatile/clk-vexpress-osc.c Hi Mike, As agreed - this patch and the next one ("clk: Common clocks implementation for Versatile Express") are all yours. Regards Pawel