1f8c08524SHans Verkuil /* 2f8c08524SHans Verkuil * GemTek radio card driver 3f8c08524SHans Verkuil * 4f8c08524SHans Verkuil * Copyright 1998 Jonas Munsin <jmunsin@iki.fi> 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * GemTek hasn't released any specs on the card, so the protocol had to 71da177e4SLinus Torvalds * be reverse engineered with dosemu. 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * Besides the protocol changes, this is mostly a copy of: 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds * RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff 121da177e4SLinus Torvalds * 131da177e4SLinus Torvalds * Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood 14d9b01449SAlan Cox * Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk> 151da177e4SLinus Torvalds * Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org> 161da177e4SLinus Torvalds * 17f8c08524SHans Verkuil * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com> 18d1c4ecdeSMauro Carvalho Chehab * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org> 19f8c08524SHans Verkuil * 20f8c08524SHans Verkuil * Note: this card seems to swap the left and right audio channels! 21f8c08524SHans Verkuil * 22f8c08524SHans Verkuil * Fully tested with the Keene USB FM Transmitter and the v4l2-compliance tool. 231da177e4SLinus Torvalds */ 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds #include <linux/module.h> /* Modules */ 261da177e4SLinus Torvalds #include <linux/init.h> /* Initdata */ 27fb911ee8SPeter Osterlund #include <linux/ioport.h> /* request_region */ 281da177e4SLinus Torvalds #include <linux/delay.h> /* udelay */ 29d1c4ecdeSMauro Carvalho Chehab #include <linux/videodev2.h> /* kernel radio structs */ 30502b71b5SHans Verkuil #include <linux/mutex.h> 31502b71b5SHans Verkuil #include <linux/io.h> /* outb, outb_p */ 3238ed1aefSOndrej Zary #include <linux/pnp.h> 339f1dfccfSHans Verkuil #include <linux/slab.h> 34502b71b5SHans Verkuil #include <media/v4l2-ioctl.h> 35502b71b5SHans Verkuil #include <media/v4l2-device.h> 36f8c08524SHans Verkuil #include "radio-isa.h" 37502b71b5SHans Verkuil 384753647eSPekka Seppanen /* 394753647eSPekka Seppanen * Module info. 404753647eSPekka Seppanen */ 414753647eSPekka Seppanen 4229834c1aSMauro Carvalho Chehab MODULE_AUTHOR("Jonas Munsin, Pekka Seppänen <pexu@kapsi.fi>"); 434753647eSPekka Seppanen MODULE_DESCRIPTION("A driver for the GemTek Radio card."); 444753647eSPekka Seppanen MODULE_LICENSE("GPL"); 45f8c08524SHans Verkuil MODULE_VERSION("1.0.0"); 464753647eSPekka Seppanen 474753647eSPekka Seppanen /* 484753647eSPekka Seppanen * Module params. 494753647eSPekka Seppanen */ 504753647eSPekka Seppanen 514753647eSPekka Seppanen #ifndef CONFIG_RADIO_GEMTEK_PORT 524753647eSPekka Seppanen #define CONFIG_RADIO_GEMTEK_PORT -1 534753647eSPekka Seppanen #endif 544753647eSPekka Seppanen #ifndef CONFIG_RADIO_GEMTEK_PROBE 554753647eSPekka Seppanen #define CONFIG_RADIO_GEMTEK_PROBE 1 564753647eSPekka Seppanen #endif 574753647eSPekka Seppanen 58f8c08524SHans Verkuil #define GEMTEK_MAX 4 59f8c08524SHans Verkuil 6090ab5ee9SRusty Russell static bool probe = CONFIG_RADIO_GEMTEK_PROBE; 6190ab5ee9SRusty Russell static bool hardmute; 62f8c08524SHans Verkuil static int io[GEMTEK_MAX] = { [0] = CONFIG_RADIO_GEMTEK_PORT, 63f8c08524SHans Verkuil [1 ... (GEMTEK_MAX - 1)] = -1 }; 64f8c08524SHans Verkuil static int radio_nr[GEMTEK_MAX] = { [0 ... (GEMTEK_MAX - 1)] = -1 }; 654753647eSPekka Seppanen 66f8c08524SHans Verkuil module_param(probe, bool, 0444); 67f8c08524SHans Verkuil MODULE_PARM_DESC(probe, "Enable automatic device probing."); 68f8c08524SHans Verkuil 69f8c08524SHans Verkuil module_param(hardmute, bool, 0644); 70547633deSMauro Carvalho Chehab MODULE_PARM_DESC(hardmute, "Enable 'hard muting' by shutting down PLL, may reduce static noise."); 71f8c08524SHans Verkuil 72f8c08524SHans Verkuil module_param_array(io, int, NULL, 0444); 73547633deSMauro Carvalho Chehab MODULE_PARM_DESC(io, "Force I/O ports for the GemTek Radio card if automatic probing is disabled or fails. The most common I/O ports are: 0x20c 0x30c, 0x24c or 0x34c (0x20c, 0x248 and 0x28c have been reported to work for the combined sound/radiocard)."); 744753647eSPekka Seppanen 75f8c08524SHans Verkuil module_param_array(radio_nr, int, NULL, 0444); 76f8c08524SHans Verkuil MODULE_PARM_DESC(radio_nr, "Radio device numbers"); 774753647eSPekka Seppanen 78857e594aSTrent Piepho /* 79857e594aSTrent Piepho * Frequency calculation constants. Intermediate frequency 10.52 MHz (nominal 80857e594aSTrent Piepho * value 10.7 MHz), reference divisor 6.39 kHz (nominal 6.25 kHz). 81857e594aSTrent Piepho */ 82857e594aSTrent Piepho #define FSCALE 8 83857e594aSTrent Piepho #define IF_OFFSET ((unsigned int)(10.52 * 16000 * (1<<FSCALE))) 84857e594aSTrent Piepho #define REF_FREQ ((unsigned int)(6.39 * 16 * (1<<FSCALE))) 85857e594aSTrent Piepho 864753647eSPekka Seppanen #define GEMTEK_CK 0x01 /* Clock signal */ 874753647eSPekka Seppanen #define GEMTEK_DA 0x02 /* Serial data */ 884753647eSPekka Seppanen #define GEMTEK_CE 0x04 /* Chip enable */ 894753647eSPekka Seppanen #define GEMTEK_NS 0x08 /* No signal */ 904753647eSPekka Seppanen #define GEMTEK_MT 0x10 /* Line mute */ 914753647eSPekka Seppanen #define GEMTEK_STDF_3_125_KHZ 0x01 /* Standard frequency 3.125 kHz */ 924753647eSPekka Seppanen #define GEMTEK_PLL_OFF 0x07 /* PLL off */ 934753647eSPekka Seppanen 944753647eSPekka Seppanen #define BU2614_BUS_SIZE 32 /* BU2614 / BU2614FS bus size */ 954753647eSPekka Seppanen 964753647eSPekka Seppanen #define SHORT_DELAY 5 /* usec */ 974753647eSPekka Seppanen #define LONG_DELAY 75 /* usec */ 984753647eSPekka Seppanen 99502b71b5SHans Verkuil struct gemtek { 100f8c08524SHans Verkuil struct radio_isa_card isa; 101f8c08524SHans Verkuil bool muted; 102b25be979STrent Piepho u32 bu2614data; 1034753647eSPekka Seppanen }; 1044753647eSPekka Seppanen 105b25be979STrent Piepho #define BU2614_FREQ_BITS 16 /* D0..D15, Frequency data */ 106b25be979STrent Piepho #define BU2614_PORT_BITS 3 /* P0..P2, Output port control data */ 107b25be979STrent Piepho #define BU2614_VOID_BITS 4 /* unused */ 108b25be979STrent Piepho #define BU2614_FMES_BITS 1 /* CT, Frequency measurement beginning data */ 109b25be979STrent Piepho #define BU2614_STDF_BITS 3 /* R0..R2, Standard frequency data */ 110b25be979STrent Piepho #define BU2614_SWIN_BITS 1 /* S, Switch between FMIN / AMIN */ 111b25be979STrent Piepho #define BU2614_SWAL_BITS 1 /* PS, Swallow counter division (AMIN only)*/ 112b25be979STrent Piepho #define BU2614_VOID2_BITS 1 /* unused */ 113b25be979STrent Piepho #define BU2614_FMUN_BITS 1 /* GT, Frequency measurement time & unlock */ 114b25be979STrent Piepho #define BU2614_TEST_BITS 1 /* TS, Test data is input */ 1154753647eSPekka Seppanen 116b25be979STrent Piepho #define BU2614_FREQ_SHIFT 0 117b25be979STrent Piepho #define BU2614_PORT_SHIFT (BU2614_FREQ_BITS + BU2614_FREQ_SHIFT) 118b25be979STrent Piepho #define BU2614_VOID_SHIFT (BU2614_PORT_BITS + BU2614_PORT_SHIFT) 119b25be979STrent Piepho #define BU2614_FMES_SHIFT (BU2614_VOID_BITS + BU2614_VOID_SHIFT) 120b25be979STrent Piepho #define BU2614_STDF_SHIFT (BU2614_FMES_BITS + BU2614_FMES_SHIFT) 121b25be979STrent Piepho #define BU2614_SWIN_SHIFT (BU2614_STDF_BITS + BU2614_STDF_SHIFT) 122b25be979STrent Piepho #define BU2614_SWAL_SHIFT (BU2614_SWIN_BITS + BU2614_SWIN_SHIFT) 123b25be979STrent Piepho #define BU2614_VOID2_SHIFT (BU2614_SWAL_BITS + BU2614_SWAL_SHIFT) 124b25be979STrent Piepho #define BU2614_FMUN_SHIFT (BU2614_VOID2_BITS + BU2614_VOID2_SHIFT) 125b25be979STrent Piepho #define BU2614_TEST_SHIFT (BU2614_FMUN_BITS + BU2614_FMUN_SHIFT) 126b25be979STrent Piepho 127b25be979STrent Piepho #define MKMASK(field) (((1<<BU2614_##field##_BITS) - 1) << \ 128b25be979STrent Piepho BU2614_##field##_SHIFT) 129b25be979STrent Piepho #define BU2614_PORT_MASK MKMASK(PORT) 130b25be979STrent Piepho #define BU2614_FREQ_MASK MKMASK(FREQ) 131b25be979STrent Piepho #define BU2614_VOID_MASK MKMASK(VOID) 132b25be979STrent Piepho #define BU2614_FMES_MASK MKMASK(FMES) 133b25be979STrent Piepho #define BU2614_STDF_MASK MKMASK(STDF) 134b25be979STrent Piepho #define BU2614_SWIN_MASK MKMASK(SWIN) 135b25be979STrent Piepho #define BU2614_SWAL_MASK MKMASK(SWAL) 136b25be979STrent Piepho #define BU2614_VOID2_MASK MKMASK(VOID2) 137b25be979STrent Piepho #define BU2614_FMUN_MASK MKMASK(FMUN) 138b25be979STrent Piepho #define BU2614_TEST_MASK MKMASK(TEST) 1394753647eSPekka Seppanen 1404753647eSPekka Seppanen /* 1414753647eSPekka Seppanen * Set data which will be sent to BU2614FS. 1424753647eSPekka Seppanen */ 143b25be979STrent Piepho #define gemtek_bu2614_set(dev, field, data) ((dev)->bu2614data = \ 144b25be979STrent Piepho ((dev)->bu2614data & ~field##_MASK) | ((data) << field##_SHIFT)) 1454753647eSPekka Seppanen 1464753647eSPekka Seppanen /* 1474753647eSPekka Seppanen * Transmit settings to BU2614FS over GemTek IC. 1484753647eSPekka Seppanen */ 149502b71b5SHans Verkuil static void gemtek_bu2614_transmit(struct gemtek *gt) 1504753647eSPekka Seppanen { 151f8c08524SHans Verkuil struct radio_isa_card *isa = >->isa; 1524753647eSPekka Seppanen int i, bit, q, mute; 1534753647eSPekka Seppanen 154502b71b5SHans Verkuil mute = gt->muted ? GEMTEK_MT : 0x00; 1554753647eSPekka Seppanen 156f8c08524SHans Verkuil outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, isa->io); 1574753647eSPekka Seppanen udelay(LONG_DELAY); 1584753647eSPekka Seppanen 159502b71b5SHans Verkuil for (i = 0, q = gt->bu2614data; i < 32; i++, q >>= 1) { 160b25be979STrent Piepho bit = (q & 1) ? GEMTEK_DA : 0; 161f8c08524SHans Verkuil outb_p(mute | GEMTEK_CE | bit, isa->io); 1624753647eSPekka Seppanen udelay(SHORT_DELAY); 163f8c08524SHans Verkuil outb_p(mute | GEMTEK_CE | bit | GEMTEK_CK, isa->io); 1644753647eSPekka Seppanen udelay(SHORT_DELAY); 1654753647eSPekka Seppanen } 1664753647eSPekka Seppanen 167f8c08524SHans Verkuil outb_p(mute | GEMTEK_DA | GEMTEK_CK, isa->io); 1684753647eSPekka Seppanen udelay(SHORT_DELAY); 1694753647eSPekka Seppanen } 1704753647eSPekka Seppanen 1714753647eSPekka Seppanen /* 172857e594aSTrent Piepho * Calculate divisor from FM-frequency for BU2614FS (3.125 KHz STDF expected). 1734753647eSPekka Seppanen */ 174857e594aSTrent Piepho static unsigned long gemtek_convfreq(unsigned long freq) 1754753647eSPekka Seppanen { 176857e594aSTrent Piepho return ((freq << FSCALE) + IF_OFFSET + REF_FREQ / 2) / REF_FREQ; 1774753647eSPekka Seppanen } 1784753647eSPekka Seppanen 179f8c08524SHans Verkuil static struct radio_isa_card *gemtek_alloc(void) 180f8c08524SHans Verkuil { 181f8c08524SHans Verkuil struct gemtek *gt = kzalloc(sizeof(*gt), GFP_KERNEL); 182f8c08524SHans Verkuil 183f8c08524SHans Verkuil if (gt) 184f8c08524SHans Verkuil gt->muted = true; 185f8c08524SHans Verkuil return gt ? >->isa : NULL; 186f8c08524SHans Verkuil } 187f8c08524SHans Verkuil 1884753647eSPekka Seppanen /* 1894753647eSPekka Seppanen * Set FM-frequency. 1904753647eSPekka Seppanen */ 191f8c08524SHans Verkuil static int gemtek_s_frequency(struct radio_isa_card *isa, u32 freq) 1924753647eSPekka Seppanen { 193f8c08524SHans Verkuil struct gemtek *gt = container_of(isa, struct gemtek, isa); 1944753647eSPekka Seppanen 195f8c08524SHans Verkuil if (hardmute && gt->muted) 196f8c08524SHans Verkuil return 0; 1974753647eSPekka Seppanen 198502b71b5SHans Verkuil gemtek_bu2614_set(gt, BU2614_PORT, 0); 199502b71b5SHans Verkuil gemtek_bu2614_set(gt, BU2614_FMES, 0); 200502b71b5SHans Verkuil gemtek_bu2614_set(gt, BU2614_SWIN, 0); /* FM-mode */ 201502b71b5SHans Verkuil gemtek_bu2614_set(gt, BU2614_SWAL, 0); 202502b71b5SHans Verkuil gemtek_bu2614_set(gt, BU2614_FMUN, 1); /* GT bit set */ 203502b71b5SHans Verkuil gemtek_bu2614_set(gt, BU2614_TEST, 0); 204502b71b5SHans Verkuil gemtek_bu2614_set(gt, BU2614_STDF, GEMTEK_STDF_3_125_KHZ); 205502b71b5SHans Verkuil gemtek_bu2614_set(gt, BU2614_FREQ, gemtek_convfreq(freq)); 206502b71b5SHans Verkuil gemtek_bu2614_transmit(gt); 207f8c08524SHans Verkuil return 0; 2084753647eSPekka Seppanen } 2094753647eSPekka Seppanen 2104753647eSPekka Seppanen /* 2114753647eSPekka Seppanen * Set mute flag. 2124753647eSPekka Seppanen */ 213f8c08524SHans Verkuil static int gemtek_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol) 2144753647eSPekka Seppanen { 215f8c08524SHans Verkuil struct gemtek *gt = container_of(isa, struct gemtek, isa); 2164753647eSPekka Seppanen int i; 217502b71b5SHans Verkuil 218f8c08524SHans Verkuil gt->muted = mute; 2194753647eSPekka Seppanen if (hardmute) { 220f8c08524SHans Verkuil if (!mute) 221f8c08524SHans Verkuil return gemtek_s_frequency(isa, isa->freq); 222f8c08524SHans Verkuil 2234753647eSPekka Seppanen /* Turn off PLL, disable data output */ 224502b71b5SHans Verkuil gemtek_bu2614_set(gt, BU2614_PORT, 0); 225502b71b5SHans Verkuil gemtek_bu2614_set(gt, BU2614_FMES, 0); /* CT bit off */ 226502b71b5SHans Verkuil gemtek_bu2614_set(gt, BU2614_SWIN, 0); /* FM-mode */ 227502b71b5SHans Verkuil gemtek_bu2614_set(gt, BU2614_SWAL, 0); 228502b71b5SHans Verkuil gemtek_bu2614_set(gt, BU2614_FMUN, 0); /* GT bit off */ 229502b71b5SHans Verkuil gemtek_bu2614_set(gt, BU2614_TEST, 0); 230502b71b5SHans Verkuil gemtek_bu2614_set(gt, BU2614_STDF, GEMTEK_PLL_OFF); 231502b71b5SHans Verkuil gemtek_bu2614_set(gt, BU2614_FREQ, 0); 232502b71b5SHans Verkuil gemtek_bu2614_transmit(gt); 233f8c08524SHans Verkuil return 0; 234502b71b5SHans Verkuil } 235502b71b5SHans Verkuil 2364753647eSPekka Seppanen /* Read bus contents (CE, CK and DA). */ 237f8c08524SHans Verkuil i = inb_p(isa->io); 2384753647eSPekka Seppanen /* Write it back with mute flag set. */ 239f8c08524SHans Verkuil outb_p((i >> 5) | (mute ? GEMTEK_MT : 0), isa->io); 2404753647eSPekka Seppanen udelay(SHORT_DELAY); 241f8c08524SHans Verkuil return 0; 2424753647eSPekka Seppanen } 2434753647eSPekka Seppanen 244f8c08524SHans Verkuil static u32 gemtek_g_rxsubchans(struct radio_isa_card *isa) 2454753647eSPekka Seppanen { 246f8c08524SHans Verkuil if (inb_p(isa->io) & GEMTEK_NS) 247f8c08524SHans Verkuil return V4L2_TUNER_SUB_MONO; 248f8c08524SHans Verkuil return V4L2_TUNER_SUB_STEREO; 2494753647eSPekka Seppanen } 2504753647eSPekka Seppanen 2514753647eSPekka Seppanen /* 2524753647eSPekka Seppanen * Check if requested card acts like GemTek Radio card. 2534753647eSPekka Seppanen */ 254f8c08524SHans Verkuil static bool gemtek_probe(struct radio_isa_card *isa, int io) 2554753647eSPekka Seppanen { 2564753647eSPekka Seppanen int i, q; 2574753647eSPekka Seppanen 258f8c08524SHans Verkuil q = inb_p(io); /* Read bus contents before probing. */ 2594753647eSPekka Seppanen /* Try to turn on CE, CK and DA respectively and check if card responds 2604753647eSPekka Seppanen properly. */ 2614753647eSPekka Seppanen for (i = 0; i < 3; ++i) { 262f8c08524SHans Verkuil outb_p(1 << i, io); 2634753647eSPekka Seppanen udelay(SHORT_DELAY); 2644753647eSPekka Seppanen 265f8c08524SHans Verkuil if ((inb_p(io) & ~GEMTEK_NS) != (0x17 | (1 << (i + 5)))) 266f8c08524SHans Verkuil return false; 2674753647eSPekka Seppanen } 268f8c08524SHans Verkuil outb_p(q >> 5, io); /* Write bus contents back. */ 2694753647eSPekka Seppanen udelay(SHORT_DELAY); 270f8c08524SHans Verkuil return true; 2714753647eSPekka Seppanen } 2724753647eSPekka Seppanen 273f8c08524SHans Verkuil static const struct radio_isa_ops gemtek_ops = { 274f8c08524SHans Verkuil .alloc = gemtek_alloc, 275f8c08524SHans Verkuil .probe = gemtek_probe, 276f8c08524SHans Verkuil .s_mute_volume = gemtek_s_mute_volume, 277f8c08524SHans Verkuil .s_frequency = gemtek_s_frequency, 278f8c08524SHans Verkuil .g_rxsubchans = gemtek_g_rxsubchans, 2791da177e4SLinus Torvalds }; 2801da177e4SLinus Torvalds 281f8c08524SHans Verkuil static const int gemtek_ioports[] = { 0x20c, 0x30c, 0x24c, 0x34c, 0x248, 0x28c }; 282e9bb9c64SDouglas Landgraf 28338ed1aefSOndrej Zary #ifdef CONFIG_PNP 284db4a8505SArvind Yadav static const struct pnp_device_id gemtek_pnp_devices[] = { 28538ed1aefSOndrej Zary /* AOpen FX-3D/Pro Radio */ 28638ed1aefSOndrej Zary {.id = "ADS7183", .driver_data = 0}, 28738ed1aefSOndrej Zary {.id = ""} 28838ed1aefSOndrej Zary }; 28938ed1aefSOndrej Zary 29038ed1aefSOndrej Zary MODULE_DEVICE_TABLE(pnp, gemtek_pnp_devices); 29138ed1aefSOndrej Zary #endif 29238ed1aefSOndrej Zary 293f8c08524SHans Verkuil static struct radio_isa_driver gemtek_driver = { 294f8c08524SHans Verkuil .driver = { 295f8c08524SHans Verkuil .match = radio_isa_match, 296f8c08524SHans Verkuil .probe = radio_isa_probe, 297f8c08524SHans Verkuil .remove = radio_isa_remove, 298f8c08524SHans Verkuil .driver = { 299f8c08524SHans Verkuil .name = "radio-gemtek", 300f8c08524SHans Verkuil }, 301f8c08524SHans Verkuil }, 30238ed1aefSOndrej Zary #ifdef CONFIG_PNP 30338ed1aefSOndrej Zary .pnp_driver = { 30438ed1aefSOndrej Zary .name = "radio-gemtek", 30538ed1aefSOndrej Zary .id_table = gemtek_pnp_devices, 30638ed1aefSOndrej Zary .probe = radio_isa_pnp_probe, 30738ed1aefSOndrej Zary .remove = radio_isa_pnp_remove, 30838ed1aefSOndrej Zary }, 30938ed1aefSOndrej Zary #endif 310f8c08524SHans Verkuil .io_params = io, 311f8c08524SHans Verkuil .radio_nr_params = radio_nr, 312f8c08524SHans Verkuil .io_ports = gemtek_ioports, 313f8c08524SHans Verkuil .num_of_io_ports = ARRAY_SIZE(gemtek_ioports), 314f8c08524SHans Verkuil .region_size = 1, 315f8c08524SHans Verkuil .card = "GemTek Radio", 316f8c08524SHans Verkuil .ops = &gemtek_ops, 317f8c08524SHans Verkuil .has_stereo = true, 3181da177e4SLinus Torvalds }; 3191da177e4SLinus Torvalds 3201da177e4SLinus Torvalds static int __init gemtek_init(void) 3211da177e4SLinus Torvalds { 322f8c08524SHans Verkuil gemtek_driver.probe = probe; 32338ed1aefSOndrej Zary #ifdef CONFIG_PNP 32438ed1aefSOndrej Zary pnp_register_driver(&gemtek_driver.pnp_driver); 32538ed1aefSOndrej Zary #endif 326f8c08524SHans Verkuil return isa_register_driver(&gemtek_driver.driver, GEMTEK_MAX); 3271da177e4SLinus Torvalds } 3281da177e4SLinus Torvalds 3294753647eSPekka Seppanen static void __exit gemtek_exit(void) 3301da177e4SLinus Torvalds { 3318b4b6818SMauro Carvalho Chehab hardmute = true; /* Turn off PLL */ 33238ed1aefSOndrej Zary #ifdef CONFIG_PNP 33338ed1aefSOndrej Zary pnp_unregister_driver(&gemtek_driver.pnp_driver); 33438ed1aefSOndrej Zary #endif 335f8c08524SHans Verkuil isa_unregister_driver(&gemtek_driver.driver); 3361da177e4SLinus Torvalds } 3371da177e4SLinus Torvalds 3381da177e4SLinus Torvalds module_init(gemtek_init); 3394753647eSPekka Seppanen module_exit(gemtek_exit); 340