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