Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.17 321 lines 7.0 kB view raw
1/* radio-trust.c - Trust FM Radio card driver for Linux 2.2 2 * by Eric Lammerts <eric@scintilla.utwente.nl> 3 * 4 * Based on radio-aztech.c. Original notes: 5 * 6 * Adapted to support the Video for Linux API by 7 * Russell Kroll <rkroll@exploits.org>. Based on original tuner code by: 8 * 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) 14 * 15 * The basis for this code may be found at http://bigbang.vtc.vsc.edu/fmradio/ 16 */ 17 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 */ 26 27/* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */ 28 29#ifndef CONFIG_RADIO_TRUST_PORT 30#define CONFIG_RADIO_TRUST_PORT -1 31#endif 32 33static int io = CONFIG_RADIO_TRUST_PORT; 34static int radio_nr = -1; 35static int ioval = 0xf; 36static __u16 curvol; 37static __u16 curbass; 38static __u16 curtreble; 39static unsigned long curfreq; 40static int curstereo; 41static int curmute; 42 43/* i2c addresses */ 44#define TDA7318_ADDR 0x88 45#define TSA6060T_ADDR 0xc4 46 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) 52 53static void write_i2c(int n, ...) 54{ 55 unsigned char val, mask; 56 va_list args; 57 58 va_start(args, n); 59 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; 67 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; 79 } 80 /* acknowledge bit */ 81 TR_SET_SDA; 82 TR_SET_SCL; 83 TR_DELAY; 84 TR_CLR_SCL; 85 TR_DELAY; 86 } 87 88 /* stop condition */ 89 TR_CLR_SDA; 90 TR_DELAY; 91 TR_SET_SCL; 92 TR_DELAY; 93 TR_SET_SDA; 94 TR_DELAY; 95 96 va_end(args); 97} 98 99static void tr_setvol(__u16 vol) 100{ 101 curvol = vol / 2048; 102 write_i2c(2, TDA7318_ADDR, curvol ^ 0x1f); 103} 104 105static int basstreble2chip[15] = { 106 0, 1, 2, 3, 4, 5, 6, 7, 14, 13, 12, 11, 10, 9, 8 107}; 108 109static void tr_setbass(__u16 bass) 110{ 111 curbass = bass / 4370; 112 write_i2c(2, TDA7318_ADDR, 0x60 | basstreble2chip[curbass]); 113} 114 115static void tr_settreble(__u16 treble) 116{ 117 curtreble = treble / 4370; 118 write_i2c(2, TDA7318_ADDR, 0x70 | basstreble2chip[curtreble]); 119} 120 121static void tr_setstereo(int stereo) 122{ 123 curstereo = !!stereo; 124 ioval = (ioval & 0xfb) | (!curstereo << 2); 125 outb(ioval, io); 126} 127 128static void tr_setmute(int mute) 129{ 130 curmute = !!mute; 131 ioval = (ioval & 0xf7) | (curmute << 3); 132 outb(ioval, io); 133} 134 135static int tr_getsigstr(void) 136{ 137 int i, v; 138 139 for(i = 0, v = 0; i < 100; i++) v |= inb(io); 140 return (v & 1)? 0 : 0xffff; 141} 142 143static int tr_getstereo(void) 144{ 145 /* don't know how to determine it, just return the setting */ 146 return curstereo; 147} 148 149static void tr_setfreq(unsigned long f) 150{ 151 f /= 160; /* Convert to 10 kHz units */ 152 f += 1070; /* Add 10.7 MHz IF */ 153 154 write_i2c(5, TSA6060T_ADDR, (f << 1) | 1, f >> 7, 0x60 | ((f >> 15) & 1), 0); 155} 156 157static int tr_do_ioctl(struct inode *inode, struct file *file, 158 unsigned int cmd, void *arg) 159{ 160 switch(cmd) 161 { 162 case VIDIOCGCAP: 163 { 164 struct video_capability *v = arg; 165 166 memset(v,0,sizeof(*v)); 167 v->type=VID_TYPE_TUNER; 168 v->channels=1; 169 v->audios=1; 170 strcpy(v->name, "Trust FM Radio"); 171 172 return 0; 173 } 174 case VIDIOCGTUNER: 175 { 176 struct video_tuner *v = arg; 177 178 if(v->tuner) /* Only 1 tuner */ 179 return -EINVAL; 180 181 v->rangelow = 87500 * 16; 182 v->rangehigh = 108000 * 16; 183 v->flags = VIDEO_TUNER_LOW; 184 v->mode = VIDEO_MODE_AUTO; 185 186 v->signal = tr_getsigstr(); 187 if(tr_getstereo()) 188 v->flags |= VIDEO_TUNER_STEREO_ON; 189 190 strcpy(v->name, "FM"); 191 192 return 0; 193 } 194 case VIDIOCSTUNER: 195 { 196 struct video_tuner *v = arg; 197 if(v->tuner != 0) 198 return -EINVAL; 199 return 0; 200 } 201 case VIDIOCGFREQ: 202 { 203 unsigned long *freq = arg; 204 *freq = curfreq; 205 return 0; 206 } 207 case VIDIOCSFREQ: 208 { 209 unsigned long *freq = arg; 210 tr_setfreq(*freq); 211 return 0; 212 } 213 case VIDIOCGAUDIO: 214 { 215 struct video_audio *v = arg; 216 217 memset(v,0, sizeof(*v)); 218 v->flags = VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME | 219 VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE; 220 v->mode = curstereo? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; 221 v->volume = curvol * 2048; 222 v->step = 2048; 223 v->bass = curbass * 4370; 224 v->treble = curtreble * 4370; 225 226 strcpy(v->name, "Trust FM Radio"); 227 return 0; 228 } 229 case VIDIOCSAUDIO: 230 { 231 struct video_audio *v = arg; 232 233 if(v->audio) 234 return -EINVAL; 235 tr_setvol(v->volume); 236 tr_setbass(v->bass); 237 tr_settreble(v->treble); 238 tr_setstereo(v->mode & VIDEO_SOUND_STEREO); 239 tr_setmute(v->flags & VIDEO_AUDIO_MUTE); 240 return 0; 241 } 242 default: 243 return -ENOIOCTLCMD; 244 } 245} 246 247static int tr_ioctl(struct inode *inode, struct file *file, 248 unsigned int cmd, unsigned long arg) 249{ 250 return video_usercopy(inode, file, cmd, arg, tr_do_ioctl); 251} 252 253static struct file_operations trust_fops = { 254 .owner = THIS_MODULE, 255 .open = video_exclusive_open, 256 .release = video_exclusive_release, 257 .ioctl = tr_ioctl, 258 .compat_ioctl = v4l_compat_ioctl32, 259 .llseek = no_llseek, 260}; 261 262static struct video_device trust_radio= 263{ 264 .owner = THIS_MODULE, 265 .name = "Trust FM Radio", 266 .type = VID_TYPE_TUNER, 267 .hardware = VID_HARDWARE_TRUST, 268 .fops = &trust_fops, 269}; 270 271static int __init trust_init(void) 272{ 273 if(io == -1) { 274 printk(KERN_ERR "You must set an I/O address with io=0x???\n"); 275 return -EINVAL; 276 } 277 if(!request_region(io, 2, "Trust FM Radio")) { 278 printk(KERN_ERR "trust: port 0x%x already in use\n", io); 279 return -EBUSY; 280 } 281 if(video_register_device(&trust_radio, VFL_TYPE_RADIO, radio_nr)==-1) 282 { 283 release_region(io, 2); 284 return -EINVAL; 285 } 286 287 printk(KERN_INFO "Trust FM Radio card driver v1.0.\n"); 288 289 write_i2c(2, TDA7318_ADDR, 0x80); /* speaker att. LF = 0 dB */ 290 write_i2c(2, TDA7318_ADDR, 0xa0); /* speaker att. RF = 0 dB */ 291 write_i2c(2, TDA7318_ADDR, 0xc0); /* speaker att. LR = 0 dB */ 292 write_i2c(2, TDA7318_ADDR, 0xe0); /* speaker att. RR = 0 dB */ 293 write_i2c(2, TDA7318_ADDR, 0x40); /* stereo 1 input, gain = 18.75 dB */ 294 295 tr_setvol(0x8000); 296 tr_setbass(0x8000); 297 tr_settreble(0x8000); 298 tr_setstereo(1); 299 300 /* mute card - prevents noisy bootups */ 301 tr_setmute(1); 302 303 return 0; 304} 305 306MODULE_AUTHOR("Eric Lammerts, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); 307MODULE_DESCRIPTION("A driver for the Trust FM Radio card."); 308MODULE_LICENSE("GPL"); 309 310module_param(io, int, 0); 311MODULE_PARM_DESC(io, "I/O address of the Trust FM Radio card (0x350 or 0x358)"); 312module_param(radio_nr, int, 0); 313 314static void __exit cleanup_trust_module(void) 315{ 316 video_unregister_device(&trust_radio); 317 release_region(io, 2); 318} 319 320module_init(trust_init); 321module_exit(cleanup_trust_module);