Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 1/4] Documentation: dt-bindings: add the Amlogic Meson SAR ADC documentation
From: Martin Blumenstingl @ 2017-01-15 22:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170115224221.15510-1-martin.blumenstingl@googlemail.com>

This adds the devicetree binding documentation for the SAR ADC found in
Amlogic Meson SoCs.
Currently only the GXBB, GXL and GXM SoCs are supported.

Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
 .../bindings/iio/adc/amlogic,meson-saradc.txt      | 31 ++++++++++++++++++++++
 1 file changed, 31 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt

diff --git a/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt b/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt
new file mode 100644
index 000000000000..9a0bec7afc63
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt
@@ -0,0 +1,31 @@
+* Amlogic Meson SAR (Successive Approximation Register) A/D converter
+
+Required properties:
+- compatible:	depending on the SoC this should be one of:
+			- "amlogic,meson-gxbb-saradc" for GXBB
+			- "amlogic,meson-gxl-saradc" for GXL and GXM
+		along with the generic "amlogic,meson-saradc"
+- reg:		the physical base address and length of the registers
+- clocks:	phandle and clock identifier (see clock-names)
+- clock-names:	mandatory clocks:
+			- "clkin" for the reference clock (typically XTAL)
+			- "core" for the SAR ADC core clock
+		optional clocks:
+			- "sana" for the analog clock
+			- "adc_clk" for the ADC (sampling) clock
+			- "adc_sel" for the ADC (sampling) clock mux
+- vref-supply:	the regulator supply for the ADC reference voltage
+- #io-channel-cells: must be 1, see ../iio-bindings.txt
+
+Example:
+	saradc: adc at 8680 {
+		compatible = "amlogic,meson-gxl-saradc", "amlogic,meson-saradc";
+		#io-channel-cells = <1>;
+		reg = <0x0 0x8680 0x0 0x34>;
+		clocks = <&xtal>,
+			 <&clkc CLKID_SAR_ADC>,
+			 <&clkc CLKID_SANA>,
+			 <&clkc CLKID_SAR_ADC_CLK>,
+			 <&clkc CLKID_SAR_ADC_SEL>;
+		clock-names = "clkin", "core", "sana", "adc_clk", "adc_sel";
+	};
-- 
2.11.0

^ permalink raw reply related

* [PATCH v2 2/4] clk: gxbb: add the SAR ADC clocks and expose them
From: Martin Blumenstingl @ 2017-01-15 22:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170115224221.15510-1-martin.blumenstingl@googlemail.com>

The HHI_SAR_CLK_CNTL contains three SAR ADC specific clocks:
- a mux clock to choose between different ADC reference clocks (this is
  2-bit wide, but the datasheet only lists the parents for the first
  bit)
- a divider for the input/reference clock
- a gate which enables the ADC clock

Additionally this exposes the ADC core clock (CLKID_SAR_ADC) and
CLKID_SANA (which seems to enable the analog inputs, but unfortunately
there is no documentation for this - we just mimic what the vendor
driver does).

Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
 drivers/clk/meson/gxbb.c              | 48 +++++++++++++++++++++++++++++++++++
 drivers/clk/meson/gxbb.h              |  9 ++++---
 include/dt-bindings/clock/gxbb-clkc.h |  4 +++
 3 files changed, 58 insertions(+), 3 deletions(-)

diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c
index 9d9af446bafc..1c1ec137a3cc 100644
--- a/drivers/clk/meson/gxbb.c
+++ b/drivers/clk/meson/gxbb.c
@@ -564,6 +564,46 @@ static struct clk_gate gxbb_clk81 = {
 	},
 };
 
+static struct clk_mux gxbb_sar_adc_clk_sel = {
+	.reg = (void *)HHI_SAR_CLK_CNTL,
+	.mask = 0x3,
+	.shift = 9,
+	.lock = &clk_lock,
+	.hw.init = &(struct clk_init_data){
+		.name = "sar_adc_clk_sel",
+		.ops = &clk_mux_ops,
+		/* NOTE: The datasheet doesn't list the parents for bit 10 */
+		.parent_names = (const char *[]){ "xtal", "clk81", },
+		.num_parents = 2,
+	},
+};
+
+static struct clk_divider gxbb_sar_adc_clk_div = {
+	.reg = (void *)HHI_SAR_CLK_CNTL,
+	.shift = 0,
+	.width = 8,
+	.lock = &clk_lock,
+	.hw.init = &(struct clk_init_data){
+		.name = "sar_adc_clk_div",
+		.ops = &clk_divider_ops,
+		.parent_names = (const char *[]){ "sar_adc_clk_sel" },
+		.num_parents = 1,
+	},
+};
+
+static struct clk_gate gxbb_sar_adc_clk = {
+	.reg = (void *)HHI_SAR_CLK_CNTL,
+	.bit_idx = 8,
+	.lock = &clk_lock,
+	.hw.init = &(struct clk_init_data){
+		.name = "sar_adc_clk",
+		.ops = &clk_gate_ops,
+		.parent_names = (const char *[]){ "sar_adc_clk_div" },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
 /* Everything Else (EE) domain gates */
 static MESON_GATE(gxbb_ddr, HHI_GCLK_MPEG0, 0);
 static MESON_GATE(gxbb_dos, HHI_GCLK_MPEG0, 1);
@@ -754,6 +794,9 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = {
 		[CLKID_SD_EMMC_A]	    = &gxbb_emmc_a.hw,
 		[CLKID_SD_EMMC_B]	    = &gxbb_emmc_b.hw,
 		[CLKID_SD_EMMC_C]	    = &gxbb_emmc_c.hw,
+		[CLKID_SAR_ADC_CLK]	    = &gxbb_sar_adc_clk.hw,
+		[CLKID_SAR_ADC_SEL]	    = &gxbb_sar_adc_clk_sel.hw,
+		[CLKID_SAR_ADC_DIV]	    = &gxbb_sar_adc_clk_div.hw,
 	},
 	.num = NR_CLKS,
 };
@@ -856,6 +899,7 @@ static struct clk_gate *gxbb_clk_gates[] = {
 	&gxbb_emmc_a,
 	&gxbb_emmc_b,
 	&gxbb_emmc_c,
+	&gxbb_sar_adc_clk,
 };
 
 static int gxbb_clkc_probe(struct platform_device *pdev)
@@ -888,6 +932,10 @@ static int gxbb_clkc_probe(struct platform_device *pdev)
 	gxbb_mpeg_clk_sel.reg = clk_base + (u64)gxbb_mpeg_clk_sel.reg;
 	gxbb_mpeg_clk_div.reg = clk_base + (u64)gxbb_mpeg_clk_div.reg;
 
+	/* Populate the base address for the SAR ADC clks */
+	gxbb_sar_adc_clk_sel.reg = clk_base + (u64)gxbb_sar_adc_clk_sel.reg;
+	gxbb_sar_adc_clk_div.reg = clk_base + (u64)gxbb_sar_adc_clk_div.reg;
+
 	/* Populate base address for gates */
 	for (i = 0; i < ARRAY_SIZE(gxbb_clk_gates); i++)
 		gxbb_clk_gates[i]->reg = clk_base +
diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h
index 0252939ba58f..d90052d74abd 100644
--- a/drivers/clk/meson/gxbb.h
+++ b/drivers/clk/meson/gxbb.h
@@ -191,7 +191,7 @@
 #define CLKID_PERIPHS		  20
 #define CLKID_SPICC		  21
 /* CLKID_I2C */
-#define CLKID_SAR_ADC		  23
+/* #define CLKID_SAR_ADC */
 #define CLKID_SMART_CARD	  24
 #define CLKID_RNG0		  25
 #define CLKID_UART0		  26
@@ -237,7 +237,7 @@
 #define CLKID_MMC_PCLK		  66
 #define CLKID_DVIN		  67
 #define CLKID_UART2		  68
-#define CLKID_SANA		  69
+/* #define CLKID_SANA */
 #define CLKID_VPU_INTR		  70
 #define CLKID_SEC_AHB_AHB3_BRIDGE 71
 #define CLKID_CLK81_A53		  72
@@ -265,8 +265,11 @@
 /* CLKID_SD_EMMC_A */
 /* CLKID_SD_EMMC_B */
 /* CLKID_SD_EMMC_C */
+/* CLKID_SAR_ADC_CLK */
+/* CLKID_SAR_ADC_SEL */
+#define CLKID_SAR_ADC_DIV	  99
 
-#define NR_CLKS			  97
+#define NR_CLKS			  100
 
 /* include the CLKIDs that have been made part of the stable DT binding */
 #include <dt-bindings/clock/gxbb-clkc.h>
diff --git a/include/dt-bindings/clock/gxbb-clkc.h b/include/dt-bindings/clock/gxbb-clkc.h
index baade6f429d0..c2e93676010d 100644
--- a/include/dt-bindings/clock/gxbb-clkc.h
+++ b/include/dt-bindings/clock/gxbb-clkc.h
@@ -14,15 +14,19 @@
 #define CLKID_MPLL2		15
 #define CLKID_SPI		34
 #define CLKID_I2C		22
+#define CLKID_SAR_ADC		23
 #define CLKID_ETH		36
 #define CLKID_USB0		50
 #define CLKID_USB1		51
 #define CLKID_USB		55
 #define CLKID_USB1_DDR_BRIDGE	64
 #define CLKID_USB0_DDR_BRIDGE	65
+#define CLKID_SANA		69
 #define CLKID_AO_I2C		93
 #define CLKID_SD_EMMC_A		94
 #define CLKID_SD_EMMC_B		95
 #define CLKID_SD_EMMC_C		96
+#define CLKID_SAR_ADC_CLK	97
+#define CLKID_SAR_ADC_SEL	98
 
 #endif /* __GXBB_CLKC_H */
-- 
2.11.0

^ permalink raw reply related

* [PATCH v2 3/4] iio: adc: add a driver for the SAR ADC found in Amlogic Meson SoCs
From: Martin Blumenstingl @ 2017-01-15 22:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170115224221.15510-1-martin.blumenstingl@googlemail.com>

This adds support for the SAR (Successive Approximation Register) ADC
on the Amlogic Meson SoCs.

The code is based on the public S805 (Meson8b) and S905 (GXBB)
datasheets (see [0] and [1]), as well as by reading (various versions
of) the vendor driver and by inspecting the registers on the vendor
kernels of my testing-hardware.

Currently the GXBB, GXL and GXM SoCs are supported. GXBB hardware has
10-bit ADC resolution, while GXL and GXM have 12-bit ADC resolution.
The code was written to support older SoCs (Meson8 and Meson8b) as well,
but due to lack of actual testing-hardware no of_device_id was added for
these.

Two "features" from the vendor driver are currently missing:
- the vendor driver uses channel #7 for calibration (this improves the
  accuracy of the results - in my tests the results were less than 3%
  off without calibration compared to the vendor driver). Adding support
  for this should be easy, but is not required for most applications.
- channel #6 is connected to the SoCs internal temperature sensor.
  Adding support for this is probably not so easy since (based on the
  u-boot sources) most SoC versions are using different registers and
  algorithms for the conversion from "ADC value" to temperature.

Supported by the hardware but currently not supported by the driver:
- reading multiple channels at the same time (the hardware has a FIFO
  buffer which stores multiple results)
- continuous sampling (this would require a way to enable this
  individually because otherwise the ADC would be drawing power
  constantly)
- interrupt support (similar to the vendor driver this new driver is
  polling the results. It is unclear if the IRQ-mode is supported on
  older (Meson6 or Meson8) hardware as well or if there are any errata)

[0]
http://dn.odroid.com/S805/Datasheet/S805_Datasheet%20V0.8%2020150126.pdf
[1] http://dn.odroid.com/S905/DataSheet/S905_Public_Datasheet_V1.1.4.pdf

Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
 drivers/iio/adc/Kconfig        |  12 +
 drivers/iio/adc/Makefile       |   1 +
 drivers/iio/adc/meson_saradc.c | 893 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 906 insertions(+)
 create mode 100644 drivers/iio/adc/meson_saradc.c

diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 9c8b558ba19e..86059b9b91bf 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -371,6 +371,18 @@ config MEN_Z188_ADC
 	  This driver can also be built as a module. If so, the module will be
 	  called men_z188_adc.
 
+config MESON_SARADC
+	tristate "Amlogic Meson SAR ADC driver"
+	default ARCH_MESON
+	depends on OF && COMMON_CLK && (ARCH_MESON || COMPILE_TEST)
+	select REGMAP_MMIO
+	help
+	  Say yes here to build support for the SAR ADC found in Amlogic Meson
+	  SoCs.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called meson_saradc.
+
 config MXS_LRADC
         tristate "Freescale i.MX23/i.MX28 LRADC"
         depends on (ARCH_MXS || COMPILE_TEST) && HAS_IOMEM
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index d36c4be8d1fc..de05b9e75f8f 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_MCP320X) += mcp320x.o
 obj-$(CONFIG_MCP3422) += mcp3422.o
 obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
 obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
+obj-$(CONFIG_MESON_SARADC) += meson_saradc.o
 obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o
 obj-$(CONFIG_NAU7802) += nau7802.o
 obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c
