162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  FM Driver for Connectivity chip of Texas Instruments.
462306a36Sopenharmony_ci *  This sub-module of FM driver implements FM RX functionality.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci *  Copyright (C) 2011 Texas Instruments
762306a36Sopenharmony_ci *  Author: Raja Mani <raja_mani@ti.com>
862306a36Sopenharmony_ci *  Author: Manjunatha Halli <manjunatha_halli@ti.com>
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include "fmdrv.h"
1262306a36Sopenharmony_ci#include "fmdrv_common.h"
1362306a36Sopenharmony_ci#include "fmdrv_rx.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_civoid fm_rx_reset_rds_cache(struct fmdev *fmdev)
1662306a36Sopenharmony_ci{
1762306a36Sopenharmony_ci	fmdev->rx.rds.flag = FM_RDS_DISABLE;
1862306a36Sopenharmony_ci	fmdev->rx.rds.last_blk_idx = 0;
1962306a36Sopenharmony_ci	fmdev->rx.rds.wr_idx = 0;
2062306a36Sopenharmony_ci	fmdev->rx.rds.rd_idx = 0;
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci	if (fmdev->rx.af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON)
2362306a36Sopenharmony_ci		fmdev->irq_info.mask |= FM_LEV_EVENT;
2462306a36Sopenharmony_ci}
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_civoid fm_rx_reset_station_info(struct fmdev *fmdev)
2762306a36Sopenharmony_ci{
2862306a36Sopenharmony_ci	fmdev->rx.stat_info.picode = FM_NO_PI_CODE;
2962306a36Sopenharmony_ci	fmdev->rx.stat_info.afcache_size = 0;
3062306a36Sopenharmony_ci	fmdev->rx.stat_info.af_list_max = 0;
3162306a36Sopenharmony_ci}
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ciint fm_rx_set_freq(struct fmdev *fmdev, u32 freq)
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	unsigned long timeleft;
3662306a36Sopenharmony_ci	u16 payload, curr_frq, intr_flag;
3762306a36Sopenharmony_ci	u32 curr_frq_in_khz;
3862306a36Sopenharmony_ci	u32 resp_len;
3962306a36Sopenharmony_ci	int ret;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	if (freq < fmdev->rx.region.bot_freq || freq > fmdev->rx.region.top_freq) {
4262306a36Sopenharmony_ci		fmerr("Invalid frequency %d\n", freq);
4362306a36Sopenharmony_ci		return -EINVAL;
4462306a36Sopenharmony_ci	}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	/* Set audio enable */
4762306a36Sopenharmony_ci	payload = FM_RX_AUDIO_ENABLE_I2S_AND_ANALOG;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	ret = fmc_send_cmd(fmdev, AUDIO_ENABLE_SET, REG_WR, &payload,
5062306a36Sopenharmony_ci			sizeof(payload), NULL, NULL);
5162306a36Sopenharmony_ci	if (ret < 0)
5262306a36Sopenharmony_ci		return ret;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	/* Set hilo to automatic selection */
5562306a36Sopenharmony_ci	payload = FM_RX_IFFREQ_HILO_AUTOMATIC;
5662306a36Sopenharmony_ci	ret = fmc_send_cmd(fmdev, HILO_SET, REG_WR, &payload,
5762306a36Sopenharmony_ci			sizeof(payload), NULL, NULL);
5862306a36Sopenharmony_ci	if (ret < 0)
5962306a36Sopenharmony_ci		return ret;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	/* Calculate frequency index and set*/
6262306a36Sopenharmony_ci	payload = (freq - fmdev->rx.region.bot_freq) / FM_FREQ_MUL;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	ret = fmc_send_cmd(fmdev, FREQ_SET, REG_WR, &payload,
6562306a36Sopenharmony_ci			sizeof(payload), NULL, NULL);
6662306a36Sopenharmony_ci	if (ret < 0)
6762306a36Sopenharmony_ci		return ret;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	/* Read flags - just to clear any pending interrupts if we had */
7062306a36Sopenharmony_ci	ret = fmc_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, 2, NULL, NULL);
7162306a36Sopenharmony_ci	if (ret < 0)
7262306a36Sopenharmony_ci		return ret;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	/* Enable FR, BL interrupts */
7562306a36Sopenharmony_ci	intr_flag = fmdev->irq_info.mask;
7662306a36Sopenharmony_ci	fmdev->irq_info.mask = (FM_FR_EVENT | FM_BL_EVENT);
7762306a36Sopenharmony_ci	payload = fmdev->irq_info.mask;
7862306a36Sopenharmony_ci	ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
7962306a36Sopenharmony_ci			sizeof(payload), NULL, NULL);
8062306a36Sopenharmony_ci	if (ret < 0)
8162306a36Sopenharmony_ci		return ret;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	/* Start tune */
8462306a36Sopenharmony_ci	payload = FM_TUNER_PRESET_MODE;
8562306a36Sopenharmony_ci	ret = fmc_send_cmd(fmdev, TUNER_MODE_SET, REG_WR, &payload,
8662306a36Sopenharmony_ci			sizeof(payload), NULL, NULL);
8762306a36Sopenharmony_ci	if (ret < 0)
8862306a36Sopenharmony_ci		goto exit;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	/* Wait for tune ended interrupt */
9162306a36Sopenharmony_ci	init_completion(&fmdev->maintask_comp);
9262306a36Sopenharmony_ci	timeleft = wait_for_completion_timeout(&fmdev->maintask_comp,
9362306a36Sopenharmony_ci			FM_DRV_TX_TIMEOUT);
9462306a36Sopenharmony_ci	if (!timeleft) {
9562306a36Sopenharmony_ci		fmerr("Timeout(%d sec),didn't get tune ended int\n",
9662306a36Sopenharmony_ci			   jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000);
9762306a36Sopenharmony_ci		ret = -ETIMEDOUT;
9862306a36Sopenharmony_ci		goto exit;
9962306a36Sopenharmony_ci	}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	/* Read freq back to confirm */
10262306a36Sopenharmony_ci	ret = fmc_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, 2, &curr_frq, &resp_len);
10362306a36Sopenharmony_ci	if (ret < 0)
10462306a36Sopenharmony_ci		goto exit;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	curr_frq = be16_to_cpu((__force __be16)curr_frq);
10762306a36Sopenharmony_ci	curr_frq_in_khz = (fmdev->rx.region.bot_freq + ((u32)curr_frq * FM_FREQ_MUL));
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	if (curr_frq_in_khz != freq) {
11062306a36Sopenharmony_ci		pr_info("Frequency is set to (%d) but requested freq is (%d)\n",
11162306a36Sopenharmony_ci			curr_frq_in_khz, freq);
11262306a36Sopenharmony_ci	}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	/* Update local cache  */
11562306a36Sopenharmony_ci	fmdev->rx.freq = curr_frq_in_khz;
11662306a36Sopenharmony_ciexit:
11762306a36Sopenharmony_ci	/* Re-enable default FM interrupts */
11862306a36Sopenharmony_ci	fmdev->irq_info.mask = intr_flag;
11962306a36Sopenharmony_ci	payload = fmdev->irq_info.mask;
12062306a36Sopenharmony_ci	ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
12162306a36Sopenharmony_ci			sizeof(payload), NULL, NULL);
12262306a36Sopenharmony_ci	if (ret < 0)
12362306a36Sopenharmony_ci		return ret;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	/* Reset RDS cache and current station pointers */
12662306a36Sopenharmony_ci	fm_rx_reset_rds_cache(fmdev);
12762306a36Sopenharmony_ci	fm_rx_reset_station_info(fmdev);
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	return ret;
13062306a36Sopenharmony_ci}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistatic int fm_rx_set_channel_spacing(struct fmdev *fmdev, u32 spacing)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	u16 payload;
13562306a36Sopenharmony_ci	int ret;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	if (spacing > 0 && spacing <= 50000)
13862306a36Sopenharmony_ci		spacing = FM_CHANNEL_SPACING_50KHZ;
13962306a36Sopenharmony_ci	else if (spacing > 50000 && spacing <= 100000)
14062306a36Sopenharmony_ci		spacing = FM_CHANNEL_SPACING_100KHZ;
14162306a36Sopenharmony_ci	else
14262306a36Sopenharmony_ci		spacing = FM_CHANNEL_SPACING_200KHZ;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	/* set channel spacing */
14562306a36Sopenharmony_ci	payload = spacing;
14662306a36Sopenharmony_ci	ret = fmc_send_cmd(fmdev, CHANL_BW_SET, REG_WR, &payload,
14762306a36Sopenharmony_ci			sizeof(payload), NULL, NULL);
14862306a36Sopenharmony_ci	if (ret < 0)
14962306a36Sopenharmony_ci		return ret;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	fmdev->rx.region.chanl_space = spacing * FM_FREQ_MUL;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	return ret;
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ciint fm_rx_seek(struct fmdev *fmdev, u32 seek_upward,
15762306a36Sopenharmony_ci		u32 wrap_around, u32 spacing)
15862306a36Sopenharmony_ci{
15962306a36Sopenharmony_ci	u32 resp_len;
16062306a36Sopenharmony_ci	u16 curr_frq, next_frq, last_frq;
16162306a36Sopenharmony_ci	u16 payload, int_reason, intr_flag;
16262306a36Sopenharmony_ci	u16 offset, space_idx;
16362306a36Sopenharmony_ci	unsigned long timeleft;
16462306a36Sopenharmony_ci	int ret;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	/* Set channel spacing */
16762306a36Sopenharmony_ci	ret = fm_rx_set_channel_spacing(fmdev, spacing);
16862306a36Sopenharmony_ci	if (ret < 0) {
16962306a36Sopenharmony_ci		fmerr("Failed to set channel spacing\n");
17062306a36Sopenharmony_ci		return ret;
17162306a36Sopenharmony_ci	}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	/* Read the current frequency from chip */
17462306a36Sopenharmony_ci	ret = fmc_send_cmd(fmdev, FREQ_SET, REG_RD, NULL,
17562306a36Sopenharmony_ci			sizeof(curr_frq), &curr_frq, &resp_len);
17662306a36Sopenharmony_ci	if (ret < 0)
17762306a36Sopenharmony_ci		return ret;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	curr_frq = be16_to_cpu((__force __be16)curr_frq);
18062306a36Sopenharmony_ci	last_frq = (fmdev->rx.region.top_freq - fmdev->rx.region.bot_freq) / FM_FREQ_MUL;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	/* Check the offset in order to be aligned to the channel spacing*/
18362306a36Sopenharmony_ci	space_idx = fmdev->rx.region.chanl_space / FM_FREQ_MUL;
18462306a36Sopenharmony_ci	offset = curr_frq % space_idx;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	next_frq = seek_upward ? curr_frq + space_idx /* Seek Up */ :
18762306a36Sopenharmony_ci				curr_frq - space_idx /* Seek Down */ ;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	/*
19062306a36Sopenharmony_ci	 * Add or subtract offset in order to stay aligned to the channel
19162306a36Sopenharmony_ci	 * spacing.
19262306a36Sopenharmony_ci	 */
19362306a36Sopenharmony_ci	if ((short)next_frq < 0)
19462306a36Sopenharmony_ci		next_frq = last_frq - offset;
19562306a36Sopenharmony_ci	else if (next_frq > last_frq)
19662306a36Sopenharmony_ci		next_frq = 0 + offset;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ciagain:
19962306a36Sopenharmony_ci	/* Set calculated next frequency to perform seek */
20062306a36Sopenharmony_ci	payload = next_frq;
20162306a36Sopenharmony_ci	ret = fmc_send_cmd(fmdev, FREQ_SET, REG_WR, &payload,
20262306a36Sopenharmony_ci			sizeof(payload), NULL, NULL);
20362306a36Sopenharmony_ci	if (ret < 0)
20462306a36Sopenharmony_ci		return ret;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	/* Set search direction (0:Seek Down, 1:Seek Up) */
20762306a36Sopenharmony_ci	payload = (seek_upward ? FM_SEARCH_DIRECTION_UP : FM_SEARCH_DIRECTION_DOWN);
20862306a36Sopenharmony_ci	ret = fmc_send_cmd(fmdev, SEARCH_DIR_SET, REG_WR, &payload,
20962306a36Sopenharmony_ci			sizeof(payload), NULL, NULL);
21062306a36Sopenharmony_ci	if (ret < 0)
21162306a36Sopenharmony_ci		return ret;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	/* Read flags - just to clear any pending interrupts if we had */
21462306a36Sopenharmony_ci	ret = fmc_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, 2, NULL, NULL);
21562306a36Sopenharmony_ci	if (ret < 0)
21662306a36Sopenharmony_ci		return ret;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	/* Enable FR, BL interrupts */
21962306a36Sopenharmony_ci	intr_flag = fmdev->irq_info.mask;
22062306a36Sopenharmony_ci	fmdev->irq_info.mask = (FM_FR_EVENT | FM_BL_EVENT);
22162306a36Sopenharmony_ci	payload = fmdev->irq_info.mask;
22262306a36Sopenharmony_ci	ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
22362306a36Sopenharmony_ci			sizeof(payload), NULL, NULL);
22462306a36Sopenharmony_ci	if (ret < 0)
22562306a36Sopenharmony_ci		return ret;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	/* Start seek */
22862306a36Sopenharmony_ci	payload = FM_TUNER_AUTONOMOUS_SEARCH_MODE;
22962306a36Sopenharmony_ci	ret = fmc_send_cmd(fmdev, TUNER_MODE_SET, REG_WR, &payload,
23062306a36Sopenharmony_ci			sizeof(payload), NULL, NULL);
23162306a36Sopenharmony_ci	if (ret < 0)
23262306a36Sopenharmony_ci		return ret;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	/* Wait for tune ended/band limit reached interrupt */
23562306a36Sopenharmony_ci	init_completion(&fmdev->maintask_comp);
23662306a36Sopenharmony_ci	timeleft = wait_for_completion_timeout(&fmdev->maintask_comp,
23762306a36Sopenharmony_ci			FM_DRV_RX_SEEK_TIMEOUT);
23862306a36Sopenharmony_ci	if (!timeleft) {
23962306a36Sopenharmony_ci		fmerr("Timeout(%d sec),didn't get tune ended int\n",
24062306a36Sopenharmony_ci			   jiffies_to_msecs(FM_DRV_RX_SEEK_TIMEOUT) / 1000);
24162306a36Sopenharmony_ci		return -ENODATA;
24262306a36Sopenharmony_ci	}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	int_reason = fmdev->irq_info.flag & (FM_TUNE_COMPLETE | FM_BAND_LIMIT);
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	/* Re-enable default FM interrupts */
24762306a36Sopenharmony_ci	fmdev->irq_info.mask = intr_flag;
24862306a36Sopenharmony_ci	payload = fmdev->irq_info.mask;
24962306a36Sopenharmony_ci	ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
25062306a36Sopenharmony_ci			sizeof(payload), NULL, NULL);
25162306a36Sopenharmony_ci	if (ret < 0)
25262306a36Sopenharmony_ci		return ret;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	if (int_reason & FM_BL_EVENT) {
25562306a36Sopenharmony_ci		if (wrap_around == 0) {
25662306a36Sopenharmony_ci			fmdev->rx.freq = seek_upward ?
25762306a36Sopenharmony_ci				fmdev->rx.region.top_freq :
25862306a36Sopenharmony_ci				fmdev->rx.region.bot_freq;
25962306a36Sopenharmony_ci		} else {
26062306a36Sopenharmony_ci			fmdev->rx.freq = seek_upward ?
26162306a36Sopenharmony_ci				fmdev->rx.region.bot_freq :
26262306a36Sopenharmony_ci				fmdev->rx.region.top_freq;
26362306a36Sopenharmony_ci			/* Calculate frequency index to write */
26462306a36Sopenharmony_ci			next_frq = (fmdev->rx.freq -
26562306a36Sopenharmony_ci					fmdev->rx.region.bot_freq) / FM_FREQ_MUL;
26662306a36Sopenharmony_ci			goto again;
26762306a36Sopenharmony_ci		}
26862306a36Sopenharmony_ci	} else {
26962306a36Sopenharmony_ci		/* Read freq to know where operation tune operation stopped */
27062306a36Sopenharmony_ci		ret = fmc_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, 2,
27162306a36Sopenharmony_ci				&curr_frq, &resp_len);
27262306a36Sopenharmony_ci		if (ret < 0)
27362306a36Sopenharmony_ci			return ret;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci		curr_frq = be16_to_cpu((__force __be16)curr_frq);
27662306a36Sopenharmony_ci		fmdev->rx.freq = (fmdev->rx.region.bot_freq +
27762306a36Sopenharmony_ci				((u32)curr_frq * FM_FREQ_MUL));
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	}
28062306a36Sopenharmony_ci	/* Reset RDS cache and current station pointers */
28162306a36Sopenharmony_ci	fm_rx_reset_rds_cache(fmdev);
28262306a36Sopenharmony_ci	fm_rx_reset_station_info(fmdev);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	return ret;
28562306a36Sopenharmony_ci}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ciint fm_rx_set_volume(struct fmdev *fmdev, u16 vol_to_set)
28862306a36Sopenharmony_ci{
28962306a36Sopenharmony_ci	u16 payload;
29062306a36Sopenharmony_ci	int ret;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	if (fmdev->curr_fmmode != FM_MODE_RX)
29362306a36Sopenharmony_ci		return -EPERM;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	if (vol_to_set > FM_RX_VOLUME_MAX) {
29662306a36Sopenharmony_ci		fmerr("Volume is not within(%d-%d) range\n",
29762306a36Sopenharmony_ci			   FM_RX_VOLUME_MIN, FM_RX_VOLUME_MAX);
29862306a36Sopenharmony_ci		return -EINVAL;
29962306a36Sopenharmony_ci	}
30062306a36Sopenharmony_ci	vol_to_set *= FM_RX_VOLUME_GAIN_STEP;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	payload = vol_to_set;
30362306a36Sopenharmony_ci	ret = fmc_send_cmd(fmdev, VOLUME_SET, REG_WR, &payload,
30462306a36Sopenharmony_ci			sizeof(payload), NULL, NULL);
30562306a36Sopenharmony_ci	if (ret < 0)
30662306a36Sopenharmony_ci		return ret;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	fmdev->rx.volume = vol_to_set;
30962306a36Sopenharmony_ci	return ret;
31062306a36Sopenharmony_ci}
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci/* Get volume */
31362306a36Sopenharmony_ciint fm_rx_get_volume(struct fmdev *fmdev, u16 *curr_vol)
31462306a36Sopenharmony_ci{
31562306a36Sopenharmony_ci	if (fmdev->curr_fmmode != FM_MODE_RX)
31662306a36Sopenharmony_ci		return -EPERM;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	if (curr_vol == NULL) {
31962306a36Sopenharmony_ci		fmerr("Invalid memory\n");
32062306a36Sopenharmony_ci		return -ENOMEM;
32162306a36Sopenharmony_ci	}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	*curr_vol = fmdev->rx.volume / FM_RX_VOLUME_GAIN_STEP;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	return 0;
32662306a36Sopenharmony_ci}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci/* To get current band's bottom and top frequency */
32962306a36Sopenharmony_ciint fm_rx_get_band_freq_range(struct fmdev *fmdev, u32 *bot_freq, u32 *top_freq)
33062306a36Sopenharmony_ci{
33162306a36Sopenharmony_ci	if (bot_freq != NULL)
33262306a36Sopenharmony_ci		*bot_freq = fmdev->rx.region.bot_freq;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	if (top_freq != NULL)
33562306a36Sopenharmony_ci		*top_freq = fmdev->rx.region.top_freq;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	return 0;
33862306a36Sopenharmony_ci}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci/* Returns current band index (0-Europe/US; 1-Japan) */
34162306a36Sopenharmony_civoid fm_rx_get_region(struct fmdev *fmdev, u8 *region)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	*region = fmdev->rx.region.fm_band;
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci/* Sets band (0-Europe/US; 1-Japan) */
34762306a36Sopenharmony_ciint fm_rx_set_region(struct fmdev *fmdev, u8 region_to_set)
34862306a36Sopenharmony_ci{
34962306a36Sopenharmony_ci	u16 payload;
35062306a36Sopenharmony_ci	u32 new_frq = 0;
35162306a36Sopenharmony_ci	int ret;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	if (region_to_set != FM_BAND_EUROPE_US &&
35462306a36Sopenharmony_ci	    region_to_set != FM_BAND_JAPAN) {
35562306a36Sopenharmony_ci		fmerr("Invalid band\n");
35662306a36Sopenharmony_ci		return -EINVAL;
35762306a36Sopenharmony_ci	}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	if (fmdev->rx.region.fm_band == region_to_set) {
36062306a36Sopenharmony_ci		fmerr("Requested band is already configured\n");
36162306a36Sopenharmony_ci		return 0;
36262306a36Sopenharmony_ci	}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	/* Send cmd to set the band  */
36562306a36Sopenharmony_ci	payload = (u16)region_to_set;
36662306a36Sopenharmony_ci	ret = fmc_send_cmd(fmdev, BAND_SET, REG_WR, &payload,
36762306a36Sopenharmony_ci			sizeof(payload), NULL, NULL);
36862306a36Sopenharmony_ci	if (ret < 0)
36962306a36Sopenharmony_ci		return ret;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	fmc_update_region_info(fmdev, region_to_set);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	/* Check whether current RX frequency is within band boundary */
37462306a36Sopenharmony_ci	if (fmdev->rx.freq < fmdev->rx.region.bot_freq)
37562306a36Sopenharmony_ci		new_frq = fmdev->rx.region.bot_freq;
37662306a36Sopenharmony_ci	else if (fmdev->rx.freq > fmdev->rx.region.top_freq)
37762306a36Sopenharmony_ci		new_frq = fmdev->rx.region.top_freq;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	if (new_frq) {
38062306a36Sopenharmony_ci		fmdbg("Current freq is not within band limit boundary,switching to %d KHz\n",
38162306a36Sopenharmony_ci		      new_frq);
38262306a36Sopenharmony_ci		 /* Current RX frequency is not in range. So, update it */
38362306a36Sopenharmony_ci		ret = fm_rx_set_freq(fmdev, new_frq);
38462306a36Sopenharmony_ci	}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	return ret;
38762306a36Sopenharmony_ci}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci/* Reads current mute mode (Mute Off/On/Attenuate)*/
39062306a36Sopenharmony_ciint fm_rx_get_mute_mode(struct fmdev *fmdev, u8 *curr_mute_mode)
39162306a36Sopenharmony_ci{
39262306a36Sopenharmony_ci	if (fmdev->curr_fmmode != FM_MODE_RX)
39362306a36Sopenharmony_ci		return -EPERM;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	if (curr_mute_mode == NULL) {
39662306a36Sopenharmony_ci		fmerr("Invalid memory\n");
39762306a36Sopenharmony_ci		return -ENOMEM;
39862306a36Sopenharmony_ci	}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	*curr_mute_mode = fmdev->rx.mute_mode;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	return 0;
40362306a36Sopenharmony_ci}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_cistatic int fm_config_rx_mute_reg(struct fmdev *fmdev)
40662306a36Sopenharmony_ci{
40762306a36Sopenharmony_ci	u16 payload, muteval;
40862306a36Sopenharmony_ci	int ret;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	muteval = 0;
41162306a36Sopenharmony_ci	switch (fmdev->rx.mute_mode) {
41262306a36Sopenharmony_ci	case FM_MUTE_ON:
41362306a36Sopenharmony_ci		muteval = FM_RX_AC_MUTE_MODE;
41462306a36Sopenharmony_ci		break;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	case FM_MUTE_OFF:
41762306a36Sopenharmony_ci		muteval = FM_RX_UNMUTE_MODE;
41862306a36Sopenharmony_ci		break;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	case FM_MUTE_ATTENUATE:
42162306a36Sopenharmony_ci		muteval = FM_RX_SOFT_MUTE_FORCE_MODE;
42262306a36Sopenharmony_ci		break;
42362306a36Sopenharmony_ci	}
42462306a36Sopenharmony_ci	if (fmdev->rx.rf_depend_mute == FM_RX_RF_DEPENDENT_MUTE_ON)
42562306a36Sopenharmony_ci		muteval |= FM_RX_RF_DEP_MODE;
42662306a36Sopenharmony_ci	else
42762306a36Sopenharmony_ci		muteval &= ~FM_RX_RF_DEP_MODE;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	payload = muteval;
43062306a36Sopenharmony_ci	ret = fmc_send_cmd(fmdev, MUTE_STATUS_SET, REG_WR, &payload,
43162306a36Sopenharmony_ci			sizeof(payload), NULL, NULL);
43262306a36Sopenharmony_ci	if (ret < 0)
43362306a36Sopenharmony_ci		return ret;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	return 0;
43662306a36Sopenharmony_ci}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci/* Configures mute mode (Mute Off/On/Attenuate) */
43962306a36Sopenharmony_ciint fm_rx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset)
44062306a36Sopenharmony_ci{
44162306a36Sopenharmony_ci	u8 org_state;
44262306a36Sopenharmony_ci	int ret;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	if (fmdev->rx.mute_mode == mute_mode_toset)
44562306a36Sopenharmony_ci		return 0;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	org_state = fmdev->rx.mute_mode;
44862306a36Sopenharmony_ci	fmdev->rx.mute_mode = mute_mode_toset;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	ret = fm_config_rx_mute_reg(fmdev);
45162306a36Sopenharmony_ci	if (ret < 0) {
45262306a36Sopenharmony_ci		fmdev->rx.mute_mode = org_state;
45362306a36Sopenharmony_ci		return ret;
45462306a36Sopenharmony_ci	}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	return 0;
45762306a36Sopenharmony_ci}
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci/* Gets RF dependent soft mute mode enable/disable status */
46062306a36Sopenharmony_ciint fm_rx_get_rfdepend_softmute(struct fmdev *fmdev, u8 *curr_mute_mode)
46162306a36Sopenharmony_ci{
46262306a36Sopenharmony_ci	if (fmdev->curr_fmmode != FM_MODE_RX)
46362306a36Sopenharmony_ci		return -EPERM;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	if (curr_mute_mode == NULL) {
46662306a36Sopenharmony_ci		fmerr("Invalid memory\n");
46762306a36Sopenharmony_ci		return -ENOMEM;
46862306a36Sopenharmony_ci	}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	*curr_mute_mode = fmdev->rx.rf_depend_mute;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	return 0;
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci/* Sets RF dependent soft mute mode */
47662306a36Sopenharmony_ciint fm_rx_set_rfdepend_softmute(struct fmdev *fmdev, u8 rfdepend_mute)
47762306a36Sopenharmony_ci{
47862306a36Sopenharmony_ci	u8 org_state;
47962306a36Sopenharmony_ci	int ret;
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	if (fmdev->curr_fmmode != FM_MODE_RX)
48262306a36Sopenharmony_ci		return -EPERM;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	if (rfdepend_mute != FM_RX_RF_DEPENDENT_MUTE_ON &&
48562306a36Sopenharmony_ci	    rfdepend_mute != FM_RX_RF_DEPENDENT_MUTE_OFF) {
48662306a36Sopenharmony_ci		fmerr("Invalid RF dependent soft mute\n");
48762306a36Sopenharmony_ci		return -EINVAL;
48862306a36Sopenharmony_ci	}
48962306a36Sopenharmony_ci	if (fmdev->rx.rf_depend_mute == rfdepend_mute)
49062306a36Sopenharmony_ci		return 0;
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	org_state = fmdev->rx.rf_depend_mute;
49362306a36Sopenharmony_ci	fmdev->rx.rf_depend_mute = rfdepend_mute;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	ret = fm_config_rx_mute_reg(fmdev);
49662306a36Sopenharmony_ci	if (ret < 0) {
49762306a36Sopenharmony_ci		fmdev->rx.rf_depend_mute = org_state;
49862306a36Sopenharmony_ci		return ret;
49962306a36Sopenharmony_ci	}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	return 0;
50262306a36Sopenharmony_ci}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci/* Returns the signal strength level of current channel */
50562306a36Sopenharmony_ciint fm_rx_get_rssi_level(struct fmdev *fmdev, u16 *rssilvl)
50662306a36Sopenharmony_ci{
50762306a36Sopenharmony_ci	__be16 curr_rssi_lel;
50862306a36Sopenharmony_ci	u32 resp_len;
50962306a36Sopenharmony_ci	int ret;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	if (rssilvl == NULL) {
51262306a36Sopenharmony_ci		fmerr("Invalid memory\n");
51362306a36Sopenharmony_ci		return -ENOMEM;
51462306a36Sopenharmony_ci	}
51562306a36Sopenharmony_ci	/* Read current RSSI level */
51662306a36Sopenharmony_ci	ret = fmc_send_cmd(fmdev, RSSI_LVL_GET, REG_RD, NULL, 2,
51762306a36Sopenharmony_ci			&curr_rssi_lel, &resp_len);
51862306a36Sopenharmony_ci	if (ret < 0)
51962306a36Sopenharmony_ci		return ret;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	*rssilvl = be16_to_cpu(curr_rssi_lel);
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	return 0;
52462306a36Sopenharmony_ci}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci/*
52762306a36Sopenharmony_ci * Sets the signal strength level that once reached
52862306a36Sopenharmony_ci * will stop the auto search process
52962306a36Sopenharmony_ci */
53062306a36Sopenharmony_ciint fm_rx_set_rssi_threshold(struct fmdev *fmdev, short rssi_lvl_toset)
53162306a36Sopenharmony_ci{
53262306a36Sopenharmony_ci	u16 payload;
53362306a36Sopenharmony_ci	int ret;
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	if (rssi_lvl_toset < FM_RX_RSSI_THRESHOLD_MIN ||
53662306a36Sopenharmony_ci			rssi_lvl_toset > FM_RX_RSSI_THRESHOLD_MAX) {
53762306a36Sopenharmony_ci		fmerr("Invalid RSSI threshold level\n");
53862306a36Sopenharmony_ci		return -EINVAL;
53962306a36Sopenharmony_ci	}
54062306a36Sopenharmony_ci	payload = (u16)rssi_lvl_toset;
54162306a36Sopenharmony_ci	ret = fmc_send_cmd(fmdev, SEARCH_LVL_SET, REG_WR, &payload,
54262306a36Sopenharmony_ci			sizeof(payload), NULL, NULL);
54362306a36Sopenharmony_ci	if (ret < 0)
54462306a36Sopenharmony_ci		return ret;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	fmdev->rx.rssi_threshold = rssi_lvl_toset;
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	return 0;
54962306a36Sopenharmony_ci}
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci/* Returns current RX RSSI threshold value */
55262306a36Sopenharmony_ciint fm_rx_get_rssi_threshold(struct fmdev *fmdev, short *curr_rssi_lvl)
55362306a36Sopenharmony_ci{
55462306a36Sopenharmony_ci	if (fmdev->curr_fmmode != FM_MODE_RX)
55562306a36Sopenharmony_ci		return -EPERM;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	if (curr_rssi_lvl == NULL) {
55862306a36Sopenharmony_ci		fmerr("Invalid memory\n");
55962306a36Sopenharmony_ci		return -ENOMEM;
56062306a36Sopenharmony_ci	}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	*curr_rssi_lvl = fmdev->rx.rssi_threshold;
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	return 0;
56562306a36Sopenharmony_ci}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci/* Sets RX stereo/mono modes */
56862306a36Sopenharmony_ciint fm_rx_set_stereo_mono(struct fmdev *fmdev, u16 mode)
56962306a36Sopenharmony_ci{
57062306a36Sopenharmony_ci	u16 payload;
57162306a36Sopenharmony_ci	int ret;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	if (mode != FM_STEREO_MODE && mode != FM_MONO_MODE) {
57462306a36Sopenharmony_ci		fmerr("Invalid mode\n");
57562306a36Sopenharmony_ci		return -EINVAL;
57662306a36Sopenharmony_ci	}
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	/* Set stereo/mono mode */
57962306a36Sopenharmony_ci	payload = (u16)mode;
58062306a36Sopenharmony_ci	ret = fmc_send_cmd(fmdev, MOST_MODE_SET, REG_WR, &payload,
58162306a36Sopenharmony_ci			sizeof(payload), NULL, NULL);
58262306a36Sopenharmony_ci	if (ret < 0)
58362306a36Sopenharmony_ci		return ret;
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	/* Set stereo blending mode */
58662306a36Sopenharmony_ci	payload = FM_STEREO_SOFT_BLEND;
58762306a36Sopenharmony_ci	ret = fmc_send_cmd(fmdev, MOST_BLEND_SET, REG_WR, &payload,
58862306a36Sopenharmony_ci			sizeof(payload), NULL, NULL);
58962306a36Sopenharmony_ci	if (ret < 0)
59062306a36Sopenharmony_ci		return ret;
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	return 0;
59362306a36Sopenharmony_ci}
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci/* Gets current RX stereo/mono mode */
59662306a36Sopenharmony_ciint fm_rx_get_stereo_mono(struct fmdev *fmdev, u16 *mode)
59762306a36Sopenharmony_ci{
59862306a36Sopenharmony_ci	__be16 curr_mode;
59962306a36Sopenharmony_ci	u32 resp_len;
60062306a36Sopenharmony_ci	int ret;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	if (mode == NULL) {
60362306a36Sopenharmony_ci		fmerr("Invalid memory\n");
60462306a36Sopenharmony_ci		return -ENOMEM;
60562306a36Sopenharmony_ci	}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	ret = fmc_send_cmd(fmdev, MOST_MODE_SET, REG_RD, NULL, 2,
60862306a36Sopenharmony_ci			&curr_mode, &resp_len);
60962306a36Sopenharmony_ci	if (ret < 0)
61062306a36Sopenharmony_ci		return ret;
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	*mode = be16_to_cpu(curr_mode);
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	return 0;
61562306a36Sopenharmony_ci}
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci/* Choose RX de-emphasis filter mode (50us/75us) */
61862306a36Sopenharmony_ciint fm_rx_set_deemphasis_mode(struct fmdev *fmdev, u16 mode)
61962306a36Sopenharmony_ci{
62062306a36Sopenharmony_ci	u16 payload;
62162306a36Sopenharmony_ci	int ret;
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	if (fmdev->curr_fmmode != FM_MODE_RX)
62462306a36Sopenharmony_ci		return -EPERM;
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	if (mode != FM_RX_EMPHASIS_FILTER_50_USEC &&
62762306a36Sopenharmony_ci			mode != FM_RX_EMPHASIS_FILTER_75_USEC) {
62862306a36Sopenharmony_ci		fmerr("Invalid rx de-emphasis mode (%d)\n", mode);
62962306a36Sopenharmony_ci		return -EINVAL;
63062306a36Sopenharmony_ci	}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	payload = mode;
63362306a36Sopenharmony_ci	ret = fmc_send_cmd(fmdev, DEMPH_MODE_SET, REG_WR, &payload,
63462306a36Sopenharmony_ci			sizeof(payload), NULL, NULL);
63562306a36Sopenharmony_ci	if (ret < 0)
63662306a36Sopenharmony_ci		return ret;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	fmdev->rx.deemphasis_mode = mode;
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	return 0;
64162306a36Sopenharmony_ci}
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci/* Gets current RX de-emphasis filter mode */
64462306a36Sopenharmony_ciint fm_rx_get_deemph_mode(struct fmdev *fmdev, u16 *curr_deemphasis_mode)
64562306a36Sopenharmony_ci{
64662306a36Sopenharmony_ci	if (fmdev->curr_fmmode != FM_MODE_RX)
64762306a36Sopenharmony_ci		return -EPERM;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	if (curr_deemphasis_mode == NULL) {
65062306a36Sopenharmony_ci		fmerr("Invalid memory\n");
65162306a36Sopenharmony_ci		return -ENOMEM;
65262306a36Sopenharmony_ci	}
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	*curr_deemphasis_mode = fmdev->rx.deemphasis_mode;
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	return 0;
65762306a36Sopenharmony_ci}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci/* Enable/Disable RX RDS */
66062306a36Sopenharmony_ciint fm_rx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis)
66162306a36Sopenharmony_ci{
66262306a36Sopenharmony_ci	u16 payload;
66362306a36Sopenharmony_ci	int ret;
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	if (rds_en_dis != FM_RDS_ENABLE && rds_en_dis != FM_RDS_DISABLE) {
66662306a36Sopenharmony_ci		fmerr("Invalid rds option\n");
66762306a36Sopenharmony_ci		return -EINVAL;
66862306a36Sopenharmony_ci	}
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	if (rds_en_dis == FM_RDS_ENABLE
67162306a36Sopenharmony_ci	    && fmdev->rx.rds.flag == FM_RDS_DISABLE) {
67262306a36Sopenharmony_ci		/* Turn on RX RDS and RDS circuit */
67362306a36Sopenharmony_ci		payload = FM_RX_PWR_SET_FM_AND_RDS_BLK_ON;
67462306a36Sopenharmony_ci		ret = fmc_send_cmd(fmdev, POWER_SET, REG_WR, &payload,
67562306a36Sopenharmony_ci				sizeof(payload), NULL, NULL);
67662306a36Sopenharmony_ci		if (ret < 0)
67762306a36Sopenharmony_ci			return ret;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci		/* Clear and reset RDS FIFO */
68062306a36Sopenharmony_ci		payload = FM_RX_RDS_FLUSH_FIFO;
68162306a36Sopenharmony_ci		ret = fmc_send_cmd(fmdev, RDS_CNTRL_SET, REG_WR, &payload,
68262306a36Sopenharmony_ci		sizeof(payload), NULL, NULL);
68362306a36Sopenharmony_ci		if (ret < 0)
68462306a36Sopenharmony_ci			return ret;
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci		/* Read flags - just to clear any pending interrupts. */
68762306a36Sopenharmony_ci		ret = fmc_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, 2,
68862306a36Sopenharmony_ci				NULL, NULL);
68962306a36Sopenharmony_ci		if (ret < 0)
69062306a36Sopenharmony_ci			return ret;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci		/* Set RDS FIFO threshold value */
69362306a36Sopenharmony_ci		payload = FM_RX_RDS_FIFO_THRESHOLD;
69462306a36Sopenharmony_ci		ret = fmc_send_cmd(fmdev, RDS_MEM_SET, REG_WR, &payload,
69562306a36Sopenharmony_ci		sizeof(payload), NULL, NULL);
69662306a36Sopenharmony_ci		if (ret < 0)
69762306a36Sopenharmony_ci			return ret;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci		/* Enable RDS interrupt */
70062306a36Sopenharmony_ci		fmdev->irq_info.mask |= FM_RDS_EVENT;
70162306a36Sopenharmony_ci		payload = fmdev->irq_info.mask;
70262306a36Sopenharmony_ci		ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
70362306a36Sopenharmony_ci				sizeof(payload), NULL, NULL);
70462306a36Sopenharmony_ci		if (ret < 0) {
70562306a36Sopenharmony_ci			fmdev->irq_info.mask &= ~FM_RDS_EVENT;
70662306a36Sopenharmony_ci			return ret;
70762306a36Sopenharmony_ci		}
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci		/* Update our local flag */
71062306a36Sopenharmony_ci		fmdev->rx.rds.flag = FM_RDS_ENABLE;
71162306a36Sopenharmony_ci	} else if (rds_en_dis == FM_RDS_DISABLE
71262306a36Sopenharmony_ci		   && fmdev->rx.rds.flag == FM_RDS_ENABLE) {
71362306a36Sopenharmony_ci		/* Turn off RX RDS */
71462306a36Sopenharmony_ci		payload = FM_RX_PWR_SET_FM_ON_RDS_OFF;
71562306a36Sopenharmony_ci		ret = fmc_send_cmd(fmdev, POWER_SET, REG_WR, &payload,
71662306a36Sopenharmony_ci				sizeof(payload), NULL, NULL);
71762306a36Sopenharmony_ci		if (ret < 0)
71862306a36Sopenharmony_ci			return ret;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci		/* Reset RDS pointers */
72162306a36Sopenharmony_ci		fmdev->rx.rds.last_blk_idx = 0;
72262306a36Sopenharmony_ci		fmdev->rx.rds.wr_idx = 0;
72362306a36Sopenharmony_ci		fmdev->rx.rds.rd_idx = 0;
72462306a36Sopenharmony_ci		fm_rx_reset_station_info(fmdev);
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci		/* Update RDS local cache */
72762306a36Sopenharmony_ci		fmdev->irq_info.mask &= ~(FM_RDS_EVENT);
72862306a36Sopenharmony_ci		fmdev->rx.rds.flag = FM_RDS_DISABLE;
72962306a36Sopenharmony_ci	}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	return 0;
73262306a36Sopenharmony_ci}
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci/* Returns current RX RDS enable/disable status */
73562306a36Sopenharmony_ciint fm_rx_get_rds_mode(struct fmdev *fmdev, u8 *curr_rds_en_dis)
73662306a36Sopenharmony_ci{
73762306a36Sopenharmony_ci	if (fmdev->curr_fmmode != FM_MODE_RX)
73862306a36Sopenharmony_ci		return -EPERM;
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	if (curr_rds_en_dis == NULL) {
74162306a36Sopenharmony_ci		fmerr("Invalid memory\n");
74262306a36Sopenharmony_ci		return -ENOMEM;
74362306a36Sopenharmony_ci	}
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	*curr_rds_en_dis = fmdev->rx.rds.flag;
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	return 0;
74862306a36Sopenharmony_ci}
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci/* Sets RDS operation mode (RDS/RDBS) */
75162306a36Sopenharmony_ciint fm_rx_set_rds_system(struct fmdev *fmdev, u8 rds_mode)
75262306a36Sopenharmony_ci{
75362306a36Sopenharmony_ci	u16 payload;
75462306a36Sopenharmony_ci	int ret;
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	if (fmdev->curr_fmmode != FM_MODE_RX)
75762306a36Sopenharmony_ci		return -EPERM;
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci	if (rds_mode != FM_RDS_SYSTEM_RDS && rds_mode != FM_RDS_SYSTEM_RBDS) {
76062306a36Sopenharmony_ci		fmerr("Invalid rds mode\n");
76162306a36Sopenharmony_ci		return -EINVAL;
76262306a36Sopenharmony_ci	}
76362306a36Sopenharmony_ci	/* Set RDS operation mode */
76462306a36Sopenharmony_ci	payload = (u16)rds_mode;
76562306a36Sopenharmony_ci	ret = fmc_send_cmd(fmdev, RDS_SYSTEM_SET, REG_WR, &payload,
76662306a36Sopenharmony_ci			sizeof(payload), NULL, NULL);
76762306a36Sopenharmony_ci	if (ret < 0)
76862306a36Sopenharmony_ci		return ret;
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	fmdev->rx.rds_mode = rds_mode;
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	return 0;
77362306a36Sopenharmony_ci}
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci/* Configures Alternate Frequency switch mode */
77662306a36Sopenharmony_ciint fm_rx_set_af_switch(struct fmdev *fmdev, u8 af_mode)
77762306a36Sopenharmony_ci{
77862306a36Sopenharmony_ci	u16 payload;
77962306a36Sopenharmony_ci	int ret;
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	if (fmdev->curr_fmmode != FM_MODE_RX)
78262306a36Sopenharmony_ci		return -EPERM;
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	if (af_mode != FM_RX_RDS_AF_SWITCH_MODE_ON &&
78562306a36Sopenharmony_ci	    af_mode != FM_RX_RDS_AF_SWITCH_MODE_OFF) {
78662306a36Sopenharmony_ci		fmerr("Invalid af mode\n");
78762306a36Sopenharmony_ci		return -EINVAL;
78862306a36Sopenharmony_ci	}
78962306a36Sopenharmony_ci	/* Enable/disable low RSSI interrupt based on af_mode */
79062306a36Sopenharmony_ci	if (af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON)
79162306a36Sopenharmony_ci		fmdev->irq_info.mask |= FM_LEV_EVENT;
79262306a36Sopenharmony_ci	else
79362306a36Sopenharmony_ci		fmdev->irq_info.mask &= ~FM_LEV_EVENT;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	payload = fmdev->irq_info.mask;
79662306a36Sopenharmony_ci	ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
79762306a36Sopenharmony_ci			sizeof(payload), NULL, NULL);
79862306a36Sopenharmony_ci	if (ret < 0)
79962306a36Sopenharmony_ci		return ret;
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	fmdev->rx.af_mode = af_mode;
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	return 0;
80462306a36Sopenharmony_ci}
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci/* Returns Alternate Frequency switch status */
80762306a36Sopenharmony_ciint fm_rx_get_af_switch(struct fmdev *fmdev, u8 *af_mode)
80862306a36Sopenharmony_ci{
80962306a36Sopenharmony_ci	if (fmdev->curr_fmmode != FM_MODE_RX)
81062306a36Sopenharmony_ci		return -EPERM;
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	if (af_mode == NULL) {
81362306a36Sopenharmony_ci		fmerr("Invalid memory\n");
81462306a36Sopenharmony_ci		return -ENOMEM;
81562306a36Sopenharmony_ci	}
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	*af_mode = fmdev->rx.af_mode;
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	return 0;
82062306a36Sopenharmony_ci}
821