Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1542327 > unrolled thread

[PATCH 0/6] Add board support for TS-4600

Started bySebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
First post2016-12-15 00:20 +0100
Last post2016-12-30 09:00 +0100
Articles 14 — 4 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH 0/6] Add board support for TS-4600 Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com> - 2016-12-15 00:20 +0100
    [PATCH 3/6] dt-bindings: bus: Add documentation for the Technologic Systems NBUS Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com> - 2016-12-15 00:20 +0100
      Re: [PATCH 3/6] dt-bindings: bus: Add documentation for the  Technologic Systems NBUS Rob Herring <robh@kernel.org> - 2016-12-19 23:20 +0100
    [PATCH 5/6] ARM: dts: TS-4600: add NBUS support Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com> - 2016-12-15 00:20 +0100
      Re: [PATCH 5/6] ARM: dts: TS-4600: add NBUS support Linus Walleij <linus.walleij@linaro.org> - 2016-12-30 09:10 +0100
    [PATCH 6/6] watchdog: ts4600: add driver for TS-4600 watchdog Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com> - 2016-12-15 00:20 +0100
      Re: [PATCH 6/6] watchdog: ts4600: add driver for TS-4600 watchdog Rob Herring <robh@kernel.org> - 2016-12-19 23:20 +0100
      Re: [PATCH 6/6] watchdog: ts4600: add driver for TS-4600 watchdog Guenter Roeck <linux@roeck-us.net> - 2016-12-23 03:00 +0100
    [PATCH 2/6] ARM: dts: TS-4600: add basic device tree Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com> - 2016-12-15 00:20 +0100
    [PATCH 2/6] ARM: dts: TS-4600: add basic device tree Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com> - 2016-12-15 00:20 +0100
    [PATCH 1/6] of: documentation: add bindings documentation for TS-4600 Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com> - 2016-12-15 00:20 +0100
      Re: [PATCH 1/6] of: documentation: add bindings documentation for  TS-4600 Rob Herring <robh@kernel.org> - 2016-12-19 23:10 +0100
    [PATCH 4/6] bus: add driver for the Technologic Systems NBUS Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com> - 2016-12-15 00:20 +0100
      Re: [PATCH 4/6] bus: add driver for the Technologic Systems NBUS Linus Walleij <linus.walleij@linaro.org> - 2016-12-30 09:00 +0100

#1542327 — [PATCH 0/6] Add board support for TS-4600

FromSebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
Date2016-12-15 00:20 +0100
Subject[PATCH 0/6] Add board support for TS-4600
Message-ID<sOr06-6CZ-13@gated-at.bofh.it>
This patch serie adds support for the TS-4600 boards rev A and B. These
boards, manufactured by Technologic Systems, are based on an i.MX28.

This serie include the support for the watchdog which could be enable
at Linux boot time depending on the bootloader.

The watchdog and few peripherals are implemented in a FPGA, and can
only be access using a custom GPIOs bit-banged bus which is called the
NBUS by Technologic Systems.
A driver for this bus is also included and used by the watchdog.

Sebastien Bourdelin (6):
  of: documentation: add bindings documentation for TS-4600
  ARM: dts: TS-4600: add basic device tree
  dt-bindings: bus: Add documentation for the Technologic Systems NBUS
  bus: add driver for the Technologic Systems NBUS
  ARM: dts: TS-4600: add NBUS support
  watchdog: ts4600: add driver for TS-4600 watchdog

 .../devicetree/bindings/arm/technologic.txt        |   5 +
 Documentation/devicetree/bindings/bus/ts-nbus.txt  |  50 +++
 .../devicetree/bindings/watchdog/ts4600-wdt.txt    |  16 +
 arch/arm/boot/dts/Makefile                         |   2 +
 arch/arm/boot/dts/imx28-ts4600-common.dtsi         | 126 ++++++
 arch/arm/boot/dts/imx28-ts4600-rev-a.dts           |  22 +
 arch/arm/boot/dts/imx28-ts4600-rev-b.dts           |  22 +
 drivers/bus/Kconfig                                |   9 +
 drivers/bus/Makefile                               |   1 +
 drivers/bus/ts-nbus.c                              | 451 +++++++++++++++++++++
 drivers/watchdog/Kconfig                           |  10 +
 drivers/watchdog/Makefile                          |   1 +
 drivers/watchdog/ts4600_wdt.c                      | 213 ++++++++++
 include/linux/ts-nbus.h                            |  17 +
 14 files changed, 945 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/bus/ts-nbus.txt
 create mode 100644 Documentation/devicetree/bindings/watchdog/ts4600-wdt.txt
 create mode 100644 arch/arm/boot/dts/imx28-ts4600-common.dtsi
 create mode 100644 arch/arm/boot/dts/imx28-ts4600-rev-a.dts
 create mode 100644 arch/arm/boot/dts/imx28-ts4600-rev-b.dts
 create mode 100644 drivers/bus/ts-nbus.c
 create mode 100644 drivers/watchdog/ts4600_wdt.c
 create mode 100644 include/linux/ts-nbus.h

-- 
2.10.2

[toc] | [next] | [standalone]


#1542328 — [PATCH 3/6] dt-bindings: bus: Add documentation for the Technologic Systems NBUS

FromSebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
Date2016-12-15 00:20 +0100
Subject[PATCH 3/6] dt-bindings: bus: Add documentation for the Technologic Systems NBUS
Message-ID<sOr06-6CZ-11@gated-at.bofh.it>
In reply to#1542327
Add binding documentation for the Technologic Systems NBUS that is used
to interface with peripherals in the FPGA of the TS-4600 SoM.

Signed-off-by: Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
---
 Documentation/devicetree/bindings/bus/ts-nbus.txt | 50 +++++++++++++++++++++++
 1 file changed, 50 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/bus/ts-nbus.txt

diff --git a/Documentation/devicetree/bindings/bus/ts-nbus.txt b/Documentation/devicetree/bindings/bus/ts-nbus.txt
new file mode 100644
index 0000000..2f777ee
--- /dev/null
+++ b/Documentation/devicetree/bindings/bus/ts-nbus.txt
@@ -0,0 +1,50 @@
+Technologic Systems NBUS
+
+The NBUS is a bus used to interface with peripherals in the Technologic
+Systems FPGA on the TS-4600 SoM.
+
+Required properties :
+ - compatible     : "technologic,ts-nbus", "simple-bus"
+ - #address-cells : must be 1
+ - #size-cells    : must be 0
+ - pws            : The PWM pin connected to the clock line on the FPGA
+ - data-gpios	  : The GPIO pin connected to the data line on the FPGA
+ - csn-gpios	  : The GPIO pin connected to the csn line on the FPGA
+ - txrx-gpios	  : The GPIO pin connected to the txrx line on the FPGA
+ - strobe-gpios	  : The GPIO pin connected to the stobe line on the FPGA
+ - ale-gpios	  : The GPIO pin connected to the ale line on the FPGA
+ - rdy-gpios	  : The GPIO pin connected to the rdy line on the FPGA
+
+Child nodes:
+
+The NBUS node can contain zero or more child nodes representing peripherals
+on the bus.
+
+Example:
+
+	nbus {
+		compatible = "technologic,ts-nbus", "simple-bus";
+		pinctrl-0 = <&nbus_pins>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		pwms = <&pwm 2 83>;
+		data-gpios   = <&gpio0 0 GPIO_ACTIVE_HIGH
+				&gpio0 1 GPIO_ACTIVE_HIGH
+				&gpio0 2 GPIO_ACTIVE_HIGH
+				&gpio0 3 GPIO_ACTIVE_HIGH
+				&gpio0 4 GPIO_ACTIVE_HIGH
+				&gpio0 5 GPIO_ACTIVE_HIGH
+				&gpio0 6 GPIO_ACTIVE_HIGH
+				&gpio0 7 GPIO_ACTIVE_HIGH>;
+		csn-gpios    = <&gpio0 16 GPIO_ACTIVE_HIGH>;
+		txrx-gpios   = <&gpio0 24 GPIO_ACTIVE_HIGH>;
+		strobe-gpios = <&gpio0 25 GPIO_ACTIVE_HIGH>;
+		ale-gpios    = <&gpio0 26 GPIO_ACTIVE_HIGH>;
+		rdy-gpios    = <&gpio0 21 GPIO_ACTIVE_HIGH>;
+
+		wdt@2a {
+			compatible = "...";
+
+			/* ... */
+		};
+	};
-- 
2.10.2

[toc] | [prev] | [next] | [standalone]


#1544791 — Re: [PATCH 3/6] dt-bindings: bus: Add documentation for the Technologic Systems NBUS

FromRob Herring <robh@kernel.org>
Date2016-12-19 23:20 +0100
SubjectRe: [PATCH 3/6] dt-bindings: bus: Add documentation for the Technologic Systems NBUS
Message-ID<sQerL-5iK-9@gated-at.bofh.it>
In reply to#1542328
On Wed, Dec 14, 2016 at 06:12:33PM -0500, Sebastien Bourdelin wrote:
> Add binding documentation for the Technologic Systems NBUS that is used
> to interface with peripherals in the FPGA of the TS-4600 SoM.
> 
> Signed-off-by: Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
> ---
>  Documentation/devicetree/bindings/bus/ts-nbus.txt | 50 +++++++++++++++++++++++
>  1 file changed, 50 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/bus/ts-nbus.txt
> 
> diff --git a/Documentation/devicetree/bindings/bus/ts-nbus.txt b/Documentation/devicetree/bindings/bus/ts-nbus.txt
> new file mode 100644
> index 0000000..2f777ee
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/bus/ts-nbus.txt
> @@ -0,0 +1,50 @@
> +Technologic Systems NBUS
> +
> +The NBUS is a bus used to interface with peripherals in the Technologic
> +Systems FPGA on the TS-4600 SoM.
> +
> +Required properties :
> + - compatible     : "technologic,ts-nbus", "simple-bus"
> + - #address-cells : must be 1
> + - #size-cells    : must be 0
> + - pws            : The PWM pin connected to the clock line on the FPGA

