Skip to content

Commit c050daf

Browse files
committed
Merge tag 'pwm/for-6.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/ukleinek/linux
Pull pwm updates from Uwe Kleine-König: "The core highlights for this cycle are: - The pca9586 driver was converted to the waveform API - Waveform drivers automatically provide a gpio chip to make PWMs usable as GPIOs (The pca9586 driver did that in a driver specific implementation before) Otherwise it's the usual mix of fixes and device tree and driver changes to support new hardware variants" * tag 'pwm/for-6.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/ukleinek/linux: (30 commits) pwm: cros-ec: Avoid -Wflex-array-member-not-at-end warnings dt-bindings: pwm: samsung: add exynos8890 compatible dt-bindings: pwm: apple,s5l-fpwm: Add t6020-fpwm compatible dt-bindings: pwm: nxp,lpc1850-sct-pwm: Minor whitespace cleanup in example pwm: pca9586: Convert to waveform API pwm: pca9685: Drop GPIO support pwm: pca9685: Make use of register caching in regmap pwm: pca9685: Use bulk write to atomicially update registers pwm: pca9685: Don't disable hardware in .free() pwm: Add the S32G support in the Freescale FTM driver dt-bindings: pwm: fsl,vf610-ftm-pwm: Add compatible for s32g2 and s32g3 pwm: mediatek: Lock and cache clock rate pwm: mediatek: Fix various issues in the .apply() callback pwm: mediatek: Implement .get_state() callback pwm: mediatek: Initialize clks when the hardware is enabled at probe time pwm: mediatek: Rework parameters for clk helper function pwm: mediatek: Introduce and use a few more register defines pwm: mediatek: Simplify representation of channel offsets pwm: tiecap: Document behaviour of hardware disable pwm: Provide a gpio device for waveform drivers ...
2 parents 989253c + 8f2689f commit c050daf

16 files changed

Lines changed: 661 additions & 515 deletions

Documentation/devicetree/bindings/pwm/apple,s5l-fpwm.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ properties:
1717
items:
1818
- enum:
1919
- apple,t8103-fpwm
20-
- apple,t6000-fpwm
2120
- apple,t8112-fpwm
21+
- apple,t6000-fpwm
22+
- apple,t6020-fpwm
2223
- const: apple,s5l-fpwm
2324

2425
reg:

Documentation/devicetree/bindings/pwm/fsl,vf610-ftm-pwm.yaml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,14 @@ maintainers:
2626

2727
properties:
2828
compatible:
29-
enum:
30-
- fsl,vf610-ftm-pwm
31-
- fsl,imx8qm-ftm-pwm
29+
oneOf:
30+
- enum:
31+
- fsl,vf610-ftm-pwm
32+
- fsl,imx8qm-ftm-pwm
33+
- nxp,s32g2-ftm-pwm
34+
- items:
35+
- const: nxp,s32g3-ftm-pwm
36+
- const: nxp,s32g2-ftm-pwm
3237

3338
reg:
3439
maxItems: 1

Documentation/devicetree/bindings/pwm/nxp,lpc1850-sct-pwm.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ examples:
4848
pwm@40000000 {
4949
compatible = "nxp,lpc1850-sct-pwm";
5050
reg = <0x40000000 0x1000>;
51-
clocks =<&ccu1 CLK_CPU_SCT>;
51+
clocks = <&ccu1 CLK_CPU_SCT>;
5252
clock-names = "pwm";
5353
#pwm-cells = <3>;
5454
};

Documentation/devicetree/bindings/pwm/pwm-samsung.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ properties:
3131
- enum:
3232
- samsung,exynos5433-pwm
3333
- samsung,exynos7-pwm
34+
- samsung,exynos8890-pwm
3435
- samsung,exynosautov9-pwm
3536
- samsung,exynosautov920-pwm
3637
- tesla,fsd-pwm

Documentation/devicetree/bindings/timer/renesas,rz-mtu3.yaml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,10 @@ properties:
221221
maxItems: 1
222222

223223
"#pwm-cells":
224-
const: 2
224+
oneOf:
225+
- const: 2
226+
deprecated: true
227+
- const: 3
225228

