File Index
Files and directories
Sign in
FILE

clk-gpt-synth.c

File preview with syntax highlighting.

linux-6.19.14/drivers/clk/spear/clk-gpt-synth.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (C) 2012 ST Microelectronics
  4 * Viresh Kumar <vireshk@kernel.org>
  5 *
  6 * General Purpose Timer Synthesizer clock implementation
  7 */
  8
  9#define pr_fmt(fmt) "clk-gpt-synth: " fmt
 10
 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		0xFFF
 18#define GPT_NSCALE_SHIFT	12
 19#define GPT_NSCALE_MASK		0xF
 20
 21/*
 22 * DOC: General Purpose Timer Synthesizer clock
 23 *
 24 * Calculates gpt synth clk rate for different values of mscale and nscale
 25 *
 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 int clk_gpt_determine_rate(struct clk_hw *hw,
 43				  struct clk_rate_request *req)
 44{
 45	struct clk_gpt *gpt = to_clk_gpt(hw);
 46	int unused;
 47
 48	req->rate = clk_round_rate_index(hw, req->rate, req->best_parent_rate,
 49					 gpt_calc_rate, gpt->rtbl_cnt, &unused);
 50
 51	return 0;
 52}
 53
 54static unsigned long clk_gpt_recalc_rate(struct clk_hw *hw,
 55		unsigned long parent_rate)
 56{
 57	struct clk_gpt *gpt = to_clk_gpt(hw);
 58	unsigned long flags = 0;
 59	unsigned int div = 1, val;
 60
 61	if (gpt->lock)
 62		spin_lock_irqsave(gpt->lock, flags);
 63
 64	val = readl_relaxed(gpt->reg);
 65
 66	if (gpt->lock)
 67		spin_unlock_irqrestore(gpt->lock, flags);
 68
 69	div += val & GPT_MSCALE_MASK;
 70	div *= 1 << (((val >> GPT_NSCALE_SHIFT) & GPT_NSCALE_MASK) + 1);
 71
 72	if (!div)
 73		return 0;
 74
 75	return parent_rate / div;
 76}
 77
 78/* Configures new clock rate of gpt */
 79static int clk_gpt_set_rate(struct clk_hw *hw, unsigned long drate,
 80				unsigned long prate)
 81{
 82	struct clk_gpt *gpt = to_clk_gpt(hw);
 83	struct gpt_rate_tbl *rtbl = gpt->rtbl;
 84	unsigned long flags = 0, val;
 85	int i;
 86
 87	clk_round_rate_index(hw, drate, prate, gpt_calc_rate, gpt->rtbl_cnt,
 88			&i);
 89
 90	if (gpt->lock)
 91		spin_lock_irqsave(gpt->lock, flags);
 92
 93	val = readl(gpt->reg) & ~GPT_MSCALE_MASK;
 94	val &= ~(GPT_NSCALE_MASK << GPT_NSCALE_SHIFT);
 95
 96	val |= rtbl[i].mscale & GPT_MSCALE_MASK;
 97	val |= (rtbl[i].nscale & GPT_NSCALE_MASK) << GPT_NSCALE_SHIFT;
 98
 99	writel_relaxed(val, gpt->reg);
100
101	if (gpt->lock)
102		spin_unlock_irqrestore(gpt->lock, flags);
103
104	return 0;
105}
106
107static const struct clk_ops clk_gpt_ops = {
108	.recalc_rate = clk_gpt_recalc_rate,
109	.determine_rate = clk_gpt_determine_rate,
110	.set_rate = clk_gpt_set_rate,
111};
112
113struct clk *clk_register_gpt(const char *name, const char *parent_name, unsigned
114		long flags, void __iomem *reg, struct gpt_rate_tbl *rtbl, u8
115		rtbl_cnt, spinlock_t *lock)
116{
117	struct clk_init_data init;
118	struct clk_gpt *gpt;
119	struct clk *clk;
120
121	if (!name || !parent_name || !reg || !rtbl || !rtbl_cnt) {
122		pr_err("Invalid arguments passed\n");
123		return ERR_PTR(-EINVAL);
124	}
125
126	gpt = kzalloc(sizeof(*gpt), GFP_KERNEL);
127	if (!gpt)
128		return ERR_PTR(-ENOMEM);
129
130	/* struct clk_gpt assignments */
131	gpt->reg = reg;
132	gpt->rtbl = rtbl;
133	gpt->rtbl_cnt = rtbl_cnt;
134	gpt->lock = lock;
135	gpt->hw.init = &init;
136
137	init.name = name;
138	init.ops = &clk_gpt_ops;
139	init.flags = flags;
140	init.parent_names = &parent_name;
141	init.num_parents = 1;
142
143	clk = clk_register(NULL, &gpt->hw);
144	if (!IS_ERR_OR_NULL(clk))
145		return clk;
146
147	pr_err("clk register failed\n");
148	kfree(gpt);
149
150	return NULL;
151}
~/ Read-only file preview.