pwm: Add device tree support
authorThierry Reding <thierry.reding@avionic-design.de>
Wed, 14 Dec 2011 10:10:32 +0000 (11:10 +0100)
committerThierry Reding <thierry.reding@avionic-design.de>
Fri, 15 Jun 2012 10:56:57 +0000 (12:56 +0200)
This patch adds helpers to support device tree bindings for the generic
PWM API. Device tree binding documentation for PWM controllers is also
provided.

Acked-by: Arnd Bergmann <arnd@arndb.de>
Reviewed-by: Shawn Guo <shawn.guo@linaro.org>
Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
Documentation/devicetree/bindings/pwm/pwm.txt [new file with mode: 0644]
drivers/pwm/core.c
include/linux/pwm.h

diff --git a/Documentation/devicetree/bindings/pwm/pwm.txt b/Documentation/devicetree/bindings/pwm/pwm.txt
new file mode 100644 (file)
index 0000000..73ec962
--- /dev/null
@@ -0,0 +1,57 @@
+Specifying PWM information for devices
+======================================
+
+1) PWM user nodes
+-----------------
+
+PWM users should specify a list of PWM devices that they want to use
+with a property containing a 'pwm-list':
+
+       pwm-list ::= <single-pwm> [pwm-list]
+       single-pwm ::= <pwm-phandle> <pwm-specifier>
+       pwm-phandle : phandle to PWM controller node
+       pwm-specifier : array of #pwm-cells specifying the given PWM
+                       (controller specific)
+
+PWM properties should be named "pwms". The exact meaning of each pwms
+property must be documented in the device tree binding for each device.
+An optional property "pwm-names" may contain a list of strings to label
+each of the PWM devices listed in the "pwms" property. If no "pwm-names"
+property is given, the name of the user node will be used as fallback.
+
+Drivers for devices that use more than a single PWM device can use the
+"pwm-names" property to map the name of the PWM device requested by the
+pwm_get() call to an index into the list given by the "pwms" property.
+
+The following example could be used to describe a PWM-based backlight
+device:
+
+       pwm: pwm {
+               #pwm-cells = <2>;
+       };
+
+       [...]
+
+       bl: backlight {
+               pwms = <&pwm 0 5000000>;
+               pwm-names = "backlight";
+       };
+
+pwm-specifier typically encodes the chip-relative PWM number and the PWM
+period in nanoseconds. Note that in the example above, specifying the
+"pwm-names" is redundant because the name "backlight" would be used as
+fallback anyway.
+
+2) PWM controller nodes
+-----------------------
+
+PWM controller nodes must specify the number of cells used for the
+specifier using the '#pwm-cells' property.
+
+An example PWM controller might look like this:
+
+       pwm: pwm@7000a000 {
+               compatible = "nvidia,tegra20-pwm";
+               reg = <0x7000a000 0x100>;
+               #pwm-cells = <2>;
+       };
index a2af599e61ae3434b174286df47eb622742724da..dbab53005da8a944928d827b483236e85b76cc2b 100644 (file)
@@ -129,6 +129,45 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label)
        return 0;
 }
 
