cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

clk-frac.c (2970B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright 2012 Freescale Semiconductor, Inc.
      4 */
      5
      6#include <linux/clk-provider.h>
      7#include <linux/err.h>
      8#include <linux/io.h>
      9#include <linux/slab.h>
     10#include "clk.h"
     11
     12/**
     13 * struct clk_frac - mxs fractional divider clock
     14 * @hw: clk_hw for the fractional divider clock
     15 * @reg: register address
     16 * @shift: the divider bit shift
     17 * @width: the divider bit width
     18 * @busy: busy bit shift
     19 *
     20 * The clock is an adjustable fractional divider with a busy bit to wait
     21 * when the divider is adjusted.
     22 */
     23struct clk_frac {
     24	struct clk_hw hw;
     25	void __iomem *reg;
     26	u8 shift;
     27	u8 width;
     28	u8 busy;
     29};
     30
     31#define to_clk_frac(_hw) container_of(_hw, struct clk_frac, hw)
     32
     33static unsigned long clk_frac_recalc_rate(struct clk_hw *hw,
     34					  unsigned long parent_rate)
     35{
     36	struct clk_frac *frac = to_clk_frac(hw);
     37	u32 div;
     38	u64 tmp_rate;
     39
     40	div = readl_relaxed(frac->reg) >> frac->shift;
     41	div &= (1 << frac->width) - 1;
     42
     43	tmp_rate = (u64)parent_rate * div;
     44	return tmp_rate >> frac->width;
     45}
     46
     47static long clk_frac_round_rate(struct clk_hw *hw, unsigned long rate,
     48				unsigned long *prate)
     49{
     50	struct clk_frac *frac = to_clk_frac(hw);
     51	unsigned long parent_rate = *prate;
     52	u32 div;
     53	u64 tmp, tmp_rate, result;
     54
     55	if (rate > parent_rate)
     56		return -EINVAL;
     57
     58	tmp = rate;
     59	tmp <<= frac->width;
     60	do_div(tmp, parent_rate);
     61	div = tmp;
     62
     63	if (!div)
     64		return -EINVAL;
     65
     66	tmp_rate = (u64)parent_rate * div;
     67	result = tmp_rate >> frac->width;
     68	if ((result << frac->width) < tmp_rate)
     69		result += 1;
     70	return result;
     71}
     72
     73static int clk_frac_set_rate(struct clk_hw *hw, unsigned long rate,
     74			     unsigned long parent_rate)
     75{
     76	struct clk_frac *frac = to_clk_frac(hw);
     77	unsigned long flags;
     78	u32 div, val;
     79	u64 tmp;
     80
     81	if (rate > parent_rate)
     82		return -EINVAL;
     83
     84	tmp = rate;
     85	tmp <<= frac->width;
     86	do_div(tmp, parent_rate);
     87	div = tmp;
     88
     89	if (!div)
     90		return -EINVAL;
     91
     92	spin_lock_irqsave(&mxs_lock, flags);
     93
     94	val = readl_relaxed(frac->reg);
     95	val &= ~(((1 << frac->width) - 1) << frac->shift);
     96	val |= div << frac->shift;
     97	writel_relaxed(val, frac->reg);
     98
     99	spin_unlock_irqrestore(&mxs_lock, flags);
    100
    101	return mxs_clk_wait(frac->reg, frac->busy);
    102}
    103
    104static const struct clk_ops clk_frac_ops = {
    105	.recalc_rate = clk_frac_recalc_rate,
    106	.round_rate = clk_frac_round_rate,
    107	.set_rate = clk_frac_set_rate,
    108};
    109
    110struct clk *mxs_clk_frac(const char *name, const char *parent_name,
    111			 void __iomem *reg, u8 shift, u8 width, u8 busy)
    112{
    113	struct clk_frac *frac;
    114	struct clk *clk;
    115	struct clk_init_data init;
    116
    117	frac = kzalloc(sizeof(*frac), GFP_KERNEL);
    118	if (!frac)
    119		return ERR_PTR(-ENOMEM);
    120
    121	init.name = name;
    122	init.ops = &clk_frac_ops;
    123	init.flags = CLK_SET_RATE_PARENT;
    124	init.parent_names = (parent_name ? &parent_name: NULL);
    125	init.num_parents = (parent_name ? 1 : 0);
    126
    127	frac->reg = reg;
    128	frac->shift = shift;
    129	frac->width = width;
    130	frac->busy = busy;
    131	frac->hw.init = &init;
    132
    133	clk = clk_register(NULL, &frac->hw);
    134	if (IS_ERR(clk))
    135		kfree(frac);
    136
    137	return clk;
    138}