drivers/cpufreq/brcmstb-avs-cpufreq.c

Source file repositories/reference/linux-study-clean/drivers/cpufreq/brcmstb-avs-cpufreq.c

File Facts

System
Linux kernel
Corpus path
drivers/cpufreq/brcmstb-avs-cpufreq.c
Extension
.c
Size
20670 bytes
Lines
784
Domain
Driver Families
Bucket
drivers/cpufreq
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

struct pmap {
	unsigned int mode;
	unsigned int p1;
	unsigned int p2;
	unsigned int state;
};

struct private_data {
	void __iomem *base;
	void __iomem *avs_intr_base;
	struct device *dev;
	struct completion done;
	struct semaphore sem;
	struct pmap pmap;
	int host_irq;
};

static void __iomem *__map_region(const char *name)
{
	struct device_node *np;
	void __iomem *ptr;

	np = of_find_compatible_node(NULL, NULL, name);
	if (!np)
		return NULL;

	ptr = of_iomap(np, 0);
	of_node_put(np);

	return ptr;
}

static unsigned long wait_for_avs_command(struct private_data *priv,
					  unsigned long timeout)
{
	unsigned long time_left = 0;
	u32 val;

	/* Event driven, wait for the command interrupt */
	if (priv->host_irq >= 0)
		return wait_for_completion_timeout(&priv->done,
						   msecs_to_jiffies(timeout));

	/* Polling for command completion */
	do {
		time_left = timeout;
		val = readl(priv->base + AVS_MBOX_STATUS);
		if (val)
			break;

		usleep_range(1000, 2000);
	} while (--timeout);

	return time_left;
}

static int __issue_avs_command(struct private_data *priv, unsigned int cmd,
			       unsigned int num_in, unsigned int num_out,
			       u32 args[])
{
	void __iomem *base = priv->base;
	unsigned long time_left;
	unsigned int i;
	int ret;
	u32 val;

	ret = down_interruptible(&priv->sem);
	if (ret)
		return ret;

	/*
	 * Make sure no other command is currently running: cmd is 0 if AVS
	 * co-processor is idle. Due to the guard above, we should almost never
	 * have to wait here.
	 */
	for (i = 0, val = 1; val != 0 && i < AVS_LOOP_LIMIT; i++)
		val = readl(base + AVS_MBOX_COMMAND);

	/* Give the caller a chance to retry if AVS is busy. */
	if (i == AVS_LOOP_LIMIT) {
		ret = -EAGAIN;
		goto out;
	}

	/* Clear status before we begin. */
	writel(AVS_STATUS_CLEAR, base + AVS_MBOX_STATUS);

	/* Provide input parameters */
	for (i = 0; i < num_in; i++)
		writel(args[i], base + AVS_MBOX_PARAM(i));

Annotation

Implementation Notes