drm/amd/amdgpu:flush ttm delayed work before cancel_sync
[linux-2.6-microblaze.git] / drivers / leds / leds-ns2.c
index bd806e7..1677d66 100644 (file)
@@ -24,25 +24,16 @@ enum ns2_led_modes {
        NS_V2_LED_SATA,
 };
 
+/*
+ * If the size of this structure or types of its members is changed,
+ * the filling of array modval in function ns2_led_register must be changed
+ * accordingly.
+ */
 struct ns2_led_modval {
-       enum ns2_led_modes      mode;
-       int                     cmd_level;
-       int                     slow_level;
-};
-
-struct ns2_led {
-       const char      *name;
-       const char      *default_trigger;
-       struct gpio_desc *cmd;
-       struct gpio_desc *slow;
-       int             num_modes;
-       struct ns2_led_modval *modval;
-};
-
-struct ns2_led_platform_data {
-       int             num_leds;
-       struct ns2_led  *leds;
-};
+       u32                     mode;
+       u32                     cmd_level;
+       u32                     slow_level;
+} __packed;
 
 /*
  * The Network Space v2 dual-GPIO LED is wired to a CPLD. Three different LED
@@ -51,7 +42,7 @@ struct ns2_led_platform_data {
  * for the command/slow GPIOs corresponds to a LED mode.
  */
 
