Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1684967 > unrolled thread
| Started by | Chunyan Zhang <chunyan.zhang@spreadtrum.com> |
|---|---|
| First post | 2017-07-11 13:10 +0200 |
| Last post | 2017-07-11 13:10 +0200 |
| Articles | 8 — 3 participants |
Back to article view | Back to linux.kernel
[PATCH V2 00/10] add clock driver for Spreadtrum platforms Chunyan Zhang <chunyan.zhang@spreadtrum.com> - 2017-07-11 13:10 +0200
[PATCH V2 08/10] clk: sprd: add adjustable pll support Chunyan Zhang <chunyan.zhang@spreadtrum.com> - 2017-07-11 13:10 +0200
[PATCH V2 02/10] dt-bindings: Add Spreadtrum clock binding documentation Chunyan Zhang <chunyan.zhang@spreadtrum.com> - 2017-07-11 13:10 +0200
Re: [PATCH V2 02/10] dt-bindings: Add Spreadtrum clock binding documentation Rob Herring <robh@kernel.org> - 2017-07-14 18:20 +0200
Re: [PATCH V2 02/10] dt-bindings: Add Spreadtrum clock binding documentation Chunyan Zhang <zhang.lyra@gmail.com> - 2017-07-17 04:10 +0200
[PATCH V2 07/10] clk: sprd: add composite clock support Chunyan Zhang <chunyan.zhang@spreadtrum.com> - 2017-07-11 13:10 +0200
[PATCH V2 04/10] clk: sprd: add gate clock support Chunyan Zhang <chunyan.zhang@spreadtrum.com> - 2017-07-11 13:10 +0200
[PATCH V2 03/10] clk: sprd: Add common infrastructure Chunyan Zhang <chunyan.zhang@spreadtrum.com> - 2017-07-11 13:10 +0200
| From | Chunyan Zhang <chunyan.zhang@spreadtrum.com> |
|---|---|
| Date | 2017-07-11 13:10 +0200 |
| Subject | [PATCH V2 00/10] add clock driver for Spreadtrum platforms |
| Message-ID | <u21dg-1yp-9@gated-at.bofh.it> |
This is a rewrite of Spreadtrum's original clock driver[1] according to the
comments[2] from Stephen Boyd.
This series adds Spreadtrum clock support together with its binding
documentation and devicetree data.
Any comments would be greatly appreciated.
Thanks,
Chunyan
Changes from V1 (https://lkml.org/lkml/2017/6/17/356):
* Address Stephen's comments:
- Switch to use platform device driver instead of the DT probing mechanism.
- Move the common clock macro out from vendor directory, but need to remove those
overlap code from other vendors (such as sunxi-ng) once this gets merged.
- Add support to be built as a module.
- Add 'sprd_' prefix for all spin locks used in these drivers.
- Mark input parameter of sprd_x with const.
- Remove unreasonable dependencies to CONFIG_64BIT.
- Add readl() after writing the same register.
- Remove CLK_IS_BASIC which is no longer used.
- Remove unnecessary CLK_IGNORE_UNUSED when defining a clock.
- Change to expose all clock index.
- Use clk_ instead of ccu.
- Add Kconfig for sprd clocks.
- Move the fixed clocks out from the soc node.
- Switch to use 64-bit math in pll driver instead of 32-bit math.
* Revise binding documentation according to dt modification.
* Rename sc9860.c to sc9860-clk.c
[1] https://lwn.net/Articles/722739/
[2] https://www.spinics.net/lists/arm-kernel/msg582017.html
Chunyan Zhang (10):
drivers: move clock common macros out from vendor directories
dt-bindings: Add Spreadtrum clock binding documentation
clk: sprd: Add common infrastructure
clk: sprd: add gate clock support
clk: sprd: add mux clock support
clk: sprd: add divider clock support
clk: sprd: add composite clock support
clk: sprd: add adjustable pll support
clk: sprd: add clocks support for SC9860
arm64: dts: add clocks for SC9860
Documentation/devicetree/bindings/clock/sprd.txt | 36 +
arch/arm64/boot/dts/sprd/sc9860.dtsi | 22 +
arch/arm64/boot/dts/sprd/whale2.dtsi | 3 +-
drivers/clk/Kconfig | 1 +
drivers/clk/Makefile | 1 +
drivers/clk/clk_common.h | 60 +
drivers/clk/sprd/Kconfig | 14 +
drivers/clk/sprd/Makefile | 11 +
drivers/clk/sprd/common.c | 83 ++
drivers/clk/sprd/common.h | 56 +
drivers/clk/sprd/composite.c | 64 +
drivers/clk/sprd/composite.h | 47 +
drivers/clk/sprd/div.c | 98 ++
drivers/clk/sprd/div.h | 77 +
drivers/clk/sprd/gate.c | 104 ++
drivers/clk/sprd/gate.h | 58 +
drivers/clk/sprd/mux.c | 86 ++
drivers/clk/sprd/mux.h | 63 +
drivers/clk/sprd/pll.c | 236 +++
drivers/clk/sprd/pll.h | 133 ++
drivers/clk/sprd/sc9860-clk.c | 1726 ++++++++++++++++++++++
include/dt-bindings/clock/sprd,sc9860-clk.h | 375 +++++
22 files changed, 3352 insertions(+), 2 deletions(-)
create mode 100644 Documentation/devicetree/bindings/clock/sprd.txt
create mode 100644 drivers/clk/clk_common.h
create mode 100644 drivers/clk/sprd/Kconfig
create mode 100644 drivers/clk/sprd/Makefile
create mode 100644 drivers/clk/sprd/common.c
create mode 100644 drivers/clk/sprd/common.h
create mode 100644 drivers/clk/sprd/composite.c
create mode 100644 drivers/clk/sprd/composite.h
create mode 100644 drivers/clk/sprd/div.c
create mode 100644 drivers/clk/sprd/div.h
create mode 100644 drivers/clk/sprd/gate.c
create mode 100644 drivers/clk/sprd/gate.h
create mode 100644 drivers/clk/sprd/mux.c
create mode 100644 drivers/clk/sprd/mux.h
create mode 100644 drivers/clk/sprd/pll.c
create mode 100644 drivers/clk/sprd/pll.h
create mode 100644 drivers/clk/sprd/sc9860-clk.c
create mode 100644 include/dt-bindings/clock/sprd,sc9860-clk.h
--
2.7.4
[toc] | [next] | [standalone]
| From | Chunyan Zhang <chunyan.zhang@spreadtrum.com> |
|---|---|
| Date | 2017-07-11 13:10 +0200 |
| Subject | [PATCH V2 08/10] clk: sprd: add adjustable pll support |
| Message-ID | <u21dg-1yp-21@gated-at.bofh.it> |
| In reply to | #1684967 |
Introduced a common adjustable pll clock driver for Spreadtrum SoCs.
Original-by: Xiaolong Zhang <xiaolong.zhang@spreadtrum.com>
Signed-off-by: Chunyan Zhang <chunyan.zhang@spreadtrum.com>
---
drivers/clk/sprd/Makefile | 1 +
drivers/clk/sprd/pll.c | 236 ++++++++++++++++++++++++++++++++++++++++++++++
drivers/clk/sprd/pll.h | 133 ++++++++++++++++++++++++++
3 files changed, 370 insertions(+)
create mode 100644 drivers/clk/sprd/pll.c
create mode 100644 drivers/clk/sprd/pll.h
diff --git a/drivers/clk/sprd/Makefile b/drivers/clk/sprd/Makefile
index 2262e76..d693969 100644
--- a/drivers/clk/sprd/Makefile
+++ b/drivers/clk/sprd/Makefile
@@ -5,3 +5,4 @@ clk-sprd-y += gate.o
clk-sprd-y += mux.o
clk-sprd-y += div.o
clk-sprd-y += composite.o
+clk-sprd-y += pll.o
diff --git a/drivers/clk/sprd/pll.c b/drivers/clk/sprd/pll.c
new file mode 100644
index 0000000..97935a2
--- /dev/null
+++ b/drivers/clk/sprd/pll.c
@@ -0,0 +1,236 @@
+/*
+ * Spreadtrum pll clock driver
+ *
+ * Copyright (C) 2017 Spreadtrum, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+
+#include "pll.h"
+
+#define CLK_PLL_1M 1000000
+#define CLK_PLL_10M (CLK_PLL_1M * 10)
+
+#define pindex(pll, member) \
+ (pll->factors[member].shift / (8 * sizeof(pll->regs[0])))
+
+#define pshift(pll, member) \
+ (pll->factors[member].shift % (8 * sizeof(pll->regs[0])))
+
+#define pwidth(pll, member) \
+ pll->factors[member].width
+
+#define pmask(pll, member) \
+ ((pwidth(pll, member)) ? \
+ GENMASK(pwidth(pll, member) + pshift(pll, member) - 1, \
+ pshift(pll, member)) : 0)
+
+#define pinternal(pll, cfg, member) \
+ (cfg[pindex(pll, member)] & pmask(pll, member))
+
+#define pinternal_val(pll, cfg, member) \
+ (pinternal(pll, cfg, member) >> pshift(pll, member))
+
+static unsigned long pll_get_refin(const struct sprd_pll *pll)
+{
+ u32 shift, mask, index, refin_id = 3;
+ const unsigned long refin[4] = { 2, 4, 13, 26 };
+
+ if (pwidth(pll, PLL_REFIN)) {
+ index = pindex(pll, PLL_REFIN);
+ shift = pshift(pll, PLL_REFIN);
+ mask = pmask(pll, PLL_REFIN);
+ refin_id = (sprd_pll_readl(pll, index) & mask) >> shift;
+ if (refin_id > 3)
+ refin_id = 3;
+ }
+
+ return refin[refin_id];
+}
+
+static u32 pll_get_ibias(u64 rate, const u64 *table)
+{
+ u32 i, num = table[0];
+
+ for (i = 1; i < num + 1; i++)
+ if (rate <= table[i])
+ break;
+
+ return (i == num + 1) ? num : i;
+}
+
+static unsigned long _sprd_pll_recalc_rate(const struct sprd_pll *pll,
+ unsigned long parent_rate)
+{
+ u32 *cfg;
+ u32 i, mask, reg_num = pll->regs[0];
+ unsigned long rate, nint, kint = 0;
+ u64 refin;
+ u16 k1, k2;
+
+ cfg = kcalloc(reg_num, sizeof(*cfg), GFP_KERNEL);
+ if (!cfg)
+ return -ENOMEM;
+
+ for (i = 0; i < reg_num; i++)
+ cfg[i] = sprd_pll_readl(pll, i);
+
+ refin = pll_get_refin(pll);
+
+ if (pinternal(pll, cfg, PLL_PREDIV))
+ refin = refin * 2;
+
+ if (pwidth(pll, PLL_POSTDIV) &&
+ ((pll->fflag == 1 && pinternal(pll, cfg, PLL_POSTDIV)) ||
+ (!pll->fflag && !pinternal(pll, cfg, PLL_POSTDIV))))
+ refin = refin / 2;
+
+ if (!pinternal(pll, cfg, PLL_DIV_S)) {
+ rate = refin * pinternal_val(pll, cfg, PLL_N) * CLK_PLL_10M;
+ } else {
+ nint = pinternal_val(pll, cfg, PLL_NINT);
+ if (pinternal(pll, cfg, PLL_SDM_EN))
+ kint = pinternal_val(pll, cfg, PLL_KINT);
+
+ mask = pmask(pll, PLL_KINT);
+
+ k1 = pll->k1;
+ k2 = pll->k2;
+ rate = DIV_ROUND_CLOSEST_ULL(refin * kint * k1,
+ ((mask >> __ffs(mask)) + 1)) *
+ k2 + refin * nint * CLK_PLL_1M;
+ }
+
+ return rate;
+}
+
+#define SPRD_PLL_WRITE_CHECK(pll, i, mask, val) \
+ ((sprd_pll_readl(pll, i) & mask) == val) ? 0 : -EFAULT
+
+static int _sprd_pll_set_rate(const struct sprd_pll *pll,
+ unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct reg_cfg *cfg;
+ int ret = 0;
+ u32 mask, shift, width, ibias_val, index;
+ u32 reg_num = pll->regs[0], i = 0;
+ unsigned long kint, nint;
+ u64 refin, fvco = rate;
+
+ cfg = kcalloc(reg_num, sizeof(*cfg), GFP_KERNEL);
+ if (!cfg)
+ return -ENOMEM;
+
+ refin = pll_get_refin(pll);
+
+ mask = pmask(pll, PLL_PREDIV);
+ index = pindex(pll, PLL_PREDIV);
+ width = pwidth(pll, PLL_PREDIV);
+ if (width && (sprd_pll_readl(pll, index) & mask))
+ refin = refin * 2;
+
+ mask = pmask(pll, PLL_POSTDIV);
+ index = pindex(pll, PLL_POSTDIV);
+ width = pwidth(pll, PLL_POSTDIV);
+ cfg[index].msk = mask;
+ if (width && ((pll->fflag == 1 && fvco <= pll->fvco) ||
+ (pll->fflag == 0 && fvco > pll->fvco)))
+ cfg[index].val |= mask;
+
+ if (width && fvco <= pll->fvco)
+ fvco = fvco * 2;
+
+ mask = pmask(pll, PLL_DIV_S);
+ index = pindex(pll, PLL_DIV_S);
+ cfg[index].val |= mask;
+ cfg[index].msk |= mask;
+
+ mask = pmask(pll, PLL_SDM_EN);
+ index = pindex(pll, PLL_SDM_EN);
+ cfg[index].val |= mask;
+ cfg[index].msk |= mask;
+
+ nint = fvco/(refin * CLK_PLL_1M);
+
+ mask = pmask(pll, PLL_NINT);
+ index = pindex(pll, PLL_NINT);
+ shift = pshift(pll, PLL_NINT);
+ cfg[index].val |= (nint << shift) & mask;
+ cfg[index].msk |= mask;
+
+ mask = pmask(pll, PLL_KINT);
+ index = pindex(pll, PLL_KINT);
+ width = pwidth(pll, PLL_KINT);
+ shift = pshift(pll, PLL_KINT);
+ kint = DIV_ROUND_CLOSEST_ULL(((fvco - refin * nint * CLK_PLL_1M) /
+ 10000) * ((mask >> shift) + 1),
+ refin * 100);
+ cfg[index].val |= (kint << shift) & mask;
+ cfg[index].msk |= mask;
+
+ ibias_val = pll_get_ibias(fvco, pll->itable);
+
+ mask = pmask(pll, PLL_IBIAS);
+ index = pindex(pll, PLL_IBIAS);
+ shift = pshift(pll, PLL_IBIAS);
+ cfg[index].val |= ibias_val << shift & mask;
+ cfg[index].msk |= mask;
+
+ for (i = 0; i < reg_num; i++) {
+ if (cfg[i].msk) {
+ sprd_pll_writel(pll, i, cfg[i].msk, cfg[i].val);
+ ret |= SPRD_PLL_WRITE_CHECK(pll, i, cfg[i].msk,
+ cfg[i].val);
+ }
+ }
+
+ if (!ret)
+ udelay(pll->udelay);
+
+ return ret;
+}
+
+static unsigned long sprd_pll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct sprd_pll *pll = hw_to_sprd_pll(hw);
+
+ return _sprd_pll_recalc_rate(pll, parent_rate);
+}
+
+static int sprd_pll_set_rate(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct sprd_pll *pll = hw_to_sprd_pll(hw);
+
+ return _sprd_pll_set_rate(pll, rate, parent_rate);
+}
+
+static int sprd_pll_clk_prepare(struct clk_hw *hw)
+{
+ struct sprd_pll *pll = hw_to_sprd_pll(hw);
+
+ udelay(pll->udelay);
+
+ return 0;
+}
+
+static long sprd_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ return rate;
+}
+
+const struct clk_ops sprd_pll_ops = {
+ .prepare = sprd_pll_clk_prepare,
+ .recalc_rate = sprd_pll_recalc_rate,
+ .round_rate = sprd_pll_round_rate,
+ .set_rate = sprd_pll_set_rate,
+};
+EXPORT_SYMBOL_GPL(sprd_pll_ops);
diff --git a/drivers/clk/sprd/pll.h b/drivers/clk/sprd/pll.h
new file mode 100644
index 0000000..af5b2da
--- /dev/null
+++ b/drivers/clk/sprd/pll.h
@@ -0,0 +1,133 @@
+/*
+ * Spreadtrum clock pll configurations
+ *
+ * Copyright (C) 2017 Spreadtrum, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _SPRD_PLL_H_
+#define _SPRD_PLL_H_
+
+#include "common.h"
+
+struct reg_cfg {
+ u32 val;
+ u32 msk;
+};
+
+struct clk_bit_field {
+ u8 shift;
+ u8 width;
+};
+
+enum {
+ PLL_LOCK_DONE,
+ PLL_DIV_S,
+ PLL_MOD_EN,
+ PLL_SDM_EN,
+ PLL_REFIN,
+ PLL_IBIAS,
+ PLL_N,
+ PLL_NINT,
+ PLL_KINT,
+ PLL_PREDIV,
+ PLL_POSTDIV,
+
+ PLL_FACT_MAX
+};
+
+/*
+ * struct sprd_pll - definition of adjustable pll clock
+ *
+ * @reg: registers used to set the configuration of pll clock,
+ * reg[0] shows how many registers this pll clock uses.
+ * @itable: pll ibias table, itable[0] means how many items this
+ * table includes
+ * @udelay delay time after setting rate
+ * @factors used to calculate the pll clock rate
+ * @fvco: fvco threshold rate
+ * @fflag: fvco flag
+ */
+struct sprd_pll {
+ const u32 *regs;
+ const u64 *itable;
+ const struct clk_bit_field *factors;
+ u16 udelay;
+ u16 k1;
+ u16 k2;
+ u16 fflag;
+ u64 fvco;
+
+ struct sprd_clk_common common;
+};
+
+#define SPRD_PLL_WITH_ITABLE_K_FVCO(_struct, _name, _parent, _reg, \
+ _regs, _itable, _factors, _udelay, \
+ _k1, _k2, _fflag, _fvco) \
+ struct sprd_pll _struct = { \
+ .regs = _regs, \
+ .itable = _itable, \
+ .factors = _factors, \
+ .udelay = _udelay, \
+ .k1 = _k1, \
+ .k2 = _k2, \
+ .fflag = _fflag, \
+ .fvco = _fvco, \
+ .common = { \
+ .reg = _reg, \
+ .hw.init = CLK_HW_INIT(_name, \
+ _parent, \
+ &sprd_pll_ops, \
+ 0), \
+ }, \
+ }
+
+#define SPRD_PLL_WITH_ITABLE_K(_struct, _name, _parent, _reg, \
+ _regs, _itable, _factors, \
+ _udelay, _k1, _k2) \
+ SPRD_PLL_WITH_ITABLE_K_FVCO(_struct, _name, _parent, _reg, \
+ _regs, _itable, _factors, \
+ _udelay, _k1, _k2, 0, 0)
+
+#define SPRD_PLL_WITH_ITABLE_1K(_struct, _name, _parent, _reg, \
+ _regs, _itable, _factors, _udelay) \
+ SPRD_PLL_WITH_ITABLE_K_FVCO(_struct, _name, _parent, _reg, \
+ _regs, _itable, _factors, _udelay, \
+ 1000, 1000, 0, 0)
+
+static inline struct sprd_pll *hw_to_sprd_pll(struct clk_hw *hw)
+{
+ struct sprd_clk_common *common = hw_to_sprd_clk_common(hw);
+
+ return container_of(common, struct sprd_pll, common);
+}
+
+static inline u32 sprd_pll_readl(const struct sprd_pll *pll, u8 index)
+{
+ const struct sprd_clk_common *common = &pll->common;
+
+ if (WARN_ON(index >= pll->regs[0]))
+ return 0;
+
+ return readl(common->base + pll->regs[index + 1]);
+}
+
+static inline void sprd_pll_writel(const struct sprd_pll *pll, u8 index,
+ u32 msk, u32 val)
+{
+ const struct sprd_clk_common *common = &pll->common;
+ void __iomem *addr;
+ u32 reg;
+
+ if (WARN_ON(index >= pll->regs[0]))
+ return;
+
+ addr = common->base + pll->regs[index + 1];
+ reg = readl(addr);
+ writel((reg & ~msk) | val, addr);
+}
+
+extern const struct clk_ops sprd_pll_ops;
+
+#endif /* _SPRD_PLL_H_ */
--
2.7.4
[toc] | [prev] | [next] | [standalone]
| From | Chunyan Zhang <chunyan.zhang@spreadtrum.com> |
|---|---|
| Date | 2017-07-11 13:10 +0200 |
| Subject | [PATCH V2 02/10] dt-bindings: Add Spreadtrum clock binding documentation |
| Message-ID | <u21dh-1yp-35@gated-at.bofh.it> |
| In reply to | #1684967 |
Introduce a new binding with its documentation for Spreadtrum clock
sub-framework.
Signed-off-by: Chunyan Zhang <chunyan.zhang@spreadtrum.com>
---
Documentation/devicetree/bindings/clock/sprd.txt | 36 ++++++++++++++++++++++++
1 file changed, 36 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/sprd.txt
diff --git a/Documentation/devicetree/bindings/clock/sprd.txt b/Documentation/devicetree/bindings/clock/sprd.txt
new file mode 100644
index 0000000..c6f3abf
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/sprd.txt
@@ -0,0 +1,36 @@
+Spreadtrum Clock Binding
+------------------------
+
+Required properties:
+- compatible: must contain the following compatible:
+ - "sprd,sc9860-clk" (only support SC9860 for the time being)
+
+- reg: Must contain the registers base address and length.
+ Clocks on most of Spreadtrum's SoCs were designed to locate in a few
+ different address areas, so there would be more than one items under
+ this property.
+
+- #clock-cells: must be 1
+
+Example:
+
+clk: clk {
+ compatible = "sprd,sc9860-clk";
+ #clock-cells = <1>;
+ reg = <0 0x20000000 0 0x400>,
+ <0 0x20210000 0 0x3000>,
+ <0 0x402b0000 0 0x4000>,
+ <0 0x402d0000 0 0x400>,
+ <0 0x402e0000 0 0x4000>,
+ <0 0x40400000 0 0x400>,
+ <0 0x40880000 0 0x400>,
+ <0 0x415e0000 0 0x400>,
+ <0 0x60200000 0 0x400>,
+ <0 0x61000000 0 0x400>,
+ <0 0x61100000 0 0x3000>,
+ <0 0x62000000 0 0x4000>,
+ <0 0x62100000 0 0x4000>,
+ <0 0x63000000 0 0x400>,
+ <0 0x63100000 0 0x3000>,
+ <0 0x70b00000 0 0x3000>;
+};
--
2.7.4
[toc] | [prev] | [next] | [standalone]
| From | Rob Herring <robh@kernel.org> |
|---|---|
| Date | 2017-07-14 18:20 +0200 |
| Subject | Re: [PATCH V2 02/10] dt-bindings: Add Spreadtrum clock binding documentation |
| Message-ID | <u3btU-5Sa-11@gated-at.bofh.it> |
| In reply to | #1684971 |
On Tue, Jul 11, 2017 at 06:56:19PM +0800, Chunyan Zhang wrote: > Introduce a new binding with its documentation for Spreadtrum clock > sub-framework. > > Signed-off-by: Chunyan Zhang <chunyan.zhang@spreadtrum.com> > --- > Documentation/devicetree/bindings/clock/sprd.txt | 36 ++++++++++++++++++++++++ > 1 file changed, 36 insertions(+) > create mode 100644 Documentation/devicetree/bindings/clock/sprd.txt Acked-by: Rob Herring <robh@kernel.org>
[toc] | [prev] | [next] | [standalone]
| From | Chunyan Zhang <zhang.lyra@gmail.com> |
|---|---|
| Date | 2017-07-17 04:10 +0200 |
| Subject | Re: [PATCH V2 02/10] dt-bindings: Add Spreadtrum clock binding documentation |
| Message-ID | <u43E0-7fA-21@gated-at.bofh.it> |
| In reply to | #1687545 |
On 15 July 2017 at 00:10, Rob Herring <robh@kernel.org> wrote: > On Tue, Jul 11, 2017 at 06:56:19PM +0800, Chunyan Zhang wrote: >> Introduce a new binding with its documentation for Spreadtrum clock >> sub-framework. >> >> Signed-off-by: Chunyan Zhang <chunyan.zhang@spreadtrum.com> >> --- >> Documentation/devicetree/bindings/clock/sprd.txt | 36 ++++++++++++++++++++++++ >> 1 file changed, 36 insertions(+) >> create mode 100644 Documentation/devicetree/bindings/clock/sprd.txt > > Acked-by: Rob Herring <robh@kernel.org> Thank you, Rob Cheers, Chunyan
[toc] | [prev] | [next] | [standalone]
| From | Chunyan Zhang <chunyan.zhang@spreadtrum.com> |
|---|---|
| Date | 2017-07-11 13:10 +0200 |
| Subject | [PATCH V2 07/10] clk: sprd: add composite clock support |
| Message-ID | <u21di-1yp-43@gated-at.bofh.it> |
| In reply to | #1684967 |
This patch introduced composite driveri for Spreadtrum's SoCs. The
functions of this composite clock simply consist of divider and
mux clocks.
Original-by: Xiaolong Zhang <xiaolong.zhang@spreadtrum.com>
Signed-off-by: Chunyan Zhang <chunyan.zhang@spreadtrum.com>
---
drivers/clk/sprd/Makefile | 1 +
drivers/clk/sprd/composite.c | 64 ++++++++++++++++++++++++++++++++++++++++++++
drivers/clk/sprd/composite.h | 47 ++++++++++++++++++++++++++++++++
3 files changed, 112 insertions(+)
create mode 100644 drivers/clk/sprd/composite.c
create mode 100644 drivers/clk/sprd/composite.h
diff --git a/drivers/clk/sprd/Makefile b/drivers/clk/sprd/Makefile
index 80e6039..2262e76 100644
--- a/drivers/clk/sprd/Makefile
+++ b/drivers/clk/sprd/Makefile
@@ -4,3 +4,4 @@ clk-sprd-y += common.o
clk-sprd-y += gate.o
clk-sprd-y += mux.o
clk-sprd-y += div.o
+clk-sprd-y += composite.o
diff --git a/drivers/clk/sprd/composite.c b/drivers/clk/sprd/composite.c
new file mode 100644
index 0000000..25b045d
--- /dev/null
+++ b/drivers/clk/sprd/composite.c
@@ -0,0 +1,64 @@
+/*
+ * Spreadtrum composite clock driver
+ *
+ * Copyright (C) 2017 Spreadtrum, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <linux/clk-provider.h>
+
+#include "composite.h"
+
+DEFINE_SPINLOCK(sprd_comp_lock);
+EXPORT_SYMBOL_GPL(sprd_comp_lock);
+
+static long sprd_comp_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct sprd_comp *cc = hw_to_sprd_comp(hw);
+
+ return sprd_div_helper_round_rate(&cc->common, &cc->div,
+ rate, parent_rate);
+}
+
+static unsigned long sprd_comp_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct sprd_comp *cc = hw_to_sprd_comp(hw);
+
+ return sprd_div_helper_recalc_rate(&cc->common, &cc->div, parent_rate);
+}
+
+static int sprd_comp_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct sprd_comp *cc = hw_to_sprd_comp(hw);
+
+ return sprd_div_helper_set_rate(&cc->common, &cc->div,
+ rate, parent_rate);
+}
+
+static u8 sprd_comp_get_parent(struct clk_hw *hw)
+{
+ struct sprd_comp *cc = hw_to_sprd_comp(hw);
+
+ return sprd_mux_helper_get_parent(&cc->common, &cc->mux);
+}
+
+static int sprd_comp_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct sprd_comp *cc = hw_to_sprd_comp(hw);
+
+ return sprd_mux_helper_set_parent(&cc->common, &cc->mux, index);
+}
+
+const struct clk_ops sprd_comp_ops = {
+ .get_parent = sprd_comp_get_parent,
+ .set_parent = sprd_comp_set_parent,
+
+ .round_rate = sprd_comp_round_rate,
+ .recalc_rate = sprd_comp_recalc_rate,
+ .set_rate = sprd_comp_set_rate,
+};
+EXPORT_SYMBOL_GPL(sprd_comp_ops);
diff --git a/drivers/clk/sprd/composite.h b/drivers/clk/sprd/composite.h
new file mode 100644
index 0000000..f5ca0c9
--- /dev/null
+++ b/drivers/clk/sprd/composite.h
@@ -0,0 +1,47 @@
+/*
+ * Spreadtrum composite clock driver
+ *
+ * Copyright (C) 2017 Spreadtrum, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _SPRD_COMPOSITE_H_
+#define _SPRD_COMPOSITE_H_
+
+#include "common.h"
+#include "mux.h"
+#include "div.h"
+
+struct sprd_comp {
+ struct sprd_mux_internal mux;
+ struct sprd_div_internal div;
+ struct sprd_clk_common common;
+};
+
+#define SPRD_COMP_CLK(_struct, _name, _parent, _reg, _table, \
+ _mshift, _mwidth, _dshift, _dwidth, _flags) \
+ struct sprd_comp _struct = { \
+ .mux = _SPRD_MUX_CLK(_mshift, _mwidth, _table), \
+ .div = _SPRD_DIV_CLK(_dshift, _dwidth), \
+ .common = { \
+ .reg = _reg, \
+ .lock = &sprd_comp_lock, \
+ .hw.init = CLK_HW_INIT_PARENTS(_name, \
+ _parent, \
+ &sprd_comp_ops, \
+ _flags), \
+ } \
+ }
+
+static inline struct sprd_comp *hw_to_sprd_comp(const struct clk_hw *hw)
+{
+ struct sprd_clk_common *common = hw_to_sprd_clk_common(hw);
+
+ return container_of(common, struct sprd_comp, common);
+}
+
+extern const struct clk_ops sprd_comp_ops;
+extern spinlock_t sprd_comp_lock;
+
+#endif /* _SPRD_COMPOSITE_H_ */
--
2.7.4
[toc] | [prev] | [next] | [standalone]
| From | Chunyan Zhang <chunyan.zhang@spreadtrum.com> |
|---|---|
| Date | 2017-07-11 13:10 +0200 |
| Subject | [PATCH V2 04/10] clk: sprd: add gate clock support |
| Message-ID | <u21dh-1yp-39@gated-at.bofh.it> |
| In reply to | #1684967 |
Some clocks on the Spreadtrum's SoCs are just simple gates. Add
support for those clocks.
Original-by: Xiaolong Zhang <xiaolong.zhang@spreadtrum.com>
Signed-off-by: Chunyan Zhang <chunyan.zhang@spreadtrum.com>
---
drivers/clk/sprd/Makefile | 1 +
drivers/clk/sprd/gate.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++
drivers/clk/sprd/gate.h | 58 ++++++++++++++++++++++++++
3 files changed, 163 insertions(+)
create mode 100644 drivers/clk/sprd/gate.c
create mode 100644 drivers/clk/sprd/gate.h
diff --git a/drivers/clk/sprd/Makefile b/drivers/clk/sprd/Makefile
index 74f4b80..8cd5592 100644
--- a/drivers/clk/sprd/Makefile
+++ b/drivers/clk/sprd/Makefile
@@ -1,3 +1,4 @@
obj-$(CONFIG_SPRD_COMMON_CLK) += clk-sprd.o
clk-sprd-y += common.o
+clk-sprd-y += gate.o
diff --git a/drivers/clk/sprd/gate.c b/drivers/clk/sprd/gate.c
new file mode 100644
index 0000000..aa56b2b
--- /dev/null
+++ b/drivers/clk/sprd/gate.c
@@ -0,0 +1,104 @@
+/*
+ * Spreadtrum gate clock driver
+ *
+ * Copyright (C) 2017 Spreadtrum, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <linux/clk-provider.h>
+
+#include "gate.h"
+
+DEFINE_SPINLOCK(sprd_gate_lock);
+EXPORT_SYMBOL_GPL(sprd_gate_lock);
+
+static void sprd_gate_endisable(const struct sprd_gate *sg, u32 en)
+{
+ const struct sprd_clk_common *common = &sg->common;
+ unsigned long flags = 0;
+ u32 reg;
+ int set = sg->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0;
+
+ set ^= en;
+
+ spin_lock_irqsave(common->lock, flags);
+
+ reg = sprd_clk_readl(common);
+
+ if (set)
+ reg |= sg->op_bit;
+ else
+ reg &= ~sg->op_bit;
+
+ sprd_clk_writel(reg, common);
+
+ spin_unlock_irqrestore(common->lock, flags);
+}
+
+static void clk_sc_gate_endisable(const struct sprd_gate *sg, u32 en)
+{
+ const struct sprd_clk_common *common = &sg->common;
+ unsigned long flags = 0;
+ int set = sg->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0;
+ u32 offset;
+
+ set ^= en;
+
+ /*
+ * Each set/clear gate clock has three registers:
+ * common->reg - base register
+ * common->reg + offset - set register
+ * common->reg + 2 * offset - clear register
+ */
+ offset = set ? sg->sc_offset : sg->sc_offset * 2;
+
+ spin_lock_irqsave(common->lock, flags);
+ sprd_clk_writel_offset(sg->op_bit, common, offset);
+ spin_unlock_irqrestore(common->lock, flags);
+}
+
+static void sprd_gate_disable(struct clk_hw *hw)
+{
+ struct sprd_gate *sg = hw_to_sprd_gate(hw);
+
+ if (sg->sc_offset)
+ clk_sc_gate_endisable(sg, 0);
+ else
+ sprd_gate_endisable(sg, 0);
+}
+
+static int sprd_gate_enable(struct clk_hw *hw)
+{
+ struct sprd_gate *sg = hw_to_sprd_gate(hw);
+
+ if (sg->sc_offset)
+ clk_sc_gate_endisable(sg, 1);
+ else
+ sprd_gate_endisable(sg, 1);
+
+ return 0;
+}
+
+static int sprd_gate_is_enabled(struct clk_hw *hw)
+{
+ struct sprd_gate *sg = hw_to_sprd_gate(hw);
+ struct sprd_clk_common *common = &sg->common;
+ u32 reg;
+
+ reg = sprd_clk_readl(common);
+
+ if (sg->flags & CLK_GATE_SET_TO_DISABLE)
+ reg ^= sg->op_bit;
+
+ reg &= sg->op_bit;
+
+ return reg ? 1 : 0;
+}
+
+const struct clk_ops sprd_gate_ops = {
+ .disable = sprd_gate_disable,
+ .enable = sprd_gate_enable,
+ .is_enabled = sprd_gate_is_enabled,
+};
+EXPORT_SYMBOL_GPL(sprd_gate_ops);
diff --git a/drivers/clk/sprd/gate.h b/drivers/clk/sprd/gate.h
new file mode 100644
index 0000000..7fb4e49
--- /dev/null
+++ b/drivers/clk/sprd/gate.h
@@ -0,0 +1,58 @@
+/*
+ * Spreadtrum gate clock driver
+ *
+ * Copyright (C) 2017 Spreadtrum, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _SPRD_GATE_H_
+#define _SPRD_GATE_H_
+
+#include "common.h"
+
+struct sprd_gate {
+ u32 op_bit;
+ u16 flags;
+ u16 sc_offset;
+
+ struct sprd_clk_common common;
+};
+
+#define SPRD_GATE_CLK(_struct, _name, _parent, _reg, _sc_offset, \
+ _op_bit, _flags, _gate_flags) \
+ struct sprd_gate _struct = { \
+ .op_bit = _op_bit, \
+ .sc_offset = _sc_offset, \
+ .flags = _gate_flags, \
+ .common = { \
+ .reg = _reg, \
+ .lock = &sprd_gate_lock, \
+ .hw.init = CLK_HW_INIT(_name, \
+ _parent, \
+ &sprd_gate_ops, \
+ _flags), \
+ } \
+ }
+
+static inline struct sprd_gate *hw_to_sprd_gate(const struct clk_hw *hw)
+{
+ struct sprd_clk_common *common = hw_to_sprd_clk_common(hw);
+
+ return container_of(common, struct sprd_gate, common);
+}
+
+static inline void sprd_clk_writel_offset(u32 val,
+ const struct sprd_clk_common *common, u32 offset)
+{
+ writel(val, common->base + common->reg + offset);
+}
+
+void sprd_gate_helper_disable(struct sprd_clk_common *common, u32 gate);
+int sprd_gate_helper_enable(struct sprd_clk_common *common, u32 gate);
+int sprd_gate_helper_is_enabled(struct sprd_clk_common *common, u32 gate);
+
+extern const struct clk_ops sprd_gate_ops;
+extern spinlock_t sprd_gate_lock;
+
+#endif /* _SPRD_GATE_H_ */
--
2.7.4
[toc] | [prev] | [next] | [standalone]
| From | Chunyan Zhang <chunyan.zhang@spreadtrum.com> |
|---|---|
| Date | 2017-07-11 13:10 +0200 |
| Subject | [PATCH V2 03/10] clk: sprd: Add common infrastructure |
| Message-ID | <u21di-1yp-45@gated-at.bofh.it> |
| In reply to | #1684967 |
Added Spreadtrum's clock driver framework together with common
structures and interface functions.
Signed-off-by: Chunyan Zhang <chunyan.zhang@spreadtrum.com>
---
drivers/clk/Kconfig | 1 +
drivers/clk/Makefile | 1 +
drivers/clk/sprd/Kconfig | 4 +++
drivers/clk/sprd/Makefile | 3 ++
drivers/clk/sprd/common.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/clk/sprd/common.h | 56 ++++++++++++++++++++++++++++++++
6 files changed, 148 insertions(+)
create mode 100644 drivers/clk/sprd/Kconfig
create mode 100644 drivers/clk/sprd/Makefile
create mode 100644 drivers/clk/sprd/common.c
create mode 100644 drivers/clk/sprd/common.h
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 36cfea3..baf1688 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -225,6 +225,7 @@ source "drivers/clk/mvebu/Kconfig"
source "drivers/clk/qcom/Kconfig"
source "drivers/clk/renesas/Kconfig"
source "drivers/clk/samsung/Kconfig"
+source "drivers/clk/sprd/Kconfig"
source "drivers/clk/sunxi-ng/Kconfig"
source "drivers/clk/tegra/Kconfig"
source "drivers/clk/ti/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index c19983a..1d62721 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -81,6 +81,7 @@ obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/
obj-$(CONFIG_ARCH_SIRF) += sirf/
obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/
obj-$(CONFIG_PLAT_SPEAR) += spear/
+obj-$(CONFIG_ARCH_SPRD) += sprd/
obj-$(CONFIG_ARCH_STI) += st/
obj-$(CONFIG_ARCH_SUNXI) += sunxi/
obj-$(CONFIG_ARCH_SUNXI) += sunxi-ng/
diff --git a/drivers/clk/sprd/Kconfig b/drivers/clk/sprd/Kconfig
new file mode 100644
index 0000000..67a3287
--- /dev/null
+++ b/drivers/clk/sprd/Kconfig
@@ -0,0 +1,4 @@
+config SPRD_COMMON_CLK
+ tristate "Clock support for Spreadtrum SoCs"
+ depends on ARCH_SPRD || COMPILE_TEST
+ default ARCH_SPRD
diff --git a/drivers/clk/sprd/Makefile b/drivers/clk/sprd/Makefile
new file mode 100644
index 0000000..74f4b80
--- /dev/null
+++ b/drivers/clk/sprd/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_SPRD_COMMON_CLK) += clk-sprd.o
+
+clk-sprd-y += common.o
diff --git a/drivers/clk/sprd/common.c b/drivers/clk/sprd/common.c
new file mode 100644
index 0000000..5ff0473
--- /dev/null
+++ b/drivers/clk/sprd/common.c
@@ -0,0 +1,83 @@
+/*
+ * Spreadtrum clock infrastructure
+ *
+ * Copyright (C) 2017 Spreadtrum, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <linux/module.h>
+
+#include "common.h"
+
+static inline void __iomem *clk_find_base(const struct clk_addr_map *maps,
+ unsigned int num, unsigned int reg)
+{
+ int i;
+
+ for (i = 0; i < num; i++)
+ if ((reg & 0xffff0000) == maps[i].phy)
+ return maps[i].virt;
+
+ return 0;
+}
+
+int sprd_clk_probe(struct device_node *node, const struct clk_addr_map *maps,
+ unsigned int count, const struct sprd_clk_desc *desc)
+{
+ int i, ret = 0;
+ struct sprd_clk_common *cclk;
+ struct clk_hw *hw;
+
+ for (i = 0; i < desc->num_clk_clks; i++) {
+ cclk = desc->clk_clks[i];
+ if (!cclk)
+ continue;
+
+ cclk->base = clk_find_base(maps, count, cclk->reg);
+ if (!cclk->base) {
+ pr_err("%s: No mapped address found for clock(0x%x)\n",
+ __func__, cclk->reg);
+ return -EINVAL;
+ }
+ cclk->reg = cclk->reg & 0xffff;
+ }
+
+ for (i = 0; i < desc->hw_clks->num; i++) {
+
+ hw = desc->hw_clks->hws[i];
+
+ if (!hw)
+ continue;
+
+ ret = clk_hw_register(NULL, hw);
+ if (ret) {
+ pr_err("Couldn't register clock %d - %s\n",
+ i, hw->init->name);
+ goto err_clk_unreg;
+ }
+ }
+
+ ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get,
+ desc->hw_clks);
+ if (ret) {
+ pr_err("Failed to add clock provider.\n");
+ goto err_clk_unreg;
+ }
+
+ return 0;
+
+err_clk_unreg:
+ while (--i >= 0) {
+ hw = desc->hw_clks->hws[i];
+ if (!hw)
+ continue;
+
+ clk_hw_unregister(hw);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(sprd_clk_probe);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/sprd/common.h b/drivers/clk/sprd/common.h
new file mode 100644
index 0000000..c747a7d
--- /dev/null
+++ b/drivers/clk/sprd/common.h
@@ -0,0 +1,56 @@
+/*
+ * Spreadtrum clock infrastructure
+ *
+ * Copyright (C) 2017 Spreadtrum, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef _SPRD_CLK_COMMON_H_
+#define _SPRD_CLK_COMMON_H_
+
+#include <linux/clk-provider.h>
+
+#include "../clk_common.h"
+
+struct device_node;
+
+struct sprd_clk_common {
+ void __iomem *base;
+ u32 reg;
+ spinlock_t *lock;
+ struct clk_hw hw;
+};
+
+struct clk_addr_map {
+ phys_addr_t phy;
+ void __iomem *virt;
+};
+
+static inline u32 sprd_clk_readl(const struct sprd_clk_common *common)
+{
+ return readl(common->base + common->reg);
+}
+
+static inline void sprd_clk_writel(u32 val,
+ const struct sprd_clk_common *common)
+{
+ writel(val, common->base + common->reg);
+}
+
+static inline struct sprd_clk_common *
+ hw_to_sprd_clk_common(const struct clk_hw *hw)
+{
+ return container_of(hw, struct sprd_clk_common, hw);
+}
+
+struct sprd_clk_desc {
+ struct sprd_clk_common **clk_clks;
+ unsigned long num_clk_clks;
+ struct clk_hw_onecell_data *hw_clks;
+};
+
+int sprd_clk_probe(struct device_node *node, const struct clk_addr_map *maps,
+ unsigned int count, const struct sprd_clk_desc *desc);
+
+#endif /* _SPRD_CLK_COMMON_H_ */
--
2.7.4
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web