pwm: Changes for v4.19-rc1

This contains mostly minor bug fixes as well as some new chip support
 for existing drivers.
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCAA3FiEEiOrDCAFJzPfAjcif3SOs138+s6EFAlt+tkoZHHRoaWVycnku
 cmVkaW5nQGdtYWlsLmNvbQAKCRDdI6zXfz6zod9ED/9PpR9nHTyi9yQdLsAykSwg
 AaM59A0A/ZFYW24RoB3FNq0xLV7H0qIVK4XXZNtWMQh2qTK8QRkfKCH+pdlveN/t
 guMunVNau6hr42tay/OtCcHPulDs/qlndwDeqymFwbYFIcVFkx5BpGthimntYHra
 rwzIqvz1u1eRY8O4czQSWXctJR/LWn+8xLzQrToGoa+7UjZJ1Dj9PYuTT7ePOc7Q
 /OrR5M+f6CGc99PaA39oMfmoqe/HCXIEWBhuMS8CJJMW1JFozNKHraOTcT25pPCt
 6cxDmOZn/RlVY3bwjy4AInikbcVOmjTT7uCRuFTiB890prLMeBHlL51gzxQgo/Qk
 1eelpW/E1YOMt8eULm0K5o+wrFepWto/fiH17SvjxDJKMM0YAoCJhrSvD794lF3u
 e8ISDB1rw7RoE8NsByAsnde5IrRl0jBdjHHi4gMt+34iMzMsWoA0GNwFB0DjclEU
 DVEsqLbVzpRFSaWTR6pqJIEJBmKJtd4JdvgNDSsVIp5ungrwYxmr2Ta1VnvroWYo
 Wt42MCv37jhBF4o50CVKgEcGX8g4Ka4hwSxXJTt142hIQ8xQNGXNBx5tzBlFwPnl
 WxwzbCxdsVCW53/EHaUDc7114pRPD/p8zaGn91kh99eh8hxZJcDNqAQlt2Xgv2Ek
 260ZlHXYdKCa1/FGEuk93A==
 =Y0ng
 -----END PGP SIGNATURE-----

Merge tag 'pwm/for-4.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm

Pull pwm updates from Thierry Reding:
 "This contains mostly minor bug fixes as well as some new chip support
  for existing drivers"

* tag 'pwm/for-4.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm:
  pwm: mediatek: Add MT7628 support
  dt-bindings: pwm: Add MT7628 information
  dt-bindings: pwm: rcar: Add bindings for R-Car E3 support
  pwm: meson: Fix mux clock names
  pwm: stm32-lp: Remove useless loop in stm32_pwm_lp_remove()
  pwm: omap-dmtimer: Return -EPROBE_DEFER if no dmtimer platform data
  pwm: mxs: Switch to SPDX identifier
  dt-bindings: pwm: fsl-ftm: Add compatible string for i.MX8QM
  pwm: fsl-ftm: Enable support for the new SoC i.MX8QM
  pwm: fsl-ftm: Added the support of per-compatible data
  pwm: fsl-ftm: Added a dedicated IP interface clock
  pwm: cros-ec: Switch to SPDX identifier
  pwm: imx: Switch to SPDX identifier
  pwm: tiehrpwm: Fix disabling of output of PWMs
  pwm: tiehrpwm: Don't use emulation mode bits to control PWM output
  pwm: berlin: Don't use broken prescaler values
This commit is contained in:
Linus Torvalds 2018-08-23 15:51:09 -07:00
commit b39d7efc11
14 changed files with 115 additions and 66 deletions

View File

@ -16,7 +16,10 @@ modes in device tree.
Required properties:
- compatible: Should be "fsl,vf610-ftm-pwm".
- compatible : should be "fsl,<soc>-ftm-pwm" and one of the following
compatible strings:
- "fsl,vf610-ftm-pwm" for PWM compatible with the one integrated on VF610
- "fsl,imx8qm-ftm-pwm" for PWM compatible with the one integrated on i.MX8QM
- reg: Physical base address and length of the controller's registers
- #pwm-cells: Should be 3. See pwm.txt in this directory for a description of
the cells format.

