Skip to contentSkip to conversation

Add support for Thermal and CMT

PATCH New Biju Das 2 participants 14 messages May 30, 2018 – May 31, 2018

Subsystems (4)
lore
Share & tools
lore

Biju Das

author
#0 lore raw

v2 cover Add support for Thermal and CMT

This patch series add support for thermal and CMT.

This patchset is rebased on top of the previous patch set

0001-pinctrl-sh-pfc-r8a7791-Add-can_clk-function.patch to 0058-thermal-rcar_thermal-don-t-open-code-of_device_get_m.patch

V1-->V2
* Incorporated thermal related review comments
* Added CMT support

Biju Das (2):
dt-bindings: thermal: rcar: Add device tree support for r8a7743
ARM: dts: r8a7743: Add thermal device to DT

Bui Duc Phuc (1):
thermal: rcar_thermal: don't call thermal_zone_device_unregister when
USE_OF_THERMAL

Dirk Behme (1):
thermal: rcar_thermal: Fix priv->zone error handling

Eduardo Valentin (1):
thermal: convert rcar_thermal to use
devm_thermal_zone_of_sensor_register

Fabrizio Castro (2):
ARM: dts: r8a7743: Add CMT SoC specific support
ARM: dts: iwg20m: Enable cmt0

Kuninori Morimoto (1):
thermal: rcar-thermal: enable hwmon when
thermal_zone_of_sensor_register is used

Laxman Dewangan (1):
thermal: of-thermal: Add devm version of
thermal_zone_of_sensor_register

Nicolai Stange (2):
clocksource: sh_cmt: Compute rate before registration again clockevents/drivers/sh_cmt: Set ->min_delta_ticks and

    ->max_delta_ticks
 .../devicetree/bindings/thermal/rcar-thermal.txt   |  1 +
 arch/arm/boot/dts/r8a7743-iwg20m.dtsi              |  4 ++
 arch/arm/boot/dts/r8a7743.dtsi                     | 67 ++++++++++++++++++
 drivers/clocksource/sh_cmt.c                       | 47 +++++++------
 drivers/thermal/of-thermal.c                       | 81 ++++++++++++++++++++++
 drivers/thermal/rcar_thermal.c                     | 26 +++++--
 include/linux/thermal.h                            | 18 +++++
 7 files changed, 220 insertions(+), 24 deletions(-)
Signature · 1 line
2.7.4
author
#1 lore raw

PATCH v2 1/11 thermal: of-thermal: Add devm version of thermal_zone_of_sensor_register

From: Laxman Dewangan <[email protected]>

Add resource managed version of thermal_zone_of_sensor_register() and thermal_zone_of_sensor_unregister().

This helps in reducing the code size in error path, remove of driver remove callbacks and making proper sequence for deallocations.

(cherry picked from commit e498b4984db82b4ba3ceea7dba813222a31e9c2e)
---
 drivers/thermal/of-thermal.c | 81 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/thermal.h      | 18 ++++++++++
 2 files changed, 99 insertions(+)
drivers/thermal/of-thermal.c +81 -0
index be4eedc..5a515f8 100644
@@ -559,6 +559,87 @@ void thermal_zone_of_sensor_unregister(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(thermal_zone_of_sensor_unregister);
 
+static void devm_thermal_zone_of_sensor_release(struct device *dev, void *res)
+{
+	thermal_zone_of_sensor_unregister(dev,
+					  *(struct thermal_zone_device **)res);
+}
+
+static int devm_thermal_zone_of_sensor_match(struct device *dev, void *res,
+					     void *data)
+{
+	struct thermal_zone_device **r = res;
+
+	if (WARN_ON(!r || !*r))
+		return 0;
+
+	return *r == data;
+}
+
+/**
+ * devm_thermal_zone_of_sensor_register - Resource managed version of
+ *				thermal_zone_of_sensor_register()
+ * @dev: a valid struct device pointer of a sensor device. Must contain
+ *       a valid .of_node, for the sensor node.
+ * @sensor_id: a sensor identifier, in case the sensor IP has more
+ *	       than one sensors
+ * @data: a private pointer (owned by the caller) that will be passed
+ *	  back, when a temperature reading is needed.
+ * @ops: struct thermal_zone_of_device_ops *. Must contain at least .get_temp.
+ *
+ * Refer thermal_zone_of_sensor_register() for more details.
+ *
+ * Return: On success returns a valid struct thermal_zone_device,
+ * otherwise, it returns a corresponding ERR_PTR(). Caller must
+ * check the return value with help of IS_ERR() helper.
+ * Registered hermal_zone_device device will automatically be
+ * released when device is unbounded.
+ */
+struct thermal_zone_device *devm_thermal_zone_of_sensor_register(
+	struct device *dev, int sensor_id,
+	void *data, const struct thermal_zone_of_device_ops *ops)
+{
+	struct thermal_zone_device **ptr, *tzd;
+
+	ptr = devres_alloc(devm_thermal_zone_of_sensor_release, sizeof(*ptr),
+			   GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	tzd = thermal_zone_of_sensor_register(dev, sensor_id, data, ops);
+	if (IS_ERR(tzd)) {
+		devres_free(ptr);
+		return tzd;
+	}
+
+	*ptr = tzd;
+	devres_add(dev, ptr);
+
+	return tzd;
+}
+EXPORT_SYMBOL_GPL(devm_thermal_zone_of_sensor_register);
+
+/**
+ * devm_thermal_zone_of_sensor_unregister - Resource managed version of
+ *				thermal_zone_of_sensor_unregister().
+ * @dev: Device for which which resource was allocated.
+ * @tzd: a pointer to struct thermal_zone_device where the sensor is registered.
+ *
+ * This function removes the sensor callbacks and private data from the
+ * thermal zone device registered with devm_thermal_zone_of_sensor_register()
+ * API. It will also silent the zone by remove the .get_temp() and .get_trend()
+ * thermal zone device callbacks.
+ * Normally this function will not need to be called and the resource
+ * management code will ensure that the resource is freed.
+ */
+void devm_thermal_zone_of_sensor_unregister(struct device *dev,
+					    struct thermal_zone_device *tzd)
+{
+	WARN_ON(devres_release(dev, devm_thermal_zone_of_sensor_release,
+			       devm_thermal_zone_of_sensor_match, tzd));
+}
+EXPORT_SYMBOL_GPL(devm_thermal_zone_of_sensor_unregister);
+
 /***   functions parsing device tree nodes   ***/
 
 /**
include/linux/thermal.h +18 -0
index 4a849f1..a55d052 100644
@@ -364,6 +364,11 @@ thermal_zone_of_sensor_register(struct device *dev, int id, void *data,
 				const struct thermal_zone_of_device_ops *ops);
 void thermal_zone_of_sensor_unregister(struct device *dev,
 				       struct thermal_zone_device *tz);
+struct thermal_zone_device *devm_thermal_zone_of_sensor_register(
+		struct device *dev, int id, void *data,
+		const struct thermal_zone_of_device_ops *ops);
+void devm_thermal_zone_of_sensor_unregister(struct device *dev,
+					    struct thermal_zone_device *tz);
 #else
 static inline struct thermal_zone_device *
 thermal_zone_of_sensor_register(struct device *dev, int id, void *data,
@@ -378,6 +383,19 @@ void thermal_zone_of_sensor_unregister(struct device *dev,
 {
 }
 
+static inline struct thermal_zone_device *devm_thermal_zone_of_sensor_register(
+		struct device *dev, int id, void *data,
+		const struct thermal_zone_of_device_ops *ops)
+{
+	return ERR_PTR(-ENODEV);
+}
+
+static inline
+void devm_thermal_zone_of_sensor_unregister(struct device *dev,
+					    struct thermal_zone_device *tz)
+{
+}
+
 #endif
 
 #if IS_ENABLED(CONFIG_THERMAL)
Signature · 1 line
2.7.4
author
#2 lore raw

PATCH v2 2/11 thermal: convert rcar_thermal to use devm_thermal_zone_of_sensor_register

In reply to Biju Das

From: Eduardo Valentin <[email protected]>

This changes the driver to use the devm_ version
of thermal_zone_of_sensor_register and cleans
up the local points and unregister calls.

Cc Zhang Rui <[email protected]>
Cc linux-pm at vger.kernel.org
Cc linux-kernel at vger.kernel.org
(cherry picked from commit 5e325868aa59d3c743aa1c9526f386f30c234cd7)
---
 drivers/thermal/rcar_thermal.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/thermal/rcar_thermal.c +1 -1
index 82daba0..71a3392 100644
@@ -492,7 +492,7 @@ static int rcar_thermal_probe(struct platform_device *pdev)
 			goto error_unregister;
 
 		if (of_data == USE_OF_THERMAL)
-			priv->zone = thermal_zone_of_sensor_register(
+			priv->zone = devm_thermal_zone_of_sensor_register(
 						dev, i, priv,
 						&rcar_thermal_zone_of_ops);
 		else
Signature · 1 line
2.7.4
author
#3 lore raw

PATCH v2 3/11 thermal: rcar_thermal: Fix priv->zone error handling

In reply to Biju Das

From: Dirk Behme <[email protected]>

In case thermal_zone_xxx_register() returns an error, priv->zone isn't NULL any more, but contains the error code.

This is passed to thermal_zone_device_unregister(), then. This checks for priv->zone being NULL, but the error code is != NULL. So it works with the error code as a pointer. Crashing immediately.

To fix this, reset priv->zone to NULL before entering rcar_gen3_thermal_remove().

(cherry picked from commit 87260d3f7aecba9a5fadc6886c338b2a8fccfca9)
---
 drivers/thermal/rcar_thermal.c | 1 +
 1 file changed, 1 insertion(+)
drivers/thermal/rcar_thermal.c +1 -0
index 71a3392..5f81792 100644
@@ -504,6 +504,7 @@ static int rcar_thermal_probe(struct platform_device *pdev)
 		if (IS_ERR(priv->zone)) {
 			dev_err(dev, "can't register thermal zone\n");
 			ret = PTR_ERR(priv->zone);
+			priv->zone = NULL;
 			goto error_unregister;
 		}
 
Signature · 1 line
2.7.4
author
#4 lore raw

PATCH v2 4/11 thermal: rcar-thermal: enable hwmon when thermal_zone_of_sensor_register is used

In reply to Biju Das

From: Kuninori Morimoto <[email protected]>

rcar-thermal is supporting both thermal_zone_of_sensor_register() and thermal_zone_device_register(). But thermal_zone_of_sensor_register() doesn't enable hwmon as default.
This patch enables it to keep compatibility

(cherry picked from commit 64a411e8042ed00057658000126fd9f2b4105bdd)
---
 drivers/thermal/rcar_thermal.c | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)
drivers/thermal/rcar_thermal.c +18 -2
index 5f81792..4048003 100644
@@ -31,6 +31,8 @@
 #include <linux/spinlock.h>
 #include <linux/thermal.h>
 
+#include "thermal_hwmon.h"
+
 #define IDLE_INTERVAL	5000
 
 #define COMMON_STR	0x00
@@ -75,6 +77,8 @@ struct rcar_thermal_priv {
 #define rcar_priv_to_dev(priv)		((priv)->common->dev)
 #define rcar_has_irq_support(priv)	((priv)->common->base)
 #define rcar_id_to_shift(priv)		((priv)->id * 8)
+#define rcar_of_data(dev)		((unsigned long)of_device_get_match_data(dev))
+#define rcar_use_of_thermal(dev)	(rcar_of_data(dev) == USE_OF_THERMAL)
 
 #define USE_OF_THERMAL	1
 static const struct of_device_id rcar_thermal_dt_ids[] = {
@@ -416,6 +420,8 @@ static int rcar_thermal_remove(struct platform_device *pdev)
 	rcar_thermal_for_each_priv(priv, common) {
 		rcar_thermal_irq_disable(priv);
 		thermal_zone_device_unregister(priv->zone);
+		if (rcar_use_of_thermal(dev))
+			thermal_remove_hwmon_sysfs(priv->zone);
 	}
 
 	pm_runtime_put(dev);
@@ -430,7 +436,6 @@ static int rcar_thermal_probe(struct platform_device *pdev)
 	struct rcar_thermal_priv *priv;
 	struct device *dev = &pdev->dev;
 	struct resource *res, *irq;
-	unsigned long of_data = (unsigned long)of_device_get_match_data(dev);
 	int mres = 0;
 	int i;
 	int ret = -ENODEV;
@@ -491,7 +496,7 @@ static int rcar_thermal_probe(struct platform_device *pdev)
 		if (ret < 0)
 			goto error_unregister;
 
-		if (of_data == USE_OF_THERMAL)
+		if (rcar_use_of_thermal(dev))
 			priv->zone = devm_thermal_zone_of_sensor_register(
 						dev, i, priv,
 						&rcar_thermal_zone_of_ops);
@@ -508,6 +513,17 @@ static int rcar_thermal_probe(struct platform_device *pdev)
 			goto error_unregister;
 		}
 
+		if (rcar_use_of_thermal(dev)) {
+			/*
+			 * thermal_zone doesn't enable hwmon as default,
+			 * but, enable it here to keep compatible
+			 */
+			priv->zone->tzp->no_hwmon = false;
+			ret = thermal_add_hwmon_sysfs(priv->zone);
+			if (ret)
+				goto error_unregister;
+		}
+
 		rcar_thermal_irq_enable(priv);
 
 		list_move_tail(&priv->list, &common->head);
Signature · 1 line
2.7.4
author
#5 lore raw

PATCH v2 5/11 thermal: rcar_thermal: don't call thermal_zone_device_unregister when USE_OF_THERMAL

In reply to Biju Das

From: Bui Duc Phuc <[email protected]>

devm_thermal_zone_of_sensor_register() case doesn't need to call thermal_zone_device_unregister().
Otherwise, rcar-thermal can't register thermal zone again after rebind. This patch fixes it.

(cherry picked from commit d4b23c5c434a7af053782cc0f9eebee51ec71bb2)
---
 drivers/thermal/rcar_thermal.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/thermal/rcar_thermal.c +2 -1
index 4048003..e895830 100644
@@ -419,9 +419,10 @@ static int rcar_thermal_remove(struct platform_device *pdev)
 
 	rcar_thermal_for_each_priv(priv, common) {
 		rcar_thermal_irq_disable(priv);
-		thermal_zone_device_unregister(priv->zone);
 		if (rcar_use_of_thermal(dev))
 			thermal_remove_hwmon_sysfs(priv->zone);
+		else
+			thermal_zone_device_unregister(priv->zone);
 	}
 
 	pm_runtime_put(dev);
Signature · 1 line
2.7.4
author
#6 lore raw

PATCH v2 6/11 dt-bindings: thermal: rcar: Add device tree support for r8a7743

In reply to Biju Das

Add thermal sensor support for r8a7743 SoC. The Renesas RZ/G1M (r8a7743) thermal sensor module is identical to the R-Car Gen2 family.

No driver change is needed due to the fallback compatible value "renesas,rcar-gen2-thermal".

---
 Documentation/devicetree/bindings/thermal/rcar-thermal.txt | 1 +
 1 file changed, 1 insertion(+)
Documentation/devicetree/bindings/thermal/rcar-thermal.txt +1 -0
index e5ee3f1..689e7e8 100644
@@ -6,6 +6,7 @@ Required properties:
 			   "renesas,rcar-thermal" (without thermal-zone) as fallback.
 			  Examples with soctypes are:
 			    - "renesas,thermal-r8a73a4" (R-Mobile APE6)
+			    - "renesas,thermal-r8a7743" (RZ/G1M)
 			    - "renesas,thermal-r8a7779" (R-Car H1)
 			    - "renesas,thermal-r8a7790" (R-Car H2)
 			    - "renesas,thermal-r8a7791" (R-Car M2-W)
Signature · 1 line
2.7.4
author
#7 lore raw

PATCH v2 7/11 ARM: dts: r8a7743: Add thermal device to DT

In reply to Biju Das

This patch instantiates the thermal sensor module with thermal-zone support.

This patch is based on the commit cac68a56e34b
("ARM: dts: r8a7791: enable to use thermal-zone") by Kuninori Morimoto.

(cherry picked from commit 6c76b4f7d89e89f0ae405dfc7a64c6d2b5d02813)

(updated clocks and power-domains property.removed resets property)

---
 arch/arm/boot/dts/r8a7743.dtsi | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)
