radio-maxiradio.c 11 KB

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