From patchwork Thu May 14 11:25:57 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Magnus Damm X-Patchwork-Id: 23742 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n4EBTFYi018114 for ; Thu, 14 May 2009 11:29:15 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754773AbZENL2y (ORCPT ); Thu, 14 May 2009 07:28:54 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1753761AbZENL2y (ORCPT ); Thu, 14 May 2009 07:28:54 -0400 Received: from wa-out-1112.google.com ([209.85.146.180]:22915 "EHLO wa-out-1112.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754773AbZENL2w (ORCPT ); Thu, 14 May 2009 07:28:52 -0400 Received: by wa-out-1112.google.com with SMTP id j5so472417wah.21 for ; Thu, 14 May 2009 04:28:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:from:to:cc:date:message-id :subject; bh=Gfhe9dii3R9Pa9+M0+DNEvvVeVFKdEW6lvMTnAUci6c=; b=Nv1hWCpc8CEFVx4Cbsa4vRDpoWQbOnjtYRO+5WKZnMrmp7pjGQbu+cXGCfW5rLwit3 ItnWw132FQ7tKFVC73tRSIfa/KLKlX5pqXThDEj6bbXRaXtoBbi+oAiDYp+JiWnoJnpL PnEbWCp8VzxdigC46HCxH9IbhkLoaMazqYT1Y= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:cc:date:message-id:subject; b=R/PxsCFxBB72RWoH/Flz4xm48HBrBzHOIhyTiVTpVD8Z+4WKpxCkM5q2CX2ppaxzS9 ecvMpV+EkfmUEy7F+8yiIsYx/Dn1S8ghyD0zLvg2ClRDMAyO8aiawBI/n/wu2YlFYDXa HOz/0X6lqtuA1EC+vptSycL6ILngyGk9HFFG8= Received: by 10.114.200.2 with SMTP id x2mr1875295waf.187.1242300533553; Thu, 14 May 2009 04:28:53 -0700 (PDT) Received: from rx1.opensource.se (210.5.32.202.bf.2iij.net [202.32.5.210]) by mx.google.com with ESMTPS id n22sm2808973pof.8.2009.05.14.04.28.46 (version=TLSv1/SSLv3 cipher=RC4-MD5); Thu, 14 May 2009 04:28:50 -0700 (PDT) From: Magnus Damm To: linux-sh@vger.kernel.org Cc: Magnus Damm , lethal@linux-sh.org Date: Thu, 14 May 2009 20:25:57 +0900 Message-Id: <20090514112557.27985.47363.sendpatchset@rx1.opensource.se> Subject: [PATCH] sh: sh_dac_audio fixes Sender: linux-sh-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-sh@vger.kernel.org From: Magnus Damm This patch modifies sh_dac_audio in the following ways: - use high resolution timer instead of TMU1 - fix cpu/dac.h include - add CONFIG_SH_HP6XX ifdefs - add future rewrite comment Signed-off-by: Magnus Damm --- sound/oss/Kconfig | 2 - sound/oss/sh_dac_audio.c | 81 +++++++++++++++++----------------------------- 2 files changed, 32 insertions(+), 51 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-sh" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html --- 0001/sound/oss/Kconfig +++ work/sound/oss/Kconfig 2009-05-14 19:14:45.000000000 +0900 @@ -561,7 +561,7 @@ endif # SOUND_OSS config SOUND_SH_DAC_AUDIO tristate "SuperH DAC audio support" - depends on CPU_SH3 + depends on CPU_SH3 && HIGH_RES_TIMERS config SOUND_SH_DAC_AUDIO_CHANNEL int "DAC channel" --- 0001/sound/oss/sh_dac_audio.c +++ work/sound/oss/sh_dac_audio.c 2009-05-14 19:13:48.000000000 +0900 @@ -18,47 +18,36 @@ #include #include #include +#include #include #include #include #include #include -#include -#include +#include #include #include #include #define MODNAME "sh_dac_audio" -#define TMU_TOCR_INIT 0x00 - -#define TMU1_TCR_INIT 0x0020 /* Clock/4, rising edge; interrupt on */ -#define TMU1_TSTR_INIT 0x02 /* Bit to turn on TMU1 */ - #define BUFFER_SIZE 48000 static int rate; static int empty; static char *data_buffer, *buffer_begin, *buffer_end; static int in_use, device_major; +static struct hrtimer hrtimer; +static ktime_t wakeups_per_second; static void dac_audio_start_timer(void) { - u8 tstr; - - tstr = ctrl_inb(TMU_TSTR); - tstr |= TMU1_TSTR_INIT; - ctrl_outb(tstr, TMU_TSTR); + hrtimer_start(&hrtimer, wakeups_per_second, HRTIMER_MODE_REL); } static void dac_audio_stop_timer(void) { - u8 tstr; - - tstr = ctrl_inb(TMU_TSTR); - tstr &= ~TMU1_TSTR_INIT; - ctrl_outb(tstr, TMU_TSTR); + hrtimer_cancel(&hrtimer); } static void dac_audio_reset(void) @@ -76,39 +65,33 @@ static void dac_audio_sync(void) static void dac_audio_start(void) { +#ifdef CONFIG_SH_HP6XX if (mach_is_hp6xx()) { u16 v = inw(HD64461_GPADR); v &= ~HD64461_GPADR_SPEAKER; outw(v, HD64461_GPADR); } - +#endif sh_dac_enable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL); - ctrl_outw(TMU1_TCR_INIT, TMU1_TCR); } static void dac_audio_stop(void) { dac_audio_stop_timer(); +#ifdef CONFIG_SH_HP6XX if (mach_is_hp6xx()) { u16 v = inw(HD64461_GPADR); v |= HD64461_GPADR_SPEAKER; outw(v, HD64461_GPADR); } - +#endif sh_dac_output(0, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL); sh_dac_disable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL); } static void dac_audio_set_rate(void) { - unsigned long interval; - struct clk *clk; - - clk = clk_get(NULL, "module_clk"); - interval = (clk_get_rate(clk) / 4) / rate; - clk_put(clk); - ctrl_outl(interval, TMU1_TCOR); - ctrl_outl(interval, TMU1_TCNT); + wakeups_per_second = ktime_set(0, 1000000000 / rate); } static int dac_audio_ioctl(struct inode *inode, struct file *file, @@ -265,32 +248,26 @@ const struct file_operations dac_audio_f .release = dac_audio_release, }; -static irqreturn_t timer1_interrupt(int irq, void *dev) +static enum hrtimer_restart sh_dac_audio_timer(struct hrtimer *handle) { - unsigned long timer_status; - - timer_status = ctrl_inw(TMU1_TCR); - timer_status &= ~0x100; - ctrl_outw(timer_status, TMU1_TCR); - if (!empty) { sh_dac_output(*buffer_begin, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL); buffer_begin++; if (buffer_begin == data_buffer + BUFFER_SIZE) buffer_begin = data_buffer; - if (buffer_begin == buffer_end) { + if (buffer_begin == buffer_end) empty = 1; - dac_audio_stop_timer(); - } } - return IRQ_HANDLED; + + if (!empty) + hrtimer_start(&hrtimer, wakeups_per_second, HRTIMER_MODE_REL); + + return HRTIMER_NORESTART; } static int __init dac_audio_init(void) { - int retval; - if ((device_major = register_sound_dsp(&dac_audio_fops, -1)) < 0) { printk(KERN_ERR "Cannot register dsp device"); return device_major; @@ -306,21 +283,25 @@ static int __init dac_audio_init(void) rate = 8000; dac_audio_set_rate(); - retval = - request_irq(TIMER1_IRQ, timer1_interrupt, IRQF_DISABLED, MODNAME, 0); - if (retval < 0) { - printk(KERN_ERR "sh_dac_audio: IRQ %d request failed\n", - TIMER1_IRQ); - return retval; - } + /* Today: High Resolution Timer driven DAC playback. + * The timer callback gets called once per sample. Ouch. + * + * Future: A much better approach would be to use the + * SH7720 CMT+DMAC+DAC hardware combination like this: + * - Program sample rate using CMT0 or CMT1 + * - Program DMAC to use CMT for timing and output to DAC + * - Play sound using DMAC, let CPU sleep. + * - While at it, rewrite this driver to use ALSA. + */ + + hrtimer_init(&hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + hrtimer.function = sh_dac_audio_timer; return 0; } static void __exit dac_audio_exit(void) { - free_irq(TIMER1_IRQ, 0); - unregister_sound_dsp(device_major); kfree((void *)data_buffer); }