Commit 93874681 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'clk-for-linus' of git://git.linaro.org/people/mturquette/linux

Pull clock framework changes from Mike Turquette:
 "The common clock framework changes for 3.8 are comprised of lots of
  fixes for existing platforms as well as new ports for some ARM
  platforms.  In addition there are new clk drivers for audio devices
  and MFDs."

Fix up trivial conflict in <linux/clk-provider.h> (removal of 'inline'
clashing with return type fixes)

* tag 'clk-for-linus' of git://git.linaro.org/people/mturquette/linux: (51 commits)
  MAINTAINERS: bad email address for Mike Turquette
  clk: introduce optional disable_unused callback
  clk: ux500: fix bit error
  clk: clock multiplexers may register out of order
  clk: ux500: Initial support for abx500 clock driver
  CLK: SPEAr: Remove unused dummy apb_pclk
  CLK: SPEAr: Correct index scanning done for clock synths
  CLK: SPEAr: Update clock rate table
  CLK: SPEAr: Add missing clocks
  CLK: SPEAr: Set CLK_SET_RATE_PARENT for few clocks
  CLK: SPEAr13xx: fix parent names of multiple clocks
  CLK: SPEAr13xx: Fix mux clock names
  CLK: SPEAr: Fix dev_id & con_id for multiple clocks
  clk: move IM-PD1 clocks to drivers/clk
  clk: make ICST driver handle the VCO registers
  clk: add GPLv2 headers to the Versatile clock files
  clk: mxs: Use a better name for the USB PHY clock
  clk: spear: Add stub functions for spear3[0|1|2]0_clk_init()
  CLK: clk-twl6040: fix return value check in twl6040_clk_probe()
  clk: ux500: Register nomadik keypad clock lookups for u8500
  ...
