ACPI / platform: create LPSS clocks if Lynxpoint devices are found during scan
Mika Westerberg [Fri, 18 Jan 2013 13:46:01 +0000 (13:46 +0000)]
Intel Lynxpoint LPSS peripheral drivers depend on LPSS clock tree being
created in order to function properly. The clock tree is exposed as a
platform driver that binds to a device named 'clk-lpt'.

To support this we modify the acpi_create_platform_device() to take one
additional parameter called flags. This is passed from
acpi_platform_device_ids[] array when acpi_create_platform_device() is
called.

We then introduce a new flag ACPI_PLATFORM_CLK which is used to tell
acpi_create_platform_device() to create the platform clocks as well.

Finally we set the ACPI_PLATFORM_CLK flags for all the Lynxpoint LPSS
devices and make sure that when this flag is set we create the
corresponding clock tree platform device.

Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

drivers/acpi/acpi_platform.c
drivers/acpi/internal.h
drivers/acpi/scan.c

index 5554aea..2d1fb4c 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/acpi.h>
 #include <linux/device.h>
+#include <linux/err.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 
 ACPI_MODULE_NAME("platform");
 
+static int acpi_create_platform_clks(struct acpi_device *adev)
+{
+       static struct platform_device *pdev;
+
+       /* Create Lynxpoint LPSS clocks */
+       if (!pdev && !strncmp(acpi_device_hid(adev), "INT33C", 6)) {
+               pdev = platform_device_register_simple("clk-lpt", -1, NULL, 0);
+               if (IS_ERR(pdev))
+                       return PTR_ERR(pdev);
+       }
+
+       return 0;
+}
+
 /**
  * acpi_create_platform_device - Create platform device for ACPI device node
  * @adev: ACPI device node to create a platform device for.
+ * @flags: ACPI_PLATFORM_* flags that affect the creation of the platform
+ *        devices.
  *
  * Check if the given @adev can be represented as a platform device and, if
  * that's the case, create and register a platform device, populate its common
@@ -31,7 +48,8 @@ ACPI_MODULE_NAME("platform");
  *
  * Name of the platform device will be the same as @adev's.
  */
-struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
+struct platform_device *acpi_create_platform_device(struct acpi_device *adev,
+                                                   unsigned long flags)
 {
        struct platform_device *pdev = NULL;
        struct acpi_device *acpi_parent;
@@ -41,6 +59,11 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
        struct resource *resources;
        int count;
 
+       if ((flags & ACPI_PLATFORM_CLK) && acpi_create_platform_clks(adev)) {
+               dev_err(&adev->dev, "failed to create clocks\n");
+               return NULL;
+       }
+
        /* If the ACPI node already has a physical device attached, skip it. */
        if (adev->physical_node_count)
                return NULL;
index 4d2e4bf..4b68373 100644 (file)
@@ -100,6 +100,10 @@ static inline void suspend_nvs_restore(void) {}
   -------------------------------------------------------------------------- */
 struct platform_device;
 
-struct platform_device *acpi_create_platform_device(struct acpi_device *adev);
+/* Flags for acpi_create_platform_device */
+#define ACPI_PLATFORM_CLK      BIT(0)
+
+struct platform_device *acpi_create_platform_device(struct acpi_device *adev,
+                                                   unsigned long flags);
 
 #endif /* _ACPI_INTERNAL_H_ */
index a85b408..fe171aa 100644 (file)
@@ -38,14 +38,14 @@ static const struct acpi_device_id acpi_platform_device_ids[] = {
        { "PNP0D40" },
 
        /* Haswell LPSS devices */
-       { "INT33C0", 0 },
-       { "INT33C1", 0 },
-       { "INT33C2", 0 },
-       { "INT33C3", 0 },
-       { "INT33C4", 0 },
-       { "INT33C5", 0 },
-       { "INT33C6", 0 },
-       { "INT33C7", 0 },
+       { "INT33C0", ACPI_PLATFORM_CLK },
+       { "INT33C1", ACPI_PLATFORM_CLK },
+       { "INT33C2", ACPI_PLATFORM_CLK },
+       { "INT33C3", ACPI_PLATFORM_CLK },
+       { "INT33C4", ACPI_PLATFORM_CLK },
+       { "INT33C5", ACPI_PLATFORM_CLK },
+       { "INT33C6", ACPI_PLATFORM_CLK },
+       { "INT33C7", ACPI_PLATFORM_CLK },
 
        { }
 };
@@ -1553,6 +1553,7 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
 static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used,
                                          void *not_used, void **ret_not_used)
 {
+       const struct acpi_device_id *id;
        acpi_status status = AE_OK;
        struct acpi_device *device;
        unsigned long long sta_not_used;
@@ -1568,9 +1569,10 @@ static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used,
        if (acpi_bus_get_device(handle, &device))
                return AE_CTRL_DEPTH;
 
-       if (!acpi_match_device_ids(device, acpi_platform_device_ids)) {
+       id = __acpi_match_device(device, acpi_platform_device_ids);
+       if (id) {
                /* This is a known good platform device. */
-               acpi_create_platform_device(device);
+               acpi_create_platform_device(device, id->driver_data);
        } else if (device_attach(&device->dev) < 0) {
                status = AE_CTRL_DEPTH;
        }