// SPDX-License-Identifier: GPL-2.0
/*
* PLL clock driver for TI Davinci SoCs
*
* Copyright (C) 2018 David Lechner <david@lechnology.com>
*
* Based on arch/arm/mach-davinci/clock.c
* Copyright (C) 2006-2007 Texas Instruments.
* Copyright (C) 2008-2009 Deep Root Systems, LLC
*/
#include <linux/clk-provider.h>
#include <linux/clk.h>
#include <linux/clk/davinci.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
#include <linux/notifier.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/platform_data/clk-davinci-pll.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/types.h>
#include "pll.h"
#define MAX_NAME_SIZE 20
#define OSCIN_CLK_NAME "oscin"
#define REVID 0x000
#define PLLCTL 0x100
#define OCSEL 0x104
#define PLLSECCTL 0x108
#define PLLM 0x110
#define PREDIV 0x114
#define PLLDIV1 0x118
#define PLLDIV2 0x11c
#define PLLDIV3 0x120
#define OSCDIV 0x124
#define POSTDIV 0x128
#define BPDIV 0x12c
#define PLLCMD 0x138
#define PLLSTAT 0x13c
#define ALNCTL 0x140
#define DCHANGE 0x144
#define CKEN 0x148
#define CKSTAT 0x14c
#define SYSTAT 0x150
#define PLLDIV4 0x160
#define PLLDIV5 0x164
#define PLLDIV6 0x168
#define PLLDIV7 0x16c
#define PLLDIV8 0x170
#define PLLDIV9 0x174
#define PLLCTL_PLLEN BIT(0)
#define PLLCTL_PLLPWRDN BIT(1)
#define PLLCTL_PLLRST BIT(3)
#define PLLCTL_PLLDIS BIT(4)
#define PLLCTL_PLLENSRC BIT(5)
#define PLLCTL_CLKMODE BIT(8)
/* shared by most *DIV registers */
#define DIV_RATIO_SHIFT 0
#define DIV_RATIO_WIDTH 5
#define DIV_ENABLE_SHIFT 15
#define PLLCMD_GOSET BIT(0)
#define PLLSTAT_GOSTAT BIT(0)
#define CKEN_OBSCLK_SHIFT 1
#define CKEN_AUXEN_SHIFT 0
/*
* OMAP-L138 system reference guide recommends a wait for 4 OSCIN/CLKIN
* cycles to ensure that the PLLC has switched to bypass mode. Delay of 1us
* ensures we are good for all > 4MHz OSCIN/CLKIN inputs. Typically the input
* is ~25MHz. Units are micro seconds.
*/
#define PLL_BYPASS_TIME 1
/* From OMAP-L138 datasheet table 6-4. Units are micro seconds */
#define PLL_RESET_TIME 1
/*
* From OMAP-L138 datasheet table 6-4; assuming prediv = 1, sqrt(pllm) = 4
* Units are micro seconds.
*/
#define PLL_LOCK_TIME 20
/**
* struct davinci_pll_clk - Main PLL clock (aka PLLOUT)
* @hw: clk_hw for the pll
* @base: Base memory address
* @pllm_min: The minimum allowable PLLM[PLLM] value
* @pllm_max: The maxiumum allowable PLLM[PLLM] value
* @pllm_mask: Bitmask for PLLM[PLLM] value
*/
struct davinci_pll_clk {
struct clk_hw hw;
void __iomem *base;
u32 pllm_min;
u32 pllm_max;
u32 pllm_mask;
};
#define to_davinci_pll_clk(_hw) \
container_of((_hw), struct davinci_pll_clk, hw)
static unsigned long davinci_pll_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct davinci_pll_clk *pll = to_davinci_pll_clk(hw);
unsigned long rate = parent_rate;
u32 mult;
mult = readl(pll->base + PLLM) & pll->pllm_mask;
rate *= mult + 1;
return rate;
}
static int davinci_pll_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
struct davinci_pll_clk *pll = to_davinci_pll_clk(hw);
struct clk_hw *parent = req->best_parent_hw;
unsigned long parent_rate = req->best_parent_rate;
unsigned long rate = req->rate;
unsigned long best_rate, r;
u32 mult;
/* there is a limited range of valid outputs (see datasheet) */
if (rate < req->min_rate)
return -EINVAL;
rate = min(rate, req->max_rate);
mult = rate / parent_rate;
best_rate = parent_rate * mult;
/* easy case when there is no PREDIV */
if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
if (best_rate < req->min_rate)
return -EINVAL;
if (mult < pll->pllm_min || mult > pll->pllm_max)
return -EINVAL;
req->rate = best_rate;
return 0;
}
/* see if the PREDIV clock can help us */
best_rate = 0;
for (mult = pll->pllm_min; mult <= pll->pllm_max; mult++) {
parent_rate = clk_hw_round_rate(parent, rate / mult);
r = parent_rate * mult;
if (r < req->min_rate)
continue;
if (r > rate || r > req->max_rate)
break;
if (r > best_rate) {
best_rate = r;
req->rate = best_rate;
req->best_parent_rate = parent_rate;
if (best_rate == rate)
break;
}
}
return 0;
}
static int davinci_pll_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct davinci_pll_clk *pll = to_davinci_pll_clk(hw);
u32 mult;
mult = rate / parent_rate;
writel(mult - 1, pll->base + PLLM);
return 0;
}
#ifdef CONFIG_DEBUG_FS
static void davinci_pll_debug_init(struct clk_hw *hw, struct dentry *dentry);
#else
#define davinci_pll_debug_init NULL
#endif
static const struct