From 62ae18a8466547492e7380774ec80285d7fe8ad4 Mon Sep 17 00:00:00 2001 From: alk3pInjection Date: Sat, 17 Sep 2022 17:12:03 +0800 Subject: [PATCH] treewide: Import OEM changes Change-Id: I1375797d70876931eef62f215f70e2e4bc776d5b --- android/abi_gki_aarch64_qcom_internal | 5 + drivers/gpu/drm/drm_modes.c | 4 + drivers/input/misc/qcom-hv-haptics.c | 780 ++++++++++++++++++++- drivers/irqchip/msm_show_resume_irq.c | 2 +- drivers/nfc/qti/nfc_common.h | 4 +- drivers/nfc/qti/nfc_i2c_drv.c | 27 + drivers/pinctrl/qcom/pinctrl-yupik.c | 2 +- drivers/power/supply/qti_battery_charger.c | 306 ++++++++ drivers/soc/qcom/fsa4480-i2c.c | 58 +- drivers/soc/qcom/icnss2/qmi.c | 12 + 10 files changed, 1193 insertions(+), 7 deletions(-) diff --git a/android/abi_gki_aarch64_qcom_internal b/android/abi_gki_aarch64_qcom_internal index adc2d0594099..82ac3868e049 100644 --- a/android/abi_gki_aarch64_qcom_internal +++ b/android/abi_gki_aarch64_qcom_internal @@ -192,3 +192,8 @@ __tracepoint_rmnet_shs_low __tracepoint_rmnet_shs_wq_high __tracepoint_rmnet_shs_wq_low + device_remove_bin_file + snd_pcm_format_physical_width + snd_pcm_hw_constraint_mask64 + devm_snd_soc_register_component + devm_gpio_free diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index e4e33cafd495..08194f560404 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -1016,6 +1016,10 @@ bool drm_mode_match(const struct drm_display_mode *mode1, if (!mode1 || !mode2) return false; + /* different refresh rate should be considered as different drm mode */ + if (mode1->vrefresh != mode2->vrefresh) + return false; + if (match_flags & DRM_MODE_MATCH_TIMINGS && !drm_mode_match_timings(mode1, mode2)) return false; diff --git a/drivers/input/misc/qcom-hv-haptics.c b/drivers/input/misc/qcom-hv-haptics.c index 7f79ba9af213..99a2ab8c46b2 100644 --- a/drivers/input/misc/qcom-hv-haptics.c +++ b/drivers/input/misc/qcom-hv-haptics.c @@ -28,6 +28,13 @@ #include #include +#define RICHTAP_FOR_PMIC_ENABLE +#ifdef RICHTAP_FOR_PMIC_ENABLE +#include +#include +#define RICHTAP_NAME "aw8697_haptic" +#endif //RICHTAP_FOR_PMIC_ENABLE + /* status register definitions in HAPTICS_CFG module */ #define HAP_CFG_REVISION2_REG 0x01 #define HAP_CFG_V1 0x1 @@ -441,6 +448,7 @@ struct haptics_effect { struct brake_cfg *brake; u32 id; u32 vmax_mv; + u32 Vrms_mv; u32 t_lra_us; enum pattern_src src; bool auto_res_disable; @@ -471,6 +479,7 @@ struct haptics_play_info { struct fifo_play_status fifo_status; struct mutex lock; u32 vmax_mv; + u32 Vrms_mv; u32 length_us; enum pattern_src pattern_src; bool in_calibration; @@ -479,6 +488,7 @@ struct haptics_play_info { struct haptics_hw_config { struct brake_cfg brake; u32 vmax_mv; + u32 Vrms_mv; u32 t_lra_us; u32 cl_t_lra_us; u32 lra_min_mohms; @@ -498,6 +508,51 @@ struct custom_fifo_data { u8 *data; }; +#ifdef RICHTAP_FOR_PMIC_ENABLE +enum { + RICHTAP_UNKNOWN = -1, + RICHTAP_AW_8697 = 0x05, + RICHTAP_PMIC_8350BH = 0x06, +}; + +enum { + MMAP_BUF_DATA_VALID = 0x55, + MMAP_BUF_DATA_FINISHED = 0xAA, + MMAP_BUF_DATA_INVALID = 0xFF, +}; + +#define RICHTAP_IOCTL_GROUP 0x52 +#define RICHTAP_GET_HWINFO _IO(RICHTAP_IOCTL_GROUP, 0x03) +#define RICHTAP_SET_FREQ _IO(RICHTAP_IOCTL_GROUP, 0x04) +#define RICHTAP_SETTING_GAIN _IO(RICHTAP_IOCTL_GROUP, 0x05) +#define RICHTAP_OFF_MODE _IO(RICHTAP_IOCTL_GROUP, 0x06) +#define RICHTAP_TIMEOUT_MODE _IO(RICHTAP_IOCTL_GROUP, 0x07) +#define RICHTAP_RAM_MOD _IO(RICHTAP_IOCTL_GROUP, 0x08) +#define RICHTAP_RTP_MODE _IO(RICHTAP_IOCTL_GROUP, 0x09) +#define RICHTAP_STREAM_MODE _IO(RICHTAP_IOCTL_GROUP, 0x0A) +#define RICHTAP_UPDATE_RAM _IO(RICHTAP_IOCTL_GROUP, 0x10) +#define RICHTAP_GET_F0 _IO(RICHTAP_IOCTL_GROUP, 0x11) +#define RICHTAP_STOP_MODE _IO(RICHTAP_IOCTL_GROUP, 0x12) +#define RICHTAP_F0_UPDATE _IO(RICHTAP_IOCTL_GROUP, 0x13) + +#define RICHTAP_MMAP_BUF_SIZE 1000 +#define RICHTAP_MMAP_PAGE_ORDER 2 +#define RICHTAP_MMAP_BUF_SUM 16 + +#pragma pack(4) +struct mmap_buf_format { + uint8_t status; + uint8_t bit; + int16_t length; + uint32_t reserve; + struct mmap_buf_format *kernel_next; + struct mmap_buf_format *user_next; + uint8_t data[RICHTAP_MMAP_BUF_SIZE]; +}; +#pragma pack() + +#endif //RICHTAP_FOR_PMIC_ENABLE + struct haptics_chip { struct device *dev; struct regmap *regmap; @@ -533,6 +588,16 @@ struct haptics_chip { bool hpwr_vreg_enabled; bool is_hv_haptics; bool hboost_enabled; +#ifdef RICHTAP_FOR_PMIC_ENABLE + uint8_t *rtp_ptr; + struct mmap_buf_format *start_buf; + struct mmap_buf_format *current_buf; + struct work_struct richtap_stream_work; + struct work_struct richtap_erase_work; + int16_t pos; + atomic_t richtap_mode; + bool f0_flag; +#endif //RICHTAP_FOR_PMIC_ENABLE }; struct haptics_reg_info { @@ -540,6 +605,10 @@ struct haptics_reg_info { u8 val; }; +#ifdef RICHTAP_FOR_PMIC_ENABLE +struct haptics_chip *g_richtap_ptr; +#endif //RICHTAP_FOR_PMIC_ENABLE + static inline int get_max_fifo_samples(struct haptics_chip *chip) { int val = 0; @@ -1507,11 +1576,20 @@ static int haptics_open_loop_drive_config(struct haptics_chip *chip, bool en) dev_dbg(chip->dev, "Toggle CAL_EN in open-loop-VREG playing\n"); } +#ifndef RICHTAP_FOR_PMIC_ENABLE } else if (!is_haptics_external_powered(chip)) { rc = haptics_masked_write(chip, chip->cfg_addr_base, HAP_CFG_VSET_CFG_REG, FORCE_VREG_RDY_BIT, 0); } +#else + } else { + val = en ? FORCE_VREG_RDY_BIT : 0; + rc = haptics_masked_write(chip, chip->cfg_addr_base, + HAP_CFG_VSET_CFG_REG, + FORCE_VREG_RDY_BIT, val); + } +#endif //RICHTAP_FOR_PMIC_ENABLE return rc; } @@ -2171,6 +2249,7 @@ static int haptics_init_custom_effect(struct haptics_chip *chip) chip->custom_effect->t_lra_us = chip->config.t_lra_us; chip->custom_effect->src = FIFO; chip->custom_effect->auto_res_disable = true; + chip->custom_effect->Vrms_mv = chip->config.Vrms_mv; return 0; } @@ -2841,17 +2920,31 @@ static irqreturn_t fifo_empty_irq_handler(int irq, void *data) struct haptics_chip *chip = data; struct fifo_cfg *fifo; struct fifo_play_status *status; - u32 samples_left; + u32 samples_left, fill; u8 *samples, val; int rc, num; +#ifdef RICHTAP_FOR_PMIC_ENABLE + int16_t num_rt = 0; + int16_t num_val = 0; +#endif //RICHTAP_FOR_PMIC_ENABLE + rc = haptics_read(chip, chip->cfg_addr_base, HAP_CFG_INT_RT_STS_REG, &val, 1); if (rc < 0) return IRQ_HANDLED; +#ifdef RICHTAP_FOR_PMIC_ENABLE + if (!(val & FIFO_EMPTY_BIT)) { + haptics_get_fifo_fill_status(chip, &fill); + if ((atomic_read(&chip->richtap_mode)) && (fill < 24)) + schedule_work(&chip->richtap_erase_work); + return IRQ_HANDLED; + } +#else if (!(val & FIFO_EMPTY_BIT)) return IRQ_HANDLED; +#endif mutex_lock(&chip->play.lock); status = &chip->play.fifo_status; @@ -2869,6 +2962,11 @@ static irqreturn_t fifo_empty_irq_handler(int irq, void *data) goto unlock; } +#ifdef RICHTAP_FOR_PMIC_ENABLE + if (atomic_read(&chip->richtap_mode)) + atomic_set(&chip->richtap_mode, false); +#endif //RICHTAP_FOR_PMIC_ENABLE + rc = haptics_stop_fifo_play(chip); if (rc < 0) goto unlock; @@ -2880,6 +2978,72 @@ static irqreturn_t fifo_empty_irq_handler(int irq, void *data) goto unlock; } +#ifdef RICHTAP_FOR_PMIC_ENABLE + if (atomic_read(&chip->richtap_mode)) { + num_rt = (int16_t)haptics_get_available_fifo_memory(chip); + if (num_rt == get_max_fifo_samples(chip)) { + dev_dbg(chip->dev, "aacrichtap fifo stoped,wait next vibrator d%\n", num_rt); + goto unlock; + } + if (num_rt < 0) { + dev_err(chip->dev,"get fifo error, num_rt = %d\n", num_rt); + schedule_work(&chip->richtap_erase_work); + goto unlock; + } + while (num_rt > 0) { + num_val = chip->current_buf->length - chip->pos; + if (num_val < 0) { + dev_err(chip->dev,"aacrichtap length error , pos = %d, length = %d\n", + chip->pos, chip->current_buf->length); + schedule_work(&chip->richtap_erase_work); + goto unlock; + } + if ((chip->current_buf->status == MMAP_BUF_DATA_VALID) + && (num_rt >= num_val)) { + samples_left = (u32)num_val; + samples_left -= + (samples_left % HAP_PTN_V2_FIFO_DIN_NUM); + + rc = haptics_update_fifo_samples(chip, + &chip->current_buf->data[chip->pos], samples_left); + if (rc < 0) { + dev_err(chip->dev,"richtap Update fail, rc=%d\n", rc); + goto unlock; + } + num_rt -= num_val; + chip->current_buf->status = MMAP_BUF_DATA_INVALID; + chip->current_buf->length = 0; + chip->current_buf = chip->current_buf->kernel_next; + chip->pos = 0; + continue; + } + + if (chip->current_buf->status == MMAP_BUF_DATA_VALID) { + num_rt -= (num_rt % HAP_PTN_V2_FIFO_DIN_NUM); + + rc = haptics_update_fifo_samples(chip, + &chip->current_buf->data[chip->pos], (u32)num_rt); + if (rc < 0) { + dev_err(chip->dev, + "richtap Update FIFO fail, rc=%d\n", rc); + goto unlock; + } + chip->pos += num_rt; + num_rt = 0; + continue; + } + + if (chip->current_buf->status != MMAP_BUF_DATA_FINISHED) + dev_err(chip->dev, "aac richtap invalid data buf\n"); + schedule_work(&chip->richtap_erase_work); + dev_dbg(chip->dev,"richtap stream mode is done\n"); + + break; + } + goto unlock; + } +#endif //RICHTAP_FOR_PMIC_ENABLE + if (!chip->play.effect) goto unlock; @@ -4094,6 +4258,15 @@ static int haptics_parse_dt(struct haptics_chip *chip) goto free_pbs; } + config->Vrms_mv = DEFAULT_VMAX_MV; + of_property_read_u32(node, "qcom,Vrms_mv", &config->Vrms_mv); + if (config->Vrms_mv >= MAX_VMAX_MV) { + dev_err(chip->dev, "qcom,Vrms_mv (%d) exceed the max value: %d\n", + config->Vrms_mv, MAX_VMAX_MV); + rc = -EINVAL; + goto free_pbs; + } + config->fifo_empty_thresh = get_fifo_empty_threshold(chip); of_property_read_u32(node, "qcom,fifo-empty-threshold", &config->fifo_empty_thresh); @@ -4453,7 +4626,7 @@ static int haptics_detect_lra_frequency(struct haptics_chip *chip) { int rc; u8 autores_cfg, amplitude; - u32 vmax_mv = chip->config.vmax_mv; + u32 vmax_mv = chip->config.Vrms_mv; rc = haptics_read(chip, chip->cfg_addr_base, HAP_CFG_AUTORES_CFG_REG, &autores_cfg, 1); @@ -4636,10 +4809,566 @@ static ssize_t lra_impedance_show(struct class *c, } static CLASS_ATTR_RO(lra_impedance); +static ssize_t fifo_vmax_store(struct class *c, + struct class_attribute *attr, const char *buf, size_t count) +{ + struct haptics_chip *chip = container_of(c, + struct haptics_chip, hap_class); + u32 bt; + ssize_t result; + result = sscanf(buf, "%d", &bt); + if (result != 1) + return -EINVAL; + chip->config.vmax_mv = bt; + return count; +} + +static ssize_t fifo_vmax_show(struct class *c, + struct class_attribute *attr, char *buf) +{ + struct haptics_chip *chip = container_of(c, + struct haptics_chip, hap_class); + u32 cl_f_lra; + + cl_f_lra = chip->config.vmax_mv; + + return scnprintf(buf, PAGE_SIZE, "%dmv\n", cl_f_lra); +} +static CLASS_ATTR_RW(fifo_vmax); + +#ifdef RICHTAP_FOR_PMIC_ENABLE +static void richtap_clean_buf(struct haptics_chip *chip, int status) +{ + struct mmap_buf_format *opbuf = chip->start_buf; + int i; + + for (i = 0; i < RICHTAP_MMAP_BUF_SUM; i++) { + opbuf->status = status; + opbuf->length = 0; + opbuf = opbuf->kernel_next; + } +} + +static int richtap_get_lra_frequency_hz(struct haptics_chip *chip, u32 *val) +{ + if (chip->config.cl_t_lra_us == 0) + return -EINVAL; + + *val = USEC_PER_SEC / chip->config.cl_t_lra_us; + +#ifdef raac_FEATURE_CHG_BASIC + if (chip->cal_data_restore) { + if (chip->cal_data.cl_t_lra_us != 0) + *val = USEC_PER_SEC / chip->cal_data.cl_t_lra_us; + else + *val = 0; + dev_err(chip->dev, "lra_frequency_hz read : %d\n", *val); + } +#endif + + return 0; +} + +static int richtap_rc_clk_disable(struct haptics_chip *chip) +{ + int rc; + u8 val; + + /* + * All other playing modes would use AUTO mode RC + * calibration except FIFO streaming mode, so restore + * back to AUTO RC calibration after FIFO playing. + */ + val = CAL_RC_CLK_DISABLED_VAL << CAL_RC_CLK_SHIFT; + rc = haptics_masked_write(chip, chip->cfg_addr_base, + HAP_CFG_CAL_EN_REG, CAL_RC_CLK_MASK, val); + if (rc < 0) + return rc; + + return 0; +} + +static int richtap_set_fifo(struct haptics_chip *chip, struct fifo_cfg *fifo) +{ + struct fifo_play_status *status = &chip->play.fifo_status; + u32 num, fifo_thresh; + int rc, available; + + if (atomic_read(&status->is_busy) == 1) { + dev_err(chip->dev, "FIFO is busy\n"); + return -EBUSY; + } + + if (chip->ptn_revision == HAP_PTN_V1 && + fifo->period_per_s > F_8KHZ && + fifo->num_s > get_max_fifo_samples(chip)) { + dev_err(chip->dev, "PM8350B v1 not play long pattern higher than 8 KHz play rate\n"); + return -EINVAL; + } + + /* Configure FIFO play rate */ + rc = haptics_set_fifo_playrate(chip, fifo->period_per_s); + if (rc < 0) + return rc; + + atomic_set(&status->written_done, 0); + atomic_set(&status->cancelled, 0); + status->samples_written = 0; + + /* + * Write the 1st set of the data into FIFO if there are + * more than get_max_fifo_samples samples, the rest will be + * written if any FIFO memory is available after playing. + */ + num = min_t(u32, fifo->num_s, get_max_fifo_samples(chip)); + available = haptics_get_available_fifo_memory(chip); + if (available < 0) + return available; + + num = min_t(u32, available, num); + rc = haptics_update_fifo_samples(chip, fifo->samples, num); + if (rc < 0) { + dev_err(chip->dev, "write FIFO samples failed, rc=%d\n", rc); + return rc; + } + + dev_dbg(chip->dev, "aac Richtap set busy to 1\n"); + atomic_set(&status->is_busy, 1); + status->samples_written = num; + + fifo_thresh = 480; //480 * 40us + + + /* + * Set FIFO empty threshold here. FIFO empty IRQ will + * be enabled after playing FIFO samples so that more + * FIFO samples can be written (if available) when + * FIFO empty IRQ is triggered. + */ + + return haptics_set_fifo_empty_threshold(chip, fifo_thresh); +} + +static void richtap_erase_work_proc(struct work_struct *work) +{ + struct haptics_chip *chip = container_of(work, + struct haptics_chip, richtap_erase_work); + int rc; + u8 count = 5; + u32 fill; + + while (count--) { + rc = haptics_get_fifo_fill_status(chip, &fill); + if ((rc < 0) || (atomic_read(&chip->play.fifo_status.is_busy) == 0)) + return; + if (fill < 24) + break; + fill /= 24; //24k play_rate_hz + fill *= 1000; + usleep_range((fill + 25), (fill + 30)); + } + + dev_dbg(chip->dev, "aacrichtap0424 fill=%d,count = %d\n", fill, count); + mutex_lock(&chip->play.lock); + richtap_clean_buf(chip, MMAP_BUF_DATA_FINISHED); + atomic_set(&chip->play.fifo_status.written_done, 1); + haptics_set_fifo_empty_threshold(chip, 0); + haptics_stop_fifo_play(chip); + atomic_set(&chip->richtap_mode, false); + mutex_unlock(&chip->play.lock); +} + +static int richtap_playback(struct haptics_chip *chip, bool on) +{ + struct haptics_play_info *play = &chip->play; + int rc; + + if (on) { + rc = haptics_enable_play(chip, true); + if (rc < 0) + return rc; + + if (play->pattern_src == FIFO) + haptics_fifo_empty_irq_config(chip, true); + } else { + if (play->pattern_src == FIFO && + atomic_read(&play->fifo_status.is_busy)) { + dev_dbg(chip->dev, "FIFO playing is not done yet, defer stopping in erase\n"); + return 0; + } + + rc = haptics_enable_play(chip, false); + } + + return rc; +} + +static int richtap_load_prebake(struct haptics_chip *chip, u8 *data, u32 length) +{ + struct haptics_play_info *play = &chip->play; + struct custom_fifo_data custom_data = {}; + struct fifo_cfg *fifo; + int rc; + + if (!chip->custom_effect || !chip->custom_effect->fifo) + return -ENOMEM; + fifo = chip->custom_effect->fifo; + custom_data.length = length; + custom_data.play_rate_hz = 24000; //24000; + custom_data.data = data; + + dev_dbg(chip->dev, "aac RichTap data %d length\n", length); + + rc = haptics_convert_sample_period(chip, custom_data.play_rate_hz); + if (rc < 0) { + dev_err(chip->dev, "aac RichTap Can't support play rate: %d Hz\n", + custom_data.play_rate_hz); + return rc; + } + + mutex_lock(&chip->play.lock); + + fifo->period_per_s = rc; + fifo->num_s = length; + /* + * Before allocating samples buffer, free the old sample + * buffer first if it's not been freed. + */ + kfree(fifo->samples); + fifo->samples = kcalloc(custom_data.length, sizeof(u8), GFP_KERNEL); + if (!fifo->samples) { + rc = -ENOMEM; + goto unlock; + } + + memcpy(fifo->samples, custom_data.data, custom_data.length); + + play->effect = chip->custom_effect; + play->brake = NULL; + + rc = haptics_set_vmax_mv(chip, play->vmax_mv); + if (rc < 0) + goto cleanup; + + rc = haptics_enable_autores(chip, false); + if (rc < 0) + goto cleanup; + + //Toggle HAPTICS_EN for a clear start point of FIFO playing + rc = haptics_toggle_module_enable(chip); + if (rc < 0) + goto cleanup; + + play->pattern_src = FIFO; + rc = richtap_set_fifo(chip, play->effect->fifo); + if (rc < 0) + goto cleanup; + dev_dbg(chip->dev, "aac RichTap haptics_set_fifo success\n"); + + mutex_unlock(&chip->play.lock); + + return 0; +cleanup: + kfree(fifo->samples); + fifo->samples = NULL; +unlock: + mutex_unlock(&chip->play.lock); + return rc; +} + +static void richtap_work_proc(struct work_struct *work) +{ + struct haptics_chip *chip = container_of(work, struct haptics_chip, richtap_stream_work); + struct mmap_buf_format *first; + + uint32_t count = 100; + int ret; + + while ((count--) && (chip->start_buf->status != MMAP_BUF_DATA_VALID)) { + usleep_range(1000, 1001); + } + if ((chip->start_buf->length <= 0) || + (chip->start_buf->status != MMAP_BUF_DATA_VALID)) { + dev_err(chip->dev, "aacrichtap first length invalid %d %d ", + chip->start_buf->status, chip->start_buf->length); + mutex_lock(&chip->play.lock); + richtap_clean_buf(chip, MMAP_BUF_DATA_FINISHED); + atomic_set(&chip->play.fifo_status.written_done, 1); + haptics_set_fifo_empty_threshold(chip, 0); + haptics_stop_fifo_play(chip); + atomic_set(&chip->richtap_mode, false); + mutex_unlock(&chip->play.lock); + + return; + } + + chip->pos = 0; + first = chip->start_buf; + if (first->length >= get_max_fifo_samples(chip)) { + if ((first->length > get_max_fifo_samples(chip))) { + chip->pos = get_max_fifo_samples(chip); + chip->current_buf = first; + } else { + chip->current_buf = first->kernel_next; + } + goto play_rate; + } else { + chip->current_buf = first->kernel_next; + } + + count = 0; + while (first->length < get_max_fifo_samples(chip)) { + if ((chip->current_buf->status == MMAP_BUF_DATA_FINISHED) || + (count > 30)) + break; + if ((chip->current_buf->status != MMAP_BUF_DATA_VALID) && + (count < 30)) { + count++; + usleep_range(1000, 1001); + dev_err(chip->dev, "wait for data\n"); + continue; + } + if ((first->length + chip->current_buf->length) <= + get_max_fifo_samples(chip)) { + memcpy(&first->data[first->length], chip->current_buf->data, + chip->current_buf->length); + chip->current_buf->status = MMAP_BUF_DATA_INVALID; + first->length += chip->current_buf->length; + chip->current_buf->length = 0; + chip->current_buf = chip->current_buf->kernel_next; + count = 0; + } else { + memcpy(&first->data[first->length], chip->current_buf->data, + (get_max_fifo_samples(chip) - first->length)); + chip->pos = get_max_fifo_samples(chip) - first->length; + first->length = get_max_fifo_samples(chip); + dev_err(chip->dev, "first full\n"); + } + } + +play_rate: + dev_dbg(chip->dev, "pos %d,first %d,current %d\n", chip->pos, first->length, chip->current_buf->length); + ret = richtap_load_prebake(chip, first->data, first->length <= + get_max_fifo_samples(chip) ? first->length : get_max_fifo_samples(chip)); + if (ret < 0) { + dev_err(chip->dev, "aac RichTap Upload FIFO data fail\n", ret); + return; + } + + if (first->length <= get_max_fifo_samples(chip)) { + first->status = MMAP_BUF_DATA_INVALID; + first->length = 0; + } + + + ret = haptics_enable_hpwr_vreg(chip, true); + if (ret < 0) { + dev_err(chip->dev, "aac RichTap en hpwr_vreg fail, rc=%d\n", ret); + return; + } + + ret = haptics_wait_hboost_ready(chip); + if (ret < 0) { + schedule_work(&chip->richtap_erase_work); + return; + } + + ret = richtap_playback(chip, true); + if (ret < 0) + dev_err(chip->dev, "aac RichTap richtap_playback fail, rc=%d\n", ret); +} + +/***************************************************** + * + * haptic fops + * + *****************************************************/ +static int richtap_file_open(struct inode *inode, struct file *file) +{ + if (!try_module_get(THIS_MODULE)) + return -ENODEV; + + file->private_data = (void *)g_richtap_ptr; + + return 0; +} + +static int richtap_file_release(struct inode *inode, struct file *file) +{ + file->private_data = (void *)NULL; + + module_put(THIS_MODULE); + + return 0; +} + +static long richtap_file_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct haptics_chip *chip = (struct haptics_chip *)file->private_data; + uint32_t tmp; + int ret = 0; + + dev_dbg(chip->dev, "%s: cmd=0x%x, arg=0x%lx\n", + __func__, cmd, arg); + + switch (cmd) { + case RICHTAP_GET_HWINFO: + tmp = RICHTAP_AW_8697; + if (copy_to_user((void __user *)arg, &tmp, sizeof(uint32_t))) + return -EFAULT; + break; + case RICHTAP_RTP_MODE: + if (copy_from_user(chip->rtp_ptr, (void __user *)arg, + RICHTAP_MMAP_BUF_SIZE * RICHTAP_MMAP_BUF_SUM)) { + ret = -EFAULT; + break; + } + tmp = *((uint32_t *)chip->rtp_ptr); + if (tmp > (RICHTAP_MMAP_BUF_SIZE * RICHTAP_MMAP_BUF_SUM - 4)) { + dev_err(chip->dev, "aac RichTap rtp mode date len error %d\n", tmp); + ret = -EINVAL; + break; + } + + mutex_lock(&chip->play.lock); + haptics_stop_fifo_play(chip); + mutex_unlock(&chip->play.lock); + richtap_rc_clk_disable(chip); + atomic_set(&chip->richtap_mode, false); + + ret = richtap_load_prebake(chip, &chip->rtp_ptr[4], tmp); + if (ret < 0) { + dev_err(chip->dev, "aac RichTap Upload FIFO data fail\n", ret); + break; + } + + ret = haptics_enable_hpwr_vreg(chip, true); + if (ret < 0) { + dev_err(chip->dev, "aac RichTap en hpwr_vreg fail, rc=%d\n", ret); + break; + } + + ret = haptics_wait_hboost_ready(chip); + if (ret < 0) { + schedule_work(&chip->richtap_erase_work); + break; + } + + ret = richtap_playback(chip, true); + if (ret < 0) + dev_err(chip->dev, "aac RichTap en hpwr_vreg fail, rc=%d\n", ret); + schedule_work(&chip->richtap_erase_work); + break; + case RICHTAP_OFF_MODE: + break; + case RICHTAP_GET_F0: + ret = richtap_get_lra_frequency_hz(chip, &tmp); + dev_dbg(chip->dev, "aac RichTap get f0 =%d\n", tmp); + //tmp = 170; //just for debug,f0 right should remove + if (ret < 0) { + dev_err(chip->dev, "aac RichTap get f0 error, ret=%d\n", ret); + break; + } + tmp *= 10; + if (copy_to_user((void __user *)arg, &tmp, sizeof(uint32_t))) + ret = -EFAULT; + break; + case RICHTAP_SETTING_GAIN: + if (arg > 0x80) + arg = 0x80; + tmp = chip->config.vmax_mv; + chip->play.vmax_mv = ((u32)(arg * tmp)) / 128; + haptics_set_vmax_mv(chip, chip->play.vmax_mv); + break; + case RICHTAP_STREAM_MODE: + richtap_clean_buf(chip, MMAP_BUF_DATA_INVALID); + mutex_lock(&chip->play.lock); + haptics_stop_fifo_play(chip); + mutex_unlock(&chip->play.lock); + richtap_rc_clk_disable(chip); + atomic_set(&chip->richtap_mode, true); + schedule_work(&chip->richtap_stream_work); + break; + case RICHTAP_STOP_MODE: + mutex_lock(&chip->play.lock); + richtap_clean_buf(chip, MMAP_BUF_DATA_FINISHED); + atomic_set(&chip->play.fifo_status.written_done, 1); + haptics_set_fifo_empty_threshold(chip, 0); + haptics_stop_fifo_play(chip); + atomic_set(&chip->richtap_mode, false); + mutex_unlock(&chip->play.lock); + break; + case RICHTAP_F0_UPDATE: + break; + default: + dev_err(chip->dev, "%s, unknown cmd\n", __func__); + break; + } + + return ret; +} + +static ssize_t richtap_file_read(struct file *filp, char *buff, size_t len, loff_t *offset) +{ + return len; +} + +static ssize_t richtap_file_write(struct file *filp, const char *buff, size_t len, loff_t *off) +{ + return len; +} + +static int richtap_file_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct haptics_chip *chip = (struct haptics_chip *)filp->private_data; + unsigned long phys; + int ret = 0; + + //only accept PROT_READ, PROT_WRITE and MAP_SHARED from the API of mmap + vm_flags_t vm_flags = calc_vm_prot_bits(PROT_READ|PROT_WRITE, 0) | + calc_vm_flag_bits(MAP_SHARED); + vm_flags |= current->mm->def_flags | VM_MAYREAD | + VM_MAYWRITE | VM_MAYEXEC | VM_SHARED | VM_MAYSHARE; + if (vma && (pgprot_val(vma->vm_page_prot) != pgprot_val(vm_get_page_prot(vm_flags)))) + return -EPERM; + + if (vma && ((vma->vm_end - vma->vm_start) != (PAGE_SIZE << RICHTAP_MMAP_PAGE_ORDER))) + return -ENOMEM; + + phys = virt_to_phys(chip->start_buf); + + ret = remap_pfn_range(vma, vma->vm_start, (phys >> PAGE_SHIFT), + (vma->vm_end - vma->vm_start), vma->vm_page_prot); + if (ret) { + dev_err(chip->dev, "Error mmap failed\n"); + return ret; + } + + return ret; +} + +static const struct file_operations fops = { + .owner = THIS_MODULE, + .read = richtap_file_read, + .write = richtap_file_write, + .mmap = richtap_file_mmap, + .unlocked_ioctl = richtap_file_unlocked_ioctl, + .open = richtap_file_open, + .release = richtap_file_release, +}; + +static struct miscdevice richtap_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = RICHTAP_NAME, + .fops = &fops, +}; +#endif //RICHTAP_FOR_PMIC_ENABLE + static struct attribute *hap_class_attrs[] = { &class_attr_lra_calibration.attr, &class_attr_lra_frequency_hz.attr, &class_attr_lra_impedance.attr, + &class_attr_fifo_vmax.attr, NULL, }; ATTRIBUTE_GROUPS(hap_class); @@ -4723,6 +5452,8 @@ static int haptics_probe(struct platform_device *pdev) rc = devm_request_threaded_irq(chip->dev, chip->fifo_empty_irq, NULL, fifo_empty_irq_handler, IRQF_ONESHOT, "fifo-empty", chip); + dev_err(chip->dev, "request fifo-empty IRQ success, rc=%d\n", + rc); if (rc < 0) { dev_err(chip->dev, "request fifo-empty IRQ failed, rc=%d\n", rc); @@ -4782,12 +5513,51 @@ static int haptics_probe(struct platform_device *pdev) goto destroy_ff; } +#ifdef RICHTAP_FOR_PMIC_ENABLE + chip->rtp_ptr = kmalloc(RICHTAP_MMAP_BUF_SIZE * RICHTAP_MMAP_BUF_SUM, GFP_KERNEL); + if (chip->rtp_ptr == NULL) + goto destroy_ff; + + chip->start_buf = (struct mmap_buf_format *)__get_free_pages(GFP_KERNEL, + RICHTAP_MMAP_PAGE_ORDER); + if (chip->start_buf == NULL) { + dev_err(chip->dev, "Error __get_free_pages failed\n"); + goto destroy_richtap; + } + SetPageReserved(virt_to_page(chip->start_buf)); + { + struct mmap_buf_format *temp; + uint32_t i = 0; + + temp = chip->start_buf; + for (i = 1; i < RICHTAP_MMAP_BUF_SUM; i++) { + temp->kernel_next = (chip->start_buf + i); + temp = temp->kernel_next; + } + temp->kernel_next = chip->start_buf; + } + + INIT_WORK(&chip->richtap_stream_work, richtap_work_proc); + INIT_WORK(&chip->richtap_erase_work, richtap_erase_work_proc); + + misc_register(&richtap_misc); + + atomic_set(&chip->richtap_mode, false); + g_richtap_ptr = chip; +#endif //RICHTAP_FOR_PMIC_ENABLE + #ifdef CONFIG_DEBUG_FS rc = haptics_create_debugfs(chip); if (rc < 0) dev_err(chip->dev, "Creating debugfs failed, rc=%d\n", rc); #endif return 0; + +#ifdef RICHTAP_FOR_PMIC_ENABLE +destroy_richtap: + kfree(chip->rtp_ptr); +#endif //RICHTAP_FOR_PMIC_ENABLE + destroy_ff: input_ff_destroy(chip->input_dev); return rc; @@ -4804,6 +5574,12 @@ static int haptics_remove(struct platform_device *pdev) #ifdef CONFIG_DEBUG_FS debugfs_remove_recursive(chip->debugfs_dir); #endif + +#ifdef RICHTAP_FOR_PMIC_ENABLE + kfree(chip->rtp_ptr); + free_pages((unsigned long)chip->start_buf, RICHTAP_MMAP_PAGE_ORDER); +#endif //RICHTAP_FOR_PMIC_ENABLE + input_ff_destroy(chip->input_dev); dev_set_drvdata(chip->dev, NULL); diff --git a/drivers/irqchip/msm_show_resume_irq.c b/drivers/irqchip/msm_show_resume_irq.c index 4815feecd194..fdc3dc5394d4 100644 --- a/drivers/irqchip/msm_show_resume_irq.c +++ b/drivers/irqchip/msm_show_resume_irq.c @@ -7,7 +7,7 @@ #include #include -int msm_show_resume_irq_mask; +int msm_show_resume_irq_mask = 1; module_param_named( debug_mask, msm_show_resume_irq_mask, int, 0664); diff --git a/drivers/nfc/qti/nfc_common.h b/drivers/nfc/qti/nfc_common.h index 2dc31036c1e7..897d0b6586cc 100644 --- a/drivers/nfc/qti/nfc_common.h +++ b/drivers/nfc/qti/nfc_common.h @@ -35,7 +35,7 @@ #define CLASS_NAME "nfc" // NFC character device name, this will be in /dev/ -#define NFC_CHAR_DEV_NAME "nq-nci" +#define NFC_CHAR_DEV_NAME "pn553" // HDR length of NCI packet #define NCI_HDR_LEN 3 @@ -82,7 +82,7 @@ // Ioctls // The type should be aligned with MW HAL definitions -#define NFC_SET_PWR _IOW(NFC_MAGIC, 0x01, unsigned int) +#define NFC_SET_PWR _IOW(NFC_MAGIC, 0x01, long) #define ESE_SET_PWR _IOW(NFC_MAGIC, 0x02, unsigned int) #define ESE_GET_PWR _IOR(NFC_MAGIC, 0x03, unsigned int) #define NFC_GET_PLATFORM_TYPE _IO(NFC_MAGIC, 0x04) diff --git a/drivers/nfc/qti/nfc_i2c_drv.c b/drivers/nfc/qti/nfc_i2c_drv.c index fee83a9f9a2e..4d7c705e2ddd 100644 --- a/drivers/nfc/qti/nfc_i2c_drv.c +++ b/drivers/nfc/qti/nfc_i2c_drv.c @@ -258,6 +258,27 @@ out: return ret; } +static ssize_t scan_stats_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct nfc_dev *nfc_dev = dev_get_drvdata(dev); + int value; + value = gpio_get_value(nfc_dev->gpio.clkreq); + + return scnprintf(buf, PAGE_SIZE,"%d\n", value); +} + +static DEVICE_ATTR_RO(scan_stats); + +static struct attribute *nfc_i2c_attrs[] = { + &dev_attr_scan_stats.attr, + NULL, +}; + +static struct attribute_group nfc_i2c_attr_grp = { + .attrs = nfc_i2c_attrs, +}; + static const struct file_operations nfc_i2c_dev_fops = { .owner = THIS_MODULE, .llseek = no_llseek, @@ -372,6 +393,12 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id) goto err_nfcc_hw_check; } + ret = sysfs_create_group(&client->dev.kobj, &nfc_i2c_attr_grp); + if (ret) { + pr_err("%s: sysfs_create_group failed\n", __func__); + goto err_nfcc_hw_check; + } + device_init_wakeup(&client->dev, true); i2c_dev->irq_wake_up = false; nfc_dev->is_ese_session_active = false; diff --git a/drivers/pinctrl/qcom/pinctrl-yupik.c b/drivers/pinctrl/qcom/pinctrl-yupik.c index a6ebf2016b30..3e77bbba2486 100644 --- a/drivers/pinctrl/qcom/pinctrl-yupik.c +++ b/drivers/pinctrl/qcom/pinctrl-yupik.c @@ -1808,7 +1808,7 @@ static const struct msm_pingroup yupik_groups[] = { }; static const int yupik_reserved_gpios[] = { - 32, 33, 48, 49, 50, 51, -1 + 32, 33, -1 }; static struct pinctrl_qup yupik_qup_regs[] = { QUP_I3C(0, QUP_I3C_0_MODE_OFFSET), diff --git a/drivers/power/supply/qti_battery_charger.c b/drivers/power/supply/qti_battery_charger.c index 3f2993698fcc..4b7eb4706317 100644 --- a/drivers/power/supply/qti_battery_charger.c +++ b/drivers/power/supply/qti_battery_charger.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -53,6 +54,10 @@ #define WLS_FW_BUF_SIZE 128 #define DEFAULT_RESTRICT_FCC_UA 1000000 +#define CONFIG_STWLC38_FW +#define DIVIDE_1000_TIMES 1000 +#define DIVIDE_1000000_TIMES 1000000 + enum usb_connector_type { USB_CONNECTOR_TYPE_TYPEC, USB_CONNECTOR_TYPE_MICRO_USB, @@ -115,6 +120,11 @@ enum usb_property_id { USB_TYPEC_COMPLIANT, USB_SCOPE, USB_CONNECTOR_TYPE, + USB_CHARGE_PUMP_ENABLE, + USB_CC_ORIENTATION, + USB_CHARGE_ENABLE, + USB_SLOWCHARGE_ENABLE, + USB_CHARGE_POWER, USB_PROP_MAX, }; @@ -126,6 +136,13 @@ enum wireless_property_id { WLS_CURR_MAX, WLS_TYPE, WLS_BOOST_EN, +#ifdef CONFIG_STWLC38_FW + WLS_VOLT_TX, + WLS_CURR_TX, + WLS_ST38_REG, + WLS_ST38_DATA, + WLS_REVERSE_STATUS, +#endif WLS_PROP_MAX, }; @@ -243,6 +260,7 @@ struct battery_chg_dev { int fake_soc; bool block_tx; bool ship_mode_en; + bool usb_charger_en; bool debug_battery_detected; bool wls_fw_update_reqd; u32 wls_fw_version; @@ -321,6 +339,7 @@ static const char * const qc_power_supply_usb_type_text[] = { "HVDCP", "HVDCP_3", "HVDCP_3P5" }; +#ifndef CONFIG_STWLC38_FW static int battery_chg_fw_write(struct battery_chg_dev *bcdev, void *data, int len) { @@ -346,6 +365,7 @@ static int battery_chg_fw_write(struct battery_chg_dev *bcdev, void *data, return rc; } +#endif static int battery_chg_write(struct battery_chg_dev *bcdev, void *data, int len) @@ -1269,6 +1289,7 @@ static void battery_chg_subsys_up_work(struct work_struct *work) } } +#ifndef CONFIG_STWLC38_FW static int wireless_fw_send_firmware(struct battery_chg_dev *bcdev, const struct firmware *fw) { @@ -1313,6 +1334,7 @@ static int wireless_fw_send_firmware(struct battery_chg_dev *bcdev, return 0; } +#endif static int wireless_fw_check_for_update(struct battery_chg_dev *bcdev, u32 version, size_t size) @@ -1333,6 +1355,60 @@ static int wireless_fw_check_for_update(struct battery_chg_dev *bcdev, #define IDT_FW_MAJOR_VER_OFFSET 0x94 #define IDT_FW_MINOR_VER_OFFSET 0x96 + +#ifdef CONFIG_STWLC38_FW +static int wireless_fw_update(struct battery_chg_dev *bcdev, bool force) +{ + struct psy_state *pst; + u32 version = 0; + int rc; + + pm_stay_awake(bcdev->dev); + + /* + * Check for USB presence. If nothing is connected, check whether + * battery SOC is at least 50% before allowing FW update. + */ + pst = &bcdev->psy_list[PSY_TYPE_USB]; + rc = read_property_id(bcdev, pst, USB_ONLINE); + if (rc < 0) + goto out; + + if (!pst->prop[USB_ONLINE]) { + pst = &bcdev->psy_list[PSY_TYPE_BATTERY]; + rc = read_property_id(bcdev, pst, BATT_CAPACITY); + if (rc < 0) + goto out; + + if ((pst->prop[BATT_CAPACITY] / 100) < 50) { + pr_err("Battery SOC should be at least 50%% or connect charger\n"); + rc = -EINVAL; + goto out; + } + } + + pr_err("Wireless FW update start\n"); + + rc = wireless_fw_check_for_update(bcdev, version, 0); + if (rc < 0) { + pr_err("Wireless FW update not needed, rc=%d\n", rc); + goto release_fw; + } + + if (!bcdev->wls_fw_update_reqd) { + pr_warn("Wireless FW update not required\n"); + goto release_fw; + } + pr_err("Wireless FW update done\n"); + +release_fw: + bcdev->wls_fw_crc = 0; +out: + pm_relax(bcdev->dev); + + return rc; +} +#else static int wireless_fw_update(struct battery_chg_dev *bcdev, bool force) { const struct firmware *fw; @@ -1433,6 +1509,7 @@ out: return rc; } +#endif static ssize_t wireless_fw_crc_store(struct class *c, struct class_attribute *attr, @@ -1764,6 +1841,120 @@ static ssize_t soh_show(struct class *c, struct class_attribute *attr, } static CLASS_ATTR_RO(soh); +static ssize_t charge_pump_enable_show(struct class *c, struct class_attribute *attr, + char *buf) +{ + struct battery_chg_dev *bcdev = container_of(c, struct battery_chg_dev, + battery_class); + struct psy_state *pst = &bcdev->psy_list[PSY_TYPE_USB]; + int rc; + + rc = read_property_id(bcdev, pst, USB_CHARGE_PUMP_ENABLE); + if (rc < 0) + return rc; + + return scnprintf(buf, PAGE_SIZE, "%d\n", pst->prop[USB_CHARGE_PUMP_ENABLE]); +} +static CLASS_ATTR_RO(charge_pump_enable); + +static ssize_t typec_cc_orientation_show(struct class *c, struct class_attribute *attr, + char *buf) +{ + struct battery_chg_dev *bcdev = container_of(c, struct battery_chg_dev, + battery_class); + struct psy_state *pst = &bcdev->psy_list[PSY_TYPE_USB]; + int rc; + + rc = read_property_id(bcdev, pst, USB_CC_ORIENTATION); + if (rc < 0) + return rc; + + return scnprintf(buf, PAGE_SIZE, "%d\n", pst->prop[USB_CC_ORIENTATION]); +} +static CLASS_ATTR_RO(typec_cc_orientation); + + +static ssize_t usb_charger_en_store(struct class *c, struct class_attribute *attr, + const char *buf, size_t count) +{ + struct battery_chg_dev *bcdev = container_of(c, struct battery_chg_dev, + battery_class); + int rc; + bool val; + + if (kstrtobool(buf, &val)) + return -EINVAL; + + rc = write_property_id(bcdev, &bcdev->psy_list[PSY_TYPE_USB], + USB_CHARGE_ENABLE, val); + if (rc < 0) + return rc; + + return count; +} + +static ssize_t usb_charger_en_show(struct class *c, struct class_attribute *attr, + char *buf) +{ + struct battery_chg_dev *bcdev = container_of(c, struct battery_chg_dev, + battery_class); + struct psy_state *pst = &bcdev->psy_list[PSY_TYPE_USB]; + int rc; + + rc = read_property_id(bcdev, pst, USB_CHARGE_ENABLE); + if (rc < 0) + return rc; + + return scnprintf(buf, PAGE_SIZE, "%d\n", pst->prop[USB_CHARGE_ENABLE]); +} +static CLASS_ATTR_RW(usb_charger_en); + +static ssize_t charge_power_show(struct class *c, struct class_attribute *attr, + char *buf) +{ + struct battery_chg_dev *bcdev = container_of(c, struct battery_chg_dev, + battery_class); + struct psy_state *pst = &bcdev->psy_list[PSY_TYPE_USB]; + read_property_id(bcdev, pst, USB_CHARGE_POWER); + return scnprintf(buf, PAGE_SIZE, "%d\n", pst->prop[USB_CHARGE_POWER]); +} +static CLASS_ATTR_RO(charge_power); + +static ssize_t slowcharge_en_store(struct class *c, struct class_attribute *attr, + const char *buf, size_t count) +{ + struct battery_chg_dev *bcdev = container_of(c, struct battery_chg_dev, + battery_class); + int rc; + u32 val; + + if (kstrtou32(buf, 16, &val)) + return -EINVAL; + + rc = write_property_id(bcdev, &bcdev->psy_list[PSY_TYPE_USB], + USB_SLOWCHARGE_ENABLE, val); + if (rc < 0) + return rc; + + return count; +} + +static ssize_t slowcharge_en_show(struct class *c, struct class_attribute *attr, + char *buf) +{ + struct battery_chg_dev *bcdev = container_of(c, struct battery_chg_dev, + battery_class); + struct psy_state *pst = &bcdev->psy_list[PSY_TYPE_USB]; + int rc; + + rc = read_property_id(bcdev, pst, USB_SLOWCHARGE_ENABLE); + if (rc < 0) + return rc; + + return scnprintf(buf, PAGE_SIZE, "%d\n", pst->prop[USB_SLOWCHARGE_ENABLE]); +} +static CLASS_ATTR_RW(slowcharge_en); + static ssize_t ship_mode_en_store(struct class *c, struct class_attribute *attr, const char *buf, size_t count) { @@ -1786,6 +1977,106 @@ static ssize_t ship_mode_en_show(struct class *c, struct class_attribute *attr, } static CLASS_ATTR_RW(ship_mode_en); +#ifdef CONFIG_STWLC38_FW +static ssize_t wls_volt_tx_show(struct class *c, struct class_attribute *attr, + char *buf) +{ + struct battery_chg_dev *bcdev = container_of(c, struct battery_chg_dev, + battery_class); + struct psy_state *pst = &bcdev->psy_list[PSY_TYPE_WLS]; + int rc; + rc = read_property_id(bcdev, pst, WLS_VOLT_TX); + if (rc < 0) + return rc; + return scnprintf(buf, PAGE_SIZE, "%d\n", pst->prop[WLS_VOLT_TX]); +} +static CLASS_ATTR_RO(wls_volt_tx); +static ssize_t wls_curr_tx_show(struct class *c, struct class_attribute *attr, + char *buf) +{ + struct battery_chg_dev *bcdev = container_of(c, struct battery_chg_dev, + battery_class); + struct psy_state *pst = &bcdev->psy_list[PSY_TYPE_WLS]; + int rc; + rc = read_property_id(bcdev, pst, WLS_CURR_TX); + if (rc < 0) + return rc; + return scnprintf(buf, PAGE_SIZE, "%d\n", pst->prop[WLS_CURR_TX]); +} +static CLASS_ATTR_RO(wls_curr_tx); +static ssize_t wls_st38_reg_show(struct class *c, struct class_attribute *attr, + char *buf) +{ + struct battery_chg_dev *bcdev = container_of(c, struct battery_chg_dev, + battery_class); + struct psy_state *pst = &bcdev->psy_list[PSY_TYPE_WLS]; + int rc; + rc = read_property_id(bcdev, pst, WLS_ST38_REG); + if (rc < 0) + return rc; + return scnprintf(buf, PAGE_SIZE, "0x%04x\n", pst->prop[WLS_ST38_REG]); +} +static ssize_t wls_st38_reg_store(struct class *c, + struct class_attribute *attr, + const char *buf, size_t count) +{ + struct battery_chg_dev *bcdev = container_of(c, struct battery_chg_dev, + battery_class); + int rc; + u32 val; + if (kstrtou32(buf, 16, &val)) + return -EINVAL; + rc = write_property_id(bcdev, &bcdev->psy_list[PSY_TYPE_WLS], + WLS_ST38_REG, val); + if (rc < 0) + return rc; + return count; +} +static CLASS_ATTR_RW(wls_st38_reg); +static ssize_t wls_st38_data_show(struct class *c, struct class_attribute *attr, + char *buf) +{ + struct battery_chg_dev *bcdev = container_of(c, struct battery_chg_dev, + battery_class); + struct psy_state *pst = &bcdev->psy_list[PSY_TYPE_WLS]; + int rc; + rc = read_property_id(bcdev, pst, WLS_ST38_DATA); + if (rc < 0) + return rc; + return scnprintf(buf, PAGE_SIZE, "0x%04x; %d\n", pst->prop[WLS_ST38_DATA], pst->prop[WLS_ST38_DATA]); +} +static ssize_t wls_st38_data_store(struct class *c, + struct class_attribute *attr, + const char *buf, size_t count) +{ + struct battery_chg_dev *bcdev = container_of(c, struct battery_chg_dev, + battery_class); + int rc; + u32 val; + if (kstrtou32(buf, 0, &val)) + return -EINVAL; + rc = write_property_id(bcdev, &bcdev->psy_list[PSY_TYPE_WLS], + WLS_ST38_DATA, val); + if (rc < 0) + return rc; + return count; +} +static CLASS_ATTR_RW(wls_st38_data); +static ssize_t wls_reverse_status_show(struct class *c, struct class_attribute *attr, + char *buf) +{ + struct battery_chg_dev *bcdev = container_of(c, struct battery_chg_dev, + battery_class); + struct psy_state *pst = &bcdev->psy_list[PSY_TYPE_WLS]; + int rc; + rc = read_property_id(bcdev, pst, WLS_REVERSE_STATUS); + if (rc < 0) + return rc; + return scnprintf(buf, PAGE_SIZE, "0x%x\n", pst->prop[WLS_REVERSE_STATUS]); +} +static CLASS_ATTR_RO(wls_reverse_status); +#endif + static ssize_t charging_enabled_store(struct class *c, struct class_attribute *attr, const char *buf, size_t count) @@ -1847,10 +2138,25 @@ static struct attribute *battery_class_attrs[] = { &class_attr_wireless_fw_version.attr, &class_attr_wireless_fw_crc.attr, &class_attr_ship_mode_en.attr, + &class_attr_usb_charger_en.attr, + &class_attr_charge_power.attr, + &class_attr_slowcharge_en.attr, + &class_attr_usb_charger_en.attr, + &class_attr_charge_power.attr, + &class_attr_slowcharge_en.attr, &class_attr_restrict_chg.attr, &class_attr_restrict_cur.attr, &class_attr_usb_real_type.attr, &class_attr_usb_typec_compliant.attr, + &class_attr_charge_pump_enable.attr, + &class_attr_typec_cc_orientation.attr, +#ifdef CONFIG_STWLC38_FW + &class_attr_wls_volt_tx.attr, + &class_attr_wls_curr_tx.attr, + &class_attr_wls_st38_reg.attr, + &class_attr_wls_st38_data.attr, + &class_attr_wls_reverse_status.attr, +#endif &class_attr_charging_enabled.attr, NULL, }; diff --git a/drivers/soc/qcom/fsa4480-i2c.c b/drivers/soc/qcom/fsa4480-i2c.c index e263d671dc6c..0fef1771b3fc 100644 --- a/drivers/soc/qcom/fsa4480-i2c.c +++ b/drivers/soc/qcom/fsa4480-i2c.c @@ -17,6 +17,7 @@ #define FSA4480_SWITCH_SETTINGS 0x04 #define FSA4480_SWITCH_CONTROL 0x05 +#define FSA4480_SWITCH_STATUS 0X06 #define FSA4480_SWITCH_STATUS1 0x07 #define FSA4480_SLOW_L 0x08 #define FSA4480_SLOW_R 0x09 @@ -27,6 +28,9 @@ #define FSA4480_DELAY_L_MIC 0x0E #define FSA4480_DELAY_L_SENSE 0x0F #define FSA4480_DELAY_L_AGND 0x10 +#define FSA4480_FUNCTION_ENABLE 0X12 +#define FSA4480_JACK_STATUS 0X17 +#define FSA4480_JACK_FLAG 0X18 #define FSA4480_RESET 0x1E struct fsa4480_priv { @@ -227,6 +231,7 @@ static int fsa4480_usbc_analog_setup_switches_ucsi( { int rc = 0; int mode; + int value = 0; struct device *dev; if (!fsa_priv) @@ -241,12 +246,58 @@ static int fsa4480_usbc_analog_setup_switches_ucsi( dev_dbg(dev, "%s: setting GPIOs active = %d\n", __func__, mode != TYPEC_ACCESSORY_NONE); + regmap_write(fsa_priv->regmap, FSA4480_RESET, 0x01); + msleep(1); switch (mode) { /* add all modes FSA should notify for in here */ case TYPEC_ACCESSORY_AUDIO: /* activate switches */ - fsa4480_usbc_update_settings(fsa_priv, 0x00, 0x9F); + regmap_read(fsa_priv->regmap, 0x00, &value); + dev_dbg(fsa_priv->dev, "%s: reg[0x00]=0x%x\n",__func__, value); + if (value == 241) { + dev_dbg(fsa_priv->dev, "%s:DIO headset detection .\n",__func__); + regmap_write(fsa_priv->regmap, FSA4480_SLOW_L, 0x4f); + regmap_read(fsa_priv->regmap, FSA4480_SLOW_L, &value); + dev_dbg(fsa_priv->dev, "%s: reg[0x08]=0x%x\n",__func__, value); + regmap_write(fsa_priv->regmap, FSA4480_SLOW_R, 0x4f); + regmap_read(fsa_priv->regmap, FSA4480_SLOW_R, &value); + dev_dbg(fsa_priv->dev, "%s: reg[0x09]=0x%x\n",__func__, value); + regmap_write(fsa_priv->regmap, FSA4480_SLOW_MIC, 0x4f); + regmap_read(fsa_priv->regmap, FSA4480_SLOW_MIC, &value); + dev_dbg(fsa_priv->dev, "%s: reg[0x0a]=0x%x\n",__func__, value); + regmap_write(fsa_priv->regmap, FSA4480_SLOW_SENSE, 0x4f); + regmap_read(fsa_priv->regmap, FSA4480_SLOW_SENSE, &value); + dev_dbg(fsa_priv->dev, "%s: reg[0x0b]=0x%x\n",__func__, value); + regmap_write(fsa_priv->regmap, FSA4480_SLOW_GND, 0x4f); + regmap_read(fsa_priv->regmap, FSA4480_SLOW_GND, &value); + dev_dbg(fsa_priv->dev, "%s: reg[0x0c]=0x%x\n",__func__, value); + regmap_write(fsa_priv->regmap, FSA4480_FUNCTION_ENABLE, 0x09); + dev_dbg(fsa_priv->dev, "%s: set reg[0x12] done.\n",__func__); + regmap_read(fsa_priv->regmap, FSA4480_FUNCTION_ENABLE, &value); + dev_dbg(fsa_priv->dev, "%s: reg[0x12]=0x%x\n",__func__, value); + msleep(1000); + regmap_read(fsa_priv->regmap, FSA4480_JACK_FLAG, &value); + dev_dbg(fsa_priv->dev, "%s: reg[0x18]=0x%x\n",__func__, value); + msleep(1); + regmap_read(fsa_priv->regmap, FSA4480_JACK_STATUS, &value); + dev_dbg(fsa_priv->dev, "%s: reg[0x17]=0x%x\n",__func__, value); + regmap_read(fsa_priv->regmap, FSA4480_SWITCH_STATUS, &value); + dev_dbg(fsa_priv->dev, "%s: reg[0x6]=0x%x\n",__func__, value); + regmap_read(fsa_priv->regmap, FSA4480_SWITCH_STATUS1, &value); + dev_dbg(fsa_priv->dev, "%s: reg[0x7]=0x%x\n",__func__, value); + } else { + dev_dbg(fsa_priv->dev, "%s:FSA headset detection.\n",__func__); + fsa4480_usbc_update_settings(fsa_priv, 0x00, 0x9F); + regmap_write(fsa_priv->regmap, FSA4480_FUNCTION_ENABLE, 0x01); + dev_dbg(fsa_priv->dev, "%s: set reg[0x12] done.\n",__func__); + regmap_read(fsa_priv->regmap, FSA4480_JACK_STATUS, &value); + dev_dbg(fsa_priv->dev, "%s: reg[0x17]=0x%x\n",__func__, value); + regmap_read(fsa_priv->regmap, FSA4480_SWITCH_STATUS, &value); + dev_dbg(fsa_priv->dev, "%s: reg[0x6]=0x%x\n",__func__, value); + regmap_read(fsa_priv->regmap, FSA4480_SWITCH_STATUS1, &value); + dev_dbg(fsa_priv->dev, "%s: reg[0x7]=0x%x\n",__func__, value); + } /* notify call chain on event */ blocking_notifier_call_chain(&fsa_priv->fsa4480_notifier, @@ -259,6 +310,8 @@ static int fsa4480_usbc_analog_setup_switches_ucsi( /* deactivate switches */ fsa4480_usbc_update_settings(fsa_priv, 0x18, 0x98); + regmap_write(fsa_priv->regmap, FSA4480_FUNCTION_ENABLE, 0x00); + dev_dbg(fsa_priv->dev, "%s: set reg[0x12] reset.\n",__func__); break; default: /* ignore other usb connection modes */ @@ -538,6 +591,9 @@ static int fsa4480_remove(struct i2c_client *i2c) if (!fsa_priv) return -EINVAL; + regmap_write(fsa_priv->regmap, FSA4480_FUNCTION_ENABLE, 0x00); + dev_dbg(fsa_priv->dev, "%s: set reg[0x12] reset.\n",__func__); + if (fsa_priv->use_powersupply) { /* deregister from PMI */ power_supply_unreg_notifier(&fsa_priv->nb); diff --git a/drivers/soc/qcom/icnss2/qmi.c b/drivers/soc/qcom/icnss2/qmi.c index 5290daccb276..d74a27cfef53 100644 --- a/drivers/soc/qcom/icnss2/qmi.c +++ b/drivers/soc/qcom/icnss2/qmi.c @@ -731,6 +731,17 @@ out: return ret; } +void icnss_mac2bd(u8 *localAddr) +{ + int i; + u8 temp; + for (i = 0; i < 3; i++) { + temp = localAddr[i]; + localAddr[i] = localAddr[5-i]; + localAddr[5-i] = temp; + } +} + int icnss_qmi_get_dms_mac(struct icnss_priv *priv) { struct dms_get_mac_address_req_msg_v01 req; @@ -789,6 +800,7 @@ int icnss_qmi_get_dms_mac(struct icnss_priv *priv) } priv->dms.mac_valid = true; memcpy(priv->dms.mac, resp.mac_address, QMI_WLFW_MAC_ADDR_SIZE_V01); + icnss_mac2bd(priv->dms.mac); icnss_pr_info("Received DMS MAC: [%pM]\n", priv->dms.mac); out: return ret;