diff options
Diffstat (limited to 'drivers/base/platform.c')
| -rw-r--r-- | drivers/base/platform.c | 56 | 
1 files changed, 54 insertions, 2 deletions
diff --git a/drivers/base/platform.c b/drivers/base/platform.c index eee48c49f5de..ab4f4ce02722 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -23,6 +23,8 @@  #include <linux/pm_runtime.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 +177,7 @@ EXPORT_SYMBOL_GPL(platform_add_devices);  struct platform_object {  	struct platform_device pdev; -	char name[1]; +	char name[];  };  /** @@ -201,6 +203,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 +219,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,6 +502,10 @@ static int platform_drv_probe(struct device *_dev)  	struct platform_device *dev = to_platform_device(_dev);  	int ret; +	ret = of_clk_set_defaults(_dev->of_node, false); +	if (ret < 0) +		return ret; +  	acpi_dev_pm_attach(_dev, true);  	ret = drv->probe(dev); @@ -708,8 +715,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 +813,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;  |