Skip to contentSkip to conversation

Implement event capture for OMAP (draft)

PATCH Superseded Ladislav Michl 3 participants 15 messages Feb 23, 2018 – Mar 28, 2018

Subsystems (2)

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore
#0 lore raw

cover Implement event capture for OMAP (draft)

Hi,

this patchset based on next-20180223 first cleans up playground (patches 1-4 which I'd appreciate to be reviewed and merged eventually) and then adds event capture functionality which is just good for doing:

$ echo 0 > /sys/class/pwm/pwmchip4/export
$ cat /sys/class/pwm/pwmchip4/pwm0/capture 
1000000 500000
$ cat /sys/class/pwm/pwmchip4/pwm0/capture 
100000 50000
$ cat /sys/class/pwm/pwmchip4/pwm0/capture 
100000 75000

Above measured frequencies are 1kHz and 10kHz with 50% duty cycle, the last one is with 75% duty cycle. However with 100kHz it sometimes ends with:

$ cat /sys/class/pwm/pwmchip4/pwm0/capture 
omap_dm_timer_read_status: timer not available or enabled.
12462 6231

So locking is probably not done right, therefore patches 5 and 6 are sent only for reference, as there's also another fundamental problem:

Hardware can be told to capture both edges, but there's no way to tell it which one should be captured first. Other posibility would be first configure for rising edge and reconfigure in interrupt for falling one. Here we meet latency problem again:
https://www.spinics.net/lists/linux-omap/msg140081.html
Attached test patch shows average diff around 150us (sometimes over 300us) which pretty much limits maximum measurable frequency.

I tried to misuse PM_QOS_CPU_DMA_LATENCY to overcome latency issue, but with no luck.

Ladislav Michl (6):
clocksource: timer-ti-dm: Make unexported functions static
clocksource: timer-ti-dm: Consolidate set source
clocksource: timer-ti-dm: Check prescaler value
pwm: pwm-omap-dmtimer: Fix frequency when using prescaler
clocksource: timer-ti-dm: Add event capture
pwm: pwm-omap-dmtimer: Add capture functionality

 drivers/clocksource/timer-ti-dm.c          | 263 ++++++++++++++++-------------
 drivers/pwm/pwm-omap-dmtimer.c             | 220 +++++++++++++++++++-----
 include/clocksource/timer-ti-dm.h          |  33 ----
 include/linux/platform_data/dmtimer-omap.h |   8 +
 4 files changed, 340 insertions(+), 184 deletions(-)

Latency test patch:

drivers/pwm/pwm-omap-dmtimer.c +5 -1
index 5a2fc0e0a1c5..c1a94740079a 100644
@@ -46,7 +46,7 @@ struct pwm_omap_dmtimer_chip {
 	const struct omap_dm_timer_ops *pdata;
 	struct platform_device *dm_timer_pdev;
 	unsigned long freq;
-	unsigned int ev_cnt, overflow, width;
+	unsigned int ev_cnt, overflow, width, counter_irq, counter_captured;
 };
 
 static inline struct pwm_omap_dmtimer_chip *
@@ -280,6 +280,8 @@ static int pwm_omap_dmtimer_capture(struct pwm_chip *chip,
 		omap->ev_cnt = omap->width = 0;
 		spin_unlock_irqrestore(&omap->lock, flags);
 
+		printk("diff: %d\n", pwm_omap_dmtimer_ticks_to_ns(omap, omap->counter_irq - omap->counter_captured));
+
 		res = wait_event_interruptible_timeout(omap->wait,
 						       omap->width > 0,
 						       timeout);
@@ -317,6 +319,8 @@ static irqreturn_t pwm_omap_dmtimer_irq(int irq, void *dev_id)
 	if (l & OMAP_TIMER_INT_CAPTURE) {
 		if (!omap->width && omap->ev_cnt == 1) {
 			omap->pdata->read_capture(omap->dm_timer, &c1, &c2);
+			omap->counter_irq = omap->pdata->read_counter(omap->dm_timer);
+			omap->counter_captured = c2;
 			omap->width = pwm_omap_dmtimer_get_width(omap, c1, c2);
 			wake_up(&omap->wait);
 		}
Signature · 1 line
2.16.1
#1 lore raw

PATCH 1/6 clocksource: timer-ti-dm: Make unexported functions static

As dmtimer no longer exports functions, make those previously exported static (this requires few functions to be moved around as their prototypes were deleted).

---
 drivers/clocksource/timer-ti-dm.c | 218 +++++++++++++++++++-------------------
 include/clocksource/timer-ti-dm.h |  33 ------
 2 files changed, 109 insertions(+), 142 deletions(-)
drivers/clocksource/timer-ti-dm.c +109 -109
index 70782a41c493..e4d75a8eaa91 100644
@@ -163,6 +163,92 @@ static int omap_dm_timer_of_set_source(struct omap_dm_timer *timer)
 	return ret;
 }
 
+static int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
+{
+	int ret;
+	char *parent_name = NULL;
+	struct clk *parent;
+	struct dmtimer_platform_data *pdata;
+
+	if (unlikely(!timer))
+		return -EINVAL;
+
+	pdata = timer->pdev->dev.platform_data;
+
+	if (source < 0 || source >= 3)
+		return -EINVAL;
+
+	/*
+	 * FIXME: Used for OMAP1 devices only because they do not currently
+	 * use the clock framework to set the parent clock. To be removed
+	 * once OMAP1 migrated to using clock framework for dmtimers
+	 */
+	if (pdata && pdata->set_timer_src)
+		return pdata->set_timer_src(timer->pdev, source);
+
+	if (IS_ERR(timer->fclk))
+		return -EINVAL;
+
+#if defined(CONFIG_COMMON_CLK)
+	/* Check if the clock has configurable parents */
+	if (clk_hw_get_num_parents(__clk_get_hw(timer->fclk)) < 2)
+		return 0;
+#endif
+
+	switch (source) {
+	case OMAP_TIMER_SRC_SYS_CLK:
+		parent_name = "timer_sys_ck";
+		break;
+
+	case OMAP_TIMER_SRC_32_KHZ:
+		parent_name = "timer_32k_ck";
+		break;
+
+	case OMAP_TIMER_SRC_EXT_CLK:
+		parent_name = "timer_ext_ck";
+		break;
+	}
+
+	parent = clk_get(&timer->pdev->dev, parent_name);
+	if (IS_ERR(parent)) {
+		pr_err("%s: %s not found\n", __func__, parent_name);
+		return -EINVAL;
+	}
+
+	ret = clk_set_parent(timer->fclk, parent);
+	if (ret < 0)
+		pr_err("%s: failed to set %s as parent\n", __func__,
+			parent_name);
+
+	clk_put(parent);
+
+	return ret;
+}
+
+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)
+{
+	pm_runtime_put_sync(&timer->pdev->dev);
+}
+
 static int omap_dm_timer_prepare(struct omap_dm_timer *timer)
 {
 	int rc;
@@ -298,16 +384,16 @@ static struct omap_dm_timer *_omap_dm_timer_request(int req_type, void *data)
 	return timer;
 }
 
-struct omap_dm_timer *omap_dm_timer_request(void)
+static struct omap_dm_timer *omap_dm_timer_request(void)
 {
 	return _omap_dm_timer_request(REQUEST_ANY, NULL);
 }
 
-struct omap_dm_timer *omap_dm_timer_request_specific(int id)
+static struct omap_dm_timer *omap_dm_timer_request_specific(int id)
 {
 	/* Requesting timer by ID is not supported when device tree is used */
 	if (of_have_populated_dt()) {
-		pr_warn("%s: Please use omap_dm_timer_request_by_cap/node()\n",
+		pr_warn("%s: Please use omap_dm_timer_request_by_node()\n",
 			__func__);
 		return NULL;
 	}
@@ -336,7 +422,7 @@ struct omap_dm_timer *omap_dm_timer_request_by_cap(u32 cap)
  * Request a timer based upon a device node pointer. Returns pointer to
  * timer handle on success and a NULL pointer on failure.
  */
-struct omap_dm_timer *omap_dm_timer_request_by_node(struct device_node *np)
+static struct omap_dm_timer *omap_dm_timer_request_by_node(struct device_node *np)
 {
 	if (!np)
 		return NULL;
@@ -344,7 +430,7 @@ struct omap_dm_timer *omap_dm_timer_request_by_node(struct device_node *np)
 	return _omap_dm_timer_request(REQUEST_BY_NODE, np);
 }
 
-int omap_dm_timer_free(struct omap_dm_timer *timer)
+static int omap_dm_timer_free(struct omap_dm_timer *timer)
 {
 	if (unlikely(!timer))
 		return -EINVAL;
@@ -356,30 +442,6 @@ int omap_dm_timer_free(struct omap_dm_timer *timer)
 	return 0;
 }
 
-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);
-		}
-	}
-}
-
-void omap_dm_timer_disable(struct omap_dm_timer *timer)
-{
-	pm_runtime_put_sync(&timer->pdev->dev);
-}
-
 int omap_dm_timer_get_irq(struct omap_dm_timer *timer)
 {
 	if (timer)
@@ -424,7 +486,7 @@ __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
 
 #else
 
-struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
+static struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
 {
 	if (timer && !IS_ERR(timer->fclk))
 		return timer->fclk;
@@ -451,7 +513,7 @@ int omap_dm_timer_trigger(struct omap_dm_timer *timer)
 	return 0;
 }
 
-int omap_dm_timer_start(struct omap_dm_timer *timer)
+static int omap_dm_timer_start(struct omap_dm_timer *timer)
 {
 	u32 l;
 
@@ -471,7 +533,7 @@ int omap_dm_timer_start(struct omap_dm_timer *timer)
 	return 0;
 }
 
-int omap_dm_timer_stop(struct omap_dm_timer *timer)
+static int omap_dm_timer_stop(struct omap_dm_timer *timer)
 {
 	unsigned long rate = 0;
 
@@ -494,70 +556,8 @@ int omap_dm_timer_stop(struct omap_dm_timer *timer)
 	return 0;
 }
 
-int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
-{
-	int ret;
-	char *parent_name = NULL;
-	struct clk *parent;
-	struct dmtimer_platform_data *pdata;
-
-	if (unlikely(!timer))
-		return -EINVAL;
-
-	pdata = timer->pdev->dev.platform_data;
-
-	if (source < 0 || source >= 3)
-		return -EINVAL;
-
-	/*
-	 * FIXME: Used for OMAP1 devices only because they do not currently
-	 * use the clock framework to set the parent clock. To be removed
-	 * once OMAP1 migrated to using clock framework for dmtimers
-	 */
-	if (pdata && pdata->set_timer_src)
-		return pdata->set_timer_src(timer->pdev, source);
-
-	if (IS_ERR(timer->fclk))
-		return -EINVAL;
-
-#if defined(CONFIG_COMMON_CLK)
-	/* Check if the clock has configurable parents */
-	if (clk_hw_get_num_parents(__clk_get_hw(timer->fclk)) < 2)
-		return 0;
-#endif
-
-	switch (source) {
-	case OMAP_TIMER_SRC_SYS_CLK:
-		parent_name = "timer_sys_ck";
-		break;
-
-	case OMAP_TIMER_SRC_32_KHZ:
-		parent_name = "timer_32k_ck";
-		break;
-
-	case OMAP_TIMER_SRC_EXT_CLK:
-		parent_name = "timer_ext_ck";
-		break;
-	}
-
-	parent = clk_get(&timer->pdev->dev, parent_name);
-	if (IS_ERR(parent)) {
-		pr_err("%s: %s not found\n", __func__, parent_name);
-		return -EINVAL;
-	}
-
-	ret = clk_set_parent(timer->fclk, parent);
-	if (ret < 0)
-		pr_err("%s: failed to set %s as parent\n", __func__,
-			parent_name);
-
-	clk_put(parent);
-
-	return ret;
-}
-
-int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
-			    unsigned int load)
+static int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
+				  unsigned int load)
 {
 	u32 l;
 
@@ -609,9 +609,8 @@ int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
 	timer->context.tcrr = load;
 	return 0;
 }
