提交 17bffc78 编写于 作者: O Olof Johansson

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
......@@ -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 */
......
......@@ -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
......@@ -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
......@@ -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);
......
......@@ -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");
}
/*
* 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");
......@@ -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 @@ unsigned long __clk_get_rate(struct clk *clk)
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)
......
......@@ -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);
......
......@@ -133,6 +133,40 @@ static void clk_prcmu_opp_unprepare(struct clk_hw *hw)
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);
}
......@@ -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 */
......@@ -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,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
/*
* 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);
}
/*
* 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
......@@ -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;
......
......@@ -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);
/*
......
......@@ -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;
}
......
......@@ -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;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册