drivers/platform/x86/intel/crystal_cove_charger.c

Source file repositories/reference/linux-study-clean/drivers/platform/x86/intel/crystal_cove_charger.c

File Facts

System
Linux kernel
Corpus path
drivers/platform/x86/intel/crystal_cove_charger.c
Extension
.c
Size
4536 bytes
Lines
154
Domain
Driver Families
Bucket
drivers/platform
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 crystal_cove_charger_data {
	struct mutex buslock; /* irq_bus_lock */
	struct irq_chip irqchip;
	struct regmap *regmap;
	struct irq_domain *irq_domain;
	int irq;
	int charger_irq;
	u8 mask;
	u8 new_mask;
};

static irqreturn_t crystal_cove_charger_irq(int irq, void *data)
{
	struct crystal_cove_charger_data *charger = data;

	/* No need to read CHGRIRQ_REG as there is only 1 IRQ */
	handle_nested_irq(charger->charger_irq);

	/* Ack CHGRIRQ 0 */
	regmap_write(charger->regmap, CHGRIRQ_REG, BIT(0));

	return IRQ_HANDLED;
}

static void crystal_cove_charger_irq_bus_lock(struct irq_data *data)
{
	struct crystal_cove_charger_data *charger = irq_data_get_irq_chip_data(data);

	mutex_lock(&charger->buslock);
}

static void crystal_cove_charger_irq_bus_sync_unlock(struct irq_data *data)
{
	struct crystal_cove_charger_data *charger = irq_data_get_irq_chip_data(data);

	if (charger->mask != charger->new_mask) {
		regmap_write(charger->regmap, MCHGRIRQ_REG, charger->new_mask);
		charger->mask = charger->new_mask;
	}

	mutex_unlock(&charger->buslock);
}

static void crystal_cove_charger_irq_unmask(struct irq_data *data)
{
	struct crystal_cove_charger_data *charger = irq_data_get_irq_chip_data(data);

	charger->new_mask &= ~BIT(data->hwirq);
}

static void crystal_cove_charger_irq_mask(struct irq_data *data)
{
	struct crystal_cove_charger_data *charger = irq_data_get_irq_chip_data(data);

	charger->new_mask |= BIT(data->hwirq);
}

static void crystal_cove_charger_rm_irq_domain(void *data)
{
	struct crystal_cove_charger_data *charger = data;

	irq_domain_remove(charger->irq_domain);
}

static int crystal_cove_charger_probe(struct platform_device *pdev)
{
	struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
	struct crystal_cove_charger_data *charger;
	int ret;

	charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL);
	if (!charger)
		return -ENOMEM;

	charger->regmap = pmic->regmap;
	mutex_init(&charger->buslock);

	charger->irq = platform_get_irq(pdev, 0);
	if (charger->irq < 0)
		return charger->irq;

	charger->irq_domain = irq_domain_create_linear(dev_fwnode(pdev->dev.parent), 1,
						       &irq_domain_simple_ops, NULL);
	if (!charger->irq_domain)
		return -ENOMEM;

	/* Distuingish IRQ domain from others sharing (MFD) the same fwnode */
	irq_domain_update_bus_token(charger->irq_domain, DOMAIN_BUS_WAKEUP);

	ret = devm_add_action_or_reset(&pdev->dev, crystal_cove_charger_rm_irq_domain, charger);

Annotation

Implementation Notes