// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright 2013 Emilio López
*
* Emilio López <emilio@elopez.com.ar>
*/
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/reset-controller.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/log2.h>
#include "clk-factors.h"
static DEFINE_SPINLOCK(clk_lock);
/* Maximum number of parents our clocks have */
#define SUNXI_MAX_PARENTS 5
/**
* sun4i_get_pll1_factors() - calculates n, k, m, p factors for PLL1
* PLL1 rate is calculated as follows
* rate = (parent_rate * n * (k + 1) >> p) / (m + 1);
* parent_rate is always 24Mhz
*/
static void sun4i_get_pll1_factors(struct factors_request *req)
{
u8 div;
/* Normalize value to a 6M multiple */
div = req->rate / 6000000;
req->rate = 6000000 * div;
/* m is always zero for pll1 */
req->m = 0;
/* k is 1 only on these cases */
if (req->rate >= 768000000 || req->rate == 42000000 ||
req->rate == 54000000)
req->k = 1;
else
req->k = 0;
/* p will be 3 for divs under 10 */
if (div < 10)
req->p = 3;
/* p will be 2 for divs between 10 - 20 and odd divs under 32 */
else if (div < 20 || (div < 32 && (div & 1)))
req->p = 2;
/* p will be 1 for even divs under 32, divs under 40 and odd pairs
* of divs between 40-62 */
else if (div < 40 || (div < 64 && (div & 2)))
req->p = 1;
/* any other entries have p = 0 */
else
req->p = 0;
/* calculate a suitable n based on k and p */
div <<= req->p;
div /= (req->k + 1);
req->n = div / 4;
}
/**
* sun6i_a31_get_pll1_factors() - calculates n, k and m factors for PLL1
* PLL1 rate is calculated as follows
* rate = parent_rate * (n + 1) * (k + 1) / (m + 1);
* parent_rate should always be 24MHz
*/
static void sun6i_a31_get_pll1_factors(struct factors_request *req)
{
/*
* We can operate only on MHz, this will make our life easier
* later.
*/
u32 freq_mhz = req->rate / 1000000;
u32 parent_freq_mhz = req->parent_rate / 1000000;
/*
* Round down the frequency to the closest multiple of either
* 6 or 16
*/
u32 round_freq_6 = round_down(freq_mhz, 6);
u32 round_freq_16 = round_down(freq_mhz, 16);
if (round_freq_6 > round_freq_16)
freq_mhz = round_freq_6;
else
freq_mhz = round_freq_16;
req->rate = freq_mhz * 1000000;
/* If the frequency is a multiple of 32 MHz, k is always 3 */
if (!(freq_mhz % 32))
req->k = 3;
/* If the frequency is a multiple of 9 MHz, k is always 2 */
else if (!(freq_mhz % 9))
req->k = 2;
/* If the frequency is a multiple of 8 MHz, k is always 1 */
else if (!(freq_mhz % 8))
req->k = 1;
/* Otherwise, we don't use the k factor */
else
req->k = 0;
/*
* If the frequency is a multiple of 2 but not a multiple of
* 3, m is 3. This is the first time we use 6 here, yet we
* will use it on several other places.
* We use this number because it's the lowest frequency we can
* generate (with n = 0, k = 0, m = 3), so every other frequency
* somehow relates to this frequency.
*/
if ((freq_mhz % 6) == 2 || (freq_mhz % 6) == 4)
req->m = 2;
/*
* If the frequency is a multiple of 6MHz, but the factor is
* odd, m will be 3
*/
else if ((freq_mhz / 6) & 1)
req->m = 3;
/* Otherwise, we end up with m = 1 */
else
req->m = 1;
/* Calculate n thanks to the above factors we already got */
req->n = freq_mhz * (req->m + 1) / ((req->k + 1) * parent_freq_mhz)
- 1;
/*
* If n end up being outbound, and that we can still decrease
* m, do it.
*/
if ((req->n + 1) > 31 && (req->m + 1) > 1) {
req->n = (req->n + 1) / 2 - 1;
req->m = (req->m + 1) / 2 - 1;
}
}
/**
* sun8i_a23_get_pll1_factors() - calculates n, k, m, p factors for PLL1
* PLL1 rate is calculated as follows
* rate = (parent_rate * (n + 1) * (k + 1) >> p) / (m + 1);
* parent_rate is always 24Mhz
*/
static void sun8i_a23_get_pll1_factors(struct factors_request *req)