summaryrefslogtreecommitdiff
path: root/drivers/platform
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/chrome/cros_ec_ishtp.c1
-rw-r--r--drivers/platform/chrome/cros_ec_lightbar.c16
-rw-r--r--drivers/platform/chrome/cros_ec_sensorhub_ring.c11
-rw-r--r--drivers/platform/chrome/cros_usbpd_notify.c17
-rw-r--r--drivers/platform/surface/surface_aggregator_registry.c13
-rw-r--r--drivers/platform/x86/intel/Kconfig13
-rw-r--r--drivers/platform/x86/intel/Makefile1
-rw-r--r--drivers/platform/x86/intel/chtwc_int33fe.c29
-rw-r--r--drivers/platform/x86/intel/ehl_pse_io.c86
9 files changed, 160 insertions, 27 deletions
diff --git a/drivers/platform/chrome/cros_ec_ishtp.c b/drivers/platform/chrome/cros_ec_ishtp.c
index 4e74e702c5a2..3766cef81fe8 100644
--- a/drivers/platform/chrome/cros_ec_ishtp.c
+++ b/drivers/platform/chrome/cros_ec_ishtp.c
@@ -667,6 +667,7 @@ static void cros_ec_ishtp_remove(struct ishtp_cl_device *cl_device)
cancel_work_sync(&client_data->work_ishtp_reset);
cancel_work_sync(&client_data->work_ec_evt);
+ cros_ec_unregister(client_data->ec_dev);
cros_ish_deinit(cros_ish_cl);
ishtp_put_device(cl_device);
}
diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c
index 87634f6921b7..8352e9732791 100644
--- a/drivers/platform/chrome/cros_ec_lightbar.c
+++ b/drivers/platform/chrome/cros_ec_lightbar.c
@@ -30,6 +30,13 @@ static unsigned long lb_interval_jiffies = 50 * HZ / 1000;
*/
static bool userspace_control;
+/*
+ * Whether or not the lightbar supports the manual suspend commands.
+ * The Pixel 2013 (Link) does not while all other devices with a
+ * lightbar do.
+ */
+static bool has_manual_suspend;
+
static ssize_t interval_msec_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -550,7 +557,7 @@ static int cros_ec_lightbar_probe(struct platform_device *pd)
return -ENODEV;
/* Take control of the lightbar from the EC. */
- lb_manual_suspend_ctrl(ec_dev, 1);
+ has_manual_suspend = (lb_manual_suspend_ctrl(ec_dev, 1) != -EINVAL);
ret = sysfs_create_group(&ec_dev->class_dev.kobj,
&cros_ec_lightbar_attr_group);
@@ -569,14 +576,15 @@ static void cros_ec_lightbar_remove(struct platform_device *pd)
&cros_ec_lightbar_attr_group);
/* Let the EC take over the lightbar again. */
- lb_manual_suspend_ctrl(ec_dev, 0);
+ if (has_manual_suspend)
+ lb_manual_suspend_ctrl(ec_dev, 0);
}
static int __maybe_unused cros_ec_lightbar_resume(struct device *dev)
{
struct cros_ec_dev *ec_dev = dev_get_drvdata(dev->parent);
- if (userspace_control)
+ if (userspace_control || !has_manual_suspend)
return 0;
return lb_send_empty_cmd(ec_dev, LIGHTBAR_CMD_RESUME);
@@ -586,7 +594,7 @@ static int __maybe_unused cros_ec_lightbar_suspend(struct device *dev)
{
struct cros_ec_dev *ec_dev = dev_get_drvdata(dev->parent);
- if (userspace_control)
+ if (userspace_control || !has_manual_suspend)
return 0;
return lb_send_empty_cmd(ec_dev, LIGHTBAR_CMD_SUSPEND);
diff --git a/drivers/platform/chrome/cros_ec_sensorhub_ring.c b/drivers/platform/chrome/cros_ec_sensorhub_ring.c
index 1205219515d6..a10579144c34 100644
--- a/drivers/platform/chrome/cros_ec_sensorhub_ring.c
+++ b/drivers/platform/chrome/cros_ec_sensorhub_ring.c
@@ -129,6 +129,17 @@ int cros_ec_sensorhub_ring_fifo_enable(struct cros_ec_sensorhub *sensorhub,
/* We expect to receive a payload of 4 bytes, ignore. */
if (ret > 0)
ret = 0;
+ /*
+ * Some platforms (such as Smaug) don't support the FIFO_INT_ENABLE
+ * command and the interrupt is always enabled. In the case, it
+ * returns -EINVAL.
+ *
+ * N.B: there is no danger of -EINVAL meaning any other invalid
+ * parameter since fifo_int_enable.enable is a bool and can never
+ * be in an invalid range.
+ */
+ else if (ret == -EINVAL)
+ ret = 0;
return ret;
}
diff --git a/drivers/platform/chrome/cros_usbpd_notify.c b/drivers/platform/chrome/cros_usbpd_notify.c
index 313d2bcd577b..c90174360004 100644
--- a/drivers/platform/chrome/cros_usbpd_notify.c
+++ b/drivers/platform/chrome/cros_usbpd_notify.c
@@ -6,6 +6,7 @@
*/
#include <linux/acpi.h>
+#include <linux/fwnode.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_data/cros_ec_proto.h>
@@ -15,6 +16,7 @@
#define DRV_NAME "cros-usbpd-notify"
#define DRV_NAME_PLAT_ACPI "cros-usbpd-notify-acpi"
#define ACPI_DRV_NAME "GOOG0003"
+#define CREC_DRV_NAME "GOOG0004"
static BLOCKING_NOTIFIER_HEAD(cros_usbpd_notifier_list);
@@ -98,8 +100,9 @@ static int cros_usbpd_notify_probe_acpi(struct platform_device *pdev)
{
struct cros_usbpd_notify_data *pdnotify;
struct device *dev = &pdev->dev;
- struct acpi_device *adev;
+ struct acpi_device *adev, *parent_adev;
struct cros_ec_device *ec_dev;
+ struct fwnode_handle *parent_fwnode;
acpi_status status;
adev = ACPI_COMPANION(dev);
@@ -114,8 +117,18 @@ static int cros_usbpd_notify_probe_acpi(struct platform_device *pdev)
/*
* We continue even for older devices which don't have the
* correct device heirarchy, namely, GOOG0003 is a child
- * of GOOG0004.
+ * of GOOG0004. If GOOG0003 is a child of GOOG0004 and we
+ * can't get a pointer to the Chrome EC device, defer the
+ * probe function.
*/
+ parent_fwnode = fwnode_get_parent(dev->fwnode);
+ if (parent_fwnode) {
+ parent_adev = to_acpi_device_node(parent_fwnode);
+ if (parent_adev &&
+ acpi_dev_hid_match(parent_adev, CREC_DRV_NAME)) {
+ return -EPROBE_DEFER;
+ }
+ }
dev_warn(dev, "Couldn't get Chrome EC device pointer.\n");
}
diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
index a594d5fcfcfd..78ac3a8fbb73 100644
--- a/drivers/platform/surface/surface_aggregator_registry.c
+++ b/drivers/platform/surface/surface_aggregator_registry.c
@@ -491,24 +491,13 @@ static const struct of_device_id ssam_platform_hub_of_match[] __maybe_unused = {
static int ssam_platform_hub_probe(struct platform_device *pdev)
{
const struct software_node **nodes;
- const struct of_device_id *match;
- struct device_node *fdt_root;
struct ssam_controller *ctrl;
struct fwnode_handle *root;
int status;
nodes = (const struct software_node **)acpi_device_get_match_data(&pdev->dev);
if (!nodes) {
- fdt_root = of_find_node_by_path("/");
- if (!fdt_root)
- return -ENODEV;
-
- match = of_match_node(ssam_platform_hub_of_match, fdt_root);
- of_node_put(fdt_root);
- if (!match)
- return -ENODEV;
-
- nodes = (const struct software_node **)match->data;
+ nodes = (const struct software_node **)of_machine_get_match_data(ssam_platform_hub_of_match);
if (!nodes)
return -ENODEV;
}
diff --git a/drivers/platform/x86/intel/Kconfig b/drivers/platform/x86/intel/Kconfig
index 19a2246f2770..2900407d6095 100644
--- a/drivers/platform/x86/intel/Kconfig
+++ b/drivers/platform/x86/intel/Kconfig
@@ -41,6 +41,19 @@ config INTEL_VBTN
To compile this driver as a module, choose M here: the module will
be called intel_vbtn.
+config INTEL_EHL_PSE_IO
+ tristate "Intel Elkhart Lake PSE I/O driver"
+ depends on PCI
+ select AUXILIARY_BUS
+ help
+ Select this option to enable Intel Elkhart Lake PSE GPIO and Timed
+ I/O support. This driver enumerates the PCI parent device and
+ creates auxiliary child devices for these capabilities. The actual
+ functionalities are provided by their respective auxiliary drivers.
+
+ To compile this driver as a module, choose M here: the module will
+ be called intel_ehl_pse_io.
+
config INTEL_INT0002_VGPIO
tristate "Intel ACPI INT0002 Virtual GPIO driver"
depends on GPIOLIB && ACPI && PM_SLEEP
diff --git a/drivers/platform/x86/intel/Makefile b/drivers/platform/x86/intel/Makefile
index 78acb414e154..138b13756158 100644
--- a/drivers/platform/x86/intel/Makefile
+++ b/drivers/platform/x86/intel/Makefile
@@ -21,6 +21,7 @@ intel-target-$(CONFIG_INTEL_HID_EVENT) += hid.o
intel-target-$(CONFIG_INTEL_VBTN) += vbtn.o
# Intel miscellaneous drivers
+intel-target-$(CONFIG_INTEL_EHL_PSE_IO) += ehl_pse_io.o
intel-target-$(CONFIG_INTEL_INT0002_VGPIO) += int0002_vgpio.o
intel-target-$(CONFIG_INTEL_ISHTP_ECLITE) += ishtp_eclite.o
intel-target-$(CONFIG_INTEL_OAKTRAIL) += oaktrail.o
diff --git a/drivers/platform/x86/intel/chtwc_int33fe.c b/drivers/platform/x86/intel/chtwc_int33fe.c
index 29e8b5432f4c..d183aa53c318 100644
--- a/drivers/platform/x86/intel/chtwc_int33fe.c
+++ b/drivers/platform/x86/intel/chtwc_int33fe.c
@@ -77,7 +77,7 @@ static const struct software_node max17047_node = {
* software node.
*/
static struct software_node_ref_args fusb302_mux_refs[] = {
- { .node = NULL },
+ SOFTWARE_NODE_REFERENCE(NULL),
};
static const struct property_entry fusb302_properties[] = {
@@ -190,11 +190,6 @@ static void cht_int33fe_remove_nodes(struct cht_int33fe_data *data)
{
software_node_unregister_node_group(node_group);
- if (fusb302_mux_refs[0].node) {
- fwnode_handle_put(software_node_fwnode(fusb302_mux_refs[0].node));
- fusb302_mux_refs[0].node = NULL;
- }
-
if (data->dp) {
data->dp->secondary = NULL;
fwnode_handle_put(data->dp);
@@ -202,7 +197,15 @@ static void cht_int33fe_remove_nodes(struct cht_int33fe_data *data)
}
}
-static int cht_int33fe_add_nodes(struct cht_int33fe_data *data)
+static void cht_int33fe_put_swnode(void *data)
+{
+ struct fwnode_handle *fwnode = data;
+
+ fwnode_handle_put(fwnode);
+ fusb302_mux_refs[0] = SOFTWARE_NODE_REFERENCE(NULL);
+}
+
+static int cht_int33fe_add_nodes(struct device *dev, struct cht_int33fe_data *data)
{
const struct software_node *mux_ref_node;
int ret;
@@ -212,17 +215,25 @@ static int cht_int33fe_add_nodes(struct cht_int33fe_data *data)
* until the mux driver has created software node for the mux device.
* It means we depend on the mux driver. This function will return
* -EPROBE_DEFER until the mux device is registered.
+ *
+ * FIXME: the relevant software node exists in intel-xhci-usb-role-switch
+ * and - if exported - could be used to set up a static reference.
*/
mux_ref_node = software_node_find_by_name(NULL, "intel-xhci-usb-sw");
if (!mux_ref_node)
return -EPROBE_DEFER;
+ ret = devm_add_action_or_reset(dev, cht_int33fe_put_swnode,
+ software_node_fwnode(mux_ref_node));
+ if (ret)
+ return ret;
+
/*
* Update node used in "usb-role-switch" property. Note that we
* rely on software_node_register_node_group() to use the original
* instance of properties instead of copying them.
*/
- fusb302_mux_refs[0].node = mux_ref_node;
+ fusb302_mux_refs[0] = SOFTWARE_NODE_REFERENCE(mux_ref_node);
ret = software_node_register_node_group(node_group);
if (ret)
@@ -345,7 +356,7 @@ static int cht_int33fe_typec_probe(struct platform_device *pdev)
return fusb302_irq;
}
- ret = cht_int33fe_add_nodes(data);
+ ret = cht_int33fe_add_nodes(dev, data);
if (ret)
return ret;
diff --git a/drivers/platform/x86/intel/ehl_pse_io.c b/drivers/platform/x86/intel/ehl_pse_io.c
new file mode 100644
index 000000000000..861e14808b35
--- /dev/null
+++ b/drivers/platform/x86/intel/ehl_pse_io.c
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Intel Elkhart Lake Programmable Service Engine (PSE) I/O
+ *
+ * Copyright (c) 2025 Intel Corporation.
+ *
+ * Author: Raag Jadav <raag.jadav@intel.com>
+ */
+
+#include <linux/auxiliary_bus.h>
+#include <linux/device/devres.h>
+#include <linux/errno.h>
+#include <linux/gfp_types.h>
+#include <linux/ioport.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/sizes.h>
+#include <linux/types.h>
+
+#include <linux/ehl_pse_io_aux.h>
+
+#define EHL_PSE_IO_DEV_SIZE SZ_4K
+
+static int ehl_pse_io_dev_create(struct pci_dev *pci, const char *name, int idx)
+{
+ struct device *dev = &pci->dev;
+ struct auxiliary_device *adev;
+ struct ehl_pse_io_data *data;
+ resource_size_t start, offset;
+ u32 id;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ id = (pci_domain_nr(pci->bus) << 16) | pci_dev_id(pci);
+ start = pci_resource_start(pci, 0);
+ offset = EHL_PSE_IO_DEV_SIZE * idx;
+
+ data->mem = DEFINE_RES_MEM(start + offset, EHL_PSE_IO_DEV_SIZE);
+ data->irq = pci_irq_vector(pci, idx);
+
+ adev = __devm_auxiliary_device_create(dev, EHL_PSE_IO_NAME, name, data, id);
+
+ return adev ? 0 : -ENODEV;
+}
+
+static int ehl_pse_io_probe(struct pci_dev *pci, const struct pci_device_id *id)
+{
+ int ret;
+
+ ret = pcim_enable_device(pci);
+ if (ret)
+ return ret;
+
+ pci_set_master(pci);
+
+ ret = pci_alloc_irq_vectors(pci, 2, 2, PCI_IRQ_MSI);
+ if (ret < 0)
+ return ret;
+
+ ret = ehl_pse_io_dev_create(pci, EHL_PSE_GPIO_NAME, 0);
+ if (ret)
+ return ret;
+
+ return ehl_pse_io_dev_create(pci, EHL_PSE_TIO_NAME, 1);
+}
+
+static const struct pci_device_id ehl_pse_io_ids[] = {
+ { PCI_VDEVICE(INTEL, 0x4b88) },
+ { PCI_VDEVICE(INTEL, 0x4b89) },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, ehl_pse_io_ids);
+
+static struct pci_driver ehl_pse_io_driver = {
+ .name = EHL_PSE_IO_NAME,
+ .id_table = ehl_pse_io_ids,
+ .probe = ehl_pse_io_probe,
+};
+module_pci_driver(ehl_pse_io_driver);
+
+MODULE_AUTHOR("Raag Jadav <raag.jadav@intel.com>");
+MODULE_DESCRIPTION("Intel Elkhart Lake PSE I/O driver");
+MODULE_LICENSE("GPL");