pwm: Add device tree support
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>
This commit is contained in:
parent
e05e5070f0
commit
7299ab70e6
57
Documentation/devicetree/bindings/pwm/pwm.txt
Normal file
57
Documentation/devicetree/bindings/pwm/pwm.txt
Normal file
|
@ -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>;
|
||||||
|
};
|
|
@ -129,6 +129,45 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label)
|
||||||
return 0;
|
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_set_chip_data() - set private chip data for a PWM
|
||||||
* @pwm: PWM device
|
* @pwm: PWM device
|
||||||
|
@ -201,6 +240,9 @@ int pwmchip_add(struct pwm_chip *chip)
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_OF))
|
||||||
|
of_pwmchip_add(chip);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
mutex_unlock(&pwm_lock);
|
mutex_unlock(&pwm_lock);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -231,6 +273,10 @@ int pwmchip_remove(struct pwm_chip *chip)
|
||||||
}
|
}
|
||||||
|
|
||||||
list_del_init(&chip->list);
|
list_del_init(&chip->list);
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_OF))
|
||||||
|
of_pwmchip_remove(chip);
|
||||||
|
|
||||||
free_pwms(chip);
|
free_pwms(chip);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
@ -356,6 +402,99 @@ void pwm_disable(struct pwm_device *pwm)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(pwm_disable);
|
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
|
* pwm_add_table() - register PWM device consumers
|
||||||
* @table: array of consumers to register
|
* @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
|
* @dev: device for PWM consumer
|
||||||
* @con_id: consumer name
|
* @con_id: consumer name
|
||||||
*
|
*
|
||||||
* Look up a PWM chip and a relative index via a table supplied by board setup
|
* Lookup is first attempted using DT. If the device was not instantiated from
|
||||||
* code (see pwm_add_table()).
|
* 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
|
* Once a PWM chip has been found the specified PWM device will be requested
|
||||||
* and is ready to be used.
|
* 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 index;
|
||||||
unsigned int match;
|
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
|
* We look up the provider in the static table typically provided by
|
||||||
* board setup code. We first try to lookup the consumer device by
|
* board setup code. We first try to lookup the consumer device by
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef __LINUX_PWM_H
|
#ifndef __LINUX_PWM_H
|
||||||
#define __LINUX_PWM_H
|
#define __LINUX_PWM_H
|
||||||
|
|
||||||
|
#include <linux/of.h>
|
||||||
|
|
||||||
struct pwm_device;
|
struct pwm_device;
|
||||||
struct seq_file;
|
struct seq_file;
|
||||||
|
|
||||||
|
@ -105,6 +107,10 @@ struct pwm_chip {
|
||||||
unsigned int npwm;
|
unsigned int npwm;
|
||||||
|
|
||||||
struct pwm_device *pwms;
|
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);
|
int pwm_set_chip_data(struct pwm_device *pwm, void *data);
|
||||||
|
|
Loading…
Reference in a new issue