226229
required:
227230
- compatible
@@ -299,5 +302,5 @@ examples:
299302
clocks = <&cpg CPG_MOD R9A07G044_MTU_X_MCK_MTU3>;
300303
power-domains = <&cpg>;
301304
resets = <&cpg R9A07G044_MTU_X_PRESET_MTU3>;
302-
#pwm-cells = <2>;
305+
#pwm-cells = <3>;
303306
};

drivers/pwm/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,15 @@ config PWM_DEBUG
3838
It is expected to introduce some runtime overhead and diagnostic
3939
output to the kernel log, so only enable while working on a driver.
4040

41+
config PWM_PROVIDE_GPIO
42+
bool "Provide a GPIO chip for each PWM chip"
43+
depends on GPIOLIB
44+
help
45+
Most PWMs can emit both a constant active high and a constant active
46+
low signal and so they can be used as GPIO. Say Y here to let each
47+
PWM chip provide a GPIO chip and so be easily plugged into consumers
48+
that know how to handle GPIOs but not PWMs.
49+
4150
config PWM_AB8500
4251
tristate "AB8500 PWM support"
4352
depends on AB8500_CORE && ARCH_U8500

drivers/pwm/core.c

Lines changed: 94 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ int pwm_round_waveform_might_sleep(struct pwm_device *pwm, struct pwm_waveform *
276276

277277
if (IS_ENABLED(CONFIG_PWM_DEBUG) && ret_fromhw > 0)
278278
dev_err(&chip->dev, "Unexpected return value from __pwm_round_waveform_fromhw: requested %llu/%llu [+%llu], return value %d\n",
279-
wf_req.duty_length_ns, wf_req.period_length_ns, wf_req.duty_offset_ns, ret_tohw);
279+
wf_req.duty_length_ns, wf_req.period_length_ns, wf_req.duty_offset_ns, ret_fromhw);
280280

