18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * FM Driver for Connectivity chip of Texas Instruments. 48c2ecf20Sopenharmony_ci * This sub-module of FM driver implements FM TX functionality. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2011 Texas Instruments 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/delay.h> 108c2ecf20Sopenharmony_ci#include "fmdrv.h" 118c2ecf20Sopenharmony_ci#include "fmdrv_common.h" 128c2ecf20Sopenharmony_ci#include "fmdrv_tx.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ciint fm_tx_set_stereo_mono(struct fmdev *fmdev, u16 mode) 158c2ecf20Sopenharmony_ci{ 168c2ecf20Sopenharmony_ci u16 payload; 178c2ecf20Sopenharmony_ci int ret; 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci if (fmdev->tx_data.aud_mode == mode) 208c2ecf20Sopenharmony_ci return 0; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci fmdbg("stereo mode: %d\n", mode); 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci /* Set Stereo/Mono mode */ 258c2ecf20Sopenharmony_ci payload = (1 - mode); 268c2ecf20Sopenharmony_ci ret = fmc_send_cmd(fmdev, MONO_SET, REG_WR, &payload, 278c2ecf20Sopenharmony_ci sizeof(payload), NULL, NULL); 288c2ecf20Sopenharmony_ci if (ret < 0) 298c2ecf20Sopenharmony_ci return ret; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci fmdev->tx_data.aud_mode = mode; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci return ret; 348c2ecf20Sopenharmony_ci} 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic int set_rds_text(struct fmdev *fmdev, u8 *rds_text) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci u16 payload; 398c2ecf20Sopenharmony_ci int ret; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci ret = fmc_send_cmd(fmdev, RDS_DATA_SET, REG_WR, rds_text, 428c2ecf20Sopenharmony_ci strlen(rds_text), NULL, NULL); 438c2ecf20Sopenharmony_ci if (ret < 0) 448c2ecf20Sopenharmony_ci return ret; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci /* Scroll mode */ 478c2ecf20Sopenharmony_ci payload = (u16)0x1; 488c2ecf20Sopenharmony_ci ret = fmc_send_cmd(fmdev, DISPLAY_MODE, REG_WR, &payload, 498c2ecf20Sopenharmony_ci sizeof(payload), NULL, NULL); 508c2ecf20Sopenharmony_ci if (ret < 0) 518c2ecf20Sopenharmony_ci return ret; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci return 0; 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic int set_rds_data_mode(struct fmdev *fmdev, u8 mode) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci u16 payload; 598c2ecf20Sopenharmony_ci int ret; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci /* Setting unique PI TODO: how unique? */ 628c2ecf20Sopenharmony_ci payload = (u16)0xcafe; 638c2ecf20Sopenharmony_ci ret = fmc_send_cmd(fmdev, PI_SET, REG_WR, &payload, 648c2ecf20Sopenharmony_ci sizeof(payload), NULL, NULL); 658c2ecf20Sopenharmony_ci if (ret < 0) 668c2ecf20Sopenharmony_ci return ret; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci /* Set decoder id */ 698c2ecf20Sopenharmony_ci payload = (u16)0xa; 708c2ecf20Sopenharmony_ci ret = fmc_send_cmd(fmdev, DI_SET, REG_WR, &payload, 718c2ecf20Sopenharmony_ci sizeof(payload), NULL, NULL); 728c2ecf20Sopenharmony_ci if (ret < 0) 738c2ecf20Sopenharmony_ci return ret; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci /* TODO: RDS_MODE_GET? */ 768c2ecf20Sopenharmony_ci return 0; 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic int set_rds_len(struct fmdev *fmdev, u8 type, u16 len) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci u16 payload; 828c2ecf20Sopenharmony_ci int ret; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci len |= type << 8; 858c2ecf20Sopenharmony_ci payload = len; 868c2ecf20Sopenharmony_ci ret = fmc_send_cmd(fmdev, RDS_CONFIG_DATA_SET, REG_WR, &payload, 878c2ecf20Sopenharmony_ci sizeof(payload), NULL, NULL); 888c2ecf20Sopenharmony_ci if (ret < 0) 898c2ecf20Sopenharmony_ci return ret; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci /* TODO: LENGTH_GET? */ 928c2ecf20Sopenharmony_ci return 0; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ciint fm_tx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci u16 payload; 988c2ecf20Sopenharmony_ci int ret; 998c2ecf20Sopenharmony_ci u8 rds_text[] = "Zoom2\n"; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci fmdbg("rds_en_dis:%d(E:%d, D:%d)\n", rds_en_dis, 1028c2ecf20Sopenharmony_ci FM_RDS_ENABLE, FM_RDS_DISABLE); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci if (rds_en_dis == FM_RDS_ENABLE) { 1058c2ecf20Sopenharmony_ci /* Set RDS length */ 1068c2ecf20Sopenharmony_ci set_rds_len(fmdev, 0, strlen(rds_text)); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci /* Set RDS text */ 1098c2ecf20Sopenharmony_ci set_rds_text(fmdev, rds_text); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci /* Set RDS mode */ 1128c2ecf20Sopenharmony_ci set_rds_data_mode(fmdev, 0x0); 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci /* Send command to enable RDS */ 1168c2ecf20Sopenharmony_ci if (rds_en_dis == FM_RDS_ENABLE) 1178c2ecf20Sopenharmony_ci payload = 0x01; 1188c2ecf20Sopenharmony_ci else 1198c2ecf20Sopenharmony_ci payload = 0x00; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci ret = fmc_send_cmd(fmdev, RDS_DATA_ENB, REG_WR, &payload, 1228c2ecf20Sopenharmony_ci sizeof(payload), NULL, NULL); 1238c2ecf20Sopenharmony_ci if (ret < 0) 1248c2ecf20Sopenharmony_ci return ret; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci if (rds_en_dis == FM_RDS_ENABLE) { 1278c2ecf20Sopenharmony_ci /* Set RDS length */ 1288c2ecf20Sopenharmony_ci set_rds_len(fmdev, 0, strlen(rds_text)); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci /* Set RDS text */ 1318c2ecf20Sopenharmony_ci set_rds_text(fmdev, rds_text); 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci fmdev->tx_data.rds.flag = rds_en_dis; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci return 0; 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ciint fm_tx_set_radio_text(struct fmdev *fmdev, u8 *rds_text, u8 rds_type) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci u16 payload; 1418c2ecf20Sopenharmony_ci int ret; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci if (fmdev->curr_fmmode != FM_MODE_TX) 1448c2ecf20Sopenharmony_ci return -EPERM; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci fm_tx_set_rds_mode(fmdev, 0); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci /* Set RDS length */ 1498c2ecf20Sopenharmony_ci set_rds_len(fmdev, rds_type, strlen(rds_text)); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci /* Set RDS text */ 1528c2ecf20Sopenharmony_ci set_rds_text(fmdev, rds_text); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci /* Set RDS mode */ 1558c2ecf20Sopenharmony_ci set_rds_data_mode(fmdev, 0x0); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci payload = 1; 1588c2ecf20Sopenharmony_ci ret = fmc_send_cmd(fmdev, RDS_DATA_ENB, REG_WR, &payload, 1598c2ecf20Sopenharmony_ci sizeof(payload), NULL, NULL); 1608c2ecf20Sopenharmony_ci if (ret < 0) 1618c2ecf20Sopenharmony_ci return ret; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci return 0; 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ciint fm_tx_set_af(struct fmdev *fmdev, u32 af) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci u16 payload; 1698c2ecf20Sopenharmony_ci int ret; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci if (fmdev->curr_fmmode != FM_MODE_TX) 1728c2ecf20Sopenharmony_ci return -EPERM; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci fmdbg("AF: %d\n", af); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci af = (af - 87500) / 100; 1778c2ecf20Sopenharmony_ci payload = (u16)af; 1788c2ecf20Sopenharmony_ci ret = fmc_send_cmd(fmdev, TA_SET, REG_WR, &payload, 1798c2ecf20Sopenharmony_ci sizeof(payload), NULL, NULL); 1808c2ecf20Sopenharmony_ci if (ret < 0) 1818c2ecf20Sopenharmony_ci return ret; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci return 0; 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ciint fm_tx_set_region(struct fmdev *fmdev, u8 region) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci u16 payload; 1898c2ecf20Sopenharmony_ci int ret; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci if (region != FM_BAND_EUROPE_US && region != FM_BAND_JAPAN) { 1928c2ecf20Sopenharmony_ci fmerr("Invalid band\n"); 1938c2ecf20Sopenharmony_ci return -EINVAL; 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci /* Send command to set the band */ 1978c2ecf20Sopenharmony_ci payload = (u16)region; 1988c2ecf20Sopenharmony_ci ret = fmc_send_cmd(fmdev, TX_BAND_SET, REG_WR, &payload, 1998c2ecf20Sopenharmony_ci sizeof(payload), NULL, NULL); 2008c2ecf20Sopenharmony_ci if (ret < 0) 2018c2ecf20Sopenharmony_ci return ret; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci return 0; 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ciint fm_tx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci u16 payload; 2098c2ecf20Sopenharmony_ci int ret; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci fmdbg("tx: mute mode %d\n", mute_mode_toset); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci payload = mute_mode_toset; 2148c2ecf20Sopenharmony_ci ret = fmc_send_cmd(fmdev, MUTE, REG_WR, &payload, 2158c2ecf20Sopenharmony_ci sizeof(payload), NULL, NULL); 2168c2ecf20Sopenharmony_ci if (ret < 0) 2178c2ecf20Sopenharmony_ci return ret; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci return 0; 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci/* Set TX Audio I/O */ 2238c2ecf20Sopenharmony_cistatic int set_audio_io(struct fmdev *fmdev) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci struct fmtx_data *tx = &fmdev->tx_data; 2268c2ecf20Sopenharmony_ci u16 payload; 2278c2ecf20Sopenharmony_ci int ret; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci /* Set Audio I/O Enable */ 2308c2ecf20Sopenharmony_ci payload = tx->audio_io; 2318c2ecf20Sopenharmony_ci ret = fmc_send_cmd(fmdev, AUDIO_IO_SET, REG_WR, &payload, 2328c2ecf20Sopenharmony_ci sizeof(payload), NULL, NULL); 2338c2ecf20Sopenharmony_ci if (ret < 0) 2348c2ecf20Sopenharmony_ci return ret; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci /* TODO: is audio set? */ 2378c2ecf20Sopenharmony_ci return 0; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci/* Start TX Transmission */ 2418c2ecf20Sopenharmony_cistatic int enable_xmit(struct fmdev *fmdev, u8 new_xmit_state) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci struct fmtx_data *tx = &fmdev->tx_data; 2448c2ecf20Sopenharmony_ci unsigned long timeleft; 2458c2ecf20Sopenharmony_ci u16 payload; 2468c2ecf20Sopenharmony_ci int ret; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* Enable POWER_ENB interrupts */ 2498c2ecf20Sopenharmony_ci payload = FM_POW_ENB_EVENT; 2508c2ecf20Sopenharmony_ci ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, 2518c2ecf20Sopenharmony_ci sizeof(payload), NULL, NULL); 2528c2ecf20Sopenharmony_ci if (ret < 0) 2538c2ecf20Sopenharmony_ci return ret; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci /* Set Power Enable */ 2568c2ecf20Sopenharmony_ci payload = new_xmit_state; 2578c2ecf20Sopenharmony_ci ret = fmc_send_cmd(fmdev, POWER_ENB_SET, REG_WR, &payload, 2588c2ecf20Sopenharmony_ci sizeof(payload), NULL, NULL); 2598c2ecf20Sopenharmony_ci if (ret < 0) 2608c2ecf20Sopenharmony_ci return ret; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci /* Wait for Power Enabled */ 2638c2ecf20Sopenharmony_ci init_completion(&fmdev->maintask_comp); 2648c2ecf20Sopenharmony_ci timeleft = wait_for_completion_timeout(&fmdev->maintask_comp, 2658c2ecf20Sopenharmony_ci FM_DRV_TX_TIMEOUT); 2668c2ecf20Sopenharmony_ci if (!timeleft) { 2678c2ecf20Sopenharmony_ci fmerr("Timeout(%d sec),didn't get tune ended interrupt\n", 2688c2ecf20Sopenharmony_ci jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000); 2698c2ecf20Sopenharmony_ci return -ETIMEDOUT; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci set_bit(FM_CORE_TX_XMITING, &fmdev->flag); 2738c2ecf20Sopenharmony_ci tx->xmit_state = new_xmit_state; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci return 0; 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci/* Set TX power level */ 2798c2ecf20Sopenharmony_ciint fm_tx_set_pwr_lvl(struct fmdev *fmdev, u8 new_pwr_lvl) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci u16 payload; 2828c2ecf20Sopenharmony_ci struct fmtx_data *tx = &fmdev->tx_data; 2838c2ecf20Sopenharmony_ci int ret; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if (fmdev->curr_fmmode != FM_MODE_TX) 2868c2ecf20Sopenharmony_ci return -EPERM; 2878c2ecf20Sopenharmony_ci fmdbg("tx: pwr_level_to_set %ld\n", (long int)new_pwr_lvl); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci /* If the core isn't ready update global variable */ 2908c2ecf20Sopenharmony_ci if (!test_bit(FM_CORE_READY, &fmdev->flag)) { 2918c2ecf20Sopenharmony_ci tx->pwr_lvl = new_pwr_lvl; 2928c2ecf20Sopenharmony_ci return 0; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci /* Set power level: Application will specify power level value in 2968c2ecf20Sopenharmony_ci * units of dB/uV, whereas range and step are specific to FM chip. 2978c2ecf20Sopenharmony_ci * For TI's WL chips, convert application specified power level value 2988c2ecf20Sopenharmony_ci * to chip specific value by subtracting 122 from it. Refer to TI FM 2998c2ecf20Sopenharmony_ci * data sheet for details. 3008c2ecf20Sopenharmony_ci * */ 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci payload = (FM_PWR_LVL_HIGH - new_pwr_lvl); 3038c2ecf20Sopenharmony_ci ret = fmc_send_cmd(fmdev, POWER_LEV_SET, REG_WR, &payload, 3048c2ecf20Sopenharmony_ci sizeof(payload), NULL, NULL); 3058c2ecf20Sopenharmony_ci if (ret < 0) 3068c2ecf20Sopenharmony_ci return ret; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci /* TODO: is the power level set? */ 3098c2ecf20Sopenharmony_ci tx->pwr_lvl = new_pwr_lvl; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci return 0; 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci/* 3158c2ecf20Sopenharmony_ci * Sets FM TX pre-emphasis filter value (OFF, 50us, or 75us) 3168c2ecf20Sopenharmony_ci * Convert V4L2 specified filter values to chip specific filter values. 3178c2ecf20Sopenharmony_ci */ 3188c2ecf20Sopenharmony_ciint fm_tx_set_preemph_filter(struct fmdev *fmdev, u32 preemphasis) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci struct fmtx_data *tx = &fmdev->tx_data; 3218c2ecf20Sopenharmony_ci u16 payload; 3228c2ecf20Sopenharmony_ci int ret; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci if (fmdev->curr_fmmode != FM_MODE_TX) 3258c2ecf20Sopenharmony_ci return -EPERM; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci switch (preemphasis) { 3288c2ecf20Sopenharmony_ci case V4L2_PREEMPHASIS_DISABLED: 3298c2ecf20Sopenharmony_ci payload = FM_TX_PREEMPH_OFF; 3308c2ecf20Sopenharmony_ci break; 3318c2ecf20Sopenharmony_ci case V4L2_PREEMPHASIS_50_uS: 3328c2ecf20Sopenharmony_ci payload = FM_TX_PREEMPH_50US; 3338c2ecf20Sopenharmony_ci break; 3348c2ecf20Sopenharmony_ci case V4L2_PREEMPHASIS_75_uS: 3358c2ecf20Sopenharmony_ci payload = FM_TX_PREEMPH_75US; 3368c2ecf20Sopenharmony_ci break; 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci ret = fmc_send_cmd(fmdev, PREMPH_SET, REG_WR, &payload, 3408c2ecf20Sopenharmony_ci sizeof(payload), NULL, NULL); 3418c2ecf20Sopenharmony_ci if (ret < 0) 3428c2ecf20Sopenharmony_ci return ret; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci tx->preemph = payload; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci return ret; 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci/* Get the TX tuning capacitor value.*/ 3508c2ecf20Sopenharmony_ciint fm_tx_get_tune_cap_val(struct fmdev *fmdev) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci u16 curr_val; 3538c2ecf20Sopenharmony_ci u32 resp_len; 3548c2ecf20Sopenharmony_ci int ret; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci if (fmdev->curr_fmmode != FM_MODE_TX) 3578c2ecf20Sopenharmony_ci return -EPERM; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci ret = fmc_send_cmd(fmdev, READ_FMANT_TUNE_VALUE, REG_RD, 3608c2ecf20Sopenharmony_ci NULL, sizeof(curr_val), &curr_val, &resp_len); 3618c2ecf20Sopenharmony_ci if (ret < 0) 3628c2ecf20Sopenharmony_ci return ret; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci curr_val = be16_to_cpu((__force __be16)curr_val); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci return curr_val; 3678c2ecf20Sopenharmony_ci} 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci/* Set TX Frequency */ 3708c2ecf20Sopenharmony_ciint fm_tx_set_freq(struct fmdev *fmdev, u32 freq_to_set) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci struct fmtx_data *tx = &fmdev->tx_data; 3738c2ecf20Sopenharmony_ci u16 payload, chanl_index; 3748c2ecf20Sopenharmony_ci int ret; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci if (test_bit(FM_CORE_TX_XMITING, &fmdev->flag)) { 3778c2ecf20Sopenharmony_ci enable_xmit(fmdev, 0); 3788c2ecf20Sopenharmony_ci clear_bit(FM_CORE_TX_XMITING, &fmdev->flag); 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci /* Enable FR, BL interrupts */ 3828c2ecf20Sopenharmony_ci payload = (FM_FR_EVENT | FM_BL_EVENT); 3838c2ecf20Sopenharmony_ci ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, 3848c2ecf20Sopenharmony_ci sizeof(payload), NULL, NULL); 3858c2ecf20Sopenharmony_ci if (ret < 0) 3868c2ecf20Sopenharmony_ci return ret; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci tx->tx_frq = (unsigned long)freq_to_set; 3898c2ecf20Sopenharmony_ci fmdbg("tx: freq_to_set %ld\n", (long int)tx->tx_frq); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci chanl_index = freq_to_set / 10; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci /* Set current tuner channel */ 3948c2ecf20Sopenharmony_ci payload = chanl_index; 3958c2ecf20Sopenharmony_ci ret = fmc_send_cmd(fmdev, CHANL_SET, REG_WR, &payload, 3968c2ecf20Sopenharmony_ci sizeof(payload), NULL, NULL); 3978c2ecf20Sopenharmony_ci if (ret < 0) 3988c2ecf20Sopenharmony_ci return ret; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci fm_tx_set_pwr_lvl(fmdev, tx->pwr_lvl); 4018c2ecf20Sopenharmony_ci fm_tx_set_preemph_filter(fmdev, tx->preemph); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci tx->audio_io = 0x01; /* I2S */ 4048c2ecf20Sopenharmony_ci set_audio_io(fmdev); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci enable_xmit(fmdev, 0x01); /* Enable transmission */ 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci tx->aud_mode = FM_STEREO_MODE; 4098c2ecf20Sopenharmony_ci tx->rds.flag = FM_RDS_DISABLE; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci return 0; 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 414