]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ASoC: SDCA: add a HID device for HIDE entity
authorShuming Fan <shumingf@realtek.com>
Mon, 16 Jun 2025 11:49:29 +0000 (19:49 +0800)
committerMark Brown <broonie@kernel.org>
Sun, 22 Jun 2025 23:26:53 +0000 (00:26 +0100)
This patch supports to add a HID device for SDCA HIDE entity.
The codec driver could call 'hid_input_report' to report events.

Signed-off-by: Shuming Fan <shumingf@realtek.com>
Reviewed-by: Charles Keepax <ckeepax@opensource.cirrus.com>
Link: https://patch.msgid.link/20250616114929.855496-1-shumingf@realtek.com
Signed-off-by: Mark Brown <broonie@kernel.org>
include/sound/sdca_hid.h [new file with mode: 0644]
sound/soc/sdca/Kconfig
sound/soc/sdca/Makefile
sound/soc/sdca/sdca_functions.c
sound/soc/sdca/sdca_hid.c [new file with mode: 0644]

diff --git a/include/sound/sdca_hid.h b/include/sound/sdca_hid.h
new file mode 100644 (file)
index 0000000..8ab3e49
--- /dev/null
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
+/*
+ * The MIPI SDCA specification is available for public downloads at
+ * https://www.mipi.org/mipi-sdca-v1-0-download
+ *
+ */
+
+#ifndef __SDCA_HID_H__
+#define __SDCA_HID_H__
+
+#include <linux/types.h>
+#include <linux/hid.h>
+
+#if IS_ENABLED(CONFIG_SND_SOC_SDCA_HID)
+int sdca_add_hid_device(struct device *dev, struct sdca_entity *entity);
+
+#else
+static inline int sdca_add_hid_device(struct device *dev, struct sdca_entity *entity)
+{
+       return 0;
+}
+
+#endif
+
+#endif /* __SDCA_HID_H__ */
index ee20b9914aa1faa512c88f64739d8654e76b00b1..ec28855fe3b09b1f2af932c9ec428aacdc7f2bd2 100644 (file)
@@ -9,3 +9,7 @@ config SND_SOC_SDCA
 
 config SND_SOC_SDCA_OPTIONAL
        def_tristate SND_SOC_SDCA || !SND_SOC_SDCA
+
+config SND_SOC_SDCA_HID
+       tristate "SDCA HID support"
+       depends on SND_SOC_SDCA && HID
index 53344f108ca676fe294aefe2a5859ed6dd7a7786..9af46e7edfd2afe82a72930fca5f015c20ecabc4 100644 (file)
@@ -2,4 +2,7 @@
 
 snd-soc-sdca-y := sdca_functions.o sdca_device.o sdca_regmap.o sdca_asoc.o
 
+snd-soc-sdca-hid-y := sdca_hid.o
+
+obj-$(CONFIG_SND_SOC_SDCA_HID) += snd-soc-sdca-hid.o
 obj-$(CONFIG_SND_SOC_SDCA)     += snd-soc-sdca.o
index 4a89067dcf7686f7ed7d9237bfcc8e63309c11c4..093c681e93879ed1b40d6daa3e919daa4bbbd2e7 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/types.h>
 #include <sound/sdca.h>
 #include <sound/sdca_function.h>
+#include <sound/sdca_hid.h>
 
 /*
  * Should be long enough to encompass all the MIPI DisCo properties.
@@ -1294,6 +1295,13 @@ find_sdca_entity_hide(struct device *dev, struct fwnode_handle *function_node,
                        hide->hid_report_desc = report_desc;
                        fwnode_property_read_u8_array(function_node, "mipi-sdca-report-descriptor",
                                                      report_desc, nval);
+
+                       /* add HID device */
+                       ret = sdca_add_hid_device(dev, entity);
+                       if (ret) {
+                               dev_err(dev, "%pfwP: failed to add HID device: %d\n", entity_node, ret);
+                               return ret;
+                       }
                }
        }
 
