1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (c) by Lee Revell <rlrevell@joe-job.com> |
4 | * Clemens Ladisch <clemens@ladisch.de> |
5 | * Oswald Buddenhagen <oswald.buddenhagen@gmx.de> |
6 | * |
7 | * Routines for control of EMU10K1 chips |
8 | */ |
9 | |
10 | #include <linux/time.h> |
11 | #include <sound/core.h> |
12 | #include <sound/emu10k1.h> |
13 | |
14 | static int snd_emu10k1_timer_start(struct snd_timer *timer) |
15 | { |
16 | struct snd_emu10k1 *emu; |
17 | unsigned int delay; |
18 | |
19 | emu = snd_timer_chip(timer); |
20 | delay = timer->sticks - 1; |
21 | if (delay < 5 ) /* minimum time is 5 ticks */ |
22 | delay = 5; |
23 | snd_emu10k1_intr_enable(emu, INTE_INTERVALTIMERENB); |
24 | outw(value: delay & TIMER_RATE_MASK, port: emu->port + TIMER); |
25 | return 0; |
26 | } |
27 | |
28 | static int snd_emu10k1_timer_stop(struct snd_timer *timer) |
29 | { |
30 | struct snd_emu10k1 *emu; |
31 | |
32 | emu = snd_timer_chip(timer); |
33 | snd_emu10k1_intr_disable(emu, INTE_INTERVALTIMERENB); |
34 | return 0; |
35 | } |
36 | |
37 | static unsigned long snd_emu10k1_timer_c_resolution(struct snd_timer *timer) |
38 | { |
39 | struct snd_emu10k1 *emu = snd_timer_chip(timer); |
40 | |
41 | if (emu->card_capabilities->emu_model && |
42 | emu->emu1010.word_clock == 44100) |
43 | return 22676; // 1 sample @ 44.1 kHz = 22.675736...us |
44 | else |
45 | return 20833; // 1 sample @ 48 kHz = 20.833...us |
46 | } |
47 | |
48 | static int snd_emu10k1_timer_precise_resolution(struct snd_timer *timer, |
49 | unsigned long *num, unsigned long *den) |
50 | { |
51 | struct snd_emu10k1 *emu = snd_timer_chip(timer); |
52 | |
53 | *num = 1; |
54 | if (emu->card_capabilities->emu_model) |
55 | *den = emu->emu1010.word_clock; |
56 | else |
57 | *den = 48000; |
58 | return 0; |
59 | } |
60 | |
61 | static const struct snd_timer_hardware snd_emu10k1_timer_hw = { |
62 | .flags = SNDRV_TIMER_HW_AUTO, |
63 | .ticks = 1024, |
64 | .start = snd_emu10k1_timer_start, |
65 | .stop = snd_emu10k1_timer_stop, |
66 | .c_resolution = snd_emu10k1_timer_c_resolution, |
67 | .precise_resolution = snd_emu10k1_timer_precise_resolution, |
68 | }; |
69 | |
70 | int snd_emu10k1_timer(struct snd_emu10k1 *emu, int device) |
71 | { |
72 | struct snd_timer *timer = NULL; |
73 | struct snd_timer_id tid; |
74 | int err; |
75 | |
76 | tid.dev_class = SNDRV_TIMER_CLASS_CARD; |
77 | tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE; |
78 | tid.card = emu->card->number; |
79 | tid.device = device; |
80 | tid.subdevice = 0; |
81 | err = snd_timer_new(card: emu->card, id: "EMU10K1" , tid: &tid, rtimer: &timer); |
82 | if (err >= 0) { |
83 | strcpy(p: timer->name, q: "EMU10K1 timer" ); |
84 | timer->private_data = emu; |
85 | timer->hw = snd_emu10k1_timer_hw; |
86 | } |
87 | emu->timer = timer; |
88 | return err; |
89 | } |
90 | |