linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/5] Add capture functionality to OMAP pwm driver
@ 2018-01-08 15:39 Ladislav Michl
  2018-01-08 15:40 ` [PATCH 1/5] clocksource: timer-dm: Make unexported functions static Ladislav Michl
                   ` (5 more replies)
  0 siblings, 6 replies; 11+ messages in thread
From: Ladislav Michl @ 2018-01-08 15:39 UTC (permalink / raw)
  To: linux-arm-kernel

Folowing patchset is based on Keerthy's "v6 omap: dmtimer: Move driver
out of plat-omap" minus last patch which is here corrected.

Keerthy, feel free to pick cleanup/bugfix patches into your serie
if you find it usefull.

Tony, I wanted to do something easy to understand as a base for
event capture interrupt, but either I do not understand hardware,
or it indeed cannot do pulse capture.

Please see comments in the last patch in the serie.

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

 drivers/clocksource/timer-dm.c             | 269 +++++++++++++++++------------
 drivers/pwm/pwm-omap-dmtimer.c             | 200 +++++++++++++++++----
 include/clocksource/dmtimer.h              |  24 ---
 include/linux/platform_data/dmtimer-omap.h |   8 +
 4 files changed, 334 insertions(+), 167 deletions(-)

-- 
2.15.1

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 1/5] clocksource: timer-dm: Make unexported functions static
  2018-01-08 15:39 [PATCH 0/5] Add capture functionality to OMAP pwm driver Ladislav Michl
@ 2018-01-08 15:40 ` Ladislav Michl
  2018-01-08 15:41 ` [PATCH 2/5] clocksource: timer-dm: Check prescaler value Ladislav Michl
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 11+ messages in thread
From: Ladislav Michl @ 2018-01-08 15:40 UTC (permalink / raw)
  To: linux-arm-kernel

As dmtimer no longer exports functions, make those previously
exported static.

Signed-off-by: Ladislav Michl <ladis@linux-mips.org>

diff --git a/drivers/clocksource/timer-dm.c b/drivers/clocksource/timer-dm.c
index 60db1734ea3b..43531eecbe54 100644
--- a/drivers/clocksource/timer-dm.c
+++ b/drivers/clocksource/timer-dm.c
@@ -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;
 
@@ -582,8 +582,8 @@ 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;
 
@@ -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__);
diff --git a/include/clocksource/dmtimer.h b/include/clocksource/dmtimer.h
index 862ad62dab9d..ce596172a93a 100644
--- a/include/clocksource/dmtimer.h
+++ b/include/clocksource/dmtimer.h
@@ -125,37 +125,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);
-struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer);
 
 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);
 
