13b01f87bSUlf Hansson /* 23b01f87bSUlf Hansson * PRCC clock implementation for ux500 platform. 33b01f87bSUlf Hansson * 43b01f87bSUlf Hansson * Copyright (C) 2012 ST-Ericsson SA 53b01f87bSUlf Hansson * Author: Ulf Hansson <ulf.hansson@linaro.org> 63b01f87bSUlf Hansson * 73b01f87bSUlf Hansson * License terms: GNU General Public License (GPL) version 2 83b01f87bSUlf Hansson */ 93b01f87bSUlf Hansson 103b01f87bSUlf Hansson #include <linux/clk-provider.h> 113b01f87bSUlf Hansson #include <linux/slab.h> 123b01f87bSUlf Hansson #include <linux/io.h> 133b01f87bSUlf Hansson #include <linux/err.h> 143b01f87bSUlf Hansson #include <linux/types.h> 153b01f87bSUlf Hansson 163b01f87bSUlf Hansson #include "clk.h" 173b01f87bSUlf Hansson 183b01f87bSUlf Hansson #define PRCC_PCKEN 0x000 193b01f87bSUlf Hansson #define PRCC_PCKDIS 0x004 203b01f87bSUlf Hansson #define PRCC_KCKEN 0x008 213b01f87bSUlf Hansson #define PRCC_KCKDIS 0x00C 223b01f87bSUlf Hansson #define PRCC_PCKSR 0x010 233b01f87bSUlf Hansson #define PRCC_KCKSR 0x014 243b01f87bSUlf Hansson 253b01f87bSUlf Hansson #define to_clk_prcc(_hw) container_of(_hw, struct clk_prcc, hw) 263b01f87bSUlf Hansson 273b01f87bSUlf Hansson struct clk_prcc { 283b01f87bSUlf Hansson struct clk_hw hw; 293b01f87bSUlf Hansson void __iomem *base; 303b01f87bSUlf Hansson u32 cg_sel; 313b01f87bSUlf Hansson int is_enabled; 323b01f87bSUlf Hansson }; 333b01f87bSUlf Hansson 343b01f87bSUlf Hansson /* PRCC clock operations. */ 353b01f87bSUlf Hansson 363b01f87bSUlf Hansson static int clk_prcc_pclk_enable(struct clk_hw *hw) 373b01f87bSUlf Hansson { 383b01f87bSUlf Hansson struct clk_prcc *clk = to_clk_prcc(hw); 393b01f87bSUlf Hansson 403b01f87bSUlf Hansson writel(clk->cg_sel, (clk->base + PRCC_PCKEN)); 413b01f87bSUlf Hansson while (!(readl(clk->base + PRCC_PCKSR) & clk->cg_sel)) 423b01f87bSUlf Hansson cpu_relax(); 433b01f87bSUlf Hansson 443b01f87bSUlf Hansson clk->is_enabled = 1; 453b01f87bSUlf Hansson return 0; 463b01f87bSUlf Hansson } 473b01f87bSUlf Hansson 483b01f87bSUlf Hansson static void clk_prcc_pclk_disable(struct clk_hw *hw) 493b01f87bSUlf Hansson { 503b01f87bSUlf Hansson struct clk_prcc *clk = to_clk_prcc(hw); 513b01f87bSUlf Hansson 523b01f87bSUlf Hansson writel(clk->cg_sel, (clk->base + PRCC_PCKDIS)); 533b01f87bSUlf Hansson clk->is_enabled = 0; 543b01f87bSUlf Hansson } 553b01f87bSUlf Hansson 563b01f87bSUlf Hansson static int clk_prcc_kclk_enable(struct clk_hw *hw) 573b01f87bSUlf Hansson { 583b01f87bSUlf Hansson struct clk_prcc *clk = to_clk_prcc(hw); 593b01f87bSUlf Hansson 603b01f87bSUlf Hansson writel(clk->cg_sel, (clk->base + PRCC_KCKEN)); 613b01f87bSUlf Hansson while (!(readl(clk->base + PRCC_KCKSR) & clk->cg_sel)) 623b01f87bSUlf Hansson cpu_relax(); 633b01f87bSUlf Hansson 643b01f87bSUlf Hansson clk->is_enabled = 1; 653b01f87bSUlf Hansson return 0; 663b01f87bSUlf Hansson } 673b01f87bSUlf Hansson 683b01f87bSUlf Hansson static void clk_prcc_kclk_disable(struct clk_hw *hw) 693b01f87bSUlf Hansson { 703b01f87bSUlf Hansson struct clk_prcc *clk = to_clk_prcc(hw); 713b01f87bSUlf Hansson 723b01f87bSUlf Hansson writel(clk->cg_sel, (clk->base + PRCC_KCKDIS)); 733b01f87bSUlf Hansson clk->is_enabled = 0; 743b01f87bSUlf Hansson } 753b01f87bSUlf Hansson 763b01f87bSUlf Hansson static int clk_prcc_is_enabled(struct clk_hw *hw) 773b01f87bSUlf Hansson { 783b01f87bSUlf Hansson struct clk_prcc *clk = to_clk_prcc(hw); 793b01f87bSUlf Hansson return clk->is_enabled; 803b01f87bSUlf Hansson } 813b01f87bSUlf Hansson 82*56d87776SArvind Yadav static const struct clk_ops clk_prcc_pclk_ops = { 833b01f87bSUlf Hansson .enable = clk_prcc_pclk_enable, 843b01f87bSUlf Hansson .disable = clk_prcc_pclk_disable, 853b01f87bSUlf Hansson .is_enabled = clk_prcc_is_enabled, 863b01f87bSUlf Hansson }; 873b01f87bSUlf Hansson 88*56d87776SArvind Yadav static const struct clk_ops clk_prcc_kclk_ops = { 893b01f87bSUlf Hansson .enable = clk_prcc_kclk_enable, 903b01f87bSUlf Hansson .disable = clk_prcc_kclk_disable, 913b01f87bSUlf Hansson .is_enabled = clk_prcc_is_enabled, 923b01f87bSUlf Hansson }; 933b01f87bSUlf Hansson 943b01f87bSUlf Hansson static struct clk *clk_reg_prcc(const char *name, 953b01f87bSUlf Hansson const char *parent_name, 963b01f87bSUlf Hansson resource_size_t phy_base, 973b01f87bSUlf Hansson u32 cg_sel, 983b01f87bSUlf Hansson unsigned long flags, 99*56d87776SArvind Yadav const struct clk_ops *clk_prcc_ops) 1003b01f87bSUlf Hansson { 1013b01f87bSUlf Hansson struct clk_prcc *clk; 1023b01f87bSUlf Hansson struct clk_init_data clk_prcc_init; 1033b01f87bSUlf Hansson struct clk *clk_reg; 1043b01f87bSUlf Hansson 1053b01f87bSUlf Hansson if (!name) { 1063b01f87bSUlf Hansson pr_err("clk_prcc: %s invalid arguments passed\n", __func__); 1073b01f87bSUlf Hansson return ERR_PTR(-EINVAL); 1083b01f87bSUlf Hansson } 1093b01f87bSUlf Hansson 1103b01f87bSUlf Hansson clk = kzalloc(sizeof(struct clk_prcc), GFP_KERNEL); 1113b01f87bSUlf Hansson if (!clk) { 1123b01f87bSUlf Hansson pr_err("clk_prcc: %s could not allocate clk\n", __func__); 1133b01f87bSUlf Hansson return ERR_PTR(-ENOMEM); 1143b01f87bSUlf Hansson } 1153b01f87bSUlf Hansson 1163b01f87bSUlf Hansson clk->base = ioremap(phy_base, SZ_4K); 1173b01f87bSUlf Hansson if (!clk->base) 1183b01f87bSUlf Hansson goto free_clk; 1193b01f87bSUlf Hansson 1203b01f87bSUlf Hansson clk->cg_sel = cg_sel; 1213b01f87bSUlf Hansson clk->is_enabled = 1; 1223b01f87bSUlf Hansson 1233b01f87bSUlf Hansson clk_prcc_init.name = name; 1243b01f87bSUlf Hansson clk_prcc_init.ops = clk_prcc_ops; 1253b01f87bSUlf Hansson clk_prcc_init.flags = flags; 1263b01f87bSUlf Hansson clk_prcc_init.parent_names = (parent_name ? &parent_name : NULL); 1273b01f87bSUlf Hansson clk_prcc_init.num_parents = (parent_name ? 1 : 0); 1283b01f87bSUlf Hansson clk->hw.init = &clk_prcc_init; 1293b01f87bSUlf Hansson 1303b01f87bSUlf Hansson clk_reg = clk_register(NULL, &clk->hw); 1313b01f87bSUlf Hansson if (IS_ERR_OR_NULL(clk_reg)) 1323b01f87bSUlf Hansson goto unmap_clk; 1333b01f87bSUlf Hansson 1343b01f87bSUlf Hansson return clk_reg; 1353b01f87bSUlf Hansson 1363b01f87bSUlf Hansson unmap_clk: 1373b01f87bSUlf Hansson iounmap(clk->base); 1383b01f87bSUlf Hansson free_clk: 1393b01f87bSUlf Hansson kfree(clk); 1403b01f87bSUlf Hansson pr_err("clk_prcc: %s failed to register clk\n", __func__); 1413b01f87bSUlf Hansson return ERR_PTR(-ENOMEM); 1423b01f87bSUlf Hansson } 1433b01f87bSUlf Hansson 1443b01f87bSUlf Hansson struct clk *clk_reg_prcc_pclk(const char *name, 1453b01f87bSUlf Hansson const char *parent_name, 1463b01f87bSUlf Hansson resource_size_t phy_base, 1473b01f87bSUlf Hansson u32 cg_sel, 1483b01f87bSUlf Hansson unsigned long flags) 1493b01f87bSUlf Hansson { 1503b01f87bSUlf Hansson return clk_reg_prcc(name, parent_name, phy_base, cg_sel, flags, 1513b01f87bSUlf Hansson &clk_prcc_pclk_ops); 1523b01f87bSUlf Hansson } 1533b01f87bSUlf Hansson 1543b01f87bSUlf Hansson struct clk *clk_reg_prcc_kclk(const char *name, 1553b01f87bSUlf Hansson const char *parent_name, 1563b01f87bSUlf Hansson resource_size_t phy_base, 1573b01f87bSUlf Hansson u32 cg_sel, 1583b01f87bSUlf Hansson unsigned long flags) 1593b01f87bSUlf Hansson { 1603b01f87bSUlf Hansson return clk_reg_prcc(name, parent_name, phy_base, cg_sel, flags, 1613b01f87bSUlf Hansson &clk_prcc_kclk_ops); 1623b01f87bSUlf Hansson } 163