drivers/input/misc/drv260x.c

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

File Facts

System
Linux kernel
Corpus path
drivers/input/misc/drv260x.c
Extension
.c
Size
18882 bytes
Lines
673
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 drv260x_data {
	struct input_dev *input_dev;
	struct i2c_client *client;
	struct regmap *regmap;
	struct work_struct work;
	struct gpio_desc *enable_gpio;
	struct regulator *regulator;
	u8 magnitude;
	u32 mode;
	u32 library;
	int rated_voltage;
	int overdrive_voltage;
};

#define DRV260X_DEF_RATED_VOLT		0x90
#define DRV260X_DEF_OD_CLAMP_VOLT	0x90

/*
 * Rated and Overdriver Voltages:
 * Calculated using the formula r = v * 255 / 5.6
 * where r is what will be written to the register
 * and v is the rated or overdriver voltage of the actuator
 */
static int drv260x_calculate_voltage(unsigned int voltage)
{
	return (voltage * 255 / 5600);
}

static void drv260x_worker(struct work_struct *work)
{
	struct drv260x_data *haptics = container_of(work, struct drv260x_data, work);
	int error;

	gpiod_set_value(haptics->enable_gpio, 1);
	/* Data sheet says to wait 250us before trying to communicate */
	udelay(250);

	error = regmap_write(haptics->regmap,
			     DRV260X_MODE, DRV260X_RT_PLAYBACK);
	if (error) {
		dev_err(&haptics->client->dev,
			"Failed to write set mode: %d\n", error);
	} else {
		error = regmap_write(haptics->regmap,
				     DRV260X_RT_PB_IN, haptics->magnitude);
		if (error)
			dev_err(&haptics->client->dev,
				"Failed to set magnitude: %d\n", error);
	}
}

static int drv260x_haptics_play(struct input_dev *input, void *data,
				struct ff_effect *effect)
{
	struct drv260x_data *haptics = input_get_drvdata(input);

	haptics->mode = DRV260X_LRA_NO_CAL_MODE;

	/* Scale u16 magnitude into u8 register value */
	if (effect->u.rumble.strong_magnitude > 0)
		haptics->magnitude = effect->u.rumble.strong_magnitude >> 8;
	else if (effect->u.rumble.weak_magnitude > 0)
		haptics->magnitude = effect->u.rumble.weak_magnitude >> 8;
	else
		haptics->magnitude = 0;

	schedule_work(&haptics->work);

	return 0;
}

static void drv260x_close(struct input_dev *input)
{
	struct drv260x_data *haptics = input_get_drvdata(input);
	int error;

	cancel_work_sync(&haptics->work);

	error = regmap_write(haptics->regmap, DRV260X_MODE, DRV260X_STANDBY);
	if (error)
		dev_err(&haptics->client->dev,
			"Failed to enter standby mode: %d\n", error);

	gpiod_set_value(haptics->enable_gpio, 0);
}

static const struct reg_sequence drv260x_lra_cal_regs[] = {
	{ DRV260X_MODE, DRV260X_AUTO_CAL },
	{ DRV260X_CTRL3, DRV260X_NG_THRESH_2 | DRV260X_RTP_UNSIGNED_DATA },
	{ DRV260X_FEEDBACK_CTRL, DRV260X_FB_REG_LRA_MODE |

Annotation

Implementation Notes