Browse Source

Merge branch 'depends/clk' into next/soc

From Mike Turquette:
* depends/clk:
  clk: Common clocks implementation for Versatile Express
  clk: Versatile Express clock generators ("osc") driver
  CLK: clk-twl6040: Initial clock driver for OMAP4+ McPDM fclk clock
  clk: fix return value check in sirfsoc_of_clk_init()
  clk: fix return value check in of_fixed_clk_setup()
  clk: ux500: Update sdmmc clock to 100MHz for u8500
  clk: ux500: Support prcmu ape opp voltage clock
  mfd: dbx500: Export prmcu_request_ape_opp_100_voltage
  clk: Don't return negative numbers for unsigned values with !clk
  clk: Fix documentation typos
  clk: Document .is_enabled op
  clk: SPEAr: Vco-pll: Fix compilation warning
Olof Johansson 12 years ago
parent
commit
17bffc7843

+ 2 - 0
arch/arm/include/asm/hardware/sp810.h

@@ -56,6 +56,8 @@
 #define SCCTRL_TIMEREN1SEL_REFCLK	(0 << 17)
 #define SCCTRL_TIMEREN1SEL_TIMCLK	(1 << 17)
 
+#define SCCTRL_TIMERENnSEL_SHIFT(n)	(15 + ((n) * 2))
+
 static inline void sysctl_soft_reset(void __iomem *base)
 {
 	/* switch to slow mode */

+ 13 - 3
drivers/clk/Kconfig

@@ -42,10 +42,12 @@ config COMMON_CLK_WM831X
 
 config COMMON_CLK_VERSATILE
 	bool "Clock driver for ARM Reference designs"
-	depends on ARCH_INTEGRATOR || ARCH_REALVIEW
+	depends on ARCH_INTEGRATOR || ARCH_REALVIEW || ARCH_VEXPRESS
 	---help---
-          Supports clocking on ARM Reference designs Integrator/AP,
-	  Integrator/CP, RealView PB1176, EB, PB11MP and PBX.
+          Supports clocking on ARM Reference designs:
+	  - Integrator/AP and Integrator/CP
+	  - RealView PB1176, EB, PB11MP and PBX
+	  - Versatile Express
 
 config COMMON_CLK_MAX77686
 	tristate "Clock driver for Maxim 77686 MFD"
@@ -53,4 +55,12 @@ config COMMON_CLK_MAX77686
 	---help---
 	  This driver supports Maxim 77686 crystal oscillator clock. 
 
+config CLK_TWL6040
+	tristate "External McPDM functional clock from twl6040"
+	depends on TWL6040_CORE
+	---help---
+	  Enable the external functional clock support on OMAP4+ platforms for
+	  McPDM. McPDM module is using the external bit clock on the McPDM bus
+	  as functional clock.
+
 endmenu

+ 1 - 0
drivers/clk/Makefile

@@ -24,3 +24,4 @@ obj-$(CONFIG_ARCH_SUNXI)	+= clk-sunxi.o
 # Chip specific
 obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
 obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
+obj-$(CONFIG_CLK_TWL6040)	+= clk-twl6040.o

+ 1 - 1
drivers/clk/clk-fixed-rate.c

@@ -97,7 +97,7 @@ void __init of_fixed_clk_setup(struct device_node *node)
 	of_property_read_string(node, "clock-output-names", &clk_name);
 
 	clk = clk_register_fixed_rate(NULL, clk_name, NULL, CLK_IS_ROOT, rate);
-	if (clk)
+	if (!IS_ERR(clk))
 		of_clk_add_provider(node, of_clk_src_simple_get, clk);
 }
 EXPORT_SYMBOL_GPL(of_fixed_clk_setup);

+ 42 - 42
drivers/clk/clk-prima2.c

