Merge branch 'for-next/defer'
This commit is contained in:
commit
389218585a
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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[] = {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue