162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * FM Driver for Connectivity chip of Texas Instruments. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Common header for all FM driver sub-modules. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 2011 Texas Instruments 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#ifndef _FM_DRV_H 1162306a36Sopenharmony_ci#define _FM_DRV_H 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/skbuff.h> 1462306a36Sopenharmony_ci#include <linux/interrupt.h> 1562306a36Sopenharmony_ci#include <sound/core.h> 1662306a36Sopenharmony_ci#include <sound/initval.h> 1762306a36Sopenharmony_ci#include <linux/timer.h> 1862306a36Sopenharmony_ci#include <media/v4l2-ioctl.h> 1962306a36Sopenharmony_ci#include <media/v4l2-common.h> 2062306a36Sopenharmony_ci#include <media/v4l2-device.h> 2162306a36Sopenharmony_ci#include <media/v4l2-ctrls.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define FM_DRV_VERSION "0.1.1" 2462306a36Sopenharmony_ci#define FM_DRV_NAME "ti_fmdrv" 2562306a36Sopenharmony_ci#define FM_DRV_CARD_SHORT_NAME "TI FM Radio" 2662306a36Sopenharmony_ci#define FM_DRV_CARD_LONG_NAME "Texas Instruments FM Radio" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* Flag info */ 2962306a36Sopenharmony_ci#define FM_INTTASK_RUNNING 0 3062306a36Sopenharmony_ci#define FM_INTTASK_SCHEDULE_PENDING 1 3162306a36Sopenharmony_ci#define FM_FW_DW_INPROGRESS 2 3262306a36Sopenharmony_ci#define FM_CORE_READY 3 3362306a36Sopenharmony_ci#define FM_CORE_TRANSPORT_READY 4 3462306a36Sopenharmony_ci#define FM_AF_SWITCH_INPROGRESS 5 3562306a36Sopenharmony_ci#define FM_CORE_TX_XMITING 6 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#define FM_TUNE_COMPLETE 0x1 3862306a36Sopenharmony_ci#define FM_BAND_LIMIT 0x2 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define FM_DRV_TX_TIMEOUT (5*HZ) /* 5 seconds */ 4162306a36Sopenharmony_ci#define FM_DRV_RX_SEEK_TIMEOUT (20*HZ) /* 20 seconds */ 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#define fmerr(format, ...) \ 4462306a36Sopenharmony_ci printk(KERN_ERR "fmdrv: " format, ## __VA_ARGS__) 4562306a36Sopenharmony_ci#define fmwarn(format, ...) \ 4662306a36Sopenharmony_ci printk(KERN_WARNING "fmdrv: " format, ##__VA_ARGS__) 4762306a36Sopenharmony_ci#ifdef DEBUG 4862306a36Sopenharmony_ci#define fmdbg(format, ...) \ 4962306a36Sopenharmony_ci printk(KERN_DEBUG "fmdrv: " format, ## __VA_ARGS__) 5062306a36Sopenharmony_ci#else /* DEBUG */ 5162306a36Sopenharmony_ci#define fmdbg(format, ...) do {} while(0) 5262306a36Sopenharmony_ci#endif 5362306a36Sopenharmony_cienum { 5462306a36Sopenharmony_ci FM_MODE_OFF, 5562306a36Sopenharmony_ci FM_MODE_TX, 5662306a36Sopenharmony_ci FM_MODE_RX, 5762306a36Sopenharmony_ci FM_MODE_ENTRY_MAX 5862306a36Sopenharmony_ci}; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#define FM_RX_RDS_INFO_FIELD_MAX 8 /* 4 Group * 2 Bytes */ 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/* RX RDS data format */ 6362306a36Sopenharmony_cistruct fm_rdsdata_format { 6462306a36Sopenharmony_ci union { 6562306a36Sopenharmony_ci struct { 6662306a36Sopenharmony_ci u8 buff[FM_RX_RDS_INFO_FIELD_MAX]; 6762306a36Sopenharmony_ci } groupdatabuff; 6862306a36Sopenharmony_ci struct { 6962306a36Sopenharmony_ci u16 pidata; 7062306a36Sopenharmony_ci u8 blk_b[2]; 7162306a36Sopenharmony_ci u8 blk_c[2]; 7262306a36Sopenharmony_ci u8 blk_d[2]; 7362306a36Sopenharmony_ci } groupgeneral; 7462306a36Sopenharmony_ci struct { 7562306a36Sopenharmony_ci u16 pidata; 7662306a36Sopenharmony_ci u8 blk_b[2]; 7762306a36Sopenharmony_ci u8 af[2]; 7862306a36Sopenharmony_ci u8 ps[2]; 7962306a36Sopenharmony_ci } group0A; 8062306a36Sopenharmony_ci struct { 8162306a36Sopenharmony_ci u16 pi[2]; 8262306a36Sopenharmony_ci u8 blk_b[2]; 8362306a36Sopenharmony_ci u8 ps[2]; 8462306a36Sopenharmony_ci } group0B; 8562306a36Sopenharmony_ci } data; 8662306a36Sopenharmony_ci}; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci/* FM region (Europe/US, Japan) info */ 8962306a36Sopenharmony_cistruct region_info { 9062306a36Sopenharmony_ci u32 chanl_space; 9162306a36Sopenharmony_ci u32 bot_freq; 9262306a36Sopenharmony_ci u32 top_freq; 9362306a36Sopenharmony_ci u8 fm_band; 9462306a36Sopenharmony_ci}; 9562306a36Sopenharmony_cistruct fmdev; 9662306a36Sopenharmony_citypedef void (*int_handler_prototype) (struct fmdev *); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci/* FM Interrupt processing related info */ 9962306a36Sopenharmony_cistruct fm_irq { 10062306a36Sopenharmony_ci u8 stage; 10162306a36Sopenharmony_ci u16 flag; /* FM interrupt flag */ 10262306a36Sopenharmony_ci u16 mask; /* FM interrupt mask */ 10362306a36Sopenharmony_ci /* Interrupt process timeout handler */ 10462306a36Sopenharmony_ci struct timer_list timer; 10562306a36Sopenharmony_ci u8 retry; 10662306a36Sopenharmony_ci int_handler_prototype *handlers; 10762306a36Sopenharmony_ci}; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci/* RDS info */ 11062306a36Sopenharmony_cistruct fm_rds { 11162306a36Sopenharmony_ci u8 flag; /* RX RDS on/off status */ 11262306a36Sopenharmony_ci u8 last_blk_idx; /* Last received RDS block */ 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci /* RDS buffer */ 11562306a36Sopenharmony_ci wait_queue_head_t read_queue; 11662306a36Sopenharmony_ci u32 buf_size; /* Size is always multiple of 3 */ 11762306a36Sopenharmony_ci u32 wr_idx; 11862306a36Sopenharmony_ci u32 rd_idx; 11962306a36Sopenharmony_ci u8 *buff; 12062306a36Sopenharmony_ci}; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci#define FM_RDS_MAX_AF_LIST 25 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci/* 12562306a36Sopenharmony_ci * Current RX channel Alternate Frequency cache. 12662306a36Sopenharmony_ci * This info is used to switch to other freq (AF) 12762306a36Sopenharmony_ci * when current channel signal strength is below RSSI threshold. 12862306a36Sopenharmony_ci */ 12962306a36Sopenharmony_cistruct tuned_station_info { 13062306a36Sopenharmony_ci u16 picode; 13162306a36Sopenharmony_ci u32 af_cache[FM_RDS_MAX_AF_LIST]; 13262306a36Sopenharmony_ci u8 afcache_size; 13362306a36Sopenharmony_ci u8 af_list_max; 13462306a36Sopenharmony_ci}; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci/* FM RX mode info */ 13762306a36Sopenharmony_cistruct fm_rx { 13862306a36Sopenharmony_ci struct region_info region; /* Current selected band */ 13962306a36Sopenharmony_ci u32 freq; /* Current RX frquency */ 14062306a36Sopenharmony_ci u8 mute_mode; /* Current mute mode */ 14162306a36Sopenharmony_ci u8 deemphasis_mode; /* Current deemphasis mode */ 14262306a36Sopenharmony_ci /* RF dependent soft mute mode */ 14362306a36Sopenharmony_ci u8 rf_depend_mute; 14462306a36Sopenharmony_ci u16 volume; /* Current volume level */ 14562306a36Sopenharmony_ci u16 rssi_threshold; /* Current RSSI threshold level */ 14662306a36Sopenharmony_ci /* Holds the index of the current AF jump */ 14762306a36Sopenharmony_ci u8 afjump_idx; 14862306a36Sopenharmony_ci /* Will hold the frequency before the jump */ 14962306a36Sopenharmony_ci u32 freq_before_jump; 15062306a36Sopenharmony_ci u8 rds_mode; /* RDS operation mode (RDS/RDBS) */ 15162306a36Sopenharmony_ci u8 af_mode; /* Alternate frequency on/off */ 15262306a36Sopenharmony_ci struct tuned_station_info stat_info; 15362306a36Sopenharmony_ci struct fm_rds rds; 15462306a36Sopenharmony_ci}; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci#define FMTX_RDS_TXT_STR_SIZE 25 15762306a36Sopenharmony_ci/* 15862306a36Sopenharmony_ci * FM TX RDS data 15962306a36Sopenharmony_ci * 16062306a36Sopenharmony_ci * @ text_type: is the text following PS or RT 16162306a36Sopenharmony_ci * @ text: radio text string which could either be PS or RT 16262306a36Sopenharmony_ci * @ af_freq: alternate frequency for Tx 16362306a36Sopenharmony_ci * TODO: to be declared in application 16462306a36Sopenharmony_ci */ 16562306a36Sopenharmony_cistruct tx_rds { 16662306a36Sopenharmony_ci u8 text_type; 16762306a36Sopenharmony_ci u8 text[FMTX_RDS_TXT_STR_SIZE]; 16862306a36Sopenharmony_ci u8 flag; 16962306a36Sopenharmony_ci u32 af_freq; 17062306a36Sopenharmony_ci}; 17162306a36Sopenharmony_ci/* 17262306a36Sopenharmony_ci * FM TX global data 17362306a36Sopenharmony_ci * 17462306a36Sopenharmony_ci * @ pwr_lvl: Power Level of the Transmission from mixer control 17562306a36Sopenharmony_ci * @ xmit_state: Transmission state = Updated locally upon Start/Stop 17662306a36Sopenharmony_ci * @ audio_io: i2S/Analog 17762306a36Sopenharmony_ci * @ tx_frq: Transmission frequency 17862306a36Sopenharmony_ci */ 17962306a36Sopenharmony_cistruct fmtx_data { 18062306a36Sopenharmony_ci u8 pwr_lvl; 18162306a36Sopenharmony_ci u8 xmit_state; 18262306a36Sopenharmony_ci u8 audio_io; 18362306a36Sopenharmony_ci u8 region; 18462306a36Sopenharmony_ci u16 aud_mode; 18562306a36Sopenharmony_ci u32 preemph; 18662306a36Sopenharmony_ci u32 tx_frq; 18762306a36Sopenharmony_ci struct tx_rds rds; 18862306a36Sopenharmony_ci}; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci/* FM driver operation structure */ 19162306a36Sopenharmony_cistruct fmdev { 19262306a36Sopenharmony_ci struct video_device *radio_dev; /* V4L2 video device pointer */ 19362306a36Sopenharmony_ci struct v4l2_device v4l2_dev; /* V4L2 top level struct */ 19462306a36Sopenharmony_ci struct snd_card *card; /* Card which holds FM mixer controls */ 19562306a36Sopenharmony_ci u16 asci_id; 19662306a36Sopenharmony_ci spinlock_t rds_buff_lock; /* To protect access to RDS buffer */ 19762306a36Sopenharmony_ci spinlock_t resp_skb_lock; /* To protect access to received SKB */ 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci long flag; /* FM driver state machine info */ 20062306a36Sopenharmony_ci int streg_cbdata; /* status of ST registration */ 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci struct sk_buff_head rx_q; /* RX queue */ 20362306a36Sopenharmony_ci struct tasklet_struct rx_task; /* RX Tasklet */ 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci struct sk_buff_head tx_q; /* TX queue */ 20662306a36Sopenharmony_ci struct tasklet_struct tx_task; /* TX Tasklet */ 20762306a36Sopenharmony_ci unsigned long last_tx_jiffies; /* Timestamp of last pkt sent */ 20862306a36Sopenharmony_ci atomic_t tx_cnt; /* Number of packets can send at a time */ 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci struct sk_buff *resp_skb; /* Response from the chip */ 21162306a36Sopenharmony_ci /* Main task completion handler */ 21262306a36Sopenharmony_ci struct completion maintask_comp; 21362306a36Sopenharmony_ci /* Opcode of last command sent to the chip */ 21462306a36Sopenharmony_ci u8 pre_op; 21562306a36Sopenharmony_ci /* Handler used for wakeup when response packet is received */ 21662306a36Sopenharmony_ci struct completion *resp_comp; 21762306a36Sopenharmony_ci struct fm_irq irq_info; 21862306a36Sopenharmony_ci u8 curr_fmmode; /* Current FM chip mode (TX, RX, OFF) */ 21962306a36Sopenharmony_ci struct fm_rx rx; /* FM receiver info */ 22062306a36Sopenharmony_ci struct fmtx_data tx_data; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci /* V4L2 ctrl framework handler*/ 22362306a36Sopenharmony_ci struct v4l2_ctrl_handler ctrl_handler; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci /* For core assisted locking */ 22662306a36Sopenharmony_ci struct mutex mutex; 22762306a36Sopenharmony_ci}; 22862306a36Sopenharmony_ci#endif 229