Skip to content

Commit

Permalink
Merge tag 'pwm/for-5.4-rc1' of git://git.kernel.org/pub/scm/linux/ker…
Browse files Browse the repository at this point in the history
…nel/git/thierry.reding/linux-pwm

Pull pwm updates from Thierry Reding:
 "Besides one new driver being added for the PWM controller found in
  various Spreadtrum SoCs, this series of changes brings a slew of,
  mostly minor, fixes and cleanups for existing drivers, as well as some
  enhancements to the core code.

  Lastly, Uwe is added to the PWM subsystem entry of the MAINTAINERS
  file, making official his role as a reviewer"

* tag 'pwm/for-5.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm: (34 commits)
  MAINTAINERS: Add myself as reviewer for the PWM subsystem
  MAINTAINERS: Add patchwork link for PWM entry
  MAINTAINERS: Add a selection of PWM related keywords to the PWM entry
  pwm: mediatek: Add MT7629 compatible string
  dt-bindings: pwm: Update bindings for MT7629 SoC
  pwm: mediatek: Update license and switch to SPDX tag
  pwm: mediatek: Use pwm_mediatek as common prefix
  pwm: mediatek: Allocate the clks array dynamically
  pwm: mediatek: Remove the has_clks field
  pwm: mediatek: Drop the check for of_device_get_match_data()
  pwm: atmel: Consolidate driver data initialization
  pwm: atmel: Remove unneeded check for match data
  pwm: atmel: Remove platform_device_id and use only dt bindings
  pwm: stm32-lp: Add check in case requested period cannot be achieved
  pwm: Ensure pwm_apply_state() doesn't modify the state argument
  pwm: fsl-ftm: Don't update the state for the caller of pwm_apply_state()
  pwm: sun4i: Don't update the state for the caller of pwm_apply_state()
  pwm: rockchip: Don't update the state for the caller of pwm_apply_state()
  pwm: Let pwm_get_state() return the last implemented state
  pwm: Introduce local struct pwm_chip in pwm_apply_state()
  ...
  • Loading branch information
Linus Torvalds committed Sep 27, 2019
2 parents 738f531 + da635e7 commit e37e3bc
Show file tree
Hide file tree
Showing 31 changed files with 576 additions and 236 deletions.
2 changes: 2 additions & 0 deletions Documentation/devicetree/bindings/pwm/pwm-mediatek.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ Required properties:
- "mediatek,mt7622-pwm": found on mt7622 SoC.
- "mediatek,mt7623-pwm": found on mt7623 SoC.
- "mediatek,mt7628-pwm": found on mt7628 SoC.
- "mediatek,mt7629-pwm", "mediatek,mt7622-pwm": found on mt7629 SoC.
- "mediatek,mt8516-pwm": found on mt8516 SoC.
- reg: physical base address and length of the controller's registers.
- #pwm-cells: must be 2. See pwm.txt in this directory for a description of
the cell format.
Expand Down
40 changes: 40 additions & 0 deletions Documentation/devicetree/bindings/pwm/pwm-sprd.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
Spreadtrum PWM controller

Spreadtrum SoCs PWM controller provides 4 PWM channels.

Required properties:
- compatible : Should be "sprd,ums512-pwm".
- reg: Physical base address and length of the controller's registers.
- clocks: The phandle and specifier referencing the controller's clocks.
- clock-names: Should contain following entries:
"pwmn": used to derive the functional clock for PWM channel n (n range: 0 ~ 3).
"enablen": for PWM channel n enable clock (n range: 0 ~ 3).
- #pwm-cells: Should be 2. See pwm.txt in this directory for a description of
the cells format.

Optional properties:
- assigned-clocks: Reference to the PWM clock entries.
- assigned-clock-parents: The phandle of the parent clock of PWM clock.

