1*3b01f87bSUlf Hansson /* 2*3b01f87bSUlf Hansson * PRCC clock implementation for ux500 platform. 3*3b01f87bSUlf Hansson * 4*3b01f87bSUlf Hansson * Copyright (C) 2012 ST-Ericsson SA 5*3b01f87bSUlf Hansson * Author: Ulf Hansson <ulf.hansson@linaro.org> 6*3b01f87bSUlf Hansson * 7*3b01f87bSUlf Hansson * License terms: GNU General Public License (GPL) version 2 8*3b01f87bSUlf Hansson */ 9*3b01f87bSUlf Hansson 10*3b01f87bSUlf Hansson #include <linux/clk-provider.h> 11*3b01f87bSUlf Hansson #include <linux/clk-private.h> 12*3b01f87bSUlf Hansson #include <linux/slab.h> 13*3b01f87bSUlf Hansson #include <linux/io.h> 14*3b01f87bSUlf Hansson #include <linux/err.h> 15*3b01f87bSUlf Hansson #include <linux/types.h> 16*3b01f87bSUlf Hansson #include <mach/hardware.h> 17*3b01f87bSUlf Hansson 18*3b01f87bSUlf Hansson #include "clk.h" 19*3b01f87bSUlf Hansson 20*3b01f87bSUlf Hansson #define PRCC_PCKEN 0x000 21*3b01f87bSUlf Hansson #define PRCC_PCKDIS 0x004 22*3b01f87bSUlf Hansson #define PRCC_KCKEN 0x008 23*3b01f87bSUlf Hansson #define PRCC_KCKDIS 0x00C 24*3b01f87bSUlf Hansson #define PRCC_PCKSR 0x010 25*3b01f87bSUlf Hansson #define PRCC_KCKSR 0x014 26*3b01f87bSUlf Hansson 27*3b01f87bSUlf Hansson #define to_clk_prcc(_hw) container_of(_hw, struct clk_prcc, hw) 28*3b01f87bSUlf Hansson 29*3b01f87bSUlf Hansson struct clk_prcc { 30*3b01f87bSUlf Hansson struct clk_hw hw; 31*3b01f87bSUlf Hansson void __iomem *base; 32*3b01f87bSUlf Hansson u32 cg_sel; 33*3b01f87bSUlf Hansson int is_enabled; 34*3b01f87bSUlf Hansson }; 35*3b01f87bSUlf Hansson 36*3b01f87bSUlf Hansson /* PRCC clock operations. */ 37*3b01f87bSUlf Hansson 38*3b01f87bSUlf Hansson static int clk_prcc_pclk_enable(struct clk_hw *hw) 39*3b01f87bSUlf Hansson { 40*3b01f87bSUlf Hansson struct clk_prcc *clk = to_clk_prcc(hw); 41*3b01f87bSUlf Hansson 42*3b01f87bSUlf Hansson writel(clk->cg_sel, (clk->base + PRCC_PCKEN)); 43*3b01f87bSUlf Hansson while (!(readl(clk->base + PRCC_PCKSR) & clk->cg_sel)) 44*3b01f87bSUlf Hansson cpu_relax(); 45*3b01f87bSUlf Hansson 46*3b01f87bSUlf Hansson clk->is_enabled = 1; 47*3b01f87bSUlf Hansson return 0; 48*3b01f87bSUlf Hansson } 49*3b01f87bSUlf Hansson 50*3b01f87bSUlf Hansson static void clk_prcc_pclk_disable(struct clk_hw *hw) 51*3b01f87bSUlf Hansson { 52*3b01f87bSUlf Hansson struct clk_prcc *clk = to_clk_prcc(hw); 53*3b01f87bSUlf Hansson 54*3b01f87bSUlf Hansson writel(clk->cg_sel, (clk->base + PRCC_PCKDIS)); 55*3b01f87bSUlf Hansson clk->is_enabled = 0; 56*3b01f87bSUlf Hansson } 57*3b01f87bSUlf Hansson 58*3b01f87bSUlf Hansson static int clk_prcc_kclk_enable(struct clk_hw *hw) 59*3b01f87bSUlf Hansson { 60*3b01f87bSUlf Hansson struct clk_prcc *clk = to_clk_prcc(hw); 61*3b01f87bSUlf Hansson 62*3b01f87bSUlf Hansson writel(clk->cg_sel, (clk->base + PRCC_KCKEN)); 63*3b01f87bSUlf Hansson while (!(readl(clk->base + PRCC_KCKSR) & clk->cg_sel)) 64*3b01f87bSUlf Hansson cpu_relax(); 65*3b01f87bSUlf Hansson 66*3b01f87bSUlf Hansson clk->is_enabled = 1; 67*3b01f87bSUlf Hansson return 0; 68*3b01f87bSUlf Hansson } 69*3b01f87bSUlf Hansson 70*3b01f87bSUlf Hansson static void clk_prcc_kclk_disable(struct clk_hw *hw) 71*3b01f87bSUlf Hansson { 72*3b01f87bSUlf Hansson struct clk_prcc *clk = to_clk_prcc(hw); 73*3b01f87bSUlf Hansson 74*3b01f87bSUlf Hansson writel(clk->cg_sel, (clk->base + PRCC_KCKDIS)); 75*3b01f87bSUlf Hansson clk->is_enabled = 0; 76*3b01f87bSUlf Hansson } 77*3b01f87bSUlf Hansson 78*3b01f87bSUlf Hansson static int clk_prcc_is_enabled(struct clk_hw *hw) 79*3b01f87bSUlf Hansson { 80*3b01f87bSUlf Hansson struct clk_prcc *clk = to_clk_prcc(hw); 81*3b01f87bSUlf Hansson return clk->is_enabled; 82*3b01f87bSUlf Hansson } 83*3b01f87bSUlf Hansson 84*3b01f87bSUlf Hansson static struct clk_ops clk_prcc_pclk_ops = { 85*3b01f87bSUlf Hansson .enable = clk_prcc_pclk_enable, 86*3b01f87bSUlf Hansson .disable = clk_prcc_pclk_disable, 87*3b01f87bSUlf Hansson .is_enabled = clk_prcc_is_enabled, 88*3b01f87bSUlf Hansson }; 89*3b01f87bSUlf Hansson 90*3b01f87bSUlf Hansson static struct clk_ops clk_prcc_kclk_ops = { 91*3b01f87bSUlf Hansson .enable = clk_prcc_kclk_enable, 92*3b01f87bSUlf Hansson .disable = clk_prcc_kclk_disable, 93*3b01f87bSUlf Hansson .is_enabled = clk_prcc_is_enabled, 94*3b01f87bSUlf Hansson }; 95*3b01f87bSUlf Hansson 96*3b01f87bSUlf Hansson static struct clk *clk_reg_prcc(const char *name, 97*3b01f87bSUlf Hansson const char *parent_name, 98*3b01f87bSUlf Hansson resource_size_t phy_base, 99*3b01f87bSUlf Hansson u32 cg_sel, 100*3b01f87bSUlf Hansson unsigned long flags, 101*3b01f87bSUlf Hansson struct clk_ops *clk_prcc_ops) 102*3b01f87bSUlf Hansson { 103*3b01f87bSUlf Hansson struct clk_prcc *clk; 104*3b01f87bSUlf Hansson struct clk_init_data clk_prcc_init; 105*3b01f87bSUlf Hansson struct clk *clk_reg; 106*3b01f87bSUlf Hansson 107*3b01f87bSUlf Hansson if (!name) { 108*3b01f87bSUlf Hansson pr_err("clk_prcc: %s invalid arguments passed\n", __func__); 109*3b01f87bSUlf Hansson return ERR_PTR(-EINVAL); 110*3b01f87bSUlf Hansson } 111*3b01f87bSUlf Hansson 112*3b01f87bSUlf Hansson clk = kzalloc(sizeof(struct clk_prcc), GFP_KERNEL); 113*3b01f87bSUlf Hansson if (!clk) { 114*3b01f87bSUlf Hansson pr_err("clk_prcc: %s could not allocate clk\n", __func__); 115*3b01f87bSUlf Hansson return ERR_PTR(-ENOMEM); 116*3b01f87bSUlf Hansson } 117*3b01f87bSUlf Hansson 118*3b01f87bSUlf Hansson clk->base = ioremap(phy_base, SZ_4K); 119*3b01f87bSUlf Hansson if (!clk->base) 120*3b01f87bSUlf Hansson goto free_clk; 121*3b01f87bSUlf Hansson 122*3b01f87bSUlf Hansson clk->cg_sel = cg_sel; 123*3b01f87bSUlf Hansson clk->is_enabled = 1; 124*3b01f87bSUlf Hansson 125*3b01f87bSUlf Hansson clk_prcc_init.name = name; 126*3b01f87bSUlf Hansson clk_prcc_init.ops = clk_prcc_ops; 127*3b01f87bSUlf Hansson clk_prcc_init.flags = flags; 128*3b01f87bSUlf Hansson clk_prcc_init.parent_names = (parent_name ? &parent_name : NULL); 129*3b01f87bSUlf Hansson clk_prcc_init.num_parents = (parent_name ? 1 : 0); 130*3b01f87bSUlf Hansson clk->hw.init = &clk_prcc_init; 131*3b01f87bSUlf Hansson 132*3b01f87bSUlf Hansson clk_reg = clk_register(NULL, &clk->hw); 133*3b01f87bSUlf Hansson if (IS_ERR_OR_NULL(clk_reg)) 134*3b01f87bSUlf Hansson goto unmap_clk; 135*3b01f87bSUlf Hansson 136*3b01f87bSUlf Hansson return clk_reg; 137*3b01f87bSUlf Hansson 138*3b01f87bSUlf Hansson unmap_clk: 139*3b01f87bSUlf Hansson iounmap(clk->base); 140*3b01f87bSUlf Hansson free_clk: 141*3b01f87bSUlf Hansson kfree(clk); 142*3b01f87bSUlf Hansson pr_err("clk_prcc: %s failed to register clk\n", __func__); 143*3b01f87bSUlf Hansson return ERR_PTR(-ENOMEM); 144*3b01f87bSUlf Hansson } 145*3b01f87bSUlf Hansson 146*3b01f87bSUlf Hansson struct clk *clk_reg_prcc_pclk(const char *name, 147*3b01f87bSUlf Hansson const char *parent_name, 148*3b01f87bSUlf Hansson resource_size_t phy_base, 149*3b01f87bSUlf Hansson u32 cg_sel, 150*3b01f87bSUlf Hansson unsigned long flags) 151*3b01f87bSUlf Hansson { 152*3b01f87bSUlf Hansson return clk_reg_prcc(name, parent_name, phy_base, cg_sel, flags, 153*3b01f87bSUlf Hansson &clk_prcc_pclk_ops); 154*3b01f87bSUlf Hansson } 155*3b01f87bSUlf Hansson 156*3b01f87bSUlf Hansson struct clk *clk_reg_prcc_kclk(const char *name, 157*3b01f87bSUlf Hansson const char *parent_name, 158*3b01f87bSUlf Hansson resource_size_t phy_base, 159*3b01f87bSUlf Hansson u32 cg_sel, 160*3b01f87bSUlf Hansson unsigned long flags) 161*3b01f87bSUlf Hansson { 162*3b01f87bSUlf Hansson return clk_reg_prcc(name, parent_name, phy_base, cg_sel, flags, 163*3b01f87bSUlf Hansson &clk_prcc_kclk_ops); 164*3b01f87bSUlf Hansson } 165