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
|
@ -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;
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue