Compare commits
18
Commits
2f81bc20ef
...
a432aad700
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a432aad700 | ||
|
|
a409dcbfec | ||
|
|
98f77a3a33 | ||
|
|
fd2bf45a19 | ||
|
|
0c0127fdc3 | ||
|
|
4e346d269a | ||
|
|
8e4d11a333 | ||
|
|
3543245775 | ||
|
|
cbf2e8abe9 | ||
|
|
acf07bcb94 | ||
|
|
e449ec78a4 | ||
|
|
35a4c34d22 | ||
|
|
e07a012ff0 | ||
|
|
a87a23eb5b | ||
|
|
8530ab4958 | ||
|
|
bd1802e48c | ||
|
|
75be9aeeac | ||
|
|
dd86f157f6 |
No files matched your search
@@ -1,969 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
|
||||
#include <dt-bindings/mfd/max77620.h>
|
||||
#include <dt-bindings/gpio/tegra-gpio.h>
|
||||
#include <dt-bindings/thermal/thermal.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/soc/tegra-pmc.h>
|
||||
#include <dt-bindings/input/input.h>
|
||||
#include <dt-bindings/pwm/pwm.h>
|
||||
#include <dt-bindings/pinctrl/pinctrl-tegra.h>
|
||||
|
||||
#include "tegra210.dtsi"
|
||||
|
||||
/ {
|
||||
aliases {
|
||||
i2c1 = "/i2c@7000c000";
|
||||
i2c2 = "/i2c@7000c400";
|
||||
i2c3 = "/i2c@7000c500";
|
||||
i2c5 = "/i2c@7000d000";
|
||||
rtc0 = "/i2c@7000d000/max77620@3c";
|
||||
rtc1 = "/rtc@7000e000";
|
||||
serial0 = &uarta;
|
||||
serial1 = &uartb;
|
||||
serial2 = &uartc;
|
||||
serial3 = &uartd;
|
||||
};
|
||||
|
||||
chosen {
|
||||
bootargs = "root=/dev/mmcblk0p2 rw rootwait fbcon=rotate:3 printk.synchronous=1 loglevel=4 console=fb0 console=ttyGS0 earlycon";
|
||||
stdout-path = "serial1:115200n8";
|
||||
};
|
||||
|
||||
cpus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
cpu@0 {
|
||||
vdd-cpu-supply = <&cpu_max_reg>;
|
||||
};
|
||||
|
||||
idle-states {
|
||||
cpu-sleep {
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
gpu@57000000 {
|
||||
status = "okay";
|
||||
vdd-supply = <&gpu_max_reg>;
|
||||
};
|
||||
|
||||
pcie@1003000 {
|
||||
status = "okay";
|
||||
|
||||
avdd-pll-uerefe-supply = <&max77620_ldo1>;
|
||||
hvddio-pex-supply = <&max77620_sd3>;
|
||||
dvddio-pex-supply = <&max77620_ldo1>;
|
||||
dvdd-pex-pll-supply = <&max77620_ldo1>;
|
||||
hvdd-pex-pll-e-supply = <&max77620_sd3>;
|
||||
vddio-pex-ctl-supply = <&max77620_sd3>;
|
||||
|
||||
pci@1,0 {
|
||||
phys = <&{/padctl@7009f000/pads/pcie/lanes/pcie-3}>, /* Referred to plat config */
|
||||
<&{/padctl@7009f000/pads/pcie/lanes/pcie-2}>;
|
||||
phy-names = "pcie-0", "pcie-1";
|
||||
nvidia,num-lanes = <2>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
pci@2,0 {
|
||||
phys = <&{/padctl@7009f000/pads/pcie/lanes/pcie-0}>;
|
||||
phy-names = "pcie-0";
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
|
||||
host1x@50000000 {
|
||||
dsia: dsi@54300000 {
|
||||
status = "okay";
|
||||
|
||||
panel@0 {
|
||||
compatible = "nintendo,panel-nx-dsi";
|
||||
reset-gpios = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_HIGH>;
|
||||
backlight = <&backlight>;
|
||||
vdd1-supply = <&v_pavdd_5v0>;
|
||||
vdd2-supply = <&v_navdd_5v0>;
|
||||
};
|
||||
};
|
||||
|
||||
/* tegradc.0: DSI */
|
||||
dc@54200000 {
|
||||
status = "okay";
|
||||
pavdd_lcd-supply = <&v_pavdd_5v0>;
|
||||
navdd_lcd-supply = <&v_navdd_5v0>;
|
||||
dvdd_lcd-supply = <&max77620_sd3>;
|
||||
vdd_lcd_bl_en-supply = <&lcd_bl_en>;
|
||||
nvidia,outputs = <&dsia>;
|
||||
};
|
||||
|
||||
/* tegradc.1: DP */
|
||||
dc@54240000 {
|
||||
status = "okay";
|
||||
avdd_hdmi-supply = <&max77620_ldo8>; /* 1V05 */
|
||||
avdd_hdmi_pll-supply = <&max77620_sd3>; /* 1V8 */
|
||||
// vdd_hdmi_5v0-supply = <&vdd_hdmi>; /* 5V0 GPIO_PCC7 fixed reg */
|
||||
|
||||
vdd-dp-pwr-supply = <&vdd_3v3>;
|
||||
avdd-dp-pll-supply = <&max77620_sd3>;
|
||||
vdd-dp-pad-supply = <&max77620_ldo8>;
|
||||
|
||||
extcon-cables = <&bm92t 3>;
|
||||
extcon-cable-names = "typec1";
|
||||
|
||||
nvidia,outputs = <&sor1>;
|
||||
};
|
||||
|
||||
dpaux1: dpaux@54040000 {
|
||||
status = "okay";
|
||||
vdd-supply = <&v_pavdd_5v0>;
|
||||
};
|
||||
|
||||
sor1: sor@54580000 {
|
||||
status = "okay";
|
||||
nvidia,dpaux = <&dpaux1>;
|
||||
|
||||
avdd-io-hdmi-dp-supply = <&max77620_ldo8>;
|
||||
vdd-hdmi-dp-pll-supply = <&max77620_sd3>;
|
||||
|
||||
nvidia,hpd-gpio = <&gpio TEGRA_GPIO(CC, 1) GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
||||
vi: i2c@546c0000 {
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
|
||||
clock@70110000 {
|
||||
status = "okay";
|
||||
nvidia,cf = <6>;
|
||||
nvidia,ci = <0>;
|
||||
nvidia,cg = <2>;
|
||||
nvidia,droop-ctrl = <0x00000f00>;
|
||||
nvidia,force-mode = <1>;
|
||||
nvidia,i2c-fs-rate = <400000>;
|
||||
nvidia,sample-rate = <12500>;
|
||||
vdd-cpu-supply = <&cpu_max_reg>;
|
||||
};
|
||||
|
||||
memory {
|
||||
device_type = "memory";
|
||||
reg = <0x0 0x80000000 0x0 0x80000000>;
|
||||
};
|
||||
|
||||
reserved-memory {
|
||||
/delete-node/ vpr-carveout;
|
||||
/delete-node/ iram-carveout;
|
||||
};
|
||||
|
||||
r2p {
|
||||
compatible = "tegra-r2p";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
/* debug port */
|
||||
serial@70006000 {
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
/* joycon ports:
|
||||
invert TXD and RTS via IRDA_CSR
|
||||
start @ 1000000 baud, switch to 3000000
|
||||
when they are >= 3000000 baud, use 2 stop bits
|
||||
use flow control
|
||||
Note: hsuart driver is required for flow control
|
||||
*/
|
||||
/* right joycon */
|
||||
serial@70006040 {
|
||||
status = "okay";
|
||||
compatible = "nvidia,tegra124-hsuart", "nvidia,tegra30-hsuart";
|
||||
nvidia,invert-txd;
|
||||
nvidia,invert-rts;
|
||||
reset-names = "serial";
|
||||
|
||||
joyconr {
|
||||
status = "okay";
|
||||
compatible = "nintendo,joycon-serdev";
|
||||
charger-supply = <&en_vdd_jcr_chgr>;
|
||||
detect-en-gpios = <&gpio TEGRA_GPIO(G, 0) GPIO_ACTIVE_HIGH>;
|
||||
detect-gpios = <&gpio TEGRA_GPIO(H, 6) GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
||||
|
||||
/* left joycon */
|
||||
serial@70006200 {
|
||||
status = "okay";
|
||||
compatible = "nvidia,tegra124-hsuart", "nvidia,tegra30-hsuart";
|
||||
nvidia,invert-txd;
|
||||
nvidia,invert-rts;
|
||||
reset-names = "serial";
|
||||
|
||||
joyconl {
|
||||
status = "okay";
|
||||
compatible = "nintendo,joycon-serdev";
|
||||
charger-supply = <&en_vdd_jcl_chgr>;
|
||||
detect-en-gpios = <&gpio TEGRA_GPIO(D, 1) GPIO_ACTIVE_HIGH>;
|
||||
detect-gpios = <&gpio TEGRA_GPIO(E, 6) GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
||||
|
||||
/* bluetooth */
|
||||
serial@70006300 {
|
||||
dma-names = "tx";
|
||||
status = "okay";
|
||||
compatible = "nvidia,tegra124-hsuart", "nvidia,tegra30-hsuart";
|
||||
reset-names = "serial";
|
||||
|
||||
bluetooth {
|
||||
compatible = "brcm,bcm43438-bt";
|
||||
vbat-supply = <&battery_reg>;
|
||||
vddio-supply = <&battery_reg>;
|
||||
shutdown-gpios = <&gpio TEGRA_GPIO(H, 4) GPIO_ACTIVE_HIGH>;
|
||||
device-wakeup-gpios = <&gpio TEGRA_GPIO(H, 3) GPIO_ACTIVE_LOW>;
|
||||
max-speed = <3000000>; /* Max supported 4 MBaud */
|
||||
sco-routing = <1>; /* Over HCI */
|
||||
};
|
||||
};
|
||||
|
||||
clk32k_in: clock-32k {
|
||||
compatible = "fixed-clock";
|
||||
clock-frequency = <32768>;
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
|
||||
backlight: backlight {
|
||||
compatible = "pwm-backlight";
|
||||
pwms = <&pwm 0 33898>;
|
||||
pwm-names = "backlight";
|
||||
brightness-levels = <
|
||||
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
||||
17 18 19 20 21 22 23 24 25 26 27 28 29 30
|
||||
31 32 33 34 35 36 37 38 39 40 41 42 43 44
|
||||
45 46 47 48 49 50 51 52 53 54 55 56 57 58
|
||||
59 60 61 62 63 64 65 66 67 68 69 70 71 72
|
||||
73 74 75 76 77 78 79 80 81 82 83 84 85 86
|
||||
87 88 89 90 91 92 93 94 95 96 97 98 99 100
|
||||
>;
|
||||
default-brightness-level = <50>;
|
||||
enable-gpios = <&gpio TEGRA_GPIO(V, 1) GPIO_ACTIVE_HIGH>;
|
||||
power-supply = <&max77620_sd3>;
|
||||
};
|
||||
|
||||
/* Fixed regulators */
|
||||
battery_reg: vdd-ac-bat {
|
||||
compatible = "regulator-fixed";
|
||||
status = "okay";
|
||||
regulator-name = "vdd-ac-bat";
|
||||
regulator-min-microvolt = <4800000>;
|
||||
regulator-max-microvolt = <4800000>;
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
};
|
||||
|
||||
vdd_3v3: vdd-3v3 {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "vdd-3v3";
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-always-on;
|
||||
gpio = <&max77620 3 0>;
|
||||
enable-active-high;
|
||||
regulator-enable-ramp-delay = <160>;
|
||||
regulator-disable-ramp-delay = <10000>;
|
||||
};
|
||||
|
||||
max77620_gpio7: avdd-dsi-csi-1v2 {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "max77620-gpio7";
|
||||
regulator-min-microvolt = <1200000>;
|
||||
regulator-max-microvolt = <1200000>;
|
||||
regulator-boot-on; /* Must be set for seamless display */
|
||||
gpio = <&max77620 7 0>;
|
||||
enable-active-high;
|
||||
regulator-enable-ramp-delay = <240>;
|
||||
regulator-disable-ramp-delay = <11340>;
|
||||
vin-supply = <&max77620_ldo0>;
|
||||
};
|
||||
|
||||
lcd_bl_en: lcd-bl-en {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "lcd-bl-en";
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <1800000>;
|
||||
gpio = <&gpio TEGRA_GPIO(V, 1) 0>;
|
||||
regulator-boot-on; /* Must be set for seamless display */
|
||||
enable-active-high;
|
||||
regulator-always-on;
|
||||
regulator-state-mem {
|
||||
regulator-off-in-suspend;
|
||||
};
|
||||
};
|
||||
|
||||
en_vdd_sd: en-vdd-sd {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "en-vdd-sd";
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
gpio = <&gpio TEGRA_GPIO(E, 4) 0>;
|
||||
enable-active-high;
|
||||
regulator-enable-ramp-delay = <472>;
|
||||
regulator-disable-ramp-delay = <4880>;
|
||||
vin-supply = <&vdd_3v3>;
|
||||
};
|
||||
|
||||
/* LCD Power Enable +5V. Rohm BD8316GWL. */
|
||||
v_pavdd_5v0: v-pavdd-5v0 {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "v_pavdd_5v0";
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <1800000>;
|
||||
gpio = <&gpio TEGRA_GPIO(I, 0) 0>;
|
||||
enable-active-high;
|
||||
regulator-boot-on; /* Must be set for seamless display */
|
||||
regulator-enable-ramp-delay = <232>;
|
||||
};
|
||||
|
||||
/* LCD Power Enable -5V. Rohm BD8316GWL. */
|
||||
v_navdd_5v0: v-navdd-5v0 {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "v_navdd_5v0";
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <1800000>;
|
||||
gpio = <&gpio TEGRA_GPIO(I, 1) 0>;
|
||||
enable-active-high;
|
||||
regulator-boot-on; /* Must be set for seamless display */
|
||||
regulator-enable-ramp-delay = <232>;
|
||||
};
|
||||
|
||||
/* Joycon/Fan power (battery). Maxim MAX8969EWL53+. */
|
||||
v_vdd50_a: v-vdd50-a {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "v_vdd50_a";
|
||||
regulator-min-microvolt = <5300000>;
|
||||
regulator-max-microvolt = <5300000>;
|
||||
gpio = <&gpio TEGRA_GPIO(A, 5) 0>;
|
||||
enable-active-high;
|
||||
};
|
||||
|
||||
/* Joycon/Fan power (usb). DC0 on Odin. Maxim MAX8969EWL53+ on Modin. */
|
||||
v_vdd50_b: v-vdd50-b {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "v_vdd50_b";
|
||||
regulator-min-microvolt = <5000000>;
|
||||
regulator-max-microvolt = <5000000>;
|
||||
gpio = <&gpio TEGRA_GPIO(CC, 4) 0>;
|
||||
enable-active-high;
|
||||
};
|
||||
|
||||
v_vdd5v3: v-vdd5v3 {
|
||||
compatible = "regulator-fixed";
|
||||
status = "okay"; /* Only enabled on Modin/Vali/Fric */
|
||||
regulator-name = "v_vdd5v3";
|
||||
regulator-min-microvolt = <5300000>;
|
||||
regulator-max-microvolt = <5300000>;
|
||||
gpio = <&gpio TEGRA_GPIO(X, 3) 0>;
|
||||
enable-active-high;
|
||||
regulator-enable-ramp-delay = <10000>;
|
||||
};
|
||||
|
||||
vdd3v3_gc: vdd3v3-gc {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "vdd3v3_gc";
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
gpio = <&gpio TEGRA_GPIO(E, 5) 0>;
|
||||
enable-active-high;
|
||||
regulator-enable-ramp-delay = <472>;
|
||||
regulator-disable-ramp-delay = <4880>;
|
||||
vin-supply = <&vdd_3v3>;
|
||||
};
|
||||
|
||||
/* TI TCR2EE48 4.8V */
|
||||
en_vdd_jcl_chgr: left-joycon-charger {
|
||||
compatible = "regulator-fixed";
|
||||
status = "okay";
|
||||
regulator-name = "left-joycon-charger";
|
||||
regulator-min-microvolt = <4800000>;
|
||||
regulator-max-microvolt = <4800000>;
|
||||
gpio = <&gpio TEGRA_GPIO(CC, 3) GPIO_ACTIVE_HIGH>;
|
||||
enable-active-high;
|
||||
vin-supply = <&v_vdd50_a>;
|
||||
regulator-state-mem {
|
||||
regulator-off-in-suspend;
|
||||
};
|
||||
};
|
||||
|
||||
/* TI TCR2EE48 4.8V */
|
||||
en_vdd_jcr_chgr: right-joycon-charger {
|
||||
compatible = "regulator-fixed";
|
||||
status = "okay";
|
||||
regulator-name = "right-joycon-charger";
|
||||
regulator-min-microvolt = <4800000>;
|
||||
regulator-max-microvolt = <4800000>;
|
||||
gpio = <&gpio TEGRA_GPIO(K, 3) GPIO_ACTIVE_HIGH>;
|
||||
enable-active-high;
|
||||
vin-supply = <&v_vdd50_a>;
|
||||
regulator-state-mem {
|
||||
regulator-off-in-suspend;
|
||||
};
|
||||
};
|
||||
|
||||
/* SDMMC4 for EMMC */
|
||||
mmc@700b0600 {
|
||||
status = "disabled";
|
||||
bus-width = <8>;
|
||||
max-frequency = <200000000>;
|
||||
|
||||
cap-mmc-highspeed;
|
||||
mmc-ddr-1_8v;
|
||||
mmc-hs200-1_8v;
|
||||
mmc-hs400-1_8v;
|
||||
non-removable;
|
||||
|
||||
vqmmc-supply = <&max77620_sd3>;
|
||||
vmmc-supply = <&vdd_3v3>;
|
||||
};
|
||||
|
||||
/* SDMMC3 Not Used */
|
||||
mmc@700b0400 {
|
||||
status = "disabled";
|
||||
|
||||
vqmmc-supply = <&max77620_sd3>;
|
||||
vmmc-supply = <&vdd_3v3>;
|
||||
};
|
||||
|
||||
/* SDMMC2 for Gamecard */
|
||||
mmc@700b0200 {
|
||||
status = "disabled";
|
||||
bus-width = <8>;
|
||||
max-frequency = <200000000>;
|
||||
|
||||
mmc-ddr-1_8v;
|
||||
mmc-hs400-1_8v;
|
||||
mmc-hs200-1_8v;
|
||||
cap-mmc-highspeed;
|
||||
cap-sd-highspeed;
|
||||
non-removable;
|
||||
|
||||
vqmmc-supply = <&max77620_sd3>;
|
||||
vmmc-supply = <&vdd_3v3>;
|
||||
};
|
||||
|
||||
/* SDMMC1 for SD Card */
|
||||
mmc@700b0000 {
|
||||
status = "okay";
|
||||
bus-width = <4>;
|
||||
max-frequency = <200000000>;
|
||||
|
||||
cap-sd-highspeed;
|
||||
sd-uhs-sdr12;
|
||||
sd-uhs-sdr50;
|
||||
sd-uhs-sdr104;
|
||||
|
||||
cd-gpios = <&gpio TEGRA_GPIO(Z, 1) GPIO_ACTIVE_LOW>;
|
||||
|
||||
vmmc-supply = <&en_vdd_sd>;
|
||||
vqmmc-supply = <&max77620_ldo2>;
|
||||
};
|
||||
|
||||
hda@70030000 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
/* i2c1 @ 100000hz
|
||||
1c: realtek 5639
|
||||
18: rohm usb-pd
|
||||
4c: ti temperature sensor
|
||||
6b: ti charger
|
||||
36: maxim fuel gauge
|
||||
*/
|
||||
i2c@7000c000 {
|
||||
status = "okay";
|
||||
clock-frequency = <100000>;
|
||||
|
||||
bq24193@6b {
|
||||
compatible = "ti,bq24193";
|
||||
reg = <0x6b>;
|
||||
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <TEGRA_GPIO(Z, 0) IRQ_TYPE_LEVEL_LOW>;
|
||||
|
||||
monitored-battery = <&fuel_gauge>;
|
||||
#extcon-cells = <1>;
|
||||
|
||||
omit-battery-class;
|
||||
|
||||
battery_charger: charger {
|
||||
regulator-name = "batt_regulator";
|
||||
regulator-max-microamp = <4500000>;
|
||||
};
|
||||
|
||||
usb0_vbus: usb-otg-vbus {
|
||||
regulator-name = "vbus_regulator";
|
||||
};
|
||||
};
|
||||
|
||||
fuel_gauge: fuel-gauge@36 {
|
||||
compatible = "maxim,max17050";
|
||||
status = "okay";
|
||||
reg = <0x36>;
|
||||
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <TEGRA_GPIO(Y, 0) IRQ_TYPE_NONE>;
|
||||
|
||||
/* Actual is 5000 but driver does not account for CGAIN */
|
||||
/* And does not take into account Rsense and CGAIN for capacity */
|
||||
maxim,rsns-microohm = <10000>;
|
||||
maxim,over-heat-temp = <600>;
|
||||
maxim,dead-volt = <3000>;
|
||||
maxim,over-volt = <4208>; /* Actual: 4258 mV */
|
||||
|
||||
#thermal-sensor-cells = <0>;
|
||||
};
|
||||
|
||||
rt5639: audio-codec@1c {
|
||||
status = "okay";
|
||||
compatible = "realtek,rt5639";
|
||||
reg = <0x1c>;
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <TEGRA_GPIO(BB, 4) IRQ_TYPE_EDGE_RISING>;
|
||||
realtek,ldo1-en-gpios = <&gpio TEGRA_GPIO(Z, 4) GPIO_ACTIVE_HIGH>;
|
||||
realtek,over-current-threshold-microamp = <600>;
|
||||
realtek,over-current-scale-factor = <2>;
|
||||
realtek,jack-detect-is-jd1;
|
||||
};
|
||||
|
||||
/* PD Chip */
|
||||
bm92t: bm92t@18 {
|
||||
compatible = "rohm,bm92t";
|
||||
reg = <0x18>;
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <TEGRA_GPIO(K, 4) IRQ_TYPE_EDGE_RISING>;
|
||||
#extcon-cells = <1>;
|
||||
pd_bat_chg-supply = <&battery_charger>;
|
||||
vbus-source-supply = <&v_vdd5v3>;
|
||||
vbus-supply = <&usb0_vbus>;
|
||||
|
||||
rohm,dp-lanes = <2>;
|
||||
rohm,dp-signal-toggle-on-resume;
|
||||
|
||||
/* Absolute max is 2.4A, constrained by BQ24193 ILIM */
|
||||
rohm,pd-5v-current-limit-ma = <2000>;
|
||||
rohm,pd-9v-current-limit-ma = <2000>;
|
||||
rohm,pd-12v-current-limit-ma = <1500>;
|
||||
rohm,pd-15v-current-limit-ma = <1200>;
|
||||
|
||||
port {
|
||||
usb_con_ep: endpoint {
|
||||
remote-endpoint = <&usb_port_0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
tmp451: temperature-sensor@4c {
|
||||
compatible = "ti,tmp451";
|
||||
status = "okay";
|
||||
reg = <0x4c>;
|
||||
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <TEGRA_GPIO(X, 4) IRQ_TYPE_EDGE_FALLING>;
|
||||
vcc-supply = <&battery_reg>;
|
||||
|
||||
#thermal-sensor-cells = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
/* i2c3 @ 400000hz
|
||||
49: stm touchscreen controller
|
||||
*/
|
||||
i2c@7000c500 {
|
||||
status = "okay";
|
||||
clock-frequency = <400000>;
|
||||
|
||||
touchscreen@49 {
|
||||
compatible = "stm,ftm4_fts";
|
||||
status = "okay";
|
||||
reg = <0x49>;
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <TEGRA_GPIO(X, 1) IRQ_TYPE_LEVEL_LOW>;
|
||||
vdd-tp-2v9-supply = <&max77620_ldo6>;
|
||||
stm,vio-gpio = <&gpio TEGRA_GPIO(J, 7) GPIO_ACTIVE_HIGH>;
|
||||
stm,irq_type = <0x2000>; /* IRQF_ONESHOT */
|
||||
stm,regulator_avdd = "vdd-tp-2v9";
|
||||
stm,max_coords = <1280 720>;
|
||||
stm,max-real-coords = <1264 704>;
|
||||
stm,edge-offset = <15 15>;
|
||||
stm,delayed-open;
|
||||
stm,delayed-open-time = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/* i2c2 @ 400000hz
|
||||
29: rohm ambient light sensor
|
||||
*/
|
||||
i2c@7000c400 {
|
||||
status = "okay";
|
||||
clock-frequency = <400000>;
|
||||
|
||||
bh1730fvc: bh1730fvc@29 {
|
||||
status = "disabled";
|
||||
compatible = "rohm,bh1730fvc";
|
||||
reg = <0x29>;
|
||||
als-vid-supply = <&max77620_ldo6>;
|
||||
als-vdd-supply = <&vdd_3v3>;
|
||||
rohm,integration-cycle = <38>;
|
||||
rohm,lux-multiplier = <3600>;
|
||||
|
||||
rohm,opt-win-coeff = < 500 5002 7502
|
||||
754 2250 2000
|
||||
1029 1999 1667
|
||||
1373 884 583
|
||||
1879 309 165>;
|
||||
|
||||
rohm,gain-coeff = < 2500 0
|
||||
1600 7800
|
||||
10 50000
|
||||
0 1000>;
|
||||
};
|
||||
};
|
||||
|
||||
spi@7000da00 {
|
||||
status = "disabled"; /* Disabled for Vali */
|
||||
num-cs = <1>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
// spi-cs-setup-delay-ns = <2>;
|
||||
// spi-cs-hold-delay-ns = <2>;
|
||||
// spi-cs-inactive-delay-ns = <2>;
|
||||
|
||||
/*
|
||||
* Model WHOAMI:
|
||||
* LSM6DS3H 0x69, LSM6DSE 0x6A, LSM6DSO 0x6C, ICM40607 0x38.
|
||||
*/
|
||||
gyroscope: imu@0 {
|
||||
reg = <0>;
|
||||
status = "disabled";
|
||||
compatible = "st,lsm6ds3h";
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
spi-max-frequency = <8000000>;
|
||||
|
||||
/* SPI Mode-3 */
|
||||
spi-cpha;
|
||||
spi-cpol;
|
||||
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <TEGRA_GPIO(X, 2) IRQ_TYPE_LEVEL_HIGH>;
|
||||
|
||||
vdd-supply = <&battery_reg>;
|
||||
vddio-supply = <&battery_reg>;
|
||||
|
||||
st,drdy-int-pin = <2>;
|
||||
|
||||
nvidia,rx-clk-tap-delay = <0x1f>;
|
||||
nvidia,tx-clk-tap-delay = <0x0>;
|
||||
|
||||
|
||||
mount-matrix =
|
||||
"1", "0", "0", /* X: x */
|
||||
"0", "1", "0", /* Y: y */
|
||||
"0", "0", "1"; /* Z: z */
|
||||
};
|
||||
};
|
||||
|
||||
gpio-keys {
|
||||
compatible = "gpio-keys";
|
||||
|
||||
key-volume-down {
|
||||
label = "Volume Down";
|
||||
gpios = <&gpio TEGRA_GPIO(X, 7) GPIO_ACTIVE_LOW>;
|
||||
linux,input-type = <EV_KEY>;
|
||||
linux,code = <KEY_VOLUMEDOWN>;
|
||||
debounce-interval = <10>;
|
||||
};
|
||||
|
||||
key-volume-up {
|
||||
label = "Volume Up";
|
||||
gpios = <&gpio TEGRA_GPIO(X, 6) GPIO_ACTIVE_LOW>;
|
||||
linux,input-type = <EV_KEY>;
|
||||
linux,code = <KEY_VOLUMEUP>;
|
||||
debounce-interval = <10>;
|
||||
};
|
||||
};
|
||||
|
||||
gpio@6000d000 {
|
||||
boot-default-output-high {
|
||||
gpio-hog;
|
||||
output-high;
|
||||
gpios = <TEGRA_GPIO(H, 1) GPIO_ACTIVE_HIGH>; /* Wi-Fi Reset. Powered on by default. */
|
||||
line-name = "boot-default-output-high";
|
||||
};
|
||||
};
|
||||
|
||||
pwm@7000a000 {
|
||||
status = "okay";
|
||||
#pwm-cells = <2>;
|
||||
};
|
||||
|
||||
fan: pwm-fan {
|
||||
compatible = "pwm-fan";
|
||||
cooling-min-state = <0>;
|
||||
cooling-max-state = <5>;
|
||||
#cooling-cells = <2>;
|
||||
pwms = <&pwm 1 33333>;
|
||||
fan-supply = <&v_vdd50_a>;
|
||||
enable-gpios = <&gpio TEGRA_GPIO(A, 5) GPIO_ACTIVE_HIGH>;
|
||||
/* cooling level (0, 1, 2, 3, 4, 5) - pwm inverted */
|
||||
cooling-levels = <255 204 153 102 51 0>;
|
||||
};
|
||||
|
||||
sound {
|
||||
status = "okay";
|
||||
compatible = "nvidia,tegra-audio-rt5640-tx1",
|
||||
"nvidia,tegra-audio-rt5640";
|
||||
nvidia,model = "Nintendo Switch";
|
||||
|
||||
nvidia,audio-codec = <&rt5639>;
|
||||
nvidia,i2s-controller = <&tegra_i2s1>;
|
||||
// nvidia,hp-det-gpios = <&gpio 143 0>;
|
||||
|
||||
clocks = <&tegra_car TEGRA210_CLK_PLL_A>,
|
||||
<&tegra_car TEGRA210_CLK_PLL_A_OUT0>,
|
||||
<&tegra_car TEGRA210_CLK_CLK_M>;
|
||||
clock-names = "pll_a", "plla_out0", "mclk";
|
||||
|
||||
assigned-clocks = <&tegra_car TEGRA210_CLK_PLL_A>,
|
||||
<&tegra_car TEGRA210_CLK_PLL_A_OUT0>,
|
||||
<&tegra_car TEGRA210_CLK_D_AUDIO>,
|
||||
<&tegra_car TEGRA210_CLK_EXTERN1>;
|
||||
assigned-clock-rates = <368640000>, <36864000>,
|
||||
<36864000>, <12288000>;
|
||||
|
||||
nvidia,audio-routing =
|
||||
"Headphones", "HPOL",
|
||||
"Headphones", "HPOR",
|
||||
"Speakers", "SPORP",
|
||||
"Speakers", "SPORN",
|
||||
"Speakers", "SPOLP",
|
||||
"Speakers", "SPOLN",
|
||||
"IN1P", "Mic Jack",
|
||||
"IN1P", "Mic Jack";
|
||||
};
|
||||
|
||||
thermal-zones {
|
||||
cpu {
|
||||
polling-delay-passive = <250>;
|
||||
polling-delay = <500>;
|
||||
status = "okay";
|
||||
|
||||
/* Based on Console profile SoC: 95% (100% at Handheld) */
|
||||
coefficients = <95 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0>;
|
||||
thermal-sensors = <&tmp451 1>;
|
||||
|
||||
trips {
|
||||
cpu_critical: cpu-critical {
|
||||
temperature = <102500>;
|
||||
hysteresis = <0>;
|
||||
type = "critical";
|
||||
};
|
||||
|
||||
cpu_heavy: cpu-heavy {
|
||||
temperature = <98500>;
|
||||
hysteresis = <1000>;
|
||||
type = "hot";
|
||||
};
|
||||
|
||||
cpu_throttle: cpu-throttle {
|
||||
temperature = <89000>;
|
||||
hysteresis = <2000>;
|
||||
type = "passive";
|
||||
};
|
||||
|
||||
cpu_cap_trip1: cpu-cap-trip1 {
|
||||
temperature = <58000>;
|
||||
hysteresis = <2000>;
|
||||
type = "active";
|
||||
};
|
||||
|
||||
cpu_floor_trip1: cpu-floor-trip1 {
|
||||
temperature = <53000>;
|
||||
hysteresis = <2000>;
|
||||
type = "active";
|
||||
};
|
||||
|
||||
cpu_cap_trip0: cpu-cap-trip0 {
|
||||
temperature = <48000>;
|
||||
hysteresis = <2000>;
|
||||
type = "active";
|
||||
};
|
||||
|
||||
cpu_floor_trip0: cpu-floor-trip0 {
|
||||
temperature = <43000>;
|
||||
hysteresis = <2000>;
|
||||
type = "active";
|
||||
};
|
||||
};
|
||||
|
||||
cooling-maps {
|
||||
map0 {
|
||||
cooling-device = <&fan THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
|
||||
trip = <&cpu_critical>;
|
||||
};
|
||||
|
||||
map1 {
|
||||
cooling-device = <&fan THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
|
||||
trip = <&cpu_heavy>;
|
||||
};
|
||||
|
||||
map2 {
|
||||
cooling-device = <&fan THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
|
||||
trip = <&cpu_throttle>;
|
||||
};
|
||||
|
||||
map3 {
|
||||
cooling-device = <&fan 1 1>;
|
||||
trip = <&cpu_cap_trip1>;
|
||||
};
|
||||
|
||||
map4 {
|
||||
cooling-device = <&fan 2 2>;
|
||||
trip = <&cpu_floor_trip1>;
|
||||
};
|
||||
|
||||
map5 {
|
||||
cooling-device = <&fan 3 3>;
|
||||
trip = <&cpu_cap_trip0>;
|
||||
};
|
||||
|
||||
map6 {
|
||||
cooling-device = <&fan 4 4>;
|
||||
trip = <&cpu_floor_trip0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
gpu {
|
||||
polling-delay-passive = <250>;
|
||||
polling-delay = <500>;
|
||||
status = "okay";
|
||||
thermal-sensors = <&tmp451 1>;
|
||||
|
||||
trips {
|
||||
gpu_critical: gpu-critical {
|
||||
temperature = <103000>;
|
||||
hysteresis = <0>;
|
||||
type = "critical";
|
||||
};
|
||||
|
||||
gpu_heavy: gpu-heavy {
|
||||
temperature = <100000>;
|
||||
hysteresis = <1000>;
|
||||
type = "hot";
|
||||
};
|
||||
|
||||
gpu_throttle: gpu-throttle {
|
||||
temperature = <90500>;
|
||||
hysteresis = <0>;
|
||||
type = "passive";
|
||||
};
|
||||
};
|
||||
|
||||
cooling-maps {
|
||||
map0 {
|
||||
trip = <&gpu_critical>;
|
||||
cooling-device = <&fan THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
|
||||
};
|
||||
map1 {
|
||||
trip = <&gpu_heavy>;
|
||||
cooling-device = <&fan THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
|
||||
};
|
||||
map2 {
|
||||
trip = <&gpu_throttle>;
|
||||
cooling-device = <&fan THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
pmic {
|
||||
status = "okay";
|
||||
polling-delay-passive = <250>;
|
||||
polling-delay = <500>;
|
||||
thermal-sensors = <&max77620>;
|
||||
|
||||
trips {
|
||||
pmic_die_warn_temp_thresh: hot-die {
|
||||
temperature = <120000>;
|
||||
type = "hot";
|
||||
hysteresis = <0>;
|
||||
};
|
||||
|
||||
pmic_die_cirt_temp_thresh: critical-die {
|
||||
temperature = <140000>;
|
||||
type = "critical";
|
||||
hysteresis = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
cooling-maps {
|
||||
map0 {
|
||||
trip = <&pmic_die_warn_temp_thresh>;
|
||||
cooling-device = <&throttle_heavy 1 1>;
|
||||
contribution = <100>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
cpu_vreg {
|
||||
status = "okay";
|
||||
polling-delay-passive = <250>;
|
||||
polling-delay = <500>;
|
||||
thermal-sensors = <&cpu_max_reg>;
|
||||
|
||||
trips {
|
||||
cpu_vreg_die_warn_temp_thresh: hot-die {
|
||||
temperature = <120000>;
|
||||
type = "hot";
|
||||
hysteresis = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
cooling-maps {
|
||||
map0 {
|
||||
trip = <&cpu_vreg_die_warn_temp_thresh>;
|
||||
cooling-device = <&throttle_heavy 1 1>;
|
||||
contribution = <100>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
gpu_vreg {
|
||||
status = "okay";
|
||||
polling-delay-passive = <250>;
|
||||
polling-delay = <500>;
|
||||
thermal-sensors = <&gpu_max_reg>;
|
||||
|
||||
trips {
|
||||
gpu_vreg_die_warn_temp_thresh: hot-die {
|
||||
temperature = <120000>;
|
||||
type = "hot";
|
||||
hysteresis = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
cooling-maps {
|
||||
/*
|
||||
* There are currently no cooling maps,
|
||||
* because there are no cooling devices.
|
||||
*/
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,9 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
|
||||
#include "tegra210b01-nx.dtsi"
|
||||
|
||||
/ {
|
||||
model = "Nintendo Switch (OLED model)";
|
||||
compatible = "nvidia,fric", "nintendo,aula", "nintendo,nx", "nvidia,tegra210b01";
|
||||
};
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,10 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
|
||||
#include "tegra210b01-nx.dtsi"
|
||||
|
||||
/ {
|
||||
|
||||
model = "Nintendo Switch (2019)";
|
||||
compatible = "nvidia,modin", "nvidia,odin", "nintendo,iowa", "nintendo,nx", "nvidia,tegra210b01";
|
||||
};
|
||||
@@ -48,6 +48,8 @@
|
||||
};
|
||||
|
||||
pinmux@700008d4 {
|
||||
compatible = "nvidia,tegra210b01-pinmux";
|
||||
|
||||
pinmux-sdmmc1-1v8-drv {
|
||||
sdmmc1 {
|
||||
nvidia,pull-down-strength = <0x8>;
|
||||
|
||||
+326
-15
@@ -31,6 +31,7 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
@@ -193,6 +194,37 @@
|
||||
*/
|
||||
#define REF_CLK_CYC_PER_DVCO_SAMPLE 4
|
||||
|
||||
/*
|
||||
* DFLL_OUTPUT_RAMP_DELAY: after the DFLL's I2C PMIC output starts
|
||||
* requesting the minimum TUNE_HIGH voltage, the minimum number of
|
||||
* microseconds to wait for the PMIC's voltage output to finish
|
||||
* slewing
|
||||
*/
|
||||
#define DFLL_OUTPUT_RAMP_DELAY 100
|
||||
|
||||
/*
|
||||
* DFLL_TUNE_HIGH_DELAY: number of microseconds to wait between tests
|
||||
* to see if the high voltage has been reached yet, during a
|
||||
* transition from the low-voltage range to the high-voltage range
|
||||
*/
|
||||
#define DFLL_TUNE_HIGH_DELAY 2000
|
||||
|
||||
/*
|
||||
* DFLL_TUNE_HIGH_MARGIN_STEPS: attempt to initially program the DFLL
|
||||
* voltage target to a (DFLL_TUNE_HIGH_MARGIN_STEPS * 10 millivolt)
|
||||
* margin above the high voltage floor, in closed-loop mode in the
|
||||
* high-voltage range
|
||||
*/
|
||||
#define DFLL_TUNE_HIGH_MARGIN_STEPS 2
|
||||
|
||||
/*
|
||||
* I2C_OUTPUT_ACTIVE_TEST_US: mandatory minimum interval (in
|
||||
* microseconds) between testing whether the I2C controller is
|
||||
* currently sending a voltage-set command. Some comments list this
|
||||
* as being a worst-case margin for "disable propagation."
|
||||
*/
|
||||
#define I2C_OUTPUT_ACTIVE_TEST_US 2
|
||||
|
||||
/*
|
||||
* REF_CLOCK_RATE: the DFLL reference clock rate currently supported by this
|
||||
* driver, in Hz
|
||||
@@ -224,6 +256,9 @@ enum dfll_ctrl_mode {
|
||||
* enum dfll_tune_range - voltage range that the driver believes it's in
|
||||
* @DFLL_TUNE_UNINITIALIZED: DFLL tuning not yet programmed
|
||||
* @DFLL_TUNE_LOW: DFLL in the low-voltage range (or open-loop mode)
|
||||
* @DFLL_TUNE_WAIT_DFLL: waiting for DFLL voltage output to reach high
|
||||
* @DFLL_TUNE_WAIT_PMIC: waiting for PMIC to react to DFLL output
|
||||
* @DFLL_TUNE_HIGH: DFLL in the high-voltage range
|
||||
*
|
||||
* Some DFLL tuning parameters may need to change depending on the
|
||||
* DVCO's voltage; these states represent the ranges that the driver
|
||||
@@ -232,7 +267,10 @@ enum dfll_ctrl_mode {
|
||||
*/
|
||||
enum dfll_tune_range {
|
||||
DFLL_TUNE_UNINITIALIZED = 0,
|
||||
DFLL_TUNE_LOW = 1,
|
||||
DFLL_TUNE_LOW,
|
||||
DFLL_TUNE_WAIT_DFLL,
|
||||
DFLL_TUNE_WAIT_PMIC,
|
||||
DFLL_TUNE_HIGH,
|
||||
};
|
||||
|
||||
|
||||
@@ -285,6 +323,10 @@ struct tegra_dfll {
|
||||
struct dfll_rate_req last_req;
|
||||
unsigned long last_unrounded_rate;
|
||||
|
||||
struct hrtimer tune_timer;
|
||||
ktime_t tune_delay;
|
||||
ktime_t tune_ramp_delay;
|
||||
|
||||
/* Parameters from DT */
|
||||
u32 droop_ctrl;
|
||||
u32 sample_rate;
|
||||
@@ -305,6 +347,11 @@ struct tegra_dfll {
|
||||
int lut_size;
|
||||
u8 lut_bottom, lut_min, lut_max, lut_safe;
|
||||
|
||||
/* tuning parameters */
|
||||
u8 tune_high_out_start;
|
||||
u8 tune_high_out_min;
|
||||
u8 tune_out_last;
|
||||
|
||||
/* PWM interface */
|
||||
enum tegra_dfll_pmu_if pmu_if;
|
||||
unsigned long pwm_rate;
|
||||
@@ -312,6 +359,9 @@ struct tegra_dfll {
|
||||
struct pinctrl_state *pwm_enable_state;
|
||||
struct pinctrl_state *pwm_disable_state;
|
||||
u32 reg_init_uV;
|
||||
|
||||
/* spinlock protecting register accesses */
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
#define clk_hw_to_dfll(_hw) container_of(_hw, struct tegra_dfll, dfll_clk_hw)
|
||||
@@ -324,6 +374,8 @@ static const char * const mode_name[] = {
|
||||
[DFLL_CLOSED_LOOP] = "closed_loop",
|
||||
};
|
||||
|
||||
static void dfll_load_i2c_lut(struct tegra_dfll *td);
|
||||
|
||||
/*
|
||||
* Register accessors
|
||||
*/
|
||||
@@ -361,6 +413,36 @@ static inline void dfll_i2c_wmb(struct tegra_dfll *td)
|
||||
dfll_i2c_readl(td, DFLL_I2C_CFG);
|
||||
}
|
||||
|
||||
/**
|
||||
* is_output_i2c_req_pending - is an I2C voltage-set command in progress?
|
||||
* @pdev: DFLL instance
|
||||
*
|
||||
* Returns 1 if an I2C request is in progress, or 0 if not. The DFLL
|
||||
* IP block requires two back-to-back reads of the I2C_REQ_PENDING
|
||||
* field to return 0 before the software can be sure that no I2C
|
||||
* request is currently pending. Also, a minimum time interval
|
||||
* between DFLL_I2C_STS reads is required by the IP block.
|
||||
*/
|
||||
static int is_output_i2c_req_pending(struct tegra_dfll *td)
|
||||
{
|
||||
u32 sts;
|
||||
|
||||
if (td->pmu_if == TEGRA_DFLL_PMU_PWM)
|
||||
return 0;
|
||||
|
||||
sts = dfll_i2c_readl(td, DFLL_I2C_STS);
|
||||
if (sts & DFLL_I2C_STS_I2C_REQ_PENDING)
|
||||
return 1;
|
||||
|
||||
udelay(I2C_OUTPUT_ACTIVE_TEST_US);
|
||||
|
||||
sts = dfll_i2c_readl(td, DFLL_I2C_STS);
|
||||
if (sts & DFLL_I2C_STS_I2C_REQ_PENDING)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dfll_is_running - is the DFLL currently generating a clock?
|
||||
* @td: DFLL instance
|
||||
@@ -452,13 +534,139 @@ static void dfll_tune_low(struct tegra_dfll *td)
|
||||
td->tune_range = DFLL_TUNE_LOW;
|
||||
|
||||
dfll_writel(td, td->soc->cvb->cpu_dfll_data.tune0_low, DFLL_TUNE0);
|
||||
dfll_writel(td, td->soc->cvb->cpu_dfll_data.tune1, DFLL_TUNE1);
|
||||
dfll_writel(td, td->soc->cvb->cpu_dfll_data.tune1_low, DFLL_TUNE1);
|
||||
dfll_wmb(td);
|
||||
|
||||
if (td->soc->set_clock_trimmers_low)
|
||||
td->soc->set_clock_trimmers_low();
|
||||
}
|
||||
|
||||
/**
|
||||
* dfll_tune_high - tune DFLL and CPU clock shaper for high voltages
|
||||
* @td: DFLL instance
|
||||
*
|
||||
* Tune the DFLL oscillator parameters and the CPU clock shaper
|
||||
* for the high-voltage range. The bottom end of the high-voltage
|
||||
* range is represented by the index td->soc->tune_high_min_millivolts.
|
||||
* Used in closed-loop mode. No return value.
|
||||
*/
|
||||
static void dfll_tune_high(struct tegra_dfll *td)
|
||||
{
|
||||
u32 tune0_high;
|
||||
u32 tune1_high;
|
||||
|
||||
td->tune_range = DFLL_TUNE_HIGH;
|
||||
|
||||
tune0_high = td->soc->cvb->cpu_dfll_data.tune0_high;
|
||||
if (!tune0_high)
|
||||
tune0_high = td->soc->cvb->cpu_dfll_data.tune0_low;
|
||||
dfll_writel(td, tune0_high, DFLL_TUNE0);
|
||||
|
||||
tune1_high = td->soc->cvb->cpu_dfll_data.tune1_high;
|
||||
if (!tune1_high)
|
||||
tune1_high = td->soc->cvb->cpu_dfll_data.tune1_low;
|
||||
dfll_writel(td, tune1_high, DFLL_TUNE1);
|
||||
|
||||
dfll_wmb(td);
|
||||
|
||||
if (td->soc->set_clock_trimmers_high)
|
||||
td->soc->set_clock_trimmers_high();
|
||||
}
|
||||
|
||||
/**
|
||||
* dfll_set_close_loop_config - prepare to switch to closed-loop mode
|
||||
* @pdev: DFLL instance
|
||||
* @req: requested output rate
|
||||
*
|
||||
* Prepare to switch the DFLL to closed-loop mode. This involves
|
||||
* switching the DFLL's tuning voltage regime (if necessary), and
|
||||
* rewriting the LUT to restrict the minimum and maximum voltages. No
|
||||
* return value.
|
||||
*/
|
||||
static void dfll_set_close_loop_config(struct tegra_dfll *td,
|
||||
struct dfll_rate_req *req)
|
||||
{
|
||||
bool sample_tune_out_last = false;
|
||||
|
||||
switch (td->tune_range) {
|
||||
case DFLL_TUNE_LOW:
|
||||
if (req->lut_index > td->tune_high_out_start) {
|
||||
hrtimer_start(&td->tune_timer, td->tune_delay,
|
||||
HRTIMER_MODE_REL);
|
||||
}
|
||||
sample_tune_out_last = true;
|
||||
break;
|
||||
|
||||
case DFLL_TUNE_HIGH:
|
||||
case DFLL_TUNE_WAIT_DFLL:
|
||||
case DFLL_TUNE_WAIT_PMIC:
|
||||
if (req->lut_index <= td->tune_high_out_start)
|
||||
dfll_tune_low(td);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
td->lut_min = td->tune_range == DFLL_TUNE_LOW ?
|
||||
0 : td->tune_high_out_min;
|
||||
|
||||
if (sample_tune_out_last && td->pmu_if == TEGRA_DFLL_PMU_I2C) {
|
||||
u32 val;
|
||||
|
||||
val = dfll_i2c_readl(td, DFLL_I2C_STS);
|
||||
td->tune_out_last = val >> DFLL_I2C_STS_I2C_LAST_SHIFT;
|
||||
td->tune_out_last &= OUT_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dfll_tune_timer_cb - timer callback while tuning low to high
|
||||
* @data: struct platform_device * of the DFLL instance
|
||||
*
|
||||
* Timer callback, used when switching from TUNE_LOW to TUNE_HIGH in
|
||||
* closed-loop mode. Waits for DFLL I2C voltage command output to
|
||||
* reach tune_high_out_min, then waits for the PMIC to react to the
|
||||
* command. No return value.
|
||||
*/
|
||||
static enum hrtimer_restart dfll_tune_timer_cb(struct hrtimer *timer)
|
||||
{
|
||||
struct tegra_dfll *td;
|
||||
u32 val, out_min, out_last;
|
||||
bool use_ramp_delay;
|
||||
|
||||
td = container_of(timer, struct tegra_dfll, tune_timer);
|
||||
|
||||
if (td->tune_range == DFLL_TUNE_WAIT_DFLL) {
|
||||
out_min = td->lut_min;
|
||||
|
||||
if (td->pmu_if == TEGRA_DFLL_PMU_I2C) {
|
||||
val = dfll_i2c_readl(td, DFLL_I2C_STS);
|
||||
out_last = val >> DFLL_I2C_STS_I2C_LAST_SHIFT;
|
||||
out_last &= OUT_MASK;
|
||||
} else {
|
||||
out_last = out_min;
|
||||
}
|
||||
|
||||
use_ramp_delay = !is_output_i2c_req_pending(td);
|
||||
use_ramp_delay |= td->tune_out_last != out_last;
|
||||
|
||||
if (use_ramp_delay &&
|
||||
(out_last >= td->tune_high_out_min) &&
|
||||
(out_min >= td->tune_high_out_min)) {
|
||||
td->tune_range = DFLL_TUNE_WAIT_PMIC;
|
||||
hrtimer_start(&td->tune_timer, td->tune_ramp_delay,
|
||||
HRTIMER_MODE_REL);
|
||||
} else {
|
||||
hrtimer_start(&td->tune_timer, td->tune_delay,
|
||||
HRTIMER_MODE_REL);
|
||||
}
|
||||
} else if (td->tune_range == DFLL_TUNE_WAIT_PMIC) {
|
||||
dfll_tune_high(td);
|
||||
}
|
||||
|
||||
return HRTIMER_NORESTART;
|
||||
}
|
||||
|
||||
/*
|
||||
* Output clock scaler helpers
|
||||
*/
|
||||
@@ -554,7 +762,6 @@ static int dfll_i2c_set_output_enabled(struct tegra_dfll *td, bool enable)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* DFLL-to-PWM controller interface
|
||||
*/
|
||||
@@ -679,10 +886,10 @@ static void dfll_load_i2c_lut(struct tegra_dfll *td)
|
||||
u32 val;
|
||||
|
||||
for (i = 0; i < MAX_DFLL_VOLTAGES; i++) {
|
||||
if (i < td->lut_min)
|
||||
lut_index = td->lut_min;
|
||||
else if (i > td->lut_max)
|
||||
lut_index = td->lut_max;
|
||||
if (i < td->lut_bottom)
|
||||
lut_index = td->lut_bottom;
|
||||
else if (i > td->lut_size - 1)
|
||||
lut_index = td->lut_size - 1;
|
||||
else
|
||||
lut_index = i;
|
||||
|
||||
@@ -813,6 +1020,28 @@ static int find_lut_index_for_rate(struct tegra_dfll *td, unsigned long rate)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* find_mv_out_cap - find the out_map index with voltage >= @mv
|
||||
* @td: DFLL instance
|
||||
* @mv: millivolts
|
||||
*
|
||||
* Find the lut index with voltage greater than or equal to @mv,
|
||||
* and return it. If all of the voltages in out_map are less than
|
||||
* @mv, then return the lut index * corresponding to the highest
|
||||
* possible voltage, even though it's less than @mv.
|
||||
*/
|
||||
static u8 find_mv_out_cap(struct tegra_dfll *td, int mv)
|
||||
{
|
||||
u8 i;
|
||||
|
||||
for (i = td->lut_bottom; i < td->lut_size; i++) {
|
||||
if (td->lut_uv[i] >= mv * 1000)
|
||||
return i;
|
||||
}
|
||||
|
||||
return i - 1; /* maximum possible output */
|
||||
}
|
||||
|
||||
/**
|
||||
* dfll_calculate_rate_request - calculate DFLL parameters for a given rate
|
||||
* @td: DFLL instance
|
||||
@@ -913,6 +1142,7 @@ static int dfll_request_rate(struct tegra_dfll *td, unsigned long rate)
|
||||
{
|
||||
int ret;
|
||||
struct dfll_rate_req req;
|
||||
unsigned long flags;
|
||||
|
||||
if (td->mode == DFLL_UNINITIALIZED) {
|
||||
dev_err(td->dev, "%s: Cannot set DFLL rate in %s mode\n",
|
||||
@@ -927,8 +1157,12 @@ static int dfll_request_rate(struct tegra_dfll *td, unsigned long rate)
|
||||
td->last_unrounded_rate = rate;
|
||||
td->last_req = req;
|
||||
|
||||
if (td->mode == DFLL_CLOSED_LOOP)
|
||||
if (td->mode == DFLL_CLOSED_LOOP) {
|
||||
spin_lock_irqsave(&td->lock, flags);
|
||||
dfll_set_close_loop_config(td, &td->last_req);
|
||||
dfll_set_frequency_request(td, &td->last_req);
|
||||
spin_unlock_irqrestore(&td->lock, flags);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -946,13 +1180,18 @@ static int dfll_request_rate(struct tegra_dfll *td, unsigned long rate)
|
||||
*/
|
||||
static int dfll_disable(struct tegra_dfll *td)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (td->mode != DFLL_OPEN_LOOP) {
|
||||
dev_err(td->dev, "cannot disable DFLL in %s mode\n",
|
||||
mode_name[td->mode]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&td->lock, flags);
|
||||
dfll_set_mode(td, DFLL_DISABLED);
|
||||
spin_unlock_irqrestore(&td->lock, flags);
|
||||
|
||||
pm_runtime_put_sync(td->dev);
|
||||
|
||||
return 0;
|
||||
@@ -1016,6 +1255,7 @@ static void dfll_set_open_loop_config(struct tegra_dfll *td)
|
||||
static int dfll_lock(struct tegra_dfll *td)
|
||||
{
|
||||
struct dfll_rate_req *req = &td->last_req;
|
||||
unsigned long flags;
|
||||
|
||||
switch (td->mode) {
|
||||
case DFLL_CLOSED_LOOP:
|
||||
@@ -1033,9 +1273,12 @@ static int dfll_lock(struct tegra_dfll *td)
|
||||
else
|
||||
dfll_i2c_set_output_enabled(td, true);
|
||||
|
||||
spin_lock_irqsave(&td->lock, flags);
|
||||
dfll_set_mode(td, DFLL_CLOSED_LOOP);
|
||||
dfll_set_close_loop_config(td, req);
|
||||
dfll_set_frequency_request(td, req);
|
||||
dfll_set_force_output_enabled(td, false);
|
||||
spin_unlock_irqrestore(&td->lock, flags);
|
||||
return 0;
|
||||
|
||||
default:
|
||||
@@ -1055,14 +1298,19 @@ static int dfll_lock(struct tegra_dfll *td)
|
||||
*/
|
||||
static int dfll_unlock(struct tegra_dfll *td)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
switch (td->mode) {
|
||||
case DFLL_CLOSED_LOOP:
|
||||
spin_lock_irqsave(&td->lock, flags);
|
||||
dfll_set_open_loop_config(td);
|
||||
dfll_set_mode(td, DFLL_OPEN_LOOP);
|
||||
if (td->pmu_if == TEGRA_DFLL_PMU_PWM)
|
||||
dfll_pwm_set_output_enabled(td, false);
|
||||
else
|
||||
dfll_i2c_set_output_enabled(td, false);
|
||||
|
||||
spin_unlock_irqrestore(&td->lock, flags);
|
||||
return 0;
|
||||
|
||||
case DFLL_OPEN_LOOP:
|
||||
@@ -1325,8 +1573,10 @@ static int attr_registers_show(struct seq_file *s, void *data)
|
||||
{
|
||||
u32 val, offs;
|
||||
struct tegra_dfll *td = s->private;
|
||||
unsigned long flags;
|
||||
|
||||
seq_puts(s, "CONTROL REGISTERS:\n");
|
||||
spin_lock_irqsave(&td->lock, flags);
|
||||
for (offs = 0; offs <= DFLL_MONITOR_DATA; offs += 4) {
|
||||
if (offs == DFLL_OUTPUT_CFG)
|
||||
val = dfll_i2c_readl(td, offs);
|
||||
@@ -1355,6 +1605,8 @@ static int attr_registers_show(struct seq_file *s, void *data)
|
||||
__raw_readl(td->lut_base + offs));
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&td->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1445,6 +1697,53 @@ static int dfll_init_clks(struct tegra_dfll *td)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dfll_init_tuning_thresholds - set up the high voltage range, if possible
|
||||
* @td: DFLL instance
|
||||
*
|
||||
* Determine whether the DFLL tuning parameters need to be
|
||||
* reprogrammed when the DFLL voltage reaches a certain minimum
|
||||
* threshold. No return value.
|
||||
*/
|
||||
static void dfll_init_tuning_thresholds(struct tegra_dfll *td)
|
||||
{
|
||||
u8 out_min, out_start, max_voltage_index;
|
||||
|
||||
max_voltage_index = td->lut_size - 1;
|
||||
|
||||
/*
|
||||
* Convert high tuning voltage threshold into output LUT
|
||||
* index, and add necessary margin. If voltage threshold is
|
||||
* outside operating range set it at maximum output level to
|
||||
* effectively disable tuning parameters adjustment.
|
||||
*/
|
||||
td->tune_high_out_min = max_voltage_index;
|
||||
td->tune_high_out_start = max_voltage_index;
|
||||
if (td->soc->tune_high_min_millivolts < td->soc->min_millivolts)
|
||||
return; /* no difference between low & high voltage range */
|
||||
|
||||
out_min = find_mv_out_cap(td, td->soc->tune_high_min_millivolts);
|
||||
if ((out_min + 2) > max_voltage_index)
|
||||
return;
|
||||
|
||||
if (td->soc->cvb->cpu_dfll_data.tune_high_margin_millivolts) {
|
||||
unsigned int mv;
|
||||
|
||||
mv = td->soc->tune_high_min_millivolts +
|
||||
td->soc->cvb->cpu_dfll_data.tune_high_margin_millivolts;
|
||||
if (mv * 1000 > td->lut_uv[max_voltage_index])
|
||||
return;
|
||||
out_start = max((u8)(out_min + 1), find_mv_out_cap(td, mv));
|
||||
} else {
|
||||
out_start = out_min + DFLL_TUNE_HIGH_MARGIN_STEPS;
|
||||
}
|
||||
if (out_start > max_voltage_index)
|
||||
return;
|
||||
|
||||
td->tune_high_out_min = out_min;
|
||||
td->tune_high_out_start = out_start;
|
||||
}
|
||||
|
||||
/**
|
||||
* dfll_init - Prepare the DFLL IP block for use
|
||||
* @td: DFLL instance
|
||||
@@ -1501,6 +1800,8 @@ static int dfll_init(struct tegra_dfll *td)
|
||||
|
||||
dfll_init_out_if(td);
|
||||
|
||||
dfll_init_tuning_thresholds(td);
|
||||
|
||||
pm_runtime_put_sync(td->dev);
|
||||
|
||||
return 0;
|
||||
@@ -1647,7 +1948,7 @@ static int dfll_build_pwm_lut(struct tegra_dfll *td, unsigned long v_max)
|
||||
int i;
|
||||
unsigned long rate, reg_volt;
|
||||
u8 lut_bottom = MAX_DFLL_VOLTAGES;
|
||||
int v_min = td->soc->cvb->min_millivolts * 1000;
|
||||
int v_min = td->soc->min_millivolts * 1000;
|
||||
|
||||
for (i = 0; i < MAX_DFLL_VOLTAGES; i++) {
|
||||
reg_volt = td->lut_uv[i];
|
||||
@@ -1667,7 +1968,7 @@ static int dfll_build_pwm_lut(struct tegra_dfll *td, unsigned long v_max)
|
||||
if ((lut_bottom == MAX_DFLL_VOLTAGES) ||
|
||||
(lut_bottom + 1 >= td->lut_size)) {
|
||||
dev_err(td->dev, "no voltage above DFLL minimum %d mV\n",
|
||||
td->soc->cvb->min_millivolts);
|
||||
td->soc->min_millivolts);
|
||||
return -EINVAL;
|
||||
}
|
||||
td->lut_bottom = lut_bottom;
|
||||
@@ -1676,7 +1977,7 @@ static int dfll_build_pwm_lut(struct tegra_dfll *td, unsigned long v_max)
|
||||
rate = get_dvco_rate_below(td, td->lut_bottom);
|
||||
if (!rate) {
|
||||
dev_err(td->dev, "no opp below DFLL minimum voltage %d mV\n",
|
||||
td->soc->cvb->min_millivolts);
|
||||
td->soc->min_millivolts);
|
||||
return -EINVAL;
|
||||
}
|
||||
td->dvco_rate_min = rate;
|
||||
@@ -1699,17 +2000,20 @@ static int dfll_build_pwm_lut(struct tegra_dfll *td, unsigned long v_max)
|
||||
*/
|
||||
static int dfll_build_i2c_lut(struct tegra_dfll *td, unsigned long v_max)
|
||||
{
|
||||
unsigned long rate, v, v_opp;
|
||||
unsigned long rate, v, v_opp, v_min_align;
|
||||
int ret = -EINVAL;
|
||||
int j, selector, lut;
|
||||
|
||||
v = td->soc->cvb->min_millivolts * 1000;
|
||||
v = td->soc->min_millivolts * 1000;
|
||||
lut = find_vdd_map_entry_exact(td, v);
|
||||
if (lut < 0)
|
||||
goto out;
|
||||
td->lut[0] = lut;
|
||||
td->lut_bottom = 0;
|
||||
|
||||
v_min_align = DIV_ROUND_UP(td->soc->min_millivolts * 1000,
|
||||
td->soc->alignment.step_uv) * td->soc->alignment.step_uv;
|
||||
|
||||
for (j = 1, rate = 0; ; rate++) {
|
||||
struct dev_pm_opp *opp;
|
||||
|
||||
@@ -1718,7 +2022,7 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td, unsigned long v_max)
|
||||
break;
|
||||
v_opp = dev_pm_opp_get_voltage(opp);
|
||||
|
||||
if (v_opp <= td->soc->cvb->min_millivolts * 1000)
|
||||
if (v_opp <= v_min_align)
|
||||
td->dvco_rate_min = dev_pm_opp_get_freq(opp);
|
||||
|
||||
dev_pm_opp_put(opp);
|
||||
@@ -1749,7 +2053,7 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td, unsigned long v_max)
|
||||
|
||||
if (!td->dvco_rate_min)
|
||||
dev_err(td->dev, "no opp above DFLL minimum voltage %d mV\n",
|
||||
td->soc->cvb->min_millivolts);
|
||||
td->soc->min_millivolts);
|
||||
else {
|
||||
ret = 0;
|
||||
for (j = 0; j < td->lut_size; j++)
|
||||
@@ -2057,12 +2361,19 @@ int tegra_dfll_register(struct platform_device *pdev,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
spin_lock_init(&td->lock);
|
||||
|
||||
ret = dfll_register_clk(td);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "DFLL clk registration failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Initialize tuning timer */
|
||||
hrtimer_setup(&td->tune_timer, dfll_tune_timer_cb, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
||||
td->tune_delay = ktime_set(0, DFLL_TUNE_HIGH_DELAY * 1000);
|
||||
td->tune_ramp_delay = ktime_set(0, DFLL_OUTPUT_RAMP_DELAY * 1000);
|
||||
|
||||
dfll_debug_init(td);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -31,6 +31,8 @@ struct tegra_dfll_soc_data {
|
||||
unsigned long max_freq;
|
||||
const struct cvb_table *cvb;
|
||||
struct rail_alignment alignment;
|
||||
unsigned int min_millivolts;
|
||||
unsigned int tune_high_min_millivolts;
|
||||
|
||||
void (*init_clock_trimmers)(void);
|
||||
void (*set_clock_trimmers_high)(void);
|
||||
|
||||
@@ -64,7 +64,7 @@ static const unsigned long tegra114_cpu_max_freq_table[] = {
|
||||
.cpu_dfll_data = { \
|
||||
.tune0_low = 0x00b0039d, \
|
||||
.tune0_high = 0x00b0009d, \
|
||||
.tune1 = 0x0000001f, \
|
||||
.tune1_low = 0x0000001f, \
|
||||
.tune_high_min_millivolts = 1050, \
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ static const struct cvb_table tegra114_cpu_cvb_tables[] = {
|
||||
.cpu_dfll_data = {
|
||||
.tune0_low = 0x00b0019d,
|
||||
.tune0_high = 0x00b0019d,
|
||||
.tune1 = 0x0000001f,
|
||||
.tune1_low = 0x0000001f,
|
||||
.tune_high_min_millivolts = 1000,
|
||||
}
|
||||
},
|
||||
@@ -167,7 +167,7 @@ static const struct cvb_table tegra124_cpu_cvb_tables[] = {
|
||||
.cpu_dfll_data = {
|
||||
.tune0_low = 0x005020ff,
|
||||
.tune0_high = 0x005040ff,
|
||||
.tune1 = 0x00000060,
|
||||
.tune1_low = 0x00000060,
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -335,7 +335,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
|
||||
.cpu_dfll_data = {
|
||||
.tune0_low = 0xffead0ff,
|
||||
.tune0_high = 0xffead0ff,
|
||||
.tune1 = 0x20091d9,
|
||||
.tune1_low = 0x20091d9,
|
||||
.tune_high_min_millivolts = 864,
|
||||
}
|
||||
},
|
||||
@@ -348,7 +348,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
|
||||
.cpu_dfll_data = {
|
||||
.tune0_low = 0xffead0ff,
|
||||
.tune0_high = 0xffead0ff,
|
||||
.tune1 = 0x20091d9,
|
||||
.tune1_low = 0x20091d9,
|
||||
.tune_high_min_millivolts = 864,
|
||||
}
|
||||
},
|
||||
@@ -361,7 +361,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
|
||||
.cpu_dfll_data = {
|
||||
.tune0_low = 0xffead0ff,
|
||||
.tune0_high = 0xffead0ff,
|
||||
.tune1 = 0x20091d9,
|
||||
.tune1_low = 0x20091d9,
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -373,7 +373,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
|
||||
.cpu_dfll_data = {
|
||||
.tune0_low = 0xffead0ff,
|
||||
.tune0_high = 0xffead0ff,
|
||||
.tune1 = 0x20091d9,
|
||||
.tune1_low = 0x20091d9,
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -385,7 +385,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
|
||||
.cpu_dfll_data = {
|
||||
.tune0_low = 0xffead0ff,
|
||||
.tune0_high = 0xffead0ff,
|
||||
.tune1 = 0x20091d9,
|
||||
.tune1_low = 0x20091d9,
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -397,7 +397,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
|
||||
.cpu_dfll_data = {
|
||||
.tune0_low = 0xffead0ff,
|
||||
.tune0_high = 0xffead0ff,
|
||||
.tune1 = 0x20091d9,
|
||||
.tune1_low = 0x20091d9,
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -409,7 +409,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
|
||||
.cpu_dfll_data = {
|
||||
.tune0_low = 0xffead0ff,
|
||||
.tune0_high = 0xffead0ff,
|
||||
.tune1 = 0x20091d9,
|
||||
.tune1_low = 0x20091d9,
|
||||
.tune_high_min_millivolts = 864,
|
||||
}
|
||||
},
|
||||
@@ -422,7 +422,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
|
||||
.cpu_dfll_data = {
|
||||
.tune0_low = 0xffead0ff,
|
||||
.tune0_high = 0xffead0ff,
|
||||
.tune1 = 0x20091d9,
|
||||
.tune1_low = 0x20091d9,
|
||||
.tune_high_min_millivolts = 864,
|
||||
}
|
||||
},
|
||||
@@ -434,7 +434,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
|
||||
TEGRA210_CPU_CVB_TABLE,
|
||||
.cpu_dfll_data = {
|
||||
.tune0_low = 0xffead0ff,
|
||||
.tune1 = 0x20091d9,
|
||||
.tune1_low = 0x20091d9,
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -445,7 +445,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
|
||||
TEGRA210_CPU_CVB_TABLE,
|
||||
.cpu_dfll_data = {
|
||||
.tune0_low = 0xffead0ff,
|
||||
.tune1 = 0x25501d0,
|
||||
.tune1_low = 0x25501d0,
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -457,7 +457,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
|
||||
.cpu_dfll_data = {
|
||||
.tune0_low = 0xffead0ff,
|
||||
.tune0_high = 0xffead0ff,
|
||||
.tune1 = 0x20091d9,
|
||||
.tune1_low = 0x20091d9,
|
||||
.tune_high_min_millivolts = 864,
|
||||
}
|
||||
},
|
||||
@@ -470,7 +470,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
|
||||
.cpu_dfll_data = {
|
||||
.tune0_low = 0xffead0ff,
|
||||
.tune0_high = 0xffead0ff,
|
||||
.tune1 = 0x25501d0,
|
||||
.tune1_low = 0x25501d0,
|
||||
.tune_high_min_millivolts = 864,
|
||||
}
|
||||
},
|
||||
@@ -482,7 +482,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
|
||||
TEGRA210_CPU_CVB_TABLE_XA,
|
||||
.cpu_dfll_data = {
|
||||
.tune0_low = 0xffead0ff,
|
||||
.tune1 = 0x17711BD,
|
||||
.tune1_low = 0x17711BD,
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -494,7 +494,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
|
||||
.cpu_dfll_data = {
|
||||
.tune0_low = 0xffead0ff,
|
||||
.tune0_high = 0xffead0ff,
|
||||
.tune1 = 0x20091d9,
|
||||
.tune1_low = 0x20091d9,
|
||||
.tune_high_min_millivolts = 864,
|
||||
}
|
||||
},
|
||||
@@ -507,7 +507,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
|
||||
.cpu_dfll_data = {
|
||||
.tune0_low = 0xffead0ff,
|
||||
.tune0_high = 0xffead0ff,
|
||||
.tune1 = 0x25501d0,
|
||||
.tune1_low = 0x25501d0,
|
||||
.tune_high_min_millivolts = 864,
|
||||
}
|
||||
},
|
||||
@@ -519,7 +519,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
|
||||
TEGRA210_CPU_CVB_TABLE,
|
||||
.cpu_dfll_data = {
|
||||
.tune0_low = 0xffead0ff,
|
||||
.tune1 = 0x20091d9,
|
||||
.tune1_low = 0x20091d9,
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -530,7 +530,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
|
||||
TEGRA210_CPU_CVB_TABLE,
|
||||
.cpu_dfll_data = {
|
||||
.tune0_low = 0xffead0ff,
|
||||
.tune1 = 0x25501d0,
|
||||
.tune1_low = 0x25501d0,
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -542,7 +542,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
|
||||
.cpu_dfll_data = {
|
||||
.tune0_low = 0xffead0ff,
|
||||
.tune0_high = 0xffead0ff,
|
||||
.tune1 = 0x20091d9,
|
||||
.tune1_low = 0x20091d9,
|
||||
.tune_high_min_millivolts = 864,
|
||||
}
|
||||
},
|
||||
@@ -555,7 +555,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
|
||||
.cpu_dfll_data = {
|
||||
.tune0_low = 0xffead0ff,
|
||||
.tune0_high = 0xffead0ff,
|
||||
.tune1 = 0x25501d0,
|
||||
.tune1_low = 0x25501d0,
|
||||
.tune_high_min_millivolts = 864,
|
||||
}
|
||||
},
|
||||
@@ -568,7 +568,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
|
||||
.cpu_dfll_data = {
|
||||
.tune0_low = 0xffead0ff,
|
||||
.tune0_high = 0xffead0ff,
|
||||
.tune1 = 0x20091d9,
|
||||
.tune1_low = 0x20091d9,
|
||||
.tune_high_min_millivolts = 864,
|
||||
}
|
||||
},
|
||||
@@ -581,7 +581,7 @@ static struct cvb_table tegra210_cpu_cvb_tables[] = {
|
||||
.cpu_dfll_data = {
|
||||
.tune0_low = 0xffead0ff,
|
||||
.tune0_high = 0xffead0ff,
|
||||
.tune1 = 0x25501d0,
|
||||
.tune1_low = 0x25501d0,
|
||||
.tune_high_min_millivolts = 864,
|
||||
}
|
||||
},
|
||||
@@ -680,10 +680,13 @@ static struct cvb_table tegra210b01_cpu_cvb_tables[] = {
|
||||
.process_id = -1,
|
||||
.max_millivolts = 1120,
|
||||
CPUB01_CVB_TABLE,
|
||||
.vmin_coefficients = { 620000, 0, 0 },
|
||||
.cpu_dfll_data = {
|
||||
.tune0_low = 0x0000ffcf,
|
||||
.tune1 = 0x012207ff,
|
||||
.tune1_low = 0x012207ff,
|
||||
.tune1_high = 0x03FFF7FF,
|
||||
.tune_high_min_millivolts = 850,
|
||||
.tune_high_margin_millivolts = 38,
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -691,11 +694,13 @@ static struct cvb_table tegra210b01_cpu_cvb_tables[] = {
|
||||
.process_id = 1,
|
||||
.max_millivolts = 1120,
|
||||
CPUB01_CVB_TABLE_SLT_B1,
|
||||
.vmin_coefficients = { 600000, 0, 0 },
|
||||
.cpu_dfll_data = {
|
||||
.tune0_low = 0x0000ffa0,
|
||||
.tune0_high = 0x0000ffff,
|
||||
.tune1 = 0x021107ff,
|
||||
.tune1_low = 0x021107ff,
|
||||
.tune_high_min_millivolts = 850,
|
||||
.tune_high_margin_millivolts = 38,
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -703,11 +708,13 @@ static struct cvb_table tegra210b01_cpu_cvb_tables[] = {
|
||||
.process_id = 0,
|
||||
.max_millivolts = 1120,
|
||||
CPUB01_CVB_TABLE_SLT_B0,
|
||||
.vmin_coefficients = { 600000, 0, 0 },
|
||||
.cpu_dfll_data = {
|
||||
.tune0_low = 0x0000ff90,
|
||||
.tune0_high = 0x0000ffff,
|
||||
.tune1 = 0x021107ff,
|
||||
.tune1_low = 0x021107ff,
|
||||
.tune_high_min_millivolts = 850,
|
||||
.tune_high_margin_millivolts = 38,
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -715,10 +722,12 @@ static struct cvb_table tegra210b01_cpu_cvb_tables[] = {
|
||||
.process_id = -1,
|
||||
.max_millivolts = 1120,
|
||||
CPUB01_CVB_TABLE,
|
||||
.vmin_coefficients = { 620000, 0, 0 },
|
||||
.cpu_dfll_data = {
|
||||
.tune0_low = 0x0000ffcf,
|
||||
.tune1 = 0x012207ff,
|
||||
.tune1_low = 0x012207ff,
|
||||
.tune_high_min_millivolts = 850,
|
||||
.tune_high_margin_millivolts = 38,
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -845,7 +854,8 @@ static int tegra124_dfll_fcpu_probe(struct platform_device *pdev)
|
||||
soc->cvb = tegra_cvb_add_opp_table(soc->dev, fcpu_data->cpu_cvb_tables,
|
||||
fcpu_data->cpu_cvb_tables_size,
|
||||
&align, process_id, speedo_id,
|
||||
speedo_value, soc->max_freq);
|
||||
speedo_value, soc->max_freq,
|
||||
&soc->min_millivolts);
|
||||
soc->alignment = align;
|
||||
|
||||
if (IS_ERR(soc->cvb)) {
|
||||
@@ -854,6 +864,9 @@ static int tegra124_dfll_fcpu_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(soc->cvb);
|
||||
}
|
||||
|
||||
soc->tune_high_min_millivolts =
|
||||
soc->cvb->cpu_dfll_data.tune_high_min_millivolts;
|
||||
|
||||
err = tegra_dfll_register(pdev, soc);
|
||||
if (err < 0) {
|
||||
tegra_cvb_remove_opp_table(soc->dev, soc->cvb, soc->max_freq);
|
||||
|
||||
+13
-4
@@ -54,13 +54,18 @@ static int round_voltage(int mv, const struct rail_alignment *align, int up)
|
||||
|
||||
static int build_opp_table(struct device *dev, const struct cvb_table *table,
|
||||
struct rail_alignment *align,
|
||||
int speedo_value, unsigned long max_freq)
|
||||
int speedo_value, unsigned long max_freq, int *vmin)
|
||||
{
|
||||
int i, ret, dfll_mv, min_mv, max_mv;
|
||||
|
||||
min_mv = round_voltage(table->min_millivolts, align, UP);
|
||||
max_mv = round_voltage(table->max_millivolts, align, DOWN);
|
||||
|
||||
dfll_mv = get_cvb_voltage(
|
||||
speedo_value, table->speedo_scale, &table->vmin_coefficients);
|
||||
dfll_mv = round_cvb_voltage(dfll_mv, table->voltage_scale, align);
|
||||
min_mv = max(min_mv, dfll_mv);
|
||||
|
||||
for (i = 0; i < MAX_DVFS_FREQS; i++) {
|
||||
const struct cvb_table_freq_entry *entry = &table->entries[i];
|
||||
|
||||
@@ -78,6 +83,9 @@ static int build_opp_table(struct device *dev, const struct cvb_table *table,
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (vmin)
|
||||
*vmin = min_mv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -90,7 +98,8 @@ static int build_opp_table(struct device *dev, const struct cvb_table *table,
|
||||
* @process_id: process id of the HW module
|
||||
* @speedo_id: speedo id of the HW module
|
||||
* @speedo_value: speedo value of the HW module
|
||||
* @max_freq: highest safe clock rate
|
||||
* @max_rate: highest safe clock rate
|
||||
* @vmin: final minimum voltage returned to the caller
|
||||
*
|
||||
* On Tegra, a CVB table encodes the relationship between operating voltage
|
||||
* and safe maximal frequency for a given module (e.g. GPU or CPU). This
|
||||
@@ -103,7 +112,7 @@ const struct cvb_table *
|
||||
tegra_cvb_add_opp_table(struct device *dev, const struct cvb_table *tables,
|
||||
size_t count, struct rail_alignment *align,
|
||||
int process_id, int speedo_id, int speedo_value,
|
||||
unsigned long max_freq)
|
||||
unsigned long max_freq, int *vmin)
|
||||
{
|
||||
size_t i;
|
||||
int ret;
|
||||
@@ -118,7 +127,7 @@ tegra_cvb_add_opp_table(struct device *dev, const struct cvb_table *tables,
|
||||
continue;
|
||||
|
||||
ret = build_opp_table(dev, table, align, speedo_value,
|
||||
max_freq);
|
||||
max_freq, vmin);
|
||||
return ret ? ERR_PTR(ret) : table;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,8 +31,10 @@ struct cvb_table_freq_entry {
|
||||
struct cvb_cpu_dfll_data {
|
||||
u32 tune0_low;
|
||||
u32 tune0_high;
|
||||
u32 tune1;
|
||||
u32 tune1_low;
|
||||
u32 tune1_high;
|
||||
unsigned int tune_high_min_millivolts;
|
||||
unsigned int tune_high_margin_millivolts;
|
||||
};
|
||||
|
||||
struct cvb_table {
|
||||
@@ -46,13 +48,14 @@ struct cvb_table {
|
||||
int voltage_scale;
|
||||
struct cvb_table_freq_entry entries[MAX_DVFS_FREQS];
|
||||
struct cvb_cpu_dfll_data cpu_dfll_data;
|
||||
struct cvb_coefficients vmin_coefficients;
|
||||
};
|
||||
|
||||
const struct cvb_table *
|
||||
tegra_cvb_add_opp_table(struct device *dev, const struct cvb_table *cvb_tables,
|
||||
size_t count, struct rail_alignment *align,
|
||||
int process_id, int speedo_id, int speedo_value,
|
||||
unsigned long max_freq);
|
||||
unsigned long max_freq, int *vmin);
|
||||
void tegra_cvb_remove_opp_table(struct device *dev,
|
||||
const struct cvb_table *table,
|
||||
unsigned long max_freq);
|
||||
|
||||
@@ -285,9 +285,9 @@ static void gpio_irq_unmask(struct irq_data *d)
|
||||
|
||||
gpiochip_enable_irq(&chips->chip, hwirq);
|
||||
|
||||
status &= IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING;
|
||||
status &= IRQ_TYPE_EDGE_BOTH;
|
||||
if (!status)
|
||||
status = IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING;
|
||||
status = IRQ_TYPE_EDGE_BOTH;
|
||||
|
||||
if (status & IRQ_TYPE_EDGE_FALLING)
|
||||
writel_relaxed(mask, &g->set_falling);
|
||||
@@ -297,7 +297,7 @@ static void gpio_irq_unmask(struct irq_data *d)
|
||||
|
||||
static int gpio_irq_type(struct irq_data *d, unsigned trigger)
|
||||
{
|
||||
if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
|
||||
if (trigger & ~IRQ_TYPE_EDGE_BOTH)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
@@ -400,7 +400,7 @@ static int gpio_irq_type_unbanked(struct irq_data *data, unsigned trigger)
|
||||
|
||||
mask = __gpio_mask(i);
|
||||
|
||||
if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
|
||||
if (trigger & ~IRQ_TYPE_EDGE_BOTH)
|
||||
return -EINVAL;
|
||||
|
||||
writel_relaxed(mask, (trigger & IRQ_TYPE_EDGE_FALLING)
|
||||
|
||||
@@ -160,7 +160,7 @@ mediatek_gpio_irq_type(struct irq_data *d, unsigned int type)
|
||||
rg->hlevel | rg->llevel) & mask)
|
||||
return 0;
|
||||
|
||||
type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
|
||||
type = IRQ_TYPE_EDGE_BOTH;
|
||||
}
|
||||
|
||||
rg->rising &= ~mask;
|
||||
|
||||
@@ -1263,14 +1263,14 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
|
||||
gc = irq_get_domain_generic_chip(mvchip->domain, 0);
|
||||
gc->private = mvchip;
|
||||
ct = &gc->chip_types[0];
|
||||
ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW;
|
||||
ct->type = IRQ_TYPE_LEVEL_MASK;
|
||||
ct->chip.irq_mask = mvebu_gpio_level_irq_mask;
|
||||
ct->chip.irq_unmask = mvebu_gpio_level_irq_unmask;
|
||||
ct->chip.irq_set_type = mvebu_gpio_irq_set_type;
|
||||
ct->chip.name = mvchip->chip.label;
|
||||
|
||||
ct = &gc->chip_types[1];
|
||||
ct->type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
|
||||
ct->type = IRQ_TYPE_EDGE_BOTH;
|
||||
ct->chip.irq_ack = mvebu_gpio_irq_ack;
|
||||
ct->chip.irq_mask = mvebu_gpio_edge_irq_mask;
|
||||
ct->chip.irq_unmask = mvebu_gpio_edge_irq_unmask;
|
||||
|
||||
@@ -198,7 +198,7 @@ static int mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base)
|
||||
gc->private = port;
|
||||
|
||||
ct = &gc->chip_types[0];
|
||||
ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW;
|
||||
ct->type = IRQ_TYPE_LEVEL_MASK;
|
||||
ct->chip.irq_ack = irq_gc_ack_set_bit;
|
||||
ct->chip.irq_mask = irq_gc_mask_disable_reg;
|
||||
ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
|
||||
@@ -210,7 +210,7 @@ static int mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base)
|
||||
ct->regs.disable = PINCTRL_PIN2IRQ(port) + MXS_CLR;
|
||||
|
||||
ct = &gc->chip_types[1];
|
||||
ct->type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
|
||||
ct->type = IRQ_TYPE_EDGE_BOTH;
|
||||
ct->chip.irq_ack = irq_gc_ack_set_bit;
|
||||
ct->chip.irq_mask = irq_gc_mask_disable_reg;
|
||||
ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
|
||||
|
||||
@@ -432,8 +432,7 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
|
||||
if (type & ~IRQ_TYPE_SENSE_MASK)
|
||||
return -EINVAL;
|
||||
|
||||
if (!bank->regs->leveldetect0 &&
|
||||
(type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH)))
|
||||
if (!bank->regs->leveldetect0 && (type & IRQ_TYPE_LEVEL_MASK))
|
||||
return -EINVAL;
|
||||
|
||||
raw_spin_lock_irqsave(&bank->lock, flags);
|
||||
@@ -450,9 +449,9 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
|
||||
}
|
||||
raw_spin_unlock_irqrestore(&bank->lock, flags);
|
||||
|
||||
if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
|
||||
if (type & IRQ_TYPE_LEVEL_MASK)
|
||||
irq_set_handler_locked(d, handle_level_irq);
|
||||
else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
|
||||
else if (type & IRQ_TYPE_EDGE_BOTH)
|
||||
/*
|
||||
* Edge IRQs are already cleared/acked in irq_handler and
|
||||
* not need to be masked, as result handle_edge_irq()
|
||||
@@ -702,7 +701,7 @@ static void omap_gpio_unmask_irq(struct irq_data *d)
|
||||
* after enabing the interrupt to clear the wakeup status.
|
||||
*/
|
||||
if (bank->regs->leveldetect0 && bank->regs->wkup_en &&
|
||||
trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
|
||||
trigger & IRQ_TYPE_LEVEL_MASK)
|
||||
omap_clear_gpio_irqstatus(bank, offset);
|
||||
|
||||
if (trigger)
|
||||
|
||||
@@ -132,8 +132,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
|
||||
if (offset < 0 || offset >= PL061_GPIO_NR)
|
||||
return -EINVAL;
|
||||
|
||||
if ((trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) &&
|
||||
(trigger & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)))
|
||||
if ((trigger & IRQ_TYPE_LEVEL_MASK) && (trigger & IRQ_TYPE_EDGE_BOTH))
|
||||
{
|
||||
dev_err(gc->parent,
|
||||
"trying to configure line %d for both level and edge "
|
||||
@@ -149,7 +148,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
|
||||
gpiois = readb(pl061->base + GPIOIS);
|
||||
gpioibe = readb(pl061->base + GPIOIBE);
|
||||
|
||||
if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
|
||||
if (trigger & IRQ_TYPE_LEVEL_MASK) {
|
||||
bool polarity = trigger & IRQ_TYPE_LEVEL_HIGH;
|
||||
|
||||
/* Disable edge detection */
|
||||
|
||||
@@ -406,7 +406,7 @@ static int pxa_gpio_irq_type(struct irq_data *d, unsigned int type)
|
||||
if (__gpio_is_occupied(pchip, gpio))
|
||||
return 0;
|
||||
|
||||
type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
|
||||
type = IRQ_TYPE_EDGE_BOTH;
|
||||
}
|
||||
|
||||
gpdr = readl_relaxed(c->regbase + GPDR_OFFSET);
|
||||
|
||||
@@ -169,9 +169,9 @@ static int rda_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
|
||||
if (flow_type & IRQ_TYPE_LEVEL_MASK)
|
||||
irq_set_handler_locked(data, handle_level_irq);
|
||||
else if (flow_type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
|
||||
else if (flow_type & IRQ_TYPE_EDGE_BOTH)
|
||||
irq_set_handler_locked(data, handle_edge_irq);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -134,7 +134,7 @@ static int sa1100_gpio_type(struct irq_data *d, unsigned int type)
|
||||
if (type == IRQ_TYPE_PROBE) {
|
||||
if ((sgc->irqrising | sgc->irqfalling) & mask)
|
||||
return 0;
|
||||
type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
|
||||
type = IRQ_TYPE_EDGE_BOTH;
|
||||
}
|
||||
|
||||
if (type & IRQ_TYPE_EDGE_RISING)
|
||||
|
||||
@@ -158,7 +158,7 @@ static int sdv_register_irqsupport(struct sdv_gpio_chip_data *sd,
|
||||
|
||||
sd->gc->private = sd;
|
||||
ct = sd->gc->chip_types;
|
||||
ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW;
|
||||
ct->type = IRQ_TYPE_LEVEL_MASK;
|
||||
ct->regs.eoi = GPSTR;
|
||||
ct->regs.mask = GPIO_INT;
|
||||
ct->chip.irq_mask = irq_gc_mask_clr_bit;
|
||||
|
||||
@@ -149,7 +149,7 @@ static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
||||
int regoffset = offset / 8;
|
||||
int mask = BIT(offset % 8);
|
||||
|
||||
if (type & IRQ_TYPE_LEVEL_LOW || type & IRQ_TYPE_LEVEL_HIGH)
|
||||
if (type & IRQ_TYPE_LEVEL_MASK)
|
||||
return -EINVAL;
|
||||
|
||||
/* STMPE801 and STMPE 1600 don't have RE and FE registers */
|
||||
|
||||
@@ -172,18 +172,11 @@ static int tegra_gpio_direction_input(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
|
||||
int ret;
|
||||
|
||||
tegra_gpio_mask_write(tgi, GPIO_MSK_OE(tgi, offset), offset, 0);
|
||||
tegra_gpio_enable(tgi, offset);
|
||||
|
||||
ret = pinctrl_gpio_direction_input(chip, offset);
|
||||
if (ret < 0)
|
||||
dev_err(tgi->dev,
|
||||
"Failed to set pinctrl input direction of GPIO %d: %d",
|
||||
chip->base + offset, ret);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_gpio_direction_output(struct gpio_chip *chip,
|
||||
@@ -191,19 +184,12 @@ static int tegra_gpio_direction_output(struct gpio_chip *chip,
|
||||
int value)
|
||||
{
|
||||
struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
|
||||
int ret;
|
||||
|
||||
tegra_gpio_set(chip, offset, value);
|
||||
tegra_gpio_mask_write(tgi, GPIO_MSK_OE(tgi, offset), offset, 1);
|
||||
tegra_gpio_enable(tgi, offset);
|
||||
|
||||
ret = pinctrl_gpio_direction_output(chip, offset);
|
||||
if (ret < 0)
|
||||
dev_err(tgi->dev,
|
||||
"Failed to set pinctrl output direction of GPIO %d: %d",
|
||||
chip->base + offset, ret);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_gpio_get_direction(struct gpio_chip *chip,
|
||||
@@ -356,9 +342,9 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
|
||||
if (type & IRQ_TYPE_LEVEL_MASK)
|
||||
irq_set_handler_locked(d, handle_level_irq);
|
||||
else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
|
||||
else if (type & IRQ_TYPE_EDGE_BOTH)
|
||||
irq_set_handler_locked(d, handle_edge_irq);
|
||||
|
||||
if (d->parent_data)
|
||||
@@ -722,7 +708,6 @@ static int tegra_gpio_probe(struct platform_device *pdev)
|
||||
tgi->gc.direction_output = tegra_gpio_direction_output;
|
||||
tgi->gc.set = tegra_gpio_set;
|
||||
tgi->gc.get_direction = tegra_gpio_get_direction;
|
||||
tgi->gc.base = 0;
|
||||
tgi->gc.ngpio = tgi->bank_count * 32;
|
||||
tgi->gc.parent = &pdev->dev;
|
||||
|
||||
|
||||
@@ -149,7 +149,7 @@ static int timbgpio_irq_type(struct irq_data *d, unsigned trigger)
|
||||
if (ver > 2)
|
||||
bflr = ioread32(tgpio->membase + TGPIO_BFLR);
|
||||
|
||||
if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
|
||||
if (trigger & IRQ_TYPE_LEVEL_MASK) {
|
||||
bflr &= ~(1 << offset);
|
||||
flr &= ~(1 << offset);
|
||||
if (trigger & IRQ_TYPE_LEVEL_HIGH)
|
||||
|
||||
@@ -1088,7 +1088,7 @@ static int tegra_dsi_init(struct host1x_client *client)
|
||||
dev_err(dsi->dev, "failed to initialize output: %d\n",
|
||||
err);
|
||||
|
||||
dsi->output.encoder.possible_crtcs = 0x3;
|
||||
tegra_output_find_possible_crtcs(&dsi->output, drm);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -240,6 +240,12 @@
|
||||
|
||||
#define XUSB_PADCTL_UPHY_PLL_S0_CTL8 0x87c
|
||||
|
||||
#define XUSB_PADCTL_UPHY_PLL_S0_CTL10 0x384
|
||||
#define CFG_ADDR(x) (((x) & 0xff) << 16)
|
||||
#define CFG_WDATA(x) (((x) & 0xffff) << 0)
|
||||
#define CFG_RESET (1 << 27)
|
||||
#define CFG_WS (1 << 24)
|
||||
|
||||
#define XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL1 0x960
|
||||
#define XUSB_PADCTL_UPHY_MISC_PAD_S0_CTL2 0x964
|
||||
|
||||
@@ -407,6 +413,18 @@
|
||||
#define UHSIC_STROBE_RPD_C BIT(16)
|
||||
#define UHSIC_STROBE_RPD_D BIT(24)
|
||||
|
||||
struct init_data {
|
||||
u8 cfg_addr;
|
||||
u16 cfg_wdata;
|
||||
};
|
||||
|
||||
static struct init_data tegra210b01_usb3_pll_g1_init_data[] = {
|
||||
{.cfg_addr = 0x2, .cfg_wdata = 0x0000},
|
||||
{.cfg_addr = 0x3, .cfg_wdata = 0x7051},
|
||||
{.cfg_addr = 0x25, .cfg_wdata = 0x0130},
|
||||
{.cfg_addr = 0x1E, .cfg_wdata = 0x0017},
|
||||
};
|
||||
|
||||
struct tegra210_xusb_fuse_calibration {
|
||||
u32 hs_curr_level[4];
|
||||
u32 hs_term_range_adj;
|
||||
@@ -508,6 +526,7 @@ static int tegra210_usb3_lane_map(struct tegra_xusb_lane *lane)
|
||||
static int tegra210_pex_uphy_enable(struct tegra_xusb_padctl *padctl)
|
||||
{
|
||||
struct tegra_xusb_pcie_pad *pcie = to_pcie_pad(padctl->pcie);
|
||||
bool is_t210b01 = padctl->soc == &tegra210b01_xusb_padctl_soc;
|
||||
unsigned long timeout;
|
||||
u32 value;
|
||||
unsigned int i;
|
||||
@@ -533,6 +552,18 @@ static int tegra210_pex_uphy_enable(struct tegra_xusb_padctl *padctl)
|
||||
if (err < 0)
|
||||
goto disable;
|
||||
|
||||
if (is_t210b01) {
|
||||
for (i = 0; i < ARRAY_SIZE(tegra210b01_usb3_pll_g1_init_data); i++) {
|
||||
value = 0;
|
||||
value |= CFG_ADDR(tegra210b01_usb3_pll_g1_init_data[i].cfg_addr);
|
||||
value |= CFG_WDATA(tegra210b01_usb3_pll_g1_init_data[i].cfg_wdata);
|
||||
value |= CFG_RESET;
|
||||
value |= CFG_WS;
|
||||
padctl_writel(padctl, value,
|
||||
XUSB_PADCTL_UPHY_PLL_S0_CTL10);
|
||||
}
|
||||
}
|
||||
|
||||
value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_P0_CTL2);
|
||||
value &= ~(XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_MASK <<
|
||||
XUSB_PADCTL_UPHY_PLL_CTL2_CAL_CTRL_SHIFT);
|
||||
|
||||
@@ -7,12 +7,17 @@
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pinctrl/pinctrl.h>
|
||||
#include <linux/pinctrl/pinmux.h>
|
||||
|
||||
#include "pinctrl-tegra.h"
|
||||
|
||||
struct tegra210_pinctrl_soc {
|
||||
bool lpdr_support;
|
||||
};
|
||||
|
||||
/*
|
||||
* Most pins affected by the pinmux can also be GPIOs. Define these first.
|
||||
* These must match how the GPIO driver names/numbers its pins.
|
||||
@@ -1349,7 +1354,7 @@ static const char * const tegra210_functions[] = {
|
||||
.parked_bitmask = prk_mask, \
|
||||
}
|
||||
|
||||
static const struct tegra_pingroup tegra210_groups[] = {
|
||||
static struct tegra_pingroup tegra210_groups[] = {
|
||||
/* pg_name, f0, f1, f2, f3, r, hsm, drvtype, e_io_hv, lpdr, rdrv, drvdn_b, drvdn_w, drvup_b, drvup_w, slwr_b, slwr_w, slwf_b, slwf_w */
|
||||
PINGROUP(sdmmc1_clk_pm0, SDMMC1, RSVD1, RSVD2, RSVD3, 0x3000, Y, Y, N, N, -1, -1, -1, -1, -1, -1, -1, -1, -1),
|
||||
PINGROUP(sdmmc1_cmd_pm1, SDMMC1, SPI3, RSVD2, RSVD3, 0x3004, Y, Y, N, N, -1, -1, -1, -1, -1, -1, -1, -1, -1),
|
||||
@@ -1558,12 +1563,39 @@ static const struct tegra_pinctrl_soc_data tegra210_pinctrl = {
|
||||
|
||||
static int tegra210_pinctrl_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct tegra210_pinctrl_soc *soc;
|
||||
struct tegra_pingroup *g;
|
||||
int i;
|
||||
|
||||
soc = of_device_get_match_data(&pdev->dev);
|
||||
if (soc->lpdr_support) {
|
||||
for (i = 0; i < tegra210_pinctrl.ngroups; ++i) {
|
||||
g = &tegra210_groups[i];
|
||||
if (g->mux_reg >= 0)
|
||||
g->lpdr_bit = 8;
|
||||
}
|
||||
}
|
||||
|
||||
return tegra_pinctrl_probe(pdev, &tegra210_pinctrl);
|
||||
}
|
||||
|
||||
static const struct tegra210_pinctrl_soc tegra210_pinctrl_soc_data = {
|
||||
.lpdr_support = false,
|
||||
};
|
||||
|
||||
static const struct tegra210_pinctrl_soc tegra210b01_pinctrl_soc_data = {
|
||||
.lpdr_support = true,
|
||||
};
|
||||
|
||||
static const struct of_device_id tegra210_pinctrl_of_match[] = {
|
||||
{ .compatible = "nvidia,tegra210-pinmux", },
|
||||
{ },
|
||||
{
|
||||
.compatible = "nvidia,tegra210-pinmux",
|
||||
.data = &tegra210_pinctrl_soc_data,
|
||||
}, {
|
||||
.compatible = "nvidia,tegra210b01-pinmux",
|
||||
.data = &tegra210b01_pinctrl_soc_data,
|
||||
}, {
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_driver tegra210_pinctrl_driver = {
|
||||
|
||||
@@ -122,8 +122,9 @@ static void tegra_fuse_print_sku_info(struct tegra_sku_info *tegra_sku_info)
|
||||
tegra_revision_name[tegra_sku_info->revision],
|
||||
tegra_sku_info->sku_id, tegra_sku_info->cpu_process_id,
|
||||
tegra_sku_info->soc_process_id);
|
||||
pr_debug("Tegra CPU Speedo ID %d, SoC Speedo ID %d\n",
|
||||
tegra_sku_info->cpu_speedo_id, tegra_sku_info->soc_speedo_id);
|
||||
pr_info("Tegra CPU Speedo ID %d, SoC Speedo ID %d, GPU Speedo ID %d\n",
|
||||
tegra_sku_info->cpu_speedo_id, tegra_sku_info->soc_speedo_id,
|
||||
tegra_sku_info->gpu_speedo_id);
|
||||
}
|
||||
|
||||
static int tegra_fuse_add_lookups(struct tegra_fuse *fuse)
|
||||
|
||||
@@ -68,7 +68,6 @@ config TYPEC_BM92TXX
|
||||
tristate "Rohm Semiconductor BM92TXX USB Type-C Support"
|
||||
depends on I2C
|
||||
depends on USB_ROLE_SWITCH
|
||||
depends on DRM
|
||||
help
|
||||
Say Y or M here if your system has Rohm BM92TXX USB Type-C and
|
||||
Power Delivery controller.
|
||||
|
||||
+281
-290
@@ -28,13 +28,13 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/extcon-provider.h>
|
||||
#include <linux/usb/role.h>
|
||||
#include <linux/usb/typec.h>
|
||||
#include <linux/usb/pd.h>
|
||||
#include <linux/usb/pd_vdo.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <drm/drm_connector.h>
|
||||
#ifdef CONFIG_SWITCH
|
||||
#include <linux/switch.h>
|
||||
#endif
|
||||
|
||||
|
||||
/* Registers */
|
||||
@@ -258,6 +258,16 @@
|
||||
#define STOP_HPD_CMD 0x3939 /* Stop handling HPD */
|
||||
#define STOP_HPD_EXIT_DP_CMD 0x3B3B /* Stop handling HPD and exit DP Alt mode */
|
||||
|
||||
/* General defines */
|
||||
#define PDO_TYPE_FIXED 0
|
||||
#define PDO_TYPE_BATT 1
|
||||
#define PDO_TYPE_VAR 2
|
||||
|
||||
#define PDO_INFO_DR_DATA (1 << 5)
|
||||
#define PDO_INFO_USB_COMM (1 << 6)
|
||||
#define PDO_INFO_EXT_POWER (1 << 7)
|
||||
#define PDO_INFO_HP_CAP (1 << 8)
|
||||
#define PDO_INFO_DR_POWER (1 << 9)
|
||||
|
||||
/* VDM/VDO */
|
||||
#define VDM_CMD_RESERVED 0x00
|
||||
@@ -276,6 +286,14 @@
|
||||
#define VDM_UNSTRUCTURED 0x00
|
||||
#define VDM_STRUCTURED 0x80
|
||||
|
||||
/* VDM Discover ID */
|
||||
#define VDO_ID_TYPE_NONE 0
|
||||
#define VDO_ID_TYPE_PD_HUB 1
|
||||
#define VDO_ID_TYPE_PD_PERIPH 2
|
||||
#define VDO_ID_TYPE_PASS_CBL 3
|
||||
#define VDO_ID_TYPE_ACTI_CBL 4
|
||||
#define VDO_ID_TYPE_ALTERNATE 5
|
||||
|
||||
/* VDM Discover Mode Caps [From device (UFP_U) to host (DFP_U)] */
|
||||
#define VDO_DP_UFP_D BIT(0) /* DisplayPort Sink */
|
||||
#define VDO_DP_DFP_D BIT(1) /* DisplayPort Source */
|
||||
@@ -376,6 +394,47 @@ enum bm92t_state_type {
|
||||
DOCK_CONFIG_HANDLED
|
||||
};
|
||||
|
||||
struct __packed pd_object {
|
||||
unsigned int amp:10;
|
||||
unsigned int volt:10;
|
||||
unsigned int info:10;
|
||||
unsigned int type:2;
|
||||
};
|
||||
|
||||
struct __packed rd_object {
|
||||
unsigned int max_amp:10;
|
||||
unsigned int op_amp:10;
|
||||
unsigned int info:6;
|
||||
unsigned int usb_comms:1;
|
||||
unsigned int mismatch:1;
|
||||
unsigned int obj_no:4;
|
||||
};
|
||||
|
||||
struct __packed vd_object {
|
||||
unsigned int vid:16;
|
||||
unsigned int rsvd:10;
|
||||
unsigned int modal:1;
|
||||
unsigned int type:3;
|
||||
unsigned int ufp:1;
|
||||
unsigned int dfp:1;
|
||||
|
||||
unsigned int xid;
|
||||
|
||||
unsigned int bcd:16;
|
||||
unsigned int pid:16;
|
||||
|
||||
unsigned int prod_type;
|
||||
};
|
||||
|
||||
struct bm92t_device {
|
||||
int pdo_no;
|
||||
unsigned int charging_limit;
|
||||
bool drd_support;
|
||||
bool is_nintendo_dock;
|
||||
struct pd_object pdo;
|
||||
struct vd_object vdo;
|
||||
};
|
||||
|
||||
struct bm92t_platform_data {
|
||||
int vconn_en_gpio;
|
||||
|
||||
@@ -393,14 +452,6 @@ struct bm92t_platform_data {
|
||||
unsigned int pd_15v_current_limit;
|
||||
};
|
||||
|
||||
struct bm92t_device {
|
||||
int pdo_no;
|
||||
unsigned int charging_limit;
|
||||
bool drd_support;
|
||||
bool is_nintendo_dock;
|
||||
u32 pdo;
|
||||
};
|
||||
|
||||
struct bm92t_info {
|
||||
struct i2c_client *i2c_client;
|
||||
struct bm92t_platform_data *pdata;
|
||||
@@ -411,10 +462,7 @@ struct bm92t_info {
|
||||
int state;
|
||||
bool first_init;
|
||||
|
||||
struct typec_port *port;
|
||||
struct typec_partner *partner;
|
||||
struct usb_pd_identity partner_identity;
|
||||
|
||||
struct extcon_dev *edev;
|
||||
struct delayed_work oneshot_work;
|
||||
struct delayed_work power_work;
|
||||
|
||||
@@ -432,7 +480,9 @@ struct bm92t_info {
|
||||
struct bm92t_device cable;
|
||||
|
||||
struct usb_role_switch *role_sw;
|
||||
struct fwnode_handle *connector_fwnode;
|
||||
#ifdef CONFIG_SWITCH
|
||||
struct switch_dev pd_switch;
|
||||
#endif
|
||||
};
|
||||
|
||||
static const char * const states[] = {
|
||||
@@ -464,6 +514,28 @@ static const char * const states[] = {
|
||||
"DOCK_CONFIG_HANDLED"
|
||||
};
|
||||
|
||||
static const unsigned int bm92t_extcon_cable[] = {
|
||||
EXTCON_USB_HOST, /* Id */
|
||||
EXTCON_USB, /* Vbus */
|
||||
EXTCON_CHG_USB_PD, /* USB-PD */
|
||||
EXTCON_DISP_DP, /* DisplayPort. Handled by HPD so not used. */
|
||||
EXTCON_NONE
|
||||
};
|
||||
|
||||
struct bm92t_extcon_cables {
|
||||
unsigned int cable;
|
||||
char *name;
|
||||
};
|
||||
|
||||
static const struct bm92t_extcon_cables bm92t_extcon_cable_names[] = {
|
||||
{ EXTCON_USB_HOST, "USB HOST"},
|
||||
{ EXTCON_USB, "USB"},
|
||||
{ EXTCON_CHG_USB_PD, "USB-PD"},
|
||||
{ EXTCON_DISP_DP, "DisplayPort"},
|
||||
{ EXTCON_NONE, "None"},
|
||||
{ -1, "Unknown"}
|
||||
};
|
||||
|
||||
/* charger current input limits */
|
||||
static const unsigned int current_input_limits[] = {
|
||||
100, 150, 500, 900, 1200, 1500, 2000, 3000
|
||||
@@ -522,7 +594,7 @@ static int bm92t_write_reg(struct bm92t_info *info,
|
||||
xfer_msg[0].buf = buf;
|
||||
|
||||
dev_dbg(&info->i2c_client->dev,
|
||||
"write reg cmd = 0x%02X len = %d\n", buf[0], len);
|
||||
"write reg cmd = 0x%02X len = %d\n", buf[0], len);
|
||||
return (i2c_transfer(info->i2c_client->adapter, xfer_msg, 1) != 1);
|
||||
}
|
||||
|
||||
@@ -570,8 +642,8 @@ static int bm92t_send_cmd(struct bm92t_info *info, unsigned short *cmd)
|
||||
|
||||
ret = bm92t_write_reg(info, msg, 3);
|
||||
dev_dbg(&info->i2c_client->dev,
|
||||
"Sent cmd 0x%02X 0x%02X return value %d\n",
|
||||
_cmd[0], _cmd[1], ret);
|
||||
"Sent cmd 0x%02X 0x%02X return value %d\n",
|
||||
_cmd[0], _cmd[1], ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -645,6 +717,7 @@ static int bm92t_handle_dp_config_and_hpd(struct bm92t_info *info)
|
||||
unsigned char cfg[6] = {OUTGOING_VDM_REG, 0x04,
|
||||
VDO_DP_SUPPORT | VDO_DP_U_UFP_D,
|
||||
0x00, 0x00, 0x00};
|
||||
union extcon_property_value prop;
|
||||
|
||||
/* Set primary pin assignment by lanes supported */
|
||||
unsigned char pin_cfg = (info->pdata->dp_lanes == 4) ?
|
||||
@@ -653,7 +726,7 @@ static int bm92t_handle_dp_config_and_hpd(struct bm92t_info *info)
|
||||
/* Read DisplayPort Capabilities */
|
||||
err = bm92t_read_reg(info, INCOMING_VDM_REG, msg, sizeof(msg));
|
||||
dev_info(&info->i2c_client->dev,
|
||||
"DP Pin assignments: %02X %02X\n", msg[2], msg[3]);
|
||||
"DP Pin assignments: %02X %02X\n", msg[2], msg[3]);
|
||||
|
||||
/* Prepare UFP_U as UFP_D configuration */
|
||||
for (i = 0; i < 2; i++) {
|
||||
@@ -702,8 +775,9 @@ static int bm92t_handle_dp_config_and_hpd(struct bm92t_info *info)
|
||||
/* Configure DP Alt mode and start handling HPD */
|
||||
bm92t_send_cmd(info, &cmd);
|
||||
|
||||
info->cable.charging_limit = valid_lanes > info->pdata->dp_lanes ?
|
||||
info->pdata->dp_lanes : valid_lanes;
|
||||
prop.intval = valid_lanes > info->pdata->dp_lanes ?
|
||||
info->pdata->dp_lanes : valid_lanes;
|
||||
|
||||
} else {
|
||||
dev_warn(&info->i2c_client->dev,
|
||||
"No compatible DP Pin assignment (%d: %02X %02X %02X)!\n",
|
||||
@@ -860,20 +934,56 @@ ret:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void bm92t_set_data_role(struct bm92t_info *info,
|
||||
enum typec_data_role role, bool attached)
|
||||
static char *bm92t_extcon_cable_get_name(const unsigned int cable)
|
||||
{
|
||||
enum usb_role usb_role = USB_ROLE_NONE;
|
||||
int i, count;
|
||||
|
||||
if (attached) {
|
||||
if (role == TYPEC_HOST)
|
||||
usb_role = USB_ROLE_HOST;
|
||||
else
|
||||
usb_role = USB_ROLE_DEVICE;
|
||||
count = ARRAY_SIZE(bm92t_extcon_cable_names);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (bm92t_extcon_cable_names[i].cable == cable)
|
||||
return bm92t_extcon_cable_names[i].name;
|
||||
}
|
||||
|
||||
usb_role_switch_set_role(info->role_sw, usb_role);
|
||||
typec_set_data_role(info->port, role);
|
||||
return bm92t_extcon_cable_names[count - 1].name;
|
||||
}
|
||||
|
||||
static void bm92t_usb_role_update(struct bm92t_info *info)
|
||||
{
|
||||
enum usb_role role;
|
||||
|
||||
/* Consider host mode highest priority */
|
||||
if (extcon_get_state(info->edev, EXTCON_USB_HOST))
|
||||
role = USB_ROLE_HOST;
|
||||
else if (extcon_get_state(info->edev, EXTCON_USB))
|
||||
role = USB_ROLE_DEVICE;
|
||||
else
|
||||
role = USB_ROLE_NONE;
|
||||
|
||||
if (usb_role_switch_get_role(info->role_sw) != role)
|
||||
usb_role_switch_set_role(info->role_sw, role);
|
||||
}
|
||||
|
||||
static void bm92t_extcon_cable_update(struct bm92t_info *info,
|
||||
const unsigned int cable, bool is_attached)
|
||||
{
|
||||
int state = extcon_get_state(info->edev, cable);
|
||||
|
||||
if (state != is_attached) {
|
||||
dev_info(&info->i2c_client->dev, "extcon cable (%02d: %s) %s\n",
|
||||
cable, bm92t_extcon_cable_get_name(cable),
|
||||
is_attached ? "attached" : "detached");
|
||||
extcon_set_state(info->edev, cable, is_attached);
|
||||
}
|
||||
|
||||
switch (cable) {
|
||||
case EXTCON_USB:
|
||||
case EXTCON_USB_HOST:
|
||||
bm92t_usb_role_update(info);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void bm92t_state_machine(struct bm92t_info *info, int state)
|
||||
@@ -930,9 +1040,15 @@ static void bm92t_power_work(struct work_struct *work)
|
||||
|
||||
bm92t_set_current_limit(info, info->cable.charging_limit * 1000u);
|
||||
info->pd_charging_enabled = true;
|
||||
|
||||
extcon_set_state(info->edev, EXTCON_CHG_USB_PD, true);
|
||||
|
||||
#ifdef CONFIG_SWITCH
|
||||
switch_set_state(&info->pd_switch, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void bm92t_port_set_init_state(struct work_struct *work)
|
||||
static void bm92t_extcon_cable_set_init_state(struct work_struct *work)
|
||||
{
|
||||
struct bm92t_info *info = container_of(to_delayed_work(work),
|
||||
struct bm92t_info, oneshot_work);
|
||||
@@ -953,8 +1069,13 @@ static void bm92t_port_set_init_state(struct work_struct *work)
|
||||
/* Enable DisplayPort Alerts */
|
||||
bm92t_set_dp_alerts(info, info->pdata->dp_alerts_enable);
|
||||
|
||||
/* Initialize states for extcons */
|
||||
bm92t_extcon_cable_update(info, EXTCON_DISP_DP, false);
|
||||
bm92t_extcon_cable_update(info, EXTCON_USB_HOST, false);
|
||||
bm92t_extcon_cable_update(info, EXTCON_USB, false);
|
||||
|
||||
dev_info(&info->i2c_client->dev,
|
||||
"port is set to init state\n");
|
||||
"extcon cable is set to init state\n");
|
||||
|
||||
msleep(100); /* Wait a bit */
|
||||
queue_work(info->event_wq, &info->work);
|
||||
@@ -965,16 +1086,16 @@ static bool bm92t_check_pdo(struct bm92t_info *info)
|
||||
int i, err, pdos_no;
|
||||
struct device *dev;
|
||||
unsigned char pdos[29];
|
||||
u32 pdo[7];
|
||||
struct pd_object pdo[7];
|
||||
unsigned int prev_wattage = 0;
|
||||
unsigned int amperage, voltage, wattage;
|
||||
unsigned int amperage, voltage, wattage, type;
|
||||
|
||||
dev = &info->i2c_client->dev;
|
||||
|
||||
memset(&info->cable, 0, sizeof(struct bm92t_device));
|
||||
|
||||
err = bm92t_read_reg(info, READ_PDOS_SRC_REG, pdos, sizeof(pdos));
|
||||
pdos_no = pdos[0] / sizeof(u32);
|
||||
pdos_no = pdos[0] / sizeof(struct pd_object);
|
||||
|
||||
/* Check if errors or no pdo received */
|
||||
if (err || !pdos_no)
|
||||
@@ -984,27 +1105,27 @@ static bool bm92t_check_pdo(struct bm92t_info *info)
|
||||
memcpy(pdo, pdos + 1, pdos[0]);
|
||||
for (i = 0; i < pdos_no; ++i) {
|
||||
dev_info(dev, "PDO %d: %4dmA %5dmV %s\n",
|
||||
i + 1, pdo_fixed_current(pdo[i]),
|
||||
pdo_fixed_voltage(pdo[i]),
|
||||
(pdo[i] & PDO_FIXED_DATA_SWAP) ? "DRD" : "No DRD");
|
||||
i + 1, pdo[i].amp * 10, pdo[i].volt * 50,
|
||||
(pdo[i].info & PDO_INFO_DR_DATA) ? "DRD" : "No DRD");
|
||||
}
|
||||
|
||||
if (pdo[0] & PDO_FIXED_DATA_SWAP)
|
||||
if (pdo[0].info & PDO_INFO_DR_DATA)
|
||||
info->cable.drd_support = true;
|
||||
|
||||
/* Check for dock mode */
|
||||
if (!info->pdata->dock_power_limit_disable &&
|
||||
pdos_no == 2 &&
|
||||
pdo_fixed_voltage(pdo[0]) == DOCK_ID_VOLTAGE_MV &&
|
||||
pdo_fixed_current(pdo[0]) == DOCK_ID_CURRENT_MA) {
|
||||
(pdo[0].volt * 50) == DOCK_ID_VOLTAGE_MV &&
|
||||
(pdo[0].amp * 10) == DOCK_ID_CURRENT_MA) {
|
||||
/* Only accept 15V, >= 2.6A for dock mode. */
|
||||
if (pdo_type(pdo[1]) == PDO_TYPE_FIXED &&
|
||||
pdo_fixed_voltage(pdo[1]) == DOCK_INPUT_VOLTAGE_MV &&
|
||||
pdo_fixed_current(pdo[1]) >= DOCK_INPUT_CURRENT_LIMIT_MIN_MA &&
|
||||
pdo_fixed_current(pdo[1]) <= DOCK_INPUT_CURRENT_LIMIT_MAX_MA) {
|
||||
if (pdo[1].type == PDO_TYPE_FIXED &&
|
||||
(pdo[1].volt * 50) == DOCK_INPUT_VOLTAGE_MV &&
|
||||
(pdo[1].amp * 10) >= DOCK_INPUT_CURRENT_LIMIT_MIN_MA &&
|
||||
(pdo[1].amp * 10) <= DOCK_INPUT_CURRENT_LIMIT_MAX_MA) {
|
||||
dev_info(dev, "Device in Nintendo mode\n");
|
||||
info->cable.pdo_no = 2;
|
||||
info->cable.pdo = pdo[1];
|
||||
memcpy(&info->cable.pdo, &pdo[1],
|
||||
sizeof(struct pd_object));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1014,8 +1135,9 @@ static bool bm92t_check_pdo(struct bm92t_info *info)
|
||||
|
||||
/* Not in dock mode. Check for max possible wattage */
|
||||
for (i = 0; i < pdos_no; ++i) {
|
||||
voltage = pdo_fixed_voltage(pdo[i]);
|
||||
amperage = pdo_fixed_current(pdo[i]);
|
||||
type = pdo[i].type;
|
||||
voltage = pdo[i].volt * 50;
|
||||
amperage = pdo[i].amp * 10;
|
||||
wattage = voltage * amperage;
|
||||
|
||||
/* Only USB-PD defined voltages with max 15V. */
|
||||
@@ -1030,16 +1152,17 @@ static bool bm92t_check_pdo(struct bm92t_info *info)
|
||||
}
|
||||
|
||||
/* Only accept <= 3A and select max wattage with max voltage. */
|
||||
if (pdo_type(pdo[i]) == PDO_TYPE_FIXED &&
|
||||
if (type == PDO_TYPE_FIXED &&
|
||||
amperage >= PD_INPUT_CURRENT_LIMIT_MIN_MA &&
|
||||
amperage <= PD_INPUT_CURRENT_LIMIT_MAX_MA) {
|
||||
if (wattage > prev_wattage ||
|
||||
(voltage > pdo_fixed_voltage(info->cable.pdo) &&
|
||||
(voltage > (info->cable.pdo.volt * 50) &&
|
||||
wattage && wattage == prev_wattage) ||
|
||||
(!info->cable.pdo_no && !amperage && voltage == 5000)) {
|
||||
prev_wattage = wattage;
|
||||
info->cable.pdo_no = i + 1;
|
||||
info->cable.pdo = pdo[i];
|
||||
memcpy(&info->cable.pdo, &pdo[i],
|
||||
sizeof(struct pd_object));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1054,25 +1177,26 @@ static bool bm92t_check_pdo(struct bm92t_info *info)
|
||||
|
||||
static int bm92t_send_rdo(struct bm92t_info *info)
|
||||
{
|
||||
u32 rdo;
|
||||
struct rd_object rdo = { 0 };
|
||||
unsigned char msg[6] = { SET_RDO_REG, 0x04, 0x00, 0x00, 0x00, 0x00};
|
||||
unsigned short cmd = SEND_RDO_CMD;
|
||||
|
||||
/* Calculate operating current */
|
||||
bm92t_calculate_current_limit(info, pdo_fixed_voltage(info->cable.pdo),
|
||||
pdo_fixed_current(info->cable.pdo));
|
||||
bm92t_calculate_current_limit(info, info->cable.pdo.volt * 50,
|
||||
info->cable.pdo.amp * 10);
|
||||
|
||||
dev_info(&info->i2c_client->dev,
|
||||
"Requesting %d: min %dmA, max %4dmA, %5dmV\n",
|
||||
info->cable.pdo_no, info->cable.charging_limit,
|
||||
pdo_fixed_current(info->cable.pdo),
|
||||
pdo_fixed_voltage(info->cable.pdo));
|
||||
"Requesting %d: min %dmA, max %4dmA, %5dmV\n",
|
||||
info->cable.pdo_no, info->cable.charging_limit,
|
||||
info->cable.pdo.amp * 10,
|
||||
info->cable.pdo.volt * 50);
|
||||
|
||||
rdo = RDO_FIXED(info->cable.pdo_no, info->cable.charging_limit,
|
||||
pdo_fixed_current(info->cable.pdo),
|
||||
RDO_USB_COMM | RDO_NO_SUSPEND);
|
||||
rdo.usb_comms = 1;
|
||||
rdo.obj_no = info->cable.pdo_no;
|
||||
rdo.max_amp = info->cable.pdo.amp;
|
||||
rdo.op_amp = info->cable.charging_limit / 10;
|
||||
|
||||
memcpy(&msg[2], &rdo, sizeof(u32));
|
||||
memcpy(&msg[2], &rdo, sizeof(struct rd_object));
|
||||
|
||||
if (bm92t_write_reg(info, msg, sizeof(msg))) {
|
||||
dev_err(&info->i2c_client->dev, "Send RDO failure!\n");
|
||||
@@ -1157,84 +1281,36 @@ static void bm92t_usbhub_dp_sleep(struct bm92t_info *info, bool sleep)
|
||||
}
|
||||
|
||||
static void bm92t_print_dp_dev_info(struct device *dev,
|
||||
struct usb_pd_identity *id)
|
||||
struct vd_object *vdo)
|
||||
{
|
||||
u32 idh = id->id_header;
|
||||
|
||||
dev_info(dev, "Connected PD device:\n");
|
||||
dev_info(dev, "VID: %04X, PID: %04X\n",
|
||||
PD_IDH_VID(idh), PD_PRODUCT_PID(id->product));
|
||||
dev_info(dev, "VID: %04X, PID: %04X\n", vdo->vid, vdo->pid);
|
||||
|
||||
switch (PD_IDH_PTYPE(idh)) {
|
||||
case IDH_PTYPE_UNDEF:
|
||||
switch (vdo->type) {
|
||||
case VDO_ID_TYPE_NONE:
|
||||
dev_info(dev, "Type: Undefined\n");
|
||||
break;
|
||||
case IDH_PTYPE_HUB:
|
||||
case VDO_ID_TYPE_PD_HUB:
|
||||
dev_info(dev, "Type: PD HUB\n");
|
||||
break;
|
||||
case IDH_PTYPE_PERIPH:
|
||||
case VDO_ID_TYPE_PD_PERIPH:
|
||||
dev_info(dev, "Type: PD Peripheral\n");
|
||||
break;
|
||||
case IDH_PTYPE_PCABLE:
|
||||
case VDO_ID_TYPE_PASS_CBL:
|
||||
dev_info(dev, "Type: Passive Cable\n");
|
||||
break;
|
||||
case IDH_PTYPE_ACABLE:
|
||||
case VDO_ID_TYPE_ACTI_CBL:
|
||||
dev_info(dev, "Type: Active Cable\n");
|
||||
break;
|
||||
case IDH_PTYPE_AMA:
|
||||
case VDO_ID_TYPE_ALTERNATE:
|
||||
dev_info(dev, "Type: Alternate Mode Adapter\n");
|
||||
break;
|
||||
default:
|
||||
dev_info(dev, "Type: Unknown (%d)\n", PD_IDH_PTYPE(idh));
|
||||
dev_info(dev, "Type: Unknown (%d)\n", vdo->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void bm92t_connect(struct bm92t_info *info, unsigned short status1_data)
|
||||
{
|
||||
struct typec_partner_desc desc;
|
||||
|
||||
if (info->partner)
|
||||
return;
|
||||
|
||||
memset(&info->partner_identity, 0, sizeof(info->partner_identity));
|
||||
|
||||
desc.usb_pd = true;
|
||||
desc.accessory = TYPEC_ACCESSORY_NONE;
|
||||
desc.identity = &info->partner_identity;
|
||||
|
||||
info->partner = typec_register_partner(info->port, &desc);
|
||||
if (IS_ERR(info->partner)) {
|
||||
dev_err(&info->i2c_client->dev, "failed to register partner\n");
|
||||
info->partner = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
typec_set_pwr_opmode(info->port, TYPEC_PWR_MODE_PD);
|
||||
typec_set_pwr_role(info->port, bm92t_is_dfp(status1_data) ?
|
||||
TYPEC_SOURCE : TYPEC_SINK);
|
||||
typec_set_vconn_role(info->port, TYPEC_SOURCE);
|
||||
bm92t_set_data_role(info, bm92t_is_dfp(status1_data) ?
|
||||
TYPEC_HOST : TYPEC_DEVICE, true);
|
||||
}
|
||||
|
||||
static void bm92t_disconnect(struct bm92t_info *info, unsigned short status1_data)
|
||||
{
|
||||
if (info->partner) {
|
||||
typec_unregister_partner(info->partner);
|
||||
info->partner = NULL;
|
||||
}
|
||||
|
||||
typec_set_pwr_opmode(info->port, TYPEC_PWR_MODE_USB);
|
||||
typec_set_pwr_role(info->port, TYPEC_SINK);
|
||||
typec_set_vconn_role(info->port, TYPEC_SINK);
|
||||
bm92t_set_data_role(info, TYPEC_DEVICE, false);
|
||||
|
||||
if (info->connector_fwnode)
|
||||
drm_connector_oob_hotplug_event(info->connector_fwnode,
|
||||
connector_status_disconnected);
|
||||
}
|
||||
|
||||
static void bm92t_event_handler(struct work_struct *work)
|
||||
{
|
||||
static bool sys_reset;
|
||||
@@ -1242,7 +1318,8 @@ static void bm92t_event_handler(struct work_struct *work)
|
||||
int i, err;
|
||||
struct bm92t_info *info;
|
||||
struct device *dev;
|
||||
u32 curr_pdo, curr_rdo;
|
||||
struct pd_object curr_pdo;
|
||||
struct rd_object curr_rdo;
|
||||
unsigned short cmd;
|
||||
unsigned short alert_data;
|
||||
unsigned short status1_data;
|
||||
@@ -1297,7 +1374,9 @@ static void bm92t_event_handler(struct work_struct *work)
|
||||
if (err) {
|
||||
dev_err(dev, "Internal error occurred. Ecode = %d\n", err);
|
||||
bm92t_state_machine(info, INIT_STATE);
|
||||
bm92t_disconnect(info, status1_data);
|
||||
bm92t_extcon_cable_update(info, EXTCON_DISP_DP, false);
|
||||
bm92t_extcon_cable_update(info, EXTCON_USB_HOST, false);
|
||||
bm92t_extcon_cable_update(info, EXTCON_USB, false);
|
||||
bm92t_set_vbus_enable(info, false);
|
||||
if (bm92t_is_plugged(status1_data) ||
|
||||
alert_data & ALERT_SNK_FAULT ||
|
||||
@@ -1341,11 +1420,18 @@ src_fault:
|
||||
if (info->pd_charging_enabled) {
|
||||
bm92t_set_current_limit(info, 0);
|
||||
info->pd_charging_enabled = false;
|
||||
bm92t_extcon_cable_update(info,
|
||||
EXTCON_CHG_USB_PD, false);
|
||||
#ifdef CONFIG_SWITCH
|
||||
switch_set_state(&info->pd_switch, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Reset USB modes and state */
|
||||
retries_usbhub = 10;
|
||||
bm92t_disconnect(info, status1_data);
|
||||
bm92t_extcon_cable_update(info, EXTCON_DISP_DP, false);
|
||||
bm92t_extcon_cable_update(info, EXTCON_USB_HOST, false);
|
||||
bm92t_extcon_cable_update(info, EXTCON_USB, false);
|
||||
bm92t_state_machine(info, INIT_STATE);
|
||||
goto ret;
|
||||
} else if (status1_data & STATUS1_SRC_MODE && /* OTG plug event */
|
||||
@@ -1353,7 +1439,9 @@ src_fault:
|
||||
/* Enable VBUS for sourcing power to OTG device */
|
||||
bm92t_set_vbus_enable(info, true);
|
||||
|
||||
bm92t_connect(info, status1_data);
|
||||
/* Set USB to host mode */
|
||||
bm92t_extcon_cable_update(info, EXTCON_USB, false);
|
||||
bm92t_extcon_cable_update(info, EXTCON_USB_HOST, true);
|
||||
goto ret;
|
||||
} else if (alert_data & ALERT_CONTRACT) {
|
||||
/* When there's a plug-in wake-up, check if a new
|
||||
@@ -1408,14 +1496,13 @@ handle_new_state:
|
||||
goto init_contract_out;
|
||||
}
|
||||
|
||||
/* Register partner if not already */
|
||||
bm92t_connect(info, status1_data);
|
||||
|
||||
/* Negotiate new power profile */
|
||||
if (!bm92t_check_pdo(info)) {
|
||||
dev_info(dev, "Power Negotiation not supported\n");
|
||||
bm92t_state_machine(info, INIT_STATE);
|
||||
msleep(550); /* WAR: charger good power test */
|
||||
bm92t_extcon_cable_update(info,
|
||||
EXTCON_USB, true);
|
||||
goto init_contract_out;
|
||||
}
|
||||
|
||||
@@ -1431,7 +1518,7 @@ init_contract_out:
|
||||
|
||||
/* Check if forced workqueue and unplugged */
|
||||
if (!alert_data && !bm92t_is_plugged(status1_data))
|
||||
bm92t_disconnect(info, status1_data);
|
||||
bm92t_extcon_cable_update(info, EXTCON_USB, false);
|
||||
break;
|
||||
|
||||
case NEW_PDO:
|
||||
@@ -1442,20 +1529,19 @@ init_contract_out:
|
||||
/* Check PDO/RDO */
|
||||
err = bm92t_read_reg(info, CURRENT_PDO_REG,
|
||||
pdo, sizeof(pdo));
|
||||
memcpy(&curr_pdo, &pdo[1], sizeof(u32));
|
||||
memcpy(&curr_pdo, &pdo[1], sizeof(struct pd_object));
|
||||
err = bm92t_read_reg(info, CURRENT_RDO_REG,
|
||||
rdo, sizeof(rdo));
|
||||
memcpy(&curr_rdo, &rdo[1], sizeof(u32));
|
||||
memcpy(&curr_rdo, &rdo[1], sizeof(struct rd_object));
|
||||
|
||||
dev_info(dev, "New PD Contract:\n");
|
||||
dev_info(dev, "PDO: %d: %dmA, %dmV\n",
|
||||
info->cable.pdo_no, pdo_fixed_current(curr_pdo),
|
||||
pdo_fixed_voltage(curr_pdo));
|
||||
info->cable.pdo_no, curr_pdo.amp * 10,
|
||||
curr_pdo.volt * 50);
|
||||
dev_info(dev, "RDO: op %dmA, %dmA max\n",
|
||||
rdo_op_current(curr_rdo),
|
||||
rdo_max_current(curr_rdo));
|
||||
curr_rdo.op_amp * 10, curr_rdo.max_amp * 10);
|
||||
|
||||
if (curr_rdo & RDO_CAP_MISMATCH)
|
||||
if (curr_rdo.mismatch)
|
||||
dev_err(dev, "PD mismatch!\n");
|
||||
|
||||
cmd = PS_RDY_CMD;
|
||||
@@ -1466,6 +1552,7 @@ init_contract_out:
|
||||
|
||||
case PS_RDY_SENT:
|
||||
if (bm92t_is_success(alert_data)) {
|
||||
bm92t_extcon_cable_update(info, EXTCON_USB_HOST, true);
|
||||
schedule_delayed_work(&info->power_work,
|
||||
msecs_to_jiffies(2000));
|
||||
|
||||
@@ -1493,15 +1580,15 @@ init_contract_out:
|
||||
bm92t_is_plugged(status1_data) &&
|
||||
bm92t_is_lastcmd_ok(info, "DR_SWAP_CMD", status1_data) &&
|
||||
bm92t_is_dfp(status1_data)) {
|
||||
bm92t_set_data_role(info, TYPEC_HOST, true);
|
||||
bm92t_send_vdm(info, vdm_discover_id_msg,
|
||||
sizeof(vdm_discover_id_msg));
|
||||
bm92t_state_machine(info, VDM_DISC_ID_SENT);
|
||||
} else if (bm92t_is_plugged(status1_data) &&
|
||||
bm92t_lastcmd_status(status1_data) ==
|
||||
LASTCMD_REJECTED) {
|
||||
LASTCMD_REJECTED) {
|
||||
/* UFP rejected data role swap. */
|
||||
bm92t_set_data_role(info, TYPEC_DEVICE, true);
|
||||
bm92t_extcon_cable_update(info, EXTCON_USB_HOST, false);
|
||||
bm92t_extcon_cable_update(info, EXTCON_USB, true);
|
||||
bm92t_state_machine(info, INIT_STATE);
|
||||
}
|
||||
break;
|
||||
@@ -1531,31 +1618,15 @@ init_contract_out:
|
||||
err = bm92t_read_reg(info, INCOMING_VDM_REG,
|
||||
vdm, sizeof(vdm));
|
||||
|
||||
/* VDM layout: [0]=size, [1]=cmd/ack, [2]=structured,
|
||||
* [3-4]=SVID, [5..]=VDO objects
|
||||
*/
|
||||
info->partner_identity.id_header =
|
||||
vdm[5] | (vdm[6] << 8) |
|
||||
(vdm[7] << 16) | (vdm[8] << 24);
|
||||
info->partner_identity.cert_stat =
|
||||
vdm[9] | (vdm[10] << 8) |
|
||||
(vdm[11] << 16) | (vdm[12] << 24);
|
||||
info->partner_identity.product =
|
||||
vdm[13] | (vdm[14] << 8) |
|
||||
(vdm[15] << 16) | (vdm[16] << 24);
|
||||
memcpy(&info->cable.vdo, &vdm[5],
|
||||
sizeof(struct vd_object));
|
||||
|
||||
bm92t_print_dp_dev_info(dev, &info->partner_identity);
|
||||
|
||||
if (info->partner)
|
||||
typec_partner_set_identity(info->partner);
|
||||
bm92t_print_dp_dev_info(dev, &info->cable.vdo);
|
||||
|
||||
/* Check if Nintendo dock. */
|
||||
if (!(PD_IDH_PTYPE(info->partner_identity.id_header)
|
||||
== IDH_PTYPE_AMA &&
|
||||
PD_IDH_VID(info->partner_identity.id_header)
|
||||
== VID_NINTENDO &&
|
||||
PD_PRODUCT_PID(info->partner_identity.product)
|
||||
== PID_NIN_DOCK)) {
|
||||
if (!(info->cable.vdo.type == VDO_ID_TYPE_ALTERNATE &&
|
||||
info->cable.vdo.vid == VID_NINTENDO &&
|
||||
info->cable.vdo.pid == PID_NIN_DOCK)) {
|
||||
dev_info(dev, "VID/PID not Nintendo Dock\n");
|
||||
|
||||
if (info->pdata->dp_disable) {
|
||||
@@ -1709,12 +1780,8 @@ init_contract_out:
|
||||
} else
|
||||
bm92t_state_machine(info,
|
||||
DOCK_CONFIG_HANDLED);
|
||||
|
||||
/* Report DP connection to DRM */
|
||||
if (info->connector_fwnode)
|
||||
drm_connector_oob_hotplug_event(
|
||||
info->connector_fwnode,
|
||||
connector_status_connected);
|
||||
bm92t_extcon_cable_update(info,
|
||||
EXTCON_DISP_DP, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1739,9 +1806,11 @@ init_contract_out:
|
||||
vdm[7] == (VDM_NCMD_DEVICE_STATE + 1)) {
|
||||
/* Check if USB HUB is supported */
|
||||
if (vdm[11] & 0x02) {
|
||||
bm92t_set_data_role(info, TYPEC_DEVICE, false);
|
||||
bm92t_extcon_cable_update(info,
|
||||
EXTCON_USB_HOST, false);
|
||||
msleep(500);
|
||||
bm92t_set_data_role(info, TYPEC_DEVICE, true);
|
||||
bm92t_extcon_cable_update(info,
|
||||
EXTCON_USB, true);
|
||||
dev_warn(dev, "Dock has old FW!\n");
|
||||
}
|
||||
dev_info(dev, "Dock state: %02X %02X %02X %02X\n",
|
||||
@@ -1875,21 +1944,6 @@ static void bm92t_remove(struct i2c_client *client)
|
||||
{
|
||||
struct bm92t_info *info = i2c_get_clientdata(client);
|
||||
|
||||
if (client->irq > 0)
|
||||
free_irq(client->irq, info);
|
||||
|
||||
cancel_delayed_work_sync(&info->oneshot_work);
|
||||
cancel_delayed_work_sync(&info->power_work);
|
||||
cancel_work_sync(&info->work);
|
||||
destroy_workqueue(info->event_wq);
|
||||
|
||||
if (info->partner)
|
||||
typec_unregister_partner(info->partner);
|
||||
|
||||
typec_unregister_port(info->port);
|
||||
usb_role_switch_put(info->role_sw);
|
||||
fwnode_handle_put(info->connector_fwnode);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
debugfs_remove_recursive(info->debugfs_root);
|
||||
#endif
|
||||
@@ -2293,57 +2347,12 @@ static struct bm92t_platform_data *bm92t_parse_dt(struct device *dev)
|
||||
}
|
||||
#endif
|
||||
|
||||
static int bm92t_try_role(struct typec_port *port, int role)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int bm92t_dr_set(struct typec_port *port, enum typec_data_role role)
|
||||
{
|
||||
struct bm92t_info *info = typec_get_drvdata(port);
|
||||
unsigned short cmd = DR_SWAP_CMD;
|
||||
|
||||
return bm92t_send_cmd(info, &cmd);
|
||||
}
|
||||
|
||||
static int bm92t_pr_set(struct typec_port *port, enum typec_role role)
|
||||
{
|
||||
struct bm92t_info *info = typec_get_drvdata(port);
|
||||
unsigned short cmd = PR_SWAP_CMD;
|
||||
|
||||
return bm92t_send_cmd(info, &cmd);
|
||||
}
|
||||
|
||||
static int bm92t_port_type_set(struct typec_port *port,
|
||||
enum typec_port_type type)
|
||||
{
|
||||
struct bm92t_info *info = typec_get_drvdata(port);
|
||||
|
||||
switch (type) {
|
||||
case TYPEC_PORT_SNK:
|
||||
return bm92t_set_source_mode(info, SPDSRC12_OFF);
|
||||
case TYPEC_PORT_SRC:
|
||||
case TYPEC_PORT_DRP:
|
||||
return bm92t_set_source_mode(info, SPDSRC12_ON);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct typec_operations bm92t_ops = {
|
||||
.try_role = bm92t_try_role,
|
||||
.dr_set = bm92t_dr_set,
|
||||
.pr_set = bm92t_pr_set,
|
||||
.port_type_set = bm92t_port_type_set,
|
||||
};
|
||||
|
||||
static int bm92t_probe(struct i2c_client *client)
|
||||
{
|
||||
struct bm92t_info *info;
|
||||
struct fwnode_handle *connector;
|
||||
struct fwnode_handle *ep, *remote;
|
||||
struct regulator *batt_chg_reg;
|
||||
struct regulator *vbus_reg, *vbus_src_reg;
|
||||
struct typec_capability typec_cap = { };
|
||||
int err;
|
||||
unsigned short reg_value;
|
||||
|
||||
@@ -2409,25 +2418,25 @@ static int bm92t_probe(struct i2c_client *client)
|
||||
gpio_direction_output(info->pdata->vconn_en_gpio, 0);
|
||||
}
|
||||
|
||||
/* Get connector fwnode (st style) */
|
||||
connector = device_get_named_child_node(&client->dev, "connector");
|
||||
if (!connector) {
|
||||
dev_err(&client->dev, "Connector node not found\n");
|
||||
ep = fwnode_graph_get_endpoint_by_id(
|
||||
dev_fwnode(&client->dev), 0, 0, 0);
|
||||
if (!ep) {
|
||||
dev_err(&client->dev, "Endpoint not found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
fw_devlink_purge_absent_suppliers(connector);
|
||||
|
||||
info->role_sw = fwnode_usb_role_switch_get(connector);
|
||||
if (IS_ERR(info->role_sw)) {
|
||||
err = PTR_ERR(info->role_sw);
|
||||
dev_err(&client->dev, "Failed to get usb role switch: %d\n", err);
|
||||
goto err_put_connector;
|
||||
remote = fwnode_graph_get_remote_endpoint(ep);
|
||||
if (!remote) {
|
||||
dev_err(&client->dev, "Remote not found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Optional DP connector fwnode for HPD reporting */
|
||||
info->connector_fwnode = fwnode_find_reference(connector, "displayport", 0);
|
||||
if (IS_ERR(info->connector_fwnode))
|
||||
info->connector_fwnode = NULL;
|
||||
info->role_sw = fwnode_usb_role_switch_get(remote);
|
||||
if (IS_ERR(info->role_sw)) {
|
||||
err = PTR_ERR(info->role_sw);
|
||||
dev_err(&client->dev, "Failed to retrieve fwnode: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, info);
|
||||
|
||||
@@ -2440,29 +2449,25 @@ static int bm92t_probe(struct i2c_client *client)
|
||||
info->state = INIT_STATE;
|
||||
info->first_init = true;
|
||||
|
||||
/* Register typec port */
|
||||
typec_cap.revision = USB_TYPEC_REV_1_2;
|
||||
typec_cap.pd_revision = 0x200;
|
||||
typec_cap.prefer_role = TYPEC_NO_PREFERRED_ROLE;
|
||||
typec_cap.type = TYPEC_PORT_DRP;
|
||||
typec_cap.data = TYPEC_PORT_DRD;
|
||||
typec_cap.driver_data = info;
|
||||
typec_cap.ops = &bm92t_ops;
|
||||
typec_cap.fwnode = connector;
|
||||
/* Allocate extcon */
|
||||
info->edev = devm_extcon_dev_allocate(&client->dev, bm92t_extcon_cable);
|
||||
if (IS_ERR(info->edev)) {
|
||||
dev_err(&client->dev, "kzalloc error\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
info->port = typec_register_port(&client->dev, &typec_cap);
|
||||
if (IS_ERR(info->port)) {
|
||||
err = PTR_ERR(info->port);
|
||||
dev_err(&client->dev, "failed to register typec port: %d\n", err);
|
||||
goto err_put_role;
|
||||
/* Register extcon */
|
||||
err = devm_extcon_dev_register(&client->dev, info->edev);
|
||||
if (err < 0) {
|
||||
dev_err(&client->dev, "Cannot register extcon device\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Create workqueue */
|
||||
info->event_wq = create_singlethread_workqueue("bm92t-event-queue");
|
||||
if (!info->event_wq) {
|
||||
dev_err(&client->dev, "Cannot create work queue\n");
|
||||
err = -ENOMEM;
|
||||
goto err_unreg_port;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
err = bm92t_read_reg(info, FW_TYPE_REG,
|
||||
@@ -2478,8 +2483,7 @@ static int bm92t_probe(struct i2c_client *client)
|
||||
|
||||
if (info->fw_revision <= 0x644) {
|
||||
dev_err(&client->dev, "fw revision not supported\n");
|
||||
err = -EINVAL;
|
||||
goto err_destroy_wq;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Disable Source mode at boot */
|
||||
@@ -2487,29 +2491,27 @@ static int bm92t_probe(struct i2c_client *client)
|
||||
|
||||
INIT_WORK(&info->work, bm92t_event_handler);
|
||||
INIT_DELAYED_WORK(&info->oneshot_work,
|
||||
bm92t_port_set_init_state);
|
||||
bm92t_extcon_cable_set_init_state);
|
||||
|
||||
INIT_DELAYED_WORK(&info->power_work, bm92t_power_work);
|
||||
|
||||
if (client->irq > 0) {
|
||||
/*
|
||||
* Level-triggered (active-low) IRQ wired to BM92T36 ALERT.
|
||||
* Use a threaded handler with IRQF_ONESHOT so the line is
|
||||
* masked while bm92t_interrupt_handler runs i2c reads, then
|
||||
* re-enabled after the work clears the controller's status.
|
||||
* Without IRQF_ONESHOT this would re-enter immediately on
|
||||
* the still-asserted line and "irq nobody cared" disable it.
|
||||
*/
|
||||
if (request_threaded_irq(client->irq, NULL,
|
||||
bm92t_interrupt_handler,
|
||||
IRQF_TRIGGER_LOW | IRQF_ONESHOT, "bm92t",
|
||||
if (request_irq(client->irq, bm92t_interrupt_handler,
|
||||
IRQF_TRIGGER_LOW, "bm92t",
|
||||
info)) {
|
||||
dev_err(&client->dev, "Request irq failed\n");
|
||||
err = -EBUSY;
|
||||
goto err_destroy_wq;
|
||||
destroy_workqueue(info->event_wq);
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SWITCH
|
||||
info->pd_switch.name = pd_switch_name;
|
||||
err = switch_dev_register(&info->pd_switch);
|
||||
if (err)
|
||||
dev_err(&client->dev, "failed to register pd switch, err=%d\n", err);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
bm92t_debug_init(info);
|
||||
#endif
|
||||
@@ -2526,18 +2528,7 @@ static int bm92t_probe(struct i2c_client *client)
|
||||
|
||||
dev_info(&client->dev, "init done\n");
|
||||
|
||||
fwnode_handle_put(connector);
|
||||
return 0;
|
||||
|
||||
err_destroy_wq:
|
||||
destroy_workqueue(info->event_wq);
|
||||
err_unreg_port:
|
||||
typec_unregister_port(info->port);
|
||||
err_put_role:
|
||||
usb_role_switch_put(info->role_sw);
|
||||
err_put_connector:
|
||||
fwnode_handle_put(connector);
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
@@ -2653,5 +2644,5 @@ static void __exit bm92t_exit(void)
|
||||
module_exit(bm92t_exit);
|
||||
|
||||
MODULE_AUTHOR("CTCaer <ctcaer@gmail.com>");
|
||||
MODULE_DESCRIPTION("Rohm BM92TXX USB Type-C and PD controller driver");
|
||||
MODULE_DESCRIPTION("BM92TXX USB PD/DP management IC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
Reference in new issue
Block a user