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-plldiv.c (2243B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
      4 */
      5
      6#include <linux/clk-provider.h>
      7#include <linux/clkdev.h>
      8#include <linux/clk/at91_pmc.h>
      9#include <linux/of.h>
     10#include <linux/mfd/syscon.h>
     11#include <linux/regmap.h>
     12
     13#include "pmc.h"
     14
     15#define to_clk_plldiv(hw) container_of(hw, struct clk_plldiv, hw)
     16
     17struct clk_plldiv {
     18	struct clk_hw hw;
     19	struct regmap *regmap;
     20};
     21
     22static unsigned long clk_plldiv_recalc_rate(struct clk_hw *hw,
     23					    unsigned long parent_rate)
     24{
     25	struct clk_plldiv *plldiv = to_clk_plldiv(hw);
     26	unsigned int mckr;
     27
     28	regmap_read(plldiv->regmap, AT91_PMC_MCKR, &mckr);
     29
     30	if (mckr & AT91_PMC_PLLADIV2)
     31		return parent_rate / 2;
     32
     33	return parent_rate;
     34}
     35
     36static long clk_plldiv_round_rate(struct clk_hw *hw, unsigned long rate,
     37					unsigned long *parent_rate)
     38{
     39	unsigned long div;
     40
     41	if (rate > *parent_rate)
     42		return *parent_rate;
     43	div = *parent_rate / 2;
     44	if (rate < div)
     45		return div;
     46
     47	if (rate - div < *parent_rate - rate)
     48		return div;
     49
     50	return *parent_rate;
     51}
     52
     53static int clk_plldiv_set_rate(struct clk_hw *hw, unsigned long rate,
     54			       unsigned long parent_rate)
     55{
     56	struct clk_plldiv *plldiv = to_clk_plldiv(hw);
     57
     58	if ((parent_rate != rate) && (parent_rate / 2 != rate))
     59		return -EINVAL;
     60
     61	regmap_update_bits(plldiv->regmap, AT91_PMC_MCKR, AT91_PMC_PLLADIV2,
     62			   parent_rate != rate ? AT91_PMC_PLLADIV2 : 0);
     63
     64	return 0;
     65}
     66
     67static const struct clk_ops plldiv_ops = {
     68	.recalc_rate = clk_plldiv_recalc_rate,
     69	.round_rate = clk_plldiv_round_rate,
     70	.set_rate = clk_plldiv_set_rate,
     71};
     72
     73struct clk_hw * __init
     74at91_clk_register_plldiv(struct regmap *regmap, const char *name,
     75			 const char *parent_name)
     76{
     77	struct clk_plldiv *plldiv;
     78	struct clk_hw *hw;
     79	struct clk_init_data init;
     80	int ret;
     81
     82	plldiv = kzalloc(sizeof(*plldiv), GFP_KERNEL);
     83	if (!plldiv)
     84		return ERR_PTR(-ENOMEM);
     85
     86	init.name = name;
     87	init.ops = &plldiv_ops;
     88	init.parent_names = parent_name ? &parent_name : NULL;
     89	init.num_parents = parent_name ? 1 : 0;
     90	init.flags = CLK_SET_RATE_GATE;
     91
     92	plldiv->hw.init = &init;
     93	plldiv->regmap = regmap;
     94
     95	hw = &plldiv->hw;
     96	ret = clk_hw_register(NULL, &plldiv->hw);
     97	if (ret) {
     98		kfree(plldiv);
     99		hw = ERR_PTR(ret);
    100	}
    101
    102	return hw;
    103}