pwm: Changes for v6.8-rc1

This contains a bunch of cleanups and simplifications across the board,
 as well as a number of small fixes.
 
 Perhaps the most notable change here is the addition of an API that
 allows PWMs to be used in atomic contexts, which is useful when time-
 critical operations are involved, such as using a PWM to generate IR
 signals.
 
 Finally, I have decided to step down as PWM subsystem maintainer. Due to
 other responsibilities I have lately not been able to find the time that
 the subsystem deserves and Uwe, who has been helping out a lot for the
 past few years and has many things planned for the future, has kindly
 volunteered to take over. I have no doubt that he will be a suitable
 replacement.
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCAA3FiEEiOrDCAFJzPfAjcif3SOs138+s6EFAmWhYQAZHHRoaWVycnku
 cmVkaW5nQGdtYWlsLmNvbQAKCRDdI6zXfz6zobK8EACtzJX+AeoTkN2S671A7QoG
 IGl9mrFhvrqN/6syigAIU8ZGOgb5uScZDH58PeTXH/oGEMn+bhQ9MK7JyWF5BUzF
 I8p6CqaVjG66LsfWz1m8AEAl/0N2Sc2032fWQSJB0o8qgYH0ZRBKc1j371Zm2DgD
 HT78pZJDSnyCnltPKjbDLShRfBwGINspmbihZKFa6yxrPbvADixCTo19b9Pk8XGa
 S9k2R/9S/QKPxvB+3DiZAHFstwoTn2p+1IBsg+hp/jLniw8XidZp2Rq0RJuwTjqO
 jVQDnOFOqNBa3VQccvNe23rDaKUkrmYwk+zzuFF27URam2Gp9wHZ8Y86WPSO5TA9
 ftNsoeW++R25PBsOVZFGMU9r9aI9XI1tNyVuv2blNc0yr1fNSRzwjcELzLzG2myp
 gHgdayJofnvlKM7JV5ZDY6BDPwTP9jfDRdZOqKKNUeB8e9IiQD9JtAV9P+EL/5Hl
 C+7mh5Xb17bVlczWHqNkTd89Omp+Eu2z5BMfJyiQWQ2lzZpxOkBwB0nrlPshZpPi
 hz5IhsGjREkEfNV2qz/YDEyaj+CAYO8toitFGt5HeAYTftuG4WD49rHE5VQ8nhwg
 P9XpWNFHK2EtpU3/BRuupWHZRVd7MU4kMx4WQvWZGOFEqc9DYaC29ynk6sK0ryaC
 ba8U4gpBS66d3wNvVpkN3A==
 =pIh8
 -----END PGP SIGNATURE-----

Merge tag 'pwm/for-6.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm

Pull pwm updates from Thierry Reding:
 "This contains a bunch of cleanups and simplifications across the
  board, as well as a number of small fixes.

  Perhaps the most notable change here is the addition of an API that
  allows PWMs to be used in atomic contexts, which is useful when time-
  critical operations are involved, such as using a PWM to generate IR
  signals.

  Finally, I have decided to step down as PWM subsystem maintainer. Due
  to other responsibilities I have lately not been able to find the time
  that the subsystem deserves and Uwe, who has been helping out a lot
  for the past few years and has many things planned for the future, has
  kindly volunteered to take over. I have no doubt that he will be a
  suitable replacement"

* tag 'pwm/for-6.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm: (44 commits)
  MAINTAINERS: pwm: Thierry steps down, Uwe takes over
  pwm: linux/pwm.h: fix Excess kernel-doc description warning
  pwm: Add pwm_apply_state() compatibility stub
  pwm: cros-ec: Drop documentation for dropped struct member
  pwm: Drop two unused API functions
  pwm: lpc18xx-sct: Don't modify the cached period of other PWM outputs
  pwm: meson: Simplify using dev_err_probe()
  pwm: stmpe: Silence duplicate error messages
  pwm: Reduce number of pointer dereferences in pwm_device_request()
  pwm: crc: Use consistent variable naming for driver data
  pwm: omap-dmtimer: Drop locking
  dt-bindings: pwm: ti,pwm-omap-dmtimer: Update binding for yaml
  media: pwm-ir-tx: Trigger edges from hrtimer interrupt context
  pwm: bcm2835: Allow PWM driver to be used in atomic context
  pwm: Make it possible to apply PWM changes in atomic context
  pwm: renesas: Remove unused include
  pwm: Replace ENOTSUPP with EOPNOTSUPP
  pwm: Rename pwm_apply_state() to pwm_apply_might_sleep()
  pwm: Stop referencing pwm->chip
  pwm: Update kernel doc for struct pwm_chip
  ...
This commit is contained in:
Linus Torvalds 2024-01-12 14:59:50 -08:00
commit 42bff4d0f9
53 changed files with 517 additions and 365 deletions

View File

@ -8,7 +8,6 @@ title: MediaTek DISP_PWM Controller
maintainers:
- Jitao Shi <jitao.shi@mediatek.com>
- Xinlei Lee <xinlei.lee@mediatek.com>
allOf:
- $ref: pwm.yaml#

View File

@ -1,22 +0,0 @@
* OMAP PWM for dual-mode timers
Required properties:
- compatible: Shall contain "ti,omap-dmtimer-pwm".
- ti,timers: phandle to PWM capable OMAP timer. See timer/ti,timer-dm.yaml for info
about these timers.
- #pwm-cells: Should be 3. See pwm.yaml in this directory for a description of
the cells format.
Optional properties:
- ti,prescaler: Should be a value between 0 and 7, see the timers datasheet
- ti,clock-source: Set dmtimer parent clock, values between 0 and 2:
- 0x00 - high-frequency system clock (timer_sys_ck)
- 0x01 - 32-kHz always-on clock (timer_32k_ck)
- 0x02 - external clock (timer_ext_ck, OMAP2 only)
Example:
pwm9: dmtimer-pwm@9 {
compatible = "ti,omap-dmtimer-pwm";
ti,timers = <&timer9>;
#pwm-cells = <3>;
};

View File

@ -0,0 +1,59 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/pwm/ti,omap-dmtimer-pwm.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: TI dual mode timer PWM controller
maintainers:
- Tony Lindgren <tony@atomide.com>
description:
TI dual mode timer instances have an IO pin for PWM capability
allOf:
- $ref: pwm.yaml#
properties:
compatible:
const: ti,omap-dmtimer-pwm
"#pwm-cells":
const: 3
ti,timers:
description: Timer instance phandle for the PWM
$ref: /schemas/types.yaml#/definitions/phandle
ti,prescaler:
description: |
Legacy clock prescaler for timer. The timer counter is prescaled
with 2^n where n is the prescaler.
$ref: /schemas/types.yaml#/definitions/uint32
enum: [ 0, 1, 2, 3, 4, 5, 6, 7 ]
deprecated: true
ti,clock-source:
description: |
Legacy clock for timer, please use assigned-clocks instead.
0x00 - high-frequency system clock (timer_sys_ck)
0x01 - 32-kHz always-on clock (timer_32k_ck)
0x02 - external clock (timer_ext_ck, OMAP2 only)
$ref: /schemas/types.yaml#/definitions/uint32
enum: [ 0, 1, 2 ]
deprecated: true
required:
- compatible
- ti,timers
unevaluatedProperties: false
examples:
- |
pwm9: pwm {
compatible = "ti,omap-dmtimer-pwm";
ti,timers = <&timer9>;
#pwm-cells = <3>;
};

View File

@ -41,11 +41,20 @@ the getter, devm_pwm_get() and devm_fwnode_pwm_get(), also exist.
After being requested, a PWM has to be configured using::
int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state);
int pwm_apply_might_sleep(struct pwm_device *pwm, struct pwm_state *state);
This API controls both the PWM period/duty_cycle config and the
enable/disable state.
PWM devices can be used from atomic context, if the PWM does not sleep. You
can check if this the case with::
bool pwm_might_sleep(struct pwm_device *pwm);
If false, the PWM can also be configured from atomic context with::
int pwm_apply_atomic(struct pwm_device *pwm, struct pwm_state *state);
As a consumer, don't rely on the output's state for a disabled PWM. If it's
easily possible, drivers are supposed to emit the inactive state, but some
drivers cannot. If you rely on getting the inactive state, use .duty_cycle=0,
@ -57,13 +66,13 @@ If supported by the driver, the signal can be optimized, for example to improve
EMI by phase shifting the individual channels of a chip.
The pwm_config(), pwm_enable() and pwm_disable() functions are just wrappers
around pwm_apply_state() and should not be used if the user wants to change
around pwm_apply_might_sleep() and should not be used if the user wants to change
several parameter at once. For example, if you see pwm_config() and
pwm_{enable,disable}() calls in the same function, this probably means you
should switch to pwm_apply_state().
should switch to pwm_apply_might_sleep().
The PWM user API also allows one to query the PWM state that was passed to the
last invocation of pwm_apply_state() using pwm_get_state(). Note this is
last invocation of pwm_apply_might_sleep() using pwm_get_state(). Note this is
different to what the driver has actually implemented if the request cannot be
satisfied exactly with the hardware in use. There is currently no way for
consumers to get the actually implemented settings.

View File

@ -17645,12 +17645,11 @@ F: Documentation/devicetree/bindings/leds/irled/pwm-ir-tx.yaml
F: drivers/media/rc/pwm-ir-tx.c
PWM SUBSYSTEM
M: Thierry Reding <thierry.reding@gmail.com>
R: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
M: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
L: linux-pwm@vger.kernel.org
S: Maintained
Q: https://patchwork.ozlabs.org/project/linux-pwm/list/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm.git
T: git https://git.kernel.org/pub/scm/linux/kernel/git/ukleinek/linux.git
F: Documentation/devicetree/bindings/gpio/gpio-mvebu.yaml
F: Documentation/devicetree/bindings/pwm/
F: Documentation/driver-api/pwm.rst
@ -17660,7 +17659,7 @@ F: drivers/video/backlight/pwm_bl.c
F: include/dt-bindings/pwm/
F: include/linux/pwm.h
F: include/linux/pwm_backlight.h
K: pwm_(config|apply_state|ops)
K: pwm_(config|apply_might_sleep|apply_atomic|ops)
PXA GPIO DRIVER
M: Robert Jarzmik <robert.jarzmik@free.fr>

View File

