]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/base/platform.c
Merge tag 'please-pull-sys_bpf' of git://git.kernel.org/pub/scm/linux/kernel/git...
[karo-tx-linux.git] / drivers / base / platform.c
index eee48c49f5def2b6f556454f14228b001d01ee27..b2afc29403f9e887554d441a0c36629ccb49bce6 100644 (file)
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/pm_runtime.h>
+#include <linux/pm_domain.h>
 #include <linux/idr.h>
 #include <linux/acpi.h>
+#include <linux/clk/clk-conf.h>
+#include <linux/limits.h>
 
 #include "base.h"
 #include "power/power.h"
@@ -175,7 +178,7 @@ EXPORT_SYMBOL_GPL(platform_add_devices);
 
 struct platform_object {
        struct platform_device pdev;
-       char name[1];
+       char name[];
 };
 
 /**
@@ -201,6 +204,7 @@ static void platform_device_release(struct device *dev)
        kfree(pa->pdev.dev.platform_data);
        kfree(pa->pdev.mfd_cell);
        kfree(pa->pdev.resource);
+       kfree(pa->pdev.driver_override);
        kfree(pa);
 }
 
@@ -216,7 +220,7 @@ struct platform_device *platform_device_alloc(const char *name, int id)
 {
        struct platform_object *pa;
 
-       pa = kzalloc(sizeof(struct platform_object) + strlen(name), GFP_KERNEL);
+       pa = kzalloc(sizeof(*pa) + strlen(name) + 1, GFP_KERNEL);
        if (pa) {
                strcpy(pa->name, name);
                pa->pdev.name = pa->name;
@@ -499,11 +503,16 @@ static int platform_drv_probe(struct device *_dev)
        struct platform_device *dev = to_platform_device(_dev);
        int ret;
 
-       acpi_dev_pm_attach(_dev, true);
+       ret = of_clk_set_defaults(_dev->of_node, false);
+       if (ret < 0)
+               return ret;
 
-       ret = drv->probe(dev);
-       if (ret)
-               acpi_dev_pm_detach(_dev, true);
+       ret = dev_pm_domain_attach(_dev, true);
+       if (ret != -EPROBE_DEFER) {
+               ret = drv->probe(dev);
+               if (ret)
+                       dev_pm_domain_detach(_dev, true);
+       }
 
        if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) {
                dev_warn(_dev, "probe deferral not supported\n");
@@ -525,7 +534,7 @@ static int platform_drv_remove(struct device *_dev)
        int ret;
 
        ret = drv->remove(dev);
-       acpi_dev_pm_detach(_dev, true);
+       dev_pm_domain_detach(_dev, true);
 
        return ret;
 }
@@ -536,7 +545,7 @@ static void platform_drv_shutdown(struct device *_dev)
        struct platform_device *dev = to_platform_device(_dev);
 
        drv->shutdown(dev);
-       acpi_dev_pm_detach(_dev, true);
+       dev_pm_domain_detach(_dev, true);
 }
 
 /**
@@ -708,8 +717,49 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
 }
 static DEVICE_ATTR_RO(modalias);
 
+static ssize_t driver_override_store(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       char *driver_override, *old = pdev->driver_override, *cp;
+
+       if (count > PATH_MAX)
+               return -EINVAL;
+
+       driver_override = kstrndup(buf, count, GFP_KERNEL);
+       if (!driver_override)
+               return -ENOMEM;
+
+       cp = strchr(driver_override, '\n');
+       if (cp)
+               *cp = '\0';
+
+       if (strlen(driver_override)) {
+               pdev->driver_override = driver_override;
+       } else {
+               kfree(driver_override);
+               pdev->driver_override = NULL;
+       }
+
+       kfree(old);
+
+       return count;
+}
+
+static ssize_t driver_override_show(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+
+       return sprintf(buf, "%s\n", pdev->driver_override);
+}
+static DEVICE_ATTR_RW(driver_override);
+
+
 static struct attribute *platform_dev_attrs[] = {
        &dev_attr_modalias.attr,
+       &dev_attr_driver_override.attr,
        NULL,
 };
 ATTRIBUTE_GROUPS(platform_dev);
@@ -765,6 +815,10 @@ static int platform_match(struct device *dev, struct device_driver *drv)
        struct platform_device *pdev = to_platform_device(dev);
        struct platform_driver *pdrv = to_platform_driver(drv);
 
+       /* When driver_override is set, only bind to the matching driver */
+       if (pdev->driver_override)
+               return !strcmp(pdev->driver_override, drv->name);
+
        /* Attempt an OF style match first */
        if (of_driver_match_device(dev, drv))
                return 1;