linux/drivers/clk/clk-apple-nco.c

// SPDX-License-Identifier: GPL-2.0-only OR MIT
/*
 * Driver for an SoC block (Numerically Controlled Oscillator)
 * found on t8103 (M1) and other Apple chips
 *
 * Copyright (C) The Asahi Linux Contributors
 */

#include <linux/bits.h>
#include <linux/bitfield.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/math64.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>

#define NCO_CHANNEL_STRIDE
#define NCO_CHANNEL_REGSIZE

#define REG_CTRL
#define CTRL_ENABLE
#define REG_DIV
#define DIV_FINE
#define DIV_COARSE
#define REG_INC1
#define REG_INC2
#define REG_ACCINIT

/*
 * Theory of operation (postulated)
 *
 * The REG_DIV register indirectly expresses a base integer divisor, roughly
 * corresponding to twice the desired ratio of input to output clock. This
 * base divisor is adjusted on a cycle-by-cycle basis based on the state of a
 * 32-bit phase accumulator to achieve a desired precise clock ratio over the
 * long term.
 *
 * Specifically an output clock cycle is produced after (REG_DIV divisor)/2
 * or (REG_DIV divisor + 1)/2 input cycles, the latter taking effect when top
 * bit of the 32-bit accumulator is set. The accumulator is incremented each
 * produced output cycle, by the value from either REG_INC1 or REG_INC2, which
 * of the two is selected depending again on the accumulator's current top bit.
 *
 * Because the NCO hardware implements counting of input clock cycles in part
 * in a Galois linear-feedback shift register, the higher bits of divisor
 * are programmed into REG_DIV by picking an appropriate LFSR state. See
 * applnco_compute_tables/applnco_div_translate for details on this.
 */

#define LFSR_POLY
#define LFSR_INIT
#define LFSR_LEN
#define LFSR_PERIOD
#define LFSR_TBLSIZE

/* The minimal attainable coarse divisor (first value in table) */
#define COARSE_DIV_OFFSET

struct applnco_tables {};

struct applnco_channel {};

#define to_applnco_channel(_hw)

static void applnco_enable_nolock(struct clk_hw *hw)
{}

static void applnco_disable_nolock(struct clk_hw *hw)
{}

static int applnco_is_enabled(struct clk_hw *hw)
{}

static void applnco_compute_tables(struct applnco_tables *tbl)
{}

static bool applnco_div_out_of_range(unsigned int div)
{}

static u32 applnco_div_translate(struct applnco_tables *tbl, unsigned int div)
{}

static unsigned int applnco_div_translate_inv(struct applnco_tables *tbl, u32 regval)
{}

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

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

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

static int applnco_enable(struct clk_hw *hw)
{}

static void applnco_disable(struct clk_hw *hw)
{}

static const struct clk_ops applnco_ops =;

static int applnco_probe(struct platform_device *pdev)
{}

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

static struct platform_driver applnco_driver =;
module_platform_driver();

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