Skip to content

Commit 0494fc3

Browse files
Gokul Praveendlezcano
authored andcommitted
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
1 parent 4e9bfe6 commit 0494fc3

2 files changed

Lines changed: 121 additions & 2 deletions

File tree

drivers/clocksource/timer-ti-dm.c

Lines changed: 117 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <linux/platform_data/dmtimer-omap.h>
3232

3333
#include <clocksource/timer-ti-dm.h>
34+
#include <linux/delay.h>
3435

3536
/*
3637
* timer errata flags
@@ -836,6 +837,48 @@ static int omap_dm_timer_set_match(struct omap_dm_timer *cookie, int enable,
836837
return 0;
837838
}
838839

840+
static int omap_dm_timer_set_cap(struct omap_dm_timer *cookie,
841+
int autoreload, bool config_period)
842+
{
843+
struct dmtimer *timer;
844+
struct device *dev;
845+
int rc;
846+
u32 l;
847+
848+
timer = to_dmtimer(cookie);
849+
if (unlikely(!timer))
850+
return -EINVAL;
851+
852+
dev = &timer->pdev->dev;
853+
rc = pm_runtime_resume_and_get(dev);
854+
if (rc)
855+
return rc;
856+
/*
857+
* 1. Select autoreload mode. TIMER_TCLR[1] AR bit.
858+
* 2. TIMER_TCLR[14]: Sets the functionality of the TIMER IO pin.
859+
* 3. TIMER_TCLR[13] : Capture mode select bit.
860+
* 3. TIMER_TCLR[9-8] : Select transition capture mode.
861+
*/
862+
863+
l = dmtimer_read(timer, OMAP_TIMER_CTRL_REG);
864+
865+
if (autoreload)
866+
l |= OMAP_TIMER_CTRL_AR;
867+
868+
l |= OMAP_TIMER_CTRL_CAPTMODE | OMAP_TIMER_CTRL_GPOCFG;
869+
870+
if (config_period == true)
871+
l |= OMAP_TIMER_CTRL_TCM_LOWTOHIGH; /* Time Period config */
872+
else
873+
l |= OMAP_TIMER_CTRL_TCM_BOTHEDGES; /* Duty Cycle config */
874+
875+
dmtimer_write(timer, OMAP_TIMER_CTRL_REG, l);
876+
877+
pm_runtime_put_sync(dev);
878+
879+
return 0;
880+
}
881+
839882
static int omap_dm_timer_set_pwm(struct omap_dm_timer *cookie, int def_on,
840883
int toggle, int trigger, int autoreload)
841884
{
@@ -1023,23 +1066,92 @@ static unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *cookie)
10231066
return __omap_dm_timer_read_counter(timer);
10241067
}
10251068