-
-int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
-			     unsigned int match)
+static int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
+				   unsigned int match)
 {
 	u32 l;
 
@@ -634,8 +633,8 @@ int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
 	return 0;
 }
 
-int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
-			   int toggle, int trigger)
+static int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
+				 int toggle, int trigger)
 {
 	u32 l;
 
@@ -659,7 +658,8 @@ int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
 	return 0;
 }
 
-int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
+static int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer,
+					int prescaler)
 {
 	u32 l;
 
@@ -681,8 +681,8 @@ int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
 	return 0;
 }
 
-int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
-				  unsigned int value)
+static int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
+					unsigned int value)
 {
 	if (unlikely(!timer))
 		return -EINVAL;
@@ -704,7 +704,7 @@ int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
  *
  * Disables the specified timer interrupts for a timer.
  */
-int omap_dm_timer_set_int_disable(struct omap_dm_timer *timer, u32 mask)
+static int omap_dm_timer_set_int_disable(struct omap_dm_timer *timer, u32 mask)
 {
 	u32 l = mask;
 
@@ -727,7 +727,7 @@ int omap_dm_timer_set_int_disable(struct omap_dm_timer *timer, u32 mask)
 	return 0;
 }
 
-unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
+static unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
 {
 	unsigned int l;
 
@@ -741,7 +741,7 @@ unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
 	return l;
 }
 
-int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
+static int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
 {
 	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev)))
 		return -EINVAL;