+static struct pwm_device *of_pwm_simple_xlate(struct pwm_chip *pc,
+                                             const struct of_phandle_args *args)
+{
+       struct pwm_device *pwm;
+
+       if (pc->of_pwm_n_cells < 2)
+               return ERR_PTR(-EINVAL);
+
+       if (args->args[0] >= pc->npwm)
+               return ERR_PTR(-EINVAL);
+
+       pwm = pwm_request_from_chip(pc, args->args[0], NULL);
+       if (IS_ERR(pwm))
+               return pwm;
+
+       pwm_set_period(pwm, args->args[1]);
+
+       return pwm;
+}
+
+void of_pwmchip_add(struct pwm_chip *chip)
+{
+       if (!chip->dev || !chip->dev->of_node)
+               return;
+
+       if (!chip->of_xlate) {
+               chip->of_xlate = of_pwm_simple_xlate;
+               chip->of_pwm_n_cells = 2;
+       }
+
+       of_node_get(chip->dev->of_node);
+}
+
+void of_pwmchip_remove(struct pwm_chip *chip)
+{
+       if (chip->dev && chip->dev->of_node)
+               of_node_put(chip->dev->of_node);
+}
+
 /**
  * pwm_set_chip_data() - set private chip data for a PWM
  * @pwm: PWM device
@@ -201,6 +240,9 @@ int pwmchip_add(struct pwm_chip *chip)
 
        ret = 0;
 
+       if (IS_ENABLED(CONFIG_OF))
+               of_pwmchip_add(chip);
+
 out:
        mutex_unlock(&pwm_lock);
        return ret;
@@ -231,6 +273,10 @@ int pwmchip_remove(struct pwm_chip *chip)
        }
 
        list_del_init(&chip->list);
+
+       if (IS_ENABLED(CONFIG_OF))
+               of_pwmchip_remove(chip);
+
        free_pwms(chip);
 
 out:
@@ -356,6 +402,99 @@ void pwm_disable(struct pwm_device *pwm)
 }
 EXPORT_SYMBOL_GPL(pwm_disable);
 
+static struct pwm_chip *of_node_to_pwmchip(struct device_node *np)
+{
+       struct pwm_chip *chip;
+
+       mutex_lock(&pwm_lock);
+
+       list_for_each_entry(chip, &pwm_chips, list)
+               if (chip->dev && chip->dev->of_node == np) {
+                       mutex_unlock(&pwm_lock);
+                       return chip;
+               }
+
+       mutex_unlock(&pwm_lock);
+
+       return ERR_PTR(-EPROBE_DEFER);
+}
+
+/**
+ * of_pwm_request() - request a PWM via the PWM framework
+ * @np: device node to get the PWM from
+ * @con_id: consumer name
+ *
+ * Returns the PWM device parsed from the phandle and index specified in the
+ * "pwms" property of a device tree node or a negative error-code on failure.
+ * Values parsed from the device tree are stored in the returned PWM device
+ * object.
+ *
+ * If con_id is NULL, the first PWM device listed in the "pwms" property will
+ * be requested. Otherwise the "pwm-names" property is used to do a reverse
+ * lookup of the PWM index. This also means that the "pwm-names" property
+ * becomes mandatory for devices that look up the PWM device via the con_id
+ * parameter.
+ */
+static struct pwm_device *of_pwm_request(struct device_node *np,
+                                        const char *con_id)
+{
+       struct pwm_device *pwm = NULL;
+       struct of_phandle_args args;
+       struct pwm_chip *pc;
+       int index = 0;
+       int err;
+
+       if (con_id) {
+               index = of_property_match_string(np, "pwm-names", con_id);
+               if (index < 0)
+                       return ERR_PTR(index);
+       }
+
+       err = of_parse_phandle_with_args(np, "pwms", "#pwm-cells", index,
+                                        &args);
+       if (err) {
+               pr_debug("%s(): can't parse \"pwms\" property\n", __func__);
+               return ERR_PTR(err);
+       }
+
+       pc = of_node_to_pwmchip(args.np);
+       if (IS_ERR(pc)) {
+               pr_debug("%s(): PWM chip not found\n", __func__);
+               pwm = ERR_CAST(pc);
+               goto put;
+       }
+
+       if (args.args_count != pc->of_pwm_n_cells) {
+               pr_debug("%s: wrong #pwm-cells for %s\n", np->full_name,
+                        args.np->full_name);
+               pwm = ERR_PTR(-EINVAL);
+               goto put;
+       }
+
+       pwm = pc->of_xlate(pc, &args);
+       if (IS_ERR(pwm))
+               goto put;
+
+       /*
+        * If a consumer name was not given, try to look it up from the
+        * "pwm-names" property if it exists. Otherwise use the name of
+        * the user device node.
+        */
+       if (!con_id) {
+               err = of_property_read_string_index(np, "pwm-names", index,
+                                                   &con_id);
+               if (err < 0)
+                       con_id = np->name;
+       }
+
+       pwm->label = con_id;
+
+put:
+       of_node_put(args.np);
+
+       return pwm;
+}
+
 /**
  * pwm_add_table() - register PWM device consumers
  * @table: array of consumers to register
@@ -378,8 +517,9 @@ void __init pwm_add_table(struct pwm_lookup *table, size_t num)
  * @dev: device for PWM consumer
  * @con_id: consumer name
  *
- * Look up a PWM chip and a relative index via a table supplied by board setup
- * code (see pwm_add_table()).
+ * Lookup is first attempted using DT. If the device was not instantiated from
+ * a device tree, a PWM chip and a relative index is looked up via a table
+ * supplied by board setup code (see pwm_add_table()).
  *
  * Once a PWM chip has been found the specified PWM device will be requested
  * and is ready to be used.
@@ -394,6 +534,10 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id)
        unsigned int index;
        unsigned int match;
 
+       /* look up via DT first */
+       if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node)
+               return of_pwm_request(dev->of_node, con_id);
+
        /*
         * We look up the provider in the static table typically provided by
         * board setup code. We first try to lookup the consumer device by
index 2947a4fea6ad076a1e24790b6242ca0b9011f76d..21d076c5089e9646418113fb9d27d30e4ba109f7 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __LINUX_PWM_H
 #define __LINUX_PWM_H
 
+#include <linux/of.h>
+
 struct pwm_device;
 struct seq_file;
 
@@ -105,6 +107,10 @@ struct pwm_chip {
        unsigned int            npwm;
 
        struct pwm_device       *pwms;
+
+       struct pwm_device *     (*of_xlate)(struct pwm_chip *pc,
+                                           const struct of_phandle_args *args);
+       unsigned int            of_pwm_n_cells;
 };
 
 int pwm_set_chip_data(struct pwm_device *pwm, void *data);