1 /* 2 * Guillemot Maxi Radio FM 2000 PCI radio card driver for Linux 3 * (C) 2001 Dimitromanolakis Apostolos <apdim@grecian.net> 4 * 5 * Based in the radio Maestro PCI driver. Actually it uses the same chip 6 * for radio but different pci controller. 7 * 8 * I didn't have any specs I reversed engineered the protocol from 9 * the windows driver (radio.dll). 10 * 11 * The card uses the TEA5757 chip that includes a search function but it 12 * is useless as I haven't found any way to read back the frequency. If 13 * anybody does please mail me. 14 * 15 * For the pdf file see: 16 * http://www.nxp.com/acrobat_download2/expired_datasheets/TEA5757_5759_3.pdf 17 * 18 * 19 * CHANGES: 20 * 0.75b 21 * - better pci interface thanks to Francois Romieu <romieu@cogenit.fr> 22 * 23 * 0.75 Sun Feb 4 22:51:27 EET 2001 24 * - tiding up 25 * - removed support for multiple devices as it didn't work anyway 26 * 27 * BUGS: 28 * - card unmutes if you change frequency 29 * 30 * (c) 2006, 2007 by Mauro Carvalho Chehab <mchehab@infradead.org>: 31 * - Conversion to V4L2 API 32 * - Uses video_ioctl2 for parsing and to add debug support 33 */ 34 35 36 #include <linux/module.h> 37 #include <linux/init.h> 38 #include <linux/ioport.h> 39 #include <linux/delay.h> 40 #include <linux/mutex.h> 41 #include <linux/pci.h> 42 #include <linux/videodev2.h> 43 #include <linux/version.h> /* for KERNEL_VERSION MACRO */ 44 #include <linux/io.h> 45 #include <linux/slab.h> 46 #include <media/v4l2-device.h> 47 #include <media/v4l2-ioctl.h> 48 49 MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net"); 50 MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio."); 51 MODULE_LICENSE("GPL"); 52 53 static int radio_nr = -1; 54 module_param(radio_nr, int, 0); 55 56 static int debug; 57 58 module_param(debug, int, 0644); 59 MODULE_PARM_DESC(debug, "activates debug info"); 60 61 #define DRIVER_VERSION "0.77" 62 63 #define RADIO_VERSION KERNEL_VERSION(0, 7, 7) 64 65 #define dprintk(dev, num, fmt, arg...) \ 66 v4l2_dbg(num, debug, &dev->v4l2_dev, fmt, ## arg) 67 68 #ifndef PCI_VENDOR_ID_GUILLEMOT 69 #define PCI_VENDOR_ID_GUILLEMOT 0x5046 70 #endif 71 72 #ifndef PCI_DEVICE_ID_GUILLEMOT 73 #define PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO 0x1001 74 #endif 75 76 77 /* TEA5757 pin mappings */ 78 static const int clk = 1, data = 2, wren = 4, mo_st = 8, power = 16; 79 80 #define FREQ_LO (50 * 16000) 81 #define FREQ_HI (150 * 16000) 82 83 #define FREQ_IF 171200 /* 10.7*16000 */ 84 #define FREQ_STEP 200 /* 12.5*16 */ 85 86 /* (x==fmhz*16*1000) -> bits */ 87 #define FREQ2BITS(x) \ 88 ((((unsigned int)(x) + FREQ_IF + (FREQ_STEP << 1)) / (FREQ_STEP << 2)) << 2) 89 90 #define BITS2FREQ(x) ((x) * FREQ_STEP - FREQ_IF) 91 92 93 struct maxiradio 94 { 95 struct v4l2_device v4l2_dev; 96 struct video_device vdev; 97 struct pci_dev *pdev; 98 99 u16 io; /* base of radio io */ 100 u16 muted; /* VIDEO_AUDIO_MUTE */ 101 u16 stereo; /* VIDEO_TUNER_STEREO_ON */ 102 u16 tuned; /* signal strength (0 or 0xffff) */ 103 104 unsigned long freq; 105 106 struct mutex lock; 107 }; 108 109 static inline struct maxiradio *to_maxiradio(struct v4l2_device *v4l2_dev) 110 { 111 return container_of(v4l2_dev, struct maxiradio, v4l2_dev); 112 } 113 114 static void outbit(unsigned long bit, u16 io) 115 { 116 int val = power | wren | (bit ? data : 0); 117 118 outb(val, io); 119 udelay(4); 120 outb(val | clk, io); 121 udelay(4); 122 outb(val, io); 123 udelay(4); 124 } 125 126 static void turn_power(struct maxiradio *dev, int p) 127 { 128 if (p != 0) { 129 dprintk(dev, 1, "Radio powered on\n"); 130 outb(power, dev->io); 131 } else { 132 dprintk(dev, 1, "Radio powered off\n"); 133 outb(0, dev->io); 134 } 135 } 136 137 static void set_freq(struct maxiradio *dev, u32 freq) 138 { 139 unsigned long int si; 140 int bl; 141 int io = dev->io; 142 int val = FREQ2BITS(freq); 143 144 /* TEA5757 shift register bits (see pdf) */ 145 146 outbit(0, io); /* 24 search */ 147 outbit(1, io); /* 23 search up/down */ 148 149 outbit(0, io); /* 22 stereo/mono */ 150 151 outbit(0, io); /* 21 band */ 152 outbit(0, io); /* 20 band (only 00=FM works I think) */ 153 154 outbit(0, io); /* 19 port ? */ 155 outbit(0, io); /* 18 port ? */ 156 157 outbit(0, io); /* 17 search level */ 158 outbit(0, io); /* 16 search level */ 159 160 si = 0x8000; 161 for (bl = 1; bl <= 16; bl++) { 162 outbit(val & si, io); 163 si >>= 1; 164 } 165 166 dprintk(dev, 1, "Radio freq set to %d.%02d MHz\n", 167 freq / 16000, 168 freq % 16000 * 100 / 16000); 169 170 turn_power(dev, 1); 171 } 172 173 static int get_stereo(u16 io) 174 { 175 outb(power,io); 176 udelay(4); 177 178 return !(inb(io) & mo_st); 179 } 180 181 static int get_tune(u16 io) 182 { 183 outb(power+clk,io); 184 udelay(4); 185 186 return !(inb(io) & mo_st); 187 } 188 189 190 static int vidioc_querycap(struct file *file, void *priv, 191 struct v4l2_capability *v) 192 { 193 struct maxiradio *dev = video_drvdata(file); 194 195 strlcpy(v->driver, "radio-maxiradio", sizeof(v->driver)); 196 strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof(v->card)); 197 snprintf(v->bus_info, sizeof(v->bus_info), "PCI:%s", pci_name(dev->pdev)); 198 v->version = RADIO_VERSION; 199 v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; 200 return 0; 201 } 202 203 static int vidioc_g_tuner(struct file *file, void *priv, 204 struct v4l2_tuner *v) 205 { 206 struct maxiradio *dev = video_drvdata(file); 207 208 if (v->index > 0) 209 return -EINVAL; 210 211 mutex_lock(&dev->lock); 212 strlcpy(v->name, "FM", sizeof(v->name)); 213 v->type = V4L2_TUNER_RADIO; 214 v->rangelow = FREQ_LO; 215 v->rangehigh = FREQ_HI; 216 v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; 217 v->capability = V4L2_TUNER_CAP_LOW; 218 if (get_stereo(dev->io)) 219 v->audmode = V4L2_TUNER_MODE_STEREO; 220 else 221 v->audmode = V4L2_TUNER_MODE_MONO; 222 v->signal = 0xffff * get_tune(dev->io); 223 mutex_unlock(&dev->lock); 224 225 return 0; 226 } 227 228 static int vidioc_s_tuner(struct file *file, void *priv, 229 struct v4l2_tuner *v) 230 { 231 return v->index ? -EINVAL : 0; 232 } 233 234 static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) 235 { 236 *i = 0; 237 return 0; 238 } 239 240 static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) 241 { 242 return i ? -EINVAL : 0; 243 } 244 245 static int vidioc_g_audio(struct file *file, void *priv, 246 struct v4l2_audio *a) 247 { 248 a->index = 0; 249 strlcpy(a->name, "Radio", sizeof(a->name)); 250 a->capability = V4L2_AUDCAP_STEREO; 251 return 0; 252 } 253 254 255 static int vidioc_s_audio(struct file *file, void *priv, 256 struct v4l2_audio *a) 257 { 258 return a->index ? -EINVAL : 0; 259 } 260 261 static int vidioc_s_frequency(struct file *file, void *priv, 262 struct v4l2_frequency *f) 263 { 264 struct maxiradio *dev = video_drvdata(file); 265 266 if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) 267 return -EINVAL; 268 if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) { 269 dprintk(dev, 1, "radio freq (%d.%02d MHz) out of range (%d-%d)\n", 270 f->frequency / 16000, 271 f->frequency % 16000 * 100 / 16000, 272 FREQ_LO / 16000, FREQ_HI / 16000); 273 274 return -EINVAL; 275 } 276 277 mutex_lock(&dev->lock); 278 dev->freq = f->frequency; 279 set_freq(dev, dev->freq); 280 msleep(125); 281 mutex_unlock(&dev->lock); 282 283 return 0; 284 } 285 286 static int vidioc_g_frequency(struct file *file, void *priv, 287 struct v4l2_frequency *f) 288 { 289 struct maxiradio *dev = video_drvdata(file); 290 291 if (f->tuner != 0) 292 return -EINVAL; 293 f->type = V4L2_TUNER_RADIO; 294 f->frequency = dev->freq; 295 296 dprintk(dev, 4, "radio freq is %d.%02d MHz", 297 f->frequency / 16000, 298 f->frequency % 16000 * 100 / 16000); 299 300 return 0; 301 } 302 303 static int vidioc_queryctrl(struct file *file, void *priv, 304 struct v4l2_queryctrl *qc) 305 { 306 switch (qc->id) { 307 case V4L2_CID_AUDIO_MUTE: 308 return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); 309 } 310 return -EINVAL; 311 } 312 313 static int vidioc_g_ctrl(struct file *file, void *priv, 314 struct v4l2_control *ctrl) 315 { 316 struct maxiradio *dev = video_drvdata(file); 317 318 switch (ctrl->id) { 319 case V4L2_CID_AUDIO_MUTE: 320 ctrl->value = dev->muted; 321 return 0; 322 } 323 324 return -EINVAL; 325 } 326 327 static int vidioc_s_ctrl(struct file *file, void *priv, 328 struct v4l2_control *ctrl) 329 { 330 struct maxiradio *dev = video_drvdata(file); 331 332 switch (ctrl->id) { 333 case V4L2_CID_AUDIO_MUTE: 334 mutex_lock(&dev->lock); 335 dev->muted = ctrl->value; 336 if (dev->muted) 337 turn_power(dev, 0); 338 else 339 set_freq(dev, dev->freq); 340 mutex_unlock(&dev->lock); 341 return 0; 342 } 343 344 return -EINVAL; 345 } 346 347 static const struct v4l2_file_operations maxiradio_fops = { 348 .owner = THIS_MODULE, 349 .unlocked_ioctl = video_ioctl2, 350 }; 351 352 static const struct v4l2_ioctl_ops maxiradio_ioctl_ops = { 353 .vidioc_querycap = vidioc_querycap, 354 .vidioc_g_tuner = vidioc_g_tuner, 355 .vidioc_s_tuner = vidioc_s_tuner, 356 .vidioc_g_audio = vidioc_g_audio, 357 .vidioc_s_audio = vidioc_s_audio, 358 .vidioc_g_input = vidioc_g_input, 359 .vidioc_s_input = vidioc_s_input, 360 .vidioc_g_frequency = vidioc_g_frequency, 361 .vidioc_s_frequency = vidioc_s_frequency, 362 .vidioc_queryctrl = vidioc_queryctrl, 363 .vidioc_g_ctrl = vidioc_g_ctrl, 364 .vidioc_s_ctrl = vidioc_s_ctrl, 365 }; 366 367 static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) 368 { 369 struct maxiradio *dev; 370 struct v4l2_device *v4l2_dev; 371 int retval = -ENOMEM; 372 373 dev = kzalloc(sizeof(*dev), GFP_KERNEL); 374 if (dev == NULL) { 375 dev_err(&pdev->dev, "not enough memory\n"); 376 return -ENOMEM; 377 } 378 379 v4l2_dev = &dev->v4l2_dev; 380 mutex_init(&dev->lock); 381 dev->pdev = pdev; 382 dev->muted = 1; 383 dev->freq = FREQ_LO; 384 385 strlcpy(v4l2_dev->name, "maxiradio", sizeof(v4l2_dev->name)); 386 387 retval = v4l2_device_register(&pdev->dev, v4l2_dev); 388 if (retval < 0) { 389 v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); 390 goto errfr; 391 } 392 393 if (!request_region(pci_resource_start(pdev, 0), 394 pci_resource_len(pdev, 0), "Maxi Radio FM 2000")) { 395 v4l2_err(v4l2_dev, "can't reserve I/O ports\n"); 396 goto err_out; 397 } 398 399 if (pci_enable_device(pdev)) 400 goto err_out_free_region; 401 402 dev->io = pci_resource_start(pdev, 0); 403 strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); 404 dev->vdev.v4l2_dev = v4l2_dev; 405 dev->vdev.fops = &maxiradio_fops; 406 dev->vdev.ioctl_ops = &maxiradio_ioctl_ops; 407 dev->vdev.release = video_device_release_empty; 408 video_set_drvdata(&dev->vdev, dev); 409 410 if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { 411 v4l2_err(v4l2_dev, "can't register device!"); 412 goto err_out_free_region; 413 } 414 415 v4l2_info(v4l2_dev, "version " DRIVER_VERSION 416 " time " __TIME__ " " __DATE__ "\n"); 417 418 v4l2_info(v4l2_dev, "found Guillemot MAXI Radio device (io = 0x%x)\n", 419 dev->io); 420 return 0; 421 422 err_out_free_region: 423 release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); 424 err_out: 425 v4l2_device_unregister(v4l2_dev); 426 errfr: 427 kfree(dev); 428 return -ENODEV; 429 } 430 431 static void __devexit maxiradio_remove_one(struct pci_dev *pdev) 432 { 433 struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); 434 struct maxiradio *dev = to_maxiradio(v4l2_dev); 435 436 video_unregister_device(&dev->vdev); 437 v4l2_device_unregister(&dev->v4l2_dev); 438 release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); 439 } 440 441 static struct pci_device_id maxiradio_pci_tbl[] = { 442 { PCI_VENDOR_ID_GUILLEMOT, PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO, 443 PCI_ANY_ID, PCI_ANY_ID, }, 444 { 0 } 445 }; 446 447 MODULE_DEVICE_TABLE(pci, maxiradio_pci_tbl); 448 449 static struct pci_driver maxiradio_driver = { 450 .name = "radio-maxiradio", 451 .id_table = maxiradio_pci_tbl, 452 .probe = maxiradio_init_one, 453 .remove = __devexit_p(maxiradio_remove_one), 454 }; 455 456 static int __init maxiradio_radio_init(void) 457 { 458 return pci_register_driver(&maxiradio_driver); 459 } 460 461 static void __exit maxiradio_radio_exit(void) 462 { 463 pci_unregister_driver(&maxiradio_driver); 464 } 465 466 module_init(maxiradio_radio_init); 467 module_exit(maxiradio_radio_exit); 468