diff --git a/config/linux-sunxi-dev.config b/config/linux-sunxi-dev.config index f8f91ec0a..9c2ae51f5 100644 --- a/config/linux-sunxi-dev.config +++ b/config/linux-sunxi-dev.config @@ -2857,6 +2857,7 @@ CONFIG_CLOCK_THERMAL=y # CONFIG_THERMAL_EMULATION is not set # CONFIG_IMX_THERMAL is not set # CONFIG_RCAR_THERMAL is not set +CONFIG_SUN8I_THS=m CONFIG_WATCHDOG=y CONFIG_WATCHDOG_CORE=y # CONFIG_WATCHDOG_NOWAYOUT is not set @@ -3040,6 +3041,7 @@ CONFIG_REGULATOR_SKY81452=m # CONFIG_REGULATOR_TPS65023 is not set # CONFIG_REGULATOR_TPS6507X is not set # CONFIG_REGULATOR_TPS6524X is not set +CONFIG_REGULATOR_SY8106A=y CONFIG_MEDIA_SUPPORT=y # diff --git a/patch/kernel/sunxi-dev/0001-add-bananapim2-plus.patch b/patch/kernel/sunxi-dev/0001-add-bananapim2-plus.patch new file mode 100644 index 000000000..fa726d2ce --- /dev/null +++ b/patch/kernel/sunxi-dev/0001-add-bananapim2-plus.patch @@ -0,0 +1,254 @@ +diff --git a/arch/arm/boot/dts/sun8i-h3-bananapi-m2plus.dts b/arch/arm/boot/dts/sun8i-h3-bananapi-m2plus.dts +new file mode 100644 +index 0000000..ca7c0ec +--- /dev/null ++++ b/arch/arm/boot/dts/sun8i-h3-bananapi-m2plus.dts +@@ -0,0 +1,234 @@ ++/* ++ * Copyright (C) 2015 Jens Kuske ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPL or the X11 license, at your option. Note that this dual ++ * licensing only applies to this file, and not this project as a ++ * whole. ++ * ++ * a) This file 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 file 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. ++ * ++ * Or, alternatively, ++ * ++ * b) Permission is hereby granted, free of charge, to any person ++ * obtaining a copy of this software and associated documentation ++ * files (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, ++ * copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following ++ * conditions: ++ * ++ * The above copyright notice and this permission notice shall be ++ * included in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES ++ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ++ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, ++ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ */ ++ ++/dts-v1/; ++#include "sun8i-h3.dtsi" ++#include "sunxi-common-regulators.dtsi" ++ ++#include ++#include ++#include ++ ++/ { ++ model = "Sinovoip Banana Pi M2 Plus"; ++ compatible = "sinovoip,bananapi-m2-plus", "allwinner,sun8i-h3"; ++ ++ aliases { ++ serial0 = &uart0; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&leds_r_opc>; ++ ++ status_led { ++ label = "bananapi:red:status"; ++ gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>; ++ default-state = "on"; ++ }; ++ }; ++ ++ r_gpio_keys { ++ compatible = "gpio-keys"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sw_r_opc>; ++ ++ sw2 { ++ label = "sw2"; ++ linux,code = ; ++ gpios = <&r_pio 0 4 GPIO_ACTIVE_LOW>; ++ }; ++ ++ sw4 { ++ label = "sw4"; ++ linux,code = ; ++ gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>; ++ }; ++ }; ++ ++ wifi_pwrseq: wifi_pwrseq { ++ compatible = "mmc-pwrseq-simple"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&wifi_pwrseq_pin_orangepi>; ++ reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>; /* PL7 WIFI_EN */ ++ }; ++ ++ reg_gmac_3v3: gmac-3v3 { ++ compatible = "regulator-fixed"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&gmac_power_pin_orangepi>; ++ regulator-name = "gmac-3v3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ startup-delay-us = <100000>; ++ enable-active-high; ++ gpio = <&pio 3 6 GPIO_ACTIVE_HIGH>; ++ }; ++}; ++ ++&ehci1 { ++ status = "okay"; ++}; ++ ++&ehci2 { ++ status = "okay"; ++}; ++ ++&ohci1 { ++ status = "okay"; ++}; ++ ++&ohci2 { ++ status = "okay"; ++}; ++ ++&ir { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&ir_pins_a>; ++ status = "okay"; ++}; ++ ++&mmc0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>; ++ vmmc-supply = <®_vcc3v3>; ++ bus-width = <4>; ++ cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */ ++ cd-inverted; ++ status = "okay"; ++}; ++ ++&mmc1 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mmc1_pins_a>; ++ vmmc-supply = <®_vcc3v3>; ++ mmc-pwrseq = <&wifi_pwrseq>; ++ bus-width = <4>; ++ non-removable; ++ status = "okay"; ++}; ++ ++&r_pio { ++ leds_r_opc: led_pins@0 { ++ allwinner,pins = "PL10"; ++ allwinner,function = "gpio_out"; ++ allwinner,drive = ; ++ allwinner,pull = ; ++ }; ++ ++ sw_r_opc: key_pins@0 { ++ allwinner,pins = "PL3", "PL4"; ++ allwinner,function = "gpio_in"; ++ allwinner,drive = ; ++ allwinner,pull = ; ++ }; ++ ++ wifi_pwrseq_pin_orangepi: wifi_pwrseq_pin@0 { ++ allwinner,pins = "PL7"; ++ allwinner,function = "gpio_out"; ++ allwinner,drive = ; ++ allwinner,pull = ; ++ }; ++}; ++ ++®_usb1_vbus { ++ gpio = <&pio 6 13 GPIO_ACTIVE_HIGH>; ++ status = "okay"; ++}; ++ ++&uart0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart0_pins_a>; ++ status = "okay"; ++}; ++ ++&usb1_vbus_pin_a { ++ allwinner,pins = "PG13"; ++}; ++ ++&usbphy { ++ usb1_vbus-supply = <®_usb1_vbus>; ++ status = "okay"; ++}; ++ ++&mmc2 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mmc2_8bit_pins>; ++ vmmc-supply = <®_vcc3v3>; ++ bus-width = <8>; ++ non-removable; ++ cap-mmc-hw-reset; ++ status = "okay"; ++}; ++ ++&mmc2_8bit_pins { ++ /* Increase drive strength for DDR modes */ ++ allwinner,drive = ; ++ /* eMMC is missing pull-ups */ ++ allwinner,pull = ; ++}; ++ ++&pio { ++ gmac_power_pin_orangepi: gmac_power_pin@0 { ++ allwinner,pins = "PD6"; ++ allwinner,function = "gpio_out"; ++ allwinner,drive = ; ++ allwinner,pull = ; ++ }; ++}; ++ ++&emac { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&emac_rgmii_pins>; ++ phy = <&phy1>; ++ phy-mode = "rgmii"; ++ phy-supply = <®_gmac_3v3>; ++ status = "okay"; ++ phy1: ethernet-phy@1 { ++ reg = <0>; ++ }; ++}; +diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile +index 4666e08..94e7470 100644 +--- a/arch/arm/boot/dts/Makefile ++++ b/arch/arm/boot/dts/Makefile +@@ -722,7 +722,8 @@ dtb-$(CONFIG_MACH_SUN8I) += \ + sun8i-a83t-cubietruck-plus.dtb \ + sun8i-h3-orangepi-2.dtb \ + sun8i-h3-orangepi-pc.dtb \ +- sun8i-h3-orangepi-plus.dtb ++ sun8i-h3-orangepi-plus.dtb \ ++ sun8i-h3-bananapi-m2plus.dtb + dtb-$(CONFIG_MACH_SUN9I) += \ + sun9i-a80-optimus.dtb \ + sun9i-a80-cubieboard4.dtb diff --git a/patch/kernel/sunxi-dev/0002-sun8i-sy8106a-dvfs-cpufreq.patch.disabled b/patch/kernel/sunxi-dev/0002-sun8i-sy8106a-dvfs-cpufreq.patch.disabled new file mode 100644 index 000000000..df6985b89 --- /dev/null +++ b/patch/kernel/sunxi-dev/0002-sun8i-sy8106a-dvfs-cpufreq.patch.disabled @@ -0,0 +1,1238 @@ +diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt +index 834436f..6feb93c 100644 +--- a/Documentation/devicetree/bindings/clock/sunxi.txt ++++ b/Documentation/devicetree/bindings/clock/sunxi.txt +@@ -81,6 +81,7 @@ Required properties: + "allwinner,sun9i-a80-usb-mod-clk" - for usb gates + resets on A80 + "allwinner,sun9i-a80-usb-phy-clk" - for usb phy gates + resets on A80 + "allwinner,sun4i-a10-ve-clk" - for the Video Engine clock ++ "allwinner,sun8i-h3-ths-clk" - for THS on H3 + + Required properties for all clocks: + - reg : shall be the control register address for the clock. +diff --git a/Documentation/devicetree/bindings/thermal/sun8i-ths.txt b/Documentation/devicetree/bindings/thermal/sun8i-ths.txt +new file mode 100644 +index 0000000..826cd57 +--- /dev/null ++++ b/Documentation/devicetree/bindings/thermal/sun8i-ths.txt +@@ -0,0 +1,31 @@ ++* sun8i THS ++ ++Required properties: ++- compatible : "allwinner,sun8i-h3-ths" ++- reg : Address range of the thermal registers and location of the calibration ++ value ++- resets : Must contain an entry for each entry in reset-names. ++ see ../reset/reset.txt for details ++- reset-names : Must include the name "ahb" ++- clocks : Must contain an entry for each entry in clock-names. ++- clock-names : Must contain "ahb" for the bus gate and "ths" for the THS ++ clock ++ ++Optional properties: ++- nvmem-cells : Must contain an entry for each entry in nvmem-cell-names ++- nvmem-cell-names : Must contain "calibration" for the cell containing the ++ temperature calibration cell, if available ++ ++Example: ++ths: ths@01c25000 { ++ #thermal-sensor-cells = <0>; ++ compatible = "allwinner,sun8i-h3-ths"; ++ reg = <0x01c25000 0x400>; ++ interrupts = ; ++ resets = <&bus_rst 136>; ++ reset-names = "ahb"; ++ clocks = <&bus_gates 72>, <&ths_clk>; ++ clock-names = "ahb", "ths"; ++ nvmem-cells = <&ths_calibration>; ++ nvmem-cell-names = "calibration"; ++}; +diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-2.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-2.dts +index d8118d0..2aa8e2c 100644 +--- a/arch/arm/boot/dts/sun8i-h3-orangepi-2.dts ++++ b/arch/arm/boot/dts/sun8i-h3-orangepi-2.dts +@@ -103,6 +103,62 @@ + }; + }; + ++&cpu0 { ++ clocks = <&cpu>; ++ clock-latency = <244144>; /* 8 32k periods */ ++ operating-points = < ++ /* kHz uV */ ++ 1344000 1340000 ++ 1296000 1320000 ++ 1200000 1240000 ++ 1104000 1180000 ++ 1008000 1140000 ++ 648000 1050000 ++ 408000 980000 ++ >; ++ #cooling-cells = <2>; ++ cooling-min-level = <0>; ++ cooling-max-level = <6>; ++ cpu0-supply = <&vdd_cpu>; ++}; ++ ++&cpu_thermal { ++ cooling-maps { ++ map0 { ++ trip = <&cpu_alert0>; ++ cooling-device = <&cpu0 (-1) (-1)>; ++ }; ++ }; ++ ++ trips { ++ cpu_alert0: cpu_alert0 { ++ temperature = <75000>; ++ hysteresis = <2000>; ++ type = "passive"; ++ }; ++ ++ cpu_crit: cpu_crit { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "critical"; ++ }; ++ }; ++}; ++ ++&r_twi { ++ status = "okay"; ++ ++ vdd_cpu: regulator@65 { ++ compatible = "sy8106a"; ++ reg = <0x65>; ++ regulator-min-microvolt = <980000>; ++ regulator-max-microvolt = <1400000>; ++ regulator-ramp-delay = <200>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++}; ++ + &ehci1 { + status = "okay"; + }; +diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts +new file mode 100644 +index 0000000..994730d +--- /dev/null ++++ b/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts +@@ -0,0 +1,247 @@ ++/* ++ * Copyright (C) 2015 Chen-Yu Tsai ++ * Copyright (C) 2016 Ondřej Jirman ++ * ++ * This file is dual-licensed: you can use it either under the terms ++ * of the GPL or the X11 license, at your option. Note that this dual ++ * licensing only applies to this file, and not this project as a ++ * whole. ++ * ++ * a) This file 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 file 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. ++ * ++ * Or, alternatively, ++ * ++ * b) Permission is hereby granted, free of charge, to any person ++ * obtaining a copy of this software and associated documentation ++ * files (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, ++ * copy, modify, merge, publish, distribute, sublicense, and/or ++ * sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following ++ * conditions: ++ * ++ * The above copyright notice and this permission notice shall be ++ * included in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES ++ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT ++ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, ++ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ */ ++ ++/dts-v1/; ++#include "sun8i-h3.dtsi" ++#include "sunxi-common-regulators.dtsi" ++ ++#include ++#include ++#include ++ ++/ { ++ model = "Xunlong Orange Pi One"; ++ compatible = "xunlong,orangepi-one", "allwinner,sun8i-h3"; ++ ++ aliases { ++ serial0 = &uart0; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&leds_opc>, <&leds_r_opc>; ++ ++ pwr_led { ++ label = "orangepi:green:pwr"; ++ gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>; ++ default-state = "on"; ++ }; ++ ++ status_led { ++ label = "orangepi:red:status"; ++ gpios = <&pio 0 15 GPIO_ACTIVE_HIGH>; ++ }; ++ }; ++ ++ r_gpio_keys { ++ compatible = "gpio-keys"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sw_r_opc>; ++ ++ sw4 { ++ label = "sw4"; ++ linux,code = ; ++ gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>; ++ }; ++ }; ++ ++ vdd_soc: gpio-regulator { ++ compatible = "regulator-gpio"; ++ ++ regulator-name = "soc-vdd-supply"; ++ regulator-min-microvolt = <1100000>; ++ regulator-max-microvolt = <1300000>; ++ regulator-boot-on; ++ regulator-type = "voltage"; ++ ++ gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>; ++ states = <1100000 0x0 ++ 1300000 0x1>; ++ ++ startup-delay-us = <100000>; ++ enable-active-high; ++ }; ++}; ++ ++&cpu0 { ++ clocks = <&cpu>; ++ clock-latency = <244144>; /* 8 32k periods */ ++ operating-points = < ++ /* kHz uV */ ++ 1296000 1300000 ++ 1200000 1300000 ++ 624000 1100000 ++ 480000 1100000 ++ 312000 1100000 ++ 240000 1100000 ++ >; ++ #cooling-cells = <2>; ++ cooling-min-level = <0>; ++ cooling-max-level = <5>; ++ cpu0-supply = <&vdd_soc>; ++}; ++ ++&cpu_thermal { ++ cooling-maps { ++ map0 { ++ trip = <&cpu_alert0>; ++ cooling-device = <&cpu0 (-1) (-1)>; ++ }; ++ }; ++ ++ trips { ++ cpu_alert0: cpu_alert0 { ++ temperature = <75000>; ++ hysteresis = <2000>; ++ type = "passive"; ++ }; ++ ++ cpu_crit: cpu_crit { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "critical"; ++ }; ++ }; ++}; ++ ++&ehci1 { ++ status = "okay"; ++}; ++ ++&ehci2 { ++ status = "okay"; ++}; ++ ++&ehci3 { ++ status = "okay"; ++}; ++ ++&ephy { ++ allwinner,ephy-addr = <0x1>; ++}; ++ ++&emac { ++ phy = <&phy1>; ++ phy-mode = "mii"; ++ status = "okay"; ++ ++ phy1: ethernet-phy@1 { ++ reg = <1>; ++ }; ++}; ++ ++&ir { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&ir_pins_a>; ++ status = "okay"; ++}; ++ ++&mmc0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin>; ++ vmmc-supply = <®_vcc3v3>; ++ bus-width = <4>; ++ cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */ ++ cd-inverted; ++ status = "okay"; ++}; ++ ++&ohci1 { ++ status = "okay"; ++}; ++ ++&ohci2 { ++ status = "okay"; ++}; ++ ++&ohci3 { ++ status = "okay"; ++}; ++ ++&pio { ++ leds_opc: led_pins@0 { ++ allwinner,pins = "PA15"; ++ allwinner,function = "gpio_out"; ++ allwinner,drive = ; ++ allwinner,pull = ; ++ }; ++}; ++ ++&r_pio { ++ leds_r_opc: led_pins@0 { ++ allwinner,pins = "PL10"; ++ allwinner,function = "gpio_out"; ++ allwinner,drive = ; ++ allwinner,pull = ; ++ }; ++ ++ sw_r_opc: key_pins@0 { ++ allwinner,pins = "PL3"; ++ allwinner,function = "gpio_in"; ++ allwinner,drive = ; ++ allwinner,pull = ; ++ }; ++ ++ soc_reg0: soc_reg@0 { ++ allwinner,pins = "PL6"; ++ allwinner,function = "gpio_out"; ++ allwinner,drive = ; ++ allwinner,pull = ; ++ }; ++}; ++ ++&uart0 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&uart0_pins_a>; ++ status = "okay"; ++}; ++ ++&usbphy { ++ /* USB VBUS is always on */ ++ status = "okay"; ++}; +diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts +index 2249d40..0ddf741 100644 +--- a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts ++++ b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts +@@ -90,6 +90,62 @@ + }; + }; + ++&cpu0 { ++ clocks = <&cpu>; ++ clock-latency = <244144>; /* 8 32k periods */ ++ operating-points = < ++ /* kHz uV */ ++ 1344000 1340000 ++ 1296000 1320000 ++ 1200000 1240000 ++ 1104000 1180000 ++ 1008000 1140000 ++ 648000 1050000 ++ 408000 980000 ++ >; ++ #cooling-cells = <2>; ++ cooling-min-level = <0>; ++ cooling-max-level = <6>; ++ cpu0-supply = <&vdd_cpu>; ++}; ++ ++&cpu_thermal { ++ cooling-maps { ++ map0 { ++ trip = <&cpu_alert0>; ++ cooling-device = <&cpu0 (-1) (-1)>; ++ }; ++ }; ++ ++ trips { ++ cpu_alert0: cpu_alert0 { ++ temperature = <75000>; ++ hysteresis = <2000>; ++ type = "passive"; ++ }; ++ ++ cpu_crit: cpu_crit { ++ temperature = <105000>; ++ hysteresis = <2000>; ++ type = "critical"; ++ }; ++ }; ++}; ++ ++&r_twi { ++ status = "okay"; ++ ++ vdd_cpu: regulator@65 { ++ compatible = "sy8106a"; ++ reg = <0x65>; ++ regulator-min-microvolt = <980000>; ++ regulator-max-microvolt = <1400000>; ++ regulator-ramp-delay = <200>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++}; ++ + &ehci1 { + status = "okay"; + }; +diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi +index e7b6334..780389d 100644 +--- a/arch/arm/boot/dts/sun8i-h3.dtsi ++++ b/arch/arm/boot/dts/sun8i-h3.dtsi +@@ -52,7 +52,7 @@ + #address-cells = <1>; + #size-cells = <0>; + +- cpu@0 { ++ cpu0: cpu@0 { + compatible = "arm,cortex-a7"; + device_type = "cpu"; + reg = <0>; +@@ -77,6 +77,14 @@ + }; + }; + ++ thermal-zones { ++ cpu_thermal: cpu_thermal { ++ polling-delay-passive = <1000>; ++ polling-delay = <5000>; ++ thermal-sensors = <&ths 0>; ++ }; ++ }; ++ + timer { + compatible = "arm,armv7-timer"; + interrupts = , +@@ -239,6 +247,14 @@ + "bus_scr", "bus_ephy", "bus_dbg"; + }; + ++ ths_clk: clk@01c20074 { ++ #clock-cells = <0>; ++ compatible = "allwinner,sun8i-h3-ths-clk"; ++ reg = <0x01c20074 0x4>; ++ clocks = <&osc24M>; ++ clock-output-names = "ths"; ++ }; ++ + mmc0_clk: clk@01c20088 { + #clock-cells = <1>; + compatible = "allwinner,sun4i-a10-mmc-clk"; +@@ -304,8 +320,8 @@ + reg = <0x01f01428 0x4>; + #clock-cells = <1>; + clocks = <&apb0>; +- clock-indices = <0>, <1>; +- clock-output-names = "apb0_pio", "apb0_ir"; ++ clock-indices = <0>, <1>, <6>; ++ clock-output-names = "apb0_pio", "apb0_ir", "apb0_i2c"; + }; + + ir_clk: ir_clk@01f01454 { +@@ -389,6 +405,17 @@ + #size-cells = <0>; + }; + ++ sid: eeprom@01c14000 { ++ compatible = "allwinner,sun4i-a10-sid"; ++ reg = <0x01c14000 0x400>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ ths_calibration: calib@234 { ++ reg = <0x234 0x4>; ++ }; ++ }; ++ + usbphy: phy@01c19400 { + compatible = "allwinner,sun8i-h3-usb-phy"; + reg = <0x01c19400 0x2c>, +@@ -585,6 +612,19 @@ + interrupts = ; + }; + ++ ths: ths@01c25000 { ++ #thermal-sensor-cells = <0>; ++ compatible = "allwinner,sun8i-h3-ths"; ++ reg = <0x01c25000 0x400>; ++ interrupts = ; ++ resets = <&apb1_rst 8>; ++ reset-names = "ahb"; ++ clocks = <&bus_gates 72>, <&ths_clk>; ++ clock-names = "ahb", "ths"; ++ nvmem-cells = <&ths_calibration>; ++ nvmem-cell-names = "calibration"; ++ }; ++ + uart0: serial@01c28000 { + compatible = "snps,dw-apb-uart"; + reg = <0x01c28000 0x400>; +@@ -637,6 +677,20 @@ + status = "disabled"; + }; + ++ r_twi: i2c@01f02400 { ++ compatible = "allwinner,sun6i-a31-i2c"; ++ reg = <0x01f02400 0x400>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&r_twi_pins_a>; ++ clocks = <&apb0_gates 6>; ++ clock-frequency = <100000>; ++ resets = <&apb0_reset 6>; ++ status = "disabled"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ + emac: ethernet@1c30000 { + compatible = "allwinner,sun8i-h3-emac"; + reg = <0x01c30000 0x104>; +@@ -701,6 +755,14 @@ + allwinner,drive = ; + allwinner,pull = ; + }; ++ ++ r_twi_pins_a: r_twi@0 { ++ allwinner,pins = "PL0", "PL1"; ++ allwinner,function = "s_twi"; ++ allwinner,drive = ; ++ allwinner,pull = ; ++ }; + }; + }; + }; ++ +diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile +index 3fd7901..50578b3 100644 +--- a/drivers/clk/sunxi/Makefile ++++ b/drivers/clk/sunxi/Makefile +@@ -9,6 +9,7 @@ obj-y += clk-a10-mod1.o + obj-y += clk-a10-pll2.o + obj-y += clk-a10-ve.o + obj-y += clk-a20-gmac.o ++obj-y += clk-h3-ths.o + obj-y += clk-mod0.o + obj-y += clk-simple-gates.o + obj-y += clk-sun8i-bus-gates.o +diff --git a/drivers/clk/sunxi/clk-h3-ths.c b/drivers/clk/sunxi/clk-h3-ths.c +new file mode 100644 +index 0000000..c1d6d32 +--- /dev/null ++++ b/drivers/clk/sunxi/clk-h3-ths.c +@@ -0,0 +1,98 @@ ++/* ++ * sun8i THS clock driver ++ * ++ * Copyright (C) 2015 Josef Gajdusek ++ * ++ * This software is licensed under the terms of the GNU General Public ++ * License version 2, as published by the Free Software Foundation, and ++ * may be copied, distributed, and modified under those terms. ++ * ++ * 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. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#define SUN8I_H3_THS_CLK_ENABLE 31 ++#define SUN8I_H3_THS_CLK_DIVIDER_SHIFT 0 ++#define SUN8I_H3_THS_CLK_DIVIDER_WIDTH 2 ++ ++static DEFINE_SPINLOCK(sun8i_h3_ths_clk_lock); ++ ++static const struct clk_div_table sun8i_h3_ths_clk_table[] __initconst = { ++ { .val = 0, .div = 1 }, ++ { .val = 1, .div = 2 }, ++ { .val = 2, .div = 4 }, ++ { .val = 3, .div = 6 }, ++ { } /* sentinel */ ++}; ++ ++static void __init sun8i_h3_ths_clk_setup(struct device_node *node) ++{ ++ struct clk *clk; ++ struct clk_gate *gate; ++ struct clk_divider *div; ++ const char *parent; ++ const char *clk_name = node->name; ++ void __iomem *reg; ++ int err; ++ ++ reg = of_io_request_and_map(node, 0, of_node_full_name(node)); ++ ++ if (IS_ERR(reg)) ++ return; ++ ++ gate = kzalloc(sizeof(*gate), GFP_KERNEL); ++ if (!gate) ++ goto err_unmap; ++ ++ div = kzalloc(sizeof(*gate), GFP_KERNEL); ++ if (!div) ++ goto err_gate_free; ++ ++ of_property_read_string(node, "clock-output-names", &clk_name); ++ parent = of_clk_get_parent_name(node, 0); ++ ++ gate->reg = reg; ++ gate->bit_idx = SUN8I_H3_THS_CLK_ENABLE; ++ gate->lock = &sun8i_h3_ths_clk_lock; ++ ++ div->reg = reg; ++ div->shift = SUN8I_H3_THS_CLK_DIVIDER_SHIFT; ++ div->width = SUN8I_H3_THS_CLK_DIVIDER_WIDTH; ++ div->table = sun8i_h3_ths_clk_table; ++ div->lock = &sun8i_h3_ths_clk_lock; ++ ++ clk = clk_register_composite(NULL, clk_name, &parent, 1, ++ NULL, NULL, ++ &div->hw, &clk_divider_ops, ++ &gate->hw, &clk_gate_ops, ++ CLK_SET_RATE_PARENT); ++ ++ if (IS_ERR(clk)) ++ goto err_div_free; ++ ++ err = of_clk_add_provider(node, of_clk_src_simple_get, clk); ++ if (err) ++ goto err_unregister_clk; ++ ++ return; ++ ++err_unregister_clk: ++ clk_unregister(clk); ++err_gate_free: ++ kfree(gate); ++err_div_free: ++ kfree(div); ++err_unmap: ++ iounmap(reg); ++} ++ ++CLK_OF_DECLARE(sun8i_h3_ths_clk, "allwinner,sun8i-h3-ths-clk", ++ sun8i_h3_ths_clk_setup); +diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig +index c77dc08..9872e66 100644 +--- a/drivers/regulator/Kconfig ++++ b/drivers/regulator/Kconfig +@@ -843,5 +843,11 @@ config REGULATOR_WM8994 + This driver provides support for the voltage regulators on the + WM8994 CODEC. + +-endif ++config REGULATOR_SY8106A ++ tristate "Silergy SY8106A" ++ depends on I2C ++ select REGMAP_I2C ++ help ++ This driver provides support for the voltage regulator SY8106A. + ++endif +diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile +index 61bfbb9..4b55f11 100644 +--- a/drivers/regulator/Makefile ++++ b/drivers/regulator/Makefile +@@ -108,6 +108,6 @@ obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o + obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o + obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o + obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o +- ++obj-$(CONFIG_REGULATOR_SY8106A) += sy8106a-regulator.o + + ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG +diff --git a/drivers/regulator/sy8106a-regulator.c b/drivers/regulator/sy8106a-regulator.c +new file mode 100644 +index 0000000..1f5492a +--- /dev/null ++++ b/drivers/regulator/sy8106a-regulator.c +@@ -0,0 +1,152 @@ ++/* ++ * sy8106a-regulator.c - Regulator device driver for SY8106A ++ * Copyright (C) 2016 Ondřej Jirman ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the ++ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, ++ * Boston, MA 02110-1301, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define SY8106A_REG_VOUT1_SEL 0x01 ++#define SY8106A_REG_VOUT_COM 0x02 ++#define SY8106A_REG_VOUT1_SEL_MASK 0x7f ++#define SY8106A_DISABLE_REG 0x01 ++ ++struct sy8106a { ++ struct regulator_dev *rdev; ++ struct regmap *regmap; ++}; ++ ++static const struct regmap_config sy8106a_regmap_config = { ++ .reg_bits = 8, ++ .val_bits = 8, ++}; ++ ++static int sy8106a_set_voltage_sel(struct regulator_dev *rdev, unsigned sel) ++{ ++ return regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg, ++ 0xff, sel | 0x80); ++} ++ ++static const struct regulator_ops sy8106a_ops = { ++ .is_enabled = regulator_is_enabled_regmap, ++ .set_voltage_sel = sy8106a_set_voltage_sel, ++ .set_voltage_time_sel = regulator_set_voltage_time_sel, ++ .get_voltage_sel = regulator_get_voltage_sel_regmap, ++ .list_voltage = regulator_list_voltage_linear, ++}; ++ ++/* Default limits measured in millivolts and milliamps */ ++#define SY8106A_MIN_MV 680 ++#define SY8106A_MAX_MV 1950 ++#define SY8106A_STEP_MV 10 ++ ++static const struct regulator_desc sy8106a_reg = { ++ .name = "SY8106A", ++ .id = 0, ++ .ops = &sy8106a_ops, ++ .type = REGULATOR_VOLTAGE, ++ .n_voltages = ((SY8106A_MAX_MV - SY8106A_MIN_MV) / SY8106A_STEP_MV) + 1, ++ .min_uV = (SY8106A_MIN_MV * 1000), ++ .uV_step = (SY8106A_STEP_MV * 1000), ++ .vsel_reg = SY8106A_REG_VOUT1_SEL, ++ .vsel_mask = SY8106A_REG_VOUT1_SEL_MASK, ++ .enable_reg = SY8106A_REG_VOUT_COM, ++ .enable_mask = SY8106A_DISABLE_REG, ++ .disable_val = SY8106A_DISABLE_REG, ++ .enable_is_inverted = 1, ++ .owner = THIS_MODULE, ++}; ++ ++/* ++ * I2C driver interface functions ++ */ ++static int sy8106a_i2c_probe(struct i2c_client *i2c, ++ const struct i2c_device_id *id) ++{ ++ struct sy8106a *chip; ++ struct device *dev = &i2c->dev; ++ struct regulator_dev *rdev = NULL; ++ struct regulator_config config = { }; ++ unsigned int selector; ++ int error; ++ ++ chip = devm_kzalloc(&i2c->dev, sizeof(struct sy8106a), GFP_KERNEL); ++ if (!chip) ++ return -ENOMEM; ++ ++ chip->regmap = devm_regmap_init_i2c(i2c, &sy8106a_regmap_config); ++ if (IS_ERR(chip->regmap)) { ++ error = PTR_ERR(chip->regmap); ++ dev_err(&i2c->dev, "Failed to allocate register map: %d\n", ++ error); ++ return error; ++ } ++ ++ config.dev = &i2c->dev; ++ config.init_data = of_get_regulator_init_data(dev, dev->of_node, &sy8106a_reg); ++ config.driver_data = chip; ++ config.regmap = chip->regmap; ++ config.of_node = dev->of_node; ++ ++ /* Probe regulator */ ++ error = regmap_read(chip->regmap, SY8106A_REG_VOUT1_SEL, &selector); ++ dev_info(&i2c->dev, "SY8106A voltage at boot: %u mV\n", SY8106A_MIN_MV + SY8106A_STEP_MV * (selector & SY8106A_REG_VOUT1_SEL_MASK)); ++ if (error) { ++ dev_err(&i2c->dev, "Failed to read voltage at probe time: %d\n", error); ++ return error; ++ } ++ ++ rdev = devm_regulator_register(&i2c->dev, &sy8106a_reg, &config); ++ if (IS_ERR(rdev)) { ++ dev_err(&i2c->dev, "Failed to register SY8106A regulator\n"); ++ return PTR_ERR(rdev); ++ } ++ ++ chip->rdev = rdev; ++ ++ i2c_set_clientdata(i2c, chip); ++ ++ return 0; ++} ++ ++static const struct i2c_device_id sy8106a_i2c_id[] = { ++ {"sy8106a", 0}, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(i2c, sy8106a_i2c_id); ++ ++static struct i2c_driver sy8106a_regulator_driver = { ++ .driver = { ++ .name = "sy8106a", ++ }, ++ .probe = sy8106a_i2c_probe, ++ .id_table = sy8106a_i2c_id, ++}; ++ ++module_i2c_driver(sy8106a_regulator_driver); ++ ++MODULE_AUTHOR("Ondřej Jirman "); ++MODULE_DESCRIPTION("Regulator device driver for Silergy SY8106A"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig +index c37eedc..bbf03e2 100644 +--- a/drivers/thermal/Kconfig ++++ b/drivers/thermal/Kconfig +@@ -381,6 +381,13 @@ config MTK_THERMAL + Enable this option if you want to have support for thermal management + controller present in Mediatek SoCs + ++config SUN8I_THS ++ tristate "sun8i THS driver" ++ depends on MACH_SUN8I ++ depends on OF ++ help ++ Enable this to support thermal reporting on some newer Allwinner SoCs. ++ + menu "Texas Instruments thermal drivers" + depends on ARCH_HAS_BANDGAP || COMPILE_TEST + depends on HAS_IOMEM +diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile +index 8e9cbc3..bb6e1a7 100644 +--- a/drivers/thermal/Makefile ++++ b/drivers/thermal/Makefile +@@ -49,3 +49,4 @@ obj-$(CONFIG_ST_THERMAL) += st/ + obj-$(CONFIG_TEGRA_SOCTHERM) += tegra_soctherm.o + obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o + obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o ++obj-$(CONFIG_SUN8I_THS) += sun8i_ths.o +diff --git a/drivers/thermal/sun8i_ths.c b/drivers/thermal/sun8i_ths.c +new file mode 100644 +index 0000000..c8468a7 +--- /dev/null ++++ b/drivers/thermal/sun8i_ths.c +@@ -0,0 +1,338 @@ ++/* ++ * sun8i THS driver ++ * ++ * Copyright (C) 2015 Josef Gajdusek ++ * ++ * This software is licensed under the terms of the GNU General Public ++ * License version 2, as published by the Free Software Foundation, and ++ * may be copied, distributed, and modified under those terms. ++ * ++ * 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. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define THS_H3_CTRL0 0x00 ++#define THS_H3_CTRL1 0x04 ++#define THS_H3_CDAT 0x14 ++#define THS_H3_CTRL2 0x40 ++#define THS_H3_INT_CTRL 0x44 ++#define THS_H3_STAT 0x48 ++#define THS_H3_ALARM_CTRL 0x50 ++#define THS_H3_SHUTDOWN_CTRL 0x60 ++#define THS_H3_FILTER 0x70 ++#define THS_H3_CDATA 0x74 ++#define THS_H3_DATA 0x80 ++ ++#define THS_H3_CTRL0_SENSOR_ACQ0_OFFS 0 ++#define THS_H3_CTRL0_SENSOR_ACQ0(x) \ ++ ((x) << THS_H3_CTRL0_SENSOR_ACQ0_OFFS) ++#define THS_H3_CTRL1_ADC_CALI_EN_OFFS 17 ++#define THS_H3_CTRL1_ADC_CALI_EN \ ++ BIT(THS_H3_CTRL1_ADC_CALI_EN_OFFS) ++#define THS_H3_CTRL1_OP_BIAS_OFFS 20 ++#define THS_H3_CTRL1_OP_BIAS(x) \ ++ ((x) << THS_H3_CTRL1_OP_BIAS_OFFS) ++#define THS_H3_CTRL2_SENSE_EN_OFFS 0 ++#define THS_H3_CTRL2_SENSE_EN \ ++ BIT(THS_H3_CTRL2_SENSE_EN_OFFS) ++#define THS_H3_CTRL2_SENSOR_ACQ1_OFFS 16 ++#define THS_H3_CTRL2_SENSOR_ACQ1(x) \ ++ ((x) << THS_H3_CTRL2_SENSOR_ACQ1_OFFS) ++ ++#define THS_H3_INT_CTRL_ALARM_INT_EN_OFFS 0 ++#define THS_H3_INT_CTRL_ALARM_INT_EN \ ++ BIT(THS_H3_INT_CTRL_ALARM_INT_EN_OFFS) ++#define THS_H3_INT_CTRL_SHUT_INT_EN_OFFS 4 ++#define THS_H3_INT_CTRL_SHUT_INT_EN \ ++ BIT(THS_H3_INT_CTRL_SHUT_INT_EN_OFFS) ++#define THS_H3_INT_CTRL_DATA_IRQ_EN_OFFS 8 ++#define THS_H3_INT_CTRL_DATA_IRQ_EN \ ++ BIT(THS_H3_INT_CTRL_DATA_IRQ_EN_OFFS) ++#define THS_H3_INT_CTRL_THERMAL_PER_OFFS 12 ++#define THS_H3_INT_CTRL_THERMAL_PER(x) \ ++ ((x) << THS_H3_INT_CTRL_THERMAL_PER_OFFS) ++ ++#define THS_H3_STAT_ALARM_INT_STS_OFFS 0 ++#define THS_H3_STAT_ALARM_INT_STS \ ++ BIT(THS_H3_STAT_ALARM_INT_STS_OFFS) ++#define THS_H3_STAT_SHUT_INT_STS_OFFS 4 ++#define THS_H3_STAT_SHUT_INT_STS \ ++ BIT(THS_H3_STAT_SHUT_INT_STS_OFFS) ++#define THS_H3_STAT_DATA_IRQ_STS_OFFS 8 ++#define THS_H3_STAT_DATA_IRQ_STS \ ++ BIT(THS_H3_STAT_DATA_IRQ_STS_OFFS) ++#define THS_H3_STAT_ALARM_OFF_STS_OFFS 12 ++#define THS_H3_STAT_ALARM_OFF_STS \ ++ BIT(THS_H3_STAT_ALARM_OFF_STS_OFFS) ++ ++#define THS_H3_ALARM_CTRL_ALARM0_T_HYST_OFFS 0 ++#define THS_H3_ALARM_CTRL_ALARM0_T_HYST(x) \ ++ ((x) << THS_H3_ALARM_CTRL_ALARM0_T_HYST_OFFS) ++#define THS_H3_ALARM_CTRL_ALARM0_T_HOT_OFFS 16 ++#define THS_H3_ALARM_CTRL_ALARM0_T_HOT(x) \ ++ ((x) << THS_H3_ALARM_CTRL_ALARM0_T_HOT_OFFS) ++ ++#define THS_H3_SHUTDOWN_CTRL_SHUT0_T_HOT_OFFS 16 ++#define THS_H3_SHUTDOWN_CTRL_SHUT0_T_HOT(x) \ ++ ((x) << THS_H3_SHUTDOWN_CTRL_SHUT0_T_HOT_OFFS) ++ ++#define THS_H3_FILTER_TYPE_OFFS 0 ++#define THS_H3_FILTER_TYPE(x) \ ++ ((x) << THS_H3_FILTER_TYPE_OFFS) ++#define THS_H3_FILTER_EN_OFFS 2 ++#define THS_H3_FILTER_EN \ ++ BIT(THS_H3_FILTER_EN_OFFS) ++ ++#define THS_H3_CTRL0_SENSOR_ACQ0_VALUE 0xff ++#define THS_H3_INT_CTRL_THERMAL_PER_VALUE 0x79 ++#define THS_H3_FILTER_TYPE_VALUE 0x2 ++#define THS_H3_CTRL2_SENSOR_ACQ1_VALUE 0x3f ++ ++struct sun8i_ths_data { ++ struct reset_control *reset; ++ struct clk *clk; ++ struct clk *busclk; ++ void __iomem *regs; ++ struct nvmem_cell *calcell; ++ struct platform_device *pdev; ++ struct thermal_zone_device *tzd; ++}; ++ ++/* Formula and parameters from the Allwinner 3.4 kernel */ ++static int sun8i_ths_reg_to_temperature(s32 reg, int divisor, int constant) ++{ ++ return constant - (reg * 1000000) / divisor; ++} ++ ++static int sun8i_ths_get_temp(void *_data, int *out) ++{ ++ struct sun8i_ths_data *data = _data; ++ ++ int val = readl(data->regs + THS_H3_DATA); ++ if (val == 0) ++ return -EINVAL; ++ ++ *out = sun8i_ths_reg_to_temperature(val, 8253, 217000); ++ return 0; ++} ++ ++static irqreturn_t sun8i_ths_irq_thread(int irq, void *_data) ++{ ++ struct sun8i_ths_data *data = _data; ++ ++ //XXX: clear only received interrupt? ++ writel(THS_H3_STAT_DATA_IRQ_STS | ++ THS_H3_STAT_ALARM_INT_STS | ++ THS_H3_STAT_ALARM_OFF_STS | ++ THS_H3_STAT_SHUT_INT_STS, ++ data->regs + THS_H3_STAT); ++ ++ thermal_zone_device_update(data->tzd); ++ ++ return IRQ_HANDLED; ++} ++ ++static int sun8i_ths_h3_init(struct platform_device *pdev, ++ struct sun8i_ths_data *data) ++{ ++ int ret; ++ size_t callen; ++ s32 *caldata; ++ ++ data->busclk = devm_clk_get(&pdev->dev, "ahb"); ++ if (IS_ERR(data->busclk)) { ++ ret = PTR_ERR(data->busclk); ++ dev_err(&pdev->dev, "failed to get ahb clk: %d\n", ret); ++ return ret; ++ } ++ ++ data->clk = devm_clk_get(&pdev->dev, "ths"); ++ if (IS_ERR(data->clk)) { ++ ret = PTR_ERR(data->clk); ++ dev_err(&pdev->dev, "failed to get ths clk: %d\n", ret); ++ return ret; ++ } ++ ++ data->reset = devm_reset_control_get(&pdev->dev, "ahb"); ++ if (IS_ERR(data->reset)) { ++ ret = PTR_ERR(data->reset); ++ dev_err(&pdev->dev, "failed to get reset: %d\n", ret); ++ return ret; ++ } ++ ++ if (data->calcell) { ++ caldata = nvmem_cell_read(data->calcell, &callen); ++ if (IS_ERR(caldata)) ++ return PTR_ERR(caldata); ++ ++ writel(be32_to_cpu(*caldata), data->regs + THS_H3_CDATA); ++ kfree(caldata); ++ } ++ ++ ret = clk_prepare_enable(data->busclk); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to enable bus clk: %d\n", ret); ++ return ret; ++ } ++ ++ ret = clk_prepare_enable(data->clk); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to enable ths clk: %d\n", ret); ++ goto err_disable_bus; ++ } ++ ++ ret = reset_control_deassert(data->reset); ++ if (ret) { ++ dev_err(&pdev->dev, "reset deassert failed: %d\n", ret); ++ goto err_disable_ths; ++ } ++ ++ /* The final sample period is calculated as follows: ++ * (THERMAL_PER + 1) * 4096 / f_clk * 2^(FILTER_TYPE + 1) ++ * ++ * This results to about 1Hz with these settings. ++ */ ++ //XXX: what's this? why it is fixed ++ ret = clk_set_rate(data->clk, 4000000); ++ if (ret) ++ goto err_disable_ths; ++ ++ writel(THS_H3_CTRL0_SENSOR_ACQ0(THS_H3_CTRL0_SENSOR_ACQ0_VALUE), ++ data->regs + THS_H3_CTRL0); ++ writel(THS_H3_INT_CTRL_THERMAL_PER(THS_H3_INT_CTRL_THERMAL_PER_VALUE) | ++ THS_H3_INT_CTRL_DATA_IRQ_EN, ++ data->regs + THS_H3_INT_CTRL); ++ writel(THS_H3_FILTER_EN | THS_H3_FILTER_TYPE(THS_H3_FILTER_TYPE_VALUE), ++ data->regs + THS_H3_FILTER); ++ writel(THS_H3_CTRL2_SENSOR_ACQ1(THS_H3_CTRL2_SENSOR_ACQ1_VALUE) | ++ THS_H3_CTRL2_SENSE_EN, ++ data->regs + THS_H3_CTRL2); ++ ++ return 0; ++ ++err_disable_ths: ++ clk_disable_unprepare(data->clk); ++err_disable_bus: ++ clk_disable_unprepare(data->busclk); ++ ++ return ret; ++} ++ ++static void sun8i_ths_h3_deinit(struct sun8i_ths_data *data) ++{ ++ reset_control_assert(data->reset); ++ clk_disable_unprepare(data->clk); ++ clk_disable_unprepare(data->busclk); ++} ++ ++static const struct thermal_zone_of_device_ops sun8i_ths_thermal_ops = { ++ .get_temp = sun8i_ths_get_temp, ++}; ++ ++static const struct of_device_id sun8i_ths_id_table[] = { ++ { ++ .compatible = "allwinner,sun8i-h3-ths", ++ }, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, sun8i_ths_id_table); ++ ++static int sun8i_ths_probe(struct platform_device *pdev) ++{ ++ struct sun8i_ths_data *data; ++ struct resource *res; ++ int ret; ++ int irq; ++ ++ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ data->pdev = pdev; ++ ++ data->calcell = devm_nvmem_cell_get(&pdev->dev, "calibration"); ++ if (IS_ERR(data->calcell)) { ++ if (PTR_ERR(data->calcell) == -EPROBE_DEFER) ++ return PTR_ERR(data->calcell); ++ ++ data->calcell = NULL; /* No calibration data */ ++ } ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ data->regs = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(data->regs)) { ++ ret = PTR_ERR(data->regs); ++ dev_err(&pdev->dev, "failed to ioremap THS registers: %d\n", ret); ++ return ret; ++ } ++ ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) { ++ dev_err(&pdev->dev, "failed to get IRQ: %d\n", irq); ++ return irq; ++ } ++ ++ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, ++ sun8i_ths_irq_thread, IRQF_ONESHOT, ++ dev_name(&pdev->dev), data); ++ if (ret) ++ return ret; ++ ++ ret = sun8i_ths_h3_init(pdev, data); ++ if (ret) ++ return ret; ++ ++ data->tzd = thermal_zone_of_sensor_register(&pdev->dev, 0, data, ++ &sun8i_ths_thermal_ops); ++ if (IS_ERR(data->tzd)) { ++ ret = PTR_ERR(data->tzd); ++ dev_err(&pdev->dev, "failed to register thermal zone: %d\n", ++ ret); ++ goto err_deinit; ++ } ++ ++ platform_set_drvdata(pdev, data); ++ return 0; ++ ++err_deinit: ++ sun8i_ths_h3_deinit(data); ++ return ret; ++} ++ ++static int sun8i_ths_remove(struct platform_device *pdev) ++{ ++ struct sun8i_ths_data *data = platform_get_drvdata(pdev); ++ ++ thermal_zone_of_sensor_unregister(&pdev->dev, data->tzd); ++ sun8i_ths_h3_deinit(data); ++ return 0; ++} ++ ++static struct platform_driver sun8i_ths_driver = { ++ .probe = sun8i_ths_probe, ++ .remove = sun8i_ths_remove, ++ .driver = { ++ .name = "sun8i_ths", ++ .of_match_table = sun8i_ths_id_table, ++ }, ++}; ++ ++module_platform_driver(sun8i_ths_driver); ++ ++MODULE_AUTHOR("Josef Gajdusek "); ++MODULE_DESCRIPTION("sun8i THS driver"); ++MODULE_LICENSE("GPL v2"); diff --git a/patch/u-boot/u-boot-dev/u-boot-99-opi-change-build-settings.patch b/patch/u-boot/u-boot-dev/u-boot-99-opi-change-build-settings.patch index 0700db084..3fd01e826 100644 --- a/patch/u-boot/u-boot-dev/u-boot-99-opi-change-build-settings.patch +++ b/patch/u-boot/u-boot-dev/u-boot-99-opi-change-build-settings.patch @@ -2,16 +2,18 @@ diff --git a/configs/orangepi_pc_defconfig b/configs/orangepi_pc_defconfig index 4e9051d..6fba0b0 100644 --- a/configs/orangepi_pc_defconfig +++ b/configs/orangepi_pc_defconfig -@@ -17,3 +17,5 @@ CONFIG_USB_EHCI_HCD=y +@@ -17,3 +17,7 @@ CONFIG_USB_EHCI_HCD=y CONFIG_USB1_VBUS_PIN="" CONFIG_USB2_VBUS_PIN="" CONFIG_USB3_VBUS_PIN="" +CONFIG_DM=y +CONFIG_DM_GPIO=y ++CONFIG_SY8106A_VOUT1_VOLT=1200 ++CONFIG_SYS_CLK_FREQ=1008000000 diff -Nur a/configs/orangepi_h3_defconfig b/configs/orangepi_h3_defconfig --- a/configs/orangepi_h3_defconfig 1970-01-01 01:00:00.000000000 +0100 +++ b/configs/orangepi_h3_defconfig 2016-02-19 00:58:31.007705977 +0100 -@@ -0,0 +1,18 @@ +@@ -0,0 +1,20 @@ +CONFIG_ARM=y +CONFIG_ARCH_SUNXI=y +CONFIG_MACH_SUN8I_H3=y @@ -33,22 +35,26 @@ diff -Nur a/configs/orangepi_h3_defconfig b/configs/orangepi_h3_defconfig +CONFIG_USB3_VBUS_PIN="" +CONFIG_DM=y +CONFIG_DM_GPIO=y ++CONFIG_SY8106A_VOUT1_VOLT=1200 ++CONFIG_SYS_CLK_FREQ=1008000000 diff --git a/configs/orangepi_plus_defconfig b/configs/orangepi_plus_defconfig index ff124bd..d78f8c7 100644 --- a/configs/orangepi_plus_defconfig +++ b/configs/orangepi_plus_defconfig -@@ -18,3 +18,5 @@ CONFIG_SY8106A_POWER=y +@@ -18,3 +18,7 @@ CONFIG_SY8106A_POWER=y CONFIG_USB_EHCI_HCD=y CONFIG_USB1_VBUS_PIN="PG13" CONFIG_SYS_EXTRA_OPTIONS="SATAPWR=SUNXI_GPG(11)" +CONFIG_DM=y +CONFIG_DM_GPIO=y ++CONFIG_SY8106A_VOUT1_VOLT=1200 ++CONFIG_SYS_CLK_FREQ=1008000000 diff --git a/configs/Sinovoip_BPI_M2_plus_defconfig b/configs/Sinovoip_BPI_M2_plus_defconfig new file mode 100644 index 0000000..2e7c095 --- /dev/null +++ b/configs/Sinovoip_BPI_M2_plus_defconfig -@@ -0,0 +1,17 @@ +@@ -0,0 +1,18 @@ +CONFIG_ARM=y +CONFIG_ARCH_SUNXI=y +CONFIG_MACH_SUN8I_H3=y @@ -66,6 +72,7 @@ index 0000000..2e7c095 +CONFIG_USB_EHCI_HCD=y +CONFIG_DM=y +CONFIG_DM_GPIO=y ++CONFIG_SYS_CLK_FREQ=816000000 diff --git a/arch/arm/dts/sun8i-h3-bananapi-m2plus.dts b/arch/arm/dts/sun8i-h3-bananapi-m2plus.dts new file mode 100644 index 0000000..da6481f @@ -381,3 +388,42 @@ index c2f63c5..e7b6334 100644 gic: interrupt-controller@01c81000 { compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic"; reg = <0x01c81000 0x1000>, +diff --git a/configs/orangepi_2_defconfig b/configs/orangepi_2_defconfig +index ff9ac09..992cfa1 100644 +--- a/configs/orangepi_2_defconfig ++++ b/configs/orangepi_2_defconfig +@@ -16,3 +16,7 @@ CONFIG_CMD_GPIO=y + CONFIG_SY8106A_POWER=y + CONFIG_USB_EHCI_HCD=y + CONFIG_USB1_VBUS_PIN="PG13" ++CONFIG_DM=y ++CONFIG_DM_GPIO=y ++CONFIG_SY8106A_VOUT1_VOLT=1200 ++CONFIG_SYS_CLK_FREQ=1008000000 +diff --git a/configs/orangepi_one_defconfig b/configs/orangepi_one_defconfig +new file mode 100644 +index 0000000..a69961c +--- /dev/null ++++ b/configs/orangepi_one_defconfig +@@ -0,0 +1,21 @@ ++CONFIG_ARM=y ++CONFIG_ARCH_SUNXI=y ++CONFIG_MACH_SUN8I_H3=y ++CONFIG_DRAM_CLK=624 ++CONFIG_DRAM_ZQ=3881979 ++CONFIG_DRAM_ODT_EN=y ++# CONFIG_VIDEO is not set ++CONFIG_DEFAULT_DEVICE_TREE="sun8i-h3-orangepi-pc" ++# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set ++CONFIG_SPL=y ++# CONFIG_CMD_IMLS is not set ++# CONFIG_CMD_FLASH is not set ++# CONFIG_CMD_FPGA is not set ++CONFIG_CMD_GPIO=y ++CONFIG_USB_EHCI_HCD=y ++CONFIG_USB1_VBUS_PIN="" ++CONFIG_USB2_VBUS_PIN="" ++CONFIG_USB3_VBUS_PIN="" ++CONFIG_SYS_CLK_FREQ=1008000000 ++CONFIG_DM=y ++CONFIG_DM_GPIO=y diff --git a/patch/u-boot/u-boot-dev/u-boot-set-safe-axi_apb-clock-dividers.patch b/patch/u-boot/u-boot-dev/u-boot-set-safe-axi_apb-clock-dividers.patch new file mode 100644 index 000000000..128bf50eb --- /dev/null +++ b/patch/u-boot/u-boot-dev/u-boot-set-safe-axi_apb-clock-dividers.patch @@ -0,0 +1,42 @@ +diff --git a/arch/arm/mach-sunxi/clock_sun6i.c b/arch/arm/mach-sunxi/clock_sun6i.c +index 15272c9..cedddc2 100644 +--- a/arch/arm/mach-sunxi/clock_sun6i.c ++++ b/arch/arm/mach-sunxi/clock_sun6i.c +@@ -117,8 +117,8 @@ void clock_set_pll1(unsigned int clk) + sdelay(200); + + /* Switch CPU to PLL1 */ +- writel(AXI_DIV_3 << AXI_DIV_SHIFT | +- ATB_DIV_2 << ATB_DIV_SHIFT | ++ writel(AXI_DIV_4 << AXI_DIV_SHIFT | ++ ATB_DIV_4 << ATB_DIV_SHIFT | + CPU_CLK_SRC_PLL1 << CPU_CLK_SRC_SHIFT, + &ccm->cpu_axi_cfg); + } +diff --git a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h +index f2990db..b3a8575 100644 +--- a/arch/arm/include/asm/arch-sunxi/clock_sun6i.h ++++ b/arch/arm/include/asm/arch-sunxi/clock_sun6i.h +@@ -180,6 +180,7 @@ struct sunxi_ccm_reg { + #define CCM_PLL1_CTRL_N(n) ((((n) - 1) & 0x1f) << 8) + #define CCM_PLL1_CTRL_P(n) (((n) & 0x3) << 16) + #define CCM_PLL1_CTRL_EN (0x1 << 31) ++#define CCM_PLL1_CTRL_LOCK (0x1 << 28) + + #define CCM_PLL3_CTRL_M_SHIFT 0 + #define CCM_PLL3_CTRL_M_MASK (0xf << CCM_PLL3_CTRL_M_SHIFT) +diff --git a/arch/arm/mach-sunxi/clock_sun6i.c b/arch/arm/mach-sunxi/clock_sun6i.c +index cedddc2..3fe9305 100644 +--- a/arch/arm/mach-sunxi/clock_sun6i.c ++++ b/arch/arm/mach-sunxi/clock_sun6i.c +@@ -114,7 +114,9 @@ void clock_set_pll1(unsigned int clk) + writel(CCM_PLL1_CTRL_EN | CCM_PLL1_CTRL_P(p) | + CCM_PLL1_CTRL_N(clk / (24000000 * k / m)) | + CCM_PLL1_CTRL_K(k) | CCM_PLL1_CTRL_M(m), &ccm->pll1_cfg); +- sdelay(200); ++ ++ while (!(readl(&ccm->pll1_cfg) & CCM_PLL1_CTRL_LOCK)) ++ ; + + /* Switch CPU to PLL1 */ + writel(AXI_DIV_4 << AXI_DIV_SHIFT |