linux/drivers/clk/clk-si5351.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * clk-si5351.c: Skyworks / Silicon Labs Si5351A/B/C I2C Clock Generator
 *
 * Sebastian Hesselbarth <[email protected]>
 * Rabeeh Khoury <[email protected]>
 *
 * References:
 * [1] "Si5351A/B/C Data Sheet"
 *     https://www.skyworksinc.com/-/media/Skyworks/SL/documents/public/data-sheets/Si5351-B.pdf
 * [2] "AN619: Manually Generating an Si5351 Register Map"
 *     https://www.skyworksinc.com/-/media/Skyworks/SL/documents/public/application-notes/AN619.pdf
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/rational.h>
#include <linux/i2c.h>
#include <linux/of.h>
#include <linux/platform_data/si5351.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <asm/div64.h>

#include "clk-si5351.h"

struct si5351_driver_data;

struct si5351_parameters {};

struct si5351_hw_data {};

struct si5351_driver_data {};

static const char * const si5351_input_names[] =;
static const char * const si5351_pll_names[] =;
static const char * const si5351_msynth_names[] =;
static const char * const si5351_clkout_names[] =;

/*
 * Si5351 i2c regmap
 */
static inline u8 si5351_reg_read(struct si5351_driver_data *drvdata, u8 reg)
{}

static inline int si5351_bulk_read(struct si5351_driver_data *drvdata,
				   u8 reg, u8 count, u8 *buf)
{}

static inline int si5351_reg_write(struct si5351_driver_data *drvdata,
				   u8 reg, u8 val)
{}

static inline int si5351_bulk_write(struct si5351_driver_data *drvdata,
				    u8 reg, u8 count, const u8 *buf)
{}

static inline int si5351_set_bits(struct si5351_driver_data *drvdata,
				  u8 reg, u8 mask, u8 val)
{}

static inline u8 si5351_msynth_params_address(int num)
{}

static void si5351_read_parameters(struct si5351_driver_data *drvdata,
				   u8 reg, struct si5351_parameters *params)
{}

static void si5351_write_parameters(struct si5351_driver_data *drvdata,
				    u8 reg, struct si5351_parameters *params)
{}

static bool si5351_regmap_is_volatile(struct device *dev, unsigned int reg)
{}

static bool si5351_regmap_is_writeable(struct device *dev, unsigned int reg)
{}

static const struct regmap_config si5351_regmap_config =;

/*
 * Si5351 xtal clock input
 */
static int si5351_xtal_prepare(struct clk_hw *hw)
{}

static void si5351_xtal_unprepare(struct clk_hw *hw)
{}

static const struct clk_ops si5351_xtal_ops =;

/*
 * Si5351 clkin clock input (Si5351C only)
 */
static int si5351_clkin_prepare(struct clk_hw *hw)
{}

static void si5351_clkin_unprepare(struct clk_hw *hw)
{}

/*
 * CMOS clock source constraints:
 * The input frequency range of the PLL is 10Mhz to 40MHz.
 * If CLKIN is >40MHz, the input divider must be used.
 */
static unsigned long si5351_clkin_recalc_rate(struct clk_hw *hw,
					      unsigned long parent_rate)
{}

static const struct clk_ops si5351_clkin_ops =;

/*
 * Si5351 vxco clock input (Si5351B only)
 */

static int si5351_vxco_prepare(struct clk_hw *hw)
{}

static void si5351_vxco_unprepare(struct clk_hw *hw)
{}

static unsigned long si5351_vxco_recalc_rate(struct clk_hw *hw,
					     unsigned long parent_rate)
{}

static int si5351_vxco_set_rate(struct clk_hw *hw, unsigned long rate,
				unsigned long parent)
{}

static const struct clk_ops si5351_vxco_ops =;

/*
 * Si5351 pll a/b
 *
 * Feedback Multisynth Divider Equations [2]
 *
 * fVCO = fIN * (a + b/c)
 *
 * with 15 + 0/1048575 <= (a + b/c) <= 90 + 0/1048575 and
 * fIN = fXTAL or fIN = fCLKIN/CLKIN_DIV
 *
 * Feedback Multisynth Register Equations
 *
 * (1) MSNx_P1[17:0] = 128 * a + floor(128 * b/c) - 512
 * (2) MSNx_P2[19:0] = 128 * b - c * floor(128 * b/c) = (128*b) mod c
 * (3) MSNx_P3[19:0] = c
 *
 * Transposing (2) yields: (4) floor(128 * b/c) = (128 * b / MSNx_P2)/c
 *
 * Using (4) on (1) yields:
 * MSNx_P1 = 128 * a + (128 * b/MSNx_P2)/c - 512
 * MSNx_P1 + 512 + MSNx_P2/c = 128 * a + 128 * b/c
 *
 * a + b/c = (MSNx_P1 + MSNx_P2/MSNx_P3 + 512)/128
 *         = (MSNx_P1*MSNx_P3 + MSNx_P2 + 512*MSNx_P3)/(128*MSNx_P3)
 *
 */
