Linux 2.4.0-test7-pre6
[davej-history.git] / drivers / char / radio-trust.c
blob4e86bda903a1d426ff6eae133d2f66bf51ccbf63
1 /* radio-trust.c - Trust FM Radio card driver for Linux 2.2
2 * by Eric Lammerts <eric@scintilla.utwente.nl>
4 * Based on radio-aztech.c. Original notes:
6 * Adapted to support the Video for Linux API by
7 * Russell Kroll <rkroll@exploits.org>. Based on original tuner code by:
9 * Quay Ly
10 * Donald Song
11 * Jason Lewis (jlewis@twilight.vtc.vsc.edu)
12 * Scott McGrath (smcgrath@twilight.vtc.vsc.edu)
13 * William McGrath (wmcgrath@twilight.vtc.vsc.edu)
15 * The basis for this code may be found at http://bigbang.vtc.vsc.edu/fmradio/
18 #include <stdarg.h>
19 #include <linux/module.h>
20 #include <linux/init.h>
21 #include <linux/ioport.h>
22 #include <asm/io.h>
23 #include <asm/uaccess.h>
24 #include <linux/videodev.h>
25 #include <linux/config.h> /* CONFIG_RADIO_TRUST_PORT */
27 /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
29 #ifndef CONFIG_RADIO_TRUST_PORT
30 #define CONFIG_RADIO_TRUST_PORT -1
31 #endif
33 static int io = CONFIG_RADIO_TRUST_PORT;
34 static int ioval = 0xf;
35 static int users = 0;
36 static __u16 curvol;
37 static __u16 curbass;
38 static __u16 curtreble;
39 static unsigned long curfreq;
40 static int curstereo;
41 static int curmute;
43 /* i2c addresses */
44 #define TDA7318_ADDR 0x88
45 #define TSA6060T_ADDR 0xc4
47 #define TR_DELAY do { inb(io); inb(io); inb(io); } while(0)
48 #define TR_SET_SCL outb(ioval |= 2, io)
49 #define TR_CLR_SCL outb(ioval &= 0xfd, io)
50 #define TR_SET_SDA outb(ioval |= 1, io)
51 #define TR_CLR_SDA outb(ioval &= 0xfe, io)
53 static void write_i2c(int n, ...)
55 unsigned char val, mask;
56 va_list args;
58 va_start(args, n);
60 /* start condition */
61 TR_SET_SDA;
62 TR_SET_SCL;
63 TR_DELAY;
64 TR_CLR_SDA;
65 TR_CLR_SCL;
66 TR_DELAY;
68 for(; n; n--) {
69 val = va_arg(args, unsigned);
70 for(mask = 0x80; mask; mask >>= 1) {
71 if(val & mask)
72 TR_SET_SDA;
73 else
74 TR_CLR_SDA;
75 TR_SET_SCL;
76 TR_DELAY;
77 TR_CLR_SCL;
78 TR_DELAY;
80 /* acknowledge bit */
81 TR_SET_SDA;
82 TR_SET_SCL;
83 TR_DELAY;
84 TR_CLR_SCL;
85 TR_DELAY;
88 /* stop condition */
89 TR_CLR_SDA;
90 TR_DELAY;
91 TR_SET_SCL;
92 TR_DELAY;
93 TR_SET_SDA;
94 TR_DELAY;
96 va_end(args);
99 static void tr_setvol(__u16 vol)
101 curvol = vol / 2048;
102 write_i2c(2, TDA7318_ADDR, curvol ^ 0x1f);
105 static int basstreble2chip[15] = {
106 0, 1, 2, 3, 4, 5, 6, 7, 14, 13, 12, 11, 10, 9, 8
109 static void tr_setbass(__u16 bass)
111 curbass = bass / 4370;
112 write_i2c(2, TDA7318_ADDR, 0x60 | basstreble2chip[curbass]);
115 static void tr_settreble(__u16 treble)
117 curtreble = treble / 4370;
118 write_i2c(2, TDA7318_ADDR, 0x70 | basstreble2chip[curtreble]);
121 static void tr_setstereo(int stereo)
123 curstereo = !!stereo;
124 ioval = (ioval & 0xfb) | (!curstereo << 2);
125 outb(ioval, io);
128 static void tr_setmute(int mute)
130 curmute = !!mute;
131 ioval = (ioval & 0xf7) | (curmute << 3);
132 outb(ioval, io);
135 static int tr_getsigstr(void)
137 int i, v;
139 for(i = 0, v = 0; i < 100; i++) v |= inb(io);
140 return (v & 1)? 0 : 0xffff;
143 static int tr_getstereo(void)
145 /* don't know how to determine it, just return the setting */
146 return curstereo;
149 static void tr_setfreq(unsigned long f)
151 f /= 160; /* Convert to 10 kHz units */
152 f += 1070; /* Add 10.7 MHz IF */
154 write_i2c(5, TSA6060T_ADDR, (f << 1) | 1, f >> 7, 0x60 | ((f >> 15) & 1), 0);
157 static int tr_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
159 switch(cmd)
161 case VIDIOCGCAP:
163 struct video_capability v;
165 v.type=VID_TYPE_TUNER;
166 v.channels=1;
167 v.audios=1;
169 /* No we don't do pictures */
170 v.maxwidth=0;
171 v.maxheight=0;
172 v.minwidth=0;
173 v.minheight=0;
175 strcpy(v.name, "Trust FM Radio");
177 if(copy_to_user(arg,&v,sizeof(v)))
178 return -EFAULT;
180 return 0;
182 case VIDIOCGTUNER:
184 struct video_tuner v;
186 if(copy_from_user(&v, arg,sizeof(v))!=0)
187 return -EFAULT;
189 if(v.tuner) /* Only 1 tuner */
190 return -EINVAL;
192 v.rangelow = 87500 * 16;
193 v.rangehigh = 108000 * 16;
194 v.flags = VIDEO_TUNER_LOW;
195 v.mode = VIDEO_MODE_AUTO;
197 v.signal = tr_getsigstr();
198 if(tr_getstereo())
199 v.flags |= VIDEO_TUNER_STEREO_ON;
201 strcpy(v.name, "FM");
203 if(copy_to_user(arg,&v, sizeof(v)))
204 return -EFAULT;
206 return 0;
208 case VIDIOCSTUNER:
210 struct video_tuner v;
212 if(copy_from_user(&v, arg, sizeof(v)))
213 return -EFAULT;
214 if(v.tuner != 0)
215 return -EINVAL;
217 return 0;
219 case VIDIOCGFREQ:
220 if(copy_to_user(arg, &curfreq, sizeof(curfreq)))
221 return -EFAULT;
222 return 0;
224 case VIDIOCSFREQ:
226 unsigned long f;
228 if(copy_from_user(&f, arg, sizeof(curfreq)))
229 return -EFAULT;
230 tr_setfreq(f);
231 return 0;
233 case VIDIOCGAUDIO:
235 struct video_audio v;
237 memset(&v,0, sizeof(v));
238 v.flags = VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME |
239 VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE;
240 v.mode = curstereo? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
241 v.volume = curvol * 2048;
242 v.step = 2048;
243 v.bass = curbass * 4370;
244 v.treble = curtreble * 4370;
246 strcpy(v.name, "Trust FM Radio");
247 if(copy_to_user(arg,&v, sizeof(v)))
248 return -EFAULT;
249 return 0;
251 case VIDIOCSAUDIO:
253 struct video_audio v;
255 if(copy_from_user(&v, arg, sizeof(v)))
256 return -EFAULT;
257 if(v.audio)
258 return -EINVAL;
260 tr_setvol(v.volume);
261 tr_setbass(v.bass);
262 tr_settreble(v.treble);
263 tr_setstereo(v.mode & VIDEO_SOUND_STEREO);
264 tr_setmute(v.flags & VIDEO_AUDIO_MUTE);
265 return 0;
267 default:
268 return -ENOIOCTLCMD;
272 static int tr_open(struct video_device *dev, int flags)
274 if(users)
275 return -EBUSY;
276 users++;
277 MOD_INC_USE_COUNT;
278 return 0;
281 static void tr_close(struct video_device *dev)
283 users--;
284 MOD_DEC_USE_COUNT;
287 static struct video_device trust_radio=
289 "Trust FM Radio",
290 VID_TYPE_TUNER,
291 VID_HARDWARE_TRUST,
292 tr_open,
293 tr_close,
294 NULL, /* Can't read (no capture ability) */
295 NULL, /* Can't write */
296 NULL, /* No poll */
297 tr_ioctl,
298 NULL,
299 NULL
302 static int __init trust_init(void)
304 if(io == -1) {
305 printk(KERN_ERR "You must set an I/O address with io=0x???\n");
306 return -EINVAL;
308 if(check_region(io, 2)) {
309 printk(KERN_ERR "trust: port 0x%x already in use\n", io);
310 return -EBUSY;
312 if(video_register_device(&trust_radio, VFL_TYPE_RADIO)==-1)
313 return -EINVAL;
315 request_region(io, 2, "Trust FM Radio");
317 printk(KERN_INFO "Trust FM Radio card driver v1.0.\n");
319 write_i2c(2, TDA7318_ADDR, 0x80); /* speaker att. LF = 0 dB */
320 write_i2c(2, TDA7318_ADDR, 0xa0); /* speaker att. RF = 0 dB */
321 write_i2c(2, TDA7318_ADDR, 0xc0); /* speaker att. LR = 0 dB */
322 write_i2c(2, TDA7318_ADDR, 0xe0); /* speaker att. RR = 0 dB */
323 write_i2c(2, TDA7318_ADDR, 0x40); /* stereo 1 input, gain = 18.75 dB */
325 tr_setvol(0x8000);
326 tr_setbass(0x8000);
327 tr_settreble(0x8000);
328 tr_setstereo(1);
330 /* mute card - prevents noisy bootups */
331 tr_setmute(1);
333 return 0;
336 MODULE_AUTHOR("Eric Lammerts, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
337 MODULE_DESCRIPTION("A driver for the Trust FM Radio card.");
338 MODULE_PARM(io, "i");
339 MODULE_PARM_DESC(io, "I/O address of the Trust FM Radio card (0x350 or 0x358)");
341 EXPORT_NO_SYMBOLS;
343 static void __exit cleanup_trust_module(void)
345 video_unregister_device(&trust_radio);
346 release_region(io, 2);
349 module_init(trust_init);
350 module_exit(cleanup_trust_module);