@@ -751,7 +751,7 @@ int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
 	return 0;
 }
 
-unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
+static unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
 {
 	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
 		pr_err("%s: timer not iavailable or enabled.\n", __func__);
@@ -761,7 +761,7 @@ unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
 	return __omap_dm_timer_read_counter(timer, timer->posted);
 }
 
-int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
+static int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
 {
 	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
 		pr_err("%s: timer not available or enabled.\n", __func__);
include/clocksource/timer-ti-dm.h +0 -33
index 4f310957c21b..7d9598dc578d 100644
@@ -119,46 +119,13 @@ struct omap_dm_timer {
 };
 
 int omap_dm_timer_reserve_systimer(int id);
-struct omap_dm_timer *omap_dm_timer_request(void);
-struct omap_dm_timer *omap_dm_timer_request_specific(int timer_id);
 struct omap_dm_timer *omap_dm_timer_request_by_cap(u32 cap);
-struct omap_dm_timer *omap_dm_timer_request_by_node(struct device_node *np);
-int omap_dm_timer_free(struct omap_dm_timer *timer);
-void omap_dm_timer_enable(struct omap_dm_timer *timer);
-void omap_dm_timer_disable(struct omap_dm_timer *timer);
 
 int omap_dm_timer_get_irq(struct omap_dm_timer *timer);
 
 u32 omap_dm_timer_modify_idlect_mask(u32 inputmask);
 
-#ifndef CONFIG_ARCH_OMAP1
-struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer);
-#else
-static inline
-struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
-{
-	return NULL;
-}
-#endif
-
 int omap_dm_timer_trigger(struct omap_dm_timer *timer);
-int omap_dm_timer_start(struct omap_dm_timer *timer);
-int omap_dm_timer_stop(struct omap_dm_timer *timer);
-
-int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source);
-int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, unsigned int value);
-int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload, unsigned int value);
-int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable, unsigned int match);
-int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, int toggle, int trigger);
-int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler);
-
-int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, unsigned int value);
-int omap_dm_timer_set_int_disable(struct omap_dm_timer *timer, u32 mask);
-
-unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer);
-int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value);
-unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer);
-int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value);
 
 int omap_dm_timers_active(void);
 
Signature · 1 line
2.16.1
#6 lore raw

PATCH 2/6 clocksource: timer-ti-dm: Consolidate set source

In reply to Ladislav Michl

Reorder omap_dm_timer_set_source internals to get
source verification more straightforward.

---
 drivers/clocksource/timer-ti-dm.c | 38 ++++++++++++++++----------------------
 1 file changed, 16 insertions(+), 22 deletions(-)
