linux/drivers/clk/clk-si5341.c

// SPDX-License-Identifier: GPL-2.0
/*
 * Driver for Silicon Labs Si5340, Si5341, Si5342, Si5344 and Si5345
 * Copyright (C) 2019 Topic Embedded Products
 * Author: Mike Looijmans <[email protected]>
 *
 * The Si5341 has 10 outputs and 5 synthesizers.
 * The Si5340 is a smaller version of the Si5341 with only 4 outputs.
 * The Si5345 is similar to the Si5341, with the addition of fractional input
 * dividers and automatic input selection.
 * The Si5342 and Si5344 are smaller versions of the Si5345.
 */

#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/gcd.h>
#include <linux/math64.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <asm/unaligned.h>

#define SI5341_NUM_INPUTS

#define SI5340_MAX_NUM_OUTPUTS
#define SI5341_MAX_NUM_OUTPUTS
#define SI5342_MAX_NUM_OUTPUTS
#define SI5344_MAX_NUM_OUTPUTS
#define SI5345_MAX_NUM_OUTPUTS

#define SI5340_NUM_SYNTH
#define SI5341_NUM_SYNTH
#define SI5342_NUM_SYNTH
#define SI5344_NUM_SYNTH
#define SI5345_NUM_SYNTH

/* Range of the synthesizer fractional divider */
#define SI5341_SYNTH_N_MIN
#define SI5341_SYNTH_N_MAX

/* The chip can get its input clock from 3 input pins or an XTAL */

/* There is one PLL running at 13500–14256 MHz */
#define SI5341_PLL_VCO_MIN
#define SI5341_PLL_VCO_MAX

/* The 5 frequency synthesizers obtain their input from the PLL */
struct clk_si5341_synth {};
#define to_clk_si5341_synth(_hw)

/* The output stages can be connected to any synth (full mux) */
struct clk_si5341_output {};
#define to_clk_si5341_output(_hw)

struct clk_si5341 {};
#define to_clk_si5341(_hw)

struct clk_si5341_output_config {};

#define SI5341_PAGE
#define SI5341_PN_BASE
#define SI5341_DEVICE_REV
#define SI5341_STATUS
#define SI5341_LOS
#define SI5341_STATUS_STICKY
#define SI5341_LOS_STICKY
#define SI5341_SOFT_RST
#define SI5341_IN_SEL
#define SI5341_DEVICE_READY
#define SI5341_XAXB_CFG
#define SI5341_IO_VDD_SEL
#define SI5341_IN_EN
#define SI5341_INX_TO_PFD_EN

/* Status bits */
#define SI5341_STATUS_SYSINCAL
#define SI5341_STATUS_LOSXAXB
#define SI5341_STATUS_LOSREF
#define SI5341_STATUS_LOL

/* Input selection */
#define SI5341_IN_SEL_MASK
#define SI5341_IN_SEL_SHIFT
#define SI5341_IN_SEL_REGCTRL
#define SI5341_INX_TO_PFD_SHIFT

/* XTAL config bits */
#define SI5341_XAXB_CFG_EXTCLK_EN
#define SI5341_XAXB_CFG_PDNB

/* Input dividers (48-bit) */
#define SI5341_IN_PDIV(x)
#define SI5341_IN_PSET(x)
#define SI5341_PX_UPD

/* PLL configuration */
#define SI5341_PLL_M_NUM
#define SI5341_PLL_M_DEN

/* Output configuration */
#define SI5341_OUT_CONFIG(output)
#define SI5341_OUT_FORMAT(output)
#define SI5341_OUT_CM(output)
#define SI5341_OUT_MUX_SEL(output)
#define SI5341_OUT_R_REG(output)

#define SI5341_OUT_MUX_VDD_SEL_MASK

/* Synthesize N divider */
#define SI5341_SYNTH_N_NUM(x)
#define SI5341_SYNTH_N_DEN(x)
#define SI5341_SYNTH_N_UPD(x)

/* Synthesizer output enable, phase bypass, power mode */
#define SI5341_SYNTH_N_CLK_TO_OUTX_EN
#define SI5341_SYNTH_N_PIBYP
#define SI5341_SYNTH_N_PDNB
#define SI5341_SYNTH_N_CLK_DIS

#define SI5341_REGISTER_MAX

/* SI5341_OUT_CONFIG bits */
#define SI5341_OUT_CFG_PDN
#define SI5341_OUT_CFG_OE
#define SI5341_OUT_CFG_RDIV_FORCE2

/* Static configuration (to be moved to firmware) */
struct si5341_reg_default {};

static const char * const si5341_input_clock_names[] =;

/* Output configuration registers 0..9 are not quite logically organized */
/* Also for si5345 */
static const u16 si5341_reg_output_offset[] =;

/* for si5340, si5342 and si5344 */
static const u16 si5340_reg_output_offset[] =;

/* The location of the R divider registers */
static const u16 si5341_reg_rdiv_offset[] =;
static const u16 si5340_reg_rdiv_offset[] =;

/*
 * Programming sequence from ClockBuilder, settings to initialize the system
 * using only the XTAL input, without pre-divider.
 * This also contains settings that aren't mentioned anywhere in the datasheet.
 * The "known" settings like synth and output configuration are done later.
 */
static const struct si5341_reg_default si5341_reg_defaults[] =;

