/* SPDX-License-Identifier: GPL-2.0-only */12#ifndef _ZL3073X_CORE_H3#define _ZL3073X_CORE_H45#include <linux/kthread.h>6#include <linux/list.h>7#include <linux/mutex.h>8#include <linux/types.h>910#include "regs.h"1112struct device;13struct regmap;14struct zl3073x_dpll;1516/*17* Hardware limits for ZL3073x chip family18*/19#define ZL3073X_MAX_CHANNELS 520#define ZL3073X_NUM_REFS 1021#define ZL3073X_NUM_OUTS 1022#define ZL3073X_NUM_SYNTHS 523#define ZL3073X_NUM_INPUT_PINS ZL3073X_NUM_REFS24#define ZL3073X_NUM_OUTPUT_PINS (ZL3073X_NUM_OUTS * 2)25#define ZL3073X_NUM_PINS (ZL3073X_NUM_INPUT_PINS + \26ZL3073X_NUM_OUTPUT_PINS)2728/**29* struct zl3073x_ref - input reference invariant info30* @enabled: input reference is enabled or disabled31* @diff: true if input reference is differential32* @ffo: current fractional frequency offset33*/34struct zl3073x_ref {35bool enabled;36bool diff;37s64 ffo;38};3940/**41* struct zl3073x_out - output invariant info42* @enabled: out is enabled or disabled43* @synth: synthesizer the out is connected to44* @signal_format: out signal format45*/46struct zl3073x_out {47bool enabled;48u8 synth;49u8 signal_format;50};5152/**53* struct zl3073x_synth - synthesizer invariant info54* @freq: synthesizer frequency55* @dpll: ID of DPLL the synthesizer is driven by56* @enabled: synth is enabled or disabled57*/58struct zl3073x_synth {59u32 freq;60u8 dpll;61bool enabled;62};6364/**65* struct zl3073x_dev - zl3073x device66* @dev: pointer to device67* @regmap: regmap to access device registers68* @multiop_lock: to serialize multiple register operations69* @clock_id: clock id of the device70* @ref: array of input references' invariants71* @out: array of outs' invariants72* @synth: array of synths' invariants73* @dplls: list of DPLLs74* @kworker: thread for periodic work75* @work: periodic work76*/77struct zl3073x_dev {78struct device *dev;79struct regmap *regmap;80struct mutex multiop_lock;81u64 clock_id;8283/* Invariants */84struct zl3073x_ref ref[ZL3073X_NUM_REFS];85struct zl3073x_out out[ZL3073X_NUM_OUTS];86struct zl3073x_synth synth[ZL3073X_NUM_SYNTHS];8788/* DPLL channels */89struct list_head dplls;9091/* Monitor */92struct kthread_worker *kworker;93struct kthread_delayed_work work;94};9596struct zl3073x_chip_info {97const u16 *ids;98size_t num_ids;99int num_channels;100};101102extern const struct zl3073x_chip_info zl30731_chip_info;103extern const struct zl3073x_chip_info zl30732_chip_info;104extern const struct zl3073x_chip_info zl30733_chip_info;105extern const struct zl3073x_chip_info zl30734_chip_info;106extern const struct zl3073x_chip_info zl30735_chip_info;107extern const struct regmap_config zl3073x_regmap_config;108109struct zl3073x_dev *zl3073x_devm_alloc(struct device *dev);110int zl3073x_dev_probe(struct zl3073x_dev *zldev,111const struct zl3073x_chip_info *chip_info);112113/**********************114* Registers operations115**********************/116117int zl3073x_mb_op(struct zl3073x_dev *zldev, unsigned int op_reg, u8 op_val,118unsigned int mask_reg, u16 mask_val);119int zl3073x_poll_zero_u8(struct zl3073x_dev *zldev, unsigned int reg, u8 mask);120int zl3073x_read_u8(struct zl3073x_dev *zldev, unsigned int reg, u8 *val);121int zl3073x_read_u16(struct zl3073x_dev *zldev, unsigned int reg, u16 *val);122int zl3073x_read_u32(struct zl3073x_dev *zldev, unsigned int reg, u32 *val);123int zl3073x_read_u48(struct zl3073x_dev *zldev, unsigned int reg, u64 *val);124int zl3073x_write_u8(struct zl3073x_dev *zldev, unsigned int reg, u8 val);125int zl3073x_write_u16(struct zl3073x_dev *zldev, unsigned int reg, u16 val);126int zl3073x_write_u32(struct zl3073x_dev *zldev, unsigned int reg, u32 val);127int zl3073x_write_u48(struct zl3073x_dev *zldev, unsigned int reg, u64 val);128129/*****************130* Misc operations131*****************/132133int zl3073x_ref_freq_factorize(u32 freq, u16 *base, u16 *mult);134int zl3073x_ref_phase_offsets_update(struct zl3073x_dev *zldev, int channel);135136static inline bool137zl3073x_is_n_pin(u8 id)138{139/* P-pins ids are even while N-pins are odd */140return id & 1;141}142143static inline bool144zl3073x_is_p_pin(u8 id)145{146return !zl3073x_is_n_pin(id);147}148149/**150* zl3073x_input_pin_ref_get - get reference for given input pin151* @id: input pin id152*153* Return: reference id for the given input pin154*/155static inline u8156zl3073x_input_pin_ref_get(u8 id)157{158return id;159}160161/**162* zl3073x_output_pin_out_get - get output for the given output pin163* @id: output pin id164*165* Return: output id for the given output pin166*/167static inline u8168zl3073x_output_pin_out_get(u8 id)169{170/* Output pin pair shares the single output */171return id / 2;172}173174/**175* zl3073x_ref_ffo_get - get current fractional frequency offset176* @zldev: pointer to zl3073x device177* @index: input reference index178*179* Return: the latest measured fractional frequency offset180*/181static inline s64182zl3073x_ref_ffo_get(struct zl3073x_dev *zldev, u8 index)183{184return zldev->ref[index].ffo;185}186187/**188* zl3073x_ref_is_diff - check if the given input reference is differential189* @zldev: pointer to zl3073x device190* @index: input reference index191*192* Return: true if reference is differential, false if reference is single-ended193*/194static inline bool195zl3073x_ref_is_diff(struct zl3073x_dev *zldev, u8 index)196{197return zldev->ref[index].diff;198}199200/**201* zl3073x_ref_is_enabled - check if the given input reference is enabled202* @zldev: pointer to zl3073x device203* @index: input reference index204*205* Return: true if input refernce is enabled, false otherwise206*/207static inline bool208zl3073x_ref_is_enabled(struct zl3073x_dev *zldev, u8 index)209{210return zldev->ref[index].enabled;211}212213/**214* zl3073x_synth_dpll_get - get DPLL ID the synth is driven by215* @zldev: pointer to zl3073x device216* @index: synth index217*218* Return: ID of DPLL the given synthetizer is driven by219*/220static inline u8221zl3073x_synth_dpll_get(struct zl3073x_dev *zldev, u8 index)222{223return zldev->synth[index].dpll;224}225226/**227* zl3073x_synth_freq_get - get synth current freq228* @zldev: pointer to zl3073x device229* @index: synth index230*231* Return: frequency of given synthetizer232*/233static inline u32234zl3073x_synth_freq_get(struct zl3073x_dev *zldev, u8 index)235{236return zldev->synth[index].freq;237}238239/**240* zl3073x_synth_is_enabled - check if the given synth is enabled241* @zldev: pointer to zl3073x device242* @index: synth index243*244* Return: true if synth is enabled, false otherwise245*/246static inline bool247zl3073x_synth_is_enabled(struct zl3073x_dev *zldev, u8 index)248{249return zldev->synth[index].enabled;250}251252/**253* zl3073x_out_synth_get - get synth connected to given output254* @zldev: pointer to zl3073x device255* @index: output index256*257* Return: index of synth connected to given output.258*/259static inline u8260zl3073x_out_synth_get(struct zl3073x_dev *zldev, u8 index)261{262return zldev->out[index].synth;263}264265/**266* zl3073x_out_is_enabled - check if the given output is enabled267* @zldev: pointer to zl3073x device268* @index: output index269*270* Return: true if the output is enabled, false otherwise271*/272static inline bool273zl3073x_out_is_enabled(struct zl3073x_dev *zldev, u8 index)274{275u8 synth;276277/* Output is enabled only if associated synth is enabled */278synth = zl3073x_out_synth_get(zldev, index);279if (zl3073x_synth_is_enabled(zldev, synth))280return zldev->out[index].enabled;281282return false;283}284285/**286* zl3073x_out_signal_format_get - get output signal format287* @zldev: pointer to zl3073x device288* @index: output index289*290* Return: signal format of given output291*/292static inline u8293zl3073x_out_signal_format_get(struct zl3073x_dev *zldev, u8 index)294{295return zldev->out[index].signal_format;296}297298/**299* zl3073x_out_dpll_get - get DPLL ID the output is driven by300* @zldev: pointer to zl3073x device301* @index: output index302*303* Return: ID of DPLL the given output is driven by304*/305static inline306u8 zl3073x_out_dpll_get(struct zl3073x_dev *zldev, u8 index)307{308u8 synth;309310/* Get synthesizer connected to given output */311synth = zl3073x_out_synth_get(zldev, index);312313/* Return DPLL that drives the synth */314return zl3073x_synth_dpll_get(zldev, synth);315}316317/**318* zl3073x_out_is_diff - check if the given output is differential319* @zldev: pointer to zl3073x device320* @index: output index321*322* Return: true if output is differential, false if output is single-ended323*/324static inline bool325zl3073x_out_is_diff(struct zl3073x_dev *zldev, u8 index)326{327switch (zl3073x_out_signal_format_get(zldev, index)) {328case ZL_OUTPUT_MODE_SIGNAL_FORMAT_LVDS:329case ZL_OUTPUT_MODE_SIGNAL_FORMAT_DIFF:330case ZL_OUTPUT_MODE_SIGNAL_FORMAT_LOWVCM:331return true;332default:333break;334}335336return false;337}338339/**340* zl3073x_output_pin_is_enabled - check if the given output pin is enabled341* @zldev: pointer to zl3073x device342* @id: output pin id343*344* Checks if the output of the given output pin is enabled and also that345* its signal format also enables the given pin.346*347* Return: true if output pin is enabled, false if output pin is disabled348*/349static inline bool350zl3073x_output_pin_is_enabled(struct zl3073x_dev *zldev, u8 id)351{352u8 output = zl3073x_output_pin_out_get(id);353354/* Check if the whole output is enabled */355if (!zl3073x_out_is_enabled(zldev, output))356return false;357358/* Check signal format */359switch (zl3073x_out_signal_format_get(zldev, output)) {360case ZL_OUTPUT_MODE_SIGNAL_FORMAT_DISABLED:361/* Both output pins are disabled by signal format */362return false;363364case ZL_OUTPUT_MODE_SIGNAL_FORMAT_1P:365/* Output is one single ended P-pin output */366if (zl3073x_is_n_pin(id))367return false;368break;369case ZL_OUTPUT_MODE_SIGNAL_FORMAT_1N:370/* Output is one single ended N-pin output */371if (zl3073x_is_p_pin(id))372return false;373break;374default:375/* For other format both pins are enabled */376break;377}378379return true;380}381382#endif /* _ZL3073X_CORE_H */383384385