Pull pwm updates from Thierry Reding: "There's quite a few changes this time around. Most of these are fixes and cleanups, but there's also new chip support for some drivers and a bit of rework" * tag 'pwm/for-5.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm: (33 commits) pwm: pca9685: Fix PWM/GPIO inter-operation pwm: Make pwm_apply_state_debug() static pwm: meson: Remove redundant assignment to variable fin_freq pwm: jz4740: Allow selection of PWM channels 0 and 1 pwm: jz4740: Obtain regmap from parent node pwm: jz4740: Improve algorithm of clock calculation pwm: jz4740: Use clocks from TCU driver pwm: sun4i: Remove redundant needs_delay pwm: omap-dmtimer: Implement .apply callback pwm: omap-dmtimer: Do not disable PWM before changing period/duty_cycle pwm: omap-dmtimer: Fix PWM enabling sequence pwm: omap-dmtimer: Update description for PWM OMAP DM timer pwm: omap-dmtimer: Drop unused header file pwm: renesas-tpu: Drop confusing registered message pwm: renesas-tpu: Fix late Runtime PM enablement pwm: rcar: Fix late Runtime PM enablement dt-bindings: pwm: renesas-tpu: Document more R-Car Gen2 support pwm: meson: Fix confusing indentation pwm: pca9685: Use gpio core provided macro GPIO_LINE_DIRECTION_OUT pwm: pca9685: Replace CONFIG_PM with __maybe_unused ...
Unified · Split
| @@ -1,23 +0,0 @@ | ||
| 1 | −* PWM controlled by ChromeOS EC | |
| 2 | − | |
| 3 | −Google's ChromeOS EC PWM is a simple PWM attached to the Embedded Controller | |
| 4 | −(EC) and controlled via a host-command interface. | |
| 5 | − | |
| 6 | −An EC PWM node should be only found as a sub-node of the EC node (see | |
| 7 | −Documentation/devicetree/bindings/mfd/cros-ec.txt). | |
| 8 | − | |
| 9 | −Required properties: | |
| 10 | −- compatible: Must contain "google,cros-ec-pwm" | |
| 11 | −- #pwm-cells: Should be 1. The cell specifies the PWM index. | |
| 12 | − | |
| 13 | −Example: | |
| 14 | − cros-ec@0 { | |
| 15 | − compatible = "google,cros-ec-spi"; | |
| 16 | − | |
| 17 | − ... | |
| 18 | − | |
| 19 | − cros_ec_pwm: ec-pwm { | |
| 20 | − compatible = "google,cros-ec-pwm"; | |
| 21 | − #pwm-cells = <1>; | |
| 22 | − }; | |
| 23 | − }; | |
| @@ -0,0 +1,40 @@ | ||
| 1 | +# SPDX-License-Identifier: GPL-2.0 | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/pwm/google,cros-ec-pwm.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: PWM controlled by ChromeOS EC | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Thierry Reding <thierry.reding@gmail.com> | |
| 11 | + - '"Uwe Kleine-König" <u.kleine-koenig@pengutronix.de>' | |
| 12 | + | |
| 13 | +description: | | |
| 14 | + Google's ChromeOS EC PWM is a simple PWM attached to the Embedded Controller | |
| 15 | + (EC) and controlled via a host-command interface. | |
| 16 | + An EC PWM node should be only found as a sub-node of the EC node (see | |
| 17 | + Documentation/devicetree/bindings/mfd/cros-ec.txt). | |
| 18 | + | |
| 19 | +properties: | |
| 20 | + compatible: | |
| 21 | + const: google,cros-ec-pwm | |
| 22 | + "#pwm-cells": | |
| 23 | + description: The cell specifies the PWM index. | |
| 24 | + const: 1 | |
| 25 | + | |
| 26 | +required: | |
| 27 | + - compatible | |
| 28 | + - '#pwm-cells' | |
| 29 | + | |
| 30 | +additionalProperties: false | |
| 31 | + | |
| 32 | +examples: | |
| 33 | + - | | |
| 34 | + cros-ec@0 { | |
| 35 | + compatible = "google,cros-ec-spi"; | |
| 36 | + cros_ec_pwm: ec-pwm { | |
| 37 | + compatible = "google,cros-ec-pwm"; | |
| 38 | + #pwm-cells = <1>; | |
| 39 | + }; | |
| 40 | + }; | |
| @@ -9,6 +9,7 @@ Required properties: · 8 unmodified lines | ||
| 9 | 9 | - "nvidia,tegra132-pwm", "nvidia,tegra20-pwm": for Tegra132 |
| 10 | 10 | - "nvidia,tegra210-pwm", "nvidia,tegra20-pwm": for Tegra210 |
| 11 | 11 | - "nvidia,tegra186-pwm": for Tegra186 |
| 12 | + - "nvidia,tegra194-pwm": for Tegra194 | |
| 12 | 13 | - reg: physical base address and length of the controller's registers |
| 13 | 14 | - #pwm-cells: should be 2. See pwm.yaml in this directory for a description of |
| 14 | 15 | the cells format. |
| @@ -33,6 +33,15 @@ config PWM_SYSFS · 32 unmodified lines | ||
| 33 | 33 | bool |
| 34 | 34 | default y if SYSFS |
| 35 | 35 | |
| 36 | +config PWM_DEBUG | |
| 37 | + bool "PWM lowlevel drivers additional checks and debug messages" | |
| 38 | + depends on DEBUG_KERNEL | |
| 39 | + help | |
| 40 | + This option enables some additional checks to help lowlevel driver | |
| 41 | + authors to get their callbacks implemented correctly. | |
| 42 | + It is expected to introduce some runtime overhead and diagnostic | |
| 43 | + output to the kernel log, so only enable while working on a driver. | |
| 44 | + | |
| 36 | 45 | config PWM_AB8500 |
| 37 | 46 | tristate "AB8500 PWM support" |
| 38 | 47 | depends on AB8500_CORE && ARCH_U8500 |
| @@ -44,7 +53,8 @@ config PWM_AB8500 · 5 unmodified lines | ||
| 44 | 53 | |
| 45 | 54 | config PWM_ATMEL |
| 46 | 55 | tristate "Atmel PWM support" |
| 47 | − depends on ARCH_AT91 && OF | |
| 56 | + depends on OF | |
| 57 | + depends on ARCH_AT91 || COMPILE_TEST | |
| 48 | 58 | help |
| 49 | 59 | Generic PWM framework driver for Atmel SoC. |
| 50 | 60 | |
| @@ -100,7 +110,7 @@ config PWM_BCM_KONA · 49 unmodified lines | ||
| 100 | 110 | |
| 101 | 111 | config PWM_BCM2835 |
| 102 | 112 | tristate "BCM2835 PWM support" |
| 103 | − depends on ARCH_BCM2835 || ARCH_BRCMSTB | |
| 113 | + depends on ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST | |
| 104 | 114 | help |
| 105 | 115 | PWM framework driver for BCM2835 controller (Raspberry Pi) |
| 106 | 116 | |
| @@ -109,7 +119,7 @@ config PWM_BCM2835 · 2 unmodified lines | ||
| 109 | 119 | |
| 110 | 120 | config PWM_BERLIN |
| 111 | 121 | tristate "Marvell Berlin PWM support" |
| 112 | − depends on ARCH_BERLIN | |
| 122 | + depends on ARCH_BERLIN || COMPILE_TEST | |
| 113 | 123 | help |
| 114 | 124 | PWM framework driver for Marvell Berlin SoCs. |
| 115 | 125 | |
| @@ -118,7 +128,7 @@ config PWM_BERLIN · 2 unmodified lines | ||
| 118 | 128 | |
| 119 | 129 | config PWM_BRCMSTB |
| 120 | 130 | tristate "Broadcom STB PWM support" |
| 121 | − depends on ARCH_BRCMSTB || BMIPS_GENERIC | |
| 131 | + depends on ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST | |
| 122 | 132 | help |
| 123 | 133 | Generic PWM framework driver for the Broadcom Set-top-Box |
| 124 | 134 | SoCs (BCM7xxx). |
| @@ -152,7 +162,7 @@ config PWM_CROS_EC · 27 unmodified lines | ||
| 152 | 162 | |
| 153 | 163 | config PWM_EP93XX |
| 154 | 164 | tristate "Cirrus Logic EP93xx PWM support" |
| 155 | − depends on ARCH_EP93XX | |
| 165 | + depends on ARCH_EP93XX || COMPILE_TEST | |
| 156 | 166 | help |
| 157 | 167 | Generic PWM framework driver for Cirrus Logic EP93xx. |
| 158 | 168 | |
| @@ -195,7 +205,7 @@ config PWM_IMG · 36 unmodified lines | ||
| 195 | 205 | |
| 196 | 206 | config PWM_IMX1 |
| 197 | 207 | tristate "i.MX1 PWM support" |
| 198 | − depends on ARCH_MXC | |
| 208 | + depends on ARCH_MXC || COMPILE_TEST | |
| 199 | 209 | help |
| 200 | 210 | Generic PWM framework driver for i.MX1 and i.MX21 |
| 201 | 211 | |
| @@ -204,7 +214,7 @@ config PWM_IMX1 · 2 unmodified lines | ||
| 204 | 214 | |
| 205 | 215 | config PWM_IMX27 |
| 206 | 216 | tristate "i.MX27 PWM support" |
| 207 | − depends on ARCH_MXC | |
| 217 | + depends on ARCH_MXC || COMPILE_TEST | |
| 208 | 218 | help |
| 209 | 219 | Generic PWM framework driver for i.MX27 and later i.MX SoCs. |
| 210 | 220 | |
| @@ -225,6 +235,8 @@ config PWM_IMX_TPM · 14 unmodified lines | ||
| 225 | 235 | config PWM_JZ4740 |
| 226 | 236 | tristate "Ingenic JZ47xx PWM support" |
| 227 | 237 | depends on MACH_INGENIC |
| 238 | + depends on COMMON_CLK | |
| 239 | + select MFD_SYSCON | |
| 228 | 240 | help |
| 229 | 241 | Generic PWM framework driver for Ingenic JZ47xx based |
| 230 | 242 | machines. |
| @@ -244,7 +256,7 @@ config PWM_LP3943 · 13 unmodified lines | ||
| 244 | 256 | |
| 245 | 257 | config PWM_LPC18XX_SCT |
| 246 | 258 | tristate "LPC18xx/43xx PWM/SCT support" |
| 247 | − depends on ARCH_LPC18XX | |
| 259 | + depends on ARCH_LPC18XX || COMPILE_TEST | |
| 248 | 260 | help |
| 249 | 261 | Generic PWM framework driver for NXP LPC18xx PWM/SCT which |
| 250 | 262 | supports 16 channels. |
| @@ -256,7 +268,7 @@ config PWM_LPC18XX_SCT · 5 unmodified lines | ||
| 256 | 268 | |
| 257 | 269 | config PWM_LPC32XX |
| 258 | 270 | tristate "LPC32XX PWM support" |
| 259 | − depends on ARCH_LPC32XX | |
| 271 | + depends on ARCH_LPC32XX || COMPILE_TEST | |
| 260 | 272 | help |
| 261 | 273 | Generic PWM framework driver for LPC32XX. The LPC32XX SOC has two |
| 262 | 274 | PWM controllers. |
| @@ -289,7 +301,8 @@ config PWM_LPSS_PLATFORM · 26 unmodified lines | ||
| 289 | 301 | |
| 290 | 302 | config PWM_MESON |
| 291 | 303 | tristate "Amlogic Meson PWM driver" |
| 292 | − depends on ARCH_MESON | |
| 304 | + depends on ARCH_MESON || COMPILE_TEST | |
| 305 | + depends on COMMON_CLK | |
| 293 | 306 | help |
| 294 | 307 | The platform driver for Amlogic Meson PWM controller. |
| 295 | 308 | |
| @@ -318,7 +331,8 @@ config PWM_MEDIATEK · 22 unmodified lines | ||
| 318 | 331 | |
| 319 | 332 | config PWM_MXS |
| 320 | 333 | tristate "Freescale MXS PWM support" |
| 321 | − depends on ARCH_MXS && OF | |
| 334 | + depends on OF | |
| 335 | + depends on ARCH_MXS || COMPILE_TEST | |
| 322 | 336 | select STMP_DEVICE |
| 323 | 337 | help |
| 324 | 338 | Generic PWM framework driver for Freescale MXS. |
| @@ -357,7 +371,7 @@ config PWM_PUV3 · 32 unmodified lines | ||
| 357 | 371 | |
| 358 | 372 | config PWM_PXA |
| 359 | 373 | tristate "PXA PWM support" |
| 360 | − depends on ARCH_PXA | |
| 374 | + depends on ARCH_PXA || COMPILE_TEST | |
| 361 | 375 | help |
| 362 | 376 | Generic PWM framework driver for PXA. |
| 363 | 377 | |
| @@ -388,14 +402,14 @@ config PWM_RENESAS_TPU · 24 unmodified lines | ||
| 388 | 402 | |
| 389 | 403 | config PWM_ROCKCHIP |
| 390 | 404 | tristate "Rockchip PWM support" |
| 391 | − depends on ARCH_ROCKCHIP | |
| 405 | + depends on ARCH_ROCKCHIP || COMPILE_TEST | |
| 392 | 406 | help |
| 393 | 407 | Generic PWM framework driver for the PWM controller found on |
| 394 | 408 | Rockchip SoCs. |
| 395 | 409 | |
| 396 | 410 | config PWM_SAMSUNG |
| 397 | 411 | tristate "Samsung PWM support" |
| 398 | − depends on PLAT_SAMSUNG || ARCH_EXYNOS | |
| 412 | + depends on PLAT_SAMSUNG || ARCH_EXYNOS || COMPILE_TEST | |
| 399 | 413 | help |
| 400 | 414 | Generic PWM framework driver for Samsung. |
| 401 | 415 | |
| @@ -415,7 +429,7 @@ config PWM_SIFIVE · 13 unmodified lines | ||
| 415 | 429 | |
| 416 | 430 | config PWM_SPEAR |
| 417 | 431 | tristate "STMicroelectronics SPEAr PWM support" |
| 418 | − depends on PLAT_SPEAR | |
| 432 | + depends on PLAT_SPEAR || COMPILE_TEST | |
| 419 | 433 | depends on OF |
| 420 | 434 | help |
| 421 | 435 | Generic PWM framework driver for the PWM controller on ST |
| @@ -437,7 +451,7 @@ config PWM_SPRD · 15 unmodified lines | ||
| 437 | 451 | |
| 438 | 452 | config PWM_STI |
| 439 | 453 | tristate "STiH4xx PWM support" |
| 440 | − depends on ARCH_STI | |
| 454 | + depends on ARCH_STI || COMPILE_TEST | |
| 441 | 455 | depends on OF |
| 442 | 456 | help |
| 443 | 457 | Generic PWM framework driver for STiH4xx SoCs. |
| @@ -447,7 +461,7 @@ config PWM_STI · 3 unmodified lines | ||
| 447 | 461 | |
| 448 | 462 | config PWM_STM32 |
| 449 | 463 | tristate "STMicroelectronics STM32 PWM" |
| 450 | − depends on MFD_STM32_TIMERS | |
| 464 | + depends on MFD_STM32_TIMERS || COMPILE_TEST | |
| 451 | 465 | help |
| 452 | 466 | Generic PWM framework driver for STM32 SoCs. |
| 453 | 467 | |
| @@ -483,7 +497,7 @@ config PWM_SUN4I · 29 unmodified lines | ||
| 483 | 497 | |
| 484 | 498 | config PWM_TEGRA |
| 485 | 499 | tristate "NVIDIA Tegra PWM support" |
| 486 | − depends on ARCH_TEGRA | |
| 500 | + depends on ARCH_TEGRA || COMPILE_TEST | |
| 487 | 501 | help |
| 488 | 502 | Generic PWM framework driver for the PWFM controller found on NVIDIA |
| 489 | 503 | Tegra SoCs. |
| @@ -493,7 +507,7 @@ config PWM_TEGRA · 3 unmodified lines | ||
| 493 | 507 | |
| 494 | 508 | config PWM_TIECAP |
| 495 | 509 | tristate "ECAP PWM support" |
| 496 | − depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_KEYSTONE || ARCH_K3 | |
| 510 | + depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST | |
| 497 | 511 | help |
| 498 | 512 | PWM driver support for the ECAP APWM controller found on TI SOCs |
| 499 | 513 | |
| @@ -502,7 +516,7 @@ config PWM_TIECAP · 2 unmodified lines | ||
| 502 | 516 | |
| 503 | 517 | config PWM_TIEHRPWM |
| 504 | 518 | tristate "EHRPWM PWM support" |
| 505 | − depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_K3 | |
| 519 | + depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_K3 || COMPILE_TEST | |
| 506 | 520 | help |
| 507 | 521 | PWM driver support for the EHRPWM controller found on TI SOCs |
| 508 | 522 | |
| @@ -529,7 +543,7 @@ config PWM_TWL_LED · 20 unmodified lines | ||
| 529 | 543 | |
| 530 | 544 | config PWM_VT8500 |
| 531 | 545 | tristate "vt8500 PWM support" |
| 532 | − depends on ARCH_VT8500 | |
| 546 | + depends on ARCH_VT8500 || COMPILE_TEST | |
| 533 | 547 | help |
| 534 | 548 | Generic PWM framework driver for vt8500. |
| 535 | 549 | |
| @@ -538,7 +552,7 @@ config PWM_VT8500 · 2 unmodified lines | ||
| 538 | 552 | |
| 539 | 553 | config PWM_ZX |
| 540 | 554 | tristate "ZTE ZX PWM support" |
| 541 | − depends on ARCH_ZX | |
| 555 | + depends on ARCH_ZX || COMPILE_TEST | |
| 542 | 556 | help |
| 543 | 557 | Generic PWM framework driver for ZTE ZX family SoCs. |
| 544 | 558 | |
| @@ -120,6 +120,9 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label) · 119 unmodified lines | ||
| 120 | 120 | if (pwm->chip->ops->get_state) { |
| 121 | 121 | pwm->chip->ops->get_state(pwm->chip, pwm, &pwm->state); |
| 122 | 122 | trace_pwm_get(pwm, &pwm->state); |
| 123 | + | |
| 124 | + if (IS_ENABLED(PWM_DEBUG)) | |
| 125 | + pwm->last = pwm->state; | |
| 123 | 126 | } |
| 124 | 127 | |
| 125 | 128 | set_bit(PWMF_REQUESTED, &pwm->flags); |
| @@ -232,17 +235,28 @@ void *pwm_get_chip_data(struct pwm_device *pwm) · 106 unmodified lines | ||
| 232 | 235 | } |
| 233 | 236 | EXPORT_SYMBOL_GPL(pwm_get_chip_data); |
| 234 | 237 | |
| 235 | −static bool pwm_ops_check(const struct pwm_ops *ops) | |
| 238 | +static bool pwm_ops_check(const struct pwm_chip *chip) | |
| 236 | 239 | { |
| 240 | + | |
| 241 | + const struct pwm_ops *ops = chip->ops; | |
| 242 | + | |
| 237 | 243 | /* driver supports legacy, non-atomic operation */ |
| 238 | − if (ops->config && ops->enable && ops->disable) | |
| 239 | − return true; | |
| 244 | + if (ops->config && ops->enable && ops->disable) { | |
| 245 | + if (IS_ENABLED(CONFIG_PWM_DEBUG)) | |
| 246 | + dev_warn(chip->dev, | |
| 247 | + "Driver needs updating to atomic API\n"); | |
| 240 | 248 | |
| 241 | − /* driver supports atomic operation */ | |
| 242 | − if (ops->apply) | |
| 243 | 249 | return true; |
| 250 | + } | |
| 244 | 251 | |
| 245 | − return false; | |
| 252 | + if (!ops->apply) | |
| 253 | + return false; | |
| 254 | + | |
| 255 | + if (IS_ENABLED(CONFIG_PWM_DEBUG) && !ops->get_state) | |
| 256 | + dev_warn(chip->dev, | |
| 257 | + "Please implement the .get_state() callback\n"); | |
| 258 | + | |
| 259 | + return true; | |
| 246 | 260 | } |
| 247 | 261 | |
| 248 | 262 | /** |
| @@ -266,7 +280,7 @@ int pwmchip_add_with_polarity(struct pwm_chip *chip, · 17 unmodified lines | ||
| 266 | 280 | if (!chip || !chip->dev || !chip->ops || !chip->npwm) |
| 267 | 281 | return -EINVAL; |
| 268 | 282 | |
| 269 | − if (!pwm_ops_check(chip->ops)) | |
| 283 | + if (!pwm_ops_check(chip)) | |
| 270 | 284 | return -EINVAL; |
| 271 | 285 | |
| 272 | 286 | mutex_lock(&pwm_lock); |
| @@ -450,6 +464,107 @@ void pwm_free(struct pwm_device *pwm) · 177 unmodified lines | ||
| 450 | 464 | } |
| 451 | 465 | EXPORT_SYMBOL_GPL(pwm_free); |
| 452 | 466 | |
| 467 | +static void pwm_apply_state_debug(struct pwm_device *pwm, | |
| 468 | + const struct pwm_state *state) | |
| 469 | +{ | |
| 470 | + struct pwm_state *last = &pwm->last; | |
| 471 | + struct pwm_chip *chip = pwm->chip; | |
| 472 | + struct pwm_state s1, s2; | |
| 473 | + int err; | |
| 474 | + | |
| 475 | + if (!IS_ENABLED(CONFIG_PWM_DEBUG)) | |
| 476 | + return; | |
| 477 | + | |
| 478 | + /* No reasonable diagnosis possible without .get_state() */ | |
| 479 | + if (!chip->ops->get_state) | |
| 480 | + return; | |
| 481 | + | |
| 482 | + /* | |
| 483 | + * *state was just applied. Read out the hardware state and do some | |
| 484 | + * checks. | |
| 485 | + */ | |
| 486 | + | |
| 487 | + chip->ops->get_state(chip, pwm, &s1); | |
| 488 | + trace_pwm_get(pwm, &s1); | |
| 489 | + | |
| 490 | + /* | |
| 491 | + * The lowlevel driver either ignored .polarity (which is a bug) or as | |
| 492 | + * best effort inverted .polarity and fixed .duty_cycle respectively. | |
| 493 | + * Undo this inversion and fixup for further tests. | |
| 494 | + */ | |
| 495 | + if (s1.enabled && s1.polarity != state->polarity) { | |
| 496 | + s2.polarity = state->polarity; | |
| 497 | + s2.duty_cycle = s1.period - s1.duty_cycle; | |
| 498 | + s2.period = s1.period; | |
| 499 | + s2.enabled = s1.enabled; | |
| 500 | + } else { | |
| 501 | + s2 = s1; | |
| 502 | + } | |
| 503 | + | |
| 504 | + if (s2.polarity != state->polarity && | |
| 505 | + state->duty_cycle < state->period) | |
| 506 | + dev_warn(chip->dev, ".apply ignored .polarity\n"); | |
| 507 | + | |
| 508 | + if (state->enabled && | |
| 509 | + last->polarity == state->polarity && | |
| 510 | + last->period > s2.period && | |
| 511 | + last->period <= state->period) | |
| 512 | + dev_warn(chip->dev, | |
| 513 | + ".apply didn't pick the best available period (requested: %u, applied: %u, possible: %u)\n", | |
| 514 | + state->period, s2.period, last->period); | |
| 515 | + | |
| 516 | + if (state->enabled && state->period < s2.period) | |
| 517 | + dev_warn(chip->dev, | |
| 518 | + ".apply is supposed to round down period (requested: %u, applied: %u)\n", | |
| 519 | + state->period, s2.period); | |
| 520 | + | |
| 521 | + if (state->enabled && | |
| 522 | + last->polarity == state->polarity && | |
| 523 | + last->period == s2.period && | |
| 524 | + last->duty_cycle > s2.duty_cycle && | |
| 525 | + last->duty_cycle <= state->duty_cycle) | |
| 526 | + dev_warn(chip->dev, | |
| 527 | + ".apply didn't pick the best available duty cycle (requested: %u/%u, applied: %u/%u, possible: %u/%u)\n", | |
| 528 | + state->duty_cycle, state->period, | |
| 529 | + s2.duty_cycle, s2.period, | |
| 530 | + last->duty_cycle, last->period); | |
| 531 | + | |
| 532 | + if (state->enabled && state->duty_cycle < s2.duty_cycle) | |
| 533 | + dev_warn(chip->dev, | |
| 534 | + ".apply is supposed to round down duty_cycle (requested: %u/%u, applied: %u/%u)\n", | |
| 535 | + state->duty_cycle, state->period, | |
| 536 | + s2.duty_cycle, s2.period); | |
| 537 | + | |
| 538 | + if (!state->enabled && s2.enabled && s2.duty_cycle > 0) | |
| 539 | + dev_warn(chip->dev, | |
| 540 | + "requested disabled, but yielded enabled with duty > 0"); | |
| 541 | + | |
| 542 | + /* reapply the state that the driver reported being configured. */ | |
| 543 | + err = chip->ops->apply(chip, pwm, &s1); | |
| 544 | + if (err) { | |
| 545 | + *last = s1; | |
| 546 | + dev_err(chip->dev, "failed to reapply current setting\n"); | |
| 547 | + return; | |
| 548 | + } | |
| 549 | + | |
| 550 | + trace_pwm_apply(pwm, &s1); | |
| 551 | + | |
| 552 | + chip->ops->get_state(chip, pwm, last); | |
| 553 | + trace_pwm_get(pwm, last); | |
| 554 | + | |
| 555 | + /* reapplication of the current state should give an exact match */ | |
| 556 | + if (s1.enabled != last->enabled || | |
| 557 | + s1.polarity != last->polarity || | |
| 558 | + (s1.enabled && s1.period != last->period) || | |
| 559 | + (s1.enabled && s1.duty_cycle != last->duty_cycle)) { | |
| 560 | + dev_err(chip->dev, | |
| 561 | + ".apply is not idempotent (ena=%d pol=%d %u/%u) -> (ena=%d pol=%d %u/%u)\n", | |
| 562 | + s1.enabled, s1.polarity, s1.duty_cycle, s1.period, | |
| 563 | + last->enabled, last->polarity, last->duty_cycle, | |
| 564 | + last->period); | |
| 565 | + } | |
| 566 | +} | |
| 567 | + | |
| 453 | 568 | /** |
| 454 | 569 | * pwm_apply_state() - atomically apply a new state to a PWM device |
| 455 | 570 | * @pwm: PWM device |
| @@ -480,6 +595,12 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state) · 24 unmodified lines | ||
| 480 | 595 | trace_pwm_apply(pwm, state); |
| 481 | 596 | |
| 482 | 597 | pwm->state = *state; |
| 598 | + | |
| 599 | + /* | |
| 600 | + * only do this after pwm->state was applied as some | |
| 601 | + * implementations of .get_state depend on this | |
| 602 | + */ | |
| 603 | + pwm_apply_state_debug(pwm, state); | |
| 483 | 604 | } else { |
| 484 | 605 | /* |
| 485 | 606 | * FIXME: restore the initial state in case of error. |
| @@ -166,6 +166,7 @@ static int bcm2835_pwm_probe(struct platform_device *pdev) · 165 unmodified lines | ||
| 166 | 166 | |
| 167 | 167 | pc->chip.dev = &pdev->dev; |
| 168 | 168 | pc->chip.ops = &bcm2835_pwm_ops; |
| 169 | + pc->chip.base = -1; | |
| 169 | 170 | pc->chip.npwm = 2; |
| 170 | 171 | pc->chip.of_xlate = of_pwm_xlate_with_flags; |
| 171 | 172 | pc->chip.of_pwm_n_cells = 3; |
| @@ -18,10 +18,8 @@ · 17 unmodified lines | ||
| 18 | 18 | #include <linux/clk.h> |
| 19 | 19 | #include <linux/err.h> |
| 20 | 20 | #include <linux/io.h> |
| 21 | −#include <linux/log2.h> | |
| 22 | 21 | #include <linux/module.h> |
| 23 | 22 | #include <linux/of.h> |
| 24 | −#include <linux/of_address.h> | |
| 25 | 23 | #include <linux/platform_device.h> |
| 26 | 24 | #include <linux/pwm.h> |
| 27 | 25 | #include <linux/slab.h> |
| @@ -18,7 +18,6 @@ · 17 unmodified lines | ||
| 18 | 18 | #include <linux/kernel.h> |
| 19 | 19 | #include <linux/module.h> |
| 20 | 20 | #include <linux/of.h> |
| 21 | −#include <linux/of_device.h> | |
| 22 | 21 | #include <linux/platform_device.h> |
| 23 | 22 | #include <linux/pwm.h> |
| 24 | 23 | #include <linux/slab.h> |
| @@ -96,9 +95,8 @@ struct pwm_imx27_chip { · 71 unmodified lines | ||
| 96 | 95 | |
| 97 | 96 | #define to_pwm_imx27_chip(chip) container_of(chip, struct pwm_imx27_chip, chip) |
| 98 | 97 | |
| 99 | −static int pwm_imx27_clk_prepare_enable(struct pwm_chip *chip) | |
| 98 | +static int pwm_imx27_clk_prepare_enable(struct pwm_imx27_chip *imx) | |
| 100 | 99 | { |
| 101 | − struct pwm_imx27_chip *imx = to_pwm_imx27_chip(chip); | |
| 102 | 100 | int ret; |
| 103 | 101 | |
| 104 | 102 | ret = clk_prepare_enable(imx->clk_ipg); |
| @@ -114,10 +112,8 @@ static int pwm_imx27_clk_prepare_enable(struct pwm_chip *chip) · 9 unmodified lines | ||
| 114 | 112 | return 0; |
| 115 | 113 | } |
| 116 | 114 | |
| 117 | −static void pwm_imx27_clk_disable_unprepare(struct pwm_chip *chip) | |
| 115 | +static void pwm_imx27_clk_disable_unprepare(struct pwm_imx27_chip *imx) | |
| 118 | 116 | { |
| 119 | − struct pwm_imx27_chip *imx = to_pwm_imx27_chip(chip); | |
| 120 | − | |
| 121 | 117 | clk_disable_unprepare(imx->clk_per); |
| 122 | 118 | clk_disable_unprepare(imx->clk_ipg); |
| 123 | 119 | } |
| @@ -130,7 +126,7 @@ static void pwm_imx27_get_state(struct pwm_chip *chip, · 6 unmodified lines | ||
| 130 | 126 | u64 tmp; |
| 131 | 127 | int ret; |
| 132 | 128 | |
| 133 | − ret = pwm_imx27_clk_prepare_enable(chip); | |
| 129 | + ret = pwm_imx27_clk_prepare_enable(imx); | |
| 134 | 130 | if (ret < 0) |
| 135 | 131 | return; |
| 136 | 132 | |
| @@ -174,8 +170,7 @@ static void pwm_imx27_get_state(struct pwm_chip *chip, · 37 unmodified lines | ||
| 174 | 170 | tmp = NSEC_PER_SEC * (u64)(val); |
| 175 | 171 | state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, pwm_clk); |
| 176 | 172 | |
| 177 | − if (!state->enabled) | |
| 178 | − pwm_imx27_clk_disable_unprepare(chip); | |
| 173 | + pwm_imx27_clk_disable_unprepare(imx); | |
| 179 | 174 | } |
| 180 | 175 | |
| 181 | 176 | static void pwm_imx27_sw_reset(struct pwm_chip *chip) |
| @@ -259,7 +254,7 @@ static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm, · 77 unmodified lines | ||
| 259 | 254 | if (cstate.enabled) { |
| 260 | 255 | pwm_imx27_wait_fifo_slot(chip, pwm); |
| 261 | 256 | } else { |
| 262 | − ret = pwm_imx27_clk_prepare_enable(chip); | |
| 257 | + ret = pwm_imx27_clk_prepare_enable(imx); | |
| 263 | 258 | if (ret) |
| 264 | 259 | return ret; |
| 265 | 260 | |
| @@ -289,8 +284,8 @@ static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm, · 23 unmodified lines | ||
| 289 | 284 | |
| 290 | 285 | writel(cr, imx->mmio_base + MX3_PWMCR); |
| 291 | 286 | |
| 292 | − if (!state->enabled && cstate.enabled) | |
| 293 | − pwm_imx27_clk_disable_unprepare(chip); | |
| 287 | + if (!state->enabled) | |
| 288 | + pwm_imx27_clk_disable_unprepare(imx); | |
| 294 | 289 | |
| 295 | 290 | return 0; |
| 296 | 291 | } |
| @@ -310,6 +305,8 @@ MODULE_DEVICE_TABLE(of, pwm_imx27_dt_ids); · 13 unmodified lines | ||
| 310 | 305 | static int pwm_imx27_probe(struct platform_device *pdev) |
| 311 | 306 | { |
| 312 | 307 | struct pwm_imx27_chip *imx; |
| 308 | + int ret; | |
| 309 | + u32 pwmcr; | |
| 313 | 310 | |
| 314 | 311 | imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL); |
| 315 | 312 | if (imx == NULL) |
| @@ -352,6 +349,15 @@ static int pwm_imx27_probe(struct platform_device *pdev) · 36 unmodified lines | ||
| 352 | 349 | if (IS_ERR(imx->mmio_base)) |
| 353 | 350 | return PTR_ERR(imx->mmio_base); |
| 354 | 351 | |
| 352 | + ret = pwm_imx27_clk_prepare_enable(imx); | |
| 353 | + if (ret) | |
| 354 | + return ret; | |
| 355 | + | |
| 356 | + /* keep clks on if pwm is running */ | |
| 357 | + pwmcr = readl(imx->mmio_base + MX3_PWMCR); | |
| 358 | + if (!(pwmcr & MX3_PWMCR_EN)) | |
| 359 | + pwm_imx27_clk_disable_unprepare(imx); | |
| 360 | + | |
| 355 | 361 | return pwmchip_add(&imx->chip); |
| 356 | 362 | } |
| 357 | 363 | |
| @@ -361,8 +367,6 @@ static int pwm_imx27_remove(struct platform_device *pdev) · 3 unmodified lines | ||
| 361 | 367 | |
| 362 | 368 | imx = platform_get_drvdata(pdev); |
| 363 | 369 | |
| 364 | − pwm_imx27_clk_disable_unprepare(&imx->chip); | |
| 365 | − | |
| 366 | 370 | return pwmchip_remove(&imx->chip); |
| 367 | 371 | } |
| 368 | 372 | |
| @@ -13,18 +13,19 @@ · 12 unmodified lines | ||
| 13 | 13 | #include <linux/err.h> |
| 14 | 14 | #include <linux/gpio.h> |
| 15 | 15 | #include <linux/kernel.h> |
| 16 | +#include <linux/mfd/ingenic-tcu.h> | |
| 17 | +#include <linux/mfd/syscon.h> | |
| 16 | 18 | #include <linux/module.h> |
| 17 | 19 | #include <linux/of_device.h> |
| 18 | 20 | #include <linux/platform_device.h> |
| 19 | 21 | #include <linux/pwm.h> |
| 20 | − | |
| 21 | −#include <asm/mach-jz4740/timer.h> | |
| 22 | +#include <linux/regmap.h> | |
| 22 | 23 | |
| 23 | 24 | #define NUM_PWM 8 |
| 24 | 25 | |
| 25 | 26 | struct jz4740_pwm_chip { |
| 26 | 27 | struct pwm_chip chip; |
| 27 | − struct clk *clk; | |
| 28 | + struct regmap *map; | |
| 28 | 29 | }; |
| 29 | 30 | |
| 30 | 31 | static inline struct jz4740_pwm_chip *to_jz4740(struct pwm_chip *chip) |
| @@ -32,82 +33,134 @@ static inline struct jz4740_pwm_chip *to_jz4740(struct pwm_chip *chip) · 1 unmodified line | ||
| 32 | 33 | return container_of(chip, struct jz4740_pwm_chip, chip); |
| 33 | 34 | } |
| 34 | 35 | |
| 36 | +static bool jz4740_pwm_can_use_chn(struct jz4740_pwm_chip *jz, | |
| 37 | + unsigned int channel) | |
| 38 | +{ | |
| 39 | + /* Enable all TCU channels for PWM use by default except channels 0/1 */ | |
| 40 | + u32 pwm_channels_mask = GENMASK(NUM_PWM - 1, 2); | |
| 41 | + | |
| 42 | + device_property_read_u32(jz->chip.dev->parent, | |
| 43 | + "ingenic,pwm-channels-mask", | |
| 44 | + &pwm_channels_mask); | |
| 45 | + | |
| 46 | + return !!(pwm_channels_mask & BIT(channel)); | |
| 47 | +} | |
| 48 | + | |
| 35 | 49 | static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) |
| 36 | 50 | { |
| 37 | − /* | |
| 38 | − * Timers 0 and 1 are used for system tasks, so they are unavailable | |
| 39 | − * for use as PWMs. | |
| 40 | − */ | |
| 41 | − if (pwm->hwpwm < 2) | |
| 51 | + struct jz4740_pwm_chip *jz = to_jz4740(chip); | |
| 52 | + struct clk *clk; | |
| 53 | + char name[16]; | |
| 54 | + int err; | |
| 55 | + | |
| 56 | + if (!jz4740_pwm_can_use_chn(jz, pwm->hwpwm)) | |
| 42 | 57 | return -EBUSY; |
| 43 | 58 | |
| 44 | − jz4740_timer_start(pwm->hwpwm); | |
| 59 | + snprintf(name, sizeof(name), "timer%u", pwm->hwpwm); | |
| 60 | + | |
| 61 | + clk = clk_get(chip->dev, name); | |
| 62 | + if (IS_ERR(clk)) { | |
| 63 | + if (PTR_ERR(clk) != -EPROBE_DEFER) | |
| 64 | + dev_err(chip->dev, "Failed to get clock: %pe", clk); | |
| 65 | + | |
| 66 | + return PTR_ERR(clk); | |
| 67 | + } | |
| 68 | + | |
| 69 | + err = clk_prepare_enable(clk); | |
| 70 | + if (err < 0) { | |
| 71 | + clk_put(clk); | |
| 72 | + return err; | |
| 73 | + } | |
| 74 | + | |
| 75 | + pwm_set_chip_data(pwm, clk); | |
| 45 | 76 | |
| 46 | 77 | return 0; |
| 47 | 78 | } |
| 48 | 79 | |
| 49 | 80 | static void jz4740_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) |
| 50 | 81 | { |
| 51 | − jz4740_timer_set_ctrl(pwm->hwpwm, 0); | |
| 82 | + struct clk *clk = pwm_get_chip_data(pwm); | |
| 52 | 83 | |
| 53 | − jz4740_timer_stop(pwm->hwpwm); | |
| 84 | + clk_disable_unprepare(clk); | |
| 85 | + clk_put(clk); | |
| 54 | 86 | } |
| 55 | 87 | |
| 56 | 88 | static int jz4740_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) |
| 57 | 89 | { |
| 58 | − uint32_t ctrl = jz4740_timer_get_ctrl(pwm->pwm); | |
| 90 | + struct jz4740_pwm_chip *jz = to_jz4740(chip); | |
| 91 | + | |
| 92 | + /* Enable PWM output */ | |
| 93 | + regmap_update_bits(jz->map, TCU_REG_TCSRc(pwm->hwpwm), | |
| 94 | + TCU_TCSR_PWM_EN, TCU_TCSR_PWM_EN); | |
| 59 | 95 | |
| 60 | − ctrl |= JZ_TIMER_CTRL_PWM_ENABLE; | |
| 61 | − jz4740_timer_set_ctrl(pwm->hwpwm, ctrl); | |
| 62 | − jz4740_timer_enable(pwm->hwpwm); | |
| 96 | + /* Start counter */ | |
| 97 | + regmap_write(jz->map, TCU_REG_TESR, BIT(pwm->hwpwm)); | |
| 63 | 98 | |
| 64 | 99 | return 0; |
| 65 | 100 | } |
| 66 | 101 | |
| 67 | 102 | static void jz4740_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) |
| 68 | 103 | { |
| 69 | − uint32_t ctrl = jz4740_timer_get_ctrl(pwm->hwpwm); | |
| 104 | + struct jz4740_pwm_chip *jz = to_jz4740(chip); | |
| 70 | 105 | |
| 71 | 106 | /* |
| 72 | 107 | * Set duty > period. This trick allows the TCU channels in TCU2 mode to |
| 73 | 108 | * properly return to their init level. |
| 74 | 109 | */ |
| 75 | − jz4740_timer_set_duty(pwm->hwpwm, 0xffff); | |
| 76 | − jz4740_timer_set_period(pwm->hwpwm, 0x0); | |
| 110 | + regmap_write(jz->map, TCU_REG_TDHRc(pwm->hwpwm), 0xffff); | |
| 111 | + regmap_write(jz->map, TCU_REG_TDFRc(pwm->hwpwm), 0x0); | |
| 77 | 112 | |
| 78 | 113 | /* |
| 79 | 114 | * Disable PWM output. |
| 80 | 115 | * In TCU2 mode (channel 1/2 on JZ4750+), this must be done before the |
| 81 | 116 | * counter is stopped, while in TCU1 mode the order does not matter. |
| 82 | 117 | */ |
| 83 | − ctrl &= ~JZ_TIMER_CTRL_PWM_ENABLE; | |
| 84 | − jz4740_timer_set_ctrl(pwm->hwpwm, ctrl); | |
| 118 | + regmap_update_bits(jz->map, TCU_REG_TCSRc(pwm->hwpwm), | |
| 119 | + TCU_TCSR_PWM_EN, 0); | |
| 85 | 120 | |
| 86 | 121 | /* Stop counter */ |
| 87 | − jz4740_timer_disable(pwm->hwpwm); | |
| 122 | + regmap_write(jz->map, TCU_REG_TECR, BIT(pwm->hwpwm)); | |
| 88 | 123 | } |
| 89 | 124 | |
| 90 | 125 | static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, |
| 91 | 126 | const struct pwm_state *state) |
| 92 | 127 | { |
| 93 | 128 | struct jz4740_pwm_chip *jz4740 = to_jz4740(pwm->chip); |
| 94 | − unsigned long long tmp; | |
| 129 | + unsigned long long tmp = 0xffffull * NSEC_PER_SEC; | |
| 130 | + struct clk *clk = pwm_get_chip_data(pwm); | |
| 95 | 131 | unsigned long period, duty; |
| 96 | − unsigned int prescaler = 0; | |
| 97 | − uint16_t ctrl; | |
| 132 | + long rate; | |
| 133 | + int err; | |
| 98 | 134 | |
| 99 | − tmp = (unsigned long long)clk_get_rate(jz4740->clk) * state->period; | |
| 100 | − do_div(tmp, 1000000000); | |
| 101 | − period = tmp; | |
| 135 | + /* | |
| 136 | + * Limit the clock to a maximum rate that still gives us a period value | |
| 137 | + * which fits in 16 bits. | |
| 138 | + */ | |
| 139 | + do_div(tmp, state->period); | |
| 102 | 140 | |
| 103 | − while (period > 0xffff && prescaler < 6) { | |
| 104 | − period >>= 2; | |
| 105 | − ++prescaler; | |
| 141 | + /* | |
| 142 | + * /!\ IMPORTANT NOTE: | |
| 143 | + * ------------------- | |
| 144 | + * This code relies on the fact that clk_round_rate() will always round | |
| 145 | + * down, which is not a valid assumption given by the clk API, but only | |
| 146 | + * happens to be true with the clk drivers used for Ingenic SoCs. | |
| 147 | + * | |
| 148 | + * Right now, there is no alternative as the clk API does not have a | |
| 149 | + * round-down function (and won't have one for a while), but if it ever | |
| 150 | + * comes to light, a round-down function should be used instead. | |
| 151 | + */ | |
| 152 | + rate = clk_round_rate(clk, tmp); | |
| 153 | + if (rate < 0) { | |
| 154 | + dev_err(chip->dev, "Unable to round rate: %ld", rate); | |
| 155 | + return rate; | |
| 106 | 156 | } |
| 107 | 157 | |
| 108 | − if (prescaler == 6) | |
| 109 | − return -EINVAL; | |
| 158 | + /* Calculate period value */ | |
| 159 | + tmp = (unsigned long long)rate * state->period; | |
| 160 | + do_div(tmp, NSEC_PER_SEC); | |
| 161 | + period = (unsigned long)tmp; | |
| 110 | 162 | |
| 163 | + /* Calculate duty value */ | |
| 111 | 164 | tmp = (unsigned long long)period * state->duty_cycle; |
| 112 | 165 | do_div(tmp, state->period); |
| 113 | 166 | duty = period - tmp; |
| @@ -117,26 +170,38 @@ static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, · 3 unmodified lines | ||
| 117 | 170 | |
| 118 | 171 | jz4740_pwm_disable(chip, pwm); |
| 119 | 172 | |
| 120 | − jz4740_timer_set_count(pwm->hwpwm, 0); | |
| 121 | − jz4740_timer_set_duty(pwm->hwpwm, duty); | |
| 122 | − jz4740_timer_set_period(pwm->hwpwm, period); | |
| 173 | + err = clk_set_rate(clk, rate); | |
| 174 | + if (err) { | |
| 175 | + dev_err(chip->dev, "Unable to set rate: %d", err); | |
| 176 | + return err; | |
| 177 | + } | |
| 178 | + | |
| 179 | + /* Reset counter to 0 */ | |
| 180 | + regmap_write(jz4740->map, TCU_REG_TCNTc(pwm->hwpwm), 0); | |
| 123 | 181 | |
| 124 | − ctrl = JZ_TIMER_CTRL_PRESCALER(prescaler) | JZ_TIMER_CTRL_SRC_EXT | | |
| 125 | − JZ_TIMER_CTRL_PWM_ABBRUPT_SHUTDOWN; | |
| 182 | + /* Set duty */ | |
| 183 | + regmap_write(jz4740->map, TCU_REG_TDHRc(pwm->hwpwm), duty); | |
| 126 | 184 | |
| 127 | − jz4740_timer_set_ctrl(pwm->hwpwm, ctrl); | |
| 185 | + /* Set period */ | |
| 186 | + regmap_write(jz4740->map, TCU_REG_TDFRc(pwm->hwpwm), period); | |
| 128 | 187 | |
| 188 | + /* Set abrupt shutdown */ | |
| 189 | + regmap_update_bits(jz4740->map, TCU_REG_TCSRc(pwm->hwpwm), | |
| 190 | + TCU_TCSR_PWM_SD, TCU_TCSR_PWM_SD); | |
| 191 | + | |
| 192 | + /* Set polarity */ | |
| 129 | 193 | switch (state->polarity) { |
| 130 | 194 | case PWM_POLARITY_NORMAL: |
| 131 | − ctrl &= ~JZ_TIMER_CTRL_PWM_ACTIVE_LOW; | |
| 195 | + regmap_update_bits(jz4740->map, TCU_REG_TCSRc(pwm->hwpwm), | |
| 196 | + TCU_TCSR_PWM_INITL_HIGH, 0); | |
| 132 | 197 | break; |
| 133 | 198 | case PWM_POLARITY_INVERSED: |
| 134 | − ctrl |= JZ_TIMER_CTRL_PWM_ACTIVE_LOW; | |
| 199 | + regmap_update_bits(jz4740->map, TCU_REG_TCSRc(pwm->hwpwm), | |
| 200 | + TCU_TCSR_PWM_INITL_HIGH, | |
| 201 | + TCU_TCSR_PWM_INITL_HIGH); | |
| 135 | 202 | break; |
| 136 | 203 | } |
| 137 | 204 | |
| 138 | − jz4740_timer_set_ctrl(pwm->hwpwm, ctrl); | |
| 139 | − | |
| 140 | 205 | if (state->enabled) |
| 141 | 206 | jz4740_pwm_enable(chip, pwm); |
| 142 | 207 | |
| @@ -152,17 +217,20 @@ static const struct pwm_ops jz4740_pwm_ops = { · 9 unmodified lines | ||
| 152 | 217 | |
| 153 | 218 | static int jz4740_pwm_probe(struct platform_device *pdev) |
| 154 | 219 | { |
| 220 | + struct device *dev = &pdev->dev; | |
| 155 | 221 | struct jz4740_pwm_chip *jz4740; |
| 156 | 222 | |
| 157 | − jz4740 = devm_kzalloc(&pdev->dev, sizeof(*jz4740), GFP_KERNEL); | |
| 223 | + jz4740 = devm_kzalloc(dev, sizeof(*jz4740), GFP_KERNEL); | |
| 158 | 224 | if (!jz4740) |
| 159 | 225 | return -ENOMEM; |
| 160 | 226 | |
| 161 | − jz4740->clk = devm_clk_get(&pdev->dev, "ext"); | |
| 162 | − if (IS_ERR(jz4740->clk)) | |
| 163 | − return PTR_ERR(jz4740->clk); | |
| 227 | + jz4740->map = device_node_to_regmap(dev->parent->of_node); | |
| 228 | + if (IS_ERR(jz4740->map)) { | |
| 229 | + dev_err(dev, "regmap not found: %ld\n", PTR_ERR(jz4740->map)); | |
| 230 | + return PTR_ERR(jz4740->map); | |
| 231 | + } | |
| 164 | 232 | |
| 165 | − jz4740->chip.dev = &pdev->dev; | |
| 233 | + jz4740->chip.dev = dev; | |
| 166 | 234 | jz4740->chip.ops = &jz4740_pwm_ops; |
| 167 | 235 | jz4740->chip.npwm = NUM_PWM; |
| 168 | 236 | jz4740->chip.base = -1; |
| @@ -136,7 +136,7 @@ static int meson_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) · 135 unmodified lines | ||
| 136 | 136 | dev_err(dev, "failed to set parent %s for %s: %d\n", |
| 137 | 137 | __clk_get_name(channel->clk_parent), |
| 138 | 138 | __clk_get_name(channel->clk), err); |
| 139 | − return err; | |
| 139 | + return err; | |
| 140 | 140 | } |
| 141 | 141 | } |
| 142 | 142 | |
| @@ -163,7 +163,7 @@ static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm, · 20 unmodified lines | ||
| 163 | 163 | { |
| 164 | 164 | struct meson_pwm_channel *channel = pwm_get_chip_data(pwm); |
| 165 | 165 | unsigned int duty, period, pre_div, cnt, duty_cnt; |
| 166 | − unsigned long fin_freq = -1; | |
| 166 | + unsigned long fin_freq; | |
| 167 | 167 | |
| 168 | 168 | duty = state->duty_cycle; |
| 169 | 169 | period = state->period; |
| @@ -9,7 +9,6 @@ · 8 unmodified lines | ||
| 9 | 9 | #include <linux/kernel.h> |
| 10 | 10 | #include <linux/module.h> |
| 11 | 11 | #include <linux/of.h> |
| 12 | −#include <linux/of_address.h> | |
| 13 | 12 | #include <linux/platform_device.h> |
| 14 | 13 | #include <linux/pwm.h> |
| 15 | 14 | #include <linux/slab.h> |
| @@ -10,7 +10,27 @@ · 9 unmodified lines | ||
| 10 | 10 | * |
| 11 | 11 | * Description: |
| 12 | 12 | * This file is the core OMAP support for the generic, Linux |
| 13 | − * PWM driver / controller, using the OMAP's dual-mode timers. | |
| 13 | + * PWM driver / controller, using the OMAP's dual-mode timers | |
| 14 | + * with a timer counter that goes up. When it overflows it gets | |
| 15 | + * reloaded with the load value and the pwm output goes up. | |
| 16 | + * When counter matches with match register, the output goes down. | |
| 17 | + * Reference Manual: http://www.ti.com/lit/ug/spruh73q/spruh73q.pdf | |
| 18 | + * | |
| 19 | + * Limitations: | |
| 20 | + * - When PWM is stopped, timer counter gets stopped immediately. This | |
| 21 | + * doesn't allow the current PWM period to complete and stops abruptly. | |
| 22 | + * - When PWM is running and changing both duty cycle and period, | |
| 23 | + * we cannot prevent in software that the output might produce | |
| 24 | + * a period with mixed settings. Especially when period/duty_cyle | |
| 25 | + * is updated while the pwm pin is high, current pwm period/duty_cycle | |
| 26 | + * can get updated as below based on the current timer counter: | |
| 27 | + * - period for current cycle = current_period + new period | |
| 28 | + * - duty_cycle for current period = current period + new duty_cycle. | |
| 29 | + * - PWM OMAP DM timer cannot change the polarity when pwm is active. When | |
| 30 | + * user requests a change in polarity when in active state: | |
| 31 | + * - PWM is stopped abruptly(without completing the current cycle) | |
| 32 | + * - Polarity is changed | |
| 33 | + * - A fresh cycle is started. | |
| 14 | 34 | */ |
| 15 | 35 | |
| 16 | 36 | #include <linux/clk.h> |
| @@ -20,8 +40,8 @@ · 3 unmodified lines | ||
| 20 | 40 | #include <linux/mutex.h> |
| 21 | 41 | #include <linux/of.h> |
| 22 | 42 | #include <linux/of_platform.h> |
| 43 | +#include <clocksource/timer-ti-dm.h> | |
| 23 | 44 | #include <linux/platform_data/dmtimer-omap.h> |
| 24 | −#include <linux/platform_data/pwm_omap_dmtimer.h> | |
| 25 | 45 | #include <linux/platform_device.h> |
| 26 | 46 | #include <linux/pm_runtime.h> |
| 27 | 47 | #include <linux/pwm.h> |
| @@ -31,10 +51,20 @@ · 3 unmodified lines | ||
| 31 | 51 | #define DM_TIMER_LOAD_MIN 0xfffffffe |
| 32 | 52 | #define DM_TIMER_MAX 0xffffffff |
| 33 | 53 | |
| 54 | +/** | |
| 55 | + * struct pwm_omap_dmtimer_chip - Structure representing a pwm chip | |
| 56 | + * corresponding to omap dmtimer. | |
| 57 | + * @chip: PWM chip structure representing PWM controller | |
| 58 | + * @mutex: Mutex to protect pwm apply state | |
| 59 | + * @dm_timer: Pointer to omap dm timer. | |
| 60 | + * @pdata: Pointer to omap dm timer ops. | |
| 61 | + * dm_timer_pdev: Pointer to omap dm timer platform device | |
| 62 | + */ | |
| 34 | 63 | struct pwm_omap_dmtimer_chip { |
| 35 | 64 | struct pwm_chip chip; |
| 65 | + /* Mutex to protect pwm apply state */ | |
| 36 | 66 | struct mutex mutex; |
| 37 | − pwm_omap_dmtimer *dm_timer; | |
| 67 | + struct omap_dm_timer *dm_timer; | |
| 38 | 68 | const struct omap_dm_timer_ops *pdata; |
| 39 | 69 | struct platform_device *dm_timer_pdev; |
| 40 | 70 | }; |
| @@ -45,11 +75,22 @@ to_pwm_omap_dmtimer_chip(struct pwm_chip *chip) · 4 unmodified lines | ||
| 45 | 75 | return container_of(chip, struct pwm_omap_dmtimer_chip, chip); |
| 46 | 76 | } |
| 47 | 77 | |
| 78 | +/** | |
| 79 | + * pwm_omap_dmtimer_get_clock_cycles() - Get clock cycles in a time frame | |
| 80 | + * @clk_rate: pwm timer clock rate | |
| 81 | + * @ns: time frame in nano seconds. | |
| 82 | + * | |
| 83 | + * Return number of clock cycles in a given period(ins ns). | |
| 84 | + */ | |
| 48 | 85 | static u32 pwm_omap_dmtimer_get_clock_cycles(unsigned long clk_rate, int ns) |
| 49 | 86 | { |
| 50 | 87 | return DIV_ROUND_CLOSEST_ULL((u64)clk_rate * ns, NSEC_PER_SEC); |
| 51 | 88 | } |
| 52 | 89 | |
| 90 | +/** | |
| 91 | + * pwm_omap_dmtimer_start() - Start the pwm omap dm timer in pwm mode | |
| 92 | + * @omap: Pointer to pwm omap dm timer chip | |
| 93 | + */ | |
| 53 | 94 | static void pwm_omap_dmtimer_start(struct pwm_omap_dmtimer_chip *omap) |
| 54 | 95 | { |
| 55 | 96 | /* |
| @@ -67,28 +108,46 @@ static void pwm_omap_dmtimer_start(struct pwm_omap_dmtimer_chip *omap) · 11 unmodified lines | ||
| 67 | 108 | omap->pdata->start(omap->dm_timer); |
| 68 | 109 | } |
| 69 | 110 | |
| 70 | −static int pwm_omap_dmtimer_enable(struct pwm_chip *chip, | |
| 71 | − struct pwm_device *pwm) | |
| 111 | +/** | |
| 112 | + * pwm_omap_dmtimer_is_enabled() - Detect if the pwm is enabled. | |
| 113 | + * @omap: Pointer to pwm omap dm timer chip | |
| 114 | + * | |
| 115 | + * Return true if pwm is enabled else false. | |
| 116 | + */ | |
| 117 | +static bool pwm_omap_dmtimer_is_enabled(struct pwm_omap_dmtimer_chip *omap) | |
| 72 | 118 | { |
| 73 | − struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip); | |
| 119 | + u32 status; | |
| 74 | 120 | |
| 75 | − mutex_lock(&omap->mutex); | |
| 76 | − pwm_omap_dmtimer_start(omap); | |
| 77 | − mutex_unlock(&omap->mutex); | |
| 121 | + status = omap->pdata->get_pwm_status(omap->dm_timer); | |
| 78 | 122 | |
| 79 | − return 0; | |
| 123 | + return !!(status & OMAP_TIMER_CTRL_ST); | |
| 80 | 124 | } |
| 81 | 125 | |
| 82 | −static void pwm_omap_dmtimer_disable(struct pwm_chip *chip, | |
| 83 | − struct pwm_device *pwm) | |
| 126 | +/** | |
| 127 | + * pwm_omap_dmtimer_polarity() - Detect the polarity of pwm. | |
| 128 | + * @omap: Pointer to pwm omap dm timer chip | |
| 129 | + * | |
| 130 | + * Return the polarity of pwm. | |
| 131 | + */ | |
| 132 | +static int pwm_omap_dmtimer_polarity(struct pwm_omap_dmtimer_chip *omap) | |
| 84 | 133 | { |
| 85 | − struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip); | |
| 134 | + u32 status; | |
| 86 | 135 | |
| 87 | − mutex_lock(&omap->mutex); | |
| 88 | − omap->pdata->stop(omap->dm_timer); | |
| 89 | − mutex_unlock(&omap->mutex); | |
| 136 | + status = omap->pdata->get_pwm_status(omap->dm_timer); | |
| 137 | + | |
| 138 | + return !!(status & OMAP_TIMER_CTRL_SCPWM); | |
| 90 | 139 | } |
| 91 | 140 | |
| 141 | +/** | |
| 142 | + * pwm_omap_dmtimer_config() - Update the configuration of pwm omap dm timer | |
| 143 | + * @chip: Pointer to PWM controller | |
| 144 | + * @pwm: Pointer to PWM channel | |
| 145 | + * @duty_ns: New duty cycle in nano seconds | |
| 146 | + * @period_ns: New period in nano seconds | |
| 147 | + * | |
| 148 | + * Return 0 if successfully changed the period/duty_cycle else appropriate | |
| 149 | + * error. | |
| 150 | + */ | |
| 92 | 151 | static int pwm_omap_dmtimer_config(struct pwm_chip *chip, |
| 93 | 152 | struct pwm_device *pwm, |
| 94 | 153 | int duty_ns, int period_ns) |
| @@ -96,31 +155,26 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip, · 1 unmodified line | ||
| 96 | 155 | struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip); |
| 97 | 156 | u32 period_cycles, duty_cycles; |
| 98 | 157 | u32 load_value, match_value; |
| 99 | − struct clk *fclk; | |
| 100 | 158 | unsigned long clk_rate; |
| 101 | − bool timer_active; | |
| 159 | + struct clk *fclk; | |
| 102 | 160 | |
| 103 | 161 | dev_dbg(chip->dev, "requested duty cycle: %d ns, period: %d ns\n", |
| 104 | 162 | duty_ns, period_ns); |
| 105 | 163 | |
| 106 | − mutex_lock(&omap->mutex); | |
| 107 | 164 | if (duty_ns == pwm_get_duty_cycle(pwm) && |
| 108 | − period_ns == pwm_get_period(pwm)) { | |
| 109 | − /* No change - don't cause any transients. */ | |
| 110 | − mutex_unlock(&omap->mutex); | |
| 165 | + period_ns == pwm_get_period(pwm)) | |
| 111 | 166 | return 0; |
| 112 | − } | |
| 113 | 167 | |
| 114 | 168 | fclk = omap->pdata->get_fclk(omap->dm_timer); |
| 115 | 169 | if (!fclk) { |
| 116 | 170 | dev_err(chip->dev, "invalid pmtimer fclk\n"); |
| 117 | − goto err_einval; | |
| 171 | + return -EINVAL; | |
| 118 | 172 | } |
| 119 | 173 | |
| 120 | 174 | clk_rate = clk_get_rate(fclk); |
| 121 | 175 | if (!clk_rate) { |
| 122 | 176 | dev_err(chip->dev, "invalid pmtimer fclk rate\n"); |
| 123 | − goto err_einval; | |
| 177 | + return -EINVAL; | |
| 124 | 178 | } |
| 125 | 179 | |
| 126 | 180 | dev_dbg(chip->dev, "clk rate: %luHz\n", clk_rate); |
| @@ -148,7 +202,7 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip, · 21 unmodified lines | ||
| 148 | 202 | dev_info(chip->dev, |
| 149 | 203 | "period %d ns too short for clock rate %lu Hz\n", |
| 150 | 204 | period_ns, clk_rate); |
| 151 | − goto err_einval; | |
| 205 | + return -EINVAL; | |
| 152 | 206 | } |
| 153 | 207 | |
| 154 | 208 | if (duty_cycles < 1) { |
| @@ -174,81 +228,103 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip, · 19 unmodified lines | ||
| 174 | 228 | load_value = (DM_TIMER_MAX - period_cycles) + 1; |
| 175 | 229 | match_value = load_value + duty_cycles - 1; |
| 176 | 230 | |
| 177 | − /* | |
| 178 | − * We MUST stop the associated dual-mode timer before attempting to | |
| 179 | − * write its registers, but calls to omap_dm_timer_start/stop must | |
| 180 | − * be balanced so check if timer is active before calling timer_stop. | |
| 181 | − */ | |
| 182 | − timer_active = pm_runtime_active(&omap->dm_timer_pdev->dev); | |
| 183 | − if (timer_active) | |
| 184 | − omap->pdata->stop(omap->dm_timer); | |
| 185 | − | |
| 186 | 231 | omap->pdata->set_load(omap->dm_timer, load_value); |
| 187 | 232 | omap->pdata->set_match(omap->dm_timer, true, match_value); |
| 188 | 233 | |
| 189 | 234 | dev_dbg(chip->dev, "load value: %#08x (%d), match value: %#08x (%d)\n", |
| 190 | 235 | load_value, load_value, match_value, match_value); |
| 191 | 236 | |
| 192 | − omap->pdata->set_pwm(omap->dm_timer, | |
| 193 | − pwm_get_polarity(pwm) == PWM_POLARITY_INVERSED, | |
| 194 | − true, | |
| 195 | − PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE, | |
| 196 | − true); | |
| 197 | − | |
| 198 | − /* If config was called while timer was running it must be reenabled. */ | |
| 199 | − if (timer_active) | |
| 200 | − pwm_omap_dmtimer_start(omap); | |
| 237 | + return 0; | |
| 238 | +} | |
| 201 | 239 | |
| 202 | − mutex_unlock(&omap->mutex); | |
| 240 | +/** | |
| 241 | + * pwm_omap_dmtimer_set_polarity() - Changes the polarity of the pwm dm timer. | |
| 242 | + * @chip: Pointer to PWM controller | |
| 243 | + * @pwm: Pointer to PWM channel | |
| 244 | + * @polarity: New pwm polarity to be set | |
| 245 | + */ | |
| 246 | +static void pwm_omap_dmtimer_set_polarity(struct pwm_chip *chip, | |
| 247 | + struct pwm_device *pwm, | |
| 248 | + enum pwm_polarity polarity) | |
| 249 | +{ | |
| 250 | + struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip); | |
| 251 | + bool enabled; | |
| 203 | 252 | |
| 204 | − return 0; | |
| 253 | + /* Disable the PWM before changing the polarity. */ | |
| 254 | + enabled = pwm_omap_dmtimer_is_enabled(omap); | |
| 255 | + if (enabled) | |
| 256 | + omap->pdata->stop(omap->dm_timer); | |
| 205 | 257 | |
| 206 | −err_einval: | |
| 207 | − mutex_unlock(&omap->mutex); | |
| 258 | + omap->pdata->set_pwm(omap->dm_timer, | |
| 259 | + polarity == PWM_POLARITY_INVERSED, | |
| 260 | + true, OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE, | |
| 261 | + true); | |
| 208 | 262 | |
| 209 | − return -EINVAL; | |
| 263 | + if (enabled) | |
| 264 | + pwm_omap_dmtimer_start(omap); | |
| 210 | 265 | } |
| 211 | 266 | |
| 212 | −static int pwm_omap_dmtimer_set_polarity(struct pwm_chip *chip, | |
| 213 | − struct pwm_device *pwm, | |
| 214 | − enum pwm_polarity polarity) | |
| 267 | +/** | |
| 268 | + * pwm_omap_dmtimer_apply() - Changes the state of the pwm omap dm timer. | |
| 269 | + * @chip: Pointer to PWM controller | |
| 270 | + * @pwm: Pointer to PWM channel | |
| 271 | + * @state: New state to apply | |
| 272 | + * | |
| 273 | + * Return 0 if successfully changed the state else appropriate error. | |
| 274 | + */ | |
| 275 | +static int pwm_omap_dmtimer_apply(struct pwm_chip *chip, | |
| 276 | + struct pwm_device *pwm, | |
| 277 | + const struct pwm_state *state) | |
| 215 | 278 | { |
| 216 | 279 | struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip); |
| 280 | + int ret = 0; | |
| 217 | 281 | |
| 218 | − /* | |
| 219 | − * PWM core will not call set_polarity while PWM is enabled so it's | |
| 220 | − * safe to reconfigure the timer here without stopping it first. | |
| 221 | − */ | |
| 222 | 282 | mutex_lock(&omap->mutex); |
| 223 | − omap->pdata->set_pwm(omap->dm_timer, | |
| 224 | − polarity == PWM_POLARITY_INVERSED, | |
| 225 | − true, | |
| 226 | − PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE, | |
| 227 | − true); | |
| 283 | + | |
| 284 | + if (pwm_omap_dmtimer_is_enabled(omap) && !state->enabled) { | |
| 285 | + omap->pdata->stop(omap->dm_timer); | |
| 286 | + goto unlock_mutex; | |
| 287 | + } | |
| 288 | + | |
| 289 | + if (pwm_omap_dmtimer_polarity(omap) != state->polarity) | |
| 290 | + pwm_omap_dmtimer_set_polarity(chip, pwm, state->polarity); | |
| 291 | + | |
| 292 | + ret = pwm_omap_dmtimer_config(chip, pwm, state->duty_cycle, | |
| 293 | + state->period); | |
| 294 | + if (ret) | |
| 295 | + goto unlock_mutex; | |
| 296 | + | |
| 297 | + if (!pwm_omap_dmtimer_is_enabled(omap) && state->enabled) { | |
| 298 | + omap->pdata->set_pwm(omap->dm_timer, | |
| 299 | + state->polarity == PWM_POLARITY_INVERSED, | |
| 300 | + true, | |
| 301 | + OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE, | |
| 302 | + true); | |
| 303 | + pwm_omap_dmtimer_start(omap); | |
| 304 | + } | |
| 305 | + | |
| 306 | +unlock_mutex: | |
| 228 | 307 | mutex_unlock(&omap->mutex); |
| 229 | 308 | |
| 230 | − return 0; | |
| 309 | + return ret; | |
| 231 | 310 | } |
| 232 | 311 | |
| 233 | 312 | static const struct pwm_ops pwm_omap_dmtimer_ops = { |
| 234 | − .enable = pwm_omap_dmtimer_enable, | |
| 235 | − .disable = pwm_omap_dmtimer_disable, | |
| 236 | − .config = pwm_omap_dmtimer_config, | |
| 237 | − .set_polarity = pwm_omap_dmtimer_set_polarity, | |
| 313 | + .apply = pwm_omap_dmtimer_apply, | |
| 238 | 314 | .owner = THIS_MODULE, |
| 239 | 315 | }; |
| 240 | 316 | |
| 241 | 317 | static int pwm_omap_dmtimer_probe(struct platform_device *pdev) |
| 242 | 318 | { |
| 243 | 319 | struct device_node *np = pdev->dev.of_node; |
| 244 | − struct device_node *timer; | |
| 245 | − struct platform_device *timer_pdev; | |
| 246 | − struct pwm_omap_dmtimer_chip *omap; | |
| 247 | 320 | struct dmtimer_platform_data *timer_pdata; |
| 248 | 321 | const struct omap_dm_timer_ops *pdata; |
| 249 | − pwm_omap_dmtimer *dm_timer; | |
| 250 | − u32 v; | |
| 322 | + struct platform_device *timer_pdev; | |
| 323 | + struct pwm_omap_dmtimer_chip *omap; | |
| 324 | + struct omap_dm_timer *dm_timer; | |
| 325 | + struct device_node *timer; | |
| 251 | 326 | int ret = 0; |
| 327 | + u32 v; | |
| 252 | 328 | |
| 253 | 329 | timer = of_parse_phandle(np, "ti,timers", 0); |
| 254 | 330 | if (!timer) |
| @@ -281,6 +357,7 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev) · 26 unmodified lines | ||
| 281 | 357 | !pdata->set_load || |
| 282 | 358 | !pdata->set_match || |
| 283 | 359 | !pdata->set_pwm || |
| 360 | + !pdata->get_pwm_status || | |
| 284 | 361 | !pdata->set_prescaler || |
| 285 | 362 | !pdata->write_counter) { |
| 286 | 363 | dev_err(&pdev->dev, "Incomplete dmtimer pdata structure\n"); |
| @@ -20,6 +20,7 @@ · 19 unmodified lines | ||
| 20 | 20 | #include <linux/slab.h> |
| 21 | 21 | #include <linux/delay.h> |
| 22 | 22 | #include <linux/pm_runtime.h> |
| 23 | +#include <linux/bitmap.h> | |
| 23 | 24 | |
| 24 | 25 | /* |
| 25 | 26 | * Because the PCA9685 has only one prescaler per chip, changing the period of |
| @@ -69,11 +70,11 @@ · 43 unmodified lines | ||
| 69 | 70 | struct pca9685 { |
| 70 | 71 | struct pwm_chip chip; |
| 71 | 72 | struct regmap *regmap; |
| 72 | − int duty_ns; | |
| 73 | 73 | int period_ns; |
| 74 | 74 | #if IS_ENABLED(CONFIG_GPIOLIB) |
| 75 | 75 | struct mutex lock; |
| 76 | 76 | struct gpio_chip gpio; |
| 77 | + DECLARE_BITMAP(pwms_inuse, PCA9685_MAXCHAN + 1); | |
| 77 | 78 | #endif |
| 78 | 79 | }; |
| 79 | 80 | |
| @@ -83,51 +84,51 @@ static inline struct pca9685 *to_pca(struct pwm_chip *chip) · 3 unmodified lines | ||
| 83 | 84 | } |
| 84 | 85 | |
| 85 | 86 | #if IS_ENABLED(CONFIG_GPIOLIB) |
| 86 | −static int pca9685_pwm_gpio_request(struct gpio_chip *gpio, unsigned int offset) | |
| 87 | +static bool pca9685_pwm_test_and_set_inuse(struct pca9685 *pca, int pwm_idx) | |
| 87 | 88 | { |
| 88 | − struct pca9685 *pca = gpiochip_get_data(gpio); | |
| 89 | − struct pwm_device *pwm; | |
| 89 | + bool is_inuse; | |
| 90 | 90 | |
| 91 | 91 | mutex_lock(&pca->lock); |
| 92 | − | |
| 93 | − pwm = &pca->chip.pwms[offset]; | |
| 94 | − | |
| 95 | − if (pwm->flags & (PWMF_REQUESTED | PWMF_EXPORTED)) { | |
| 96 | − mutex_unlock(&pca->lock); | |
| 97 | − return -EBUSY; | |
| 92 | + if (pwm_idx >= PCA9685_MAXCHAN) { | |
| 93 | + /* | |
| 94 | + * "all LEDs" channel: | |
| 95 | + * pretend already in use if any of the PWMs are requested | |
| 96 | + */ | |
| 97 | + if (!bitmap_empty(pca->pwms_inuse, PCA9685_MAXCHAN)) { | |
| 98 | + is_inuse = true; | |
| 99 | + goto out; | |
| 100 | + } | |
| 101 | + } else { | |
| 102 | + /* | |
| 103 | + * regular channel: | |
| 104 | + * pretend already in use if the "all LEDs" channel is requested | |
| 105 | + */ | |
| 106 | + if (test_bit(PCA9685_MAXCHAN, pca->pwms_inuse)) { | |
| 107 | + is_inuse = true; | |
| 108 | + goto out; | |
| 109 | + } | |
| 98 | 110 | } |
| 99 | − | |
| 100 | − pwm_set_chip_data(pwm, (void *)1); | |
| 101 | − | |
| 111 | + is_inuse = test_and_set_bit(pwm_idx, pca->pwms_inuse); | |
| 112 | +out: | |
| 102 | 113 | mutex_unlock(&pca->lock); |
| 103 | − pm_runtime_get_sync(pca->chip.dev); | |
| 104 | − return 0; | |
| 114 | + return is_inuse; | |
| 105 | 115 | } |
| 106 | 116 | |
| 107 | −static bool pca9685_pwm_is_gpio(struct pca9685 *pca, struct pwm_device *pwm) | |
| 117 | +static void pca9685_pwm_clear_inuse(struct pca9685 *pca, int pwm_idx) | |
| 108 | 118 | { |
| 109 | − bool is_gpio = false; | |
| 110 | − | |
| 111 | 119 | mutex_lock(&pca->lock); |
| 120 | + clear_bit(pwm_idx, pca->pwms_inuse); | |
| 121 | + mutex_unlock(&pca->lock); | |
| 122 | +} | |
| 112 | 123 | |
| 113 | − if (pwm->hwpwm >= PCA9685_MAXCHAN) { | |
| 114 | − unsigned int i; | |
| 115 | − | |
| 116 | − /* | |
| 117 | − * Check if any of the GPIOs are requested and in that case | |
| 118 | − * prevent using the "all LEDs" channel. | |
| 119 | − */ | |
| 120 | − for (i = 0; i < pca->gpio.ngpio; i++) | |
| 121 | − if (gpiochip_is_requested(&pca->gpio, i)) { | |
| 122 | − is_gpio = true; | |
| 123 | − break; | |
| 124 | − } | |
| 125 | − } else if (pwm_get_chip_data(pwm)) { | |
| 126 | − is_gpio = true; | |
| 127 | − } | |
| 124 | +static int pca9685_pwm_gpio_request(struct gpio_chip *gpio, unsigned int offset) | |
| 125 | +{ | |
| 126 | + struct pca9685 *pca = gpiochip_get_data(gpio); | |
| 128 | 127 | |
| 129 | − mutex_unlock(&pca->lock); | |
| 130 | − return is_gpio; | |
| 128 | + if (pca9685_pwm_test_and_set_inuse(pca, offset)) | |
| 129 | + return -EBUSY; | |
| 130 | + pm_runtime_get_sync(pca->chip.dev); | |
| 131 | + return 0; | |
| 131 | 132 | } |
| 132 | 133 | |
| 133 | 134 | static int pca9685_pwm_gpio_get(struct gpio_chip *gpio, unsigned int offset) |
| @@ -162,13 +163,14 @@ static void pca9685_pwm_gpio_free(struct gpio_chip *gpio, unsigned int offset) · 28 unmodified lines | ||
| 162 | 163 | |
| 163 | 164 | pca9685_pwm_gpio_set(gpio, offset, 0); |
| 164 | 165 | pm_runtime_put(pca->chip.dev); |
| 166 | + pca9685_pwm_clear_inuse(pca, offset); | |
| 165 | 167 | } |
| 166 | 168 | |
| 167 | 169 | static int pca9685_pwm_gpio_get_direction(struct gpio_chip *chip, |
| 168 | 170 | unsigned int offset) |
| 169 | 171 | { |
| 170 | 172 | /* Always out */ |
| 171 | − return 0; | |
| 173 | + return GPIO_LINE_DIRECTION_OUT; | |
| 172 | 174 | } |
| 173 | 175 | |
| 174 | 176 | static int pca9685_pwm_gpio_direction_input(struct gpio_chip *gpio, |
| @@ -213,12 +215,17 @@ static int pca9685_pwm_gpio_probe(struct pca9685 *pca) · 38 unmodified lines | ||
| 213 | 215 | return devm_gpiochip_add_data(dev, &pca->gpio, pca); |
| 214 | 216 | } |
| 215 | 217 | #else |
| 216 | −static inline bool pca9685_pwm_is_gpio(struct pca9685 *pca, | |
| 217 | − struct pwm_device *pwm) | |
| 218 | +static inline bool pca9685_pwm_test_and_set_inuse(struct pca9685 *pca, | |
| 219 | + int pwm_idx) | |
| 218 | 220 | { |
| 219 | 221 | return false; |
| 220 | 222 | } |
| 221 | 223 | |
| 224 | +static inline void | |
| 225 | +pca9685_pwm_clear_inuse(struct pca9685 *pca, int pwm_idx) | |
| 226 | +{ | |
| 227 | +} | |
| 228 | + | |
| 222 | 229 | static inline int pca9685_pwm_gpio_probe(struct pca9685 *pca) |
| 223 | 230 | { |
| 224 | 231 | return 0; |
| @@ -272,8 +279,6 @@ static int pca9685_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, · 47 unmodified lines | ||
| 272 | 279 | } |
| 273 | 280 | } |
| 274 | 281 | |
| 275 | − pca->duty_ns = duty_ns; | |
| 276 | − | |
| 277 | 282 | if (duty_ns < 1) { |
| 278 | 283 | if (pwm->hwpwm >= PCA9685_MAXCHAN) |
| 279 | 284 | reg = PCA9685_ALL_LED_OFF_H; |
| @@ -402,7 +407,7 @@ static int pca9685_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) · 122 unmodified lines | ||
| 402 | 407 | { |
| 403 | 408 | struct pca9685 *pca = to_pca(chip); |
| 404 | 409 | |
| 405 | − if (pca9685_pwm_is_gpio(pca, pwm)) | |
| 410 | + if (pca9685_pwm_test_and_set_inuse(pca, pwm->hwpwm)) | |
| 406 | 411 | return -EBUSY; |
| 407 | 412 | pm_runtime_get_sync(chip->dev); |
| 408 | 413 | |
| @@ -411,8 +416,11 @@ static int pca9685_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) · 2 unmodified lines | ||
| 411 | 416 | |
| 412 | 417 | static void pca9685_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) |
| 413 | 418 | { |
| 419 | + struct pca9685 *pca = to_pca(chip); | |
| 420 | + | |
| 414 | 421 | pca9685_pwm_disable(chip, pwm); |
| 415 | 422 | pm_runtime_put(chip->dev); |
| 423 | + pca9685_pwm_clear_inuse(pca, pwm->hwpwm); | |
| 416 | 424 | } |
| 417 | 425 | |
| 418 | 426 | static const struct pwm_ops pca9685_pwm_ops = { |
| @@ -449,7 +457,6 @@ static int pca9685_pwm_probe(struct i2c_client *client, · 30 unmodified lines | ||
| 449 | 457 | ret); |
| 450 | 458 | return ret; |
| 451 | 459 | } |
| 452 | − pca->duty_ns = 0; | |
| 453 | 460 | pca->period_ns = PCA9685_DEFAULT_PERIOD; |
| 454 | 461 | |
| 455 | 462 | i2c_set_clientdata(client, pca); |
| @@ -512,8 +519,7 @@ static int pca9685_pwm_remove(struct i2c_client *client) · 56 unmodified lines | ||
| 512 | 519 | return 0; |
| 513 | 520 | } |
| 514 | 521 | |
| 515 | −#ifdef CONFIG_PM | |
| 516 | −static int pca9685_pwm_runtime_suspend(struct device *dev) | |
| 522 | +static int __maybe_unused pca9685_pwm_runtime_suspend(struct device *dev) | |
| 517 | 523 | { |
| 518 | 524 | struct i2c_client *client = to_i2c_client(dev); |
| 519 | 525 | struct pca9685 *pca = i2c_get_clientdata(client); |
| @@ -522,7 +528,7 @@ static int pca9685_pwm_runtime_suspend(struct device *dev) · 2 unmodified lines | ||
| 522 | 528 | return 0; |
| 523 | 529 | } |
| 524 | 530 | |
| 525 | −static int pca9685_pwm_runtime_resume(struct device *dev) | |
| 531 | +static int __maybe_unused pca9685_pwm_runtime_resume(struct device *dev) | |
| 526 | 532 | { |
| 527 | 533 | struct i2c_client *client = to_i2c_client(dev); |
| 528 | 534 | struct pca9685 *pca = i2c_get_clientdata(client); |
| @@ -530,7 +536,6 @@ static int pca9685_pwm_runtime_resume(struct device *dev) · 1 unmodified line | ||
| 530 | 536 | pca9685_set_sleep_mode(pca, false); |
| 531 | 537 | return 0; |
| 532 | 538 | } |
| 533 | −#endif | |
| 534 | 539 | |
| 535 | 540 | static const struct i2c_device_id pca9685_id[] = { |
| 536 | 541 | { "pca9685", 0 }, |
| @@ -229,24 +229,28 @@ static int rcar_pwm_probe(struct platform_device *pdev) · 228 unmodified lines | ||
| 229 | 229 | rcar_pwm->chip.base = -1; |
| 230 | 230 | rcar_pwm->chip.npwm = 1; |
| 231 | 231 | |
| 232 | + pm_runtime_enable(&pdev->dev); | |
| 233 | + | |
| 232 | 234 | ret = pwmchip_add(&rcar_pwm->chip); |
| 233 | 235 | if (ret < 0) { |
| 234 | 236 | dev_err(&pdev->dev, "failed to register PWM chip: %d\n", ret); |
| 237 | + pm_runtime_disable(&pdev->dev); | |
| 235 | 238 | return ret; |
| 236 | 239 | } |
| 237 | 240 | |
| 238 | − pm_runtime_enable(&pdev->dev); | |
| 239 | − | |
| 240 | 241 | return 0; |
| 241 | 242 | } |
| 242 | 243 | |
| 243 | 244 | static int rcar_pwm_remove(struct platform_device *pdev) |
| 244 | 245 | { |
| 245 | 246 | struct rcar_pwm_chip *rcar_pwm = platform_get_drvdata(pdev); |
| 247 | + int ret; | |
| 248 | + | |
| 249 | + ret = pwmchip_remove(&rcar_pwm->chip); | |
| 246 | 250 | |
| 247 | 251 | pm_runtime_disable(&pdev->dev); |
| 248 | 252 | |
| 249 | − return pwmchip_remove(&rcar_pwm->chip); | |
| 253 | + return ret; | |
| 250 | 254 | } |
| 251 | 255 | |
| 252 | 256 | static const struct of_device_id rcar_pwm_of_table[] = { |
| @@ -415,16 +415,15 @@ static int tpu_probe(struct platform_device *pdev) · 414 unmodified lines | ||
| 415 | 415 | tpu->chip.base = -1; |
| 416 | 416 | tpu->chip.npwm = TPU_CHANNEL_MAX; |
| 417 | 417 | |
| 418 | + pm_runtime_enable(&pdev->dev); | |
| 419 | + | |
| 418 | 420 | ret = pwmchip_add(&tpu->chip); |
| 419 | 421 | if (ret < 0) { |
| 420 | 422 | dev_err(&pdev->dev, "failed to register PWM chip\n"); |
| 423 | + pm_runtime_disable(&pdev->dev); | |
| 421 | 424 | return ret; |
| 422 | 425 | } |
| 423 | 426 | |
| 424 | − dev_info(&pdev->dev, "TPU PWM %d registered\n", tpu->pdev->id); | |
| 425 | − | |
| 426 | − pm_runtime_enable(&pdev->dev); | |
| 427 | − | |
| 428 | 427 | return 0; |
| 429 | 428 | } |
| 430 | 429 | |
| @@ -434,12 +433,10 @@ static int tpu_remove(struct platform_device *pdev) · 3 unmodified lines | ||
| 434 | 433 | int ret; |
| 435 | 434 | |
| 436 | 435 | ret = pwmchip_remove(&tpu->chip); |
| 437 | − if (ret) | |
| 438 | − return ret; | |
| 439 | 436 | |
| 440 | 437 | pm_runtime_disable(&pdev->dev); |
| 441 | 438 | |
| 442 | − return 0; | |
| 439 | + return ret; | |
| 443 | 440 | } |
| 444 | 441 | |
| 445 | 442 | #ifdef CONFIG_OF |
| @@ -90,7 +90,6 @@ struct sun4i_pwm_chip { · 89 unmodified lines | ||
| 90 | 90 | spinlock_t ctrl_lock; |
| 91 | 91 | const struct sun4i_pwm_data *data; |
| 92 | 92 | unsigned long next_period[2]; |
| 93 | − bool needs_delay[2]; | |
| 94 | 93 | }; |
| 95 | 94 | |
| 96 | 95 | static inline struct sun4i_pwm_chip *to_sun4i_pwm_chip(struct pwm_chip *chip) |
| @@ -287,7 +286,6 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, · 190 unmodified lines | ||
| 287 | 286 | sun4i_pwm_writel(sun4i_pwm, val, PWM_CH_PRD(pwm->hwpwm)); |
| 288 | 287 | sun4i_pwm->next_period[pwm->hwpwm] = jiffies + |
| 289 | 288 | usecs_to_jiffies(cstate.period / 1000 + 1); |
| 290 | − sun4i_pwm->needs_delay[pwm->hwpwm] = true; | |
| 291 | 289 | |
| 292 | 290 | if (state->polarity != PWM_POLARITY_NORMAL) |
| 293 | 291 | ctrl &= ~BIT_CH(PWM_ACT_STATE, pwm->hwpwm); |
| @@ -298,7 +296,7 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, · 4 unmodified lines | ||
| 298 | 296 | |
| 299 | 297 | if (state->enabled) { |
| 300 | 298 | ctrl |= BIT_CH(PWM_EN, pwm->hwpwm); |
| 301 | − } else if (!sun4i_pwm->needs_delay[pwm->hwpwm]) { | |
| 299 | + } else { | |
| 302 | 300 | ctrl &= ~BIT_CH(PWM_EN, pwm->hwpwm); |
| 303 | 301 | ctrl &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm); |
| 304 | 302 | } |
| @@ -310,15 +308,9 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, · 5 unmodified lines | ||
| 310 | 308 | if (state->enabled) |
| 311 | 309 | return 0; |
| 312 | 310 | |
| 313 | − if (!sun4i_pwm->needs_delay[pwm->hwpwm]) { | |
| 314 | − clk_disable_unprepare(sun4i_pwm->clk); | |
| 315 | − return 0; | |
| 316 | − } | |
| 317 | − | |
| 318 | 311 | /* We need a full period to elapse before disabling the channel. */ |
| 319 | 312 | now = jiffies; |
| 320 | − if (sun4i_pwm->needs_delay[pwm->hwpwm] && | |
| 321 | − time_before(now, sun4i_pwm->next_period[pwm->hwpwm])) { | |
| 313 | + if (time_before(now, sun4i_pwm->next_period[pwm->hwpwm])) { | |
| 322 | 314 | delay_us = jiffies_to_usecs(sun4i_pwm->next_period[pwm->hwpwm] - |
| 323 | 315 | now); |
| 324 | 316 | if ((delay_us / 500) > MAX_UDELAY_MS) |
| @@ -326,7 +318,6 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, · 1 unmodified line | ||
| 326 | 318 | else |
| 327 | 319 | usleep_range(delay_us, delay_us * 2); |
| 328 | 320 | } |
| 329 | − sun4i_pwm->needs_delay[pwm->hwpwm] = false; | |
| 330 | 321 | |
| 331 | 322 | spin_lock(&sun4i_pwm->ctrl_lock); |
| 332 | 323 | ctrl = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG); |
| @@ -282,9 +282,15 @@ static const struct tegra_pwm_soc tegra186_pwm_soc = { · 281 unmodified lines | ||
| 282 | 282 | .max_frequency = 102000000UL, |
| 283 | 283 | }; |
| 284 | 284 | |
| 285 | +static const struct tegra_pwm_soc tegra194_pwm_soc = { | |
| 286 | + .num_channels = 1, | |
| 287 | + .max_frequency = 408000000UL, | |
| 288 | +}; | |
| 289 | + | |
| 285 | 290 | static const struct of_device_id tegra_pwm_of_match[] = { |
| 286 | 291 | { .compatible = "nvidia,tegra20-pwm", .data = &tegra20_pwm_soc }, |
| 287 | 292 | { .compatible = "nvidia,tegra186-pwm", .data = &tegra186_pwm_soc }, |
| 293 | + { .compatible = "nvidia,tegra194-pwm", .data = &tegra194_pwm_soc }, | |
| 288 | 294 | { } |
| 289 | 295 | }; |
| 290 | 296 | MODULE_DEVICE_TABLE(of, tegra_pwm_of_match); |
| @@ -248,8 +248,7 @@ int omap_dm_timers_active(void); · 247 unmodified lines | ||
| 248 | 248 | |
| 249 | 249 | /* |
| 250 | 250 | * The below are inlined to optimize code size for system timers. Other code |
| 251 | − * should not need these at all, see | |
| 252 | − * include/linux/platform_data/pwm_omap_dmtimer.h | |
| 251 | + * should not need these at all. | |
| 253 | 252 | */ |
| 254 | 253 | #if defined(CONFIG_ARCH_OMAP1) || defined(CONFIG_ARCH_OMAP2PLUS) |
| 255 | 254 | static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg, |
| @@ -1,90 +0,0 @@ | ||
| 1 | −/* | |
| 2 | − * include/linux/platform_data/pwm_omap_dmtimer.h | |
| 3 | − * | |
| 4 | − * OMAP Dual-Mode Timer PWM platform data | |
| 5 | − * | |
| 6 | − * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ | |
| 7 | − * Tarun Kanti DebBarma <tarun.kanti@ti.com> | |
| 8 | − * Thara Gopinath <thara@ti.com> | |
| 9 | − * | |
| 10 | − * Platform device conversion and hwmod support. | |
| 11 | − * | |
| 12 | − * Copyright (C) 2005 Nokia Corporation | |
| 13 | − * Author: Lauri Leukkunen <lauri.leukkunen@nokia.com> | |
| 14 | − * PWM and clock framework support by Timo Teras. | |
| 15 | − * | |
| 16 | − * This program is free software; you can redistribute it and/or modify it | |
| 17 | − * under the terms of the GNU General Public License as published by the | |
| 18 | − * Free Software Foundation; either version 2 of the License, or (at your | |
| 19 | − * option) any later version. | |
| 20 | − * | |
| 21 | − * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
| 22 | − * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
| 23 | − * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | |
| 24 | − * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| 25 | − * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
| 26 | − * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 27 | − * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
| 28 | − * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 29 | − * | |
| 30 | − * You should have received a copy of the GNU General Public License along | |
| 31 | − * with this program; if not, write to the Free Software Foundation, Inc., | |
| 32 | − * 675 Mass Ave, Cambridge, MA 02139, USA. | |
| 33 | − */ | |
| 34 | − | |
| 35 | −#ifndef __PWM_OMAP_DMTIMER_PDATA_H | |
| 36 | −#define __PWM_OMAP_DMTIMER_PDATA_H | |
| 37 | − | |
| 38 | −/* clock sources */ | |
| 39 | −#define PWM_OMAP_DMTIMER_SRC_SYS_CLK 0x00 | |
| 40 | −#define PWM_OMAP_DMTIMER_SRC_32_KHZ 0x01 | |
| 41 | −#define PWM_OMAP_DMTIMER_SRC_EXT_CLK 0x02 | |
| 42 | − | |
| 43 | −/* timer interrupt enable bits */ | |
| 44 | −#define PWM_OMAP_DMTIMER_INT_CAPTURE (1 << 2) | |
| 45 | −#define PWM_OMAP_DMTIMER_INT_OVERFLOW (1 << 1) | |
| 46 | −#define PWM_OMAP_DMTIMER_INT_MATCH (1 << 0) | |
| 47 | − | |
| 48 | −/* trigger types */ | |
| 49 | −#define PWM_OMAP_DMTIMER_TRIGGER_NONE 0x00 | |
| 50 | −#define PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW 0x01 | |
| 51 | −#define PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE 0x02 | |
| 52 | − | |
| 53 | −struct omap_dm_timer; | |
| 54 | −typedef struct omap_dm_timer pwm_omap_dmtimer; | |
| 55 | − | |
| 56 | −struct pwm_omap_dmtimer_pdata { | |
| 57 | − pwm_omap_dmtimer *(*request_by_node)(struct device_node *np); | |
| 58 | − pwm_omap_dmtimer *(*request_specific)(int timer_id); | |
| 59 | − pwm_omap_dmtimer *(*request)(void); | |
| 60 | − | |
| 61 | − int (*free)(pwm_omap_dmtimer *timer); | |
| 62 | − | |
| 63 | − void (*enable)(pwm_omap_dmtimer *timer); | |
| 64 | − void (*disable)(pwm_omap_dmtimer *timer); | |
| 65 | − | |
| 66 | − int (*get_irq)(pwm_omap_dmtimer *timer); | |
| 67 | − int (*set_int_enable)(pwm_omap_dmtimer *timer, unsigned int value); | |
| 68 | − int (*set_int_disable)(pwm_omap_dmtimer *timer, u32 mask); | |
| 69 | − | |
| 70 | − struct clk *(*get_fclk)(pwm_omap_dmtimer *timer); | |
| 71 | − | |
| 72 | − int (*start)(pwm_omap_dmtimer *timer); | |
| 73 | − int (*stop)(pwm_omap_dmtimer *timer); | |
| 74 | − int (*set_source)(pwm_omap_dmtimer *timer, int source); | |
| 75 | − | |
| 76 | − int (*set_load)(pwm_omap_dmtimer *timer, int autoreload, | |
| 77 | − unsigned int value); | |
| 78 | − int (*set_match)(pwm_omap_dmtimer *timer, int enable, | |
| 79 | − unsigned int match); | |
| 80 | − int (*set_pwm)(pwm_omap_dmtimer *timer, int def_on, | |
| 81 | − int toggle, int trigger); | |
| 82 | − int (*set_prescaler)(pwm_omap_dmtimer *timer, int prescaler); | |
| 83 | − | |
| 84 | − unsigned int (*read_counter)(pwm_omap_dmtimer *timer); | |
| 85 | − int (*write_counter)(pwm_omap_dmtimer *timer, unsigned int value); | |
| 86 | − unsigned int (*read_status)(pwm_omap_dmtimer *timer); | |
| 87 | − int (*write_status)(pwm_omap_dmtimer *timer, unsigned int value); | |
| 88 | −}; | |
| 89 | − | |
| 90 | −#endif /* __PWM_OMAP_DMTIMER_PDATA_H */ | |
| @@ -71,7 +71,8 @@ struct pwm_state { · 70 unmodified lines | ||
| 71 | 71 | * @chip: PWM chip providing this PWM device |
| 72 | 72 | * @chip_data: chip-private data associated with the PWM device |
| 73 | 73 | * @args: PWM arguments |
| 74 | − * @state: curent PWM channel state | |
| 74 | + * @state: last applied state | |
| 75 | + * @last: last implemented state (for PWM_DEBUG) | |
| 75 | 76 | */ |
| 76 | 77 | struct pwm_device { |
| 77 | 78 | const char *label; |
| @@ -83,6 +84,7 @@ struct pwm_device { · 5 unmodified lines | ||
| 83 | 84 | |
| 84 | 85 | struct pwm_args args; |
| 85 | 86 | struct pwm_state state; |
| 87 | + struct pwm_state last; | |
| 86 | 88 | }; |
| 87 | 89 | |
| 88 | 90 | /** |