1*d2912cb1SThomas 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> 209c636342SDmitry Baryshkov 219c636342SDmitry Baryshkov #include <sound/pxa2xx-lib.h> 229c636342SDmitry Baryshkov 239482ee71SRob Herring #include <mach/irqs.h> 241f017a99SEric Miao #include <mach/regs-ac97.h> 259c636342SDmitry Baryshkov #include <mach/audio.h> 269c636342SDmitry Baryshkov 279c636342SDmitry Baryshkov static DEFINE_MUTEX(car_mutex); 289c636342SDmitry Baryshkov static DECLARE_WAIT_QUEUE_HEAD(gsr_wq); 299c636342SDmitry Baryshkov static volatile long gsr_bits; 309c636342SDmitry Baryshkov static struct clk *ac97_clk; 319c636342SDmitry Baryshkov static struct clk *ac97conf_clk; 3226ade896SRobert Jarzmik static int reset_gpio; 339c636342SDmitry Baryshkov 34053fe0f1SMike Dunn extern void pxa27x_configure_ac97reset(int reset_gpio, bool to_gpio); 35fb1bf8cdSEric Miao 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 466f8acad6SRobert Jarzmik int pxa2xx_ac97_read(int slot, unsigned short reg) 479c636342SDmitry Baryshkov { 486f8acad6SRobert Jarzmik int val = -ENODEV; 499c636342SDmitry Baryshkov volatile u32 *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) 586f8acad6SRobert Jarzmik reg_addr = slot ? &SMC_REG_BASE : &PMC_REG_BASE; 599c636342SDmitry Baryshkov else 606f8acad6SRobert Jarzmik reg_addr = slot ? &SAC_REG_BASE : &PAC_REG_BASE; 619c636342SDmitry Baryshkov reg_addr += (reg >> 1); 629c636342SDmitry Baryshkov 639c636342SDmitry Baryshkov /* start read access across the ac97 link */ 649c636342SDmitry Baryshkov GSR = GSR_CDONE | GSR_SDONE; 659c636342SDmitry Baryshkov gsr_bits = 0; 666f8acad6SRobert Jarzmik val = (*reg_addr & 0xffff); 679c636342SDmitry Baryshkov if (reg == AC97_GPIO_STATUS) 689c636342SDmitry Baryshkov goto out; 699c636342SDmitry Baryshkov if (wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1) <= 0 && 709c636342SDmitry Baryshkov !((GSR | gsr_bits) & GSR_SDONE)) { 719c636342SDmitry Baryshkov printk(KERN_ERR "%s: read error (ac97_reg=%d GSR=%#lx)\n", 729c636342SDmitry Baryshkov __func__, reg, GSR | gsr_bits); 736f8acad6SRobert Jarzmik val = -ETIMEDOUT; 749c636342SDmitry Baryshkov goto out; 759c636342SDmitry Baryshkov } 769c636342SDmitry Baryshkov 779c636342SDmitry Baryshkov /* valid data now */ 789c636342SDmitry Baryshkov GSR = GSR_CDONE | GSR_SDONE; 799c636342SDmitry Baryshkov gsr_bits = 0; 806f8acad6SRobert Jarzmik val = (*reg_addr & 0xffff); 819c636342SDmitry Baryshkov /* but we've just started another cycle... */ 829c636342SDmitry Baryshkov wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1); 839c636342SDmitry Baryshkov 849c636342SDmitry Baryshkov out: mutex_unlock(&car_mutex); 859c636342SDmitry Baryshkov return val; 869c636342SDmitry Baryshkov } 879c636342SDmitry Baryshkov EXPORT_SYMBOL_GPL(pxa2xx_ac97_read); 889c636342SDmitry Baryshkov 896f8acad6SRobert Jarzmik int pxa2xx_ac97_write(int slot, unsigned short reg, unsigned short val) 909c636342SDmitry Baryshkov { 919c636342SDmitry Baryshkov volatile u32 *reg_addr; 926f8acad6SRobert Jarzmik int ret = 0; 939c636342SDmitry Baryshkov 949c636342SDmitry Baryshkov mutex_lock(&car_mutex); 959c636342SDmitry Baryshkov 969c636342SDmitry Baryshkov /* set up primary or secondary codec space */ 978825e8e8SMarc Zyngier if (cpu_is_pxa25x() && reg == AC97_GPIO_STATUS) 986f8acad6SRobert Jarzmik reg_addr = slot ? &SMC_REG_BASE : &PMC_REG_BASE; 999c636342SDmitry Baryshkov else 1006f8acad6SRobert Jarzmik reg_addr = slot ? &SAC_REG_BASE : &PAC_REG_BASE; 1019c636342SDmitry Baryshkov reg_addr += (reg >> 1); 1029c636342SDmitry Baryshkov 1039c636342SDmitry Baryshkov GSR = GSR_CDONE | GSR_SDONE; 1049c636342SDmitry Baryshkov gsr_bits = 0; 1059c636342SDmitry Baryshkov *reg_addr = val; 1069c636342SDmitry Baryshkov if (wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_CDONE, 1) <= 0 && 1076f8acad6SRobert Jarzmik !((GSR | gsr_bits) & GSR_CDONE)) { 1089c636342SDmitry Baryshkov printk(KERN_ERR "%s: write error (ac97_reg=%d GSR=%#lx)\n", 1099c636342SDmitry Baryshkov __func__, reg, GSR | gsr_bits); 1106f8acad6SRobert Jarzmik ret = -EIO; 1116f8acad6SRobert Jarzmik } 1129c636342SDmitry Baryshkov 1139c636342SDmitry Baryshkov mutex_unlock(&car_mutex); 1146f8acad6SRobert Jarzmik return ret; 1159c636342SDmitry Baryshkov } 1169c636342SDmitry Baryshkov EXPORT_SYMBOL_GPL(pxa2xx_ac97_write); 1179c636342SDmitry Baryshkov 1189d1cf39bSDmitry Baryshkov #ifdef CONFIG_PXA25x 1199d1cf39bSDmitry Baryshkov static inline void pxa_ac97_warm_pxa25x(void) 1209c636342SDmitry Baryshkov { 1219c636342SDmitry Baryshkov gsr_bits = 0; 1229c636342SDmitry Baryshkov 123beb02cddSDmitry Eremin-Solenikov GCR |= GCR_WARM_RST; 1249d1cf39bSDmitry Baryshkov } 1259d1cf39bSDmitry Baryshkov 1269d1cf39bSDmitry Baryshkov static inline void pxa_ac97_cold_pxa25x(void) 1279d1cf39bSDmitry Baryshkov { 1289d1cf39bSDmitry Baryshkov GCR &= GCR_COLD_RST; /* clear everything but nCRST */ 1299d1cf39bSDmitry Baryshkov GCR &= ~GCR_COLD_RST; /* then assert nCRST */ 1309d1cf39bSDmitry Baryshkov 1319d1cf39bSDmitry Baryshkov gsr_bits = 0; 1329d1cf39bSDmitry Baryshkov 1339d1cf39bSDmitry Baryshkov GCR = GCR_COLD_RST; 1349d1cf39bSDmitry Baryshkov } 1359d1cf39bSDmitry Baryshkov #endif 1369d1cf39bSDmitry Baryshkov 1379c636342SDmitry Baryshkov #ifdef CONFIG_PXA27x 1389d1cf39bSDmitry Baryshkov static inline void pxa_ac97_warm_pxa27x(void) 1399d1cf39bSDmitry Baryshkov { 1409d1cf39bSDmitry Baryshkov gsr_bits = 0; 1419d1cf39bSDmitry Baryshkov 142fb1bf8cdSEric Miao /* warm reset broken on Bulverde, so manually keep AC97 reset high */ 143053fe0f1SMike Dunn pxa27x_configure_ac97reset(reset_gpio, true); 1449c636342SDmitry Baryshkov udelay(10); 1459c636342SDmitry Baryshkov GCR |= GCR_WARM_RST; 146053fe0f1SMike Dunn pxa27x_configure_ac97reset(reset_gpio, false); 1479c636342SDmitry Baryshkov udelay(500); 1489d1cf39bSDmitry Baryshkov } 1499d1cf39bSDmitry Baryshkov 1509d1cf39bSDmitry Baryshkov static inline void pxa_ac97_cold_pxa27x(void) 1519d1cf39bSDmitry Baryshkov { 1529d1cf39bSDmitry Baryshkov GCR &= GCR_COLD_RST; /* clear everything but nCRST */ 1539d1cf39bSDmitry Baryshkov GCR &= ~GCR_COLD_RST; /* then assert nCRST */ 1549d1cf39bSDmitry Baryshkov 1559d1cf39bSDmitry Baryshkov gsr_bits = 0; 1569d1cf39bSDmitry Baryshkov 1579d1cf39bSDmitry Baryshkov /* PXA27x Developers Manual section 13.5.2.2.1 */ 1584091d342SRobert Jarzmik clk_prepare_enable(ac97conf_clk); 1599d1cf39bSDmitry Baryshkov udelay(5); 1604091d342SRobert Jarzmik clk_disable_unprepare(ac97conf_clk); 16141b645c8SMike Dunn GCR = GCR_COLD_RST | GCR_WARM_RST; 1629d1cf39bSDmitry Baryshkov } 1639d1cf39bSDmitry Baryshkov #endif 1649d1cf39bSDmitry Baryshkov 1659d1cf39bSDmitry Baryshkov #ifdef CONFIG_PXA3xx 1669d1cf39bSDmitry Baryshkov static inline void pxa_ac97_warm_pxa3xx(void) 1679d1cf39bSDmitry Baryshkov { 1689d1cf39bSDmitry Baryshkov gsr_bits = 0; 1699d1cf39bSDmitry Baryshkov 1709c636342SDmitry Baryshkov /* Can't use interrupts */ 1719c636342SDmitry Baryshkov GCR |= GCR_WARM_RST; 1729d1cf39bSDmitry Baryshkov } 1739d1cf39bSDmitry Baryshkov 1749d1cf39bSDmitry Baryshkov static inline void pxa_ac97_cold_pxa3xx(void) 1759d1cf39bSDmitry Baryshkov { 1769d1cf39bSDmitry Baryshkov /* Hold CLKBPB for 100us */ 1779d1cf39bSDmitry Baryshkov GCR = 0; 1789d1cf39bSDmitry Baryshkov GCR = GCR_CLKBPB; 1799d1cf39bSDmitry Baryshkov udelay(100); 1809d1cf39bSDmitry Baryshkov GCR = 0; 1819d1cf39bSDmitry Baryshkov 1829d1cf39bSDmitry Baryshkov GCR &= GCR_COLD_RST; /* clear everything but nCRST */ 1839d1cf39bSDmitry Baryshkov GCR &= ~GCR_COLD_RST; /* then assert nCRST */ 1849d1cf39bSDmitry Baryshkov 1859d1cf39bSDmitry Baryshkov gsr_bits = 0; 1869d1cf39bSDmitry Baryshkov 1879d1cf39bSDmitry Baryshkov /* Can't use interrupts on PXA3xx */ 1889d1cf39bSDmitry Baryshkov GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN); 1899d1cf39bSDmitry Baryshkov 1909d1cf39bSDmitry Baryshkov GCR = GCR_WARM_RST | GCR_COLD_RST; 1919d1cf39bSDmitry Baryshkov } 1929c636342SDmitry Baryshkov #endif 1939c636342SDmitry Baryshkov 1946f8acad6SRobert Jarzmik bool pxa2xx_ac97_try_warm_reset(void) 1959d1cf39bSDmitry Baryshkov { 196057de50cSLuotao Fu unsigned long gsr; 197beb02cddSDmitry Eremin-Solenikov unsigned int timeout = 100; 198057de50cSLuotao Fu 1999d1cf39bSDmitry Baryshkov #ifdef CONFIG_PXA25x 2008825e8e8SMarc Zyngier if (cpu_is_pxa25x()) 2019d1cf39bSDmitry Baryshkov pxa_ac97_warm_pxa25x(); 2029d1cf39bSDmitry Baryshkov else 2039d1cf39bSDmitry Baryshkov #endif 2049d1cf39bSDmitry Baryshkov #ifdef CONFIG_PXA27x 2059d1cf39bSDmitry Baryshkov if (cpu_is_pxa27x()) 2069d1cf39bSDmitry Baryshkov pxa_ac97_warm_pxa27x(); 2079d1cf39bSDmitry Baryshkov else 2089d1cf39bSDmitry Baryshkov #endif 2099d1cf39bSDmitry Baryshkov #ifdef CONFIG_PXA3xx 2109d1cf39bSDmitry Baryshkov if (cpu_is_pxa3xx()) 2119d1cf39bSDmitry Baryshkov pxa_ac97_warm_pxa3xx(); 2129d1cf39bSDmitry Baryshkov else 2139d1cf39bSDmitry Baryshkov #endif 21488ec7ae8STakashi Iwai snd_BUG(); 215beb02cddSDmitry Eremin-Solenikov 216beb02cddSDmitry Eremin-Solenikov while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--) 217beb02cddSDmitry Eremin-Solenikov mdelay(1); 218beb02cddSDmitry Eremin-Solenikov 219057de50cSLuotao Fu gsr = GSR | gsr_bits; 220057de50cSLuotao Fu if (!(gsr & (GSR_PCR | GSR_SCR))) { 2219c636342SDmitry Baryshkov printk(KERN_INFO "%s: warm reset timeout (GSR=%#lx)\n", 222057de50cSLuotao Fu __func__, gsr); 2239c636342SDmitry Baryshkov 2249c636342SDmitry Baryshkov return false; 2259c636342SDmitry Baryshkov } 2269c636342SDmitry Baryshkov 2279c636342SDmitry Baryshkov return true; 2289c636342SDmitry Baryshkov } 2299c636342SDmitry Baryshkov EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_warm_reset); 2309c636342SDmitry Baryshkov 2316f8acad6SRobert Jarzmik bool pxa2xx_ac97_try_cold_reset(void) 2329c636342SDmitry Baryshkov { 233057de50cSLuotao Fu unsigned long gsr; 234beb02cddSDmitry Eremin-Solenikov unsigned int timeout = 1000; 235057de50cSLuotao Fu 2369d1cf39bSDmitry Baryshkov #ifdef CONFIG_PXA25x 2378825e8e8SMarc Zyngier if (cpu_is_pxa25x()) 2389d1cf39bSDmitry Baryshkov pxa_ac97_cold_pxa25x(); 2399d1cf39bSDmitry Baryshkov else 2409c636342SDmitry Baryshkov #endif 2419c636342SDmitry Baryshkov #ifdef CONFIG_PXA27x 2429d1cf39bSDmitry Baryshkov if (cpu_is_pxa27x()) 2439d1cf39bSDmitry Baryshkov pxa_ac97_cold_pxa27x(); 2449d1cf39bSDmitry Baryshkov else 2459c636342SDmitry Baryshkov #endif 2469d1cf39bSDmitry Baryshkov #ifdef CONFIG_PXA3xx 2479d1cf39bSDmitry Baryshkov if (cpu_is_pxa3xx()) 2489d1cf39bSDmitry Baryshkov pxa_ac97_cold_pxa3xx(); 2499d1cf39bSDmitry Baryshkov else 2509d1cf39bSDmitry Baryshkov #endif 25188ec7ae8STakashi Iwai snd_BUG(); 2529c636342SDmitry Baryshkov 253beb02cddSDmitry Eremin-Solenikov while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--) 254beb02cddSDmitry Eremin-Solenikov mdelay(1); 255beb02cddSDmitry Eremin-Solenikov 256057de50cSLuotao Fu gsr = GSR | gsr_bits; 257057de50cSLuotao Fu if (!(gsr & (GSR_PCR | GSR_SCR))) { 2589c636342SDmitry Baryshkov printk(KERN_INFO "%s: cold reset timeout (GSR=%#lx)\n", 259057de50cSLuotao Fu __func__, gsr); 2609c636342SDmitry Baryshkov 2619c636342SDmitry Baryshkov return false; 2629c636342SDmitry Baryshkov } 2639c636342SDmitry Baryshkov 2649c636342SDmitry Baryshkov return true; 2659c636342SDmitry Baryshkov } 2669c636342SDmitry Baryshkov EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_cold_reset); 2679c636342SDmitry Baryshkov 2689c636342SDmitry Baryshkov 2696f8acad6SRobert Jarzmik void pxa2xx_ac97_finish_reset(void) 2709c636342SDmitry Baryshkov { 2719c636342SDmitry Baryshkov GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN); 2729c636342SDmitry Baryshkov GCR |= GCR_SDONE_IE|GCR_CDONE_IE; 2739c636342SDmitry Baryshkov } 2749c636342SDmitry Baryshkov EXPORT_SYMBOL_GPL(pxa2xx_ac97_finish_reset); 2759c636342SDmitry Baryshkov 2769c636342SDmitry Baryshkov static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id) 2779c636342SDmitry Baryshkov { 2789c636342SDmitry Baryshkov long status; 2799c636342SDmitry Baryshkov 2809c636342SDmitry Baryshkov status = GSR; 2819c636342SDmitry Baryshkov if (status) { 2829c636342SDmitry Baryshkov GSR = status; 2839c636342SDmitry Baryshkov gsr_bits |= status; 2849c636342SDmitry Baryshkov wake_up(&gsr_wq); 2859c636342SDmitry Baryshkov 2869c636342SDmitry Baryshkov /* Although we don't use those we still need to clear them 2879c636342SDmitry Baryshkov since they tend to spuriously trigger when MMC is used 2889c636342SDmitry Baryshkov (hardware bug? go figure)... */ 2899d1cf39bSDmitry Baryshkov if (cpu_is_pxa27x()) { 2909c636342SDmitry Baryshkov MISR = MISR_EOC; 2919c636342SDmitry Baryshkov PISR = PISR_EOC; 2929c636342SDmitry Baryshkov MCSR = MCSR_EOC; 2939d1cf39bSDmitry Baryshkov } 2949c636342SDmitry Baryshkov 2959c636342SDmitry Baryshkov return IRQ_HANDLED; 2969c636342SDmitry Baryshkov } 2979c636342SDmitry Baryshkov 2989c636342SDmitry Baryshkov return IRQ_NONE; 2999c636342SDmitry Baryshkov } 3009c636342SDmitry Baryshkov 3019c636342SDmitry Baryshkov #ifdef CONFIG_PM 3029c636342SDmitry Baryshkov int pxa2xx_ac97_hw_suspend(void) 3039c636342SDmitry Baryshkov { 3049c636342SDmitry Baryshkov GCR |= GCR_ACLINK_OFF; 3054091d342SRobert Jarzmik clk_disable_unprepare(ac97_clk); 3069c636342SDmitry Baryshkov return 0; 3079c636342SDmitry Baryshkov } 3089c636342SDmitry Baryshkov EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_suspend); 3099c636342SDmitry Baryshkov 3109c636342SDmitry Baryshkov int pxa2xx_ac97_hw_resume(void) 3119c636342SDmitry Baryshkov { 3124091d342SRobert Jarzmik clk_prepare_enable(ac97_clk); 3139c636342SDmitry Baryshkov return 0; 3149c636342SDmitry Baryshkov } 3159c636342SDmitry Baryshkov EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_resume); 3169c636342SDmitry Baryshkov #endif 3179c636342SDmitry Baryshkov 318e21596bbSBill Pemberton int pxa2xx_ac97_hw_probe(struct platform_device *dev) 3199c636342SDmitry Baryshkov { 3209c636342SDmitry Baryshkov int ret; 321eae17754SMark Brown pxa2xx_audio_ops_t *pdata = dev->dev.platform_data; 32226ade896SRobert Jarzmik 32326ade896SRobert Jarzmik if (pdata) { 32426ade896SRobert Jarzmik switch (pdata->reset_gpio) { 32526ade896SRobert Jarzmik case 95: 32626ade896SRobert Jarzmik case 113: 32726ade896SRobert Jarzmik reset_gpio = pdata->reset_gpio; 32826ade896SRobert Jarzmik break; 32926ade896SRobert Jarzmik case 0: 33026ade896SRobert Jarzmik reset_gpio = 113; 33126ade896SRobert Jarzmik break; 33226ade896SRobert Jarzmik case -1: 33326ade896SRobert Jarzmik break; 33426ade896SRobert Jarzmik default: 3351f218695STakashi Iwai dev_err(&dev->dev, "Invalid reset GPIO %d\n", 33626ade896SRobert Jarzmik pdata->reset_gpio); 33726ade896SRobert Jarzmik } 338a4519526SRobert Jarzmik } else if (!pdata && dev->dev.of_node) { 339a4519526SRobert Jarzmik pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL); 340a4519526SRobert Jarzmik if (!pdata) 341a4519526SRobert Jarzmik return -ENOMEM; 342a4519526SRobert Jarzmik pdata->reset_gpio = of_get_named_gpio(dev->dev.of_node, 343a4519526SRobert Jarzmik "reset-gpios", 0); 344a4519526SRobert Jarzmik if (pdata->reset_gpio == -ENOENT) 345a4519526SRobert Jarzmik pdata->reset_gpio = -1; 346a4519526SRobert Jarzmik else if (pdata->reset_gpio < 0) 347a4519526SRobert Jarzmik return pdata->reset_gpio; 348a4519526SRobert Jarzmik reset_gpio = pdata->reset_gpio; 34926ade896SRobert Jarzmik } else { 35026ade896SRobert Jarzmik if (cpu_is_pxa27x()) 35126ade896SRobert Jarzmik reset_gpio = 113; 35226ade896SRobert Jarzmik } 3539c636342SDmitry Baryshkov 3549d1cf39bSDmitry Baryshkov if (cpu_is_pxa27x()) { 3553b4bc7bcSMike Dunn /* 3563b4bc7bcSMike Dunn * This gpio is needed for a work-around to a bug in the ac97 3573b4bc7bcSMike Dunn * controller during warm reset. The direction and level is set 3583b4bc7bcSMike Dunn * here so that it is an output driven high when switching from 3593b4bc7bcSMike Dunn * AC97_nRESET alt function to generic gpio. 3603b4bc7bcSMike Dunn */ 3613b4bc7bcSMike Dunn ret = gpio_request_one(reset_gpio, GPIOF_OUT_INIT_HIGH, 3623b4bc7bcSMike Dunn "pxa27x ac97 reset"); 3633b4bc7bcSMike Dunn if (ret < 0) { 3643b4bc7bcSMike Dunn pr_err("%s: gpio_request_one() failed: %d\n", 3653b4bc7bcSMike Dunn __func__, ret); 3663b4bc7bcSMike Dunn goto err_conf; 3673b4bc7bcSMike Dunn } 368053fe0f1SMike Dunn pxa27x_configure_ac97reset(reset_gpio, false); 3693b4bc7bcSMike Dunn 3709c636342SDmitry Baryshkov ac97conf_clk = clk_get(&dev->dev, "AC97CONFCLK"); 3719c636342SDmitry Baryshkov if (IS_ERR(ac97conf_clk)) { 3729c636342SDmitry Baryshkov ret = PTR_ERR(ac97conf_clk); 3739c636342SDmitry Baryshkov ac97conf_clk = NULL; 37479612336SDmitry Baryshkov goto err_conf; 3759c636342SDmitry Baryshkov } 3769d1cf39bSDmitry Baryshkov } 3779c636342SDmitry Baryshkov 3789c636342SDmitry Baryshkov ac97_clk = clk_get(&dev->dev, "AC97CLK"); 3799c636342SDmitry Baryshkov if (IS_ERR(ac97_clk)) { 3809c636342SDmitry Baryshkov ret = PTR_ERR(ac97_clk); 3819c636342SDmitry Baryshkov ac97_clk = NULL; 38279612336SDmitry Baryshkov goto err_clk; 3839c636342SDmitry Baryshkov } 3849c636342SDmitry Baryshkov 3854091d342SRobert Jarzmik ret = clk_prepare_enable(ac97_clk); 38679612336SDmitry Baryshkov if (ret) 38779612336SDmitry Baryshkov goto err_clk2; 38879612336SDmitry Baryshkov 38988e24c3aSYong Zhang ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, 0, "AC97", NULL); 39079612336SDmitry Baryshkov if (ret < 0) 39179612336SDmitry Baryshkov goto err_irq; 39279612336SDmitry Baryshkov 39379612336SDmitry Baryshkov return 0; 3949c636342SDmitry Baryshkov 3959c636342SDmitry Baryshkov err_irq: 3969c636342SDmitry Baryshkov GCR |= GCR_ACLINK_OFF; 39779612336SDmitry Baryshkov err_clk2: 39879612336SDmitry Baryshkov clk_put(ac97_clk); 39979612336SDmitry Baryshkov ac97_clk = NULL; 40079612336SDmitry Baryshkov err_clk: 4019c636342SDmitry Baryshkov if (ac97conf_clk) { 4029c636342SDmitry Baryshkov clk_put(ac97conf_clk); 4039c636342SDmitry Baryshkov ac97conf_clk = NULL; 4049c636342SDmitry Baryshkov } 40579612336SDmitry Baryshkov err_conf: 4069c636342SDmitry Baryshkov return ret; 4079c636342SDmitry Baryshkov } 4089c636342SDmitry Baryshkov EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_probe); 4099c636342SDmitry Baryshkov 4109c636342SDmitry Baryshkov void pxa2xx_ac97_hw_remove(struct platform_device *dev) 4119c636342SDmitry Baryshkov { 4123b4bc7bcSMike Dunn if (cpu_is_pxa27x()) 4133b4bc7bcSMike Dunn gpio_free(reset_gpio); 4149c636342SDmitry Baryshkov GCR |= GCR_ACLINK_OFF; 4159c636342SDmitry Baryshkov free_irq(IRQ_AC97, NULL); 4169d1cf39bSDmitry Baryshkov if (ac97conf_clk) { 4179c636342SDmitry Baryshkov clk_put(ac97conf_clk); 4189c636342SDmitry Baryshkov ac97conf_clk = NULL; 4199d1cf39bSDmitry Baryshkov } 4204091d342SRobert Jarzmik clk_disable_unprepare(ac97_clk); 4219c636342SDmitry Baryshkov clk_put(ac97_clk); 4229c636342SDmitry Baryshkov ac97_clk = NULL; 4239c636342SDmitry Baryshkov } 4249c636342SDmitry Baryshkov EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_remove); 4259c636342SDmitry Baryshkov 4269c636342SDmitry Baryshkov MODULE_AUTHOR("Nicolas Pitre"); 4279c636342SDmitry Baryshkov MODULE_DESCRIPTION("Intel/Marvell PXA sound library"); 4289c636342SDmitry Baryshkov MODULE_LICENSE("GPL"); 4299c636342SDmitry Baryshkov 430