#define GEMTEK_LOWFREQ (87*16000)
#define GEMTEK_HIGHFREQ (108*16000)
+/*
+ * Frequency calculation constants. Intermediate frequency 10.52 MHz (nominal
+ * value 10.7 MHz), reference divisor 6.39 kHz (nominal 6.25 kHz).
+ */
+#define FSCALE 8
+#define IF_OFFSET ((unsigned int)(10.52 * 16000 * (1<<FSCALE)))
+#define REF_FREQ ((unsigned int)(6.39 * 16 * (1<<FSCALE)))
+
#define GEMTEK_CK 0x01 /* Clock signal */
#define GEMTEK_DA 0x02 /* Serial data */
#define GEMTEK_CE 0x04 /* Chip enable */
#define GEMTEK_PLL_OFF 0x07 /* PLL off */
#define BU2614_BUS_SIZE 32 /* BU2614 / BU2614FS bus size */
-#define BU2614_NOPS 8 /* Number of supported operations */
#define SHORT_DELAY 5 /* usec */
#define LONG_DELAY 75 /* usec */
struct gemtek_device {
unsigned long lastfreq;
int muted;
- unsigned long bu2614data[BU2614_NOPS];
-};
-
-enum {
- BU2614_VOID,
- BU2614_FREQ, /* D0..D15, Frequency data */
- BU2614_PORT, /* P0..P2, Output port control data */
- BU2614_FMES, /* CT, Frequency measurement beginning data */
- BU2614_STDF, /* R0..R2, Standard frequency data */
- BU2614_SWIN, /* S, Switch between FMIN / AMIN */
- BU2614_SWAL, /* PS, Swallow counter division (AMIN only) */
- BU2614_FMUN, /* GT, Frequency measurement time and unlock */
- BU2614_TEST /* TS, Test data is input */
+ u32 bu2614data;
};
-struct bu2614_op {
- int op; /* Operation */
- int size; /* Data size */
-};
+#define BU2614_FREQ_BITS 16 /* D0..D15, Frequency data */
+#define BU2614_PORT_BITS 3 /* P0..P2, Output port control data */
+#define BU2614_VOID_BITS 4 /* unused */
+#define BU2614_FMES_BITS 1 /* CT, Frequency measurement beginning data */
+#define BU2614_STDF_BITS 3 /* R0..R2, Standard frequency data */
+#define BU2614_SWIN_BITS 1 /* S, Switch between FMIN / AMIN */
+#define BU2614_SWAL_BITS 1 /* PS, Swallow counter division (AMIN only)*/
+#define BU2614_VOID2_BITS 1 /* unused */
+#define BU2614_FMUN_BITS 1 /* GT, Frequency measurement time & unlock */
+#define BU2614_TEST_BITS 1 /* TS, Test data is input */
+
+#define BU2614_FREQ_SHIFT 0
+#define BU2614_PORT_SHIFT (BU2614_FREQ_BITS + BU2614_FREQ_SHIFT)
+#define BU2614_VOID_SHIFT (BU2614_PORT_BITS + BU2614_PORT_SHIFT)
+#define BU2614_FMES_SHIFT (BU2614_VOID_BITS + BU2614_VOID_SHIFT)
+#define BU2614_STDF_SHIFT (BU2614_FMES_BITS + BU2614_FMES_SHIFT)
+#define BU2614_SWIN_SHIFT (BU2614_STDF_BITS + BU2614_STDF_SHIFT)
+#define BU2614_SWAL_SHIFT (BU2614_SWIN_BITS + BU2614_SWIN_SHIFT)
+#define BU2614_VOID2_SHIFT (BU2614_SWAL_BITS + BU2614_SWAL_SHIFT)
+#define BU2614_FMUN_SHIFT (BU2614_VOID2_BITS + BU2614_VOID2_SHIFT)
+#define BU2614_TEST_SHIFT (BU2614_FMUN_BITS + BU2614_FMUN_SHIFT)
+
+#define MKMASK(field) (((1<<BU2614_##field##_BITS) - 1) << \
+ BU2614_##field##_SHIFT)
+#define BU2614_PORT_MASK MKMASK(PORT)
+#define BU2614_FREQ_MASK MKMASK(FREQ)
+#define BU2614_VOID_MASK MKMASK(VOID)
+#define BU2614_FMES_MASK MKMASK(FMES)
+#define BU2614_STDF_MASK MKMASK(STDF)
+#define BU2614_SWIN_MASK MKMASK(SWIN)
+#define BU2614_SWAL_MASK MKMASK(SWAL)
+#define BU2614_VOID2_MASK MKMASK(VOID2)
+#define BU2614_FMUN_MASK MKMASK(FMUN)
+#define BU2614_TEST_MASK MKMASK(TEST)
static struct gemtek_device gemtek_unit;
-static struct bu2614_op bu2614ops[] = {
- {.op = BU2614_FREQ,
- .size = 0x10},
- {.op = BU2614_PORT,
- .size = 0x03},
- {.op = BU2614_VOID,
- .size = 0x04},
- {.op = BU2614_FMES,
- .size = 0x01},
- {.op = BU2614_STDF,
- .size = 0x03},
- {.op = BU2614_SWIN,
- .size = 0x01},
- {.op = BU2614_SWAL,
- .size = 0x01},
- {.op = BU2614_VOID,
- .size = 0x01},
- {.op = BU2614_FMUN,
- .size = 0x01},
- {.op = BU2614_TEST,
- .size = 0x01}
-};
-
static spinlock_t lock;
/*
* Set data which will be sent to BU2614FS.
*/
-static void gemtek_bu2614_set(struct gemtek_device *dev, int op,
- unsigned long data)
-{
- int i, q;
-
- for (i = 0, q = 0; q < ARRAY_SIZE(dev->bu2614data); ++i) {
- if (bu2614ops[i].op == op) {
- dev->bu2614data[q] =
- data & ((1 << bu2614ops[i].size) - 1);
- return;
- }
-
- if (bu2614ops[i].op != BU2614_VOID)
- ++q;
- }
-}
+#define gemtek_bu2614_set(dev, field, data) ((dev)->bu2614data = \
+ ((dev)->bu2614data & ~field##_MASK) | ((data) << field##_SHIFT))
/*
* Transmit settings to BU2614FS over GemTek IC.
outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, io);
udelay(LONG_DELAY);
- for (i = 0, q = 0; q < ARRAY_SIZE(dev->bu2614data); ++i) {
- for (bit = 0; bit < bu2614ops[i].size; ++bit) {
- if (bu2614ops[i].op != BU2614_VOID &&
- dev->bu2614data[q] & (1 << bit)) {
- outb_p(mute | GEMTEK_CE | GEMTEK_DA, io);
- udelay(SHORT_DELAY);
- outb_p(mute | GEMTEK_CE | GEMTEK_DA |
- GEMTEK_CK, io);
- udelay(SHORT_DELAY);
- } else {
- outb_p(mute | GEMTEK_CE, io);
- udelay(SHORT_DELAY);
- outb_p(mute | GEMTEK_CE | GEMTEK_CK, io);
- udelay(SHORT_DELAY);
- }
- }
-
- if (bu2614ops[i].op != BU2614_VOID)
- ++q;
+ for (i = 0, q = dev->bu2614data; i < 32; i++, q >>= 1) {
+ bit = (q & 1) ? GEMTEK_DA : 0;
+ outb_p(mute | GEMTEK_CE | bit, io);
+ udelay(SHORT_DELAY);
+ outb_p(mute | GEMTEK_CE | bit | GEMTEK_CK, io);
+ udelay(SHORT_DELAY);
}
outb_p(mute | GEMTEK_DA | GEMTEK_CK, io);
}
/*
- * Convert FM-frequency for BU2614FS (3.125 KHz STDF expected).
+ * Calculate divisor from FM-frequency for BU2614FS (3.125 KHz STDF expected).
*/
-static inline void gemtek_convfreq(unsigned long *freq)
+static unsigned long gemtek_convfreq(unsigned long freq)
{
- (*freq) /= 160;
- (*freq) += 1052; /* FMIN, 10.52 MHz */
- (*freq) *= 1565; /* STDF, 1 / 156.5 = 0.00639 */
- (*freq) /= 1000;
+ return ((freq<<FSCALE) + IF_OFFSET + REF_FREQ/2) / REF_FREQ;
}
/*
gemtek_bu2614_set(dev, BU2614_FMUN, 1); /* GT bit set */
gemtek_bu2614_set(dev, BU2614_TEST, 0);
- gemtek_convfreq(&freq);
-
gemtek_bu2614_set(dev, BU2614_STDF, GEMTEK_STDF_3_125_KHZ);
- gemtek_bu2614_set(dev, BU2614_FREQ, freq);
+ gemtek_bu2614_set(dev, BU2614_FREQ, gemtek_convfreq(freq));
gemtek_bu2614_transmit(dev);
}
.owner = THIS_MODULE,
.name = "GemTek Radio card",
.type = VID_TYPE_TUNER,
- .hardware = VID_HARDWARE_GEMTEK,
.fops = &gemtek_fops,
.vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = vidioc_g_tuner,
*/
static int __init gemtek_init(void)
{
- int i;
-
printk(KERN_INFO RADIO_BANNER "\n");
spin_lock_init(&lock);
/* Set defaults */
gemtek_unit.lastfreq = GEMTEK_LOWFREQ;
- for (i = 0; i < ARRAY_SIZE(gemtek_unit.bu2614data); ++i)
- gemtek_unit.bu2614data[i] = 0;
+ gemtek_unit.bu2614data = 0;
if (initmute)
gemtek_mute(&gemtek_unit);