linux/drivers/clk/sophgo/clk-sg2042-pll.c

// SPDX-License-Identifier: GPL-2.0
/*
 * Sophgo SG2042 PLL clock Driver
 *
 * Copyright (C) 2024 Sophgo Technology Inc.
 * Copyright (C) 2024 Chen Wang <[email protected]>
 */

#include <linux/array_size.h>
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/platform_device.h>
#include <asm/div64.h>

#include <dt-bindings/clock/sophgo,sg2042-pll.h>

#include "clk-sg2042.h"

/* Registers defined in SYS_CTRL */
#define R_PLL_BEGIN
#define R_PLL_STAT
#define R_PLL_CLKEN_CONTROL
#define R_MPLL_CONTROL
#define R_FPLL_CONTROL
#define R_DPLL0_CONTROL
#define R_DPLL1_CONTROL

/**
 * struct sg2042_pll_clock - PLL clock
 * @hw:				clk_hw for initialization
 * @id:				used to map clk_onecell_data
 * @base:			used for readl/writel.
 *				**NOTE**: PLL registers are all in SYS_CTRL!
 * @lock:			spinlock to protect register access, modification
 *				of frequency can only be served one at the time.
 * @offset_ctrl:		offset of pll control registers
 * @shift_status_lock:		shift of XXX_LOCK in pll status register
 * @shift_status_updating:	shift of UPDATING_XXX in pll status register
 * @shift_enable:		shift of XXX_CLK_EN in pll enable register
 */
struct sg2042_pll_clock {};

#define to_sg2042_pll_clk(_hw)

#define KHZ
#define MHZ

#define REFDIV_MIN
#define REFDIV_MAX
#define FBDIV_MIN
#define FBDIV_MAX

#define PLL_FREF_SG2042

#define PLL_FOUTPOSTDIV_MIN
#define PLL_FOUTPOSTDIV_MAX

#define PLL_FOUTVCO_MIN
#define PLL_FOUTVCO_MAX

struct sg2042_pll_ctrl {};

#define PLLCTRL_FBDIV_MASK
#define PLLCTRL_POSTDIV2_MASK
#define PLLCTRL_POSTDIV1_MASK
#define PLLCTRL_REFDIV_MASK

static inline u32 sg2042_pll_ctrl_encode(struct sg2042_pll_ctrl *ctrl)
{}

static inline void sg2042_pll_ctrl_decode(unsigned int reg_value,
					  struct sg2042_pll_ctrl *ctrl)
{}

static inline void sg2042_pll_enable(struct sg2042_pll_clock *pll, bool en)
{}

/**
 * sg2042_pll_recalc_rate() - Calculate rate for plls
 * @reg_value: current register value
 * @parent_rate: parent frequency
 *
 * This function is used to calculate below "rate" in equation
 * rate = (parent_rate/REFDIV) x FBDIV/POSTDIV1/POSTDIV2
 *      = (parent_rate x FBDIV) / (REFDIV x POSTDIV1 x POSTDIV2)
 *
 * Return: The rate calculated.
 */
static unsigned long sg2042_pll_recalc_rate(unsigned int reg_value,
					    unsigned long parent_rate)
{}

/**
 * sg2042_pll_get_postdiv_1_2() - Based on input rate/prate/fbdiv/refdiv,
 * look up the postdiv1_2 table to get the closest postdiiv combination.
 * @rate: FOUTPOSTDIV
 * @prate: parent rate, i.e. FREF
 * @fbdiv: FBDIV
 * @refdiv: REFDIV
 * @postdiv1: POSTDIV1, output
 * @postdiv2: POSTDIV2, output
 *
 * postdiv1_2 contains all the possible combination lists of POSTDIV1 and POSTDIV2
 * for example:
 * postdiv1_2[0] = {2, 4, 8}, where div1 = 2, div2 = 4 , div1 * div2 = 8
 *
 * See TRM:
 * FOUTPOSTDIV = FREF * FBDIV / REFDIV / (POSTDIV1 * POSTDIV2)
 * So we get following formula to get POSTDIV1 and POSTDIV2:
 * POSTDIV = (prate/REFDIV) x FBDIV/rate
 * above POSTDIV = POSTDIV1*POSTDIV2
 *
 * Return:
 * %0 - OK
 * %-EINVAL - invalid argument, which means Failed to get the postdivs.
 */
static int sg2042_pll_get_postdiv_1_2(unsigned long rate,
				      unsigned long prate,
				      unsigned int fbdiv,
				      unsigned int refdiv,
				      unsigned int *postdiv1,
				      unsigned int *postdiv2)
{}

/**
 * sg2042_get_pll_ctl_setting() - Based on the given FOUTPISTDIV and the input
 * FREF to calculate the REFDIV/FBDIV/PSTDIV1/POSTDIV2 combination for pllctrl
 * register.
 * @req_rate: expected output clock rate, i.e. FOUTPISTDIV
 * @parent_rate: input parent clock rate, i.e. FREF
 * @best: output to hold calculated combination of REFDIV/FBDIV/PSTDIV1/POSTDIV2
 *
 * Return:
 * %0 - OK
 * %-EINVAL - invalid argument
 */
static int sg2042_get_pll_ctl_setting(struct sg2042_pll_ctrl *best,
				      unsigned long req_rate,
				      unsigned long parent_rate)
{}

/**
 * sg2042_clk_pll_recalc_rate() - recalc_rate callback for pll clks
 * @hw: ccf use to hook get sg2042_pll_clock
 * @parent_rate: parent rate
 *
 * The is function will be called through clk_get_rate
 * and return current rate after decoding reg value
 *
 * Return: Current rate recalculated.
 */
static unsigned long sg2042_clk_pll_recalc_rate(struct clk_hw *hw,
						unsigned long parent_rate)
{}

static long sg2042_clk_pll_round_rate(struct clk_hw *hw,
				      unsigned long req_rate,
				      unsigned long *prate)
{}

static int sg2042_clk_pll_determine_rate(struct clk_hw *hw,
					 struct clk_rate_request *req)
{}

static int sg2042_clk_pll_set_rate(struct clk_hw *hw,
				   unsigned long rate,
				   unsigned long parent_rate)
{}

static const struct clk_ops sg2042_clk_pll_ops =;

static const struct clk_ops sg2042_clk_pll_ro_ops =;

/*
 * Clock initialization macro naming rules:
 * FW: use CLK_HW_INIT_FW_NAME
 * RO: means Read-Only
 */
#define SG2042_PLL_FW(_id, _name, _parent, _r_ctrl, _shift)

#define SG2042_PLL_FW_RO(_id, _name, _parent, _r_ctrl, _shift)

static struct sg2042_pll_clock sg2042_pll_clks[] =;

static DEFINE_SPINLOCK(sg2042_clk_lock);

static int sg2042_clk_register_plls(struct device *dev,
				    struct sg2042_clk_data *clk_data,
				    struct sg2042_pll_clock pll_clks[],
				    int num_pll_clks)
{}

static int sg2042_init_clkdata(struct platform_device *pdev,
			       int num_clks,
			       struct sg2042_clk_data **pp_clk_data)
{}

static int sg2042_pll_probe(struct platform_device *pdev)
{}

static const struct of_device_id sg2042_pll_match[] =;
MODULE_DEVICE_TABLE(of, sg2042_pll_match);

static struct platform_driver sg2042_pll_driver =;
module_platform_driver();

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();