Using PWM binding?

> + - data-gpios	  : The GPIO pin connected to the data line on the FPGA
> + - csn-gpios	  : The GPIO pin connected to the csn line on the FPGA
> + - txrx-gpios	  : The GPIO pin connected to the txrx line on the FPGA
> + - strobe-gpios	  : The GPIO pin connected to the stobe line on the FPGA
> + - ale-gpios	  : The GPIO pin connected to the ale line on the FPGA
> + - rdy-gpios	  : The GPIO pin connected to the rdy line on the FPGA

These all need vendor prefix.

This is not any sort of standard bus?

> +
> +Child nodes:
> +
> +The NBUS node can contain zero or more child nodes representing peripherals
> +on the bus.
> +
> +Example:
> +
> +	nbus {
> +		compatible = "technologic,ts-nbus", "simple-bus";

I don't think simple-bus is really valid here. Don't you need the nbus 
driver before the devices are usable?

> +		pinctrl-0 = <&nbus_pins>;
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		pwms = <&pwm 2 83>;
> +		data-gpios   = <&gpio0 0 GPIO_ACTIVE_HIGH
> +				&gpio0 1 GPIO_ACTIVE_HIGH
> +				&gpio0 2 GPIO_ACTIVE_HIGH
> +				&gpio0 3 GPIO_ACTIVE_HIGH
> +				&gpio0 4 GPIO_ACTIVE_HIGH
> +				&gpio0 5 GPIO_ACTIVE_HIGH
> +				&gpio0 6 GPIO_ACTIVE_HIGH
> +				&gpio0 7 GPIO_ACTIVE_HIGH>;
> +		csn-gpios    = <&gpio0 16 GPIO_ACTIVE_HIGH>;
> +		txrx-gpios   = <&gpio0 24 GPIO_ACTIVE_HIGH>;
> +		strobe-gpios = <&gpio0 25 GPIO_ACTIVE_HIGH>;
> +		ale-gpios    = <&gpio0 26 GPIO_ACTIVE_HIGH>;
> +		rdy-gpios    = <&gpio0 21 GPIO_ACTIVE_HIGH>;
> +
> +		wdt@2a {

watchdog@...

> +			compatible = "...";
> +
> +			/* ... */
> +		};
> +	};
> -- 
> 2.10.2
> 
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

[toc] | [prev] | [next] | [standalone]


#1542330 — [PATCH 5/6] ARM: dts: TS-4600: add NBUS support

FromSebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
Date2016-12-15 00:20 +0100
Subject[PATCH 5/6] ARM: dts: TS-4600: add NBUS support
Message-ID<sOr06-6CZ-43@gated-at.bofh.it>
In reply to#1542327
This commit enables the NBUS on the TS-4600, using the ts-nbus driver.

Signed-off-by: Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
---
 arch/arm/boot/dts/imx28-ts4600-common.dtsi | 43 ++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/arch/arm/boot/dts/imx28-ts4600-common.dtsi b/arch/arm/boot/dts/imx28-ts4600-common.dtsi
index 04bd5a5..b668933 100644
--- a/arch/arm/boot/dts/imx28-ts4600-common.dtsi
+++ b/arch/arm/boot/dts/imx28-ts4600-common.dtsi
@@ -44,6 +44,28 @@
 					fsl,pull-up = <MXS_PULL_DISABLE>;
 				};
 
+				nbus_pins: nbus_pins {
+					fsl,pinmux-ids = <
+						MX28_PAD_GPMI_D00__GPIO_0_0
+						MX28_PAD_GPMI_D01__GPIO_0_1
+						MX28_PAD_GPMI_D02__GPIO_0_2
+						MX28_PAD_GPMI_D03__GPIO_0_3
+						MX28_PAD_GPMI_D04__GPIO_0_4
+						MX28_PAD_GPMI_D05__GPIO_0_5
+						MX28_PAD_GPMI_D06__GPIO_0_6
+						MX28_PAD_GPMI_D07__GPIO_0_7
+						MX28_PAD_GPMI_CE0N__GPIO_0_16
+						MX28_PAD_GPMI_RDY1__GPIO_0_21
+						MX28_PAD_GPMI_RDN__GPIO_0_24
+						MX28_PAD_GPMI_WRN__GPIO_0_25
+						MX28_PAD_GPMI_ALE__GPIO_0_26
+					>;
+					fsl,drive-strength = <MXS_DRIVE_4mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+
+				};
+
 			};
 		};
 
@@ -75,4 +97,25 @@
 		};
 	};
 
+	nbus {
+		compatible = "technologic,ts-nbus", "simple-bus";
+		pinctrl-0 = <&nbus_pins>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		pwms = <&pwm 2 83>;
+		data-gpios   = <&gpio0 0 GPIO_ACTIVE_HIGH
+				&gpio0 1 GPIO_ACTIVE_HIGH
+				&gpio0 2 GPIO_ACTIVE_HIGH
+				&gpio0 3 GPIO_ACTIVE_HIGH
+				&gpio0 4 GPIO_ACTIVE_HIGH
+				&gpio0 5 GPIO_ACTIVE_HIGH
+				&gpio0 6 GPIO_ACTIVE_HIGH
+				&gpio0 7 GPIO_ACTIVE_HIGH>;
+		csn-gpios    = <&gpio0 16 GPIO_ACTIVE_HIGH>;
+		txrx-gpios   = <&gpio0 24 GPIO_ACTIVE_HIGH>;
+		strobe-gpios = <&gpio0 25 GPIO_ACTIVE_HIGH>;
+		ale-gpios    = <&gpio0 26 GPIO_ACTIVE_HIGH>;
+		rdy-gpios    = <&gpio0 21 GPIO_ACTIVE_HIGH>;
+	};
+
 };
-- 
2.10.2

[toc] | [prev] | [next] | [standalone]


#1548485 — Re: [PATCH 5/6] ARM: dts: TS-4600: add NBUS support

FromLinus Walleij <linus.walleij@linaro.org>
Date2016-12-30 09:10 +0100
SubjectRe: [PATCH 5/6] ARM: dts: TS-4600: add NBUS support
Message-ID<sU0qd-1M6-7@gated-at.bofh.it>
In reply to#1542330
On Thu, Dec 15, 2016 at 12:12 AM, Sebastien Bourdelin
<sebastien.bourdelin@savoirfairelinux.com> wrote:

> This commit enables the NBUS on the TS-4600, using the ts-nbus driver.
>
> Signed-off-by: Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>

> +       nbus {
> +               compatible = "technologic,ts-nbus", "simple-bus";
> +               pinctrl-0 = <&nbus_pins>;
> +               #address-cells = <1>;
> +               #size-cells = <0>;
> +               pwms = <&pwm 2 83>;
> +               data-gpios   = <&gpio0 0 GPIO_ACTIVE_HIGH
> +                               &gpio0 1 GPIO_ACTIVE_HIGH
> +                               &gpio0 2 GPIO_ACTIVE_HIGH
> +                               &gpio0 3 GPIO_ACTIVE_HIGH
> +                               &gpio0 4 GPIO_ACTIVE_HIGH
> +                               &gpio0 5 GPIO_ACTIVE_HIGH
> +                               &gpio0 6 GPIO_ACTIVE_HIGH
> +                               &gpio0 7 GPIO_ACTIVE_HIGH>;
> +               csn-gpios    = <&gpio0 16 GPIO_ACTIVE_HIGH>;
> +               txrx-gpios   = <&gpio0 24 GPIO_ACTIVE_HIGH>;
> +               strobe-gpios = <&gpio0 25 GPIO_ACTIVE_HIGH>;
> +               ale-gpios    = <&gpio0 26 GPIO_ACTIVE_HIGH>;
> +               rdy-gpios    = <&gpio0 21 GPIO_ACTIVE_HIGH>;

devm_gpiod_get(&pdev->dev, "csn", GPIOD_OUT_HIGH); etc will get these
from the spawned
platform device.

Yours,
Linus Walleij

[toc] | [prev] | [next] | [standalone]


#1542331 — [PATCH 6/6] watchdog: ts4600: add driver for TS-4600 watchdog

FromSebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
Date2016-12-15 00:20 +0100
Subject[PATCH 6/6] watchdog: ts4600: add driver for TS-4600 watchdog
Message-ID<sOr06-6CZ-27@gated-at.bofh.it>
In reply to#1542327
This watchdog is instantiated in a FPGA and can only be access using a
GPIOs bit-banged bus, called the NBUS by Technologic Systems.
The watchdog is made of only one register, called the feed register.
Writing to this register will re-arm the watchdog for a given time (and
enable it if it was disable). It can be disabled by writing a special
value into it.

Signed-off-by: Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
---
 .../devicetree/bindings/watchdog/ts4600-wdt.txt    |  16 ++
 arch/arm/boot/dts/imx28-ts4600-common.dtsi         |   5 +
 drivers/watchdog/Kconfig                           |  10 +
 drivers/watchdog/Makefile                          |   1 +
 drivers/watchdog/ts4600_wdt.c                      | 213 +++++++++++++++++++++
 5 files changed, 245 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/watchdog/ts4600-wdt.txt
 create mode 100644 drivers/watchdog/ts4600_wdt.c

diff --git a/Documentation/devicetree/bindings/watchdog/ts4600-wdt.txt b/Documentation/devicetree/bindings/watchdog/ts4600-wdt.txt
new file mode 100644
index 0000000..61d620e
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/ts4600-wdt.txt
@@ -0,0 +1,16 @@
+TS-4600 Technologic Systems Watchdog
+
+Required properties:
+- compatible: must be "technologic,ts4600-wdt"
+- reg: offset to the FPGA's watchdog register
+
+Optional property:
+- timeout-sec: contains the watchdog timeout in seconds.
+
+Example:
+
+wdt {
+	compatible = "technologic,ts4600-wdt";
+	reg = <0x2a>;
+	timeout-sec = <10>;
+};
diff --git a/arch/arm/boot/dts/imx28-ts4600-common.dtsi b/arch/arm/boot/dts/imx28-ts4600-common.dtsi
index b668933..dd7318c 100644
--- a/arch/arm/boot/dts/imx28-ts4600-common.dtsi
+++ b/arch/arm/boot/dts/imx28-ts4600-common.dtsi
@@ -116,6 +116,11 @@
 		strobe-gpios = <&gpio0 25 GPIO_ACTIVE_HIGH>;
 		ale-gpios    = <&gpio0 26 GPIO_ACTIVE_HIGH>;
 		rdy-gpios    = <&gpio0 21 GPIO_ACTIVE_HIGH>;
+
+		wdt@2a {
+			compatible = "technologic,ts4600-wdt";
+			reg = <0x2a>;
+		};
 	};
 
 };
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 3eb58cb..7a8e176 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -500,6 +500,16 @@ config NUC900_WATCHDOG
 	  To compile this driver as a module, choose M here: the
 	  module will be called nuc900_wdt.
 
