drivers/input/misc/twl6040-vibra.c

Source file repositories/reference/linux-study-clean/drivers/input/misc/twl6040-vibra.c

File Facts

System
Linux kernel
Corpus path
drivers/input/misc/twl6040-vibra.c
Extension
.c
Size
9561 bytes
Lines
364
Domain
Driver Families
Bucket
drivers/input
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 vibra_info {
	struct device *dev;
	struct input_dev *input_dev;
	struct work_struct play_work;

	int irq;

	bool enabled;
	int weak_speed;
	int strong_speed;
	int direction;

	unsigned int vibldrv_res;
	unsigned int vibrdrv_res;
	unsigned int viblmotor_res;
	unsigned int vibrmotor_res;

	struct regulator_bulk_data supplies[TWL6040_NUM_SUPPLIES];

	struct twl6040 *twl6040;
};

static irqreturn_t twl6040_vib_irq_handler(int irq, void *data)
{
	struct vibra_info *info = data;
	struct twl6040 *twl6040 = info->twl6040;
	u8 status;

	status = twl6040_reg_read(twl6040, TWL6040_REG_STATUS);
	if (status & TWL6040_VIBLOCDET) {
		dev_warn(info->dev, "Left Vibrator overcurrent detected\n");
		twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLL,
				   TWL6040_VIBENA);
	}
	if (status & TWL6040_VIBROCDET) {
		dev_warn(info->dev, "Right Vibrator overcurrent detected\n");
		twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLR,
				   TWL6040_VIBENA);
	}

	return IRQ_HANDLED;
}

static void twl6040_vibra_enable(struct vibra_info *info)
{
	struct twl6040 *twl6040 = info->twl6040;
	int ret;

	ret = regulator_bulk_enable(ARRAY_SIZE(info->supplies), info->supplies);
	if (ret) {
		dev_err(info->dev, "failed to enable regulators %d\n", ret);
		return;
	}

	twl6040_power(info->twl6040, 1);
	if (twl6040_get_revid(twl6040) <= TWL6040_REV_ES1_1) {
		/*
		 * ERRATA: Disable overcurrent protection for at least
		 * 3ms when enabling vibrator drivers to avoid false
		 * overcurrent detection
		 */
		twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL,
				  TWL6040_VIBENA | TWL6040_VIBCTRL);
		twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR,
				  TWL6040_VIBENA | TWL6040_VIBCTRL);
		usleep_range(3000, 3500);
	}

	twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL,
			  TWL6040_VIBENA);
	twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR,
			  TWL6040_VIBENA);

	info->enabled = true;
}

static void twl6040_vibra_disable(struct vibra_info *info)
{
	struct twl6040 *twl6040 = info->twl6040;

	twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL, 0x00);
	twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR, 0x00);
	twl6040_power(info->twl6040, 0);

	regulator_bulk_disable(ARRAY_SIZE(info->supplies), info->supplies);

	info->enabled = false;
}

static u8 twl6040_vibra_code(int vddvib, int vibdrv_res, int motor_res,

Annotation

Implementation Notes