radio-maxiradio.c 11 KB

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