diff --git a/arch/arm64/boot/dts/nexell/Makefile b/arch/arm64/boot/dts/nexell/Makefile
index 46364d6a..7f4dcadb 100644
--- a/arch/arm64/boot/dts/nexell/Makefile
+++ b/arch/arm64/boot/dts/nexell/Makefile
@@ -1,4 +1,5 @@
 dtb-$(CONFIG_ARCH_S5P6818) += s5p6818-nanopi-m3.dtb
+dtb-$(CONFIG_ARCH_S5P6818) += s5p6818-nanopi-fire3.dtb
 
 always		:= $(dtb-y)
 subdir-y	:= $(dts-dirs)
diff --git a/arch/arm64/boot/dts/nexell/s5p6818-nanopi-fire3.dts b/arch/arm64/boot/dts/nexell/s5p6818-nanopi-fire3.dts
new file mode 100644
index 00000000..25ac71dd
--- /dev/null
+++ b/arch/arm64/boot/dts/nexell/s5p6818-nanopi-fire3.dts
@@ -0,0 +1,837 @@
+/*
+ * Copyright (C) 2016  Nexell Co., Ltd.
+ * Author: Youngbok, Park <ybpark@nexell.co.kr>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/dts-v1/;
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/thermal/thermal.h>
+#include <dt-bindings/input/input.h>
+#include "s5p6818.dtsi"
+
+#define PMIC_PDATA_INIT(_id, _rname, _minuv,	\
+			_maxuv, _always_on, _boot_on,		\
+			_init_uv, _init_enable, _slp_slots)	\
+		regulator-name = _rname;		\
+		regulator-min-microvolt = <_minuv>;	\
+		regulator-max-microvolt = <_maxuv>;	\
+		nx,id = <_id>;				\
+		nx,always_on = <_always_on>;		\
+		nx,boot_on = <_boot_on>;		\
+		nx,init_enable = <_init_enable>;	\
+		nx,init_uV = <_init_uv>;		\
+		nx,sleep_slots = <_slp_slots>;
+
+/ {
+	memory {
+		/* Note: Samsung Artik u-boot fixates memory information to values
+		 * specified by CONFIG_SYS_SDRAM_BASE and CONFIG_SYS_SDRAM_SIZE in
+		 * the u-boot configuration. Values specified below are meaningless.
+		 */
+		device_type = "memory";
+		reg = <0x40000000 0x40000000>;
+	};
+
+	aliases {
+		ethernet0 = &gmac0;
+	};
+
+	nx-v4l2 {
+		status = "okay";
+	};
+
+	soc {
+		#include "s5p6818-pinctrl.dtsi"
+
+		clocks {
+			uart0:uart@c00a9000 { clock-frequency = <147500000>; };
+			uart1:uart@c00a8000 { clock-frequency = <147500000>; };
+			uart2:uart@c00aa000 { clock-frequency = <147500000>; };
+			uart3:uart@c00ab000 { clock-frequency = <147500000>; };
+			uart4:uart@c006e000 { clock-frequency = <147500000>; };
+			uart5:uart@c0084000 { clock-frequency = <147500000>; };
+			pwm0:pwm0@c00ba000 { clock-frequency = <100000000>; };
+			i2c0:i2c@c00ae000  { clock-frequency = <200000000>; };
+			i2c1:i2c@c00af000  { clock-frequency = <200000000>; };
+			i2c2:i2c@c00b0000  { clock-frequency = <200000000>; };
+			vip1:vip@c00c2000 { src-force = <4>; };
+		};
+
+		serial0:serial@c00a1000 {
+			status ="okay";
+		};
+
+		serial1:serial@c00a0000 {
+			status ="okay";
+			pinctrl-names = "default";
+			pinctrl-0 = <&serial1_pin &serial1_flow>;
+		};
+
+		amba {
+			pl08xdma0:pl08xdma@c0000000 {
+				use_isr;
+
+				ch12 {
+					slave_wait_flush_dma;
+				};
+
+				ch13 {
+					slave_wait_flush_dma;
+				};
+
+				ch14 {
+					slave_wait_flush_dma;
+				};
+
+				ch15 {
+					slave_wait_flush_dma;
+				};
+			};
+
+			pl08xdma1:pl08xdma@c0001000 {
+				use_isr;
+
+				ch0 {
+					slave_wait_flush_dma;
+				};
+
+				ch1 {
+					slave_wait_flush_dma;
+				};
+			};
+		};
+
+		dw_mmc_0:dw_mmc@c0062000 {			// mappings from kernel 3.x:
+			bus-width = <4>;				// MMC_CAP_4_BIT_DATA
+			cap-sd-highspeed;				// DW_MCI_QUIRK_HIGHSPEED
+			cap-mmc-highspeed;				// also DW_MCI_QUIRK_HIGHSPEED
+			clock-frequency = <100000000>;	// bus_hz: 100 * 1000 * 1000
+			card-detect-delay = <200>;		// detect_delay_ms
+			disable-wp;						// write protect: -> get_ro; feature not available for micro SD
+			cd-gpios = <&alive_0 1 GPIO_ACTIVE_LOW>; // card detect: CFG_SDMMC0_DETECT_IO == PAD_GPIO_ALV + 1
+			nexell,drive_dly = <0x0>;		// DW_MMC_DRIVE_DELAY(0)
+			nexell,drive_shift = <0x02>;	// DW_MMC_DRIVE_PHASE(2)
+			nexell,sample_dly = <0x00>;		// DW_MMC_SAMPLE_DELAY(0)
+			nexell,sample_shift = <0x01>;	// DW_MMC_SAMPLE_PHASE(1)
+			status = "okay";
+		};
+
+		dw_mmc_1:dw_mmc@c0068000 {
+			bus-width = <4>;
+			cap-sd-highspeed;
+			clock-frequency = <100000000>;
+			card-detect-delay = <200>;
+			non-removable;
+            keep-power-in-suspend;
+			nexell,drive_dly = <0x0>;
+			nexell,drive_shift = <0x02>;
+			nexell,sample_dly = <0x00>;
+			nexell,sample_shift = <0x01>;
+			mmc-pwrseq = <&wifi_powerseq>;
+			status = "okay";
+
+			/* wifi definition for brcmfmac.ko module */
+            brcmf: bcrmf@1 {
+                compatible = "brcm,bcm4329-fmac";
+                reg = <1>;
+				interrupt-parent = <&gpio_c>;
+				interrupts = <17 IRQ_TYPE_LEVEL_HIGH>;
+				brcm,powersave-default-off;
+            };
+		};
+
+		dw_mmc_2:dw_mmc@c0069000 {
+			bus-width = <4>;				// MMC_CAP_4_BIT_DATA
+			cap-sd-highspeed;				// DW_MCI_QUIRK_HIGHSPEED
+			cap-mmc-highspeed;				// also DW_MCI_QUIRK_HIGHSPEED
+			sd-uhs-ddr50;					// MMC_CAP_UHS_DDR50
+			cap-mmc-hw-reset;				// MMC_CAP_HW_RESET
+			clock-frequency = <200000000>;	// bus_hz: 200 * 1000 * 1000
+			card-detect-delay = <200>;		// detect_delay_ms
+			non-removable;					// MMC_CAP_NONREMOVABLE
+			broken-cd;
+			cd-gpios = <&gpio_c 24 GPIO_ACTIVE_LOW>; // card detect: CFG_SDMMC2_DETECT_IO == PAD_GPIO_C + 24
+			nexell,drive_dly = <0x0>;		// DW_MMC_DRIVE_DELAY(0)
+			nexell,drive_shift = <0x03>;	// DW_MMC_DRIVE_PHASE(3)
+			nexell,sample_dly = <0x00>;		// DW_MMC_SAMPLE_DELAY(0)
+			nexell,sample_shift = <0x02>;	// DW_MMC_SAMPLE_PHASE(2)
+			status = "okay";
+		};
+
+		dvfs:dynamic-freq@bb000 {
+			supply_name = "vdd_arm_spu";
+			supply_optional = "vdd_arm_axp";
+			vdd_arm_spu-supply = <&VCC1P1_ARM_SPU>;
+			vdd_arm_axp-supply = <&VCC1P1_ARM_PMIC>;
+			status = "okay";
+			dvfs-tables = < 1400000 1200000
+					1300000 1140000
+					1200000 1100000
+					1100000 1040000
+					1000000 1040000
+					 900000 1000000
+					 800000 1000000
+					 700000  980000
+					 600000  980000
+					 500000  940000
+					 400000  940000>;
+		};
+
+		tmuctrl_0: tmuctrl@c0096000 {
+			status = "okay";
+		};
+
+		thermal-zones {
+			cpu0_thermal: cpu0-thermal {
+				thermal-sensors = <&tmuctrl_0>;
+				polling-delay-passive = <250>;
+				polling-delay = <1000>;
+
+				trips {
+					cpu_alert0: cpu-alert-0 {
+						temperature = <80000>;
+						hysteresis = <2000>;
+						type = "passive";
+					};
+
+					cpu_alert1: cpu-alert-1 {
+						temperature = <85000>;
+						hysteresis = <2000>;
+						type = "passive";
+					};
+
+					cpu_alert2: cpu-alert-2 {
+						temperature = <100000>;
+						hysteresis = <2000>;
+						type = "passive";
+					};
+
+					cpu_crit0: cpu-crit-0 {
+						temperature = <115000>;
+						hysteresis = <2000>;
+						type = "critical";
+					};
+				};
+
+				cooling-maps {
+					map0 {
+						trip = <&cpu_alert0>;
+						cooling-device = <&cpu0 THERMAL_NO_LIMIT 1>;
+						};
+
+					map1 {
+						trip = <&cpu_alert1>;
+						cooling-device = <&cpu0 1 4>;
+					};
+
+					map2 {
+						trip = <&cpu_alert2>;
+						cooling-device = <&cpu0 4 10>;
+					};
+				};
+			};
+		};
+
+		/* FIXME: bluetooth reset is piggybacked here although their data flow
+		 * goes through serial1 */
+		wifi_powerseq: wifi_powerseq  {
+			compatible = "mmc-pwrseq-simple";
+			reset-gpios =
+				<&gpio_b 24 GPIO_ACTIVE_LOW		/* wifi */
+				&gpio_b 8 GPIO_ACTIVE_LOW>;		/* bluetooth */
+			post-power-on-delay-ms = <50>;
+		};
+
+		i2c3_gpio:i2c@0 {
+			compatible = "i2c-gpio";
+			gpios = <&gpio_e 31 0	/* sda */
+				&gpio_e 30 0	/* scl */
+				>;
+			i2c-gpio,delay-us = <10>;/* ~100 kHz */
+			i2c-gpio,ch =<3>;
+		};
+
+		i2c3_gpio:i2c@0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			spu1705@2d {
+				compatible = "spu1705,fe-pmu";
+				reg = <0x2d>;
+				regulators {
+					VCC1P1_ARM_SPU: DCDC1 {
+						regulator-name = "vdd_arm_1.3V";
+						regulator-min-microvolt = <905000>;
+						regulator-max-microvolt = <1265000>;
+						regulator-always-on;
+					};
+				};
+			};
+
+			axp228@34 {
+				compatible = "x-powers,axp228";
+				reg = <0x34>;
+				interrupt-parent = <&alive_0>;	// CFG_GPIO_PMIC_INTR
+				interrupts = <0x4 IRQ_TYPE_EDGE_FALLING>;
+				nx,id = <0>;
+				/* vdd_arm-supply = <&VCC1P1_ARM_PMIC>; */
+				/* vdd_core-supply = <&VCC1P0_CORE_PMIC>; */
+				regulators {
+					VCC_LDO1:
+						axp22_rtcldo{PMIC_PDATA_INIT( 0,
+						"axp228_rtcldo",
+						3000000, 3000000, 0, 0, 3300000,
+						0, 0xF) };
+					VCC_LDO2:
+						axp22_aldo1{PMIC_PDATA_INIT( 1,
+						"axp228_3p3_alive",
+						700000, 3300000, 1, 1, 3300000,
+						1, 0xF) };
+					VCC_LDO3:
+						axp22_aldo2{PMIC_PDATA_INIT( 2,
+						"axp228_1p8_alive",
+						700000, 3300000, 1, 1, 1800000,
+						1, 0xF) };
+					VCC_LDO4:
+						axp22_aldo3{PMIC_PDATA_INIT( 3,
+						"axp228_1p0_alive",
+						700000, 3300000, 1, 1, 1000000,
+						1, 0xF) };
+					VCC_LDO5:
+						axp22_dldo1{PMIC_PDATA_INIT( 4,
+						"axp228_wide",
+						700000, 3300000, 1, 1, 3300000,
+						1, 0xF) };
+					VCC_LDO6:
+						axp22_dldo2{PMIC_PDATA_INIT( 5,
+						"axp228_1p8_cam",
+						700000, 3300000, 0, 0, 1800000,
+						0, 0xF) };
+					VCC_LDO7:
+						axp22_dldo3{PMIC_PDATA_INIT( 6,
+						"axp228_dldo3",
+						700000, 3300000, 0, 0,  700000,
+						0, 0xF) };
+					VCC_LDO8:
+						axp22_dldo4{PMIC_PDATA_INIT( 7,
+						"axp228_dldo4",
+						700000, 3300000, 0, 0,  700000,
+						0, 0xF) };
+					VCC_LDO9:
+						axp22_eldo1{PMIC_PDATA_INIT( 8,
+						"axp228_1p8_sys",
+						700000, 3300000, 1, 1, 1800000,
+						1, 0xF) };
+					VCC_LDO10:
+						axp22_eldo2{PMIC_PDATA_INIT( 9,
+						"axp228_3p3_wifi",
+						700000, 3300000, 1, 1, 3300000,
+						1, 0xF) };
+					VCC_LDO11:
+						axp22_eldo3{PMIC_PDATA_INIT(10,
+						"axp228_eldo3",
+						700000, 3300000, 0, 0,  700000,
+						0, 0xF) };
+					VCC_LDO12:
+						axp22_dc5ldo{PMIC_PDATA_INIT(11,
+						"axp228_1p2_cvbs",
+						700000, 1400000, 0, 0, 1200000,
+						0, 0xF) };
+					VCC_DCDC1:
+						axp22_dcdc1{PMIC_PDATA_INIT(12,
+						"axp228_3p3_sys",
+						1600000, 3400000, 1, 1, 3300000,
+						1, 0xF) };
+					VCC1P1_ARM_PMIC:
+						axp22_dcdc2{PMIC_PDATA_INIT(13,
+						"axp228_1p1_arm",
+						600000, 1540000, 1, 1, 1200000,
+						1, 0xF) };
+					VCC1P0_CORE_PMIC:
+						axp22_dcdc3{PMIC_PDATA_INIT(14,
+						"axp228_1p0_core",
+						600000, 1860000, 1, 1, 1200000,
+						1, 0xF) };
+					VCC_DCDC4:
+						axp22_dcdc4{PMIC_PDATA_INIT(15,
+						"axp228_1p5_sys",
+						600000, 1540000, 1, 1, 1500000,
+						1, 0xF) };
+					VCC_DCDC5:
+						axp22_dcdc5{PMIC_PDATA_INIT(16,
+						"axp228_1p5_ddr",
+						1000000, 2550000, 1, 1, 1500000,
+						1, 0xF) };
+					VCC_LDOIO0:
+						axp22_ldoio0{PMIC_PDATA_INIT(17,
+						"axp228_ldoio0",
+						700000, 3300000, 0, 0, 1800000,
+						0, 0xF) };
+					VCC_LDOIO1:
+						axp22_ldoio1{PMIC_PDATA_INIT(18,
+						"axp228_ldoio1",
+						700000, 3300000, 0, 0, 1000000,
+						0, 0xF) };
+				};
+			};
+		};
+
+		pinctrl@C0010000 {
+			key_power: key_power {
+				nexell,pins = "alive-0";
+				nexell,pin-function = <0>;
+				nexell,pin-pull = <1>;
+				nexell,pin-strength = <0>;
+			};
+
+			touchpanel_irq: touchpanel-irq {
+				nexell,pins = "gpioc-16";
+				nexell,pin-function = <1>;
+				nexell,pin-pull = <2>;
+				nexell,pin-strength = <0>;
+			};
+		};
+
+		nexell_usbphy: nexell-usbphy@c0012000 {
+			status = "okay";
+		};
+
+		ehci@c0030000 {
+			status = "okay";
+			port@0 {
+				status = "okay";
+			};
+		};
+
+		ohci@c0020000 {
+			status = "okay";
+			port@0 {
+				status = "okay";
+			};
+		};
+
+		dwc2otg@c0040000 {
+			gpios = <&gpio_d 21 0>;
+			status = "okay";
+		};
+
+		gmac0:ethernet@c0060000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&gmac_pins>;
+
+			status = "okay";
+			#address-cells = <0x1>;
+			#size-cells = <0x0>;
+
+			snps,phy-addr = <7>;
+			snps,reset-gpio = <&gpio_e 22 0>;
+			snps,reset-active-low;
+			snps,reset-delays-us = <0 10000 30000>;
+
+			mdio {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				ethernet_phy: ethernet-phy@3 {
+					reg = <3>;
+					fixed-link {
+						speed = <1000>;
+						full-duplex;
+					};
+				};
+			};
+		};
+
+		i2c_0:i2c@c00a4000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			es8316_codec: es8316@11 {
+				#sound-dai-cells = <0>;
+				compatible = "everest,es8316";
+				reg = <0x11>;
+			};
+		};
+
+		i2c_1:i2c@c00a5000 {
+			status = "okay";
+		};
+
+		i2c_2:i2c@c00a6000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "okay";
+
+			/* Note: touch sensors are registered by onewire */
+			/*touchscreen@38 {
+				compatible = "edt,edt-ft5506";
+				reg = <0x38>;
+				interrupt-parent = <&gpio_c>;
+				interrupts = <16 IRQ_TYPE_EDGE_FALLING>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&touchpanel_irq>;
+				touchscreen-size-x = <1280>;
+				touchscreen-size-y = <800>;
+				touchscreen-max-pressure = <255>;
+			};*/
+
+			/*touchscreen@46 {
+				compatible = "ite,it7260";
+				reg = <0x46>;
+				interrupt-parent = <&gpio_c>;
+				interrupts = <16 IRQ_TYPE_LEVEL_LOW>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&touchpanel_irq>;
+			};*/
+		};
+
+		pwm:pwm@c0018000 {
+			// block pwm3_pin - conflicts with spi0_miso (on spi0_bus) drawn on 2.54mm header
+			pinctrl-0 = <&pwm0_pin &pwm1_pin &pwm2_pin>;
+			samsung,pwm-outputs = <0>, <1>, <2>;
+			status = "okay";
+		};
+
+		vip_1:vip@c0064000 {
+			status = "okay";
+		};
+
+		clipper_1:clipper1@c0064000 {
+			status = "okay";
+			pwms = <&pwm 1 41 0>; /* 1000000000/41 */
+			interface_type = <NX_CAPTURE_INTERFACE_PARALLEL>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&vid1_data_clk &vid1_sync> ;
+			port = <0>;
+			external_sync = <0>;
+			data_order = <NX_VIN_Y0CBY1CR>;
+			interlace = <0>;
+			regulator_names = "axp22_dldo2";
+			regulator_voltages = <1800000>;
+
+			gpios = <&gpio_c 4 0
+				 &gpio_c 5 0
+			         &gpio_c 6 0>;
+
+			sensor {
+				type = <NX_CAPTURE_SENSOR_I2C>;
+				i2c_name = "SP2518";
+				i2c_adapter = <0>;
+				addr = <0x30>;
+			};
+
+			power {
+				enable_seq = <
+				NX_ACTION_START NX_ACTION_TYPE_GPIO 2 1 0 NX_ACTION_END
+				NX_ACTION_START NX_ACTION_TYPE_PMIC 0 0 NX_ACTION_END
+				NX_ACTION_START NX_ACTION_TYPE_PMIC 1 0 NX_ACTION_END
+				NX_ACTION_START NX_ACTION_TYPE_GPIO 0 0 0 1 0 NX_ACTION_END
+				NX_ACTION_START NX_ACTION_TYPE_CLOCK 1 10 NX_ACTION_END
+				NX_ACTION_START NX_ACTION_TYPE_GPIO 0 0 0 NX_ACTION_END
+				NX_ACTION_START NX_ACTION_TYPE_GPIO 1 1 0 0 1 NX_ACTION_END
+				NX_ACTION_START NX_ACTION_TYPE_GPIO 1 1 100 NX_ACTION_END
+				>;
+			};
+		};
+
+		dp_drm: display_drm {
+            status = "okay";
+            ports {
+                port@0 {
+                    reg = <0>;
+                    back_color = < 0x0 >;
+                    color_key = < 0x0 >;
+					/* Port 0 has two RGB planes and one video plane. These planes
+					 * are arranged in z-order: RGB plane 0 is below plane 1,
+					 * video plane may be set at any position in z-order.
+					 *
+					 * Possible names for RGB planes: "primary", "rgb", "cursor"
+					 * Possible name for video plane: "video"
+					 * Two RGB plane names and one video plane name may be specified in
+					 * "plane-names" property.
+					 * RGB plane "primary" will be used as root window.
+					 * RGB plane "cursor" will be used for cursor.
+					 * RGB plane "rgb" and video plane are overlay planes, normally
+					 * not used by X-windows.
+					 *
+					 * Order of plane names specifies z-order of planes, top to bottom.
+					 */
+                    plane-names = "cursor", "video", "primary";
+                };
+                port@1 {
+                    reg = <1>;
+                    back_color = < 0x0 >;
+                    color_key = < 0x0 >;
+					/* Port 1 has one RGB plane and one video plane only. */
+                    plane-names = "video", "primary";
+                };
+            };
+        };
+
+        dp_drm_hdmi: display_drm_hdmi {
+            ddc-i2c-bus = <&i2c_1>;
+            q_range = <1>;
+            status = "ok";
+        };
+
+        dp_drm_rgb: display_drm_rgb {
+            remote-endpoint = <&rgb_panel>;
+            status = "okay";
+
+            dp_control {
+                clk_src_lv0 = <0>;
+                clk_div_lv0 = <16>;
+                clk_src_lv1 = <7>;
+                clk_div_lv1 = <1>;
+                out_format = <3>;
+                invert_field = <0>;
+                swap_rb = <0>;
+                yc_order = <0>;
+                delay_mask = < ((1<<0) | (1<<1) | (1<<2) | (1<<3)) >;
+                d_rgb_pvd = <0>;
+                d_hsync_cp1 = <0>;
+                d_vsync_fram = <0>;
+                d_de_cp2 = <7>;
+                vs_start_offset = <863>;
+                ev_start_offset = <863>;
+                vs_end_offset = <0>;
+                ev_end_offset = <0>;
+            };
+        };
+
+        dp_drm_lvds: display_drm_lvds {
+			status = "ok";
+			remote-endpoint = <&lvds_panel>;
+			dp_control {
+				clk_src_lv0 = <0>;
+				clk_div_lv0 = <16>;
+				clk_src_lv1 = <7>;
+				clk_div_lv1 = <1>;
+				out_format = <3>;
+			};
+		};
+
+		rtc@c0010c00 {
+			status = "okay";
+		};
+
+		i2s_0:i2s@c0055000 {
+			#sound-dai-cells = <1>;
+			sample-rate = <48000>;
+			frame-bit = <32>;
+			status = "okay";
+		};
+
+		spdif_tx: spdiftx@c0059000 {
+			#sound-dai-cells = <1>;
+			status = "okay";
+		};
+
+		adc:adc@c0053000 {
+			status = "okay";
+		};
+
+		video-codec@c0080000 {
+			status = "okay";
+			sram = <0 0>;
+		};
+
+		scaler@c0066000 {
+			status = "okay";
+		};
+
+		nano-videodev {
+			compatible = "nexell,nano-videodev";
+			reg = <0xc0102000 0x100>;
+			reg-names = "mlc.0";
+			status = "okay";
+		};
+
+		leds {
+			compatible = "gpio-leds";
+
+			green {
+				label = "green";
+				gpios = <&gpio_b 12 GPIO_ACTIVE_LOW>;
+				linux,default-trigger = "heartbeat";
+			};
+		};
+
+	};	/*** soc ***/
+
+	panel_lvds {
+		compatible = "nanopi,nano-panel";
+		lvds;
+		status = "okay";
+
+		port {
+			lvds_panel: endpoint {
+			};
+		};
+	};
+
+	panel_rgb {
+		compatible = "nanopi,nano-panel";
+		status = "okay";
+
+		pinctrl-names = "default";
+		pinctrl-0 = <&dp_rgb_vclk &dp_rgb_vsync &dp_rgb_hsync
+			&dp_rgb_de &dp_rgb_R &dp_rgb_G &dp_rgb_B>;
+
+		port {
+			rgb_panel: endpoint {
+			};
+		};
+	};
+
+	gpio_key: gpio_keys {
+		compatible = "gpio-keys";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&key_power>;
+
+		power {
+			label = "Power";
+			gpios = <&alive_0 0 0>;
+			linux,code = <KEY_POWER>;
+			gpio-key,wakeup;
+		};
+	};
+
+	spdif_out: spdif-out {
+		#sound-dai-cells = <0>;
+		compatible = "linux,spdif-dit";
+		status = "okay";
+	};
+
+	/* Audio jack output configured to use with Nexell driver. Not used.
+	 */
+	es8316_sound: es8316@i2s0 {
+		compatible = "nexell,nexell-es8316";
+		ch = <0>;
+		sample-rate = <48000>;
+		format = "S16";
+		hpin-support = <0>;
+		hpin-gpio = <&gpio_b 27 0>;
+		hpin-level = <1>;
+		status = "disabled";
+	};
+
+	/* HDMI output configured to use with Nexell driver. Not used also.
+	 *
+	 * Note that es8316_sound and spdif_sound cannot be enabled together
+	 * because of nexell-pcm device used by both.
+	 */
+	spdif_sound {
+		compatible = "nexell,spdif-transceiver";
+		sample_rate = <48000>;
+		format = "S16";
+		status = "disabled";
+	};
+
+	jack_sound {
+		compatible = "simple-audio-card";
+		simple-audio-card,mclk-fs = <256>;
+		simple-audio-card,name = "Jack";
+		simple-audio-card,widgets =
+			"Headphone", "Headphones",
+			"Microphone", "Microphone";
+		simple-audio-card,routing =
+			"Headphones", "HPOL",
+			"Headphones", "HPOR",
+			"MIC1", "Microphone";
+		status = "okay";
+
+		simple-audio-card,dai-link@0 {
+		    format = "i2s";
+			cpu {
+				sound-dai = <&i2s_0 0>;
+		    };
+
+		    codec {
+				sound-dai = <&es8316_codec>;
+		    };
+		};
+	};
+
+	hdmi_sound {
+		compatible = "simple-audio-card";
+		simple-audio-card,mclk-fs = <256>;
+		simple-audio-card,name = "HDMI";
+		simple-audio-card,widgets =
+			"Headphone", "TV Out";
+		simple-audio-card,routing =
+			"TV Out", "spdif-out";
+		status = "okay";
+
+		simple-audio-card,dai-link@0 {
+		    cpu {
+				sound-dai = <&spdif_tx 0>;
+		    };
+
+		    codec {
+				sound-dai = <&spdif_out>;
+		    };
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		blue {
+			label = "blue";
+			gpios = <&gpio_b 12 GPIO_ACTIVE_LOW>;
+			linux,default-trigger = "mmc1";
+		};
+	};
+
+	wifi_bcm4329 { /* wifi definition for bcmdhd.ko module */
+		compatible = "nanopi,bcm4329";
+		interrupt-parent = <&gpio_c>;
+		interrupts = <17 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	nanopi-thermistor {
+		compatible = "friendlyarm,nanopi-thermistor";
+		status = "okay";
+
+		io-channels = <&adc 2>;
+		io-channel-names = "nanopi-thermistor";
+	};
+
+	nanopi-onewire {
+		interrupt-parent = <&gic>;
+		compatible = "friendlyarm,onewire";
+
+		channel-gpio = <&gpio_c 15 0>;
+		reg = <PHYS_BASE_TIMER 0x1000>;
+		interrupts = <0 IRQ_TIMER3 0>;
+		irq-timer = <3>;
+	};
+
+	onewire-touch {
+		compatible = "friendlyarm,onewire-touch";
+		interrupt-parent = <&gpio_c>;
+		interrupts = <16 IRQ_TYPE_NONE>;
+		i2c-bus = <&i2c_2>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&touchpanel_irq>;
+	};
+};
+
diff --git a/arch/arm64/configs/nanopim3_defconfig b/arch/arm64/configs/nanopim3_defconfig
index 662657a2..fba15ac2 100644
--- a/arch/arm64/configs/nanopim3_defconfig
+++ b/arch/arm64/configs/nanopim3_defconfig
@@ -2032,8 +2032,8 @@ CONFIG_THERMAL_GOV_STEP_WISE=y
 # CONFIG_THERMAL_GOV_BANG_BANG is not set
 # CONFIG_THERMAL_GOV_USER_SPACE is not set
 # CONFIG_THERMAL_GOV_POWER_ALLOCATOR is not set
-# CONFIG_CPU_THERMAL is not set
-# CONFIG_THERMAL_EMULATION is not set
+CONFIG_CPU_THERMAL=y
+CONFIG_THERMAL_EMULATION=y
 # CONFIG_QORIQ_THERMAL is not set
 
 #
@@ -2210,6 +2210,7 @@ CONFIG_REGULATOR_AXP228=y
 # CONFIG_REGULATOR_PV88080 is not set
 # CONFIG_REGULATOR_PV88090 is not set
 # CONFIG_REGULATOR_PWM is not set
+CONFIG_REGULATOR_SPU1705=y
 # CONFIG_REGULATOR_TPS51632 is not set
 # CONFIG_REGULATOR_TPS62360 is not set
 # CONFIG_REGULATOR_TPS65023 is not set
diff --git a/drivers/cpufreq/nexell-cpufreq.c b/drivers/cpufreq/nexell-cpufreq.c
index 94a00121..f698a270 100644
--- a/drivers/cpufreq/nexell-cpufreq.c
+++ b/drivers/cpufreq/nexell-cpufreq.c
@@ -713,6 +713,7 @@ static void *nxp_cpufreq_make_table(struct platform_device *pdev,
 	struct cpufreq_frequency_table *freq_table;
 	struct cpufreq_asv_ops *ops = &asv_ops;
 	unsigned long (*plat_tbs)[2] = NULL;
+	unsigned long plat_n_voltage = 0;
 	int tb_size, asv_size = 0;
 	int id = 0, n = 0;
 
@@ -741,17 +742,22 @@ static void *nxp_cpufreq_make_table(struct platform_device *pdev,
 	/* make frequency table with platform data */
 	if (asv_size > 0) {
 		for (n = 0, id = 0; tb_size > id && asv_size > n; n++) {
-			if (plat_tbs) {
-				for (n = 0; asv_size > n; n++) {
-					if (plat_tbs[id][0] ==
-					    dvfs_tables[n][0]) {
-						dvfs_tables[id][0] =
-							dvfs_tables[n][0];
-						dvfs_tables[id][1] =
-							dvfs_tables[n][1];
-						break;
-					}
-				}
+                        if (plat_tbs && plat_tbs[id][1] > 0)
+                                plat_n_voltage = plat_tbs[id][1];
+
+                        if (plat_n_voltage) {
+                                dvfs_tables[id][0] = plat_tbs[id][0];
+                                dvfs_tables[id][1] = plat_n_voltage;
+
+                        } else if (plat_tbs) {
+                                for (n = 0; asv_size > n; n++) {
+                                        if (plat_tbs[id][0] == dvfs_tables[n][0]) {
+                                                dvfs_tables[id][0] = dvfs_tables[n][0];
+                                                dvfs_tables[id][1] = dvfs_tables[n][1];
+                                                break;
+                                        }
+                                }
+
 			} else {
 				if (dvfs_tables[n][0] > FREQ_MAX_FREQ_KHZ)
 					continue;
@@ -775,6 +781,10 @@ static void *nxp_cpufreq_make_table(struct platform_device *pdev,
 		}
 	}
 
+	/* disabling ASV table to active user defined one */
+	if (plat_n_voltage)
+		ops->get_voltage = NULL;
+
 	/* End table */
 	freq_table[id].frequency = CPUFREQ_TABLE_END;
 	*table_size = id;
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 32763d82..db3f7cb8 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -776,6 +776,12 @@ config REGULATOR_STM32_VREFBUF
 	  This driver can also be built as a module. If so, the module
 	  will be called stm32-vrefbuf.
 
+config REGULATOR_SPU1705
+	tristate "FriendlyElec SPU1705 regulator driver"
+	depends on I2C
+	help
+	  Say Y here to support the voltage regulators on SPU1705
+
 config REGULATOR_TI_ABB
 	tristate "TI Adaptive Body Bias on-chip LDO"
 	depends on ARCH_OMAP
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 24b2ff3f..4e6ddfec 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -96,6 +96,7 @@ obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o
 obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
 obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
 obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o
+obj-$(CONFIG_REGULATOR_SPU1705) += spu1705.o
 obj-$(CONFIG_REGULATOR_STM32_VREFBUF) += stm32-vrefbuf.o
 obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o
 obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o
diff --git a/drivers/regulator/spu1705.c b/drivers/regulator/spu1705.c
new file mode 100644
index 00000000..b021e5d4
--- /dev/null
+++ b/drivers/regulator/spu1705.c
@@ -0,0 +1,596 @@
+/*
+ * Regulator driver for STM32 based PMIC chip
+ *
+ * Copyright (C) Guangzhou FriendlyElec Computer Tech. Co., Ltd.
+ * (http://www.friendlyarm.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can access it online at
+ * http://www.gnu.org/licenses/gpl-2.0.html.
+ */
+
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regulator/spu1705.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/cpufreq.h>
+#include <linux/rtc.h>
+#include <linux/reboot.h>
+
+struct spu1705 {
+	struct device *dev;
+	struct mutex io_lock;
+	struct i2c_client *i2c;
+	int chip_id, chip_rev;
+	int pwm_en;
+	int num_regulators;
+	struct regulator_dev *rdev[SPU1705_NUM_REGULATORS];
+	void (*pm_power_off)(void);
+#if defined(CONFIG_REGULATOR_SPU1705_REBOOT)
+	struct notifier_block reboot_handler;
+	int blocked_uV;
+#endif
+};
+
+static int spu1705_i2c_read(struct i2c_client *client,
+		unsigned char req, unsigned char *buf, int count)
+{
+	int ret;
+
+	struct i2c_msg msgs[] = {
+		{
+			.addr   = client->addr,
+			.flags  = 0,
+			.len    = 1,
+			.buf    = &req,
+		}, {
+			.addr   = client->addr,
+			.flags  = I2C_M_RD,
+			.len    = count,
+			.buf    = buf,
+		},
+	};
+
+	ret = i2c_transfer(client->adapter, &msgs[0], 2);
+	if (ret < 0) {
+		pr_err("spu1705: REQ 0x%02x: i2c xfer error %d\n", req, ret);
+		return ret;
+	}
+
+	pr_debug("spu1705: resp %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3]);
+	return 0;
+}
+
+static int spu1705_i2c_write(struct i2c_client *client,
+		unsigned char req, unsigned char *buf, int count)
+{
+	int ret;
+	struct i2c_msg msgs[] = {
+		{
+			.addr   = client->addr,
+			.flags  = 0,
+			.len    = count,
+			.buf    = buf,
+		},
+	};
+
+	ret = i2c_transfer(client->adapter, &msgs[0], 1);
+	if (ret < 0) {
+		pr_err("spu1705: REQ 0x%02x: i2c write error %d\n", req, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/* Supported commands */
+#define SPU1705_GET_INFO	0x21
+#define SPU1705_GET_TIME	0x22
+#define SPU1705_GET_PWM		0x23
+#define SPU1705_SET_TIME	0x11
+#define SPU1705_SET_PWR		0x12
+#define SPU1705_SET_PWM		0x13
+
+/* Supported voltages */
+#define SPU1705_MIN_uV		905000
+#define SPU1705_MAX_uV		1265000
+#define SPU1705_INIT_uV		1200000
+#define SPU1705_N_VOLTAGES	96
+
+#define VOLT_STEP	((SPU1705_MAX_uV - SPU1705_MIN_uV) / SPU1705_N_VOLTAGES)
+
+static int spu1705_dcdc_list_voltage(struct regulator_dev *dev, unsigned index)
+{
+	return (SPU1705_MAX_uV - (VOLT_STEP * index));
+}
+
+/* DCDC is always enabled */
+static int spu1705_dcdc_is_enabled(struct regulator_dev *dev)
+{
+	return 1;
+}
+
+static int spu1705_dcdc_enable(struct regulator_dev *dev)
+{
+	return 0;
+}
+
+static int spu1705_dcdc_disable(struct regulator_dev *dev)
+{
+	return 0;
+}
+
+static int spu1705_dcdc_get_voltage(struct regulator_dev *dev)
+{
+	struct spu1705 *priv = rdev_get_drvdata(dev);
+	int buck = rdev_get_id(dev) - SPU1705_DCDC1;
+	unsigned char pwm[4] = { 0 };
+
+	if (!priv->pwm_en) {
+		dev_dbg(priv->dev, "get_voltage: %d (default)\n", SPU1705_INIT_uV);
+		return SPU1705_INIT_uV;
+	}
+
+	mutex_lock(&priv->io_lock);
+	spu1705_i2c_read(priv->i2c, SPU1705_GET_PWM, pwm, 2);
+	mutex_unlock(&priv->io_lock);
+
+	dev_dbg(priv->dev, "get_voltage: buck = %d, pwm = %d, vol = %d\n",
+			buck, pwm[buck], (SPU1705_MAX_uV - (VOLT_STEP * pwm[buck])));
+
+	return (SPU1705_MAX_uV - (VOLT_STEP * pwm[buck]));
+}
+
+static int spu1705_dcdc_set_voltage(struct regulator_dev *dev,
+		int min_uV, int max_uV,
+		unsigned int *selector)
+{
+	struct spu1705 *priv = rdev_get_drvdata(dev);
+	int buck = rdev_get_id(dev) - SPU1705_DCDC1;
+	int index;
+	u8 buf[4];
+	int ret;
+
+	index = (SPU1705_MAX_uV - min_uV) / VOLT_STEP;
+	*selector = index;
+
+#if defined(CONFIG_REGULATOR_SPU1705_REBOOT)
+	if (unlikely(min_uV < priv->blocked_uV)) {
+		dev_dbg(priv->dev, "voltage blocked to %d mV\n", priv->blocked_uV/1000);
+		return 0;
+	}
+#endif
+
+	mutex_lock(&priv->io_lock);
+
+	buf[0] = SPU1705_SET_PWM;
+	buf[1] = (buck + 1) & 0xff;
+	buf[2] = index & 0xff;
+	spu1705_i2c_write(priv->i2c, SPU1705_SET_PWM, buf, 3);
+	priv->pwm_en = 1;
+
+	/* verify write */
+	buf[0] = 0;
+	buf[1] = 0;
+	ret = spu1705_i2c_read(priv->i2c, SPU1705_GET_PWM, buf, 2);
+
+	mutex_unlock(&priv->io_lock);
+
+	if (ret < 0 || buf[buck] != index)
+		return -EIO;
+
+	dev_dbg(priv->dev, "set DCDC%d (%d, %d) mV --> sel %d\n", buck,
+			min_uV/1000, max_uV/1000, buf[buck]);
+	return 0;
+}
+
+static struct regulator_ops spu1705_dcdc_ops = {
+	.list_voltage = spu1705_dcdc_list_voltage,
+	.is_enabled = spu1705_dcdc_is_enabled,
+	.enable = spu1705_dcdc_enable,
+	.disable = spu1705_dcdc_disable,
+	.get_voltage = spu1705_dcdc_get_voltage,
+	.set_voltage = spu1705_dcdc_set_voltage,
+};
+
+static struct regulator_desc regulators[] = {
+	{
+		.name = "DCDC1",
+		.id = SPU1705_DCDC1,
+		.ops = &spu1705_dcdc_ops,
+		.n_voltages = SPU1705_N_VOLTAGES,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "DCDC2",
+		.id = SPU1705_DCDC2,
+		.ops = &spu1705_dcdc_ops,
+		.n_voltages = SPU1705_N_VOLTAGES,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+};
+
+static int spu1705_dt_parse_pdata(struct spu1705 *priv,
+		struct spu1705_platform_data *pdata)
+{
+	struct device *dev = priv->dev;
+	struct device_node *regulators_np, *reg_np;
+	struct spu1705_regulator_subdev *rdata;
+	int i, ret;
+
+	regulators_np = of_get_child_by_name(dev->of_node, "regulators");
+	if (!regulators_np) {
+		dev_err(dev, "could not find regulators sub-node\n");
+		return -EINVAL;
+	}
+
+	/* count the number of regulators to be supported in pmic */
+	ret = of_get_child_count(regulators_np);
+	if (ret <= 0) {
+		dev_err(dev, "Error parsing regulator init data, %d\n", ret);
+		return -EINVAL;
+	}
+
+	rdata = devm_kzalloc(dev, sizeof(*rdata) * ret, GFP_KERNEL);
+	if (!rdata) {
+		of_node_put(regulators_np);
+		return -ENOMEM;
+	}
+
+	pdata->num_regulators = ret;
+	pdata->regulators = rdata;
+
+	for_each_child_of_node(regulators_np, reg_np) {
+		for (i = 0; i < ARRAY_SIZE(regulators); i++)
+			if (!of_node_cmp(reg_np->name, regulators[i].name))
+				break;
+
+		if (i == ARRAY_SIZE(regulators)) {
+			dev_warn(dev, "don't know how to configure regulator %s\n",
+					reg_np->name);
+			continue;
+		}
+
+		rdata->id = i;
+		rdata->initdata = of_get_regulator_init_data(dev, reg_np, &regulators[i]);
+		rdata->reg_node = reg_np;
+		rdata++;
+	}
+
+	of_node_put(regulators_np);
+
+	return 0;
+}
+
+static int setup_regulators(struct spu1705 *priv,
+		struct spu1705_platform_data *pdata)
+{
+	struct regulator_config config = { };
+	int i, err;
+
+	priv->num_regulators = pdata->num_regulators;
+
+	for (i = 0; i < pdata->num_regulators; i++) {
+		int id = pdata->regulators[i].id;
+
+		config.dev = priv->dev;
+		config.driver_data = priv;
+		config.init_data = pdata->regulators[i].initdata;
+		config.of_node = pdata->regulators[i].reg_node;
+
+		priv->rdev[i] = devm_regulator_register(priv->dev, &regulators[id],
+				&config);
+		if (IS_ERR(priv->rdev[i])) {
+			err = PTR_ERR(priv->rdev[i]);
+			dev_err(priv->dev, "failed to register regulator %d, err = %d\n",
+					i, err);
+			return err;
+
+		}
+	}
+
+	return 0;
+}
+
+/* Power On/Off support */
+static struct i2c_client *pm_i2c;
+
+static void spu1705_power_off(void)
+{
+	struct spu1705 *priv = i2c_get_clientdata(pm_i2c);
+	u8 buf[4];
+
+	buf[0] = SPU1705_SET_PWR;
+	buf[1] = 0x01;
+	spu1705_i2c_write(pm_i2c, SPU1705_SET_PWR, buf, 2);
+
+	pr_info("spu1705: power off\n");
+
+	if (priv->pm_power_off)
+		priv->pm_power_off();
+}
+
+#if defined(CONFIG_REGULATOR_SPU1705_REBOOT)
+static int spu1705_restart_handle(struct notifier_block *this,
+		unsigned long mode, void *cmd)
+{
+	struct spu1705 *priv =
+		container_of(this, struct spu1705, reboot_handler);
+	unsigned int sel;
+	int i;
+
+	priv->blocked_uV = SPU1705_INIT_uV;
+
+	for (i = 0; i < priv->num_regulators; i++)
+		spu1705_dcdc_set_voltage(priv->rdev[i],
+				SPU1705_INIT_uV, SPU1705_INIT_uV, &sel);
+
+	return NOTIFY_DONE;
+}
+#endif
+
+#define to_i2c_client(d) container_of(d, struct i2c_client, dev)
+
+static inline void spu1705_tm_to_data(struct rtc_time *tm, u8 *data)
+{
+	data[0] = tm->tm_hour;
+	data[1] = tm->tm_min;
+	data[2] = tm->tm_sec;
+}
+
+static ssize_t spu1705_sysfs_show_wakealarm(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct spu1705 *priv = dev_get_drvdata(dev);
+	u8 tm[8];
+	ssize_t n;
+	int ret;
+
+	mutex_lock(&priv->io_lock);
+	ret = spu1705_i2c_read(priv->i2c, SPU1705_GET_TIME, tm, 7);
+	mutex_unlock(&priv->io_lock);
+
+	if (ret < 0)
+		return -EIO;
+
+	n = sprintf(buf, "%02d:%02d:%02d", tm[1], tm[2], tm[3]);
+	if (tm[0])
+		n += sprintf(buf + n, " %02d:%02d:%02d\n", tm[4], tm[5], tm[6]);
+	else
+		n += sprintf(buf + n, " disabled\n");
+
+	return n;
+}
+
+#define SPU1705_ALARM_MIN	60
+
+static ssize_t spu1705_sysfs_set_wakealarm(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t n)
+{
+	struct spu1705 *priv = dev_get_drvdata(dev);
+	struct rtc_time tm;
+	struct timeval tv;
+	unsigned long alarm;
+	u8 data[8];
+	int count = 8;
+
+	do_gettimeofday(&tv);
+	rtc_time_to_tm(tv.tv_sec, &tm);
+	spu1705_tm_to_data(&tm, &data[2]);
+
+	alarm = simple_strtoul(buf, NULL, 0);
+	if (alarm > SPU1705_ALARM_MIN) {
+		data[1] = 1;
+		tv.tv_sec += alarm;
+		rtc_time_to_tm(tv.tv_sec, &tm);
+		spu1705_tm_to_data(&tm, &data[5]);
+		dev_info(dev, "wake alarm: %02d:%02d:%02d\n", tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+	} else if (alarm == 0) {
+		data[1] = 0;
+		count = 2;
+		dev_info(dev, "wake alarm: disabled\n");
+
+	} else {
+		dev_err(dev, "invalid alarm %lu (0: disable, >%d: enable)\n",
+				alarm, SPU1705_ALARM_MIN);
+		return -EINVAL;
+	}
+
+	mutex_lock(&priv->io_lock);
+
+	data[0] = SPU1705_SET_TIME;
+	spu1705_i2c_write(priv->i2c, SPU1705_SET_TIME, data, count);
+
+	mutex_unlock(&priv->io_lock);
+
+	return n;
+}
+
+static DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR,
+		spu1705_sysfs_show_wakealarm, spu1705_sysfs_set_wakealarm);
+
+static void spu1705_sysfs_add_device(struct spu1705 *priv)
+{
+	int err;
+
+	err = device_create_file(priv->dev, &dev_attr_wakealarm);
+	if (err)
+		dev_err(priv->dev, "failed to create alarm attribute, %d\n", err);
+}
+
+static int sp1705_identify_chip(struct spu1705 *priv)
+{
+	unsigned char id[4] = { 0 };
+
+	if (spu1705_i2c_read(priv->i2c, SPU1705_GET_INFO, id, 4) < 0)
+		return -1;
+
+	if (!id[0] || !id[1])
+		return -1;
+
+	priv->chip_id = id[0];
+	priv->chip_rev = id[1] * 100 + id[2];
+	priv->pwm_en = id[3];
+
+	return 0;
+}
+
+static int spu1705_i2c_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	struct spu1705_platform_data *pdata = client->dev.platform_data;
+	struct spu1705 *priv;
+	int ret;
+
+	priv = devm_kzalloc(&client->dev, sizeof(struct spu1705),
+			GFP_KERNEL);
+	if (priv == NULL)
+		return -ENOMEM;
+
+	mutex_init(&priv->io_lock);
+	priv->i2c = client;
+	priv->dev = &client->dev;
+
+	if (IS_ENABLED(CONFIG_OF) && priv->dev->of_node) {
+		pdata = devm_kzalloc(&client->dev,
+				sizeof(struct spu1705_platform_data), GFP_KERNEL);
+		if (!pdata) {
+			dev_err(&client->dev, "could not allocate memory for pdata\n");
+			return -ENOMEM;
+		}
+
+		ret = spu1705_dt_parse_pdata(priv, pdata);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (!pdata) {
+		dev_err(&client->dev, "No platform init data supplied\n");
+		return -ENODEV;
+	}
+
+	if (sp1705_identify_chip(priv) < 0) {
+		dev_err(&client->dev, "failed to detect chip\n");
+		ret = -ENODEV;
+		goto err_detect;
+	}
+
+	ret = setup_regulators(priv, pdata);
+	if (ret < 0)
+		goto err_detect;
+
+	i2c_set_clientdata(client, priv);
+
+	/* PM hookup */
+	if (pm_power_off)
+		priv->pm_power_off = pm_power_off;
+	pm_i2c = client;
+	pm_power_off = spu1705_power_off;
+
+#if defined(CONFIG_REGULATOR_SPU1705_REBOOT)
+	priv->reboot_handler.notifier_call = spu1705_restart_handle;
+	priv->reboot_handler.priority = 192;
+	ret = register_reboot_notifier(&priv->reboot_handler);
+	if (ret) {
+		dev_err(&client->dev, "can't register restart notifier, %d\n", ret);
+		return ret;
+	}
+#endif
+
+	spu1705_sysfs_add_device(priv);
+
+	dev_info(&client->dev, "found chip 0x%02x, rev %04d\n",
+			priv->chip_id, priv->chip_rev);
+	return 0;
+
+err_detect:
+	return ret;
+}
+
+static int spu1705_i2c_remove(struct i2c_client *i2c)
+{
+	struct spu1705 *priv = i2c_get_clientdata(i2c);
+	unsigned int sel;
+	int i;
+
+#if defined(CONFIG_REGULATOR_SPU1705_REBOOT)
+	if (unregister_reboot_notifier(&priv->reboot_handler))
+		dev_err(priv->dev, "can't unregister restart handler\n");
+		return -ENODEV;
+	}
+#endif
+
+	pm_power_off = priv->pm_power_off;
+
+	for (i = 0; i < priv->num_regulators; i++)
+		spu1705_dcdc_set_voltage(priv->rdev[i],
+				SPU1705_INIT_uV, SPU1705_INIT_uV, &sel);
+
+	return 0;
+}
+
+static const struct i2c_device_id spu1705_i2c_id[] = {
+	{ "fe-pmu", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, spu1705_i2c_id);
+
+#if defined(CONFIG_OF)
+static const struct of_device_id spu1705_of_match[] = {
+	{ .compatible = "spu1705", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, spu1705_of_match);
+#endif
+
+static struct i2c_driver spu1705_i2c_driver = {
+	.driver = {
+		.name = "spu1705",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(spu1705_of_match),
+	},
+	.probe    = spu1705_i2c_probe,
+	.remove   = spu1705_i2c_remove,
+	.id_table = spu1705_i2c_id,
+};
+
+static int __init spu1705_module_init(void)
+{
+	int ret;
+
+	ret = i2c_add_driver(&spu1705_i2c_driver);
+	if (ret != 0)
+		pr_err("Failed to register I2C driver: %d\n", ret);
+
+	return ret;
+}
+module_init(spu1705_module_init);
+
+static void __exit spu1705_module_exit(void)
+{
+	i2c_del_driver(&spu1705_i2c_driver);
+}
+module_exit(spu1705_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Guangzhou FriendlyElec Computer Tech. Co., Ltd.");
+MODULE_DESCRIPTION("SPU1705 PMIC driver");
diff --git a/include/linux/regulator/spu1705.h b/include/linux/regulator/spu1705.h
new file mode 100644
index 00000000..03fce65e
--- /dev/null
+++ b/include/linux/regulator/spu1705.h
@@ -0,0 +1,44 @@
+/*
+ * STM32 based PMIC chip client interface
+ *
+ * Copyright (C) Guangzhou FriendlyElec Computer Tech. Co., Ltd.
+ * (http://www.friendlyarm.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __LINUX_REGULATOR_SPU1705_H
+#define __LINUX_REGULATOR_SPU1705_H
+
+#include <linux/regulator/machine.h>
+
+#define SPU1705_DCDC1		0
+#define SPU1705_DCDC2		1
+
+#define SPU1705_NUM_REGULATORS	2
+
+
+struct spu1705_regulator_subdev {
+	int id;
+	struct regulator_init_data *initdata;
+	struct device_node *reg_node;
+};
+
+struct spu1705_platform_data {
+	int num_regulators;
+	struct spu1705_regulator_subdev *regulators;
+};
+
+#endif /* __LINUX_REGULATOR_SPU1705_H */
