brintos

brintos / linux-shallow public Read only

0
0
Text · 3.3 KiB · 4ef747c Raw
150 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2012 ST Microelectronics4 * Viresh Kumar <vireshk@kernel.org>5 *6 * General Purpose Timer Synthesizer clock implementation7 */8 9#define pr_fmt(fmt) "clk-gpt-synth: " fmt10 11#include <linux/clk-provider.h>12#include <linux/slab.h>13#include <linux/io.h>14#include <linux/err.h>15#include "clk.h"16 17#define GPT_MSCALE_MASK		0xFFF18#define GPT_NSCALE_SHIFT	1219#define GPT_NSCALE_MASK		0xF20 21/*22 * DOC: General Purpose Timer Synthesizer clock23 *24 * Calculates gpt synth clk rate for different values of mscale and nscale25 *26 * Fout= Fin/((2 ^ (N+1)) * (M+1))27 */28 29#define to_clk_gpt(_hw) container_of(_hw, struct clk_gpt, hw)30 31static unsigned long gpt_calc_rate(struct clk_hw *hw, unsigned long prate,32		int index)33{34	struct clk_gpt *gpt = to_clk_gpt(hw);35	struct gpt_rate_tbl *rtbl = gpt->rtbl;36 37	prate /= ((1 << (rtbl[index].nscale + 1)) * (rtbl[index].mscale + 1));38 39	return prate;40}41 42static long clk_gpt_round_rate(struct clk_hw *hw, unsigned long drate,43		unsigned long *prate)44{45	struct clk_gpt *gpt = to_clk_gpt(hw);46	int unused;47 48	return clk_round_rate_index(hw, drate, *prate, gpt_calc_rate,49			gpt->rtbl_cnt, &unused);50}51 52static unsigned long clk_gpt_recalc_rate(struct clk_hw *hw,53		unsigned long parent_rate)54{55	struct clk_gpt *gpt = to_clk_gpt(hw);56	unsigned long flags = 0;57	unsigned int div = 1, val;58 59	if (gpt->lock)60		spin_lock_irqsave(gpt->lock, flags);61 62	val = readl_relaxed(gpt->reg);63 64	if (gpt->lock)65		spin_unlock_irqrestore(gpt->lock, flags);66 67	div += val & GPT_MSCALE_MASK;68	div *= 1 << (((val >> GPT_NSCALE_SHIFT) & GPT_NSCALE_MASK) + 1);69 70	if (!div)71		return 0;72 73	return parent_rate / div;74}75 76/* Configures new clock rate of gpt */77static int clk_gpt_set_rate(struct clk_hw *hw, unsigned long drate,78				unsigned long prate)79{80	struct clk_gpt *gpt = to_clk_gpt(hw);81	struct gpt_rate_tbl *rtbl = gpt->rtbl;82	unsigned long flags = 0, val;83	int i;84 85	clk_round_rate_index(hw, drate, prate, gpt_calc_rate, gpt->rtbl_cnt,86			&i);87 88	if (gpt->lock)89		spin_lock_irqsave(gpt->lock, flags);90 91	val = readl(gpt->reg) & ~GPT_MSCALE_MASK;92	val &= ~(GPT_NSCALE_MASK << GPT_NSCALE_SHIFT);93 94	val |= rtbl[i].mscale & GPT_MSCALE_MASK;95	val |= (rtbl[i].nscale & GPT_NSCALE_MASK) << GPT_NSCALE_SHIFT;96 97	writel_relaxed(val, gpt->reg);98 99	if (gpt->lock)100		spin_unlock_irqrestore(gpt->lock, flags);101 102	return 0;103}104 105static const struct clk_ops clk_gpt_ops = {106	.recalc_rate = clk_gpt_recalc_rate,107	.round_rate = clk_gpt_round_rate,108	.set_rate = clk_gpt_set_rate,109};110 111struct clk *clk_register_gpt(const char *name, const char *parent_name, unsigned112		long flags, void __iomem *reg, struct gpt_rate_tbl *rtbl, u8113		rtbl_cnt, spinlock_t *lock)114{115	struct clk_init_data init;116	struct clk_gpt *gpt;117	struct clk *clk;118 119	if (!name || !parent_name || !reg || !rtbl || !rtbl_cnt) {120		pr_err("Invalid arguments passed\n");121		return ERR_PTR(-EINVAL);122	}123 124	gpt = kzalloc(sizeof(*gpt), GFP_KERNEL);125	if (!gpt)126		return ERR_PTR(-ENOMEM);127 128	/* struct clk_gpt assignments */129	gpt->reg = reg;130	gpt->rtbl = rtbl;131	gpt->rtbl_cnt = rtbl_cnt;132	gpt->lock = lock;133	gpt->hw.init = &init;134 135	init.name = name;136	init.ops = &clk_gpt_ops;137	init.flags = flags;138	init.parent_names = &parent_name;139	init.num_parents = 1;140 141	clk = clk_register(NULL, &gpt->hw);142	if (!IS_ERR_OR_NULL(clk))143		return clk;144 145	pr_err("clk register failed\n");146	kfree(gpt);147 148	return NULL;149}150