/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #ifndef __RADIO_SILABS_H #define __RADIO_SILABS_H #include #include #define WRITE_REG_NUM 8 #define READ_REG_NUM 16 #define FMDBG(fmt, args...) pr_debug("silabs_radio: " fmt, ##args) #define FMDERR(fmt, args...) pr_err("silabs_radio: " fmt, ##args) /* For bounds checking. */ const unsigned char MIN_RDS_STD = 0x00; const unsigned char MAX_RDS_STD = 0x02; const unsigned char MIN_SRCH_MODE = 0x00; const unsigned char MAX_SRCH_MODE = 0x02; /* Standard buffer size */ #define STD_BUF_SIZE (256) /* Search direction */ #define SRCH_DIR_UP (1) #define SRCH_DIR_DOWN (0) #define WAIT_TIMEOUT_MSEC 2000 #define SILABS_DELAY_MSEC 10 #define CTS_RETRY_COUNT 10 #define RADIO_NR -1 #define TURNING_ON 1 #define TURNING_OFF 0 #define CH_SPACING_200 200 #define CH_SPACING_100 100 #define CH_SPACING_50 50 /* to distinguish between seek, tune during STC int. */ #define NO_SEEK_TUNE_PENDING 0 #define TUNE_PENDING 1 #define SEEK_PENDING 2 #define SCAN_PENDING 3 #define WRAP_ENABLE 1 #define WRAP_DISABLE 0 #define VALID_MASK 0x01 /* it will check whether UPPER band reached or not */ #define BLTF_MASK 0x80 #define SAMPLE_RATE_48_KHZ 0xBB80 #define MIN_DWELL_TIME 0x00 #define MAX_DWELL_TIME 0x0F #define START_SCAN 1 #define GET_MSB(x)((x >> 8) & 0xFF) #define GET_LSB(x)((x) & 0xFF) /* * When tuning, we need to divide freq by TUNE_STEP_SIZE * before sending it to chip */ #define TUNE_STEP_SIZE 10 #define TUNE_PARAM 16 #define OFFSET_OF_GRP_TYP 11 #define RDS_INT_BIT 0x01 #define FIFO_CNT_16 0x10 #define UNCORRECTABLE_RDS_EN 0xFF01 #define NO_OF_RDS_BLKS 4 #define MSB_OF_BLK_0 4 #define LSB_OF_BLK_0 5 #define MSB_OF_BLK_1 6 #define LSB_OF_BLK_1 7 #define MSB_OF_BLK_2 8 #define LSB_OF_BLK_2 9 #define MSB_OF_BLK_3 10 #define LSB_OF_BLK_3 11 #define MAX_RT_LEN 64 #define END_OF_RT 0x0d #define MAX_PS_LEN 8 #define OFFSET_OF_PS 5 #define PS_VALIDATE_LIMIT 2 #define RT_VALIDATE_LIMIT 2 #define RDS_CMD_LEN 3 #define RDS_RSP_LEN 13 #define PS_EVT_DATA_LEN (MAX_PS_LEN + OFFSET_OF_PS) #define NO_OF_PS 1 #define OFFSET_OF_RT 5 #define OFFSET_OF_PTY 5 #define MAX_LEN_2B_GRP_RT 32 #define CNT_FOR_2A_GRP_RT 4 #define CNT_FOR_2B_GRP_RT 2 #define PS_MASK 0x3 #define PTY_MASK 0x1F #define NO_OF_CHARS_IN_EACH_ADD 2 #define MIN_SNR 0 #define MAX_SNR 127 #define MIN_RSSI 0 #define MAX_RSSI 127 #define MIN_RDS_FIFO_CNT 0 #define MAX_RDS_FIFO_CNT 25 #define DEFAULT_SNR_TH 2 #define DEFAULT_RSSI_TH 7 #define DEFAULT_AF_RSSI_LOW_TH 25 #define NO_OF_AF_IN_GRP 2 #define MAX_NO_OF_AF 25 #define MAX_AF_LIST_SIZE (MAX_NO_OF_AF * 4) /* 4 bytes per freq */ #define GET_AF_EVT_LEN(x) (7 + x*4) #define GET_AF_LIST_LEN(x) (x*4) #define MIN_AF_FREQ_CODE 1 #define MAX_AF_FREQ_CODE 204 /* 25 AFs supported for a freq. 224 means 1 AF. 225 means 2 AFs and so on */ #define NO_AF_CNT_CODE 224 #define MIN_AF_CNT_CODE 225 #define MAX_AF_CNT_CODE 249 #define AF_WAIT_SEC 10 #define MAX_AF_WAIT_SEC 255 #define AF_PI_WAIT_TIME 50 /* 50*100msec = 5sec */ /* freqs are divided by 10. */ #define SCALE_AF_CODE_TO_FREQ_KHZ(x) (87500 + (x*100)) /* commands */ #define POWER_UP_CMD 0x01 #define GET_REV_CMD 0x10 #define POWER_DOWN_CMD 0x11 #define SET_PROPERTY_CMD 0x12 #define GET_PROPERTY_CMD 0x13 #define GET_INT_STATUS_CMD 0x14 #define PATCH_ARGS_CMD 0x15 #define PATCH_DATA_CMD 0x16 #define FM_TUNE_FREQ_CMD 0x20 #define FM_SEEK_START_CMD 0x21 #define FM_TUNE_STATUS_CMD 0x22 #define FM_RSQ_STATUS_CMD 0x23 #define FM_RDS_STATUS_CMD 0x24 #define FM_AGC_STATUS_CMD 0x27 #define FM_AGC_OVERRIDE_CMD 0x28 #define GPIO_CTL_CMD 0x80 #define GPIO_SET_CMD 0x81 /* properties */ #define GPO_IEN_PROP 0x0001 #define DIGITAL_OUTPUT_FORMAT_PROP 0x0102 #define DIGITAL_OUTPUT_SAMPLE_RATE_PROP 0x0104 #define REFCLK_FREQ_PROP 0x0201 #define REFCLK_PRESCALE_PROP 0x0202 #define FM_DEEMPHASIS_PROP 0x1100 #define FM_CHANNEL_FILTER_PROP 0x1102 #define FM_ANTENNA_INPUT_PROP 0x1107 #define FM_RSQ_INT_SOURCE_PROP 0x1200 #define FM_RSQ_RSSI_LO_THRESHOLD_PROP 0x1204 #define FM_SEEK_BAND_BOTTOM_PROP 0x1400 #define FM_SEEK_BAND_TOP_PROP 0x1401 #define FM_SEEK_FREQ_SPACING_PROP 0x1402 #define FM_SEEK_TUNE_SNR_THRESHOLD_PROP 0x1403 #define FM_SEEK_TUNE_RSSI_THRESHOLD_PROP 0x1404 #define FM_RDS_INT_SOURCE_PROP 0x1500 #define FM_RDS_INT_FIFO_COUNT_PROP 0x1501 #define FM_RDS_CONFIG_PROP 0x1502 #define RX_HARD_MUTE_PROP 0x4001 /* BIT MASKS */ #define ENABLE_CTS_INT_MASK (1 << 7) #define ENABLE_GPO2_INT_MASK (1 << 6) #define PATCH_ENABLE_MASK (1 << 5) /* to use clock present on daughter card or MSM's */ #define CLOCK_ENABLE_MASK (1 << 4) #define FUNC_QUERY_LIB_ID_MASK 15 #define CANCEL_SEEK_MASK (1 << 1) #define INTACK_MASK 1 #define SEEK_WRAP_MASK (1 << 2) #define SEEK_UP_MASK (1 << 3) /* BIT MASKS to parse response bytes */ #define CTS_INT_BIT_MASK (1 << 7) #define ERR_BIT_MASK (1 << 6) #define RSQ_INT_BIT_MASK (1 << 3) /* set RDS repeat int bit along with RDS int bit */ #define RDS_INT_BIT_MASK (0x0404) #define STC_INT_BIT_MASK 1 #define RSSI_LOW_TH_INT_BIT_MASK 1 #define RDS_INT_DISABLE_MASK 0x9 #define RSQ_INT_DISABLE_MASK 0x5 #define HARD_MUTE_MASK 0x3 #define GPIO1_OUTPUT_ENABLE_MASK (1 << 1) #define GPIO_OUTPUT_LOW_MASK 0 #define DCLK_FALLING_EDGE_MASK (1 << 7) /* Command lengths */ #define SET_PROP_CMD_LEN 6 #define GET_PROP_CMD_LEN 4 #define GET_INT_STATUS_CMD_LEN 1 #define POWER_UP_CMD_LEN 3 #define POWER_DOWN_CMD_LEN 1 #define TUNE_FREQ_CMD_LEN 5 #define SEEK_CMD_LEN 2 #define TUNE_STATUS_CMD_LEN 2 #define RSQ_STATUS_CMD_LEN 2 #define GPIO_CTL_CMD_LEN 2 #define GPIO_SET_CMD_LEN 2 #define HIGH_BYTE_16BIT(x) (x >> 8) #define LOW_BYTE_16BIT(x) (x & 0xFF) #define AUDIO_OPMODE_ANALOG 0x05 #define AUDIO_OPMODE_DIGITAL 0xB0 /* ERROR codes */ #define BAD_CMD 0x10 #define BAD_ARG1 0x11 #define BAD_ARG2 0x12 #define BAD_ARG3 0x13 #define BAD_ARG4 0x14 #define BAD_ARG5 0x15 #define BAD_ARG6 0x16 #define BAD_ARG7 0x17 #define BAD_PROP 0x20 #define BAD_BOOT_MODE 0x30 /* RDS */ #define FM_RDS_BUF 100 #define FM_RDS_STATUS_IN_INTACK 0x01 #define FM_RDS_STATUS_IN_MTFIFO 0x02 #define FM_RDS_STATUS_OUT_GRPLOST 0x04 #define FM_RDS_STATUS_OUT_BLED 0x03 #define FM_RDS_STATUS_OUT_BLEC 0x0C #define FM_RDS_STATUS_OUT_BLEB 0x30 #define FM_RDS_STATUS_OUT_BLEA 0xC0 #define FM_RDS_STATUS_OUT_BLED_SHFT 0 #define FM_RDS_STATUS_OUT_BLEC_SHFT 2 #define FM_RDS_STATUS_OUT_BLEB_SHFT 4 #define FM_RDS_STATUS_OUT_BLEA_SHFT 6 #define RDS_TYPE_0A (0 * 2 + 0) #define RDS_TYPE_0B (0 * 2 + 1) #define RDS_TYPE_2A (2 * 2 + 0) #define RDS_TYPE_2B (2 * 2 + 1) #define RDS_TYPE_3A (3 * 2 + 0) #define UNCORRECTABLE 3 #define RT_VALIDATE_LIMIT 2 #define APP_GRP_typ_MASK 0x1F /*ERT*/ #define ERT_AID 0x6552 #define MAX_ERT_SEGMENT 31 #define MAX_ERT_LEN 256 #define ERT_OFFSET 3 #define ERT_FORMAT_DIR_BIT 1 #define ERT_CNT_PER_BLK 2 /*RT PLUS*/ #define DUMMY_CLASS 0 #define RT_PLUS_LEN_1_TAG 3 #define RT_ERT_FLAG_BIT 13 #define RT_PLUS_AID 0x4bd7 #define RT_ERT_FLAG_OFFSET 1 #define RT_PLUS_OFFSET 2 /*TAG1*/ #define TAG1_MSB_OFFSET 3 #define TAG1_MSB_MASK 7 #define TAG1_LSB_OFFSET 13 #define TAG1_POS_MSB_MASK 0x3F #define TAG1_POS_MSB_OFFSET 1 #define TAG1_POS_LSB_OFFSET 7 #define TAG1_LEN_OFFSET 1 #define TAG1_LEN_MASK 0x3F /*TAG2*/ #define TAG2_MSB_OFFSET 5 #define TAG2_MSB_MASK 9 #define TAG2_LSB_OFFSET 11 #define TAG2_POS_MSB_MASK 0x3F #define TAG2_POS_MSB_OFFSET 3 #define TAG2_POS_LSB_OFFSET 5 #define TAG2_LEN_MASK 0x1F #define EXTRACT_BIT(data, bit_pos) ((data >> bit_pos) & 1) /* FM states */ enum radio_state_t { FM_OFF, FM_RECV, FM_RESET, FM_CALIB, FM_TURNING_OFF, FM_RECV_TURNING_ON, FM_MAX_NO_STATES, }; enum emphasis_type { FM_RX_EMP75 = 0x0002, FM_RX_EMP50 = 0x0001 }; /* 3 valid values: 5 (50 kHz), 10 (100 kHz), and 20 (200 kHz). */ enum channel_space_type { FM_RX_SPACE_200KHZ = 0x0014, FM_RX_SPACE_100KHZ = 0x000A, FM_RX_SPACE_50KHZ = 0x0005 }; enum v4l2_cid_private_silabs_fm_t { V4L2_CID_PRIVATE_SILABS_SRCHMODE = (V4L2_CID_PRIVATE_BASE + 1), V4L2_CID_PRIVATE_SILABS_SCANDWELL, V4L2_CID_PRIVATE_SILABS_SRCHON, V4L2_CID_PRIVATE_SILABS_STATE, V4L2_CID_PRIVATE_SILABS_TRANSMIT_MODE, V4L2_CID_PRIVATE_SILABS_RDSGROUP_MASK, V4L2_CID_PRIVATE_SILABS_REGION, V4L2_CID_PRIVATE_SILABS_SIGNAL_TH, V4L2_CID_PRIVATE_SILABS_SRCH_PTY, V4L2_CID_PRIVATE_SILABS_SRCH_PI, V4L2_CID_PRIVATE_SILABS_SRCH_CNT, V4L2_CID_PRIVATE_SILABS_EMPHASIS, V4L2_CID_PRIVATE_SILABS_RDS_STD, V4L2_CID_PRIVATE_SILABS_SPACING, V4L2_CID_PRIVATE_SILABS_RDSON, V4L2_CID_PRIVATE_SILABS_RDSGROUP_PROC, V4L2_CID_PRIVATE_SILABS_LP_MODE, V4L2_CID_PRIVATE_SILABS_ANTENNA, V4L2_CID_PRIVATE_SILABS_RDSD_BUF, V4L2_CID_PRIVATE_SILABS_PSALL, /*v4l2 Tx controls*/ V4L2_CID_PRIVATE_SILABS_TX_SETPSREPEATCOUNT, V4L2_CID_PRIVATE_SILABS_STOP_RDS_TX_PS_NAME, V4L2_CID_PRIVATE_SILABS_STOP_RDS_TX_RT, V4L2_CID_PRIVATE_SILABS_IOVERC, V4L2_CID_PRIVATE_SILABS_INTDET, V4L2_CID_PRIVATE_SILABS_MPX_DCC, V4L2_CID_PRIVATE_SILABS_AF_JUMP, V4L2_CID_PRIVATE_SILABS_RSSI_DELTA, V4L2_CID_PRIVATE_SILABS_HLSI, /* * Here we have IOCTl's that are specific to IRIS * (V4L2_CID_PRIVATE_BASE + 0x1E to V4L2_CID_PRIVATE_BASE + 0x28) */ V4L2_CID_PRIVATE_SILABS_SOFT_MUTE,/* 0x800001E*/ V4L2_CID_PRIVATE_SILABS_RIVA_ACCS_ADDR, V4L2_CID_PRIVATE_SILABS_RIVA_ACCS_LEN, V4L2_CID_PRIVATE_SILABS_RIVA_PEEK, V4L2_CID_PRIVATE_SILABS_RIVA_POKE, V4L2_CID_PRIVATE_SILABS_SSBI_ACCS_ADDR, V4L2_CID_PRIVATE_SILABS_SSBI_PEEK, V4L2_CID_PRIVATE_SILABS_SSBI_POKE, V4L2_CID_PRIVATE_SILABS_TX_TONE, V4L2_CID_PRIVATE_SILABS_RDS_GRP_COUNTERS, V4L2_CID_PRIVATE_SILABS_SET_NOTCH_FILTER,/* 0x8000028 */ V4L2_CID_PRIVATE_SILABS_SET_AUDIO_PATH,/* 0x8000029 */ V4L2_CID_PRIVATE_SILABS_DO_CALIBRATION,/* 0x800002A : IRIS */ V4L2_CID_PRIVATE_SILABS_SRCH_ALGORITHM,/* 0x800002B */ V4L2_CID_PRIVATE_SILABS_GET_SINR, /* 0x800002C : IRIS */ V4L2_CID_PRIVATE_SILABS_INTF_LOW_THRESHOLD, /* 0x800002D */ V4L2_CID_PRIVATE_SILABS_INTF_HIGH_THRESHOLD, /* 0x800002E */ V4L2_CID_PRIVATE_SILABS_SINR_THRESHOLD, /* 0x800002F : IRIS */ V4L2_CID_PRIVATE_SILABS_SINR_SAMPLES, /* 0x8000030 : IRIS */ V4L2_CID_PRIVATE_SILABS_SPUR_FREQ, V4L2_CID_PRIVATE_SILABS_SPUR_FREQ_RMSSI, V4L2_CID_PRIVATE_SILABS_SPUR_SELECTION, V4L2_CID_PRIVATE_SILABS_UPDATE_SPUR_TABLE, V4L2_CID_PRIVATE_SILABS_VALID_CHANNEL, V4L2_CID_PRIVATE_SILABS_AF_RMSSI_TH, V4L2_CID_PRIVATE_SILABS_AF_RMSSI_SAMPLES, V4L2_CID_PRIVATE_SILABS_GOOD_CH_RMSSI_TH, V4L2_CID_PRIVATE_SILABS_SRCHALGOTYPE, V4L2_CID_PRIVATE_SILABS_CF0TH12, V4L2_CID_PRIVATE_SILABS_SINRFIRSTSTAGE, V4L2_CID_PRIVATE_SILABS_RMSSIFIRSTSTAGE, V4L2_CID_PRIVATE_SILABS_RXREPEATCOUNT, V4L2_CID_PRIVATE_SILABS_RSSI_TH, /* 0x800003E */ V4L2_CID_PRIVATE_SILABS_AF_JUMP_RSSI_TH /* 0x800003F */ }; enum silabs_buf_t { SILABS_FM_BUF_SRCH_LIST, SILABS_FM_BUF_EVENTS, SILABS_FM_BUF_RT_RDS, SILABS_FM_BUF_PS_RDS, SILABS_FM_BUF_RAW_RDS, SILABS_FM_BUF_AF_LIST, SILABS_FM_BUF_RT_PLUS = 11, SILABS_FM_BUF_ERT, SILABS_FM_BUF_MAX }; enum silabs_evt_t { SILABS_EVT_RADIO_READY, SILABS_EVT_TUNE_SUCC, SILABS_EVT_SEEK_COMPLETE, SILABS_EVT_SCAN_NEXT, SILABS_EVT_NEW_RAW_RDS, SILABS_EVT_NEW_RT_RDS, SILABS_EVT_NEW_PS_RDS, SILABS_EVT_ERROR, SILABS_EVT_BELOW_TH, SILABS_EVT_ABOVE_TH, SILABS_EVT_STEREO, SILABS_EVT_MONO, SILABS_EVT_RDS_AVAIL, SILABS_EVT_RDS_NOT_AVAIL, SILABS_EVT_NEW_SRCH_LIST, SILABS_EVT_NEW_AF_LIST, SILABS_EVT_TXRDSDAT, SILABS_EVT_TXRDSDONE, SILABS_EVT_RADIO_DISABLED, SILABS_EVT_NEW_ODA, SILABS_EVT_NEW_RT_PLUS, SILABS_EVT_NEW_ERT }; enum silabs_region_t { SILABS_REGION_US, SILABS_REGION_EU, SILABS_REGION_JAPAN, SILABS_REGION_JAPAN_WIDE, SILABS_REGION_OTHER }; enum silabs_interrupts_t { DISABLE_ALL_INTERRUPTS, ENABLE_STC_RDS_INTERRUPTS, ENABLE_STC_INTERRUPTS, ENABLE_RDS_INTERRUPTS, DISABLE_RDS_INTERRUPTS, ENABLE_RSQ_INTERRUPTS, DISABLE_RSQ_INTERRUPTS }; struct silabs_fm_recv_conf_req { __u16 emphasis; __u16 ch_spacing; /* limits stored as actual freq / TUNE_STEP_SIZE */ __u16 band_low_limit; __u16 band_high_limit; }; struct af_list_ev { __le32 tune_freq_khz; __le16 pi_code; __u8 af_size; __u8 af_list[MAX_AF_LIST_SIZE]; } __packed; struct silabs_af_info { /* no. of invalid AFs. */ u8 inval_freq_cnt; /* no. of AFs in the list. */ u8 cnt; /* actual size of the list */ u8 size; /* index of currently tuned station in the AF list. */ u8 index; /* PI of the frequency */ u16 pi; /* freq to which AF list belongs to. */ u32 orig_freq_khz; /* AF list */ u32 af_list[MAX_NO_OF_AF]; }; static inline bool is_valid_chan_spacing(int spacing) { if ((spacing == 0) || (spacing == 1) || (spacing == 2)) return 1; else return 0; } static inline bool is_valid_rds_std(int rds_std) { if ((rds_std >= MIN_RDS_STD) && (rds_std <= MAX_RDS_STD)) return 1; else return 0; } static inline bool is_valid_srch_mode(int srch_mode) { if ((srch_mode >= MIN_SRCH_MODE) && (srch_mode <= MAX_SRCH_MODE)) return 1; else return 0; } struct fm_power_vreg_data { /* voltage regulator handle */ struct regulator *reg; /* regulator name */ const char *name; /* voltage levels to be set */ unsigned int low_vol_level; unsigned int high_vol_level; bool set_voltage_sup; /* is this regulator enabled? */ bool is_enabled; }; struct silabs_rel_freq { __u8 rel_freq_msb; __u8 rel_freq_lsb; } __packed; struct silabs_srch_list_compl { __u8 num_stations_found; struct silabs_rel_freq rel_freq[20]; } __packed; enum search_t { SEEK, SCAN, SCAN_FOR_STRONG, }; #endif /* __RADIO_SILABS_H */