View File

@ -5,11 +5,13 @@ Required properties:
- "mediatek,mt2712-pwm": found on mt2712 SoC.
- "mediatek,mt7622-pwm": found on mt7622 SoC.
- "mediatek,mt7623-pwm": found on mt7623 SoC.
- "mediatek,mt7628-pwm": found on mt7628 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.
- clocks: phandle and clock specifier of the PWM reference clock.
- clock-names: must contain the following:
- clock-names: must contain the following, except for MT7628 which
has no clocks
- "top": the top clock generator
- "main": clock used by the PWM core
- "pwm1-8": the eight per PWM clocks for mt2712

View File

@ -12,6 +12,7 @@ Required Properties:
- "renesas,pwm-r8a7795": for R-Car H3
- "renesas,pwm-r8a7796": for R-Car M3-W
- "renesas,pwm-r8a77965": for R-Car M3-N
- "renesas,pwm-r8a77990": for R-Car E3
- "renesas,pwm-r8a77995": for R-Car D3
- reg: base address and length of the registers block for the PWM.
- #pwm-cells: should be 2. See pwm.txt in this directory for a description of

View File

@ -286,7 +286,7 @@ config PWM_MTK_DISP
config PWM_MEDIATEK
tristate "MediaTek PWM support"
depends on ARCH_MEDIATEK || COMPILE_TEST
depends on ARCH_MEDIATEK || RALINK || COMPILE_TEST
help
Generic PWM framework driver for Mediatek ARM SoC.

View File

@ -21,8 +21,18 @@
#define BERLIN_PWM_EN 0x0
#define BERLIN_PWM_ENABLE BIT(0)
#define BERLIN_PWM_CONTROL 0x4
#define BERLIN_PWM_PRESCALE_MASK 0x7
#define BERLIN_PWM_PRESCALE_MAX 4096
/*
* The prescaler claims to support 8 different moduli, configured using the
* low three bits of PWM_CONTROL. (Sequentially, they are 1, 4, 8, 16, 64,
* 256, 1024, and 4096.) However, the moduli from 4 to 1024 appear to be
* implemented by internally shifting TCNT left without adding additional
* bits. So, the max TCNT that actually works for a modulus of 4 is 0x3fff;
* for 8, 0x1fff; and so on. This means that those moduli are entirely
* useless, as we could just do the shift ourselves. The 4096 modulus is
* implemented with a real prescaler, so we do use that, but we treat it
* as a flag instead of pretending the modulus is actually configurable.
*/
#define BERLIN_PWM_PRESCALE_4096 0x7
#define BERLIN_PWM_INVERT_POLARITY BIT(3)
#define BERLIN_PWM_DUTY 0x8
#define BERLIN_PWM_TCNT 0xc
@ -46,10 +56,6 @@ static inline struct berlin_pwm_chip *to_berlin_pwm_chip(struct pwm_chip *chip)
return container_of(chip, struct berlin_pwm_chip, chip);
}
static const u32 prescaler_table[] = {
1, 4, 8, 16, 64, 256, 1024, 4096
};
static inline u32 berlin_pwm_readl(struct berlin_pwm_chip *chip,
unsigned int channel, unsigned long offset)
{
@ -86,33 +92,32 @@ static int berlin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm_dev,
int duty_ns, int period_ns)
{
struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip);
unsigned int prescale;
bool prescale_4096 = false;
u32 value, duty, period;
u64 cycles, tmp;
u64 cycles;
cycles = clk_get_rate(pwm->clk);
cycles *= period_ns;
do_div(cycles, NSEC_PER_SEC);
for (prescale = 0; prescale < ARRAY_SIZE(prescaler_table); prescale++) {
tmp = cycles;
do_div(tmp, prescaler_table[prescale]);
if (cycles > BERLIN_PWM_MAX_TCNT) {
prescale_4096 = true;
cycles >>= 12; // Prescaled by 4096
if (tmp <= BERLIN_PWM_MAX_TCNT)
break;
if (cycles > BERLIN_PWM_MAX_TCNT)
return -ERANGE;
}
if (tmp > BERLIN_PWM_MAX_TCNT)
return -ERANGE;
period = tmp;
cycles = tmp * duty_ns;
period = cycles;
cycles *= duty_ns;
do_div(cycles, period_ns);
duty = cycles;
value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_CONTROL);
value &= ~BERLIN_PWM_PRESCALE_MASK;
value |= prescale;
if (prescale_4096)
value |= BERLIN_PWM_PRESCALE_4096;
else
value &= ~BERLIN_PWM_PRESCALE_4096;
berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_CONTROL);
berlin_pwm_writel(pwm, pwm_dev->hwpwm, duty, BERLIN_PWM_DUTY);

