18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Copyright (c) by Lee Revell <rlrevell@joe-job.com>
48c2ecf20Sopenharmony_ci *                   Clemens Ladisch <clemens@ladisch.de>
58c2ecf20Sopenharmony_ci *  Routines for control of EMU10K1 chips
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *  BUGS:
88c2ecf20Sopenharmony_ci *    --
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci *  TODO:
118c2ecf20Sopenharmony_ci *    --
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/time.h>
158c2ecf20Sopenharmony_ci#include <sound/core.h>
168c2ecf20Sopenharmony_ci#include <sound/emu10k1.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistatic int snd_emu10k1_timer_start(struct snd_timer *timer)
198c2ecf20Sopenharmony_ci{
208c2ecf20Sopenharmony_ci	struct snd_emu10k1 *emu;
218c2ecf20Sopenharmony_ci	unsigned long flags;
228c2ecf20Sopenharmony_ci	unsigned int delay;
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci	emu = snd_timer_chip(timer);
258c2ecf20Sopenharmony_ci	delay = timer->sticks - 1;
268c2ecf20Sopenharmony_ci	if (delay < 5 ) /* minimum time is 5 ticks */
278c2ecf20Sopenharmony_ci		delay = 5;
288c2ecf20Sopenharmony_ci	spin_lock_irqsave(&emu->reg_lock, flags);
298c2ecf20Sopenharmony_ci	snd_emu10k1_intr_enable(emu, INTE_INTERVALTIMERENB);
308c2ecf20Sopenharmony_ci	outw(delay & TIMER_RATE_MASK, emu->port + TIMER);
318c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&emu->reg_lock, flags);
328c2ecf20Sopenharmony_ci	return 0;
338c2ecf20Sopenharmony_ci}
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistatic int snd_emu10k1_timer_stop(struct snd_timer *timer)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	struct snd_emu10k1 *emu;
388c2ecf20Sopenharmony_ci	unsigned long flags;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	emu = snd_timer_chip(timer);
418c2ecf20Sopenharmony_ci	spin_lock_irqsave(&emu->reg_lock, flags);
428c2ecf20Sopenharmony_ci	snd_emu10k1_intr_disable(emu, INTE_INTERVALTIMERENB);
438c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&emu->reg_lock, flags);
448c2ecf20Sopenharmony_ci	return 0;
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic int snd_emu10k1_timer_precise_resolution(struct snd_timer *timer,
488c2ecf20Sopenharmony_ci					       unsigned long *num, unsigned long *den)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	*num = 1;
518c2ecf20Sopenharmony_ci	*den = 48000;
528c2ecf20Sopenharmony_ci	return 0;
538c2ecf20Sopenharmony_ci}
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistatic const struct snd_timer_hardware snd_emu10k1_timer_hw = {
568c2ecf20Sopenharmony_ci	.flags = SNDRV_TIMER_HW_AUTO,
578c2ecf20Sopenharmony_ci	.resolution = 20833, /* 1 sample @ 48KHZ = 20.833...us */
588c2ecf20Sopenharmony_ci	.ticks = 1024,
598c2ecf20Sopenharmony_ci	.start = snd_emu10k1_timer_start,
608c2ecf20Sopenharmony_ci	.stop = snd_emu10k1_timer_stop,
618c2ecf20Sopenharmony_ci	.precise_resolution = snd_emu10k1_timer_precise_resolution,
628c2ecf20Sopenharmony_ci};
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ciint snd_emu10k1_timer(struct snd_emu10k1 *emu, int device)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	struct snd_timer *timer = NULL;
678c2ecf20Sopenharmony_ci	struct snd_timer_id tid;
688c2ecf20Sopenharmony_ci	int err;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	tid.dev_class = SNDRV_TIMER_CLASS_CARD;
718c2ecf20Sopenharmony_ci	tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
728c2ecf20Sopenharmony_ci	tid.card = emu->card->number;
738c2ecf20Sopenharmony_ci	tid.device = device;
748c2ecf20Sopenharmony_ci	tid.subdevice = 0;
758c2ecf20Sopenharmony_ci	if ((err = snd_timer_new(emu->card, "EMU10K1", &tid, &timer)) >= 0) {
768c2ecf20Sopenharmony_ci		strcpy(timer->name, "EMU10K1 timer");
778c2ecf20Sopenharmony_ci		timer->private_data = emu;
788c2ecf20Sopenharmony_ci		timer->hw = snd_emu10k1_timer_hw;
798c2ecf20Sopenharmony_ci	}
808c2ecf20Sopenharmony_ci	emu->timer = timer;
818c2ecf20Sopenharmony_ci	return err;
828c2ecf20Sopenharmony_ci}
83