drivers/input/misc/sc27xx-vibra.c

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

File Facts

System
Linux kernel
Corpus path
drivers/input/misc/sc27xx-vibra.c
Extension
.c
Size
5150 bytes
Lines
202
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 sc27xx_vibra_data {
	u32 cur_drv_cal_sel;
	u32 slp_pd_en;
	u32 ldo_pd;
};

struct vibra_info {
	struct input_dev	*input_dev;
	struct work_struct	play_work;
	struct regmap		*regmap;
	const struct sc27xx_vibra_data *data;
	u32			base;
	u32			strength;
	bool			enabled;
};

static const struct sc27xx_vibra_data sc2731_data = {
	.cur_drv_cal_sel = CUR_DRV_CAL_SEL,
	.slp_pd_en = SLP_LDOVIBR_PD_EN,
	.ldo_pd = LDO_VIBR_PD,
};

static const struct sc27xx_vibra_data sc2730_data = {
	.cur_drv_cal_sel = SC2730_CUR_DRV_CAL_SEL,
	.slp_pd_en = SC2730_SLP_LDOVIBR_PD_EN,
	.ldo_pd = SC2730_LDO_VIBR_PD,
};

static const struct sc27xx_vibra_data sc2721_data = {
	.cur_drv_cal_sel = CUR_DRV_CAL_SEL,
	.slp_pd_en = SLP_LDOVIBR_PD_EN,
	.ldo_pd = LDO_VIBR_PD,
};

static void sc27xx_vibra_set(struct vibra_info *info, bool on)
{
	const struct sc27xx_vibra_data *data = info->data;
	if (on) {
		regmap_update_bits(info->regmap, info->base, data->ldo_pd, 0);
		regmap_update_bits(info->regmap, info->base,
				   data->slp_pd_en, 0);
		info->enabled = true;
	} else {
		regmap_update_bits(info->regmap, info->base, data->ldo_pd,
				   data->ldo_pd);
		regmap_update_bits(info->regmap, info->base,
				   data->slp_pd_en, data->slp_pd_en);
		info->enabled = false;
	}
}

static int sc27xx_vibra_hw_init(struct vibra_info *info)
{
	const struct sc27xx_vibra_data *data = info->data;

	if (!data->cur_drv_cal_sel)
		return 0;

	return regmap_update_bits(info->regmap, info->base,
				  data->cur_drv_cal_sel, 0);
}

static void sc27xx_vibra_play_work(struct work_struct *work)
{
	struct vibra_info *info = container_of(work, struct vibra_info,
					       play_work);

	if (info->strength && !info->enabled)
		sc27xx_vibra_set(info, true);
	else if (info->strength == 0 && info->enabled)
		sc27xx_vibra_set(info, false);
}

static int sc27xx_vibra_play(struct input_dev *input, void *data,
			     struct ff_effect *effect)
{
	struct vibra_info *info = input_get_drvdata(input);

	info->strength = effect->u.rumble.weak_magnitude;
	schedule_work(&info->play_work);

	return 0;
}

static void sc27xx_vibra_close(struct input_dev *input)
{
	struct vibra_info *info = input_get_drvdata(input);

	cancel_work_sync(&info->play_work);
	if (info->enabled)

Annotation

Implementation Notes