-struct ns2_led_data {
+struct ns2_led {
        struct led_classdev     cdev;
        struct gpio_desc        *cmd;
        struct gpio_desc        *slow;
@@ -62,77 +53,67 @@ struct ns2_led_data {
        struct ns2_led_modval   *modval;
 };
 
-static int ns2_led_get_mode(struct ns2_led_data *led_dat,
-                           enum ns2_led_modes *mode)
+static int ns2_led_get_mode(struct ns2_led *led, enum ns2_led_modes *mode)
 {
        int i;
-       int ret = -EINVAL;
        int cmd_level;
        int slow_level;
 
-       cmd_level = gpiod_get_value_cansleep(led_dat->cmd);
-       slow_level = gpiod_get_value_cansleep(led_dat->slow);
+       cmd_level = gpiod_get_value_cansleep(led->cmd);
+       slow_level = gpiod_get_value_cansleep(led->slow);
 
-       for (i = 0; i < led_dat->num_modes; i++) {
-               if (cmd_level == led_dat->modval[i].cmd_level &&
-                   slow_level == led_dat->modval[i].slow_level) {
-                       *mode = led_dat->modval[i].mode;
-                       ret = 0;
-                       break;
+       for (i = 0; i < led->num_modes; i++) {
+               if (cmd_level == led->modval[i].cmd_level &&
+                   slow_level == led->modval[i].slow_level) {
+                       *mode = led->modval[i].mode;
+                       return 0;
                }
        }
 
-       return ret;
+       return -EINVAL;
 }
 
-static void ns2_led_set_mode(struct ns2_led_data *led_dat,
-                            enum ns2_led_modes mode)
+static void ns2_led_set_mode(struct ns2_led *led, enum ns2_led_modes mode)
 {
        int i;
-       bool found = false;
        unsigned long flags;
 
-       for (i = 0; i < led_dat->num_modes; i++)
-               if (mode == led_dat->modval[i].mode) {
-                       found = true;
+       for (i = 0; i < led->num_modes; i++)
+               if (mode == led->modval[i].mode)
                        break;
-               }
 
-       if (!found)
+       if (i == led->num_modes)
                return;
 
-       write_lock_irqsave(&led_dat->rw_lock, flags);
+       write_lock_irqsave(&led->rw_lock, flags);
 
-       if (!led_dat->can_sleep) {
-               gpiod_set_value(led_dat->cmd,
-                               led_dat->modval[i].cmd_level);
-               gpiod_set_value(led_dat->slow,
-                               led_dat->modval[i].slow_level);
+       if (!led->can_sleep) {
+               gpiod_set_value(led->cmd, led->modval[i].cmd_level);
+               gpiod_set_value(led->slow, led->modval[i].slow_level);
                goto exit_unlock;
        }
 
-       gpiod_set_value_cansleep(led_dat->cmd, led_dat->modval[i].cmd_level);
-       gpiod_set_value_cansleep(led_dat->slow, led_dat->modval[i].slow_level);
+       gpiod_set_value_cansleep(led->cmd, led->modval[i].cmd_level);
+       gpiod_set_value_cansleep(led->slow, led->modval[i].slow_level);
 
 exit_unlock:
-       write_unlock_irqrestore(&led_dat->rw_lock, flags);
+       write_unlock_irqrestore(&led->rw_lock, flags);
 }
 
 static void ns2_led_set(struct led_classdev *led_cdev,
                        enum led_brightness value)
 {
-       struct ns2_led_data *led_dat =
-               container_of(led_cdev, struct ns2_led_data, cdev);
+       struct ns2_led *led = container_of(led_cdev, struct ns2_led, cdev);
        enum ns2_led_modes mode;
 
        if (value == LED_OFF)
                mode = NS_V2_LED_OFF;
-       else if (led_dat->sata)
+       else if (led->sata)
                mode = NS_V2_LED_SATA;
        else
                mode = NS_V2_LED_ON;
 
-       ns2_led_set_mode(led_dat, mode);
+       ns2_led_set_mode(led, mode);
 }
 
 static int ns2_led_set_blocking(struct led_classdev *led_cdev,
@@ -147,8 +128,7 @@ static ssize_t ns2_led_sata_store(struct device *dev,
                                  const char *buff, size_t count)
 {
        struct led_classdev *led_cdev = dev_get_drvdata(dev);
-       struct ns2_led_data *led_dat =
-               container_of(led_cdev, struct ns2_led_data, cdev);
+       struct ns2_led *led = container_of(led_cdev, struct ns2_led, cdev);
        int ret;
        unsigned long enable;
 
@@ -158,18 +138,18 @@ static ssize_t ns2_led_sata_store(struct device *dev,
 
        enable = !!enable;
 
-       if (led_dat->sata == enable)
+       if (led->sata == enable)
                goto exit;
 
-       led_dat->sata = enable;
+       led->sata = enable;
 
        if (!led_get_brightness(led_cdev))
                goto exit;
 
        if (enable)
-               ns2_led_set_mode(led_dat, NS_V2_LED_SATA);
+               ns2_led_set_mode(led, NS_V2_LED_SATA);
        else
-               ns2_led_set_mode(led_dat, NS_V2_LED_ON);
+               ns2_led_set_mode(led, NS_V2_LED_ON);
 
 exit:
        return count;
@@ -179,10 +159,9 @@ static ssize_t ns2_led_sata_show(struct device *dev,
                                 struct device_attribute *attr, char *buf)
 {
        struct led_classdev *led_cdev = dev_get_drvdata(dev);
-       struct ns2_led_data *led_dat =
-               container_of(led_cdev, struct ns2_led_data, cdev);
+       struct ns2_led *led = container_of(led_cdev, struct ns2_led, cdev);
 
-       return sprintf(buf, "%d\n", led_dat->sata);
+       return sprintf(buf, "%d\n", led->sata);
 }
 
 static DEVICE_ATTR(sata, 0644, ns2_led_sata_show, ns2_led_sata_store);
@@ -193,147 +172,94 @@ static struct attribute *ns2_led_attrs[] = {
 };
 ATTRIBUTE_GROUPS(ns2_led);
 
-static int
-create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat,
-              const struct ns2_led *template)
+static int ns2_led_register(struct device *dev, struct fwnode_handle *node,
+                           struct ns2_led *led)
 {
-       int ret;
+       struct led_init_data init_data = {};
+       struct ns2_led_modval *modval;
        enum ns2_led_modes mode;
+       int nmodes, ret;
+
+       led->cmd = devm_fwnode_gpiod_get_index(dev, node, "cmd", 0, GPIOD_ASIS,
+                                              fwnode_get_name(node));
+       if (IS_ERR(led->cmd))
+               return PTR_ERR(led->cmd);
+
+       led->slow = devm_fwnode_gpiod_get_index(dev, node, "slow", 0,
+                                               GPIOD_ASIS,
+                                               fwnode_get_name(node));
+       if (IS_ERR(led->slow))
+               return PTR_ERR(led->slow);
+
+       ret = fwnode_property_count_u32(node, "modes-map");
+       if (ret < 0 || ret % 3) {
+               dev_err(dev, "Missing or malformed modes-map for %pfw\n", node);
+               return -EINVAL;
+       }
+
+       nmodes = ret / 3;
+       modval = devm_kcalloc(dev, nmodes, sizeof(*modval), GFP_KERNEL);
+       if (!modval)
+               return -ENOMEM;
+
+       fwnode_property_read_u32_array(node, "modes-map", (void *)modval,
+                                      nmodes * 3);
+
+       rwlock_init(&led->rw_lock);
 
-       rwlock_init(&led_dat->rw_lock);
-
-       led_dat->cdev.name = template->name;
-       led_dat->cdev.default_trigger = template->default_trigger;
-       led_dat->cdev.blink_set = NULL;
-       led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
-       led_dat->cdev.groups = ns2_led_groups;
-       led_dat->cmd = template->cmd;
-       led_dat->slow = template->slow;
-       led_dat->can_sleep = gpiod_cansleep(led_dat->cmd) |
-                               gpiod_cansleep(led_dat->slow);
-       if (led_dat->can_sleep)
-               led_dat->cdev.brightness_set_blocking = ns2_led_set_blocking;
+       led->cdev.blink_set = NULL;
+       led->cdev.flags |= LED_CORE_SUSPENDRESUME;
+       led->cdev.groups = ns2_led_groups;
+       led->can_sleep = gpiod_cansleep(led->cmd) || gpiod_cansleep(led->slow);
+       if (led->can_sleep)
+               led->cdev.brightness_set_blocking = ns2_led_set_blocking;
        else
-               led_dat->cdev.brightness_set = ns2_led_set;
-       led_dat->modval = template->modval;
-       led_dat->num_modes = template->num_modes;
+               led->cdev.brightness_set = ns2_led_set;
+       led->num_modes = nmodes;
+       led->modval = modval;
 
-       ret = ns2_led_get_mode(led_dat, &mode);
+       ret = ns2_led_get_mode(led, &mode);
        if (ret < 0)
                return ret;
 
        /* Set LED initial state. */
-       led_dat->sata = (mode == NS_V2_LED_SATA) ? 1 : 0;
-       led_dat->cdev.brightness =
-               (mode == NS_V2_LED_OFF) ? LED_OFF : LED_FULL;
+       led->sata = (mode == NS_V2_LED_SATA) ? 1 : 0;
+       led->cdev.brightness = (mode == NS_V2_LED_OFF) ? LED_OFF : LED_FULL;
 
-       ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
-       if (ret < 0)
-               return ret;
+       init_data.fwnode = node;
 
-       return 0;
-}
+       ret = devm_led_classdev_register_ext(dev, &led->cdev, &init_data);
+       if (ret)
+               dev_err(dev, "Failed to register LED for node %pfw\n", node);
 
-static void delete_ns2_led(struct ns2_led_data *led_dat)
-{
-       led_classdev_unregister(&led_dat->cdev);
+       return ret;
 }
 
-#ifdef CONFIG_OF_GPIO
-/*
- * Translate OpenFirmware node properties into platform_data.
- */
-static int
-ns2_leds_get_of_pdata(struct device *dev, struct ns2_led_platform_data *pdata)
+static int ns2_led_probe(struct platform_device *pdev)
 {
-       struct device_node *np = dev->of_node;
-       struct device_node *child;
-       struct ns2_led *led, *leds;
-       int ret, num_leds = 0;
+       struct device *dev = &pdev->dev;
+       struct fwnode_handle *child;
+       struct ns2_led *leds;
+       int count;
+       int ret;
 
-       num_leds = of_get_child_count(np);
-       if (!num_leds)
+       count = device_get_child_node_count(dev);
+       if (!count)
                return -ENODEV;
 
-       leds = devm_kcalloc(dev, num_leds, sizeof(struct ns2_led),
-                           GFP_KERNEL);
+       leds = devm_kzalloc(dev, array_size(sizeof(*leds), count), GFP_KERNEL);
        if (!leds)
                return -ENOMEM;
 
-       led = leds;
-       for_each_child_of_node(np, child) {
-               const char *string;
-               int i, num_modes;
-               struct ns2_led_modval *modval;
-               struct gpio_desc *gd;
-
-               ret = of_property_read_string(child, "label", &string);
-               led->name = (ret == 0) ? string : child->name;
-
-               gd = gpiod_get_from_of_node(child, "cmd-gpio", 0,
-                                           GPIOD_ASIS, led->name);
-               if (IS_ERR(gd)) {
-                       ret = PTR_ERR(gd);
-                       goto err_node_put;
-               }
-               led->cmd = gd;
-               gd = gpiod_get_from_of_node(child, "slow-gpio", 0,
-                                           GPIOD_ASIS, led->name);
-               if (IS_ERR(gd)) {
-                       ret = PTR_ERR(gd);
-                       goto err_node_put;
-               }
-               led->slow = gd;
-
-               ret = of_property_read_string(child, "linux,default-trigger",
-                                             &string);
-               if (ret == 0)
-                       led->default_trigger = string;
-
-               ret = of_property_count_u32_elems(child, "modes-map");
-               if (ret < 0 || ret % 3) {
-                       dev_err(dev,
-                               "Missing or malformed modes-map property\n");
-                       ret = -EINVAL;
-                       goto err_node_put;
-               }
-
-               num_modes = ret / 3;
-               modval = devm_kcalloc(dev,
-                                     num_modes,
-                                     sizeof(struct ns2_led_modval),
-                                     GFP_KERNEL);
-               if (!modval) {
-                       ret = -ENOMEM;
-                       goto err_node_put;
-               }
-
-               for (i = 0; i < num_modes; i++) {
-                       of_property_read_u32_index(child,
-                                               "modes-map", 3 * i,
-                                               (u32 *) &modval[i].mode);
-                       of_property_read_u32_index(child,
-                                               "modes-map", 3 * i + 1,
-                                               (u32 *) &modval[i].cmd_level);
-                       of_property_read_u32_index(child,
-                                               "modes-map", 3 * i + 2,
-                                               (u32 *) &modval[i].slow_level);
+       device_for_each_child_node(dev, child) {
+               ret = ns2_led_register(dev, child, leds++);
+               if (ret) {
+                       fwnode_handle_put(child);
+                       return ret;
                }
-
-               led->num_modes = num_modes;
-               led->modval = modval;
-
-               led++;
        }
 
-       pdata->leds = leds;
-       pdata->num_leds = num_leds;
-
        return 0;
-
-err_node_put:
-       of_node_put(child);
-       return ret;
 }
 
 static const struct of_device_id of_ns2_leds_match[] = {
@@ -341,76 +267,12 @@ static const struct of_device_id of_ns2_leds_match[] = {
        {},
 };
 MODULE_DEVICE_TABLE(of, of_ns2_leds_match);
-#endif /* CONFIG_OF_GPIO */
-
-struct ns2_led_priv {
-       int num_leds;
-       struct ns2_led_data leds_data[];
-};
-
-static int ns2_led_probe(struct platform_device *pdev)
-{
-       struct ns2_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
-       struct ns2_led_priv *priv;
-       int i;
-       int ret;
-
-#ifdef CONFIG_OF_GPIO
-       if (!pdata) {
-               pdata = devm_kzalloc(&pdev->dev,
-                                    sizeof(struct ns2_led_platform_data),
-                                    GFP_KERNEL);
-               if (!pdata)
-                       return -ENOMEM;
-
-               ret = ns2_leds_get_of_pdata(&pdev->dev, pdata);
-               if (ret)
-                       return ret;
-       }
-#else
-       if (!pdata)
-               return -EINVAL;
-#endif /* CONFIG_OF_GPIO */
-
-       priv = devm_kzalloc(&pdev->dev, struct_size(priv, leds_data, pdata->num_leds), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-       priv->num_leds = pdata->num_leds;
-
-       for (i = 0; i < priv->num_leds; i++) {
-               ret = create_ns2_led(pdev, &priv->leds_data[i],
-                                    &pdata->leds[i]);
-               if (ret < 0) {
-                       for (i = i - 1; i >= 0; i--)
-                               delete_ns2_led(&priv->leds_data[i]);
-                       return ret;
-               }
-       }
-
-       platform_set_drvdata(pdev, priv);
-
-       return 0;
-}
-
-static int ns2_led_remove(struct platform_device *pdev)
-{
-       int i;
-       struct ns2_led_priv *priv;
-
-       priv = platform_get_drvdata(pdev);
-
-       for (i = 0; i < priv->num_leds; i++)
-               delete_ns2_led(&priv->leds_data[i]);
-
-       return 0;
-}
 
 static struct platform_driver ns2_led_driver = {
        .probe          = ns2_led_probe,
-       .remove         = ns2_led_remove,
        .driver         = {
                .name           = "leds-ns2",
-               .of_match_table = of_match_ptr(of_ns2_leds_match),
+               .of_match_table = of_ns2_leds_match,
        },
 };