mirror of https://gitee.com/openkylin/linux.git
pwm: Changes for v5.13-rc1
This set of changes adds support for the PWM controller found on Toshiba Visconti SoCs and converts a couple of drivers to the atomic API. There's also a bunch of cleanups and minor fixes across the board. -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEEiOrDCAFJzPfAjcif3SOs138+s6EFAmCS5fUZHHRoaWVycnku cmVkaW5nQGdtYWlsLmNvbQAKCRDdI6zXfz6zoe3FD/9vloMEaieCdiL7ImFSw44b YsKwoyemT2utsAZd0/xckIogB0vU51m/Wx/Xvmlp8Xw1pn512Csi7sd/aD1Ryc6x 2J7HnA9rin/X0wFxspVrZ0OZCEP9d1v4GhPYI1tMQ4RKYxlAU3nC2wx1+W55j0mD dircs7QXg963iYN0bhyl+YrniesfQ6wWPgTC8IRgpozS9cTAk5dKE7chNEhIbyal pdtg3072oFIP3B2kVb9m2sluPSuvPivXLbUs527vhPaiKtfaOmwcZHON6LZk2+87 2fza/6qf061NVmmi9w8BqsFagrTFyQvEHAHoO4E5qlZUWHpzqfiMMxSWOPyVCMLf jmJVBGxVNnB60B+O2+QQgHw8JoO99v84UEpvrhk1Mei1WWZfEfvBV6+jIAU08TwF RLJgw2YFvcmtAZVjNw7hW1JwqMNIfNbM4Y4eWiPIP1qrP32nS85V4m9rHE19kMGh Ww6gSMv7Wsl5COjQ/WnvTzodKemLuJ1dqmpeVdKJw8gluOnKQa0Uu6B/ArricoZI tkODvQdaenjk4rBL9gi6bwN01ubjjDFW3AnBtDSSyrRxw2uGUNmx8N3WxnKiis7O Vp6271hpriqzSomOvCdpc1Oy+iT0iHElioLSzrc4ODOLyHFBmT/LaXhVxEhTwxRy BCyUw/G2AjsjxYzWRwa4zA== =d0HN -----END PGP SIGNATURE----- Merge tag 'pwm/for-5.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm Pull pwm updates from Thierry Reding: "This adds support for the PWM controller found on Toshiba Visconti SoCs and converts a couple of drivers to the atomic API. There's also a bunch of cleanups and minor fixes across the board" * tag 'pwm/for-5.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm: (35 commits) pwm: Reword docs about pwm_apply_state() pwm: atmel: Improve duty cycle calculation in .apply() pwm: atmel: Fix duty cycle calculation in .get_state() pwm: visconti: Add Toshiba Visconti SoC PWM support dt-bindings: pwm: Add bindings for Toshiba Visconti PWM Controller arm64: dts: rockchip: Remove clock-names from PWM nodes ARM: dts: rockchip: Remove clock-names from PWM nodes dt-bindings: pwm: rockchip: Add more compatible strings dt-bindings: pwm: Convert pwm-rockchip.txt to YAML pwm: mediatek: Remove unused function pwm: pca9685: Improve runtime PM behavior pwm: pca9685: Support hardware readout pwm: pca9685: Switch to atomic API pwm: lpss: Don't modify HW state in .remove callback pwm: sti: Free resources only after pwmchip_remove() pwm: sti: Don't modify HW state in .remove callback pwm: lpc3200: Don't modify HW state in .remove callback pwm: lpc18xx-sct: Free resources only after pwmchip_remove() pwm: bcm-kona: Don't modify HW state in .remove callback pwm: bcm2835: Free resources only after pwmchip_remove() ...
This commit is contained in:
commit
7b9df264f0
|
@ -1,27 +0,0 @@
|
|||
Rockchip PWM controller
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "rockchip,<name>-pwm"
|
||||
"rockchip,rk2928-pwm": found on RK29XX,RK3066 and RK3188 SoCs
|
||||
"rockchip,rk3288-pwm": found on RK3288 SOC
|
||||
"rockchip,rv1108-pwm", "rockchip,rk3288-pwm": found on RV1108 SoC
|
||||
"rockchip,vop-pwm": found integrated in VOP on RK3288 SoC
|
||||
- reg: physical base address and length of the controller's registers
|
||||
- clocks: See ../clock/clock-bindings.txt
|
||||
- For older hardware (rk2928, rk3066, rk3188, rk3228, rk3288, rk3399):
|
||||
- There is one clock that's used both to derive the functional clock
|
||||
for the device and as the bus clock.
|
||||
- For newer hardware (rk3328 and future socs): specified by name
|
||||
- "pwm": This is used to derive the functional clock.
|
||||
- "pclk": This is the APB bus clock.
|
||||
- #pwm-cells: must be 2 (rk2928) or 3 (rk3288). See pwm.yaml in this directory
|
||||
for a description of the cell format.
|
||||
|
||||
Example:
|
||||
|
||||
pwm0: pwm@20030000 {
|
||||
compatible = "rockchip,rk2928-pwm";
|
||||
reg = <0x20030000 0x10>;
|
||||
clocks = <&cru PCLK_PWM01>;
|
||||
#pwm-cells = <2>;
|
||||
};
|
|
@ -0,0 +1,100 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/pwm/pwm-rockchip.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Rockchip PWM controller
|
||||
|
||||
maintainers:
|
||||
- Heiko Stuebner <heiko@sntech.de>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: rockchip,rk2928-pwm
|
||||
- const: rockchip,rk3288-pwm
|
||||
- const: rockchip,rk3328-pwm
|
||||
- const: rockchip,vop-pwm
|
||||
- items:
|
||||
- const: rockchip,rk3036-pwm
|
||||
- const: rockchip,rk2928-pwm
|
||||
- items:
|
||||
- enum:
|
||||
- rockchip,rk3368-pwm
|
||||
- rockchip,rk3399-pwm
|
||||
- rockchip,rv1108-pwm
|
||||
- const: rockchip,rk3288-pwm
|
||||
- items:
|
||||
- enum:
|
||||
- rockchip,px30-pwm
|
||||
- rockchip,rk3308-pwm
|
||||
- const: rockchip,rk3328-pwm
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
maxItems: 2
|
||||
|
||||
"#pwm-cells":
|
||||
enum: [2, 3]
|
||||
description:
|
||||
Must be 2 (rk2928) or 3 (rk3288 and later).
|
||||
See pwm.yaml for a description of the cell format.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- "#pwm-cells"
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- rockchip,rk3328-pwm
|
||||
- rockchip,rv1108-pwm
|
||||
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
items:
|
||||
- description: Used to derive the functional clock for the device.
|
||||
- description: Used as the APB bus clock.
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: pwm
|
||||
- const: pclk
|
||||
|
||||
required:
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
else:
|
||||
properties:
|
||||
clocks:
|
||||
maxItems: 1
|
||||
description:
|
||||
Used both to derive the functional clock
|
||||
for the device and as the bus clock.
|
||||
|
||||
required:
|
||||
- clocks
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/rk3188-cru-common.h>
|
||||
pwm0: pwm@20030000 {
|
||||
compatible = "rockchip,rk2928-pwm";
|
||||
reg = <0x20030000 0x10>;
|
||||
clocks = <&cru PCLK_PWM01>;
|
||||
#pwm-cells = <2>;
|
||||
};
|
|
@ -0,0 +1,43 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/pwm/toshiba,pwm-visconti.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Toshiba Visconti PWM Controller
|
||||
|
||||
maintainers:
|
||||
- Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: toshiba,visconti-pwm
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
'#pwm-cells':
|
||||
const: 2
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- '#pwm-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
soc {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
pwm: pwm@241c0000 {
|
||||
compatible = "toshiba,visconti-pwm";
|
||||
reg = <0 0x241c0000 0 0x1000>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pwm_mux>;
|
||||
#pwm-cells = <2>;
|
||||
};
|
||||
};
|
|
@ -55,7 +55,11 @@ 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().
|
||||
|
||||
The PWM user API also allows one to query the PWM state with pwm_get_state().
|
||||
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
|
||||
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.
|
||||
|
||||
In addition to the PWM state, the PWM API also exposes PWM arguments, which
|
||||
are the reference PWM config one should use on this PWM.
|
||||
|
|
|
@ -355,7 +355,6 @@ pwm0: pwm@20050000 {
|
|||
reg = <0x20050000 0x10>;
|
||||
#pwm-cells = <3>;
|
||||
clocks = <&cru PCLK_PWM>;
|
||||
clock-names = "pwm";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pwm0_pin>;
|
||||
status = "disabled";
|
||||
|
@ -366,7 +365,6 @@ pwm1: pwm@20050010 {
|
|||
reg = <0x20050010 0x10>;
|
||||
#pwm-cells = <3>;
|
||||
clocks = <&cru PCLK_PWM>;
|
||||
clock-names = "pwm";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pwm1_pin>;
|
||||
status = "disabled";
|
||||
|
@ -377,7 +375,6 @@ pwm2: pwm@20050020 {
|
|||
reg = <0x20050020 0x10>;
|
||||
#pwm-cells = <3>;
|
||||
clocks = <&cru PCLK_PWM>;
|
||||
clock-names = "pwm";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pwm2_pin>;
|
||||
status = "disabled";
|
||||
|
@ -388,7 +385,6 @@ pwm3: pwm@20050030 {
|
|||
reg = <0x20050030 0x10>;
|
||||
#pwm-cells = <2>;
|
||||
clocks = <&cru PCLK_PWM>;
|
||||
clock-names = "pwm";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pwm3_pin>;
|
||||
status = "disabled";
|
||||
|
|
|
@ -679,7 +679,6 @@ pwm0: pwm@ff680000 {
|
|||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pwm0_pin>;
|
||||
clocks = <&cru PCLK_RKPWM>;
|
||||
clock-names = "pwm";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -690,7 +689,6 @@ pwm1: pwm@ff680010 {
|
|||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pwm1_pin>;
|
||||
clocks = <&cru PCLK_RKPWM>;
|
||||
clock-names = "pwm";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -701,7 +699,6 @@ pwm2: pwm@ff680020 {
|
|||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pwm2_pin>;
|
||||
clocks = <&cru PCLK_RKPWM>;
|
||||
clock-names = "pwm";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -712,7 +709,6 @@ pwm3: pwm@ff680030 {
|
|||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pwm3_pin>;
|
||||
clocks = <&cru PCLK_RKPWM>;
|
||||
clock-names = "pwm";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
|
|
@ -558,7 +558,6 @@ pwm0: pwm@ff680000 {
|
|||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pwm0_pin>;
|
||||
clocks = <&cru PCLK_PWM1>;
|
||||
clock-names = "pwm";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -569,7 +568,6 @@ pwm1: pwm@ff680010 {
|
|||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pwm1_pin>;
|
||||
clocks = <&cru PCLK_PWM1>;
|
||||
clock-names = "pwm";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -578,7 +576,6 @@ pwm2: pwm@ff680020 {
|
|||
reg = <0x0 0xff680020 0x0 0x10>;
|
||||
#pwm-cells = <3>;
|
||||
clocks = <&cru PCLK_PWM1>;
|
||||
clock-names = "pwm";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -589,7 +586,6 @@ pwm3: pwm@ff680030 {
|
|||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pwm3_pin>;
|
||||
clocks = <&cru PCLK_PWM1>;
|
||||
clock-names = "pwm";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
|
|
@ -1182,7 +1182,6 @@ pwm0: pwm@ff420000 {
|
|||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pwm0_pin>;
|
||||
clocks = <&pmucru PCLK_RKPWM_PMU>;
|
||||
clock-names = "pwm";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -1193,7 +1192,6 @@ pwm1: pwm@ff420010 {
|
|||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pwm1_pin>;
|
||||
clocks = <&pmucru PCLK_RKPWM_PMU>;
|
||||
clock-names = "pwm";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -1204,7 +1202,6 @@ pwm2: pwm@ff420020 {
|
|||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pwm2_pin>;
|
||||
clocks = <&pmucru PCLK_RKPWM_PMU>;
|
||||
clock-names = "pwm";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -1215,7 +1212,6 @@ pwm3: pwm@ff420030 {
|
|||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pwm3a_pin>;
|
||||
clocks = <&pmucru PCLK_RKPWM_PMU>;
|
||||
clock-names = "pwm";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
|
|
@ -618,6 +618,15 @@ config PWM_TWL_LED
|
|||
To compile this driver as a module, choose M here: the module
|
||||
will be called pwm-twl-led.
|
||||
|
||||
config PWM_VISCONTI
|
||||
tristate "Toshiba Visconti PWM support"
|
||||
depends on ARCH_VISCONTI || COMPILE_TEST
|
||||
help
|
||||
PWM Subsystem driver support for Toshiba Visconti SoCs.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called pwm-visconti.
|
||||
|
||||
config PWM_VT8500
|
||||
tristate "vt8500 PWM support"
|
||||
depends on ARCH_VT8500 || COMPILE_TEST
|
||||
|
|
|
@ -58,4 +58,5 @@ obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o
|
|||
obj-$(CONFIG_PWM_TIEHRPWM) += pwm-tiehrpwm.o
|
||||
obj-$(CONFIG_PWM_TWL) += pwm-twl.o
|
||||
obj-$(CONFIG_PWM_TWL_LED) += pwm-twl-led.o
|
||||
obj-$(CONFIG_PWM_VISCONTI) += pwm-visconti.o
|
||||
obj-$(CONFIG_PWM_VT8500) += pwm-vt8500.o
|
||||
|
|
|
@ -37,23 +37,13 @@ static struct pwm_device *pwm_to_device(unsigned int pwm)
|
|||
return radix_tree_lookup(&pwm_tree, pwm);
|
||||
}
|
||||
|
||||
static int alloc_pwms(int pwm, unsigned int count)
|
||||
static int alloc_pwms(unsigned int count)
|
||||
{
|
||||
unsigned int from = 0;
|
||||
unsigned int start;
|
||||
|
||||
if (pwm >= MAX_PWMS)
|
||||
return -EINVAL;
|
||||
|
||||
if (pwm >= 0)
|
||||
from = pwm;
|
||||
|
||||
start = bitmap_find_next_zero_area(allocated_pwms, MAX_PWMS, from,
|
||||
start = bitmap_find_next_zero_area(allocated_pwms, MAX_PWMS, 0,
|
||||
count, 0);
|
||||
|
||||
if (pwm >= 0 && start != pwm)
|
||||
return -EEXIST;
|
||||
|
||||
if (start + count > MAX_PWMS)
|
||||
return -ENOSPC;
|
||||
|
||||
|
@ -260,18 +250,14 @@ static bool pwm_ops_check(const struct pwm_chip *chip)
|
|||
}
|
||||
|
||||
/**
|
||||
* pwmchip_add_with_polarity() - register a new PWM chip
|
||||
* pwmchip_add() - register a new PWM chip
|
||||
* @chip: the PWM chip to add
|
||||
* @polarity: initial polarity of PWM channels
|
||||
*
|
||||
* Register a new PWM chip. If chip->base < 0 then a dynamically assigned base
|
||||
* will be used. The initial polarity for all channels is specified by the
|
||||
* @polarity parameter.
|
||||
* Register a new PWM chip.
|
||||
*
|
||||
* Returns: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int pwmchip_add_with_polarity(struct pwm_chip *chip,
|
||||
enum pwm_polarity polarity)
|
||||
int pwmchip_add(struct pwm_chip *chip)
|
||||
{
|
||||
struct pwm_device *pwm;
|
||||
unsigned int i;
|
||||
|
@ -285,25 +271,24 @@ int pwmchip_add_with_polarity(struct pwm_chip *chip,
|
|||
|
||||
mutex_lock(&pwm_lock);
|
||||
|
||||
ret = alloc_pwms(chip->base, chip->npwm);
|
||||
ret = alloc_pwms(chip->npwm);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
chip->base = ret;
|
||||
|
||||
chip->pwms = kcalloc(chip->npwm, sizeof(*pwm), GFP_KERNEL);
|
||||
if (!chip->pwms) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
chip->base = ret;
|
||||
|
||||
for (i = 0; i < chip->npwm; i++) {
|
||||
pwm = &chip->pwms[i];
|
||||
|
||||
pwm->chip = chip;
|
||||
pwm->pwm = chip->base + i;
|
||||
pwm->hwpwm = i;
|
||||
pwm->state.polarity = polarity;
|
||||
|
||||
radix_tree_insert(&pwm_tree, pwm->pwm, pwm);
|
||||
}
|
||||
|
@ -326,21 +311,6 @@ int pwmchip_add_with_polarity(struct pwm_chip *chip,
|
|||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pwmchip_add_with_polarity);
|
||||
|
||||
/**
|
||||
* pwmchip_add() - register a new PWM chip
|
||||
* @chip: the PWM chip to add
|
||||
*
|
||||
* Register a new PWM chip. If chip->base < 0 then a dynamically assigned base
|
||||
* will be used. The initial polarity for all channels is normal.
|
||||
*
|
||||
* Returns: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int pwmchip_add(struct pwm_chip *chip)
|
||||
{
|
||||
return pwmchip_add_with_polarity(chip, PWM_POLARITY_NORMAL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pwmchip_add);
|
||||
|
||||
/**
|
||||
|
@ -607,7 +577,7 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state)
|
|||
*/
|
||||
if (state->polarity != pwm->state.polarity) {
|
||||
if (!chip->ops->set_polarity)
|
||||
return -ENOTSUPP;
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Changing the polarity of a running PWM is
|
||||
|
|
|
@ -24,23 +24,37 @@ struct ab8500_pwm_chip {
|
|||
struct pwm_chip chip;
|
||||
};
|
||||
|
||||
static int ab8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
int duty_ns, int period_ns)
|
||||
static int ab8500_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned int higher_val, lower_val;
|
||||
int ret;
|
||||
u8 reg;
|
||||
unsigned int higher_val, lower_val;
|
||||
|
||||
if (state->polarity != PWM_POLARITY_NORMAL)
|
||||
return -EINVAL;
|
||||
|
||||
if (!state->enabled) {
|
||||
ret = abx500_mask_and_set_register_interruptible(chip->dev,
|
||||
AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG,
|
||||
1 << (chip->base - 1), 0);
|
||||
|
||||
if (ret < 0)
|
||||
dev_err(chip->dev, "%s: Failed to disable PWM, Error %d\n",
|
||||
pwm->label, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* get the first 8 bits that are be written to
|
||||
* AB8500_PWM_OUT_CTRL1_REG[0:7]
|
||||
*/
|
||||
lower_val = duty_ns & 0x00FF;
|
||||
lower_val = state->duty_cycle & 0x00FF;
|
||||
/*
|
||||
* get bits [9:10] that are to be written to
|
||||
* AB8500_PWM_OUT_CTRL2_REG[0:1]
|
||||
*/
|
||||
higher_val = ((duty_ns & 0x0300) >> 8);
|
||||
higher_val = ((state->duty_cycle & 0x0300) >> 8);
|
||||
|
||||
reg = AB8500_PWM_OUT_CTRL1_REG + ((chip->base - 1) * 2);
|
||||
|
||||
|
@ -48,15 +62,11 @@ static int ab8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
|||
reg, (u8)lower_val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = abx500_set_register_interruptible(chip->dev, AB8500_MISC,
|
||||
(reg + 1), (u8)higher_val);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ab8500_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
int ret;
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = abx500_mask_and_set_register_interruptible(chip->dev,
|
||||
AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG,
|
||||
|
@ -64,25 +74,12 @@ static int ab8500_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
|||
if (ret < 0)
|
||||
dev_err(chip->dev, "%s: Failed to enable PWM, Error %d\n",
|
||||
pwm->label, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ab8500_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = abx500_mask_and_set_register_interruptible(chip->dev,
|
||||
AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG,
|
||||
1 << (chip->base - 1), 0);
|
||||
if (ret < 0)
|
||||
dev_err(chip->dev, "%s: Failed to disable PWM, Error %d\n",
|
||||
pwm->label, ret);
|
||||
}
|
||||
|
||||
static const struct pwm_ops ab8500_pwm_ops = {
|
||||
.config = ab8500_pwm_config,
|
||||
.enable = ab8500_pwm_enable,
|
||||
.disable = ab8500_pwm_disable,
|
||||
.apply = ab8500_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
@ -101,7 +98,6 @@ static int ab8500_pwm_probe(struct platform_device *pdev)
|
|||
|
||||
ab8500->chip.dev = &pdev->dev;
|
||||
ab8500->chip.ops = &ab8500_pwm_ops;
|
||||
ab8500->chip.base = -1;
|
||||
ab8500->chip.npwm = 1;
|
||||
|
||||
err = pwmchip_add(&ab8500->chip);
|
||||
|
|
|
@ -265,12 +265,11 @@ static int atmel_hlcdc_pwm_probe(struct platform_device *pdev)
|
|||
chip->hlcdc = hlcdc;
|
||||
chip->chip.ops = &atmel_hlcdc_pwm_ops;
|
||||
chip->chip.dev = dev;
|
||||
chip->chip.base = -1;
|
||||
chip->chip.npwm = 1;
|
||||
chip->chip.of_xlate = of_pwm_xlate_with_flags;
|
||||
chip->chip.of_pwm_n_cells = 3;
|
||||
|
||||
ret = pwmchip_add_with_polarity(&chip->chip, PWM_POLARITY_INVERSED);
|
||||
ret = pwmchip_add(&chip->chip);
|
||||
if (ret) {
|
||||
clk_disable_unprepare(hlcdc->periph_clk);
|
||||
return ret;
|
||||
|
|
|
@ -362,20 +362,37 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
|||
tcbpwm->div = i;
|
||||
tcbpwm->duty = duty;
|
||||
|
||||
/* If the PWM is enabled, call enable to apply the new conf */
|
||||
if (pwm_is_enabled(pwm))
|
||||
atmel_tcb_pwm_enable(chip, pwm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atmel_tcb_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
int duty_cycle, period;
|
||||
int ret;
|
||||
|
||||
/* This function only sets a flag in driver data */
|
||||
atmel_tcb_pwm_set_polarity(chip, pwm, state->polarity);
|
||||
|
||||
if (!state->enabled) {
|
||||
atmel_tcb_pwm_disable(chip, pwm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
period = state->period < INT_MAX ? state->period : INT_MAX;
|
||||
duty_cycle = state->duty_cycle < INT_MAX ? state->duty_cycle : INT_MAX;
|
||||
|
||||
ret = atmel_tcb_pwm_config(chip, pwm, duty_cycle, period);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return atmel_tcb_pwm_enable(chip, pwm);
|
||||
}
|
||||
|
||||
static const struct pwm_ops atmel_tcb_pwm_ops = {
|
||||
.request = atmel_tcb_pwm_request,
|
||||
.free = atmel_tcb_pwm_free,
|
||||
.config = atmel_tcb_pwm_config,
|
||||
.set_polarity = atmel_tcb_pwm_set_polarity,
|
||||
.enable = atmel_tcb_pwm_enable,
|
||||
.disable = atmel_tcb_pwm_disable,
|
||||
.apply = atmel_tcb_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
@ -454,7 +471,6 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev)
|
|||
tcbpwm->chip.ops = &atmel_tcb_pwm_ops;
|
||||
tcbpwm->chip.of_xlate = of_pwm_xlate_with_flags;
|
||||
tcbpwm->chip.of_pwm_n_cells = 3;
|
||||
tcbpwm->chip.base = -1;
|
||||
tcbpwm->chip.npwm = NPWM;
|
||||
tcbpwm->channel = channel;
|
||||
tcbpwm->regmap = regmap;
|
||||
|
@ -491,14 +507,14 @@ static int atmel_tcb_pwm_remove(struct platform_device *pdev)
|
|||
struct atmel_tcb_pwm_chip *tcbpwm = platform_get_drvdata(pdev);
|
||||
int err;
|
||||
|
||||
clk_disable_unprepare(tcbpwm->slow_clk);
|
||||
clk_put(tcbpwm->slow_clk);
|
||||
clk_put(tcbpwm->clk);
|
||||
|
||||
err = pwmchip_remove(&tcbpwm->chip);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
clk_disable_unprepare(tcbpwm->slow_clk);
|
||||
clk_put(tcbpwm->slow_clk);
|
||||
clk_put(tcbpwm->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -124,6 +124,7 @@ static inline void atmel_pwm_ch_writel(struct atmel_pwm_chip *chip,
|
|||
}
|
||||
|
||||
static int atmel_pwm_calculate_cprd_and_pres(struct pwm_chip *chip,
|
||||
unsigned long clkrate,
|
||||
const struct pwm_state *state,
|
||||
unsigned long *cprd, u32 *pres)
|
||||
{
|
||||
|
@ -132,7 +133,7 @@ static int atmel_pwm_calculate_cprd_and_pres(struct pwm_chip *chip,
|
|||
int shift;
|
||||
|
||||
/* Calculate the period cycles and prescale value */
|
||||
cycles *= clk_get_rate(atmel_pwm->clk);
|
||||
cycles *= clkrate;
|
||||
do_div(cycles, NSEC_PER_SEC);
|
||||
|
||||
/*
|
||||
|
@ -158,12 +159,14 @@ static int atmel_pwm_calculate_cprd_and_pres(struct pwm_chip *chip,
|
|||
}
|
||||
|
||||
static void atmel_pwm_calculate_cdty(const struct pwm_state *state,
|
||||
unsigned long cprd, unsigned long *cdty)
|
||||
unsigned long clkrate, unsigned long cprd,
|
||||
u32 pres, unsigned long *cdty)
|
||||
{
|
||||
unsigned long long cycles = state->duty_cycle;
|
||||
|
||||
cycles *= cprd;
|
||||
do_div(cycles, state->period);
|
||||
cycles *= clkrate;
|
||||
do_div(cycles, NSEC_PER_SEC);
|
||||
cycles >>= pres;
|
||||
*cdty = cprd - cycles;
|
||||
}
|
||||
|
||||
|
@ -244,17 +247,23 @@ static int atmel_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
|||
pwm_get_state(pwm, &cstate);
|
||||
|
||||
if (state->enabled) {
|
||||
unsigned long clkrate = clk_get_rate(atmel_pwm->clk);
|
||||
|
||||
if (cstate.enabled &&
|
||||
cstate.polarity == state->polarity &&
|
||||
cstate.period == state->period) {
|
||||
u32 cmr = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm, PWM_CMR);
|
||||
|
||||
cprd = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm,
|
||||
atmel_pwm->data->regs.period);
|
||||
atmel_pwm_calculate_cdty(state, cprd, &cdty);
|
||||
pres = cmr & PWM_CMR_CPRE_MSK;
|
||||
|
||||
atmel_pwm_calculate_cdty(state, clkrate, cprd, pres, &cdty);
|
||||
atmel_pwm_update_cdty(chip, pwm, cdty);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = atmel_pwm_calculate_cprd_and_pres(chip, state, &cprd,
|
||||
ret = atmel_pwm_calculate_cprd_and_pres(chip, clkrate, state, &cprd,
|
||||
&pres);
|
||||
if (ret) {
|
||||
dev_err(chip->dev,
|
||||
|
@ -262,7 +271,7 @@ static int atmel_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
|||
return ret;
|
||||
}
|
||||
|
||||
atmel_pwm_calculate_cdty(state, cprd, &cdty);
|
||||
atmel_pwm_calculate_cdty(state, clkrate, cprd, pres, &cdty);
|
||||
|
||||
if (cstate.enabled) {
|
||||
atmel_pwm_disable(chip, pwm, false);
|
||||
|
@ -319,7 +328,7 @@ static void atmel_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
|||
|
||||
cdty = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm,
|
||||
atmel_pwm->data->regs.duty);
|
||||
tmp = (u64)cdty * NSEC_PER_SEC;
|
||||
tmp = (u64)(cprd - cdty) * NSEC_PER_SEC;
|
||||
tmp <<= pres;
|
||||
state->duty_cycle = DIV64_U64_ROUND_UP(tmp, rate);
|
||||
|
||||
|
@ -429,7 +438,6 @@ static int atmel_pwm_probe(struct platform_device *pdev)
|
|||
atmel_pwm->chip.ops = &atmel_pwm_ops;
|
||||
atmel_pwm->chip.of_xlate = of_pwm_xlate_with_flags;
|
||||
atmel_pwm->chip.of_pwm_n_cells = 3;
|
||||
atmel_pwm->chip.base = -1;
|
||||
atmel_pwm->chip.npwm = 4;
|
||||
|
||||
ret = pwmchip_add(&atmel_pwm->chip);
|
||||
|
@ -451,10 +459,12 @@ static int atmel_pwm_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct atmel_pwm_chip *atmel_pwm = platform_get_drvdata(pdev);
|
||||
|
||||
pwmchip_remove(&atmel_pwm->chip);
|
||||
|
||||
clk_unprepare(atmel_pwm->clk);
|
||||
mutex_destroy(&atmel_pwm->isr_lock);
|
||||
|
||||
return pwmchip_remove(&atmel_pwm->chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver atmel_pwm_driver = {
|
||||
|
|
|
@ -209,7 +209,6 @@ static int iproc_pwmc_probe(struct platform_device *pdev)
|
|||
|
||||
ip->chip.dev = &pdev->dev;
|
||||
ip->chip.ops = &iproc_pwm_ops;
|
||||
ip->chip.base = -1;
|
||||
ip->chip.npwm = 4;
|
||||
ip->chip.of_xlate = of_pwm_xlate_with_flags;
|
||||
ip->chip.of_pwm_n_cells = 3;
|
||||
|
@ -254,9 +253,11 @@ static int iproc_pwmc_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct iproc_pwmc *ip = platform_get_drvdata(pdev);
|
||||
|
||||
pwmchip_remove(&ip->chip);
|
||||
|
||||
clk_disable_unprepare(ip->clk);
|
||||
|
||||
return pwmchip_remove(&ip->chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id bcm_iproc_pwmc_dt[] = {
|
||||
|
|
|
@ -271,7 +271,6 @@ static int kona_pwmc_probe(struct platform_device *pdev)
|
|||
|
||||
kp->chip.dev = &pdev->dev;
|
||||
kp->chip.ops = &kona_pwm_ops;
|
||||
kp->chip.base = -1;
|
||||
kp->chip.npwm = 6;
|
||||
kp->chip.of_xlate = of_pwm_xlate_with_flags;
|
||||
kp->chip.of_pwm_n_cells = 3;
|
||||
|
@ -301,7 +300,7 @@ static int kona_pwmc_probe(struct platform_device *pdev)
|
|||
|
||||
clk_disable_unprepare(kp->clk);
|
||||
|
||||
ret = pwmchip_add_with_polarity(&kp->chip, PWM_POLARITY_INVERSED);
|
||||
ret = pwmchip_add(&kp->chip);
|
||||
if (ret < 0)
|
||||
dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
|
||||
|
||||
|
@ -311,11 +310,6 @@ static int kona_pwmc_probe(struct platform_device *pdev)
|
|||
static int kona_pwmc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct kona_pwmc *kp = platform_get_drvdata(pdev);
|
||||
unsigned int chan;
|
||||
|
||||
for (chan = 0; chan < kp->chip.npwm; chan++)
|
||||
if (pwm_is_enabled(&kp->chip.pwms[chan]))
|
||||
clk_disable_unprepare(kp->clk);
|
||||
|
||||
return pwmchip_remove(&kp->chip);
|
||||
}
|
||||
|
|
|
@ -64,8 +64,9 @@ 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;
|
||||
unsigned long scaler;
|
||||
unsigned long long period_cycles;
|
||||
u64 max_period;
|
||||
|
||||
u32 val;
|
||||
|
||||
if (!rate) {
|
||||
|
@ -73,18 +74,36 @@ static int bcm2835_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
scaler = DIV_ROUND_CLOSEST(NSEC_PER_SEC, rate);
|
||||
/* set period */
|
||||
period = DIV_ROUND_CLOSEST_ULL(state->period, scaler);
|
||||
/*
|
||||
* 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
|
||||
* multiplication period * rate doesn't overflow.
|
||||
* To calculate the maximal possible period that guarantees the
|
||||
* above inequality:
|
||||
*
|
||||
* round(period * rate / NSEC_PER_SEC) <= U32_MAX
|
||||
* <=> period * rate / NSEC_PER_SEC < U32_MAX + 0.5
|
||||
* <=> period * rate < (U32_MAX + 0.5) * NSEC_PER_SEC
|
||||
* <=> period < ((U32_MAX + 0.5) * NSEC_PER_SEC) / rate
|
||||
* <=> 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;
|
||||
|
||||
/* dont accept a period that is too small or has been truncated */
|
||||
if ((period < PERIOD_MIN) || (period > U32_MAX))
|
||||
if (state->period > max_period)
|
||||
return -EINVAL;
|
||||
|
||||
writel(period, pc->base + PERIOD(pwm->hwpwm));
|
||||
/* set period */
|
||||
period_cycles = DIV_ROUND_CLOSEST_ULL(state->period * rate, NSEC_PER_SEC);
|
||||
|
||||
/* don't accept a period that is too small */
|
||||
if (period_cycles < PERIOD_MIN)
|
||||
return -EINVAL;
|
||||
|
||||
writel(period_cycles, pc->base + PERIOD(pwm->hwpwm));
|
||||
|
||||
/* set duty cycle */
|
||||
val = DIV_ROUND_CLOSEST_ULL(state->duty_cycle, scaler);
|
||||
val = DIV_ROUND_CLOSEST_ULL(state->duty_cycle * rate, NSEC_PER_SEC);
|
||||
writel(val, pc->base + DUTY(pwm->hwpwm));
|
||||
|
||||
/* set polarity */
|
||||
|
@ -139,7 +158,6 @@ static int bcm2835_pwm_probe(struct platform_device *pdev)
|
|||
|
||||
pc->chip.dev = &pdev->dev;
|
||||
pc->chip.ops = &bcm2835_pwm_ops;
|
||||
pc->chip.base = -1;
|
||||
pc->chip.npwm = 2;
|
||||
pc->chip.of_xlate = of_pwm_xlate_with_flags;
|
||||
pc->chip.of_pwm_n_cells = 3;
|
||||
|
@ -161,9 +179,11 @@ static int bcm2835_pwm_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct bcm2835_pwm *pc = platform_get_drvdata(pdev);
|
||||
|
||||
pwmchip_remove(&pc->chip);
|
||||
|
||||
clk_disable_unprepare(pc->clk);
|
||||
|
||||
return pwmchip_remove(&pc->chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id bcm2835_pwm_of_match[] = {
|
||||
|
|
|
@ -206,7 +206,6 @@ static int berlin_pwm_probe(struct platform_device *pdev)
|
|||
|
||||
pwm->chip.dev = &pdev->dev;
|
||||
pwm->chip.ops = &berlin_pwm_ops;
|
||||
pwm->chip.base = -1;
|
||||
pwm->chip.npwm = 4;
|
||||
pwm->chip.of_xlate = of_pwm_xlate_with_flags;
|
||||
pwm->chip.of_pwm_n_cells = 3;
|
||||
|
|
|
@ -258,7 +258,6 @@ static int brcmstb_pwm_probe(struct platform_device *pdev)
|
|||
|
||||
p->chip.dev = &pdev->dev;
|
||||
p->chip.ops = &brcmstb_pwm_ops;
|
||||
p->chip.base = -1;
|
||||
p->chip.npwm = 2;
|
||||
|
||||
p->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
|
|
|
@ -128,7 +128,6 @@ static int clps711x_pwm_probe(struct platform_device *pdev)
|
|||
|
||||
priv->chip.ops = &clps711x_pwm_ops;
|
||||
priv->chip.dev = &pdev->dev;
|
||||
priv->chip.base = -1;
|
||||
priv->chip.npwm = 2;
|
||||
priv->chip.of_xlate = clps711x_pwm_xlate;
|
||||
priv->chip.of_pwm_n_cells = 1;
|
||||
|
|
|
@ -168,7 +168,6 @@ static int crystalcove_pwm_probe(struct platform_device *pdev)
|
|||
|
||||
pwm->chip.dev = &pdev->dev;
|
||||
pwm->chip.ops = &crc_pwm_ops;
|
||||
pwm->chip.base = -1;
|
||||
pwm->chip.npwm = 1;
|
||||
|
||||
/* get the PMIC regmap */
|
||||
|
|
|
@ -124,6 +124,9 @@ static int cros_ec_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
|||
if (state->period != EC_PWM_MAX_DUTY)
|
||||
return -EINVAL;
|
||||
|
||||
if (state->polarity != PWM_POLARITY_NORMAL)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* EC doesn't separate the concept of duty cycle and enabled, but
|
||||
* kernel does. Translate.
|
||||
|
@ -253,7 +256,6 @@ static int cros_ec_pwm_probe(struct platform_device *pdev)
|
|||
chip->ops = &cros_ec_pwm_ops;
|
||||
chip->of_xlate = cros_ec_pwm_xlate;
|
||||
chip->of_pwm_n_cells = 1;
|
||||
chip->base = -1;
|
||||
ret = cros_ec_num_pwms(ec);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Couldn't find PWMs: %d\n", ret);
|
||||
|
|
|
@ -233,7 +233,6 @@ static int dwc_pwm_probe(struct pci_dev *pci, const struct pci_device_id *id)
|
|||
dwc->chip.dev = dev;
|
||||
dwc->chip.ops = &dwc_pwm_ops;
|
||||
dwc->chip.npwm = DWC_TIMERS_TOTAL;
|
||||
dwc->chip.base = -1;
|
||||
|
||||
ret = pwmchip_add(&dwc->chip);
|
||||
if (ret)
|
||||
|
|
|
@ -185,7 +185,6 @@ static int ep93xx_pwm_probe(struct platform_device *pdev)
|
|||
|
||||
ep93xx_pwm->chip.dev = &pdev->dev;
|
||||
ep93xx_pwm->chip.ops = &ep93xx_pwm_ops;
|
||||
ep93xx_pwm->chip.base = -1;
|
||||
ep93xx_pwm->chip.npwm = 1;
|
||||
|
||||
ret = pwmchip_add(&ep93xx_pwm->chip);
|
||||
|
|
|
@ -453,7 +453,6 @@ static int fsl_pwm_probe(struct platform_device *pdev)
|
|||
fpc->chip.ops = &fsl_pwm_ops;
|
||||
fpc->chip.of_xlate = of_pwm_xlate_with_flags;
|
||||
fpc->chip.of_pwm_n_cells = 3;
|
||||
fpc->chip.base = -1;
|
||||
fpc->chip.npwm = 8;
|
||||
|
||||
ret = pwmchip_add(&fpc->chip);
|
||||
|
|
|
@ -205,7 +205,6 @@ static int hibvt_pwm_probe(struct platform_device *pdev)
|
|||
|
||||
pwm_chip->chip.ops = &hibvt_pwm_ops;
|
||||
pwm_chip->chip.dev = &pdev->dev;
|
||||
pwm_chip->chip.base = -1;
|
||||
pwm_chip->chip.npwm = soc->num_pwms;
|
||||
pwm_chip->chip.of_xlate = of_pwm_xlate_with_flags;
|
||||
pwm_chip->chip.of_pwm_n_cells = 3;
|
||||
|
|
|
@ -304,7 +304,6 @@ static int img_pwm_probe(struct platform_device *pdev)
|
|||
|
||||
pwm->chip.dev = &pdev->dev;
|
||||
pwm->chip.ops = &img_pwm_ops;
|
||||
pwm->chip.base = -1;
|
||||
pwm->chip.npwm = IMG_PWM_NPWM;
|
||||
|
||||
ret = pwmchip_add(&pwm->chip);
|
||||
|
|
|
@ -363,7 +363,6 @@ static int pwm_imx_tpm_probe(struct platform_device *pdev)
|
|||
|
||||
tpm->chip.dev = &pdev->dev;
|
||||
tpm->chip.ops = &imx_tpm_pwm_ops;
|
||||
tpm->chip.base = -1;
|
||||
tpm->chip.of_xlate = of_pwm_xlate_with_flags;
|
||||
tpm->chip.of_pwm_n_cells = 3;
|
||||
|
||||
|
@ -411,9 +410,7 @@ static int __maybe_unused pwm_imx_tpm_resume(struct device *dev)
|
|||
|
||||
ret = clk_prepare_enable(tpm->clk);
|
||||
if (ret)
|
||||
dev_err(dev,
|
||||
"failed to prepare or enable clock: %d\n",
|
||||
ret);
|
||||
dev_err(dev, "failed to prepare or enable clock: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -155,7 +155,6 @@ static int pwm_imx1_probe(struct platform_device *pdev)
|
|||
|
||||
imx->chip.ops = &pwm_imx1_ops;
|
||||
imx->chip.dev = &pdev->dev;
|
||||
imx->chip.base = -1;
|
||||
imx->chip.npwm = 1;
|
||||
|
||||
imx->mmio_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
|
|
|
@ -327,7 +327,6 @@ static int pwm_imx27_probe(struct platform_device *pdev)
|
|||
|
||||
imx->chip.ops = &pwm_imx27_ops;
|
||||
imx->chip.dev = &pdev->dev;
|
||||
imx->chip.base = -1;
|
||||
imx->chip.npwm = 1;
|
||||
|
||||
imx->chip.of_xlate = of_pwm_xlate_with_flags;
|
||||
|
|
|
@ -207,7 +207,6 @@ static int lgm_pwm_probe(struct platform_device *pdev)
|
|||
pc->chip.dev = dev;
|
||||
pc->chip.ops = &lgm_pwm_ops;
|
||||
pc->chip.npwm = 1;
|
||||
pc->chip.base = -1;
|
||||
|
||||
lgm_pwm_init(pc);
|
||||
|
||||
|
|
|
@ -206,7 +206,6 @@ static int iqs620_pwm_probe(struct platform_device *pdev)
|
|||
|
||||
iqs620_pwm->chip.dev = &pdev->dev;
|
||||
iqs620_pwm->chip.ops = &iqs620_pwm_ops;
|
||||
iqs620_pwm->chip.base = -1;
|
||||
iqs620_pwm->chip.npwm = 1;
|
||||
|
||||
mutex_init(&iqs620_pwm->lock);
|
||||
|
|
|
@ -244,7 +244,6 @@ static int jz4740_pwm_probe(struct platform_device *pdev)
|
|||
jz4740->chip.dev = dev;
|
||||
jz4740->chip.ops = &jz4740_pwm_ops;
|
||||
jz4740->chip.npwm = info->num_pwms;
|
||||
jz4740->chip.base = -1;
|
||||
jz4740->chip.of_xlate = of_pwm_xlate_with_flags;
|
||||
jz4740->chip.of_pwm_n_cells = 3;
|
||||
|
||||
|
|
|
@ -203,7 +203,6 @@ static int keembay_pwm_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
priv->chip.base = -1;
|
||||
priv->chip.dev = dev;
|
||||
priv->chip.ops = &keembay_pwm_ops;
|
||||
priv->chip.npwm = KMB_TOTAL_PWM_CHANNELS;
|
||||
|
|
|
@ -275,7 +275,6 @@ static int lp3943_pwm_probe(struct platform_device *pdev)
|
|||
lp3943_pwm->chip.dev = &pdev->dev;
|
||||
lp3943_pwm->chip.ops = &lp3943_pwm_ops;
|
||||
lp3943_pwm->chip.npwm = LP3943_NUM_PWMS;
|
||||
lp3943_pwm->chip.base = -1;
|
||||
|
||||
platform_set_drvdata(pdev, lp3943_pwm);
|
||||
|
||||
|
|
|
@ -370,7 +370,6 @@ static int lpc18xx_pwm_probe(struct platform_device *pdev)
|
|||
|
||||
lpc18xx_pwm->chip.dev = &pdev->dev;
|
||||
lpc18xx_pwm->chip.ops = &lpc18xx_pwm_ops;
|
||||
lpc18xx_pwm->chip.base = -1;
|
||||
lpc18xx_pwm->chip.npwm = 16;
|
||||
lpc18xx_pwm->chip.of_xlate = of_pwm_xlate_with_flags;
|
||||
lpc18xx_pwm->chip.of_pwm_n_cells = 3;
|
||||
|
@ -442,13 +441,15 @@ static int lpc18xx_pwm_remove(struct platform_device *pdev)
|
|||
struct lpc18xx_pwm_chip *lpc18xx_pwm = platform_get_drvdata(pdev);
|
||||
u32 val;
|
||||
|
||||
pwmchip_remove(&lpc18xx_pwm->chip);
|
||||
|
||||
val = lpc18xx_pwm_readl(lpc18xx_pwm, LPC18XX_PWM_CTRL);
|
||||
lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CTRL,
|
||||
val | LPC18XX_PWM_CTRL_HALT);
|
||||
|
||||
clk_disable_unprepare(lpc18xx_pwm->pwm_clk);
|
||||
|
||||
return pwmchip_remove(&lpc18xx_pwm->chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver lpc18xx_pwm_driver = {
|
||||
|
|
|
@ -116,7 +116,6 @@ static int lpc32xx_pwm_probe(struct platform_device *pdev)
|
|||
lpc32xx->chip.dev = &pdev->dev;
|
||||
lpc32xx->chip.ops = &lpc32xx_pwm_ops;
|
||||
lpc32xx->chip.npwm = 1;
|
||||
lpc32xx->chip.base = -1;
|
||||
|
||||
ret = pwmchip_add(&lpc32xx->chip);
|
||||
if (ret < 0) {
|
||||
|
@ -137,10 +136,6 @@ static int lpc32xx_pwm_probe(struct platform_device *pdev)
|
|||
static int lpc32xx_pwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct lpc32xx_pwm_chip *lpc32xx = platform_get_drvdata(pdev);
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < lpc32xx->chip.npwm; i++)
|
||||
pwm_disable(&lpc32xx->chip.pwms[i]);
|
||||
|
||||
return pwmchip_remove(&lpc32xx->chip);
|
||||
}
|
||||
|
|
|
@ -234,7 +234,6 @@ struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r,
|
|||
|
||||
lpwm->chip.dev = dev;
|
||||
lpwm->chip.ops = &pwm_lpss_ops;
|
||||
lpwm->chip.base = -1;
|
||||
lpwm->chip.npwm = info->npwm;
|
||||
|
||||
ret = pwmchip_add(&lpwm->chip);
|
||||
|
@ -255,12 +254,6 @@ EXPORT_SYMBOL_GPL(pwm_lpss_probe);
|
|||
|
||||
int pwm_lpss_remove(struct pwm_lpss_chip *lpwm)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < lpwm->info->npwm; i++) {
|
||||
if (pwm_is_enabled(&lpwm->chip.pwms[i]))
|
||||
pm_runtime_put(lpwm->chip.dev);
|
||||
}
|
||||
return pwmchip_remove(&lpwm->chip);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pwm_lpss_remove);
|
||||
|
|
|
@ -107,12 +107,6 @@ static void pwm_mediatek_clk_disable(struct pwm_chip *chip,
|
|||
clk_disable_unprepare(pc->clk_top);
|
||||
}
|
||||
|
||||
static inline u32 pwm_mediatek_readl(struct pwm_mediatek_chip *chip,
|
||||
unsigned int num, unsigned int offset)
|
||||
{
|
||||
return readl(chip->regs + pwm_mediatek_reg_offset[num] + offset);
|
||||
}
|
||||
|
||||
static inline void pwm_mediatek_writel(struct pwm_mediatek_chip *chip,
|
||||
unsigned int num, unsigned int offset,
|
||||
u32 value)
|
||||
|
@ -263,7 +257,6 @@ static int pwm_mediatek_probe(struct platform_device *pdev)
|
|||
|
||||
pc->chip.dev = &pdev->dev;
|
||||
pc->chip.ops = &pwm_mediatek_ops;
|
||||
pc->chip.base = -1;
|
||||
pc->chip.npwm = pc->soc->num_pwms;
|
||||
|
||||
ret = pwmchip_add(&pc->chip);
|
||||
|
|
|
@ -550,7 +550,6 @@ static int meson_pwm_probe(struct platform_device *pdev)
|
|||
spin_lock_init(&meson->lock);
|
||||
meson->chip.dev = &pdev->dev;
|
||||
meson->chip.ops = &meson_pwm_ops;
|
||||
meson->chip.base = -1;
|
||||
meson->chip.npwm = MESON_NUM_PWMS;
|
||||
meson->chip.of_xlate = of_pwm_xlate_with_flags;
|
||||
meson->chip.of_pwm_n_cells = 3;
|
||||
|
|
|
@ -202,7 +202,6 @@ static int mtk_disp_pwm_probe(struct platform_device *pdev)
|
|||
|
||||
mdp->chip.dev = &pdev->dev;
|
||||
mdp->chip.ops = &mtk_disp_pwm_ops;
|
||||
mdp->chip.base = -1;
|
||||
mdp->chip.npwm = 1;
|
||||
|
||||
ret = pwmchip_add(&mdp->chip);
|
||||
|
|
|
@ -140,7 +140,6 @@ static int mxs_pwm_probe(struct platform_device *pdev)
|
|||
mxs->chip.ops = &mxs_pwm_ops;
|
||||
mxs->chip.of_xlate = of_pwm_xlate_with_flags;
|
||||
mxs->chip.of_pwm_n_cells = 3;
|
||||
mxs->chip.base = -1;
|
||||
|
||||
ret = of_property_read_u32(np, "fsl,pwm-number", &mxs->chip.npwm);
|
||||
if (ret < 0) {
|
||||
|
|
|
@ -403,7 +403,6 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
|
|||
|
||||
omap->chip.dev = &pdev->dev;
|
||||
omap->chip.ops = &pwm_omap_dmtimer_ops;
|
||||
omap->chip.base = -1;
|
||||
omap->chip.npwm = 1;
|
||||
omap->chip.of_xlate = of_pwm_xlate_with_flags;
|
||||
omap->chip.of_pwm_n_cells = 3;
|
||||
|
|
|
@ -51,7 +51,6 @@
|
|||
#define PCA9685_PRESCALE_MAX 0xFF /* => min. frequency of 24 Hz */
|
||||
|
||||
#define PCA9685_COUNTER_RANGE 4096
|
||||
#define PCA9685_DEFAULT_PERIOD 5000000 /* Default period_ns = 1/200 Hz */
|
||||
#define PCA9685_OSC_CLOCK_MHZ 25 /* Internal oscillator with 25 MHz */
|
||||
|
||||
#define PCA9685_NUMREGS 0xFF
|
||||
|
@ -71,10 +70,14 @@
|
|||
#define LED_N_OFF_H(N) (PCA9685_LEDX_OFF_H + (4 * (N)))
|
||||
#define LED_N_OFF_L(N) (PCA9685_LEDX_OFF_L + (4 * (N)))
|
||||
|
||||
#define REG_ON_H(C) ((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_ON_H : LED_N_ON_H((C)))
|
||||
#define REG_ON_L(C) ((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_ON_L : LED_N_ON_L((C)))
|
||||
#define REG_OFF_H(C) ((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_OFF_H : LED_N_OFF_H((C)))
|
||||
#define REG_OFF_L(C) ((C) >= PCA9685_MAXCHAN ? PCA9685_ALL_LED_OFF_L : LED_N_OFF_L((C)))
|
||||
|
||||
struct pca9685 {
|
||||
struct pwm_chip chip;
|
||||
struct regmap *regmap;
|
||||
int period_ns;
|
||||
#if IS_ENABLED(CONFIG_GPIOLIB)
|
||||
struct mutex lock;
|
||||
struct gpio_chip gpio;
|
||||
|
@ -87,6 +90,53 @@ static inline struct pca9685 *to_pca(struct pwm_chip *chip)
|
|||
return container_of(chip, struct pca9685, chip);
|
||||
}
|
||||
|
||||
/* Helper function to set the duty cycle ratio to duty/4096 (e.g. duty=2048 -> 50%) */
|
||||
static void pca9685_pwm_set_duty(struct pca9685 *pca, int channel, unsigned int duty)
|
||||
{
|
||||
if (duty == 0) {
|
||||
/* Set the full OFF bit, which has the highest precedence */
|
||||
regmap_write(pca->regmap, REG_OFF_H(channel), LED_FULL);
|
||||
} else if (duty >= PCA9685_COUNTER_RANGE) {
|
||||
/* Set the full ON bit and clear the full OFF bit */
|
||||
regmap_write(pca->regmap, REG_ON_H(channel), LED_FULL);
|
||||
regmap_write(pca->regmap, REG_OFF_H(channel), 0);
|
||||
} else {
|
||||
/* Set OFF time (clears the full OFF bit) */
|
||||
regmap_write(pca->regmap, REG_OFF_L(channel), duty & 0xff);
|
||||
regmap_write(pca->regmap, REG_OFF_H(channel), (duty >> 8) & 0xf);
|
||||
/* Clear the full ON bit */
|
||||
regmap_write(pca->regmap, REG_ON_H(channel), 0);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int pca9685_pwm_get_duty(struct pca9685 *pca, int channel)
|
||||
{
|
||||
unsigned int off_h = 0, val = 0;
|
||||
|
||||
if (WARN_ON(channel >= PCA9685_MAXCHAN)) {
|
||||
/* HW does not support reading state of "all LEDs" channel */
|
||||
return 0;
|
||||
}
|
||||
|
||||
regmap_read(pca->regmap, LED_N_OFF_H(channel), &off_h);
|
||||
if (off_h & LED_FULL) {
|
||||
/* Full OFF bit is set */
|
||||
return 0;
|
||||
}
|
||||
|
||||
regmap_read(pca->regmap, LED_N_ON_H(channel), &val);
|
||||
if (val & LED_FULL) {
|
||||
/* Full ON bit is set */
|
||||
return PCA9685_COUNTER_RANGE;
|
||||
}
|
||||
|
||||
if (regmap_read(pca->regmap, LED_N_OFF_L(channel), &val)) {
|
||||
/* Reset val to 0 in case reading LED_N_OFF_L failed */
|
||||
val = 0;
|
||||
}
|
||||
return ((off_h & 0xf) << 8) | (val & 0xff);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_GPIOLIB)
|
||||
static bool pca9685_pwm_test_and_set_inuse(struct pca9685 *pca, int pwm_idx)
|
||||
{
|
||||
|
@ -138,34 +188,23 @@ static int pca9685_pwm_gpio_request(struct gpio_chip *gpio, unsigned int offset)
|
|||
static int pca9685_pwm_gpio_get(struct gpio_chip *gpio, unsigned int offset)
|
||||
{
|
||||
struct pca9685 *pca = gpiochip_get_data(gpio);
|
||||
struct pwm_device *pwm = &pca->chip.pwms[offset];
|
||||
unsigned int value;
|
||||
|
||||
regmap_read(pca->regmap, LED_N_ON_H(pwm->hwpwm), &value);
|
||||
|
||||
return value & LED_FULL;
|
||||
return pca9685_pwm_get_duty(pca, offset) != 0;
|
||||
}
|
||||
|
||||
static void pca9685_pwm_gpio_set(struct gpio_chip *gpio, unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
struct pca9685 *pca = gpiochip_get_data(gpio);
|
||||
struct pwm_device *pwm = &pca->chip.pwms[offset];
|
||||
unsigned int on = value ? LED_FULL : 0;
|
||||
|
||||
/* Clear both OFF registers */
|
||||
regmap_write(pca->regmap, LED_N_OFF_L(pwm->hwpwm), 0);
|
||||
regmap_write(pca->regmap, LED_N_OFF_H(pwm->hwpwm), 0);
|
||||
|
||||
/* Set the full ON bit */
|
||||
regmap_write(pca->regmap, LED_N_ON_H(pwm->hwpwm), on);
|
||||
pca9685_pwm_set_duty(pca, offset, value ? PCA9685_COUNTER_RANGE : 0);
|
||||
}
|
||||
|
||||
static void pca9685_pwm_gpio_free(struct gpio_chip *gpio, unsigned int offset)
|
||||
{
|
||||
struct pca9685 *pca = gpiochip_get_data(gpio);
|
||||
|
||||
pca9685_pwm_gpio_set(gpio, offset, 0);
|
||||
pca9685_pwm_set_duty(pca, offset, 0);
|
||||
pm_runtime_put(pca->chip.dev);
|
||||
pca9685_pwm_clear_inuse(pca, offset);
|
||||
}
|
||||
|
@ -246,165 +285,85 @@ static void pca9685_set_sleep_mode(struct pca9685 *pca, bool enable)
|
|||
}
|
||||
}
|
||||
|
||||
static int pca9685_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
int duty_ns, int period_ns)
|
||||
static int pca9685_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
struct pca9685 *pca = to_pca(chip);
|
||||
unsigned long long duty, prescale;
|
||||
unsigned int val = 0;
|
||||
|
||||
if (state->polarity != PWM_POLARITY_NORMAL)
|
||||
return -EINVAL;
|
||||
|
||||
prescale = DIV_ROUND_CLOSEST_ULL(PCA9685_OSC_CLOCK_MHZ * state->period,
|
||||
PCA9685_COUNTER_RANGE * 1000) - 1;
|
||||
if (prescale < PCA9685_PRESCALE_MIN || prescale > PCA9685_PRESCALE_MAX) {
|
||||
dev_err(chip->dev, "pwm not changed: period out of bounds!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!state->enabled) {
|
||||
pca9685_pwm_set_duty(pca, pwm->hwpwm, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
regmap_read(pca->regmap, PCA9685_PRESCALE, &val);
|
||||
if (prescale != val) {
|
||||
/*
|
||||
* Putting the chip briefly into SLEEP mode
|
||||
* at this point won't interfere with the
|
||||
* pm_runtime framework, because the pm_runtime
|
||||
* state is guaranteed active here.
|
||||
*/
|
||||
/* Put chip into sleep mode */
|
||||
pca9685_set_sleep_mode(pca, true);
|
||||
|
||||
/* Change the chip-wide output frequency */
|
||||
regmap_write(pca->regmap, PCA9685_PRESCALE, prescale);
|
||||
|
||||
/* Wake the chip up */
|
||||
pca9685_set_sleep_mode(pca, false);
|
||||
}
|
||||
|
||||
duty = PCA9685_COUNTER_RANGE * state->duty_cycle;
|
||||
duty = DIV_ROUND_UP_ULL(duty, state->period);
|
||||
pca9685_pwm_set_duty(pca, pwm->hwpwm, duty);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pca9685_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
struct pwm_state *state)
|
||||
{
|
||||
struct pca9685 *pca = to_pca(chip);
|
||||
unsigned long long duty;
|
||||
unsigned int reg;
|
||||
int prescale;
|
||||
|
||||
if (period_ns != pca->period_ns) {
|
||||
prescale = DIV_ROUND_CLOSEST(PCA9685_OSC_CLOCK_MHZ * period_ns,
|
||||
PCA9685_COUNTER_RANGE * 1000) - 1;
|
||||
|
||||
if (prescale >= PCA9685_PRESCALE_MIN &&
|
||||
prescale <= PCA9685_PRESCALE_MAX) {
|
||||
/*
|
||||
* Putting the chip briefly into SLEEP mode
|
||||
* at this point won't interfere with the
|
||||
* pm_runtime framework, because the pm_runtime
|
||||
* state is guaranteed active here.
|
||||
*/
|
||||
/* Put chip into sleep mode */
|
||||
pca9685_set_sleep_mode(pca, true);
|
||||
|
||||
/* Change the chip-wide output frequency */
|
||||
regmap_write(pca->regmap, PCA9685_PRESCALE, prescale);
|
||||
|
||||
/* Wake the chip up */
|
||||
pca9685_set_sleep_mode(pca, false);
|
||||
|
||||
pca->period_ns = period_ns;
|
||||
} else {
|
||||
dev_err(chip->dev,
|
||||
"prescaler not set: period out of bounds!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (duty_ns < 1) {
|
||||
if (pwm->hwpwm >= PCA9685_MAXCHAN)
|
||||
reg = PCA9685_ALL_LED_OFF_H;
|
||||
else
|
||||
reg = LED_N_OFF_H(pwm->hwpwm);
|
||||
|
||||
regmap_write(pca->regmap, reg, LED_FULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (duty_ns == period_ns) {
|
||||
/* Clear both OFF registers */
|
||||
if (pwm->hwpwm >= PCA9685_MAXCHAN)
|
||||
reg = PCA9685_ALL_LED_OFF_L;
|
||||
else
|
||||
reg = LED_N_OFF_L(pwm->hwpwm);
|
||||
|
||||
regmap_write(pca->regmap, reg, 0x0);
|
||||
|
||||
if (pwm->hwpwm >= PCA9685_MAXCHAN)
|
||||
reg = PCA9685_ALL_LED_OFF_H;
|
||||
else
|
||||
reg = LED_N_OFF_H(pwm->hwpwm);
|
||||
|
||||
regmap_write(pca->regmap, reg, 0x0);
|
||||
|
||||
/* Set the full ON bit */
|
||||
if (pwm->hwpwm >= PCA9685_MAXCHAN)
|
||||
reg = PCA9685_ALL_LED_ON_H;
|
||||
else
|
||||
reg = LED_N_ON_H(pwm->hwpwm);
|
||||
|
||||
regmap_write(pca->regmap, reg, LED_FULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
duty = PCA9685_COUNTER_RANGE * (unsigned long long)duty_ns;
|
||||
duty = DIV_ROUND_UP_ULL(duty, period_ns);
|
||||
|
||||
if (pwm->hwpwm >= PCA9685_MAXCHAN)
|
||||
reg = PCA9685_ALL_LED_OFF_L;
|
||||
else
|
||||
reg = LED_N_OFF_L(pwm->hwpwm);
|
||||
|
||||
regmap_write(pca->regmap, reg, (int)duty & 0xff);
|
||||
|
||||
if (pwm->hwpwm >= PCA9685_MAXCHAN)
|
||||
reg = PCA9685_ALL_LED_OFF_H;
|
||||
else
|
||||
reg = LED_N_OFF_H(pwm->hwpwm);
|
||||
|
||||
regmap_write(pca->regmap, reg, ((int)duty >> 8) & 0xf);
|
||||
|
||||
/* Clear the full ON bit, otherwise the set OFF time has no effect */
|
||||
if (pwm->hwpwm >= PCA9685_MAXCHAN)
|
||||
reg = PCA9685_ALL_LED_ON_H;
|
||||
else
|
||||
reg = LED_N_ON_H(pwm->hwpwm);
|
||||
|
||||
regmap_write(pca->regmap, reg, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pca9685_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct pca9685 *pca = to_pca(chip);
|
||||
unsigned int reg;
|
||||
unsigned int val = 0;
|
||||
|
||||
/* Calculate (chip-wide) period from prescale value */
|
||||
regmap_read(pca->regmap, PCA9685_PRESCALE, &val);
|
||||
/*
|
||||
* The PWM subsystem does not support a pre-delay.
|
||||
* So, set the ON-timeout to 0
|
||||
* PCA9685_OSC_CLOCK_MHZ is 25, i.e. an integer divider of 1000.
|
||||
* The following calculation is therefore only a multiplication
|
||||
* and we are not losing precision.
|
||||
*/
|
||||
if (pwm->hwpwm >= PCA9685_MAXCHAN)
|
||||
reg = PCA9685_ALL_LED_ON_L;
|
||||
else
|
||||
reg = LED_N_ON_L(pwm->hwpwm);
|
||||
state->period = (PCA9685_COUNTER_RANGE * 1000 / PCA9685_OSC_CLOCK_MHZ) *
|
||||
(val + 1);
|
||||
|
||||
regmap_write(pca->regmap, reg, 0);
|
||||
/* The (per-channel) polarity is fixed */
|
||||
state->polarity = PWM_POLARITY_NORMAL;
|
||||
|
||||
if (pwm->hwpwm >= PCA9685_MAXCHAN)
|
||||
reg = PCA9685_ALL_LED_ON_H;
|
||||
else
|
||||
reg = LED_N_ON_H(pwm->hwpwm);
|
||||
if (pwm->hwpwm >= PCA9685_MAXCHAN) {
|
||||
/*
|
||||
* The "all LEDs" channel does not support HW readout
|
||||
* Return 0 and disabled for backwards compatibility
|
||||
*/
|
||||
state->duty_cycle = 0;
|
||||
state->enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
regmap_write(pca->regmap, reg, 0);
|
||||
|
||||
/*
|
||||
* Clear the full-off bit.
|
||||
* It has precedence over the others and must be off.
|
||||
*/
|
||||
if (pwm->hwpwm >= PCA9685_MAXCHAN)
|
||||
reg = PCA9685_ALL_LED_OFF_H;
|
||||
else
|
||||
reg = LED_N_OFF_H(pwm->hwpwm);
|
||||
|
||||
regmap_update_bits(pca->regmap, reg, LED_FULL, 0x0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pca9685_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct pca9685 *pca = to_pca(chip);
|
||||
unsigned int reg;
|
||||
|
||||
if (pwm->hwpwm >= PCA9685_MAXCHAN)
|
||||
reg = PCA9685_ALL_LED_OFF_H;
|
||||
else
|
||||
reg = LED_N_OFF_H(pwm->hwpwm);
|
||||
|
||||
regmap_write(pca->regmap, reg, LED_FULL);
|
||||
|
||||
/* Clear the LED_OFF counter. */
|
||||
if (pwm->hwpwm >= PCA9685_MAXCHAN)
|
||||
reg = PCA9685_ALL_LED_OFF_L;
|
||||
else
|
||||
reg = LED_N_OFF_L(pwm->hwpwm);
|
||||
|
||||
regmap_write(pca->regmap, reg, 0x0);
|
||||
state->enabled = true;
|
||||
duty = pca9685_pwm_get_duty(pca, pwm->hwpwm);
|
||||
state->duty_cycle = DIV_ROUND_DOWN_ULL(duty * state->period, PCA9685_COUNTER_RANGE);
|
||||
}
|
||||
|
||||
static int pca9685_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
|
@ -422,15 +381,14 @@ static void pca9685_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
|
|||
{
|
||||
struct pca9685 *pca = to_pca(chip);
|
||||
|
||||
pca9685_pwm_disable(chip, pwm);
|
||||
pca9685_pwm_set_duty(pca, pwm->hwpwm, 0);
|
||||
pm_runtime_put(chip->dev);
|
||||
pca9685_pwm_clear_inuse(pca, pwm->hwpwm);
|
||||
}
|
||||
|
||||
static const struct pwm_ops pca9685_pwm_ops = {
|
||||
.enable = pca9685_pwm_enable,
|
||||
.disable = pca9685_pwm_disable,
|
||||
.config = pca9685_pwm_config,
|
||||
.apply = pca9685_pwm_apply,
|
||||
.get_state = pca9685_pwm_get_state,
|
||||
.request = pca9685_pwm_request,
|
||||
.free = pca9685_pwm_free,
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -461,7 +419,6 @@ static int pca9685_pwm_probe(struct i2c_client *client,
|
|||
ret);
|
||||
return ret;
|
||||
}
|
||||
pca->period_ns = PCA9685_DEFAULT_PERIOD;
|
||||
|
||||
i2c_set_clientdata(client, pca);
|
||||
|
||||
|
@ -484,16 +441,15 @@ static int pca9685_pwm_probe(struct i2c_client *client,
|
|||
reg &= ~(MODE1_ALLCALL | MODE1_SUB1 | MODE1_SUB2 | MODE1_SUB3);
|
||||
regmap_write(pca->regmap, PCA9685_MODE1, reg);
|
||||
|
||||
/* Clear all "full off" bits */
|
||||
regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_L, 0);
|
||||
regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_H, 0);
|
||||
/* Reset OFF registers to POR default */
|
||||
regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_L, LED_FULL);
|
||||
regmap_write(pca->regmap, PCA9685_ALL_LED_OFF_H, LED_FULL);
|
||||
|
||||
pca->chip.ops = &pca9685_pwm_ops;
|
||||
/* Add an extra channel for ALL_LED */
|
||||
pca->chip.npwm = PCA9685_MAXCHAN + 1;
|
||||
|
||||
pca->chip.dev = &client->dev;
|
||||
pca->chip.base = -1;
|
||||
|
||||
ret = pwmchip_add(&pca->chip);
|
||||
if (ret < 0)
|
||||
|
@ -505,14 +461,20 @@ static int pca9685_pwm_probe(struct i2c_client *client,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* The chip comes out of power-up in the active state */
|
||||
pm_runtime_set_active(&client->dev);
|
||||
/*
|
||||
* Enable will put the chip into suspend, which is what we
|
||||
* want as all outputs are disabled at this point
|
||||
*/
|
||||
pm_runtime_enable(&client->dev);
|
||||
|
||||
if (pm_runtime_enabled(&client->dev)) {
|
||||
/*
|
||||
* Although the chip comes out of power-up in the sleep state,
|
||||
* we force it to sleep in case it was woken up before
|
||||
*/
|
||||
pca9685_set_sleep_mode(pca, true);
|
||||
pm_runtime_set_suspended(&client->dev);
|
||||
} else {
|
||||
/* Wake the chip up if runtime PM is disabled */
|
||||
pca9685_set_sleep_mode(pca, false);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -524,7 +486,14 @@ static int pca9685_pwm_remove(struct i2c_client *client)
|
|||
ret = pwmchip_remove(&pca->chip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!pm_runtime_enabled(&client->dev)) {
|
||||
/* Put chip in sleep state if runtime PM is disabled */
|
||||
pca9685_set_sleep_mode(pca, true);
|
||||
}
|
||||
|
||||
pm_runtime_disable(&client->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -184,7 +184,6 @@ static int pwm_probe(struct platform_device *pdev)
|
|||
|
||||
pwm->chip.dev = &pdev->dev;
|
||||
pwm->chip.ops = &pxa_pwm_ops;
|
||||
pwm->chip.base = -1;
|
||||
pwm->chip.npwm = (id->driver_data & HAS_SECONDARY_PWM) ? 2 : 1;
|
||||
|
||||
if (IS_ENABLED(CONFIG_OF)) {
|
||||
|
|
|
@ -224,7 +224,6 @@ static int rcar_pwm_probe(struct platform_device *pdev)
|
|||
|
||||
rcar_pwm->chip.dev = &pdev->dev;
|
||||
rcar_pwm->chip.ops = &rcar_pwm_ops;
|
||||
rcar_pwm->chip.base = -1;
|
||||
rcar_pwm->chip.npwm = 1;
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
|
|
@ -410,7 +410,6 @@ static int tpu_probe(struct platform_device *pdev)
|
|||
tpu->chip.ops = &tpu_pwm_ops;
|
||||
tpu->chip.of_xlate = of_pwm_xlate_with_flags;
|
||||
tpu->chip.of_pwm_n_cells = 3;
|
||||
tpu->chip.base = -1;
|
||||
tpu->chip.npwm = TPU_CHANNEL_MAX;
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
|
|
@ -352,7 +352,6 @@ static int rockchip_pwm_probe(struct platform_device *pdev)
|
|||
pc->data = id->data;
|
||||
pc->chip.dev = &pdev->dev;
|
||||
pc->chip.ops = &rockchip_pwm_ops;
|
||||
pc->chip.base = -1;
|
||||
pc->chip.npwm = 1;
|
||||
|
||||
if (pc->data->supports_polarity) {
|
||||
|
|
|
@ -519,7 +519,6 @@ static int pwm_samsung_probe(struct platform_device *pdev)
|
|||
|
||||
chip->chip.dev = &pdev->dev;
|
||||
chip->chip.ops = &pwm_samsung_ops;
|
||||
chip->chip.base = -1;
|
||||
chip->chip.npwm = SAMSUNG_PWM_NUM;
|
||||
chip->inverter_mask = BIT(SAMSUNG_PWM_NUM) - 1;
|
||||
|
||||
|
|
|
@ -244,7 +244,6 @@ static int pwm_sifive_probe(struct platform_device *pdev)
|
|||
chip->ops = &pwm_sifive_ops;
|
||||
chip->of_xlate = of_pwm_xlate_with_flags;
|
||||
chip->of_pwm_n_cells = 3;
|
||||
chip->base = -1;
|
||||
chip->npwm = 4;
|
||||
|
||||
ddata->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
|
|
|
@ -229,7 +229,6 @@ static int sl28cpld_pwm_probe(struct platform_device *pdev)
|
|||
chip = &priv->pwm_chip;
|
||||
chip->dev = &pdev->dev;
|
||||
chip->ops = &sl28cpld_pwm_ops;
|
||||
chip->base = -1;
|
||||
chip->npwm = 1;
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
|
|
@ -193,7 +193,6 @@ static int spear_pwm_probe(struct platform_device *pdev)
|
|||
|
||||
pc->chip.dev = &pdev->dev;
|
||||
pc->chip.ops = &spear_pwm_ops;
|
||||
pc->chip.base = -1;
|
||||
pc->chip.npwm = NUM_PWM;
|
||||
|
||||
ret = clk_prepare(pc->clk);
|
||||
|
|
|
@ -164,6 +164,9 @@ static int sprd_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
|||
struct pwm_state *cstate = &pwm->state;
|
||||
int ret;
|
||||
|
||||
if (state->polarity != PWM_POLARITY_NORMAL)
|
||||
return -EINVAL;
|
||||
|
||||
if (state->enabled) {
|
||||
if (!cstate->enabled) {
|
||||
/*
|
||||
|
@ -268,7 +271,6 @@ static int sprd_pwm_probe(struct platform_device *pdev)
|
|||
|
||||
spc->chip.dev = &pdev->dev;
|
||||
spc->chip.ops = &sprd_pwm_ops;
|
||||
spc->chip.base = -1;
|
||||
spc->chip.npwm = spc->num_pwms;
|
||||
|
||||
ret = pwmchip_add(&spc->chip);
|
||||
|
|
|
@ -619,7 +619,6 @@ static int sti_pwm_probe(struct platform_device *pdev)
|
|||
|
||||
pc->chip.dev = dev;
|
||||
pc->chip.ops = &sti_pwm_ops;
|
||||
pc->chip.base = -1;
|
||||
pc->chip.npwm = pc->cdata->pwm_num_devs;
|
||||
|
||||
ret = pwmchip_add(&pc->chip);
|
||||
|
@ -650,15 +649,13 @@ static int sti_pwm_probe(struct platform_device *pdev)
|
|||
static int sti_pwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct sti_pwm_chip *pc = platform_get_drvdata(pdev);
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < pc->cdata->pwm_num_devs; i++)
|
||||
pwm_disable(&pc->chip.pwms[i]);
|
||||
pwmchip_remove(&pc->chip);
|
||||
|
||||
clk_unprepare(pc->pwm_clk);
|
||||
clk_unprepare(pc->cpt_clk);
|
||||
|
||||
return pwmchip_remove(&pc->chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id sti_pwm_of_match[] = {
|
||||
|
|
|
@ -205,7 +205,6 @@ static int stm32_pwm_lp_probe(struct platform_device *pdev)
|
|||
|
||||
priv->regmap = ddata->regmap;
|
||||
priv->clk = ddata->clk;
|
||||
priv->chip.base = -1;
|
||||
priv->chip.dev = &pdev->dev;
|
||||
priv->chip.ops = &stm32_pwm_lp_ops;
|
||||
priv->chip.npwm = 1;
|
||||
|
|
|
@ -633,7 +633,6 @@ static int stm32_pwm_probe(struct platform_device *pdev)
|
|||
|
||||
stm32_pwm_detect_complementary(priv);
|
||||
|
||||
priv->chip.base = -1;
|
||||
priv->chip.dev = dev;
|
||||
priv->chip.ops = &stm32pwm_ops;
|
||||
priv->chip.npwm = stm32_pwm_detect_channels(priv);
|
||||
|
|
|
@ -278,7 +278,6 @@ static int __init stmpe_pwm_probe(struct platform_device *pdev)
|
|||
|
||||
pwm->stmpe = stmpe;
|
||||
pwm->chip.dev = &pdev->dev;
|
||||
pwm->chip.base = -1;
|
||||
|
||||
if (stmpe->partnum == STMPE2401 || stmpe->partnum == STMPE2403) {
|
||||
pwm->chip.ops = &stmpe_24xx_pwm_ops;
|
||||
|
|
|
@ -459,7 +459,6 @@ static int sun4i_pwm_probe(struct platform_device *pdev)
|
|||
|
||||
pwm->chip.dev = &pdev->dev;
|
||||
pwm->chip.ops = &sun4i_pwm_ops;
|
||||
pwm->chip.base = -1;
|
||||
pwm->chip.npwm = pwm->data->npwm;
|
||||
pwm->chip.of_xlate = of_pwm_xlate_with_flags;
|
||||
pwm->chip.of_pwm_n_cells = 3;
|
||||
|
|
|
@ -285,7 +285,6 @@ static int tegra_pwm_probe(struct platform_device *pdev)
|
|||
|
||||
pwm->chip.dev = &pdev->dev;
|
||||
pwm->chip.ops = &tegra_pwm_ops;
|
||||
pwm->chip.base = -1;
|
||||
pwm->chip.npwm = pwm->soc->num_channels;
|
||||
|
||||
ret = pwmchip_add(&pwm->chip);
|
||||
|
|
|
@ -226,7 +226,6 @@ static int ecap_pwm_probe(struct platform_device *pdev)
|
|||
pc->chip.ops = &ecap_pwm_ops;
|
||||
pc->chip.of_xlate = of_pwm_xlate_with_flags;
|
||||
pc->chip.of_pwm_n_cells = 3;
|
||||
pc->chip.base = -1;
|
||||
pc->chip.npwm = 1;
|
||||
|
||||
pc->mmio_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
|
|
|
@ -449,7 +449,6 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev)
|
|||
pc->chip.ops = &ehrpwm_pwm_ops;
|
||||
pc->chip.of_xlate = of_pwm_xlate_with_flags;
|
||||
pc->chip.of_pwm_n_cells = 3;
|
||||
pc->chip.base = -1;
|
||||
pc->chip.npwm = NUM_PWM_CHANNEL;
|
||||
|
||||
pc->mmio_base = devm_platform_ioremap_resource(pdev, 0);
|
||||
|
|
|
@ -291,7 +291,6 @@ static int twl_pwmled_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
twl->chip.dev = &pdev->dev;
|
||||
twl->chip.base = -1;
|
||||
|
||||
mutex_init(&twl->mutex);
|
||||
|
||||
|
|
|
@ -310,7 +310,6 @@ static int twl_pwm_probe(struct platform_device *pdev)
|
|||
twl->chip.ops = &twl6030_pwm_ops;
|
||||
|
||||
twl->chip.dev = &pdev->dev;
|
||||
twl->chip.base = -1;
|
||||
twl->chip.npwm = 2;
|
||||
|
||||
mutex_init(&twl->mutex);
|
||||
|
|
|
@ -0,0 +1,190 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Toshiba Visconti pulse-width-modulation controller driver
|
||||
*
|
||||
* Copyright (c) 2020 - 2021 TOSHIBA CORPORATION
|
||||
* Copyright (c) 2020 - 2021 Toshiba Electronic Devices & Storage Corporation
|
||||
*
|
||||
* Authors: Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
|
||||
*
|
||||
* Limitations:
|
||||
* - The fixed input clock is running at 1 MHz and is divided by either 1,
|
||||
* 2, 4 or 8.
|
||||
* - When the settings of the PWM are modified, the new values are shadowed
|
||||
* in hardware until the PIPGM_PCSR register is written and the currently
|
||||
* running period is completed. This way the hardware switches atomically
|
||||
* from the old setting to the new.
|
||||
* - Disabling the hardware completes the currently running period and keeps
|
||||
* the output at low level at all times.
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pwm.h>
|
||||
|
||||
#define PIPGM_PCSR(ch) (0x400 + 4 * (ch))
|
||||
#define PIPGM_PDUT(ch) (0x420 + 4 * (ch))
|
||||
#define PIPGM_PWMC(ch) (0x440 + 4 * (ch))
|
||||
|
||||
#define PIPGM_PWMC_PWMACT BIT(5)
|
||||
#define PIPGM_PWMC_CLK_MASK GENMASK(1, 0)
|
||||
#define PIPGM_PWMC_POLARITY_MASK GENMASK(5, 5)
|
||||
|
||||
struct visconti_pwm_chip {
|
||||
struct pwm_chip chip;
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
static inline struct visconti_pwm_chip *visconti_pwm_from_chip(struct pwm_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct visconti_pwm_chip, chip);
|
||||
}
|
||||
|
||||
static int visconti_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
struct visconti_pwm_chip *priv = visconti_pwm_from_chip(chip);
|
||||
u32 period, duty_cycle, pwmc0;
|
||||
|
||||
if (!state->enabled) {
|
||||
writel(0, priv->base + PIPGM_PCSR(pwm->hwpwm));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The biggest period the hardware can provide is
|
||||
* (0xffff << 3) * 1000 ns
|
||||
* This value fits easily in an u32, so simplify the maths by
|
||||
* capping the values to 32 bit integers.
|
||||
*/
|
||||
if (state->period > (0xffff << 3) * 1000)
|
||||
period = (0xffff << 3) * 1000;
|
||||
else
|
||||
period = state->period;
|
||||
|
||||
if (state->duty_cycle > period)
|
||||
duty_cycle = period;
|
||||
else
|
||||
duty_cycle = state->duty_cycle;
|
||||
|
||||
/*
|
||||
* The input clock runs fixed at 1 MHz, so we have only
|
||||
* microsecond resolution and so can divide by
|
||||
* NSEC_PER_SEC / CLKFREQ = 1000 without losing precision.
|
||||
*/
|
||||
period /= 1000;
|
||||
duty_cycle /= 1000;
|
||||
|
||||
if (!period)
|
||||
return -ERANGE;
|
||||
|
||||
/*
|
||||
* PWMC controls a divider that divides the input clk by a
|
||||
* power of two between 1 and 8. As a smaller divider yields
|
||||
* higher precision, pick the smallest possible one.
|
||||
*/
|
||||
if (period > 0xffff) {
|
||||
pwmc0 = ilog2(period >> 16);
|
||||
if (WARN_ON(pwmc0 > 3))
|
||||
return -EINVAL;
|
||||
} else {
|
||||
pwmc0 = 0;
|
||||
}
|
||||
|
||||
period >>= pwmc0;
|
||||
duty_cycle >>= pwmc0;
|
||||
|
||||
if (state->polarity == PWM_POLARITY_INVERSED)
|
||||
pwmc0 |= PIPGM_PWMC_PWMACT;
|
||||
writel(pwmc0, priv->base + PIPGM_PWMC(pwm->hwpwm));
|
||||
writel(duty_cycle, priv->base + PIPGM_PDUT(pwm->hwpwm));
|
||||
writel(period, priv->base + PIPGM_PCSR(pwm->hwpwm));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void visconti_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
struct pwm_state *state)
|
||||
{
|
||||
struct visconti_pwm_chip *priv = visconti_pwm_from_chip(chip);
|
||||
u32 period, duty, pwmc0, pwmc0_clk;
|
||||
|
||||
period = readl(priv->base + PIPGM_PCSR(pwm->hwpwm));
|
||||
duty = readl(priv->base + PIPGM_PDUT(pwm->hwpwm));
|
||||
pwmc0 = readl(priv->base + PIPGM_PWMC(pwm->hwpwm));
|
||||
pwmc0_clk = pwmc0 & PIPGM_PWMC_CLK_MASK;
|
||||
|
||||
state->period = (period << pwmc0_clk) * NSEC_PER_USEC;
|
||||
state->duty_cycle = (duty << pwmc0_clk) * NSEC_PER_USEC;
|
||||
if (pwmc0 & PIPGM_PWMC_POLARITY_MASK)
|
||||
state->polarity = PWM_POLARITY_INVERSED;
|
||||
else
|
||||
state->polarity = PWM_POLARITY_NORMAL;
|
||||
|
||||
state->enabled = true;
|
||||
}
|
||||
|
||||
static const struct pwm_ops visconti_pwm_ops = {
|
||||
.apply = visconti_pwm_apply,
|
||||
.get_state = visconti_pwm_get_state,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int visconti_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct visconti_pwm_chip *priv;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(priv->base))
|
||||
return PTR_ERR(priv->base);
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
priv->chip.dev = dev;
|
||||
priv->chip.ops = &visconti_pwm_ops;
|
||||
priv->chip.npwm = 4;
|
||||
|
||||
ret = pwmchip_add(&priv->chip);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(&pdev->dev, ret, "Cannot register visconti PWM\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int visconti_pwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct visconti_pwm_chip *priv = platform_get_drvdata(pdev);
|
||||
|
||||
pwmchip_remove(&priv->chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id visconti_pwm_of_match[] = {
|
||||
{ .compatible = "toshiba,visconti-pwm", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, visconti_pwm_of_match);
|
||||
|
||||
static struct platform_driver visconti_pwm_driver = {
|
||||
.driver = {
|
||||
.name = "pwm-visconti",
|
||||
.of_match_table = visconti_pwm_of_match,
|
||||
},
|
||||
.probe = visconti_pwm_probe,
|
||||
.remove = visconti_pwm_remove,
|
||||
};
|
||||
module_platform_driver(visconti_pwm_driver);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>");
|
||||
MODULE_ALIAS("platform:pwm-visconti");
|
|
@ -209,7 +209,6 @@ static int vt8500_pwm_probe(struct platform_device *pdev)
|
|||
chip->chip.ops = &vt8500_pwm_ops;
|
||||
chip->chip.of_xlate = of_pwm_xlate_with_flags;
|
||||
chip->chip.of_pwm_n_cells = 3;
|
||||
chip->chip.base = -1;
|
||||
chip->chip.npwm = VT8500_NR_PWMS;
|
||||
|
||||
chip->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
|
|
|
@ -91,6 +91,11 @@ struct pwm_device {
|
|||
* pwm_get_state() - retrieve the current PWM state
|
||||
* @pwm: 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
|
||||
* state (if supported) or the default settings.
|
||||
*/
|
||||
static inline void pwm_get_state(const struct pwm_device *pwm,
|
||||
struct pwm_state *state)
|
||||
|
@ -392,8 +397,6 @@ int pwm_capture(struct pwm_device *pwm, struct pwm_capture *result,
|
|||
int pwm_set_chip_data(struct pwm_device *pwm, void *data);
|
||||
void *pwm_get_chip_data(struct pwm_device *pwm);
|
||||
|
||||
int pwmchip_add_with_polarity(struct pwm_chip *chip,
|
||||
enum pwm_polarity polarity);
|
||||
int pwmchip_add(struct pwm_chip *chip);
|
||||
int pwmchip_remove(struct pwm_chip *chip);
|
||||
struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip,
|
||||
|
|
Loading…
Reference in New Issue