-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
clk: ux500: Adapt PRCMU and PRCC clocks for common clk
First version of common clock implementation of PRCMU clocks and PRCC clocks for ux500 platforms. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Acked-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Mike Turquette <mturquette@linaro.org>
- Loading branch information
Ulf Hansson
authored and
Mike Turquette
committed
Sep 6, 2012
1 parent
672575e
commit 3b01f87
Showing
4 changed files
with
452 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# | ||
# Makefile for ux500 clocks | ||
# | ||
|
||
# Clock types | ||
obj-y += clk-prcc.o | ||
obj-y += clk-prcmu.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
/* | ||
* PRCC 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/clk-provider.h> | ||
#include <linux/clk-private.h> | ||
#include <linux/slab.h> | ||
#include <linux/io.h> | ||
#include <linux/err.h> | ||
#include <linux/types.h> | ||
#include <mach/hardware.h> | ||
|
||
#include "clk.h" | ||
|
||
#define PRCC_PCKEN 0x000 | ||
#define PRCC_PCKDIS 0x004 | ||
#define PRCC_KCKEN 0x008 | ||
#define PRCC_KCKDIS 0x00C | ||
#define PRCC_PCKSR 0x010 | ||
#define PRCC_KCKSR 0x014 | ||
|
||
#define to_clk_prcc(_hw) container_of(_hw, struct clk_prcc, hw) | ||
|
||
struct clk_prcc { | ||
struct clk_hw hw; | ||
void __iomem *base; | ||
u32 cg_sel; | ||
int is_enabled; | ||
}; | ||
|
||
/* PRCC clock operations. */ | ||
|
||
static int clk_prcc_pclk_enable(struct clk_hw *hw) | ||
{ | ||
struct clk_prcc *clk = to_clk_prcc(hw); | ||
|
||
writel(clk->cg_sel, (clk->base + PRCC_PCKEN)); | ||
while (!(readl(clk->base + PRCC_PCKSR) & clk->cg_sel)) | ||
cpu_relax(); | ||
|
||
clk->is_enabled = 1; | ||
return 0; | ||
} | ||
|
||
static void clk_prcc_pclk_disable(struct clk_hw *hw) | ||
{ | ||
struct clk_prcc *clk = to_clk_prcc(hw); | ||
|
||
writel(clk->cg_sel, (clk->base + PRCC_PCKDIS)); | ||
clk->is_enabled = 0; | ||
} | ||
|
||
static int clk_prcc_kclk_enable(struct clk_hw *hw) | ||
{ | ||
struct clk_prcc *clk = to_clk_prcc(hw); | ||
|
||
writel(clk->cg_sel, (clk->base + PRCC_KCKEN)); | ||
while (!(readl(clk->base + PRCC_KCKSR) & clk->cg_sel)) | ||
cpu_relax(); | ||
|
||
clk->is_enabled = 1; | ||
return 0; | ||
} | ||
|
||
static void clk_prcc_kclk_disable(struct clk_hw *hw) | ||
{ | ||
struct clk_prcc *clk = to_clk_prcc(hw); | ||
|
||
writel(clk->cg_sel, (clk->base + PRCC_KCKDIS)); | ||
clk->is_enabled = 0; | ||
} | ||
|
||
static int clk_prcc_is_enabled(struct clk_hw *hw) | ||
{ | ||
struct clk_prcc *clk = to_clk_prcc(hw); | ||
return clk->is_enabled; | ||
} | ||
|
||
static struct clk_ops clk_prcc_pclk_ops = { | ||
.enable = clk_prcc_pclk_enable, | ||
.disable = clk_prcc_pclk_disable, | ||
.is_enabled = clk_prcc_is_enabled, | ||
}; | ||
|
||
static struct clk_ops clk_prcc_kclk_ops = { | ||
.enable = clk_prcc_kclk_enable, | ||
.disable = clk_prcc_kclk_disable, | ||
.is_enabled = clk_prcc_is_enabled, | ||
}; | ||
|
||
static struct clk *clk_reg_prcc(const char *name, | ||
const char *parent_name, | ||
resource_size_t phy_base, | ||
u32 cg_sel, | ||
unsigned long flags, | ||
struct clk_ops *clk_prcc_ops) | ||
{ | ||
struct clk_prcc *clk; | ||
struct clk_init_data clk_prcc_init; | ||
struct clk *clk_reg; | ||
|
||
if (!name) { | ||
pr_err("clk_prcc: %s invalid arguments passed\n", __func__); | ||
return ERR_PTR(-EINVAL); | ||
} | ||
|
||
clk = kzalloc(sizeof(struct clk_prcc), GFP_KERNEL); | ||
if (!clk) { | ||
pr_err("clk_prcc: %s could not allocate clk\n", __func__); | ||
return ERR_PTR(-ENOMEM); | ||
} | ||
|
||
clk->base = ioremap(phy_base, SZ_4K); | ||
if (!clk->base) | ||
goto free_clk; | ||
|
||
clk->cg_sel = cg_sel; | ||
clk->is_enabled = 1; | ||
|
||
clk_prcc_init.name = name; | ||
clk_prcc_init.ops = clk_prcc_ops; | ||
clk_prcc_init.flags = flags; | ||
clk_prcc_init.parent_names = (parent_name ? &parent_name : NULL); | ||
clk_prcc_init.num_parents = (parent_name ? 1 : 0); | ||
clk->hw.init = &clk_prcc_init; | ||
|
||
clk_reg = clk_register(NULL, &clk->hw); | ||
if (IS_ERR_OR_NULL(clk_reg)) | ||
goto unmap_clk; | ||
|
||
return clk_reg; | ||
|
||
unmap_clk: | ||
iounmap(clk->base); | ||
free_clk: | ||
kfree(clk); | ||
pr_err("clk_prcc: %s failed to register clk\n", __func__); | ||
return ERR_PTR(-ENOMEM); | ||
} | ||
|
||
struct clk *clk_reg_prcc_pclk(const char *name, | ||
const char *parent_name, | ||
resource_size_t phy_base, | ||
u32 cg_sel, | ||
unsigned long flags) | ||
{ | ||
return clk_reg_prcc(name, parent_name, phy_base, cg_sel, flags, | ||
&clk_prcc_pclk_ops); | ||
} | ||
|
||
struct clk *clk_reg_prcc_kclk(const char *name, | ||
const char *parent_name, | ||
resource_size_t phy_base, | ||
u32 cg_sel, | ||
unsigned long flags) | ||
{ | ||
return clk_reg_prcc(name, parent_name, phy_base, cg_sel, flags, | ||
&clk_prcc_kclk_ops); | ||
} |
Oops, something went wrong.