|
@@ -137,9 +137,14 @@ of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args)
|
|
{
|
|
{
|
|
struct pwm_device *pwm;
|
|
struct pwm_device *pwm;
|
|
|
|
|
|
|
|
+ /* check, whether the driver supports a third cell for flags */
|
|
if (pc->of_pwm_n_cells < 3)
|
|
if (pc->of_pwm_n_cells < 3)
|
|
return ERR_PTR(-EINVAL);
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
|
|
|
|
+ /* flags in the third cell are optional */
|
|
|
|
+ if (args->args_count < 2)
|
|
|
|
+ return ERR_PTR(-EINVAL);
|
|
|
|
+
|
|
if (args->args[0] >= pc->npwm)
|
|
if (args->args[0] >= pc->npwm)
|
|
return ERR_PTR(-EINVAL);
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
|
|
@@ -148,11 +153,10 @@ of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args)
|
|
return pwm;
|
|
return pwm;
|
|
|
|
|
|
pwm->args.period = args->args[1];
|
|
pwm->args.period = args->args[1];
|
|
|
|
+ pwm->args.polarity = PWM_POLARITY_NORMAL;
|
|
|
|
|
|
- if (args->args[2] & PWM_POLARITY_INVERTED)
|
|
|
|
|
|
+ if (args->args_count > 2 && args->args[2] & PWM_POLARITY_INVERTED)
|
|
pwm->args.polarity = PWM_POLARITY_INVERSED;
|
|
pwm->args.polarity = PWM_POLARITY_INVERSED;
|
|
- else
|
|
|
|
- pwm->args.polarity = PWM_POLARITY_NORMAL;
|
|
|
|
|
|
|
|
return pwm;
|
|
return pwm;
|
|
}
|
|
}
|
|
@@ -163,9 +167,14 @@ of_pwm_simple_xlate(struct pwm_chip *pc, const struct of_phandle_args *args)
|
|
{
|
|
{
|
|
struct pwm_device *pwm;
|
|
struct pwm_device *pwm;
|
|
|
|
|
|
|
|
+ /* sanity check driver support */
|
|
if (pc->of_pwm_n_cells < 2)
|
|
if (pc->of_pwm_n_cells < 2)
|
|
return ERR_PTR(-EINVAL);
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
|
|
|
|
+ /* all cells are required */
|
|
|
|
+ if (args->args_count != pc->of_pwm_n_cells)
|
|
|
|
+ return ERR_PTR(-EINVAL);
|
|
|
|
+
|
|
if (args->args[0] >= pc->npwm)
|
|
if (args->args[0] >= pc->npwm)
|
|
return ERR_PTR(-EINVAL);
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
|
|
@@ -663,24 +672,17 @@ struct pwm_device *of_pwm_get(struct device_node *np, const char *con_id)
|
|
err = of_parse_phandle_with_args(np, "pwms", "#pwm-cells", index,
|
|
err = of_parse_phandle_with_args(np, "pwms", "#pwm-cells", index,
|
|
&args);
|
|
&args);
|
|
if (err) {
|
|
if (err) {
|
|
- pr_debug("%s(): can't parse \"pwms\" property\n", __func__);
|
|
|
|
|
|
+ pr_err("%s(): can't parse \"pwms\" property\n", __func__);
|
|
return ERR_PTR(err);
|
|
return ERR_PTR(err);
|
|
}
|
|
}
|
|
|
|
|
|
pc = of_node_to_pwmchip(args.np);
|
|
pc = of_node_to_pwmchip(args.np);
|
|
if (IS_ERR(pc)) {
|
|
if (IS_ERR(pc)) {
|
|
- pr_debug("%s(): PWM chip not found\n", __func__);
|
|
|
|
|
|
+ pr_err("%s(): PWM chip not found\n", __func__);
|
|
pwm = ERR_CAST(pc);
|
|
pwm = ERR_CAST(pc);
|
|
goto put;
|
|
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);
|
|
pwm = pc->of_xlate(pc, &args);
|
|
if (IS_ERR(pwm))
|
|
if (IS_ERR(pwm))
|
|
goto put;
|
|
goto put;
|
|
@@ -757,12 +759,13 @@ void pwm_remove_table(struct pwm_lookup *table, size_t num)
|
|
*/
|
|
*/
|
|
struct pwm_device *pwm_get(struct device *dev, const char *con_id)
|
|
struct pwm_device *pwm_get(struct device *dev, const char *con_id)
|
|
{
|
|
{
|
|
- struct pwm_device *pwm = ERR_PTR(-EPROBE_DEFER);
|
|
|
|
const char *dev_id = dev ? dev_name(dev) : NULL;
|
|
const char *dev_id = dev ? dev_name(dev) : NULL;
|
|
- struct pwm_chip *chip = NULL;
|
|
|
|
|
|
+ struct pwm_device *pwm;
|
|
|
|
+ struct pwm_chip *chip;
|
|
unsigned int best = 0;
|
|
unsigned int best = 0;
|
|
struct pwm_lookup *p, *chosen = NULL;
|
|
struct pwm_lookup *p, *chosen = NULL;
|
|
unsigned int match;
|
|
unsigned int match;
|
|
|
|
+ int err;
|
|
|
|
|
|
/* look up via DT first */
|
|
/* look up via DT first */
|
|
if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node)
|
|
if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node)
|
|
@@ -817,24 +820,35 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- if (!chosen) {
|
|
|
|
- pwm = ERR_PTR(-ENODEV);
|
|
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
|
|
+ mutex_unlock(&pwm_lookup_lock);
|
|
|
|
+
|
|
|
|
+ if (!chosen)
|
|
|
|
+ return ERR_PTR(-ENODEV);
|
|
|
|
|
|
chip = pwmchip_find_by_name(chosen->provider);
|
|
chip = pwmchip_find_by_name(chosen->provider);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * If the lookup entry specifies a module, load the module and retry
|
|
|
|
+ * the PWM chip lookup. This can be used to work around driver load
|
|
|
|
+ * ordering issues if driver's can't be made to properly support the
|
|
|
|
+ * deferred probe mechanism.
|
|
|
|
+ */
|
|
|
|
+ if (!chip && chosen->module) {
|
|
|
|
+ err = request_module(chosen->module);
|
|
|
|
+ if (err == 0)
|
|
|
|
+ chip = pwmchip_find_by_name(chosen->provider);
|
|
|
|
+ }
|
|
|
|
+
|
|
if (!chip)
|
|
if (!chip)
|
|
- goto out;
|
|
|
|
|
|
+ return ERR_PTR(-EPROBE_DEFER);
|
|
|
|
|
|
pwm = pwm_request_from_chip(chip, chosen->index, con_id ?: dev_id);
|
|
pwm = pwm_request_from_chip(chip, chosen->index, con_id ?: dev_id);
|
|
if (IS_ERR(pwm))
|
|
if (IS_ERR(pwm))
|
|
- goto out;
|
|
|
|
|
|
+ return pwm;
|
|
|
|
|
|
pwm->args.period = chosen->period;
|
|
pwm->args.period = chosen->period;
|
|
pwm->args.polarity = chosen->polarity;
|
|
pwm->args.polarity = chosen->polarity;
|
|
|
|
|
|
-out:
|
|
|
|
- mutex_unlock(&pwm_lookup_lock);
|
|
|
|
return pwm;
|
|
return pwm;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(pwm_get);
|
|
EXPORT_SYMBOL_GPL(pwm_get);
|
|
@@ -960,18 +974,6 @@ void devm_pwm_put(struct device *dev, struct pwm_device *pwm)
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(devm_pwm_put);
|
|
EXPORT_SYMBOL_GPL(devm_pwm_put);
|
|
|
|
|
|
-/**
|
|
|
|
- * pwm_can_sleep() - report whether PWM access will sleep
|
|
|
|
- * @pwm: PWM device
|
|
|
|
- *
|
|
|
|
- * Returns: True if accessing the PWM can sleep, false otherwise.
|
|
|
|
- */
|
|
|
|
-bool pwm_can_sleep(struct pwm_device *pwm)
|
|
|
|
-{
|
|
|
|
- return true;
|
|
|
|
-}
|
|
|
|
-EXPORT_SYMBOL_GPL(pwm_can_sleep);
|
|
|
|
-
|
|
|
|
#ifdef CONFIG_DEBUG_FS
|
|
#ifdef CONFIG_DEBUG_FS
|
|
static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s)
|
|
static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s)
|
|
{
|
|
{
|