Example:
pwms: pwm@32260000 {
compatible = "sprd,ums512-pwm";
reg = <0 0x32260000 0 0x10000>;
clock-names = "pwm0", "enable0",
"pwm1", "enable1",
"pwm2", "enable2",
"pwm3", "enable3";
clocks = <&aon_clk CLK_PWM0>, <&aonapb_gate CLK_PWM0_EB>,
<&aon_clk CLK_PWM1>, <&aonapb_gate CLK_PWM1_EB>,
<&aon_clk CLK_PWM2>, <&aonapb_gate CLK_PWM2_EB>,
<&aon_clk CLK_PWM3>, <&aonapb_gate CLK_PWM3_EB>;
assigned-clocks = <&aon_clk CLK_PWM0>,
<&aon_clk CLK_PWM1>,
<&aon_clk CLK_PWM2>,
<&aon_clk CLK_PWM3>;
assigned-clock-parents = <&ext_26m>,
<&ext_26m>,
<&ext_26m>,
<&ext_26m>;
#pwm-cells = <2>;
};
3 changes: 3 additions & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -13246,9 +13246,11 @@ F: drivers/media/rc/pwm-ir-tx.c

PWM SUBSYSTEM
M: Thierry Reding <thierry.reding@gmail.com>
R: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
L: linux-pwm@vger.kernel.org
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm.git
Q: https://patchwork.ozlabs.org/project/linux-pwm/list/
F: Documentation/driver-api/pwm.rst
F: Documentation/devicetree/bindings/pwm/
F: include/linux/pwm.h
Expand All @@ -13257,6 +13259,7 @@ F: drivers/video/backlight/pwm_bl.c
F: include/linux/pwm_backlight.h
F: drivers/gpio/gpio-mvebu.c
F: Documentation/devicetree/bindings/gpio/gpio-mvebu.txt
K: pwm_(config|apply_state|ops)

PXA GPIO DRIVER
M: Robert Jarzmik <robert.jarzmik@free.fr>
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpio/gpio-mvebu.c
Original file line number Diff line number Diff line change
Expand Up @@ -694,7 +694,7 @@ static void mvebu_pwm_get_state(struct pwm_chip *chip,
}

static int mvebu_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
struct pwm_state *state)
const struct pwm_state *state)
{
struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip);
struct mvebu_gpio_chip *mvchip = mvpwm->mvchip;
Expand Down
13 changes: 12 additions & 1 deletion drivers/pwm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ config PWM_AB8500

config PWM_ATMEL
tristate "Atmel PWM support"
depends on ARCH_AT91
depends on ARCH_AT91 && OF
help
Generic PWM framework driver for Atmel SoC.

Expand Down Expand Up @@ -423,6 +423,17 @@ config PWM_SPEAR
To compile this driver as a module, choose M here: the module
will be called pwm-spear.

config PWM_SPRD
tristate "Spreadtrum PWM support"
depends on ARCH_SPRD || COMPILE_TEST
depends on HAS_IOMEM
help
Generic PWM framework driver for the PWM controller on
Spreadtrum SoCs.

To compile this driver as a module, choose M here: the module
will be called pwm-sprd.

