xref: /openbmc/linux/sound/arm/pxa2xx-ac97-lib.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
29c636342SDmitry Baryshkov /*
39c636342SDmitry Baryshkov  * Based on sound/arm/pxa2xx-ac97.c and sound/soc/pxa/pxa2xx-ac97.c
49c636342SDmitry Baryshkov  * which contain:
59c636342SDmitry Baryshkov  *
69c636342SDmitry Baryshkov  * Author:	Nicolas Pitre
79c636342SDmitry Baryshkov  * Created:	Dec 02, 2004
89c636342SDmitry Baryshkov  * Copyright:	MontaVista Software Inc.
99c636342SDmitry Baryshkov  */
109c636342SDmitry Baryshkov 
119c636342SDmitry Baryshkov #include <linux/kernel.h>
129c636342SDmitry Baryshkov #include <linux/platform_device.h>
139c636342SDmitry Baryshkov #include <linux/interrupt.h>
149c636342SDmitry Baryshkov #include <linux/clk.h>
159c636342SDmitry Baryshkov #include <linux/delay.h>
16da155d5bSPaul Gortmaker #include <linux/module.h>
1723019a73SRob Herring #include <linux/io.h>
183b4bc7bcSMike Dunn #include <linux/gpio.h>
19a4519526SRobert Jarzmik #include <linux/of_gpio.h>
2008d3df8cSArnd Bergmann #include <linux/soc/pxa/cpu.h>
219c636342SDmitry Baryshkov 
229c636342SDmitry Baryshkov #include <sound/pxa2xx-lib.h>
239c636342SDmitry Baryshkov 
2422f08665SArnd Bergmann #include <linux/platform_data/asoc-pxa.h>
259c636342SDmitry Baryshkov 
268ff06452SArnd Bergmann #include "pxa2xx-ac97-regs.h"
278ff06452SArnd Bergmann 
289c636342SDmitry Baryshkov static DEFINE_MUTEX(car_mutex);
299c636342SDmitry Baryshkov static DECLARE_WAIT_QUEUE_HEAD(gsr_wq);
309c636342SDmitry Baryshkov static volatile long gsr_bits;
319c636342SDmitry Baryshkov static struct clk *ac97_clk;
329c636342SDmitry Baryshkov static struct clk *ac97conf_clk;
3326ade896SRobert Jarzmik static int reset_gpio;
348ff06452SArnd Bergmann static void __iomem *ac97_reg_base;
359c636342SDmitry Baryshkov 
369c636342SDmitry Baryshkov /*
379c636342SDmitry Baryshkov  * Beware PXA27x bugs:
389c636342SDmitry Baryshkov  *
399c636342SDmitry Baryshkov  *   o Slot 12 read from modem space will hang controller.
409c636342SDmitry Baryshkov  *   o CDONE, SDONE interrupt fails after any slot 12 IO.
419c636342SDmitry Baryshkov  *
429c636342SDmitry Baryshkov  * We therefore have an hybrid approach for waiting on SDONE (interrupt or
439c636342SDmitry Baryshkov  * 1 jiffy timeout if interrupt never comes).
449c636342SDmitry Baryshkov  */
459c636342SDmitry Baryshkov 
pxa2xx_ac97_read(int slot,unsigned short reg)466f8acad6SRobert Jarzmik int pxa2xx_ac97_read(int slot, unsigned short reg)
479c636342SDmitry Baryshkov {
486f8acad6SRobert Jarzmik 	int val = -ENODEV;
498ff06452SArnd Bergmann 	u32 __iomem *reg_addr;
509c636342SDmitry Baryshkov 
516f8acad6SRobert Jarzmik 	if (slot > 0)
526f8acad6SRobert Jarzmik 		return -ENODEV;
536f8acad6SRobert Jarzmik 
549c636342SDmitry Baryshkov 	mutex_lock(&car_mutex);
559c636342SDmitry Baryshkov 
569c636342SDmitry Baryshkov 	/* set up primary or secondary codec space */
578825e8e8SMarc Zyngier 	if (cpu_is_pxa25x() && reg == AC97_GPIO_STATUS)
588ff06452SArnd Bergmann 		reg_addr = ac97_reg_base +
598ff06452SArnd Bergmann 			   (slot ? SMC_REG_BASE : PMC_REG_BASE);
609c636342SDmitry Baryshkov 	else
618ff06452SArnd Bergmann 		reg_addr = ac97_reg_base +
628ff06452SArnd Bergmann 			   (slot ? SAC_REG_BASE : PAC_REG_BASE);
639c636342SDmitry Baryshkov 	reg_addr += (reg >> 1);
649c636342SDmitry Baryshkov 
659c636342SDmitry Baryshkov 	/* start read access across the ac97 link */
668ff06452SArnd Bergmann 	writel(GSR_CDONE | GSR_SDONE, ac97_reg_base + GSR);
679c636342SDmitry Baryshkov 	gsr_bits = 0;
688ff06452SArnd Bergmann 	val = (readl(reg_addr) & 0xffff);
699c636342SDmitry Baryshkov 	if (reg == AC97_GPIO_STATUS)
709c636342SDmitry Baryshkov 		goto out;
718ff06452SArnd Bergmann 	if (wait_event_timeout(gsr_wq, (readl(ac97_reg_base + GSR) | gsr_bits) & GSR_SDONE, 1) <= 0 &&
728ff06452SArnd Bergmann 	    !((readl(ac97_reg_base + GSR) | gsr_bits) & GSR_SDONE)) {
739c636342SDmitry Baryshkov 		printk(KERN_ERR "%s: read error (ac97_reg=%d GSR=%#lx)\n",
748ff06452SArnd Bergmann 				__func__, reg, readl(ac97_reg_base + GSR) | gsr_bits);
756f8acad6SRobert Jarzmik 		val = -ETIMEDOUT;
769c636342SDmitry Baryshkov 		goto out;
779c636342SDmitry Baryshkov 	}
789c636342SDmitry Baryshkov 
799c636342SDmitry Baryshkov 	/* valid data now */
808ff06452SArnd Bergmann 	writel(GSR_CDONE | GSR_SDONE, ac97_reg_base + GSR);
819c636342SDmitry Baryshkov 	gsr_bits = 0;
828ff06452SArnd Bergmann 	val = (readl(reg_addr) & 0xffff);
839c636342SDmitry Baryshkov 	/* but we've just started another cycle... */
848ff06452SArnd Bergmann 	wait_event_timeout(gsr_wq, (readl(ac97_reg_base + GSR) | gsr_bits) & GSR_SDONE, 1);
859c636342SDmitry Baryshkov 
869c636342SDmitry Baryshkov out:	mutex_unlock(&car_mutex);
879c636342SDmitry Baryshkov 	return val;
889c636342SDmitry Baryshkov }
899c636342SDmitry Baryshkov EXPORT_SYMBOL_GPL(pxa2xx_ac97_read);
909c636342SDmitry Baryshkov 
pxa2xx_ac97_write(int slot,unsigned short reg,unsigned short val)916f8acad6SRobert Jarzmik int pxa2xx_ac97_write(int slot, unsigned short reg, unsigned short val)
929c636342SDmitry Baryshkov {
938ff06452SArnd Bergmann 	u32 __iomem *reg_addr;
946f8acad6SRobert Jarzmik 	int ret = 0;
959c636342SDmitry Baryshkov 
969c636342SDmitry Baryshkov 	mutex_lock(&car_mutex);
979c636342SDmitry Baryshkov 
989c636342SDmitry Baryshkov 	/* set up primary or secondary codec space */
998825e8e8SMarc Zyngier 	if (cpu_is_pxa25x() && reg == AC97_GPIO_STATUS)
1008ff06452SArnd Bergmann 		reg_addr = ac97_reg_base +
1018ff06452SArnd Bergmann 			   (slot ? SMC_REG_BASE : PMC_REG_BASE);
1029c636342SDmitry Baryshkov 	else
1038ff06452SArnd Bergmann 		reg_addr = ac97_reg_base +
1048ff06452SArnd Bergmann 			   (slot ? SAC_REG_BASE : PAC_REG_BASE);
1059c636342SDmitry Baryshkov 	reg_addr += (reg >> 1);
1069c636342SDmitry Baryshkov 
1078ff06452SArnd Bergmann 	writel(GSR_CDONE | GSR_SDONE, ac97_reg_base + GSR);
1089c636342SDmitry Baryshkov 	gsr_bits = 0;
1098ff06452SArnd Bergmann 	writel(val, reg_addr);
1108ff06452SArnd Bergmann 	if (wait_event_timeout(gsr_wq, (readl(ac97_reg_base + GSR) | gsr_bits) & GSR_CDONE, 1) <= 0 &&
1118ff06452SArnd Bergmann 	    !((readl(ac97_reg_base + GSR) | gsr_bits) & GSR_CDONE)) {
1129c636342SDmitry Baryshkov 		printk(KERN_ERR "%s: write error (ac97_reg=%d GSR=%#lx)\n",
1138ff06452SArnd Bergmann 				__func__, reg, readl(ac97_reg_base + GSR) | gsr_bits);
1146f8acad6SRobert Jarzmik 		ret = -EIO;
1156f8acad6SRobert Jarzmik 	}
1169c636342SDmitry Baryshkov 
1179c636342SDmitry Baryshkov 	mutex_unlock(&car_mutex);
1186f8acad6SRobert Jarzmik 	return ret;
1199c636342SDmitry Baryshkov }
1209c636342SDmitry Baryshkov EXPORT_SYMBOL_GPL(pxa2xx_ac97_write);
1219c636342SDmitry Baryshkov 
1229d1cf39bSDmitry Baryshkov #ifdef CONFIG_PXA25x
pxa_ac97_warm_pxa25x(void)1239d1cf39bSDmitry Baryshkov static inline void pxa_ac97_warm_pxa25x(void)
1249c636342SDmitry Baryshkov {
1259c636342SDmitry Baryshkov 	gsr_bits = 0;
1269c636342SDmitry Baryshkov 
1278ff06452SArnd Bergmann 	writel(readl(ac97_reg_base + GCR) | (GCR_WARM_RST), ac97_reg_base + GCR);
1289d1cf39bSDmitry Baryshkov }
1299d1cf39bSDmitry Baryshkov 
pxa_ac97_cold_pxa25x(void)1309d1cf39bSDmitry Baryshkov static inline void pxa_ac97_cold_pxa25x(void)
1319d1cf39bSDmitry Baryshkov {
1328ff06452SArnd Bergmann 	writel(readl(ac97_reg_base + GCR) & ( GCR_COLD_RST), ac97_reg_base + GCR);  /* clear everything but nCRST */
1338ff06452SArnd Bergmann 	writel(readl(ac97_reg_base + GCR) & (~GCR_COLD_RST), ac97_reg_base + GCR);  /* then assert nCRST */
1349d1cf39bSDmitry Baryshkov 
1359d1cf39bSDmitry Baryshkov 	gsr_bits = 0;
1369d1cf39bSDmitry Baryshkov 
1378ff06452SArnd Bergmann 	writel(GCR_COLD_RST, ac97_reg_base + GCR);
1389d1cf39bSDmitry Baryshkov }
1399d1cf39bSDmitry Baryshkov #endif
1409d1cf39bSDmitry Baryshkov 
1419c636342SDmitry Baryshkov #ifdef CONFIG_PXA27x
pxa_ac97_warm_pxa27x(void)1429d1cf39bSDmitry Baryshkov static inline void pxa_ac97_warm_pxa27x(void)
1439d1cf39bSDmitry Baryshkov {
1449d1cf39bSDmitry Baryshkov 	gsr_bits = 0;
1459d1cf39bSDmitry Baryshkov 
146fb1bf8cdSEric Miao 	/* warm reset broken on Bulverde, so manually keep AC97 reset high */
147053fe0f1SMike Dunn 	pxa27x_configure_ac97reset(reset_gpio, true);
1489c636342SDmitry Baryshkov 	udelay(10);
1498ff06452SArnd Bergmann 	writel(readl(ac97_reg_base + GCR) | (GCR_WARM_RST), ac97_reg_base + GCR);
150053fe0f1SMike Dunn 	pxa27x_configure_ac97reset(reset_gpio, false);
1519c636342SDmitry Baryshkov 	udelay(500);
1529d1cf39bSDmitry Baryshkov }
1539d1cf39bSDmitry Baryshkov 
pxa_ac97_cold_pxa27x(void)1549d1cf39bSDmitry Baryshkov static inline void pxa_ac97_cold_pxa27x(void)
1559d1cf39bSDmitry Baryshkov {
1568ff06452SArnd Bergmann 	writel(readl(ac97_reg_base + GCR) & ( GCR_COLD_RST), ac97_reg_base + GCR);  /* clear everything but nCRST */
1578ff06452SArnd Bergmann 	writel(readl(ac97_reg_base + GCR) & (~GCR_COLD_RST), ac97_reg_base + GCR);  /* then assert nCRST */
1589d1cf39bSDmitry Baryshkov 
1599d1cf39bSDmitry Baryshkov 	gsr_bits = 0;
1609d1cf39bSDmitry Baryshkov 
1619d1cf39bSDmitry Baryshkov 	/* PXA27x Developers Manual section 13.5.2.2.1 */
1624091d342SRobert Jarzmik 	clk_prepare_enable(ac97conf_clk);
1639d1cf39bSDmitry Baryshkov 	udelay(5);
1644091d342SRobert Jarzmik 	clk_disable_unprepare(ac97conf_clk);
1658ff06452SArnd Bergmann 	writel(GCR_COLD_RST | GCR_WARM_RST, ac97_reg_base + GCR);
1669d1cf39bSDmitry Baryshkov }
1679d1cf39bSDmitry Baryshkov #endif
1689d1cf39bSDmitry Baryshkov 
1699d1cf39bSDmitry Baryshkov #ifdef CONFIG_PXA3xx
pxa_ac97_warm_pxa3xx(void)1709d1cf39bSDmitry Baryshkov static inline void pxa_ac97_warm_pxa3xx(void)
1719d1cf39bSDmitry Baryshkov {
1729d1cf39bSDmitry Baryshkov 	gsr_bits = 0;
1739d1cf39bSDmitry Baryshkov 
1749c636342SDmitry Baryshkov 	/* Can't use interrupts */
1758ff06452SArnd Bergmann 	writel(readl(ac97_reg_base + GCR) | (GCR_WARM_RST), ac97_reg_base + GCR);
1769d1cf39bSDmitry Baryshkov }
1779d1cf39bSDmitry Baryshkov 
pxa_ac97_cold_pxa3xx(void)1789d1cf39bSDmitry Baryshkov static inline void pxa_ac97_cold_pxa3xx(void)
1799d1cf39bSDmitry Baryshkov {
1809d1cf39bSDmitry Baryshkov 	/* Hold CLKBPB for 100us */
1818ff06452SArnd Bergmann 	writel(0, ac97_reg_base + GCR);
1828ff06452SArnd Bergmann 	writel(GCR_CLKBPB, ac97_reg_base + GCR);
1839d1cf39bSDmitry Baryshkov 	udelay(100);
1848ff06452SArnd Bergmann 	writel(0, ac97_reg_base + GCR);
1859d1cf39bSDmitry Baryshkov 
1868ff06452SArnd Bergmann 	writel(readl(ac97_reg_base + GCR) & ( GCR_COLD_RST), ac97_reg_base + GCR);  /* clear everything but nCRST */
1878ff06452SArnd Bergmann 	writel(readl(ac97_reg_base + GCR) & (~GCR_COLD_RST), ac97_reg_base + GCR);  /* then assert nCRST */
1889d1cf39bSDmitry Baryshkov 
1899d1cf39bSDmitry Baryshkov 	gsr_bits = 0;
1909d1cf39bSDmitry Baryshkov 
1919d1cf39bSDmitry Baryshkov 	/* Can't use interrupts on PXA3xx */
1928ff06452SArnd Bergmann 	writel(readl(ac97_reg_base + GCR) & (~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN)), ac97_reg_base + GCR);
1939d1cf39bSDmitry Baryshkov 
1948ff06452SArnd Bergmann 	writel(GCR_WARM_RST | GCR_COLD_RST, ac97_reg_base + GCR);
1959d1cf39bSDmitry Baryshkov }
1969c636342SDmitry Baryshkov #endif
1979c636342SDmitry Baryshkov 
pxa2xx_ac97_try_warm_reset(void)1986f8acad6SRobert Jarzmik bool pxa2xx_ac97_try_warm_reset(void)
1999d1cf39bSDmitry Baryshkov {
200057de50cSLuotao Fu 	unsigned long gsr;
201beb02cddSDmitry Eremin-Solenikov 	unsigned int timeout = 100;
202057de50cSLuotao Fu 
2039d1cf39bSDmitry Baryshkov #ifdef CONFIG_PXA25x
2048825e8e8SMarc Zyngier 	if (cpu_is_pxa25x())
2059d1cf39bSDmitry Baryshkov 		pxa_ac97_warm_pxa25x();
2069d1cf39bSDmitry Baryshkov 	else
2079d1cf39bSDmitry Baryshkov #endif
2089d1cf39bSDmitry Baryshkov #ifdef CONFIG_PXA27x
2099d1cf39bSDmitry Baryshkov 	if (cpu_is_pxa27x())
2109d1cf39bSDmitry Baryshkov 		pxa_ac97_warm_pxa27x();
2119d1cf39bSDmitry Baryshkov 	else
2129d1cf39bSDmitry Baryshkov #endif
2139d1cf39bSDmitry Baryshkov #ifdef CONFIG_PXA3xx
2149d1cf39bSDmitry Baryshkov 	if (cpu_is_pxa3xx())
2159d1cf39bSDmitry Baryshkov 		pxa_ac97_warm_pxa3xx();
2169d1cf39bSDmitry Baryshkov 	else
2179d1cf39bSDmitry Baryshkov #endif
21888ec7ae8STakashi Iwai 		snd_BUG();
219beb02cddSDmitry Eremin-Solenikov 
2208ff06452SArnd Bergmann 	while (!((readl(ac97_reg_base + GSR) | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--)
221beb02cddSDmitry Eremin-Solenikov 		mdelay(1);
222beb02cddSDmitry Eremin-Solenikov 
2238ff06452SArnd Bergmann 	gsr = readl(ac97_reg_base + GSR) | gsr_bits;
224057de50cSLuotao Fu 	if (!(gsr & (GSR_PCR | GSR_SCR))) {
2259c636342SDmitry Baryshkov 		printk(KERN_INFO "%s: warm reset timeout (GSR=%#lx)\n",
226057de50cSLuotao Fu 				 __func__, gsr);
2279c636342SDmitry Baryshkov 
2289c636342SDmitry Baryshkov 		return false;
2299c636342SDmitry Baryshkov 	}
2309c636342SDmitry Baryshkov 
2319c636342SDmitry Baryshkov 	return true;
2329c636342SDmitry Baryshkov }
2339c636342SDmitry Baryshkov EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_warm_reset);
2349c636342SDmitry Baryshkov 
pxa2xx_ac97_try_cold_reset(void)2356f8acad6SRobert Jarzmik bool pxa2xx_ac97_try_cold_reset(void)
2369c636342SDmitry Baryshkov {
237057de50cSLuotao Fu 	unsigned long gsr;
238beb02cddSDmitry Eremin-Solenikov 	unsigned int timeout = 1000;
239057de50cSLuotao Fu 
2409d1cf39bSDmitry Baryshkov #ifdef CONFIG_PXA25x
2418825e8e8SMarc Zyngier 	if (cpu_is_pxa25x())
2429d1cf39bSDmitry Baryshkov 		pxa_ac97_cold_pxa25x();
2439d1cf39bSDmitry Baryshkov 	else
2449c636342SDmitry Baryshkov #endif
2459c636342SDmitry Baryshkov #ifdef CONFIG_PXA27x
2469d1cf39bSDmitry Baryshkov 	if (cpu_is_pxa27x())
2479d1cf39bSDmitry Baryshkov 		pxa_ac97_cold_pxa27x();
2489d1cf39bSDmitry Baryshkov 	else
2499c636342SDmitry Baryshkov #endif
2509d1cf39bSDmitry Baryshkov #ifdef CONFIG_PXA3xx
2519d1cf39bSDmitry Baryshkov 	if (cpu_is_pxa3xx())
2529d1cf39bSDmitry Baryshkov 		pxa_ac97_cold_pxa3xx();
2539d1cf39bSDmitry Baryshkov 	else
2549d1cf39bSDmitry Baryshkov #endif
25588ec7ae8STakashi Iwai 		snd_BUG();
2569c636342SDmitry Baryshkov 
2578ff06452SArnd Bergmann 	while (!((readl(ac97_reg_base + GSR) | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--)
258beb02cddSDmitry Eremin-Solenikov 		mdelay(1);
259beb02cddSDmitry Eremin-Solenikov 
2608ff06452SArnd Bergmann 	gsr = readl(ac97_reg_base + GSR) | gsr_bits;
261057de50cSLuotao Fu 	if (!(gsr & (GSR_PCR | GSR_SCR))) {
2629c636342SDmitry Baryshkov 		printk(KERN_INFO "%s: cold reset timeout (GSR=%#lx)\n",
263057de50cSLuotao Fu 				 __func__, gsr);
2649c636342SDmitry Baryshkov 
2659c636342SDmitry Baryshkov 		return false;
2669c636342SDmitry Baryshkov 	}
2679c636342SDmitry Baryshkov 
2689c636342SDmitry Baryshkov 	return true;
2699c636342SDmitry Baryshkov }
2709c636342SDmitry Baryshkov EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_cold_reset);
2719c636342SDmitry Baryshkov 
2729c636342SDmitry Baryshkov 
pxa2xx_ac97_finish_reset(void)2736f8acad6SRobert Jarzmik void pxa2xx_ac97_finish_reset(void)
2749c636342SDmitry Baryshkov {
2758ff06452SArnd Bergmann 	u32 gcr = readl(ac97_reg_base + GCR);
2768ff06452SArnd Bergmann 	gcr &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
2778ff06452SArnd Bergmann 	gcr |= GCR_SDONE_IE|GCR_CDONE_IE;
2788ff06452SArnd Bergmann 	writel(gcr, ac97_reg_base + GCR);
2799c636342SDmitry Baryshkov }
2809c636342SDmitry Baryshkov EXPORT_SYMBOL_GPL(pxa2xx_ac97_finish_reset);
2819c636342SDmitry Baryshkov 
pxa2xx_ac97_irq(int irq,void * dev_id)2829c636342SDmitry Baryshkov static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id)
2839c636342SDmitry Baryshkov {
2849c636342SDmitry Baryshkov 	long status;
2859c636342SDmitry Baryshkov 
2868ff06452SArnd Bergmann 	status = readl(ac97_reg_base + GSR);
2879c636342SDmitry Baryshkov 	if (status) {
2888ff06452SArnd Bergmann 		writel(status, ac97_reg_base + GSR);
2899c636342SDmitry Baryshkov 		gsr_bits |= status;
2909c636342SDmitry Baryshkov 		wake_up(&gsr_wq);
2919c636342SDmitry Baryshkov 
2929c636342SDmitry Baryshkov 		/* Although we don't use those we still need to clear them
2939c636342SDmitry Baryshkov 		   since they tend to spuriously trigger when MMC is used
2949c636342SDmitry Baryshkov 		   (hardware bug? go figure)... */
2959d1cf39bSDmitry Baryshkov 		if (cpu_is_pxa27x()) {
2968ff06452SArnd Bergmann 			writel(MISR_EOC, ac97_reg_base + MISR);
2978ff06452SArnd Bergmann 			writel(PISR_EOC, ac97_reg_base + PISR);
2988ff06452SArnd Bergmann 			writel(MCSR_EOC, ac97_reg_base + MCSR);
2999d1cf39bSDmitry Baryshkov 		}
3009c636342SDmitry Baryshkov 
3019c636342SDmitry Baryshkov 		return IRQ_HANDLED;
3029c636342SDmitry Baryshkov 	}
3039c636342SDmitry Baryshkov 
3049c636342SDmitry Baryshkov 	return IRQ_NONE;
3059c636342SDmitry Baryshkov }
3069c636342SDmitry Baryshkov 
3079c636342SDmitry Baryshkov #ifdef CONFIG_PM
pxa2xx_ac97_hw_suspend(void)3089c636342SDmitry Baryshkov int pxa2xx_ac97_hw_suspend(void)
3099c636342SDmitry Baryshkov {
3108ff06452SArnd Bergmann 	writel(readl(ac97_reg_base + GCR) | (GCR_ACLINK_OFF), ac97_reg_base + GCR);
3114091d342SRobert Jarzmik 	clk_disable_unprepare(ac97_clk);
3129c636342SDmitry Baryshkov 	return 0;
3139c636342SDmitry Baryshkov }
3149c636342SDmitry Baryshkov EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_suspend);
3159c636342SDmitry Baryshkov 
pxa2xx_ac97_hw_resume(void)3169c636342SDmitry Baryshkov int pxa2xx_ac97_hw_resume(void)
3179c636342SDmitry Baryshkov {
3184091d342SRobert Jarzmik 	clk_prepare_enable(ac97_clk);
3199c636342SDmitry Baryshkov 	return 0;
3209c636342SDmitry Baryshkov }
3219c636342SDmitry Baryshkov EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_resume);
3229c636342SDmitry Baryshkov #endif
3239c636342SDmitry Baryshkov 
pxa2xx_ac97_hw_probe(struct platform_device * dev)324e21596bbSBill Pemberton int pxa2xx_ac97_hw_probe(struct platform_device *dev)
3259c636342SDmitry Baryshkov {
3269c636342SDmitry Baryshkov 	int ret;
3272548e6c7SArnd Bergmann 	int irq;
328eae17754SMark Brown 	pxa2xx_audio_ops_t *pdata = dev->dev.platform_data;
32926ade896SRobert Jarzmik 
3308ff06452SArnd Bergmann 	ac97_reg_base = devm_platform_ioremap_resource(dev, 0);
3318ff06452SArnd Bergmann 	if (IS_ERR(ac97_reg_base)) {
3328ff06452SArnd Bergmann 		dev_err(&dev->dev, "Missing MMIO resource\n");
3338ff06452SArnd Bergmann 		return PTR_ERR(ac97_reg_base);
3348ff06452SArnd Bergmann 	}
3358ff06452SArnd Bergmann 
33626ade896SRobert Jarzmik 	if (pdata) {
33726ade896SRobert Jarzmik 		switch (pdata->reset_gpio) {
33826ade896SRobert Jarzmik 		case 95:
33926ade896SRobert Jarzmik 		case 113:
34026ade896SRobert Jarzmik 			reset_gpio = pdata->reset_gpio;
34126ade896SRobert Jarzmik 			break;
34226ade896SRobert Jarzmik 		case 0:
34326ade896SRobert Jarzmik 			reset_gpio = 113;
34426ade896SRobert Jarzmik 			break;
34526ade896SRobert Jarzmik 		case -1:
34626ade896SRobert Jarzmik 			break;
34726ade896SRobert Jarzmik 		default:
3481f218695STakashi Iwai 			dev_err(&dev->dev, "Invalid reset GPIO %d\n",
34926ade896SRobert Jarzmik 				pdata->reset_gpio);
35026ade896SRobert Jarzmik 		}
351a4519526SRobert Jarzmik 	} else if (!pdata && dev->dev.of_node) {
352a4519526SRobert Jarzmik 		pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL);
353a4519526SRobert Jarzmik 		if (!pdata)
354a4519526SRobert Jarzmik 			return -ENOMEM;
355a4519526SRobert Jarzmik 		pdata->reset_gpio = of_get_named_gpio(dev->dev.of_node,
356a4519526SRobert Jarzmik 						      "reset-gpios", 0);
357a4519526SRobert Jarzmik 		if (pdata->reset_gpio == -ENOENT)
358a4519526SRobert Jarzmik 			pdata->reset_gpio = -1;
359a4519526SRobert Jarzmik 		else if (pdata->reset_gpio < 0)
360a4519526SRobert Jarzmik 			return pdata->reset_gpio;
361a4519526SRobert Jarzmik 		reset_gpio = pdata->reset_gpio;
36226ade896SRobert Jarzmik 	} else {
36326ade896SRobert Jarzmik 		if (cpu_is_pxa27x())
36426ade896SRobert Jarzmik 			reset_gpio = 113;
36526ade896SRobert Jarzmik 	}
3669c636342SDmitry Baryshkov 
3679d1cf39bSDmitry Baryshkov 	if (cpu_is_pxa27x()) {
3683b4bc7bcSMike Dunn 		/*
3693b4bc7bcSMike Dunn 		 * This gpio is needed for a work-around to a bug in the ac97
3703b4bc7bcSMike Dunn 		 * controller during warm reset.  The direction and level is set
3713b4bc7bcSMike Dunn 		 * here so that it is an output driven high when switching from
3723b4bc7bcSMike Dunn 		 * AC97_nRESET alt function to generic gpio.
3733b4bc7bcSMike Dunn 		 */
3743b4bc7bcSMike Dunn 		ret = gpio_request_one(reset_gpio, GPIOF_OUT_INIT_HIGH,
3753b4bc7bcSMike Dunn 				       "pxa27x ac97 reset");
3763b4bc7bcSMike Dunn 		if (ret < 0) {
3773b4bc7bcSMike Dunn 			pr_err("%s: gpio_request_one() failed: %d\n",
3783b4bc7bcSMike Dunn 			       __func__, ret);
3793b4bc7bcSMike Dunn 			goto err_conf;
3803b4bc7bcSMike Dunn 		}
381053fe0f1SMike Dunn 		pxa27x_configure_ac97reset(reset_gpio, false);
3823b4bc7bcSMike Dunn 
3839c636342SDmitry Baryshkov 		ac97conf_clk = clk_get(&dev->dev, "AC97CONFCLK");
3849c636342SDmitry Baryshkov 		if (IS_ERR(ac97conf_clk)) {
3859c636342SDmitry Baryshkov 			ret = PTR_ERR(ac97conf_clk);
3869c636342SDmitry Baryshkov 			ac97conf_clk = NULL;
38779612336SDmitry Baryshkov 			goto err_conf;
3889c636342SDmitry Baryshkov 		}
3899d1cf39bSDmitry Baryshkov 	}
3909c636342SDmitry Baryshkov 
3919c636342SDmitry Baryshkov 	ac97_clk = clk_get(&dev->dev, "AC97CLK");
3929c636342SDmitry Baryshkov 	if (IS_ERR(ac97_clk)) {
3939c636342SDmitry Baryshkov 		ret = PTR_ERR(ac97_clk);
3949c636342SDmitry Baryshkov 		ac97_clk = NULL;
39579612336SDmitry Baryshkov 		goto err_clk;
3969c636342SDmitry Baryshkov 	}
3979c636342SDmitry Baryshkov 
3984091d342SRobert Jarzmik 	ret = clk_prepare_enable(ac97_clk);
39979612336SDmitry Baryshkov 	if (ret)
40079612336SDmitry Baryshkov 		goto err_clk2;
40179612336SDmitry Baryshkov 
4022548e6c7SArnd Bergmann 	irq = platform_get_irq(dev, 0);
403*46cf1954SYang Yingliang 	if (irq < 0) {
404*46cf1954SYang Yingliang 		ret = irq;
4052548e6c7SArnd Bergmann 		goto err_irq;
406*46cf1954SYang Yingliang 	}
4072548e6c7SArnd Bergmann 
4082548e6c7SArnd Bergmann 	ret = request_irq(irq, pxa2xx_ac97_irq, 0, "AC97", NULL);
40979612336SDmitry Baryshkov 	if (ret < 0)
41079612336SDmitry Baryshkov 		goto err_irq;
41179612336SDmitry Baryshkov 
41279612336SDmitry Baryshkov 	return 0;
4139c636342SDmitry Baryshkov 
4149c636342SDmitry Baryshkov err_irq:
4158ff06452SArnd Bergmann 	writel(readl(ac97_reg_base + GCR) | (GCR_ACLINK_OFF), ac97_reg_base + GCR);
41679612336SDmitry Baryshkov err_clk2:
41779612336SDmitry Baryshkov 	clk_put(ac97_clk);
41879612336SDmitry Baryshkov 	ac97_clk = NULL;
41979612336SDmitry Baryshkov err_clk:
4209c636342SDmitry Baryshkov 	if (ac97conf_clk) {
4219c636342SDmitry Baryshkov 		clk_put(ac97conf_clk);
4229c636342SDmitry Baryshkov 		ac97conf_clk = NULL;
4239c636342SDmitry Baryshkov 	}
42479612336SDmitry Baryshkov err_conf:
4259c636342SDmitry Baryshkov 	return ret;
4269c636342SDmitry Baryshkov }
4279c636342SDmitry Baryshkov EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_probe);
4289c636342SDmitry Baryshkov 
pxa2xx_ac97_hw_remove(struct platform_device * dev)4299c636342SDmitry Baryshkov void pxa2xx_ac97_hw_remove(struct platform_device *dev)
4309c636342SDmitry Baryshkov {
4313b4bc7bcSMike Dunn 	if (cpu_is_pxa27x())
4323b4bc7bcSMike Dunn 		gpio_free(reset_gpio);
4338ff06452SArnd Bergmann 	writel(readl(ac97_reg_base + GCR) | (GCR_ACLINK_OFF), ac97_reg_base + GCR);
4342548e6c7SArnd Bergmann 	free_irq(platform_get_irq(dev, 0), NULL);
4359d1cf39bSDmitry Baryshkov 	if (ac97conf_clk) {
4369c636342SDmitry Baryshkov 		clk_put(ac97conf_clk);
4379c636342SDmitry Baryshkov 		ac97conf_clk = NULL;
4389d1cf39bSDmitry Baryshkov 	}
4394091d342SRobert Jarzmik 	clk_disable_unprepare(ac97_clk);
4409c636342SDmitry Baryshkov 	clk_put(ac97_clk);
4419c636342SDmitry Baryshkov 	ac97_clk = NULL;
4429c636342SDmitry Baryshkov }
4439c636342SDmitry Baryshkov EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_remove);
4449c636342SDmitry Baryshkov 
pxa2xx_ac97_read_modr(void)445e217b085SArnd Bergmann u32 pxa2xx_ac97_read_modr(void)
446e217b085SArnd Bergmann {
4478ff06452SArnd Bergmann 	if (!ac97_reg_base)
4488ff06452SArnd Bergmann 		return 0;
4498ff06452SArnd Bergmann 
4508ff06452SArnd Bergmann 	return readl(ac97_reg_base + MODR);
451e217b085SArnd Bergmann }
452e217b085SArnd Bergmann EXPORT_SYMBOL_GPL(pxa2xx_ac97_read_modr);
453e217b085SArnd Bergmann 
pxa2xx_ac97_read_misr(void)454e217b085SArnd Bergmann u32 pxa2xx_ac97_read_misr(void)
455e217b085SArnd Bergmann {
4568ff06452SArnd Bergmann 	if (!ac97_reg_base)
4578ff06452SArnd Bergmann 		return 0;
4588ff06452SArnd Bergmann 
4598ff06452SArnd Bergmann 	return readl(ac97_reg_base + MISR);
460e217b085SArnd Bergmann }
461e217b085SArnd Bergmann EXPORT_SYMBOL_GPL(pxa2xx_ac97_read_misr);
462e217b085SArnd Bergmann 
4639c636342SDmitry Baryshkov MODULE_AUTHOR("Nicolas Pitre");
4649c636342SDmitry Baryshkov MODULE_DESCRIPTION("Intel/Marvell PXA sound library");
4659c636342SDmitry Baryshkov MODULE_LICENSE("GPL");
4669c636342SDmitry Baryshkov 
467