+config TS4600_WATCHDOG
+	tristate "TS-4600 Watchdog"
+	depends on HAS_IOMEM && OF
+	depends on SOC_IMX28 || COMPILE_TEST
+	select WATCHDOG_CORE
+	help
+	  Technologic Systems TS-4600 has watchdog timer implemented in
+	  an external FPGA. Say Y here if you want to support for the
+	  watchdog timer on TS-4600 board.
+
 config TS4800_WATCHDOG
 	tristate "TS-4800 Watchdog"
 	depends on HAS_IOMEM && OF
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index caa9f4a..d4b4bd2 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -61,6 +61,7 @@ obj-$(CONFIG_RN5T618_WATCHDOG) += rn5t618_wdt.o
 obj-$(CONFIG_COH901327_WATCHDOG) += coh901327_wdt.o
 obj-$(CONFIG_STMP3XXX_RTC_WATCHDOG) += stmp3xxx_rtc_wdt.o
 obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o
+obj-$(CONFIG_TS4600_WATCHDOG) += ts4600_wdt.o
 obj-$(CONFIG_TS4800_WATCHDOG) += ts4800_wdt.o
 obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o
 obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o
diff --git a/drivers/watchdog/ts4600_wdt.c b/drivers/watchdog/ts4600_wdt.c
new file mode 100644
index 0000000..db91b40
--- /dev/null
+++ b/drivers/watchdog/ts4600_wdt.c
@@ -0,0 +1,213 @@
+/*
+ * Watchdog driver for TS-4600 based boards
+ *
+ * Copyright (c) 2016 - Savoir-faire Linux
+ * Author: Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ *
+ * The watchdog on the TS-4600 based boards is in an FPGA and can only be
+ * accessed using a GPIO bit-banged bus called the NBUS by Technologic Systems.
+ * The logic for the watchdog is the same then for the TS-4800 SoM, only the way
+ * to access it change, therefore this driver is heavely based on the ts4800_wdt
+ * driver from Damien Riegel <damien.riegel@savoirfairelinux.com>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/ts-nbus.h>
+#include <linux/watchdog.h>
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout,
+	"Watchdog cannot be stopped once started (default="
+	__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+/* possible feed values */
+#define TS4600_WDT_FEED_2S       0x1
+#define TS4600_WDT_FEED_10S      0x2
+#define TS4600_WDT_DISABLE       0x3
+
+struct ts4600_wdt {
+	struct watchdog_device  wdd;
+	u32                     feed_offset;
+	u32                     feed_val;
+};
+
+/*
+ * TS-4600 supports the following timeout values:
+ *
+ *   value desc
+ *   ---------------------
+ *     0    feed for 338ms
+ *     1    feed for 2.706s
+ *     2    feed for 10.824s
+ *     3    disable watchdog
+ *
+ * Keep the regmap/timeout map ordered by timeout
+ */
+static const struct {
+	const int timeout;
+	const int regval;
+} ts4600_wdt_map[] = {
+	{ 2,  TS4600_WDT_FEED_2S },
+	{ 10, TS4600_WDT_FEED_10S },
+};
+
+#define MAX_TIMEOUT_INDEX       (ARRAY_SIZE(ts4600_wdt_map) - 1)
+
+static void ts4600_write_feed(struct ts4600_wdt *wdt, u32 val)
+{
+	ts_nbus_write(wdt->feed_offset, val);
+}
+
+static int ts4600_wdt_start(struct watchdog_device *wdd)
+{
+	struct ts4600_wdt *wdt = watchdog_get_drvdata(wdd);
+
+	ts4600_write_feed(wdt, wdt->feed_val);
+
+	return 0;
+}
+
+static int ts4600_wdt_stop(struct watchdog_device *wdd)
+{
+	struct ts4600_wdt *wdt = watchdog_get_drvdata(wdd);
+
+	ts4600_write_feed(wdt, TS4600_WDT_DISABLE);
+	return 0;
+}
+
+static int ts4600_wdt_set_timeout(struct watchdog_device *wdd,
+				  unsigned int timeout)
+{
+	struct ts4600_wdt *wdt = watchdog_get_drvdata(wdd);
+	int i;
+
+	for (i = 0; i < MAX_TIMEOUT_INDEX; i++) {
+		if (ts4600_wdt_map[i].timeout >= timeout)
+			break;
+	}
+
+	wdd->timeout = ts4600_wdt_map[i].timeout;
+	wdt->feed_val = ts4600_wdt_map[i].regval;
+
+	return 0;
+}
+
+static const struct watchdog_ops ts4600_wdt_ops = {
+	.owner = THIS_MODULE,
+	.start = ts4600_wdt_start,
+	.stop = ts4600_wdt_stop,
+	.set_timeout = ts4600_wdt_set_timeout,
+};
+
+static const struct watchdog_info ts4600_wdt_info = {
+	.options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
+	.identity = "TS-4600 Watchdog",
+};
+
+static int ts4600_wdt_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct watchdog_device *wdd;
+	struct ts4600_wdt *wdt;
+	u32 reg;
+	int ret;
+
+	ret = of_property_read_u32(np, "reg", &reg);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "missing reg property\n");
+		return ret;
+	}
+
+	/* check for the NBUS state and defer the probing if it is not ready */
+	if (!ts_nbus_is_ready())
+		return -EPROBE_DEFER;
+
+	/* allocate memory for watchdog struct */
+	wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+	if (!wdt)
+		return -ENOMEM;
+
+	/* set offset to know where to write */
+	wdt->feed_offset = reg;
+
+	/* Initialize struct watchdog_device */
+	wdd = &wdt->wdd;
+	wdd->parent = &pdev->dev;
+	wdd->info = &ts4600_wdt_info;
+	wdd->ops = &ts4600_wdt_ops;
+	wdd->min_timeout = ts4600_wdt_map[0].timeout;
+	wdd->max_timeout = ts4600_wdt_map[MAX_TIMEOUT_INDEX].timeout;
+
+	watchdog_set_drvdata(wdd, wdt);
+	watchdog_set_nowayout(wdd, nowayout);
+	watchdog_init_timeout(wdd, 0, &pdev->dev);
+
+	/*
+	 * As this watchdog supports only a few values, ts4600_wdt_set_timeout
+	 * must be called to initialize timeout and feed_val with valid values.
+	 * Default to maximum timeout if none, or an invalid one, is provided in
+	 * device tree.
+	 */
+	if (!wdd->timeout)
+		wdd->timeout = wdd->max_timeout;
+	ts4600_wdt_set_timeout(wdd, wdd->timeout);
+
+	/*
+	 * The feed register is write-only, so it is not possible to determine
+	 * watchdog's state. Disable it to be in a known state.
+	 */
+	ts4600_wdt_stop(wdd);
+
+	ret = watchdog_register_device(wdd);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"failed to register watchdog device\n");
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, wdt);
+
+	dev_info(&pdev->dev,
+		 "initialized (timeout = %d sec, nowayout = %d)\n",
+		 wdd->timeout, nowayout);
+
+	return 0;
+}
+
+static int ts4600_wdt_remove(struct platform_device *pdev)
+{
+	struct ts4600_wdt *wdt = platform_get_drvdata(pdev);
+
+	watchdog_unregister_device(&wdt->wdd);
+
+	return 0;
+}
+
+static const struct of_device_id ts4600_wdt_of_match[] = {
+	{ .compatible = "technologic,ts4600-wdt", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, ts4600_wdt_of_match);
+
+static struct platform_driver ts4600_wdt_driver = {
+	.probe		= ts4600_wdt_probe,
+	.remove		= ts4600_wdt_remove,
+	.driver		= {
+		.name	= "ts4600_wdt",
+		.of_match_table = ts4600_wdt_of_match,
+	},
+};
+
+module_platform_driver(ts4600_wdt_driver);
+
+MODULE_AUTHOR("Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:ts4600_wdt");
-- 
2.10.2

[toc] | [prev] | [next] | [standalone]


#1544790 — Re: [PATCH 6/6] watchdog: ts4600: add driver for TS-4600 watchdog

FromRob Herring <robh@kernel.org>
Date2016-12-19 23:20 +0100
SubjectRe: [PATCH 6/6] watchdog: ts4600: add driver for TS-4600 watchdog
Message-ID<sQerL-5iK-3@gated-at.bofh.it>
In reply to#1542331
On Wed, Dec 14, 2016 at 06:12:36PM -0500, Sebastien Bourdelin wrote:
> This watchdog is instantiated in a FPGA and can only be access using a
> GPIOs bit-banged bus, called the NBUS by Technologic Systems.
> The watchdog is made of only one register, called the feed register.
> Writing to this register will re-arm the watchdog for a given time (and
> enable it if it was disable). It can be disabled by writing a special
> value into it.
> 
> Signed-off-by: Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
> ---
>  .../devicetree/bindings/watchdog/ts4600-wdt.txt    |  16 ++
>  arch/arm/boot/dts/imx28-ts4600-common.dtsi         |   5 +

Acked-by: Rob Herring <robh@kernel.org>

>  drivers/watchdog/Kconfig                           |  10 +
>  drivers/watchdog/Makefile                          |   1 +
>  drivers/watchdog/ts4600_wdt.c                      | 213 +++++++++++++++++++++
>  5 files changed, 245 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/watchdog/ts4600-wdt.txt
>  create mode 100644 drivers/watchdog/ts4600_wdt.c

[toc] | [prev] | [next] | [standalone]


#1546711 — Re: [PATCH 6/6] watchdog: ts4600: add driver for TS-4600 watchdog

FromGuenter Roeck <linux@roeck-us.net>
Date2016-12-23 03:00 +0100
SubjectRe: [PATCH 6/6] watchdog: ts4600: add driver for TS-4600 watchdog
Message-ID<sRnjj-mq-1@gated-at.bofh.it>
In reply to#1542331
On 12/14/2016 03:12 PM, Sebastien Bourdelin wrote:
> This watchdog is instantiated in a FPGA and can only be access using a
> GPIOs bit-banged bus, called the NBUS by Technologic Systems.
> The watchdog is made of only one register, called the feed register.
> Writing to this register will re-arm the watchdog for a given time (and
> enable it if it was disable). It can be disabled by writing a special
> value into it.
>
> Signed-off-by: Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
> ---
>  .../devicetree/bindings/watchdog/ts4600-wdt.txt    |  16 ++
>  arch/arm/boot/dts/imx28-ts4600-common.dtsi         |   5 +
>  drivers/watchdog/Kconfig                           |  10 +
>  drivers/watchdog/Makefile                          |   1 +
>  drivers/watchdog/ts4600_wdt.c                      | 213 +++++++++++++++++++++
>  5 files changed, 245 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/watchdog/ts4600-wdt.txt
>  create mode 100644 drivers/watchdog/ts4600_wdt.c
>
> diff --git a/Documentation/devicetree/bindings/watchdog/ts4600-wdt.txt b/Documentation/devicetree/bindings/watchdog/ts4600-wdt.txt
> new file mode 100644
> index 0000000..61d620e
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/watchdog/ts4600-wdt.txt
> @@ -0,0 +1,16 @@
> +TS-4600 Technologic Systems Watchdog
> +
> +Required properties:
> +- compatible: must be "technologic,ts4600-wdt"
> +- reg: offset to the FPGA's watchdog register
> +
> +Optional property:
> +- timeout-sec: contains the watchdog timeout in seconds.
> +
> +Example:
> +
> +wdt {
> +	compatible = "technologic,ts4600-wdt";
> +	reg = <0x2a>;
> +	timeout-sec = <10>;
> +};
> diff --git a/arch/arm/boot/dts/imx28-ts4600-common.dtsi b/arch/arm/boot/dts/imx28-ts4600-common.dtsi
> index b668933..dd7318c 100644
> --- a/arch/arm/boot/dts/imx28-ts4600-common.dtsi
> +++ b/arch/arm/boot/dts/imx28-ts4600-common.dtsi
> @@ -116,6 +116,11 @@
>  		strobe-gpios = <&gpio0 25 GPIO_ACTIVE_HIGH>;
>  		ale-gpios    = <&gpio0 26 GPIO_ACTIVE_HIGH>;
>  		rdy-gpios    = <&gpio0 21 GPIO_ACTIVE_HIGH>;
> +
> +		wdt@2a {
> +			compatible = "technologic,ts4600-wdt";
> +			reg = <0x2a>;
> +		};
>  	};
>
>  };
> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
> index 3eb58cb..7a8e176 100644
> --- a/drivers/watchdog/Kconfig
> +++ b/drivers/watchdog/Kconfig
> @@ -500,6 +500,16 @@ config NUC900_WATCHDOG
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called nuc900_wdt.
>
> +config TS4600_WATCHDOG
> +	tristate "TS-4600 Watchdog"
> +	depends on HAS_IOMEM && OF
> +	depends on SOC_IMX28 || COMPILE_TEST