drivers/clocksource/timer-ti-dm.c +16 -22
index e4d75a8eaa91..4d645d6c6c31 100644
@@ -166,17 +166,28 @@ static int omap_dm_timer_of_set_source(struct omap_dm_timer *timer)
 static int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
 {
 	int ret;
-	char *parent_name = NULL;
+	const char *parent_name;
 	struct clk *parent;
 	struct dmtimer_platform_data *pdata;
 
-	if (unlikely(!timer))
+	if (unlikely(!timer) || IS_ERR(timer->fclk))
 		return -EINVAL;
 
-	pdata = timer->pdev->dev.platform_data;
-
-	if (source < 0 || source >= 3)
+	switch (source) {
+	case OMAP_TIMER_SRC_SYS_CLK:
+		parent_name = "timer_sys_ck";
+		break;
+	case OMAP_TIMER_SRC_32_KHZ:
+		parent_name = "timer_32k_ck";
+		break;
+	case OMAP_TIMER_SRC_EXT_CLK:
+		parent_name = "timer_ext_ck";
+		break;
+	default:
 		return -EINVAL;
+	}
+
+	pdata = timer->pdev->dev.platform_data;
 
 	/*
 	 * FIXME: Used for OMAP1 devices only because they do not currently
@@ -186,29 +197,12 @@ static int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
 	if (pdata && pdata->set_timer_src)
 		return pdata->set_timer_src(timer->pdev, source);
 
-	if (IS_ERR(timer->fclk))
-		return -EINVAL;
-
 #if defined(CONFIG_COMMON_CLK)
 	/* Check if the clock has configurable parents */
 	if (clk_hw_get_num_parents(__clk_get_hw(timer->fclk)) < 2)
 		return 0;
 #endif
 
-	switch (source) {
-	case OMAP_TIMER_SRC_SYS_CLK:
-		parent_name = "timer_sys_ck";
-		break;
-
-	case OMAP_TIMER_SRC_32_KHZ:
-		parent_name = "timer_32k_ck";
-		break;
-
-	case OMAP_TIMER_SRC_EXT_CLK:
-		parent_name = "timer_ext_ck";
-		break;
-	}
-
 	parent = clk_get(&timer->pdev->dev, parent_name);
 	if (IS_ERR(parent)) {
 		pr_err("%s: %s not found\n", __func__, parent_name);
Signature · 1 line
2.16.1
#7 lore raw

PATCH 3/6 clocksource: timer-ti-dm: Check prescaler value

In reply to Ladislav Michl

Invalid value silently disables use of the prescaler. Use -1 explicitely for that purpose and error out on invalid value.

---
 drivers/clocksource/timer-ti-dm.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/clocksource/timer-ti-dm.c +2 -2
index 4d645d6c6c31..b57e875b74ca 100644
@@ -657,13 +657,13 @@ static int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer,
 {
 	u32 l;
 
-	if (unlikely(!timer))
+	if (unlikely(!timer) || prescaler < -1 || prescaler > 7)
 		return -EINVAL;
 
 	omap_dm_timer_enable(timer);
 	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
 	l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
-	if (prescaler >= 0x00 && prescaler <= 0x07) {
+	if (prescaler >= 0) {
 		l |= OMAP_TIMER_CTRL_PRE;
 		l |= prescaler << 2;
 	}
Signature · 1 line
2.16.1
#8 lore raw

PATCH 4/6 pwm: pwm-omap-dmtimer: Fix frequency when using prescaler

In reply to Ladislav Michl

Prescaler setting is currently not taken into account. Fix that by introducing freq member variable and initialize it at device probe time. This also avoids frequency recomputing at each pwm configure time.

---
 drivers/pwm/pwm-omap-dmtimer.c | 93 +++++++++++++++++++++++++-----------------
 1 file changed, 55 insertions(+), 38 deletions(-)
drivers/pwm/pwm-omap-dmtimer.c +55 -38
index 665da3c8fbce..48342285c953 100644
@@ -40,6 +40,7 @@ struct pwm_omap_dmtimer_chip {
 	pwm_omap_dmtimer *dm_timer;
 	const struct omap_dm_timer_ops *pdata;
 	struct platform_device *dm_timer_pdev;
+	unsigned long freq;
 };
 
 static inline struct pwm_omap_dmtimer_chip *
@@ -48,9 +49,10 @@ to_pwm_omap_dmtimer_chip(struct pwm_chip *chip)
 	return container_of(chip, struct pwm_omap_dmtimer_chip, chip);
 }
 
-static u32 pwm_omap_dmtimer_get_clock_cycles(unsigned long clk_rate, int ns)
+static inline u32
+pwm_omap_dmtimer_get_clock_cycles(struct pwm_omap_dmtimer_chip *omap, int ns)
 {
-	return DIV_ROUND_CLOSEST_ULL((u64)clk_rate * ns, NSEC_PER_SEC);
+	return DIV_ROUND_CLOSEST_ULL((u64)omap->freq * ns, NSEC_PER_SEC);
 }
 
 static void pwm_omap_dmtimer_start(struct pwm_omap_dmtimer_chip *omap)
@@ -99,8 +101,6 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
 	struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
 	u32 period_cycles, duty_cycles;
 	u32 load_value, match_value;
-	struct clk *fclk;
-	unsigned long clk_rate;
 	bool timer_active;
 
 	dev_dbg(chip->dev, "requested duty cycle: %d ns, period: %d ns\n",
@@ -114,19 +114,6 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
 		return 0;
 	}
 
-	fclk = omap->pdata->get_fclk(omap->dm_timer);
-	if (!fclk) {
-		dev_err(chip->dev, "invalid pmtimer fclk\n");
-		goto err_einval;
-	}
-
-	clk_rate = clk_get_rate(fclk);
-	if (!clk_rate) {
-		dev_err(chip->dev, "invalid pmtimer fclk rate\n");
-		goto err_einval;
-	}
-
-	dev_dbg(chip->dev, "clk rate: %luHz\n", clk_rate);
 
 	/*
 	 * Calculate the appropriate load and match values based on the
@@ -144,35 +131,35 @@ static int pwm_omap_dmtimer_config(struct pwm_chip *chip,
 	 *   OMAP4430/60/70 TRM sections 22.2.4.10 and 22.2.4.11
 	 *   AM335x Sitara TRM sections 20.1.3.5 and 20.1.3.6
 	 */
-	period_cycles = pwm_omap_dmtimer_get_clock_cycles(clk_rate, period_ns);
-	duty_cycles = pwm_omap_dmtimer_get_clock_cycles(clk_rate, duty_ns);
+	period_cycles = pwm_omap_dmtimer_get_clock_cycles(omap, period_ns);
+	duty_cycles = pwm_omap_dmtimer_get_clock_cycles(omap, duty_ns);
 
 	if (period_cycles < 2) {
 		dev_info(chip->dev,
 			 "period %d ns too short for clock rate %lu Hz\n",
-			 period_ns, clk_rate);
+			 period_ns, omap->freq);
 		goto err_einval;
 	}
 
 	if (duty_cycles < 1) {
 		dev_dbg(chip->dev,
 			"duty cycle %d ns is too short for clock rate %lu Hz\n",
-			duty_ns, clk_rate);
+			duty_ns, omap->freq);
 		dev_dbg(chip->dev, "using minimum of 1 clock cycle\n");
 		duty_cycles = 1;
 	} else if (duty_cycles >= period_cycles) {
 		dev_dbg(chip->dev,
 			"duty cycle %d ns is too long for period %d ns at clock rate %lu Hz\n",
-			duty_ns, period_ns, clk_rate);
+			duty_ns, period_ns, omap->freq);
 		dev_dbg(chip->dev, "using maximum of 1 clock cycle less than period\n");
 		duty_cycles = period_cycles - 1;
 	}
 
 	dev_dbg(chip->dev, "effective duty cycle: %lld ns, period: %lld ns\n",
 		DIV_ROUND_CLOSEST_ULL((u64)NSEC_PER_SEC * duty_cycles,
-				      clk_rate),
+				      omap->freq),
 		DIV_ROUND_CLOSEST_ULL((u64)NSEC_PER_SEC * period_cycles,
-				      clk_rate));
+				      omap->freq));
 
 	load_value = (DM_TIMER_MAX - period_cycles) + 1;
 	match_value = load_value + duty_cycles - 1;
