* [PATCH 0/7] PWM: rockchip: add driver support
@ 2024-04-15 5:35 Ahmad Fatoum
2024-04-15 5:35 ` [PATCH 1/7] PWM: core: check that struct pwm_chip::devname is set Ahmad Fatoum
` (7 more replies)
0 siblings, 8 replies; 9+ messages in thread
From: Ahmad Fatoum @ 2024-04-15 5:35 UTC (permalink / raw)
To: barebox
This series aligns the barebox PWM framework more with the current Linux
state in v6.8 and then ports over the Rockchip PWM driver.
This has been tested on the RK3566 controlling backlight and PWM LEDs.
Ahmad Fatoum (7):
PWM: core: check that struct pwm_chip::devname is set
PWM: core: add struct pwm_chip::dev
PWM: core: adopt Linux prototype for struct pwm_ops::apply
PWM: align struct pwm_state member names with Linux
PWM: core: add definition for PWM_POLARITY_INVERSED
PWM: rockchip: add driver support
ARM: dts: rk356x: add aliases for PWM controllers
arch/arm/dts/rk356x.dtsi | 16 ++
commands/pwm.c | 32 ++--
drivers/led/led-pwm.c | 8 +-
drivers/pwm/Kconfig | 7 +
drivers/pwm/Makefile | 1 +
drivers/pwm/core.c | 45 ++---
drivers/pwm/pwm-atmel.c | 21 ++-
drivers/pwm/pwm-imx.c | 17 +-
drivers/pwm/pwm-mxs.c | 19 +-
drivers/pwm/pwm-rockchip.c | 348 +++++++++++++++++++++++++++++++++++++
drivers/pwm/pwm-stm32.c | 15 +-
drivers/pwm/pxa_pwm.c | 19 +-
drivers/sound/pwm-beeper.c | 6 +-
include/pwm.h | 39 +++--
14 files changed, 499 insertions(+), 94 deletions(-)
create mode 100644 drivers/pwm/pwm-rockchip.c
--
2.39.2
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 1/7] PWM: core: check that struct pwm_chip::devname is set
2024-04-15 5:35 [PATCH 0/7] PWM: rockchip: add driver support Ahmad Fatoum
@ 2024-04-15 5:35 ` Ahmad Fatoum
2024-04-15 5:35 ` [PATCH 2/7] PWM: core: add struct pwm_chip::dev Ahmad Fatoum
` (6 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Ahmad Fatoum @ 2024-04-15 5:35 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
There's no equivalent to devname in the Linux API, but it's required for
barebox and not populating the pointer in struct pwm_chip will lead to a
crash inside pwmchip_add. Check that the pointer is non-NULL to catch
this case.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/pwm/core.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index a3f27708e6ef..976357e6062f 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -97,6 +97,9 @@ int pwmchip_add(struct pwm_chip *chip, struct device *dev)
struct param_d *p;
int ret;
+ if (!chip->devname)
+ return -EINVAL;
+
if (_find_pwm(chip->devname))
return -EBUSY;
--
2.39.2
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 2/7] PWM: core: add struct pwm_chip::dev
2024-04-15 5:35 [PATCH 0/7] PWM: rockchip: add driver support Ahmad Fatoum
2024-04-15 5:35 ` [PATCH 1/7] PWM: core: check that struct pwm_chip::devname is set Ahmad Fatoum
@ 2024-04-15 5:35 ` Ahmad Fatoum
2024-04-15 5:35 ` [PATCH 3/7] PWM: core: adopt Linux prototype for struct pwm_ops::apply Ahmad Fatoum
` (5 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Ahmad Fatoum @ 2024-04-15 5:35 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
For compatibility with Linux, let's add a dev member into struct pwm_chip
instead of passing it as argument to pwmchip_add
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/pwm/core.c | 6 +++---
drivers/pwm/pwm-atmel.c | 3 ++-
drivers/pwm/pwm-imx.c | 3 ++-
drivers/pwm/pwm-mxs.c | 3 ++-
drivers/pwm/pwm-stm32.c | 3 ++-
drivers/pwm/pxa_pwm.c | 3 ++-
include/pwm.h | 4 +++-
7 files changed, 16 insertions(+), 9 deletions(-)
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index 976357e6062f..ab7e55b00079 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -91,7 +91,7 @@ static int set_enable(struct param_d *p, void *priv)
* register a new pwm. pwm->devname must be initialized, usually
* from dev_name(dev) from the hardware driver.
*/
-int pwmchip_add(struct pwm_chip *chip, struct device *dev)
+int pwmchip_add(struct pwm_chip *chip)
{
struct pwm_device *pwm;
struct param_d *p;
@@ -105,11 +105,11 @@ int pwmchip_add(struct pwm_chip *chip, struct device *dev)
pwm = xzalloc(sizeof(*pwm));
pwm->chip = chip;
- pwm->hwdev = dev;
+ pwm->hwdev = chip->dev;
dev_set_name(&pwm->dev, chip->devname);
pwm->dev.id = DEVICE_ID_SINGLE;
- pwm->dev.parent = dev;
+ pwm->dev.parent = chip->dev;
ret = register_device(&pwm->dev);
if (ret)
diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c
index d5e70600ee59..52b5926097b5 100644
--- a/drivers/pwm/pwm-atmel.c
+++ b/drivers/pwm/pwm-atmel.c
@@ -453,7 +453,8 @@ static int atmel_pwm_probe(struct device *dev)
chip->ops = &atmel_pwm_ops;
chip->id = i;
- ret = pwmchip_add(chip, dev);
+ chip->dev = dev;
+ ret = pwmchip_add(chip);
if (ret) {
dev_err(dev, "failed to add pwm chip %d\n", ret);
return ret;
diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c
index c9db4aef3443..0b79b0831a5c 100644
--- a/drivers/pwm/pwm-imx.c
+++ b/drivers/pwm/pwm-imx.c
@@ -267,6 +267,7 @@ static int imx_pwm_probe(struct device *dev)
return PTR_ERR(iores);
imx->mmio_base = IOMEM(iores->start);
+ imx->chip.dev = dev;
imx->chip.ops = &imx_pwm_ops;
if (dev->of_node) {
imx->chip.devname = of_alias_get(dev->of_node);
@@ -280,7 +281,7 @@ static int imx_pwm_probe(struct device *dev)
imx->config = data->config;
imx->set_enable = data->set_enable;
- return pwmchip_add(&imx->chip, dev);;
+ return pwmchip_add(&imx->chip);
}
static struct driver imx_pwm_driver = {
diff --git a/drivers/pwm/pwm-mxs.c b/drivers/pwm/pwm-mxs.c
index 6b89ac192ad9..e94fcf538488 100644
--- a/drivers/pwm/pwm-mxs.c
+++ b/drivers/pwm/pwm-mxs.c
@@ -130,9 +130,10 @@ static int mxs_pwm_probe(struct device *dev)
mxspwm->chip.ops = &mxs_pwm_ops;
mxspwm->chip.devname = basprintf("pwm%d", i);
mxspwm->chip.id = i;
+ mxspwm->chip.dev = dev;
mxspwm->mxs = mxs;
- ret = pwmchip_add(&mxspwm->chip, dev);
+ ret = pwmchip_add(&mxspwm->chip);
if (ret < 0) {
dev_err(dev, "failed to add pwm chip %d\n", ret);
return ret;
diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c
index 5c2029ab6ad6..7c7a8e2ce68e 100644
--- a/drivers/pwm/pwm-stm32.c
+++ b/drivers/pwm/pwm-stm32.c
@@ -377,8 +377,9 @@ static int stm32_pwm_probe(struct device *dev)
chip->ops = &stm32pwm_ops;
chip->id = i;
+ chip->dev = dev;
- ret = pwmchip_add(chip, dev);
+ ret = pwmchip_add(chip);
if (ret < 0) {
dev_err(dev, "failed to add pwm chip %d\n", ret);
return ret;
diff --git a/drivers/pwm/pxa_pwm.c b/drivers/pwm/pxa_pwm.c
index 0ed69d999f02..69ff7dfb7736 100644
--- a/drivers/pwm/pxa_pwm.c
+++ b/drivers/pwm/pxa_pwm.c
@@ -141,9 +141,10 @@ static int pxa_pwm_probe(struct device *dev)
return PTR_ERR(iores);
chip->iobase = IOMEM(iores->start);
chip->id = dev->id;
+ chip->chip.dev = dev;
dev->priv = chip;
- return pwmchip_add(&chip->chip, dev);
+ return pwmchip_add(&chip->chip);
}
static struct driver pxa_pwm_driver = {
diff --git a/include/pwm.h b/include/pwm.h
index 4d403fe1746c..5157fee7d43d 100644
--- a/include/pwm.h
+++ b/include/pwm.h
@@ -128,12 +128,14 @@ struct pwm_ops {
/**
* struct pwm_chip - abstract a PWM
+ * @dev: device providing the PWMs
* @id: The id of this pwm
* @devname: unique identifier for this pwm
* @ops: The callbacks for this PWM
* @state: current state of the PWM
*/
struct pwm_chip {
+ struct device *dev;
int id;
const char *devname;
const struct pwm_ops *ops;
@@ -141,7 +143,7 @@ struct pwm_chip {
struct pwm_state state;
};
-int pwmchip_add(struct pwm_chip *chip, struct device *dev);
+int pwmchip_add(struct pwm_chip *chip);
int pwmchip_remove(struct pwm_chip *chip);
#endif /* __PWM_H */
--
2.39.2
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 3/7] PWM: core: adopt Linux prototype for struct pwm_ops::apply
2024-04-15 5:35 [PATCH 0/7] PWM: rockchip: add driver support Ahmad Fatoum
2024-04-15 5:35 ` [PATCH 1/7] PWM: core: check that struct pwm_chip::devname is set Ahmad Fatoum
2024-04-15 5:35 ` [PATCH 2/7] PWM: core: add struct pwm_chip::dev Ahmad Fatoum
@ 2024-04-15 5:35 ` Ahmad Fatoum
2024-04-15 5:35 ` [PATCH 4/7] PWM: align struct pwm_state member names with Linux Ahmad Fatoum
` (4 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Ahmad Fatoum @ 2024-04-15 5:35 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
In Linux, a pwm_chip can have more one pwm_device, one for each channel.
Therefore, pwm_apply takes a pwm_device as argument to identify, which
channel is the one being operated on.
In barebox, there's a 1:1 relationship between the two, but let's add
pwm_device as extra, so far unused, parameter to make porting kernel
code slightly easier.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/pwm/core.c | 2 +-
drivers/pwm/pwm-atmel.c | 4 +++-
drivers/pwm/pwm-imx.c | 4 +++-
drivers/pwm/pwm-mxs.c | 4 +++-
drivers/pwm/pwm-stm32.c | 4 +++-
drivers/pwm/pxa_pwm.c | 4 +++-
include/pwm.h | 3 ++-
7 files changed, 18 insertions(+), 7 deletions(-)
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index ab7e55b00079..706c4515e9a8 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -326,7 +326,7 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state)
if (state->duty_ns > state->period_ns)
goto err;
- ret = chip->ops->apply(chip, state);
+ ret = chip->ops->apply(chip, pwm, state);
err:
if (ret == 0)
chip->state = *state;
diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c
index 52b5926097b5..331a6e97124f 100644
--- a/drivers/pwm/pwm-atmel.c
+++ b/drivers/pwm/pwm-atmel.c
@@ -286,7 +286,9 @@ static void atmel_pwm_disable(struct pwm_chip *chip, bool disable_clk)
clk_disable(atmel_pwm->clk);
}
-static int atmel_pwm_apply(struct pwm_chip *chip, const struct pwm_state *state)
+static int atmel_pwm_apply(struct pwm_chip *chip,
+ struct pwm_device *pwm,
+ const struct pwm_state *state)
{
struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip);
struct pwm_state cstate;
diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c
index 0b79b0831a5c..f5e3cbcd7c80 100644
--- a/drivers/pwm/pwm-imx.c
+++ b/drivers/pwm/pwm-imx.c
@@ -191,7 +191,9 @@ static void imx_pwm_set_enable_v2(struct pwm_chip *chip, bool enable)
imx_pwm_clk_disable_v2(imx);
}
-static int imx_pwm_apply(struct pwm_chip *chip, const struct pwm_state *state)
+static int imx_pwm_apply(struct pwm_chip *chip,
+ struct pwm_device *pwm,
+ const struct pwm_state *state)
{
struct imx_chip *imx = to_imx_chip(chip);
bool enabled;
diff --git a/drivers/pwm/pwm-mxs.c b/drivers/pwm/pwm-mxs.c
index e94fcf538488..18279bf287b4 100644
--- a/drivers/pwm/pwm-mxs.c
+++ b/drivers/pwm/pwm-mxs.c
@@ -44,7 +44,9 @@ struct mxs_pwm {
#define to_mxs_pwm_chip(_chip) container_of(_chip, struct mxs_pwm_chip, chip)
-static int mxs_pwm_apply(struct pwm_chip *chip, const struct pwm_state *state)
+static int mxs_pwm_apply(struct pwm_chip *chip,
+ struct pwm_device *pwm,
+ const struct pwm_state *state)
{
struct mxs_pwm_chip *mxs = to_mxs_pwm_chip(chip);
int div = 0;
diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c
index 7c7a8e2ce68e..218a270c022d 100644
--- a/drivers/pwm/pwm-stm32.c
+++ b/drivers/pwm/pwm-stm32.c
@@ -198,7 +198,9 @@ static void stm32_pwm_disable(struct stm32_pwm *priv, unsigned ch)
clk_disable(priv->clk);
}
-static int stm32_pwm_apply(struct pwm_chip *chip, const struct pwm_state *state)
+static int stm32_pwm_apply(struct pwm_chip *chip,
+ struct pwm_device *pwm,
+ const struct pwm_state *state)
{
bool enabled;
struct stm32_pwm *priv = to_stm32_pwm_dev(chip);
diff --git a/drivers/pwm/pxa_pwm.c b/drivers/pwm/pxa_pwm.c
index 69ff7dfb7736..09f36c92dda2 100644
--- a/drivers/pwm/pxa_pwm.c
+++ b/drivers/pwm/pxa_pwm.c
@@ -77,7 +77,9 @@ static void pxa_pwm_disable(struct pxa_pwm_chip *pxa_pwm)
* duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
* PWM_CLK_RATE = 13 MHz
*/
-static int pxa_pwm_apply(struct pwm_chip *chip, const struct pwm_state *state)
+static int pxa_pwm_apply(struct pwm_chip *chip,
+ struct pwm_device *pwm,
+ const struct pwm_state *state)
{
unsigned long long c;
unsigned long period_cycles, prescale, pv, dc;
diff --git a/include/pwm.h b/include/pwm.h
index 5157fee7d43d..876a242289d7 100644
--- a/include/pwm.h
+++ b/include/pwm.h
@@ -123,7 +123,8 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state);
struct pwm_ops {
int (*request)(struct pwm_chip *chip);
void (*free)(struct pwm_chip *chip);
- int (*apply)(struct pwm_chip *chip, const struct pwm_state *state);
+ int (*apply)(struct pwm_chip *chip, struct pwm_device *pwm,
+ const struct pwm_state *state);
};
/**
--
2.39.2
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 4/7] PWM: align struct pwm_state member names with Linux
2024-04-15 5:35 [PATCH 0/7] PWM: rockchip: add driver support Ahmad Fatoum
` (2 preceding siblings ...)
2024-04-15 5:35 ` [PATCH 3/7] PWM: core: adopt Linux prototype for struct pwm_ops::apply Ahmad Fatoum
@ 2024-04-15 5:35 ` Ahmad Fatoum
2024-04-15 5:35 ` [PATCH 5/7] PWM: core: add definition for PWM_POLARITY_INVERSED Ahmad Fatoum
` (3 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Ahmad Fatoum @ 2024-04-15 5:35 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
This introduces no functional change, but removes some churn of porting
Linux drivers by aligning the naming of the frequently used struct
pwm_state.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
commands/pwm.c | 32 ++++++++++++++++----------------
drivers/led/led-pwm.c | 8 ++++----
drivers/pwm/core.c | 32 ++++++++++++++++----------------
drivers/pwm/pwm-atmel.c | 14 +++++++-------
drivers/pwm/pwm-imx.c | 10 +++++-----
drivers/pwm/pwm-mxs.c | 12 ++++++------
drivers/pwm/pwm-stm32.c | 8 ++++----
drivers/pwm/pxa_pwm.c | 12 ++++++------
drivers/sound/pwm-beeper.c | 6 +++---
include/pwm.h | 18 +++++++++---------
10 files changed, 76 insertions(+), 76 deletions(-)
diff --git a/commands/pwm.c b/commands/pwm.c
index 5d41fa8ff42b..b86f865d55aa 100644
--- a/commands/pwm.c
+++ b/commands/pwm.c
@@ -15,10 +15,10 @@
static bool is_equal_state(struct pwm_state *state1, struct pwm_state *state2)
{
- return (state1->period_ns == state2->period_ns)
- && (state1->duty_ns == state2->duty_ns)
+ return (state1->period == state2->period)
+ && (state1->duty_cycle == state2->duty_cycle)
&& (state1->polarity == state2->polarity)
- && (state1->p_enable == state2->p_enable);
+ && (state1->enabled == state2->enabled);
}
static int do_pwm_cmd(int argc, char *argv[])
@@ -109,12 +109,12 @@ static int do_pwm_cmd(int argc, char *argv[])
/* argc will be at least 3 with a valid devname */
if (verbose || (argc <= 3)) {
printf("pwm params for '%s':\n", devname);
- printf(" period : %u (ns)\n", state.period_ns);
- printf(" duty : %u (ns)\n", state.duty_ns);
- printf(" enabled : %d\n", state.p_enable);
+ printf(" period : %u (ns)\n", state.period);
+ printf(" duty : %u (ns)\n", state.duty_cycle);
+ printf(" enabled : %d\n", state.enabled);
printf(" polarity : %s\n", state.polarity == 0 ? "Normal" : "Inverted");
- if (state.period_ns)
- printf(" freq : %lu (Hz)\n", HZ_FROM_NANOSECONDS(state.period_ns));
+ if (state.period)
+ printf(" freq : %lu (Hz)\n", HZ_FROM_NANOSECONDS(state.period));
else
printf(" freq : -\n");
@@ -122,7 +122,7 @@ static int do_pwm_cmd(int argc, char *argv[])
return 0;
}
- if ((state.period_ns == 0) && (freq < 0) && (period < 0)) {
+ if ((state.period == 0) && (freq < 0) && (period < 0)) {
printf(" need to know some timing info: freq or period\n");
pwm_free(pwm);
return COMMAND_ERROR;
@@ -135,24 +135,24 @@ static int do_pwm_cmd(int argc, char *argv[])
/* period */
if (freq > 0) {
- state.p_enable = true;
- state.period_ns = HZ_TO_NANOSECONDS(freq);
+ state.enabled = true;
+ state.period = HZ_TO_NANOSECONDS(freq);
if (use_default_width && (width < 0)) {
width = 50;
}
} else if (period > 0) {
- state.p_enable = true;
- state.period_ns = period;
+ state.enabled = true;
+ state.period = period;
}
/* duty */
if (width >= 0) {
pwm_set_relative_duty_cycle(&state, width, 100);
} else if (duty >= 0) {
- state.duty_ns = duty;
+ state.duty_cycle = duty;
}
- if (state.duty_ns > state.period_ns) {
+ if (state.duty_cycle > state.period) {
printf(" duty_ns must not be greater than period_ns\n");
}
@@ -167,7 +167,7 @@ static int do_pwm_cmd(int argc, char *argv[])
* output (eg if duty => 0) and stopping in one command
*/
if (stop > 0) {
- state.p_enable = false;
+ state.enabled = false;
error = pwm_apply_state(pwm, &state);
if (error < 0)
printf(" error while stopping: %d\n", error);
diff --git a/drivers/led/led-pwm.c b/drivers/led/led-pwm.c
index 2ffb72e692cd..6f4abf97c8b7 100644
--- a/drivers/led/led-pwm.c
+++ b/drivers/led/led-pwm.c
@@ -27,14 +27,14 @@ static void led_pwm_set(struct led *led, unsigned int brightness)
pwm_get_state(pwmled->pwm, &state);
- duty = state.period_ns * brightness;
+ duty = state.period * brightness;
do_div(duty, max);
if (pwmled->active_low)
- duty = state.period_ns - duty;
+ duty = state.period - duty;
- state.p_enable = true;
- state.duty_ns = duty;
+ state.enabled = true;
+ state.duty_cycle = duty;
pwm_apply_state(pwmled->pwm, &state);
}
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index 706c4515e9a8..7e090cc144af 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -76,7 +76,7 @@ static int set_enable(struct param_d *p, void *priv)
{
struct pwm_device *pwm = priv;
- if (pwm->params.p_enable)
+ if (pwm->params.enabled)
pwm_enable(pwm);
else
pwm_disable(pwm);
@@ -118,17 +118,17 @@ int pwmchip_add(struct pwm_chip *chip)
list_add_tail(&pwm->node, &pwm_list);
p = dev_add_param_uint32(&pwm->dev, "duty_ns", apply_params,
- NULL, &pwm->params.duty_ns, "%u", pwm);
+ NULL, &pwm->params.duty_cycle, "%u", pwm);
if (IS_ERR(p))
return PTR_ERR(p);
p = dev_add_param_uint32(&pwm->dev, "period_ns", apply_params,
- NULL, &pwm->params.period_ns, "%u", pwm);
+ NULL, &pwm->params.period, "%u", pwm);
if (IS_ERR(p))
return PTR_ERR(p);
p = dev_add_param_bool(&pwm->dev, "enable", set_enable,
- NULL, &pwm->params.p_enable, pwm);
+ NULL, &pwm->params.enabled, pwm);
if (IS_ERR(p))
return PTR_ERR(p);
@@ -309,9 +309,9 @@ void pwm_init_state(const struct pwm_device *pwm,
/* Then fill it with the reference config */
pwm_get_args(pwm, &args);
- state->period_ns = args.period_ns;
+ state->period = args.period_ns;
state->polarity = args.polarity;
- state->duty_ns = 0;
+ state->duty_cycle = 0;
}
EXPORT_SYMBOL_GPL(pwm_init_state);
@@ -320,10 +320,10 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state)
struct pwm_chip *chip = pwm->chip;
int ret = -EINVAL;
- if (state->period_ns == 0)
+ if (state->period == 0)
goto err;
- if (state->duty_ns > state->period_ns)
+ if (state->duty_cycle > state->period)
goto err;
ret = chip->ops->apply(chip, pwm, state);
@@ -346,18 +346,18 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
return -EINVAL;
pwm_get_state(pwm, &state);
- if (state.duty_ns == duty_ns && state.period_ns == period_ns)
+ if (state.duty_cycle == duty_ns && state.period == period_ns)
return 0;
- state.duty_ns = duty_ns;
- state.period_ns = period_ns;
+ state.duty_cycle = duty_ns;
+ state.period = period_ns;
return pwm_apply_state(pwm, &state);
}
EXPORT_SYMBOL_GPL(pwm_config);
unsigned int pwm_get_period(struct pwm_device *pwm)
{
- return pwm->chip->state.period_ns;
+ return pwm->chip->state.period;
}
/*
@@ -368,10 +368,10 @@ int pwm_enable(struct pwm_device *pwm)
struct pwm_state state;
pwm_get_state(pwm, &state);
- if (state.p_enable)
+ if (state.enabled)
return 0;
- state.p_enable = true;
+ state.enabled = true;
return pwm_apply_state(pwm, &state);
}
EXPORT_SYMBOL_GPL(pwm_enable);
@@ -384,10 +384,10 @@ void pwm_disable(struct pwm_device *pwm)
struct pwm_state state;
pwm_get_state(pwm, &state);
- if (!state.p_enable)
+ if (!state.enabled)
return;
- state.p_enable = false;
+ state.enabled = false;
pwm_apply_state(pwm, &state);
}
EXPORT_SYMBOL_GPL(pwm_disable);
diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c
index 331a6e97124f..851676c0dd87 100644
--- a/drivers/pwm/pwm-atmel.c
+++ b/drivers/pwm/pwm-atmel.c
@@ -194,7 +194,7 @@ static int atmel_pwm_calculate_cprd_and_pres(struct pwm_chip *chip,
unsigned long *cprd, u32 *pres)
{
struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip);
- unsigned long long cycles = state->period_ns;
+ unsigned long long cycles = state->period;
int shift;
/* Calculate the period cycles and prescale value */
@@ -227,7 +227,7 @@ static void atmel_pwm_calculate_cdty(const struct pwm_state *state,
unsigned long clkrate, unsigned long cprd,
u32 pres, unsigned long *cdty)
{
- unsigned long long cycles = state->duty_ns;
+ unsigned long long cycles = state->duty_cycle;
cycles *= clkrate;
do_div(cycles, NSEC_PER_SEC);
@@ -298,12 +298,12 @@ static int atmel_pwm_apply(struct pwm_chip *chip,
cstate = chip->state;
- if (state->p_enable) {
+ if (state->enabled) {
unsigned long clkrate = clk_get_rate(atmel_pwm->clk);
- if (cstate.p_enable &&
+ if (cstate.enabled &&
cstate.polarity == state->polarity &&
- cstate.period_ns == state->period_ns) {
+ cstate.period == state->period) {
u32 cmr = atmel_pwm_ch_readl(atmel_pwm, chip->id, PWM_CMR);
cprd = atmel_pwm_ch_readl(atmel_pwm, chip->id,
@@ -325,7 +325,7 @@ static int atmel_pwm_apply(struct pwm_chip *chip,
atmel_pwm_calculate_cdty(state, clkrate, cprd, pres, &cdty);
- if (cstate.p_enable) {
+ if (cstate.enabled) {
atmel_pwm_disable(chip, false);
} else {
ret = clk_enable(atmel_pwm->clk);
@@ -345,7 +345,7 @@ static int atmel_pwm_apply(struct pwm_chip *chip,
atmel_pwm_ch_writel(atmel_pwm, chip->id, PWM_CMR, val);
atmel_pwm_set_cprd_cdty(chip, cprd, cdty);
atmel_pwm_writel(atmel_pwm, PWM_ENA, 1 << chip->id);
- } else if (cstate.p_enable) {
+ } else if (cstate.enabled) {
atmel_pwm_disable(chip, true);
}
diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c
index f5e3cbcd7c80..2a754005939c 100644
--- a/drivers/pwm/pwm-imx.c
+++ b/drivers/pwm/pwm-imx.c
@@ -162,7 +162,7 @@ static int imx_pwm_config_v2(struct pwm_chip *chip,
writel(cr, imx->mmio_base + MX3_PWMCR);
- if (!chip->state.p_enable)
+ if (!chip->state.enabled)
imx_pwm_clk_disable_v2(imx);
return 0;
@@ -199,18 +199,18 @@ static int imx_pwm_apply(struct pwm_chip *chip,
bool enabled;
int ret;
- enabled = chip->state.p_enable;
+ enabled = chip->state.enabled;
- if (enabled && !state->p_enable) {
+ if (enabled && !state->enabled) {
imx->set_enable(chip, false);
return 0;
}
- ret = imx->config(chip, state->duty_ns, state->period_ns);
+ ret = imx->config(chip, state->duty_cycle, state->period);
if (ret)
return ret;
- if (!enabled && state->p_enable)
+ if (!enabled && state->enabled)
imx->set_enable(chip, true);
return 0;
diff --git a/drivers/pwm/pwm-mxs.c b/drivers/pwm/pwm-mxs.c
index 18279bf287b4..3e3efade685d 100644
--- a/drivers/pwm/pwm-mxs.c
+++ b/drivers/pwm/pwm-mxs.c
@@ -55,9 +55,9 @@ static int mxs_pwm_apply(struct pwm_chip *chip,
unsigned long long c;
bool enabled;
- enabled = chip->state.p_enable;
+ enabled = chip->state.enabled;
- if (enabled && !state->p_enable) {
+ if (enabled && !state->enabled) {
writel(1 << mxs->chip.id, mxs->mxs->base + PWM_CTRL + CLR);
return 0;
}
@@ -65,7 +65,7 @@ static int mxs_pwm_apply(struct pwm_chip *chip,
rate = clk_get_rate(mxs->mxs->clk);
while (1) {
c = rate / cdiv[div];
- c = c * state->period_ns;
+ c = c * state->period;
do_div(c, 1000000000);
if (c < PERIOD_PERIOD_MAX)
break;
@@ -75,8 +75,8 @@ static int mxs_pwm_apply(struct pwm_chip *chip,
}
period_cycles = c;
- c *= state->duty_ns;
- do_div(c, state->period_ns);
+ c *= state->duty_cycle;
+ do_div(c, state->period);
duty_cycles = c;
writel(duty_cycles << 16,
@@ -85,7 +85,7 @@ static int mxs_pwm_apply(struct pwm_chip *chip,
PERIOD_INACTIVE_LOW | PERIOD_CDIV(div),
mxs->mxs->base + PWM_PERIOD0 + mxs->chip.id * 0x20);
- if (!enabled && state->p_enable)
+ if (!enabled && state->enabled)
writel(1 << mxs->chip.id, mxs->mxs->base + PWM_CTRL + SET);
return 0;
diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c
index 218a270c022d..16f80381c2f1 100644
--- a/drivers/pwm/pwm-stm32.c
+++ b/drivers/pwm/pwm-stm32.c
@@ -206,9 +206,9 @@ static int stm32_pwm_apply(struct pwm_chip *chip,
struct stm32_pwm *priv = to_stm32_pwm_dev(chip);
int ret;
- enabled = chip->state.p_enable;
+ enabled = chip->state.enabled;
- if (enabled && !state->p_enable) {
+ if (enabled && !state->enabled) {
stm32_pwm_disable(priv, chip->id);
return 0;
}
@@ -217,11 +217,11 @@ static int stm32_pwm_apply(struct pwm_chip *chip,
stm32_pwm_set_polarity(priv, chip->id, state->polarity);
ret = stm32_pwm_config(priv, chip->id,
- state->duty_ns, state->period_ns);
+ state->duty_cycle, state->period);
if (ret)
return ret;
- if (!enabled && state->p_enable)
+ if (!enabled && state->enabled)
ret = stm32_pwm_enable(priv, chip->id);
return ret;
diff --git a/drivers/pwm/pxa_pwm.c b/drivers/pwm/pxa_pwm.c
index 09f36c92dda2..42ccb37b9af2 100644
--- a/drivers/pwm/pxa_pwm.c
+++ b/drivers/pwm/pxa_pwm.c
@@ -86,15 +86,15 @@ static int pxa_pwm_apply(struct pwm_chip *chip,
struct pxa_pwm_chip *pxa_pwm = to_pxa_pwm_chip(chip);
bool enabled;
- enabled = chip->state.p_enable;
+ enabled = chip->state.enabled;
- if (enabled && !state->p_enable) {
+ if (enabled && !state->enabled) {
pxa_pwm_disable(pxa_pwm);
return 0;
}
c = pxa_get_pwmclk();
- c = c * state->period_ns;
+ c = c * state->period;
do_div(c, 1000000000);
period_cycles = c;
@@ -106,10 +106,10 @@ static int pxa_pwm_apply(struct pwm_chip *chip,
if (prescale > 63)
return -EINVAL;
- if (state->duty_ns == state->period_ns)
+ if (state->duty_cycle == state->period)
dc = PWMDCR_FD;
else
- dc = (pv + 1) * state->duty_ns / state->period_ns;
+ dc = (pv + 1) * state->duty_cycle / state->period;
/* NOTE: the clock to PWM has to be enabled first
* before writing to the registers
@@ -118,7 +118,7 @@ static int pxa_pwm_apply(struct pwm_chip *chip,
writel(dc, pxa_pwm->iobase + PWMDCR);
writel(pv, pxa_pwm->iobase + PWMPCR);
- if (!enabled && state->p_enable) {
+ if (!enabled && state->enabled) {
pxa_pwm_enable(pxa_pwm);
return 0;
}
diff --git a/drivers/sound/pwm-beeper.c b/drivers/sound/pwm-beeper.c
index 21e57d4b070b..94b27359c1c3 100644
--- a/drivers/sound/pwm-beeper.c
+++ b/drivers/sound/pwm-beeper.c
@@ -31,8 +31,8 @@ static int pwm_beeper_beep(struct sound_card *card, unsigned freq, unsigned dura
pwm_get_state(beeper->pwm, &state);
- state.p_enable = true;
- state.period_ns = HZ_TO_NANOSECONDS(freq);
+ state.enabled = true;
+ state.period = HZ_TO_NANOSECONDS(freq);
pwm_set_relative_duty_cycle(&state, 50, 100);
error = pwm_apply_state(beeper->pwm, &state);
@@ -66,7 +66,7 @@ static int pwm_beeper_probe(struct device *dev)
/* Sync up PWM state and ensure it is off. */
pwm_init_state(beeper->pwm, &state);
- state.p_enable = false;
+ state.enabled = false;
error = pwm_apply_state(beeper->pwm, &state);
if (error) {
dev_err(dev, "failed to apply initial PWM state: %d\n",
diff --git a/include/pwm.h b/include/pwm.h
index 876a242289d7..e8b0f2c96263 100644
--- a/include/pwm.h
+++ b/include/pwm.h
@@ -12,16 +12,16 @@ struct device;
/*
* struct pwm_state - state of a PWM channel
- * @period_ns: PWM period (in nanoseconds)
- * @duty_ns: PWM duty cycle (in nanoseconds)
+ * @period: PWM period (in nanoseconds)
+ * @duty_cycle: PWM duty cycle (in nanoseconds)
* @polarity: PWM polarity
- * @p_enable: PWM enabled status
+ * @enabled: PWM enabled status
*/
struct pwm_state {
- unsigned int period_ns;
- unsigned int duty_ns;
+ unsigned int period;
+ unsigned int duty_cycle;
unsigned int polarity;
- unsigned int p_enable;
+ unsigned int enabled;
};
void pwm_print(void);
@@ -91,9 +91,9 @@ pwm_set_relative_duty_cycle(struct pwm_state *state, unsigned int duty_cycle,
if (!scale || duty_cycle > scale)
return -EINVAL;
- state->duty_ns = DIV_ROUND_CLOSEST_ULL((u64)duty_cycle *
- state->period_ns,
- scale);
+ state->duty_cycle = DIV_ROUND_CLOSEST_ULL((u64)duty_cycle *
+ state->period,
+ scale);
return 0;
}
--
2.39.2
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 5/7] PWM: core: add definition for PWM_POLARITY_INVERSED
2024-04-15 5:35 [PATCH 0/7] PWM: rockchip: add driver support Ahmad Fatoum
` (3 preceding siblings ...)
2024-04-15 5:35 ` [PATCH 4/7] PWM: align struct pwm_state member names with Linux Ahmad Fatoum
@ 2024-04-15 5:35 ` Ahmad Fatoum
2024-04-15 5:35 ` [PATCH 6/7] PWM: rockchip: add driver support Ahmad Fatoum
` (2 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Ahmad Fatoum @ 2024-04-15 5:35 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
PWM_POLARITY_INVERTED is the macro used in the DT binding, while
PWM_POLARITY_INVERSED is the Linux driver macro that it is translated
to.
They are the same value, but Linux PWM chip drivers will use the latter,
so define it as well.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/pwm/core.c | 2 +-
include/pwm.h | 14 +++++++++++++-
2 files changed, 14 insertions(+), 2 deletions(-)
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index 7e090cc144af..69724e1a5c26 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -244,7 +244,7 @@ struct pwm_device *of_pwm_request(struct device_node *np, const char *con_id)
pwm->args.polarity = PWM_POLARITY_NORMAL;
if (args.args_count > 2 && args.args[2] & PWM_POLARITY_INVERTED)
- pwm->args.polarity = PWM_POLARITY_INVERTED;
+ pwm->args.polarity = PWM_POLARITY_INVERSED;
ret = __pwm_request(pwm);
if (ret)
diff --git a/include/pwm.h b/include/pwm.h
index e8b0f2c96263..b90ac1de4220 100644
--- a/include/pwm.h
+++ b/include/pwm.h
@@ -8,7 +8,19 @@
struct pwm_device;
struct device;
-#define PWM_POLARITY_NORMAL 0
+/**
+ * enum pwm_polarity - polarity of a PWM signal
+ * @PWM_POLARITY_NORMAL: a high signal for the duration of the duty-
+ * cycle, followed by a low signal for the remainder of the pulse
+ * period
+ * @PWM_POLARITY_INVERSED: a low signal for the duration of the duty-
+ * cycle, followed by a high signal for the remainder of the pulse
+ * period
+ */
+enum pwm_polarity {
+ PWM_POLARITY_NORMAL,
+ PWM_POLARITY_INVERSED,
+};
/*
* struct pwm_state - state of a PWM channel
--
2.39.2
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 6/7] PWM: rockchip: add driver support
2024-04-15 5:35 [PATCH 0/7] PWM: rockchip: add driver support Ahmad Fatoum
` (4 preceding siblings ...)
2024-04-15 5:35 ` [PATCH 5/7] PWM: core: add definition for PWM_POLARITY_INVERSED Ahmad Fatoum
@ 2024-04-15 5:35 ` Ahmad Fatoum
2024-04-15 5:36 ` [PATCH 7/7] ARM: dts: rk356x: add aliases for PWM controllers Ahmad Fatoum
2024-04-16 10:11 ` [PATCH 0/7] PWM: rockchip: add driver support Sascha Hauer
7 siblings, 0 replies; 9+ messages in thread
From: Ahmad Fatoum @ 2024-04-15 5:35 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
Import the Linux v6.8 state of the driver to enable barebox control of PWM
LEDs and other peripherals.
This has been tested on the RK3566.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
drivers/pwm/Kconfig | 7 +
drivers/pwm/Makefile | 1 +
drivers/pwm/pwm-rockchip.c | 348 +++++++++++++++++++++++++++++++++++++
3 files changed, 356 insertions(+)
create mode 100644 drivers/pwm/pwm-rockchip.c
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 0b12278e80e7..eb04f92c6f35 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -42,4 +42,11 @@ config PWM_STM32
help
This enables PWM support for STM32 MCUs and MPUs.
+config PWM_ROCKCHIP
+ tristate "Rockchip PWM support"
+ depends on ARCH_ROCKCHIP || COMPILE_TEST
+ help
+ Generic PWM framework driver for the PWM controller found on
+ Rockchip SoCs.
+
endif
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 9c3b10ae313b..4adc083e6c95 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_PWM_ATMEL) += pwm-atmel.o
obj-$(CONFIG_PWM_IMX) += pwm-imx.o
obj-$(CONFIG_PWM_MXS) += pwm-mxs.o
obj-$(CONFIG_PWM_STM32) += pwm-stm32.o
+obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o
diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c
new file mode 100644
index 000000000000..960867c52066
--- /dev/null
+++ b/drivers/pwm/pwm-rockchip.c
@@ -0,0 +1,348 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * PWM driver for Rockchip SoCs
+ *
+ * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
+ * Copyright (C) 2014 ROCKCHIP, Inc.
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <module.h>
+#include <of.h>
+#include <linux/device.h>
+#include <pwm.h>
+#include <linux/time.h>
+
+#define PWM_CTRL_TIMER_EN (1 << 0)
+#define PWM_CTRL_OUTPUT_EN (1 << 3)
+
+#define PWM_ENABLE (1 << 0)
+#define PWM_CONTINUOUS (1 << 1)
+#define PWM_DUTY_POSITIVE (1 << 3)
+#define PWM_DUTY_NEGATIVE (0 << 3)
+#define PWM_INACTIVE_NEGATIVE (0 << 4)
+#define PWM_INACTIVE_POSITIVE (1 << 4)
+#define PWM_POLARITY_MASK (PWM_DUTY_POSITIVE | PWM_INACTIVE_POSITIVE)
+#define PWM_OUTPUT_LEFT (0 << 5)
+#define PWM_LOCK_EN (1 << 6)
+#define PWM_LP_DISABLE (0 << 8)
+
+struct rockchip_pwm_chip {
+ struct pwm_chip chip;
+ struct clk *clk;
+ struct clk *pclk;
+ const struct rockchip_pwm_data *data;
+ void __iomem *base;
+};
+
+struct rockchip_pwm_regs {
+ unsigned long duty;
+ unsigned long period;
+ unsigned long cntr;
+ unsigned long ctrl;
+};
+
+struct rockchip_pwm_data {
+ struct rockchip_pwm_regs regs;
+ unsigned int prescaler;
+ bool supports_polarity;
+ bool supports_lock;
+ u32 enable_conf;
+};
+
+static inline struct rockchip_pwm_chip *to_rockchip_pwm_chip(struct pwm_chip *chip)
+{
+ return container_of(chip, struct rockchip_pwm_chip, chip);
+}
+
+static void rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+ const struct pwm_state *state)
+{
+ struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
+ unsigned long period, duty;
+ u64 clk_rate, div;
+ u32 ctrl;
+
+ clk_rate = clk_get_rate(pc->clk);
+
+ /*
+ * Since period and duty cycle registers have a width of 32
+ * bits, every possible input period can be obtained using the
+ * default prescaler value for all practical clock rate values.
+ */
+ div = clk_rate * state->period;
+ period = DIV_ROUND_CLOSEST_ULL(div,
+ pc->data->prescaler * NSEC_PER_SEC);
+
+ div = clk_rate * state->duty_cycle;
+ duty = DIV_ROUND_CLOSEST_ULL(div, pc->data->prescaler * NSEC_PER_SEC);
+
+ /*
+ * Lock the period and duty of previous configuration, then
+ * change the duty and period, that would not be effective.
+ */
+ ctrl = readl_relaxed(pc->base + pc->data->regs.ctrl);
+ if (pc->data->supports_lock) {
+ ctrl |= PWM_LOCK_EN;
+ writel_relaxed(ctrl, pc->base + pc->data->regs.ctrl);
+ }
+
+ writel(period, pc->base + pc->data->regs.period);
+ writel(duty, pc->base + pc->data->regs.duty);
+
+ if (pc->data->supports_polarity) {
+ ctrl &= ~PWM_POLARITY_MASK;
+ if (state->polarity == PWM_POLARITY_INVERSED)
+ ctrl |= PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSITIVE;
+ else
+ ctrl |= PWM_DUTY_POSITIVE | PWM_INACTIVE_NEGATIVE;
+ }
+
+ /*
+ * Unlock and set polarity at the same time,
+ * the configuration of duty, period and polarity
+ * would be effective together at next period.
+ */
+ if (pc->data->supports_lock)
+ ctrl &= ~PWM_LOCK_EN;
+
+ writel(ctrl, pc->base + pc->data->regs.ctrl);
+}
+
+static int rockchip_pwm_enable(struct pwm_chip *chip,
+ struct pwm_device *pwm,
+ bool enable)
+{
+ struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip);
+ u32 enable_conf = pc->data->enable_conf;
+ int ret;
+ u32 val;
+
+ if (enable) {
+ ret = clk_enable(pc->clk);
+ if (ret)
+ return ret;
+ }
+
+ val = readl_relaxed(pc->base + pc->data->regs.ctrl);
+
+ if (enable)
+ val |= enable_conf;
+ else
+ val &= ~enable_conf;
+
+ writel_relaxed(val, pc->base + pc->data->regs.ctrl);
+
+ if (!enable)
+ clk_disable(pc->clk);
+
+ return 0;
+}
+
+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);
+ struct pwm_state curstate;
+ bool enabled;
+ int ret = 0;
+
+ ret = clk_enable(pc->pclk);
+ if (ret)
+ return ret;
+
+ ret = clk_enable(pc->clk);
+ if (ret)
+ return ret;
+
+ pwm_get_state(pwm, &curstate);
+ enabled = curstate.enabled;
+
+ if (state->polarity != curstate.polarity && enabled &&
+ !pc->data->supports_lock) {
+ ret = rockchip_pwm_enable(chip, pwm, false);
+ if (ret)
+ goto out;
+ enabled = false;
+ }
+
+ rockchip_pwm_config(chip, pwm, state);
+ if (state->enabled != enabled) {
+ ret = rockchip_pwm_enable(chip, pwm, state->enabled);
+ if (ret)
+ goto out;
+ }
+
+out:
+ clk_disable(pc->clk);
+ clk_disable(pc->pclk);
+
+ return ret;
+}
+
+static const struct pwm_ops rockchip_pwm_ops = {
+ .apply = rockchip_pwm_apply,
+};
+
+static const struct rockchip_pwm_data pwm_data_v1 = {
+ .regs = {
+ .duty = 0x04,
+ .period = 0x08,
+ .cntr = 0x00,
+ .ctrl = 0x0c,
+ },
+ .prescaler = 2,
+ .supports_polarity = false,
+ .supports_lock = false,
+ .enable_conf = PWM_CTRL_OUTPUT_EN | PWM_CTRL_TIMER_EN,
+};
+
+static const struct rockchip_pwm_data pwm_data_v2 = {
+ .regs = {
+ .duty = 0x08,
+ .period = 0x04,
+ .cntr = 0x00,
+ .ctrl = 0x0c,
+ },
+ .prescaler = 1,
+ .supports_polarity = true,
+ .supports_lock = false,
+ .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE |
+ PWM_CONTINUOUS,
+};
+
+static const struct rockchip_pwm_data pwm_data_vop = {
+ .regs = {
+ .duty = 0x08,
+ .period = 0x04,
+ .cntr = 0x0c,
+ .ctrl = 0x00,
+ },
+ .prescaler = 1,
+ .supports_polarity = true,
+ .supports_lock = false,
+ .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE |
+ PWM_CONTINUOUS,
+};
+
+static const struct rockchip_pwm_data pwm_data_v3 = {
+ .regs = {
+ .duty = 0x08,
+ .period = 0x04,
+ .cntr = 0x00,
+ .ctrl = 0x0c,
+ },
+ .prescaler = 1,
+ .supports_polarity = true,
+ .supports_lock = true,
+ .enable_conf = PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE |
+ PWM_CONTINUOUS,
+};
+
+static const struct of_device_id rockchip_pwm_dt_ids[] = {
+ { .compatible = "rockchip,rk2928-pwm", .data = &pwm_data_v1},
+ { .compatible = "rockchip,rk3288-pwm", .data = &pwm_data_v2},
+ { .compatible = "rockchip,vop-pwm", .data = &pwm_data_vop},
+ { .compatible = "rockchip,rk3328-pwm", .data = &pwm_data_v3},
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rockchip_pwm_dt_ids);
+
+static int rockchip_pwm_probe(struct device *dev)
+{
+ struct rockchip_pwm_chip *pc;
+ u32 enable_conf, ctrl;
+ bool enabled;
+ int ret, count;
+
+ pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL);
+ if (!pc)
+ return -ENOMEM;
+
+ pc->base = dev_platform_ioremap_resource(dev, 0);
+ if (IS_ERR(pc->base))
+ return PTR_ERR(pc->base);
+
+ pc->clk = clk_get(dev, "pwm");
+ if (IS_ERR(pc->clk)) {
+ pc->clk = clk_get(dev, NULL);
+ if (IS_ERR(pc->clk))
+ return dev_err_probe(dev, PTR_ERR(pc->clk),
+ "Can't get PWM clk\n");
+ }
+
+ count = of_count_phandle_with_args(dev->of_node,
+ "clocks", "#clock-cells");
+ if (count == 2)
+ pc->pclk = clk_get(dev, "pclk");
+ else
+ pc->pclk = pc->clk;
+
+ if (IS_ERR(pc->pclk))
+ return dev_err_probe(dev, PTR_ERR(pc->pclk), "Can't get APB clk\n");
+
+ ret = clk_prepare_enable(pc->clk);
+ if (ret)
+ return dev_err_probe(dev, ret, "Can't prepare enable PWM clk\n");
+
+ ret = clk_prepare_enable(pc->pclk);
+ if (ret) {
+ dev_err_probe(dev, ret, "Can't prepare enable APB clk\n");
+ goto err_clk;
+ }
+
+ dev->priv = pc;
+
+ pc->data = device_get_match_data(dev);
+ pc->chip.dev = dev;
+ pc->chip.ops = &rockchip_pwm_ops;
+
+ enable_conf = pc->data->enable_conf;
+ ctrl = readl_relaxed(pc->base + pc->data->regs.ctrl);
+ enabled = (ctrl & enable_conf) == enable_conf;
+
+ pc->chip.devname = of_alias_get(dev->of_node);
+ if (!pc->chip.devname)
+ pc->chip.devname = basprintf("pwm_%p", pc->base);
+
+ ret = pwmchip_add(&pc->chip);
+ if (ret < 0) {
+ dev_err_probe(dev, ret, "pwmchip_add() failed\n");
+ goto err_pclk;
+ }
+
+ /* Keep the PWM clk enabled if the PWM appears to be up and running. */
+ if (!enabled)
+ clk_disable(pc->clk);
+
+ clk_disable(pc->pclk);
+
+ return 0;
+
+err_pclk:
+ clk_disable_unprepare(pc->pclk);
+err_clk:
+ clk_disable_unprepare(pc->clk);
+
+ return ret;
+}
+
+static void rockchip_pwm_remove(struct device *dev)
+{
+ struct rockchip_pwm_chip *pc = dev->priv;
+
+ pwmchip_remove(&pc->chip);
+}
+
+static struct driver rockchip_pwm_driver = {
+ .name = "rockchip-pwm",
+ .of_match_table = rockchip_pwm_dt_ids,
+ .probe = rockchip_pwm_probe,
+ .remove = rockchip_pwm_remove,
+};
+device_platform_driver(rockchip_pwm_driver);
+
+MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>");
+MODULE_DESCRIPTION("Rockchip SoC PWM driver");
+MODULE_LICENSE("GPL v2");
--
2.39.2
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 7/7] ARM: dts: rk356x: add aliases for PWM controllers
2024-04-15 5:35 [PATCH 0/7] PWM: rockchip: add driver support Ahmad Fatoum
` (5 preceding siblings ...)
2024-04-15 5:35 ` [PATCH 6/7] PWM: rockchip: add driver support Ahmad Fatoum
@ 2024-04-15 5:36 ` Ahmad Fatoum
2024-04-16 10:11 ` [PATCH 0/7] PWM: rockchip: add driver support Sascha Hauer
7 siblings, 0 replies; 9+ messages in thread
From: Ahmad Fatoum @ 2024-04-15 5:36 UTC (permalink / raw)
To: barebox; +Cc: Ahmad Fatoum
The Rockchip PWM driver will identify the different PWM chips by their
MMIO address. Make the names shorter and easier to handle by assigning
0-based aliases according to their numbering in the TRM.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
arch/arm/dts/rk356x.dtsi | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/arch/arm/dts/rk356x.dtsi b/arch/arm/dts/rk356x.dtsi
index 7fd5f72a5918..fbabf2a6a6b0 100644
--- a/arch/arm/dts/rk356x.dtsi
+++ b/arch/arm/dts/rk356x.dtsi
@@ -5,6 +5,22 @@
/ {
aliases {
pmugrf.reboot_mode = &reboot_mode_pmugrf;
+ pwm0 = &pwm0;
+ pwm1 = &pwm1;
+ pwm2 = &pwm2;
+ pwm3 = &pwm3;
+ pwm4 = &pwm4;
+ pwm5 = &pwm5;
+ pwm6 = &pwm6;
+ pwm7 = &pwm7;
+ pwm8 = &pwm8;
+ pwm9 = &pwm9;
+ pwm10 = &pwm10;
+ pwm11 = &pwm11;
+ pwm12 = &pwm12;
+ pwm13 = &pwm13;
+ pwm14 = &pwm14;
+ pwm15 = &pwm15;
};
chosen {
--
2.39.2
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 0/7] PWM: rockchip: add driver support
2024-04-15 5:35 [PATCH 0/7] PWM: rockchip: add driver support Ahmad Fatoum
` (6 preceding siblings ...)
2024-04-15 5:36 ` [PATCH 7/7] ARM: dts: rk356x: add aliases for PWM controllers Ahmad Fatoum
@ 2024-04-16 10:11 ` Sascha Hauer
7 siblings, 0 replies; 9+ messages in thread
From: Sascha Hauer @ 2024-04-16 10:11 UTC (permalink / raw)
To: barebox, Ahmad Fatoum
On Mon, 15 Apr 2024 07:35:53 +0200, Ahmad Fatoum wrote:
> This series aligns the barebox PWM framework more with the current Linux
> state in v6.8 and then ports over the Rockchip PWM driver.
>
> This has been tested on the RK3566 controlling backlight and PWM LEDs.
>
> Ahmad Fatoum (7):
> PWM: core: check that struct pwm_chip::devname is set
> PWM: core: add struct pwm_chip::dev
> PWM: core: adopt Linux prototype for struct pwm_ops::apply
> PWM: align struct pwm_state member names with Linux
> PWM: core: add definition for PWM_POLARITY_INVERSED
> PWM: rockchip: add driver support
> ARM: dts: rk356x: add aliases for PWM controllers
>
> [...]
Applied, thanks!
[1/7] PWM: core: check that struct pwm_chip::devname is set
https://git.pengutronix.de/cgit/barebox/commit/?id=9c2ce1113752 (link may not be stable)
[2/7] PWM: core: add struct pwm_chip::dev
https://git.pengutronix.de/cgit/barebox/commit/?id=66cc09c044ab (link may not be stable)
[3/7] PWM: core: adopt Linux prototype for struct pwm_ops::apply
https://git.pengutronix.de/cgit/barebox/commit/?id=29e00152bb73 (link may not be stable)
[4/7] PWM: align struct pwm_state member names with Linux
https://git.pengutronix.de/cgit/barebox/commit/?id=c5ae8eb5ef72 (link may not be stable)
[5/7] PWM: core: add definition for PWM_POLARITY_INVERSED
https://git.pengutronix.de/cgit/barebox/commit/?id=32a64b0e2cf7 (link may not be stable)
[6/7] PWM: rockchip: add driver support
https://git.pengutronix.de/cgit/barebox/commit/?id=b96d3bccc710 (link may not be stable)
[7/7] ARM: dts: rk356x: add aliases for PWM controllers
https://git.pengutronix.de/cgit/barebox/commit/?id=a77bd919a9e0 (link may not be stable)
Best regards,
--
Sascha Hauer <s.hauer@pengutronix.de>
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2024-04-16 10:12 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-04-15 5:35 [PATCH 0/7] PWM: rockchip: add driver support Ahmad Fatoum
2024-04-15 5:35 ` [PATCH 1/7] PWM: core: check that struct pwm_chip::devname is set Ahmad Fatoum
2024-04-15 5:35 ` [PATCH 2/7] PWM: core: add struct pwm_chip::dev Ahmad Fatoum
2024-04-15 5:35 ` [PATCH 3/7] PWM: core: adopt Linux prototype for struct pwm_ops::apply Ahmad Fatoum
2024-04-15 5:35 ` [PATCH 4/7] PWM: align struct pwm_state member names with Linux Ahmad Fatoum
2024-04-15 5:35 ` [PATCH 5/7] PWM: core: add definition for PWM_POLARITY_INVERSED Ahmad Fatoum
2024-04-15 5:35 ` [PATCH 6/7] PWM: rockchip: add driver support Ahmad Fatoum
2024-04-15 5:36 ` [PATCH 7/7] ARM: dts: rk356x: add aliases for PWM controllers Ahmad Fatoum
2024-04-16 10:11 ` [PATCH 0/7] PWM: rockchip: add driver support Sascha Hauer
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox