Discussion:
[PATCH 13/13] input: gpio_keys_polled - Make use of device property API
Rafael J. Wysocki
2014-10-07 00:19:20 UTC
Permalink
From: Aaron Lu <***@intel.com>

Make use of device property API in this driver so that both OF based
system and ACPI based system can use this driver.

Signed-off-by: Aaron Lu <***@intel.com>
Signed-off-by: Mika Westerberg <***@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <***@intel.com>
---
drivers/input/keyboard/gpio_keys_polled.c | 81 +++++++++++-------------------
1 file changed, 31 insertions(+), 50 deletions(-)

Index: linux-pm/drivers/input/keyboard/gpio_keys_polled.c
===================================================================
--- linux-pm.orig/drivers/input/keyboard/gpio_keys_polled.c
+++ linux-pm/drivers/input/keyboard/gpio_keys_polled.c
@@ -25,9 +25,7 @@
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio_keys.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/of_gpio.h>
+#include <linux/property.h>

#define DRV_NAME "gpio-keys-polled"

@@ -102,21 +100,15 @@ static void gpio_keys_polled_close(struc
pdata->disable(bdev->dev);
}

-#ifdef CONFIG_OF
static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct device *dev)
{
- struct device_node *node, *pp;
struct gpio_keys_platform_data *pdata;
struct gpio_keys_button *button;
+ void *child;
int error;
int nbuttons;
- int i;
-
- node = dev->of_node;
- if (!node)
- return NULL;

- nbuttons = of_get_child_count(node);
+ nbuttons = device_get_child_node_count(dev);
if (nbuttons == 0)
return NULL;

@@ -126,52 +118,50 @@ static struct gpio_keys_platform_data *g
return ERR_PTR(-ENOMEM);

pdata->buttons = (struct gpio_keys_button *)(pdata + 1);
- pdata->nbuttons = nbuttons;

- pdata->rep = !!of_get_property(node, "autorepeat", NULL);
- of_property_read_u32(node, "poll-interval", &pdata->poll_interval);
+ pdata->rep = !device_get_property(dev, "autorepeat", NULL);
+ device_property_read_u32(dev, "poll-interval", &pdata->poll_interval);

- i = 0;
- for_each_child_of_node(node, pp) {
- int gpio;
- enum of_gpio_flags flags;
-
- if (!of_find_property(pp, "gpios", NULL)) {
- pdata->nbuttons--;
- dev_warn(dev, "Found button without gpios\n");
- continue;
- }
+ device_for_each_child_node(dev, child) {
+ struct gpio_desc *desc;

- gpio = of_get_gpio_flags(pp, 0, &flags);
- if (gpio < 0) {
- error = gpio;
+ desc = devm_get_named_gpiod_from_child(dev, child, "gpios", 0);
+ if (IS_ERR(desc)) {
+ error = PTR_ERR(desc);
if (error != -EPROBE_DEFER)
dev_err(dev,
"Failed to get gpio flags, error: %d\n",
error);
+ device_put_child_node(dev, child);
return ERR_PTR(error);
}

- button = &pdata->buttons[i++];
-
- button->gpio = gpio;
- button->active_low = flags & OF_GPIO_ACTIVE_LOW;
+ button = &pdata->buttons[pdata->nbuttons++];
+ button->gpiod = desc;

- if (of_property_read_u32(pp, "linux,code", &button->code)) {
- dev_err(dev, "Button without keycode: 0x%x\n",
- button->gpio);
+ if (device_child_property_read_u32(dev, child, "linux,code",
+ &button->code)) {
+ dev_err(dev, "Button without keycode: %d\n",
+ pdata->nbuttons - 1);
+ device_put_child_node(dev, child);
return ERR_PTR(-EINVAL);
}

- button->desc = of_get_property(pp, "label", NULL);
+ device_child_property_read_string(dev, child, "label",
+ &button->desc);

- if (of_property_read_u32(pp, "linux,input-type", &button->type))
+ if (device_child_property_read_u32(dev, child,
+ "linux,input-type",
+ &button->type))
button->type = EV_KEY;

- button->wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL);
-
- if (of_property_read_u32(pp, "debounce-interval",
- &button->debounce_interval))
+ button->wakeup = !device_get_child_property(dev, child,
+ "gpio-key,wakeup",
+ NULL);
+
+ if (device_child_property_read_u32(dev, child,
+ "debounce-interval",
+ &button->debounce_interval))
button->debounce_interval = 5;
}

@@ -187,15 +177,6 @@ static const struct of_device_id gpio_ke
};
MODULE_DEVICE_TABLE(of, gpio_keys_polled_of_match);

-#else
-
-static inline struct gpio_keys_platform_data *
-gpio_keys_polled_get_devtree_pdata(struct device *dev)
-{
- return NULL;
-}
-#endif
-
static int gpio_keys_polled_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -323,7 +304,7 @@ static struct platform_driver gpio_keys_
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
- .of_match_table = of_match_ptr(gpio_keys_polled_of_match),
+ .of_match_table = gpio_keys_polled_of_match,
},
};
module_platform_driver(gpio_keys_polled_driver);
Rafael J. Wysocki
2014-10-07 00:18:45 UTC
Permalink
From: Rafael J. Wysocki <***@intel.com>

Make use of device property API in this driver so that both OF and ACPI
based system can use the same driver.

This change contains material from Max Eliaser and Mika Westerberg.

Signed-off-by: Mika Westerberg <***@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <***@intel.com>
---
drivers/leds/leds-gpio.c | 67 +++++++++++++++++++++--------------------------
1 file changed, 30 insertions(+), 37 deletions(-)

Index: linux-pm/drivers/leds/leds-gpio.c
===================================================================
--- linux-pm.orig/drivers/leds/leds-gpio.c
+++ linux-pm/drivers/leds/leds-gpio.c
@@ -15,13 +15,11 @@
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/leds.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/module.h>
#include <linux/err.h>
+#include <linux/property.h>

struct gpio_led_data {
struct led_classdev cdev;
@@ -171,40 +169,41 @@ static inline int sizeof_gpio_leds_priv(
(sizeof(struct gpio_led_data) * num_leds);
}

-/* Code to create from OpenFirmware platform devices */
-#ifdef CONFIG_OF_GPIO
-static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
+static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
{
- struct device_node *np = pdev->dev.of_node, *child;
+ struct device *dev = &pdev->dev;
struct gpio_leds_priv *priv;
int count, ret;
+ void *child;

- /* count LEDs in this device, so we know how much to allocate */
- count = of_get_available_child_count(np);
+ count = device_get_child_node_count(dev);
if (!count)
return ERR_PTR(-ENODEV);

- for_each_available_child_of_node(np, child)
- if (of_get_gpio(child, 0) == -EPROBE_DEFER)
- return ERR_PTR(-EPROBE_DEFER);
-
- priv = devm_kzalloc(&pdev->dev, sizeof_gpio_leds_priv(count),
- GFP_KERNEL);
+ priv = devm_kzalloc(dev, sizeof_gpio_leds_priv(count), GFP_KERNEL);
if (!priv)
return ERR_PTR(-ENOMEM);

- for_each_available_child_of_node(np, child) {
+ device_for_each_child_node(dev, child) {
struct gpio_led led = {};
- enum of_gpio_flags flags;
- const char *state;
+ const char *state = NULL;
+
+ led.gpiod = devm_get_named_gpiod_from_child(dev, child,
+ "gpios", 0);
+ if (IS_ERR(led.gpiod)) {
+ device_put_child_node(dev, child);
+ goto err;
+ }

- led.gpio = of_get_gpio_flags(child, 0, &flags);
- led.active_low = flags & OF_GPIO_ACTIVE_LOW;
- led.name = of_get_property(child, "label", NULL) ? : child->name;
- led.default_trigger =
- of_get_property(child, "linux,default-trigger", NULL);
- state = of_get_property(child, "default-state", NULL);
- if (state) {
+ device_child_property_read_string(dev, child,
+ "label", &led.name);
+ device_child_property_read_string(dev, child,
+ "linux,default-trigger",
+ &led.default_trigger);
+
+ if (!device_child_property_read_string(dev, child,
+ "linux,default_state",
+ &state)) {
if (!strcmp(state, "keep"))
led.default_state = LEDS_GPIO_DEFSTATE_KEEP;
else if (!strcmp(state, "on"))
@@ -213,13 +212,14 @@ static struct gpio_leds_priv *gpio_leds_
led.default_state = LEDS_GPIO_DEFSTATE_OFF;
}

- if (of_get_property(child, "retain-state-suspended", NULL))
+ if (!device_get_child_property(dev, child,
+ "retain-state-suspended", NULL))
led.retain_state_suspended = 1;

ret = create_gpio_led(&led, &priv->leds[priv->num_leds++],
- &pdev->dev, NULL);
+ dev, NULL);
if (ret < 0) {
- of_node_put(child);
+ device_put_child_node(dev, child);
goto err;
}
}
@@ -238,13 +238,6 @@ static const struct of_device_id of_gpio
};

MODULE_DEVICE_TABLE(of, of_gpio_leds_match);
-#else /* CONFIG_OF_GPIO */
-static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
-{
- return ERR_PTR(-ENODEV);
-}
-#endif /* CONFIG_OF_GPIO */
-

static int gpio_led_probe(struct platform_device *pdev)
{
@@ -273,7 +266,7 @@ static int gpio_led_probe(struct platfor
}
}
} else {
- priv = gpio_leds_create_of(pdev);
+ priv = gpio_leds_create(pdev);
if (IS_ERR(priv))
return PTR_ERR(priv);
}
@@ -300,7 +293,7 @@ static struct platform_driver gpio_led_d
.driver = {
.name = "leds-gpio",
.owner = THIS_MODULE,
- .of_match_table = of_match_ptr(of_gpio_leds_match),
+ .of_match_table = of_gpio_leds_match,
},
};


--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Rafael J. Wysocki
2014-10-08 14:04:13 UTC
Permalink
Post by Rafael J. Wysocki
Make use of device property API in this driver so that both OF and ACPI
based system can use the same driver.
This change contains material from Max Eliaser and Mika Westerberg.
Bryan, can you please tell me if you are OK with this patch?

You said you were for one of the previous versions if I remember correctly,
but it's changed quite a bit since then, so can you please check this new
version too?
Post by Rafael J. Wysocki
---
drivers/leds/leds-gpio.c | 67 +++++++++++++++++++++--------------------------
1 file changed, 30 insertions(+), 37 deletions(-)
Index: linux-pm/drivers/leds/leds-gpio.c
===================================================================
--- linux-pm.orig/drivers/leds/leds-gpio.c
+++ linux-pm/drivers/leds/leds-gpio.c
@@ -15,13 +15,11 @@
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/leds.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/module.h>
#include <linux/err.h>
+#include <linux/property.h>
struct gpio_led_data {
struct led_classdev cdev;
@@ -171,40 +169,41 @@ static inline int sizeof_gpio_leds_priv(
(sizeof(struct gpio_led_data) * num_leds);
}
-/* Code to create from OpenFirmware platform devices */
-#ifdef CONFIG_OF_GPIO
-static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
+static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
{
- struct device_node *np = pdev->dev.of_node, *child;
+ struct device *dev = &pdev->dev;
struct gpio_leds_priv *priv;
int count, ret;
+ void *child;
- /* count LEDs in this device, so we know how much to allocate */
- count = of_get_available_child_count(np);
+ count = device_get_child_node_count(dev);
if (!count)
return ERR_PTR(-ENODEV);
- for_each_available_child_of_node(np, child)
- if (of_get_gpio(child, 0) == -EPROBE_DEFER)
- return ERR_PTR(-EPROBE_DEFER);
-
- priv = devm_kzalloc(&pdev->dev, sizeof_gpio_leds_priv(count),
- GFP_KERNEL);
+ priv = devm_kzalloc(dev, sizeof_gpio_leds_priv(count), GFP_KERNEL);
if (!priv)
return ERR_PTR(-ENOMEM);
- for_each_available_child_of_node(np, child) {
+ device_for_each_child_node(dev, child) {
struct gpio_led led = {};
- enum of_gpio_flags flags;
- const char *state;
+ const char *state = NULL;
+
+ led.gpiod = devm_get_named_gpiod_from_child(dev, child,
+ "gpios", 0);
+ if (IS_ERR(led.gpiod)) {
+ device_put_child_node(dev, child);
+ goto err;
+ }
- led.gpio = of_get_gpio_flags(child, 0, &flags);
- led.active_low = flags & OF_GPIO_ACTIVE_LOW;
- led.name = of_get_property(child, "label", NULL) ? : child->name;
- led.default_trigger =
- of_get_property(child, "linux,default-trigger", NULL);
- state = of_get_property(child, "default-state", NULL);
- if (state) {
+ device_child_property_read_string(dev, child,
+ "label", &led.name);
+ device_child_property_read_string(dev, child,
+ "linux,default-trigger",
+ &led.default_trigger);
+
+ if (!device_child_property_read_string(dev, child,
+ "linux,default_state",
+ &state)) {
if (!strcmp(state, "keep"))
led.default_state = LEDS_GPIO_DEFSTATE_KEEP;
else if (!strcmp(state, "on"))
@@ -213,13 +212,14 @@ static struct gpio_leds_priv *gpio_leds_
led.default_state = LEDS_GPIO_DEFSTATE_OFF;
}
- if (of_get_property(child, "retain-state-suspended", NULL))
+ if (!device_get_child_property(dev, child,
+ "retain-state-suspended", NULL))
led.retain_state_suspended = 1;
ret = create_gpio_led(&led, &priv->leds[priv->num_leds++],
- &pdev->dev, NULL);
+ dev, NULL);
if (ret < 0) {
- of_node_put(child);
+ device_put_child_node(dev, child);
goto err;
}
}
@@ -238,13 +238,6 @@ static const struct of_device_id of_gpio
};
MODULE_DEVICE_TABLE(of, of_gpio_leds_match);
-#else /* CONFIG_OF_GPIO */
-static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
-{
- return ERR_PTR(-ENODEV);
-}
-#endif /* CONFIG_OF_GPIO */
-
static int gpio_led_probe(struct platform_device *pdev)
{
@@ -273,7 +266,7 @@ static int gpio_led_probe(struct platfor
}
}
} else {
- priv = gpio_leds_create_of(pdev);
+ priv = gpio_leds_create(pdev);
if (IS_ERR(priv))
return PTR_ERR(priv);
}
@@ -300,7 +293,7 @@ static struct platform_driver gpio_led_d
.driver = {
.name = "leds-gpio",
.owner = THIS_MODULE,
- .of_match_table = of_match_ptr(of_gpio_leds_match),
+ .of_match_table = of_gpio_leds_match,
},
};
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
More majordomo info at http://vger.kernel.org/majordomo-info.html
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
Bryan Wu
2014-10-08 17:47:16 UTC
Permalink
Post by Rafael J. Wysocki
Post by Rafael J. Wysocki
Make use of device property API in this driver so that both OF and ACPI
based system can use the same driver.
This change contains material from Max Eliaser and Mika Westerberg.
Bryan, can you please tell me if you are OK with this patch?
You said you were for one of the previous versions if I remember correctly,
but it's changed quite a bit since then, so can you please check this new
version too?
Sure, the new one is even better than before. Please go ahead with my Ack
Acked-by: Bryan Wu <cooloney-***@public.gmane.org>

Thanks,
-Bryan
Post by Rafael J. Wysocki
Post by Rafael J. Wysocki
---
drivers/leds/leds-gpio.c | 67 +++++++++++++++++++++--------------------------
1 file changed, 30 insertions(+), 37 deletions(-)
Index: linux-pm/drivers/leds/leds-gpio.c
===================================================================
--- linux-pm.orig/drivers/leds/leds-gpio.c
+++ linux-pm/drivers/leds/leds-gpio.c
@@ -15,13 +15,11 @@
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/leds.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/module.h>
#include <linux/err.h>
+#include <linux/property.h>
struct gpio_led_data {
struct led_classdev cdev;
@@ -171,40 +169,41 @@ static inline int sizeof_gpio_leds_priv(
(sizeof(struct gpio_led_data) * num_leds);
}
-/* Code to create from OpenFirmware platform devices */
-#ifdef CONFIG_OF_GPIO
-static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
+static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
{
- struct device_node *np = pdev->dev.of_node, *child;
+ struct device *dev = &pdev->dev;
struct gpio_leds_priv *priv;
int count, ret;
+ void *child;
- /* count LEDs in this device, so we know how much to allocate */
- count = of_get_available_child_count(np);
+ count = device_get_child_node_count(dev);
if (!count)
return ERR_PTR(-ENODEV);
- for_each_available_child_of_node(np, child)
- if (of_get_gpio(child, 0) == -EPROBE_DEFER)
- return ERR_PTR(-EPROBE_DEFER);
-
- priv = devm_kzalloc(&pdev->dev, sizeof_gpio_leds_priv(count),
- GFP_KERNEL);
+ priv = devm_kzalloc(dev, sizeof_gpio_leds_priv(count), GFP_KERNEL);
if (!priv)
return ERR_PTR(-ENOMEM);
- for_each_available_child_of_node(np, child) {
+ device_for_each_child_node(dev, child) {
struct gpio_led led = {};
- enum of_gpio_flags flags;
- const char *state;
+ const char *state = NULL;
+
+ led.gpiod = devm_get_named_gpiod_from_child(dev, child,
+ "gpios", 0);
+ if (IS_ERR(led.gpiod)) {
+ device_put_child_node(dev, child);
+ goto err;
+ }
- led.gpio = of_get_gpio_flags(child, 0, &flags);
- led.active_low = flags & OF_GPIO_ACTIVE_LOW;
- led.name = of_get_property(child, "label", NULL) ? : child->name;
- led.default_trigger =
- of_get_property(child, "linux,default-trigger", NULL);
- state = of_get_property(child, "default-state", NULL);
- if (state) {
+ device_child_property_read_string(dev, child,
+ "label", &led.name);
+ device_child_property_read_string(dev, child,
+ "linux,default-trigger",
+ &led.default_trigger);
+
+ if (!device_child_property_read_string(dev, child,
+ "linux,default_state",
+ &state)) {
if (!strcmp(state, "keep"))
led.default_state = LEDS_GPIO_DEFSTATE_KEEP;
else if (!strcmp(state, "on"))
@@ -213,13 +212,14 @@ static struct gpio_leds_priv *gpio_leds_
led.default_state = LEDS_GPIO_DEFSTATE_OFF;
}
- if (of_get_property(child, "retain-state-suspended", NULL))
+ if (!device_get_child_property(dev, child,
+ "retain-state-suspended", NULL))
led.retain_state_suspended = 1;
ret = create_gpio_led(&led, &priv->leds[priv->num_leds++],
- &pdev->dev, NULL);
+ dev, NULL);
if (ret < 0) {
- of_node_put(child);
+ device_put_child_node(dev, child);
goto err;
}
}
@@ -238,13 +238,6 @@ static const struct of_device_id of_gpio
};
MODULE_DEVICE_TABLE(of, of_gpio_leds_match);
-#else /* CONFIG_OF_GPIO */
-static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
-{
- return ERR_PTR(-ENODEV);
-}
-#endif /* CONFIG_OF_GPIO */
-
static int gpio_led_probe(struct platform_device *pdev)
{
@@ -273,7 +266,7 @@ static int gpio_led_probe(struct platfor
}
}
} else {
- priv = gpio_leds_create_of(pdev);
+ priv = gpio_leds_create(pdev);
if (IS_ERR(priv))
return PTR_ERR(priv);
}
@@ -300,7 +293,7 @@ static struct platform_driver gpio_led_d
.driver = {
.name = "leds-gpio",
.owner = THIS_MODULE,
- .of_match_table = of_match_ptr(of_gpio_leds_match),
+ .of_match_table = of_gpio_leds_match,
},
};
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
More majordomo info at http://vger.kernel.org/majordomo-info.html
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-***@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Rafael J. Wysocki
2014-10-08 22:02:08 UTC
Permalink
Post by Bryan Wu
Post by Rafael J. Wysocki
Post by Rafael J. Wysocki
Make use of device property API in this driver so that both OF and ACPI
based system can use the same driver.
This change contains material from Max Eliaser and Mika Westerberg.
Bryan, can you please tell me if you are OK with this patch?
You said you were for one of the previous versions if I remember correctly,
but it's changed quite a bit since then, so can you please check this new
version too?
Sure, the new one is even better than before. Please go ahead with my Ack
Thanks!

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Rafael J. Wysocki
2014-10-07 00:16:47 UTC
Permalink
From: Aaron Lu <aaron.lu-***@public.gmane.org>

GPIO descriptors are the preferred way over legacy GPIO numbers
nowadays. Convert the driver to use GPIO descriptors internally but
still allow passing legacy GPIO numbers from platform data to support
existing platforms.

Signed-off-by: Aaron Lu <aaron.lu-***@public.gmane.org>
Signed-off-by: Mika Westerberg <mika.westerberg-VuQAYsv1563Yd54FQh9/***@public.gmane.org>
Acked-by: Alexandre Courbot <acourbot-DDmLM1+adcrQT0dZR+***@public.gmane.org>
Reviewed-by: Linus Walleij <linus.walleij-QSEj5FYQhm4dnm+***@public.gmane.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki-***@public.gmane.org>
---
drivers/input/keyboard/gpio_keys_polled.c | 39 +++++++++++++++++++++----------
include/linux/gpio_keys.h | 3 +++
2 files changed, 30 insertions(+), 12 deletions(-)

diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c
index 432d363..b7a514c 100644
--- a/drivers/input/keyboard/gpio_keys_polled.c
+++ b/drivers/input/keyboard/gpio_keys_polled.c
@@ -23,6 +23,7 @@
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/gpio_keys.h>
#include <linux/of.h>
#include <linux/of_platform.h>
@@ -51,15 +52,14 @@ static void gpio_keys_polled_check_state(struct input_dev *input,
int state;

if (bdata->can_sleep)
- state = !!gpio_get_value_cansleep(button->gpio);
+ state = !!gpiod_get_value_cansleep(button->gpiod);
else
- state = !!gpio_get_value(button->gpio);
+ state = !!gpiod_get_value(button->gpiod);

if (state != bdata->last_state) {
unsigned int type = button->type ?: EV_KEY;

- input_event(input, type, button->code,
- !!(state ^ button->active_low));
+ input_event(input, type, button->code, state);
input_sync(input);
bdata->count = 0;
bdata->last_state = state;
@@ -259,7 +259,6 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
for (i = 0; i < pdata->nbuttons; i++) {
struct gpio_keys_button *button = &pdata->buttons[i];
struct gpio_keys_button_data *bdata = &bdev->data[i];
- unsigned int gpio = button->gpio;
unsigned int type = button->type ?: EV_KEY;

if (button->wakeup) {
@@ -267,15 +266,31 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
return -EINVAL;
}

- error = devm_gpio_request_one(&pdev->dev, gpio, GPIOF_IN,
- button->desc ? : DRV_NAME);
- if (error) {
- dev_err(dev, "unable to claim gpio %u, err=%d\n",
- gpio, error);
- return error;
+ /*
+ * Legacy GPIO number so request the GPIO here and
+ * convert it to descriptor.
+ */
+ if (!button->gpiod && gpio_is_valid(button->gpio)) {
+ unsigned flags = 0;
+
+ if (button->active_low)
+ flags |= GPIOF_ACTIVE_LOW;
+
+ error = devm_gpio_request_one(&pdev->dev, button->gpio,
+ flags, button->desc ? : DRV_NAME);
+ if (error) {
+ dev_err(dev, "unable to claim gpio %u, err=%d\n",
+ button->gpio, error);
+ return error;
+ }
+
+ button->gpiod = gpio_to_desc(button->gpio);
}

- bdata->can_sleep = gpio_cansleep(gpio);
+ if (IS_ERR(button->gpiod))
+ return PTR_ERR(button->gpiod);
+
+ bdata->can_sleep = gpiod_cansleep(button->gpiod);
bdata->last_state = -1;
bdata->threshold = DIV_ROUND_UP(button->debounce_interval,
pdata->poll_interval);
diff --git a/include/linux/gpio_keys.h b/include/linux/gpio_keys.h
index 8b62246..ee2d8c6 100644
--- a/include/linux/gpio_keys.h
+++ b/include/linux/gpio_keys.h
@@ -2,6 +2,7 @@
#define _GPIO_KEYS_H

struct device;
+struct gpio_desc;

/**
* struct gpio_keys_button - configuration parameters
@@ -17,6 +18,7 @@ struct device;
* disable button via sysfs
* @value: axis value for %EV_ABS
* @irq: Irq number in case of interrupt keys
+ * @gpiod: GPIO descriptor
*/
struct gpio_keys_button {
unsigned int code;
@@ -29,6 +31,7 @@ struct gpio_keys_button {
bool can_disable;
int value;
unsigned int irq;
+ struct gpio_desc *gpiod;
};

/**
--
1.9.3


--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-***@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Dmitry Torokhov
2014-10-07 17:29:47 UTC
Permalink
Post by Rafael J. Wysocki
GPIO descriptors are the preferred way over legacy GPIO numbers
nowadays. Convert the driver to use GPIO descriptors internally but
still allow passing legacy GPIO numbers from platform data to support
existing platforms.
---
drivers/input/keyboard/gpio_keys_polled.c | 39 +++++++++++++++++++++----------
include/linux/gpio_keys.h | 3 +++
2 files changed, 30 insertions(+), 12 deletions(-)
diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c
index 432d363..b7a514c 100644
--- a/drivers/input/keyboard/gpio_keys_polled.c
+++ b/drivers/input/keyboard/gpio_keys_polled.c
@@ -23,6 +23,7 @@
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/gpio_keys.h>
#include <linux/of.h>
#include <linux/of_platform.h>
@@ -51,15 +52,14 @@ static void gpio_keys_polled_check_state(struct input_dev *input,
int state;
if (bdata->can_sleep)
- state = !!gpio_get_value_cansleep(button->gpio);
+ state = !!gpiod_get_value_cansleep(button->gpiod);
else
- state = !!gpio_get_value(button->gpio);
+ state = !!gpiod_get_value(button->gpiod);
if (state != bdata->last_state) {
unsigned int type = button->type ?: EV_KEY;
- input_event(input, type, button->code,
- !!(state ^ button->active_low));
+ input_event(input, type, button->code, state);
input_sync(input);
bdata->count = 0;
bdata->last_state = state;
@@ -259,7 +259,6 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
for (i = 0; i < pdata->nbuttons; i++) {
struct gpio_keys_button *button = &pdata->buttons[i];
struct gpio_keys_button_data *bdata = &bdev->data[i];
- unsigned int gpio = button->gpio;
unsigned int type = button->type ?: EV_KEY;
if (button->wakeup) {
@@ -267,15 +266,31 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
return -EINVAL;
}
- error = devm_gpio_request_one(&pdev->dev, gpio, GPIOF_IN,
- button->desc ? : DRV_NAME);
- if (error) {
- dev_err(dev, "unable to claim gpio %u, err=%d\n",
- gpio, error);
- return error;
+ /*
+ * Legacy GPIO number so request the GPIO here and
+ * convert it to descriptor.
+ */
+ if (!button->gpiod && gpio_is_valid(button->gpio)) {
+ unsigned flags = 0;
+
+ if (button->active_low)
+ flags |= GPIOF_ACTIVE_LOW;
+
+ error = devm_gpio_request_one(&pdev->dev, button->gpio,
+ flags, button->desc ? : DRV_NAME);
+ if (error) {
+ dev_err(dev, "unable to claim gpio %u, err=%d\n",
+ button->gpio, error);
+ return error;
+ }
+
+ button->gpiod = gpio_to_desc(button->gpio);
}
- bdata->can_sleep = gpio_cansleep(gpio);
+ if (IS_ERR(button->gpiod))
+ return PTR_ERR(button->gpiod);
+
+ bdata->can_sleep = gpiod_cansleep(button->gpiod);
bdata->last_state = -1;
bdata->threshold = DIV_ROUND_UP(button->debounce_interval,
pdata->poll_interval);
diff --git a/include/linux/gpio_keys.h b/include/linux/gpio_keys.h
index 8b62246..ee2d8c6 100644
--- a/include/linux/gpio_keys.h
+++ b/include/linux/gpio_keys.h
@@ -2,6 +2,7 @@
#define _GPIO_KEYS_H
struct device;
+struct gpio_desc;
/**
* struct gpio_keys_button - configuration parameters
@@ -17,6 +18,7 @@ struct device;
* disable button via sysfs
*/
struct gpio_keys_button {
unsigned int code;
@@ -29,6 +31,7 @@ struct gpio_keys_button {
bool can_disable;
int value;
unsigned int irq;
+ struct gpio_desc *gpiod;
};
/**
--
1.9.3
--
Dmitry
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-***@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Rafael J. Wysocki
2014-10-07 00:14:44 UTC
Permalink
From: Mika Westerberg <***@linux.intel.com>

Make use of device property API in this driver so that both DT and ACPI
based systems can use this driver.

Signed-off-by: Mika Westerberg <***@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <***@intel.com>
---
drivers/misc/eeprom/at25.c | 34 +++++++++++++---------------------
1 file changed, 13 insertions(+), 21 deletions(-)

diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c
index 634f729..58f6cdd 100644
--- a/drivers/misc/eeprom/at25.c
+++ b/drivers/misc/eeprom/at25.c
@@ -18,7 +18,7 @@

#include <linux/spi/spi.h>
#include <linux/spi/eeprom.h>
-#include <linux/of.h>
+#include <linux/property.h>

/*
* NOTE: this is an *EEPROM* driver. The vagaries of product naming
@@ -301,35 +301,33 @@ static ssize_t at25_mem_write(struct memory_accessor *mem, const char *buf,

/*-------------------------------------------------------------------------*/

-static int at25_np_to_chip(struct device *dev,
- struct device_node *np,
- struct spi_eeprom *chip)
+static int at25_fw_to_chip(struct device *dev, struct spi_eeprom *chip)
{
u32 val;

memset(chip, 0, sizeof(*chip));
- strncpy(chip->name, np->name, sizeof(chip->name));
+ strncpy(chip->name, "at25", sizeof(chip->name));

- if (of_property_read_u32(np, "size", &val) == 0 ||
- of_property_read_u32(np, "at25,byte-len", &val) == 0) {
+ if (device_property_read_u32(dev, "size", &val) == 0 ||
+ device_property_read_u32(dev, "at25,byte-len", &val) == 0) {
chip->byte_len = val;
} else {
dev_err(dev, "Error: missing \"size\" property\n");
return -ENODEV;
}

- if (of_property_read_u32(np, "pagesize", &val) == 0 ||
- of_property_read_u32(np, "at25,page-size", &val) == 0) {
+ if (device_property_read_u32(dev, "pagesize", &val) == 0 ||
+ device_property_read_u32(dev, "at25,page-size", &val) == 0) {
chip->page_size = (u16)val;
} else {
dev_err(dev, "Error: missing \"pagesize\" property\n");
return -ENODEV;
}

- if (of_property_read_u32(np, "at25,addr-mode", &val) == 0) {
+ if (device_property_read_u32(dev, "at25,addr-mode", &val) == 0) {
chip->flags = (u16)val;
} else {
- if (of_property_read_u32(np, "address-width", &val)) {
+ if (device_property_read_u32(dev, "address-width", &val)) {
dev_err(dev,
"Error: missing \"address-width\" property\n");
return -ENODEV;
@@ -350,7 +348,7 @@ static int at25_np_to_chip(struct device *dev,
val);
return -ENODEV;
}
- if (of_find_property(np, "read-only", NULL))
+ if (!device_get_property(dev, "read-only", NULL))
chip->flags |= EE_READONLY;
}
return 0;
@@ -360,21 +358,15 @@ static int at25_probe(struct spi_device *spi)
{
struct at25_data *at25 = NULL;
struct spi_eeprom chip;
- struct device_node *np = spi->dev.of_node;
int err;
int sr;
int addrlen;

/* Chip description */
if (!spi->dev.platform_data) {
- if (np) {
- err = at25_np_to_chip(&spi->dev, np, &chip);
- if (err)
- return err;
- } else {
- dev_err(&spi->dev, "Error: no chip description\n");
- return -ENODEV;
- }
+ err = at25_fw_to_chip(&spi->dev, &chip);
+ if (err)
+ return err;
} else
chip = *(struct spi_eeprom *)spi->dev.platform_data;
--
1.9.3
Geert Uytterhoeven
2014-10-07 09:10:23 UTC
Permalink
Post by Rafael J. Wysocki
@@ -301,35 +301,33 @@ static ssize_t at25_mem_write(struct memory_accessor *mem, const char *buf,
/*-------------------------------------------------------------------------*/
-static int at25_np_to_chip(struct device *dev,
- struct device_node *np,
- struct spi_eeprom *chip)
+static int at25_fw_to_chip(struct device *dev, struct spi_eeprom *chip)
{
u32 val;
memset(chip, 0, sizeof(*chip));
- strncpy(chip->name, np->name, sizeof(chip->name));
+ strncpy(chip->name, "at25", sizeof(chip->name));
So this changes chip->name from "eeprom" (or whatever name the DTS
writer used; "eeprom" is the ePAPR-compliant name) to "at25"?

Note:The example in Documentation/devicetree/bindings/misc/at25.txt
uses "at25", not "eeprom".

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- ***@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Mika Westerberg
2014-10-07 09:32:03 UTC
Permalink
Post by Geert Uytterhoeven
Post by Rafael J. Wysocki
@@ -301,35 +301,33 @@ static ssize_t at25_mem_write(struct memory_accessor *mem, const char *buf,
/*-------------------------------------------------------------------------*/
-static int at25_np_to_chip(struct device *dev,
- struct device_node *np,
- struct spi_eeprom *chip)
+static int at25_fw_to_chip(struct device *dev, struct spi_eeprom *chip)
{
u32 val;
memset(chip, 0, sizeof(*chip));
- strncpy(chip->name, np->name, sizeof(chip->name));
+ strncpy(chip->name, "at25", sizeof(chip->name));
So this changes chip->name from "eeprom" (or whatever name the DTS
writer used; "eeprom" is the ePAPR-compliant name) to "at25"?
Yes.

Is there something depending on that name?
Post by Geert Uytterhoeven
Note:The example in Documentation/devicetree/bindings/misc/at25.txt
uses "at25", not "eeprom".
Which is the same we use here.
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Rafael J. Wysocki
2014-10-07 00:12:59 UTC
Permalink
From: Rafael J. Wysocki <***@intel.com>

Add a uniform interface by which device drivers can request device
properties from the platform firmware by providing a property name
and the corresponding data type. The purpose of it is to help to
write portable code that won't depend on any particular platform
firmware interface.

Three general helper functions, device_get_property(),
device_read_property() and device_read_property_array() are provided.
The first one allows the raw value of a given device property to be
accessed. The remaining two allow the value of a numeric or string
property and multiple numeric or string values of one array
property to be acquired, respectively. Static inline wrappers are also
provided for the various property data types that can be passed to
device_read_property() or device_read_property_array() for extra type
checking.

The interface covers both ACPI and Device Trees.

This change set includes material from Mika Westerberg and Aaron Lu.

Signed-off-by: Aaron Lu <***@intel.com>
Signed-off-by: Mika Westerberg <***@linux.intel.com>
Acked-by: Greg Kroah-Hartman <***@linuxfoundation.org>
Signed-off-by: Rafael J. Wysocki <***@intel.com>
---
drivers/acpi/property.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++
drivers/base/Makefile | 2
drivers/base/property.c | 97 ++++++++++++++++++++++++++
drivers/of/base.c | 171 +++++++++++++++++++++++++++++++++++++++++++++++
include/linux/acpi.h | 31 ++++++++
include/linux/of.h | 27 +++++++
include/linux/property.h | 108 +++++++++++++++++++++++++++++
7 files changed, 604 insertions(+), 1 deletion(-)
create mode 100644 drivers/base/property.c
create mode 100644 include/linux/property.h

Index: linux-pm/drivers/acpi/property.c
===================================================================
--- linux-pm.orig/drivers/acpi/property.c
+++ linux-pm/drivers/acpi/property.c
@@ -362,3 +362,172 @@ int acpi_dev_get_property_reference(stru
return -EPROTO;
}
EXPORT_SYMBOL_GPL(acpi_dev_get_property_reference);
+
+int acpi_dev_prop_get(struct acpi_device *adev, const char *propname,
+ void **valptr)
+{
+ return acpi_dev_get_property(adev, propname, ACPI_TYPE_ANY,
+ (const union acpi_object **)valptr);
+}
+
+int acpi_dev_prop_read(struct acpi_device *adev, const char *propname,
+ enum dev_prop_type proptype, void *val)
+{
+ const union acpi_object *obj;
+ int ret = -EINVAL;
+
+ if (!val)
+ return -EINVAL;
+
+ if (proptype >= DEV_PROP_U8 && proptype <= DEV_PROP_U64) {
+ ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_INTEGER, &obj);
+ if (ret)
+ return ret;
+
+ switch (proptype) {
+ case DEV_PROP_U8:
+ if (obj->integer.value > U8_MAX)
+ return -EOVERFLOW;
+ *(u8 *)val = obj->integer.value;
+ break;
+ case DEV_PROP_U16:
+ if (obj->integer.value > U16_MAX)
+ return -EOVERFLOW;
+ *(u16 *)val = obj->integer.value;
+ break;
+ case DEV_PROP_U32:
+ if (obj->integer.value > U32_MAX)
+ return -EOVERFLOW;
+ *(u32 *)val = obj->integer.value;
+ break;
+ default:
+ *(u64 *)val = obj->integer.value;
+ break;
+ }
+ } else if (proptype == DEV_PROP_STRING) {
+ ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_STRING, &obj);
+ if (ret)
+ return ret;
+
+ *(char **)val = obj->string.pointer;
+ }
+ return ret;
+}
+
+static int acpi_copy_property_array_u8(const union acpi_object *items, u8 *val,
+ size_t nval)
+{
+ int i;
+
+ for (i = 0; i < nval; i++) {
+ if (items[i].type != ACPI_TYPE_INTEGER)
+ return -EPROTO;
+ if (items[i].integer.value > U8_MAX)
+ return -EOVERFLOW;
+
+ val[i] = items[i].integer.value;
+ }
+ return 0;
+}
+
+static int acpi_copy_property_array_u16(const union acpi_object *items,
+ u16 *val, size_t nval)
+{
+ int i;
+
+ for (i = 0; i < nval; i++) {
+ if (items[i].type != ACPI_TYPE_INTEGER)
+ return -EPROTO;
+ if (items[i].integer.value > U16_MAX)
+ return -EOVERFLOW;
+
+ val[i] = items[i].integer.value;
+ }
+ return 0;
+}
+
+static int acpi_copy_property_array_u32(const union acpi_object *items,
+ u32 *val, size_t nval)
+{
+ int i;
+
+ for (i = 0; i < nval; i++) {
+ if (items[i].type != ACPI_TYPE_INTEGER)
+ return -EPROTO;
+ if (items[i].integer.value > U32_MAX)
+ return -EOVERFLOW;
+
+ val[i] = items[i].integer.value;
+ }
+ return 0;
+}
+
+static int acpi_copy_property_array_u64(const union acpi_object *items,
+ u64 *val, size_t nval)
+{
+ int i;
+
+ for (i = 0; i < nval; i++) {
+ if (items[i].type != ACPI_TYPE_INTEGER)
+ return -EPROTO;
+
+ val[i] = items[i].integer.value;
+ }
+ return 0;
+}
+
+static int acpi_copy_property_array_string(const union acpi_object *items,
+ char **val, size_t nval)
+{
+ int i;
+
+ for (i = 0; i < nval; i++) {
+ if (items[i].type != ACPI_TYPE_STRING)
+ return -EPROTO;
+
+ val[i] = items[i].string.pointer;
+ }
+ return 0;
+}
+
+int acpi_dev_prop_read_array(struct acpi_device *adev, const char *propname,
+ enum dev_prop_type proptype, void *val,
+ size_t nval)
+{
+ const union acpi_object *obj;
+ const union acpi_object *items;
+ int ret;
+
+ ret = acpi_dev_get_property_array(adev, propname, ACPI_TYPE_ANY, &obj);
+ if (ret)
+ return ret;
+
+ if (!val)
+ return obj->package.count;
+
+ if (nval > obj->package.count)
+ nval = obj->package.count;
+
+ items = obj->package.elements;
+ switch (proptype) {
+ case DEV_PROP_U8:
+ ret = acpi_copy_property_array_u8(items, (u8 *)val, nval);
+ break;
+ case DEV_PROP_U16:
+ ret = acpi_copy_property_array_u16(items, (u16 *)val, nval);
+ break;
+ case DEV_PROP_U32:
+ ret = acpi_copy_property_array_u32(items, (u32 *)val, nval);
+ break;
+ case DEV_PROP_U64:
+ ret = acpi_copy_property_array_u64(items, (u64 *)val, nval);
+ break;
+ case DEV_PROP_STRING:
+ ret = acpi_copy_property_array_string(items, (char **)val, nval);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
Index: linux-pm/drivers/base/Makefile
===================================================================
--- linux-pm.orig/drivers/base/Makefile
+++ linux-pm/drivers/base/Makefile
@@ -4,7 +4,7 @@ obj-y := component.o core.o bus.o dd.o
driver.o class.o platform.o \
cpu.o firmware.o init.o map.o devres.o \
attribute_container.o transport_class.o \
- topology.o container.o
+ topology.o container.o property.o
obj-$(CONFIG_DEVTMPFS) += devtmpfs.o
obj-$(CONFIG_DMA_CMA) += dma-contiguous.o
obj-y += power/
Index: linux-pm/drivers/base/property.c
===================================================================
--- /dev/null
+++ linux-pm/drivers/base/property.c
@@ -0,0 +1,97 @@
+/*
+ * property.c - Unified device property interface.
+ *
+ * Copyright (C) 2014, Intel Corporation
+ * Authors: Rafael J. Wysocki <***@intel.com>
+ * Mika Westerberg <***@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/property.h>
+#include <linux/export.h>
+#include <linux/acpi.h>
+#include <linux/of.h>
+
+/**
+ * device_get_property - return a raw property of a device
+ * @dev: Device get the property of
+ * @propname: Name of the property
+ * @valptr: The raw property value is stored here
+ *
+ * Function reads property @propname from the device firmware description and
+ * stores the raw value into @valptr if found. Otherwise returns a negative
+ * errno as specified below.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not exist.
+ */
+int device_get_property(struct device *dev, const char *propname, void **valptr)
+{
+ if (IS_ENABLED(CONFIG_OF) && dev->of_node)
+ return of_dev_prop_get(dev->of_node, propname, valptr);
+
+ return acpi_dev_prop_get(ACPI_COMPANION(dev), propname, valptr);
+}
+EXPORT_SYMBOL_GPL(device_get_property);
+
+/**
+ * device_read_property - read a typed property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @proptype: Type of the property
+ * @val: The value is stored here
+ *
+ * Function reads property @propname from the device firmware description and
+ * stores the value into @val if found. The value is checked to be of type
+ * @proptype.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not exist,
+ * %-EPROTO if the property type does not match @proptype,
+ * %-EOVERFLOW if the property value is out of bounds of @proptype.
+ */
+int device_read_property(struct device *dev, const char *propname,
+ enum dev_prop_type proptype, void *val)
+{
+ if (IS_ENABLED(CONFIG_OF) && dev->of_node)
+ return of_dev_prop_read(dev->of_node, propname, proptype, val);
+
+ return acpi_dev_prop_read(ACPI_COMPANION(dev), propname, proptype, val);
+}
+EXPORT_SYMBOL_GPL(device_read_property);
+
+/**
+ * device_read_property_array - read an array property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @proptype: Type of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Function reads an array of properties with @propname from the device
+ * firmware description and stores them to @val if found. All the values
+ * in the array must be of type @proptype.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not exist,
+ * %-EPROTO if the property type does not match @proptype,
+ * %-EOVERFLOW if the property value is out of bounds of @proptype.
+ */
+int device_read_property_array(struct device *dev, const char *propname,
+ enum dev_prop_type proptype, void *val,
+ size_t nval)
+{
+ if (IS_ENABLED(CONFIG_OF) && dev->of_node)
+ return of_dev_prop_read_array(dev->of_node, propname, proptype,
+ val, nval);
+
+ return acpi_dev_prop_read_array(ACPI_COMPANION(dev), propname, proptype,
+ val, nval);
+}
+EXPORT_SYMBOL_GPL(device_read_property_array);
Index: linux-pm/drivers/of/base.c
===================================================================
--- linux-pm.orig/drivers/of/base.c
+++ linux-pm/drivers/of/base.c
@@ -1247,6 +1247,39 @@ int of_property_read_u64(const struct de
EXPORT_SYMBOL_GPL(of_property_read_u64);

/**
+ * of_property_read_u64_array - Find and read an array of 64 bit integers
+ * from a property.
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @out_values: pointer to return value, modified only if return value is 0.
+ * @sz: number of array elements to read
+ *
+ * Search for a property in a device node and read 64-bit value(s) from
+ * it. Returns 0 on success, -EINVAL if the property does not exist,
+ * -ENODATA if property does not have a value, and -EOVERFLOW if the
+ * property data isn't large enough.
+ *
+ * The out_values is modified only if a valid u64 value can be decoded.
+ */
+int of_property_read_u64_array(const struct device_node *np,
+ const char *propname, u64 *out_values,
+ size_t sz)
+{
+ const __be32 *val = of_find_property_value_of_size(np, propname,
+ (sz * sizeof(*out_values)));
+
+ if (IS_ERR(val))
+ return PTR_ERR(val);
+
+ while (sz--) {
+ *out_values++ = of_read_number(val, 2);
+ val += 2;
+ }
+ return 0;
+}
+
+/**
* of_property_read_string - Find and read a string from a property
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
@@ -1394,6 +1427,49 @@ int of_property_count_strings(struct dev
}
EXPORT_SYMBOL_GPL(of_property_count_strings);

+/**
+ * of_property_read_string_array - Find and read an array of strings
+ * from a multiple strings property.
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @out_string: pointer to null terminated return string, modified only if
+ * return value is 0.
+ * @sz: number of array elements to read
+ *
+ * Search for a property in a device tree node and retrieve a list of
+ * terminated string value (pointer to data, not a copy) in that property.
+ * Returns 0 on success, -EINVAL if the property does not exist, -ENODATA if
+ * property does not have a value, and -EOVERFLOW if the string is not
+ * null-terminated within the length of the property data.
+ *
+ * The out_string pointer is modified only if a valid string can be decoded.
+ */
+int of_property_read_string_array(struct device_node *np, const char *propname,
+ char **output, size_t sz)
+{
+ struct property *prop = of_find_property(np, propname, NULL);
+ int i = 0;
+ size_t l = 0, total = 0;
+ char *p;
+
+ if (!prop)
+ return -EINVAL;
+
+ if (!prop->value)
+ return -ENODATA;
+
+ if (strnlen(prop->value, prop->length) >= prop->length)
+ return -EOVERFLOW;
+
+ p = prop->value;
+
+ for (i = 0; total < prop->length; total += l, p += l) {
+ output[i++] = p;
+ l = strlen(p) + 1;
+ }
+ return 0;
+}
+
void of_print_phandle_args(const char *msg, const struct of_phandle_args *args)
{
int i;
@@ -2183,3 +2259,98 @@ struct device_node *of_graph_get_remote_
return of_get_next_parent(np);
}
EXPORT_SYMBOL(of_graph_get_remote_port);
+
+int of_dev_prop_get(struct device_node *dn, const char *propname, void **valptr)
+{
+ struct property *pp = of_find_property(dn, propname, NULL);
+
+ if (!pp)
+ return -ENODATA;
+
+ if (valptr)
+ *valptr = pp->value;
+ return 0;
+}
+
+int of_dev_prop_read(struct device_node *dn, const char *propname,
+ enum dev_prop_type proptype, void *val)
+{
+ void *value;
+ int ret = of_dev_prop_get(dn, propname, &value);
+
+ if (ret)
+ return ret;
+
+ if (proptype >= DEV_PROP_U8 && proptype <= DEV_PROP_U64) {
+ switch (proptype) {
+ case DEV_PROP_U8: {
+ *(u8 *)val = *(u8 *)value;
+ break;
+ }
+ case DEV_PROP_U16:
+ *(u16 *)val = *(u16 *)value;
+ break;
+ case DEV_PROP_U32:
+ *(u32 *)val = *(u32 *)value;
+ break;
+ default:
+ *(u64 *)val = *(u64 *)value;
+ break;
+ }
+ } else if (proptype == DEV_PROP_STRING) {
+ *(char **)val = value;
+ }
+ return ret;
+
+}
+
+int of_dev_prop_read_array(struct device_node *dn, const char *propname,
+ enum dev_prop_type proptype, void *val, size_t nval)
+{
+ int ret, elem_size;
+
+ if (!val) {
+ switch (proptype) {
+ case DEV_PROP_U8:
+ elem_size = sizeof(u8);
+ break;
+ case DEV_PROP_U16:
+ elem_size = sizeof(u16);
+ break;
+ case DEV_PROP_U32:
+ elem_size = sizeof(u32);
+ break;
+ case DEV_PROP_U64:
+ elem_size = sizeof(u64);
+ break;
+ case DEV_PROP_STRING:
+ return of_property_count_strings(dn, propname);
+ default:
+ return -EINVAL;
+ }
+ return of_property_count_elems_of_size(dn, propname, elem_size);
+ }
+
+ switch (proptype) {
+ case DEV_PROP_U8:
+ ret = of_property_read_u8_array(dn, propname, (u8 *)val, nval);
+ break;
+ case DEV_PROP_U16:
+ ret = of_property_read_u16_array(dn, propname, (u16 *)val, nval);
+ break;
+ case DEV_PROP_U32:
+ ret = of_property_read_u32_array(dn, propname, (u32 *)val, nval);
+ break;
+ case DEV_PROP_U64:
+ ret = of_property_read_u64_array(dn, propname, (u64 *)val, nval);
+ break;
+ case DEV_PROP_STRING:
+ ret = of_property_read_string_array(dn, propname,
+ (char **)val, nval);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
Index: linux-pm/include/linux/acpi.h
===================================================================
--- linux-pm.orig/include/linux/acpi.h
+++ linux-pm/include/linux/acpi.h
@@ -28,6 +28,7 @@
#include <linux/errno.h>
#include <linux/ioport.h> /* for struct resource */
#include <linux/device.h>
+#include <linux/property.h>

#ifndef _LINUX
#define _LINUX
@@ -676,6 +677,14 @@ int acpi_dev_get_property_array(struct a
int acpi_dev_get_property_reference(struct acpi_device *adev, const char *name,
const char *cells_name, size_t index,
struct acpi_reference_args *args);
+
+int acpi_dev_prop_get(struct acpi_device *adev, const char *propname,
+ void **valptr);
+int acpi_dev_prop_read(struct acpi_device *adev, const char *propname,
+ enum dev_prop_type proptype, void *val);
+int acpi_dev_prop_read_array(struct acpi_device *adev, const char *propname,
+ enum dev_prop_type proptype, void *val,
+ size_t nval);
#else
static inline int acpi_dev_get_property(struct acpi_device *adev,
const char *name, acpi_object_type type,
@@ -696,6 +705,28 @@ static inline int acpi_dev_get_property_
{
return -ENXIO;
}
+
+static inline int acpi_dev_prop_get(struct acpi_device *adev,
+ const char *propname,
+ void **valptr)
+{
+ return -ENXIO;
+}
+
+static inline int acpi_dev_prop_read(struct acpi_device *adev,
+ const char *propname,
+ enum dev_prop_type proptype, void *val)
+{
+ return -ENXIO;
+}
+
+static inline int acpi_dev_prop_read_array(struct acpi_device *adev,
+ const char *propname,
+ enum dev_prop_type proptype,
+ void *val, size_t nval)
+{
+ return -ENXIO;
+}
#endif

#endif /*_LINUX_ACPI_H*/
Index: linux-pm/include/linux/of.h
===================================================================
--- linux-pm.orig/include/linux/of.h
+++ linux-pm/include/linux/of.h
@@ -23,6 +23,7 @@
#include <linux/spinlock.h>
#include <linux/topology.h>
#include <linux/notifier.h>
+#include <linux/property.h>

#include <asm/byteorder.h>
#include <asm/errno.h>
@@ -355,6 +356,12 @@ const char *of_prop_next_string(struct p

bool of_console_check(struct device_node *dn, char *name, int index);

+int of_dev_prop_get(struct device_node *dn, const char *propname, void **valptr);
+int of_dev_prop_read(struct device_node *dn, const char *propname,
+ enum dev_prop_type proptype, void *val);
+int of_dev_prop_read_array(struct device_node *dn, const char *propname,
+ enum dev_prop_type proptype, void *val, size_t nval);
+
#else /* CONFIG_OF */

static inline const char* of_node_full_name(const struct device_node *np)
@@ -582,6 +589,26 @@ static inline const char *of_prop_next_s
return NULL;
}

+static inline int of_dev_prop_get(struct device_node *dn, const char *propname,
+ void **valptr)
+{
+ return -ENXIO;
+}
+
+static inline int of_dev_prop_read(struct device_node *dn, const char *propname,
+ enum dev_prop_type proptype, void *val)
+{
+ return -ENXIO;
+}
+
+static inline int of_dev_prop_read_array(struct device_node *dn,
+ const char *propname,
+ enum dev_prop_type proptype,
+ void *val, size_t nval)
+{
+ return -ENXIO;
+}
+
#define of_match_ptr(_ptr) NULL
#define of_match_node(_matches, _node) NULL
#endif /* CONFIG_OF */
Index: linux-pm/include/linux/property.h
===================================================================
--- /dev/null
+++ linux-pm/include/linux/property.h
@@ -0,0 +1,108 @@
+/*
+ * property.h - Unified device property interface.
+ *
+ * Copyright (C) 2014, Intel Corporation
+ * Authors: Rafael J. Wysocki <***@intel.com>
+ * Mika Westerberg <***@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _LINUX_PROPERTY_H_
+#define _LINUX_PROPERTY_H_
+
+#include <linux/types.h>
+
+struct device;
+
+enum dev_prop_type {
+ DEV_PROP_U8,
+ DEV_PROP_U16,
+ DEV_PROP_U32,
+ DEV_PROP_U64,
+ DEV_PROP_STRING,
+ DEV_PROP_MAX,
+};
+
+int device_get_property(struct device *dev, const char *propname,
+ void **valptr);
+int device_read_property(struct device *dev, const char *propname,
+ enum dev_prop_type proptype, void *val);
+int device_read_property_array(struct device *dev, const char *propname,
+ enum dev_prop_type proptype, void *val,
+ size_t nval);
+
+static inline int device_property_read_u8(struct device *dev,
+ const char *propname, u8 *out_value)
+{
+ return device_read_property(dev, propname, DEV_PROP_U8, out_value);
+}
+
+static inline int device_property_read_u16(struct device *dev,
+ const char *propname, u16 *out_value)
+{
+ return device_read_property(dev, propname, DEV_PROP_U16, out_value);
+}
+
+static inline int device_property_read_u32(struct device *dev,
+ const char *propname, u32 *out_value)
+{
+ return device_read_property(dev, propname, DEV_PROP_U32, out_value);
+}
+
+static inline int device_property_read_u64(struct device *dev,
+ const char *propname, u64 *out_value)
+{
+ return device_read_property(dev, propname, DEV_PROP_U64, out_value);
+}
+
+static inline int device_property_read_u8_array(struct device *dev,
+ const char *propname,
+ u8 *val, size_t nval)
+{
+ return device_read_property_array(dev, propname, DEV_PROP_U8, val,
+ nval);
+}
+
+static inline int device_property_read_u16_array(struct device *dev,
+ const char *propname,
+ u16 *val, size_t nval)
+{
+ return device_read_property_array(dev, propname, DEV_PROP_U16, val,
+ nval);
+}
+
+static inline int device_property_read_u32_array(struct device *dev,
+ const char *propname,
+ u32 *val, size_t nval)
+{
+ return device_read_property_array(dev, propname, DEV_PROP_U32, val,
+ nval);
+}
+
+static inline int device_property_read_u64_array(struct device *dev,
+ const char *propname,
+ u64 *val, size_t nval)
+{
+ return device_read_property_array(dev, propname, DEV_PROP_U64, val,
+ nval);
+}
+
+static inline int device_property_read_string(struct device *dev,
+ const char *propname,
+ const char **out_string)
+{
+ return device_read_property(dev, propname, DEV_PROP_STRING, out_string);
+}
+
+static inline int device_property_read_string_array(struct device *dev,
+ const char *propname,
+ const char **out_strings,
+ size_t nstrings)
+{
+ return device_read_property_array(dev, propname, DEV_PROP_STRING,
+ out_strings, nstrings);
+}
+#endif /* _LINUX_PROPERTY_H_ */
Rafael J. Wysocki
2014-10-07 00:18:08 UTC
Permalink
From: Mika Westerberg <***@linux.intel.com>

Some drivers need to deal with only firmware representation of its
GPIOs. An example would be a GPIO button array driver where each button
is described as a separate firmware node in device tree. Typically these
child nodes do not have physical representation in the Linux device
model.

In order to help device drivers to handle such firmware child nodes we
add dev[m]_get_named_gpiod_from_child() that takes a child firmware
node pointer as its second argument (the first one is the parent device
itself), finds the GPIO using whatever is the underlying firmware
method, and requests the GPIO properly.

Signed-off-by: Mika Westerberg <***@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <***@intel.com>
---
drivers/gpio/devres.c | 34 ++++++++++++++++++++++++++
drivers/gpio/gpiolib.c | 56 +++++++++++++++++++++++++++++++++++++++++++
include/linux/gpio/consumer.h | 5 ++++
3 files changed, 95 insertions(+)

diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c
index 954b9f6..a1f7e55 100644
--- a/drivers/gpio/devres.c
+++ b/drivers/gpio/devres.c
@@ -109,6 +109,40 @@ struct gpio_desc *__must_check __devm_gpiod_get_index(struct device *dev,
EXPORT_SYMBOL(__devm_gpiod_get_index);

/**
+ * devm_get_named_gpiod_from_child - managed dev_get_named_gpiod_from_child()
+ * @dev: GPIO consumer
+ * @child: firmware node (child of @dev)
+ * @propname: name of the firmware property
+ * @index: index of the GPIO in the property value in case of many
+ *
+ * GPIO descriptors returned from this function are automatically disposed on
+ * driver detach.
+ */
+struct gpio_desc *devm_get_named_gpiod_from_child(struct device *dev, void *child,
+ const char *propname, int index)
+{
+ struct gpio_desc **dr;
+ struct gpio_desc *desc;
+
+ dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *),
+ GFP_KERNEL);
+ if (!dr)
+ return ERR_PTR(-ENOMEM);
+
+ desc = dev_get_named_gpiod_from_child(dev, child, propname, index);
+ if (IS_ERR(desc)) {
+ devres_free(dr);
+ return desc;
+ }
+
+ *dr = desc;
+ devres_add(dev, dr);
+
+ return desc;
+}
+EXPORT_SYMBOL(devm_get_named_gpiod_from_child);
+
+/**
* devm_gpiod_get_index_optional - Resource-managed gpiod_get_index_optional()
* @dev: GPIO consumer
* @con_id: function within the GPIO consumer
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 4c86601..344bc12 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1717,6 +1717,62 @@ struct gpio_desc *__must_check __gpiod_get_index(struct device *dev,
EXPORT_SYMBOL_GPL(__gpiod_get_index);

/**
+ * dev_get_named_gpiod_from_child - obtain a GPIO from firmware node
+ * @dev: parent device
+ * @child: firmware node (child of @dev)
+ * @propname: name of the firmware property
+ * @idx: index of the GPIO in the property value in case of many
+ *
+ * This function can be used for drivers that get their configuration
+ * from firmware in such a way that some properties are described as child
+ * nodes for the parent device in DT or ACPI.
+ *
+ * Function properly finds the corresponding GPIO using whatever is the
+ * underlying firmware interface and then makes sure that the GPIO
+ * descriptor is requested before it is returned to the caller.
+ *
+ * In case of error an ERR_PTR() is returned.
+ */
+struct gpio_desc *dev_get_named_gpiod_from_child(struct device *dev, void *child,
+ const char *propname, int index)
+{
+ struct gpio_desc *desc = ERR_PTR(-ENODEV);
+ bool active_low = false;
+ int ret;
+
+ if (!child)
+ return ERR_PTR(-EINVAL);
+
+ if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
+ enum of_gpio_flags flags;
+
+ desc = of_get_named_gpiod_flags(child, propname, index, &flags);
+ if (!IS_ERR(desc))
+ active_low = flags & OF_GPIO_ACTIVE_LOW;
+ } else if (ACPI_COMPANION(dev)) {
+ struct acpi_gpio_info info;
+
+ desc = acpi_get_gpiod_by_index(child, propname, index, &info);
+ if (!IS_ERR(desc))
+ active_low = info.active_low;
+ }
+
+ if (IS_ERR(desc))
+ return desc;
+
+ ret = gpiod_request(desc, NULL);
+ if (ret)
+ return ERR_PTR(ret);
+
+ /* Only value flag can be set from both DT and ACPI is active_low */
+ if (active_low)
+ set_bit(FLAG_ACTIVE_LOW, &desc->flags);
+
+ return desc;
+}
+EXPORT_SYMBOL_GPL(dev_get_named_gpiod_from_child);
+
+/**
* gpiod_get_index_optional - obtain an optional GPIO from a multi-index GPIO
* function
* @dev: GPIO consumer, can be NULL for system-global GPIOs
diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h
index 12f146f..033d2fd 100644
--- a/include/linux/gpio/consumer.h
+++ b/include/linux/gpio/consumer.h
@@ -94,6 +94,11 @@ int gpiod_to_irq(const struct gpio_desc *desc);
struct gpio_desc *gpio_to_desc(unsigned gpio);
int desc_to_gpio(const struct gpio_desc *desc);

+/* Child properties interface */
+struct gpio_desc *dev_get_named_gpiod_from_child(struct device *dev, void *child,
+ const char *propname, int index);
+struct gpio_desc *devm_get_named_gpiod_from_child(struct device *dev, void *child,
+ const char *propname, int index);
#else /* CONFIG_GPIOLIB */

static inline struct gpio_desc *__must_check __gpiod_get(struct device *dev,
--
1.9.3
Alexandre Courbot
2014-10-07 10:22:13 UTC
Permalink
Post by Rafael J. Wysocki
Some drivers need to deal with only firmware representation of its
GPIOs. An example would be a GPIO button array driver where each button
is described as a separate firmware node in device tree. Typically these
child nodes do not have physical representation in the Linux device
model.
In order to help device drivers to handle such firmware child nodes we
add dev[m]_get_named_gpiod_from_child() that takes a child firmware
node pointer as its second argument (the first one is the parent device
itself), finds the GPIO using whatever is the underlying firmware
method, and requests the GPIO properly.
...
Post by Rafael J. Wysocki
+/* Child properties interface */
+struct gpio_desc *dev_get_named_gpiod_from_child(struct device *dev, void *child,
+ const char *propname, int index);
+struct gpio_desc *devm_get_named_gpiod_from_child(struct device *dev, void *child,
+ const char *propname, int index);
I see the reason for these functions and am not opposed to them.
However, I wonder if we could not replace propname by a con_id that
would be resolved to one of con_id-gpio for DT and whatever naming
convention ACPI is using?

This would prevent users to name GPIOs outside of the conventions
defined in the bindings and be generally safer. Is there a particular
reason (used by some old code?) for the current direct property
access? If not, maybe we could call a slightly-modified of_find_gpio()
to resolve the GPIO property for DT, and the equivalent function for
ACPI?
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Mika Westerberg
2014-10-07 10:40:21 UTC
Permalink
Post by Alexandre Courbot
Post by Rafael J. Wysocki
Some drivers need to deal with only firmware representation of its
GPIOs. An example would be a GPIO button array driver where each button
is described as a separate firmware node in device tree. Typically these
child nodes do not have physical representation in the Linux device
model.
In order to help device drivers to handle such firmware child nodes we
add dev[m]_get_named_gpiod_from_child() that takes a child firmware
node pointer as its second argument (the first one is the parent device
itself), finds the GPIO using whatever is the underlying firmware
method, and requests the GPIO properly.
...
Post by Rafael J. Wysocki
+/* Child properties interface */
+struct gpio_desc *dev_get_named_gpiod_from_child(struct device *dev, void *child,
+ const char *propname, int index);
+struct gpio_desc *devm_get_named_gpiod_from_child(struct device *dev, void *child,
+ const char *propname, int index);
I see the reason for these functions and am not opposed to them.
However, I wonder if we could not replace propname by a con_id that
would be resolved to one of con_id-gpio for DT and whatever naming
convention ACPI is using?
The code in gpio-leds.c and gpio_keys_polled.c refers to "gpios" as the
property name. If we can change that somehow to work with con_id-gpio
instead without breaking things, then why not.
Post by Alexandre Courbot
This would prevent users to name GPIOs outside of the conventions
defined in the bindings and be generally safer. Is there a particular
reason (used by some old code?) for the current direct property
access? If not, maybe we could call a slightly-modified of_find_gpio()
to resolve the GPIO property for DT, and the equivalent function for
ACPI?
Only reason I can think of is support for the existing properties that
are used directly. Drivers using gpiod_get() and friends do not need
dev_get_named_gpiod_from_child() anyway.
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Alexandre Courbot
2014-10-07 10:52:02 UTC
Permalink
On Tue, Oct 7, 2014 at 7:40 PM, Mika Westerberg
Post by Mika Westerberg
Post by Alexandre Courbot
Post by Rafael J. Wysocki
Some drivers need to deal with only firmware representation of its
GPIOs. An example would be a GPIO button array driver where each button
is described as a separate firmware node in device tree. Typically these
child nodes do not have physical representation in the Linux device
model.
In order to help device drivers to handle such firmware child nodes we
add dev[m]_get_named_gpiod_from_child() that takes a child firmware
node pointer as its second argument (the first one is the parent device
itself), finds the GPIO using whatever is the underlying firmware
method, and requests the GPIO properly.
...
Post by Rafael J. Wysocki
+/* Child properties interface */
+struct gpio_desc *dev_get_named_gpiod_from_child(struct device *dev, void *child,
+ const char *propname, int index);
+struct gpio_desc *devm_get_named_gpiod_from_child(struct device *dev, void *child,
+ const char *propname, int index);
I see the reason for these functions and am not opposed to them.
However, I wonder if we could not replace propname by a con_id that
would be resolved to one of con_id-gpio for DT and whatever naming
convention ACPI is using?
The code in gpio-leds.c and gpio_keys_polled.c refers to "gpios" as the
property name. If we can change that somehow to work with con_id-gpio
instead without breaking things, then why not.
Post by Alexandre Courbot
This would prevent users to name GPIOs outside of the conventions
defined in the bindings and be generally safer. Is there a particular
reason (used by some old code?) for the current direct property
access? If not, maybe we could call a slightly-modified of_find_gpio()
to resolve the GPIO property for DT, and the equivalent function for
ACPI?
Only reason I can think of is support for the existing properties that
are used directly. Drivers using gpiod_get() and friends do not need
dev_get_named_gpiod_from_child() anyway.
Right. Another thing is that the property handling code (active low
only for now) is duplicated again, but that can be addressed
separately.

I will have a look at gpio-leds and gpio_keys_polled to see if we
cannot make this work at a higher level. It's easier to have the
bindings respected if the code itself enforces them.
Rafael J. Wysocki
2014-10-08 00:09:26 UTC
Permalink
Post by Alexandre Courbot
On Tue, Oct 7, 2014 at 7:40 PM, Mika Westerberg
Post by Mika Westerberg
Post by Alexandre Courbot
Post by Rafael J. Wysocki
Some drivers need to deal with only firmware representation of its
GPIOs. An example would be a GPIO button array driver where each button
is described as a separate firmware node in device tree. Typically these
child nodes do not have physical representation in the Linux device
model.
In order to help device drivers to handle such firmware child nodes we
add dev[m]_get_named_gpiod_from_child() that takes a child firmware
node pointer as its second argument (the first one is the parent device
itself), finds the GPIO using whatever is the underlying firmware
method, and requests the GPIO properly.
...
Post by Rafael J. Wysocki
+/* Child properties interface */
+struct gpio_desc *dev_get_named_gpiod_from_child(struct device *dev, void *child,
+ const char *propname, int index);
+struct gpio_desc *devm_get_named_gpiod_from_child(struct device *dev, void *child,
+ const char *propname, int index);
I see the reason for these functions and am not opposed to them.
However, I wonder if we could not replace propname by a con_id that
would be resolved to one of con_id-gpio for DT and whatever naming
convention ACPI is using?
The code in gpio-leds.c and gpio_keys_polled.c refers to "gpios" as the
property name. If we can change that somehow to work with con_id-gpio
instead without breaking things, then why not.
Post by Alexandre Courbot
This would prevent users to name GPIOs outside of the conventions
defined in the bindings and be generally safer. Is there a particular
reason (used by some old code?) for the current direct property
access? If not, maybe we could call a slightly-modified of_find_gpio()
to resolve the GPIO property for DT, and the equivalent function for
ACPI?
Only reason I can think of is support for the existing properties that
are used directly. Drivers using gpiod_get() and friends do not need
dev_get_named_gpiod_from_child() anyway.
Right. Another thing is that the property handling code (active low
only for now) is duplicated again, but that can be addressed
separately.
I will have a look at gpio-leds and gpio_keys_polled to see if we
cannot make this work at a higher level. It's easier to have the
bindings respected if the code itself enforces them.
I'm wondering if that can be done after merging the current work?

We'll be able to use the drivers in question with our hardware in the
meantime then ...
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
Alexandre Courbot
2014-10-08 02:55:08 UTC
Permalink
Post by Rafael J. Wysocki
Post by Alexandre Courbot
On Tue, Oct 7, 2014 at 7:40 PM, Mika Westerberg
Post by Mika Westerberg
Post by Alexandre Courbot
Post by Rafael J. Wysocki
Some drivers need to deal with only firmware representation of its
GPIOs. An example would be a GPIO button array driver where each button
is described as a separate firmware node in device tree. Typically these
child nodes do not have physical representation in the Linux device
model.
In order to help device drivers to handle such firmware child nodes we
add dev[m]_get_named_gpiod_from_child() that takes a child firmware
node pointer as its second argument (the first one is the parent device
itself), finds the GPIO using whatever is the underlying firmware
method, and requests the GPIO properly.
...
Post by Rafael J. Wysocki
+/* Child properties interface */
+struct gpio_desc *dev_get_named_gpiod_from_child(struct device *dev, void *child,
+ const char *propname, int index);
+struct gpio_desc *devm_get_named_gpiod_from_child(struct device *dev, void *child,
+ const char *propname, int index);
I see the reason for these functions and am not opposed to them.
However, I wonder if we could not replace propname by a con_id that
would be resolved to one of con_id-gpio for DT and whatever naming
convention ACPI is using?
The code in gpio-leds.c and gpio_keys_polled.c refers to "gpios" as the
property name. If we can change that somehow to work with con_id-gpio
instead without breaking things, then why not.
Post by Alexandre Courbot
This would prevent users to name GPIOs outside of the conventions
defined in the bindings and be generally safer. Is there a particular
reason (used by some old code?) for the current direct property
access? If not, maybe we could call a slightly-modified of_find_gpio()
to resolve the GPIO property for DT, and the equivalent function for
ACPI?
Only reason I can think of is support for the existing properties that
are used directly. Drivers using gpiod_get() and friends do not need
dev_get_named_gpiod_from_child() anyway.
Right. Another thing is that the property handling code (active low
only for now) is duplicated again, but that can be addressed
separately.
I will have a look at gpio-leds and gpio_keys_polled to see if we
cannot make this work at a higher level. It's easier to have the
bindings respected if the code itself enforces them.
I'm wondering if that can be done after merging the current work?
We'll be able to use the drivers in question with our hardware in the
meantime then ...
Yeah, that's probably ok. The properties in question already exist so
we will have to support them anyway ; it's just a matter of seeing
whether we can improve the proposed way.

So for now:

Acked-by: Alexandre Courbot <***@nvidia.com>
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Rafael J. Wysocki
2014-10-08 14:01:45 UTC
Permalink
Post by Alexandre Courbot
Post by Rafael J. Wysocki
Post by Alexandre Courbot
On Tue, Oct 7, 2014 at 7:40 PM, Mika Westerberg
Post by Mika Westerberg
Post by Alexandre Courbot
Post by Rafael J. Wysocki
Some drivers need to deal with only firmware representation of its
GPIOs. An example would be a GPIO button array driver where each button
is described as a separate firmware node in device tree. Typically these
child nodes do not have physical representation in the Linux device
model.
In order to help device drivers to handle such firmware child nodes we
add dev[m]_get_named_gpiod_from_child() that takes a child firmware
node pointer as its second argument (the first one is the parent device
itself), finds the GPIO using whatever is the underlying firmware
method, and requests the GPIO properly.
...
Post by Rafael J. Wysocki
+/* Child properties interface */
+struct gpio_desc *dev_get_named_gpiod_from_child(struct device *dev, void *child,
+ const char *propname, int index);
+struct gpio_desc *devm_get_named_gpiod_from_child(struct device *dev, void *child,
+ const char *propname, int index);
I see the reason for these functions and am not opposed to them.
However, I wonder if we could not replace propname by a con_id that
would be resolved to one of con_id-gpio for DT and whatever naming
convention ACPI is using?
The code in gpio-leds.c and gpio_keys_polled.c refers to "gpios" as the
property name. If we can change that somehow to work with con_id-gpio
instead without breaking things, then why not.
Post by Alexandre Courbot
This would prevent users to name GPIOs outside of the conventions
defined in the bindings and be generally safer. Is there a particular
reason (used by some old code?) for the current direct property
access? If not, maybe we could call a slightly-modified of_find_gpio()
to resolve the GPIO property for DT, and the equivalent function for
ACPI?
Only reason I can think of is support for the existing properties that
are used directly. Drivers using gpiod_get() and friends do not need
dev_get_named_gpiod_from_child() anyway.
Right. Another thing is that the property handling code (active low
only for now) is duplicated again, but that can be addressed
separately.
I will have a look at gpio-leds and gpio_keys_polled to see if we
cannot make this work at a higher level. It's easier to have the
bindings respected if the code itself enforces them.
I'm wondering if that can be done after merging the current work?
We'll be able to use the drivers in question with our hardware in the
meantime then ...
Yeah, that's probably ok. The properties in question already exist so
we will have to support them anyway ; it's just a matter of seeing
whether we can improve the proposed way.
Thanks!
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Rafael J. Wysocki
2014-10-07 00:12:23 UTC
Permalink
From: Mika Westerberg <***@linux.intel.com>

Device Tree is used in many embedded systems to describe the system
configuration to the OS. It supports attaching properties or name-value
pairs to the devices it describe. With these properties one can pass
additional information to the drivers that would not be available
otherwise.

ACPI is another configuration mechanism (among other things) typically
seen, but not limited to, x86 machines. ACPI allows passing arbitrary
data from methods but there has not been mechanism equivalent to Device
Tree until the introduction of _DSD in the recent publication of the
ACPI 5.1 specification.

In order to facilitate ACPI usage in systems where Device Tree is
typically used, it would be beneficial to standardize a way to retrieve
Device Tree style properties from ACPI devices, which is what we do in
this patch.

If a given device described in ACPI namespace wants to export properties it
must implement _DSD method (Device Specific Data, introduced with ACPI 5.1)
that returns the properties in a package of packages. For example:

Name (_DSD, Package () {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () {"name1", <VALUE1>},
Package () {"name2", <VALUE2>},
...
}
})

The UUID reserved for properties is daffd814-6eba-4d8c-8a91-bc9bbf4aa301
and is documented in the ACPI 5.1 companion document called "_DSD
Implementation Guide" [1], [2].

We add several helper functions that can be used to extract these
properties and convert them to different Linux data types.

The ultimate goal is that we only have one device property API that
retrieves the requested properties from Device Tree or from ACPI
transparent to the caller.

[1] http://www.uefi.org/sites/default/files/resources/_DSD-implementation-guide-toplevel.htm
[2] http://www.uefi.org/sites/default/files/resources/_DSD-device-properties-UUID.pdf

Reviewed-by: Hanjun Guo <***@linaro.org>
Reviewed-by: Josh Triplett <***@joshtriplett.org>
Signed-off-by: Darren Hart <***@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <***@intel.com>
Signed-off-by: Mika Westerberg <***@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <***@intel.com>
---
drivers/acpi/Makefile | 1
drivers/acpi/internal.h | 6
drivers/acpi/property.c | 364 ++++++++++++++++++++++++++++++++++++++++++++++++
drivers/acpi/scan.c | 2
include/acpi/acpi_bus.h | 7
include/linux/acpi.h | 40 +++++
6 files changed, 420 insertions(+)
create mode 100644 drivers/acpi/property.c

Index: linux-pm/drivers/acpi/Makefile
===================================================================
--- linux-pm.orig/drivers/acpi/Makefile
+++ linux-pm/drivers/acpi/Makefile
@@ -46,6 +46,7 @@ acpi-y += acpi_pnp.o
acpi-y += power.o
acpi-y += event.o
acpi-y += sysfs.o
+acpi-y += property.o
acpi-$(CONFIG_X86) += acpi_cmos_rtc.o
acpi-$(CONFIG_DEBUG_FS) += debugfs.o
acpi-$(CONFIG_ACPI_NUMA) += numa.o
Index: linux-pm/drivers/acpi/internal.h
===================================================================
--- linux-pm.orig/drivers/acpi/internal.h
+++ linux-pm/drivers/acpi/internal.h
@@ -181,4 +181,10 @@ struct platform_device *acpi_create_plat
bool acpi_osi_is_win8(void);
#endif

+/*--------------------------------------------------------------------------
+ Device properties
+ -------------------------------------------------------------------------- */
+void acpi_init_properties(struct acpi_device *adev);
+void acpi_free_properties(struct acpi_device *adev);
+
#endif /* _ACPI_INTERNAL_H_ */
Index: linux-pm/drivers/acpi/property.c
===================================================================
--- /dev/null
+++ linux-pm/drivers/acpi/property.c
@@ -0,0 +1,364 @@
+/*
+ * ACPI device specific properties support.
+ *
+ * Copyright (C) 2014, Intel Corporation
+ * All rights reserved.
+ *
+ * Authors: Mika Westerberg <***@linux.intel.com>
+ * Darren Hart <***@linux.intel.com>
+ * Rafael J. Wysocki <***@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/export.h>
+
+#include "internal.h"
+
+/* ACPI _DSD device properties UUID: daffd814-6eba-4d8c-8a91-bc9bbf4aa301 */
+static const u8 prp_uuid[16] = {
+ 0x14, 0xd8, 0xff, 0xda, 0xba, 0x6e, 0x8c, 0x4d,
+ 0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01
+};
+
+static bool acpi_property_value_ok(const union acpi_object *value)
+{
+ int j;
+
+ /*
+ * The value must be an integer, a string, a reference, or a package
+ * whose every element must be an integer, a string, or a reference.
+ */
+ switch (value->type) {
+ case ACPI_TYPE_INTEGER:
+ case ACPI_TYPE_STRING:
+ case ACPI_TYPE_LOCAL_REFERENCE:
+ return true;
+
+ case ACPI_TYPE_PACKAGE:
+ for (j = 0; j < value->package.count; j++)
+ switch (value->package.elements[j].type) {
+ case ACPI_TYPE_INTEGER:
+ case ACPI_TYPE_STRING:
+ case ACPI_TYPE_LOCAL_REFERENCE:
+ continue;
+
+ default:
+ return false;
+ }
+
+ return true;
+ }
+ return false;
+}
+
+static bool acpi_properties_format_valid(const union acpi_object *properties)
+{
+ int i;
+
+ for (i = 0; i < properties->package.count; i++) {
+ const union acpi_object *property;
+
+ property = &properties->package.elements[i];
+ /*
+ * Only two elements allowed, the first one must be a string and
+ * the second one has to satisfy certain conditions.
+ */
+ if (property->package.count != 2
+ || property->package.elements[0].type != ACPI_TYPE_STRING
+ || !acpi_property_value_ok(&property->package.elements[1]))
+ return false;
+ }
+ return true;
+}
+
+void acpi_init_properties(struct acpi_device *adev)
+{
+ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
+ const union acpi_object *desc;
+ acpi_status status;
+ int i;
+
+ status = acpi_evaluate_object_typed(adev->handle, "_DSD", NULL, &buf,
+ ACPI_TYPE_PACKAGE);
+ if (ACPI_FAILURE(status))
+ return;
+
+ desc = buf.pointer;
+ if (desc->package.count % 2)
+ goto fail;
+
+ /* Look for the device properties UUID. */
+ for (i = 0; i < desc->package.count; i += 2) {
+ const union acpi_object *uuid, *properties;
+
+ uuid = &desc->package.elements[i];
+ properties = &desc->package.elements[i + 1];
+
+ /*
+ * The first element must be a UUID and the second one must be
+ * a package.
+ */
+ if (uuid->type != ACPI_TYPE_BUFFER || uuid->buffer.length != 16
+ || properties->type != ACPI_TYPE_PACKAGE)
+ break;
+
+ if (memcmp(uuid->buffer.pointer, prp_uuid, sizeof(prp_uuid)))
+ continue;
+
+ /*
+ * We found the matching UUID. Now validate the format of the
+ * package immediately following it.
+ */
+ if (!acpi_properties_format_valid(properties))
+ break;
+
+ adev->data.pointer = buf.pointer;
+ adev->data.properties = properties;
+ return;
+ }
+
+ fail:
+ dev_warn(&adev->dev, "Returned _DSD data is not valid, skipping\n");
+ ACPI_FREE(buf.pointer);
+}
+
+void acpi_free_properties(struct acpi_device *adev)
+{
+ ACPI_FREE((void *)adev->data.pointer);
+ adev->data.pointer = NULL;
+ adev->data.properties = NULL;
+}
+
+/**
+ * acpi_dev_get_property - return an ACPI property with given name
+ * @adev: ACPI device to get property
+ * @name: Name of the property
+ * @type: Expected property type
+ * @obj: Location to store the property value (if not %NULL)
+ *
+ * Look up a property with @name and store a pointer to the resulting ACPI
+ * object at the location pointed to by @obj if found.
+ *
+ * Callers must not attempt to free the returned objects. These objects will be
+ * freed by the ACPI core automatically during the removal of @adev.
+ *
+ * Return: %0 if property with @name has been found (success),
+ * %-EINVAL if the arguments are invalid,
+ * %-ENODATA if the property doesn't exist,
+ * %-EPROTO if the property value type doesn't match @type.
+ */
+int acpi_dev_get_property(struct acpi_device *adev, const char *name,
+ acpi_object_type type, const union acpi_object **obj)
+{
+ const union acpi_object *properties;
+ int i;
+
+ if (!adev || !name)
+ return -EINVAL;
+
+ if (!adev->data.pointer || !adev->data.properties)
+ return -ENODATA;
+
+ properties = adev->data.properties;
+ for (i = 0; i < properties->package.count; i++) {
+ const union acpi_object *propname, *propvalue;
+ const union acpi_object *property;
+
+ property = &properties->package.elements[i];
+
+ propname = &property->package.elements[0];
+ propvalue = &property->package.elements[1];
+
+ if (!strcmp(name, propname->string.pointer)) {
+ if (type != ACPI_TYPE_ANY && propvalue->type != type)
+ return -EPROTO;
+ else if (obj)
+ *obj = propvalue;
+
+ return 0;
+ }
+ }
+ return -ENODATA;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_property);
+
+/**
+ * acpi_dev_get_property_array - return an ACPI array property with given name
+ * @adev: ACPI device to get property
+ * @name: Name of the property
+ * @type: Expected type of array elements
+ * @obj: Location to store a pointer to the property value (if not NULL)
+ *
+ * Look up an array property with @name and store a pointer to the resulting
+ * ACPI object at the location pointed to by @obj if found.
+ *
+ * Callers must not attempt to free the returned objects. Those objects will be
+ * freed by the ACPI core automatically during the removal of @adev.
+ *
+ * Return: %0 if array property (package) with @name has been found (success),
+ * %-EINVAL if the arguments are invalid,
+ * %-ENODATA if the property doesn't exist,
+ * %-EPROTO if the property is not a package or the type of its elements
+ * doesn't match @type.
+ */
+int acpi_dev_get_property_array(struct acpi_device *adev, const char *name,
+ acpi_object_type type,
+ const union acpi_object **obj)
+{
+ const union acpi_object *prop;
+ int ret, i;
+
+ ret = acpi_dev_get_property(adev, name, ACPI_TYPE_PACKAGE, &prop);
+ if (ret)
+ return ret;
+
+ if (type != ACPI_TYPE_ANY) {
+ /* Check that all elements are of correct type. */
+ for (i = 0; i < prop->package.count; i++)
+ if (prop->package.elements[i].type != type)
+ return -EPROTO;
+ }
+ if (obj)
+ *obj = prop;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_property_array);
+
+/**
+ * acpi_dev_get_property_reference - returns handle to the referenced object
+ * @adev: ACPI device to get property
+ * @name: Name of the property
+ * @size_prop: Name of the "size" property in referenced object
+ * @index: Index of the reference to return
+ * @args: Location to store the returned reference with optional arguments
+ *
+ * Find property with @name, verifify that it is a package containing at least
+ * one object reference and if so, store the ACPI device object pointer to the
+ * target object in @args->adev.
+ *
+ * If the reference includes arguments (@size_prop is not %NULL) follow the
+ * reference and check whether or not there is an integer property @size_prop
+ * under the target object and if so, whether or not its value matches the
+ * number of arguments that follow the reference. If there's more than one
+ * reference in the property value package, @index is used to select the one to
+ * return.
+ *
+ * Return: %0 on success, negative error code on failure.
+ */
+int acpi_dev_get_property_reference(struct acpi_device *adev, const char *name,
+ const char *size_prop, size_t index,
+ struct acpi_reference_args *args)
+{
+ const union acpi_object *element, *end;
+ const union acpi_object *obj;
+ struct acpi_device *device;
+ int ret, idx = 0;
+
+ ret = acpi_dev_get_property(adev, name, ACPI_TYPE_ANY, &obj);
+ if (ret)
+ return ret;
+
+ /*
+ * The simplest case is when the value is a single reference. Just
+ * return that reference then.
+ */
+ if (obj->type == ACPI_TYPE_LOCAL_REFERENCE) {
+ if (size_prop || index)
+ return -EINVAL;
+
+ ret = acpi_bus_get_device(obj->reference.handle, &device);
+ if (ret)
+ return ret;
+
+ args->adev = device;
+ args->nargs = 0;
+ return 0;
+ }
+
+ /*
+ * If it is not a single reference, then it is a package of
+ * references followed by number of ints as follows:
+ *
+ * Package () { REF, INT, REF, INT, INT }
+ *
+ * The index argument is then used to determine which reference
+ * the caller wants (along with the arguments).
+ */
+ if (obj->type != ACPI_TYPE_PACKAGE || index >= obj->package.count)
+ return -EPROTO;
+
+ element = obj->package.elements;
+ end = element + obj->package.count;
+
+ while (element < end) {
+ u32 nargs, i;
+
+ if (element->type != ACPI_TYPE_LOCAL_REFERENCE)
+ return -EPROTO;
+
+ ret = acpi_bus_get_device(element->reference.handle, &device);
+ if (ret)
+ return -ENODEV;
+
+ element++;
+ nargs = 0;
+
+ if (size_prop) {
+ const union acpi_object *prop;
+
+ /*
+ * Find out how many arguments the refenced object
+ * expects by reading its size_prop property.
+ */
+ ret = acpi_dev_get_property(device, size_prop,
+ ACPI_TYPE_INTEGER, &prop);
+ if (ret)
+ return ret;
+
+ nargs = prop->integer.value;
+ if (nargs > MAX_ACPI_REFERENCE_ARGS
+ || element + nargs > end)
+ return -EPROTO;
+
+ /*
+ * Skip to the start of the arguments and verify
+ * that they all are in fact integers.
+ */
+ for (i = 0; i < nargs; i++)
+ if (element[i].type != ACPI_TYPE_INTEGER)
+ return -EPROTO;
+ } else {
+ /* assume following integer elements are all args */
+ for (i = 0; element + i < end; i++) {
+ int type = element[i].type;
+
+ if (type == ACPI_TYPE_INTEGER)
+ nargs++;
+ else if (type == ACPI_TYPE_LOCAL_REFERENCE)
+ break;
+ else
+ return -EPROTO;
+ }
+ }
+
+ if (idx++ == index) {
+ args->adev = device;
+ args->nargs = nargs;
+ for (i = 0; i < nargs; i++)
+ args->args[i] = element[i].integer.value;
+
+ return 0;
+ }
+
+ element += nargs;
+ }
+
+ return -EPROTO;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_property_reference);
Index: linux-pm/drivers/acpi/scan.c
===================================================================
--- linux-pm.orig/drivers/acpi/scan.c
+++ linux-pm/drivers/acpi/scan.c
@@ -884,6 +884,7 @@ static void acpi_device_release(struct d
{
struct acpi_device *acpi_dev = to_acpi_device(dev);

+ acpi_free_properties(acpi_dev);
acpi_free_pnp_ids(&acpi_dev->pnp);
acpi_free_power_resources_lists(acpi_dev);
kfree(acpi_dev);
@@ -1888,6 +1889,7 @@ void acpi_init_device_object(struct acpi
acpi_set_device_status(device, sta);
acpi_device_get_busid(device);
acpi_set_pnp_ids(handle, &device->pnp, type);
+ acpi_init_properties(device);
acpi_bus_get_flags(device);
device->flags.match_driver = false;
device->flags.initialized = true;
Index: linux-pm/include/acpi/acpi_bus.h
===================================================================
--- linux-pm.orig/include/acpi/acpi_bus.h
+++ linux-pm/include/acpi/acpi_bus.h
@@ -337,6 +337,12 @@ struct acpi_device_physical_node {
bool put_online:1;
};

+/* ACPI Device Specific Data (_DSD) */
+struct acpi_device_data {
+ const union acpi_object *pointer;
+ const union acpi_object *properties;
+};
+
/* Device */
struct acpi_device {
int device_type;
@@ -353,6 +359,7 @@ struct acpi_device {
struct acpi_device_wakeup wakeup;
struct acpi_device_perf performance;
struct acpi_device_dir dir;
+ struct acpi_device_data data;
struct acpi_scan_handler *handler;
struct acpi_hotplug_context *hp;
struct acpi_driver *driver;
Index: linux-pm/include/linux/acpi.h
===================================================================
--- linux-pm.orig/include/linux/acpi.h
+++ linux-pm/include/linux/acpi.h
@@ -658,4 +658,44 @@ do { \
#endif
#endif

+/* Device properties */
+
+#define MAX_ACPI_REFERENCE_ARGS 8
+struct acpi_reference_args {
+ struct acpi_device *adev;
+ size_t nargs;
+ u64 args[MAX_ACPI_REFERENCE_ARGS];
+};
+
+#ifdef CONFIG_ACPI
+int acpi_dev_get_property(struct acpi_device *adev, const char *name,
+ acpi_object_type type, const union acpi_object **obj);
+int acpi_dev_get_property_array(struct acpi_device *adev, const char *name,
+ acpi_object_type type,
+ const union acpi_object **obj);
+int acpi_dev_get_property_reference(struct acpi_device *adev, const char *name,
+ const char *cells_name, size_t index,
+ struct acpi_reference_args *args);
+#else
+static inline int acpi_dev_get_property(struct acpi_device *adev,
+ const char *name, acpi_object_type type,
+ const union acpi_object **obj)
+{
+ return -ENXIO;
+}
+static inline int acpi_dev_get_property_array(struct acpi_device *adev,
+ const char *name,
+ acpi_object_type type,
+ const union acpi_object **obj)
+{
+ return -ENXIO;
+}
+static inline int acpi_dev_get_property_reference(struct acpi_device *adev,
+ const char *name, const char *cells_name,
+ size_t index, struct acpi_reference_args *args)
+{
+ return -ENXIO;
+}
+#endif
+
#endif /*_LINUX_ACPI_H*/
Grant Likely
2014-10-13 12:47:42 UTC
Permalink
On Tue, 07 Oct 2014 02:12:23 +0200
Post by Rafael J. Wysocki
Device Tree is used in many embedded systems to describe the system
configuration to the OS. It supports attaching properties or name-value
pairs to the devices it describe. With these properties one can pass
additional information to the drivers that would not be available
otherwise.
ACPI is another configuration mechanism (among other things) typically
seen, but not limited to, x86 machines. ACPI allows passing arbitrary
data from methods but there has not been mechanism equivalent to Device
Tree until the introduction of _DSD in the recent publication of the
ACPI 5.1 specification.
In order to facilitate ACPI usage in systems where Device Tree is
typically used, it would be beneficial to standardize a way to retrieve
Device Tree style properties from ACPI devices, which is what we do in
this patch.
If a given device described in ACPI namespace wants to export properties it
must implement _DSD method (Device Specific Data, introduced with ACPI 5.1)
Name (_DSD, Package () {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () {"name1", <VALUE1>},
Package () {"name2", <VALUE2>},
...
}
})
The UUID reserved for properties is daffd814-6eba-4d8c-8a91-bc9bbf4aa301
and is documented in the ACPI 5.1 companion document called "_DSD
Implementation Guide" [1], [2].
We add several helper functions that can be used to extract these
properties and convert them to different Linux data types.
The ultimate goal is that we only have one device property API that
retrieves the requested properties from Device Tree or from ACPI
transparent to the caller.
[1] http://www.uefi.org/sites/default/files/resources/_DSD-implementation-guide-toplevel.htm
[2] http://www.uefi.org/sites/default/files/resources/_DSD-device-properties-UUID.pdf
This patch seems fine.
Post by Rafael J. Wysocki
---
drivers/acpi/Makefile | 1
drivers/acpi/internal.h | 6
drivers/acpi/property.c | 364 ++++++++++++++++++++++++++++++++++++++++++++++++
drivers/acpi/scan.c | 2
include/acpi/acpi_bus.h | 7
include/linux/acpi.h | 40 +++++
6 files changed, 420 insertions(+)
create mode 100644 drivers/acpi/property.c
Index: linux-pm/drivers/acpi/Makefile
===================================================================
--- linux-pm.orig/drivers/acpi/Makefile
+++ linux-pm/drivers/acpi/Makefile
@@ -46,6 +46,7 @@ acpi-y += acpi_pnp.o
acpi-y += power.o
acpi-y += event.o
acpi-y += sysfs.o
+acpi-y += property.o
acpi-$(CONFIG_X86) += acpi_cmos_rtc.o
acpi-$(CONFIG_DEBUG_FS) += debugfs.o
acpi-$(CONFIG_ACPI_NUMA) += numa.o
Index: linux-pm/drivers/acpi/internal.h
===================================================================
--- linux-pm.orig/drivers/acpi/internal.h
+++ linux-pm/drivers/acpi/internal.h
@@ -181,4 +181,10 @@ struct platform_device *acpi_create_plat
bool acpi_osi_is_win8(void);
#endif
+/*--------------------------------------------------------------------------
+ Device properties
+ -------------------------------------------------------------------------- */
+void acpi_init_properties(struct acpi_device *adev);
+void acpi_free_properties(struct acpi_device *adev);
+
#endif /* _ACPI_INTERNAL_H_ */
Index: linux-pm/drivers/acpi/property.c
===================================================================
--- /dev/null
+++ linux-pm/drivers/acpi/property.c
@@ -0,0 +1,364 @@
+/*
+ * ACPI device specific properties support.
+ *
+ * Copyright (C) 2014, Intel Corporation
+ * All rights reserved.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/export.h>
+
+#include "internal.h"
+
+/* ACPI _DSD device properties UUID: daffd814-6eba-4d8c-8a91-bc9bbf4aa301 */
+static const u8 prp_uuid[16] = {
+ 0x14, 0xd8, 0xff, 0xda, 0xba, 0x6e, 0x8c, 0x4d,
+ 0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01
+};
+
+static bool acpi_property_value_ok(const union acpi_object *value)
+{
+ int j;
+
+ /*
+ * The value must be an integer, a string, a reference, or a package
+ * whose every element must be an integer, a string, or a reference.
+ */
+ switch (value->type) {
+ return true;
+
+ for (j = 0; j < value->package.count; j++)
+ switch (value->package.elements[j].type) {
+ continue;
+
+ return false;
+ }
+
+ return true;
+ }
+ return false;
+}
+
+static bool acpi_properties_format_valid(const union acpi_object *properties)
+{
+ int i;
+
+ for (i = 0; i < properties->package.count; i++) {
+ const union acpi_object *property;
+
+ property = &properties->package.elements[i];
+ /*
+ * Only two elements allowed, the first one must be a string and
+ * the second one has to satisfy certain conditions.
+ */
+ if (property->package.count != 2
+ || property->package.elements[0].type != ACPI_TYPE_STRING
+ || !acpi_property_value_ok(&property->package.elements[1]))
+ return false;
+ }
+ return true;
+}
+
+void acpi_init_properties(struct acpi_device *adev)
+{
+ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
+ const union acpi_object *desc;
+ acpi_status status;
+ int i;
+
+ status = acpi_evaluate_object_typed(adev->handle, "_DSD", NULL, &buf,
+ ACPI_TYPE_PACKAGE);
+ if (ACPI_FAILURE(status))
+ return;
+
+ desc = buf.pointer;
+ if (desc->package.count % 2)
+ goto fail;
+
+ /* Look for the device properties UUID. */
+ for (i = 0; i < desc->package.count; i += 2) {
+ const union acpi_object *uuid, *properties;
+
+ uuid = &desc->package.elements[i];
+ properties = &desc->package.elements[i + 1];
+
+ /*
+ * The first element must be a UUID and the second one must be
+ * a package.
+ */
+ if (uuid->type != ACPI_TYPE_BUFFER || uuid->buffer.length != 16
+ || properties->type != ACPI_TYPE_PACKAGE)
+ break;
+
+ if (memcmp(uuid->buffer.pointer, prp_uuid, sizeof(prp_uuid)))
+ continue;
+
+ /*
+ * We found the matching UUID. Now validate the format of the
+ * package immediately following it.
+ */
+ if (!acpi_properties_format_valid(properties))
+ break;
+
+ adev->data.pointer = buf.pointer;
+ adev->data.properties = properties;
+ return;
+ }
+
+ dev_warn(&adev->dev, "Returned _DSD data is not valid, skipping\n");
+ ACPI_FREE(buf.pointer);
+}
+
+void acpi_free_properties(struct acpi_device *adev)
+{
+ ACPI_FREE((void *)adev->data.pointer);
+ adev->data.pointer = NULL;
+ adev->data.properties = NULL;
+}
+
+/**
+ * acpi_dev_get_property - return an ACPI property with given name
+ *
+ *
+ * Callers must not attempt to free the returned objects. These objects will be
+ *
+ * %-EINVAL if the arguments are invalid,
+ * %-ENODATA if the property doesn't exist,
+ */
+int acpi_dev_get_property(struct acpi_device *adev, const char *name,
+ acpi_object_type type, const union acpi_object **obj)
+{
+ const union acpi_object *properties;
+ int i;
+
+ if (!adev || !name)
+ return -EINVAL;
+
+ if (!adev->data.pointer || !adev->data.properties)
+ return -ENODATA;
+
+ properties = adev->data.properties;
+ for (i = 0; i < properties->package.count; i++) {
+ const union acpi_object *propname, *propvalue;
+ const union acpi_object *property;
+
+ property = &properties->package.elements[i];
+
+ propname = &property->package.elements[0];
+ propvalue = &property->package.elements[1];
+
+ if (!strcmp(name, propname->string.pointer)) {
+ if (type != ACPI_TYPE_ANY && propvalue->type != type)
+ return -EPROTO;
+ else if (obj)
+ *obj = propvalue;
+
+ return 0;
+ }
+ }
+ return -ENODATA;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_property);
+
+/**
+ * acpi_dev_get_property_array - return an ACPI array property with given name
+ *
+ *
+ * Callers must not attempt to free the returned objects. Those objects will be
+ *
+ * %-EINVAL if the arguments are invalid,
+ * %-ENODATA if the property doesn't exist,
+ * %-EPROTO if the property is not a package or the type of its elements
+ */
+int acpi_dev_get_property_array(struct acpi_device *adev, const char *name,
+ acpi_object_type type,
+ const union acpi_object **obj)
+{
+ const union acpi_object *prop;
+ int ret, i;
+
+ ret = acpi_dev_get_property(adev, name, ACPI_TYPE_PACKAGE, &prop);
+ if (ret)
+ return ret;
+
+ if (type != ACPI_TYPE_ANY) {
+ /* Check that all elements are of correct type. */
+ for (i = 0; i < prop->package.count; i++)
+ if (prop->package.elements[i].type != type)
+ return -EPROTO;
+ }
+ if (obj)
+ *obj = prop;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_property_array);
+
+/**
+ * acpi_dev_get_property_reference - returns handle to the referenced object
+ *
+ * one object reference and if so, store the ACPI device object pointer to the
+ *
+ * under the target object and if so, whether or not its value matches the
+ * number of arguments that follow the reference. If there's more than one
+ * return.
+ *
+ * Return: %0 on success, negative error code on failure.
+ */
+int acpi_dev_get_property_reference(struct acpi_device *adev, const char *name,
+ const char *size_prop, size_t index,
+ struct acpi_reference_args *args)
+{
+ const union acpi_object *element, *end;
+ const union acpi_object *obj;
+ struct acpi_device *device;
+ int ret, idx = 0;
+
+ ret = acpi_dev_get_property(adev, name, ACPI_TYPE_ANY, &obj);
+ if (ret)
+ return ret;
+
+ /*
+ * The simplest case is when the value is a single reference. Just
+ * return that reference then.
+ */
+ if (obj->type == ACPI_TYPE_LOCAL_REFERENCE) {
+ if (size_prop || index)
+ return -EINVAL;
+
+ ret = acpi_bus_get_device(obj->reference.handle, &device);
+ if (ret)
+ return ret;
+
+ args->adev = device;
+ args->nargs = 0;
+ return 0;
+ }
+
+ /*
+ * If it is not a single reference, then it is a package of
+ *
+ * Package () { REF, INT, REF, INT, INT }
+ *
+ * The index argument is then used to determine which reference
+ * the caller wants (along with the arguments).
+ */
+ if (obj->type != ACPI_TYPE_PACKAGE || index >= obj->package.count)
+ return -EPROTO;
+
+ element = obj->package.elements;
+ end = element + obj->package.count;
+
+ while (element < end) {
+ u32 nargs, i;
+
+ if (element->type != ACPI_TYPE_LOCAL_REFERENCE)
+ return -EPROTO;
+
+ ret = acpi_bus_get_device(element->reference.handle, &device);
+ if (ret)
+ return -ENODEV;
+
+ element++;
+ nargs = 0;
+
+ if (size_prop) {
+ const union acpi_object *prop;
+
+ /*
+ * Find out how many arguments the refenced object
+ * expects by reading its size_prop property.
+ */
+ ret = acpi_dev_get_property(device, size_prop,
+ ACPI_TYPE_INTEGER, &prop);
+ if (ret)
+ return ret;
+
+ nargs = prop->integer.value;
+ if (nargs > MAX_ACPI_REFERENCE_ARGS
+ || element + nargs > end)
+ return -EPROTO;
+
+ /*
+ * Skip to the start of the arguments and verify
+ * that they all are in fact integers.
+ */
+ for (i = 0; i < nargs; i++)
+ if (element[i].type != ACPI_TYPE_INTEGER)
+ return -EPROTO;
+ } else {
+ /* assume following integer elements are all args */
+ for (i = 0; element + i < end; i++) {
+ int type = element[i].type;
+
+ if (type == ACPI_TYPE_INTEGER)
+ nargs++;
+ else if (type == ACPI_TYPE_LOCAL_REFERENCE)
+ break;
+ else
+ return -EPROTO;
+ }
+ }
+
+ if (idx++ == index) {
+ args->adev = device;
+ args->nargs = nargs;
+ for (i = 0; i < nargs; i++)
+ args->args[i] = element[i].integer.value;
+
+ return 0;
+ }
+
+ element += nargs;
+ }
+
+ return -EPROTO;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_property_reference);
Index: linux-pm/drivers/acpi/scan.c
===================================================================
--- linux-pm.orig/drivers/acpi/scan.c
+++ linux-pm/drivers/acpi/scan.c
@@ -884,6 +884,7 @@ static void acpi_device_release(struct d
{
struct acpi_device *acpi_dev = to_acpi_device(dev);
+ acpi_free_properties(acpi_dev);
acpi_free_pnp_ids(&acpi_dev->pnp);
acpi_free_power_resources_lists(acpi_dev);
kfree(acpi_dev);
@@ -1888,6 +1889,7 @@ void acpi_init_device_object(struct acpi
acpi_set_device_status(device, sta);
acpi_device_get_busid(device);
acpi_set_pnp_ids(handle, &device->pnp, type);
+ acpi_init_properties(device);
acpi_bus_get_flags(device);
device->flags.match_driver = false;
device->flags.initialized = true;
Index: linux-pm/include/acpi/acpi_bus.h
===================================================================
--- linux-pm.orig/include/acpi/acpi_bus.h
+++ linux-pm/include/acpi/acpi_bus.h
@@ -337,6 +337,12 @@ struct acpi_device_physical_node {
bool put_online:1;
};
+/* ACPI Device Specific Data (_DSD) */
+struct acpi_device_data {
+ const union acpi_object *pointer;
+ const union acpi_object *properties;
+};
+
/* Device */
struct acpi_device {
int device_type;
@@ -353,6 +359,7 @@ struct acpi_device {
struct acpi_device_wakeup wakeup;
struct acpi_device_perf performance;
struct acpi_device_dir dir;
+ struct acpi_device_data data;
struct acpi_scan_handler *handler;
struct acpi_hotplug_context *hp;
struct acpi_driver *driver;
Index: linux-pm/include/linux/acpi.h
===================================================================
--- linux-pm.orig/include/linux/acpi.h
+++ linux-pm/include/linux/acpi.h
@@ -658,4 +658,44 @@ do { \
#endif
#endif
+/* Device properties */
+
+#define MAX_ACPI_REFERENCE_ARGS 8
+struct acpi_reference_args {
+ struct acpi_device *adev;
+ size_t nargs;
+ u64 args[MAX_ACPI_REFERENCE_ARGS];
+};
+
+#ifdef CONFIG_ACPI
+int acpi_dev_get_property(struct acpi_device *adev, const char *name,
+ acpi_object_type type, const union acpi_object **obj);
+int acpi_dev_get_property_array(struct acpi_device *adev, const char *name,
+ acpi_object_type type,
+ const union acpi_object **obj);
+int acpi_dev_get_property_reference(struct acpi_device *adev, const char *name,
+ const char *cells_name, size_t index,
+ struct acpi_reference_args *args);
+#else
+static inline int acpi_dev_get_property(struct acpi_device *adev,
+ const char *name, acpi_object_type type,
+ const union acpi_object **obj)
+{
+ return -ENXIO;
+}
+static inline int acpi_dev_get_property_array(struct acpi_device *adev,
+ const char *name,
+ acpi_object_type type,
+ const union acpi_object **obj)
+{
+ return -ENXIO;
+}
+static inline int acpi_dev_get_property_reference(struct acpi_device *adev,
+ const char *name, const char *cells_name,
+ size_t index, struct acpi_reference_args *args)
+{
+ return -ENXIO;
+}
+#endif
+
#endif /*_LINUX_ACPI_H*/
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Rafael J. Wysocki
2014-10-07 00:13:29 UTC
Permalink
From: Mika Westerberg <***@linux.intel.com>

We have lots of existing Device Tree enabled drivers and allocating
separate _HID for each is not feasible. Instead we allocate special _HID
"PRP0001" that means that the match should be done using Device Tree
compatible property using driver's .of_match_table instead if the driver
is missing .acpi_match_table.

If there is a need to distinguish from where the device is enumerated
(DT/ACPI) driver can check dev->of_node or ACPI_COMPATION(dev).

Signed-off-by: Mika Westerberg <***@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <***@intel.com>
---
drivers/acpi/property.c | 34 +++++++++++++++++
drivers/acpi/scan.c | 97 +++++++++++++++++++++++++++++++++++++++++++------
include/acpi/acpi_bus.h | 1 +
include/linux/acpi.h | 8 +---
4 files changed, 123 insertions(+), 17 deletions(-)

diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c
index 680f7f1..ff53eb8 100644
--- a/drivers/acpi/property.c
+++ b/drivers/acpi/property.c
@@ -76,6 +76,37 @@ static bool acpi_properties_format_valid(const union acpi_object *properties)
return true;
}

+static void acpi_init_of_compatible(struct acpi_device *adev)
+{
+ const union acpi_object *of_compatible;
+ struct acpi_hardware_id *hwid;
+ bool acpi_of = false;
+
+ /*
+ * Check if the special PRP0001 ACPI ID is present and in that
+ * case we fill in Device Tree compatible properties for this
+ * device.
+ */
+ list_for_each_entry(hwid, &adev->pnp.ids, list) {
+ if (!strcmp(hwid->id, "PRP0001")) {
+ acpi_of = true;
+ break;
+ }
+ }
+
+ if (!acpi_of)
+ return;
+
+ if (acpi_dev_get_property_array(adev, "compatible", ACPI_TYPE_STRING,
+ &of_compatible)) {
+ acpi_handle_warn(adev->handle,
+ "PRP0001 requires compatible property\n");
+ return;
+ }
+
+ adev->data.of_compatible = of_compatible;
+}
+
void acpi_init_properties(struct acpi_device *adev)
{
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
@@ -119,6 +150,8 @@ void acpi_init_properties(struct acpi_device *adev)

adev->data.pointer = buf.pointer;
adev->data.properties = properties;
+
+ acpi_init_of_compatible(adev);
return;
}

@@ -130,6 +163,7 @@ void acpi_init_properties(struct acpi_device *adev)
void acpi_free_properties(struct acpi_device *adev)
{
ACPI_FREE((void *)adev->data.pointer);
+ adev->data.of_compatible = NULL;
adev->data.pointer = NULL;
adev->data.properties = NULL;
}
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 1979ab3..bc999f1 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -124,17 +124,51 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
if (list_empty(&acpi_dev->pnp.ids))
return 0;

- len = snprintf(modalias, size, "acpi:");
- size -= len;
-
- list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
- count = snprintf(&modalias[len], size, "%s:", id->id);
- if (count < 0)
- return -EINVAL;
- if (count >= size)
- return -ENOMEM;
- len += count;
- size -= count;
+ /*
+ * If the device has PRP0001 we expose DT compatible modalias
+ * instead in form of of:NnameTCcompatible.
+ */
+ if (acpi_dev->data.of_compatible) {
+ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
+ const union acpi_object *of_compatible, *obj;
+ char *c;
+ int i;
+
+ acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf);
+ /* DT strings are all in lower case */
+ for (c = buf.pointer; *c != '\0'; c++)
+ *c = tolower(*c);
+
+ len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer);
+ ACPI_FREE(buf.pointer);
+
+ of_compatible = acpi_dev->data.of_compatible;
+ for (i = 0; i < of_compatible->package.count; i++) {
+ obj = &of_compatible->package.elements[i];
+
+ count = snprintf(&modalias[len], size, "C%s",
+ obj->string.pointer);
+ if (count < 0)
+ return -EINVAL;
+ if (count >= size)
+ return -ENOMEM;
+
+ len += count;
+ size -= count;
+ }
+ } else {
+ len = snprintf(modalias, size, "acpi:");
+ size -= len;
+
+ list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
+ count = snprintf(&modalias[len], size, "%s:", id->id);
+ if (count < 0)
+ return -EINVAL;
+ if (count >= size)
+ return -ENOMEM;
+ len += count;
+ size -= count;
+ }
}

modalias[len] = '\0';
@@ -864,6 +898,47 @@ int acpi_match_device_ids(struct acpi_device *device,
}
EXPORT_SYMBOL(acpi_match_device_ids);

+/* Performs match against special "PRP0001" shoehorn ACPI ID */
+static bool acpi_of_driver_match_device(struct device *dev,
+ const struct device_driver *drv)
+{
+ const union acpi_object *of_compatible;
+ struct acpi_device *adev;
+ int i;
+
+ adev = ACPI_COMPANION(dev);
+ if (!adev)
+ return false;
+
+ of_compatible = adev->data.of_compatible;
+ if (!drv->of_match_table || !of_compatible)
+ return false;
+
+ /* Now we can look for the driver DT compatible strings */
+ for (i = 0; i < of_compatible->package.count; i++) {
+ const struct of_device_id *id;
+ const union acpi_object *obj;
+
+ obj = &of_compatible->package.elements[i];
+
+ for (id = drv->of_match_table; id->compatible[0]; id++)
+ if (!strcasecmp(obj->string.pointer, id->compatible))
+ return true;
+ }
+
+ return false;
+}
+
+bool acpi_driver_match_device(struct device *dev,
+ const struct device_driver *drv)
+{
+ if (!drv->acpi_match_table)
+ return acpi_of_driver_match_device(dev, drv);
+
+ return !!acpi_match_device(drv->acpi_match_table, dev);
+}
+EXPORT_SYMBOL_GPL(acpi_driver_match_device);
+
static void acpi_free_power_resources_lists(struct acpi_device *device)
{
int i;
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index f9734fa..98cd723 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -341,6 +341,7 @@ struct acpi_device_physical_node {
struct acpi_device_data {
const union acpi_object *pointer;
const union acpi_object *properties;
+ const union acpi_object *of_compatible;
};

/* Device */
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 18c1bc3..11aa6b8 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -424,12 +424,8 @@ extern int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *),
const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids,
const struct device *dev);

-static inline bool acpi_driver_match_device(struct device *dev,
- const struct device_driver *drv)
-{
- return !!acpi_match_device(drv->acpi_match_table, dev);
-}
-
+extern bool acpi_driver_match_device(struct device *dev,
+ const struct device_driver *drv);
int acpi_device_uevent_modalias(struct device *, struct kobj_uevent_env *);
int acpi_device_modalias(struct device *, char *, int);
--
1.9.3
Grant Likely
2014-10-14 13:38:00 UTC
Permalink
On Tue, 07 Oct 2014 02:13:29 +0200
Post by Rafael J. Wysocki
We have lots of existing Device Tree enabled drivers and allocating
separate _HID for each is not feasible. Instead we allocate special _HID
"PRP0001" that means that the match should be done using Device Tree
compatible property using driver's .of_match_table instead if the driver
is missing .acpi_match_table.
If there is a need to distinguish from where the device is enumerated
(DT/ACPI) driver can check dev->of_node or ACPI_COMPATION(dev).
Looks okay to me.
Post by Rafael J. Wysocki
---
drivers/acpi/property.c | 34 +++++++++++++++++
drivers/acpi/scan.c | 97 +++++++++++++++++++++++++++++++++++++++++++------
include/acpi/acpi_bus.h | 1 +
include/linux/acpi.h | 8 +---
4 files changed, 123 insertions(+), 17 deletions(-)
diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c
index 680f7f1..ff53eb8 100644
--- a/drivers/acpi/property.c
+++ b/drivers/acpi/property.c
@@ -76,6 +76,37 @@ static bool acpi_properties_format_valid(const union acpi_object *properties)
return true;
}
+static void acpi_init_of_compatible(struct acpi_device *adev)
+{
+ const union acpi_object *of_compatible;
+ struct acpi_hardware_id *hwid;
+ bool acpi_of = false;
+
+ /*
+ * Check if the special PRP0001 ACPI ID is present and in that
+ * case we fill in Device Tree compatible properties for this
+ * device.
+ */
+ list_for_each_entry(hwid, &adev->pnp.ids, list) {
+ if (!strcmp(hwid->id, "PRP0001")) {
+ acpi_of = true;
+ break;
+ }
+ }
+
+ if (!acpi_of)
+ return;
+
+ if (acpi_dev_get_property_array(adev, "compatible", ACPI_TYPE_STRING,
+ &of_compatible)) {
+ acpi_handle_warn(adev->handle,
+ "PRP0001 requires compatible property\n");
+ return;
+ }
+
+ adev->data.of_compatible = of_compatible;
+}
+
void acpi_init_properties(struct acpi_device *adev)
{
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
@@ -119,6 +150,8 @@ void acpi_init_properties(struct acpi_device *adev)
adev->data.pointer = buf.pointer;
adev->data.properties = properties;
+
+ acpi_init_of_compatible(adev);
return;
}
@@ -130,6 +163,7 @@ void acpi_init_properties(struct acpi_device *adev)
void acpi_free_properties(struct acpi_device *adev)
{
ACPI_FREE((void *)adev->data.pointer);
+ adev->data.of_compatible = NULL;
adev->data.pointer = NULL;
adev->data.properties = NULL;
}
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 1979ab3..bc999f1 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -124,17 +124,51 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
if (list_empty(&acpi_dev->pnp.ids))
return 0;
- len = snprintf(modalias, size, "acpi:");
- size -= len;
-
- list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
- count = snprintf(&modalias[len], size, "%s:", id->id);
- if (count < 0)
- return -EINVAL;
- if (count >= size)
- return -ENOMEM;
- len += count;
- size -= count;
+ /*
+ * If the device has PRP0001 we expose DT compatible modalias
+ * instead in form of of:NnameTCcompatible.
+ */
+ if (acpi_dev->data.of_compatible) {
+ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
+ const union acpi_object *of_compatible, *obj;
+ char *c;
+ int i;
+
+ acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf);
+ /* DT strings are all in lower case */
+ for (c = buf.pointer; *c != '\0'; c++)
+ *c = tolower(*c);
+
+ len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer);
+ ACPI_FREE(buf.pointer);
+
+ of_compatible = acpi_dev->data.of_compatible;
+ for (i = 0; i < of_compatible->package.count; i++) {
+ obj = &of_compatible->package.elements[i];
+
+ count = snprintf(&modalias[len], size, "C%s",
+ obj->string.pointer);
+ if (count < 0)
+ return -EINVAL;
+ if (count >= size)
+ return -ENOMEM;
+
+ len += count;
+ size -= count;
+ }
+ } else {
+ len = snprintf(modalias, size, "acpi:");
+ size -= len;
+
+ list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
+ count = snprintf(&modalias[len], size, "%s:", id->id);
+ if (count < 0)
+ return -EINVAL;
+ if (count >= size)
+ return -ENOMEM;
+ len += count;
+ size -= count;
+ }
}
modalias[len] = '\0';
@@ -864,6 +898,47 @@ int acpi_match_device_ids(struct acpi_device *device,
}
EXPORT_SYMBOL(acpi_match_device_ids);
+/* Performs match against special "PRP0001" shoehorn ACPI ID */
+static bool acpi_of_driver_match_device(struct device *dev,
+ const struct device_driver *drv)
+{
+ const union acpi_object *of_compatible;
+ struct acpi_device *adev;
+ int i;
+
+ adev = ACPI_COMPANION(dev);
+ if (!adev)
+ return false;
+
+ of_compatible = adev->data.of_compatible;
+ if (!drv->of_match_table || !of_compatible)
+ return false;
+
+ /* Now we can look for the driver DT compatible strings */
+ for (i = 0; i < of_compatible->package.count; i++) {
+ const struct of_device_id *id;
+ const union acpi_object *obj;
+
+ obj = &of_compatible->package.elements[i];
+
+ for (id = drv->of_match_table; id->compatible[0]; id++)
+ if (!strcasecmp(obj->string.pointer, id->compatible))
+ return true;
+ }
+
+ return false;
+}
+
+bool acpi_driver_match_device(struct device *dev,
+ const struct device_driver *drv)
+{
+ if (!drv->acpi_match_table)
+ return acpi_of_driver_match_device(dev, drv);
+
+ return !!acpi_match_device(drv->acpi_match_table, dev);
+}
+EXPORT_SYMBOL_GPL(acpi_driver_match_device);
+
static void acpi_free_power_resources_lists(struct acpi_device *device)
{
int i;
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index f9734fa..98cd723 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -341,6 +341,7 @@ struct acpi_device_physical_node {
struct acpi_device_data {
const union acpi_object *pointer;
const union acpi_object *properties;
+ const union acpi_object *of_compatible;
};
/* Device */
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 18c1bc3..11aa6b8 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -424,12 +424,8 @@ extern int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *),
const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids,
const struct device *dev);
-static inline bool acpi_driver_match_device(struct device *dev,
- const struct device_driver *drv)
-{
- return !!acpi_match_device(drv->acpi_match_table, dev);
-}
-
+extern bool acpi_driver_match_device(struct device *dev,
+ const struct device_driver *drv);
int acpi_device_uevent_modalias(struct device *, struct kobj_uevent_env *);
int acpi_device_modalias(struct device *, char *, int);
--
1.9.3
Rafael J. Wysocki
2014-10-07 00:14:06 UTC
Permalink
From: Mika Westerberg <***@linux.intel.com>

This document describes the data format and interfaces of ACPI device
specific properties.

Signed-off-by: Mika Westerberg <***@linux.intel.com>
Signed-off-by: Darren Hart <***@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <***@intel.com>
---
Documentation/acpi/properties.txt | 376 ++++++++++++++++++++++++++++++++++++++
1 file changed, 376 insertions(+)
create mode 100644 Documentation/acpi/properties.txt

Index: linux-pm/Documentation/acpi/properties.txt
===================================================================
--- /dev/null
+++ linux-pm/Documentation/acpi/properties.txt
@@ -0,0 +1,376 @@
+ACPI device properties
+======================
+This document describes the format and interfaces of ACPI device
+properties as specified in "Device Properties UUID For _DSD" available
+here:
+
+http://www.uefi.org/sites/default/files/resources/_DSD-device-properties-UUID.pdf
+
+1. Introduction
+---------------
+In systems that use ACPI and want to take advantage of device specific
+properties, there needs to be a standard way to return and extract
+name-value pairs for a given ACPI device.
+
+An ACPI device that wants to export its properties must implement a
+static name called _DSD that takes no arguments and returns a package of
+packages:
+
+ Name (_DSD, Package () {
+ ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ Package () {
+ Package () {"name1", <VALUE1>},
+ Package () {"name2", <VALUE2>}
+ }
+ })
+
+The UUID identifies contents of the following package. In case of ACPI
+device properties it is daffd814-6eba-4d8c-8a91-bc9bbf4aa301.
+
+In each returned package, the first item is the name and must be a string.
+The corresponding value can be a string, integer, reference, or package. If
+a package it may only contain strings, integers, and references.
+
+An example device where we might need properties is a device that uses
+GPIOs. In addition to the GpioIo/GpioInt resources the driver needs to
+know which GPIO is used for which purpose.
+
+To solve this we add the following ACPI device properties to the device:
+
+ Device (DEV0)
+ {
+ Name (_CRS, ResourceTemplate () {
+ GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
+ "\\_SB.PCI0.LPC", 0, ResourceConsumer) {0}
+ GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
+ "\\_SB.PCI0.LPC", 0, ResourceConsumer) {1}
+ ...
+ })
+
+ Name (_DSD, Package () {
+ ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ Package () {
+ Package () {"reset-gpio", {^DEV0, 0, 0, 0}},
+ Package () {"shutdown-gpio", {^DEV0, 1, 0, 0}},
+ }
+ })
+ }
+
+Now the device driver can reference the GPIOs using names instead of
+using indexes.
+
+If there is an existing Device Tree binding for a device, it is expected
+that the same bindings are used with ACPI properties, so that the driver
+dealing with the device needs only minor modifications if any.
+
+2. Formal definition of properties
+----------------------------------
+The following chapters define the currently supported properties. For
+these there exists a helper function that can be used to extract the
+property value.
+
+2.1 Integer types
+-----------------
+ACPI integers are always 64-bit. However, for drivers the full range is
+typically not needed so we provide a set of functions which convert the
+64-bit integer to a smaller Linux integer type.
+
+An integer property looks like this:
+
+ Package () {"i2c-sda-hold-time-ns", 300},
+ Package () {"clock-frequency", 400000},
+
+To read a property value, use a unified property accessor as shown
+below:
+
+ u32 val;
+ int ret;
+
+ ret = device_property_read_u32(dev, "clock-frequency", &val);
+ if (ret)
+ /* Handle error */
+
+The function returns 0 if the property is copied to 'val' or negative
+errno if something went wrong (or the property does not exist).
+
+2.2 Integer arrays
+------------------
+An integer array is a package holding only integers. Arrays can be used to
+represent different things like Linux input key codes to GPIO mappings, pin
+control settings, dma request lines, etc.
+
+An integer array looks like this:
+
+ Package () {
+ "max8952,dvs-mode-microvolt",
+ Package () {
+ 1250000,
+ 1200000,
+ 1050000,
+ 950000,
+ }
+ }
+
+The above array property can be accessed like:
+
+ u32 voltages[4];
+ int ret;
+
+ ret = device_property_read_u32_array(dev, "max8952,dvs-mode-microvolt",
+ voltages, ARRAY_SIZE(voltages));
+ if (ret)
+ /* Handle error */
+
+
+All functions copy the resulting values cast to a requested type to the
+caller supplied array. If you pass NULL in the value pointer ('voltages' in
+this case), the function returns number of items in the array. This can be
+useful if caller does not know size of the array beforehand.
+
+2.3 Strings
+-----------
+String properties can be used to describe many things like labels for GPIO
+buttons, compability ids, etc.
+
+A string property looks like this:
+
+ Package () {"name", "value"},
+ Package () {"label", "Status-LED"},
+
+You can use device_property_read_string() to extract strings:
+
+ const char *val;
+ int ret;
+
+ ret = device_property_read_string(dev, "label", &val);
+ if (ret)
+ /* Handle error */
+
+Note that the function does not copy the returned string but instead the
+value is modified to point to the string property itself.
+
+The memory is owned by the associated ACPI device object and released
+when it is removed. The user need not free the associated memory.
+
+2.4 String arrays
+-----------------
+String arrays can be useful in describing a list of labels, names for
+DMA channels, etc.
+
+A string array property looks like this:
+
+ Package () {"dma-names", Package () {"tx", "rx", "rx-tx"}},
+ Package () {"clock-output-names", Package () {"pll", "pll-switched"}},
+
+And these can be read in similar way that the integer arrrays:
+
+ const char *dma_names[3];
+ int ret;
+
+ ret = device_property_read_string_array(dev, "dma-names", dma_names,
+ ARRAY_SIZE(dma_names));
+ if (ret)
+ /* Handle error */
+
+The memory management rules follow what is specified for single strings.
+Specifically the returned pointers should be treated as constant and not to
+be freed. That is done automatically when the correspondig ACPI device
+object is released.
+
+2.5 Object references
+---------------------
+An ACPI object reference is used to refer to some object in the
+namespace. For example, if a device has dependencies with some other
+object, an object reference can be used.
+
+An object reference looks like this:
+
+ Package () {"dev0", \_SB.DEV0},
+
+At the time of writing this, there is no unified device_property_* accessor
+for references so one needs to use the following ACPI helper function:
+
+ int acpi_dev_get_property_reference(struct acpi_device *adev,
+ const char *name,
+ const char *size_prop, int index,
+ struct acpi_reference_args *args);
+
+The referenced ACPI device is returned in args->adev if found.
+
+In addition to simple object references it is also possible to have object
+references with arguments. These are represented in ASL as follows:
+
+ Device (\_SB.PCI0.PWM)
+ {
+ Name (_DSD, Package () {
+ ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ Package () {
+ Package () {"#pwm-cells", 2}
+ }
+ })
+ }
+
+ Device (\_SB.PCI0.BL)
+ {
+ Name (_DSD, Package () {
+ ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ Package () {
+ Package () {
+ "pwms",
+ Package () {
+ \_SB.PCI0.PWM, 0, 5000000,
+ \_SB.PCI0.PWM, 1, 4500000,
+ }
+ }
+ }
+ })
+ }
+
+In the above example, the referenced device declares a property that
+returns the number of expected arguments (here it is "#pwm-cells"). If
+no such property is given we assume that all the integers following the
+reference are arguments.
+
+In the above example PWM device expects 2 additional arguments. This
+will be validated by the ACPI property core.
+
+The additional arguments must be integers. Nothing else is supported.
+
+It is possible, as in the above example, to have multiple references
+with varying number of integer arguments. It is up to the referenced
+device to declare how many arguments it expects. The 'index' parameter
+selects which reference is returned.
+
+One can use acpi_dev_get_property_reference() as well to extract the
+information in additional parameters:
+
+ struct acpi_reference_args args;
+ struct acpi_device *adev = /* this will point to the BL device */
+ int ret;
+
+ /* extract the first reference */
+ acpi_dev_get_property_reference(adev, "pwms", "#pwm-cells", 0, &args);
+
+ BUG_ON(args.nargs != 2);
+ BUG_ON(args.args[0] != 0);
+ BUG_ON(args.args[1] != 5000000);
+
+ /* extract the second reference */
+ acpi_dev_get_property_reference(adev, "pwms", "#pwm-cells", 1, &args);
+
+ BUG_ON(args.nargs != 2);
+ BUG_ON(args.args[0] != 1);
+ BUG_ON(args.args[1] != 4500000);
+
+In addition to arguments, args.adev now points to the ACPI device that
+corresponds to \_SB.PCI0.PWM.
+
+It is intended that this function is not used directly but instead
+subsystems like pwm implement their ACPI support on top of this function
+in such way that it is hidden from the client drivers, such as via
+pwm_get().
+
+3. Device property hierarchies
+------------------------------
+Devices are organized in a tree within the Linux kernel. It follows that
+the configuration data would also be hierarchical. In order to reach
+equivalence with Device Tree, the ACPI mechanism must also provide some
+sort of tree-like representation. Fortunately, the ACPI namespace is
+already such a structure.
+
+For example, we could have the following device in ACPI namespace. The
+KEYS device is much like gpio_keys_polled.c in that it includes "pseudo"
+devices for each GPIO:
+
+ Device (KEYS)
+ {
+ Name (_CRS, ResourceTemplate () {
+ GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
+ "\\_SB.PCI0.LPC", 0, ResourceConsumer) {0}
+ GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
+ "\\_SB.PCI0.LPC", 0, ResourceConsumer) {1}
+ ...
+ })
+
+ // "pseudo" devices declared under the parent device
+ Device (BTN0) {
+ Name (_DSD, Package () {
+ ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ Package () {
+ Package () {"label", "minnow_btn0"}
+ Package () {"gpios", Package () {^KEYS, 0, 0, 1}}
+ }
+ })
+ }
+
+ Device (BTN1) {
+ Name (_DSD, Package () {
+ ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ Package () {
+ Package () {"label", "minnow_btn1"}
+ Package () {"gpios", Package () {^KEYS, 1, 0, 1}}
+ }
+ })
+ }
+ }
+
+We can extract the above in gpio_keys_polled.c like:
+
+ static void gpio_keys_polled_probe(struct device *dev)
+ {
+ void *child;
+
+ /* Properties for the KEYS device itself */
+ device_property_read(dev, ...);
+
+ /*
+ * Iterate over button devices and extract their
+ * firmware configuration.
+ */
+ device_for_each_child_node(dev, child) {
+ const char *label = NULL;
+
+ /*
+ * We need to use device_child_ variant here to access
+ * properties of the child.
+ */
+ device_child_property_read_string(dev, child, "label", &label);
+ /* and so on */
+ }
+ }
+
+Note that you still need proper error handling which is omitted in the
+above example.
+
+4. Existing Device Tree enabled drivers
+---------------------------------------
+At the time of writing this, there are ~250 existing DT enabled drivers.
+Allocating _HID/_CID for each would not be feasible. To make sure that
+those drivers can still be used on ACPI systems, we provide an
+alternative way to get these matched.
+
+There is a special _HID "PRP0001" which means that use the DT bindings
+for matching this device to a driver. The driver needs to have
+.of_match_table filled in even when !CONFIG_OF.
+
+An example device would be leds that can be controlled via GPIOs. This
+is represented as "leds-gpio" device and looks like this in the ACPI
+namespace:
+
+ Device (LEDS)
+ {
+ Name (_DSD, Package () {
+ ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ Package () {
+ Package () {"compatible", Package () {"gpio-leds"}},
+ }
+ })
+ ...
+ }
+
+Once ACPI core sees "PRP0001" and that the device has "compatible"
+property it will do the match using .of_match_table instead if the
+driver does not have .acpi_match_table.
+
+It is preferred that new devices get a proper _HID allocated for them
+instead of inventing new DT "compatible" devices.
Grant Likely
2014-10-13 12:41:32 UTC
Permalink
On Tue, 07 Oct 2014 02:14:06 +0200
Post by Rafael J. Wysocki
This document describes the data format and interfaces of ACPI device
specific properties.
---
Documentation/acpi/properties.txt | 376 ++++++++++++++++++++++++++++++++++++++
1 file changed, 376 insertions(+)
create mode 100644 Documentation/acpi/properties.txt
Index: linux-pm/Documentation/acpi/properties.txt
===================================================================
--- /dev/null
+++ linux-pm/Documentation/acpi/properties.txt
@@ -0,0 +1,376 @@
+ACPI device properties
+======================
+This document describes the format and interfaces of ACPI device
+properties as specified in "Device Properties UUID For _DSD" available
+
+http://www.uefi.org/sites/default/files/resources/_DSD-device-properties-UUID.pdf
+
+1. Introduction
+---------------
+In systems that use ACPI and want to take advantage of device specific
+properties, there needs to be a standard way to return and extract
+name-value pairs for a given ACPI device.
+
+An ACPI device that wants to export its properties must implement a
+static name called _DSD that takes no arguments and returns a package of
+
+ Name (_DSD, Package () {
+ ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ Package () {
+ Package () {"name1", <VALUE1>},
+ Package () {"name2", <VALUE2>}
+ }
+ })
+
+The UUID identifies contents of the following package. In case of ACPI
+device properties it is daffd814-6eba-4d8c-8a91-bc9bbf4aa301.
+
+In each returned package, the first item is the name and must be a string.
+The corresponding value can be a string, integer, reference, or package. If
+a package it may only contain strings, integers, and references.
+
+An example device where we might need properties is a device that uses
+GPIOs. In addition to the GpioIo/GpioInt resources the driver needs to
+know which GPIO is used for which purpose.
+
+
+ Device (DEV0)
+ {
+ Name (_CRS, ResourceTemplate () {
+ GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
+ "\\_SB.PCI0.LPC", 0, ResourceConsumer) {0}
+ GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
+ "\\_SB.PCI0.LPC", 0, ResourceConsumer) {1}
+ ...
+ })
+
+ Name (_DSD, Package () {
+ ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ Package () {
+ Package () {"reset-gpio", {^DEV0, 0, 0, 0}},
+ Package () {"shutdown-gpio", {^DEV0, 1, 0, 0}},
+ }
+ })
+ }
+
+Now the device driver can reference the GPIOs using names instead of
+using indexes.
Ummm... so this is kind of odd. Why would arguments be needed for the
gpio reference, or a device trying to reference itself (^DEV0) within
it's own device.

It looks like it is trying to shoehorn DT design patterns into the ACPI
tables when ACPI already has a native method for doing the same thing.
That concerns me.

[...]
Post by Rafael J. Wysocki
+In addition to simple object references it is also possible to have object
+
+ Device (\_SB.PCI0.PWM)
+ {
+ Name (_DSD, Package () {
+ ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ Package () {
+ Package () {"#pwm-cells", 2}
+ }
+ })
+ }
+
+ Device (\_SB.PCI0.BL)
+ {
+ Name (_DSD, Package () {
+ ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ Package () {
+ Package () {
+ "pwms",
+ Package () {
+ \_SB.PCI0.PWM, 0, 5000000,
+ \_SB.PCI0.PWM, 1, 4500000,
+ }
+ }
+ }
+ })
+ }
This worries me even more. #x-cells is a very devicetree oriented
pattern that looks wrong for ACPI data. I would expect PWM resources in
ACPI to look much like ACPI GPIO resources or Serial bus resources.

g.
Mika Westerberg
2014-10-14 09:42:06 UTC
Permalink
Post by Grant Likely
On Tue, 07 Oct 2014 02:14:06 +0200
Post by Rafael J. Wysocki
This document describes the data format and interfaces of ACPI device
specific properties.
---
Documentation/acpi/properties.txt | 376 ++++++++++++++++++++++++++++++++++++++
1 file changed, 376 insertions(+)
create mode 100644 Documentation/acpi/properties.txt
Index: linux-pm/Documentation/acpi/properties.txt
===================================================================
--- /dev/null
+++ linux-pm/Documentation/acpi/properties.txt
@@ -0,0 +1,376 @@
+ACPI device properties
+======================
+This document describes the format and interfaces of ACPI device
+properties as specified in "Device Properties UUID For _DSD" available
+
+http://www.uefi.org/sites/default/files/resources/_DSD-device-properties-UUID.pdf
+
+1. Introduction
+---------------
+In systems that use ACPI and want to take advantage of device specific
+properties, there needs to be a standard way to return and extract
+name-value pairs for a given ACPI device.
+
+An ACPI device that wants to export its properties must implement a
+static name called _DSD that takes no arguments and returns a package of
+
+ Name (_DSD, Package () {
+ ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ Package () {
+ Package () {"name1", <VALUE1>},
+ Package () {"name2", <VALUE2>}
+ }
+ })
+
+The UUID identifies contents of the following package. In case of ACPI
+device properties it is daffd814-6eba-4d8c-8a91-bc9bbf4aa301.
+
+In each returned package, the first item is the name and must be a string.
+The corresponding value can be a string, integer, reference, or package. If
+a package it may only contain strings, integers, and references.
+
+An example device where we might need properties is a device that uses
+GPIOs. In addition to the GpioIo/GpioInt resources the driver needs to
+know which GPIO is used for which purpose.
+
+
+ Device (DEV0)
+ {
+ Name (_CRS, ResourceTemplate () {
+ GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
+ "\\_SB.PCI0.LPC", 0, ResourceConsumer) {0}
+ GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
+ "\\_SB.PCI0.LPC", 0, ResourceConsumer) {1}
+ ...
+ })
+
+ Name (_DSD, Package () {
+ ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ Package () {
+ Package () {"reset-gpio", {^DEV0, 0, 0, 0}},
+ Package () {"shutdown-gpio", {^DEV0, 1, 0, 0}},
+ }
+ })
+ }
+
+Now the device driver can reference the GPIOs using names instead of
+using indexes.
Ummm... so this is kind of odd. Why would arguments be needed for the
gpio reference, or a device trying to reference itself (^DEV0) within
it's own device.
The reference doesn't need to be the device itself. It can be the parent
device for example.

Also arguments contain information that is not available in ACPI GpioIo
resources:

- Name of the GPIO
- Is the GPIO active low

Remember that we can write the above also like:

Name (_CRS, ResourceTemplate () {
GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
"\\_SB.PCI0.LPC", 0, ResourceConsumer) {0, 1}
...
})

Name (_DSD, Package () {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () {"reset-gpio", {^DEV0, 0, 0, 0}},
Package () {"shutdown-gpio", {^DEV0, 0, 1, 0}},
}
})

So the first two integers are used as indexes in _CRS and in the
pinlist.
Post by Grant Likely
It looks like it is trying to shoehorn DT design patterns into the ACPI
tables when ACPI already has a native method for doing the same thing.
That concerns me.
There is no native method in ACPI to do what we are doing.
Post by Grant Likely
[...]
Post by Rafael J. Wysocki
+In addition to simple object references it is also possible to have object
+
+ Device (\_SB.PCI0.PWM)
+ {
+ Name (_DSD, Package () {
+ ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ Package () {
+ Package () {"#pwm-cells", 2}
+ }
+ })
+ }
+
+ Device (\_SB.PCI0.BL)
+ {
+ Name (_DSD, Package () {
+ ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ Package () {
+ Package () {
+ "pwms",
+ Package () {
+ \_SB.PCI0.PWM, 0, 5000000,
+ \_SB.PCI0.PWM, 1, 4500000,
+ }
+ }
+ }
+ })
+ }
This worries me even more. #x-cells is a very devicetree oriented
pattern that looks wrong for ACPI data. I would expect PWM resources in
ACPI to look much like ACPI GPIO resources or Serial bus resources.
This was already discussed in v3 version of the series and our argument
here is that we should be able to reuse the existing DT schemas as much
as possible as long as ACPI does not have a native method to describe
the thing (and it makes sense in general).

However, nothing prevents us to extend the
acpi_dev_get_property_reference() in future to support a more ACPI style
way of doing things:

http://www.spinics.net/lists/linux-acpi/msg53367.html
Rafael J. Wysocki
2014-10-07 00:15:18 UTC
Permalink
From: Mika Westerberg <***@linux.intel.com>

With release of ACPI 5.1 and _DSD method we can finally name GPIOs (and
other things as well) returned by _CRS. Previously we were only able to
use integer index to find the corresponding GPIO, which is pretty error
prone if the order changes.

With _DSD we can now query GPIOs using name instead of an integer index,
like the below example shows:

// Bluetooth device with reset and shutdown GPIOs
Device (BTH)
{
Name (_HID, ...)

Name (_CRS, ResourceTemplate ()
{
GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
"\\_SB.GPO0", 0, ResourceConsumer) {15}
GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
"\\_SB.GPO0", 0, ResourceConsumer) {27, 31}
})

Name (_DSD, Package ()
{
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package ()
{
Package () {"reset-gpio", Package() {^BTH, 1, 1, 0 }},
Package () {"shutdown-gpio", Package() {^BTH, 0, 0, 0 }},
}
})
}

The format of the supported GPIO property is:

Package () { "name", Package () { ref, index, pin, active_low }}

ref - The device that has _CRS containing GpioIo()/GpioInt() resources,
typically this is the device itself (BTH in our case).
index - Index of the GpioIo()/GpioInt() resource in _CRS starting from zero.
pin - Pin in the GpioIo()/GpioInt() resource. Typically this is zero.
active_low - If 1 the GPIO is marked as active_low.

Since ACPI GpioIo() resource does not have field saying whether it is
active low or high, the "active_low" argument can be used here. Setting
it to 1 marks the GPIO as active low.

In our Bluetooth example the "reset-gpio" refers to the second GpioIo()
resource, second pin in that resource with the GPIO number of 31.

This patch implements necessary support to gpiolib for extracting GPIOs
using _DSD device properties.

Signed-off-by: Mika Westerberg <***@linux.intel.com>
Acked-by: Linus Walleij <***@linaro.org>
Signed-off-by: Rafael J. Wysocki <***@intel.com>
---
drivers/gpio/gpiolib-acpi.c | 78 +++++++++++++++++++++++++++++++++++++--------
drivers/gpio/gpiolib.c | 30 ++++++++++++++---
drivers/gpio/gpiolib.h | 7 ++--
3 files changed, 94 insertions(+), 21 deletions(-)

diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index 687476f..b14c045 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -293,6 +293,7 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip)
struct acpi_gpio_lookup {
struct acpi_gpio_info info;
int index;
+ int pin_index;
struct gpio_desc *desc;
int n;
};
@@ -306,13 +307,24 @@ static int acpi_find_gpio(struct acpi_resource *ares, void *data)

if (lookup->n++ == lookup->index && !lookup->desc) {
const struct acpi_resource_gpio *agpio = &ares->data.gpio;
+ int pin_index = lookup->pin_index;
+
+ if (pin_index >= agpio->pin_table_length)
+ return 1;

lookup->desc = acpi_get_gpiod(agpio->resource_source.string_ptr,
- agpio->pin_table[0]);
+ agpio->pin_table[pin_index]);
lookup->info.gpioint =
agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT;
- lookup->info.active_low =
- agpio->polarity == ACPI_ACTIVE_LOW;
+
+ /*
+ * ActiveLow is only specified for GpioInt resource. If
+ * GpioIo is used then the only way to set the flag is
+ * to use _DSD "gpios" property.
+ */
+ if (lookup->info.gpioint)
+ lookup->info.active_low =
+ agpio->polarity == ACPI_ACTIVE_LOW;
}

return 1;
@@ -320,40 +332,75 @@ static int acpi_find_gpio(struct acpi_resource *ares, void *data)

/**
* acpi_get_gpiod_by_index() - get a GPIO descriptor from device resources
- * @dev: pointer to a device to get GPIO from
+ * @adev: pointer to a ACPI device to get GPIO from
+ * @propname: Property name of the GPIO (optional)
* @index: index of GpioIo/GpioInt resource (starting from %0)
* @info: info pointer to fill in (optional)
*
- * Function goes through ACPI resources for @dev and based on @index looks
+ * Function goes through ACPI resources for @adev and based on @index looks
* up a GpioIo/GpioInt resource, translates it to the Linux GPIO descriptor,
* and returns it. @index matches GpioIo/GpioInt resources only so if there
* are total %3 GPIO resources, the index goes from %0 to %2.
*
+ * If @propname is specified the GPIO is looked using device property. In
+ * that case @index is used to select the GPIO entry in the property value
+ * (in case of multiple).
+ *
* If the GPIO cannot be translated or there is an error an ERR_PTR is
* returned.
*
* Note: if the GPIO resource has multiple entries in the pin list, this
* function only returns the first.
*/
-struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index,
+struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
+ const char *propname, int index,
struct acpi_gpio_info *info)
{
struct acpi_gpio_lookup lookup;
struct list_head resource_list;
- struct acpi_device *adev;
- acpi_handle handle;
+ bool active_low = false;
int ret;

- if (!dev)
- return ERR_PTR(-EINVAL);
-
- handle = ACPI_HANDLE(dev);
- if (!handle || acpi_bus_get_device(handle, &adev))
+ if (!adev)
return ERR_PTR(-ENODEV);

memset(&lookup, 0, sizeof(lookup));
lookup.index = index;

+ if (propname) {
+ struct acpi_reference_args args;
+
+ dev_dbg(&adev->dev, "GPIO: looking up %s\n", propname);
+
+ memset(&args, 0, sizeof(args));
+ ret = acpi_dev_get_property_reference(adev, propname, NULL,
+ index, &args);
+ if (ret)
+ return ERR_PTR(ret);
+
+ /*
+ * The property was found and resolved so need to
+ * lookup the GPIO based on returned args instead.
+ */
+ adev = args.adev;
+ if (args.nargs >= 2) {
+ lookup.index = args.args[0];
+ lookup.pin_index = args.args[1];
+ /*
+ * 3rd argument, if present is used to
+ * specify active_low.
+ */
+ if (args.nargs >= 3)
+ active_low = !!args.args[2];
+ }
+
+ dev_dbg(&adev->dev, "GPIO: _DSD returned %s %zd %llu %llu %llu\n",
+ dev_name(&adev->dev), args.nargs,
+ args.args[0], args.args[1], args.args[2]);
+ } else {
+ dev_dbg(&adev->dev, "GPIO: looking up %d in _CRS\n", index);
+ }
+
INIT_LIST_HEAD(&resource_list);
ret = acpi_dev_get_resources(adev, &resource_list, acpi_find_gpio,
&lookup);
@@ -362,8 +409,11 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index,

acpi_dev_free_resource_list(&resource_list);

- if (lookup.desc && info)
+ if (lookup.desc && info) {
*info = lookup.info;
+ if (active_low)
+ info->active_low = active_low;
+ }

return lookup.desc ? lookup.desc : ERR_PTR(-ENOENT);
}
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index c68d037..4c86601 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1487,14 +1487,36 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id,
unsigned int idx,
enum gpio_lookup_flags *flags)
{
+ static const char * const suffixes[] = { "gpios", "gpio" };
+ struct acpi_device *adev = ACPI_COMPANION(dev);
struct acpi_gpio_info info;
struct gpio_desc *desc;
+ char propname[32];
+ int i;

- desc = acpi_get_gpiod_by_index(dev, idx, &info);
- if (IS_ERR(desc))
- return desc;
+ /* Try first from _DSD */
+ for (i = 0; i < ARRAY_SIZE(suffixes); i++) {
+ if (con_id && strcmp(con_id, "gpios")) {
+ snprintf(propname, sizeof(propname), "%s-%s",
+ con_id, suffixes[i]);
+ } else {
+ snprintf(propname, sizeof(propname), "%s",
+ suffixes[i]);
+ }
+
+ desc = acpi_get_gpiod_by_index(adev, propname, 0, &info);
+ if (!IS_ERR(desc) || (PTR_ERR(desc) == -EPROBE_DEFER))
+ break;
+ }
+
+ /* Then from plain _CRS GPIOs */
+ if (IS_ERR(desc)) {
+ desc = acpi_get_gpiod_by_index(adev, NULL, idx, &info);
+ if (IS_ERR(desc))
+ return desc;
+ }

- if (info.gpioint && info.active_low)
+ if (info.active_low)
*flags |= GPIO_ACTIVE_LOW;

return desc;
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index 9db2b6a..e3a5211 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -34,7 +34,8 @@ void acpi_gpiochip_remove(struct gpio_chip *chip);
void acpi_gpiochip_request_interrupts(struct gpio_chip *chip);
void acpi_gpiochip_free_interrupts(struct gpio_chip *chip);

-struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index,
+struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
+ const char *propname, int index,
struct acpi_gpio_info *info);
#else
static inline void acpi_gpiochip_add(struct gpio_chip *chip) { }
@@ -47,8 +48,8 @@ static inline void
acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { }

static inline struct gpio_desc *
-acpi_get_gpiod_by_index(struct device *dev, int index,
- struct acpi_gpio_info *info)
+acpi_get_gpiod_by_index(struct acpi_device *adev, const char *propname,
+ int index, struct acpi_gpio_info *info)
{
return ERR_PTR(-ENOSYS);
}
--
1.9.3
Grant Likely
2014-10-14 13:44:03 UTC
Permalink
On Tue, 07 Oct 2014 02:15:18 +0200
Post by Rafael J. Wysocki
With release of ACPI 5.1 and _DSD method we can finally name GPIOs (and
other things as well) returned by _CRS. Previously we were only able to
use integer index to find the corresponding GPIO, which is pretty error
prone if the order changes.
With _DSD we can now query GPIOs using name instead of an integer index,
// Bluetooth device with reset and shutdown GPIOs
Device (BTH)
{
Name (_HID, ...)
Name (_CRS, ResourceTemplate ()
{
GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
"\\_SB.GPO0", 0, ResourceConsumer) {15}
GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
"\\_SB.GPO0", 0, ResourceConsumer) {27, 31}
})
Name (_DSD, Package ()
{
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package ()
{
Package () {"reset-gpio", Package() {^BTH, 1, 1, 0 }},
Package () {"shutdown-gpio", Package() {^BTH, 0, 0, 0 }},
}
})
}
Package () { "name", Package () { ref, index, pin, active_low }}
ref - The device that has _CRS containing GpioIo()/GpioInt() resources,
typically this is the device itself (BTH in our case).
index - Index of the GpioIo()/GpioInt() resource in _CRS starting from zero.
pin - Pin in the GpioIo()/GpioInt() resource. Typically this is zero.
active_low - If 1 the GPIO is marked as active_low.
Since ACPI GpioIo() resource does not have field saying whether it is
active low or high, the "active_low" argument can be used here. Setting
it to 1 marks the GPIO as active low.
In our Bluetooth example the "reset-gpio" refers to the second GpioIo()
resource, second pin in that resource with the GPIO number of 31.
This patch implements necessary support to gpiolib for extracting GPIOs
using _DSD device properties.
Patch looks good, but please put the above description into
/Documentation until we've got a better place to document extra bindings.

g.
Post by Rafael J. Wysocki
---
drivers/gpio/gpiolib-acpi.c | 78 +++++++++++++++++++++++++++++++++++++--------
drivers/gpio/gpiolib.c | 30 ++++++++++++++---
drivers/gpio/gpiolib.h | 7 ++--
3 files changed, 94 insertions(+), 21 deletions(-)
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index 687476f..b14c045 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -293,6 +293,7 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip)
struct acpi_gpio_lookup {
struct acpi_gpio_info info;
int index;
+ int pin_index;
struct gpio_desc *desc;
int n;
};
@@ -306,13 +307,24 @@ static int acpi_find_gpio(struct acpi_resource *ares, void *data)
if (lookup->n++ == lookup->index && !lookup->desc) {
const struct acpi_resource_gpio *agpio = &ares->data.gpio;
+ int pin_index = lookup->pin_index;
+
+ if (pin_index >= agpio->pin_table_length)
+ return 1;
lookup->desc = acpi_get_gpiod(agpio->resource_source.string_ptr,
- agpio->pin_table[0]);
+ agpio->pin_table[pin_index]);
lookup->info.gpioint =
agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT;
- lookup->info.active_low =
- agpio->polarity == ACPI_ACTIVE_LOW;
+
+ /*
+ * ActiveLow is only specified for GpioInt resource. If
+ * GpioIo is used then the only way to set the flag is
+ * to use _DSD "gpios" property.
+ */
+ if (lookup->info.gpioint)
+ lookup->info.active_low =
+ agpio->polarity == ACPI_ACTIVE_LOW;
}
return 1;
@@ -320,40 +332,75 @@ static int acpi_find_gpio(struct acpi_resource *ares, void *data)
/**
* acpi_get_gpiod_by_index() - get a GPIO descriptor from device resources
*
* up a GpioIo/GpioInt resource, translates it to the Linux GPIO descriptor,
* are total %3 GPIO resources, the index goes from %0 to %2.
*
+ * (in case of multiple).
+ *
* If the GPIO cannot be translated or there is an error an ERR_PTR is
* returned.
*
* Note: if the GPIO resource has multiple entries in the pin list, this
* function only returns the first.
*/
-struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index,
+struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
+ const char *propname, int index,
struct acpi_gpio_info *info)
{
struct acpi_gpio_lookup lookup;
struct list_head resource_list;
- struct acpi_device *adev;
- acpi_handle handle;
+ bool active_low = false;
int ret;
- if (!dev)
- return ERR_PTR(-EINVAL);
-
- handle = ACPI_HANDLE(dev);
- if (!handle || acpi_bus_get_device(handle, &adev))
+ if (!adev)
return ERR_PTR(-ENODEV);
memset(&lookup, 0, sizeof(lookup));
lookup.index = index;
+ if (propname) {
+ struct acpi_reference_args args;
+
+ dev_dbg(&adev->dev, "GPIO: looking up %s\n", propname);
+
+ memset(&args, 0, sizeof(args));
+ ret = acpi_dev_get_property_reference(adev, propname, NULL,
+ index, &args);
+ if (ret)
+ return ERR_PTR(ret);
+
+ /*
+ * The property was found and resolved so need to
+ * lookup the GPIO based on returned args instead.
+ */
+ adev = args.adev;
+ if (args.nargs >= 2) {
+ lookup.index = args.args[0];
+ lookup.pin_index = args.args[1];
+ /*
+ * 3rd argument, if present is used to
+ * specify active_low.
+ */
+ if (args.nargs >= 3)
+ active_low = !!args.args[2];
+ }
+
+ dev_dbg(&adev->dev, "GPIO: _DSD returned %s %zd %llu %llu %llu\n",
+ dev_name(&adev->dev), args.nargs,
+ args.args[0], args.args[1], args.args[2]);
+ } else {
+ dev_dbg(&adev->dev, "GPIO: looking up %d in _CRS\n", index);
+ }
+
INIT_LIST_HEAD(&resource_list);
ret = acpi_dev_get_resources(adev, &resource_list, acpi_find_gpio,
&lookup);
@@ -362,8 +409,11 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index,
acpi_dev_free_resource_list(&resource_list);
- if (lookup.desc && info)
+ if (lookup.desc && info) {
*info = lookup.info;
+ if (active_low)
+ info->active_low = active_low;
+ }
return lookup.desc ? lookup.desc : ERR_PTR(-ENOENT);
}
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index c68d037..4c86601 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1487,14 +1487,36 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id,
unsigned int idx,
enum gpio_lookup_flags *flags)
{
+ static const char * const suffixes[] = { "gpios", "gpio" };
+ struct acpi_device *adev = ACPI_COMPANION(dev);
struct acpi_gpio_info info;
struct gpio_desc *desc;
+ char propname[32];
+ int i;
- desc = acpi_get_gpiod_by_index(dev, idx, &info);
- if (IS_ERR(desc))
- return desc;
+ /* Try first from _DSD */
+ for (i = 0; i < ARRAY_SIZE(suffixes); i++) {
+ if (con_id && strcmp(con_id, "gpios")) {
+ snprintf(propname, sizeof(propname), "%s-%s",
+ con_id, suffixes[i]);
+ } else {
+ snprintf(propname, sizeof(propname), "%s",
+ suffixes[i]);
+ }
+
+ desc = acpi_get_gpiod_by_index(adev, propname, 0, &info);
+ if (!IS_ERR(desc) || (PTR_ERR(desc) == -EPROBE_DEFER))
+ break;
+ }
+
+ /* Then from plain _CRS GPIOs */
+ if (IS_ERR(desc)) {
+ desc = acpi_get_gpiod_by_index(adev, NULL, idx, &info);
+ if (IS_ERR(desc))
+ return desc;
+ }
- if (info.gpioint && info.active_low)
+ if (info.active_low)
*flags |= GPIO_ACTIVE_LOW;
return desc;
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index 9db2b6a..e3a5211 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -34,7 +34,8 @@ void acpi_gpiochip_remove(struct gpio_chip *chip);
void acpi_gpiochip_request_interrupts(struct gpio_chip *chip);
void acpi_gpiochip_free_interrupts(struct gpio_chip *chip);
-struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index,
+struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
+ const char *propname, int index,
struct acpi_gpio_info *info);
#else
static inline void acpi_gpiochip_add(struct gpio_chip *chip) { }
@@ -47,8 +48,8 @@ static inline void
acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { }
static inline struct gpio_desc *
-acpi_get_gpiod_by_index(struct device *dev, int index,
- struct acpi_gpio_info *info)
+acpi_get_gpiod_by_index(struct acpi_device *adev, const char *propname,
+ int index, struct acpi_gpio_info *info)
{
return ERR_PTR(-ENOSYS);
}
--
1.9.3
Mika Westerberg
2014-10-15 08:46:20 UTC
Permalink
Post by Grant Likely
On Tue, 07 Oct 2014 02:15:18 +0200
Post by Rafael J. Wysocki
With release of ACPI 5.1 and _DSD method we can finally name GPIOs (and
other things as well) returned by _CRS. Previously we were only able to
use integer index to find the corresponding GPIO, which is pretty error
prone if the order changes.
With _DSD we can now query GPIOs using name instead of an integer index,
// Bluetooth device with reset and shutdown GPIOs
Device (BTH)
{
Name (_HID, ...)
Name (_CRS, ResourceTemplate ()
{
GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
"\\_SB.GPO0", 0, ResourceConsumer) {15}
GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
"\\_SB.GPO0", 0, ResourceConsumer) {27, 31}
})
Name (_DSD, Package ()
{
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package ()
{
Package () {"reset-gpio", Package() {^BTH, 1, 1, 0 }},
Package () {"shutdown-gpio", Package() {^BTH, 0, 0, 0 }},
}
})
}
Package () { "name", Package () { ref, index, pin, active_low }}
ref - The device that has _CRS containing GpioIo()/GpioInt() resources,
typically this is the device itself (BTH in our case).
index - Index of the GpioIo()/GpioInt() resource in _CRS starting from zero.
pin - Pin in the GpioIo()/GpioInt() resource. Typically this is zero.
active_low - If 1 the GPIO is marked as active_low.
Since ACPI GpioIo() resource does not have field saying whether it is
active low or high, the "active_low" argument can be used here. Setting
it to 1 marks the GPIO as active low.
In our Bluetooth example the "reset-gpio" refers to the second GpioIo()
resource, second pin in that resource with the GPIO number of 31.
This patch implements necessary support to gpiolib for extracting GPIOs
using _DSD device properties.
Patch looks good, but please put the above description into
/Documentation until we've got a better place to document extra bindings.
Thanks for the review.

If you don't mind, I would like to make a separate patch on top of this
series adding this description to Documentation/acpi/properties.txt.
Rafael J. Wysocki
2014-10-07 00:15:48 UTC
Permalink
From: Mika Westerberg <***@linux.intel.com>

This is actually a single device with two sets of identical registers,
which just happen to start from a different offset. Instead of having
separate GPIO chips created we consolidate them to be single GPIO chip.

In addition having a single GPIO chip allows us to handle ACPI GPIO
translation in the core in a more generic way, since the two GPIO chips
share the same parent ACPI device.

Signed-off-by: Mika Westerberg <***@linux.intel.com>
Acked-by: Linus Walleij <***@linaro.org>
Signed-off-by: Rafael J. Wysocki <***@intel.com>
---
drivers/gpio/gpio-sch.c | 293 ++++++++++++++++++------------------------------
1 file changed, 112 insertions(+), 181 deletions(-)

diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c
index 41e91d7..99720c8 100644
--- a/drivers/gpio/gpio-sch.c
+++ b/drivers/gpio/gpio-sch.c
@@ -29,290 +29,221 @@

#include <linux/gpio.h>

-static DEFINE_SPINLOCK(gpio_lock);
-
-#define CGEN (0x00)
-#define CGIO (0x04)
-#define CGLV (0x08)
-
-#define RGEN (0x20)
-#define RGIO (0x24)
-#define RGLV (0x28)
-
-static unsigned short gpio_ba;
-
-static int sch_gpio_core_direction_in(struct gpio_chip *gc, unsigned gpio_num)
-{
- u8 curr_dirs;
- unsigned short offset, bit;
-
- spin_lock(&gpio_lock);
-
- offset = CGIO + gpio_num / 8;
- bit = gpio_num % 8;
-
- curr_dirs = inb(gpio_ba + offset);
-
- if (!(curr_dirs & (1 << bit)))
- outb(curr_dirs | (1 << bit), gpio_ba + offset);
+#define GEN 0x00
+#define GIO 0x04
+#define GLV 0x08
+
+struct sch_gpio {
+ struct gpio_chip chip;
+ spinlock_t lock;
+ unsigned short iobase;
+ unsigned short core_base;
+ unsigned short resume_base;
+};

- spin_unlock(&gpio_lock);
- return 0;
-}
+#define to_sch_gpio(c) container_of(c, struct sch_gpio, chip)

-static int sch_gpio_core_get(struct gpio_chip *gc, unsigned gpio_num)
+static unsigned sch_gpio_offset(struct sch_gpio *sch, unsigned gpio,
+ unsigned reg)
{
- int res;
- unsigned short offset, bit;
+ unsigned base = 0;

- offset = CGLV + gpio_num / 8;
- bit = gpio_num % 8;
+ if (gpio >= sch->resume_base) {
+ gpio -= sch->resume_base;
+ base += 0x20;
+ }

- res = !!(inb(gpio_ba + offset) & (1 << bit));
- return res;
+ return base + reg + gpio / 8;
}

-static void sch_gpio_core_set(struct gpio_chip *gc, unsigned gpio_num, int val)
+static unsigned sch_gpio_bit(struct sch_gpio *sch, unsigned gpio)
{
- u8 curr_vals;
- unsigned short offset, bit;
-
- spin_lock(&gpio_lock);
-
- offset = CGLV + gpio_num / 8;
- bit = gpio_num % 8;
-
- curr_vals = inb(gpio_ba + offset);
-
- if (val)
- outb(curr_vals | (1 << bit), gpio_ba + offset);
- else
- outb((curr_vals & ~(1 << bit)), gpio_ba + offset);
- spin_unlock(&gpio_lock);
+ if (gpio >= sch->resume_base)
+ gpio -= sch->resume_base;
+ return gpio % 8;
}

-static int sch_gpio_core_direction_out(struct gpio_chip *gc,
- unsigned gpio_num, int val)
+static void sch_gpio_enable(struct sch_gpio *sch, unsigned gpio)
{
- u8 curr_dirs;
unsigned short offset, bit;
+ u8 enable;

- spin_lock(&gpio_lock);
+ spin_lock(&sch->lock);

- offset = CGIO + gpio_num / 8;
- bit = gpio_num % 8;
-
- curr_dirs = inb(gpio_ba + offset);
- if (curr_dirs & (1 << bit))
- outb(curr_dirs & ~(1 << bit), gpio_ba + offset);
+ offset = sch_gpio_offset(sch, gpio, GEN);
+ bit = sch_gpio_bit(sch, gpio);

- spin_unlock(&gpio_lock);
+ enable = inb(sch->iobase + offset);
+ if (!(enable & (1 << bit)))
+ outb(enable | (1 << bit), sch->iobase + offset);

- /*
- * according to the datasheet, writing to the level register has no
- * effect when GPIO is programmed as input.
- * Actually the the level register is read-only when configured as input.
- * Thus presetting the output level before switching to output is _NOT_ possible.
- * Hence we set the level after configuring the GPIO as output.
- * But we cannot prevent a short low pulse if direction is set to high
- * and an external pull-up is connected.
- */
- sch_gpio_core_set(gc, gpio_num, val);
- return 0;
+ spin_unlock(&sch->lock);
}

-static struct gpio_chip sch_gpio_core = {
- .label = "sch_gpio_core",
- .owner = THIS_MODULE,
- .direction_input = sch_gpio_core_direction_in,
- .get = sch_gpio_core_get,
- .direction_output = sch_gpio_core_direction_out,
- .set = sch_gpio_core_set,
-};
-
-static int sch_gpio_resume_direction_in(struct gpio_chip *gc,
- unsigned gpio_num)
+static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned gpio_num)
{
+ struct sch_gpio *sch = to_sch_gpio(gc);
u8 curr_dirs;
unsigned short offset, bit;

- spin_lock(&gpio_lock);
+ spin_lock(&sch->lock);

- offset = RGIO + gpio_num / 8;
- bit = gpio_num % 8;
+ offset = sch_gpio_offset(sch, gpio_num, GIO);
+ bit = sch_gpio_bit(sch, gpio_num);

- curr_dirs = inb(gpio_ba + offset);
+ curr_dirs = inb(sch->iobase + offset);

if (!(curr_dirs & (1 << bit)))
- outb(curr_dirs | (1 << bit), gpio_ba + offset);
+ outb(curr_dirs | (1 << bit), sch->iobase + offset);

- spin_unlock(&gpio_lock);
+ spin_unlock(&sch->lock);
return 0;
}

-static int sch_gpio_resume_get(struct gpio_chip *gc, unsigned gpio_num)
+static int sch_gpio_get(struct gpio_chip *gc, unsigned gpio_num)
{
+ struct sch_gpio *sch = to_sch_gpio(gc);
+ int res;
unsigned short offset, bit;

- offset = RGLV + gpio_num / 8;
- bit = gpio_num % 8;
+ offset = sch_gpio_offset(sch, gpio_num, GLV);
+ bit = sch_gpio_bit(sch, gpio_num);
+
+ res = !!(inb(sch->iobase + offset) & (1 << bit));

- return !!(inb(gpio_ba + offset) & (1 << bit));
+ return res;
}

-static void sch_gpio_resume_set(struct gpio_chip *gc,
- unsigned gpio_num, int val)
+static void sch_gpio_set(struct gpio_chip *gc, unsigned gpio_num, int val)
{
+ struct sch_gpio *sch = to_sch_gpio(gc);
u8 curr_vals;
unsigned short offset, bit;

- spin_lock(&gpio_lock);
+ spin_lock(&sch->lock);

- offset = RGLV + gpio_num / 8;
- bit = gpio_num % 8;
+ offset = sch_gpio_offset(sch, gpio_num, GLV);
+ bit = sch_gpio_bit(sch, gpio_num);

- curr_vals = inb(gpio_ba + offset);
+ curr_vals = inb(sch->iobase + offset);

if (val)
- outb(curr_vals | (1 << bit), gpio_ba + offset);
+ outb(curr_vals | (1 << bit), sch->iobase + offset);
else
- outb((curr_vals & ~(1 << bit)), gpio_ba + offset);
+ outb((curr_vals & ~(1 << bit)), sch->iobase + offset);

- spin_unlock(&gpio_lock);
+ spin_unlock(&sch->lock);
}

-static int sch_gpio_resume_direction_out(struct gpio_chip *gc,
- unsigned gpio_num, int val)
+static int sch_gpio_direction_out(struct gpio_chip *gc, unsigned gpio_num,
+ int val)
{
+ struct sch_gpio *sch = to_sch_gpio(gc);
u8 curr_dirs;
unsigned short offset, bit;

- offset = RGIO + gpio_num / 8;
- bit = gpio_num % 8;
+ spin_lock(&sch->lock);

- spin_lock(&gpio_lock);
+ offset = sch_gpio_offset(sch, gpio_num, GIO);
+ bit = sch_gpio_bit(sch, gpio_num);

- curr_dirs = inb(gpio_ba + offset);
+ curr_dirs = inb(sch->iobase + offset);
if (curr_dirs & (1 << bit))
- outb(curr_dirs & ~(1 << bit), gpio_ba + offset);
+ outb(curr_dirs & ~(1 << bit), sch->iobase + offset);

- spin_unlock(&gpio_lock);
+ spin_unlock(&sch->lock);

/*
- * according to the datasheet, writing to the level register has no
- * effect when GPIO is programmed as input.
- * Actually the the level register is read-only when configured as input.
- * Thus presetting the output level before switching to output is _NOT_ possible.
- * Hence we set the level after configuring the GPIO as output.
- * But we cannot prevent a short low pulse if direction is set to high
- * and an external pull-up is connected.
- */
- sch_gpio_resume_set(gc, gpio_num, val);
+ * according to the datasheet, writing to the level register has no
+ * effect when GPIO is programmed as input.
+ * Actually the the level register is read-only when configured as input.
+ * Thus presetting the output level before switching to output is _NOT_ possible.
+ * Hence we set the level after configuring the GPIO as output.
+ * But we cannot prevent a short low pulse if direction is set to high
+ * and an external pull-up is connected.
+ */
+ sch_gpio_set(gc, gpio_num, val);
return 0;
}

-static struct gpio_chip sch_gpio_resume = {
- .label = "sch_gpio_resume",
+static struct gpio_chip sch_gpio_chip = {
+ .label = "sch_gpio",
.owner = THIS_MODULE,
- .direction_input = sch_gpio_resume_direction_in,
- .get = sch_gpio_resume_get,
- .direction_output = sch_gpio_resume_direction_out,
- .set = sch_gpio_resume_set,
+ .direction_input = sch_gpio_direction_in,
+ .get = sch_gpio_get,
+ .direction_output = sch_gpio_direction_out,
+ .set = sch_gpio_set,
};

static int sch_gpio_probe(struct platform_device *pdev)
{
+ struct sch_gpio *sch;
struct resource *res;
- int err, id;

- id = pdev->id;
- if (!id)
- return -ENODEV;
+ sch = devm_kzalloc(&pdev->dev, sizeof(*sch), GFP_KERNEL);
+ if (!sch)
+ return -ENOMEM;

res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (!res)
return -EBUSY;

- if (!request_region(res->start, resource_size(res), pdev->name))
+ if (!devm_request_region(&pdev->dev, res->start, resource_size(res),
+ pdev->name))
return -EBUSY;

- gpio_ba = res->start;
+ spin_lock_init(&sch->lock);
+ sch->iobase = res->start;
+ sch->chip = sch_gpio_chip;
+ sch->chip.label = dev_name(&pdev->dev);
+ sch->chip.dev = &pdev->dev;

- switch (id) {
+ switch (pdev->id) {
case PCI_DEVICE_ID_INTEL_SCH_LPC:
- sch_gpio_core.base = 0;
- sch_gpio_core.ngpio = 10;
- sch_gpio_resume.base = 10;
- sch_gpio_resume.ngpio = 4;
+ sch->core_base = 0;
+ sch->resume_base = 10;
+ sch->chip.ngpio = 14;
+
/*
* GPIO[6:0] enabled by default
* GPIO7 is configured by the CMC as SLPIOVR
* Enable GPIO[9:8] core powered gpios explicitly
*/
- outb(0x3, gpio_ba + CGEN + 1);
+ sch_gpio_enable(sch, 8);
+ sch_gpio_enable(sch, 9);
/*
* SUS_GPIO[2:0] enabled by default
* Enable SUS_GPIO3 resume powered gpio explicitly
*/
- outb(0x8, gpio_ba + RGEN);
+ sch_gpio_enable(sch, 13);
break;

case PCI_DEVICE_ID_INTEL_ITC_LPC:
- sch_gpio_core.base = 0;
- sch_gpio_core.ngpio = 5;
- sch_gpio_resume.base = 5;
- sch_gpio_resume.ngpio = 9;
+ sch->core_base = 0;
+ sch->resume_base = 5;
+ sch->chip.ngpio = 14;
break;

case PCI_DEVICE_ID_INTEL_CENTERTON_ILB:
- sch_gpio_core.base = 0;
- sch_gpio_core.ngpio = 21;
- sch_gpio_resume.base = 21;
- sch_gpio_resume.ngpio = 9;
+ sch->core_base = 0;
+ sch->resume_base = 21;
+ sch->chip.ngpio = 30;
break;

default:
- err = -ENODEV;
- goto err_sch_gpio_core;
+ return -ENODEV;
}

- sch_gpio_core.dev = &pdev->dev;
- sch_gpio_resume.dev = &pdev->dev;
-
- err = gpiochip_add(&sch_gpio_core);
- if (err < 0)
- goto err_sch_gpio_core;
+ platform_set_drvdata(pdev, sch);

- err = gpiochip_add(&sch_gpio_resume);
- if (err < 0)
- goto err_sch_gpio_resume;
-
- return 0;
-
-err_sch_gpio_resume:
- gpiochip_remove(&sch_gpio_core);
-
-err_sch_gpio_core:
- release_region(res->start, resource_size(res));
- gpio_ba = 0;
-
- return err;
+ return gpiochip_add(&sch->chip);
}

static int sch_gpio_remove(struct platform_device *pdev)
{
- struct resource *res;
- if (gpio_ba) {
-
- gpiochip_remove(&sch_gpio_core);
- gpiochip_remove(&sch_gpio_resume);
-
- res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-
- release_region(res->start, resource_size(res));
- gpio_ba = 0;
- }
+ struct sch_gpio *sch = platform_get_drvdata(pdev);

+ gpiochip_remove(&sch->chip);
return 0;
}
--
1.9.3
Rafael J. Wysocki
2014-10-07 00:16:14 UTC
Permalink
From: Mika Westerberg <***@linux.intel.com>

GPIO descriptors are the preferred way over legacy GPIO numbers
nowadays. Convert the driver to use GPIO descriptors internally but
still allow passing legacy GPIO numbers from platform data to support
existing platforms.

Signed-off-by: Mika Westerberg <***@linux.intel.com>
Acked-by: Alexandre Courbot <***@nvidia.com>
Acked-by: Bryan Wu <***@gmail.com>
Signed-off-by: Rafael J. Wysocki <***@intel.com>
---
drivers/leds/leds-gpio.c | 80 +++++++++++++++++++++++++++---------------------
include/linux/leds.h | 1 +
2 files changed, 46 insertions(+), 35 deletions(-)

diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index 57ff20f..c84e913 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/leds.h>
#include <linux/of.h>
#include <linux/of_platform.h>
@@ -24,11 +25,10 @@

struct gpio_led_data {
struct led_classdev cdev;
- unsigned gpio;
+ struct gpio_desc *gpiod;
struct work_struct work;
u8 new_level;
u8 can_sleep;
- u8 active_low;
u8 blinking;
int (*platform_gpio_blink_set)(unsigned gpio, int state,
unsigned long *delay_on, unsigned long *delay_off);
@@ -40,12 +40,16 @@ static void gpio_led_work(struct work_struct *work)
container_of(work, struct gpio_led_data, work);

if (led_dat->blinking) {
- led_dat->platform_gpio_blink_set(led_dat->gpio,
- led_dat->new_level,
- NULL, NULL);
+ int gpio = desc_to_gpio(led_dat->gpiod);
+ int level = led_dat->new_level;
+
+ if (gpiod_is_active_low(led_dat->gpiod))
+ level = !level;
+
+ led_dat->platform_gpio_blink_set(gpio, level, NULL, NULL);
led_dat->blinking = 0;
} else
- gpio_set_value_cansleep(led_dat->gpio, led_dat->new_level);
+ gpiod_set_value_cansleep(led_dat->gpiod, led_dat->new_level);
}

static void gpio_led_set(struct led_classdev *led_cdev,
@@ -60,9 +64,6 @@ static void gpio_led_set(struct led_classdev *led_cdev,
else
level = 1;

- if (led_dat->active_low)
- level = !level;
-
/* Setting GPIOs with I2C/etc requires a task context, and we don't
* seem to have a reliable way to know if we're already in one; so
* let's just assume the worst.
@@ -72,11 +73,16 @@ static void gpio_led_set(struct led_classdev *led_cdev,
schedule_work(&led_dat->work);
} else {
if (led_dat->blinking) {
- led_dat->platform_gpio_blink_set(led_dat->gpio, level,
- NULL, NULL);
+ int gpio = desc_to_gpio(led_dat->gpiod);
+
+ if (gpiod_is_active_low(led_dat->gpiod))
+ level = !level;
+
+ led_dat->platform_gpio_blink_set(gpio, level, NULL,
+ NULL);
led_dat->blinking = 0;
} else
- gpio_set_value(led_dat->gpio, level);
+ gpiod_set_value(led_dat->gpiod, level);
}
}

@@ -85,9 +91,10 @@ static int gpio_blink_set(struct led_classdev *led_cdev,
{
struct gpio_led_data *led_dat =
container_of(led_cdev, struct gpio_led_data, cdev);
+ int gpio = desc_to_gpio(led_dat->gpiod);

led_dat->blinking = 1;
- return led_dat->platform_gpio_blink_set(led_dat->gpio, GPIO_LED_BLINK,
+ return led_dat->platform_gpio_blink_set(gpio, GPIO_LED_BLINK,
delay_on, delay_off);
}

@@ -97,24 +104,33 @@ static int create_gpio_led(const struct gpio_led *template,
{
int ret, state;

- led_dat->gpio = -1;
+ if (!template->gpiod) {
+ unsigned long flags = 0;

- /* skip leds that aren't available */
- if (!gpio_is_valid(template->gpio)) {
- dev_info(parent, "Skipping unavailable LED gpio %d (%s)\n",
- template->gpio, template->name);
- return 0;
- }
+ /* skip leds that aren't available */
+ if (!gpio_is_valid(template->gpio)) {
+ dev_info(parent, "Skipping unavailable LED gpio %d (%s)\n",
+ template->gpio, template->name);
+ return 0;
+ }

- ret = devm_gpio_request(parent, template->gpio, template->name);
- if (ret < 0)
- return ret;
+ if (template->active_low)
+ flags |= GPIOF_ACTIVE_LOW;
+
+ ret = devm_gpio_request_one(parent, template->gpio, flags,
+ template->name);
+ if (ret < 0)
+ return ret;
+
+ led_dat->gpiod = gpio_to_desc(template->gpio);
+ if (IS_ERR(led_dat->gpiod))
+ return PTR_ERR(led_dat->gpiod);
+ }

led_dat->cdev.name = template->name;
led_dat->cdev.default_trigger = template->default_trigger;
- led_dat->gpio = template->gpio;
- led_dat->can_sleep = gpio_cansleep(template->gpio);
- led_dat->active_low = template->active_low;
+ led_dat->gpiod = template->gpiod;
+ led_dat->can_sleep = gpiod_cansleep(template->gpiod);
led_dat->blinking = 0;
if (blink_set) {
led_dat->platform_gpio_blink_set = blink_set;
@@ -122,30 +138,24 @@ static int create_gpio_led(const struct gpio_led *template,
}
led_dat->cdev.brightness_set = gpio_led_set;
if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP)
- state = !!gpio_get_value_cansleep(led_dat->gpio) ^ led_dat->active_low;
+ state = !!gpiod_get_value_cansleep(led_dat->gpiod);
else
state = (template->default_state == LEDS_GPIO_DEFSTATE_ON);
led_dat->cdev.brightness = state ? LED_FULL : LED_OFF;
if (!template->retain_state_suspended)
led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;

- ret = gpio_direction_output(led_dat->gpio, led_dat->active_low ^ state);
+ ret = gpiod_direction_output(led_dat->gpiod, state);
if (ret < 0)
return ret;

INIT_WORK(&led_dat->work, gpio_led_work);

- ret = led_classdev_register(parent, &led_dat->cdev);
- if (ret < 0)
- return ret;
-
- return 0;
+ return led_classdev_register(parent, &led_dat->cdev);
}

static void delete_gpio_led(struct gpio_led_data *led)
{
- if (!gpio_is_valid(led->gpio))
- return;
led_classdev_unregister(&led->cdev);
cancel_work_sync(&led->work);
}
diff --git a/include/linux/leds.h b/include/linux/leds.h
index e436864..879a113 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -246,6 +246,7 @@ struct led_platform_data {
struct gpio_led {
const char *name;
const char *default_trigger;
+ struct gpio_desc *gpiod;
unsigned gpio;
unsigned active_low : 1;
unsigned retain_state_suspended : 1;
--
1.9.3
Rafael J. Wysocki
2014-10-07 00:17:17 UTC
Permalink
From: Rafael J. Wysocki <***@intel.com>

Add new generic routines for retrieving properties from device
description objects in the platform firmware in case a device driver
needs/wants to access properties of a child object of a given device
object. There are cases in which there is no struct device
representation of such child objects and this additional API is useful
then. Three functions are provided, device_get_child_property(),
device_read_child_property(), device_read_child_property_array(), in
analogy with device_get_property(), device_read_property() and
device_read_property_array() introduced earlier, respectively, along
with static inline wrappers for all of the propery data types that can
be used. For all of them, the first argument is a struct device
pointer to the parent device object and the second argument is a
(void *) pointer to the child description provided by the platform
firmware (either ACPI or FDT).

Additionally, provided are a new macro device_for_each_child_node()
for iterating over the children of the device description object
associated with a given device and a new function
device_get_child_node_count() returning the number of a given
device's child nodes.

The interface covers both ACPI and Device Trees.

This change set includes material from Mika Westerberg.

Signed-off-by: Mika Westerberg <***@linux.intel.com>
Acked-by: Greg Kroah-Hartman <***@linuxfoundation.org>
Signed-off-by: Rafael J. Wysocki <***@intel.com>
---
drivers/acpi/scan.c | 20 ++++++
drivers/base/property.c | 148 +++++++++++++++++++++++++++++++++++++++++++++++
include/linux/acpi.h | 9 ++
include/linux/property.h | 108 ++++++++++++++++++++++++++++++++++
4 files changed, 285 insertions(+)

Index: linux-pm/include/linux/property.h
===================================================================
--- linux-pm.orig/include/linux/property.h
+++ linux-pm/include/linux/property.h
@@ -34,6 +34,21 @@ int device_read_property_array(struct de
enum dev_prop_type proptype, void *val,
size_t nval);

+int device_get_child_property(struct device *dev, void *child,
+ const char *propname, void **valptr);
+int device_read_child_property(struct device *dev, void *child,
+ const char *propname,
+ enum dev_prop_type proptype, void *val);
+int device_read_child_property_array(struct device *dev, void *child,
+ const char *propname,
+ enum dev_prop_type proptype, void *val,
+ size_t nval);
+
+void *device_get_next_child_node(struct device *dev, void *child);
+void device_put_child_node(struct device *dev, void *child);
+
+unsigned int device_get_child_node_count(struct device *dev);
+
static inline int device_property_read_u8(struct device *dev,
const char *propname, u8 *out_value)
{
@@ -105,4 +120,97 @@ static inline int device_property_read_s
return device_read_property_array(dev, propname, DEV_PROP_STRING,
out_strings, nstrings);
}
+
+static inline int device_child_property_read_u8(struct device *dev, void *child,
+ const char *propname,
+ u8 *out_value)
+{
+ return device_read_child_property(dev, child, propname, DEV_PROP_U8,
+ out_value);
+}
+
+static inline int device_child_property_read_u16(struct device *dev, void *child,
+ const char *propname,
+ u16 *out_value)
+{
+ return device_read_child_property(dev, child, propname, DEV_PROP_U16,
+ out_value);
+}
+
+static inline int device_child_property_read_u32(struct device *dev, void *child,
+ const char *propname,
+ u32 *out_value)
+{
+ return device_read_child_property(dev, child, propname, DEV_PROP_U32,
+ out_value);
+}
+
+static inline int device_child_property_read_u64(struct device *dev, void *child,
+ const char *propname,
+ u64 *out_value)
+{
+ return device_read_child_property(dev, child, propname, DEV_PROP_U64,
+ out_value);
+}
+
+static inline int device_child_property_read_u8_array(struct device *dev,
+ void *child,
+ const char *propname,
+ u8 *val, size_t nval)
+{
+ return device_read_child_property_array(dev, child, propname,
+ DEV_PROP_U8, val, nval);
+}
+
+static inline int device_child_property_read_u16_array(struct device *dev,
+ void *child,
+ const char *propname,
+ u16 *val, size_t nval)
+{
+ return device_read_child_property_array(dev, child, propname,
+ DEV_PROP_U16, val, nval);
+}
+
+static inline int device_child_property_read_u32_array(struct device *dev,
+ void *child,
+ const char *propname,
+ u32 *val, size_t nval)
+{
+ return device_read_child_property_array(dev, child, propname,
+ DEV_PROP_U32, val, nval);
+}
+
+static inline int device_child_property_read_u64_array(struct device *dev,
+ void *child,
+ const char *propname,
+ u64 *val, size_t nval)
+{
+ return device_read_child_property_array(dev, child, propname,
+ DEV_PROP_U64, val, nval);
+}
+
+static inline int device_child_property_read_string(struct device *dev,
+ void *child,
+ const char *propname,
+ const char **out_string)
+{
+ return device_read_child_property(dev, child, propname, DEV_PROP_STRING,
+ out_string);
+}
+
+static inline int device_child_property_read_string_array(struct device *dev,
+ void *child,
+ const char *propname,
+ const char **out_strings,
+ size_t nstrings)
+{
+ return device_read_child_property_array(dev, child, propname,
+ DEV_PROP_STRING,
+ out_strings, nstrings);
+}
+
+#define device_for_each_child_node(dev, child) \
+ for (child = device_get_next_child_node(dev, NULL); child; \
+ child = device_get_next_child_node(dev, child))
+
#endif /* _LINUX_PROPERTY_H_ */
Index: linux-pm/drivers/base/property.c
===================================================================
--- linux-pm.orig/drivers/base/property.c
+++ linux-pm/drivers/base/property.c
@@ -95,3 +95,151 @@ int device_read_property_array(struct de
val, nval);
}
EXPORT_SYMBOL_GPL(device_read_property_array);
+
+/**
+ * device_get_child_property - return a raw property of a device's child
+ * @dev: Parent device
+ * @child: Child to get a property of
+ * @propname: Name of the property
+ * @valptr: The raw property value is stored here
+ *
+ * Function reads property @propname from the firmware description of @child and
+ * stores the raw value into @valptr if found. Otherwise returns a negative
+ * errno as specified below.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not exist.
+ */
+int device_get_child_property(struct device *dev, void *child,
+ const char *propname, void **valptr)
+{
+ if (!child)
+ return -EINVAL;
+
+ if (IS_ENABLED(CONFIG_OF) && dev->of_node)
+ return of_dev_prop_get(child, propname, valptr);
+ else if (ACPI_COMPANION(dev))
+ return acpi_dev_prop_get(child, propname, valptr);
+
+ return -ENODATA;
+}
+EXPORT_SYMBOL_GPL(device_get_child_property);
+
+/**
+ * device_read_child_property - read a typed property of a device's child
+ * @dev: Parent device
+ * @child: Child to read a property of
+ * @propname: Name of the property
+ * @proptype: Type of the property
+ * @val: The value is stored here
+ *
+ * Function reads property @propname from the firmware description of @child and
+ * stores the value into @val if found. The value is checked to be of type
+ * @proptype.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not exist,
+ * %-EPROTO if the property type does not match @proptype,
+ * %-EOVERFLOW if the property value is out of bounds of @proptype.
+ */
+int device_read_child_property(struct device *dev, void *child,
+ const char *propname, enum dev_prop_type proptype,
+ void *val)
+{
+ if (!child)
+ return -EINVAL;
+
+ if (IS_ENABLED(CONFIG_OF) && dev->of_node)
+ return of_dev_prop_read(child, propname, proptype, val);
+ else if (ACPI_COMPANION(dev))
+ return acpi_dev_prop_read(child, propname, proptype, val);
+
+ return -ENODATA;
+}
+EXPORT_SYMBOL_GPL(device_read_child_property);
+
+/**
+ * device_read_child_property_array - read an array property of a device's child
+ * @dev: Parent device
+ * @child: Child to get the property of
+ * @propname: Name of the property
+ * @proptype: Type of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Function reads an array of properties with @propname from the firmware
+ * description of @child and stores them to @val if found. All the values
+ * in the array must be of type @proptype.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not exist,
+ * %-EPROTO if the property type does not match @proptype,
+ * %-EOVERFLOW if the property value is out of bounds of @proptype.
+ */
+int device_read_child_property_array(struct device *dev, void *child,
+ const char *propname,
+ enum dev_prop_type proptype, void *val,
+ size_t nval)
+{
+ if (!child)
+ return -EINVAL;
+
+ if (IS_ENABLED(CONFIG_OF) && dev->of_node)
+ return of_dev_prop_read_array(child, propname, proptype,
+ val, nval);
+ else if (ACPI_COMPANION(dev))
+ return acpi_dev_prop_read_array(child, propname, proptype,
+ val, nval);
+
+ return -ENODATA;
+}
+EXPORT_SYMBOL_GPL(device_read_child_property_array);
+
+/**
+ * device_get_next_child_node - Return the next child node pointer for a device
+ * @dev: Device to find the next child node for.
+ * @child: Pointer to one of the device's child nodes or NULL.
+ */
+void *device_get_next_child_node(struct device *dev, void *child)
+{
+ if (IS_ENABLED(CONFIG_OF) && dev->of_node)
+ return of_get_next_available_child(dev->of_node, child);
+
+ return acpi_get_next_child(dev, child);
+}
+EXPORT_SYMBOL_GPL(device_get_next_child_node);
+
+/**
+ * device_put_child_node - Drop reference to a device child node
+ * @dev: Parent device.
+ * @child: Pointer to the child to drop the reference to.
+ *
+ * This has to be used when terminating device_for_each_child_node() iteration
+ * with break or return to prevent stale device node references from being left
+ * behind.
+ */
+void device_put_child_node(struct device *dev, void *child)
+{
+ if (IS_ENABLED(CONFIG_OF) && dev->of_node)
+ of_node_put(child);
+}
+EXPORT_SYMBOL_GPL(device_put_child_node);
+
+/**
+ * device_get_child_node_count - return the number of child nodes for device
+ * @dev: Device to cound the child nodes for
+ */
+unsigned int device_get_child_node_count(struct device *dev)
+{
+ unsigned int count = 0;
+ void *child = NULL;
+
+ device_for_each_child_node(dev, child)
+ count++;
+
+ return count;
+}
+EXPORT_SYMBOL_GPL(device_get_child_node_count);
Index: linux-pm/include/linux/acpi.h
===================================================================
--- linux-pm.orig/include/linux/acpi.h
+++ linux-pm/include/linux/acpi.h
@@ -681,6 +681,9 @@ int acpi_dev_prop_read(struct acpi_devic
int acpi_dev_prop_read_array(struct acpi_device *adev, const char *propname,
enum dev_prop_type proptype, void *val,
size_t nval);
+
+struct acpi_device *acpi_get_next_child(struct device *dev,
+ struct acpi_device *child);
#else
static inline int acpi_dev_get_property(struct acpi_device *adev,
const char *name, acpi_object_type type,
@@ -723,6 +726,12 @@ static inline int acpi_dev_prop_read_arr
{
return -ENXIO;
}
+
+static inline struct acpi_device *acpi_get_next_child(struct device *dev,
+ struct acpi_device *child)
+{
+ return NULL;
+}
#endif

#endif /*_LINUX_ACPI_H*/
Index: linux-pm/drivers/acpi/scan.c
===================================================================
--- linux-pm.orig/drivers/acpi/scan.c
+++ linux-pm/drivers/acpi/scan.c
@@ -1342,6 +1342,26 @@ int acpi_device_add(struct acpi_device *
return result;
}

+struct acpi_device *acpi_get_next_child(struct device *dev,
+ struct acpi_device *child)
+{
+ struct acpi_device *adev = ACPI_COMPANION(dev);
+ struct list_head *head, *next;
+
+ if (!adev)
+ return NULL;
+
+ head = &adev->children;
+ if (list_empty(head))
+ return NULL;
+
+ if (!child)
+ return list_first_entry(head, struct acpi_device, node);
+
+ next = child->node.next;
+ return next == head ? NULL : list_entry(next, struct acpi_device, node);
+}
+
/* --------------------------------------------------------------------------
Driver Management
-------------------------------------------------------------------------- */
Rafael J. Wysocki
2014-10-07 00:39:14 UTC
Permalink
Hi Everyone,
This is version 4 of the unified device properties interface patchset.
http://marc.info/?l=devicetree&m=141087052200600&w=4
http://marc.info/?l=linux-acpi&m=141212903816560&w=4
One major change from the previous iteration is that now we will
use the "compatible" property to match drivers to devices having
"PRP0001" as their _HID, so for example the at25 driver doesn't
have to add the extra ACPI match table as part of the conversion
to the unified interface (patch [05/13] in this series).
The second major change is that I've split the driver core patch
in two, where the first one ([02/13]) does not contain any stuff
related to iterating over the child nodes of a given device.
Accordingly, the whole patch series has been rearranged so that
the relatively non-controversial patches [01-09/13], most of which
have been ACKed already, go first and then goes the second driver
core patch ([10/13]) and the other patches related to it.
In patches [10-13/13] I used the Arnd's suggestion to implement
device_for_each_child_node() as a macro which makes the changes
in patches [12-13/13] look more straightforward among other things.
I've retained the Greg's ACKs on patches [02/13] and [10/13], because
the first of them is things ACKed by Greg only and the change in the
second one is just an implementation detail in my opinion (Greg, please
let me know if that's inappropriate).
I should have mentioned that the whole series is available in the
device-properties branch of the linux-pm.git tree at kernel.org.
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Greg Kroah-Hartman
2014-10-07 02:28:55 UTC
Permalink
Hi Everyone,
This is version 4 of the unified device properties interface patchset.
http://marc.info/?l=devicetree&m=141087052200600&w=4
http://marc.info/?l=linux-acpi&m=141212903816560&w=4
One major change from the previous iteration is that now we will
use the "compatible" property to match drivers to devices having
"PRP0001" as their _HID, so for example the at25 driver doesn't
have to add the extra ACPI match table as part of the conversion
to the unified interface (patch [05/13] in this series).
The second major change is that I've split the driver core patch
in two, where the first one ([02/13]) does not contain any stuff
related to iterating over the child nodes of a given device.
Accordingly, the whole patch series has been rearranged so that
the relatively non-controversial patches [01-09/13], most of which
have been ACKed already, go first and then goes the second driver
core patch ([10/13]) and the other patches related to it.
In patches [10-13/13] I used the Arnd's suggestion to implement
device_for_each_child_node() as a macro which makes the changes
in patches [12-13/13] look more straightforward among other things.
I've retained the Greg's ACKs on patches [02/13] and [10/13], because
the first of them is things ACKed by Greg only and the change in the
second one is just an implementation detail in my opinion (Greg, please
let me know if that's inappropriate).
No objection from me, looks good.

greg k-h
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Dmitry Torokhov
2014-10-07 17:30:06 UTC
Permalink
Post by Rafael J. Wysocki
Make use of device property API in this driver so that both OF based
system and ACPI based system can use this driver.
---
drivers/input/keyboard/gpio_keys_polled.c | 81 +++++++++++-------------------
1 file changed, 31 insertions(+), 50 deletions(-)
Index: linux-pm/drivers/input/keyboard/gpio_keys_polled.c
===================================================================
--- linux-pm.orig/drivers/input/keyboard/gpio_keys_polled.c
+++ linux-pm/drivers/input/keyboard/gpio_keys_polled.c
@@ -25,9 +25,7 @@
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio_keys.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/of_gpio.h>
+#include <linux/property.h>
#define DRV_NAME "gpio-keys-polled"
@@ -102,21 +100,15 @@ static void gpio_keys_polled_close(struc
pdata->disable(bdev->dev);
}
-#ifdef CONFIG_OF
static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct device *dev)
{
- struct device_node *node, *pp;
struct gpio_keys_platform_data *pdata;
struct gpio_keys_button *button;
+ void *child;
int error;
int nbuttons;
- int i;
-
- node = dev->of_node;
- if (!node)
- return NULL;
- nbuttons = of_get_child_count(node);
+ nbuttons = device_get_child_node_count(dev);
if (nbuttons == 0)
return NULL;
@@ -126,52 +118,50 @@ static struct gpio_keys_platform_data *g
return ERR_PTR(-ENOMEM);
pdata->buttons = (struct gpio_keys_button *)(pdata + 1);
- pdata->nbuttons = nbuttons;
- pdata->rep = !!of_get_property(node, "autorepeat", NULL);
- of_property_read_u32(node, "poll-interval", &pdata->poll_interval);
+ pdata->rep = !device_get_property(dev, "autorepeat", NULL);
+ device_property_read_u32(dev, "poll-interval", &pdata->poll_interval);
- i = 0;
- for_each_child_of_node(node, pp) {
- int gpio;
- enum of_gpio_flags flags;
-
- if (!of_find_property(pp, "gpios", NULL)) {
- pdata->nbuttons--;
- dev_warn(dev, "Found button without gpios\n");
- continue;
- }
+ device_for_each_child_node(dev, child) {
+ struct gpio_desc *desc;
- gpio = of_get_gpio_flags(pp, 0, &flags);
- if (gpio < 0) {
- error = gpio;
+ desc = devm_get_named_gpiod_from_child(dev, child, "gpios", 0);
+ if (IS_ERR(desc)) {
+ error = PTR_ERR(desc);
if (error != -EPROBE_DEFER)
dev_err(dev,
"Failed to get gpio flags, error: %d\n",
error);
+ device_put_child_node(dev, child);
return ERR_PTR(error);
}
- button = &pdata->buttons[i++];
-
- button->gpio = gpio;
- button->active_low = flags & OF_GPIO_ACTIVE_LOW;
+ button = &pdata->buttons[pdata->nbuttons++];
+ button->gpiod = desc;
- if (of_property_read_u32(pp, "linux,code", &button->code)) {
- dev_err(dev, "Button without keycode: 0x%x\n",
- button->gpio);
+ if (device_child_property_read_u32(dev, child, "linux,code",
+ &button->code)) {
+ dev_err(dev, "Button without keycode: %d\n",
+ pdata->nbuttons - 1);
+ device_put_child_node(dev, child);
return ERR_PTR(-EINVAL);
}
- button->desc = of_get_property(pp, "label", NULL);
+ device_child_property_read_string(dev, child, "label",
+ &button->desc);
- if (of_property_read_u32(pp, "linux,input-type", &button->type))
+ if (device_child_property_read_u32(dev, child,
+ "linux,input-type",
+ &button->type))
button->type = EV_KEY;
- button->wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL);
-
- if (of_property_read_u32(pp, "debounce-interval",
- &button->debounce_interval))
+ button->wakeup = !device_get_child_property(dev, child,
+ "gpio-key,wakeup",
+ NULL);
+
+ if (device_child_property_read_u32(dev, child,
+ "debounce-interval",
+ &button->debounce_interval))
button->debounce_interval = 5;
}
@@ -187,15 +177,6 @@ static const struct of_device_id gpio_ke
};
MODULE_DEVICE_TABLE(of, gpio_keys_polled_of_match);
-#else
-
-static inline struct gpio_keys_platform_data *
-gpio_keys_polled_get_devtree_pdata(struct device *dev)
-{
- return NULL;
-}
-#endif
-
static int gpio_keys_polled_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -323,7 +304,7 @@ static struct platform_driver gpio_keys_
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
- .of_match_table = of_match_ptr(gpio_keys_polled_of_match),
+ .of_match_table = gpio_keys_polled_of_match,
},
};
module_platform_driver(gpio_keys_polled_driver);
--
Dmitry
David Woodhouse
2014-10-15 13:04:31 UTC
Permalink
Here's a completely untested patch to convert of_serial to be usable via
ACPI properties too. The properties themselves were fairly
straightforward; the interesting part is converting to
platform_get_irq() and platform_get_resource() — in the latter case
first trying IORESOURCE_MEM then IORESOURCE_IO if that fails.

Does this look sane? We'll probably want to think about renaming the
module and the config option too, but that can come after the basic
functionality.

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 26cec64..be95a4c 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1094,14 +1094,14 @@ config SERIAL_NETX_CONSOLE
you can make it the console by answering Y to this option.

config SERIAL_OF_PLATFORM
- tristate "Serial port on Open Firmware platform bus"
- depends on OF
+ tristate "Serial port on firmware platform bus"
+ depends on OF || ACPI
depends on SERIAL_8250 || SERIAL_OF_PLATFORM_NWPSERIAL
help
- If you have a PowerPC based system that has serial ports
- on a platform specific bus, you should enable this option.
- Currently, only 8250 compatible ports are supported, but
- others can easily be added.
+ If you have a system which advertises its serial ports through
+ devicetree or ACPI, you should enable this option. Currently
+ only 8250 compatible and NWP ports and are supported, but others
+ can easily be added.

config SERIAL_OMAP
tristate "OMAP serial port support"
diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c
index 68d4455..73ee9af 100644
--- a/drivers/tty/serial/of_serial.c
+++ b/drivers/tty/serial/of_serial.c
@@ -57,13 +57,14 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
int type, struct uart_port *port,
struct of_serial_info *info)
{
- struct resource resource;
- struct device_node *np = ofdev->dev.of_node;
+ struct resource *resource;
u32 clk, spd, prop;
+ unsigned char iotype = UPIO_MEM;
+ u32 res_start;
int ret;

memset(port, 0, sizeof *port);
- if (of_property_read_u32(np, "clock-frequency", &clk)) {
+ if (device_property_read_u32(&ofdev->dev, "clock-frequency", &clk)) {

/* Get clk rate through clk driver if present */
info->clk = clk_get(&ofdev->dev, NULL);
@@ -77,40 +78,52 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
clk = clk_get_rate(info->clk);
}
/* If current-speed was set, then try not to change it. */
- if (of_property_read_u32(np, "current-speed", &spd) == 0)
+ if (device_property_read_u32(&ofdev->dev, "current-speed", &spd) == 0)
port->custom_divisor = clk / (16 * spd);

- ret = of_address_to_resource(np, 0, &resource);
- if (ret) {
+ resource = platform_get_resource(ofdev, IORESOURCE_MEM, 0);
+ if (!resource) {
+ resource = platform_get_resource(ofdev, IORESOURCE_IO, 0);
+ iotype = UPIO_PORT;
+ }
+ if (!resource) {
dev_warn(&ofdev->dev, "invalid address\n");
goto out;
}

spin_lock_init(&port->lock);
- port->mapbase = resource.start;
+ res_start = resource->start;

/* Check for shifted address mapping */
- if (of_property_read_u32(np, "reg-offset", &prop) == 0)
- port->mapbase += prop;
+ if (device_property_read_u32(&ofdev->dev, "reg-offset", &prop) == 0)
+ res_start += prop;
+
+ if (iotype == UPIO_PORT)
+ port->iobase = res_start;
+ else
+ port->mapbase = res_start;

/* Check for registers offset within the devices address range */
- if (of_property_read_u32(np, "reg-shift", &prop) == 0)
+ if (device_property_read_u32(&ofdev->dev, "reg-shift", &prop) == 0)
port->regshift = prop;

/* Check for fifo size */
- if (of_property_read_u32(np, "fifo-size", &prop) == 0)
+ if (device_property_read_u32(&ofdev->dev, "fifo-size", &prop) == 0)
port->fifosize = prop;

- port->irq = irq_of_parse_and_map(np, 0);
- port->iotype = UPIO_MEM;
- if (of_property_read_u32(np, "reg-io-width", &prop) == 0) {
+ port->irq = platform_get_irq(ofdev, 0);
+ port->iotype = iotype;
+ if (device_property_read_u32(&ofdev->dev, "reg-io-width", &prop) == 0) {
switch (prop) {
case 1:
- port->iotype = UPIO_MEM;
+ port->iotype = iotype;
break;
case 4:
- port->iotype = UPIO_MEM32;
- break;
+ if (iotype == UPIO_MEM) {
+ port->iotype = UPIO_MEM32;
+ break;
+ }
+ /* Fall through for non-memory */
default:
dev_warn(&ofdev->dev, "unsupported reg-io-width (%d)\n",
prop);
@@ -124,7 +137,7 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP
| UPF_FIXED_PORT | UPF_FIXED_TYPE;

- if (of_find_property(np, "no-loopback-test", NULL))
+ if (!device_get_property(&ofdev->dev, "no-loopback-test", NULL))
port->flags |= UPF_SKIP_TEST;

port->dev = &ofdev->dev;
@@ -155,7 +168,7 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
if (!match)
return -EINVAL;

- if (of_find_property(ofdev->dev.of_node, "used-by-rtas", NULL))
+ if (!device_get_property(&ofdev->dev, "used-by-rtas", NULL))
return -EBUSY;

info = kmalloc(sizeof(*info), GFP_KERNEL);
@@ -179,12 +192,10 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
if (port.fifosize)
port8250.capabilities = UART_CAP_FIFO;

- if (of_property_read_bool(ofdev->dev.of_node,
- "auto-flow-control"))
+ if (!device_get_property(&ofdev->dev, "auto-flow-control", NULL))
port8250.capabilities |= UART_CAP_AFE;

- if (of_property_read_bool(ofdev->dev.of_node,
- "has-hw-flow-control"))
+ if (!device_get_property(&ofdev->dev, "has-hw-flow-control", NULL))
port8250.port.flags |= UPF_HARD_FLOW;

ret = serial8250_register_8250_port(&port8250);
--
dwmw2
Mark Rutland
2014-10-15 13:15:51 UTC
Permalink
Here's a completely untested patch to convert of_serial to be usable =
via
ACPI properties too. The properties themselves were fairly
straightforward; the interesting part is converting to
platform_get_irq() and platform_get_resource() =E2=80=94 in the latte=
r case
first trying IORESOURCE_MEM then IORESOURCE_IO if that fails.
=20
Does this look sane? We'll probably want to think about renaming the
module and the config option too, but that can come after the basic
functionality.
The majority of these properties look like they constrained to the
device in question, so make sense for _DSD too.

However...
@@ -155,7 +168,7 @@ static int of_platform_serial_probe(struct platfo=
rm_device *ofdev)
if (!match)
return -EINVAL;
=20
- if (of_find_property(ofdev->dev.of_node, "used-by-rtas", NULL))
+ if (!device_get_property(&ofdev->dev, "used-by-rtas", NULL))
return -EBUSY;
This property should never be present on an ACPI system. RTAS is a
completely different firmware interface on PowerPC.

As a general note, I would hope that we're not going to blindly convert
drivers and subsystems over to a common property interface without
considering each property w.r.t. the particular FW interface.=20

Each addition to _DSD, especially if through a common accessor needs
_more_ scrutiny than is applied to DT bindings, and we hardly manage to
review DT bindings.

Mark.
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" i=
n
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
David Woodhouse
2014-10-15 13:28:56 UTC
Permalink
Post by Mark Rutland
Post by David Woodhouse
@@ -155,7 +168,7 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
if (!match)
return -EINVAL;
- if (of_find_property(ofdev->dev.of_node, "used-by-rtas", NULL))
+ if (!device_get_property(&ofdev->dev, "used-by-rtas", NULL))
return -EBUSY;
This property should never be present on an ACPI system. RTAS is a
completely different firmware interface on PowerPC.
Yes, I sincerely hope we never see used-by-rtas being set on a non-PPC
system. But this isn't a new consideration; we were already checking for
'used-by-rtas' on *all* platforms. Perhaps we shouldn't be. But that's
almost orthogonal to the issue at hand.
Post by Mark Rutland
As a general note, I would hope that we're not going to blindly convert
drivers and subsystems over to a common property interface without
considering each property w.r.t. the particular FW interface.
Each addition to _DSD, especially if through a common accessor needs
_more_ scrutiny than is applied to DT bindings, and we hardly manage to
review DT bindings.
The whole point here is to use existing bindings rather than having to
reinvent the wheel. Sure, where the existing binding really makes no
sense for certain subsystems, we should come up with something
different.

But in the general case for 'leaf-node' peripherals we would hope that
we don't really have to change *anything* other than to make sure the
driver is using generic property accessor functions instead of the old
OF-specific ones. The point here is *consistency*. We really don't want
to make a habit of reinventing different bindings to be exposed through
the different firmware types.
--
David Woodhouse Open Source Technology Centre
***@intel.com Intel Corporation
Mark Rutland
2014-10-15 13:42:09 UTC
Permalink
Post by David Woodhouse
Post by Mark Rutland
Post by David Woodhouse
@@ -155,7 +168,7 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
if (!match)
return -EINVAL;
- if (of_find_property(ofdev->dev.of_node, "used-by-rtas", NULL))
+ if (!device_get_property(&ofdev->dev, "used-by-rtas", NULL))
return -EBUSY;
This property should never be present on an ACPI system. RTAS is a
completely different firmware interface on PowerPC.
Yes, I sincerely hope we never see used-by-rtas being set on a non-PPC
system. But this isn't a new consideration; we were already checking for
'used-by-rtas' on *all* platforms. Perhaps we shouldn't be. But that's
almost orthogonal to the issue at hand.
We have been checking for all DT platforms, and that's a bug for DT.
Copying that bug to ACPI is inexcusable given we know it's a bug to do
so.

No-one is using ACPI+RTAS, so there is no reason to enable this property
for ACPI. The only reason anyone would (mis)use this property with ACPI
is because Linux happened to support that combination, which need not be
the case because it doesn't make any sense.
Post by David Woodhouse
Post by Mark Rutland
As a general note, I would hope that we're not going to blindly convert
drivers and subsystems over to a common property interface without
considering each property w.r.t. the particular FW interface.
Each addition to _DSD, especially if through a common accessor needs
_more_ scrutiny than is applied to DT bindings, and we hardly manage to
review DT bindings.
The whole point here is to use existing bindings rather than having to
reinvent the wheel. Sure, where the existing binding really makes no
sense for certain subsystems, we should come up with something
different.
I understand that. However, where a binding doesn't make sense (as in
this case), it shouldn't be enabled for ACPI as it provides a larger
surface area for misuse, for no benefit.
Post by David Woodhouse
But in the general case for 'leaf-node' peripherals we would hope that
we don't really have to change *anything* other than to make sure the
driver is using generic property accessor functions instead of the old
OF-specific ones. The point here is *consistency*. We really don't want
to make a habit of reinventing different bindings to be exposed through
the different firmware types.
Where we have a property of a leaf-node that is independent of the
description format, sure. I am not asking us to re-invent bindings, but
we must consider the differences between ACPI and DT systems when trying
to port a DT binding to ACPI.

My concern here is that we don't have the mechanisms in place for
sufficient scrutiny to be applied when bindings are ported over. We
_will_ end up porting over things that don't make sense (as this patch
shows), and some of those are likely to cause unnecessary pain for
everyone. It does not make sense to say that is OK.

Mark.
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Darren Hart
2014-10-15 14:46:39 UTC
Permalink
Post by Mark Rutland
We have been checking for all DT platforms, and that's a bug for DT.
Copying that bug to ACPI is inexcusable given we know it's a bug to do
so.
We'll, perhaps it should be named 'used-by-firmware' and actually it's
just as valid under ACPI as it is on RTAS systems. All it does is stop the
OS from using the port.
Post by Mark Rutland
I understand that. However, where a binding doesn't make sense (as in
this case), it shouldn't be enabled for ACPI as it provides a larger
surface area for misuse, for no benefit.
These are *optional* properties. They were optional precisely *because*
they only make sense in some cases. I don't know that it makes sense to
take them away. The benefit we get is *consistency*. For example if
someone *does* use the property in question as 'used-by-firmware' and
expects the OS not to touch it, we don't want that to change behaviour
between ACPI and fdt boots.
My comment was going to be along the same lines. It is an optional
parameter, which is what I would expect for a firmware-specific type of
property.

I also don't agree that this is "copying that bug to ACPI". This line of
code has no impact to ACPI. No ACPI implementation should add this,
certainly not if it was actually tested as it would not run if it was
present in the _DSD. So... what's the problem exactly? Or perhaps more
specifically:

Mark, what would you propose we do differently to enable this driver to
be firmware-type agnostic?
--
Darren Hart
Intel Open Source Technology Center
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
David Woodhouse
2014-10-15 15:11:18 UTC
Permalink
Post by Darren Hart
My comment was going to be along the same lines. It is an optional
parameter, which is what I would expect for a firmware-specific type of
property.
Right. Fundamentally, device properties (in DT or ACPI) exist to describe
the hardware in a generic and abstract fashion. It's a slippery slope from
saying "you don't need this property because you know you whether you are
on the *foo* architecture", to saying "you don't this property because you
know whether you're on a Assabet or not." I think it's wrong to go down
that path.
--
dwmw2

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Mark Rutland
2014-10-15 15:17:02 UTC
Permalink
Post by Darren Hart
Post by Mark Rutland
We have been checking for all DT platforms, and that's a bug for DT.
Copying that bug to ACPI is inexcusable given we know it's a bug to do
so.
We'll, perhaps it should be named 'used-by-firmware' and actually it's
just as valid under ACPI as it is on RTAS systems. All it does is stop the
OS from using the port.
Post by Mark Rutland
I understand that. However, where a binding doesn't make sense (as in
this case), it shouldn't be enabled for ACPI as it provides a larger
surface area for misuse, for no benefit.
These are *optional* properties. They were optional precisely *because*
they only make sense in some cases. I don't know that it makes sense to
take them away. The benefit we get is *consistency*. For example if
someone *does* use the property in question as 'used-by-firmware' and
expects the OS not to touch it, we don't want that to change behaviour
between ACPI and fdt boots.
My comment was going to be along the same lines. It is an optional
parameter, which is what I would expect for a firmware-specific type of
property.
I also don't agree that this is "copying that bug to ACPI". This line of
code has no impact to ACPI. No ACPI implementation should add this,
certainly not if it was actually tested as it would not run if it was
present in the _DSD. So... what's the problem exactly? Or perhaps more
Mark, what would you propose we do differently to enable this driver to
be firmware-type agnostic?
For this particular driver, all I'm asking for is that the
"used-by-rtas" property is not moved over from of_find_property to
device_get_property. It is irrelevant for all ACPI systems. Evidently my
comment was unclear; I apologise for that.

We have status = "disabled" as a less specific mechanism for telling the
OS to ignore a node in DT. I was under the impression that ACPI already
had a mechanism for marking devices to be ignored, but perhaps I am
mistaken.

The concerns I mentioned at the end of my original reply were of a more
general nature than this particular device description.

Thanks,
Mark.
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Darren Hart
2014-10-15 15:43:01 UTC
Permalink
Post by Mark Rutland
Post by Darren Hart
Mark, what would you propose we do differently to enable this driver to
be firmware-type agnostic?
For this particular driver, all I'm asking for is that the
"used-by-rtas" property is not moved over from of_find_property to
device_get_property. It is irrelevant for all ACPI systems. Evidently my
comment was unclear; I apologise for that.
So my objection here is that by keeping the of_* terms in the driver we
are required to include of, although it does safely convert to returning
NULL if !CONFIG_OF I suppose.
Post by Mark Rutland
We have status = "disabled" as a less specific mechanism for telling the
OS to ignore a node in DT. I was under the impression that ACPI already
had a mechanism for marking devices to be ignored, but perhaps I am
mistaken.
That is correct, in ACPI this would be properly implemented with the
_STA reserved named method. In which case it wouldn't enumerate.
Post by Mark Rutland
The concerns I mentioned at the end of my original reply were of a more
general nature than this particular device description.
Thanks,
Mark.
--
Darren Hart
Intel Open Source Technology Center
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Rafael J. Wysocki
2014-10-16 10:05:16 UTC
Permalink
Post by Darren Hart
Post by Mark Rutland
Post by Darren Hart
Mark, what would you propose we do differently to enable this driver to
be firmware-type agnostic?
For this particular driver, all I'm asking for is that the
"used-by-rtas" property is not moved over from of_find_property to
device_get_property. It is irrelevant for all ACPI systems. Evidently my
comment was unclear; I apologise for that.
So my objection here is that by keeping the of_* terms in the driver we
are required to include of, although it does safely convert to returning
NULL if !CONFIG_OF I suppose.
Agreed.
Post by Darren Hart
Post by Mark Rutland
We have status = "disabled" as a less specific mechanism for telling the
OS to ignore a node in DT. I was under the impression that ACPI already
had a mechanism for marking devices to be ignored, but perhaps I am
mistaken.
That is correct, in ACPI this would be properly implemented with the
_STA reserved named method. In which case it wouldn't enumerate.
Post by Mark Rutland
The concerns I mentioned at the end of my original reply were of a more
general nature than this particular device description.
Moreover, to me, the question really is "Does this driver need to be any
different depending on whether DT or ACPI is used by the platform and if
so, then why?".

In my opinion, there is no technical reason for such differences to be present
in this particular case. The fact that the "used-by-rtas" property does not
make sense for the ACPI case doesn't imply that the driver should not be allowed
to check it then.
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
David Woodhouse
2014-10-16 14:55:56 UTC
Permalink
Post by Darren Hart
So my objection here is that by keeping the of_* terms in the driver we
are required to include of, although it does safely convert to returning
NULL if !CONFIG_OF I suppose.
New version removes everything but the of_match_id bits which we need to
match ACPI devices too. Perhaps they ought to be renamed, but I'm not
sure it's worth it.

This also removes the call to platform_get_resource(IORESOURCE_MEM) and
fall back to platform_get_resource(IORESOURCE_IO) as discussed IRL with
Rafael. I'm not sure it's much of an improvement, mind you :)

Still untested. I think it's OK to switch to platform_get_irq() and then
drop the irq_dispose_mapping() call, right? The platform_device takes
care of all of that for us?

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 26cec64..be95a4c 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1094,14 +1094,14 @@ config SERIAL_NETX_CONSOLE
you can make it the console by answering Y to this option.

config SERIAL_OF_PLATFORM
- tristate "Serial port on Open Firmware platform bus"
- depends on OF
+ tristate "Serial port on firmware platform bus"
+ depends on OF || ACPI
depends on SERIAL_8250 || SERIAL_OF_PLATFORM_NWPSERIAL
help
- If you have a PowerPC based system that has serial ports
- on a platform specific bus, you should enable this option.
- Currently, only 8250 compatible ports are supported, but
- others can easily be added.
+ If you have a system which advertises its serial ports through
+ devicetree or ACPI, you should enable this option. Currently
+ only 8250 compatible and NWP ports and are supported, but others
+ can easily be added.

config SERIAL_OMAP
tristate "OMAP serial port support"
diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c
index 68d4455..cc6c99b 100644
--- a/drivers/tty/serial/of_serial.c
+++ b/drivers/tty/serial/of_serial.c
@@ -14,8 +14,7 @@
#include <linux/delay.h>
#include <linux/serial_core.h>
#include <linux/serial_reg.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
+#include <linux/property.h>
#include <linux/of_platform.h>
#include <linux/nwpserial.h>
#include <linux/clk.h>
@@ -53,22 +52,22 @@ static inline void tegra_serial_handle_break(struct uart_port *port)
/*
* Fill a struct uart_port for a given device node
*/
-static int of_platform_serial_setup(struct platform_device *ofdev,
+static int of_platform_serial_setup(struct platform_device *pdev,
int type, struct uart_port *port,
struct of_serial_info *info)
{
- struct resource resource;
- struct device_node *np = ofdev->dev.of_node;
u32 clk, spd, prop;
- int ret;
+ int iotype = -1;
+ u32 res_start;
+ int ret, i;

memset(port, 0, sizeof *port);
- if (of_property_read_u32(np, "clock-frequency", &clk)) {
+ if (device_property_read_u32(&pdev->dev, "clock-frequency", &clk)) {

/* Get clk rate through clk driver if present */
- info->clk = clk_get(&ofdev->dev, NULL);
+ info->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(info->clk)) {
- dev_warn(&ofdev->dev,
+ dev_warn(&pdev->dev,
"clk or clock-frequency not defined\n");
return PTR_ERR(info->clk);
}
@@ -77,57 +76,63 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
clk = clk_get_rate(info->clk);
}
/* If current-speed was set, then try not to change it. */
- if (of_property_read_u32(np, "current-speed", &spd) == 0)
+ if (device_property_read_u32(&pdev->dev, "current-speed", &spd) == 0)
port->custom_divisor = clk / (16 * spd);

- ret = of_address_to_resource(np, 0, &resource);
- if (ret) {
- dev_warn(&ofdev->dev, "invalid address\n");
+ /* Check for shifted address mapping */
+ if (device_property_read_u32(&pdev->dev, "reg-offset", &prop) != 0)
+ prop = 0;
+
+ for (i = 0; iotype == -1 && i < pdev->num_resources; i++) {
+ struct resource *resource = &pdev->resource[i];
+ if (resource_type(resource) == IORESOURCE_MEM) {
+ iotype = UPIO_MEM;
+ port->mapbase = res_start + prop;
+ } else if (resource_type(resource) == IORESOURCE_IO) {
+ iotype = UPIO_PORT;
+ port->iobase = res_start + prop;
+ }
+
+ res_start = resource->start;
+ }
+ if (iotype == -1) {
+ dev_warn(&pdev->dev, "invalid address\n");
goto out;
}

spin_lock_init(&port->lock);
- port->mapbase = resource.start;
-
- /* Check for shifted address mapping */
- if (of_property_read_u32(np, "reg-offset", &prop) == 0)
- port->mapbase += prop;

/* Check for registers offset within the devices address range */
- if (of_property_read_u32(np, "reg-shift", &prop) == 0)
+ if (device_property_read_u32(&pdev->dev, "reg-shift", &prop) == 0)
port->regshift = prop;

/* Check for fifo size */
- if (of_property_read_u32(np, "fifo-size", &prop) == 0)
+ if (device_property_read_u32(&pdev->dev, "fifo-size", &prop) == 0)
port->fifosize = prop;

- port->irq = irq_of_parse_and_map(np, 0);
- port->iotype = UPIO_MEM;
- if (of_property_read_u32(np, "reg-io-width", &prop) == 0) {
- switch (prop) {
- case 1:
- port->iotype = UPIO_MEM;
- break;
- case 4:
- port->iotype = UPIO_MEM32;
- break;
- default:
- dev_warn(&ofdev->dev, "unsupported reg-io-width (%d)\n",
+ port->irq = platform_get_irq(pdev, 0);
+
+ if (device_property_read_u32(&pdev->dev, "reg-io-width", &prop) == 0) {
+ if (prop == 4 && iotype == UPIO_MEM) {
+ iotype = UPIO_MEM32;
+ } else {
+ dev_warn(&pdev->dev, "unsupported reg-io-width (%d)\n",
prop);
ret = -EINVAL;
goto out;
}
}

+ port->iotype = iotype;
port->type = type;
port->uartclk = clk;
port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP
| UPF_FIXED_PORT | UPF_FIXED_TYPE;

- if (of_find_property(np, "no-loopback-test", NULL))
+ if (!device_get_property(&pdev->dev, "no-loopback-test", NULL))
port->flags |= UPF_SKIP_TEST;

- port->dev = &ofdev->dev;
+ port->dev = &pdev->dev;

if (type == PORT_TEGRA)
port->handle_break = tegra_serial_handle_break;
@@ -143,7 +148,7 @@ out:
* Try to register a serial port
*/
static struct of_device_id of_platform_serial_table[];
-static int of_platform_serial_probe(struct platform_device *ofdev)
+static int of_platform_serial_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
struct of_serial_info *info;
@@ -151,11 +156,11 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
int port_type;
int ret;

- match = of_match_device(of_platform_serial_table, &ofdev->dev);
+ match = of_match_device(of_platform_serial_table, &pdev->dev);
if (!match)
return -EINVAL;

- if (of_find_property(ofdev->dev.of_node, "used-by-rtas", NULL))
+ if (!device_get_property(&pdev->dev, "used-by-rtas", NULL))
return -EBUSY;

info = kmalloc(sizeof(*info), GFP_KERNEL);
@@ -163,7 +168,7 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
return -ENOMEM;

port_type = (unsigned long)match->data;
- ret = of_platform_serial_setup(ofdev, port_type, &port, info);
+ ret = of_platform_serial_setup(pdev, port_type, &port, info);
if (ret)
goto out;

@@ -179,12 +184,10 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
if (port.fifosize)
port8250.capabilities = UART_CAP_FIFO;

- if (of_property_read_bool(ofdev->dev.of_node,
- "auto-flow-control"))
+ if (!device_get_property(&pdev->dev, "auto-flow-control", NULL))
port8250.capabilities |= UART_CAP_AFE;

- if (of_property_read_bool(ofdev->dev.of_node,
- "has-hw-flow-control"))
+ if (!device_get_property(&pdev->dev, "has-hw-flow-control", NULL))
port8250.port.flags |= UPF_HARD_FLOW;

ret = serial8250_register_8250_port(&port8250);
@@ -199,7 +202,7 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
default:
/* need to add code for these */
case PORT_UNKNOWN:
- dev_info(&ofdev->dev, "Unknown serial port found, ignored\n");
+ dev_info(&pdev->dev, "Unknown serial port found, ignored\n");
ret = -ENODEV;
break;
}
@@ -208,20 +211,19 @@ static int of_platform_serial_probe(struct platform_device *ofdev)

info->type = port_type;
info->line = ret;
- platform_set_drvdata(ofdev, info);
+ platform_set_drvdata(pdev, info);
return 0;
out:
kfree(info);
- irq_dispose_mapping(port.irq);
return ret;
}

/*
* Release a line
*/
-static int of_platform_serial_remove(struct platform_device *ofdev)
+static int of_platform_serial_remove(struct platform_device *pdev)
{
- struct of_serial_info *info = platform_get_drvdata(ofdev);
+ struct of_serial_info *info = platform_get_drvdata(pdev);
switch (info->type) {
#ifdef CONFIG_SERIAL_8250
case PORT_8250 ... PORT_MAX_8250:
--
David Woodhouse Open Source Technology Centre
***@intel.com Intel Corporation
Grant Likely
2014-10-18 08:39:54 UTC
Permalink
On Thu, 16 Oct 2014 16:55:56 +0200
Post by David Woodhouse
Post by Darren Hart
So my objection here is that by keeping the of_* terms in the driver we
are required to include of, although it does safely convert to returning
NULL if !CONFIG_OF I suppose.
New version removes everything but the of_match_id bits which we need to
match ACPI devices too. Perhaps they ought to be renamed, but I'm not
sure it's worth it.
This also removes the call to platform_get_resource(IORESOURCE_MEM) and
fall back to platform_get_resource(IORESOURCE_IO) as discussed IRL with
Rafael. I'm not sure it's much of an improvement, mind you :)
Still untested. I think it's OK to switch to platform_get_irq() and then
drop the irq_dispose_mapping() call, right? The platform_device takes
care of all of that for us?
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 26cec64..be95a4c 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1094,14 +1094,14 @@ config SERIAL_NETX_CONSOLE
you can make it the console by answering Y to this option.
config SERIAL_OF_PLATFORM
- tristate "Serial port on Open Firmware platform bus"
- depends on OF
+ tristate "Serial port on firmware platform bus"
+ depends on OF || ACPI
depends on SERIAL_8250 || SERIAL_OF_PLATFORM_NWPSERIAL
help
- If you have a PowerPC based system that has serial ports
- on a platform specific bus, you should enable this option.
- Currently, only 8250 compatible ports are supported, but
- others can easily be added.
+ If you have a system which advertises its serial ports through
+ devicetree or ACPI, you should enable this option. Currently
+ only 8250 compatible and NWP ports and are supported, but others
+ can easily be added.
config SERIAL_OMAP
tristate "OMAP serial port support"
diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c
index 68d4455..cc6c99b 100644
--- a/drivers/tty/serial/of_serial.c
+++ b/drivers/tty/serial/of_serial.c
@@ -14,8 +14,7 @@
#include <linux/delay.h>
#include <linux/serial_core.h>
#include <linux/serial_reg.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
+#include <linux/property.h>
#include <linux/of_platform.h>
#include <linux/nwpserial.h>
#include <linux/clk.h>
@@ -53,22 +52,22 @@ static inline void tegra_serial_handle_break(struct uart_port *port)
/*
* Fill a struct uart_port for a given device node
*/
-static int of_platform_serial_setup(struct platform_device *ofdev,
+static int of_platform_serial_setup(struct platform_device *pdev,
int type, struct uart_port *port,
struct of_serial_info *info)
{
- struct resource resource;
- struct device_node *np = ofdev->dev.of_node;
u32 clk, spd, prop;
- int ret;
+ int iotype = -1;
+ u32 res_start;
+ int ret, i;
memset(port, 0, sizeof *port);
- if (of_property_read_u32(np, "clock-frequency", &clk)) {
+ if (device_property_read_u32(&pdev->dev, "clock-frequency", &clk)) {
/* Get clk rate through clk driver if present */
- info->clk = clk_get(&ofdev->dev, NULL);
+ info->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(info->clk)) {
- dev_warn(&ofdev->dev,
+ dev_warn(&pdev->dev,
"clk or clock-frequency not defined\n");
return PTR_ERR(info->clk);
}
@@ -77,57 +76,63 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
clk = clk_get_rate(info->clk);
}
/* If current-speed was set, then try not to change it. */
- if (of_property_read_u32(np, "current-speed", &spd) == 0)
+ if (device_property_read_u32(&pdev->dev, "current-speed", &spd) == 0)
port->custom_divisor = clk / (16 * spd);
- ret = of_address_to_resource(np, 0, &resource);
- if (ret) {
- dev_warn(&ofdev->dev, "invalid address\n");
+ /* Check for shifted address mapping */
+ if (device_property_read_u32(&pdev->dev, "reg-offset", &prop) != 0)
+ prop = 0;
+
+ for (i = 0; iotype == -1 && i < pdev->num_resources; i++) {
+ struct resource *resource = &pdev->resource[i];
+ if (resource_type(resource) == IORESOURCE_MEM) {
+ iotype = UPIO_MEM;
+ port->mapbase = res_start + prop;
+ } else if (resource_type(resource) == IORESOURCE_IO) {
+ iotype = UPIO_PORT;
+ port->iobase = res_start + prop;
+ }
+
+ res_start = resource->start;
+ }
+ if (iotype == -1) {
+ dev_warn(&pdev->dev, "invalid address\n");
goto out;
}
spin_lock_init(&port->lock);
- port->mapbase = resource.start;
-
- /* Check for shifted address mapping */
- if (of_property_read_u32(np, "reg-offset", &prop) == 0)
- port->mapbase += prop;
/* Check for registers offset within the devices address range */
- if (of_property_read_u32(np, "reg-shift", &prop) == 0)
+ if (device_property_read_u32(&pdev->dev, "reg-shift", &prop) == 0)
port->regshift = prop;
/* Check for fifo size */
- if (of_property_read_u32(np, "fifo-size", &prop) == 0)
+ if (device_property_read_u32(&pdev->dev, "fifo-size", &prop) == 0)
port->fifosize = prop;
- port->irq = irq_of_parse_and_map(np, 0);
- port->iotype = UPIO_MEM;
- if (of_property_read_u32(np, "reg-io-width", &prop) == 0) {
- switch (prop) {
- port->iotype = UPIO_MEM;
- break;
- port->iotype = UPIO_MEM32;
- break;
- dev_warn(&ofdev->dev, "unsupported reg-io-width (%d)\n",
+ port->irq = platform_get_irq(pdev, 0);
+
+ if (device_property_read_u32(&pdev->dev, "reg-io-width", &prop) == 0) {
+ if (prop == 4 && iotype == UPIO_MEM) {
+ iotype = UPIO_MEM32;
+ } else {
+ dev_warn(&pdev->dev, "unsupported reg-io-width (%d)\n",
prop);
ret = -EINVAL;
goto out;
}
}
+ port->iotype = iotype;
port->type = type;
port->uartclk = clk;
port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP
| UPF_FIXED_PORT | UPF_FIXED_TYPE;
- if (of_find_property(np, "no-loopback-test", NULL))
+ if (!device_get_property(&pdev->dev, "no-loopback-test", NULL))
port->flags |= UPF_SKIP_TEST;
- port->dev = &ofdev->dev;
+ port->dev = &pdev->dev;
if (type == PORT_TEGRA)
port->handle_break = tegra_serial_handle_break;
* Try to register a serial port
*/
static struct of_device_id of_platform_serial_table[];
-static int of_platform_serial_probe(struct platform_device *ofdev)
+static int of_platform_serial_probe(struct platform_device *pdev)
Nit: Separate patch please. The rename of ofdev to pdev is nothing more
than cleanup. It has no functional impact and just makes the patch
larger.
Post by David Woodhouse
{
const struct of_device_id *match;
struct of_serial_info *info;
@@ -151,11 +156,11 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
int port_type;
int ret;
- match = of_match_device(of_platform_serial_table, &ofdev->dev);
+ match = of_match_device(of_platform_serial_table, &pdev->dev);
if (!match)
return -EINVAL;
- if (of_find_property(ofdev->dev.of_node, "used-by-rtas", NULL))
+ if (!device_get_property(&pdev->dev, "used-by-rtas", NULL))
return -EBUSY;
info = kmalloc(sizeof(*info), GFP_KERNEL);
@@ -163,7 +168,7 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
return -ENOMEM;
port_type = (unsigned long)match->data;
- ret = of_platform_serial_setup(ofdev, port_type, &port, info);
+ ret = of_platform_serial_setup(pdev, port_type, &port, info);
if (ret)
goto out;
@@ -179,12 +184,10 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
if (port.fifosize)
port8250.capabilities = UART_CAP_FIFO;
- if (of_property_read_bool(ofdev->dev.of_node,
- "auto-flow-control"))
+ if (!device_get_property(&pdev->dev, "auto-flow-control", NULL))
port8250.capabilities |= UART_CAP_AFE;
- if (of_property_read_bool(ofdev->dev.of_node,
- "has-hw-flow-control"))
+ if (!device_get_property(&pdev->dev, "has-hw-flow-control", NULL))
port8250.port.flags |= UPF_HARD_FLOW;
ret = serial8250_register_8250_port(&port8250);
@@ -199,7 +202,7 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
/* need to add code for these */
- dev_info(&ofdev->dev, "Unknown serial port found, ignored\n");
+ dev_info(&pdev->dev, "Unknown serial port found, ignored\n");
ret = -ENODEV;
break;
}
@@ -208,20 +211,19 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
info->type = port_type;
info->line = ret;
- platform_set_drvdata(ofdev, info);
+ platform_set_drvdata(pdev, info);
return 0;
kfree(info);
- irq_dispose_mapping(port.irq);
return ret;
}
/*
* Release a line
*/
-static int of_platform_serial_remove(struct platform_device *ofdev)
+static int of_platform_serial_remove(struct platform_device *pdev)
{
- struct of_serial_info *info = platform_get_drvdata(ofdev);
+ struct of_serial_info *info = platform_get_drvdata(pdev);
switch (info->type) {
#ifdef CONFIG_SERIAL_8250
--
David Woodhouse Open Source Technology Centre
Attachment: smime.p7s (application/x-pkcs7-signature)

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Grant Likely
2014-10-18 08:37:56 UTC
Permalink
On Thu, 16 Oct 2014 16:55:56 +0200
Post by David Woodhouse
Post by Darren Hart
So my objection here is that by keeping the of_* terms in the driver we
are required to include of, although it does safely convert to returning
NULL if !CONFIG_OF I suppose.
New version removes everything but the of_match_id bits which we need to
match ACPI devices too. Perhaps they ought to be renamed, but I'm not
sure it's worth it.
This also removes the call to platform_get_resource(IORESOURCE_MEM) and
fall back to platform_get_resource(IORESOURCE_IO) as discussed IRL with
Rafael. I'm not sure it's much of an improvement, mind you :)
Still untested. I think it's OK to switch to platform_get_irq() and then
drop the irq_dispose_mapping() call, right? The platform_device takes
care of all of that for us?
Well, the irq management code is all messed up, but what you are doing
is indeed okay. Unfortunately for platform devices we can never free an
IRQ once we've claimed it. That's a completely separate problem and you
don't need to worry about it for this patch.

g.

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Grant Likely
2014-10-18 08:35:49 UTC
Permalink
On Wed, 15 Oct 2014 17:43:01 +0200
Post by Darren Hart
Post by Mark Rutland
Post by Darren Hart
Mark, what would you propose we do differently to enable this driver to
be firmware-type agnostic?
For this particular driver, all I'm asking for is that the
"used-by-rtas" property is not moved over from of_find_property to
device_get_property. It is irrelevant for all ACPI systems. Evidently my
comment was unclear; I apologise for that.
So my objection here is that by keeping the of_* terms in the driver we
are required to include of, although it does safely convert to returning
NULL if !CONFIG_OF I suppose.
This shouldn't be that controversial. There will be things that only make
sense for DT or only ACPI. Allowing the property to be processed when
the other interface is being used may tempt firmware authors to use the
property because it just happens to have a side effect that looks right
to them.

I don't see any problem with factoring out those bits into a function
that is only called (or built) when the associated firmware interface is
used. In these situations, the driver isn't 100% generic, so having
small per-firmware hooks is absolutely okay and not a burden to
maintain.

g.
Darren Hart
2014-10-21 21:50:19 UTC
Permalink
Post by Grant Likely
On Wed, 15 Oct 2014 17:43:01 +0200
Post by Darren Hart
Post by Mark Rutland
Post by Darren Hart
Mark, what would you propose we do differently to enable this driver to
be firmware-type agnostic?
For this particular driver, all I'm asking for is that the
"used-by-rtas" property is not moved over from of_find_property to
device_get_property. It is irrelevant for all ACPI systems. Evidently my
comment was unclear; I apologise for that.
So my objection here is that by keeping the of_* terms in the driver we
are required to include of, although it does safely convert to returning
NULL if !CONFIG_OF I suppose.
This shouldn't be that controversial. There will be things that only make
sense for DT or only ACPI. Allowing the property to be processed when
the other interface is being used may tempt firmware authors to use the
property because it just happens to have a side effect that looks right
to them.
I don't see any problem with factoring out those bits into a function
that is only called (or built) when the associated firmware interface is
used. In these situations, the driver isn't 100% generic, so having
small per-firmware hooks is absolutely okay and not a burden to
maintain.
Hrm... well, I suppose this isn't a hill I want to die on. I can disagree and
commit here :-)
--
Darren Hart
Intel Open Source Technology Center
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
David Woodhouse
2014-10-15 14:08:09 UTC
Permalink
Post by Mark Rutland
We have been checking for all DT platforms, and that's a bug for DT.
Copying that bug to ACPI is inexcusable given we know it's a bug to do
so.
We'll, perhaps it should be named 'used-by-firmware' and actually it's
just as valid under ACPI as it is on RTAS systems. All it does is stop the
OS from using the port.
Post by Mark Rutland
I understand that. However, where a binding doesn't make sense (as in
this case), it shouldn't be enabled for ACPI as it provides a larger
surface area for misuse, for no benefit.
These are *optional* properties. They were optional precisely *because*
they only make sense in some cases. I don't know that it makes sense to
take them away. The benefit we get is *consistency*. For example if
someone *does* use the property in question as 'used-by-firmware' and
expects the OS not to touch it, we don't want that to change behaviour
between ACPI and fdt boots.
--
dwmw2

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Rafael J. Wysocki
2014-10-17 12:22:48 UTC
Permalink
Hi Everyone,
Hving had a couple of chats with Grant and Arnd during LinuxCon EU/LPC, we
now have version 5 taking all feedback into account (hopefully).
Changes have been made to patch [02/12] and to patches [09-12/12], although
in patches [10-12/12] they are fairly minor. I have retained the Greg's
ACK on patch [02/12], because it is essentially the same that have been
posted aleady and ACKed by him (Greg, please let me know if I shouldn't
do that) and all the ACKs on the remaining patches except for patch [09/12]
which is substantially different. Still, if reviewers think that their
ACKs don't apply any more, please let me know and I'll remove them.
Patch [02/12] now contains helper functions for all proprerty data types
that can be accessed which call the existing of_ functions, because Grant
preferred that.
Patch [09/12] introduces quite a new concept, which is the struct fwnode_handle
structure containing one field (type) and embedded in struct device_node
(type==FWNODE_OF) and struct acpi_device (type==FWNODE_ACPI). In short, if
we are passed a struct fwnode_handle pointer, we can get from it to the
appropriate device node pointer (either struct acpi_device or struct device_node)
using container_of() after we've checked the type. This is needed for the code
that needs to access child nodes of a device in case when they don't have
struct device representations (whatever the reason). This has been suggested
by Grant and pretty much everyone involved agrees that it's better that the
alternatives presented so far.
While at it, many thanks to Mika for testing the patches on MinnowBoard 1 and
MinnowBoard Max and fixing build problems with them while we've been having
fun at the conferences! I wouldn't have been able to prepare the patchset
for posting without that work.

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Rafael J. Wysocki
2014-10-17 12:05:59 UTC
Permalink
From: Mika Westerberg <***@linux.intel.com>

We have lots of existing Device Tree enabled drivers and allocating
separate _HID for each is not feasible. Instead we allocate special _HID
"PRP0001" that means that the match should be done using Device Tree
compatible property using driver's .of_match_table instead if the driver
is missing .acpi_match_table.

If there is a need to distinguish from where the device is enumerated
(DT/ACPI) driver can check dev->of_node or ACPI_COMPATION(dev).

Signed-off-by: Mika Westerberg <***@linux.intel.com>
Reviewed-by: Grant Likely <***@linaro.org>
Signed-off-by: Rafael J. Wysocki <***@intel.com>
---
drivers/acpi/property.c | 34 +++++++++++++++++
drivers/acpi/scan.c | 97 +++++++++++++++++++++++++++++++++++++++++++------
include/acpi/acpi_bus.h | 1 +
include/linux/acpi.h | 8 +---
4 files changed, 123 insertions(+), 17 deletions(-)

diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c
index 680f7f1..ff53eb8 100644
--- a/drivers/acpi/property.c
+++ b/drivers/acpi/property.c
@@ -76,6 +76,37 @@ static bool acpi_properties_format_valid(const union acpi_object *properties)
return true;
}

+static void acpi_init_of_compatible(struct acpi_device *adev)
+{
+ const union acpi_object *of_compatible;
+ struct acpi_hardware_id *hwid;
+ bool acpi_of = false;
+
+ /*
+ * Check if the special PRP0001 ACPI ID is present and in that
+ * case we fill in Device Tree compatible properties for this
+ * device.
+ */
+ list_for_each_entry(hwid, &adev->pnp.ids, list) {
+ if (!strcmp(hwid->id, "PRP0001")) {
+ acpi_of = true;
+ break;
+ }
+ }
+
+ if (!acpi_of)
+ return;
+
+ if (acpi_dev_get_property_array(adev, "compatible", ACPI_TYPE_STRING,
+ &of_compatible)) {
+ acpi_handle_warn(adev->handle,
+ "PRP0001 requires compatible property\n");
+ return;
+ }
+
+ adev->data.of_compatible = of_compatible;
+}
+
void acpi_init_properties(struct acpi_device *adev)
{
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
@@ -119,6 +150,8 @@ void acpi_init_properties(struct acpi_device *adev)

adev->data.pointer = buf.pointer;
adev->data.properties = properties;
+
+ acpi_init_of_compatible(adev);
return;
}

@@ -130,6 +163,7 @@ void acpi_init_properties(struct acpi_device *adev)
void acpi_free_properties(struct acpi_device *adev)
{
ACPI_FREE((void *)adev->data.pointer);
+ adev->data.of_compatible = NULL;
adev->data.pointer = NULL;
adev->data.properties = NULL;
}
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 1979ab3..bc999f1 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -124,17 +124,51 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
if (list_empty(&acpi_dev->pnp.ids))
return 0;

- len = snprintf(modalias, size, "acpi:");
- size -= len;
-
- list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
- count = snprintf(&modalias[len], size, "%s:", id->id);
- if (count < 0)
- return -EINVAL;
- if (count >= size)
- return -ENOMEM;
- len += count;
- size -= count;
+ /*
+ * If the device has PRP0001 we expose DT compatible modalias
+ * instead in form of of:NnameTCcompatible.
+ */
+ if (acpi_dev->data.of_compatible) {
+ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
+ const union acpi_object *of_compatible, *obj;
+ char *c;
+ int i;
+
+ acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf);
+ /* DT strings are all in lower case */
+ for (c = buf.pointer; *c != '\0'; c++)
+ *c = tolower(*c);
+
+ len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer);
+ ACPI_FREE(buf.pointer);
+
+ of_compatible = acpi_dev->data.of_compatible;
+ for (i = 0; i < of_compatible->package.count; i++) {
+ obj = &of_compatible->package.elements[i];
+
+ count = snprintf(&modalias[len], size, "C%s",
+ obj->string.pointer);
+ if (count < 0)
+ return -EINVAL;
+ if (count >= size)
+ return -ENOMEM;
+
+ len += count;
+ size -= count;
+ }
+ } else {
+ len = snprintf(modalias, size, "acpi:");
+ size -= len;
+
+ list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
+ count = snprintf(&modalias[len], size, "%s:", id->id);
+ if (count < 0)
+ return -EINVAL;
+ if (count >= size)
+ return -ENOMEM;
+ len += count;
+ size -= count;
+ }
}

modalias[len] = '\0';
@@ -864,6 +898,47 @@ int acpi_match_device_ids(struct acpi_device *device,
}
EXPORT_SYMBOL(acpi_match_device_ids);

+/* Performs match against special "PRP0001" shoehorn ACPI ID */
+static bool acpi_of_driver_match_device(struct device *dev,
+ const struct device_driver *drv)
+{
+ const union acpi_object *of_compatible;
+ struct acpi_device *adev;
+ int i;
+
+ adev = ACPI_COMPANION(dev);
+ if (!adev)
+ return false;
+
+ of_compatible = adev->data.of_compatible;
+ if (!drv->of_match_table || !of_compatible)
+ return false;
+
+ /* Now we can look for the driver DT compatible strings */
+ for (i = 0; i < of_compatible->package.count; i++) {
+ const struct of_device_id *id;
+ const union acpi_object *obj;
+
+ obj = &of_compatible->package.elements[i];
+
+ for (id = drv->of_match_table; id->compatible[0]; id++)
+ if (!strcasecmp(obj->string.pointer, id->compatible))
+ return true;
+ }
+
+ return false;
+}
+
+bool acpi_driver_match_device(struct device *dev,
+ const struct device_driver *drv)
+{
+ if (!drv->acpi_match_table)
+ return acpi_of_driver_match_device(dev, drv);
+
+ return !!acpi_match_device(drv->acpi_match_table, dev);
+}
+EXPORT_SYMBOL_GPL(acpi_driver_match_device);
+
static void acpi_free_power_resources_lists(struct acpi_device *device)
{
int i;
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index f9734fa..98cd723 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -341,6 +341,7 @@ struct acpi_device_physical_node {
struct acpi_device_data {
const union acpi_object *pointer;
const union acpi_object *properties;
+ const union acpi_object *of_compatible;
};

/* Device */
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 18c1bc3..11aa6b8 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -424,12 +424,8 @@ extern int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *),
const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids,
const struct device *dev);

-static inline bool acpi_driver_match_device(struct device *dev,
- const struct device_driver *drv)
-{
- return !!acpi_match_device(drv->acpi_match_table, dev);
-}
-
+extern bool acpi_driver_match_device(struct device *dev,
+ const struct device_driver *drv);
int acpi_device_uevent_modalias(struct device *, struct kobj_uevent_env *);
int acpi_device_modalias(struct device *, char *, int);
--
1.9.3
Grant Likely
2014-10-20 14:05:01 UTC
Permalink
On Fri, 17 Oct 2014 14:05:59 +0200
Post by Rafael J. Wysocki
We have lots of existing Device Tree enabled drivers and allocating
separate _HID for each is not feasible. Instead we allocate special _HID
"PRP0001" that means that the match should be done using Device Tree
compatible property using driver's .of_match_table instead if the driver
is missing .acpi_match_table.
(Not a critique of this patch, but merely a helpful comment; my previous
ack remains intact) :-)

It would be useful for the code to point at some document that describes
the semantics of the PRP0001 binding.

g.
Post by Rafael J. Wysocki
If there is a need to distinguish from where the device is enumerated
(DT/ACPI) driver can check dev->of_node or ACPI_COMPATION(dev).
---
drivers/acpi/property.c | 34 +++++++++++++++++
drivers/acpi/scan.c | 97 +++++++++++++++++++++++++++++++++++++++++++------
include/acpi/acpi_bus.h | 1 +
include/linux/acpi.h | 8 +---
4 files changed, 123 insertions(+), 17 deletions(-)
diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c
index 680f7f1..ff53eb8 100644
--- a/drivers/acpi/property.c
+++ b/drivers/acpi/property.c
@@ -76,6 +76,37 @@ static bool acpi_properties_format_valid(const union acpi_object *properties)
return true;
}
+static void acpi_init_of_compatible(struct acpi_device *adev)
+{
+ const union acpi_object *of_compatible;
+ struct acpi_hardware_id *hwid;
+ bool acpi_of = false;
+
+ /*
+ * Check if the special PRP0001 ACPI ID is present and in that
+ * case we fill in Device Tree compatible properties for this
+ * device.
+ */
+ list_for_each_entry(hwid, &adev->pnp.ids, list) {
+ if (!strcmp(hwid->id, "PRP0001")) {
+ acpi_of = true;
+ break;
+ }
+ }
+
+ if (!acpi_of)
+ return;
+
+ if (acpi_dev_get_property_array(adev, "compatible", ACPI_TYPE_STRING,
+ &of_compatible)) {
+ acpi_handle_warn(adev->handle,
+ "PRP0001 requires compatible property\n");
+ return;
+ }
+
+ adev->data.of_compatible = of_compatible;
+}
+
void acpi_init_properties(struct acpi_device *adev)
{
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
@@ -119,6 +150,8 @@ void acpi_init_properties(struct acpi_device *adev)
adev->data.pointer = buf.pointer;
adev->data.properties = properties;
+
+ acpi_init_of_compatible(adev);
return;
}
@@ -130,6 +163,7 @@ void acpi_init_properties(struct acpi_device *adev)
void acpi_free_properties(struct acpi_device *adev)
{
ACPI_FREE((void *)adev->data.pointer);
+ adev->data.of_compatible = NULL;
adev->data.pointer = NULL;
adev->data.properties = NULL;
}
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 1979ab3..bc999f1 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -124,17 +124,51 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
if (list_empty(&acpi_dev->pnp.ids))
return 0;
- len = snprintf(modalias, size, "acpi:");
- size -= len;
-
- list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
- count = snprintf(&modalias[len], size, "%s:", id->id);
- if (count < 0)
- return -EINVAL;
- if (count >= size)
- return -ENOMEM;
- len += count;
- size -= count;
+ /*
+ * If the device has PRP0001 we expose DT compatible modalias
+ * instead in form of of:NnameTCcompatible.
+ */
+ if (acpi_dev->data.of_compatible) {
+ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
+ const union acpi_object *of_compatible, *obj;
+ char *c;
+ int i;
+
+ acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf);
+ /* DT strings are all in lower case */
+ for (c = buf.pointer; *c != '\0'; c++)
+ *c = tolower(*c);
+
+ len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer);
+ ACPI_FREE(buf.pointer);
+
+ of_compatible = acpi_dev->data.of_compatible;
+ for (i = 0; i < of_compatible->package.count; i++) {
+ obj = &of_compatible->package.elements[i];
+
+ count = snprintf(&modalias[len], size, "C%s",
+ obj->string.pointer);
+ if (count < 0)
+ return -EINVAL;
+ if (count >= size)
+ return -ENOMEM;
+
+ len += count;
+ size -= count;
+ }
+ } else {
+ len = snprintf(modalias, size, "acpi:");
+ size -= len;
+
+ list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
+ count = snprintf(&modalias[len], size, "%s:", id->id);
+ if (count < 0)
+ return -EINVAL;
+ if (count >= size)
+ return -ENOMEM;
+ len += count;
+ size -= count;
+ }
}
modalias[len] = '\0';
@@ -864,6 +898,47 @@ int acpi_match_device_ids(struct acpi_device *device,
}
EXPORT_SYMBOL(acpi_match_device_ids);
+/* Performs match against special "PRP0001" shoehorn ACPI ID */
+static bool acpi_of_driver_match_device(struct device *dev,
+ const struct device_driver *drv)
+{
+ const union acpi_object *of_compatible;
+ struct acpi_device *adev;
+ int i;
+
+ adev = ACPI_COMPANION(dev);
+ if (!adev)
+ return false;
+
+ of_compatible = adev->data.of_compatible;
+ if (!drv->of_match_table || !of_compatible)
+ return false;
+
+ /* Now we can look for the driver DT compatible strings */
+ for (i = 0; i < of_compatible->package.count; i++) {
+ const struct of_device_id *id;
+ const union acpi_object *obj;
+
+ obj = &of_compatible->package.elements[i];
+
+ for (id = drv->of_match_table; id->compatible[0]; id++)
+ if (!strcasecmp(obj->string.pointer, id->compatible))
+ return true;
+ }
+
+ return false;
+}
+
+bool acpi_driver_match_device(struct device *dev,
+ const struct device_driver *drv)
+{
+ if (!drv->acpi_match_table)
+ return acpi_of_driver_match_device(dev, drv);
+
+ return !!acpi_match_device(drv->acpi_match_table, dev);
+}
+EXPORT_SYMBOL_GPL(acpi_driver_match_device);
+
static void acpi_free_power_resources_lists(struct acpi_device *device)
{
int i;
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index f9734fa..98cd723 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -341,6 +341,7 @@ struct acpi_device_physical_node {
struct acpi_device_data {
const union acpi_object *pointer;
const union acpi_object *properties;
+ const union acpi_object *of_compatible;
};
/* Device */
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 18c1bc3..11aa6b8 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -424,12 +424,8 @@ extern int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *),
const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids,
const struct device *dev);
-static inline bool acpi_driver_match_device(struct device *dev,
- const struct device_driver *drv)
-{
- return !!acpi_match_device(drv->acpi_match_table, dev);
-}
-
+extern bool acpi_driver_match_device(struct device *dev,
+ const struct device_driver *drv);
int acpi_device_uevent_modalias(struct device *, struct kobj_uevent_env *);
int acpi_device_modalias(struct device *, char *, int);
--
1.9.3
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Rafael J. Wysocki
2014-10-20 22:19:17 UTC
Permalink
Post by Grant Likely
On Fri, 17 Oct 2014 14:05:59 +0200
Post by Rafael J. Wysocki
We have lots of existing Device Tree enabled drivers and allocating
separate _HID for each is not feasible. Instead we allocate special _HID
"PRP0001" that means that the match should be done using Device Tree
compatible property using driver's .of_match_table instead if the driver
is missing .acpi_match_table.
(Not a critique of this patch, but merely a helpful comment; my previous
ack remains intact) :-)
It would be useful for the code to point at some document that describes
the semantics of the PRP0001 binding.
Well, we need to create that document in the first place. :-)

I'd prefer to wait with that until the thing settles, however.

Rafael

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Rafael J. Wysocki
2014-10-17 12:16:00 UTC
Permalink
From: Mika Westerberg <***@linux.intel.com>

Some drivers need to deal with only firmware representation of its
GPIOs. An example would be a GPIO button array driver where each button
is described as a separate firmware node in device tree. Typically these
child nodes do not have physical representation in the Linux device
model.

In order to help device drivers to handle such firmware child nodes we
add dev[m]_get_named_gpiod_from_child() that takes a child firmware
node pointer as its second argument (the first one is the parent device
itself), finds the GPIO using whatever is the underlying firmware
method, and requests the GPIO properly.

Signed-off-by: Mika Westerberg <***@linux.intel.com>
Acked-by: Alexandre Courbot <***@nvidia.com>
Signed-off-by: Rafael J. Wysocki <***@intel.com>
---
drivers/gpio/devres.c | 36 +++++++++++++++++++++++++++
drivers/gpio/gpiolib.c | 56 ++++++++++++++++++++++++++++++++++++++++++
include/linux/gpio/consumer.h | 8 ++++++
3 files changed, 100 insertions(+)

Index: linux-pm/drivers/gpio/devres.c
===================================================================
--- linux-pm.orig/drivers/gpio/devres.c
+++ linux-pm/drivers/gpio/devres.c
@@ -109,6 +109,42 @@ struct gpio_desc *__must_check __devm_gp
EXPORT_SYMBOL(__devm_gpiod_get_index);

/**
+ * devm_get_named_gpiod_from_child - managed dev_get_named_gpiod_from_child()
+ * @dev: GPIO consumer
+ * @child: firmware node (child of @dev)
+ * @propname: name of the firmware property
+ * @index: index of the GPIO in the property value in case of many
+ *
+ * GPIO descriptors returned from this function are automatically disposed on
+ * driver detach.
+ */
+struct gpio_desc *devm_get_named_gpiod_from_child(struct device *dev,
+ struct fwnode_handle *child,
+ const char *propname,
+ int index)
+{
+ struct gpio_desc **dr;
+ struct gpio_desc *desc;
+
+ dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *),
+ GFP_KERNEL);
+ if (!dr)
+ return ERR_PTR(-ENOMEM);
+
+ desc = fwnode_get_named_gpiod(child, propname, index);
+ if (IS_ERR(desc)) {
+ devres_free(dr);
+ return desc;
+ }
+
+ *dr = desc;
+ devres_add(dev, dr);
+
+ return desc;
+}
+EXPORT_SYMBOL(devm_get_named_gpiod_from_child);
+
+/**
* devm_gpiod_get_index_optional - Resource-managed gpiod_get_index_optional()
* @dev: GPIO consumer
* @con_id: function within the GPIO consumer
Index: linux-pm/drivers/gpio/gpiolib.c
===================================================================
--- linux-pm.orig/drivers/gpio/gpiolib.c
+++ linux-pm/drivers/gpio/gpiolib.c
@@ -1735,6 +1735,62 @@ struct gpio_desc *__must_check __gpiod_g
EXPORT_SYMBOL_GPL(__gpiod_get_index);

/**
+ * fwnode_get_named_gpiod - obtain a GPIO from firmware node
+ * @fwnode: handle of the firmware node
+ * @propname: name of the firmware property
+ * @idx: index of the GPIO in the property value in case of many
+ *
+ * This function can be used for drivers that get their configuration
+ * from firmware.
+ *
+ * Function properly finds the corresponding GPIO using whatever is the
+ * underlying firmware interface and then makes sure that the GPIO
+ * descriptor is requested before it is returned to the caller.
+ *
+ * In case of error an ERR_PTR() is returned.
+ */
+struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
+ const char *propname, int index)
+{
+ struct gpio_desc *desc = ERR_PTR(-ENODEV);
+ bool active_low = false;
+ int ret;
+
+ if (!fwnode)
+ return ERR_PTR(-EINVAL);
+
+ if (is_of_node(fwnode)) {
+ enum of_gpio_flags flags;
+
+ desc = of_get_named_gpiod_flags(of_node(fwnode), propname,
+ index, &flags);
+ if (!IS_ERR(desc))
+ active_low = flags & OF_GPIO_ACTIVE_LOW;
+ } else if (is_acpi_node(fwnode)) {
+ struct acpi_gpio_info info;
+
+ desc = acpi_get_gpiod_by_index(acpi_node(fwnode), propname,
+ index, &info);
+ if (!IS_ERR(desc))
+ active_low = info.active_low;
+ }
+
+ if (IS_ERR(desc))
+ return desc;
+
+ ret = gpiod_request(desc, NULL);
+ if (ret)
+ return ERR_PTR(ret);
+
+ /* Only value flag can be set from both DT and ACPI is active_low */
+ if (active_low)
+ set_bit(FLAG_ACTIVE_LOW, &desc->flags);
+
+ return desc;
+}
+EXPORT_SYMBOL_GPL(fwnode_get_named_gpiod);
+
+/**
* gpiod_get_index_optional - obtain an optional GPIO from a multi-index GPIO
* function
* @dev: GPIO consumer, can be NULL for system-global GPIOs
Index: linux-pm/include/linux/gpio/consumer.h
===================================================================
--- linux-pm.orig/include/linux/gpio/consumer.h
+++ linux-pm/include/linux/gpio/consumer.h
@@ -94,6 +94,14 @@ int gpiod_to_irq(const struct gpio_desc
struct gpio_desc *gpio_to_desc(unsigned gpio);
int desc_to_gpio(const struct gpio_desc *desc);

+/* Child properties interface */
+struct fwnode_handle;
+
+struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
+ const char *propname, int index);
+struct gpio_desc *devm_get_named_gpiod_from_child(struct device *dev,
+ struct fwnode_handle *child,
+ const char *propname, int index);
#else /* CONFIG_GPIOLIB */

static inline struct gpio_desc *__must_check __gpiod_get(struct device *dev,
Arnd Bergmann
2014-10-17 18:09:51 UTC
Permalink
Post by Rafael J. Wysocki
Some drivers need to deal with only firmware representation of its
GPIOs. An example would be a GPIO button array driver where each button
is described as a separate firmware node in device tree. Typically these
child nodes do not have physical representation in the Linux device
model.
In order to help device drivers to handle such firmware child nodes we
add dev[m]_get_named_gpiod_from_child() that takes a child firmware
node pointer as its second argument (the first one is the parent device
itself), finds the GPIO using whatever is the underlying firmware
method, and requests the GPIO properly.
Could we also have a wrapper around this function without a "name" argument, using just the index?

Arnd
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Arnd Bergmann
2014-10-18 09:47:41 UTC
Permalink
Post by Arnd Bergmann
Post by Rafael J. Wysocki
Some drivers need to deal with only firmware representation of its
GPIOs. An example would be a GPIO button array driver where each button
is described as a separate firmware node in device tree. Typically these
child nodes do not have physical representation in the Linux device
model.
In order to help device drivers to handle such firmware child nodes we
add dev[m]_get_named_gpiod_from_child() that takes a child firmware
node pointer as its second argument (the first one is the parent device
itself), finds the GPIO using whatever is the underlying firmware
method, and requests the GPIO properly.
Could we also have a wrapper around this function without a "name" argument,
using just the index?
Expanding on this thought: I think we should mandate for new bindings
that they use either a name and no index, or an index but not name,
and I also think that for named gpios, we should try to converge on a
common naming scheme. As discussed, we will probably want to support all
the existing ways to do this even with ACPI and with the unified
interface, but it doesn't have to be the obvious way.

We could do it like this:

// internal implementation, may be called from drivers with legacy bindings
struct gpio_desc *__fwnode_get_gpiod_from_property(struct fwnode_handle *fwnode,
const char *propname, int index)
{
... /* your current code */
}

// recommended interface
static inline struct gpio_desc *fwnode_get_gpiod(struct fwnode_handle *fwnode,
int index)
{
return __fwnode_get_gpiod_from_property(fwnode, "gpios", index);
}

// alternative interface
struct gpio_desc *fwnode_get_gpiod(struct fwnode_handle *fwnode, const char *name)
{
char propname[64];
int ret;

ret = snprintf(propname, sizeof(propname), "%s-gpios", name);
if (ret > sizeof(propname))
return -EINVAL;

return __fwnode_get_gpiod_from_property(fwnode, propname, 0);
}

The above is just a suggestion, I'm hoping for the GPIO maintainers to
provide more guidance if they have other ideas.

Arnd
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Rafael J. Wysocki
2014-10-19 23:58:57 UTC
Permalink
Post by Arnd Bergmann
Post by Arnd Bergmann
Post by Rafael J. Wysocki
Some drivers need to deal with only firmware representation of its
GPIOs. An example would be a GPIO button array driver where each button
is described as a separate firmware node in device tree. Typically these
child nodes do not have physical representation in the Linux device
model.
In order to help device drivers to handle such firmware child nodes we
add dev[m]_get_named_gpiod_from_child() that takes a child firmware
node pointer as its second argument (the first one is the parent device
itself), finds the GPIO using whatever is the underlying firmware
method, and requests the GPIO properly.
Could we also have a wrapper around this function without a "name" argument,
using just the index?
Expanding on this thought: I think we should mandate for new bindings
that they use either a name and no index, or an index but not name,
and I also think that for named gpios, we should try to converge on a
common naming scheme. As discussed, we will probably want to support all
the existing ways to do this even with ACPI and with the unified
interface, but it doesn't have to be the obvious way.
// internal implementation, may be called from drivers with legacy bindings
struct gpio_desc *__fwnode_get_gpiod_from_property(struct fwnode_handle *fwnode,
const char *propname, int index)
{
... /* your current code */
}
// recommended interface
static inline struct gpio_desc *fwnode_get_gpiod(struct fwnode_handle *fwnode,
int index)
{
return __fwnode_get_gpiod_from_property(fwnode, "gpios", index);
}
// alternative interface
struct gpio_desc *fwnode_get_gpiod(struct fwnode_handle *fwnode, const char *name)
{
char propname[64];
int ret;
ret = snprintf(propname, sizeof(propname), "%s-gpios", name);
if (ret > sizeof(propname))
return -EINVAL;
return __fwnode_get_gpiod_from_property(fwnode, propname, 0);
}
The above is just a suggestion, I'm hoping for the GPIO maintainers to
provide more guidance if they have other ideas.
Actually, since the two last patches in the series, which currently are
the only users of these new functions, both pass "gpios" as the property
name and 0 as the index, I can simplify the functions so that (a)
fwnode_get_gpiod() takes fwnode and name and then simply passes 0 as the
index to either of_get_named_gpiod_flags() or acpi_get_gpiod_by_index()
and (b) devm_get_named_gpiod_from_child() takes only dev and fwnode (child)
and passes "gpios" as the property name to fwnode_get_gpiod(). The name
of devm_get_named_gpiod_from_child() could then be changed to something
like devm_get_gpiod_from_child() even.

If anyone in the future needs anything more general, they can simply
add more complexity to that code, but for now we can go for a simplified
interface just fine.

Rafael

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Arnd Bergmann
2014-10-20 14:22:15 UTC
Permalink
Post by Rafael J. Wysocki
Actually, since the two last patches in the series, which currently are
the only users of these new functions, both pass "gpios" as the property
name and 0 as the index, I can simplify the functions so that (a)
fwnode_get_gpiod() takes fwnode and name and then simply passes 0 as the
index to either of_get_named_gpiod_flags() or acpi_get_gpiod_by_index()
and (b) devm_get_named_gpiod_from_child() takes only dev and fwnode (child)
and passes "gpios" as the property name to fwnode_get_gpiod(). The name
of devm_get_named_gpiod_from_child() could then be changed to something
like devm_get_gpiod_from_child() even.
If anyone in the future needs anything more general, they can simply
add more complexity to that code, but for now we can go for a simplified
interface just fine.
That sounds good, yes.

Arnd
Alexandre Courbot
2014-10-20 06:12:50 UTC
Permalink
Post by Arnd Bergmann
Post by Arnd Bergmann
Post by Rafael J. Wysocki
Some drivers need to deal with only firmware representation of its
GPIOs. An example would be a GPIO button array driver where each button
is described as a separate firmware node in device tree. Typically these
child nodes do not have physical representation in the Linux device
model.
In order to help device drivers to handle such firmware child nodes we
add dev[m]_get_named_gpiod_from_child() that takes a child firmware
node pointer as its second argument (the first one is the parent device
itself), finds the GPIO using whatever is the underlying firmware
method, and requests the GPIO properly.
Could we also have a wrapper around this function without a "name" argument,
using just the index?
Expanding on this thought: I think we should mandate for new bindings
that they use either a name and no index, or an index but not name,
I'm afraid this could forbid some useful use-cases, namely the ones
where several GPIOs serve the same function (and are typically set
together). We had a few patch proposals to handle such GPIO groups,
and even though one was in pretty good shape the submitter did not
push it until the end. :/

But my concern is that instead of having this:

enable-gpio = <&gpio 0 GPIO_ACTIVE_HIGH>;
value-gpios = <&gpio 1 GPIO_ACTIVE_HIGH ... &gpio 8 GPIO_ACTIVE_HIGH>;

We would force this:

enable-gpio = <&gpio 0 GPIO_ACTIVE_HIGH>;
value0-gpio = <&gpio 1 GPIO_ACTIVE_HIGH>;
...
value7-gpio = <&gpio 8 GPIO_ACTIVE_HIGH>;

Or this:

// First GPIO is enable, other GPIOs are value
gpios = <&gpio 0 GPIO_ACTIVE_HIGH &gpio 1 GPIO_ACTIVE_HIGH ... &gpio 8
GPIO_ACTIVE_HIGH>;

Most bindings don't need that much sophistication, and for these we
should indeed make sure that they stick to using either the names or
index (and in a consistent manner), but closing the possibility to use
both together may bite us in the end.
Post by Arnd Bergmann
and I also think that for named gpios, we should try to converge on a
common naming scheme. As discussed, we will probably want to support all
the existing ways to do this even with ACPI and with the unified
interface, but it doesn't have to be the obvious way.
Personally, I like the idea that each GPIO has a function, so now that
ACPI fully supports this I'd suggest the policy of using names for
each GPIO (e.g. never use the fallback "gpios" or "gpio" property),
and only ressort to indexes if several GPIOs happen to serve the same
function. I know we haven't reached consensus about this so far, but
it would be nice it we could discuss this point again in the light of
the new ACPI capabilities and come with something to write as a
guideline in the GPIO documentation.
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Arnd Bergmann
2014-10-20 14:26:30 UTC
Permalink
Post by Alexandre Courbot
Post by Arnd Bergmann
Post by Arnd Bergmann
Post by Rafael J. Wysocki
Some drivers need to deal with only firmware representation of its
GPIOs. An example would be a GPIO button array driver where each button
is described as a separate firmware node in device tree. Typically these
child nodes do not have physical representation in the Linux device
model.
In order to help device drivers to handle such firmware child nodes we
add dev[m]_get_named_gpiod_from_child() that takes a child firmware
node pointer as its second argument (the first one is the parent device
itself), finds the GPIO using whatever is the underlying firmware
method, and requests the GPIO properly.
Could we also have a wrapper around this function without a "name" argument,
using just the index?
Expanding on this thought: I think we should mandate for new bindings
that they use either a name and no index, or an index but not name,
I'm afraid this could forbid some useful use-cases, namely the ones
where several GPIOs serve the same function (and are typically set
together). We had a few patch proposals to handle such GPIO groups,
and even though one was in pretty good shape the submitter did not
push it until the end. :/
enable-gpio = <&gpio 0 GPIO_ACTIVE_HIGH>;
value-gpios = <&gpio 1 GPIO_ACTIVE_HIGH ... &gpio 8 GPIO_ACTIVE_HIGH>;
enable-gpio = <&gpio 0 GPIO_ACTIVE_HIGH>;
value0-gpio = <&gpio 1 GPIO_ACTIVE_HIGH>;
...
value7-gpio = <&gpio 8 GPIO_ACTIVE_HIGH>;
// First GPIO is enable, other GPIOs are value
gpios = <&gpio 0 GPIO_ACTIVE_HIGH &gpio 1 GPIO_ACTIVE_HIGH ... &gpio 8
GPIO_ACTIVE_HIGH>;
Most bindings don't need that much sophistication, and for these we
should indeed make sure that they stick to using either the names or
index (and in a consistent manner), but closing the possibility to use
both together may bite us in the end.
I would actually prefer the single-property case here, but I see your
point. Could we make it a strong suggestion rather than a mandatory
requirement for new bindings then?
Post by Alexandre Courbot
Post by Arnd Bergmann
and I also think that for named gpios, we should try to converge on a
common naming scheme. As discussed, we will probably want to support all
the existing ways to do this even with ACPI and with the unified
interface, but it doesn't have to be the obvious way.
Personally, I like the idea that each GPIO has a function, so now that
ACPI fully supports this I'd suggest the policy of using names for
each GPIO (e.g. never use the fallback "gpios" or "gpio" property),
and only ressort to indexes if several GPIOs happen to serve the same
function. I know we haven't reached consensus about this so far, but
it would be nice it we could discuss this point again in the light of
the new ACPI capabilities and come with something to write as a
guideline in the GPIO documentation.
We have enforced naming things for the dmaengine binding, which has
just led to everyone calling things "rx" and "tx". My fear is that
if we start to enforce giving a name, we'd end up with lots of
drivers that use a "gpio-gpios" property or something silly.

Arnd
Rafael J. Wysocki
2014-10-17 12:17:06 UTC
Permalink
From: Rafael J. Wysocki <***@intel.com>

Make use of device property API in this driver so that both OF and ACPI
based system can use the same driver.

This change contains material from Max Eliaser and Mika Westerberg.

Signed-off-by: Mika Westerberg <***@linux.intel.com>
Acked-by: Bryan Wu <***@gmail.com>
Signed-off-by: Rafael J. Wysocki <***@intel.com>
---
drivers/leds/leds-gpio.c | 62 ++++++++++++++++++-----------------------------
1 file changed, 25 insertions(+), 37 deletions(-)

Index: linux-pm/drivers/leds/leds-gpio.c
===================================================================
--- linux-pm.orig/drivers/leds/leds-gpio.c
+++ linux-pm/drivers/leds/leds-gpio.c
@@ -15,13 +15,11 @@
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/leds.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/module.h>
#include <linux/err.h>
+#include <linux/property.h>

struct gpio_led_data {
struct led_classdev cdev;
@@ -171,40 +169,37 @@ static inline int sizeof_gpio_leds_priv(
(sizeof(struct gpio_led_data) * num_leds);
}

-/* Code to create from OpenFirmware platform devices */
-#ifdef CONFIG_OF_GPIO
-static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
+static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
{
- struct device_node *np = pdev->dev.of_node, *child;
+ struct device *dev = &pdev->dev;
+ struct fwnode_handle *child;
struct gpio_leds_priv *priv;
int count, ret;

- /* count LEDs in this device, so we know how much to allocate */
- count = of_get_available_child_count(np);
+ count = device_get_child_node_count(dev);
if (!count)
return ERR_PTR(-ENODEV);

- for_each_available_child_of_node(np, child)
- if (of_get_gpio(child, 0) == -EPROBE_DEFER)
- return ERR_PTR(-EPROBE_DEFER);
-
- priv = devm_kzalloc(&pdev->dev, sizeof_gpio_leds_priv(count),
- GFP_KERNEL);
+ priv = devm_kzalloc(dev, sizeof_gpio_leds_priv(count), GFP_KERNEL);
if (!priv)
return ERR_PTR(-ENOMEM);

- for_each_available_child_of_node(np, child) {
+ device_for_each_child_node(dev, child) {
struct gpio_led led = {};
- enum of_gpio_flags flags;
- const char *state;
+ const char *state = NULL;
+
+ led.gpiod = devm_get_named_gpiod_from_child(dev, child, "gpios", 0);
+ if (IS_ERR(led.gpiod)) {
+ fwnode_handle_put(child);
+ goto err;
+ }
+
+ fwnode_property_read_string(child, "label", &led.name);
+ fwnode_property_read_string(child, "linux,default-trigger",
+ &led.default_trigger);

- led.gpio = of_get_gpio_flags(child, 0, &flags);
- led.active_low = flags & OF_GPIO_ACTIVE_LOW;
- led.name = of_get_property(child, "label", NULL) ? : child->name;
- led.default_trigger =
- of_get_property(child, "linux,default-trigger", NULL);
- state = of_get_property(child, "default-state", NULL);
- if (state) {
+ if (!fwnode_property_read_string(child, "linux,default_state",
+ &state)) {
if (!strcmp(state, "keep"))
led.default_state = LEDS_GPIO_DEFSTATE_KEEP;
else if (!strcmp(state, "on"))
@@ -213,13 +208,13 @@ static struct gpio_leds_priv *gpio_leds_
led.default_state = LEDS_GPIO_DEFSTATE_OFF;
}

- if (of_get_property(child, "retain-state-suspended", NULL))
+ if (fwnode_property_present(child, "retain-state-suspended"))
led.retain_state_suspended = 1;

ret = create_gpio_led(&led, &priv->leds[priv->num_leds++],
- &pdev->dev, NULL);
+ dev, NULL);
if (ret < 0) {
- of_node_put(child);
+ fwnode_handle_put(child);
goto err;
}
}
@@ -238,13 +233,6 @@ static const struct of_device_id of_gpio
};

MODULE_DEVICE_TABLE(of, of_gpio_leds_match);
-#else /* CONFIG_OF_GPIO */
-static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
-{
- return ERR_PTR(-ENODEV);
-}
-#endif /* CONFIG_OF_GPIO */
-

static int gpio_led_probe(struct platform_device *pdev)
{
@@ -273,7 +261,7 @@ static int gpio_led_probe(struct platfor
}
}
} else {
- priv = gpio_leds_create_of(pdev);
+ priv = gpio_leds_create(pdev);
if (IS_ERR(priv))
return PTR_ERR(priv);
}
@@ -300,7 +288,7 @@ static struct platform_driver gpio_led_d
.driver = {
.name = "leds-gpio",
.owner = THIS_MODULE,
- .of_match_table = of_match_ptr(of_gpio_leds_match),
+ .of_match_table = of_gpio_leds_match,
},
};
Rafael J. Wysocki
2014-10-17 12:01:33 UTC
Permalink
Hi Everyone,

Hving had a couple of chats with Grant and Arnd during LinuxCon EU/LPC, we
now have version 5 taking all feedback into account (hopefully).

Changes have been made to patch [02/12] and to patches [09-12/12], although
in patches [10-12/12] they are fairly minor. I have retained the Greg's
ACK on patch [02/12], because it is essentially the same that have been
posted aleady and ACKed by him (Greg, please let me know if I shouldn't
do that) and all the ACKs on the remaining patches except for patch [09/12]
which is substantially different. Still, if reviewers think that their
ACKs don't apply any more, please let me know and I'll remove them.

Patch [02/12] now contains helper functions for all proprerty data types
that can be accessed which call the existing of_ functions, because Grant
preferred that.

Patch [09/12] introduces quite a new concept, which is the struct fwnode_handle
structure containing one field (type) and embedded in struct device_node
(type==FWNODE_OF) and struct acpi_device (type==FWNODE_ACPI). In short, if
we are passed a struct fwnode_handle pointer, we can get from it to the
appropriate device node pointer (either struct acpi_device or struct device_node)
using container_of() after we've checked the type. This is needed for the code
that needs to access child nodes of a device in case when they don't have
struct device representations (whatever the reason). This has been suggested
by Grant and pretty much everyone involved agrees that it's better that the
alternatives presented so far.

For completeness, the previous cover letter is appended below.

Rafael
Hi Everyone,
This is version 4 of the unified device properties interface patchset.
http://marc.info/?l=devicetree&m=141087052200600&w=4
http://marc.info/?l=linux-acpi&m=141212903816560&w=4
One major change from the previous iteration is that now we will
use the "compatible" property to match drivers to devices having
"PRP0001" as their _HID, so for example the at25 driver doesn't
have to add the extra ACPI match table as part of the conversion
to the unified interface (patch [05/13] in this series).
The second major change is that I've split the driver core patch
in two, where the first one ([02/13]) does not contain any stuff
related to iterating over the child nodes of a given device.
Accordingly, the whole patch series has been rearranged so that
the relatively non-controversial patches [01-09/13], most of which
have been ACKed already, go first and then goes the second driver
core patch ([10/13]) and the other patches related to it.
In patches [10-13/13] I used the Arnd's suggestion to implement
device_for_each_child_node() as a macro which makes the changes
in patches [12-13/13] look more straightforward among other things.
I've retained the Greg's ACKs on patches [02/13] and [10/13], because
the first of them is things ACKed by Greg only and the change in the
second one is just an implementation detail in my opinion (Greg, please
let me know if that's inappropriate).
Thanks!
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
Rafael J. Wysocki
2014-10-17 12:03:03 UTC
Permalink
From: Mika Westerberg <***@linux.intel.com>

Device Tree is used in many embedded systems to describe the system
configuration to the OS. It supports attaching properties or name-value
pairs to the devices it describe. With these properties one can pass
additional information to the drivers that would not be available
otherwise.

ACPI is another configuration mechanism (among other things) typically
seen, but not limited to, x86 machines. ACPI allows passing arbitrary
data from methods but there has not been mechanism equivalent to Device
Tree until the introduction of _DSD in the recent publication of the
ACPI 5.1 specification.

In order to facilitate ACPI usage in systems where Device Tree is
typically used, it would be beneficial to standardize a way to retrieve
Device Tree style properties from ACPI devices, which is what we do in
this patch.

If a given device described in ACPI namespace wants to export properties it
must implement _DSD method (Device Specific Data, introduced with ACPI 5.1)
that returns the properties in a package of packages. For example:

Name (_DSD, Package () {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () {"name1", <VALUE1>},
Package () {"name2", <VALUE2>},
...
}
})

The UUID reserved for properties is daffd814-6eba-4d8c-8a91-bc9bbf4aa301
and is documented in the ACPI 5.1 companion document called "_DSD
Implementation Guide" [1], [2].

We add several helper functions that can be used to extract these
properties and convert them to different Linux data types.

The ultimate goal is that we only have one device property API that
retrieves the requested properties from Device Tree or from ACPI
transparent to the caller.

[1] http://www.uefi.org/sites/default/files/resources/_DSD-implementation-guide-toplevel.htm
[2] http://www.uefi.org/sites/default/files/resources/_DSD-device-properties-UUID.pdf

Reviewed-by: Hanjun Guo <***@linaro.org>
Reviewed-by: Josh Triplett <***@joshtriplett.org>
Reviewed-by: Grant Likely <***@linaro.org>
Signed-off-by: Darren Hart <***@linux.intel.com>
Signed-off-by: Mika Westerberg <***@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <***@intel.com>
---
drivers/acpi/Makefile | 1
drivers/acpi/internal.h | 6
drivers/acpi/property.c | 364 ++++++++++++++++++++++++++++++++++++++++++++++++
drivers/acpi/scan.c | 2
include/acpi/acpi_bus.h | 7
include/linux/acpi.h | 40 +++++
6 files changed, 420 insertions(+)
create mode 100644 drivers/acpi/property.c

Index: linux-pm/drivers/acpi/Makefile
===================================================================
--- linux-pm.orig/drivers/acpi/Makefile
+++ linux-pm/drivers/acpi/Makefile
@@ -46,6 +46,7 @@ acpi-y += acpi_pnp.o
acpi-y += power.o
acpi-y += event.o
acpi-y += sysfs.o
+acpi-y += property.o
acpi-$(CONFIG_X86) += acpi_cmos_rtc.o
acpi-$(CONFIG_DEBUG_FS) += debugfs.o
acpi-$(CONFIG_ACPI_NUMA) += numa.o
Index: linux-pm/drivers/acpi/internal.h
===================================================================
--- linux-pm.orig/drivers/acpi/internal.h
+++ linux-pm/drivers/acpi/internal.h
@@ -181,4 +181,10 @@ struct platform_device *acpi_create_plat
bool acpi_osi_is_win8(void);
#endif

+/*--------------------------------------------------------------------------
+ Device properties
+ -------------------------------------------------------------------------- */
+void acpi_init_properties(struct acpi_device *adev);
+void acpi_free_properties(struct acpi_device *adev);
+
#endif /* _ACPI_INTERNAL_H_ */
Index: linux-pm/drivers/acpi/property.c
===================================================================
--- /dev/null
+++ linux-pm/drivers/acpi/property.c
@@ -0,0 +1,364 @@
+/*
+ * ACPI device specific properties support.
+ *
+ * Copyright (C) 2014, Intel Corporation
+ * All rights reserved.
+ *
+ * Authors: Mika Westerberg <***@linux.intel.com>
+ * Darren Hart <***@linux.intel.com>
+ * Rafael J. Wysocki <***@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/export.h>
+
+#include "internal.h"
+
+/* ACPI _DSD device properties UUID: daffd814-6eba-4d8c-8a91-bc9bbf4aa301 */
+static const u8 prp_uuid[16] = {
+ 0x14, 0xd8, 0xff, 0xda, 0xba, 0x6e, 0x8c, 0x4d,
+ 0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01
+};
+
+static bool acpi_property_value_ok(const union acpi_object *value)
+{
+ int j;
+
+ /*
+ * The value must be an integer, a string, a reference, or a package
+ * whose every element must be an integer, a string, or a reference.
+ */
+ switch (value->type) {
+ case ACPI_TYPE_INTEGER:
+ case ACPI_TYPE_STRING:
+ case ACPI_TYPE_LOCAL_REFERENCE:
+ return true;
+
+ case ACPI_TYPE_PACKAGE:
+ for (j = 0; j < value->package.count; j++)
+ switch (value->package.elements[j].type) {
+ case ACPI_TYPE_INTEGER:
+ case ACPI_TYPE_STRING:
+ case ACPI_TYPE_LOCAL_REFERENCE:
+ continue;
+
+ default:
+ return false;
+ }
+
+ return true;
+ }
+ return false;
+}
+
+static bool acpi_properties_format_valid(const union acpi_object *properties)
+{
+ int i;
+
+ for (i = 0; i < properties->package.count; i++) {
+ const union acpi_object *property;
+
+ property = &properties->package.elements[i];
+ /*
+ * Only two elements allowed, the first one must be a string and
+ * the second one has to satisfy certain conditions.
+ */
+ if (property->package.count != 2
+ || property->package.elements[0].type != ACPI_TYPE_STRING
+ || !acpi_property_value_ok(&property->package.elements[1]))
+ return false;
+ }
+ return true;
+}
+
+void acpi_init_properties(struct acpi_device *adev)
+{
+ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
+ const union acpi_object *desc;
+ acpi_status status;
+ int i;
+
+ status = acpi_evaluate_object_typed(adev->handle, "_DSD", NULL, &buf,
+ ACPI_TYPE_PACKAGE);
+ if (ACPI_FAILURE(status))
+ return;
+
+ desc = buf.pointer;
+ if (desc->package.count % 2)
+ goto fail;
+
+ /* Look for the device properties UUID. */
+ for (i = 0; i < desc->package.count; i += 2) {
+ const union acpi_object *uuid, *properties;
+
+ uuid = &desc->package.elements[i];
+ properties = &desc->package.elements[i + 1];
+
+ /*
+ * The first element must be a UUID and the second one must be
+ * a package.
+ */
+ if (uuid->type != ACPI_TYPE_BUFFER || uuid->buffer.length != 16
+ || properties->type != ACPI_TYPE_PACKAGE)
+ break;
+
+ if (memcmp(uuid->buffer.pointer, prp_uuid, sizeof(prp_uuid)))
+ continue;
+
+ /*
+ * We found the matching UUID. Now validate the format of the
+ * package immediately following it.
+ */
+ if (!acpi_properties_format_valid(properties))
+ break;
+
+ adev->data.pointer = buf.pointer;
+ adev->data.properties = properties;
+ return;
+ }
+
+ fail:
+ dev_warn(&adev->dev, "Returned _DSD data is not valid, skipping\n");
+ ACPI_FREE(buf.pointer);
+}
+
+void acpi_free_properties(struct acpi_device *adev)
+{
+ ACPI_FREE((void *)adev->data.pointer);
+ adev->data.pointer = NULL;
+ adev->data.properties = NULL;
+}
+
+/**
+ * acpi_dev_get_property - return an ACPI property with given name
+ * @adev: ACPI device to get property
+ * @name: Name of the property
+ * @type: Expected property type
+ * @obj: Location to store the property value (if not %NULL)
+ *
+ * Look up a property with @name and store a pointer to the resulting ACPI
+ * object at the location pointed to by @obj if found.
+ *
+ * Callers must not attempt to free the returned objects. These objects will be
+ * freed by the ACPI core automatically during the removal of @adev.
+ *
+ * Return: %0 if property with @name has been found (success),
+ * %-EINVAL if the arguments are invalid,
+ * %-ENODATA if the property doesn't exist,
+ * %-EPROTO if the property value type doesn't match @type.
+ */
+int acpi_dev_get_property(struct acpi_device *adev, const char *name,
+ acpi_object_type type, const union acpi_object **obj)
+{
+ const union acpi_object *properties;
+ int i;
+
+ if (!adev || !name)
+ return -EINVAL;
+
+ if (!adev->data.pointer || !adev->data.properties)
+ return -ENODATA;
+
+ properties = adev->data.properties;
+ for (i = 0; i < properties->package.count; i++) {
+ const union acpi_object *propname, *propvalue;
+ const union acpi_object *property;
+
+ property = &properties->package.elements[i];
+
+ propname = &property->package.elements[0];
+ propvalue = &property->package.elements[1];
+
+ if (!strcmp(name, propname->string.pointer)) {
+ if (type != ACPI_TYPE_ANY && propvalue->type != type)
+ return -EPROTO;
+ else if (obj)
+ *obj = propvalue;
+
+ return 0;
+ }
+ }
+ return -ENODATA;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_property);
+
+/**
+ * acpi_dev_get_property_array - return an ACPI array property with given name
+ * @adev: ACPI device to get property
+ * @name: Name of the property
+ * @type: Expected type of array elements
+ * @obj: Location to store a pointer to the property value (if not NULL)
+ *
+ * Look up an array property with @name and store a pointer to the resulting
+ * ACPI object at the location pointed to by @obj if found.
+ *
+ * Callers must not attempt to free the returned objects. Those objects will be
+ * freed by the ACPI core automatically during the removal of @adev.
+ *
+ * Return: %0 if array property (package) with @name has been found (success),
+ * %-EINVAL if the arguments are invalid,
+ * %-ENODATA if the property doesn't exist,
+ * %-EPROTO if the property is not a package or the type of its elements
+ * doesn't match @type.
+ */
+int acpi_dev_get_property_array(struct acpi_device *adev, const char *name,
+ acpi_object_type type,
+ const union acpi_object **obj)
+{
+ const union acpi_object *prop;
+ int ret, i;
+
+ ret = acpi_dev_get_property(adev, name, ACPI_TYPE_PACKAGE, &prop);
+ if (ret)
+ return ret;
+
+ if (type != ACPI_TYPE_ANY) {
+ /* Check that all elements are of correct type. */
+ for (i = 0; i < prop->package.count; i++)
+ if (prop->package.elements[i].type != type)
+ return -EPROTO;
+ }
+ if (obj)
+ *obj = prop;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_property_array);
+
+/**
+ * acpi_dev_get_property_reference - returns handle to the referenced object
+ * @adev: ACPI device to get property
+ * @name: Name of the property
+ * @size_prop: Name of the "size" property in referenced object
+ * @index: Index of the reference to return
+ * @args: Location to store the returned reference with optional arguments
+ *
+ * Find property with @name, verifify that it is a package containing at least
+ * one object reference and if so, store the ACPI device object pointer to the
+ * target object in @args->adev.
+ *
+ * If the reference includes arguments (@size_prop is not %NULL) follow the
+ * reference and check whether or not there is an integer property @size_prop
+ * under the target object and if so, whether or not its value matches the
+ * number of arguments that follow the reference. If there's more than one
+ * reference in the property value package, @index is used to select the one to
+ * return.
+ *
+ * Return: %0 on success, negative error code on failure.
+ */
+int acpi_dev_get_property_reference(struct acpi_device *adev, const char *name,
+ const char *size_prop, size_t index,
+ struct acpi_reference_args *args)
+{
+ const union acpi_object *element, *end;
+ const union acpi_object *obj;
+ struct acpi_device *device;
+ int ret, idx = 0;
+
+ ret = acpi_dev_get_property(adev, name, ACPI_TYPE_ANY, &obj);
+ if (ret)
+ return ret;
+
+ /*
+ * The simplest case is when the value is a single reference. Just
+ * return that reference then.
+ */
+ if (obj->type == ACPI_TYPE_LOCAL_REFERENCE) {
+ if (size_prop || index)
+ return -EINVAL;
+
+ ret = acpi_bus_get_device(obj->reference.handle, &device);
+ if (ret)
+ return ret;
+
+ args->adev = device;
+ args->nargs = 0;
+ return 0;
+ }
+
+ /*
+ * If it is not a single reference, then it is a package of
+ * references followed by number of ints as follows:
+ *
+ * Package () { REF, INT, REF, INT, INT }
+ *
+ * The index argument is then used to determine which reference
+ * the caller wants (along with the arguments).
+ */
+ if (obj->type != ACPI_TYPE_PACKAGE || index >= obj->package.count)
+ return -EPROTO;
+
+ element = obj->package.elements;
+ end = element + obj->package.count;
+
+ while (element < end) {
+ u32 nargs, i;
+
+ if (element->type != ACPI_TYPE_LOCAL_REFERENCE)
+ return -EPROTO;
+
+ ret = acpi_bus_get_device(element->reference.handle, &device);
+ if (ret)
+ return -ENODEV;
+
+ element++;
+ nargs = 0;
+
+ if (size_prop) {
+ const union acpi_object *prop;
+
+ /*
+ * Find out how many arguments the refenced object
+ * expects by reading its size_prop property.
+ */
+ ret = acpi_dev_get_property(device, size_prop,
+ ACPI_TYPE_INTEGER, &prop);
+ if (ret)
+ return ret;
+
+ nargs = prop->integer.value;
+ if (nargs > MAX_ACPI_REFERENCE_ARGS
+ || element + nargs > end)
+ return -EPROTO;
+
+ /*
+ * Skip to the start of the arguments and verify
+ * that they all are in fact integers.
+ */
+ for (i = 0; i < nargs; i++)
+ if (element[i].type != ACPI_TYPE_INTEGER)
+ return -EPROTO;
+ } else {
+ /* assume following integer elements are all args */
+ for (i = 0; element + i < end; i++) {
+ int type = element[i].type;
+
+ if (type == ACPI_TYPE_INTEGER)
+ nargs++;
+ else if (type == ACPI_TYPE_LOCAL_REFERENCE)
+ break;
+ else
+ return -EPROTO;
+ }
+ }
+
+ if (idx++ == index) {
+ args->adev = device;
+ args->nargs = nargs;
+ for (i = 0; i < nargs; i++)
+ args->args[i] = element[i].integer.value;
+
+ return 0;
+ }
+
+ element += nargs;
+ }
+
+ return -EPROTO;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_property_reference);
Index: linux-pm/drivers/acpi/scan.c
===================================================================
--- linux-pm.orig/drivers/acpi/scan.c
+++ linux-pm/drivers/acpi/scan.c
@@ -884,6 +884,7 @@ static void acpi_device_release(struct d
{
struct acpi_device *acpi_dev = to_acpi_device(dev);

+ acpi_free_properties(acpi_dev);
acpi_free_pnp_ids(&acpi_dev->pnp);
acpi_free_power_resources_lists(acpi_dev);
kfree(acpi_dev);
@@ -1888,6 +1889,7 @@ void acpi_init_device_object(struct acpi
acpi_set_device_status(device, sta);
acpi_device_get_busid(device);
acpi_set_pnp_ids(handle, &device->pnp, type);
+ acpi_init_properties(device);
acpi_bus_get_flags(device);
device->flags.match_driver = false;
device->flags.initialized = true;
Index: linux-pm/include/acpi/acpi_bus.h
===================================================================
--- linux-pm.orig/include/acpi/acpi_bus.h
+++ linux-pm/include/acpi/acpi_bus.h
@@ -337,6 +337,12 @@ struct acpi_device_physical_node {
bool put_online:1;
};

+/* ACPI Device Specific Data (_DSD) */
+struct acpi_device_data {
+ const union acpi_object *pointer;
+ const union acpi_object *properties;
+};
+
/* Device */
struct acpi_device {
int device_type;
@@ -353,6 +359,7 @@ struct acpi_device {
struct acpi_device_wakeup wakeup;
struct acpi_device_perf performance;
struct acpi_device_dir dir;
+ struct acpi_device_data data;
struct acpi_scan_handler *handler;
struct acpi_hotplug_context *hp;
struct acpi_driver *driver;
Index: linux-pm/include/linux/acpi.h
===================================================================
--- linux-pm.orig/include/linux/acpi.h
+++ linux-pm/include/linux/acpi.h
@@ -658,4 +658,44 @@ do { \
#endif
#endif

+/* Device properties */
+
+#define MAX_ACPI_REFERENCE_ARGS 8
+struct acpi_reference_args {
+ struct acpi_device *adev;
+ size_t nargs;
+ u64 args[MAX_ACPI_REFERENCE_ARGS];
+};
+
+#ifdef CONFIG_ACPI
+int acpi_dev_get_property(struct acpi_device *adev, const char *name,
+ acpi_object_type type, const union acpi_object **obj);
+int acpi_dev_get_property_array(struct acpi_device *adev, const char *name,
+ acpi_object_type type,
+ const union acpi_object **obj);
+int acpi_dev_get_property_reference(struct acpi_device *adev, const char *name,
+ const char *cells_name, size_t index,
+ struct acpi_reference_args *args);
+#else
+static inline int acpi_dev_get_property(struct acpi_device *adev,
+ const char *name, acpi_object_type type,
+ const union acpi_object **obj)
+{
+ return -ENXIO;
+}
+static inline int acpi_dev_get_property_array(struct acpi_device *adev,
+ const char *name,
+ acpi_object_type type,
+ const union acpi_object **obj)
+{
+ return -ENXIO;
+}
+static inline int acpi_dev_get_property_reference(struct acpi_device *adev,
+ const char *name, const char *cells_name,
+ size_t index, struct acpi_reference_args *args)
+{
+ return -ENXIO;
+}
+#endif
+
#endif /*_LINUX_ACPI_H*/
Rafael J. Wysocki
2014-10-17 12:04:41 UTC
Permalink
From: "Rafael J. Wysocki" <***@intel.com>

Add a uniform interface by which device drivers can request device
properties from the platform firmware by providing a property name
and the corresponding data type. The purpose of it is to help to
write portable code that won't depend on any particular platform
firmware interface.

The following general helper functions are added:

device_property_present()
device_property_read_u8()
device_property_read_u16()
device_property_read_u32()
device_property_read_u64()
device_property_read_string()
device_property_read_u8_array()
device_property_read_u16_array()
device_property_read_u32_array()
device_property_read_u64_array()
device_property_read_string_array()

The first one allows the caller to check if the given property is
present. The next 5 of them allow single-valued properties of
various types to be retrieved in a uniform way. The remaining 5 are
for reading properties with multiple values (arrays of either numbers
or strings).

The interface covers both ACPI and Device Trees.

This change set includes material from Mika Westerberg and Aaron Lu.

Signed-off-by: Aaron Lu <***@intel.com>
Signed-off-by: Mika Westerberg <***@linux.intel.com>
Acked-by: Greg Kroah-Hartman <***@linuxfoundation.org>
Signed-off-by: Rafael J. Wysocki <***@intel.com>
---
drivers/acpi/property.c | 169 ++++++++++++++++++++++++++
drivers/base/Makefile | 2
drivers/base/property.c | 301 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/of/base.c | 106 ++++++++++++++--
include/linux/acpi.h | 32 ++++
include/linux/of.h | 22 +++
include/linux/property.h | 47 +++++++
7 files changed, 662 insertions(+), 17 deletions(-)
create mode 100644 drivers/base/property.c
create mode 100644 include/linux/property.h

Index: linux-pm/include/linux/property.h
===================================================================
--- /dev/null
+++ linux-pm/include/linux/property.h
@@ -0,0 +1,47 @@
+/*
+ * property.h - Unified device property interface.
+ *
+ * Copyright (C) 2014, Intel Corporation
+ * Authors: Rafael J. Wysocki <***@intel.com>
+ * Mika Westerberg <***@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _LINUX_PROPERTY_H_
+#define _LINUX_PROPERTY_H_
+
+#include <linux/types.h>
+
+struct device;
+
+enum dev_prop_type {
+ DEV_PROP_U8,
+ DEV_PROP_U16,
+ DEV_PROP_U32,
+ DEV_PROP_U64,
+ DEV_PROP_STRING,
+ DEV_PROP_MAX,
+};
+
+bool device_property_present(struct device *dev, const char *propname);
+int device_property_read_u8(struct device *dev, const char *propname, u8 *val);
+int device_property_read_u16(struct device *dev, const char *propname, u16 *val);
+int device_property_read_u32(struct device *dev, const char *propname, u32 *val);
+int device_property_read_u64(struct device *dev, const char *propname, u64 *val);
+int device_property_read_string(struct device *dev, const char *propname,
+ const char **val);
+int device_property_read_u8_array(struct device *dev, const char *propname,
+ u8 *val, size_t nval);
+int device_property_read_u16_array(struct device *dev, const char *propname,
+ u16 *val, size_t nval);
+int device_property_read_u32_array(struct device *dev, const char *propname,
+ u32 *val, size_t nval);
+int device_property_read_u64_array(struct device *dev, const char *propname,
+ u64 *val, size_t nval);
+int device_property_read_string_array(struct device *dev, const char *propname,
+ char **val, size_t nval);
+
+#endif /* _LINUX_PROPERTY_H_ */
Index: linux-pm/include/linux/of.h
===================================================================
--- linux-pm.orig/include/linux/of.h
+++ linux-pm/include/linux/of.h
@@ -23,6 +23,7 @@
#include <linux/spinlock.h>
#include <linux/topology.h>
#include <linux/notifier.h>
+#include <linux/property.h>

#include <asm/byteorder.h>
#include <asm/errno.h>
@@ -263,6 +264,10 @@ extern int of_property_read_u32_array(co
size_t sz);
extern int of_property_read_u64(const struct device_node *np,
const char *propname, u64 *out_value);
+extern int of_property_read_u64_array(const struct device_node *np,
+ const char *propname,
+ u64 *out_values,
+ size_t sz);

extern int of_property_read_string(struct device_node *np,
const char *propname,
@@ -275,6 +280,9 @@ extern int of_property_match_string(stru
const char *string);
extern int of_property_count_strings(struct device_node *np,
const char *propname);
+extern int void of_property_read_string_array(struct device_node *np,
+ const char *propname,
+ char **out_strs, size_t sz);
extern int of_device_is_compatible(const struct device_node *device,
const char *);
extern int of_device_is_available(const struct device_node *device);
@@ -479,6 +487,13 @@ static inline int of_property_read_u32_a
return -ENOSYS;
}

+static inline int of_property_read_u64_array(const struct device_node *np,
+ const char *propname,
+ u64 *out_values, size_t sz)
+{
+ return -ENOSYS;
+}
+
static inline int of_property_read_string(struct device_node *np,
const char *propname,
const char **out_string)
@@ -498,6 +513,13 @@ static inline int of_property_count_stri
{
return -ENOSYS;
}
+
+static inline int of_property_read_string_array(struct device_node *np,
+ const char *propname,
+ char **out_strs, size_t sz)
+{
+ return -ENOSYS;
+}

static inline const void *of_get_property(const struct device_node *node,
const char *name,
Index: linux-pm/include/linux/acpi.h
===================================================================
--- linux-pm.orig/include/linux/acpi.h
+++ linux-pm/include/linux/acpi.h
@@ -28,6 +28,7 @@
#include <linux/errno.h>
#include <linux/ioport.h> /* for struct resource */
#include <linux/device.h>
+#include <linux/property.h>

#ifndef _LINUX
#define _LINUX
@@ -676,6 +677,14 @@ int acpi_dev_get_property_array(struct a
int acpi_dev_get_property_reference(struct acpi_device *adev, const char *name,
const char *cells_name, size_t index,
struct acpi_reference_args *args);
+
+int acpi_dev_prop_get(struct acpi_device *adev, const char *propname,
+ void **valptr);
+int acpi_dev_prop_read(struct acpi_device *adev, const char *propname,
+ enum dev_prop_type proptype, void *val);
+int acpi_dev_prop_read_array(struct acpi_device *adev, const char *propname,
+ enum dev_prop_type proptype, void *val,
+ size_t nval);
#else
static inline int acpi_dev_get_property(struct acpi_device *adev,
const char *name, acpi_object_type type,
@@ -696,6 +705,29 @@ static inline int acpi_dev_get_property_
{
return -ENXIO;
}
+
+static inline int acpi_dev_prop_get(struct acpi_device *adev,
+ const char *propname,
+ void **valptr)
+{
+ return -ENXIO;
+}
+
+static inline int acpi_dev_prop_read(struct acpi_device *adev,
+ const char *propname,
+ enum dev_prop_type proptype, void *val)
+{
+ return -ENXIO;
+}
+
+static inline int acpi_dev_prop_read_array(struct acpi_device *adev,
+ const char *propname,
+ enum dev_prop_type proptype,
+ void *val, size_t nval)
+{
+ return -ENXIO;
+}
+
#endif

#endif /*_LINUX_ACPI_H*/
Index: linux-pm/drivers/base/Makefile
===================================================================
--- linux-pm.orig/drivers/base/Makefile
+++ linux-pm/drivers/base/Makefile
@@ -4,7 +4,7 @@ obj-y := component.o core.o bus.o dd.o
driver.o class.o platform.o \
cpu.o firmware.o init.o map.o devres.o \
attribute_container.o transport_class.o \
- topology.o container.o
+ topology.o container.o property.o
obj-$(CONFIG_DEVTMPFS) += devtmpfs.o
obj-$(CONFIG_DMA_CMA) += dma-contiguous.o
obj-y += power/
Index: linux-pm/drivers/base/property.c
===================================================================
--- /dev/null
+++ linux-pm/drivers/base/property.c
@@ -0,0 +1,301 @@
+/*
+ * property.c - Unified device property interface.
+ *
+ * Copyright (C) 2014, Intel Corporation
+ * Authors: Rafael J. Wysocki <***@intel.com>
+ * Mika Westerberg <***@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/property.h>
+#include <linux/export.h>
+#include <linux/acpi.h>
+#include <linux/of.h>
+
+/**
+ * device_property_present - check if a property of a device is present
+ * @dev: Device whose property is being checked
+ * @propname: Name of the property
+ *
+ * Check if property @propname is present in the device firmware description.
+ */
+bool device_property_present(struct device *dev, const char *propname)
+{
+ if (IS_ENABLED(CONFIG_OF) && dev->of_node)
+ return of_property_read_bool(dev->of_node, propname);
+
+ return !acpi_dev_prop_get(ACPI_COMPANION(dev), propname, NULL);
+}
+EXPORT_SYMBOL_GPL(device_property_present);
+
+/**
+ * device_property_read_u8 - return a u8 property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The value is stored here
+ *
+ * Function reads property @propname from the device firmware description and
+ * stores the value into @val if found. The value is checked to be of type u8.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property type is not u8,
+ * %-EOVERFLOW if the property value is out of bounds of u8.
+ */
+int device_property_read_u8(struct device *dev, const char *propname, u8 *val)
+{
+ if (IS_ENABLED(CONFIG_OF) && dev->of_node)
+ return of_property_read_u8(dev->of_node, propname, val);
+
+ return acpi_dev_prop_read(ACPI_COMPANION(dev), propname,
+ DEV_PROP_U8, val);
+}
+EXPORT_SYMBOL_GPL(device_property_read_u8);
+
+/**
+ * device_property_read_u16 - return a u16 property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The value is stored here
+ *
+ * Function reads property @propname from the device firmware description and
+ * stores the value into @val if found. The value is checked to be of type u16.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property type is not u16,
+ * %-EOVERFLOW if the property value is out of bounds of u16.
+ */
+int device_property_read_u16(struct device *dev, const char *propname, u16 *val)
+{
+ if (IS_ENABLED(CONFIG_OF) && dev->of_node)
+ return of_property_read_u16(dev->of_node, propname, val);
+
+ return acpi_dev_prop_read(ACPI_COMPANION(dev), propname,
+ DEV_PROP_U16, val);
+}
+EXPORT_SYMBOL_GPL(device_property_read_u16);
+
+/**
+ * device_property_read_u32 - return a u32 property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The value is stored here
+ *
+ * Function reads property @propname from the device firmware description and
+ * stores the value into @val if found. The value is checked to be of type u32.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property type is not u32,
+ * %-EOVERFLOW if the property value is out of bounds of u32.
+ */
+int device_property_read_u32(struct device *dev, const char *propname, u32 *val)
+{
+ if (IS_ENABLED(CONFIG_OF) && dev->of_node)
+ return of_property_read_u32(dev->of_node, propname, val);
+
+ return acpi_dev_prop_read(ACPI_COMPANION(dev), propname,
+ DEV_PROP_U32, val);
+}
+EXPORT_SYMBOL_GPL(device_property_read_u32);
+
+/**
+ * device_property_read_u64 - return a u64 property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The value is stored here
+ *
+ * Function reads property @propname from the device firmware description and
+ * stores the value into @val if found. The value is checked to be of type u64.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property type is not u64,
+ * %-EOVERFLOW if the property value is out of bounds of u64.
+ */
+int device_property_read_u64(struct device *dev, const char *propname, u64 *val)
+{
+ if (IS_ENABLED(CONFIG_OF) && dev->of_node)
+ return of_property_read_u64(dev->of_node, propname, val);
+
+ return acpi_dev_prop_read(ACPI_COMPANION(dev), propname,
+ DEV_PROP_U64, val);
+}
+EXPORT_SYMBOL_GPL(device_property_read_u64);
+
+/**
+ * device_property_read_string - return a string property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The value is stored here
+ *
+ * Function reads property @propname from the device firmware description and
+ * stores the value into @val if found. The value is checked to be a string.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property type is not a string.
+ */
+int device_property_read_string(struct device *dev, const char *propname,
+ const char **val)
+{
+ if (IS_ENABLED(CONFIG_OF) && dev->of_node)
+ return of_property_read_string(dev->of_node, propname, val);
+
+ return acpi_dev_prop_read(ACPI_COMPANION(dev), propname,
+ DEV_PROP_STRING, val);
+}
+EXPORT_SYMBOL_GPL(device_property_read_string);
+
+#define of_dev_prop_read_array(node, propname, type, val, nval) \
+ (val) ? of_property_read_##type##_array((node), (propname), (val), (nval)) \
+ : of_property_count_elems_of_size((node), (propname), sizeof(type))
+
+/**
+ * device_property_read_u8_array - return a u8 array property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Function reads an array of u8 properties with @propname from the device
+ * firmware description and stores them to @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected.
+ */
+int device_property_read_u8_array(struct device *dev, const char *propname,
+ u8 *val, size_t nval)
+{
+ if (IS_ENABLED(CONFIG_OF) && dev->of_node)
+ return of_dev_prop_read_array(dev->of_node, propname,
+ u8, val, nval);
+
+ return acpi_dev_prop_read_array(ACPI_COMPANION(dev), propname,
+ DEV_PROP_U8, val, nval);
+}
+EXPORT_SYMBOL_GPL(device_property_read_u8_array);
+
+/**
+ * device_property_read_u16_array - return a u16 array property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Function reads an array of u16 properties with @propname from the device
+ * firmware description and stores them to @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected.
+ */
+int device_property_read_u16_array(struct device *dev, const char *propname,
+ u16 *val, size_t nval)
+{
+ if (IS_ENABLED(CONFIG_OF) && dev->of_node)
+ return of_dev_prop_read_array(dev->of_node, propname,
+ u16, val, nval);
+
+ return acpi_dev_prop_read_array(ACPI_COMPANION(dev), propname,
+ DEV_PROP_U16, val, nval);
+}
+EXPORT_SYMBOL_GPL(device_property_read_u16_array);
+
+/**
+ * device_property_read_u32_array - return a u32 array property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Function reads an array of u32 properties with @propname from the device
+ * firmware description and stores them to @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected.
+ */
+int device_property_read_u32_array(struct device *dev, const char *propname,
+ u32 *val, size_t nval)
+{
+ if (IS_ENABLED(CONFIG_OF) && dev->of_node)
+ return of_dev_prop_read_array(dev->of_node, propname,
+ u32, val, nval);
+
+ return acpi_dev_prop_read_array(ACPI_COMPANION(dev), propname,
+ DEV_PROP_U32, val, nval);
+}
+EXPORT_SYMBOL_GPL(device_property_read_u32_array);
+
+/**
+ * device_property_read_u64_array - return a u64 array property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Function reads an array of u64 properties with @propname from the device
+ * firmware description and stores them to @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected.
+ */
+int device_property_read_u64_array(struct device *dev, const char *propname,
+ u64 *val, size_t nval)
+{
+ if (IS_ENABLED(CONFIG_OF) && dev->of_node)
+ return of_dev_prop_read_array(dev->of_node, propname,
+ u64, val, nval);
+
+ return acpi_dev_prop_read_array(ACPI_COMPANION(dev), propname,
+ DEV_PROP_U64, val, nval);
+}
+EXPORT_SYMBOL_GPL(device_property_read_u64_array);
+
+/**
+ * device_property_read_string_array - return a string array property of device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Function reads an array of string properties with @propname from the device
+ * firmware description and stores them to @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property is not an array of strings,
+ * %-EOVERFLOW if the size of the property is not as expected.
+ */
+int device_property_read_string_array(struct device *dev, const char *propname,
+ char **val, size_t nval)
+{
+ if (IS_ENABLED(CONFIG_OF) && dev->of_node)
+ return of_property_read_string_array(dev->of_node, propname,
+ val, nval);
+
+ return acpi_dev_prop_read_array(ACPI_COMPANION(dev), propname,
+ DEV_PROP_STRING, val, nval);
+}
+EXPORT_SYMBOL_GPL(device_property_read_string_array);
Index: linux-pm/drivers/of/base.c
===================================================================
--- linux-pm.orig/drivers/of/base.c
+++ linux-pm/drivers/of/base.c
@@ -1250,6 +1250,39 @@ int of_property_read_u64(const struct de
EXPORT_SYMBOL_GPL(of_property_read_u64);

/**
+ * of_property_read_u64_array - Find and read an array of 64 bit integers
+ * from a property.
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @out_values: pointer to return value, modified only if return value is 0.
+ * @sz: number of array elements to read
+ *
+ * Search for a property in a device node and read 64-bit value(s) from
+ * it. Returns 0 on success, -EINVAL if the property does not exist,
+ * -ENODATA if property does not have a value, and -EOVERFLOW if the
+ * property data isn't large enough.
+ *
+ * The out_values is modified only if a valid u64 value can be decoded.
+ */
+int of_property_read_u64_array(const struct device_node *np,
+ const char *propname, u64 *out_values,
+ size_t sz)
+{
+ const __be32 *val = of_find_property_value_of_size(np, propname,
+ (sz * sizeof(*out_values)));
+
+ if (IS_ERR(val))
+ return PTR_ERR(val);
+
+ while (sz--) {
+ *out_values++ = of_read_number(val, 2);
+ val += 2;
+ };
+ return 0;
+}
+
+/**
* of_property_read_string - Find and read a string from a property
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
@@ -1362,24 +1395,11 @@ int of_property_match_string(struct devi
}
EXPORT_SYMBOL_GPL(of_property_match_string);

-/**
- * of_property_count_strings - Find and return the number of strings from a
- * multiple strings property.
- * @np: device node from which the property value is to be read.
- * @propname: name of the property to be searched.
- *
- * Search for a property in a device tree node and retrieve the number of null
- * terminated string contain in it. Returns the number of strings on
- * success, -EINVAL if the property does not exist, -ENODATA if property
- * does not have a value, and -EILSEQ if the string is not null-terminated
- * within the length of the property data.
- */
-int of_property_count_strings(struct device_node *np, const char *propname)
+static int property_count_strings(struct property *prop)
{
- struct property *prop = of_find_property(np, propname, NULL);
- int i = 0;
- size_t l = 0, total = 0;
const char *p;
+ size_t l = 0, total = 0;
+ int i = 0;

if (!prop)
return -EINVAL;
@@ -1395,8 +1415,62 @@ int of_property_count_strings(struct dev

return i;
}
+
+/**
+ * of_property_count_strings - Find and return the number of strings from a
+ * multiple strings property.
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ *
+ * Search for a property in a device tree node and retrieve the number of null
+ * terminated string contain in it. Returns the number of strings on
+ * success, -EINVAL if the property does not exist, -ENODATA if property
+ * does not have a value, and -EILSEQ if the string is not null-terminated
+ * within the length of the property data.
+ */
+int of_property_count_strings(struct device_node *np, const char *propname)
+{
+ return property_count_strings(of_find_property(np, propname, NULL));
+}
EXPORT_SYMBOL_GPL(of_property_count_strings);

+/**
+ * of_property_read_string_array - Read an array of strings from a multiple
+ * strings property.
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @out_strs: output array of string pointers.
+ * @sz: number of array elements to read.
+ *
+ * Search for a property in a device tree node and retrieve a list of
+ * terminated string values (pointer to data, not a copy) in that property.
+ *
+ * If @out_strs is NULL, the number of strings in the property is returned.
+ */
+int of_property_read_string_array(struct device_node *np, const char *propname,
+ char **out_strs, size_t sz)
+{
+ struct property *prop = of_find_property(np, propname, NULL);
+ char *p = prop->value;
+ size_t total = 0;
+ int i;
+
+ i = property_count_strings(prop);
+ if (!out_strs || i < 0)
+ return i;
+
+ if (i < sz)
+ return -EOVERFLOW;
+
+ while (total < prop->length && i < sz) {
+ size_t l = strlen(p) + 1;
+
+ out_strs[i++] = p;
+ total += l;
+ p += l;
+ }
+}
+
void of_print_phandle_args(const char *msg, const struct of_phandle_args *args)
{
int i;
Index: linux-pm/drivers/acpi/property.c
===================================================================
--- linux-pm.orig/drivers/acpi/property.c
+++ linux-pm/drivers/acpi/property.c
@@ -362,3 +362,172 @@ int acpi_dev_get_property_reference(stru
return -EPROTO;
}
EXPORT_SYMBOL_GPL(acpi_dev_get_property_reference);
+
+int acpi_dev_prop_get(struct acpi_device *adev, const char *propname,
+ void **valptr)
+{
+ return acpi_dev_get_property(adev, propname, ACPI_TYPE_ANY,
+ (const union acpi_object **)valptr);
+}
+
+int acpi_dev_prop_read(struct acpi_device *adev, const char *propname,
+ enum dev_prop_type proptype, void *val)
+{
+ const union acpi_object *obj;
+ int ret = -EINVAL;
+
+ if (!val)
+ return -EINVAL;
+
+ if (proptype >= DEV_PROP_U8 && proptype <= DEV_PROP_U64) {
+ ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_INTEGER, &obj);
+ if (ret)
+ return ret;
+
+ switch (proptype) {
+ case DEV_PROP_U8:
+ if (obj->integer.value > U8_MAX)
+ return -EOVERFLOW;
+ *(u8 *)val = obj->integer.value;
+ break;
+ case DEV_PROP_U16:
+ if (obj->integer.value > U16_MAX)
+ return -EOVERFLOW;
+ *(u16 *)val = obj->integer.value;
+ break;
+ case DEV_PROP_U32:
+ if (obj->integer.value > U32_MAX)
+ return -EOVERFLOW;
+ *(u32 *)val = obj->integer.value;
+ break;
+ default:
+ *(u64 *)val = obj->integer.value;
+ break;
+ }
+ } else if (proptype == DEV_PROP_STRING) {
+ ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_STRING, &obj);
+ if (ret)
+ return ret;
+
+ *(char **)val = obj->string.pointer;
+ }
+ return ret;
+}
+
+static int acpi_copy_property_array_u8(const union acpi_object *items, u8 *val,
+ size_t nval)
+{
+ int i;
+
+ for (i = 0; i < nval; i++) {
+ if (items[i].type != ACPI_TYPE_INTEGER)
+ return -EPROTO;
+ if (items[i].integer.value > U8_MAX)
+ return -EOVERFLOW;
+
+ val[i] = items[i].integer.value;
+ }
+ return 0;
+}
+
+static int acpi_copy_property_array_u16(const union acpi_object *items,
+ u16 *val, size_t nval)
+{
+ int i;
+
+ for (i = 0; i < nval; i++) {
+ if (items[i].type != ACPI_TYPE_INTEGER)
+ return -EPROTO;
+ if (items[i].integer.value > U16_MAX)
+ return -EOVERFLOW;
+
+ val[i] = items[i].integer.value;
+ }
+ return 0;
+}
+
+static int acpi_copy_property_array_u32(const union acpi_object *items,
+ u32 *val, size_t nval)
+{
+ int i;
+
+ for (i = 0; i < nval; i++) {
+ if (items[i].type != ACPI_TYPE_INTEGER)
+ return -EPROTO;
+ if (items[i].integer.value > U32_MAX)
+ return -EOVERFLOW;
+
+ val[i] = items[i].integer.value;
+ }
+ return 0;
+}
+
+static int acpi_copy_property_array_u64(const union acpi_object *items,
+ u64 *val, size_t nval)
+{
+ int i;
+
+ for (i = 0; i < nval; i++) {
+ if (items[i].type != ACPI_TYPE_INTEGER)
+ return -EPROTO;
+
+ val[i] = items[i].integer.value;
+ }
+ return 0;
+}
+
+static int acpi_copy_property_array_string(const union acpi_object *items,
+ char **val, size_t nval)
+{
+ int i;
+
+ for (i = 0; i < nval; i++) {
+ if (items[i].type != ACPI_TYPE_STRING)
+ return -EPROTO;
+
+ val[i] = items[i].string.pointer;
+ }
+ return 0;
+}
+
+int acpi_dev_prop_read_array(struct acpi_device *adev, const char *propname,
+ enum dev_prop_type proptype, void *val,
+ size_t nval)
+{
+ const union acpi_object *obj;
+ const union acpi_object *items;
+ int ret;
+
+ ret = acpi_dev_get_property_array(adev, propname, ACPI_TYPE_ANY, &obj);
+ if (ret)
+ return ret;
+
+ if (!val)
+ return obj->package.count;
+
+ if (nval > obj->package.count)
+ return -EOVERFLOW;
+
+ items = obj->package.elements;
+ switch (proptype) {
+ case DEV_PROP_U8:
+ ret = acpi_copy_property_array_u8(items, (u8 *)val, nval);
+ break;
+ case DEV_PROP_U16:
+ ret = acpi_copy_property_array_u16(items, (u16 *)val, nval);
+ break;
+ case DEV_PROP_U32:
+ ret = acpi_copy_property_array_u32(items, (u32 *)val, nval);
+ break;
+ case DEV_PROP_U64:
+ ret = acpi_copy_property_array_u64(items, (u64 *)val, nval);
+ break;
+ case DEV_PROP_STRING:
+ ret = acpi_copy_property_array_string(items, (char **)val, nval);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
Rafael J. Wysocki
2014-10-20 00:07:31 UTC
Permalink
From: "Rafael J. Wysocki" <***@intel.com>

Add a uniform interface by which device drivers can request device
properties from the platform firmware by providing a property name
and the corresponding data type. The purpose of it is to help to
write portable code that won't depend on any particular platform
firmware interface.

The following general helper functions are added:

device_property_present()
device_property_read_u8()
device_property_read_u16()
device_property_read_u32()
device_property_read_u64()
device_property_read_string()
device_property_read_u8_array()
device_property_read_u16_array()
device_property_read_u32_array()
device_property_read_u64_array()
device_property_read_string_array()

The first one allows the caller to check if the given property is
present. The next 5 of them allow single-valued properties of
various types to be retrieved in a uniform way. The remaining 5 are
for reading properties with multiple values (arrays of either numbers
or strings).

The interface covers both ACPI and Device Trees.

This change set includes material from Mika Westerberg and Aaron Lu.

Signed-off-by: Aaron Lu <***@intel.com>
Signed-off-by: Mika Westerberg <***@linux.intel.com>
Acked-by: Greg Kroah-Hartman <***@linuxfoundation.org>
Signed-off-by: Rafael J. Wysocki <***@intel.com>
---

This adds device_property_read_bool() as a wrapper around device_property_present()
and uses macros to generate the bodies of device_property_read_*(), except for
device_property_read_string_array() that doesn't match the overall scheme exactly.

I believe that the Greg's ACK still applies. :-)

Rafael

---
drivers/acpi/property.c | 169 ++++++++++++++++++++++++++++
drivers/base/Makefile | 2
drivers/base/property.c | 276 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/of/base.c | 106 +++++++++++++++---
include/linux/acpi.h | 32 +++++
include/linux/of.h | 22 +++
include/linux/property.h | 53 +++++++++
7 files changed, 643 insertions(+), 17 deletions(-)
create mode 100644 drivers/base/property.c
create mode 100644 include/linux/property.h

Index: linux-pm/include/linux/property.h
===================================================================
--- /dev/null
+++ linux-pm/include/linux/property.h
@@ -0,0 +1,53 @@
+/*
+ * property.h - Unified device property interface.
+ *
+ * Copyright (C) 2014, Intel Corporation
+ * Authors: Rafael J. Wysocki <***@intel.com>
+ * Mika Westerberg <***@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _LINUX_PROPERTY_H_
+#define _LINUX_PROPERTY_H_
+
+#include <linux/types.h>
+
+struct device;
+
+enum dev_prop_type {
+ DEV_PROP_U8,
+ DEV_PROP_U16,
+ DEV_PROP_U32,
+ DEV_PROP_U64,
+ DEV_PROP_STRING,
+ DEV_PROP_MAX,
+};
+
+bool device_property_present(struct device *dev, const char *propname);
+int device_property_read_u8(struct device *dev, const char *propname, u8 *val);
+int device_property_read_u16(struct device *dev, const char *propname, u16 *val);
+int device_property_read_u32(struct device *dev, const char *propname, u32 *val);
+int device_property_read_u64(struct device *dev, const char *propname, u64 *val);
+int device_property_read_string(struct device *dev, const char *propname,
+ const char **val);
+int device_property_read_u8_array(struct device *dev, const char *propname,
+ u8 *val, size_t nval);
+int device_property_read_u16_array(struct device *dev, const char *propname,
+ u16 *val, size_t nval);
+int device_property_read_u32_array(struct device *dev, const char *propname,
+ u32 *val, size_t nval);
+int device_property_read_u64_array(struct device *dev, const char *propname,
+ u64 *val, size_t nval);
+int device_property_read_string_array(struct device *dev, const char *propname,
+ char **val, size_t nval);
+
+static inline bool device_property_read_bool(struct device *dev,
+ const char *propname)
+{
+ return device_property_present(dev, propname);
+}
+
+#endif /* _LINUX_PROPERTY_H_ */
Index: linux-pm/include/linux/of.h
===================================================================
--- linux-pm.orig/include/linux/of.h
+++ linux-pm/include/linux/of.h
@@ -23,6 +23,7 @@
#include <linux/spinlock.h>
#include <linux/topology.h>
#include <linux/notifier.h>
+#include <linux/property.h>

#include <asm/byteorder.h>
#include <asm/errno.h>
@@ -263,6 +264,10 @@ extern int of_property_read_u32_array(co
size_t sz);
extern int of_property_read_u64(const struct device_node *np,
const char *propname, u64 *out_value);
+extern int of_property_read_u64_array(const struct device_node *np,
+ const char *propname,
+ u64 *out_values,
+ size_t sz);

extern int of_property_read_string(struct device_node *np,
const char *propname,
@@ -275,6 +280,9 @@ extern int of_property_match_string(stru
const char *string);
extern int of_property_count_strings(struct device_node *np,
const char *propname);
+extern int of_property_read_string_array(struct device_node *np,
+ const char *propname,
+ char **out_strs, size_t sz);
extern int of_device_is_compatible(const struct device_node *device,
const char *);
extern int of_device_is_available(const struct device_node *device);
@@ -479,6 +487,13 @@ static inline int of_property_read_u32_a
return -ENOSYS;
}

+static inline int of_property_read_u64_array(const struct device_node *np,
+ const char *propname,
+ u64 *out_values, size_t sz)
+{
+ return -ENOSYS;
+}
+
static inline int of_property_read_string(struct device_node *np,
const char *propname,
const char **out_string)
@@ -498,6 +513,13 @@ static inline int of_property_count_stri
{
return -ENOSYS;
}
+
+static inline int of_property_read_string_array(struct device_node *np,
+ const char *propname,
+ char **out_strs, size_t sz)
+{
+ return -ENOSYS;
+}

static inline const void *of_get_property(const struct device_node *node,
const char *name,
Index: linux-pm/include/linux/acpi.h
===================================================================
--- linux-pm.orig/include/linux/acpi.h
+++ linux-pm/include/linux/acpi.h
@@ -28,6 +28,7 @@
#include <linux/errno.h>
#include <linux/ioport.h> /* for struct resource */
#include <linux/device.h>
+#include <linux/property.h>

#ifndef _LINUX
#define _LINUX
@@ -676,6 +677,14 @@ int acpi_dev_get_property_array(struct a
int acpi_dev_get_property_reference(struct acpi_device *adev, const char *name,
const char *cells_name, size_t index,
struct acpi_reference_args *args);
+
+int acpi_dev_prop_get(struct acpi_device *adev, const char *propname,
+ void **valptr);
+int acpi_dev_prop_read(struct acpi_device *adev, const char *propname,
+ enum dev_prop_type proptype, void *val);
+int acpi_dev_prop_read_array(struct acpi_device *adev, const char *propname,
+ enum dev_prop_type proptype, void *val,
+ size_t nval);
#else
static inline int acpi_dev_get_property(struct acpi_device *adev,
const char *name, acpi_object_type type,
@@ -696,6 +705,29 @@ static inline int acpi_dev_get_property_
{
return -ENXIO;
}
+
+static inline int acpi_dev_prop_get(struct acpi_device *adev,
+ const char *propname,
+ void **valptr)
+{
+ return -ENXIO;
+}
+
+static inline int acpi_dev_prop_read(struct acpi_device *adev,
+ const char *propname,
+ enum dev_prop_type proptype, void *val)
+{
+ return -ENXIO;
+}
+
+static inline int acpi_dev_prop_read_array(struct acpi_device *adev,
+ const char *propname,
+ enum dev_prop_type proptype,
+ void *val, size_t nval)
+{
+ return -ENXIO;
+}
+
#endif

#endif /*_LINUX_ACPI_H*/
Index: linux-pm/drivers/base/Makefile
===================================================================
--- linux-pm.orig/drivers/base/Makefile
+++ linux-pm/drivers/base/Makefile
@@ -4,7 +4,7 @@ obj-y := component.o core.o bus.o dd.o
driver.o class.o platform.o \
cpu.o firmware.o init.o map.o devres.o \
attribute_container.o transport_class.o \
- topology.o container.o
+ topology.o container.o property.o
obj-$(CONFIG_DEVTMPFS) += devtmpfs.o
obj-$(CONFIG_DMA_CMA) += dma-contiguous.o
obj-y += power/
Index: linux-pm/drivers/base/property.c
===================================================================
--- /dev/null
+++ linux-pm/drivers/base/property.c
@@ -0,0 +1,276 @@
+/*
+ * property.c - Unified device property interface.
+ *
+ * Copyright (C) 2014, Intel Corporation
+ * Authors: Rafael J. Wysocki <***@intel.com>
+ * Mika Westerberg <***@linux.intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/property.h>
+#include <linux/export.h>
+#include <linux/acpi.h>
+#include <linux/of.h>
+
+/**
+ * device_property_present - check if a property of a device is present
+ * @dev: Device whose property is being checked
+ * @propname: Name of the property
+ *
+ * Check if property @propname is present in the device firmware description.
+ */
+bool device_property_present(struct device *dev, const char *propname)
+{
+ if (IS_ENABLED(CONFIG_OF) && dev->of_node)
+ return of_property_read_bool(dev->of_node, propname);
+
+ return !acpi_dev_prop_get(ACPI_COMPANION(dev), propname, NULL);
+}
+EXPORT_SYMBOL_GPL(device_property_present);
+
+#define DEVICE_PROPERTY_READ(_dev_, _propname_, _type_, _proptype_, _val_) \
+ IS_ENABLED(CONFIG_OF) && _dev_->of_node ? \
+ of_property_read_##_type_(_dev_->of_node, _propname_, _val_) : \
+ acpi_dev_prop_read(ACPI_COMPANION(_dev_), _propname_, \
+ _proptype_, _val_)
+
+/**
+ * device_property_read_u8 - return a u8 property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The value is stored here
+ *
+ * Function reads property @propname from the device firmware description and
+ * stores the value into @val if found. The value is checked to be of type u8.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property type is not u8,
+ * %-EOVERFLOW if the property value is out of bounds of u8.
+ */
+int device_property_read_u8(struct device *dev, const char *propname, u8 *val)
+{
+ return DEVICE_PROPERTY_READ(dev, propname, u8, DEV_PROP_U8, val);
+}
+EXPORT_SYMBOL_GPL(device_property_read_u8);
+
+/**
+ * device_property_read_u16 - return a u16 property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The value is stored here
+ *
+ * Function reads property @propname from the device firmware description and
+ * stores the value into @val if found. The value is checked to be of type u16.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property type is not u16,
+ * %-EOVERFLOW if the property value is out of bounds of u16.
+ */
+int device_property_read_u16(struct device *dev, const char *propname, u16 *val)
+{
+ return DEVICE_PROPERTY_READ(dev, propname, u16, DEV_PROP_U16, val);
+}
+EXPORT_SYMBOL_GPL(device_property_read_u16);
+
+/**
+ * device_property_read_u32 - return a u32 property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The value is stored here
+ *
+ * Function reads property @propname from the device firmware description and
+ * stores the value into @val if found. The value is checked to be of type u32.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property type is not u32,
+ * %-EOVERFLOW if the property value is out of bounds of u32.
+ */
+int device_property_read_u32(struct device *dev, const char *propname, u32 *val)
+{
+ return DEVICE_PROPERTY_READ(dev, propname, u32, DEV_PROP_U32, val);
+}
+EXPORT_SYMBOL_GPL(device_property_read_u32);
+
+/**
+ * device_property_read_u64 - return a u64 property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The value is stored here
+ *
+ * Function reads property @propname from the device firmware description and
+ * stores the value into @val if found. The value is checked to be of type u64.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property type is not u64,
+ * %-EOVERFLOW if the property value is out of bounds of u64.
+ */
+int device_property_read_u64(struct device *dev, const char *propname, u64 *val)
+{
+ return DEVICE_PROPERTY_READ(dev, propname, u64, DEV_PROP_U64, val);
+}
+EXPORT_SYMBOL_GPL(device_property_read_u64);
+
+/**
+ * device_property_read_string - return a string property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The value is stored here
+ *
+ * Function reads property @propname from the device firmware description and
+ * stores the value into @val if found. The value is checked to be a string.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property type is not a string.
+ */
+int device_property_read_string(struct device *dev, const char *propname,
+ const char **val)
+{
+ return DEVICE_PROPERTY_READ(dev, propname, string, DEV_PROP_STRING, val);
+}
+EXPORT_SYMBOL_GPL(device_property_read_string);
+
+#define OF_DEV_PROP_READ_ARRAY(node, propname, type, val, nval) \
+ (val) ? of_property_read_##type##_array((node), (propname), (val), (nval)) \
+ : of_property_count_elems_of_size((node), (propname), sizeof(type))
+
+#define DEVICE_PROPERTY_READ_ARRAY(_dev_, _propname_, _type_, _proptype_, _val_, _nval_) \
+ IS_ENABLED(CONFIG_OF) && _dev_->of_node ? \
+ (OF_DEV_PROP_READ_ARRAY(_dev_->of_node, _propname_, _type_, \
+ _val_, _nval_)) : \
+ acpi_dev_prop_read_array(ACPI_COMPANION(_dev_), _propname_, \
+ _proptype_, _val_, _nval_)
+
+/**
+ * device_property_read_u8_array - return a u8 array property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Function reads an array of u8 properties with @propname from the device
+ * firmware description and stores them to @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected.
+ */
+int device_property_read_u8_array(struct device *dev, const char *propname,
+ u8 *val, size_t nval)
+{
+ return DEVICE_PROPERTY_READ_ARRAY(dev, propname, u8, DEV_PROP_U8, val,
+ nval);
+}
+EXPORT_SYMBOL_GPL(device_property_read_u8_array);
+
+/**
+ * device_property_read_u16_array - return a u16 array property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Function reads an array of u16 properties with @propname from the device
+ * firmware description and stores them to @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected.
+ */
+int device_property_read_u16_array(struct device *dev, const char *propname,
+ u16 *val, size_t nval)
+{
+ return DEVICE_PROPERTY_READ_ARRAY(dev, propname, u16, DEV_PROP_U16, val,
+ nval);
+}
+EXPORT_SYMBOL_GPL(device_property_read_u16_array);
+
+/**
+ * device_property_read_u32_array - return a u32 array property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Function reads an array of u32 properties with @propname from the device
+ * firmware description and stores them to @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected.
+ */
+int device_property_read_u32_array(struct device *dev, const char *propname,
+ u32 *val, size_t nval)
+{
+ return DEVICE_PROPERTY_READ_ARRAY(dev, propname, u32, DEV_PROP_U32, val,
+ nval);
+}
+EXPORT_SYMBOL_GPL(device_property_read_u32_array);
+
+/**
+ * device_property_read_u64_array - return a u64 array property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Function reads an array of u64 properties with @propname from the device
+ * firmware description and stores them to @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected.
+ */
+int device_property_read_u64_array(struct device *dev, const char *propname,
+ u64 *val, size_t nval)
+{
+ return DEVICE_PROPERTY_READ_ARRAY(dev, propname, u64, DEV_PROP_U64, val,
+ nval);
+}
+EXPORT_SYMBOL_GPL(device_property_read_u64_array);
+
+/**
+ * device_property_read_string_array - return a string array property of device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Function reads an array of string properties with @propname from the device
+ * firmware description and stores them to @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property is not an array of strings,
+ * %-EOVERFLOW if the size of the property is not as expected.
+ */
+int device_property_read_string_array(struct device *dev, const char *propname,
+ char **val, size_t nval)
+{
+ return IS_ENABLED(CONFIG_OF) && dev->of_node ?
+ of_property_read_string_array(dev->of_node, propname, val, nval) :
+ acpi_dev_prop_read_array(ACPI_COMPANION(dev), propname,
+ DEV_PROP_STRING, val, nval);
+}
+EXPORT_SYMBOL_GPL(device_property_read_string_array);
Index: linux-pm/drivers/of/base.c
===================================================================
--- linux-pm.orig/drivers/of/base.c
+++ linux-pm/drivers/of/base.c
@@ -1247,6 +1247,39 @@ int of_property_read_u64(const struct de
EXPORT_SYMBOL_GPL(of_property_read_u64);

/**
+ * of_property_read_u64_array - Find and read an array of 64 bit integers
+ * from a property.
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @out_values: pointer to return value, modified only if return value is 0.
+ * @sz: number of array elements to read
+ *
+ * Search for a property in a device node and read 64-bit value(s) from
+ * it. Returns 0 on success, -EINVAL if the property does not exist,
+ * -ENODATA if property does not have a value, and -EOVERFLOW if the
+ * property data isn't large enough.
+ *
+ * The out_values is modified only if a valid u64 value can be decoded.
+ */
+int of_property_read_u64_array(const struct device_node *np,
+ const char *propname, u64 *out_values,
+ size_t sz)
+{
+ const __be32 *val = of_find_property_value_of_size(np, propname,
+ (sz * sizeof(*out_values)));
+
+ if (IS_ERR(val))
+ return PTR_ERR(val);
+
+ while (sz--) {
+ *out_values++ = of_read_number(val, 2);
+ val += 2;
+ }
+ return 0;
+}
+
+/**
* of_property_read_string - Find and read a string from a property
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
@@ -1359,24 +1392,11 @@ int of_property_match_string(struct devi
}
EXPORT_SYMBOL_GPL(of_property_match_string);

-/**
- * of_property_count_strings - Find and return the number of strings from a
- * multiple strings property.
- * @np: device node from which the property value is to be read.
- * @propname: name of the property to be searched.
- *
- * Search for a property in a device tree node and retrieve the number of null
- * terminated string contain in it. Returns the number of strings on
- * success, -EINVAL if the property does not exist, -ENODATA if property
- * does not have a value, and -EILSEQ if the string is not null-terminated
- * within the length of the property data.
- */
-int of_property_count_strings(struct device_node *np, const char *propname)
+static int property_count_strings(struct property *prop)
{
- struct property *prop = of_find_property(np, propname, NULL);
- int i = 0;
- size_t l = 0, total = 0;
const char *p;
+ size_t l = 0, total = 0;
+ int i = 0;

if (!prop)
return -EINVAL;
@@ -1392,8 +1412,62 @@ int of_property_count_strings(struct dev

return i;
}
+
+/**
+ * of_property_count_strings - Find and return the number of strings from a
+ * multiple strings property.
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ *
+ * Search for a property in a device tree node and retrieve the number of null
+ * terminated string contain in it. Returns the number of strings on
+ * success, -EINVAL if the property does not exist, -ENODATA if property
+ * does not have a value, and -EILSEQ if the string is not null-terminated
+ * within the length of the property data.
+ */
+int of_property_count_strings(struct device_node *np, const char *propname)
+{
+ return property_count_strings(of_find_property(np, propname, NULL));
+}
EXPORT_SYMBOL_GPL(of_property_count_strings);

+/**
+ * of_property_read_string_array - Read an array of strings from a multiple
+ * strings property.
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @out_strs: output array of string pointers.
+ * @sz: number of array elements to read.
+ *
+ * Search for a property in a device tree node and retrieve a list of
+ * terminated string values (pointer to data, not a copy) in that property.
+ *
+ * If @out_strs is NULL, the number of strings in the property is returned.
+ */
+int of_property_read_string_array(struct device_node *np, const char *propname,
+ char **out_strs, size_t sz)
+{
+ struct property *prop = of_find_property(np, propname, NULL);
+ char *p = prop->value;
+ size_t total = 0;
+ int i;
+
+ i = property_count_strings(prop);
+ if (!out_strs || i < 0)
+ return i;
+
+ if (i < sz)
+ return -EOVERFLOW;
+
+ while (total < prop->length && i < sz) {
+ size_t l = strlen(p) + 1;
+
+ out_strs[i++] = p;
+ total += l;
+ p += l;
+ }
+}
+
void of_print_phandle_args(const char *msg, const struct of_phandle_args *args)
{
int i;
Index: linux-pm/drivers/acpi/property.c
===================================================================
--- linux-pm.orig/drivers/acpi/property.c
+++ linux-pm/drivers/acpi/property.c
@@ -362,3 +362,172 @@ int acpi_dev_get_property_reference(stru
return -EPROTO;
}
EXPORT_SYMBOL_GPL(acpi_dev_get_property_reference);
+
+int acpi_dev_prop_get(struct acpi_device *adev, const char *propname,
+ void **valptr)
+{
+ return acpi_dev_get_property(adev, propname, ACPI_TYPE_ANY,
+ (const union acpi_object **)valptr);
+}
+
+int acpi_dev_prop_read(struct acpi_device *adev, const char *propname,
+ enum dev_prop_type proptype, void *val)
+{
+ const union acpi_object *obj;
+ int ret = -EINVAL;
+
+ if (!val)
+ return -EINVAL;
+
+ if (proptype >= DEV_PROP_U8 && proptype <= DEV_PROP_U64) {
+ ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_INTEGER, &obj);
+ if (ret)
+ return ret;
+
+ switch (proptype) {
+ case DEV_PROP_U8:
+ if (obj->integer.value > U8_MAX)
+ return -EOVERFLOW;
+ *(u8 *)val = obj->integer.value;
+ break;
+ case DEV_PROP_U16:
+ if (obj->integer.value > U16_MAX)
+ return -EOVERFLOW;
+ *(u16 *)val = obj->integer.value;
+ break;
+ case DEV_PROP_U32:
+ if (obj->integer.value > U32_MAX)
+ return -EOVERFLOW;
+ *(u32 *)val = obj->integer.value;
+ break;
+ default:
+ *(u64 *)val = obj->integer.value;
+ break;
+ }
+ } else if (proptype == DEV_PROP_STRING) {
+ ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_STRING, &obj);
+ if (ret)
+ return ret;
+
+ *(char **)val = obj->string.pointer;
+ }
+ return ret;
+}
+
+static int acpi_copy_property_array_u8(const union acpi_object *items, u8 *val,
+ size_t nval)
+{
+ int i;
+
+ for (i = 0; i < nval; i++) {
+ if (items[i].type != ACPI_TYPE_INTEGER)
+ return -EPROTO;
+ if (items[i].integer.value > U8_MAX)
+ return -EOVERFLOW;
+
+ val[i] = items[i].integer.value;
+ }
+ return 0;
+}
+
+static int acpi_copy_property_array_u16(const union acpi_object *items,
+ u16 *val, size_t nval)
+{
+ int i;
+
+ for (i = 0; i < nval; i++) {
+ if (items[i].type != ACPI_TYPE_INTEGER)
+ return -EPROTO;
+ if (items[i].integer.value > U16_MAX)
+ return -EOVERFLOW;
+
+ val[i] = items[i].integer.value;
+ }
+ return 0;
+}
+
+static int acpi_copy_property_array_u32(const union acpi_object *items,
+ u32 *val, size_t nval)
+{
+ int i;
+
+ for (i = 0; i < nval; i++) {
+ if (items[i].type != ACPI_TYPE_INTEGER)
+ return -EPROTO;
+ if (items[i].integer.value > U32_MAX)
+ return -EOVERFLOW;
+
+ val[i] = items[i].integer.value;
+ }
+ return 0;
+}
+
+static int acpi_copy_property_array_u64(const union acpi_object *items,
+ u64 *val, size_t nval)
+{
+ int i;
+
+ for (i = 0; i < nval; i++) {
+ if (items[i].type != ACPI_TYPE_INTEGER)
+ return -EPROTO;
+
+ val[i] = items[i].integer.value;
+ }
+ return 0;
+}
+
+static int acpi_copy_property_array_string(const union acpi_object *items,
+ char **val, size_t nval)
+{
+ int i;
+
+ for (i = 0; i < nval; i++) {
+ if (items[i].type != ACPI_TYPE_STRING)
+ return -EPROTO;
+
+ val[i] = items[i].string.pointer;
+ }
+ return 0;
+}
+
+int acpi_dev_prop_read_array(struct acpi_device *adev, const char *propname,
+ enum dev_prop_type proptype, void *val,
+ size_t nval)
+{
+ const union acpi_object *obj;
+ const union acpi_object *items;
+ int ret;
+
+ ret = acpi_dev_get_property_array(adev, propname, ACPI_TYPE_ANY, &obj);
+ if (ret)
+ return ret;
+
+ if (!val)
+ return obj->package.count;
+
+ if (nval > obj->package.count)
+ return -EOVERFLOW;
+
+ items = obj->package.elements;
+ switch (proptype) {
+ case DEV_PROP_U8:
+ ret = acpi_copy_property_array_u8(items, (u8 *)val, nval);
+ break;
+ case DEV_PROP_U16:
+ ret = acpi_copy_property_array_u16(items, (u16 *)val, nval);
+ break;
+ case DEV_PROP_U32:
+ ret = acpi_copy_property_array_u32(items, (u32 *)val, nval);
+ break;
+ case DEV_PROP_U64:
+ ret = acpi_copy_property_array_u64(items, (u64 *)val, nval);
+ break;
+ case DEV_PROP_STRING:
+ ret = acpi_copy_property_array_string(items, (char **)val, nval);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Rafael J. Wysocki
2014-10-17 12:18:58 UTC
Permalink
From: Aaron Lu <***@intel.com>

Make use of device property API in this driver so that both OF based
system and ACPI based system can use this driver.

Signed-off-by: Aaron Lu <***@intel.com>
Signed-off-by: Mika Westerberg <***@linux.intel.com>
Acked-by: Dmitry Torokhov <***@gmail.com>
Signed-off-by: Rafael J. Wysocki <***@intel.com>
---
drivers/input/keyboard/gpio_keys_polled.c | 73 +++++++++---------------------
1 file changed, 24 insertions(+), 49 deletions(-)

Index: linux-pm/drivers/input/keyboard/gpio_keys_polled.c
===================================================================
--- linux-pm.orig/drivers/input/keyboard/gpio_keys_polled.c
+++ linux-pm/drivers/input/keyboard/gpio_keys_polled.c
@@ -25,9 +25,7 @@
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio_keys.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/of_gpio.h>
+#include <linux/property.h>

#define DRV_NAME "gpio-keys-polled"

@@ -102,21 +100,15 @@ static void gpio_keys_polled_close(struc
pdata->disable(bdev->dev);
}

-#ifdef CONFIG_OF
static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct device *dev)
{
- struct device_node *node, *pp;
struct gpio_keys_platform_data *pdata;
struct gpio_keys_button *button;
+ struct fwnode_handle *child;
int error;
int nbuttons;
- int i;
-
- node = dev->of_node;
- if (!node)
- return NULL;

- nbuttons = of_get_child_count(node);
+ nbuttons = device_get_child_node_count(dev);
if (nbuttons == 0)
return NULL;

@@ -126,52 +118,44 @@ static struct gpio_keys_platform_data *g
return ERR_PTR(-ENOMEM);

pdata->buttons = (struct gpio_keys_button *)(pdata + 1);
- pdata->nbuttons = nbuttons;

- pdata->rep = !!of_get_property(node, "autorepeat", NULL);
- of_property_read_u32(node, "poll-interval", &pdata->poll_interval);
+ pdata->rep = device_property_present(dev, "autorepeat");
+ device_property_read_u32(dev, "poll-interval", &pdata->poll_interval);

- i = 0;
- for_each_child_of_node(node, pp) {
- int gpio;
- enum of_gpio_flags flags;
-
- if (!of_find_property(pp, "gpios", NULL)) {
- pdata->nbuttons--;
- dev_warn(dev, "Found button without gpios\n");
- continue;
- }
+ device_for_each_child_node(dev, child) {
+ struct gpio_desc *desc;

- gpio = of_get_gpio_flags(pp, 0, &flags);
- if (gpio < 0) {
- error = gpio;
+ desc = devm_get_named_gpiod_from_child(dev, child, "gpios", 0);
+ if (IS_ERR(desc)) {
+ error = PTR_ERR(desc);
if (error != -EPROBE_DEFER)
dev_err(dev,
"Failed to get gpio flags, error: %d\n",
error);
+ fwnode_handle_put(child);
return ERR_PTR(error);
}

- button = &pdata->buttons[i++];
-
- button->gpio = gpio;
- button->active_low = flags & OF_GPIO_ACTIVE_LOW;
+ button = &pdata->buttons[pdata->nbuttons++];
+ button->gpiod = desc;

- if (of_property_read_u32(pp, "linux,code", &button->code)) {
- dev_err(dev, "Button without keycode: 0x%x\n",
- button->gpio);
+ if (fwnode_property_read_u32(child, "linux,code", &button->code)) {
+ dev_err(dev, "Button without keycode: %d\n",
+ pdata->nbuttons - 1);
+ fwnode_handle_put(child);
return ERR_PTR(-EINVAL);
}

- button->desc = of_get_property(pp, "label", NULL);
+ fwnode_property_read_string(child, "label", &button->desc);

- if (of_property_read_u32(pp, "linux,input-type", &button->type))
+ if (fwnode_property_read_u32(child, "linux,input-type",
+ &button->type))
button->type = EV_KEY;

- button->wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL);
+ button->wakeup = fwnode_property_present(child, "gpio-key,wakeup");

- if (of_property_read_u32(pp, "debounce-interval",
- &button->debounce_interval))
+ if (fwnode_property_read_u32(child, "debounce-interval",
+ &button->debounce_interval))
button->debounce_interval = 5;
}

@@ -187,15 +171,6 @@ static const struct of_device_id gpio_ke
};
MODULE_DEVICE_TABLE(of, gpio_keys_polled_of_match);

-#else
-
-static inline struct gpio_keys_platform_data *
-gpio_keys_polled_get_devtree_pdata(struct device *dev)
-{
- return NULL;
-}
-#endif
-
static int gpio_keys_polled_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -323,7 +298,7 @@ static struct platform_driver gpio_keys_
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
- .of_match_table = of_match_ptr(gpio_keys_polled_of_match),
+ .of_match_table = gpio_keys_polled_of_match,
},
};
module_platform_driver(gpio_keys_polled_driver);
Rafael J. Wysocki
2014-10-17 12:07:20 UTC
Permalink
From: Mika Westerberg <***@linux.intel.com>

Make use of device property API in this driver so that both DT and ACPI
based systems can use this driver.

Signed-off-by: Mika Westerberg <***@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <***@intel.com>
---
drivers/misc/eeprom/at25.c | 34 +++++++++++++---------------------
1 file changed, 13 insertions(+), 21 deletions(-)

Index: linux-pm/drivers/misc/eeprom/at25.c
===================================================================
--- linux-pm.orig/drivers/misc/eeprom/at25.c
+++ linux-pm/drivers/misc/eeprom/at25.c
@@ -18,7 +18,7 @@

#include <linux/spi/spi.h>
#include <linux/spi/eeprom.h>
-#include <linux/of.h>
+#include <linux/property.h>

/*
* NOTE: this is an *EEPROM* driver. The vagaries of product naming
@@ -301,35 +301,33 @@ static ssize_t at25_mem_write(struct mem

/*-------------------------------------------------------------------------*/

-static int at25_np_to_chip(struct device *dev,
- struct device_node *np,
- struct spi_eeprom *chip)
+static int at25_fw_to_chip(struct device *dev, struct spi_eeprom *chip)
{
u32 val;

memset(chip, 0, sizeof(*chip));
- strncpy(chip->name, np->name, sizeof(chip->name));
+ strncpy(chip->name, "at25", sizeof(chip->name));

- if (of_property_read_u32(np, "size", &val) == 0 ||
- of_property_read_u32(np, "at25,byte-len", &val) == 0) {
+ if (device_property_read_u32(dev, "size", &val) == 0 ||
+ device_property_read_u32(dev, "at25,byte-len", &val) == 0) {
chip->byte_len = val;
} else {
dev_err(dev, "Error: missing \"size\" property\n");
return -ENODEV;
}

- if (of_property_read_u32(np, "pagesize", &val) == 0 ||
- of_property_read_u32(np, "at25,page-size", &val) == 0) {
+ if (device_property_read_u32(dev, "pagesize", &val) == 0 ||
+ device_property_read_u32(dev, "at25,page-size", &val) == 0) {
chip->page_size = (u16)val;
} else {
dev_err(dev, "Error: missing \"pagesize\" property\n");
return -ENODEV;
}

- if (of_property_read_u32(np, "at25,addr-mode", &val) == 0) {
+ if (device_property_read_u32(dev, "at25,addr-mode", &val) == 0) {
chip->flags = (u16)val;
} else {
- if (of_property_read_u32(np, "address-width", &val)) {
+ if (device_property_read_u32(dev, "address-width", &val)) {
dev_err(dev,
"Error: missing \"address-width\" property\n");
return -ENODEV;
@@ -350,7 +348,7 @@ static int at25_np_to_chip(struct device
val);
return -ENODEV;
}
- if (of_find_property(np, "read-only", NULL))
+ if (device_property_present(dev, "read-only"))
chip->flags |= EE_READONLY;
}
return 0;
@@ -360,21 +358,15 @@ static int at25_probe(struct spi_device
{
struct at25_data *at25 = NULL;
struct spi_eeprom chip;
- struct device_node *np = spi->dev.of_node;
int err;
int sr;
int addrlen;

/* Chip description */
if (!spi->dev.platform_data) {
- if (np) {
- err = at25_np_to_chip(&spi->dev, np, &chip);
- if (err)
- return err;
- } else {
- dev_err(&spi->dev, "Error: no chip description\n");
- return -ENODEV;
- }
+ err = at25_fw_to_chip(&spi->dev, &chip);
+ if (err)
+ return err;
} else
chip = *(struct spi_eeprom *)spi->dev.platform_data;
Rafael J. Wysocki
2014-10-17 12:09:06 UTC
Permalink
From: Mika Westerberg <***@linux.intel.com>

With release of ACPI 5.1 and _DSD method we can finally name GPIOs (and
other things as well) returned by _CRS. Previously we were only able to
use integer index to find the corresponding GPIO, which is pretty error
prone if the order changes.

With _DSD we can now query GPIOs using name instead of an integer index,
like the below example shows:

// Bluetooth device with reset and shutdown GPIOs
Device (BTH)
{
Name (_HID, ...)

Name (_CRS, ResourceTemplate ()
{
GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
"\\_SB.GPO0", 0, ResourceConsumer) {15}
GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
"\\_SB.GPO0", 0, ResourceConsumer) {27, 31}
})

Name (_DSD, Package ()
{
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package ()
{
Package () {"reset-gpio", Package() {^BTH, 1, 1, 0 }},
Package () {"shutdown-gpio", Package() {^BTH, 0, 0, 0 }},
}
})
}

The format of the supported GPIO property is:

Package () { "name", Package () { ref, index, pin, active_low }}

ref - The device that has _CRS containing GpioIo()/GpioInt() resources,
typically this is the device itself (BTH in our case).
index - Index of the GpioIo()/GpioInt() resource in _CRS starting from zero.
pin - Pin in the GpioIo()/GpioInt() resource. Typically this is zero.
active_low - If 1 the GPIO is marked as active_low.

Since ACPI GpioIo() resource does not have field saying whether it is
active low or high, the "active_low" argument can be used here. Setting
it to 1 marks the GPIO as active low.

In our Bluetooth example the "reset-gpio" refers to the second GpioIo()
resource, second pin in that resource with the GPIO number of 31.

This patch implements necessary support to gpiolib for extracting GPIOs
using _DSD device properties.

Signed-off-by: Mika Westerberg <***@linux.intel.com>
Acked-by: Linus Walleij <***@linaro.org>
Signed-off-by: Rafael J. Wysocki <***@intel.com>
---
Documentation/acpi/gpio-properties.txt | 52 ++++++++++++++++++++++
drivers/gpio/gpiolib-acpi.c | 78 +++++++++++++++++++++++++++------
drivers/gpio/gpiolib.c | 30 +++++++++++-
drivers/gpio/gpiolib.h | 7 +-
4 files changed, 146 insertions(+), 21 deletions(-)

Index: linux-pm/drivers/gpio/gpiolib-acpi.c
===================================================================
--- linux-pm.orig/drivers/gpio/gpiolib-acpi.c
+++ linux-pm/drivers/gpio/gpiolib-acpi.c
@@ -290,6 +290,7 @@ void acpi_gpiochip_free_interrupts(struc
struct acpi_gpio_lookup {
struct acpi_gpio_info info;
int index;
+ int pin_index;
struct gpio_desc *desc;
int n;
};
@@ -303,13 +304,24 @@ static int acpi_find_gpio(struct acpi_re

if (lookup->n++ == lookup->index && !lookup->desc) {
const struct acpi_resource_gpio *agpio = &ares->data.gpio;
+ int pin_index = lookup->pin_index;
+
+ if (pin_index >= agpio->pin_table_length)
+ return 1;

lookup->desc = acpi_get_gpiod(agpio->resource_source.string_ptr,
- agpio->pin_table[0]);
+ agpio->pin_table[pin_index]);
lookup->info.gpioint =
agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT;
- lookup->info.active_low =
- agpio->polarity == ACPI_ACTIVE_LOW;
+
+ /*
+ * ActiveLow is only specified for GpioInt resource. If
+ * GpioIo is used then the only way to set the flag is
+ * to use _DSD "gpios" property.
+ */
+ if (lookup->info.gpioint)
+ lookup->info.active_low =
+ agpio->polarity == ACPI_ACTIVE_LOW;
}

return 1;
@@ -317,40 +329,75 @@ static int acpi_find_gpio(struct acpi_re

/**
* acpi_get_gpiod_by_index() - get a GPIO descriptor from device resources
- * @dev: pointer to a device to get GPIO from
+ * @adev: pointer to a ACPI device to get GPIO from
+ * @propname: Property name of the GPIO (optional)
* @index: index of GpioIo/GpioInt resource (starting from %0)
* @info: info pointer to fill in (optional)
*
- * Function goes through ACPI resources for @dev and based on @index looks
+ * Function goes through ACPI resources for @adev and based on @index looks
* up a GpioIo/GpioInt resource, translates it to the Linux GPIO descriptor,
* and returns it. @index matches GpioIo/GpioInt resources only so if there
* are total %3 GPIO resources, the index goes from %0 to %2.
*
+ * If @propname is specified the GPIO is looked using device property. In
+ * that case @index is used to select the GPIO entry in the property value
+ * (in case of multiple).
+ *
* If the GPIO cannot be translated or there is an error an ERR_PTR is
* returned.
*
* Note: if the GPIO resource has multiple entries in the pin list, this
* function only returns the first.
*/
-struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index,
+struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
+ const char *propname, int index,
struct acpi_gpio_info *info)
{
struct acpi_gpio_lookup lookup;
struct list_head resource_list;
- struct acpi_device *adev;
- acpi_handle handle;
+ bool active_low = false;
int ret;

- if (!dev)
- return ERR_PTR(-EINVAL);
-
- handle = ACPI_HANDLE(dev);
- if (!handle || acpi_bus_get_device(handle, &adev))
+ if (!adev)
return ERR_PTR(-ENODEV);

memset(&lookup, 0, sizeof(lookup));
lookup.index = index;

+ if (propname) {
+ struct acpi_reference_args args;
+
+ dev_dbg(&adev->dev, "GPIO: looking up %s\n", propname);
+
+ memset(&args, 0, sizeof(args));
+ ret = acpi_dev_get_property_reference(adev, propname, NULL,
+ index, &args);
+ if (ret)
+ return ERR_PTR(ret);
+
+ /*
+ * The property was found and resolved so need to
+ * lookup the GPIO based on returned args instead.
+ */
+ adev = args.adev;
+ if (args.nargs >= 2) {
+ lookup.index = args.args[0];
+ lookup.pin_index = args.args[1];
+ /*
+ * 3rd argument, if present is used to
+ * specify active_low.
+ */
+ if (args.nargs >= 3)
+ active_low = !!args.args[2];
+ }
+
+ dev_dbg(&adev->dev, "GPIO: _DSD returned %s %zd %llu %llu %llu\n",
+ dev_name(&adev->dev), args.nargs,
+ args.args[0], args.args[1], args.args[2]);
+ } else {
+ dev_dbg(&adev->dev, "GPIO: looking up %d in _CRS\n", index);
+ }
+
INIT_LIST_HEAD(&resource_list);
ret = acpi_dev_get_resources(adev, &resource_list, acpi_find_gpio,
&lookup);
@@ -359,8 +406,11 @@ struct gpio_desc *acpi_get_gpiod_by_inde

acpi_dev_free_resource_list(&resource_list);

- if (lookup.desc && info)
+ if (lookup.desc && info) {
*info = lookup.info;
+ if (active_low)
+ info->active_low = active_low;
+ }

return lookup.desc ? lookup.desc : ERR_PTR(-ENOENT);
}
Index: linux-pm/drivers/gpio/gpiolib.c
===================================================================
--- linux-pm.orig/drivers/gpio/gpiolib.c
+++ linux-pm/drivers/gpio/gpiolib.c
@@ -1505,14 +1505,36 @@ static struct gpio_desc *acpi_find_gpio(
unsigned int idx,
enum gpio_lookup_flags *flags)
{
+ static const char * const suffixes[] = { "gpios", "gpio" };
+ struct acpi_device *adev = ACPI_COMPANION(dev);
struct acpi_gpio_info info;
struct gpio_desc *desc;
+ char propname[32];
+ int i;

- desc = acpi_get_gpiod_by_index(dev, idx, &info);
- if (IS_ERR(desc))
- return desc;
+ /* Try first from _DSD */
+ for (i = 0; i < ARRAY_SIZE(suffixes); i++) {
+ if (con_id && strcmp(con_id, "gpios")) {
+ snprintf(propname, sizeof(propname), "%s-%s",
+ con_id, suffixes[i]);
+ } else {
+ snprintf(propname, sizeof(propname), "%s",
+ suffixes[i]);
+ }

- if (info.gpioint && info.active_low)
+ desc = acpi_get_gpiod_by_index(adev, propname, 0, &info);
+ if (!IS_ERR(desc) || (PTR_ERR(desc) == -EPROBE_DEFER))
+ break;
+ }
+
+ /* Then from plain _CRS GPIOs */
+ if (IS_ERR(desc)) {
+ desc = acpi_get_gpiod_by_index(adev, NULL, idx, &info);
+ if (IS_ERR(desc))
+ return desc;
+ }
+
+ if (info.active_low)
*flags |= GPIO_ACTIVE_LOW;

return desc;
Index: linux-pm/drivers/gpio/gpiolib.h
===================================================================
--- linux-pm.orig/drivers/gpio/gpiolib.h
+++ linux-pm/drivers/gpio/gpiolib.h
@@ -34,7 +34,8 @@ void acpi_gpiochip_remove(struct gpio_ch
void acpi_gpiochip_request_interrupts(struct gpio_chip *chip);
void acpi_gpiochip_free_interrupts(struct gpio_chip *chip);

-struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index,
+struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
+ const char *propname, int index,
struct acpi_gpio_info *info);
#else
static inline void acpi_gpiochip_add(struct gpio_chip *chip) { }
@@ -47,8 +48,8 @@ static inline void
acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { }

static inline struct gpio_desc *
-acpi_get_gpiod_by_index(struct device *dev, int index,
- struct acpi_gpio_info *info)
+acpi_get_gpiod_by_index(struct acpi_device *adev, const char *propname,
+ int index, struct acpi_gpio_info *info)
{
return ERR_PTR(-ENOSYS);
}
Index: linux-pm/Documentation/acpi/gpio-properties.txt
===================================================================
--- /dev/null
+++ linux-pm/Documentation/acpi/gpio-properties.txt
@@ -0,0 +1,52 @@
+_DSD Device Properties Related to GPIO
+--------------------------------------
+
+With the release of ACPI 5.1 and the _DSD configuration objecte names
+can finally be given to GPIOs (and other things as well) returned by
+_CRS. Previously, we were only able to use an integer index to find
+the corresponding GPIO, which is pretty error prone (it depends on
+the _CRS output ordering, for example).
+
+With _DSD we can now query GPIOs using a name instead of an integer
+index, like the ASL example below shows:
+
+ // Bluetooth device with reset and shutdown GPIOs
+ Device (BTH)
+ {
+ Name (_HID, ...)
+
+ Name (_CRS, ResourceTemplate ()
+ {
+ GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
+ "\\_SB.GPO0", 0, ResourceConsumer) {15}
+ GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
+ "\\_SB.GPO0", 0, ResourceConsumer) {27, 31}
+ })
+
+ Name (_DSD, Package ()
+ {
+ ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ Package ()
+ {
+ Package () {"reset-gpio", Package() {^BTH, 1, 1, 0 }},
+ Package () {"shutdown-gpio", Package() {^BTH, 0, 0, 0 }},
+ }
+ })
+ }
+
+The format of the supported GPIO property is:
+
+ Package () { "name", Package () { ref, index, pin, active_low }}
+
+ ref - The device that has _CRS containing GpioIo()/GpioInt() resources,
+ typically this is the device itself (BTH in our case).
+ index - Index of the GpioIo()/GpioInt() resource in _CRS starting from zero.
+ pin - Pin in the GpioIo()/GpioInt() resource. Typically this is zero.
+ active_low - If 1 the GPIO is marked as active_low.
+
+Since ACPI GpioIo() resource does not have a field saying whether it is
+active low or high, the "active_low" argument can be used here. Setting
+it to 1 marks the GPIO as active low.
+
+In our Bluetooth example the "reset-gpio" refers to the second GpioIo()
+resource, second pin in that resource with the GPIO number of 31.
Rafael J. Wysocki
2014-10-17 12:10:30 UTC
Permalink
From: Mika Westerberg <***@linux.intel.com>

This is actually a single device with two sets of identical registers,
which just happen to start from a different offset. Instead of having
separate GPIO chips created we consolidate them to be single GPIO chip.

In addition having a single GPIO chip allows us to handle ACPI GPIO
translation in the core in a more generic way, since the two GPIO chips
share the same parent ACPI device.

Signed-off-by: Mika Westerberg <***@linux.intel.com>
Acked-by: Linus Walleij <***@linaro.org>
Signed-off-by: Rafael J. Wysocki <***@intel.com>
---
drivers/gpio/gpio-sch.c | 293 ++++++++++++++++++------------------------------
1 file changed, 112 insertions(+), 181 deletions(-)

diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c
index 41e91d7..99720c8 100644
--- a/drivers/gpio/gpio-sch.c
+++ b/drivers/gpio/gpio-sch.c
@@ -29,290 +29,221 @@

#include <linux/gpio.h>

-static DEFINE_SPINLOCK(gpio_lock);
-
-#define CGEN (0x00)
-#define CGIO (0x04)
-#define CGLV (0x08)
-
-#define RGEN (0x20)
-#define RGIO (0x24)
-#define RGLV (0x28)
-
-static unsigned short gpio_ba;
-
-static int sch_gpio_core_direction_in(struct gpio_chip *gc, unsigned gpio_num)
-{
- u8 curr_dirs;
- unsigned short offset, bit;
-
- spin_lock(&gpio_lock);
-
- offset = CGIO + gpio_num / 8;
- bit = gpio_num % 8;
-
- curr_dirs = inb(gpio_ba + offset);
-
- if (!(curr_dirs & (1 << bit)))
- outb(curr_dirs | (1 << bit), gpio_ba + offset);
+#define GEN 0x00
+#define GIO 0x04
+#define GLV 0x08
+
+struct sch_gpio {
+ struct gpio_chip chip;
+ spinlock_t lock;
+ unsigned short iobase;
+ unsigned short core_base;
+ unsigned short resume_base;
+};

- spin_unlock(&gpio_lock);
- return 0;
-}
+#define to_sch_gpio(c) container_of(c, struct sch_gpio, chip)

-static int sch_gpio_core_get(struct gpio_chip *gc, unsigned gpio_num)
+static unsigned sch_gpio_offset(struct sch_gpio *sch, unsigned gpio,
+ unsigned reg)
{
- int res;
- unsigned short offset, bit;
+ unsigned base = 0;

- offset = CGLV + gpio_num / 8;
- bit = gpio_num % 8;
+ if (gpio >= sch->resume_base) {
+ gpio -= sch->resume_base;
+ base += 0x20;
+ }

- res = !!(inb(gpio_ba + offset) & (1 << bit));
- return res;
+ return base + reg + gpio / 8;
}

-static void sch_gpio_core_set(struct gpio_chip *gc, unsigned gpio_num, int val)
+static unsigned sch_gpio_bit(struct sch_gpio *sch, unsigned gpio)
{
- u8 curr_vals;
- unsigned short offset, bit;
-
- spin_lock(&gpio_lock);
-
- offset = CGLV + gpio_num / 8;
- bit = gpio_num % 8;
-
- curr_vals = inb(gpio_ba + offset);
-
- if (val)
- outb(curr_vals | (1 << bit), gpio_ba + offset);
- else
- outb((curr_vals & ~(1 << bit)), gpio_ba + offset);
- spin_unlock(&gpio_lock);
+ if (gpio >= sch->resume_base)
+ gpio -= sch->resume_base;
+ return gpio % 8;
}

-static int sch_gpio_core_direction_out(struct gpio_chip *gc,
- unsigned gpio_num, int val)
+static void sch_gpio_enable(struct sch_gpio *sch, unsigned gpio)
{
- u8 curr_dirs;
unsigned short offset, bit;
+ u8 enable;

- spin_lock(&gpio_lock);
+ spin_lock(&sch->lock);

- offset = CGIO + gpio_num / 8;
- bit = gpio_num % 8;
-
- curr_dirs = inb(gpio_ba + offset);
- if (curr_dirs & (1 << bit))
- outb(curr_dirs & ~(1 << bit), gpio_ba + offset);
+ offset = sch_gpio_offset(sch, gpio, GEN);
+ bit = sch_gpio_bit(sch, gpio);

- spin_unlock(&gpio_lock);
+ enable = inb(sch->iobase + offset);
+ if (!(enable & (1 << bit)))
+ outb(enable | (1 << bit), sch->iobase + offset);

- /*
- * according to the datasheet, writing to the level register has no
- * effect when GPIO is programmed as input.
- * Actually the the level register is read-only when configured as input.
- * Thus presetting the output level before switching to output is _NOT_ possible.
- * Hence we set the level after configuring the GPIO as output.
- * But we cannot prevent a short low pulse if direction is set to high
- * and an external pull-up is connected.
- */
- sch_gpio_core_set(gc, gpio_num, val);
- return 0;
+ spin_unlock(&sch->lock);
}

-static struct gpio_chip sch_gpio_core = {
- .label = "sch_gpio_core",
- .owner = THIS_MODULE,
- .direction_input = sch_gpio_core_direction_in,
- .get = sch_gpio_core_get,
- .direction_output = sch_gpio_core_direction_out,
- .set = sch_gpio_core_set,
-};
-
-static int sch_gpio_resume_direction_in(struct gpio_chip *gc,
- unsigned gpio_num)
+static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned gpio_num)
{
+ struct sch_gpio *sch = to_sch_gpio(gc);
u8 curr_dirs;
unsigned short offset, bit;

- spin_lock(&gpio_lock);
+ spin_lock(&sch->lock);

- offset = RGIO + gpio_num / 8;
- bit = gpio_num % 8;
+ offset = sch_gpio_offset(sch, gpio_num, GIO);
+ bit = sch_gpio_bit(sch, gpio_num);

- curr_dirs = inb(gpio_ba + offset);
+ curr_dirs = inb(sch->iobase + offset);

if (!(curr_dirs & (1 << bit)))
- outb(curr_dirs | (1 << bit), gpio_ba + offset);
+ outb(curr_dirs | (1 << bit), sch->iobase + offset);

- spin_unlock(&gpio_lock);
+ spin_unlock(&sch->lock);
return 0;
}

-static int sch_gpio_resume_get(struct gpio_chip *gc, unsigned gpio_num)
+static int sch_gpio_get(struct gpio_chip *gc, unsigned gpio_num)
{
+ struct sch_gpio *sch = to_sch_gpio(gc);
+ int res;
unsigned short offset, bit;

- offset = RGLV + gpio_num / 8;
- bit = gpio_num % 8;
+ offset = sch_gpio_offset(sch, gpio_num, GLV);
+ bit = sch_gpio_bit(sch, gpio_num);
+
+ res = !!(inb(sch->iobase + offset) & (1 << bit));

- return !!(inb(gpio_ba + offset) & (1 << bit));
+ return res;
}

-static void sch_gpio_resume_set(struct gpio_chip *gc,
- unsigned gpio_num, int val)
+static void sch_gpio_set(struct gpio_chip *gc, unsigned gpio_num, int val)
{
+ struct sch_gpio *sch = to_sch_gpio(gc);
u8 curr_vals;
unsigned short offset, bit;

- spin_lock(&gpio_lock);
+ spin_lock(&sch->lock);

- offset = RGLV + gpio_num / 8;
- bit = gpio_num % 8;
+ offset = sch_gpio_offset(sch, gpio_num, GLV);
+ bit = sch_gpio_bit(sch, gpio_num);

- curr_vals = inb(gpio_ba + offset);
+ curr_vals = inb(sch->iobase + offset);

if (val)
- outb(curr_vals | (1 << bit), gpio_ba + offset);
+ outb(curr_vals | (1 << bit), sch->iobase + offset);
else
- outb((curr_vals & ~(1 << bit)), gpio_ba + offset);
+ outb((curr_vals & ~(1 << bit)), sch->iobase + offset);

- spin_unlock(&gpio_lock);
+ spin_unlock(&sch->lock);
}

-static int sch_gpio_resume_direction_out(struct gpio_chip *gc,
- unsigned gpio_num, int val)
+static int sch_gpio_direction_out(struct gpio_chip *gc, unsigned gpio_num,
+ int val)
{
+ struct sch_gpio *sch = to_sch_gpio(gc);
u8 curr_dirs;
unsigned short offset, bit;

- offset = RGIO + gpio_num / 8;
- bit = gpio_num % 8;
+ spin_lock(&sch->lock);

- spin_lock(&gpio_lock);
+ offset = sch_gpio_offset(sch, gpio_num, GIO);
+ bit = sch_gpio_bit(sch, gpio_num);

- curr_dirs = inb(gpio_ba + offset);
+ curr_dirs = inb(sch->iobase + offset);
if (curr_dirs & (1 << bit))
- outb(curr_dirs & ~(1 << bit), gpio_ba + offset);
+ outb(curr_dirs & ~(1 << bit), sch->iobase + offset);

- spin_unlock(&gpio_lock);
+ spin_unlock(&sch->lock);

/*
- * according to the datasheet, writing to the level register has no
- * effect when GPIO is programmed as input.
- * Actually the the level register is read-only when configured as input.
- * Thus presetting the output level before switching to output is _NOT_ possible.
- * Hence we set the level after configuring the GPIO as output.
- * But we cannot prevent a short low pulse if direction is set to high
- * and an external pull-up is connected.
- */
- sch_gpio_resume_set(gc, gpio_num, val);
+ * according to the datasheet, writing to the level register has no
+ * effect when GPIO is programmed as input.
+ * Actually the the level register is read-only when configured as input.
+ * Thus presetting the output level before switching to output is _NOT_ possible.
+ * Hence we set the level after configuring the GPIO as output.
+ * But we cannot prevent a short low pulse if direction is set to high
+ * and an external pull-up is connected.
+ */
+ sch_gpio_set(gc, gpio_num, val);
return 0;
}

-static struct gpio_chip sch_gpio_resume = {
- .label = "sch_gpio_resume",
+static struct gpio_chip sch_gpio_chip = {
+ .label = "sch_gpio",
.owner = THIS_MODULE,
- .direction_input = sch_gpio_resume_direction_in,
- .get = sch_gpio_resume_get,
- .direction_output = sch_gpio_resume_direction_out,
- .set = sch_gpio_resume_set,
+ .direction_input = sch_gpio_direction_in,
+ .get = sch_gpio_get,
+ .direction_output = sch_gpio_direction_out,
+ .set = sch_gpio_set,
};

static int sch_gpio_probe(struct platform_device *pdev)
{
+ struct sch_gpio *sch;
struct resource *res;
- int err, id;

- id = pdev->id;
- if (!id)
- return -ENODEV;
+ sch = devm_kzalloc(&pdev->dev, sizeof(*sch), GFP_KERNEL);
+ if (!sch)
+ return -ENOMEM;

res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (!res)
return -EBUSY;

- if (!request_region(res->start, resource_size(res), pdev->name))
+ if (!devm_request_region(&pdev->dev, res->start, resource_size(res),
+ pdev->name))
return -EBUSY;

- gpio_ba = res->start;
+ spin_lock_init(&sch->lock);
+ sch->iobase = res->start;
+ sch->chip = sch_gpio_chip;
+ sch->chip.label = dev_name(&pdev->dev);
+ sch->chip.dev = &pdev->dev;

- switch (id) {
+ switch (pdev->id) {
case PCI_DEVICE_ID_INTEL_SCH_LPC:
- sch_gpio_core.base = 0;
- sch_gpio_core.ngpio = 10;
- sch_gpio_resume.base = 10;
- sch_gpio_resume.ngpio = 4;
+ sch->core_base = 0;
+ sch->resume_base = 10;
+ sch->chip.ngpio = 14;
+
/*
* GPIO[6:0] enabled by default
* GPIO7 is configured by the CMC as SLPIOVR
* Enable GPIO[9:8] core powered gpios explicitly
*/
- outb(0x3, gpio_ba + CGEN + 1);
+ sch_gpio_enable(sch, 8);
+ sch_gpio_enable(sch, 9);
/*
* SUS_GPIO[2:0] enabled by default
* Enable SUS_GPIO3 resume powered gpio explicitly
*/
- outb(0x8, gpio_ba + RGEN);
+ sch_gpio_enable(sch, 13);
break;

case PCI_DEVICE_ID_INTEL_ITC_LPC:
- sch_gpio_core.base = 0;
- sch_gpio_core.ngpio = 5;
- sch_gpio_resume.base = 5;
- sch_gpio_resume.ngpio = 9;
+ sch->core_base = 0;
+ sch->resume_base = 5;
+ sch->chip.ngpio = 14;
break;

case PCI_DEVICE_ID_INTEL_CENTERTON_ILB:
- sch_gpio_core.base = 0;
- sch_gpio_core.ngpio = 21;
- sch_gpio_resume.base = 21;
- sch_gpio_resume.ngpio = 9;
+ sch->core_base = 0;
+ sch->resume_base = 21;
+ sch->chip.ngpio = 30;
break;

default:
- err = -ENODEV;
- goto err_sch_gpio_core;
+ return -ENODEV;
}

- sch_gpio_core.dev = &pdev->dev;
- sch_gpio_resume.dev = &pdev->dev;
-
- err = gpiochip_add(&sch_gpio_core);
- if (err < 0)
- goto err_sch_gpio_core;
+ platform_set_drvdata(pdev, sch);

- err = gpiochip_add(&sch_gpio_resume);
- if (err < 0)
- goto err_sch_gpio_resume;
-
- return 0;
-
-err_sch_gpio_resume:
- gpiochip_remove(&sch_gpio_core);
-
-err_sch_gpio_core:
- release_region(res->start, resource_size(res));
- gpio_ba = 0;
-
- return err;
+ return gpiochip_add(&sch->chip);
}

static int sch_gpio_remove(struct platform_device *pdev)
{
- struct resource *res;
- if (gpio_ba) {
-
- gpiochip_remove(&sch_gpio_core);
- gpiochip_remove(&sch_gpio_resume);
-
- res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-
- release_region(res->start, resource_size(res));
- gpio_ba = 0;
- }
+ struct sch_gpio *sch = platform_get_drvdata(pdev);

+ gpiochip_remove(&sch->chip);
return 0;
}
--
1.9.3
Rafael J. Wysocki
2014-10-17 12:11:27 UTC
Permalink
From: Mika Westerberg <***@linux.intel.com>

GPIO descriptors are the preferred way over legacy GPIO numbers
nowadays. Convert the driver to use GPIO descriptors internally but
still allow passing legacy GPIO numbers from platform data to support
existing platforms.

Signed-off-by: Mika Westerberg <***@linux.intel.com>
Acked-by: Alexandre Courbot <***@nvidia.com>
Acked-by: Bryan Wu <***@gmail.com>
Signed-off-by: Rafael J. Wysocki <***@intel.com>
---
drivers/leds/leds-gpio.c | 80 ++++++++++++++++++++++++++---------------------
include/linux/leds.h | 1
2 files changed, 46 insertions(+), 35 deletions(-)

Index: linux-pm/drivers/leds/leds-gpio.c
===================================================================
--- linux-pm.orig/drivers/leds/leds-gpio.c
+++ linux-pm/drivers/leds/leds-gpio.c
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/leds.h>
#include <linux/of.h>
#include <linux/of_platform.h>
@@ -24,11 +25,10 @@

struct gpio_led_data {
struct led_classdev cdev;
- unsigned gpio;
+ struct gpio_desc *gpiod;
struct work_struct work;
u8 new_level;
u8 can_sleep;
- u8 active_low;
u8 blinking;
int (*platform_gpio_blink_set)(unsigned gpio, int state,
unsigned long *delay_on, unsigned long *delay_off);
@@ -40,12 +40,16 @@ static void gpio_led_work(struct work_st
container_of(work, struct gpio_led_data, work);

if (led_dat->blinking) {
- led_dat->platform_gpio_blink_set(led_dat->gpio,
- led_dat->new_level,
- NULL, NULL);
+ int gpio = desc_to_gpio(led_dat->gpiod);
+ int level = led_dat->new_level;
+
+ if (gpiod_is_active_low(led_dat->gpiod))
+ level = !level;
+
+ led_dat->platform_gpio_blink_set(gpio, level, NULL, NULL);
led_dat->blinking = 0;
} else
- gpio_set_value_cansleep(led_dat->gpio, led_dat->new_level);
+ gpiod_set_value_cansleep(led_dat->gpiod, led_dat->new_level);
}

static void gpio_led_set(struct led_classdev *led_cdev,
@@ -60,9 +64,6 @@ static void gpio_led_set(struct led_clas
else
level = 1;

- if (led_dat->active_low)
- level = !level;
-
/* Setting GPIOs with I2C/etc requires a task context, and we don't
* seem to have a reliable way to know if we're already in one; so
* let's just assume the worst.
@@ -72,11 +73,16 @@ static void gpio_led_set(struct led_clas
schedule_work(&led_dat->work);
} else {
if (led_dat->blinking) {
- led_dat->platform_gpio_blink_set(led_dat->gpio, level,
- NULL, NULL);
+ int gpio = desc_to_gpio(led_dat->gpiod);
+
+ if (gpiod_is_active_low(led_dat->gpiod))
+ level = !level;
+
+ led_dat->platform_gpio_blink_set(gpio, level, NULL,
+ NULL);
led_dat->blinking = 0;
} else
- gpio_set_value(led_dat->gpio, level);
+ gpiod_set_value(led_dat->gpiod, level);
}
}

@@ -85,9 +91,10 @@ static int gpio_blink_set(struct led_cla
{
struct gpio_led_data *led_dat =
container_of(led_cdev, struct gpio_led_data, cdev);
+ int gpio = desc_to_gpio(led_dat->gpiod);

led_dat->blinking = 1;
- return led_dat->platform_gpio_blink_set(led_dat->gpio, GPIO_LED_BLINK,
+ return led_dat->platform_gpio_blink_set(gpio, GPIO_LED_BLINK,
delay_on, delay_off);
}

@@ -97,24 +104,33 @@ static int create_gpio_led(const struct
{
int ret, state;

- led_dat->gpio = -1;
+ if (!template->gpiod) {
+ unsigned long flags = 0;

- /* skip leds that aren't available */
- if (!gpio_is_valid(template->gpio)) {
- dev_info(parent, "Skipping unavailable LED gpio %d (%s)\n",
- template->gpio, template->name);
- return 0;
+ /* skip leds that aren't available */
+ if (!gpio_is_valid(template->gpio)) {
+ dev_info(parent, "Skipping unavailable LED gpio %d (%s)\n",
+ template->gpio, template->name);
+ return 0;
+ }
+
+ if (template->active_low)
+ flags |= GPIOF_ACTIVE_LOW;
+
+ ret = devm_gpio_request_one(parent, template->gpio, flags,
+ template->name);
+ if (ret < 0)
+ return ret;
+
+ led_dat->gpiod = gpio_to_desc(template->gpio);
+ if (IS_ERR(led_dat->gpiod))
+ return PTR_ERR(led_dat->gpiod);
}

- ret = devm_gpio_request(parent, template->gpio, template->name);
- if (ret < 0)
- return ret;
-
led_dat->cdev.name = template->name;
led_dat->cdev.default_trigger = template->default_trigger;
- led_dat->gpio = template->gpio;
- led_dat->can_sleep = gpio_cansleep(template->gpio);
- led_dat->active_low = template->active_low;
+ led_dat->gpiod = template->gpiod;
+ led_dat->can_sleep = gpiod_cansleep(template->gpiod);
led_dat->blinking = 0;
if (blink_set) {
led_dat->platform_gpio_blink_set = blink_set;
@@ -122,30 +138,24 @@ static int create_gpio_led(const struct
}
led_dat->cdev.brightness_set = gpio_led_set;
if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP)
- state = !!gpio_get_value_cansleep(led_dat->gpio) ^ led_dat->active_low;
+ state = !!gpiod_get_value_cansleep(led_dat->gpiod);
else
state = (template->default_state == LEDS_GPIO_DEFSTATE_ON);
led_dat->cdev.brightness = state ? LED_FULL : LED_OFF;
if (!template->retain_state_suspended)
led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;

- ret = gpio_direction_output(led_dat->gpio, led_dat->active_low ^ state);
+ ret = gpiod_direction_output(led_dat->gpiod, state);
if (ret < 0)
return ret;

INIT_WORK(&led_dat->work, gpio_led_work);

- ret = led_classdev_register(parent, &led_dat->cdev);
- if (ret < 0)
- return ret;
-
- return 0;
+ return led_classdev_register(parent, &led_dat->cdev);
}

static void delete_gpio_led(struct gpio_led_data *led)
{
- if (!gpio_is_valid(led->gpio))
- return;
led_classdev_unregister(&led->cdev);
cancel_work_sync(&led->work);
}
Index: linux-pm/include/linux/leds.h
===================================================================
--- linux-pm.orig/include/linux/leds.h
+++ linux-pm/include/linux/leds.h
@@ -251,6 +251,7 @@ struct gpio_led {
unsigned retain_state_suspended : 1;
unsigned default_state : 2;
/* default_state should be one of LEDS_GPIO_DEFSTATE_(ON|OFF|KEEP) */
+ struct gpio_desc *gpiod;
};
#define LEDS_GPIO_DEFSTATE_OFF 0
#define LEDS_GPIO_DEFSTATE_ON 1
Rafael J. Wysocki
2014-10-17 12:12:54 UTC
Permalink
From: Aaron Lu <***@intel.com>

GPIO descriptors are the preferred way over legacy GPIO numbers
nowadays. Convert the driver to use GPIO descriptors internally but
still allow passing legacy GPIO numbers from platform data to support
existing platforms.

Signed-off-by: Aaron Lu <***@intel.com>
Signed-off-by: Mika Westerberg <***@linux.intel.com>
Acked-by: Alexandre Courbot <***@nvidia.com>
Reviewed-by: Linus Walleij <***@linaro.org>
Acked-by: Dmitry Torokhov <***@gmail.com>
Signed-off-by: Rafael J. Wysocki <***@intel.com>
---
drivers/input/keyboard/gpio_keys_polled.c | 39 +++++++++++++++++++++----------
include/linux/gpio_keys.h | 3 +++
2 files changed, 30 insertions(+), 12 deletions(-)

diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c
index 432d363..b7a514c 100644
--- a/drivers/input/keyboard/gpio_keys_polled.c
+++ b/drivers/input/keyboard/gpio_keys_polled.c
@@ -23,6 +23,7 @@
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/gpio_keys.h>
#include <linux/of.h>
#include <linux/of_platform.h>
@@ -51,15 +52,14 @@ static void gpio_keys_polled_check_state(struct input_dev *input,
int state;

if (bdata->can_sleep)
- state = !!gpio_get_value_cansleep(button->gpio);
+ state = !!gpiod_get_value_cansleep(button->gpiod);
else
- state = !!gpio_get_value(button->gpio);
+ state = !!gpiod_get_value(button->gpiod);

if (state != bdata->last_state) {
unsigned int type = button->type ?: EV_KEY;

- input_event(input, type, button->code,
- !!(state ^ button->active_low));
+ input_event(input, type, button->code, state);
input_sync(input);
bdata->count = 0;
bdata->last_state = state;
@@ -259,7 +259,6 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
for (i = 0; i < pdata->nbuttons; i++) {
struct gpio_keys_button *button = &pdata->buttons[i];
struct gpio_keys_button_data *bdata = &bdev->data[i];
- unsigned int gpio = button->gpio;
unsigned int type = button->type ?: EV_KEY;

if (button->wakeup) {
@@ -267,15 +266,31 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
return -EINVAL;
}

- error = devm_gpio_request_one(&pdev->dev, gpio, GPIOF_IN,
- button->desc ? : DRV_NAME);
- if (error) {
- dev_err(dev, "unable to claim gpio %u, err=%d\n",
- gpio, error);
- return error;
+ /*
+ * Legacy GPIO number so request the GPIO here and
+ * convert it to descriptor.
+ */
+ if (!button->gpiod && gpio_is_valid(button->gpio)) {
+ unsigned flags = 0;
+
+ if (button->active_low)
+ flags |= GPIOF_ACTIVE_LOW;
+
+ error = devm_gpio_request_one(&pdev->dev, button->gpio,
+ flags, button->desc ? : DRV_NAME);
+ if (error) {
+ dev_err(dev, "unable to claim gpio %u, err=%d\n",
+ button->gpio, error);
+ return error;
+ }
+
+ button->gpiod = gpio_to_desc(button->gpio);
}

- bdata->can_sleep = gpio_cansleep(gpio);
+ if (IS_ERR(button->gpiod))
+ return PTR_ERR(button->gpiod);
+
+ bdata->can_sleep = gpiod_cansleep(button->gpiod);
bdata->last_state = -1;
bdata->threshold = DIV_ROUND_UP(button->debounce_interval,
pdata->poll_interval);
diff --git a/include/linux/gpio_keys.h b/include/linux/gpio_keys.h
index 8b62246..ee2d8c6 100644
--- a/include/linux/gpio_keys.h
+++ b/include/linux/gpio_keys.h
@@ -2,6 +2,7 @@
#define _GPIO_KEYS_H

struct device;
+struct gpio_desc;

/**
* struct gpio_keys_button - configuration parameters
@@ -17,6 +18,7 @@ struct device;
* disable button via sysfs
* @value: axis value for %EV_ABS
* @irq: Irq number in case of interrupt keys
+ * @gpiod: GPIO descriptor
*/
struct gpio_keys_button {
unsigned int code;
@@ -29,6 +31,7 @@ struct gpio_keys_button {
bool can_disable;
int value;
unsigned int irq;
+ struct gpio_desc *gpiod;
};

/**
--
1.9.3


--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Rafael J. Wysocki
2014-10-17 12:14:53 UTC
Permalink
From: Rafael J. Wysocki <***@intel.com>

Add new generic routines are provided for retrieving properties from
device description objects in the platform firmware in case there are
no struct device objects for them (either those objects have not been
created yet or they do not exist at all).

The following functions are provided:

fwnode_property_present()
fwnode_property_read_u8()
fwnode_property_read_u16()
fwnode_property_read_u32()
fwnode_property_read_u64()
fwnode_property_read_string()
fwnode_property_read_u8_array()
fwnode_property_read_u16_array()
fwnode_property_read_u32_array()
fwnode_property_read_u64_array()
fwnode_property_read_string_array()

in analogy with the corresponding functions for struct device added
previously. For all of them, the first argument is a pointer to struct
fwnode_handle (new type) that allows a device description object
(depending on what platform firmware interface is in use) to be
obtained.

Add a new macro device_for_each_child_node() for iterating over the
children of the device description object associated with a given
device and a new function device_get_child_node_count() returning the
number of a given device's child nodes.

The interface covers both ACPI and Device Trees.

Suggested-by: Grant Likely <***@linaro.org>
Signed-off-by: Rafael J. Wysocki <***@intel.com>
---
drivers/acpi/scan.c | 21 ++
drivers/base/property.c | 373 +++++++++++++++++++++++++++++++++++++++++++++++
include/acpi/acpi_bus.h | 12 +
include/linux/acpi.h | 21 ++
include/linux/of.h | 22 ++
include/linux/property.h | 48 ++++++
6 files changed, 497 insertions(+)

Index: linux-pm/include/linux/property.h
===================================================================
--- linux-pm.orig/include/linux/property.h
+++ linux-pm/include/linux/property.h
@@ -44,4 +44,52 @@ int device_property_read_u64_array(struc
int device_property_read_string_array(struct device *dev, const char *propname,
char **val, size_t nval);

+enum fwnode_type {
+ FWNODE_INVALID = 0,
+ FWNODE_OF,
+ FWNODE_ACPI,
+};
+
+struct fwnode_handle {
+ enum fwnode_type type;
+};
+
+bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname);
+int fwnode_property_read_u8(struct fwnode_handle *fwnode, const char *propname,
+ u8 *val);
+int fwnode_property_read_u16(struct fwnode_handle *fwnode, const char *propname,
+ u16 *val);
+int fwnode_property_read_u32(struct fwnode_handle *fwnode, const char *propname,
+ u32 *val);
+int fwnode_property_read_u64(struct fwnode_handle *fwnode, const char *propname,
+ u64 *val);
+int fwnode_property_read_string(struct fwnode_handle *fwnode,
+ const char *propname, const char **val);
+int fwnode_property_read_u8_array(struct fwnode_handle *fwnode,
+ const char *propname, u8 *val,
+ size_t nval);
+int fwnode_property_read_u16_array(struct fwnode_handle *fwnode,
+ const char *propname, u16 *val,
+ size_t nval);
+int fwnode_property_read_u32_array(struct fwnode_handle *fwnode,
+ const char *propname, u32 *val,
+ size_t nval);
+int fwnode_property_read_u64_array(struct fwnode_handle *fwnode,
+ const char *propname, u64 *val,
+ size_t nval);
+int fwnode_property_read_string_array(struct fwnode_handle *fwnode,
+ const char *propname, char **val,
+ size_t nval);
+
+struct fwnode_handle *device_get_next_child_node(struct device *dev,
+ struct fwnode_handle *child);
+
+#define device_for_each_child_node(dev, child) \
+ for (child = device_get_next_child_node(dev, NULL); child; \
+ child = device_get_next_child_node(dev, child))
+
+void fwnode_handle_put(struct fwnode_handle *fwnode);
+
+unsigned int device_get_child_node_count(struct device *dev);
+
#endif /* _LINUX_PROPERTY_H_ */
Index: linux-pm/include/acpi/acpi_bus.h
===================================================================
--- linux-pm.orig/include/acpi/acpi_bus.h
+++ linux-pm/include/acpi/acpi_bus.h
@@ -27,6 +27,7 @@
#define __ACPI_BUS_H__

#include <linux/device.h>
+#include <linux/property.h>

/* TBD: Make dynamic */
#define ACPI_MAX_HANDLES 10
@@ -348,6 +349,7 @@ struct acpi_device_data {
struct acpi_device {
int device_type;
acpi_handle handle; /* no handle for fixed hardware */
+ struct fwnode_handle fwnode;
struct acpi_device *parent;
struct list_head children;
struct list_head node;
@@ -372,6 +374,16 @@ struct acpi_device {
void (*remove)(struct acpi_device *);
};

+static inline bool is_acpi_node(struct fwnode_handle *fwnode)
+{
+ return fwnode && fwnode->type == FWNODE_ACPI;
+}
+
+static inline struct acpi_device *acpi_node(struct fwnode_handle *fwnode)
+{
+ return fwnode ? container_of(fwnode, struct acpi_device, fwnode) : NULL;
+}
+
static inline void *acpi_driver_data(struct acpi_device *d)
{
return d->driver_data;
Index: linux-pm/include/linux/acpi.h
===================================================================
--- linux-pm.orig/include/linux/acpi.h
+++ linux-pm/include/linux/acpi.h
@@ -439,6 +439,18 @@ int acpi_device_modalias(struct device *
#define ACPI_COMPANION_SET(dev, adev) do { } while (0)
#define ACPI_HANDLE(dev) (NULL)

+struct fwnode_handle;
+
+static inline bool is_acpi_node(struct fwnode_handle *fwnode)
+{
+ return false;
+}
+
+static inline struct acpi_device *acpi_node(struct fwnode_handle *fwnode)
+{
+ return NULL;
+}
+
static inline const char *acpi_dev_name(struct acpi_device *adev)
{
return NULL;
@@ -681,6 +693,9 @@ int acpi_dev_prop_read(struct acpi_devic
int acpi_dev_prop_read_array(struct acpi_device *adev, const char *propname,
enum dev_prop_type proptype, void *val,
size_t nval);
+
+struct acpi_device *acpi_get_next_child(struct device *dev,
+ struct acpi_device *child);
#else
static inline int acpi_dev_get_property(struct acpi_device *adev,
const char *name, acpi_object_type type,
@@ -724,6 +739,12 @@ static inline int acpi_dev_prop_read_arr
return -ENXIO;
}

+static inline struct acpi_device *acpi_get_next_child(struct device *dev,
+ struct acpi_device *child)
+{
+ return NULL;
+}
+
#endif

#endif /*_LINUX_ACPI_H*/
Index: linux-pm/include/linux/of.h
===================================================================
--- linux-pm.orig/include/linux/of.h
+++ linux-pm/include/linux/of.h
@@ -50,6 +50,7 @@ struct device_node {
const char *type;
phandle phandle;
const char *full_name;
+ struct fwnode_handle fwnode;

struct property *properties;
struct property *deadprops; /* removed properties */
@@ -80,6 +81,7 @@ extern struct kobj_type of_node_ktype;
static inline void of_node_init(struct device_node *node)
{
kobject_init(&node->kobj, &of_node_ktype);
+ node->fwnode.type = FWNODE_OF;
}

/* true when node is initialized */
@@ -115,6 +117,16 @@ extern struct device_node *of_aliases;
extern struct device_node *of_stdout;
extern raw_spinlock_t devtree_lock;

+static inline bool is_of_node(struct fwnode_handle *fwnode)
+{
+ return fwnode && fwnode->type == FWNODE_OF;
+}
+
+static inline struct device_node *of_node(struct fwnode_handle *fwnode)
+{
+ return fwnode ? container_of(fwnode, struct device_node, fwnode) : NULL;
+}
+
static inline bool of_have_populated_dt(void)
{
return of_allnodes != NULL;
@@ -365,6 +377,16 @@ bool of_console_check(struct device_node

#else /* CONFIG_OF */

+static inline bool is_of_node(struct fwnode_handle *fwnode)
+{
+ return false;
+}
+
+static inline struct device_node *of_node(struct fwnode_handle *fwnode)
+{
+ return NULL;
+}
+
static inline const char* of_node_full_name(const struct device_node *np)
{
return "<no-node>";
Index: linux-pm/drivers/base/property.c
===================================================================
--- linux-pm.orig/drivers/base/property.c
+++ linux-pm/drivers/base/property.c
@@ -156,6 +156,166 @@ int device_property_read_string(struct d
}
EXPORT_SYMBOL_GPL(device_property_read_string);

+/**
+ * fwnode_property_present - check if a property of a firmware node is present
+ * @fwnode: Firmware node whose property to check
+ * @propname: Name of the property
+ */
+bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname)
+{
+ if (is_of_node(fwnode))
+ return of_property_read_bool(of_node(fwnode), propname);
+ else if (is_acpi_node(fwnode))
+ return !acpi_dev_prop_get(acpi_node(fwnode), propname, NULL);
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_present);
+
+/**
+ * fwnode_property_read_u8 - return a u8 property of a firmware node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The value is stored here
+ *
+ * Read property @propname from the given firmware node and store the value into
+ * @val if found. The value is checked to be of type u8.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property type is not u8,
+ * %-EOVERFLOW if the property value is out of bounds of u8,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u8(struct fwnode_handle *fwnode, const char *propname,
+ u8 *val)
+{
+ if (is_of_node(fwnode))
+ return of_property_read_u8(of_node(fwnode), propname, val);
+ else if (is_acpi_node(fwnode))
+ return acpi_dev_prop_read(acpi_node(fwnode), propname,
+ DEV_PROP_U8, val);
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u8);
+
+/**
+ * fwnode_property_read_u16 - return a u16 property of a firmware node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The value is stored here
+ *
+ * Read property @propname from the given firmware node and store the value into
+ * @val if found. The value is checked to be of type u16.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property type is not u16,
+ * %-EOVERFLOW if the property value is out of bounds of u16,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u16(struct fwnode_handle *fwnode, const char *propname,
+ u16 *val)
+{
+ if (is_of_node(fwnode))
+ return of_property_read_u16(of_node(fwnode), propname, val);
+ else if (is_acpi_node(fwnode))
+ return acpi_dev_prop_read(acpi_node(fwnode), propname,
+ DEV_PROP_U16, val);
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u16);
+
+/**
+ * fwnode_property_read_u32 - return a u32 property of a firmware node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The value is stored here
+ *
+ * Read property @propname from the given firmware node and store the value into
+ * @val if found. The value is checked to be of type u32.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property type is not u32,
+ * %-EOVERFLOW if the property value is out of bounds of u32,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u32(struct fwnode_handle *fwnode, const char *propname,
+ u32 *val)
+{
+ if (is_of_node(fwnode))
+ return of_property_read_u32(of_node(fwnode), propname, val);
+ else if (is_acpi_node(fwnode))
+ return acpi_dev_prop_read(acpi_node(fwnode), propname,
+ DEV_PROP_U32, val);
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u32);
+
+/**
+ * fwnode_property_read_u64 - return a u64 property of a firmware node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The value is stored here
+ *
+ * Read property @propname from the given firmware node and store the value into
+ * @val if found. The value is checked to be of type u64.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property type is not u64,
+ * %-EOVERFLOW if the property value is out of bounds of u64,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u64(struct fwnode_handle *fwnode, const char *propname,
+ u64 *val)
+{
+ if (is_of_node(fwnode))
+ return of_property_read_u64(of_node(fwnode), propname, val);
+ else if (is_acpi_node(fwnode))
+ return acpi_dev_prop_read(acpi_node(fwnode), propname,
+ DEV_PROP_U64, val);
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u64);
+
+/**
+ * fwnode_property_read_string - return a string property of a firmware node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The value is stored here
+ *
+ * Read property @propname from the given firmware node and store the value into
+ * @val if found. The value is checked to be a string.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property is not a string,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_string(struct fwnode_handle *fwnode,
+ const char *propname, const char **val)
+{
+ if (is_of_node(fwnode))
+ return of_property_read_string(of_node(fwnode), propname, val);
+ else if (is_acpi_node(fwnode))
+ return acpi_dev_prop_read(acpi_node(fwnode), propname,
+ DEV_PROP_STRING, val);
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_string);
+
#define of_dev_prop_read_array(node, propname, type, val, nval) \
(val) ? of_property_read_##type##_array((node), (propname), (val), (nval)) \
: of_property_count_elems_of_size((node), (propname), sizeof(type))
@@ -299,3 +459,216 @@ int device_property_read_string_array(st
DEV_PROP_STRING, val, nval);
}
EXPORT_SYMBOL_GPL(device_property_read_string_array);
+
+/**
+ * fwnode_property_read_u8_array - return a u8 array property of firmware node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Read an array of u8 properties with @propname from @fwnode and stores them to
+ * @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u8_array(struct fwnode_handle *fwnode,
+ const char *propname, u8 *val, size_t nval)
+{
+ if (is_of_node(fwnode))
+ return of_dev_prop_read_array(of_node(fwnode), propname,
+ u8, val, nval);
+ else if (is_acpi_node(fwnode))
+ return acpi_dev_prop_read_array(acpi_node(fwnode), propname,
+ DEV_PROP_U8, val, nval);
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u8_array);
+
+/**
+ * fwnode_property_read_u16_array - return a u16 array property of firmware node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Read an array of u16 properties with @propname from @fwnode and store them to
+ * @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u16_array(struct fwnode_handle *fwnode,
+ const char *propname, u16 *val, size_t nval)
+{
+ if (is_of_node(fwnode))
+ return of_dev_prop_read_array(of_node(fwnode), propname,
+ u16, val, nval);
+ else if (is_acpi_node(fwnode))
+ return acpi_dev_prop_read_array(acpi_node(fwnode), propname,
+ DEV_PROP_U16, val, nval);
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u16_array);
+
+/**
+ * fwnode_property_read_u32_array - return a u32 array property of firmware node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Read an array of u32 properties with @propname from @fwnode store them to
+ * @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u32_array(struct fwnode_handle *fwnode,
+ const char *propname, u32 *val, size_t nval)
+{
+ if (is_of_node(fwnode))
+ return of_dev_prop_read_array(of_node(fwnode), propname,
+ u32, val, nval);
+ else if (is_acpi_node(fwnode))
+ return acpi_dev_prop_read_array(acpi_node(fwnode), propname,
+ DEV_PROP_U32, val, nval);
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u32_array);
+
+/**
+ * fwnode_property_read_u64_array - return a u64 array property firmware node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Read an array of u64 properties with @propname from @fwnode and store them to
+ * @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u64_array(struct fwnode_handle *fwnode,
+ const char *propname, u64 *val, size_t nval)
+{
+ if (is_of_node(fwnode))
+ return of_dev_prop_read_array(of_node(fwnode), propname,
+ u64, val, nval);
+ else if (is_acpi_node(fwnode))
+ return acpi_dev_prop_read_array(acpi_node(fwnode), propname,
+ DEV_PROP_U64, val, nval);
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u64_array);
+
+/**
+ * fwnode_property_read_string_array - return string array property of a node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Read an string list property @propname from the given firmware node and store
+ * them to @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of strings,
+ * %-EOVERFLOW if the size of the property is not as expected,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_string_array(struct fwnode_handle *fwnode,
+ const char *propname, char **val,
+ size_t nval)
+{
+ if (is_of_node(fwnode))
+ return of_property_read_string_array(of_node(fwnode), propname,
+ val, nval);
+ else if (is_acpi_node(fwnode))
+ return acpi_dev_prop_read_array(acpi_node(fwnode), propname,
+ DEV_PROP_STRING, val, nval);
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_string_array);
+
+
+/**
+ * device_get_next_child_node - Return the next child node handle for a device
+ * @dev: Device to find the next child node for.
+ * @child: Handle to one of the device's child nodes or a null handle.
+ */
+struct fwnode_handle *device_get_next_child_node(struct device *dev,
+ struct fwnode_handle *child)
+{
+ if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
+ struct device_node *node;
+
+ node = of_get_next_available_child(dev->of_node, of_node(child));
+ if (node)
+ return &node->fwnode;
+ } else if (ACPI_COMPANION(dev)) {
+ struct acpi_device *node;
+
+ node = acpi_get_next_child(dev, acpi_node(child));
+ if (node)
+ return &node->fwnode;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(device_get_next_child_node);
+
+/**
+ * fwnode_handle_put - Drop reference to a device node
+ * @fwnode: Pointer to the device node to drop the reference to.
+ *
+ * This has to be used when terminating device_for_each_child_node() iteration
+ * with break or return to prevent stale device node references from being left
+ * behind.
+ */
+void fwnode_handle_put(struct fwnode_handle *fwnode)
+{
+ if (is_of_node(fwnode))
+ of_node_put(of_node(fwnode));
+}
+EXPORT_SYMBOL_GPL(fwnode_handle_put);
+
+/**
+ * device_get_child_node_count - return the number of child nodes for device
+ * @dev: Device to cound the child nodes for
+ */
+unsigned int device_get_child_node_count(struct device *dev)
+{
+ struct fwnode_handle *child;
+ unsigned int count = 0;
+
+ device_for_each_child_node(dev, child)
+ count++;
+
+ return count;
+}
+EXPORT_SYMBOL_GPL(device_get_child_node_count);
Index: linux-pm/drivers/acpi/scan.c
===================================================================
--- linux-pm.orig/drivers/acpi/scan.c
+++ linux-pm/drivers/acpi/scan.c
@@ -1342,6 +1342,26 @@ int acpi_device_add(struct acpi_device *
return result;
}

+struct acpi_device *acpi_get_next_child(struct device *dev,
+ struct acpi_device *child)
+{
+ struct acpi_device *adev = ACPI_COMPANION(dev);
+ struct list_head *head, *next;
+
+ if (!adev)
+ return NULL;
+
+ head = &adev->children;
+ if (list_empty(head))
+ return NULL;
+
+ if (!child)
+ return list_first_entry(head, struct acpi_device, node);
+
+ next = child->node.next;
+ return next == head ? NULL : list_entry(next, struct acpi_device, node);
+}
+
/* --------------------------------------------------------------------------
Driver Management
-------------------------------------------------------------------------- */
@@ -1961,6 +1981,7 @@ void acpi_init_device_object(struct acpi
device->device_type = type;
device->handle = handle;
device->parent = acpi_bus_get_parent(handle);
+ device->fwnode.type = FWNODE_ACPI;
acpi_set_device_status(device, sta);
acpi_device_get_busid(device);
acpi_set_pnp_ids(handle, &device->pnp, type);
Arnd Bergmann
2014-10-18 09:35:21 UTC
Permalink
Post by Rafael J. Wysocki
+/**
+ * fwnode_property_present - check if a property of a firmware node is present
+ */
+bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname)
+{
+ if (is_of_node(fwnode))
+ return of_property_read_bool(of_node(fwnode), propname);
+ else if (is_acpi_node(fwnode))
+ return !acpi_dev_prop_get(acpi_node(fwnode), propname, NULL);
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_present);
Should this be

return acpi_dev_prop_get(acpi_node(fwnode), propname, NULL);

without the '!'?

I'm also unsure about the '_present' vs '_read_bool' naming. IIRC we had
a long debate about this before we decided on 'read_bool' for DT, and
I don't really want to start a new debate, but being consistent would
be nice.

We could of course have

static inline bool fwnode_property_read_bool(struct fwnode_handle *fwnode, const char *propname)
{
return fwnode_property_present(fwnode, propname);
}

which is completely redundant, but would help for drivers using the
interface to document whether we are checking for bool property that
we expect to be either empty or absent (_get_bool), vs checking for
the presence of a non-empty property (_present).

Arnd
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Rafael J. Wysocki
2014-10-19 23:30:47 UTC
Permalink
Post by Arnd Bergmann
Post by Rafael J. Wysocki
+/**
+ * fwnode_property_present - check if a property of a firmware node is present
+ */
+bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname)
+{
+ if (is_of_node(fwnode))
+ return of_property_read_bool(of_node(fwnode), propname);
+ else if (is_acpi_node(fwnode))
+ return !acpi_dev_prop_get(acpi_node(fwnode), propname, NULL);
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_present);
Should this be
return acpi_dev_prop_get(acpi_node(fwnode), propname, NULL);
without the '!'?
No, acpi_dev_prop_get() returns 0 on success. :-)
Post by Arnd Bergmann
I'm also unsure about the '_present' vs '_read_bool' naming. IIRC we had
a long debate about this before we decided on 'read_bool' for DT, and
I don't really want to start a new debate, but being consistent would
be nice.
We could of course have
static inline bool fwnode_property_read_bool(struct fwnode_handle *fwnode, const char *propname)
{
return fwnode_property_present(fwnode, propname);
}
which is completely redundant, but would help for drivers using the
interface to document whether we are checking for bool property that
we expect to be either empty or absent (_get_bool), vs checking for
the presence of a non-empty property (_present).
I'm fine with that, so I'll add fwnode_property_read_bool() (and an analogous
wrapper for device_) to patches [02/12] and [09/12].

I'll be sending updates of them shortly, so please have a look at those.

Rafael

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Arnd Bergmann
2014-10-20 14:14:35 UTC
Permalink
Post by Rafael J. Wysocki
Post by Arnd Bergmann
Post by Rafael J. Wysocki
+/**
+ * fwnode_property_present - check if a property of a firmware node is present
+ */
+bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname)
+{
+ if (is_of_node(fwnode))
+ return of_property_read_bool(of_node(fwnode), propname);
+ else if (is_acpi_node(fwnode))
+ return !acpi_dev_prop_get(acpi_node(fwnode), propname, NULL);
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_present);
Should this be
return acpi_dev_prop_get(acpi_node(fwnode), propname, NULL);
without the '!'?
No, acpi_dev_prop_get() returns 0 on success.
Ah, got it now.
Post by Rafael J. Wysocki
Post by Arnd Bergmann
I'm also unsure about the '_present' vs '_read_bool' naming. IIRC we had
a long debate about this before we decided on 'read_bool' for DT, and
I don't really want to start a new debate, but being consistent would
be nice.
We could of course have
static inline bool fwnode_property_read_bool(struct fwnode_handle *fwnode, const char *propname)
{
return fwnode_property_present(fwnode, propname);
}
which is completely redundant, but would help for drivers using the
interface to document whether we are checking for bool property that
we expect to be either empty or absent (_get_bool), vs checking for
the presence of a non-empty property (_present).
I'm fine with that, so I'll add fwnode_property_read_bool() (and an analogous
wrapper for device_) to patches [02/12] and [09/12].
I'll be sending updates of them shortly, so please have a look at those.
Ok, will do.

Arnd
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Grant Likely
2014-10-18 14:55:20 UTC
Permalink
On Fri, 17 Oct 2014 14:14:53 +0200
Post by Rafael J. Wysocki
Add new generic routines are provided for retrieving properties from
device description objects in the platform firmware in case there are
no struct device objects for them (either those objects have not been
created yet or they do not exist at all).
fwnode_property_present()
fwnode_property_read_u8()
fwnode_property_read_u16()
fwnode_property_read_u32()
fwnode_property_read_u64()
fwnode_property_read_string()
fwnode_property_read_u8_array()
fwnode_property_read_u16_array()
fwnode_property_read_u32_array()
fwnode_property_read_u64_array()
fwnode_property_read_string_array()
in analogy with the corresponding functions for struct device added
previously. For all of them, the first argument is a pointer to struct
fwnode_handle (new type) that allows a device description object
(depending on what platform firmware interface is in use) to be
obtained.
Add a new macro device_for_each_child_node() for iterating over the
children of the device description object associated with a given
device and a new function device_get_child_node_count() returning the
number of a given device's child nodes.
The interface covers both ACPI and Device Trees.
This is all *so much* better. I'm a lot happier.

I was about to make the comment that the implementation for
device_property_read_*() should merely be wrappers around
fwnode_property_read_*(), but when when I actually looked at it, I saw
this:

In patch 2:
int device_property_read_u8(struct device *dev, const char *propname, u8 *val)
{
if (IS_ENABLED(CONFIG_OF) && dev->of_node)
return of_property_read_u8(dev->of_node, propname, val);

return acpi_dev_prop_read(ACPI_COMPANION(dev), propname,
DEV_PROP_U8, val);
}

And in this patch:
int fwnode_property_read_u8(struct fwnode_handle *fwnode, const char *propname,
u8 *val)
{
if (is_of_node(fwnode))
return of_property_read_u8(of_node(fwnode), propname, val);
else if (is_acpi_node(fwnode))
return acpi_dev_prop_read(acpi_node(fwnode), propname,
DEV_PROP_U8, val);

return -ENXIO;
}

Making the device_property functions wrappers around fwnode_property_*
wouldn't actually be great since it would need to decode the fwnode
pointer twice.

I do still think the functions above should be macro generated, just in
terms of keeping the line count down, and I would suggest merging patches #2
and #9.

Something like:

#define define_fwnode_accessors(__type, __devprop_type) \
int device_property_read_##__type(struct device *dev, \
const char *propname, __type *val) \
{ \
if (IS_ENABLED(CONFIG_OF) && dev->of_node) \
return of_property_read_##__type(dev->of_node, propname, val); \
return acpi_dev_prop_read(ACPI_COMPANION(dev), propname, \
__devprop_type, val); \
} \
int fwnode_property_read_##__type(struct fwnode_handle *fwnode, \
const char *propname, __type *val) \
{ \
if (IS_ENABLED(CONFIG_OF) && is_of_node(fwnode)) \
return of_property_read_##__type(of_node(fwnode), propname, val); \
else if (IS_ENABLED(CONFIG_ACPI) && is_acpi_node(fwnode)) \
return acpi_dev_prop_read(acpi_node(fwnode), propname, \
__devprop_type, val); \
return -ENXIO; \
}

define_fwnode_accessors(u8, DEV_PROP_U8);
define_fwnode_accessors(u16, DEV_PROP_U16);
define_fwnode_accessors(u32, DEV_PROP_U32);
define_fwnode_accessors(u64, DEV_PROP_U64);

That significantly reduces the code size for these things.

Also, can the non-array versions be implemented as a wrapper around the
array versions? That also will reduce the sheer number of lines of code
a lot.

Maybe this:

#define define_fwnode_accessors(__type, __devprop_type) \
int device_property_read_##__type##_array(struct device *dev, \
const char *propname, __type *val, \
size_t nval) \
{ \
if (IS_ENABLED(CONFIG_OF) && dev->of_node) \
return of_property_read_##__type##_array(dev->of_node, \
propname, val, nval); \
return acpi_dev_prop_read_array(ACPI_COMPANION(dev), propname, \
__devprop_type, val, nval); \
} \
static inline int device_property_read_##__type(struct device *dev, \
const char *propname, __type *val) \
{ \
return device_property_read_##__type##_array(dev, propname, val, 1) \
} \
int fwnode_property_read_##__type##_array(struct fwnode_handle *fwnode, \
const char *propname, __type *val, \
size_t nval) \
{ \
if (IS_ENABLED(CONFIG_OF) && is_of_node(fwnode)) \
return of_property_read_##__type(of_node(fwnode), propname, val, nval); \
else if (IS_ENABLED(CONFIG_ACPI) && is_acpi_node(fwnode)) \
return acpi_dev_prop_read(acpi_node(fwnode), propname, \
__devprop_type, val, nval); \
return -ENXIO; \
} \
static inline int fwnode_property_read_##__type(struct fwnode_handle *fwnode, \
const char *propname, __type *val) \
{ \
return fwnode_property_read_##__type##_array(fwnode, propname, val, 1) \
}
define_fwnode_accessors(u8, DEV_PROP_U8);
define_fwnode_accessors(u16, DEV_PROP_U16);
define_fwnode_accessors(u32, DEV_PROP_U32);
define_fwnode_accessors(u64, DEV_PROP_U64);

g.
Post by Rafael J. Wysocki
---
drivers/acpi/scan.c | 21 ++
drivers/base/property.c | 373 +++++++++++++++++++++++++++++++++++++++++++++++
include/acpi/acpi_bus.h | 12 +
include/linux/acpi.h | 21 ++
include/linux/of.h | 22 ++
include/linux/property.h | 48 ++++++
6 files changed, 497 insertions(+)
Index: linux-pm/include/linux/property.h
===================================================================
--- linux-pm.orig/include/linux/property.h
+++ linux-pm/include/linux/property.h
@@ -44,4 +44,52 @@ int device_property_read_u64_array(struc
int device_property_read_string_array(struct device *dev, const char *propname,
char **val, size_t nval);
+enum fwnode_type {
+ FWNODE_INVALID = 0,
+ FWNODE_OF,
+ FWNODE_ACPI,
+};
+
+struct fwnode_handle {
+ enum fwnode_type type;
+};
+
+bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname);
+int fwnode_property_read_u8(struct fwnode_handle *fwnode, const char *propname,
+ u8 *val);
+int fwnode_property_read_u16(struct fwnode_handle *fwnode, const char *propname,
+ u16 *val);
+int fwnode_property_read_u32(struct fwnode_handle *fwnode, const char *propname,
+ u32 *val);
+int fwnode_property_read_u64(struct fwnode_handle *fwnode, const char *propname,
+ u64 *val);
+int fwnode_property_read_string(struct fwnode_handle *fwnode,
+ const char *propname, const char **val);
+int fwnode_property_read_u8_array(struct fwnode_handle *fwnode,
+ const char *propname, u8 *val,
+ size_t nval);
+int fwnode_property_read_u16_array(struct fwnode_handle *fwnode,
+ const char *propname, u16 *val,
+ size_t nval);
+int fwnode_property_read_u32_array(struct fwnode_handle *fwnode,
+ const char *propname, u32 *val,
+ size_t nval);
+int fwnode_property_read_u64_array(struct fwnode_handle *fwnode,
+ const char *propname, u64 *val,
+ size_t nval);
+int fwnode_property_read_string_array(struct fwnode_handle *fwnode,
+ const char *propname, char **val,
+ size_t nval);
+
+struct fwnode_handle *device_get_next_child_node(struct device *dev,
+ struct fwnode_handle *child);
+
+#define device_for_each_child_node(dev, child) \
+ for (child = device_get_next_child_node(dev, NULL); child; \
+ child = device_get_next_child_node(dev, child))
+
+void fwnode_handle_put(struct fwnode_handle *fwnode);
+
+unsigned int device_get_child_node_count(struct device *dev);
+
#endif /* _LINUX_PROPERTY_H_ */
Index: linux-pm/include/acpi/acpi_bus.h
===================================================================
--- linux-pm.orig/include/acpi/acpi_bus.h
+++ linux-pm/include/acpi/acpi_bus.h
@@ -27,6 +27,7 @@
#define __ACPI_BUS_H__
#include <linux/device.h>
+#include <linux/property.h>
/* TBD: Make dynamic */
#define ACPI_MAX_HANDLES 10
@@ -348,6 +349,7 @@ struct acpi_device_data {
struct acpi_device {
int device_type;
acpi_handle handle; /* no handle for fixed hardware */
+ struct fwnode_handle fwnode;
struct acpi_device *parent;
struct list_head children;
struct list_head node;
@@ -372,6 +374,16 @@ struct acpi_device {
void (*remove)(struct acpi_device *);
};
+static inline bool is_acpi_node(struct fwnode_handle *fwnode)
+{
+ return fwnode && fwnode->type == FWNODE_ACPI;
+}
+
+static inline struct acpi_device *acpi_node(struct fwnode_handle *fwnode)
+{
+ return fwnode ? container_of(fwnode, struct acpi_device, fwnode) : NULL;
+}
+
static inline void *acpi_driver_data(struct acpi_device *d)
{
return d->driver_data;
Index: linux-pm/include/linux/acpi.h
===================================================================
--- linux-pm.orig/include/linux/acpi.h
+++ linux-pm/include/linux/acpi.h
@@ -439,6 +439,18 @@ int acpi_device_modalias(struct device *
#define ACPI_COMPANION_SET(dev, adev) do { } while (0)
#define ACPI_HANDLE(dev) (NULL)
+struct fwnode_handle;
+
+static inline bool is_acpi_node(struct fwnode_handle *fwnode)
+{
+ return false;
+}
+
+static inline struct acpi_device *acpi_node(struct fwnode_handle *fwnode)
+{
+ return NULL;
+}
+
static inline const char *acpi_dev_name(struct acpi_device *adev)
{
return NULL;
@@ -681,6 +693,9 @@ int acpi_dev_prop_read(struct acpi_devic
int acpi_dev_prop_read_array(struct acpi_device *adev, const char *propname,
enum dev_prop_type proptype, void *val,
size_t nval);
+
+struct acpi_device *acpi_get_next_child(struct device *dev,
+ struct acpi_device *child);
#else
static inline int acpi_dev_get_property(struct acpi_device *adev,
const char *name, acpi_object_type type,
@@ -724,6 +739,12 @@ static inline int acpi_dev_prop_read_arr
return -ENXIO;
}
+static inline struct acpi_device *acpi_get_next_child(struct device *dev,
+ struct acpi_device *child)
+{
+ return NULL;
+}
+
#endif
#endif /*_LINUX_ACPI_H*/
Index: linux-pm/include/linux/of.h
===================================================================
--- linux-pm.orig/include/linux/of.h
+++ linux-pm/include/linux/of.h
@@ -50,6 +50,7 @@ struct device_node {
const char *type;
phandle phandle;
const char *full_name;
+ struct fwnode_handle fwnode;
struct property *properties;
struct property *deadprops; /* removed properties */
@@ -80,6 +81,7 @@ extern struct kobj_type of_node_ktype;
static inline void of_node_init(struct device_node *node)
{
kobject_init(&node->kobj, &of_node_ktype);
+ node->fwnode.type = FWNODE_OF;
}
/* true when node is initialized */
@@ -115,6 +117,16 @@ extern struct device_node *of_aliases;
extern struct device_node *of_stdout;
extern raw_spinlock_t devtree_lock;
+static inline bool is_of_node(struct fwnode_handle *fwnode)
+{
+ return fwnode && fwnode->type == FWNODE_OF;
+}
+
+static inline struct device_node *of_node(struct fwnode_handle *fwnode)
+{
+ return fwnode ? container_of(fwnode, struct device_node, fwnode) : NULL;
+}
+
static inline bool of_have_populated_dt(void)
{
return of_allnodes != NULL;
@@ -365,6 +377,16 @@ bool of_console_check(struct device_node
#else /* CONFIG_OF */
+static inline bool is_of_node(struct fwnode_handle *fwnode)
+{
+ return false;
+}
+
+static inline struct device_node *of_node(struct fwnode_handle *fwnode)
+{
+ return NULL;
+}
+
static inline const char* of_node_full_name(const struct device_node *np)
{
return "<no-node>";
Index: linux-pm/drivers/base/property.c
===================================================================
--- linux-pm.orig/drivers/base/property.c
+++ linux-pm/drivers/base/property.c
@@ -156,6 +156,166 @@ int device_property_read_string(struct d
}
EXPORT_SYMBOL_GPL(device_property_read_string);
+/**
+ * fwnode_property_present - check if a property of a firmware node is present
+ */
+bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname)
+{
+ if (is_of_node(fwnode))
+ return of_property_read_bool(of_node(fwnode), propname);
+ else if (is_acpi_node(fwnode))
+ return !acpi_dev_prop_get(acpi_node(fwnode), propname, NULL);
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_present);
+
+/**
+ * fwnode_property_read_u8 - return a u8 property of a firmware node
+ *
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property type is not u8,
+ * %-EOVERFLOW if the property value is out of bounds of u8,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u8(struct fwnode_handle *fwnode, const char *propname,
+ u8 *val)
+{
+ if (is_of_node(fwnode))
+ return of_property_read_u8(of_node(fwnode), propname, val);
+ else if (is_acpi_node(fwnode))
+ return acpi_dev_prop_read(acpi_node(fwnode), propname,
+ DEV_PROP_U8, val);
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u8);
+
+/**
+ * fwnode_property_read_u16 - return a u16 property of a firmware node
+ *
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property type is not u16,
+ * %-EOVERFLOW if the property value is out of bounds of u16,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u16(struct fwnode_handle *fwnode, const char *propname,
+ u16 *val)
+{
+ if (is_of_node(fwnode))
+ return of_property_read_u16(of_node(fwnode), propname, val);
+ else if (is_acpi_node(fwnode))
+ return acpi_dev_prop_read(acpi_node(fwnode), propname,
+ DEV_PROP_U16, val);
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u16);
+
+/**
+ * fwnode_property_read_u32 - return a u32 property of a firmware node
+ *
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property type is not u32,
+ * %-EOVERFLOW if the property value is out of bounds of u32,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u32(struct fwnode_handle *fwnode, const char *propname,
+ u32 *val)
+{
+ if (is_of_node(fwnode))
+ return of_property_read_u32(of_node(fwnode), propname, val);
+ else if (is_acpi_node(fwnode))
+ return acpi_dev_prop_read(acpi_node(fwnode), propname,
+ DEV_PROP_U32, val);
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u32);
+
+/**
+ * fwnode_property_read_u64 - return a u64 property of a firmware node
+ *
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property type is not u64,
+ * %-EOVERFLOW if the property value is out of bounds of u64,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u64(struct fwnode_handle *fwnode, const char *propname,
+ u64 *val)
+{
+ if (is_of_node(fwnode))
+ return of_property_read_u64(of_node(fwnode), propname, val);
+ else if (is_acpi_node(fwnode))
+ return acpi_dev_prop_read(acpi_node(fwnode), propname,
+ DEV_PROP_U64, val);
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u64);
+
+/**
+ * fwnode_property_read_string - return a string property of a firmware node
+ *
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property is not a string,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_string(struct fwnode_handle *fwnode,
+ const char *propname, const char **val)
+{
+ if (is_of_node(fwnode))
+ return of_property_read_string(of_node(fwnode), propname, val);
+ else if (is_acpi_node(fwnode))
+ return acpi_dev_prop_read(acpi_node(fwnode), propname,
+ DEV_PROP_STRING, val);
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_string);
+
#define of_dev_prop_read_array(node, propname, type, val, nval) \
(val) ? of_property_read_##type##_array((node), (propname), (val), (nval)) \
: of_property_count_elems_of_size((node), (propname), sizeof(type))
@@ -299,3 +459,216 @@ int device_property_read_string_array(st
DEV_PROP_STRING, val, nval);
}
EXPORT_SYMBOL_GPL(device_property_read_string_array);
+
+/**
+ * fwnode_property_read_u8_array - return a u8 array property of firmware node
+ *
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u8_array(struct fwnode_handle *fwnode,
+ const char *propname, u8 *val, size_t nval)
+{
+ if (is_of_node(fwnode))
+ return of_dev_prop_read_array(of_node(fwnode), propname,
+ u8, val, nval);
+ else if (is_acpi_node(fwnode))
+ return acpi_dev_prop_read_array(acpi_node(fwnode), propname,
+ DEV_PROP_U8, val, nval);
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u8_array);
+
+/**
+ * fwnode_property_read_u16_array - return a u16 array property of firmware node
+ *
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u16_array(struct fwnode_handle *fwnode,
+ const char *propname, u16 *val, size_t nval)
+{
+ if (is_of_node(fwnode))
+ return of_dev_prop_read_array(of_node(fwnode), propname,
+ u16, val, nval);
+ else if (is_acpi_node(fwnode))
+ return acpi_dev_prop_read_array(acpi_node(fwnode), propname,
+ DEV_PROP_U16, val, nval);
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u16_array);
+
+/**
+ * fwnode_property_read_u32_array - return a u32 array property of firmware node
+ *
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u32_array(struct fwnode_handle *fwnode,
+ const char *propname, u32 *val, size_t nval)
+{
+ if (is_of_node(fwnode))
+ return of_dev_prop_read_array(of_node(fwnode), propname,
+ u32, val, nval);
+ else if (is_acpi_node(fwnode))
+ return acpi_dev_prop_read_array(acpi_node(fwnode), propname,
+ DEV_PROP_U32, val, nval);
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u32_array);
+
+/**
+ * fwnode_property_read_u64_array - return a u64 array property firmware node
+ *
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u64_array(struct fwnode_handle *fwnode,
+ const char *propname, u64 *val, size_t nval)
+{
+ if (is_of_node(fwnode))
+ return of_dev_prop_read_array(of_node(fwnode), propname,
+ u64, val, nval);
+ else if (is_acpi_node(fwnode))
+ return acpi_dev_prop_read_array(acpi_node(fwnode), propname,
+ DEV_PROP_U64, val, nval);
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u64_array);
+
+/**
+ * fwnode_property_read_string_array - return string array property of a node
+ *
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of strings,
+ * %-EOVERFLOW if the size of the property is not as expected,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_string_array(struct fwnode_handle *fwnode,
+ const char *propname, char **val,
+ size_t nval)
+{
+ if (is_of_node(fwnode))
+ return of_property_read_string_array(of_node(fwnode), propname,
+ val, nval);
+ else if (is_acpi_node(fwnode))
+ return acpi_dev_prop_read_array(acpi_node(fwnode), propname,
+ DEV_PROP_STRING, val, nval);
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_string_array);
+
+
+/**
+ * device_get_next_child_node - Return the next child node handle for a device
+ */
+struct fwnode_handle *device_get_next_child_node(struct device *dev,
+ struct fwnode_handle *child)
+{
+ if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
+ struct device_node *node;
+
+ node = of_get_next_available_child(dev->of_node, of_node(child));
+ if (node)
+ return &node->fwnode;
+ } else if (ACPI_COMPANION(dev)) {
+ struct acpi_device *node;
+
+ node = acpi_get_next_child(dev, acpi_node(child));
+ if (node)
+ return &node->fwnode;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(device_get_next_child_node);
+
+/**
+ * fwnode_handle_put - Drop reference to a device node
+ *
+ * This has to be used when terminating device_for_each_child_node() iteration
+ * with break or return to prevent stale device node references from being left
+ * behind.
+ */
+void fwnode_handle_put(struct fwnode_handle *fwnode)
+{
+ if (is_of_node(fwnode))
+ of_node_put(of_node(fwnode));
+}
+EXPORT_SYMBOL_GPL(fwnode_handle_put);
+
+/**
+ * device_get_child_node_count - return the number of child nodes for device
+ */
+unsigned int device_get_child_node_count(struct device *dev)
+{
+ struct fwnode_handle *child;
+ unsigned int count = 0;
+
+ device_for_each_child_node(dev, child)
+ count++;
+
+ return count;
+}
+EXPORT_SYMBOL_GPL(device_get_child_node_count);
Index: linux-pm/drivers/acpi/scan.c
===================================================================
--- linux-pm.orig/drivers/acpi/scan.c
+++ linux-pm/drivers/acpi/scan.c
@@ -1342,6 +1342,26 @@ int acpi_device_add(struct acpi_device *
return result;
}
+struct acpi_device *acpi_get_next_child(struct device *dev,
+ struct acpi_device *child)
+{
+ struct acpi_device *adev = ACPI_COMPANION(dev);
+ struct list_head *head, *next;
+
+ if (!adev)
+ return NULL;
+
+ head = &adev->children;
+ if (list_empty(head))
+ return NULL;
+
+ if (!child)
+ return list_first_entry(head, struct acpi_device, node);
+
+ next = child->node.next;
+ return next == head ? NULL : list_entry(next, struct acpi_device, node);
+}
+
/* --------------------------------------------------------------------------
Driver Management
-------------------------------------------------------------------------- */
@@ -1961,6 +1981,7 @@ void acpi_init_device_object(struct acpi
device->device_type = type;
device->handle = handle;
device->parent = acpi_bus_get_parent(handle);
+ device->fwnode.type = FWNODE_ACPI;
acpi_set_device_status(device, sta);
acpi_device_get_busid(device);
acpi_set_pnp_ids(handle, &device->pnp, type);
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Rafael J. Wysocki
2014-10-19 23:46:00 UTC
Permalink
Post by Grant Likely
On Fri, 17 Oct 2014 14:14:53 +0200
Post by Rafael J. Wysocki
Add new generic routines are provided for retrieving properties from
device description objects in the platform firmware in case there are
no struct device objects for them (either those objects have not been
created yet or they do not exist at all).
fwnode_property_present()
fwnode_property_read_u8()
fwnode_property_read_u16()
fwnode_property_read_u32()
fwnode_property_read_u64()
fwnode_property_read_string()
fwnode_property_read_u8_array()
fwnode_property_read_u16_array()
fwnode_property_read_u32_array()
fwnode_property_read_u64_array()
fwnode_property_read_string_array()
in analogy with the corresponding functions for struct device added
previously. For all of them, the first argument is a pointer to struct
fwnode_handle (new type) that allows a device description object
(depending on what platform firmware interface is in use) to be
obtained.
Add a new macro device_for_each_child_node() for iterating over the
children of the device description object associated with a given
device and a new function device_get_child_node_count() returning the
number of a given device's child nodes.
The interface covers both ACPI and Device Trees.
This is all *so much* better. I'm a lot happier.
I was about to make the comment that the implementation for
device_property_read_*() should merely be wrappers around
fwnode_property_read_*(), but when when I actually looked at it, I saw
int device_property_read_u8(struct device *dev, const char *propname, u8 *val)
{
if (IS_ENABLED(CONFIG_OF) && dev->of_node)
return of_property_read_u8(dev->of_node, propname, val);
return acpi_dev_prop_read(ACPI_COMPANION(dev), propname,
DEV_PROP_U8, val);
}
int fwnode_property_read_u8(struct fwnode_handle *fwnode, const char *propname,
u8 *val)
{
if (is_of_node(fwnode))
return of_property_read_u8(of_node(fwnode), propname, val);
else if (is_acpi_node(fwnode))
return acpi_dev_prop_read(acpi_node(fwnode), propname,
DEV_PROP_U8, val);
return -ENXIO;
}
Making the device_property functions wrappers around fwnode_property_*
wouldn't actually be great since it would need to decode the fwnode
pointer twice.
Indeed.
Post by Grant Likely
I do still think the functions above should be macro generated, just in
terms of keeping the line count down, and I would suggest merging patches #2
and #9.
Well, the changes in those patches are almost completely independent and patch
#9 is only actually needed for #11 and #12, so I'm not sure if that would be
better. I certainly prefer splitting longer patches into pieces if that makes
sense and it does make sense to do so in this particular case IMHO.
Post by Grant Likely
#define define_fwnode_accessors(__type, __devprop_type) \
int device_property_read_##__type(struct device *dev, \
const char *propname, __type *val) \
{ \
if (IS_ENABLED(CONFIG_OF) && dev->of_node) \
return of_property_read_##__type(dev->of_node, propname, val); \
return acpi_dev_prop_read(ACPI_COMPANION(dev), propname, \
__devprop_type, val); \
} \
int fwnode_property_read_##__type(struct fwnode_handle *fwnode, \
const char *propname, __type *val) \
{ \
if (IS_ENABLED(CONFIG_OF) && is_of_node(fwnode)) \
return of_property_read_##__type(of_node(fwnode), propname, val); \
else if (IS_ENABLED(CONFIG_ACPI) && is_acpi_node(fwnode)) \
return acpi_dev_prop_read(acpi_node(fwnode), propname, \
__devprop_type, val); \
return -ENXIO; \
}
define_fwnode_accessors(u8, DEV_PROP_U8);
define_fwnode_accessors(u16, DEV_PROP_U16);
define_fwnode_accessors(u32, DEV_PROP_U32);
define_fwnode_accessors(u64, DEV_PROP_U64);
That significantly reduces the code size for these things.
So I was considering to do that, but eventually decided not to, because (1)
adding kerneldoc comments to such things looks odd and (2) (which IMO is
more important) this breaks LXR (for example, the thing at lxr.free-electrons.com
that some people, including me in particular, occasionally use to check how things
are defined). And even if you used the old good grep to look for a definition of
fwnode_property_read_u8, say, this wouldn't work exactly as expected I'm afraid. ;-)

I would very much like to retain the headers at least for this reason, if that's
not a big deal.

What I can do, however, is to use macros for generating the bodies of those
functions.

I'm going to send updates of patches #2 and #9 with that modification shortly,
please have a look at them.
Post by Grant Likely
Also, can the non-array versions be implemented as a wrapper around the
array versions? That also will reduce the sheer number of lines of code
a lot.
#define define_fwnode_accessors(__type, __devprop_type) \
int device_property_read_##__type##_array(struct device *dev, \
const char *propname, __type *val, \
size_t nval) \
{ \
if (IS_ENABLED(CONFIG_OF) && dev->of_node) \
return of_property_read_##__type##_array(dev->of_node, \
propname, val, nval); \
return acpi_dev_prop_read_array(ACPI_COMPANION(dev), propname, \
__devprop_type, val, nval); \
} \
static inline int device_property_read_##__type(struct device *dev, \
const char *propname, __type *val) \
{ \
return device_property_read_##__type##_array(dev, propname, val, 1) \
} \
int fwnode_property_read_##__type##_array(struct fwnode_handle *fwnode, \
const char *propname, __type *val, \
size_t nval) \
{ \
if (IS_ENABLED(CONFIG_OF) && is_of_node(fwnode)) \
return of_property_read_##__type(of_node(fwnode), propname, val, nval); \
else if (IS_ENABLED(CONFIG_ACPI) && is_acpi_node(fwnode)) \
return acpi_dev_prop_read(acpi_node(fwnode), propname, \
__devprop_type, val, nval); \
return -ENXIO; \
} \
static inline int fwnode_property_read_##__type(struct fwnode_handle *fwnode, \
const char *propname, __type *val) \
{ \
return fwnode_property_read_##__type##_array(fwnode, propname, val, 1) \
}
define_fwnode_accessors(u8, DEV_PROP_U8);
define_fwnode_accessors(u16, DEV_PROP_U16);
define_fwnode_accessors(u32, DEV_PROP_U32);
define_fwnode_accessors(u64, DEV_PROP_U64);
No, that wouldn't work for ACPI (if I understand your idea correctly), because
acpi_dev_prop_read(adev, propname, DEV_PROP_U8, val) will look for a single-value
int property, whereas acpi_dev_prop_read_array(adev, propname, DEV_PROP_U8, val, 1)
will look for a list (package) property and will attempt to retrieve the first
element of that.

Rafael
Grant Likely
2014-10-20 14:18:18 UTC
Permalink
On Mon, 20 Oct 2014 01:46 +0200
Post by Rafael J. Wysocki
Post by Grant Likely
On Fri, 17 Oct 2014 14:14:53 +0200
Post by Rafael J. Wysocki
Add new generic routines are provided for retrieving properties from
device description objects in the platform firmware in case there are
no struct device objects for them (either those objects have not been
created yet or they do not exist at all).
fwnode_property_present()
fwnode_property_read_u8()
fwnode_property_read_u16()
fwnode_property_read_u32()
fwnode_property_read_u64()
fwnode_property_read_string()
fwnode_property_read_u8_array()
fwnode_property_read_u16_array()
fwnode_property_read_u32_array()
fwnode_property_read_u64_array()
fwnode_property_read_string_array()
in analogy with the corresponding functions for struct device added
previously. For all of them, the first argument is a pointer to struct
fwnode_handle (new type) that allows a device description object
(depending on what platform firmware interface is in use) to be
obtained.
Add a new macro device_for_each_child_node() for iterating over the
children of the device description object associated with a given
device and a new function device_get_child_node_count() returning the
number of a given device's child nodes.
The interface covers both ACPI and Device Trees.
This is all *so much* better. I'm a lot happier.
I was about to make the comment that the implementation for
device_property_read_*() should merely be wrappers around
fwnode_property_read_*(), but when when I actually looked at it, I saw
int device_property_read_u8(struct device *dev, const char *propname, u8 *val)
{
if (IS_ENABLED(CONFIG_OF) && dev->of_node)
return of_property_read_u8(dev->of_node, propname, val);
return acpi_dev_prop_read(ACPI_COMPANION(dev), propname,
DEV_PROP_U8, val);
}
int fwnode_property_read_u8(struct fwnode_handle *fwnode, const char *propname,
u8 *val)
{
if (is_of_node(fwnode))
return of_property_read_u8(of_node(fwnode), propname, val);
else if (is_acpi_node(fwnode))
return acpi_dev_prop_read(acpi_node(fwnode), propname,
DEV_PROP_U8, val);
return -ENXIO;
}
Making the device_property functions wrappers around fwnode_property_*
wouldn't actually be great since it would need to decode the fwnode
pointer twice.
Indeed.
Post by Grant Likely
I do still think the functions above should be macro generated, just in
terms of keeping the line count down, and I would suggest merging patches #2
and #9.
Well, the changes in those patches are almost completely independent and patch
#9 is only actually needed for #11 and #12, so I'm not sure if that would be
better. I certainly prefer splitting longer patches into pieces if that makes
sense and it does make sense to do so in this particular case IMHO.
I'm not going to make a big deal about. Do what you think is best.
Post by Rafael J. Wysocki
Post by Grant Likely
#define define_fwnode_accessors(__type, __devprop_type) \
int device_property_read_##__type(struct device *dev, \
const char *propname, __type *val) \
{ \
if (IS_ENABLED(CONFIG_OF) && dev->of_node) \
return of_property_read_##__type(dev->of_node, propname, val); \
return acpi_dev_prop_read(ACPI_COMPANION(dev), propname, \
__devprop_type, val); \
} \
int fwnode_property_read_##__type(struct fwnode_handle *fwnode, \
const char *propname, __type *val) \
{ \
if (IS_ENABLED(CONFIG_OF) && is_of_node(fwnode)) \
return of_property_read_##__type(of_node(fwnode), propname, val); \
else if (IS_ENABLED(CONFIG_ACPI) && is_acpi_node(fwnode)) \
return acpi_dev_prop_read(acpi_node(fwnode), propname, \
__devprop_type, val); \
return -ENXIO; \
}
define_fwnode_accessors(u8, DEV_PROP_U8);
define_fwnode_accessors(u16, DEV_PROP_U16);
define_fwnode_accessors(u32, DEV_PROP_U32);
define_fwnode_accessors(u64, DEV_PROP_U64);
That significantly reduces the code size for these things.
So I was considering to do that, but eventually decided not to, because (1)
adding kerneldoc comments to such things looks odd and (2) (which IMO is
more important) this breaks LXR (for example, the thing at lxr.free-electrons.com
that some people, including me in particular, occasionally use to check how things
are defined). And even if you used the old good grep to look for a definition of
fwnode_property_read_u8, say, this wouldn't work exactly as expected I'm afraid. ;-)
I would very much like to retain the headers at least for this reason, if that's
not a big deal.
What I can do, however, is to use macros for generating the bodies of those
functions.
I'm fine with that. It's the near-identical blocks of code that I'm
concerned about. It is easy to miss one instance when fixing bugs if
they all have to be open coded. Plus it simply means a lot more lines of
code to wade through and review.
Post by Rafael J. Wysocki
Post by Grant Likely
Also, can the non-array versions be implemented as a wrapper around the
array versions? That also will reduce the sheer number of lines of code
a lot.
#define define_fwnode_accessors(__type, __devprop_type) \
int device_property_read_##__type##_array(struct device *dev, \
const char *propname, __type *val, \
size_t nval) \
{ \
if (IS_ENABLED(CONFIG_OF) && dev->of_node) \
return of_property_read_##__type##_array(dev->of_node, \
propname, val, nval); \
return acpi_dev_prop_read_array(ACPI_COMPANION(dev), propname, \
__devprop_type, val, nval); \
} \
static inline int device_property_read_##__type(struct device *dev, \
const char *propname, __type *val) \
{ \
return device_property_read_##__type##_array(dev, propname, val, 1) \
} \
int fwnode_property_read_##__type##_array(struct fwnode_handle *fwnode, \
const char *propname, __type *val, \
size_t nval) \
{ \
if (IS_ENABLED(CONFIG_OF) && is_of_node(fwnode)) \
return of_property_read_##__type(of_node(fwnode), propname, val, nval); \
else if (IS_ENABLED(CONFIG_ACPI) && is_acpi_node(fwnode)) \
return acpi_dev_prop_read(acpi_node(fwnode), propname, \
__devprop_type, val, nval); \
return -ENXIO; \
} \
static inline int fwnode_property_read_##__type(struct fwnode_handle *fwnode, \
const char *propname, __type *val) \
{ \
return fwnode_property_read_##__type##_array(fwnode, propname, val, 1) \
}
define_fwnode_accessors(u8, DEV_PROP_U8);
define_fwnode_accessors(u16, DEV_PROP_U16);
define_fwnode_accessors(u32, DEV_PROP_U32);
define_fwnode_accessors(u64, DEV_PROP_U64);
No, that wouldn't work for ACPI (if I understand your idea correctly), because
acpi_dev_prop_read(adev, propname, DEV_PROP_U8, val) will look for a single-value
int property, whereas acpi_dev_prop_read_array(adev, propname, DEV_PROP_U8, val, 1)
will look for a list (package) property and will attempt to retrieve the first
element of that.
That's a problem. There are certainly cases of DT code that use the
non-array version to read something that could also be read as an array
when the code only want the first value. It is a completely valid thing
to do. The ACPI accessors should be completely okay with either a single
value, or the first item(s) in a package when doing either a single read or
an array read.

so, if it is encoded as a singl values, then return that value, and the
largest size of array it will return is 1 element.

If it is encoded as a package, then a single read should return the
first element, and an array read should return up to the number of
values in the package.

g.

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-***@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Rafael J. Wysocki
2014-10-20 22:14:51 UTC
Permalink
Post by Grant Likely
On Mon, 20 Oct 2014 01:46 +0200
Post by Rafael J. Wysocki
Post by Grant Likely
On Fri, 17 Oct 2014 14:14:53 +0200
[cut]
Post by Grant Likely
Post by Rafael J. Wysocki
No, that wouldn't work for ACPI (if I understand your idea correctly), because
acpi_dev_prop_read(adev, propname, DEV_PROP_U8, val) will look for a single-value
int property, whereas acpi_dev_prop_read_array(adev, propname, DEV_PROP_U8, val, 1)
will look for a list (package) property and will attempt to retrieve the first
element of that.
That's a problem. There are certainly cases of DT code that use the
non-array version to read something that could also be read as an array
when the code only want the first value. It is a completely valid thing
to do. The ACPI accessors should be completely okay with either a single
value, or the first item(s) in a package when doing either a single read or
an array read.
Yeah.

So I have a new version of the patchset in which that is implemented as
you are describing. Fortunately, the differences are limited to patches #2,
#3 (for the "compatible" property to behave this way too) and #9 and are not
too big.

I'd prefer that to pass the Mika's tests before posting it, though, which will
take some time I suppose.
Post by Grant Likely
so, if it is encoded as a singl values, then return that value, and the
largest size of array it will return is 1 element.
If it is encoded as a package, then a single read should return the
first element, and an array read should return up to the number of
values in the package.
Rafael
Arnd Bergmann
2014-10-20 14:19:57 UTC
Permalink
Post by Rafael J. Wysocki
Post by Grant Likely
#define define_fwnode_accessors(__type, __devprop_type) \
int device_property_read_##__type(struct device *dev, \
const char *propname, __type *val) \
{ \
if (IS_ENABLED(CONFIG_OF) && dev->of_node) \
return of_property_read_##__type(dev->of_node, propname, val); \
return acpi_dev_prop_read(ACPI_COMPANION(dev), propname, \
__devprop_type, val); \
} \
int fwnode_property_read_##__type(struct fwnode_handle *fwnode, \
const char *propname, __type *val) \
{ \
if (IS_ENABLED(CONFIG_OF) && is_of_node(fwnode)) \
return of_property_read_##__type(of_node(fwnode), propname, val); \
else if (IS_ENABLED(CONFIG_ACPI) && is_acpi_node(fwnode)) \
return acpi_dev_prop_read(acpi_node(fwnode), propname, \
__devprop_type, val); \
return -ENXIO; \
}
define_fwnode_accessors(u8, DEV_PROP_U8);
define_fwnode_accessors(u16, DEV_PROP_U16);
define_fwnode_accessors(u32, DEV_PROP_U32);
define_fwnode_accessors(u64, DEV_PROP_U64);
That significantly reduces the code size for these things.
So I was considering to do that, but eventually decided not to, because (1)
adding kerneldoc comments to such things looks odd and (2) (which IMO is
more important) this breaks LXR (for example, the thing at lxr.free-electrons.com
that some people, including me in particular, occasionally use to check how things
are defined). And even if you used the old good grep to look for a definition of
fwnode_property_read_u8, say, this wouldn't work exactly as expected I'm afraid.
Agreed, I'd also prefer your proposed code over Grant's macros.
Post by Rafael J. Wysocki
I would very much like to retain the headers at least for this reason, if that's
not a big deal.
What I can do, however, is to use macros for generating the bodies of those
functions.
Yes, just don't do any concatenation to generate the names of the called
functions, i.e.

return fwnode_call(of_property_read_u32, acpi_dev_prop_read, DEV_PROP_U32, node, propname, val);

is better than

return fwnode_call(u32, DEV_PROP_U32, node, propname, val);

because it's easier to understand the call chain.

Arnd
Grant Likely
2014-10-20 14:55:08 UTC
Permalink
Post by Arnd Bergmann
Post by Rafael J. Wysocki
Post by Grant Likely
#define define_fwnode_accessors(__type, __devprop_type) \
int device_property_read_##__type(struct device *dev, \
const char *propname, __type *val) \
{ \
if (IS_ENABLED(CONFIG_OF) && dev->of_node) \
return of_property_read_##__type(dev->of_node, propname, val); \
return acpi_dev_prop_read(ACPI_COMPANION(dev), propname, \
__devprop_type, val); \
} \
int fwnode_property_read_##__type(struct fwnode_handle *fwnode, \
const char *propname, __type *val) \
{ \
if (IS_ENABLED(CONFIG_OF) && is_of_node(fwnode)) \
return of_property_read_##__type(of_node(fwnode), propname, val); \
else if (IS_ENABLED(CONFIG_ACPI) && is_acpi_node(fwnode)) \
return acpi_dev_prop_read(acpi_node(fwnode), propname, \
__devprop_type, val); \
return -ENXIO; \
}
define_fwnode_accessors(u8, DEV_PROP_U8);
define_fwnode_accessors(u16, DEV_PROP_U16);
define_fwnode_accessors(u32, DEV_PROP_U32);
define_fwnode_accessors(u64, DEV_PROP_U64);
That significantly reduces the code size for these things.
So I was considering to do that, but eventually decided not to, because (1)
adding kerneldoc comments to such things looks odd and (2) (which IMO is
more important) this breaks LXR (for example, the thing at lxr.free-electrons.com
that some people, including me in particular, occasionally use to check how things
are defined). And even if you used the old good grep to look for a definition of
fwnode_property_read_u8, say, this wouldn't work exactly as expected I'm afraid.
Agreed, I'd also prefer your proposed code over Grant's macros.
Post by Rafael J. Wysocki
I would very much like to retain the headers at least for this reason, if that's
not a big deal.
What I can do, however, is to use macros for generating the bodies of those
functions.
Yes, just don't do any concatenation to generate the names of the called
functions, i.e.
return fwnode_call(of_property_read_u32, acpi_dev_prop_read, DEV_PROP_U32, node, propname, val);
is better than
return fwnode_call(u32, DEV_PROP_U32, node, propname, val);
because it's easier to understand the call chain.
Sounds reasonable. I've got no problem with that.

g.
Rafael J. Wysocki
2014-10-20 22:22:09 UTC
Permalink
Post by Arnd Bergmann
Post by Rafael J. Wysocki
Post by Grant Likely
#define define_fwnode_accessors(__type, __devprop_type) \
int device_property_read_##__type(struct device *dev, \
const char *propname, __type *val) \
{ \
if (IS_ENABLED(CONFIG_OF) && dev->of_node) \
return of_property_read_##__type(dev->of_node, propname, val); \
return acpi_dev_prop_read(ACPI_COMPANION(dev), propname, \
__devprop_type, val); \
} \
int fwnode_property_read_##__type(struct fwnode_handle *fwnode, \
const char *propname, __type *val) \
{ \
if (IS_ENABLED(CONFIG_OF) && is_of_node(fwnode)) \
return of_property_read_##__type(of_node(fwnode), propname, val); \
else if (IS_ENABLED(CONFIG_ACPI) && is_acpi_node(fwnode)) \
return acpi_dev_prop_read(acpi_node(fwnode), propname, \
__devprop_type, val); \
return -ENXIO; \
}
define_fwnode_accessors(u8, DEV_PROP_U8);
define_fwnode_accessors(u16, DEV_PROP_U16);
define_fwnode_accessors(u32, DEV_PROP_U32);
define_fwnode_accessors(u64, DEV_PROP_U64);
That significantly reduces the code size for these things.
So I was considering to do that, but eventually decided not to, because (1)
adding kerneldoc comments to such things looks odd and (2) (which IMO is
more important) this breaks LXR (for example, the thing at lxr.free-electrons.com
that some people, including me in particular, occasionally use to check how things
are defined). And even if you used the old good grep to look for a definition of
fwnode_property_read_u8, say, this wouldn't work exactly as expected I'm afraid.
Agreed, I'd also prefer your proposed code over Grant's macros.
Post by Rafael J. Wysocki
I would very much like to retain the headers at least for this reason, if that's
not a big deal.
What I can do, however, is to use macros for generating the bodies of those
functions.
Yes, just don't do any concatenation to generate the names of the called
functions, i.e.
return fwnode_call(of_property_read_u32, acpi_dev_prop_read, DEV_PROP_U32, node, propname, val);
is better than
return fwnode_call(u32, DEV_PROP_U32, node, propname, val);
because it's easier to understand the call chain.
There is one concatenation like that in the code I have today, but it was
already present in the $subject series, in the of_dev_prop_read_array macro
in patch #2 (and it actually makes sense to me).

Rafael
Greg Kroah-Hartman
2014-10-19 22:14:34 UTC
Permalink
Post by Rafael J. Wysocki
Add new generic routines are provided for retrieving properties from
device description objects in the platform firmware in case there are
no struct device objects for them (either those objects have not been
created yet or they do not exist at all).
fwnode_property_present()
fwnode_property_read_u8()
fwnode_property_read_u16()
fwnode_property_read_u32()
fwnode_property_read_u64()
fwnode_property_read_string()
fwnode_property_read_u8_array()
fwnode_property_read_u16_array()
fwnode_property_read_u32_array()
fwnode_property_read_u64_array()
fwnode_property_read_string_array()
in analogy with the corresponding functions for struct device added
previously. For all of them, the first argument is a pointer to struct
fwnode_handle (new type) that allows a device description object
(depending on what platform firmware interface is in use) to be
obtained.
Add a new macro device_for_each_child_node() for iterating over the
children of the device description object associated with a given
device and a new function device_get_child_node_count() returning the
number of a given device's child nodes.
The interface covers both ACPI and Device Trees.
Acked-by: Greg Kroah-Hartman <***@linuxfoundation.org>
Rafael J. Wysocki
2014-10-19 23:31:07 UTC
Permalink
Post by Rafael J. Wysocki
Add new generic routines are provided for retrieving properties from
device description objects in the platform firmware in case there are
no struct device objects for them (either those objects have not been
created yet or they do not exist at all).
fwnode_property_present()
fwnode_property_read_u8()
fwnode_property_read_u16()
fwnode_property_read_u32()
fwnode_property_read_u64()
fwnode_property_read_string()
fwnode_property_read_u8_array()
fwnode_property_read_u16_array()
fwnode_property_read_u32_array()
fwnode_property_read_u64_array()
fwnode_property_read_string_array()
in analogy with the corresponding functions for struct device added
previously. For all of them, the first argument is a pointer to struct
fwnode_handle (new type) that allows a device description object
(depending on what platform firmware interface is in use) to be
obtained.
Add a new macro device_for_each_child_node() for iterating over the
children of the device description object associated with a given
device and a new function device_get_child_node_count() returning the
number of a given device's child nodes.
The interface covers both ACPI and Device Trees.
Thanks!
Rafael J. Wysocki
2014-10-20 00:15:12 UTC
Permalink
From: Rafael J. Wysocki <***@intel.com>

Add new generic routines are provided for retrieving properties from
device description objects in the platform firmware in case there are
no struct device objects for them (either those objects have not been
created yet or they do not exist at all).

The following functions are provided:

fwnode_property_present()
fwnode_property_read_u8()
fwnode_property_read_u16()
fwnode_property_read_u32()
fwnode_property_read_u64()
fwnode_property_read_string()
fwnode_property_read_u8_array()
fwnode_property_read_u16_array()
fwnode_property_read_u32_array()
fwnode_property_read_u64_array()
fwnode_property_read_string_array()

in analogy with the corresponding functions for struct device added
previously. For all of them, the first argument is a pointer to struct
fwnode_handle (new type) that allows a device description object
(depending on what platform firmware interface is in use) to be
obtained.

Add a new macro device_for_each_child_node() for iterating over the
children of the device description object associated with a given
device and a new function device_get_child_node_count() returning the
number of a given device's child nodes.

The interface covers both ACPI and Device Trees.

Suggested-by: Grant Likely <***@linaro.org>
Acked-by: Greg Kroah-Hartman <***@linuxfoundation.org>
Signed-off-by: Rafael J. Wysocki <***@intel.com>
---

This applies on top of https://patchwork.kernel.org/patch/5101721/ .

It adds fwnode_property_read_bool() as a wrapper around fwnode_property_present()
and uses macros to generate the bodies of fwnode_property_read_*(), except for
fwnode_property_read_string_array() whose structure is a bit different from the
other functions.

Also added is the fresh ACK from Greg as the overall picture is still the same
as before.

Rafael

---
drivers/acpi/scan.c | 21 ++
drivers/base/property.c | 349 +++++++++++++++++++++++++++++++++++++++++++++++
include/acpi/acpi_bus.h | 17 ++
include/linux/acpi.h | 26 +++
include/linux/of.h | 22 ++
include/linux/property.h | 54 +++++++
6 files changed, 489 insertions(+)

Index: linux-pm/include/linux/property.h
===================================================================
--- linux-pm.orig/include/linux/property.h
+++ linux-pm/include/linux/property.h
@@ -44,10 +44,64 @@ int device_property_read_u64_array(struc
int device_property_read_string_array(struct device *dev, const char *propname,
char **val, size_t nval);

+enum fwnode_type {
+ FWNODE_INVALID = 0,
+ FWNODE_OF,
+ FWNODE_ACPI,
+};
+
+struct fwnode_handle {
+ enum fwnode_type type;
+};
+
+bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname);
+int fwnode_property_read_u8(struct fwnode_handle *fwnode, const char *propname,
+ u8 *val);
+int fwnode_property_read_u16(struct fwnode_handle *fwnode, const char *propname,
+ u16 *val);
+int fwnode_property_read_u32(struct fwnode_handle *fwnode, const char *propname,
+ u32 *val);
+int fwnode_property_read_u64(struct fwnode_handle *fwnode, const char *propname,
+ u64 *val);
+int fwnode_property_read_string(struct fwnode_handle *fwnode,
+ const char *propname, const char **val);
+int fwnode_property_read_u8_array(struct fwnode_handle *fwnode,
+ const char *propname, u8 *val,
+ size_t nval);
+int fwnode_property_read_u16_array(struct fwnode_handle *fwnode,
+ const char *propname, u16 *val,
+ size_t nval);
+int fwnode_property_read_u32_array(struct fwnode_handle *fwnode,
+ const char *propname, u32 *val,
+ size_t nval);
+int fwnode_property_read_u64_array(struct fwnode_handle *fwnode,
+ const char *propname, u64 *val,
+ size_t nval);
+int fwnode_property_read_string_array(struct fwnode_handle *fwnode,
+ const char *propname, char **val,
+ size_t nval);
+
+struct fwnode_handle *device_get_next_child_node(struct device *dev,
+ struct fwnode_handle *child);
+
+#define device_for_each_child_node(dev, child) \
+ for (child = device_get_next_child_node(dev, NULL); child; \
+ child = device_get_next_child_node(dev, child))
+
+void fwnode_handle_put(struct fwnode_handle *fwnode);
+
+unsigned int device_get_child_node_count(struct device *dev);
+
static inline bool device_property_read_bool(struct device *dev,
const char *propname)
{
return device_property_present(dev, propname);
}

+static inline bool fwnode_property_read_bool(struct fwnode_handle *fwnode,
+ const char *propname)
+{
+ return fwnode_property_present(fwnode, propname);
+}
+
#endif /* _LINUX_PROPERTY_H_ */
Index: linux-pm/include/acpi/acpi_bus.h
===================================================================
--- linux-pm.orig/include/acpi/acpi_bus.h
+++ linux-pm/include/acpi/acpi_bus.h
@@ -27,6 +27,7 @@
#define __ACPI_BUS_H__

#include <linux/device.h>
+#include <linux/property.h>

/* TBD: Make dynamic */
#define ACPI_MAX_HANDLES 10
@@ -348,6 +349,7 @@ struct acpi_device_data {
struct acpi_device {
int device_type;
acpi_handle handle; /* no handle for fixed hardware */
+ struct fwnode_handle fwnode;
struct acpi_device *parent;
struct list_head children;
struct list_head node;
@@ -372,6 +374,21 @@ struct acpi_device {
void (*remove)(struct acpi_device *);
};

+static inline bool is_acpi_node(struct fwnode_handle *fwnode)
+{
+ return fwnode && fwnode->type == FWNODE_ACPI;
+}
+
+static inline struct acpi_device *acpi_node(struct fwnode_handle *fwnode)
+{
+ return fwnode ? container_of(fwnode, struct acpi_device, fwnode) : NULL;
+}
+
+static inline struct fwnode_handle *acpi_fwnode_handle(struct acpi_device *adev)
+{
+ return &adev->fwnode;
+}
+
static inline void *acpi_driver_data(struct acpi_device *d)
{
return d->driver_data;
Index: linux-pm/include/linux/acpi.h
===================================================================
--- linux-pm.orig/include/linux/acpi.h
+++ linux-pm/include/linux/acpi.h
@@ -439,6 +439,23 @@ int acpi_device_modalias(struct device *
#define ACPI_COMPANION_SET(dev, adev) do { } while (0)
#define ACPI_HANDLE(dev) (NULL)

+struct fwnode_handle;
+
+static inline bool is_acpi_node(struct fwnode_handle *fwnode)
+{
+ return false;
+}
+
+static inline struct acpi_device *acpi_node(struct fwnode_handle *fwnode)
+{
+ return NULL;
+}
+
+static inline struct fwnode_handle *acpi_fwnode_handle(struct acpi_device *adev)
+{
+ return NULL;
+}
+
static inline const char *acpi_dev_name(struct acpi_device *adev)
{
return NULL;
@@ -681,6 +698,9 @@ int acpi_dev_prop_read(struct acpi_devic
int acpi_dev_prop_read_array(struct acpi_device *adev, const char *propname,
enum dev_prop_type proptype, void *val,
size_t nval);
+
+struct acpi_device *acpi_get_next_child(struct device *dev,
+ struct acpi_device *child);
#else
static inline int acpi_dev_get_property(struct acpi_device *adev,
const char *name, acpi_object_type type,
@@ -724,6 +744,12 @@ static inline int acpi_dev_prop_read_arr
return -ENXIO;
}

+static inline struct acpi_device *acpi_get_next_child(struct device *dev,
+ struct acpi_device *child)
+{
+ return NULL;
+}
+
#endif

#endif /*_LINUX_ACPI_H*/
Index: linux-pm/include/linux/of.h
===================================================================
--- linux-pm.orig/include/linux/of.h
+++ linux-pm/include/linux/of.h
@@ -50,6 +50,7 @@ struct device_node {
const char *type;
phandle phandle;
const char *full_name;
+ struct fwnode_handle fwnode;

struct property *properties;
struct property *deadprops; /* removed properties */
@@ -80,6 +81,7 @@ extern struct kobj_type of_node_ktype;
static inline void of_node_init(struct device_node *node)
{
kobject_init(&node->kobj, &of_node_ktype);
+ node->fwnode.type = FWNODE_OF;
}

/* true when node is initialized */
@@ -115,6 +117,16 @@ extern struct device_node *of_aliases;
extern struct device_node *of_stdout;
extern raw_spinlock_t devtree_lock;

+static inline bool is_of_node(struct fwnode_handle *fwnode)
+{
+ return fwnode && fwnode->type == FWNODE_OF;
+}
+
+static inline struct device_node *of_node(struct fwnode_handle *fwnode)
+{
+ return fwnode ? container_of(fwnode, struct device_node, fwnode) : NULL;
+}
+
static inline bool of_have_populated_dt(void)
{
return of_allnodes != NULL;
@@ -365,6 +377,16 @@ bool of_console_check(struct device_node

#else /* CONFIG_OF */

+static inline bool is_of_node(struct fwnode_handle *fwnode)
+{
+ return false;
+}
+
+static inline struct device_node *of_node(struct fwnode_handle *fwnode)
+{
+ return NULL;
+}
+
static inline const char* of_node_full_name(const struct device_node *np)
{
return "<no-node>";
Index: linux-pm/drivers/base/property.c
===================================================================
--- linux-pm.orig/drivers/base/property.c
+++ linux-pm/drivers/base/property.c
@@ -142,6 +142,151 @@ int device_property_read_string(struct d
}
EXPORT_SYMBOL_GPL(device_property_read_string);

+/**
+ * fwnode_property_present - check if a property of a firmware node is present
+ * @fwnode: Firmware node whose property to check
+ * @propname: Name of the property
+ */
+bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname)
+{
+ if (is_of_node(fwnode))
+ return of_property_read_bool(of_node(fwnode), propname);
+ else if (is_acpi_node(fwnode))
+ return !acpi_dev_prop_get(acpi_node(fwnode), propname, NULL);
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_present);
+
+#define FWNODE_PROPERTY_READ(_fwnode_, _propname_, _type_, _proptype_, _val_) \
+({ \
+ int _ret_; \
+ if (is_of_node(_fwnode_)) \
+ _ret_ = of_property_read_##_type_(of_node(_fwnode_), \
+ _propname_, _val_); \
+ else if (is_acpi_node(_fwnode_)) \
+ _ret_ = acpi_dev_prop_read(acpi_node(_fwnode_), _propname_, \
+ _proptype_, _val_); \
+ else \
+ _ret_ = -ENXIO; \
+ _ret_; \
+})
+
+/**
+ * fwnode_property_read_u8 - return a u8 property of a firmware node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The value is stored here
+ *
+ * Read property @propname from the given firmware node and store the value into
+ * @val if found. The value is checked to be of type u8.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property type is not u8,
+ * %-EOVERFLOW if the property value is out of bounds of u8,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u8(struct fwnode_handle *fwnode, const char *propname,
+ u8 *val)
+{
+ return FWNODE_PROPERTY_READ(fwnode, propname, u8, DEV_PROP_U8, val);
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u8);
+
+/**
+ * fwnode_property_read_u16 - return a u16 property of a firmware node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The value is stored here
+ *
+ * Read property @propname from the given firmware node and store the value into
+ * @val if found. The value is checked to be of type u16.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property type is not u16,
+ * %-EOVERFLOW if the property value is out of bounds of u16,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u16(struct fwnode_handle *fwnode, const char *propname,
+ u16 *val)
+{
+ return FWNODE_PROPERTY_READ(fwnode, propname, u16, DEV_PROP_U16, val);
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u16);
+
+/**
+ * fwnode_property_read_u32 - return a u32 property of a firmware node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The value is stored here
+ *
+ * Read property @propname from the given firmware node and store the value into
+ * @val if found. The value is checked to be of type u32.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property type is not u32,
+ * %-EOVERFLOW if the property value is out of bounds of u32,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u32(struct fwnode_handle *fwnode, const char *propname,
+ u32 *val)
+{
+ return FWNODE_PROPERTY_READ(fwnode, propname, u32, DEV_PROP_U32, val);
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u32);
+
+/**
+ * fwnode_property_read_u64 - return a u64 property of a firmware node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The value is stored here
+ *
+ * Read property @propname from the given firmware node and store the value into
+ * @val if found. The value is checked to be of type u64.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property type is not u64,
+ * %-EOVERFLOW if the property value is out of bounds of u64,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u64(struct fwnode_handle *fwnode, const char *propname,
+ u64 *val)
+{
+ return FWNODE_PROPERTY_READ(fwnode, propname, u64, DEV_PROP_U64, val);
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u64);
+
+/**
+ * fwnode_property_read_string - return a string property of a firmware node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The value is stored here
+ *
+ * Read property @propname from the given firmware node and store the value into
+ * @val if found. The value is checked to be a string.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property is not a string,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_string(struct fwnode_handle *fwnode,
+ const char *propname, const char **val)
+{
+ return FWNODE_PROPERTY_READ(fwnode, propname, string, DEV_PROP_STRING,
+ val);
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_string);
+
#define OF_DEV_PROP_READ_ARRAY(node, propname, type, val, nval) \
(val) ? of_property_read_##type##_array((node), (propname), (val), (nval)) \
: of_property_count_elems_of_size((node), (propname), sizeof(type))
@@ -274,3 +419,207 @@ int device_property_read_string_array(st
DEV_PROP_STRING, val, nval);
}
EXPORT_SYMBOL_GPL(device_property_read_string_array);
+
+#define FWNODE_PROPERTY_READ_ARRAY(_fwnode_, _propname_, _type_, _proptype_, _val_, _nval_) \
+({ \
+ int _ret_; \
+ if (is_of_node(_fwnode_)) \
+ _ret_ = OF_DEV_PROP_READ_ARRAY(of_node(_fwnode_), _propname_, \
+ _type_, _val_, _nval_); \
+ else if (is_acpi_node(_fwnode_)) \
+ _ret_ = acpi_dev_prop_read_array(acpi_node(_fwnode_), \
+ _propname_, _proptype_, \
+ _val_, _nval_); \
+ else \
+ _ret_ = -ENXIO; \
+ _ret_; \
+})
+
+/**
+ * fwnode_property_read_u8_array - return a u8 array property of firmware node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Read an array of u8 properties with @propname from @fwnode and stores them to
+ * @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u8_array(struct fwnode_handle *fwnode,
+ const char *propname, u8 *val, size_t nval)
+{
+ return FWNODE_PROPERTY_READ_ARRAY(fwnode, propname, u8, DEV_PROP_U8,
+ val, nval);
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u8_array);
+
+/**
+ * fwnode_property_read_u16_array - return a u16 array property of firmware node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Read an array of u16 properties with @propname from @fwnode and store them to
+ * @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u16_array(struct fwnode_handle *fwnode,
+ const char *propname, u16 *val, size_t nval)
+{
+ return FWNODE_PROPERTY_READ_ARRAY(fwnode, propname, u16, DEV_PROP_U16,
+ val, nval);
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u16_array);
+
+/**
+ * fwnode_property_read_u32_array - return a u32 array property of firmware node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Read an array of u32 properties with @propname from @fwnode store them to
+ * @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u32_array(struct fwnode_handle *fwnode,
+ const char *propname, u32 *val, size_t nval)
+{
+ return FWNODE_PROPERTY_READ_ARRAY(fwnode, propname, u32, DEV_PROP_U32,
+ val, nval);
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u32_array);
+
+/**
+ * fwnode_property_read_u64_array - return a u64 array property firmware node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Read an array of u64 properties with @propname from @fwnode and store them to
+ * @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u64_array(struct fwnode_handle *fwnode,
+ const char *propname, u64 *val, size_t nval)
+{
+ return FWNODE_PROPERTY_READ_ARRAY(fwnode, propname, u64, DEV_PROP_U64,
+ val, nval);
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u64_array);
+
+/**
+ * fwnode_property_read_string_array - return string array property of a node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Read an string list property @propname from the given firmware node and store
+ * them to @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of strings,
+ * %-EOVERFLOW if the size of the property is not as expected,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_string_array(struct fwnode_handle *fwnode,
+ const char *propname, char **val,
+ size_t nval)
+{
+ if (is_of_node(fwnode))
+ return of_property_read_string_array(of_node(fwnode), propname,
+ val, nval);
+ else if (is_acpi_node(fwnode))
+ return acpi_dev_prop_read_array(acpi_node(fwnode), propname,
+ DEV_PROP_STRING, val, nval);
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_string_array);
+
+
+/**
+ * device_get_next_child_node - Return the next child node handle for a device
+ * @dev: Device to find the next child node for.
+ * @child: Handle to one of the device's child nodes or a null handle.
+ */
+struct fwnode_handle *device_get_next_child_node(struct device *dev,
+ struct fwnode_handle *child)
+{
+ if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
+ struct device_node *node;
+
+ node = of_get_next_available_child(dev->of_node, of_node(child));
+ if (node)
+ return &node->fwnode;
+ } else if (ACPI_COMPANION(dev)) {
+ struct acpi_device *node;
+
+ node = acpi_get_next_child(dev, acpi_node(child));
+ if (node)
+ return acpi_fwnode_handle(node);
+ }
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(device_get_next_child_node);
+
+/**
+ * fwnode_handle_put - Drop reference to a device node
+ * @fwnode: Pointer to the device node to drop the reference to.
+ *
+ * This has to be used when terminating device_for_each_child_node() iteration
+ * with break or return to prevent stale device node references from being left
+ * behind.
+ */
+void fwnode_handle_put(struct fwnode_handle *fwnode)
+{
+ if (is_of_node(fwnode))
+ of_node_put(of_node(fwnode));
+}
+EXPORT_SYMBOL_GPL(fwnode_handle_put);
+
+/**
+ * device_get_child_node_count - return the number of child nodes for device
+ * @dev: Device to cound the child nodes for
+ */
+unsigned int device_get_child_node_count(struct device *dev)
+{
+ struct fwnode_handle *child;
+ unsigned int count = 0;
+
+ device_for_each_child_node(dev, child)
+ count++;
+
+ return count;
+}
+EXPORT_SYMBOL_GPL(device_get_child_node_count);
Index: linux-pm/drivers/acpi/scan.c
===================================================================
--- linux-pm.orig/drivers/acpi/scan.c
+++ linux-pm/drivers/acpi/scan.c
@@ -1342,6 +1342,26 @@ int acpi_device_add(struct acpi_device *
return result;
}

+struct acpi_device *acpi_get_next_child(struct device *dev,
+ struct acpi_device *child)
+{
+ struct acpi_device *adev = ACPI_COMPANION(dev);
+ struct list_head *head, *next;
+
+ if (!adev)
+ return NULL;
+
+ head = &adev->children;
+ if (list_empty(head))
+ return NULL;
+
+ if (!child)
+ return list_first_entry(head, struct acpi_device, node);
+
+ next = child->node.next;
+ return next == head ? NULL : list_entry(next, struct acpi_device, node);
+}
+
/* --------------------------------------------------------------------------
Driver Management
-------------------------------------------------------------------------- */
@@ -1961,6 +1981,7 @@ void acpi_init_device_object(struct acpi
device->device_type = type;
device->handle = handle;
device->parent = acpi_bus_get_parent(handle);
+ device->fwnode.type = FWNODE_ACPI;
acpi_set_device_status(device, sta);
acpi_device_get_busid(device);
acpi_set_pnp_ids(handle, &device->pnp, type);
Greg Kroah-Hartman
2014-10-17 15:40:07 UTC
Permalink
Hi Everyone,
Hving had a couple of chats with Grant and Arnd during LinuxCon EU/LPC, we
now have version 5 taking all feedback into account (hopefully).
Changes have been made to patch [02/12] and to patches [09-12/12], although
in patches [10-12/12] they are fairly minor. I have retained the Greg's
ACK on patch [02/12], because it is essentially the same that have been
posted aleady and ACKed by him (Greg, please let me know if I shouldn't
do that) and all the ACKs on the remaining patches except for patch [09/12]
which is substantially different. Still, if reviewers think that their
ACKs don't apply any more, please let me know and I'll remove them.
No objection from me to keep my ACK on those patches, thanks for asking.

greg k-h
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Darren Hart
2014-10-17 19:23:14 UTC
Permalink
Post by Greg Kroah-Hartman
Hi Everyone,
Hving had a couple of chats with Grant and Arnd during LinuxCon EU/LPC, we
now have version 5 taking all feedback into account (hopefully).
Changes have been made to patch [02/12] and to patches [09-12/12], although
in patches [10-12/12] they are fairly minor. I have retained the Greg's
ACK on patch [02/12], because it is essentially the same that have been
posted aleady and ACKed by him (Greg, please let me know if I shouldn't
do that) and all the ACKs on the remaining patches except for patch [09/12]
which is substantially different. Still, if reviewers think that their
ACKs don't apply any more, please let me know and I'll remove them.
No objection from me to keep my ACK on those patches, thanks for asking.
greg k-h
Mine certainly still apply as well.
--
Darren Hart
Intel Open Source Technology Center
Rafael J. Wysocki
2014-10-17 21:49:45 UTC
Permalink
Post by Greg Kroah-Hartman
Hi Everyone,
Hving had a couple of chats with Grant and Arnd during LinuxCon EU/LPC, we
now have version 5 taking all feedback into account (hopefully).
Changes have been made to patch [02/12] and to patches [09-12/12], although
in patches [10-12/12] they are fairly minor. I have retained the Greg's
ACK on patch [02/12], because it is essentially the same that have been
posted aleady and ACKed by him (Greg, please let me know if I shouldn't
do that) and all the ACKs on the remaining patches except for patch [09/12]
which is substantially different. Still, if reviewers think that their
ACKs don't apply any more, please let me know and I'll remove them.
No objection from me to keep my ACK on those patches, thanks for asking.
Well, that's just fair IMO. :-)

Does [09/12] look good too in particular?

Rafael

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Greg Kroah-Hartman
2014-10-19 22:14:12 UTC
Permalink
Post by Rafael J. Wysocki
Post by Greg Kroah-Hartman
Hi Everyone,
Hving had a couple of chats with Grant and Arnd during LinuxCon EU/LPC, we
now have version 5 taking all feedback into account (hopefully).
Changes have been made to patch [02/12] and to patches [09-12/12], although
in patches [10-12/12] they are fairly minor. I have retained the Greg's
ACK on patch [02/12], because it is essentially the same that have been
posted aleady and ACKed by him (Greg, please let me know if I shouldn't
do that) and all the ACKs on the remaining patches except for patch [09/12]
which is substantially different. Still, if reviewers think that their
ACKs don't apply any more, please let me know and I'll remove them.
No objection from me to keep my ACK on those patches, thanks for asking.
Well, that's just fair IMO. :-)
Does [09/12] look good too in particular?
Yes, I have no objections to it.
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Arnd Bergmann
2014-10-17 18:04:52 UTC
Permalink
Hi Everyone,
Hving had a couple of chats with Grant and Arnd during LinuxCon EU/LPC, we
now have version 5 taking all feedback into account (hopefully).
Awesome, that was really fast. I'm currently on my way his me in the train, replying from my phone, but it looks good now. I'll have a more detailed look next week but I'm definitely happy to see this go in (to next and 3.19) now, any details we still find can be fixed on top.
In
short, if
we are passed a struct fwnode_handle pointer, we can get from it to the
appropriate device node pointer (either struct acpi_device or struct device_node)
using container_of() after we've checked the type. This is needed for the code
that needs to access child nodes of a device in case when they don't have
struct device representations (whatever the reason). This has been suggested
by Grant and pretty much everyone involved agrees that it's better that the
alternatives presented so far.
Yes, it's nice enough that I now take back all the objections I had for the child accessory API.

Arnd
Rafael J. Wysocki
2014-10-17 22:50:00 UTC
Permalink
Post by Arnd Bergmann
Hi Everyone,
Hving had a couple of chats with Grant and Arnd during LinuxCon EU/LPC, we
now have version 5 taking all feedback into account (hopefully).
Awesome, that was really fast. I'm currently on my way his me in
the train, replying from my phone, but it looks good now. I'll have a more
detailed look next week but I'm definitely happy to see this go in (to next
and 3.19) now, any details we still find can be fixed on top.
In
short, if
we are passed a struct fwnode_handle pointer, we can get from it to the
appropriate device node pointer (either struct acpi_device or struct device_node)
using container_of() after we've checked the type. This is needed for the code
that needs to access child nodes of a device in case when they don't have
struct device representations (whatever the reason). This has been suggested
by Grant and pretty much everyone involved agrees that it's better that the
alternatives presented so far.
Yes, it's nice enough that I now take back all the objections I had for the
child accessory API.
Cool, thanks!

I've just refreshed the device-properties branch of the linux-pm.git tree
and it contains the current material now (including a couple of build
fixes reported by the autobuild robot in patches [02/12] and [09/12]).

My plan is to merge this into the linux-next branch when 3.18-rc1 is out.

Rafael

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Grant Likely
2014-10-18 08:49:59 UTC
Permalink
On Sat, 18 Oct 2014 00:50 +0200
Post by Rafael J. Wysocki
Post by Arnd Bergmann
Hi Everyone,
Hving had a couple of chats with Grant and Arnd during LinuxCon EU/LPC, we
now have version 5 taking all feedback into account (hopefully).
Awesome, that was really fast. I'm currently on my way his me in
the train, replying from my phone, but it looks good now. I'll have a more
detailed look next week but I'm definitely happy to see this go in (to next
and 3.19) now, any details we still find can be fixed on top.
In
short, if
we are passed a struct fwnode_handle pointer, we can get from it to the
appropriate device node pointer (either struct acpi_device or struct device_node)
using container_of() after we've checked the type. This is needed for the code
that needs to access child nodes of a device in case when they don't have
struct device representations (whatever the reason). This has been suggested
by Grant and pretty much everyone involved agrees that it's better that the
alternatives presented so far.
Yes, it's nice enough that I now take back all the objections I had for the
child accessory API.
Cool, thanks!
I've just refreshed the device-properties branch of the linux-pm.git tree
and it contains the current material now (including a couple of build
fixes reported by the autobuild robot in patches [02/12] and [09/12]).
My plan is to merge this into the linux-next branch when 3.18-rc1 is out.
Wait for my ack please, but I should be able to review it this weekend
or on Monday. I'm actually reviewing now, but I'm on a plane near the
end of the flight. As soon as I get on the ground SIGFAMILY will
interrupt me for a bit. :-)

g.
Rafael J. Wysocki
2014-10-19 23:32:06 UTC
Permalink
Post by Grant Likely
On Sat, 18 Oct 2014 00:50 +0200
Post by Rafael J. Wysocki
Post by Arnd Bergmann
Hi Everyone,
Hving had a couple of chats with Grant and Arnd during LinuxCon EU/LPC, we
now have version 5 taking all feedback into account (hopefully).
Awesome, that was really fast. I'm currently on my way his me in
the train, replying from my phone, but it looks good now. I'll have a more
detailed look next week but I'm definitely happy to see this go in (to next
and 3.19) now, any details we still find can be fixed on top.
In
short, if
we are passed a struct fwnode_handle pointer, we can get from it to the
appropriate device node pointer (either struct acpi_device or struct device_node)
using container_of() after we've checked the type. This is needed for the code
that needs to access child nodes of a device in case when they don't have
struct device representations (whatever the reason). This has been suggested
by Grant and pretty much everyone involved agrees that it's better that the
alternatives presented so far.
Yes, it's nice enough that I now take back all the objections I had for the
child accessory API.
Cool, thanks!
I've just refreshed the device-properties branch of the linux-pm.git tree
and it contains the current material now (including a couple of build
fixes reported by the autobuild robot in patches [02/12] and [09/12]).
My plan is to merge this into the linux-next branch when 3.18-rc1 is out.
Wait for my ack please, but I should be able to review it this weekend
or on Monday. I'm actually reviewing now, but I'm on a plane near the
end of the flight. As soon as I get on the ground SIGFAMILY will
interrupt me for a bit. :-)
Sure, I won't be trying to push things that you don't like :-)

Rafael

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Loading...