From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: MCC45TR Date: Tue, 25 Aug 2026 17:32:03 +0300 Subject: [PATCH 10/21] nabu: port DT2W, stable refresh switching and charging fixes to 7.2 --- .../boot/dts/qcom/sm8150-xiaomi-nabu.dts | 2 + drivers/gpu/drm/panel/panel-novatek-nt36523.c | 22 +++-- drivers/input/touchscreen/nt36523/nt36xxx.c | 82 ++++++++++++++++--- drivers/input/touchscreen/nt36523/nt36xxx.h | 4 +- drivers/power/supply/qcom_fg.c | 23 ++++-- 5 files changed, 107 insertions(+), 26 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sm8150-xiaomi-nabu.dts b/arch/arm64/boot/dts/qcom/sm8150-xiaomi-nabu.dts index 2b65e5da205b..c1fe5e0e020f 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-xiaomi-nabu.dts +++ b/arch/arm64/boot/dts/qcom/sm8150-xiaomi-nabu.dts @@ -854,6 +854,8 @@ touchscreen@0 { novatek,pen-support; novatek,wgp-stylus; + wakeup-source; + novatek,double-tap-to-wake; /* 523 */ novatek,swrst-n8-addr = <0x03F0FE>; diff --git a/drivers/gpu/drm/panel/panel-novatek-nt36523.c b/drivers/gpu/drm/panel/panel-novatek-nt36523.c index a5ecce82b834..755b71826045 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt36523.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt36523.c @@ -1264,20 +1264,26 @@ static int nt36523_sync_pen_fps(struct panel_info *pinfo, bool panel_init) "no pen synchronization command for %u Hz\n", pinfo->refresh_rate); + /* + * Xiaomi only provides TDDI scan commands for the stock 60 and 120 Hz + * modes. Writing either vendor value while the additional 90 Hz VFP + * timing is active resets the NVT firmware. Keep its current scan band + * at 90 Hz; boot initialization is 120 Hz and 60/120 retain the exact + * downstream commands. + */ + if (pinfo->refresh_rate == 90) { + dev_info(pinfo->panel.dev, + "kept existing touch scan band for 90 Hz\n"); + return 0; + } + /* Xiaomi's downstream panel commands synchronize the TDDI scan rate. */ mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xff, 0x2a); /* The vendor's live sync sequence omits the page-unlock write. */ if (panel_init) mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0xfb, 0x01); - /* - * Xiaomi only defines TDDI scan bands for the stock 60 and 120 Hz - * modes. Nabu's additional 90 Hz VFP mode must use the lower band: - * issuing the 120 Hz value (0x0d) after the 90 Hz timing latch resets - * the NVT touch firmware and leaves the compositor confirmation dialog - * without touch input. - */ - if (pinfo->refresh_rate == 60 || pinfo->refresh_rate == 90) + if (pinfo->refresh_rate == 60) mipi_dsi_dual_dcs_write_seq_multi(dsi_ctx, dsi0, dsi1, 0x23, 0x0c); else diff --git a/drivers/input/touchscreen/nt36523/nt36xxx.c b/drivers/input/touchscreen/nt36523/nt36xxx.c index 46cc0dd60c88..3d31d2268356 100644 --- a/drivers/input/touchscreen/nt36523/nt36xxx.c +++ b/drivers/input/touchscreen/nt36523/nt36xxx.c @@ -54,6 +54,10 @@ static int nvt_drm_notifier_callback(struct notifier_block *self, unsigned long static int32_t nvt_ts_suspend(struct device *dev); static int32_t nvt_ts_resume(struct device *dev); +#define GESTURE_DOUBLE_CLICK 15 +#define DATA_PROTOCOL 30 +#define FUNCPAGE_GESTURE 1 + uint32_t ENG_RST_ADDR = 0x7FFF80; uint32_t SWRST_N8_ADDR = 0; //read from dtsi uint32_t SPI_RD_FAST_ADDR = 0; //read from dtsi @@ -686,6 +690,16 @@ static int32_t nvt_parse_dt(struct device *dev) ts->wgp_stylus = of_property_read_bool(np, "novatek,wgp-stylus"); NVT_LOG("novatek,wgp-stylus=%d\n", ts->wgp_stylus); + ts->wakeup_source = of_property_read_bool(np, "wakeup-source"); + ts->db_wakeup = of_property_read_bool(np, + "novatek,double-tap-to-wake"); + if (ts->db_wakeup && !ts->wakeup_source) { + NVT_ERR("double tap requested without wakeup-source; disabling\n"); + ts->db_wakeup = 0; + } + NVT_LOG("double-tap-to-wake=%d, wakeup-source=%d\n", + ts->db_wakeup, ts->wakeup_source); + ret = of_property_read_u32(np, "novatek,swrst-n8-addr", &SWRST_N8_ADDR); if (ret) { NVT_ERR("error reading novatek,swrst-n8-addr. ret=%d\n", ret); @@ -1000,6 +1014,30 @@ static irqreturn_t nvt_ts_work_func(int irq, void *data) goto XFER_ERROR; } + /* + * In low-power gesture mode the first report byte carries the gesture + * identifier rather than a finger slot. Nabu firmware reports double + * tap either directly as ID 15 or through protocol page 1. + */ + if (!bTouchIsAwake && ts->db_wakeup) { + uint8_t gesture_id = point_data[1] >> 3; + + if (gesture_id == DATA_PROTOCOL && + point_data[2] == FUNCPAGE_GESTURE) + gesture_id = point_data[3]; + + if (gesture_id == GESTURE_DOUBLE_CLICK) { + NVT_LOG("Gesture: double tap wakeup\n"); + pm_wakeup_event(&ts->client->dev, 5000); + input_report_key(ts->input_dev, KEY_WAKEUP, 1); + input_sync(ts->input_dev); + input_report_key(ts->input_dev, KEY_WAKEUP, 0); + input_sync(ts->input_dev); + } + + goto XFER_ERROR; + } + finger_cnt = 0; for (i = 0; i < ts->max_touch_num; i++) { @@ -1348,7 +1386,6 @@ static int32_t nvt_ts_probe(struct spi_device *client) ts->input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); ts->input_dev->propbit[0] = BIT(INPUT_PROP_DIRECT); - ts->db_wakeup = 0; ts->fw_ver = 0; ts->x_num = 32; ts->y_num = 50; @@ -1390,6 +1427,7 @@ static int32_t nvt_ts_probe(struct spi_device *client) ts->input_dev->name = NVT_TS_NAME; ts->input_dev->phys = ts->phys; ts->input_dev->id.bustype = BUS_SPI; + input_set_capability(ts->input_dev, EV_KEY, KEY_WAKEUP); //---register input device--- ret = input_register_device(ts->input_dev); @@ -1520,6 +1558,13 @@ static int32_t nvt_ts_probe(struct spi_device *client) } #endif + ret = device_init_wakeup(&client->dev, ts->wakeup_source); + if (ret) { + NVT_ERR("failed to initialize wakeup source: %d\n", ret); + ts->wakeup_source = false; + ts->db_wakeup = 0; + } + bTouchIsAwake = 1; disable_pen_input_device(false); NVT_LOG("end\n"); @@ -1617,6 +1662,9 @@ static void nvt_ts_remove(struct spi_device *client) #endif nvt_irq_enable(false); + if (ts->irq_wake_enabled) + disable_irq_wake(client->irq); + device_init_wakeup(&client->dev, false); free_irq(client->irq, ts); mutex_destroy(&ts->xbuf_lock); @@ -1649,6 +1697,10 @@ static void nvt_ts_shutdown(struct spi_device *client) NVT_LOG("Shutdown driver...\n"); nvt_irq_enable(false); + if (ts->irq_wake_enabled) { + disable_irq_wake(client->irq); + ts->irq_wake_enabled = false; + } #ifdef CONFIG_DRM if (mi_drm_unregister_client(&ts->drm_notif)) @@ -1715,15 +1767,14 @@ static int32_t nvt_ts_suspend(struct device *dev) if (ts->db_wakeup) { /*---write command to enter "wakeup gesture mode"---*/ - /*DoubleClick wakeup CMD was sent by display to meet timing*/ - /* buf[0] = EVENT_MAP_HOST_CMD; buf[1] = 0x13; - CTP_SPI_WRITE(ts->client, buf, 2); - */ - enable_irq_wake(ts->client->irq); - - NVT_LOG("Enabled touch wakeup gesture\n"); + if (CTP_SPI_WRITE(ts->client, buf, 2) < 0) { + NVT_ERR("failed to enter wakeup gesture mode\n"); + nvt_irq_enable(false); + } else { + NVT_LOG("Enabled touch wakeup gesture\n"); + } } else { /*---write command to enter "deep sleep mode"---*/ buf[0] = EVENT_MAP_HOST_CMD; @@ -1794,7 +1845,7 @@ static int32_t nvt_ts_resume(struct device *dev) nvt_check_fw_reset_state(RESET_STATE_REK); - if (!ts->db_wakeup && !ts->irq_enabled) { + if (!ts->irq_enabled) { nvt_irq_enable(true); } @@ -1857,9 +1908,15 @@ static int nvt_drm_notifier_callback(struct notifier_block *self, unsigned long static int nvt_pm_suspend(struct device *dev) { - if (device_may_wakeup(dev) && ts->db_wakeup) { + int ret; + + if (device_may_wakeup(dev) && ts->db_wakeup && + !ts->irq_wake_enabled) { NVT_LOG("enable touch irq wake\n"); - enable_irq_wake(ts->client->irq); + ret = enable_irq_wake(ts->client->irq); + if (ret) + return ret; + ts->irq_wake_enabled = true; } ts->dev_pm_suspend = true; reinit_completion(&ts->dev_pm_suspend_completion); @@ -1869,9 +1926,10 @@ static int nvt_pm_suspend(struct device *dev) static int nvt_pm_resume(struct device *dev) { - if (device_may_wakeup(dev) && ts->db_wakeup) { + if (ts->irq_wake_enabled) { NVT_LOG("disable touch irq wake\n"); disable_irq_wake(ts->client->irq); + ts->irq_wake_enabled = false; } ts->dev_pm_suspend = false; complete(&ts->dev_pm_suspend_completion); diff --git a/drivers/input/touchscreen/nt36523/nt36xxx.h b/drivers/input/touchscreen/nt36523/nt36xxx.h index 530d3661365d..489b5d780761 100644 --- a/drivers/input/touchscreen/nt36523/nt36xxx.h +++ b/drivers/input/touchscreen/nt36523/nt36xxx.h @@ -169,6 +169,8 @@ struct nvt_ts_data { int panel_index; uint32_t spi_max_freq; int db_wakeup; + bool wakeup_source; + bool irq_wake_enabled; uint8_t debug_flag; bool fw_debug; bool dev_pm_suspend; @@ -241,4 +243,4 @@ void Boot_Update_Firmware(struct work_struct *work); extern void nvt_esd_check_enable(uint8_t enable); #endif /* #if NVT_TOUCH_ESD_PROTECT */ -#endif /* _LINUX_NVT_TOUCH_H */ \ No newline at end of file +#endif /* _LINUX_NVT_TOUCH_H */ diff --git a/drivers/power/supply/qcom_fg.c b/drivers/power/supply/qcom_fg.c index 1282d9519ea8..7ddb2b7ac4be 100644 --- a/drivers/power/supply/qcom_fg.c +++ b/drivers/power/supply/qcom_fg.c @@ -926,9 +926,14 @@ static int qcom_fg_get_property(struct power_supply *psy, val->intval = POWER_SUPPLY_STATUS_UNKNOWN; break; } - if (temp < 0) + /* + * qcom_fg_get_current() follows the PSY convention: + * positive current charges the battery, negative current + * discharges it. + */ + if (temp > 0) val->intval = POWER_SUPPLY_STATUS_CHARGING; - else if (temp > 0) + else if (temp < 0) val->intval = POWER_SUPPLY_STATUS_DISCHARGING; else val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; @@ -1129,10 +1134,11 @@ static int qcom_fg_notifier_call(struct notifier_block *nb, unsigned long val, if (psy == chip->chg_psy) { ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_STATUS, &propval); - if (ret) + if (ret) { chip->status = POWER_SUPPLY_STATUS_UNKNOWN; - - chip->status = propval.intval; + } else { + chip->status = propval.intval; + } power_supply_changed(chip->batt_psy); @@ -1335,9 +1341,16 @@ static int qcom_fg_probe(struct platform_device *pdev) } if (chip->chg_psy) { + union power_supply_propval propval; + INIT_DELAYED_WORK(&chip->status_changed_work, qcom_fg_status_changed_worker); + ret = power_supply_get_property(chip->chg_psy, + POWER_SUPPLY_PROP_STATUS, + &propval); + chip->status = ret ? POWER_SUPPLY_STATUS_UNKNOWN : propval.intval; + chip->nb.notifier_call = qcom_fg_notifier_call; ret = power_supply_reg_notifier(&chip->nb); if (ret) {