Merge tag 'pwm/for-5.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm
Merge commit. Changes below are compared with the first parent: 8f02f363.
Changes
13 files changed · +438 −45
| File | Status | Add | Del | Content |
|---|---|---|---|---|
| Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.yaml | modified | +1 | −0 | View file |
| MAINTAINERS | modified | +1 | −0 | View file |
| drivers/pwm/Kconfig | modified | +11 | −1 | View file |
| drivers/pwm/Makefile | modified | +1 | −0 | View file |
| drivers/pwm/core.c | modified | +2 | −2 | View file |
| drivers/pwm/pwm-img.c | modified | +6 | −2 | View file |
| drivers/pwm/pwm-imx27.c | modified | +10 | −10 | View file |
| drivers/pwm/pwm-iqs620a.c | added | +270 | −0 | View file |
| drivers/pwm/pwm-jz4740.c | modified | +39 | −16 | View file |
| drivers/pwm/pwm-lpss.c | modified | +11 | −4 | View file |
| drivers/pwm/pwm-rockchip.c | modified | +1 | −6 | View file |
| drivers/pwm/pwm-sun4i.c | modified | +9 | −0 | View file |
| drivers/pwm/pwm-tegra.c | modified | +76 | −4 | View file |
Only the first 600 diff lines are shown. Download the complete patch.
Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.yaml
View filediff --git a/Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.yaml b/Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.yaml
index 461afb4..daadde9 100644
--- a/Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.yaml
+++ b/Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.yaml
@@ -27,6 +27,7 @@ properties:
- renesas,pwm-r8a7794 # R-Car E2
- renesas,pwm-r8a7795 # R-Car H3
- renesas,pwm-r8a7796 # R-Car M3-W
+ - renesas,pwm-r8a77961 # R-Car M3-W+
- renesas,pwm-r8a77965 # R-Car M3-N
- renesas,pwm-r8a77970 # R-Car V3M
- renesas,pwm-r8a77980 # R-Car V3H
MAINTAINERS
View filediff --git a/MAINTAINERS b/MAINTAINERS
index b0642aa..b5cbbc2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13919,6 +13919,7 @@ F: drivers/media/rc/pwm-ir-tx.c
PWM SUBSYSTEM
M: Thierry Reding <[email protected]>
R: Uwe Kleine-König <[email protected]>
+M: Lee Jones <[email protected]>
S: Maintained
Q: https://patchwork.ozlabs.org/project/linux-pwm/list/
drivers/pwm/Kconfig
View filediff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index eebbc91..cb8d739 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -232,9 +232,19 @@ config PWM_IMX_TPM
To compile this driver as a module, choose M here: the module
will be called pwm-imx-tpm.
+config PWM_IQS620A
+ tristate "Azoteq IQS620A PWM support"
+ depends on MFD_IQS62X || COMPILE_TEST
+ help
+ Generic PWM framework driver for the Azoteq IQS620A multi-function
+ sensor.
+
+ To compile this driver as a module, choose M here: the module will
+ be called pwm-iqs620a.
+
config PWM_JZ4740
tristate "Ingenic JZ47xx PWM support"
- depends on MACH_INGENIC
+ depends on MIPS
depends on COMMON_CLK
select MFD_SYSCON
help
drivers/pwm/Makefile
View filediff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 9a47507..a59c710 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_PWM_IMG) += pwm-img.o
obj-$(CONFIG_PWM_IMX1) += pwm-imx1.o
obj-$(CONFIG_PWM_IMX27) += pwm-imx27.o
obj-$(CONFIG_PWM_IMX_TPM) += pwm-imx-tpm.o
+obj-$(CONFIG_PWM_IQS620A) += pwm-iqs620a.o
obj-$(CONFIG_PWM_JZ4740) += pwm-jz4740.o
obj-$(CONFIG_PWM_LP3943) += pwm-lp3943.o
obj-$(CONFIG_PWM_LPC18XX_SCT) += pwm-lpc18xx-sct.o
drivers/pwm/core.c
View filediff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index 9973c44..004b2ea 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -121,7 +121,7 @@ static int pwm_device_request(struct pwm_device *pwm, const char *label)
pwm->chip->ops->get_state(pwm->chip, pwm, &pwm->state);
trace_pwm_get(pwm, &pwm->state);
- if (IS_ENABLED(PWM_DEBUG))
+ if (IS_ENABLED(CONFIG_PWM_DEBUG))
pwm->last = pwm->state;
}
@@ -537,7 +537,7 @@ static void pwm_apply_state_debug(struct pwm_device *pwm,
if (!state->enabled && s2.enabled && s2.duty_cycle > 0)
dev_warn(chip->dev,
- "requested disabled, but yielded enabled with duty > 0");
+ "requested disabled, but yielded enabled with duty > 0\n");
/* reapply the state that the driver reported being configured. */
err = chip->ops->apply(chip, pwm, &s1);
drivers/pwm/pwm-img.c
View filediff --git a/drivers/pwm/pwm-img.c b/drivers/pwm/pwm-img.c
index c9e57bd..599a0f6 100644
--- a/drivers/pwm/pwm-img.c
+++ b/drivers/pwm/pwm-img.c
@@ -129,8 +129,10 @@ static int img_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
duty = DIV_ROUND_UP(timebase * duty_ns, period_ns);
ret = pm_runtime_get_sync(chip->dev);
- if (ret < 0)
+ if (ret < 0) {
+ pm_runtime_put_autosuspend(chip->dev);
return ret;
+ }
val = img_pwm_readl(pwm_chip, PWM_CTRL_CFG);
val &= ~(PWM_CTRL_CFG_DIV_MASK << PWM_CTRL_CFG_DIV_SHIFT(pwm->hwpwm));
@@ -331,8 +333,10 @@ static int img_pwm_remove(struct platform_device *pdev)
int ret;
ret = pm_runtime_get_sync(&pdev->dev);
- if (ret < 0)
+ if (ret < 0) {
+ pm_runtime_put(&pdev->dev);
return ret;
+ }
for (i = 0; i < pwm_chip->chip.npwm; i++) {
val = img_pwm_readl(pwm_chip, PWM_CTRL_CFG);
drivers/pwm/pwm-imx27.c
View filediff --git a/drivers/pwm/pwm-imx27.c b/drivers/pwm/pwm-imx27.c
index a6e40d4..732a6f3 100644
--- a/drivers/pwm/pwm-imx27.c
+++ b/drivers/pwm/pwm-imx27.c
@@ -150,13 +150,12 @@ static void pwm_imx27_get_state(struct pwm_chip *chip,
prescaler = MX3_PWMCR_PRESCALER_GET(val);
pwm_clk = clk_get_rate(imx->clk_per);
- pwm_clk = DIV_ROUND_CLOSEST_ULL(pwm_clk, prescaler);
val = readl(imx->mmio_base + MX3_PWMPR);
period = val >= MX3_PWMPR_MAX ? MX3_PWMPR_MAX : val;
/* PWMOUT (Hz) = PWMCLK / (PWMPR + 2) */
- tmp = NSEC_PER_SEC * (u64)(period + 2);
- state->period = DIV_ROUND_CLOSEST_ULL(tmp, pwm_clk);
+ tmp = NSEC_PER_SEC * (u64)(period + 2) * prescaler;
+ state->period = DIV_ROUND_UP_ULL(tmp, pwm_clk);
/*
* PWMSAR can be read only if PWM is enabled. If the PWM is disabled,
@@ -167,8 +166,8 @@ static void pwm_imx27_get_state(struct pwm_chip *chip,
else
val = imx->duty_cycle;
- tmp = NSEC_PER_SEC * (u64)(val);
- state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, pwm_clk);
+ tmp = NSEC_PER_SEC * (u64)(val) * prescaler;
+ state->duty_cycle = DIV_ROUND_UP_ULL(tmp, pwm_clk);
pwm_imx27_clk_disable_unprepare(imx);
}
@@ -220,22 +219,23 @@ static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm,
struct pwm_imx27_chip *imx = to_pwm_imx27_chip(chip);
struct pwm_state cstate;
unsigned long long c;
+ unsigned long long clkrate;
int ret;
u32 cr;
pwm_get_state(pwm, &cstate);
- c = clk_get_rate(imx->clk_per);
- c *= state->period;
+ clkrate = clk_get_rate(imx->clk_per);
+ c = clkrate * state->period;
- do_div(c, 1000000000);
+ do_div(c, NSEC_PER_SEC);
period_cycles = c;
prescale = period_cycles / 0x10000 + 1;
period_cycles /= prescale;
- c = (unsigned long long)period_cycles * state->duty_cycle;
- do_div(c, state->period);
+ c = clkrate * state->duty_cycle;
+ do_div(c, NSEC_PER_SEC * prescale);
duty_cycles = c;
/*
drivers/pwm/pwm-iqs620a.c
View filediff --git a/drivers/pwm/pwm-iqs620a.c b/drivers/pwm/pwm-iqs620a.c
new file mode 100644
index 0000000..674f0e2
--- /dev/null
+++ b/drivers/pwm/pwm-iqs620a.c
@@ -0,0 +1,270 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Azoteq IQS620A PWM Generator
+ *
+ * Copyright (C) 2019 Jeff LaBundy <[email protected]>
+ *
+ * Limitations:
+ * - The period is fixed to 1 ms and is generated continuously despite changes
+ * to the duty cycle or enable/disable state.
+ * - Changes to the duty cycle or enable/disable state take effect immediately
+ * and may result in a glitch during the period in which the change is made.
+ * - The device cannot generate a 0% duty cycle. For duty cycles below 1 / 256
+ * ms, the output is disabled and relies upon an external pull-down resistor
+ * to hold the GPIO3/LTX pin low.
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/mfd/iqs62x.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/notifier.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#define IQS620_PWR_SETTINGS 0xD2
+#define IQS620_PWR_SETTINGS_PWM_OUT BIT(7)
+
+#define IQS620_PWM_DUTY_CYCLE 0xD8
+
+#define IQS620_PWM_PERIOD_NS 1000000
+
+struct iqs620_pwm_private {
+ struct iqs62x_core *iqs62x;
+ struct pwm_chip chip;
+ struct notifier_block notifier;
+ struct mutex lock;
+ bool out_en;
+ u8 duty_val;
+};
+
+static int iqs620_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+ const struct pwm_state *state)
+{
+ struct iqs620_pwm_private *iqs620_pwm;
+ struct iqs62x_core *iqs62x;
+ int duty_scale, ret;
+
+ if (state->polarity != PWM_POLARITY_NORMAL)
+ return -ENOTSUPP;
+
+ if (state->period < IQS620_PWM_PERIOD_NS)
+ return -EINVAL;
+
+ iqs620_pwm = container_of(chip, struct iqs620_pwm_private, chip);
+ iqs62x = iqs620_pwm->iqs62x;
+
+ /*
+ * The duty cycle generated by the device is calculated as follows:
+ *
+ * duty_cycle = (IQS620_PWM_DUTY_CYCLE + 1) / 256 * 1 ms
+ *
+ * ...where IQS620_PWM_DUTY_CYCLE is a register value between 0 and 255
+ * (inclusive). Therefore the lowest duty cycle the device can generate
+ * while the output is enabled is 1 / 256 ms.
+ *
+ * For lower duty cycles (e.g. 0), the PWM output is simply disabled to
+ * allow an external pull-down resistor to hold the GPIO3/LTX pin low.
+ */
+ duty_scale = state->duty_cycle * 256 / IQS620_PWM_PERIOD_NS;
+
+ mutex_lock(&iqs620_pwm->lock);
+
+ if (!state->enabled || !duty_scale) {
+ ret = regmap_update_bits(iqs62x->regmap, IQS620_PWR_SETTINGS,
+ IQS620_PWR_SETTINGS_PWM_OUT, 0);
+ if (ret)
+ goto err_mutex;
+ }
+
+ if (duty_scale) {
+ u8 duty_val = min(duty_scale - 1, 0xFF);
+
+ ret = regmap_write(iqs62x->regmap, IQS620_PWM_DUTY_CYCLE,
+ duty_val);
+ if (ret)
+ goto err_mutex;
+
+ iqs620_pwm->duty_val = duty_val;
+ }
+
+ if (state->enabled && duty_scale) {
+ ret = regmap_update_bits(iqs62x->regmap, IQS620_PWR_SETTINGS,
+ IQS620_PWR_SETTINGS_PWM_OUT, 0xFF);
+ if (ret)
+ goto err_mutex;
+ }
+
+ iqs620_pwm->out_en = state->enabled;
+
+err_mutex:
+ mutex_unlock(&iqs620_pwm->lock);
+
+ return ret;
+}
+
+static void iqs620_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
+ struct pwm_state *state)
+{
+ struct iqs620_pwm_private *iqs620_pwm;
+
+ iqs620_pwm = container_of(chip, struct iqs620_pwm_private, chip);
+
+ mutex_lock(&iqs620_pwm->lock);
+
+ /*
+ * Since the device cannot generate a 0% duty cycle, requests to do so
+ * cause subsequent calls to iqs620_pwm_get_state to report the output
+ * as disabled with duty cycle equal to that which was in use prior to
+ * the request. This is not ideal, but is the best compromise based on
+ * the capabilities of the device.
+ */
+ state->enabled = iqs620_pwm->out_en;
+ state->duty_cycle = DIV_ROUND_UP((iqs620_pwm->duty_val + 1) *
+ IQS620_PWM_PERIOD_NS, 256);
+
+ mutex_unlock(&iqs620_pwm->lock);
+
+ state->period = IQS620_PWM_PERIOD_NS;
+}
+
+static int iqs620_pwm_notifier(struct notifier_block *notifier,
+ unsigned long event_flags, void *context)
+{
+ struct iqs620_pwm_private *iqs620_pwm;
+ struct iqs62x_core *iqs62x;
+ int ret;
+
+ if (!(event_flags & BIT(IQS62X_EVENT_SYS_RESET)))
+ return NOTIFY_DONE;
+
+ iqs620_pwm = container_of(notifier, struct iqs620_pwm_private,
+ notifier);
+ iqs62x = iqs620_pwm->iqs62x;
+
+ mutex_lock(&iqs620_pwm->lock);
+
+ /*
+ * The parent MFD driver already prints an error message in the event
+ * of a device reset, so nothing else is printed here unless there is
+ * an additional failure.
+ */
+ ret = regmap_write(iqs62x->regmap, IQS620_PWM_DUTY_CYCLE,
+ iqs620_pwm->duty_val);
+ if (ret)
+ goto err_mutex;
+
+ ret = regmap_update_bits(iqs62x->regmap, IQS620_PWR_SETTINGS,
+ IQS620_PWR_SETTINGS_PWM_OUT,
+ iqs620_pwm->out_en ? 0xFF : 0);
+
+err_mutex:
+ mutex_unlock(&iqs620_pwm->lock);
+
+ if (ret) {
+ dev_err(iqs620_pwm->chip.dev,
+ "Failed to re-initialize device: %d\n", ret);
+ return NOTIFY_BAD;
+ }
+
+ return NOTIFY_OK;
+}
+
+static const struct pwm_ops iqs620_pwm_ops = {
+ .apply = iqs620_pwm_apply,
+ .get_state = iqs620_pwm_get_state,
+ .owner = THIS_MODULE,
+};
+
+static void iqs620_pwm_notifier_unregister(void *context)
+{
+ struct iqs620_pwm_private *iqs620_pwm = context;
+ int ret;
+
+ ret = blocking_notifier_chain_unregister(&iqs620_pwm->iqs62x->nh,
+ &iqs620_pwm->notifier);
+ if (ret)
+ dev_err(iqs620_pwm->chip.dev,
+ "Failed to unregister notifier: %d\n", ret);
+}
+
+static int iqs620_pwm_probe(struct platform_device *pdev)
+{
+ struct iqs62x_core *iqs62x = dev_get_drvdata(pdev->dev.parent);
+ struct iqs620_pwm_private *iqs620_pwm;
+ unsigned int val;
+ int ret;
+
+ iqs620_pwm = devm_kzalloc(&pdev->dev, sizeof(*iqs620_pwm), GFP_KERNEL);
+ if (!iqs620_pwm)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, iqs620_pwm);
+ iqs620_pwm->iqs62x = iqs62x;
+
+ ret = regmap_read(iqs62x->regmap, IQS620_PWR_SETTINGS, &val);
+ if (ret)
+ return ret;
+ iqs620_pwm->out_en = val & IQS620_PWR_SETTINGS_PWM_OUT;
+
+ ret = regmap_read(iqs62x->regmap, IQS620_PWM_DUTY_CYCLE, &val);
+ if (ret)
+ return ret;
+ iqs620_pwm->duty_val = val;
+
+ 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);
+
+ iqs620_pwm->notifier.notifier_call = iqs620_pwm_notifier;
+ ret = blocking_notifier_chain_register(&iqs620_pwm->iqs62x->nh,
+ &iqs620_pwm->notifier);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register notifier: %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_add_action_or_reset(&pdev->dev,
+ iqs620_pwm_notifier_unregister,
+ iqs620_pwm);
+ if (ret)
+ return ret;
+
+ ret = pwmchip_add(&iqs620_pwm->chip);
+ if (ret)
+ dev_err(&pdev->dev, "Failed to add device: %d\n", ret);
+
+ return ret;
+}
+
+static int iqs620_pwm_remove(struct platform_device *pdev)
+{
+ struct iqs620_pwm_private *iqs620_pwm = platform_get_drvdata(pdev);
+ int ret;
+
+ ret = pwmchip_remove(&iqs620_pwm->chip);
+ if (ret)
+ dev_err(&pdev->dev, "Failed to remove device: %d\n", ret);
+
+ return ret;
+}
+
+static struct platform_driver iqs620_pwm_platform_driver = {
+ .driver = {
+ .name = "iqs620a-pwm",
+ },
+ .probe = iqs620_pwm_probe,
+ .remove = iqs620_pwm_remove,
+};
+module_platform_driver(iqs620_pwm_platform_driver);
+
+MODULE_AUTHOR("Jeff LaBundy <[email protected]>");
+MODULE_DESCRIPTION("Azoteq IQS620A PWM Generator");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:iqs620a-pwm");
drivers/pwm/pwm-jz4740.c
View filediff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c
index 3cd5c05..5830ac2 100644
--- a/drivers/pwm/pwm-jz4740.c
+++ b/drivers/pwm/pwm-jz4740.c
@@ -6,7 +6,6 @@
* Limitations:
* - The .apply callback doesn't complete the currently running period before
* reconfiguring the hardware.
- * - Each period starts with the inactive part.
*/
#include <linux/clk.h>
@@ -21,7 +20,9 @@
#include <linux/pwm.h>
#include <linux/regmap.h>
-#define NUM_PWM 8
+struct soc_info {
+ unsigned int num_pwms;
+};
struct jz4740_pwm_chip {
struct pwm_chip chip;
@@ -37,7 +38,7 @@ static bool jz4740_pwm_can_use_chn(struct jz4740_pwm_chip *jz,
unsigned int channel)
{
/* Enable all TCU channels for PWM use by default except channels 0/1 */
- u32 pwm_channels_mask = GENMASK(NUM_PWM - 1, 2);
+ u32 pwm_channels_mask = GENMASK(jz->chip.npwm - 1, 2);
device_property_read_u32(jz->chip.dev->parent,
"ingenic,pwm-channels-mask",
@@ -158,12 +159,12 @@ static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
/* Calculate period value */
tmp = (unsigned long long)rate * state->period;
do_div(tmp, NSEC_PER_SEC);
- period = (unsigned long)tmp;
+ period = tmp;
/* Calculate duty value */
- tmp = (unsigned long long)period * state->duty_cycle;
- do_div(tmp, state->period);
- duty = period - tmp;
+ tmp = (unsigned long long)rate * state->duty_cycle;
+ do_div(tmp, NSEC_PER_SEC);
+ duty = tmp;
if (duty >= period)
duty = period - 1;
@@ -189,18 +190,26 @@ static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
regmap_update_bits(jz4740->map, TCU_REG_TCSRc(pwm->hwpwm),
TCU_TCSR_PWM_SD, TCU_TCSR_PWM_SD);
- /* Set polarity */
- switch (state->polarity) {
- case PWM_POLARITY_NORMAL:
+ /*
+ * Set polarity.
+ *
+ * The PWM starts in inactive state until the internal timer reaches the
+ * duty value, then becomes active until the timer reaches the period
+ * value. In theory, we should then use (period - duty) as the real duty
+ * value, as a high duty value would otherwise result in the PWM pin
+ * being inactive most of the time.
+ *
+ * Here, we don't do that, and instead invert the polarity of the PWM
+ * when it is active. This trick makes the PWM start with its active
+ * state instead of its inactive state.
+ */
+ if ((state->polarity == PWM_POLARITY_NORMAL) ^ state->enabled)
regmap_update_bits(jz4740->map, TCU_REG_TCSRc(pwm->hwpwm),
TCU_TCSR_PWM_INITL_HIGH, 0);
- break;
- case PWM_POLARITY_INVERSED:
+ else
regmap_update_bits(jz4740->map, TCU_REG_TCSRc(pwm->hwpwm),
TCU_TCSR_PWM_INITL_HIGH,
TCU_TCSR_PWM_INITL_HIGH);
- break;
- }
if (state->enabled)
jz4740_pwm_enable(chip, pwm);
@@ -219,6 +228,11 @@ static int jz4740_pwm_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct jz4740_pwm_chip *jz4740;
+ const struct soc_info *info;
+
+ info = device_get_match_data(dev);
+ if (!info)
+ return -EINVAL;
jz4740 = devm_kzalloc(dev, sizeof(*jz4740), GFP_KERNEL);
if (!jz4740)
@@ -232,7 +246,7 @@ static int jz4740_pwm_probe(struct platform_device *pdev)
jz4740->chip.dev = dev;
jz4740->chip.ops = &jz4740_pwm_ops;
- jz4740->chip.npwm = NUM_PWM;
+ 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;
@@ -249,9 +263,18 @@ static int jz4740_pwm_remove(struct platform_device *pdev)
return pwmchip_remove(&jz4740->chip);
}
+static const struct soc_info __maybe_unused jz4740_soc_info = {
+ .num_pwms = 8,
+};
+
+static const struct soc_info __maybe_unused jz4725b_soc_info = {
+ .num_pwms = 6,
+};
+
#ifdef CONFIG_OF
static const struct of_device_id jz4740_pwm_dt_ids[] = {
- { .compatible = "ingenic,jz4740-pwm", },
+ { .compatible = "ingenic,jz4740-pwm", .data = &jz4740_soc_info },
+ { .compatible = "ingenic,jz4725b-pwm", .data = &jz4725b_soc_info },
{},
};
MODULE_DEVICE_TABLE(of, jz4740_pwm_dt_ids);
drivers/pwm/pwm-lpss.c
View filediff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c
index 75bbfe5..9d965ff 100644
--- a/drivers/pwm/pwm-lpss.c
+++ b/drivers/pwm/pwm-lpss.c
@@ -158,7 +158,6 @@ static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm,
return 0;
}
-/* This function gets called once from pwmchip_add to get the initial state */
static void pwm_lpss_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
struct pwm_state *state)
{
@@ -167,6 +166,8 @@ static void pwm_lpss_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
unsigned long long base_unit, freq, on_time_div;
u32 ctrl;
+ pm_runtime_get_sync(chip->dev);
+
base_unit_range = BIT(lpwm->info->base_unit_bits);
ctrl = pwm_lpss_read(pwm);
@@ -187,8 +188,7 @@ static void pwm_lpss_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
state->polarity = PWM_POLARITY_NORMAL;
state->enabled = !!(ctrl & PWM_ENABLE);
- if (state->enabled)
- pm_runtime_get(chip->dev);
+ pm_runtime_put(chip->dev);
}
This diff is incomplete. Download the complete patch.
drivers/pwm/pwm-rockchip.c
View fileThis diff is incomplete. Download the complete patch.
drivers/pwm/pwm-sun4i.c
View fileThis diff is incomplete. Download the complete patch.
drivers/pwm/pwm-tegra.c
View fileThis diff is incomplete. Download the complete patch.