11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * Driver for Sound Core PDAudioCF soundcard
41da177e4SLinus Torvalds  *
5c1017a4cSJaroslav Kysela  * Copyright (c) 2003 by Jaroslav Kysela <perex@perex.cz>
61da177e4SLinus Torvalds  */
71da177e4SLinus Torvalds 
81da177e4SLinus Torvalds #include <sound/core.h>
91da177e4SLinus Torvalds #include "pdaudiocf.h"
101da177e4SLinus Torvalds #include <sound/initval.h>
1197432886SAl Viro #include <asm/irq_regs.h>
121da177e4SLinus Torvalds 
131da177e4SLinus Torvalds /*
141da177e4SLinus Torvalds  *
151da177e4SLinus Torvalds  */
pdacf_interrupt(int irq,void * dev)167d12e780SDavid Howells irqreturn_t pdacf_interrupt(int irq, void *dev)
171da177e4SLinus Torvalds {
18db131548STakashi Iwai 	struct snd_pdacf *chip = dev;
191da177e4SLinus Torvalds 	unsigned short stat;
203b73cfe5STakashi Iwai 	bool wake_thread = false;
211da177e4SLinus Torvalds 
221da177e4SLinus Torvalds 	if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|
231da177e4SLinus Torvalds 				  PDAUDIOCF_STAT_IS_CONFIGURED|
241da177e4SLinus Torvalds 				  PDAUDIOCF_STAT_IS_SUSPENDED)) != PDAUDIOCF_STAT_IS_CONFIGURED)
251da177e4SLinus Torvalds 		return IRQ_HANDLED;	/* IRQ_NONE here? */
261da177e4SLinus Torvalds 
271da177e4SLinus Torvalds 	stat = inw(chip->port + PDAUDIOCF_REG_ISR);
281da177e4SLinus Torvalds 	if (stat & (PDAUDIOCF_IRQLVL|PDAUDIOCF_IRQOVR)) {
291da177e4SLinus Torvalds 		if (stat & PDAUDIOCF_IRQOVR)	/* should never happen */
301da177e4SLinus Torvalds 			snd_printk(KERN_ERR "PDAUDIOCF SRAM buffer overrun detected!\n");
311da177e4SLinus Torvalds 		if (chip->pcm_substream)
323b73cfe5STakashi Iwai 			wake_thread = true;
331da177e4SLinus Torvalds 		if (!(stat & PDAUDIOCF_IRQAKM))
341da177e4SLinus Torvalds 			stat |= PDAUDIOCF_IRQAKM;	/* check rate */
351da177e4SLinus Torvalds 	}
367d12e780SDavid Howells 	if (get_irq_regs() != NULL)
371da177e4SLinus Torvalds 		snd_ak4117_check_rate_and_errors(chip->ak4117, 0);
383b73cfe5STakashi Iwai 	return wake_thread ? IRQ_WAKE_THREAD : IRQ_HANDLED;
391da177e4SLinus Torvalds }
401da177e4SLinus Torvalds 
pdacf_transfer_mono16(u16 * dst,u16 xor,unsigned int size,unsigned long rdp_port)411da177e4SLinus Torvalds static inline void pdacf_transfer_mono16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
421da177e4SLinus Torvalds {
431da177e4SLinus Torvalds 	while (size-- > 0) {
441da177e4SLinus Torvalds 		*dst++ = inw(rdp_port) ^ xor;
451da177e4SLinus Torvalds 		inw(rdp_port);
461da177e4SLinus Torvalds 	}
471da177e4SLinus Torvalds }
481da177e4SLinus Torvalds 
pdacf_transfer_mono32(u32 * dst,u32 xor,unsigned int size,unsigned long rdp_port)491da177e4SLinus Torvalds static inline void pdacf_transfer_mono32(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
501da177e4SLinus Torvalds {
511da177e4SLinus Torvalds 	register u16 val1, val2;
521da177e4SLinus Torvalds 
531da177e4SLinus Torvalds 	while (size-- > 0) {
541da177e4SLinus Torvalds 		val1 = inw(rdp_port);
551da177e4SLinus Torvalds 		val2 = inw(rdp_port);
561da177e4SLinus Torvalds 		inw(rdp_port);
571da177e4SLinus Torvalds 		*dst++ = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
581da177e4SLinus Torvalds 	}
591da177e4SLinus Torvalds }
601da177e4SLinus Torvalds 
pdacf_transfer_stereo16(u16 * dst,u16 xor,unsigned int size,unsigned long rdp_port)611da177e4SLinus Torvalds static inline void pdacf_transfer_stereo16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
621da177e4SLinus Torvalds {
631da177e4SLinus Torvalds 	while (size-- > 0) {
641da177e4SLinus Torvalds 		*dst++ = inw(rdp_port) ^ xor;
651da177e4SLinus Torvalds 		*dst++ = inw(rdp_port) ^ xor;
661da177e4SLinus Torvalds 	}
671da177e4SLinus Torvalds }
681da177e4SLinus Torvalds 
pdacf_transfer_stereo32(u32 * dst,u32 xor,unsigned int size,unsigned long rdp_port)691da177e4SLinus Torvalds static inline void pdacf_transfer_stereo32(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
701da177e4SLinus Torvalds {
711da177e4SLinus Torvalds 	register u16 val1, val2, val3;
721da177e4SLinus Torvalds 
731da177e4SLinus Torvalds 	while (size-- > 0) {
741da177e4SLinus Torvalds 		val1 = inw(rdp_port);
751da177e4SLinus Torvalds 		val2 = inw(rdp_port);
761da177e4SLinus Torvalds 		val3 = inw(rdp_port);
771da177e4SLinus Torvalds 		*dst++ = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
781da177e4SLinus Torvalds 		*dst++ = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;
791da177e4SLinus Torvalds 	}
801da177e4SLinus Torvalds }
811da177e4SLinus Torvalds 
pdacf_transfer_mono16sw(u16 * dst,u16 xor,unsigned int size,unsigned long rdp_port)821da177e4SLinus Torvalds static inline void pdacf_transfer_mono16sw(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
831da177e4SLinus Torvalds {
841da177e4SLinus Torvalds 	while (size-- > 0) {
851da177e4SLinus Torvalds 		*dst++ = swab16(inw(rdp_port) ^ xor);
861da177e4SLinus Torvalds 		inw(rdp_port);
871da177e4SLinus Torvalds 	}
881da177e4SLinus Torvalds }
891da177e4SLinus Torvalds 
pdacf_transfer_mono32sw(u32 * dst,u32 xor,unsigned int size,unsigned long rdp_port)901da177e4SLinus Torvalds static inline void pdacf_transfer_mono32sw(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
911da177e4SLinus Torvalds {
921da177e4SLinus Torvalds 	register u16 val1, val2;
931da177e4SLinus Torvalds 
941da177e4SLinus Torvalds 	while (size-- > 0) {
951da177e4SLinus Torvalds 		val1 = inw(rdp_port);
961da177e4SLinus Torvalds 		val2 = inw(rdp_port);
971da177e4SLinus Torvalds 		inw(rdp_port);
981da177e4SLinus Torvalds 		*dst++ = swab32((((val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor);
991da177e4SLinus Torvalds 	}
1001da177e4SLinus Torvalds }
1011da177e4SLinus Torvalds 
pdacf_transfer_stereo16sw(u16 * dst,u16 xor,unsigned int size,unsigned long rdp_port)1021da177e4SLinus Torvalds static inline void pdacf_transfer_stereo16sw(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
1031da177e4SLinus Torvalds {
1041da177e4SLinus Torvalds 	while (size-- > 0) {
1051da177e4SLinus Torvalds 		*dst++ = swab16(inw(rdp_port) ^ xor);
1061da177e4SLinus Torvalds 		*dst++ = swab16(inw(rdp_port) ^ xor);
1071da177e4SLinus Torvalds 	}
1081da177e4SLinus Torvalds }
1091da177e4SLinus Torvalds 
pdacf_transfer_stereo32sw(u32 * dst,u32 xor,unsigned int size,unsigned long rdp_port)1101da177e4SLinus Torvalds static inline void pdacf_transfer_stereo32sw(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
1111da177e4SLinus Torvalds {
1121da177e4SLinus Torvalds 	register u16 val1, val2, val3;
1131da177e4SLinus Torvalds 
1141da177e4SLinus Torvalds 	while (size-- > 0) {
1151da177e4SLinus Torvalds 		val1 = inw(rdp_port);
1161da177e4SLinus Torvalds 		val2 = inw(rdp_port);
1171da177e4SLinus Torvalds 		val3 = inw(rdp_port);
1181da177e4SLinus Torvalds 		*dst++ = swab32((((val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor);
1191da177e4SLinus Torvalds 		*dst++ = swab32((((u32)val3 << 16) | (val2 & 0xff00)) ^ xor);
1201da177e4SLinus Torvalds 	}
1211da177e4SLinus Torvalds }
1221da177e4SLinus Torvalds 
pdacf_transfer_mono24le(u8 * dst,u16 xor,unsigned int size,unsigned long rdp_port)1231da177e4SLinus Torvalds static inline void pdacf_transfer_mono24le(u8 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
1241da177e4SLinus Torvalds {
1251da177e4SLinus Torvalds 	register u16 val1, val2;
1261da177e4SLinus Torvalds 	register u32 xval1;
1271da177e4SLinus Torvalds 
1281da177e4SLinus Torvalds 	while (size-- > 0) {
1291da177e4SLinus Torvalds 		val1 = inw(rdp_port);
1301da177e4SLinus Torvalds 		val2 = inw(rdp_port);
1311da177e4SLinus Torvalds 		inw(rdp_port);
1321da177e4SLinus Torvalds 		xval1 = (((val2 & 0xff) << 8) | (val1 << 16)) ^ xor;
1331da177e4SLinus Torvalds 		*dst++ = (u8)(xval1 >> 8);
1341da177e4SLinus Torvalds 		*dst++ = (u8)(xval1 >> 16);
1351da177e4SLinus Torvalds 		*dst++ = (u8)(xval1 >> 24);
1361da177e4SLinus Torvalds 	}
1371da177e4SLinus Torvalds }
1381da177e4SLinus Torvalds 
pdacf_transfer_mono24be(u8 * dst,u16 xor,unsigned int size,unsigned long rdp_port)1391da177e4SLinus Torvalds static inline void pdacf_transfer_mono24be(u8 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
1401da177e4SLinus Torvalds {
1411da177e4SLinus Torvalds 	register u16 val1, val2;
1421da177e4SLinus Torvalds 	register u32 xval1;
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds 	while (size-- > 0) {
1451da177e4SLinus Torvalds 		val1 = inw(rdp_port);
1461da177e4SLinus Torvalds 		val2 = inw(rdp_port);
1471da177e4SLinus Torvalds 		inw(rdp_port);
1481da177e4SLinus Torvalds 		xval1 = (((val2 & 0xff) << 8) | (val1 << 16)) ^ xor;
1491da177e4SLinus Torvalds 		*dst++ = (u8)(xval1 >> 24);
1501da177e4SLinus Torvalds 		*dst++ = (u8)(xval1 >> 16);
1511da177e4SLinus Torvalds 		*dst++ = (u8)(xval1 >> 8);
1521da177e4SLinus Torvalds 	}
1531da177e4SLinus Torvalds }
1541da177e4SLinus Torvalds 
pdacf_transfer_stereo24le(u8 * dst,u32 xor,unsigned int size,unsigned long rdp_port)1551da177e4SLinus Torvalds static inline void pdacf_transfer_stereo24le(u8 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
1561da177e4SLinus Torvalds {
1571da177e4SLinus Torvalds 	register u16 val1, val2, val3;
1581da177e4SLinus Torvalds 	register u32 xval1, xval2;
1591da177e4SLinus Torvalds 
1601da177e4SLinus Torvalds 	while (size-- > 0) {
1611da177e4SLinus Torvalds 		val1 = inw(rdp_port);
1621da177e4SLinus Torvalds 		val2 = inw(rdp_port);
1631da177e4SLinus Torvalds 		val3 = inw(rdp_port);
1641da177e4SLinus Torvalds 		xval1 = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
1651da177e4SLinus Torvalds 		xval2 = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;
1661da177e4SLinus Torvalds 		*dst++ = (u8)(xval1 >> 8);
1671da177e4SLinus Torvalds 		*dst++ = (u8)(xval1 >> 16);
1681da177e4SLinus Torvalds 		*dst++ = (u8)(xval1 >> 24);
1691da177e4SLinus Torvalds 		*dst++ = (u8)(xval2 >> 8);
1701da177e4SLinus Torvalds 		*dst++ = (u8)(xval2 >> 16);
1711da177e4SLinus Torvalds 		*dst++ = (u8)(xval2 >> 24);
1721da177e4SLinus Torvalds 	}
1731da177e4SLinus Torvalds }
1741da177e4SLinus Torvalds 
pdacf_transfer_stereo24be(u8 * dst,u32 xor,unsigned int size,unsigned long rdp_port)1751da177e4SLinus Torvalds static inline void pdacf_transfer_stereo24be(u8 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
1761da177e4SLinus Torvalds {
1771da177e4SLinus Torvalds 	register u16 val1, val2, val3;
1781da177e4SLinus Torvalds 	register u32 xval1, xval2;
1791da177e4SLinus Torvalds 
1801da177e4SLinus Torvalds 	while (size-- > 0) {
1811da177e4SLinus Torvalds 		val1 = inw(rdp_port);
1821da177e4SLinus Torvalds 		val2 = inw(rdp_port);
1831da177e4SLinus Torvalds 		val3 = inw(rdp_port);
1841da177e4SLinus Torvalds 		xval1 = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
1851da177e4SLinus Torvalds 		xval2 = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;
1861da177e4SLinus Torvalds 		*dst++ = (u8)(xval1 >> 24);
1871da177e4SLinus Torvalds 		*dst++ = (u8)(xval1 >> 16);
1881da177e4SLinus Torvalds 		*dst++ = (u8)(xval1 >> 8);
1891da177e4SLinus Torvalds 		*dst++ = (u8)(xval2 >> 24);
1901da177e4SLinus Torvalds 		*dst++ = (u8)(xval2 >> 16);
1911da177e4SLinus Torvalds 		*dst++ = (u8)(xval2 >> 8);
1921da177e4SLinus Torvalds 	}
1931da177e4SLinus Torvalds }
1941da177e4SLinus Torvalds 
pdacf_transfer(struct snd_pdacf * chip,unsigned int size,unsigned int off)195db131548STakashi Iwai static void pdacf_transfer(struct snd_pdacf *chip, unsigned int size, unsigned int off)
1961da177e4SLinus Torvalds {
1971da177e4SLinus Torvalds 	unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;
1981da177e4SLinus Torvalds 	unsigned int xor = chip->pcm_xor;
1991da177e4SLinus Torvalds 
2001da177e4SLinus Torvalds 	if (chip->pcm_sample == 3) {
2011da177e4SLinus Torvalds 		if (chip->pcm_little) {
2021da177e4SLinus Torvalds 			if (chip->pcm_channels == 1) {
2031da177e4SLinus Torvalds 				pdacf_transfer_mono24le((char *)chip->pcm_area + (off * 3), xor, size, rdp_port);
2041da177e4SLinus Torvalds 			} else {
2051da177e4SLinus Torvalds 				pdacf_transfer_stereo24le((char *)chip->pcm_area + (off * 6), xor, size, rdp_port);
2061da177e4SLinus Torvalds 			}
2071da177e4SLinus Torvalds 		} else {
2081da177e4SLinus Torvalds 			if (chip->pcm_channels == 1) {
2091da177e4SLinus Torvalds 				pdacf_transfer_mono24be((char *)chip->pcm_area + (off * 3), xor, size, rdp_port);
2101da177e4SLinus Torvalds 			} else {
2111da177e4SLinus Torvalds 				pdacf_transfer_stereo24be((char *)chip->pcm_area + (off * 6), xor, size, rdp_port);
2121da177e4SLinus Torvalds 			}
2131da177e4SLinus Torvalds 		}
2141da177e4SLinus Torvalds 		return;
2151da177e4SLinus Torvalds 	}
2161da177e4SLinus Torvalds 	if (chip->pcm_swab == 0) {
2171da177e4SLinus Torvalds 		if (chip->pcm_channels == 1) {
2181da177e4SLinus Torvalds 			if (chip->pcm_frame == 2) {
2191da177e4SLinus Torvalds 				pdacf_transfer_mono16((u16 *)chip->pcm_area + off, xor, size, rdp_port);
2201da177e4SLinus Torvalds 			} else {
2211da177e4SLinus Torvalds 				pdacf_transfer_mono32((u32 *)chip->pcm_area + off, xor, size, rdp_port);
2221da177e4SLinus Torvalds 			}
2231da177e4SLinus Torvalds 		} else {
2241da177e4SLinus Torvalds 			if (chip->pcm_frame == 2) {
2251da177e4SLinus Torvalds 				pdacf_transfer_stereo16((u16 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
2261da177e4SLinus Torvalds 			} else {
2271da177e4SLinus Torvalds 				pdacf_transfer_stereo32((u32 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
2281da177e4SLinus Torvalds 			}
2291da177e4SLinus Torvalds 		}
2301da177e4SLinus Torvalds 	} else {
2311da177e4SLinus Torvalds 		if (chip->pcm_channels == 1) {
2321da177e4SLinus Torvalds 			if (chip->pcm_frame == 2) {
2331da177e4SLinus Torvalds 				pdacf_transfer_mono16sw((u16 *)chip->pcm_area + off, xor, size, rdp_port);
2341da177e4SLinus Torvalds 			} else {
2351da177e4SLinus Torvalds 				pdacf_transfer_mono32sw((u32 *)chip->pcm_area + off, xor, size, rdp_port);
2361da177e4SLinus Torvalds 			}
2371da177e4SLinus Torvalds 		} else {
2381da177e4SLinus Torvalds 			if (chip->pcm_frame == 2) {
2391da177e4SLinus Torvalds 				pdacf_transfer_stereo16sw((u16 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
2401da177e4SLinus Torvalds 			} else {
2411da177e4SLinus Torvalds 				pdacf_transfer_stereo32sw((u32 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
2421da177e4SLinus Torvalds 			}
2431da177e4SLinus Torvalds 		}
2441da177e4SLinus Torvalds 	}
2451da177e4SLinus Torvalds }
2461da177e4SLinus Torvalds 
pdacf_threaded_irq(int irq,void * dev)2473b73cfe5STakashi Iwai irqreturn_t pdacf_threaded_irq(int irq, void *dev)
2481da177e4SLinus Torvalds {
2493b73cfe5STakashi Iwai 	struct snd_pdacf *chip = dev;
2501da177e4SLinus Torvalds 	int size, off, cont, rdp, wdp;
2511da177e4SLinus Torvalds 
2521da177e4SLinus Torvalds 	if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|PDAUDIOCF_STAT_IS_CONFIGURED)) != PDAUDIOCF_STAT_IS_CONFIGURED)
2533b73cfe5STakashi Iwai 		return IRQ_HANDLED;
2541da177e4SLinus Torvalds 
2551da177e4SLinus Torvalds 	if (chip->pcm_substream == NULL || chip->pcm_substream->runtime == NULL || !snd_pcm_running(chip->pcm_substream))
2563b73cfe5STakashi Iwai 		return IRQ_HANDLED;
2571da177e4SLinus Torvalds 
2581da177e4SLinus Torvalds 	rdp = inw(chip->port + PDAUDIOCF_REG_RDP);
2591da177e4SLinus Torvalds 	wdp = inw(chip->port + PDAUDIOCF_REG_WDP);
2602ebfb8eeSTakashi Iwai 	/* printk(KERN_DEBUG "TASKLET: rdp = %x, wdp = %x\n", rdp, wdp); */
2611da177e4SLinus Torvalds 	size = wdp - rdp;
2621da177e4SLinus Torvalds 	if (size < 0)
2631da177e4SLinus Torvalds 		size += 0x10000;
2641da177e4SLinus Torvalds 	if (size == 0)
2651da177e4SLinus Torvalds 		size = 0x10000;
2661da177e4SLinus Torvalds 	size /= chip->pcm_frame;
2671da177e4SLinus Torvalds 	if (size > 64)
2681da177e4SLinus Torvalds 		size -= 32;
2691da177e4SLinus Torvalds 
2701da177e4SLinus Torvalds #if 0
2711da177e4SLinus Torvalds 	chip->pcm_hwptr += size;
2721da177e4SLinus Torvalds 	chip->pcm_hwptr %= chip->pcm_size;
2731da177e4SLinus Torvalds 	chip->pcm_tdone += size;
2741da177e4SLinus Torvalds 	if (chip->pcm_frame == 2) {
2751da177e4SLinus Torvalds 		unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;
2761da177e4SLinus Torvalds 		while (size-- > 0) {
2771da177e4SLinus Torvalds 			inw(rdp_port);
2781da177e4SLinus Torvalds 			inw(rdp_port);
2791da177e4SLinus Torvalds 		}
2801da177e4SLinus Torvalds 	} else {
2811da177e4SLinus Torvalds 		unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;
2821da177e4SLinus Torvalds 		while (size-- > 0) {
2831da177e4SLinus Torvalds 			inw(rdp_port);
2841da177e4SLinus Torvalds 			inw(rdp_port);
2851da177e4SLinus Torvalds 			inw(rdp_port);
2861da177e4SLinus Torvalds 		}
2871da177e4SLinus Torvalds 	}
2881da177e4SLinus Torvalds #else
2891da177e4SLinus Torvalds 	off = chip->pcm_hwptr + chip->pcm_tdone;
2901da177e4SLinus Torvalds 	off %= chip->pcm_size;
2911da177e4SLinus Torvalds 	chip->pcm_tdone += size;
2921da177e4SLinus Torvalds 	while (size > 0) {
2931da177e4SLinus Torvalds 		cont = chip->pcm_size - off;
2941da177e4SLinus Torvalds 		if (cont > size)
2951da177e4SLinus Torvalds 			cont = size;
2961da177e4SLinus Torvalds 		pdacf_transfer(chip, cont, off);
2971da177e4SLinus Torvalds 		off += cont;
2981da177e4SLinus Torvalds 		off %= chip->pcm_size;
2991da177e4SLinus Torvalds 		size -= cont;
3001da177e4SLinus Torvalds 	}
3011da177e4SLinus Torvalds #endif
3023b73cfe5STakashi Iwai 	mutex_lock(&chip->reg_lock);
3031da177e4SLinus Torvalds 	while (chip->pcm_tdone >= chip->pcm_period) {
3041da177e4SLinus Torvalds 		chip->pcm_hwptr += chip->pcm_period;
3051da177e4SLinus Torvalds 		chip->pcm_hwptr %= chip->pcm_size;
3061da177e4SLinus Torvalds 		chip->pcm_tdone -= chip->pcm_period;
3073b73cfe5STakashi Iwai 		mutex_unlock(&chip->reg_lock);
3081da177e4SLinus Torvalds 		snd_pcm_period_elapsed(chip->pcm_substream);
3093b73cfe5STakashi Iwai 		mutex_lock(&chip->reg_lock);
3101da177e4SLinus Torvalds 	}
3113b73cfe5STakashi Iwai 	mutex_unlock(&chip->reg_lock);
3123b73cfe5STakashi Iwai 	return IRQ_HANDLED;
3131da177e4SLinus Torvalds }
314