@@ -1054,118 +1054,118 @@ void __init sirfsoc_of_clk_init(void)
 	/* These are always available (RTC and 26MHz OSC)*/
 	clk = clk_register_fixed_rate(NULL, "rtc", NULL,
 		CLK_IS_ROOT, 32768);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk = clk_register_fixed_rate(NULL, "osc", NULL,
 		CLK_IS_ROOT, 26000000);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 
 	clk = clk_register(NULL, &clk_pll1.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk = clk_register(NULL, &clk_pll2.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk = clk_register(NULL, &clk_pll3.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk = clk_register(NULL, &clk_mem.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk = clk_register(NULL, &clk_sys.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk = clk_register(NULL, &clk_security.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk_register_clkdev(clk, NULL, "b8030000.security");
 	clk = clk_register(NULL, &clk_dsp.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk = clk_register(NULL, &clk_gps.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk_register_clkdev(clk, NULL, "a8010000.gps");
 	clk = clk_register(NULL, &clk_mf.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk = clk_register(NULL, &clk_io.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk_register_clkdev(clk, NULL, "io");
 	clk = clk_register(NULL, &clk_cpu.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk_register_clkdev(clk, NULL, "cpu");
 	clk = clk_register(NULL, &clk_uart0.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk_register_clkdev(clk, NULL, "b0050000.uart");
 	clk = clk_register(NULL, &clk_uart1.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk_register_clkdev(clk, NULL, "b0060000.uart");
 	clk = clk_register(NULL, &clk_uart2.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk_register_clkdev(clk, NULL, "b0070000.uart");
 	clk = clk_register(NULL, &clk_tsc.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk_register_clkdev(clk, NULL, "b0110000.tsc");
 	clk = clk_register(NULL, &clk_i2c0.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk_register_clkdev(clk, NULL, "b00e0000.i2c");
 	clk = clk_register(NULL, &clk_i2c1.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk_register_clkdev(clk, NULL, "b00f0000.i2c");
 	clk = clk_register(NULL, &clk_spi0.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk_register_clkdev(clk, NULL, "b00d0000.spi");
 	clk = clk_register(NULL, &clk_spi1.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk_register_clkdev(clk, NULL, "b0170000.spi");
 	clk = clk_register(NULL, &clk_pwmc.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk_register_clkdev(clk, NULL, "b0130000.pwm");
 	clk = clk_register(NULL, &clk_efuse.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk_register_clkdev(clk, NULL, "b0140000.efusesys");
 	clk = clk_register(NULL, &clk_pulse.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk_register_clkdev(clk, NULL, "b0150000.pulsec");
 	clk = clk_register(NULL, &clk_dmac0.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk_register_clkdev(clk, NULL, "b00b0000.dma-controller");
 	clk = clk_register(NULL, &clk_dmac1.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk_register_clkdev(clk, NULL, "b0160000.dma-controller");
 	clk = clk_register(NULL, &clk_nand.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk_register_clkdev(clk, NULL, "b0030000.nand");
 	clk = clk_register(NULL, &clk_audio.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk_register_clkdev(clk, NULL, "b0040000.audio");
 	clk = clk_register(NULL, &clk_usp0.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk_register_clkdev(clk, NULL, "b0080000.usp");
 	clk = clk_register(NULL, &clk_usp1.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk_register_clkdev(clk, NULL, "b0090000.usp");
 	clk = clk_register(NULL, &clk_usp2.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk_register_clkdev(clk, NULL, "b00a0000.usp");
 	clk = clk_register(NULL, &clk_vip.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk_register_clkdev(clk, NULL, "b00c0000.vip");
 	clk = clk_register(NULL, &clk_gfx.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk_register_clkdev(clk, NULL, "98000000.graphics");
 	clk = clk_register(NULL, &clk_mm.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk_register_clkdev(clk, NULL, "a0000000.multimedia");
 	clk = clk_register(NULL, &clk_lcd.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk_register_clkdev(clk, NULL, "90010000.display");
 	clk = clk_register(NULL, &clk_vpp.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk_register_clkdev(clk, NULL, "90020000.vpp");
 	clk = clk_register(NULL, &clk_mmc01.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk = clk_register(NULL, &clk_mmc23.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk = clk_register(NULL, &clk_mmc45.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk = clk_register(NULL, &usb_pll_clk_hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk = clk_register(NULL, &clk_usb0.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk_register_clkdev(clk, NULL, "b00e0000.usb");
 	clk = clk_register(NULL, &clk_usb1.hw);
-	BUG_ON(!clk);
+	BUG_ON(IS_ERR(clk));
 	clk_register_clkdev(clk, NULL, "b00f0000.usb");
 }

+ 126 - 0
drivers/clk/clk-twl6040.c

@@ -0,0 +1,126 @@
+/*
+* TWL6040 clock module driver for OMAP4 McPDM functional clock
+*
+* Copyright (C) 2012 Texas Instruments Inc.
+* Peter Ujfalusi <peter.ujfalusi@ti.com>
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA
+*
+*/
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/twl6040.h>
+#include <linux/clk-provider.h>
+
+struct twl6040_clk {
+	struct twl6040 *twl6040;
+	struct device *dev;
+	struct clk_hw mcpdm_fclk;
+	struct clk *clk;
+	int enabled;
+};
+
+static int twl6040_bitclk_is_enabled(struct clk_hw *hw)
+{
+	struct twl6040_clk *twl6040_clk = container_of(hw, struct twl6040_clk,
+						       mcpdm_fclk);
+	return twl6040_clk->enabled;
+}
+
+static int twl6040_bitclk_prepare(struct clk_hw *hw)
+{
+	struct twl6040_clk *twl6040_clk = container_of(hw, struct twl6040_clk,
+						       mcpdm_fclk);
+	int ret;
+
+	ret = twl6040_power(twl6040_clk->twl6040, 1);
+	if (!ret)
+		twl6040_clk->enabled = 1;
+
+	return ret;
+}
+
+static void twl6040_bitclk_unprepare(struct clk_hw *hw)
+{
+	struct twl6040_clk *twl6040_clk = container_of(hw, struct twl6040_clk,
+						       mcpdm_fclk);
+	int ret;
+
+	ret = twl6040_power(twl6040_clk->twl6040, 0);
+	if (!ret)
+		twl6040_clk->enabled = 0;
+}
+
+static const struct clk_ops twl6040_mcpdm_ops = {
+	.is_enabled = twl6040_bitclk_is_enabled,
+	.prepare = twl6040_bitclk_prepare,
+	.unprepare = twl6040_bitclk_unprepare,
+};
+
+static struct clk_init_data wm831x_clkout_init = {
+	.name = "mcpdm_fclk",
+	.ops = &twl6040_mcpdm_ops,
+	.flags = CLK_IS_ROOT,
+};
+
+static int __devinit twl6040_clk_probe(struct platform_device *pdev)
+{
+	struct twl6040 *twl6040 = dev_get_drvdata(pdev->dev.parent);
+	struct twl6040_clk *clkdata;
+
+	clkdata = devm_kzalloc(&pdev->dev, sizeof(*clkdata), GFP_KERNEL);
+	if (!clkdata)
+		return -ENOMEM;
+
+	clkdata->dev = &pdev->dev;
+	clkdata->twl6040 = twl6040;
+
+	clkdata->mcpdm_fclk.init = &wm831x_clkout_init;
+	clkdata->clk = clk_register(&pdev->dev, &clkdata->mcpdm_fclk);
+	if (!clkdata->clk)
+		return -EINVAL;
+
+	dev_set_drvdata(&pdev->dev, clkdata);
+
+	return 0;
+}
+
+static int __devexit twl6040_clk_remove(struct platform_device *pdev)
+{
+	struct twl6040_clk *clkdata = dev_get_drvdata(&pdev->dev);
+
+	clk_unregister(clkdata->clk);
+
+	return 0;
+}
+
+static struct platform_driver twl6040_clk_driver = {
+	.driver = {
+		.name = "twl6040-clk",
+		.owner = THIS_MODULE,
+	},
+	.probe = twl6040_clk_probe,
+	.remove = __devexit_p(twl6040_clk_remove),
+};
+
+module_platform_driver(twl6040_clk_driver);
+
+MODULE_DESCRIPTION("TWL6040 clock driver for McPDM functional clock");
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
+MODULE_ALIAS("platform:twl6040-clk");
+MODULE_LICENSE("GPL");

+ 10 - 10
drivers/clk/clk.c

@@ -261,7 +261,7 @@ inline struct clk_hw *__clk_get_hw(struct clk *clk)
 
 inline u8 __clk_get_num_parents(struct clk *clk)
 {
-	return !clk ? -EINVAL : clk->num_parents;
+	return !clk ? 0 : clk->num_parents;
 }
 
 inline struct clk *__clk_get_parent(struct clk *clk)
@@ -269,14 +269,14 @@ inline struct clk *__clk_get_parent(struct clk *clk)
 	return !clk ? NULL : clk->parent;
 }
 
-inline int __clk_get_enable_count(struct clk *clk)
+inline unsigned int __clk_get_enable_count(struct clk *clk)
 {
-	return !clk ? -EINVAL : clk->enable_count;
+	return !clk ? 0 : clk->enable_count;
 }
 
-inline int __clk_get_prepare_count(struct clk *clk)
+inline unsigned int __clk_get_prepare_count(struct clk *clk)
 {
-	return !clk ? -EINVAL : clk->prepare_count;
+	return !clk ? 0 : clk->prepare_count;
 }
 
 unsigned long __clk_get_rate(struct clk *clk)
@@ -302,15 +302,15 @@ out:
 
 inline unsigned long __clk_get_flags(struct clk *clk)
 {
-	return !clk ? -EINVAL : clk->flags;
+	return !clk ? 0 : clk->flags;
 }
 
-int __clk_is_enabled(struct clk *clk)
+bool __clk_is_enabled(struct clk *clk)
 {
 	int ret;
 
 	if (!clk)
-		return -EINVAL;
+		return false;
 
 	/*
 	 * .is_enabled is only mandatory for clocks that gate
@@ -323,7 +323,7 @@ int __clk_is_enabled(struct clk *clk)
 
 	ret = clk->ops->is_enabled(clk->hw);
 out:
-	return ret;
+	return !!ret;
 }
 
 static struct clk *__clk_lookup_subtree(const char *name, struct clk *clk)
@@ -568,7 +568,7 @@ unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
 	unsigned long parent_rate = 0;
 
 	if (!clk)
-		return -EINVAL;
+		return 0;
 
 	if (!clk->ops->round_rate) {
 		if (clk->flags & CLK_SET_RATE_PARENT)

+ 1 - 1
drivers/clk/spear/clk-vco-pll.c

@@ -147,7 +147,7 @@ static int clk_pll_set_rate(struct clk_hw *hw, unsigned long drate,
 	struct clk_pll *pll = to_clk_pll(hw);
 	struct pll_rate_tbl *rtbl = pll->vco->rtbl;
 	unsigned long flags = 0, val;
-	int i;
+	int uninitialized_var(i);
 
 	clk_pll_round_rate_index(hw, drate, NULL, &i);
 

+ 55 - 0
drivers/clk/ux500/clk-prcmu.c

@@ -133,6 +133,40 @@ out_error:
 		hw->init->name);
 }
 
+static int clk_prcmu_opp_volt_prepare(struct clk_hw *hw)
+{
+	int err;
+	struct clk_prcmu *clk = to_clk_prcmu(hw);
+
+	err = prcmu_request_ape_opp_100_voltage(true);
+	if (err) {
+		pr_err("clk_prcmu: %s failed to request APE OPP VOLT for %s.\n",
+			__func__, hw->init->name);
+		return err;
+	}
+
+	err = prcmu_request_clock(clk->cg_sel, true);
+	if (err)
+		prcmu_request_ape_opp_100_voltage(false);
+
+	return err;
+}
+
+static void clk_prcmu_opp_volt_unprepare(struct clk_hw *hw)
+{
+	struct clk_prcmu *clk = to_clk_prcmu(hw);
+
+	if (prcmu_request_clock(clk->cg_sel, false))
+		goto out_error;
+	if (prcmu_request_ape_opp_100_voltage(false))
+		goto out_error;
+	return;
+
+out_error:
+	pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
+		hw->init->name);
+}
+
 static struct clk_ops clk_prcmu_scalable_ops = {
 	.prepare = clk_prcmu_prepare,
 	.unprepare = clk_prcmu_unprepare,
@@ -167,6 +201,17 @@ static struct clk_ops clk_prcmu_opp_gate_ops = {
 	.recalc_rate = clk_prcmu_recalc_rate,
 };
 
+static struct clk_ops clk_prcmu_opp_volt_scalable_ops = {
+	.prepare = clk_prcmu_opp_volt_prepare,
+	.unprepare = clk_prcmu_opp_volt_unprepare,
+	.enable = clk_prcmu_enable,
+	.disable = clk_prcmu_disable,
+	.is_enabled = clk_prcmu_is_enabled,
+	.recalc_rate = clk_prcmu_recalc_rate,
+	.round_rate = clk_prcmu_round_rate,
+	.set_rate = clk_prcmu_set_rate,
+};
+
 static struct clk *clk_reg_prcmu(const char *name,
 				 const char *parent_name,
 				 u8 cg_sel,
@@ -250,3 +295,13 @@ struct clk *clk_reg_prcmu_opp_gate(const char *name,
 	return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags,
 			&clk_prcmu_opp_gate_ops);
 }
+
+struct clk *clk_reg_prcmu_opp_volt_scalable(const char *name,
+					    const char *parent_name,
+					    u8 cg_sel,
+					    unsigned long rate,
+					    unsigned long flags)
+{
+	return clk_reg_prcmu(name, parent_name, cg_sel, rate, flags,
+			&clk_prcmu_opp_volt_scalable_ops);
+}

+ 6 - 0
drivers/clk/ux500/clk.h

@@ -45,4 +45,10 @@ struct clk *clk_reg_prcmu_opp_gate(const char *name,
 				   u8 cg_sel,
 				   unsigned long flags);
 
+struct clk *clk_reg_prcmu_opp_volt_scalable(const char *name,
+					    const char *parent_name,
+					    u8 cg_sel,
+					    unsigned long rate,
+					    unsigned long flags);
+
 #endif /* __UX500_CLK_H */

+ 3 - 2
drivers/clk/ux500/u8500_clk.c

@@ -170,10 +170,11 @@ void u8500_clk_init(void)
 	clk_register_clkdev(clk, NULL, "mtu0");
 	clk_register_clkdev(clk, NULL, "mtu1");
 
-	clk = clk_reg_prcmu_gate("sdmmcclk", NULL, PRCMU_SDMMCCLK, CLK_IS_ROOT);
+	clk = clk_reg_prcmu_opp_volt_scalable("sdmmcclk", NULL, PRCMU_SDMMCCLK,
+					100000000,
+					CLK_IS_ROOT|CLK_SET_RATE_GATE);
 	clk_register_clkdev(clk, NULL, "sdmmc");
 
-
 	clk = clk_reg_prcmu_scalable("dsi_pll", "hdmiclk",
 				PRCMU_PLLDSI, 0, CLK_SET_RATE_GATE);
 	clk_register_clkdev(clk, "dsihs2", "mcde");

+ 2 - 0
drivers/clk/versatile/Makefile

@@ -2,3 +2,5 @@
 obj-$(CONFIG_ICST)		+= clk-icst.o
 obj-$(CONFIG_ARCH_INTEGRATOR)	+= clk-integrator.o
 obj-$(CONFIG_ARCH_REALVIEW)	+= clk-realview.o
+obj-$(CONFIG_ARCH_VEXPRESS)	+= clk-vexpress.o
+obj-$(CONFIG_VEXPRESS_CONFIG)	+= clk-vexpress-osc.o

+ 146 - 0
drivers/clk/versatile/clk-vexpress-osc.c

@@ -0,0 +1,146 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Copyright (C) 2012 ARM Limited
+ */
+
+#define pr_fmt(fmt) "vexpress-osc: " fmt
+
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/vexpress.h>
+
+struct vexpress_osc {
+	struct vexpress_config_func *func;
+	struct clk_hw hw;
+	unsigned long rate_min;
+	unsigned long rate_max;
+};
+
+#define to_vexpress_osc(osc) container_of(osc, struct vexpress_osc, hw)
+
+static unsigned long vexpress_osc_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct vexpress_osc *osc = to_vexpress_osc(hw);
+	u32 rate;
+
+	vexpress_config_read(osc->func, 0, &rate);
+
+	return rate;
+}
+
+static long vexpress_osc_round_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long *parent_rate)
+{
+	struct vexpress_osc *osc = to_vexpress_osc(hw);
+
+	if (WARN_ON(osc->rate_min && rate < osc->rate_min))
+		rate = osc->rate_min;
+
+	if (WARN_ON(osc->rate_max && rate > osc->rate_max))
+		rate = osc->rate_max;
+
+	return rate;
+}
+
+static int vexpress_osc_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
+{
+	struct vexpress_osc *osc = to_vexpress_osc(hw);
+
+	return vexpress_config_write(osc->func, 0, rate);
+}
+
+static struct clk_ops vexpress_osc_ops = {
+	.recalc_rate = vexpress_osc_recalc_rate,
+	.round_rate = vexpress_osc_round_rate,
+	.set_rate = vexpress_osc_set_rate,
+};
+
+
+struct clk * __init vexpress_osc_setup(struct device *dev)
+{
+	struct clk_init_data init;
+	struct vexpress_osc *osc = kzalloc(sizeof(*osc), GFP_KERNEL);
+
+	if (!osc)
+		return NULL;
+
+	osc->func = vexpress_config_func_get_by_dev(dev);
+	if (!osc->func) {
+		kfree(osc);
+		return NULL;
+	}
+
+	init.name = dev_name(dev);
+	init.ops = &vexpress_osc_ops;
+	init.flags = CLK_IS_ROOT;
+	init.num_parents = 0;
+	osc->hw.init = &init;
+
+	return clk_register(NULL, &osc->hw);
+}
+
+void __init vexpress_osc_of_setup(struct device_node *node)
+{
+	struct clk_init_data init;
+	struct vexpress_osc *osc;
+	struct clk *clk;
+	u32 range[2];
+
+	osc = kzalloc(sizeof(*osc), GFP_KERNEL);
+	if (!osc)
+		goto error;
+
+	osc->func = vexpress_config_func_get_by_node(node);
+	if (!osc->func) {
+		pr_err("Failed to obtain config func for node '%s'!\n",
+				node->name);
+		goto error;
+	}
+
+	if (of_property_read_u32_array(node, "freq-range", range,
+			ARRAY_SIZE(range)) == 0) {
+		osc->rate_min = range[0];
+		osc->rate_max = range[1];
+	}
+
+	of_property_read_string(node, "clock-output-names", &init.name);
+	if (!init.name)
+		init.name = node->name;
+
+	init.ops = &vexpress_osc_ops;
+	init.flags = CLK_IS_ROOT;
+	init.num_parents = 0;
+
+	osc->hw.init = &init;
+
+	clk = clk_register(NULL, &osc->hw);
+	if (IS_ERR(clk)) {
+		pr_err("Failed to register clock '%s'!\n", init.name);
+		goto error;
+	}
+
+	of_clk_add_provider(node, of_clk_src_simple_get, clk);
+
+	pr_debug("Registered clock '%s'\n", init.name);
+
+	return;
+
+error:
+	if (osc->func)
+		vexpress_config_func_put(osc->func);
+	kfree(osc);
+}

+ 142 - 0
drivers/clk/versatile/clk-vexpress.c

@@ -0,0 +1,142 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Copyright (C) 2012 ARM Limited
+ */
+
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/vexpress.h>
+
+#include <asm/hardware/sp810.h>
+
+static struct clk *vexpress_sp810_timerclken[4];
+static DEFINE_SPINLOCK(vexpress_sp810_lock);
+
+static void __init vexpress_sp810_init(void __iomem *base)
+{
+	int i;
+
+	if (WARN_ON(!base))
+		return;
+
+	for (i = 0; i < ARRAY_SIZE(vexpress_sp810_timerclken); i++) {
+		char name[12];
+		const char *parents[] = {
+			"v2m:refclk32khz", /* REFCLK */
+			"v2m:refclk1mhz" /* TIMCLK */
+		};
+
+		snprintf(name, ARRAY_SIZE(name), "timerclken%d", i);
+
+		vexpress_sp810_timerclken[i] = clk_register_mux(NULL, name,
+				parents, 2, 0, base + SCCTRL,
+				SCCTRL_TIMERENnSEL_SHIFT(i), 1,
+				0, &vexpress_sp810_lock);
+
+		if (WARN_ON(IS_ERR(vexpress_sp810_timerclken[i])))
+			break;
+	}
+}
+
+
+static const char * const vexpress_clk_24mhz_periphs[] __initconst = {
+	"mb:uart0", "mb:uart1", "mb:uart2", "mb:uart3",
+	"mb:mmci", "mb:kmi0", "mb:kmi1"
+};
+
+void __init vexpress_clk_init(void __iomem *sp810_base)
+{
+	struct clk *clk;
+	int i;
+
+	clk = clk_register_fixed_rate(NULL, "dummy_apb_pclk", NULL,
+			CLK_IS_ROOT, 0);
+	WARN_ON(clk_register_clkdev(clk, "apb_pclk", NULL));
+
+	clk = clk_register_fixed_rate(NULL, "v2m:clk_24mhz", NULL,
+			CLK_IS_ROOT, 24000000);
+	for (i = 0; i < ARRAY_SIZE(vexpress_clk_24mhz_periphs); i++)
+		WARN_ON(clk_register_clkdev(clk, NULL,
+				vexpress_clk_24mhz_periphs[i]));
+
+	clk = clk_register_fixed_rate(NULL, "v2m:refclk32khz", NULL,
+			CLK_IS_ROOT, 32768);
+	WARN_ON(clk_register_clkdev(clk, NULL, "v2m:wdt"));
+
+	clk = clk_register_fixed_rate(NULL, "v2m:refclk1mhz", NULL,
+			CLK_IS_ROOT, 1000000);
+
+	vexpress_sp810_init(sp810_base);
+
+	for (i = 0; i < ARRAY_SIZE(vexpress_sp810_timerclken); i++)
+		WARN_ON(clk_set_parent(vexpress_sp810_timerclken[i], clk));
+
+	WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[0],
+				"v2m-timer0", "sp804"));
+	WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[1],
+				"v2m-timer1", "sp804"));
+}
+
+#if defined(CONFIG_OF)
+
+struct clk *vexpress_sp810_of_get(struct of_phandle_args *clkspec, void *data)
+{
+	if (WARN_ON(clkspec->args_count != 1 || clkspec->args[0] >
+			ARRAY_SIZE(vexpress_sp810_timerclken)))
+		return NULL;
+
+	return vexpress_sp810_timerclken[clkspec->args[0]];
+}
+
+static const __initconst struct of_device_id vexpress_fixed_clk_match[] = {
+	{ .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
+	{ .compatible = "arm,vexpress-osc", .data = vexpress_osc_of_setup, },
+	{}
+};
+
+void __init vexpress_clk_of_init(void)
+{
+	struct device_node *node;
+	struct clk *clk;
+	struct clk *refclk, *timclk;
+
+	of_clk_init(vexpress_fixed_clk_match);
+
+	node = of_find_compatible_node(NULL, NULL, "arm,sp810");
+	vexpress_sp810_init(of_iomap(node, 0));
+	of_clk_add_provider(node, vexpress_sp810_of_get, NULL);
+
+	/* Select "better" (faster) parent for SP804 timers */
+	refclk = of_clk_get_by_name(node, "refclk");
+	timclk = of_clk_get_by_name(node, "timclk");
+	if (!WARN_ON(IS_ERR(refclk) || IS_ERR(timclk))) {
+		int i = 0;
+
+		if (clk_get_rate(refclk) > clk_get_rate(timclk))
+			clk = refclk;
+		else
+			clk = timclk;
+
+		for (i = 0; i < ARRAY_SIZE(vexpress_sp810_timerclken); i++)
+			WARN_ON(clk_set_parent(vexpress_sp810_timerclken[i],
+					clk));
+	}
+
+	WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[0],
+				"v2m-timer0", "sp804"));
+	WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[1],
+				"v2m-timer1", "sp804"));
+}
+
+#endif

+ 2 - 2
drivers/mfd/db8500-prcmu.c

@@ -1169,12 +1169,12 @@ int db8500_prcmu_get_ape_opp(void)
 }
 
 /**
- * prcmu_request_ape_opp_100_voltage - Request APE OPP 100% voltage
+ * db8500_prcmu_request_ape_opp_100_voltage - Request APE OPP 100% voltage
  * @enable: true to request the higher voltage, false to drop a request.
  *
  * Calls to this function to enable and disable requests must be balanced.
  */
-int prcmu_request_ape_opp_100_voltage(bool enable)
+int db8500_prcmu_request_ape_opp_100_voltage(bool enable)
 {
 	int r = 0;
 	u8 header;

+ 10 - 6
include/linux/clk-provider.h

@@ -53,9 +53,13 @@ struct clk_hw;
  * @disable:	Disable the clock atomically. Called with enable_lock held.
  * 		This function must not sleep.
  *
- * @recalc_rate	Recalculate the rate of this clock, by quering hardware.  The
+ * @is_enabled:	Queries the hardware to determine if the clock is enabled.
+ * 		This function must not sleep. Optional, if this op is not
+ * 		set then the enable count will be used.
+ *
+ * @recalc_rate	Recalculate the rate of this clock, by querying hardware. The
  * 		parent rate is an input parameter.  It is up to the caller to
- * 		insure that the prepare_mutex is held across this call.
+ * 		ensure that the prepare_mutex is held across this call.
  * 		Returns the calculated rate.  Optional, but recommended - if
  * 		this op is not set then clock rate will be initialized to 0.
  *
@@ -89,7 +93,7 @@ struct clk_hw;
  * implementations to split any work between atomic (enable) and sleepable
  * (prepare) contexts.  If enabling a clock requires code that might sleep,
  * this must be done in clk_prepare.  Clock enable code that will never be
- * called in a sleepable context may be implement in clk_enable.
+ * called in a sleepable context may be implemented in clk_enable.
  *
  * Typically, drivers will call clk_prepare when a clock may be needed later
  * (eg. when a device is opened), and clk_enable when the clock is actually
@@ -335,11 +339,11 @@ const char *__clk_get_name(struct clk *clk);
 struct clk_hw *__clk_get_hw(struct clk *clk);
 u8 __clk_get_num_parents(struct clk *clk);
 struct clk *__clk_get_parent(struct clk *clk);
-inline int __clk_get_enable_count(struct clk *clk);
-inline int __clk_get_prepare_count(struct clk *clk);
+inline unsigned int __clk_get_enable_count(struct clk *clk);
+inline unsigned int __clk_get_prepare_count(struct clk *clk);
 unsigned long __clk_get_rate(struct clk *clk);
 unsigned long __clk_get_flags(struct clk *clk);
-int __clk_is_enabled(struct clk *clk);
+bool __clk_is_enabled(struct clk *clk);
 struct clk *__clk_lookup(const char *name);
 
 /*

+ 2 - 2
include/linux/mfd/db8500-prcmu.h

@@ -515,7 +515,6 @@ enum romcode_read prcmu_get_rc_p2a(void);
 enum ap_pwrst prcmu_get_xp70_current_state(void);
 bool prcmu_has_arm_maxopp(void);
 struct prcmu_fw_version *prcmu_get_fw_version(void);
-int prcmu_request_ape_opp_100_voltage(bool enable);
 int prcmu_release_usb_wakeup_state(void);
 void prcmu_configure_auto_pm(struct prcmu_auto_pm_config *sleep,
 	struct prcmu_auto_pm_config *idle);
@@ -564,6 +563,7 @@ int db8500_prcmu_set_arm_opp(u8 opp);
 int db8500_prcmu_get_arm_opp(void);
 int db8500_prcmu_set_ape_opp(u8 opp);
 int db8500_prcmu_get_ape_opp(void);
+int db8500_prcmu_request_ape_opp_100_voltage(bool enable);
 int db8500_prcmu_set_ddr_opp(u8 opp);
 int db8500_prcmu_get_ddr_opp(void);
 
@@ -610,7 +610,7 @@ static inline int db8500_prcmu_get_ape_opp(void)
 	return APE_100_OPP;
 }
 
-static inline int prcmu_request_ape_opp_100_voltage(bool enable)
+static inline int db8500_prcmu_request_ape_opp_100_voltage(bool enable)
 {
 	return 0;
 }

+ 10 - 0
include/linux/mfd/dbx500-prcmu.h

@@ -336,6 +336,11 @@ static inline int prcmu_get_ape_opp(void)
 	return db8500_prcmu_get_ape_opp();
 }
 
+static inline int prcmu_request_ape_opp_100_voltage(bool enable)
+{
+	return db8500_prcmu_request_ape_opp_100_voltage(enable);
+}
+
 static inline void prcmu_system_reset(u16 reset_code)
 {
 	return db8500_prcmu_system_reset(reset_code);
@@ -507,6 +512,11 @@ static inline int prcmu_get_ape_opp(void)
 	return APE_100_OPP;
 }
 
+static inline int prcmu_request_ape_opp_100_voltage(bool enable)
+{
+	return 0;
+}
+
 static inline int prcmu_set_arm_opp(u8 opp)
 {
 	return 0;