radio-si470x-common.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * drivers/media/radio/si470x/radio-si470x-common.c
  4. *
  5. * Driver for radios with Silicon Labs Si470x FM Radio Receivers
  6. *
  7. * Copyright (c) 2009 Tobias Lorenz <[email protected]>
  8. * Copyright (c) 2012 Hans de Goede <[email protected]>
  9. */
  10. /*
  11. * History:
  12. * 2008-01-12 Tobias Lorenz <[email protected]>
  13. * Version 1.0.0
  14. * - First working version
  15. * 2008-01-13 Tobias Lorenz <[email protected]>
  16. * Version 1.0.1
  17. * - Improved error handling, every function now returns errno
  18. * - Improved multi user access (start/mute/stop)
  19. * - Channel doesn't get lost anymore after start/mute/stop
  20. * - RDS support added (polling mode via interrupt EP 1)
  21. * - marked default module parameters with *value*
  22. * - switched from bit structs to bit masks
  23. * - header file cleaned and integrated
  24. * 2008-01-14 Tobias Lorenz <[email protected]>
  25. * Version 1.0.2
  26. * - hex values are now lower case
  27. * - commented USB ID for ADS/Tech moved on todo list
  28. * - blacklisted si470x in hid-quirks.c
  29. * - rds buffer handling functions integrated into *_work, *_read
  30. * - rds_command in si470x_poll exchanged against simple retval
  31. * - check for firmware version 15
  32. * - code order and prototypes still remain the same
  33. * - spacing and bottom of band codes remain the same
  34. * 2008-01-16 Tobias Lorenz <[email protected]>
  35. * Version 1.0.3
  36. * - code reordered to avoid function prototypes
  37. * - switch/case defaults are now more user-friendly
  38. * - unified comment style
  39. * - applied all checkpatch.pl v1.12 suggestions
  40. * except the warning about the too long lines with bit comments
  41. * - renamed FMRADIO to RADIO to cut line length (checkpatch.pl)
  42. * 2008-01-22 Tobias Lorenz <[email protected]>
  43. * Version 1.0.4
  44. * - avoid poss. locking when doing copy_to_user which may sleep
  45. * - RDS is automatically activated on read now
  46. * - code cleaned of unnecessary rds_commands
  47. * - USB Vendor/Product ID for ADS/Tech FM Radio Receiver verified
  48. * (thanks to Guillaume RAMOUSSE)
  49. * 2008-01-27 Tobias Lorenz <[email protected]>
  50. * Version 1.0.5
  51. * - number of seek_retries changed to tune_timeout
  52. * - fixed problem with incomplete tune operations by own buffers
  53. * - optimization of variables and printf types
  54. * - improved error logging
  55. * 2008-01-31 Tobias Lorenz <[email protected]>
  56. * Oliver Neukum <[email protected]>
  57. * Version 1.0.6
  58. * - fixed coverity checker warnings in *_usb_driver_disconnect
  59. * - probe()/open() race by correct ordering in probe()
  60. * - DMA coherency rules by separate allocation of all buffers
  61. * - use of endianness macros
  62. * - abuse of spinlock, replaced by mutex
  63. * - racy handling of timer in disconnect,
  64. * replaced by delayed_work
  65. * - racy interruptible_sleep_on(),
  66. * replaced with wait_event_interruptible()
  67. * - handle signals in read()
  68. * 2008-02-08 Tobias Lorenz <[email protected]>
  69. * Oliver Neukum <[email protected]>
  70. * Version 1.0.7
  71. * - usb autosuspend support
  72. * - unplugging fixed
  73. * 2008-05-07 Tobias Lorenz <[email protected]>
  74. * Version 1.0.8
  75. * - hardware frequency seek support
  76. * - afc indication
  77. * - more safety checks, let si470x_get_freq return errno
  78. * - vidioc behavior corrected according to v4l2 spec
  79. * 2008-10-20 Alexey Klimov <[email protected]>
  80. * - add support for KWorld USB FM Radio FM700
  81. * - blacklisted KWorld radio in hid-core.c and hid-ids.h
  82. * 2008-12-03 Mark Lord <[email protected]>
  83. * - add support for DealExtreme USB Radio
  84. * 2009-01-31 Bob Ross <[email protected]>
  85. * - correction of stereo detection/setting
  86. * - correction of signal strength indicator scaling
  87. * 2009-01-31 Rick Bronson <[email protected]>
  88. * Tobias Lorenz <[email protected]>
  89. * - add LED status output
  90. * - get HW/SW version from scratchpad
  91. * 2009-06-16 Edouard Lafargue <[email protected]>
  92. * Version 1.0.10
  93. * - add support for interrupt mode for RDS endpoint,
  94. * instead of polling.
  95. * Improves RDS reception significantly
  96. */
  97. /* kernel includes */
  98. #include "radio-si470x.h"
  99. /**************************************************************************
  100. * Module Parameters
  101. **************************************************************************/
  102. /* Spacing (kHz) */
  103. /* 0: 200 kHz (USA, Australia) */
  104. /* 1: 100 kHz (Europe, Japan) */
  105. /* 2: 50 kHz */
  106. static unsigned short space = 2;
  107. module_param(space, ushort, 0444);
  108. MODULE_PARM_DESC(space, "Spacing: 0=200kHz 1=100kHz *2=50kHz*");
  109. /* De-emphasis */
  110. /* 0: 75 us (USA) */
  111. /* 1: 50 us (Europe, Australia, Japan) */
  112. static unsigned short de = 1;
  113. module_param(de, ushort, 0444);
  114. MODULE_PARM_DESC(de, "De-emphasis: 0=75us *1=50us*");
  115. /* Tune timeout */
  116. static unsigned int tune_timeout = 3000;
  117. module_param(tune_timeout, uint, 0644);
  118. MODULE_PARM_DESC(tune_timeout, "Tune timeout: *3000*");
  119. /* Seek timeout */
  120. static unsigned int seek_timeout = 5000;
  121. module_param(seek_timeout, uint, 0644);
  122. MODULE_PARM_DESC(seek_timeout, "Seek timeout: *5000*");
  123. static const struct v4l2_frequency_band bands[] = {
  124. {
  125. .type = V4L2_TUNER_RADIO,
  126. .index = 0,
  127. .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
  128. V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO |
  129. V4L2_TUNER_CAP_FREQ_BANDS |
  130. V4L2_TUNER_CAP_HWSEEK_BOUNDED |
  131. V4L2_TUNER_CAP_HWSEEK_WRAP,
  132. .rangelow = 87500 * 16,
  133. .rangehigh = 108000 * 16,
  134. .modulation = V4L2_BAND_MODULATION_FM,
  135. },
  136. {
  137. .type = V4L2_TUNER_RADIO,
  138. .index = 1,
  139. .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
  140. V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO |
  141. V4L2_TUNER_CAP_FREQ_BANDS |
  142. V4L2_TUNER_CAP_HWSEEK_BOUNDED |
  143. V4L2_TUNER_CAP_HWSEEK_WRAP,
  144. .rangelow = 76000 * 16,
  145. .rangehigh = 108000 * 16,
  146. .modulation = V4L2_BAND_MODULATION_FM,
  147. },
  148. {
  149. .type = V4L2_TUNER_RADIO,
  150. .index = 2,
  151. .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
  152. V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO |
  153. V4L2_TUNER_CAP_FREQ_BANDS |
  154. V4L2_TUNER_CAP_HWSEEK_BOUNDED |
  155. V4L2_TUNER_CAP_HWSEEK_WRAP,
  156. .rangelow = 76000 * 16,
  157. .rangehigh = 90000 * 16,
  158. .modulation = V4L2_BAND_MODULATION_FM,
  159. },
  160. };
  161. /**************************************************************************
  162. * Generic Functions
  163. **************************************************************************/
  164. /*
  165. * si470x_set_band - set the band
  166. */
  167. static int si470x_set_band(struct si470x_device *radio, int band)
  168. {
  169. if (radio->band == band)
  170. return 0;
  171. radio->band = band;
  172. radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_BAND;
  173. radio->registers[SYSCONFIG2] |= radio->band << 6;
  174. return radio->set_register(radio, SYSCONFIG2);
  175. }
  176. /*
  177. * si470x_set_chan - set the channel
  178. */
  179. static int si470x_set_chan(struct si470x_device *radio, unsigned short chan)
  180. {
  181. int retval;
  182. unsigned long time_left;
  183. bool timed_out = false;
  184. retval = radio->get_register(radio, POWERCFG);
  185. if (retval)
  186. return retval;
  187. if ((radio->registers[POWERCFG] & (POWERCFG_ENABLE|POWERCFG_DMUTE))
  188. != (POWERCFG_ENABLE|POWERCFG_DMUTE)) {
  189. return 0;
  190. }
  191. /* start tuning */
  192. radio->registers[CHANNEL] &= ~CHANNEL_CHAN;
  193. radio->registers[CHANNEL] |= CHANNEL_TUNE | chan;
  194. retval = radio->set_register(radio, CHANNEL);
  195. if (retval < 0)
  196. goto done;
  197. /* wait till tune operation has completed */
  198. reinit_completion(&radio->completion);
  199. time_left = wait_for_completion_timeout(&radio->completion,
  200. msecs_to_jiffies(tune_timeout));
  201. if (time_left == 0)
  202. timed_out = true;
  203. if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
  204. dev_warn(&radio->videodev.dev, "tune does not complete\n");
  205. if (timed_out)
  206. dev_warn(&radio->videodev.dev,
  207. "tune timed out after %u ms\n", tune_timeout);
  208. /* stop tuning */
  209. radio->registers[CHANNEL] &= ~CHANNEL_TUNE;
  210. retval = radio->set_register(radio, CHANNEL);
  211. done:
  212. return retval;
  213. }
  214. /*
  215. * si470x_get_step - get channel spacing
  216. */
  217. static unsigned int si470x_get_step(struct si470x_device *radio)
  218. {
  219. /* Spacing (kHz) */
  220. switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_SPACE) >> 4) {
  221. /* 0: 200 kHz (USA, Australia) */
  222. case 0:
  223. return 200 * 16;
  224. /* 1: 100 kHz (Europe, Japan) */
  225. case 1:
  226. return 100 * 16;
  227. /* 2: 50 kHz */
  228. default:
  229. return 50 * 16;
  230. }
  231. }
  232. /*
  233. * si470x_get_freq - get the frequency
  234. */
  235. static int si470x_get_freq(struct si470x_device *radio, unsigned int *freq)
  236. {
  237. int chan, retval;
  238. /* read channel */
  239. retval = radio->get_register(radio, READCHAN);
  240. chan = radio->registers[READCHAN] & READCHAN_READCHAN;
  241. /* Frequency (MHz) = Spacing (kHz) x Channel + Bottom of Band (MHz) */
  242. *freq = chan * si470x_get_step(radio) + bands[radio->band].rangelow;
  243. return retval;
  244. }
  245. /*
  246. * si470x_set_freq - set the frequency
  247. */
  248. int si470x_set_freq(struct si470x_device *radio, unsigned int freq)
  249. {
  250. unsigned short chan;
  251. freq = clamp(freq, bands[radio->band].rangelow,
  252. bands[radio->band].rangehigh);
  253. /* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */
  254. chan = (freq - bands[radio->band].rangelow) / si470x_get_step(radio);
  255. return si470x_set_chan(radio, chan);
  256. }
  257. EXPORT_SYMBOL_GPL(si470x_set_freq);
  258. /*
  259. * si470x_set_seek - set seek
  260. */
  261. static int si470x_set_seek(struct si470x_device *radio,
  262. const struct v4l2_hw_freq_seek *seek)
  263. {
  264. int band, retval;
  265. unsigned int freq;
  266. bool timed_out = false;
  267. unsigned long time_left;
  268. /* set band */
  269. if (seek->rangelow || seek->rangehigh) {
  270. for (band = 0; band < ARRAY_SIZE(bands); band++) {
  271. if (bands[band].rangelow == seek->rangelow &&
  272. bands[band].rangehigh == seek->rangehigh)
  273. break;
  274. }
  275. if (band == ARRAY_SIZE(bands))
  276. return -EINVAL; /* No matching band found */
  277. } else
  278. band = 1; /* If nothing is specified seek 76 - 108 Mhz */
  279. if (radio->band != band) {
  280. retval = si470x_get_freq(radio, &freq);
  281. if (retval)
  282. return retval;
  283. retval = si470x_set_band(radio, band);
  284. if (retval)
  285. return retval;
  286. retval = si470x_set_freq(radio, freq);
  287. if (retval)
  288. return retval;
  289. }
  290. /* start seeking */
  291. radio->registers[POWERCFG] |= POWERCFG_SEEK;
  292. if (seek->wrap_around)
  293. radio->registers[POWERCFG] &= ~POWERCFG_SKMODE;
  294. else
  295. radio->registers[POWERCFG] |= POWERCFG_SKMODE;
  296. if (seek->seek_upward)
  297. radio->registers[POWERCFG] |= POWERCFG_SEEKUP;
  298. else
  299. radio->registers[POWERCFG] &= ~POWERCFG_SEEKUP;
  300. retval = radio->set_register(radio, POWERCFG);
  301. if (retval < 0)
  302. return retval;
  303. /* wait till tune operation has completed */
  304. reinit_completion(&radio->completion);
  305. time_left = wait_for_completion_timeout(&radio->completion,
  306. msecs_to_jiffies(seek_timeout));
  307. if (time_left == 0)
  308. timed_out = true;
  309. if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
  310. dev_warn(&radio->videodev.dev, "seek does not complete\n");
  311. if (radio->registers[STATUSRSSI] & STATUSRSSI_SF)
  312. dev_warn(&radio->videodev.dev,
  313. "seek failed / band limit reached\n");
  314. /* stop seeking */
  315. radio->registers[POWERCFG] &= ~POWERCFG_SEEK;
  316. retval = radio->set_register(radio, POWERCFG);
  317. /* try again, if timed out */
  318. if (retval == 0 && timed_out)
  319. return -ENODATA;
  320. return retval;
  321. }
  322. /*
  323. * si470x_start - switch on radio
  324. */
  325. int si470x_start(struct si470x_device *radio)
  326. {
  327. int retval;
  328. /* powercfg */
  329. radio->registers[POWERCFG] =
  330. POWERCFG_DMUTE | POWERCFG_ENABLE | POWERCFG_RDSM;
  331. retval = radio->set_register(radio, POWERCFG);
  332. if (retval < 0)
  333. goto done;
  334. /* sysconfig 1 */
  335. radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDSIEN | SYSCONFIG1_STCIEN |
  336. SYSCONFIG1_RDS;
  337. radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_GPIO2;
  338. radio->registers[SYSCONFIG1] |= SYSCONFIG1_GPIO2_INT;
  339. if (de)
  340. radio->registers[SYSCONFIG1] |= SYSCONFIG1_DE;
  341. retval = radio->set_register(radio, SYSCONFIG1);
  342. if (retval < 0)
  343. goto done;
  344. /* sysconfig 2 */
  345. radio->registers[SYSCONFIG2] =
  346. (0x1f << 8) | /* SEEKTH */
  347. ((radio->band << 6) & SYSCONFIG2_BAND) |/* BAND */
  348. ((space << 4) & SYSCONFIG2_SPACE) | /* SPACE */
  349. 15; /* VOLUME (max) */
  350. retval = radio->set_register(radio, SYSCONFIG2);
  351. if (retval < 0)
  352. goto done;
  353. /* reset last channel */
  354. retval = si470x_set_chan(radio,
  355. radio->registers[CHANNEL] & CHANNEL_CHAN);
  356. done:
  357. return retval;
  358. }
  359. EXPORT_SYMBOL_GPL(si470x_start);
  360. /*
  361. * si470x_stop - switch off radio
  362. */
  363. int si470x_stop(struct si470x_device *radio)
  364. {
  365. int retval;
  366. /* sysconfig 1 */
  367. radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS;
  368. retval = radio->set_register(radio, SYSCONFIG1);
  369. if (retval < 0)
  370. goto done;
  371. /* powercfg */
  372. radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
  373. /* POWERCFG_ENABLE has to automatically go low */
  374. radio->registers[POWERCFG] |= POWERCFG_ENABLE | POWERCFG_DISABLE;
  375. retval = radio->set_register(radio, POWERCFG);
  376. done:
  377. return retval;
  378. }
  379. EXPORT_SYMBOL_GPL(si470x_stop);
  380. /*
  381. * si470x_rds_on - switch on rds reception
  382. */
  383. static int si470x_rds_on(struct si470x_device *radio)
  384. {
  385. int retval;
  386. /* sysconfig 1 */
  387. radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDS;
  388. retval = radio->set_register(radio, SYSCONFIG1);
  389. if (retval < 0)
  390. radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS;
  391. return retval;
  392. }
  393. /**************************************************************************
  394. * File Operations Interface
  395. **************************************************************************/
  396. /*
  397. * si470x_fops_read - read RDS data
  398. */
  399. static ssize_t si470x_fops_read(struct file *file, char __user *buf,
  400. size_t count, loff_t *ppos)
  401. {
  402. struct si470x_device *radio = video_drvdata(file);
  403. int retval = 0;
  404. unsigned int block_count = 0;
  405. /* switch on rds reception */
  406. if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
  407. si470x_rds_on(radio);
  408. /* block if no new data available */
  409. while (radio->wr_index == radio->rd_index) {
  410. if (file->f_flags & O_NONBLOCK) {
  411. retval = -EWOULDBLOCK;
  412. goto done;
  413. }
  414. if (wait_event_interruptible(radio->read_queue,
  415. radio->wr_index != radio->rd_index) < 0) {
  416. retval = -EINTR;
  417. goto done;
  418. }
  419. }
  420. /* calculate block count from byte count */
  421. count /= 3;
  422. /* copy RDS block out of internal buffer and to user buffer */
  423. while (block_count < count) {
  424. if (radio->rd_index == radio->wr_index)
  425. break;
  426. /* always transfer rds complete blocks */
  427. if (copy_to_user(buf, &radio->buffer[radio->rd_index], 3))
  428. /* retval = -EFAULT; */
  429. break;
  430. /* increment and wrap read pointer */
  431. radio->rd_index += 3;
  432. if (radio->rd_index >= radio->buf_size)
  433. radio->rd_index = 0;
  434. /* increment counters */
  435. block_count++;
  436. buf += 3;
  437. retval += 3;
  438. }
  439. done:
  440. return retval;
  441. }
  442. /*
  443. * si470x_fops_poll - poll RDS data
  444. */
  445. static __poll_t si470x_fops_poll(struct file *file,
  446. struct poll_table_struct *pts)
  447. {
  448. struct si470x_device *radio = video_drvdata(file);
  449. __poll_t req_events = poll_requested_events(pts);
  450. __poll_t retval = v4l2_ctrl_poll(file, pts);
  451. if (req_events & (EPOLLIN | EPOLLRDNORM)) {
  452. /* switch on rds reception */
  453. if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
  454. si470x_rds_on(radio);
  455. poll_wait(file, &radio->read_queue, pts);
  456. if (radio->rd_index != radio->wr_index)
  457. retval |= EPOLLIN | EPOLLRDNORM;
  458. }
  459. return retval;
  460. }
  461. static int si470x_fops_open(struct file *file)
  462. {
  463. struct si470x_device *radio = video_drvdata(file);
  464. return radio->fops_open(file);
  465. }
  466. /*
  467. * si470x_fops_release - file release
  468. */
  469. static int si470x_fops_release(struct file *file)
  470. {
  471. struct si470x_device *radio = video_drvdata(file);
  472. return radio->fops_release(file);
  473. }
  474. /*
  475. * si470x_fops - file operations interface
  476. */
  477. static const struct v4l2_file_operations si470x_fops = {
  478. .owner = THIS_MODULE,
  479. .read = si470x_fops_read,
  480. .poll = si470x_fops_poll,
  481. .unlocked_ioctl = video_ioctl2,
  482. .open = si470x_fops_open,
  483. .release = si470x_fops_release,
  484. };
  485. /**************************************************************************
  486. * Video4Linux Interface
  487. **************************************************************************/
  488. static int si470x_s_ctrl(struct v4l2_ctrl *ctrl)
  489. {
  490. struct si470x_device *radio =
  491. container_of(ctrl->handler, struct si470x_device, hdl);
  492. switch (ctrl->id) {
  493. case V4L2_CID_AUDIO_VOLUME:
  494. radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME;
  495. radio->registers[SYSCONFIG2] |= ctrl->val;
  496. return radio->set_register(radio, SYSCONFIG2);
  497. case V4L2_CID_AUDIO_MUTE:
  498. if (ctrl->val)
  499. radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
  500. else
  501. radio->registers[POWERCFG] |= POWERCFG_DMUTE;
  502. return radio->set_register(radio, POWERCFG);
  503. default:
  504. return -EINVAL;
  505. }
  506. }
  507. /*
  508. * si470x_vidioc_g_tuner - get tuner attributes
  509. */
  510. static int si470x_vidioc_g_tuner(struct file *file, void *priv,
  511. struct v4l2_tuner *tuner)
  512. {
  513. struct si470x_device *radio = video_drvdata(file);
  514. int retval = 0;
  515. if (tuner->index != 0)
  516. return -EINVAL;
  517. if (!radio->status_rssi_auto_update) {
  518. retval = radio->get_register(radio, STATUSRSSI);
  519. if (retval < 0)
  520. return retval;
  521. }
  522. /* driver constants */
  523. strscpy(tuner->name, "FM", sizeof(tuner->name));
  524. tuner->type = V4L2_TUNER_RADIO;
  525. tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
  526. V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO |
  527. V4L2_TUNER_CAP_HWSEEK_BOUNDED |
  528. V4L2_TUNER_CAP_HWSEEK_WRAP;
  529. tuner->rangelow = 76 * FREQ_MUL;
  530. tuner->rangehigh = 108 * FREQ_MUL;
  531. /* stereo indicator == stereo (instead of mono) */
  532. if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 0)
  533. tuner->rxsubchans = V4L2_TUNER_SUB_MONO;
  534. else
  535. tuner->rxsubchans = V4L2_TUNER_SUB_STEREO;
  536. /* If there is a reliable method of detecting an RDS channel,
  537. then this code should check for that before setting this
  538. RDS subchannel. */
  539. tuner->rxsubchans |= V4L2_TUNER_SUB_RDS;
  540. /* mono/stereo selector */
  541. if ((radio->registers[POWERCFG] & POWERCFG_MONO) == 0)
  542. tuner->audmode = V4L2_TUNER_MODE_STEREO;
  543. else
  544. tuner->audmode = V4L2_TUNER_MODE_MONO;
  545. /* min is worst, max is best; signal:0..0xffff; rssi: 0..0xff */
  546. /* measured in units of dbµV in 1 db increments (max at ~75 dbµV) */
  547. tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI);
  548. /* the ideal factor is 0xffff/75 = 873,8 */
  549. tuner->signal = (tuner->signal * 873) + (8 * tuner->signal / 10);
  550. if (tuner->signal > 0xffff)
  551. tuner->signal = 0xffff;
  552. /* automatic frequency control: -1: freq to low, 1 freq to high */
  553. /* AFCRL does only indicate that freq. differs, not if too low/high */
  554. tuner->afc = (radio->registers[STATUSRSSI] & STATUSRSSI_AFCRL) ? 1 : 0;
  555. return retval;
  556. }
  557. /*
  558. * si470x_vidioc_s_tuner - set tuner attributes
  559. */
  560. static int si470x_vidioc_s_tuner(struct file *file, void *priv,
  561. const struct v4l2_tuner *tuner)
  562. {
  563. struct si470x_device *radio = video_drvdata(file);
  564. if (tuner->index != 0)
  565. return -EINVAL;
  566. /* mono/stereo selector */
  567. switch (tuner->audmode) {
  568. case V4L2_TUNER_MODE_MONO:
  569. radio->registers[POWERCFG] |= POWERCFG_MONO; /* force mono */
  570. break;
  571. case V4L2_TUNER_MODE_STEREO:
  572. default:
  573. radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */
  574. break;
  575. }
  576. return radio->set_register(radio, POWERCFG);
  577. }
  578. /*
  579. * si470x_vidioc_g_frequency - get tuner or modulator radio frequency
  580. */
  581. static int si470x_vidioc_g_frequency(struct file *file, void *priv,
  582. struct v4l2_frequency *freq)
  583. {
  584. struct si470x_device *radio = video_drvdata(file);
  585. if (freq->tuner != 0)
  586. return -EINVAL;
  587. freq->type = V4L2_TUNER_RADIO;
  588. return si470x_get_freq(radio, &freq->frequency);
  589. }
  590. /*
  591. * si470x_vidioc_s_frequency - set tuner or modulator radio frequency
  592. */
  593. static int si470x_vidioc_s_frequency(struct file *file, void *priv,
  594. const struct v4l2_frequency *freq)
  595. {
  596. struct si470x_device *radio = video_drvdata(file);
  597. int retval;
  598. if (freq->tuner != 0)
  599. return -EINVAL;
  600. if (freq->frequency < bands[radio->band].rangelow ||
  601. freq->frequency > bands[radio->band].rangehigh) {
  602. /* Switch to band 1 which covers everything we support */
  603. retval = si470x_set_band(radio, 1);
  604. if (retval)
  605. return retval;
  606. }
  607. return si470x_set_freq(radio, freq->frequency);
  608. }
  609. /*
  610. * si470x_vidioc_s_hw_freq_seek - set hardware frequency seek
  611. */
  612. static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv,
  613. const struct v4l2_hw_freq_seek *seek)
  614. {
  615. struct si470x_device *radio = video_drvdata(file);
  616. if (seek->tuner != 0)
  617. return -EINVAL;
  618. if (file->f_flags & O_NONBLOCK)
  619. return -EWOULDBLOCK;
  620. return si470x_set_seek(radio, seek);
  621. }
  622. /*
  623. * si470x_vidioc_enum_freq_bands - enumerate supported bands
  624. */
  625. static int si470x_vidioc_enum_freq_bands(struct file *file, void *priv,
  626. struct v4l2_frequency_band *band)
  627. {
  628. if (band->tuner != 0)
  629. return -EINVAL;
  630. if (band->index >= ARRAY_SIZE(bands))
  631. return -EINVAL;
  632. *band = bands[band->index];
  633. return 0;
  634. }
  635. const struct v4l2_ctrl_ops si470x_ctrl_ops = {
  636. .s_ctrl = si470x_s_ctrl,
  637. };
  638. EXPORT_SYMBOL_GPL(si470x_ctrl_ops);
  639. static int si470x_vidioc_querycap(struct file *file, void *priv,
  640. struct v4l2_capability *capability)
  641. {
  642. struct si470x_device *radio = video_drvdata(file);
  643. return radio->vidioc_querycap(file, priv, capability);
  644. };
  645. /*
  646. * si470x_ioctl_ops - video device ioctl operations
  647. */
  648. static const struct v4l2_ioctl_ops si470x_ioctl_ops = {
  649. .vidioc_querycap = si470x_vidioc_querycap,
  650. .vidioc_g_tuner = si470x_vidioc_g_tuner,
  651. .vidioc_s_tuner = si470x_vidioc_s_tuner,
  652. .vidioc_g_frequency = si470x_vidioc_g_frequency,
  653. .vidioc_s_frequency = si470x_vidioc_s_frequency,
  654. .vidioc_s_hw_freq_seek = si470x_vidioc_s_hw_freq_seek,
  655. .vidioc_enum_freq_bands = si470x_vidioc_enum_freq_bands,
  656. .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
  657. .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
  658. };
  659. /*
  660. * si470x_viddev_template - video device interface
  661. */
  662. const struct video_device si470x_viddev_template = {
  663. .fops = &si470x_fops,
  664. .name = DRIVER_NAME,
  665. .release = video_device_release_empty,
  666. .ioctl_ops = &si470x_ioctl_ops,
  667. };
  668. EXPORT_SYMBOL_GPL(si470x_viddev_template);
  669. MODULE_LICENSE("GPL");