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:
Linus Torvalds 2021-05-05 12:53:16 -07:00
commit 7b9df264f0
67 changed files with 634 additions and 410 deletions

View File

@ -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>;
};

View File

@ -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>;
};

View File

@ -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>;
};
};

View File

@ -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.

View File

@ -355,7 +355,6 @@
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 @@
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 @@
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 @@
reg = <0x20050030 0x10>;
#pwm-cells = <2>;
clocks = <&cru PCLK_PWM>;
clock-names = "pwm";
pinctrl-names = "default";
pinctrl-0 = <&pwm3_pin>;
status = "disabled";

View File

@ -679,7 +679,6 @@
pinctrl-names = "default";
pinctrl-0 = <&pwm0_pin>;
clocks = <&cru PCLK_RKPWM>;
clock-names = "pwm";
status = "disabled";
};
@ -690,7 +689,6 @@
pinctrl-names = "default";
pinctrl-0 = <&pwm1_pin>;
clocks = <&cru PCLK_RKPWM>;
clock-names = "pwm";
status = "disabled";
};
@ -701,7 +699,6 @@
pinctrl-names = "default";
pinctrl-0 = <&pwm2_pin>;
clocks = <&cru PCLK_RKPWM>;
clock-names = "pwm";
status = "disabled";
};
@ -712,7 +709,6 @@
pinctrl-names = "default";
pinctrl-0 = <&pwm3_pin>;
clocks = <&cru PCLK_RKPWM>;
clock-names = "pwm";
status = "disabled";
};

View File

@ -558,7 +558,6 @@
pinctrl-names = "default";
pinctrl-0 = <&pwm0_pin>;
clocks = <&cru PCLK_PWM1>;
clock-names = "pwm";
status = "disabled";
};
@ -569,7 +568,6 @@
pinctrl-names = "default";
pinctrl-0 = <&pwm1_pin>;
clocks = <&cru PCLK_PWM1>;
clock-names = "pwm";
status = "disabled";
};
@ -578,7 +576,6 @@
reg = <0x0 0xff680020 0x0 0x10>;
#pwm-cells = <3>;
clocks = <&cru PCLK_PWM1>;
clock-names = "pwm";
status = "disabled";
};
@ -589,7 +586,6 @@
pinctrl-names = "default";
pinctrl-0 = <&pwm3_pin>;
clocks = <&cru PCLK_PWM1>;
clock-names = "pwm";
status = "disabled";
};

View File

@ -1182,7 +1182,6 @@
pinctrl-names = "default";
pinctrl-0 = <&pwm0_pin>;
clocks = <&pmucru PCLK_RKPWM_PMU>;
clock-names = "pwm";
status = "disabled";
};
@ -1193,7 +1192,6 @@
pinctrl-names = "default";
pinctrl-0 = <&pwm1_pin>;
clocks = <&pmucru PCLK_RKPWM_PMU>;
clock-names = "pwm";
status = "disabled";
};
@ -1204,7 +1202,6 @@
pinctrl-names = "default";
pinctrl-0 = <&pwm2_pin>;
clocks = <&pmucru PCLK_RKPWM_PMU>;
clock-names = "pwm";
status = "disabled";
};
@ -1215,7 +1212,6 @@
pinctrl-names = "default";
pinctrl-0 = <&pwm3a_pin>;
clocks = <&pmucru PCLK_RKPWM_PMU>;
clock-names = "pwm";
status = "disabled";
};

View File

@ -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

View File

@ -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

View File

@ -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 @@ out:
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

View File

@ -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);

View File

@ -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;

View File

@ -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;
}

View File

@ -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 = {

View File

@ -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[] = {

View File

@ -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);
}

View File

@ -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[] = {

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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 */

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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 = {

View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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) {

View File

@ -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;

View File

@ -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;
}

View File

@ -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)) {

View File

@ -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);

View File

@ -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);

View File

@ -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) {

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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[] = {

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

190
drivers/pwm/pwm-visconti.c Normal file
View File

@ -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");

View File

@ -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);

View File

@ -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,