From: Werner Sembach <wse@tuxedocomputers.com>
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 <wse@tuxedocomputers.com>
Subject: [PATCH v4 2/5] platform/x86/uniwill: Implement USB-C power priority setting
Date: Tue, 3 Mar 2026 23:54:08 +0100 [thread overview]
Message-ID: <20260303225440.504358-3-wse@tuxedocomputers.com> (raw)
In-Reply-To: <20260303225440.504358-1-wse@tuxedocomputers.com>
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.
Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
---
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..22ae5fccd6a06 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)
-#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)
/* 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 = 0,
+ USB_C_POWER_PRIORITY_PERFORMANCE,
+};
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 and state safe */
+ enum usb_c_power_priority_options last_usb_c_power_priority_option;
};
struct uniwill_battery_entry {
@@ -527,6 +535,7 @@ static bool uniwill_writeable_reg(struct device *dev, unsigned 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, unsigned 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, unsigned 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_data *data)
return 0;
}
+static const char * const USB_C_POWER_PRIORITY_TEXT[] = {
+ [USB_C_POWER_PRIORITY_CHARGING] = "charging",
+ [USB_C_POWER_PRIORITY_PERFORMANCE] = "performance",
+};
+
+static const u8 USB_C_POWER_PRIORITY_VALUE[] = {
+ [USB_C_POWER_PRIORITY_CHARGING] = 0,
+ [USB_C_POWER_PRIORITY_PERFORMANCE] = 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 = dev_get_drvdata(dev);
+ enum usb_c_power_priority_options option;
+ unsigned int value;
+ int ret;
+
+ option = sysfs_match_string(USB_C_POWER_PRIORITY_TEXT, buf);
+ if (option < 0)
+ return option;
+
+ value = USB_C_POWER_PRIORITY_VALUE[option];
+
+ guard(mutex)(&data->usb_c_power_priority_lock);
+
+ ret = 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 = option;
+
+ return count;
+}
+
+static ssize_t usb_c_power_priority_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct uniwill_data *data = dev_get_drvdata(dev);
+ unsigned int value;
+ int ret;
+
+ ret = regmap_read(data->regmap, EC_ADDR_USB_C_POWER_PRIORITY, &value);
+ if (ret < 0)
+ return ret;
+
+ value &= USB_C_POWER_PRIORITY;
+
+ if (USB_C_POWER_PRIORITY_VALUE[USB_C_POWER_PRIORITY_PERFORMANCE] == value)
+ 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_PRIORITY_CHARGING]);
+}
+
+static DEVICE_ATTR_RW(usb_c_power_priority);
+
+static int usb_c_power_priority_restore(struct uniwill_data *data)
+{
+ unsigned int value;
+
+ value = USB_C_POWER_PRIORITY_VALUE[data->last_usb_c_power_priority_option];
+
+ 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 = devm_mutex_init(data->dev, &data->usb_c_power_priority_lock);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(data->regmap, EC_ADDR_USB_C_POWER_PRIORITY, &value);
+ if (ret < 0)
+ return ret;
+
+ value &= USB_C_POWER_PRIORITY;
+
+ data->last_usb_c_power_priority_option =
+ USB_C_POWER_PRIORITY_VALUE[USB_C_POWER_PRIORITY_PERFORMANCE] == value ?
+ USB_C_POWER_PRIORITY_PERFORMANCE :
+ USB_C_POWER_PRIORITY_CHARGING;
+
+ return 0;
+}
+
static struct attribute *uniwill_attrs[] = {
/* Keyboard-related */
&dev_attr_fn_lock.attr,
@@ -893,6 +1002,7 @@ static struct attribute *uniwill_attrs[] = {
&dev_attr_breathing_in_suspend.attr,
/* Power-management-related */
&dev_attr_ctgp_offset.attr,
+ &dev_attr_usb_c_power_priority.attr,
NULL
};
@@ -927,6 +1037,11 @@ static umode_t uniwill_attr_is_visible(struct kobject *kobj, struct attribute *a
return attr->mode;
}
+ if (attr == &dev_attr_usb_c_power_priority.attr) {
+ if (uniwill_device_supports(data, UNIWILL_FEATURE_USB_C_POWER_PRIORITY))
+ return attr->mode;
+ }
+
return 0;
}
@@ -1417,11 +1532,10 @@ static int uniwill_notifier_call(struct notifier_block *nb, unsigned long action
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;
- 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,10 +1629,15 @@ static int uniwill_probe(struct platform_device *pdev)
return PTR_ERR(regmap);
data->regmap = regmap;
+
ret = devm_mutex_init(&pdev->dev, &data->super_key_lock);
if (ret < 0)
return ret;
+ ret = usb_c_power_priority_init(data);
+ if (ret < 0)
+ return ret;
+
ret = uniwill_ec_init(data);
if (ret < 0)
return ret;
@@ -1681,6 +1800,14 @@ static int uniwill_resume_nvidia_ctgp(struct uniwill_data *data)
CTGP_DB_DB_ENABLE | CTGP_DB_CTGP_ENABLE);
}
+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 = dev_get_drvdata(dev);
@@ -1704,7 +1831,11 @@ static int uniwill_resume(struct device *dev)
if (ret < 0)
return ret;
- return uniwill_resume_nvidia_ctgp(data);
+ ret = uniwill_resume_nvidia_ctgp(data);
+ if (ret < 0)
+ return ret;
+
+ return uniwill_resume_usb_c_power_priority(data);
}
static DEFINE_SIMPLE_DEV_PM_OPS(uniwill_pm_ops, uniwill_suspend, uniwill_resume);
--
2.43.0
next prev parent reply other threads:[~2026-03-03 22:54 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-03 22:54 [PATCH v4 0/5] platform/x86/uniwill: More support for TUXEDO devices Werner Sembach
2026-03-03 22:54 ` [PATCH v4 1/5] platform/x86/uniwill: uniwill-laptop: Rework hwmon feature defines Werner Sembach
2026-03-03 22:58 ` Werner Sembach
2026-03-03 22:54 ` Werner Sembach [this message]
2026-03-07 15:52 ` [PATCH v4 2/5] platform/x86/uniwill: Implement USB-C power priority setting Armin Wolf
2026-03-03 22:54 ` [PATCH v4 3/5] platform/x86/uniwill: Apply features across all TUXEDO devices Werner Sembach
2026-03-03 22:54 ` [PATCH v4 4/5] platform/x86/uniwill: Readd Schenker system vendor for XMG FUSION Werner Sembach
2026-03-07 15:56 ` Armin Wolf
2026-03-03 22:54 ` [PATCH v4 5/5] Documentation: laptops: Update documentation for uniwill laptops Werner Sembach
2026-03-03 23:05 ` Randy Dunlap
2026-03-10 22:34 ` Werner Sembach
2026-03-04 8:31 ` kernel test robot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260303225440.504358-3-wse@tuxedocomputers.com \
--to=wse@tuxedocomputers.com \
--cc=W_Armin@gmx.de \
--cc=hansg@kernel.org \
--cc=ilpo.jarvinen@linux.intel.com \
--cc=linux-kernel@vger.kernel.org \
--cc=platform-driver-x86@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.