Skip to content

Commit

Permalink
Merge tag 'pwm/for-4.5-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:
 "This set of changes contains a new driver for OMAP (using the
  dual-mode timers) as well as an assortment of fixes all across the
  board"

* tag 'pwm/for-4.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm:
  pwm: Mark all devices as "might sleep"
  pwm: omap-dmtimer: Potential NULL dereference on error
  pwm: add HAS_IOMEM dependency to PWM_FSL_FTM
  pwm: Add PWM driver for OMAP using dual-mode timers
  pwm: rcar: Improve accuracy of frequency division setting
  pwm: lpc32xx: return ERANGE, if requested period is not supported
  pwm: lpc32xx: fix and simplify duty cycle and period calculations
  pwm: lpc32xx: make device usable with common clock framework
  pwm: lpc32xx: correct number of PWM channels from 2 to 1
  dt: lpc32xx: pwm: update documentation of LPC32xx PWM device
  dt: lpc32xx: pwm: correct LPC32xx PWM device node example
  pwm: fsl-ftm: Fix clock enable/disable when using PM
  pwm: lpss: Rework the sequence of programming PWM_SW_UPDATE
  pwm: lpss: Select core part automatically
  pwm: lpss: Update PWM setting for Broxton
  pwm: bcm2835: Fix email address specification
  pwm: bcm2835: Prevent division by zero
  pwm: bcm2835: Calculate scaler in ->config()
  pwm: lpss: Remove ->free() callback
  • Loading branch information
torvalds committed Jan 21, 2016
2 parents 96461fd + ff01c94 commit 859e762
Show file tree
Hide file tree
Showing 13 changed files with 539 additions and 107 deletions.
9 changes: 7 additions & 2 deletions Documentation/devicetree/bindings/pwm/lpc32xx-pwm.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ Required properties:

Examples:

pwm@0x4005C000 {
pwm@4005c000 {
compatible = "nxp,lpc3220-pwm";
reg = <0x4005C000 0x8>;
reg = <0x4005c000 0x4>;
};

pwm@4005c004 {
compatible = "nxp,lpc3220-pwm";
reg = <0x4005c004 0x4>;
};
18 changes: 18 additions & 0 deletions Documentation/devicetree/bindings/pwm/pwm-omap-dmtimer.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
* OMAP PWM for dual-mode timers

Required properties:
- compatible: Shall contain "ti,omap-dmtimer-pwm".
- ti,timers: phandle to PWM capable OMAP timer. See arm/omap/timer.txt for info
about these timers.
- #pwm-cells: Should be 3. See pwm.txt in this directory for a description of
the cells format.

Optional properties:
- ti,prescaler: Should be a value between 0 and 7, see the timers datasheet

Example:
pwm9: dmtimer-pwm@9 {
compatible = "ti,omap-dmtimer-pwm";
ti,timers = <&timer9>;
#pwm-cells = <3>;
};
25 changes: 15 additions & 10 deletions drivers/pwm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ config PWM_EP93XX

config PWM_FSL_FTM
tristate "Freescale FlexTimer Module (FTM) PWM support"
depends on HAS_IOMEM
depends on OF
select REGMAP_MMIO
help
Expand Down Expand Up @@ -222,18 +223,12 @@ config PWM_LPC32XX
will be called pwm-lpc32xx.

config PWM_LPSS
tristate "Intel LPSS PWM support"
depends on X86
help
Generic PWM framework driver for Intel Low Power Subsystem PWM
controller.

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

config PWM_LPSS_PCI
tristate "Intel LPSS PWM PCI driver"
depends on PWM_LPSS && PCI
depends on X86 && PCI
select PWM_LPSS
help
The PCI driver for Intel Low Power Subsystem PWM controller.

Expand All @@ -242,7 +237,8 @@ config PWM_LPSS_PCI

config PWM_LPSS_PLATFORM
tristate "Intel LPSS PWM platform driver"
depends on PWM_LPSS && ACPI
depends on X86 && ACPI
select PWM_LPSS
help
The platform driver for Intel Low Power Subsystem PWM controller.

Expand Down Expand Up @@ -270,6 +266,15 @@ config PWM_MXS
To compile this driver as a module, choose M here: the module
will be called pwm-mxs.

config PWM_OMAP_DMTIMER
tristate "OMAP Dual-Mode Timer PWM support"
depends on OF && ARCH_OMAP && OMAP_DM_TIMER
help
Generic PWM framework driver for OMAP Dual-Mode Timer PWM output

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

config PWM_PCA9685
tristate "NXP PCA9685 PWM driver"
depends on I2C
Expand Down
1 change: 1 addition & 0 deletions drivers/pwm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ obj-$(CONFIG_PWM_LPSS_PCI) += pwm-lpss-pci.o
obj-$(CONFIG_PWM_LPSS_PLATFORM) += pwm-lpss-platform.o
obj-$(CONFIG_PWM_MTK_DISP) += pwm-mtk-disp.o
obj-$(CONFIG_PWM_MXS) += pwm-mxs.o
obj-$(CONFIG_PWM_OMAP_DMTIMER) += pwm-omap-dmtimer.o
obj-$(CONFIG_PWM_PCA9685) += pwm-pca9685.o
obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o
obj-$(CONFIG_PWM_PXA) += pwm-pxa.o
Expand Down
2 changes: 1 addition & 1 deletion drivers/pwm/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -889,7 +889,7 @@ EXPORT_SYMBOL_GPL(devm_pwm_put);
*/
bool pwm_can_sleep(struct pwm_device *pwm)
{
return pwm->chip->can_sleep;
return true;
}
EXPORT_SYMBOL_GPL(pwm_can_sleep);

Expand Down
18 changes: 12 additions & 6 deletions drivers/pwm/pwm-bcm2835.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
struct bcm2835_pwm {
struct pwm_chip chip;
struct device *dev;
unsigned long scaler;
void __iomem *base;
struct clk *clk;
};
Expand Down Expand Up @@ -66,15 +65,24 @@ static int bcm2835_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
int duty_ns, int period_ns)
{
struct bcm2835_pwm *pc = to_bcm2835_pwm(chip);
unsigned long rate = clk_get_rate(pc->clk);
unsigned long scaler;

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

scaler = NSEC_PER_SEC / rate;

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

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

return 0;
}
Expand Down Expand Up @@ -156,8 +164,6 @@ static int bcm2835_pwm_probe(struct platform_device *pdev)
if (ret)
return ret;

