From 341e8cba6c32bb7509eabb91619a233b7ae249b9 Mon Sep 17 00:00:00 2001 From: Lokesh Vutla Date: Thu, 5 Mar 2020 13:57:10 +0530 Subject: clocksource/drivers/timer-ti-dm: Convert to SPDX identifier Use SPDX-License-Identifier instead of a verbose license text. Signed-off-by: Lokesh Vutla Acked-by: Tony Lindgren Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20200305082715.15861-2-lokeshvutla@ti.com --- drivers/clocksource/timer-ti-dm.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) (limited to 'drivers/clocksource/timer-ti-dm.c') diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c index 269a994d6a99..c0e9e9978cdd 100644 --- a/drivers/clocksource/timer-ti-dm.c +++ b/drivers/clocksource/timer-ti-dm.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * linux/arch/arm/plat-omap/dmtimer.c * @@ -15,24 +16,6 @@ * * Copyright (C) 2009 Texas Instruments * Added OMAP4 support - Santosh Shilimkar - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. */ #include -- cgit v1.2.3 From 5e20931c6a750b4b1ea9a2f7b863cc2dd9222ead Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 5 Mar 2020 13:57:11 +0530 Subject: clocksource/drivers/timer-ti-dm: Prepare for using cpuidle Let's add runtime_suspend and resume functions and atomic enabled flag. This way we can use these when converting to use cpuidle for saving and restoring device context. And we need to maintain the driver state in the driver as documented in "9. Autosuspend, or automatically-delayed suspends" in the Documentation/power/runtime_pm.rst document related to using driver private lock and races with runtime_suspend(). Signed-off-by: Tony Lindgren Signed-off-by: Lokesh Vutla Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20200305082715.15861-3-lokeshvutla@ti.com --- drivers/clocksource/timer-ti-dm.c | 36 +++++++++++++++++++++++++++++++----- include/clocksource/timer-ti-dm.h | 1 + 2 files changed, 32 insertions(+), 5 deletions(-) (limited to 'drivers/clocksource/timer-ti-dm.c') diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c index c0e9e9978cdd..fe939d1c0b38 100644 --- a/drivers/clocksource/timer-ti-dm.c +++ b/drivers/clocksource/timer-ti-dm.c @@ -491,7 +491,7 @@ __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask) int omap_dm_timer_trigger(struct omap_dm_timer *timer) { - if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) { + if (unlikely(!timer || !atomic_read(&timer->enabled))) { pr_err("%s: timer not available or enabled.\n", __func__); return -EINVAL; } @@ -690,7 +690,7 @@ static unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer) { unsigned int l; - if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) { + if (unlikely(!timer || !atomic_read(&timer->enabled))) { pr_err("%s: timer not available or enabled.\n", __func__); return 0; } @@ -702,7 +702,7 @@ static unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer) static int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value) { - if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) + if (unlikely(!timer || !atomic_read(&timer->enabled))) return -EINVAL; __omap_dm_timer_write_status(timer, value); @@ -712,7 +712,7 @@ static int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int static unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer) { - if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) { + if (unlikely(!timer || !atomic_read(&timer->enabled))) { pr_err("%s: timer not iavailable or enabled.\n", __func__); return 0; } @@ -722,7 +722,7 @@ static unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer) static int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value) { - if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) { + if (unlikely(!timer || !atomic_read(&timer->enabled))) { pr_err("%s: timer not available or enabled.\n", __func__); return -EINVAL; } @@ -750,6 +750,29 @@ int omap_dm_timers_active(void) return 0; } +static int __maybe_unused omap_dm_timer_runtime_suspend(struct device *dev) +{ + struct omap_dm_timer *timer = dev_get_drvdata(dev); + + atomic_set(&timer->enabled, 0); + + return 0; +} + +static int __maybe_unused omap_dm_timer_runtime_resume(struct device *dev) +{ + struct omap_dm_timer *timer = dev_get_drvdata(dev); + + atomic_set(&timer->enabled, 1); + + return 0; +} + +static const struct dev_pm_ops omap_dm_timer_pm_ops = { + SET_RUNTIME_PM_OPS(omap_dm_timer_runtime_suspend, + omap_dm_timer_runtime_resume, NULL) +}; + static const struct of_device_id omap_timer_match[]; /** @@ -791,6 +814,8 @@ static int omap_dm_timer_probe(struct platform_device *pdev) if (IS_ERR(timer->io_base)) return PTR_ERR(timer->io_base); + platform_set_drvdata(pdev, timer); + if (dev->of_node) { if (of_find_property(dev->of_node, "ti,timer-alwon", NULL)) timer->capability |= OMAP_TIMER_ALWON; @@ -936,6 +961,7 @@ static struct platform_driver omap_dm_timer_driver = { .driver = { .name = "omap_timer", .of_match_table = of_match_ptr(omap_timer_match), + .pm = &omap_dm_timer_pm_ops, }, }; diff --git a/include/clocksource/timer-ti-dm.h b/include/clocksource/timer-ti-dm.h index 7d9598dc578d..eef5de300731 100644 --- a/include/clocksource/timer-ti-dm.h +++ b/include/clocksource/timer-ti-dm.h @@ -105,6 +105,7 @@ struct omap_dm_timer { void __iomem *pend; /* write pending */ void __iomem *func_base; /* function register base */ + atomic_t enabled; unsigned long rate; unsigned reserved:1; unsigned posted:1; -- cgit v1.2.3 From b34677b0999a7c0de45e57b780508c14cb438ed8 Mon Sep 17 00:00:00 2001 From: Lokesh Vutla Date: Mon, 16 Mar 2020 16:44:53 +0530 Subject: clocksource/drivers/timer-ti-dm: Implement cpu_pm notifier for context save and restore omap_dm_timer_enable() restores the entire context(including counter) based on 2 conditions: - If get_context_loss_count is populated and context is lost. - If get_context_loss_count is not populated update unconditionally. Case2 has a side effect of updating the counter register even though context is not lost. When timer is configured in pwm mode, this is causing undesired behaviour in the pwm period. Instead of using get_context_loss_count call back, implement cpu_pm notifier with context save and restore support. And delete the get_context_loss_count callback all together. Suggested-by: Tony Lindgren Signed-off-by: Lokesh Vutla [tony@atomide.com: removed pm_runtime calls from cpuidle calls] Signed-off-by: Tony Lindgren Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20200316111453.15441-1-lokeshvutla@ti.com --- drivers/clocksource/timer-ti-dm.c | 97 +++++++++++++++++++++++---------------- include/clocksource/timer-ti-dm.h | 3 +- 2 files changed, 58 insertions(+), 42 deletions(-) (limited to 'drivers/clocksource/timer-ti-dm.c') diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c index fe939d1c0b38..1d1bea79cbf1 100644 --- a/drivers/clocksource/timer-ti-dm.c +++ b/drivers/clocksource/timer-ti-dm.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -92,6 +93,47 @@ static void omap_timer_restore_context(struct omap_dm_timer *timer) timer->context.tclr); } +static void omap_timer_save_context(struct omap_dm_timer *timer) +{ + timer->context.tclr = + omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); + timer->context.twer = + omap_dm_timer_read_reg(timer, OMAP_TIMER_WAKEUP_EN_REG); + timer->context.tldr = + omap_dm_timer_read_reg(timer, OMAP_TIMER_LOAD_REG); + timer->context.tmar = + omap_dm_timer_read_reg(timer, OMAP_TIMER_MATCH_REG); + timer->context.tier = readl_relaxed(timer->irq_ena); + timer->context.tsicr = + omap_dm_timer_read_reg(timer, OMAP_TIMER_IF_CTRL_REG); +} + +static int omap_timer_context_notifier(struct notifier_block *nb, + unsigned long cmd, void *v) +{ + struct omap_dm_timer *timer; + + timer = container_of(nb, struct omap_dm_timer, nb); + + switch (cmd) { + case CPU_CLUSTER_PM_ENTER: + if ((timer->capability & OMAP_TIMER_ALWON) || + !atomic_read(&timer->enabled)) + break; + omap_timer_save_context(timer); + break; + case CPU_CLUSTER_PM_ENTER_FAILED: + case CPU_CLUSTER_PM_EXIT: + if ((timer->capability & OMAP_TIMER_ALWON) || + !atomic_read(&timer->enabled)) + break; + omap_timer_restore_context(timer); + break; + } + + return NOTIFY_OK; +} + static int omap_dm_timer_reset(struct omap_dm_timer *timer) { u32 l, timeout = 100000; @@ -208,21 +250,7 @@ static int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) static void omap_dm_timer_enable(struct omap_dm_timer *timer) { - int c; - pm_runtime_get_sync(&timer->pdev->dev); - - if (!(timer->capability & OMAP_TIMER_ALWON)) { - if (timer->get_context_loss_count) { - c = timer->get_context_loss_count(&timer->pdev->dev); - if (c != timer->ctx_loss_count) { - omap_timer_restore_context(timer); - timer->ctx_loss_count = c; - } - } else { - omap_timer_restore_context(timer); - } - } } static void omap_dm_timer_disable(struct omap_dm_timer *timer) @@ -515,8 +543,6 @@ static int omap_dm_timer_start(struct omap_dm_timer *timer) omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); } - /* Save the context */ - timer->context.tclr = l; return 0; } @@ -532,13 +558,6 @@ static int omap_dm_timer_stop(struct omap_dm_timer *timer) __omap_dm_timer_stop(timer, timer->posted, rate); - /* - * Since the register values are computed and written within - * __omap_dm_timer_stop, we need to use read to retrieve the - * context. - */ - timer->context.tclr = - omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); omap_dm_timer_disable(timer); return 0; } @@ -561,9 +580,6 @@ static int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load); omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0); - /* Save the context */ - timer->context.tclr = l; - timer->context.tldr = load; omap_dm_timer_disable(timer); return 0; } @@ -585,9 +601,6 @@ static int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable, omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match); omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); - /* Save the context */ - timer->context.tclr = l; - timer->context.tmar = match; omap_dm_timer_disable(timer); return 0; } @@ -611,8 +624,6 @@ static int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, l |= trigger << 10; omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); - /* Save the context */ - timer->context.tclr = l; omap_dm_timer_disable(timer); return 0; } @@ -634,8 +645,6 @@ static int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, } omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); - /* Save the context */ - timer->context.tclr = l; omap_dm_timer_disable(timer); return 0; } @@ -649,9 +658,6 @@ static int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, omap_dm_timer_enable(timer); __omap_dm_timer_int_enable(timer, value); - /* Save the context */ - timer->context.tier = value; - timer->context.twer = value; omap_dm_timer_disable(timer); return 0; } @@ -679,9 +685,6 @@ static int omap_dm_timer_set_int_disable(struct omap_dm_timer *timer, u32 mask) l = omap_dm_timer_read_reg(timer, OMAP_TIMER_WAKEUP_EN_REG) & ~mask; omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, l); - /* Save the context */ - timer->context.tier &= ~mask; - timer->context.twer &= ~mask; omap_dm_timer_disable(timer); return 0; } @@ -756,6 +759,11 @@ static int __maybe_unused omap_dm_timer_runtime_suspend(struct device *dev) atomic_set(&timer->enabled, 0); + if (timer->capability & OMAP_TIMER_ALWON || !timer->func_base) + return 0; + + omap_timer_save_context(timer); + return 0; } @@ -763,6 +771,9 @@ static int __maybe_unused omap_dm_timer_runtime_resume(struct device *dev) { struct omap_dm_timer *timer = dev_get_drvdata(dev); + if (!(timer->capability & OMAP_TIMER_ALWON) && timer->func_base) + omap_timer_restore_context(timer); + atomic_set(&timer->enabled, 1); return 0; @@ -829,7 +840,11 @@ static int omap_dm_timer_probe(struct platform_device *pdev) timer->id = pdev->id; timer->capability = pdata->timer_capability; timer->reserved = omap_dm_timer_reserved_systimer(timer->id); - timer->get_context_loss_count = pdata->get_context_loss_count; + } + + if (!(timer->capability & OMAP_TIMER_ALWON)) { + timer->nb.notifier_call = omap_timer_context_notifier; + cpu_pm_register_notifier(&timer->nb); } if (pdata) @@ -883,6 +898,8 @@ static int omap_dm_timer_remove(struct platform_device *pdev) list_for_each_entry(timer, &omap_timer_list, node) if (!strcmp(dev_name(&timer->pdev->dev), dev_name(&pdev->dev))) { + if (!(timer->capability & OMAP_TIMER_ALWON)) + cpu_pm_unregister_notifier(&timer->nb); list_del(&timer->node); ret = 0; break; diff --git a/include/clocksource/timer-ti-dm.h b/include/clocksource/timer-ti-dm.h index eef5de300731..25f05235866e 100644 --- a/include/clocksource/timer-ti-dm.h +++ b/include/clocksource/timer-ti-dm.h @@ -110,13 +110,12 @@ struct omap_dm_timer { unsigned reserved:1; unsigned posted:1; struct timer_regs context; - int (*get_context_loss_count)(struct device *); - int ctx_loss_count; int revision; u32 capability; u32 errata; struct platform_device *pdev; struct list_head node; + struct notifier_block nb; }; int omap_dm_timer_reserve_systimer(int id); -- cgit v1.2.3 From aff7665dc64b60c1f93d6e52fde297ae6b8999ae Mon Sep 17 00:00:00 2001 From: Lokesh Vutla Date: Thu, 5 Mar 2020 13:57:13 +0530 Subject: clocksource/drivers/timer-ti-dm: Do not update counter on updating the period Write to trigger register(OMAP_TIMER_TRIGGER_REG) will load the value in Load register(OMAP_TIMER_LOAD_REG) into Counter register (OMAP_TIMER_COUNTER_REG). omap_dm_timer_set_load() writes into trigger register every time load register is updated. When timer is configured in pwm mode, this causes disruption in current pwm cycle, which is not expected especially when pwm is used as PPS signal for synchronized PTP clocks. So do not write into trigger register on updating the period. Tested-by: Tony Lindgren Signed-off-by: Lokesh Vutla Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20200305082715.15861-5-lokeshvutla@ti.com --- drivers/clocksource/timer-ti-dm.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/clocksource/timer-ti-dm.c') diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c index 1d1bea79cbf1..b565b8456e5c 100644 --- a/drivers/clocksource/timer-ti-dm.c +++ b/drivers/clocksource/timer-ti-dm.c @@ -579,7 +579,6 @@ static int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load); - omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0); omap_dm_timer_disable(timer); return 0; } -- cgit v1.2.3 From 92fd86864ec4ac089de47f0f1f4c47418b343448 Mon Sep 17 00:00:00 2001 From: Lokesh Vutla Date: Thu, 5 Mar 2020 13:57:14 +0530 Subject: clocksource/drivers/timer-ti-dm: Add support to get pwm current status omap_dm_timer_ops provide support to configure the pwm but there is no support to get the current status. For configuring pwm it is advised to check the current hw status instead of relying on pwm framework. So implement a new timer ops to get the current status of pwm. Signed-off-by: Lokesh Vutla Acked-by: Tony Lindgen Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20200305082715.15861-6-lokeshvutla@ti.com --- drivers/clocksource/timer-ti-dm.c | 15 +++++++++++++++ include/linux/platform_data/dmtimer-omap.h | 1 + 2 files changed, 16 insertions(+) (limited to 'drivers/clocksource/timer-ti-dm.c') diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c index b565b8456e5c..73ac73efdef8 100644 --- a/drivers/clocksource/timer-ti-dm.c +++ b/drivers/clocksource/timer-ti-dm.c @@ -627,6 +627,20 @@ static int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, return 0; } +static int omap_dm_timer_get_pwm_status(struct omap_dm_timer *timer) +{ + u32 l; + + if (unlikely(!timer)) + return -EINVAL; + + omap_dm_timer_enable(timer); + l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); + omap_dm_timer_disable(timer); + + return l; +} + static int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler) { @@ -927,6 +941,7 @@ static const struct omap_dm_timer_ops dmtimer_ops = { .set_load = omap_dm_timer_set_load, .set_match = omap_dm_timer_set_match, .set_pwm = omap_dm_timer_set_pwm, + .get_pwm_status = omap_dm_timer_get_pwm_status, .set_prescaler = omap_dm_timer_set_prescaler, .read_counter = omap_dm_timer_read_counter, .write_counter = omap_dm_timer_write_counter, diff --git a/include/linux/platform_data/dmtimer-omap.h b/include/linux/platform_data/dmtimer-omap.h index bdaaf537604a..3173b7b6ff6f 100644 --- a/include/linux/platform_data/dmtimer-omap.h +++ b/include/linux/platform_data/dmtimer-omap.h @@ -36,6 +36,7 @@ struct omap_dm_timer_ops { unsigned int match); int (*set_pwm)(struct omap_dm_timer *timer, int def_on, int toggle, int trigger); + int (*get_pwm_status)(struct omap_dm_timer *timer); int (*set_prescaler)(struct omap_dm_timer *timer, int prescaler); unsigned int (*read_counter)(struct omap_dm_timer *timer); -- cgit v1.2.3 From 02e6d546e3bdc1a8a764343cd1ba354da07e8623 Mon Sep 17 00:00:00 2001 From: Lokesh Vutla Date: Thu, 5 Mar 2020 13:57:15 +0530 Subject: clocksource/drivers/timer-ti-dm: Enable autoreload in set_pwm dm timer ops set_load() api allows to configure the load value and to set the auto reload feature. But auto reload feature is independent of load value and should be part of configuring pwm. This way pwm can be disabled by disabling auto reload feature using set_pwm() so that the current pwm cycle will be completed. Else pwm disabling causes the cycle to be stopped abruptly. Signed-off-by: Lokesh Vutla Acked-by: Tony Lindgren Signed-off-by: Daniel Lezcano Link: https://lore.kernel.org/r/20200305082715.15861-7-lokeshvutla@ti.com --- drivers/clocksource/timer-ti-dm.c | 16 +++++----------- drivers/pwm/pwm-omap-dmtimer.c | 8 +++++--- include/linux/platform_data/dmtimer-omap.h | 5 ++--- 3 files changed, 12 insertions(+), 17 deletions(-) (limited to 'drivers/clocksource/timer-ti-dm.c') diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c index 73ac73efdef8..f5c73ebfe4ca 100644 --- a/drivers/clocksource/timer-ti-dm.c +++ b/drivers/clocksource/timer-ti-dm.c @@ -562,21 +562,13 @@ static int omap_dm_timer_stop(struct omap_dm_timer *timer) return 0; } -static int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, +static int omap_dm_timer_set_load(struct omap_dm_timer *timer, unsigned int load) { - u32 l; - if (unlikely(!timer)) return -EINVAL; omap_dm_timer_enable(timer); - l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); - if (autoreload) - l |= OMAP_TIMER_CTRL_AR; - else - l &= ~OMAP_TIMER_CTRL_AR; - omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load); omap_dm_timer_disable(timer); @@ -605,7 +597,7 @@ static int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable, } static int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, - int toggle, int trigger) + int toggle, int trigger, int autoreload) { u32 l; @@ -615,12 +607,14 @@ static int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, omap_dm_timer_enable(timer); l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM | - OMAP_TIMER_CTRL_PT | (0x03 << 10)); + OMAP_TIMER_CTRL_PT | (0x03 << 10) | OMAP_TIMER_CTRL_AR); if (def_on) l |= OMAP_TIMER_CTRL_SCPWM; if (toggle) l |= OMAP_TIMER_CTRL_PT; l |= trigger << 10; + if (autoreload) + l |= OMAP_TIMER_CTRL_AR; omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); omap_dm_timer_disable(timer); diff --git a/drivers/pwm/pwm-omap-dmtimer.c b/drivers/pwm/pwm-omap-dmtimer.c index 88a3c5690fea..9e4378dc6897 100644 --- a/drivers/pwm/pwm-omap-dmtimer.c +++ b/drivers/pwm/pwm-omap-dmtimer.c @@ -183,7 +183,7 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip, if (timer_active) omap->pdata->stop(omap->dm_timer); - omap->pdata->set_load(omap->dm_timer, true, load_value); + omap->pdata->set_load(omap->dm_timer, load_value); omap->pdata->set_match(omap->dm_timer, true, match_value); dev_dbg(chip->dev, "load value: %#08x (%d), match value: %#08x (%d)\n", @@ -192,7 +192,8 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip, omap->pdata->set_pwm(omap->dm_timer, pwm_get_polarity(pwm) == PWM_POLARITY_INVERSED, true, - PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE); + PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE, + true); /* If config was called while timer was running it must be reenabled. */ if (timer_active) @@ -222,7 +223,8 @@ static int pwm_omap_dmtimer_set_polarity(struct pwm_chip *chip, omap->pdata->set_pwm(omap->dm_timer, polarity == PWM_POLARITY_INVERSED, true, - PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE); + PWM_OMAP_DMTIMER_TRIGGER_OVERFLOW_AND_COMPARE, + true); mutex_unlock(&omap->mutex); return 0; diff --git a/include/linux/platform_data/dmtimer-omap.h b/include/linux/platform_data/dmtimer-omap.h index 3173b7b6ff6f..95d852aef130 100644 --- a/include/linux/platform_data/dmtimer-omap.h +++ b/include/linux/platform_data/dmtimer-omap.h @@ -30,12 +30,11 @@ struct omap_dm_timer_ops { int (*stop)(struct omap_dm_timer *timer); int (*set_source)(struct omap_dm_timer *timer, int source); - int (*set_load)(struct omap_dm_timer *timer, int autoreload, - unsigned int value); + int (*set_load)(struct omap_dm_timer *timer, unsigned int value); int (*set_match)(struct omap_dm_timer *timer, int enable, unsigned int match); int (*set_pwm)(struct omap_dm_timer *timer, int def_on, - int toggle, int trigger); + int toggle, int trigger, int autoreload); int (*get_pwm_status)(struct omap_dm_timer *timer); int (*set_prescaler)(struct omap_dm_timer *timer, int prescaler); -- cgit v1.2.3