1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Terratec ActiveRadio ISA Standalone card driver for Linux radio support
3 * (c) 1999 R. Offermanns (rolf@offermanns.de)
4 * based on the aimslab radio driver from M. Kirkwood
5 * many thanks to Michael Becker and Friedhelm Birth (from TerraTec)
9 * 1999-05-21 First preview release
11 * Notes on the hardware:
12 * There are two "main" chips on the card:
13 * - Philips OM5610 (http://www-us.semiconductors.philips.com/acrobat/datasheets/OM5610_2.pdf)
14 * - Philips SAA6588 (http://www-us.semiconductors.philips.com/acrobat/datasheets/SAA6588_1.pdf)
15 * (you can get the datasheet at the above links)
17 * Frequency control is done digitally -- ie out(port,encodefreq(95.8));
18 * Volume Control is done digitally
20 * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com>
21 * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@kernel.org>
24 #include <linux/module.h> /* Modules */
25 #include <linux/init.h> /* Initdata */
26 #include <linux/ioport.h> /* request_region */
27 #include <linux/videodev2.h> /* kernel radio structs */
28 #include <linux/mutex.h>
29 #include <linux/io.h> /* outb, outb_p */
30 #include <linux/slab.h>
31 #include <media/v4l2-device.h>
32 #include <media/v4l2-ioctl.h>
33 #include "radio-isa.h"
35 MODULE_AUTHOR("R. Offermans & others");
36 MODULE_DESCRIPTION("A driver for the TerraTec ActiveRadio Standalone radio card.");
37 MODULE_LICENSE("GPL");
38 MODULE_VERSION("0.1.99");
40 /* Note: there seems to be only one possible port (0x590), but without
41 hardware this is hard to verify. For now, this is the only one we will
43 static int io
= 0x590;
44 static int radio_nr
= -1;
46 module_param(radio_nr
, int, 0444);
47 MODULE_PARM_DESC(radio_nr
, "Radio device number");
57 static struct radio_isa_card
*terratec_alloc(void)
59 return kzalloc(sizeof(struct radio_isa_card
), GFP_KERNEL
);
62 static int terratec_s_mute_volume(struct radio_isa_card
*isa
, bool mute
, int vol
)
68 vol
= vol
+ (vol
* 32); /* change both channels */
69 for (i
= 0; i
< 8; i
++) {
70 if (vol
& (0x80 >> i
))
71 outb(0x80, isa
->io
+ 1);
73 outb(0x00, isa
->io
+ 1);
79 /* this is the worst part in this driver */
80 /* many more or less strange things are going on here, but hey, it works :) */
82 static int terratec_s_frequency(struct radio_isa_card
*isa
, u32 freq
)
88 unsigned char buffer
[25]; /* we have to bit shift 25 registers */
90 freq
= freq
/ 160; /* convert the freq. to a nice to handle value */
91 memset(buffer
, 0, sizeof(buffer
));
93 rest
= freq
* 10 + 10700; /* I once had understood what is going on here */
94 /* maybe some wise guy (friedhelm?) can comment this stuff */
99 if (rest
% temp
== rest
)
110 for (i
= 24; i
> -1; i
--) { /* bit shift the values to the radiocard */
111 if (buffer
[i
] == 1) {
112 outb(WRT_EN
| DATA
, isa
->io
);
113 outb(WRT_EN
| DATA
| CLK_ON
, isa
->io
);
114 outb(WRT_EN
| DATA
, isa
->io
);
116 outb(WRT_EN
| 0x00, isa
->io
);
117 outb(WRT_EN
| 0x00 | CLK_ON
, isa
->io
);
124 static u32
terratec_g_signal(struct radio_isa_card
*isa
)
126 /* bit set = no signal present */
127 return (inb(isa
->io
) & 2) ? 0 : 0xffff;
130 static const struct radio_isa_ops terratec_ops
= {
131 .alloc
= terratec_alloc
,
132 .s_mute_volume
= terratec_s_mute_volume
,
133 .s_frequency
= terratec_s_frequency
,
134 .g_signal
= terratec_g_signal
,
137 static const int terratec_ioports
[] = { 0x590 };
139 static struct radio_isa_driver terratec_driver
= {
141 .match
= radio_isa_match
,
142 .probe
= radio_isa_probe
,
143 .remove
= radio_isa_remove
,
145 .name
= "radio-terratec",
149 .radio_nr_params
= &radio_nr
,
150 .io_ports
= terratec_ioports
,
151 .num_of_io_ports
= ARRAY_SIZE(terratec_ioports
),
153 .card
= "TerraTec ActiveRadio",
154 .ops
= &terratec_ops
,
159 static int __init
terratec_init(void)
161 return isa_register_driver(&terratec_driver
.driver
, 1);
164 static void __exit
terratec_exit(void)
166 isa_unregister_driver(&terratec_driver
.driver
);
169 module_init(terratec_init
);
170 module_exit(terratec_exit
);