/* Read and interpret a 44-bit followed by a 32-bit value in the regmap */
static int si5341_decode_44_32(struct regmap *regmap, unsigned int reg,
	u64 *val1, u32 *val2)
{}

static int si5341_encode_44_32(struct regmap *regmap, unsigned int reg,
	u64 n_num, u32 n_den)
{}

/* VCO, we assume it runs at a constant frequency */
static unsigned long si5341_clk_recalc_rate(struct clk_hw *hw,
		unsigned long parent_rate)
{}

static int si5341_clk_get_selected_input(struct clk_si5341 *data)
{}

static u8 si5341_clk_get_parent(struct clk_hw *hw)
{}

static int si5341_clk_reparent(struct clk_si5341 *data, u8 index)
{}

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

static const struct clk_ops si5341_clk_ops =;

/* Synthesizers, there are 5 synthesizers that connect to any of the outputs */

/* The synthesizer is on if all power and enable bits are set */
static int si5341_synth_clk_is_on(struct clk_hw *hw)
{}

static void si5341_synth_clk_unprepare(struct clk_hw *hw)
{}

static int si5341_synth_clk_prepare(struct clk_hw *hw)
{}

/* Synth clock frequency: Fvco * n_den / n_den, with Fvco in 13500-14256 MHz */
static unsigned long si5341_synth_clk_recalc_rate(struct clk_hw *hw,
		unsigned long parent_rate)
{}

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

static int si5341_synth_program(struct clk_si5341_synth *synth,
	u64 n_num, u32 n_den, bool is_integer)
{}


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

static const struct clk_ops si5341_synth_clk_ops =;

static int si5341_output_clk_is_on(struct clk_hw *hw)
{}

/* Disables and then powers down the output */
static void si5341_output_clk_unprepare(struct clk_hw *hw)
{}

/* Powers up and then enables the output */
static int si5341_output_clk_prepare(struct clk_hw *hw)
{}

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

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

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

static int si5341_output_reparent(struct clk_si5341_output *output, u8 index)
{}

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

static u8 si5341_output_get_parent(struct clk_hw *hw)
{}

static const struct clk_ops si5341_output_clk_ops =;

/*
 * The chip can be bought in a pre-programmed version, or one can program the
 * NVM in the chip to boot up in a preset mode. This routine tries to determine
 * if that's the case, or if we need to reset and program everything from
 * scratch. Returns negative error, or true/false.
 */
static int si5341_is_programmed_already(struct clk_si5341 *data)
{}

static struct clk_hw *
of_clk_si5341_get(struct of_phandle_args *clkspec, void *_data)
{}

static int si5341_probe_chip_id(struct clk_si5341 *data)
{}

/* Read active settings into the regmap cache for later reference */
static int si5341_read_settings(struct clk_si5341 *data)
{}

static int si5341_write_multiple(struct clk_si5341 *data,
	const struct si5341_reg_default *values, unsigned int num_values)
{}

static const struct si5341_reg_default si5341_preamble[] =;

static const struct si5341_reg_default si5345_preamble[] =;

static int si5341_send_preamble(struct clk_si5341 *data)
{}

/* Perform a soft reset and write post-amble */
static int si5341_finalize_defaults(struct clk_si5341 *data)
{}


static const struct regmap_range si5341_regmap_volatile_range[] =;

static const struct regmap_access_table si5341_regmap_volatile =;

/* Pages 0, 1, 2, 3, 9, A, B are valid, so there are 12 pages */
static const struct regmap_range_cfg si5341_regmap_ranges[] =;

static int si5341_wait_device_ready(struct i2c_client *client)
{}

static const struct regmap_config si5341_regmap_config =;

static int si5341_dt_parse_dt(struct clk_si5341 *data,
			      struct clk_si5341_output_config *config)
{}

/*
 * If not pre-configured, calculate and set the PLL configuration manually.
 * For low-jitter performance, the PLL should be set such that the synthesizers
 * only need integer division.
 * Without any user guidance, we'll set the PLL to 14GHz, which still allows
 * the chip to generate any frequency on its outputs, but jitter performance
 * may be sub-optimal.
 */
static int si5341_initialize_pll(struct clk_si5341 *data)
{}

static int si5341_clk_select_active_input(struct clk_si5341 *data)
{}

static ssize_t input_present_show(struct device *dev,
				  struct device_attribute *attr,
				  char *buf)
{}
static DEVICE_ATTR_RO(input_present);

static ssize_t input_present_sticky_show(struct device *dev,
					 struct device_attribute *attr,
					 char *buf)
{}
static DEVICE_ATTR_RO(input_present_sticky);

static ssize_t pll_locked_show(struct device *dev,
			       struct device_attribute *attr,
			       char *buf)
{}
static DEVICE_ATTR_RO(pll_locked);

static ssize_t pll_locked_sticky_show(struct device *dev,
				      struct device_attribute *attr,
				      char *buf)
{}
static DEVICE_ATTR_RO(pll_locked_sticky);

static ssize_t clear_sticky_store(struct device *dev,
				  struct device_attribute *attr,
				  const char *buf, size_t count)
{}
static DEVICE_ATTR_WO(clear_sticky);

static const struct attribute *si5341_attributes[] =;

static int si5341_probe(struct i2c_client *client)
{}

static void si5341_remove(struct i2c_client *client)
{}

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

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

static struct i2c_driver si5341_driver =;
module_i2c_driver();

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