Asd 0day reports, this does not work.

> +	select WATCHDOG_CORE
> +	help
> +	  Technologic Systems TS-4600 has watchdog timer implemented in
> +	  an external FPGA. Say Y here if you want to support for the
> +	  watchdog timer on TS-4600 board.
> +
>  config TS4800_WATCHDOG
>  	tristate "TS-4800 Watchdog"
>  	depends on HAS_IOMEM && OF
> diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
> index caa9f4a..d4b4bd2 100644
> --- a/drivers/watchdog/Makefile
> +++ b/drivers/watchdog/Makefile
> @@ -61,6 +61,7 @@ obj-$(CONFIG_RN5T618_WATCHDOG) += rn5t618_wdt.o
>  obj-$(CONFIG_COH901327_WATCHDOG) += coh901327_wdt.o
>  obj-$(CONFIG_STMP3XXX_RTC_WATCHDOG) += stmp3xxx_rtc_wdt.o
>  obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o
> +obj-$(CONFIG_TS4600_WATCHDOG) += ts4600_wdt.o
>  obj-$(CONFIG_TS4800_WATCHDOG) += ts4800_wdt.o
>  obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o
>  obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o
> diff --git a/drivers/watchdog/ts4600_wdt.c b/drivers/watchdog/ts4600_wdt.c
> new file mode 100644
> index 0000000..db91b40
> --- /dev/null
> +++ b/drivers/watchdog/ts4600_wdt.c
> @@ -0,0 +1,213 @@
> +/*
> + * Watchdog driver for TS-4600 based boards
> + *
> + * Copyright (c) 2016 - Savoir-faire Linux
> + * Author: Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + *
> + * The watchdog on the TS-4600 based boards is in an FPGA and can only be
> + * accessed using a GPIO bit-banged bus called the NBUS by Technologic Systems.
> + * The logic for the watchdog is the same then for the TS-4800 SoM, only the way
> + * to access it change, therefore this driver is heavely based on the ts4800_wdt
> + * driver from Damien Riegel <damien.riegel@savoirfairelinux.com>.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/ts-nbus.h>
> +#include <linux/watchdog.h>
> +
> +static bool nowayout = WATCHDOG_NOWAYOUT;
> +module_param(nowayout, bool, 0);
> +MODULE_PARM_DESC(nowayout,
> +	"Watchdog cannot be stopped once started (default="
> +	__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
> +
> +/* possible feed values */
> +#define TS4600_WDT_FEED_2S       0x1
> +#define TS4600_WDT_FEED_10S      0x2
> +#define TS4600_WDT_DISABLE       0x3
> +
> +struct ts4600_wdt {
> +	struct watchdog_device  wdd;
> +	u32                     feed_offset;
> +	u32                     feed_val;
> +};
> +
> +/*
> + * TS-4600 supports the following timeout values:
> + *
> + *   value desc
> + *   ---------------------
> + *     0    feed for 338ms
> + *     1    feed for 2.706s
> + *     2    feed for 10.824s
> + *     3    disable watchdog
> + *
> + * Keep the regmap/timeout map ordered by timeout
> + */
> +static const struct {
> +	const int timeout;
> +	const int regval;
> +} ts4600_wdt_map[] = {
> +	{ 2,  TS4600_WDT_FEED_2S },
> +	{ 10, TS4600_WDT_FEED_10S },
> +};
> +
> +#define MAX_TIMEOUT_INDEX       (ARRAY_SIZE(ts4600_wdt_map) - 1)
> +
> +static void ts4600_write_feed(struct ts4600_wdt *wdt, u32 val)
> +{
> +	ts_nbus_write(wdt->feed_offset, val);
> +}
> +
> +static int ts4600_wdt_start(struct watchdog_device *wdd)
> +{
> +	struct ts4600_wdt *wdt = watchdog_get_drvdata(wdd);
> +
> +	ts4600_write_feed(wdt, wdt->feed_val);
> +
> +	return 0;
> +}
> +
> +static int ts4600_wdt_stop(struct watchdog_device *wdd)
> +{
> +	struct ts4600_wdt *wdt = watchdog_get_drvdata(wdd);
> +
> +	ts4600_write_feed(wdt, TS4600_WDT_DISABLE);
> +	return 0;
> +}
> +
> +static int ts4600_wdt_set_timeout(struct watchdog_device *wdd,
> +				  unsigned int timeout)
> +{
> +	struct ts4600_wdt *wdt = watchdog_get_drvdata(wdd);
> +	int i;
> +
> +	for (i = 0; i < MAX_TIMEOUT_INDEX; i++) {
> +		if (ts4600_wdt_map[i].timeout >= timeout)
> +			break;
> +	}

An if/else would be much simpler here.

> +
> +	wdd->timeout = ts4600_wdt_map[i].timeout;
> +	wdt->feed_val = ts4600_wdt_map[i].regval;
> +
> +	return 0;
> +}
> +
> +static const struct watchdog_ops ts4600_wdt_ops = {
> +	.owner = THIS_MODULE,
> +	.start = ts4600_wdt_start,
> +	.stop = ts4600_wdt_stop,
> +	.set_timeout = ts4600_wdt_set_timeout,
> +};
> +
> +static const struct watchdog_info ts4600_wdt_info = {
> +	.options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
> +	.identity = "TS-4600 Watchdog",
> +};
> +
> +static int ts4600_wdt_probe(struct platform_device *pdev)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	struct watchdog_device *wdd;
> +	struct ts4600_wdt *wdt;
> +	u32 reg;
> +	int ret;
> +
> +	ret = of_property_read_u32(np, "reg", &reg);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "missing reg property\n");
> +		return ret;
> +	}
> +
> +	/* check for the NBUS state and defer the probing if it is not ready */
> +	if (!ts_nbus_is_ready())
> +		return -EPROBE_DEFER;
> +
> +	/* allocate memory for watchdog struct */
> +	wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
> +	if (!wdt)
> +		return -ENOMEM;
> +
> +	/* set offset to know where to write */
> +	wdt->feed_offset = reg;
> +
> +	/* Initialize struct watchdog_device */
> +	wdd = &wdt->wdd;
> +	wdd->parent = &pdev->dev;
> +	wdd->info = &ts4600_wdt_info;
> +	wdd->ops = &ts4600_wdt_ops;
> +	wdd->min_timeout = ts4600_wdt_map[0].timeout;
> +	wdd->max_timeout = ts4600_wdt_map[MAX_TIMEOUT_INDEX].timeout;
> +

