aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/radio
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-12-09 22:50:49 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-12-09 22:50:49 -0500
commit3e7468313758913c5e4d372f35b271b96bad1298 (patch)
treeeb612d252a9e2349a1173451cd779beebd18a33e /drivers/media/radio
parent6825fbc4cb219f2c98bb7d157915d797cf5cb823 (diff)
parente97f4677961f68e29bd906022ebf60a6df7f530a (diff)
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (345 commits) V4L/DVB (13542): ir-keytable: Allow dynamic table change V4L/DVB (13541): atbm8830: replace 64-bit division and floating point usage V4L/DVB (13540): ir-common: Cleanup get key evdev code V4L/DVB (13539): ir-common: add __func__ for debug messages V4L/DVB (13538): ir-common: Use a dynamic keycode table V4L/DVB (13537): ir: Prepare the code for dynamic keycode table allocation V4L/DVB (13536): em28xx: Use the full RC5 code on HVR-950 Remote Controller V4L/DVB (13535): ir-common: Add a hauppauge new table with the complete RC5 code V4L/DVB (13534): ir-common: Remove some unused fields/structs V4L/DVB (13533): ir: use dynamic tables, instead of static ones V4L/DVB (13532): ir-common: Add infrastructure to use a dynamic keycode table V4L/DVB (13531): ir-common: rename the debug routine to allow exporting it V4L/DVB (13458): go7007: subdev conversion V4L/DVB (13457): s2250: subdev conversion V4L/DVB (13456): s2250: Change module structure V4L/DVB (13528): em28xx: add support for em2800 VC211A card em28xx: don't reduce scale to half size for em2800 em28xx: don't load audio modules when AC97 is mis-detected em28xx: em2800 chips support max width of 640 V4L/DVB (13523): dvb-bt8xx: fix compile warning ... Fix up trivial conflicts due to spelling fixes from the trivial tree in Documentation/video4linux/gspca.txt drivers/media/video/cx18/cx18-mailbox.h
Diffstat (limited to 'drivers/media/radio')
-rw-r--r--drivers/media/radio/Kconfig12
-rw-r--r--drivers/media/radio/Makefile1
-rw-r--r--drivers/media/radio/radio-mr800.c358
-rw-r--r--drivers/media/radio/tef6862.c232
4 files changed, 412 insertions, 191 deletions
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index b134553eb3b..d4389963b31 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -419,4 +419,16 @@ config RADIO_TEA5764_XTAL
419 Say Y here if TEA5764 have a 32768 Hz crystal in circuit, say N 419 Say Y here if TEA5764 have a 32768 Hz crystal in circuit, say N
420 here if TEA5764 reference frequency is connected in FREQIN. 420 here if TEA5764 reference frequency is connected in FREQIN.
421 421
422config RADIO_TEF6862
423 tristate "TEF6862 Car Radio Enhanced Selectivity Tuner"
424 depends on I2C && VIDEO_V4L2
425 ---help---
426 Say Y here if you want to use the TEF6862 Car Radio Enhanced
427 Selectivity Tuner, found for instance on the Russellville development
428 board. On the russellville the device is connected to internal
429 timberdale I2C bus.
430
431 To compile this driver as a module, choose M here: the
432 module will be called TEF6862.
433
422endif # RADIO_ADAPTERS 434endif # RADIO_ADAPTERS
diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile
index 8a63d543ae4..01922ada691 100644
--- a/drivers/media/radio/Makefile
+++ b/drivers/media/radio/Makefile
@@ -23,5 +23,6 @@ obj-$(CONFIG_USB_DSBR) += dsbr100.o
23obj-$(CONFIG_RADIO_SI470X) += si470x/ 23obj-$(CONFIG_RADIO_SI470X) += si470x/
24obj-$(CONFIG_USB_MR800) += radio-mr800.o 24obj-$(CONFIG_USB_MR800) += radio-mr800.o
25obj-$(CONFIG_RADIO_TEA5764) += radio-tea5764.o 25obj-$(CONFIG_RADIO_TEA5764) += radio-tea5764.o
26obj-$(CONFIG_RADIO_TEF6862) += tef6862.o
26 27
27EXTRA_CFLAGS += -Isound 28EXTRA_CFLAGS += -Isound
diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c
index 5f79acb56e4..949f60513d9 100644
--- a/drivers/media/radio/radio-mr800.c
+++ b/drivers/media/radio/radio-mr800.c
@@ -85,6 +85,9 @@ MODULE_LICENSE("GPL");
85#define amradio_dev_warn(dev, fmt, arg...) \ 85#define amradio_dev_warn(dev, fmt, arg...) \
86 dev_warn(dev, MR800_DRIVER_NAME " - " fmt, ##arg) 86 dev_warn(dev, MR800_DRIVER_NAME " - " fmt, ##arg)
87 87
88#define amradio_dev_err(dev, fmt, arg...) \
89 dev_err(dev, MR800_DRIVER_NAME " - " fmt, ##arg)
90
88/* Probably USB_TIMEOUT should be modified in module parameter */ 91/* Probably USB_TIMEOUT should be modified in module parameter */
89#define BUFFER_LENGTH 8 92#define BUFFER_LENGTH 8
90#define USB_TIMEOUT 500 93#define USB_TIMEOUT 500
@@ -129,18 +132,20 @@ static int usb_amradio_resume(struct usb_interface *intf);
129struct amradio_device { 132struct amradio_device {
130 /* reference to USB and video device */ 133 /* reference to USB and video device */
131 struct usb_device *usbdev; 134 struct usb_device *usbdev;
132 struct video_device *videodev; 135 struct usb_interface *intf;
136 struct video_device videodev;
133 struct v4l2_device v4l2_dev; 137 struct v4l2_device v4l2_dev;
134 138
135 unsigned char *buffer; 139 unsigned char *buffer;
136 struct mutex lock; /* buffer locking */ 140 struct mutex lock; /* buffer locking */
137 int curfreq; 141 int curfreq;
138 int stereo; 142 int stereo;
139 int users;
140 int removed;
141 int muted; 143 int muted;
144 int initialized;
142}; 145};
143 146
147#define vdev_to_amradio(r) container_of(r, struct amradio_device, videodev)
148
144/* USB Device ID List */ 149/* USB Device ID List */
145static struct usb_device_id usb_amradio_device_table[] = { 150static struct usb_device_id usb_amradio_device_table[] = {
146 {USB_DEVICE_AND_INTERFACE_INFO(USB_AMRADIO_VENDOR, USB_AMRADIO_PRODUCT, 151 {USB_DEVICE_AND_INTERFACE_INFO(USB_AMRADIO_VENDOR, USB_AMRADIO_PRODUCT,
@@ -159,7 +164,7 @@ static struct usb_driver usb_amradio_driver = {
159 .resume = usb_amradio_resume, 164 .resume = usb_amradio_resume,
160 .reset_resume = usb_amradio_resume, 165 .reset_resume = usb_amradio_resume,
161 .id_table = usb_amradio_device_table, 166 .id_table = usb_amradio_device_table,
162 .supports_autosuspend = 0, 167 .supports_autosuspend = 1,
163}; 168};
164 169
165/* switch on/off the radio. Send 8 bytes to device */ 170/* switch on/off the radio. Send 8 bytes to device */
@@ -168,11 +173,7 @@ static int amradio_set_mute(struct amradio_device *radio, char argument)
168 int retval; 173 int retval;
169 int size; 174 int size;
170 175
171 /* safety check */ 176 BUG_ON(!mutex_is_locked(&radio->lock));
172 if (radio->removed)
173 return -EIO;
174
175 mutex_lock(&radio->lock);
176 177
177 radio->buffer[0] = 0x00; 178 radio->buffer[0] = 0x00;
178 radio->buffer[1] = 0x55; 179 radio->buffer[1] = 0x55;
@@ -187,14 +188,12 @@ static int amradio_set_mute(struct amradio_device *radio, char argument)
187 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); 188 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
188 189
189 if (retval < 0 || size != BUFFER_LENGTH) { 190 if (retval < 0 || size != BUFFER_LENGTH) {
190 mutex_unlock(&radio->lock); 191 amradio_dev_warn(&radio->videodev.dev, "set mute failed\n");
191 return retval; 192 return retval;
192 } 193 }
193 194
194 radio->muted = argument; 195 radio->muted = argument;
195 196
196 mutex_unlock(&radio->lock);
197
198 return retval; 197 return retval;
199} 198}
200 199
@@ -205,11 +204,7 @@ static int amradio_setfreq(struct amradio_device *radio, int freq)
205 int size; 204 int size;
206 unsigned short freq_send = 0x10 + (freq >> 3) / 25; 205 unsigned short freq_send = 0x10 + (freq >> 3) / 25;
207 206
208 /* safety check */ 207 BUG_ON(!mutex_is_locked(&radio->lock));
209 if (radio->removed)
210 return -EIO;
211
212 mutex_lock(&radio->lock);
213 208
214 radio->buffer[0] = 0x00; 209 radio->buffer[0] = 0x00;
215 radio->buffer[1] = 0x55; 210 radio->buffer[1] = 0x55;
@@ -223,10 +218,8 @@ static int amradio_setfreq(struct amradio_device *radio, int freq)
223 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), 218 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
224 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); 219 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
225 220
226 if (retval < 0 || size != BUFFER_LENGTH) { 221 if (retval < 0 || size != BUFFER_LENGTH)
227 mutex_unlock(&radio->lock); 222 goto out_err;
228 return retval;
229 }
230 223
231 /* frequency is calculated from freq_send and placed in first 2 bytes */ 224 /* frequency is calculated from freq_send and placed in first 2 bytes */
232 radio->buffer[0] = (freq_send >> 8) & 0xff; 225 radio->buffer[0] = (freq_send >> 8) & 0xff;
@@ -240,13 +233,15 @@ static int amradio_setfreq(struct amradio_device *radio, int freq)
240 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), 233 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
241 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); 234 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
242 235
243 if (retval < 0 || size != BUFFER_LENGTH) { 236 if (retval < 0 || size != BUFFER_LENGTH)
244 mutex_unlock(&radio->lock); 237 goto out_err;
245 return retval;
246 }
247 238
248 mutex_unlock(&radio->lock); 239 radio->curfreq = freq;
240 goto out;
249 241
242out_err:
243 amradio_dev_warn(&radio->videodev.dev, "set frequency failed\n");
244out:
250 return retval; 245 return retval;
251} 246}
252 247
@@ -255,11 +250,7 @@ static int amradio_set_stereo(struct amradio_device *radio, char argument)
255 int retval; 250 int retval;
256 int size; 251 int size;
257 252
258 /* safety check */ 253 BUG_ON(!mutex_is_locked(&radio->lock));
259 if (radio->removed)
260 return -EIO;
261
262 mutex_lock(&radio->lock);
263 254
264 radio->buffer[0] = 0x00; 255 radio->buffer[0] = 0x00;
265 radio->buffer[1] = 0x55; 256 radio->buffer[1] = 0x55;
@@ -274,14 +265,14 @@ static int amradio_set_stereo(struct amradio_device *radio, char argument)
274 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); 265 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
275 266
276 if (retval < 0 || size != BUFFER_LENGTH) { 267 if (retval < 0 || size != BUFFER_LENGTH) {
277 radio->stereo = -1; 268 amradio_dev_warn(&radio->videodev.dev, "set stereo failed\n");
278 mutex_unlock(&radio->lock);
279 return retval; 269 return retval;
280 } 270 }
281 271
282 radio->stereo = 1; 272 if (argument == WANT_STEREO)
283 273 radio->stereo = 1;
284 mutex_unlock(&radio->lock); 274 else
275 radio->stereo = 0;
285 276
286 return retval; 277 return retval;
287} 278}
@@ -296,19 +287,19 @@ static void usb_amradio_disconnect(struct usb_interface *intf)
296 struct amradio_device *radio = usb_get_intfdata(intf); 287 struct amradio_device *radio = usb_get_intfdata(intf);
297 288
298 mutex_lock(&radio->lock); 289 mutex_lock(&radio->lock);
299 radio->removed = 1; 290 radio->usbdev = NULL;
300 mutex_unlock(&radio->lock); 291 mutex_unlock(&radio->lock);
301 292
302 usb_set_intfdata(intf, NULL); 293 usb_set_intfdata(intf, NULL);
303 video_unregister_device(radio->videodev);
304 v4l2_device_disconnect(&radio->v4l2_dev); 294 v4l2_device_disconnect(&radio->v4l2_dev);
295 video_unregister_device(&radio->videodev);
305} 296}
306 297
307/* vidioc_querycap - query device capabilities */ 298/* vidioc_querycap - query device capabilities */
308static int vidioc_querycap(struct file *file, void *priv, 299static int vidioc_querycap(struct file *file, void *priv,
309 struct v4l2_capability *v) 300 struct v4l2_capability *v)
310{ 301{
311 struct amradio_device *radio = video_drvdata(file); 302 struct amradio_device *radio = file->private_data;
312 303
313 strlcpy(v->driver, "radio-mr800", sizeof(v->driver)); 304 strlcpy(v->driver, "radio-mr800", sizeof(v->driver));
314 strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card)); 305 strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card));
@@ -322,13 +313,9 @@ static int vidioc_querycap(struct file *file, void *priv,
322static int vidioc_g_tuner(struct file *file, void *priv, 313static int vidioc_g_tuner(struct file *file, void *priv,
323 struct v4l2_tuner *v) 314 struct v4l2_tuner *v)
324{ 315{
325 struct amradio_device *radio = video_get_drvdata(video_devdata(file)); 316 struct amradio_device *radio = file->private_data;
326 int retval; 317 int retval;
327 318
328 /* safety check */
329 if (radio->removed)
330 return -EIO;
331
332 if (v->index > 0) 319 if (v->index > 0)
333 return -EINVAL; 320 return -EINVAL;
334 321
@@ -341,9 +328,6 @@ static int vidioc_g_tuner(struct file *file, void *priv,
341 * amradio_set_stereo shouldn't be here 328 * amradio_set_stereo shouldn't be here
342 */ 329 */
343 retval = amradio_set_stereo(radio, WANT_STEREO); 330 retval = amradio_set_stereo(radio, WANT_STEREO);
344 if (retval < 0)
345 amradio_dev_warn(&radio->videodev->dev,
346 "set stereo failed\n");
347 331
348 strcpy(v->name, "FM"); 332 strcpy(v->name, "FM");
349 v->type = V4L2_TUNER_RADIO; 333 v->type = V4L2_TUNER_RADIO;
@@ -357,19 +341,16 @@ static int vidioc_g_tuner(struct file *file, void *priv,
357 v->audmode = V4L2_TUNER_MODE_MONO; 341 v->audmode = V4L2_TUNER_MODE_MONO;
358 v->signal = 0xffff; /* Can't get the signal strength, sad.. */ 342 v->signal = 0xffff; /* Can't get the signal strength, sad.. */
359 v->afc = 0; /* Don't know what is this */ 343 v->afc = 0; /* Don't know what is this */
360 return 0; 344
345 return retval;
361} 346}
362 347
363/* vidioc_s_tuner - set tuner attributes */ 348/* vidioc_s_tuner - set tuner attributes */
364static int vidioc_s_tuner(struct file *file, void *priv, 349static int vidioc_s_tuner(struct file *file, void *priv,
365 struct v4l2_tuner *v) 350 struct v4l2_tuner *v)
366{ 351{
367 struct amradio_device *radio = video_get_drvdata(video_devdata(file)); 352 struct amradio_device *radio = file->private_data;
368 int retval; 353 int retval = -EINVAL;
369
370 /* safety check */
371 if (radio->removed)
372 return -EIO;
373 354
374 if (v->index > 0) 355 if (v->index > 0)
375 return -EINVAL; 356 return -EINVAL;
@@ -378,57 +359,33 @@ static int vidioc_s_tuner(struct file *file, void *priv,
378 switch (v->audmode) { 359 switch (v->audmode) {
379 case V4L2_TUNER_MODE_MONO: 360 case V4L2_TUNER_MODE_MONO:
380 retval = amradio_set_stereo(radio, WANT_MONO); 361 retval = amradio_set_stereo(radio, WANT_MONO);
381 if (retval < 0)
382 amradio_dev_warn(&radio->videodev->dev,
383 "set mono failed\n");
384 break; 362 break;
385 case V4L2_TUNER_MODE_STEREO: 363 case V4L2_TUNER_MODE_STEREO:
386 retval = amradio_set_stereo(radio, WANT_STEREO); 364 retval = amradio_set_stereo(radio, WANT_STEREO);
387 if (retval < 0)
388 amradio_dev_warn(&radio->videodev->dev,
389 "set stereo failed\n");
390 break; 365 break;
391 default:
392 return -EINVAL;
393 } 366 }
394 367
395 return 0; 368 return retval;
396} 369}
397 370
398/* vidioc_s_frequency - set tuner radio frequency */ 371/* vidioc_s_frequency - set tuner radio frequency */
399static int vidioc_s_frequency(struct file *file, void *priv, 372static int vidioc_s_frequency(struct file *file, void *priv,
400 struct v4l2_frequency *f) 373 struct v4l2_frequency *f)
401{ 374{
402 struct amradio_device *radio = video_get_drvdata(video_devdata(file)); 375 struct amradio_device *radio = file->private_data;
403 int retval;
404 376
405 /* safety check */ 377 return amradio_setfreq(radio, f->frequency);
406 if (radio->removed)
407 return -EIO;
408
409 mutex_lock(&radio->lock);
410 radio->curfreq = f->frequency;
411 mutex_unlock(&radio->lock);
412
413 retval = amradio_setfreq(radio, radio->curfreq);
414 if (retval < 0)
415 amradio_dev_warn(&radio->videodev->dev,
416 "set frequency failed\n");
417 return 0;
418} 378}
419 379
420/* vidioc_g_frequency - get tuner radio frequency */ 380/* vidioc_g_frequency - get tuner radio frequency */
421static int vidioc_g_frequency(struct file *file, void *priv, 381static int vidioc_g_frequency(struct file *file, void *priv,
422 struct v4l2_frequency *f) 382 struct v4l2_frequency *f)
423{ 383{
424 struct amradio_device *radio = video_get_drvdata(video_devdata(file)); 384 struct amradio_device *radio = file->private_data;
425
426 /* safety check */
427 if (radio->removed)
428 return -EIO;
429 385
430 f->type = V4L2_TUNER_RADIO; 386 f->type = V4L2_TUNER_RADIO;
431 f->frequency = radio->curfreq; 387 f->frequency = radio->curfreq;
388
432 return 0; 389 return 0;
433} 390}
434 391
@@ -448,17 +405,14 @@ static int vidioc_queryctrl(struct file *file, void *priv,
448static int vidioc_g_ctrl(struct file *file, void *priv, 405static int vidioc_g_ctrl(struct file *file, void *priv,
449 struct v4l2_control *ctrl) 406 struct v4l2_control *ctrl)
450{ 407{
451 struct amradio_device *radio = video_get_drvdata(video_devdata(file)); 408 struct amradio_device *radio = file->private_data;
452
453 /* safety check */
454 if (radio->removed)
455 return -EIO;
456 409
457 switch (ctrl->id) { 410 switch (ctrl->id) {
458 case V4L2_CID_AUDIO_MUTE: 411 case V4L2_CID_AUDIO_MUTE:
459 ctrl->value = radio->muted; 412 ctrl->value = radio->muted;
460 return 0; 413 return 0;
461 } 414 }
415
462 return -EINVAL; 416 return -EINVAL;
463} 417}
464 418
@@ -466,33 +420,20 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
466static int vidioc_s_ctrl(struct file *file, void *priv, 420static int vidioc_s_ctrl(struct file *file, void *priv,
467 struct v4l2_control *ctrl) 421 struct v4l2_control *ctrl)
468{ 422{
469 struct amradio_device *radio = video_get_drvdata(video_devdata(file)); 423 struct amradio_device *radio = file->private_data;
470 int retval; 424 int retval = -EINVAL;
471
472 /* safety check */
473 if (radio->removed)
474 return -EIO;
475 425
476 switch (ctrl->id) { 426 switch (ctrl->id) {
477 case V4L2_CID_AUDIO_MUTE: 427 case V4L2_CID_AUDIO_MUTE:
478 if (ctrl->value) { 428 if (ctrl->value)
479 retval = amradio_set_mute(radio, AMRADIO_STOP); 429 retval = amradio_set_mute(radio, AMRADIO_STOP);
480 if (retval < 0) { 430 else
481 amradio_dev_warn(&radio->videodev->dev,
482 "amradio_stop failed\n");
483 return -1;
484 }
485 } else {
486 retval = amradio_set_mute(radio, AMRADIO_START); 431 retval = amradio_set_mute(radio, AMRADIO_START);
487 if (retval < 0) { 432
488 amradio_dev_warn(&radio->videodev->dev, 433 break;
489 "amradio_start failed\n");
490 return -1;
491 }
492 }
493 return 0;
494 } 434 }
495 return -EINVAL; 435
436 return retval;
496} 437}
497 438
498/* vidioc_g_audio - get audio attributes */ 439/* vidioc_g_audio - get audio attributes */
@@ -531,75 +472,108 @@ static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
531 return 0; 472 return 0;
532} 473}
533 474
534/* open device - amradio_start() and amradio_setfreq() */ 475static int usb_amradio_init(struct amradio_device *radio)
535static int usb_amradio_open(struct file *file)
536{ 476{
537 struct amradio_device *radio = video_get_drvdata(video_devdata(file));
538 int retval; 477 int retval;
539 478
540 lock_kernel(); 479 retval = amradio_set_mute(radio, AMRADIO_STOP);
480 if (retval)
481 goto out_err;
541 482
542 radio->users = 1; 483 retval = amradio_set_stereo(radio, WANT_STEREO);
543 radio->muted = 1; 484 if (retval)
485 goto out_err;
544 486
545 retval = amradio_set_mute(radio, AMRADIO_START); 487 radio->initialized = 1;
546 if (retval < 0) { 488 goto out;
547 amradio_dev_warn(&radio->videodev->dev, 489
548 "radio did not start up properly\n"); 490out_err:
549 radio->users = 0; 491 amradio_dev_err(&radio->videodev.dev, "initialization failed\n");
550 unlock_kernel(); 492out:
551 return -EIO; 493 return retval;
494}
495
496/* open device - amradio_start() and amradio_setfreq() */
497static int usb_amradio_open(struct file *file)
498{
499 struct amradio_device *radio = vdev_to_amradio(video_devdata(file));
500 int retval = 0;
501
502 mutex_lock(&radio->lock);
503
504 if (!radio->usbdev) {
505 retval = -EIO;
506 goto unlock;
552 } 507 }
553 508
554 retval = amradio_set_stereo(radio, WANT_STEREO); 509 file->private_data = radio;
555 if (retval < 0) 510 retval = usb_autopm_get_interface(radio->intf);
556 amradio_dev_warn(&radio->videodev->dev, 511 if (retval)
557 "set stereo failed\n"); 512 goto unlock;
558 513
559 retval = amradio_setfreq(radio, radio->curfreq); 514 if (unlikely(!radio->initialized)) {
560 if (retval < 0) 515 retval = usb_amradio_init(radio);
561 amradio_dev_warn(&radio->videodev->dev, 516 if (retval)
562 "set frequency failed\n"); 517 usb_autopm_put_interface(radio->intf);
518 }
563 519
564 unlock_kernel(); 520unlock:
565 return 0; 521 mutex_unlock(&radio->lock);
522 return retval;
566} 523}
567 524
568/*close device */ 525/*close device */
569static int usb_amradio_close(struct file *file) 526static int usb_amradio_close(struct file *file)
570{ 527{
571 struct amradio_device *radio = video_get_drvdata(video_devdata(file)); 528 struct amradio_device *radio = file->private_data;
572 int retval; 529 int retval = 0;
573
574 if (!radio)
575 return -ENODEV;
576 530
577 mutex_lock(&radio->lock); 531 mutex_lock(&radio->lock);
578 radio->users = 0; 532
533 if (!radio->usbdev)
534 retval = -EIO;
535 else
536 usb_autopm_put_interface(radio->intf);
537
579 mutex_unlock(&radio->lock); 538 mutex_unlock(&radio->lock);
539 return retval;
540}
580 541
581 if (!radio->removed) { 542static long usb_amradio_ioctl(struct file *file, unsigned int cmd,
582 retval = amradio_set_mute(radio, AMRADIO_STOP); 543 unsigned long arg)
583 if (retval < 0) 544{
584 amradio_dev_warn(&radio->videodev->dev, 545 struct amradio_device *radio = file->private_data;
585 "amradio_stop failed\n"); 546 long retval = 0;
547
548 mutex_lock(&radio->lock);
549
550 if (!radio->usbdev) {
551 retval = -EIO;
552 goto unlock;
586 } 553 }
587 554
588 return 0; 555 retval = video_ioctl2(file, cmd, arg);
556
557unlock:
558 mutex_unlock(&radio->lock);
559 return retval;
589} 560}
590 561
591/* Suspend device - stop device. Need to be checked and fixed */ 562/* Suspend device - stop device. Need to be checked and fixed */
592static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message) 563static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
593{ 564{
594 struct amradio_device *radio = usb_get_intfdata(intf); 565 struct amradio_device *radio = usb_get_intfdata(intf);
595 int retval;
596 566
597 retval = amradio_set_mute(radio, AMRADIO_STOP); 567 mutex_lock(&radio->lock);
598 if (retval < 0) 568
599 dev_warn(&intf->dev, "amradio_stop failed\n"); 569 if (!radio->muted && radio->initialized) {
570 amradio_set_mute(radio, AMRADIO_STOP);
571 radio->muted = 0;
572 }
600 573
601 dev_info(&intf->dev, "going into suspend..\n"); 574 dev_info(&intf->dev, "going into suspend..\n");
602 575
576 mutex_unlock(&radio->lock);
603 return 0; 577 return 0;
604} 578}
605 579
@@ -607,14 +581,26 @@ static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
607static int usb_amradio_resume(struct usb_interface *intf) 581static int usb_amradio_resume(struct usb_interface *intf)
608{ 582{
609 struct amradio_device *radio = usb_get_intfdata(intf); 583 struct amradio_device *radio = usb_get_intfdata(intf);
610 int retval;
611 584
612 retval = amradio_set_mute(radio, AMRADIO_START); 585 mutex_lock(&radio->lock);
613 if (retval < 0) 586
614 dev_warn(&intf->dev, "amradio_start failed\n"); 587 if (unlikely(!radio->initialized))
588 goto unlock;
589
590 if (radio->stereo)
591 amradio_set_stereo(radio, WANT_STEREO);
592 else
593 amradio_set_stereo(radio, WANT_MONO);
594
595 amradio_setfreq(radio, radio->curfreq);
615 596
597 if (!radio->muted)
598 amradio_set_mute(radio, AMRADIO_START);
599
600unlock:
616 dev_info(&intf->dev, "coming out of suspend..\n"); 601 dev_info(&intf->dev, "coming out of suspend..\n");
617 602
603 mutex_unlock(&radio->lock);
618 return 0; 604 return 0;
619} 605}
620 606
@@ -623,7 +609,7 @@ static const struct v4l2_file_operations usb_amradio_fops = {
623 .owner = THIS_MODULE, 609 .owner = THIS_MODULE,
624 .open = usb_amradio_open, 610 .open = usb_amradio_open,
625 .release = usb_amradio_close, 611 .release = usb_amradio_close,
626 .ioctl = video_ioctl2, 612 .ioctl = usb_amradio_ioctl,
627}; 613};
628 614
629static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = { 615static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = {
@@ -643,10 +629,7 @@ static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = {
643 629
644static void usb_amradio_video_device_release(struct video_device *videodev) 630static void usb_amradio_video_device_release(struct video_device *videodev)
645{ 631{
646 struct amradio_device *radio = video_get_drvdata(videodev); 632 struct amradio_device *radio = vdev_to_amradio(videodev);
647
648 /* we call v4l to free radio->videodev */
649 video_device_release(videodev);
650 633
651 v4l2_device_unregister(&radio->v4l2_dev); 634 v4l2_device_unregister(&radio->v4l2_dev);
652 635
@@ -660,70 +643,63 @@ static int usb_amradio_probe(struct usb_interface *intf,
660 const struct usb_device_id *id) 643 const struct usb_device_id *id)
661{ 644{
662 struct amradio_device *radio; 645 struct amradio_device *radio;
663 struct v4l2_device *v4l2_dev; 646 int retval = 0;
664 int retval;
665 647
666 radio = kzalloc(sizeof(struct amradio_device), GFP_KERNEL); 648 radio = kzalloc(sizeof(struct amradio_device), GFP_KERNEL);
667 649
668 if (!radio) { 650 if (!radio) {
669 dev_err(&intf->dev, "kmalloc for amradio_device failed\n"); 651 dev_err(&intf->dev, "kmalloc for amradio_device failed\n");
670 return -ENOMEM; 652 retval = -ENOMEM;
653 goto err;
671 } 654 }
672 655
673 radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL); 656 radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
674 657
675 if (!radio->buffer) { 658 if (!radio->buffer) {
676 dev_err(&intf->dev, "kmalloc for radio->buffer failed\n"); 659 dev_err(&intf->dev, "kmalloc for radio->buffer failed\n");
677 kfree(radio); 660 retval = -ENOMEM;
678 return -ENOMEM; 661 goto err_nobuf;
679 } 662 }
680 663
681 v4l2_dev = &radio->v4l2_dev; 664 retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev);
682 retval = v4l2_device_register(&intf->dev, v4l2_dev);
683 if (retval < 0) { 665 if (retval < 0) {
684 dev_err(&intf->dev, "couldn't register v4l2_device\n"); 666 dev_err(&intf->dev, "couldn't register v4l2_device\n");
685 kfree(radio->buffer); 667 goto err_v4l2;
686 kfree(radio);
687 return retval;
688 } 668 }
689 669
690 radio->videodev = video_device_alloc(); 670 strlcpy(radio->videodev.name, radio->v4l2_dev.name,
691 671 sizeof(radio->videodev.name));
692 if (!radio->videodev) { 672 radio->videodev.v4l2_dev = &radio->v4l2_dev;
693 dev_err(&intf->dev, "video_device_alloc failed\n"); 673 radio->videodev.fops = &usb_amradio_fops;
694 kfree(radio->buffer); 674 radio->videodev.ioctl_ops = &usb_amradio_ioctl_ops;
695 kfree(radio); 675 radio->videodev.release = usb_amradio_video_device_release;
696 return -ENOMEM;
697 }
698 676
699 strlcpy(radio->videodev->name, v4l2_dev->name, sizeof(radio->videodev->name));
700 radio->videodev->v4l2_dev = v4l2_dev;
701 radio->videodev->fops = &usb_amradio_fops;
702 radio->videodev->ioctl_ops = &usb_amradio_ioctl_ops;
703 radio->videodev->release = usb_amradio_video_device_release;
704
705 radio->removed = 0;
706 radio->users = 0;
707 radio->usbdev = interface_to_usbdev(intf); 677 radio->usbdev = interface_to_usbdev(intf);
678 radio->intf = intf;
708 radio->curfreq = 95.16 * FREQ_MUL; 679 radio->curfreq = 95.16 * FREQ_MUL;
709 radio->stereo = -1;
710 680
711 mutex_init(&radio->lock); 681 mutex_init(&radio->lock);
712 682
713 video_set_drvdata(radio->videodev, radio); 683 video_set_drvdata(&radio->videodev, radio);
714 684
715 retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr); 685 retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO,
686 radio_nr);
716 if (retval < 0) { 687 if (retval < 0) {
717 dev_err(&intf->dev, "could not register video device\n"); 688 dev_err(&intf->dev, "could not register video device\n");
718 video_device_release(radio->videodev); 689 goto err_vdev;
719 v4l2_device_unregister(v4l2_dev);
720 kfree(radio->buffer);
721 kfree(radio);
722 return -EIO;
723 } 690 }
724 691
725 usb_set_intfdata(intf, radio); 692 usb_set_intfdata(intf, radio);
726 return 0; 693 return 0;
694
695err_vdev:
696 v4l2_device_unregister(&radio->v4l2_dev);
697err_v4l2:
698 kfree(radio->buffer);
699err_nobuf:
700 kfree(radio);
701err:
702 return retval;
727} 703}
728 704
729static int __init amradio_init(void) 705static int __init amradio_init(void)
diff --git a/drivers/media/radio/tef6862.c b/drivers/media/radio/tef6862.c
new file mode 100644
index 00000000000..6e607ff0c16
--- /dev/null
+++ b/drivers/media/radio/tef6862.c
@@ -0,0 +1,232 @@
1/*
2 * tef6862.c Philips TEF6862 Car Radio Enhanced Selectivity Tuner
3 * Copyright (c) 2009 Intel Corporation
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19#include <linux/module.h>
20#include <linux/init.h>
21#include <linux/errno.h>
22#include <linux/kernel.h>
23#include <linux/interrupt.h>
24#include <linux/i2c.h>
25#include <linux/i2c-id.h>
26#include <media/v4l2-ioctl.h>
27#include <media/v4l2-device.h>
28#include <media/v4l2-chip-ident.h>
29
30#define DRIVER_NAME "tef6862"
31
32#define FREQ_MUL 16000
33
34#define TEF6862_LO_FREQ (875 * FREQ_MUL / 10)
35#define TEF6862_HI_FREQ (108 * FREQ_MUL)
36
37/* Write mode sub addresses */
38#define WM_SUB_BANDWIDTH 0x0
39#define WM_SUB_PLLM 0x1
40#define WM_SUB_PLLL 0x2
41#define WM_SUB_DAA 0x3
42#define WM_SUB_AGC 0x4
43#define WM_SUB_BAND 0x5
44#define WM_SUB_CONTROL 0x6
45#define WM_SUB_LEVEL 0x7
46#define WM_SUB_IFCF 0x8
47#define WM_SUB_IFCAP 0x9
48#define WM_SUB_ACD 0xA
49#define WM_SUB_TEST 0xF
50
51/* Different modes of the MSA register */
52#define MODE_BUFFER 0x0
53#define MODE_PRESET 0x1
54#define MODE_SEARCH 0x2
55#define MODE_AF_UPDATE 0x3
56#define MODE_JUMP 0x4
57#define MODE_CHECK 0x5
58#define MODE_LOAD 0x6
59#define MODE_END 0x7
60#define MODE_SHIFT 5
61
62struct tef6862_state {
63 struct v4l2_subdev sd;
64 unsigned long freq;
65};
66
67static inline struct tef6862_state *to_state(struct v4l2_subdev *sd)
68{
69 return container_of(sd, struct tef6862_state, sd);
70}
71
72static u16 tef6862_sigstr(struct i2c_client *client)
73{
74 u8 buf[4];
75 int err = i2c_master_recv(client, buf, sizeof(buf));
76 if (err == sizeof(buf))
77 return buf[3] << 8;
78 return 0;
79}
80
81static int tef6862_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v)
82{
83 if (v->index > 0)
84 return -EINVAL;
85
86 /* only support FM for now */
87 strlcpy(v->name, "FM", sizeof(v->name));
88 v->type = V4L2_TUNER_RADIO;
89 v->rangelow = TEF6862_LO_FREQ;
90 v->rangehigh = TEF6862_HI_FREQ;
91 v->rxsubchans = V4L2_TUNER_SUB_MONO;
92 v->capability = V4L2_TUNER_CAP_LOW;
93 v->audmode = V4L2_TUNER_MODE_STEREO;
94 v->signal = tef6862_sigstr(v4l2_get_subdevdata(sd));
95
96 return 0;
97}
98
99static int tef6862_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v)
100{
101 return v->index ? -EINVAL : 0;
102}
103
104static int tef6862_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
105{
106 struct tef6862_state *state = to_state(sd);
107 struct i2c_client *client = v4l2_get_subdevdata(sd);
108 u16 pll;
109 u8 i2cmsg[3];
110 int err;
111
112 if (f->tuner != 0)
113 return -EINVAL;
114
115 pll = 1964 + ((f->frequency - TEF6862_LO_FREQ) * 20) / FREQ_MUL;
116 i2cmsg[0] = (MODE_PRESET << MODE_SHIFT) | WM_SUB_PLLM;
117 i2cmsg[1] = (pll >> 8) & 0xff;
118 i2cmsg[2] = pll & 0xff;
119
120 err = i2c_master_send(client, i2cmsg, sizeof(i2cmsg));
121 if (!err)
122 state->freq = f->frequency;
123 return err;
124}
125
126static int tef6862_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f)
127{
128 struct tef6862_state *state = to_state(sd);
129
130 if (f->tuner != 0)
131 return -EINVAL;
132 f->type = V4L2_TUNER_RADIO;
133 f->frequency = state->freq;
134 return 0;
135}
136
137static int tef6862_g_chip_ident(struct v4l2_subdev *sd,
138 struct v4l2_dbg_chip_ident *chip)
139{
140 struct i2c_client *client = v4l2_get_subdevdata(sd);
141
142 return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TEF6862, 0);
143}
144
145static const struct v4l2_subdev_tuner_ops tef6862_tuner_ops = {
146 .g_tuner = tef6862_g_tuner,
147 .s_tuner = tef6862_s_tuner,
148 .s_frequency = tef6862_s_frequency,
149 .g_frequency = tef6862_g_frequency,
150};
151
152static const struct v4l2_subdev_core_ops tef6862_core_ops = {
153 .g_chip_ident = tef6862_g_chip_ident,
154};
155
156static const struct v4l2_subdev_ops tef6862_ops = {
157 .core = &tef6862_core_ops,
158 .tuner = &tef6862_tuner_ops,
159};
160
161/*
162 * Generic i2c probe
163 * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
164 */
165
166static int __devinit tef6862_probe(struct i2c_client *client,
167 const struct i2c_device_id *id)
168{
169 struct tef6862_state *state;
170 struct v4l2_subdev *sd;
171
172 /* Check if the adapter supports the needed features */
173 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
174 return -EIO;
175
176 v4l_info(client, "chip found @ 0x%02x (%s)\n",
177 client->addr << 1, client->adapter->name);
178
179 state = kmalloc(sizeof(struct tef6862_state), GFP_KERNEL);
180 if (state == NULL)
181 return -ENOMEM;
182 state->freq = TEF6862_LO_FREQ;
183
184 sd = &state->sd;
185 v4l2_i2c_subdev_init(sd, client, &tef6862_ops);
186
187 return 0;
188}
189
190static int __devexit tef6862_remove(struct i2c_client *client)
191{
192 struct v4l2_subdev *sd = i2c_get_clientdata(client);
193
194 v4l2_device_unregister_subdev(sd);
195 kfree(to_state(sd));
196 return 0;
197}
198
199static const struct i2c_device_id tef6862_id[] = {
200 {DRIVER_NAME, 0},
201 {},
202};
203
204MODULE_DEVICE_TABLE(i2c, tef6862_id);
205
206static struct i2c_driver tef6862_driver = {
207 .driver = {
208 .owner = THIS_MODULE,
209 .name = DRIVER_NAME,
210 },
211 .probe = tef6862_probe,
212 .remove = tef6862_remove,
213 .id_table = tef6862_id,
214};
215
216static __init int tef6862_init(void)
217{
218 return i2c_add_driver(&tef6862_driver);
219}
220
221static __exit void tef6862_exit(void)
222{
223 i2c_del_driver(&tef6862_driver);
224}
225
226module_init(tef6862_init);
227module_exit(tef6862_exit);
228
229MODULE_DESCRIPTION("TEF6862 Car Radio Enhanced Selectivity Tuner");
230MODULE_AUTHOR("Mocean Laboratories");
231MODULE_LICENSE("GPL v2");
232