1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114#include "radio-si470x.h"
115
116
117
118
119
120
121
122
123
124
125
126static unsigned short space = 2;
127module_param(space, ushort, 0444);
128MODULE_PARM_DESC(space, "Spacing: 0=200kHz 1=100kHz *2=50kHz*");
129
130
131
132
133
134static unsigned short band = 1;
135module_param(band, ushort, 0444);
136MODULE_PARM_DESC(band, "Band: 0=87.5..108MHz *1=76..108MHz* 2=76..90MHz");
137
138
139
140
141static unsigned short de = 1;
142module_param(de, ushort, 0444);
143MODULE_PARM_DESC(de, "De-emphasis: 0=75us *1=50us*");
144
145
146static unsigned int tune_timeout = 3000;
147module_param(tune_timeout, uint, 0644);
148MODULE_PARM_DESC(tune_timeout, "Tune timeout: *3000*");
149
150
151static unsigned int seek_timeout = 5000;
152module_param(seek_timeout, uint, 0644);
153MODULE_PARM_DESC(seek_timeout, "Seek timeout: *5000*");
154
155
156
157
158
159
160
161
162
163
164static int si470x_set_chan(struct si470x_device *radio, unsigned short chan)
165{
166 int retval;
167 unsigned long timeout;
168 bool timed_out = 0;
169
170
171 radio->registers[CHANNEL] &= ~CHANNEL_CHAN;
172 radio->registers[CHANNEL] |= CHANNEL_TUNE | chan;
173 retval = si470x_set_register(radio, CHANNEL);
174 if (retval < 0)
175 goto done;
176
177
178 timeout = jiffies + msecs_to_jiffies(tune_timeout);
179 do {
180 retval = si470x_get_register(radio, STATUSRSSI);
181 if (retval < 0)
182 goto stop;
183 timed_out = time_after(jiffies, timeout);
184 } while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) &&
185 (!timed_out));
186 if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
187 dev_warn(&radio->videodev->dev, "tune does not complete\n");
188 if (timed_out)
189 dev_warn(&radio->videodev->dev,
190 "tune timed out after %u ms\n", tune_timeout);
191
192stop:
193
194 radio->registers[CHANNEL] &= ~CHANNEL_TUNE;
195 retval = si470x_set_register(radio, CHANNEL);
196
197done:
198 return retval;
199}
200
201
202
203
204
205static int si470x_get_freq(struct si470x_device *radio, unsigned int *freq)
206{
207 unsigned int spacing, band_bottom;
208 unsigned short chan;
209 int retval;
210
211
212 switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_SPACE) >> 4) {
213
214 case 0:
215 spacing = 0.200 * FREQ_MUL; break;
216
217 case 1:
218 spacing = 0.100 * FREQ_MUL; break;
219
220 default:
221 spacing = 0.050 * FREQ_MUL; break;
222 };
223
224
225 switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
226
227 case 0:
228 band_bottom = 87.5 * FREQ_MUL; break;
229
230 default:
231 band_bottom = 76 * FREQ_MUL; break;
232
233 case 2:
234 band_bottom = 76 * FREQ_MUL; break;
235 };
236
237
238 retval = si470x_get_register(radio, READCHAN);
239 chan = radio->registers[READCHAN] & READCHAN_READCHAN;
240
241
242 *freq = chan * spacing + band_bottom;
243
244 return retval;
245}
246
247
248
249
250
251int si470x_set_freq(struct si470x_device *radio, unsigned int freq)
252{
253 unsigned int spacing, band_bottom;
254 unsigned short chan;
255
256
257 switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_SPACE) >> 4) {
258
259 case 0:
260 spacing = 0.200 * FREQ_MUL; break;
261
262 case 1:
263 spacing = 0.100 * FREQ_MUL; break;
264
265 default:
266 spacing = 0.050 * FREQ_MUL; break;
267 };
268
269
270 switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
271
272 case 0:
273 band_bottom = 87.5 * FREQ_MUL; break;
274
275 default:
276 band_bottom = 76 * FREQ_MUL; break;
277
278 case 2:
279 band_bottom = 76 * FREQ_MUL; break;
280 };
281
282
283 chan = (freq - band_bottom) / spacing;
284
285 return si470x_set_chan(radio, chan);
286}
287
288
289
290
291
292static int si470x_set_seek(struct si470x_device *radio,
293 unsigned int wrap_around, unsigned int seek_upward)
294{
295 int retval = 0;
296 unsigned long timeout;
297 bool timed_out = 0;
298
299
300 radio->registers[POWERCFG] |= POWERCFG_SEEK;
301 if (wrap_around == 1)
302 radio->registers[POWERCFG] &= ~POWERCFG_SKMODE;
303 else
304 radio->registers[POWERCFG] |= POWERCFG_SKMODE;
305 if (seek_upward == 1)
306 radio->registers[POWERCFG] |= POWERCFG_SEEKUP;
307 else
308 radio->registers[POWERCFG] &= ~POWERCFG_SEEKUP;
309 retval = si470x_set_register(radio, POWERCFG);
310 if (retval < 0)
311 goto done;
312
313
314 timeout = jiffies + msecs_to_jiffies(seek_timeout);
315 do {
316 retval = si470x_get_register(radio, STATUSRSSI);
317 if (retval < 0)
318 goto stop;
319 timed_out = time_after(jiffies, timeout);
320 } while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) &&
321 (!timed_out));
322 if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
323 dev_warn(&radio->videodev->dev, "seek does not complete\n");
324 if (radio->registers[STATUSRSSI] & STATUSRSSI_SF)
325 dev_warn(&radio->videodev->dev,
326 "seek failed / band limit reached\n");
327 if (timed_out)
328 dev_warn(&radio->videodev->dev,
329 "seek timed out after %u ms\n", seek_timeout);
330
331stop:
332
333 radio->registers[POWERCFG] &= ~POWERCFG_SEEK;
334 retval = si470x_set_register(radio, POWERCFG);
335
336done:
337
338 if ((retval == 0) && timed_out)
339 retval = -EAGAIN;
340
341 return retval;
342}
343
344
345
346
347
348int si470x_start(struct si470x_device *radio)
349{
350 int retval;
351
352
353 radio->registers[POWERCFG] =
354 POWERCFG_DMUTE | POWERCFG_ENABLE | POWERCFG_RDSM;
355 retval = si470x_set_register(radio, POWERCFG);
356 if (retval < 0)
357 goto done;
358
359
360 radio->registers[SYSCONFIG1] = SYSCONFIG1_DE;
361 retval = si470x_set_register(radio, SYSCONFIG1);
362 if (retval < 0)
363 goto done;
364
365
366 radio->registers[SYSCONFIG2] =
367 (0x3f << 8) |
368 ((band << 6) & SYSCONFIG2_BAND) |
369 ((space << 4) & SYSCONFIG2_SPACE) |
370 15;
371 retval = si470x_set_register(radio, SYSCONFIG2);
372 if (retval < 0)
373 goto done;
374
375
376 retval = si470x_set_chan(radio,
377 radio->registers[CHANNEL] & CHANNEL_CHAN);
378
379done:
380 return retval;
381}
382
383
384
385
386
387int si470x_stop(struct si470x_device *radio)
388{
389 int retval;
390
391
392 radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS;
393 retval = si470x_set_register(radio, SYSCONFIG1);
394 if (retval < 0)
395 goto done;
396
397
398 radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
399
400 radio->registers[POWERCFG] |= POWERCFG_ENABLE | POWERCFG_DISABLE;
401 retval = si470x_set_register(radio, POWERCFG);
402
403done:
404 return retval;
405}
406
407
408
409
410
411int si470x_rds_on(struct si470x_device *radio)
412{
413 int retval;
414
415
416 mutex_lock(&radio->lock);
417 radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDS;
418 retval = si470x_set_register(radio, SYSCONFIG1);
419 if (retval < 0)
420 radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS;
421 mutex_unlock(&radio->lock);
422
423 return retval;
424}
425
426
427
428
429
430
431
432
433
434
435static int si470x_vidioc_queryctrl(struct file *file, void *priv,
436 struct v4l2_queryctrl *qc)
437{
438 struct si470x_device *radio = video_drvdata(file);
439 int retval = -EINVAL;
440
441
442 if (qc->id < V4L2_CID_BASE)
443 goto done;
444
445
446 switch (qc->id) {
447 case V4L2_CID_AUDIO_VOLUME:
448 return v4l2_ctrl_query_fill(qc, 0, 15, 1, 15);
449 case V4L2_CID_AUDIO_MUTE:
450 return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
451 }
452
453
454
455 if ((retval == -EINVAL) && (qc->id < V4L2_CID_LASTP1)) {
456 qc->flags = V4L2_CTRL_FLAG_DISABLED;
457 retval = 0;
458 }
459
460done:
461 if (retval < 0)
462 dev_warn(&radio->videodev->dev,
463 "query controls failed with %d\n", retval);
464 return retval;
465}
466
467
468
469
470
471static int si470x_vidioc_g_ctrl(struct file *file, void *priv,
472 struct v4l2_control *ctrl)
473{
474 struct si470x_device *radio = video_drvdata(file);
475 int retval = 0;
476
477
478 retval = si470x_disconnect_check(radio);
479 if (retval)
480 goto done;
481
482 switch (ctrl->id) {
483 case V4L2_CID_AUDIO_VOLUME:
484 ctrl->value = radio->registers[SYSCONFIG2] &
485 SYSCONFIG2_VOLUME;
486 break;
487 case V4L2_CID_AUDIO_MUTE:
488 ctrl->value = ((radio->registers[POWERCFG] &
489 POWERCFG_DMUTE) == 0) ? 1 : 0;
490 break;
491 default:
492 retval = -EINVAL;
493 }
494
495done:
496 if (retval < 0)
497 dev_warn(&radio->videodev->dev,
498 "get control failed with %d\n", retval);
499 return retval;
500}
501
502
503
504
505
506static int si470x_vidioc_s_ctrl(struct file *file, void *priv,
507 struct v4l2_control *ctrl)
508{
509 struct si470x_device *radio = video_drvdata(file);
510 int retval = 0;
511
512
513 retval = si470x_disconnect_check(radio);
514 if (retval)
515 goto done;
516
517 switch (ctrl->id) {
518 case V4L2_CID_AUDIO_VOLUME:
519 radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME;
520 radio->registers[SYSCONFIG2] |= ctrl->value;
521 retval = si470x_set_register(radio, SYSCONFIG2);
522 break;
523 case V4L2_CID_AUDIO_MUTE:
524 if (ctrl->value == 1)
525 radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
526 else
527 radio->registers[POWERCFG] |= POWERCFG_DMUTE;
528 retval = si470x_set_register(radio, POWERCFG);
529 break;
530 default:
531 retval = -EINVAL;
532 }
533
534done:
535 if (retval < 0)
536 dev_warn(&radio->videodev->dev,
537 "set control failed with %d\n", retval);
538 return retval;
539}
540
541
542
543
544
545static int si470x_vidioc_g_audio(struct file *file, void *priv,
546 struct v4l2_audio *audio)
547{
548
549 audio->index = 0;
550 strcpy(audio->name, "Radio");
551 audio->capability = V4L2_AUDCAP_STEREO;
552 audio->mode = 0;
553
554 return 0;
555}
556
557
558
559
560
561static int si470x_vidioc_g_tuner(struct file *file, void *priv,
562 struct v4l2_tuner *tuner)
563{
564 struct si470x_device *radio = video_drvdata(file);
565 int retval = 0;
566
567
568 retval = si470x_disconnect_check(radio);
569 if (retval)
570 goto done;
571
572 if (tuner->index != 0) {
573 retval = -EINVAL;
574 goto done;
575 }
576
577 retval = si470x_get_register(radio, STATUSRSSI);
578 if (retval < 0)
579 goto done;
580
581
582 strcpy(tuner->name, "FM");
583 tuner->type = V4L2_TUNER_RADIO;
584#if defined(CONFIG_USB_SI470X) || defined(CONFIG_USB_SI470X_MODULE)
585 tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
586 V4L2_TUNER_CAP_RDS;
587#else
588 tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
589#endif
590
591
592 switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
593
594 default:
595 tuner->rangelow = 87.5 * FREQ_MUL;
596 tuner->rangehigh = 108 * FREQ_MUL;
597 break;
598
599 case 1:
600 tuner->rangelow = 76 * FREQ_MUL;
601 tuner->rangehigh = 108 * FREQ_MUL;
602 break;
603
604 case 2:
605 tuner->rangelow = 76 * FREQ_MUL;
606 tuner->rangehigh = 90 * FREQ_MUL;
607 break;
608 };
609
610
611 if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 0)
612 tuner->rxsubchans = V4L2_TUNER_SUB_MONO;
613 else
614 tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
615#if defined(CONFIG_USB_SI470X) || defined(CONFIG_USB_SI470X_MODULE)
616
617
618
619 tuner->rxsubchans |= V4L2_TUNER_SUB_RDS;
620#endif
621
622
623 if ((radio->registers[POWERCFG] & POWERCFG_MONO) == 0)
624 tuner->audmode = V4L2_TUNER_MODE_STEREO;
625 else
626 tuner->audmode = V4L2_TUNER_MODE_MONO;
627
628
629
630 tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI);
631
632 tuner->signal = (tuner->signal * 873) + (8 * tuner->signal / 10);
633
634
635
636 tuner->afc = (radio->registers[STATUSRSSI] & STATUSRSSI_AFCRL) ? 1 : 0;
637
638done:
639 if (retval < 0)
640 dev_warn(&radio->videodev->dev,
641 "get tuner failed with %d\n", retval);
642 return retval;
643}
644
645
646
647
648
649static int si470x_vidioc_s_tuner(struct file *file, void *priv,
650 struct v4l2_tuner *tuner)
651{
652 struct si470x_device *radio = video_drvdata(file);
653 int retval = -EINVAL;
654
655
656 retval = si470x_disconnect_check(radio);
657 if (retval)
658 goto done;
659
660 if (tuner->index != 0)
661 goto done;
662
663
664 switch (tuner->audmode) {
665 case V4L2_TUNER_MODE_MONO:
666 radio->registers[POWERCFG] |= POWERCFG_MONO;
667 break;
668 case V4L2_TUNER_MODE_STEREO:
669 radio->registers[POWERCFG] &= ~POWERCFG_MONO;
670 break;
671 default:
672 goto done;
673 }
674
675 retval = si470x_set_register(radio, POWERCFG);
676
677done:
678 if (retval < 0)
679 dev_warn(&radio->videodev->dev,
680 "set tuner failed with %d\n", retval);
681 return retval;
682}
683
684
685
686
687
688static int si470x_vidioc_g_frequency(struct file *file, void *priv,
689 struct v4l2_frequency *freq)
690{
691 struct si470x_device *radio = video_drvdata(file);
692 int retval = 0;
693
694
695 retval = si470x_disconnect_check(radio);
696 if (retval)
697 goto done;
698
699 if (freq->tuner != 0) {
700 retval = -EINVAL;
701 goto done;
702 }
703
704 freq->type = V4L2_TUNER_RADIO;
705 retval = si470x_get_freq(radio, &freq->frequency);
706
707done:
708 if (retval < 0)
709 dev_warn(&radio->videodev->dev,
710 "get frequency failed with %d\n", retval);
711 return retval;
712}
713
714
715
716
717
718static int si470x_vidioc_s_frequency(struct file *file, void *priv,
719 struct v4l2_frequency *freq)
720{
721 struct si470x_device *radio = video_drvdata(file);
722 int retval = 0;
723
724
725 retval = si470x_disconnect_check(radio);
726 if (retval)
727 goto done;
728
729 if (freq->tuner != 0) {
730 retval = -EINVAL;
731 goto done;
732 }
733
734 retval = si470x_set_freq(radio, freq->frequency);
735
736done:
737 if (retval < 0)
738 dev_warn(&radio->videodev->dev,
739 "set frequency failed with %d\n", retval);
740 return retval;
741}
742
743
744
745
746
747static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv,
748 struct v4l2_hw_freq_seek *seek)
749{
750 struct si470x_device *radio = video_drvdata(file);
751 int retval = 0;
752
753
754 retval = si470x_disconnect_check(radio);
755 if (retval)
756 goto done;
757
758 if (seek->tuner != 0) {
759 retval = -EINVAL;
760 goto done;
761 }
762
763 retval = si470x_set_seek(radio, seek->wrap_around, seek->seek_upward);
764
765done:
766 if (retval < 0)
767 dev_warn(&radio->videodev->dev,
768 "set hardware frequency seek failed with %d\n", retval);
769 return retval;
770}
771
772
773
774
775
776static const struct v4l2_ioctl_ops si470x_ioctl_ops = {
777 .vidioc_querycap = si470x_vidioc_querycap,
778 .vidioc_queryctrl = si470x_vidioc_queryctrl,
779 .vidioc_g_ctrl = si470x_vidioc_g_ctrl,
780 .vidioc_s_ctrl = si470x_vidioc_s_ctrl,
781 .vidioc_g_audio = si470x_vidioc_g_audio,
782 .vidioc_g_tuner = si470x_vidioc_g_tuner,
783 .vidioc_s_tuner = si470x_vidioc_s_tuner,
784 .vidioc_g_frequency = si470x_vidioc_g_frequency,
785 .vidioc_s_frequency = si470x_vidioc_s_frequency,
786 .vidioc_s_hw_freq_seek = si470x_vidioc_s_hw_freq_seek,
787};
788
789
790
791
792
793struct video_device si470x_viddev_template = {
794 .fops = &si470x_fops,
795 .name = DRIVER_NAME,
796 .release = video_device_release,
797 .ioctl_ops = &si470x_ioctl_ops,
798};
799