1+ // SPDX-License-Identifier: GPL-2.0+
12/*
23 * linux/arch/arm/plat-omap/dmtimer.c
34 *
1516 *
1617 * Copyright (C) 2009 Texas Instruments
1718 * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
18- *
19- * This program is free software; you can redistribute it and/or modify it
20- * under the terms of the GNU General Public License as published by the
21- * Free Software Foundation; either version 2 of the License, or (at your
22- * option) any later version.
23- *
24- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
25- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
27- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32- *
33- * You should have received a copy of the GNU General Public License along
34- * with this program; if not, write to the Free Software Foundation, Inc.,
35- * 675 Mass Ave, Cambridge, MA 02139, USA.
3619 */
3720
3821#include <linux/clk.h>
3922#include <linux/clk-provider.h>
23+ #include <linux/cpu_pm.h>
4024#include <linux/module.h>
4125#include <linux/io.h>
4226#include <linux/device.h>
@@ -109,6 +93,47 @@ static void omap_timer_restore_context(struct omap_dm_timer *timer)
10993 timer -> context .tclr );
11094}
11195
96+ static void omap_timer_save_context (struct omap_dm_timer * timer )
97+ {
98+ timer -> context .tclr =
99+ omap_dm_timer_read_reg (timer , OMAP_TIMER_CTRL_REG );
100+ timer -> context .twer =
101+ omap_dm_timer_read_reg (timer , OMAP_TIMER_WAKEUP_EN_REG );
102+ timer -> context .tldr =
103+ omap_dm_timer_read_reg (timer , OMAP_TIMER_LOAD_REG );
104+ timer -> context .tmar =
105+ omap_dm_timer_read_reg (timer , OMAP_TIMER_MATCH_REG );
106+ timer -> context .tier = readl_relaxed (timer -> irq_ena );
107+ timer -> context .tsicr =
108+ omap_dm_timer_read_reg (timer , OMAP_TIMER_IF_CTRL_REG );
109+ }
110+
111+ static int omap_timer_context_notifier (struct notifier_block * nb ,
112+ unsigned long cmd , void * v )
113+ {
114+ struct omap_dm_timer * timer ;
115+
116+ timer = container_of (nb , struct omap_dm_timer , nb );
117+
118+ switch (cmd ) {
119+ case CPU_CLUSTER_PM_ENTER :
120+ if ((timer -> capability & OMAP_TIMER_ALWON ) ||
121+ !atomic_read (& timer -> enabled ))
122+ break ;
123+ omap_timer_save_context (timer );
124+ break ;
125+ case CPU_CLUSTER_PM_ENTER_FAILED :
126+ case CPU_CLUSTER_PM_EXIT :
127+ if ((timer -> capability & OMAP_TIMER_ALWON ) ||
128+ !atomic_read (& timer -> enabled ))
129+ break ;
130+ omap_timer_restore_context (timer );
131+ break ;
132+ }
133+
134+ return NOTIFY_OK ;
135+ }
136+
112137static int omap_dm_timer_reset (struct omap_dm_timer * timer )
113138{
114139 u32 l , timeout = 100000 ;
@@ -196,21 +221,7 @@ static int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
196221
197222static void omap_dm_timer_enable (struct omap_dm_timer * timer )
198223{
199- int c ;
200-
201224 pm_runtime_get_sync (& timer -> pdev -> dev );
202-
203- if (!(timer -> capability & OMAP_TIMER_ALWON )) {
204- if (timer -> get_context_loss_count ) {
205- c = timer -> get_context_loss_count (& timer -> pdev -> dev );
206- if (c != timer -> ctx_loss_count ) {
207- omap_timer_restore_context (timer );
208- timer -> ctx_loss_count = c ;
209- }
210- } else {
211- omap_timer_restore_context (timer );
212- }
213- }
214225}
215226
216227static void omap_dm_timer_disable (struct omap_dm_timer * timer )
@@ -477,7 +488,7 @@ __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
477488
478489int omap_dm_timer_trigger (struct omap_dm_timer * timer )
479490{
480- if (unlikely (!timer || pm_runtime_suspended (& timer -> pdev -> dev ))) {
491+ if (unlikely (!timer || ! atomic_read (& timer -> enabled ))) {
481492 pr_err ("%s: timer not available or enabled.\n" , __func__ );
482493 return - EINVAL ;
483494 }
@@ -501,8 +512,6 @@ static int omap_dm_timer_start(struct omap_dm_timer *timer)
501512 omap_dm_timer_write_reg (timer , OMAP_TIMER_CTRL_REG , l );
502513 }
503514
504- /* Save the context */
505- timer -> context .tclr = l ;
506515 return 0 ;
507516}
508517
@@ -518,37 +527,19 @@ static int omap_dm_timer_stop(struct omap_dm_timer *timer)
518527
519528 __omap_dm_timer_stop (timer , timer -> posted , rate );
520529
521- /*
522- * Since the register values are computed and written within
523- * __omap_dm_timer_stop, we need to use read to retrieve the
524- * context.
525- */
526- timer -> context .tclr =
527- omap_dm_timer_read_reg (timer , OMAP_TIMER_CTRL_REG );
528530 omap_dm_timer_disable (timer );
529531 return 0 ;
530532}
531533
532- static int omap_dm_timer_set_load (struct omap_dm_timer * timer , int autoreload ,
534+ static int omap_dm_timer_set_load (struct omap_dm_timer * timer ,
533535 unsigned int load )
534536{
535- u32 l ;
536-
537537 if (unlikely (!timer ))
538538 return - EINVAL ;
539539
540540 omap_dm_timer_enable (timer );
541- l = omap_dm_timer_read_reg (timer , OMAP_TIMER_CTRL_REG );
542- if (autoreload )
543- l |= OMAP_TIMER_CTRL_AR ;
544- else
545- l &= ~OMAP_TIMER_CTRL_AR ;
546- omap_dm_timer_write_reg (timer , OMAP_TIMER_CTRL_REG , l );
547541 omap_dm_timer_write_reg (timer , OMAP_TIMER_LOAD_REG , load );
548542
549- /* Save the context */
550- timer -> context .tclr = l ;
551- timer -> context .tldr = load ;
552543 omap_dm_timer_disable (timer );
553544 return 0 ;
554545}
@@ -570,15 +561,12 @@ static int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
570561 omap_dm_timer_write_reg (timer , OMAP_TIMER_MATCH_REG , match );
571562 omap_dm_timer_write_reg (timer , OMAP_TIMER_CTRL_REG , l );
572563
573- /* Save the context */
574- timer -> context .tclr = l ;
575- timer -> context .tmar = match ;
576564 omap_dm_timer_disable (timer );
577565 return 0 ;
578566}
579567
580568static int omap_dm_timer_set_pwm (struct omap_dm_timer * timer , int def_on ,
581- int toggle , int trigger )
569+ int toggle , int trigger , int autoreload )
582570{
583571 u32 l ;
584572
@@ -588,20 +576,34 @@ static int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
588576 omap_dm_timer_enable (timer );
589577 l = omap_dm_timer_read_reg (timer , OMAP_TIMER_CTRL_REG );
590578 l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM |
591- OMAP_TIMER_CTRL_PT | (0x03 << 10 ));
579+ OMAP_TIMER_CTRL_PT | (0x03 << 10 ) | OMAP_TIMER_CTRL_AR );
592580 if (def_on )
593581 l |= OMAP_TIMER_CTRL_SCPWM ;
594582 if (toggle )
595583 l |= OMAP_TIMER_CTRL_PT ;
596584 l |= trigger << 10 ;
585+ if (autoreload )
586+ l |= OMAP_TIMER_CTRL_AR ;
597587 omap_dm_timer_write_reg (timer , OMAP_TIMER_CTRL_REG , l );
598588
599- /* Save the context */
600- timer -> context .tclr = l ;
601589 omap_dm_timer_disable (timer );
602590 return 0 ;
603591}
604592
593+ static int omap_dm_timer_get_pwm_status (struct omap_dm_timer * timer )
594+ {
595+ u32 l ;
596+
597+ if (unlikely (!timer ))
598+ return - EINVAL ;
599+
600+ omap_dm_timer_enable (timer );
601+ l = omap_dm_timer_read_reg (timer , OMAP_TIMER_CTRL_REG );
602+ omap_dm_timer_disable (timer );
603+
604+ return l ;
605+ }
606+
605607static int omap_dm_timer_set_prescaler (struct omap_dm_timer * timer ,
606608 int prescaler )
607609{
@@ -619,8 +621,6 @@ static int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer,
619621 }
620622 omap_dm_timer_write_reg (timer , OMAP_TIMER_CTRL_REG , l );
621623
622- /* Save the context */
623- timer -> context .tclr = l ;
624624 omap_dm_timer_disable (timer );
625625 return 0 ;
626626}
@@ -634,9 +634,6 @@ static int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
634634 omap_dm_timer_enable (timer );
635635 __omap_dm_timer_int_enable (timer , value );
636636
637- /* Save the context */
638- timer -> context .tier = value ;
639- timer -> context .twer = value ;
640637 omap_dm_timer_disable (timer );
641638 return 0 ;
642639}
@@ -664,9 +661,6 @@ static int omap_dm_timer_set_int_disable(struct omap_dm_timer *timer, u32 mask)
664661 l = omap_dm_timer_read_reg (timer , OMAP_TIMER_WAKEUP_EN_REG ) & ~mask ;
665662 omap_dm_timer_write_reg (timer , OMAP_TIMER_WAKEUP_EN_REG , l );
666663
667- /* Save the context */
668- timer -> context .tier &= ~mask ;
669- timer -> context .twer &= ~mask ;
670664 omap_dm_timer_disable (timer );
671665 return 0 ;
672666}
@@ -675,7 +669,7 @@ static unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
675669{
676670 unsigned int l ;
677671
678- if (unlikely (!timer || pm_runtime_suspended (& timer -> pdev -> dev ))) {
672+ if (unlikely (!timer || ! atomic_read (& timer -> enabled ))) {
679673 pr_err ("%s: timer not available or enabled.\n" , __func__ );
680674 return 0 ;
681675 }
@@ -687,7 +681,7 @@ static unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
687681
688682static int omap_dm_timer_write_status (struct omap_dm_timer * timer , unsigned int value )
689683{
690- if (unlikely (!timer || pm_runtime_suspended (& timer -> pdev -> dev )))
684+ if (unlikely (!timer || ! atomic_read (& timer -> enabled )))
691685 return - EINVAL ;
692686
693687 __omap_dm_timer_write_status (timer , value );
@@ -697,7 +691,7 @@ static int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int
697691
698692static unsigned int omap_dm_timer_read_counter (struct omap_dm_timer * timer )
699693{
700- if (unlikely (!timer || pm_runtime_suspended (& timer -> pdev -> dev ))) {
694+ if (unlikely (!timer || ! atomic_read (& timer -> enabled ))) {
701695 pr_err ("%s: timer not iavailable or enabled.\n" , __func__ );
702696 return 0 ;
703697 }
@@ -707,7 +701,7 @@ static unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
707701
708702static int omap_dm_timer_write_counter (struct omap_dm_timer * timer , unsigned int value )
709703{
710- if (unlikely (!timer || pm_runtime_suspended (& timer -> pdev -> dev ))) {
704+ if (unlikely (!timer || ! atomic_read (& timer -> enabled ))) {
711705 pr_err ("%s: timer not available or enabled.\n" , __func__ );
712706 return - EINVAL ;
713707 }
@@ -735,6 +729,37 @@ int omap_dm_timers_active(void)
735729 return 0 ;
736730}
737731
732+ static int __maybe_unused omap_dm_timer_runtime_suspend (struct device * dev )
733+ {
734+ struct omap_dm_timer * timer = dev_get_drvdata (dev );
735+
736+ atomic_set (& timer -> enabled , 0 );
737+
738+ if (timer -> capability & OMAP_TIMER_ALWON || !timer -> func_base )
739+ return 0 ;
740+
741+ omap_timer_save_context (timer );
742+
743+ return 0 ;
744+ }
745+
746+ static int __maybe_unused omap_dm_timer_runtime_resume (struct device * dev )
747+ {
748+ struct omap_dm_timer * timer = dev_get_drvdata (dev );
749+
750+ if (!(timer -> capability & OMAP_TIMER_ALWON ) && timer -> func_base )
751+ omap_timer_restore_context (timer );
752+
753+ atomic_set (& timer -> enabled , 1 );
754+
755+ return 0 ;
756+ }
757+
758+ static const struct dev_pm_ops omap_dm_timer_pm_ops = {
759+ SET_RUNTIME_PM_OPS (omap_dm_timer_runtime_suspend ,
760+ omap_dm_timer_runtime_resume , NULL )
761+ };
762+
738763static const struct of_device_id omap_timer_match [];
739764
740765/**
@@ -776,6 +801,8 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
776801 if (IS_ERR (timer -> io_base ))
777802 return PTR_ERR (timer -> io_base );
778803
804+ platform_set_drvdata (pdev , timer );
805+
779806 if (dev -> of_node ) {
780807 if (of_find_property (dev -> of_node , "ti,timer-alwon" , NULL ))
781808 timer -> capability |= OMAP_TIMER_ALWON ;
@@ -789,7 +816,11 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
789816 timer -> id = pdev -> id ;
790817 timer -> capability = pdata -> timer_capability ;
791818 timer -> reserved = omap_dm_timer_reserved_systimer (timer -> id );
792- timer -> get_context_loss_count = pdata -> get_context_loss_count ;
819+ }
820+
821+ if (!(timer -> capability & OMAP_TIMER_ALWON )) {
822+ timer -> nb .notifier_call = omap_timer_context_notifier ;
823+ cpu_pm_register_notifier (& timer -> nb );
793824 }
794825
795826 if (pdata )
@@ -843,6 +874,8 @@ static int omap_dm_timer_remove(struct platform_device *pdev)
843874 list_for_each_entry (timer , & omap_timer_list , node )
844875 if (!strcmp (dev_name (& timer -> pdev -> dev ),
845876 dev_name (& pdev -> dev ))) {
877+ if (!(timer -> capability & OMAP_TIMER_ALWON ))
878+ cpu_pm_unregister_notifier (& timer -> nb );
846879 list_del (& timer -> node );
847880 ret = 0 ;
848881 break ;
@@ -871,6 +904,7 @@ static const struct omap_dm_timer_ops dmtimer_ops = {
871904 .set_load = omap_dm_timer_set_load ,
872905 .set_match = omap_dm_timer_set_match ,
873906 .set_pwm = omap_dm_timer_set_pwm ,
907+ .get_pwm_status = omap_dm_timer_get_pwm_status ,
874908 .set_prescaler = omap_dm_timer_set_prescaler ,
875909 .read_counter = omap_dm_timer_read_counter ,
876910 .write_counter = omap_dm_timer_write_counter ,
@@ -921,6 +955,7 @@ static struct platform_driver omap_dm_timer_driver = {
921955 .driver = {
922956 .name = "omap_timer" ,
923957 .of_match_table = of_match_ptr (omap_timer_match ),
958+ .pm = & omap_dm_timer_pm_ops ,
924959 },
925960};
926961
0 commit comments