@@ -248,6 +235,7 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
 	struct dmtimer_platform_data *timer_pdata;
 	const struct omap_dm_timer_ops *pdata;
 	pwm_omap_dmtimer *dm_timer;
+	struct clk *fclk;
 	u32 v;
 	int ret = 0;
 
@@ -295,10 +283,8 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
 	}
 
 	dm_timer = pdata->request_by_node(timer);
-	if (!dm_timer) {
+	if (!dm_timer)
 		ret = -EPROBE_DEFER;
-		goto put;
-	}
 
 put:
 	of_node_put(timer);
@@ -307,8 +293,8 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
 
 	omap = devm_kzalloc(&pdev->dev, sizeof(*omap), GFP_KERNEL);
 	if (!omap) {
-		pdata->free(dm_timer);
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto free_dm_timer;
 	}
 
 	omap->pdata = pdata;
@@ -319,15 +305,42 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
 	 * Ensure that the timer is stopped before we allow PWM core to call
 	 * pwm_enable.
 	 */
-	if (pm_runtime_active(&omap->dm_timer_pdev->dev))
-		omap->pdata->stop(omap->dm_timer);
-
-	if (!of_property_read_u32(pdev->dev.of_node, "ti,prescaler", &v))
-		omap->pdata->set_prescaler(omap->dm_timer, v);
+	if (pm_runtime_active(&timer_pdev->dev))
+		pdata->stop(dm_timer);
 
 	/* setup dmtimer clock source */
-	if (!of_property_read_u32(pdev->dev.of_node, "ti,clock-source", &v))
-		omap->pdata->set_source(omap->dm_timer, v);
+	if (!of_property_read_u32(pdev->dev.of_node, "ti,clock-source", &v)) {
+		ret = pdata->set_source(dm_timer, v);
+		if (ret) {
+			dev_err(&pdev->dev, "invalid clock-source\n");
+			goto free_dm_timer;
+		}
+	}
+
+	fclk = pdata->get_fclk(dm_timer);
+	if (!fclk) {
+		dev_err(&pdev->dev, "invalid fclk\n");
+		ret = -EINVAL;
+		goto free_dm_timer;
+	}
+
+	omap->freq = clk_get_rate(fclk);
+	if (!omap->freq) {
+		dev_err(&pdev->dev, "invalid fclk rate\n");
+		ret = -EINVAL;
+		goto free_dm_timer;
+	}
+
+	if (!of_property_read_u32(pdev->dev.of_node, "ti,prescaler", &v)) {
+		ret = pdata->set_prescaler(dm_timer, v);
+		if (ret) {
+			dev_err(&pdev->dev, "invalid prescaler\n");
+			goto free_dm_timer;
+		}
+		omap->freq >>= v + 1;
+	}
+
+	dev_dbg(&pdev->dev, "clk rate: %luHz\n", omap->freq);
 
 	omap->chip.dev = &pdev->dev;
 	omap->chip.ops = &pwm_omap_dmtimer_ops;
@@ -341,13 +354,17 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
 	ret = pwmchip_add(&omap->chip);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "failed to register PWM\n");
-		omap->pdata->free(omap->dm_timer);
-		return ret;
+		goto free_dm_timer;
 	}
 
 	platform_set_drvdata(pdev, omap);
 
 	return 0;
+
+free_dm_timer:
+	pdata->free(dm_timer);
+
+	return ret;
 }
 
 static int pwm_omap_dmtimer_remove(struct platform_device *pdev)
Signature · 1 line
2.16.1
#13 lore raw

PATCH 5/6 clocksource: timer-ti-dm: Add event capture

In reply to Ladislav Michl

Implement event capture functions.

---
 drivers/clocksource/timer-ti-dm.c          | 47 ++++++++++++++++++++++++++++--
 include/linux/platform_data/dmtimer-omap.h |  8 +++++
 2 files changed, 53 insertions(+), 2 deletions(-)
drivers/clocksource/timer-ti-dm.c +45 -2
index b57e875b74ca..c227d62794a0 100644
@@ -576,8 +576,8 @@ static int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
 }
 
 /* Optimized set_load which removes costly spin wait in timer_start */
-int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
-                            unsigned int load)
+static int omap_dm_timer_set_load_start(struct omap_dm_timer *timer,
+					int autoreload, unsigned int load)
 {
 	u32 l;
 
@@ -627,6 +627,30 @@ static int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
 	return 0;
 }
 
+static int omap_dm_timer_set_capture(struct omap_dm_timer *timer,
+				     int captmode, int edges)
+{
+	u32 l;
+
+	if (unlikely(!timer))
+		return -EINVAL;
+
+	omap_dm_timer_enable(timer);
+	l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
+	l &= ~(OMAP_TIMER_CTRL_CAPTMODE | OMAP_TIMER_CTRL_SCPWM |
+	       OMAP_TIMER_CTRL_PT | OMAP_TIMER_CTRL_TCM_BOTHEDGES);
+	l |= OMAP_TIMER_CTRL_GPOCFG;
+	if (captmode)
+		l |= OMAP_TIMER_CTRL_CAPTMODE;
+	l |= edges << 8;
+	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;
+}
+
 static int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
 				 int toggle, int trigger)
 {
@@ -785,6 +809,22 @@ int omap_dm_timers_active(void)
 	return 0;
 }
 
