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