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