1069+
static inline unsigned int __omap_dm_timer_cap(struct dmtimer *timer, int idx)
1070+
{
1071+
return idx == 0 ? dmtimer_read(timer, OMAP_TIMER_CAPTURE_REG) :
1072+
dmtimer_read(timer, OMAP_TIMER_CAPTURE2_REG);
1073+
}
1074+
10261075
static int omap_dm_timer_write_counter(struct omap_dm_timer *cookie, unsigned int value)
10271076
{
10281077
struct dmtimer *timer;
1078+
struct device *dev;
10291079

10301080
timer = to_dmtimer(cookie);
1031-
if (unlikely(!timer || !atomic_read(&timer->enabled))) {
1032-
pr_err("%s: timer not available or enabled.\n", __func__);
1081+
if (unlikely(!timer)) {
1082+
pr_err("%s: timer not available.\n", __func__);
10331083
return -EINVAL;
10341084
}
10351085

1086+
dev = &timer->pdev->dev;
1087+
1088+
pm_runtime_resume_and_get(dev);
10361089
dmtimer_write(timer, OMAP_TIMER_COUNTER_REG, value);
1090+
pm_runtime_put_sync(dev);
10371091

10381092
/* Save the context */
10391093
timer->context.tcrr = value;
10401094
return 0;
10411095
}
10421096

1097+
/**
1098+
* omap_dm_timer_cap_counter() - Calculate the high count or period count depending on the
1099+
* configuration.
1100+
* @cookie:Pointer to OMAP DM timer
1101+
* @is_period:Whether to configure timer in period or duty cycle mode
1102+
*
1103+
* Return high count or period count if timer is enabled else appropriate error.
1104+
*/
1105+
static unsigned int omap_dm_timer_cap_counter(struct omap_dm_timer *cookie, bool is_period)
1106+
{
1107+
struct dmtimer *timer;
1108+
unsigned int cap1 = 0;
1109+
unsigned int cap2 = 0;
1110+
u32 l, ret;
1111+
1112+
timer = to_dmtimer(cookie);
1113+
if (unlikely(!timer || !atomic_read(&timer->enabled))) {
1114+
pr_err("%s:timer is not available or enabled.%p\n", __func__, (void *)timer);
1115+
return -EINVAL;
1116+
}
1117+
1118+
/* Stop the timer */
1119+
omap_dm_timer_stop(cookie);
1120+
1121+
/* Clear the timer counter value to 0 */
1122+
ret = omap_dm_timer_write_counter(cookie, 0);
1123+
if (ret)
1124+
return ret;
1125+
1126+
/* Sets the timer capture configuration for period/duty cycle calculation */
1127+
ret = omap_dm_timer_set_cap(cookie, true, is_period);
1128+
if (ret) {
1129+
pr_err("%s: Failed to set timer capture configuration.\n", __func__);
1130+
return ret;
1131+
}
1132+
/* Start the timer */
1133+
omap_dm_timer_start(cookie);
1134+
1135+
/*
1136+
* 1 sec delay is given so as to provide
1137+
* enough time to capture low frequency signals.
1138+
*/
1139+
msleep(1000);
1140+
1141+
cap1 = __omap_dm_timer_cap(timer, 0);
1142+
cap2 = __omap_dm_timer_cap(timer, 1);
1143+
1144+
/*
1145+
* Clears the TCLR configuration.
1146+
* The start bit must be set to 1 as the timer is already in start mode.
1147+
*/
1148+
l = dmtimer_read(timer, OMAP_TIMER_CTRL_REG);
1149+
l &= ~(0xffff) | 0x1;
1150+
dmtimer_write(timer, OMAP_TIMER_CTRL_REG, l);
1151+
1152+
return (cap2-cap1);
1153+
}
1154+
10431155
static int __maybe_unused omap_dm_timer_runtime_suspend(struct device *dev)
10441156
{
10451157
struct dmtimer *timer = dev_get_drvdata(dev);
@@ -1246,6 +1358,9 @@ static const struct omap_dm_timer_ops dmtimer_ops = {
12461358
.write_counter = omap_dm_timer_write_counter,
12471359
.read_status = omap_dm_timer_read_status,
12481360
.write_status = omap_dm_timer_write_status,
1361+
.set_cap = omap_dm_timer_set_cap,
1362+
.get_cap_status = omap_dm_timer_get_pwm_status,
1363+
.read_cap = omap_dm_timer_cap_counter,
12491364
};
12501365

12511366
static const struct dmtimer_platform_data omap3plus_pdata = {

include/linux/platform_data/dmtimer-omap.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,13 @@ struct omap_dm_timer_ops {
3636
int (*set_pwm)(struct omap_dm_timer *timer, int def_on,
3737
int toggle, int trigger, int autoreload);
3838
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);
3942
int (*set_prescaler)(struct omap_dm_timer *timer, int prescaler);
4043

4144
unsigned int (*read_counter)(struct omap_dm_timer *timer);
45+
unsigned int (*read_cap)(struct omap_dm_timer *timer, bool is_period);
4246
int (*write_counter)(struct omap_dm_timer *timer,
4347
unsigned int value);
4448
unsigned int (*read_status)(struct omap_dm_timer *timer);

0 commit comments

Comments
 (0)