Your call, but it might be better and more flexible to just use a single
hardware timeout (such as the 2.x second one), provide it here as
max_hw_heartbeat_ms, and let the kernel handle the actual (and larger)
timeouts.

> +	watchdog_set_drvdata(wdd, wdt);
> +	watchdog_set_nowayout(wdd, nowayout);
> +	watchdog_init_timeout(wdd, 0, &pdev->dev);
> +
> +	/*
> +	 * As this watchdog supports only a few values, ts4600_wdt_set_timeout
> +	 * must be called to initialize timeout and feed_val with valid values.
> +	 * Default to maximum timeout if none, or an invalid one, is provided in
> +	 * device tree.
> +	 */
> +	if (!wdd->timeout)
> +		wdd->timeout = wdd->max_timeout;
> +	ts4600_wdt_set_timeout(wdd, wdd->timeout);
> +
> +	/*
> +	 * The feed register is write-only, so it is not possible to determine
> +	 * watchdog's state. Disable it to be in a known state.
> +	 */
> +	ts4600_wdt_stop(wdd);
> +
> +	ret = watchdog_register_device(wdd);
> +	if (ret) {
> +		dev_err(&pdev->dev,
> +			"failed to register watchdog device\n");
> +		return ret;
> +	}
> +
> +	platform_set_drvdata(pdev, wdt);
> +
> +	dev_info(&pdev->dev,
> +		 "initialized (timeout = %d sec, nowayout = %d)\n",
> +		 wdd->timeout, nowayout);
> +
> +	return 0;
> +}
> +
> +static int ts4600_wdt_remove(struct platform_device *pdev)
> +{
> +	struct ts4600_wdt *wdt = platform_get_drvdata(pdev);
> +
> +	watchdog_unregister_device(&wdt->wdd);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id ts4600_wdt_of_match[] = {
> +	{ .compatible = "technologic,ts4600-wdt", },
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(of, ts4600_wdt_of_match);
> +
> +static struct platform_driver ts4600_wdt_driver = {
> +	.probe		= ts4600_wdt_probe,
> +	.remove		= ts4600_wdt_remove,
> +	.driver		= {
> +		.name	= "ts4600_wdt",
> +		.of_match_table = ts4600_wdt_of_match,
> +	},
> +};
> +
> +module_platform_driver(ts4600_wdt_driver);
> +
> +MODULE_AUTHOR("Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>");
> +MODULE_LICENSE("GPL v2");
> +MODULE_ALIAS("platform:ts4600_wdt");
>

[toc] | [prev] | [next] | [standalone]


#1542332 — [PATCH 2/6] ARM: dts: TS-4600: add basic device tree

FromSebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
Date2016-12-15 00:20 +0100
Subject[PATCH 2/6] ARM: dts: TS-4600: add basic device tree
Message-ID<sOr06-6CZ-29@gated-at.bofh.it>
In reply to#1542327
These device trees add support for the TS-4600 by Technologic Systems.

More details here:
  http://wiki.embeddedarm.com/wiki/TS-4600

Signed-off-by: Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
---
 arch/arm/boot/dts/Makefile                 |  2 +
 arch/arm/boot/dts/imx28-ts4600-common.dtsi | 78 ++++++++++++++++++++++++++++++
 arch/arm/boot/dts/imx28-ts4600-rev-a.dts   | 22 +++++++++
 arch/arm/boot/dts/imx28-ts4600-rev-b.dts   | 22 +++++++++
 4 files changed, 124 insertions(+)
 create mode 100644 arch/arm/boot/dts/imx28-ts4600-common.dtsi
 create mode 100644 arch/arm/boot/dts/imx28-ts4600-rev-a.dts
 create mode 100644 arch/arm/boot/dts/imx28-ts4600-rev-b.dts

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index c558ba7..5a79fab 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -466,6 +466,8 @@ dtb-$(CONFIG_ARCH_MXS) += \
 	imx28-m28cu3.dtb \
 	imx28-m28evk.dtb \
 	imx28-sps1.dtb \
+	imx28-ts4600-rev-a.dtb \
+	imx28-ts4600-rev-b.dtb \
 	imx28-tx28.dtb
 dtb-$(CONFIG_ARCH_NOMADIK) += \
 	ste-nomadik-s8815.dtb \
diff --git a/arch/arm/boot/dts/imx28-ts4600-common.dtsi b/arch/arm/boot/dts/imx28-ts4600-common.dtsi
new file mode 100644
index 0000000..04bd5a5
--- /dev/null
+++ b/arch/arm/boot/dts/imx28-ts4600-common.dtsi
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2016 Savoir-Faire Linux
+ * Author: Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+#include "imx28.dtsi"
+#include "dt-bindings/gpio/gpio.h"
+
+/ {
+
+	compatible = "technologic,imx28-ts4600", "fsl,imx28";
+
+	apb@80000000 {
+		apbh@80000000 {
+			ssp0: ssp@80010000 {
+				compatible = "fsl,imx28-mmc";
+				pinctrl-names = "default";
+				pinctrl-0 = <&mmc0_4bit_pins_a
+					     &mmc0_sck_cfg
+					     &en_sd_pwr>;
+				broken-cd = <1>;
+				bus-width = <4>;
+				vmmc-supply = <&reg_vddio_sd0>;
+				status = "okay";
+			};
+
+			pinctrl@80018000 {
+				pinctrl-names = "default";
+
+				en_sd_pwr: en_sd_pwr {
+					fsl,pinmux-ids = <
+						MX28_PAD_PWM3__GPIO_3_28
+					>;
+					fsl,drive-strength = <MXS_DRIVE_4mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+			};
+		};
+
+		apbx@80040000 {
+			pwm: pwm@80064000 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&pwm2_pins_a>;
+				status = "okay";
+			};
+
+			duart: serial@80074000 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&duart_pins_a>;
+				status = "okay";
+			};
+		};
+	};
+
+	regulators {
+		compatible = "simple-bus";
+
+		reg_vddio_sd0: vddio-sd0 {
+			compatible = "regulator-fixed";
+			regulator-name = "vddio-sd0";
+			regulator-min-microvolt = <3300000>;
+			regulator-max-microvolt = <3300000>;
+			regulator-boot-on;
+			gpio = <&gpio3 28 0>;
+		};
+	};
+
+};
diff --git a/arch/arm/boot/dts/imx28-ts4600-rev-a.dts b/arch/arm/boot/dts/imx28-ts4600-rev-a.dts
new file mode 100644
index 0000000..e8cb729
--- /dev/null
+++ b/arch/arm/boot/dts/imx28-ts4600-rev-a.dts
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2016 Savoir-Faire Linux
+ * Author: Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include "imx28-ts4600-common.dtsi"
+
+/ {
+	model = "Technologic Systems i.MX28 TS-4600 Rev A";
+
+	memory {
+		reg = <0x40000000 0x08000000>;   /* 128MB */
+	};
+
+};
diff --git a/arch/arm/boot/dts/imx28-ts4600-rev-b.dts b/arch/arm/boot/dts/imx28-ts4600-rev-b.dts
new file mode 100644
index 0000000..a115f83
--- /dev/null
+++ b/arch/arm/boot/dts/imx28-ts4600-rev-b.dts
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2016 Savoir-Faire Linux
+ * Author: Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include "imx28-ts4600-common.dtsi"
+
+/ {
+	model = "Technologic Systems i.MX28 TS-4600 Rev B";
+
+	memory {
+		reg = <0x40000000 0x10000000>;   /* 256MB */
+	};
+
+};
-- 
2.10.2

[toc] | [prev] | [next] | [standalone]


#1542335 — [PATCH 2/6] ARM: dts: TS-4600: add basic device tree

FromSebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
Date2016-12-15 00:20 +0100
Subject[PATCH 2/6] ARM: dts: TS-4600: add basic device tree
Message-ID<sOr06-6CZ-33@gated-at.bofh.it>
In reply to#1542327
These device trees add support for the TS-4600 by Technologic Systems.

More details here:
  http://wiki.embeddedarm.com/wiki/TS-4600

Signed-off-by: Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
---
 arch/arm/boot/dts/Makefile                 |  2 +
 arch/arm/boot/dts/imx28-ts4600-common.dtsi | 78 ++++++++++++++++++++++++++++++
 arch/arm/boot/dts/imx28-ts4600-rev-a.dts   | 22 +++++++++
 arch/arm/boot/dts/imx28-ts4600-rev-b.dts   | 22 +++++++++
 4 files changed, 124 insertions(+)
 create mode 100644 arch/arm/boot/dts/imx28-ts4600-common.dtsi
 create mode 100644 arch/arm/boot/dts/imx28-ts4600-rev-a.dts
 create mode 100644 arch/arm/boot/dts/imx28-ts4600-rev-b.dts

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index c558ba7..5a79fab 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -466,6 +466,8 @@ dtb-$(CONFIG_ARCH_MXS) += \
 	imx28-m28cu3.dtb \
 	imx28-m28evk.dtb \
 	imx28-sps1.dtb \
+	imx28-ts4600-rev-a.dtb \
+	imx28-ts4600-rev-b.dtb \
 	imx28-tx28.dtb
 dtb-$(CONFIG_ARCH_NOMADIK) += \
 	ste-nomadik-s8815.dtb \
diff --git a/arch/arm/boot/dts/imx28-ts4600-common.dtsi b/arch/arm/boot/dts/imx28-ts4600-common.dtsi
new file mode 100644
index 0000000..04bd5a5
--- /dev/null
+++ b/arch/arm/boot/dts/imx28-ts4600-common.dtsi
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2016 Savoir-Faire Linux
+ * Author: Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+#include "imx28.dtsi"
+#include "dt-bindings/gpio/gpio.h"
+
+/ {
+
+	compatible = "technologic,imx28-ts4600", "fsl,imx28";
+
+	apb@80000000 {
+		apbh@80000000 {
+			ssp0: ssp@80010000 {
+				compatible = "fsl,imx28-mmc";
+				pinctrl-names = "default";
+				pinctrl-0 = <&mmc0_4bit_pins_a
+					     &mmc0_sck_cfg
+					     &en_sd_pwr>;
+				broken-cd = <1>;
+				bus-width = <4>;
+				vmmc-supply = <&reg_vddio_sd0>;
+				status = "okay";
+			};
+
+			pinctrl@80018000 {
+				pinctrl-names = "default";
+
+				en_sd_pwr: en_sd_pwr {
+					fsl,pinmux-ids = <
+						MX28_PAD_PWM3__GPIO_3_28
+					>;
+					fsl,drive-strength = <MXS_DRIVE_4mA>;
+					fsl,voltage = <MXS_VOLTAGE_HIGH>;
+					fsl,pull-up = <MXS_PULL_DISABLE>;
+				};
+
+			};
+		};
+
+		apbx@80040000 {
+			pwm: pwm@80064000 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&pwm2_pins_a>;
+				status = "okay";
+			};
+
+			duart: serial@80074000 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&duart_pins_a>;
+				status = "okay";
+			};
+		};
+	};
+
+	regulators {
+		compatible = "simple-bus";
+
+		reg_vddio_sd0: vddio-sd0 {
+			compatible = "regulator-fixed";
+			regulator-name = "vddio-sd0";
+			regulator-min-microvolt = <3300000>;
+			regulator-max-microvolt = <3300000>;
+			regulator-boot-on;
+			gpio = <&gpio3 28 0>;
+		};
+	};
+
+};
diff --git a/arch/arm/boot/dts/imx28-ts4600-rev-a.dts b/arch/arm/boot/dts/imx28-ts4600-rev-a.dts
new file mode 100644
index 0000000..e8cb729
--- /dev/null
+++ b/arch/arm/boot/dts/imx28-ts4600-rev-a.dts
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2016 Savoir-Faire Linux
+ * Author: Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include "imx28-ts4600-common.dtsi"
+
+/ {
+	model = "Technologic Systems i.MX28 TS-4600 Rev A";
+
+	memory {
+		reg = <0x40000000 0x08000000>;   /* 128MB */
+	};
+
+};
diff --git a/arch/arm/boot/dts/imx28-ts4600-rev-b.dts b/arch/arm/boot/dts/imx28-ts4600-rev-b.dts
new file mode 100644
index 0000000..a115f83
--- /dev/null
+++ b/arch/arm/boot/dts/imx28-ts4600-rev-b.dts
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2016 Savoir-Faire Linux
+ * Author: Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include "imx28-ts4600-common.dtsi"
+
+/ {
+	model = "Technologic Systems i.MX28 TS-4600 Rev B";
+
+	memory {
+		reg = <0x40000000 0x10000000>;   /* 256MB */
+	};
+
+};
-- 
2.10.2