arch/arm/boot/dts/r8a7743.dtsi +31 -0
index 17be22c..1d9adcc 100644
@@ -237,6 +237,37 @@
 			power-domains = <&cpg_clocks>;
 		};
 
+		thermal: thermal at e61f0000 {
+			compatible = "renesas,thermal-r8a7743",
+				     "renesas,rcar-gen2-thermal",
+				     "renesas,rcar-thermal";
+			reg = <0 0xe61f0000 0 0x10>, <0 0xe61f0100 0 0x38>;
+			interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&mstp5_clks R8A7743_CLK_THERMAL>;
+			power-domains = <&cpg_clocks>;
+			#thermal-sensor-cells = <0>;
+		};
+
+		thermal-zones {
+			cpu_thermal: cpu-thermal {
+				polling-delay-passive = <0>;
+				polling-delay = <0>;
+
+				thermal-sensors = <&thermal>;
+
+				trips {
+					cpu-crit {
+						temperature = <95000>;
+						hysteresis = <0>;
+						type = "critical";
+					};
+				};
+
+				cooling-maps {
+				};
+			};
+		};
+
 		timer {
 			compatible = "arm,armv7-timer";
 			interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) |
Signature · 1 line
2.7.4
#8 lore raw

PATCH v2 7/11 ARM: dts: r8a7743: Add thermal device to DT

