radio-maxiradio.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  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. #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 <media/v4l2-device.h>
  44. #include <media/v4l2-ioctl.h>
  45. MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net");
  46. MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio.");
  47. MODULE_LICENSE("GPL");
  48. static int radio_nr = -1;
  49. module_param(radio_nr, int, 0);
  50. static int debug;
  51. module_param(debug, int, 0644);
  52. MODULE_PARM_DESC(debug, "activates debug info");
  53. #define DRIVER_VERSION "0.77"
  54. #define RADIO_VERSION KERNEL_VERSION(0, 7, 7)
  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 (50 * 16000)
  66. #define FREQ_HI (150 * 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->version = RADIO_VERSION;
  155. v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
  156. return 0;
  157. }
  158. static int vidioc_g_tuner(struct file *file, void *priv,
  159. struct v4l2_tuner *v)
  160. {
  161. struct maxiradio *dev = video_drvdata(file);
  162. if (v->index > 0)
  163. return -EINVAL;
  164. mutex_lock(&dev->lock);
  165. strlcpy(v->name, "FM", sizeof(v->name));
  166. v->type = V4L2_TUNER_RADIO;
  167. v->rangelow = FREQ_LO;
  168. v->rangehigh = FREQ_HI;
  169. v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
  170. v->capability = V4L2_TUNER_CAP_LOW;
  171. if (get_stereo(dev->io))
  172. v->audmode = V4L2_TUNER_MODE_STEREO;
  173. else
  174. v->audmode = V4L2_TUNER_MODE_MONO;
  175. v->signal = 0xffff * get_tune(dev->io);
  176. mutex_unlock(&dev->lock);
  177. return 0;
  178. }
  179. static int vidioc_s_tuner(struct file *file, void *priv,
  180. struct v4l2_tuner *v)
  181. {
  182. return v->index ? -EINVAL : 0;
  183. }
  184. static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
  185. {
  186. *i = 0;
  187. return 0;
  188. }
  189. static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
  190. {
  191. return i ? -EINVAL : 0;
  192. }
  193. static int vidioc_g_audio(struct file *file, void *priv,
  194. struct v4l2_audio *a)
  195. {
  196. a->index = 0;
  197. strlcpy(a->name, "Radio", sizeof(a->name));
  198. a->capability = V4L2_AUDCAP_STEREO;
  199. return 0;
  200. }
  201. static int vidioc_s_audio(struct file *file, void *priv,
  202. struct v4l2_audio *a)
  203. {
  204. return a->index ? -EINVAL : 0;
  205. }
  206. static int vidioc_s_frequency(struct file *file, void *priv,
  207. struct v4l2_frequency *f)
  208. {
  209. struct maxiradio *dev = video_drvdata(file);
  210. if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) {
  211. dprintk(dev, 1, "radio freq (%d.%02d MHz) out of range (%d-%d)\n",
  212. f->frequency / 16000,
  213. f->frequency % 16000 * 100 / 16000,
  214. FREQ_LO / 16000, FREQ_HI / 16000);
  215. return -EINVAL;
  216. }
  217. mutex_lock(&dev->lock);
  218. dev->freq = f->frequency;
  219. set_freq(dev, dev->freq);
  220. msleep(125);
  221. mutex_unlock(&dev->lock);
  222. return 0;
  223. }
  224. static int vidioc_g_frequency(struct file *file, void *priv,
  225. struct v4l2_frequency *f)
  226. {
  227. struct maxiradio *dev = video_drvdata(file);
  228. f->type = V4L2_TUNER_RADIO;
  229. f->frequency = dev->freq;
  230. dprintk(dev, 4, "radio freq is %d.%02d MHz",
  231. f->frequency / 16000,
  232. f->frequency % 16000 * 100 / 16000);
  233. return 0;
  234. }
  235. static int vidioc_queryctrl(struct file *file, void *priv,
  236. struct v4l2_queryctrl *qc)
  237. {
  238. switch (qc->id) {
  239. case V4L2_CID_AUDIO_MUTE:
  240. return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
  241. }
  242. return -EINVAL;
  243. }
  244. static int vidioc_g_ctrl(struct file *file, void *priv,
  245. struct v4l2_control *ctrl)
  246. {
  247. struct maxiradio *dev = video_drvdata(file);
  248. switch (ctrl->id) {
  249. case V4L2_CID_AUDIO_MUTE:
  250. ctrl->value = dev->muted;
  251. return 0;
  252. }
  253. return -EINVAL;
  254. }
  255. static int vidioc_s_ctrl(struct file *file, void *priv,
  256. struct v4l2_control *ctrl)
  257. {
  258. struct maxiradio *dev = video_drvdata(file);
  259. switch (ctrl->id) {
  260. case V4L2_CID_AUDIO_MUTE:
  261. mutex_lock(&dev->lock);
  262. dev->muted = ctrl->value;
  263. if (dev->muted)
  264. turn_power(dev, 0);
  265. else
  266. set_freq(dev, dev->freq);
  267. mutex_unlock(&dev->lock);
  268. return 0;
  269. }
  270. return -EINVAL;
  271. }
  272. static const struct v4l2_file_operations maxiradio_fops = {
  273. .owner = THIS_MODULE,
  274. .ioctl = video_ioctl2,
  275. };
  276. static const struct v4l2_ioctl_ops maxiradio_ioctl_ops = {
  277. .vidioc_querycap = vidioc_querycap,
  278. .vidioc_g_tuner = vidioc_g_tuner,
  279. .vidioc_s_tuner = vidioc_s_tuner,
  280. .vidioc_g_audio = vidioc_g_audio,
  281. .vidioc_s_audio = vidioc_s_audio,
  282. .vidioc_g_input = vidioc_g_input,
  283. .vidioc_s_input = vidioc_s_input,
  284. .vidioc_g_frequency = vidioc_g_frequency,
  285. .vidioc_s_frequency = vidioc_s_frequency,
  286. .vidioc_queryctrl = vidioc_queryctrl,
  287. .vidioc_g_ctrl = vidioc_g_ctrl,
  288. .vidioc_s_ctrl = vidioc_s_ctrl,
  289. };
  290. static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
  291. {
  292. struct maxiradio *dev;
  293. struct v4l2_device *v4l2_dev;
  294. int retval = -ENOMEM;
  295. dev = kzalloc(sizeof(*dev), GFP_KERNEL);
  296. if (dev == NULL) {
  297. dev_err(&pdev->dev, "not enough memory\n");
  298. return -ENOMEM;
  299. }
  300. v4l2_dev = &dev->v4l2_dev;
  301. mutex_init(&dev->lock);
  302. dev->pdev = pdev;
  303. dev->muted = 1;
  304. dev->freq = FREQ_LO;
  305. strlcpy(v4l2_dev->name, "maxiradio", sizeof(v4l2_dev->name));
  306. retval = v4l2_device_register(&pdev->dev, v4l2_dev);
  307. if (retval < 0) {
  308. v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
  309. goto errfr;
  310. }
  311. if (!request_region(pci_resource_start(pdev, 0),
  312. pci_resource_len(pdev, 0), "Maxi Radio FM 2000")) {
  313. v4l2_err(v4l2_dev, "can't reserve I/O ports\n");
  314. goto err_out;
  315. }
  316. if (pci_enable_device(pdev))
  317. goto err_out_free_region;
  318. dev->io = pci_resource_start(pdev, 0);
  319. strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
  320. dev->vdev.v4l2_dev = v4l2_dev;
  321. dev->vdev.fops = &maxiradio_fops;
  322. dev->vdev.ioctl_ops = &maxiradio_ioctl_ops;
  323. dev->vdev.release = video_device_release_empty;
  324. video_set_drvdata(&dev->vdev, dev);
  325. if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
  326. v4l2_err(v4l2_dev, "can't register device!");
  327. goto err_out_free_region;
  328. }
  329. v4l2_info(v4l2_dev, "version " DRIVER_VERSION
  330. " time " __TIME__ " " __DATE__ "\n");
  331. v4l2_info(v4l2_dev, "found Guillemot MAXI Radio device (io = 0x%x)\n",
  332. dev->io);
  333. return 0;
  334. err_out_free_region:
  335. release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
  336. err_out:
  337. v4l2_device_unregister(v4l2_dev);
  338. errfr:
  339. kfree(dev);
  340. return -ENODEV;
  341. }
  342. static void __devexit maxiradio_remove_one(struct pci_dev *pdev)
  343. {
  344. struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
  345. struct maxiradio *dev = to_maxiradio(v4l2_dev);
  346. video_unregister_device(&dev->vdev);
  347. v4l2_device_unregister(&dev->v4l2_dev);
  348. release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
  349. }
  350. static struct pci_device_id maxiradio_pci_tbl[] = {
  351. { PCI_VENDOR_ID_GUILLEMOT, PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO,
  352. PCI_ANY_ID, PCI_ANY_ID, },
  353. { 0 }
  354. };
  355. MODULE_DEVICE_TABLE(pci, maxiradio_pci_tbl);
  356. static struct pci_driver maxiradio_driver = {
  357. .name = "radio-maxiradio",
  358. .id_table = maxiradio_pci_tbl,
  359. .probe = maxiradio_init_one,
  360. .remove = __devexit_p(maxiradio_remove_one),
  361. };
  362. static int __init maxiradio_radio_init(void)
  363. {
  364. return pci_register_driver(&maxiradio_driver);
  365. }
  366. static void __exit maxiradio_radio_exit(void)
  367. {
  368. pci_unregister_driver(&maxiradio_driver);
  369. }
  370. module_init(maxiradio_radio_init);
  371. module_exit(maxiradio_radio_exit);