From: Mike Turquette <mturquette@linaro.org>
To: Heikki Krogerus <heikki.krogerus@linux.intel.com>,
"Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Mika Westerberg <mika.westerberg@linux.intel.com>,
Jin Yao <yao.jin@linux.intel.com>,
Li Aubrey <aubrey.li@linux.intel.com>,
Andy Shevchenko <andriy.shevchenko@linux.intel.com>,
linux-acpi@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCHv2 3/4] clk: new basic clk type for fractional divider
Date: Thu, 15 May 2014 09:53:49 -0700 [thread overview]
Message-ID: <20140515165349.9521.75672@quantum> (raw)
In-Reply-To: <1400161226-24067-4-git-send-email-heikki.krogerus@linux.intel.com>
Quoting Heikki Krogerus (2014-05-15 06:40:25)
> Fractional divider clocks are fairly common. This adds basic
> type for them.
>
> Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Taken into clk-next.
Just FYI, there was some talk at Embedded Linux Conference on providing
a better abstraction layer for some of these "basic" clock types. This
abstraction would allow the basic clock types to implement the
machine-agnostic logic (e.g. an incoming rate is divided by a value) and
then platforms and drivers could plug in the machine-specific parts
(e.g. divider is made up of m/n, or divider is power-of-two, or divider
is a simple integer with min == 1 and max == 5).
All of that is to say that in time this fractional divider could go away
once the abstraction layer allows us to fold the m/n divider stuff into
a core divider implementation.
Nothing wrong with the patch for now, so I've taken it for 3.16.
Regards,
Mike
> ---
> drivers/clk/Makefile | 1 +
> drivers/clk/clk-fractional-divider.c | 135 +++++++++++++++++++++++++++++++++++
> include/linux/clk-provider.h | 31 ++++++++
> 3 files changed, 167 insertions(+)
> create mode 100644 drivers/clk/clk-fractional-divider.c
>
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index f651b2a..33bc79e 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -8,6 +8,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-fixed-rate.o
> obj-$(CONFIG_COMMON_CLK) += clk-gate.o
> obj-$(CONFIG_COMMON_CLK) += clk-mux.o
> obj-$(CONFIG_COMMON_CLK) += clk-composite.o
> +obj-$(CONFIG_COMMON_CLK) += clk-fractional-divider.o
>
> # hardware specific clock types
> # please keep this section sorted lexicographically by file/directory path name
> diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c
> new file mode 100644
> index 0000000..ede685c
> --- /dev/null
> +++ b/drivers/clk/clk-fractional-divider.c
> @@ -0,0 +1,135 @@
> +/*
> + * Copyright (C) 2014 Intel Corporation
> + *
> + * 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.
> + *
> + * Adjustable fractional divider clock implementation.
> + * Output rate = (m / n) * parent_rate.
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/module.h>
> +#include <linux/device.h>
> +#include <linux/slab.h>
> +#include <linux/gcd.h>
> +
> +#define to_clk_fd(_hw) container_of(_hw, struct clk_fractional_divider, hw)
> +
> +static unsigned long clk_fd_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + struct clk_fractional_divider *fd = to_clk_fd(hw);
> + unsigned long flags = 0;
> + u32 val, m, n;
> + u64 ret;
> +
> + if (fd->lock)
> + spin_lock_irqsave(fd->lock, flags);
> +
> + val = clk_readl(fd->reg);
> +
> + if (fd->lock)
> + spin_unlock_irqrestore(fd->lock, flags);
> +
> + m = (val & fd->mmask) >> fd->mshift;
> + n = (val & fd->nmask) >> fd->nshift;
> +
> + ret = parent_rate * m;
> + do_div(ret, n);
> +
> + return ret;
> +}
> +
> +static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long *prate)
> +{
> + struct clk_fractional_divider *fd = to_clk_fd(hw);
> + unsigned maxn = (fd->nmask >> fd->nshift) + 1;
> + unsigned div;
> +
> + if (!rate || rate >= *prate)
> + return *prate;
> +
> + div = gcd(*prate, rate);
> +
> + while ((*prate / div) > maxn) {
> + div <<= 1;
> + rate <<= 1;
> + }
> +
> + return rate;
> +}
> +
> +static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long parent_rate)
> +{
> + struct clk_fractional_divider *fd = to_clk_fd(hw);
> + unsigned long flags = 0;
> + unsigned long div;
> + unsigned n, m;
> + u32 val;
> +
> + div = gcd(parent_rate, rate);
> + m = rate / div;
> + n = parent_rate / div;
> +
> + if (fd->lock)
> + spin_lock_irqsave(fd->lock, flags);
> +
> + val = clk_readl(fd->reg);
> + val &= ~(fd->mmask | fd->nmask);
> + val |= (m << fd->mshift) | (n << fd->nshift);
> + clk_writel(val, fd->reg);
> +
> + if (fd->lock)
> + spin_unlock_irqrestore(fd->lock, flags);
> +
> + return 0;
> +}
> +
> +const struct clk_ops clk_fractional_divider_ops = {
> + .recalc_rate = clk_fd_recalc_rate,
> + .round_rate = clk_fd_round_rate,
> + .set_rate = clk_fd_set_rate,
> +};
> +EXPORT_SYMBOL_GPL(clk_fractional_divider_ops);
> +
> +struct clk *clk_register_fractional_divider(struct device *dev,
> + const char *name, const char *parent_name, unsigned long flags,
> + void __iomem *reg, u8 mshift, u8 mwidth, u8 nshift, u8 nwidth,
> + u8 clk_divider_flags, spinlock_t *lock)
> +{
> + struct clk_fractional_divider *fd;
> + struct clk_init_data init;
> + struct clk *clk;
> +
> + fd = kzalloc(sizeof(*fd), GFP_KERNEL);
> + if (!fd) {
> + dev_err(dev, "could not allocate fractional divider clk\n");
> + return ERR_PTR(-ENOMEM);
> + }
> +
> + init.name = name;
> + init.ops = &clk_fractional_divider_ops;
> + init.flags = flags | CLK_IS_BASIC;
> + init.parent_names = parent_name ? &parent_name : NULL;
> + init.num_parents = parent_name ? 1 : 0;
> +
> + fd->reg = reg;
> + fd->mshift = mshift;
> + fd->mmask = (BIT(mwidth) - 1) << mshift;
> + fd->nshift = nshift;
> + fd->nmask = (BIT(nwidth) - 1) << nshift;
> + fd->flags = clk_divider_flags;
> + fd->lock = lock;
> + fd->hw.init = &init;
> +
> + clk = clk_register(dev, &fd->hw);
> + if (IS_ERR(clk))
> + kfree(fd);
> +
> + return clk;
> +}
> +EXPORT_SYMBOL_GPL(clk_register_fractional_divider);
> diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
> index 4080943..d76188a 100644
> --- a/include/linux/clk-provider.h
> +++ b/include/linux/clk-provider.h
> @@ -422,6 +422,37 @@ struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
> const char *parent_name, unsigned long flags,
> unsigned int mult, unsigned int div);
>
> +/**
> + * struct clk_fractional_divider - adjustable fractional divider clock
> + *
> + * @hw: handle between common and hardware-specific interfaces
> + * @reg: register containing the divider
> + * @mshift: shift to the numerator bit field
> + * @mwidth: width of the numerator bit field
> + * @nshift: shift to the denominator bit field
> + * @nwidth: width of the denominator bit field
> + * @lock: register lock
> + *
> + * Clock with adjustable fractional divider affecting its output frequency.
> + */
> +
> +struct clk_fractional_divider {
> + struct clk_hw hw;
> + void __iomem *reg;
> + u8 mshift;
> + u32 mmask;
> + u8 nshift;
> + u32 nmask;
> + u8 flags;
> + spinlock_t *lock;
> +};
> +
> +extern const struct clk_ops clk_fractional_divider_ops;
> +struct clk *clk_register_fractional_divider(struct device *dev,
> + const char *name, const char *parent_name, unsigned long flags,
> + void __iomem *reg, u8 mshift, u8 mwidth, u8 nshift, u8 nwidth,
> + u8 clk_divider_flags, spinlock_t *lock);
> +
> /***
> * struct clk_composite - aggregate clock of mux, divider and gate clocks
> *
> --
> 2.0.0.rc2
>
next prev parent reply other threads:[~2014-05-15 16:53 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-05-15 13:40 [PATCHv2 0/4] ACPI / LPSS: Solution for two issues seen on Asus T100 Heikki Krogerus
2014-05-15 13:40 ` [PATCHv2 1/4] ACPI / PM: Export rest of the subsys functions Heikki Krogerus
2014-05-15 13:40 ` [PATCHv2 2/4] ACPI / LPSS: custom power domain for LPSS Heikki Krogerus
2014-05-20 21:33 ` Rafael J. Wysocki
2014-05-21 10:05 ` Heikki Krogerus
2014-05-21 11:01 ` Rafael J. Wysocki
2014-05-21 10:52 ` Heikki Krogerus
2014-05-21 23:28 ` Rafael J. Wysocki
2014-05-23 12:30 ` Heikki Krogerus
2014-05-23 13:10 ` Rafael J. Wysocki
2014-05-23 13:02 ` Heikki Krogerus
2014-05-23 13:15 ` [PATCHv3 " Heikki Krogerus
2014-05-26 13:03 ` Rafael J. Wysocki
2014-05-26 13:42 ` Heikki Krogerus
2014-05-26 21:30 ` Rafael J. Wysocki
2014-05-15 13:40 ` [PATCHv2 3/4] clk: new basic clk type for fractional divider Heikki Krogerus
2014-05-15 16:53 ` Mike Turquette [this message]
2014-05-16 22:38 ` Rafael J. Wysocki
[not found] ` <20140516230905.9521.88763@quantum>
2014-05-17 0:15 ` Rafael J. Wysocki
[not found] ` <20140517013403.9521.86191@quantum>
2014-05-19 0:15 ` Rafael J. Wysocki
2014-05-15 13:40 ` [PATCHv2 4/4] ACPI / LPSS: support for fractional divider clock Heikki Krogerus
2014-05-19 11:42 ` [PATCHv3 " Heikki Krogerus
2014-05-15 14:35 ` [PATCHv2 0/4] ACPI / LPSS: Solution for two issues seen on Asus T100 Li, Aubrey
2014-05-15 14:53 ` Andy Shevchenko
2014-05-15 15:59 ` Li, Aubrey
2014-05-15 16:11 ` Mika Westerberg
2014-05-15 23:29 ` Li, Aubrey
2014-05-16 7:04 ` Andy Shevchenko
2014-05-16 13:37 ` Li, Aubrey
2014-05-16 14:45 ` Andy Shevchenko
2014-05-20 11:17 ` Li, Aubrey
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20140515165349.9521.75672@quantum \
--to=mturquette@linaro.org \
--cc=andriy.shevchenko@linux.intel.com \
--cc=aubrey.li@linux.intel.com \
--cc=heikki.krogerus@linux.intel.com \
--cc=linux-acpi@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mika.westerberg@linux.intel.com \
--cc=rjw@rjwysocki.net \
--cc=yao.jin@linux.intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.