config PWM_STI
tristate "STiH4xx PWM support"
depends on ARCH_STI
Expand Down
1 change: 1 addition & 0 deletions drivers/pwm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o
obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o
obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o
obj-$(CONFIG_PWM_SPRD) += pwm-sprd.o
obj-$(CONFIG_PWM_STI) += pwm-sti.o
obj-$(CONFIG_PWM_STM32) += pwm-stm32.o
obj-$(CONFIG_PWM_STM32_LP) += pwm-stm32-lp.o
Expand Down
40 changes: 24 additions & 16 deletions drivers/pwm/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -448,36 +448,44 @@ EXPORT_SYMBOL_GPL(pwm_free);
/**
* pwm_apply_state() - atomically apply a new state to a PWM device
* @pwm: PWM device
* @state: new state to apply. This can be adjusted by the PWM driver
* if the requested config is not achievable, for example,
* ->duty_cycle and ->period might be approximated.
* @state: new state to apply
*/
int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state)
int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state)
{
struct pwm_chip *chip;
int err;

if (!pwm || !state || !state->period ||
state->duty_cycle > state->period)
return -EINVAL;

chip = pwm->chip;

if (state->period == pwm->state.period &&
state->duty_cycle == pwm->state.duty_cycle &&
state->polarity == pwm->state.polarity &&
state->enabled == pwm->state.enabled)
return 0;

if (pwm->chip->ops->apply) {
err = pwm->chip->ops->apply(pwm->chip, pwm, state);
if (chip->ops->apply) {
err = chip->ops->apply(chip, pwm, state);
if (err)
return err;

pwm->state = *state;
/*
* .apply might have to round some values in *state, if possible
* read the actually implemented value back.
*/
if (chip->ops->get_state)
chip->ops->get_state(chip, pwm, &pwm->state);
else
pwm->state = *state;
} else {
/*
* FIXME: restore the initial state in case of error.
*/
if (state->polarity != pwm->state.polarity) {
if (!pwm->chip->ops->set_polarity)
if (!chip->ops->set_polarity)
return -ENOTSUPP;

/*
Expand All @@ -486,12 +494,12 @@ int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state)
* ->apply().
*/
if (pwm->state.enabled) {
pwm->chip->ops->disable(pwm->chip, pwm);
chip->ops->disable(chip, pwm);
pwm->state.enabled = false;
}

err = pwm->chip->ops->set_polarity(pwm->chip, pwm,
state->polarity);
err = chip->ops->set_polarity(chip, pwm,
state->polarity);
if (err)
return err;

Expand All @@ -500,9 +508,9 @@ int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state)

if (state->period != pwm->state.period ||
state->duty_cycle != pwm->state.duty_cycle) {
err = pwm->chip->ops->config(pwm->chip, pwm,
state->duty_cycle,
state->period);
err = chip->ops->config(pwm->chip, pwm,
state->duty_cycle,
state->period);
if (err)
return err;

Expand All @@ -512,11 +520,11 @@ int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state)

if (state->enabled != pwm->state.enabled) {
if (state->enabled) {
err = pwm->chip->ops->enable(pwm->chip, pwm);
err = chip->ops->enable(chip, pwm);
if (err)
return err;
} else {
pwm->chip->ops->disable(pwm->chip, pwm);
chip->ops->disable(chip, pwm);
}

pwm->state.enabled = state->enabled;
Expand Down
2 changes: 1 addition & 1 deletion drivers/pwm/pwm-atmel-hlcdc.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ static inline struct atmel_hlcdc_pwm *to_atmel_hlcdc_pwm(struct pwm_chip *chip)
}

static int atmel_hlcdc_pwm_apply(struct pwm_chip *c, struct pwm_device *pwm,
struct pwm_state *state)
const struct pwm_state *state)
{
struct atmel_hlcdc_pwm *chip = to_atmel_hlcdc_pwm(c);
struct atmel_hlcdc *hlcdc = chip->hlcdc;
Expand Down
49 changes: 7 additions & 42 deletions drivers/pwm/pwm-atmel.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ static void atmel_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm,
}

static int atmel_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
struct pwm_state *state)
const struct pwm_state *state)
{
struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip);
struct pwm_state cstate;
Expand Down Expand Up @@ -318,19 +318,6 @@ static const struct atmel_pwm_data mchp_sam9x60_pwm_data = {
},
};

static const struct platform_device_id atmel_pwm_devtypes[] = {
{
.name = "at91sam9rl-pwm",
.driver_data = (kernel_ulong_t)&atmel_sam9rl_pwm_data,
}, {
.name = "sama5d3-pwm",
.driver_data = (kernel_ulong_t)&atmel_sama5_pwm_data,
}, {
/* sentinel */
},
};
MODULE_DEVICE_TABLE(platform, atmel_pwm_devtypes);

