cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

si476x-core.h (15192B)


      1/* SPDX-License-Identifier: GPL-2.0-only */
      2/*
      3 * include/media/si476x-core.h -- Common definitions for si476x core
      4 * device
      5 *
      6 * Copyright (C) 2012 Innovative Converged Devices(ICD)
      7 * Copyright (C) 2013 Andrey Smirnov
      8 *
      9 * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
     10 */
     11
     12#ifndef SI476X_CORE_H
     13#define SI476X_CORE_H
     14
     15#include <linux/kfifo.h>
     16#include <linux/atomic.h>
     17#include <linux/i2c.h>
     18#include <linux/regmap.h>
     19#include <linux/mutex.h>
     20#include <linux/mfd/core.h>
     21#include <linux/videodev2.h>
     22#include <linux/regulator/consumer.h>
     23
     24#include <linux/mfd/si476x-platform.h>
     25#include <linux/mfd/si476x-reports.h>
     26
     27/* Command Timeouts */
     28#define SI476X_DEFAULT_TIMEOUT	100000
     29#define SI476X_TIMEOUT_TUNE	700000
     30#define SI476X_TIMEOUT_POWER_UP	330000
     31#define SI476X_STATUS_POLL_US	0
     32
     33/* -------------------- si476x-i2c.c ----------------------- */
     34
     35enum si476x_freq_supported_chips {
     36	SI476X_CHIP_SI4761 = 1,
     37	SI476X_CHIP_SI4764,
     38	SI476X_CHIP_SI4768,
     39};
     40
     41enum si476x_part_revisions {
     42	SI476X_REVISION_A10 = 0,
     43	SI476X_REVISION_A20 = 1,
     44	SI476X_REVISION_A30 = 2,
     45};
     46
     47enum si476x_mfd_cells {
     48	SI476X_RADIO_CELL = 0,
     49	SI476X_CODEC_CELL,
     50	SI476X_MFD_CELLS,
     51};
     52
     53/**
     54 * enum si476x_power_state - possible power state of the si476x
     55 * device.
     56 *
     57 * @SI476X_POWER_DOWN: In this state all regulators are turned off
     58 * and the reset line is pulled low. The device is completely
     59 * inactive.
     60 * @SI476X_POWER_UP_FULL: In this state all the power regulators are
     61 * turned on, reset line pulled high, IRQ line is enabled(polling is
     62 * active for polling use scenario) and device is turned on with
     63 * POWER_UP command. The device is ready to be used.
     64 * @SI476X_POWER_INCONSISTENT: This state indicates that previous
     65 * power down was inconsistent, meaning some of the regulators were
     66 * not turned down and thus use of the device, without power-cycling
     67 * is impossible.
     68 */
     69enum si476x_power_state {
     70	SI476X_POWER_DOWN		= 0,
     71	SI476X_POWER_UP_FULL		= 1,
     72	SI476X_POWER_INCONSISTENT	= 2,
     73};
     74
     75/**
     76 * struct si476x_core - internal data structure representing the
     77 * underlying "core" device which all the MFD cell-devices use.
     78 *
     79 * @client: Actual I2C client used to transfer commands to the chip.
     80 * @chip_id: Last digit of the chip model(E.g. "1" for SI4761)
     81 * @cells: MFD cell devices created by this driver.
     82 * @cmd_lock: Mutex used to serialize all the requests to the core
     83 * device. This filed should not be used directly. Instead
     84 * si476x_core_lock()/si476x_core_unlock() should be used to get
     85 * exclusive access to the "core" device.
     86 * @users: Active users counter(Used by the radio cell)
     87 * @rds_read_queue: Wait queue used to wait for RDS data.
     88 * @rds_fifo: FIFO in which all the RDS data received from the chip is
     89 * placed.
     90 * @rds_fifo_drainer: Worker that drains on-chip RDS FIFO.
     91 * @rds_drainer_is_working: Flag used for launching only one instance
     92 * of the @rds_fifo_drainer.
     93 * @rds_drainer_status_lock: Lock used to guard access to the
     94 * @rds_drainer_is_working variable.
     95 * @command: Wait queue for wainting on the command comapletion.
     96 * @cts: Clear To Send flag set upon receiving first status with CTS
     97 * set.
     98 * @tuning: Wait queue used for wainting for tune/seek comand
     99 * completion.
    100 * @stc: Similar to @cts, but for the STC bit of the status value.
    101 * @power_up_parameters: Parameters used as argument for POWER_UP
    102 * command when the device is started.
    103 * @state: Current power state of the device.
    104 * @supplues: Structure containing handles to all power supplies used
    105 * by the device (NULL ones are ignored).
    106 * @gpio_reset: GPIO pin connectet to the RSTB pin of the chip.
    107 * @pinmux: Chip's configurable pins configuration.
    108 * @diversity_mode: Chips role when functioning in diversity mode.
    109 * @status_monitor: Polling worker used in polling use case scenarion
    110 * (when IRQ is not avalible).
    111 * @revision: Chip's running firmware revision number(Used for correct
    112 * command set support).
    113 */
    114
    115struct si476x_core {
    116	struct i2c_client *client;
    117	struct regmap *regmap;
    118	int chip_id;
    119	struct mfd_cell cells[SI476X_MFD_CELLS];
    120
    121	struct mutex cmd_lock; /* for serializing fm radio operations */
    122	atomic_t users;
    123
    124	wait_queue_head_t  rds_read_queue;
    125	struct kfifo       rds_fifo;
    126	struct work_struct rds_fifo_drainer;
    127	bool               rds_drainer_is_working;
    128	struct mutex       rds_drainer_status_lock;
    129
    130	wait_queue_head_t command;
    131	atomic_t          cts;
    132
    133	wait_queue_head_t tuning;
    134	atomic_t          stc;
    135
    136	struct si476x_power_up_args power_up_parameters;
    137
    138	enum si476x_power_state power_state;
    139
    140	struct regulator_bulk_data supplies[4];
    141
    142	int gpio_reset;
    143
    144	struct si476x_pinmux pinmux;
    145	enum si476x_phase_diversity_mode diversity_mode;
    146
    147	atomic_t is_alive;
    148
    149	struct delayed_work status_monitor;
    150#define SI476X_WORK_TO_CORE(w) container_of(to_delayed_work(w),	\
    151					    struct si476x_core,	\
    152					    status_monitor)
    153
    154	int revision;
    155
    156	int rds_fifo_depth;
    157};
    158
    159static inline struct si476x_core *i2c_mfd_cell_to_core(struct device *dev)
    160{
    161	struct i2c_client *client = to_i2c_client(dev->parent);
    162	return i2c_get_clientdata(client);
    163}
    164
    165
    166/**
    167 * si476x_core_lock() - lock the core device to get an exclusive access
    168 * to it.
    169 */
    170static inline void si476x_core_lock(struct si476x_core *core)
    171{
    172	mutex_lock(&core->cmd_lock);
    173}
    174
    175/**
    176 * si476x_core_unlock() - unlock the core device to relinquish an
    177 * exclusive access to it.
    178 */
    179static inline void si476x_core_unlock(struct si476x_core *core)
    180{
    181	mutex_unlock(&core->cmd_lock);
    182}
    183
    184/* *_TUNE_FREQ family of commands accept frequency in multiples of
    185    10kHz */
    186static inline u16 hz_to_si476x(struct si476x_core *core, int freq)
    187{
    188	u16 result;
    189
    190	switch (core->power_up_parameters.func) {
    191	default:
    192	case SI476X_FUNC_FM_RECEIVER:
    193		result = freq / 10000;
    194		break;
    195	case SI476X_FUNC_AM_RECEIVER:
    196		result = freq / 1000;
    197		break;
    198	}
    199
    200	return result;
    201}
    202
    203static inline int si476x_to_hz(struct si476x_core *core, u16 freq)
    204{
    205	int result;
    206
    207	switch (core->power_up_parameters.func) {
    208	default:
    209	case SI476X_FUNC_FM_RECEIVER:
    210		result = freq * 10000;
    211		break;
    212	case SI476X_FUNC_AM_RECEIVER:
    213		result = freq * 1000;
    214		break;
    215	}
    216
    217	return result;
    218}
    219
    220/* Since the V4L2_TUNER_CAP_LOW flag is supplied, V4L2 subsystem
    221 * mesures frequency in 62.5 Hz units */
    222
    223static inline int hz_to_v4l2(int freq)
    224{
    225	return (freq * 10) / 625;
    226}
    227
    228static inline int v4l2_to_hz(int freq)
    229{
    230	return (freq * 625) / 10;
    231}
    232
    233static inline u16 v4l2_to_si476x(struct si476x_core *core, int freq)
    234{
    235	return hz_to_si476x(core, v4l2_to_hz(freq));
    236}
    237
    238static inline int si476x_to_v4l2(struct si476x_core *core, u16 freq)
    239{
    240	return hz_to_v4l2(si476x_to_hz(core, freq));
    241}
    242
    243
    244
    245/**
    246 * struct si476x_func_info - structure containing result of the
    247 * FUNC_INFO command.
    248 *
    249 * @firmware.major: Firmware major number.
    250 * @firmware.minor[...]: Firmware minor numbers.
    251 * @patch_id:
    252 * @func: Mode tuner is working in.
    253 */
    254struct si476x_func_info {
    255	struct {
    256		u8 major, minor[2];
    257	} firmware;
    258	u16 patch_id;
    259	enum si476x_func func;
    260};
    261
    262/**
    263 * struct si476x_power_down_args - structure used to pass parameters
    264 * to POWER_DOWN command
    265 *
    266 * @xosc: true - Power down, but leav oscillator running.
    267 *        false - Full power down.
    268 */
    269struct si476x_power_down_args {
    270	bool xosc;
    271};
    272
    273/**
    274 * enum si476x_tunemode - enum representing possible tune modes for
    275 * the chip.
    276 * @SI476X_TM_VALIDATED_NORMAL_TUNE: Unconditionally stay on the new
    277 * channel after tune, tune status is valid.
    278 * @SI476X_TM_INVALIDATED_FAST_TUNE: Unconditionally stay in the new
    279 * channel after tune, tune status invalid.
    280 * @SI476X_TM_VALIDATED_AF_TUNE: Jump back to previous channel if
    281 * metric thresholds are not met.
    282 * @SI476X_TM_VALIDATED_AF_CHECK: Unconditionally jump back to the
    283 * previous channel.
    284 */
    285enum si476x_tunemode {
    286	SI476X_TM_VALIDATED_NORMAL_TUNE = 0,
    287	SI476X_TM_INVALIDATED_FAST_TUNE = 1,
    288	SI476X_TM_VALIDATED_AF_TUNE     = 2,
    289	SI476X_TM_VALIDATED_AF_CHECK    = 3,
    290};
    291
    292/**
    293 * enum si476x_smoothmetrics - enum containing the possible setting fo
    294 * audio transitioning of the chip
    295 * @SI476X_SM_INITIALIZE_AUDIO: Initialize audio state to match this
    296 * new channel
    297 * @SI476X_SM_TRANSITION_AUDIO: Transition audio state from previous
    298 * channel values to the new values
    299 */
    300enum si476x_smoothmetrics {
    301	SI476X_SM_INITIALIZE_AUDIO = 0,
    302	SI476X_SM_TRANSITION_AUDIO = 1,
    303};
    304
    305/**
    306 * struct si476x_rds_status_report - the structure representing the
    307 * response to 'FM_RD_STATUS' command
    308 * @rdstpptyint: Traffic program flag(TP) and/or program type(PTY)
    309 * code has changed.
    310 * @rdspiint: Program identification(PI) code has changed.
    311 * @rdssyncint: RDS synchronization has changed.
    312 * @rdsfifoint: RDS was received and the RDS FIFO has at least
    313 * 'FM_RDS_INTERRUPT_FIFO_COUNT' elements in it.
    314 * @tpptyvalid: TP flag and PTY code are valid falg.
    315 * @pivalid: PI code is valid flag.
    316 * @rdssync: RDS is currently synchronized.
    317 * @rdsfifolost: On or more RDS groups have been lost/discarded flag.
    318 * @tp: Current channel's TP flag.
    319 * @pty: Current channel's PTY code.
    320 * @pi: Current channel's PI code.
    321 * @rdsfifoused: Number of blocks remaining in the RDS FIFO (0 if
    322 * empty).
    323 */
    324struct si476x_rds_status_report {
    325	bool rdstpptyint, rdspiint, rdssyncint, rdsfifoint;
    326	bool tpptyvalid, pivalid, rdssync, rdsfifolost;
    327	bool tp;
    328
    329	u8 pty;
    330	u16 pi;
    331
    332	u8 rdsfifoused;
    333	u8 ble[4];
    334
    335	struct v4l2_rds_data rds[4];
    336};
    337
    338struct si476x_rsq_status_args {
    339	bool primary;
    340	bool rsqack;
    341	bool attune;
    342	bool cancel;
    343	bool stcack;
    344};
    345
    346enum si476x_injside {
    347	SI476X_INJSIDE_AUTO	= 0,
    348	SI476X_INJSIDE_LOW	= 1,
    349	SI476X_INJSIDE_HIGH	= 2,
    350};
    351
    352struct si476x_tune_freq_args {
    353	bool zifsr;
    354	bool hd;
    355	enum si476x_injside injside;
    356	int freq;
    357	enum si476x_tunemode tunemode;
    358	enum si476x_smoothmetrics smoothmetrics;
    359	int antcap;
    360};
    361
    362int  si476x_core_stop(struct si476x_core *, bool);
    363int  si476x_core_start(struct si476x_core *, bool);
    364int  si476x_core_set_power_state(struct si476x_core *, enum si476x_power_state);
    365bool si476x_core_has_am(struct si476x_core *);
    366bool si476x_core_has_diversity(struct si476x_core *);
    367bool si476x_core_is_a_secondary_tuner(struct si476x_core *);
    368bool si476x_core_is_a_primary_tuner(struct si476x_core *);
    369bool si476x_core_is_in_am_receiver_mode(struct si476x_core *core);
    370bool si476x_core_is_powered_up(struct si476x_core *core);
    371
    372enum si476x_i2c_type {
    373	SI476X_I2C_SEND,
    374	SI476X_I2C_RECV
    375};
    376
    377int si476x_core_i2c_xfer(struct si476x_core *,
    378			 enum si476x_i2c_type,
    379			 char *, int);
    380
    381
    382/* -------------------- si476x-cmd.c ----------------------- */
    383
    384int si476x_core_cmd_func_info(struct si476x_core *, struct si476x_func_info *);
    385int si476x_core_cmd_set_property(struct si476x_core *, u16, u16);
    386int si476x_core_cmd_get_property(struct si476x_core *, u16);
    387int si476x_core_cmd_dig_audio_pin_cfg(struct si476x_core *,
    388				      enum si476x_dclk_config,
    389				      enum si476x_dfs_config,
    390				      enum si476x_dout_config,
    391				      enum si476x_xout_config);
    392int si476x_core_cmd_zif_pin_cfg(struct si476x_core *,
    393				enum si476x_iqclk_config,
    394				enum si476x_iqfs_config,
    395				enum si476x_iout_config,
    396				enum si476x_qout_config);
    397int si476x_core_cmd_ic_link_gpo_ctl_pin_cfg(struct si476x_core *,
    398					    enum si476x_icin_config,
    399					    enum si476x_icip_config,
    400					    enum si476x_icon_config,
    401					    enum si476x_icop_config);
    402int si476x_core_cmd_ana_audio_pin_cfg(struct si476x_core *,
    403				      enum si476x_lrout_config);
    404int si476x_core_cmd_intb_pin_cfg(struct si476x_core *, enum si476x_intb_config,
    405				 enum si476x_a1_config);
    406int si476x_core_cmd_fm_seek_start(struct si476x_core *, bool, bool);
    407int si476x_core_cmd_am_seek_start(struct si476x_core *, bool, bool);
    408int si476x_core_cmd_fm_rds_status(struct si476x_core *, bool, bool, bool,
    409				  struct si476x_rds_status_report *);
    410int si476x_core_cmd_fm_rds_blockcount(struct si476x_core *, bool,
    411				      struct si476x_rds_blockcount_report *);
    412int si476x_core_cmd_fm_tune_freq(struct si476x_core *,
    413				 struct si476x_tune_freq_args *);
    414int si476x_core_cmd_am_tune_freq(struct si476x_core *,
    415				 struct si476x_tune_freq_args *);
    416int si476x_core_cmd_am_rsq_status(struct si476x_core *,
    417				  struct si476x_rsq_status_args *,
    418				  struct si476x_rsq_status_report *);
    419int si476x_core_cmd_fm_rsq_status(struct si476x_core *,
    420				  struct si476x_rsq_status_args *,
    421				  struct si476x_rsq_status_report *);
    422int si476x_core_cmd_power_up(struct si476x_core *,
    423			     struct si476x_power_up_args *);
    424int si476x_core_cmd_power_down(struct si476x_core *,
    425			       struct si476x_power_down_args *);
    426int si476x_core_cmd_fm_phase_div_status(struct si476x_core *);
    427int si476x_core_cmd_fm_phase_diversity(struct si476x_core *,
    428				       enum si476x_phase_diversity_mode);
    429
    430int si476x_core_cmd_fm_acf_status(struct si476x_core *,
    431				  struct si476x_acf_status_report *);
    432int si476x_core_cmd_am_acf_status(struct si476x_core *,
    433				  struct si476x_acf_status_report *);
    434int si476x_core_cmd_agc_status(struct si476x_core *,
    435			       struct si476x_agc_status_report *);
    436
    437enum si476x_power_grid_type {
    438	SI476X_POWER_GRID_50HZ = 0,
    439	SI476X_POWER_GRID_60HZ,
    440};
    441
    442/* Properties  */
    443
    444enum si476x_interrupt_flags {
    445	SI476X_STCIEN = (1 << 0),
    446	SI476X_ACFIEN = (1 << 1),
    447	SI476X_RDSIEN = (1 << 2),
    448	SI476X_RSQIEN = (1 << 3),
    449
    450	SI476X_ERRIEN = (1 << 6),
    451	SI476X_CTSIEN = (1 << 7),
    452
    453	SI476X_STCREP = (1 << 8),
    454	SI476X_ACFREP = (1 << 9),
    455	SI476X_RDSREP = (1 << 10),
    456	SI476X_RSQREP = (1 << 11),
    457};
    458
    459enum si476x_rdsint_sources {
    460	SI476X_RDSTPPTY = (1 << 4),
    461	SI476X_RDSPI    = (1 << 3),
    462	SI476X_RDSSYNC	= (1 << 1),
    463	SI476X_RDSRECV	= (1 << 0),
    464};
    465
    466enum si476x_status_response_bits {
    467	SI476X_CTS	  = (1 << 7),
    468	SI476X_ERR	  = (1 << 6),
    469	/* Status response for WB receiver */
    470	SI476X_WB_ASQ_INT = (1 << 4),
    471	SI476X_RSQ_INT    = (1 << 3),
    472	/* Status response for FM receiver */
    473	SI476X_FM_RDS_INT = (1 << 2),
    474	SI476X_ACF_INT    = (1 << 1),
    475	SI476X_STC_INT    = (1 << 0),
    476};
    477
    478/* -------------------- si476x-prop.c ----------------------- */
    479
    480enum si476x_common_receiver_properties {
    481	SI476X_PROP_INT_CTL_ENABLE			= 0x0000,
    482	SI476X_PROP_DIGITAL_IO_INPUT_SAMPLE_RATE	= 0x0200,
    483	SI476X_PROP_DIGITAL_IO_INPUT_FORMAT		= 0x0201,
    484	SI476X_PROP_DIGITAL_IO_OUTPUT_SAMPLE_RATE	= 0x0202,
    485	SI476X_PROP_DIGITAL_IO_OUTPUT_FORMAT		= 0x0203,
    486
    487	SI476X_PROP_SEEK_BAND_BOTTOM			= 0x1100,
    488	SI476X_PROP_SEEK_BAND_TOP			= 0x1101,
    489	SI476X_PROP_SEEK_FREQUENCY_SPACING		= 0x1102,
    490
    491	SI476X_PROP_VALID_MAX_TUNE_ERROR		= 0x2000,
    492	SI476X_PROP_VALID_SNR_THRESHOLD			= 0x2003,
    493	SI476X_PROP_VALID_RSSI_THRESHOLD		= 0x2004,
    494};
    495
    496enum si476x_am_receiver_properties {
    497	SI476X_PROP_AUDIO_PWR_LINE_FILTER		= 0x0303,
    498};
    499
    500enum si476x_fm_receiver_properties {
    501	SI476X_PROP_AUDIO_DEEMPHASIS			= 0x0302,
    502
    503	SI476X_PROP_FM_RDS_INTERRUPT_SOURCE		= 0x4000,
    504	SI476X_PROP_FM_RDS_INTERRUPT_FIFO_COUNT		= 0x4001,
    505	SI476X_PROP_FM_RDS_CONFIG			= 0x4002,
    506};
    507
    508enum si476x_prop_audio_pwr_line_filter_bits {
    509	SI476X_PROP_PWR_HARMONICS_MASK	= 0x001f,
    510	SI476X_PROP_PWR_GRID_MASK	= 0x0100,
    511	SI476X_PROP_PWR_ENABLE_MASK	= 0x0200,
    512	SI476X_PROP_PWR_GRID_50HZ	= 0x0000,
    513	SI476X_PROP_PWR_GRID_60HZ	= 0x0100,
    514};
    515
    516enum si476x_prop_fm_rds_config_bits {
    517	SI476X_PROP_RDSEN_MASK	= 0x1,
    518	SI476X_PROP_RDSEN	= 0x1,
    519};
    520
    521
    522struct regmap *devm_regmap_init_si476x(struct si476x_core *);
    523
    524#endif	/* SI476X_CORE_H */