static int _si5351_pll_reparent(struct si5351_driver_data *drvdata,
				int num, enum si5351_pll_src parent)
{}

static unsigned char si5351_pll_get_parent(struct clk_hw *hw)
{}

static int si5351_pll_set_parent(struct clk_hw *hw, u8 index)
{}

static unsigned long si5351_pll_recalc_rate(struct clk_hw *hw,
					    unsigned long parent_rate)
{}

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

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

static const struct clk_ops si5351_pll_ops =;

/*
 * Si5351 multisync divider
 *
 * for fOUT <= 150 MHz:
 *
 * fOUT = (fIN * (a + b/c)) / CLKOUTDIV
 *
 * with 6 + 0/1048575 <= (a + b/c) <= 1800 + 0/1048575 and
 * fIN = fVCO0, fVCO1
 *
 * Output Clock Multisynth Register Equations
 *
 * MSx_P1[17:0] = 128 * a + floor(128 * b/c) - 512
 * MSx_P2[19:0] = 128 * b - c * floor(128 * b/c) = (128*b) mod c
 * MSx_P3[19:0] = c
 *
 * MS[6,7] are integer (P1) divide only, P1 = divide value,
 * P2 and P3 are not applicable
 *
 * for 150MHz < fOUT <= 160MHz:
 *
 * MSx_P1 = 0, MSx_P2 = 0, MSx_P3 = 1, MSx_INT = 1, MSx_DIVBY4 = 11b
 */
static int _si5351_msynth_reparent(struct si5351_driver_data *drvdata,
				   int num, enum si5351_multisynth_src parent)
{}

static unsigned char si5351_msynth_get_parent(struct clk_hw *hw)
{}

static int si5351_msynth_set_parent(struct clk_hw *hw, u8 index)
{}

static unsigned long si5351_msynth_recalc_rate(struct clk_hw *hw,
					       unsigned long parent_rate)
{}

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

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

static const struct clk_ops si5351_msynth_ops =;

/*
 * Si5351 clkout divider
 */
static int _si5351_clkout_reparent(struct si5351_driver_data *drvdata,
				   int num, enum si5351_clkout_src parent)
{}

static int _si5351_clkout_set_drive_strength(
	struct si5351_driver_data *drvdata, int num,
	enum si5351_drive_strength drive)
{}

static int _si5351_clkout_set_disable_state(
	struct si5351_driver_data *drvdata, int num,
	enum si5351_disable_state state)
{}

static void _si5351_clkout_reset_pll(struct si5351_driver_data *drvdata, int num)
{}

static int si5351_clkout_prepare(struct clk_hw *hw)
{}

static void si5351_clkout_unprepare(struct clk_hw *hw)
{}

static u8 si5351_clkout_get_parent(struct clk_hw *hw)
{}

static int si5351_clkout_set_parent(struct clk_hw *hw, u8 index)
{}

static unsigned long si5351_clkout_recalc_rate(struct clk_hw *hw,
					       unsigned long parent_rate)
{}

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

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

static const struct clk_ops si5351_clkout_ops =;

/*
 * Si5351 i2c probe and DT
 */
#ifdef CONFIG_OF
static const struct of_device_id si5351_dt_ids[] =;
MODULE_DEVICE_TABLE(of, si5351_dt_ids);

static int si5351_dt_parse(struct i2c_client *client,
			   enum si5351_variant variant)
{}

static struct clk_hw *
si53351_of_clk_get(struct of_phandle_args *clkspec, void *data)
{}
#else
static int si5351_dt_parse(struct i2c_client *client, enum si5351_variant variant)
{
	return 0;
}

static struct clk_hw *
si53351_of_clk_get(struct of_phandle_args *clkspec, void *data)
{
	return NULL;
}
#endif /* CONFIG_OF */

static const struct i2c_device_id si5351_i2c_ids[] =;
MODULE_DEVICE_TABLE(i2c, si5351_i2c_ids);

static int si5351_i2c_probe(struct i2c_client *client)
{}

static struct i2c_driver si5351_driver =;
module_i2c_driver();

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