pc->scaler = NSEC_PER_SEC / clk_get_rate(pc->clk);

pc->chip.dev = &pdev->dev;
pc->chip.ops = &bcm2835_pwm_ops;
pc->chip.npwm = 2;
Expand Down Expand Up @@ -200,6 +206,6 @@ static struct platform_driver bcm2835_pwm_driver = {
};
module_platform_driver(bcm2835_pwm_driver);

MODULE_AUTHOR("Bart Tanghe <[email protected]");
MODULE_AUTHOR("Bart Tanghe <[email protected]>");
MODULE_DESCRIPTION("Broadcom BCM2835 PWM driver");
MODULE_LICENSE("GPL v2");
58 changes: 25 additions & 33 deletions drivers/pwm/pwm-fsl-ftm.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ struct fsl_pwm_chip {

struct mutex lock;

unsigned int use_count;
unsigned int cnt_select;
unsigned int clk_ps;

Expand Down Expand Up @@ -300,9 +299,6 @@ static int fsl_counter_clock_enable(struct fsl_pwm_chip *fpc)
{
int ret;

if (fpc->use_count++ != 0)
return 0;

/* select counter clock source */
regmap_update_bits(fpc->regmap, FTM_SC, FTM_SC_CLK_MASK,
FTM_SC_CLK(fpc->cnt_select));
Expand Down Expand Up @@ -334,25 +330,6 @@ static int fsl_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
return ret;
}

static void fsl_counter_clock_disable(struct fsl_pwm_chip *fpc)
{
/*
* already disabled, do nothing
*/
if (fpc->use_count == 0)
return;

/* there are still users, so can't disable yet */
if (--fpc->use_count > 0)
return;

/* no users left, disable PWM counter clock */
regmap_update_bits(fpc->regmap, FTM_SC, FTM_SC_CLK_MASK, 0);

clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]);
clk_disable_unprepare(fpc->clk[fpc->cnt_select]);
}

static void fsl_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
{
struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
Expand All @@ -362,7 +339,8 @@ static void fsl_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
regmap_update_bits(fpc->regmap, FTM_OUTMASK, BIT(pwm->hwpwm),
BIT(pwm->hwpwm));

fsl_counter_clock_disable(fpc);
clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]);
clk_disable_unprepare(fpc->clk[fpc->cnt_select]);

regmap_read(fpc->regmap, FTM_OUTMASK, &val);
if ((val & 0xFF) == 0xFF)
Expand Down Expand Up @@ -492,17 +470,24 @@ static int fsl_pwm_remove(struct platform_device *pdev)
static int fsl_pwm_suspend(struct device *dev)
{
struct fsl_pwm_chip *fpc = dev_get_drvdata(dev);
u32 val;
int i;

regcache_cache_only(fpc->regmap, true);
regcache_mark_dirty(fpc->regmap);

/* read from cache */
regmap_read(fpc->regmap, FTM_OUTMASK, &val);
if ((val & 0xFF) != 0xFF) {
for (i = 0; i < fpc->chip.npwm; i++) {
struct pwm_device *pwm = &fpc->chip.pwms[i];

if (!test_bit(PWMF_REQUESTED, &pwm->flags))
continue;

clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]);

if (!pwm_is_enabled(pwm))
continue;

clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]);
clk_disable_unprepare(fpc->clk[fpc->cnt_select]);
clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]);
}

