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->frequency < FREQ_LO || f->frequency > FREQ_HI) { 266 dprintk(dev, 1, "radio freq (%d.%02d MHz) out of range (%d-%d)\n", 267 f->frequency / 16000, 268 f->frequency % 16000 * 100 / 16000, 269 FREQ_LO / 16000, FREQ_HI / 16000); 270 271 return -EINVAL; 272 } 273 274 mutex_lock(&dev->lock); 275 dev->freq = f->frequency; 276 set_freq(dev, dev->freq); 277 msleep(125); 278 mutex_unlock(&dev->lock); 279 280 return 0; 281 } 282 283 static int vidioc_g_frequency(struct file *file, void *priv, 284 struct v4l2_frequency *f) 285 { 286 struct maxiradio *dev = video_drvdata(file); 287 288 f->type = V4L2_TUNER_RADIO; 289 f->frequency = dev->freq; 290 291 dprintk(dev, 4, "radio freq is %d.%02d MHz", 292 f->frequency / 16000, 293 f->frequency % 16000 * 100 / 16000); 294 295 return 0; 296 } 297 298 static int vidioc_queryctrl(struct file *file, void *priv, 299 struct v4l2_queryctrl *qc) 300 { 301 switch (qc->id) { 302 case V4L2_CID_AUDIO_MUTE: 303 return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); 304 } 305 return -EINVAL; 306 } 307 308 static int vidioc_g_ctrl(struct file *file, void *priv, 309 struct v4l2_control *ctrl) 310 { 311 struct maxiradio *dev = video_drvdata(file); 312 313 switch (ctrl->id) { 314 case V4L2_CID_AUDIO_MUTE: 315 ctrl->value = dev->muted; 316 return 0; 317 } 318 319 return -EINVAL; 320 } 321 322 static int vidioc_s_ctrl(struct file *file, void *priv, 323 struct v4l2_control *ctrl) 324 { 325 struct maxiradio *dev = video_drvdata(file); 326 327 switch (ctrl->id) { 328 case V4L2_CID_AUDIO_MUTE: 329 mutex_lock(&dev->lock); 330 dev->muted = ctrl->value; 331 if (dev->muted) 332 turn_power(dev, 0); 333 else 334 set_freq(dev, dev->freq); 335 mutex_unlock(&dev->lock); 336 return 0; 337 } 338 339 return -EINVAL; 340 } 341 342 static const struct v4l2_file_operations maxiradio_fops = { 343 .owner = THIS_MODULE, 344 .ioctl = video_ioctl2, 345 }; 346 347 static const struct v4l2_ioctl_ops maxiradio_ioctl_ops = { 348 .vidioc_querycap = vidioc_querycap, 349 .vidioc_g_tuner = vidioc_g_tuner, 350 .vidioc_s_tuner = vidioc_s_tuner, 351 .vidioc_g_audio = vidioc_g_audio, 352 .vidioc_s_audio = vidioc_s_audio, 353 .vidioc_g_input = vidioc_g_input, 354 .vidioc_s_input = vidioc_s_input, 355 .vidioc_g_frequency = vidioc_g_frequency, 356 .vidioc_s_frequency = vidioc_s_frequency, 357 .vidioc_queryctrl = vidioc_queryctrl, 358 .vidioc_g_ctrl = vidioc_g_ctrl, 359 .vidioc_s_ctrl = vidioc_s_ctrl, 360 }; 361 362 static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) 363 { 364 struct maxiradio *dev; 365 struct v4l2_device *v4l2_dev; 366 int retval = -ENOMEM; 367 368 dev = kzalloc(sizeof(*dev), GFP_KERNEL); 369 if (dev == NULL) { 370 dev_err(&pdev->dev, "not enough memory\n"); 371 return -ENOMEM; 372 } 373 374 v4l2_dev = &dev->v4l2_dev; 375 mutex_init(&dev->lock); 376 dev->pdev = pdev; 377 dev->muted = 1; 378 dev->freq = FREQ_LO; 379 380 strlcpy(v4l2_dev->name, "maxiradio", sizeof(v4l2_dev->name)); 381 382 retval = v4l2_device_register(&pdev->dev, v4l2_dev); 383 if (retval < 0) { 384 v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); 385 goto errfr; 386 } 387 388 if (!request_region(pci_resource_start(pdev, 0), 389 pci_resource_len(pdev, 0), "Maxi Radio FM 2000")) { 390 v4l2_err(v4l2_dev, "can't reserve I/O ports\n"); 391 goto err_out; 392 } 393 394 if (pci_enable_device(pdev)) 395 goto err_out_free_region; 396 397 dev->io = pci_resource_start(pdev, 0); 398 strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); 399 dev->vdev.v4l2_dev = v4l2_dev; 400 dev->vdev.fops = &maxiradio_fops; 401 dev->vdev.ioctl_ops = &maxiradio_ioctl_ops; 402 dev->vdev.release = video_device_release_empty; 403 video_set_drvdata(&dev->vdev, dev); 404 405 if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { 406 v4l2_err(v4l2_dev, "can't register device!"); 407 goto err_out_free_region; 408 } 409 410 v4l2_info(v4l2_dev, "version " DRIVER_VERSION 411 " time " __TIME__ " " __DATE__ "\n"); 412 413 v4l2_info(v4l2_dev, "found Guillemot MAXI Radio device (io = 0x%x)\n", 414 dev->io); 415 return 0; 416 417 err_out_free_region: 418 release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); 419 err_out: 420 v4l2_device_unregister(v4l2_dev); 421 errfr: 422 kfree(dev); 423 return -ENODEV; 424 } 425 426 static void __devexit maxiradio_remove_one(struct pci_dev *pdev) 427 { 428 struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); 429 struct maxiradio *dev = to_maxiradio(v4l2_dev); 430 431 video_unregister_device(&dev->vdev); 432 v4l2_device_unregister(&dev->v4l2_dev); 433 release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); 434 } 435 436 static struct pci_device_id maxiradio_pci_tbl[] = { 437 { PCI_VENDOR_ID_GUILLEMOT, PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO, 438 PCI_ANY_ID, PCI_ANY_ID, }, 439 { 0 } 440 }; 441 442 MODULE_DEVICE_TABLE(pci, maxiradio_pci_tbl); 443 444 static struct pci_driver maxiradio_driver = { 445 .name = "radio-maxiradio", 446 .id_table = maxiradio_pci_tbl, 447 .probe = maxiradio_init_one, 448 .remove = __devexit_p(maxiradio_remove_one), 449 }; 450 451 static int __init maxiradio_radio_init(void) 452 { 453 return pci_register_driver(&maxiradio_driver); 454 } 455 456 static void __exit maxiradio_radio_exit(void) 457 { 458 pci_unregister_driver(&maxiradio_driver); 459 } 460 461 module_init(maxiradio_radio_init); 462 module_exit(maxiradio_radio_exit); 463