Blame view

sound/core/rtctimer.c 4.13 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  /*
   *  RTC based high-frequency timer
   *
   *  Copyright (C) 2000 Takashi Iwai
   *	based on rtctimer.c by Steve Ratcliffe
   *
   *   This program is free software; you can redistribute it and/or modify
   *   it under the terms of the GNU General Public License as published by
   *   the Free Software Foundation; either version 2 of the License, or
   *   (at your option) any later version.
   *
   *   This program is distributed in the hope that it will be useful,
   *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *   GNU General Public License for more details.
   *
   *   You should have received a copy of the GNU General Public License
   *   along with this program; if not, write to the Free Software
   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   *
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
  #include <linux/init.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
  #include <linux/interrupt.h>
ec2cf68e0   Randy Dunlap   ALSA: rtctimer.c ...
24
  #include <linux/module.h>
62e96a1ca   vignesh babu   [ALSA] is_power_o...
25
  #include <linux/log2.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
27
  #include <sound/core.h>
  #include <sound/timer.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
30
31
32
33
34
35
36
37
38
  
  #if defined(CONFIG_RTC) || defined(CONFIG_RTC_MODULE)
  
  #include <linux/mc146818rtc.h>
  
  #define RTC_FREQ	1024		/* default frequency */
  #define NANO_SEC	1000000000L	/* 10^9 in sec */
  
  /*
   * prototypes
   */
53d2f744a   Takashi Iwai   [ALSA] Remove xxx...
39
40
41
42
  static int rtctimer_open(struct snd_timer *t);
  static int rtctimer_close(struct snd_timer *t);
  static int rtctimer_start(struct snd_timer *t);
  static int rtctimer_stop(struct snd_timer *t);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
45
46
47
  
  
  /*
   * The hardware dependent description for this timer.
   */
53d2f744a   Takashi Iwai   [ALSA] Remove xxx...
48
  static struct snd_timer_hardware rtc_hw = {
ac5d1a7d2   Clemens Ladisch   [ALSA] rtctimer: ...
49
50
51
  	.flags =	SNDRV_TIMER_HW_AUTO |
  			SNDRV_TIMER_HW_FIRST |
  			SNDRV_TIMER_HW_TASKLET,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
54
55
56
57
58
59
  	.ticks =	100000000L,		/* FIXME: XXX */
  	.open =		rtctimer_open,
  	.close =	rtctimer_close,
  	.start =	rtctimer_start,
  	.stop =		rtctimer_stop,
  };
  
  static int rtctimer_freq = RTC_FREQ;		/* frequency */
53d2f744a   Takashi Iwai   [ALSA] Remove xxx...
60
  static struct snd_timer *rtctimer;
ac5d1a7d2   Clemens Ladisch   [ALSA] rtctimer: ...
61
  static struct tasklet_struct rtc_tasklet;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
64
65
  static rtc_task_t rtc_task;
  
  
  static int
53d2f744a   Takashi Iwai   [ALSA] Remove xxx...
66
  rtctimer_open(struct snd_timer *t)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
69
70
71
72
73
74
75
76
77
  {
  	int err;
  
  	err = rtc_register(&rtc_task);
  	if (err < 0)
  		return err;
  	t->private_data = &rtc_task;
  	return 0;
  }
  
  static int
53d2f744a   Takashi Iwai   [ALSA] Remove xxx...
78
  rtctimer_close(struct snd_timer *t)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
80
81
82
  {
  	rtc_task_t *rtc = t->private_data;
  	if (rtc) {
  		rtc_unregister(rtc);
ac5d1a7d2   Clemens Ladisch   [ALSA] rtctimer: ...
83
  		tasklet_kill(&rtc_tasklet);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
85
86
87
88
89
  		t->private_data = NULL;
  	}
  	return 0;
  }
  
  static int
53d2f744a   Takashi Iwai   [ALSA] Remove xxx...
90
  rtctimer_start(struct snd_timer *timer)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