static const struct of_device_id atmel_pwm_dt_ids[] = {
{
.compatible = "atmel,at91sam9rl-pwm",
Expand All @@ -350,34 +337,20 @@ static const struct of_device_id atmel_pwm_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, atmel_pwm_dt_ids);

static inline const struct atmel_pwm_data *
atmel_pwm_get_driver_data(struct platform_device *pdev)
{
const struct platform_device_id *id;

if (pdev->dev.of_node)
return of_device_get_match_data(&pdev->dev);

id = platform_get_device_id(pdev);

return (struct atmel_pwm_data *)id->driver_data;
}

static int atmel_pwm_probe(struct platform_device *pdev)
{
const struct atmel_pwm_data *data;
struct atmel_pwm_chip *atmel_pwm;
struct resource *res;
int ret;

data = atmel_pwm_get_driver_data(pdev);
if (!data)
return -ENODEV;

atmel_pwm = devm_kzalloc(&pdev->dev, sizeof(*atmel_pwm), GFP_KERNEL);
if (!atmel_pwm)
return -ENOMEM;

mutex_init(&atmel_pwm->isr_lock);
atmel_pwm->data = of_device_get_match_data(&pdev->dev);
atmel_pwm->updated_pwms = 0;

res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
atmel_pwm->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(atmel_pwm->base))
Expand All @@ -395,17 +368,10 @@ static int atmel_pwm_probe(struct platform_device *pdev)

atmel_pwm->chip.dev = &pdev->dev;
atmel_pwm->chip.ops = &atmel_pwm_ops;

if (pdev->dev.of_node) {
atmel_pwm->chip.of_xlate = of_pwm_xlate_with_flags;
atmel_pwm->chip.of_pwm_n_cells = 3;
}

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;
atmel_pwm->data = data;
atmel_pwm->updated_pwms = 0;
mutex_init(&atmel_pwm->isr_lock);

ret = pwmchip_add(&atmel_pwm->chip);
if (ret < 0) {
Expand Down Expand Up @@ -437,7 +403,6 @@ static struct platform_driver atmel_pwm_driver = {
.name = "atmel-pwm",
.of_match_table = of_match_ptr(atmel_pwm_dt_ids),
},
.id_table = atmel_pwm_devtypes,
.probe = atmel_pwm_probe,
.remove = atmel_pwm_remove,
};
Expand Down
2 changes: 1 addition & 1 deletion drivers/pwm/pwm-bcm-iproc.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ static void iproc_pwmc_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
}

static int iproc_pwmc_apply(struct pwm_chip *chip, struct pwm_device *pwm,
struct pwm_state *state)
const struct pwm_state *state)
{
unsigned long prescale = IPROC_PWM_PRESCALE_MIN;
struct iproc_pwmc *ip = to_iproc_pwmc(chip);
Expand Down
19 changes: 10 additions & 9 deletions drivers/pwm/pwm-bcm2835.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
#define PERIOD(x) (((x) * 0x10) + 0x10)
#define DUTY(x) (((x) * 0x10) + 0x14)

#define MIN_PERIOD 108 /* 9.2 MHz max. PWM clock */
#define PERIOD_MIN 0x2

struct bcm2835_pwm {
struct pwm_chip chip;
Expand Down Expand Up @@ -64,24 +64,22 @@ static int bcm2835_pwm_config(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 scaler;
u32 period;

if (!rate) {
dev_err(pc->dev, "failed to get clock rate\n");
return -EINVAL;
}

scaler = DIV_ROUND_CLOSEST(NSEC_PER_SEC, rate);
period = DIV_ROUND_CLOSEST(period_ns, scaler);

if (period_ns <= MIN_PERIOD) {
dev_err(pc->dev, "period %d not supported, minimum %d\n",
period_ns, MIN_PERIOD);
if (period < PERIOD_MIN)
return -EINVAL;
}

writel(DIV_ROUND_CLOSEST(duty_ns, scaler),
pc->base + DUTY(pwm->hwpwm));
writel(DIV_ROUND_CLOSEST(period_ns, scaler),
pc->base + PERIOD(pwm->hwpwm));
writel(period, pc->base + PERIOD(pwm->hwpwm));

return 0;
}
Expand Down Expand Up @@ -155,8 +153,11 @@ static int bcm2835_pwm_probe(struct platform_device *pdev)

pc->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(pc->clk)) {
dev_err(&pdev->dev, "clock not found: %ld\n", PTR_ERR(pc->clk));
return PTR_ERR(pc->clk);
ret = PTR_ERR(pc->clk);
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev, "clock not found: %d\n", ret);

return ret;
}

ret = clk_prepare_enable(pc->clk);
Expand Down
2 changes: 1 addition & 1 deletion drivers/pwm/pwm-cros-ec.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ static int cros_ec_pwm_get_duty(struct cros_ec_device *ec, u8 index)
}

static int cros_ec_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
struct pwm_state *state)
const struct pwm_state *state)
{
struct cros_ec_pwm_device *ec_pwm = pwm_to_cros_ec_pwm(chip);
int duty_cycle;
Expand Down
Loading

0 comments on commit e37e3bc

Please sign in to comment.