View File

@ -1,11 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2016 Google, Inc
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2, as published by
* the Free Software Foundation.
*
* Expose a PWM controlled by the ChromeOS EC to the host processor.
*
* Copyright (C) 2016 Google, Inc.
*/
#include <linux/module.h>

View File

@ -16,6 +16,7 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/pwm.h>
@ -75,6 +76,10 @@ enum fsl_pwm_clk {
FSL_PWM_CLK_MAX
};
struct fsl_ftm_soc {
bool has_enable_bits;
};
struct fsl_pwm_chip {
struct pwm_chip chip;
@ -87,7 +92,10 @@ struct fsl_pwm_chip {
int period_ns;
struct clk *ipg_clk;
struct clk *clk[FSL_PWM_CLK_MAX];
const struct fsl_ftm_soc *soc;
};
static inline struct fsl_pwm_chip *to_fsl_chip(struct pwm_chip *chip)
@ -97,16 +105,32 @@ static inline struct fsl_pwm_chip *to_fsl_chip(struct pwm_chip *chip)
static int fsl_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
{
int ret;
struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
return clk_prepare_enable(fpc->clk[FSL_PWM_CLK_SYS]);
ret = clk_prepare_enable(fpc->ipg_clk);
if (!ret && fpc->soc->has_enable_bits) {
mutex_lock(&fpc->lock);
regmap_update_bits(fpc->regmap, FTM_SC, BIT(pwm->hwpwm + 16),
BIT(pwm->hwpwm + 16));
mutex_unlock(&fpc->lock);
}
return ret;
}
static void fsl_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
{
struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]);
if (fpc->soc->has_enable_bits) {
mutex_lock(&fpc->lock);
regmap_update_bits(fpc->regmap, FTM_SC, BIT(pwm->hwpwm + 16),
0);
mutex_unlock(&fpc->lock);
}
clk_disable_unprepare(fpc->ipg_clk);
}
static int fsl_pwm_calculate_default_ps(struct fsl_pwm_chip *fpc,
@ -363,7 +387,7 @@ static int fsl_pwm_init(struct fsl_pwm_chip *fpc)
{
int ret;
ret = clk_prepare_enable(fpc->clk[FSL_PWM_CLK_SYS]);
ret = clk_prepare_enable(fpc->ipg_clk);
if (ret)
return ret;
@ -371,7 +395,7 @@ static int fsl_pwm_init(struct fsl_pwm_chip *fpc)
regmap_write(fpc->regmap, FTM_OUTINIT, 0x00);
regmap_write(fpc->regmap, FTM_OUTMASK, 0xFF);
clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]);
clk_disable_unprepare(fpc->ipg_clk);
return 0;
}
@ -408,6 +432,7 @@ static int fsl_pwm_probe(struct platform_device *pdev)
mutex_init(&fpc->lock);
fpc->soc = of_device_get_match_data(&pdev->dev);
fpc->chip.dev = &pdev->dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@ -441,6 +466,15 @@ static int fsl_pwm_probe(struct platform_device *pdev)
if (IS_ERR(fpc->clk[FSL_PWM_CLK_CNTEN]))
return PTR_ERR(fpc->clk[FSL_PWM_CLK_CNTEN]);
/*
* ipg_clk is the interface clock for the IP. If not provided, use the
* ftm_sys clock as the default.
*/
fpc->ipg_clk = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(fpc->ipg_clk))
fpc->ipg_clk = fpc->clk[FSL_PWM_CLK_SYS];
fpc->chip.ops = &fsl_pwm_ops;
fpc->chip.of_xlate = of_pwm_xlate_with_flags;
fpc->chip.of_pwm_n_cells = 3;
@ -480,7 +514,7 @@ static int fsl_pwm_suspend(struct device *dev)
if (!test_bit(PWMF_REQUESTED, &pwm->flags))
continue;
clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]);
clk_disable_unprepare(fpc->ipg_clk);
if (!pwm_is_enabled(pwm))
continue;
@ -503,7 +537,7 @@ static int fsl_pwm_resume(struct device *dev)
if (!test_bit(PWMF_REQUESTED, &pwm->flags))
continue;
clk_prepare_enable(fpc->clk[FSL_PWM_CLK_SYS]);
clk_prepare_enable(fpc->ipg_clk);
if (!pwm_is_enabled(pwm))
continue;
@ -524,8 +558,17 @@ static const struct dev_pm_ops fsl_pwm_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(fsl_pwm_suspend, fsl_pwm_resume)
};
static const struct fsl_ftm_soc vf610_ftm_pwm = {
.has_enable_bits = false,
};
static const struct fsl_ftm_soc imx8qm_ftm_pwm = {
.has_enable_bits = true,
};
static const struct of_device_id fsl_pwm_dt_ids[] = {
{ .compatible = "fsl,vf610-ftm-pwm", },
{ .compatible = "fsl,vf610-ftm-pwm", .data = &vf610_ftm_pwm },
{ .compatible = "fsl,imx8qm-ftm-pwm", .data = &imx8qm_ftm_pwm },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, fsl_pwm_dt_ids);