[toc] | [prev] | [next] | [standalone]


#1542336 — [PATCH 1/6] of: documentation: add bindings documentation for TS-4600

FromSebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
Date2016-12-15 00:20 +0100
Subject[PATCH 1/6] of: documentation: add bindings documentation for TS-4600
Message-ID<sOr06-6CZ-35@gated-at.bofh.it>
In reply to#1542327
This adds the documentation for the TS-4600 by Technologic Systems.

Signed-off-by: Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
---
 Documentation/devicetree/bindings/arm/technologic.txt | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/technologic.txt b/Documentation/devicetree/bindings/arm/technologic.txt
index 33797ac..e9d6d65 100644
--- a/Documentation/devicetree/bindings/arm/technologic.txt
+++ b/Documentation/devicetree/bindings/arm/technologic.txt
@@ -1,6 +1,11 @@
 Technologic Systems Platforms Device Tree Bindings
 --------------------------------------------------
 
+TS-4600 is a System-on-Module based on the Freescale i.MX28 System-on-Chip.
+It can be mounted on a carrier board providing additional peripheral connectors.
+Required root node properties:
+	- compatible = "technologic,imx28-ts4600", "fsl,imx28"
+
 TS-4800 board
 Required root node properties:
 	- compatible = "technologic,imx51-ts4800", "fsl,imx51";
-- 
2.10.2

[toc] | [prev] | [next] | [standalone]


#1544788 — Re: [PATCH 1/6] of: documentation: add bindings documentation for TS-4600

FromRob Herring <robh@kernel.org>
Date2016-12-19 23:10 +0100
SubjectRe: [PATCH 1/6] of: documentation: add bindings documentation for TS-4600
Message-ID<sQei6-5fb-19@gated-at.bofh.it>
In reply to#1542336
On Wed, Dec 14, 2016 at 06:12:31PM -0500, Sebastien Bourdelin wrote:
> This adds the documentation for the TS-4600 by Technologic Systems.
> 
> Signed-off-by: Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
> ---
>  Documentation/devicetree/bindings/arm/technologic.txt | 5 +++++
>  1 file changed, 5 insertions(+)

Acked-by: Rob Herring <robh@kernel.org>

[toc] | [prev] | [next] | [standalone]


#1542337 — [PATCH 4/6] bus: add driver for the Technologic Systems NBUS

FromSebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
Date2016-12-15 00:20 +0100
Subject[PATCH 4/6] bus: add driver for the Technologic Systems NBUS
Message-ID<sOr06-6CZ-45@gated-at.bofh.it>
In reply to#1542327
This driver implements a GPIOs bit-banged bus, called the NBUS by
Technologic Systems. It is used to communicate with the peripherals in
the FPGA on the TS-4600 SoM.

Signed-off-by: Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
---
 drivers/bus/Kconfig     |   9 +
 drivers/bus/Makefile    |   1 +
 drivers/bus/ts-nbus.c   | 451 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/ts-nbus.h |  17 ++
 4 files changed, 478 insertions(+)
 create mode 100644 drivers/bus/ts-nbus.c
 create mode 100644 include/linux/ts-nbus.h

diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index 7875105..74e72b3 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -150,6 +150,15 @@ config TEGRA_ACONNECT
 	  Driver for the Tegra ACONNECT bus which is used to interface with
 	  the devices inside the Audio Processing Engine (APE) for Tegra210.
 
