platform/x86: intel_scu_ipc: Add managed function to register SCU IPC
authorMika Westerberg <mika.westerberg@linux.intel.com>
Thu, 16 Apr 2020 08:15:40 +0000 (11:15 +0300)
committerLee Jones <lee.jones@linaro.org>
Fri, 24 Apr 2020 10:17:44 +0000 (11:17 +0100)
Drivers such as intel_pmc_ipc.c can be unloaded as well so in order to
support those in this driver add a new function that can be called to
unregister the SCU IPC when it is not needed anymore.

We also add a managed version of the intel_scu_ipc_register() that takes
care of calling intel_scu_ipc_unregister() automatically when the driver
is unbound.

Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
arch/x86/include/asm/intel_scu_ipc.h
drivers/platform/x86/intel_scu_ipc.c

index d5f6ae5..11d457a 100644 (file)
@@ -25,6 +25,16 @@ __intel_scu_ipc_register(struct device *parent,
 #define intel_scu_ipc_register(parent, scu_data)  \
        __intel_scu_ipc_register(parent, scu_data, THIS_MODULE)
 
+void intel_scu_ipc_unregister(struct intel_scu_ipc_dev *scu);
+
+struct intel_scu_ipc_dev *
+__devm_intel_scu_ipc_register(struct device *parent,
+                             const struct intel_scu_ipc_data *scu_data,
+                             struct module *owner);
+
+#define devm_intel_scu_ipc_register(parent, scu_data)  \
+       __devm_intel_scu_ipc_register(parent, scu_data, THIS_MODULE)
+
 struct intel_scu_ipc_dev *intel_scu_ipc_dev_get(void);
 void intel_scu_ipc_dev_put(struct intel_scu_ipc_dev *scu);
 struct intel_scu_ipc_dev *devm_intel_scu_ipc_dev_get(struct device *dev);
index 608034e..d9cf7f7 100644 (file)
@@ -637,6 +637,68 @@ err_unlock:
 }
 EXPORT_SYMBOL_GPL(__intel_scu_ipc_register);
 
+/**
+ * intel_scu_ipc_unregister() - Unregister SCU IPC
+ * @scu: SCU IPC handle
+ *
+ * This unregisters the SCU IPC device and releases the acquired
+ * resources once the refcount goes to zero.
+ */
+void intel_scu_ipc_unregister(struct intel_scu_ipc_dev *scu)
+{
+       mutex_lock(&ipclock);
+       if (!WARN_ON(!ipcdev)) {
+               ipcdev = NULL;
+               device_unregister(&scu->dev);
+       }
+       mutex_unlock(&ipclock);
+}
+EXPORT_SYMBOL_GPL(intel_scu_ipc_unregister);
+
+static void devm_intel_scu_ipc_unregister(struct device *dev, void *res)
+{
+       struct intel_scu_ipc_devres *dr = res;
+       struct intel_scu_ipc_dev *scu = dr->scu;
+
+       intel_scu_ipc_unregister(scu);
+}
+
+/**
+ * __devm_intel_scu_ipc_register() - Register managed SCU IPC device
+ * @parent: Parent device
+ * @scu_data: Data used to configure SCU IPC
+ * @owner: Module registering the SCU IPC device
+ *
+ * Call this function to register managed SCU IPC mechanism under
+ * @parent. Returns pointer to the new SCU IPC device or ERR_PTR() in
+ * case of failure. The caller may use the returned instance if it needs
+ * to do SCU IPC calls itself.
+ */
+struct intel_scu_ipc_dev *
+__devm_intel_scu_ipc_register(struct device *parent,
+                             const struct intel_scu_ipc_data *scu_data,
+                             struct module *owner)
+{
+       struct intel_scu_ipc_devres *dr;
+       struct intel_scu_ipc_dev *scu;
+
+       dr = devres_alloc(devm_intel_scu_ipc_unregister, sizeof(*dr), GFP_KERNEL);
+       if (!dr)
+               return NULL;
+
+       scu = __intel_scu_ipc_register(parent, scu_data, owner);
+       if (IS_ERR(scu)) {
+               devres_free(dr);
+               return scu;
+       }
+
+       dr->scu = scu;
+       devres_add(parent, dr);
+
+       return scu;
+}
+EXPORT_SYMBOL_GPL(__devm_intel_scu_ipc_register);
+
 static int __init intel_scu_ipc_init(void)
 {
        return class_register(&intel_scu_ipc_class);