/** * struct pm8xxx_vib - structure to hold vibrator data * @vib_input_dev: input device supporting force feedback * @work: work structure to set the vibration parameters * @regmap: regmap for register read/write * @regs: registers' info * @enable_addr: vibrator enable register * @drv_addr: vibrator drive strength register * @drv2_addr: vibrator drive strength upper byte register * @speed: speed of vibration set from userland * @active: state of vibrator * @level: level of vibration to set in the chip * @reg_vib_drv: regs->drv_addr register value
*/ struct pm8xxx_vib { struct input_dev *vib_input_dev; struct work_struct work; struct regmap *regmap; conststruct pm8xxx_regs *regs; unsignedint enable_addr; unsignedint drv_addr; unsignedint drv2_addr; int speed; int level; bool active;
u8 reg_vib_drv;
};
/** * pm8xxx_vib_set - handler to start/stop vibration * @vib: pointer to vibrator structure * @on: state to set
*/ staticint pm8xxx_vib_set(struct pm8xxx_vib *vib, bool on)
{ int rc; unsignedint val = vib->reg_vib_drv; conststruct pm8xxx_regs *regs = vib->regs;
if (regs->drv_in_step)
vib->level /= VIB_PER_STEP_mV(vib);
if (on)
val |= (vib->level << regs->drv_shift) & regs->drv_mask; else
val &= ~regs->drv_mask;
if (regs->drv2_mask) {
val = vib->level << regs->drv2_shift;
rc = regmap_write_bits(vib->regmap, vib->drv2_addr,
regs->drv2_mask, on ? val : 0); if (rc < 0) return rc;
}
if (regs->enable_mask)
rc = regmap_update_bits(vib->regmap, vib->enable_addr,
regs->enable_mask, on ? regs->enable_mask : 0);
return rc;
}
/** * pm8xxx_work_handler - worker to set vibration level * @work: pointer to work_struct
*/ staticvoid pm8xxx_work_handler(struct work_struct *work)
{ struct pm8xxx_vib *vib = container_of(work, struct pm8xxx_vib, work); unsignedint val; int rc;
rc = regmap_read(vib->regmap, vib->drv_addr, &val); if (rc < 0) return;
/* * pmic vibrator supports voltage ranges from MIN_LEVEL to MAX_LEVEL, so * scale the level to fit into these ranges.
*/ if (vib->speed) {
vib->active = true;
vib->level = VIB_MIN_LEVEL_mV(vib);
vib->level += mult_frac(VIB_MAX_LEVELS(vib), vib->speed, MAX_FF_SPEED);
} else {
vib->active = false;
vib->level = VIB_MIN_LEVEL_mV(vib);
}
pm8xxx_vib_set(vib, vib->active);
}
/** * pm8xxx_vib_close - callback of input close callback * @dev: input device pointer * * Turns off the vibrator.
*/ staticvoid pm8xxx_vib_close(struct input_dev *dev)
{ struct pm8xxx_vib *vib = input_get_drvdata(dev);
cancel_work_sync(&vib->work); if (vib->active)
pm8xxx_vib_set(vib, false);
}
/** * pm8xxx_vib_play_effect - function to handle vib effects. * @dev: input device pointer * @data: data of effect * @effect: effect to play * * Currently this driver supports only rumble effects.
*/ staticint pm8xxx_vib_play_effect(struct input_dev *dev, void *data, struct ff_effect *effect)
{ struct pm8xxx_vib *vib = input_get_drvdata(dev);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.