-- 
2.15.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 2/5] clocksource: timer-dm: Check prescaler value
  2018-01-08 15:39 [PATCH 0/5] Add capture functionality to OMAP pwm driver Ladislav Michl
  2018-01-08 15:40 ` [PATCH 1/5] clocksource: timer-dm: Make unexported functions static Ladislav Michl
@ 2018-01-08 15:41 ` Ladislav Michl
  2018-01-08 15:41 ` [PATCH 3/5] pwm: pwm-omap-dmtimer: Fix frequency when using prescaler Ladislav Michl
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 11+ messages in thread
From: Ladislav Michl @ 2018-01-08 15:41 UTC (permalink / raw)
  To: linux-arm-kernel

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

Signed-off-by: Ladislav Michl <ladis@linux-mips.org>

diff --git a/drivers/clocksource/timer-dm.c b/drivers/clocksource/timer-dm.c
index 43531eecbe54..bde1014308f9 100644
--- a/drivers/clocksource/timer-dm.c
+++ b/drivers/clocksource/timer-dm.c
@@ -663,13 +663,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;
 	}
-- 
2.15.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 3/5] pwm: pwm-omap-dmtimer: Fix frequency when using prescaler
  2018-01-08 15:39 [PATCH 0/5] Add capture functionality to OMAP pwm driver Ladislav Michl
  2018-01-08 15:40 ` [PATCH 1/5] clocksource: timer-dm: Make unexported functions static Ladislav Michl
  2018-01-08 15:41 ` [PATCH 2/5] clocksource: timer-dm: Check prescaler value Ladislav Michl
@ 2018-01-08 15:41 ` Ladislav Michl
  2018-01-08 15:42 ` [PATCH 4/5] clocksource: timer-dm: Add event capture Ladislav Michl
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 11+ messages in thread
From: Ladislav Michl @ 2018-01-08 15:41 UTC (permalink / raw)
  To: linux-arm-kernel

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.

Signed-off-by: Ladislav Michl <ladis@linux-mips.org>

diff --git a/drivers/pwm/pwm-omap-dmtimer.c b/drivers/pwm/pwm-omap-dmtimer.c
index 3b27aff585b7..ee1cd92b1744 100644
--- a/drivers/pwm/pwm-omap-dmtimer.c
+++ b/drivers/pwm/pwm-omap-dmtimer.c
@@ -40,6 +40,7 @@ struct pwm_omap_dmtimer_chip {
 	pwm_omap_dmtimer *dm_timer;
 	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;
 	struct omap_dm_timer_ops *pdata;
 	pwm_omap_dmtimer *dm_timer;
+	struct clk *fclk;
 	u32 v;
 	int status;
 
@@ -311,12 +299,37 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
 	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);
-
 	/* 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)) {
+		status = omap->pdata->set_source(omap->dm_timer, v);
+		if (status) {
+			dev_err(&pdev->dev, "invalid clock-source\n");
+			return status;
+		}
+	}
+
+	fclk = omap->pdata->get_fclk(omap->dm_timer);
+	if (!fclk) {
+		dev_err(&pdev->dev, "invalid fclk\n");
+		return -EINVAL;
+	}
+
+	omap->freq = clk_get_rate(fclk);
+	if (!omap->freq) {
+		dev_err(&pdev->dev, "invalid fclk rate\n");
+		return -EINVAL;
+	}
+
+	if (!of_property_read_u32(pdev->dev.of_node, "ti,prescaler", &v)) {
+		status = omap->pdata->set_prescaler(omap->dm_timer, v);
+		if (status) {
+			dev_err(&pdev->dev, "invalid prescaler\n");
+			return status;
+		}
+		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;
-- 
2.15.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 4/5] clocksource: timer-dm: Add event capture
  2018-01-08 15:39 [PATCH 0/5] Add capture functionality to OMAP pwm driver Ladislav Michl
                   ` (2 preceding siblings ...)
  2018-01-08 15:41 ` [PATCH 3/5] pwm: pwm-omap-dmtimer: Fix frequency when using prescaler Ladislav Michl
@ 2018-01-08 15:42 ` Ladislav Michl
  2018-01-08 21:51 ` [PATCH 0/5] Add capture functionality to OMAP pwm driver Tony Lindgren
       [not found] ` <20180108154336.GE4077@lenoch>
  5 siblings, 0 replies; 11+ messages in thread
From: Ladislav Michl @ 2018-01-08 15:42 UTC (permalink / raw)
  To: linux-arm-kernel

Implement event capture functions.

Signed-off-by: Ladislav Michl <ladis@linux-mips.org>

