static int qpnp_hap_play(struct qpnp_hap *hap, int on) { u8 val; int rc; val = hap->reg_play; if (on) val |= QPNP_HAP_PLAY_EN; else val &= ~QPNP_HAP_PLAY_EN; if (hap->play_mode == QPNP_HAP_DIRECT) { if (!on) { /* */ #if 0 /* 2 x VMAX reverse braking */ hap->vmax_mv = hap->vmax_mv_orig * 2; #endif /* */ hap->vmax_mv = QPNP_HAP_OV_RB_MV; qpnp_hap_vmax_config(hap,1); } } rc = qpnp_hap_write_reg(hap, &val, QPNP_HAP_PLAY_REG(hap->base)); if (rc < 0) return rc; pr_info("[LGE VIBRATOR] qpnp_hap_play play : %d voltage : %d \n", on , hap->vmax_mv); hap->reg_play = val; return 0; }
static int qpnp_hap_play(struct qpnp_hap *hap, int on) { u8 val; int rc; val = hap->reg_play; if (on) val |= QPNP_HAP_PLAY_EN; else val &= ~QPNP_HAP_PLAY_EN; rc = qpnp_hap_write_reg(hap, &val, QPNP_HAP_PLAY_REG(hap->base)); if (rc < 0) return rc; hap->reg_play = val; return 0; }
/* Configuration api for haptics registers */ static int qpnp_hap_config(struct qpnp_hap *hap) { u8 reg = 0; int rc, i, temp; /* Configure the ACTUATOR TYPE register */ rc = qpnp_hap_read_reg(hap, ®, QPNP_HAP_ACT_TYPE_REG(hap->base)); if (rc < 0) return rc; reg &= QPNP_HAP_ACT_TYPE_MASK; reg |= hap->act_type; rc = qpnp_hap_write_reg(hap, ®, QPNP_HAP_ACT_TYPE_REG(hap->base)); if (rc) return rc; /* Configure auto resonance parameters */ if (hap->act_type == QPNP_HAP_LRA) { if (hap->lra_res_cal_period < QPNP_HAP_RES_CAL_PERIOD_MIN) hap->lra_res_cal_period = QPNP_HAP_RES_CAL_PERIOD_MIN; else if (hap->lra_res_cal_period > QPNP_HAP_RES_CAL_PERIOD_MAX) hap->lra_res_cal_period = QPNP_HAP_RES_CAL_PERIOD_MAX; rc = qpnp_hap_read_reg(hap, ®, QPNP_HAP_LRA_AUTO_RES_REG(hap->base)); if (rc < 0) return rc; reg &= QPNP_HAP_AUTO_RES_MODE_MASK; reg |= (hap->auto_res_mode << QPNP_HAP_AUTO_RES_MODE_SHIFT); reg &= QPNP_HAP_LRA_HIGH_Z_MASK; reg |= (hap->lra_high_z << QPNP_HAP_LRA_HIGH_Z_SHIFT); reg &= QPNP_HAP_LRA_RES_CAL_PER_MASK; temp = fls(hap->lra_res_cal_period) - 1; reg |= (temp - 2); rc = qpnp_hap_write_reg(hap, ®, QPNP_HAP_LRA_AUTO_RES_REG(hap->base)); if (rc) return rc; } else { /* disable auto resonance for ERM */ reg = 0x00; rc = qpnp_hap_write_reg(hap, ®, QPNP_HAP_LRA_AUTO_RES_REG(hap->base)); if (rc) return rc; } /* Configure the PLAY MODE register */ rc = qpnp_hap_play_mode_config(hap); if (rc) return rc; /* Configure the VMAX register */ rc = qpnp_hap_vmax_config(hap); if (rc) return rc; /* Configure the ILIM register */ if (hap->ilim_ma < QPNP_HAP_ILIM_MIN_MA) hap->ilim_ma = QPNP_HAP_ILIM_MIN_MA; else if (hap->ilim_ma > QPNP_HAP_ILIM_MAX_MA) hap->ilim_ma = QPNP_HAP_ILIM_MAX_MA; rc = qpnp_hap_read_reg(hap, ®, QPNP_HAP_ILIM_REG(hap->base)); if (rc < 0) return rc; reg &= QPNP_HAP_ILIM_MASK; temp = (hap->ilim_ma / QPNP_HAP_ILIM_MIN_MA) >> 1; reg |= temp; rc = qpnp_hap_write_reg(hap, ®, QPNP_HAP_ILIM_REG(hap->base)); if (rc) return rc; /* Configure the short circuit debounce register */ rc = qpnp_hap_sc_deb_config(hap); if (rc) return rc; /* Configure the INTERNAL_PWM register */ if (hap->int_pwm_freq_khz <= QPNP_HAP_INT_PWM_FREQ_253_KHZ) { hap->int_pwm_freq_khz = QPNP_HAP_INT_PWM_FREQ_253_KHZ; temp = 0; } else if (hap->int_pwm_freq_khz <= QPNP_HAP_INT_PWM_FREQ_505_KHZ) { hap->int_pwm_freq_khz = QPNP_HAP_INT_PWM_FREQ_505_KHZ; temp = 1; } else if (hap->int_pwm_freq_khz <= QPNP_HAP_INT_PWM_FREQ_739_KHZ) { hap->int_pwm_freq_khz = QPNP_HAP_INT_PWM_FREQ_739_KHZ; temp = 2; } else { hap->int_pwm_freq_khz = QPNP_HAP_INT_PWM_FREQ_1076_KHZ; temp = 3; } rc = qpnp_hap_read_reg(hap, ®, QPNP_HAP_INT_PWM_REG(hap->base)); if (rc < 0) return rc; reg &= QPNP_HAP_INT_PWM_MASK; reg |= temp; rc = qpnp_hap_write_reg(hap, ®, QPNP_HAP_INT_PWM_REG(hap->base)); if (rc) return rc; rc = qpnp_hap_read_reg(hap, ®, QPNP_HAP_PWM_CAP_REG(hap->base)); if (rc < 0) return rc; reg &= QPNP_HAP_INT_PWM_MASK; reg |= temp; rc = qpnp_hap_write_reg(hap, ®, QPNP_HAP_PWM_CAP_REG(hap->base)); if (rc) return rc; /* Configure the WAVE SHAPE register */ rc = qpnp_hap_read_reg(hap, ®, QPNP_HAP_WAV_SHAPE_REG(hap->base)); if (rc < 0) return rc; reg &= QPNP_HAP_WAV_SHAPE_MASK; reg |= hap->wave_shape; rc = qpnp_hap_write_reg(hap, ®, QPNP_HAP_WAV_SHAPE_REG(hap->base)); if (rc) return rc; /* Configure RATE_CFG1 and RATE_CFG2 registers */ /* Note: For ERM these registers act as play rate and for LRA these represent resonance period */ if (hap->wave_play_rate_us < QPNP_HAP_WAV_PLAY_RATE_US_MIN) hap->wave_play_rate_us = QPNP_HAP_WAV_PLAY_RATE_US_MIN; else if (hap->wave_play_rate_us > QPNP_HAP_WAV_PLAY_RATE_US_MAX) hap->wave_play_rate_us = QPNP_HAP_WAV_PLAY_RATE_US_MAX; temp = hap->wave_play_rate_us / QPNP_HAP_RATE_CFG_STEP_US; reg = temp & QPNP_HAP_RATE_CFG1_MASK; rc = qpnp_hap_write_reg(hap, ®, QPNP_HAP_RATE_CFG1_REG(hap->base)); if (rc) return rc; rc = qpnp_hap_read_reg(hap, ®, QPNP_HAP_RATE_CFG2_REG(hap->base)); if (rc < 0) return rc; reg &= QPNP_HAP_RATE_CFG2_MASK; temp = temp >> QPNP_HAP_RATE_CFG2_SHFT; reg |= temp; rc = qpnp_hap_write_reg(hap, ®, QPNP_HAP_RATE_CFG2_REG(hap->base)); if (rc) return rc; /* Configure BRAKE register */ rc = qpnp_hap_read_reg(hap, ®, QPNP_HAP_EN_CTL2_REG(hap->base)); if (rc < 0) return rc; reg &= QPNP_HAP_BRAKE_MASK; reg |= hap->en_brake; rc = qpnp_hap_write_reg(hap, ®, QPNP_HAP_EN_CTL2_REG(hap->base)); if (rc) return rc; if (hap->en_brake && hap->sup_brake_pat) { for (i = QPNP_HAP_BRAKE_PAT_LEN - 1, reg = 0; i >= 0; i--) { hap->brake_pat[i] &= QPNP_HAP_BRAKE_PAT_MASK; temp = i << 1; reg |= hap->brake_pat[i] << temp; } rc = qpnp_hap_write_reg(hap, ®, QPNP_HAP_BRAKE_REG(hap->base)); if (rc) return rc; } /* Cache enable control register */ rc = qpnp_hap_read_reg(hap, ®, QPNP_HAP_EN_CTL_REG(hap->base)); if (rc < 0) return rc; hap->reg_en_ctl = reg; /* Cache play register */ rc = qpnp_hap_read_reg(hap, ®, QPNP_HAP_PLAY_REG(hap->base)); if (rc < 0) return rc; hap->reg_play = reg; if (hap->play_mode == QPNP_HAP_BUFFER) rc = qpnp_hap_buffer_config(hap); else if (hap->play_mode == QPNP_HAP_PWM) rc = qpnp_hap_pwm_config(hap); else if (hap->play_mode == QPNP_HAP_AUDIO) rc = qpnp_hap_mod_enable(hap, true); if (rc) return rc; /* setup short circuit irq */ if (hap->use_sc_irq) { rc = devm_request_threaded_irq(&hap->spmi->dev, hap->sc_irq, NULL, qpnp_hap_sc_irq, QPNP_IRQ_FLAGS, "qpnp_sc_irq", hap); if (rc < 0) { dev_err(&hap->spmi->dev, "Unable to request sc(%d) IRQ(err:%d)\n", hap->sc_irq, rc); return rc; } } return rc; }