Quoted 2 lines · Biju Das

This patch instantiates the thermal sensor module with thermal-zone support.

The thermal-zones node this adds was later moved by commit b9db3affbcdc ("ARM: dts: r8a7743: move timer and thermal-zones nodes out of bus"). Do you think that is worth applying too?

Ben.

Quoted 11 lines

This patch is based on the commit cac68a56e34b
("ARM: dts: r8a7791: enable to use thermal-zone") by Kuninori Morimoto.

(cherry picked from commit 6c76b4f7d89e89f0ae405dfc7a64c6d2b5d02813)

(updated clocks and power-domains property.removed resets property)

[...]

Signature · 4 lines
Ben Hutchings, Software Developer                ?        Codethink Ltd
https://www.codethink.co.uk/                 Dale House, 35 Dale Street
                                     Manchester, M1 2HF, United Kingdom
We respect your privacy.?? See https://www.codethink.co.uk/privacy.html
author
#9 lore raw

PATCH v2 7/11 ARM: dts: r8a7743: Add thermal device to DT

Hello Ben,

Thanks for the feedback.

Quoted 8 lines

-----Original Message-----
From: Ben Hutchings [mailto:ben.hutchings at codethink.co.uk]
Sent: 30 May 2018 19:44
To: Biju Das <[email protected]>
Cc: Chris Paterson <[email protected]>; Fabrizio Castro <[email protected]>; cip-dev at lists.cip-project.org
Subject: Re: [PATCH v2 07/11] ARM: dts: r8a7743: Add thermal device to DT

