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
This commit is contained in:
Коммит
17bffc7843
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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");
|
|
@ -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)
|
||||
|
|
|
@ -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 @@ 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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче