9
0
Fork 0

Merge branch 'for-next/defer'

This commit is contained in:
Sascha Hauer 2015-05-06 21:36:12 +02:00
commit 389218585a
7 changed files with 99 additions and 20 deletions

View File

@ -29,6 +29,7 @@
#include <console.h>
#include <linux/ctype.h>
#include <errno.h>
#include <init.h>
#include <fs.h>
#include <of.h>
#include <linux/list.h>
@ -43,6 +44,7 @@ LIST_HEAD(driver_list);
EXPORT_SYMBOL(driver_list);
static LIST_HEAD(active);
static LIST_HEAD(deferred);
struct device_d *get_device_by_name(const char *name)
{
@ -88,13 +90,20 @@ int device_probe(struct device_d *dev)
list_add(&dev->active, &active);
ret = dev->bus->probe(dev);
if (ret) {
if (ret == 0)
return 0;
if (ret == -EPROBE_DEFER) {
list_del(&dev->active);
dev_err(dev, "probe failed: %s\n", strerror(-ret));
list_add(&dev->active, &deferred);
dev_dbg(dev, "probe deferred\n");
return ret;
}
return 0;
list_del(&dev->active);
dev_err(dev, "probe failed: %s\n", strerror(-ret));
return ret;
}
int device_detect(struct device_d *dev)
@ -213,6 +222,47 @@ int unregister_device(struct device_d *old_dev)
}
EXPORT_SYMBOL(unregister_device);
/*
* Loop over list of deferred devices as long as at least one
* device is successfully probed. Devices that again request
* deferral are re-added to deferred list in device_probe().
* For devices finally left in deferred list -EPROBE_DEFER
* becomes a fatal error.
*/
static int device_probe_deferred(void)
{
struct device_d *dev, *tmp;
struct driver_d *drv;
bool success;
do {
success = false;
if (list_empty(&deferred))
break;
list_for_each_entry_safe(dev, tmp, &deferred, active) {
list_del(&dev->active);
dev_dbg(dev, "re-probe device\n");
bus_for_each_driver(dev->bus, drv) {
if (match(drv, dev))
continue;
success = true;
break;
}
}
} while (success);
if (list_empty(&deferred))
return 0;
list_for_each_entry(dev, &deferred, active)
dev_err(dev, "probe permanently deferred\n");
return 0;
}
late_initcall(device_probe_deferred);
struct driver_d *get_driver_by_name(const char *name)
{
struct driver_d *drv;

View File

@ -124,9 +124,4 @@ static struct driver_d orion_gpio_driver = {
.probe = orion_gpio_probe,
.of_compatible = DRV_OF_COMPAT(orion_gpio_dt_ids),
};
static int orion_gpio_init(void)
{
return platform_driver_register(&orion_gpio_driver);
}
postcore_initcall(orion_gpio_init);
device_platform_driver(orion_gpio_driver);

View File

@ -292,12 +292,15 @@ int gpio_get_num(struct device_d *dev, int gpio)
{
struct gpio_chip *chip;
if (!dev)
return -ENODEV;
list_for_each_entry(chip, &chip_list, list) {
if (chip->dev == dev)
return chip->base + gpio;
}
return -ENODEV;
return -EPROBE_DEFER;
}
#ifdef CONFIG_CMD_GPIO

View File

@ -20,6 +20,7 @@
#include <common.h>
#include <init.h>
#include <led.h>
#include <malloc.h>
#include <gpio.h>
#include <of_gpio.h>
@ -63,6 +64,7 @@ int led_gpio_register(struct gpio_led *led)
void led_gpio_unregister(struct gpio_led *led)
{
led_unregister(&led->led);
gpio_free(led->gpio);
}
#ifdef CONFIG_LED_GPIO_BICOLOR
@ -130,6 +132,8 @@ err_gpio_c0:
void led_gpio_bicolor_unregister(struct gpio_bicolor_led *led)
{
led_unregister(&led->led);
gpio_free(led->gpio_c1);
gpio_free(led->gpio_c0);
}
#endif
@ -191,9 +195,12 @@ err_gpio_r:
* led_gpio_rgb_unregister - remove a gpio controlled rgb LED from the framework
* @param led The gpio LED
*/
void led_gpio_rgb_unregister(struct gpio_led *led)
void led_gpio_rgb_unregister(struct gpio_rgb_led *led)
{
led_unregister(&led->led);
gpio_free(led->gpio_b);
gpio_free(led->gpio_g);
gpio_free(led->gpio_r);
}
#endif /* CONFIG_LED_GPIO_RGB */
@ -201,19 +208,32 @@ void led_gpio_rgb_unregister(struct gpio_led *led)
static int led_gpio_of_probe(struct device_d *dev)
{
struct device_node *child;
struct gpio_led *leds;
int num_leds;
int ret = 0, n = 0;
num_leds = of_get_child_count(dev->device_node);
if (num_leds <= 0)
return num_leds;
leds = xzalloc(num_leds * sizeof(struct gpio_led));
for_each_child_of_node(dev->device_node, child) {
struct gpio_led *gled;
struct gpio_led *gled = &leds[n];
const char *default_state;
enum of_gpio_flags flags;
int gpio;
const char *label;
gpio = of_get_named_gpio_flags(child, "gpios", 0, &flags);
if (gpio < 0)
continue;
if (gpio < 0) {
if (gpio != -EPROBE_DEFER)
dev_err(dev, "failed to get gpio for %s: %d\n",
child->full_name, gpio);
ret = gpio;
goto err;
}
gled = xzalloc(sizeof(*gled));
if (of_property_read_string(child, "label", &label))
label = child->name;
gled->led.name = xstrdup(label);
@ -233,9 +253,17 @@ static int led_gpio_of_probe(struct device_d *dev)
else if (!strcmp(default_state, "off"))
led_gpio_set(&gled->led, 0);
}
n++;
}
return 0;
err:
for (n = n - 1; n >= 0; n--)
led_gpio_unregister(&leds[n]);
free(leds);
return ret;
}
static struct of_device_id led_gpio_of_ids[] = {

View File

@ -32,12 +32,14 @@ int of_get_named_gpio_flags(struct device_node *np, const char *propname,
dev = of_find_device_by_node(out_args.np);
if (!dev) {
pr_err("%s: unable to find device of node %s\n",
__func__, out_args.np->full_name);
return -ENODEV;
pr_debug("%s: unable to find device of node %s\n",
__func__, out_args.np->full_name);
return -EPROBE_DEFER;
}
ret = gpio_get_num(dev, out_args.args[0]);
if (ret == -EPROBE_DEFER)
return ret;
if (ret < 0) {
pr_err("%s: unable to get gpio num of device %s: %d\n",
__func__, dev_name(dev), ret);

View File

@ -132,6 +132,7 @@
#define ERESTARTNOINTR 513
#define ERESTARTNOHAND 514 /* restart if no handler.. */
#define ENOIOCTLCMD 515 /* No ioctl command */
#define EPROBE_DEFER 517 /* Driver requests probe retry */
#define ENOTSUPP 524 /* Operation is not supported */

View File

@ -110,14 +110,14 @@ static inline void led_gpio_bicolor_unregister(struct gpio_bicolor_led *led)
#ifdef CONFIG_LED_GPIO_RGB
int led_gpio_rgb_register(struct gpio_rgb_led *led);
void led_gpio_rgb_unregister(struct gpio_led *led);
void led_gpio_rgb_unregister(struct gpio_rgb_led *led);
#else
static inline int led_gpio_rgb_register(struct gpio_rgb_led *led)
{
return -ENOSYS;
}
static inline void led_gpio_rgb_unregister(struct gpio_led *led)
static inline void led_gpio_rgb_unregister(struct gpio_rgb_led *led)
{
}
#endif