// SPDX-License-Identifier: GPL-2.0-only /* * Based on sound/arm/pxa2xx-ac97.c and sound/soc/pxa/pxa2xx-ac97.c * which contain: * * Author: Nicolas Pitre * Created: Dec 02, 2004 * Copyright: MontaVista Software Inc.
*/
/* * Beware PXA27x bugs: * * o Slot 12 read from modem space will hang controller. * o CDONE, SDONE interrupt fails after any slot 12 IO. * * We therefore have an hybrid approach for waiting on SDONE (interrupt or * 1 jiffy timeout if interrupt never comes).
*/
int pxa2xx_ac97_read(int slot, unsignedshort reg)
{ int val = -ENODEV;
u32 __iomem *reg_addr;
if (slot > 0) return -ENODEV;
mutex_lock(&car_mutex);
/* set up primary or secondary codec space */ if (cpu_is_pxa25x() && reg == AC97_GPIO_STATUS)
reg_addr = ac97_reg_base +
(slot ? SMC_REG_BASE : PMC_REG_BASE); else
reg_addr = ac97_reg_base +
(slot ? SAC_REG_BASE : PAC_REG_BASE);
reg_addr += (reg >> 1);
/* start read access across the ac97 link */
writel(GSR_CDONE | GSR_SDONE, ac97_reg_base + GSR);
gsr_bits = 0;
val = (readl(reg_addr) & 0xffff); if (reg == AC97_GPIO_STATUS) goto out; if (wait_event_timeout(gsr_wq, (readl(ac97_reg_base + GSR) | gsr_bits) & GSR_SDONE, 1) <= 0 &&
!((readl(ac97_reg_base + GSR) | gsr_bits) & GSR_SDONE)) {
printk(KERN_ERR "%s: read error (ac97_reg=%d GSR=%#lx)\n",
__func__, reg, readl(ac97_reg_base + GSR) | gsr_bits);
val = -ETIMEDOUT; goto out;
}
/* valid data now */
writel(GSR_CDONE | GSR_SDONE, ac97_reg_base + GSR);
gsr_bits = 0;
val = (readl(reg_addr) & 0xffff); /* but we've just started another cycle... */
wait_event_timeout(gsr_wq, (readl(ac97_reg_base + GSR) | gsr_bits) & GSR_SDONE, 1);
static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id)
{ long status;
status = readl(ac97_reg_base + GSR); if (status) {
writel(status, ac97_reg_base + GSR);
gsr_bits |= status;
wake_up(&gsr_wq);
/* Although we don't use those we still need to clear them since they tend to spuriously trigger when MMC is used
(hardware bug? go figure)... */ if (cpu_is_pxa27x()) {
writel(MISR_EOC, ac97_reg_base + MISR);
writel(PISR_EOC, ac97_reg_base + PISR);
writel(MCSR_EOC, ac97_reg_base + MCSR);
}
if (pdata) { switch (pdata->reset_gpio) { case 95: case 113:
reset_gpio = pdata->reset_gpio; break; case 0:
reset_gpio = 113; break; case -1: break; default:
dev_err(&dev->dev, "Invalid reset GPIO %d\n",
pdata->reset_gpio);
}
} elseif (!pdata && dev->dev.of_node) {
pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM;
pdata->reset_gpio = of_get_named_gpio(dev->dev.of_node, "reset-gpios", 0); if (pdata->reset_gpio == -ENOENT)
pdata->reset_gpio = -1; elseif (pdata->reset_gpio < 0) return pdata->reset_gpio;
reset_gpio = pdata->reset_gpio;
} else { if (cpu_is_pxa27x())
reset_gpio = 113;
}
if (cpu_is_pxa27x()) { /* * This gpio is needed for a work-around to a bug in the ac97 * controller during warm reset. The direction and level is set * here so that it is an output driven high when switching from * AC97_nRESET alt function to generic gpio.
*/
ret = gpio_request_one(reset_gpio, GPIOF_OUT_INIT_HIGH, "pxa27x ac97 reset"); if (ret < 0) {
pr_err("%s: gpio_request_one() failed: %d\n",
__func__, ret); goto err_conf;
}
pxa27x_configure_ac97reset(reset_gpio, false);
ac97conf_clk = clk_get(&dev->dev, "AC97CONFCLK"); if (IS_ERR(ac97conf_clk)) {
ret = PTR_ERR(ac97conf_clk);
ac97conf_clk = NULL; goto err_conf;
}
}
ac97_clk = clk_get(&dev->dev, "AC97CLK"); if (IS_ERR(ac97_clk)) {
ret = PTR_ERR(ac97_clk);
ac97_clk = NULL; goto err_clk;
}
ret = clk_prepare_enable(ac97_clk); if (ret) goto err_clk2;
irq = platform_get_irq(dev, 0); if (irq < 0) {
ret = irq; goto err_irq;
}
ret = request_irq(irq, pxa2xx_ac97_irq, 0, "AC97", NULL); if (ret < 0) goto err_irq;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.