return 0;
Expand All @@ -511,12 +496,19 @@ static int fsl_pwm_suspend(struct device *dev)
static int fsl_pwm_resume(struct device *dev)
{
struct fsl_pwm_chip *fpc = dev_get_drvdata(dev);
u32 val;
int i;

for (i = 0; i < fpc->chip.npwm; i++) {
struct pwm_device *pwm = &fpc->chip.pwms[i];

if (!test_bit(PWMF_REQUESTED, &pwm->flags))
continue;

/* read from cache */
regmap_read(fpc->regmap, FTM_OUTMASK, &val);
if ((val & 0xFF) != 0xFF) {
clk_prepare_enable(fpc->clk[FSL_PWM_CLK_SYS]);

if (!pwm_is_enabled(pwm))
continue;

clk_prepare_enable(fpc->clk[fpc->cnt_select]);
clk_prepare_enable(fpc->clk[FSL_PWM_CLK_CNTEN]);
}
Expand Down
59 changes: 22 additions & 37 deletions drivers/pwm/pwm-lpc32xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ struct lpc32xx_pwm_chip {
void __iomem *base;
};

#define PWM_ENABLE (1 << 31)
#define PWM_RELOADV(x) (((x) & 0xFF) << 8)
#define PWM_DUTY(x) ((x) & 0xFF)
#define PWM_ENABLE BIT(31)

#define to_lpc32xx_pwm_chip(_chip) \
container_of(_chip, struct lpc32xx_pwm_chip, chip)
Expand All @@ -38,40 +36,27 @@ static int lpc32xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
unsigned long long c;
int period_cycles, duty_cycles;
u32 val;

c = clk_get_rate(lpc32xx->clk) / 256;
c = c * period_ns;
do_div(c, NSEC_PER_SEC);

/* Handle high and low extremes */
if (c == 0)
c = 1;
if (c > 255)
c = 0; /* 0 set division by 256 */
period_cycles = c;

/* The duty-cycle value is as follows:
*
* DUTY-CYCLE HIGH LEVEL
* 1 99.9%
* 25 90.0%
* 128 50.0%
* 220 10.0%
* 255 0.1%
* 0 0.0%
*
* In other words, the register value is duty-cycle % 256 with
* duty-cycle in the range 1-256.
*/
c = 256 * duty_ns;
do_div(c, period_ns);
if (c > 255)
c = 255;
duty_cycles = 256 - c;
c = clk_get_rate(lpc32xx->clk);

/* The highest acceptable divisor is 256, which is represented by 0 */
period_cycles = div64_u64(c * period_ns,
(unsigned long long)NSEC_PER_SEC * 256);
if (!period_cycles || period_cycles > 256)
return -ERANGE;
if (period_cycles == 256)
period_cycles = 0;

/* Compute 256 x #duty/period value and care for corner cases */
duty_cycles = div64_u64((unsigned long long)(period_ns - duty_ns) * 256,
period_ns);
if (!duty_cycles)
duty_cycles = 1;
if (duty_cycles > 255)
duty_cycles = 255;

val = readl(lpc32xx->base + (pwm->hwpwm << 2));
val &= ~0xFFFF;
val |= PWM_RELOADV(period_cycles) | PWM_DUTY(duty_cycles);
val |= (period_cycles << 8) | duty_cycles;
writel(val, lpc32xx->base + (pwm->hwpwm << 2));

return 0;
Expand All @@ -83,7 +68,7 @@ static int lpc32xx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
u32 val;
int ret;

ret = clk_enable(lpc32xx->clk);
ret = clk_prepare_enable(lpc32xx->clk);
if (ret)
return ret;

Expand All @@ -103,7 +88,7 @@ static void lpc32xx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
val &= ~PWM_ENABLE;
writel(val, lpc32xx->base + (pwm->hwpwm << 2));

clk_disable(lpc32xx->clk);
clk_disable_unprepare(lpc32xx->clk);
}

static const struct pwm_ops lpc32xx_pwm_ops = {
Expand Down Expand Up @@ -134,7 +119,7 @@ static int lpc32xx_pwm_probe(struct platform_device *pdev)

lpc32xx->chip.dev = &pdev->dev;
lpc32xx->chip.ops = &lpc32xx_pwm_ops;
lpc32xx->chip.npwm = 2;
lpc32xx->chip.npwm = 1;
lpc32xx->chip.base = -1;

ret = pwmchip_add(&lpc32xx->chip);
Expand Down
Loading

0 comments on commit 859e762

Please sign in to comment.