* [RFC PATCH 03/15] pwm: add pwm_get_polarity helper function
From: Boris Brezillon @ 2015-07-01 8:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1435738921-25027-1-git-send-email-boris.brezillon@free-electrons.com>
Some drivers are directly accessing the ->polarity field in pwm_device.
Add an helper to retrieve the current polarity so that we can easily move
this field elsewhere (required to support atomic update).
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
include/linux/pwm.h | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index d8f6913..6f286df 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -124,6 +124,11 @@ static inline unsigned int pwm_get_duty_cycle(const struct pwm_device *pwm)
*/
int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity);
+static inline enum pwm_polarity pwm_get_polarity(const struct pwm_device *pwm)
+{
+ return pwm ? pwm->polarity : PWM_POLARITY_NORMAL;
+}
+
/**
* struct pwm_ops - PWM controller operations
* @request: optional hook for requesting a PWM
--
1.9.1
^ permalink raw reply related
* [RFC PATCH 04/15] pwm: make use of pwm_get_xxx helpers where appropriate
From: Boris Brezillon @ 2015-07-01 8:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1435738921-25027-1-git-send-email-boris.brezillon@free-electrons.com>
Use the pwm_get_xxx helpers instead of directly accessing the fields in
pwm_device. This will allow us to smoothly move to the atomic update
approach.
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
drivers/pwm/pwm-atmel.c | 2 +-
drivers/pwm/pwm-bcm-kona.c | 3 ++-
drivers/pwm/pwm-imx.c | 3 ++-
drivers/pwm/pwm-rockchip.c | 2 +-
drivers/pwm/sysfs.c | 11 ++++++-----
5 files changed, 12 insertions(+), 9 deletions(-)
diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c
index b3b294d..0e4bd4e 100644
--- a/drivers/pwm/pwm-atmel.c
+++ b/drivers/pwm/pwm-atmel.c
@@ -114,7 +114,7 @@ static int atmel_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
u32 val;
int ret;
- if (pwm_is_enabled(pwm) && (period_ns != pwm->period)) {
+ if (pwm_is_enabled(pwm) && (period_ns != pwm_get_period(pwm))) {
dev_err(chip->dev, "cannot change PWM period while enabled\n");
return -EBUSY;
}
diff --git a/drivers/pwm/pwm-bcm-kona.c b/drivers/pwm/pwm-bcm-kona.c
index dfdcf88..920cd1b 100644
--- a/drivers/pwm/pwm-bcm-kona.c
+++ b/drivers/pwm/pwm-bcm-kona.c
@@ -194,7 +194,8 @@ static int kona_pwmc_enable(struct pwm_chip *chip, struct pwm_device *pwm)
return ret;
}
- ret = kona_pwmc_config(chip, pwm, pwm->duty_cycle, pwm->period);
+ ret = kona_pwmc_config(chip, pwm, pwm_get_duty_cycle(pwm),
+ pwm_get_period(pwm));
if (ret < 0) {
clk_disable_unprepare(kp->clk);
return ret;
diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c
index 008dc64..d600fd5 100644
--- a/drivers/pwm/pwm-imx.c
+++ b/drivers/pwm/pwm-imx.c
@@ -129,7 +129,8 @@ static int imx_pwm_config_v2(struct pwm_chip *chip,
sr = readl(imx->mmio_base + MX3_PWMSR);
fifoav = sr & MX3_PWMSR_FIFOAV_MASK;
if (fifoav = MX3_PWMSR_FIFOAV_4WORDS) {
- period_ms = DIV_ROUND_UP(pwm->period, NSEC_PER_MSEC);
+ period_ms = DIV_ROUND_UP(pwm_get_period(pwm),
+ NSEC_PER_MSEC);
msleep(period_ms);
sr = readl(imx->mmio_base + MX3_PWMSR);
diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c
index 9442df2..7d9cc90 100644
--- a/drivers/pwm/pwm-rockchip.c
+++ b/drivers/pwm/pwm-rockchip.c
@@ -83,7 +83,7 @@ static void rockchip_pwm_set_enable_v2(struct pwm_chip *chip,
PWM_CONTINUOUS;
u32 val;
- if (pwm->polarity = PWM_POLARITY_INVERSED)
+ if (pwm_get_polarity(pwm) = PWM_POLARITY_INVERSED)
enable_conf |= PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSITIVE;
else
enable_conf |= PWM_DUTY_POSITIVE | PWM_INACTIVE_NEGATIVE;
diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c
index eecf21d..ac0abec 100644
--- a/drivers/pwm/sysfs.c
+++ b/drivers/pwm/sysfs.c
@@ -46,7 +46,7 @@ static ssize_t pwm_period_show(struct device *child,
{
const struct pwm_device *pwm = child_to_pwm_device(child);
- return sprintf(buf, "%u\n", pwm->period);
+ return sprintf(buf, "%u\n", pwm_get_period(pwm));
}
static ssize_t pwm_period_store(struct device *child,
@@ -61,7 +61,7 @@ static ssize_t pwm_period_store(struct device *child,
if (ret)
return ret;
- ret = pwm_config(pwm, pwm->duty_cycle, val);
+ ret = pwm_config(pwm, pwm_get_duty_cycle(pwm), val);
return ret ? : size;
}
@@ -72,7 +72,7 @@ static ssize_t pwm_duty_cycle_show(struct device *child,
{
const struct pwm_device *pwm = child_to_pwm_device(child);
- return sprintf(buf, "%u\n", pwm->duty_cycle);
+ return sprintf(buf, "%u\n", pwm_get_duty_cycle(pwm));
}
static ssize_t pwm_duty_cycle_store(struct device *child,
@@ -87,7 +87,7 @@ static ssize_t pwm_duty_cycle_store(struct device *child,
if (ret)
return ret;
- ret = pwm_config(pwm, val, pwm->period);
+ ret = pwm_config(pwm, val, pwm_get_period(pwm));
return ret ? : size;
}
@@ -134,7 +134,8 @@ static ssize_t pwm_polarity_show(struct device *child,
{
const struct pwm_device *pwm = child_to_pwm_device(child);
- return sprintf(buf, "%s\n", pwm->polarity ? "inversed" : "normal");
+ return sprintf(buf, "%s\n",
+ pwm_get_polarity(pwm) ? "inversed" : "normal");
}
static ssize_t pwm_polarity_store(struct device *child,
--
1.9.1
^ permalink raw reply related
* [RFC PATCH 05/15] pwm: introduce default period and polarity concepts
From: Boris Brezillon @ 2015-07-01 8:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1435738921-25027-1-git-send-email-boris.brezillon@free-electrons.com>
When requested by a user, the PWM is assigned a default period and polarity
extracted from the DT, the platform data or statically set by the driver.
Those default values are currently stored in the period and polarity
fields of the pwm_device struct, but they will be stored somewhere else
once we have introduced the architecture allowing for hardware state
retrieval.
The pwm_set_default_polarity and pwm_set_default_period should only be
used by PWM drivers or the PWM core infrastructure to specify the
default period and polarity values.
PWM users might call the pwm_get_default_period to query the default
period value. There is currently no helper to query the default
polarity, but it might be added later on if there is a need for it.
This patch also modifies all the places where the default helpers should
be used in place of the standard ones.
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
drivers/leds/leds-pwm.c | 2 +-
drivers/pwm/core.c | 14 +++++++-------
drivers/pwm/pwm-pxa.c | 2 +-
drivers/pwm/pwm-sun4i.c | 3 ++-
drivers/regulator/pwm-regulator.c | 2 +-
drivers/video/backlight/lm3630a_bl.c | 4 ++--
drivers/video/backlight/pwm_bl.c | 2 +-
drivers/video/fbdev/ssd1307fb.c | 2 +-
include/linux/pwm.h | 15 +++++++++++++++
9 files changed, 31 insertions(+), 15 deletions(-)
diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c
index 1d07e3e..2c564d1 100644
--- a/drivers/leds/leds-pwm.c
+++ b/drivers/leds/leds-pwm.c
@@ -125,7 +125,7 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
if (led_data->can_sleep)
INIT_WORK(&led_data->work, led_pwm_work);
- led_data->period = pwm_get_period(led_data->pwm);
+ led_data->period = pwm_get_default_period(led_data->pwm);
if (!led_data->period && (led->pwm_period_ns > 0))
led_data->period = led->pwm_period_ns;
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index f7c11d2..7ffad2b 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -146,12 +146,12 @@ of_pwm_xlate_with_flags(struct pwm_chip *pc, const struct of_phandle_args *args)
if (IS_ERR(pwm))
return pwm;
- pwm_set_period(pwm, args->args[1]);
+ pwm_set_default_period(pwm, args->args[1]);
if (args->args[2] & PWM_POLARITY_INVERTED)
- pwm_set_polarity(pwm, PWM_POLARITY_INVERSED);
+ pwm_set_default_polarity(pwm, PWM_POLARITY_INVERSED);
else
- pwm_set_polarity(pwm, PWM_POLARITY_NORMAL);
+ pwm_set_default_polarity(pwm, PWM_POLARITY_NORMAL);
return pwm;
}
@@ -172,7 +172,7 @@ of_pwm_simple_xlate(struct pwm_chip *pc, const struct of_phandle_args *args)
if (IS_ERR(pwm))
return pwm;
- pwm_set_period(pwm, args->args[1]);
+ pwm_set_default_period(pwm, args->args[1]);
return pwm;
}
@@ -262,7 +262,7 @@ int pwmchip_add_with_polarity(struct pwm_chip *chip,
pwm->chip = chip;
pwm->pwm = chip->base + i;
pwm->hwpwm = i;
- pwm->polarity = polarity;
+ pwm_set_default_polarity(pwm, polarity);
radix_tree_insert(&pwm_tree, pwm->pwm, pwm);
}
@@ -704,8 +704,8 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id)
if (IS_ERR(pwm))
goto out;
- pwm_set_period(pwm, chosen->period);
- pwm_set_polarity(pwm, chosen->polarity);
+ pwm_set_default_period(pwm, chosen->period);
+ pwm_set_default_polarity(pwm, chosen->polarity);
out:
mutex_unlock(&pwm_lookup_lock);
diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c
index cb2f702..65b80aa 100644
--- a/drivers/pwm/pwm-pxa.c
+++ b/drivers/pwm/pwm-pxa.c
@@ -160,7 +160,7 @@ pxa_pwm_of_xlate(struct pwm_chip *pc, const struct of_phandle_args *args)
if (IS_ERR(pwm))
return pwm;
- pwm_set_period(pwm, args->args[0]);
+ pwm_set_default_period(pwm, args->args[0]);
return pwm;
}
diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c
index cd9dde5..a364fb7 100644
--- a/drivers/pwm/pwm-sun4i.c
+++ b/drivers/pwm/pwm-sun4i.c
@@ -333,7 +333,8 @@ static int sun4i_pwm_probe(struct platform_device *pdev)
val = sun4i_pwm_readl(pwm, PWM_CTRL_REG);
for (i = 0; i < pwm->chip.npwm; i++)
if (!(val & BIT_CH(PWM_ACT_STATE, i)))
- pwm->chip.pwms[i].polarity = PWM_POLARITY_INVERSED;
+ pwm_set_default_polarity(&pwm->chip.pwms[i],
+ PWM_POLARITY_INVERSED);
clk_disable_unprepare(pwm->clk);
return 0;
diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c
index ffa9612..12b4d9d 100644
--- a/drivers/regulator/pwm-regulator.c
+++ b/drivers/regulator/pwm-regulator.c
@@ -46,7 +46,7 @@ static int pwm_regulator_set_voltage_sel(struct regulator_dev *rdev,
int dutycycle;
int ret;
- pwm_reg_period = pwm_get_period(drvdata->pwm);
+ pwm_reg_period = pwm_get_default_period(drvdata->pwm);
dutycycle = (pwm_reg_period *
drvdata->duty_cycle_table[selector].dutycycle) / 100;
diff --git a/drivers/video/backlight/lm3630a_bl.c b/drivers/video/backlight/lm3630a_bl.c
index 35fe482..449ebc3 100644
--- a/drivers/video/backlight/lm3630a_bl.c
+++ b/drivers/video/backlight/lm3630a_bl.c
@@ -162,7 +162,7 @@ static int lm3630a_intr_config(struct lm3630a_chip *pchip)
static void lm3630a_pwm_ctrl(struct lm3630a_chip *pchip, int br, int br_max)
{
- unsigned int period = pwm_get_period(pchip->pwmd);
+ unsigned int period = pwm_get_default_period(pchip->pwmd);
unsigned int duty = br * period / br_max;
pwm_config(pchip->pwmd, duty, period);
@@ -425,7 +425,7 @@ static int lm3630a_probe(struct i2c_client *client,
return PTR_ERR(pchip->pwmd);
}
}
- pchip->pwmd->period = pdata->pwm_period;
+ pwm_set_default_period(pchip->pwmd, pdata->pwm_period);
/* interrupt enable : irq 0 is not allowed */
pchip->irq = client->irq;
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index eff379b..ae498c1 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -294,7 +294,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
* set the period from platform data if it has not already been set
* via the PWM lookup table.
*/
- pb->period = pwm_get_period(pb->pwm);
+ pb->period = pwm_get_default_period(pb->pwm);
if (!pb->period && (data->pwm_period_ns > 0)) {
pb->period = data->pwm_period_ns;
pwm_set_period(pb->pwm, data->pwm_period_ns);
diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c
index 3e153c0..6949626 100644
--- a/drivers/video/fbdev/ssd1307fb.c
+++ b/drivers/video/fbdev/ssd1307fb.c
@@ -294,7 +294,7 @@ static int ssd1307fb_init(struct ssd1307fb_par *par)
return PTR_ERR(par->pwm);
}
- par->pwm_period = pwm_get_period(par->pwm);
+ par->pwm_period = pwm_get_default_period(par->pwm);
/* Enable the PWM */
pwm_config(par->pwm, par->pwm_period / 2, par->pwm_period);
pwm_enable(par->pwm);
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index 6f286df..72a21d5 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -103,11 +103,21 @@ static inline void pwm_set_period(struct pwm_device *pwm, unsigned int period)
pwm->period = period;
}
+static inline void pwm_set_default_period(struct pwm_device *pwm, unsigned int period)
+{
+ pwm_set_period(pwm, period);
+}
+
static inline unsigned int pwm_get_period(const struct pwm_device *pwm)
{
return pwm ? pwm->period : 0;
}
+static inline unsigned int pwm_get_default_period(const struct pwm_device *pwm)
+{
+ return pwm_get_period(pwm);
+}
+
static inline void pwm_set_duty_cycle(struct pwm_device *pwm, unsigned int duty)
{
if (pwm)
@@ -124,6 +134,11 @@ static inline unsigned int pwm_get_duty_cycle(const struct pwm_device *pwm)
*/
int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity);
+static inline void pwm_set_default_polarity(struct pwm_device *pwm, enum pwm_polarity polarity)
+{
+ pwm_set_polarity(pwm, polarity);
+}
+
static inline enum pwm_polarity pwm_get_polarity(const struct pwm_device *pwm)
{
return pwm ? pwm->polarity : PWM_POLARITY_NORMAL;
--
1.9.1
^ permalink raw reply related
* [RFC PATCH 06/15] pwm: define a new pwm_state struct
From: Boris Brezillon @ 2015-07-01 8:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1435738921-25027-1-git-send-email-boris.brezillon@free-electrons.com>
The PWM state, represented by its period, duty_cycle and polarity,
is currently directly stored in the PWM device.
Declare a pwm_state structure embedding those field so that we can later
use this struct to atomically update all the PWM parameters at once.
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
drivers/pwm/core.c | 6 +++---
include/linux/pwm.h | 20 ++++++++++++--------
2 files changed, 15 insertions(+), 11 deletions(-)
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index 7ffad2b..a6bc8e6 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -431,8 +431,8 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
if (err)
return err;
- pwm->duty_cycle = duty_ns;
- pwm->period = period_ns;
+ pwm->state.duty_cycle = duty_ns;
+ pwm->state.period = period_ns;
return 0;
}
@@ -462,7 +462,7 @@ int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity)
if (err)
return err;
- pwm->polarity = polarity;
+ pwm->state.polarity = polarity;
return 0;
}
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index 72a21d5..bed7234 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -79,6 +79,12 @@ enum {
PWMF_EXPORTED = 1 << 2,
};
+struct pwm_state {
+ unsigned int period; /* in nanoseconds */
+ unsigned int duty_cycle; /* in nanoseconds */
+ enum pwm_polarity polarity;
+};
+
struct pwm_device {
const char *label;
unsigned long flags;
@@ -87,9 +93,7 @@ struct pwm_device {
struct pwm_chip *chip;
void *chip_data;
- unsigned int period; /* in nanoseconds */
- unsigned int duty_cycle; /* in nanoseconds */
- enum pwm_polarity polarity;
+ struct pwm_state state;
};
static inline bool pwm_is_enabled(const struct pwm_device *pwm)
@@ -100,7 +104,7 @@ static inline bool pwm_is_enabled(const struct pwm_device *pwm)
static inline void pwm_set_period(struct pwm_device *pwm, unsigned int period)
{
if (pwm)
- pwm->period = period;
+ pwm->state.period = period;
}
static inline void pwm_set_default_period(struct pwm_device *pwm, unsigned int period)
@@ -110,7 +114,7 @@ static inline void pwm_set_default_period(struct pwm_device *pwm, unsigned int p
static inline unsigned int pwm_get_period(const struct pwm_device *pwm)
{
- return pwm ? pwm->period : 0;
+ return pwm ? pwm->state.period : 0;
}
static inline unsigned int pwm_get_default_period(const struct pwm_device *pwm)
@@ -121,12 +125,12 @@ static inline unsigned int pwm_get_default_period(const struct pwm_device *pwm)
static inline void pwm_set_duty_cycle(struct pwm_device *pwm, unsigned int duty)
{
if (pwm)
- pwm->duty_cycle = duty;
+ pwm->state.duty_cycle = duty;
}
static inline unsigned int pwm_get_duty_cycle(const struct pwm_device *pwm)
{
- return pwm ? pwm->duty_cycle : 0;
+ return pwm ? pwm->state.duty_cycle : 0;
}
/*
@@ -141,7 +145,7 @@ static inline void pwm_set_default_polarity(struct pwm_device *pwm, enum pwm_pol
static inline enum pwm_polarity pwm_get_polarity(const struct pwm_device *pwm)
{
- return pwm ? pwm->polarity : PWM_POLARITY_NORMAL;
+ return pwm ? pwm->state.polarity : PWM_POLARITY_NORMAL;
}
/**
--
1.9.1
^ permalink raw reply related
* [RFC PATCH 07/15] pwm: move the enabled/disabled info to pwm_state struct
From: Boris Brezillon @ 2015-07-01 8:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1435738921-25027-1-git-send-email-boris.brezillon@free-electrons.com>
Prepare the transition to PWM atomic update by moving the enabled/disabled
state into the pwm_state struct. This way we can easily update the whole
PWM state by copying the new state in the ->state field.
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
drivers/pwm/core.c | 15 ++++++++++++---
include/linux/pwm.h | 6 +++---
2 files changed, 15 insertions(+), 6 deletions(-)
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index a6bc8e6..3e830ce 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -474,8 +474,15 @@ EXPORT_SYMBOL_GPL(pwm_set_polarity);
*/
int pwm_enable(struct pwm_device *pwm)
{
- if (pwm && !test_and_set_bit(PWMF_ENABLED, &pwm->flags))
- return pwm->chip->ops->enable(pwm->chip, pwm);
+ if (pwm && !pwm_is_enabled(pwm)) {
+ int err;
+
+ err = pwm->chip->ops->enable(pwm->chip, pwm);
+ if (!err)
+ pwm->state.enabled = true;
+
+ return err;
+ }
return pwm ? 0 : -EINVAL;
}
@@ -487,8 +494,10 @@ EXPORT_SYMBOL_GPL(pwm_enable);
*/
void pwm_disable(struct pwm_device *pwm)
{
- if (pwm && test_and_clear_bit(PWMF_ENABLED, &pwm->flags))
+ if (pwm && pwm_is_enabled(pwm)) {
pwm->chip->ops->disable(pwm->chip, pwm);
+ pwm->state.enabled = false;
+ }
}
EXPORT_SYMBOL_GPL(pwm_disable);
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index bed7234..fd3e0f0 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -75,14 +75,14 @@ enum pwm_polarity {
enum {
PWMF_REQUESTED = 1 << 0,
- PWMF_ENABLED = 1 << 1,
- PWMF_EXPORTED = 1 << 2,
+ PWMF_EXPORTED = 1 << 1,
};
struct pwm_state {
unsigned int period; /* in nanoseconds */
unsigned int duty_cycle; /* in nanoseconds */
enum pwm_polarity polarity;
+ bool enabled;
};
struct pwm_device {
@@ -98,7 +98,7 @@ struct pwm_device {
static inline bool pwm_is_enabled(const struct pwm_device *pwm)
{
- return test_bit(PWMF_ENABLED, &pwm->flags);
+ return pwm->state.enabled;
}
static inline void pwm_set_period(struct pwm_device *pwm, unsigned int period)
--
1.9.1
^ permalink raw reply related
* [RFC PATCH 08/15] backlight: pwm_bl: remove useless call to pwm_set_period
From: Boris Brezillon @ 2015-07-01 8:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1435738921-25027-1-git-send-email-boris.brezillon@free-electrons.com>
The PWM period will be set when calling pwm_config. Remove this useless
call to pwm_set_period, which might mess up with the initial PWM state
once we have added proper support for PWM init state retrieval.
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
drivers/video/backlight/pwm_bl.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index ae498c1..fe5597c 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -295,10 +295,8 @@ static int pwm_backlight_probe(struct platform_device *pdev)
* via the PWM lookup table.
*/
pb->period = pwm_get_default_period(pb->pwm);
- if (!pb->period && (data->pwm_period_ns > 0)) {
+ if (!pb->period && (data->pwm_period_ns > 0))
pb->period = data->pwm_period_ns;
- pwm_set_period(pb->pwm, data->pwm_period_ns);
- }
pb->lth_brightness = data->lth_brightness * (pb->period / pb->scale);
--
1.9.1
^ permalink raw reply related
* [RFC PATCH 09/15] pwm: declare a default PWM state
From: Boris Brezillon @ 2015-07-01 8:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1435738921-25027-1-git-send-email-boris.brezillon@free-electrons.com>
Prepare the addition of the PWM initial state retrieval by adding a default
state where all the parameters retrieved from DT, platform data or
statically forced by the hardware will be stored.
Once done we will be able to store the initial state in the ->state field
without risking to loose the default parameters.
Update the pwm_set/get_default_xxx helpers accordingly.
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
include/linux/pwm.h | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index fd3e0f0..0f36a06 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -94,6 +94,7 @@ struct pwm_device {
void *chip_data;
struct pwm_state state;
+ struct pwm_state default_state;
};
static inline bool pwm_is_enabled(const struct pwm_device *pwm)
@@ -109,7 +110,8 @@ static inline void pwm_set_period(struct pwm_device *pwm, unsigned int period)
static inline void pwm_set_default_period(struct pwm_device *pwm, unsigned int period)
{
- pwm_set_period(pwm, period);
+ if (pwm)
+ pwm->default_state.period = period;
}
static inline unsigned int pwm_get_period(const struct pwm_device *pwm)
@@ -119,7 +121,7 @@ static inline unsigned int pwm_get_period(const struct pwm_device *pwm)
static inline unsigned int pwm_get_default_period(const struct pwm_device *pwm)
{
- return pwm_get_period(pwm);
+ return pwm ? pwm->default_state.period : 0;
}
static inline void pwm_set_duty_cycle(struct pwm_device *pwm, unsigned int duty)
@@ -140,7 +142,8 @@ int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity);
static inline void pwm_set_default_polarity(struct pwm_device *pwm, enum pwm_polarity polarity)
{
- pwm_set_polarity(pwm, polarity);
+ if (pwm)
+ pwm->default_state.polarity = polarity;
}
static inline enum pwm_polarity pwm_get_polarity(const struct pwm_device *pwm)
--
1.9.1
^ permalink raw reply related
* [RFC PATCH 10/15] pwm: add the PWM initial state retrieval infra
From: Boris Brezillon @ 2015-07-01 8:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1435738921-25027-1-git-send-email-boris.brezillon@free-electrons.com>
Add a ->init_state() function to the pwm_ops struct to let PWM drivers
initialize the PWM state attached to a PWM device.
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
drivers/pwm/core.c | 3 +++
include/linux/pwm.h | 2 ++
2 files changed, 5 insertions(+)
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index 3e830ce..30631f5 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -264,6 +264,9 @@ int pwmchip_add_with_polarity(struct pwm_chip *chip,
pwm->hwpwm = i;
pwm_set_default_polarity(pwm, polarity);
+ if (chip->ops->init_state)
+ chip->ops->init_state(chip, pwm);
+
radix_tree_insert(&pwm_tree, pwm->pwm, pwm);
}
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index 0f36a06..b47244a 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -177,6 +177,8 @@ struct pwm_ops {
struct pwm_device *pwm);
void (*disable)(struct pwm_chip *chip,
struct pwm_device *pwm);
+ void (*init_state)(struct pwm_chip *chip,
+ struct pwm_device *pwm);
#ifdef CONFIG_DEBUG_FS
void (*dbg_show)(struct pwm_chip *chip,
struct seq_file *s);
--
1.9.1
^ permalink raw reply related
* [RFC PATCH 11/15] pwm: add the core infrastructure to allow atomic update
From: Boris Brezillon @ 2015-07-01 8:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1435738921-25027-1-git-send-email-boris.brezillon@free-electrons.com>
Add an ->apply() method to the pwm_ops struct to allow PWM drivers to
implement atomic update.
This method will be prefered over the ->enable(), ->disable() and
->config() methods if available.
Add the pwm_get_state(), pwm_get_default_state() and pwm_apply_state()
functions for PWM users to be able to use the atomic update feature.
Note that the pwm_apply_state() does not guarantee the atomicity of the
update operation, it all depends on the availability and implementation
of the ->apply() method.
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
drivers/pwm/core.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++------
include/linux/pwm.h | 26 +++++++++++++
2 files changed, 124 insertions(+), 12 deletions(-)
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index 30631f5..6dafd8e 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -238,8 +238,9 @@ int pwmchip_add_with_polarity(struct pwm_chip *chip,
unsigned int i;
int ret;
- if (!chip || !chip->dev || !chip->ops || !chip->ops->config ||
- !chip->ops->enable || !chip->ops->disable || !chip->npwm)
+ if (!chip || !chip->dev || !chip->ops || (!chip->ops->apply &&
+ (!chip->ops->config || !chip->ops->enable ||
+ !chip->ops->disable)) || !chip->npwm)
return -EINVAL;
mutex_lock(&pwm_lock);
@@ -430,7 +431,17 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
if (!pwm || duty_ns < 0 || period_ns <= 0 || duty_ns > period_ns)
return -EINVAL;
- err = pwm->chip->ops->config(pwm->chip, pwm, duty_ns, period_ns);
+ if (pwm->chip->ops->apply) {
+ struct pwm_state state = pwm->state;
+
+ state.period = period_ns;
+ state.duty_cycle = duty_ns;
+
+ err = pwm->chip->ops->apply(pwm->chip, pwm, &state);
+ } else {
+ err = pwm->chip->ops->config(pwm->chip, pwm, duty_ns, period_ns);
+ }
+
if (err)
return err;
@@ -455,6 +466,17 @@ int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity)
if (!pwm || !pwm->chip->ops)
return -EINVAL;
+ if (pwm->chip->ops->apply) {
+ struct pwm_state state = pwm->state;
+
+ state.polarity = polarity;
+ err = pwm->chip->ops->apply(pwm->chip, pwm, &state);
+ if (!err)
+ pwm->state.polarity = polarity;
+
+ return err;
+ }
+
if (!pwm->chip->ops->set_polarity)
return -ENOSYS;
@@ -477,17 +499,27 @@ EXPORT_SYMBOL_GPL(pwm_set_polarity);
*/
int pwm_enable(struct pwm_device *pwm)
{
- if (pwm && !pwm_is_enabled(pwm)) {
- int err;
+ int err;
- err = pwm->chip->ops->enable(pwm->chip, pwm);
- if (!err)
- pwm->state.enabled = true;
+ if (!pwm)
+ return -EINVAL;
- return err;
+ if (pwm_is_enabled(pwm))
+ return 0;
+
+ if (pwm->chip->ops->apply) {
+ struct pwm_state state = pwm->state;
+
+ state.enabled = true;
+ err = pwm->chip->ops->apply(pwm->chip, pwm, &state);
+ } else {
+ err = pwm->chip->ops->enable(pwm->chip, pwm);
}
- return pwm ? 0 : -EINVAL;
+ if (!err)
+ pwm->state.enabled = true;
+
+ return err;
}
EXPORT_SYMBOL_GPL(pwm_enable);
@@ -497,13 +529,67 @@ EXPORT_SYMBOL_GPL(pwm_enable);
*/
void pwm_disable(struct pwm_device *pwm)
{
- if (pwm && pwm_is_enabled(pwm)) {
+ if (!pwm || !pwm_is_enabled(pwm))
+ return;
+
+ if (pwm->chip->ops->apply) {
+ struct pwm_state state = pwm->state;
+
+ state.enabled = false;
+ pwm->chip->ops->apply(pwm->chip, pwm, &state);
+ } else {
pwm->chip->ops->disable(pwm->chip, pwm);
- pwm->state.enabled = false;
}
+
+ pwm->state.enabled = false;
}
EXPORT_SYMBOL_GPL(pwm_disable);
+int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state)
+{
+ int err = 0;
+
+ if (!pwm)
+ return -EINVAL;
+
+ if (!memcmp(state, &pwm->state, sizeof(*state)))
+ return 0;
+
+ if (pwm->chip->ops->apply) {
+ err = pwm->chip->ops->apply(pwm->chip, pwm, state);
+ if (!err)
+ pwm->state = *state;
+ } else {
+ /*
+ * FIXME: restore the initial state in case of error.
+ */
+ if (state->polarity != pwm->state.polarity) {
+ pwm_disable(pwm);
+ err = pwm_set_polarity(pwm, state->polarity);
+ if (err)
+ goto out;
+ }
+
+ if (state->period != pwm->state.period ||
+ state->duty_cycle != pwm->state.duty_cycle) {
+ err = pwm_config(pwm, state->period, state->duty_cycle);
+ if (err)
+ goto out;
+ }
+
+ if (state->enabled != pwm->state.enabled) {
+ if (state->enabled)
+ err = pwm_enable(pwm);
+ else
+ pwm_disable(pwm);
+ }
+ }
+
+out:
+ return err;
+}
+EXPORT_SYMBOL_GPL(pwm_apply_state);
+
static struct pwm_chip *of_node_to_pwmchip(struct device_node *np)
{
struct pwm_chip *chip;
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index b47244a..7e99679 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -151,6 +151,29 @@ static inline enum pwm_polarity pwm_get_polarity(const struct pwm_device *pwm)
return pwm ? pwm->state.polarity : PWM_POLARITY_NORMAL;
}
+/*
+ * pwm_apply_state - apply a new state to the PWM device
+ */
+int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state);
+
+/*
+ * pwm_get_state - retrieve the current PWM state
+ */
+static inline void pwm_get_state(struct pwm_device *pwm,
+ struct pwm_state *state)
+{
+ *state = pwm->state;
+}
+
+/*
+ * pwm_get_default_state - retrieve the default PWM state
+ */
+static inline void pwm_get_default_state(struct pwm_device *pwm,
+ struct pwm_state *state)
+{
+ *state = pwm->default_state;
+}
+
/**
* struct pwm_ops - PWM controller operations
* @request: optional hook for requesting a PWM
@@ -177,6 +200,9 @@ struct pwm_ops {
struct pwm_device *pwm);
void (*disable)(struct pwm_chip *chip,
struct pwm_device *pwm);
+ int (*apply)(struct pwm_chip *chip,
+ struct pwm_device *pwm,
+ const struct pwm_state *state);
void (*init_state)(struct pwm_chip *chip,
struct pwm_device *pwm);
#ifdef CONFIG_DEBUG_FS
--
1.9.1
^ permalink raw reply related
* [RFC PATCH 12/15] pwm: rockchip: add initial state retrieval
From: Boris Brezillon @ 2015-07-01 8:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1435738921-25027-1-git-send-email-boris.brezillon@free-electrons.com>
Implement the ->init_state() function to expose initial state.
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
drivers/pwm/pwm-rockchip.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 47 insertions(+)
diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c
index 7d9cc90..11e932d 100644
--- a/drivers/pwm/pwm-rockchip.c
+++ b/drivers/pwm/pwm-rockchip.c
@@ -51,6 +51,7 @@ struct rockchip_pwm_data {
void (*set_enable)(struct pwm_chip *chip,
struct pwm_device *pwm, bool enable);
+ void (*init)(struct pwm_chip *chip, struct pwm_device *pwm);
};
static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct pwm_chip *c)
@@ -75,6 +76,17 @@ static void rockchip_pwm_set_enable_v1(struct pwm_chip *chip,
writel_relaxed(val, pc->base + pc->data->regs.ctrl);
}
+static void rockchip_pwm_init_v1(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
+ u32 enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN;
+ u32 val;
+
+ val = readl(pc->base + pc->data->regs.ctrl);
+ if ((val & enable_conf) = enable_conf)
+ pwm->state.enabled = true;
+}
+
static void rockchip_pwm_set_enable_v2(struct pwm_chip *chip,
struct pwm_device *pwm, bool enable)
{
@@ -98,6 +110,36 @@ static void rockchip_pwm_set_enable_v2(struct pwm_chip *chip,
writel_relaxed(val, pc->base + pc->data->regs.ctrl);
}
+static void rockchip_pwm_init_state(struct pwm_chip *chip,
+ struct pwm_device *pwm)
+{
+ struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
+ unsigned long clk_rate;
+ u64 tmp;
+ int ret;
+
+ ret = clk_enable(pc->clk);
+ if (ret)
+ return;
+
+ clk_rate = clk_get_rate(pc->clk);
+
+ tmp = readl(pc->base + pc->data->regs.period);
+ tmp *= pc->data->prescaler * NSEC_PER_SEC;
+ tmp = do_div(tmp, clk_rate);
+ pwm->state.period = tmp;
+
+ tmp = readl(pc->base + pc->data->regs.duty);
+ tmp *= pc->data->prescaler * NSEC_PER_SEC;
+ tmp = do_div(tmp, clk_rate);
+ pwm->state.duty_cycle = tmp;
+
+ pc->data->init(chip, chip->pwms);
+
+ if (!pwm_is_enabled(pwm))
+ clk_disable(pc->clk);
+}
+
static int rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
int duty_ns, int period_ns)
{
@@ -171,6 +213,7 @@ static void rockchip_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
}
static const struct pwm_ops rockchip_pwm_ops_v1 = {
+ .init_state = rockchip_pwm_init_state,
.config = rockchip_pwm_config,
.enable = rockchip_pwm_enable,
.disable = rockchip_pwm_disable,
@@ -178,6 +221,7 @@ static const struct pwm_ops rockchip_pwm_ops_v1 = {
};
static const struct pwm_ops rockchip_pwm_ops_v2 = {
+ .init_state = rockchip_pwm_init_state,
.config = rockchip_pwm_config,
.set_polarity = rockchip_pwm_set_polarity,
.enable = rockchip_pwm_enable,
@@ -195,6 +239,7 @@ static const struct rockchip_pwm_data pwm_data_v1 = {
.prescaler = 2,
.ops = &rockchip_pwm_ops_v1,
.set_enable = rockchip_pwm_set_enable_v1,
+ .init = rockchip_pwm_init_v1,
};
static const struct rockchip_pwm_data pwm_data_v2 = {
@@ -207,6 +252,7 @@ static const struct rockchip_pwm_data pwm_data_v2 = {
.prescaler = 1,
.ops = &rockchip_pwm_ops_v2,
.set_enable = rockchip_pwm_set_enable_v2,
+ .init = rockchip_pwm_init_v2,
};
static const struct rockchip_pwm_data pwm_data_vop = {
@@ -219,6 +265,7 @@ static const struct rockchip_pwm_data pwm_data_vop = {
.prescaler = 1,
.ops = &rockchip_pwm_ops_v2,
.set_enable = rockchip_pwm_set_enable_v2,
+ .init = rockchip_pwm_init_v2,
};
static const struct of_device_id rockchip_pwm_dt_ids[] = {
--
1.9.1
^ permalink raw reply related
* [RFC PATCH 13/15] pwm: rockchip: add support for atomic update
From: Boris Brezillon @ 2015-07-01 8:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1435738921-25027-1-git-send-email-boris.brezillon@free-electrons.com>
Implement the ->apply() function to add support for atomic update.
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
drivers/pwm/pwm-rockchip.c | 75 ++++++++++++++++++++++++++++++----------------
1 file changed, 49 insertions(+), 26 deletions(-)
diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c
index 11e932d..cbe619bf 100644
--- a/drivers/pwm/pwm-rockchip.c
+++ b/drivers/pwm/pwm-rockchip.c
@@ -50,7 +50,8 @@ struct rockchip_pwm_data {
const struct pwm_ops *ops;
void (*set_enable)(struct pwm_chip *chip,
- struct pwm_device *pwm, bool enable);
+ struct pwm_device *pwm, bool enable,
+ enum pwm_polarity polarity);
void (*init)(struct pwm_chip *chip, struct pwm_device *pwm);
};
@@ -60,7 +61,8 @@ static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct pwm_chip *c)
}
static void rockchip_pwm_set_enable_v1(struct pwm_chip *chip,
- struct pwm_device *pwm, bool enable)
+ struct pwm_device *pwm, bool enable,
+ enum pwm_polarity polarity)
{
struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
u32 enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN;
@@ -88,14 +90,15 @@ static void rockchip_pwm_init_v1(struct pwm_chip *chip, struct pwm_device *pwm)
}
static void rockchip_pwm_set_enable_v2(struct pwm_chip *chip,
- struct pwm_device *pwm, bool enable)
+ struct pwm_device *pwm, bool enable,
+ enum pwm_polarity polarity)
{
struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
u32 enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE |
PWM_CONTINUOUS;
u32 val;
- if (pwm_get_polarity(pwm) = PWM_POLARITY_INVERSED)
+ if (polarity = PWM_POLARITY_INVERSED)
enable_conf |= PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSITIVE;
else
enable_conf |= PWM_DUTY_POSITIVE | PWM_INACTIVE_NEGATIVE;
@@ -110,6 +113,26 @@ static void rockchip_pwm_set_enable_v2(struct pwm_chip *chip,
writel_relaxed(val, pc->base + pc->data->regs.ctrl);
}
+static void rockchip_pwm_init_v2(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
+ u32 enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE |
+ PWM_CONTINUOUS;
+ u32 val;
+
+ val = readl(pc->base + pc->data->regs.ctrl);
+
+ if ((val & enable_conf) != enable_conf)
+ return;
+
+ pwm->state.enabled = true;
+
+ enable_conf = PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSITIVE;
+
+ if ((val & enable_conf) = enable_conf)
+ pwm->state.polarity = PWM_POLARITY_INVERSED;
+}
+
static void rockchip_pwm_init_state(struct pwm_chip *chip,
struct pwm_device *pwm)
{
@@ -146,7 +169,6 @@ static int rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
unsigned long period, duty;
u64 clk_rate, div;
- int ret;
clk_rate = clk_get_rate(pc->clk);
@@ -163,15 +185,8 @@ static int rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
do_div(div, pc->data->prescaler * NSEC_PER_SEC);
duty = div;
- ret = clk_enable(pc->clk);
- if (ret)
- return ret;
-
writel(period, pc->base + pc->data->regs.period);
writel(duty, pc->base + pc->data->regs.duty);
- writel(0, pc->base + pc->data->regs.cntr);
-
- clk_disable(pc->clk);
return 0;
}
@@ -189,43 +204,51 @@ static int rockchip_pwm_set_polarity(struct pwm_chip *chip,
return 0;
}
-static int rockchip_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+static int rockchip_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+ const struct pwm_state *state)
{
struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
+ bool enabled = pwm_is_enabled(pwm);
int ret;
ret = clk_enable(pc->clk);
if (ret)
return ret;
- pc->data->set_enable(chip, pwm, true);
+ if (state->polarity != pwm_get_polarity(pwm) && enabled) {
+ pc->data->set_enable(chip, pwm, false, state->polarity);
+ enabled = false;
+ }
- return 0;
-}
+ ret = rockchip_pwm_config(chip, pwm, state->duty_cycle, state->period);
+ if (ret) {
+ if (enabled != pwm_is_enabled(pwm))
+ pc->data->set_enable(chip, pwm, !enabled,
+ state->polarity);
-static void rockchip_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
-{
- struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
+ goto out;
+ }
- pc->data->set_enable(chip, pwm, false);
+ if (state->enabled != enabled)
+ pc->data->set_enable(chip, pwm, state->enabled,
+ state->polarity);
+out:
clk_disable(pc->clk);
+
+ return ret;
}
static const struct pwm_ops rockchip_pwm_ops_v1 = {
.init_state = rockchip_pwm_init_state,
- .config = rockchip_pwm_config,
- .enable = rockchip_pwm_enable,
- .disable = rockchip_pwm_disable,
+ .apply = rockchip_pwm_apply,
.owner = THIS_MODULE,
};
static const struct pwm_ops rockchip_pwm_ops_v2 = {
.init_state = rockchip_pwm_init_state,
- .config = rockchip_pwm_config,
+ .apply = rockchip_pwm_apply,
.set_polarity = rockchip_pwm_set_polarity,
- .enable = rockchip_pwm_enable,
- .disable = rockchip_pwm_disable,
.owner = THIS_MODULE,
};
--
1.9.1
^ permalink raw reply related
* [RFC PATCH 14/15] regulator: pwm: implement ->enable(), ->disable() and ->is_enabled methods
From: Boris Brezillon @ 2015-07-01 8:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1435738921-25027-1-git-send-email-boris.brezillon@free-electrons.com>
Implement the ->enable(), ->disable() and ->is_enabled methods and remove
the PWM call in ->set_voltage_sel().
This is particularly important for critical regulators tagged as always-on,
because not claiming the PWM (and its dependencies) might lead to
unpredictable behavior (like a system hang because the PWM clk is only
claimed when the PWM device is enabled).
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
drivers/regulator/pwm-regulator.c | 32 ++++++++++++++++++++++++++------
1 file changed, 26 insertions(+), 6 deletions(-)
diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c
index 12b4d9d..8159518 100644
--- a/drivers/regulator/pwm-regulator.c
+++ b/drivers/regulator/pwm-regulator.c
@@ -59,12 +59,6 @@ static int pwm_regulator_set_voltage_sel(struct regulator_dev *rdev,
drvdata->state = selector;
- ret = pwm_enable(drvdata->pwm);
- if (ret) {
- dev_err(&rdev->dev, "Failed to enable PWM\n");
- return ret;
- }
-
return 0;
}
@@ -79,11 +73,37 @@ static int pwm_regulator_list_voltage(struct regulator_dev *rdev,
return drvdata->duty_cycle_table[selector].uV;
}
+static int pwm_regulator_enable(struct regulator_dev *dev)
+{
+ struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
+
+ return pwm_enable(drvdata->pwm);
+}
+
+static int pwm_regulator_disable(struct regulator_dev *dev)
+{
+ struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
+
+ pwm_disable(drvdata->pwm);
+
+ return 0;
+}
+
+static int pwm_regulator_is_enabled(struct regulator_dev *dev)
+{
+ struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);
+
+ return pwm_is_enabled(drvdata->pwm);
+}
+
static struct regulator_ops pwm_regulator_voltage_ops = {
.set_voltage_sel = pwm_regulator_set_voltage_sel,
.get_voltage_sel = pwm_regulator_get_voltage_sel,
.list_voltage = pwm_regulator_list_voltage,
.map_voltage = regulator_map_voltage_iterate,
+ .enable = pwm_regulator_enable,
+ .disable = pwm_regulator_disable,
+ .is_enabled = pwm_regulator_is_enabled,
};
static struct regulator_desc pwm_regulator_desc = {
--
1.9.1
^ permalink raw reply related
* [RFC PATCH 15/15] regulator: pwm: properly initialize the ->state field
From: Boris Brezillon @ 2015-07-01 8:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1435738921-25027-1-git-send-email-boris.brezillon@free-electrons.com>
The ->state field is currently initialized to 0, thus referencing the
voltage selector at index 0, which might not reflect the current voltage
value.
If possible, retrieve the current voltage selector from the PWM state, else
return -EINVAL.
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
drivers/regulator/pwm-regulator.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c
index 8159518..4e29717 100644
--- a/drivers/regulator/pwm-regulator.c
+++ b/drivers/regulator/pwm-regulator.c
@@ -31,10 +31,35 @@ struct pwm_voltages {
unsigned int dutycycle;
};
+static void pwm_regulator_init_state(struct regulator_dev *rdev)
+{
+ struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
+ struct pwm_state pwm_state;
+ unsigned int dutycycle;
+ int i;
+
+ pwm_get_state(drvdata->pwm, &pwm_state);
+
+ if (!pwm_state.period)
+ return;
+
+ dutycycle = (pwm_state.duty_cycle * 100) / pwm_state.period;
+
+ for (i = 0; i < rdev->desc->n_voltages; i++) {
+ if (dutycycle = drvdata->duty_cycle_table[i].dutycycle) {
+ drvdata->state = i;
+ return;
+ }
+ }
+}
+
static int pwm_regulator_get_voltage_sel(struct regulator_dev *rdev)
{
struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);
+ if (drvdata->state < 0)
+ pwm_regulator_init_state(rdev);
+
return drvdata->state;
}
@@ -170,6 +195,7 @@ static int pwm_regulator_probe(struct platform_device *pdev)
config.of_node = np;
config.dev = &pdev->dev;
config.driver_data = drvdata;
+ drvdata->state = -EINVAL;
drvdata->pwm = devm_pwm_get(&pdev->dev, NULL);
if (IS_ERR(drvdata->pwm)) {
--
1.9.1
^ permalink raw reply related
* [PATCH v2 0/12] Discover and probe dependencies
From: Tomeu Vizoso @ 2015-07-01 9:40 UTC (permalink / raw)
To: linux-kernel
Cc: Mark Brown, linux-acpi, dri-devel, linux-fbdev, linux-gpio,
devicetree, linux-pwm, Rafael J. Wysocki, alsa-devel,
Tomeu Vizoso, Alan Stern, Linus Walleij, Kumar Gala,
Jean-Christophe Plagniol-Villard, Ian Campbell, Jingoo Han,
Tomi Valkeinen, Pawel Moll, Greg Kroah-Hartman, Alexandre Courbot,
Thierry Reding, Liam Girdwood, Terje Bergström
Hi,
this is version 2 of a series that probes devices in dependency order so
as to avoid deferred probes. While deferred probing is a powerful
solution that makes sure that you eventually get a working system at the
end of the boot, can make it very time consuming to find out why a
device didn't probe and can also introduce big delays in when a device
actually probes by sending it to the end of the deferred queue.
So far I have only tested on a Tegra124 Chromebook.
Thanks,
Tomeu
Changes in v2:
- Instead of delaying all probes until late_initcall, only delay matches
of platform devices that have a firmware node attached.
- Allow bindings implementations register a function instead of using
class callbacks, as not only subsystems implement firmware bindings.
- Move strends to string.h
- Document that consumers of backlight devices can use the 'backlight'
property to hold a phandle to the backlight device.
- Allocate the list of dependencies and pass it to the function that
fills it.
Tomeu Vizoso (12):
device: property: delay device-driver matches
device: property: find dependencies of a firmware node
string: Introduce strends()
gpio: register dependency parser for firmware nodes
gpu: host1x: register dependency parser for firmware nodes
backlight: Document consumers of backlight nodes
backlight: register dependency parser for firmware nodes
USB: EHCI: register dependency parser for firmware nodes
regulator: register dependency parser for firmware nodes
pwm: register dependency parser for firmware nodes
ASoC: tegra: register dependency parser for firmware nodes
driver-core: probe dependencies before probing
.../bindings/video/backlight/backlight.txt | 22 ++++
drivers/base/dd.c | 139 +++++++++++++++++++++
drivers/base/property.c | 120 ++++++++++++++++++
drivers/gpio/gpiolib.c | 54 ++++++++
drivers/gpu/host1x/dev.c | 26 ++++
drivers/pwm/core.c | 28 +++++
drivers/regulator/core.c | 27 ++++
drivers/usb/host/ehci-tegra.c | 16 +++
drivers/video/backlight/backlight.c | 16 +++
include/linux/fwnode.h | 5 +
include/linux/property.h | 12 ++
include/linux/string.h | 13 ++
sound/soc/tegra/tegra_max98090.c | 42 ++++++-
13 files changed, 519 insertions(+), 1 deletion(-)
create mode 100644 Documentation/devicetree/bindings/video/backlight/backlight.txt
--
2.4.1
^ permalink raw reply
* [PATCH v2 01/12] device: property: delay device-driver matches
From: Tomeu Vizoso @ 2015-07-01 9:40 UTC (permalink / raw)
To: linux-kernel
Cc: devicetree, linux-fbdev, Tomeu Vizoso, linux-gpio,
Greg Kroah-Hartman, Rafael J. Wysocki, alsa-devel, dri-devel,
linux-acpi, Mark Brown, linux-pwm
In-Reply-To: <1435743667-11987-1-git-send-email-tomeu.vizoso@collabora.com>
Delay matches of platform devices until late_initcall, when we are sure
that all built-in drivers have been registered already. This is needed
to prevent deferred probes because of some dependencies' drivers not
having registered yet.
This reduces the total amount of work that the kernel does during boot
because it won't try to match devices to drivers when built-in drivers
are still registering but also reduces some parallelism, so total boot
time might slightly increase or decrease depending on the platform and
kernel configuration.
This change will make make possible to prevent any deferred probes once
devices are probed in dependency order.
Signed-off-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
---
Changes in v2:
- Instead of delaying all probes until late_initcall, only delay matches
of platform devices that have a firmware node attached.
drivers/base/property.c | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/drivers/base/property.c b/drivers/base/property.c
index 8528eb9..8ead1ba 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -16,8 +16,11 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <linux/property.h>
+static bool fwnode_match_enable = false;
+
/**
* device_add_property_set - Add a collection of properties to a device object.
* @dev: Device to add properties to.
@@ -604,6 +607,15 @@ EXPORT_SYMBOL_GPL(fwnode_is_compatible);
bool fwnode_driver_match_device(struct device *dev,
const struct device_driver *drv)
{
+ /*
+ * Delay matches of platform devices until late_initcall, when we are
+ * sure that all built-in drivers have been registered already. This
+ * is needed to prevent deferred probes because of some drivers
+ * not having registered yet.
+ */
+ if(dev->bus = &platform_bus_type && !fwnode_match_enable)
+ return false;
+
if (is_of_node(dev->fwnode))
return of_driver_match_device(dev, drv);
else if (is_acpi_node(dev->fwnode))
@@ -612,3 +624,20 @@ bool fwnode_driver_match_device(struct device *dev,
return false;
}
EXPORT_SYMBOL_GPL(fwnode_driver_match_device);
+
+static int __device_attach(struct device *dev, void *data)
+{
+ device_initial_probe(dev);
+
+ return 0;
+}
+
+static int fwnode_match_initcall(void)
+{
+ fwnode_match_enable = true;
+
+ bus_for_each_dev(&platform_bus_type, NULL, NULL, __device_attach);
+
+ return 0;
+}
+late_initcall(fwnode_match_initcall);
--
2.4.1
^ permalink raw reply related
* [PATCH v2 02/12] device: property: find dependencies of a firmware node
From: Tomeu Vizoso @ 2015-07-01 9:40 UTC (permalink / raw)
To: linux-kernel
Cc: devicetree, linux-fbdev, Tomeu Vizoso, linux-gpio,
Greg Kroah-Hartman, Rafael J. Wysocki, alsa-devel, dri-devel,
linux-acpi, Mark Brown, linux-pwm
In-Reply-To: <1435743667-11987-1-git-send-email-tomeu.vizoso@collabora.com>
Adds API that allows callers to find out what other firmware nodes a
node depends on.
Implementors of bindings documentation can register callbacks that
return the dependencies of a node.
Dependency information can be used to change the order in which devices
are probed, or to print a warning when a device node is going to be
probed without all its dependencies fulfilled.
Signed-off-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
---
Changes in v2:
- Allow bindings implementations register a function instead of using
class callbacks, as not only subsystems implement firmware bindings.
drivers/base/property.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/fwnode.h | 5 +++
include/linux/property.h | 12 +++++++
3 files changed, 108 insertions(+)
diff --git a/drivers/base/property.c b/drivers/base/property.c
index 8ead1ba..9d38ede 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -19,7 +19,13 @@
#include <linux/platform_device.h>
#include <linux/property.h>
+struct dependency_parser {
+ struct list_head parser;
+ void (*func)(struct fwnode_handle *fwnode, struct list_head *deps);
+};
+
static bool fwnode_match_enable = false;
+static LIST_HEAD(dependency_parsers);
/**
* device_add_property_set - Add a collection of properties to a device object.
@@ -553,6 +559,27 @@ bool device_dma_is_coherent(struct device *dev)
EXPORT_SYMBOL_GPL(device_dma_is_coherent);
/**
+ * fwnode_add_dependency - add firmware node to the passed dependency list
+ * @fwnode: Firmware node to add to dependency list
+ * @list: Dependency list to add the fwnode to
+ */
+void fwnode_add_dependency(struct fwnode_handle *fwnode,
+ struct list_head *list)
+{
+ struct fwnode_dependency *dep;
+
+ dep = kzalloc(sizeof(*dep), GFP_KERNEL);
+ if (!dep)
+ return;
+
+ INIT_LIST_HEAD(&dep->dependency);
+ dep->fwnode = fwnode;
+
+ list_add_tail(&dep->dependency, list);
+}
+EXPORT_SYMBOL_GPL(fwnode_add_dependency);
+
+/**
* fwnode_get_parent - return the parent node of a device node
* @fwnode: Device node to find the parent node of
*/
@@ -600,6 +627,70 @@ bool fwnode_is_compatible(struct fwnode_handle *fwnode, const char *compatible)
EXPORT_SYMBOL_GPL(fwnode_is_compatible);
/**
+ * fwnode_add_dependency_parser - register dependency parser
+ * @func: Function that will be called to find out dependencies of a node
+ *
+ * Registers a callback that will be called when collecting the dependencies
+ * of a firmware node. The callback should inspect the properties of the node
+ * and call fwnode_add_dependency() for each dependency it recognizes, from
+ * the bindings documentation.
+ */
+void fwnode_add_dependency_parser(
+ void (*func)(struct fwnode_handle *fwnode, struct list_head *deps))
+{
+ struct dependency_parser *parser;
+
+ parser = kzalloc(sizeof(*parser), GFP_KERNEL);
+ if (!parser)
+ return;
+
+ INIT_LIST_HEAD(&parser->parser);
+ parser->func = func;
+
+ list_add_tail(&parser->parser, &dependency_parsers);
+}
+EXPORT_SYMBOL_GPL(fwnode_add_dependency_parser);
+
+/**
+ * fwnode_remove_dependency_parser - unregister dependency parser
+ * @func: Function that was to be called to find out dependencies of a node
+ */
+void fwnode_remove_dependency_parser(
+ void (*func)(struct fwnode_handle *fwnode, struct list_head *deps))
+{
+ struct dependency_parser *parser, *tmp;
+
+ list_for_each_entry_safe(parser, tmp, &dependency_parsers, parser) {
+ if (parser->func = func) {
+ list_del(&parser->parser);
+ kfree(parser);
+ return;
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(fwnode_remove_dependency_parser);
+
+/**
+ * fwnode_get_dependencies - find out what dependencies a firmware node has
+ * @fwnode: firmware node to find its dependencies
+ * @deps: list of struct fwnode_dependency in which dependencies will be placed
+ */
+void fwnode_get_dependencies(struct fwnode_handle *fwnode,
+ struct list_head *deps)
+{
+ struct dependency_parser *parser;
+ struct fwnode_handle *child;
+
+ list_for_each_entry(parser, &dependency_parsers, parser)
+ parser->func(fwnode, deps);
+
+ /* Some device nodes will have dependencies in non-device sub-nodes */
+ fwnode_for_each_child_node(fwnode, child)
+ if (!fwnode_property_present(child, "compatible"))
+ fwnode_get_dependencies(child, deps);
+}
+
+/**
* fwnode_driver_match_device - Tell if a driver matches a device.
* @drv: the device_driver structure to test
* @dev: the device structure to match against
diff --git a/include/linux/fwnode.h b/include/linux/fwnode.h
index 0408545..68ab558 100644
--- a/include/linux/fwnode.h
+++ b/include/linux/fwnode.h
@@ -24,4 +24,9 @@ struct fwnode_handle {
struct fwnode_handle *secondary;
};
+struct fwnode_dependency {
+ struct fwnode_handle *fwnode;
+ struct list_head dependency;
+};
+
#endif
diff --git a/include/linux/property.h b/include/linux/property.h
index 4e453c4..b8b86ea 100644
--- a/include/linux/property.h
+++ b/include/linux/property.h
@@ -86,6 +86,18 @@ bool fwnode_is_compatible(struct fwnode_handle *fwnode, const char *compatible);
bool fwnode_driver_match_device(struct device *dev,
const struct device_driver *drv);
+void fwnode_add_dependency(struct fwnode_handle *fwnode,
+ struct list_head *list);
+
+void fwnode_add_dependency_parser(
+ void (*func)(struct fwnode_handle *fwnode, struct list_head *deps));
+
+void fwnode_remove_dependency_parser(
+ void (*func)(struct fwnode_handle *fwnode, struct list_head *deps));
+
+void fwnode_get_dependencies(struct fwnode_handle *fwnode,
+ struct list_head *list);
+
unsigned int device_get_child_node_count(struct device *dev);
static inline bool device_property_read_bool(struct device *dev,
--
2.4.1
^ permalink raw reply related
* [PATCH v2 03/12] string: Introduce strends()
From: Tomeu Vizoso @ 2015-07-01 9:40 UTC (permalink / raw)
To: linux-kernel
Cc: devicetree, linux-fbdev, Tomeu Vizoso, linux-gpio,
Rafael J. Wysocki, alsa-devel, dri-devel, linux-acpi, Mark Brown,
linux-pwm
In-Reply-To: <1435743667-11987-1-git-send-email-tomeu.vizoso@collabora.com>
To avoid duplicating code in upcoming patches that will check for
postfixes in strings, add strends().
Signed-off-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
---
Changes in v2:
- Move strends to string.h
include/linux/string.h | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/include/linux/string.h b/include/linux/string.h
index d5dfe3e..4244363 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -146,6 +146,19 @@ static inline bool strstarts(const char *str, const char *prefix)
return strncmp(str, prefix, strlen(prefix)) = 0;
}
+/**
+ * strends - does @str end with @postfix?
+ * @str: string to examine
+ * @postfix: postfix to look for
+ */
+static inline bool strends(const char *str, const char *postfix)
+{
+ if (strlen(str) < strlen(postfix))
+ return false;
+
+ return strcmp(str + strlen(str) - strlen(postfix), postfix) = 0;
+}
+
size_t memweight(const void *ptr, size_t bytes);
void memzero_explicit(void *s, size_t count);
--
2.4.1
^ permalink raw reply related
* [PATCH v2 04/12] gpio: register dependency parser for firmware nodes
From: Tomeu Vizoso @ 2015-07-01 9:40 UTC (permalink / raw)
To: linux-kernel
Cc: devicetree, linux-fbdev, Tomeu Vizoso, linux-gpio,
Rafael J. Wysocki, alsa-devel, dri-devel, linux-acpi, Mark Brown,
linux-pwm, Alexandre Courbot
In-Reply-To: <1435743667-11987-1-git-send-email-tomeu.vizoso@collabora.com>
So the GPIO subsystem can be queried about the dependencies of nodes
that consume GPIOs, as specified in bindings/gpio/gpio.txt.
Signed-off-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
---
Changes in v2: None
drivers/gpio/gpiolib.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index bf4bd1d..6a3e83f 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -2388,4 +2388,58 @@ static int __init gpiolib_debugfs_init(void)
}
subsys_initcall(gpiolib_debugfs_init);
+static void gpio_get_dependencies(struct fwnode_handle *fwnode,
+ struct list_head *deps)
+{
+ struct device_node *np;
+ struct property *pp;
+ struct of_phandle_args pspec;
+ int count, i, ret;
+
+ np = to_of_node(fwnode);
+ if (!np)
+ return;
+
+ for_each_property_of_node(np, pp) {
+ if (strcmp(pp->name, "gpio") &&
+ strcmp(pp->name, "gpios") &&
+ !strends(pp->name, "-gpios") &&
+ !strends(pp->name, "-gpio"))
+ continue;
+
+ count = of_count_phandle_with_args(np, pp->name,
+ "#gpio-cells");
+ for (i = 0; i < count; i++) {
+ ret = of_parse_phandle_with_args(np, pp->name,
+ "#gpio-cells", i,
+ &pspec);
+ if (ret || !pspec.np)
+ continue;
+
+ fwnode_add_dependency(&pspec.np->fwnode, deps);
+
+ of_node_put(pspec.np);
+ }
+ }
+
+ for (i = 0;; i++) {
+ ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3,
+ i, &pspec);
+ if (ret)
+ break;
+
+ fwnode_add_dependency(&pspec.np->fwnode, deps);
+
+ of_node_put(pspec.np);
+ }
+}
+
+static int __init gpiolib_init(void)
+{
+ fwnode_add_dependency_parser(gpio_get_dependencies);
+
+ return 0;
+}
+device_initcall(gpiolib_init);
+
#endif /* DEBUG_FS */
--
2.4.1
^ permalink raw reply related
* [PATCH v2 05/12] gpu: host1x: register dependency parser for firmware nodes
From: Tomeu Vizoso @ 2015-07-01 9:41 UTC (permalink / raw)
To: linux-kernel
Cc: devicetree, linux-fbdev, Terje Bergström, Tomeu Vizoso,
linux-gpio, Rafael J. Wysocki, alsa-devel, dri-devel, linux-acpi,
Mark Brown, linux-pwm, linux-tegra
In-Reply-To: <1435743667-11987-1-git-send-email-tomeu.vizoso@collabora.com>
So others can find out dependencies of host1x clients, as specified in
bindings/gpu/nvidia,tegra20-host1x.txt.
Signed-off-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
---
Changes in v2: None
drivers/gpu/host1x/dev.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c
index 53d3d1d..5bb10b8 100644
--- a/drivers/gpu/host1x/dev.c
+++ b/drivers/gpu/host1x/dev.c
@@ -212,6 +212,29 @@ static struct platform_driver tegra_host1x_driver = {
.remove = host1x_remove,
};
+static void add_dependency(struct fwnode_handle *fwnode,
+ const char *property,
+ struct list_head *deps)
+{
+ struct device_node *np;
+
+ np = of_parse_phandle(to_of_node(fwnode), property, 0);
+ if (!np)
+ return;
+
+ fwnode_add_dependency(&np->fwnode, deps);
+}
+
+static void host1x_get_dependencies(struct fwnode_handle *fwnode,
+ struct list_head *deps)
+{
+ add_dependency(fwnode, "nvidia,dpaux", deps);
+ add_dependency(fwnode, "nvidia,panel", deps);
+ add_dependency(fwnode, "nvidia,ddc-i2c-bus", deps);
+ add_dependency(fwnode, "nvidia,hpd-gpio", deps);
+ add_dependency(fwnode, "ddc-i2c-bus", deps);
+}
+
static int __init tegra_host1x_init(void)
{
int err;
@@ -228,6 +251,8 @@ static int __init tegra_host1x_init(void)
if (err < 0)
goto unregister_host1x;
+ fwnode_add_dependency_parser(host1x_get_dependencies);
+
return 0;
unregister_host1x:
@@ -240,6 +265,7 @@ module_init(tegra_host1x_init);
static void __exit tegra_host1x_exit(void)
{
+ fwnode_remove_dependency_parser(host1x_get_dependencies);
platform_driver_unregister(&tegra_mipi_driver);
platform_driver_unregister(&tegra_host1x_driver);
bus_unregister(&host1x_bus_type);
--
2.4.1
^ permalink raw reply related
* [PATCH v2 06/12] backlight: Document consumers of backlight nodes
From: Tomeu Vizoso @ 2015-07-01 9:41 UTC (permalink / raw)
To: linux-kernel
Cc: Mark Rutland, devicetree, linux-fbdev, Pawel Moll, Rob Herring,
Tomeu Vizoso, linux-gpio, Ian Campbell, Rafael J. Wysocki,
alsa-devel, dri-devel, linux-acpi, Mark Brown, linux-pwm,
Kumar Gala
In-Reply-To: <1435743667-11987-1-git-send-email-tomeu.vizoso@collabora.com>
Add a small note that makes explicit that properties named 'backlight'
contain phandles to backlight nodes.
This is needed so that we can automatically extract dependencies on
backlight devices by assuming that a property with that name contains a
phandle to such a device.
Signed-off-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
---
Changes in v2:
- Document that consumers of backlight devices can use the 'backlight'
property to hold a phandle to the backlight device.
.../bindings/video/backlight/backlight.txt | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
create mode 100644 Documentation/devicetree/bindings/video/backlight/backlight.txt
diff --git a/Documentation/devicetree/bindings/video/backlight/backlight.txt b/Documentation/devicetree/bindings/video/backlight/backlight.txt
new file mode 100644
index 0000000..309949d
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/backlight/backlight.txt
@@ -0,0 +1,22 @@
+Specifying backlight information for devices
+======================
+
+Backlight user nodes
+--------------------
+
+Nodes such as display panels that refer to backlight devices can do so by simply having a property named 'backlight' that contains a phandle to a backlight node.
+
+Example:
+
+ backlight: backlight {
+ compatible = "gpio-backlight";
+ gpios = <&gpio3 4 GPIO_ACTIVE_HIGH>;
+ };
+
+ [...]
+
+ panel: panel {
+ compatible = "cptt,claa101wb01";
+
+ backlight = <&backlight>;
+ };
--
2.4.1
^ permalink raw reply related
* [PATCH v2 07/12] backlight: register dependency parser for firmware nodes
From: Tomeu Vizoso @ 2015-07-01 9:41 UTC (permalink / raw)
To: linux-kernel
Cc: devicetree, linux-fbdev, Tomeu Vizoso, linux-gpio, Tomi Valkeinen,
Rafael J. Wysocki, alsa-devel, dri-devel, linux-acpi, Mark Brown,
linux-pwm, Jingoo Han, Lee Jones,
Jean-Christophe Plagniol-Villard
In-Reply-To: <1435743667-11987-1-git-send-email-tomeu.vizoso@collabora.com>
So others can find out what depends on backlight devices, as specified
in bindings/video/backlight/backlight.txt.
Signed-off-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
---
Changes in v2: None
drivers/video/backlight/backlight.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index bddc8b1..ab8f5e7 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -566,8 +566,22 @@ struct backlight_device *of_find_backlight_by_node(struct device_node *node)
EXPORT_SYMBOL(of_find_backlight_by_node);
#endif
+static void backlight_get_dependencies(struct fwnode_handle *fwnode,
+ struct list_head *deps)
+{
+ struct device_node *np;
+
+ np = of_parse_phandle(to_of_node(fwnode), "backlight", 0);
+ if (!np)
+ return;
+
+ fwnode_add_dependency(&np->fwnode, deps);
+}
+
static void __exit backlight_class_exit(void)
{
+ fwnode_remove_dependency_parser(backlight_get_dependencies);
+
class_destroy(backlight_class);
}
@@ -586,6 +600,8 @@ static int __init backlight_class_init(void)
mutex_init(&backlight_dev_list_mutex);
BLOCKING_INIT_NOTIFIER_HEAD(&backlight_notifier);
+ fwnode_add_dependency_parser(backlight_get_dependencies);
+
return 0;
}
--
2.4.1
^ permalink raw reply related
* [PATCH v2 08/12] USB: EHCI: register dependency parser for firmware nodes
From: Tomeu Vizoso @ 2015-07-01 9:41 UTC (permalink / raw)
To: linux-kernel
Cc: devicetree, linux-fbdev, linux-tegra, Tomeu Vizoso, linux-gpio,
Greg Kroah-Hartman, linux-usb, Rafael J. Wysocki, alsa-devel,
dri-devel, linux-acpi, Mark Brown, linux-pwm, Stephen Warren,
Alan Stern, Alexandre Courbot
In-Reply-To: <1435743667-11987-1-git-send-email-tomeu.vizoso@collabora.com>
So others can find out whether a firmware node depends on a phy as
specified in bindings/usb/nvidia,tegra20-ehci.txt.
Signed-off-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
---
Changes in v2: None
drivers/usb/host/ehci-tegra.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 4031b37..3665eaa 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -589,6 +589,18 @@ static const struct ehci_driver_overrides tegra_overrides __initconst = {
.reset = tegra_ehci_reset,
};
+static void tegra_ehci_get_dependencies(struct fwnode_handle *fwnode,
+ struct list_head *deps)
+{
+ struct device_node *np;
+
+ np = of_parse_phandle(to_of_node(fwnode), "nvidia,phy", 0);
+ if (!np)
+ return;
+
+ fwnode_add_dependency(&np->fwnode, deps);
+}
+
static int __init ehci_tegra_init(void)
{
if (usb_disabled())
@@ -611,6 +623,8 @@ static int __init ehci_tegra_init(void)
tegra_ehci_hc_driver.unmap_urb_for_dma = tegra_ehci_unmap_urb_for_dma;
tegra_ehci_hc_driver.hub_control = tegra_ehci_hub_control;
+ fwnode_add_dependency_parser(tegra_ehci_get_dependencies);
+
return platform_driver_register(&tegra_ehci_driver);
}
module_init(ehci_tegra_init);
@@ -618,6 +632,8 @@ module_init(ehci_tegra_init);
static void __exit ehci_tegra_cleanup(void)
{
platform_driver_unregister(&tegra_ehci_driver);
+
+ fwnode_remove_dependency_parser(tegra_ehci_get_dependencies);
}
module_exit(ehci_tegra_cleanup);
--
2.4.1
^ permalink raw reply related
* [PATCH v2 09/12] regulator: register dependency parser for firmware nodes
From: Tomeu Vizoso @ 2015-07-01 9:41 UTC (permalink / raw)
To: linux-kernel
Cc: devicetree, linux-fbdev, Tomeu Vizoso, linux-gpio,
Rafael J. Wysocki, alsa-devel, dri-devel, Liam Girdwood,
linux-acpi, Mark Brown, linux-pwm
In-Reply-To: <1435743667-11987-1-git-send-email-tomeu.vizoso@collabora.com>
So others can find out what depends on regulators, as specified
in bindings/regulator/regulator.txt.
Signed-off-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
---
Changes in v2: None
drivers/regulator/core.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index c9f7201..535cad0 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -4112,6 +4112,31 @@ static const struct file_operations regulator_summary_fops = {
#endif
};
+static void regulator_get_dependencies(struct fwnode_handle *fwnode,
+ struct list_head *deps)
+{
+ struct device_node *np;
+ struct property *pp;
+ struct device_node *dep;
+
+ np = to_of_node(fwnode);
+ if (!np)
+ return;
+
+ for_each_property_of_node(np, pp) {
+ if (!strends(pp->name, "-supply"))
+ continue;
+
+ dep = of_parse_phandle(np, pp->name, 0);
+ if (!dep)
+ continue;
+
+ fwnode_add_dependency(&dep->fwnode, deps);
+
+ of_node_put(dep);
+ }
+}
+
static int __init regulator_init(void)
{
int ret;
@@ -4130,6 +4155,8 @@ static int __init regulator_init(void)
regulator_dummy_init();
+ fwnode_add_dependency_parser(regulator_get_dependencies);
+
return ret;
}
--
2.4.1
^ permalink raw reply related
* [PATCH v2 10/12] pwm: register dependency parser for firmware nodes
From: Tomeu Vizoso @ 2015-07-01 9:41 UTC (permalink / raw)
To: linux-kernel
Cc: devicetree, linux-fbdev, Tomeu Vizoso, linux-gpio,
Rafael J. Wysocki, alsa-devel, dri-devel, linux-acpi, Mark Brown,
linux-pwm
In-Reply-To: <1435743667-11987-1-git-send-email-tomeu.vizoso@collabora.com>
So others can find out what depends on pwm controllers, as specified
in bindings/pwm/pwm.txt.
Signed-off-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
---
Changes in v2: None
drivers/pwm/core.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index 3a7769f..81b4fc0 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -917,11 +917,39 @@ static const struct file_operations pwm_debugfs_ops = {
.release = seq_release,
};
+static void pwm_get_dependencies(struct fwnode_handle *fwnode,
+ struct list_head *deps)
+{
+ struct device_node *np;
+ struct of_phandle_args pspec;
+ int count, i, ret;
+
+ np = to_of_node(fwnode);
+ if (!np)
+ return;
+
+ count = of_count_phandle_with_args(np, "pwms",
+ "#pwm-cells");
+ for (i = 0; i < count; i++) {
+ ret = of_parse_phandle_with_args(np, "pwms",
+ "#pwm-cells", i,
+ &pspec);
+ if (ret || !pspec.np)
+ continue;
+
+ fwnode_add_dependency(&pspec.np->fwnode, deps);
+
+ of_node_put(pspec.np);
+ }
+}
+
static int __init pwm_debugfs_init(void)
{
debugfs_create_file("pwm", S_IFREG | S_IRUGO, NULL, NULL,
&pwm_debugfs_ops);
+ fwnode_add_dependency_parser(pwm_get_dependencies);
+
return 0;
}
--
2.4.1
^ permalink raw reply related
* [PATCH v2 11/12] ASoC: tegra: register dependency parser for firmware nodes
From: Tomeu Vizoso @ 2015-07-01 9:41 UTC (permalink / raw)
To: linux-kernel
Cc: devicetree, linux-fbdev, Tomeu Vizoso, linux-gpio, Liam Girdwood,
Stephen Warren, Rafael J. Wysocki, alsa-devel, dri-devel,
Jaroslav Kysela, linux-acpi, Mark Brown, linux-pwm, linux-tegra,
Alexandre Courbot
In-Reply-To: <1435743667-11987-1-git-send-email-tomeu.vizoso@collabora.com>
So others can find out what dependencies a nvidia,tegra-audio-max98090
device has, as specified in
bindings/sound/nvidia,tegra-audio-max98090.txt.
Signed-off-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
---
Changes in v2: None
sound/soc/tegra/tegra_max98090.c | 42 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 41 insertions(+), 1 deletion(-)
diff --git a/sound/soc/tegra/tegra_max98090.c b/sound/soc/tegra/tegra_max98090.c
index 902da36..0f7cbf3 100644
--- a/sound/soc/tegra/tegra_max98090.c
+++ b/sound/soc/tegra/tegra_max98090.c
@@ -316,7 +316,47 @@ static struct platform_driver tegra_max98090_driver = {
.probe = tegra_max98090_probe,
.remove = tegra_max98090_remove,
};
-module_platform_driver(tegra_max98090_driver);
+
+static void add_dependency(struct fwnode_handle *fwnode,
+ const char *property,
+ struct list_head *deps)
+{
+ struct device_node *np;
+
+ np = of_parse_phandle(to_of_node(fwnode), property, 0);
+ if (!np)
+ return;
+
+ fwnode_add_dependency(&np->fwnode, deps);
+}
+
+static void tegra_max98090_get_dependencies(struct fwnode_handle *fwnode,
+ struct list_head *deps)
+{
+ add_dependency(fwnode, "nvidia,i2s-controller", deps);
+ add_dependency(fwnode, "nvidia,audio-codec", deps);
+}
+
+static int __init tegra_max98090_init(void)
+{
+ int err;
+
+ err = platform_driver_register(&tegra_max98090_driver);
+ if (err < 0)
+ return err;
+
+ fwnode_add_dependency_parser(tegra_max98090_get_dependencies);
+
+ return 0;
+}
+module_init(tegra_max98090_init);
+
+static void __exit tegra_max98090_exit(void)
+{
+ fwnode_remove_dependency_parser(tegra_max98090_get_dependencies);
+ platform_driver_unregister(&tegra_max98090_driver);
+}
+module_exit(tegra_max98090_exit);
MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
MODULE_DESCRIPTION("Tegra max98090 machine ASoC driver");
--
2.4.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox