drivers/mfd/cs40l50-core.c

Source file repositories/reference/linux-study-clean/drivers/mfd/cs40l50-core.c

File Facts

System
Linux kernel
Corpus path
drivers/mfd/cs40l50-core.c
Extension
.c
Size
14994 bytes
Lines
570
Domain
Driver Families
Bucket
drivers/mfd
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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 cs40l50_irq {
	const char *name;
	int virq;
};

static struct cs40l50_irq cs40l50_irqs[] = {
	{ "DSP", },
	{ "Global", },
	{ "Boost UVLO", },
	{ "Boost current limit", },
	{ "Boost short", },
	{ "Boost undervolt", },
	{ "Overtemp", },
	{ "Amp short", },
};

static const struct reg_sequence cs40l50_err_rls[] = {
	{ CS40L50_ERR_RLS, CS40L50_GLOBAL_ERR_RLS_SET },
	{ CS40L50_ERR_RLS, CS40L50_GLOBAL_ERR_RLS_CLEAR },
};

static irqreturn_t cs40l50_hw_err(int irq, void *data)
{
	struct cs40l50 *cs40l50 = data;
	int ret = 0, i;

	mutex_lock(&cs40l50->lock);

	/* Log hardware interrupt and execute error release sequence */
	for (i = 1; i < ARRAY_SIZE(cs40l50_irqs); i++) {
		if (cs40l50_irqs[i].virq == irq) {
			dev_err(cs40l50->dev, "%s error\n", cs40l50_irqs[i].name);
			ret = regmap_multi_reg_write(cs40l50->regmap, cs40l50_err_rls,
						     ARRAY_SIZE(cs40l50_err_rls));
			break;
		}
	}

	mutex_unlock(&cs40l50->lock);
	return IRQ_RETVAL(!ret);
}

static irqreturn_t cs40l50_dsp_queue(int irq, void *data)
{
	struct cs40l50 *cs40l50 = data;
	u32 rd_ptr, val, wt_ptr;
	int ret = 0;

	mutex_lock(&cs40l50->lock);

	/* Read from DSP queue, log, and update read pointer */
	while (!ret) {
		ret = regmap_read(cs40l50->regmap, CS40L50_DSP_QUEUE_WT, &wt_ptr);
		if (ret)
			break;

		ret = regmap_read(cs40l50->regmap, CS40L50_DSP_QUEUE_RD, &rd_ptr);
		if (ret)
			break;

		/* Check if queue is empty */
		if (wt_ptr == rd_ptr)
			break;

		ret = regmap_read(cs40l50->regmap, rd_ptr, &val);
		if (ret)
			break;

		dev_dbg(cs40l50->dev, "DSP payload: %#X", val);

		rd_ptr += sizeof(u32);

		if (rd_ptr > CS40L50_DSP_QUEUE_END)
			rd_ptr = CS40L50_DSP_QUEUE_BASE;

		ret = regmap_write(cs40l50->regmap, CS40L50_DSP_QUEUE_RD, rd_ptr);
	}

	mutex_unlock(&cs40l50->lock);

	return IRQ_RETVAL(!ret);
}

static int cs40l50_irq_init(struct cs40l50 *cs40l50)
{
	int ret, i, virq;

	ret = devm_regmap_add_irq_chip(cs40l50->dev, cs40l50->regmap, cs40l50->irq,
				       IRQF_ONESHOT | IRQF_SHARED, 0,
				       &cs40l50_irq_chip, &cs40l50->irq_data);

Annotation

Implementation Notes