brintos

brintos / linux-shallow public Read only

0
0
Text · 10.9 KiB · a03a329 Raw
467 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Based on sound/arm/pxa2xx-ac97.c and sound/soc/pxa/pxa2xx-ac97.c4 * which contain:5 *6 * Author:	Nicolas Pitre7 * Created:	Dec 02, 20048 * Copyright:	MontaVista Software Inc.9 */10 11#include <linux/kernel.h>12#include <linux/platform_device.h>13#include <linux/interrupt.h>14#include <linux/clk.h>15#include <linux/delay.h>16#include <linux/module.h>17#include <linux/io.h>18#include <linux/gpio.h>19#include <linux/of_gpio.h>20#include <linux/soc/pxa/cpu.h>21 22#include <sound/pxa2xx-lib.h>23 24#include <linux/platform_data/asoc-pxa.h>25 26#include "pxa2xx-ac97-regs.h"27 28static DEFINE_MUTEX(car_mutex);29static DECLARE_WAIT_QUEUE_HEAD(gsr_wq);30static volatile long gsr_bits;31static struct clk *ac97_clk;32static struct clk *ac97conf_clk;33static int reset_gpio;34static void __iomem *ac97_reg_base;35 36/*37 * Beware PXA27x bugs:38 *39 *   o Slot 12 read from modem space will hang controller.40 *   o CDONE, SDONE interrupt fails after any slot 12 IO.41 *42 * We therefore have an hybrid approach for waiting on SDONE (interrupt or43 * 1 jiffy timeout if interrupt never comes).44 */45 46int pxa2xx_ac97_read(int slot, unsigned short reg)47{48	int val = -ENODEV;49	u32 __iomem *reg_addr;50 51	if (slot > 0)52		return -ENODEV;53 54	mutex_lock(&car_mutex);55 56	/* set up primary or secondary codec space */57	if (cpu_is_pxa25x() && reg == AC97_GPIO_STATUS)58		reg_addr = ac97_reg_base +59			   (slot ? SMC_REG_BASE : PMC_REG_BASE);60	else61		reg_addr = ac97_reg_base +62			   (slot ? SAC_REG_BASE : PAC_REG_BASE);63	reg_addr += (reg >> 1);64 65	/* start read access across the ac97 link */66	writel(GSR_CDONE | GSR_SDONE, ac97_reg_base + GSR);67	gsr_bits = 0;68	val = (readl(reg_addr) & 0xffff);69	if (reg == AC97_GPIO_STATUS)70		goto out;71	if (wait_event_timeout(gsr_wq, (readl(ac97_reg_base + GSR) | gsr_bits) & GSR_SDONE, 1) <= 0 &&72	    !((readl(ac97_reg_base + GSR) | gsr_bits) & GSR_SDONE)) {73		printk(KERN_ERR "%s: read error (ac97_reg=%d GSR=%#lx)\n",74				__func__, reg, readl(ac97_reg_base + GSR) | gsr_bits);75		val = -ETIMEDOUT;76		goto out;77	}78 79	/* valid data now */80	writel(GSR_CDONE | GSR_SDONE, ac97_reg_base + GSR);81	gsr_bits = 0;82	val = (readl(reg_addr) & 0xffff);83	/* but we've just started another cycle... */84	wait_event_timeout(gsr_wq, (readl(ac97_reg_base + GSR) | gsr_bits) & GSR_SDONE, 1);85 86out:	mutex_unlock(&car_mutex);87	return val;88}89EXPORT_SYMBOL_GPL(pxa2xx_ac97_read);90 91int pxa2xx_ac97_write(int slot, unsigned short reg, unsigned short val)92{93	u32 __iomem *reg_addr;94	int ret = 0;95 96	mutex_lock(&car_mutex);97 98	/* set up primary or secondary codec space */99	if (cpu_is_pxa25x() && reg == AC97_GPIO_STATUS)100		reg_addr = ac97_reg_base +101			   (slot ? SMC_REG_BASE : PMC_REG_BASE);102	else103		reg_addr = ac97_reg_base +104			   (slot ? SAC_REG_BASE : PAC_REG_BASE);105	reg_addr += (reg >> 1);106 107	writel(GSR_CDONE | GSR_SDONE, ac97_reg_base + GSR);108	gsr_bits = 0;109	writel(val, reg_addr);110	if (wait_event_timeout(gsr_wq, (readl(ac97_reg_base + GSR) | gsr_bits) & GSR_CDONE, 1) <= 0 &&111	    !((readl(ac97_reg_base + GSR) | gsr_bits) & GSR_CDONE)) {112		printk(KERN_ERR "%s: write error (ac97_reg=%d GSR=%#lx)\n",113				__func__, reg, readl(ac97_reg_base + GSR) | gsr_bits);114		ret = -EIO;115	}116 117	mutex_unlock(&car_mutex);118	return ret;119}120EXPORT_SYMBOL_GPL(pxa2xx_ac97_write);121 122#ifdef CONFIG_PXA25x123static inline void pxa_ac97_warm_pxa25x(void)124{125	gsr_bits = 0;126 127	writel(readl(ac97_reg_base + GCR) | (GCR_WARM_RST), ac97_reg_base + GCR);128}129 130static inline void pxa_ac97_cold_pxa25x(void)131{132	writel(readl(ac97_reg_base + GCR) & ( GCR_COLD_RST), ac97_reg_base + GCR);  /* clear everything but nCRST */133	writel(readl(ac97_reg_base + GCR) & (~GCR_COLD_RST), ac97_reg_base + GCR);  /* then assert nCRST */134 135	gsr_bits = 0;136 137	writel(GCR_COLD_RST, ac97_reg_base + GCR);138}139#endif140 141#ifdef CONFIG_PXA27x142static inline void pxa_ac97_warm_pxa27x(void)143{144	gsr_bits = 0;145 146	/* warm reset broken on Bulverde, so manually keep AC97 reset high */147	pxa27x_configure_ac97reset(reset_gpio, true);148	udelay(10);149	writel(readl(ac97_reg_base + GCR) | (GCR_WARM_RST), ac97_reg_base + GCR);150	pxa27x_configure_ac97reset(reset_gpio, false);151	udelay(500);152}153 154static inline void pxa_ac97_cold_pxa27x(void)155{156	writel(readl(ac97_reg_base + GCR) & ( GCR_COLD_RST), ac97_reg_base + GCR);  /* clear everything but nCRST */157	writel(readl(ac97_reg_base + GCR) & (~GCR_COLD_RST), ac97_reg_base + GCR);  /* then assert nCRST */158 159	gsr_bits = 0;160 161	/* PXA27x Developers Manual section 13.5.2.2.1 */162	clk_prepare_enable(ac97conf_clk);163	udelay(5);164	clk_disable_unprepare(ac97conf_clk);165	writel(GCR_COLD_RST | GCR_WARM_RST, ac97_reg_base + GCR);166}167#endif168 169#ifdef CONFIG_PXA3xx170static inline void pxa_ac97_warm_pxa3xx(void)171{172	gsr_bits = 0;173 174	/* Can't use interrupts */175	writel(readl(ac97_reg_base + GCR) | (GCR_WARM_RST), ac97_reg_base + GCR);176}177 178static inline void pxa_ac97_cold_pxa3xx(void)179{180	/* Hold CLKBPB for 100us */181	writel(0, ac97_reg_base + GCR);182	writel(GCR_CLKBPB, ac97_reg_base + GCR);183	udelay(100);184	writel(0, ac97_reg_base + GCR);185 186	writel(readl(ac97_reg_base + GCR) & ( GCR_COLD_RST), ac97_reg_base + GCR);  /* clear everything but nCRST */187	writel(readl(ac97_reg_base + GCR) & (~GCR_COLD_RST), ac97_reg_base + GCR);  /* then assert nCRST */188 189	gsr_bits = 0;190 191	/* Can't use interrupts on PXA3xx */192	writel(readl(ac97_reg_base + GCR) & (~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN)), ac97_reg_base + GCR);193 194	writel(GCR_WARM_RST | GCR_COLD_RST, ac97_reg_base + GCR);195}196#endif197 198bool pxa2xx_ac97_try_warm_reset(void)199{200	unsigned long gsr;201	unsigned int timeout = 100;202 203#ifdef CONFIG_PXA25x204	if (cpu_is_pxa25x())205		pxa_ac97_warm_pxa25x();206	else207#endif208#ifdef CONFIG_PXA27x209	if (cpu_is_pxa27x())210		pxa_ac97_warm_pxa27x();211	else212#endif213#ifdef CONFIG_PXA3xx214	if (cpu_is_pxa3xx())215		pxa_ac97_warm_pxa3xx();216	else217#endif218		snd_BUG();219 220	while (!((readl(ac97_reg_base + GSR) | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--)221		mdelay(1);222 223	gsr = readl(ac97_reg_base + GSR) | gsr_bits;224	if (!(gsr & (GSR_PCR | GSR_SCR))) {225		printk(KERN_INFO "%s: warm reset timeout (GSR=%#lx)\n",226				 __func__, gsr);227 228		return false;229	}230 231	return true;232}233EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_warm_reset);234 235bool pxa2xx_ac97_try_cold_reset(void)236{237	unsigned long gsr;238	unsigned int timeout = 1000;239 240#ifdef CONFIG_PXA25x241	if (cpu_is_pxa25x())242		pxa_ac97_cold_pxa25x();243	else244#endif245#ifdef CONFIG_PXA27x246	if (cpu_is_pxa27x())247		pxa_ac97_cold_pxa27x();248	else249#endif250#ifdef CONFIG_PXA3xx251	if (cpu_is_pxa3xx())252		pxa_ac97_cold_pxa3xx();253	else254#endif255		snd_BUG();256 257	while (!((readl(ac97_reg_base + GSR) | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--)258		mdelay(1);259 260	gsr = readl(ac97_reg_base + GSR) | gsr_bits;261	if (!(gsr & (GSR_PCR | GSR_SCR))) {262		printk(KERN_INFO "%s: cold reset timeout (GSR=%#lx)\n",263				 __func__, gsr);264 265		return false;266	}267 268	return true;269}270EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_cold_reset);271 272 273void pxa2xx_ac97_finish_reset(void)274{275	u32 gcr = readl(ac97_reg_base + GCR);276	gcr &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);277	gcr |= GCR_SDONE_IE|GCR_CDONE_IE;278	writel(gcr, ac97_reg_base + GCR);279}280EXPORT_SYMBOL_GPL(pxa2xx_ac97_finish_reset);281 282static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id)283{284	long status;285 286	status = readl(ac97_reg_base + GSR);287	if (status) {288		writel(status, ac97_reg_base + GSR);289		gsr_bits |= status;290		wake_up(&gsr_wq);291 292		/* Although we don't use those we still need to clear them293		   since they tend to spuriously trigger when MMC is used294		   (hardware bug? go figure)... */295		if (cpu_is_pxa27x()) {296			writel(MISR_EOC, ac97_reg_base + MISR);297			writel(PISR_EOC, ac97_reg_base + PISR);298			writel(MCSR_EOC, ac97_reg_base + MCSR);299		}300 301		return IRQ_HANDLED;302	}303 304	return IRQ_NONE;305}306 307#ifdef CONFIG_PM308int pxa2xx_ac97_hw_suspend(void)309{310	writel(readl(ac97_reg_base + GCR) | (GCR_ACLINK_OFF), ac97_reg_base + GCR);311	clk_disable_unprepare(ac97_clk);312	return 0;313}314EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_suspend);315 316int pxa2xx_ac97_hw_resume(void)317{318	clk_prepare_enable(ac97_clk);319	return 0;320}321EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_resume);322#endif323 324int pxa2xx_ac97_hw_probe(struct platform_device *dev)325{326	int ret;327	int irq;328	pxa2xx_audio_ops_t *pdata = dev->dev.platform_data;329 330	ac97_reg_base = devm_platform_ioremap_resource(dev, 0);331	if (IS_ERR(ac97_reg_base)) {332		dev_err(&dev->dev, "Missing MMIO resource\n");333		return PTR_ERR(ac97_reg_base);334	}335 336	if (pdata) {337		switch (pdata->reset_gpio) {338		case 95:339		case 113:340			reset_gpio = pdata->reset_gpio;341			break;342		case 0:343			reset_gpio = 113;344			break;345		case -1:346			break;347		default:348			dev_err(&dev->dev, "Invalid reset GPIO %d\n",349				pdata->reset_gpio);350		}351	} else if (!pdata && dev->dev.of_node) {352		pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL);353		if (!pdata)354			return -ENOMEM;355		pdata->reset_gpio = of_get_named_gpio(dev->dev.of_node,356						      "reset-gpios", 0);357		if (pdata->reset_gpio == -ENOENT)358			pdata->reset_gpio = -1;359		else if (pdata->reset_gpio < 0)360			return pdata->reset_gpio;361		reset_gpio = pdata->reset_gpio;362	} else {363		if (cpu_is_pxa27x())364			reset_gpio = 113;365	}366 367	if (cpu_is_pxa27x()) {368		/*369		 * This gpio is needed for a work-around to a bug in the ac97370		 * controller during warm reset.  The direction and level is set371		 * here so that it is an output driven high when switching from372		 * AC97_nRESET alt function to generic gpio.373		 */374		ret = gpio_request_one(reset_gpio, GPIOF_OUT_INIT_HIGH,375				       "pxa27x ac97 reset");376		if (ret < 0) {377			pr_err("%s: gpio_request_one() failed: %d\n",378			       __func__, ret);379			goto err_conf;380		}381		pxa27x_configure_ac97reset(reset_gpio, false);382 383		ac97conf_clk = clk_get(&dev->dev, "AC97CONFCLK");384		if (IS_ERR(ac97conf_clk)) {385			ret = PTR_ERR(ac97conf_clk);386			ac97conf_clk = NULL;387			goto err_conf;388		}389	}390 391	ac97_clk = clk_get(&dev->dev, "AC97CLK");392	if (IS_ERR(ac97_clk)) {393		ret = PTR_ERR(ac97_clk);394		ac97_clk = NULL;395		goto err_clk;396	}397 398	ret = clk_prepare_enable(ac97_clk);399	if (ret)400		goto err_clk2;401 402	irq = platform_get_irq(dev, 0);403	if (irq < 0) {404		ret = irq;405		goto err_irq;406	}407 408	ret = request_irq(irq, pxa2xx_ac97_irq, 0, "AC97", NULL);409	if (ret < 0)410		goto err_irq;411 412	return 0;413 414err_irq:415	writel(readl(ac97_reg_base + GCR) | (GCR_ACLINK_OFF), ac97_reg_base + GCR);416err_clk2:417	clk_put(ac97_clk);418	ac97_clk = NULL;419err_clk:420	if (ac97conf_clk) {421		clk_put(ac97conf_clk);422		ac97conf_clk = NULL;423	}424err_conf:425	return ret;426}427EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_probe);428 429void pxa2xx_ac97_hw_remove(struct platform_device *dev)430{431	if (cpu_is_pxa27x())432		gpio_free(reset_gpio);433	writel(readl(ac97_reg_base + GCR) | (GCR_ACLINK_OFF), ac97_reg_base + GCR);434	free_irq(platform_get_irq(dev, 0), NULL);435	if (ac97conf_clk) {436		clk_put(ac97conf_clk);437		ac97conf_clk = NULL;438	}439	clk_disable_unprepare(ac97_clk);440	clk_put(ac97_clk);441	ac97_clk = NULL;442}443EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_remove);444 445u32 pxa2xx_ac97_read_modr(void)446{447	if (!ac97_reg_base)448		return 0;449 450	return readl(ac97_reg_base + MODR);451}452EXPORT_SYMBOL_GPL(pxa2xx_ac97_read_modr);453 454u32 pxa2xx_ac97_read_misr(void)455{456	if (!ac97_reg_base)457		return 0;458 459	return readl(ac97_reg_base + MISR);460}461EXPORT_SYMBOL_GPL(pxa2xx_ac97_read_misr);462 463MODULE_AUTHOR("Nicolas Pitre");464MODULE_DESCRIPTION("Intel/Marvell PXA sound library");465MODULE_LICENSE("GPL");466 467