xref: /openbmc/linux/drivers/clk/ux500/clk-sysctrl.c (revision b7f0dee2)
1af873fceSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
25b82d03bSUlf Hansson /*
35b82d03bSUlf Hansson  * Sysctrl clock implementation for ux500 platform.
45b82d03bSUlf Hansson  *
55b82d03bSUlf Hansson  * Copyright (C) 2013 ST-Ericsson SA
65b82d03bSUlf Hansson  * Author: Ulf Hansson <ulf.hansson@linaro.org>
75b82d03bSUlf Hansson  */
85b82d03bSUlf Hansson 
95b82d03bSUlf Hansson #include <linux/clk-provider.h>
105b82d03bSUlf Hansson #include <linux/mfd/abx500/ab8500-sysctrl.h>
115b82d03bSUlf Hansson #include <linux/device.h>
125b82d03bSUlf Hansson #include <linux/slab.h>
135b82d03bSUlf Hansson #include <linux/delay.h>
145b82d03bSUlf Hansson #include <linux/io.h>
155b82d03bSUlf Hansson #include <linux/err.h>
165b82d03bSUlf Hansson #include "clk.h"
175b82d03bSUlf Hansson 
185b82d03bSUlf Hansson #define SYSCTRL_MAX_NUM_PARENTS 4
195b82d03bSUlf Hansson 
205b82d03bSUlf Hansson #define to_clk_sysctrl(_hw) container_of(_hw, struct clk_sysctrl, hw)
215b82d03bSUlf Hansson 
225b82d03bSUlf Hansson struct clk_sysctrl {
235b82d03bSUlf Hansson 	struct clk_hw hw;
245b82d03bSUlf Hansson 	struct device *dev;
255b82d03bSUlf Hansson 	u8 parent_index;
265b82d03bSUlf Hansson 	u16 reg_sel[SYSCTRL_MAX_NUM_PARENTS];
275b82d03bSUlf Hansson 	u8 reg_mask[SYSCTRL_MAX_NUM_PARENTS];
285b82d03bSUlf Hansson 	u8 reg_bits[SYSCTRL_MAX_NUM_PARENTS];
295b82d03bSUlf Hansson 	unsigned long rate;
305b82d03bSUlf Hansson 	unsigned long enable_delay_us;
315b82d03bSUlf Hansson };
325b82d03bSUlf Hansson 
335b82d03bSUlf Hansson /* Sysctrl clock operations. */
345b82d03bSUlf Hansson 
clk_sysctrl_prepare(struct clk_hw * hw)355b82d03bSUlf Hansson static int clk_sysctrl_prepare(struct clk_hw *hw)
365b82d03bSUlf Hansson {
375b82d03bSUlf Hansson 	int ret;
385b82d03bSUlf Hansson 	struct clk_sysctrl *clk = to_clk_sysctrl(hw);
395b82d03bSUlf Hansson 
405b82d03bSUlf Hansson 	ret = ab8500_sysctrl_write(clk->reg_sel[0], clk->reg_mask[0],
415b82d03bSUlf Hansson 				clk->reg_bits[0]);
425b82d03bSUlf Hansson 
435b82d03bSUlf Hansson 	if (!ret && clk->enable_delay_us)
44c942081cSNicholas Mc Guire 		usleep_range(clk->enable_delay_us, clk->enable_delay_us +
45c942081cSNicholas Mc Guire 			     (clk->enable_delay_us >> 2));
465b82d03bSUlf Hansson 
475b82d03bSUlf Hansson 	return ret;
485b82d03bSUlf Hansson }
495b82d03bSUlf Hansson 
clk_sysctrl_unprepare(struct clk_hw * hw)505b82d03bSUlf Hansson static void clk_sysctrl_unprepare(struct clk_hw *hw)
515b82d03bSUlf Hansson {
525b82d03bSUlf Hansson 	struct clk_sysctrl *clk = to_clk_sysctrl(hw);
535b82d03bSUlf Hansson 	if (ab8500_sysctrl_clear(clk->reg_sel[0], clk->reg_mask[0]))
545b82d03bSUlf Hansson 		dev_err(clk->dev, "clk_sysctrl: %s fail to clear %s.\n",
55836ee0f7SStephen Boyd 			__func__, clk_hw_get_name(hw));
565b82d03bSUlf Hansson }
575b82d03bSUlf Hansson 
clk_sysctrl_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)585b82d03bSUlf Hansson static unsigned long clk_sysctrl_recalc_rate(struct clk_hw *hw,
595b82d03bSUlf Hansson 					unsigned long parent_rate)
605b82d03bSUlf Hansson {
615b82d03bSUlf Hansson 	struct clk_sysctrl *clk = to_clk_sysctrl(hw);
625b82d03bSUlf Hansson 	return clk->rate;
635b82d03bSUlf Hansson }
645b82d03bSUlf Hansson 
clk_sysctrl_set_parent(struct clk_hw * hw,u8 index)655b82d03bSUlf Hansson static int clk_sysctrl_set_parent(struct clk_hw *hw, u8 index)
665b82d03bSUlf Hansson {
675b82d03bSUlf Hansson 	struct clk_sysctrl *clk = to_clk_sysctrl(hw);
685b82d03bSUlf Hansson 	u8 old_index = clk->parent_index;
695b82d03bSUlf Hansson 	int ret = 0;
705b82d03bSUlf Hansson 
715b82d03bSUlf Hansson 	if (clk->reg_sel[old_index]) {
725b82d03bSUlf Hansson 		ret = ab8500_sysctrl_clear(clk->reg_sel[old_index],
735b82d03bSUlf Hansson 					clk->reg_mask[old_index]);
745b82d03bSUlf Hansson 		if (ret)
755b82d03bSUlf Hansson 			return ret;
765b82d03bSUlf Hansson 	}
775b82d03bSUlf Hansson 
785b82d03bSUlf Hansson 	if (clk->reg_sel[index]) {
795b82d03bSUlf Hansson 		ret = ab8500_sysctrl_write(clk->reg_sel[index],
805b82d03bSUlf Hansson 					clk->reg_mask[index],
815b82d03bSUlf Hansson 					clk->reg_bits[index]);
825b82d03bSUlf Hansson 		if (ret) {
835b82d03bSUlf Hansson 			if (clk->reg_sel[old_index])
845b82d03bSUlf Hansson 				ab8500_sysctrl_write(clk->reg_sel[old_index],
855b82d03bSUlf Hansson 						clk->reg_mask[old_index],
865b82d03bSUlf Hansson 						clk->reg_bits[old_index]);
875b82d03bSUlf Hansson 			return ret;
885b82d03bSUlf Hansson 		}
895b82d03bSUlf Hansson 	}
905b82d03bSUlf Hansson 	clk->parent_index = index;
915b82d03bSUlf Hansson 
925b82d03bSUlf Hansson 	return ret;
935b82d03bSUlf Hansson }
945b82d03bSUlf Hansson 
clk_sysctrl_get_parent(struct clk_hw * hw)955b82d03bSUlf Hansson static u8 clk_sysctrl_get_parent(struct clk_hw *hw)
965b82d03bSUlf Hansson {
975b82d03bSUlf Hansson 	struct clk_sysctrl *clk = to_clk_sysctrl(hw);
985b82d03bSUlf Hansson 	return clk->parent_index;
995b82d03bSUlf Hansson }
1005b82d03bSUlf Hansson 
101ca2ea4b0SArvind Yadav static const struct clk_ops clk_sysctrl_gate_ops = {
1025b82d03bSUlf Hansson 	.prepare = clk_sysctrl_prepare,
1035b82d03bSUlf Hansson 	.unprepare = clk_sysctrl_unprepare,
1045b82d03bSUlf Hansson };
1055b82d03bSUlf Hansson 
106ca2ea4b0SArvind Yadav static const struct clk_ops clk_sysctrl_gate_fixed_rate_ops = {
1075b82d03bSUlf Hansson 	.prepare = clk_sysctrl_prepare,
1085b82d03bSUlf Hansson 	.unprepare = clk_sysctrl_unprepare,
1095b82d03bSUlf Hansson 	.recalc_rate = clk_sysctrl_recalc_rate,
1105b82d03bSUlf Hansson };
1115b82d03bSUlf Hansson 
112ca2ea4b0SArvind Yadav static const struct clk_ops clk_sysctrl_set_parent_ops = {
113*b7f0dee2SMaxime Ripard 	.determine_rate = clk_hw_determine_rate_no_reparent,
1145b82d03bSUlf Hansson 	.set_parent = clk_sysctrl_set_parent,
1155b82d03bSUlf Hansson 	.get_parent = clk_sysctrl_get_parent,
1165b82d03bSUlf Hansson };
1175b82d03bSUlf Hansson 
clk_reg_sysctrl(struct device * dev,const char * name,const char ** parent_names,u8 num_parents,u16 * reg_sel,u8 * reg_mask,u8 * reg_bits,unsigned long rate,unsigned long enable_delay_us,unsigned long flags,const struct clk_ops * clk_sysctrl_ops)1185b82d03bSUlf Hansson static struct clk *clk_reg_sysctrl(struct device *dev,
1195b82d03bSUlf Hansson 				const char *name,
1205b82d03bSUlf Hansson 				const char **parent_names,
1215b82d03bSUlf Hansson 				u8 num_parents,
1225b82d03bSUlf Hansson 				u16 *reg_sel,
1235b82d03bSUlf Hansson 				u8 *reg_mask,
1245b82d03bSUlf Hansson 				u8 *reg_bits,
1255b82d03bSUlf Hansson 				unsigned long rate,
1265b82d03bSUlf Hansson 				unsigned long enable_delay_us,
1275b82d03bSUlf Hansson 				unsigned long flags,
128ca2ea4b0SArvind Yadav 				const struct clk_ops *clk_sysctrl_ops)
1295b82d03bSUlf Hansson {
1305b82d03bSUlf Hansson 	struct clk_sysctrl *clk;
1315b82d03bSUlf Hansson 	struct clk_init_data clk_sysctrl_init;
1325b82d03bSUlf Hansson 	struct clk *clk_reg;
1335b82d03bSUlf Hansson 	int i;
1345b82d03bSUlf Hansson 
1355b82d03bSUlf Hansson 	if (!dev)
1365b82d03bSUlf Hansson 		return ERR_PTR(-EINVAL);
1375b82d03bSUlf Hansson 
1385b82d03bSUlf Hansson 	if (!name || (num_parents > SYSCTRL_MAX_NUM_PARENTS)) {
1395b82d03bSUlf Hansson 		dev_err(dev, "clk_sysctrl: invalid arguments passed\n");
1405b82d03bSUlf Hansson 		return ERR_PTR(-EINVAL);
1415b82d03bSUlf Hansson 	}
1425b82d03bSUlf Hansson 
1430b10adbaSMarkus Elfring 	clk = devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL);
1447a294dc6SMarkus Elfring 	if (!clk)
1455b82d03bSUlf Hansson 		return ERR_PTR(-ENOMEM);
1465b82d03bSUlf Hansson 
147f586938bSFabio Baltieri 	/* set main clock registers */
148f586938bSFabio Baltieri 	clk->reg_sel[0] = reg_sel[0];
149f586938bSFabio Baltieri 	clk->reg_bits[0] = reg_bits[0];
150f586938bSFabio Baltieri 	clk->reg_mask[0] = reg_mask[0];
151f586938bSFabio Baltieri 
152f586938bSFabio Baltieri 	/* handle clocks with more than one parent */
153f586938bSFabio Baltieri 	for (i = 1; i < num_parents; i++) {
1545b82d03bSUlf Hansson 		clk->reg_sel[i] = reg_sel[i];
1555b82d03bSUlf Hansson 		clk->reg_bits[i] = reg_bits[i];
1565b82d03bSUlf Hansson 		clk->reg_mask[i] = reg_mask[i];
1575b82d03bSUlf Hansson 	}
1585b82d03bSUlf Hansson 
1595b82d03bSUlf Hansson 	clk->parent_index = 0;
1605b82d03bSUlf Hansson 	clk->rate = rate;
1615b82d03bSUlf Hansson 	clk->enable_delay_us = enable_delay_us;
1625b82d03bSUlf Hansson 	clk->dev = dev;
1635b82d03bSUlf Hansson 
1645b82d03bSUlf Hansson 	clk_sysctrl_init.name = name;
1655b82d03bSUlf Hansson 	clk_sysctrl_init.ops = clk_sysctrl_ops;
1665b82d03bSUlf Hansson 	clk_sysctrl_init.flags = flags;
1675b82d03bSUlf Hansson 	clk_sysctrl_init.parent_names = parent_names;
1685b82d03bSUlf Hansson 	clk_sysctrl_init.num_parents = num_parents;
1695b82d03bSUlf Hansson 	clk->hw.init = &clk_sysctrl_init;
1705b82d03bSUlf Hansson 
1715b82d03bSUlf Hansson 	clk_reg = devm_clk_register(clk->dev, &clk->hw);
1725b82d03bSUlf Hansson 	if (IS_ERR(clk_reg))
1735b82d03bSUlf Hansson 		dev_err(dev, "clk_sysctrl: clk_register failed\n");
1745b82d03bSUlf Hansson 
1755b82d03bSUlf Hansson 	return clk_reg;
1765b82d03bSUlf Hansson }
1775b82d03bSUlf Hansson 
clk_reg_sysctrl_gate(struct device * dev,const char * name,const char * parent_name,u16 reg_sel,u8 reg_mask,u8 reg_bits,unsigned long enable_delay_us,unsigned long flags)1785b82d03bSUlf Hansson struct clk *clk_reg_sysctrl_gate(struct device *dev,
1795b82d03bSUlf Hansson 				const char *name,
1805b82d03bSUlf Hansson 				const char *parent_name,
1815b82d03bSUlf Hansson 				u16 reg_sel,
1825b82d03bSUlf Hansson 				u8 reg_mask,
1835b82d03bSUlf Hansson 				u8 reg_bits,
1845b82d03bSUlf Hansson 				unsigned long enable_delay_us,
1855b82d03bSUlf Hansson 				unsigned long flags)
1865b82d03bSUlf Hansson {
1875b82d03bSUlf Hansson 	const char **parent_names = (parent_name ? &parent_name : NULL);
1885b82d03bSUlf Hansson 	u8 num_parents = (parent_name ? 1 : 0);
1895b82d03bSUlf Hansson 
1905b82d03bSUlf Hansson 	return clk_reg_sysctrl(dev, name, parent_names, num_parents,
1915b82d03bSUlf Hansson 			&reg_sel, &reg_mask, &reg_bits, 0, enable_delay_us,
1925b82d03bSUlf Hansson 			flags, &clk_sysctrl_gate_ops);
1935b82d03bSUlf Hansson }
1945b82d03bSUlf Hansson 
clk_reg_sysctrl_gate_fixed_rate(struct device * dev,const char * name,const char * parent_name,u16 reg_sel,u8 reg_mask,u8 reg_bits,unsigned long rate,unsigned long enable_delay_us,unsigned long flags)1955b82d03bSUlf Hansson struct clk *clk_reg_sysctrl_gate_fixed_rate(struct device *dev,
1965b82d03bSUlf Hansson 					const char *name,
1975b82d03bSUlf Hansson 					const char *parent_name,
1985b82d03bSUlf Hansson 					u16 reg_sel,
1995b82d03bSUlf Hansson 					u8 reg_mask,
2005b82d03bSUlf Hansson 					u8 reg_bits,
2015b82d03bSUlf Hansson 					unsigned long rate,
2025b82d03bSUlf Hansson 					unsigned long enable_delay_us,
2035b82d03bSUlf Hansson 					unsigned long flags)
2045b82d03bSUlf Hansson {
2055b82d03bSUlf Hansson 	const char **parent_names = (parent_name ? &parent_name : NULL);
2065b82d03bSUlf Hansson 	u8 num_parents = (parent_name ? 1 : 0);
2075b82d03bSUlf Hansson 
2085b82d03bSUlf Hansson 	return clk_reg_sysctrl(dev, name, parent_names, num_parents,
2095b82d03bSUlf Hansson 			&reg_sel, &reg_mask, &reg_bits,
2105b82d03bSUlf Hansson 			rate, enable_delay_us, flags,
2115b82d03bSUlf Hansson 			&clk_sysctrl_gate_fixed_rate_ops);
2125b82d03bSUlf Hansson }
2135b82d03bSUlf Hansson 
clk_reg_sysctrl_set_parent(struct device * dev,const char * name,const char ** parent_names,u8 num_parents,u16 * reg_sel,u8 * reg_mask,u8 * reg_bits,unsigned long flags)2145b82d03bSUlf Hansson struct clk *clk_reg_sysctrl_set_parent(struct device *dev,
2155b82d03bSUlf Hansson 				const char *name,
2165b82d03bSUlf Hansson 				const char **parent_names,
2175b82d03bSUlf Hansson 				u8 num_parents,
2185b82d03bSUlf Hansson 				u16 *reg_sel,
2195b82d03bSUlf Hansson 				u8 *reg_mask,
2205b82d03bSUlf Hansson 				u8 *reg_bits,
2215b82d03bSUlf Hansson 				unsigned long flags)
2225b82d03bSUlf Hansson {
2235b82d03bSUlf Hansson 	return clk_reg_sysctrl(dev, name, parent_names, num_parents,
2245b82d03bSUlf Hansson 			reg_sel, reg_mask, reg_bits, 0, 0, flags,
2255b82d03bSUlf Hansson 			&clk_sysctrl_set_parent_ops);
2265b82d03bSUlf Hansson }
227