new file mode 100644
index 000000000000..4c189e5fd7cc
--- /dev/null
+++ b/drivers/iio/adc/meson_saradc.c
@@ -0,0 +1,893 @@
+/*
+ * Amlogic Meson Successive Approximation Register (SAR) A/D Converter
+ *
+ * Copyright (C) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+#define SAR_ADC_REG0						0x00
+	#define SAR_ADC_REG0_PANEL_DETECT			BIT(31)
+	#define SAR_ADC_REG0_BUSY_MASK				GENMASK(30, 28)
+	#define SAR_ADC_REG0_DELTA_BUSY				BIT(30)
+	#define SAR_ADC_REG0_AVG_BUSY				BIT(29)
+	#define SAR_ADC_REG0_SAMPLE_BUSY			BIT(28)
+	#define SAR_ADC_REG0_FIFO_FULL				BIT(27)
+	#define SAR_ADC_REG0_FIFO_EMPTY				BIT(26)
+	#define SAR_ADC_REG0_FIFO_COUNT_MASK			GENMASK(25, 21)
+	#define SAR_ADC_REG0_ADC_BIAS_CTRL_MASK			GENMASK(20, 19)
+	#define SAR_ADC_REG0_CURR_CHAN_ID_MASK			GENMASK(18, 16)
+	#define SAR_ADC_REG0_ADC_TEMP_SEN_SEL			BIT(15)
+	#define SAR_ADC_REG0_SAMPLING_STOP			BIT(14)
+	#define SAR_ADC_REG0_CHAN_DELTA_EN_MASK			GENMASK(13, 12)
+	#define SAR_ADC_REG0_DETECT_IRQ_POL			BIT(10)
+	#define SAR_ADC_REG0_DETECT_IRQ_EN			BIT(9)
+	#define SAR_ADC_REG0_FIFO_CNT_IRQ_MASK			GENMASK(8, 4)
+	#define SAR_ADC_REG0_FIFO_IRQ_EN			BIT(3)
+	#define SAR_ADC_REG0_SAMPLING_START			BIT(2)
+	#define SAR_ADC_REG0_CONTINUOUS_EN			BIT(1)
+	#define SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE		BIT(0)
+
+#define SAR_ADC_CHAN_LIST					0x04
+	#define SAR_ADC_CHAN_LIST_MAX_INDEX_MASK		GENMASK(26, 24)
+	#define SAR_ADC_CHAN_CHAN_ENTRY_MASK(_chan)		\
+					(GENMASK(2, 0) << (_chan * 3))
+
+#define SAR_ADC_AVG_CNTL					0x08
+	#define SAR_ADC_AVG_CNTL_AVG_MODE_SHIFT(_chan)		\
+					(16 + (_chan * 2))
+	#define SAR_ADC_AVG_CNTL_AVG_MODE_MASK(_chan)		\
+					(GENMASK(17, 16) << (_chan * 2))
+	#define SAR_ADC_AVG_CNTL_NUM_SAMPLES_SHIFT(_chan)	\
+					(0 + (_chan * 2))
+	#define SAR_ADC_AVG_CNTL_NUM_SAMPLES_MASK(_chan)	\
+					(GENMASK(1, 0) << (_chan * 2))
+
+#define SAR_ADC_REG3						0x0c
+	#define SAR_ADC_REG3_CNTL_USE_SC_DLY			BIT(31)
+	#define SAR_ADC_REG3_CLK_EN				BIT(30)
+	#define SAR_ADC_REG3_BL30_INITIALIZED			BIT(28)
+	#define SAR_ADC_REG3_CTRL_CONT_RING_COUNTER_EN		BIT(27)
+	#define SAR_ADC_REG3_CTRL_SAMPLING_CLOCK_PHASE		BIT(26)
+	#define SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK		GENMASK(25, 23)
+	#define SAR_ADC_REG3_DETECT_EN				BIT(22)
+	#define SAR_ADC_REG3_ADC_EN				BIT(21)
+	#define SAR_ADC_REG3_PANEL_DETECT_COUNT_MASK		GENMASK(20, 18)
+	#define SAR_ADC_REG3_PANEL_DETECT_FILTER_TB_MASK	GENMASK(17, 16)
+	#define SAR_ADC_REG3_ADC_CLK_DIV_SHIFT			10
+	#define SAR_ADC_REG3_ADC_CLK_DIV_WIDTH			5
+	#define SAR_ADC_REG3_ADC_CLK_DIV_MASK			GENMASK(15, 10)
+	#define SAR_ADC_REG3_BLOCK_DLY_SEL_MASK			GENMASK(9, 8)
+	#define SAR_ADC_REG3_BLOCK_DLY_MASK			GENMASK(7, 0)
+
+#define SAR_ADC_DELAY						0x10
+	#define SAR_ADC_DELAY_INPUT_DLY_SEL_MASK		GENMASK(25, 24)
+	#define SAR_ADC_DELAY_BL30_BUSY				BIT(15)
+	#define SAR_ADC_DELAY_KERNEL_BUSY			BIT(14)
+	#define SAR_ADC_DELAY_INPUT_DLY_CNT_MASK		GENMASK(23, 16)
+	#define SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK		GENMASK(9, 8)
+	#define SAR_ADC_DELAY_SAMPLE_DLY_CNT_MASK		GENMASK(7, 0)
+
+#define SAR_ADC_LAST_RD						0x14
+	#define SAR_ADC_LAST_RD_LAST_CHANNEL1_MASK		GENMASK(23, 16)
+	#define SAR_ADC_LAST_RD_LAST_CHANNEL0_MASK		GENMASK(9, 0)
+
+#define SAR_ADC_FIFO_RD						0x18
+	#define SAR_ADC_FIFO_RD_CHAN_ID_MASK			GENMASK(14, 12)
+	#define SAR_ADC_FIFO_RD_SAMPLE_VALUE_MASK		GENMASK(11, 0)
+
+#define SAR_ADC_AUX_SW						0x1c
+	#define SAR_ADC_AUX_SW_MUX_SEL_CHAN_MASK(_chan)		\
+					(GENMASK(10, 8) << ((_chan - 2) * 2))
+	#define SAR_ADC_AUX_SW_VREF_P_MUX			BIT(6)
+	#define SAR_ADC_AUX_SW_VREF_N_MUX			BIT(5)
+	#define SAR_ADC_AUX_SW_MODE_SEL				BIT(4)
+	#define SAR_ADC_AUX_SW_YP_DRIVE_SW			BIT(3)
+	#define SAR_ADC_AUX_SW_XP_DRIVE_SW			BIT(2)
+	#define SAR_ADC_AUX_SW_YM_DRIVE_SW			BIT(1)
+	#define SAR_ADC_AUX_SW_XM_DRIVE_SW			BIT(0)
+
+#define SAR_ADC_CHAN_10_SW					0x20
+	#define SAR_ADC_CHAN_10_SW_CHAN1_MUX_SEL_MASK		GENMASK(25, 23)
+	#define SAR_ADC_CHAN_10_SW_CHAN1_VREF_P_MUX		BIT(22)
+	#define SAR_ADC_CHAN_10_SW_CHAN1_VREF_N_MUX		BIT(21)
+	#define SAR_ADC_CHAN_10_SW_CHAN1_MODE_SEL		BIT(20)
+	#define SAR_ADC_CHAN_10_SW_CHAN1_YP_DRIVE_SW		BIT(19)
+	#define SAR_ADC_CHAN_10_SW_CHAN1_XP_DRIVE_SW		BIT(18)
+	#define SAR_ADC_CHAN_10_SW_CHAN1_YM_DRIVE_SW		BIT(17)
+	#define SAR_ADC_CHAN_10_SW_CHAN1_XM_DRIVE_SW		BIT(16)
+	#define SAR_ADC_CHAN_10_SW_CHAN0_MUX_SEL_MASK		GENMASK(9, 7)
+	#define SAR_ADC_CHAN_10_SW_CHAN0_VREF_P_MUX		BIT(6)
+	#define SAR_ADC_CHAN_10_SW_CHAN0_VREF_N_MUX		BIT(5)
+	#define SAR_ADC_CHAN_10_SW_CHAN0_MODE_SEL		BIT(4)
+	#define SAR_ADC_CHAN_10_SW_CHAN0_YP_DRIVE_SW		BIT(3)
+	#define SAR_ADC_CHAN_10_SW_CHAN0_XP_DRIVE_SW		BIT(2)
+	#define SAR_ADC_CHAN_10_SW_CHAN0_YM_DRIVE_SW		BIT(1)
+	#define SAR_ADC_CHAN_10_SW_CHAN0_XM_DRIVE_SW		BIT(0)
+
+#define SAR_ADC_DETECT_IDLE_SW					0x24
+	#define SAR_ADC_DETECT_IDLE_SW_DETECT_SW_EN		BIT(26)
+	#define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_MUX_MASK	GENMASK(25, 23)
+	#define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_VREF_P_MUX	BIT(22)
+	#define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_VREF_N_MUX	BIT(21)
+	#define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_SEL		BIT(20)
+	#define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_YP_DRIVE_SW	BIT(19)
+	#define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_XP_DRIVE_SW	BIT(18)
+	#define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_YM_DRIVE_SW	BIT(17)
+	#define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_XM_DRIVE_SW	BIT(16)
+	#define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_MUX_SEL_MASK	GENMASK(9, 7)
+	#define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_VREF_P_MUX	BIT(6)
+	#define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_VREF_N_MUX	BIT(5)
+	#define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_SEL		BIT(4)
+	#define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_YP_DRIVE_SW	BIT(3)
+	#define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_XP_DRIVE_SW	BIT(2)
+	#define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_YM_DRIVE_SW	BIT(1)
+	#define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_XM_DRIVE_SW	BIT(0)
+
+#define SAR_ADC_DELTA_10					0x28
+	#define SAR_ADC_DELTA_10_TEMP_SEL			BIT(27)
+	#define SAR_ADC_DELTA_10_TS_REVE1			BIT(26)
+	#define SAR_ADC_DELTA_10_CHAN1_DELTA_VALUE_SHIFT	16
+	#define SAR_ADC_DELTA_10_CHAN1_DELTA_VALUE_MASK		GENMASK(25, 16)
+	#define SAR_ADC_DELTA_10_TS_REVE0			BIT(15)
+	#define SAR_ADC_DELTA_10_TS_C_SHIFT			11
+	#define SAR_ADC_DELTA_10_TS_C_MASK			GENMASK(14, 11)
+	#define SAR_ADC_DELTA_10_TS_VBG_EN			BIT(10)
+	#define SAR_ADC_DELTA_10_CHAN0_DELTA_VALUE_SHIFT	0
+	#define SAR_ADC_DELTA_10_CHAN0_DELTA_VALUE_MASK		GENMASK(9, 0)
+
+/*
+ * NOTE: registers from here are undocumented (the vendor Linux kernel driver
+ * and u-boot source served as reference). These only seem to be relevant on
+ * GXBB and newer.
+ */
+#define SAR_ADC_REG11						0x2c
+	#define SAR_ADC_REG11_BANDGAP_EN			BIT(13)
+
+#define SAR_ADC_REG13						0x34
+	#define SAR_ADC_REG13_12BIT_CALIBRATION_MASK		GENMASK(13, 8)
+
+#define SAR_ADC_MAX_FIFO_SIZE		32
+
+#define MESON_SAR_ADC_CHAN(_chan, _type) {				\
+	.type = _type,							\
+	.indexed = true,						\
+	.channel = _chan,						\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |			\
+				BIT(IIO_CHAN_INFO_AVERAGE_RAW),		\
+	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),		\
+	.datasheet_name = "SAR_ADC_CH"#_chan,				\
+}
+
+/*
+ * TODO: the hardware supports IIO_TEMP for channel 6 as well which is
+ * currently not supported by this driver.
+ */
+static const struct iio_chan_spec meson_saradc_iio_channels[] = {
+	MESON_SAR_ADC_CHAN(0, IIO_VOLTAGE),
+	MESON_SAR_ADC_CHAN(1, IIO_VOLTAGE),
+	MESON_SAR_ADC_CHAN(2, IIO_VOLTAGE),
+	MESON_SAR_ADC_CHAN(3, IIO_VOLTAGE),
+	MESON_SAR_ADC_CHAN(4, IIO_VOLTAGE),
+	MESON_SAR_ADC_CHAN(5, IIO_VOLTAGE),
+	MESON_SAR_ADC_CHAN(6, IIO_VOLTAGE),
+	MESON_SAR_ADC_CHAN(7, IIO_VOLTAGE),
+	IIO_CHAN_SOFT_TIMESTAMP(8),
+};
+
+enum meson_saradc_avg_mode {
+	NO_AVERAGING = 0x0,
+	MEAN_AVERAGING = 0x1,
+	MEDIAN_AVERAGING = 0x2,
+};
+
+enum meson_saradc_num_samples {
+	ONE_SAMPLE = 0x0,
+	TWO_SAMPLES = 0x1,
+	FOUR_SAMPLES = 0x2,
+	EIGHT_SAMPLES = 0x3,
+};
+
+enum meson_saradc_chan7_mux_sel {
+	CHAN7_MUX_VSS = 0x0,
+	CHAN7_MUX_VDD_DIV4 = 0x1,
+	CHAN7_MUX_VDD_DIV2 = 0x2,
+	CHAN7_MUX_VDD_MUL3_DIV4 = 0x3,
+	CHAN7_MUX_VDD = 0x4,
+	CHAN7_MUX_CH7_INPUT = 0x7,
+};
+
+struct meson_saradc_data {
+	unsigned int			resolution;
+	const char			*name;
+};
+
+struct meson_saradc_priv {
+	struct regmap			*regmap;
+	struct regulator		*vref;
+	const struct meson_saradc_data	*data;
+	struct clk			*clkin;
+	struct clk			*core_clk;
+	struct clk			*sana_clk;
+	struct clk			*adc_sel_clk;
+	struct clk			*adc_clk;
+	struct clk_gate			clk_gate;
+	struct clk			*adc_div_clk;
+	struct clk_divider		clk_div;
+};
+
+static const struct regmap_config meson_saradc_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 32,
+	.reg_stride = 4,
+	.max_register = SAR_ADC_REG13,
+};
+
+static unsigned int meson_saradc_get_fifo_count(struct iio_dev *indio_dev)
+{
+	struct meson_saradc_priv *priv = iio_priv(indio_dev);
+	u32 regval;
+
+	regmap_read(priv->regmap, SAR_ADC_REG0, &regval);
+
+	return FIELD_GET(SAR_ADC_REG0_FIFO_COUNT_MASK, regval);
+}
+
+static int meson_saradc_wait_busy_clear(struct iio_dev *indio_dev)
+{
+	struct meson_saradc_priv *priv = iio_priv(indio_dev);
+	int regval, timeout = 10000;
+
+	/*
+	 * NOTE: we need a small delay before reading the status, otherwise
+	 * the sample engine may not have started internally (which would
+	 * seem to us that sampling is already finished).
+	 */
+	do {
+		udelay(1);
+		regmap_read(priv->regmap, SAR_ADC_REG0, &regval);
+	} while (FIELD_GET(SAR_ADC_REG0_BUSY_MASK, regval) && timeout--);
+
+	if (timeout < 0)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static int meson_saradc_read_raw_sample(struct iio_dev *indio_dev,
+					const struct iio_chan_spec *chan,
+					int *val)
+{
+	struct meson_saradc_priv *priv = iio_priv(indio_dev);
+	int ret, regval, fifo_chan, fifo_val, sum = 0, count = 0;
+
+	ret = meson_saradc_wait_busy_clear(indio_dev);
+	if (ret)
+		return ret;
+
+	while (meson_saradc_get_fifo_count(indio_dev) > 0 &&
+	       count < SAR_ADC_MAX_FIFO_SIZE) {
+		regmap_read(priv->regmap, SAR_ADC_FIFO_RD, &regval);
+
+		fifo_chan = FIELD_GET(SAR_ADC_FIFO_RD_CHAN_ID_MASK, regval);
+		if (fifo_chan == chan->channel) {
+			fifo_val = FIELD_GET(SAR_ADC_FIFO_RD_SAMPLE_VALUE_MASK,
+						regval);
+			fifo_val &= (BIT(priv->data->resolution) - 1);
+
+			sum += fifo_val;
+			count++;
+		}
+	}
+
+	if (!count)
+		return -ENOENT;
+
+	*val = sum / count;
+
+	return 0;
+}
+
+static void meson_saradc_set_averaging(struct iio_dev *indio_dev,
+				       const struct iio_chan_spec *chan,
+				       enum meson_saradc_avg_mode mode,
+				       enum meson_saradc_num_samples samples)
+{
+	struct meson_saradc_priv *priv = iio_priv(indio_dev);
+	u32 val;
+
+	val = samples << SAR_ADC_AVG_CNTL_NUM_SAMPLES_SHIFT(chan->channel);
+	regmap_update_bits(priv->regmap, SAR_ADC_AVG_CNTL,
+			   SAR_ADC_AVG_CNTL_NUM_SAMPLES_MASK(chan->channel),
+			   val);
+
+	val = mode << SAR_ADC_AVG_CNTL_AVG_MODE_SHIFT(chan->channel);
+	regmap_update_bits(priv->regmap, SAR_ADC_AVG_CNTL,
+			   SAR_ADC_AVG_CNTL_AVG_MODE_MASK(chan->channel), val);
+}
+
+static void meson_saradc_enable_channel(struct iio_dev *indio_dev,
+					const struct iio_chan_spec *chan)
+{
+	struct meson_saradc_priv *priv = iio_priv(indio_dev);
+	u32 regval;
+
+	/* the SAR ADC engine allows sampling multiple channels at the same
+	 * time. to keep it simple we're only working with one *internal*
+	 * channel, which starts counting at index 0 (which means: count = 1).
+	 */
+	regval = FIELD_PREP(SAR_ADC_CHAN_LIST_MAX_INDEX_MASK, 0);
+	regmap_update_bits(priv->regmap, SAR_ADC_CHAN_LIST,
+			   SAR_ADC_CHAN_LIST_MAX_INDEX_MASK, regval);
+
+	/* map channel index 0 to the channel which we want to read */
+	regval = FIELD_PREP(SAR_ADC_CHAN_CHAN_ENTRY_MASK(0), chan->channel);
+	regmap_update_bits(priv->regmap, SAR_ADC_CHAN_LIST,
+			   SAR_ADC_CHAN_CHAN_ENTRY_MASK(0), regval);
+
+	regval = FIELD_PREP(SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_MUX_MASK,
+			    chan->channel);
+	regmap_update_bits(priv->regmap, SAR_ADC_DETECT_IDLE_SW,
+			   SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_MUX_MASK,
+			   regval);
+
+	regval = FIELD_PREP(SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_MUX_SEL_MASK,
+			    chan->channel);
+	regmap_update_bits(priv->regmap, SAR_ADC_DETECT_IDLE_SW,
+			   SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_MUX_SEL_MASK,
+			   regval);
+
+	if (chan->channel == 6)
+		regmap_update_bits(priv->regmap, SAR_ADC_DELTA_10,
+				   SAR_ADC_DELTA_10_TEMP_SEL, 0);
+}
+
+static void meson_saradc_set_channel7_mux(struct iio_dev *indio_dev,
+					  enum meson_saradc_chan7_mux_sel sel)
+{
+	struct meson_saradc_priv *priv = iio_priv(indio_dev);
+	u32 regval;
+
+	regval = FIELD_PREP(SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK, sel);
+	regmap_update_bits(priv->regmap, SAR_ADC_REG3,
+			   SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK, regval);
+
+	usleep_range(10, 20);
+}
+
+static void meson_saradc_start_sample_engine(struct iio_dev *indio_dev)
+{
+	struct meson_saradc_priv *priv = iio_priv(indio_dev);
+
+	regmap_update_bits(priv->regmap, SAR_ADC_REG0,
+			   SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE,
+			   SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE);
+
+	regmap_update_bits(priv->regmap, SAR_ADC_REG0,
+			   SAR_ADC_REG0_SAMPLING_START,
+			   SAR_ADC_REG0_SAMPLING_START);
+}
+
+static void meson_saradc_stop_sample_engine(struct iio_dev *indio_dev)
+{
+	struct meson_saradc_priv *priv = iio_priv(indio_dev);
+
+	regmap_update_bits(priv->regmap, SAR_ADC_REG0,
+			   SAR_ADC_REG0_SAMPLING_STOP,
+			   SAR_ADC_REG0_SAMPLING_STOP);
+
+	/* wait until all modules are stopped */
+	meson_saradc_wait_busy_clear(indio_dev);
+
+	regmap_update_bits(priv->regmap, SAR_ADC_REG0,
+			   SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE, 0);
+}
+
+static void meson_saradc_lock(struct iio_dev *indio_dev)
+{
+	struct meson_saradc_priv *priv = iio_priv(indio_dev);
+	int val;
+
+	mutex_lock(&indio_dev->mlock);
+
+	/* prevent BL30 from using the SAR ADC while we are using it */
+	regmap_update_bits(priv->regmap, SAR_ADC_DELAY,
+			   SAR_ADC_DELAY_KERNEL_BUSY,
+			   SAR_ADC_DELAY_KERNEL_BUSY);
+
+	/* wait until BL30 releases it's lock (so we can use the SAR ADC) */
+	do {
+		udelay(1);
+		regmap_read(priv->regmap, SAR_ADC_DELAY, &val);
+	} while (val & SAR_ADC_DELAY_BL30_BUSY);
+}
+
+static void meson_saradc_unlock(struct iio_dev *indio_dev)
+{
+	struct meson_saradc_priv *priv = iio_priv(indio_dev);
+
+	/* allow BL30 to use the SAR ADC again */
+	regmap_update_bits(priv->regmap, SAR_ADC_DELAY,
+			   SAR_ADC_DELAY_KERNEL_BUSY, 0);
+
+	mutex_unlock(&indio_dev->mlock);
+}
+
+static void meson_saradc_clear_fifo(struct iio_dev *indio_dev)
+{
+	struct meson_saradc_priv *priv = iio_priv(indio_dev);
+	int count;
+
+	for (count = 0; count < SAR_ADC_MAX_FIFO_SIZE; count++) {
+		if (!meson_saradc_get_fifo_count(indio_dev))
+			break;
+
+		regmap_read(priv->regmap, SAR_ADC_FIFO_RD, 0);
+	}
+}
+
+static int meson_saradc_get_sample(struct iio_dev *indio_dev,
+				   const struct iio_chan_spec *chan,
+				   enum meson_saradc_avg_mode avg_mode,
+				   enum meson_saradc_num_samples avg_samples,
+				   int *val)
+{
+	int ret;
+
+	meson_saradc_lock(indio_dev);
+
+	/* clear the FIFO to make sure we're not reading old values */
+	meson_saradc_clear_fifo(indio_dev);
+
+	meson_saradc_set_averaging(indio_dev, chan, avg_mode, avg_samples);
+
+	meson_saradc_enable_channel(indio_dev, chan);
+
+	meson_saradc_start_sample_engine(indio_dev);
+	ret = meson_saradc_read_raw_sample(indio_dev, chan, val);
+	meson_saradc_stop_sample_engine(indio_dev);
+
+	meson_saradc_unlock(indio_dev);
+
+	if (ret) {
+		dev_warn(indio_dev->dev.parent,
+			 "failed to read sample for channel %d: %d\n",
+			 chan->channel, ret);
+		return ret;
+	}
+
+	return IIO_VAL_INT;
+}
+
+static int meson_saradc_iio_info_read_raw(struct iio_dev *indio_dev,
+					  const struct iio_chan_spec *chan,
+					  int *val, int *val2, long mask)
+{
+	struct meson_saradc_priv *priv = iio_priv(indio_dev);
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		return meson_saradc_get_sample(indio_dev, chan, NO_AVERAGING,
+					       ONE_SAMPLE, val);
+		break;
+
+	case IIO_CHAN_INFO_AVERAGE_RAW:
+		return meson_saradc_get_sample(indio_dev, chan, MEAN_AVERAGING,
+					       EIGHT_SAMPLES, val);
+		break;
+
+	case IIO_CHAN_INFO_SCALE:
+		ret = regulator_get_voltage(priv->vref);
+		if (ret < 0) {
+			dev_err(indio_dev->dev.parent,
+				"failed to get vref voltage: %d\n", ret);
+			return ret;
+		}
+
+		*val = ret / 1000;
+		*val2 = priv->data->resolution;
+		return IIO_VAL_FRACTIONAL_LOG2;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int meson_saradc_clk_init(struct iio_dev *indio_dev, void __iomem *base)
+{
+	struct meson_saradc_priv *priv = iio_priv(indio_dev);
+	struct clk_init_data init;
+	const char *clk_parents[1];
+
+	init.name = devm_kasprintf(&indio_dev->dev, GFP_KERNEL, "%s#adc_div",
+				   of_node_full_name(indio_dev->dev.of_node));
+	init.flags = 0;
+	init.ops = &clk_divider_ops;
+	clk_parents[0] = __clk_get_name(priv->clkin);
+	init.parent_names = clk_parents;
+	init.num_parents = 1;
+
+	priv->clk_div.reg = base + SAR_ADC_REG3;
+	priv->clk_div.shift = SAR_ADC_REG3_ADC_CLK_DIV_SHIFT;
+	priv->clk_div.width = SAR_ADC_REG3_ADC_CLK_DIV_WIDTH;
+	priv->clk_div.hw.init = &init;
+	priv->clk_div.flags = 0;
+
+	priv->adc_div_clk = devm_clk_register(&indio_dev->dev,
+					      &priv->clk_div.hw);
+	if (WARN_ON(IS_ERR(priv->adc_div_clk)))
+		return PTR_ERR(priv->adc_div_clk);
+
+	init.name = devm_kasprintf(&indio_dev->dev, GFP_KERNEL, "%s#adc_en",
+				   of_node_full_name(indio_dev->dev.of_node));
+	init.flags = CLK_SET_RATE_PARENT;
+	init.ops = &clk_gate_ops;
+	clk_parents[0] = __clk_get_name(priv->adc_div_clk);
+	init.parent_names = clk_parents;
+	init.num_parents = 1;
+
+	priv->clk_gate.reg = base + SAR_ADC_REG3;
+	priv->clk_gate.bit_idx = fls(SAR_ADC_REG3_CLK_EN);
+	priv->clk_gate.hw.init = &init;
+
+	priv->adc_clk = devm_clk_register(&indio_dev->dev, &priv->clk_gate.hw);
+	if (WARN_ON(IS_ERR(priv->adc_clk)))
+		return PTR_ERR(priv->adc_clk);
+
+	return 0;
+}
+
+static int meson_saradc_init(struct iio_dev *indio_dev)
+{
+	struct meson_saradc_priv *priv = iio_priv(indio_dev);
+	int regval, ret;
+
+	/*
+	 * make sure we start at CH7 input since the other muxes are only used
+	 * for internal calibration.
+	 */
+	meson_saradc_set_channel7_mux(indio_dev, CHAN7_MUX_CH7_INPUT);
+
+	/*
+	 * leave sampling delay and the input clocks as configured by BL30 to
+	 * make sure BL30 gets the values it expects when reading the
+	 * temperature sensor.
+	 */
+	regmap_read(priv->regmap, SAR_ADC_REG3, &regval);
+	if (regval & SAR_ADC_REG3_BL30_INITIALIZED)
+		return 0;
+
+	meson_saradc_stop_sample_engine(indio_dev);
+
+	/* update the channel 6 MUX to select the temperature sensor */
+	regmap_update_bits(priv->regmap, SAR_ADC_REG0,
+			SAR_ADC_REG0_ADC_TEMP_SEN_SEL,
+			SAR_ADC_REG0_ADC_TEMP_SEN_SEL);
+
+	/* disable all channels by default */
+	regmap_write(priv->regmap, SAR_ADC_CHAN_LIST, 0x0);
+
+	regmap_update_bits(priv->regmap, SAR_ADC_REG3,
+			   SAR_ADC_REG3_CTRL_SAMPLING_CLOCK_PHASE, 0);
+	regmap_update_bits(priv->regmap, SAR_ADC_REG3,
+			   SAR_ADC_REG3_CNTL_USE_SC_DLY,
+			   SAR_ADC_REG3_CNTL_USE_SC_DLY);
+
+	/* delay between two samples = (10+1) * 1uS */
+	regmap_update_bits(priv->regmap, SAR_ADC_DELAY,
+			   SAR_ADC_DELAY_INPUT_DLY_CNT_MASK,
+			   FIELD_PREP(SAR_ADC_DELAY_SAMPLE_DLY_CNT_MASK, 10));
+	regmap_update_bits(priv->regmap, SAR_ADC_DELAY,
+			   SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK,
+			   FIELD_PREP(SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK, 0));
+
+	/* delay between two samples = (10+1) * 1uS */
+	regmap_update_bits(priv->regmap, SAR_ADC_DELAY,
+			   SAR_ADC_DELAY_INPUT_DLY_CNT_MASK,
+			   FIELD_PREP(SAR_ADC_DELAY_INPUT_DLY_CNT_MASK, 10));
+	regmap_update_bits(priv->regmap, SAR_ADC_DELAY,
+			   SAR_ADC_DELAY_INPUT_DLY_SEL_MASK,
+			   FIELD_PREP(SAR_ADC_DELAY_INPUT_DLY_SEL_MASK, 1));
+
+	ret = clk_set_parent(priv->adc_sel_clk, priv->clkin);
+	if (ret) {
+		dev_err(indio_dev->dev.parent,
+			"failed to set adc parent to clkin\n");
+		return ret;
+	}
+
+	ret = clk_set_rate(priv->adc_clk, 1200000);
+	if (ret) {
+		dev_err(indio_dev->dev.parent,
+			"failed to set adc clock rate\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int meson_saradc_hw_enable(struct iio_dev *indio_dev)
+{
+	struct meson_saradc_priv *priv = iio_priv(indio_dev);
+	int ret;
+
+	meson_saradc_lock(indio_dev);
+
+	ret = regulator_enable(priv->vref);
+	if (ret < 0) {
+		dev_err(indio_dev->dev.parent,
+			"failed to enable vref regulator\n");
+		goto err_vref;
+	}
+
+	ret = clk_prepare_enable(priv->core_clk);
+	if (ret) {
+		dev_err(indio_dev->dev.parent, "failed to enable core clk\n");
+		goto err_core_clk;
+	}
+
+	ret = clk_prepare_enable(priv->sana_clk);
+	if (ret) {
+		dev_err(indio_dev->dev.parent, "failed to enable sana clk\n");
+		goto err_sana_clk;
+	}
+
+	regmap_update_bits(priv->regmap, SAR_ADC_REG11,
+			   SAR_ADC_REG11_BANDGAP_EN, SAR_ADC_REG11_BANDGAP_EN);
+	regmap_update_bits(priv->regmap, SAR_ADC_REG3, SAR_ADC_REG3_ADC_EN,
+			   SAR_ADC_REG3_ADC_EN);
+
+	udelay(5);
+
+	ret = clk_prepare_enable(priv->adc_clk);
+	if (ret) {
+		dev_err(indio_dev->dev.parent, "failed to enable adc clk\n");
+		goto err_adc_clk;
+	}
+
+	meson_saradc_unlock(indio_dev);
+
+	return 0;
+
+err_adc_clk:
+	regmap_update_bits(priv->regmap, SAR_ADC_REG3, SAR_ADC_REG3_ADC_EN, 0);
+	regmap_update_bits(priv->regmap, SAR_ADC_REG11,
+			   SAR_ADC_REG11_BANDGAP_EN, 0);
+	clk_disable_unprepare(priv->sana_clk);
+err_sana_clk:
+	clk_disable_unprepare(priv->core_clk);
+err_core_clk:
+	regulator_disable(priv->vref);
+err_vref:
+	meson_saradc_unlock(indio_dev);
+	return ret;
+}
+
+static void meson_saradc_hw_disable(struct iio_dev *indio_dev)
+{
+	struct meson_saradc_priv *priv = iio_priv(indio_dev);
+
+	meson_saradc_lock(indio_dev);
+
+	clk_disable_unprepare(priv->adc_clk);
+
+	regmap_update_bits(priv->regmap, SAR_ADC_REG3, SAR_ADC_REG3_ADC_EN, 0);
+	regmap_update_bits(priv->regmap, SAR_ADC_REG11,
+			   SAR_ADC_REG11_BANDGAP_EN, 0);
+
+	clk_disable_unprepare(priv->sana_clk);
+	clk_disable_unprepare(priv->core_clk);
+
+	regulator_disable(priv->vref);
+
+	meson_saradc_unlock(indio_dev);
+}
+
+static const struct iio_info meson_saradc_iio_info = {
+	.read_raw = meson_saradc_iio_info_read_raw,
+	.driver_module = THIS_MODULE,
+};
+
+struct meson_saradc_data meson_saradc_gxbb_data = {
+	.resolution = 10,
+	.name = "meson-gxbb-saradc",
+};
+
+struct meson_saradc_data meson_saradc_gxl_data = {
+	.resolution = 12,
+	.name = "meson-gxl-saradc",
+};
+
+static const struct of_device_id meson_saradc_of_match[] = {
+	{
+		.compatible = "amlogic,meson-gxbb-saradc",
+		.data = &meson_saradc_gxbb_data,
+	}, {
+		.compatible = "amlogic,meson-gxl-saradc",
+		.data = &meson_saradc_gxl_data,
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, meson_saradc_of_match);
+
+static int meson_saradc_probe(struct platform_device *pdev)
+{
+	struct meson_saradc_priv *priv;
+	struct iio_dev *indio_dev;
+	struct resource *res;
+	void __iomem *base;
+	const struct of_device_id *match;
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv));
+	if (!indio_dev) {
+		dev_err(&pdev->dev, "failed allocating iio device\n");
+		return -ENOMEM;
+	}
+
+	priv = iio_priv(indio_dev);
+
+	match = of_match_device(meson_saradc_of_match, &pdev->dev);
+	priv->data = match->data;
+
+	indio_dev->name = priv->data->name;
+	indio_dev->dev.parent = &pdev->dev;
+	indio_dev->dev.of_node = pdev->dev.of_node;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->info = &meson_saradc_iio_info;
+
+	indio_dev->channels = meson_saradc_iio_channels;
+	indio_dev->num_channels = ARRAY_SIZE(meson_saradc_iio_channels);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	priv->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+					     &meson_saradc_regmap_config);
+	if (IS_ERR(priv->regmap))
+		return PTR_ERR(priv->regmap);
+
+	priv->clkin = devm_clk_get(&pdev->dev, "clkin");
+	if (IS_ERR(priv->clkin)) {
+		dev_err(&pdev->dev, "failed to get clkin\n");
+		return PTR_ERR(priv->clkin);
+	}
+
+	priv->core_clk = devm_clk_get(&pdev->dev, "core");
+	if (IS_ERR(priv->core_clk)) {
+		dev_err(&pdev->dev, "failed to get core clk\n");
+		return PTR_ERR(priv->core_clk);
+	}
+
+	priv->sana_clk = devm_clk_get(&pdev->dev, "sana");
+	if (IS_ERR(priv->sana_clk)) {
+		if (PTR_ERR(priv->sana_clk) == -ENOENT) {
+			priv->sana_clk = NULL;
+		} else {
+			dev_err(&pdev->dev, "failed to get sana clk\n");
+			return PTR_ERR(priv->sana_clk);
+		}
+	}
+
+	priv->adc_clk = devm_clk_get(&pdev->dev, "adc_clk");
+	if (IS_ERR(priv->adc_clk)) {
+		if (PTR_ERR(priv->adc_clk) == -ENOENT) {
+			priv->adc_clk = NULL;
+		} else {
+			dev_err(&pdev->dev, "failed to get adc clk\n");
+			return PTR_ERR(priv->adc_clk);
+		}
+	}
+
+	priv->adc_sel_clk = devm_clk_get(&pdev->dev, "adc_sel");
+	if (IS_ERR(priv->adc_sel_clk)) {
+		if (PTR_ERR(priv->adc_sel_clk) == -ENOENT) {
+			priv->adc_sel_clk = NULL;
+		} else {
+			dev_err(&pdev->dev, "failed to get adc_sel clk\n");
+			return PTR_ERR(priv->adc_sel_clk);
+		}
+	}
+
+	/* on pre-GXBB SoCs the SAR ADC itself provides the ADC clock: */
+	if (!priv->adc_clk) {
+		ret = meson_saradc_clk_init(indio_dev, base);
+		if (ret)
+			return ret;
+	}
+
+	priv->vref = devm_regulator_get(&pdev->dev, "vref");
+	if (IS_ERR(priv->vref)) {
+		dev_err(&pdev->dev, "failed to get vref regulator\n");
+		return PTR_ERR(priv->vref);
+	}
+
+	ret = meson_saradc_init(indio_dev);
+	if (ret)
+		goto err;
+
+	ret = meson_saradc_hw_enable(indio_dev);
+	if (ret)
+		goto err;
+
+	platform_set_drvdata(pdev, indio_dev);
+
+	ret = iio_device_register(indio_dev);
+	if (ret)
+		goto err_hw;
+
+	return 0;
+
+err_hw:
+	meson_saradc_hw_disable(indio_dev);
+err:
+	return ret;
+}
+
+static int meson_saradc_remove(struct platform_device *pdev)
+{
+	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+
+	meson_saradc_hw_disable(indio_dev);
+	iio_device_unregister(indio_dev);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int meson_saradc_suspend(struct device *dev)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+
+	meson_saradc_hw_disable(indio_dev);
+
+	return 0;
+}
+
+static int meson_saradc_resume(struct device *dev)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+
+	return meson_saradc_hw_enable(indio_dev);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(meson_saradc_pm_ops,
+			 meson_saradc_suspend, meson_saradc_resume);
+
+static struct platform_driver meson_saradc_driver = {
+	.probe		= meson_saradc_probe,
+	.remove		= meson_saradc_remove,
+	.driver		= {
+		.name	= "meson-saradc",
+		.of_match_table = meson_saradc_of_match,
+		.pm = &meson_saradc_pm_ops,
+	},
+};
+
+module_platform_driver(meson_saradc_driver);
+
+MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
+MODULE_DESCRIPTION("Amlogic Meson SAR ADC driver");
+MODULE_LICENSE("GPL v2");
-- 
2.11.0

^ permalink raw reply related

* [PATCH v2 4/4] ARM64: dts: meson: meson-gx: add the SAR ADC
From: Martin Blumenstingl @ 2017-01-15 22:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170115224221.15510-1-martin.blumenstingl@googlemail.com>

Add the SAR ADC to meson-gxbb.dtsi and meson-gxl.dtsi. GXBB provides a
10-bit ADC while GXL (and GXM, which uses the same ADC as GXL) provides
a 12-bit ADC.
Some boards use resistor ladder buttons connected through one of the ADC
channels. On newer devices (GXL and GXM) some boards use pull-ups/downs
to change the resistance (and thus the ADC value) on of the ADC channels
to indicate the board revision.

Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
 arch/arm64/boot/dts/amlogic/meson-gx.dtsi   |  8 ++++++++
 arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 10 ++++++++++
 arch/arm64/boot/dts/amlogic/meson-gxl.dtsi  | 10 ++++++++++
 3 files changed, 28 insertions(+)

diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
index cddad8c795ec..041e4f0ed7d7 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
@@ -237,6 +237,14 @@
 				status = "disabled";
 			};
 
+			saradc: adc at 8680 {
+				compatible = "amlogic,meson-saradc";
+				#io-channel-cells = <1>;
+				status = "disabled";
+				reg = <0x0 0x8680 0x0 0x34>;
+				interrupts = <GIC_SPI 79 IRQ_TYPE_EDGE_RISING>;
+			};
+
 			pwm_ef: pwm at 86c0 {
 				compatible = "amlogic,meson-gx-pwm", "amlogic,meson-gxbb-pwm";
 				reg = <0x0 0x086c0 0x0 0x10>;
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
index 5d686334f692..114d7e1c9fc0 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
@@ -429,6 +429,16 @@
 	clocks = <&clkc CLKID_I2C>;
 };
 
+&saradc {
+	compatible = "amlogic,meson-gxbb-saradc", "amlogic,meson-saradc";
+	clocks = <&xtal>,
+		 <&clkc CLKID_SAR_ADC>,
+		 <&clkc CLKID_SANA>,
+		 <&clkc CLKID_SAR_ADC_CLK>,
+		 <&clkc CLKID_SAR_ADC_SEL>;
+	clock-names = "clkin", "core", "sana", "adc_clk", "adc_sel";
+};
+
 &sd_emmc_a {
 	clocks = <&clkc CLKID_SD_EMMC_A>,
 		 <&xtal>,
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
index bb2842f8a08f..6b63296b6c60 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
@@ -273,6 +273,16 @@
 	clocks = <&clkc CLKID_I2C>;
 };
 
+&saradc {
+	compatible = "amlogic,meson-gxl-saradc", "amlogic,meson-saradc";
+	clocks = <&xtal>,
+		 <&clkc CLKID_SAR_ADC>,
+		 <&clkc CLKID_SANA>,
+		 <&clkc CLKID_SAR_ADC_CLK>,
+		 <&clkc CLKID_SAR_ADC_SEL>;
+	clock-names = "clkin", "core", "sana", "adc_clk", "adc_sel";
+};
+
 &sd_emmc_a {
 	clocks = <&clkc CLKID_SD_EMMC_A>,
 		 <&xtal>,
-- 
2.11.0

^ permalink raw reply related

* [PATCH 1/4] tty: serial: meson: allow baud-rates higher than 115200
From: Andreas Färber @ 2017-01-15 22:48 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170115223255.10350-2-martin.blumenstingl@googlemail.com>

Am 15.01.2017 um 23:32 schrieb Martin Blumenstingl:
> The vendor driver allows setting baud-rates higher than 115200 baud.
> There is a check in the vendor driver which prevents using more than
> 115200 baud during startup, however it does not have such a check in
> .set_termios.
> Higher baud-rates are often used by the bluetooth modules embedded into
> the SDIO wifi chips (Amlogic devices use brcmfmac based wifi chips quite
> often, 2000000 baud seems to be a common value for the UART baud-rate in
> Amlogic's "libbt").
> 
> I have tested this on a Meson GXL device with uart_A (to which the
> bluetooth module is connected, where initialization times out with
> 115200 baud) and uart_AO (which I manually set to 2000000 baud  and then
> connected with my USB UART adapter to that).
> 
> Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>

Tested-by: Andreas F?rber <afaerber@suse.de>

Thanks,
Andreas

-- 
SUSE Linux GmbH, Maxfeldstr. 5, 90409 N?rnberg, Germany
GF: Felix Imend?rffer, Jane Smithard, Graham Norton
HRB 21284 (AG N?rnberg)

^ permalink raw reply

* [PATCH 2/4] ARM64: dts: meson-gx: add the serial CTS and RTS pin groups
From: Andreas Färber @ 2017-01-15 22:50 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170115223255.10350-3-martin.blumenstingl@googlemail.com>

Am 15.01.2017 um 23:32 schrieb Martin Blumenstingl:
> This adds pinctrl group nodes for the CTS and RTS pins of each serial
> controller. This makes it possible to enable the CTS and RTS pins which
> are controlled by the serial controller hardware (through the meson_uart
> driver).
> 
> Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>

Tested-by: Andreas F?rber <afaerber@suse.de>

Thanks,
Andreas

-- 
SUSE Linux GmbH, Maxfeldstr. 5, 90409 N?rnberg, Germany
GF: Felix Imend?rffer, Jane Smithard, Graham Norton
HRB 21284 (AG N?rnberg)

^ permalink raw reply

* [PATCH 4/4] ARM64: dts: meson-gxbb-vega-s95: enable the Bluetooth module
From: Andreas Färber @ 2017-01-15 22:55 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170115223255.10350-5-martin.blumenstingl@googlemail.com>

Am 15.01.2017 um 23:32 schrieb Martin Blumenstingl:
> This takes the Bluetooth module out of reset (the reset line is
> connected to GPIOX_20) and enables uart_A which is used to configure the
> module. This is common for all Vega S95 boards.
> The device can then be initialized by running the hciattach tool:
> hciattach -s115200 /dev/ttyAML1 bcm43xx 2000000 flow -
> 
> Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
> ---
>  arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi | 9 +++++++++
>  1 file changed, 9 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi
> index ab497126c9a3..9e0a13b1ac93 100644
> --- a/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi
> +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi
> @@ -47,6 +47,7 @@
>  
>  	aliases {
>  		serial0 = &uart_AO;
> +		serial1 = &uart_A;
>  	};
>  
>  	chosen {
> @@ -100,6 +101,14 @@
>  	};
>  };
>  
> +/* This is connected to the Bluetooth module of the wifi/BT combo chip: */

Personally I would just say "Connected to the .... chip" or even just
"Bluetooth .... chip", without trailing colon, for consistency.

> +&uart_A {
> +	status = "okay";
> +	pinctrl-0 = <&uart_a_pins &uart_a_cts_rts_pins>;
> +	pinctrl-names = "default";
> +	uart-has-rtscts;
> +};
> +
>  &uart_AO {
>  	status = "okay";
>  	pinctrl-0 = <&uart_ao_a_pins>;

Tested-by: Andreas F?rber <afaerber@suse.de>

Thanks,
Andreas

-- 
SUSE Linux GmbH, Maxfeldstr. 5, 90409 N?rnberg, Germany
GF: Felix Imend?rffer, Jane Smithard, Graham Norton
HRB 21284 (AG N?rnberg)

^ permalink raw reply

* [PATCH 04/10] sata: hardreset: retry if phys link is down
From: Tejun Heo @ 2017-01-15 23:10 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1484311084-31547-5-git-send-email-bgolaszewski@baylibre.com>

Hello,

On Fri, Jan 13, 2017 at 01:37:58PM +0100, Bartosz Golaszewski wrote:
> The sata core driver already retries to resume the link because some
> controllers ignore writes to the SControl register.
> 
> We have a use case with the da850 SATA controller where at PLL0
> frequency of 456MHz (needed to properly service the LCD controller)
> the chip becomes unstable and the hardreset operation is ignored the
> first time 50% of times.
> 
> Retrying just the resume operation doesn't work - we need to issue
> the phy/wake reset again to make it work.
> 
> If ata_phys_link_offline() returns true in sata_link_hardreset(),
> retry a couple times before really giving up.

I think it'd be better to implement the driver specific implementation
rather than changing the behavior for everybody.

Thanks.

-- 
tejun

^ permalink raw reply

* [PATCH 06/10] sata: ahci_da850: implement a softreset quirk
From: Tejun Heo @ 2017-01-15 23:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1484311084-31547-7-git-send-email-bgolaszewski@baylibre.com>

On Fri, Jan 13, 2017 at 01:38:00PM +0100, Bartosz Golaszewski wrote:
> +static int ahci_da850_softreset(struct ata_link *link,
> +				unsigned int *class, unsigned long deadline)
> +{
> +	int pmp, ret;
> +
> +	pmp = sata_srst_pmp(link);
> +
> +	ret = ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready);
> +	if (pmp && ret == -EBUSY)
> +		return ahci_do_softreset(link, class, 0,
> +					 deadline, ahci_check_ready);
> +
> +	return ret;
> +}

Please add some comments explaining what's going on.

Thanks.

-- 
tejun

^ permalink raw reply

* [PATCH 3/4] ARM64: dts: meson-gx-p23x-q20x: enable the Bluetooth module
From: Andreas Färber @ 2017-01-16  0:47 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170115223255.10350-4-martin.blumenstingl@googlemail.com>

Am 15.01.2017 um 23:32 schrieb Martin Blumenstingl:
> This takes the Bluetooth module out of reset (the reset line is
> connected to GPIOX_17) and enables uart_A which is used to configure the
> module.
> This is identical for all boards which inherit meson-gx-p23x-q20x:
> - GXL S905D P230
> - GXL S905D P231
> - GXM S912 Q200
> - GXM S912 Q201
> 
> To get the HCI interface up one has to install bluez-utils and run:
> hciattach -s115200 /dev/ttyAML1 bcm43xx 2000000 flow -
> 
> Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
> ---
>  arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi | 12 +++++++++++-
>  1 file changed, 11 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
> index 7a078bef04cd..7db779048091 100644
> --- a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
> +++ b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
> @@ -48,6 +48,7 @@
>  / {
>  	aliases {
>  		serial0 = &uart_AO;
> +		serial1 = &uart_A;
>  	};
>  
>  	chosen {
> @@ -94,12 +95,21 @@
>  
>  	sdio_pwrseq: sdio-pwrseq {
>  		compatible = "mmc-pwrseq-simple";
> -		reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>;
> +		reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>,
> +			      <&gpio GPIOX_17 GPIO_ACTIVE_LOW>;
>  		clocks = <&wifi32k>;
>  		clock-names = "ext_clock";
>  	};
>  };
>  
> +/* This is connected to the Bluetooth module of the wifi/BT combo chip: */
> +&uart_A {
> +	status = "okay";
> +	pinctrl-0 = <&uart_a_pins &uart_a_cts_rts_pins>;

Nit: <&uart_a_pins>, <&uart_a_cts_rts_pins> please, like you've done for
reset-gpios above.

Regards,
Andreas

> +	pinctrl-names = "default";
> +	uart-has-rtscts;
> +};
> +
>  /* This UART is brought out to the DB9 connector */
>  &uart_AO {
>  	status = "okay";
> 


-- 
SUSE Linux GmbH, Maxfeldstr. 5, 90409 N?rnberg, Germany
GF: Felix Imend?rffer, Jane Smithard, Graham Norton
HRB 21284 (AG N?rnberg)

^ permalink raw reply

* [PATCH v18 00/15] acpi, clocksource: add GTDT driver and GTDT support in arm_arch_timer
From: Fu Wei @ 2017-01-16  0:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CADyBb7vF0v2DwXA8fNUOTQcqriJK1Hp57_G8DKi0WO9FnvrB5w@mail.gmail.com>

Hi Mark,

On 14 January 2017 at 19:34, Fu Wei <fu.wei@linaro.org> wrote:
> Hi Mark,
>
> On 14 January 2017 at 03:29, Mark Rutland <mark.rutland@arm.com> wrote:
>> Hi,
>>
>> On Fri, Dec 09, 2016 at 01:33:04AM +0800, fu.wei at linaro.org wrote:
>>> From: Fu Wei <fu.wei@linaro.org>
>>>
>>> This patchset:
>>>     (1)Preparation for adding GTDT support in arm_arch_timer:
>>>         1. Move some enums and marcos to header file;
>>>         2. Add a new enum for spi type;
>>>         3. Improve printk relevant code;
>>>         4. Rename some enums and defines;
>>>         5. Rework PPI determination;
>>>         6. Rework counter frequency detection;
>>>         7. Refactor arch_timer_needs_probing, move it into DT init call
>>>         8. Introduce some new structs and refactor the MMIO timer init code
>>>         for reusing some common code.
>>>
>>>     (2)Introduce ACPI GTDT parser: drivers/acpi/arm64/acpi_gtdt.c
>>>     Parse all kinds of timer in GTDT table of ACPI:arch timer,
>>>     memory-mapped timer and SBSA Generic Watchdog timer.
>>>     This driver can help to simplify all the relevant timer drivers,
>>>     and separate all the ACPI GTDT knowledge from them.
>>>
>>>     (3)Simplify ACPI code for arm_arch_timer
>>>
>>>     (4)Add GTDT support for ARM memory-mapped timer.
>>>
>>> This patchset has been tested on the following platforms with ACPI enabled:
>>>     (1)ARM Foundation v8 model
>>
>> Once v4.10-rc4 comes out this weekend, could you please rebase and
>> repost this?
>
> Yes, of course.
>
> I have rebased v19 to the latest v4.10-rc3-e96f8f1, it dosen't need
> any modification.
> I will rebase it every day, and will repost it if it need any  modification.
>
> But for now, V19 works well with the master branch of upstream kernel.
> Do I need to re-post it even if it doesn't need any improvement or
> modification? :-)

I just fetched the latest mainline kernel, and rebase v19 on the top
of 4.10-rc4.
I have double checked it, V19 works well with  4.10-rc4.
For rebasing,  it doesn't need any modification.

So please help me to review V19, I will improve it ASAP according to
your suggestion.

Many thanks!

>
>>
>> Marc and I will be happy to take a look then.
>
> Great thanks for your help!
>
>>
>> Thanks,
>> Mark.
>
>
>
> --
> Best regards,
>
> Fu Wei
> Software Engineer
> Red Hat



-- 
Best regards,

Fu Wei
Software Engineer
Red Hat

^ permalink raw reply

* [PATCH v11 02/12] drm/mediatek: add helpers for coverting from the generic components
From: CK Hu @ 2017-01-16  1:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1484117473-46644-3-git-send-email-yt.shen@mediatek.com>

On Wed, 2017-01-11 at 14:51 +0800, YT Shen wrote:
> define helpers for converting from 'mtk_ddp_comp' to 'mtk_disp_ovl'
> define helpers for converting from 'mtk_ddp_comp' to 'mtk_disp_rdma'
> 
> Signed-off-by: YT Shen <yt.shen@mediatek.com>

Acked-by CK Hu <ck.hu@mediatek.com>

> ---
>  drivers/gpu/drm/mediatek/mtk_disp_ovl.c  | 15 +++++++++------
>  drivers/gpu/drm/mediatek/mtk_disp_rdma.c | 15 +++++++++------
>  2 files changed, 18 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> index c703102..ce2759f 100644
> --- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> +++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> @@ -57,6 +57,11 @@ struct mtk_disp_ovl {
>  	struct drm_crtc			*crtc;
>  };
>  
> +static inline struct mtk_disp_ovl *comp_to_ovl(struct mtk_ddp_comp *comp)
> +{
> +	return container_of(comp, struct mtk_disp_ovl, ddp_comp);
> +}
> +
>  static irqreturn_t mtk_disp_ovl_irq_handler(int irq, void *dev_id)
>  {
>  	struct mtk_disp_ovl *priv = dev_id;
> @@ -76,20 +81,18 @@ static irqreturn_t mtk_disp_ovl_irq_handler(int irq, void *dev_id)
>  static void mtk_ovl_enable_vblank(struct mtk_ddp_comp *comp,
>  				  struct drm_crtc *crtc)
>  {
> -	struct mtk_disp_ovl *priv = container_of(comp, struct mtk_disp_ovl,
> -						 ddp_comp);
> +	struct mtk_disp_ovl *ovl = comp_to_ovl(comp);
>  
> -	priv->crtc = crtc;
> +	ovl->crtc = crtc;
>  	writel(0x0, comp->regs + DISP_REG_OVL_INTSTA);
>  	writel_relaxed(OVL_FME_CPL_INT, comp->regs + DISP_REG_OVL_INTEN);
>  }
>  
>  static void mtk_ovl_disable_vblank(struct mtk_ddp_comp *comp)
>  {
> -	struct mtk_disp_ovl *priv = container_of(comp, struct mtk_disp_ovl,
> -						 ddp_comp);
> +	struct mtk_disp_ovl *ovl = comp_to_ovl(comp);
>  
> -	priv->crtc = NULL;
> +	ovl->crtc = NULL;
>  	writel_relaxed(0x0, comp->regs + DISP_REG_OVL_INTEN);
>  }
>  
> diff --git a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
> index 0df05f9..21eff6f 100644
> --- a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
> +++ b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
> @@ -49,6 +49,11 @@ struct mtk_disp_rdma {
>  	struct drm_crtc			*crtc;
>  };
>  
> +static inline struct mtk_disp_rdma *comp_to_rdma(struct mtk_ddp_comp *comp)
> +{
> +	return container_of(comp, struct mtk_disp_rdma, ddp_comp);
> +}
> +
>  static irqreturn_t mtk_disp_rdma_irq_handler(int irq, void *dev_id)
>  {
>  	struct mtk_disp_rdma *priv = dev_id;
> @@ -77,20 +82,18 @@ static void rdma_update_bits(struct mtk_ddp_comp *comp, unsigned int reg,
>  static void mtk_rdma_enable_vblank(struct mtk_ddp_comp *comp,
>  				   struct drm_crtc *crtc)
>  {
> -	struct mtk_disp_rdma *priv = container_of(comp, struct mtk_disp_rdma,
> -						  ddp_comp);
> +	struct mtk_disp_rdma *rdma = comp_to_rdma(comp);
>  
> -	priv->crtc = crtc;
> +	rdma->crtc = crtc;
>  	rdma_update_bits(comp, DISP_REG_RDMA_INT_ENABLE, RDMA_FRAME_END_INT,
>  			 RDMA_FRAME_END_INT);
>  }
>  
>  static void mtk_rdma_disable_vblank(struct mtk_ddp_comp *comp)
>  {
> -	struct mtk_disp_rdma *priv = container_of(comp, struct mtk_disp_rdma,
> -						  ddp_comp);
> +	struct mtk_disp_rdma *rdma = comp_to_rdma(comp);
>  
> -	priv->crtc = NULL;
> +	rdma->crtc = NULL;
>  	rdma_update_bits(comp, DISP_REG_RDMA_INT_ENABLE, RDMA_FRAME_END_INT, 0);
>  }
>  

^ permalink raw reply

* [v2 2/3] ARM: dts: STM32 Add USB FS host mode support
From: Bruno Herrera @ 2017-01-16  2:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170116020958.62767-1-bruherrera@gmail.com>

This patch adds the USB pins and nodes for USB HS/FS cores working at FS speed,
using embedded PHY.

Signed-off-by: Bruno Herrera <bruherrera@gmail.com>
---
 arch/arm/boot/dts/stm32f429-disco.dts | 30 ++++++++++++++++++++++++++++++
 arch/arm/boot/dts/stm32f429.dtsi      | 35 ++++++++++++++++++++++++++++++++++-
 arch/arm/boot/dts/stm32f469-disco.dts | 30 ++++++++++++++++++++++++++++++
 3 files changed, 94 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/stm32f429-disco.dts b/arch/arm/boot/dts/stm32f429-disco.dts
index 7d0415e..374c5ed 100644
--- a/arch/arm/boot/dts/stm32f429-disco.dts
+++ b/arch/arm/boot/dts/stm32f429-disco.dts
@@ -88,6 +88,16 @@
 			gpios = <&gpioa 0 0>;
 		};
 	};
+
+	/* This turns on vbus for otg for host mode (dwc2) */
+	vcc5v_otg: vcc5v-otg-regulator {
+		compatible = "regulator-fixed";
+		gpio = <&gpioc 4 0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&usbotg_pwren_h>;
+		regulator-name = "vcc5_host1";
+		regulator-always-on;
+	};
 };
 
 &clk_hse {
@@ -99,3 +109,23 @@
 	pinctrl-names = "default";
 	status = "okay";
 };
+
+&usbotg_hs {
+	compatible = "st,stm32-fsotg", "snps,dwc2";
+	dr_mode = "host";
+	pinctrl-0 = <&usbotg_fs_pins_b>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&pinctrl {
+	usb-host {
+		usbotg_pwren_h: usbotg-pwren-h {
+			pins {
+				pinmux = <STM32F429_PC4_FUNC_GPIO>;
+				bias-disable;
+				drive-push-pull;
+			};
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
index e4dae0e..bc07aa8 100644
--- a/arch/arm/boot/dts/stm32f429.dtsi
+++ b/arch/arm/boot/dts/stm32f429.dtsi
@@ -206,7 +206,7 @@
 			reg = <0x40007000 0x400>;
 		};
 
-		pin-controller {
+		pinctrl: pin-controller {
 			#address-cells = <1>;
 			#size-cells = <1>;
 			compatible = "st,stm32f429-pinctrl";
@@ -316,6 +316,30 @@
 				};
 			};
 
+			usbotg_fs_pins_a: usbotg_fs at 0 {
+				pins {
+					pinmux = <STM32F429_PA10_FUNC_OTG_FS_ID>,
+						 <STM32F429_PA11_FUNC_OTG_FS_DM>,
+						 <STM32F429_PA12_FUNC_OTG_FS_DP>;
+					bias-disable;
+					drive-push-pull;
+					slew-rate = <2>;
+				};
+			};
+
+			usbotg_fs_pins_b: usbotg_fs at 1 {
+				pins {
+					pinmux = <STM32F429_PB12_FUNC_OTG_HS_ID>,
+						 <STM32F429_PB14_FUNC_OTG_HS_DM>,
+						 <STM32F429_PB15_FUNC_OTG_HS_DP>;
+					bias-disable;
+					drive-push-pull;
+					slew-rate = <2>;
+				};
+			};
+
+
+
 			usbotg_hs_pins_a: usbotg_hs at 0 {
 				pins {
 					pinmux = <STM32F429_PH4_FUNC_OTG_HS_ULPI_NXT>,
@@ -420,6 +444,15 @@
 			status = "disabled";
 		};
 
+		usbotg_fs: usb at 50000000 {
+			compatible = "st,stm32f4xx-fsotg", "snps,dwc2";
+			reg = <0x50000000 0x40000>;
+			interrupts = <67>;
+			clocks = <&rcc 0 39>;
+			clock-names = "otg";
+			status = "disabled";
+		};
+
 		rng: rng at 50060800 {
 			compatible = "st,stm32-rng";
 			reg = <0x50060800 0x400>;
diff --git a/arch/arm/boot/dts/stm32f469-disco.dts b/arch/arm/boot/dts/stm32f469-disco.dts
index 8877c00..8ae6763 100644
--- a/arch/arm/boot/dts/stm32f469-disco.dts
+++ b/arch/arm/boot/dts/stm32f469-disco.dts
@@ -68,6 +68,17 @@
 	soc {
 		dma-ranges = <0xc0000000 0x0 0x10000000>;
 	};
+
+	/* This turns on vbus for otg for host mode (dwc2) */
+	vcc5v_otg: vcc5v-otg-regulator {
+		compatible = "regulator-fixed";
+		enable-active-high;
+		gpio = <&gpiob 2 0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&usbotg_pwren_h>;
+		regulator-name = "vcc5_host1";
+		regulator-always-on;
+	};
 };
 
 &rcc {
@@ -81,3 +92,22 @@
 &usart3 {
 	status = "okay";
 };
+
+&usbotg_fs {
+	dr_mode = "host";
+	pinctrl-0 = <&usbotg_fs_pins_a>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&pinctrl {
+	usb-host {
+		usbotg_pwren_h: usbotg-pwren-h {
+			pins {
+				pinmux = <STM32F429_PB2_FUNC_GPIO>;
+				bias-disable;
+				drive-push-pull;
+			};
+		};
+	};
+};
-- 
2.10.1 (Apple Git-78)

^ permalink raw reply related

* [PATCH v4 5/5] ARM: dts: mt2701: add iommu/smi dtsi node for mt2701
From: Honghui Zhang @ 2017-01-16  2:48 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <5a45da57-9262-b1ff-1c6a-c5c211c1bfd4@gmail.com>

On Fri, 2017-01-13 at 15:54 +0100, Matthias Brugger wrote:
> 
> On 04/07/16 10:00, Matthias Brugger wrote:
> >
> >
> > On 04/07/16 03:32, Honghui Zhang wrote:
> >> On Sun, 2016-07-03 at 21:12 +0200, Matthias Brugger wrote:
> >>>
> >>> On 07/03/2016 08:24 AM, Matthias Brugger wrote:
> >>>>
> >>>>
> >>>> On 06/08/2016 11:51 AM, honghui.zhang at mediatek.com wrote:
> >>>>> From: Honghui Zhang <honghui.zhang@mediatek.com>
> >>>>>
> >>>>> Add the dtsi node of iommu and smi for mt2701.
> >>>>>
> >>>>> Signed-off-by: Honghui Zhang <honghui.zhang@mediatek.com>
> >>>>> ---
> >>>>>   arch/arm/boot/dts/mt2701.dtsi | 51
> >>>>> +++++++++++++++++++++++++++++++++++++++++++
> >>>>>   1 file changed, 51 insertions(+)
> >>>>>
> >>>>
> >>>> Applied,
> >>>
> >>> Please resend the patch including the infracfg and mmsys node.
> >>>
> >>
> >> Hi, Matthias,
> >>
> >> Please hold this one.
> >> This one is based on CCF "arm: dts: mt2701: Add clock controller device
> >> nodes"[1] and power domain patch "Mediatek MT2701 SCPSYS power domain
> >> support v7"[2],
> >> But these two patchset are still being reviewed now.
> >>
> >> Do you think it's better that I send this one later after ccf and power
> >> domain patch got merged? I will send this patch later if it's OK with
> >> you.
> >>
> >
> > Sounds good.
> 
> Applied now to v4.10-next/dts32
> 
> Thanks.
> 

Thanks.

> >
> > Thanks a lot,
> > Matthias
> >
> >> Thanks.
> >> [1] https://patchwork.kernel.org/patch/9109081
> >> [2]
> >> http://lists.infradead.org/pipermail/linux-mediatek/2016-May/005429.html
> >>

^ permalink raw reply

* [PATCH v2 2/6] arm: dts: mt2701: Add iommu/smi device node
From: Honghui Zhang @ 2017-01-16  2:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <02062506-f917-0140-4934-31d7d3317b80@gmail.com>

On Fri, 2017-01-13 at 16:05 +0100, Matthias Brugger wrote:
> Hi Erin,
> 
> I just took the patch from Honghui he send in june.
> Please see my comment inline.
> 
> On 13/01/17 09:42, Erin Lo wrote:
> > From: Honghui Zhang <honghui.zhang@mediatek.com>
> >
> > Add the device node of iommu and smi for MT2701.
> >
> > Signed-off-by: Honghui Zhang <honghui.zhang@mediatek.com>
> > Signed-off-by: Erin Lo <erin.lo@mediatek.com>
> > ---
> >  arch/arm/boot/dts/mt2701.dtsi | 54 +++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 54 insertions(+)
> >
> > diff --git a/arch/arm/boot/dts/mt2701.dtsi b/arch/arm/boot/dts/mt2701.dtsi
> > index eb4c6fd..87be52c 100644
> > --- a/arch/arm/boot/dts/mt2701.dtsi
> > +++ b/arch/arm/boot/dts/mt2701.dtsi
> > @@ -17,6 +17,7 @@
> >  #include <dt-bindings/interrupt-controller/irq.h>
> >  #include <dt-bindings/interrupt-controller/arm-gic.h>
> >  #include <dt-bindings/reset/mt2701-resets.h>
> > +#include <dt-bindings/memory/mt2701-larb-port.h>
> >  #include "skeleton64.dtsi"
> >  #include "mt2701-pinfunc.h"
> >
> > @@ -161,6 +162,16 @@
> >  		clock-names = "system-clk", "rtc-clk";
> >  	};
> >
> > +	smi_common: smi at 1000c000 {
> > +		compatible = "mediatek,mt2701-smi-common";
> > +		reg = <0 0x1000c000 0 0x1000>;
> > +		clocks = <&infracfg CLK_INFRA_SMI>,
> > +			 <&mmsys CLK_MM_SMI_COMMON>,
> > +			 <&infracfg CLK_INFRA_SMI>;
> > +		clock-names = "apb", "smi", "async";
> > +		power-domains = <&scpsys MT2701_POWER_DOMAIN_DISP>;
> > +	};
> > +
> >  	sysirq: interrupt-controller at 10200100 {
> >  		compatible = "mediatek,mt2701-sysirq",
> >  			     "mediatek,mt6577-sysirq";
> > @@ -170,6 +181,16 @@
> >  		reg = <0 0x10200100 0 0x1c>;
> >  	};
> >
> > +	iommu: mmsys_iommu at 10205000 {
> > +		compatible = "mediatek,mt2701-m4u";
> > +		reg = <0 0x10205000 0 0x1000>;
> > +		interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_LOW>;
> > +		clocks = <&infracfg CLK_INFRA_M4U>;
> > +		clock-names = "bclk";
> > +		mediatek,larbs = <&larb0 &larb1 &larb2>;
> > +		#iommu-cells = <1>;
> > +	};
> > +
> >  	apmixedsys: syscon at 10209000 {
> >  		compatible = "mediatek,mt2701-apmixedsys", "syscon";
> >  		reg = <0 0x10209000 0 0x1000>;
> > @@ -272,18 +293,51 @@
> >  		#clock-cells = <1>;
> >  	};
> >
> > +	larb0: larb at 14010000 {
> > +		compatible = "mediatek,mt2701-smi-larb";
> > +		reg = <0 0x14010000 0 0x1000>;
> > +		mediatek,smi = <&smi_common>;
> > +		mediatek,larbidx = <0>;
> 
> Did I miss something? 'mediatek,larbidx' does not sound familiar to me.
> 

Hi, Mathias,
	It's my mistake, we found a bug need this to fix in smi driver,
but I mix those patches together and make it un-clear.

	I will send new patch serial to add the 'mediatek,larbidx' later since
you have applied the last one.

thanks very much.

> Regards,
> Matthias
> 
> > +		clocks = <&mmsys CLK_MM_SMI_LARB0>,
> > +			 <&mmsys CLK_MM_SMI_LARB0>;
> > +		clock-names = "apb", "smi";
> > +		power-domains = <&scpsys MT2701_POWER_DOMAIN_DISP>;
> > +	};
> > +
> >  	imgsys: syscon at 15000000 {
> >  		compatible = "mediatek,mt2701-imgsys", "syscon";
> >  		reg = <0 0x15000000 0 0x1000>;
> >  		#clock-cells = <1>;
> >  	};
> >
> > +	larb2: larb at 15001000 {
> > +		compatible = "mediatek,mt2701-smi-larb";
> > +		reg = <0 0x15001000 0 0x1000>;
> > +		mediatek,smi = <&smi_common>;
> > +		mediatek,larbidx = <2>;
> > +		clocks = <&imgsys CLK_IMG_SMI_COMM>,
> > +			 <&imgsys CLK_IMG_SMI_COMM>;
> > +		clock-names = "apb", "smi";
> > +		power-domains = <&scpsys MT2701_POWER_DOMAIN_ISP>;
> > +	};
> > +
> >  	vdecsys: syscon at 16000000 {
> >  		compatible = "mediatek,mt2701-vdecsys", "syscon";
> >  		reg = <0 0x16000000 0 0x1000>;
> >  		#clock-cells = <1>;
> >  	};
> >
> > +	larb1: larb at 16010000 {
> > +		compatible = "mediatek,mt2701-smi-larb";
> > +		reg = <0 0x16010000 0 0x1000>;
> > +		mediatek,smi = <&smi_common>;
> > +		mediatek,larbidx = <1>;
> > +		clocks = <&vdecsys CLK_VDEC_CKGEN>,
> > +			 <&vdecsys CLK_VDEC_LARB>;
> > +		clock-names = "apb", "smi";
> > +		power-domains = <&scpsys MT2701_POWER_DOMAIN_VDEC>;
> > +	};
> > +
> >  	hifsys: syscon at 1a000000 {
> >  		compatible = "mediatek,mt2701-hifsys", "syscon";
> >  		reg = <0 0x1a000000 0 0x1000>;
> >

^ permalink raw reply

* [PATCH v2 6/6] arm: dts: mt2701: Add thermal device node.
From: Dawei Chien @ 2017-01-16  3:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <c8bbd4a4-2207-44f0-4462-3761c1d6c8a9@gmail.com>

On Fri, 2017-01-13 at 16:27 +0100, Matthias Brugger wrote:
> 
> On 13/01/17 09:42, Erin Lo wrote:
> > From: Dawei Chien <dawei.chien@mediatek.com>
> >
> > Add thermal controller device nodes for MT2701.
> >
> > Signed-off-by: Dawei Chien <dawei.chien@mediatek.com>
> > Signed-off-by: Erin Lo <erin.lo@mediatek.com>
> > ---
> >  arch/arm/boot/dts/mt2701.dtsi | 43 +++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 43 insertions(+)
> >
> > diff --git a/arch/arm/boot/dts/mt2701.dtsi b/arch/arm/boot/dts/mt2701.dtsi
> > index 3847f70..c43d5f8 100644
> > --- a/arch/arm/boot/dts/mt2701.dtsi
> > +++ b/arch/arm/boot/dts/mt2701.dtsi
> > @@ -89,6 +89,36 @@
> >  		clock-output-names = "rtc32k";
> >  	};
> >
> > +	thermal-zones {
> > +		cpu_thermal: cpu_thermal {
> > +			polling-delay-passive = <1000>; /* milliseconds */
> > +			polling-delay = <1000>; /* milliseconds */
> > +
> > +			thermal-sensors = <&thermal 0>;
> > +			sustainable-power = <1000>;
> > +
> > +			trips {
> > +				threshold: trip-point at 0 {
> > +					temperature = <68000>;
> > +					hysteresis = <2000>;
> > +					type = "passive";
> > +				};
> > +
> > +				target: trip-point at 1 {
> > +					temperature = <85000>;
> > +					hysteresis = <2000>;
> > +					type = "passive";
> > +				};
> > +
> > +				cpu_crit: cpu_crit at 0 {
> > +					temperature = <115000>;
> > +					hysteresis = <2000>;
> > +					type = "critical";
> > +				};
> > +			};
> > +		};
> > +	};
> > +
> >  	timer {
> >  		compatible = "arm,armv7-timer";
> >  		interrupt-parent = <&gic>;
> > @@ -270,6 +300,19 @@
> >  		status = "disabled";
> >  	};
> >
> > +	thermal: thermal at 1100b000 {
> > +		#thermal-sensor-cells = <0>;
> > +		compatible = "mediatek,mt2701-thermal";
> > +		reg = <0 0x1100b000 0 0x1000>;
> > +		interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_LOW>;
> > +		clocks = <&pericfg CLK_PERI_THERM>, <&pericfg CLK_PERI_AUXADC>;
> > +		clock-names = "therm", "auxadc";
> > +		resets = <&pericfg 0x10>;
> 
> should be MT2701_PERI_AUXADC_SW_RST, right?
> 
Thank you for your reminding, I didn't realize mt2701-resets.h upstream
already, I would update on next version, thank you.

resets = <&pericfg MT2701_PERI_AUXADC_SW_RST>;

> > +		reset-names = "therm";
> > +		mediatek,auxadc = <&auxadc>;
> > +		mediatek,apmixedsys = <&apmixedsys>;
> > +	};
> > +
> >  	nandc: nfi at 1100d000 {
> >  		compatible = "mediatek,mt2701-nfc";
> >  		reg = <0 0x1100d000 0 0x1000>;
> >

^ permalink raw reply

* [PATCH v6 23/25] usb: chipidea: Pullup D+ in device mode via phy APIs
From: Peter Chen @ 2017-01-16  3:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <148433778067.32719.6179204976256776867@sboyd-linaro>

On Fri, Jan 13, 2017 at 12:03:00PM -0800, Stephen Boyd wrote:
> Quoting Peter Chen (2017-01-12 19:35:36)
> > On Thu, Jan 12, 2017 at 02:49:51PM -0800, Stephen Boyd wrote:
> > > 
> > > With the boards I have, vbus is not routed to the phy. Instead, there's
> > > a vbus comparator on the PMIC where the vbus line from the usb
> > > receptacle is sent. The vbus extcon driver probes the comparator on the
> > > PMIC to see if vbus is present or not and then notifies extcon users
> > > when vbus changes.
> > > 
> > > The ULPI register we write in the phy is a vendor specific register
> > > (called MISC_A) that has two bits. If you look at
> > > qcom_usb_hs_phy_set_mode() in this series you'll see that we set
> > > VBUSVLDEXTSEL and VBUSVLDEXT. VBUSVLDEXTSEL controls a mux in the phy
> > > that chooses between an internal comparator, in the case where vbus goes
> > > to the phy, or an external signal input to the phy, VBUSVLDEXT, to
> > > consider as the "session valid" signal. It looks like the session valid
> > > signal drives the D+ pullup resistor in the phy. These bits in MISC_A
> > > don't matter when the phy is in host mode.
> > > 
> > > So when the board doesn't route vbus to the phy, we have to toggle the
> > > VBUSVLDEXT bit to signal to the phy that the vbus is there or not. I
> > > also see that we're not supposed to toggle the VBUSVLDEXTSEL bit when in
> > > "normal" operating mode. So perhaps we should do everything in the
> > > qcom_usb_hs_phy_set_mode() routine during the role switch as you
> > > suggest, except toggle the VBUSVLDEXT bit. Toggling the VBUSVLDEXT bit
> > > can be done via some new phy op when the extcon triggers?
> > 
> > Why not call phy_set_mode(phy, DEVICE) directly at ci_handle_vbus_change when
> > you get extcon vbus event?
> > 
> 
> Right, I can call phy_set_mode(phy, DEVICE) there, but is that correct?
> How do we signal vbus is gone, with phy_set_mode(phy, HOST)? Mode
> doesn't seem the same as "vbus status changed" so this feels wrong.


> So when the board doesn't route vbus to the phy, we have to toggle the
> VBUSVLDEXT bit to signal to the phy that the vbus is there or not. I
> also see that we're not supposed to toggle the VBUSVLDEXTSEL bit when in
> "normal" operating mode. So perhaps we should do everything in the
> qcom_usb_hs_phy_set_mode() routine during the role switch as you
> suggest, except toggle the VBUSVLDEXT bit. Toggling the VBUSVLDEXT bit
> can be done via some new phy op when the extcon triggers?

So, you need to call phy_set_mode when switching between host and device.
Besides, you also need to toggle VBUSVLDEXT when the external vbus
is on or off at device mode (doesn't need for host mode), is it correct?

At include/linux/usb/phy.h, we have .set_vbus interface, maybe you need
to port it to generic phy framework.

-- 

Best Regards,
Peter Chen

^ permalink raw reply

* [PATCH v2 6/6] arm: dts: mt2701: Add thermal device node.
From: Dawei Chien @ 2017-01-16  3:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1484538290.13258.3.camel@mtksdaap41>

On Mon, 2017-01-16 at 11:44 +0800, Dawei Chien wrote:
> On Fri, 2017-01-13 at 16:27 +0100, Matthias Brugger wrote:
> > 
> > On 13/01/17 09:42, Erin Lo wrote:
> > > From: Dawei Chien <dawei.chien@mediatek.com>
> > >
> > > Add thermal controller device nodes for MT2701.
> > >
> > > Signed-off-by: Dawei Chien <dawei.chien@mediatek.com>
> > > Signed-off-by: Erin Lo <erin.lo@mediatek.com>
> > > ---
> > >  arch/arm/boot/dts/mt2701.dtsi | 43 +++++++++++++++++++++++++++++++++++++++++++
> > >  1 file changed, 43 insertions(+)
> > >
> > > diff --git a/arch/arm/boot/dts/mt2701.dtsi b/arch/arm/boot/dts/mt2701.dtsi
> > > index 3847f70..c43d5f8 100644
> > > --- a/arch/arm/boot/dts/mt2701.dtsi
> > > +++ b/arch/arm/boot/dts/mt2701.dtsi
> > > @@ -89,6 +89,36 @@
> > >  		clock-output-names = "rtc32k";
> > >  	};
> > >
> > > +	thermal-zones {
> > > +		cpu_thermal: cpu_thermal {
> > > +			polling-delay-passive = <1000>; /* milliseconds */
> > > +			polling-delay = <1000>; /* milliseconds */
> > > +
> > > +			thermal-sensors = <&thermal 0>;
> > > +			sustainable-power = <1000>;
> > > +
> > > +			trips {
> > > +				threshold: trip-point at 0 {
> > > +					temperature = <68000>;
> > > +					hysteresis = <2000>;
> > > +					type = "passive";
> > > +				};
> > > +
> > > +				target: trip-point at 1 {
> > > +					temperature = <85000>;
> > > +					hysteresis = <2000>;
> > > +					type = "passive";
> > > +				};
> > > +
> > > +				cpu_crit: cpu_crit at 0 {
> > > +					temperature = <115000>;
> > > +					hysteresis = <2000>;
> > > +					type = "critical";
> > > +				};
> > > +			};
> > > +		};
> > > +	};
> > > +
> > >  	timer {
> > >  		compatible = "arm,armv7-timer";
> > >  		interrupt-parent = <&gic>;
> > > @@ -270,6 +300,19 @@
> > >  		status = "disabled";
> > >  	};
> > >
> > > +	thermal: thermal at 1100b000 {
> > > +		#thermal-sensor-cells = <0>;
> > > +		compatible = "mediatek,mt2701-thermal";
> > > +		reg = <0 0x1100b000 0 0x1000>;
> > > +		interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_LOW>;
> > > +		clocks = <&pericfg CLK_PERI_THERM>, <&pericfg CLK_PERI_AUXADC>;
> > > +		clock-names = "therm", "auxadc";
> > > +		resets = <&pericfg 0x10>;
> > 
> > should be MT2701_PERI_AUXADC_SW_RST, right?
> > 
> Thank you for your reminding, I didn't realize mt2701-resets.h upstream
> already, I would update on next version, thank you.
> 
> resets = <&pericfg MT2701_PERI_AUXADC_SW_RST>;

Actually, Should be MT2701_PERI_THERM_SW_RST.

resets = <&pericfg MT2701_PERI_THERM_SW_RST>;

> > > +		reset-names = "therm";
> > > +		mediatek,auxadc = <&auxadc>;
> > > +		mediatek,apmixedsys = <&apmixedsys>;
> > > +	};
> > > +
> > >  	nandc: nfi at 1100d000 {
> > >  		compatible = "mediatek,mt2701-nfc";
> > >  		reg = <0 0x1100d000 0 0x1000>;
> > >
> 

^ permalink raw reply

* [PATCH 2/4] clk: samsung: Remove Exynos4415 driver (SoC not supported anymore)
From: Chanwoo Choi @ 2017-01-16  3:55 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170114123642.15581-3-krzk@kernel.org>

Hi,

On 2017? 01? 14? 21:36, Krzysztof Kozlowski wrote:
> Support for Exynos4415 is going away because there are no internal nor
> external users.
> 
> Since commit 46dcf0ff0de3 ("ARM: dts: exynos: Remove exynos4415.dtsi"),
> the platform cannot be instantiated so remove also the drivers.
> 
> Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
> ---
>  .../devicetree/bindings/clock/exynos4415-clock.txt |   38 -
>  drivers/clk/samsung/Makefile                       |    1 -
>  drivers/clk/samsung/clk-exynos4415.c               | 1022 --------------------
>  include/dt-bindings/clock/exynos4415.h             |  360 -------
>  4 files changed, 1421 deletions(-)
>  delete mode 100644 Documentation/devicetree/bindings/clock/exynos4415-clock.txt
>  delete mode 100644 drivers/clk/samsung/clk-exynos4415.c
>  delete mode 100644 include/dt-bindings/clock/exynos4415.h

Reviewed-by: Chanwoo Choi <cw00.choi@samsung.com>

[snip]

-- 
Best Regards,
Chanwoo Choi
S/W Center, Samsung Electronics

^ permalink raw reply

* [PATCH 3/4] pinctrl: samsung: Remove support for Exynos4415 (SoC not supported anymore)
From: Chanwoo Choi @ 2017-01-16  3:56 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170114123642.15581-4-krzk@kernel.org>

On 2017? 01? 14? 21:36, Krzysztof Kozlowski wrote:
> Support for Exynos4415 is going away because there are no internal nor
> external users.
> 
> Since commit 46dcf0ff0de3 ("ARM: dts: exynos: Remove exynos4415.dtsi"),
> the platform cannot be instantiated so remove also the drivers.
> 
> Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
> ---
>  drivers/pinctrl/samsung/pinctrl-exynos.c  | 75 -------------------------------
>  drivers/pinctrl/samsung/pinctrl-samsung.c |  2 -
>  drivers/pinctrl/samsung/pinctrl-samsung.h |  1 -
>  3 files changed, 78 deletions(-)

Reviewed-by: Chanwoo Choi <cw00.choi@samsung.com>

[snip]

-- 
Best Regards,
Chanwoo Choi
S/W Center, Samsung Electronics

^ permalink raw reply

* [PATCH 1/4] ARM: EXYNOS: Remove Exynos4415 driver (SoC not supported anymore)
From: Chanwoo Choi @ 2017-01-16  3:56 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170114123642.15581-2-krzk@kernel.org>

On 2017? 01? 14? 21:36, Krzysztof Kozlowski wrote:
> Support for Exynos4415 is going away because there are no internal nor
> external users.
> 
> Since commit 46dcf0ff0de3 ("ARM: dts: exynos: Remove exynos4415.dtsi"),
> the platform cannot be instantiated so remove also the mach code.
> 
> Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
> ---
>  arch/arm/mach-exynos/Kconfig   | 5 -----
>  arch/arm/mach-exynos/exynos.c  | 1 -
>  arch/arm/mach-exynos/suspend.c | 1 -
>  3 files changed, 7 deletions(-)

Reviewed-by: Chanwoo Choi <cw00.choi@samsung.com>

[snip]

-- 
Best Regards,
Chanwoo Choi
S/W Center, Samsung Electronics

^ permalink raw reply

* [PATCH v1 1/3] dt: bindings: add documentation for zx2967 family watchdog controller
From: Baoyou Xie @ 2017-01-16  4:19 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds dt-binding documentation for zx2967 family
watchdog controller.

Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
---
 .../bindings/watchdog/zte,zx2967-wdt.txt           | 29 ++++++++++++++++++++++
 1 file changed, 29 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/watchdog/zte,zx2967-wdt.txt

diff --git a/Documentation/devicetree/bindings/watchdog/zte,zx2967-wdt.txt b/Documentation/devicetree/bindings/watchdog/zte,zx2967-wdt.txt
new file mode 100644
index 0000000..0fe0d40
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/zte,zx2967-wdt.txt
@@ -0,0 +1,29 @@
+ZTE zx2967 Watchdog timer
+
+Required properties:
+
+- compatible : should be one of the following.
+       * zte,zx296718-wdt
+- reg : Specifies base physical address and size of the registers.
+- clocks : Pairs of phandle and specifier referencing the controller's clocks.
+- clock-names: "wdtclk" for the watchdog clock.
+- resets : Reference to the reset controller controlling the watchdog
+           controller.
+- reset-names : Must include the following entries:
+       * wdtrst
+
+Optional properties:
+
+- reset-mask-config : Mask and configuare value that be wrote to aon-sysctrl.
+
+Example:
+
+wdt_ares: watchdog at 1465000 {
+	compatible = "zte,zx296718-wdt";
+	reg = <0x1465000 0x1000>;
+	clocks = <&topcrm WDT_WCLK>;
+	clock-names = "wdtclk";
+	resets = <&toprst 35>;
+	reset-names = "wdtrst";
+	reset-mask-config = <1 0x115>;
+};
-- 
2.7.4

^ permalink raw reply related

* [PATCH v1 2/3] MAINTAINERS: add zx2967 watchdog controller driver to ARM ZTE architecture
From: Baoyou Xie @ 2017-01-16  4:19 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1484540395-3335-1-git-send-email-baoyou.xie@linaro.org>

Add the zx2967 watchdog controller driver as maintained by ARM ZTE
architecture maintainers, as they're parts of the core IP.

Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
---
 MAINTAINERS | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 08f8155..77f0290 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1983,11 +1983,13 @@ F:	drivers/clk/zte/
 F:	drivers/reset/reset-zx2967.c
 F:	drivers/soc/zte/
 F:	drivers/thermal/zx*
+F:	drivers/watchdog/zx2967_wdt.c
 F:	Documentation/devicetree/bindings/arm/zte.txt
 F:	Documentation/devicetree/bindings/clock/zx296702-clk.txt
 F:	Documentation/devicetree/bindings/reset/zte,zx2967-reset.txt
 F:	Documentation/devicetree/bindings/soc/zte/
 F:	Documentation/devicetree/bindings/thermal/zx*
+F:	Documentation/devicetree/bindings/watchdog/zte,zx2967-wdt.txt
 F:	include/dt-bindings/soc/zx*.h
 
 ARM/ZYNQ ARCHITECTURE
-- 
2.7.4

^ permalink raw reply related

* [PATCH v1 3/3] watchdog: zx2967: add watchdog controller driver for ZTE's zx2967 family
From: Baoyou Xie @ 2017-01-16  4:19 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1484540395-3335-1-git-send-email-baoyou.xie@linaro.org>

This patch adds watchdog controller driver for ZTE's zx2967 family.

Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
---
 drivers/watchdog/Kconfig      |  10 ++
 drivers/watchdog/Makefile     |   1 +
 drivers/watchdog/zx2967_wdt.c | 405 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 416 insertions(+)
 create mode 100644 drivers/watchdog/zx2967_wdt.c

diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 3eb58cb..79027da 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -714,6 +714,16 @@ config ASPEED_WATCHDOG
 	  To compile this driver as a module, choose M here: the
 	  module will be called aspeed_wdt.
 
+config ZX2967_WATCHDOG
+	tristate "ZTE zx2967 SoCs watchdog support"
+	depends on ARCH_ZX
+	select WATCHDOG_CORE
+	help
+	  Say Y here to include support for the watchdog timer
+	  in ZTE zx2967 SoCs.
+	  To compile this driver as a module, choose M here: the
+	  module will be called zx2967_wdt.
+
 # AVR32 Architecture
 
 config AT32AP700X_WDT
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index caa9f4a..ea08925 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -82,6 +82,7 @@ obj-$(CONFIG_BCM7038_WDT) += bcm7038_wdt.o
 obj-$(CONFIG_ATLAS7_WATCHDOG) += atlas7_wdt.o
 obj-$(CONFIG_RENESAS_WDT) += renesas_wdt.o
 obj-$(CONFIG_ASPEED_WATCHDOG) += aspeed_wdt.o
+obj-$(CONFIG_ZX2967_WATCHDOG) += zx2967_wdt.o
 
 # AVR32 Architecture
 obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
diff --git a/drivers/watchdog/zx2967_wdt.c b/drivers/watchdog/zx2967_wdt.c
new file mode 100644
index 0000000..8791dd2
--- /dev/null
+++ b/drivers/watchdog/zx2967_wdt.c
@@ -0,0 +1,405 @@
+/*
+ * watchdog driver for ZTE's zx2967 family
+ *
+ * Copyright (C) 2017 ZTE Ltd.
+ *
+ * Author: Baoyou Xie <baoyou.xie@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <linux/reset.h>
+#include <linux/watchdog.h>
+
+#define ZX2967_WDT_CFG_REG			0x4
+#define ZX2967_WDT_LOAD_REG			0x8
+#define ZX2967_WDT_REFRESH_REG			0x18
+#define ZX2967_WDT_START_REG			0x1c
+
+#define ZX2967_WDT_REFRESH_MASK			0x3f
+
+#define ZX2967_WDT_CFG_DIV(n)			((((n)&0xff) - 1) << 8)
+#define ZX2967_WDT_START_EN			0x1
+
+#define ZX2967_WDT_WRITEKEY			0x12340000
+
+#define ZX2967_WDT_DIV_DEFAULT			16
+#define ZX2967_WDT_DEFAULT_TIMEOUT		32
+#define ZX2967_WDT_MIN_TIMEOUT			1
+#define ZX2967_WDT_MAX_TIMEOUT			500
+#define ZX2967_WDT_MAX_COUNT			0xffff
+
+#define ZX2967_WDT_FLAG_REBOOT_MON		(1 << 0)
+
+#define ZX2967_RESET_MASK_REG			0xb0
+
+#define zx2967_wdt_write_reg(v, r) \
+			writel((v) | ZX2967_WDT_WRITEKEY, r)
+#define zx2967_wdt_read_reg(r)			readl(r)
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+static unsigned int timeout = ZX2967_WDT_DEFAULT_TIMEOUT;
+
+struct zx2967_wdt {
+	struct device		*dev;
+	struct clk		*clock;
+	void __iomem		*reg_base;
+	unsigned int		conf;
+	unsigned int		load;
+	unsigned int		flags;
+	spinlock_t		lock;
+	struct watchdog_device	wdt_device;
+	struct notifier_block	restart_handler;
+	struct notifier_block	reboot_handler;
+};
+
+static void zx2967_wdt_refresh(struct zx2967_wdt *wdt)
+{
+	unsigned int val;
+
+	spin_lock(&wdt->lock);
+
+	val = zx2967_wdt_read_reg(wdt->reg_base + ZX2967_WDT_REFRESH_REG);
+	val ^= ZX2967_WDT_REFRESH_MASK;
+	zx2967_wdt_write_reg(val, wdt->reg_base + ZX2967_WDT_REFRESH_REG);
+
+	spin_unlock(&wdt->lock);
+}
+
+static void __zx2967_wdt_stop(struct zx2967_wdt *wdt)
+{
+	unsigned int val;
+
+	spin_lock(&wdt->lock);
+
+	val = zx2967_wdt_read_reg(wdt->reg_base + ZX2967_WDT_START_REG);
+	val &= ~(ZX2967_WDT_START_EN);
+	zx2967_wdt_write_reg(val, wdt->reg_base + ZX2967_WDT_START_REG);
+
+	spin_unlock(&wdt->lock);
+}
+
+static void __zx2967_wdt_start(struct zx2967_wdt *wdt)
+{
+	unsigned int val;
+
+	spin_lock(&wdt->lock);
+
+	val = zx2967_wdt_read_reg(wdt->reg_base + ZX2967_WDT_START_REG);
+	val |= ZX2967_WDT_START_EN;
+	zx2967_wdt_write_reg(val, wdt->reg_base + ZX2967_WDT_START_REG);
+
+	spin_unlock(&wdt->lock);
+}
+
+static unsigned int
+__zx2967_wdt_set_timeout(struct zx2967_wdt *wdt, unsigned int timeout)
+{
+	unsigned int freq = clk_get_rate(wdt->clock);
+	unsigned int divisor = ZX2967_WDT_DIV_DEFAULT, count;
+
+	count = timeout * freq;
+	if (count > divisor * ZX2967_WDT_MAX_COUNT)
+		divisor = DIV_ROUND_UP(count, ZX2967_WDT_MAX_COUNT);
+	count = DIV_ROUND_UP(count, divisor);
+	zx2967_wdt_write_reg(ZX2967_WDT_CFG_DIV(divisor),
+			     wdt->reg_base + ZX2967_WDT_CFG_REG);
+	zx2967_wdt_write_reg(count, wdt->reg_base + ZX2967_WDT_LOAD_REG);
+	zx2967_wdt_refresh(wdt);
+
+	wdt->load = count;
+	dev_info(wdt->dev, "count=%d, timeout=%d, divisor=%d\n",
+		 count, timeout, divisor);
+
+	return (count * divisor) / freq;
+}
+
+static int zx2967_wdt_set_timeout(struct watchdog_device *wdd,
+				  unsigned int timeout)
+{
+	struct zx2967_wdt *wdt = watchdog_get_drvdata(wdd);
+
+	if (watchdog_timeout_invalid(&wdt->wdt_device, timeout)) {
+		dev_err(wdt->dev, "timeout %d is invalid\n", timeout);
+
+		return -EINVAL;
+	}
+
+	wdd->timeout = __zx2967_wdt_set_timeout(wdt, timeout);
+
+	return 0;
+}
+
+static int zx2967_wdt_start(struct watchdog_device *wdd)
+{
+	struct zx2967_wdt *wdt = watchdog_get_drvdata(wdd);
+
+	__zx2967_wdt_stop(wdt);
+	zx2967_wdt_set_timeout(wdd, wdd->timeout);
+	__zx2967_wdt_start(wdt);
+
+	return 0;
+}
+
+static int zx2967_wdt_stop(struct watchdog_device *wdd)
+{
+	struct zx2967_wdt *wdt = watchdog_get_drvdata(wdd);
+
+	__zx2967_wdt_stop(wdt);
+
+	return 0;
+}
+
+static int zx2967_wdt_keepalive(struct watchdog_device *wdd)
+{
+	struct zx2967_wdt *wdt = watchdog_get_drvdata(wdd);
+
+	zx2967_wdt_refresh(wdt);
+
+	return 0;
+}
+
+#define ZX2967_WDT_OPTIONS \
+	(WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE)
+static const struct watchdog_info zx2967_wdt_ident = {
+	.options          =     ZX2967_WDT_OPTIONS,
+	.firmware_version =	0,
+	.identity         =	"zx2967 watchdog",
+};
+
+static struct watchdog_ops zx2967_wdt_ops = {
+	.owner = THIS_MODULE,
+	.start = zx2967_wdt_start,
+	.stop = zx2967_wdt_stop,
+	.ping = zx2967_wdt_keepalive,
+	.set_timeout = zx2967_wdt_set_timeout,
+};
+
+static void zx2967_wdt_fix_sysdown(struct zx2967_wdt *wdt)
+{
+	__zx2967_wdt_stop(wdt);
+	__zx2967_wdt_set_timeout(wdt, 15);
+	__zx2967_wdt_start(wdt);
+}
+
+static int zx2967_wdt_notify_sys(struct notifier_block *this,
+			     unsigned long code, void *unused)
+{
+	struct zx2967_wdt *wdt = container_of(this, struct zx2967_wdt,
+					      reboot_handler);
+
+	wdt->flags |= ZX2967_WDT_FLAG_REBOOT_MON;
+	switch (code) {
+	case SYS_HALT:
+	case SYS_POWER_OFF:
+	case SYS_RESTART:
+		zx2967_wdt_fix_sysdown(wdt);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int zx2967_wdt_restart(struct notifier_block *this,
+			      unsigned long mode, void *cmd)
+{
+	struct zx2967_wdt *wdt;
+
+	wdt = container_of(this, struct zx2967_wdt, restart_handler);
+
+	zx2967_wdt_stop(&wdt->wdt_device);
+
+	zx2967_wdt_write_reg(0x80, wdt->reg_base + ZX2967_WDT_LOAD_REG);
+	zx2967_wdt_refresh(wdt);
+	zx2967_wdt_write_reg(ZX2967_WDT_START_EN,
+			     wdt->reg_base + ZX2967_WDT_START_REG);
+
+	zx2967_wdt_start(&wdt->wdt_device);
+	/* wait for reset*/
+	mdelay(500);
+
+	return NOTIFY_DONE;
+}
+
+static void zx2967_reset_mask_config(struct device *dev)
+{
+	struct device_node *np = NULL;
+	void __iomem *reg;
+	unsigned int  val, mask, config, size;
+	const unsigned int *prop;
+
+	prop = of_get_property(dev->of_node, "reset-mask-config", &size);
+	if (size < (sizeof(*prop) * 2)) {
+		dev_err(dev, "bad data for reset-mask-config");
+		return;
+	}
+	config = be32_to_cpup(prop++);
+	mask = be32_to_cpup(prop);
+	np = of_find_compatible_node(NULL, NULL, "zte,aon-sysctrl");
+	if (!np) {
+		dev_err(dev, "Cannot found pcu device node\n");
+		return;
+	}
+	reg = of_iomap(np, 0) + ZX2967_RESET_MASK_REG;
+	of_node_put(np);
+
+	val = readl(reg);
+	val &= ~mask;
+	val |= config;
+	writel(val, reg);
+}
+
+static int zx2967_wdt_probe(struct platform_device *pdev)
+{
+	struct device *dev;
+	struct zx2967_wdt *wdt;
+	struct resource *base;
+	int err, ret = 0;
+	unsigned int rate, val;
+
+	struct reset_control *rstc;
+
+	dev = &pdev->dev;
+
+	wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
+	if (!wdt) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	platform_set_drvdata(pdev, wdt);
+
+	wdt->dev = dev;
+	spin_lock_init(&wdt->lock);
+
+	wdt->wdt_device.info = &zx2967_wdt_ident;
+	wdt->wdt_device.ops = &zx2967_wdt_ops;
+	wdt->wdt_device.timeout = ZX2967_WDT_DEFAULT_TIMEOUT;
+	wdt->wdt_device.max_timeout = ZX2967_WDT_MAX_TIMEOUT;
+	wdt->wdt_device.min_timeout = ZX2967_WDT_MIN_TIMEOUT;
+	wdt->wdt_device.parent = &pdev->dev;
+
+	base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	wdt->reg_base = devm_ioremap_resource(dev, base);
+
+	if (of_find_property(dev->of_node, "reset-mask-config", NULL))
+		zx2967_reset_mask_config(dev);
+
+	wdt->reboot_handler.notifier_call = zx2967_wdt_notify_sys;
+	ret = register_reboot_notifier(&wdt->reboot_handler);
+	wdt->clock = devm_clk_get(dev, "wdtclk");
+	if (IS_ERR(wdt->clock)) {
+		dev_err(dev, "failed to find watchdog clock source\n");
+		ret = PTR_ERR(wdt->clock);
+		goto out;
+	}
+	ret = clk_prepare_enable(wdt->clock);
+	if (ret < 0) {
+		dev_err(dev, "failed to enable clock\n");
+		goto out;
+	}
+
+	rate = clk_get_rate(wdt->clock);
+	if (rate == 24000000)
+		ret = clk_set_rate(wdt->clock, 32768);
+	rate = clk_get_rate(wdt->clock);
+
+	rstc = devm_reset_control_get(dev, "wdtrst");
+	if (!rstc) {
+		dev_info(dev, "rstc get failed");
+	} else {
+		reset_control_assert(rstc);
+		mdelay(10);
+		reset_control_deassert(rstc);
+	}
+
+	watchdog_set_drvdata(&wdt->wdt_device, wdt);
+
+	watchdog_init_timeout(&wdt->wdt_device, timeout, &pdev->dev);
+	watchdog_set_nowayout(&wdt->wdt_device, nowayout);
+
+	zx2967_wdt_stop(&wdt->wdt_device);
+
+	err = watchdog_register_device(&wdt->wdt_device);
+	if (unlikely(err)) {
+		ret = err;
+		goto fail_register;
+	}
+
+	wdt->restart_handler.notifier_call = zx2967_wdt_restart;
+	wdt->restart_handler.priority = 128;
+	ret = register_restart_handler(&wdt->restart_handler);
+	if (ret) {
+		pr_err("cannot register restart handler, %d\n", ret);
+		goto fail_restart;
+	}
+
+	val = zx2967_wdt_read_reg(wdt->reg_base + ZX2967_WDT_START_REG);
+	dev_info(&pdev->dev, "watchdog enabled (timeout=%d sec, nowayout=%d)",
+		 wdt->wdt_device.timeout, nowayout);
+
+	return 0;
+
+fail_restart:
+	watchdog_unregister_device(&wdt->wdt_device);
+fail_register:
+	clk_disable_unprepare(wdt->clock);
+out:
+	return ret;
+}
+
+static int zx2967_wdt_remove(struct platform_device *pdev)
+{
+	struct zx2967_wdt *wdt = platform_get_drvdata(pdev);
+
+	unregister_restart_handler(&wdt->restart_handler);
+	watchdog_unregister_device(&wdt->wdt_device);
+	clk_disable_unprepare(wdt->clock);
+
+	return 0;
+}
+
+static void zx2967_wdt_shutdown(struct platform_device *pdev)
+{
+	struct zx2967_wdt *wdt = platform_get_drvdata(pdev);
+
+	if (!(wdt->flags & ZX2967_WDT_FLAG_REBOOT_MON))
+		zx2967_wdt_stop(&wdt->wdt_device);
+}
+
+static const struct of_device_id zx2967_wdt_match[] = {
+	{ .compatible = "zte,zx296718-wdt", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, zx2967_wdt_match);
+
+static const struct platform_device_id zx2967_wdt_ids[] = {
+	{ .name = "zx2967-wdt", },
+	{}
+};
+MODULE_DEVICE_TABLE(platform, zx2967_wdt_ids);
+
+static struct platform_driver zx2967_wdt_driver = {
+	.probe		= zx2967_wdt_probe,
+	.remove		= zx2967_wdt_remove,
+	.shutdown	= zx2967_wdt_shutdown,
+	.id_table	= zx2967_wdt_ids,
+	.driver		= {
+		.name	= "zx2967-wdt",
+		.of_match_table	= of_match_ptr(zx2967_wdt_match),
+	},
+};
+module_platform_driver(zx2967_wdt_driver);
+
+MODULE_AUTHOR("Baoyou Xie <baoyou.xie@linaro.org>");
+MODULE_DESCRIPTION("ZTE zx2967 Watchdog Device Driver");
+MODULE_LICENSE("GPL");
-- 
2.7.4

^ permalink raw reply related

* [PATCH 4/4] clk: rockchip: add rk3288 cif_out clock
From: Jacob Chen @ 2017-01-16  4:59 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <2707876.A5Xp7pLXJo@phil>

2017-01-13 21:53 GMT+08:00 Heiko Stuebner <heiko@sntech.de>:
> Hi Jacob,
>
> Am Dienstag, 10. Januar 2017, 19:59:20 CET schrieb Jacob Chen:
>> Add the clocks for the cif block of the rk3288
>>
>> Signed-off-by: Jacob Chen <jacob-chen@iotwrt.com>
>> ---
>>  drivers/clk/rockchip/clk-rk3288.c | 7 +++++++
>>  1 file changed, 7 insertions(+)
>>
>> diff --git a/drivers/clk/rockchip/clk-rk3288.c
>> b/drivers/clk/rockchip/clk-rk3288.c index 8047cea..f071c24 100644
>> --- a/drivers/clk/rockchip/clk-rk3288.c
>> +++ b/drivers/clk/rockchip/clk-rk3288.c
>> @@ -192,6 +192,7 @@ PNAME(mux_uart1_p)        = { "uart1_src", "uart1_frac",
>> "xin24m" }; PNAME(mux_uart2_p)        = { "uart2_src", "uart2_frac", "xin24m" };
>>  PNAME(mux_uart3_p)   = { "uart3_src", "uart3_frac", "xin24m" };
>>  PNAME(mux_uart4_p)   = { "uart4_src", "uart4_frac", "xin24m" };
>> +PNAME(mux_cif_out_p) = { "cif_src", "xin24m" };
>>  PNAME(mux_vip_out_p) = { "vip_src", "xin24m" };
>>  PNAME(mux_mac_p)     = { "mac_pll_src", "ext_gmac" };
>>  PNAME(mux_hsadcout_p)        = { "hsadc_src", "ext_hsadc" };
>> @@ -448,6 +449,12 @@ static struct rockchip_clk_branch rk3288_clk_branches[]
>> __initdata = { RK3288_CLKSEL_CON(6), 14, 2, MFLAGS, 8, 6, DFLAGS,
>>                       RK3288_CLKGATE_CON(3), 15, GFLAGS),
>>
>> +     COMPOSITE_NOGATE(0, "cif_src", mux_pll_src_cpll_gpll_p, 0,
>> +                     RK3288_CLKSEL_CON(26), 8, 1, MFLAGS, 9, 5, DFLAGS),
>> +     COMPOSITE_NODIV(SCLK_CIF_OUT, "sclk_cif_out", mux_cif_out_p, 0,
>> +                     RK3288_CLKSEL_CON(26), 15, 1, MFLAGS,
>> +                     RK3288_CLKGATE_CON(3), 7, GFLAGS),
>> +
>
> we already have vip_src and sclk_vip_out defined, which I guess are the clocks
> you are adding here and according to the TRM I have the names are also correct
> (clock diagram 2).
>
> But the clkid is not set yet, so I'd suggest adding SCLK_VIP_OUT and assigning
> to the existing clocks.
>
> Also, according to the clock diagram, the gate needs to be (and already is)
> part of the vip_src clock and not the sclk_vip_out.
>
>
> Heiko

Right, I didn't find that it have already been defined..

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox