fmdrv_rx.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829
  1. /*
  2. * FM Driver for Connectivity chip of Texas Instruments.
  3. * This sub-module of FM driver implements FM RX functionality.
  4. *
  5. * Copyright (C) 2011 Texas Instruments
  6. * Author: Raja Mani <raja_mani@ti.com>
  7. * Author: Manjunatha Halli <manjunatha_halli@ti.com>
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License version 2 as
  11. * published by the Free Software Foundation.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. */
  19. #include "fmdrv.h"
  20. #include "fmdrv_common.h"
  21. #include "fmdrv_rx.h"
  22. void fm_rx_reset_rds_cache(struct fmdev *fmdev)
  23. {
  24. fmdev->rx.rds.flag = FM_RDS_DISABLE;
  25. fmdev->rx.rds.last_blk_idx = 0;
  26. fmdev->rx.rds.wr_idx = 0;
  27. fmdev->rx.rds.rd_idx = 0;
  28. if (fmdev->rx.af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON)
  29. fmdev->irq_info.mask |= FM_LEV_EVENT;
  30. }
  31. void fm_rx_reset_station_info(struct fmdev *fmdev)
  32. {
  33. fmdev->rx.stat_info.picode = FM_NO_PI_CODE;
  34. fmdev->rx.stat_info.afcache_size = 0;
  35. fmdev->rx.stat_info.af_list_max = 0;
  36. }
  37. int fm_rx_set_freq(struct fmdev *fmdev, u32 freq)
  38. {
  39. unsigned long timeleft;
  40. u16 payload, curr_frq, intr_flag;
  41. u32 curr_frq_in_khz;
  42. u32 resp_len;
  43. int ret;
  44. if (freq < fmdev->rx.region.bot_freq || freq > fmdev->rx.region.top_freq) {
  45. fmerr("Invalid frequency %d\n", freq);
  46. return -EINVAL;
  47. }
  48. /* Set audio enable */
  49. payload = FM_RX_AUDIO_ENABLE_I2S_AND_ANALOG;
  50. ret = fmc_send_cmd(fmdev, AUDIO_ENABLE_SET, REG_WR, &payload,
  51. sizeof(payload), NULL, NULL);
  52. if (ret < 0)
  53. return ret;
  54. /* Set hilo to automatic selection */
  55. payload = FM_RX_IFFREQ_HILO_AUTOMATIC;
  56. ret = fmc_send_cmd(fmdev, HILO_SET, REG_WR, &payload,
  57. sizeof(payload), NULL, NULL);
  58. if (ret < 0)
  59. return ret;
  60. /* Calculate frequency index and set*/
  61. payload = (freq - fmdev->rx.region.bot_freq) / FM_FREQ_MUL;
  62. ret = fmc_send_cmd(fmdev, FREQ_SET, REG_WR, &payload,
  63. sizeof(payload), NULL, NULL);
  64. if (ret < 0)
  65. return ret;
  66. /* Read flags - just to clear any pending interrupts if we had */
  67. ret = fmc_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, 2, NULL, NULL);
  68. if (ret < 0)
  69. return ret;
  70. /* Enable FR, BL interrupts */
  71. intr_flag = fmdev->irq_info.mask;
  72. fmdev->irq_info.mask = (FM_FR_EVENT | FM_BL_EVENT);
  73. payload = fmdev->irq_info.mask;
  74. ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
  75. sizeof(payload), NULL, NULL);
  76. if (ret < 0)
  77. return ret;
  78. /* Start tune */
  79. payload = FM_TUNER_PRESET_MODE;
  80. ret = fmc_send_cmd(fmdev, TUNER_MODE_SET, REG_WR, &payload,
  81. sizeof(payload), NULL, NULL);
  82. if (ret < 0)
  83. goto exit;
  84. /* Wait for tune ended interrupt */
  85. init_completion(&fmdev->maintask_comp);
  86. timeleft = wait_for_completion_timeout(&fmdev->maintask_comp,
  87. FM_DRV_TX_TIMEOUT);
  88. if (!timeleft) {
  89. fmerr("Timeout(%d sec),didn't get tune ended int\n",
  90. jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000);
  91. ret = -ETIMEDOUT;
  92. goto exit;
  93. }
  94. /* Read freq back to confirm */
  95. ret = fmc_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, 2, &curr_frq, &resp_len);
  96. if (ret < 0)
  97. goto exit;
  98. curr_frq = be16_to_cpu((__force __be16)curr_frq);
  99. curr_frq_in_khz = (fmdev->rx.region.bot_freq + ((u32)curr_frq * FM_FREQ_MUL));
  100. if (curr_frq_in_khz != freq) {
  101. pr_info("Frequency is set to (%d) but requested freq is (%d)\n",
  102. curr_frq_in_khz, freq);
  103. }
  104. /* Update local cache */
  105. fmdev->rx.freq = curr_frq_in_khz;
  106. exit:
  107. /* Re-enable default FM interrupts */
  108. fmdev->irq_info.mask = intr_flag;
  109. payload = fmdev->irq_info.mask;
  110. ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
  111. sizeof(payload), NULL, NULL);
  112. if (ret < 0)
  113. return ret;
  114. /* Reset RDS cache and current station pointers */
  115. fm_rx_reset_rds_cache(fmdev);
  116. fm_rx_reset_station_info(fmdev);
  117. return ret;
  118. }
  119. static int fm_rx_set_channel_spacing(struct fmdev *fmdev, u32 spacing)
  120. {
  121. u16 payload;
  122. int ret;
  123. if (spacing > 0 && spacing <= 50000)
  124. spacing = FM_CHANNEL_SPACING_50KHZ;
  125. else if (spacing > 50000 && spacing <= 100000)
  126. spacing = FM_CHANNEL_SPACING_100KHZ;
  127. else
  128. spacing = FM_CHANNEL_SPACING_200KHZ;
  129. /* set channel spacing */
  130. payload = spacing;
  131. ret = fmc_send_cmd(fmdev, CHANL_BW_SET, REG_WR, &payload,
  132. sizeof(payload), NULL, NULL);
  133. if (ret < 0)
  134. return ret;
  135. fmdev->rx.region.chanl_space = spacing * FM_FREQ_MUL;
  136. return ret;
  137. }
  138. int fm_rx_seek(struct fmdev *fmdev, u32 seek_upward,
  139. u32 wrap_around, u32 spacing)
  140. {
  141. u32 resp_len;
  142. u16 curr_frq, next_frq, last_frq;
  143. u16 payload, int_reason, intr_flag;
  144. u16 offset, space_idx;
  145. unsigned long timeleft;
  146. int ret;
  147. /* Set channel spacing */
  148. ret = fm_rx_set_channel_spacing(fmdev, spacing);
  149. if (ret < 0) {
  150. fmerr("Failed to set channel spacing\n");
  151. return ret;
  152. }
  153. /* Read the current frequency from chip */
  154. ret = fmc_send_cmd(fmdev, FREQ_SET, REG_RD, NULL,
  155. sizeof(curr_frq), &curr_frq, &resp_len);
  156. if (ret < 0)
  157. return ret;
  158. curr_frq = be16_to_cpu((__force __be16)curr_frq);
  159. last_frq = (fmdev->rx.region.top_freq - fmdev->rx.region.bot_freq) / FM_FREQ_MUL;
  160. /* Check the offset in order to be aligned to the channel spacing*/
  161. space_idx = fmdev->rx.region.chanl_space / FM_FREQ_MUL;
  162. offset = curr_frq % space_idx;
  163. next_frq = seek_upward ? curr_frq + space_idx /* Seek Up */ :
  164. curr_frq - space_idx /* Seek Down */ ;
  165. /*
  166. * Add or subtract offset in order to stay aligned to the channel
  167. * spacing.
  168. */
  169. if ((short)next_frq < 0)
  170. next_frq = last_frq - offset;
  171. else if (next_frq > last_frq)
  172. next_frq = 0 + offset;
  173. again:
  174. /* Set calculated next frequency to perform seek */
  175. payload = next_frq;
  176. ret = fmc_send_cmd(fmdev, FREQ_SET, REG_WR, &payload,
  177. sizeof(payload), NULL, NULL);
  178. if (ret < 0)
  179. return ret;
  180. /* Set search direction (0:Seek Down, 1:Seek Up) */
  181. payload = (seek_upward ? FM_SEARCH_DIRECTION_UP : FM_SEARCH_DIRECTION_DOWN);
  182. ret = fmc_send_cmd(fmdev, SEARCH_DIR_SET, REG_WR, &payload,
  183. sizeof(payload), NULL, NULL);
  184. if (ret < 0)
  185. return ret;
  186. /* Read flags - just to clear any pending interrupts if we had */
  187. ret = fmc_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, 2, NULL, NULL);
  188. if (ret < 0)
  189. return ret;
  190. /* Enable FR, BL interrupts */
  191. intr_flag = fmdev->irq_info.mask;
  192. fmdev->irq_info.mask = (FM_FR_EVENT | FM_BL_EVENT);
  193. payload = fmdev->irq_info.mask;
  194. ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
  195. sizeof(payload), NULL, NULL);
  196. if (ret < 0)
  197. return ret;
  198. /* Start seek */
  199. payload = FM_TUNER_AUTONOMOUS_SEARCH_MODE;
  200. ret = fmc_send_cmd(fmdev, TUNER_MODE_SET, REG_WR, &payload,
  201. sizeof(payload), NULL, NULL);
  202. if (ret < 0)
  203. return ret;
  204. /* Wait for tune ended/band limit reached interrupt */
  205. init_completion(&fmdev->maintask_comp);
  206. timeleft = wait_for_completion_timeout(&fmdev->maintask_comp,
  207. FM_DRV_RX_SEEK_TIMEOUT);
  208. if (!timeleft) {
  209. fmerr("Timeout(%d sec),didn't get tune ended int\n",
  210. jiffies_to_msecs(FM_DRV_RX_SEEK_TIMEOUT) / 1000);
  211. return -ENODATA;
  212. }
  213. int_reason = fmdev->irq_info.flag & (FM_TUNE_COMPLETE | FM_BAND_LIMIT);
  214. /* Re-enable default FM interrupts */
  215. fmdev->irq_info.mask = intr_flag;
  216. payload = fmdev->irq_info.mask;
  217. ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
  218. sizeof(payload), NULL, NULL);
  219. if (ret < 0)
  220. return ret;
  221. if (int_reason & FM_BL_EVENT) {
  222. if (wrap_around == 0) {
  223. fmdev->rx.freq = seek_upward ?
  224. fmdev->rx.region.top_freq :
  225. fmdev->rx.region.bot_freq;
  226. } else {
  227. fmdev->rx.freq = seek_upward ?
  228. fmdev->rx.region.bot_freq :
  229. fmdev->rx.region.top_freq;
  230. /* Calculate frequency index to write */
  231. next_frq = (fmdev->rx.freq -
  232. fmdev->rx.region.bot_freq) / FM_FREQ_MUL;
  233. goto again;
  234. }
  235. } else {
  236. /* Read freq to know where operation tune operation stopped */
  237. ret = fmc_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, 2,
  238. &curr_frq, &resp_len);
  239. if (ret < 0)
  240. return ret;
  241. curr_frq = be16_to_cpu((__force __be16)curr_frq);
  242. fmdev->rx.freq = (fmdev->rx.region.bot_freq +
  243. ((u32)curr_frq * FM_FREQ_MUL));
  244. }
  245. /* Reset RDS cache and current station pointers */
  246. fm_rx_reset_rds_cache(fmdev);
  247. fm_rx_reset_station_info(fmdev);
  248. return ret;
  249. }
  250. int fm_rx_set_volume(struct fmdev *fmdev, u16 vol_to_set)
  251. {
  252. u16 payload;
  253. int ret;
  254. if (fmdev->curr_fmmode != FM_MODE_RX)
  255. return -EPERM;
  256. if (vol_to_set > FM_RX_VOLUME_MAX) {
  257. fmerr("Volume is not within(%d-%d) range\n",
  258. FM_RX_VOLUME_MIN, FM_RX_VOLUME_MAX);
  259. return -EINVAL;
  260. }
  261. vol_to_set *= FM_RX_VOLUME_GAIN_STEP;
  262. payload = vol_to_set;
  263. ret = fmc_send_cmd(fmdev, VOLUME_SET, REG_WR, &payload,
  264. sizeof(payload), NULL, NULL);
  265. if (ret < 0)
  266. return ret;
  267. fmdev->rx.volume = vol_to_set;
  268. return ret;
  269. }
  270. /* Get volume */
  271. int fm_rx_get_volume(struct fmdev *fmdev, u16 *curr_vol)
  272. {
  273. if (fmdev->curr_fmmode != FM_MODE_RX)
  274. return -EPERM;
  275. if (curr_vol == NULL) {
  276. fmerr("Invalid memory\n");
  277. return -ENOMEM;
  278. }
  279. *curr_vol = fmdev->rx.volume / FM_RX_VOLUME_GAIN_STEP;
  280. return 0;
  281. }
  282. /* To get current band's bottom and top frequency */
  283. int fm_rx_get_band_freq_range(struct fmdev *fmdev, u32 *bot_freq, u32 *top_freq)
  284. {
  285. if (bot_freq != NULL)
  286. *bot_freq = fmdev->rx.region.bot_freq;
  287. if (top_freq != NULL)
  288. *top_freq = fmdev->rx.region.top_freq;
  289. return 0;
  290. }
  291. /* Returns current band index (0-Europe/US; 1-Japan) */
  292. void fm_rx_get_region(struct fmdev *fmdev, u8 *region)
  293. {
  294. *region = fmdev->rx.region.fm_band;
  295. }
  296. /* Sets band (0-Europe/US; 1-Japan) */
  297. int fm_rx_set_region(struct fmdev *fmdev, u8 region_to_set)
  298. {
  299. u16 payload;
  300. u32 new_frq = 0;
  301. int ret;
  302. if (region_to_set != FM_BAND_EUROPE_US &&
  303. region_to_set != FM_BAND_JAPAN) {
  304. fmerr("Invalid band\n");
  305. return -EINVAL;
  306. }
  307. if (fmdev->rx.region.fm_band == region_to_set) {
  308. fmerr("Requested band is already configured\n");
  309. return 0;
  310. }
  311. /* Send cmd to set the band */
  312. payload = (u16)region_to_set;
  313. ret = fmc_send_cmd(fmdev, BAND_SET, REG_WR, &payload,
  314. sizeof(payload), NULL, NULL);
  315. if (ret < 0)
  316. return ret;
  317. fmc_update_region_info(fmdev, region_to_set);
  318. /* Check whether current RX frequency is within band boundary */
  319. if (fmdev->rx.freq < fmdev->rx.region.bot_freq)
  320. new_frq = fmdev->rx.region.bot_freq;
  321. else if (fmdev->rx.freq > fmdev->rx.region.top_freq)
  322. new_frq = fmdev->rx.region.top_freq;
  323. if (new_frq) {
  324. fmdbg("Current freq is not within band limit boundary,switching to %d KHz\n",
  325. new_frq);
  326. /* Current RX frequency is not in range. So, update it */
  327. ret = fm_rx_set_freq(fmdev, new_frq);
  328. }
  329. return ret;
  330. }
  331. /* Reads current mute mode (Mute Off/On/Attenuate)*/
  332. int fm_rx_get_mute_mode(struct fmdev *fmdev, u8 *curr_mute_mode)
  333. {
  334. if (fmdev->curr_fmmode != FM_MODE_RX)
  335. return -EPERM;
  336. if (curr_mute_mode == NULL) {
  337. fmerr("Invalid memory\n");
  338. return -ENOMEM;
  339. }
  340. *curr_mute_mode = fmdev->rx.mute_mode;
  341. return 0;
  342. }
  343. static int fm_config_rx_mute_reg(struct fmdev *fmdev)
  344. {
  345. u16 payload, muteval;
  346. int ret;
  347. muteval = 0;
  348. switch (fmdev->rx.mute_mode) {
  349. case FM_MUTE_ON:
  350. muteval = FM_RX_AC_MUTE_MODE;
  351. break;
  352. case FM_MUTE_OFF:
  353. muteval = FM_RX_UNMUTE_MODE;
  354. break;
  355. case FM_MUTE_ATTENUATE:
  356. muteval = FM_RX_SOFT_MUTE_FORCE_MODE;
  357. break;
  358. }
  359. if (fmdev->rx.rf_depend_mute == FM_RX_RF_DEPENDENT_MUTE_ON)
  360. muteval |= FM_RX_RF_DEP_MODE;
  361. else
  362. muteval &= ~FM_RX_RF_DEP_MODE;
  363. payload = muteval;
  364. ret = fmc_send_cmd(fmdev, MUTE_STATUS_SET, REG_WR, &payload,
  365. sizeof(payload), NULL, NULL);
  366. if (ret < 0)
  367. return ret;
  368. return 0;
  369. }
  370. /* Configures mute mode (Mute Off/On/Attenuate) */
  371. int fm_rx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset)
  372. {
  373. u8 org_state;
  374. int ret;
  375. if (fmdev->rx.mute_mode == mute_mode_toset)
  376. return 0;
  377. org_state = fmdev->rx.mute_mode;
  378. fmdev->rx.mute_mode = mute_mode_toset;
  379. ret = fm_config_rx_mute_reg(fmdev);
  380. if (ret < 0) {
  381. fmdev->rx.mute_mode = org_state;
  382. return ret;
  383. }
  384. return 0;
  385. }
  386. /* Gets RF dependent soft mute mode enable/disable status */
  387. int fm_rx_get_rfdepend_softmute(struct fmdev *fmdev, u8 *curr_mute_mode)
  388. {
  389. if (fmdev->curr_fmmode != FM_MODE_RX)
  390. return -EPERM;
  391. if (curr_mute_mode == NULL) {
  392. fmerr("Invalid memory\n");
  393. return -ENOMEM;
  394. }
  395. *curr_mute_mode = fmdev->rx.rf_depend_mute;
  396. return 0;
  397. }
  398. /* Sets RF dependent soft mute mode */
  399. int fm_rx_set_rfdepend_softmute(struct fmdev *fmdev, u8 rfdepend_mute)
  400. {
  401. u8 org_state;
  402. int ret;
  403. if (fmdev->curr_fmmode != FM_MODE_RX)
  404. return -EPERM;
  405. if (rfdepend_mute != FM_RX_RF_DEPENDENT_MUTE_ON &&
  406. rfdepend_mute != FM_RX_RF_DEPENDENT_MUTE_OFF) {
  407. fmerr("Invalid RF dependent soft mute\n");
  408. return -EINVAL;
  409. }
  410. if (fmdev->rx.rf_depend_mute == rfdepend_mute)
  411. return 0;
  412. org_state = fmdev->rx.rf_depend_mute;
  413. fmdev->rx.rf_depend_mute = rfdepend_mute;
  414. ret = fm_config_rx_mute_reg(fmdev);
  415. if (ret < 0) {
  416. fmdev->rx.rf_depend_mute = org_state;
  417. return ret;
  418. }
  419. return 0;
  420. }
  421. /* Returns the signal strength level of current channel */
  422. int fm_rx_get_rssi_level(struct fmdev *fmdev, u16 *rssilvl)
  423. {
  424. __be16 curr_rssi_lel;
  425. u32 resp_len;
  426. int ret;
  427. if (rssilvl == NULL) {
  428. fmerr("Invalid memory\n");
  429. return -ENOMEM;
  430. }
  431. /* Read current RSSI level */
  432. ret = fmc_send_cmd(fmdev, RSSI_LVL_GET, REG_RD, NULL, 2,
  433. &curr_rssi_lel, &resp_len);
  434. if (ret < 0)
  435. return ret;
  436. *rssilvl = be16_to_cpu(curr_rssi_lel);
  437. return 0;
  438. }
  439. /*
  440. * Sets the signal strength level that once reached
  441. * will stop the auto search process
  442. */
  443. int fm_rx_set_rssi_threshold(struct fmdev *fmdev, short rssi_lvl_toset)
  444. {
  445. u16 payload;
  446. int ret;
  447. if (rssi_lvl_toset < FM_RX_RSSI_THRESHOLD_MIN ||
  448. rssi_lvl_toset > FM_RX_RSSI_THRESHOLD_MAX) {
  449. fmerr("Invalid RSSI threshold level\n");
  450. return -EINVAL;
  451. }
  452. payload = (u16)rssi_lvl_toset;
  453. ret = fmc_send_cmd(fmdev, SEARCH_LVL_SET, REG_WR, &payload,
  454. sizeof(payload), NULL, NULL);
  455. if (ret < 0)
  456. return ret;
  457. fmdev->rx.rssi_threshold = rssi_lvl_toset;
  458. return 0;
  459. }
  460. /* Returns current RX RSSI threshold value */
  461. int fm_rx_get_rssi_threshold(struct fmdev *fmdev, short *curr_rssi_lvl)
  462. {
  463. if (fmdev->curr_fmmode != FM_MODE_RX)
  464. return -EPERM;
  465. if (curr_rssi_lvl == NULL) {
  466. fmerr("Invalid memory\n");
  467. return -ENOMEM;
  468. }
  469. *curr_rssi_lvl = fmdev->rx.rssi_threshold;
  470. return 0;
  471. }
  472. /* Sets RX stereo/mono modes */
  473. int fm_rx_set_stereo_mono(struct fmdev *fmdev, u16 mode)
  474. {
  475. u16 payload;
  476. int ret;
  477. if (mode != FM_STEREO_MODE && mode != FM_MONO_MODE) {
  478. fmerr("Invalid mode\n");
  479. return -EINVAL;
  480. }
  481. /* Set stereo/mono mode */
  482. payload = (u16)mode;
  483. ret = fmc_send_cmd(fmdev, MOST_MODE_SET, REG_WR, &payload,
  484. sizeof(payload), NULL, NULL);
  485. if (ret < 0)
  486. return ret;
  487. /* Set stereo blending mode */
  488. payload = FM_STEREO_SOFT_BLEND;
  489. ret = fmc_send_cmd(fmdev, MOST_BLEND_SET, REG_WR, &payload,
  490. sizeof(payload), NULL, NULL);
  491. if (ret < 0)
  492. return ret;
  493. return 0;
  494. }
  495. /* Gets current RX stereo/mono mode */
  496. int fm_rx_get_stereo_mono(struct fmdev *fmdev, u16 *mode)
  497. {
  498. __be16 curr_mode;
  499. u32 resp_len;
  500. int ret;
  501. if (mode == NULL) {
  502. fmerr("Invalid memory\n");
  503. return -ENOMEM;
  504. }
  505. ret = fmc_send_cmd(fmdev, MOST_MODE_SET, REG_RD, NULL, 2,
  506. &curr_mode, &resp_len);
  507. if (ret < 0)
  508. return ret;
  509. *mode = be16_to_cpu(curr_mode);
  510. return 0;
  511. }
  512. /* Choose RX de-emphasis filter mode (50us/75us) */
  513. int fm_rx_set_deemphasis_mode(struct fmdev *fmdev, u16 mode)
  514. {
  515. u16 payload;
  516. int ret;
  517. if (fmdev->curr_fmmode != FM_MODE_RX)
  518. return -EPERM;
  519. if (mode != FM_RX_EMPHASIS_FILTER_50_USEC &&
  520. mode != FM_RX_EMPHASIS_FILTER_75_USEC) {
  521. fmerr("Invalid rx de-emphasis mode (%d)\n", mode);
  522. return -EINVAL;
  523. }
  524. payload = mode;
  525. ret = fmc_send_cmd(fmdev, DEMPH_MODE_SET, REG_WR, &payload,
  526. sizeof(payload), NULL, NULL);
  527. if (ret < 0)
  528. return ret;
  529. fmdev->rx.deemphasis_mode = mode;
  530. return 0;
  531. }
  532. /* Gets current RX de-emphasis filter mode */
  533. int fm_rx_get_deemph_mode(struct fmdev *fmdev, u16 *curr_deemphasis_mode)
  534. {
  535. if (fmdev->curr_fmmode != FM_MODE_RX)
  536. return -EPERM;
  537. if (curr_deemphasis_mode == NULL) {
  538. fmerr("Invalid memory\n");
  539. return -ENOMEM;
  540. }
  541. *curr_deemphasis_mode = fmdev->rx.deemphasis_mode;
  542. return 0;
  543. }
  544. /* Enable/Disable RX RDS */
  545. int fm_rx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis)
  546. {
  547. u16 payload;
  548. int ret;
  549. if (rds_en_dis != FM_RDS_ENABLE && rds_en_dis != FM_RDS_DISABLE) {
  550. fmerr("Invalid rds option\n");
  551. return -EINVAL;
  552. }
  553. if (rds_en_dis == FM_RDS_ENABLE
  554. && fmdev->rx.rds.flag == FM_RDS_DISABLE) {
  555. /* Turn on RX RDS and RDS circuit */
  556. payload = FM_RX_PWR_SET_FM_AND_RDS_BLK_ON;
  557. ret = fmc_send_cmd(fmdev, POWER_SET, REG_WR, &payload,
  558. sizeof(payload), NULL, NULL);
  559. if (ret < 0)
  560. return ret;
  561. /* Clear and reset RDS FIFO */
  562. payload = FM_RX_RDS_FLUSH_FIFO;
  563. ret = fmc_send_cmd(fmdev, RDS_CNTRL_SET, REG_WR, &payload,
  564. sizeof(payload), NULL, NULL);
  565. if (ret < 0)
  566. return ret;
  567. /* Read flags - just to clear any pending interrupts. */
  568. ret = fmc_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, 2,
  569. NULL, NULL);
  570. if (ret < 0)
  571. return ret;
  572. /* Set RDS FIFO threshold value */
  573. payload = FM_RX_RDS_FIFO_THRESHOLD;
  574. ret = fmc_send_cmd(fmdev, RDS_MEM_SET, REG_WR, &payload,
  575. sizeof(payload), NULL, NULL);
  576. if (ret < 0)
  577. return ret;
  578. /* Enable RDS interrupt */
  579. fmdev->irq_info.mask |= FM_RDS_EVENT;
  580. payload = fmdev->irq_info.mask;
  581. ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
  582. sizeof(payload), NULL, NULL);
  583. if (ret < 0) {
  584. fmdev->irq_info.mask &= ~FM_RDS_EVENT;
  585. return ret;
  586. }
  587. /* Update our local flag */
  588. fmdev->rx.rds.flag = FM_RDS_ENABLE;
  589. } else if (rds_en_dis == FM_RDS_DISABLE
  590. && fmdev->rx.rds.flag == FM_RDS_ENABLE) {
  591. /* Turn off RX RDS */
  592. payload = FM_RX_PWR_SET_FM_ON_RDS_OFF;
  593. ret = fmc_send_cmd(fmdev, POWER_SET, REG_WR, &payload,
  594. sizeof(payload), NULL, NULL);
  595. if (ret < 0)
  596. return ret;
  597. /* Reset RDS pointers */
  598. fmdev->rx.rds.last_blk_idx = 0;
  599. fmdev->rx.rds.wr_idx = 0;
  600. fmdev->rx.rds.rd_idx = 0;
  601. fm_rx_reset_station_info(fmdev);
  602. /* Update RDS local cache */
  603. fmdev->irq_info.mask &= ~(FM_RDS_EVENT);
  604. fmdev->rx.rds.flag = FM_RDS_DISABLE;
  605. }
  606. return 0;
  607. }
  608. /* Returns current RX RDS enable/disable status */
  609. int fm_rx_get_rds_mode(struct fmdev *fmdev, u8 *curr_rds_en_dis)
  610. {
  611. if (fmdev->curr_fmmode != FM_MODE_RX)
  612. return -EPERM;
  613. if (curr_rds_en_dis == NULL) {
  614. fmerr("Invalid memory\n");
  615. return -ENOMEM;
  616. }
  617. *curr_rds_en_dis = fmdev->rx.rds.flag;
  618. return 0;
  619. }
  620. /* Sets RDS operation mode (RDS/RDBS) */
  621. int fm_rx_set_rds_system(struct fmdev *fmdev, u8 rds_mode)
  622. {
  623. u16 payload;
  624. int ret;
  625. if (fmdev->curr_fmmode != FM_MODE_RX)
  626. return -EPERM;
  627. if (rds_mode != FM_RDS_SYSTEM_RDS && rds_mode != FM_RDS_SYSTEM_RBDS) {
  628. fmerr("Invalid rds mode\n");
  629. return -EINVAL;
  630. }
  631. /* Set RDS operation mode */
  632. payload = (u16)rds_mode;
  633. ret = fmc_send_cmd(fmdev, RDS_SYSTEM_SET, REG_WR, &payload,
  634. sizeof(payload), NULL, NULL);
  635. if (ret < 0)
  636. return ret;
  637. fmdev->rx.rds_mode = rds_mode;
  638. return 0;
  639. }
  640. /* Configures Alternate Frequency switch mode */
  641. int fm_rx_set_af_switch(struct fmdev *fmdev, u8 af_mode)
  642. {
  643. u16 payload;
  644. int ret;
  645. if (fmdev->curr_fmmode != FM_MODE_RX)
  646. return -EPERM;
  647. if (af_mode != FM_RX_RDS_AF_SWITCH_MODE_ON &&
  648. af_mode != FM_RX_RDS_AF_SWITCH_MODE_OFF) {
  649. fmerr("Invalid af mode\n");
  650. return -EINVAL;
  651. }
  652. /* Enable/disable low RSSI interrupt based on af_mode */
  653. if (af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON)
  654. fmdev->irq_info.mask |= FM_LEV_EVENT;
  655. else
  656. fmdev->irq_info.mask &= ~FM_LEV_EVENT;
  657. payload = fmdev->irq_info.mask;
  658. ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload,
  659. sizeof(payload), NULL, NULL);
  660. if (ret < 0)
  661. return ret;
  662. fmdev->rx.af_mode = af_mode;
  663. return 0;
  664. }
  665. /* Returns Alternate Frequency switch status */
  666. int fm_rx_get_af_switch(struct fmdev *fmdev, u8 *af_mode)
  667. {
  668. if (fmdev->curr_fmmode != FM_MODE_RX)
  669. return -EPERM;
  670. if (af_mode == NULL) {
  671. fmerr("Invalid memory\n");
  672. return -ENOMEM;
  673. }
  674. *af_mode = fmdev->rx.af_mode;
  675. return 0;
  676. }