Quoted 7 lines
Quoted 2 lines · Biju Das

This patch instantiates the thermal sensor module with thermal-zone support.

The thermal-zones node this adds was later moved by commit b9db3affbcdc ("ARM: dts: r8a7743: move timer and thermal-zones nodes out of bus"). Do you think that is worth applying too?

I believe this patch is to fix the "make dtbs W=1" warnings which is not triggered with 4.4 kernel. Other than thermal-zones, we also need to move timer nodes out of bus.
There is another patch in upstream which is for sorting nodes.
I think we can combine this 2 patches at later stage.
What is your thoughts on this?

[>] regards,
Biju

Quoted 11 lines
Quoted 11 lines

This patch is based on the commit cac68a56e34b
("ARM: dts: r8a7791: enable to use thermal-zone") by Kuninori Morimoto.

picked from commit 6c76b4f7d89e89f0ae405dfc7a64c6d2b5d02813) (updated clocks and power-domains property.removed resets property)

Quoted 2 lines

[...]

Renesas Electronics Europe Ltd, Dukes Meadow, Millboard Road, Bourne End, Buckinghamshire, SL8 5FH, UK. Registered in England & Wales under Registered No. 04586709.

author
#10 lore raw

PATCH v2 8/11 clocksource: sh_cmt: Compute rate before registration again

In reply to Biju Das

From: Nicolai Stange <[email protected]>

With the upcoming NTP correction related rate adjustments to be implemented in the clockevents core, the latter needs to get informed about every rate change of a clockevent device made after its registration.

Currently, sh_cmt violates this requirement in that it registers its clockevent device with a dummy rate and sets its final ->mult and ->shift values from its ->set_state_oneshot() and ->set_state_periodic() functions respectively.

This patch moves the setting of the clockevent device's ->mult and ->shift values to before its registration.

Note that there has been some back and forth regarding this question with respect to the clocksource also provided by this driver:
commit f4d7c3565c16 ("clocksource: sh_cmt: compute mult and shift before
registration")
moves the rate determination from the clocksource's ->enable() function to before its registration. OTOH, the later
commit 3593f5fe40a1 ("clocksource: sh_cmt: __clocksource_updatefreq_hz()
update")
basically reverts this, saying
"Without this patch the old code uses clocksource_register() together
with a hack that assumes a never changing clock rate."

However, I checked all current sh_cmt users in arch/sh as well as in arch/arm/mach-shmobile carefully and right now, none of them changes any rate in any clock tree relevant to sh_cmt after their respective time_init(). Since all sh_cmt instances are created after time_init(), none of them should ever observe any clock rate changes.

What's more, both, a clocksource as well as a clockevent device, can immediately get selected for use at their registration and thus, enabled at this point already. So it's probably safer to assume a "never changing clock rate" here.

- Move the struct sh_cmt_channel's ->rate member to struct sh_cmt_device:
it's a property of the underlying clock which is in turn specific to the sh_cmt_device.
- Determine the ->rate value in sh_cmt_setup() at device probing rather than at first usage.
- Set the clockevent device's ->mult and ->shift values right before its registration.
- Although not strictly necessary for the upcoming clockevent core changes, set the clocksource's rate at its registration for consistency.

(cherry picked from commit 890f423b266623e1cfb3a97b864f3e5039bdfbb9)
---
 drivers/clocksource/sh_cmt.c | 45 ++++++++++++++++++++++++--------------------
 1 file changed, 25 insertions(+), 20 deletions(-)
drivers/clocksource/sh_cmt.c +25 -20
index 103c493..3038885 100644
@@ -103,7 +103,6 @@ struct sh_cmt_channel {
 	unsigned long match_value;
 	unsigned long next_match_value;
 	unsigned long max_match_value;
-	unsigned long rate;
 	raw_spinlock_t lock;
 	struct clock_event_device ced;
 	struct clocksource cs;
@@ -118,6 +117,7 @@ struct sh_cmt_device {
 
 	void __iomem *mapbase;
 	struct clk *clk;
+	unsigned long rate;
 
 	raw_spinlock_t lock; /* Protect the shared start/stop register */
 
@@ -320,7 +320,7 @@ static void sh_cmt_start_stop_ch(struct sh_cmt_channel *ch, int start)
 	raw_spin_unlock_irqrestore(&ch->cmt->lock, flags);
 }
 
-static int sh_cmt_enable(struct sh_cmt_channel *ch, unsigned long *rate)
+static int sh_cmt_enable(struct sh_cmt_channel *ch)
 {
 	int k, ret;
 
@@ -340,11 +340,9 @@ static int sh_cmt_enable(struct sh_cmt_channel *ch, unsigned long *rate)
 
 	/* configure channel, periodic mode and maximum timeout */
 	if (ch->cmt->info->width == 16) {
-		*rate = clk_get_rate(ch->cmt->clk) / 512;
 		sh_cmt_write_cmcsr(ch, SH_CMT16_CMCSR_CMIE |
 				   SH_CMT16_CMCSR_CKS512);
 	} else {
-		*rate = clk_get_rate(ch->cmt->clk) / 8;
 		sh_cmt_write_cmcsr(ch, SH_CMT32_CMCSR_CMM |
 				   SH_CMT32_CMCSR_CMTOUT_IE |
 				   SH_CMT32_CMCSR_CMR_IRQ |
@@ -572,7 +570,7 @@ static int sh_cmt_start(struct sh_cmt_channel *ch, unsigned long flag)
 	raw_spin_lock_irqsave(&ch->lock, flags);
 
 	if (!(ch->flags & (FLAG_CLOCKEVENT | FLAG_CLOCKSOURCE)))
-		ret = sh_cmt_enable(ch, &ch->rate);
+		ret = sh_cmt_enable(ch);
 
 	if (ret)
 		goto out;
@@ -640,10 +638,9 @@ static int sh_cmt_clocksource_enable(struct clocksource *cs)
 	ch->total_cycles = 0;
 
 	ret = sh_cmt_start(ch, FLAG_CLOCKSOURCE);
-	if (!ret) {
-		__clocksource_update_freq_hz(cs, ch->rate);
+	if (!ret)
 		ch->cs_enabled = true;
-	}
+
 	return ret;
 }
 
@@ -697,8 +694,7 @@ static int sh_cmt_register_clocksource(struct sh_cmt_channel *ch,
 	dev_info(&ch->cmt->pdev->dev, "ch%u: used as clock source\n",
 		 ch->index);
 
-	/* Register with dummy 1 Hz value, gets updated in ->enable() */
-	clocksource_register_hz(cs, 1);
+	clocksource_register_hz(cs, ch->cmt->rate);
 	return 0;
 }
 
@@ -709,19 +705,10 @@ static struct sh_cmt_channel *ced_to_sh_cmt(struct clock_event_device *ced)
 
 static void sh_cmt_clock_event_start(struct sh_cmt_channel *ch, int periodic)
 {
-	struct clock_event_device *ced = &ch->ced;
-
 	sh_cmt_start(ch, FLAG_CLOCKEVENT);
 
-	/* TODO: calculate good shift from rate and counter bit width */
-
-	ced->shift = 32;
-	ced->mult = div_sc(ch->rate, NSEC_PER_SEC, ced->shift);
-	ced->max_delta_ns = clockevent_delta2ns(ch->max_match_value, ced);
-	ced->min_delta_ns = clockevent_delta2ns(0x1f, ced);
-
 	if (periodic)
-		sh_cmt_set_next(ch, ((ch->rate + HZ/2) / HZ) - 1);
+		sh_cmt_set_next(ch, ((ch->cmt->rate + HZ/2) / HZ) - 1);
 	else
 		sh_cmt_set_next(ch, ch->max_match_value);
 }
@@ -824,6 +811,12 @@ static int sh_cmt_register_clockevent(struct sh_cmt_channel *ch,
 	ced->suspend = sh_cmt_clock_event_suspend;
 	ced->resume = sh_cmt_clock_event_resume;
 
+	/* TODO: calculate good shift from rate and counter bit width */
+	ced->shift = 32;
+	ced->mult = div_sc(ch->cmt->rate, NSEC_PER_SEC, ced->shift);
+	ced->max_delta_ns = clockevent_delta2ns(ch->max_match_value, ced);
+	ced->min_delta_ns = clockevent_delta2ns(0x1f, ced);
+
 	dev_info(&ch->cmt->pdev->dev, "ch%u: used for clock events\n",
 		 ch->index);
 	clockevents_register_device(ced);
@@ -996,6 +989,18 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev)
 	if (ret < 0)
 		goto err_clk_put;
 
+	/* Determine clock rate. */
+	ret = clk_enable(cmt->clk);
+	if (ret < 0)
+		goto err_clk_unprepare;
+
+	if (cmt->info->width == 16)
+		cmt->rate = clk_get_rate(cmt->clk) / 512;
+	else
+		cmt->rate = clk_get_rate(cmt->clk) / 8;
+
+	clk_disable(cmt->clk);
+
 	/* Map the memory resource(s). */
 	ret = sh_cmt_map_memory(cmt);
 	if (ret < 0)
Signature · 1 line
2.7.4
author
#11 lore raw

PATCH v2 9/11 clockevents/drivers/sh_cmt: Set ->min_delta_ticks and ->max_delta_ticks

In reply to Biju Das

From: Nicolai Stange <[email protected]>

In preparation for making the clockevents core NTP correction aware, all clockevent device drivers must set ->min_delta_ticks and ->max_delta_ticks rather than ->min_delta_ns and ->max_delta_ns: a clockevent device's rate is going to change dynamically and thus, the ratio of ns to ticks ceases to stay invariant.

Make the sh_cmt clockevent driver initialize these fields properly.

This patch alone doesn't introduce any change in functionality as the clockevents core still looks exclusively at the (untouched) ->min_delta_ns and ->max_delta_ns. As soon as this has changed, a followup patch will purge the initialization of ->min_delta_ns and ->max_delta_ns from this driver.

Cc Ingo Molnar <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc Daniel Lezcano <[email protected]>
Cc Richard Cochran <[email protected]>
Cc Prarit Bhargava <[email protected]>
Cc Stephen Boyd <[email protected]>
(cherry picked from commit bb2e94ac0cf4628f5e5f778c8de4a376dac43558)
---
 drivers/clocksource/sh_cmt.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/clocksource/sh_cmt.c +2 -0
index 3038885..97ce6bf 100644
@@ -815,7 +815,9 @@ static int sh_cmt_register_clockevent(struct sh_cmt_channel *ch,
 	ced->shift = 32;
 	ced->mult = div_sc(ch->cmt->rate, NSEC_PER_SEC, ced->shift);
 	ced->max_delta_ns = clockevent_delta2ns(ch->max_match_value, ced);
+	ced->max_delta_ticks = ch->max_match_value;
 	ced->min_delta_ns = clockevent_delta2ns(0x1f, ced);
+	ced->min_delta_ticks = 0x1f;
 
 	dev_info(&ch->cmt->pdev->dev, "ch%u: used for clock events\n",
 		 ch->index);
Signature · 1 line
2.7.4
author
#12 lore raw

PATCH v2 10/11 ARM: dts: r8a7743: Add CMT SoC specific support

In reply to Biju Das

From: Fabrizio Castro <[email protected]>

Add CMT[01] support to SoC DT.

(cherry picked from commit 3114c70c532ae2555948739f645ace268554228d)

(updated clocks and power-domains property.removed resets property. Changed the compatible string due to the commit 8d50e9476bb4 ("clocksource/drivers/sh_cmt: Mark "renesas, cmt-48-gen2" deprecated"). Added renesas,channels-mask property which is removed based on the commit 4e18111ff38f0664 ("devicetree:bindings: Remove deprecated properties"))

---
 arch/arm/boot/dts/r8a7743.dtsi | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)
arch/arm/boot/dts/r8a7743.dtsi +36 -0
index 1d9adcc..72a23c9 100644
@@ -1653,6 +1653,42 @@
 			status = "disabled";
 		};
 
+		cmt0: timer at ffca0000 {
+			compatible = "renesas,cmt-48-r8a7743",
+				     "renesas,cmt-48-gen2";
+			reg = <0 0xffca0000 0 0x1004>;
+			interrupts = <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&mstp1_clks R8A7743_CLK_CMT0>;
+			clock-names = "fck";
+			power-domains = <&cpg_clocks>;
+
+			renesas,channels-mask = <0x60>;
+
+			status = "disabled";
+		};
+
+		cmt1: timer at e6130000 {
+			compatible = "renesas,cmt-48-r8a7743",
+				     "renesas,cmt-48-gen2";
+			reg = <0 0xe6130000 0 0x1004>;
+			interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
+				     <GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&mstp3_clks R8A7743_CLK_CMT1>;
+			clock-names = "fck";
+			power-domains = <&cpg_clocks>;
+
+			renesas,channels-mask = <0xff>;
+
+			status = "disabled";
+		};
+
 		rcar_sound: sound at ec500000 {
 			/*
 			 * #sound-dai-cells is required
Signature · 1 line
2.7.4
author
#13 lore raw

PATCH v2 11/11 ARM: dts: iwg20m: Enable cmt0

In reply to Biju Das

From: Fabrizio Castro <[email protected]>

This patch enables cmt0 support from within the iwg20m SoM dtsi.

(cherry picked from commit cbeb319b9f220982acc2f533ffee5042a6763c39)
---
 arch/arm/boot/dts/r8a7743-iwg20m.dtsi | 4 ++++
 1 file changed, 4 insertions(+)
arch/arm/boot/dts/r8a7743-iwg20m.dtsi +4 -0
index 75a8ca5..1d3e950 100644
@@ -34,6 +34,10 @@
 	};
 };
 
+&cmt0 {
+	status = "okay";
+};
+
 &extal_clk {
 	clock-frequency = <20000000>;
 };
Signature · 1 line
2.7.4