+static int omap_dm_timer_read_capture(struct omap_dm_timer *timer,
+					unsigned int *reg,
+					unsigned int *reg2)
+{
+	if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
+		pr_err("%s: timer not available or enabled.\n", __func__);
+		return -EINVAL;
+	}
+
+	*reg = omap_dm_timer_read_reg(timer, OMAP_TIMER_CAPTURE_REG);
+	if (reg2)
+		*reg2 = omap_dm_timer_read_reg(timer, OMAP_TIMER_CAPTURE2_REG);
+
+	return 0;
+}
+
 static const struct of_device_id omap_timer_match[];
 
 /**
@@ -930,11 +970,14 @@ const static struct omap_dm_timer_ops dmtimer_ops = {
 	.start = omap_dm_timer_start,
 	.stop = omap_dm_timer_stop,
 	.set_load = omap_dm_timer_set_load,
+	.set_load_start = omap_dm_timer_set_load_start,
 	.set_match = omap_dm_timer_set_match,
+	.set_capture = omap_dm_timer_set_capture,
 	.set_pwm = omap_dm_timer_set_pwm,
 	.set_prescaler = omap_dm_timer_set_prescaler,
 	.read_counter = omap_dm_timer_read_counter,
 	.write_counter = omap_dm_timer_write_counter,
+	.read_capture = omap_dm_timer_read_capture,
 	.read_status = omap_dm_timer_read_status,
 	.write_status = omap_dm_timer_write_status,
 };
include/linux/platform_data/dmtimer-omap.h +8 -0
index 757a0f9e26f9..7502f130b213 100644
@@ -43,8 +43,12 @@ struct omap_dm_timer_ops {
 
 	int	(*set_load)(struct omap_dm_timer *timer, int autoreload,
 			    unsigned int value);
+	int	(*set_load_start)(struct omap_dm_timer *timer, int autoreload,
+				  unsigned int value);
 	int	(*set_match)(struct omap_dm_timer *timer, int enable,
 			     unsigned int match);
+	int	(*set_capture)(struct omap_dm_timer *timer, int captmode,
+			       int edges);
 	int	(*set_pwm)(struct omap_dm_timer *timer, int def_on,
 			   int toggle, int trigger);
 	int	(*set_prescaler)(struct omap_dm_timer *timer, int prescaler);
@@ -52,6 +56,10 @@ struct omap_dm_timer_ops {
 	unsigned int (*read_counter)(struct omap_dm_timer *timer);
 	int	(*write_counter)(struct omap_dm_timer *timer,
 				 unsigned int value);
+
+	int	(*read_capture)(struct omap_dm_timer *timer, unsigned int *reg,
+				unsigned int *reg2);
+
 	unsigned int (*read_status)(struct omap_dm_timer *timer);
 	int	(*write_status)(struct omap_dm_timer *timer,
 				unsigned int value);
Signature · 1 line
2.16.1
#14 lore raw

PATCH 6/6 pwm: pwm-omap-dmtimer: Add capture functionality

In reply to Ladislav Michl

Implement event capture.

---
Note: Please see cover letter

 drivers/pwm/pwm-omap-dmtimer.c | 127 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 127 insertions(+)
drivers/pwm/pwm-omap-dmtimer.c +127 -0
index 48342285c953..5a2fc0e0a1c5 100644
@@ -16,8 +16,10 @@
  *   PWM driver / controller, using the OMAP's dual-mode timers.
  */
 
+#include <clocksource/timer-ti-dm.h>
 #include <linux/clk.h>
 #include <linux/err.h>
+#include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
@@ -30,17 +32,21 @@
 #include <linux/pwm.h>
 #include <linux/slab.h>
 #include <linux/time.h>
+#include <linux/wait.h>
 
 #define DM_TIMER_LOAD_MIN 0xfffffffe
 #define DM_TIMER_MAX      0xffffffff
 
 struct pwm_omap_dmtimer_chip {
 	struct pwm_chip chip;
+	spinlock_t lock;
 	struct mutex mutex;
+	wait_queue_head_t wait;
 	pwm_omap_dmtimer *dm_timer;
 	const struct omap_dm_timer_ops *pdata;
 	struct platform_device *dm_timer_pdev;
 	unsigned long freq;
+	unsigned int ev_cnt, overflow, width;
 };
 
 static inline struct pwm_omap_dmtimer_chip *
@@ -55,6 +61,22 @@ pwm_omap_dmtimer_get_clock_cycles(struct pwm_omap_dmtimer_chip *omap, int ns)
 	return DIV_ROUND_CLOSEST_ULL((u64)omap->freq * ns, NSEC_PER_SEC);
 }
 