281281
if (IS_ENABLED(CONFIG_PWM_DEBUG) &&
282282
(ret_tohw == 0) != pwm_check_rounding(&wf_req, wf))
@@ -496,6 +496,13 @@ static void pwm_apply_debug(struct pwm_device *pwm,
496496
if (!chip->ops->get_state)
497497
return;
498498

499+
/*
500+
* If a disabled PWM was requested the result is unspecified, so nothing
501+
* to check.
502+
*/
503+
if (!state->enabled)
504+
return;
505+
499506
/*
500507
* *state was just applied. Read out the hardware state and do some
501508
* checks.
@@ -507,26 +514,32 @@ static void pwm_apply_debug(struct pwm_device *pwm,
507514
/* If that failed there isn't much to debug */
508515
return;
509516

517+
/*
518+
* If the PWM was disabled that's maybe strange but there is nothing
519+
* that can be sensibly checked then. So return early.
520+
*/
521+
if (!s1.enabled)
522+
return;
523+
510524
/*
511525
* The lowlevel driver either ignored .polarity (which is a bug) or as
512526
* best effort inverted .polarity and fixed .duty_cycle respectively.
513527
* Undo this inversion and fixup for further tests.
514528
*/
515-
if (s1.enabled && s1.polarity != state->polarity) {
529+
if (s1.polarity != state->polarity) {
516530
s2.polarity = state->polarity;
517531
s2.duty_cycle = s1.period - s1.duty_cycle;
518532
s2.period = s1.period;
519-
s2.enabled = s1.enabled;
533+
s2.enabled = true;
520534
} else {
521535
s2 = s1;
522536
}
523537

524538
if (s2.polarity != state->polarity &&
525-
state->duty_cycle < state->period)
539+
s2.duty_cycle < s2.period)
526540
dev_warn(pwmchip_parent(chip), ".apply ignored .polarity\n");
527541

528-
if (state->enabled && s2.enabled &&
529-
last->polarity == state->polarity &&
542+
if (last->polarity == state->polarity &&
530543
last->period > s2.period &&
531544
last->period <= state->period)
532545
dev_warn(pwmchip_parent(chip),
@@ -537,13 +550,12 @@ static void pwm_apply_debug(struct pwm_device *pwm,
537550
* Rounding period up is fine only if duty_cycle is 0 then, because a
538551
* flat line doesn't have a characteristic period.
539552
*/
540-
if (state->enabled && s2.enabled && state->period < s2.period && s2.duty_cycle)
553+
if (state->period < s2.period && s2.duty_cycle)
541554
dev_warn(pwmchip_parent(chip),
542555
".apply is supposed to round down period (requested: %llu, applied: %llu)\n",
543556
state->period, s2.period);
544557

545-
if (state->enabled &&
546-
last->polarity == state->polarity &&
558+
if (last->polarity == state->polarity &&
547559
last->period == s2.period &&
548560
last->duty_cycle > s2.duty_cycle &&
549561
last->duty_cycle <= state->duty_cycle)
@@ -553,16 +565,12 @@ static void pwm_apply_debug(struct pwm_device *pwm,
553565
s2.duty_cycle, s2.period,
554566
last->duty_cycle, last->period);
555567

556-
if (state->enabled && s2.enabled && state->duty_cycle < s2.duty_cycle)
568+
if (state->duty_cycle < s2.duty_cycle)
557569
dev_warn(pwmchip_parent(chip),
558570
".apply is supposed to round down duty_cycle (requested: %llu/%llu, applied: %llu/%llu)\n",
559571
state->duty_cycle, state->period,
560572
s2.duty_cycle, s2.period);
561573

562-
if (!state->enabled && s2.enabled && s2.duty_cycle > 0)
563-
dev_warn(pwmchip_parent(chip),
564-
"requested disabled, but yielded enabled with duty > 0\n");
565-
566574
/* reapply the state that the driver reported being configured. */
567575
err = chip->ops->apply(chip, pwm, &s1);
568576
trace_pwm_apply(pwm, &s1, err);
@@ -2383,6 +2391,51 @@ static const struct file_operations pwm_cdev_fileops = {
23832391

23842392
static dev_t pwm_devt;
23852393

2394+
static int pwm_gpio_request(struct gpio_chip *gc, unsigned int offset)
2395+
{
2396+
struct pwm_chip *chip = gpiochip_get_data(gc);
2397+
struct pwm_device *pwm;
2398+
2399+
pwm = pwm_request_from_chip(chip, offset, "pwm-gpio");
2400+
if (IS_ERR(pwm))
2401+
return PTR_ERR(pwm);
2402+
2403+
return 0;
2404+
}
2405+
2406+
static void pwm_gpio_free(struct gpio_chip *gc, unsigned int offset)
2407+
{
2408+
struct pwm_chip *chip = gpiochip_get_data(gc);
2409+
2410+
pwm_put(&chip->pwms[offset]);
2411+
}
2412+
2413+
static int pwm_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
2414+
{
2415+
return GPIO_LINE_DIRECTION_OUT;
2416+
}
2417+
2418+
static int pwm_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
2419+
{
2420+
struct pwm_chip *chip = gpiochip_get_data(gc);
2421+
struct pwm_device *pwm = &chip->pwms[offset];
2422+
int ret;
2423+
struct pwm_waveform wf = {
2424+
.period_length_ns = 1,
2425+
};
2426+
2427+
ret = pwm_round_waveform_might_sleep(pwm, &wf);
2428+
if (ret < 0)
2429+
return ret;
2430+
2431+
if (value)
2432+
wf.duty_length_ns = wf.period_length_ns;
2433+
else
2434+
wf.duty_length_ns = 0;
2435+
2436+
return pwm_set_waveform_might_sleep(pwm, &wf, true);
2437+
}
2438+
23862439
/**
23872440
* __pwmchip_add() - register a new PWM chip
23882441
* @chip: the PWM chip to add
@@ -2449,9 +2502,33 @@ int __pwmchip_add(struct pwm_chip *chip, struct module *owner)
24492502
if (ret)
24502503
goto err_device_add;
24512504

2505+
if (IS_ENABLED(CONFIG_PWM_PROVIDE_GPIO) && chip->ops->write_waveform) {
2506+
struct device *parent = pwmchip_parent(chip);
2507+
2508+
chip->gpio = (typeof(chip->gpio)){
2509+
.label = dev_name(parent),
2510+
.parent = parent,
2511+
.request = pwm_gpio_request,
2512+
.free = pwm_gpio_free,
2513+
.get_direction = pwm_gpio_get_direction,
2514+
.set = pwm_gpio_set,
2515+
.base = -1,
2516+
.ngpio = chip->npwm,
2517+
.can_sleep = true,
2518+
};
2519+
2520+
ret = gpiochip_add_data(&chip->gpio, chip);
2521+
if (ret)
2522+
goto err_gpiochip_add;
2523+
}
2524+
24522525
return 0;
24532526

2527+
err_gpiochip_add:
2528+
2529+
cdev_device_del(&chip->cdev, &chip->dev);
24542530
err_device_add:
2531+
24552532
scoped_guard(pwmchip, chip)
24562533
chip->operational = false;
24572534

@@ -2472,6 +2549,9 @@ EXPORT_SYMBOL_GPL(__pwmchip_add);
24722549
*/
24732550
void pwmchip_remove(struct pwm_chip *chip)
24742551
{
2552+
if (IS_ENABLED(CONFIG_PWM_PROVIDE_GPIO) && chip->ops->write_waveform)
2553+
gpiochip_remove(&chip->gpio);
2554+
24752555
pwmchip_sysfs_unexport(chip);
24762556

24772557
scoped_guard(mutex, &pwm_lock) {

drivers/pwm/pwm-berlin.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ static int berlin_pwm_suspend(struct device *dev)
234234
for (i = 0; i < chip->npwm; i++) {
235235
struct berlin_pwm_channel *channel = &bpc->channel[i];
236236

237-
channel->enable = berlin_pwm_readl(bpc, i, BERLIN_PWM_ENABLE);
237+
channel->enable = berlin_pwm_readl(bpc, i, BERLIN_PWM_EN);
238238
channel->ctrl = berlin_pwm_readl(bpc, i, BERLIN_PWM_CONTROL);
239239
channel->duty = berlin_pwm_readl(bpc, i, BERLIN_PWM_DUTY);
240240
channel->tcnt = berlin_pwm_readl(bpc, i, BERLIN_PWM_TCNT);
@@ -262,7 +262,7 @@ static int berlin_pwm_resume(struct device *dev)
262262
berlin_pwm_writel(bpc, i, channel->ctrl, BERLIN_PWM_CONTROL);
263263
berlin_pwm_writel(bpc, i, channel->duty, BERLIN_PWM_DUTY);
264264
berlin_pwm_writel(bpc, i, channel->tcnt, BERLIN_PWM_TCNT);
265-
berlin_pwm_writel(bpc, i, channel->enable, BERLIN_PWM_ENABLE);
265+
berlin_pwm_writel(bpc, i, channel->enable, BERLIN_PWM_EN);
266266
}
267267

268268
return 0;

drivers/pwm/pwm-cros-ec.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,9 @@ static int cros_ec_pwm_set_duty(struct cros_ec_pwm_device *ec_pwm, u8 index,
4949
u16 duty)
5050
{
5151
struct cros_ec_device *ec = ec_pwm->ec;
52-
struct {
53-
struct cros_ec_command msg;
52+
TRAILING_OVERLAP(struct cros_ec_command, msg, data,
5453
struct ec_params_pwm_set_duty params;
55-
} __packed buf;
54+
) __packed buf;
5655
struct ec_params_pwm_set_duty *params = &buf.params;
5756
struct cros_ec_command *msg = &buf.msg;
5857
int ret;
@@ -83,13 +82,12 @@ static int cros_ec_pwm_set_duty(struct cros_ec_pwm_device *ec_pwm, u8 index,
8382

8483
static int cros_ec_pwm_get_duty(struct cros_ec_device *ec, bool use_pwm_type, u8 index)
8584
{
86-
struct {
87-
struct cros_ec_command msg;
85+
TRAILING_OVERLAP(struct cros_ec_command, msg, data,
8886
union {
8987
struct ec_params_pwm_get_duty params;
9088
struct ec_response_pwm_get_duty resp;
9189
};
92-
} __packed buf;
90+
) __packed buf;
9391
struct ec_params_pwm_get_duty *params = &buf.params;
9492
struct ec_response_pwm_get_duty *resp = &buf.resp;
9593
struct cros_ec_command *msg = &buf.msg;

0 commit comments

Comments
 (0)