mirror of
https://github.com/torvalds/linux.git
synced 2026-09-24 06:24:02 +02:00
platform/x86: uniwill-laptop: Add support for USB powershare
Some devices support a "USB powershare" feature where the system will continue to provide power via the USB ports when hibernating or powered off. Add support for this feaure. Signed-off-by: Armin Wolf <W_Armin@gmx.de> Link: https://patch.msgid.link/20260530170813.10166-5-W_Armin@gmx.de Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
This commit is contained in:
parent
c393505bab
commit
e02c8d7a19
|
|
@ -86,6 +86,20 @@ Contact: Armin Wolf <W_Armin@gmx.de>
|
|||
Description:
|
||||
Allows userspace applications to configure if the device should boot automatically
|
||||
when being connected to a power source. Writing "1"/"0" into this file
|
||||
enables/disables this functionality.
|
||||
enables/disables this functionality. Enabling both AC auto boot and USB powershare
|
||||
at the same time is not supported.
|
||||
|
||||
Reading this file returns the current status of the AC auto boot functionality.
|
||||
|
||||
What: /sys/bus/platform/devices/INOU0000:XX/usb_powershare_high
|
||||
Date: March 2026
|
||||
KernelVersion: 7.1
|
||||
Contact: Armin Wolf <W_Armin@gmx.de>
|
||||
Description:
|
||||
Allows userspace applications to configure if the device should continue to provide
|
||||
power via the USB ports when hibernating or powered off. Might also increase the
|
||||
power budget available to USB ports on some devices. Writing "1"/"0" into this
|
||||
file enables/disables this functionality. Enabling both USB powershare and AC auto
|
||||
boot at the same time is not supported.
|
||||
|
||||
Reading this file returns the current status of the USB powershare functionality.
|
||||
|
|
|
|||
|
|
@ -105,6 +105,13 @@ The ``uniwill-laptop`` driver allows the user to configure if the system should
|
|||
boot when being connected to a power source, see
|
||||
Documentation/ABI/testing/sysfs-driver-uniwill-laptop for details.
|
||||
|
||||
USB Powershare
|
||||
--------------
|
||||
|
||||
The ``uniwill-laptop`` driver allows the user to configure if the system should continue to
|
||||
provide power via the USB ports when hibernating or powered off, see
|
||||
Documentation/ABI/testing/sysfs-driver-uniwill-laptop for details.
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
|
|
|
|||
|
|
@ -368,6 +368,7 @@
|
|||
#define UNIWILL_FEATURE_USB_C_POWER_PRIORITY BIT(11)
|
||||
#define UNIWILL_FEATURE_KEYBOARD_BACKLIGHT BIT(12)
|
||||
#define UNIWILL_FEATURE_AC_AUTO_BOOT BIT(13)
|
||||
#define UNIWILL_FEATURE_USB_POWERSHARE BIT(14)
|
||||
|
||||
enum usb_c_power_priority_options {
|
||||
USB_C_POWER_PRIORITY_CHARGING = 0,
|
||||
|
|
@ -393,6 +394,7 @@ struct uniwill_data {
|
|||
bool last_fn_lock_state;
|
||||
bool last_super_key_enable_state;
|
||||
bool last_touchpad_toggle_enable_state;
|
||||
bool last_usb_powershare_high_state;
|
||||
struct mutex super_key_lock; /* Protects the toggling of the super key lock state */
|
||||
struct list_head batteries;
|
||||
struct mutex led_lock; /* Protects writes to the lightbar registers */
|
||||
|
|
@ -1181,6 +1183,70 @@ static ssize_t ac_auto_boot_show(struct device *dev, struct device_attribute *at
|
|||
|
||||
static DEVICE_ATTR_RW(ac_auto_boot);
|
||||
|
||||
static int uniwill_write_usb_powershare_high(struct uniwill_data *data, bool status)
|
||||
{
|
||||
unsigned int value;
|
||||
|
||||
if (status)
|
||||
value = TRIGGER_USB_CHARGING;
|
||||
else
|
||||
value = 0;
|
||||
|
||||
/*
|
||||
* Normaly this RMW-sequence could also trigger the super key toggle,
|
||||
* but the EC seems to take care that those bits are always read as 0.
|
||||
*/
|
||||
return regmap_update_bits(data->regmap, EC_ADDR_TRIGGER, TRIGGER_USB_CHARGING, value);
|
||||
}
|
||||
|
||||
static ssize_t usb_powershare_high_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct uniwill_data *data = dev_get_drvdata(dev);
|
||||
bool enable;
|
||||
int ret;
|
||||
|
||||
ret = kstrtobool(buf, &enable);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = uniwill_write_usb_powershare_high(data, enable);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int uniwill_read_usb_powershare_high(struct uniwill_data *data, bool *status)
|
||||
{
|
||||
unsigned int value;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(data->regmap, EC_ADDR_TRIGGER, &value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
*status = !!(value & TRIGGER_USB_CHARGING);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t usb_powershare_high_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct uniwill_data *data = dev_get_drvdata(dev);
|
||||
bool status;
|
||||
int ret;
|
||||
|
||||
ret = uniwill_read_usb_powershare_high(data, &status);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sysfs_emit(buf, "%d\n", status);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(usb_powershare_high);
|
||||
|
||||
static struct attribute *uniwill_attrs[] = {
|
||||
/* Keyboard-related */
|
||||
&dev_attr_fn_lock.attr,
|
||||
|
|
@ -1193,6 +1259,7 @@ static struct attribute *uniwill_attrs[] = {
|
|||
&dev_attr_ctgp_offset.attr,
|
||||
&dev_attr_usb_c_power_priority.attr,
|
||||
&dev_attr_ac_auto_boot.attr,
|
||||
&dev_attr_usb_powershare_high.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
@ -1237,6 +1304,11 @@ static umode_t uniwill_attr_is_visible(struct kobject *kobj, struct attribute *a
|
|||
return attr->mode;
|
||||
}
|
||||
|
||||
if (attr == &dev_attr_usb_powershare_high.attr) {
|
||||
if (uniwill_device_supports(data, UNIWILL_FEATURE_USB_POWERSHARE))
|
||||
return attr->mode;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -2382,6 +2454,18 @@ static int uniwill_suspend_kbd_led(struct uniwill_data *data)
|
|||
return regmap_write(data->regmap, EC_ADDR_KBD_STATUS, regval);
|
||||
}
|
||||
|
||||
static int uniwill_suspend_usb_powershare(struct uniwill_data *data)
|
||||
{
|
||||
if (!uniwill_device_supports(data, UNIWILL_FEATURE_USB_POWERSHARE))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* EC_ADDR_TRIGGER is marked as volatile, so we have to restore it
|
||||
* ourselves.
|
||||
*/
|
||||
return uniwill_read_usb_powershare_high(data, &data->last_usb_powershare_high_state);
|
||||
}
|
||||
|
||||
static int uniwill_suspend_nvidia_ctgp(struct uniwill_data *data)
|
||||
{
|
||||
if (!uniwill_device_supports(data, UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL))
|
||||
|
|
@ -2416,6 +2500,10 @@ static int uniwill_suspend(struct device *dev)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = uniwill_suspend_usb_powershare(data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = uniwill_suspend_nvidia_ctgp(data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
|
@ -2479,6 +2567,14 @@ static int uniwill_resume_kbd_led(struct uniwill_data *data)
|
|||
return regmap_write_bits(data->regmap, EC_ADDR_TRIGGER, RGB_APPLY_COLOR, RGB_APPLY_COLOR);
|
||||
}
|
||||
|
||||
static int uniwill_resume_usb_powershare(struct uniwill_data *data)
|
||||
{
|
||||
if (!uniwill_device_supports(data, UNIWILL_FEATURE_USB_POWERSHARE))
|
||||
return 0;
|
||||
|
||||
return uniwill_write_usb_powershare_high(data, data->last_usb_powershare_high_state);
|
||||
}
|
||||
|
||||
static int uniwill_resume_nvidia_ctgp(struct uniwill_data *data)
|
||||
{
|
||||
if (!uniwill_device_supports(data, UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL))
|
||||
|
|
@ -2527,6 +2623,10 @@ static int uniwill_resume(struct device *dev)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = uniwill_resume_usb_powershare(data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = uniwill_resume_nvidia_ctgp(data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user