staticbool da7280_volatile_register(struct device *dev, unsignedint reg)
{ switch (reg) { case DA7280_IRQ_EVENT1: case DA7280_IRQ_EVENT_WARNING_DIAG: case DA7280_IRQ_EVENT_SEQ_DIAG: case DA7280_IRQ_STATUS1: case DA7280_TOP_CTL1: returntrue; default: returnfalse;
}
}
staticint da7280_haptic_mem_update(struct da7280_haptic *haptics)
{ unsignedint val; int error;
/* The patterns should be updated when haptic is not working */
error = regmap_read(haptics->regmap, DA7280_IRQ_STATUS1, &val); if (error) return error; if (val & DA7280_STA_WARNING_MASK) {
dev_warn(haptics->dev, "Warning! Please check HAPTIC status.\n"); return -EBUSY;
}
/* Patterns are not updated if the lock bit is enabled */
val = 0;
error = regmap_read(haptics->regmap, DA7280_MEM_CTL2, &val); if (error) return error; if (~val & DA7280_WAV_MEM_LOCK_MASK) {
dev_warn(haptics->dev, "Please unlock the bit first\n"); return -EACCES;
}
/* Set to Inactive mode to make sure safety */
error = regmap_update_bits(haptics->regmap,
DA7280_TOP_CTL1,
DA7280_OPERATION_MODE_MASK,
0); if (error) return error;
error = regmap_read(haptics->regmap, DA7280_MEM_CTL1, &val); if (error) return error;
return regmap_bulk_write(haptics->regmap, val, haptics->snp_mem,
DA7280_SNP_MEM_MAX - val + 1);
}
/* * The interpretation of duty cycle depends on the acc_en, * it should be between 50% and 100% for acc_en = 0. * See datasheet 'PWM mode' section.
*/ if (!haptics->acc_en) {
period_mag_multi += state.period;
period_mag_multi /= 2;
}
state.duty_cycle = period_mag_multi;
}
error = pwm_apply_might_sleep(haptics->pwm_dev, &state); if (error)
dev_err(haptics->dev, "Failed to apply pwm state: %d\n", error);
return error;
}
staticvoid da7280_haptic_activate(struct da7280_haptic *haptics)
{ int error;
if (haptics->active) return;
switch (haptics->op_mode) { case DA7280_DRO_MODE: /* the valid range check when acc_en is enabled */ if (haptics->acc_en && haptics->level > 0x7F)
haptics->level = 0x7F; elseif (haptics->level > 0xFF)
haptics->level = 0xFF;
/* Set level as a % of ACTUATOR_NOMMAX (nommax) */
error = regmap_write(haptics->regmap, DA7280_TOP_CTL2,
haptics->level); if (error) {
dev_err(haptics->dev, "Failed to set level to %d: %d\n",
haptics->level, error); return;
} break;
case DA7280_PWM_MODE: if (da7280_haptic_set_pwm(haptics, true)) return; break;
case DA7280_RTWM_MODE: /* * The pattern will be played by the PS_SEQ_ID and the * PS_SEQ_LOOP
*/ break;
case DA7280_ETWM_MODE: /* * The pattern will be played by the GPI[N] state, * GPI(N)_SEQUENCE_ID and the PS_SEQ_LOOP. See the * datasheet for the details.
*/ break;
default:
dev_err(haptics->dev, "Invalid op mode %d\n", haptics->op_mode); return;
}
error = regmap_update_bits(haptics->regmap,
DA7280_TOP_CTL1,
DA7280_OPERATION_MODE_MASK,
haptics->op_mode); if (error) {
dev_err(haptics->dev, "Failed to set operation mode: %d", error); return;
}
if (haptics->op_mode == DA7280_PWM_MODE ||
haptics->op_mode == DA7280_RTWM_MODE) {
error = regmap_update_bits(haptics->regmap,
DA7280_TOP_CTL1,
DA7280_SEQ_START_MASK,
DA7280_SEQ_START_MASK); if (error) {
dev_err(haptics->dev, "Failed to start sequence: %d\n", error); return;
}
}
haptics->active = true;
}
staticvoid da7280_haptic_deactivate(struct da7280_haptic *haptics)
{ int error;
if (!haptics->active) return;
/* Set to Inactive mode */
error = regmap_update_bits(haptics->regmap,
DA7280_TOP_CTL1,
DA7280_OPERATION_MODE_MASK, 0); if (error) {
dev_err(haptics->dev, "Failed to clear operation mode: %d", error); return;
}
switch (haptics->op_mode) { case DA7280_DRO_MODE:
error = regmap_write(haptics->regmap,
DA7280_TOP_CTL2, 0); if (error) {
dev_err(haptics->dev, "Failed to disable DRO mode: %d\n", error); return;
} break;
case DA7280_PWM_MODE: if (da7280_haptic_set_pwm(haptics, false)) return; break;
case DA7280_RTWM_MODE: case DA7280_ETWM_MODE:
error = regmap_update_bits(haptics->regmap,
DA7280_TOP_CTL1,
DA7280_SEQ_START_MASK, 0); if (error) {
dev_err(haptics->dev, "Failed to disable RTWM/ETWM mode: %d\n",
error); return;
} break;
default:
dev_err(haptics->dev, "Invalid op mode %d\n", haptics->op_mode); return;
}
haptics->active = false;
}
staticvoid da7280_haptic_work(struct work_struct *work)
{ struct da7280_haptic *haptics =
container_of(work, struct da7280_haptic, work); int val = haptics->val;
if (val)
da7280_haptic_activate(haptics); else
da7280_haptic_deactivate(haptics);
}
staticint da7280_haptics_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old)
{ struct da7280_haptic *haptics = input_get_drvdata(dev);
s16 data[DA7280_SNP_MEM_SIZE] = { 0 }; unsignedint val; int tmp, i, num; int error;
/* The effect should be uploaded when haptic is not working */ if (haptics->active) return -EBUSY;
switch (effect->type) { /* DRO/PWM modes support this type */ case FF_CONSTANT:
haptics->op_mode = haptics->const_op_mode; if (haptics->op_mode == DA7280_DRO_MODE) {
tmp = effect->u.constant.level * 254;
haptics->level = tmp / 0x7FFF; break;
}
/* RTWM/ETWM modes support this type */ case FF_PERIODIC: if (effect->u.periodic.waveform != FF_CUSTOM) {
dev_err(haptics->dev, "Device can only accept FF_CUSTOM waveform\n"); return -EINVAL;
}
/* * Load the data and check the length. * the data will be patterns in this case: 4 < X <= 100, * and will be saved into the waveform memory inside DA728x. * If X = 2, the data will be PS_SEQ_ID and PS_SEQ_LOOP. * If X = 3, the 1st data will be GPIX_SEQUENCE_ID .
*/ if (effect->u.periodic.custom_len == DA7280_CUSTOM_DATA_LEN) goto set_seq_id_loop;
if (effect->u.periodic.custom_len == DA7280_CUSTOM_GP_DATA_LEN) goto set_gpix_seq_id;
if (effect->u.periodic.custom_len < DA7280_CUSTOM_DATA_LEN ||
effect->u.periodic.custom_len > DA7280_SNP_MEM_SIZE) {
dev_err(haptics->dev, "Invalid waveform data size\n"); return -EINVAL;
}
if (copy_from_user(data, effect->u.periodic.custom_data, sizeof(s16) *
effect->u.periodic.custom_len)) return -EFAULT;
memset(haptics->snp_mem, 0, DA7280_SNP_MEM_SIZE);
for (i = 0; i < effect->u.periodic.custom_len; i++) { if (data[i] < 0 || data[i] > 0xff) {
dev_err(haptics->dev, "Invalid waveform data %d at offset %d\n",
data[i], i); return -EINVAL;
}
haptics->snp_mem[i] = (u8)data[i];
}
error = da7280_haptic_mem_update(haptics); if (error) {
dev_err(haptics->dev, "Failed to upload waveform: %d\n", error); return error;
} break;
set_seq_id_loop: if (copy_from_user(data, effect->u.periodic.custom_data, sizeof(s16) * DA7280_CUSTOM_DATA_LEN)) return -EFAULT;
if (data[DA7280_CUSTOM_SEQ_ID_IDX] < 0 ||
data[DA7280_CUSTOM_SEQ_ID_IDX] > DA7280_SEQ_ID_MAX ||
data[DA7280_CUSTOM_SEQ_LOOP_IDX] < 0 ||
data[DA7280_CUSTOM_SEQ_LOOP_IDX] > DA7280_SEQ_LOOP_MAX) {
dev_err(haptics->dev, "Invalid custom id (%d) or loop (%d)\n",
data[DA7280_CUSTOM_SEQ_ID_IDX],
data[DA7280_CUSTOM_SEQ_LOOP_IDX]); return -EINVAL;
}
/* * If there is no property, then use the mode programmed into the chip.
*/
haptics->dev_type = DA7280_DEV_MAX;
error = device_property_read_string(dev, "dlg,actuator-type", &str); if (!error)
haptics->dev_type = da7280_haptic_of_mode_str(dev, str);
haptics->const_op_mode = DA7280_DRO_MODE;
error = device_property_read_u32(dev, "dlg,const-op-mode", &val); if (!error && val == DA7280_FF_PERIODIC_PWM)
haptics->const_op_mode = DA7280_PWM_MODE;
haptics->periodic_op_mode = DA7280_RTWM_MODE;
error = device_property_read_u32(dev, "dlg,periodic-op-mode", &val); if (!error && val == DA7280_FF_PERIODIC_ETWM)
haptics->periodic_op_mode = DA7280_ETWM_MODE;
haptics->nommax = DA7280_SKIP_INIT;
error = device_property_read_u32(dev, "dlg,nom-microvolt", &val); if (!error && val < DA7280_VOLTAGE_RATE_MAX)
haptics->nommax = da7280_haptic_of_volt_rating_set(val);
haptics->absmax = DA7280_SKIP_INIT;
error = device_property_read_u32(dev, "dlg,abs-max-microvolt", &val); if (!error && val < DA7280_VOLTAGE_RATE_MAX)
haptics->absmax = da7280_haptic_of_volt_rating_set(val);
/* If no property, set to zero as default is to do nothing. */
haptics->ps_seq_id = 0;
error = device_property_read_u32(dev, "dlg,ps-seq-id", &val); if (!error && val <= DA7280_SEQ_ID_MAX)
haptics->ps_seq_id = val;
haptics->ps_seq_loop = 0;
error = device_property_read_u32(dev, "dlg,ps-seq-loop", &val); if (!error && val <= DA7280_SEQ_LOOP_MAX)
haptics->ps_seq_loop = val;
/* GPI0~2 Control */ for (i = 0; i <= DA7280_GPI_SEQ_ID_MAX; i++) {
gpi_str1[7] = '0' + i;
haptics->gpi_ctl[i].seq_id = DA7280_GPI_SEQ_ID_DFT + i;
error = device_property_read_u32 (dev, gpi_str1, &val); if (!error && val <= DA7280_SEQ_ID_MAX)
haptics->gpi_ctl[i].seq_id = val;
if (events[0] & DA7280_E_SEQ_FAULT_MASK) { /* * Stop first if haptic is active, otherwise, the fault may * happen continually even though the bit is cleared.
*/
error = regmap_update_bits(haptics->regmap, DA7280_TOP_CTL1,
DA7280_OPERATION_MODE_MASK, 0); if (error)
dev_err(dev, "failed to clear op mode on fault: %d\n",
error);
}
if (events[0] & DA7280_E_SEQ_DONE_MASK)
haptics->active = false;
if (events[0] & DA7280_E_WARNING_MASK) { if (events[1] & DA7280_E_LIM_DRIVE_MASK ||
events[1] & DA7280_E_LIM_DRIVE_ACC_MASK)
dev_warn(dev, "Please reduce the driver level\n"); if (events[1] & DA7280_E_MEM_TYPE_MASK)
dev_warn(dev, "Please check the mem data format\n"); if (events[1] & DA7280_E_OVERTEMP_WARN_MASK)
dev_warn(dev, "Over-temperature warning\n");
}
if (events[0] & DA7280_E_SEQ_FAULT_MASK) { if (events[2] & DA7280_E_SEQ_ID_FAULT_MASK)
dev_info(dev, "Please reload PS_SEQ_ID & mem data\n"); if (events[2] & DA7280_E_MEM_FAULT_MASK)
dev_info(dev, "Please reload the mem data\n"); if (events[2] & DA7280_E_PWM_FAULT_MASK)
dev_info(dev, "Please restart PWM interface\n");
}
out: return IRQ_HANDLED;
}
staticint da7280_init(struct da7280_haptic *haptics)
{ unsignedint val = 0;
u32 v2i_factor; int error, i;
u8 mask = 0;
/* * If device type is DA7280_DEV_MAX then simply use currently * programmed mode.
*/ if (haptics->dev_type == DA7280_DEV_MAX) {
error = regmap_read(haptics->regmap, DA7280_TOP_CFG1, &val); if (error) goto out_err;
haptics->dev_type = val & DA7280_ACTUATOR_TYPE_MASK ?
DA7280_ERM_COIN : DA7280_LRA;
}
/* Apply user settings */ if (haptics->dev_type == DA7280_LRA &&
haptics->resonant_freq_l != DA7280_SKIP_INIT) {
error = regmap_write(haptics->regmap, DA7280_FRQ_LRA_PER_H,
haptics->resonant_freq_h); if (error) goto out_err;
error = regmap_write(haptics->regmap, DA7280_FRQ_LRA_PER_L,
haptics->resonant_freq_l); if (error) goto out_err;
} elseif (haptics->dev_type == DA7280_ERM_COIN) {
error = regmap_update_bits(haptics->regmap, DA7280_TOP_INT_CFG1,
DA7280_BEMF_FAULT_LIM_MASK, 0); if (error) goto out_err;
mask = DA7280_TST_CALIB_IMPEDANCE_DIS_MASK |
DA7280_V2I_FACTOR_FREEZE_MASK;
val = DA7280_TST_CALIB_IMPEDANCE_DIS_MASK |
DA7280_V2I_FACTOR_FREEZE_MASK;
error = regmap_update_bits(haptics->regmap, DA7280_TOP_CFG4,
mask, val); if (error) goto out_err;
if (!client->irq) {
dev_err(dev, "No IRQ configured\n"); return -EINVAL;
}
haptics = devm_kzalloc(dev, sizeof(*haptics), GFP_KERNEL); if (!haptics) return -ENOMEM;
haptics->dev = dev;
da7280_parse_properties(dev, haptics);
if (haptics->const_op_mode == DA7280_PWM_MODE) {
haptics->pwm_dev = devm_pwm_get(dev, NULL);
error = PTR_ERR_OR_ZERO(haptics->pwm_dev); if (error) { if (error != -EPROBE_DEFER)
dev_err(dev, "Unable to request PWM: %d\n",
error); return error;
}
/* Sync up PWM state and ensure it is off. */
pwm_init_state(haptics->pwm_dev, &state);
state.enabled = false;
error = pwm_apply_might_sleep(haptics->pwm_dev, &state); if (error) {
dev_err(dev, "Failed to apply PWM state: %d\n", error); return error;
}
/* * Make sure no new requests will be submitted while device is * suspended.
*/
scoped_guard(spinlock_irq, &haptics->input_dev->event_lock) {
haptics->suspended = true;
}
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.