/* SPDX-License-Identifier: GPL-2.0-only */12#ifndef _ZL3073X_CORE_H3#define _ZL3073X_CORE_H45#include <linux/bitfield.h>6#include <linux/kthread.h>7#include <linux/list.h>8#include <linux/mutex.h>9#include <linux/types.h>1011#include "regs.h"1213struct device;14struct regmap;15struct zl3073x_dpll;1617/*18* Hardware limits for ZL3073x chip family19*/20#define ZL3073X_MAX_CHANNELS 521#define ZL3073X_NUM_REFS 1022#define ZL3073X_NUM_OUTS 1023#define ZL3073X_NUM_SYNTHS 524#define ZL3073X_NUM_INPUT_PINS ZL3073X_NUM_REFS25#define ZL3073X_NUM_OUTPUT_PINS (ZL3073X_NUM_OUTS * 2)26#define ZL3073X_NUM_PINS (ZL3073X_NUM_INPUT_PINS + \27ZL3073X_NUM_OUTPUT_PINS)2829/**30* struct zl3073x_ref - input reference invariant info31* @enabled: input reference is enabled or disabled32* @diff: true if input reference is differential33* @ffo: current fractional frequency offset34*/35struct zl3073x_ref {36bool enabled;37bool diff;38s64 ffo;39};4041/**42* struct zl3073x_out - output invariant info43* @enabled: out is enabled or disabled44* @synth: synthesizer the out is connected to45* @signal_format: out signal format46*/47struct zl3073x_out {48bool enabled;49u8 synth;50u8 signal_format;51};5253/**54* struct zl3073x_synth - synthesizer invariant info55* @freq: synthesizer frequency56* @dpll: ID of DPLL the synthesizer is driven by57* @enabled: synth is enabled or disabled58*/59struct zl3073x_synth {60u32 freq;61u8 dpll;62bool enabled;63};6465/**66* struct zl3073x_dev - zl3073x device67* @dev: pointer to device68* @regmap: regmap to access device registers69* @multiop_lock: to serialize multiple register operations70* @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* @clock_id: clock id of the device77* @phase_avg_factor: phase offset measurement averaging factor78*/79struct zl3073x_dev {80struct device *dev;81struct regmap *regmap;82struct mutex multiop_lock;8384/* Invariants */85struct zl3073x_ref ref[ZL3073X_NUM_REFS];86struct zl3073x_out out[ZL3073X_NUM_OUTS];87struct zl3073x_synth synth[ZL3073X_NUM_SYNTHS];8889/* DPLL channels */90struct list_head dplls;9192/* Monitor */93struct kthread_worker *kworker;94struct kthread_delayed_work work;9596/* Devlink parameters */97u64 clock_id;98u8 phase_avg_factor;99};100101struct zl3073x_chip_info {102const u16 *ids;103size_t num_ids;104int num_channels;105};106107extern const struct zl3073x_chip_info zl30731_chip_info;108extern const struct zl3073x_chip_info zl30732_chip_info;109extern const struct zl3073x_chip_info zl30733_chip_info;110extern const struct zl3073x_chip_info zl30734_chip_info;111extern const struct zl3073x_chip_info zl30735_chip_info;112extern const struct regmap_config zl3073x_regmap_config;113114struct zl3073x_dev *zl3073x_devm_alloc(struct device *dev);115int zl3073x_dev_probe(struct zl3073x_dev *zldev,116const struct zl3073x_chip_info *chip_info);117118int zl3073x_dev_start(struct zl3073x_dev *zldev, bool full);119void zl3073x_dev_stop(struct zl3073x_dev *zldev);120121static inline u8 zl3073x_dev_phase_avg_factor_get(struct zl3073x_dev *zldev)122{123return zldev->phase_avg_factor;124}125126int zl3073x_dev_phase_avg_factor_set(struct zl3073x_dev *zldev, u8 factor);127128/**********************129* Registers operations130**********************/131132/**133* struct zl3073x_hwreg_seq_item - HW register write sequence item134* @addr: HW register to be written135* @value: value to be written to HW register136* @mask: bitmask indicating bits to be updated137* @wait: number of ms to wait after register write138*/139struct zl3073x_hwreg_seq_item {140u32 addr;141u32 value;142u32 mask;143u32 wait;144};145146#define HWREG_SEQ_ITEM(_addr, _value, _mask, _wait) \147{ \148.addr = _addr, \149.value = FIELD_PREP_CONST(_mask, _value), \150.mask = _mask, \151.wait = _wait, \152}153154int zl3073x_mb_op(struct zl3073x_dev *zldev, unsigned int op_reg, u8 op_val,155unsigned int mask_reg, u16 mask_val);156int zl3073x_poll_zero_u8(struct zl3073x_dev *zldev, unsigned int reg, u8 mask);157int zl3073x_read_u8(struct zl3073x_dev *zldev, unsigned int reg, u8 *val);158int zl3073x_read_u16(struct zl3073x_dev *zldev, unsigned int reg, u16 *val);159int zl3073x_read_u32(struct zl3073x_dev *zldev, unsigned int reg, u32 *val);160int zl3073x_read_u48(struct zl3073x_dev *zldev, unsigned int reg, u64 *val);161int zl3073x_write_u8(struct zl3073x_dev *zldev, unsigned int reg, u8 val);162int zl3073x_write_u16(struct zl3073x_dev *zldev, unsigned int reg, u16 val);163int zl3073x_write_u32(struct zl3073x_dev *zldev, unsigned int reg, u32 val);164int zl3073x_write_u48(struct zl3073x_dev *zldev, unsigned int reg, u64 val);165int zl3073x_read_hwreg(struct zl3073x_dev *zldev, u32 addr, u32 *value);166int zl3073x_write_hwreg(struct zl3073x_dev *zldev, u32 addr, u32 value);167int zl3073x_update_hwreg(struct zl3073x_dev *zldev, u32 addr, u32 value,168u32 mask);169int zl3073x_write_hwreg_seq(struct zl3073x_dev *zldev,170const struct zl3073x_hwreg_seq_item *seq,171size_t num_items);172173/*****************174* Misc operations175*****************/176177int zl3073x_ref_freq_factorize(u32 freq, u16 *base, u16 *mult);178int zl3073x_ref_phase_offsets_update(struct zl3073x_dev *zldev, int channel);179180static inline bool181zl3073x_is_n_pin(u8 id)182{183/* P-pins ids are even while N-pins are odd */184return id & 1;185}186187static inline bool188zl3073x_is_p_pin(u8 id)189{190return !zl3073x_is_n_pin(id);191}192193/**194* zl3073x_input_pin_ref_get - get reference for given input pin195* @id: input pin id196*197* Return: reference id for the given input pin198*/199static inline u8200zl3073x_input_pin_ref_get(u8 id)201{202return id;203}204205/**206* zl3073x_output_pin_out_get - get output for the given output pin207* @id: output pin id208*209* Return: output id for the given output pin210*/211static inline u8212zl3073x_output_pin_out_get(u8 id)213{214/* Output pin pair shares the single output */215return id / 2;216}217218/**219* zl3073x_ref_ffo_get - get current fractional frequency offset220* @zldev: pointer to zl3073x device221* @index: input reference index222*223* Return: the latest measured fractional frequency offset224*/225static inline s64226zl3073x_ref_ffo_get(struct zl3073x_dev *zldev, u8 index)227{228return zldev->ref[index].ffo;229}230231/**232* zl3073x_ref_is_diff - check if the given input reference is differential233* @zldev: pointer to zl3073x device234* @index: input reference index235*236* Return: true if reference is differential, false if reference is single-ended237*/238static inline bool239zl3073x_ref_is_diff(struct zl3073x_dev *zldev, u8 index)240{241return zldev->ref[index].diff;242}243244/**245* zl3073x_ref_is_enabled - check if the given input reference is enabled246* @zldev: pointer to zl3073x device247* @index: input reference index248*249* Return: true if input refernce is enabled, false otherwise250*/251static inline bool252zl3073x_ref_is_enabled(struct zl3073x_dev *zldev, u8 index)253{254return zldev->ref[index].enabled;255}256257/**258* zl3073x_synth_dpll_get - get DPLL ID the synth is driven by259* @zldev: pointer to zl3073x device260* @index: synth index261*262* Return: ID of DPLL the given synthetizer is driven by263*/264static inline u8265zl3073x_synth_dpll_get(struct zl3073x_dev *zldev, u8 index)266{267return zldev->synth[index].dpll;268}269270/**271* zl3073x_synth_freq_get - get synth current freq272* @zldev: pointer to zl3073x device273* @index: synth index274*275* Return: frequency of given synthetizer276*/277static inline u32278zl3073x_synth_freq_get(struct zl3073x_dev *zldev, u8 index)279{280return zldev->synth[index].freq;281}282283/**284* zl3073x_synth_is_enabled - check if the given synth is enabled285* @zldev: pointer to zl3073x device286* @index: synth index287*288* Return: true if synth is enabled, false otherwise289*/290static inline bool291zl3073x_synth_is_enabled(struct zl3073x_dev *zldev, u8 index)292{293return zldev->synth[index].enabled;294}295296/**297* zl3073x_out_synth_get - get synth connected to given output298* @zldev: pointer to zl3073x device299* @index: output index300*301* Return: index of synth connected to given output.302*/303static inline u8304zl3073x_out_synth_get(struct zl3073x_dev *zldev, u8 index)305{306return zldev->out[index].synth;307}308309/**310* zl3073x_out_is_enabled - check if the given output is enabled311* @zldev: pointer to zl3073x device312* @index: output index313*314* Return: true if the output is enabled, false otherwise315*/316static inline bool317zl3073x_out_is_enabled(struct zl3073x_dev *zldev, u8 index)318{319u8 synth;320321/* Output is enabled only if associated synth is enabled */322synth = zl3073x_out_synth_get(zldev, index);323if (zl3073x_synth_is_enabled(zldev, synth))324return zldev->out[index].enabled;325326return false;327}328329/**330* zl3073x_out_signal_format_get - get output signal format331* @zldev: pointer to zl3073x device332* @index: output index333*334* Return: signal format of given output335*/336static inline u8337zl3073x_out_signal_format_get(struct zl3073x_dev *zldev, u8 index)338{339return zldev->out[index].signal_format;340}341342/**343* zl3073x_out_dpll_get - get DPLL ID the output is driven by344* @zldev: pointer to zl3073x device345* @index: output index346*347* Return: ID of DPLL the given output is driven by348*/349static inline350u8 zl3073x_out_dpll_get(struct zl3073x_dev *zldev, u8 index)351{352u8 synth;353354/* Get synthesizer connected to given output */355synth = zl3073x_out_synth_get(zldev, index);356357/* Return DPLL that drives the synth */358return zl3073x_synth_dpll_get(zldev, synth);359}360361/**362* zl3073x_out_is_diff - check if the given output is differential363* @zldev: pointer to zl3073x device364* @index: output index365*366* Return: true if output is differential, false if output is single-ended367*/368static inline bool369zl3073x_out_is_diff(struct zl3073x_dev *zldev, u8 index)370{371switch (zl3073x_out_signal_format_get(zldev, index)) {372case ZL_OUTPUT_MODE_SIGNAL_FORMAT_LVDS:373case ZL_OUTPUT_MODE_SIGNAL_FORMAT_DIFF:374case ZL_OUTPUT_MODE_SIGNAL_FORMAT_LOWVCM:375return true;376default:377break;378}379380return false;381}382383/**384* zl3073x_output_pin_is_enabled - check if the given output pin is enabled385* @zldev: pointer to zl3073x device386* @id: output pin id387*388* Checks if the output of the given output pin is enabled and also that389* its signal format also enables the given pin.390*391* Return: true if output pin is enabled, false if output pin is disabled392*/393static inline bool394zl3073x_output_pin_is_enabled(struct zl3073x_dev *zldev, u8 id)395{396u8 output = zl3073x_output_pin_out_get(id);397398/* Check if the whole output is enabled */399if (!zl3073x_out_is_enabled(zldev, output))400return false;401402/* Check signal format */403switch (zl3073x_out_signal_format_get(zldev, output)) {404case ZL_OUTPUT_MODE_SIGNAL_FORMAT_DISABLED:405/* Both output pins are disabled by signal format */406return false;407408case ZL_OUTPUT_MODE_SIGNAL_FORMAT_1P:409/* Output is one single ended P-pin output */410if (zl3073x_is_n_pin(id))411return false;412break;413case ZL_OUTPUT_MODE_SIGNAL_FORMAT_1N:414/* Output is one single ended N-pin output */415if (zl3073x_is_p_pin(id))416return false;417break;418default:419/* For other format both pins are enabled */420break;421}422423return true;424}425426#endif /* _ZL3073X_CORE_H */427428429