92
  {
  	rtc_task_t *rtc = timer->private_data;
7eaa943c8   Takashi Iwai   ALSA: Kill snd_as...
93
94
  	if (snd_BUG_ON(!rtc))
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
96
  	rtc_control(rtc, RTC_IRQP_SET, rtctimer_freq);
  	rtc_control(rtc, RTC_PIE_ON, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
98
99
100
  	return 0;
  }
  
  static int
53d2f744a   Takashi Iwai   [ALSA] Remove xxx...
101
  rtctimer_stop(struct snd_timer *timer)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
103
  {
  	rtc_task_t *rtc = timer->private_data;
7eaa943c8   Takashi Iwai   ALSA: Kill snd_as...
104
105
  	if (snd_BUG_ON(!rtc))
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
107
108
  	rtc_control(rtc, RTC_PIE_OFF, 0);
  	return 0;
  }
ac5d1a7d2   Clemens Ladisch   [ALSA] rtctimer: ...
109
110
111
112
  static void rtctimer_tasklet(unsigned long data)
  {
  	snd_timer_interrupt((struct snd_timer *)data, 1);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
114
115
116
117
  /*
   * interrupt
   */
  static void rtctimer_interrupt(void *private_data)
  {
1f04128a3   Takashi Iwai   ALSA: hda - Conve...
118
  	tasklet_schedule(private_data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
120
121
122
123
124
125
126
  }
  
  
  /*
   *  ENTRY functions
   */
  static int __init rtctimer_init(void)
  {
d9ad1bdd6   Clemens Ladisch   [ALSA] rtctimer: ...
127
  	int err;
53d2f744a   Takashi Iwai   [ALSA] Remove xxx...
128
  	struct snd_timer *timer;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129

d9ad1bdd6   Clemens Ladisch   [ALSA] rtctimer: ...
130
  	if (rtctimer_freq < 2 || rtctimer_freq > 8192 ||
62e96a1ca   vignesh babu   [ALSA] is_power_o...
131
  	    !is_power_of_2(rtctimer_freq)) {
de24214d0   Clemens Ladisch   [ALSA] timers: ad...
132
133
134
  		snd_printk(KERN_ERR "rtctimer: invalid frequency %d
  ",
  			   rtctimer_freq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135
136
137
138
139
140
141
  		return -EINVAL;
  	}
  
  	/* Create a new timer and set up the fields */
  	err = snd_timer_global_new("rtc", SNDRV_TIMER_GLOBAL_RTC, &timer);
  	if (err < 0)
  		return err;
de24214d0   Clemens Ladisch   [ALSA] timers: ad...
142
  	timer->module = THIS_MODULE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
144
145
  	strcpy(timer->name, "RTC timer");
  	timer->hw = rtc_hw;
  	timer->hw.resolution = NANO_SEC / rtctimer_freq;
ac5d1a7d2   Clemens Ladisch   [ALSA] rtctimer: ...
146
  	tasklet_init(&rtc_tasklet, rtctimer_tasklet, (unsigned long)timer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
148
  	/* set up RTC callback */
  	rtc_task.func = rtctimer_interrupt;
ac5d1a7d2   Clemens Ladisch   [ALSA] rtctimer: ...
149
  	rtc_task.private_data = &rtc_tasklet;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
151
152
153
154
155
156
157
158
159
160
161
162
163
  
  	err = snd_timer_global_register(timer);
  	if (err < 0) {
  		snd_timer_global_free(timer);
  		return err;
  	}
  	rtctimer = timer; /* remember this */
  
  	return 0;
  }
  
  static void __exit rtctimer_exit(void)
  {
  	if (rtctimer) {
c461482c8   Takashi Iwai   [ALSA] Unregister...
164
  		snd_timer_global_free(rtctimer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
  		rtctimer = NULL;
  	}
  }
  
  
  /*
   * exported stuff
   */
  module_init(rtctimer_init)
  module_exit(rtctimer_exit)
  
  module_param(rtctimer_freq, int, 0444);
  MODULE_PARM_DESC(rtctimer_freq, "timer frequency in Hz");
  
  MODULE_LICENSE("GPL");
  
  MODULE_ALIAS("snd-timer-" __stringify(SNDRV_TIMER_GLOBAL_RTC));
  
  #endif /* CONFIG_RTC || CONFIG_RTC_MODULE */