drivers/mfd/iqs62x.c

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

File Facts

System
Linux kernel
Corpus path
drivers/mfd/iqs62x.c
Extension
.c
Size
27008 bytes
Lines
1080
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 iqs62x_fw_rec {
	u8 type;
	u8 addr;
	u8 len;
	u8 data;
} __packed;

struct iqs62x_fw_blk {
	struct list_head list;
	u8 addr;
	u8 mask;
	u8 len;
	u8 data[] __counted_by(len);
};

struct iqs62x_info {
	u8 prod_num;
	u8 sw_num;
	u8 hw_num;
} __packed;

static int iqs62x_dev_init(struct iqs62x_core *iqs62x)
{
	struct iqs62x_fw_blk *fw_blk;
	unsigned int val;
	int ret;

	list_for_each_entry(fw_blk, &iqs62x->fw_blk_head, list) {
		/*
		 * In case ATI is in progress, wait for it to complete before
		 * lowering the core clock frequency.
		 */
		if (fw_blk->addr == IQS62X_SYS_SETTINGS &&
		    *fw_blk->data & IQS62X_SYS_SETTINGS_CLK_DIV)
			msleep(IQS62X_ATI_STARTUP_MS);

		if (fw_blk->mask)
			ret = regmap_update_bits(iqs62x->regmap, fw_blk->addr,
						 fw_blk->mask, *fw_blk->data);
		else
			ret = regmap_raw_write(iqs62x->regmap, fw_blk->addr,
					       fw_blk->data, fw_blk->len);
		if (ret)
			return ret;
	}

	switch (iqs62x->dev_desc->prod_num) {
	case IQS620_PROD_NUM:
	case IQS622_PROD_NUM:
		ret = regmap_read(iqs62x->regmap,
				  iqs62x->dev_desc->prox_settings, &val);
		if (ret)
			return ret;

		if (val & IQS620_PROX_SETTINGS_4_SAR_EN)
			iqs62x->ui_sel = IQS62X_UI_SAR1;
		fallthrough;

	case IQS621_PROD_NUM:
		ret = regmap_write(iqs62x->regmap, IQS620_GLBL_EVENT_MASK,
				   IQS620_GLBL_EVENT_MASK_PMU |
				   iqs62x->dev_desc->prox_mask |
				   iqs62x->dev_desc->sar_mask |
				   iqs62x->dev_desc->hall_mask |
				   iqs62x->dev_desc->hyst_mask |
				   iqs62x->dev_desc->temp_mask |
				   iqs62x->dev_desc->als_mask |
				   iqs62x->dev_desc->ir_mask);
		if (ret)
			return ret;
		break;

	default:
		ret = regmap_write(iqs62x->regmap, IQS624_HALL_UI,
				   IQS624_HALL_UI_WHL_EVENT |
				   IQS624_HALL_UI_INT_EVENT |
				   IQS624_HALL_UI_AUTO_CAL);
		if (ret)
			return ret;

		/*
		 * The IQS625 default interval divider is below the minimum
		 * permissible value, and the datasheet mandates that it is
		 * corrected during initialization (unless an updated value
		 * has already been provided by firmware).
		 *
		 * To protect against an unacceptably low user-entered value
		 * stored in the firmware, the same check is extended to the
		 * IQS624 as well.
		 */

Annotation

Implementation Notes