xref: /openbmc/linux/sound/isa/gus/gus_timer.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1*1da177e4SLinus Torvalds /*
2*1da177e4SLinus Torvalds  *  Routines for Gravis UltraSound soundcards - Timers
3*1da177e4SLinus Torvalds  *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
4*1da177e4SLinus Torvalds  *
5*1da177e4SLinus Torvalds  *  GUS have similar timers as AdLib (OPL2/OPL3 chips).
6*1da177e4SLinus Torvalds  *
7*1da177e4SLinus Torvalds  *
8*1da177e4SLinus Torvalds  *   This program is free software; you can redistribute it and/or modify
9*1da177e4SLinus Torvalds  *   it under the terms of the GNU General Public License as published by
10*1da177e4SLinus Torvalds  *   the Free Software Foundation; either version 2 of the License, or
11*1da177e4SLinus Torvalds  *   (at your option) any later version.
12*1da177e4SLinus Torvalds  *
13*1da177e4SLinus Torvalds  *   This program is distributed in the hope that it will be useful,
14*1da177e4SLinus Torvalds  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15*1da177e4SLinus Torvalds  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16*1da177e4SLinus Torvalds  *   GNU General Public License for more details.
17*1da177e4SLinus Torvalds  *
18*1da177e4SLinus Torvalds  *   You should have received a copy of the GNU General Public License
19*1da177e4SLinus Torvalds  *   along with this program; if not, write to the Free Software
20*1da177e4SLinus Torvalds  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
21*1da177e4SLinus Torvalds  *
22*1da177e4SLinus Torvalds  */
23*1da177e4SLinus Torvalds 
24*1da177e4SLinus Torvalds #include <sound/driver.h>
25*1da177e4SLinus Torvalds #include <linux/time.h>
26*1da177e4SLinus Torvalds #include <sound/core.h>
27*1da177e4SLinus Torvalds #include <sound/gus.h>
28*1da177e4SLinus Torvalds 
29*1da177e4SLinus Torvalds /*
30*1da177e4SLinus Torvalds  *  Timer 1 - 80us
31*1da177e4SLinus Torvalds  */
32*1da177e4SLinus Torvalds 
33*1da177e4SLinus Torvalds static int snd_gf1_timer1_start(snd_timer_t * timer)
34*1da177e4SLinus Torvalds {
35*1da177e4SLinus Torvalds 	unsigned long flags;
36*1da177e4SLinus Torvalds 	unsigned char tmp;
37*1da177e4SLinus Torvalds 	unsigned int ticks;
38*1da177e4SLinus Torvalds 	snd_gus_card_t *gus;
39*1da177e4SLinus Torvalds 
40*1da177e4SLinus Torvalds 	gus = snd_timer_chip(timer);
41*1da177e4SLinus Torvalds 	spin_lock_irqsave(&gus->reg_lock, flags);
42*1da177e4SLinus Torvalds 	ticks = timer->sticks;
43*1da177e4SLinus Torvalds 	tmp = (gus->gf1.timer_enabled |= 4);
44*1da177e4SLinus Torvalds 	snd_gf1_write8(gus, SNDRV_GF1_GB_ADLIB_TIMER_1, 256 - ticks);	/* timer 1 count */
45*1da177e4SLinus Torvalds 	snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, tmp);	/* enable timer 1 IRQ */
46*1da177e4SLinus Torvalds 	snd_gf1_adlib_write(gus, 0x04, tmp >> 2);	/* timer 2 start */
47*1da177e4SLinus Torvalds 	spin_unlock_irqrestore(&gus->reg_lock, flags);
48*1da177e4SLinus Torvalds 	return 0;
49*1da177e4SLinus Torvalds }
50*1da177e4SLinus Torvalds 
51*1da177e4SLinus Torvalds static int snd_gf1_timer1_stop(snd_timer_t * timer)
52*1da177e4SLinus Torvalds {
53*1da177e4SLinus Torvalds 	unsigned long flags;
54*1da177e4SLinus Torvalds 	unsigned char tmp;
55*1da177e4SLinus Torvalds 	snd_gus_card_t *gus;
56*1da177e4SLinus Torvalds 
57*1da177e4SLinus Torvalds 	gus = snd_timer_chip(timer);
58*1da177e4SLinus Torvalds 	spin_lock_irqsave(&gus->reg_lock, flags);
59*1da177e4SLinus Torvalds 	tmp = (gus->gf1.timer_enabled &= ~4);
60*1da177e4SLinus Torvalds 	snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, tmp);	/* disable timer #1 */
61*1da177e4SLinus Torvalds 	spin_unlock_irqrestore(&gus->reg_lock, flags);
62*1da177e4SLinus Torvalds 	return 0;
63*1da177e4SLinus Torvalds }
64*1da177e4SLinus Torvalds 
65*1da177e4SLinus Torvalds /*
66*1da177e4SLinus Torvalds  *  Timer 2 - 320us
67*1da177e4SLinus Torvalds  */
68*1da177e4SLinus Torvalds 
69*1da177e4SLinus Torvalds static int snd_gf1_timer2_start(snd_timer_t * timer)
70*1da177e4SLinus Torvalds {
71*1da177e4SLinus Torvalds 	unsigned long flags;
72*1da177e4SLinus Torvalds 	unsigned char tmp;
73*1da177e4SLinus Torvalds 	unsigned int ticks;
74*1da177e4SLinus Torvalds 	snd_gus_card_t *gus;
75*1da177e4SLinus Torvalds 
76*1da177e4SLinus Torvalds 	gus = snd_timer_chip(timer);
77*1da177e4SLinus Torvalds 	spin_lock_irqsave(&gus->reg_lock, flags);
78*1da177e4SLinus Torvalds 	ticks = timer->sticks;
79*1da177e4SLinus Torvalds 	tmp = (gus->gf1.timer_enabled |= 8);
80*1da177e4SLinus Torvalds 	snd_gf1_write8(gus, SNDRV_GF1_GB_ADLIB_TIMER_2, 256 - ticks);	/* timer 2 count */
81*1da177e4SLinus Torvalds 	snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, tmp);	/* enable timer 2 IRQ */
82*1da177e4SLinus Torvalds 	snd_gf1_adlib_write(gus, 0x04, tmp >> 2);	/* timer 2 start */
83*1da177e4SLinus Torvalds 	spin_unlock_irqrestore(&gus->reg_lock, flags);
84*1da177e4SLinus Torvalds 	return 0;
85*1da177e4SLinus Torvalds }
86*1da177e4SLinus Torvalds 
87*1da177e4SLinus Torvalds static int snd_gf1_timer2_stop(snd_timer_t * timer)
88*1da177e4SLinus Torvalds {
89*1da177e4SLinus Torvalds 	unsigned long flags;
90*1da177e4SLinus Torvalds 	unsigned char tmp;
91*1da177e4SLinus Torvalds 	snd_gus_card_t *gus;
92*1da177e4SLinus Torvalds 
93*1da177e4SLinus Torvalds 	gus = snd_timer_chip(timer);
94*1da177e4SLinus Torvalds 	spin_lock_irqsave(&gus->reg_lock, flags);
95*1da177e4SLinus Torvalds 	tmp = (gus->gf1.timer_enabled &= ~8);
96*1da177e4SLinus Torvalds 	snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, tmp);	/* disable timer #1 */
97*1da177e4SLinus Torvalds 	spin_unlock_irqrestore(&gus->reg_lock, flags);
98*1da177e4SLinus Torvalds 	return 0;
99*1da177e4SLinus Torvalds }
100*1da177e4SLinus Torvalds 
101*1da177e4SLinus Torvalds /*
102*1da177e4SLinus Torvalds 
103*1da177e4SLinus Torvalds  */
104*1da177e4SLinus Torvalds 
105*1da177e4SLinus Torvalds static void snd_gf1_interrupt_timer1(snd_gus_card_t * gus)
106*1da177e4SLinus Torvalds {
107*1da177e4SLinus Torvalds 	snd_timer_t *timer = gus->gf1.timer1;
108*1da177e4SLinus Torvalds 
109*1da177e4SLinus Torvalds 	if (timer == NULL)
110*1da177e4SLinus Torvalds 		return;
111*1da177e4SLinus Torvalds 	snd_timer_interrupt(timer, timer->sticks);
112*1da177e4SLinus Torvalds }
113*1da177e4SLinus Torvalds 
114*1da177e4SLinus Torvalds static void snd_gf1_interrupt_timer2(snd_gus_card_t * gus)
115*1da177e4SLinus Torvalds {
116*1da177e4SLinus Torvalds 	snd_timer_t *timer = gus->gf1.timer2;
117*1da177e4SLinus Torvalds 
118*1da177e4SLinus Torvalds 	if (timer == NULL)
119*1da177e4SLinus Torvalds 		return;
120*1da177e4SLinus Torvalds 	snd_timer_interrupt(timer, timer->sticks);
121*1da177e4SLinus Torvalds }
122*1da177e4SLinus Torvalds 
123*1da177e4SLinus Torvalds /*
124*1da177e4SLinus Torvalds 
125*1da177e4SLinus Torvalds  */
126*1da177e4SLinus Torvalds 
127*1da177e4SLinus Torvalds static struct _snd_timer_hardware snd_gf1_timer1 =
128*1da177e4SLinus Torvalds {
129*1da177e4SLinus Torvalds 	.flags =	SNDRV_TIMER_HW_STOP,
130*1da177e4SLinus Torvalds 	.resolution =	80000,
131*1da177e4SLinus Torvalds 	.ticks =	256,
132*1da177e4SLinus Torvalds 	.start =	snd_gf1_timer1_start,
133*1da177e4SLinus Torvalds 	.stop =		snd_gf1_timer1_stop,
134*1da177e4SLinus Torvalds };
135*1da177e4SLinus Torvalds 
136*1da177e4SLinus Torvalds static struct _snd_timer_hardware snd_gf1_timer2 =
137*1da177e4SLinus Torvalds {
138*1da177e4SLinus Torvalds 	.flags =	SNDRV_TIMER_HW_STOP,
139*1da177e4SLinus Torvalds 	.resolution =	320000,
140*1da177e4SLinus Torvalds 	.ticks =	256,
141*1da177e4SLinus Torvalds 	.start =	snd_gf1_timer2_start,
142*1da177e4SLinus Torvalds 	.stop =		snd_gf1_timer2_stop,
143*1da177e4SLinus Torvalds };
144*1da177e4SLinus Torvalds 
145*1da177e4SLinus Torvalds static void snd_gf1_timer1_free(snd_timer_t *timer)
146*1da177e4SLinus Torvalds {
147*1da177e4SLinus Torvalds 	snd_gus_card_t *gus = timer->private_data;
148*1da177e4SLinus Torvalds 	gus->gf1.timer1 = NULL;
149*1da177e4SLinus Torvalds }
150*1da177e4SLinus Torvalds 
151*1da177e4SLinus Torvalds static void snd_gf1_timer2_free(snd_timer_t *timer)
152*1da177e4SLinus Torvalds {
153*1da177e4SLinus Torvalds 	snd_gus_card_t *gus = timer->private_data;
154*1da177e4SLinus Torvalds 	gus->gf1.timer2 = NULL;
155*1da177e4SLinus Torvalds }
156*1da177e4SLinus Torvalds 
157*1da177e4SLinus Torvalds void snd_gf1_timers_init(snd_gus_card_t * gus)
158*1da177e4SLinus Torvalds {
159*1da177e4SLinus Torvalds 	snd_timer_t *timer;
160*1da177e4SLinus Torvalds 	snd_timer_id_t tid;
161*1da177e4SLinus Torvalds 
162*1da177e4SLinus Torvalds 	if (gus->gf1.timer1 != NULL || gus->gf1.timer2 != NULL)
163*1da177e4SLinus Torvalds 		return;
164*1da177e4SLinus Torvalds 
165*1da177e4SLinus Torvalds 	gus->gf1.interrupt_handler_timer1 = snd_gf1_interrupt_timer1;
166*1da177e4SLinus Torvalds 	gus->gf1.interrupt_handler_timer2 = snd_gf1_interrupt_timer2;
167*1da177e4SLinus Torvalds 
168*1da177e4SLinus Torvalds 	tid.dev_class = SNDRV_TIMER_CLASS_CARD;
169*1da177e4SLinus Torvalds 	tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
170*1da177e4SLinus Torvalds 	tid.card = gus->card->number;
171*1da177e4SLinus Torvalds 	tid.device = gus->timer_dev;
172*1da177e4SLinus Torvalds 	tid.subdevice = 0;
173*1da177e4SLinus Torvalds 
174*1da177e4SLinus Torvalds 	if (snd_timer_new(gus->card, "GF1 timer", &tid, &timer) >= 0) {
175*1da177e4SLinus Torvalds 		strcpy(timer->name, "GF1 timer #1");
176*1da177e4SLinus Torvalds 		timer->private_data = gus;
177*1da177e4SLinus Torvalds 		timer->private_free = snd_gf1_timer1_free;
178*1da177e4SLinus Torvalds 		timer->hw = snd_gf1_timer1;
179*1da177e4SLinus Torvalds 	}
180*1da177e4SLinus Torvalds 	gus->gf1.timer1 = timer;
181*1da177e4SLinus Torvalds 
182*1da177e4SLinus Torvalds 	tid.device++;
183*1da177e4SLinus Torvalds 
184*1da177e4SLinus Torvalds 	if (snd_timer_new(gus->card, "GF1 timer", &tid, &timer) >= 0) {
185*1da177e4SLinus Torvalds 		strcpy(timer->name, "GF1 timer #2");
186*1da177e4SLinus Torvalds 		timer->private_data = gus;
187*1da177e4SLinus Torvalds 		timer->private_free = snd_gf1_timer2_free;
188*1da177e4SLinus Torvalds 		timer->hw = snd_gf1_timer2;
189*1da177e4SLinus Torvalds 	}
190*1da177e4SLinus Torvalds 	gus->gf1.timer2 = timer;
191*1da177e4SLinus Torvalds }
192*1da177e4SLinus Torvalds 
193*1da177e4SLinus Torvalds void snd_gf1_timers_done(snd_gus_card_t * gus)
194*1da177e4SLinus Torvalds {
195*1da177e4SLinus Torvalds 	snd_gf1_set_default_handlers(gus, SNDRV_GF1_HANDLER_TIMER1 | SNDRV_GF1_HANDLER_TIMER2);
196*1da177e4SLinus Torvalds 	if (gus->gf1.timer1) {
197*1da177e4SLinus Torvalds 		snd_device_free(gus->card, gus->gf1.timer1);
198*1da177e4SLinus Torvalds 		gus->gf1.timer1 = NULL;
199*1da177e4SLinus Torvalds 	}
200*1da177e4SLinus Torvalds 	if (gus->gf1.timer2) {
201*1da177e4SLinus Torvalds 		snd_device_free(gus->card, gus->gf1.timer2);
202*1da177e4SLinus Torvalds 		gus->gf1.timer2 = NULL;
203*1da177e4SLinus Torvalds 	}
204*1da177e4SLinus Torvalds }
205