+config TS_NBUS
+	tristate "Technologic Systems NBUS Driver"
+	default y
+	depends on SOC_IMX28
+	depends on OF_GPIO && PWM
+	help
+	  Driver for the Technologic Systems NBUS which is used to interface
+	  with the peripherals in the FPGA of the TS-4600 SoM.
+
 config UNIPHIER_SYSTEM_BUS
 	tristate "UniPhier System Bus driver"
 	depends on ARCH_UNIPHIER && OF
diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile
index c6cfa6b..83f874a 100644
--- a/drivers/bus/Makefile
+++ b/drivers/bus/Makefile
@@ -19,5 +19,6 @@ obj-$(CONFIG_QCOM_EBI2)		+= qcom-ebi2.o
 obj-$(CONFIG_SUNXI_RSB)		+= sunxi-rsb.o
 obj-$(CONFIG_SIMPLE_PM_BUS)	+= simple-pm-bus.o
 obj-$(CONFIG_TEGRA_ACONNECT)	+= tegra-aconnect.o
+obj-$(CONFIG_TS_NBUS)		+= ts-nbus.o
 obj-$(CONFIG_UNIPHIER_SYSTEM_BUS)	+= uniphier-system-bus.o
 obj-$(CONFIG_VEXPRESS_CONFIG)	+= vexpress-config.o
