mirror of
https://github.com/Fishwaldo/build.git
synced 2025-03-30 02:31:46 +00:00
1238 lines
33 KiB
Text
1238 lines
33 KiB
Text
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 = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ 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 <wens@csie.org>
|
|
+ * Copyright (C) 2016 Ondřej Jirman <megous@megous.com>
|
|
+ *
|
|
+ * 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 <dt-bindings/gpio/gpio.h>
|
|
+#include <dt-bindings/input/input.h>
|
|
+#include <dt-bindings/pinctrl/sun4i-a10.h>
|
|
+
|
|
+/ {
|
|
+ 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 = <BTN_0>;
|
|
+ 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 = <SUN4I_PINCTRL_10_MA>;
|
|
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
|
|
+ };
|
|
+};
|
|
+
|
|
+&r_pio {
|
|
+ leds_r_opc: led_pins@0 {
|
|
+ allwinner,pins = "PL10";
|
|
+ allwinner,function = "gpio_out";
|
|
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
|
|
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
|
|
+ };
|
|
+
|
|
+ sw_r_opc: key_pins@0 {
|
|
+ allwinner,pins = "PL3";
|
|
+ allwinner,function = "gpio_in";
|
|
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
|
|
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
|
|
+ };
|
|
+
|
|
+ soc_reg0: soc_reg@0 {
|
|
+ allwinner,pins = "PL6";
|
|
+ allwinner,function = "gpio_out";
|
|
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
|
|
+ allwinner,pull = <SUN4I_PINCTRL_NO_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 = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
|
|
@@ -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 = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
|
|
};
|
|
|
|
+ ths: ths@01c25000 {
|
|
+ #thermal-sensor-cells = <0>;
|
|
+ compatible = "allwinner,sun8i-h3-ths";
|
|
+ reg = <0x01c25000 0x400>;
|
|
+ interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ 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 = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ 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 = <SUN4I_PINCTRL_10_MA>;
|
|
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
|
|
};
|
|
+
|
|
+ r_twi_pins_a: r_twi@0 {
|
|
+ allwinner,pins = "PL0", "PL1";
|
|
+ allwinner,function = "s_twi";
|
|
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
|
|
+ allwinner,pull = <SUN4I_PINCTRL_NO_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 <linux/clk-provider.h>
|
|
+#include <linux/of_address.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/spinlock.h>
|
|
+
|
|
+#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 <megous@megous.com>
|
|
+ *
|
|
+ * 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 <linux/err.h>
|
|
+#include <linux/i2c.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/regulator/driver.h>
|
|
+#include <linux/regulator/machine.h>
|
|
+#include <linux/regulator/of_regulator.h>
|
|
+#include <linux/regmap.h>
|
|
+
|
|
+#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 <megous@megous.com>");
|
|
+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 <linux/clk.h>
|
|
+#include <linux/interrupt.h>
|
|
+#include <linux/io.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/nvmem-consumer.h>
|
|
+#include <linux/of_device.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/reset.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/thermal.h>
|
|
+
|
|
+#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 <atx@atx.name>");
|
|
+MODULE_DESCRIPTION("sun8i THS driver");
|
|
+MODULE_LICENSE("GPL v2");
|