summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Rothwell <sfr@canb.auug.org.au>2014-09-12 16:05:49 +1000
committerStephen Rothwell <sfr@canb.auug.org.au>2014-09-12 16:05:49 +1000
commitf4a0a26b524431b3e2684101682e94c320a48385 (patch)
tree9405e92501459bd2d614661599aa49c6c4657d0a
parentb6c39dd7b012235aebbbde1865614bb787b5dc96 (diff)
parent0469a43bc32001e63092df87c2d1fdf588ea7b3a (diff)
Merge remote-tracking branch 'clk/clk-next'
Conflicts: Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt
-rw-r--r--Documentation/devicetree/bindings/clock/maxim,max77686.txt16
-rw-r--r--Documentation/devicetree/bindings/clock/maxim,max77802.txt44
-rw-r--r--Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt1
-rw-r--r--Documentation/devicetree/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt1
-rw-r--r--drivers/clk/Kconfig11
-rw-r--r--drivers/clk/Makefile2
-rw-r--r--drivers/clk/at91/clk-pll.c160
-rw-r--r--drivers/clk/at91/clk-usb.c20
-rw-r--r--drivers/clk/clk-fractional-divider.c2
-rw-r--r--drivers/clk/clk-max-gen.c192
-rw-r--r--drivers/clk/clk-max-gen.h32
-rw-r--r--drivers/clk/clk-max77686.c183
-rw-r--r--drivers/clk/clk-max77802.c98
-rw-r--r--drivers/clk/clk.c73
-rw-r--r--drivers/clk/mvebu/common.c9
-rw-r--r--drivers/clk/mvebu/common.h2
-rw-r--r--drivers/clk/mvebu/kirkwood.c102
-rw-r--r--drivers/clk/rockchip/clk-rk3188.c8
-rw-r--r--drivers/clk/rockchip/clk-rk3288.c8
-rw-r--r--drivers/clk/rockchip/clk.c73
-rw-r--r--drivers/clk/rockchip/clk.h1
-rw-r--r--drivers/clk/shmobile/clk-rcar-gen2.c1
-rw-r--r--drivers/clk/zynq/clkc.c30
-rw-r--r--drivers/clk/zynq/pll.c4
-rw-r--r--drivers/cpufreq/kirkwood-cpufreq.c14
-rw-r--r--include/dt-bindings/clock/maxim,max77686.h23
-rw-r--r--include/dt-bindings/clock/maxim,max77802.h22
-rw-r--r--include/linux/clk-private.h1
28 files changed, 788 insertions, 345 deletions
diff --git a/Documentation/devicetree/bindings/clock/maxim,max77686.txt b/Documentation/devicetree/bindings/clock/maxim,max77686.txt
index 96ce71bbd745..9c40739a661a 100644
--- a/Documentation/devicetree/bindings/clock/maxim,max77686.txt
+++ b/Documentation/devicetree/bindings/clock/maxim,max77686.txt
@@ -9,13 +9,21 @@ The MAX77686 contains three 32.768khz clock outputs that can be controlled
Following properties should be presend in main device node of the MFD chip.
Required properties:
-- #clock-cells: simple one-cell clock specifier format is used, where the
- only cell is used as an index of the clock inside the provider. Following
- indices are allowed:
+
+- #clock-cells: from common clock binding; shall be set to 1.
+
+Optional properties:
+- clock-output-names: From common clock binding.
+
+Each clock is assigned an identifier and client nodes can use this identifier
+to specify the clock which they consume. Following indices are allowed:
- 0: 32khz_ap clock,
- 1: 32khz_cp clock,
- 2: 32khz_pmic clock.
+Clocks are defined as preprocessor macros in dt-bindings/clock/maxim,max77686.h
+header and can be used in device tree sources.
+
Example: Node of the MFD chip
max77686: max77686@09 {
@@ -34,5 +42,5 @@ Example: Clock consumer node
compatible = "bar,foo";
/* ... */
clock-names = "my-clock";
- clocks = <&max77686 2>;
+ clocks = <&max77686 MAX77686_CLK_PMIC>;
};
diff --git a/Documentation/devicetree/bindings/clock/maxim,max77802.txt b/Documentation/devicetree/bindings/clock/maxim,max77802.txt
new file mode 100644
index 000000000000..c6dc7835f06c
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/maxim,max77802.txt
@@ -0,0 +1,44 @@
+Binding for Maxim MAX77802 32k clock generator block
+
+This is a part of device tree bindings of MAX77802 multi-function device.
+More information can be found in bindings/mfd/max77802.txt file.
+
+The MAX77802 contains two 32.768khz clock outputs that can be controlled
+(gated/ungated) over I2C.
+
+Following properties should be present in main device node of the MFD chip.
+
+Required properties:
+- #clock-cells: From common clock binding; shall be set to 1.
+
+Optional properties:
+- clock-output-names: From common clock binding.
+
+Each clock is assigned an identifier and client nodes can use this identifier
+to specify the clock which they consume. Following indices are allowed:
+ - 0: 32khz_ap clock,
+ - 1: 32khz_cp clock.
+
+Clocks are defined as preprocessor macros in dt-bindings/clock/maxim,max77802.h
+header and can be used in device tree sources.
+
+Example: Node of the MFD chip
+
+ max77802: max77802@09 {
+ compatible = "maxim,max77802";
+ interrupt-parent = <&wakeup_eint>;
+ interrupts = <26 0>;
+ reg = <0x09>;
+ #clock-cells = <1>;
+
+ /* ... */
+ };
+
+Example: Clock consumer node
+
+ foo@0 {
+ compatible = "bar,foo";
+ /* ... */
+ clock-names = "my-clock";
+ clocks = <&max77802 MAX77802_CLK_32K_AP>;
+ };
diff --git a/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt b/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt
index 8f1424f0fa43..a5f52238c80d 100644
--- a/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt
+++ b/Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt
@@ -15,6 +15,7 @@ Required Properties:
- "renesas,r8a7779-mstp-clocks" for R8A7779 (R-Car H1) MSTP gate clocks
- "renesas,r8a7790-mstp-clocks" for R8A7790 (R-Car H2) MSTP gate clocks
- "renesas,r8a7791-mstp-clocks" for R8A7791 (R-Car M2) MSTP gate clocks
+ - "renesas,r8a7794-mstp-clocks" for R8A7794 (R-Car E2) MSTP gate clocks
- "renesas,sh73a0-mstp-clocks" for SH73A0 (SH-MobileAG5) MSTP gate clocks
- "renesas,cpg-mstp-clock" for generic MSTP gate clocks
- reg: Base address and length of the I/O mapped registers used by the MSTP
diff --git a/Documentation/devicetree/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt b/Documentation/devicetree/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt
index 7b41c2fe54db..e6ad35b894f9 100644
--- a/Documentation/devicetree/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt
+++ b/Documentation/devicetree/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt
@@ -8,6 +8,7 @@ Required Properties:
- compatible: Must be one of
- "renesas,r8a7790-cpg-clocks" for the r8a7790 CPG
- "renesas,r8a7791-cpg-clocks" for the r8a7791 CPG
+ - "renesas,r8a7794-cpg-clocks" for the r8a7794 CPG
- "renesas,rcar-gen2-cpg-clocks" for the generic R-Car Gen2 CPG
- reg: Base address and length of the memory resource used by the CPG
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index cfd3af7b2cbd..85131ae0b288 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -32,12 +32,23 @@ config COMMON_CLK_WM831X
source "drivers/clk/versatile/Kconfig"
+config COMMON_CLK_MAX_GEN
+ bool
+
config COMMON_CLK_MAX77686
tristate "Clock driver for Maxim 77686 MFD"
depends on MFD_MAX77686
+ select COMMON_CLK_MAX_GEN
---help---
This driver supports Maxim 77686 crystal oscillator clock.
+config COMMON_CLK_MAX77802
+ tristate "Clock driver for Maxim 77802 PMIC"
+ depends on MFD_MAX77686
+ select COMMON_CLK_MAX_GEN
+ ---help---
+ This driver supports Maxim 77802 crystal oscillator clock.
+
config COMMON_CLK_SI5351
tristate "Clock driver for SiLabs 5351A/B/C"
depends on I2C
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index f537a0b1f798..27c542ba9e73 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -22,7 +22,9 @@ obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o
obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o
+obj-$(CONFIG_COMMON_CLK_MAX_GEN) += clk-max-gen.o
obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
+obj-$(CONFIG_COMMON_CLK_MAX77802) += clk-max77802.o
obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o
obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o
obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o
diff --git a/drivers/clk/at91/clk-pll.c b/drivers/clk/at91/clk-pll.c
index cf6ed023504c..6ec79dbc0840 100644
--- a/drivers/clk/at91/clk-pll.c
+++ b/drivers/clk/at91/clk-pll.c
@@ -15,6 +15,7 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/io.h>
+#include <linux/kernel.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
@@ -29,9 +30,12 @@
#define PLL_DIV(reg) ((reg) & PLL_DIV_MASK)
#define PLL_MUL(reg, layout) (((reg) >> (layout)->mul_shift) & \
(layout)->mul_mask)
+#define PLL_MUL_MIN 2
+#define PLL_MUL_MASK(layout) ((layout)->mul_mask)
+#define PLL_MUL_MAX(layout) (PLL_MUL_MASK(layout) + 1)
#define PLL_ICPR_SHIFT(id) ((id) * 16)
#define PLL_ICPR_MASK(id) (0xffff << PLL_ICPR_SHIFT(id))
-#define PLL_MAX_COUNT 0x3ff
+#define PLL_MAX_COUNT 0x3f
#define PLL_COUNT_SHIFT 8
#define PLL_OUT_SHIFT 14
#define PLL_MAX_ID 1
@@ -147,115 +151,113 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_pll *pll = to_clk_pll(hw);
- const struct clk_pll_layout *layout = pll->layout;
- struct at91_pmc *pmc = pll->pmc;
- int offset = PLL_REG(pll->id);
- u32 tmp = pmc_read(pmc, offset) & layout->pllr_mask;
- u8 div = PLL_DIV(tmp);
- u16 mul = PLL_MUL(tmp, layout);
- if (!div || !mul)
+
+ if (!pll->div || !pll->mul)
return 0;
- return (parent_rate * (mul + 1)) / div;
+ return (parent_rate / pll->div) * (pll->mul + 1);
}
static long clk_pll_get_best_div_mul(struct clk_pll *pll, unsigned long rate,
unsigned long parent_rate,
u32 *div, u32 *mul,
u32 *index) {
- unsigned long maxrate;
- unsigned long minrate;
- unsigned long divrate;
- unsigned long bestdiv = 1;
- unsigned long bestmul;
- unsigned long tmpdiv;
- unsigned long roundup;
- unsigned long rounddown;
- unsigned long remainder;
- unsigned long bestremainder;
- unsigned long maxmul;
- unsigned long maxdiv;
- unsigned long mindiv;
- int i = 0;
const struct clk_pll_layout *layout = pll->layout;
const struct clk_pll_characteristics *characteristics =
pll->characteristics;
+ unsigned long bestremainder = ULONG_MAX;
+ unsigned long maxdiv, mindiv, tmpdiv;
+ long bestrate = -ERANGE;
+ unsigned long bestdiv;
+ unsigned long bestmul;
+ int i = 0;
- /* Minimum divider = 1 */
- /* Maximum multiplier = max_mul */
- maxmul = layout->mul_mask + 1;
- maxrate = (parent_rate * maxmul) / 1;
-
- /* Maximum divider = max_div */
- /* Minimum multiplier = 2 */
- maxdiv = PLL_DIV_MAX;
- minrate = (parent_rate * 2) / maxdiv;
-
+ /* Check if parent_rate is a valid input rate */
if (parent_rate < characteristics->input.min ||
- parent_rate < characteristics->input.max)
- return -ERANGE;
-
- if (parent_rate < minrate || parent_rate > maxrate)
+ parent_rate > characteristics->input.max)
return -ERANGE;
- for (i = 0; i < characteristics->num_output; i++) {
- if (parent_rate >= characteristics->output[i].min &&
- parent_rate <= characteristics->output[i].max)
- break;
- }
-
- if (i >= characteristics->num_output)
- return -ERANGE;
-
- bestmul = rate / parent_rate;
- rounddown = parent_rate % rate;
- roundup = rate - rounddown;
- bestremainder = roundup < rounddown ? roundup : rounddown;
-
- if (!bestremainder) {
- if (div)
- *div = bestdiv;
- if (mul)
- *mul = bestmul;
- if (index)
- *index = i;
- return rate;
- }
-
- maxdiv = 255 / (bestmul + 1);
- if (parent_rate / maxdiv < characteristics->input.min)
- maxdiv = parent_rate / characteristics->input.min;
- mindiv = parent_rate / characteristics->input.max;
- if (parent_rate % characteristics->input.max)
- mindiv++;
-
- for (tmpdiv = mindiv; tmpdiv < maxdiv; tmpdiv++) {
- divrate = parent_rate / tmpdiv;
-
- rounddown = rate % divrate;
- roundup = divrate - rounddown;
- remainder = roundup < rounddown ? roundup : rounddown;
-
+ /*
+ * Calculate minimum divider based on the minimum multiplier, the
+ * parent_rate and the requested rate.
+ * Should always be 2 according to the input and output characteristics
+ * of the PLL blocks.
+ */
+ mindiv = (parent_rate * PLL_MUL_MIN) / rate;
+ if (!mindiv)
+ mindiv = 1;
+
+ /*
+ * Calculate the maximum divider which is limited by PLL register
+ * layout (limited by the MUL or DIV field size).
+ */
+ maxdiv = DIV_ROUND_UP(parent_rate * PLL_MUL_MAX(layout), rate);
+ if (maxdiv > PLL_DIV_MAX)
+ maxdiv = PLL_DIV_MAX;
+
+ /*
+ * Iterate over the acceptable divider values to find the best
+ * divider/multiplier pair (the one that generates the closest
+ * rate to the requested one).
+ */
+ for (tmpdiv = mindiv; tmpdiv <= maxdiv; tmpdiv++) {
+ unsigned long remainder;
+ unsigned long tmprate;
+ unsigned long tmpmul;
+
+ /*
+ * Calculate the multiplier associated with the current
+ * divider that provide the closest rate to the requested one.
+ */
+ tmpmul = DIV_ROUND_CLOSEST(rate, parent_rate / tmpdiv);
+ tmprate = (parent_rate / tmpdiv) * tmpmul;
+ if (tmprate > rate)
+ remainder = tmprate - rate;
+ else
+ remainder = rate - tmprate;
+
+ /*
+ * Compare the remainder with the best remainder found until
+ * now and elect a new best multiplier/divider pair if the
+ * current remainder is smaller than the best one.
+ */
if (remainder < bestremainder) {
bestremainder = remainder;
- bestmul = rate / divrate;
bestdiv = tmpdiv;
+ bestmul = tmpmul;
+ bestrate = tmprate;
}
+ /*
+ * We've found a perfect match!
+ * Stop searching now and use this multiplier/divider pair.
+ */
if (!remainder)
break;
}
- rate = (parent_rate / bestdiv) * bestmul;
+ /* We haven't found any multiplier/divider pair => return -ERANGE */
+ if (bestrate < 0)
+ return bestrate;
+
+ /* Check if bestrate is a valid output rate */
+ for (i = 0; i < characteristics->num_output; i++) {
+ if (bestrate >= characteristics->output[i].min &&
+ bestrate <= characteristics->output[i].max)
+ break;
+ }
+
+ if (i >= characteristics->num_output)
+ return -ERANGE;
if (div)
*div = bestdiv;
if (mul)
- *mul = bestmul;
+ *mul = bestmul - 1;
if (index)
*index = i;
- return rate;
+ return bestrate;
}
static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c
index 7d1d26a4bd04..24b5b020753a 100644
--- a/drivers/clk/at91/clk-usb.c
+++ b/drivers/clk/at91/clk-usb.c
@@ -238,16 +238,22 @@ static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw);
+ struct clk *parent = __clk_get_parent(hw->clk);
unsigned long bestrate = 0;
int bestdiff = -1;
unsigned long tmprate;
int tmpdiff;
int i = 0;
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < RM9200_USB_DIV_TAB_SIZE; i++) {
+ unsigned long tmp_parent_rate;
+
if (!usb->divisors[i])
continue;
- tmprate = *parent_rate / usb->divisors[i];
+
+ tmp_parent_rate = rate * usb->divisors[i];
+ tmp_parent_rate = __clk_round_rate(parent, tmp_parent_rate);
+ tmprate = tmp_parent_rate / usb->divisors[i];
if (tmprate < rate)
tmpdiff = rate - tmprate;
else
@@ -256,6 +262,7 @@ static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate,
if (bestdiff < 0 || bestdiff > tmpdiff) {
bestrate = tmprate;
bestdiff = tmpdiff;
+ *parent_rate = tmp_parent_rate;
}
if (!bestdiff)
@@ -272,10 +279,13 @@ static int at91rm9200_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate,
int i;
struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(hw);
struct at91_pmc *pmc = usb->pmc;
- unsigned long div = parent_rate / rate;
+ unsigned long div;
- if (parent_rate % rate)
+ if (!rate || parent_rate % rate)
return -EINVAL;
+
+ div = parent_rate / rate;
+
for (i = 0; i < RM9200_USB_DIV_TAB_SIZE; i++) {
if (usb->divisors[i] == div) {
tmp = pmc_read(pmc, AT91_CKGR_PLLBR) &
@@ -311,7 +321,7 @@ at91rm9200_clk_register_usb(struct at91_pmc *pmc, const char *name,
init.ops = &at91rm9200_usb_ops;
init.parent_names = &parent_name;
init.num_parents = 1;
- init.flags = 0;
+ init.flags = CLK_SET_RATE_PARENT;
usb->hw.init = &init;
usb->pmc = pmc;
diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c
index ede685ca0d20..82a59d0086cc 100644
--- a/drivers/clk/clk-fractional-divider.c
+++ b/drivers/clk/clk-fractional-divider.c
@@ -36,7 +36,7 @@ static unsigned long clk_fd_recalc_rate(struct clk_hw *hw,
m = (val & fd->mmask) >> fd->mshift;
n = (val & fd->nmask) >> fd->nshift;
- ret = parent_rate * m;
+ ret = (u64)parent_rate * m;
do_div(ret, n);
return ret;
diff --git a/drivers/clk/clk-max-gen.c b/drivers/clk/clk-max-gen.c
new file mode 100644
index 000000000000..6505049d50f1
--- /dev/null
+++ b/drivers/clk/clk-max-gen.c
@@ -0,0 +1,192 @@
+/*
+ * clk-max-gen.c - Generic clock driver for Maxim PMICs clocks
+ *
+ * Copyright (C) 2014 Google, Inc
+ *
+ * Copyright (C) 2012 Samsung Electornics
+ * Jonghwa Lee <jonghwa3.lee@samsung.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.
+ *
+ * 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.
+ *
+ * This driver is based on clk-max77686.c
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include <linux/clk-provider.h>
+#include <linux/mutex.h>
+#include <linux/clkdev.h>
+#include <linux/of.h>
+#include <linux/export.h>
+
+struct max_gen_clk {
+ struct regmap *regmap;
+ u32 mask;
+ u32 reg;
+ struct clk_hw hw;
+};
+
+static struct max_gen_clk *to_max_gen_clk(struct clk_hw *hw)
+{
+ return container_of(hw, struct max_gen_clk, hw);
+}
+
+static int max_gen_clk_prepare(struct clk_hw *hw)
+{
+ struct max_gen_clk *max_gen = to_max_gen_clk(hw);
+
+ return regmap_update_bits(max_gen->regmap, max_gen->reg,
+ max_gen->mask, max_gen->mask);
+}
+
+static void max_gen_clk_unprepare(struct clk_hw *hw)
+{
+ struct max_gen_clk *max_gen = to_max_gen_clk(hw);
+
+ regmap_update_bits(max_gen->regmap, max_gen->reg,
+ max_gen->mask, ~max_gen->mask);
+}
+
+static int max_gen_clk_is_prepared(struct clk_hw *hw)
+{
+ struct max_gen_clk *max_gen = to_max_gen_clk(hw);
+ int ret;
+ u32 val;
+
+ ret = regmap_read(max_gen->regmap, max_gen->reg, &val);
+
+ if (ret < 0)
+ return -EINVAL;
+
+ return val & max_gen->mask;
+}
+
+static unsigned long max_gen_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ return 32768;
+}
+
+struct clk_ops max_gen_clk_ops = {
+ .prepare = max_gen_clk_prepare,
+ .unprepare = max_gen_clk_unprepare,
+ .is_prepared = max_gen_clk_is_prepared,
+ .recalc_rate = max_gen_recalc_rate,
+};
+EXPORT_SYMBOL_GPL(max_gen_clk_ops);
+
+static struct clk *max_gen_clk_register(struct device *dev,
+ struct max_gen_clk *max_gen)
+{
+ struct clk *clk;
+ struct clk_hw *hw = &max_gen->hw;
+ int ret;
+
+ clk = devm_clk_register(dev, hw);
+ if (IS_ERR(clk))
+ return clk;
+
+ ret = clk_register_clkdev(clk, hw->init->name, NULL);
+
+ if (ret)
+ return ERR_PTR(ret);
+
+ return clk;
+}
+
+int max_gen_clk_probe(struct platform_device *pdev, struct regmap *regmap,
+ u32 reg, struct clk_init_data *clks_init, int num_init)
+{
+ int i, ret;
+ struct max_gen_clk *max_gen_clks;
+ struct clk **clocks;
+ struct device *dev = pdev->dev.parent;
+ const char *clk_name;
+ struct clk_init_data *init;
+
+ clocks = devm_kzalloc(dev, sizeof(struct clk *) * num_init, GFP_KERNEL);
+ if (!clocks)
+ return -ENOMEM;
+
+ max_gen_clks = devm_kzalloc(dev, sizeof(struct max_gen_clk)
+ * num_init, GFP_KERNEL);
+ if (!max_gen_clks)
+ return -ENOMEM;
+
+ for (i = 0; i < num_init; i++) {
+ max_gen_clks[i].regmap = regmap;
+ max_gen_clks[i].mask = 1 << i;
+ max_gen_clks[i].reg = reg;
+
+ init = devm_kzalloc(dev, sizeof(*init), GFP_KERNEL);
+ if (!init)
+ return -ENOMEM;
+
+ if (dev->of_node &&
+ !of_property_read_string_index(dev->of_node,
+ "clock-output-names",
+ i, &clk_name))
+ init->name = clk_name;
+ else
+ init->name = clks_init[i].name;
+
+ init->ops = clks_init[i].ops;
+ init->flags = clks_init[i].flags;
+
+ max_gen_clks[i].hw.init = init;
+
+ clocks[i] = max_gen_clk_register(dev, &max_gen_clks[i]);
+ if (IS_ERR(clocks[i])) {
+ ret = PTR_ERR(clocks[i]);
+ dev_err(dev, "failed to register %s\n",
+ max_gen_clks[i].hw.init->name);
+ return ret;
+ }
+ }
+
+ platform_set_drvdata(pdev, clocks);
+
+ if (dev->of_node) {
+ struct clk_onecell_data *of_data;
+
+ of_data = devm_kzalloc(dev, sizeof(*of_data), GFP_KERNEL);
+ if (!of_data)
+ return -ENOMEM;
+
+ of_data->clks = clocks;
+ of_data->clk_num = num_init;
+ ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get,
+ of_data);
+
+ if (ret) {
+ dev_err(dev, "failed to register OF clock provider\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(max_gen_clk_probe);
+
+int max_gen_clk_remove(struct platform_device *pdev, int num_init)
+{
+ struct device *dev = pdev->dev.parent;
+
+ if (dev->of_node)
+ of_clk_del_provider(dev->of_node);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(max_gen_clk_remove);
diff --git a/drivers/clk/clk-max-gen.h b/drivers/clk/clk-max-gen.h
new file mode 100644
index 000000000000..997e86fc3f4d
--- /dev/null
+++ b/drivers/clk/clk-max-gen.h
@@ -0,0 +1,32 @@
+/*
+ * clk-max-gen.h - Generic clock driver for Maxim PMICs clocks
+ *
+ * Copyright (C) 2014 Google, Inc
+ *
+ * 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.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __CLK_MAX_GEN_H__
+#define __CLK_MAX_GEN_H__
+
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/clkdev.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+
+int max_gen_clk_probe(struct platform_device *pdev, struct regmap *regmap,
+ u32 reg, struct clk_init_data *clks_init, int num_init);
+int max_gen_clk_remove(struct platform_device *pdev, int num_init);
+extern struct clk_ops max_gen_clk_ops;
+
+#endif /* __CLK_MAX_GEN_H__ */
diff --git a/drivers/clk/clk-max77686.c b/drivers/clk/clk-max77686.c
index 3d7e8dd8fd58..ed0beb4cb39b 100644
--- a/drivers/clk/clk-max77686.c
+++ b/drivers/clk/clk-max77686.c
@@ -30,193 +30,38 @@
#include <linux/mutex.h>
#include <linux/clkdev.h>
-enum {
- MAX77686_CLK_AP = 0,
- MAX77686_CLK_CP,
- MAX77686_CLK_PMIC,
- MAX77686_CLKS_NUM,
-};
-
-struct max77686_clk {
- struct max77686_dev *iodev;
- u32 mask;
- struct clk_hw hw;
- struct clk_lookup *lookup;
-};
-
-static struct max77686_clk *to_max77686_clk(struct clk_hw *hw)
-{
- return container_of(hw, struct max77686_clk, hw);
-}
-
-static int max77686_clk_prepare(struct clk_hw *hw)
-{
- struct max77686_clk *max77686 = to_max77686_clk(hw);
-
- return regmap_update_bits(max77686->iodev->regmap,
- MAX77686_REG_32KHZ, max77686->mask,
- max77686->mask);
-}
-
-static void max77686_clk_unprepare(struct clk_hw *hw)
-{
- struct max77686_clk *max77686 = to_max77686_clk(hw);
-
- regmap_update_bits(max77686->iodev->regmap,
- MAX77686_REG_32KHZ, max77686->mask, ~max77686->mask);
-}
-
-static int max77686_clk_is_prepared(struct clk_hw *hw)
-{
- struct max77686_clk *max77686 = to_max77686_clk(hw);
- int ret;
- u32 val;
-
- ret = regmap_read(max77686->iodev->regmap,
- MAX77686_REG_32KHZ, &val);
-
- if (ret < 0)
- return -EINVAL;
-
- return val & max77686->mask;
-}
-
-static unsigned long max77686_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
-{
- return 32768;
-}
-
-static struct clk_ops max77686_clk_ops = {
- .prepare = max77686_clk_prepare,
- .unprepare = max77686_clk_unprepare,
- .is_prepared = max77686_clk_is_prepared,
- .recalc_rate = max77686_recalc_rate,
-};
+#include <dt-bindings/clock/maxim,max77686.h>
+#include "clk-max-gen.h"
static struct clk_init_data max77686_clks_init[MAX77686_CLKS_NUM] = {
[MAX77686_CLK_AP] = {
.name = "32khz_ap",
- .ops = &max77686_clk_ops,
+ .ops = &max_gen_clk_ops,
.flags = CLK_IS_ROOT,
},
[MAX77686_CLK_CP] = {
.name = "32khz_cp",
- .ops = &max77686_clk_ops,
+ .ops = &max_gen_clk_ops,
.flags = CLK_IS_ROOT,
},
[MAX77686_CLK_PMIC] = {
.name = "32khz_pmic",
- .ops = &max77686_clk_ops,
+ .ops = &max_gen_clk_ops,
.flags = CLK_IS_ROOT,
},
};
-static struct clk *max77686_clk_register(struct device *dev,
- struct max77686_clk *max77686)
-{
- struct clk *clk;
- struct clk_hw *hw = &max77686->hw;
-
- clk = clk_register(dev, hw);
- if (IS_ERR(clk))
- return clk;
-
- max77686->lookup = kzalloc(sizeof(struct clk_lookup), GFP_KERNEL);
- if (!max77686->lookup)
- return ERR_PTR(-ENOMEM);
-
- max77686->lookup->con_id = hw->init->name;
- max77686->lookup->clk = clk;
-
- clkdev_add(max77686->lookup);
-
- return clk;
-}
-
static int max77686_clk_probe(struct platform_device *pdev)
{
struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent);
- struct max77686_clk *max77686_clks[MAX77686_CLKS_NUM];
- struct clk **clocks;
- int i, ret;
-
- clocks = devm_kzalloc(&pdev->dev, sizeof(struct clk *)
- * MAX77686_CLKS_NUM, GFP_KERNEL);
- if (!clocks)
- return -ENOMEM;
-
- for (i = 0; i < MAX77686_CLKS_NUM; i++) {
- max77686_clks[i] = devm_kzalloc(&pdev->dev,
- sizeof(struct max77686_clk), GFP_KERNEL);
- if (!max77686_clks[i])
- return -ENOMEM;
- }
-
- for (i = 0; i < MAX77686_CLKS_NUM; i++) {
- max77686_clks[i]->iodev = iodev;
- max77686_clks[i]->mask = 1 << i;
- max77686_clks[i]->hw.init = &max77686_clks_init[i];
-
- clocks[i] = max77686_clk_register(&pdev->dev, max77686_clks[i]);
- if (IS_ERR(clocks[i])) {
- ret = PTR_ERR(clocks[i]);
- dev_err(&pdev->dev, "failed to register %s\n",
- max77686_clks[i]->hw.init->name);
- goto err_clocks;
- }
- }
-
- platform_set_drvdata(pdev, clocks);
-
- if (iodev->dev->of_node) {
- struct clk_onecell_data *of_data;
- of_data = devm_kzalloc(&pdev->dev,
- sizeof(*of_data), GFP_KERNEL);
- if (!of_data) {
- ret = -ENOMEM;
- goto err_clocks;
- }
-
- of_data->clks = clocks;
- of_data->clk_num = MAX77686_CLKS_NUM;
- ret = of_clk_add_provider(iodev->dev->of_node,
- of_clk_src_onecell_get, of_data);
- if (ret) {
- dev_err(&pdev->dev, "failed to register OF clock provider\n");
- goto err_clocks;
- }
- }
-
- return 0;
-
-err_clocks:
- for (--i; i >= 0; --i) {
- clkdev_drop(max77686_clks[i]->lookup);
- clk_unregister(max77686_clks[i]->hw.clk);
- }
-
- return ret;
+ return max_gen_clk_probe(pdev, iodev->regmap, MAX77686_REG_32KHZ,
+ max77686_clks_init, MAX77686_CLKS_NUM);
}
static int max77686_clk_remove(struct platform_device *pdev)
{
- struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent);
- struct clk **clocks = platform_get_drvdata(pdev);
- int i;
-
- if (iodev->dev->of_node)
- of_clk_del_provider(iodev->dev->of_node);
-
- for (i = 0; i < MAX77686_CLKS_NUM; i++) {
- struct clk_hw *hw = __clk_get_hw(clocks[i]);
- struct max77686_clk *max77686 = to_max77686_clk(hw);
-
- clkdev_drop(max77686->lookup);
- clk_unregister(clocks[i]);
- }
- return 0;
+ return max_gen_clk_remove(pdev, MAX77686_CLKS_NUM);
}
static const struct platform_device_id max77686_clk_id[] = {
@@ -235,17 +80,7 @@ static struct platform_driver max77686_clk_driver = {
.id_table = max77686_clk_id,
};
-static int __init max77686_clk_init(void)
-{
- return platform_driver_register(&max77686_clk_driver);
-}
-subsys_initcall(max77686_clk_init);
-
-static void __init max77686_clk_cleanup(void)
-{
- platform_driver_unregister(&max77686_clk_driver);
-}
-module_exit(max77686_clk_cleanup);
+module_platform_driver(max77686_clk_driver);
MODULE_DESCRIPTION("MAXIM 77686 Clock Driver");
MODULE_AUTHOR("Jonghwa Lee <jonghwa3.lee@samsung.com>");
diff --git a/drivers/clk/clk-max77802.c b/drivers/clk/clk-max77802.c
new file mode 100644
index 000000000000..8e480c5c2945
--- /dev/null
+++ b/drivers/clk/clk-max77802.c
@@ -0,0 +1,98 @@
+/*
+ * clk-max77802.c - Clock driver for Maxim 77802
+ *
+ * Copyright (C) 2014 Google, Inc
+ *
+ * Copyright (C) 2012 Samsung Electornics
+ * Jonghwa Lee <jonghwa3.lee@samsung.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.
+ *
+ * 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.
+ *
+ * This driver is based on clk-max77686.c
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/max77686-private.h>
+#include <linux/clk-provider.h>
+#include <linux/mutex.h>
+#include <linux/clkdev.h>
+
+#include <dt-bindings/clock/maxim,max77802.h>
+#include "clk-max-gen.h"
+
+#define MAX77802_CLOCK_OPMODE_MASK 0x1
+#define MAX77802_CLOCK_LOW_JITTER_SHIFT 0x3
+
+static struct clk_init_data max77802_clks_init[MAX77802_CLKS_NUM] = {
+ [MAX77802_CLK_32K_AP] = {
+ .name = "32khz_ap",
+ .ops = &max_gen_clk_ops,
+ .flags = CLK_IS_ROOT,
+ },
+ [MAX77802_CLK_32K_CP] = {
+ .name = "32khz_cp",
+ .ops = &max_gen_clk_ops,
+ .flags = CLK_IS_ROOT,
+ },
+};
+
+static int max77802_clk_probe(struct platform_device *pdev)
+{
+ struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+ int ret;
+
+ ret = max_gen_clk_probe(pdev, iodev->regmap, MAX77802_REG_32KHZ,
+ max77802_clks_init, MAX77802_CLKS_NUM);
+
+ if (ret) {
+ dev_err(&pdev->dev, "generic probe failed %d\n", ret);
+ return ret;
+ }
+
+ /* Enable low-jitter mode on the 32khz clocks. */
+ ret = regmap_update_bits(iodev->regmap, MAX77802_REG_32KHZ,
+ 1 << MAX77802_CLOCK_LOW_JITTER_SHIFT,
+ 1 << MAX77802_CLOCK_LOW_JITTER_SHIFT);
+ if (ret < 0)
+ dev_err(&pdev->dev, "failed to enable low-jitter mode\n");
+
+ return ret;
+}
+
+static int max77802_clk_remove(struct platform_device *pdev)
+{
+ return max_gen_clk_remove(pdev, MAX77802_CLKS_NUM);
+}
+
+static const struct platform_device_id max77802_clk_id[] = {
+ { "max77802-clk", 0},
+ { },
+};
+MODULE_DEVICE_TABLE(platform, max77802_clk_id);
+
+static struct platform_driver max77802_clk_driver = {
+ .driver = {
+ .name = "max77802-clk",
+ .owner = THIS_MODULE,
+ },
+ .probe = max77802_clk_probe,
+ .remove = max77802_clk_remove,
+ .id_table = max77802_clk_id,
+};
+
+module_platform_driver(max77802_clk_driver);
+
+MODULE_DESCRIPTION("MAXIM 77802 Clock Driver");
+MODULE_AUTHOR("Javier Martinez Canillas <javier.martinez@collabora.co.uk>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index b76fa69b44cb..8ca28189e4e9 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -100,6 +100,8 @@ static void clk_enable_unlock(unsigned long flags)
static struct dentry *rootdir;
static int inited = 0;
+static DEFINE_MUTEX(clk_debug_lock);
+static HLIST_HEAD(clk_debug_list);
static struct hlist_head *all_lists[] = {
&clk_root_list,
@@ -300,28 +302,6 @@ out:
return ret;
}
-/* caller must hold prepare_lock */
-static int clk_debug_create_subtree(struct clk *clk, struct dentry *pdentry)
-{
- struct clk *child;
- int ret = -EINVAL;;
-
- if (!clk || !pdentry)
- goto out;
-
- ret = clk_debug_create_one(clk, pdentry);
-
- if (ret)
- goto out;
-
- hlist_for_each_entry(child, &clk->children, child_node)
- clk_debug_create_subtree(child, pdentry);
-
- ret = 0;
-out:
- return ret;
-}
-
/**
* clk_debug_register - add a clk node to the debugfs clk tree
* @clk: the clk being added to the debugfs clk tree
@@ -329,20 +309,21 @@ out:
* Dynamically adds a clk to the debugfs clk tree if debugfs has been
* initialized. Otherwise it bails out early since the debugfs clk tree
* will be created lazily by clk_debug_init as part of a late_initcall.
- *
- * Caller must hold prepare_lock. Only clk_init calls this function (so
- * far) so this is taken care.
*/
static int clk_debug_register(struct clk *clk)
{
int ret = 0;
+ mutex_lock(&clk_debug_lock);
+ hlist_add_head(&clk->debug_node, &clk_debug_list);
+
if (!inited)
- goto out;
+ goto unlock;
- ret = clk_debug_create_subtree(clk, rootdir);
+ ret = clk_debug_create_one(clk, rootdir);
+unlock:
+ mutex_unlock(&clk_debug_lock);
-out:
return ret;
}
@@ -353,12 +334,18 @@ out:
* Dynamically removes a clk and all it's children clk nodes from the
* debugfs clk tree if clk->dentry points to debugfs created by
* clk_debug_register in __clk_init.
- *
- * Caller must hold prepare_lock.
*/
static void clk_debug_unregister(struct clk *clk)
{
+ mutex_lock(&clk_debug_lock);
+ if (!clk->dentry)
+ goto out;
+
+ hlist_del_init(&clk->debug_node);
debugfs_remove_recursive(clk->dentry);
+ clk->dentry = NULL;
+out:
+ mutex_unlock(&clk_debug_lock);
}
struct dentry *clk_debugfs_add_file(struct clk *clk, char *name, umode_t mode,
@@ -415,17 +402,12 @@ static int __init clk_debug_init(void)
if (!d)
return -ENOMEM;
- clk_prepare_lock();
-
- hlist_for_each_entry(clk, &clk_root_list, child_node)
- clk_debug_create_subtree(clk, rootdir);
-
- hlist_for_each_entry(clk, &clk_orphan_list, child_node)
- clk_debug_create_subtree(clk, rootdir);
+ mutex_lock(&clk_debug_lock);
+ hlist_for_each_entry(clk, &clk_debug_list, debug_node)
+ clk_debug_create_one(clk, rootdir);
inited = 1;
-
- clk_prepare_unlock();
+ mutex_unlock(&clk_debug_lock);
return 0;
}
@@ -2087,14 +2069,16 @@ void clk_unregister(struct clk *clk)
{
unsigned long flags;
- if (!clk || WARN_ON_ONCE(IS_ERR(clk)))
- return;
+ if (!clk || WARN_ON_ONCE(IS_ERR(clk)))
+ return;
+
+ clk_debug_unregister(clk);
clk_prepare_lock();
if (clk->ops == &clk_nodrv_ops) {
pr_err("%s: unregistered clock: %s\n", __func__, clk->name);
- goto out;
+ return;
}
/*
* Assign empty clock ops for consumers that might still hold
@@ -2113,16 +2097,13 @@ void clk_unregister(struct clk *clk)
clk_set_parent(child, NULL);
}
- clk_debug_unregister(clk);
-
hlist_del_init(&clk->child_node);
if (clk->prepare_count)
pr_warn("%s: unregistering prepared clock: %s\n",
__func__, clk->name);
-
kref_put(&clk->ref, __clk_release);
-out:
+
clk_prepare_unlock();
}
EXPORT_SYMBOL_GPL(clk_unregister);
diff --git a/drivers/clk/mvebu/common.c b/drivers/clk/mvebu/common.c
index 354bbadb3bce..7f8a33ab265b 100644
--- a/drivers/clk/mvebu/common.c
+++ b/drivers/clk/mvebu/common.c
@@ -171,8 +171,10 @@ void __init mvebu_coreclk_setup(struct device_node *np,
* Clock Gating Control
*/
+DEFINE_SPINLOCK(ctrl_gating_lock);
+
struct clk_gating_ctrl {
- spinlock_t lock;
+ spinlock_t *lock;
struct clk **gates;
int num_gates;
};
@@ -220,7 +222,8 @@ void __init mvebu_clk_gating_setup(struct device_node *np,
if (WARN_ON(!ctrl))
goto ctrl_out;
- spin_lock_init(&ctrl->lock);
+ /* lock must already be initialized */
+ ctrl->lock = &ctrl_gating_lock;
/* Count, allocate, and register clock gates */
for (n = 0; desc[n].name;)
@@ -237,7 +240,7 @@ void __init mvebu_clk_gating_setup(struct device_node *np,
(desc[n].parent) ? desc[n].parent : default_parent;
ctrl->gates[n] = clk_register_gate(NULL, desc[n].name, parent,
desc[n].flags, base, desc[n].bit_idx,
- 0, &ctrl->lock);
+ 0, ctrl->lock);
WARN_ON(IS_ERR(ctrl->gates[n]));
}
diff --git a/drivers/clk/mvebu/common.h b/drivers/clk/mvebu/common.h
index 59efaa850bde..8f8db7eac3f6 100644
--- a/drivers/clk/mvebu/common.h
+++ b/drivers/clk/mvebu/common.h
@@ -17,6 +17,8 @@
#include <linux/kernel.h>
+extern spinlock_t ctrl_gating_lock;
+
struct device_node;
struct coreclk_ratio {
diff --git a/drivers/clk/mvebu/kirkwood.c b/drivers/clk/mvebu/kirkwood.c
index ddb666a86500..99550f25975e 100644
--- a/drivers/clk/mvebu/kirkwood.c
+++ b/drivers/clk/mvebu/kirkwood.c
@@ -13,9 +13,11 @@
*/
#include <linux/kernel.h>
+#include <linux/slab.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include "common.h"
/*
@@ -214,7 +216,6 @@ static const struct clk_gating_soc_desc kirkwood_gating_desc[] __initconst = {
{ "runit", NULL, 7, 0 },
{ "xor0", NULL, 8, 0 },
{ "audio", NULL, 9, 0 },
- { "powersave", "cpuclk", 11, 0 },
{ "sata0", NULL, 14, 0 },
{ "sata1", NULL, 15, 0 },
{ "xor1", NULL, 16, 0 },
@@ -225,6 +226,101 @@ static const struct clk_gating_soc_desc kirkwood_gating_desc[] __initconst = {
{ }
};
+
+/*
+ * Clock Muxing Control
+ */
+
+struct clk_muxing_soc_desc {
+ const char *name;
+ const char **parents;
+ int num_parents;
+ int shift;
+ int width;
+ unsigned long flags;
+};
+
+struct clk_muxing_ctrl {
+ spinlock_t *lock;
+ struct clk **muxes;
+ int num_muxes;
+};
+
+static const char *powersave_parents[] = {
+ "cpuclk",
+ "ddrclk",
+};
+
+static const struct clk_muxing_soc_desc kirkwood_mux_desc[] __initconst = {
+ { "powersave", powersave_parents, ARRAY_SIZE(powersave_parents),
+ 11, 1, 0 },
+};
+
+#define to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw)
+
+static struct clk *clk_muxing_get_src(
+ struct of_phandle_args *clkspec, void *data)
+{
+ struct clk_muxing_ctrl *ctrl = (struct clk_muxing_ctrl *)data;
+ int n;
+
+ if (clkspec->args_count < 1)
+ return ERR_PTR(-EINVAL);
+
+ for (n = 0; n < ctrl->num_muxes; n++) {
+ struct clk_mux *mux =
+ to_clk_mux(__clk_get_hw(ctrl->muxes[n]));
+ if (clkspec->args[0] == mux->shift)
+ return ctrl->muxes[n];
+ }
+ return ERR_PTR(-ENODEV);
+}
+
+static void __init kirkwood_clk_muxing_setup(struct device_node *np,
+ const struct clk_muxing_soc_desc *desc)
+{
+ struct clk_muxing_ctrl *ctrl;
+ void __iomem *base;
+ int n;
+
+ base = of_iomap(np, 0);
+ if (WARN_ON(!base))
+ return;
+
+ ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
+ if (WARN_ON(!ctrl))
+ goto ctrl_out;
+
+ /* lock must already be initialized */
+ ctrl->lock = &ctrl_gating_lock;
+
+ /* Count, allocate, and register clock muxes */
+ for (n = 0; desc[n].name;)
+ n++;
+
+ ctrl->num_muxes = n;
+ ctrl->muxes = kcalloc(ctrl->num_muxes, sizeof(struct clk *),
+ GFP_KERNEL);
+ if (WARN_ON(!ctrl->muxes))
+ goto muxes_out;
+
+ for (n = 0; n < ctrl->num_muxes; n++) {
+ ctrl->muxes[n] = clk_register_mux(NULL, desc[n].name,
+ desc[n].parents, desc[n].num_parents,
+ desc[n].flags, base, desc[n].shift,
+ desc[n].width, desc[n].flags, ctrl->lock);
+ WARN_ON(IS_ERR(ctrl->muxes[n]));
+ }
+
+ of_clk_add_provider(np, clk_muxing_get_src, ctrl);
+
+ return;
+muxes_out:
+ kfree(ctrl);
+ctrl_out:
+ iounmap(base);
+}
+
static void __init kirkwood_clk_init(struct device_node *np)
{
struct device_node *cgnp =
@@ -236,8 +332,10 @@ static void __init kirkwood_clk_init(struct device_node *np)
else
mvebu_coreclk_setup(np, &kirkwood_coreclks);
- if (cgnp)
+ if (cgnp) {
mvebu_clk_gating_setup(cgnp, kirkwood_gating_desc);
+ kirkwood_clk_muxing_setup(cgnp, kirkwood_mux_desc);
+ }
}
CLK_OF_DECLARE(kirkwood_clk, "marvell,kirkwood-core-clock",
kirkwood_clk_init);
diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c
index a83a6d8d0fb6..0147614e94b8 100644
--- a/drivers/clk/rockchip/clk-rk3188.c
+++ b/drivers/clk/rockchip/clk-rk3188.c
@@ -599,6 +599,12 @@ static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = {
GATE(ACLK_GPS, "aclk_gps", "aclk_peri", 0, RK2928_CLKGATE_CON(8), 13, GFLAGS),
};
+static const char *rk3188_critical_clocks[] __initconst = {
+ "aclk_cpu",
+ "aclk_peri",
+ "hclk_peri",
+};
+
static void __init rk3188_common_clk_init(struct device_node *np)
{
void __iomem *reg_base;
@@ -628,6 +634,8 @@ static void __init rk3188_common_clk_init(struct device_node *np)
RK3188_GRF_SOC_STATUS);
rockchip_clk_register_branches(common_clk_branches,
ARRAY_SIZE(common_clk_branches));
+ rockchip_clk_protect_critical(rk3188_critical_clocks,
+ ARRAY_SIZE(rk3188_critical_clocks));
rockchip_register_softrst(np, 9, reg_base + RK2928_SOFTRST_CON(0),
ROCKCHIP_SOFTRST_HIWORD_MASK);
diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c
index 0d8c6c59a75e..08c24c6e3e67 100644
--- a/drivers/clk/rockchip/clk-rk3288.c
+++ b/drivers/clk/rockchip/clk-rk3288.c
@@ -680,6 +680,12 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
GATE(0, "pclk_isp_in", "ext_isp", 0, RK3288_CLKGATE_CON(16), 3, GFLAGS),
};
+static const char *rk3288_critical_clocks[] __initconst = {
+ "aclk_cpu",
+ "aclk_peri",
+ "hclk_peri",
+};
+
static void __init rk3288_clk_init(struct device_node *np)
{
void __iomem *reg_base;
@@ -710,6 +716,8 @@ static void __init rk3288_clk_init(struct device_node *np)
RK3288_GRF_SOC_STATUS);
rockchip_clk_register_branches(rk3288_clk_branches,
ARRAY_SIZE(rk3288_clk_branches));
+ rockchip_clk_protect_critical(rk3288_critical_clocks,
+ ARRAY_SIZE(rk3288_critical_clocks));
rockchip_register_softrst(np, 9, reg_base + RK3288_SOFTRST_CON(0),
ROCKCHIP_SOFTRST_HIWORD_MASK);
diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c
index 278cf9dd1e23..d9c6db2151ba 100644
--- a/drivers/clk/rockchip/clk.c
+++ b/drivers/clk/rockchip/clk.c
@@ -37,7 +37,7 @@
*
* sometimes without one of those components.
*/
-struct clk *rockchip_clk_register_branch(const char *name,
+static struct clk *rockchip_clk_register_branch(const char *name,
const char **parent_names, u8 num_parents, void __iomem *base,
int muxdiv_offset, u8 mux_shift, u8 mux_width, u8 mux_flags,
u8 div_shift, u8 div_width, u8 div_flags,
@@ -103,6 +103,54 @@ struct clk *rockchip_clk_register_branch(const char *name,
return clk;
}
+static struct clk *rockchip_clk_register_frac_branch(const char *name,
+ const char **parent_names, u8 num_parents, void __iomem *base,
+ int muxdiv_offset, u8 div_flags,
+ int gate_offset, u8 gate_shift, u8 gate_flags,
+ unsigned long flags, spinlock_t *lock)
+{
+ struct clk *clk;
+ struct clk_gate *gate = NULL;
+ struct clk_fractional_divider *div = NULL;
+ const struct clk_ops *div_ops = NULL, *gate_ops = NULL;
+
+ if (gate_offset >= 0) {
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate)
+ return ERR_PTR(-ENOMEM);
+
+ gate->flags = gate_flags;
+ gate->reg = base + gate_offset;
+ gate->bit_idx = gate_shift;
+ gate->lock = lock;
+ gate_ops = &clk_gate_ops;
+ }
+
+ if (muxdiv_offset < 0)
+ return ERR_PTR(-EINVAL);
+
+ div = kzalloc(sizeof(*div), GFP_KERNEL);
+ if (!div)
+ return ERR_PTR(-ENOMEM);
+
+ div->flags = div_flags;
+ div->reg = base + muxdiv_offset;
+ div->mshift = 16;
+ div->mmask = 0xffff0000;
+ div->nshift = 0;
+ div->nmask = 0xffff;
+ div->lock = lock;
+ div_ops = &clk_fractional_divider_ops;
+
+ clk = clk_register_composite(NULL, name, parent_names, num_parents,
+ NULL, NULL,
+ &div->hw, div_ops,
+ gate ? &gate->hw : NULL, gate_ops,
+ flags);
+
+ return clk;
+}
+
static DEFINE_SPINLOCK(clk_lock);
static struct clk **clk_table;
static void __iomem *reg_base;
@@ -197,8 +245,14 @@ void __init rockchip_clk_register_branches(
list->div_flags, &clk_lock);
break;
case branch_fraction_divider:
- /* unimplemented */
- continue;
+ /* keep all gates untouched for now */
+ flags |= CLK_IGNORE_UNUSED;
+
+ clk = rockchip_clk_register_frac_branch(list->name,
+ list->parent_names, list->num_parents,
+ reg_base, list->muxdiv_offset, list->div_flags,
+ list->gate_offset, list->gate_shift,
+ list->gate_flags, flags, &clk_lock);
break;
case branch_gate:
flags |= CLK_SET_RATE_PARENT;
@@ -242,3 +296,16 @@ void __init rockchip_clk_register_branches(
rockchip_clk_add_lookup(clk, list->id);
}
}
+
+void __init rockchip_clk_protect_critical(const char *clocks[], int nclocks)
+{
+ int i;
+
+ /* Protect the clocks that needs to stay on */
+ for (i = 0; i < nclocks; i++) {
+ struct clk *clk = __clk_lookup(clocks[i]);
+
+ if (clk)
+ clk_prepare_enable(clk);
+ }
+}
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
index 887cbdeca2aa..2b0bca19db47 100644
--- a/drivers/clk/rockchip/clk.h
+++ b/drivers/clk/rockchip/clk.h
@@ -329,6 +329,7 @@ void rockchip_clk_register_branches(struct rockchip_clk_branch *clk_list,
unsigned int nr_clk);
void rockchip_clk_register_plls(struct rockchip_pll_clock *pll_list,
unsigned int nr_pll, int grf_lock_offset);
+void rockchip_clk_protect_critical(const char *clocks[], int nclocks);
#define ROCKCHIP_SOFTRST_HIWORD_MASK BIT(0)
diff --git a/drivers/clk/shmobile/clk-rcar-gen2.c b/drivers/clk/shmobile/clk-rcar-gen2.c
index dff7f79a19b9..e996425d06a9 100644
--- a/drivers/clk/shmobile/clk-rcar-gen2.c
+++ b/drivers/clk/shmobile/clk-rcar-gen2.c
@@ -202,6 +202,7 @@ static const struct clk_div_table cpg_sdh_div_table[] = {
};
static const struct clk_div_table cpg_sd01_div_table[] = {
+ { 4, 8 },
{ 5, 12 }, { 6, 16 }, { 7, 18 }, { 8, 24 },
{ 10, 36 }, { 11, 48 }, { 12, 10 }, { 0, 0 },
};
diff --git a/drivers/clk/zynq/clkc.c b/drivers/clk/zynq/clkc.c
index 246cf1226eaa..9037bebd69f7 100644
--- a/drivers/clk/zynq/clkc.c
+++ b/drivers/clk/zynq/clkc.c
@@ -85,24 +85,22 @@ static DEFINE_SPINLOCK(canmioclk_lock);
static DEFINE_SPINLOCK(dbgclk_lock);
static DEFINE_SPINLOCK(aperclk_lock);
-static const char dummy_nm[] __initconst = "dummy_name";
-
-static const char *armpll_parents[] __initdata = {"armpll_int", "ps_clk"};
-static const char *ddrpll_parents[] __initdata = {"ddrpll_int", "ps_clk"};
-static const char *iopll_parents[] __initdata = {"iopll_int", "ps_clk"};
-static const char *gem0_mux_parents[] __initdata = {"gem0_div1", dummy_nm};
-static const char *gem1_mux_parents[] __initdata = {"gem1_div1", dummy_nm};
-static const char *can0_mio_mux2_parents[] __initdata = {"can0_gate",
+static const char *armpll_parents[] __initconst = {"armpll_int", "ps_clk"};
+static const char *ddrpll_parents[] __initconst = {"ddrpll_int", "ps_clk"};
+static const char *iopll_parents[] __initconst = {"iopll_int", "ps_clk"};
+static const char *gem0_mux_parents[] __initconst = {"gem0_div1", "dummy_name"};
+static const char *gem1_mux_parents[] __initconst = {"gem1_div1", "dummy_name"};
+static const char *can0_mio_mux2_parents[] __initconst = {"can0_gate",
"can0_mio_mux"};
-static const char *can1_mio_mux2_parents[] __initdata = {"can1_gate",
+static const char *can1_mio_mux2_parents[] __initconst = {"can1_gate",
"can1_mio_mux"};
-static const char *dbg_emio_mux_parents[] __initdata = {"dbg_div",
- dummy_nm};
+static const char *dbg_emio_mux_parents[] __initconst = {"dbg_div",
+ "dummy_name"};
-static const char *dbgtrc_emio_input_names[] __initdata = {"trace_emio_clk"};
-static const char *gem0_emio_input_names[] __initdata = {"gem0_emio_clk"};
-static const char *gem1_emio_input_names[] __initdata = {"gem1_emio_clk"};
-static const char *swdt_ext_clk_input_names[] __initdata = {"swdt_ext_clk"};
+static const char *dbgtrc_emio_input_names[] __initconst = {"trace_emio_clk"};
+static const char *gem0_emio_input_names[] __initconst = {"gem0_emio_clk"};
+static const char *gem1_emio_input_names[] __initconst = {"gem1_emio_clk"};
+static const char *swdt_ext_clk_input_names[] __initconst = {"swdt_ext_clk"};
static void __init zynq_clk_register_fclk(enum zynq_clk fclk,
const char *clk_name, void __iomem *fclk_ctrl_reg,
@@ -230,6 +228,7 @@ static void __init zynq_clk_setup(struct device_node *np)
const char *periph_parents[4];
const char *swdt_ext_clk_mux_parents[2];
const char *can_mio_mux_parents[NUM_MIO_PINS];
+ const char *dummy_nm = "dummy_name";
pr_info("Zynq clock init\n");
@@ -619,5 +618,4 @@ void __init zynq_clock_init(void)
np_err:
of_node_put(np);
BUG();
- return;
}
diff --git a/drivers/clk/zynq/pll.c b/drivers/clk/zynq/pll.c
index cec97596fe65..00d72fb5c036 100644
--- a/drivers/clk/zynq/pll.c
+++ b/drivers/clk/zynq/pll.c
@@ -211,10 +211,8 @@ struct clk *clk_register_zynq_pll(const char *name, const char *parent,
};
pll = kmalloc(sizeof(*pll), GFP_KERNEL);
- if (!pll) {
- pr_err("%s: Could not allocate Zynq PLL clk.\n", __func__);
+ if (!pll)
return ERR_PTR(-ENOMEM);
- }
/* Populate the struct */
pll->hw.init = &initd;
diff --git a/drivers/cpufreq/kirkwood-cpufreq.c b/drivers/cpufreq/kirkwood-cpufreq.c
index 37a480680cd0..7906d4acfe40 100644
--- a/drivers/cpufreq/kirkwood-cpufreq.c
+++ b/drivers/cpufreq/kirkwood-cpufreq.c
@@ -12,7 +12,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/clk.h>
-#include <linux/clk-provider.h>
#include <linux/cpufreq.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
@@ -39,8 +38,7 @@ static struct priv
* - cpu clk
* - ddr clk
*
- * The frequencies are set at runtime before registering this *
- * table.
+ * The frequencies are set at runtime before registering this table.
*/
static struct cpufreq_frequency_table kirkwood_freq_table[] = {
{0, STATE_CPU_FREQ, 0}, /* CPU uses cpuclk */
@@ -50,9 +48,7 @@ static struct cpufreq_frequency_table kirkwood_freq_table[] = {
static unsigned int kirkwood_cpufreq_get_cpu_frequency(unsigned int cpu)
{
- if (__clk_is_enabled(priv.powersave_clk))
- return kirkwood_freq_table[1].frequency;
- return kirkwood_freq_table[0].frequency;
+ return clk_get_rate(priv.powersave_clk) / 1000;
}
static int kirkwood_cpufreq_target(struct cpufreq_policy *policy,
@@ -70,10 +66,10 @@ static int kirkwood_cpufreq_target(struct cpufreq_policy *policy,
switch (state) {
case STATE_CPU_FREQ:
- clk_disable(priv.powersave_clk);
+ clk_set_parent(priv.powersave_clk, priv.cpu_clk);
break;
case STATE_DDR_FREQ:
- clk_enable(priv.powersave_clk);
+ clk_set_parent(priv.powersave_clk, priv.ddr_clk);
break;
}
@@ -150,7 +146,7 @@ static int kirkwood_cpufreq_probe(struct platform_device *pdev)
err = PTR_ERR(priv.powersave_clk);
goto out_ddr;
}
- clk_prepare(priv.powersave_clk);
+ clk_prepare_enable(priv.powersave_clk);
of_node_put(np);
np = NULL;
diff --git a/include/dt-bindings/clock/maxim,max77686.h b/include/dt-bindings/clock/maxim,max77686.h
new file mode 100644
index 000000000000..7b28b0905869
--- /dev/null
+++ b/include/dt-bindings/clock/maxim,max77686.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2014 Google, Inc
+ *
+ * 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.
+ *
+ * Device Tree binding constants clocks for the Maxim 77686 PMIC.
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_MAXIM_MAX77686_CLOCK_H
+#define _DT_BINDINGS_CLOCK_MAXIM_MAX77686_CLOCK_H
+
+/* Fixed rate clocks. */
+
+#define MAX77686_CLK_AP 0
+#define MAX77686_CLK_CP 1
+#define MAX77686_CLK_PMIC 2
+
+/* Total number of clocks. */
+#define MAX77686_CLKS_NUM (MAX77686_CLK_PMIC + 1)
+
+#endif /* _DT_BINDINGS_CLOCK_MAXIM_MAX77686_CLOCK_H */
diff --git a/include/dt-bindings/clock/maxim,max77802.h b/include/dt-bindings/clock/maxim,max77802.h
new file mode 100644
index 000000000000..997312edcbb5
--- /dev/null
+++ b/include/dt-bindings/clock/maxim,max77802.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2014 Google, Inc
+ *
+ * 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.
+ *
+ * Device Tree binding constants clocks for the Maxim 77802 PMIC.
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_MAXIM_MAX77802_CLOCK_H
+#define _DT_BINDINGS_CLOCK_MAXIM_MAX77802_CLOCK_H
+
+/* Fixed rate clocks. */
+
+#define MAX77802_CLK_32K_AP 0
+#define MAX77802_CLK_32K_CP 1
+
+/* Total number of clocks. */
+#define MAX77802_CLKS_NUM (MAX77802_CLK_32K_CP + 1)
+
+#endif /* _DT_BINDINGS_CLOCK_MAXIM_MAX77802_CLOCK_H */
diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h
index efbf70b9fd84..4ed34105c371 100644
--- a/include/linux/clk-private.h
+++ b/include/linux/clk-private.h
@@ -48,6 +48,7 @@ struct clk {
unsigned long accuracy;
struct hlist_head children;
struct hlist_node child_node;
+ struct hlist_node debug_node;
unsigned int notifier_count;
#ifdef CONFIG_DEBUG_FS
struct dentry *dentry;