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 36053fe0f1SMike Dunn extern void pxa27x_configure_ac97reset(int reset_gpio, bool to_gpio); 37fb1bf8cdSEric Miao 389c636342SDmitry Baryshkov /* 399c636342SDmitry Baryshkov * Beware PXA27x bugs: 409c636342SDmitry Baryshkov * 419c636342SDmitry Baryshkov * o Slot 12 read from modem space will hang controller. 429c636342SDmitry Baryshkov * o CDONE, SDONE interrupt fails after any slot 12 IO. 439c636342SDmitry Baryshkov * 449c636342SDmitry Baryshkov * We therefore have an hybrid approach for waiting on SDONE (interrupt or 459c636342SDmitry Baryshkov * 1 jiffy timeout if interrupt never comes). 469c636342SDmitry Baryshkov */ 479c636342SDmitry Baryshkov 486f8acad6SRobert Jarzmik int pxa2xx_ac97_read(int slot, unsigned short reg) 499c636342SDmitry Baryshkov { 506f8acad6SRobert Jarzmik int val = -ENODEV; 518ff06452SArnd Bergmann u32 __iomem *reg_addr; 529c636342SDmitry Baryshkov 536f8acad6SRobert Jarzmik if (slot > 0) 546f8acad6SRobert Jarzmik return -ENODEV; 556f8acad6SRobert Jarzmik 569c636342SDmitry Baryshkov mutex_lock(&car_mutex); 579c636342SDmitry Baryshkov 589c636342SDmitry Baryshkov /* set up primary or secondary codec space */ 598825e8e8SMarc Zyngier if (cpu_is_pxa25x() && reg == AC97_GPIO_STATUS) 608ff06452SArnd Bergmann reg_addr = ac97_reg_base + 618ff06452SArnd Bergmann (slot ? SMC_REG_BASE : PMC_REG_BASE); 629c636342SDmitry Baryshkov else 638ff06452SArnd Bergmann reg_addr = ac97_reg_base + 648ff06452SArnd Bergmann (slot ? SAC_REG_BASE : PAC_REG_BASE); 659c636342SDmitry Baryshkov reg_addr += (reg >> 1); 669c636342SDmitry Baryshkov 679c636342SDmitry Baryshkov /* start read access across the ac97 link */ 688ff06452SArnd Bergmann writel(GSR_CDONE | GSR_SDONE, ac97_reg_base + GSR); 699c636342SDmitry Baryshkov gsr_bits = 0; 708ff06452SArnd Bergmann val = (readl(reg_addr) & 0xffff); 719c636342SDmitry Baryshkov if (reg == AC97_GPIO_STATUS) 729c636342SDmitry Baryshkov goto out; 738ff06452SArnd Bergmann if (wait_event_timeout(gsr_wq, (readl(ac97_reg_base + GSR) | gsr_bits) & GSR_SDONE, 1) <= 0 && 748ff06452SArnd Bergmann !((readl(ac97_reg_base + GSR) | gsr_bits) & GSR_SDONE)) { 759c636342SDmitry Baryshkov printk(KERN_ERR "%s: read error (ac97_reg=%d GSR=%#lx)\n", 768ff06452SArnd Bergmann __func__, reg, readl(ac97_reg_base + GSR) | gsr_bits); 776f8acad6SRobert Jarzmik val = -ETIMEDOUT; 789c636342SDmitry Baryshkov goto out; 799c636342SDmitry Baryshkov } 809c636342SDmitry Baryshkov 819c636342SDmitry Baryshkov /* valid data now */ 828ff06452SArnd Bergmann writel(GSR_CDONE | GSR_SDONE, ac97_reg_base + GSR); 839c636342SDmitry Baryshkov gsr_bits = 0; 848ff06452SArnd Bergmann val = (readl(reg_addr) & 0xffff); 859c636342SDmitry Baryshkov /* but we've just started another cycle... */ 868ff06452SArnd Bergmann wait_event_timeout(gsr_wq, (readl(ac97_reg_base + GSR) | gsr_bits) & GSR_SDONE, 1); 879c636342SDmitry Baryshkov 889c636342SDmitry Baryshkov out: mutex_unlock(&car_mutex); 899c636342SDmitry Baryshkov return val; 909c636342SDmitry Baryshkov } 919c636342SDmitry Baryshkov EXPORT_SYMBOL_GPL(pxa2xx_ac97_read); 929c636342SDmitry Baryshkov 936f8acad6SRobert Jarzmik int pxa2xx_ac97_write(int slot, unsigned short reg, unsigned short val) 949c636342SDmitry Baryshkov { 958ff06452SArnd Bergmann u32 __iomem *reg_addr; 966f8acad6SRobert Jarzmik int ret = 0; 979c636342SDmitry Baryshkov 989c636342SDmitry Baryshkov mutex_lock(&car_mutex); 999c636342SDmitry Baryshkov 1009c636342SDmitry Baryshkov /* set up primary or secondary codec space */ 1018825e8e8SMarc Zyngier if (cpu_is_pxa25x() && reg == AC97_GPIO_STATUS) 1028ff06452SArnd Bergmann reg_addr = ac97_reg_base + 1038ff06452SArnd Bergmann (slot ? SMC_REG_BASE : PMC_REG_BASE); 1049c636342SDmitry Baryshkov else 1058ff06452SArnd Bergmann reg_addr = ac97_reg_base + 1068ff06452SArnd Bergmann (slot ? SAC_REG_BASE : PAC_REG_BASE); 1079c636342SDmitry Baryshkov reg_addr += (reg >> 1); 1089c636342SDmitry Baryshkov 1098ff06452SArnd Bergmann writel(GSR_CDONE | GSR_SDONE, ac97_reg_base + GSR); 1109c636342SDmitry Baryshkov gsr_bits = 0; 1118ff06452SArnd Bergmann writel(val, reg_addr); 1128ff06452SArnd Bergmann if (wait_event_timeout(gsr_wq, (readl(ac97_reg_base + GSR) | gsr_bits) & GSR_CDONE, 1) <= 0 && 1138ff06452SArnd Bergmann !((readl(ac97_reg_base + GSR) | gsr_bits) & GSR_CDONE)) { 1149c636342SDmitry Baryshkov printk(KERN_ERR "%s: write error (ac97_reg=%d GSR=%#lx)\n", 1158ff06452SArnd Bergmann __func__, reg, readl(ac97_reg_base + GSR) | gsr_bits); 1166f8acad6SRobert Jarzmik ret = -EIO; 1176f8acad6SRobert Jarzmik } 1189c636342SDmitry Baryshkov 1199c636342SDmitry Baryshkov mutex_unlock(&car_mutex); 1206f8acad6SRobert Jarzmik return ret; 1219c636342SDmitry Baryshkov } 1229c636342SDmitry Baryshkov EXPORT_SYMBOL_GPL(pxa2xx_ac97_write); 1239c636342SDmitry Baryshkov 1249d1cf39bSDmitry Baryshkov #ifdef CONFIG_PXA25x 1259d1cf39bSDmitry Baryshkov static inline void pxa_ac97_warm_pxa25x(void) 1269c636342SDmitry Baryshkov { 1279c636342SDmitry Baryshkov gsr_bits = 0; 1289c636342SDmitry Baryshkov 1298ff06452SArnd Bergmann writel(readl(ac97_reg_base + GCR) | (GCR_WARM_RST), ac97_reg_base + GCR); 1309d1cf39bSDmitry Baryshkov } 1319d1cf39bSDmitry Baryshkov 1329d1cf39bSDmitry Baryshkov static inline void pxa_ac97_cold_pxa25x(void) 1339d1cf39bSDmitry Baryshkov { 1348ff06452SArnd Bergmann writel(readl(ac97_reg_base + GCR) & ( GCR_COLD_RST), ac97_reg_base + GCR); /* clear everything but nCRST */ 1358ff06452SArnd Bergmann writel(readl(ac97_reg_base + GCR) & (~GCR_COLD_RST), ac97_reg_base + GCR); /* then assert nCRST */ 1369d1cf39bSDmitry Baryshkov 1379d1cf39bSDmitry Baryshkov gsr_bits = 0; 1389d1cf39bSDmitry Baryshkov 1398ff06452SArnd Bergmann writel(GCR_COLD_RST, ac97_reg_base + GCR); 1409d1cf39bSDmitry Baryshkov } 1419d1cf39bSDmitry Baryshkov #endif 1429d1cf39bSDmitry Baryshkov 1439c636342SDmitry Baryshkov #ifdef CONFIG_PXA27x 1449d1cf39bSDmitry Baryshkov static inline void pxa_ac97_warm_pxa27x(void) 1459d1cf39bSDmitry Baryshkov { 1469d1cf39bSDmitry Baryshkov gsr_bits = 0; 1479d1cf39bSDmitry Baryshkov 148fb1bf8cdSEric Miao /* warm reset broken on Bulverde, so manually keep AC97 reset high */ 149053fe0f1SMike Dunn pxa27x_configure_ac97reset(reset_gpio, true); 1509c636342SDmitry Baryshkov udelay(10); 1518ff06452SArnd Bergmann writel(readl(ac97_reg_base + GCR) | (GCR_WARM_RST), ac97_reg_base + GCR); 152053fe0f1SMike Dunn pxa27x_configure_ac97reset(reset_gpio, false); 1539c636342SDmitry Baryshkov udelay(500); 1549d1cf39bSDmitry Baryshkov } 1559d1cf39bSDmitry Baryshkov 1569d1cf39bSDmitry Baryshkov static inline void pxa_ac97_cold_pxa27x(void) 1579d1cf39bSDmitry Baryshkov { 1588ff06452SArnd Bergmann writel(readl(ac97_reg_base + GCR) & ( GCR_COLD_RST), ac97_reg_base + GCR); /* clear everything but nCRST */ 1598ff06452SArnd Bergmann writel(readl(ac97_reg_base + GCR) & (~GCR_COLD_RST), ac97_reg_base + GCR); /* then assert nCRST */ 1609d1cf39bSDmitry Baryshkov 1619d1cf39bSDmitry Baryshkov gsr_bits = 0; 1629d1cf39bSDmitry Baryshkov 1639d1cf39bSDmitry Baryshkov /* PXA27x Developers Manual section 13.5.2.2.1 */ 1644091d342SRobert Jarzmik clk_prepare_enable(ac97conf_clk); 1659d1cf39bSDmitry Baryshkov udelay(5); 1664091d342SRobert Jarzmik clk_disable_unprepare(ac97conf_clk); 1678ff06452SArnd Bergmann writel(GCR_COLD_RST | GCR_WARM_RST, ac97_reg_base + GCR); 1689d1cf39bSDmitry Baryshkov } 1699d1cf39bSDmitry Baryshkov #endif 1709d1cf39bSDmitry Baryshkov 1719d1cf39bSDmitry Baryshkov #ifdef CONFIG_PXA3xx 1729d1cf39bSDmitry Baryshkov static inline void pxa_ac97_warm_pxa3xx(void) 1739d1cf39bSDmitry Baryshkov { 1749d1cf39bSDmitry Baryshkov gsr_bits = 0; 1759d1cf39bSDmitry Baryshkov 1769c636342SDmitry Baryshkov /* Can't use interrupts */ 1778ff06452SArnd Bergmann writel(readl(ac97_reg_base + GCR) | (GCR_WARM_RST), ac97_reg_base + GCR); 1789d1cf39bSDmitry Baryshkov } 1799d1cf39bSDmitry Baryshkov 1809d1cf39bSDmitry Baryshkov static inline void pxa_ac97_cold_pxa3xx(void) 1819d1cf39bSDmitry Baryshkov { 1829d1cf39bSDmitry Baryshkov /* Hold CLKBPB for 100us */ 1838ff06452SArnd Bergmann writel(0, ac97_reg_base + GCR); 1848ff06452SArnd Bergmann writel(GCR_CLKBPB, ac97_reg_base + GCR); 1859d1cf39bSDmitry Baryshkov udelay(100); 1868ff06452SArnd Bergmann writel(0, ac97_reg_base + GCR); 1879d1cf39bSDmitry Baryshkov 1888ff06452SArnd Bergmann writel(readl(ac97_reg_base + GCR) & ( GCR_COLD_RST), ac97_reg_base + GCR); /* clear everything but nCRST */ 1898ff06452SArnd Bergmann writel(readl(ac97_reg_base + GCR) & (~GCR_COLD_RST), ac97_reg_base + GCR); /* then assert nCRST */ 1909d1cf39bSDmitry Baryshkov 1919d1cf39bSDmitry Baryshkov gsr_bits = 0; 1929d1cf39bSDmitry Baryshkov 1939d1cf39bSDmitry Baryshkov /* Can't use interrupts on PXA3xx */ 1948ff06452SArnd Bergmann writel(readl(ac97_reg_base + GCR) & (~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN)), ac97_reg_base + GCR); 1959d1cf39bSDmitry Baryshkov 1968ff06452SArnd Bergmann writel(GCR_WARM_RST | GCR_COLD_RST, ac97_reg_base + GCR); 1979d1cf39bSDmitry Baryshkov } 1989c636342SDmitry Baryshkov #endif 1999c636342SDmitry Baryshkov 2006f8acad6SRobert Jarzmik bool pxa2xx_ac97_try_warm_reset(void) 2019d1cf39bSDmitry Baryshkov { 202057de50cSLuotao Fu unsigned long gsr; 203beb02cddSDmitry Eremin-Solenikov unsigned int timeout = 100; 204057de50cSLuotao Fu 2059d1cf39bSDmitry Baryshkov #ifdef CONFIG_PXA25x 2068825e8e8SMarc Zyngier if (cpu_is_pxa25x()) 2079d1cf39bSDmitry Baryshkov pxa_ac97_warm_pxa25x(); 2089d1cf39bSDmitry Baryshkov else 2099d1cf39bSDmitry Baryshkov #endif 2109d1cf39bSDmitry Baryshkov #ifdef CONFIG_PXA27x 2119d1cf39bSDmitry Baryshkov if (cpu_is_pxa27x()) 2129d1cf39bSDmitry Baryshkov pxa_ac97_warm_pxa27x(); 2139d1cf39bSDmitry Baryshkov else 2149d1cf39bSDmitry Baryshkov #endif 2159d1cf39bSDmitry Baryshkov #ifdef CONFIG_PXA3xx 2169d1cf39bSDmitry Baryshkov if (cpu_is_pxa3xx()) 2179d1cf39bSDmitry Baryshkov pxa_ac97_warm_pxa3xx(); 2189d1cf39bSDmitry Baryshkov else 2199d1cf39bSDmitry Baryshkov #endif 22088ec7ae8STakashi Iwai snd_BUG(); 221beb02cddSDmitry Eremin-Solenikov 2228ff06452SArnd Bergmann while (!((readl(ac97_reg_base + GSR) | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--) 223beb02cddSDmitry Eremin-Solenikov mdelay(1); 224beb02cddSDmitry Eremin-Solenikov 2258ff06452SArnd Bergmann gsr = readl(ac97_reg_base + GSR) | gsr_bits; 226057de50cSLuotao Fu if (!(gsr & (GSR_PCR | GSR_SCR))) { 2279c636342SDmitry Baryshkov printk(KERN_INFO "%s: warm reset timeout (GSR=%#lx)\n", 228057de50cSLuotao Fu __func__, gsr); 2299c636342SDmitry Baryshkov 2309c636342SDmitry Baryshkov return false; 2319c636342SDmitry Baryshkov } 2329c636342SDmitry Baryshkov 2339c636342SDmitry Baryshkov return true; 2349c636342SDmitry Baryshkov } 2359c636342SDmitry Baryshkov EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_warm_reset); 2369c636342SDmitry Baryshkov 2376f8acad6SRobert Jarzmik bool pxa2xx_ac97_try_cold_reset(void) 2389c636342SDmitry Baryshkov { 239057de50cSLuotao Fu unsigned long gsr; 240beb02cddSDmitry Eremin-Solenikov unsigned int timeout = 1000; 241057de50cSLuotao Fu 2429d1cf39bSDmitry Baryshkov #ifdef CONFIG_PXA25x 2438825e8e8SMarc Zyngier if (cpu_is_pxa25x()) 2449d1cf39bSDmitry Baryshkov pxa_ac97_cold_pxa25x(); 2459d1cf39bSDmitry Baryshkov else 2469c636342SDmitry Baryshkov #endif 2479c636342SDmitry Baryshkov #ifdef CONFIG_PXA27x 2489d1cf39bSDmitry Baryshkov if (cpu_is_pxa27x()) 2499d1cf39bSDmitry Baryshkov pxa_ac97_cold_pxa27x(); 2509d1cf39bSDmitry Baryshkov else 2519c636342SDmitry Baryshkov #endif 2529d1cf39bSDmitry Baryshkov #ifdef CONFIG_PXA3xx 2539d1cf39bSDmitry Baryshkov if (cpu_is_pxa3xx()) 2549d1cf39bSDmitry Baryshkov pxa_ac97_cold_pxa3xx(); 2559d1cf39bSDmitry Baryshkov else 2569d1cf39bSDmitry Baryshkov #endif 25788ec7ae8STakashi Iwai snd_BUG(); 2589c636342SDmitry Baryshkov 2598ff06452SArnd Bergmann while (!((readl(ac97_reg_base + GSR) | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--) 260beb02cddSDmitry Eremin-Solenikov mdelay(1); 261beb02cddSDmitry Eremin-Solenikov 2628ff06452SArnd Bergmann gsr = readl(ac97_reg_base + GSR) | gsr_bits; 263057de50cSLuotao Fu if (!(gsr & (GSR_PCR | GSR_SCR))) { 2649c636342SDmitry Baryshkov printk(KERN_INFO "%s: cold reset timeout (GSR=%#lx)\n", 265057de50cSLuotao Fu __func__, gsr); 2669c636342SDmitry Baryshkov 2679c636342SDmitry Baryshkov return false; 2689c636342SDmitry Baryshkov } 2699c636342SDmitry Baryshkov 2709c636342SDmitry Baryshkov return true; 2719c636342SDmitry Baryshkov } 2729c636342SDmitry Baryshkov EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_cold_reset); 2739c636342SDmitry Baryshkov 2749c636342SDmitry Baryshkov 2756f8acad6SRobert Jarzmik void pxa2xx_ac97_finish_reset(void) 2769c636342SDmitry Baryshkov { 2778ff06452SArnd Bergmann u32 gcr = readl(ac97_reg_base + GCR); 2788ff06452SArnd Bergmann gcr &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN); 2798ff06452SArnd Bergmann gcr |= GCR_SDONE_IE|GCR_CDONE_IE; 2808ff06452SArnd Bergmann writel(gcr, ac97_reg_base + GCR); 2819c636342SDmitry Baryshkov } 2829c636342SDmitry Baryshkov EXPORT_SYMBOL_GPL(pxa2xx_ac97_finish_reset); 2839c636342SDmitry Baryshkov 2849c636342SDmitry Baryshkov static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id) 2859c636342SDmitry Baryshkov { 2869c636342SDmitry Baryshkov long status; 2879c636342SDmitry Baryshkov 2888ff06452SArnd Bergmann status = readl(ac97_reg_base + GSR); 2899c636342SDmitry Baryshkov if (status) { 2908ff06452SArnd Bergmann writel(status, ac97_reg_base + GSR); 2919c636342SDmitry Baryshkov gsr_bits |= status; 2929c636342SDmitry Baryshkov wake_up(&gsr_wq); 2939c636342SDmitry Baryshkov 2949c636342SDmitry Baryshkov /* Although we don't use those we still need to clear them 2959c636342SDmitry Baryshkov since they tend to spuriously trigger when MMC is used 2969c636342SDmitry Baryshkov (hardware bug? go figure)... */ 2979d1cf39bSDmitry Baryshkov if (cpu_is_pxa27x()) { 2988ff06452SArnd Bergmann writel(MISR_EOC, ac97_reg_base + MISR); 2998ff06452SArnd Bergmann writel(PISR_EOC, ac97_reg_base + PISR); 3008ff06452SArnd Bergmann writel(MCSR_EOC, ac97_reg_base + MCSR); 3019d1cf39bSDmitry Baryshkov } 3029c636342SDmitry Baryshkov 3039c636342SDmitry Baryshkov return IRQ_HANDLED; 3049c636342SDmitry Baryshkov } 3059c636342SDmitry Baryshkov 3069c636342SDmitry Baryshkov return IRQ_NONE; 3079c636342SDmitry Baryshkov } 3089c636342SDmitry Baryshkov 3099c636342SDmitry Baryshkov #ifdef CONFIG_PM 3109c636342SDmitry Baryshkov int pxa2xx_ac97_hw_suspend(void) 3119c636342SDmitry Baryshkov { 3128ff06452SArnd Bergmann writel(readl(ac97_reg_base + GCR) | (GCR_ACLINK_OFF), ac97_reg_base + GCR); 3134091d342SRobert Jarzmik clk_disable_unprepare(ac97_clk); 3149c636342SDmitry Baryshkov return 0; 3159c636342SDmitry Baryshkov } 3169c636342SDmitry Baryshkov EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_suspend); 3179c636342SDmitry Baryshkov 3189c636342SDmitry Baryshkov int pxa2xx_ac97_hw_resume(void) 3199c636342SDmitry Baryshkov { 3204091d342SRobert Jarzmik clk_prepare_enable(ac97_clk); 3219c636342SDmitry Baryshkov return 0; 3229c636342SDmitry Baryshkov } 3239c636342SDmitry Baryshkov EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_resume); 3249c636342SDmitry Baryshkov #endif 3259c636342SDmitry Baryshkov 326e21596bbSBill Pemberton int pxa2xx_ac97_hw_probe(struct platform_device *dev) 3279c636342SDmitry Baryshkov { 3289c636342SDmitry Baryshkov int ret; 3292548e6c7SArnd Bergmann int irq; 330eae17754SMark Brown pxa2xx_audio_ops_t *pdata = dev->dev.platform_data; 33126ade896SRobert Jarzmik 3328ff06452SArnd Bergmann ac97_reg_base = devm_platform_ioremap_resource(dev, 0); 3338ff06452SArnd Bergmann if (IS_ERR(ac97_reg_base)) { 3348ff06452SArnd Bergmann dev_err(&dev->dev, "Missing MMIO resource\n"); 3358ff06452SArnd Bergmann return PTR_ERR(ac97_reg_base); 3368ff06452SArnd Bergmann } 3378ff06452SArnd Bergmann 33826ade896SRobert Jarzmik if (pdata) { 33926ade896SRobert Jarzmik switch (pdata->reset_gpio) { 34026ade896SRobert Jarzmik case 95: 34126ade896SRobert Jarzmik case 113: 34226ade896SRobert Jarzmik reset_gpio = pdata->reset_gpio; 34326ade896SRobert Jarzmik break; 34426ade896SRobert Jarzmik case 0: 34526ade896SRobert Jarzmik reset_gpio = 113; 34626ade896SRobert Jarzmik break; 34726ade896SRobert Jarzmik case -1: 34826ade896SRobert Jarzmik break; 34926ade896SRobert Jarzmik default: 3501f218695STakashi Iwai dev_err(&dev->dev, "Invalid reset GPIO %d\n", 35126ade896SRobert Jarzmik pdata->reset_gpio); 35226ade896SRobert Jarzmik } 353a4519526SRobert Jarzmik } else if (!pdata && dev->dev.of_node) { 354a4519526SRobert Jarzmik pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL); 355a4519526SRobert Jarzmik if (!pdata) 356a4519526SRobert Jarzmik return -ENOMEM; 357a4519526SRobert Jarzmik pdata->reset_gpio = of_get_named_gpio(dev->dev.of_node, 358a4519526SRobert Jarzmik "reset-gpios", 0); 359a4519526SRobert Jarzmik if (pdata->reset_gpio == -ENOENT) 360a4519526SRobert Jarzmik pdata->reset_gpio = -1; 361a4519526SRobert Jarzmik else if (pdata->reset_gpio < 0) 362a4519526SRobert Jarzmik return pdata->reset_gpio; 363a4519526SRobert Jarzmik reset_gpio = pdata->reset_gpio; 36426ade896SRobert Jarzmik } else { 36526ade896SRobert Jarzmik if (cpu_is_pxa27x()) 36626ade896SRobert Jarzmik reset_gpio = 113; 36726ade896SRobert Jarzmik } 3689c636342SDmitry Baryshkov 3699d1cf39bSDmitry Baryshkov if (cpu_is_pxa27x()) { 3703b4bc7bcSMike Dunn /* 3713b4bc7bcSMike Dunn * This gpio is needed for a work-around to a bug in the ac97 3723b4bc7bcSMike Dunn * controller during warm reset. The direction and level is set 3733b4bc7bcSMike Dunn * here so that it is an output driven high when switching from 3743b4bc7bcSMike Dunn * AC97_nRESET alt function to generic gpio. 3753b4bc7bcSMike Dunn */ 3763b4bc7bcSMike Dunn ret = gpio_request_one(reset_gpio, GPIOF_OUT_INIT_HIGH, 3773b4bc7bcSMike Dunn "pxa27x ac97 reset"); 3783b4bc7bcSMike Dunn if (ret < 0) { 3793b4bc7bcSMike Dunn pr_err("%s: gpio_request_one() failed: %d\n", 3803b4bc7bcSMike Dunn __func__, ret); 3813b4bc7bcSMike Dunn goto err_conf; 3823b4bc7bcSMike Dunn } 383053fe0f1SMike Dunn pxa27x_configure_ac97reset(reset_gpio, false); 3843b4bc7bcSMike Dunn 3859c636342SDmitry Baryshkov ac97conf_clk = clk_get(&dev->dev, "AC97CONFCLK"); 3869c636342SDmitry Baryshkov if (IS_ERR(ac97conf_clk)) { 3879c636342SDmitry Baryshkov ret = PTR_ERR(ac97conf_clk); 3889c636342SDmitry Baryshkov ac97conf_clk = NULL; 38979612336SDmitry Baryshkov goto err_conf; 3909c636342SDmitry Baryshkov } 3919d1cf39bSDmitry Baryshkov } 3929c636342SDmitry Baryshkov 3939c636342SDmitry Baryshkov ac97_clk = clk_get(&dev->dev, "AC97CLK"); 3949c636342SDmitry Baryshkov if (IS_ERR(ac97_clk)) { 3959c636342SDmitry Baryshkov ret = PTR_ERR(ac97_clk); 3969c636342SDmitry Baryshkov ac97_clk = NULL; 39779612336SDmitry Baryshkov goto err_clk; 3989c636342SDmitry Baryshkov } 3999c636342SDmitry Baryshkov 4004091d342SRobert Jarzmik ret = clk_prepare_enable(ac97_clk); 40179612336SDmitry Baryshkov if (ret) 40279612336SDmitry Baryshkov goto err_clk2; 40379612336SDmitry Baryshkov 4042548e6c7SArnd Bergmann irq = platform_get_irq(dev, 0); 405*46cf1954SYang Yingliang if (irq < 0) { 406*46cf1954SYang Yingliang ret = irq; 4072548e6c7SArnd Bergmann goto err_irq; 408*46cf1954SYang Yingliang } 4092548e6c7SArnd Bergmann 4102548e6c7SArnd Bergmann ret = request_irq(irq, pxa2xx_ac97_irq, 0, "AC97", NULL); 41179612336SDmitry Baryshkov if (ret < 0) 41279612336SDmitry Baryshkov goto err_irq; 41379612336SDmitry Baryshkov 41479612336SDmitry Baryshkov return 0; 4159c636342SDmitry Baryshkov 4169c636342SDmitry Baryshkov err_irq: 4178ff06452SArnd Bergmann writel(readl(ac97_reg_base + GCR) | (GCR_ACLINK_OFF), ac97_reg_base + GCR); 41879612336SDmitry Baryshkov err_clk2: 41979612336SDmitry Baryshkov clk_put(ac97_clk); 42079612336SDmitry Baryshkov ac97_clk = NULL; 42179612336SDmitry Baryshkov err_clk: 4229c636342SDmitry Baryshkov if (ac97conf_clk) { 4239c636342SDmitry Baryshkov clk_put(ac97conf_clk); 4249c636342SDmitry Baryshkov ac97conf_clk = NULL; 4259c636342SDmitry Baryshkov } 42679612336SDmitry Baryshkov err_conf: 4279c636342SDmitry Baryshkov return ret; 4289c636342SDmitry Baryshkov } 4299c636342SDmitry Baryshkov EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_probe); 4309c636342SDmitry Baryshkov 4319c636342SDmitry Baryshkov void pxa2xx_ac97_hw_remove(struct platform_device *dev) 4329c636342SDmitry Baryshkov { 4333b4bc7bcSMike Dunn if (cpu_is_pxa27x()) 4343b4bc7bcSMike Dunn gpio_free(reset_gpio); 4358ff06452SArnd Bergmann writel(readl(ac97_reg_base + GCR) | (GCR_ACLINK_OFF), ac97_reg_base + GCR); 4362548e6c7SArnd Bergmann free_irq(platform_get_irq(dev, 0), NULL); 4379d1cf39bSDmitry Baryshkov if (ac97conf_clk) { 4389c636342SDmitry Baryshkov clk_put(ac97conf_clk); 4399c636342SDmitry Baryshkov ac97conf_clk = NULL; 4409d1cf39bSDmitry Baryshkov } 4414091d342SRobert Jarzmik clk_disable_unprepare(ac97_clk); 4429c636342SDmitry Baryshkov clk_put(ac97_clk); 4439c636342SDmitry Baryshkov ac97_clk = NULL; 4449c636342SDmitry Baryshkov } 4459c636342SDmitry Baryshkov EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_remove); 4469c636342SDmitry Baryshkov 447e217b085SArnd Bergmann u32 pxa2xx_ac97_read_modr(void) 448e217b085SArnd Bergmann { 4498ff06452SArnd Bergmann if (!ac97_reg_base) 4508ff06452SArnd Bergmann return 0; 4518ff06452SArnd Bergmann 4528ff06452SArnd Bergmann return readl(ac97_reg_base + MODR); 453e217b085SArnd Bergmann } 454e217b085SArnd Bergmann EXPORT_SYMBOL_GPL(pxa2xx_ac97_read_modr); 455e217b085SArnd Bergmann 456e217b085SArnd Bergmann u32 pxa2xx_ac97_read_misr(void) 457e217b085SArnd Bergmann { 4588ff06452SArnd Bergmann if (!ac97_reg_base) 4598ff06452SArnd Bergmann return 0; 4608ff06452SArnd Bergmann 4618ff06452SArnd Bergmann return readl(ac97_reg_base + MISR); 462e217b085SArnd Bergmann } 463e217b085SArnd Bergmann EXPORT_SYMBOL_GPL(pxa2xx_ac97_read_misr); 464e217b085SArnd Bergmann 4659c636342SDmitry Baryshkov MODULE_AUTHOR("Nicolas Pitre"); 4669c636342SDmitry Baryshkov MODULE_DESCRIPTION("Intel/Marvell PXA sound library"); 4679c636342SDmitry Baryshkov MODULE_LICENSE("GPL"); 4689c636342SDmitry Baryshkov 469