@@ -1933,3 +1941,4 @@ EXPORT_SYMBOL_NS(sdca_parse_function, "SND_SOC_SDCA");
 
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_DESCRIPTION("SDCA library");
+MODULE_IMPORT_NS("SND_SOC_SDCA_HID");
diff --git a/sound/soc/sdca/sdca_hid.c b/sound/soc/sdca/sdca_hid.c
new file mode 100644 (file)
index 0000000..b227ad9
--- /dev/null
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+
+/*
+ * The MIPI SDCA specification is available for public downloads at
+ * https://www.mipi.org/mipi-sdca-v1-0-download
+ */
+
+#include <linux/acpi.h>
+#include <linux/byteorder/generic.h>
+#include <linux/cleanup.h>
+#include <linux/device.h>
+#include <linux/dev_printk.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/types.h>
+#include <sound/sdca.h>
+#include <sound/sdca_function.h>
+#include <sound/sdca_hid.h>
+
+static int sdwhid_parse(struct hid_device *hid)
+{
+       struct sdca_entity *entity = hid->driver_data;
+       unsigned int rsize;
+       int ret;
+
+       rsize = entity->hide.hid_desc.rpt_desc.wDescriptorLength;
+
+       if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) {
+               dev_err(&hid->dev, "invalid size of report descriptor (%u)\n", rsize);
+               return -EINVAL;
+       }
+
+       ret = hid_parse_report(hid, entity->hide.hid_report_desc, rsize);
+
+       if (!ret)
+               return 0;
+
+       dev_err(&hid->dev, "parsing report descriptor failed\n");
+       return ret;
+}
+
+static int sdwhid_start(struct hid_device *hid)
+{
+       return 0;
+}
+
+static void sdwhid_stop(struct hid_device *hid)
+{
+}
+
+static int sdwhid_raw_request(struct hid_device *hid, unsigned char reportnum,
+                             __u8 *buf, size_t len, unsigned char rtype, int reqtype)
+{
+       switch (reqtype) {
+       case HID_REQ_GET_REPORT:
+               /* not implemented yet */
+               return 0;
+       case HID_REQ_SET_REPORT:
+               /* not implemented yet */
+               return 0;
+       default:
+               return -EIO;
+       }
+}
+
+static int sdwhid_open(struct hid_device *hid)
+{
+       return 0;
+}
+
+static void sdwhid_close(struct hid_device *hid)
+{
+}
+
+static const struct hid_ll_driver sdw_hid_driver = {
+       .parse = sdwhid_parse,
+       .start = sdwhid_start,
+       .stop = sdwhid_stop,
+       .open = sdwhid_open,
+       .close = sdwhid_close,
+       .raw_request = sdwhid_raw_request,
+};
+
+int sdca_add_hid_device(struct device *dev, struct sdca_entity *entity)
+{
+       struct sdw_bus *bus;
+       struct hid_device *hid;
+       struct sdw_slave *slave = dev_to_sdw_dev(dev);
+       int ret;
+
+       bus = slave->bus;
+
+       hid = hid_allocate_device();
+       if (IS_ERR(hid))
+               return PTR_ERR(hid);
+
+       hid->ll_driver = &sdw_hid_driver;
+
+       hid->dev.parent = dev;
+       hid->bus = BUS_SDW;
+       hid->version = le16_to_cpu(entity->hide.hid_desc.bcdHID);
+
+       snprintf(hid->name, sizeof(hid->name),
+                "HID sdw:%01x:%01x:%04x:%04x:%02x",
+                bus->controller_id, bus->link_id, slave->id.mfg_id,
+                slave->id.part_id, slave->id.class_id);
+
+       snprintf(hid->phys, sizeof(hid->phys), "%s", dev->bus->name);
+
+       hid->driver_data = entity;
+
+       ret = hid_add_device(hid);
+       if (ret && ret != -ENODEV) {
+               dev_err(dev, "can't add hid device: %d\n", ret);
+               hid_destroy_device(hid);
+               return ret;
+       }
+
+       entity->hide.hid = hid;
+
+       return 0;
+}
+EXPORT_SYMBOL_NS(sdca_add_hid_device, "SND_SOC_SDCA_HID");
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("SDCA HID library");