Commit 69308402 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'platform-drivers-x86-v6.3-1' of...

Merge tag 'platform-drivers-x86-v6.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86

Pull x86 platform driver updates from Hans de Goede:

 - AMD PMC: Improvements to aid s2idle debugging

 - Dell WMI-DDV: hwmon support

 - INT3472 camera sensor power-management: Improve privacy LED support

 - Intel VSEC: Base TPMI (Topology Aware Register and PM Capsule
   Interface) support

 - Mellanox: SN5600 and Nvidia L1 switch support

 - Microsoft Surface Support: Various cleanups + code improvements

 - tools/intel-speed-select: Various improvements

 - Miscellaneous other cleanups / fixes

* tag 'platform-drivers-x86-v6.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86: (80 commits)
  platform/x86: nvidia-wmi-ec-backlight: Add force module parameter
  platform/x86/amd/pmf: Add depends on CONFIG_POWER_SUPPLY
  platform/x86: dell-ddv: Prefer asynchronous probing
  platform/x86: dell-ddv: Add hwmon support
  Documentation/ABI: Add new attribute for mlxreg-io sysfs interfaces
  platform: mellanox: mlx-platform: Move bus shift assignment out of the loop
  platform: mellanox: mlx-platform: Add mux selection register to regmap
  platform_data/mlxreg: Add field with mapped resource address
  platform/mellanox: mlxreg-hotplug: Allow more flexible hotplug events configuration
  platform: mellanox: Extend all systems with I2C notification callback
  platform: mellanox: Split logic in init and exit flow
  platform: mellanox: Split initialization procedure
  platform: mellanox: Introduce support of new Nvidia L1 switch
  platform: mellanox: Introduce support for next-generation 800GB/s switch
  platform: mellanox: Cosmetic changes - rename to more common name
  platform: mellanox: Change "reset_pwr_converter_fail" attribute
  platform: mellanox: Introduce support for rack manager switch
  MAINTAINERS: dell-wmi-sysman: drop Divya Bharathi
  x86/platform/uv: Make kobj_type structure constant
  platform/x86: think-lmi: Make kobj_type structure constant
  ...
