Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clocksource/drivers/timer-ti-dm : Capture functionality for OMAP DM timer

Add PWM capture function in DM timer driver.

OMAP DM timer hardware supports capture feature.It can be used to
timestamp events (falling/rising edges) detected on input signal.

Signed-off-by: Gokul Praveen <g-praveen@ti.com>
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Reviewed-by: Neha Malcom Francis <n-francis@ti.com>
Link: https://lore.kernel.org/r/20250812105346.203541-1-g-praveen@ti.com

authored by

Gokul Praveen and committed by
Daniel Lezcano
0494fc34 4e9bfe69

+121 -2
+117 -2
drivers/clocksource/timer-ti-dm.c
··· 31 31 #include <linux/platform_data/dmtimer-omap.h> 32 32 33 33 #include <clocksource/timer-ti-dm.h> 34 + #include <linux/delay.h> 34 35 35 36 /* 36 37 * timer errata flags ··· 837 836 return 0; 838 837 } 839 838 839 + static int omap_dm_timer_set_cap(struct omap_dm_timer *cookie, 840 + int autoreload, bool config_period) 841 + { 842 + struct dmtimer *timer; 843 + struct device *dev; 844 + int rc; 845 + u32 l; 846 + 847 + timer = to_dmtimer(cookie); 848 + if (unlikely(!timer)) 849 + return -EINVAL; 850 + 851 + dev = &timer->pdev->dev; 852 + rc = pm_runtime_resume_and_get(dev); 853 + if (rc) 854 + return rc; 855 + /* 856 + * 1. Select autoreload mode. TIMER_TCLR[1] AR bit. 857 + * 2. TIMER_TCLR[14]: Sets the functionality of the TIMER IO pin. 858 + * 3. TIMER_TCLR[13] : Capture mode select bit. 859 + * 3. TIMER_TCLR[9-8] : Select transition capture mode. 860 + */ 861 + 862 + l = dmtimer_read(timer, OMAP_TIMER_CTRL_REG); 863 + 864 + if (autoreload) 865 + l |= OMAP_TIMER_CTRL_AR; 866 + 867 + l |= OMAP_TIMER_CTRL_CAPTMODE | OMAP_TIMER_CTRL_GPOCFG; 868 + 869 + if (config_period == true) 870 + l |= OMAP_TIMER_CTRL_TCM_LOWTOHIGH; /* Time Period config */ 871 + else 872 + l |= OMAP_TIMER_CTRL_TCM_BOTHEDGES; /* Duty Cycle config */ 873 + 874 + dmtimer_write(timer, OMAP_TIMER_CTRL_REG, l); 875 + 876 + pm_runtime_put_sync(dev); 877 + 878 + return 0; 879 + } 880 + 840 881 static int omap_dm_timer_set_pwm(struct omap_dm_timer *cookie, int def_on, 841 882 int toggle, int trigger, int autoreload) 842 883 { ··· 1066 1023 return __omap_dm_timer_read_counter(timer); 1067 1024 } 1068 1025 1026 + static inline unsigned int __omap_dm_timer_cap(struct dmtimer *timer, int idx) 1027 + { 1028 + return idx == 0 ? dmtimer_read(timer, OMAP_TIMER_CAPTURE_REG) : 1029 + dmtimer_read(timer, OMAP_TIMER_CAPTURE2_REG); 1030 + } 1031 + 1069 1032 static int omap_dm_timer_write_counter(struct omap_dm_timer *cookie, unsigned int value) 1070 1033 { 1071 1034 struct dmtimer *timer; 1035 + struct device *dev; 1072 1036 1073 1037 timer = to_dmtimer(cookie); 1074 - if (unlikely(!timer || !atomic_read(&timer->enabled))) { 1075 - pr_err("%s: timer not available or enabled.\n", __func__); 1038 + if (unlikely(!timer)) { 1039 + pr_err("%s: timer not available.\n", __func__); 1076 1040 return -EINVAL; 1077 1041 } 1078 1042 1043 + dev = &timer->pdev->dev; 1044 + 1045 + pm_runtime_resume_and_get(dev); 1079 1046 dmtimer_write(timer, OMAP_TIMER_COUNTER_REG, value); 1047 + pm_runtime_put_sync(dev); 1080 1048 1081 1049 /* Save the context */ 1082 1050 timer->context.tcrr = value; 1083 1051 return 0; 1052 + } 1053 + 1054 + /** 1055 + * omap_dm_timer_cap_counter() - Calculate the high count or period count depending on the 1056 + * configuration. 1057 + * @cookie:Pointer to OMAP DM timer 1058 + * @is_period:Whether to configure timer in period or duty cycle mode 1059 + * 1060 + * Return high count or period count if timer is enabled else appropriate error. 1061 + */ 1062 + static unsigned int omap_dm_timer_cap_counter(struct omap_dm_timer *cookie, bool is_period) 1063 + { 1064 + struct dmtimer *timer; 1065 + unsigned int cap1 = 0; 1066 + unsigned int cap2 = 0; 1067 + u32 l, ret; 1068 + 1069 + timer = to_dmtimer(cookie); 1070 + if (unlikely(!timer || !atomic_read(&timer->enabled))) { 1071 + pr_err("%s:timer is not available or enabled.%p\n", __func__, (void *)timer); 1072 + return -EINVAL; 1073 + } 1074 + 1075 + /* Stop the timer */ 1076 + omap_dm_timer_stop(cookie); 1077 + 1078 + /* Clear the timer counter value to 0 */ 1079 + ret = omap_dm_timer_write_counter(cookie, 0); 1080 + if (ret) 1081 + return ret; 1082 + 1083 + /* Sets the timer capture configuration for period/duty cycle calculation */ 1084 + ret = omap_dm_timer_set_cap(cookie, true, is_period); 1085 + if (ret) { 1086 + pr_err("%s: Failed to set timer capture configuration.\n", __func__); 1087 + return ret; 1088 + } 1089 + /* Start the timer */ 1090 + omap_dm_timer_start(cookie); 1091 + 1092 + /* 1093 + * 1 sec delay is given so as to provide 1094 + * enough time to capture low frequency signals. 1095 + */ 1096 + msleep(1000); 1097 + 1098 + cap1 = __omap_dm_timer_cap(timer, 0); 1099 + cap2 = __omap_dm_timer_cap(timer, 1); 1100 + 1101 + /* 1102 + * Clears the TCLR configuration. 1103 + * The start bit must be set to 1 as the timer is already in start mode. 1104 + */ 1105 + l = dmtimer_read(timer, OMAP_TIMER_CTRL_REG); 1106 + l &= ~(0xffff) | 0x1; 1107 + dmtimer_write(timer, OMAP_TIMER_CTRL_REG, l); 1108 + 1109 + return (cap2-cap1); 1084 1110 } 1085 1111 1086 1112 static int __maybe_unused omap_dm_timer_runtime_suspend(struct device *dev) ··· 1358 1246 .write_counter = omap_dm_timer_write_counter, 1359 1247 .read_status = omap_dm_timer_read_status, 1360 1248 .write_status = omap_dm_timer_write_status, 1249 + .set_cap = omap_dm_timer_set_cap, 1250 + .get_cap_status = omap_dm_timer_get_pwm_status, 1251 + .read_cap = omap_dm_timer_cap_counter, 1361 1252 }; 1362 1253 1363 1254 static const struct dmtimer_platform_data omap3plus_pdata = {
+4
include/linux/platform_data/dmtimer-omap.h
··· 36 36 int (*set_pwm)(struct omap_dm_timer *timer, int def_on, 37 37 int toggle, int trigger, int autoreload); 38 38 int (*get_pwm_status)(struct omap_dm_timer *timer); 39 + int (*set_cap)(struct omap_dm_timer *timer, 40 + int autoreload, bool config_period); 41 + int (*get_cap_status)(struct omap_dm_timer *timer); 39 42 int (*set_prescaler)(struct omap_dm_timer *timer, int prescaler); 40 43 41 44 unsigned int (*read_counter)(struct omap_dm_timer *timer); 45 + unsigned int (*read_cap)(struct omap_dm_timer *timer, bool is_period); 42 46 int (*write_counter)(struct omap_dm_timer *timer, 43 47 unsigned int value); 44 48 unsigned int (*read_status)(struct omap_dm_timer *timer);