@ -275,7 +275,7 @@ static void ext_pwm_set_backlight(const struct drm_connector_state *conn_state,
struct intel_panel *panel = &to_intel_connector(conn_state->connector)->panel;
pwm_set_relative_duty_cycle(&panel->backlight.pwm_state, level, 100);
pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state);
pwm_apply_might_sleep(panel->backlight.pwm, &panel->backlight.pwm_state);
}
static void
@ -428,7 +428,7 @@ static void ext_pwm_disable_backlight(const struct drm_connector_state *old_conn
intel_backlight_set_pwm_level(old_conn_state, level);
panel->backlight.pwm_state.enabled = false;
pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state);
pwm_apply_might_sleep(panel->backlight.pwm, &panel->backlight.pwm_state);
}
void intel_backlight_disable(const struct drm_connector_state *old_conn_state)
@ -750,7 +750,7 @@ static void ext_pwm_enable_backlight(const struct intel_crtc_state *crtc_state,
pwm_set_relative_duty_cycle(&panel->backlight.pwm_state, level, 100);
panel->backlight.pwm_state.enabled = true;
pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state);
pwm_apply_might_sleep(panel->backlight.pwm, &panel->backlight.pwm_state);
}
static void __intel_backlight_enable(const struct intel_crtc_state *crtc_state,

View File

@ -319,7 +319,7 @@ static int ssd130x_pwm_enable(struct ssd130x_device *ssd130x)
pwm_init_state(ssd130x->pwm, &pwmstate);
pwm_set_relative_duty_cycle(&pwmstate, 50, 100);
pwm_apply_state(ssd130x->pwm, &pwmstate);
pwm_apply_might_sleep(ssd130x->pwm, &pwmstate);
/* Enable the PWM */
pwm_enable(ssd130x->pwm);

View File

@ -151,7 +151,7 @@ static int pwm_fan_power_on(struct pwm_fan_ctx *ctx)
}
state->enabled = true;
ret = pwm_apply_state(ctx->pwm, state);
ret = pwm_apply_might_sleep(ctx->pwm, state);
if (ret) {
dev_err(ctx->dev, "failed to enable PWM\n");
goto disable_regulator;
@ -181,7 +181,7 @@ static int pwm_fan_power_off(struct pwm_fan_ctx *ctx)
state->enabled = false;
state->duty_cycle = 0;
ret = pwm_apply_state(ctx->pwm, state);
ret = pwm_apply_might_sleep(ctx->pwm, state);
if (ret) {
dev_err(ctx->dev, "failed to disable PWM\n");
return ret;
@ -207,7 +207,7 @@ static int __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm)
period = state->period;
state->duty_cycle = DIV_ROUND_UP(pwm * (period - 1), MAX_PWM);
ret = pwm_apply_state(ctx->pwm, state);
ret = pwm_apply_might_sleep(ctx->pwm, state);
if (ret)
return ret;
ret = pwm_fan_power_on(ctx);
@ -278,7 +278,7 @@ static int pwm_fan_update_enable(struct pwm_fan_ctx *ctx, long val)
state,
&enable_regulator);
pwm_apply_state(ctx->pwm, state);
pwm_apply_might_sleep(ctx->pwm, state);
pwm_fan_switch_power(ctx, enable_regulator);
pwm_fan_update_state(ctx, 0);
}

View File

@ -352,7 +352,7 @@ static int da7280_haptic_set_pwm(struct da7280_haptic *haptics, bool enabled)
state.duty_cycle = period_mag_multi;
}
error = pwm_apply_state(haptics->pwm_dev, &state);
error = pwm_apply_might_sleep(haptics->pwm_dev, &state);
if (error)
dev_err(haptics->dev, "Failed to apply pwm state: %d\n", error);
@ -1175,7 +1175,7 @@ static int da7280_probe(struct i2c_client *client)
/* Sync up PWM state and ensure it is off. */
pwm_init_state(haptics->pwm_dev, &state);
state.enabled = false;
error = pwm_apply_state(haptics->pwm_dev, &state);
error = pwm_apply_might_sleep(haptics->pwm_dev, &state);
if (error) {
dev_err(dev, "Failed to apply PWM state: %d\n", error);
return error;

View File

@ -39,7 +39,7 @@ static int pwm_beeper_on(struct pwm_beeper *beeper, unsigned long period)
state.period = period;
pwm_set_relative_duty_cycle(&state, 50, 100);
error = pwm_apply_state(beeper->pwm, &state);
error = pwm_apply_might_sleep(beeper->pwm, &state);
if (error)
return error;
@ -138,7 +138,7 @@ static int pwm_beeper_probe(struct platform_device *pdev)
/* Sync up PWM state and ensure it is off. */
pwm_init_state(beeper->pwm, &state);
state.enabled = false;
error = pwm_apply_state(beeper->pwm, &state);
error = pwm_apply_might_sleep(beeper->pwm, &state);
if (error) {
dev_err(dev, "failed to apply initial PWM state: %d\n",
error);

View File

@ -56,7 +56,7 @@ static int pwm_vibrator_start(struct pwm_vibrator *vibrator)
pwm_set_relative_duty_cycle(&state, vibrator->level, 0xffff);
state.enabled = true;
err = pwm_apply_state(vibrator->pwm, &state);
err = pwm_apply_might_sleep(vibrator->pwm, &state);
if (err) {
dev_err(pdev, "failed to apply pwm state: %d\n", err);
return err;
@ -67,7 +67,7 @@ static int pwm_vibrator_start(struct pwm_vibrator *vibrator)
state.duty_cycle = vibrator->direction_duty_cycle;
state.enabled = true;
err = pwm_apply_state(vibrator->pwm_dir, &state);
err = pwm_apply_might_sleep(vibrator->pwm_dir, &state);
if (err) {
dev_err(pdev, "failed to apply dir-pwm state: %d\n", err);
pwm_disable(vibrator->pwm);
@ -160,7 +160,7 @@ static int pwm_vibrator_probe(struct platform_device *pdev)
/* Sync up PWM state and ensure it is off. */
pwm_init_state(vibrator->pwm, &state);
state.enabled = false;
err = pwm_apply_state(vibrator->pwm, &state);
err = pwm_apply_might_sleep(vibrator->pwm, &state);
if (err) {
dev_err(&pdev->dev, "failed to apply initial PWM state: %d\n",
err);
@ -174,7 +174,7 @@ static int pwm_vibrator_probe(struct platform_device *pdev)
/* Sync up PWM state and ensure it is off. */
pwm_init_state(vibrator->pwm_dir, &state);
state.enabled = false;
err = pwm_apply_state(vibrator->pwm_dir, &state);
err = pwm_apply_might_sleep(vibrator->pwm_dir, &state);
if (err) {
dev_err(&pdev->dev, "failed to apply initial PWM state: %d\n",
err);

View File

@ -54,7 +54,7 @@ static int led_pwm_set(struct led_classdev *led_cdev,
led_dat->pwmstate.duty_cycle = duty;
led_dat->pwmstate.enabled = true;
return pwm_apply_state(led_dat->pwm, &led_dat->pwmstate);
return pwm_apply_might_sleep(led_dat->pwm, &led_dat->pwmstate);
}
__attribute__((nonnull))

View File

@ -51,7 +51,7 @@ static int led_pwm_mc_set(struct led_classdev *cdev,
priv->leds[i].state.duty_cycle = duty;
priv->leds[i].state.enabled = duty > 0;
ret = pwm_apply_state(priv->leds[i].pwm,
ret = pwm_apply_might_sleep(priv->leds[i].pwm,
&priv->leds[i].state);
if (ret)
break;

View File

@ -10,6 +10,8 @@
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/hrtimer.h>
#include <linux/completion.h>
#include <media/rc-core.h>
#define DRIVER_NAME "pwm-ir-tx"
@ -17,8 +19,14 @@
struct pwm_ir {
struct pwm_device *pwm;
unsigned int carrier;
unsigned int duty_cycle;
struct hrtimer timer;
struct completion tx_done;
struct pwm_state *state;
u32 carrier;
u32 duty_cycle;
const unsigned int *txbuf;
unsigned int txbuf_len;
unsigned int txbuf_index;
};
static const struct of_device_id pwm_ir_of_match[] = {
@ -49,7 +57,7 @@ static int pwm_ir_set_carrier(struct rc_dev *dev, u32 carrier)
return 0;
}
static int pwm_ir_tx(struct rc_dev *dev, unsigned int *txbuf,
static int pwm_ir_tx_sleep(struct rc_dev *dev, unsigned int *txbuf,
unsigned int count)
{
struct pwm_ir *pwm_ir = dev->priv;
@ -68,7 +76,7 @@ static int pwm_ir_tx(struct rc_dev *dev, unsigned int *txbuf,
for (i = 0; i < count; i++) {
state.enabled = !(i % 2);
pwm_apply_state(pwm, &state);
pwm_apply_might_sleep(pwm, &state);
edge = ktime_add_us(edge, txbuf[i]);
delta = ktime_us_delta(edge, ktime_get());
@ -77,11 +85,67 @@ static int pwm_ir_tx(struct rc_dev *dev, unsigned int *txbuf,
}
state.enabled = false;
pwm_apply_state(pwm, &state);
pwm_apply_might_sleep(pwm, &state);
return count;
}
static int pwm_ir_tx_atomic(struct rc_dev *dev, unsigned int *txbuf,
unsigned int count)
{
struct pwm_ir *pwm_ir = dev->priv;
struct pwm_device *pwm = pwm_ir->pwm;
struct pwm_state state;
pwm_init_state(pwm, &state);
state.period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, pwm_ir->carrier);
pwm_set_relative_duty_cycle(&state, pwm_ir->duty_cycle, 100);
pwm_ir->txbuf = txbuf;
pwm_ir->txbuf_len = count;
pwm_ir->txbuf_index = 0;
pwm_ir->state = &state;
hrtimer_start(&pwm_ir->timer, 0, HRTIMER_MODE_REL);
wait_for_completion(&pwm_ir->tx_done);
return count;
}
static enum hrtimer_restart pwm_ir_timer(struct hrtimer *timer)
{
struct pwm_ir *pwm_ir = container_of(timer, struct pwm_ir, timer);
ktime_t now;
/*
* If we happen to hit an odd latency spike, loop through the
* pulses until we catch up.
*/
do {
u64 ns;
pwm_ir->state->enabled = !(pwm_ir->txbuf_index % 2);
pwm_apply_atomic(pwm_ir->pwm, pwm_ir->state);
if (pwm_ir->txbuf_index >= pwm_ir->txbuf_len) {
complete(&pwm_ir->tx_done);
return HRTIMER_NORESTART;
}
ns = US_TO_NS(pwm_ir->txbuf[pwm_ir->txbuf_index]);
hrtimer_add_expires_ns(timer, ns);
pwm_ir->txbuf_index++;
now = timer->base->get_time();
} while (hrtimer_get_expires_tv64(timer) < now);
return HRTIMER_RESTART;
}
static int pwm_ir_probe(struct platform_device *pdev)
{
struct pwm_ir *pwm_ir;
@ -103,10 +167,19 @@ static int pwm_ir_probe(struct platform_device *pdev)
if (!rcdev)
return -ENOMEM;
if (pwm_might_sleep(pwm_ir->pwm)) {
dev_info(&pdev->dev, "TX will not be accurate as PWM device might sleep\n");
rcdev->tx_ir = pwm_ir_tx_sleep;
} else {
init_completion(&pwm_ir->tx_done);
hrtimer_init(&pwm_ir->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
pwm_ir->timer.function = pwm_ir_timer;
rcdev->tx_ir = pwm_ir_tx_atomic;
}
rcdev->priv = pwm_ir;
rcdev->driver_name = DRIVER_NAME;
rcdev->device_name = DEVICE_NAME;
rcdev->tx_ir = pwm_ir_tx;
rcdev->s_tx_duty_cycle = pwm_ir_set_duty_cycle;
rcdev->s_tx_carrier = pwm_ir_set_carrier;

View File

@ -435,7 +435,7 @@ static int yogabook_pdev_set_kbd_backlight(struct yogabook_data *data, u8 level)
.enabled = level,
};
pwm_apply_state(data->kbd_bl_pwm, &state);
pwm_apply_might_sleep(data->kbd_bl_pwm, &state);
gpiod_set_value(data->kbd_bl_led_enable, level ? 1 : 0);
return 0;
}

View File

@ -8,6 +8,7 @@
#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/idr.h>
#include <linux/of.h>
#include <linux/pwm.h>
#include <linux/list.h>
@ -23,52 +24,25 @@
#define CREATE_TRACE_POINTS
#include <trace/events/pwm.h>
#define MAX_PWMS 1024
static DEFINE_MUTEX(pwm_lookup_lock);
static LIST_HEAD(pwm_lookup_list);
/* protects access to pwm_chips and allocated_pwms */
/* protects access to pwm_chips */
static DEFINE_MUTEX(pwm_lock);
static LIST_HEAD(pwm_chips);
static DECLARE_BITMAP(allocated_pwms, MAX_PWMS);
/* Called with pwm_lock held */
static int alloc_pwms(unsigned int count)
{
unsigned int start;
start = bitmap_find_next_zero_area(allocated_pwms, MAX_PWMS, 0,
count, 0);
if (start + count > MAX_PWMS)
return -ENOSPC;
bitmap_set(allocated_pwms, start, count);
return start;
}
/* Called with pwm_lock held */
static void free_pwms(struct pwm_chip *chip)
{
bitmap_clear(allocated_pwms, chip->base, chip->npwm);
kfree(chip->pwms);
chip->pwms = NULL;
}
static DEFINE_IDR(pwm_chips);
static struct pwm_chip *pwmchip_find_by_name(const char *name)
{
struct pwm_chip *chip;
unsigned long id, tmp;
if (!name)
return NULL;
mutex_lock(&pwm_lock);
list_for_each_entry(chip, &pwm_chips, list) {
idr_for_each_entry_ul(&pwm_chips, chip, tmp, id) {
const char *chip_name = dev_name(chip->dev);
if (chip_name && strcmp(chip_name, name) == 0) {
@ -85,22 +59,24 @@ static struct pwm_chip *pwmchip_find_by_name(const char *name)
static int pwm_device_request(struct pwm_device *pwm, const char *label)
{
int err;
struct pwm_chip *chip = pwm->chip;
const struct pwm_ops *ops = chip->ops;
if (test_bit(PWMF_REQUESTED, &pwm->flags))
return -EBUSY;
if (!try_module_get(pwm->chip->owner))
if (!try_module_get(chip->owner))
return -ENODEV;
if (pwm->chip->ops->request) {
err = pwm->chip->ops->request(pwm->chip, pwm);
if (ops->request) {
err = ops->request(chip, pwm);
if (err) {
module_put(pwm->chip->owner);
module_put(chip->owner);
return err;
}
}
if (pwm->chip->ops->get_state) {
if (ops->get_state) {
/*
* Zero-initialize state because most drivers are unaware of
* .usage_power. The other members of state are supposed to be
@ -110,7 +86,7 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label)
*/
struct pwm_state state = { 0, };
err = pwm->chip->ops->get_state(pwm->chip, pwm, &state);
err = ops->get_state(chip, pwm, &state);
trace_pwm_get(pwm, &state, err);
if (!err)
@ -234,7 +210,6 @@ static bool pwm_ops_check(const struct pwm_chip *chip)
*/
int __pwmchip_add(struct pwm_chip *chip, struct module *owner)
{
struct pwm_device *pwm;
unsigned int i;
int ret;
@ -246,31 +221,28 @@ int __pwmchip_add(struct pwm_chip *chip, struct module *owner)
chip->owner = owner;
chip->pwms = kcalloc(chip->npwm, sizeof(*pwm), GFP_KERNEL);
chip->pwms = kcalloc(chip->npwm, sizeof(*chip->pwms), GFP_KERNEL);
if (!chip->pwms)
return -ENOMEM;
mutex_lock(&pwm_lock);
ret = alloc_pwms(chip->npwm);
ret = idr_alloc(&pwm_chips, chip, 0, 0, GFP_KERNEL);
if (ret < 0) {
mutex_unlock(&pwm_lock);
kfree(chip->pwms);
return ret;
}
chip->base = ret;
chip->id = ret;
for (i = 0; i < chip->npwm; i++) {
pwm = &chip->pwms[i];
struct pwm_device *pwm = &chip->pwms[i];
pwm->chip = chip;
pwm->pwm = chip->base + i;
pwm->hwpwm = i;
}
list_add(&chip->list, &pwm_chips);
mutex_unlock(&pwm_lock);
if (IS_ENABLED(CONFIG_OF))
@ -297,11 +269,11 @@ void pwmchip_remove(struct pwm_chip *chip)
mutex_lock(&pwm_lock);
list_del_init(&chip->list);
free_pwms(chip);
idr_remove(&pwm_chips, chip->id);
mutex_unlock(&pwm_lock);
kfree(chip->pwms);
}
EXPORT_SYMBOL_GPL(pwmchip_remove);
@ -356,7 +328,7 @@ struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip,
}
EXPORT_SYMBOL_GPL(pwm_request_from_chip);
static void pwm_apply_state_debug(struct pwm_device *pwm,
static void pwm_apply_debug(struct pwm_device *pwm,
const struct pwm_state *state)
{
struct pwm_state *last = &pwm->last;
@ -463,24 +435,15 @@ static void pwm_apply_state_debug(struct pwm_device *pwm,
}
/**
* pwm_apply_state() - atomically apply a new state to a PWM device
* __pwm_apply() - atomically apply a new state to a PWM device
* @pwm: PWM device
* @state: new state to apply
*/
int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state)
static int __pwm_apply(struct pwm_device *pwm, const struct pwm_state *state)
{
struct pwm_chip *chip;
int err;
/*
* Some lowlevel driver's implementations of .apply() make use of
* mutexes, also with some drivers only returning when the new
* configuration is active calling pwm_apply_state() from atomic context
* is a bad idea. So make it explicit that calling this function might
* sleep.
*/
might_sleep();
if (!pwm || !state || !state->period ||
state->duty_cycle > state->period)
return -EINVAL;
@ -505,11 +468,60 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state)
* only do this after pwm->state was applied as some
* implementations of .get_state depend on this
*/
pwm_apply_state_debug(pwm, state);
pwm_apply_debug(pwm, state);
return 0;
}
EXPORT_SYMBOL_GPL(pwm_apply_state);
/**
* pwm_apply_might_sleep() - atomically apply a new state to a PWM device
* Cannot be used in atomic context.
* @pwm: PWM device
* @state: new state to apply
*/
int pwm_apply_might_sleep(struct pwm_device *pwm, const struct pwm_state *state)
{
int err;
/*
* Some lowlevel driver's implementations of .apply() make use of
* mutexes, also with some drivers only returning when the new
* configuration is active calling pwm_apply_might_sleep() from atomic context
* is a bad idea. So make it explicit that calling this function might
* sleep.
*/
might_sleep();
if (IS_ENABLED(CONFIG_PWM_DEBUG) && pwm->chip->atomic) {
/*
* Catch any drivers that have been marked as atomic but
* that will sleep anyway.
*/
non_block_start();
err = __pwm_apply(pwm, state);
non_block_end();
} else {
err = __pwm_apply(pwm, state);
}
return err;
}
EXPORT_SYMBOL_GPL(pwm_apply_might_sleep);
/**
* pwm_apply_atomic() - apply a new state to a PWM device from atomic context
* Not all PWM devices support this function, check with pwm_might_sleep().
* @pwm: PWM device
* @state: new state to apply
*/
int pwm_apply_atomic(struct pwm_device *pwm, const struct pwm_state *state)
{
WARN_ONCE(!pwm->chip->atomic,
"sleeping PWM driver used in atomic context\n");
return __pwm_apply(pwm, state);
}
EXPORT_SYMBOL_GPL(pwm_apply_atomic);
/**
* pwm_capture() - capture and report a PWM signal
@ -567,7 +579,7 @@ int pwm_adjust_config(struct pwm_device *pwm)
state.period = pargs.period;
state.polarity = pargs.polarity;
return pwm_apply_state(pwm, &state);
return pwm_apply_might_sleep(pwm, &state);
}
/*
@ -590,17 +602,18 @@ int pwm_adjust_config(struct pwm_device *pwm)
state.duty_cycle = state.period - state.duty_cycle;
}
return pwm_apply_state(pwm, &state);
return pwm_apply_might_sleep(pwm, &state);
}
EXPORT_SYMBOL_GPL(pwm_adjust_config);
static struct pwm_chip *fwnode_to_pwmchip(struct fwnode_handle *fwnode)
{
struct pwm_chip *chip;
unsigned long id, tmp;
mutex_lock(&pwm_lock);
list_for_each_entry(chip, &pwm_chips, list)
idr_for_each_entry_ul(&pwm_chips, chip, tmp, id)
if (chip->dev && device_match_fwnode(chip->dev, fwnode)) {
mutex_unlock(&pwm_lock);
return chip;
@ -1058,17 +1071,27 @@ static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s)
static void *pwm_seq_start(struct seq_file *s, loff_t *pos)
{
unsigned long id = *pos;
void *ret;
mutex_lock(&pwm_lock);
s->private = "";
return seq_list_start(&pwm_chips, *pos);
ret = idr_get_next_ul(&pwm_chips, &id);
*pos = id;
return ret;
}
static void *pwm_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
unsigned long id = *pos + 1;
void *ret;
s->private = "\n";
return seq_list_next(v, &pwm_chips, pos);
ret = idr_get_next_ul(&pwm_chips, &id);
*pos = id;
return ret;
}
static void pwm_seq_stop(struct seq_file *s, void *v)
@ -1078,9 +1101,10 @@ static void pwm_seq_stop(struct seq_file *s, void *v)
static int pwm_seq_show(struct seq_file *s, void *v)
{
struct pwm_chip *chip = list_entry(v, struct pwm_chip, list);
struct pwm_chip *chip = v;
seq_printf(s, "%s%s/%s, %d PWM device%s\n", (char *)s->private,
seq_printf(s, "%s%d: %s/%s, %d PWM device%s\n",
(char *)s->private, chip->id,
chip->dev->bus ? chip->dev->bus->name : "no-bus",
dev_name(chip->dev), chip->npwm,
(chip->npwm != 1) ? "s" : "");

View File

@ -180,7 +180,6 @@ static const struct atmel_hlcdc_pwm_errata atmel_hlcdc_pwm_sama5d3_errata = {
.div1_clk_erratum = true,
};
#ifdef CONFIG_PM_SLEEP
static int atmel_hlcdc_pwm_suspend(struct device *dev)
{
struct atmel_hlcdc_pwm *atmel = dev_get_drvdata(dev);
@ -210,9 +209,8 @@ static int atmel_hlcdc_pwm_resume(struct device *dev)
return atmel_hlcdc_pwm_apply(&atmel->chip, &atmel->chip.pwms[0],
&state);
}
#endif
static SIMPLE_DEV_PM_OPS(atmel_hlcdc_pwm_pm_ops,
static DEFINE_SIMPLE_DEV_PM_OPS(atmel_hlcdc_pwm_pm_ops,
atmel_hlcdc_pwm_suspend, atmel_hlcdc_pwm_resume);
static const struct of_device_id atmel_hlcdc_dt_ids[] = {
@ -297,7 +295,7 @@ static struct platform_driver atmel_hlcdc_pwm_driver = {
.driver = {
.name = "atmel-hlcdc-pwm",
.of_match_table = atmel_hlcdc_pwm_dt_ids,
.pm = &atmel_hlcdc_pwm_pm_ops,
.pm = pm_ptr(&atmel_hlcdc_pwm_pm_ops),
},
.probe = atmel_hlcdc_pwm_probe,
.remove_new = atmel_hlcdc_pwm_remove,

View File

@ -489,7 +489,6 @@ static const struct of_device_id atmel_tcb_pwm_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, atmel_tcb_pwm_dt_ids);
#ifdef CONFIG_PM_SLEEP
static int atmel_tcb_pwm_suspend(struct device *dev)
{
struct atmel_tcb_pwm_chip *tcbpwm = dev_get_drvdata(dev);
@ -522,16 +521,15 @@ static int atmel_tcb_pwm_resume(struct device *dev)
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(atmel_tcb_pwm_pm_ops, atmel_tcb_pwm_suspend,
static DEFINE_SIMPLE_DEV_PM_OPS(atmel_tcb_pwm_pm_ops, atmel_tcb_pwm_suspend,
atmel_tcb_pwm_resume);
static struct platform_driver atmel_tcb_pwm_driver = {
.driver = {
.name = "atmel-tcb-pwm",
.of_match_table = atmel_tcb_pwm_dt_ids,
.pm = &atmel_tcb_pwm_pm_ops,
.pm = pm_ptr(&atmel_tcb_pwm_pm_ops),
},
.probe = atmel_tcb_pwm_probe,
.remove_new = atmel_tcb_pwm_remove,

View File

@ -260,7 +260,7 @@ static int kona_pwmc_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return err;
}
err = kona_pwmc_config(pwm->chip, pwm, state->duty_cycle, state->period);
err = kona_pwmc_config(chip, pwm, state->duty_cycle, state->period);
if (err && !pwm->state.enabled)
clk_disable_unprepare(kp->clk);

View File

@ -28,6 +28,7 @@ struct bcm2835_pwm {
struct device *dev;
void __iomem *base;
struct clk *clk;
unsigned long rate;
};
static inline struct bcm2835_pwm *to_bcm2835_pwm(struct pwm_chip *chip)
@ -63,17 +64,11 @@ static int bcm2835_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
{
struct bcm2835_pwm *pc = to_bcm2835_pwm(chip);
unsigned long rate = clk_get_rate(pc->clk);
unsigned long long period_cycles;
u64 max_period;
u32 val;
if (!rate) {
dev_err(pc->dev, "failed to get clock rate\n");
return -EINVAL;
}
/*
* period_cycles must be a 32 bit value, so period * rate / NSEC_PER_SEC
* must be <= U32_MAX. As U32_MAX * NSEC_PER_SEC < U64_MAX the
@ -88,13 +83,13 @@ static int bcm2835_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
* <=> period < ((U32_MAX * NSEC_PER_SEC + NSEC_PER_SEC/2) / rate
* <=> period <= ceil((U32_MAX * NSEC_PER_SEC + NSEC_PER_SEC/2) / rate) - 1
*/
max_period = DIV_ROUND_UP_ULL((u64)U32_MAX * NSEC_PER_SEC + NSEC_PER_SEC / 2, rate) - 1;
max_period = DIV_ROUND_UP_ULL((u64)U32_MAX * NSEC_PER_SEC + NSEC_PER_SEC / 2, pc->rate) - 1;
if (state->period > max_period)
return -EINVAL;
/* set period */
period_cycles = DIV_ROUND_CLOSEST_ULL(state->period * rate, NSEC_PER_SEC);
period_cycles = DIV_ROUND_CLOSEST_ULL(state->period * pc->rate, NSEC_PER_SEC);
/* don't accept a period that is too small */
if (period_cycles < PERIOD_MIN)
@ -103,7 +98,7 @@ static int bcm2835_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
writel(period_cycles, pc->base + PERIOD(pwm->hwpwm));
/* set duty cycle */
val = DIV_ROUND_CLOSEST_ULL(state->duty_cycle * rate, NSEC_PER_SEC);
val = DIV_ROUND_CLOSEST_ULL(state->duty_cycle * pc->rate, NSEC_PER_SEC);
writel(val, pc->base + DUTY(pwm->hwpwm));
/* set polarity */
@ -131,6 +126,13 @@ static const struct pwm_ops bcm2835_pwm_ops = {
.apply = bcm2835_pwm_apply,
};
static void devm_clk_rate_exclusive_put(void *data)
{
struct clk *clk = data;
clk_rate_exclusive_put(clk);
}
static int bcm2835_pwm_probe(struct platform_device *pdev)
{
struct bcm2835_pwm *pc;
@ -151,8 +153,26 @@ static int bcm2835_pwm_probe(struct platform_device *pdev)
return dev_err_probe(&pdev->dev, PTR_ERR(pc->clk),
"clock not found\n");
ret = clk_rate_exclusive_get(pc->clk);
if (ret)
return dev_err_probe(&pdev->dev, ret,
"fail to get exclusive rate\n");
ret = devm_add_action_or_reset(&pdev->dev, devm_clk_rate_exclusive_put,
pc->clk);
if (ret) {
clk_rate_exclusive_put(pc->clk);
return ret;
}
pc->rate = clk_get_rate(pc->clk);
if (!pc->rate)
return dev_err_probe(&pdev->dev, -EINVAL,
"failed to get clock rate\n");
pc->chip.dev = &pdev->dev;
pc->chip.ops = &bcm2835_pwm_ops;
pc->chip.atomic = true;
pc->chip.npwm = 2;
platform_set_drvdata(pdev, pc);

View File

@ -226,7 +226,6 @@ static int berlin_pwm_probe(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int berlin_pwm_suspend(struct device *dev)
{
struct berlin_pwm_chip *bpc = dev_get_drvdata(dev);
@ -267,9 +266,8 @@ static int berlin_pwm_resume(struct device *dev)
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(berlin_pwm_pm_ops, berlin_pwm_suspend,
static DEFINE_SIMPLE_DEV_PM_OPS(berlin_pwm_pm_ops, berlin_pwm_suspend,
berlin_pwm_resume);
static struct platform_driver berlin_pwm_driver = {
@ -277,7 +275,7 @@ static struct platform_driver berlin_pwm_driver = {
.driver = {
.name = "berlin-pwm",
.of_match_table = berlin_pwm_match,
.pm = &berlin_pwm_pm_ops,
.pm = pm_ptr(&berlin_pwm_pm_ops),
},
};
module_platform_driver(berlin_pwm_driver);

View File

@ -259,7 +259,6 @@ static int brcmstb_pwm_probe(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int brcmstb_pwm_suspend(struct device *dev)
{
struct brcmstb_pwm *p = dev_get_drvdata(dev);
@ -275,9 +274,8 @@ static int brcmstb_pwm_resume(struct device *dev)
return clk_prepare_enable(p->clk);
}
#endif
static SIMPLE_DEV_PM_OPS(brcmstb_pwm_pm_ops, brcmstb_pwm_suspend,
static DEFINE_SIMPLE_DEV_PM_OPS(brcmstb_pwm_pm_ops, brcmstb_pwm_suspend,
brcmstb_pwm_resume);
static struct platform_driver brcmstb_pwm_driver = {
@ -285,7 +283,7 @@ static struct platform_driver brcmstb_pwm_driver = {
.driver = {
.name = "pwm-brcmstb",
.of_match_table = brcmstb_pwm_of_match,
.pm = &brcmstb_pwm_pm_ops,
.pm = pm_ptr(&brcmstb_pwm_pm_ops),
},
};
module_platform_driver(brcmstb_pwm_driver);

View File

@ -160,22 +160,22 @@ static const struct pwm_ops crc_pwm_ops = {
static int crystalcove_pwm_probe(struct platform_device *pdev)
{
struct crystalcove_pwm *pwm;
struct crystalcove_pwm *crc_pwm;
struct device *dev = pdev->dev.parent;
struct intel_soc_pmic *pmic = dev_get_drvdata(dev);
pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
if (!pwm)
crc_pwm = devm_kzalloc(&pdev->dev, sizeof(*crc_pwm), GFP_KERNEL);
if (!crc_pwm)
return -ENOMEM;
pwm->chip.dev = &pdev->dev;
pwm->chip.ops = &crc_pwm_ops;
pwm->chip.npwm = 1;
crc_pwm->chip.dev = &pdev->dev;
crc_pwm->chip.ops = &crc_pwm_ops;
crc_pwm->chip.npwm = 1;
/* get the PMIC regmap */
pwm->regmap = pmic->regmap;
crc_pwm->regmap = pmic->regmap;
return devm_pwmchip_add(&pdev->dev, &pwm->chip);
return devm_pwmchip_add(&pdev->dev, &crc_pwm->chip);
}
static struct platform_driver crystalcove_pwm_driver = {

View File

@ -18,14 +18,12 @@
/**
* struct cros_ec_pwm_device - Driver data for EC PWM
*
* @dev: Device node
* @ec: Pointer to EC device
* @chip: PWM controller chip
* @use_pwm_type: Use PWM types instead of generic channels
* @channel: array with per-channel data
*/
struct cros_ec_pwm_device {
struct device *dev;
struct cros_ec_device *ec;
struct pwm_chip chip;
bool use_pwm_type;

View File

@ -71,7 +71,6 @@ static void dwc_pwm_remove(struct pci_dev *pci)
pm_runtime_get_noresume(&pci->dev);
}
#ifdef CONFIG_PM_SLEEP
static int dwc_pwm_suspend(struct device *dev)
{
struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
@ -106,9 +105,8 @@ static int dwc_pwm_resume(struct device *dev)
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(dwc_pwm_pm_ops, dwc_pwm_suspend, dwc_pwm_resume);
static DEFINE_SIMPLE_DEV_PM_OPS(dwc_pwm_pm_ops, dwc_pwm_suspend, dwc_pwm_resume);
static const struct pci_device_id dwc_pwm_id_table[] = {
{ PCI_VDEVICE(INTEL, 0x4bb7) }, /* Elkhart Lake */
@ -122,7 +120,7 @@ static struct pci_driver dwc_pwm_driver = {
.remove = dwc_pwm_remove,
.id_table = dwc_pwm_id_table,
.driver = {
.pm = &dwc_pwm_pm_ops,
.pm = pm_ptr(&dwc_pwm_pm_ops),
},
};

View File

@ -13,9 +13,9 @@
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
#include <linux/pwm.h>
#include <linux/regmap.h>
#include <linux/slab.h>
@ -196,7 +196,7 @@ static int img_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return 0;
}
err = img_pwm_config(pwm->chip, pwm, state->duty_cycle, state->period);
err = img_pwm_config(chip, pwm, state->duty_cycle, state->period);
if (err)
return err;
@ -260,7 +260,6 @@ static int img_pwm_probe(struct platform_device *pdev)
u64 val;
unsigned long clk_rate;
struct img_pwm_chip *imgchip;
const struct of_device_id *of_dev_id;
imgchip = devm_kzalloc(&pdev->dev, sizeof(*imgchip), GFP_KERNEL);
if (!imgchip)
@ -272,10 +271,7 @@ static int img_pwm_probe(struct platform_device *pdev)
if (IS_ERR(imgchip->base))
return PTR_ERR(imgchip->base);
of_dev_id = of_match_device(img_pwm_of_match, &pdev->dev);
if (!of_dev_id)
return -ENODEV;
imgchip->data = of_dev_id->data;
imgchip->data = device_get_match_data(&pdev->dev);
imgchip->periph_regs = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
"img,cr-periph");

View File

@ -371,7 +371,7 @@ static int pwm_imx_tpm_probe(struct platform_device *pdev)
return 0;
}
static int __maybe_unused pwm_imx_tpm_suspend(struct device *dev)
static int pwm_imx_tpm_suspend(struct device *dev)
{
struct imx_tpm_pwm_chip *tpm = dev_get_drvdata(dev);
@ -390,7 +390,7 @@ static int __maybe_unused pwm_imx_tpm_suspend(struct device *dev)
return 0;
}
static int __maybe_unused pwm_imx_tpm_resume(struct device *dev)
static int pwm_imx_tpm_resume(struct device *dev)
{
struct imx_tpm_pwm_chip *tpm = dev_get_drvdata(dev);
int ret = 0;
@ -402,7 +402,7 @@ static int __maybe_unused pwm_imx_tpm_resume(struct device *dev)
return ret;
}
static SIMPLE_DEV_PM_OPS(imx_tpm_pwm_pm,
static DEFINE_SIMPLE_DEV_PM_OPS(imx_tpm_pwm_pm,
pwm_imx_tpm_suspend, pwm_imx_tpm_resume);
static const struct of_device_id imx_tpm_pwm_dt_ids[] = {
@ -415,7 +415,7 @@ static struct platform_driver imx_tpm_pwm_driver = {
.driver = {
.name = "imx7ulp-tpm-pwm",
.of_match_table = imx_tpm_pwm_dt_ids,
.pm = &imx_tpm_pwm_pm,
.pm = pm_ptr(&imx_tpm_pwm_pm),
},
.probe = pwm_imx_tpm_probe,
};

View File

@ -123,7 +123,7 @@ static void jz4740_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
const struct pwm_state *state)
{
struct jz4740_pwm_chip *jz = to_jz4740(pwm->chip);
struct jz4740_pwm_chip *jz = to_jz4740(chip);
unsigned long long tmp = 0xffffull * NSEC_PER_SEC;
struct clk *clk = jz->clk[pwm->hwpwm];
unsigned long period, duty;
@ -149,7 +149,7 @@ static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
*/
rate = clk_round_rate(clk, tmp);
if (rate < 0) {
dev_err(chip->dev, "Unable to round rate: %ld", rate);
dev_err(chip->dev, "Unable to round rate: %ld\n", rate);
return rate;
}
@ -170,7 +170,7 @@ static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
err = clk_set_rate(clk, rate);
if (err) {
dev_err(chip->dev, "Unable to set rate: %d", err);
dev_err(chip->dev, "Unable to set rate: %d\n", err);
return err;
}

View File

@ -194,7 +194,7 @@ static int lpc18xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
int duty_ns, int period_ns)
{
struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip);
int requested_events, i;
int requested_events;
if (period_ns < lpc18xx_pwm->min_period_ns ||
period_ns > lpc18xx_pwm->max_period_ns) {
@ -223,8 +223,6 @@ static int lpc18xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
if ((requested_events <= 2 && lpc18xx_pwm->period_ns != period_ns) ||
!lpc18xx_pwm->period_ns) {
lpc18xx_pwm->period_ns = period_ns;
for (i = 0; i < chip->npwm; i++)
pwm_set_period(&chip->pwms[i], period_ns);
lpc18xx_pwm_config_period(chip, period_ns);
}
@ -328,7 +326,7 @@ static int lpc18xx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return 0;
}
err = lpc18xx_pwm_config(pwm->chip, pwm, state->duty_cycle, state->period);
err = lpc18xx_pwm_config(chip, pwm, state->duty_cycle, state->period);
if (err)
return err;

View File

@ -103,7 +103,7 @@ static int lpc32xx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return 0;
}
err = lpc32xx_pwm_config(pwm->chip, pwm, state->duty_cycle, state->period);
err = lpc32xx_pwm_config(chip, pwm, state->duty_cycle, state->period);
if (err)
return err;

View File

@ -217,7 +217,7 @@ static int pwm_mediatek_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return 0;
}
err = pwm_mediatek_config(pwm->chip, pwm, state->duty_cycle, state->period);
err = pwm_mediatek_config(chip, pwm, state->duty_cycle, state->period);
if (err)
return err;

View File

@ -468,10 +468,9 @@ static int meson_pwm_init_channels(struct meson_pwm *meson)
channel->mux.hw.init = &init;
err = devm_clk_hw_register(dev, &channel->mux.hw);
if (err) {
dev_err(dev, "failed to register %s: %d\n", name, err);
return err;
}
if (err)
return dev_err_probe(dev, err,
"failed to register %s\n", name);
snprintf(name, sizeof(name), "%s#div%u", dev_name(dev), i);
@ -491,10 +490,9 @@ static int meson_pwm_init_channels(struct meson_pwm *meson)
channel->div.lock = &meson->lock;
err = devm_clk_hw_register(dev, &channel->div.hw);
if (err) {
dev_err(dev, "failed to register %s: %d\n", name, err);
return err;
}
if (err)
return dev_err_probe(dev, err,
"failed to register %s\n", name);
snprintf(name, sizeof(name), "%s#gate%u", dev_name(dev), i);
@ -513,17 +511,13 @@ static int meson_pwm_init_channels(struct meson_pwm *meson)
channel->gate.lock = &meson->lock;
err = devm_clk_hw_register(dev, &channel->gate.hw);
if (err) {
dev_err(dev, "failed to register %s: %d\n", name, err);
return err;
}
if (err)
return dev_err_probe(dev, err, "failed to register %s\n", name);
channel->clk = devm_clk_hw_get_clk(dev, &channel->gate.hw, NULL);
if (IS_ERR(channel->clk)) {
err = PTR_ERR(channel->clk);
dev_err(dev, "failed to register %s: %d\n", name, err);
return err;
}
if (IS_ERR(channel->clk))
return dev_err_probe(dev, PTR_ERR(channel->clk),
"failed to register %s\n", name);
}
return 0;
@ -554,10 +548,9 @@ static int meson_pwm_probe(struct platform_device *pdev)
return err;
err = devm_pwmchip_add(&pdev->dev, &meson->chip);
if (err < 0) {
dev_err(&pdev->dev, "failed to register PWM chip: %d\n", err);
return err;
}
if (err < 0)
return dev_err_probe(&pdev->dev, err,
"failed to register PWM chip\n");
return 0;
}

View File

@ -37,7 +37,6 @@
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <clocksource/timer-ti-dm.h>
@ -55,7 +54,6 @@
* struct pwm_omap_dmtimer_chip - Structure representing a pwm chip
* corresponding to omap dmtimer.
* @chip: PWM chip structure representing PWM controller
* @mutex: Mutex to protect pwm apply state
* @dm_timer: Pointer to omap dm timer.
* @pdata: Pointer to omap dm timer ops.
* @dm_timer_pdev: Pointer to omap dm timer platform device
@ -63,7 +61,6 @@
struct pwm_omap_dmtimer_chip {
struct pwm_chip chip;
/* Mutex to protect pwm apply state */
struct mutex mutex;
struct omap_dm_timer *dm_timer;
const struct omap_dm_timer_ops *pdata;
struct platform_device *dm_timer_pdev;
@ -277,13 +274,11 @@ static int pwm_omap_dmtimer_apply(struct pwm_chip *chip,
const struct pwm_state *state)
{
struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
int ret = 0;
mutex_lock(&omap->mutex);
int ret;
if (pwm_omap_dmtimer_is_enabled(omap) && !state->enabled) {
omap->pdata->stop(omap->dm_timer);
goto unlock_mutex;
return 0;
}
if (pwm_omap_dmtimer_polarity(omap) != state->polarity)
@ -292,7 +287,7 @@ static int pwm_omap_dmtimer_apply(struct pwm_chip *chip,
ret = pwm_omap_dmtimer_config(chip, pwm, state->duty_cycle,
state->period);
if (ret)
goto unlock_mutex;
return ret;
if (!pwm_omap_dmtimer_is_enabled(omap) && state->enabled) {
omap->pdata->set_pwm(omap->dm_timer,
@ -303,10 +298,7 @@ static int pwm_omap_dmtimer_apply(struct pwm_chip *chip,
pwm_omap_dmtimer_start(omap);
}
unlock_mutex:
mutex_unlock(&omap->mutex);
return ret;
return 0;
}
static const struct pwm_ops pwm_omap_dmtimer_ops = {
@ -404,8 +396,6 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
omap->chip.ops = &pwm_omap_dmtimer_ops;
omap->chip.npwm = 1;
mutex_init(&omap->mutex);
ret = pwmchip_add(&omap->chip);
if (ret < 0) {
dev_err(&pdev->dev, "failed to register PWM\n");
@ -452,8 +442,6 @@ static void pwm_omap_dmtimer_remove(struct platform_device *pdev)
omap->pdata->free(omap->dm_timer);
put_device(&omap->dm_timer_pdev->dev);
mutex_destroy(&omap->mutex);
}
static const struct of_device_id pwm_omap_dmtimer_of_match[] = {

View File

@ -11,7 +11,6 @@
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
@ -416,7 +415,7 @@ static int tpu_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return 0;
}
err = tpu_pwm_config(pwm->chip, pwm,
err = tpu_pwm_config(chip, pwm,
state->duty_cycle, state->period, enabled);
if (err)
return err;

View File

@ -10,8 +10,8 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/pwm.h>
#include <linux/time.h>
@ -296,16 +296,11 @@ MODULE_DEVICE_TABLE(of, rockchip_pwm_dt_ids);
static int rockchip_pwm_probe(struct platform_device *pdev)
{
const struct of_device_id *id;
struct rockchip_pwm_chip *pc;
u32 enable_conf, ctrl;
bool enabled;
int ret, count;
id = of_match_device(rockchip_pwm_dt_ids, &pdev->dev);
if (!id)
return -EINVAL;
pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
if (!pc)
return -ENOMEM;
@ -344,7 +339,7 @@ static int rockchip_pwm_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, pc);
pc->data = id->data;
pc->data = device_get_match_data(&pdev->dev);
pc->chip.dev = &pdev->dev;
pc->chip.ops = &rockchip_pwm_ops;
pc->chip.npwm = 1;

View File

@ -620,7 +620,6 @@ static void pwm_samsung_remove(struct platform_device *pdev)
clk_disable_unprepare(our_chip->base_clk);
}
#ifdef CONFIG_PM_SLEEP
static int pwm_samsung_resume(struct device *dev)
{
struct samsung_pwm_chip *our_chip = dev_get_drvdata(dev);
@ -653,14 +652,13 @@ static int pwm_samsung_resume(struct device *dev)
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(pwm_samsung_pm_ops, NULL, pwm_samsung_resume);
static DEFINE_SIMPLE_DEV_PM_OPS(pwm_samsung_pm_ops, NULL, pwm_samsung_resume);
static struct platform_driver pwm_samsung_driver = {
.driver = {
.name = "samsung-pwm",
.pm = &pwm_samsung_pm_ops,
.pm = pm_ptr(&pwm_samsung_pm_ops),
.of_match_table = of_match_ptr(samsung_pwm_matches),
},
.probe = pwm_samsung_probe,

View File

@ -407,7 +407,7 @@ static int sti_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return 0;
}
err = sti_pwm_config(pwm->chip, pwm, state->duty_cycle, state->period);
err = sti_pwm_config(chip, pwm, state->duty_cycle, state->period);
if (err)
return err;

View File

@ -218,7 +218,7 @@ static int stm32_pwm_lp_probe(struct platform_device *pdev)
return 0;
}
static int __maybe_unused stm32_pwm_lp_suspend(struct device *dev)
static int stm32_pwm_lp_suspend(struct device *dev)
{
struct stm32_pwm_lp *priv = dev_get_drvdata(dev);
struct pwm_state state;
@ -233,12 +233,12 @@ static int __maybe_unused stm32_pwm_lp_suspend(struct device *dev)
return pinctrl_pm_select_sleep_state(dev);
}
static int __maybe_unused stm32_pwm_lp_resume(struct device *dev)
static int stm32_pwm_lp_resume(struct device *dev)
{
return pinctrl_pm_select_default_state(dev);
}
static SIMPLE_DEV_PM_OPS(stm32_pwm_lp_pm_ops, stm32_pwm_lp_suspend,
static DEFINE_SIMPLE_DEV_PM_OPS(stm32_pwm_lp_pm_ops, stm32_pwm_lp_suspend,
stm32_pwm_lp_resume);
static const struct of_device_id stm32_pwm_lp_of_match[] = {
@ -252,7 +252,7 @@ static struct platform_driver stm32_pwm_lp_driver = {
.driver = {
.name = "stm32-pwm-lp",
.of_match_table = stm32_pwm_lp_of_match,
.pm = &stm32_pwm_lp_pm_ops,
.pm = pm_ptr(&stm32_pwm_lp_pm_ops),
},
};
module_platform_driver(stm32_pwm_lp_driver);

View File

@ -52,21 +52,6 @@ static u32 active_channels(struct stm32_pwm *dev)
return ccer & TIM_CCER_CCXE;
}
static int write_ccrx(struct stm32_pwm *dev, int ch, u32 value)
{
switch (ch) {
case 0:
return regmap_write(dev->regmap, TIM_CCR1, value);
case 1:
return regmap_write(dev->regmap, TIM_CCR2, value);
case 2:
return regmap_write(dev->regmap, TIM_CCR3, value);
case 3:
return regmap_write(dev->regmap, TIM_CCR4, value);
}
return -EINVAL;
}
#define TIM_CCER_CC12P (TIM_CCER_CC1P | TIM_CCER_CC2P)
#define TIM_CCER_CC12E (TIM_CCER_CC1E | TIM_CCER_CC2E)
#define TIM_CCER_CC34P (TIM_CCER_CC3P | TIM_CCER_CC4P)
@ -323,7 +308,7 @@ unlock:
return ret;
}
static int stm32_pwm_config(struct stm32_pwm *priv, int ch,
static int stm32_pwm_config(struct stm32_pwm *priv, unsigned int ch,
int duty_ns, int period_ns)
{
unsigned long long prd, div, dty;
@ -369,7 +354,7 @@ static int stm32_pwm_config(struct stm32_pwm *priv, int ch,
dty = prd * duty_ns;
do_div(dty, period_ns);
write_ccrx(priv, ch, dty);
regmap_write(priv->regmap, TIM_CCR1 + 4 * ch, dty);
/* Configure output mode */
shift = (ch & 0x1) * CCMR_CHANNEL_SHIFT;
@ -386,7 +371,7 @@ static int stm32_pwm_config(struct stm32_pwm *priv, int ch,
return 0;
}
static int stm32_pwm_set_polarity(struct stm32_pwm *priv, int ch,
static int stm32_pwm_set_polarity(struct stm32_pwm *priv, unsigned int ch,
enum pwm_polarity polarity)
{
u32 mask;
@ -401,7 +386,7 @@ static int stm32_pwm_set_polarity(struct stm32_pwm *priv, int ch,
return 0;
}
static int stm32_pwm_enable(struct stm32_pwm *priv, int ch)
static int stm32_pwm_enable(struct stm32_pwm *priv, unsigned int ch)
{
u32 mask;
int ret;
@ -426,7 +411,7 @@ static int stm32_pwm_enable(struct stm32_pwm *priv, int ch)
return 0;
}
static void stm32_pwm_disable(struct stm32_pwm *priv, int ch)
static void stm32_pwm_disable(struct stm32_pwm *priv, unsigned int ch)
{
u32 mask;
@ -486,8 +471,50 @@ static int stm32_pwm_apply_locked(struct pwm_chip *chip, struct pwm_device *pwm,
return ret;
}
static int stm32_pwm_get_state(struct pwm_chip *chip,
struct pwm_device *pwm, struct pwm_state *state)
{
struct stm32_pwm *priv = to_stm32_pwm_dev(chip);
int ch = pwm->hwpwm;
unsigned long rate;
u32 ccer, psc, arr, ccr;
u64 dty, prd;
int ret;
mutex_lock(&priv->lock);
ret = regmap_read(priv->regmap, TIM_CCER, &ccer);
if (ret)
goto out;
state->enabled = ccer & (TIM_CCER_CC1E << (ch * 4));
state->polarity = (ccer & (TIM_CCER_CC1P << (ch * 4))) ?
PWM_POLARITY_INVERSED : PWM_POLARITY_NORMAL;
ret = regmap_read(priv->regmap, TIM_PSC, &psc);
if (ret)
goto out;
ret = regmap_read(priv->regmap, TIM_ARR, &arr);
if (ret)
goto out;
ret = regmap_read(priv->regmap, TIM_CCR1 + 4 * ch, &ccr);
if (ret)
goto out;
rate = clk_get_rate(priv->clk);
prd = (u64)NSEC_PER_SEC * (psc + 1) * (arr + 1);
state->period = DIV_ROUND_UP_ULL(prd, rate);
dty = (u64)NSEC_PER_SEC * (psc + 1) * ccr;
state->duty_cycle = DIV_ROUND_UP_ULL(dty, rate);
out:
mutex_unlock(&priv->lock);
return ret;
}
static const struct pwm_ops stm32pwm_ops = {
.apply = stm32_pwm_apply_locked,
.get_state = stm32_pwm_get_state,
.capture = IS_ENABLED(CONFIG_DMA_ENGINE) ? stm32_pwm_capture : NULL,
};
@ -578,32 +605,23 @@ static void stm32_pwm_detect_complementary(struct stm32_pwm *priv)
priv->have_complementary_output = (ccer != 0);
}
static int stm32_pwm_detect_channels(struct stm32_pwm *priv)
static unsigned int stm32_pwm_detect_channels(struct stm32_pwm *priv,
unsigned int *num_enabled)
{
u32 ccer;
int npwm = 0;
u32 ccer, ccer_backup;
/*
* If channels enable bits don't exist writing 1 will have no
* effect so we can detect and count them.
*/
regmap_read(priv->regmap, TIM_CCER, &ccer_backup);
regmap_set_bits(priv->regmap, TIM_CCER, TIM_CCER_CCXE);
regmap_read(priv->regmap, TIM_CCER, &ccer);
regmap_clear_bits(priv->regmap, TIM_CCER, TIM_CCER_CCXE);
regmap_write(priv->regmap, TIM_CCER, ccer_backup);
if (ccer & TIM_CCER_CC1E)
npwm++;
*num_enabled = hweight32(ccer_backup & TIM_CCER_CCXE);
if (ccer & TIM_CCER_CC2E)
npwm++;
if (ccer & TIM_CCER_CC3E)
npwm++;
if (ccer & TIM_CCER_CC4E)
npwm++;
return npwm;
return hweight32(ccer & TIM_CCER_CCXE);
}
static int stm32_pwm_probe(struct platform_device *pdev)
@ -612,6 +630,8 @@ static int stm32_pwm_probe(struct platform_device *pdev)
struct device_node *np = dev->of_node;
struct stm32_timers *ddata = dev_get_drvdata(pdev->dev.parent);
struct stm32_pwm *priv;
unsigned int num_enabled;
unsigned int i;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@ -634,7 +654,11 @@ static int stm32_pwm_probe(struct platform_device *pdev)
priv->chip.dev = dev;
priv->chip.ops = &stm32pwm_ops;
priv->chip.npwm = stm32_pwm_detect_channels(priv);
priv->chip.npwm = stm32_pwm_detect_channels(priv, &num_enabled);
/* Initialize clock refcount to number of enabled PWM channels. */
for (i = 0; i < num_enabled; i++)
clk_enable(priv->clk);
ret = devm_pwmchip_add(dev, &priv->chip);
if (ret < 0)
@ -645,7 +669,7 @@ static int stm32_pwm_probe(struct platform_device *pdev)
return 0;
}
static int __maybe_unused stm32_pwm_suspend(struct device *dev)
static int stm32_pwm_suspend(struct device *dev)
{
struct stm32_pwm *priv = dev_get_drvdata(dev);
unsigned int i;
@ -666,7 +690,7 @@ static int __maybe_unused stm32_pwm_suspend(struct device *dev)
return pinctrl_pm_select_sleep_state(dev);
}
static int __maybe_unused stm32_pwm_resume(struct device *dev)
static int stm32_pwm_resume(struct device *dev)
{
struct stm32_pwm *priv = dev_get_drvdata(dev);
int ret;
@ -679,7 +703,7 @@ static int __maybe_unused stm32_pwm_resume(struct device *dev)
return stm32_pwm_apply_breakinputs(priv);
}
static SIMPLE_DEV_PM_OPS(stm32_pwm_pm_ops, stm32_pwm_suspend, stm32_pwm_resume);
static DEFINE_SIMPLE_DEV_PM_OPS(stm32_pwm_pm_ops, stm32_pwm_suspend, stm32_pwm_resume);
static const struct of_device_id stm32_pwm_of_match[] = {
{ .compatible = "st,stm32-pwm", },
@ -692,7 +716,7 @@ static struct platform_driver stm32_pwm_driver = {
.driver = {
.name = "stm32-pwm",
.of_match_table = stm32_pwm_of_match,
.pm = &stm32_pwm_pm_ops,
.pm = pm_ptr(&stm32_pwm_pm_ops),
},
};
module_platform_driver(stm32_pwm_driver);

View File

@ -44,7 +44,7 @@ static int stmpe_24xx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
ret = stmpe_reg_read(stmpe_pwm->stmpe, STMPE24XX_PWMCS);
if (ret < 0) {
dev_err(chip->dev, "error reading PWM#%u control\n",
dev_dbg(chip->dev, "error reading PWM#%u control\n",
pwm->hwpwm);
return ret;
}
@ -53,7 +53,7 @@ static int stmpe_24xx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
ret = stmpe_reg_write(stmpe_pwm->stmpe, STMPE24XX_PWMCS, value);
if (ret) {
dev_err(chip->dev, "error writing PWM#%u control\n",
dev_dbg(chip->dev, "error writing PWM#%u control\n",
pwm->hwpwm);
return ret;
}
@ -70,7 +70,7 @@ static int stmpe_24xx_pwm_disable(struct pwm_chip *chip,
ret = stmpe_reg_read(stmpe_pwm->stmpe, STMPE24XX_PWMCS);
if (ret < 0) {
dev_err(chip->dev, "error reading PWM#%u control\n",
dev_dbg(chip->dev, "error reading PWM#%u control\n",
pwm->hwpwm);
return ret;
}
@ -79,7 +79,7 @@ static int stmpe_24xx_pwm_disable(struct pwm_chip *chip,
ret = stmpe_reg_write(stmpe_pwm->stmpe, STMPE24XX_PWMCS, value);
if (ret)
dev_err(chip->dev, "error writing PWM#%u control\n",
dev_dbg(chip->dev, "error writing PWM#%u control\n",
pwm->hwpwm);
return ret;
}
@ -233,7 +233,7 @@ static int stmpe_24xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
ret = stmpe_reg_write(stmpe_pwm->stmpe, offset, value);
if (ret) {
dev_err(chip->dev, "error writing register %02x: %d\n",
dev_dbg(chip->dev, "error writing register %02x: %d\n",
offset, ret);
return ret;
}
@ -242,7 +242,7 @@ static int stmpe_24xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
ret = stmpe_reg_write(stmpe_pwm->stmpe, offset, value);
if (ret) {
dev_err(chip->dev, "error writing register %02x: %d\n",
dev_dbg(chip->dev, "error writing register %02x: %d\n",
offset, ret);
return ret;
}
@ -275,7 +275,7 @@ static int stmpe_24xx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return 0;
}
err = stmpe_24xx_pwm_config(pwm->chip, pwm, state->duty_cycle, state->period);
err = stmpe_24xx_pwm_config(chip, pwm, state->duty_cycle, state->period);
if (err)
return err;

View File

@ -256,7 +256,7 @@ static int tegra_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return 0;
}
err = tegra_pwm_config(pwm->chip, pwm, state->duty_cycle, state->period);
err = tegra_pwm_config(chip, pwm, state->duty_cycle, state->period);
if (err)
return err;

View File

@ -269,7 +269,6 @@ static void ecap_pwm_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
}
#ifdef CONFIG_PM_SLEEP
static void ecap_pwm_save_context(struct ecap_pwm_chip *pc)
{
pm_runtime_get_sync(pc->chip.dev);
@ -312,15 +311,14 @@ static int ecap_pwm_resume(struct device *dev)
ecap_pwm_restore_context(pc);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(ecap_pwm_pm_ops, ecap_pwm_suspend, ecap_pwm_resume);
static DEFINE_SIMPLE_DEV_PM_OPS(ecap_pwm_pm_ops, ecap_pwm_suspend, ecap_pwm_resume);
static struct platform_driver ecap_pwm_driver = {
.driver = {
.name = "ecap",
.of_match_table = ecap_of_match,
.pm = &ecap_pwm_pm_ops,
.pm = pm_ptr(&ecap_pwm_pm_ops),
},
.probe = ecap_pwm_probe,
.remove_new = ecap_pwm_remove,

View File

@ -521,7 +521,6 @@ static void ehrpwm_pwm_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
}
#ifdef CONFIG_PM_SLEEP
static void ehrpwm_pwm_save_context(struct ehrpwm_pwm_chip *pc)
{
pm_runtime_get_sync(pc->chip.dev);
@ -589,16 +588,15 @@ static int ehrpwm_pwm_resume(struct device *dev)
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(ehrpwm_pwm_pm_ops, ehrpwm_pwm_suspend,
static DEFINE_SIMPLE_DEV_PM_OPS(ehrpwm_pwm_pm_ops, ehrpwm_pwm_suspend,
ehrpwm_pwm_resume);
static struct platform_driver ehrpwm_pwm_driver = {
.driver = {
.name = "ehrpwm",
.of_match_table = ehrpwm_of_match,
.pm = &ehrpwm_pwm_pm_ops,
.pm = pm_ptr(&ehrpwm_pwm_pm_ops),
},
.probe = ehrpwm_pwm_probe,
.remove_new = ehrpwm_pwm_remove,

View File

@ -172,10 +172,10 @@ static int twl4030_pwmled_apply(struct pwm_chip *chip, struct pwm_device *pwm,
* We cannot skip calling ->config even if state->period ==
* pwm->state.period && state->duty_cycle == pwm->state.duty_cycle
* because we might have exited early in the last call to
* pwm_apply_state because of !state->enabled and so the two values in
* pwm_apply_might_sleep because of !state->enabled and so the two values in
* pwm->state might not be configured in hardware.
*/
ret = twl4030_pwmled_config(pwm->chip, pwm,
ret = twl4030_pwmled_config(chip, pwm,
state->duty_cycle, state->period);
if (ret)
return ret;
@ -275,7 +275,7 @@ static int twl6030_pwmled_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return 0;
}
err = twl6030_pwmled_config(pwm->chip, pwm,
err = twl6030_pwmled_config(chip, pwm,
state->duty_cycle, state->period);
if (err)
return err;

View File

@ -294,7 +294,7 @@ static int twl4030_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return 0;
}
err = twl_pwm_config(pwm->chip, pwm, state->duty_cycle, state->period);
err = twl_pwm_config(chip, pwm, state->duty_cycle, state->period);
if (err)
return err;
@ -319,7 +319,7 @@ static int twl6030_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return 0;
}
err = twl_pwm_config(pwm->chip, pwm, state->duty_cycle, state->period);
err = twl_pwm_config(chip, pwm, state->duty_cycle, state->period);
if (err)
return err;

View File

@ -206,10 +206,10 @@ static int vt8500_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
* We cannot skip calling ->config even if state->period ==
* pwm->state.period && state->duty_cycle == pwm->state.duty_cycle
* because we might have exited early in the last call to
* pwm_apply_state because of !state->enabled and so the two values in
* pwm_apply_might_sleep because of !state->enabled and so the two values in
* pwm->state might not be configured in hardware.
*/
err = vt8500_pwm_config(pwm->chip, pwm, state->duty_cycle, state->period);
err = vt8500_pwm_config(chip, pwm, state->duty_cycle, state->period);
if (err)
return err;

View File

@ -62,7 +62,7 @@ static ssize_t period_store(struct device *child,
mutex_lock(&export->lock);
pwm_get_state(pwm, &state);
state.period = val;
ret = pwm_apply_state(pwm, &state);
ret = pwm_apply_might_sleep(pwm, &state);
mutex_unlock(&export->lock);
return ret ? : size;
@ -97,7 +97,7 @@ static ssize_t duty_cycle_store(struct device *child,
mutex_lock(&export->lock);
pwm_get_state(pwm, &state);
state.duty_cycle = val;
ret = pwm_apply_state(pwm, &state);
ret = pwm_apply_might_sleep(pwm, &state);
mutex_unlock(&export->lock);
return ret ? : size;
@ -144,7 +144,7 @@ static ssize_t enable_store(struct device *child,
goto unlock;
}
ret = pwm_apply_state(pwm, &state);
ret = pwm_apply_might_sleep(pwm, &state);
unlock:
mutex_unlock(&export->lock);
@ -194,7 +194,7 @@ static ssize_t polarity_store(struct device *child,
mutex_lock(&export->lock);
pwm_get_state(pwm, &state);
state.polarity = polarity;
ret = pwm_apply_state(pwm, &state);
ret = pwm_apply_might_sleep(pwm, &state);
mutex_unlock(&export->lock);
return ret ? : size;
@ -401,7 +401,7 @@ static int pwm_class_apply_state(struct pwm_export *export,
struct pwm_device *pwm,
struct pwm_state *state)
{
int ret = pwm_apply_state(pwm, state);
int ret = pwm_apply_might_sleep(pwm, state);
/* release lock taken in pwm_class_get_state */
mutex_unlock(&export->lock);
@ -510,7 +510,7 @@ void pwmchip_sysfs_export(struct pwm_chip *chip)
* the kernel it's just not exported.
*/
parent = device_create(&pwm_class, chip->dev, MKDEV(0, 0), chip,
"pwmchip%d", chip->base);
"pwmchip%d", chip->id);
if (IS_ERR(parent)) {
dev_warn(chip->dev,
"device_create failed for pwm_chip sysfs export\n");

View File

@ -90,7 +90,7 @@ static int pwm_regulator_set_voltage_sel(struct regulator_dev *rdev,
pwm_set_relative_duty_cycle(&pstate,
drvdata->duty_cycle_table[selector].dutycycle, 100);
ret = pwm_apply_state(drvdata->pwm, &pstate);
ret = pwm_apply_might_sleep(drvdata->pwm, &pstate);
if (ret) {
dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret);
return ret;
@ -216,7 +216,7 @@ static int pwm_regulator_set_voltage(struct regulator_dev *rdev,
pwm_set_relative_duty_cycle(&pstate, dutycycle, duty_unit);
ret = pwm_apply_state(drvdata->pwm, &pstate);
ret = pwm_apply_might_sleep(drvdata->pwm, &pstate);
if (ret) {
dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret);
return ret;

View File

@ -180,7 +180,7 @@ static int lm3630a_pwm_ctrl(struct lm3630a_chip *pchip, int br, int br_max)
pchip->pwmd_state.enabled = pchip->pwmd_state.duty_cycle ? true : false;
return pwm_apply_state(pchip->pwmd, &pchip->pwmd_state);
return pwm_apply_might_sleep(pchip->pwmd, &pchip->pwmd_state);
}
/* update and get brightness */

View File

@ -234,7 +234,7 @@ static int lp855x_pwm_ctrl(struct lp855x *lp, int br, int max_br)
state.duty_cycle = div_u64(br * state.period, max_br);
state.enabled = state.duty_cycle;
return pwm_apply_state(lp->pwm, &state);
return pwm_apply_might_sleep(lp->pwm, &state);
}
static int lp855x_bl_update_status(struct backlight_device *bl)

View File

@ -103,7 +103,7 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
pwm_get_state(pb->pwm, &state);
state.duty_cycle = compute_duty_cycle(pb, brightness, &state);
state.enabled = true;
pwm_apply_state(pb->pwm, &state);
pwm_apply_might_sleep(pb->pwm, &state);
pwm_backlight_power_on(pb);
} else {
@ -120,7 +120,7 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
* inactive output.
*/
state.enabled = !pb->power_supply && !pb->enable_gpio;
pwm_apply_state(pb->pwm, &state);
pwm_apply_might_sleep(pb->pwm, &state);
}
if (pb->notify_after)
@ -528,7 +528,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
if (!state.period && (data->pwm_period_ns > 0))
state.period = data->pwm_period_ns;
ret = pwm_apply_state(pb->pwm, &state);
ret = pwm_apply_might_sleep(pb->pwm, &state);
if (ret) {
dev_err(&pdev->dev, "failed to apply initial PWM state: %d\n",
ret);
@ -633,7 +633,7 @@ static void pwm_backlight_remove(struct platform_device *pdev)
pwm_get_state(pb->pwm, &state);
state.duty_cycle = 0;
state.enabled = false;
pwm_apply_state(pb->pwm, &state);
pwm_apply_might_sleep(pb->pwm, &state);
if (pb->exit)
pb->exit(&pdev->dev);
@ -649,7 +649,7 @@ static void pwm_backlight_shutdown(struct platform_device *pdev)
pwm_get_state(pb->pwm, &state);
state.duty_cycle = 0;
state.enabled = false;
pwm_apply_state(pb->pwm, &state);
pwm_apply_might_sleep(pb->pwm, &state);
}
#ifdef CONFIG_PM_SLEEP
@ -673,7 +673,7 @@ static int pwm_backlight_suspend(struct device *dev)
pwm_get_state(pb->pwm, &state);
state.duty_cycle = 0;
state.enabled = false;
pwm_apply_state(pb->pwm, &state);
pwm_apply_might_sleep(pb->pwm, &state);
if (pb->notify_after)
pb->notify_after(pb->dev, 0);

View File

@ -347,7 +347,7 @@ static int ssd1307fb_init(struct ssd1307fb_par *par)
pwm_init_state(par->pwm, &pwmstate);
pwm_set_relative_duty_cycle(&pwmstate, 50, 100);
pwm_apply_state(par->pwm, &pwmstate);
pwm_apply_might_sleep(par->pwm, &pwmstate);
/* Enable the PWM */
pwm_enable(par->pwm);

View File

@ -69,7 +69,6 @@ struct pwm_state {
* @label: name of the PWM device
* @flags: flags associated with the PWM device
* @hwpwm: per-chip relative index of the PWM device
* @pwm: global index of the PWM device
* @chip: PWM chip providing this PWM device
* @args: PWM arguments
* @state: last applied state
@ -79,7 +78,6 @@ struct pwm_device {
const char *label;
unsigned long flags;
unsigned int hwpwm;
unsigned int pwm;
struct pwm_chip *chip;
struct pwm_args args;
@ -93,8 +91,8 @@ struct pwm_device {
* @state: state to fill with the current PWM state
*
* The returned PWM state represents the state that was applied by a previous call to
* pwm_apply_state(). Drivers may have to slightly tweak that state before programming it to
* hardware. If pwm_apply_state() was never called, this returns either the current hardware
* pwm_apply_might_sleep(). Drivers may have to slightly tweak that state before programming it to
* hardware. If pwm_apply_might_sleep() was never called, this returns either the current hardware
* state (if supported) or the default settings.
*/
static inline void pwm_get_state(const struct pwm_device *pwm,
@ -112,12 +110,6 @@ static inline bool pwm_is_enabled(const struct pwm_device *pwm)
return state.enabled;
}
static inline void pwm_set_period(struct pwm_device *pwm, u64 period)
{
if (pwm)
pwm->state.period = period;
}
static inline u64 pwm_get_period(const struct pwm_device *pwm)
{
struct pwm_state state;
@ -127,12 +119,6 @@ static inline u64 pwm_get_period(const struct pwm_device *pwm)
return state.period;
}
static inline void pwm_set_duty_cycle(struct pwm_device *pwm, unsigned int duty)
{
if (pwm)
pwm->state.duty_cycle = duty;
}
static inline u64 pwm_get_duty_cycle(const struct pwm_device *pwm)
{
struct pwm_state state;
@ -158,20 +144,20 @@ static inline void pwm_get_args(const struct pwm_device *pwm,
}
/**
* pwm_init_state() - prepare a new state to be applied with pwm_apply_state()
* pwm_init_state() - prepare a new state to be applied with pwm_apply_might_sleep()
* @pwm: PWM device
* @state: state to fill with the prepared PWM state
*
* This functions prepares a state that can later be tweaked and applied
* to the PWM device with pwm_apply_state(). This is a convenient function
* to the PWM device with pwm_apply_might_sleep(). This is a convenient function
* that first retrieves the current PWM state and the replaces the period
* and polarity fields with the reference values defined in pwm->args.
* Once the function returns, you can adjust the ->enabled and ->duty_cycle
* fields according to your needs before calling pwm_apply_state().
* fields according to your needs before calling pwm_apply_might_sleep().
*
* ->duty_cycle is initially set to zero to avoid cases where the current
* ->duty_cycle value exceed the pwm_args->period one, which would trigger
* an error if the user calls pwm_apply_state() without adjusting ->duty_cycle
* an error if the user calls pwm_apply_might_sleep() without adjusting ->duty_cycle
* first.
*/
static inline void pwm_init_state(const struct pwm_device *pwm,
@ -227,7 +213,7 @@ pwm_get_relative_duty_cycle(const struct pwm_state *state, unsigned int scale)
*
* pwm_init_state(pwm, &state);
* pwm_set_relative_duty_cycle(&state, 50, 100);
* pwm_apply_state(pwm, &state);
* pwm_apply_might_sleep(pwm, &state);
*
* This functions returns -EINVAL if @duty_cycle and/or @scale are
* inconsistent (@scale == 0 or @duty_cycle > @scale).
@ -282,32 +268,33 @@ struct pwm_ops {
* @dev: device providing the PWMs
* @ops: callbacks for this PWM controller
* @owner: module providing this chip
* @base: number of first PWM controlled by this chip
* @id: unique number of this PWM chip
* @npwm: number of PWMs controlled by this chip
* @of_xlate: request a PWM device given a device tree PWM specifier
* @of_pwm_n_cells: number of cells expected in the device tree PWM specifier
* @list: list node for internal use
* @atomic: can the driver's ->apply() be called in atomic context
* @pwms: array of PWM devices allocated by the framework
*/
struct pwm_chip {
struct device *dev;
const struct pwm_ops *ops;
struct module *owner;
int base;
unsigned int id;
unsigned int npwm;
struct pwm_device * (*of_xlate)(struct pwm_chip *chip,
const struct of_phandle_args *args);
unsigned int of_pwm_n_cells;
bool atomic;
/* only used internally by the PWM framework */
struct list_head list;
struct pwm_device *pwms;
};
#if IS_ENABLED(CONFIG_PWM)
/* PWM user APIs */
int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state);
int pwm_apply_might_sleep(struct pwm_device *pwm, const struct pwm_state *state);
int pwm_apply_atomic(struct pwm_device *pwm, const struct pwm_state *state);
int pwm_adjust_config(struct pwm_device *pwm);
/**
@ -335,7 +322,7 @@ static inline int pwm_config(struct pwm_device *pwm, int duty_ns,
state.duty_cycle = duty_ns;
state.period = period_ns;
return pwm_apply_state(pwm, &state);
return pwm_apply_might_sleep(pwm, &state);
}
/**
@ -356,7 +343,7 @@ static inline int pwm_enable(struct pwm_device *pwm)
return 0;
state.enabled = true;
return pwm_apply_state(pwm, &state);
return pwm_apply_might_sleep(pwm, &state);
}
/**
@ -375,7 +362,18 @@ static inline void pwm_disable(struct pwm_device *pwm)
return;
state.enabled = false;
pwm_apply_state(pwm, &state);
pwm_apply_might_sleep(pwm, &state);
}
/**
* pwm_might_sleep() - is pwm_apply_atomic() supported?
* @pwm: PWM device
*
* Returns: false if pwm_apply_atomic() can be called from atomic context.
*/
static inline bool pwm_might_sleep(struct pwm_device *pwm)
{
return !pwm->chip->atomic;
}
/* PWM provider APIs */
@ -406,16 +404,27 @@ struct pwm_device *devm_fwnode_pwm_get(struct device *dev,
struct fwnode_handle *fwnode,
const char *con_id);
#else
static inline int pwm_apply_state(struct pwm_device *pwm,
static inline bool pwm_might_sleep(struct pwm_device *pwm)
{
return true;
}
static inline int pwm_apply_might_sleep(struct pwm_device *pwm,
const struct pwm_state *state)
{
might_sleep();
return -ENOTSUPP;
return -EOPNOTSUPP;
}
static inline int pwm_apply_atomic(struct pwm_device *pwm,
const struct pwm_state *state)
{
return -EOPNOTSUPP;
}
static inline int pwm_adjust_config(struct pwm_device *pwm)
{
return -ENOTSUPP;
return -EOPNOTSUPP;
}
static inline int pwm_config(struct pwm_device *pwm, int duty_ns,
@ -524,7 +533,14 @@ static inline void pwm_apply_args(struct pwm_device *pwm)
state.period = pwm->args.period;
state.usage_power = false;
pwm_apply_state(pwm, &state);
pwm_apply_might_sleep(pwm, &state);
}
/* only for backwards-compatibility, new code should not use this */
static inline int pwm_apply_state(struct pwm_device *pwm,
const struct pwm_state *state)
{
return pwm_apply_might_sleep(pwm, state);
}
struct pwm_lookup {