+static inline unsigned int
+pwm_omap_dmtimer_ticks_to_ns(struct pwm_omap_dmtimer_chip *omap,
+			     unsigned int ticks)
+{
+	return DIV_ROUND_CLOSEST_ULL((u64)ticks * NSEC_PER_SEC, omap->freq);
+}
+
+static unsigned int pwm_omap_dmtimer_get_width(struct pwm_omap_dmtimer_chip *omap,
+					       unsigned int c1, unsigned int c2)
+{
+	if (c1 <= c2)
+		return c2 - c1;
+
+	return (c2 - omap->overflow) + (DM_TIMER_MAX - c1);
+}
+
 static void pwm_omap_dmtimer_start(struct pwm_omap_dmtimer_chip *omap)
 {
 	/*
@@ -218,7 +240,101 @@ static int pwm_omap_dmtimer_set_polarity(struct pwm_chip *chip,
 	return 0;
 }
 
+static int pwm_omap_dmtimer_capture(struct pwm_chip *chip,
+				    struct pwm_device *pwm,
+				    struct pwm_capture *result,
+				    unsigned long timeout)
+
+{
+	int res;
+	unsigned long flags;
+	struct pwm_omap_dmtimer_chip *omap = to_pwm_omap_dmtimer_chip(chip);
+
+	mutex_lock(&omap->mutex);
+
+	if (pm_runtime_active(&omap->dm_timer_pdev->dev))
+		omap->pdata->stop(omap->dm_timer);
+
+	/* Let timer overflow every 1 second */
+	omap->overflow = DM_TIMER_MAX - (1 * omap->freq);
+	timeout = msecs_to_jiffies(timeout);
+	result->period = result->duty_cycle = 0;
+
+	spin_lock_irqsave(&omap->lock, flags);
+	omap->pdata->set_int_enable(omap->dm_timer, OMAP_TIMER_INT_CAPTURE |
+				    OMAP_TIMER_INT_OVERFLOW);
+	omap->pdata->set_capture(omap->dm_timer, 1, 1);
+	omap->pdata->set_load_start(omap->dm_timer, true, omap->overflow);
+	omap->ev_cnt = omap->width = 0;
+	spin_unlock_irqrestore(&omap->lock, flags);
+
+	res = wait_event_interruptible_timeout(omap->wait,
+					       omap->width > 0, timeout);
+	if (res > 0) {
+		spin_lock_irqsave(&omap->lock, flags);
+		result->period =
+			pwm_omap_dmtimer_ticks_to_ns(omap, omap->width);
+		omap->pdata->stop(omap->dm_timer);
+		omap->pdata->set_capture(omap->dm_timer, 1, 3);
+		omap->pdata->start(omap->dm_timer);
+		omap->ev_cnt = omap->width = 0;
+		spin_unlock_irqrestore(&omap->lock, flags);
+
+		res = wait_event_interruptible_timeout(omap->wait,
+						       omap->width > 0,
+						       timeout);
+	}
+
+	spin_lock_irqsave(&omap->lock, flags);
+	omap->pdata->stop(omap->dm_timer);
+	omap->pdata->set_int_disable(omap->dm_timer, OMAP_TIMER_INT_CAPTURE |
+				     OMAP_TIMER_INT_OVERFLOW);
+	spin_unlock_irqrestore(&omap->lock, flags);
+
+	if (res == 0) {
+		res = -ETIMEDOUT;
+	} else if (res > 0) {
+		result->duty_cycle =
+			pwm_omap_dmtimer_ticks_to_ns(omap, omap->width);
+		res = 0;
+	}
+
+	mutex_unlock(&omap->mutex);
+
+	return res;
+}
+
+static irqreturn_t pwm_omap_dmtimer_irq(int irq, void *dev_id)
+{
+	u32 l;
+	unsigned int c1, c2;
+	unsigned long flags;
+        struct pwm_omap_dmtimer_chip *omap = dev_id;
+
+	spin_lock_irqsave(&omap->lock, flags);
+
+	l = omap->pdata->read_status(omap->dm_timer);
+	if (l & OMAP_TIMER_INT_CAPTURE) {
+		if (!omap->width && omap->ev_cnt == 1) {
+			omap->pdata->read_capture(omap->dm_timer, &c1, &c2);
+			omap->width = pwm_omap_dmtimer_get_width(omap, c1, c2);
+			wake_up(&omap->wait);
+		}
+		omap->ev_cnt++;
+	}
+	/* TODO: handle overflow as well
+	if (l & OMAP_TIMER_INT_OVERFLOW)
+		overflow++;
+	*/
+	omap->pdata->write_status(omap->dm_timer, l);
+
+	spin_unlock_irqrestore(&omap->lock, flags);
+
+	return IRQ_HANDLED;
+}
+
 static const struct pwm_ops pwm_omap_dmtimer_ops = {
+	.capture = pwm_omap_dmtimer_capture,
 	.enable	= pwm_omap_dmtimer_enable,
 	.disable = pwm_omap_dmtimer_disable,
 	.config	= pwm_omap_dmtimer_config,
@@ -349,7 +465,18 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
 	omap->chip.of_xlate = of_pwm_xlate_with_flags;
 	omap->chip.of_pwm_n_cells = 3;
 
+	spin_lock_init(&omap->lock);
 	mutex_init(&omap->mutex);
+	init_waitqueue_head(&omap->wait);
+
+	ret = omap->pdata->get_irq(omap->dm_timer);
+	if (ret < 0)
+		goto free_dm_timer;
+
+	ret = devm_request_irq(&pdev->dev, ret, pwm_omap_dmtimer_irq, 0,
+				"event_capture", omap);
+	if (ret)
+		goto free_dm_timer;
 
 	ret = pwmchip_add(&omap->chip);
 	if (ret < 0) {
Signature · 1 line
2.16.1
#2 lore raw

PATCH 1/6 clocksource: timer-ti-dm: Make unexported functions static

In reply to Ladislav Michl
Quoted 3 lines · Ladislav Michl

As dmtimer no longer exports functions, make those previously exported static (this requires few functions to be moved around as their prototypes were deleted).

Looks like this one fails to build with omap1_defconfig:

drivers/clocksource/timer-ti-dm.c:935:14: error:
'omap_dm_timer_get_fclk' undeclared here

Other than that the first three patches seem like nice clean-up :)

Regards,

Tony

#3 lore raw

PATCH 1/6 clocksource: timer-ti-dm: Make unexported functions static

Quoted 9 lines · Tony Lindgren
Quoted 3 lines · Ladislav Michl

As dmtimer no longer exports functions, make those previously exported static (this requires few functions to be moved around as their prototypes were deleted).

Looks like this one fails to build with omap1_defconfig:

drivers/clocksource/timer-ti-dm.c:935:14: error:
'omap_dm_timer_get_fclk' undeclared here

Umm, it compiled fine on top of previous versions, so I didn't bother to retest. I'm sorry about it.

Quoted 2 lines

Other than that the first three patches seem like nice clean-up :)

So are you okay with sending those separately as cleanup with above issue fixed?

But to be honest, I'm more interested how to do the last two patches right ;-)

Quoted 3 lines

Regards,

Tony

#4 lore raw

PATCH 1/6 clocksource: timer-ti-dm: Make unexported functions static

Quoted 11 lines · Ladislav Michl
Quoted 9 lines · Tony Lindgren
Quoted 3 lines · Ladislav Michl

As dmtimer no longer exports functions, make those previously exported static (this requires few functions to be moved around as their prototypes were deleted).

Looks like this one fails to build with omap1_defconfig:

drivers/clocksource/timer-ti-dm.c:935:14: error:
'omap_dm_timer_get_fclk' undeclared here

Quoted 8 lines

Umm, it compiled fine on top of previous versions, so I didn't bother to retest. I'm sorry about it.

Quoted 2 lines

Other than that the first three patches seem like nice clean-up :)

So are you okay with sending those separately as cleanup with above issue fixed?

Yeah seems like those first three are suitable for applying on top of the patches in omap-for-v4.17/timer :)

Quoted 2 lines

But to be honest, I'm more interested how to do the last two patches right ;-)

Yeah well if patch 4 can be sent separately as a fix, then send that separately to Thierry?

Then you're just left with the pending pwm changes that still need work it seems.

Regards,

Tony

#5 lore raw

