On Sun, Feb 6, 2022 at 9:51 AM Guenter Roeck <linux@xxxxxxxxxxxx> wrote: > > On 2/5/22 18:20, Andrey Smirnov wrote: > > Add a driver exposing various bits and pieces of functionality > > provided by Steam Deck specific VLV0100 device presented by EC > > firmware. This includes but not limited to: > > > > - CPU/device's fan control > > - Read-only access to DDIC registers > > - Battery tempreature measurements > > - Various display related control knobs > > - USB Type-C connector event notification > > > > Cc: Hans de Goede <hdegoede@xxxxxxxxxx> > > Cc: Mark Gross <markgross@xxxxxxxxxx> > > Cc: Jean Delvare <jdelvare@xxxxxxxx> > > Cc: Guenter Roeck <linux@xxxxxxxxxxxx> > > Cc: linux-kernel@xxxxxxxxxxxxxxx (open list) > > Cc: platform-driver-x86@xxxxxxxxxxxxxxx > > Cc: linux-hwmon@xxxxxxxxxxxxxxx > > Signed-off-by: Andrey Smirnov <andrew.smirnov@xxxxxxxxx> > > --- > > > ... > > > +config STEAMDECK > > + tristate "Valve Steam Deck platform driver" > > + depends on X86_64 > > + help > > + Driver exposing various bits and pieces of functionality > > + provided by Steam Deck specific VLV0100 device presented by > > + EC firmware. This includes but not limited to: > > There seems to be some indentation issue. > > > + - CPU/device's fan control > > + - Read-only access to DDIC registers > > + - Battery tempreature measurements > > + - Various display related control knobs > > + - USB Type-C connector event notification > > + > > + Say N unless you are running on a Steam Deck. > > + > > This doesn't depend on hwmon, yet it fails if devm_hwmon_device_register_with_info() > returns an eror. That has a couple of problems: if HWMON=n, it won't compile, > and if STEAMDECK=y and HWMON=m it won't compile either. You'll have to provide > some dependency against HWMON to make this work. > > ... > Yeah, my bad, will fix. > > + > > +static int steamdeck_read_fan_speed(struct steamdeck *jup, long *speed) > > +{ > > + unsigned long long val; > > + > > + if (ACPI_FAILURE(acpi_evaluate_integer(jup->adev->handle, > > + "FANR", NULL, &val))) > > + return -EIO; > > + > > + *speed = val; > > + return 0; > > +} > > + > > +static int > > +steamdeck_hwmon_read(struct device *dev, enum hwmon_sensor_types type, > > + u32 attr, int channel, long *out) > > +{ > > + struct steamdeck *sd = dev_get_drvdata(dev); > > + unsigned long long val; > > + > > + switch (type) { > > + case hwmon_temp: > > + if (attr != hwmon_temp_input) > > + return -EOPNOTSUPP; > > + > > + if (ACPI_FAILURE(acpi_evaluate_integer(sd->adev->handle, > > + "BATT", NULL, &val))) > > + return -EIO; > > + /* > > + * Assuming BATT returns deg C we need to mutiply it > > + * by 1000 to convert to mC > > + */ > > + *out = val * 1000; > > + break; > > + case hwmon_fan: > > + switch (attr) { > > + case hwmon_fan_input: > > + return steamdeck_read_fan_speed(sd, out); > > There is a bit of inconsistency here: All other atributes are handled directly, > except for this one, yet there isn't really a difference in the actual operation. > Maybe I am missing something. What is the reason for using a function here > but not for the other attributes ? > It is also used to initialize "fan_target" to its initial value in steamdeck_probe(). There's no ACPI method to read set fan target speed, so I have to cache it in "fan_target". > > + case hwmon_fan_target: > > + *out = sd->fan_target; > > + break; > > + case hwmon_fan_fault: > > + if (ACPI_FAILURE(acpi_evaluate_integer( > > + sd->adev->handle, > > + "FANC", NULL, &val))) > > + return -EIO; > > + /* > > + * FANC (Fan check): > > + * 0: Abnormal > > + * 1: Normal > > + */ > > + *out = !val; > > + break; > > + default: > > + return -EOPNOTSUPP; > > + } > > + break; > > + default: > > + return -EOPNOTSUPP; > > + } > > + > > + return 0; > > +} > > + > > +static int > > +steamdeck_hwmon_read_string(struct device *dev, enum hwmon_sensor_types type, > > + u32 attr, int channel, const char **str) > > +{ > > + switch (type) { > > + case hwmon_temp: > > + *str = "Battery Temp"; > > + break; > > + case hwmon_fan: > > + *str = "System Fan"; > > + break; > > + default: > > + return -EOPNOTSUPP; > > + } > > + > > + return 0; > > +} > > + > > +static int > > +steamdeck_hwmon_write(struct device *dev, enum hwmon_sensor_types type, > > + u32 attr, int channel, long val) > > +{ > > + struct steamdeck *sd = dev_get_drvdata(dev); > > + > > + if (type != hwmon_fan || > > + attr != hwmon_fan_target) > > + return -EOPNOTSUPP; > > + > > + if (val > U16_MAX) > > + return -EINVAL; > > This accepts negative values, and it expects the user to find > valid ranges. I suggest to use clamp_val() instead. Will do.