xref: /openbmc/linux/drivers/clk/ux500/clk-prcc.c (revision 56d877764112af89aebb17e831c579827f006df0)
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