PATCH 1/6 clocksource: timer-ti-dm: Make unexported functions static

Quoted 15 lines · Tony Lindgren
Quoted 14 lines · Ladislav Michl
Quoted 9 lines · Tony Lindgren
Quoted 3 lines · Ladislav Michl

As dmtimer no longer exports functions, make those previously exported static (this requires few functions to be moved around as their prototypes were deleted).

Looks like this one fails to build with omap1_defconfig:

drivers/clocksource/timer-ti-dm.c:935:14: error:
'omap_dm_timer_get_fclk' undeclared here

Umm, it compiled fine on top of previous versions, so I didn't bother to retest. I'm sorry about it.

Quoted 8 lines
Quoted 5 lines
Quoted 2 lines

Other than that the first three patches seem like nice clean-up :)

So are you okay with sending those separately as cleanup with above issue fixed?

Yeah seems like those first three are suitable for applying on top of the patches in omap-for-v4.17/timer :)

I've now applied your v2 of patch 1 and patches 2 and 3 of this series into omap-for-v4.17/timer.

Thanks,

Tony

#9 lore raw

PATCH 4/6 pwm: pwm-omap-dmtimer: Fix frequency when using prescaler

In reply to Ladislav Michl
Quoted 9 lines · Ladislav Michl

Prescaler setting is currently not taken into account. Fix that by introducing freq member variable and initialize it at device probe time. This also avoids frequency recomputing at each pwm configure time.

---
 drivers/pwm/pwm-omap-dmtimer.c | 93 +++++++++++++++++++++++++-----------------
 1 file changed, 55 insertions(+), 38 deletions(-)

Applied, thanks.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180327/ab6ece91/attachment.sig>

#10 lore raw

PATCH 4/6 pwm: pwm-omap-dmtimer: Fix frequency when using prescaler

Quoted 6 lines · Thierry Reding
Quoted 5 lines · Ladislav Michl

Prescaler setting is currently not taken into account. Fix that by introducing freq member variable and initialize it at device probe time. This also avoids frequency recomputing at each pwm configure time.

Quoted 6 lines
Quoted 4 lines
---
 drivers/pwm/pwm-omap-dmtimer.c | 93 +++++++++++++++++++++++++-----------------
 1 file changed, 55 insertions(+), 38 deletions(-)

Applied, thanks.

Actually, that was a little premature. It seems like this conflicts with a patch series by Keerthy that Tony merged into his tree and that you've based this on.

I think it'd be easiest if Tony merged this through the TI tree, or we wait until v4.17-rc1 to resolve the dependency. Given how late we are in the release cycle, I think it'd have to be the latter.

Tony, if you think you can find a way to still take this in for v4.17-rc1, feel free to do so:

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180328/c2b783c6/attachment.sig>

#11 lore raw

PATCH 4/6 pwm: pwm-omap-dmtimer: Fix frequency when using prescaler

Quoted 14 lines · Thierry Reding
Quoted 6 lines · Thierry Reding
Quoted 5 lines · Ladislav Michl

Prescaler setting is currently not taken into account. Fix that by introducing freq member variable and initialize it at device probe time. This also avoids frequency recomputing at each pwm configure time.

Quoted 6 lines
Quoted 4 lines
---
 drivers/pwm/pwm-omap-dmtimer.c | 93 +++++++++++++++++++++++++-----------------
 1 file changed, 55 insertions(+), 38 deletions(-)

Applied, thanks.

Quoted 7 lines

Actually, that was a little premature. It seems like this conflicts with a patch series by Keerthy that Tony merged into his tree and that you've based this on.

I think it'd be easiest if Tony merged this through the TI tree, or we wait until v4.17-rc1 to resolve the dependency. Given how late we are in the release cycle, I think it'd have to be the latter.

Sorry about the extra hassle caused by the timer move to drivers.

Quoted 4 lines

Tony, if you think you can find a way to still take this in for v4.17-rc1, feel free to do so:

I pretty much only apply fixes after -rc6. So let's wait for the dependencies to clear at this point. This seems like a "fix for a feature that never worked" so might be hard to justify it as a fix :)

Ladis, can you please resend the pending patches again to Thierry after v4.17-rc? Then Thierry can queue it as a fix or for v4.18.

Regards,

Tony

#12 lore raw

PATCH 4/6 pwm: pwm-omap-dmtimer: Fix frequency when using prescaler

Quoted 28 lines · Tony Lindgren
Quoted 14 lines · Thierry Reding
Quoted 6 lines · Thierry Reding
Quoted 5 lines · Ladislav Michl

Prescaler setting is currently not taken into account. Fix that by introducing freq member variable and initialize it at device probe time. This also avoids frequency recomputing at each pwm configure time.

Quoted 6 lines
Quoted 4 lines
---
 drivers/pwm/pwm-omap-dmtimer.c | 93 +++++++++++++++++++++++++-----------------
 1 file changed, 55 insertions(+), 38 deletions(-)

Applied, thanks.

Quoted 7 lines

Actually, that was a little premature. It seems like this conflicts with a patch series by Keerthy that Tony merged into his tree and that you've based this on.

I think it'd be easiest if Tony merged this through the TI tree, or we wait until v4.17-rc1 to resolve the dependency. Given how late we are in the release cycle, I think it'd have to be the latter.

Sorry about the extra hassle caused by the timer move to drivers.

Quoted 3 lines

Tony, if you think you can find a way to still take this in for v4.17-rc1, feel free to do so:

Quoted 6 lines
Quoted 1 line

I pretty much only apply fixes after -rc6. So let's wait for the dependencies to clear at this point. This seems like a "fix for a feature that never worked" so might be hard to justify it as a fix :)

Well, DT bindings already contain prescaler, so technically it is a fix which also optimizes code a bit ;-) But of course, I can keep this patch localy and resend for 4.18 merge window.

Quoted 3 lines

Ladis, can you please resend the pending patches again to Thierry after v4.17-rc? Then Thierry can queue it as a fix or for v4.18.

In fact, there is the only one patch ready to be applied - this one - and The others (event capture) needs to be yet sorted out. Unfortunately I do not have time for that at the moment.

Best regards,
ladis