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