root/drivers/media/radio/wl128x/fmdrv_tx.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fm_tx_set_stereo_mono
  2. set_rds_text
  3. set_rds_data_mode
  4. set_rds_len
  5. fm_tx_set_rds_mode
  6. fm_tx_set_radio_text
  7. fm_tx_set_af
  8. fm_tx_set_region
  9. fm_tx_set_mute_mode
  10. set_audio_io
  11. enable_xmit
  12. fm_tx_set_pwr_lvl
  13. fm_tx_set_preemph_filter
  14. fm_tx_get_tune_cap_val
  15. fm_tx_set_freq

   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 
  14 int 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 
  36 static 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 
  56 static 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 
  79 static 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 
  95 int 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 
 138 int 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 
 166 int 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 
 186 int 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 
 206 int 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 */
 223 static 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 */
 241 static 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 */
 279 int 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  */
 318 int 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.*/
 350 int 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 */
 370 int 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 

/* [<][>][^][v][top][bottom][index][help] */