View File

@ -1,10 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/*
* simple driver for PWM (Pulse Width Modulator) controller
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Derived from pxa PWM driver by eric miao <eric.miao@marvell.com>
*/

View File

@ -57,6 +57,7 @@ static const char * const mtk_pwm_clk_name[MTK_CLK_MAX] = {
struct mtk_pwm_platform_data {
unsigned int num_pwms;
bool pwm45_fixup;
bool has_clks;
};
/**
@ -86,6 +87,9 @@ static int mtk_pwm_clk_enable(struct pwm_chip *chip, struct pwm_device *pwm)
struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
int ret;
if (!pc->soc->has_clks)
return 0;
ret = clk_prepare_enable(pc->clks[MTK_CLK_TOP]);
if (ret < 0)
return ret;
@ -112,6 +116,9 @@ static void mtk_pwm_clk_disable(struct pwm_chip *chip, struct pwm_device *pwm)
{
struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
if (!pc->soc->has_clks)
return;
clk_disable_unprepare(pc->clks[MTK_CLK_PWM1 + pwm->hwpwm]);
clk_disable_unprepare(pc->clks[MTK_CLK_MAIN]);
clk_disable_unprepare(pc->clks[MTK_CLK_TOP]);
@ -239,7 +246,7 @@ static int mtk_pwm_probe(struct platform_device *pdev)
if (IS_ERR(pc->regs))
return PTR_ERR(pc->regs);
for (i = 0; i < data->num_pwms + 2; i++) {
for (i = 0; i < data->num_pwms + 2 && pc->soc->has_clks; i++) {
pc->clks[i] = devm_clk_get(&pdev->dev, mtk_pwm_clk_name[i]);
if (IS_ERR(pc->clks[i])) {
dev_err(&pdev->dev, "clock: %s fail: %ld\n",
@ -274,22 +281,32 @@ static int mtk_pwm_remove(struct platform_device *pdev)
static const struct mtk_pwm_platform_data mt2712_pwm_data = {
.num_pwms = 8,
.pwm45_fixup = false,
.has_clks = true,
};
static const struct mtk_pwm_platform_data mt7622_pwm_data = {
.num_pwms = 6,
.pwm45_fixup = false,
.has_clks = true,
};
static const struct mtk_pwm_platform_data mt7623_pwm_data = {
.num_pwms = 5,
.pwm45_fixup = true,
.has_clks = true,
};
static const struct mtk_pwm_platform_data mt7628_pwm_data = {
.num_pwms = 4,
.pwm45_fixup = true,
.has_clks = false,
};
static const struct of_device_id mtk_pwm_of_match[] = {
{ .compatible = "mediatek,mt2712-pwm", .data = &mt2712_pwm_data },
{ .compatible = "mediatek,mt7622-pwm", .data = &mt7622_pwm_data },
{ .compatible = "mediatek,mt7623-pwm", .data = &mt7623_pwm_data },
{ .compatible = "mediatek,mt7628-pwm", .data = &mt7628_pwm_data },
{ },
};
MODULE_DEVICE_TABLE(of, mtk_pwm_of_match);

View File

@ -458,7 +458,6 @@ static int meson_pwm_init_channels(struct meson_pwm *meson,
struct meson_pwm_channel *channels)
{
struct device *dev = meson->chip.dev;
struct device_node *np = dev->of_node;
struct clk_init_data init;
unsigned int i;
char name[255];
@ -467,7 +466,7 @@ static int meson_pwm_init_channels(struct meson_pwm *meson,
for (i = 0; i < meson->chip.npwm; i++) {
struct meson_pwm_channel *channel = &channels[i];
snprintf(name, sizeof(name), "%pOF#mux%u", np, i);
snprintf(name, sizeof(name), "%s#mux%u", dev_name(dev), i);
init.name = name;
init.ops = &clk_mux_ops;

View File

@ -1,12 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2012 Freescale Semiconductor, Inc.
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
#include <linux/clk.h>

View File

@ -264,8 +264,9 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
timer_pdata = dev_get_platdata(&timer_pdev->dev);
if (!timer_pdata) {
dev_err(&pdev->dev, "dmtimer pdata structure NULL\n");
ret = -EINVAL;
dev_dbg(&pdev->dev,
"dmtimer pdata structure NULL, deferring probe\n");
ret = -EPROBE_DEFER;
goto put;
}

View File

@ -217,10 +217,8 @@ static int stm32_pwm_lp_probe(struct platform_device *pdev)
static int stm32_pwm_lp_remove(struct platform_device *pdev)
{
struct stm32_pwm_lp *priv = platform_get_drvdata(pdev);
unsigned int i;
for (i = 0; i < priv->chip.npwm; i++)
pwm_disable(&priv->chip.pwms[i]);
pwm_disable(&priv->chip.pwms[0]);
return pwmchip_remove(&priv->chip);
}

View File

@ -33,10 +33,6 @@
#define TBCTL 0x00
#define TBPRD 0x0A
#define TBCTL_RUN_MASK (BIT(15) | BIT(14))
#define TBCTL_STOP_NEXT 0
#define TBCTL_STOP_ON_CYCLE BIT(14)
#define TBCTL_FREE_RUN (BIT(15) | BIT(14))
#define TBCTL_PRDLD_MASK BIT(3)
#define TBCTL_PRDLD_SHDW 0
#define TBCTL_PRDLD_IMDT BIT(3)
@ -360,7 +356,7 @@ static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
/* Channels polarity can be configured from action qualifier module */
configure_polarity(pc, pwm->hwpwm);
/* Enable TBCLK before enabling PWM device */
/* Enable TBCLK */
ret = clk_enable(pc->tbclk);
if (ret) {
dev_err(chip->dev, "Failed to enable TBCLK for %s: %d\n",
@ -368,9 +364,6 @@ static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
return ret;
}
/* Enable time counter for free_run */
ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_FREE_RUN);
return 0;
}
@ -388,6 +381,8 @@ static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
aqcsfrc_mask = AQCSFRC_CSFA_MASK;
}
/* Update shadow register first before modifying active register */
ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val);
/*
* Changes to immediate action on Action Qualifier. This puts
* Action Qualifier control on PWM output from next TBCLK
@ -400,9 +395,6 @@ static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
/* Disabling TBCLK on PWM disable */
clk_disable(pc->tbclk);
/* Stop Time base counter */
ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_STOP_NEXT);
/* Disable clock on PWM disable */
pm_runtime_put_sync(chip->dev);
}