aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk/idt/clk-idt8t49n24x-core.h
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk/idt/clk-idt8t49n24x-core.h')
-rw-r--r--drivers/clk/idt/clk-idt8t49n24x-core.h272
1 files changed, 272 insertions, 0 deletions
diff --git a/drivers/clk/idt/clk-idt8t49n24x-core.h b/drivers/clk/idt/clk-idt8t49n24x-core.h
new file mode 100644
index 000000000000..247ec070c621
--- /dev/null
+++ b/drivers/clk/idt/clk-idt8t49n24x-core.h
@@ -0,0 +1,272 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* clk-idt8t49n24x-core.h - Program 8T49N24x settings via I2C (common code)
+ *
+ * Copyright (C) 2018, Integrated Device Technology, Inc. <david.cater@idt.com>
+ *
+ * See https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html
+ * This program is distributed "AS IS" and WITHOUT ANY WARRANTY;
+ * including the implied warranties of MERCHANTABILITY, FITNESS FOR
+ * A PARTICULAR PURPOSE, or NON-INFRINGEMENT.
+ */
+
+#ifndef __IDT_CLK_IDT8T49N24X_CORE_H_
+#define __IDT_CLK_IDT8T49N24X_CORE_H_
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+
+/*
+ * The configurations in the settings file have 0x317 registers (last offset
+ * is 0x316).
+ */
+#define NUM_CONFIG_REGISTERS 0x317
+#define NUM_INPUTS 2
+#define NUM_OUTPUTS 4
+#define DEBUGFS_BUFFER_LENGTH 200
+#define WRITE_BLOCK_SIZE 32
+
+/* Non output-specific registers */
+#define IDT24x_REG_DBL_DIS 0x6C
+#define IDT24x_REG_DBL_DIS_MASK 0x01
+#define IDT24x_REG_DSM_INT_8 0x25
+#define IDT24x_REG_DSM_INT_8_MASK 0x01
+#define IDT24x_REG_DSM_INT_7_0 0x26
+#define IDT24x_REG_DSMFRAC_20_16 0x28
+#define IDT24x_REG_DSMFRAC_20_16_MASK 0x1F
+#define IDT24x_REG_DSMFRAC_15_8 0x29
+#define IDT24x_REG_DSMFRAC_7_0 0x2A
+#define IDT24x_REG_OUTEN 0x39
+#define IDT24x_REG_OUTMODE0_1 0x3E
+#define IDT24x_REG_OUTMODE2_3 0x3D
+#define IDT24x_REG_Q_DIS 0x6F
+
+/* Q0 */
+#define IDT24x_REG_OUTEN0_MASK 0x01
+#define IDT24x_REG_OUTMODE0_MASK 0x0E
+#define IDT24x_REG_Q0_DIS_MASK 0x01
+#define IDT24x_REG_NS1_Q0 0x3F
+#define IDT24x_REG_NS1_Q0_MASK 0x03
+#define IDT24x_REG_NS2_Q0_15_8 0x40
+#define IDT24x_REG_NS2_Q0_7_0 0x41
+
+/* Q1 */
+#define IDT24x_REG_OUTEN1_MASK 0x02
+#define IDT24x_REG_OUTMODE1_MASK 0xE0
+#define IDT24x_REG_Q1_DIS_MASK 0x02
+#define IDT24x_REG_N_Q1_17_16 0x42
+#define IDT24x_REG_N_Q1_17_16_MASK 0x03
+#define IDT24x_REG_N_Q1_15_8 0x43
+#define IDT24x_REG_N_Q1_7_0 0x44
+#define IDT24x_REG_NFRAC_Q1_27_24 0x57
+#define IDT24x_REG_NFRAC_Q1_27_24_MASK 0x0F
+#define IDT24x_REG_NFRAC_Q1_23_16 0x58
+#define IDT24x_REG_NFRAC_Q1_15_8 0x59
+#define IDT24x_REG_NFRAC_Q1_7_0 0x5A
+
+/* Q2 */
+#define IDT24x_REG_OUTEN2_MASK 0x04
+#define IDT24x_REG_OUTMODE2_MASK 0x0E
+#define IDT24x_REG_Q2_DIS_MASK 0x04
+#define IDT24x_REG_N_Q2_17_16 0x45
+#define IDT24x_REG_N_Q2_17_16_MASK 0x03
+#define IDT24x_REG_N_Q2_15_8 0x46
+#define IDT24x_REG_N_Q2_7_0 0x47
+#define IDT24x_REG_NFRAC_Q2_27_24 0x5B
+#define IDT24x_REG_NFRAC_Q2_27_24_MASK 0x0F
+#define IDT24x_REG_NFRAC_Q2_23_16 0x5C
+#define IDT24x_REG_NFRAC_Q2_15_8 0x5D
+#define IDT24x_REG_NFRAC_Q2_7_0 0x5E
+
+/* Q3 */
+#define IDT24x_REG_OUTEN3_MASK 0x08
+#define IDT24x_REG_OUTMODE3_MASK 0xE0
+#define IDT24x_REG_Q3_DIS_MASK 0x08
+#define IDT24x_REG_N_Q3_17_16 0x48
+#define IDT24x_REG_N_Q3_17_16_MASK 0x03
+#define IDT24x_REG_N_Q3_15_8 0x49
+#define IDT24x_REG_N_Q3_7_0 0x4A
+#define IDT24x_REG_NFRAC_Q3_27_24 0x5F
+#define IDT24x_REG_NFRAC_Q3_27_24_MASK 0x0F
+#define IDT24x_REG_NFRAC_Q3_23_16 0x60
+#define IDT24x_REG_NFRAC_Q3_15_8 0x61
+#define IDT24x_REG_NFRAC_Q3_7_0 0x62
+
+/**
+ * struct idt24x_output - device output information
+ * @hw: hw registration info for this specific output clcok. This gets
+ * passed as an argument to CCF api calls (e.g., set_rate).
+ * container_of can then be used to get the reference to this
+ * struct.
+ * @chip: store a reference to the parent device structure. container_of
+ * cannot be used to get to the parent device structure from
+ * idt24x_output, because clk_idt24x_chip contains an array of
+ * output structs (for future enhancements to support devices
+ * with different numbers of output clocks).
+ * @index: identifies output on the chip; used in debug statements
+ * @requested: requested output clock frequency (in Hz)
+ * @actual: actual output clock frequency (in Hz). Will only be set after
+ * successful update of the device.
+ * @debug_freq: stores value for debugfs file. Use this instead of requested
+ * struct var because debugfs expects u64, not u32.
+ */
+struct idt24x_output {
+ struct clk_hw hw;
+ struct clk_idt24x_chip *chip;
+ u8 index;
+ u32 requested;
+ u32 actual;
+ u64 debug_freq;
+};
+
+/**
+ * struct idt24x_dividers - output dividers
+ * @dsmint: int component of feedback divider for VCO (2-stage divider)
+ * @dsmfrac: fractional component of feedback divider for VCO
+ * @ns1_q0: ns1 divider component for Q0
+ * @ns2_q0: ns2 divider component for Q0
+ * @nint: int divider component for Q1-3
+ * @nfrac: fractional divider component for Q1-3
+ */
+struct idt24x_dividers {
+ u16 dsmint;
+ u32 dsmfrac;
+
+ u8 ns1_q0;
+ u16 ns2_q0;
+
+ u32 nint[3];
+ u32 nfrac[3];
+};
+
+/**
+ * struct clk_idt24x_chip - device info for chip
+ * @regmap: register map used to perform i2c writes to the chip
+ * @i2c_client: i2c_client struct passed to probe
+ * @min_freq: min frequency for this chip
+ * @max_freq: max frequency for this chip
+ * @settings: filled in if full register map is specified in the DT
+ * @has_settings: true if settings array is valid
+ * @input_clk: ptr to input clock specified in DT
+ * @input_clk_num: which input clock was specified. 0-based. A value of
+ * NUM_INPUTS indicates that a XTAL is used as the input.
+ * @input_clk_nb: notification support (if input clk changes)
+ * @input_clk_freq: current freq of input_clk
+ * @doubler_disabled: whether input doubler is enabled. This value is read
+ * from the hw on probe (in case it is set in @settings).
+ * @clk: array of outputs. One entry per output supported by the
+ * chip. Frequencies requested via the ccf api will be
+ * recorded in this array.
+ * @reg_dsm_int_8: record current value from hw to avoid modifying
+ * when writing register values
+ * @reg_dsm_frac_20_16: record current value
+ * @reg_out_en_x: record current value
+ * @reg_out_mode_0_1: record current value
+ * @reg_out_mode_2_3: record current value
+ * @reg_qx_dis: record current value
+ * @reg_ns1_q0: record current value
+ * @reg_n_qx_17_16: record current value
+ * @reg_nfrac_qx_27_24: record current value
+ * @divs: output divider values for all outputs
+ * @debugfs_dirroot: debugfs support
+ * @debugfs_fileaction: debugfs support
+ * @debugfs_filei2c: debugfs support
+ * @debugfs_map: debugfs support
+ * @dbg_cache: debugfs support
+ * @debugfs_fileqfreq: debugfs support
+ */
+struct clk_idt24x_chip {
+ struct regmap *regmap;
+ struct i2c_client *i2c_client;
+
+ u32 min_freq;
+ u32 max_freq;
+
+ u8 settings[NUM_CONFIG_REGISTERS];
+
+ bool has_settings;
+
+ struct clk *input_clk;
+ int input_clk_num;
+ struct notifier_block input_clk_nb;
+ u32 input_clk_freq;
+
+ bool doubler_disabled;
+
+ struct idt24x_output clk[NUM_OUTPUTS];
+
+ unsigned int reg_dsm_int_8;
+ unsigned int reg_dsm_frac_20_16;
+ unsigned int reg_out_en_x;
+ unsigned int reg_out_mode_0_1;
+ unsigned int reg_out_mode_2_3;
+ unsigned int reg_qx_dis;
+ unsigned int reg_ns1_q0;
+ unsigned int reg_n_qx_17_16[3];
+ unsigned int reg_nfrac_qx_27_24[3];
+
+ struct idt24x_dividers divs;
+
+ struct dentry *debugfs_dirroot, *debugfs_fileaction, *debugfs_filei2c,
+ *debugfs_map;
+ char dbg_cache[DEBUGFS_BUFFER_LENGTH];
+ struct dentry *debugfs_fileqfreq[4];
+};
+
+#define to_idt24x_output(_hw) \
+ container_of(_hw, struct idt24x_output, hw)
+#define to_clk_idt24x_from_client(_client) \
+ container_of(_client, struct clk_idt24x_chip, i2c_client)
+#define to_clk_idt24x_from_nb(_nb) \
+ container_of(_nb, struct clk_idt24x_chip, input_clk_nb)
+
+/**
+ * struct clk_register_offsets - register offsets for current context
+ * @oe_offset: offset for current output enable and mode
+ * @oe_mask: mask for current output enable
+ * @dis_mask: mask for current output disable
+ * @n_17_16_offset: offset for current output int divider (bits 17:16)
+ * @n_17_16_mask: mask for current output int divider (bits 17:16)
+ * @n_15_8_offset: offset for current output int divider (bits 15:8)
+ * @n_7_0_offset: offset for current output int divider (bits 7:0)
+ * @nfrac_27_24_offset: offset for current output frac divider (bits 27:24)
+ * @nfrac_27_24_mask: mask for current output frac divider (bits 27:24)
+ * @nfrac_23_16_offset: offset for current output frac divider (bits 23:16)
+ * @nfrac_15_8_offset: offset for current output frac divider (bits 15:8)
+ * @nfrac_7_0_offset: offset for current output frac divider (bits 7:0)
+ * @ns1_offset: offset for stage 1 div for output Q0
+ * @ns1_offset_mask: mask for stage 1 div for output Q0
+ * @ns2_15_8_offset: offset for stage 2 div for output Q0 (bits 15:8)
+ * @ns2_7_0_offset: offset for stage 2 div for output Q0 (bits 7:0)
+ */
+struct clk_register_offsets {
+ u16 oe_offset;
+ u8 oe_mask;
+ u8 dis_mask;
+
+ u16 n_17_16_offset;
+ u8 n_17_16_mask;
+ u16 n_15_8_offset;
+ u16 n_7_0_offset;
+ u16 nfrac_27_24_offset;
+ u8 nfrac_27_24_mask;
+ u16 nfrac_23_16_offset;
+ u16 nfrac_15_8_offset;
+ u16 nfrac_7_0_offset;
+
+ u16 ns1_offset;
+ u8 ns1_offset_mask;
+ u16 ns2_15_8_offset;
+ u16 ns2_7_0_offset;
+};
+
+int bits_to_shift(unsigned int mask);
+int i2cwritebulk(
+ struct i2c_client *client, struct regmap *map,
+ unsigned int reg, u8 val[], size_t val_count);
+int idt24x_get_offsets(
+ u8 output_num,
+ struct clk_register_offsets *offsets);
+int idt24x_set_frequency(struct clk_idt24x_chip *chip);
+
+#endif /* __IDT_CLK_IDT8T49N24X_CORE_H_ */