parents 505cbeda 8f871896
...@@ -52,7 +52,7 @@ clocks and IDs. ...@@ -52,7 +52,7 @@ clocks and IDs.
lcdif 38 lcdif 38
etm 39 etm 39
usb 40 usb 40
usb_pwr 41 usb_phy 41
Examples: Examples:
......
...@@ -73,8 +73,8 @@ clocks and IDs. ...@@ -73,8 +73,8 @@ clocks and IDs.
can1 59 can1 59
usb0 60 usb0 60
usb1 61 usb1 61
usb0_pwr 62 usb0_phy 62
usb1_pwr 63 usb1_phy 63
enet_out 64 enet_out 64
Examples: Examples:
......
...@@ -1987,7 +1987,6 @@ F: fs/coda/ ...@@ -1987,7 +1987,6 @@ F: fs/coda/
F: include/linux/coda*.h F: include/linux/coda*.h
COMMON CLK FRAMEWORK COMMON CLK FRAMEWORK
M: Mike Turquette <mturquette@ti.com>
M: Mike Turquette <mturquette@linaro.org> M: Mike Turquette <mturquette@linaro.org>
L: linux-arm-kernel@lists.infradead.org (same as CLK API & CLKDEV) L: linux-arm-kernel@lists.infradead.org (same as CLK API & CLKDEV)
T: git git://git.linaro.org/people/mturquette/linux.git T: git git://git.linaro.org/people/mturquette/linux.git
......
...@@ -56,6 +56,8 @@ ...@@ -56,6 +56,8 @@
#define SCCTRL_TIMEREN1SEL_REFCLK (0 << 17) #define SCCTRL_TIMEREN1SEL_REFCLK (0 << 17)
#define SCCTRL_TIMEREN1SEL_TIMCLK (1 << 17) #define SCCTRL_TIMEREN1SEL_TIMCLK (1 << 17)
#define SCCTRL_TIMERENnSEL_SHIFT(n) (15 + ((n) * 2))
static inline void sysctl_soft_reset(void __iomem *base) static inline void sysctl_soft_reset(void __iomem *base)
{ {
/* switch to slow mode */ /* switch to slow mode */
......
...@@ -21,10 +21,9 @@ ...@@ -21,10 +21,9 @@
#include <linux/amba/bus.h> #include <linux/amba/bus.h>
#include <linux/amba/clcd.h> #include <linux/amba/clcd.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/platform_data/clk-integrator.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/clkdev.h>
#include <asm/hardware/icst.h>
#include <mach/lm.h> #include <mach/lm.h>
#include <mach/impd1.h> #include <mach/impd1.h>
#include <asm/sizes.h> #include <asm/sizes.h>
...@@ -36,45 +35,6 @@ MODULE_PARM_DESC(lmid, "logic module stack position"); ...@@ -36,45 +35,6 @@ MODULE_PARM_DESC(lmid, "logic module stack position");
struct impd1_module { struct impd1_module {
void __iomem *base; void __iomem *base;
struct clk vcos[2];
struct clk_lookup *clks[3];
};
static const struct icst_params impd1_vco_params = {
.ref = 24000000, /* 24 MHz */
.vco_max = ICST525_VCO_MAX_3V,
.vco_min = ICST525_VCO_MIN,
.vd_min = 12,
.vd_max = 519,
.rd_min = 3,
.rd_max = 120,
.s2div = icst525_s2div,
.idx2s = icst525_idx2s,
};
static void impd1_setvco(struct clk *clk, struct icst_vco vco)
{
struct impd1_module *impd1 = clk->data;
u32 val = vco.v | (vco.r << 9) | (vco.s << 16);
writel(0xa05f, impd1->base + IMPD1_LOCK);
writel(val, clk->vcoreg);
writel(0, impd1->base + IMPD1_LOCK);
#ifdef DEBUG
vco.v = val & 0x1ff;
vco.r = (val >> 9) & 0x7f;
vco.s = (val >> 16) & 7;
pr_debug("IM-PD1: VCO%d clock is %ld Hz\n",
vconr, icst525_hz(&impd1_vco_params, vco));
#endif
}
static const struct clk_ops impd1_clk_ops = {
.round = icst_clk_round,
.set = icst_clk_set,
.setvco = impd1_setvco,
}; };
void impd1_tweak_control(struct device *dev, u32 mask, u32 val) void impd1_tweak_control(struct device *dev, u32 mask, u32 val)
...@@ -344,10 +304,6 @@ static struct impd1_device impd1_devs[] = { ...@@ -344,10 +304,6 @@ static struct impd1_device impd1_devs[] = {
} }
}; };
static struct clk fixed_14745600 = {
.rate = 14745600,
};
static int impd1_probe(struct lm_device *dev) static int impd1_probe(struct lm_device *dev)
{ {
struct impd1_module *impd1; struct impd1_module *impd1;
...@@ -376,23 +332,7 @@ static int impd1_probe(struct lm_device *dev) ...@@ -376,23 +332,7 @@ static int impd1_probe(struct lm_device *dev)
printk("IM-PD1 found at 0x%08lx\n", printk("IM-PD1 found at 0x%08lx\n",
(unsigned long)dev->resource.start); (unsigned long)dev->resource.start);
for (i = 0; i < ARRAY_SIZE(impd1->vcos); i++) { integrator_impd1_clk_init(impd1->base, dev->id);
impd1->vcos[i].ops = &impd1_clk_ops,
impd1->vcos[i].owner = THIS_MODULE,
impd1->vcos[i].params = &impd1_vco_params,
impd1->vcos[i].data = impd1;
}
impd1->vcos[0].vcoreg = impd1->base + IMPD1_OSC1;
impd1->vcos[1].vcoreg = impd1->base + IMPD1_OSC2;
impd1->clks[0] = clkdev_alloc(&impd1->vcos[0], NULL, "lm%x:01000",
dev->id);
impd1->clks[1] = clkdev_alloc(&fixed_14745600, NULL, "lm%x:00100",
dev->id);
impd1->clks[2] = clkdev_alloc(&fixed_14745600, NULL, "lm%x:00200",
dev->id);
for (i = 0; i < ARRAY_SIZE(impd1->clks); i++)
clkdev_add(impd1->clks[i]);
for (i = 0; i < ARRAY_SIZE(impd1_devs); i++) { for (i = 0; i < ARRAY_SIZE(impd1_devs); i++) {
struct impd1_device *idev = impd1_devs + i; struct impd1_device *idev = impd1_devs + i;
...@@ -431,12 +371,9 @@ static int impd1_remove_one(struct device *dev, void *data) ...@@ -431,12 +371,9 @@ static int impd1_remove_one(struct device *dev, void *data)
static void impd1_remove(struct lm_device *dev) static void impd1_remove(struct lm_device *dev)
{ {
struct impd1_module *impd1 = lm_get_drvdata(dev); struct impd1_module *impd1 = lm_get_drvdata(dev);
int i;
device_for_each_child(&dev->dev, NULL, impd1_remove_one); device_for_each_child(&dev->dev, NULL, impd1_remove_one);
integrator_impd1_clk_exit(dev->id);
for (i = 0; i < ARRAY_SIZE(impd1->clks); i++)
clkdev_drop(impd1->clks[i]);
lm_set_drvdata(dev, NULL); lm_set_drvdata(dev, NULL);
......
...@@ -214,9 +214,6 @@ struct device * __init u8500_init_devices(struct ab8500_platform_data *ab8500) ...@@ -214,9 +214,6 @@ struct device * __init u8500_init_devices(struct ab8500_platform_data *ab8500)
db8500_add_gpios(parent); db8500_add_gpios(parent);
db8500_add_usb(parent, usb_db8500_rx_dma_cfg, usb_db8500_tx_dma_cfg); db8500_add_usb(parent, usb_db8500_rx_dma_cfg, usb_db8500_tx_dma_cfg);
platform_device_register_data(parent,
"cpufreq-u8500", -1, NULL, 0);
for (i = 0; i < ARRAY_SIZE(platform_devs); i++) for (i = 0; i < ARRAY_SIZE(platform_devs); i++)
platform_devs[i]->dev.parent = parent; platform_devs[i]->dev.parent = parent;
...@@ -236,9 +233,6 @@ struct device * __init u8500_of_init_devices(void) ...@@ -236,9 +233,6 @@ struct device * __init u8500_of_init_devices(void)
db8500_add_usb(parent, usb_db8500_rx_dma_cfg, usb_db8500_tx_dma_cfg); db8500_add_usb(parent, usb_db8500_rx_dma_cfg, usb_db8500_tx_dma_cfg);
platform_device_register_data(parent,
"cpufreq-u8500", -1, NULL, 0);
u8500_dma40_device.dev.parent = parent; u8500_dma40_device.dev.parent = parent;
/* /*
......
...@@ -42,10 +42,12 @@ config COMMON_CLK_WM831X ...@@ -42,10 +42,12 @@ config COMMON_CLK_WM831X
config COMMON_CLK_VERSATILE config COMMON_CLK_VERSATILE
bool "Clock driver for ARM Reference designs" bool "Clock driver for ARM Reference designs"
depends on ARCH_INTEGRATOR || ARCH_REALVIEW depends on ARCH_INTEGRATOR || ARCH_REALVIEW || ARCH_VEXPRESS
---help--- ---help---
Supports clocking on ARM Reference designs Integrator/AP, Supports clocking on ARM Reference designs:
Integrator/CP, RealView PB1176, EB, PB11MP and PBX. - Integrator/AP and Integrator/CP
- RealView PB1176, EB, PB11MP and PBX
- Versatile Express
config COMMON_CLK_MAX77686 config COMMON_CLK_MAX77686
tristate "Clock driver for Maxim 77686 MFD" tristate "Clock driver for Maxim 77686 MFD"
...@@ -53,4 +55,12 @@ config COMMON_CLK_MAX77686 ...@@ -53,4 +55,12 @@ config COMMON_CLK_MAX77686
---help--- ---help---
This driver supports Maxim 77686 crystal oscillator clock. 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 endmenu
...@@ -23,3 +23,4 @@ obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o ...@@ -23,3 +23,4 @@ obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o
# Chip specific # Chip specific
obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o
...@@ -33,17 +33,17 @@ void __init bcm2835_init_clocks(void) ...@@ -33,17 +33,17 @@ void __init bcm2835_init_clocks(void)
clk = clk_register_fixed_rate(NULL, "sys_pclk", NULL, CLK_IS_ROOT, clk = clk_register_fixed_rate(NULL, "sys_pclk", NULL, CLK_IS_ROOT,
250000000); 250000000);
if (!clk) if (IS_ERR(clk))
pr_err("sys_pclk not registered\n"); pr_err("sys_pclk not registered\n");
clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT,
126000000); 126000000);
if (!clk) if (IS_ERR(clk))
pr_err("apb_pclk not registered\n"); pr_err("apb_pclk not registered\n");
clk = clk_register_fixed_rate(NULL, "uart0_pclk", NULL, CLK_IS_ROOT, clk = clk_register_fixed_rate(NULL, "uart0_pclk", NULL, CLK_IS_ROOT,
3000000); 3000000);
if (!clk) if (IS_ERR(clk))
pr_err("uart0_pclk not registered\n"); pr_err("uart0_pclk not registered\n");
ret = clk_register_clkdev(clk, NULL, "20201000.uart"); ret = clk_register_clkdev(clk, NULL, "20201000.uart");
if (ret) if (ret)
...@@ -51,7 +51,7 @@ void __init bcm2835_init_clocks(void) ...@@ -51,7 +51,7 @@ void __init bcm2835_init_clocks(void)
clk = clk_register_fixed_rate(NULL, "uart1_pclk", NULL, CLK_IS_ROOT, clk = clk_register_fixed_rate(NULL, "uart1_pclk", NULL, CLK_IS_ROOT,
125000000); 125000000);
if (!clk) if (IS_ERR(clk))
pr_err("uart1_pclk not registered\n"); pr_err("uart1_pclk not registered\n");
ret = clk_register_clkdev(clk, NULL, "20215000.uart"); ret = clk_register_clkdev(clk, NULL, "20215000.uart");
if (ret) if (ret)
......
...@@ -97,7 +97,7 @@ void __init of_fixed_clk_setup(struct device_node *node) ...@@ -97,7 +97,7 @@ void __init of_fixed_clk_setup(struct device_node *node)
of_property_read_string(node, "clock-output-names", &clk_name); of_property_read_string(node, "clock-output-names", &clk_name);
clk = clk_register_fixed_rate(NULL, clk_name, NULL, CLK_IS_ROOT, rate); 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); of_clk_add_provider(node, of_clk_src_simple_get, clk);
} }
EXPORT_SYMBOL_GPL(of_fixed_clk_setup); EXPORT_SYMBOL_GPL(of_fixed_clk_setup);
......
...@@ -1054,118 +1054,118 @@ void __init sirfsoc_of_clk_init(void) ...@@ -1054,118 +1054,118 @@ void __init sirfsoc_of_clk_init(void)
/* These are always available (RTC and 26MHz OSC)*/ /* These are always available (RTC and 26MHz OSC)*/
clk = clk_register_fixed_rate(NULL, "rtc", NULL, clk = clk_register_fixed_rate(NULL, "rtc", NULL,
CLK_IS_ROOT, 32768); CLK_IS_ROOT, 32768);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk = clk_register_fixed_rate(NULL, "osc", NULL, clk = clk_register_fixed_rate(NULL, "osc", NULL,
CLK_IS_ROOT, 26000000); CLK_IS_ROOT, 26000000);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_pll1.hw); clk = clk_register(NULL, &clk_pll1.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_pll2.hw); clk = clk_register(NULL, &clk_pll2.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_pll3.hw); clk = clk_register(NULL, &clk_pll3.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_mem.hw); clk = clk_register(NULL, &clk_mem.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_sys.hw); clk = clk_register(NULL, &clk_sys.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_security.hw); clk = clk_register(NULL, &clk_security.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b8030000.security"); clk_register_clkdev(clk, NULL, "b8030000.security");
clk = clk_register(NULL, &clk_dsp.hw); clk = clk_register(NULL, &clk_dsp.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_gps.hw); clk = clk_register(NULL, &clk_gps.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "a8010000.gps"); clk_register_clkdev(clk, NULL, "a8010000.gps");
clk = clk_register(NULL, &clk_mf.hw); clk = clk_register(NULL, &clk_mf.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_io.hw); clk = clk_register(NULL, &clk_io.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "io"); clk_register_clkdev(clk, NULL, "io");
clk = clk_register(NULL, &clk_cpu.hw); clk = clk_register(NULL, &clk_cpu.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "cpu"); clk_register_clkdev(clk, NULL, "cpu");
clk = clk_register(NULL, &clk_uart0.hw); clk = clk_register(NULL, &clk_uart0.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0050000.uart"); clk_register_clkdev(clk, NULL, "b0050000.uart");
clk = clk_register(NULL, &clk_uart1.hw); clk = clk_register(NULL, &clk_uart1.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0060000.uart"); clk_register_clkdev(clk, NULL, "b0060000.uart");
clk = clk_register(NULL, &clk_uart2.hw); clk = clk_register(NULL, &clk_uart2.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0070000.uart"); clk_register_clkdev(clk, NULL, "b0070000.uart");
clk = clk_register(NULL, &clk_tsc.hw); clk = clk_register(NULL, &clk_tsc.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0110000.tsc"); clk_register_clkdev(clk, NULL, "b0110000.tsc");
clk = clk_register(NULL, &clk_i2c0.hw); clk = clk_register(NULL, &clk_i2c0.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b00e0000.i2c"); clk_register_clkdev(clk, NULL, "b00e0000.i2c");
clk = clk_register(NULL, &clk_i2c1.hw); clk = clk_register(NULL, &clk_i2c1.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b00f0000.i2c"); clk_register_clkdev(clk, NULL, "b00f0000.i2c");
clk = clk_register(NULL, &clk_spi0.hw); clk = clk_register(NULL, &clk_spi0.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b00d0000.spi"); clk_register_clkdev(clk, NULL, "b00d0000.spi");
clk = clk_register(NULL, &clk_spi1.hw); clk = clk_register(NULL, &clk_spi1.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0170000.spi"); clk_register_clkdev(clk, NULL, "b0170000.spi");
clk = clk_register(NULL, &clk_pwmc.hw); clk = clk_register(NULL, &clk_pwmc.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0130000.pwm"); clk_register_clkdev(clk, NULL, "b0130000.pwm");
clk = clk_register(NULL, &clk_efuse.hw); clk = clk_register(NULL, &clk_efuse.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0140000.efusesys"); clk_register_clkdev(clk, NULL, "b0140000.efusesys");
clk = clk_register(NULL, &clk_pulse.hw); clk = clk_register(NULL, &clk_pulse.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0150000.pulsec"); clk_register_clkdev(clk, NULL, "b0150000.pulsec");
clk = clk_register(NULL, &clk_dmac0.hw); clk = clk_register(NULL, &clk_dmac0.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b00b0000.dma-controller"); clk_register_clkdev(clk, NULL, "b00b0000.dma-controller");
clk = clk_register(NULL, &clk_dmac1.hw); clk = clk_register(NULL, &clk_dmac1.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0160000.dma-controller"); clk_register_clkdev(clk, NULL, "b0160000.dma-controller");
clk = clk_register(NULL, &clk_nand.hw); clk = clk_register(NULL, &clk_nand.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0030000.nand"); clk_register_clkdev(clk, NULL, "b0030000.nand");
clk = clk_register(NULL, &clk_audio.hw); clk = clk_register(NULL, &clk_audio.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0040000.audio"); clk_register_clkdev(clk, NULL, "b0040000.audio");
clk = clk_register(NULL, &clk_usp0.hw); clk = clk_register(NULL, &clk_usp0.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0080000.usp"); clk_register_clkdev(clk, NULL, "b0080000.usp");
clk = clk_register(NULL, &clk_usp1.hw); clk = clk_register(NULL, &clk_usp1.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0090000.usp"); clk_register_clkdev(clk, NULL, "b0090000.usp");
clk = clk_register(NULL, &clk_usp2.hw); clk = clk_register(NULL, &clk_usp2.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b00a0000.usp"); clk_register_clkdev(clk, NULL, "b00a0000.usp");
clk = clk_register(NULL, &clk_vip.hw); clk = clk_register(NULL, &clk_vip.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b00c0000.vip"); clk_register_clkdev(clk, NULL, "b00c0000.vip");
clk = clk_register(NULL, &clk_gfx.hw); clk = clk_register(NULL, &clk_gfx.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "98000000.graphics"); clk_register_clkdev(clk, NULL, "98000000.graphics");
clk = clk_register(NULL, &clk_mm.hw); clk = clk_register(NULL, &clk_mm.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "a0000000.multimedia"); clk_register_clkdev(clk, NULL, "a0000000.multimedia");
clk = clk_register(NULL, &clk_lcd.hw); clk = clk_register(NULL, &clk_lcd.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "90010000.display"); clk_register_clkdev(clk, NULL, "90010000.display");
clk = clk_register(NULL, &clk_vpp.hw); clk = clk_register(NULL, &clk_vpp.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "90020000.vpp"); clk_register_clkdev(clk, NULL, "90020000.vpp");
clk = clk_register(NULL, &clk_mmc01.hw); clk = clk_register(NULL, &clk_mmc01.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_mmc23.hw); clk = clk_register(NULL, &clk_mmc23.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_mmc45.hw); clk = clk_register(NULL, &clk_mmc45.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &usb_pll_clk_hw); clk = clk_register(NULL, &usb_pll_clk_hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_usb0.hw); clk = clk_register(NULL, &clk_usb0.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b00e0000.usb"); clk_register_clkdev(clk, NULL, "b00e0000.usb");
clk = clk_register(NULL, &clk_usb1.hw); clk = clk_register(NULL, &clk_usb1.hw);
BUG_ON(!clk); BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b00f0000.usb"); 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 (IS_ERR(clkdata->clk))
return PTR_ERR(clkdata->clk);
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");
...@@ -120,8 +120,17 @@ static unsigned long vt8500_dclk_recalc_rate(struct clk_hw *hw, ...@@ -120,8 +120,17 @@ static unsigned long vt8500_dclk_recalc_rate(struct clk_hw *hw,
static long vt8500_dclk_round_rate(struct clk_hw *hw, unsigned long rate, static long vt8500_dclk_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate) unsigned long *prate)
{ {
struct clk_device *cdev = to_clk_device(hw);
u32 divisor = *prate / rate; u32 divisor = *prate / rate;
/*
* If this is a request for SDMMC we have to adjust the divisor
* when >31 to use the fixed predivisor
*/
if ((cdev->div_mask == 0x3F) && (divisor > 31)) {
divisor = 64 * ((divisor / 64) + 1);
}
return *prate / divisor; return *prate / divisor;
} }
...@@ -135,6 +144,15 @@ static int vt8500_dclk_set_rate(struct clk_hw *hw, unsigned long rate, ...@@ -135,6 +144,15 @@ static int vt8500_dclk_set_rate(struct clk_hw *hw, unsigned long rate,
if (divisor == cdev->div_mask + 1) if (divisor == cdev->div_mask + 1)
divisor = 0; divisor = 0;
/* SDMMC mask may need to be corrected before testing if its valid */
if ((cdev->div_mask == 0x3F) && (divisor > 31)) {
/*
* Bit 5 is a fixed /64 predivisor. If the requested divisor
* is >31 then correct for the fixed divisor being required.
*/
divisor = 0x20 + (divisor / 64);
}
if (divisor > cdev->div_mask) { if (divisor > cdev->div_mask) {
pr_err("%s: invalid divisor for clock\n", __func__); pr_err("%s: invalid divisor for clock\n", __func__);
return -EINVAL; return -EINVAL;
......
...@@ -370,43 +370,27 @@ static __devinit int wm831x_clk_probe(struct platform_device *pdev) ...@@ -370,43 +370,27 @@ static __devinit int wm831x_clk_probe(struct platform_device *pdev)
clkdata->xtal_ena = ret & WM831X_XTAL_ENA; clkdata->xtal_ena = ret & WM831X_XTAL_ENA;
clkdata->xtal_hw.init = &wm831x_xtal_init; clkdata->xtal_hw.init = &wm831x_xtal_init;
clkdata->xtal = clk_register(&pdev->dev, &clkdata->xtal_hw); clkdata->xtal = devm_clk_register(&pdev->dev, &clkdata->xtal_hw);
if (!clkdata->xtal) if (IS_ERR(clkdata->xtal))
return -EINVAL; return PTR_ERR(clkdata->xtal);
clkdata->fll_hw.init = &wm831x_fll_init; clkdata->fll_hw.init = &wm831x_fll_init;
clkdata->fll = clk_register(&pdev->dev, &clkdata->fll_hw); clkdata->fll = devm_clk_register(&pdev->dev, &clkdata->fll_hw);
if (!clkdata->fll) { if (IS_ERR(clkdata->fll))
ret = -EINVAL; return PTR_ERR(clkdata->fll);
goto err_xtal;
}
clkdata->clkout_hw.init = &wm831x_clkout_init; clkdata->clkout_hw.init = &wm831x_clkout_init;
clkdata->clkout = clk_register(&pdev->dev, &clkdata->clkout_hw); clkdata->clkout = devm_clk_register(&pdev->dev, &clkdata->clkout_hw);
if (!clkdata->clkout) { if (IS_ERR(clkdata->clkout))
ret = -EINVAL; return PTR_ERR(clkdata->clkout);
goto err_fll;
}
dev_set_drvdata(&pdev->dev, clkdata); dev_set_drvdata(&pdev->dev, clkdata);
return 0; return 0;
err_fll:
clk_unregister(clkdata->fll);
err_xtal:
clk_unregister(clkdata->xtal);
return ret;
} }
static int __devexit wm831x_clk_remove(struct platform_device *pdev) static int __devexit wm831x_clk_remove(struct platform_device *pdev)
{ {
struct wm831x_clk *clkdata = dev_get_drvdata(&pdev->dev);
clk_unregister(clkdata->clkout);
clk_unregister(clkdata->fll);
clk_unregister(clkdata->xtal);
return 0; return 0;
} }
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/device.h>
static DEFINE_SPINLOCK(enable_lock); static DEFINE_SPINLOCK(enable_lock);
static DEFINE_MUTEX(prepare_lock); static DEFINE_MUTEX(prepare_lock);
...@@ -218,8 +219,17 @@ static void clk_disable_unused_subtree(struct clk *clk) ...@@ -218,8 +219,17 @@ static void clk_disable_unused_subtree(struct clk *clk)
if (clk->flags & CLK_IGNORE_UNUSED) if (clk->flags & CLK_IGNORE_UNUSED)
goto unlock_out; goto unlock_out;
if (__clk_is_enabled(clk) && clk->ops->disable) /*
* some gate clocks have special needs during the disable-unused
* sequence. call .disable_unused if available, otherwise fall
* back to .disable
*/
if (__clk_is_enabled(clk)) {
if (clk->ops->disable_unused)
clk->ops->disable_unused(clk->hw);
else if (clk->ops->disable)
clk->ops->disable(clk->hw); clk->ops->disable(clk->hw);
}
unlock_out: unlock_out:
spin_unlock_irqrestore(&enable_lock, flags); spin_unlock_irqrestore(&enable_lock, flags);
...@@ -261,7 +271,7 @@ inline struct clk_hw *__clk_get_hw(struct clk *clk) ...@@ -261,7 +271,7 @@ inline struct clk_hw *__clk_get_hw(struct clk *clk)
inline u8 __clk_get_num_parents(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) inline struct clk *__clk_get_parent(struct clk *clk)
...@@ -269,14 +279,14 @@ inline struct clk *__clk_get_parent(struct clk *clk) ...@@ -269,14 +279,14 @@ inline struct clk *__clk_get_parent(struct clk *clk)
return !clk ? NULL : clk->parent; 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) unsigned long __clk_get_rate(struct clk *clk)
...@@ -302,15 +312,15 @@ unsigned long __clk_get_rate(struct clk *clk) ...@@ -302,15 +312,15 @@ unsigned long __clk_get_rate(struct clk *clk)
inline unsigned long __clk_get_flags(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; int ret;
if (!clk) if (!clk)
return -EINVAL; return false;
/* /*
* .is_enabled is only mandatory for clocks that gate * .is_enabled is only mandatory for clocks that gate
...@@ -323,7 +333,7 @@ int __clk_is_enabled(struct clk *clk) ...@@ -323,7 +333,7 @@ int __clk_is_enabled(struct clk *clk)
ret = clk->ops->is_enabled(clk->hw); ret = clk->ops->is_enabled(clk->hw);
out: out:
return ret; return !!ret;
} }
static struct clk *__clk_lookup_subtree(const char *name, struct clk *clk) static struct clk *__clk_lookup_subtree(const char *name, struct clk *clk)
...@@ -568,7 +578,7 @@ unsigned long __clk_round_rate(struct clk *clk, unsigned long rate) ...@@ -568,7 +578,7 @@ unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
unsigned long parent_rate = 0; unsigned long parent_rate = 0;
if (!clk) if (!clk)
return -EINVAL; return 0;
if (!clk->ops->round_rate) { if (!clk->ops->round_rate) {
if (clk->flags & CLK_SET_RATE_PARENT) if (clk->flags & CLK_SET_RATE_PARENT)
...@@ -1297,12 +1307,20 @@ int __clk_init(struct device *dev, struct clk *clk) ...@@ -1297,12 +1307,20 @@ int __clk_init(struct device *dev, struct clk *clk)
* walk the list of orphan clocks and reparent any that are children of * walk the list of orphan clocks and reparent any that are children of
* this clock * this clock
*/ */
hlist_for_each_entry_safe(orphan, tmp, tmp2, &clk_orphan_list, child_node) hlist_for_each_entry_safe(orphan, tmp, tmp2, &clk_orphan_list, child_node) {
if (orphan->ops->get_parent) {
i = orphan->ops->get_parent(orphan->hw);
if (!strcmp(clk->name, orphan->parent_names[i]))
__clk_reparent(orphan, clk);
continue;
}
for (i = 0; i < orphan->num_parents; i++) for (i = 0; i < orphan->num_parents; i++)
if (!strcmp(clk->name, orphan->parent_names[i])) { if (!strcmp(clk->name, orphan->parent_names[i])) {
__clk_reparent(orphan, clk); __clk_reparent(orphan, clk);
break; break;
} }
}
/* /*
* optional platform-specific magic * optional platform-specific magic
...@@ -1361,28 +1379,9 @@ struct clk *__clk_register(struct device *dev, struct clk_hw *hw) ...@@ -1361,28 +1379,9 @@ struct clk *__clk_register(struct device *dev, struct clk_hw *hw)
} }
EXPORT_SYMBOL_GPL(__clk_register); EXPORT_SYMBOL_GPL(__clk_register);
/** static int _clk_register(struct device *dev, struct clk_hw *hw, struct clk *clk)
* clk_register - allocate a new clock, register it and return an opaque cookie
* @dev: device that is registering this clock
* @hw: link to hardware-specific clock data
*
* clk_register is the primary interface for populating the clock tree with new
* clock nodes. It returns a pointer to the newly allocated struct clk which
* cannot be dereferenced by driver code but may be used in conjuction with the
* rest of the clock API. In the event of an error clk_register will return an
* error code; drivers must test for an error code after calling clk_register.
*/
struct clk *clk_register(struct device *dev, struct clk_hw *hw)
{ {
int i, ret; int i, ret;
struct clk *clk;
clk = kzalloc(sizeof(*clk), GFP_KERNEL);
if (!clk) {
pr_err("%s: could not allocate clk\n", __func__);
ret = -ENOMEM;
goto fail_out;
}
clk->name = kstrdup(hw->init->name, GFP_KERNEL); clk->name = kstrdup(hw->init->name, GFP_KERNEL);
if (!clk->name) { if (!clk->name) {
...@@ -1420,7 +1419,7 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw) ...@@ -1420,7 +1419,7 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
ret = __clk_init(dev, clk); ret = __clk_init(dev, clk);
if (!ret) if (!ret)
return clk; return 0;
fail_parent_names_copy: fail_parent_names_copy:
while (--i >= 0) while (--i >= 0)
...@@ -1429,6 +1428,36 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw) ...@@ -1429,6 +1428,36 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
fail_parent_names: fail_parent_names:
kfree(clk->name); kfree(clk->name);
fail_name: fail_name:
return ret;
}
/**
* clk_register - allocate a new clock, register it and return an opaque cookie
* @dev: device that is registering this clock
* @hw: link to hardware-specific clock data
*
* clk_register is the primary interface for populating the clock tree with new
* clock nodes. It returns a pointer to the newly allocated struct clk which
* cannot be dereferenced by driver code but may be used in conjuction with the
* rest of the clock API. In the event of an error clk_register will return an
* error code; drivers must test for an error code after calling clk_register.
*/
struct clk *clk_register(struct device *dev, struct clk_hw *hw)
{
int ret;
struct clk *clk;
clk = kzalloc(sizeof(*clk), GFP_KERNEL);
if (!clk) {
pr_err("%s: could not allocate clk\n", __func__);
ret = -ENOMEM;
goto fail_out;
}
ret = _clk_register(dev, hw, clk);
if (!ret)
return clk;
kfree(clk); kfree(clk);
fail_out: fail_out:
return ERR_PTR(ret); return ERR_PTR(ret);
...@@ -1444,6 +1473,63 @@ EXPORT_SYMBOL_GPL(clk_register); ...@@ -1444,6 +1473,63 @@ EXPORT_SYMBOL_GPL(clk_register);
void clk_unregister(struct clk *clk) {} void clk_unregister(struct clk *clk) {}
EXPORT_SYMBOL_GPL(clk_unregister); EXPORT_SYMBOL_GPL(clk_unregister);
static void devm_clk_release(struct device *dev, void *res)
{
clk_unregister(res);
}
/**
* devm_clk_register - resource managed clk_register()
* @dev: device that is registering this clock
* @hw: link to hardware-specific clock data
*
* Managed clk_register(). Clocks returned from this function are
* automatically clk_unregister()ed on driver detach. See clk_register() for
* more information.
*/
struct clk *devm_clk_register(struct device *dev, struct clk_hw *hw)
{
struct clk *clk;
int ret;
clk = devres_alloc(devm_clk_release, sizeof(*clk), GFP_KERNEL);
if (!clk)
return ERR_PTR(-ENOMEM);
ret = _clk_register(dev, hw, clk);
if (!ret) {
devres_add(dev, clk);
} else {
devres_free(clk);
clk = ERR_PTR(ret);
}
return clk;
}
EXPORT_SYMBOL_GPL(devm_clk_register);
static int devm_clk_match(struct device *dev, void *res, void *data)
{
struct clk *c = res;
if (WARN_ON(!c))
return 0;
return c == data;
}
/**
* devm_clk_unregister - resource managed clk_unregister()
* @clk: clock to unregister
*
* Deallocate a clock allocated with devm_clk_register(). Normally
* this function will not need to be called and the resource management
* code will ensure that the resource is freed.
*/
void devm_clk_unregister(struct device *dev, struct clk *clk)
{
WARN_ON(devres_release(dev, devm_clk_release, devm_clk_match, clk));
}
EXPORT_SYMBOL_GPL(devm_clk_unregister);
/*** clk rate change notifiers ***/ /*** clk rate change notifiers ***/
/** /**
......
...@@ -85,7 +85,7 @@ enum imx23_clk { ...@@ -85,7 +85,7 @@ enum imx23_clk {
cpu_xtal, hbus, xbus, lcdif_div, ssp_div, gpmi_div, emi_pll, cpu_xtal, hbus, xbus, lcdif_div, ssp_div, gpmi_div, emi_pll,
emi_xtal, etm_div, saif_div, clk32k_div, rtc, adc, spdif_div, emi_xtal, etm_div, saif_div, clk32k_div, rtc, adc, spdif_div,
clk32k, dri, pwm, filt, uart, ssp, gpmi, spdif, emi, saif, clk32k, dri, pwm, filt, uart, ssp, gpmi, spdif, emi, saif,
lcdif, etm, usb, usb_pwr, lcdif, etm, usb, usb_phy,
clk_max clk_max
}; };
...@@ -143,8 +143,8 @@ int __init mx23_clocks_init(void) ...@@ -143,8 +143,8 @@ int __init mx23_clocks_init(void)
clks[saif] = mxs_clk_gate("saif", "saif_div", SAIF, 31); clks[saif] = mxs_clk_gate("saif", "saif_div", SAIF, 31);
clks[lcdif] = mxs_clk_gate("lcdif", "lcdif_div", PIX, 31); clks[lcdif] = mxs_clk_gate("lcdif", "lcdif_div", PIX, 31);
clks[etm] = mxs_clk_gate("etm", "etm_div", ETM, 31); clks[etm] = mxs_clk_gate("etm", "etm_div", ETM, 31);
clks[usb] = mxs_clk_gate("usb", "usb_pwr", DIGCTRL, 2); clks[usb] = mxs_clk_gate("usb", "usb_phy", DIGCTRL, 2);
clks[usb_pwr] = clk_register_gate(NULL, "usb_pwr", "pll", 0, PLLCTRL0, 18, 0, &mxs_lock); clks[usb_phy] = clk_register_gate(NULL, "usb_phy", "pll", 0, PLLCTRL0, 18, 0, &mxs_lock);
for (i = 0; i < ARRAY_SIZE(clks); i++) for (i = 0; i < ARRAY_SIZE(clks); i++)
if (IS_ERR(clks[i])) { if (IS_ERR(clks[i])) {
......
...@@ -140,7 +140,7 @@ enum imx28_clk { ...@@ -140,7 +140,7 @@ enum imx28_clk {
emi_xtal, lcdif_div, etm_div, ptp, saif0_div, saif1_div, emi_xtal, lcdif_div, etm_div, ptp, saif0_div, saif1_div,
clk32k_div, rtc, lradc, spdif_div, clk32k, pwm, uart, ssp0, clk32k_div, rtc, lradc, spdif_div, clk32k, pwm, uart, ssp0,
ssp1, ssp2, ssp3, gpmi, spdif, emi, saif0, saif1, lcdif, etm, ssp1, ssp2, ssp3, gpmi, spdif, emi, saif0, saif1, lcdif, etm,
fec, can0, can1, usb0, usb1, usb0_pwr, usb1_pwr, enet_out, fec, can0, can1, usb0, usb1, usb0_phy, usb1_phy, enet_out,
clk_max clk_max
}; };
...@@ -218,10 +218,10 @@ int __init mx28_clocks_init(void) ...@@ -218,10 +218,10 @@ int __init mx28_clocks_init(void)
clks[fec] = mxs_clk_gate("fec", "hbus", ENET, 30); clks[fec] = mxs_clk_gate("fec", "hbus", ENET, 30);
clks[can0] = mxs_clk_gate("can0", "ref_xtal", FLEXCAN, 30); clks[can0] = mxs_clk_gate("can0", "ref_xtal", FLEXCAN, 30);
clks[can1] = mxs_clk_gate("can1", "ref_xtal", FLEXCAN, 28); clks[can1] = mxs_clk_gate("can1", "ref_xtal", FLEXCAN, 28);
clks[usb0] = mxs_clk_gate("usb0", "usb0_pwr", DIGCTRL, 2); clks[usb0] = mxs_clk_gate("usb0", "usb0_phy", DIGCTRL, 2);
clks[usb1] = mxs_clk_gate("usb1", "usb1_pwr", DIGCTRL, 16); clks[usb1] = mxs_clk_gate("usb1", "usb1_phy", DIGCTRL, 16);
clks[usb0_pwr] = clk_register_gate(NULL, "usb0_pwr", "pll0", 0, PLL0CTRL0, 18, 0, &mxs_lock); clks[usb0_phy] = clk_register_gate(NULL, "usb0_phy", "pll0", 0, PLL0CTRL0, 18, 0, &mxs_lock);
clks[usb1_pwr] = clk_register_gate(NULL, "usb1_pwr", "pll1", 0, PLL1CTRL0, 18, 0, &mxs_lock); clks[usb1_phy] = clk_register_gate(NULL, "usb1_phy", "pll1", 0, PLL1CTRL0, 18, 0, &mxs_lock);
clks[enet_out] = clk_register_gate(NULL, "enet_out", "pll2", 0, ENET, 18, 0, &mxs_lock); clks[enet_out] = clk_register_gate(NULL, "enet_out", "pll2", 0, ENET, 18, 0, &mxs_lock);
for (i = 0; i < ARRAY_SIZE(clks); i++) for (i = 0; i < ARRAY_SIZE(clks); i++)
......
...@@ -179,7 +179,8 @@ struct clk *clk_register_aux(const char *aux_name, const char *gate_name, ...@@ -179,7 +179,8 @@ struct clk *clk_register_aux(const char *aux_name, const char *gate_name,
if (gate_name) { if (gate_name) {
struct clk *tgate_clk; struct clk *tgate_clk;
tgate_clk = clk_register_gate(NULL, gate_name, aux_name, 0, reg, tgate_clk = clk_register_gate(NULL, gate_name, aux_name,
CLK_SET_RATE_PARENT, reg,
aux->masks->enable_bit, 0, lock); aux->masks->enable_bit, 0, lock);
if (IS_ERR_OR_NULL(tgate_clk)) if (IS_ERR_OR_NULL(tgate_clk))
goto free_aux; goto free_aux;
......
...@@ -147,7 +147,7 @@ static int clk_pll_set_rate(struct clk_hw *hw, unsigned long drate, ...@@ -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 clk_pll *pll = to_clk_pll(hw);
struct pll_rate_tbl *rtbl = pll->vco->rtbl; struct pll_rate_tbl *rtbl = pll->vco->rtbl;
unsigned long flags = 0, val; unsigned long flags = 0, val;
int i; int uninitialized_var(i);
clk_pll_round_rate_index(hw, drate, NULL, &i); clk_pll_round_rate_index(hw, drate, NULL, &i);
......
...@@ -32,5 +32,8 @@ long clk_round_rate_index(struct clk_hw *hw, unsigned long drate, ...@@ -32,5 +32,8 @@ long clk_round_rate_index(struct clk_hw *hw, unsigned long drate,
} }
} }
if ((*index) == rtbl_cnt)
(*index)--;
return rate; return rate;
} }
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -92,6 +92,7 @@ static struct pll_rate_tbl pll_rtbl[] = { ...@@ -92,6 +92,7 @@ static struct pll_rate_tbl pll_rtbl[] = {
/* aux rate configuration table, in ascending order of rates */ /* aux rate configuration table, in ascending order of rates */
static struct aux_rate_tbl aux_rtbl[] = { static struct aux_rate_tbl aux_rtbl[] = {
/* For PLL1 = 332 MHz */ /* For PLL1 = 332 MHz */
{.xscale = 2, .yscale = 27, .eq = 0}, /* 12.296 MHz */
{.xscale = 2, .yscale = 8, .eq = 0}, /* 41.5 MHz */ {.xscale = 2, .yscale = 8, .eq = 0}, /* 41.5 MHz */
{.xscale = 2, .yscale = 4, .eq = 0}, /* 83 MHz */ {.xscale = 2, .yscale = 4, .eq = 0}, /* 83 MHz */
{.xscale = 1, .yscale = 2, .eq = 1}, /* 166 MHz */ {.xscale = 1, .yscale = 2, .eq = 1}, /* 166 MHz */
...@@ -118,9 +119,6 @@ void __init spear6xx_clk_init(void) ...@@ -118,9 +119,6 @@ void __init spear6xx_clk_init(void)
{ {
struct clk *clk, *clk1; struct clk *clk, *clk1;
clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0);
clk_register_clkdev(clk, "apb_pclk", NULL);
clk = clk_register_fixed_rate(NULL, "osc_32k_clk", NULL, CLK_IS_ROOT, clk = clk_register_fixed_rate(NULL, "osc_32k_clk", NULL, CLK_IS_ROOT,
32000); 32000);
clk_register_clkdev(clk, "osc_32k_clk", NULL); clk_register_clkdev(clk, "osc_32k_clk", NULL);
...@@ -156,7 +154,8 @@ void __init spear6xx_clk_init(void) ...@@ -156,7 +154,8 @@ void __init spear6xx_clk_init(void)
clk_register_clkdev(clk, NULL, "wdt"); clk_register_clkdev(clk, NULL, "wdt");
/* clock derived from pll1 clk */ /* clock derived from pll1 clk */
clk = clk_register_fixed_factor(NULL, "cpu_clk", "pll1_clk", 0, 1, 1); clk = clk_register_fixed_factor(NULL, "cpu_clk", "pll1_clk",
CLK_SET_RATE_PARENT, 1, 1);
clk_register_clkdev(clk, "cpu_clk", NULL); clk_register_clkdev(clk, "cpu_clk", NULL);
clk = clk_register_divider(NULL, "ahb_clk", "pll1_clk", clk = clk_register_divider(NULL, "ahb_clk", "pll1_clk",
...@@ -261,11 +260,13 @@ void __init spear6xx_clk_init(void) ...@@ -261,11 +260,13 @@ void __init spear6xx_clk_init(void)
/* clock derived from pll3 clk */ /* clock derived from pll3 clk */
clk = clk_register_gate(NULL, "usbh0_clk", "pll3_clk", 0, clk = clk_register_gate(NULL, "usbh0_clk", "pll3_clk", 0,
PERIP1_CLK_ENB, USBH0_CLK_ENB, 0, &_lock); PERIP1_CLK_ENB, USBH0_CLK_ENB, 0, &_lock);
clk_register_clkdev(clk, NULL, "usbh.0_clk"); clk_register_clkdev(clk, NULL, "e1800000.ehci");
clk_register_clkdev(clk, NULL, "e1900000.ohci");
clk = clk_register_gate(NULL, "usbh1_clk", "pll3_clk", 0, clk = clk_register_gate(NULL, "usbh1_clk", "pll3_clk", 0,
PERIP1_CLK_ENB, USBH1_CLK_ENB, 0, &_lock); PERIP1_CLK_ENB, USBH1_CLK_ENB, 0, &_lock);
clk_register_clkdev(clk, NULL, "usbh.1_clk"); clk_register_clkdev(clk, NULL, "e2000000.ehci");
clk_register_clkdev(clk, NULL, "e2100000.ohci");
clk = clk_register_gate(NULL, "usbd_clk", "pll3_clk", 0, PERIP1_CLK_ENB, clk = clk_register_gate(NULL, "usbd_clk", "pll3_clk", 0, PERIP1_CLK_ENB,
USBD_CLK_ENB, 0, &_lock); USBD_CLK_ENB, 0, &_lock);
......
...@@ -10,3 +10,6 @@ obj-y += clk-prcmu.o ...@@ -10,3 +10,6 @@ obj-y += clk-prcmu.o
obj-y += u8500_clk.o obj-y += u8500_clk.o
obj-y += u9540_clk.o obj-y += u9540_clk.o
obj-y += u8540_clk.o obj-y += u8540_clk.o
# ABX500 clock driver
obj-y += abx500-clk.o
/*
* abx500 clock implementation for ux500 platform.
*
* Copyright (C) 2012 ST-Ericsson SA
* Author: Ulf Hansson <ulf.hansson@linaro.org>
*
* License terms: GNU General Public License (GPL) version 2
*/
#include <linux/err.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/mfd/abx500/ab8500.h>
/* TODO: Add clock implementations here */
/* Clock definitions for ab8500 */
static int ab8500_reg_clks(struct device *dev)
{
return 0;
}
/* Clock definitions for ab8540 */
static int ab8540_reg_clks(struct device *dev)
{
return 0;
}
/* Clock definitions for ab9540 */
static int ab9540_reg_clks(struct device *dev)
{
return 0;
}
static int __devinit abx500_clk_probe(struct platform_device *pdev)
{
struct ab8500 *parent = dev_get_drvdata(pdev->dev.parent);
int ret;
if (is_ab8500(parent) || is_ab8505(parent)) {
ret = ab8500_reg_clks(&pdev->dev);
} else if (is_ab8540(parent)) {
ret = ab8540_reg_clks(&pdev->dev);
} else if (is_ab9540(parent)) {
ret = ab9540_reg_clks(&pdev->dev);
} else {
dev_err(&pdev->dev, "non supported plf id\n");
return -ENODEV;
}
return ret;
}
static struct platform_driver abx500_clk_driver = {
.driver = {
.name = "abx500-clk",
.owner = THIS_MODULE,
},
.probe = abx500_clk_probe,
};
static int __init abx500_clk_init(void)
{
return platform_driver_register(&abx500_clk_driver);
}
arch_initcall(abx500_clk_init);
MODULE_AUTHOR("Ulf Hansson <ulf.hansson@linaro.org");
MODULE_DESCRIPTION("ABX500 clk driver");
MODULE_LICENSE("GPL v2");
...@@ -133,6 +133,40 @@ static void clk_prcmu_opp_unprepare(struct clk_hw *hw) ...@@ -133,6 +133,40 @@ static void clk_prcmu_opp_unprepare(struct clk_hw *hw)
hw->init->name); 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 = { static struct clk_ops clk_prcmu_scalable_ops = {
.prepare = clk_prcmu_prepare, .prepare = clk_prcmu_prepare,
.unprepare = clk_prcmu_unprepare, .unprepare = clk_prcmu_unprepare,
...@@ -153,6 +187,13 @@ static struct clk_ops clk_prcmu_gate_ops = { ...@@ -153,6 +187,13 @@ static struct clk_ops clk_prcmu_gate_ops = {
.recalc_rate = clk_prcmu_recalc_rate, .recalc_rate = clk_prcmu_recalc_rate,
}; };
static struct clk_ops clk_prcmu_scalable_rate_ops = {
.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_ops clk_prcmu_rate_ops = { static struct clk_ops clk_prcmu_rate_ops = {
.is_enabled = clk_prcmu_is_enabled, .is_enabled = clk_prcmu_is_enabled,
.recalc_rate = clk_prcmu_recalc_rate, .recalc_rate = clk_prcmu_recalc_rate,
...@@ -167,6 +208,17 @@ static struct clk_ops clk_prcmu_opp_gate_ops = { ...@@ -167,6 +208,17 @@ static struct clk_ops clk_prcmu_opp_gate_ops = {
.recalc_rate = clk_prcmu_recalc_rate, .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, static struct clk *clk_reg_prcmu(const char *name,
const char *parent_name, const char *parent_name,
u8 cg_sel, u8 cg_sel,
...@@ -233,6 +285,16 @@ struct clk *clk_reg_prcmu_gate(const char *name, ...@@ -233,6 +285,16 @@ struct clk *clk_reg_prcmu_gate(const char *name,
&clk_prcmu_gate_ops); &clk_prcmu_gate_ops);
} }
struct clk *clk_reg_prcmu_scalable_rate(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_scalable_rate_ops);
}
struct clk *clk_reg_prcmu_rate(const char *name, struct clk *clk_reg_prcmu_rate(const char *name,
const char *parent_name, const char *parent_name,
u8 cg_sel, u8 cg_sel,
...@@ -250,3 +312,13 @@ struct clk *clk_reg_prcmu_opp_gate(const char *name, ...@@ -250,3 +312,13 @@ struct clk *clk_reg_prcmu_opp_gate(const char *name,
return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags, return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags,
&clk_prcmu_opp_gate_ops); &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);
}
...@@ -35,6 +35,12 @@ struct clk *clk_reg_prcmu_gate(const char *name, ...@@ -35,6 +35,12 @@ struct clk *clk_reg_prcmu_gate(const char *name,
u8 cg_sel, u8 cg_sel,
unsigned long flags); unsigned long flags);
struct clk *clk_reg_prcmu_scalable_rate(const char *name,
const char *parent_name,
u8 cg_sel,
unsigned long rate,
unsigned long flags);
struct clk *clk_reg_prcmu_rate(const char *name, struct clk *clk_reg_prcmu_rate(const char *name,
const char *parent_name, const char *parent_name,
u8 cg_sel, u8 cg_sel,
...@@ -45,4 +51,10 @@ struct clk *clk_reg_prcmu_opp_gate(const char *name, ...@@ -45,4 +51,10 @@ struct clk *clk_reg_prcmu_opp_gate(const char *name,
u8 cg_sel, u8 cg_sel,
unsigned long flags); 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 */ #endif /* __UX500_CLK_H */
...@@ -170,10 +170,11 @@ void u8500_clk_init(void) ...@@ -170,10 +170,11 @@ void u8500_clk_init(void)
clk_register_clkdev(clk, NULL, "mtu0"); clk_register_clkdev(clk, NULL, "mtu0");
clk_register_clkdev(clk, NULL, "mtu1"); 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_register_clkdev(clk, NULL, "sdmmc");
clk = clk_reg_prcmu_scalable("dsi_pll", "hdmiclk", clk = clk_reg_prcmu_scalable("dsi_pll", "hdmiclk",
PRCMU_PLLDSI, 0, CLK_SET_RATE_GATE); PRCMU_PLLDSI, 0, CLK_SET_RATE_GATE);
clk_register_clkdev(clk, "dsihs2", "mcde"); clk_register_clkdev(clk, "dsihs2", "mcde");
...@@ -205,16 +206,18 @@ void u8500_clk_init(void) ...@@ -205,16 +206,18 @@ void u8500_clk_init(void)
clk_register_clkdev(clk, "dsilp2", "dsilink.2"); clk_register_clkdev(clk, "dsilp2", "dsilink.2");
clk_register_clkdev(clk, "dsilp2", "mcde"); clk_register_clkdev(clk, "dsilp2", "mcde");
clk = clk_reg_prcmu_rate("smp_twd", NULL, PRCMU_ARMSS, clk = clk_reg_prcmu_scalable_rate("armss", NULL,
CLK_IS_ROOT|CLK_GET_RATE_NOCACHE| PRCMU_ARMSS, 0, CLK_IS_ROOT|CLK_IGNORE_UNUSED);
CLK_IGNORE_UNUSED); clk_register_clkdev(clk, "armss", NULL);
clk = clk_register_fixed_factor(NULL, "smp_twd", "armss",
CLK_IGNORE_UNUSED, 1, 2);
clk_register_clkdev(clk, NULL, "smp_twd"); clk_register_clkdev(clk, NULL, "smp_twd");
/* /*
* FIXME: Add special handled PRCMU clocks here: * FIXME: Add special handled PRCMU clocks here:
* 1. clk_arm, use PRCMU_ARMCLK. * 1. clkout0yuv, use PRCMU as parent + need regulator + pinctrl.
* 2. clkout0yuv, use PRCMU as parent + need regulator + pinctrl. * 2. ab9540_clkout1yuv, see clkout0yuv
* 3. ab9540_clkout1yuv, see clkout0yuv
*/ */
/* PRCC P-clocks */ /* PRCC P-clocks */
...@@ -323,7 +326,7 @@ void u8500_clk_init(void) ...@@ -323,7 +326,7 @@ void u8500_clk_init(void)
clk_register_clkdev(clk, NULL, "gpioblock1"); clk_register_clkdev(clk, NULL, "gpioblock1");
clk = clk_reg_prcc_pclk("p2_pclk12", "per2clk", U8500_CLKRST2_BASE, clk = clk_reg_prcc_pclk("p2_pclk12", "per2clk", U8500_CLKRST2_BASE,
BIT(11), 0); BIT(12), 0);
clk = clk_reg_prcc_pclk("p3_pclk0", "per3clk", U8500_CLKRST3_BASE, clk = clk_reg_prcc_pclk("p3_pclk0", "per3clk", U8500_CLKRST3_BASE,
BIT(0), 0); BIT(0), 0);
...@@ -347,6 +350,8 @@ void u8500_clk_init(void) ...@@ -347,6 +350,8 @@ void u8500_clk_init(void)
clk = clk_reg_prcc_pclk("p3_pclk5", "per3clk", U8500_CLKRST3_BASE, clk = clk_reg_prcc_pclk("p3_pclk5", "per3clk", U8500_CLKRST3_BASE,
BIT(5), 0); BIT(5), 0);
clk_register_clkdev(clk, "apb_pclk", "ske");
clk_register_clkdev(clk, "apb_pclk", "nmk-ske-keypad");
clk = clk_reg_prcc_pclk("p3_pclk6", "per3clk", U8500_CLKRST3_BASE, clk = clk_reg_prcc_pclk("p3_pclk6", "per3clk", U8500_CLKRST3_BASE,
BIT(6), 0); BIT(6), 0);
...@@ -375,6 +380,7 @@ void u8500_clk_init(void) ...@@ -375,6 +380,7 @@ void u8500_clk_init(void)
clk = clk_reg_prcc_pclk("p6_pclk0", "per6clk", U8500_CLKRST6_BASE, clk = clk_reg_prcc_pclk("p6_pclk0", "per6clk", U8500_CLKRST6_BASE,
BIT(0), 0); BIT(0), 0);
clk_register_clkdev(clk, "apb_pclk", "rng");
clk = clk_reg_prcc_pclk("p6_pclk1", "per6clk", U8500_CLKRST6_BASE, clk = clk_reg_prcc_pclk("p6_pclk1", "per6clk", U8500_CLKRST6_BASE,
BIT(1), 0); BIT(1), 0);
...@@ -503,6 +509,8 @@ void u8500_clk_init(void) ...@@ -503,6 +509,8 @@ void u8500_clk_init(void)
clk = clk_reg_prcc_kclk("p3_ske_kclk", "rtc32k", clk = clk_reg_prcc_kclk("p3_ske_kclk", "rtc32k",
U8500_CLKRST3_BASE, BIT(5), CLK_SET_RATE_GATE); U8500_CLKRST3_BASE, BIT(5), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "ske");
clk_register_clkdev(clk, NULL, "nmk-ske-keypad");
clk = clk_reg_prcc_kclk("p3_uart2_kclk", "uartclk", clk = clk_reg_prcc_kclk("p3_uart2_kclk", "uartclk",
U8500_CLKRST3_BASE, BIT(6), CLK_SET_RATE_GATE); U8500_CLKRST3_BASE, BIT(6), CLK_SET_RATE_GATE);
...@@ -515,5 +523,5 @@ void u8500_clk_init(void) ...@@ -515,5 +523,5 @@ void u8500_clk_init(void)
/* Periph6 */ /* Periph6 */
clk = clk_reg_prcc_kclk("p3_rng_kclk", "rngclk", clk = clk_reg_prcc_kclk("p3_rng_kclk", "rngclk",
U8500_CLKRST6_BASE, BIT(0), CLK_SET_RATE_GATE); U8500_CLKRST6_BASE, BIT(0), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "rng");
} }
# Makefile for Versatile-specific clocks # Makefile for Versatile-specific clocks
obj-$(CONFIG_ICST) += clk-icst.o obj-$(CONFIG_ICST) += clk-icst.o
obj-$(CONFIG_ARCH_INTEGRATOR) += clk-integrator.o obj-$(CONFIG_ARCH_INTEGRATOR) += clk-integrator.o
obj-$(CONFIG_INTEGRATOR_IMPD1) += clk-impd1.o
obj-$(CONFIG_ARCH_REALVIEW) += clk-realview.o obj-$(CONFIG_ARCH_REALVIEW) += clk-realview.o
obj-$(CONFIG_ARCH_VEXPRESS) += clk-vexpress.o
obj-$(CONFIG_VEXPRESS_CONFIG) += clk-vexpress-osc.o
...@@ -3,6 +3,12 @@ ...@@ -3,6 +3,12 @@
* We wrap the custom interface from <asm/hardware/icst.h> into the generic * We wrap the custom interface from <asm/hardware/icst.h> into the generic
* clock framework. * clock framework.
* *
* Copyright (C) 2012 Linus Walleij
*
* 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.
*
* TODO: when all ARM reference designs are migrated to generic clocks, the * TODO: when all ARM reference designs are migrated to generic clocks, the
* ICST clock code from the ARM tree should probably be merged into this * ICST clock code from the ARM tree should probably be merged into this
* file. * file.
...@@ -11,33 +17,74 @@ ...@@ -11,33 +17,74 @@
#include <linux/clkdev.h> #include <linux/clkdev.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/io.h>
#include "clk-icst.h" #include "clk-icst.h"
/** /**
* struct clk_icst - ICST VCO clock wrapper * struct clk_icst - ICST VCO clock wrapper
* @hw: corresponding clock hardware entry * @hw: corresponding clock hardware entry
* @vcoreg: VCO register address
* @lockreg: VCO lock register address
* @params: parameters for this ICST instance * @params: parameters for this ICST instance
* @rate: current rate * @rate: current rate
* @setvco: function to commit ICST settings to hardware
*/ */
struct clk_icst { struct clk_icst {
struct clk_hw hw; struct clk_hw hw;
void __iomem *vcoreg;
void __iomem *lockreg;
const struct icst_params *params; const struct icst_params *params;
unsigned long rate; unsigned long rate;
struct icst_vco (*getvco)(void);
void (*setvco)(struct icst_vco);
}; };
#define to_icst(_hw) container_of(_hw, struct clk_icst, hw) #define to_icst(_hw) container_of(_hw, struct clk_icst, hw)
/**
* vco_get() - get ICST VCO settings from a certain register
* @vcoreg: register containing the VCO settings
*/
static struct icst_vco vco_get(void __iomem *vcoreg)
{
u32 val;
struct icst_vco vco;
val = readl(vcoreg);
vco.v = val & 0x1ff;
vco.r = (val >> 9) & 0x7f;
vco.s = (val >> 16) & 03;
return vco;
}
/**
* vco_set() - commit changes to an ICST VCO
* @locreg: register to poke to unlock the VCO for writing
* @vcoreg: register containing the VCO settings
* @vco: ICST VCO parameters to commit
*/
static void vco_set(void __iomem *lockreg,
void __iomem *vcoreg,
struct icst_vco vco)
{
u32 val;
val = readl(vcoreg) & ~0x7ffff;
val |= vco.v | (vco.r << 9) | (vco.s << 16);
/* This magic unlocks the VCO so it can be controlled */
writel(0xa05f, lockreg);
writel(val, vcoreg);
/* This locks the VCO again */
writel(0, lockreg);
}
static unsigned long icst_recalc_rate(struct clk_hw *hw, static unsigned long icst_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct clk_icst *icst = to_icst(hw); struct clk_icst *icst = to_icst(hw);
struct icst_vco vco; struct icst_vco vco;
vco = icst->getvco(); vco = vco_get(icst->vcoreg);
icst->rate = icst_hz(icst->params, vco); icst->rate = icst_hz(icst->params, vco);
return icst->rate; return icst->rate;
} }
...@@ -60,7 +107,7 @@ static int icst_set_rate(struct clk_hw *hw, unsigned long rate, ...@@ -60,7 +107,7 @@ static int icst_set_rate(struct clk_hw *hw, unsigned long rate,
vco = icst_hz_to_vco(icst->params, rate); vco = icst_hz_to_vco(icst->params, rate);
icst->rate = icst_hz(icst->params, vco); icst->rate = icst_hz(icst->params, vco);
icst->setvco(vco); vco_set(icst->vcoreg, icst->lockreg, vco);
return 0; return 0;
} }
...@@ -70,8 +117,9 @@ static const struct clk_ops icst_ops = { ...@@ -70,8 +117,9 @@ static const struct clk_ops icst_ops = {
.set_rate = icst_set_rate, .set_rate = icst_set_rate,
}; };
struct clk * __init icst_clk_register(struct device *dev, struct clk *icst_clk_register(struct device *dev,
const struct clk_icst_desc *desc) const struct clk_icst_desc *desc,
void __iomem *base)
{ {
struct clk *clk; struct clk *clk;
struct clk_icst *icst; struct clk_icst *icst;
...@@ -89,8 +137,8 @@ struct clk * __init icst_clk_register(struct device *dev, ...@@ -89,8 +137,8 @@ struct clk * __init icst_clk_register(struct device *dev,
init.num_parents = 0; init.num_parents = 0;
icst->hw.init = &init; icst->hw.init = &init;
icst->params = desc->params; icst->params = desc->params;
icst->getvco = desc->getvco; icst->vcoreg = base + desc->vco_offset;
icst->setvco = desc->setvco; icst->lockreg = base + desc->lock_offset;
clk = clk_register(dev, &icst->hw); clk = clk_register(dev, &icst->hw);
if (IS_ERR(clk)) if (IS_ERR(clk))
......
#include <asm/hardware/icst.h> #include <asm/hardware/icst.h>
/**
* struct clk_icst_desc - descriptor for the ICST VCO
* @params: ICST parameters
* @vco_offset: offset to the ICST VCO from the provided memory base
* @lock_offset: offset to the ICST VCO locking register from the provided
* memory base
*/
struct clk_icst_desc { struct clk_icst_desc {
const struct icst_params *params; const struct icst_params *params;
struct icst_vco (*getvco)(void); u32 vco_offset;
void (*setvco)(struct icst_vco); u32 lock_offset;
}; };
struct clk *icst_clk_register(struct device *dev, struct clk *icst_clk_register(struct device *dev,
const struct clk_icst_desc *desc); const struct clk_icst_desc *desc,
void __iomem *base);
/*
* Clock driver for the ARM Integrator/IM-PD1 board
* Copyright (C) 2012 Linus Walleij
*
* 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.
*/
#include <linux/clk-provider.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/platform_data/clk-integrator.h>
#include <mach/impd1.h>
#include "clk-icst.h"
struct impd1_clk {
struct clk *vcoclk;
struct clk *uartclk;
struct clk_lookup *clks[3];
};
static struct impd1_clk impd1_clks[4];
/*
* There are two VCO's on the IM-PD1 but only one is used by the
* kernel, that is why we are only implementing the control of
* IMPD1_OSC1 here.
*/
static const struct icst_params impd1_vco_params = {
.ref = 24000000, /* 24 MHz */
.vco_max = ICST525_VCO_MAX_3V,
.vco_min = ICST525_VCO_MIN,
.vd_min = 12,
.vd_max = 519,
.rd_min = 3,
.rd_max = 120,
.s2div = icst525_s2div,
.idx2s = icst525_idx2s,
};
static const struct clk_icst_desc impd1_icst1_desc = {
.params = &impd1_vco_params,
.vco_offset = IMPD1_OSC1,
.lock_offset = IMPD1_LOCK,
};
/**
* integrator_impd1_clk_init() - set up the integrator clock tree
* @base: base address of the logic module (LM)
* @id: the ID of this LM
*/
void integrator_impd1_clk_init(void __iomem *base, unsigned int id)
{
struct impd1_clk *imc;
struct clk *clk;
int i;
if (id > 3) {
pr_crit("no more than 4 LMs can be attached\n");
return;
}
imc = &impd1_clks[id];
clk = icst_clk_register(NULL, &impd1_icst1_desc, base);
imc->vcoclk = clk;
imc->clks[0] = clkdev_alloc(clk, NULL, "lm%x:01000", id);
/* UART reference clock */
clk = clk_register_fixed_rate(NULL, "uartclk", NULL, CLK_IS_ROOT,
14745600);
imc->uartclk = clk;
imc->clks[1] = clkdev_alloc(clk, NULL, "lm%x:00100", id);
imc->clks[2] = clkdev_alloc(clk, NULL, "lm%x:00200", id);
for (i = 0; i < ARRAY_SIZE(imc->clks); i++)
clkdev_add(imc->clks[i]);
}
void integrator_impd1_clk_exit(unsigned int id)
{
int i;
struct impd1_clk *imc;
if (id > 3)
return;
imc = &impd1_clks[id];
for (i = 0; i < ARRAY_SIZE(imc->clks); i++)
clkdev_drop(imc->clks[i]);
clk_unregister(imc->uartclk);
clk_unregister(imc->vcoclk);
}
/*
* Clock driver for the ARM Integrator/AP and Integrator/CP boards
* Copyright (C) 2012 Linus Walleij
*
* 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.
*/
#include <linux/clk-provider.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/clkdev.h> #include <linux/clkdev.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/io.h> #include <linux/platform_data/clk-integrator.h>
#include <linux/clk-provider.h>
#include <mach/hardware.h> #include <mach/hardware.h>
#include <mach/platform.h> #include <mach/platform.h>
...@@ -14,42 +22,6 @@ ...@@ -14,42 +22,6 @@
* Inspired by portions of: * Inspired by portions of:
* plat-versatile/clock.c and plat-versatile/include/plat/clock.h * plat-versatile/clock.c and plat-versatile/include/plat/clock.h
*/ */
#define CM_LOCK (__io_address(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_LOCK_OFFSET)
#define CM_AUXOSC (__io_address(INTEGRATOR_HDR_BASE)+0x1c)
/**
* cp_auxvco_get() - get ICST VCO settings for the Integrator/CP
* @vco: ICST VCO parameters to update with hardware status
*/
static struct icst_vco cp_auxvco_get(void)
{
u32 val;
struct icst_vco vco;
val = readl(CM_AUXOSC);
vco.v = val & 0x1ff;
vco.r = (val >> 9) & 0x7f;
vco.s = (val >> 16) & 03;
return vco;
}
/**
* cp_auxvco_set() - commit changes to Integrator/CP ICST VCO
* @vco: ICST VCO parameters to commit
*/
static void cp_auxvco_set(struct icst_vco vco)
{
u32 val;
val = readl(CM_AUXOSC) & ~0x7ffff;
val |= vco.v | (vco.r << 9) | (vco.s << 16);
/* This magic unlocks the CM VCO so it can be controlled */
writel(0xa05f, CM_LOCK);
writel(val, CM_AUXOSC);
/* This locks the CM again */
writel(0, CM_LOCK);
}
static const struct icst_params cp_auxvco_params = { static const struct icst_params cp_auxvco_params = {
.ref = 24000000, .ref = 24000000,
...@@ -65,8 +37,8 @@ static const struct icst_params cp_auxvco_params = { ...@@ -65,8 +37,8 @@ static const struct icst_params cp_auxvco_params = {
static const struct clk_icst_desc __initdata cp_icst_desc = { static const struct clk_icst_desc __initdata cp_icst_desc = {
.params = &cp_auxvco_params, .params = &cp_auxvco_params,
.getvco = cp_auxvco_get, .vco_offset = 0x1c,
.setvco = cp_auxvco_set, .lock_offset = INTEGRATOR_HDR_LOCK_OFFSET,
}; };
/* /*
...@@ -106,6 +78,7 @@ void __init integrator_clk_init(bool is_cp) ...@@ -106,6 +78,7 @@ void __init integrator_clk_init(bool is_cp)
clk_register_clkdev(clk, NULL, "sp804"); clk_register_clkdev(clk, NULL, "sp804");
/* ICST VCO clock used on the Integrator/CP CLCD */ /* ICST VCO clock used on the Integrator/CP CLCD */
clk = icst_clk_register(NULL, &cp_icst_desc); clk = icst_clk_register(NULL, &cp_icst_desc,
__io_address(INTEGRATOR_HDR_BASE));
clk_register_clkdev(clk, NULL, "clcd"); clk_register_clkdev(clk, NULL, "clcd");
} }
/*
* Clock driver for the ARM RealView boards
* Copyright (C) 2012 Linus Walleij
*
* 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.
*/
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/clkdev.h> #include <linux/clkdev.h>
#include <linux/err.h> #include <linux/err.h>
...@@ -13,38 +21,6 @@ ...@@ -13,38 +21,6 @@
* Implementation of the ARM RealView clock trees. * Implementation of the ARM RealView clock trees.
*/ */
static void __iomem *sys_lock;
static void __iomem *sys_vcoreg;
/**
* realview_oscvco_get() - get ICST OSC settings for the RealView
*/
static struct icst_vco realview_oscvco_get(void)
{
u32 val;
struct icst_vco vco;
val = readl(sys_vcoreg);
vco.v = val & 0x1ff;
vco.r = (val >> 9) & 0x7f;
vco.s = (val >> 16) & 03;
return vco;
}
static void realview_oscvco_set(struct icst_vco vco)
{
u32 val;
val = readl(sys_vcoreg) & ~0x7ffff;
val |= vco.v | (vco.r << 9) | (vco.s << 16);
/* This magic unlocks the CM VCO so it can be controlled */
writel(0xa05f, sys_lock);
writel(val, sys_vcoreg);
/* This locks the CM again */
writel(0, sys_lock);
}
static const struct icst_params realview_oscvco_params = { static const struct icst_params realview_oscvco_params = {
.ref = 24000000, .ref = 24000000,
.vco_max = ICST307_VCO_MAX, .vco_max = ICST307_VCO_MAX,
...@@ -57,10 +33,16 @@ static const struct icst_params realview_oscvco_params = { ...@@ -57,10 +33,16 @@ static const struct icst_params realview_oscvco_params = {
.idx2s = icst307_idx2s, .idx2s = icst307_idx2s,
}; };
static const struct clk_icst_desc __initdata realview_icst_desc = { static const struct clk_icst_desc __initdata realview_osc0_desc = {
.params = &realview_oscvco_params,
.vco_offset = REALVIEW_SYS_OSC0_OFFSET,
.lock_offset = REALVIEW_SYS_LOCK_OFFSET,
};
static const struct clk_icst_desc __initdata realview_osc4_desc = {
.params = &realview_oscvco_params, .params = &realview_oscvco_params,
.getvco = realview_oscvco_get, .vco_offset = REALVIEW_SYS_OSC4_OFFSET,
.setvco = realview_oscvco_set, .lock_offset = REALVIEW_SYS_LOCK_OFFSET,
}; };
/* /*
...@@ -70,13 +52,6 @@ void __init realview_clk_init(void __iomem *sysbase, bool is_pb1176) ...@@ -70,13 +52,6 @@ void __init realview_clk_init(void __iomem *sysbase, bool is_pb1176)
{ {
struct clk *clk; struct clk *clk;
sys_lock = sysbase + REALVIEW_SYS_LOCK_OFFSET;
if (is_pb1176)
sys_vcoreg = sysbase + REALVIEW_SYS_OSC0_OFFSET;
else
sys_vcoreg = sysbase + REALVIEW_SYS_OSC4_OFFSET;
/* APB clock dummy */ /* APB clock dummy */
clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0); clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0);
clk_register_clkdev(clk, "apb_pclk", NULL); clk_register_clkdev(clk, "apb_pclk", NULL);
...@@ -108,7 +83,11 @@ void __init realview_clk_init(void __iomem *sysbase, bool is_pb1176) ...@@ -108,7 +83,11 @@ void __init realview_clk_init(void __iomem *sysbase, bool is_pb1176)
clk_register_clkdev(clk, NULL, "sp804"); clk_register_clkdev(clk, NULL, "sp804");
/* ICST VCO clock */ /* ICST VCO clock */
clk = icst_clk_register(NULL, &realview_icst_desc); if (is_pb1176)
clk = icst_clk_register(NULL, &realview_osc0_desc, sysbase);
else
clk = icst_clk_register(NULL, &realview_osc4_desc, sysbase);
clk_register_clkdev(clk, NULL, "dev:clcd"); clk_register_clkdev(clk, NULL, "dev:clcd");
clk_register_clkdev(clk, NULL, "issp:clcd"); clk_register_clkdev(clk, NULL, "issp:clcd");
} }
/*
* 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
...@@ -8,43 +8,17 @@ ...@@ -8,43 +8,17 @@
* Author: Jonas Aaberg <jonas.aberg@stericsson.com> * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
* *
*/ */
#include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mfd/dbx500-prcmu.h> #include <linux/platform_device.h>
#include <linux/clk.h>
#include <mach/id.h> #include <mach/id.h>
static struct cpufreq_frequency_table freq_table[] = { static struct cpufreq_frequency_table *freq_table;
[0] = { static struct clk *armss_clk;
.index = 0,
.frequency = 200000,
},
[1] = {
.index = 1,
.frequency = 400000,
},
[2] = {
.index = 2,
.frequency = 800000,
},
[3] = {
/* Used for MAX_OPP, if available */
.index = 3,
.frequency = CPUFREQ_TABLE_END,
},
[4] = {
.index = 4,
.frequency = CPUFREQ_TABLE_END,
},
};
static enum arm_opp idx2opp[] = {
ARM_EXTCLK,
ARM_50_OPP,
ARM_100_OPP,
ARM_MAX_OPP
};
static struct freq_attr *db8500_cpufreq_attr[] = { static struct freq_attr *db8500_cpufreq_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs, &cpufreq_freq_attr_scaling_available_freqs,
...@@ -85,9 +59,9 @@ static int db8500_cpufreq_target(struct cpufreq_policy *policy, ...@@ -85,9 +59,9 @@ static int db8500_cpufreq_target(struct cpufreq_policy *policy,
for_each_cpu(freqs.cpu, policy->cpus) for_each_cpu(freqs.cpu, policy->cpus)
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
/* request the PRCM unit for opp change */ /* update armss clk frequency */
if (prcmu_set_arm_opp(idx2opp[idx])) { if (clk_set_rate(armss_clk, freq_table[idx].frequency * 1000)) {
pr_err("db8500-cpufreq: Failed to set OPP level\n"); pr_err("db8500-cpufreq: Failed to update armss clk\n");
return -EINVAL; return -EINVAL;
} }
...@@ -100,25 +74,36 @@ static int db8500_cpufreq_target(struct cpufreq_policy *policy, ...@@ -100,25 +74,36 @@ static int db8500_cpufreq_target(struct cpufreq_policy *policy,
static unsigned int db8500_cpufreq_getspeed(unsigned int cpu) static unsigned int db8500_cpufreq_getspeed(unsigned int cpu)
{ {
int i; int i = 0;
/* request the prcm to get the current ARM opp */ unsigned long freq = clk_get_rate(armss_clk) / 1000;
for (i = 0; prcmu_get_arm_opp() != idx2opp[i]; i++)
; while (freq_table[i].frequency != CPUFREQ_TABLE_END) {
if (freq <= freq_table[i].frequency)
return freq_table[i].frequency; return freq_table[i].frequency;
i++;
}
/* We could not find a corresponding frequency. */
pr_err("db8500-cpufreq: Failed to find cpufreq speed\n");
return 0;
} }
static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy) static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy)
{ {
int i, res; int i = 0;
int res;
BUILD_BUG_ON(ARRAY_SIZE(idx2opp) + 1 != ARRAY_SIZE(freq_table));
if (prcmu_has_arm_maxopp()) armss_clk = clk_get(NULL, "armss");
freq_table[3].frequency = 1000000; if (IS_ERR(armss_clk)) {
pr_err("db8500-cpufreq : Failed to get armss clk\n");
return PTR_ERR(armss_clk);
}
pr_info("db8500-cpufreq : Available frequencies:\n"); pr_info("db8500-cpufreq : Available frequencies:\n");
for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) while (freq_table[i].frequency != CPUFREQ_TABLE_END) {
pr_info(" %d Mhz\n", freq_table[i].frequency/1000); pr_info(" %d Mhz\n", freq_table[i].frequency/1000);
i++;
}
/* get policy fields based on the table */ /* get policy fields based on the table */
res = cpufreq_frequency_table_cpuinfo(policy, freq_table); res = cpufreq_frequency_table_cpuinfo(policy, freq_table);
...@@ -126,6 +111,7 @@ static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy) ...@@ -126,6 +111,7 @@ static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy)
cpufreq_frequency_table_get_attr(freq_table, policy->cpu); cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
else { else {
pr_err("db8500-cpufreq : Failed to read policy table\n"); pr_err("db8500-cpufreq : Failed to read policy table\n");
clk_put(armss_clk);
return res; return res;
} }
...@@ -159,12 +145,35 @@ static struct cpufreq_driver db8500_cpufreq_driver = { ...@@ -159,12 +145,35 @@ static struct cpufreq_driver db8500_cpufreq_driver = {
.attr = db8500_cpufreq_attr, .attr = db8500_cpufreq_attr,
}; };
static int db8500_cpufreq_probe(struct platform_device *pdev)
{
freq_table = dev_get_platdata(&pdev->dev);
if (!freq_table) {
pr_err("db8500-cpufreq: Failed to fetch cpufreq table\n");
return -ENODEV;
}
return cpufreq_register_driver(&db8500_cpufreq_driver);
}
static struct platform_driver db8500_cpufreq_plat_driver = {
.driver = {
.name = "cpufreq-u8500",
.owner = THIS_MODULE,
},
.probe = db8500_cpufreq_probe,
};
static int __init db8500_cpufreq_register(void) static int __init db8500_cpufreq_register(void)
{ {
if (!cpu_is_u8500_family()) if (!cpu_is_u8500_family())
return -ENODEV; return -ENODEV;
pr_info("cpufreq for DB8500 started\n"); pr_info("cpufreq for DB8500 started\n");
return cpufreq_register_driver(&db8500_cpufreq_driver); return platform_driver_register(&db8500_cpufreq_plat_driver);
} }
device_initcall(db8500_cpufreq_register); device_initcall(db8500_cpufreq_register);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("cpufreq driver for DB8500");
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/mfd/abx500/ab8500.h> #include <linux/mfd/abx500/ab8500.h>
#include <linux/regulator/db8500-prcmu.h> #include <linux/regulator/db8500-prcmu.h>
#include <linux/regulator/machine.h> #include <linux/regulator/machine.h>
#include <linux/cpufreq.h>
#include <asm/hardware/gic.h> #include <asm/hardware/gic.h>
#include <mach/hardware.h> #include <mach/hardware.h>
#include <mach/irqs.h> #include <mach/irqs.h>
...@@ -420,9 +421,6 @@ static struct { ...@@ -420,9 +421,6 @@ static struct {
static atomic_t ac_wake_req_state = ATOMIC_INIT(0); static atomic_t ac_wake_req_state = ATOMIC_INIT(0);
/* Functions definition */
static void compute_armss_rate(void);
/* Spinlocks */ /* Spinlocks */
static DEFINE_SPINLOCK(prcmu_lock); static DEFINE_SPINLOCK(prcmu_lock);
static DEFINE_SPINLOCK(clkout_lock); static DEFINE_SPINLOCK(clkout_lock);
...@@ -1019,7 +1017,6 @@ int db8500_prcmu_set_arm_opp(u8 opp) ...@@ -1019,7 +1017,6 @@ int db8500_prcmu_set_arm_opp(u8 opp)
(mb1_transfer.ack.arm_opp != opp)) (mb1_transfer.ack.arm_opp != opp))
r = -EIO; r = -EIO;
compute_armss_rate();
mutex_unlock(&mb1_transfer.lock); mutex_unlock(&mb1_transfer.lock);
return r; return r;
...@@ -1169,12 +1166,12 @@ int db8500_prcmu_get_ape_opp(void) ...@@ -1169,12 +1166,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. * @enable: true to request the higher voltage, false to drop a request.
* *
* Calls to this function to enable and disable requests must be balanced. * 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; int r = 0;
u8 header; u8 header;
...@@ -1669,13 +1666,8 @@ static unsigned long clock_rate(u8 clock) ...@@ -1669,13 +1666,8 @@ static unsigned long clock_rate(u8 clock)
else else
return 0; return 0;
} }
static unsigned long latest_armss_rate;
static unsigned long armss_rate(void)
{
return latest_armss_rate;
}
static void compute_armss_rate(void) static unsigned long armss_rate(void)
{ {
u32 r; u32 r;
unsigned long rate; unsigned long rate;
...@@ -1700,7 +1692,7 @@ static void compute_armss_rate(void) ...@@ -1700,7 +1692,7 @@ static void compute_armss_rate(void)
rate = pll_rate(PRCM_PLLARM_FREQ, ROOT_CLOCK_RATE, PLL_DIV); rate = pll_rate(PRCM_PLLARM_FREQ, ROOT_CLOCK_RATE, PLL_DIV);
} }
latest_armss_rate = rate; return rate;
} }
static unsigned long dsiclk_rate(u8 n) static unsigned long dsiclk_rate(u8 n)
...@@ -1820,6 +1812,35 @@ static long round_clock_rate(u8 clock, unsigned long rate) ...@@ -1820,6 +1812,35 @@ static long round_clock_rate(u8 clock, unsigned long rate)
return rounded_rate; return rounded_rate;
} }
/* CPU FREQ table, may be changed due to if MAX_OPP is supported. */
static struct cpufreq_frequency_table db8500_cpufreq_table[] = {
{ .frequency = 200000, .index = ARM_EXTCLK,},
{ .frequency = 400000, .index = ARM_50_OPP,},
{ .frequency = 800000, .index = ARM_100_OPP,},
{ .frequency = CPUFREQ_TABLE_END,}, /* To be used for MAX_OPP. */
{ .frequency = CPUFREQ_TABLE_END,},
};
static long round_armss_rate(unsigned long rate)
{
long freq = 0;
int i = 0;
/* cpufreq table frequencies is in KHz. */
rate = rate / 1000;
/* Find the corresponding arm opp from the cpufreq table. */
while (db8500_cpufreq_table[i].frequency != CPUFREQ_TABLE_END) {
freq = db8500_cpufreq_table[i].frequency;
if (freq == rate)
break;
i++;
}
/* Return the last valid value, even if a match was not found. */
return freq * 1000;
}
#define MIN_PLL_VCO_RATE 600000000ULL #define MIN_PLL_VCO_RATE 600000000ULL
#define MAX_PLL_VCO_RATE 1680640000ULL #define MAX_PLL_VCO_RATE 1680640000ULL
...@@ -1891,6 +1912,8 @@ long prcmu_round_clock_rate(u8 clock, unsigned long rate) ...@@ -1891,6 +1912,8 @@ long prcmu_round_clock_rate(u8 clock, unsigned long rate)
{ {
if (clock < PRCMU_NUM_REG_CLOCKS) if (clock < PRCMU_NUM_REG_CLOCKS)
return round_clock_rate(clock, rate); return round_clock_rate(clock, rate);
else if (clock == PRCMU_ARMSS)
return round_armss_rate(rate);
else if (clock == PRCMU_PLLDSI) else if (clock == PRCMU_PLLDSI)
return round_plldsi_rate(rate); return round_plldsi_rate(rate);
else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK)) else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
...@@ -1950,6 +1973,27 @@ static void set_clock_rate(u8 clock, unsigned long rate) ...@@ -1950,6 +1973,27 @@ static void set_clock_rate(u8 clock, unsigned long rate)
spin_unlock_irqrestore(&clk_mgt_lock, flags); spin_unlock_irqrestore(&clk_mgt_lock, flags);
} }
static int set_armss_rate(unsigned long rate)
{
int i = 0;
/* cpufreq table frequencies is in KHz. */
rate = rate / 1000;
/* Find the corresponding arm opp from the cpufreq table. */
while (db8500_cpufreq_table[i].frequency != CPUFREQ_TABLE_END) {
if (db8500_cpufreq_table[i].frequency == rate)
break;
i++;
}
if (db8500_cpufreq_table[i].frequency != rate)
return -EINVAL;
/* Set the new arm opp. */
return db8500_prcmu_set_arm_opp(db8500_cpufreq_table[i].index);
}
static int set_plldsi_rate(unsigned long rate) static int set_plldsi_rate(unsigned long rate)
{ {
unsigned long src_rate; unsigned long src_rate;
...@@ -2030,6 +2074,8 @@ int prcmu_set_clock_rate(u8 clock, unsigned long rate) ...@@ -2030,6 +2074,8 @@ int prcmu_set_clock_rate(u8 clock, unsigned long rate)
{ {
if (clock < PRCMU_NUM_REG_CLOCKS) if (clock < PRCMU_NUM_REG_CLOCKS)
set_clock_rate(clock, rate); set_clock_rate(clock, rate);
else if (clock == PRCMU_ARMSS)
return set_armss_rate(rate);
else if (clock == PRCMU_PLLDSI) else if (clock == PRCMU_PLLDSI)
return set_plldsi_rate(rate); return set_plldsi_rate(rate);
else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK)) else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
...@@ -2754,8 +2800,6 @@ void __init db8500_prcmu_early_init(void) ...@@ -2754,8 +2800,6 @@ void __init db8500_prcmu_early_init(void)
init_completion(&mb5_transfer.work); init_completion(&mb5_transfer.work);
INIT_WORK(&mb0_transfer.mask_work, prcmu_mask_work); INIT_WORK(&mb0_transfer.mask_work, prcmu_mask_work);
compute_armss_rate();
} }
static void __init init_prcm_registers(void) static void __init init_prcm_registers(void)
...@@ -3020,6 +3064,8 @@ static struct mfd_cell db8500_prcmu_devs[] = { ...@@ -3020,6 +3064,8 @@ static struct mfd_cell db8500_prcmu_devs[] = {
{ {
.name = "cpufreq-u8500", .name = "cpufreq-u8500",
.of_compatible = "stericsson,cpufreq-u8500", .of_compatible = "stericsson,cpufreq-u8500",
.platform_data = &db8500_cpufreq_table,
.pdata_size = sizeof(db8500_cpufreq_table),
}, },
{ {
.name = "ab8500-core", .name = "ab8500-core",
...@@ -3030,6 +3076,14 @@ static struct mfd_cell db8500_prcmu_devs[] = { ...@@ -3030,6 +3076,14 @@ static struct mfd_cell db8500_prcmu_devs[] = {
}, },
}; };
static void db8500_prcmu_update_cpufreq(void)
{
if (prcmu_has_arm_maxopp()) {
db8500_cpufreq_table[3].frequency = 1000000;
db8500_cpufreq_table[3].index = ARM_MAX_OPP;
}
}
/** /**
* prcmu_fw_init - arch init call for the Linux PRCMU fw init logic * prcmu_fw_init - arch init call for the Linux PRCMU fw init logic
* *
...@@ -3074,6 +3128,8 @@ static int __devinit db8500_prcmu_probe(struct platform_device *pdev) ...@@ -3074,6 +3128,8 @@ static int __devinit db8500_prcmu_probe(struct platform_device *pdev)
if (cpu_is_u8500v20_or_later()) if (cpu_is_u8500v20_or_later())
prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET); prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET);
db8500_prcmu_update_cpufreq();
err = mfd_add_devices(&pdev->dev, 0, db8500_prcmu_devs, err = mfd_add_devices(&pdev->dev, 0, db8500_prcmu_devs,
ARRAY_SIZE(db8500_prcmu_devs), NULL, 0, NULL); ARRAY_SIZE(db8500_prcmu_devs), NULL, 0, NULL);
if (err) { if (err) {
......
...@@ -53,9 +53,18 @@ struct clk_hw; ...@@ -53,9 +53,18 @@ struct clk_hw;
* @disable: Disable the clock atomically. Called with enable_lock held. * @disable: Disable the clock atomically. Called with enable_lock held.
* This function must not sleep. * 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.
*
* @disable_unused: Disable the clock atomically. Only called from
* clk_disable_unused for gate clocks with special needs.
* Called with enable_lock held. This function must not
* sleep.
*
* @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 * 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 * Returns the calculated rate. Optional, but recommended - if
* this op is not set then clock rate will be initialized to 0. * this op is not set then clock rate will be initialized to 0.
* *
...@@ -89,7 +98,7 @@ struct clk_hw; ...@@ -89,7 +98,7 @@ struct clk_hw;
* implementations to split any work between atomic (enable) and sleepable * implementations to split any work between atomic (enable) and sleepable
* (prepare) contexts. If enabling a clock requires code that might sleep, * (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 * 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 * 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 * (eg. when a device is opened), and clk_enable when the clock is actually
...@@ -102,6 +111,7 @@ struct clk_ops { ...@@ -102,6 +111,7 @@ struct clk_ops {
int (*enable)(struct clk_hw *hw); int (*enable)(struct clk_hw *hw);
void (*disable)(struct clk_hw *hw); void (*disable)(struct clk_hw *hw);
int (*is_enabled)(struct clk_hw *hw); int (*is_enabled)(struct clk_hw *hw);
void (*disable_unused)(struct clk_hw *hw);
unsigned long (*recalc_rate)(struct clk_hw *hw, unsigned long (*recalc_rate)(struct clk_hw *hw,
unsigned long parent_rate); unsigned long parent_rate);
long (*round_rate)(struct clk_hw *hw, unsigned long, long (*round_rate)(struct clk_hw *hw, unsigned long,
...@@ -327,19 +337,21 @@ struct clk *clk_register_fixed_factor(struct device *dev, const char *name, ...@@ -327,19 +337,21 @@ struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
* error code; drivers must test for an error code after calling clk_register. * error code; drivers must test for an error code after calling clk_register.
*/ */
struct clk *clk_register(struct device *dev, struct clk_hw *hw); struct clk *clk_register(struct device *dev, struct clk_hw *hw);
struct clk *devm_clk_register(struct device *dev, struct clk_hw *hw);
void clk_unregister(struct clk *clk); void clk_unregister(struct clk *clk);
void devm_clk_unregister(struct device *dev, struct clk *clk);
/* helper functions */ /* helper functions */
const char *__clk_get_name(struct clk *clk); const char *__clk_get_name(struct clk *clk);
struct clk_hw *__clk_get_hw(struct clk *clk); struct clk_hw *__clk_get_hw(struct clk *clk);
u8 __clk_get_num_parents(struct clk *clk); u8 __clk_get_num_parents(struct clk *clk);
struct clk *__clk_get_parent(struct clk *clk); struct clk *__clk_get_parent(struct clk *clk);
int __clk_get_enable_count(struct clk *clk); unsigned int __clk_get_enable_count(struct clk *clk);
int __clk_get_prepare_count(struct clk *clk); unsigned int __clk_get_prepare_count(struct clk *clk);
unsigned long __clk_get_rate(struct clk *clk); unsigned long __clk_get_rate(struct clk *clk);
unsigned long __clk_get_flags(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); struct clk *__clk_lookup(const char *name);
/* /*
......
...@@ -515,7 +515,6 @@ enum romcode_read prcmu_get_rc_p2a(void); ...@@ -515,7 +515,6 @@ enum romcode_read prcmu_get_rc_p2a(void);
enum ap_pwrst prcmu_get_xp70_current_state(void); enum ap_pwrst prcmu_get_xp70_current_state(void);
bool prcmu_has_arm_maxopp(void); bool prcmu_has_arm_maxopp(void);
struct prcmu_fw_version *prcmu_get_fw_version(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); int prcmu_release_usb_wakeup_state(void);
void prcmu_configure_auto_pm(struct prcmu_auto_pm_config *sleep, void prcmu_configure_auto_pm(struct prcmu_auto_pm_config *sleep,
struct prcmu_auto_pm_config *idle); struct prcmu_auto_pm_config *idle);
...@@ -564,6 +563,7 @@ int db8500_prcmu_set_arm_opp(u8 opp); ...@@ -564,6 +563,7 @@ int db8500_prcmu_set_arm_opp(u8 opp);
int db8500_prcmu_get_arm_opp(void); int db8500_prcmu_get_arm_opp(void);
int db8500_prcmu_set_ape_opp(u8 opp); int db8500_prcmu_set_ape_opp(u8 opp);
int db8500_prcmu_get_ape_opp(void); 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_set_ddr_opp(u8 opp);
int db8500_prcmu_get_ddr_opp(void); int db8500_prcmu_get_ddr_opp(void);
...@@ -610,7 +610,7 @@ static inline int db8500_prcmu_get_ape_opp(void) ...@@ -610,7 +610,7 @@ static inline int db8500_prcmu_get_ape_opp(void)
return APE_100_OPP; 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; return 0;
} }
......
...@@ -336,6 +336,11 @@ static inline int prcmu_get_ape_opp(void) ...@@ -336,6 +336,11 @@ static inline int prcmu_get_ape_opp(void)
return db8500_prcmu_get_ape_opp(); 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) static inline void prcmu_system_reset(u16 reset_code)
{ {
return db8500_prcmu_system_reset(reset_code); return db8500_prcmu_system_reset(reset_code);
...@@ -507,6 +512,11 @@ static inline int prcmu_get_ape_opp(void) ...@@ -507,6 +512,11 @@ static inline int prcmu_get_ape_opp(void)
return APE_100_OPP; 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) static inline int prcmu_set_arm_opp(u8 opp)
{ {
return 0; return 0;
......
void integrator_clk_init(bool is_cp); void integrator_clk_init(bool is_cp);
void integrator_impd1_clk_init(void __iomem *base, unsigned int id);
void integrator_impd1_clk_exit(unsigned int id);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment