mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-23 20:24:12 +08:00
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:
commit
42bff4d0f9
@ -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#
|
||||
|
@ -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>;
|
||||
};
|
@ -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>;
|
||||
};
|
@ -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.
|
||||
|
@ -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>
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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" : "");
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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 = {
|
||||
|
@ -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;
|
||||
|
@ -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),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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[] = {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user