sound/soc/ti/omap-mcbsp.c

Source file repositories/reference/linux-study-clean/sound/soc/ti/omap-mcbsp.c

File Facts

System
Linux kernel
Corpus path
sound/soc/ti/omap-mcbsp.c
Extension
.c
Size
38635 bytes
Lines
1434
Domain
Driver Families
Bucket
sound/soc
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (!mcbsp->free) {
			dev_err(mcbsp->dev, "McBSP%d is currently in use\n", mcbsp->id);
			return -EBUSY;
		}

		mcbsp->free = false;
		mcbsp->reg_cache = reg_cache;
		reg_cache = NULL;
	}

	if (mcbsp->pdata->ops && mcbsp->pdata->ops->request)
		mcbsp->pdata->ops->request(mcbsp->id - 1);

	/*
	 * Make sure that transmitter, receiver and sample-rate generator are
	 * not running before activating IRQs.
	 */
	MCBSP_WRITE(mcbsp, SPCR1, 0);
	MCBSP_WRITE(mcbsp, SPCR2, 0);

	if (mcbsp->irq) {
		err = request_irq(mcbsp->irq, omap_mcbsp_irq_handler, 0,
				  "McBSP", (void *)mcbsp);
		if (err != 0) {
			dev_err(mcbsp->dev, "Unable to request IRQ\n");
		}
	} else {
		err = request_irq(mcbsp->tx_irq, omap_mcbsp_tx_irq_handler, 0,
				  "McBSP TX", (void *)mcbsp);
		if (err != 0) {
			dev_err(mcbsp->dev, "Unable to request TX IRQ\n");
		} else {
			err = request_irq(mcbsp->rx_irq, omap_mcbsp_rx_irq_handler, 0,
					  "McBSP RX", (void *)mcbsp);
			if (err != 0) {
				dev_err(mcbsp->dev, "Unable to request RX IRQ\n");
				free_irq(mcbsp->tx_irq, (void *)mcbsp);
			}
		}
	}

	if (err != 0) {
		if (mcbsp->pdata->ops && mcbsp->pdata->ops->free)
			mcbsp->pdata->ops->free(mcbsp->id - 1);

		/* Disable wakeup behavior */
		if (mcbsp->pdata->has_wakeup)
			MCBSP_WRITE(mcbsp, WAKEUPEN, 0);

		scoped_guard(spinlock, &mcbsp->lock) {
			reg_cache = mcbsp->reg_cache;
			mcbsp->free = true;
			mcbsp->reg_cache = NULL;
		}

		return err;
	}

	return 0;
}

static void omap_mcbsp_free(struct omap_mcbsp *mcbsp)
{
	void *reg_cache;

	if(mcbsp->pdata->ops && mcbsp->pdata->ops->free)
		mcbsp->pdata->ops->free(mcbsp->id - 1);

	/* Disable wakeup behavior */
	if (mcbsp->pdata->has_wakeup)
		MCBSP_WRITE(mcbsp, WAKEUPEN, 0);

	/* Disable interrupt requests */
	if (mcbsp->irq) {
		MCBSP_WRITE(mcbsp, IRQEN, 0);

		free_irq(mcbsp->irq, (void *)mcbsp);
	} else {
		free_irq(mcbsp->rx_irq, (void *)mcbsp);
		free_irq(mcbsp->tx_irq, (void *)mcbsp);
	}

	reg_cache = mcbsp->reg_cache;

	/*
	 * Select CLKS source from internal source unconditionally before
	 * marking the McBSP port as free.
	 * If the external clock source via MCBSP_CLKS pin has been selected the
	 * system will refuse to enter idle if the CLKS pin source is not reset
	 * back to internal source.

Annotation

Implementation Notes