diff --git a/drivers/bus/ts-nbus.c b/drivers/bus/ts-nbus.c
new file mode 100644
index 0000000..44fc89d
--- /dev/null
+++ b/drivers/bus/ts-nbus.c
@@ -0,0 +1,451 @@
+/*
+ * NBUS driver for TS-4600 based boards
+ *
+ * Copyright (c) 2016 - Savoir-faire Linux
+ * Author: Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ *
+ * This driver implements a GPIOs bit-banged bus, called the NBUS by Technologic
+ * Systems. It is used to communicate with the peripherals in the FPGA on the
+ * TS-4600 SoM.
+ */
+
+#include <linux/gpio.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+
+static DEFINE_MUTEX(ts_nbus_lock);
+static bool ts_nbus_ready;
+
+#define TS_NBUS_READ_MODE  0
+#define TS_NBUS_WRITE_MODE 1
+#define TS_NBUS_DIRECTION_IN  0
+#define TS_NBUS_DIRECTION_OUT 1
+#define TS_NBUS_WRITE_ADR 0
+#define TS_NBUS_WRITE_VAL 1
+
+struct ts_nbus {
+	struct pwm_device *pwm;
+	int num_data;
+	int *data;
+	int csn;
+	int txrx;
+	int strobe;
+	int ale;
+	int rdy;
+};
+
+static struct ts_nbus *ts_nbus;
+
+/*
+ * request all gpios required by the bus.
+ */
+static int ts_nbus_init(struct platform_device *pdev)
+{
+	int err;
+	int i;
+
+	for (i = 0; i < ts_nbus->num_data; i++) {
+		err = devm_gpio_request_one(&pdev->dev, ts_nbus->data[i],
+					    GPIOF_OUT_INIT_HIGH,
+					    "TS NBUS data");
+		if (err)
+			return err;
+	}
+
+	err = devm_gpio_request_one(&pdev->dev, ts_nbus->csn,
+				    GPIOF_OUT_INIT_HIGH,
+				    "TS NBUS csn");
+	if (err)
+		return err;
+
+	err = devm_gpio_request_one(&pdev->dev, ts_nbus->txrx,
+				    GPIOF_OUT_INIT_HIGH,
+				    "TS NBUS txrx");
+	if (err)
+		return err;
+
+	err = devm_gpio_request_one(&pdev->dev, ts_nbus->strobe,
+				    GPIOF_OUT_INIT_HIGH,
+				    "TS NBUS strobe");
+	if (err)
+		return err;
+
+	err = devm_gpio_request_one(&pdev->dev, ts_nbus->ale,
+				    GPIOF_OUT_INIT_HIGH,
+				    "TS NBUS ale");
+	if (err)
+		return err;
+
+	err = devm_gpio_request_one(&pdev->dev, ts_nbus->rdy,
+				    GPIOF_IN,
+				    "TS NBUS rdy");
+	if (err)
+		return err;
+
+	return 0;
+}
+
+/*
+ * retrieve all gpios used by the bus from the device tree.
+ */
+static int ts_nbus_get_of_pdata(struct device *dev, struct device_node *np)
+{
+	int num_data;
+	int *data;
+	int ret;
+	int i;
+
+	ret = of_gpio_named_count(np, "data-gpios");
+	if (ret < 0) {
+		dev_err(dev,
+			"failed to count GPIOs in DT property data-gpios\n");
+		return ret;
+	}
+	num_data = ret;
+	data = devm_kzalloc(dev, num_data * sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	for (i = 0; i < num_data; i++) {
+		ret = of_get_named_gpio(np, "data-gpios", i);
+		if (ret < 0) {
+			dev_err(dev, "failed to retrieve data-gpio from dts\n");
+			return ret;
+		}
+		data[i] = ret;
+	}
+	ts_nbus->num_data = num_data;
+	ts_nbus->data = data;
+
+	ret = of_get_named_gpio(np, "csn-gpios", 0);
+	if (ret < 0) {
+		dev_err(dev, "failed to retrieve csn-gpio from dts\n");
+		return ret;
+	}
+	ts_nbus->csn = ret;
+
+	ret = of_get_named_gpio(np, "txrx-gpios", 0);
+	if (ret < 0) {
+		dev_err(dev, "failed to retrieve txrx-gpio from dts\n");
+		return ret;
+	}
+	ts_nbus->txrx = ret;
+
+	ret = of_get_named_gpio(np, "strobe-gpios", 0);
+	if (ret < 0) {
+		dev_err(dev, "failed to retrieve strobe-gpio from dts\n");
+		return ret;
+	}
+	ts_nbus->strobe = ret;
+
+	ret = of_get_named_gpio(np, "ale-gpios", 0);
+	if (ret < 0) {
+		dev_err(dev, "failed to retrieve ale-gpio from dts\n");
+		return ret;
+	}
+	ts_nbus->ale = ret;
+
+	ret = of_get_named_gpio(np, "rdy-gpios", 0);
+	if (ret < 0) {
+		dev_err(dev, "failed to retrieve rdy-gpio from dts\n");
+		return ret;
+	}
+	ts_nbus->rdy = ret;
+
+	return 0;
+}
+
+/*
+ * the txrx gpio is used by the FPGA to know if the following transactions
+ * should be handled to read or write a value.
+ */
+static inline void ts_nbus_set_mode(int mode)
+{
+	if (mode == TS_NBUS_READ_MODE)
+		gpio_set_value(ts_nbus->txrx, 0);
+	else
+		gpio_set_value(ts_nbus->txrx, 1);
+}
+
+/*
+ * the data gpios are used for reading and writing values, their directions
+ * should be adjusted accordingly.
+ */
+static inline void ts_nbus_set_direction(int direction)
+{
+	int i;
+
+	for (i = 0; i < ts_nbus->num_data; i++) {
+		if (direction == TS_NBUS_DIRECTION_IN)
+			gpio_direction_input(ts_nbus->data[i]);
+		else
+			gpio_direction_output(ts_nbus->data[i], 1);
+	}
+}
+
+/*
+ * reset the bus in its initial state.
+ */
+static inline void ts_nbus_reset_bus(void)
+{
+	int i;
+
+	for (i = 0; i < ts_nbus->num_data; i++)
+		gpio_set_value(ts_nbus->data[i], 0);
+
+	gpio_set_value(ts_nbus->csn, 0);
+	gpio_set_value(ts_nbus->strobe, 0);
+	gpio_set_value(ts_nbus->ale, 0);
+}
+
+/*
+ * let the FPGA knows it can process.
+ */
+static inline void ts_nbus_start_transaction(void)
+{
+	gpio_set_value(ts_nbus->strobe, 1);
+}
+
+/*
+ * return the byte value read from the data gpios.
+ */
+static inline u8 ts_nbus_read_byte(void)
+{
+	int i;
+	u8 value = 0;
+
+	for (i = 0; i < ts_nbus->num_data; i++)
+		if (ts_nbus->data[i])
+			value |= 1 << i;
+
+	return value;
+}
+
+/*
+ * set the data gpios accordingly to the byte value.
+ */
+static inline void ts_nbus_write_byte(u8 byte)
+{
+	int i;
+
+	for (i = 0; i < ts_nbus->num_data; i++)
+		if (byte & (1 << i))
+			gpio_set_value(ts_nbus->data[i], 1);
+}
+
+/*
+ * reading the bus consists of resetting the bus, then notifying the FPGA to
+ * send the data in the data gpios and return the read value.
+ */
+static inline u8 ts_nbus_read_bus(void)
+{
+	ts_nbus_reset_bus();
+	ts_nbus_start_transaction();
+
+	return ts_nbus_read_byte();
+}
+
+/*
+ * writing to the bus consists of resetting the bus, then define the type of
+ * command (address/value), write the data and notify the FPGA to retrieve the
+ * value in the data gpios.
+ */
+static inline void ts_nbus_write_bus(int cmd, u8 value)
+{
+	ts_nbus_reset_bus();
+
+	if (cmd == TS_NBUS_WRITE_ADR)
+		gpio_set_value(ts_nbus->ale, 1);
+
+	ts_nbus_write_byte(value);
+	ts_nbus_start_transaction();
+}
+
+/*
+ * read the value in the FPGA register at the given address.
+ */
+u16 ts_nbus_read(u8 adr)
+{
+	int i;
+	u16 val;
+
+	/* bus access must be atomic */
+	mutex_lock(&ts_nbus_lock);
+
+	/* set the bus in read mode */
+	ts_nbus_set_mode(TS_NBUS_READ_MODE);
+
+	/* write address */
+	ts_nbus_write_bus(TS_NBUS_WRITE_ADR, adr);
+
+	/* set the data gpios direction as input before reading */
+	ts_nbus_set_direction(TS_NBUS_DIRECTION_IN);
+
+	/* reading value MSB first */
+	do {
+		val = 0;
+		for (i = 1; i >= 0; i--)
+			val |= (ts_nbus_read_bus() << (i * 8));
+		gpio_set_value(ts_nbus->csn, 1);
+	} while (gpio_get_value(ts_nbus->rdy));
+
+	/* restore the data gpios direction as output after reading */
+	ts_nbus_set_direction(TS_NBUS_DIRECTION_OUT);
+
+	mutex_unlock(&ts_nbus_lock);
+
+	return val;
+}
+EXPORT_SYMBOL_GPL(ts_nbus_read);
+
+/*
+ * write the desired value in the FPGA register at the given address.
+ */
+int ts_nbus_write(u8 adr, u16 value)
+{
+	int i;
+
+	/* bus access must be atomic */
+	mutex_lock(&ts_nbus_lock);
+
+	/* set the bus in write mode */
+	ts_nbus_set_mode(TS_NBUS_WRITE_MODE);
+
+	/* write address */
+	ts_nbus_write_bus(TS_NBUS_WRITE_ADR, adr);
+
+	/* writing value MSB first */
+	for (i = 1; i >= 0; i--)
+		ts_nbus_write_bus(TS_NBUS_WRITE_VAL, (u8)(value >> (i * 8)));
+
+	/* wait for completion */
+	gpio_set_value(ts_nbus->csn, 1);
+	while (gpio_get_value(ts_nbus->rdy) != 0) {
+		gpio_set_value(ts_nbus->csn, 0);
+		gpio_set_value(ts_nbus->csn, 1);
+	}
+
+	mutex_unlock(&ts_nbus_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ts_nbus_write);
+
+/*
+ * helper function to know the state of the bus.
+ * this function is useful to let peripherals defer their probing while the bus
+ * is not ready.
+ */
+bool ts_nbus_is_ready(void)
+{
+	bool nbus_state;
+
+	mutex_lock(&ts_nbus_lock);
+	nbus_state = ts_nbus_ready;
+	mutex_unlock(&ts_nbus_lock);
+
+	return nbus_state;
+}
+EXPORT_SYMBOL_GPL(ts_nbus_is_ready);
+
+static int ts_nbus_probe(struct platform_device *pdev)
+{
+	struct pwm_device *pwm;
+	struct pwm_args pargs;
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	int ret;
+
+	ts_nbus = devm_kzalloc(dev, sizeof(*ts_nbus), GFP_KERNEL);
+	if (!ts_nbus)
+		return -ENOMEM;
+
+	ret = ts_nbus_get_of_pdata(dev, np);
+	if (ret)
+		return ret;
+	ret = ts_nbus_init(pdev);
+	if (ret < 0)
+		return ret;
+
+	pwm = devm_pwm_get(dev, NULL);
+	if (IS_ERR(pwm)) {
+		ret = PTR_ERR(pwm);
+		if (ret != -EPROBE_DEFER)
+			dev_err(dev, "unable to request PWM\n");
+		return ret;
+	}
+
+	pwm_get_args(pwm, &pargs);
+	if (!pargs.period) {
+		dev_err(&pdev->dev, "invalid PWM period\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * FIXME: pwm_apply_args() should be removed when switching to
+	 * the atomic PWM API.
+	 */
+	pwm_apply_args(pwm);
+	ret = pwm_config(pwm, pargs.period, pargs.period);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * we can now start the FPGA and let the peripherals knows the bus is
+	 * ready.
+	 */
+	pwm_enable(pwm);
+	ts_nbus->pwm = pwm;
+
+	mutex_lock(&ts_nbus_lock);
+	ts_nbus_ready = true;
+	mutex_unlock(&ts_nbus_lock);
+
+	dev_info(dev, "initialized\n");
+
+	return 0;
+}
+
+static int ts_nbus_remove(struct platform_device *pdev)
+{
+	/* disable bus access */
+	mutex_lock(&ts_nbus_lock);
+	ts_nbus_ready = false;
+	mutex_unlock(&ts_nbus_lock);
+
+	/* shutdown the FPGA */
+	pwm_disable(ts_nbus->pwm);
+
+	return 0;
+}
+
+static const struct of_device_id ts_nbus_of_match[] = {
+	{ .compatible = "technologic,ts-nbus", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, ts_nbus_of_match);
+
+static struct platform_driver ts_nbus_driver = {
+	.probe		= ts_nbus_probe,
+	.remove		= ts_nbus_remove,
+	.driver		= {
+		.name	= "ts_nbus",
+		.of_match_table = ts_nbus_of_match,
+	},
+};
+
+module_platform_driver(ts_nbus_driver);
+
+MODULE_ALIAS("platform:ts_nbus");
+MODULE_AUTHOR("Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>");
+MODULE_DESCRIPTION("Technologic Systems NBUS");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/ts-nbus.h b/include/linux/ts-nbus.h
new file mode 100644
index 0000000..5fcdb96
--- /dev/null
+++ b/include/linux/ts-nbus.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2016 - Savoir-faire Linux
+ * Author: Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef _TS_NBUS_H
+#define _TS_NBUS_H
+
+extern u16 ts_nbus_read(u8 adr);
+extern int ts_nbus_write(u8 adr, u16 value);
+extern bool ts_nbus_is_ready(void);
+
+#endif /* _TS_NBUS_H */
-- 
2.10.2

[toc] | [prev] | [next] | [standalone]


#1548482 — Re: [PATCH 4/6] bus: add driver for the Technologic Systems NBUS

FromLinus Walleij <linus.walleij@linaro.org>
Date2016-12-30 09:00 +0100
SubjectRe: [PATCH 4/6] bus: add driver for the Technologic Systems NBUS
Message-ID<sU0gx-1tm-3@gated-at.bofh.it>
In reply to#1542337
On Thu, Dec 15, 2016 at 12:12 AM, Sebastien Bourdelin
<sebastien.bourdelin@savoirfairelinux.com> wrote:

> This driver implements a GPIOs bit-banged bus, called the NBUS by
> Technologic Systems. It is used to communicate with the peripherals in
> the FPGA on the TS-4600 SoM.
>
> Signed-off-by: Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
(...)

> +#include <linux/gpio.h>

Use:
#include <linux/gpio/consumer.h>
instead, and deal with the fallout.

> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/of.h>
> +#include <linux/of_gpio.h>

Don't use this.

> +#include <linux/platform_device.h>
> +#include <linux/pwm.h>
> +
> +static DEFINE_MUTEX(ts_nbus_lock);
> +static bool ts_nbus_ready;

Why not move this to the struct ts_nbus state container?

It seems to be per-bus not per-system.

> +#define TS_NBUS_READ_MODE  0
> +#define TS_NBUS_WRITE_MODE 1
> +#define TS_NBUS_DIRECTION_IN  0
> +#define TS_NBUS_DIRECTION_OUT 1
> +#define TS_NBUS_WRITE_ADR 0
> +#define TS_NBUS_WRITE_VAL 1
> +
> +struct ts_nbus {
> +       struct pwm_device *pwm;
> +       int num_data;
> +       int *data;
> +       int csn;
> +       int txrx;
> +       int strobe;
> +       int ale;
> +       int rdy;
> +};
> +
> +static struct ts_nbus *ts_nbus;

Nopes. No singletons please.

Use the state container pattern:
Documentation/driver-model/design-patterns.txt

> +/*
> + * request all gpios required by the bus.
> + */
> +static int ts_nbus_init(struct platform_device *pdev)
> +{
> +       int err;
> +       int i;
> +
> +       for (i = 0; i < ts_nbus->num_data; i++) {
> +               err = devm_gpio_request_one(&pdev->dev, ts_nbus->data[i],
> +                                           GPIOF_OUT_INIT_HIGH,
> +                                           "TS NBUS data");
> +               if (err)
> +                       return err;
> +       }

DO not use the legacy GPIO API anywhere.

Reference the device and use gpiod_get() simple, fair and square.

Store struct gpio_desc * pointers in your state container instead.

> +static int ts_nbus_get_of_pdata(struct device *dev, struct device_node *np)
> +{
> +       int num_data;
> +       int *data;
> +       int ret;
> +       int i;
> +
> +       ret = of_gpio_named_count(np, "data-gpios");
> +       if (ret < 0) {
> +               dev_err(dev,
> +                       "failed to count GPIOs in DT property data-gpios\n");
> +               return ret;
> +       }

Do not reinvent the wheel.

Use devm_gpiod_get_array().


> +       ret = of_get_named_gpio(np, "csn-gpios", 0);

And again use devm_gpiod_get(), and gpiod_* accessors.
Applies everywhere.

Yours,
Linus Walleij

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web