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

fmdrv_tx.c (8699B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 *  FM Driver for Connectivity chip of Texas Instruments.
      4 *  This sub-module of FM driver implements FM TX functionality.
      5 *
      6 *  Copyright (C) 2011 Texas Instruments
      7 */
      8
      9#include <linux/delay.h>
     10#include "fmdrv.h"
     11#include "fmdrv_common.h"
     12#include "fmdrv_tx.h"
     13
     14int fm_tx_set_stereo_mono(struct fmdev *fmdev, u16 mode)
     15{
     16	u16 payload;
     17	int ret;
     18
     19	if (fmdev->tx_data.aud_mode == mode)
     20		return 0;
     21
     22	fmdbg("stereo mode: %d\n", mode);
     23
     24	/* Set Stereo/Mono mode */
     25	payload = (1 - mode);
     26	ret = fmc_send_cmd(fmdev, MONO_SET, REG_WR, &payload,
     27			sizeof(payload), NULL, NULL);
     28	if (ret < 0)
     29		return ret;
     30
     31	fmdev->tx_data.aud_mode = mode;
     32
     33	return ret;
     34}
     35
     36static int set_rds_text(struct fmdev *fmdev, u8 *rds_text)
     37{
     38	u16 payload;
     39	int ret;
     40
     41	ret = fmc_send_cmd(fmdev, RDS_DATA_SET, REG_WR, rds_text,
     42			strlen(rds_text), NULL, NULL);
     43	if (ret < 0)
     44		return ret;
     45
     46	/* Scroll mode */
     47	payload = (u16)0x1;
     48	ret = fmc_send_cmd(fmdev, DISPLAY_MODE, REG_WR, &payload,
     49			sizeof(payload), NULL, NULL);
     50	if (ret < 0)
     51		return ret;
     52
     53	return 0;
     54}
     55
     56static int set_rds_data_mode(struct fmdev *fmdev, u8 mode)
     57{
     58	u16 payload;
     59	int ret;
     60
     61	/* Setting unique PI TODO: how unique? */
     62	payload = (u16)0xcafe;
     63	ret = fmc_send_cmd(fmdev, PI_SET, REG_WR, &payload,
     64			sizeof(payload), NULL, NULL);
     65	if (ret < 0)
     66		return ret;
     67
     68	/* Set decoder id */
     69	payload = (u16)0xa;
     70	ret = fmc_send_cmd(fmdev, DI_SET, REG_WR, &payload,
     71			sizeof(payload), NULL, NULL);
     72	if (ret < 0)
     73		return ret;
     74
     75	/* TODO: RDS_MODE_GET? */
     76	return 0;
     77}
     78
     79static int set_rds_len(struct fmdev *fmdev, u8 type, u16 len)
     80{
     81	u16 payload;
     82	int ret;
     83
     84	len |= type << 8;
     85	payload = len;
     86	ret = fmc_send_cmd(fmdev, RDS_CONFIG_DATA_SET, REG_WR, &payload,
     87			sizeof(payload), NULL, NULL);
     88	if (ret < 0)
     89		return ret;
     90
     91	/* TODO: LENGTH_GET? */
     92	return 0;
     93}
     94
     95int fm_tx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis)
     96{
     97	u16 payload;
     98	int ret;
     99	u8 rds_text[] = "Zoom2\n";
    100
    101	fmdbg("rds_en_dis:%d(E:%d, D:%d)\n", rds_en_dis,
    102		   FM_RDS_ENABLE, FM_RDS_DISABLE);
    103
    104	if (rds_en_dis == FM_RDS_ENABLE) {
    105		/* Set RDS length */
    106		set_rds_len(fmdev, 0, strlen(rds_text));
    107
    108		/* Set RDS text */
    109		set_rds_text(fmdev, rds_text);
    110
    111		/* Set RDS mode */
    112		set_rds_data_mode(fmdev, 0x0);
    113	}
    114
    115	/* Send command to enable RDS */
    116	if (rds_en_dis == FM_RDS_ENABLE)
    117		payload = 0x01;
    118	else
    119		payload = 0x00;
    120
    121	ret = fmc_send_cmd(fmdev, RDS_DATA_ENB, REG_WR, &payload,
    122			sizeof(payload), NULL, NULL);
    123	if (ret < 0)
    124		return ret;
    125
    126	if (rds_en_dis == FM_RDS_ENABLE) {
    127		/* Set RDS length */
    128		set_rds_len(fmdev, 0, strlen(rds_text));
    129
    130		/* Set RDS text */
    131		set_rds_text(fmdev, rds_text);
    132	}
    133	fmdev->tx_data.rds.flag = rds_en_dis;
    134
    135	return 0;
    136}
    137
    138int fm_tx_set_radio_text(struct fmdev *fmdev, u8 *rds_text, u8 rds_type)
    139{
    140	u16 payload;
    141	int ret;
    142
    143	if (fmdev->curr_fmmode != FM_MODE_TX)
    144		return -EPERM;
    145
    146	fm_tx_set_rds_mode(fmdev, 0);
    147
    148	/* Set RDS length */
    149	set_rds_len(fmdev, rds_type, strlen(rds_text));
    150
    151	/* Set RDS text */
    152	set_rds_text(fmdev, rds_text);
    153
    154	/* Set RDS mode */
    155	set_rds_data_mode(fmdev, 0x0);
    156
    157	payload = 1;
    158	ret = fmc_send_cmd(fmdev, RDS_DATA_ENB, REG_WR, &payload,
    159			sizeof(payload), NULL, NULL);
    160	if (ret < 0)
    161		return ret;
    162
    163	return 0;
    164}
    165
    166int fm_tx_set_af(struct fmdev *fmdev, u32 af)
    167{
    168	u16 payload;
    169	int ret;
    170
    171	if (fmdev->curr_fmmode != FM_MODE_TX)
    172		return -EPERM;
    173
    174	fmdbg("AF: %d\n", af);
    175
    176	af = (af - 87500) / 100;
    177	payload = (u16)af;
    178	ret = fmc_send_cmd(fmdev, TA_SET, REG_WR, &payload,
    179			sizeof(payload), NULL, NULL);
    180	if (ret < 0)
    181		return ret;
    182
    183	return 0;
    184}
    185
    186int fm_tx_set_region(struct fmdev *fmdev, u8 region)
    187{
    188	u16 payload;
    189	int ret;
    190
    191	if (region != FM_BAND_EUROPE_US && region != FM_BAND_JAPAN) {
    192		fmerr("Invalid band\n");
    193		return -EINVAL;
    194	}
    195
    196	/* Send command to set the band */
    197	payload = (u16)region;
    198	ret = fmc_send_cmd(fmdev, TX_BAND_SET, REG_WR, &payload,
    199			sizeof(payload), NULL, NULL);
    200	if (ret < 0)
    201		return ret;
    202
    203	return 0;
    204}
    205
    206int fm_tx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset)
    207{
    208	u16 payload;
    209	int ret;
    210
    211	fmdbg("tx: mute mode %d\n", mute_mode_toset);
    212
    213	payload = mute_mode_toset;
    214	ret = fmc_send_cmd(fmdev, MUTE, REG_WR, &payload,
    215			sizeof(payload), NULL, NULL);
    216	if (ret < 0)
    217		return ret;
    218
    219	return 0;
    220}
    221
    222/* Set TX Audio I/O */
    223static int set_audio_io(struct fmdev *fmdev)
    224{
    225	struct fmtx_data *tx = &fmdev->tx_data;
    226	u16 payload;
    227	int ret;
    228
    229	/* Set Audio I/O Enable */
    230	payload = tx->audio_io;
    231	ret = fmc_send_cmd(fmdev, AUDIO_IO_SET, REG_WR, &payload,
    232			sizeof(payload), NULL, NULL);
    233	if (ret < 0)
    234		return ret;
    235
    236	/* TODO: is audio set? */
    237	return 0;
    238}
    239
    240/* Start TX Transmission */
    241static int enable_xmit(struct fmdev *fmdev, u8 new_xmit_state)
    242{
    243	struct fmtx_data *tx = &fmdev->tx_data;
    244	unsigned long timeleft;
    245	u16 payload;
    246	int ret;
    247
    248	/* Enable POWER_ENB interrupts */
    249	payload = FM_POW_ENB_EVENT;
    250	ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
    251			sizeof(payload), NULL, NULL);
    252	if (ret < 0)
    253		return ret;
    254
    255	/* Set Power Enable */
    256	payload = new_xmit_state;
    257	ret = fmc_send_cmd(fmdev, POWER_ENB_SET, REG_WR, &payload,
    258			sizeof(payload), NULL, NULL);
    259	if (ret < 0)
    260		return ret;
    261
    262	/* Wait for Power Enabled */
    263	init_completion(&fmdev->maintask_comp);
    264	timeleft = wait_for_completion_timeout(&fmdev->maintask_comp,
    265			FM_DRV_TX_TIMEOUT);
    266	if (!timeleft) {
    267		fmerr("Timeout(%d sec),didn't get tune ended interrupt\n",
    268			   jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000);
    269		return -ETIMEDOUT;
    270	}
    271
    272	set_bit(FM_CORE_TX_XMITING, &fmdev->flag);
    273	tx->xmit_state = new_xmit_state;
    274
    275	return 0;
    276}
    277
    278/* Set TX power level */
    279int fm_tx_set_pwr_lvl(struct fmdev *fmdev, u8 new_pwr_lvl)
    280{
    281	u16 payload;
    282	struct fmtx_data *tx = &fmdev->tx_data;
    283	int ret;
    284
    285	if (fmdev->curr_fmmode != FM_MODE_TX)
    286		return -EPERM;
    287	fmdbg("tx: pwr_level_to_set %ld\n", (long int)new_pwr_lvl);
    288
    289	/* If the core isn't ready update global variable */
    290	if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
    291		tx->pwr_lvl = new_pwr_lvl;
    292		return 0;
    293	}
    294
    295	/* Set power level: Application will specify power level value in
    296	 * units of dB/uV, whereas range and step are specific to FM chip.
    297	 * For TI's WL chips, convert application specified power level value
    298	 * to chip specific value by subtracting 122 from it. Refer to TI FM
    299	 * data sheet for details.
    300	 * */
    301
    302	payload = (FM_PWR_LVL_HIGH - new_pwr_lvl);
    303	ret = fmc_send_cmd(fmdev, POWER_LEV_SET, REG_WR, &payload,
    304			sizeof(payload), NULL, NULL);
    305	if (ret < 0)
    306		return ret;
    307
    308	/* TODO: is the power level set? */
    309	tx->pwr_lvl = new_pwr_lvl;
    310
    311	return 0;
    312}
    313
    314/*
    315 * Sets FM TX pre-emphasis filter value (OFF, 50us, or 75us)
    316 * Convert V4L2 specified filter values to chip specific filter values.
    317 */
    318int fm_tx_set_preemph_filter(struct fmdev *fmdev, u32 preemphasis)
    319{
    320	struct fmtx_data *tx = &fmdev->tx_data;
    321	u16 payload;
    322	int ret;
    323
    324	if (fmdev->curr_fmmode != FM_MODE_TX)
    325		return -EPERM;
    326
    327	switch (preemphasis) {
    328	case V4L2_PREEMPHASIS_DISABLED:
    329		payload = FM_TX_PREEMPH_OFF;
    330		break;
    331	case V4L2_PREEMPHASIS_50_uS:
    332		payload = FM_TX_PREEMPH_50US;
    333		break;
    334	case V4L2_PREEMPHASIS_75_uS:
    335		payload = FM_TX_PREEMPH_75US;
    336		break;
    337	}
    338
    339	ret = fmc_send_cmd(fmdev, PREMPH_SET, REG_WR, &payload,
    340			sizeof(payload), NULL, NULL);
    341	if (ret < 0)
    342		return ret;
    343
    344	tx->preemph = payload;
    345
    346	return ret;
    347}
    348
    349/* Get the TX tuning capacitor value.*/
    350int fm_tx_get_tune_cap_val(struct fmdev *fmdev)
    351{
    352	u16 curr_val;
    353	u32 resp_len;
    354	int ret;
    355
    356	if (fmdev->curr_fmmode != FM_MODE_TX)
    357		return -EPERM;
    358
    359	ret = fmc_send_cmd(fmdev, READ_FMANT_TUNE_VALUE, REG_RD,
    360			NULL, sizeof(curr_val), &curr_val, &resp_len);
    361	if (ret < 0)
    362		return ret;
    363
    364	curr_val = be16_to_cpu((__force __be16)curr_val);
    365
    366	return curr_val;
    367}
    368
    369/* Set TX Frequency */
    370int fm_tx_set_freq(struct fmdev *fmdev, u32 freq_to_set)
    371{
    372	struct fmtx_data *tx = &fmdev->tx_data;
    373	u16 payload, chanl_index;
    374	int ret;
    375
    376	if (test_bit(FM_CORE_TX_XMITING, &fmdev->flag)) {
    377		enable_xmit(fmdev, 0);
    378		clear_bit(FM_CORE_TX_XMITING, &fmdev->flag);
    379	}
    380
    381	/* Enable FR, BL interrupts */
    382	payload = (FM_FR_EVENT | FM_BL_EVENT);
    383	ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
    384			sizeof(payload), NULL, NULL);
    385	if (ret < 0)
    386		return ret;
    387
    388	tx->tx_frq = (unsigned long)freq_to_set;
    389	fmdbg("tx: freq_to_set %ld\n", (long int)tx->tx_frq);
    390
    391	chanl_index = freq_to_set / 10;
    392
    393	/* Set current tuner channel */
    394	payload = chanl_index;
    395	ret = fmc_send_cmd(fmdev, CHANL_SET, REG_WR, &payload,
    396			sizeof(payload), NULL, NULL);
    397	if (ret < 0)
    398		return ret;
    399
    400	fm_tx_set_pwr_lvl(fmdev, tx->pwr_lvl);
    401	fm_tx_set_preemph_filter(fmdev, tx->preemph);
    402
    403	tx->audio_io = 0x01;	/* I2S */
    404	set_audio_io(fmdev);
    405
    406	enable_xmit(fmdev, 0x01);	/* Enable transmission */
    407
    408	tx->aud_mode = FM_STEREO_MODE;
    409	tx->rds.flag = FM_RDS_DISABLE;
    410
    411	return 0;
    412}
    413