From nobody Fri Apr 3 14:18:12 2026 Received: from mail.tuxedocomputers.com (mail.tuxedocomputers.com [157.90.84.7]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 03C34347FEA; Tue, 24 Mar 2026 20:34:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=157.90.84.7 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774384461; cv=none; b=jJBR6GmAEKxjvoDHsG/Q12LfADh1gr34xYugzUH8kiOAJOUkqHC1ZzqNnD47fsXI/GlMOJ75VfE4IxiJJoACrqU1C8tTId5ro7dRbZtckkMcj6d7I2IGs4qxWG4dENzZPspSph/ghS+TZMQQS3AOs660lso7hIk67f/6aVeMXX8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774384461; c=relaxed/simple; bh=3eMWHDSTktvj/cyi71V9F32r+0PgsLZoGqNn4bx1MKQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=lQD9xa40iy+4C11bbel2EmsTU0nLEfDbqfaMNVRSg0/wSuCEiNH7tpjqNEYZOCmpvrxaKlLcy6FL22ridIG0qjgcabcWiXNABg8peJXo2QNB9vEwFpDiOK1n4ypg/qRpx0WUcT8ikDK3Ufri05ykPdRDq8/Wm764CgtfOJi3RGE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=tuxedocomputers.com; spf=pass smtp.mailfrom=tuxedocomputers.com; dkim=pass (1024-bit key) header.d=tuxedocomputers.com header.i=@tuxedocomputers.com header.b=ZHevLUCA; arc=none smtp.client-ip=157.90.84.7 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=tuxedocomputers.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=tuxedocomputers.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=tuxedocomputers.com header.i=@tuxedocomputers.com header.b="ZHevLUCA" Received: from wse-pc.fritz.box (i5C75F50F.versanet.de [92.117.245.15]) (Authenticated sender: wse@tuxedocomputers.com) by mail.tuxedocomputers.com (Postfix) with ESMTPA id 5EDEA2FC0219; Tue, 24 Mar 2026 21:34:18 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tuxedocomputers.com; s=default; t=1774384458; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=9KbxUO0FX3zZS7w/BleYrxDeFt1SU62P42wYkxct2yc=; b=ZHevLUCAQ54DCxl/g0I1zHIB11pXAqyM4hyTV7Ju9qlpXQTQEKgoy91hfKwRbBwpbGtYjA aJI5OQhQdDteTonLLcVDL/DkVAuIZNU+phwJRN/qXLQq/lJwAICrrYVxzmy1FVsN0eyHic nwGVYLFbbQ/gtlzRXzvx2Wn1s6ogz/8= Authentication-Results: mail.tuxedocomputers.com; auth=pass smtp.auth=wse@tuxedocomputers.com smtp.mailfrom=wse@tuxedocomputers.com From: Werner Sembach To: W_Armin@gmx.de, hansg@kernel.org, ilpo.jarvinen@linux.intel.com Cc: platform-driver-x86@vger.kernel.org, linux-kernel@vger.kernel.org, Werner Sembach Subject: [PATCH v8 2/5] platform/x86: uniwill-laptop: Implement USB-C power priority setting Date: Tue, 24 Mar 2026 21:32:09 +0100 Message-ID: <20260324203413.454361-3-wse@tuxedocomputers.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260324203413.454361-1-wse@tuxedocomputers.com> References: <20260324203413.454361-1-wse@tuxedocomputers.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" On some devices Uniwill offers the option to set the USB-C port to prioritise charging or performance. This patch exposes this setting to the userspace via sysfs for all TUXEDO devices supporting it. Reviewed-by: Armin Wolf Signed-off-by: Werner Sembach --- drivers/platform/x86/uniwill/uniwill-acpi.c | 145 +++++++++++++++++++- 1 file changed, 138 insertions(+), 7 deletions(-) diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform= /x86/uniwill/uniwill-acpi.c index 048b265bff374..48bdf43b4cb53 100644 --- a/drivers/platform/x86/uniwill/uniwill-acpi.c +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c @@ -266,8 +266,8 @@ #define BATTERY_CHARGE_FULL_OVER_24H BIT(3) #define BATTERY_ERM_STATUS_REACHED BIT(4) =20 -#define EC_ADDR_CHARGE_PRIO 0x07CC -#define CHARGING_PERFORMANCE BIT(7) +#define EC_ADDR_USB_C_POWER_PRIORITY 0x07CC +#define USB_C_POWER_PRIORITY BIT(7) =20 /* Same bits as EC_ADDR_LIGHTBAR_AC_CTRL except LIGHTBAR_S3_OFF */ #define EC_ADDR_LIGHTBAR_BAT_CTRL 0x07E2 @@ -324,6 +324,12 @@ #define UNIWILL_FEATURE_PRIMARY_FAN BIT(7) #define UNIWILL_FEATURE_SECONDARY_FAN BIT(8) #define UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL BIT(9) +#define UNIWILL_FEATURE_USB_C_POWER_PRIORITY BIT(10) + +enum usb_c_power_priority_options { + USB_C_POWER_PRIORITY_CHARGING =3D 0, + USB_C_POWER_PRIORITY_PERFORMANCE, +}; =20 struct uniwill_data { struct device *dev; @@ -343,6 +349,8 @@ struct uniwill_data { struct mutex input_lock; /* Protects input sequence during notify */ struct input_dev *input_device; struct notifier_block nb; + struct mutex usb_c_power_priority_lock; /* Protects dependent bit write a= nd state safe */ + enum usb_c_power_priority_options last_usb_c_power_priority_option; }; =20 struct uniwill_battery_entry { @@ -527,6 +535,7 @@ static bool uniwill_writeable_reg(struct device *dev, u= nsigned int reg) case EC_ADDR_CTGP_DB_CTGP_OFFSET: case EC_ADDR_CTGP_DB_TPP_OFFSET: case EC_ADDR_CTGP_DB_DB_OFFSET: + case EC_ADDR_USB_C_POWER_PRIORITY: return true; default: return false; @@ -565,6 +574,7 @@ static bool uniwill_readable_reg(struct device *dev, un= signed int reg) case EC_ADDR_CTGP_DB_CTGP_OFFSET: case EC_ADDR_CTGP_DB_TPP_OFFSET: case EC_ADDR_CTGP_DB_DB_OFFSET: + case EC_ADDR_USB_C_POWER_PRIORITY: return true; default: return false; @@ -587,6 +597,7 @@ static bool uniwill_volatile_reg(struct device *dev, un= signed int reg) case EC_ADDR_TRIGGER: case EC_ADDR_SWITCH_STATUS: case EC_ADDR_CHARGE_CTRL: + case EC_ADDR_USB_C_POWER_PRIORITY: return true; default: return false; @@ -883,6 +894,104 @@ static int uniwill_nvidia_ctgp_init(struct uniwill_da= ta *data) return 0; } =20 +static const char * const usb_c_power_priority_text[] =3D { + [USB_C_POWER_PRIORITY_CHARGING] =3D "charging", + [USB_C_POWER_PRIORITY_PERFORMANCE] =3D "performance", +}; + +static const u8 usb_c_power_priority_value[] =3D { + [USB_C_POWER_PRIORITY_CHARGING] =3D 0, + [USB_C_POWER_PRIORITY_PERFORMANCE] =3D USB_C_POWER_PRIORITY, +}; + +static ssize_t usb_c_power_priority_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct uniwill_data *data =3D dev_get_drvdata(dev); + enum usb_c_power_priority_options option; + unsigned int value; + int ret; + + option =3D sysfs_match_string(usb_c_power_priority_text, buf); + if (option < 0) + return option; + + value =3D usb_c_power_priority_value[option]; + + guard(mutex)(&data->usb_c_power_priority_lock); + + ret =3D regmap_update_bits(data->regmap, EC_ADDR_USB_C_POWER_PRIORITY, + USB_C_POWER_PRIORITY, value); + if (ret < 0) + return ret; + + data->last_usb_c_power_priority_option =3D option; + + return count; +} + +static ssize_t usb_c_power_priority_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct uniwill_data *data =3D dev_get_drvdata(dev); + unsigned int value; + int ret; + + ret =3D regmap_read(data->regmap, EC_ADDR_USB_C_POWER_PRIORITY, &value); + if (ret < 0) + return ret; + + value &=3D USB_C_POWER_PRIORITY; + + if (usb_c_power_priority_value[USB_C_POWER_PRIORITY_PERFORMANCE] =3D=3D v= alue) + return sysfs_emit(buf, "%s\n", + usb_c_power_priority_text[USB_C_POWER_PRIORITY_PERFORMANCE]); + + return sysfs_emit(buf, "%s\n", usb_c_power_priority_text[USB_C_POWER_PRIO= RITY_CHARGING]); +} + +static DEVICE_ATTR_RW(usb_c_power_priority); + +static int usb_c_power_priority_restore(struct uniwill_data *data) +{ + unsigned int value; + + value =3D usb_c_power_priority_value[data->last_usb_c_power_priority_opti= on]; + + guard(mutex)(&data->usb_c_power_priority_lock); + + return regmap_update_bits(data->regmap, EC_ADDR_USB_C_POWER_PRIORITY, + USB_C_POWER_PRIORITY, value); +} + +static int usb_c_power_priority_init(struct uniwill_data *data) +{ + unsigned int value; + int ret; + + if (!uniwill_device_supports(data, UNIWILL_FEATURE_USB_C_POWER_PRIORITY)) + return 0; + + ret =3D devm_mutex_init(data->dev, &data->usb_c_power_priority_lock); + if (ret < 0) + return ret; + + ret =3D regmap_read(data->regmap, EC_ADDR_USB_C_POWER_PRIORITY, &value); + if (ret < 0) + return ret; + + value &=3D USB_C_POWER_PRIORITY; + + data->last_usb_c_power_priority_option =3D + usb_c_power_priority_value[USB_C_POWER_PRIORITY_PERFORMANCE] =3D=3D valu= e ? + USB_C_POWER_PRIORITY_PERFORMANCE : + USB_C_POWER_PRIORITY_CHARGING; + + return 0; +} + static struct attribute *uniwill_attrs[] =3D { /* Keyboard-related */ &dev_attr_fn_lock.attr, @@ -893,6 +1002,7 @@ static struct attribute *uniwill_attrs[] =3D { &dev_attr_breathing_in_suspend.attr, /* Power-management-related */ &dev_attr_ctgp_offset.attr, + &dev_attr_usb_c_power_priority.attr, NULL }; =20 @@ -927,6 +1037,11 @@ static umode_t uniwill_attr_is_visible(struct kobject= *kobj, struct attribute *a return attr->mode; } =20 + if (attr =3D=3D &dev_attr_usb_c_power_priority.attr) { + if (uniwill_device_supports(data, UNIWILL_FEATURE_USB_C_POWER_PRIORITY)) + return attr->mode; + } + return 0; } =20 @@ -1417,11 +1532,10 @@ static int uniwill_notifier_call(struct notifier_bl= ock *nb, unsigned long action =20 return NOTIFY_OK; case UNIWILL_OSD_DC_ADAPTER_CHANGED: - /* noop for the time being, will change once charging priority - * gets implemented. - */ + if (!uniwill_device_supports(data, UNIWILL_FEATURE_USB_C_POWER_PRIORITY)) + return NOTIFY_DONE; =20 - return NOTIFY_OK; + return notifier_from_errno(usb_c_power_priority_restore(data)); case UNIWILL_OSD_FN_LOCK: if (!uniwill_device_supports(data, UNIWILL_FEATURE_FN_LOCK)) return NOTIFY_DONE; @@ -1515,6 +1629,7 @@ static int uniwill_probe(struct platform_device *pdev) return PTR_ERR(regmap); =20 data->regmap =3D regmap; + ret =3D devm_mutex_init(&pdev->dev, &data->super_key_lock); if (ret < 0) return ret; @@ -1552,6 +1667,10 @@ static int uniwill_probe(struct platform_device *pde= v) if (ret < 0) return ret; =20 + ret =3D usb_c_power_priority_init(data); + if (ret < 0) + return ret; + return uniwill_input_init(data); } =20 @@ -1681,6 +1800,14 @@ static int uniwill_resume_nvidia_ctgp(struct uniwill= _data *data) CTGP_DB_DB_ENABLE | CTGP_DB_CTGP_ENABLE); } =20 +static int uniwill_resume_usb_c_power_priority(struct uniwill_data *data) +{ + if (!uniwill_device_supports(data, UNIWILL_FEATURE_USB_C_POWER_PRIORITY)) + return 0; + + return usb_c_power_priority_restore(data); +} + static int uniwill_resume(struct device *dev) { struct uniwill_data *data =3D dev_get_drvdata(dev); @@ -1704,7 +1831,11 @@ static int uniwill_resume(struct device *dev) if (ret < 0) return ret; =20 - return uniwill_resume_nvidia_ctgp(data); + ret =3D uniwill_resume_nvidia_ctgp(data); + if (ret < 0) + return ret; + + return uniwill_resume_usb_c_power_priority(data); } =20 static DEFINE_SIMPLE_DEV_PM_OPS(uniwill_pm_ops, uniwill_suspend, uniwill_r= esume); --=20 2.43.0