* [PATCH v3 0/3] clk: keystone: Add common clock drivers
@ 2013-09-26 1:18 Santosh Shilimkar
2013-09-26 1:18 ` [PATCH v3 1/3] clk: keystone: add Keystone PLL clock driver Santosh Shilimkar
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Santosh Shilimkar @ 2013-09-26 1:18 UTC (permalink / raw)
To: linux-arm-kernel
Mike,
Here is the updated version of the series as aligned on the list.
Patchset is also available on my git tree [1]
v3:
Removed the dependency with common clock dt bindings for mux and
divider considering they are still under discussion. Only first
patch has changed from last version.
v2:
- Aligned the bindings as per the list discussion. Removed the additional
parameters by usage of reg-names and additional compatible fields.
- Addressed all the comments from v1 on drivers.
- Split the series into clock drivers($subject series) and
platform, dt updates. Will post that one separately.
Special thanks to Mike and Mark for the detailed review on v1.
Series is an attempt to add the clock drivers for Keystone SOCs
based on common clock framework. A PLL drivers taking care of
SOC PLLs and a gate control driver taking clock management for
the IPs. The current Keystone based SOCs don' support dynamic power
management usecases like DVFS, SOC ilde etc and hence most of the
usage is limited to enabling clocks and finding the current clock
rate etc.
Tested on Keystone2 EVM.
Cc: Mike Turquette <mturquette@linaro.org>
Santosh Shilimkar (3):
clk: keystone: add Keystone PLL clock driver
clk: keystone: Add gate control clock driver
clk: keystone: Build Keystone clock drivers
.../devicetree/bindings/clock/keystone-gate.txt | 29 ++
.../devicetree/bindings/clock/keystone-pll.txt | 84 ++++++
drivers/clk/Kconfig | 7 +
drivers/clk/Makefile | 1 +
drivers/clk/keystone/Makefile | 1 +
drivers/clk/keystone/gate.c | 264 +++++++++++++++++
drivers/clk/keystone/pll.c | 305 ++++++++++++++++++++
7 files changed, 691 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/keystone-gate.txt
create mode 100644 Documentation/devicetree/bindings/clock/keystone-pll.txt
create mode 100644 drivers/clk/keystone/Makefile
create mode 100644 drivers/clk/keystone/gate.c
create mode 100644 drivers/clk/keystone/pll.c
Regards,
Santosh
[1] git://git.kernel.org/pub/scm/linux/kernel/git/ssantosh/linux-keystone.git
for_3.13/keystone/clock
--
1.7.9.5
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v3 1/3] clk: keystone: add Keystone PLL clock driver
2013-09-26 1:18 [PATCH v3 0/3] clk: keystone: Add common clock drivers Santosh Shilimkar
@ 2013-09-26 1:18 ` Santosh Shilimkar
2013-09-26 1:18 ` [PATCH v3 2/3] clk: keystone: Add gate control " Santosh Shilimkar
2013-09-26 1:18 ` [PATCH v3 3/3] clk: keystone: Build Keystone clock drivers Santosh Shilimkar
2 siblings, 0 replies; 6+ messages in thread
From: Santosh Shilimkar @ 2013-09-26 1:18 UTC (permalink / raw)
To: linux-arm-kernel
Add the driver for the PLL IPs found on Keystone 2 devices. The PLL
IP typically has a multiplier, a divider and a post-divider. The PLL IPs like
ARMPLL, DDRPLL and PAPLL are controlled by the memory mapped register where
as the Main PLL is controlled by a PLL controller and memory map registers.
Cc: Mike Turquette <mturquette@linaro.org>
Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
---
.../devicetree/bindings/clock/keystone-pll.txt | 84 ++++++
drivers/clk/keystone/pll.c | 305 ++++++++++++++++++++
2 files changed, 389 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/keystone-pll.txt
create mode 100644 drivers/clk/keystone/pll.c
diff --git a/Documentation/devicetree/bindings/clock/keystone-pll.txt b/Documentation/devicetree/bindings/clock/keystone-pll.txt
new file mode 100644
index 0000000..12bd726
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/keystone-pll.txt
@@ -0,0 +1,84 @@
+Status: Unstable - ABI compatibility may be broken in the future
+
+Binding for keystone PLLs. The main PLL IP typically has a multiplier,
+a divider and a post divider. The additional PLL IPs like ARMPLL, DDRPLL
+and PAPLL are controlled by the memory mapped register where as the Main
+PLL is controlled by a PLL controller registers along with memory mapped
+registers.
+
+This binding uses the common clock binding[1].
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- #clock-cells : from common clock binding; shall be set to 0.
+- compatible : shall be "ti,keystone,main-pll-clock" or "ti,keystone,pll-clock"
+- clocks : parent clock phandle
+- reg - pll control0 and pll multipler registers
+- reg-names : control and multiplier. The multiplier is applicable only for
+ main pll clock
+- fixed-postdiv : fixed post divider value
+
+Example:
+ mainpllclk: mainpllclk at 2310110 {
+ #clock-cells = <0>;
+ compatible = "ti,keystone,main-pll-clock";
+ clocks = <&refclkmain>;
+ reg = <0x02620350 4>, <0x02310110 4>;
+ reg-names = "control", "multiplier";
+ fixed-postdiv = <2>;
+ };
+
+ papllclk: papllclk at 2620358 {
+ #clock-cells = <0>;
+ compatible = "ti,keystone,pll-clock";
+ clocks = <&refclkmain>;
+ clock-output-names = "pa-pll-clk";
+ reg = <0x02620358 4>;
+ reg-names = "control";
+ fixed-postdiv = <6>;
+ };
+
+Required properties:
+- #clock-cells : from common clock binding; shall be set to 0.
+- compatible : shall be "ti,keystone,pll-mux-clock"
+- clocks : link phandles of parent clocks
+- reg - pll mux register
+- bit-shift : number of bits to shift the bit-mask
+- bit-mask : arbitrary bitmask for programming the mux
+
+Optional properties:
+- clock-output-names : From common clock binding.
+
+Example:
+ mainmuxclk: mainmuxclk at 2310108 {
+ #clock-cells = <0>;
+ compatible = "ti,keystone,pll-mux-clock";
+ clocks = <&mainpllclk>, <&refclkmain>;
+ reg = <0x02310108 4>;
+ bit-shift = <23>;
+ bit-mask = <1>;
+ clock-output-names = "mainmuxclk";
+ };
+
+Required properties:
+- #clock-cells : from common clock binding; shall be set to 0.
+- compatible : shall be "ti,keystone,pll-divider-clock"
+- clocks : parent clock phandle
+- reg - pll mux register
+- bit-shift : number of bits to shift the bit-mask
+- bit-mask : arbitrary bitmask for programming the divider
+
+Optional properties:
+- clock-output-names : From common clock binding.
+
+Example:
+ gemtraceclk: gemtraceclk at 2310120 {
+ #clock-cells = <0>;
+ compatible = "ti,keystone,pll-divider-clock";
+ clocks = <&mainmuxclk>;
+ reg = <0x02310120 4>;
+ bit-shift = <0>;
+ bit-mask = <8>;
+ clock-output-names = "gemtraceclk";
+ };
diff --git a/drivers/clk/keystone/pll.c b/drivers/clk/keystone/pll.c
new file mode 100644
index 0000000..c9ebbba
--- /dev/null
+++ b/drivers/clk/keystone/pll.c
@@ -0,0 +1,305 @@
+/*
+ * PLL clock driver for Keystone devices
+ *
+ * Copyright (C) 2013 Texas Instruments Inc.
+ * Murali Karicheri <m-karicheri2@ti.com>
+ * Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/of_address.h>
+#include <linux/of.h>
+#include <linux/module.h>
+
+#define PLLM_LOW_MASK 0x3f
+#define PLLM_HIGH_MASK 0x7ffc0
+#define MAIN_PLLM_HIGH_MASK 0x7f000
+#define PLLM_HIGH_SHIFT 6
+#define PLLD_MASK 0x3f
+
+/**
+ * struct clk_pll_data - pll data structure
+ * @has_pllctrl: If set to non zero, lower 6 bits of multiplier is in pllm
+ * register of pll controller, else it is in the pll_ctrl0((bit 11-6)
+ * @phy_pllm: Physical address of PLLM in pll controller. Used when
+ * has_pllctrl is non zero.
+ * @phy_pll_ctl0: Physical address of PLL ctrl0. This could be that of
+ * Main PLL or any other PLLs in the device such as ARM PLL, DDR PLL
+ * or PA PLL available on keystone2. These PLLs are controlled by
+ * this register. Main PLL is controlled by a PLL controller.
+ * @pllm: PLL register map address
+ * @pll_ctl0: PLL controller map address
+ * @pllm_lower_mask: multiplier lower mask
+ * @pllm_upper_mask: multiplier upper mask
+ * @pllm_upper_shift: multiplier upper shift
+ * @plld_mask: divider mask
+ * @postdiv: Post divider
+ */
+struct clk_pll_data {
+ bool has_pllctrl;
+ u32 phy_pllm;
+ u32 phy_pll_ctl0;
+ void __iomem *pllm;
+ void __iomem *pll_ctl0;
+ u32 pllm_lower_mask;
+ u32 pllm_upper_mask;
+ u32 pllm_upper_shift;
+ u32 plld_mask;
+ u32 postdiv;
+};
+
+/**
+ * struct clk_pll - Main pll clock
+ * @hw: clk_hw for the pll
+ * @pll_data: PLL driver specific data
+ */
+struct clk_pll {
+ struct clk_hw hw;
+ struct clk_pll_data *pll_data;
+};
+
+#define to_clk_pll(_hw) container_of(_hw, struct clk_pll, hw)
+
+static unsigned long clk_pllclk_recalc(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_pll *pll = to_clk_pll(hw);
+ struct clk_pll_data *pll_data = pll->pll_data;
+ unsigned long rate = parent_rate;
+ u32 mult = 0, prediv, postdiv, val;
+
+ /*
+ * get bits 0-5 of multiplier from pllctrl PLLM register
+ * if has_pllctrl is non zero
+ */
+ if (pll_data->has_pllctrl) {
+ val = readl(pll_data->pllm);
+ mult = (val & pll_data->pllm_lower_mask);
+ }
+
+ /* bit6-12 of PLLM is in Main PLL control register */
+ val = readl(pll_data->pll_ctl0);
+ mult |= ((val & pll_data->pllm_upper_mask)
+ >> pll_data->pllm_upper_shift);
+ prediv = (val & pll_data->plld_mask);
+ postdiv = pll_data->postdiv;
+
+ rate /= (prediv + 1);
+ rate = (rate * (mult + 1));
+ rate /= postdiv;
+
+ return rate;
+}
+
+static const struct clk_ops clk_pll_ops = {
+ .recalc_rate = clk_pllclk_recalc,
+};
+
+static struct clk *clk_register_pll(struct device *dev,
+ const char *name,
+ const char *parent_name,
+ struct clk_pll_data *pll_data)
+{
+ struct clk_init_data init;
+ struct clk_pll *pll;
+ struct clk *clk;
+
+ pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+ if (!pll)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &clk_pll_ops;
+ init.flags = 0;
+ init.parent_names = (parent_name ? &parent_name : NULL);
+ init.num_parents = (parent_name ? 1 : 0);
+
+ pll->pll_data = pll_data;
+ pll->hw.init = &init;
+
+ clk = clk_register(NULL, &pll->hw);
+ if (IS_ERR(clk))
+ goto out;
+
+ return clk;
+out:
+ kfree(pll);
+ return NULL;
+}
+
+/**
+ * _of_clk_init - PLL initialisation via DT
+ * @node: device tree node for this clock
+ * @pllctrl: If true, lower 6 bits of multiplier is in pllm register of
+ * pll controller, else it is in the control regsiter0(bit 11-6)
+ */
+static void __init _of_pll_clk_init(struct device_node *node, bool pllctrl)
+{
+ struct clk_pll_data *pll_data;
+ const char *parent_name;
+ struct clk *clk;
+ int i;
+
+ pll_data = kzalloc(sizeof(*pll_data), GFP_KERNEL);
+ if (!pll_data) {
+ pr_err("%s: Out of memory\n", __func__);
+ return;
+ }
+
+ parent_name = of_clk_get_parent_name(node, 0);
+ if (of_property_read_u32(node, "fixed-postdiv", &pll_data->postdiv))
+ goto out;
+
+ i = of_property_match_string(node, "reg-names", "control");
+ pll_data->pll_ctl0 = of_iomap(node, i);
+ if (!pll_data->pll_ctl0) {
+ pr_err("%s: ioremap failed\n", __func__);
+ goto out;
+ }
+
+ pll_data->pllm_lower_mask = PLLM_LOW_MASK;
+ pll_data->pllm_upper_shift = PLLM_HIGH_SHIFT;
+ pll_data->plld_mask = PLLD_MASK;
+ pll_data->has_pllctrl = pllctrl;
+ if (!pll_data->has_pllctrl) {
+ pll_data->pllm_upper_mask = PLLM_HIGH_MASK;
+ } else {
+ pll_data->pllm_upper_mask = MAIN_PLLM_HIGH_MASK;
+ i = of_property_match_string(node, "reg-names", "multiplier");
+ pll_data->pllm = of_iomap(node, i);
+ if (!pll_data->pllm) {
+ iounmap(pll_data->pll_ctl0);
+ goto out;
+ }
+ }
+
+ clk = clk_register_pll(NULL, node->name, parent_name, pll_data);
+ if (clk) {
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ return;
+ }
+
+out:
+ pr_err("%s: error initializing pll %s\n", __func__, node->name);
+ kfree(pll_data);
+}
+
+/**
+ * of_keystone_pll_clk_init - PLL initialisation DT wrapper
+ * @node: device tree node for this clock
+ */
+static void __init of_keystone_pll_clk_init(struct device_node *node)
+{
+ _of_pll_clk_init(node, false);
+}
+CLK_OF_DECLARE(keystone_pll_clock, "ti,keystone,pll-clock",
+ of_keystone_pll_clk_init);
+
+/**
+ * of_keystone_pll_main_clk_init - Main PLL initialisation DT wrapper
+ * @node: device tree node for this clock
+ */
+static void __init of_keystone_main_pll_clk_init(struct device_node *node)
+{
+ _of_pll_clk_init(node, true);
+}
+CLK_OF_DECLARE(keystone_main_pll_clock, "ti,keystone,main-pll-clock",
+ of_keystone_main_pll_clk_init);
+
+/**
+ * of_pll_div_clk_init - PLL divider setup function
+ * @node: device tree node for this clock
+ */
+static void __init of_pll_div_clk_init(struct device_node *node)
+{
+ const char *parent_name;
+ void __iomem *reg;
+ u32 shift, mask;
+ struct clk *clk;
+ const char *clk_name = node->name;
+
+ of_property_read_string(node, "clock-output-names", &clk_name);
+ reg = of_iomap(node, 0);
+ if (!reg) {
+ pr_err("%s: ioremap failed\n", __func__);
+ return;
+ }
+
+ parent_name = of_clk_get_parent_name(node, 0);
+ if (!parent_name) {
+ pr_err("%s: missing parent clock\n", __func__);
+ return;
+ }
+
+ if (of_property_read_u32(node, "bit-shift", &shift)) {
+ pr_err("%s: missing 'shift' property\n", __func__);
+ return;
+ }
+
+ if (of_property_read_u32(node, "bit-mask", &mask)) {
+ pr_err("%s: missing 'bit-mask' property\n", __func__);
+ return;
+ }
+
+ clk = clk_register_divider(NULL, clk_name, parent_name, 0, reg, shift,
+ mask, 0, NULL);
+ if (clk)
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ else
+ pr_err("%s: error registering divider %s\n", __func__, clk_name);
+}
+CLK_OF_DECLARE(pll_divider_clock, "ti,keystone,pll-divider-clock", of_pll_div_clk_init);
+
+/**
+ * of_pll_mux_clk_init - PLL mux setup function
+ * @node: device tree node for this clock
+ */
+static void __init of_pll_mux_clk_init(struct device_node *node)
+{
+ void __iomem *reg;
+ u32 shift, mask;
+ struct clk *clk;
+ const char *parents[2];
+ const char *clk_name = node->name;
+
+ of_property_read_string(node, "clock-output-names", &clk_name);
+ reg = of_iomap(node, 0);
+ if (!reg) {
+ pr_err("%s: ioremap failed\n", __func__);
+ return;
+ }
+
+ parents[0] = of_clk_get_parent_name(node, 0);
+ parents[1] = of_clk_get_parent_name(node, 1);
+ if (!parents[0] || !parents[1]) {
+ pr_err("%s: missing parent clocks\n", __func__);
+ return;
+ }
+
+ if (of_property_read_u32(node, "bit-shift", &shift)) {
+ pr_err("%s: missing 'shift' property\n", __func__);
+ return;
+ }
+
+ if (of_property_read_u32(node, "bit-mask", &mask)) {
+ pr_err("%s: missing 'bit-mask' property\n", __func__);
+ return;
+ }
+
+ clk = clk_register_mux(NULL, clk_name, (const char **)&parents,
+ ARRAY_SIZE(parents) , 0, reg, shift, mask,
+ 0, NULL);
+ if (clk)
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ else
+ pr_err("%s: error registering mux %s\n", __func__, clk_name);
+}
+CLK_OF_DECLARE(pll_mux_clock, "ti,keystone,pll-mux-clock", of_pll_mux_clk_init);
--
1.7.9.5
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v3 2/3] clk: keystone: Add gate control clock driver
2013-09-26 1:18 [PATCH v3 0/3] clk: keystone: Add common clock drivers Santosh Shilimkar
2013-09-26 1:18 ` [PATCH v3 1/3] clk: keystone: add Keystone PLL clock driver Santosh Shilimkar
@ 2013-09-26 1:18 ` Santosh Shilimkar
2013-09-26 1:18 ` [PATCH v3 3/3] clk: keystone: Build Keystone clock drivers Santosh Shilimkar
2 siblings, 0 replies; 6+ messages in thread
From: Santosh Shilimkar @ 2013-09-26 1:18 UTC (permalink / raw)
To: linux-arm-kernel
Add the driver for the clock gate control which uses PSC (Power Sleep
Controller) IP on Keystone 2 based SOCs. It is responsible for enabling and
disabling of the clocks for different IPs present in the SoC.
Cc: Mike Turquette <mturquette@linaro.org>
Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
---
.../devicetree/bindings/clock/keystone-gate.txt | 29 +++
drivers/clk/keystone/gate.c | 264 ++++++++++++++++++++
2 files changed, 293 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/keystone-gate.txt
create mode 100644 drivers/clk/keystone/gate.c
diff --git a/Documentation/devicetree/bindings/clock/keystone-gate.txt b/Documentation/devicetree/bindings/clock/keystone-gate.txt
new file mode 100644
index 0000000..c5aa187
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/keystone-gate.txt
@@ -0,0 +1,29 @@
+Status: Unstable - ABI compatibility may be broken in the future
+
+Binding for Keystone gate control driver which uses PSC controller IP.
+
+This binding uses the common clock binding[1].
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible : shall be "ti,keystone,psc-clock".
+- #clock-cells : from common clock binding; shall be set to 0.
+- clocks : parent clock phandle
+- reg : psc control and domain address address space
+- reg-names : psc control and domain registers
+- domain-id : psc domain id needed to check the transition state register
+
+Optional properties:
+- clock-output-names : From common clock binding to override the
+ default output clock name
+Example:
+ clkusb: clkusb {
+ #clock-cells = <0>;
+ compatible = "ti,keystone,psc-clock";
+ clocks = <&chipclk16>;
+ clock-output-names = "usb";
+ reg = <0x02350008 0xb00>, <0x02350000 0x400>;
+ reg-names = "control", "domain";
+ domain-id = <0>;
+ };
diff --git a/drivers/clk/keystone/gate.c b/drivers/clk/keystone/gate.c
new file mode 100644
index 0000000..1f333bc
--- /dev/null
+++ b/drivers/clk/keystone/gate.c
@@ -0,0 +1,264 @@
+/*
+ * Clock driver for Keystone 2 based devices
+ *
+ * Copyright (C) 2013 Texas Instruments.
+ * Murali Karicheri <m-karicheri2@ti.com>
+ * Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/of_address.h>
+#include <linux/of.h>
+#include <linux/module.h>
+
+/* PSC register offsets */
+#define PTCMD 0x120
+#define PTSTAT 0x128
+#define PDSTAT 0x200
+#define PDCTL 0x300
+#define MDSTAT 0x800
+#define MDCTL 0xa00
+
+/* PSC module states */
+#define PSC_STATE_SWRSTDISABLE 0
+#define PSC_STATE_SYNCRST 1
+#define PSC_STATE_DISABLE 2
+#define PSC_STATE_ENABLE 3
+
+#define MDSTAT_STATE_MASK 0x3f
+#define MDSTAT_MCKOUT BIT(12)
+#define PDSTAT_STATE_MASK 0x1f
+#define MDCTL_FORCE BIT(31)
+#define MDCTL_LRESET BIT(8)
+#define PDCTL_NEXT BIT(0)
+
+/* Maximum timeout to bail out state transition for module */
+#define STATE_TRANS_MAX_COUNT 0xffff
+
+static void __iomem *domain_transition_base;
+
+/**
+ * struct clk_psc_data - PSC data
+ * @control_base: Base address for a PSC control
+ * @domain_base: Base address for a PSC domain
+ * @domain_id: PSC domain id number
+ */
+struct clk_psc_data {
+ void __iomem *control_base;
+ void __iomem *domain_base;
+ u32 domain_id;
+};
+
+/**
+ * struct clk_psc - PSC clock structure
+ * @hw: clk_hw for the psc
+ * @psc_data: PSC driver specific data
+ * @lock: Spinlock used by the driver
+ */
+struct clk_psc {
+ struct clk_hw hw;
+ struct clk_psc_data *psc_data;
+ spinlock_t *lock;
+};
+
+static DEFINE_SPINLOCK(psc_lock);
+
+#define to_clk_psc(_hw) container_of(_hw, struct clk_psc, hw)
+
+static void psc_config(void __iomem *control_base, void __iomem *domain_base,
+ u32 next_state, u32 domain_id)
+{
+ u32 ptcmd, pdstat, pdctl, mdstat, mdctl, ptstat;
+ u32 count = STATE_TRANS_MAX_COUNT;
+
+ mdctl = readl(control_base + MDCTL);
+ mdctl &= ~MDSTAT_STATE_MASK;
+ mdctl |= next_state;
+ /* For disable, we always put the module in local reset */
+ if (next_state == PSC_STATE_DISABLE)
+ mdctl &= ~MDCTL_LRESET;
+ writel(mdctl, control_base + MDCTL);
+
+ pdstat = readl(domain_base + PDSTAT);
+ if (!(pdstat & PDSTAT_STATE_MASK)) {
+ pdctl = readl(domain_base + PDCTL);
+ pdctl |= PDCTL_NEXT;
+ writel(pdctl, domain_base + PDCTL);
+ }
+
+ ptcmd = 1 << domain_id;
+ writel(ptcmd, domain_transition_base + PTCMD);
+ do {
+ ptstat = readl(domain_transition_base + PTSTAT);
+ } while (((ptstat >> domain_id) & 1) && count--);
+
+ count = STATE_TRANS_MAX_COUNT;
+ do {
+ mdstat = readl(control_base + MDSTAT);
+ } while (!((mdstat & MDSTAT_STATE_MASK) == next_state) && count--);
+}
+
+static int keystone_clk_is_enabled(struct clk_hw *hw)
+{
+ struct clk_psc *psc = to_clk_psc(hw);
+ struct clk_psc_data *data = psc->psc_data;
+ u32 mdstat = readl(data->control_base + MDSTAT);
+
+ return (mdstat & MDSTAT_MCKOUT) ? 1 : 0;
+}
+
+static int keystone_clk_enable(struct clk_hw *hw)
+{
+ struct clk_psc *psc = to_clk_psc(hw);
+ struct clk_psc_data *data = psc->psc_data;
+ unsigned long flags = 0;
+
+ if (psc->lock)
+ spin_lock_irqsave(psc->lock, flags);
+
+ psc_config(data->control_base, data->domain_base,
+ PSC_STATE_ENABLE, data->domain_id);
+
+ if (psc->lock)
+ spin_unlock_irqrestore(psc->lock, flags);
+
+ return 0;
+}
+
+static void keystone_clk_disable(struct clk_hw *hw)
+{
+ struct clk_psc *psc = to_clk_psc(hw);
+ struct clk_psc_data *data = psc->psc_data;
+ unsigned long flags = 0;
+
+ if (psc->lock)
+ spin_lock_irqsave(psc->lock, flags);
+
+ psc_config(data->control_base, data->domain_base,
+ PSC_STATE_DISABLE, data->domain_id);
+
+ if (psc->lock)
+ spin_unlock_irqrestore(psc->lock, flags);
+}
+
+static const struct clk_ops clk_psc_ops = {
+ .enable = keystone_clk_enable,
+ .disable = keystone_clk_disable,
+ .is_enabled = keystone_clk_is_enabled,
+};
+
+/**
+ * clk_register_psc - register psc clock
+ * @dev: device that is registering this clock
+ * @name: name of this clock
+ * @parent_name: name of clock's parent
+ * @psc_data: platform data to configure this clock
+ * @lock: spinlock used by this clock
+ */
+static struct clk *clk_register_psc(struct device *dev,
+ const char *name,
+ const char *parent_name,
+ struct clk_psc_data *psc_data,
+ spinlock_t *lock)
+{
+ struct clk_init_data init;
+ struct clk_psc *psc;
+ struct clk *clk;
+
+ psc = kzalloc(sizeof(*psc), GFP_KERNEL);
+ if (!psc)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &clk_psc_ops;
+ init.parent_names = (parent_name ? &parent_name : NULL);
+ init.num_parents = (parent_name ? 1 : 0);
+
+ psc->psc_data = psc_data;
+ psc->lock = lock;
+ psc->hw.init = &init;
+
+ clk = clk_register(NULL, &psc->hw);
+ if (IS_ERR(clk))
+ kfree(psc);
+
+ return clk;
+}
+
+/**
+ * of_psc_clk_init - initialize psc clock through DT
+ * @node: device tree node for this clock
+ * @lock: spinlock used by this clock
+ */
+static void __init of_psc_clk_init(struct device_node *node, spinlock_t *lock)
+{
+ const char *clk_name = node->name;
+ const char *parent_name;
+ struct clk_psc_data *data;
+ struct clk *clk;
+ int i;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ pr_err("%s: Out of memory\n", __func__);
+ return;
+ }
+
+ i = of_property_match_string(node, "reg-names", "control");
+ data->control_base = of_iomap(node, i);
+ if (!data->control_base) {
+ pr_err("%s: control ioremap failed\n", __func__);
+ goto out;
+ }
+
+ i = of_property_match_string(node, "reg-names", "domain");
+ data->domain_base = of_iomap(node, i);
+ if (!data->domain_base) {
+ pr_err("%s: domain ioremap failed\n", __func__);
+ iounmap(data->control_base);
+ goto out;
+ }
+
+ of_property_read_u32(node, "domain-id", &data->domain_id);
+
+ /* Domain transition registers at fixed address space of domain_id 0 */
+ if (!domain_transition_base && !data->domain_id)
+ domain_transition_base = data->domain_base;
+
+ of_property_read_string(node, "clock-output-names", &clk_name);
+ parent_name = of_clk_get_parent_name(node, 0);
+ if (!parent_name) {
+ pr_err("%s: Parent clock not found\n", __func__);
+ goto out;
+ }
+
+ clk = clk_register_psc(NULL, clk_name, parent_name, data, lock);
+ if (clk) {
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ return;
+ }
+
+ pr_err("%s: error registering clk %s\n", __func__, node->name);
+out:
+ kfree(data);
+ return;
+}
+
+/**
+ * of_keystone_psc_clk_init - initialize psc clock through DT
+ * @node: device tree node for this clock
+ */
+static void __init of_keystone_psc_clk_init(struct device_node *node)
+{
+ of_psc_clk_init(node, &psc_lock);
+}
+CLK_OF_DECLARE(keystone_gate_clk, "ti,keystone,psc-clock",
+ of_keystone_psc_clk_init);
--
1.7.9.5
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v3 3/3] clk: keystone: Build Keystone clock drivers
2013-09-26 1:18 [PATCH v3 0/3] clk: keystone: Add common clock drivers Santosh Shilimkar
2013-09-26 1:18 ` [PATCH v3 1/3] clk: keystone: add Keystone PLL clock driver Santosh Shilimkar
2013-09-26 1:18 ` [PATCH v3 2/3] clk: keystone: Add gate control " Santosh Shilimkar
@ 2013-09-26 1:18 ` Santosh Shilimkar
2013-10-08 1:28 ` Mike Turquette
2 siblings, 1 reply; 6+ messages in thread
From: Santosh Shilimkar @ 2013-09-26 1:18 UTC (permalink / raw)
To: linux-arm-kernel
Now build the keystone common clock drivers. The build is made
conditional based on COMMON_CLK_KEYSTONE
Cc: Mike Turquette <mturquette@linaro.org>
Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
---
drivers/clk/Kconfig | 7 +++++++
drivers/clk/Makefile | 1 +
drivers/clk/keystone/Makefile | 1 +
3 files changed, 9 insertions(+)
create mode 100644 drivers/clk/keystone/Makefile
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 279407a..10f85cc 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -93,6 +93,13 @@ config CLK_PPC_CORENET
This adds the clock driver support for Freescale PowerPC corenet
platforms using common clock framework.
+config COMMON_CLK_KEYSTONE
+ tristate "Clock drivers for Keystone based SOCs"
+ depends on ARCH_KEYSTONE && OF
+ ---help---
+ Supports clock drivers for Keystone based SOCs. These SOCs have local
+ a power sleep control module that gate the clock to the IPs and PLLs.
+
endmenu
source "drivers/clk/mvebu/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 7b11106..2a44d533 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o
obj-$(CONFIG_ARCH_ZYNQ) += zynq/
obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-$(CONFIG_PLAT_SAMSUNG) += samsung/
+obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/
obj-$(CONFIG_X86) += x86/
diff --git a/drivers/clk/keystone/Makefile b/drivers/clk/keystone/Makefile
new file mode 100644
index 0000000..0477cf6
--- /dev/null
+++ b/drivers/clk/keystone/Makefile
@@ -0,0 +1 @@
+obj-y += pll.o gate.o
--
1.7.9.5
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v3 3/3] clk: keystone: Build Keystone clock drivers
2013-09-26 1:18 ` [PATCH v3 3/3] clk: keystone: Build Keystone clock drivers Santosh Shilimkar
@ 2013-10-08 1:28 ` Mike Turquette
2013-10-08 13:05 ` Santosh Shilimkar
0 siblings, 1 reply; 6+ messages in thread
From: Mike Turquette @ 2013-10-08 1:28 UTC (permalink / raw)
To: linux-arm-kernel
Quoting Santosh Shilimkar (2013-09-25 18:18:15)
> Now build the keystone common clock drivers. The build is made
> conditional based on COMMON_CLK_KEYSTONE
>
> Cc: Mike Turquette <mturquette@linaro.org>
>
> Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
> ---
> drivers/clk/Kconfig | 7 +++++++
> drivers/clk/Makefile | 1 +
> drivers/clk/keystone/Makefile | 1 +
> 3 files changed, 9 insertions(+)
> create mode 100644 drivers/clk/keystone/Makefile
>
> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
> index 279407a..10f85cc 100644
> --- a/drivers/clk/Kconfig
> +++ b/drivers/clk/Kconfig
> @@ -93,6 +93,13 @@ config CLK_PPC_CORENET
> This adds the clock driver support for Freescale PowerPC corenet
> platforms using common clock framework.
>
> +config COMMON_CLK_KEYSTONE
> + tristate "Clock drivers for Keystone based SOCs"
> + depends on ARCH_KEYSTONE && OF
> + ---help---
> + Supports clock drivers for Keystone based SOCs. These SOCs have local
> + a power sleep control module that gate the clock to the IPs and PLLs.
> +
> endmenu
>
> source "drivers/clk/mvebu/Kconfig"
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index 7b11106..2a44d533 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -32,6 +32,7 @@ obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o
> obj-$(CONFIG_ARCH_ZYNQ) += zynq/
> obj-$(CONFIG_ARCH_TEGRA) += tegra/
> obj-$(CONFIG_PLAT_SAMSUNG) += samsung/
> +obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/
Thanks for respinning these patches Santosh. They look good and I've
taken them into clk-next for 3.13.
My only question: why CONFIG_COMMON_CLK_KEYSTONE and not just
CONFIG_ARCH_KEYSTONE above? This is not a blocking issue and can be
revisited later.
Regards,
Mike
>
> obj-$(CONFIG_X86) += x86/
>
> diff --git a/drivers/clk/keystone/Makefile b/drivers/clk/keystone/Makefile
> new file mode 100644
> index 0000000..0477cf6
> --- /dev/null
> +++ b/drivers/clk/keystone/Makefile
> @@ -0,0 +1 @@
> +obj-y += pll.o gate.o
> --
> 1.7.9.5
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v3 3/3] clk: keystone: Build Keystone clock drivers
2013-10-08 1:28 ` Mike Turquette
@ 2013-10-08 13:05 ` Santosh Shilimkar
0 siblings, 0 replies; 6+ messages in thread
From: Santosh Shilimkar @ 2013-10-08 13:05 UTC (permalink / raw)
To: linux-arm-kernel
On Monday 07 October 2013 09:28 PM, Mike Turquette wrote:
> Quoting Santosh Shilimkar (2013-09-25 18:18:15)
>> Now build the keystone common clock drivers. The build is made
>> conditional based on COMMON_CLK_KEYSTONE
>>
>> Cc: Mike Turquette <mturquette@linaro.org>
>>
>> Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
>> ---
>> drivers/clk/Kconfig | 7 +++++++
>> drivers/clk/Makefile | 1 +
>> drivers/clk/keystone/Makefile | 1 +
>> 3 files changed, 9 insertions(+)
>> create mode 100644 drivers/clk/keystone/Makefile
>>
>> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
>> index 279407a..10f85cc 100644
>> --- a/drivers/clk/Kconfig
>> +++ b/drivers/clk/Kconfig
>> @@ -93,6 +93,13 @@ config CLK_PPC_CORENET
>> This adds the clock driver support for Freescale PowerPC corenet
>> platforms using common clock framework.
>>
>> +config COMMON_CLK_KEYSTONE
>> + tristate "Clock drivers for Keystone based SOCs"
>> + depends on ARCH_KEYSTONE && OF
>> + ---help---
>> + Supports clock drivers for Keystone based SOCs. These SOCs have local
>> + a power sleep control module that gate the clock to the IPs and PLLs.
>> +
>> endmenu
>>
>> source "drivers/clk/mvebu/Kconfig"
>> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
>> index 7b11106..2a44d533 100644
>> --- a/drivers/clk/Makefile
>> +++ b/drivers/clk/Makefile
>> @@ -32,6 +32,7 @@ obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o
>> obj-$(CONFIG_ARCH_ZYNQ) += zynq/
>> obj-$(CONFIG_ARCH_TEGRA) += tegra/
>> obj-$(CONFIG_PLAT_SAMSUNG) += samsung/
>> +obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/
>
> Thanks for respinning these patches Santosh. They look good and I've
> taken them into clk-next for 3.13.
>
Great.
> My only question: why CONFIG_COMMON_CLK_KEYSTONE and not just
> CONFIG_ARCH_KEYSTONE above? This is not a blocking issue and can be
> revisited later.
>
The clock Kconfig had few arch using directly ARCH defines as few creating
arch CCF. I gone ahead with CCF bunch. Probably we can just make that
consistent for all other arch in future as you said.
Thanks a lot Mike.
Regards,
Santosh
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2013-10-08 13:05 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-09-26 1:18 [PATCH v3 0/3] clk: keystone: Add common clock drivers Santosh Shilimkar
2013-09-26 1:18 ` [PATCH v3 1/3] clk: keystone: add Keystone PLL clock driver Santosh Shilimkar
2013-09-26 1:18 ` [PATCH v3 2/3] clk: keystone: Add gate control " Santosh Shilimkar
2013-09-26 1:18 ` [PATCH v3 3/3] clk: keystone: Build Keystone clock drivers Santosh Shilimkar
2013-10-08 1:28 ` Mike Turquette
2013-10-08 13:05 ` Santosh Shilimkar
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).