parents 5f5ce6bc 0d9bdd8a
......@@ -522,7 +522,6 @@ Description: These files allow to each of ASICs by writing 1.
The files are write only.
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/comm_chnl_ready
Date: July 2022
KernelVersion: 5.20
......@@ -542,3 +541,124 @@ Description: The file indicates COME module hardware configuration.
The purpose is to expose some minor BOM changes for the same system SKU.
The file is read only.
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_pwr_converter_fail
Date: February 2023
KernelVersion: 6.3
Contact: Vadim Pasternak <vadimp@nvidia.com>
Description: This file shows the system reset cause due to power converter
devices failure.
Value 1 in file means this is reset cause, 0 - otherwise.
The file is read only.
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/erot1_ap_reset
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/erot2_ap_reset
Date: February 2023
KernelVersion: 6.3
Contact: Vadim Pasternak <vadimp@nvidia.com>
Description: These files aim to monitor the status of the External Root of Trust (EROT)
processor's RESET output to the Application Processor (AP).
By reading this file, could be determined if the EROT has invalidated or
revoked AP Firmware, at which point it will hold the AP in RESET until a
valid firmware is loaded. This protects the AP from running an
unauthorized firmware. In the normal flow, the AP reset should be released
after the EROT validates the integrity of the FW, and it should be done so
as quickly as possible so that the AP boots before the CPU starts to
communicate to each ASIC.
The files are read only.
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/erot1_recovery
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/erot2_recovery
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/erot1_reset
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/erot2_reset
Date: February 2023
KernelVersion: 6.3
Contact: Vadim Pasternak <vadimp@nvidia.com>
Description: These files aim to perform External Root of Trust (EROT) recovery
sequence after EROT device failure.
These EROT devices protect ASICs from unauthorized access and in normal
flow their reset should be released with system power – earliest power
up stage, so that EROTs can begin boot and authentication process before
CPU starts to communicate to ASICs.
Issuing a reset to the EROT while asserting the recovery signal will cause
the EROT Application Processor to enter recovery mode so that the EROT FW
can be updated/recovered.
For reset/recovery the related file should be toggled by 1/0.
The files are read/write.
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/erot1_wp
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/erot2_wp
Date: February 2023
KernelVersion: 6.3
Contact: Vadim Pasternak <vadimp@nvidia.com>
Description: These files allow access to External Root of Trust (EROT) for reset
and recovery sequence after EROT device failure.
Default is 0 (programming disabled).
If the system is in locked-down mode writing this file will not be allowed.
The files are read/write.
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/spi_chnl_select
Date: February 2023
KernelVersion: 6.3
Contact: Vadim Pasternak <vadimp@nvidia.com>
Description: This file allows SPI chip selection for External Root of Trust (EROT)
device Out-of-Band recovery.
File can be written with 0 or with 1. It selects which EROT can be accessed
through SPI device.
The file is read/write.
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/asic_pg_fail
Date: February 2023
KernelVersion: 6.3
Contact: Vadim Pasternak vadimp@nvidia.com
Description: This file shows ASIC Power Good status.
Value 1 in file means ASIC Power Good failed, 0 - otherwise.
The file is read only.
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/clk_brd1_boot_fail
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/clk_brd2_boot_fail
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/clk_brd_fail
Date: February 2023
KernelVersion: 6.3
Contact: Vadim Pasternak vadimp@nvidia.com
Description: These files are related to clock boards status in system.
- clk_brd1_boot_fail: warning about 1-st clock board failed to boot from CI.
- clk_brd2_boot_fail: warning about 2-nd clock board failed to boot from CI.
- clk_brd_fail: error about common clock board boot failure.
The files are read only.
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/clk_brd_prog_en
Date: February 2023
KernelVersion: 6.3
Contact: Vadim Pasternak <vadimp@nvidia.com>
Description: This file enables programming of clock boards.
Default is 0 (programming disabled).
If the system is in locked-down mode writing this file will not be allowed.
The file is read/write.
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/pwr_converter_prog_en
Date: February 2023
KernelVersion: 6.3
Contact: Vadim Pasternak <vadimp@nvidia.com>
Description: This file enables programming of power converters.
Default is 0 (programming disabled).
If the system is in locked-down mode writing this file will not be allowed.
The file is read/write.
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_ac_ok_fail
Date: February 2023
KernelVersion: 6.3
Contact: Vadim Pasternak <vadimp@nvidia.com>
Description: This file shows the system reset cause due to AC power failure.
Value 1 in file means this is reset cause, 0 - otherwise.
The file is read only.
......@@ -19,7 +19,7 @@
.. |ssam_notifier_unregister| replace:: :c:func:`ssam_notifier_unregister`
.. |ssam_device_notifier_register| replace:: :c:func:`ssam_device_notifier_register`
.. |ssam_device_notifier_unregister| replace:: :c:func:`ssam_device_notifier_unregister`
.. |ssam_request_sync| replace:: :c:func:`ssam_request_sync`
.. |ssam_request_do_sync| replace:: :c:func:`ssam_request_do_sync`
.. |ssam_event_mask| replace:: :c:type:`enum ssam_event_mask <ssam_event_mask>`
......@@ -191,7 +191,7 @@ data received from it is converted from little-endian to host endianness.
* they do not correspond to an actual SAM/EC request.
*/
rqst.target_category = SSAM_SSH_TC_SAM;
rqst.target_id = 0x01;
rqst.target_id = SSAM_SSH_TID_SAM;
rqst.command_id = 0x02;
rqst.instance_id = 0x03;
rqst.flags = SSAM_REQUEST_HAS_RESPONSE;
......@@ -209,12 +209,12 @@ data received from it is converted from little-endian to host endianness.
* with the SSAM_REQUEST_HAS_RESPONSE flag set in the specification
* above.
*/
status = ssam_request_sync(ctrl, &rqst, &resp);
status = ssam_request_do_sync(ctrl, &rqst, &resp);
/*
* Alternatively use
*
* ssam_request_sync_onstack(ctrl, &rqst, &resp, sizeof(arg_le));
* ssam_request_do_sync_onstack(ctrl, &rqst, &resp, sizeof(arg_le));
*
* to perform the request, allocating the message buffer directly
* on the stack as opposed to allocation via kzalloc().
......@@ -230,7 +230,7 @@ data received from it is converted from little-endian to host endianness.
return status;
}
Note that |ssam_request_sync| in its essence is a wrapper over lower-level
Note that |ssam_request_do_sync| in its essence is a wrapper over lower-level
request primitives, which may also be used to perform requests. Refer to its
implementation and documentation for more details.
......@@ -241,7 +241,7 @@ one of the generator macros, for example via:
SSAM_DEFINE_SYNC_REQUEST_W(__ssam_tmp_perf_mode_set, __le32, {
.target_category = SSAM_SSH_TC_TMP,
.target_id = 0x01,
.target_id = SSAM_SSH_TID_SAM,
.command_id = 0x03,
.instance_id = 0x00,
});
......
......@@ -13,6 +13,7 @@
.. |DATA_NSQ| replace:: ``DATA_NSQ``
.. |TC| replace:: ``TC``
.. |TID| replace:: ``TID``
.. |SID| replace:: ``SID``
.. |IID| replace:: ``IID``
.. |RQID| replace:: ``RQID``
.. |CID| replace:: ``CID``
......@@ -219,13 +220,13 @@ following fields, packed together and in order:
- |u8|
- Target category.
* - |TID| (out)
* - |TID|
- |u8|
- Target ID for outgoing (host to EC) commands.
- Target ID for commands/messages.
* - |TID| (in)
* - |SID|
- |u8|
- Target ID for incoming (EC to host) commands.
- Source ID for commands/messages.
* - |IID|
- |u8|
......@@ -286,19 +287,20 @@ general, however, a single target category should map to a single reserved
event request ID.
Furthermore, requests, responses, and events have an associated target ID
(``TID``). This target ID is split into output (host to EC) and input (EC to
host) fields, with the respecting other field (e.g. output field on incoming
messages) set to zero. Two ``TID`` values are known: Primary (``0x01``) and
secondary (``0x02``). In general, the response to a request should have the
same ``TID`` value, however, the field (output vs. input) should be used in
accordance to the direction in which the response is sent (i.e. on the input
field, as responses are generally sent from the EC to the host).
Note that, even though requests and events should be uniquely identifiable
by target category and command ID alone, the EC may require specific
target ID and instance ID values to accept a command. A command that is
accepted for ``TID=1``, for example, may not be accepted for ``TID=2``
and vice versa.
(``TID``) and source ID (``SID``). These two fields indicate where a message
originates from (``SID``) and what the intended target of the message is
(``TID``). Note that a response to a specific request therefore has the source
and target IDs swapped when compared to the original request (i.e. the request
target is the response source and the request source is the response target).
See (:c:type:`enum ssh_request_id <ssh_request_id>`) for possible values of
both.
Note that, even though requests and events should be uniquely identifiable by
target category and command ID alone, the EC may require specific target ID and
instance ID values to accept a command. A command that is accepted for
``TID=1``, for example, may not be accepted for ``TID=2`` and vice versa. While
this may not always hold in reality, you can think of different target/source
IDs indicating different physical ECs with potentially different feature sets.
Limitations and Observations
......
......@@ -5773,7 +5773,6 @@ F: Documentation/ABI/testing/sysfs-platform-dell-wmi-ddv
F: drivers/platform/x86/dell/dell-wmi-ddv.c
DELL WMI SYSMAN DRIVER
M: Divya Bharathi <divya.bharathi@dell.com>
M: Prasanth Ksr <prasanth.ksr@dell.com>
L: Dell.Client.Kernel@dell.com
L: platform-driver-x86@vger.kernel.org
......@@ -10535,6 +10534,13 @@ S: Maintained
F: arch/x86/include/asm/intel_telemetry.h
F: drivers/platform/x86/intel/telemetry/
INTEL TPMI DRIVER
M: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/intel/tpmi.c
F: include/linux/intel_tpmi.h
INTEL UNCORE FREQUENCY CONTROL
M: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
L: platform-driver-x86@vger.kernel.org
......@@ -22480,6 +22486,7 @@ S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git
F: drivers/platform/olpc/
F: drivers/platform/x86/
F: include/linux/platform_data/x86/
X86 PLATFORM DRIVERS - ARCH
R: Darren Hart <dvhart@infradead.org>
......
......@@ -80,7 +80,7 @@ static int ssam_hid_get_descriptor(struct surface_hid_device *shid, u8 entry, u8
rsp.length = 0;
status = ssam_retry(ssam_request_sync_onstack, shid->ctrl, &rqst, &rsp,
status = ssam_retry(ssam_request_do_sync_onstack, shid->ctrl, &rqst, &rsp,
sizeof(*slice));
if (status)
return status;
......@@ -131,7 +131,7 @@ static int ssam_hid_set_raw_report(struct surface_hid_device *shid, u8 rprt_id,
buf[0] = rprt_id;
return ssam_retry(ssam_request_sync, shid->ctrl, &rqst, NULL);
return ssam_retry(ssam_request_do_sync, shid->ctrl, &rqst, NULL);
}
static int ssam_hid_get_raw_report(struct surface_hid_device *shid, u8 rprt_id, u8 *buf, size_t len)
......@@ -151,7 +151,7 @@ static int ssam_hid_get_raw_report(struct surface_hid_device *shid, u8 rprt_id,
rsp.length = 0;
rsp.pointer = buf;
return ssam_retry(ssam_request_sync_onstack, shid->ctrl, &rqst, &rsp, sizeof(rprt_id));
return ssam_retry(ssam_request_do_sync_onstack, shid->ctrl, &rqst, &rsp, sizeof(rprt_id));
}
static u32 ssam_hid_event_fn(struct ssam_event_notifier *nf, const struct ssam_event *event)
......@@ -230,7 +230,7 @@ static void surface_hid_remove(struct ssam_device *sdev)
}
static const struct ssam_device_id surface_hid_match[] = {
{ SSAM_SDEV(HID, SSAM_ANY_TID, SSAM_ANY_IID, 0x00) },
{ SSAM_SDEV(HID, ANY, SSAM_SSH_IID_ANY, 0x00) },
{ },
};
MODULE_DEVICE_TABLE(ssam, surface_hid_match);
......
......@@ -49,7 +49,7 @@ static int ssam_kbd_get_descriptor(struct surface_hid_device *shid, u8 entry, u8
rsp.length = 0;
rsp.pointer = buf;
status = ssam_retry(ssam_request_sync_onstack, shid->ctrl, &rqst, &rsp, sizeof(entry));
status = ssam_retry(ssam_request_do_sync_onstack, shid->ctrl, &rqst, &rsp, sizeof(entry));
if (status)
return status;
......@@ -75,7 +75,7 @@ static int ssam_kbd_set_caps_led(struct surface_hid_device *shid, bool value)
rqst.length = sizeof(value_u8);
rqst.payload = &value_u8;
return ssam_retry(ssam_request_sync_onstack, shid->ctrl, &rqst, NULL, sizeof(value_u8));
return ssam_retry(ssam_request_do_sync_onstack, shid->ctrl, &rqst, NULL, sizeof(value_u8));
}
static int ssam_kbd_get_feature_report(struct surface_hid_device *shid, u8 *buf, size_t len)
......@@ -97,7 +97,7 @@ static int ssam_kbd_get_feature_report(struct surface_hid_device *shid, u8 *buf,
rsp.length = 0;
rsp.pointer = buf;
status = ssam_retry(ssam_request_sync_onstack, shid->ctrl, &rqst, &rsp, sizeof(payload));
status = ssam_retry(ssam_request_do_sync_onstack, shid->ctrl, &rqst, &rsp, sizeof(payload));
if (status)
return status;
......@@ -250,7 +250,7 @@ static int surface_kbd_probe(struct platform_device *pdev)
shid->uid.domain = SSAM_DOMAIN_SERIALHUB;
shid->uid.category = SSAM_SSH_TC_KBD;
shid->uid.target = 2;
shid->uid.target = SSAM_SSH_TID_KIP;
shid->uid.instance = 0;
shid->uid.function = 0;
......
......@@ -23,6 +23,8 @@
#include "leds.h"
static struct class *leds_class;
static DEFINE_MUTEX(leds_lookup_lock);
static LIST_HEAD(leds_lookup_list);
static ssize_t brightness_show(struct device *dev,
struct device_attribute *attr, char *buf)
......@@ -215,6 +217,23 @@ static int led_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(leds_class_dev_pm_ops, led_suspend, led_resume);
static struct led_classdev *led_module_get(struct device *led_dev)
{
struct led_classdev *led_cdev;
if (!led_dev)
return ERR_PTR(-EPROBE_DEFER);
led_cdev = dev_get_drvdata(led_dev);
if (!try_module_get(led_cdev->dev->parent->driver->owner)) {
put_device(led_cdev->dev);
return ERR_PTR(-ENODEV);
}
return led_cdev;
}
/**
* of_led_get() - request a LED device via the LED framework
* @np: device node to get the LED device from
......@@ -226,7 +245,6 @@ static SIMPLE_DEV_PM_OPS(leds_class_dev_pm_ops, led_suspend, led_resume);
struct led_classdev *of_led_get(struct device_node *np, int index)
{
struct device *led_dev;
struct led_classdev *led_cdev;
struct device_node *led_node;
led_node = of_parse_phandle(np, "leds", index);
......@@ -236,15 +254,7 @@ struct led_classdev *of_led_get(struct device_node *np, int index)
led_dev = class_find_device_by_of_node(leds_class, led_node);
of_node_put(led_node);
if (!led_dev)
return ERR_PTR(-EPROBE_DEFER);
led_cdev = dev_get_drvdata(led_dev);
if (!try_module_get(led_cdev->dev->parent->driver->owner))
return ERR_PTR(-ENODEV);
return led_cdev;
return led_module_get(led_dev);
}
EXPORT_SYMBOL_GPL(of_led_get);
......@@ -255,6 +265,7 @@ EXPORT_SYMBOL_GPL(of_led_get);
void led_put(struct led_classdev *led_cdev)
{
module_put(led_cdev->dev->parent->driver->owner);
put_device(led_cdev->dev);
}
EXPORT_SYMBOL_GPL(led_put);
......@@ -265,6 +276,22 @@ static void devm_led_release(struct device *dev, void *res)
led_put(*p);
}
static struct led_classdev *__devm_led_get(struct device *dev, struct led_classdev *led)
{
struct led_classdev **dr;
dr = devres_alloc(devm_led_release, sizeof(struct led_classdev *), GFP_KERNEL);
if (!dr) {
led_put(led);
return ERR_PTR(-ENOMEM);
}
*dr = led;
devres_add(dev, dr);
return led;
}
/**
* devm_of_led_get - Resource-managed request of a LED device
* @dev: LED consumer
......@@ -280,7 +307,6 @@ struct led_classdev *__must_check devm_of_led_get(struct device *dev,
int index)
{
struct led_classdev *led;
struct led_classdev **dr;
if (!dev)
return ERR_PTR(-EINVAL);
......@@ -289,19 +315,91 @@ struct led_classdev *__must_check devm_of_led_get(struct device *dev,
if (IS_ERR(led))
return led;
dr = devres_alloc(devm_led_release, sizeof(struct led_classdev *),
GFP_KERNEL);
if (!dr) {
led_put(led);
return ERR_PTR(-ENOMEM);
return __devm_led_get(dev, led);
}
EXPORT_SYMBOL_GPL(devm_of_led_get);
/**
* led_get() - request a LED device via the LED framework
* @dev: device for which to get the LED device
* @con_id: name of the LED from the device's point of view
*
* @return a pointer to a LED device or ERR_PTR(errno) on failure.
*/
struct led_classdev *led_get(struct device *dev, char *con_id)
{
struct led_lookup_data *lookup;
const char *provider = NULL;
struct device *led_dev;
mutex_lock(&leds_lookup_lock);
list_for_each_entry(lookup, &leds_lookup_list, list) {
if (!strcmp(lookup->dev_id, dev_name(dev)) &&
!strcmp(lookup->con_id, con_id)) {
provider = kstrdup_const(lookup->provider, GFP_KERNEL);
break;
}
}
mutex_unlock(&leds_lookup_lock);
*dr = led;
devres_add(dev, dr);
if (!provider)
return ERR_PTR(-ENOENT);
led_dev = class_find_device_by_name(leds_class, provider);
kfree_const(provider);
return led_module_get(led_dev);
}
EXPORT_SYMBOL_GPL(led_get);
/**
* devm_led_get() - request a LED device via the LED framework
* @dev: device for which to get the LED device
* @con_id: name of the LED from the device's point of view
*
* The LED device returned from this function is automatically released
* on driver detach.
*
* @return a pointer to a LED device or ERR_PTR(errno) on failure.
*/
struct led_classdev *devm_led_get(struct device *dev, char *con_id)
{
struct led_classdev *led;
led = led_get(dev, con_id);
if (IS_ERR(led))
return led;
return __devm_led_get(dev, led);
}
EXPORT_SYMBOL_GPL(devm_of_led_get);
EXPORT_SYMBOL_GPL(devm_led_get);
/**
* led_add_lookup() - Add a LED lookup table entry
* @led_lookup: the lookup table entry to add
*
* Add a LED lookup table entry. On systems without devicetree the lookup table
* is used by led_get() to find LEDs.
*/
void led_add_lookup(struct led_lookup_data *led_lookup)
{
mutex_lock(&leds_lookup_lock);
list_add_tail(&led_lookup->list, &leds_lookup_list);
mutex_unlock(&leds_lookup_lock);
}
EXPORT_SYMBOL_GPL(led_add_lookup);
/**
* led_remove_lookup() - Remove a LED lookup table entry
* @led_lookup: the lookup table entry to remove
*/
void led_remove_lookup(struct led_lookup_data *led_lookup)
{
mutex_lock(&leds_lookup_lock);
list_del(&led_lookup->list);
mutex_unlock(&leds_lookup_lock);
}
EXPORT_SYMBOL_GPL(led_remove_lookup);
static int led_classdev_next_name(const char *init_name, char *name,
size_t len)
......
......@@ -24,6 +24,8 @@
#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
#include "v4l2-subdev-priv.h"
static int v4l2_async_nf_call_bound(struct v4l2_async_notifier *n,
struct v4l2_subdev *subdev,
struct v4l2_async_subdev *asd)
......@@ -822,6 +824,8 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
if (!sd->async_list.next)
return;
v4l2_subdev_put_privacy_led(sd);
mutex_lock(&list_lock);
__v4l2_async_nf_unregister(sd->subdev_notifier);
......
......@@ -28,6 +28,8 @@
#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
#include "v4l2-subdev-priv.h"
static const struct v4l2_fwnode_bus_conv {
enum v4l2_fwnode_bus_type fwnode_bus_type;
enum v4l2_mbus_type mbus_type;
......@@ -1302,6 +1304,10 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd)
v4l2_async_nf_init(notifier);
ret = v4l2_subdev_get_privacy_led(sd);
if (ret < 0)
goto out_cleanup;
ret = v4l2_async_nf_parse_fwnode_sensor(sd->dev, notifier);
if (ret < 0)
goto out_cleanup;
......@@ -1322,6 +1328,7 @@ int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd)
v4l2_async_nf_unregister(notifier);
out_cleanup:
v4l2_subdev_put_privacy_led(sd);
v4l2_async_nf_cleanup(notifier);
kfree(notifier);
......
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* V4L2 sub-device pivate header.
*
* Copyright (C) 2023 Hans de Goede <hdegoede@redhat.com>
*/
#ifndef _V4L2_SUBDEV_PRIV_H_
#define _V4L2_SUBDEV_PRIV_H_
int v4l2_subdev_get_privacy_led(struct v4l2_subdev *sd);
void v4l2_subdev_put_privacy_led(struct v4l2_subdev *sd);
#endif
......@@ -9,6 +9,7 @@
*/
#include <linux/ioctl.h>
#include <linux/leds.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/slab.h>
......@@ -23,6 +24,8 @@
#include <media/v4l2-fh.h>
#include <media/v4l2-event.h>
#include "v4l2-subdev-priv.h"
#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd)
{
......@@ -322,6 +325,15 @@ static int call_s_stream(struct v4l2_subdev *sd, int enable)
{
int ret;
#if IS_REACHABLE(CONFIG_LEDS_CLASS)
if (!IS_ERR_OR_NULL(sd->privacy_led)) {
if (enable)
led_set_brightness(sd->privacy_led,
sd->privacy_led->max_brightness);
else
led_set_brightness(sd->privacy_led, 0);
}
#endif
ret = sd->ops->video->s_stream(sd, enable);
if (!enable && ret < 0) {
......@@ -1090,6 +1102,7 @@ void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
sd->grp_id = 0;
sd->dev_priv = NULL;
sd->host_priv = NULL;
sd->privacy_led = NULL;
#if defined(CONFIG_MEDIA_CONTROLLER)
sd->entity.name = sd->name;
sd->entity.obj_type = MEDIA_ENTITY_TYPE_V4L2_SUBDEV;
......@@ -1105,3 +1118,36 @@ void v4l2_subdev_notify_event(struct v4l2_subdev *sd,
v4l2_subdev_notify(sd, V4L2_DEVICE_NOTIFY_EVENT, (void *)ev);
}
EXPORT_SYMBOL_GPL(v4l2_subdev_notify_event);
int v4l2_subdev_get_privacy_led(struct v4l2_subdev *sd)
{
#if IS_REACHABLE(CONFIG_LEDS_CLASS)
sd->privacy_led = led_get(sd->dev, "privacy-led");
if (IS_ERR(sd->privacy_led) && PTR_ERR(sd->privacy_led) != -ENOENT)
return dev_err_probe(sd->dev, PTR_ERR(sd->privacy_led),
"getting privacy LED\n");
if (!IS_ERR_OR_NULL(sd->privacy_led)) {
mutex_lock(&sd->privacy_led->led_access);
led_sysfs_disable(sd->privacy_led);
led_trigger_remove(sd->privacy_led);
led_set_brightness(sd->privacy_led, 0);
mutex_unlock(&sd->privacy_led->led_access);
}
#endif
return 0;
}
EXPORT_SYMBOL_GPL(v4l2_subdev_get_privacy_led);
void v4l2_subdev_put_privacy_led(struct v4l2_subdev *sd)
{
#if IS_REACHABLE(CONFIG_LEDS_CLASS)
if (!IS_ERR_OR_NULL(sd->privacy_led)) {
mutex_lock(&sd->privacy_led->led_access);
led_sysfs_enable(sd->privacy_led);
mutex_unlock(&sd->privacy_led->led_access);
led_put(sd->privacy_led);
}
#endif
}
EXPORT_SYMBOL_GPL(v4l2_subdev_put_privacy_led);
......@@ -239,6 +239,17 @@ static ssize_t mlxreg_hotplug_attr_show(struct device *dev,
#define PRIV_ATTR(i) priv->mlxreg_hotplug_attr[i]
#define PRIV_DEV_ATTR(i) priv->mlxreg_hotplug_dev_attr[i]
static int mlxreg_hotplug_item_label_index_get(u32 mask, u32 bit)
{
int i, j;
for (i = 0, j = -1; i <= bit; i++) {
if (mask & BIT(i))
j++;
}
return j;
}
static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv)
{
struct mlxreg_core_hotplug_platform_data *pdata;
......@@ -246,7 +257,7 @@ static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv)
struct mlxreg_core_data *data;
unsigned long mask;
u32 regval;
int num_attrs = 0, id = 0, i, j, k, ret;
int num_attrs = 0, id = 0, i, j, k, count, ret;
pdata = dev_get_platdata(&priv->pdev->dev);
item = pdata->items;
......@@ -272,7 +283,8 @@ static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv)
/* Go over all unmasked units within item. */
mask = item->mask;
k = 0;
for_each_set_bit(j, &mask, item->count) {
count = item->ind ? item->ind : item->count;
for_each_set_bit(j, &mask, count) {
if (data->capability) {
/*
* Read capability register and skip non
......@@ -282,16 +294,17 @@ static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv)
data->capability, &regval);
if (ret)
return ret;
if (!(regval & data->bit)) {
data++;
continue;
}
}
PRIV_ATTR(id) = &PRIV_DEV_ATTR(id).dev_attr.attr;
PRIV_ATTR(id)->name = devm_kasprintf(&priv->pdev->dev,
GFP_KERNEL,
data->label);
if (!PRIV_ATTR(id)->name) {
dev_err(priv->dev, "Memory allocation failed for attr %d.\n",
id);
......@@ -365,9 +378,14 @@ mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv,
regval &= item->mask;
asserted = item->cache ^ regval;
item->cache = regval;
for_each_set_bit(bit, &asserted, 8) {
data = item->data + bit;
int pos;
pos = mlxreg_hotplug_item_label_index_get(item->mask, bit);
if (pos < 0)
goto out;
data = item->data + pos;
if (regval & BIT(bit)) {
if (item->inversed)
mlxreg_hotplug_device_destroy(priv, data, item->kind);
......
......@@ -136,9 +136,9 @@ int ssam_device_add(struct ssam_device *sdev)
* is always valid and can be used for requests as long as the client
* device we add here is registered as child under it. This essentially
* guarantees that the client driver can always expect the preconditions
* for functions like ssam_request_sync (controller has to be started
* and is not suspended) to hold and thus does not have to check for
* them.
* for functions like ssam_request_do_sync() (controller has to be
* started and is not suspended) to hold and thus does not have to check
* for them.
*
* Note that for this to work, the controller has to be a parent device.
* If it is not a direct parent, care has to be taken that the device is
......
......@@ -994,7 +994,7 @@ static void ssam_handle_event(struct ssh_rtl *rtl,
item->rqid = get_unaligned_le16(&cmd->rqid);
item->event.target_category = cmd->tc;
item->event.target_id = cmd->tid_in;
item->event.target_id = cmd->sid;
item->event.command_id = cmd->cid;
item->event.instance_id = cmd->iid;
memcpy(&item->event.data[0], data->ptr, data->len);
......@@ -1674,7 +1674,7 @@ int ssam_request_sync_submit(struct ssam_controller *ctrl,
EXPORT_SYMBOL_GPL(ssam_request_sync_submit);
/**
* ssam_request_sync() - Execute a synchronous request.
* ssam_request_do_sync() - Execute a synchronous request.
* @ctrl: The controller via which the request will be submitted.
* @spec: The request specification and payload.
* @rsp: The response buffer.
......@@ -1686,7 +1686,7 @@ EXPORT_SYMBOL_GPL(ssam_request_sync_submit);
*
* Return: Returns the status of the request or any failure during setup.
*/
int ssam_request_sync(struct ssam_controller *ctrl,
int ssam_request_do_sync(struct ssam_controller *ctrl,
const struct ssam_request *spec,
struct ssam_response *rsp)
{
......@@ -1722,10 +1722,10 @@ int ssam_request_sync(struct ssam_controller *ctrl,
ssam_request_sync_free(rqst);
return status;
}
EXPORT_SYMBOL_GPL(ssam_request_sync);
EXPORT_SYMBOL_GPL(ssam_request_do_sync);
/**
* ssam_request_sync_with_buffer() - Execute a synchronous request with the
* ssam_request_do_sync_with_buffer() - Execute a synchronous request with the
* provided buffer as back-end for the message buffer.
* @ctrl: The controller via which the request will be submitted.
* @spec: The request specification and payload.
......@@ -1738,14 +1738,14 @@ EXPORT_SYMBOL_GPL(ssam_request_sync);
* SSH_COMMAND_MESSAGE_LENGTH() macro can be used to compute the required
* message buffer size.
*
* This function does essentially the same as ssam_request_sync(), but instead
* of dynamically allocating the request and message data buffer, it uses the
* provided message data buffer and stores the (small) request struct on the
* heap.
* This function does essentially the same as ssam_request_do_sync(), but
* instead of dynamically allocating the request and message data buffer, it
* uses the provided message data buffer and stores the (small) request struct
* on the heap.
*
* Return: Returns the status of the request or any failure during setup.
*/
int ssam_request_sync_with_buffer(struct ssam_controller *ctrl,
int ssam_request_do_sync_with_buffer(struct ssam_controller *ctrl,
const struct ssam_request *spec,
struct ssam_response *rsp,
struct ssam_span *buf)
......@@ -1772,42 +1772,42 @@ int ssam_request_sync_with_buffer(struct ssam_controller *ctrl,
return status;
}
EXPORT_SYMBOL_GPL(ssam_request_sync_with_buffer);
EXPORT_SYMBOL_GPL(ssam_request_do_sync_with_buffer);
/* -- Internal SAM requests. ------------------------------------------------ */
SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_get_firmware_version, __le32, {
.target_category = SSAM_SSH_TC_SAM,
.target_id = 0x01,
.target_id = SSAM_SSH_TID_SAM,
.command_id = 0x13,
.instance_id = 0x00,
});
SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_display_off, u8, {
.target_category = SSAM_SSH_TC_SAM,
.target_id = 0x01,
.target_id = SSAM_SSH_TID_SAM,
.command_id = 0x15,
.instance_id = 0x00,
});
SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_display_on, u8, {
.target_category = SSAM_SSH_TC_SAM,
.target_id = 0x01,
.target_id = SSAM_SSH_TID_SAM,
.command_id = 0x16,
.instance_id = 0x00,
});
SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_d0_exit, u8, {
.target_category = SSAM_SSH_TC_SAM,
.target_id = 0x01,
.target_id = SSAM_SSH_TID_SAM,
.command_id = 0x33,
.instance_id = 0x00,
});
SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_d0_entry, u8, {
.target_category = SSAM_SSH_TC_SAM,
.target_id = 0x01,
.target_id = SSAM_SSH_TID_SAM,
.command_id = 0x34,
.instance_id = 0x00,
});
......@@ -1864,7 +1864,7 @@ static int __ssam_ssh_event_request(struct ssam_controller *ctrl,
result.length = 0;
result.pointer = &buf;
status = ssam_retry(ssam_request_sync_onstack, ctrl, &rqst, &result,
status = ssam_retry(ssam_request_do_sync_onstack, ctrl, &rqst, &result,
sizeof(params));
return status < 0 ? status : buf;
......
......@@ -189,8 +189,8 @@ static inline void msgb_push_cmd(struct msgbuf *msgb, u8 seq, u16 rqid,
__msgb_push_u8(msgb, SSH_PLD_TYPE_CMD); /* Payload type. */
__msgb_push_u8(msgb, rqst->target_category); /* Target category. */
__msgb_push_u8(msgb, rqst->target_id); /* Target ID (out). */
__msgb_push_u8(msgb, 0x00); /* Target ID (in). */
__msgb_push_u8(msgb, rqst->target_id); /* Target ID. */
__msgb_push_u8(msgb, SSAM_SSH_TID_HOST); /* Source ID. */
__msgb_push_u8(msgb, rqst->instance_id); /* Instance ID. */
__msgb_push_u16(msgb, rqid); /* Request ID. */
__msgb_push_u8(msgb, rqst->command_id); /* Command ID. */
......
......@@ -920,13 +920,14 @@ static void ssh_rtl_rx_command(struct ssh_ptl *p, const struct ssam_span *data)
* Check if the message was intended for us. If not, drop it.
*
* Note: We will need to change this to handle debug messages. On newer
* generation devices, these seem to be sent to tid_out=0x03. We as
* host can still receive them as they can be forwarded via an override
* option on SAM, but doing so does not change tid_out=0x00.
* generation devices, these seem to be sent to SSAM_SSH_TID_DEBUG. We
* as host can still receive them as they can be forwarded via an
* override option on SAM, but doing so does not change the target ID
* to SSAM_SSH_TID_HOST.
*/
if (command->tid_out != 0x00) {
if (command->tid != SSAM_SSH_TID_HOST) {
rtl_warn(rtl, "rtl: dropping message not intended for us (tid = %#04x)\n",
command->tid_out);
command->tid);
return;
}
......
......@@ -96,6 +96,7 @@ TRACE_DEFINE_ENUM(SSAM_SSH_TC_POS);
#define SSAM_SEQ_NOT_APPLICABLE ((u16)-1)
#define SSAM_RQID_NOT_APPLICABLE ((u32)-1)
#define SSAM_SSH_TC_NOT_APPLICABLE 0
#define SSAM_SSH_TID_NOT_APPLICABLE ((u8)-1)
#ifndef _SURFACE_AGGREGATOR_TRACE_HELPERS
#define _SURFACE_AGGREGATOR_TRACE_HELPERS
......@@ -150,12 +151,44 @@ static inline u32 ssam_trace_get_request_id(const struct ssh_packet *p)
return get_unaligned_le16(&p->data.ptr[SSH_MSGOFFSET_COMMAND(rqid)]);
}
/**
* ssam_trace_get_request_tid() - Read the packet's request target ID.
* @p: The packet.
*
* Return: Returns the packet's request target ID (TID) field if the packet
* represents a request with command data, or %SSAM_SSH_TID_NOT_APPLICABLE
* if not (e.g. flush request, control packet).
*/
static inline u32 ssam_trace_get_request_tid(const struct ssh_packet *p)
{
if (!p->data.ptr || p->data.len < SSH_COMMAND_MESSAGE_LENGTH(0))
return SSAM_SSH_TID_NOT_APPLICABLE;
return get_unaligned_le16(&p->data.ptr[SSH_MSGOFFSET_COMMAND(tid)]);
}
/**
* ssam_trace_get_request_sid() - Read the packet's request source ID.
* @p: The packet.
*
* Return: Returns the packet's request source ID (SID) field if the packet
* represents a request with command data, or %SSAM_SSH_TID_NOT_APPLICABLE
* if not (e.g. flush request, control packet).
*/
static inline u32 ssam_trace_get_request_sid(const struct ssh_packet *p)
{
if (!p->data.ptr || p->data.len < SSH_COMMAND_MESSAGE_LENGTH(0))
return SSAM_SSH_TID_NOT_APPLICABLE;
return get_unaligned_le16(&p->data.ptr[SSH_MSGOFFSET_COMMAND(sid)]);
}
/**
* ssam_trace_get_request_tc() - Read the packet's request target category.
* @p: The packet.
*
* Return: Returns the packet's request target category (TC) field if the
* packet represents a request with command data, or %SSAM_TC_NOT_APPLICABLE
* packet represents a request with command data, or %SSAM_SSH_TC_NOT_APPLICABLE
* if not (e.g. flush request, control packet).
*/
static inline u32 ssam_trace_get_request_tc(const struct ssh_packet *p)
......@@ -232,8 +265,18 @@ static inline u32 ssam_trace_get_request_tc(const struct ssh_packet *p)
{ SSAM_RQID_NOT_APPLICABLE, "N/A" } \
)
#define ssam_show_ssh_tc(rqid) \
__print_symbolic(rqid, \
#define ssam_show_ssh_tid(tid) \
__print_symbolic(tid, \
{ SSAM_SSH_TID_NOT_APPLICABLE, "N/A" }, \
{ SSAM_SSH_TID_HOST, "Host" }, \
{ SSAM_SSH_TID_SAM, "SAM" }, \
{ SSAM_SSH_TID_KIP, "KIP" }, \
{ SSAM_SSH_TID_DEBUG, "Debug" }, \
{ SSAM_SSH_TID_SURFLINK, "SurfLink" } \
)
#define ssam_show_ssh_tc(tc) \
__print_symbolic(tc, \
{ SSAM_SSH_TC_NOT_APPLICABLE, "N/A" }, \
{ SSAM_SSH_TC_SAM, "SAM" }, \
{ SSAM_SSH_TC_BAT, "BAT" }, \
......@@ -313,6 +356,8 @@ DECLARE_EVENT_CLASS(ssam_command_class,
TP_STRUCT__entry(
__field(u16, rqid)
__field(u16, len)
__field(u8, tid)
__field(u8, sid)
__field(u8, tc)
__field(u8, cid)
__field(u8, iid)
......@@ -320,14 +365,18 @@ DECLARE_EVENT_CLASS(ssam_command_class,
TP_fast_assign(
__entry->rqid = get_unaligned_le16(&cmd->rqid);
__entry->tid = cmd->tid;
__entry->sid = cmd->sid;
__entry->tc = cmd->tc;
__entry->cid = cmd->cid;
__entry->iid = cmd->iid;
__entry->len = len;
),
TP_printk("rqid=%#06x, tc=%s, cid=%#04x, iid=%#04x, len=%u",
TP_printk("rqid=%#06x, tid=%s, sid=%s, tc=%s, cid=%#04x, iid=%#04x, len=%u",
__entry->rqid,
ssam_show_ssh_tid(__entry->tid),
ssam_show_ssh_tid(__entry->sid),
ssam_show_ssh_tc(__entry->tc),
__entry->cid,
__entry->iid,
......@@ -430,6 +479,8 @@ DECLARE_EVENT_CLASS(ssam_request_class,
__field(u8, tc)
__field(u16, cid)
__field(u16, iid)
__field(u8, tid)
__field(u8, sid)
),
TP_fast_assign(
......@@ -439,16 +490,20 @@ DECLARE_EVENT_CLASS(ssam_request_class,
__entry->state = READ_ONCE(request->state);
__entry->rqid = ssam_trace_get_request_id(p);
ssam_trace_ptr_uid(p, __entry->uid);
__entry->tid = ssam_trace_get_request_tid(p);
__entry->sid = ssam_trace_get_request_sid(p);
__entry->tc = ssam_trace_get_request_tc(p);
__entry->cid = ssam_trace_get_command_field_u8(p, cid);
__entry->iid = ssam_trace_get_command_field_u8(p, iid);
),
TP_printk("uid=%s, rqid=%s, ty=%s, sta=%s, tc=%s, cid=%s, iid=%s",
TP_printk("uid=%s, rqid=%s, ty=%s, sta=%s, tid=%s, sid=%s, tc=%s, cid=%s, iid=%s",
__entry->uid,
ssam_show_request_id(__entry->rqid),
ssam_show_request_type(__entry->state),
ssam_show_request_state(__entry->state),
ssam_show_ssh_tid(__entry->tid),
ssam_show_ssh_tid(__entry->sid),
ssam_show_ssh_tc(__entry->tc),
ssam_show_generic_u8_field(__entry->cid),
ssam_show_generic_u8_field(__entry->iid)
......@@ -474,6 +529,8 @@ DECLARE_EVENT_CLASS(ssam_request_status_class,
__field(u8, tc)
__field(u16, cid)
__field(u16, iid)
__field(u8, tid)
__field(u8, sid)
),
TP_fast_assign(
......@@ -484,16 +541,20 @@ DECLARE_EVENT_CLASS(ssam_request_status_class,
__entry->rqid = ssam_trace_get_request_id(p);
__entry->status = status;
ssam_trace_ptr_uid(p, __entry->uid);
__entry->tid = ssam_trace_get_request_tid(p);
__entry->sid = ssam_trace_get_request_sid(p);
__entry->tc = ssam_trace_get_request_tc(p);
__entry->cid = ssam_trace_get_command_field_u8(p, cid);
__entry->iid = ssam_trace_get_command_field_u8(p, iid);
),
TP_printk("uid=%s, rqid=%s, ty=%s, sta=%s, tc=%s, cid=%s, iid=%s, status=%d",
TP_printk("uid=%s, rqid=%s, ty=%s, sta=%s, tid=%s, sid=%s, tc=%s, cid=%s, iid=%s, status=%d",
__entry->uid,
ssam_show_request_id(__entry->rqid),
ssam_show_request_type(__entry->state),
ssam_show_request_state(__entry->state),
ssam_show_ssh_tid(__entry->tid),
ssam_show_ssh_tid(__entry->sid),
ssam_show_ssh_tc(__entry->tc),
ssam_show_generic_u8_field(__entry->cid),
ssam_show_generic_u8_field(__entry->iid),
......
......@@ -590,7 +590,7 @@ static acpi_status san_rqst(struct san_data *d, struct gsb_buffer *buffer)
return san_rqst_fixup_suspended(d, &rqst, buffer);
}
status = __ssam_retry(ssam_request_sync_onstack, SAN_REQUEST_NUM_TRIES,
status = __ssam_retry(ssam_request_do_sync_onstack, SAN_REQUEST_NUM_TRIES,
d->ctrl, &rqst, &rsp, SAN_GSB_MAX_RQSX_PAYLOAD);
if (!status) {
......
......@@ -302,8 +302,8 @@ static long ssam_cdev_request(struct ssam_cdev_client *client, struct ssam_cdev_
* theoretical maximum (SSH_COMMAND_MAX_PAYLOAD_SIZE) of the
* underlying protocol (note that nothing remotely this size
* should ever be allocated in any normal case). This size is
* validated later in ssam_request_sync(), for allocation the
* bound imposed by u16 should be enough.
* validated later in ssam_request_do_sync(), for allocation
* the bound imposed by u16 should be enough.
*/
spec.payload = kzalloc(spec.length, GFP_KERNEL);
if (!spec.payload) {
......@@ -342,7 +342,7 @@ static long ssam_cdev_request(struct ssam_cdev_client *client, struct ssam_cdev_
}
/* Perform request. */
status = ssam_request_sync(client->cdev->ctrl, &spec, &rsp);
status = ssam_request_do_sync(client->cdev->ctrl, &spec, &rsp);
if (status)
goto out;
......
......@@ -214,7 +214,7 @@ static void ssam_hub_remove(struct ssam_device *sdev)
SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_query_opmode, u8, {
.target_category = SSAM_SSH_TC_BAS,
.target_id = 0x01,
.target_id = SSAM_SSH_TID_SAM,
.command_id = 0x0d,
.instance_id = 0x00,
});
......@@ -292,7 +292,7 @@ static const struct ssam_hub_desc base_hub = {
SSAM_DEFINE_SYNC_REQUEST_R(__ssam_kip_query_state, u8, {
.target_category = SSAM_SSH_TC_KIP,
.target_id = 0x01,
.target_id = SSAM_SSH_TID_SAM,
.command_id = 0x2c,
.instance_id = 0x00,
});
......@@ -348,8 +348,8 @@ static const struct ssam_hub_desc kip_hub = {
/* -- Driver registration. -------------------------------------------------- */
static const struct ssam_device_id ssam_hub_match[] = {
{ SSAM_VDEV(HUB, 0x01, SSAM_SSH_TC_KIP, 0x00), (unsigned long)&kip_hub },
{ SSAM_VDEV(HUB, 0x02, SSAM_SSH_TC_BAS, 0x00), (unsigned long)&base_hub },
{ SSAM_VDEV(HUB, SAM, SSAM_SSH_TC_KIP, 0x00), (unsigned long)&kip_hub },
{ SSAM_VDEV(HUB, SAM, SSAM_SSH_TC_BAS, 0x00), (unsigned long)&base_hub },
{ }
};
MODULE_DEVICE_TABLE(ssam, ssam_hub_match);
......
......@@ -46,7 +46,7 @@ static const struct software_node ssam_node_hub_kip = {
/* Base device hub (devices attached to Surface Book 3 base). */
static const struct software_node ssam_node_hub_base = {
.name = "ssam:00:00:02:11:00",
.name = "ssam:00:00:01:11:00",
.parent = &ssam_node_root,
};
......
......@@ -247,7 +247,7 @@ static bool ssam_kip_cover_state_is_tablet_mode(struct ssam_tablet_sw *sw, u32 s
SSAM_DEFINE_SYNC_REQUEST_R(__ssam_kip_get_cover_state, u8, {
.target_category = SSAM_SSH_TC_KIP,
.target_id = 0x01,
.target_id = SSAM_SSH_TID_SAM,
.command_id = 0x1d,
.instance_id = 0x00,
});
......@@ -371,7 +371,7 @@ static int ssam_pos_get_sources_list(struct ssam_tablet_sw *sw, struct ssam_sour
int status;
rqst.target_category = SSAM_SSH_TC_POS;
rqst.target_id = 0x01;
rqst.target_id = SSAM_SSH_TID_SAM;
rqst.command_id = 0x01;
rqst.instance_id = 0x00;
rqst.flags = SSAM_REQUEST_HAS_RESPONSE;
......@@ -382,7 +382,7 @@ static int ssam_pos_get_sources_list(struct ssam_tablet_sw *sw, struct ssam_sour
rsp.length = 0;
rsp.pointer = (u8 *)sources;
status = ssam_retry(ssam_request_sync_onstack, sw->sdev->ctrl, &rqst, &rsp, 0);
status = ssam_retry(ssam_request_do_sync_onstack, sw->sdev->ctrl, &rqst, &rsp, 0);
if (status)
return status;
......@@ -430,7 +430,7 @@ static int ssam_pos_get_source(struct ssam_tablet_sw *sw, u32 *source_id)
SSAM_DEFINE_SYNC_REQUEST_WR(__ssam_pos_get_posture_for_source, __le32, __le32, {
.target_category = SSAM_SSH_TC_POS,
.target_id = 0x01,
.target_id = SSAM_SSH_TID_SAM,
.command_id = 0x02,
.instance_id = 0x00,
});
......@@ -510,8 +510,8 @@ static const struct ssam_tablet_sw_desc ssam_pos_sw_desc = {
/* -- Driver registration. -------------------------------------------------- */
static const struct ssam_device_id ssam_tablet_sw_match[] = {
{ SSAM_SDEV(KIP, 0x01, 0x00, 0x01), (unsigned long)&ssam_kip_sw_desc },
{ SSAM_SDEV(POS, 0x01, 0x00, 0x01), (unsigned long)&ssam_pos_sw_desc },
{ SSAM_SDEV(KIP, SAM, 0x00, 0x01), (unsigned long)&ssam_kip_sw_desc },
{ SSAM_SDEV(POS, SAM, 0x00, 0x01), (unsigned long)&ssam_pos_sw_desc },
{ },
};
MODULE_DEVICE_TABLE(ssam, ssam_tablet_sw_match);
......
......@@ -71,63 +71,63 @@ static_assert(sizeof(struct ssam_bas_base_info) == 2);
SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_lock, {
.target_category = SSAM_SSH_TC_BAS,
.target_id = 0x01,
.target_id = SSAM_SSH_TID_SAM,
.command_id = 0x06,
.instance_id = 0x00,
});
SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_unlock, {
.target_category = SSAM_SSH_TC_BAS,
.target_id = 0x01,
.target_id = SSAM_SSH_TID_SAM,
.command_id = 0x07,
.instance_id = 0x00,
});
SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_request, {
.target_category = SSAM_SSH_TC_BAS,
.target_id = 0x01,
.target_id = SSAM_SSH_TID_SAM,
.command_id = 0x08,
.instance_id = 0x00,
});
SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_confirm, {
.target_category = SSAM_SSH_TC_BAS,
.target_id = 0x01,
.target_id = SSAM_SSH_TID_SAM,
.command_id = 0x09,
.instance_id = 0x00,
});
SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_heartbeat, {
.target_category = SSAM_SSH_TC_BAS,
.target_id = 0x01,
.target_id = SSAM_SSH_TID_SAM,
.command_id = 0x0a,
.instance_id = 0x00,
});
SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_cancel, {
.target_category = SSAM_SSH_TC_BAS,
.target_id = 0x01,
.target_id = SSAM_SSH_TID_SAM,
.command_id = 0x0b,
.instance_id = 0x00,
});
SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_get_base, struct ssam_bas_base_info, {
.target_category = SSAM_SSH_TC_BAS,
.target_id = 0x01,
.target_id = SSAM_SSH_TID_SAM,
.command_id = 0x0c,
.instance_id = 0x00,
});
SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_get_device_mode, u8, {
.target_category = SSAM_SSH_TC_BAS,
.target_id = 0x01,
.target_id = SSAM_SSH_TID_SAM,
.command_id = 0x0d,
.instance_id = 0x00,
});
SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_get_latch_status, u8, {
.target_category = SSAM_SSH_TC_BAS,
.target_id = 0x01,
.target_id = SSAM_SSH_TID_SAM,
.command_id = 0x11,
.instance_id = 0x00,
});
......@@ -1214,7 +1214,7 @@ static void surface_dtx_ssam_remove(struct ssam_device *sdev)
}
static const struct ssam_device_id surface_dtx_ssam_match[] = {
{ SSAM_SDEV(BAS, 0x01, 0x00, 0x00) },
{ SSAM_SDEV(BAS, SAM, 0x00, 0x00) },
{ },
};
MODULE_DEVICE_TABLE(ssam, surface_dtx_ssam_match);
......
......@@ -101,18 +101,12 @@ static void shps_dsm_notify_irq(struct platform_device *pdev, enum shps_irq_type
param.type = ACPI_TYPE_INTEGER;
param.integer.value = value;
result = acpi_evaluate_dsm(handle, &shps_dsm_guid, SHPS_DSM_REVISION,
shps_dsm_fn_for_irq(type), &param);
result = acpi_evaluate_dsm_typed(handle, &shps_dsm_guid, SHPS_DSM_REVISION,
shps_dsm_fn_for_irq(type), &param, ACPI_TYPE_BUFFER);
if (!result) {
dev_err(&pdev->dev, "IRQ notification via DSM failed (irq=%d, gpio=%d)\n",
type, value);
} else if (result->type != ACPI_TYPE_BUFFER) {
dev_err(&pdev->dev,
"IRQ notification via DSM failed: unexpected result type (irq=%d, gpio=%d)\n",
type, value);
} else if (result->buffer.length != 1 || result->buffer.pointer[0] != 0) {
dev_err(&pdev->dev,
"IRQ notification via DSM failed: unexpected result value (irq=%d, gpio=%d)\n",
......@@ -121,7 +115,6 @@ static void shps_dsm_notify_irq(struct platform_device *pdev, enum shps_irq_type
mutex_unlock(&sdev->lock[type]);
if (result)
ACPI_FREE(result);
}
......
......@@ -169,7 +169,7 @@ static void surface_platform_profile_remove(struct ssam_device *sdev)
}
static const struct ssam_device_id ssam_platform_profile_match[] = {
{ SSAM_SDEV(TMP, 0x01, 0x00, 0x01) },
{ SSAM_SDEV(TMP, SAM, 0x00, 0x01) },
{ },
};
MODULE_DEVICE_TABLE(ssam, ssam_platform_profile_match);
......
......@@ -214,7 +214,6 @@ config APPLE_GMUX
depends on PNP
depends on BACKLIGHT_CLASS_DEVICE
depends on BACKLIGHT_APPLE=n || BACKLIGHT_APPLE
depends on ACPI_VIDEO=n || ACPI_VIDEO
help
This driver provides support for the gmux device found on many
Apple laptops, which controls the display mux for the hybrid
......
......@@ -544,11 +544,6 @@ static int acerhdf_probe(struct platform_device *device)
return 0;
}
static int acerhdf_remove(struct platform_device *device)
{
return 0;
}
static const struct dev_pm_ops acerhdf_pm_ops = {
.suspend = acerhdf_suspend,
.freeze = acerhdf_suspend,
......@@ -560,7 +555,6 @@ static struct platform_driver acerhdf_driver = {
.pm = &acerhdf_pm_ops,
},
.probe = acerhdf_probe,
.remove = acerhdf_remove,
};
/* check hardware */
......
......@@ -43,6 +43,7 @@
#define AMD_PMC_STB_S2IDLE_PREPARE 0xC6000001
#define AMD_PMC_STB_S2IDLE_RESTORE 0xC6000002
#define AMD_PMC_STB_S2IDLE_CHECK 0xC6000003
#define AMD_PMC_STB_DUMMY_PC 0xC6000007
/* STB S2D(Spill to DRAM) has different message port offset */
#define STB_SPILL_TO_DRAM 0xBE
......@@ -104,6 +105,7 @@
#define DELAY_MIN_US 2000
#define DELAY_MAX_US 3000
#define FIFO_SIZE 4096
enum amd_pmc_def {
MSG_TEST = 0x01,
MSG_OS_HINT_PCO,
......@@ -114,6 +116,7 @@ enum s2d_arg {
S2D_TELEMETRY_SIZE = 0x01,
S2D_PHYS_ADDR_LOW,
S2D_PHYS_ADDR_HIGH,
S2D_NUM_SAMPLES,
};
struct amd_pmc_bit_map {
......@@ -246,13 +249,40 @@ static const struct file_operations amd_pmc_stb_debugfs_fops = {
static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp)
{
struct amd_pmc_dev *dev = filp->f_inode->i_private;
u32 *buf;
u32 *buf, fsize, num_samples, stb_rdptr_offset = 0;
int ret;
/* Write dummy postcode while reading the STB buffer */
ret = amd_pmc_write_stb(dev, AMD_PMC_STB_DUMMY_PC);
if (ret)
dev_err(dev->dev, "error writing to STB: %d\n", ret);
buf = kzalloc(S2D_TELEMETRY_BYTES_MAX, GFP_KERNEL);
if (!buf)
return -ENOMEM;
memcpy_fromio(buf, dev->stb_virt_addr, S2D_TELEMETRY_BYTES_MAX);
/* Spill to DRAM num_samples uses separate SMU message port */
dev->msg_port = 1;
/* Get the num_samples to calculate the last push location */
ret = amd_pmc_send_cmd(dev, S2D_NUM_SAMPLES, &num_samples, STB_SPILL_TO_DRAM, 1);
/* Clear msg_port for other SMU operation */
dev->msg_port = 0;
if (ret) {
dev_err(dev->dev, "error: S2D_NUM_SAMPLES not supported : %d\n", ret);
return ret;
}
/* Start capturing data from the last push location */
if (num_samples > S2D_TELEMETRY_BYTES_MAX) {
fsize = S2D_TELEMETRY_BYTES_MAX;
stb_rdptr_offset = num_samples - fsize;
} else {
fsize = num_samples;
stb_rdptr_offset = 0;
}
memcpy_fromio(buf, dev->stb_virt_addr + stb_rdptr_offset, fsize);
filp->private_data = buf;
return 0;
......@@ -560,13 +590,13 @@ static void amd_pmc_dump_registers(struct amd_pmc_dev *dev)
}
value = amd_pmc_reg_read(dev, response);
dev_dbg(dev->dev, "AMD_PMC_REGISTER_RESPONSE:%x\n", value);
dev_dbg(dev->dev, "AMD_%s_REGISTER_RESPONSE:%x\n", dev->msg_port ? "S2D" : "PMC", value);
value = amd_pmc_reg_read(dev, argument);
dev_dbg(dev->dev, "AMD_PMC_REGISTER_ARGUMENT:%x\n", value);
dev_dbg(dev->dev, "AMD_%s_REGISTER_ARGUMENT:%x\n", dev->msg_port ? "S2D" : "PMC", value);
value = amd_pmc_reg_read(dev, message);
dev_dbg(dev->dev, "AMD_PMC_REGISTER_MESSAGE:%x\n", value);
dev_dbg(dev->dev, "AMD_%s_REGISTER_MESSAGE:%x\n", dev->msg_port ? "S2D" : "PMC", value);
}
static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, u32 arg, u32 *data, u8 msg, bool ret)
......
......@@ -6,6 +6,7 @@
config AMD_PMF
tristate "AMD Platform Management Framework"
depends on ACPI && PCI
depends on POWER_SUPPLY
select ACPI_PLATFORM_PROFILE
help
This driver provides support for the AMD Platform Management Framework.
......
......@@ -192,12 +192,12 @@ config DELL_WMI_DESCRIPTOR
config DELL_WMI_DDV
tristate "Dell WMI sensors Support"
default m
depends on ACPI_BATTERY
depends on ACPI_WMI
depends on ACPI_BATTERY || HWMON
help
This option adds support for WMI-based sensors like
battery temperature sensors found on some Dell notebooks.
It also supports reading of the battery ePPID.
This option adds support for WMI-based fan and thermal sensors
found on some Dell notebooks. It also supports various WMI-based battery
extras like reading of the battery temperature and ePPID.
To compile this drivers as a module, choose M here: the module will
be called dell-wmi-ddv.
......
......@@ -67,10 +67,7 @@ static ssize_t smo8800_misc_read(struct file *file, char __user *buf,
retval = 1;
if (data < 255)
byte_data = data;
else
byte_data = 255;
byte_data = min_t(u32, data, 255);
if (put_user(byte_data, buf))
retval = -EFAULT;
......
This diff is collapsed.
......@@ -255,7 +255,7 @@ static void attr_name_release(struct kobject *kobj)
kfree(kobj);
}
static struct kobj_type attr_name_ktype = {
static const struct kobj_type attr_name_ktype = {
.release = attr_name_release,
.sysfs_ops = &wmi_sysman_kobj_sysfs_ops,
};
......
......@@ -217,6 +217,8 @@ static const struct key_entry hp_wmi_keymap[] = {
{ KE_KEY, 0x213b, { KEY_INFO } },
{ KE_KEY, 0x2169, { KEY_ROTATE_DISPLAY } },
{ KE_KEY, 0x216a, { KEY_SETUP } },
{ KE_IGNORE, 0x21a4, }, /* Win Lock On */
{ KE_IGNORE, 0x121a4, }, /* Win Lock Off */
{ KE_KEY, 0x21a5, { KEY_PROG2 } }, /* HP Omen Key */
{ KE_KEY, 0x21a7, { KEY_FN_ESC } },
{ KE_KEY, 0x21a9, { KEY_TOUCHPAD_OFF } },
......
......@@ -182,6 +182,19 @@ config INTEL_SMARTCONNECT
This driver checks to determine whether the device has Intel Smart
Connect enabled, and if so disables it.
config INTEL_TPMI
tristate "Intel Topology Aware Register and PM Capsule Interface (TPMI)"
depends on INTEL_VSEC
depends on X86_64
help
The Intel Topology Aware Register and PM Capsule Interface (TPMI),
provides enumerable MMIO interface for power management features.
This driver creates devices, so that other PM feature driver can
be loaded for PM specific feature operation.
To compile this driver as a module, choose M here: the module will
be called intel_vsec_tpmi.
config INTEL_TURBO_MAX_3
bool "Intel Turbo Boost Max Technology 3.0 enumeration driver"
depends on X86_64 && SCHED_MC_PRIO
......
......@@ -47,6 +47,10 @@ obj-$(CONFIG_INTEL_MRFLD_PWRBTN) += intel_mrfld_pwrbtn.o
intel_punit_ipc-y := punit_ipc.o
obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o
# TPMI drivers
intel_vsec_tpmi-y := tpmi.o
obj-$(CONFIG_INTEL_TPMI) += intel_vsec_tpmi.o
# Intel Uncore drivers
intel-rst-y := rst.o
obj-$(CONFIG_INTEL_RST) += intel-rst.o
......
......@@ -131,16 +131,15 @@ static acpi_status sar_get_device_mode(struct platform_device *device)
acpi_status status = AE_OK;
union acpi_object *out;
u32 rev = 0;
int value;
out = acpi_evaluate_dsm(context->handle, &context->guid, rev,
COMMAND_ID_DEV_MODE, NULL);
if (get_int_value(out, &value)) {
out = acpi_evaluate_dsm_typed(context->handle, &context->guid, rev,
COMMAND_ID_DEV_MODE, NULL, ACPI_TYPE_INTEGER);
if (!out) {
dev_err(&device->dev, "DSM cmd:%d Failed to retrieve value\n", COMMAND_ID_DEV_MODE);
status = AE_ERROR;
goto dev_mode_error;
}
context->sar_data.device_mode = value;
context->sar_data.device_mode = out->integer.value;
update_sar_data(context);
sysfs_notify(&device->dev.kobj, NULL, SYSFS_DATANAME);
......@@ -221,11 +220,11 @@ static void sar_get_data(int reg, struct wwan_sar_context *context)
req.type = ACPI_TYPE_INTEGER;
req.integer.value = reg;
out = acpi_evaluate_dsm(context->handle, &context->guid, rev,
COMMAND_ID_CONFIG_TABLE, &req);
out = acpi_evaluate_dsm_typed(context->handle, &context->guid, rev,
COMMAND_ID_CONFIG_TABLE, &req, ACPI_TYPE_PACKAGE);
if (!out)
return;
if (out->type == ACPI_TYPE_PACKAGE && out->package.count >= 3 &&
if (out->package.count >= 3 &&
out->package.elements[0].type == ACPI_TYPE_INTEGER &&
out->package.elements[1].type == ACPI_TYPE_INTEGER &&
out->package.elements[2].type == ACPI_TYPE_PACKAGE &&
......
......@@ -4,6 +4,7 @@ config INTEL_SKL_INT3472
depends on COMMON_CLK
depends on I2C
depends on GPIOLIB
depends on LEDS_CLASS
depends on REGULATOR
select MFD_CORE
select REGMAP_I2C
......
obj-$(CONFIG_INTEL_SKL_INT3472) += intel_skl_int3472_discrete.o \
intel_skl_int3472_tps68470.o
intel_skl_int3472_discrete-y := discrete.o clk_and_regulator.o common.o
intel_skl_int3472_discrete-y := discrete.o clk_and_regulator.o led.o common.o
intel_skl_int3472_tps68470-y := tps68470.o tps68470_board_data.o common.o
......@@ -23,8 +23,6 @@ static int skl_int3472_clk_prepare(struct clk_hw *hw)
struct int3472_gpio_clock *clk = to_int3472_clk(hw);
gpiod_set_value_cansleep(clk->ena_gpio, 1);
gpiod_set_value_cansleep(clk->led_gpio, 1);
return 0;
}
......@@ -33,7 +31,6 @@ static void skl_int3472_clk_unprepare(struct clk_hw *hw)
struct int3472_gpio_clock *clk = to_int3472_clk(hw);
gpiod_set_value_cansleep(clk->ena_gpio, 0);
gpiod_set_value_cansleep(clk->led_gpio, 0);
}
static int skl_int3472_clk_enable(struct clk_hw *hw)
......@@ -89,18 +86,37 @@ static const struct clk_ops skl_int3472_clock_ops = {
.recalc_rate = skl_int3472_clk_recalc_rate,
};
int skl_int3472_register_clock(struct int3472_discrete_device *int3472)
int skl_int3472_register_clock(struct int3472_discrete_device *int3472,
struct acpi_resource_gpio *agpio, u32 polarity)
{
char *path = agpio->resource_source.string_ptr;
struct clk_init_data init = {
.ops = &skl_int3472_clock_ops,
.flags = CLK_GET_RATE_NOCACHE,
};
int ret;
if (int3472->clock.cl)
return -EBUSY;
int3472->clock.ena_gpio = acpi_get_and_request_gpiod(path, agpio->pin_table[0],
"int3472,clk-enable");
if (IS_ERR(int3472->clock.ena_gpio))
return dev_err_probe(int3472->dev, PTR_ERR(int3472->clock.ena_gpio),
"getting clk-enable GPIO\n");
if (polarity == GPIO_ACTIVE_LOW)
gpiod_toggle_active_low(int3472->clock.ena_gpio);
/* Ensure the pin is in output mode and non-active state */
gpiod_direction_output(int3472->clock.ena_gpio, 0);
init.name = kasprintf(GFP_KERNEL, "%s-clk",
acpi_dev_name(int3472->adev));
if (!init.name)
return -ENOMEM;
if (!init.name) {
ret = -ENOMEM;
goto out_put_gpio;
}
int3472->clock.frequency = skl_int3472_get_clk_frequency(int3472);
......@@ -126,14 +142,20 @@ int skl_int3472_register_clock(struct int3472_discrete_device *int3472)
clk_unregister(int3472->clock.clk);
out_free_init_name:
kfree(init.name);
out_put_gpio:
gpiod_put(int3472->clock.ena_gpio);
return ret;
}
void skl_int3472_unregister_clock(struct int3472_discrete_device *int3472)
{
if (!int3472->clock.cl)
return;
clkdev_drop(int3472->clock.cl);
clk_unregister(int3472->clock.clk);
gpiod_put(int3472->clock.ena_gpio);
}
int skl_int3472_register_regulator(struct int3472_discrete_device *int3472,
......
......@@ -6,6 +6,7 @@
#include <linux/clk-provider.h>
#include <linux/gpio/machine.h>
#include <linux/leds.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/types.h>
......@@ -28,6 +29,8 @@
#define GPIO_REGULATOR_NAME_LENGTH 21
#define GPIO_REGULATOR_SUPPLY_NAME_LENGTH 9
#define INT3472_LED_MAX_NAME_LEN 32
#define CIO2_SENSOR_SSDB_MCLKSPEED_OFFSET 86
#define INT3472_REGULATOR(_name, _supply, _ops) \
......@@ -96,10 +99,16 @@ struct int3472_discrete_device {
struct clk_hw clk_hw;
struct clk_lookup *cl;
struct gpio_desc *ena_gpio;
struct gpio_desc *led_gpio;
u32 frequency;
} clock;
struct int3472_pled {
struct led_classdev classdev;
struct led_lookup_data lookup;
char name[INT3472_LED_MAX_NAME_LEN];
struct gpio_desc *gpio;
} pled;
unsigned int ngpios; /* how many GPIOs have we seen */
unsigned int n_sensor_gpios; /* how many have we mapped to sensor */
struct gpiod_lookup_table gpios;
......@@ -112,11 +121,16 @@ int skl_int3472_get_sensor_adev_and_name(struct device *dev,
struct acpi_device **sensor_adev_ret,
const char **name_ret);
int skl_int3472_register_clock(struct int3472_discrete_device *int3472);
int skl_int3472_register_clock(struct int3472_discrete_device *int3472,
struct acpi_resource_gpio *agpio, u32 polarity);
void skl_int3472_unregister_clock(struct int3472_discrete_device *int3472);
int skl_int3472_register_regulator(struct int3472_discrete_device *int3472,
struct acpi_resource_gpio *agpio);
void skl_int3472_unregister_regulator(struct int3472_discrete_device *int3472);
int skl_int3472_register_pled(struct int3472_discrete_device *int3472,
struct acpi_resource_gpio *agpio, u32 polarity);
void skl_int3472_unregister_pled(struct int3472_discrete_device *int3472);
#endif
......@@ -2,8 +2,6 @@
/* Author: Dan Scally <djrscally@gmail.com> */
#include <linux/acpi.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/device.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/machine.h>
......@@ -80,14 +78,6 @@ skl_int3472_get_sensor_module_config(struct int3472_discrete_device *int3472)
return ERR_PTR(-ENODEV);
}
if (obj->string.type != ACPI_TYPE_STRING) {
dev_err(int3472->dev,
"Sensor _DSM returned a non-string value\n");
ACPI_FREE(obj);
return ERR_PTR(-EINVAL);
}
for (i = 0; i < ARRAY_SIZE(int3472_sensor_configs); i++) {
if (!strcmp(int3472_sensor_configs[i].sensor_module_name,
obj->string.pointer))
......@@ -154,38 +144,34 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347
return 0;
}
static int skl_int3472_map_gpio_to_clk(struct int3472_discrete_device *int3472,
struct acpi_resource_gpio *agpio, u8 type)
static void int3472_get_func_and_polarity(u8 type, const char **func, u32 *polarity)
{
char *path = agpio->resource_source.string_ptr;
u16 pin = agpio->pin_table[0];
struct gpio_desc *gpio;
switch (type) {
case INT3472_GPIO_TYPE_RESET:
*func = "reset";
*polarity = GPIO_ACTIVE_LOW;
break;
case INT3472_GPIO_TYPE_POWERDOWN:
*func = "powerdown";
*polarity = GPIO_ACTIVE_LOW;
break;
case INT3472_GPIO_TYPE_CLK_ENABLE:
gpio = acpi_get_and_request_gpiod(path, pin, "int3472,clk-enable");
if (IS_ERR(gpio))
return (PTR_ERR(gpio));
int3472->clock.ena_gpio = gpio;
/* Ensure the pin is in output mode and non-active state */
gpiod_direction_output(int3472->clock.ena_gpio, 0);
*func = "clk-enable";
*polarity = GPIO_ACTIVE_HIGH;
break;
case INT3472_GPIO_TYPE_PRIVACY_LED:
gpio = acpi_get_and_request_gpiod(path, pin, "int3472,privacy-led");
if (IS_ERR(gpio))
return (PTR_ERR(gpio));
int3472->clock.led_gpio = gpio;
/* Ensure the pin is in output mode and non-active state */
gpiod_direction_output(int3472->clock.led_gpio, 0);
*func = "privacy-led";
*polarity = GPIO_ACTIVE_HIGH;
break;
case INT3472_GPIO_TYPE_POWER_ENABLE:
*func = "power-enable";
*polarity = GPIO_ACTIVE_HIGH;
break;
default:
dev_err(int3472->dev, "Invalid GPIO type 0x%02x for clock\n", type);
*func = "unknown";
*polarity = GPIO_ACTIVE_HIGH;
break;
}
return 0;
}
/**
......@@ -226,9 +212,11 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares,
struct int3472_discrete_device *int3472 = data;
struct acpi_resource_gpio *agpio;
union acpi_object *obj;
u8 active_value, type;
const char *err_msg;
const char *func;
u32 polarity;
int ret;
u8 type;
if (!acpi_gpio_get_io_resource(ares, &agpio))
return 1;
......@@ -250,26 +238,35 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares,
type = obj->integer.value & 0xff;
int3472_get_func_and_polarity(type, &func, &polarity);
/* If bits 31-24 of the _DSM entry are all 0 then the signal is inverted */
active_value = obj->integer.value >> 24;
if (!active_value)
polarity ^= GPIO_ACTIVE_LOW;
dev_dbg(int3472->dev, "%s %s pin %d active-%s\n", func,
agpio->resource_source.string_ptr, agpio->pin_table[0],
(polarity == GPIO_ACTIVE_HIGH) ? "high" : "low");
switch (type) {
case INT3472_GPIO_TYPE_RESET:
ret = skl_int3472_map_gpio_to_sensor(int3472, agpio, "reset",
GPIO_ACTIVE_LOW);
case INT3472_GPIO_TYPE_POWERDOWN:
ret = skl_int3472_map_gpio_to_sensor(int3472, agpio, func, polarity);
if (ret)
err_msg = "Failed to map reset pin to sensor\n";
err_msg = "Failed to map GPIO pin to sensor\n";
break;
case INT3472_GPIO_TYPE_POWERDOWN:
ret = skl_int3472_map_gpio_to_sensor(int3472, agpio, "powerdown",
GPIO_ACTIVE_LOW);
case INT3472_GPIO_TYPE_CLK_ENABLE:
ret = skl_int3472_register_clock(int3472, agpio, polarity);
if (ret)
err_msg = "Failed to map powerdown pin to sensor\n";
err_msg = "Failed to register clock\n";
break;
case INT3472_GPIO_TYPE_CLK_ENABLE:
case INT3472_GPIO_TYPE_PRIVACY_LED:
ret = skl_int3472_map_gpio_to_clk(int3472, agpio, type);
ret = skl_int3472_register_pled(int3472, agpio, polarity);
if (ret)
err_msg = "Failed to map GPIO to clock\n";
err_msg = "Failed to register LED\n";
break;
case INT3472_GPIO_TYPE_POWER_ENABLE:
......@@ -314,21 +311,6 @@ static int skl_int3472_parse_crs(struct int3472_discrete_device *int3472)
acpi_dev_free_resource_list(&resource_list);
/*
* If we find no clock enable GPIO pin then the privacy LED won't work.
* We've never seen that situation, but it's possible. Warn the user so
* it's clear what's happened.
*/
if (int3472->clock.ena_gpio) {
ret = skl_int3472_register_clock(int3472);
if (ret)
return ret;
} else {
if (int3472->clock.led_gpio)
dev_warn(int3472->dev,
"No clk GPIO. The privacy LED won't work\n");
}
int3472->gpios.dev_id = int3472->sensor_name;
gpiod_add_lookup_table(&int3472->gpios);
......@@ -341,12 +323,8 @@ static int skl_int3472_discrete_remove(struct platform_device *pdev)
gpiod_remove_lookup_table(&int3472->gpios);
if (int3472->clock.cl)
skl_int3472_unregister_clock(int3472);
gpiod_put(int3472->clock.ena_gpio);
gpiod_put(int3472->clock.led_gpio);
skl_int3472_unregister_pled(int3472);
skl_int3472_unregister_regulator(int3472);
return 0;
......
// SPDX-License-Identifier: GPL-2.0
/* Author: Hans de Goede <hdegoede@redhat.com> */
#include <linux/acpi.h>
#include <linux/gpio/consumer.h>
#include <linux/leds.h>
#include "common.h"
static int int3472_pled_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
struct int3472_discrete_device *int3472 =
container_of(led_cdev, struct int3472_discrete_device, pled.classdev);
gpiod_set_value_cansleep(int3472->pled.gpio, brightness);
return 0;
}
int skl_int3472_register_pled(struct int3472_discrete_device *int3472,
struct acpi_resource_gpio *agpio, u32 polarity)
{
char *p, *path = agpio->resource_source.string_ptr;
int ret;
if (int3472->pled.classdev.dev)
return -EBUSY;
int3472->pled.gpio = acpi_get_and_request_gpiod(path, agpio->pin_table[0],
"int3472,privacy-led");
if (IS_ERR(int3472->pled.gpio))
return dev_err_probe(int3472->dev, PTR_ERR(int3472->pled.gpio),
"getting privacy LED GPIO\n");
if (polarity == GPIO_ACTIVE_LOW)
gpiod_toggle_active_low(int3472->pled.gpio);
/* Ensure the pin is in output mode and non-active state */
gpiod_direction_output(int3472->pled.gpio, 0);
/* Generate the name, replacing the ':' in the ACPI devname with '_' */
snprintf(int3472->pled.name, sizeof(int3472->pled.name),
"%s::privacy_led", acpi_dev_name(int3472->sensor));
p = strchr(int3472->pled.name, ':');
if (p)
*p = '_';
int3472->pled.classdev.name = int3472->pled.name;
int3472->pled.classdev.max_brightness = 1;
int3472->pled.classdev.brightness_set_blocking = int3472_pled_set;
ret = led_classdev_register(int3472->dev, &int3472->pled.classdev);
if (ret)
goto err_free_gpio;
int3472->pled.lookup.provider = int3472->pled.name;
int3472->pled.lookup.dev_id = int3472->sensor_name;
int3472->pled.lookup.con_id = "privacy-led";
led_add_lookup(&int3472->pled.lookup);
return 0;
err_free_gpio:
gpiod_put(int3472->pled.gpio);
return ret;
}
void skl_int3472_unregister_pled(struct int3472_discrete_device *int3472)
{
if (IS_ERR_OR_NULL(int3472->pled.classdev.dev))
return;
led_remove_lookup(&int3472->pled.lookup);
led_classdev_unregister(&int3472->pled.classdev);
gpiod_put(int3472->pled.gpio);
}
......@@ -266,17 +266,11 @@ static int oaktrail_probe(struct platform_device *pdev)
return 0;
}
static int oaktrail_remove(struct platform_device *pdev)
{
return 0;
}
static struct platform_driver oaktrail_driver = {
.driver = {
.name = DRIVER_NAME,
},
.probe = oaktrail_probe,
.remove = oaktrail_remove,
};
static int dmi_check_cb(const struct dmi_system_id *id)
......
......@@ -221,9 +221,9 @@ void pmc_core_get_tgl_lpm_reqs(struct platform_device *pdev)
guid_parse(ACPI_S0IX_DSM_UUID, &s0ix_dsm_guid);
out_obj = acpi_evaluate_dsm(adev->handle, &s0ix_dsm_guid, 0,
ACPI_GET_LOW_MODE_REGISTERS, NULL);
if (out_obj && out_obj->type == ACPI_TYPE_BUFFER) {
out_obj = acpi_evaluate_dsm_typed(adev->handle, &s0ix_dsm_guid, 0,
ACPI_GET_LOW_MODE_REGISTERS, NULL, ACPI_TYPE_BUFFER);
if (out_obj) {
u32 size = out_obj->buffer.length;
if (size != lpm_size) {
......
......@@ -302,11 +302,6 @@ static int intel_punit_ipc_probe(struct platform_device *pdev)
return 0;
}
static int intel_punit_ipc_remove(struct platform_device *pdev)
{
return 0;
}
static const struct acpi_device_id punit_ipc_acpi_ids[] = {
{ "INT34D4", 0 },
{ }
......@@ -315,7 +310,6 @@ MODULE_DEVICE_TABLE(acpi, punit_ipc_acpi_ids);
static struct platform_driver intel_punit_ipc_driver = {
.probe = intel_punit_ipc_probe,
.remove = intel_punit_ipc_remove,
.driver = {
.name = "intel_punit_ipc",
.acpi_match_table = punit_ipc_acpi_ids,
......
This diff is collapsed.
......@@ -64,6 +64,7 @@ enum intel_vsec_id {
VSEC_ID_WATCHER = 3,
VSEC_ID_CRASHLOG = 4,
VSEC_ID_SDSI = 65,
VSEC_ID_TPMI = 66,
};
static enum intel_vsec_id intel_vsec_allow_list[] = {
......@@ -71,6 +72,7 @@ static enum intel_vsec_id intel_vsec_allow_list[] = {
VSEC_ID_WATCHER,
VSEC_ID_CRASHLOG,
VSEC_ID_SDSI,
VSEC_ID_TPMI,
};
static const char *intel_vsec_name(enum intel_vsec_id id)
......@@ -88,6 +90,9 @@ static const char *intel_vsec_name(enum intel_vsec_id id)
case VSEC_ID_SDSI:
return "sdsi";
case VSEC_ID_TPMI:
return "tpmi";
default:
return NULL;
}
......@@ -124,35 +129,48 @@ static void intel_vsec_remove_aux(void *data)
auxiliary_device_uninit(data);
}
static DEFINE_MUTEX(vsec_ida_lock);
static void intel_vsec_dev_release(struct device *dev)
{
struct intel_vsec_device *intel_vsec_dev = dev_to_ivdev(dev);
mutex_lock(&vsec_ida_lock);
ida_free(intel_vsec_dev->ida, intel_vsec_dev->auxdev.id);
mutex_unlock(&vsec_ida_lock);
kfree(intel_vsec_dev->resource);
kfree(intel_vsec_dev);
}
static int intel_vsec_add_aux(struct pci_dev *pdev, struct intel_vsec_device *intel_vsec_dev,
int intel_vsec_add_aux(struct pci_dev *pdev, struct device *parent,
struct intel_vsec_device *intel_vsec_dev,
const char *name)
{
struct auxiliary_device *auxdev = &intel_vsec_dev->auxdev;
int ret, id;
mutex_lock(&vsec_ida_lock);
ret = ida_alloc(intel_vsec_dev->ida, GFP_KERNEL);
mutex_unlock(&vsec_ida_lock);
if (ret < 0) {
kfree(intel_vsec_dev);
return ret;
}
if (!parent)
parent = &pdev->dev;
auxdev->id = ret;
auxdev->name = name;
auxdev->dev.parent = &pdev->dev;
auxdev->dev.parent = parent;
auxdev->dev.release = intel_vsec_dev_release;
ret = auxiliary_device_init(auxdev);
if (ret < 0) {
mutex_lock(&vsec_ida_lock);
ida_free(intel_vsec_dev->ida, auxdev->id);
mutex_unlock(&vsec_ida_lock);
kfree(intel_vsec_dev->resource);
kfree(intel_vsec_dev);
return ret;
......@@ -164,7 +182,7 @@ static int intel_vsec_add_aux(struct pci_dev *pdev, struct intel_vsec_device *in
return ret;
}
ret = devm_add_action_or_reset(&pdev->dev, intel_vsec_remove_aux,
ret = devm_add_action_or_reset(parent, intel_vsec_remove_aux,
auxdev);
if (ret < 0)
return ret;
......@@ -177,6 +195,7 @@ static int intel_vsec_add_aux(struct pci_dev *pdev, struct intel_vsec_device *in
return 0;
}
EXPORT_SYMBOL_NS_GPL(intel_vsec_add_aux, INTEL_VSEC);
static int intel_vsec_add_dev(struct pci_dev *pdev, struct intel_vsec_header *header,
struct intel_vsec_platform_info *info)
......@@ -234,7 +253,8 @@ static int intel_vsec_add_dev(struct pci_dev *pdev, struct intel_vsec_header *he
else
intel_vsec_dev->ida = &intel_vsec_ida;
return intel_vsec_add_aux(pdev, intel_vsec_dev, intel_vsec_name(header->id));
return intel_vsec_add_aux(pdev, NULL, intel_vsec_dev,
intel_vsec_name(header->id));
}
static bool intel_vsec_walk_header(struct pci_dev *pdev,
......
......@@ -38,8 +38,14 @@ struct intel_vsec_device {
struct ida *ida;
struct intel_vsec_platform_info *info;
int num_resources;
void *priv_data;
size_t priv_data_size;
};
int intel_vsec_add_aux(struct pci_dev *pdev, struct device *parent,
struct intel_vsec_device *intel_vsec_dev,
const char *name);
static inline struct intel_vsec_device *dev_to_ivdev(struct device *dev)
{
return container_of(dev, struct intel_vsec_device, auxdev.dev);
......
This diff is collapsed.
......@@ -12,6 +12,10 @@
#include <linux/wmi.h>
#include <acpi/video.h>
static bool force;
module_param(force, bool, 0444);
MODULE_PARM_DESC(force, "Force loading (disable acpi_backlight=xxx checks");
/**
* wmi_brightness_notify() - helper function for calling WMI-wrapped ACPI method
* @w: Pointer to the struct wmi_device identified by %WMI_BRIGHTNESS_GUID
......@@ -91,7 +95,7 @@ static int nvidia_wmi_ec_backlight_probe(struct wmi_device *wdev, const void *ct
int ret;
/* drivers/acpi/video_detect.c also checks that SOURCE == EC */
if (acpi_video_get_backlight_type() != acpi_backlight_nvidia_wmi_ec)
if (!force && acpi_video_get_backlight_type() != acpi_backlight_nvidia_wmi_ec)
return -ENODEV;
/*
......
......@@ -317,8 +317,8 @@ static int tlmi_get_pwd_settings(struct tlmi_pwdcfg *pwdcfg)
return -EIO;
}
copy_size = obj->buffer.length < sizeof(struct tlmi_pwdcfg) ?
obj->buffer.length : sizeof(struct tlmi_pwdcfg);
copy_size = min_t(size_t, obj->buffer.length, sizeof(struct tlmi_pwdcfg));
memcpy(pwdcfg, obj->buffer.pointer, copy_size);
kfree(obj);
......@@ -1089,12 +1089,12 @@ static void tlmi_pwd_setting_release(struct kobject *kobj)
kfree(setting);
}
static struct kobj_type tlmi_attr_setting_ktype = {
static const struct kobj_type tlmi_attr_setting_ktype = {
.release = &tlmi_attr_setting_release,
.sysfs_ops = &tlmi_kobj_sysfs_ops,
};
static struct kobj_type tlmi_pwd_setting_ktype = {
static const struct kobj_type tlmi_pwd_setting_ktype = {
.release = &tlmi_pwd_setting_release,
.sysfs_ops = &tlmi_kobj_sysfs_ops,
};
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment