[PATCH 00/48] ARM: at91: rework Atmel TCB drivers

STALE3419d

Revision v1 of 2 in this series.

75 messages, 8 authors, 2017-05-16 · open the first message on its own page

[PATCH 00/48] ARM: at91: rework Atmel TCB drivers

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:04:17

Hi,

This series reworks the Atmel Timer counter Block drivers. Those blocks
each have 3 counters with 2 channels each and can be used for
multiple functions:
 - timers
 - PWMs
 - Quadrature decoders
 - Stepper motor counters

Up until now, each TCB was fully used by each driver, possibly wasting
counters/channels.

There is a second issue motivating that rework. Until now, the PIT is
still used to boot then later in the boot sequence, the clocksource is
switched to the TCB. This ends up not working well with preempt-rt
because on some SoCs, the PIT interrupt is shared with the DBGU uart.
When using preempt-rt the interrupt flags for the PIT and the DBGU end
up being incompatible.

The whole rework doesn't break the DT ABI for the clocksource as the old
driver is kept anyway for AVR32. However, I still took the time to
switch all the upstreamed board dts to the new bindings.
However, there is no other choice than breaking the mainly unused
pwm-atmel-tcb binding. Only the kizbox is actually using it.

I hope we could quickly come to an agreement on the new DT bindings and
include those changes in 4.8.

Regarding the tcbclksrc driver, I'm not completely happy with the
request_irq/free_irq thing but there is not much choice unless we want
to pass in the clksrc handler even when using the clkevt driver as they
may share the same interrupt.

Cc: Antoine Aubert <redacted>
Cc: Daniel Lezcano <redacted>
Cc: devicetree at vger.kernel.org
Cc: Douglas Gilbert <dgilbert@interlog.com>
Cc: Fabio Porcedda <redacted>
Cc: Gregory CLEMENT <redacted>
Cc: Gregory Hermant <redacted>
Cc: Joachim Eastwood <redacted>
Cc: linux-clk at vger.kernel.org
Cc: linux-pwm at vger.kernel.org
Cc: Marek Vasut <marex@denx.de>
Cc: Martin Reimann <redacted>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Rodolfo Giometti <redacted>
Cc: Sergio Tanzilli <redacted>
Cc: Stephen Boyd <redacted>
Cc: Thierry Reding <redacted>
Cc: Thomas Gleixner <redacted>
Cc: Tim Schendekehl <redacted>

Alexandre Belloni (47):
  ARM: at91: Document new TCB bindings
  ARM: dts: at91: at91rm9200: TC blocks are also simple-mfd and syscon
    devices
  ARM: dts: at91: at91rm9200ek; use TCB0 as clocksource
  ARM: dts: at91: mpa1600; use TCB0 as clocksource
  ARM: dts: at91: at91sam9260: TC blocks are also simple-mfd and syscon
    devices
  ARM: dts: at91: ethernut5: use TCB0 as clocksource
  ARM: dts: at91: foxg20: use TCB0 as clocksource
  ARM: dts: at91: animeo_ip: use TCB0 as clocksource
  ARM: dts: at91: kizbox: use TCB0 as clocksource
  ARM: dts: at91: at91sam9g20ek: use TCB0 as clocksource
  ARM: dts: at91: ge863-pro3: use TCB0 as clocksource
  ARM: dts: at91: at91sam9261: TC blocks are also simple-mfd and syscon
    devices
  ARM: dts: at91: at91sam9261ek: use TCB0 as clocksource
  ARM: dts: at91: at91sam9263: TC blocks are also simple-mfd and syscon
    devices
  ARM: dts: at91: at91sam9263ek: use TCB0 as clocksource
  ARM: dts: at91: calao: use TCB0 as clocksource
  ARM: dts: at91: at91sam9g45: TC blocks are also simple-mfd and syscon
    devices
  ARM: dts: at91: at91sam9m10g45ek: use TCB0 as clocksource
  ARM: dts: at91: pm9g45: use TCB0 as clocksource
  ARM: dts: at91: at91sam9rl: TC blocks are also simple-mfd and syscon
    devices
  ARM: dts: at91: at91sam9rlek: use TCB0 as clocksource
  ARM: dts: at91: at91sam9n12: TC blocks are also simple-mfd and syscon
    devices
  ARM: dts: at91: at91sam9n12ek: use TCB0 as clocksource
  ARM: dts: at91: at91sam9x5: TC blocks are also simple-mfd and syscon
    devices
  ARM: dts: at91: at91sam9x5cm: use TCB0 as clocksource
  ARM: dts: at91: acme/g25: use TCB0 as clocksource
  ARM: dts: at91: cosino: use TCB0 as clocksource
  ARM: dts: at91: kizboxmini: use TCB0 as clocksource
  ARM: dts: at91: sama5d3: TC blocks are also simple-mfd and syscon
    devices
  ARM: dts: at91: sama5d3xek; use TCB0 as clocksource
  ARM: dts: at91: sama5d3 Xplained: use TCB0 as clocksource
  ARM: dts: at91: kizbox2: use TCB0 as clocksource
  ARM: dts: at91: sama5d4: TC blocks are also simple-mfd and syscon
    devices
  ARM: dts: at91: sama5d4: Add TCB2
  ARM: dts: at91: sama5d4ek: use TCB2 as clocksource
  ARM: dts: at91: sama5d4 Xplained: use TCB2 as clocksource
  ARM: dts: at91: ma5d4: use TCB2 as clocksource
  ARM: dts: at91: vinco: use TCB2 as clocksource
  ARM: dts: at91: sama5d2: TC blocks are also simple-mfd and syscon
    devices
  ARM: dts: at91: sama5d2 Xplained: use TCB0 as clocksource
  clocksource/drivers: Add a new driver for the Atmel ARM TC blocks
  clocksource/drivers: Add a clockevent driver for Atmel TC blocks
  clocksource: atmel-pit: allow unselecting ATMEL_PIT
  ARM: at91/defconfig: sama5: unselect ATMEL_PIT
  ARM: at91/defconfig: at91_dt unselect ATMEL_PIT
  PWM: atmel-tcb: switch to new binding
  ARM: dts: at91: kizbox: switch to new pwm-atmel-tcb binding

Cyrille Pitchen (1):
  clk: at91: replace usleep() by udelay() calls

 .../devicetree/bindings/arm/atmel-at91.txt         |  32 ---
 .../devicetree/bindings/mfd/atmel-tcb.txt          |  62 +++++
 .../devicetree/bindings/pwm/atmel-tcb-pwm.txt      |  12 +-
 arch/arm/boot/dts/animeo_ip.dts                    |  12 +
 arch/arm/boot/dts/at91-ariag25.dts                 |  12 +
 arch/arm/boot/dts/at91-ariettag25.dts              |  12 +
 arch/arm/boot/dts/at91-cosino.dtsi                 |  12 +
 arch/arm/boot/dts/at91-foxg20.dts                  |  12 +
 arch/arm/boot/dts/at91-kizbox.dts                  |  54 +++-
 arch/arm/boot/dts/at91-kizbox2.dts                 |  12 +
 arch/arm/boot/dts/at91-kizboxmini.dts              |  12 +
 arch/arm/boot/dts/at91-qil_a9260.dts               |  12 +
 arch/arm/boot/dts/at91-sama5d2_xplained.dts        |  12 +
 arch/arm/boot/dts/at91-sama5d3_xplained.dts        |  12 +
 arch/arm/boot/dts/at91-sama5d4_ma5d4.dtsi          |  12 +
 arch/arm/boot/dts/at91-sama5d4_xplained.dts        |  12 +
 arch/arm/boot/dts/at91-sama5d4ek.dts               |  12 +
 arch/arm/boot/dts/at91-vinco.dts                   |  12 +
 arch/arm/boot/dts/at91rm9200.dtsi                  |   8 +-
 arch/arm/boot/dts/at91rm9200ek.dts                 |  12 +
 arch/arm/boot/dts/at91sam9260.dtsi                 |   8 +-
 arch/arm/boot/dts/at91sam9261.dtsi                 |   4 +-
 arch/arm/boot/dts/at91sam9261ek.dts                |  12 +
 arch/arm/boot/dts/at91sam9263.dtsi                 |   4 +-
 arch/arm/boot/dts/at91sam9263ek.dts                |  12 +
 arch/arm/boot/dts/at91sam9g20ek_common.dtsi        |  12 +
 arch/arm/boot/dts/at91sam9g45.dtsi                 |   8 +-
 arch/arm/boot/dts/at91sam9m10g45ek.dts             |  12 +
 arch/arm/boot/dts/at91sam9n12.dtsi                 |   8 +-
 arch/arm/boot/dts/at91sam9n12ek.dts                |  12 +
 arch/arm/boot/dts/at91sam9rl.dtsi                  |   4 +-
 arch/arm/boot/dts/at91sam9rlek.dts                 |  12 +
 arch/arm/boot/dts/at91sam9x5.dtsi                  |   8 +-
 arch/arm/boot/dts/at91sam9x5cm.dtsi                |  12 +
 arch/arm/boot/dts/ethernut5.dts                    |  12 +
 arch/arm/boot/dts/ge863-pro3.dtsi                  |  12 +
 arch/arm/boot/dts/mpa1600.dts                      |  12 +
 arch/arm/boot/dts/pm9g45.dts                       |  12 +
 arch/arm/boot/dts/sama5d2.dtsi                     |   8 +-
 arch/arm/boot/dts/sama5d3.dtsi                     |   4 +-
 arch/arm/boot/dts/sama5d3_tcb1.dtsi                |   4 +-
 arch/arm/boot/dts/sama5d3xcm.dtsi                  |  12 +
 arch/arm/boot/dts/sama5d4.dtsi                     |  18 +-
 arch/arm/boot/dts/tny_a9260_common.dtsi            |  12 +
 arch/arm/boot/dts/tny_a9263.dts                    |  12 +
 arch/arm/boot/dts/usb_a9260_common.dtsi            |  12 +
 arch/arm/boot/dts/usb_a9263.dts                    |  12 +
 arch/arm/configs/at91_dt_defconfig                 |   1 +
 arch/arm/configs/sama5_defconfig                   |   1 +
 drivers/clk/at91/clk-main.c                        |   2 +-
 drivers/clk/at91/clk-slow.c                        |   6 +-
 drivers/clocksource/Kconfig                        |  32 ++-
 drivers/clocksource/Makefile                       |   4 +-
 drivers/clocksource/timer-atmel-tcbclkevt.c        | 220 +++++++++++++++
 drivers/clocksource/timer-atmel-tcbclksrc.c        | 305 +++++++++++++++++++++
 drivers/pwm/Kconfig                                |   3 +-
 drivers/pwm/pwm-atmel-tcb.c                        | 219 ++++++++-------
 include/soc/at91/atmel_tcb.h                       | 220 +++++++++++++++
 58 files changed, 1452 insertions(+), 179 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mfd/atmel-tcb.txt
 create mode 100644 drivers/clocksource/timer-atmel-tcbclkevt.c
 create mode 100644 drivers/clocksource/timer-atmel-tcbclksrc.c
 create mode 100644 include/soc/at91/atmel_tcb.h

-- 
2.8.1

[PATCH 01/48] clk: at91: replace usleep() by udelay() calls

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:04:11

From: Cyrille Pitchen <redacted>

Fix the main and slow clock .prepare() implementations which used to call
usleep() when the scheduler wasn't ready yet.

Cc: Stephen Boyd <redacted>
Cc: linux-clk at vger.kernel.org
Signed-off-by: Cyrille Pitchen <redacted>
Signed-off-by: Alexandre Belloni <redacted>
---
 drivers/clk/at91/clk-main.c | 2 +-
 drivers/clk/at91/clk-slow.c | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/clk/at91/clk-main.c b/drivers/clk/at91/clk-main.c
index 58b5baca670c..12c5062aeb92 100644
--- a/drivers/clk/at91/clk-main.c
+++ b/drivers/clk/at91/clk-main.c
@@ -342,7 +342,7 @@ static int clk_main_probe_frequency(struct regmap *regmap)
 		regmap_read(regmap, AT91_CKGR_MCFR, &mcfr);
 		if (mcfr & AT91_PMC_MAINRDY)
 			return 0;
-		usleep_range(MAINF_LOOP_MIN_WAIT, MAINF_LOOP_MAX_WAIT);
+		udelay(MAINF_LOOP_MIN_WAIT);
 	} while (time_before(prep_time, timeout));
 
 	return -ETIMEDOUT;
diff --git a/drivers/clk/at91/clk-slow.c b/drivers/clk/at91/clk-slow.c
index 61090b1146cf..612e893ce994 100644
--- a/drivers/clk/at91/clk-slow.c
+++ b/drivers/clk/at91/clk-slow.c
@@ -76,7 +76,7 @@ static int clk_slow_osc_prepare(struct clk_hw *hw)
 
 	writel(tmp | AT91_SCKC_OSC32EN, sckcr);
 
-	usleep_range(osc->startup_usec, osc->startup_usec + 1);
+	udelay(osc->startup_usec);
 
 	return 0;
 }
@@ -195,7 +195,7 @@ static int clk_slow_rc_osc_prepare(struct clk_hw *hw)
 
 	writel(readl(sckcr) | AT91_SCKC_RCEN, sckcr);
 
-	usleep_range(osc->startup_usec, osc->startup_usec + 1);
+	udelay(osc->startup_usec);
 
 	return 0;
 }
@@ -304,7 +304,7 @@ static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index)
 
 	writel(tmp, sckcr);
 
-	usleep_range(SLOWCK_SW_TIME_USEC, SLOWCK_SW_TIME_USEC + 1);
+	udelay(SLOWCK_SW_TIME_USEC);
 
 	return 0;
 }
-- 
2.8.1

[PATCH 03/48] ARM: dts: at91: at91rm9200: TC blocks are also simple-mfd and syscon devices

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:04:13

Add simple-mfd and syscon to the TC blocks to allow to register one of the
channels as clocksource properly at boot time. It also allows to use
regmap instead of tclib.

Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/at91rm9200.dtsi | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/at91rm9200.dtsi b/arch/arm/boot/dts/at91rm9200.dtsi
index f6cb7a80a2f5..ec0a7d36ee43 100644
--- a/arch/arm/boot/dts/at91rm9200.dtsi
+++ b/arch/arm/boot/dts/at91rm9200.dtsi
@@ -375,7 +375,9 @@
 			};
 
 			tcb0: timer at fffa0000 {
-				compatible = "atmel,at91rm9200-tcb";
+				compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon";
+				#address-cells = <1>;
+				#size-cells = <0>;
 				reg = <0xfffa0000 0x100>;
 				interrupts = <17 IRQ_TYPE_LEVEL_HIGH 0
 					      18 IRQ_TYPE_LEVEL_HIGH 0
@@ -385,7 +387,9 @@
 			};
 
 			tcb1: timer@fffa4000 {
-				compatible = "atmel,at91rm9200-tcb";
+				compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon";
+				#address-cells = <1>;
+				#size-cells = <0>;
 				reg = <0xfffa4000 0x100>;
 				interrupts = <20 IRQ_TYPE_LEVEL_HIGH 0
 					      21 IRQ_TYPE_LEVEL_HIGH 0
-- 
2.8.1

[PATCH 02/48] ARM: at91: Document new TCB bindings

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:04:16

The current binding for the TCB is not flexible enough for some use cases
and prevents proper utilization of all the channels.

Cc: Daniel Lezcano <redacted>
Cc: Thierry Reding <redacted>
Cc: linux-pwm at vger.kernel.org
Cc: Rob Herring <robh+dt@kernel.org>
Cc: devicetree at vger.kernel.org
Signed-off-by: Alexandre Belloni <redacted>
---
 .../devicetree/bindings/arm/atmel-at91.txt         | 32 -----------
 .../devicetree/bindings/mfd/atmel-tcb.txt          | 62 ++++++++++++++++++++++
 .../devicetree/bindings/pwm/atmel-tcb-pwm.txt      | 12 +++--
 3 files changed, 69 insertions(+), 37 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mfd/atmel-tcb.txt
diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.txt b/Documentation/devicetree/bindings/arm/atmel-at91.txt
index e1f5ad855f14..3dc758403d03 100644
--- a/Documentation/devicetree/bindings/arm/atmel-at91.txt
+++ b/Documentation/devicetree/bindings/arm/atmel-at91.txt
@@ -60,38 +60,6 @@ System Timer (ST) required properties:
 Its subnodes can be:
 - watchdog: compatible should be "atmel,at91rm9200-wdt"
 
-TC/TCLIB Timer required properties:
-- compatible: Should be "atmel,<chip>-tcb".
-  <chip> can be "at91rm9200" or "at91sam9x5"
-- reg: Should contain registers location and length
-- interrupts: Should contain all interrupts for the TC block
-  Note that you can specify several interrupt cells if the TC
-  block has one interrupt per channel.
-- clock-names: tuple listing input clock names.
-	Required elements: "t0_clk", "slow_clk"
-	Optional elements: "t1_clk", "t2_clk"
-- clocks: phandles to input clocks.
-
-Examples:
-
-One interrupt per TC block:
-	tcb0: timer at fff7c000 {
-		compatible = "atmel,at91rm9200-tcb";
-		reg = <0xfff7c000 0x100>;
-		interrupts = <18 4>;
-		clocks = <&tcb0_clk>;
-		clock-names = "t0_clk";
-	};
-
-One interrupt per TC channel in a TC block:
-	tcb1: timer at fffdc000 {
-		compatible = "atmel,at91rm9200-tcb";
-		reg = <0xfffdc000 0x100>;
-		interrupts = <26 4 27 4 28 4>;
-		clocks = <&tcb1_clk>;
-		clock-names = "t0_clk";
-	};
-
 RSTC Reset Controller required properties:
 - compatible: Should be "atmel,<chip>-rstc".
   <chip> can be "at91sam9260" or "at91sam9g45" or "sama5d3"
diff --git a/Documentation/devicetree/bindings/mfd/atmel-tcb.txt b/Documentation/devicetree/bindings/mfd/atmel-tcb.txt
new file mode 100644
index 000000000000..48196752c78f
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/atmel-tcb.txt
@@ -0,0 +1,62 @@
+* Device tree bindings for Atmel Timer Counter Blocks
+- compatible: Should be "atmel,<chip>-tcb", "simple-mfd", "syscon".
+  <chip> can be "at91rm9200" or "at91sam9x5"
+- reg: Should contain registers location and length
+- #address-cells: has to be 1
+- #size-cells: has to be 0
+- interrupts: Should contain all interrupts for the TC block
+  Note that you can specify several interrupt cells if the TC
+  block has one interrupt per channel.
+- clock-names: tuple listing input clock names.
+	Required elements: "t0_clk", "slow_clk"
+	Optional elements: "t1_clk", "t2_clk"
+- clocks: phandles to input clocks.
+
+The TCB can expose multiple subdevices:
+ * a clocksource and clockevent device
+   - compatible: Should be "atmel,tcb-clksrc"
+   - reg: Should contain the TCB channels to be used. If the
+     counter width is 16 bits (at91rm9200-tcb), two consecutive
+     channels are needed. Else, only one channel will be used.
+
+ * a clockevent device
+   - compatible: Should be "atmel,tcb-clkevt"
+   - reg: Should contain the TCB channel to be used
+
+ * a PWM chip: see ../pwm/atmel-tcb-pwm.txt
+
+Examples:
+
+One interrupt per TC block:
+	tcb0: timer at fff7c000 {
+		compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0xfff7c000 0x100>;
+		interrupts = <18 4>;
+		clocks = <&tcb0_clk>;
+		clock-names = "t0_clk";
+
+		timer at 0 {
+			compatible = "atmel,tcb-clksrc";
+			reg = <0>, <1>;
+		};
+
+		timer at 2 {
+			compatible = "atmel,tcb-clkevt";
+			reg = <2>;
+		};
+	};
+
+One interrupt per TC channel in a TC block:
+	tcb1: timer at fffdc000 {
+		compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0xfffdc000 0x100>;
+		interrupts = <26 4>, <27 4>, <28 4>;
+		clocks = <&tcb1_clk>;
+		clock-names = "t0_clk";
+	};
+
+
diff --git a/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt b/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt
index 8031148bcf85..ab8fbd5ba184 100644
--- a/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt
+++ b/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt
@@ -2,15 +2,17 @@ Atmel TCB PWM controller
 
 Required properties:
 - compatible: should be "atmel,tcb-pwm"
+- reg: tcb channel to use. Each channel can export 2 PWMs
 - #pwm-cells: should be 3. See pwm.txt in this directory for a description of
   the cells format. The only third cell flag supported by this binding is
   PWM_POLARITY_INVERTED.
-- tc-block: The Timer Counter block to use as a PWM chip.
 
 Example:
 
-pwm {
-	compatible = "atmel,tcb-pwm";
-	#pwm-cells = <3>;
-	tc-block = <1>;
+tcb0: timer at f800c000 {
+	pwm at 0 {
+		compatible = "atmel,tcb-pwm";
+		reg = <0>;
+		#pwm-cells = <3>;
+	};
 };
-- 
2.8.1

[PATCH 12/48] ARM: dts: at91: ge863-pro3: use TCB0 as clocksource

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:04:19

Use tcb0 as the clocksource like previously selected in at91_dt_defconfig.

Cc: Fabio Porcedda <redacted>
Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/ge863-pro3.dtsi | 12 ++++++++++++
 1 file changed, 12 insertions(+)
diff --git a/arch/arm/boot/dts/ge863-pro3.dtsi b/arch/arm/boot/dts/ge863-pro3.dtsi
index 0d0e62489d93..6b5eb285b072 100644
--- a/arch/arm/boot/dts/ge863-pro3.dtsi
+++ b/arch/arm/boot/dts/ge863-pro3.dtsi
@@ -27,6 +27,18 @@
 
 	ahb {
 		apb {
+			tcb0: timer at fffa0000 {
+				timer at 0 {
+					compatible = "atmel,tcb-clksrc";
+					reg = <0>, <1>;
+				};
+
+				timer at 2 {
+					compatible = "atmel,tcb-clkevt";
+					reg = <2>;
+				};
+			};
+
 			dbgu: serial at fffff200 {
 				status = "okay";
 			};
-- 
2.8.1

[PATCH 15/48] ARM: dts: at91: at91sam9263: TC blocks are also simple-mfd and syscon devices

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:04:20

Add simple-mfd and syscon to the TC blocks to allow to register one of the
channels as clocksource properly at boot time. It also allows to use regmap
instead of tclib.

Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/at91sam9263.dtsi | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
index 93446420af25..a06c8882c065 100644
--- a/arch/arm/boot/dts/at91sam9263.dtsi
+++ b/arch/arm/boot/dts/at91sam9263.dtsi
@@ -374,7 +374,9 @@
 			};
 
 			tcb0: timer at fff7c000 {
-				compatible = "atmel,at91rm9200-tcb";
+				compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon";
+				#address-cells = <1>;
+				#size-cells = <0>;
 				reg = <0xfff7c000 0x100>;
 				interrupts = <19 IRQ_TYPE_LEVEL_HIGH 0>;
 				clocks = <&tcb_clk>, <&slow_xtal>;
-- 
2.8.1

[PATCH 21/48] ARM: dts: at91: at91sam9rl: TC blocks are also simple-mfd and syscon devices

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:04:22

Add simple-mfd and syscon to the TC blocks to allow to register one of the
channels as clocksource properly at boot time. It also allows to use regmap
instead of tclib.

Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/at91sam9rl.dtsi | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/at91sam9rl.dtsi b/arch/arm/boot/dts/at91sam9rl.dtsi
index 6d829db4e887..da74b769d5ac 100644
--- a/arch/arm/boot/dts/at91sam9rl.dtsi
+++ b/arch/arm/boot/dts/at91sam9rl.dtsi
@@ -116,7 +116,9 @@
 			ranges;
 
 			tcb0: timer at fffa0000 {
-				compatible = "atmel,at91rm9200-tcb";
+				compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon";
+				#address-cells = <1>;
+				#size-cells = <0>;
 				reg = <0xfffa0000 0x100>;
 				interrupts = <16 IRQ_TYPE_LEVEL_HIGH 0>,
 					     <17 IRQ_TYPE_LEVEL_HIGH 0>,
-- 
2.8.1

[PATCH 40/48] ARM: dts: at91: sama5d2: TC blocks are also simple-mfd and syscon devices

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:04:25

Add simple-mfd and syscon to the TC blocks to allow to register one of the
channels as clocksource properly at boot time. It also allows to use
regmap instead of tclib.

Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/sama5d2.dtsi | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi
index 2827e7ab5ebc..0db2f8b77227 100644
--- a/arch/arm/boot/dts/sama5d2.dtsi
+++ b/arch/arm/boot/dts/sama5d2.dtsi
@@ -906,7 +906,9 @@
 			};
 
 			tcb0: timer at f800c000 {
-				compatible = "atmel,at91sam9x5-tcb";
+				compatible = "atmel,at91sam9x5-tcb", "simple-mfd", "syscon";
+				#address-cells = <1>;
+				#size-cells = <0>;
 				reg = <0xf800c000 0x100>;
 				interrupts = <35 IRQ_TYPE_LEVEL_HIGH 0>;
 				clocks = <&tcb0_clk>, <&clk32k>;
@@ -914,7 +916,9 @@
 			};
 
 			tcb1: timer at f8010000 {
-				compatible = "atmel,at91sam9x5-tcb";
+				compatible = "atmel,at91sam9x5-tcb", "simple-mfd", "syscon";
+				#address-cells = <1>;
+				#size-cells = <0>;
 				reg = <0xf8010000 0x100>;
 				interrupts = <36 IRQ_TYPE_LEVEL_HIGH 0>;
 				clocks = <&tcb1_clk>, <&clk32k>;
-- 
2.8.1

[PATCH 41/48] ARM: dts: at91: sama5d2 Xplained: use TCB0 as clocksource

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:04:26

Use tcb0 as the clocksource like previously selected in sama5_defconfig.

Tested-by: Alexandre Belloni <redacted>
Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/at91-sama5d2_xplained.dts | 12 ++++++++++++
 1 file changed, 12 insertions(+)
diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts
index eb4f1ac96271..566d303e419b 100644
--- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts
+++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts
@@ -135,6 +135,18 @@
 				};
 			};
 
+			tcb0: timer at f800c000 {
+				timer at 0 {
+					compatible = "atmel,tcb-clksrc";
+					reg = <0>;
+				};
+
+				timer at 1 {
+					compatible = "atmel,tcb-clkevt";
+					reg = <1>;
+				};
+			};
+
 			pdmic at f8018000 {
 				pinctrl-names = "default";
 				pinctrl-0 = <&pinctrl_pdmic_default>;
-- 
2.8.1

[PATCH 46/48] ARM: at91/defconfig: at91_dt unselect ATMEL_PIT

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:04:27

The PIT is not required anymore to successfully boot and may actually harm
in case preempt-rt is used because the PIT interrupt is shared.
Disable it so the TCB clocksource is used.

Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/configs/at91_dt_defconfig | 1 +
 1 file changed, 1 insertion(+)
diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig
index e4b1be66b3f5..9d068f07b84b 100644
--- a/arch/arm/configs/at91_dt_defconfig
+++ b/arch/arm/configs/at91_dt_defconfig
@@ -182,6 +182,7 @@ CONFIG_RTC_DRV_AT91RM9200=y
 CONFIG_RTC_DRV_AT91SAM9=y
 CONFIG_DMADEVICES=y
 CONFIG_AT_HDMAC=y
+# CONFIG_ATMEL_PIT is not set
 # CONFIG_IOMMU_SUPPORT is not set
 CONFIG_IIO=y
 CONFIG_AT91_ADC=y
-- 
2.8.1

[PATCH 48/48] ARM: dts: at91: kizbox: switch to new pwm-atmel-tcb binding

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:04:48

Switch to the new pwm-atmel-tcb binding that avoid wasting TCB channels.

Cc: Antoine Aubert <redacted>
Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/at91-kizbox.dts | 42 +++++++++++++++++++++++++--------------
 1 file changed, 27 insertions(+), 15 deletions(-)
diff --git a/arch/arm/boot/dts/at91-kizbox.dts b/arch/arm/boot/dts/at91-kizbox.dts
index 58c5d0d3dd66..6579f955250b 100644
--- a/arch/arm/boot/dts/at91-kizbox.dts
+++ b/arch/arm/boot/dts/at91-kizbox.dts
@@ -43,6 +43,29 @@
 				};
 			};
 
+			tcb1: timer at fffdc000 {
+				tcb1_pwm0: pwm at 0 {
+					compatible = "atmel,tcb-pwm";
+					#pwm-cells = <3>;
+					pinctrl-names = "default";
+					pinctrl-0 = <&pinctrl_tcb1_tioa0 &pinctrl_tcb1_tiob0>;
+				}
+
+				tcb1_pwm1: pwm at 1 {
+					compatible = "atmel,tcb-pwm";
+					#pwm-cells = <3>;
+					pinctrl-names = "default";
+					pinctrl-0 = &pinctrl_tcb1_tioa1>;
+				}
+
+				tcb1_pwm2: pwm at 2 {
+					compatible = "atmel,tcb-pwm";
+					#pwm-cells = <3>;
+					pinctrl-names = "default";
+					pinctrl-0 = <&pinctrl_tcb1_tioa2>;
+				}
+			};
+
 			macb0: ethernet at fffc4000 {
 				phy-mode = "mii";
 				pinctrl-0 = <&pinctrl_macb_rmii
@@ -122,41 +145,30 @@
 
 		network_green {
 			label = "pwm:green:network";
-			pwms = <&tcb_pwm 2 10000000 PWM_POLARITY_INVERTED>;
+			pwms = <&tcb1_pwm1 0 10000000 PWM_POLARITY_INVERTED>;
 			max-brightness = <255>;
 			linux,default-trigger = "default-on";
 		};
 
 		network_red {
 			label = "pwm:red:network";
-			pwms = <&tcb_pwm 4 10000000 PWM_POLARITY_INVERTED>;
+			pwms = <&tcb1_pwm2 0 10000000 PWM_POLARITY_INVERTED>;
 			max-brightness = <255>;
 			linux,default-trigger = "default-on";
 		};
 
 		user_green {
 			label = "pwm:green:user";
-			pwms = <&tcb_pwm 0 10000000 PWM_POLARITY_INVERTED>;
+			pwms = <&tcb1_pwm0 0 10000000 PWM_POLARITY_INVERTED>;
 			max-brightness = <255>;
 			linux,default-trigger = "default-on";
 		};
 
 		user_red {
 			label = "pwm:red:user";
-			pwms = <&tcb_pwm 1 10000000 PWM_POLARITY_INVERTED>;
+			pwms = <&tcb1_pwm0 1 10000000 PWM_POLARITY_INVERTED>;
 			max-brightness = <255>;
 			linux,default-trigger = "default-on";
 		};
 	};
-
-	tcb_pwm: pwm {
-		compatible = "atmel,tcb-pwm";
-		#pwm-cells = <3>;
-		tc-block = <1>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&pinctrl_tcb1_tioa0
-			     &pinctrl_tcb1_tioa1
-			     &pinctrl_tcb1_tioa2
-			     &pinctrl_tcb1_tiob0>;
-	};
 };
-- 
2.8.1

[PATCH 47/48] PWM: atmel-tcb: switch to new binding

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:04:49

The PWM is now a subnode of the used TCB. This is cleaner and it mainly
allows to stop wasting TCB channels when only 4 PWMs are used.

Cc: Thierry Reding <redacted>
Cc: linux-pwm at vger.kernel.org
Signed-off-by: Alexandre Belloni <redacted>
---
 drivers/pwm/Kconfig         |   3 +-
 drivers/pwm/pwm-atmel-tcb.c | 219 ++++++++++++++++++++++++--------------------
 2 files changed, 120 insertions(+), 102 deletions(-)
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index c182efc62c7b..431a68c2e82f 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -64,7 +64,8 @@ config PWM_ATMEL_HLCDC_PWM
 
 config PWM_ATMEL_TCB
 	tristate "Atmel TC Block PWM support"
-	depends on ATMEL_TCLIB && OF
+	depends on OF
+	select REGMAP_MMIO
 	help
 	  Generic PWM framework driver for Atmel Timer Counter Block.
 
diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c
index 75db585a2a94..5afb5116ad96 100644
--- a/drivers/pwm/pwm-atmel-tcb.c
+++ b/drivers/pwm/pwm-atmel-tcb.c
@@ -16,19 +16,26 @@
 #include <linux/err.h>
 #include <linux/ioport.h>
 #include <linux/io.h>
+#include <linux/mfd/syscon.h>
 #include <linux/platform_device.h>
-#include <linux/atmel_tc.h>
 #include <linux/pwm.h>
 #include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
+#include <soc/at91/atmel_tcb.h>
 
-#define NPWM	6
+#define NPWM	2
 
-#define ATMEL_TC_ACMR_MASK	(ATMEL_TC_ACPA | ATMEL_TC_ACPC |	\
-				 ATMEL_TC_AEEVT | ATMEL_TC_ASWTRG)
+#define ATMEL_TC_ACMR_MASK	(ATMEL_TC_CMR_ACPA_MSK | \
+				 ATMEL_TC_CMR_ACPC_MSK | \
+				 ATMEL_TC_CMR_AEEVT_MSK | \
+				 ATMEL_TC_CMR_ASWTRG_MSK)
 
-#define ATMEL_TC_BCMR_MASK	(ATMEL_TC_BCPB | ATMEL_TC_BCPC |	\
-				 ATMEL_TC_BEEVT | ATMEL_TC_BSWTRG)
+#define ATMEL_TC_BCMR_MASK	(ATMEL_TC_CMR_BCPB_MSK | \
+				 ATMEL_TC_CMR_BCPC_MSK | \
+				 ATMEL_TC_CMR_BEEVT_MSK | \
+				 ATMEL_TC_CMR_BSWTRG_MSK)
 
 struct atmel_tcb_pwm_device {
 	enum pwm_polarity polarity;	/* PWM polarity */
@@ -40,7 +47,11 @@ struct atmel_tcb_pwm_device {
 struct atmel_tcb_pwm_chip {
 	struct pwm_chip chip;
 	spinlock_t lock;
-	struct atmel_tc *tc;
+	u8 channel;
+	u8 width;
+	struct regmap *regmap;
+	struct clk *clk;
+	struct clk *slow_clk;
 	struct atmel_tcb_pwm_device *pwms[NPWM];
 };
 
@@ -65,10 +76,6 @@ static int atmel_tcb_pwm_request(struct pwm_chip *chip,
 {
 	struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip);
 	struct atmel_tcb_pwm_device *tcbpwm;
-	struct atmel_tc *tc = tcbpwmc->tc;
-	void __iomem *regs = tc->regs;
-	unsigned group = pwm->hwpwm / 2;
-	unsigned index = pwm->hwpwm % 2;
 	unsigned cmr;
 	int ret;
 
@@ -76,7 +83,7 @@ static int atmel_tcb_pwm_request(struct pwm_chip *chip,
 	if (!tcbpwm)
 		return -ENOMEM;
 
-	ret = clk_prepare_enable(tc->clk[group]);
+	ret = clk_prepare_enable(tcbpwmc->clk);
 	if (ret) {
 		devm_kfree(chip->dev, tcbpwm);
 		return ret;
@@ -89,28 +96,32 @@ static int atmel_tcb_pwm_request(struct pwm_chip *chip,
 	tcbpwm->div = 0;
 
 	spin_lock(&tcbpwmc->lock);
-	cmr = __raw_readl(regs + ATMEL_TC_REG(group, CMR));
+	regmap_read(tcbpwmc->regmap, ATMEL_TC_CMR(tcbpwmc->channel), &cmr);
 	/*
 	 * Get init config from Timer Counter registers if
 	 * Timer Counter is already configured as a PWM generator.
 	 */
-	if (cmr & ATMEL_TC_WAVE) {
-		if (index == 0)
-			tcbpwm->duty =
-				__raw_readl(regs + ATMEL_TC_REG(group, RA));
+	if (cmr & ATMEL_TC_CMR_WAVE) {
+		if (pwm->hwpwm == 0)
+			regmap_read(tcbpwmc->regmap,
+				    ATMEL_TC_RA(tcbpwmc->channel),
+				    &tcbpwm->duty);
 		else
-			tcbpwm->duty =
-				__raw_readl(regs + ATMEL_TC_REG(group, RB));
-
-		tcbpwm->div = cmr & ATMEL_TC_TCCLKS;
-		tcbpwm->period = __raw_readl(regs + ATMEL_TC_REG(group, RC));
-		cmr &= (ATMEL_TC_TCCLKS | ATMEL_TC_ACMR_MASK |
+			regmap_read(tcbpwmc->regmap,
+				    ATMEL_TC_RB(tcbpwmc->channel),
+				    &tcbpwm->duty);
+
+		tcbpwm->div = cmr & ATMEL_TC_CMR_TCLKS_MSK;
+		regmap_read(tcbpwmc->regmap, ATMEL_TC_RC(tcbpwmc->channel),
+			    &tcbpwm->period);
+		cmr &= (ATMEL_TC_CMR_TCLKS_MSK | ATMEL_TC_ACMR_MASK |
 			ATMEL_TC_BCMR_MASK);
 	} else
 		cmr = 0;
 
-	cmr |= ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO | ATMEL_TC_EEVT_XC0;
-	__raw_writel(cmr, regs + ATMEL_TC_REG(group, CMR));
+	cmr |= ATMEL_TC_CMR_WAVE | ATMEL_TC_CMR_WAVESEL_UPRC |
+	       ATMEL_TC_CMR_EEVT_XC(0);
+	regmap_write(tcbpwmc->regmap, ATMEL_TC_CMR(tcbpwmc->channel), cmr);
 	spin_unlock(&tcbpwmc->lock);
 
 	tcbpwmc->pwms[pwm->hwpwm] = tcbpwm;
@@ -122,9 +133,8 @@ static void atmel_tcb_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
 {
 	struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip);
 	struct atmel_tcb_pwm_device *tcbpwm = pwm_get_chip_data(pwm);
-	struct atmel_tc *tc = tcbpwmc->tc;
 
-	clk_disable_unprepare(tc->clk[pwm->hwpwm / 2]);
+	clk_disable_unprepare(tcbpwmc->clk);
 	tcbpwmc->pwms[pwm->hwpwm] = NULL;
 	devm_kfree(chip->dev, tcbpwm);
 }
@@ -133,10 +143,6 @@ static void atmel_tcb_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
 	struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip);
 	struct atmel_tcb_pwm_device *tcbpwm = pwm_get_chip_data(pwm);
-	struct atmel_tc *tc = tcbpwmc->tc;
-	void __iomem *regs = tc->regs;
-	unsigned group = pwm->hwpwm / 2;
-	unsigned index = pwm->hwpwm % 2;
 	unsigned cmr;
 	enum pwm_polarity polarity = tcbpwm->polarity;
 
@@ -152,35 +158,35 @@ static void atmel_tcb_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 		polarity = !polarity;
 
 	spin_lock(&tcbpwmc->lock);
-	cmr = __raw_readl(regs + ATMEL_TC_REG(group, CMR));
+	regmap_read(tcbpwmc->regmap, ATMEL_TC_CMR(tcbpwmc->channel), &cmr);
 
 	/* flush old setting and set the new one */
-	if (index == 0) {
+	if (pwm->hwpwm == 0) {
 		cmr &= ~ATMEL_TC_ACMR_MASK;
 		if (polarity == PWM_POLARITY_INVERSED)
-			cmr |= ATMEL_TC_ASWTRG_CLEAR;
+			cmr |= ATMEL_TC_CMR_ASWTRG(CLEAR);
 		else
-			cmr |= ATMEL_TC_ASWTRG_SET;
+			cmr |= ATMEL_TC_CMR_ASWTRG(SET);
 	} else {
 		cmr &= ~ATMEL_TC_BCMR_MASK;
 		if (polarity == PWM_POLARITY_INVERSED)
-			cmr |= ATMEL_TC_BSWTRG_CLEAR;
+			cmr |= ATMEL_TC_CMR_BSWTRG(CLEAR);
 		else
-			cmr |= ATMEL_TC_BSWTRG_SET;
+			cmr |= ATMEL_TC_CMR_BSWTRG(SET);
 	}
 
-	__raw_writel(cmr, regs + ATMEL_TC_REG(group, CMR));
+	regmap_write(tcbpwmc->regmap, ATMEL_TC_CMR(tcbpwmc->channel), cmr);
 
 	/*
 	 * Use software trigger to apply the new setting.
 	 * If both PWM devices in this group are disabled we stop the clock.
 	 */
-	if (!(cmr & (ATMEL_TC_ACPC | ATMEL_TC_BCPC)))
-		__raw_writel(ATMEL_TC_SWTRG | ATMEL_TC_CLKDIS,
-			     regs + ATMEL_TC_REG(group, CCR));
+	if (!(cmr & (ATMEL_TC_CMR_ACPC_MSK | ATMEL_TC_CMR_BCPC_MSK)))
+		regmap_write(tcbpwmc->regmap, ATMEL_TC_CCR(tcbpwmc->channel),
+			     ATMEL_TC_CCR_SWTRG | ATMEL_TC_CCR_CLKDIS);
 	else
-		__raw_writel(ATMEL_TC_SWTRG, regs +
-			     ATMEL_TC_REG(group, CCR));
+		regmap_write(tcbpwmc->regmap, ATMEL_TC_CCR(tcbpwmc->channel),
+			     ATMEL_TC_CCR_SWTRG);
 
 	spin_unlock(&tcbpwmc->lock);
 }
@@ -189,10 +195,6 @@ static int atmel_tcb_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 {
 	struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip);
 	struct atmel_tcb_pwm_device *tcbpwm = pwm_get_chip_data(pwm);
-	struct atmel_tc *tc = tcbpwmc->tc;
-	void __iomem *regs = tc->regs;
-	unsigned group = pwm->hwpwm / 2;
-	unsigned index = pwm->hwpwm % 2;
 	u32 cmr;
 	enum pwm_polarity polarity = tcbpwm->polarity;
 
@@ -208,25 +210,25 @@ static int atmel_tcb_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 		polarity = !polarity;
 
 	spin_lock(&tcbpwmc->lock);
-	cmr = __raw_readl(regs + ATMEL_TC_REG(group, CMR));
+	regmap_read(tcbpwmc->regmap, ATMEL_TC_CMR(tcbpwmc->channel), &cmr);
 
 	/* flush old setting and set the new one */
-	cmr &= ~ATMEL_TC_TCCLKS;
+	cmr &= ~ATMEL_TC_CMR_TCLKS_MSK;
 
-	if (index == 0) {
+	if (pwm->hwpwm == 0) {
 		cmr &= ~ATMEL_TC_ACMR_MASK;
 
 		/* Set CMR flags according to given polarity */
 		if (polarity == PWM_POLARITY_INVERSED)
-			cmr |= ATMEL_TC_ASWTRG_CLEAR;
+			cmr |= ATMEL_TC_CMR_ASWTRG(CLEAR);
 		else
-			cmr |= ATMEL_TC_ASWTRG_SET;
+			cmr |= ATMEL_TC_CMR_ASWTRG(SET);
 	} else {
 		cmr &= ~ATMEL_TC_BCMR_MASK;
 		if (polarity == PWM_POLARITY_INVERSED)
-			cmr |= ATMEL_TC_BSWTRG_CLEAR;
+			cmr |= ATMEL_TC_CMR_BSWTRG(CLEAR);
 		else
-			cmr |= ATMEL_TC_BSWTRG_SET;
+			cmr |= ATMEL_TC_CMR_BSWTRG(SET);
 	}
 
 	/*
@@ -236,33 +238,40 @@ static int atmel_tcb_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 	 * this config till next config call.
 	 */
 	if (tcbpwm->duty != tcbpwm->period && tcbpwm->duty > 0) {
-		if (index == 0) {
+		if (pwm->hwpwm == 0) {
 			if (polarity == PWM_POLARITY_INVERSED)
-				cmr |= ATMEL_TC_ACPA_SET | ATMEL_TC_ACPC_CLEAR;
+				cmr |= ATMEL_TC_CMR_ACPA(SET) |
+				       ATMEL_TC_CMR_ACPC(CLEAR);
 			else
-				cmr |= ATMEL_TC_ACPA_CLEAR | ATMEL_TC_ACPC_SET;
+				cmr |= ATMEL_TC_CMR_ACPA(CLEAR) |
+				       ATMEL_TC_CMR_ACPC(SET);
 		} else {
 			if (polarity == PWM_POLARITY_INVERSED)
-				cmr |= ATMEL_TC_BCPB_SET | ATMEL_TC_BCPC_CLEAR;
+				cmr |= ATMEL_TC_CMR_BCPB(SET) |
+				       ATMEL_TC_CMR_BCPC(CLEAR);
 			else
-				cmr |= ATMEL_TC_BCPB_CLEAR | ATMEL_TC_BCPC_SET;
+				cmr |= ATMEL_TC_CMR_BCPB(CLEAR) |
+				       ATMEL_TC_CMR_BCPC(SET);
 		}
 	}
 
-	cmr |= (tcbpwm->div & ATMEL_TC_TCCLKS);
+	cmr |= (tcbpwm->div & ATMEL_TC_CMR_TCLKS_MSK);
 
-	__raw_writel(cmr, regs + ATMEL_TC_REG(group, CMR));
+	regmap_write(tcbpwmc->regmap, ATMEL_TC_CMR(tcbpwmc->channel), cmr);
 
-	if (index == 0)
-		__raw_writel(tcbpwm->duty, regs + ATMEL_TC_REG(group, RA));
+	if (pwm->hwpwm == 0)
+		regmap_write(tcbpwmc->regmap, ATMEL_TC_RA(tcbpwmc->channel),
+			     tcbpwm->duty);
 	else
-		__raw_writel(tcbpwm->duty, regs + ATMEL_TC_REG(group, RB));
+		regmap_write(tcbpwmc->regmap, ATMEL_TC_RB(tcbpwmc->channel),
+			     tcbpwm->duty);
 
-	__raw_writel(tcbpwm->period, regs + ATMEL_TC_REG(group, RC));
+	regmap_write(tcbpwmc->regmap, ATMEL_TC_RC(tcbpwmc->channel),
+		     tcbpwm->period);
 
 	/* Use software trigger to apply the new setting */
-	__raw_writel(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG,
-		     regs + ATMEL_TC_REG(group, CCR));
+	regmap_write(tcbpwmc->regmap, ATMEL_TC_CCR(tcbpwmc->channel),
+		     ATMEL_TC_CCR_SWTRG | ATMEL_TC_CCR_CLKEN);
 	spin_unlock(&tcbpwmc->lock);
 	return 0;
 }
@@ -272,15 +281,12 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 {
 	struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip);
 	struct atmel_tcb_pwm_device *tcbpwm = pwm_get_chip_data(pwm);
-	unsigned group = pwm->hwpwm / 2;
-	unsigned index = pwm->hwpwm % 2;
 	struct atmel_tcb_pwm_device *atcbpwm = NULL;
-	struct atmel_tc *tc = tcbpwmc->tc;
 	int i;
 	int slowclk = 0;
 	unsigned period;
 	unsigned duty;
-	unsigned rate = clk_get_rate(tc->clk[group]);
+	unsigned rate = clk_get_rate(tcbpwmc->clk);
 	unsigned long long min;
 	unsigned long long max;
 
@@ -294,7 +300,7 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 			continue;
 		}
 		min = div_u64((u64)NSEC_PER_SEC * atmel_tc_divisors[i], rate);
-		max = min << tc->tcb_config->counter_width;
+		max = min << tcbpwmc->width;
 		if (max >= period_ns)
 			break;
 	}
@@ -305,9 +311,9 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 	 */
 	if (i == 5) {
 		i = slowclk;
-		rate = clk_get_rate(tc->slow_clk);
+		rate = clk_get_rate(tcbpwmc->slow_clk);
 		min = div_u64(NSEC_PER_SEC, rate);
-		max = min << tc->tcb_config->counter_width;
+		max = min << tcbpwmc->width;
 
 		/* If period is too big return ERANGE error */
 		if (max < period_ns)
@@ -317,17 +323,13 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 	duty = div_u64(duty_ns, min);
 	period = div_u64(period_ns, min);
 
-	if (index == 0)
-		atcbpwm = tcbpwmc->pwms[pwm->hwpwm + 1];
+	if (pwm->hwpwm == 0)
+		atcbpwm = tcbpwmc->pwms[1];
 	else
-		atcbpwm = tcbpwmc->pwms[pwm->hwpwm - 1];
+		atcbpwm = tcbpwmc->pwms[0];
 
 	/*
-	 * PWM devices provided by TCB driver are grouped by 2:
-	 * - group 0: PWM 0 & 1
-	 * - group 1: PWM 2 & 3
-	 * - group 2: PWM 4 & 5
-	 *
+	 * PWM devices provided by the TCB driver are grouped by 2.
 	 * PWM devices in a given group must be configured with the
 	 * same period_ns.
 	 *
@@ -365,31 +367,40 @@ static const struct pwm_ops atmel_tcb_pwm_ops = {
 
 static int atmel_tcb_pwm_probe(struct platform_device *pdev)
 {
+	const struct of_device_id *match;
 	struct atmel_tcb_pwm_chip *tcbpwm;
 	struct device_node *np = pdev->dev.of_node;
-	struct atmel_tc *tc;
+	struct regmap *regmap;
+	struct clk *clk;
+	struct clk *slow_clk;
 	int err;
-	int tcblock;
+	int channel;
 
-	err = of_property_read_u32(np, "tc-block", &tcblock);
+	err = of_property_read_u32(np, "reg", &channel);
 	if (err < 0) {
 		dev_err(&pdev->dev,
-			"failed to get Timer Counter Block number from device tree (error: %d)\n",
+			"failed to get Timer Counter Block channel from device tree (error: %d)\n",
 			err);
 		return err;
 	}
 
-	tc = atmel_tc_alloc(tcblock);
-	if (tc == NULL) {
-		dev_err(&pdev->dev, "failed to allocate Timer Counter Block\n");
-		return -ENOMEM;
-	}
+	regmap = syscon_node_to_regmap(np->parent);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	slow_clk = of_clk_get_by_name(np->parent, "slow_clk");
+	if (IS_ERR(slow_clk))
+		return PTR_ERR(slow_clk);
+
+	clk = tcb_clk_get(np, channel);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
 
 	tcbpwm = devm_kzalloc(&pdev->dev, sizeof(*tcbpwm), GFP_KERNEL);
 	if (tcbpwm == NULL) {
 		err = -ENOMEM;
 		dev_err(&pdev->dev, "failed to allocate memory\n");
-		goto err_free_tc;
+		goto err_slow_clk;
 	}
 
 	tcbpwm->chip.dev = &pdev->dev;
@@ -398,11 +409,17 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev)
 	tcbpwm->chip.of_pwm_n_cells = 3;
 	tcbpwm->chip.base = -1;
 	tcbpwm->chip.npwm = NPWM;
-	tcbpwm->tc = tc;
+	tcbpwm->channel = channel;
+	tcbpwm->regmap = regmap;
+	tcbpwm->clk = clk;
+	tcbpwm->slow_clk = slow_clk;
 
-	err = clk_prepare_enable(tc->slow_clk);
+	match = of_match_node(atmel_tcb_dt_ids, np->parent);
+	tcbpwm->width = (int)match->data;
+
+	err = clk_prepare_enable(slow_clk);
 	if (err)
-		goto err_free_tc;
+		goto err_slow_clk;
 
 	spin_lock_init(&tcbpwm->lock);
 
@@ -415,10 +432,10 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev)
 	return 0;
 
 err_disable_clk:
-	clk_disable_unprepare(tcbpwm->tc->slow_clk);
+	clk_disable_unprepare(tcbpwm->slow_clk);
 
-err_free_tc:
-	atmel_tc_free(tc);
+err_slow_clk:
+	clk_put(slow_clk);
 
 	return err;
 }
@@ -428,14 +445,14 @@ static int atmel_tcb_pwm_remove(struct platform_device *pdev)
 	struct atmel_tcb_pwm_chip *tcbpwm = platform_get_drvdata(pdev);
 	int err;
 
-	clk_disable_unprepare(tcbpwm->tc->slow_clk);
+	clk_disable_unprepare(tcbpwm->slow_clk);
+	clk_put(tcbpwm->slow_clk);
+	clk_put(tcbpwm->clk);
 
 	err = pwmchip_remove(&tcbpwm->chip);
 	if (err < 0)
 		return err;
 
-	atmel_tc_free(tcbpwm->tc);
-
 	return 0;
 }
 
-- 
2.8.1

[PATCH 45/48] ARM: at91/defconfig: sama5: unselect ATMEL_PIT

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:05:38

The PIT is not required anymore to successfully boot and may actually harm
in case preempt-rt is used because the PIT interrupt is shared.
Disable it so the TCB clocksource is used.

Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/configs/sama5_defconfig | 1 +
 1 file changed, 1 insertion(+)
diff --git a/arch/arm/configs/sama5_defconfig b/arch/arm/configs/sama5_defconfig
index 9cb1a85bb166..c17a13487bea 100644
--- a/arch/arm/configs/sama5_defconfig
+++ b/arch/arm/configs/sama5_defconfig
@@ -192,6 +192,7 @@ CONFIG_RTC_DRV_AT91RM9200=y
 CONFIG_DMADEVICES=y
 CONFIG_AT_HDMAC=y
 CONFIG_AT_XDMAC=y
+# CONFIG_ATMEL_PIT is not set
 # CONFIG_IOMMU_SUPPORT is not set
 CONFIG_IIO=y
 CONFIG_AT91_ADC=y
-- 
2.8.1

[PATCH 44/48] clocksource: atmel-pit: allow unselecting ATMEL_PIT

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:05:39

With the new TCB clocksource driver, atmel platforms are now able to boot
without the PIT driver. Allow unselecting it.

Cc: Daniel Lezcano <redacted>
Cc: Thomas Gleixner <redacted>
Signed-off-by: Alexandre Belloni <redacted>
---
 drivers/clocksource/Kconfig | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 1860f6f9b380..c651661bf43c 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -251,7 +251,14 @@ config ARMV7M_SYSTICK
 
 config ATMEL_PIT
 	select CLKSRC_OF if OF
-	def_bool SOC_AT91SAM9 || SOC_SAMA5
+	bool "Atmel Periodic Interval Timer (PIT)"
+	depends on SOC_AT91SAM9 || SOC_SAMA5
+	default SOC_AT91SAM9 || SOC_SAMA5
+	help
+	  Select this to get a clocksource based on the Atmel Periodic Interval
+	  Timer. It has a relatively low resolution and the TC Block clocksource
+	  should be preferred.
+	  It also provides a clock event device.
 
 config ATMEL_ST
 	bool
-- 
2.8.1

[PATCH 43/48] clocksource/drivers: Add a clockevent driver for Atmel TC blocks

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:05:40

Add an independent clockevent driver for the Atmel Timer Counter Blocks.
This driver provides a single clockevent device. using its own TCB channel.

Cc: Daniel Lezcano <redacted>
Cc: Thomas Gleixner <redacted>
Signed-off-by: Alexandre Belloni <redacted>
---
 drivers/clocksource/Kconfig                 |  10 ++
 drivers/clocksource/Makefile                |   1 +
 drivers/clocksource/timer-atmel-tcbclkevt.c | 220 ++++++++++++++++++++++++++++
 3 files changed, 231 insertions(+)
 create mode 100644 drivers/clocksource/timer-atmel-tcbclkevt.c
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index ff7f4022c749..1860f6f9b380 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -271,6 +271,16 @@ config ATMEL_ARM_TCB_CLKSRC
 	  to make a single 32-bit timer.
 	  It can also be used as a clock event device supporting oneshot mode.
 
+config ATMEL_ARM_TCB_CLKEVT
+	bool "TC Block Clockevent"
+	select REGMAP_MMIO
+	depends on GENERIC_CLOCKEVENTS
+	depends on SOC_AT91RM9200 || SOC_AT91SAM9 || SOC_SAMA5
+	default SOC_AT91RM9200 || SOC_AT91SAM9 || SOC_SAMA5
+	help
+	  Select this to get a high precision clockevent device based on a TC
+	  Block with the slow clock as its input.
+
 config CLKSRC_METAG_GENERIC
 	def_bool y if METAG
 	help
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 988f33de5808..c4a4155ccedc 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -3,6 +3,7 @@ obj-$(CONFIG_ATMEL_PIT)		+= timer-atmel-pit.o
 obj-$(CONFIG_ATMEL_ST)		+= timer-atmel-st.o
 obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o
 obj-$(CONFIG_ATMEL_ARM_TCB_CLKSRC)	+= timer-atmel-tcbclksrc.o
+obj-$(CONFIG_ATMEL_ARM_TCB_CLKEVT)	+= timer-atmel-tcbclkevt.o
 obj-$(CONFIG_X86_PM_TIMER)	+= acpi_pm.o
 obj-$(CONFIG_SCx200HR_TIMER)	+= scx200_hrt.o
 obj-$(CONFIG_CS5535_CLOCK_EVENT_SRC)	+= cs5535-clockevt.o
diff --git a/drivers/clocksource/timer-atmel-tcbclkevt.c b/drivers/clocksource/timer-atmel-tcbclkevt.c
new file mode 100644
index 000000000000..71440fd27b49
--- /dev/null
+++ b/drivers/clocksource/timer-atmel-tcbclkevt.c
@@ -0,0 +1,220 @@
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <soc/at91/atmel_tcb.h>
+
+struct tc_clkevt_device {
+	struct clock_event_device clkevt;
+	struct regmap *regmap;
+	struct clk *slow_clk;
+	struct clk *clk;
+	int channel;
+	int irq;
+};
+
+static struct tc_clkevt_device *to_tc_clkevt(struct clock_event_device *clkevt)
+{
+	return container_of(clkevt, struct tc_clkevt_device, clkevt);
+}
+
+static int tc_shutdown(struct clock_event_device *d)
+{
+	struct tc_clkevt_device *tcd = to_tc_clkevt(d);
+
+	regmap_write(tcd->regmap, ATMEL_TC_IDR(tcd->channel), 0xff);
+	regmap_write(tcd->regmap, ATMEL_TC_CCR(tcd->channel),
+		     ATMEL_TC_CCR_CLKDIS);
+	if (!clockevent_state_detached(d))
+		clk_disable(tcd->clk);
+
+	return 0;
+}
+
+/* For now, we always use the 32K clock ... this optimizes for NO_HZ,
+ * because using one of the divided clocks would usually mean the
+ * tick rate can never be less than several dozen Hz (vs 0.5 Hz).
+ *
+ * A divided clock could be good for high resolution timers, since
+ * 30.5 usec resolution can seem "low".
+ */
+static int tc_set_oneshot(struct clock_event_device *d)
+{
+	struct tc_clkevt_device *tcd = to_tc_clkevt(d);
+
+	if (clockevent_state_oneshot(d) || clockevent_state_periodic(d))
+		tc_shutdown(d);
+
+	clk_enable(tcd->clk);
+
+	/* slow clock, count up to RC, then irq and stop */
+	regmap_write(tcd->regmap, ATMEL_TC_CMR(tcd->channel),
+		     ATMEL_TC_CMR_TCLK(4) | ATMEL_TC_CMR_CPCSTOP |
+		     ATMEL_TC_CMR_WAVE | ATMEL_TC_CMR_WAVESEL_UPRC);
+	regmap_write(tcd->regmap, ATMEL_TC_IER(tcd->channel),
+		     ATMEL_TC_CPCS);
+
+	return 0;
+}
+
+static int tc_set_periodic(struct clock_event_device *d)
+{
+	struct tc_clkevt_device *tcd = to_tc_clkevt(d);
+
+	if (clockevent_state_oneshot(d) || clockevent_state_periodic(d))
+		tc_shutdown(d);
+
+	/* By not making the gentime core emulate periodic mode on top
+	 * of oneshot, we get lower overhead and improved accuracy.
+	 */
+	clk_enable(tcd->clk);
+
+	/* slow clock, count up to RC, then irq and restart */
+	regmap_write(tcd->regmap, ATMEL_TC_CMR(tcd->channel),
+		     ATMEL_TC_CMR_TCLK(4) | ATMEL_TC_CMR_WAVE |
+		     ATMEL_TC_CMR_WAVESEL_UPRC);
+	regmap_write(tcd->regmap, ATMEL_TC_RC(tcd->channel),
+		     (32768 + HZ / 2) / HZ);
+
+	/* Enable clock and interrupts on RC compare */
+	regmap_write(tcd->regmap, ATMEL_TC_IER(tcd->channel), ATMEL_TC_CPCS);
+	regmap_write(tcd->regmap, ATMEL_TC_CCR(tcd->channel),
+		     ATMEL_TC_CCR_CLKEN | ATMEL_TC_CCR_SWTRG);
+
+	return 0;
+}
+
+static int tc_next_event(unsigned long delta, struct clock_event_device *d)
+{
+	struct tc_clkevt_device *tcd = to_tc_clkevt(d);
+
+	regmap_write(tcd->regmap, ATMEL_TC_RC(tcd->channel), delta);
+	regmap_write(tcd->regmap, ATMEL_TC_CCR(tcd->channel),
+		     ATMEL_TC_CCR_CLKEN | ATMEL_TC_CCR_SWTRG);
+
+	return 0;
+}
+
+static struct tc_clkevt_device clkevt = {
+	.clkevt	= {
+		.features		= CLOCK_EVT_FEAT_PERIODIC |
+					  CLOCK_EVT_FEAT_ONESHOT,
+		/* Should be lower than at91rm9200's system timer */
+		.rating			= 140,
+		.set_next_event		= tc_next_event,
+		.set_state_shutdown	= tc_shutdown,
+		.set_state_periodic	= tc_set_periodic,
+		.set_state_oneshot	= tc_set_oneshot,
+	},
+};
+
+static irqreturn_t tc_clkevt_irq(int irq, void *handle)
+{
+	struct tc_clkevt_device	*tcd = handle;
+	unsigned int		sr;
+
+	regmap_read(tcd->regmap, ATMEL_TC_SR(tcd->channel), &sr);
+	if (sr & ATMEL_TC_CPCS) {
+		tcd->clkevt.event_handler(&tcd->clkevt);
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
+static int tcb_clkevt_probe(struct platform_device *pdev)
+{
+	struct tc_clkevt_device *tcd = &clkevt;
+	int ret;
+	struct device_node *node = pdev->dev.of_node;
+
+	ret = of_property_read_u32_index(node, "reg", 0, &tcd->channel);
+	if (ret)
+		return ret;
+
+	tcd->irq = tcb_irq_get(node, tcd->channel);
+	if (tcd->irq < 0)
+		return tcd->irq;
+
+	tcd->regmap = syscon_node_to_regmap(node->parent);
+	if (IS_ERR(tcd->regmap))
+		return PTR_ERR(tcd->regmap);
+
+	tcd->slow_clk = of_clk_get_by_name(node->parent, "slow_clk");
+	if (IS_ERR(tcd->slow_clk))
+		return PTR_ERR(tcd->slow_clk);
+
+	ret = clk_prepare_enable(tcd->slow_clk);
+	if (ret)
+		return ret;
+
+	tcd->clk = tcb_clk_get(node, tcd->channel);
+	if (IS_ERR(tcd->clk)) {
+		ret = PTR_ERR(tcd->clk);
+		goto err_slow;
+	}
+
+	clkevt.clkevt.name = dev_name(&pdev->dev);
+
+	/* try to enable clk to avoid future errors in mode change */
+	ret = clk_prepare_enable(tcd->clk);
+	if (ret)
+		goto err_slow;
+
+	clk_disable(tcd->clk);
+
+	clkevt.clkevt.cpumask = cpumask_of(0);
+
+	clockevents_config_and_register(&clkevt.clkevt, 32768, 1, 0xffff);
+
+	ret = request_irq(tcd->irq, tc_clkevt_irq, IRQF_TIMER | IRQF_SHARED,
+			  clkevt.clkevt.name, &clkevt);
+	if (ret)
+		goto err_clk;
+
+	return 0;
+
+err_clk:
+	clk_unprepare(tcd->clk);
+err_slow:
+	clk_disable_unprepare(tcd->slow_clk);
+
+	return ret;
+}
+
+static const struct of_device_id atmel_tcb_clkevt_dt_ids[] = {
+	{ .compatible = "atmel,tcb-clkevt" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, atmel_tcb_clkevt_dt_ids);
+
+static struct platform_driver tcb_clkevt_driver = {
+	.probe		= tcb_clkevt_probe,
+	.driver         = {
+		.name   = "atmel_tcb_clkevt",
+		.of_match_table = of_match_ptr(atmel_tcb_clkevt_dt_ids),
+	},
+};
+
+static int __init atmel_tcb_clkevt_init(void)
+{
+	return platform_driver_register(&tcb_clkevt_driver);
+}
+
+static void __exit atmel_tcb_clkevt_exit(void)
+{
+	platform_driver_unregister(&tcb_clkevt_driver);
+}
+
+early_platform_init("earlytimer", &tcb_clkevt_driver);
+subsys_initcall(atmel_tcb_clkevt_init);
+module_exit(atmel_tcb_clkevt_exit);
+
+MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@free-electrons.com>");
+MODULE_DESCRIPTION("Clockevents driver for Atmel Timer Counter Blocks");
+MODULE_LICENSE("GPL v2");
-- 
2.8.1

[PATCH 42/48] clocksource/drivers: Add a new driver for the Atmel ARM TC blocks

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:05:42

Add a driver for the Atmel Timer Counter Blocks. This driver provides a
clocksource and a clockevent device. The clockevent device is linked to the
clocksource counter and so it will run at the same frequency.

This driver uses regmap and syscon to be able to probe early in the boot
and avoid having to switch on the TCB clocksource later. Using regmap also
means that unused TCB channels may be used by other drivers (PWM for
example).

Cc: Daniel Lezcano <redacted>
Cc: Thomas Gleixner <redacted>
Signed-off-by: Alexandre Belloni <redacted>
---
 drivers/clocksource/Kconfig                 |  13 ++
 drivers/clocksource/Makefile                |   3 +-
 drivers/clocksource/timer-atmel-tcbclksrc.c | 305 ++++++++++++++++++++++++++++
 include/soc/at91/atmel_tcb.h                | 220 ++++++++++++++++++++
 4 files changed, 540 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clocksource/timer-atmel-tcbclksrc.c
 create mode 100644 include/soc/at91/atmel_tcb.h
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 47352d25c15e..ff7f4022c749 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -258,6 +258,19 @@ config ATMEL_ST
 	select CLKSRC_OF
 	select MFD_SYSCON
 
+config ATMEL_ARM_TCB_CLKSRC
+	bool "TC Block Clocksource"
+	select REGMAP_MMIO
+	depends on GENERIC_CLOCKEVENTS
+	depends on SOC_AT91RM9200 || SOC_AT91SAM9 || SOC_SAMA5
+	default SOC_AT91RM9200 || SOC_AT91SAM9 || SOC_SAMA5
+	help
+	  Select this to get a high precision clocksource based on a
+	  TC block with a 5+ MHz base clock rate.
+	  On platforms with 16-bit counters, two timer channels are combined
+	  to make a single 32-bit timer.
+	  It can also be used as a clock event device supporting oneshot mode.
+
 config CLKSRC_METAG_GENERIC
 	def_bool y if METAG
 	help
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 473974f9590a..988f33de5808 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -1,7 +1,8 @@
 obj-$(CONFIG_CLKSRC_PROBE)	+= clksrc-probe.o
 obj-$(CONFIG_ATMEL_PIT)		+= timer-atmel-pit.o
 obj-$(CONFIG_ATMEL_ST)		+= timer-atmel-st.o
-obj-$(CONFIG_ATMEL_TCB_CLKSRC)	+= tcb_clksrc.o
+obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o
+obj-$(CONFIG_ATMEL_ARM_TCB_CLKSRC)	+= timer-atmel-tcbclksrc.o
 obj-$(CONFIG_X86_PM_TIMER)	+= acpi_pm.o
 obj-$(CONFIG_SCx200HR_TIMER)	+= scx200_hrt.o
 obj-$(CONFIG_CS5535_CLOCK_EVENT_SRC)	+= cs5535-clockevt.o
diff --git a/drivers/clocksource/timer-atmel-tcbclksrc.c b/drivers/clocksource/timer-atmel-tcbclksrc.c
new file mode 100644
index 000000000000..af0b1aab7a98
--- /dev/null
+++ b/drivers/clocksource/timer-atmel-tcbclksrc.c
@@ -0,0 +1,305 @@
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_irq.h>
+#include <linux/regmap.h>
+#include <linux/sched_clock.h>
+#include <soc/at91/atmel_tcb.h>
+
+struct atmel_tcb_clksrc {
+	struct clocksource clksrc;
+	struct clock_event_device clkevt;
+	struct regmap *regmap;
+	struct clk *clk[2];
+	int channels[2];
+	u8 bits;
+	unsigned int irq;
+	bool registered;
+	bool irq_requested;
+};
+
+static struct atmel_tcb_clksrc tc = {
+	.clksrc = {
+		.name		= "tcb_clksrc",
+		.rating		= 200,
+		.mask		= CLOCKSOURCE_MASK(32),
+		.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
+	},
+	.clkevt	= {
+		.name			= "tcb_clkevt",
+		.features		= CLOCK_EVT_FEAT_ONESHOT,
+		/* Should be lower than at91rm9200's system timer */
+		.rating			= 125,
+	},
+};
+
+static cycle_t tc_get_cycles(struct clocksource *cs)
+{
+	unsigned long	flags;
+	u32		lower, upper, tmp;
+
+	raw_local_irq_save(flags);
+	do {
+		regmap_read(tc.regmap, ATMEL_TC_CV(1), &upper);
+		regmap_read(tc.regmap, ATMEL_TC_CV(0), &lower);
+		regmap_read(tc.regmap, ATMEL_TC_CV(1), &tmp);
+	} while (upper != tmp);
+
+	raw_local_irq_restore(flags);
+	return (upper << 16) | lower;
+}
+
+static cycle_t tc_get_cycles32(struct clocksource *cs)
+{
+	u32 val;
+
+	regmap_read(tc.regmap, ATMEL_TC_CV(tc.channels[0]), &val);
+
+	return val;
+}
+
+static u64 tc_sched_clock_read(void)
+{
+	return tc_get_cycles(&tc.clksrc);
+}
+
+static u64 tc_sched_clock_read32(void)
+{
+	return tc_get_cycles32(&tc.clksrc);
+}
+
+static int tcb_clkevt_next_event(unsigned long delta,
+				 struct clock_event_device *d)
+{
+	u32 val;
+
+	regmap_read(tc.regmap, ATMEL_TC_CV(tc.channels[0]), &val);
+	regmap_write(tc.regmap, ATMEL_TC_RC(tc.channels[0]), val + delta);
+	regmap_write(tc.regmap, ATMEL_TC_IER(tc.channels[0]), ATMEL_TC_CPCS);
+
+	return 0;
+}
+
+static irqreturn_t tc_clkevt_irq(int irq, void *handle)
+{
+	unsigned int sr;
+
+	regmap_read(tc.regmap, ATMEL_TC_SR(tc.channels[0]), &sr);
+	if (sr & ATMEL_TC_CPCS) {
+		tc.clkevt.event_handler(&tc.clkevt);
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
+static int tcb_clkevt_oneshot(struct clock_event_device *dev)
+{
+	int ret;
+
+	if (tc.irq_requested)
+		return 0;
+
+	ret = request_irq(tc.irq, tc_clkevt_irq, IRQF_TIMER | IRQF_SHARED,
+			  "tcb_clkevt", &tc);
+	if (!ret)
+		tc.irq_requested = true;
+
+	return ret;
+}
+
+static int tcb_clkevt_shutdown(struct clock_event_device *dev)
+{
+	regmap_write(tc.regmap, ATMEL_TC_IDR(tc.channels[0]), 0xff);
+	if (tc.bits == 16)
+		regmap_write(tc.regmap, ATMEL_TC_IDR(tc.channels[1]), 0xff);
+
+	if (tc.irq_requested) {
+		free_irq(tc.irq, &tc);
+		tc.irq_requested = false;
+	}
+
+	return 0;
+}
+
+static void __init tcb_setup_dual_chan(struct atmel_tcb_clksrc *tc,
+				       int mck_divisor_idx)
+{
+	/* first channel: waveform mode, input mclk/8, clock TIOA on overflow */
+	regmap_write(tc->regmap, ATMEL_TC_CMR(tc->channels[0]),
+		     mck_divisor_idx	/* likely divide-by-8 */
+			| ATMEL_TC_CMR_WAVE
+			| ATMEL_TC_CMR_WAVESEL_UP	/* free-run */
+			| ATMEL_TC_CMR_ACPA(SET)	/* TIOA rises at 0 */
+			| ATMEL_TC_CMR_ACPC(CLEAR));	/* (duty cycle 50%) */
+	regmap_write(tc->regmap, ATMEL_TC_RA(tc->channels[0]), 0x0000);
+	regmap_write(tc->regmap, ATMEL_TC_RC(tc->channels[0]), 0x8000);
+	regmap_write(tc->regmap, ATMEL_TC_IDR(tc->channels[0]), 0xff);	/* no irqs */
+	regmap_write(tc->regmap, ATMEL_TC_CCR(tc->channels[0]),
+		     ATMEL_TC_CCR_CLKEN);
+
+	/* second channel: waveform mode, input TIOA */
+	regmap_write(tc->regmap, ATMEL_TC_CMR(tc->channels[1]),
+		     ATMEL_TC_CMR_XC(tc->channels[1])	/* input: TIOA */
+		     | ATMEL_TC_CMR_WAVE
+		     | ATMEL_TC_CMR_WAVESEL_UP);	/* free-run */
+	regmap_write(tc->regmap, ATMEL_TC_IDR(tc->channels[1]), 0xff);	/* no irqs */
+	regmap_write(tc->regmap, ATMEL_TC_CCR(tc->channels[1]),
+		     ATMEL_TC_CCR_CLKEN);
+
+	/* chain both channel, we assume the previous channel */
+	regmap_write(tc->regmap, ATMEL_TC_BMR,
+		     ATMEL_TC_BMR_TCXC(1 + tc->channels[1], tc->channels[1]));
+	/* then reset all the timers */
+	regmap_write(tc->regmap, ATMEL_TC_BCR, ATMEL_TC_BCR_SYNC);
+}
+
+static void __init tcb_setup_single_chan(struct atmel_tcb_clksrc *tc,
+					 int mck_divisor_idx)
+{
+	/* channel 0:  waveform mode, input mclk/8 */
+	regmap_write(tc->regmap, ATMEL_TC_CMR(tc->channels[0]),
+		     mck_divisor_idx	/* likely divide-by-8 */
+			| ATMEL_TC_CMR_WAVE
+			| ATMEL_TC_CMR_WAVESEL_UP	/* free-run */
+			);
+	regmap_write(tc->regmap, ATMEL_TC_IDR(tc->channels[0]), 0xff);	/* no irqs */
+	regmap_write(tc->regmap, ATMEL_TC_CCR(tc->channels[0]),
+		     ATMEL_TC_CCR_CLKEN);
+
+	/* then reset all the timers */
+	regmap_write(tc->regmap, ATMEL_TC_BCR, ATMEL_TC_BCR_SYNC);
+}
+
+static void __init tcb_clksrc_init(struct device_node *node)
+{
+	const struct of_device_id *match;
+	u32 rate, divided_rate = 0;
+	int best_divisor_idx = -1;
+	int i, err;
+
+	if (tc.registered)
+		return;
+
+	tc.regmap = syscon_node_to_regmap(node->parent);
+	if (IS_ERR(tc.regmap))
+		return;
+
+	match = of_match_node(atmel_tcb_dt_ids, node->parent);
+	tc.bits = (int)match->data;
+
+	err = of_property_read_u32_index(node, "reg", 0, &tc.channels[0]);
+	if (err)
+		return;
+
+	tc.channels[1] = -1;
+
+	if (tc.bits == 16) {
+		of_property_read_u32_index(node, "reg", 1, &tc.channels[1]);
+		if (tc.channels[1] == -1) {
+			pr_err("%s: clocksource needs two channels\n",
+			       node->parent->full_name);
+		}
+	}
+
+	tc.irq = tcb_irq_get(node, tc.channels[0]);
+	if (tc.irq < 0)
+		return;
+
+	tc.clk[0] = tcb_clk_get(node, tc.channels[0]);
+	if (IS_ERR(tc.clk[0]))
+		return;
+	err = clk_prepare_enable(tc.clk[0]);
+	if (err) {
+		pr_debug("can't enable T0 clk\n");
+		goto err_clk;
+	}
+
+	if (tc.bits == 16) {
+		tc.clk[1] = tcb_clk_get(node, tc.channels[1]);
+		if (IS_ERR(tc.clk[1]))
+			goto err_disable_t0;
+	}
+
+	/* How fast will we be counting?  Pick something over 5 MHz.  */
+	rate = (u32)clk_get_rate(tc.clk[0]);
+	for (i = 0; i < 5; i++) {
+		unsigned int divisor = atmel_tc_divisors[i];
+		unsigned int tmp;
+
+		if (!divisor)
+			continue;
+
+		tmp = rate / divisor;
+		pr_debug("TC: %u / %-3u [%d] --> %u\n", rate, divisor, i, tmp);
+		if (best_divisor_idx > 0) {
+			if (tmp < 5 * 1000 * 1000)
+				continue;
+		}
+		divided_rate = tmp;
+		best_divisor_idx = i;
+	}
+
+	pr_debug("%s: %s@%d.%03d MHz\n", tc.clksrc.name,
+		 node->parent->full_name, divided_rate / 1000000,
+		 ((divided_rate + 500000) % 1000000) / 1000);
+
+	if (tc.bits == 32) {
+		tc.clksrc.read = tc_get_cycles32;
+		tcb_setup_single_chan(&tc, best_divisor_idx);
+	} else {
+		err = clk_prepare_enable(tc.clk[1]);
+		if (err) {
+			pr_debug("can't enable T1 clk\n");
+			goto err_clk1;
+		}
+		tc.clksrc.read = tc_get_cycles,
+		tcb_setup_dual_chan(&tc, best_divisor_idx);
+	}
+
+	err = clocksource_register_hz(&tc.clksrc, divided_rate);
+	if (err)
+		goto err_disable_t1;
+
+	if (tc.bits == 32)
+		sched_clock_register(tc_sched_clock_read32, 32, divided_rate);
+	else
+		sched_clock_register(tc_sched_clock_read, 32, divided_rate);
+
+	tc.registered = true;
+
+	/* Set up and register clockevents */
+	tc.clkevt.cpumask = cpumask_of(0);
+	tc.clkevt.set_next_event = tcb_clkevt_next_event;
+	tc.clkevt.set_state_oneshot = tcb_clkevt_oneshot;
+	tc.clkevt.set_state_shutdown = tcb_clkevt_shutdown;
+	if (tc.bits == 16)
+		clockevents_config_and_register(&tc.clkevt, divided_rate, 1,
+						0xffff);
+	else
+		clockevents_config_and_register(&tc.clkevt, divided_rate, 1,
+						0xffffffff);
+	return;
+
+err_disable_t1:
+	if (tc.bits == 16)
+		clk_disable_unprepare(tc.clk[1]);
+
+err_clk1:
+	if (tc.bits == 16)
+		clk_put(tc.clk[1]);
+
+err_disable_t0:
+	clk_disable_unprepare(tc.clk[0]);
+
+err_clk:
+	clk_put(tc.clk[0]);
+
+	pr_err("%s: unable to register clocksource/clockevent\n",
+	       tc.clksrc.name);
+}
+CLOCKSOURCE_OF_DECLARE(atmel_tcb_clksrc, "atmel,tcb-clksrc",
+		       tcb_clksrc_init);
diff --git a/include/soc/at91/atmel_tcb.h b/include/soc/at91/atmel_tcb.h
new file mode 100644
index 000000000000..ceb279810ce4
--- /dev/null
+++ b/include/soc/at91/atmel_tcb.h
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2016 Atmel
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __SOC_ATMEL_TCB_H
+#define __SOC_ATMEL_TCB_H
+
+/* Channel registers */
+#define ATMEL_TC_COFFS(c)		((c) * 0x40)
+#define ATMEL_TC_CCR(c)			ATMEL_TC_COFFS(c)
+#define ATMEL_TC_CMR(c)			(ATMEL_TC_COFFS(c) + 0x4)
+#define ATMEL_TC_SMMR(c)		(ATMEL_TC_COFFS(c) + 0x8)
+#define ATMEL_TC_RAB(c)			(ATMEL_TC_COFFS(c) + 0xc)
+#define ATMEL_TC_CV(c)			(ATMEL_TC_COFFS(c) + 0x10)
+#define ATMEL_TC_RA(c)			(ATMEL_TC_COFFS(c) + 0x14)
+#define ATMEL_TC_RB(c)			(ATMEL_TC_COFFS(c) + 0x18)
+#define ATMEL_TC_RC(c)			(ATMEL_TC_COFFS(c) + 0x1c)
+#define ATMEL_TC_SR(c)			(ATMEL_TC_COFFS(c) + 0x20)
+#define ATMEL_TC_IER(c)			(ATMEL_TC_COFFS(c) + 0x24)
+#define ATMEL_TC_IDR(c)			(ATMEL_TC_COFFS(c) + 0x28)
+#define ATMEL_TC_IMR(c)			(ATMEL_TC_COFFS(c) + 0x2c)
+#define ATMEL_TC_EMR(c)			(ATMEL_TC_COFFS(c) + 0x30)
+
+/* Block registers */
+#define ATMEL_TC_BCR			0xc0
+#define ATMEL_TC_BMR			0xc4
+#define ATMEL_TC_QIER			0xc8
+#define ATMEL_TC_QIDR			0xcc
+#define ATMEL_TC_QIMR			0xd0
+#define ATMEL_TC_QISR			0xd4
+#define ATMEL_TC_FMR			0xd8
+#define ATMEL_TC_WPMR			0xe4
+
+/* CCR fields */
+#define ATMEL_TC_CCR_CLKEN		BIT(0)
+#define ATMEL_TC_CCR_CLKDIS		BIT(1)
+#define ATMEL_TC_CCR_SWTRG		BIT(2)
+
+/* Common CMR fields */
+#define ATMEL_TC_CMR_TCLKS_MSK		GENMASK(2, 0)
+#define ATMEL_TC_CMR_TCLK(x)		(x)
+#define ATMEL_TC_CMR_XC(x)		((x) + 5)
+#define ATMEL_TC_CMR_CLKI		BIT(3)
+#define ATMEL_TC_CMR_BURST_MSK		GENMASK(5, 4)
+#define ATMEL_TC_CMR_BURST_XC(x)	(((x) + 1) << 4)
+#define ATMEL_TC_CMR_WAVE		BIT(15)
+
+/* Capture mode CMR fields */
+#define ATMEL_TC_CMR_LDBSTOP		BIT(6)
+#define ATMEL_TC_CMR_LDBDIS		BIT(7)
+#define ATMEL_TC_CMR_ETRGEDG_MSK	GENMASK(9, 8)
+#define ATMEL_TC_CMR_ETRGEDG_NONE	(0 << 8)
+#define ATMEL_TC_CMR_ETRGEDG_RISING	(1 << 8)
+#define ATMEL_TC_CMR_ETRGEDG_FALLING	(2 << 8)
+#define ATMEL_TC_CMR_ETRGEDG_BOTH	(3 << 8)
+#define ATMEL_TC_CMR_ABETRG		BIT(10)
+#define ATMEL_TC_CMR_CPCTRG		BIT(14)
+#define ATMEL_TC_CMR_LDRA_MSK		GENMASK(17, 16)
+#define ATMEL_TC_CMR_LDRA_NONE		(0 << 16)
+#define ATMEL_TC_CMR_LDRA_RISING	(1 << 16)
+#define ATMEL_TC_CMR_LDRA_FALLING	(2 << 16)
+#define ATMEL_TC_CMR_LDRA_BOTH		(3 << 16)
+#define ATMEL_TC_CMR_LDRB_MSK		GENMASK(19, 18)
+#define ATMEL_TC_CMR_LDRB_NONE		(0 << 18)
+#define ATMEL_TC_CMR_LDRB_RISING	(1 << 18)
+#define ATMEL_TC_CMR_LDRB_FALLING	(2 << 18)
+#define ATMEL_TC_CMR_LDRB_BOTH		(3 << 18)
+#define ATMEL_TC_CMR_SBSMPLR_MSK	GENMASK(22, 20)
+#define ATMEL_TC_CMR_SBSMPLR(x)		((x) << 20)
+
+/* Waveform mode CMR fields */
+#define ATMEL_TC_CMR_CPCSTOP		BIT(6)
+#define ATMEL_TC_CMR_CPCDIS		BIT(7)
+#define ATMEL_TC_CMR_EEVTEDG_MSK	GENMASK(9, 8)
+#define ATMEL_TC_CMR_EEVTEDG_NONE	(0 << 8)
+#define ATMEL_TC_CMR_EEVTEDG_RISING	(1 << 8)
+#define ATMEL_TC_CMR_EEVTEDG_FALLING	(2 << 8)
+#define ATMEL_TC_CMR_EEVTEDG_BOTH	(3 << 8)
+#define ATMEL_TC_CMR_EEVT_MSK		GENMASK(11, 10)
+#define ATMEL_TC_CMR_EEVT_XC(x)		(((x) + 1) << 10)
+#define ATMEL_TC_CMR_ENETRG		BIT(12)
+#define ATMEL_TC_CMR_WAVESEL_MSK	GENMASK(14, 13)
+#define ATMEL_TC_CMR_WAVESEL_UP		(0 << 13)
+#define ATMEL_TC_CMR_WAVESEL_UPDOWN	(1 << 13)
+#define ATMEL_TC_CMR_WAVESEL_UPRC	(2 << 13)
+#define ATMEL_TC_CMR_WAVESEL_UPDOWNRC	(3 << 13)
+#define ATMEL_TC_CMR_ACPA_MSK		GENMASK(17, 16)
+#define ATMEL_TC_CMR_ACPA(a)		(ATMEL_TC_CMR_ACTION_##a << 16)
+#define ATMEL_TC_CMR_ACPC_MSK		GENMASK(19, 18)
+#define ATMEL_TC_CMR_ACPC(a)		(ATMEL_TC_CMR_ACTION_##a << 18)
+#define ATMEL_TC_CMR_AEEVT_MSK		GENMASK(21, 20)
+#define ATMEL_TC_CMR_AEEVT(a)		(ATMEL_TC_CMR_ACTION_##a << 20)
+#define ATMEL_TC_CMR_ASWTRG_MSK		GENMASK(23, 22)
+#define ATMEL_TC_CMR_ASWTRG(a)		(ATMEL_TC_CMR_ACTION_##a << 22)
+#define ATMEL_TC_CMR_BCPB_MSK		GENMASK(25, 24)
+#define ATMEL_TC_CMR_BCPB(a)		(ATMEL_TC_CMR_ACTION_##a << 24)
+#define ATMEL_TC_CMR_BCPC_MSK		GENMASK(27, 26)
+#define ATMEL_TC_CMR_BCPC(a)		(ATMEL_TC_CMR_ACTION_##a << 26)
+#define ATMEL_TC_CMR_BEEVT_MSK		GENMASK(29, 28)
+#define ATMEL_TC_CMR_BEEVT(a)		(ATMEL_TC_CMR_ACTION_##a << 28)
+#define ATMEL_TC_CMR_BSWTRG_MSK		GENMASK(31, 30)
+#define ATMEL_TC_CMR_BSWTRG(a)		(ATMEL_TC_CMR_ACTION_##a << 30)
+#define ATMEL_TC_CMR_ACTION_NONE	0
+#define ATMEL_TC_CMR_ACTION_SET		1
+#define ATMEL_TC_CMR_ACTION_CLEAR	2
+#define ATMEL_TC_CMR_ACTION_TOGGLE	3
+
+/* SMMR fields */
+#define ATMEL_TC_SMMR_GCEN		BIT(0)
+#define ATMEL_TC_SMMR_DOWN		BIT(1)
+
+/* SR/IER/IDR/IMR fields */
+#define ATMEL_TC_COVFS			BIT(0)
+#define ATMEL_TC_LOVRS			BIT(1)
+#define ATMEL_TC_CPAS			BIT(2)
+#define ATMEL_TC_CPBS			BIT(3)
+#define ATMEL_TC_CPCS			BIT(4)
+#define ATMEL_TC_LDRAS			BIT(5)
+#define ATMEL_TC_LDRBS			BIT(6)
+#define ATMEL_TC_ETRGS			BIT(7)
+#define ATMEL_TC_CLKSTA			BIT(16)
+#define ATMEL_TC_MTIOA			BIT(17)
+#define ATMEL_TC_MTIOB			BIT(18)
+
+/* EMR fields */
+#define ATMEL_TC_EMR_TRIGSRCA_MSK	GENMASK(1, 0)
+#define ATMEL_TC_EMR_TRIGSRCA_TIOA	0
+#define ATMEL_TC_EMR_TRIGSRCA_PWMX	1
+#define ATMEL_TC_EMR_TRIGSRCB_MSK	GENMASK(5, 4)
+#define ATMEL_TC_EMR_TRIGSRCB_TIOB	(0 << 4)
+#define ATMEL_TC_EMR_TRIGSRCB_PWM	(1 << 4)
+#define ATMEL_TC_EMR_NOCLKDIV		BIT(8)
+
+/* BCR fields */
+#define ATMEL_TC_BCR_SYNC		BIT(0)
+
+/* BMR fields */
+#define ATMEL_TC_BMR_TCXC_MSK(c)	GENMASK(((c) * 2) + 1, (c) * 2)
+#define ATMEL_TC_BMR_TCXC(x, c)		((x) << (2 * (c)))
+#define ATMEL_TC_BMR_QDEN		BIT(8)
+#define ATMEL_TC_BMR_POSEN		BIT(9)
+#define ATMEL_TC_BMR_SPEEDEN		BIT(10)
+#define ATMEL_TC_BMR_QDTRANS		BIT(11)
+#define ATMEL_TC_BMR_EDGPHA		BIT(12)
+#define ATMEL_TC_BMR_INVA		BIT(13)
+#define ATMEL_TC_BMR_INVB		BIT(14)
+#define ATMEL_TC_BMR_INVIDX		BIT(15)
+#define ATMEL_TC_BMR_SWAP		BIT(16)
+#define ATMEL_TC_BMR_IDXPHB		BIT(17)
+#define ATMEL_TC_BMR_AUTOC		BIT(18)
+#define ATMEL_TC_MAXFILT_MSK		GENMASK(25, 20)
+#define ATMEL_TC_MAXFILT(x)		(((x) - 1) << 20)
+#define ATMEL_TC_MAXCMP_MSK		GENMASK(29, 26)
+#define ATMEL_TC_MAXCMP(x)		((x) << 26)
+
+/* QEDC fields */
+#define ATMEL_TC_QEDC_IDX		BIT(0)
+#define ATMEL_TC_QEDC_DIRCHG		BIT(1)
+#define ATMEL_TC_QEDC_QERR		BIT(2)
+#define ATMEL_TC_QEDC_MPE		BIT(3)
+#define ATMEL_TC_QEDC_DIR		BIT(8)
+
+/* FMR fields */
+#define ATMEL_TC_FMR_ENCF(x)		BIT(x)
+
+/* WPMR fields */
+#define ATMEL_TC_WPMR_WPKEY		(0x54494d << 8)
+#define ATMEL_TC_WPMR_WPEN		BIT(0)
+
+static inline struct clk *tcb_clk_get(struct device_node *node, int channel)
+{
+	struct clk *clk;
+	char clk_name[] = "t0_clk";
+
+	clk_name[1] += channel;
+	clk = of_clk_get_by_name(node->parent, clk_name);
+	if (!IS_ERR(clk))
+		return clk;
+
+	return of_clk_get_by_name(node->parent, "t0_clk");
+}
+
+static inline int tcb_irq_get(struct device_node *node, int channel)
+{
+	int irq;
+
+	irq = of_irq_get(node->parent, channel);
+	if (irq > 0)
+		return irq;
+
+	return of_irq_get(node->parent, 0);
+}
+
+static const u8 atmel_tc_divisors[5] = { 2, 8, 32, 128, 0, };
+
+static const struct of_device_id atmel_tcb_dt_ids[] = {
+	{
+		.compatible = "atmel,at91rm9200-tcb",
+		.data = (void *)16,
+	}, {
+		.compatible = "atmel,at91sam9x5-tcb",
+		.data = (void *)32,
+	}, {
+		/* sentinel */
+	}
+};
+
+#endif /* __SOC_ATMEL_TCB_H */
-- 
2.8.1

[PATCH 39/48] ARM: dts: at91: vinco: use TCB2 as clocksource

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:06:43

As TCB2 doesn't have any output pins, use it as a clocksource.

Cc: Gregory CLEMENT <redacted>
Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/at91-vinco.dts | 12 ++++++++++++
 1 file changed, 12 insertions(+)
diff --git a/arch/arm/boot/dts/at91-vinco.dts b/arch/arm/boot/dts/at91-vinco.dts
index 6a366ee952a8..bb68042d3f95 100644
--- a/arch/arm/boot/dts/at91-vinco.dts
+++ b/arch/arm/boot/dts/at91-vinco.dts
@@ -151,6 +151,18 @@
 				status = "okay";
 			};
 
+			tcb2: timer at fc024000 {
+				timer at 0 {
+					compatible = "atmel,tcb-clksrc";
+					reg = <0>;
+				};
+
+				timer at 1 {
+					compatible = "atmel,tcb-clkevt";
+					reg = <1>;
+				};
+			};
+
 			macb1: ethernet at fc028000 {
 				phy-mode = "rmii";
 				status = "okay";
-- 
2.8.1

[PATCH 38/48] ARM: dts: at91: ma5d4: use TCB2 as clocksource

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:07:00

As TCB2 doesn't have any output pins, use it as a clocksource.

Cc: Marek Vasut <marex@denx.de>
Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/at91-sama5d4_ma5d4.dtsi | 12 ++++++++++++
 1 file changed, 12 insertions(+)
diff --git a/arch/arm/boot/dts/at91-sama5d4_ma5d4.dtsi b/arch/arm/boot/dts/at91-sama5d4_ma5d4.dtsi
index e7b2109fc85a..d4ca06c2a8ce 100644
--- a/arch/arm/boot/dts/at91-sama5d4_ma5d4.dtsi
+++ b/arch/arm/boot/dts/at91-sama5d4_ma5d4.dtsi
@@ -86,6 +86,18 @@
 				};
 			};
 
+			tcb2: timer at fc024000 {
+				timer at 0 {
+					compatible = "atmel,tcb-clksrc";
+					reg = <0>;
+				};
+
+				timer at 1 {
+					compatible = "atmel,tcb-clkevt";
+					reg = <1>;
+				};
+			};
+
 			adc0: adc at fc034000 {
 				pinctrl-names = "default";
 				pinctrl-0 = <
-- 
2.8.1

[PATCH 37/48] ARM: dts: at91: sama5d4 Xplained: use TCB2 as clocksource

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:07:23

As TCB2 doesn't have any output pins, use it as a clocksource.

Tested-by: Alexandre Belloni <redacted>
Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/at91-sama5d4_xplained.dts | 12 ++++++++++++
 1 file changed, 12 insertions(+)
diff --git a/arch/arm/boot/dts/at91-sama5d4_xplained.dts b/arch/arm/boot/dts/at91-sama5d4_xplained.dts
index da84e65b56ef..c0be79d5cf50 100644
--- a/arch/arm/boot/dts/at91-sama5d4_xplained.dts
+++ b/arch/arm/boot/dts/at91-sama5d4_xplained.dts
@@ -122,6 +122,18 @@
 				status = "okay";
 			};
 
+			tcb2: timer at fc024000 {
+				timer at 0 {
+					compatible = "atmel,tcb-clksrc";
+					reg = <0>;
+				};
+
+				timer at 1 {
+					compatible = "atmel,tcb-clkevt";
+					reg = <1>;
+				};
+			};
+
 			adc0: adc at fc034000 {
 				pinctrl-names = "default";
 				pinctrl-0 = <
-- 
2.8.1

[PATCH 36/48] ARM: dts: at91: sama5d4ek: use TCB2 as clocksource

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:07:55

As TCB2 doesn't have any output pins, use it as a clocksource.

Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/at91-sama5d4ek.dts | 12 ++++++++++++
 1 file changed, 12 insertions(+)
diff --git a/arch/arm/boot/dts/at91-sama5d4ek.dts b/arch/arm/boot/dts/at91-sama5d4ek.dts
index 4e98cda97403..5ccd2fb54e2a 100644
--- a/arch/arm/boot/dts/at91-sama5d4ek.dts
+++ b/arch/arm/boot/dts/at91-sama5d4ek.dts
@@ -194,6 +194,18 @@
 				status = "okay";
 			};
 
+			tcb2: timer at fc024000 {
+				timer at 0 {
+					compatible = "atmel,tcb-clksrc";
+					reg = <0>;
+				};
+
+				timer at 1 {
+					compatible = "atmel,tcb-clkevt";
+					reg = <1>;
+				};
+			};
+
 			watchdog at fc068640 {
 				status = "okay";
 			};
-- 
2.8.1

[PATCH 35/48] ARM: dts: at91: sama5d4: Add TCB2

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:08:22

The third TC block is missing from the dtsi. It has no output pins but can
still be used as a clocksource/clockevents device as the IRQ is wired.

Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/sama5d4.dtsi | 10 ++++++++++
 1 file changed, 10 insertions(+)
diff --git a/arch/arm/boot/dts/sama5d4.dtsi b/arch/arm/boot/dts/sama5d4.dtsi
index 9fd39a0d2251..ef7b9b08546d 100644
--- a/arch/arm/boot/dts/sama5d4.dtsi
+++ b/arch/arm/boot/dts/sama5d4.dtsi
@@ -1193,6 +1193,16 @@
 				clock-names = "t0_clk", "slow_clk";
 			};
 
+			tcb2: timer at fc024000 {
+				compatible = "atmel,at91sam9x5-tcb", "simple-mfd", "syscon";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				reg = <0xfc024000 0x100>;
+				interrupts = <42 IRQ_TYPE_LEVEL_HIGH 0>;
+				clocks = <&tcb2_clk>, <&clk32k>;
+				clock-names = "t0_clk", "slow_clk";
+			};
+
 			macb1: ethernet at fc028000 {
 				compatible = "atmel,sama5d4-gem";
 				reg = <0xfc028000 0x100>;
-- 
2.8.1

[PATCH 34/48] ARM: dts: at91: sama5d4: TC blocks are also simple-mfd and syscon devices

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:08:44

Add simple-mfd and syscon to the TC blocks to allow to register one of the
channels as clocksource properly at boot time. It also allow sto reuse
regmap instead of tclib.

Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/sama5d4.dtsi | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/sama5d4.dtsi b/arch/arm/boot/dts/sama5d4.dtsi
index 4e2cc30d6615..9fd39a0d2251 100644
--- a/arch/arm/boot/dts/sama5d4.dtsi
+++ b/arch/arm/boot/dts/sama5d4.dtsi
@@ -954,7 +954,9 @@
 			};
 
 			tcb0: timer at f801c000 {
-				compatible = "atmel,at91sam9x5-tcb";
+				compatible = "atmel,at91sam9x5-tcb", "simple-mfd", "syscon";
+				#address-cells = <1>;
+				#size-cells = <0>;
 				reg = <0xf801c000 0x100>;
 				interrupts = <40 IRQ_TYPE_LEVEL_HIGH 0>;
 				clocks = <&tcb0_clk>, <&clk32k>;
@@ -1182,7 +1184,9 @@
 			};
 
 			tcb1: timer at fc020000 {
-				compatible = "atmel,at91sam9x5-tcb";
+				compatible = "atmel,at91sam9x5-tcb", "simple-mfd", "syscon";
+				#address-cells = <1>;
+				#size-cells = <0>;
 				reg = <0xfc020000 0x100>;
 				interrupts = <41 IRQ_TYPE_LEVEL_HIGH 0>;
 				clocks = <&tcb1_clk>, <&clk32k>;
-- 
2.8.1

[PATCH 32/48] ARM: dts: at91: sama5d3 Xplained: use TCB0 as clocksource

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:09:44

Use tcb0 as the clocksource like previously selected in sama5_defconfig.

Tested-by: Alexandre Belloni <redacted>
Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/at91-sama5d3_xplained.dts | 12 ++++++++++++
 1 file changed, 12 insertions(+)
diff --git a/arch/arm/boot/dts/at91-sama5d3_xplained.dts b/arch/arm/boot/dts/at91-sama5d3_xplained.dts
index f3e2b96c06a3..9e9bf3caabd6 100644
--- a/arch/arm/boot/dts/at91-sama5d3_xplained.dts
+++ b/arch/arm/boot/dts/at91-sama5d3_xplained.dts
@@ -65,6 +65,18 @@
 				status = "okay";
 			};
 
+			tcb0: timer at f0010000 {
+				timer at 0 {
+					compatible = "atmel,tcb-clksrc";
+					reg = <0>;
+				};
+
+				timer at 1 {
+					compatible = "atmel,tcb-clkevt";
+					reg = <1>;
+				};
+			};
+
 			i2c0: i2c at f0014000 {
 				pinctrl-0 = <&pinctrl_i2c0_pu>;
 				status = "okay";
-- 
2.8.1

[PATCH 33/48] ARM: dts: at91: kizbox2: use TCB0 as clocksource

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:09:46

Use tcb0 as the clocksource like previously selected in sama5_defconfig.

Cc: Antoine Aubert <redacted>
Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/at91-kizbox2.dts | 12 ++++++++++++
 1 file changed, 12 insertions(+)
diff --git a/arch/arm/boot/dts/at91-kizbox2.dts b/arch/arm/boot/dts/at91-kizbox2.dts
index 50a14568f094..03c47eab3771 100644
--- a/arch/arm/boot/dts/at91-kizbox2.dts
+++ b/arch/arm/boot/dts/at91-kizbox2.dts
@@ -94,6 +94,18 @@
 				};
 			};
 
+			tcb0: timer at f0010000 {
+				timer at 0 {
+					compatible = "atmel,tcb-clksrc";
+					reg = <0>;
+				};
+
+				timer at 1 {
+					compatible = "atmel,tcb-clkevt";
+					reg = <1>;
+				};
+			};
+
 			usart0: serial at f001c000 {
 				status = "okay";
 			};
-- 
2.8.1

[PATCH 31/48] ARM: dts: at91: sama5d3xek; use TCB0 as clocksource

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:10:27

Use tcb0 as the clocksource like previously selected in sama5_defconfig.

Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/sama5d3xcm.dtsi | 12 ++++++++++++
 1 file changed, 12 insertions(+)
diff --git a/arch/arm/boot/dts/sama5d3xcm.dtsi b/arch/arm/boot/dts/sama5d3xcm.dtsi
index 2cf9c3611db6..90d36b755858 100644
--- a/arch/arm/boot/dts/sama5d3xcm.dtsi
+++ b/arch/arm/boot/dts/sama5d3xcm.dtsi
@@ -35,6 +35,18 @@
 				cs-gpios = <&pioD 13 0>, <0>, <0>, <0>;
 			};
 
+			tcb0: timer at f0010000 {
+				timer at 0 {
+					compatible = "atmel,tcb-clksrc";
+					reg = <0>;
+				};
+
+				timer at 1 {
+					compatible = "atmel,tcb-clkevt";
+					reg = <1>;
+				};
+			};
+
 			macb0: ethernet at f0028000 {
 				phy-mode = "rgmii";
 				#address-cells = <1>;
-- 
2.8.1

[PATCH 30/48] ARM: dts: at91: sama5d3: TC blocks are also simple-mfd and syscon devices

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:10:47

Add simple-mfd and syscon to the TC blocks to allow to register one of the
channels as clocksource properly at boot time. It also allows to use
regmap instead of tclib.

Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/sama5d3.dtsi      | 4 +++-
 arch/arm/boot/dts/sama5d3_tcb1.dtsi | 4 +++-
 2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/sama5d3.dtsi b/arch/arm/boot/dts/sama5d3.dtsi
index 36301bd9a14a..cfa659a18639 100644
--- a/arch/arm/boot/dts/sama5d3.dtsi
+++ b/arch/arm/boot/dts/sama5d3.dtsi
@@ -142,7 +142,9 @@
 			};
 
 			tcb0: timer at f0010000 {
-				compatible = "atmel,at91sam9x5-tcb";
+				compatible = "atmel,at91sam9x5-tcb", "simple-mfd", "syscon";
+				#address-cells = <1>;
+				#size-cells = <0>;
 				reg = <0xf0010000 0x100>;
 				interrupts = <26 IRQ_TYPE_LEVEL_HIGH 0>;
 				clocks = <&tcb0_clk>, <&clk32k>;
diff --git a/arch/arm/boot/dts/sama5d3_tcb1.dtsi b/arch/arm/boot/dts/sama5d3_tcb1.dtsi
index 801f9745e82f..cb30bdb1a9ca 100644
--- a/arch/arm/boot/dts/sama5d3_tcb1.dtsi
+++ b/arch/arm/boot/dts/sama5d3_tcb1.dtsi
@@ -28,7 +28,9 @@
 			};
 
 			tcb1: timer at f8014000 {
-				compatible = "atmel,at91sam9x5-tcb";
+				compatible = "atmel,at91sam9x5-tcb", "simple-mfd", "syscon";
+				#address-cells = <1>;
+				#size-cells = <0>;
 				reg = <0xf8014000 0x100>;
 				interrupts = <27 IRQ_TYPE_LEVEL_HIGH 0>;
 				clocks = <&tcb1_clk>, <&clk32k>;
-- 
2.8.1

[PATCH 29/48] ARM: dts: at91: kizboxmini: use TCB0 as clocksource

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:11:00

Use tcb0 as the clocksource like previously selected in at91_dt_defconfig.

Cc: Antoine Aubert <redacted>
Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/at91-kizboxmini.dts | 12 ++++++++++++
 1 file changed, 12 insertions(+)
diff --git a/arch/arm/boot/dts/at91-kizboxmini.dts b/arch/arm/boot/dts/at91-kizboxmini.dts
index 9682d105d4d8..2fc100414a00 100644
--- a/arch/arm/boot/dts/at91-kizboxmini.dts
+++ b/arch/arm/boot/dts/at91-kizboxmini.dts
@@ -34,6 +34,18 @@
 
 	ahb {
 		apb {
+			tcb0: timer at f8008000 {
+				timer at 0 {
+					compatible = "atmel,tcb-clksrc";
+					reg = <0>;
+				};
+
+				timer at 1 {
+					compatible = "atmel,tcb-clkevt";
+					reg = <1>;
+				};
+			};
+
 			usart0: serial at f801c000 {
 				status = "okay";
 			};
-- 
2.8.1

[PATCH 28/48] ARM: dts: at91: cosino: use TCB0 as clocksource

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:11:38

Use tcb0 as the clocksource like previously selected in at91_dt_defconfig.

Cc: Rodolfo Giometti <redacted>
Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/at91-cosino.dtsi | 12 ++++++++++++
 1 file changed, 12 insertions(+)
diff --git a/arch/arm/boot/dts/at91-cosino.dtsi b/arch/arm/boot/dts/at91-cosino.dtsi
index b6ea3f4a7206..0cbab6f588b7 100644
--- a/arch/arm/boot/dts/at91-cosino.dtsi
+++ b/arch/arm/boot/dts/at91-cosino.dtsi
@@ -46,6 +46,18 @@
 
 	ahb {
 		apb {
+			tcb0: timer at f8008000 {
+				timer at 0 {
+					compatible = "atmel,tcb-clksrc";
+					reg = <0>;
+				};
+
+				timer at 1 {
+					compatible = "atmel,tcb-clkevt";
+					reg = <1>;
+				};
+			};
+
 			mmc0: mmc at f0008000 {
 				pinctrl-0 = <
 					&pinctrl_board_mmc0
-- 
2.8.1

[PATCH 27/48] ARM: dts: at91: acme/g25: use TCB0 as clocksource

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:11:40

Use tcb0 as the clocksource like previously selected in at91_dt_defconfig.

Cc: Sergio Tanzilli <redacted>
Cc: Douglas Gilbert <dgilbert@interlog.com>
Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/at91-ariag25.dts    | 12 ++++++++++++
 arch/arm/boot/dts/at91-ariettag25.dts | 12 ++++++++++++
 2 files changed, 24 insertions(+)
diff --git a/arch/arm/boot/dts/at91-ariag25.dts b/arch/arm/boot/dts/at91-ariag25.dts
index e9ced30159a7..b00aa7607283 100644
--- a/arch/arm/boot/dts/at91-ariag25.dts
+++ b/arch/arm/boot/dts/at91-ariag25.dts
@@ -67,6 +67,18 @@
 				};
 			};
 
+			tcb0: timer at f8008000 {
+				timer at 0 {
+					compatible = "atmel,tcb-clksrc";
+					reg = <0>;
+				};
+
+				timer at 1 {
+					compatible = "atmel,tcb-clkevt";
+					reg = <1>;
+				};
+			};
+
 			i2c0: i2c at f8010000 {
 				status = "okay";
 			};
diff --git a/arch/arm/boot/dts/at91-ariettag25.dts b/arch/arm/boot/dts/at91-ariettag25.dts
index c514502081d2..58e0026157f7 100644
--- a/arch/arm/boot/dts/at91-ariettag25.dts
+++ b/arch/arm/boot/dts/at91-ariettag25.dts
@@ -45,6 +45,18 @@
 				};
 			};
 
+			tcb0: timer at f8008000 {
+				timer at 0 {
+					compatible = "atmel,tcb-clksrc";
+					reg = <0>;
+				};
+
+				timer at 1 {
+					compatible = "atmel,tcb-clkevt";
+					reg = <1>;
+				};
+			};
+
 			usb2: gadget at f803c000 {
 				status = "okay";
 			};
-- 
2.8.1

[PATCH 26/48] ARM: dts: at91: at91sam9x5cm: use TCB0 as clocksource

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:12:13

Use tcb0 as the clocksource like previously selected in at91_dt_defconfig.

[tested on at91sam9x25ek and at91sam9x35ek]
Tested-by: Alexandre Belloni <redacted>
Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/at91sam9x5cm.dtsi | 12 ++++++++++++
 1 file changed, 12 insertions(+)
diff --git a/arch/arm/boot/dts/at91sam9x5cm.dtsi b/arch/arm/boot/dts/at91sam9x5cm.dtsi
index b098ad8cd93a..40676cc9b172 100644
--- a/arch/arm/boot/dts/at91sam9x5cm.dtsi
+++ b/arch/arm/boot/dts/at91sam9x5cm.dtsi
@@ -24,6 +24,18 @@
 
 	ahb {
 		apb {
+			tcb0: timer at f8008000 {
+				timer at 0 {
+					compatible = "atmel,tcb-clksrc";
+					reg = <0>;
+				};
+
+				timer at 1 {
+					compatible = "atmel,tcb-clkevt";
+					reg = <1>;
+				};
+			};
+
 			pinctrl at fffff400 {
 				1wire_cm {
 					pinctrl_1wire_cm: 1wire_cm-0 {
-- 
2.8.1

[PATCH 25/48] ARM: dts: at91: at91sam9x5: TC blocks are also simple-mfd and syscon devices

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:13:24

Add simple-mfd and syscon to the TC blocks to allow to register one of the
channels as clocksource properly at boot time. It also allows to use regmap
instead of tclib.

Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/at91sam9x5.dtsi | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
index cd0cd5fd09a3..6d845993406f 100644
--- a/arch/arm/boot/dts/at91sam9x5.dtsi
+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
@@ -417,7 +417,9 @@
 			};
 
 			tcb0: timer at f8008000 {
-				compatible = "atmel,at91sam9x5-tcb";
+				compatible = "atmel,at91sam9x5-tcb", "simple-mfd", "syscon";
+				#address-cells = <1>;
+				#size-cells = <0>;
 				reg = <0xf8008000 0x100>;
 				interrupts = <17 IRQ_TYPE_LEVEL_HIGH 0>;
 				clocks = <&tcb0_clk>, <&clk32k>;
@@ -425,7 +427,9 @@
 			};
 
 			tcb1: timer at f800c000 {
-				compatible = "atmel,at91sam9x5-tcb";
+				compatible = "atmel,at91sam9x5-tcb", "simple-mfd", "syscon";
+				#address-cells = <1>;
+				#size-cells = <0>;
 				reg = <0xf800c000 0x100>;
 				interrupts = <17 IRQ_TYPE_LEVEL_HIGH 0>;
 				clocks = <&tcb0_clk>, <&clk32k>;
-- 
2.8.1

[PATCH 24/48] ARM: dts: at91: at91sam9n12ek: use TCB0 as clocksource

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:13:39

Use tcb0 as the clocksource like previously selected in at91_dt_defconfig.

Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/at91sam9n12ek.dts | 12 ++++++++++++
 1 file changed, 12 insertions(+)
diff --git a/arch/arm/boot/dts/at91sam9n12ek.dts b/arch/arm/boot/dts/at91sam9n12ek.dts
index 626c67d66626..3491db62d6b3 100644
--- a/arch/arm/boot/dts/at91sam9n12ek.dts
+++ b/arch/arm/boot/dts/at91sam9n12ek.dts
@@ -42,6 +42,18 @@
 				status = "okay";
 			};
 
+			tcb0: timer at f8008000 {
+				timer at 0 {
+					compatible = "atmel,tcb-clksrc";
+					reg = <0>;
+				};
+
+				timer at 1 {
+					compatible = "atmel,tcb-clkevt";
+					reg = <1>;
+				};
+			};
+
 			i2c0: i2c at f8010000 {
 				status = "okay";
 
-- 
2.8.1

[PATCH 23/48] ARM: dts: at91: at91sam9n12: TC blocks are also simple-mfd and syscon devices

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:14:09

Add simple-mfd and syscon to the TC blocks to allow to register one of the
channels as clocksource properly at boot time. It also allows to use regmap
instead of tclib.

Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/at91sam9n12.dtsi | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
index 95569a87b6c9..1f26cb66238e 100644
--- a/arch/arm/boot/dts/at91sam9n12.dtsi
+++ b/arch/arm/boot/dts/at91sam9n12.dtsi
@@ -430,7 +430,9 @@
 			};
 
 			tcb0: timer at f8008000 {
-				compatible = "atmel,at91sam9x5-tcb";
+				compatible = "atmel,at91sam9x5-tcb", "simple-mfd", "syscon";
+				#address-cells = <1>;
+				#size-cells = <0>;
 				reg = <0xf8008000 0x100>;
 				interrupts = <17 IRQ_TYPE_LEVEL_HIGH 0>;
 				clocks = <&tcb_clk>, <&clk32k>;
@@ -438,7 +440,9 @@
 			};
 
 			tcb1: timer at f800c000 {
-				compatible = "atmel,at91sam9x5-tcb";
+				compatible = "atmel,at91sam9x5-tcb", "simple-mfd", "syscon";
+				#address-cells = <1>;
+				#size-cells = <0>;
 				reg = <0xf800c000 0x100>;
 				interrupts = <17 IRQ_TYPE_LEVEL_HIGH 0>;
 				clocks = <&tcb_clk>, <&clk32k>;
-- 
2.8.1

[PATCH 22/48] ARM: dts: at91: at91sam9rlek: use TCB0 as clocksource

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:14:28

Use tcb0 as the clocksource like previously selected in at91_dt_defconfig.

Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/at91sam9rlek.dts | 12 ++++++++++++
 1 file changed, 12 insertions(+)
diff --git a/arch/arm/boot/dts/at91sam9rlek.dts b/arch/arm/boot/dts/at91sam9rlek.dts
index f10566f759cd..cc0b6b19c5bf 100644
--- a/arch/arm/boot/dts/at91sam9rlek.dts
+++ b/arch/arm/boot/dts/at91sam9rlek.dts
@@ -101,6 +101,18 @@
 		};
 
 		apb {
+			tcb0: timer at fffa0000 {
+				timer at 0 {
+					compatible = "atmel,tcb-clksrc";
+					reg = <0>, <1>;
+				};
+
+				timer at 2 {
+					compatible = "atmel,tcb-clkevt";
+					reg = <2>;
+				};
+			};
+
 			mmc0: mmc at fffa4000 {
 				pinctrl-0 = <
 					&pinctrl_board_mmc0
-- 
2.8.1

[PATCH 20/48] ARM: dts: at91: pm9g45: use TCB0 as clocksource

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:14:42

Use tcb0 as the clocksource like previously selected in at91_dt_defconfig.

Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/pm9g45.dts | 12 ++++++++++++
 1 file changed, 12 insertions(+)
diff --git a/arch/arm/boot/dts/pm9g45.dts b/arch/arm/boot/dts/pm9g45.dts
index 66afcff67fde..5d5ccefa8644 100644
--- a/arch/arm/boot/dts/pm9g45.dts
+++ b/arch/arm/boot/dts/pm9g45.dts
@@ -63,6 +63,18 @@
 				};
 			};
 
+			tcb0: timer at fff7c000 {
+				timer at 0 {
+					compatible = "atmel,tcb-clksrc";
+					reg = <0>, <1>;
+				};
+
+				timer at 2 {
+					compatible = "atmel,tcb-clkevt";
+					reg = <2>;
+				};
+			};
+
 			mmc0: mmc at fff80000 {
 				pinctrl-0 = <
 					&pinctrl_board_mmc
-- 
2.8.1

[PATCH 19/48] ARM: dts: at91: at91sam9m10g45ek: use TCB0 as clocksource

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:14:59

Use tcb0 as the clocksource like previously selected in at91_dt_defconfig.

Tested-by: Alexandre Belloni <redacted>
Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/at91sam9m10g45ek.dts | 12 ++++++++++++
 1 file changed, 12 insertions(+)
diff --git a/arch/arm/boot/dts/at91sam9m10g45ek.dts b/arch/arm/boot/dts/at91sam9m10g45ek.dts
index 2400c99134f7..132064c60863 100644
--- a/arch/arm/boot/dts/at91sam9m10g45ek.dts
+++ b/arch/arm/boot/dts/at91sam9m10g45ek.dts
@@ -39,6 +39,18 @@
 				status = "okay";
 			};
 
+			tcb0: timer at fff7c000 {
+				timer at 0 {
+					compatible = "atmel,tcb-clksrc";
+					reg = <0>, <1>;
+				};
+
+				timer at 2 {
+					compatible = "atmel,tcb-clkevt";
+					reg = <2>;
+				};
+			};
+
 			usart1: serial at fff90000 {
 				pinctrl-0 =
 					<&pinctrl_usart1
-- 
2.8.1

[PATCH 18/48] ARM: dts: at91: at91sam9g45: TC blocks are also simple-mfd and syscon devices

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:15:30

Add simple-mfd and syscon to the TC blocks to allow to register one of the
channels as clocksource properly at boot time. It also allows to use regmap
instead of tclib.

Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/at91sam9g45.dtsi | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
index 8837b7e4292c..2b95aef4da44 100644
--- a/arch/arm/boot/dts/at91sam9g45.dtsi
+++ b/arch/arm/boot/dts/at91sam9g45.dtsi
@@ -405,7 +405,9 @@
 			};
 
 			tcb0: timer at fff7c000 {
-				compatible = "atmel,at91rm9200-tcb";
+				compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon";
+				#address-cells = <1>;
+				#size-cells = <0>;
 				reg = <0xfff7c000 0x100>;
 				interrupts = <18 IRQ_TYPE_LEVEL_HIGH 0>;
 				clocks = <&tcb0_clk>, <&tcb0_clk>, <&tcb0_clk>, <&clk32k>;
@@ -413,7 +415,9 @@
 			};
 
 			tcb1: timer at fffd4000 {
-				compatible = "atmel,at91rm9200-tcb";
+				compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon";
+				#address-cells = <1>;
+				#size-cells = <0>;
 				reg = <0xfffd4000 0x100>;
 				interrupts = <18 IRQ_TYPE_LEVEL_HIGH 0>;
 				clocks = <&tcb0_clk>, <&tcb0_clk>, <&tcb0_clk>, <&clk32k>;
-- 
2.8.1

[PATCH 17/48] ARM: dts: at91: calao: use TCB0 as clocksource

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:15:33

Use tcb0 as the clocksource like previously selected in at91_dt_defconfig.

Cc: Gregory Hermant <redacted>
[tested on usb_a9g20 and usb_a9263]
Tested-by: Alexandre Belloni <redacted>
Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/at91-qil_a9260.dts    | 12 ++++++++++++
 arch/arm/boot/dts/tny_a9260_common.dtsi | 12 ++++++++++++
 arch/arm/boot/dts/tny_a9263.dts         | 12 ++++++++++++
 arch/arm/boot/dts/usb_a9260_common.dtsi | 12 ++++++++++++
 arch/arm/boot/dts/usb_a9263.dts         | 12 ++++++++++++
 5 files changed, 60 insertions(+)
diff --git a/arch/arm/boot/dts/at91-qil_a9260.dts b/arch/arm/boot/dts/at91-qil_a9260.dts
index 4f2eebf4a560..bbc1f667cc65 100644
--- a/arch/arm/boot/dts/at91-qil_a9260.dts
+++ b/arch/arm/boot/dts/at91-qil_a9260.dts
@@ -40,6 +40,18 @@
 
 	ahb {
 		apb {
+			tcb0: timer at fffa0000 {
+				timer at 0 {
+					compatible = "atmel,tcb-clksrc";
+					reg = <0>, <1>;
+				};
+
+				timer at 2 {
+					compatible = "atmel,tcb-clkevt";
+					reg = <2>;
+				};
+			};
+
 			usb1: gadget at fffa4000 {
 				atmel,vbus-gpio = <&pioC 5 GPIO_ACTIVE_HIGH>;
 				status = "okay";
diff --git a/arch/arm/boot/dts/tny_a9260_common.dtsi b/arch/arm/boot/dts/tny_a9260_common.dtsi
index ce7138c3af1b..0b2902d7ccd3 100644
--- a/arch/arm/boot/dts/tny_a9260_common.dtsi
+++ b/arch/arm/boot/dts/tny_a9260_common.dtsi
@@ -36,6 +36,18 @@
 
 	ahb {
 		apb {
+			tcb0: timer at fffa0000 {
+				timer at 0 {
+					compatible = "atmel,tcb-clksrc";
+					reg = <0>, <1>;
+				};
+
+				timer at 2 {
+					compatible = "atmel,tcb-clkevt";
+					reg = <2>;
+				};
+			};
+
 			dbgu: serial at fffff200 {
 				status = "okay";
 			};
diff --git a/arch/arm/boot/dts/tny_a9263.dts b/arch/arm/boot/dts/tny_a9263.dts
index 3043296345b7..32ee65a9f99f 100644
--- a/arch/arm/boot/dts/tny_a9263.dts
+++ b/arch/arm/boot/dts/tny_a9263.dts
@@ -45,6 +45,18 @@
 				status = "okay";
 			};
 
+			tcb0: timer at fff7c000 {
+				timer at 0 {
+					compatible = "atmel,tcb-clksrc";
+					reg = <0>, <1>;
+				};
+
+				timer at 2 {
+					compatible = "atmel,tcb-clkevt";
+					reg = <2>;
+				};
+			};
+
 			usb1: gadget at fff78000 {
 				atmel,vbus-gpio = <&pioB 11 GPIO_ACTIVE_HIGH>;
 				status = "okay";
diff --git a/arch/arm/boot/dts/usb_a9260_common.dtsi b/arch/arm/boot/dts/usb_a9260_common.dtsi
index 9beea8976584..369a26bc5edc 100644
--- a/arch/arm/boot/dts/usb_a9260_common.dtsi
+++ b/arch/arm/boot/dts/usb_a9260_common.dtsi
@@ -32,6 +32,18 @@
 				status = "okay";
 			};
 
+			tcb0: timer at fffa0000 {
+				timer at 0 {
+					compatible = "atmel,tcb-clksrc";
+					reg = <0>, <1>;
+				};
+
+				timer at 2 {
+					compatible = "atmel,tcb-clkevt";
+					reg = <2>;
+				};
+			};
+
 			macb0: ethernet at fffc4000 {
 				phy-mode = "rmii";
 				status = "okay";
diff --git a/arch/arm/boot/dts/usb_a9263.dts b/arch/arm/boot/dts/usb_a9263.dts
index 8cc6edb29694..49a25c26b8e4 100644
--- a/arch/arm/boot/dts/usb_a9263.dts
+++ b/arch/arm/boot/dts/usb_a9263.dts
@@ -45,6 +45,18 @@
 				status = "okay";
 			};
 
+			tcb0: timer at fff7c000 {
+				timer at 0 {
+					compatible = "atmel,tcb-clksrc";
+					reg = <0>, <1>;
+				};
+
+				timer at 2 {
+					compatible = "atmel,tcb-clkevt";
+					reg = <2>;
+				};
+			};
+
 			macb0: ethernet at fffbc000 {
 				phy-mode = "rmii";
 				status = "okay";
-- 
2.8.1

[PATCH 16/48] ARM: dts: at91: at91sam9263ek: use TCB0 as clocksource

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:15:36

Use tcb0 as the clocksource like previously selected in at91_dt_defconfig.

Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/at91sam9263ek.dts | 12 ++++++++++++
 1 file changed, 12 insertions(+)
diff --git a/arch/arm/boot/dts/at91sam9263ek.dts b/arch/arm/boot/dts/at91sam9263ek.dts
index 59df9d73d276..e3b51e8d01bb 100644
--- a/arch/arm/boot/dts/at91sam9263ek.dts
+++ b/arch/arm/boot/dts/at91sam9263ek.dts
@@ -37,6 +37,18 @@
 				status = "okay";
 			};
 
+			tcb0: timer at fff7c000 {
+				timer at 0 {
+					compatible = "atmel,tcb-clksrc";
+					reg = <0>, <1>;
+				};
+
+				timer at 2 {
+					compatible = "atmel,tcb-clkevt";
+					reg = <2>;
+				};
+			};
+
 			usart0: serial at fff8c000 {
 				pinctrl-0 = <
 					&pinctrl_usart0
-- 
2.8.1

[PATCH 14/48] ARM: dts: at91: at91sam9261ek: use TCB0 as clocksource

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:16:26

Use tcb0 as the clocksource like previously selected in sama5_defconfig.

Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/at91sam9261ek.dts | 12 ++++++++++++
 1 file changed, 12 insertions(+)
diff --git a/arch/arm/boot/dts/at91sam9261ek.dts b/arch/arm/boot/dts/at91sam9261ek.dts
index 55bd51f07fa6..d1b1d11fb974 100644
--- a/arch/arm/boot/dts/at91sam9261ek.dts
+++ b/arch/arm/boot/dts/at91sam9261ek.dts
@@ -106,6 +106,18 @@
 		};
 
 		apb {
+			tcb0: timer at fffa0000 {
+				timer at 0 {
+					compatible = "atmel,tcb-clksrc";
+					reg = <0>;
+				};
+
+				timer at 1 {
+					compatible = "atmel,tcb-clkevt";
+					reg = <1>;
+				};
+			};
+
 			usb1: gadget at fffa4000 {
 				atmel,vbus-gpio = <&pioB 29 GPIO_ACTIVE_HIGH>;
 				status = "okay";
-- 
2.8.1

[PATCH 13/48] ARM: dts: at91: at91sam9261: TC blocks are also simple-mfd and syscon devices

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:16:46

Add simple-mfd and syscon to the TC blocks to allow to register one of the
channels as clocksource properly at boot time. It also allows to use regmap
instead of tclib.

Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/at91sam9261.dtsi | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/at91sam9261.dtsi b/arch/arm/boot/dts/at91sam9261.dtsi
index 5e09de4eb9cd..7dd2441561c1 100644
--- a/arch/arm/boot/dts/at91sam9261.dtsi
+++ b/arch/arm/boot/dts/at91sam9261.dtsi
@@ -114,7 +114,9 @@
 			ranges;
 
 			tcb0: timer at fffa0000 {
-				compatible = "atmel,at91rm9200-tcb";
+				compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon";
+				#address-cells = <1>;
+				#size-cells = <0>;
 				reg = <0xfffa0000 0x100>;
 				interrupts = <17 IRQ_TYPE_LEVEL_HIGH 0>,
 					     <18 IRQ_TYPE_LEVEL_HIGH 0>,
-- 
2.8.1

[PATCH 11/48] ARM: dts: at91: at91sam9g20ek: use TCB0 as clocksource

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:16:48

Use tcb0 as the clocksource like previously selected in at91_dt_defconfig.

Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/at91sam9g20ek_common.dtsi | 12 ++++++++++++
 1 file changed, 12 insertions(+)
diff --git a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
index e9cc99b6353a..e13018b4df01 100644
--- a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
+++ b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
@@ -51,6 +51,18 @@
 				status = "okay";
 			};
 
+			tcb0: timer at fffa0000 {
+				timer at 0 {
+					compatible = "atmel,tcb-clksrc";
+					reg = <0>, <1>;
+				};
+
+				timer at 2 {
+					compatible = "atmel,tcb-clkevt";
+					reg = <2>;
+				};
+			};
+
 			usart0: serial at fffb0000 {
 				pinctrl-0 =
 					<&pinctrl_usart0
-- 
2.8.1

[PATCH 10/48] ARM: dts: at91: kizbox: use TCB0 as clocksource

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:17:20

Use tcb0 as the clocksource like previously selected in at91_dt_defconfig.

Cc: Antoine Aubert <redacted>
Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/at91-kizbox.dts | 12 ++++++++++++
 1 file changed, 12 insertions(+)
diff --git a/arch/arm/boot/dts/at91-kizbox.dts b/arch/arm/boot/dts/at91-kizbox.dts
index 229e989eb60d..58c5d0d3dd66 100644
--- a/arch/arm/boot/dts/at91-kizbox.dts
+++ b/arch/arm/boot/dts/at91-kizbox.dts
@@ -31,6 +31,18 @@
 
 	ahb {
 		apb {
+			tcb0: timer at fffa0000 {
+				timer at 0 {
+					compatible = "atmel,tcb-clksrc";
+					reg = <0>, <1>;
+				};
+
+				timer at 2 {
+					compatible = "atmel,tcb-clkevt";
+					reg = <2>;
+				};
+			};
+
 			macb0: ethernet at fffc4000 {
 				phy-mode = "mii";
 				pinctrl-0 = <&pinctrl_macb_rmii
-- 
2.8.1

[PATCH 09/48] ARM: dts: at91: animeo_ip: use TCB0 as clocksource

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:17:40

Use tcb0 as the clocksource like previously selected in at91_dt_defconfig.

Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/animeo_ip.dts | 12 ++++++++++++
 1 file changed, 12 insertions(+)
diff --git a/arch/arm/boot/dts/animeo_ip.dts b/arch/arm/boot/dts/animeo_ip.dts
index 0962f2fa3f6e..e55190d706a9 100644
--- a/arch/arm/boot/dts/animeo_ip.dts
+++ b/arch/arm/boot/dts/animeo_ip.dts
@@ -52,6 +52,18 @@
 
 	ahb {
 		apb {
+			tcb0: timer at fffa0000 {
+				timer at 0 {
+					compatible = "atmel,tcb-clksrc";
+					reg = <0>, <1>;
+				};
+
+				timer at 2 {
+					compatible = "atmel,tcb-clkevt";
+					reg = <2>;
+				};
+			};
+
 			usart0: serial at fffb0000 {
 				pinctrl-0 = <&pinctrl_usart0 &pinctrl_usart0_rts>;
 				linux,rs485-enabled-at-boot-time;
-- 
2.8.1

[PATCH 08/48] ARM: dts: at91: foxg20: use TCB0 as clocksource

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:17:54

Use tcb0 as the clocksource like previously selected in at91_dt_defconfig.

Cc: Sergio Tanzilli <redacted>
Cc: Douglas Gilbert <dgilbert@interlog.com>
Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/at91-foxg20.dts | 12 ++++++++++++
 1 file changed, 12 insertions(+)
diff --git a/arch/arm/boot/dts/at91-foxg20.dts b/arch/arm/boot/dts/at91-foxg20.dts
index 6bf873e7d96c..cee2296b2c17 100644
--- a/arch/arm/boot/dts/at91-foxg20.dts
+++ b/arch/arm/boot/dts/at91-foxg20.dts
@@ -43,6 +43,18 @@
 
 	ahb {
 		apb {
+			tcb0: timer at fffa0000 {
+				timer at 0 {
+					compatible = "atmel,tcb-clksrc";
+					reg = <0>, <1>;
+				};
+
+				timer at 2 {
+					compatible = "atmel,tcb-clkevt";
+					reg = <2>;
+				};
+			};
+
 			usb1: gadget at fffa4000 {
 				atmel,vbus-gpio = <&pioC 6 GPIO_ACTIVE_HIGH>;
 				status = "okay";
-- 
2.8.1

[PATCH 07/48] ARM: dts: at91: ethernut5: use TCB0 as clocksource

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:18:10

Use tcb0 as the clocksource like previously selected in at91_dt_defconfig.

Cc: Martin Reimann <redacted>
Cc: Tim Schendekehl <redacted>
Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/ethernut5.dts | 12 ++++++++++++
 1 file changed, 12 insertions(+)
diff --git a/arch/arm/boot/dts/ethernut5.dts b/arch/arm/boot/dts/ethernut5.dts
index 243044343ee8..26ce9ee46c05 100644
--- a/arch/arm/boot/dts/ethernut5.dts
+++ b/arch/arm/boot/dts/ethernut5.dts
@@ -36,6 +36,18 @@
 				status = "okay";
 			};
 
+			tcb0: timer at fffa0000 {
+				timer at 0 {
+					compatible = "atmel,tcb-clksrc";
+					reg = <0>, <1>;
+				};
+
+				timer at 2 {
+					compatible = "atmel,tcb-clkevt";
+					reg = <2>;
+				};
+			};
+
 			usart0: serial at fffb0000 {
 				status = "okay";
 			};
-- 
2.8.1

[PATCH 06/48] ARM: dts: at91: at91sam9260: TC blocks are also simple-mfd and syscon devices

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:18:12

Add simple-mfd and syscon to the TC blocks to allow to register one of the
channels as clocksource properly at boot time. It also allows to use
regmap instead of tclib.

Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/at91sam9260.dtsi | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
index d4884dd1c243..7b2aa604a924 100644
--- a/arch/arm/boot/dts/at91sam9260.dtsi
+++ b/arch/arm/boot/dts/at91sam9260.dtsi
@@ -376,7 +376,9 @@
 			};
 
 			tcb0: timer at fffa0000 {
-				compatible = "atmel,at91rm9200-tcb";
+				compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon";
+				#address-cells = <1>;
+				#size-cells = <0>;
 				reg = <0xfffa0000 0x100>;
 				interrupts = <17 IRQ_TYPE_LEVEL_HIGH 0
 					      18 IRQ_TYPE_LEVEL_HIGH 0
@@ -386,7 +388,9 @@
 			};
 
 			tcb1: timer@fffdc000 {
-				compatible = "atmel,at91rm9200-tcb";
+				compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon";
+				#address-cells = <1>;
+				#size-cells = <0>;
 				reg = <0xfffdc000 0x100>;
 				interrupts = <26 IRQ_TYPE_LEVEL_HIGH 0
 					      27 IRQ_TYPE_LEVEL_HIGH 0
-- 
2.8.1

[PATCH 05/48] ARM: dts: at91: mpa1600; use TCB0 as clocksource

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:18:14

Use tcb0 as the clocksource like previously selected in at91_dt_defconfig.

Cc: Joachim Eastwood <redacted>
Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/mpa1600.dts | 12 ++++++++++++
 1 file changed, 12 insertions(+)
diff --git a/arch/arm/boot/dts/mpa1600.dts b/arch/arm/boot/dts/mpa1600.dts
index f0f5e1098928..d1c3ec1db086 100644
--- a/arch/arm/boot/dts/mpa1600.dts
+++ b/arch/arm/boot/dts/mpa1600.dts
@@ -41,6 +41,18 @@
 				status = "okay";
 			};
 
+			tcb0: timer at fffa0000 {
+				timer at 0 {
+					compatible = "atmel,tcb-clksrc";
+					reg = <0>, <1>;
+				};
+
+				timer at 2 {
+					compatible = "atmel,tcb-clkevt";
+					reg = <2>;
+				};
+			};
+
 			macb0: ethernet at fffbc000 {
 				phy-mode = "rmii";
 				status = "okay";
-- 
2.8.1

[PATCH 04/48] ARM: dts: at91: at91rm9200ek; use TCB0 as clocksource

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:19:31

Use tcb0 as the clocksource like previously selected in at91_dt_defconfig.

Tested-by: Alexandre Belloni <redacted>
Signed-off-by: Alexandre Belloni <redacted>
---
 arch/arm/boot/dts/at91rm9200ek.dts | 12 ++++++++++++
 1 file changed, 12 insertions(+)
diff --git a/arch/arm/boot/dts/at91rm9200ek.dts b/arch/arm/boot/dts/at91rm9200ek.dts
index f90e1c2d3caa..051cc8b88513 100644
--- a/arch/arm/boot/dts/at91rm9200ek.dts
+++ b/arch/arm/boot/dts/at91rm9200ek.dts
@@ -32,6 +32,18 @@
 
 	ahb {
 		apb {
+			tcb0: timer at fffa0000 {
+				timer at 0 {
+					compatible = "atmel,tcb-clksrc";
+					reg = <0>, <1>;
+				};
+
+				timer at 2 {
+					compatible = "atmel,tcb-clkevt";
+					reg = <2>;
+				};
+			};
+
 			usb1: gadget at fffb0000 {
 				atmel,vbus-gpio = <&pioD 4 GPIO_ACTIVE_HIGH>;
 				atmel,pullup-gpio = <&pioD 5 GPIO_ACTIVE_HIGH>;
-- 
2.8.1

Re: [PATCH 01/48] clk: at91: replace usleep() by udelay() calls

From: Arnd Bergmann <arnd@arndb.de>
Date: 2016-06-10 22:32:21

On Saturday, June 11, 2016 12:03:04 AM CEST Alexandre Belloni wrote:
From: Cyrille Pitchen <redacted>

Fix the main and slow clock .prepare() implementations which used to call
usleep() when the scheduler wasn't ready yet.
Does this have to be called that early? It seems wasteful to always
call udelay() here, when these are functions that are normally
allowed to sleep.

	Arnd

Re: [PATCH 01/48] clk: at91: replace usleep() by udelay() calls

From: Alexandre Belloni <hidden>
Date: 2016-06-10 22:37:41

On 11/06/2016 at 00:30:36 +0200, Arnd Bergmann wrote :
On Saturday, June 11, 2016 12:03:04 AM CEST Alexandre Belloni wrote:
quoted
From: Cyrille Pitchen <redacted>

Fix the main and slow clock .prepare() implementations which used to call
usleep() when the scheduler wasn't ready yet.
Does this have to be called that early? It seems wasteful to always
call udelay() here, when these are functions that are normally
allowed to sleep.
Well, the main issue here is that we want to be able to prepare_enable
the slow clock before we are allowed to sleep.

Thinking about it when writing that, I realize that when I reworked my
series, I removed the dependency between the clocksource TCB and the
slow_clock. But I guess we still have one on the main clock. I'll check
whether this is still necessary.

-- 
Alexandre Belloni, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

Re: [PATCH 48/48] ARM: dts: at91: kizbox: switch to new pwm-atmel-tcb binding

From: kbuild test robot <hidden>
Date: 2016-06-11 01:22:54

Hi,

[auto build test ERROR on at91/at91-next]
[also build test ERROR on v4.7-rc2 next-20160609]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Alexandre-Belloni/ARM-at91-rework-Atmel-TCB-drivers/20160611-062134
base:   https://git.kernel.org/pub/scm/linux/kernel/git/nferre/linux-at91.git at91-next
config: arm-at91_dt_defconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (Debian 5.3.1-8) 5.3.1 20160205
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=arm 

All errors (new ones prefixed by >>):
quoted
Error: arch/arm/boot/dts/at91-kizbox.dts:54.5-15 syntax error
   FATAL ERROR: Unable to parse input tree

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/octet-stream
Size: 21096 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160611/15668201/attachment-0001.obj>

Re: [PATCH 47/48] PWM: atmel-tcb: switch to new binding

From: kbuild test robot <hidden>
Date: 2016-06-11 02:24:26

Hi,

[auto build test WARNING on at91/at91-next]
[also build test WARNING on v4.7-rc2 next-20160609]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Alexandre-Belloni/ARM-at91-rework-Atmel-TCB-drivers/20160611-062134
base:   https://git.kernel.org/pub/scm/linux/kernel/git/nferre/linux-at91.git at91-next
config: x86_64-allmodconfig (attached as .config)
compiler: gcc-6 (Debian 6.1.1-1) 6.1.1 20160430
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All warnings (new ones prefixed by >>):

   drivers/pwm/pwm-atmel-tcb.c: In function 'atmel_tcb_pwm_probe':
quoted
drivers/pwm/pwm-atmel-tcb.c:418:18: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
     tcbpwm->width = (int)match->data;
                     ^

vim +418 drivers/pwm/pwm-atmel-tcb.c

   402			dev_err(&pdev->dev, "failed to allocate memory\n");
   403			goto err_slow_clk;
   404		}
   405	
   406		tcbpwm->chip.dev = &pdev->dev;
   407		tcbpwm->chip.ops = &atmel_tcb_pwm_ops;
   408		tcbpwm->chip.of_xlate = of_pwm_xlate_with_flags;
   409		tcbpwm->chip.of_pwm_n_cells = 3;
   410		tcbpwm->chip.base = -1;
   411		tcbpwm->chip.npwm = NPWM;
   412		tcbpwm->channel = channel;
   413		tcbpwm->regmap = regmap;
   414		tcbpwm->clk = clk;
   415		tcbpwm->slow_clk = slow_clk;
   416	
   417		match = of_match_node(atmel_tcb_dt_ids, np->parent);
 > 418		tcbpwm->width = (int)match->data;
   419	
   420		err = clk_prepare_enable(slow_clk);
   421		if (err)
   422			goto err_slow_clk;
   423	
   424		spin_lock_init(&tcbpwm->lock);
   425	
   426		err = pwmchip_add(&tcbpwm->chip);

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
-------------- next part --------------
A non-text attachment was scrubbed...
Name: .config.gz
Type: application/octet-stream
Size: 54115 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160611/97d4d8be/attachment-0001.obj>

Re: [PATCH 01/48] clk: at91: replace usleep() by udelay() calls

From: Boris Brezillon <hidden>
Date: 2016-06-11 07:49:53

On Sat, 11 Jun 2016 00:03:04 +0200
Alexandre Belloni [off-list ref] wrote:
quoted hunk
From: Cyrille Pitchen <redacted>

Fix the main and slow clock .prepare() implementations which used to call
usleep() when the scheduler wasn't ready yet.

Cc: Stephen Boyd <redacted>
Cc: linux-clk at vger.kernel.org
Signed-off-by: Cyrille Pitchen <redacted>
Signed-off-by: Alexandre Belloni <redacted>
---
 drivers/clk/at91/clk-main.c | 2 +-
 drivers/clk/at91/clk-slow.c | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/clk/at91/clk-main.c b/drivers/clk/at91/clk-main.c
index 58b5baca670c..12c5062aeb92 100644
--- a/drivers/clk/at91/clk-main.c
+++ b/drivers/clk/at91/clk-main.c
@@ -342,7 +342,7 @@ static int clk_main_probe_frequency(struct regmap *regmap)
 		regmap_read(regmap, AT91_CKGR_MCFR, &mcfr);
 		if (mcfr & AT91_PMC_MAINRDY)
 			return 0;
-		usleep_range(MAINF_LOOP_MIN_WAIT, MAINF_LOOP_MAX_WAIT);
+		udelay(MAINF_LOOP_MIN_WAIT);
 	} while (time_before(prep_time, timeout));
 
 	return -ETIMEDOUT;
diff --git a/drivers/clk/at91/clk-slow.c b/drivers/clk/at91/clk-slow.c
index 61090b1146cf..612e893ce994 100644
--- a/drivers/clk/at91/clk-slow.c
+++ b/drivers/clk/at91/clk-slow.c
@@ -76,7 +76,7 @@ static int clk_slow_osc_prepare(struct clk_hw *hw)
 
 	writel(tmp | AT91_SCKC_OSC32EN, sckcr);
 
-	usleep_range(osc->startup_usec, osc->startup_usec + 1);
+	udelay(osc->startup_usec);
If you're using udelay() you should probably move the code in
->prepare() into ->enable(). The same goes for the following changes.
quoted hunk
 
 	return 0;
 }
@@ -195,7 +195,7 @@ static int clk_slow_rc_osc_prepare(struct clk_hw *hw)
 
 	writel(readl(sckcr) | AT91_SCKC_RCEN, sckcr);
 
-	usleep_range(osc->startup_usec, osc->startup_usec + 1);
+	udelay(osc->startup_usec);
 
 	return 0;
 }
@@ -304,7 +304,7 @@ static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index)
 
 	writel(tmp, sckcr);
 
-	usleep_range(SLOWCK_SW_TIME_USEC, SLOWCK_SW_TIME_USEC + 1);
+	udelay(SLOWCK_SW_TIME_USEC);
 
 	return 0;
 }


-- 
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

Re: [PATCH 44/48] clocksource: atmel-pit: allow unselecting ATMEL_PIT

From: Thomas Gleixner <hidden>
Date: 2016-06-11 09:45:56

On Sat, 11 Jun 2016, Alexandre Belloni wrote:
With the new TCB clocksource driver, atmel platforms are now able to boot
without the PIT driver. Allow unselecting it.
Yay! Thanks for doing this!

     tglx

 

Re: [PATCH 48/48] ARM: dts: at91: kizbox: switch to new pwm-atmel-tcb binding

From: Alexandre Belloni <hidden>
Date: 2016-06-11 10:25:09

On 11/06/2016 at 08:14:13 +0800, kbuild test robot wrote :
Hi,

[auto build test ERROR on at91/at91-next]
[also build test ERROR on v4.7-rc2 next-20160609]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Alexandre-Belloni/ARM-at91-rework-Atmel-TCB-drivers/20160611-062134
base:   https://git.kernel.org/pub/scm/linux/kernel/git/nferre/linux-at91.git at91-next
config: arm-at91_dt_defconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (Debian 5.3.1-8) 5.3.1 20160205
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=arm 

All errors (new ones prefixed by >>):
quoted
quoted
Error: arch/arm/boot/dts/at91-kizbox.dts:54.5-15 syntax error
   FATAL ERROR: Unable to parse input tree
Ok, I'm not sure what happened, this is now fixed in my branch.


-- 
Alexandre Belloni, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

Re: [PATCH 44/48] clocksource: atmel-pit: allow unselecting ATMEL_PIT

From: Alexandre Belloni <hidden>
Date: 2016-06-11 10:53:54

On 11/06/2016 at 11:43:54 +0200, Thomas Gleixner wrote :
On Sat, 11 Jun 2016, Alexandre Belloni wrote:
quoted
With the new TCB clocksource driver, atmel platforms are now able to boot
without the PIT driver. Allow unselecting it.
Yay! Thanks for doing this!
Sure! Can you still check the request_irq/free_irq in
timer-atmel-tcbclksrc? I'm not sure whether this can work reliably or
only because we are before SYSTEM_STATE=RUNNING.
In the latter case, I have another way of doing that.

-- 
Alexandre Belloni, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

Re: [PATCH 42/48] clocksource/drivers: Add a new driver for the Atmel ARM TC blocks

From: Boris Brezillon <hidden>
Date: 2016-06-11 12:48:16

On Sat, 11 Jun 2016 00:03:45 +0200
Alexandre Belloni [off-list ref] wrote:
Add a driver for the Atmel Timer Counter Blocks. This driver provides a
clocksource and a clockevent device. The clockevent device is linked to the
clocksource counter and so it will run at the same frequency.

This driver uses regmap and syscon to be able to probe early in the boot
and avoid having to switch on the TCB clocksource later. Using regmap also
means that unused TCB channels may be used by other drivers (PWM for
example).
First of all, thanks for working on this
tcb/libtcb/tcb-clksource/tcb-pwm mess. It looks a lot cleaner after
your changes (both the DT representation and the code itself).
Cc: Daniel Lezcano <redacted>
Cc: Thomas Gleixner <redacted>
Signed-off-by: Alexandre Belloni <redacted>
---
 drivers/clocksource/Kconfig                 |  13 ++
 drivers/clocksource/Makefile                |   3 +-
 drivers/clocksource/timer-atmel-tcbclksrc.c | 305 ++++++++++++++++++++++++++++
 include/soc/at91/atmel_tcb.h                | 220 ++++++++++++++++++++
I think the creation of atmel_tcb.h should be done in a separate commit.
quoted hunk
 4 files changed, 540 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clocksource/timer-atmel-tcbclksrc.c
 create mode 100644 include/soc/at91/atmel_tcb.h
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 47352d25c15e..ff7f4022c749 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -258,6 +258,19 @@ config ATMEL_ST
 	select CLKSRC_OF
 	select MFD_SYSCON
 
+config ATMEL_ARM_TCB_CLKSRC
+	bool "TC Block Clocksource"
+	select REGMAP_MMIO
+	depends on GENERIC_CLOCKEVENTS
+	depends on SOC_AT91RM9200 || SOC_AT91SAM9 || SOC_SAMA5
+	default SOC_AT91RM9200 || SOC_AT91SAM9 || SOC_SAMA5
+	help
+	  Select this to get a high precision clocksource based on a
+	  TC block with a 5+ MHz base clock rate.
+	  On platforms with 16-bit counters, two timer channels are combined
+	  to make a single 32-bit timer.
+	  It can also be used as a clock event device supporting oneshot mode.
+
 config CLKSRC_METAG_GENERIC
 	def_bool y if METAG
 	help
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 473974f9590a..988f33de5808 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -1,7 +1,8 @@
 obj-$(CONFIG_CLKSRC_PROBE)	+= clksrc-probe.o
 obj-$(CONFIG_ATMEL_PIT)		+= timer-atmel-pit.o
 obj-$(CONFIG_ATMEL_ST)		+= timer-atmel-st.o
-obj-$(CONFIG_ATMEL_TCB_CLKSRC)	+= tcb_clksrc.o
+obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o
+obj-$(CONFIG_ATMEL_ARM_TCB_CLKSRC)	+= timer-atmel-tcbclksrc.o
 obj-$(CONFIG_X86_PM_TIMER)	+= acpi_pm.o
 obj-$(CONFIG_SCx200HR_TIMER)	+= scx200_hrt.o
 obj-$(CONFIG_CS5535_CLOCK_EVENT_SRC)	+= cs5535-clockevt.o
diff --git a/drivers/clocksource/timer-atmel-tcbclksrc.c b/drivers/clocksource/timer-atmel-tcbclksrc.c
new file mode 100644
index 000000000000..af0b1aab7a98
--- /dev/null
+++ b/drivers/clocksource/timer-atmel-tcbclksrc.c
@@ -0,0 +1,305 @@
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_irq.h>
+#include <linux/regmap.h>
+#include <linux/sched_clock.h>
+#include <soc/at91/atmel_tcb.h>
+
+struct atmel_tcb_clksrc {
+	struct clocksource clksrc;
+	struct clock_event_device clkevt;
+	struct regmap *regmap;
+	struct clk *clk[2];
+	int channels[2];
+	u8 bits;
+	unsigned int irq;
+	bool registered;
+	bool irq_requested;
+};
+
+static struct atmel_tcb_clksrc tc = {
+	.clksrc = {
+		.name		= "tcb_clksrc",
+		.rating		= 200,
+		.mask		= CLOCKSOURCE_MASK(32),
+		.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
			^ 2 tabs here
+	},
+	.clkevt	= {
+		.name			= "tcb_clkevt",
			^ 3 here

Can you make that consistent?
Actually, I'm not a big fan of those tabs, but if you decide to use
tabs, use the same number of them everywhere.
+		.features		= CLOCK_EVT_FEAT_ONESHOT,
+		/* Should be lower than at91rm9200's system timer */
+		.rating			= 125,
+	},
+};
+
[...]
+
+static int tcb_clkevt_next_event(unsigned long delta,
+				 struct clock_event_device *d)
+{
+	u32 val;
+
+	regmap_read(tc.regmap, ATMEL_TC_CV(tc.channels[0]), &val);
+	regmap_write(tc.regmap, ATMEL_TC_RC(tc.channels[0]), val + delta);
+	regmap_write(tc.regmap, ATMEL_TC_IER(tc.channels[0]), ATMEL_TC_CPCS);
Hm, not sure this is 100% sure. What happens if by the time you write
TC_RC, the delta value has expired? This means you'll have to wait
another round before the TC engine generates the "RC reached" interrupt.

I know this is very unlikely, but should we take the risk?

The core seems to check the ->set_next_event() return value and tries to
adjust ->min_delta_ns if it returns an error, so maybe it's worth
testing if val + delta has already occurred just before enabling the
TC_CPCS interrupt, and if it's the case, return an -ETIME error.

Something like:

	u32 val[2], next;

	regmap_read(tc.regmap, ATMEL_TC_CV(tc.channels[0]), &val[0]);
	next = (val[0] + delta) & GENMASK(tc.bits - 1, 0);
	regmap_write(tc.regmap, ATMEL_TC_RC(tc.channels[0]), next);
	regmap_read(tc.regmap, ATMEL_TC_CV(tc.channels[0]), &val[1]);

	if ((next < val[0] && val[1] < val[0] && val[1] >= next) ||
	    (next > val[0] && (val[1] < val[0] || val[1] >= next))) {
		/*
		 * Clear the CPCS bit in the status register to avoid
		 * generating a spurious interrupt next time a valid
		 * timer event is configured.
		 * FIXME: not sure it's safe, since it also clears the
		 * overflow status, but it seems this flag is not used
		 * by the driver anyway.
		 */
		regmap_read(tc.regmap, ATMEL_TC_SR, &val[0]);
		return -ETIME;
	}

	
	regmap_write(tc.regmap, ATMEL_TC_IER(tc.channels[0]),
		     ATMEL_TC_CPCS);

Thomas, Daniel, what's your opinion? 
+
+	return 0;
+}
+

-- 
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

Re: [PATCH 01/48] clk: at91: replace usleep() by udelay() calls

From: Alexandre Belloni <hidden>
Date: 2016-06-13 15:24:23

On 11/06/2016 at 00:30:36 +0200, Arnd Bergmann wrote :
On Saturday, June 11, 2016 12:03:04 AM CEST Alexandre Belloni wrote:
quoted
From: Cyrille Pitchen <redacted>

Fix the main and slow clock .prepare() implementations which used to call
usleep() when the scheduler wasn't ready yet.
Does this have to be called that early? It seems wasteful to always
call udelay() here, when these are functions that are normally
allowed to sleep.
So I've tested it and something like that would work:

	if (system_state < SYSTEM_RUNNING)
		udelay(osc->startup_usec);
	else
		usleep_range(osc->startup_usec, osc->startup_usec + 1);

But I'm afraid it would be the first driver to actually do something
like that (however, it is already the only driver trying to sleep). 

-- 
Alexandre Belloni, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

Re: [PATCH 44/48] clocksource: atmel-pit: allow unselecting ATMEL_PIT

From: Boris Brezillon <hidden>
Date: 2016-06-13 19:04:25

On Sat, 11 Jun 2016 12:53:51 +0200
Alexandre Belloni [off-list ref] wrote:
On 11/06/2016 at 11:43:54 +0200, Thomas Gleixner wrote :
quoted
On Sat, 11 Jun 2016, Alexandre Belloni wrote:
  
quoted
With the new TCB clocksource driver, atmel platforms are now able to boot
without the PIT driver. Allow unselecting it.  
Yay! Thanks for doing this!
  
Sure! Can you still check the request_irq/free_irq in
timer-atmel-tcbclksrc? I'm not sure whether this can work reliably or
only because we are before SYSTEM_STATE=RUNNING.
In the latter case, I have another way of doing that.
Sorry to put it back on the table, but shouldn't we consider adding
these irq_disable/enable_action() helpers?

-- 
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

Re: [PATCH 44/48] clocksource: atmel-pit: allow unselecting ATMEL_PIT

From: Thomas Gleixner <hidden>
Date: 2016-06-13 19:16:50

On Mon, 13 Jun 2016, Boris Brezillon wrote:
On Sat, 11 Jun 2016 12:53:51 +0200
Alexandre Belloni [off-list ref] wrote:
quoted
On 11/06/2016 at 11:43:54 +0200, Thomas Gleixner wrote :
quoted
On Sat, 11 Jun 2016, Alexandre Belloni wrote:
  
quoted
With the new TCB clocksource driver, atmel platforms are now able to boot
without the PIT driver. Allow unselecting it.  
Yay! Thanks for doing this!
  
Sure! Can you still check the request_irq/free_irq in
timer-atmel-tcbclksrc? I'm not sure whether this can work reliably or
only because we are before SYSTEM_STATE=RUNNING.
In the latter case, I have another way of doing that.
Sorry to put it back on the table, but shouldn't we consider adding
these irq_disable/enable_action() helpers?
I fear that's the only reliable way to do it.

Re: [PATCH 01/48] clk: at91: replace usleep() by udelay() calls

From: Arnd Bergmann <arnd@arndb.de>
Date: 2016-06-13 19:28:24

On Monday, June 13, 2016 5:24:09 PM CEST Alexandre Belloni wrote:
On 11/06/2016 at 00:30:36 +0200, Arnd Bergmann wrote :
quoted
On Saturday, June 11, 2016 12:03:04 AM CEST Alexandre Belloni wrote:
quoted
From: Cyrille Pitchen <redacted>

Fix the main and slow clock .prepare() implementations which used to call
usleep() when the scheduler wasn't ready yet.
Does this have to be called that early? It seems wasteful to always
call udelay() here, when these are functions that are normally
allowed to sleep.
So I've tested it and something like that would work:

        if (system_state < SYSTEM_RUNNING)
                udelay(osc->startup_usec);
        else
                usleep_range(osc->startup_usec, osc->startup_usec + 1);
I think that's reasonable in this case.
But I'm afraid it would be the first driver to actually do something
like that (however, it is already the only driver trying to sleep). 
We have a lot of drivers that call potentially sleeping function from
the .prepare callback, e.g. when they go to an i2c controller.

	Arnd

Re: [PATCH 01/48] clk: at91: replace usleep() by udelay() calls

From: Afzal Mohammed <hidden>
Date: 2016-06-14 16:05:32

Hi,

On Mon, Jun 13, 2016 at 05:24:09PM +0200, Alexandre Belloni wrote:
On 11/06/2016 at 00:30:36 +0200, Arnd Bergmann wrote :
quoted
Does this have to be called that early? It seems wasteful to always
call udelay() here, when these are functions that are normally
allowed to sleep.
So I've tested it and something like that would work:

	if (system_state < SYSTEM_RUNNING)
		udelay(osc->startup_usec);
	else
		usleep_range(osc->startup_usec, osc->startup_usec + 1);

But I'm afraid it would be the first driver to actually do something
like that (however, it is already the only driver trying to sleep). 
tglx has suggested to modify clock core to handle a somewhat similar
kind of scenario (probably should work here too) and avoid driver
changes,

http://lkml.kernel.org/r/alpine.DEB.2.11.1606061448010.28031 at nanos

Regards
afzal

Re: [PATCH 01/48] clk: at91: replace usleep() by udelay() calls

From: Boris Brezillon <hidden>
Date: 2016-06-14 16:18:29

On Tue, 14 Jun 2016 21:35:17 +0530
Afzal Mohammed [off-list ref] wrote:
Hi,

On Mon, Jun 13, 2016 at 05:24:09PM +0200, Alexandre Belloni wrote:
quoted
On 11/06/2016 at 00:30:36 +0200, Arnd Bergmann wrote :  
quoted
quoted
Does this have to be called that early? It seems wasteful to always
call udelay() here, when these are functions that are normally
allowed to sleep.  
quoted
So I've tested it and something like that would work:

	if (system_state < SYSTEM_RUNNING)
		udelay(osc->startup_usec);
	else
		usleep_range(osc->startup_usec, osc->startup_usec + 1);

But I'm afraid it would be the first driver to actually do something
like that (however, it is already the only driver trying to sleep).   
tglx has suggested to modify clock core to handle a somewhat similar
kind of scenario (probably should work here too) and avoid driver
changes,

http://lkml.kernel.org/r/alpine.DEB.2.11.1606061448010.28031 at nanos
Oh, interesting. Definitely a better solution than this custom check.


-- 
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

Re: [PATCH 02/48] ARM: at91: Document new TCB bindings

From: Rob Herring <robh@kernel.org>
Date: 2016-06-14 21:47:42

On Sat, Jun 11, 2016 at 12:03:05AM +0200, Alexandre Belloni wrote:
The current binding for the TCB is not flexible enough for some use cases
and prevents proper utilization of all the channels.

Cc: Daniel Lezcano <redacted>
Cc: Thierry Reding <redacted>
Cc: linux-pwm at vger.kernel.org
Cc: Rob Herring <robh+dt@kernel.org>
Cc: devicetree at vger.kernel.org
Signed-off-by: Alexandre Belloni <redacted>
---
 .../devicetree/bindings/arm/atmel-at91.txt         | 32 -----------
 .../devicetree/bindings/mfd/atmel-tcb.txt          | 62 ++++++++++++++++++++++
 .../devicetree/bindings/pwm/atmel-tcb-pwm.txt      | 12 +++--
 3 files changed, 69 insertions(+), 37 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mfd/atmel-tcb.txt
[...]
quoted hunk
diff --git a/Documentation/devicetree/bindings/mfd/atmel-tcb.txt b/Documentation/devicetree/bindings/mfd/atmel-tcb.txt
new file mode 100644
index 000000000000..48196752c78f
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/atmel-tcb.txt
@@ -0,0 +1,62 @@
+* Device tree bindings for Atmel Timer Counter Blocks
+- compatible: Should be "atmel,<chip>-tcb", "simple-mfd", "syscon".
+  <chip> can be "at91rm9200" or "at91sam9x5"
+- reg: Should contain registers location and length
+- #address-cells: has to be 1
+- #size-cells: has to be 0
+- interrupts: Should contain all interrupts for the TC block
+  Note that you can specify several interrupt cells if the TC
+  block has one interrupt per channel.
+- clock-names: tuple listing input clock names.
+	Required elements: "t0_clk", "slow_clk"
+	Optional elements: "t1_clk", "t2_clk"
+- clocks: phandles to input clocks.
What is the order of clocks?
+
+The TCB can expose multiple subdevices:
+ * a clocksource and clockevent device
No. These compatible names are linuxisms. Describe features of the 
timers to be able to select which timer to use if you need to pick 
certain timers. For example, interrupt capability could be used to 
select the clkevt.
+   - compatible: Should be "atmel,tcb-clksrc"
+   - reg: Should contain the TCB channels to be used. If the
+     counter width is 16 bits (at91rm9200-tcb), two consecutive
+     channels are needed. Else, only one channel will be used.
+
+ * a clockevent device
+   - compatible: Should be "atmel,tcb-clkevt"
+   - reg: Should contain the TCB channel to be used
+
+ * a PWM chip: see ../pwm/atmel-tcb-pwm.txt
+
+Examples:
+
+One interrupt per TC block:
+	tcb0: timer at fff7c000 {
+		compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0xfff7c000 0x100>;
+		interrupts = <18 4>;
+		clocks = <&tcb0_clk>;
+		clock-names = "t0_clk";
Missing slow_clk
quoted hunk
+
+		timer at 0 {
+			compatible = "atmel,tcb-clksrc";
+			reg = <0>, <1>;
+		};
+
+		timer at 2 {
+			compatible = "atmel,tcb-clkevt";
+			reg = <2>;
+		};
+	};
+
+One interrupt per TC channel in a TC block:
+	tcb1: timer at fffdc000 {
+		compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0xfffdc000 0x100>;
+		interrupts = <26 4>, <27 4>, <28 4>;
+		clocks = <&tcb1_clk>;
+		clock-names = "t0_clk";
+	};
+
+
diff --git a/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt b/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt
index 8031148bcf85..ab8fbd5ba184 100644
--- a/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt
+++ b/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt
@@ -2,15 +2,17 @@ Atmel TCB PWM controller
 
 Required properties:
 - compatible: should be "atmel,tcb-pwm"
+- reg: tcb channel to use. Each channel can export 2 PWMs
Is there a difference in channels? If not, then this compatible should 
go.
 - #pwm-cells: should be 3. See pwm.txt in this directory for a description of
   the cells format. The only third cell flag supported by this binding is
   PWM_POLARITY_INVERTED.
-- tc-block: The Timer Counter block to use as a PWM chip.
 
 Example:
 
-pwm {
-	compatible = "atmel,tcb-pwm";
-	#pwm-cells = <3>;
-	tc-block = <1>;
+tcb0: timer at f800c000 {
+	pwm at 0 {
+		compatible = "atmel,tcb-pwm";
+		reg = <0>;
+		#pwm-cells = <3>;
+	};
 };
-- 
2.8.1

Re: [PATCH 02/48] ARM: at91: Document new TCB bindings

From: Boris Brezillon <hidden>
Date: 2016-06-15 07:30:11

On Tue, 14 Jun 2016 16:47:37 -0500
Rob Herring [off-list ref] wrote:
On Sat, Jun 11, 2016 at 12:03:05AM +0200, Alexandre Belloni wrote:
quoted
The current binding for the TCB is not flexible enough for some use cases
and prevents proper utilization of all the channels.

Cc: Daniel Lezcano <redacted>
Cc: Thierry Reding <redacted>
Cc: linux-pwm at vger.kernel.org
Cc: Rob Herring <robh+dt@kernel.org>
Cc: devicetree at vger.kernel.org
Signed-off-by: Alexandre Belloni <redacted>
---
 .../devicetree/bindings/arm/atmel-at91.txt         | 32 -----------
 .../devicetree/bindings/mfd/atmel-tcb.txt          | 62 ++++++++++++++++++++++
 .../devicetree/bindings/pwm/atmel-tcb-pwm.txt      | 12 +++--
 3 files changed, 69 insertions(+), 37 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mfd/atmel-tcb.txt  
[...]
quoted
diff --git a/Documentation/devicetree/bindings/mfd/atmel-tcb.txt b/Documentation/devicetree/bindings/mfd/atmel-tcb.txt
new file mode 100644
index 000000000000..48196752c78f
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/atmel-tcb.txt
@@ -0,0 +1,62 @@
+* Device tree bindings for Atmel Timer Counter Blocks
+- compatible: Should be "atmel,<chip>-tcb", "simple-mfd", "syscon".
+  <chip> can be "at91rm9200" or "at91sam9x5"
+- reg: Should contain registers location and length
+- #address-cells: has to be 1
+- #size-cells: has to be 0
+- interrupts: Should contain all interrupts for the TC block
+  Note that you can specify several interrupt cells if the TC
+  block has one interrupt per channel.
+- clock-names: tuple listing input clock names.
+	Required elements: "t0_clk", "slow_clk"
+	Optional elements: "t1_clk", "t2_clk"
+- clocks: phandles to input clocks.  
What is the order of clocks?
quoted
+
+The TCB can expose multiple subdevices:
+ * a clocksource and clockevent device  
No. These compatible names are linuxisms. Describe features of the 
timers to be able to select which timer to use if you need to pick 
certain timers. For example, interrupt capability could be used to 
select the clkevt.
Would 'atmel,tcb-free-running-timer' (to replace 'atmel,tcb-clksrc') and
'atmel,tcb-programmable-timer' (to replace 'atmel,tcb-clkevt') be
acceptable?
quoted
+   - compatible: Should be "atmel,tcb-clksrc"
+   - reg: Should contain the TCB channels to be used. If the
+     counter width is 16 bits (at91rm9200-tcb), two consecutive
+     channels are needed. Else, only one channel will be used.
+
+ * a clockevent device
+   - compatible: Should be "atmel,tcb-clkevt"
+   - reg: Should contain the TCB channel to be used
+
+ * a PWM chip: see ../pwm/atmel-tcb-pwm.txt
+
+Examples:
+
+One interrupt per TC block:
+	tcb0: timer at fff7c000 {
+		compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0xfff7c000 0x100>;
+		interrupts = <18 4>;
+		clocks = <&tcb0_clk>;
+		clock-names = "t0_clk";  
Missing slow_clk
quoted
+
+		timer at 0 {
+			compatible = "atmel,tcb-clksrc";
+			reg = <0>, <1>;
+		};
+
+		timer at 2 {
+			compatible = "atmel,tcb-clkevt";
+			reg = <2>;
+		};
+	};
+
+One interrupt per TC channel in a TC block:
+	tcb1: timer at fffdc000 {
+		compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0xfffdc000 0x100>;
+		interrupts = <26 4>, <27 4>, <28 4>;
+		clocks = <&tcb1_clk>;
+		clock-names = "t0_clk";
+	};
+
+
diff --git a/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt b/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt
index 8031148bcf85..ab8fbd5ba184 100644
--- a/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt
+++ b/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt
@@ -2,15 +2,17 @@ Atmel TCB PWM controller
 
 Required properties:
 - compatible: should be "atmel,tcb-pwm"
+- reg: tcb channel to use. Each channel can export 2 PWMs  
Is there a difference in channels? If not, then this compatible should 
go.
This one I don't understand.
The TCB (Timer Counter Block) is an MFD containing 3 Timer Counter
devices. Each of these devices (also called channels) can be assigned a
specific mode:
- timer mode (free-running of programmable)
- waveform generator mode (IOW, a PWM)
- capture mode (an IIO device, but we don't have any driver for that
  right now)

So each sub-device of the TCB is represented as a sub-node with its own
compatible. Is there a problem with that?
quoted
 - #pwm-cells: should be 3. See pwm.txt in this directory for a description of
   the cells format. The only third cell flag supported by this binding is
   PWM_POLARITY_INVERTED.
-- tc-block: The Timer Counter block to use as a PWM chip.
 
 Example:
 
-pwm {
-	compatible = "atmel,tcb-pwm";
-	#pwm-cells = <3>;
-	tc-block = <1>;
+tcb0: timer at f800c000 {
+	pwm at 0 {
+		compatible = "atmel,tcb-pwm";
+		reg = <0>;
+		#pwm-cells = <3>;
+	};
 };
-- 
2.8.1
  


-- 
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

Re: [PATCH 44/48] clocksource: atmel-pit: allow unselecting ATMEL_PIT

From: Boris Brezillon <hidden>
Date: 2016-06-16 14:42:16

Hi Thomas,

On Mon, 13 Jun 2016 21:14:47 +0200 (CEST)
Thomas Gleixner [off-list ref] wrote:
On Mon, 13 Jun 2016, Boris Brezillon wrote:
quoted
On Sat, 11 Jun 2016 12:53:51 +0200
Alexandre Belloni [off-list ref] wrote:
  
quoted
On 11/06/2016 at 11:43:54 +0200, Thomas Gleixner wrote :  
quoted
On Sat, 11 Jun 2016, Alexandre Belloni wrote:
    
quoted
With the new TCB clocksource driver, atmel platforms are now able to boot
without the PIT driver. Allow unselecting it.    
Yay! Thanks for doing this!
    
Sure! Can you still check the request_irq/free_irq in
timer-atmel-tcbclksrc? I'm not sure whether this can work reliably or
only because we are before SYSTEM_STATE=RUNNING.
In the latter case, I have another way of doing that.
  
Sorry to put it back on the table, but shouldn't we consider adding
these irq_disable/enable_action() helpers?  
I fear that's the only reliable way to do it.
Alexandre told me you had a better implementation (or idea, I don't
remember) than what was proposed here [1].
Do you plan to submit something, or should we work on it?

Regards,

Boris

[1]https://lkml.org/lkml/2015/8/3/330

-- 
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

Re: [PATCH 02/48] ARM: at91: Document new TCB bindings

From: Rob Herring <robh@kernel.org>
Date: 2016-06-21 20:08:15

On Wed, Jun 15, 2016 at 09:29:55AM +0200, Boris Brezillon wrote:
On Tue, 14 Jun 2016 16:47:37 -0500
Rob Herring [off-list ref] wrote:
quoted
On Sat, Jun 11, 2016 at 12:03:05AM +0200, Alexandre Belloni wrote:
quoted
The current binding for the TCB is not flexible enough for some use cases
and prevents proper utilization of all the channels.

Cc: Daniel Lezcano <redacted>
Cc: Thierry Reding <redacted>
Cc: linux-pwm at vger.kernel.org
Cc: Rob Herring <robh+dt@kernel.org>
Cc: devicetree at vger.kernel.org
Signed-off-by: Alexandre Belloni <redacted>
---
 .../devicetree/bindings/arm/atmel-at91.txt         | 32 -----------
 .../devicetree/bindings/mfd/atmel-tcb.txt          | 62 ++++++++++++++++++++++
 .../devicetree/bindings/pwm/atmel-tcb-pwm.txt      | 12 +++--
 3 files changed, 69 insertions(+), 37 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mfd/atmel-tcb.txt  
[...]
quoted
diff --git a/Documentation/devicetree/bindings/mfd/atmel-tcb.txt b/Documentation/devicetree/bindings/mfd/atmel-tcb.txt
new file mode 100644
index 000000000000..48196752c78f
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/atmel-tcb.txt
@@ -0,0 +1,62 @@
+* Device tree bindings for Atmel Timer Counter Blocks
+- compatible: Should be "atmel,<chip>-tcb", "simple-mfd", "syscon".
+  <chip> can be "at91rm9200" or "at91sam9x5"
+- reg: Should contain registers location and length
+- #address-cells: has to be 1
+- #size-cells: has to be 0
+- interrupts: Should contain all interrupts for the TC block
+  Note that you can specify several interrupt cells if the TC
+  block has one interrupt per channel.
+- clock-names: tuple listing input clock names.
+	Required elements: "t0_clk", "slow_clk"
+	Optional elements: "t1_clk", "t2_clk"
+- clocks: phandles to input clocks.  
What is the order of clocks?
quoted
+
+The TCB can expose multiple subdevices:
+ * a clocksource and clockevent device  
No. These compatible names are linuxisms. Describe features of the 
timers to be able to select which timer to use if you need to pick 
certain timers. For example, interrupt capability could be used to 
select the clkevt.
Would 'atmel,tcb-free-running-timer' (to replace 'atmel,tcb-clksrc') and
'atmel,tcb-programmable-timer' (to replace 'atmel,tcb-clkevt') be
acceptable?
If that somehow matches the documentation or accurately describes the 
h/w capabilities for them, then yes.

Rob

Re: [PATCH 02/48] ARM: at91: Document new TCB bindings

From: Rob Herring <robh@kernel.org>
Date: 2016-06-21 20:44:41

On Wed, Jun 15, 2016 at 09:29:55AM +0200, Boris Brezillon wrote:
On Tue, 14 Jun 2016 16:47:37 -0500
Rob Herring [off-list ref] wrote:
quoted
On Sat, Jun 11, 2016 at 12:03:05AM +0200, Alexandre Belloni wrote:
quoted
The current binding for the TCB is not flexible enough for some use cases
and prevents proper utilization of all the channels.

Cc: Daniel Lezcano <redacted>
Cc: Thierry Reding <redacted>
Cc: linux-pwm at vger.kernel.org
Cc: Rob Herring <robh+dt@kernel.org>
Cc: devicetree at vger.kernel.org
Signed-off-by: Alexandre Belloni <redacted>
---
 .../devicetree/bindings/arm/atmel-at91.txt         | 32 -----------
 .../devicetree/bindings/mfd/atmel-tcb.txt          | 62 ++++++++++++++++++++++
 .../devicetree/bindings/pwm/atmel-tcb-pwm.txt      | 12 +++--
 3 files changed, 69 insertions(+), 37 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mfd/atmel-tcb.txt  
[...]
quoted
quoted
diff --git a/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt b/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt
index 8031148bcf85..ab8fbd5ba184 100644
--- a/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt
+++ b/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt
@@ -2,15 +2,17 @@ Atmel TCB PWM controller
 
 Required properties:
 - compatible: should be "atmel,tcb-pwm"
+- reg: tcb channel to use. Each channel can export 2 PWMs  
Is there a difference in channels? If not, then this compatible should 
go.
This one I don't understand.
The TCB (Timer Counter Block) is an MFD containing 3 Timer Counter
devices. Each of these devices (also called channels) can be assigned a
specific mode:
- timer mode (free-running of programmable)
- waveform generator mode (IOW, a PWM)
- capture mode (an IIO device, but we don't have any driver for that
  right now)

So each sub-device of the TCB is represented as a sub-node with its own
compatible. Is there a problem with that?
Missed this in my first reply. I guess for purposes of referencing pwm 
from other nodes this is okay.

Rob

Re: [PATCH 42/48] clocksource/drivers: Add a new driver for the Atmel ARM TC blocks

From: Daniel Lezcano <hidden>
Date: 2016-06-22 13:07:23

On 06/11/2016 02:48 PM, Boris Brezillon wrote:

[ ... ]
quoted
+static int tcb_clkevt_next_event(unsigned long delta,
+				 struct clock_event_device *d)
+{
+	u32 val;
+
+	regmap_read(tc.regmap, ATMEL_TC_CV(tc.channels[0]), &val);
+	regmap_write(tc.regmap, ATMEL_TC_RC(tc.channels[0]), val + delta);
+	regmap_write(tc.regmap, ATMEL_TC_IER(tc.channels[0]), ATMEL_TC_CPCS);
Hm, not sure this is 100% sure. What happens if by the time you write
TC_RC, the delta value has expired? This means you'll have to wait
another round before the TC engine generates the "RC reached" interrupt.

I know this is very unlikely, but should we take the risk?

The core seems to check the ->set_next_event() return value and tries to
adjust ->min_delta_ns if it returns an error, so maybe it's worth
testing if val + delta has already occurred just before enabling the
TC_CPCS interrupt, and if it's the case, return an -ETIME error.

Something like:

	u32 val[2], next;

	regmap_read(tc.regmap, ATMEL_TC_CV(tc.channels[0]), &val[0]);
	next = (val[0] + delta) & GENMASK(tc.bits - 1, 0);
	regmap_write(tc.regmap, ATMEL_TC_RC(tc.channels[0]), next);
	regmap_read(tc.regmap, ATMEL_TC_CV(tc.channels[0]), &val[1]);

	if ((next < val[0] && val[1] < val[0] && val[1] >= next) ||
	    (next > val[0] && (val[1] < val[0] || val[1] >= next))) {
		/*
		 * Clear the CPCS bit in the status register to avoid
		 * generating a spurious interrupt next time a valid
		 * timer event is configured.
		 * FIXME: not sure it's safe, since it also clears the
		 * overflow status, but it seems this flag is not used
		 * by the driver anyway.
		 */
		regmap_read(tc.regmap, ATMEL_TC_SR, &val[0]);
		return -ETIME;
	}

	
	regmap_write(tc.regmap, ATMEL_TC_IER(tc.channels[0]),
		     ATMEL_TC_CPCS);

Thomas, Daniel, what's your opinion?
Are you describing the same as commit 
f9eccf24615672896dc13251410c3f2f33a14f95 ?


-- 
  <http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

Re: [PATCH 42/48] clocksource/drivers: Add a new driver for the Atmel ARM TC blocks

From: Boris Brezillon <hidden>
Date: 2016-06-22 13:24:34

On Wed, 22 Jun 2016 15:07:00 +0200
Daniel Lezcano [off-list ref] wrote:
On 06/11/2016 02:48 PM, Boris Brezillon wrote:

[ ... ]
quoted
quoted
+static int tcb_clkevt_next_event(unsigned long delta,
+				 struct clock_event_device *d)
+{
+	u32 val;
+
+	regmap_read(tc.regmap, ATMEL_TC_CV(tc.channels[0]), &val);
+	regmap_write(tc.regmap, ATMEL_TC_RC(tc.channels[0]), val + delta);
+	regmap_write(tc.regmap, ATMEL_TC_IER(tc.channels[0]), ATMEL_TC_CPCS);  
Hm, not sure this is 100% sure. What happens if by the time you write
TC_RC, the delta value has expired? This means you'll have to wait
another round before the TC engine generates the "RC reached" interrupt.

I know this is very unlikely, but should we take the risk?

The core seems to check the ->set_next_event() return value and tries to
adjust ->min_delta_ns if it returns an error, so maybe it's worth
testing if val + delta has already occurred just before enabling the
TC_CPCS interrupt, and if it's the case, return an -ETIME error.

Something like:

	u32 val[2], next;

	regmap_read(tc.regmap, ATMEL_TC_CV(tc.channels[0]), &val[0]);
	next = (val[0] + delta) & GENMASK(tc.bits - 1, 0);
	regmap_write(tc.regmap, ATMEL_TC_RC(tc.channels[0]), next);
	regmap_read(tc.regmap, ATMEL_TC_CV(tc.channels[0]), &val[1]);

	if ((next < val[0] && val[1] < val[0] && val[1] >= next) ||
	    (next > val[0] && (val[1] < val[0] || val[1] >= next))) {
		/*
		 * Clear the CPCS bit in the status register to avoid
		 * generating a spurious interrupt next time a valid
		 * timer event is configured.
		 * FIXME: not sure it's safe, since it also clears the
		 * overflow status, but it seems this flag is not used
		 * by the driver anyway.
		 */
		regmap_read(tc.regmap, ATMEL_TC_SR, &val[0]);
		return -ETIME;
	}

	
	regmap_write(tc.regmap, ATMEL_TC_IER(tc.channels[0]),
		     ATMEL_TC_CPCS);

Thomas, Daniel, what's your opinion?  
Are you describing the same as commit 
f9eccf24615672896dc13251410c3f2f33a14f95 ?
Pretty much, yes. Note that this is purely hypothetical in the TCB
case, but I fear people might experience this problem if they're trying
to configure tiny delay values.

Re: [PATCH 42/48] clocksource/drivers: Add a new driver for the Atmel ARM TC blocks

From: Daniel Lezcano <hidden>
Date: 2016-06-24 10:07:06

On 06/11/2016 12:03 AM, Alexandre Belloni wrote:
quoted hunk
Add a driver for the Atmel Timer Counter Blocks. This driver provides a
clocksource and a clockevent device. The clockevent device is linked to the
clocksource counter and so it will run at the same frequency.

This driver uses regmap and syscon to be able to probe early in the boot
and avoid having to switch on the TCB clocksource later. Using regmap also
means that unused TCB channels may be used by other drivers (PWM for
example).

Cc: Daniel Lezcano <redacted>
Cc: Thomas Gleixner <redacted>
Signed-off-by: Alexandre Belloni <redacted>
---
  drivers/clocksource/Kconfig                 |  13 ++
  drivers/clocksource/Makefile                |   3 +-
  drivers/clocksource/timer-atmel-tcbclksrc.c | 305 ++++++++++++++++++++++++++++
  include/soc/at91/atmel_tcb.h                | 220 ++++++++++++++++++++
  4 files changed, 540 insertions(+), 1 deletion(-)
  create mode 100644 drivers/clocksource/timer-atmel-tcbclksrc.c
  create mode 100644 include/soc/at91/atmel_tcb.h
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 47352d25c15e..ff7f4022c749 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -258,6 +258,19 @@ config ATMEL_ST
  	select CLKSRC_OF
  	select MFD_SYSCON

+config ATMEL_ARM_TCB_CLKSRC
+	bool "TC Block Clocksource"
The Kconfig options are set now with the COMPILE_TEST option in order to 
increase the compilation test coverage.

Please, add bool "TC Block Clocksource" if COMPILE_TEST, ...
+	select REGMAP_MMIO
+	depends on GENERIC_CLOCKEVENTS
+	depends on SOC_AT91RM9200 || SOC_AT91SAM9 || SOC_SAMA5
+	default SOC_AT91RM9200 || SOC_AT91SAM9 || SOC_SAMA5
... remove these dependencies and let the SoC's Kconfig to select the 
timer like the other timers are.
quoted hunk
+	help
+	  Select this to get a high precision clocksource based on a
+	  TC block with a 5+ MHz base clock rate.
+	  On platforms with 16-bit counters, two timer channels are combined
+	  to make a single 32-bit timer.
+	  It can also be used as a clock event device supporting oneshot mode.
+
  config CLKSRC_METAG_GENERIC
  	def_bool y if METAG
  	help
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 473974f9590a..988f33de5808 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -1,7 +1,8 @@
  obj-$(CONFIG_CLKSRC_PROBE)	+= clksrc-probe.o
  obj-$(CONFIG_ATMEL_PIT)		+= timer-atmel-pit.o
  obj-$(CONFIG_ATMEL_ST)		+= timer-atmel-st.o
-obj-$(CONFIG_ATMEL_TCB_CLKSRC)	+= tcb_clksrc.o
+obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o
+obj-$(CONFIG_ATMEL_ARM_TCB_CLKSRC)	+= timer-atmel-tcbclksrc.o
  obj-$(CONFIG_X86_PM_TIMER)	+= acpi_pm.o
  obj-$(CONFIG_SCx200HR_TIMER)	+= scx200_hrt.o
  obj-$(CONFIG_CS5535_CLOCK_EVENT_SRC)	+= cs5535-clockevt.o
diff --git a/drivers/clocksource/timer-atmel-tcbclksrc.c b/drivers/clocksource/timer-atmel-tcbclksrc.c
new file mode 100644
index 000000000000..af0b1aab7a98
--- /dev/null
+++ b/drivers/clocksource/timer-atmel-tcbclksrc.c
@@ -0,0 +1,305 @@
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_irq.h>
+#include <linux/regmap.h>
+#include <linux/sched_clock.h>
+#include <soc/at91/atmel_tcb.h>
+
+struct atmel_tcb_clksrc {
+	struct clocksource clksrc;
+	struct clock_event_device clkevt;
+	struct regmap *regmap;
+	struct clk *clk[2];
+	int channels[2];
+	u8 bits;
+	unsigned int irq;
The test in the init function checks against < 0 but 'irq' is 'unsigned'
+	bool registered;
+	bool irq_requested;
+};
+
+static struct atmel_tcb_clksrc tc = {
+	.clksrc = {
+		.name		= "tcb_clksrc",
+		.rating		= 200,
+		.mask		= CLOCKSOURCE_MASK(32),
+		.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
+	},
+	.clkevt	= {
+		.name			= "tcb_clkevt",
+		.features		= CLOCK_EVT_FEAT_ONESHOT,
+		/* Should be lower than at91rm9200's system timer */
+		.rating			= 125,
+	},
+};
+
+static cycle_t tc_get_cycles(struct clocksource *cs)
+{
+	unsigned long	flags;
+	u32		lower, upper, tmp;
+
+	raw_local_irq_save(flags);
+	do {
+		regmap_read(tc.regmap, ATMEL_TC_CV(1), &upper);
+		regmap_read(tc.regmap, ATMEL_TC_CV(0), &lower);
+		regmap_read(tc.regmap, ATMEL_TC_CV(1), &tmp);
+	} while (upper != tmp);
+
+	raw_local_irq_restore(flags);
Why is this lock needed ?
+	return (upper << 16) | lower;
+}
+
+static cycle_t tc_get_cycles32(struct clocksource *cs)
+{
+	u32 val;
+
+	regmap_read(tc.regmap, ATMEL_TC_CV(tc.channels[0]), &val);
+
+	return val;
+}
+
+static u64 tc_sched_clock_read(void)
+{
+	return tc_get_cycles(&tc.clksrc);
+}
+
+static u64 tc_sched_clock_read32(void)
+{
+	return tc_get_cycles32(&tc.clksrc);
+}
'notrace' should be added here to avoid recursion with ftrace.
+static int tcb_clkevt_next_event(unsigned long delta,
+				 struct clock_event_device *d)
+{
+	u32 val;
+
+	regmap_read(tc.regmap, ATMEL_TC_CV(tc.channels[0]), &val);
+	regmap_write(tc.regmap, ATMEL_TC_RC(tc.channels[0]), val + delta);
+	regmap_write(tc.regmap, ATMEL_TC_IER(tc.channels[0]), ATMEL_TC_CPCS);
+
+	return 0;
+}
+
+static irqreturn_t tc_clkevt_irq(int irq, void *handle)
+{
+	unsigned int sr;
+
+	regmap_read(tc.regmap, ATMEL_TC_SR(tc.channels[0]), &sr);
+	if (sr & ATMEL_TC_CPCS) {
+		tc.clkevt.event_handler(&tc.clkevt);
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
+static int tcb_clkevt_oneshot(struct clock_event_device *dev)
+{
+	int ret;
+
+	if (tc.irq_requested)
+		return 0;
+
+	ret = request_irq(tc.irq, tc_clkevt_irq, IRQF_TIMER | IRQF_SHARED,
+			  "tcb_clkevt", &tc);
+	if (!ret)
+		tc.irq_requested = true;
The legacy driver checks clockevent_state_detached() and disables the clock.

Why is 'irq_requested' and request_irq/free_irq cleaner ?

Isn't there a configuration with the TCB register to disable the 
clockevent only ?
+	return ret;
+}
+
+static int tcb_clkevt_shutdown(struct clock_event_device *dev)
+{
+	regmap_write(tc.regmap, ATMEL_TC_IDR(tc.channels[0]), 0xff);
+	if (tc.bits == 16)
+		regmap_write(tc.regmap, ATMEL_TC_IDR(tc.channels[1]), 0xff);
+
+	if (tc.irq_requested) {
+		free_irq(tc.irq, &tc);
+		tc.irq_requested = false;
+	}
+
+	return 0;
+}
[ ... ]
+static void __init tcb_clksrc_init(struct device_node *node)
+{
+	const struct of_device_id *match;
+	u32 rate, divided_rate = 0;
+	int best_divisor_idx = -1;
+	int i, err;
+
+	if (tc.registered)
+		return;
That's getting annoying. It is not your fault but that's a repeating 
pattern when multiple nodes are defined for a timer. Someday we will 
have to sit down and think about that.
+	tc.regmap = syscon_node_to_regmap(node->parent);
+	if (IS_ERR(tc.regmap))
+		return;
+
+	match = of_match_node(atmel_tcb_dt_ids, node->parent);
+	tc.bits = (int)match->data;
+
+	err = of_property_read_u32_index(node, "reg", 0, &tc.channels[0]);
+	if (err)
+		return;
+
+	tc.channels[1] = -1;
+
+	if (tc.bits == 16) {
+		of_property_read_u32_index(node, "reg", 1, &tc.channels[1]);
+		if (tc.channels[1] == -1) {
+			pr_err("%s: clocksource needs two channels\n",
+			       node->parent->full_name);
+		}
+	}
+
+	tc.irq = tcb_irq_get(node, tc.channels[0]);
+	if (tc.irq < 0)
+		return;
+
+	tc.clk[0] = tcb_clk_get(node, tc.channels[0]);
+	if (IS_ERR(tc.clk[0]))
+		return;
+	err = clk_prepare_enable(tc.clk[0]);
+	if (err) {
+		pr_debug("can't enable T0 clk\n");
+		goto err_clk;
+	}
+
+	if (tc.bits == 16) {
+		tc.clk[1] = tcb_clk_get(node, tc.channels[1]);
+		if (IS_ERR(tc.clk[1]))
+			goto err_disable_t0;
+	}
+
+	/* How fast will we be counting?  Pick something over 5 MHz.  */
+	rate = (u32)clk_get_rate(tc.clk[0]);
+	for (i = 0; i < 5; i++) {
+		unsigned int divisor = atmel_tc_divisors[i];
+		unsigned int tmp;
+
+		if (!divisor)
+			continue;
+
+		tmp = rate / divisor;
+		pr_debug("TC: %u / %-3u [%d] --> %u\n", rate, divisor, i, tmp);
+		if (best_divisor_idx > 0) {
+			if (tmp < 5 * 1000 * 1000)
+				continue;
+		}
+		divided_rate = tmp;
+		best_divisor_idx = i;
+	}
+
+	pr_debug("%s: %s at %d.%03d MHz\n", tc.clksrc.name,
+		 node->parent->full_name, divided_rate / 1000000,
+		 ((divided_rate + 500000) % 1000000) / 1000);
+
+	if (tc.bits == 32) {
+		tc.clksrc.read = tc_get_cycles32;
+		tcb_setup_single_chan(&tc, best_divisor_idx);
+	} else {
+		err = clk_prepare_enable(tc.clk[1]);
+		if (err) {
+			pr_debug("can't enable T1 clk\n");
+			goto err_clk1;
+		}
+		tc.clksrc.read = tc_get_cycles,
+		tcb_setup_dual_chan(&tc, best_divisor_idx);
+	}
+
+	err = clocksource_register_hz(&tc.clksrc, divided_rate);
+	if (err)
+		goto err_disable_t1;
+
+	if (tc.bits == 32)
Can't you can group the code under tc.bits == 16 and tc.bits == 32 
instead of multiple check against the reg width ?
+		sched_clock_register(tc_sched_clock_read32, 32, divided_rate);
+	else
+		sched_clock_register(tc_sched_clock_read, 32, divided_rate);
+
+	tc.registered = true;
+
+	/* Set up and register clockevents */
+	tc.clkevt.cpumask = cpumask_of(0);
+	tc.clkevt.set_next_event = tcb_clkevt_next_event;
+	tc.clkevt.set_state_oneshot = tcb_clkevt_oneshot;
+	tc.clkevt.set_state_shutdown = tcb_clkevt_shutdown;
+	if (tc.bits == 16)
+		clockevents_config_and_register(&tc.clkevt, divided_rate, 1,
+						0xffff);
+	else
+		clockevents_config_and_register(&tc.clkevt, divided_rate, 1,
+						0xffffffff);
+	return;
clockevents_config_and_register(&tc.clkevt, divided_rate, 1, 
BIT(tc.bits) - 1);

IIRC, there is a macro somewhere doing BIT(n) - 1. CLOCKSOURCE_MASK does 
it but it is weird to set a clockevent with a clocksource mask.
+
+err_disable_t1:
+	if (tc.bits == 16)
+		clk_disable_unprepare(tc.clk[1]);
+
+err_clk1:
+	if (tc.bits == 16)
+		clk_put(tc.clk[1]);
+
+err_disable_t0:
+	clk_disable_unprepare(tc.clk[0]);
+
+err_clk:
+	clk_put(tc.clk[0]);
+
+	pr_err("%s: unable to register clocksource/clockevent\n",
+	       tc.clksrc.name);
+}
+CLOCKSOURCE_OF_DECLARE(atmel_tcb_clksrc, "atmel,tcb-clksrc",
+		       tcb_clksrc_init);
[ ... ]


-- 
  <http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

Re: [PATCH 42/48] clocksource/drivers: Add a new driver for the Atmel ARM TC blocks

From: Alexandre Belloni <hidden>
Date: 2017-05-16 11:59:23

Hi Daniel,

Almost one year later, I'm back on that topic.

On 24/06/2016 at 12:07:01 +0200, Daniel Lezcano wrote:
quoted
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 47352d25c15e..ff7f4022c749 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -258,6 +258,19 @@ config ATMEL_ST
  	select CLKSRC_OF
  	select MFD_SYSCON

+config ATMEL_ARM_TCB_CLKSRC
+	bool "TC Block Clocksource"
The Kconfig options are set now with the COMPILE_TEST option in order to
increase the compilation test coverage.

Please, add bool "TC Block Clocksource" if COMPILE_TEST, ...
quoted
+	select REGMAP_MMIO
+	depends on GENERIC_CLOCKEVENTS
+	depends on SOC_AT91RM9200 || SOC_AT91SAM9 || SOC_SAMA5
+	default SOC_AT91RM9200 || SOC_AT91SAM9 || SOC_SAMA5
... remove these dependencies and let the SoC's Kconfig to select the timer
like the other timers are.
The main issue with what you suggest is that it removes the possibility
to not compile the driver. This may be interesting for people using the
PIT as the clocksource/clockevent and the TCBs for something else.
quoted
+static cycle_t tc_get_cycles(struct clocksource *cs)
+{
+	unsigned long	flags;
+	u32		lower, upper, tmp;
+
+	raw_local_irq_save(flags);
+	do {
+		regmap_read(tc.regmap, ATMEL_TC_CV(1), &upper);
+		regmap_read(tc.regmap, ATMEL_TC_CV(0), &lower);
+		regmap_read(tc.regmap, ATMEL_TC_CV(1), &tmp);
+	} while (upper != tmp);
+
+	raw_local_irq_restore(flags);
Why is this lock needed ?
I've taken that from the old driver, I'm not sure this is needed. Maybe
to lower the chance to have upper != tmp.
quoted
+	return (upper << 16) | lower;
+}
+
quoted
+static int tcb_clkevt_oneshot(struct clock_event_device *dev)
+{
+	int ret;
+
+	if (tc.irq_requested)
+		return 0;
+
+	ret = request_irq(tc.irq, tc_clkevt_irq, IRQF_TIMER | IRQF_SHARED,
+			  "tcb_clkevt", &tc);
+	if (!ret)
+		tc.irq_requested = true;
The legacy driver checks clockevent_state_detached() and disables the clock.
This feature is different from the legacy driver. Here, the driver is
using a single TCB channel for both clocksource and clockevent while the
legacy driver always uses at least two channels.
Why is 'irq_requested' and request_irq/free_irq cleaner ?

Isn't there a configuration with the TCB register to disable the clockevent
only ?
I'll try something cleaner anyway.

-- 
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

Re: [PATCH 42/48] clocksource/drivers: Add a new driver for the Atmel ARM TC blocks

From: Daniel Lezcano <hidden>
Date: 2017-05-16 14:25:09

On 16/05/2017 13:59, Alexandre Belloni wrote:
Hi Daniel,

Almost one year later, I'm back on that topic.

On 24/06/2016 at 12:07:01 +0200, Daniel Lezcano wrote:
quoted
quoted
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 47352d25c15e..ff7f4022c749 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -258,6 +258,19 @@ config ATMEL_ST
  	select CLKSRC_OF
  	select MFD_SYSCON

+config ATMEL_ARM_TCB_CLKSRC
+	bool "TC Block Clocksource"
The Kconfig options are set now with the COMPILE_TEST option in order to
increase the compilation test coverage.

Please, add bool "TC Block Clocksource" if COMPILE_TEST, ...
quoted
+	select REGMAP_MMIO
+	depends on GENERIC_CLOCKEVENTS
+	depends on SOC_AT91RM9200 || SOC_AT91SAM9 || SOC_SAMA5
+	default SOC_AT91RM9200 || SOC_AT91SAM9 || SOC_SAMA5
... remove these dependencies and let the SoC's Kconfig to select the timer
like the other timers are.
The main issue with what you suggest is that it removes the possibility
to not compile the driver. This may be interesting for people using the
PIT as the clocksource/clockevent and the TCBs for something else.
Is it really a problem? We tend as much as possible to make silent
options in order to let the platform config to select the right clock.

quoted
quoted
+static cycle_t tc_get_cycles(struct clocksource *cs)
+{
+	unsigned long	flags;
+	u32		lower, upper, tmp;
+
+	raw_local_irq_save(flags);
+	do {
+		regmap_read(tc.regmap, ATMEL_TC_CV(1), &upper);
+		regmap_read(tc.regmap, ATMEL_TC_CV(0), &lower);
+		regmap_read(tc.regmap, ATMEL_TC_CV(1), &tmp);
+	} while (upper != tmp);
+
+	raw_local_irq_restore(flags);
Why is this lock needed ?
I've taken that from the old driver, I'm not sure this is needed. Maybe
to lower the chance to have upper != tmp.
quoted
quoted
+	return (upper << 16) | lower;
+}
+
I don't think this is needed.
quoted
quoted
+static int tcb_clkevt_oneshot(struct clock_event_device *dev)
+{
+	int ret;
+
+	if (tc.irq_requested)
+		return 0;
+
+	ret = request_irq(tc.irq, tc_clkevt_irq, IRQF_TIMER | IRQF_SHARED,
+			  "tcb_clkevt", &tc);
+	if (!ret)
+		tc.irq_requested = true;
The legacy driver checks clockevent_state_detached() and disables the clock.
This feature is different from the legacy driver. Here, the driver is
using a single TCB channel for both clocksource and clockevent while the
legacy driver always uses at least two channels.
quoted
Why is 'irq_requested' and request_irq/free_irq cleaner ?

Isn't there a configuration with the TCB register to disable the clockevent
only ?
I'll try something cleaner anyway.
Ok.


-- 
 <http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

Re: [PATCH 42/48] clocksource/drivers: Add a new driver for the Atmel ARM TC blocks

From: Alexandre Belloni <hidden>
Date: 2017-05-16 14:35:40

On 16/05/2017 at 16:25:04 +0200, Daniel Lezcano wrote:
On 16/05/2017 13:59, Alexandre Belloni wrote:
quoted
Hi Daniel,

Almost one year later, I'm back on that topic.

On 24/06/2016 at 12:07:01 +0200, Daniel Lezcano wrote:
quoted
quoted
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 47352d25c15e..ff7f4022c749 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -258,6 +258,19 @@ config ATMEL_ST
  	select CLKSRC_OF
  	select MFD_SYSCON

+config ATMEL_ARM_TCB_CLKSRC
+	bool "TC Block Clocksource"
The Kconfig options are set now with the COMPILE_TEST option in order to
increase the compilation test coverage.

Please, add bool "TC Block Clocksource" if COMPILE_TEST, ...
quoted
+	select REGMAP_MMIO
+	depends on GENERIC_CLOCKEVENTS
+	depends on SOC_AT91RM9200 || SOC_AT91SAM9 || SOC_SAMA5
+	default SOC_AT91RM9200 || SOC_AT91SAM9 || SOC_SAMA5
... remove these dependencies and let the SoC's Kconfig to select the timer
like the other timers are.
The main issue with what you suggest is that it removes the possibility
to not compile the driver. This may be interesting for people using the
PIT as the clocksource/clockevent and the TCBs for something else.
Is it really a problem? We tend as much as possible to make silent
options in order to let the platform config to select the right clock.
I depends on how much you care about being able to remove as much as
possible from the kernel.
Both the PIT and the TCB can be used by AT91SAM9 and SAMA5, similarly,
both the system timer and the TCB can be used by AT91RM9200. I would
prefer letting the user select which drivers have to be compiled in the
kernel instead of pulling both with the SoC configuration.



-- 
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help