diff --git a/drivers/clocksource/timer-dm.c b/drivers/clocksource/timer-dm.c
index bde1014308f9..dbf2b1f6a941 100644
--- a/drivers/clocksource/timer-dm.c
+++ b/drivers/clocksource/timer-dm.c
@@ -633,6 +633,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)
 {
@@ -791,6 +815,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[];
 
 /**
@@ -939,11 +979,14 @@ 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,
 };
diff --git a/include/linux/platform_data/dmtimer-omap.h b/include/linux/platform_data/dmtimer-omap.h
index a3e17945a0e9..ad247d45bc08 100644
--- a/include/linux/platform_data/dmtimer-omap.h
+++ b/include/linux/platform_data/dmtimer-omap.h
@@ -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);
-- 
2.15.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 0/5] Add capture functionality to OMAP pwm driver
  2018-01-08 15:39 [PATCH 0/5] Add capture functionality to OMAP pwm driver Ladislav Michl
                   ` (3 preceding siblings ...)
  2018-01-08 15:42 ` [PATCH 4/5] clocksource: timer-dm: Add event capture Ladislav Michl
@ 2018-01-08 21:51 ` Tony Lindgren
  2018-01-08 21:57   ` Ladislav Michl
       [not found] ` <20180108154336.GE4077@lenoch>
  5 siblings, 1 reply; 11+ messages in thread
From: Tony Lindgren @ 2018-01-08 21:51 UTC (permalink / raw)
  To: linux-arm-kernel

* Ladislav Michl <ladis@linux-mips.org> [180108 15:42]:
> Tony, I wanted to do something easy to understand as a base for
> event capture interrupt, but either I do not understand hardware,
> or it indeed cannot do pulse capture.

Hmm OK. Presumably it works as it's been around for a long time,
I thought any edge trigger will just sample the current counter
value and that's it..

Regards,

Tony

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 0/5] Add capture functionality to OMAP pwm driver
  2018-01-08 21:51 ` [PATCH 0/5] Add capture functionality to OMAP pwm driver Tony Lindgren
@ 2018-01-08 21:57   ` Ladislav Michl
  0 siblings, 0 replies; 11+ messages in thread
From: Ladislav Michl @ 2018-01-08 21:57 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jan 08, 2018 at 01:51:23PM -0800, Tony Lindgren wrote:
> * Ladislav Michl <ladis@linux-mips.org> [180108 15:42]:
> > Tony, I wanted to do something easy to understand as a base for
> > event capture interrupt, but either I do not understand hardware,
> > or it indeed cannot do pulse capture.
> 
> Hmm OK. Presumably it works as it's been around for a long time,
> I thought any edge trigger will just sample the current counter
> value and that's it..

Yes, indeed, _any_ edge will just sample the current counter value.
So what can hardware say about duty cycle of this signal?
  +-+        +-+
__| |________| |___

Depending time capture was started it will either trigger on first
falling or first rising edge.


	ladis

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [RFC 5/5] pwm: pwm-omap-dmtimer: Add capture functionality
       [not found] ` <20180108154336.GE4077@lenoch>
@ 2018-01-08 21:59   ` Tony Lindgren
  2018-01-08 22:06     ` Ladislav Michl
  0 siblings, 1 reply; 11+ messages in thread
From: Tony Lindgren @ 2018-01-08 21:59 UTC (permalink / raw)
  To: linux-arm-kernel

* Ladislav Michl <ladis@linux-mips.org> [180108 15:46]:
> Here it seems hardware can capture both edges, but I do not see a way
> how to tell it I want start from either low to high or high to low
> transition. Clues?

At least dm3730 TRM documents TCM bits [9:8] for TCLR, but you
probably know that already..

If you're having hard time getting things starting, maybe something
like this helps:

stop timer in TCLR register
configure timer in TCLR
write some value to TLDR, maybe 0?
set ST bit in TCLR to start

Regards,

Tony

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [RFC 5/5] pwm: pwm-omap-dmtimer: Add capture functionality
  2018-01-08 21:59   ` [RFC 5/5] pwm: pwm-omap-dmtimer: Add capture functionality Tony Lindgren
@ 2018-01-08 22:06     ` Ladislav Michl
  2018-01-08 22:13       ` Tony Lindgren
  0 siblings, 1 reply; 11+ messages in thread
From: Ladislav Michl @ 2018-01-08 22:06 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jan 08, 2018 at 01:59:31PM -0800, Tony Lindgren wrote:
> * Ladislav Michl <ladis@linux-mips.org> [180108 15:46]:
> > Here it seems hardware can capture both edges, but I do not see a way
> > how to tell it I want start from either low to high or high to low
> > transition. Clues?
> 
> At least dm3730 TRM documents TCM bits [9:8] for TCLR, but you
> probably know that already..
> 
> If you're having hard time getting things starting, maybe something
> like this helps:
> 
> stop timer in TCLR register
> configure timer in TCLR
> write some value to TLDR, maybe 0?
> set ST bit in TCLR to start

Let me clarify it a bit more. I have no problem starting timer and capture
events. I just didn't find a way how to tell hardware I want to start
with for example rising edge, so rising edge goes to TCAR1 and failing edge
to TCAR2. Substracting those gives pulse width.

	ladis

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [RFC 5/5] pwm: pwm-omap-dmtimer: Add capture functionality
  2018-01-08 22:06     ` Ladislav Michl
@ 2018-01-08 22:13       ` Tony Lindgren
  2018-01-08 22:26         ` Ladislav Michl
  0 siblings, 1 reply; 11+ messages in thread
From: Tony Lindgren @ 2018-01-08 22:13 UTC (permalink / raw)
  To: linux-arm-kernel

* Ladislav Michl <ladis@linux-mips.org> [180108 22:09]:
> On Mon, Jan 08, 2018 at 01:59:31PM -0800, Tony Lindgren wrote:
> > * Ladislav Michl <ladis@linux-mips.org> [180108 15:46]:
> > > Here it seems hardware can capture both edges, but I do not see a way
> > > how to tell it I want start from either low to high or high to low
> > > transition. Clues?
> > 
> > At least dm3730 TRM documents TCM bits [9:8] for TCLR, but you
> > probably know that already..
> > 
> > If you're having hard time getting things starting, maybe something
> > like this helps:
> > 
> > stop timer in TCLR register
> > configure timer in TCLR
> > write some value to TLDR, maybe 0?
> > set ST bit in TCLR to start
> 
> Let me clarify it a bit more. I have no problem starting timer and capture
> events. I just didn't find a way how to tell hardware I want to start
> with for example rising edge, so rising edge goes to TCAR1 and failing edge
> to TCAR2. Substracting those gives pulse width.

Oh I see, yeah that would be cool :) Maybe you can first configure
an interrupt to trigger on rising edge, then configure things for
falling edge, then subtract..

Regards,

Tony

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [RFC 5/5] pwm: pwm-omap-dmtimer: Add capture functionality
  2018-01-08 22:13       ` Tony Lindgren
@ 2018-01-08 22:26         ` Ladislav Michl
  0 siblings, 0 replies; 11+ messages in thread
From: Ladislav Michl @ 2018-01-08 22:26 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jan 08, 2018 at 02:13:27PM -0800, Tony Lindgren wrote:
> * Ladislav Michl <ladis@linux-mips.org> [180108 22:09]:
> > On Mon, Jan 08, 2018 at 01:59:31PM -0800, Tony Lindgren wrote:
> > > * Ladislav Michl <ladis@linux-mips.org> [180108 15:46]:
> > > > Here it seems hardware can capture both edges, but I do not see a way
> > > > how to tell it I want start from either low to high or high to low
> > > > transition. Clues?
> > > 
> > > At least dm3730 TRM documents TCM bits [9:8] for TCLR, but you
> > > probably know that already..
> > > 
> > > If you're having hard time getting things starting, maybe something
> > > like this helps:
> > > 
> > > stop timer in TCLR register
> > > configure timer in TCLR
> > > write some value to TLDR, maybe 0?
> > > set ST bit in TCLR to start
> > 
> > Let me clarify it a bit more. I have no problem starting timer and capture
> > events. I just didn't find a way how to tell hardware I want to start
> > with for example rising edge, so rising edge goes to TCAR1 and failing edge
> > to TCAR2. Substracting those gives pulse width.
> 
> Oh I see, yeah that would be cool :) Maybe you can first configure
> an interrupt to trigger on rising edge, then configure things for
> falling edge, then subtract..

That will work only for very long periods. I did test where value captured
into TCAR was compared to value read from TCRR. Sometimes those differ by
few hundreds microseconds...

I started this work to overcome GPIO edge interrupts latency, but so far
I'm a bit dissapointed.

(also please read the code, reconfiguration is done to get period and
duty cycle - but in case of duty cycle it is not clear whenever we are
measuring pulse or space length)

	ladis

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2018-01-08 22:26 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-01-08 15:39 [PATCH 0/5] Add capture functionality to OMAP pwm driver Ladislav Michl
2018-01-08 15:40 ` [PATCH 1/5] clocksource: timer-dm: Make unexported functions static Ladislav Michl
2018-01-08 15:41 ` [PATCH 2/5] clocksource: timer-dm: Check prescaler value Ladislav Michl
2018-01-08 15:41 ` [PATCH 3/5] pwm: pwm-omap-dmtimer: Fix frequency when using prescaler Ladislav Michl
2018-01-08 15:42 ` [PATCH 4/5] clocksource: timer-dm: Add event capture Ladislav Michl
2018-01-08 21:51 ` [PATCH 0/5] Add capture functionality to OMAP pwm driver Tony Lindgren
2018-01-08 21:57   ` Ladislav Michl
     [not found] ` <20180108154336.GE4077@lenoch>
2018-01-08 21:59   ` [RFC 5/5] pwm: pwm-omap-dmtimer: Add capture functionality Tony Lindgren
2018-01-08 22:06     ` Ladislav Michl
2018-01-08 22:13       ` Tony Lindgren
2018-01-08 22:26         ` Ladislav Michl

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).