Created
October 7, 2014 04:45
-
-
Save webgeek1234/8eea739d16f03dfa715b to your computer and use it in GitHub Desktop.
Add Nvidia Shield support to the Fedora kernel (kernel code by Gnurou [Alexandre Courbot])
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/SOURCES/config-arm-generic b/SOURCES/config-arm-generic | |
index 38a0016..4b65909 100644 | |
--- a/SOURCES/config-arm-generic | |
+++ b/SOURCES/config-arm-generic | |
@@ -25,7 +25,7 @@ CONFIG_RESET_GPIO=y | |
CONFIG_RCU_FANOUT_LEAF=16 | |
# CONFIG_RTC_DRV_SNVS is not set | |
# CONFIG_RTC_DRV_HYM8563 is not set | |
-CONFIG_BACKLIGHT_PWM=m | |
+CONFIG_BACKLIGHT_PWM=y | |
CONFIG_INPUT_PWM_BEEPER=m | |
CONFIG_ARM_SP805_WATCHDOG=m | |
CONFIG_ARM_ARCH_TIMER=y | |
diff --git a/SOURCES/config-armv7 b/SOURCES/config-armv7 | |
index 4ddeea5..c74d664 100644 | |
--- a/SOURCES/config-armv7 | |
+++ b/SOURCES/config-armv7 | |
@@ -170,7 +170,7 @@ CONFIG_GPIO_PALMAS=y | |
CONFIG_PINCTRL_PALMAS=y | |
CONFIG_REGULATOR_PALMAS=y | |
CONFIG_REGULATOR_PBIAS=m | |
-CONFIG_RTC_DRV_PALMAS=m | |
+CONFIG_RTC_DRV_PALMAS=y | |
CONFIG_OMAP5_DSS_HDMI=y | |
CONFIG_OMAP5_DSS_HDMI_AUDIO=y | |
diff --git a/SOURCES/config-armv7-generic b/SOURCES/config-armv7-generic | |
index 66d8a59..1651e26 100644 | |
--- a/SOURCES/config-armv7-generic | |
+++ b/SOURCES/config-armv7-generic | |
@@ -301,27 +301,28 @@ CONFIG_TEGRA30_MC=y | |
CONFIG_PCI_TEGRA=y | |
CONFIG_AHCI_TEGRA=m | |
CONFIG_TEGRA_IOMMU_SMMU=y | |
CONFIG_MMC_SDHCI_TEGRA=m | |
CONFIG_TEGRA_WATCHDOG=m | |
-CONFIG_I2C_TEGRA=m | |
+CONFIG_I2C_TEGRA=y | |
CONFIG_TEGRA_SYSTEM_DMA=y | |
CONFIG_TEGRA_EMC_SCALING_ENABLE=y | |
CONFIG_TEGRA_AHB=y | |
CONFIG_TEGRA20_APB_DMA=y | |
CONFIG_SPI_TEGRA114=m | |
-CONFIG_PWM_TEGRA=m | |
+CONFIG_PWM_TEGRA=y | |
CONFIG_KEYBOARD_TEGRA=m | |
CONFIG_USB_EHCI_TEGRA=m | |
CONFIG_RTC_DRV_TEGRA=m | |
CONFIG_SND_SOC_TEGRA=m | |
CONFIG_SND_SOC_TEGRA_MAX98090=m | |
CONFIG_SND_SOC_TEGRA_RT5640=m | |
CONFIG_SND_SOC_TEGRA30_AHUB=m | |
CONFIG_SND_SOC_TEGRA30_I2S=m | |
CONFIG_SND_HDA_TEGRA=m | |
-CONFIG_TEGRA_HOST1X=m | |
+CONFIG_TEGRA_HOST1X=y | |
CONFIG_TEGRA_HOST1X_FIREWALL=y | |
-CONFIG_DRM_TEGRA=m | |
+CONFIG_DRM_TEGRA=y | |
+CONFIG_REGULATOR_BQ2419X=m | |
CONFIG_DRM_TEGRA_FBDEV=y | |
# CONFIG_DRM_TEGRA_DEBUG is not set | |
CONFIG_DRM_TEGRA_STAGING=y | |
@@ -336,7 +336,7 @@ CONFIG_NOUVEAU_PLATFORM_DRIVER=m | |
# DRM panels | |
CONFIG_DRM_PANEL=y | |
-CONFIG_DRM_PANEL_SIMPLE=m | |
+CONFIG_DRM_PANEL_SIMPLE=y | |
CONFIG_DRM_PANEL_LD9040=m | |
CONFIG_DRM_PANEL_S6E8AA0=m | |
diff --git a/SOURCES/config-generic b/SOURCES/config-generic | |
index 8f55188..2e2c26d 100644 | |
--- a/SOURCES/config-generic | |
+++ b/SOURCES/config-generic | |
@@ -2906,7 +2906,7 @@ CONFIG_VGA_ARB_MAX_GPUS=16 | |
# CONFIG_STUB_POULSBO is not set | |
-CONFIG_DRM=m | |
+CONFIG_DRM=y | |
CONFIG_DRM_LOAD_EDID_FIRMWARE=y | |
CONFIG_DRM_AST=m # do not enable on f17 or older | |
CONFIG_DRM_CIRRUS_QEMU=m # do not enable on f17 or older | |
@@ -5252,3 +5252,29 @@ CONFIG_FMC_CHARDEV=m | |
# CONFIG_RTC_DRV_EFI is not set | |
# CONFIG_NET_XGENE is not set | |
+ | |
+# CONFIG_MFD_AS3711 is not set | |
+# CONFIG_PMIC_ADP5520 is not set | |
+# CONFIG_MFD_AAT2870_CORE is not set | |
+# CONFIG_MFD_AXP20X is not set | |
+# CONFIG_PMIC_DA903X is not set | |
+# CONFIG_MFD_DA9052_I2C is not set | |
+# CONFIG_MFD_DA9055 is not set | |
+# CONFIG_MFD_88PM800 is not set | |
+# CONFIG_MFD_88PM805 is not set | |
+# CONFIG_MFD_MAX14577 is not set | |
+# CONFIG_MFD_MAX77686 is not set | |
+# CONFIG_MFD_MAX77693 is not set | |
+# CONFIG_MFD_MAX8907 is not set | |
+# CONFIG_MFD_MAX8997 is not set | |
+# CONFIG_MFD_RC5T583 is not set | |
+# CONFIG_MFD_SEC_CORE is not set | |
+# CONFIG_MFD_SMSC is not set | |
+# CONFIG_MFD_LP8788 is not set | |
+# CONFIG_MFD_PALMAS is not set | |
+# CONFIG_MFD_TPS65090 is not set | |
+# CONFIG_MFD_TPS65910 is not set | |
+# CONFIG_MFD_TPS65912_I2C is not set | |
+# CONFIG_MFD_TPS80031 is not set | |
+# CONFIG_TWL4030_CORE is not set | |
+# CONFIG_TWL6040_CORE is not set | |
diff --git a/SPECS/kernel.spec.orig b/SPECS/kernel.spec | |
index 93b38dd..7f3f22c 100644 | |
--- a/SPECS/kernel.spec.orig | |
+++ b/SPECS/kernel.spec | |
@@ -31,7 +31,7 @@ Summary: The Linux kernel | |
# | |
# (Uncomment the '#' and both spaces below to set the buildid.) | |
# | |
-# % define buildid .local | |
+%define buildid .shield | |
################################################################### | |
# The buildid can also be specified on the rpmbuild command line | |
@@ -675,6 +675,7 @@ Patch21022: arm-imx6-utilite.patch | |
# http://www.spinics.net/lists/linux-tegra/msg17948.html | |
Patch21023: arm-tegra-drmdetection.patch | |
Patch21024: arm-qemu-fixdisplay.patch | |
+Patch21050: arm-roth.patch | |
#rhbz 754518 | |
Patch21235: scsi-sd_revalidate_disk-prevent-NULL-ptr-deref.patch | |
@@ -1281,6 +1282,7 @@ ApplyPatch arm-beagle.patch | |
ApplyPatch arm-imx6-utilite.patch | |
ApplyPatch arm-tegra-drmdetection.patch | |
ApplyPatch arm-qemu-fixdisplay.patch | |
+ApplyPatch arm-roth.patch | |
# | |
# bugfixes to drivers and filesystems | |
diff --git a/SOURCES/arm-roth.patch b/SOURCES/arm-roth.patch | |
new file mode 100644 | |
index 0000000..0d940be | |
--- /dev/null | |
+++ b/SOURCES/arm-roth.patch | |
@@ -0,0 +1,1515 @@ | |
+diff --git a/Documentation/devicetree/bindings/regulator/bq2419x-regulator.txt b/Documentation/devicetree/bindings/regulator/bq2419x-regulator.txt | |
+new file mode 100644 | |
+index 0000000000000000000000000000000000000000..c840fac6da93851061b368d15a214c83ca5f57af | |
+--- /dev/null | |
++++ b/Documentation/devicetree/bindings/regulator/bq2419x-regulator.txt | |
+@@ -0,0 +1,44 @@ | |
++TI BQ24190/BQ24192/BQ24192i/BQ24193 charger regulator driver. | |
++ | |
++Required properties: | |
++- compatible: must be "ti,bq2419x". | |
++- reg: I2C slave address of the regulator. It should be 0x1b. | |
++- interrupts: Interrupt number to generate interrupt from device. | |
++ | |
++Optional properties: | |
++- ti,watchdog-timeout: Watchdog timer period. 0 means watchdog timer disable. | |
++- ti,maximum-in-voltage-limit: Maximum input voltage (mV) for charger. | |
++- ti,fast-charge-current-limit: Maximum fast charge current (mA) limit. | |
++- otg-iusb-gpio: GPIO number for the OTG boost mode. | |
++ | |
++ | |
++Any standard regulator properties can be used to configure the VBUS and charging regulator. | |
++The driver supports two regualtors: | |
++vbus regulator for vbus supply from device. This is voltage regulator. | |
++charger regualtor for chargign battery. This is current regulator. | |
++ | |
++Example: | |
++ | |
++ bq2419x { | |
++ compatible = "ti,bq2419x"; | |
++ reg = <0x6b>; | |
++ interrupts = <120 IRQ_TYPE_LEVEL_HIGH>; | |
++ ti,watchdog-timeout = <40>; | |
++ ti,maximum-in-voltage-limit = <4200>; | |
++ ti,fast-charge-current-limit = <2500>; | |
++ otg-iusb-gpio = <&gpio 130 GPIO_ACTIVE_HIGH>; | |
++ | |
++ regulators { | |
++ vbus { | |
++ regulator-name = "vbus"; | |
++ regulator-min-microvolt = <0>; | |
++ regulator-max-microvolt = <5000000>; | |
++ }; | |
++ | |
++ charger { | |
++ regulator-name = "charger"; | |
++ regulator-min-microamp = <100000>; | |
++ regulator-max-microamp = <2000000>; | |
++ }; | |
++ }; | |
++ }; | |
+diff --git a/arch/arm/boot/dts/tegra114-roth.dts b/arch/arm/boot/dts/tegra114-roth.dts | |
+index 0b0e8e07d9658126b504058e5f82525e2071e812..78df4ee6c8cdb1e4714cc7ece3cdd64c162cbe76 100644 | |
+--- a/arch/arm/boot/dts/tegra114-roth.dts | |
++++ b/arch/arm/boot/dts/tegra114-roth.dts | |
+@@ -28,6 +28,22 @@ | |
+ reg = <0x80000000 0x79600000>; | |
+ }; | |
+ | |
++ host1x@50000000 { | |
++ dsi@54300000 { | |
++ status = "okay"; | |
++ | |
++ vdd-supply = <&vdd_1v2_ap>; | |
++ | |
++ panel@0 { | |
++ compatible = "lg,lh500wx1-sd03"; | |
++ reg = <0>; | |
++ | |
++ power-supply = <&vdd_lcd>; | |
++ backlight = <&backlight>; | |
++ }; | |
++ }; | |
++ }; | |
++ | |
+ pinmux@70000868 { | |
+ pinctrl-names = "default"; | |
+ pinctrl-0 = <&state_default>; | |
+@@ -244,7 +260,7 @@ | |
+ nvidia,function = "sdmmc1"; | |
+ nvidia,pull = <TEGRA_PIN_PULL_NONE>; | |
+ nvidia,tristate = <TEGRA_PIN_DISABLE>; | |
+- nvidia,enable-input = <TEGRA_PIN_DISABLE>; | |
++ nvidia,enable-input = <TEGRA_PIN_ENABLE>; | |
+ }; | |
+ sdmmc1_cmd_pz1 { | |
+ nvidia,pins = "sdmmc1_cmd_pz1", | |
+@@ -262,7 +278,7 @@ | |
+ nvidia,function = "sdmmc3"; | |
+ nvidia,pull = <TEGRA_PIN_PULL_NONE>; | |
+ nvidia,tristate = <TEGRA_PIN_DISABLE>; | |
+- nvidia,enable-input = <TEGRA_PIN_DISABLE>; | |
++ nvidia,enable-input = <TEGRA_PIN_ENABLE>; | |
+ }; | |
+ sdmmc3_cmd_pa7 { | |
+ nvidia,pins = "sdmmc3_cmd_pa7", | |
+@@ -290,7 +306,7 @@ | |
+ nvidia,function = "sdmmc4"; | |
+ nvidia,pull = <TEGRA_PIN_PULL_NONE>; | |
+ nvidia,tristate = <TEGRA_PIN_DISABLE>; | |
+- nvidia,enable-input = <TEGRA_PIN_DISABLE>; | |
++ nvidia,enable-input = <TEGRA_PIN_ENABLE>; | |
+ }; | |
+ sdmmc4_cmd_pt7 { | |
+ nvidia,pins = "sdmmc4_cmd_pt7", | |
+@@ -730,7 +746,6 @@ | |
+ nvidia,pins = "drive_sdio1"; | |
+ nvidia,high-speed-mode = <TEGRA_PIN_ENABLE>; | |
+ nvidia,schmitt = <TEGRA_PIN_DISABLE>; | |
+- nvidia,low-power-mode = <TEGRA_PIN_LP_DRIVE_DIV_1>; | |
+ nvidia,pull-down-strength = <36>; | |
+ nvidia,pull-up-strength = <20>; | |
+ nvidia,slew-rate-rising = <TEGRA_PIN_SLEW_RATE_SLOW>; | |
+@@ -740,7 +755,6 @@ | |
+ nvidia,pins = "drive_sdio3"; | |
+ nvidia,high-speed-mode = <TEGRA_PIN_ENABLE>; | |
+ nvidia,schmitt = <TEGRA_PIN_DISABLE>; | |
+- nvidia,low-power-mode = <TEGRA_PIN_LP_DRIVE_DIV_1>; | |
+ nvidia,pull-down-strength = <36>; | |
+ nvidia,pull-up-strength = <20>; | |
+ nvidia,slew-rate-rising = <TEGRA_PIN_SLEW_RATE_FASTEST>; | |
+@@ -750,12 +764,10 @@ | |
+ nvidia,pins = "drive_gma"; | |
+ nvidia,high-speed-mode = <TEGRA_PIN_ENABLE>; | |
+ nvidia,schmitt = <TEGRA_PIN_DISABLE>; | |
+- nvidia,low-power-mode = <TEGRA_PIN_LP_DRIVE_DIV_1>; | |
+ nvidia,pull-down-strength = <2>; | |
+ nvidia,pull-up-strength = <2>; | |
+ nvidia,slew-rate-rising = <TEGRA_PIN_SLEW_RATE_FASTEST>; | |
+ nvidia,slew-rate-falling = <TEGRA_PIN_SLEW_RATE_FASTEST>; | |
+- nvidia,drive-type = <1>; | |
+ }; | |
+ }; | |
+ }; | |
+@@ -769,6 +781,18 @@ | |
+ status = "okay"; | |
+ }; | |
+ | |
++ i2c@7000c000 { | |
++ status = "okay"; | |
++ clock-frequency = <100000>; | |
++ | |
++ charger@6b { | |
++ compatible = "ti,bq24193"; | |
++ reg = <0x6b>; | |
++ interrupt-parent = <&gpio>; | |
++ interrupts = <TEGRA_GPIO(J, 0) GPIO_ACTIVE_HIGH>; | |
++ }; | |
++ }; | |
++ | |
+ i2c@7000d000 { | |
+ status = "okay"; | |
+ clock-frequency = <400000>; | |
+@@ -815,7 +839,6 @@ | |
+ regulator-name = "vdd-1v8"; | |
+ regulator-min-microvolt = <1800000>; | |
+ regulator-max-microvolt = <1800000>; | |
+- regulator-always-on; | |
+ regulator-boot-on; | |
+ }; | |
+ | |
+@@ -862,10 +885,11 @@ | |
+ regulator-name = "vdd-2v8-display"; | |
+ regulator-min-microvolt = <2800000>; | |
+ regulator-max-microvolt = <2800000>; | |
++ regulator-always-on; | |
+ regulator-boot-on; | |
+ }; | |
+ | |
+- ldo3 { | |
++ vdd_1v2_ap: ldo3 { | |
+ regulator-name = "avdd-1v2"; | |
+ regulator-min-microvolt = <1200000>; | |
+ regulator-max-microvolt = <1200000>; | |
+@@ -946,6 +970,15 @@ | |
+ nvidia,invert-interrupt; | |
+ }; | |
+ | |
++ /* Wifi */ | |
++ sdhci@78000000 { | |
++ status = "okay"; | |
++ bus-width = <4>; | |
++ broken-cd; | |
++ keep-power-in-suspend; | |
++ cap-sdio-irq; | |
++ }; | |
++ | |
+ /* SD card */ | |
+ sdhci@78000400 { | |
+ status = "okay"; | |
+@@ -1052,7 +1085,7 @@ | |
+ regulator-boot-on; | |
+ }; | |
+ | |
+- regulator@1 { | |
++ vdd_lcd: regulator@1 { | |
+ compatible = "regulator-fixed"; | |
+ reg = <1>; | |
+ regulator-name = "vdd_lcd_1v8"; | |
+@@ -1094,6 +1127,7 @@ | |
+ vin-supply = <&vdd_1v8>; | |
+ enable-active-high; | |
+ gpio = <&gpio TEGRA_GPIO(X, 1) GPIO_ACTIVE_HIGH>; | |
++ regulator-always-on; | |
+ regulator-boot-on; | |
+ }; | |
+ | |
+diff --git a/arch/arm/boot/dts/tegra114-tn7.dts b/arch/arm/boot/dts/tegra114-tn7.dts | |
+index 96366214563542479db657f80b12a28918e30824..71aafd56825317ac144b215219e58f2d3ba47c37 100644 | |
+--- a/arch/arm/boot/dts/tegra114-tn7.dts | |
++++ b/arch/arm/boot/dts/tegra114-tn7.dts | |
+@@ -28,7 +28,59 @@ | |
+ reg = <0x80000000 0x37e00000>; | |
+ }; | |
+ | |
++ pinmux@70000868 { | |
++ pinctrl-names = "default"; | |
++ pinctrl-0 = <&state_default>; | |
++ | |
++ state_default: pinmux { | |
++ sdmmc3_clk_pa6 { | |
++ nvidia,pins = "sdmmc3_clk_pa6"; | |
++ nvidia,function = "sdmmc3"; | |
++ nvidia,pull = <TEGRA_PIN_PULL_NONE>; | |
++ nvidia,tristate = <TEGRA_PIN_DISABLE>; | |
++ nvidia,enable-input = <TEGRA_PIN_ENABLE>; | |
++ }; | |
++ sdmmc3_cmd_pa7 { | |
++ nvidia,pins = "sdmmc3_cmd_pa7", | |
++ "sdmmc3_dat0_pb7", | |
++ "sdmmc3_dat1_pb6", | |
++ "sdmmc3_dat2_pb5", | |
++ "sdmmc3_dat3_pb4", | |
++ "sdmmc3_cd_n_pv2", | |
++ "sdmmc3_clk_lb_out_pee4", | |
++ "sdmmc3_clk_lb_in_pee5", | |
++ "kb_col4_pq4"; | |
++ nvidia,function = "sdmmc3"; | |
++ nvidia,pull = <TEGRA_PIN_PULL_UP>; | |
++ nvidia,tristate = <TEGRA_PIN_DISABLE>; | |
++ nvidia,enable-input = <TEGRA_PIN_ENABLE>; | |
++ }; | |
++ | |
++ drive_sdio3 { | |
++ nvidia,pins = "drive_sdio3"; | |
++ nvidia,high-speed-mode = <TEGRA_PIN_ENABLE>; | |
++ nvidia,schmitt = <TEGRA_PIN_DISABLE>; | |
++ nvidia,pull-down-strength = <36>; | |
++ nvidia,pull-up-strength = <20>; | |
++ nvidia,slew-rate-rising = <TEGRA_PIN_SLEW_RATE_FASTEST>; | |
++ nvidia,slew-rate-falling = <TEGRA_PIN_SLEW_RATE_FASTEST>; | |
++ }; | |
++ }; | |
++ }; | |
++ | |
+ host1x@50000000 { | |
++ hdmi@54280000 { | |
++ status = "okay"; | |
++ | |
++ hdmi-supply = <&vdd_5v0_hdmi>; | |
++ vdd-supply = <&vdd_3v3_hdmi>; | |
++ pll-supply = <&vdd_1v05_pll>; | |
++ | |
++ nvidia,ddc-i2c-bus = <&hdmi_ddc>; | |
++ nvidia,hpd-gpio = | |
++ <&gpio TEGRA_GPIO(N, 7) GPIO_ACTIVE_HIGH>; | |
++ }; | |
++ | |
+ dsi@54300000 { | |
+ status = "okay"; | |
+ | |
+@@ -52,6 +104,23 @@ | |
+ status = "okay"; | |
+ }; | |
+ | |
++ i2c@7000c000 { | |
++ status = "okay"; | |
++ clock-frequency = <100000>; | |
++ | |
++ battery-charger@6b { | |
++ compatible = "ti,bq24192"; | |
++ reg = <0x6b>; | |
++ interrupt-parent = <&gpio>; | |
++ interrupts = <TEGRA_GPIO(J, 0) GPIO_ACTIVE_HIGH>; | |
++ }; | |
++ }; | |
++ | |
++ hdmi_ddc: i2c@7000c700 { | |
++ status = "okay"; | |
++ clock-frequency = <100000>; | |
++ }; | |
++ | |
+ i2c@7000d000 { | |
+ status = "okay"; | |
+ clock-frequency = <400000>; | |
+@@ -142,7 +211,7 @@ | |
+ regulator-boot-on; | |
+ }; | |
+ | |
+- ldo1 { | |
++ vdd_1v05_pll: ldo1 { | |
+ regulator-name = "va-pllx"; | |
+ regulator-min-microvolt = <1050000>; | |
+ regulator-max-microvolt = <1050000>; | |
+@@ -201,7 +270,7 @@ | |
+ regulator-boot-on; | |
+ }; | |
+ | |
+- ldo9 { | |
++ vi_sdcard: ldo9 { | |
+ regulator-name = "vi-sdcard"; | |
+ regulator-min-microvolt = <2900000>; | |
+ regulator-max-microvolt = <2900000>; | |
+@@ -215,7 +284,7 @@ | |
+ regulator-boot-on; | |
+ }; | |
+ | |
+- ldoln { | |
++ vdd_3v3_hdmi: ldoln { | |
+ regulator-name = "va-hdmi"; | |
+ regulator-min-microvolt = <3300000>; | |
+ regulator-max-microvolt = <3300000>; | |
+@@ -236,6 +305,15 @@ | |
+ nvidia,invert-interrupt; | |
+ }; | |
+ | |
++ /* SD card */ | |
++ sdhci@78000400 { | |
++ status = "okay"; | |
++ bus-width = <4>; | |
++ vmmc-supply = <&vi_sdcard>; | |
++ cd-gpios = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_LOW>; | |
++ power-gpios = <&gpio TEGRA_GPIO(K, 1) GPIO_ACTIVE_HIGH>; | |
++ }; | |
++ | |
+ /* eMMC */ | |
+ sdhci@78000600 { | |
+ status = "okay"; | |
+@@ -344,5 +422,19 @@ | |
+ vin-supply = <&vdd_1v8>; | |
+ regulator-boot-on; | |
+ }; | |
++ | |
++ vdd_5v0_hdmi: regulator@3 { | |
++ compatible = "regulator-fixed"; | |
++ reg = <3>; | |
++ regulator-name = "VDD_5V_HDMI_CONN"; | |
++ regulator-min-microvolt = <5000000>; | |
++ regulator-max-microvolt = <5000000>; | |
++ gpio = <&gpio TEGRA_GPIO(K, 6) GPIO_ACTIVE_HIGH>; | |
++ enable-active-high; | |
++ gpio-open-drain; | |
++ vin-supply = <&vdd_smps10_out1>; | |
++ regulator-always-on; | |
++ regulator-boot-on; | |
++ }; | |
+ }; | |
+ }; | |
+diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig | |
+index fb25e2982f64c848e712f397d85317bbb6f52699..31771b019fbf8bd9059e793452843d7efa16f3ce 100644 | |
+--- a/arch/arm/configs/tegra_defconfig | |
++++ b/arch/arm/configs/tegra_defconfig | |
+@@ -90,7 +90,6 @@ CONFIG_RFKILL_INPUT=y | |
+ CONFIG_RFKILL_GPIO=y | |
+ CONFIG_DEVTMPFS=y | |
+ CONFIG_DEVTMPFS_MOUNT=y | |
+-# CONFIG_FIRMWARE_IN_KERNEL is not set | |
+ CONFIG_DMA_CMA=y | |
+ CONFIG_CMA_SIZE_MBYTES=64 | |
+ CONFIG_MTD=y | |
+@@ -116,7 +115,6 @@ CONFIG_USB_PEGASUS=y | |
+ CONFIG_USB_USBNET=y | |
+ CONFIG_USB_NET_SMSC75XX=y | |
+ CONFIG_USB_NET_SMSC95XX=y | |
+-CONFIG_BRCMFMAC=m | |
+ CONFIG_RT2X00=y | |
+ CONFIG_RT2800USB=m | |
+ CONFIG_INPUT_JOYDEV=y | |
+@@ -293,3 +291,11 @@ CONFIG_CRYPTO_TWOFISH=y | |
+ # CONFIG_CRYPTO_ANSI_CPRNG is not set | |
+ CONFIG_CRYPTO_DEV_TEGRA_AES=y | |
+ CONFIG_CRC_CCITT=y | |
++CONFIG_ARM_APPENDED_DTB=y | |
++CONFIG_GPIO_SYSFS=y | |
++CONFIG_CHARGER_BQ24190=y | |
++CONFIG_BRCMFMAC=y | |
++CONFIG_BRCMFMAC_SDIO=y | |
++CONFIG_FIRMWARE_IN_KERNEL=y | |
++CONFIG_EXTRA_FIRMWARE="brcm/brcmfmac43241b0-sdio.bin brcm/brcmfmac43241b0-sdio.txt" | |
++CONFIG_EXTRA_FIRMWARE_DIR="firmware" | |
+diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c | |
+index b9c8ba258ef0b84e298ec00fed534043fa5766fe..a8379ae2faafa5074e935ba9e79aa560f5606e80 100644 | |
+--- a/drivers/clk/tegra/clk-tegra114.c | |
++++ b/drivers/clk/tegra/clk-tegra114.c | |
+@@ -1302,6 +1302,8 @@ static struct tegra_clk_init_table init_table[] __initdata = { | |
+ {TEGRA114_CLK_XUSB_HS_SRC, TEGRA114_CLK_XUSB_SS_DIV2, 61200000, 0}, | |
+ {TEGRA114_CLK_XUSB_FALCON_SRC, TEGRA114_CLK_PLL_P, 204000000, 0}, | |
+ {TEGRA114_CLK_XUSB_HOST_SRC, TEGRA114_CLK_PLL_P, 102000000, 0}, | |
++ {TEGRA114_CLK_BLINK, TEGRA114_CLK_CLK_MAX, 0, 1}, | |
++ | |
+ /* This MUST be the last entry. */ | |
+ {TEGRA114_CLK_CLK_MAX, TEGRA114_CLK_CLK_MAX, 0, 0}, | |
+ }; | |
+diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c | |
+index a25136132c318b3a18f9579d71de8799ffefad15..869a84e31dddb40428c48c76303ba70969710f05 100644 | |
+--- a/drivers/gpu/drm/panel/panel-simple.c | |
++++ b/drivers/gpu/drm/panel/panel-simple.c | |
+@@ -545,7 +545,7 @@ static const struct panel_desc_dsi lg_ld070wx3_sl01 = { | |
+ .height = 151, | |
+ }, | |
+ }, | |
+- .flags = MIPI_DSI_MODE_VIDEO, | |
++ .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_CLOCK_NON_CONTINUOUS, | |
+ .format = MIPI_DSI_FMT_RGB888, | |
+ .lanes = 4, | |
+ }; | |
+@@ -599,7 +599,8 @@ static const struct panel_desc_dsi panasonic_vvx10f004b00 = { | |
+ .height = 136, | |
+ }, | |
+ }, | |
+- .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE, | |
++ .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE | | |
++ MIPI_DSI_CLOCK_NON_CONTINUOUS, | |
+ .format = MIPI_DSI_FMT_RGB888, | |
+ .lanes = 4, | |
+ }; | |
+diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c | |
+index bd56f2affa7895b2d1e0fbd556e3e811f8e78f14..eadfeaf9e1eb8fb198f45dfb7ec52dd29bb3b979 100644 | |
+--- a/drivers/gpu/drm/tegra/dsi.c | |
++++ b/drivers/gpu/drm/tegra/dsi.c | |
+@@ -474,7 +474,8 @@ static int tegra_output_dsi_enable(struct tegra_output *output) | |
+ tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL); | |
+ | |
+ value = tegra_dsi_readl(dsi, DSI_CONTROL); | |
+- value |= DSI_CONTROL_HS_CLK_CTRL; | |
++ if (dsi->flags & MIPI_DSI_CLOCK_NON_CONTINUOUS) | |
++ value |= DSI_CONTROL_HS_CLK_CTRL; | |
+ value &= ~DSI_CONTROL_TX_TRIG(3); | |
+ value &= ~DSI_CONTROL_DCS_ENABLE; | |
+ value |= DSI_CONTROL_VIDEO_ENABLE; | |
+diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c | |
+index 47055f3f01b8580e01ff147232d106bc14db3667..c772ec00b7f1b9df4181252222a181e014514fa3 100644 | |
+--- a/drivers/mmc/host/sdhci.c | |
++++ b/drivers/mmc/host/sdhci.c | |
+@@ -1226,6 +1226,10 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned char mode, | |
+ u8 pwr = 0; | |
+ | |
+ if (mode != MMC_POWER_OFF) { | |
++ if (vdd > 21) { | |
++ printk("SHIELD wifi power workaround applied\n"); | |
++ vdd = 21; | |
++ } | |
+ switch (1 << vdd) { | |
+ case MMC_VDD_165_195: | |
+ pwr = SDHCI_POWER_180; | |
+@@ -1359,7 +1363,8 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) | |
+ * tuning procedure before sending command. | |
+ */ | |
+ if ((host->flags & SDHCI_NEEDS_RETUNING) && | |
+- !(present_state & (SDHCI_DOING_WRITE | SDHCI_DOING_READ))) { | |
++ !(present_state & (SDHCI_DOING_WRITE | SDHCI_DOING_READ)) && | |
++ mmc_cmd_type(mrq->cmd) == MMC_CMD_ADTC) { | |
+ if (mmc->card) { | |
+ /* eMMC uses cmd21 but sd and sdio use cmd19 */ | |
+ tuning_opcode = | |
+diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | |
+index 8fa0dbbbda72b6ed1d1dc84020594287cf595a37..81848c60e0cf003c2b244455a528405840609379 100644 | |
+--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | |
++++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | |
+@@ -4117,7 +4117,7 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) | |
+ | |
+ /* ...and initialize clock/power states */ | |
+ bus->clkstate = CLK_SDONLY; | |
+- bus->idletime = BRCMF_IDLE_INTERVAL; | |
++ bus->idletime = BRCMF_IDLE_ACTIVE; | |
+ bus->idleclock = BRCMF_IDLE_ACTIVE; | |
+ | |
+ /* SR state */ | |
+diff --git a/drivers/power/bq24190_charger.c b/drivers/power/bq24190_charger.c | |
+index ad3ff8fbfbbb083a897a14cc13622904108a4368..2015db241523a4b70932191482e7f1fbe014b6ca 100644 | |
+--- a/drivers/power/bq24190_charger.c | |
++++ b/drivers/power/bq24190_charger.c | |
+@@ -1515,12 +1515,16 @@ static SIMPLE_DEV_PM_OPS(bq24190_pm_ops, bq24190_pm_suspend, bq24190_pm_resume); | |
+ */ | |
+ static const struct i2c_device_id bq24190_i2c_ids[] = { | |
+ { "bq24190", BQ24190_REG_VPRS_PN_24190 }, | |
++ { "bq24192", BQ24190_REG_VPRS_PN_24192 }, | |
++ { "bq24193", BQ24190_REG_VPRS_PN_24192 }, | |
+ { }, | |
+ }; | |
+ | |
+ #ifdef CONFIG_OF | |
+ static const struct of_device_id bq24190_of_match[] = { | |
+ { .compatible = "ti,bq24190", }, | |
++ { .compatible = "ti,bq24192", }, | |
++ { .compatible = "ti,bq24193", }, | |
+ { }, | |
+ }; | |
+ MODULE_DEVICE_TABLE(of, bq24190_of_match); | |
+diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig | |
+index 789eb46090e3ffe22de72845fe8edf8f32a907d3..0cad29938f6899d5f17274fd333e8db71c65caf8 100644 | |
+--- a/drivers/regulator/Kconfig | |
++++ b/drivers/regulator/Kconfig | |
+@@ -154,6 +154,17 @@ config REGULATOR_BCM590XX | |
+ BCM590xx PMUs. This will enable support for the software | |
+ controllable LDO/Switching regulators. | |
+ | |
++config REGULATOR_BQ2419X | |
++ tristate "TI BQ24190/BQ24192/BQ24192i/BQ24193 charger regulator driver" | |
++ depends on I2C | |
++ select REGMAP_I2C | |
++ help | |
++ The bq24190, bq24192, bq24192I, and bq24193 are highly-integrated | |
++ switch-mode battery charge management and system power path | |
++ management devices for single cell Li-Ion and Li-polymer battery. | |
++ This driver support the configuration of charging parameter through | |
++ regulator framework. | |
++ | |
+ config REGULATOR_DA903X | |
+ tristate "Dialog Semiconductor DA9030/DA9034 regulators" | |
+ depends on PMIC_DA903X | |
+diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile | |
+index d461110f44631a88decc2f3eb0a0bad7338de0cf..1b4e5f48fa38ae93e5682f542a97f1000d9a7cff 100644 | |
+--- a/drivers/regulator/Makefile | |
++++ b/drivers/regulator/Makefile | |
+@@ -88,5 +88,6 @@ obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o | |
+ obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o | |
+ obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o | |
+ | |
++obj-y += bq2419x-regulator.o | |
+ | |
+ ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG | |
+diff --git a/drivers/regulator/bq2419x-regulator.c b/drivers/regulator/bq2419x-regulator.c | |
+new file mode 100644 | |
+index 0000000000000000000000000000000000000000..314f73fd39a3249cc9d1486c80c3b581c2d8dea4 | |
+--- /dev/null | |
++++ b/drivers/regulator/bq2419x-regulator.c | |
+@@ -0,0 +1,786 @@ | |
++/* | |
++ * bq2419x-charger.c -- BQ24190/BQ24192/BQ24192i/BQ24193 Charger | |
++ * regulator driver | |
++ * | |
++ * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. | |
++ * | |
++ * Author: Laxman Dewangan <[email protected]> | |
++ * | |
++ * This program is free software; you can redistribute it and/or | |
++ * modify it under the terms of the GNU General Public License as | |
++ * published by the Free Software Foundation version 2. | |
++ * | |
++ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, | |
++ * whether express or implied; without even the implied warranty of | |
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
++ * General Public License for more details. | |
++ * | |
++ * You should have received a copy of the GNU General Public License | |
++ * along with this program; if not, write to the Free Software | |
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
++ * 02111-1307, USA | |
++ */ | |
++#include <linux/delay.h> | |
++#include <linux/err.h> | |
++#include <linux/i2c.h> | |
++#include <linux/init.h> | |
++#include <linux/interrupt.h> | |
++#include <linux/gpio.h> | |
++#include <linux/kernel.h> | |
++#include <linux/module.h> | |
++#include <linux/regmap.h> | |
++#include <linux/regulator/consumer.h> | |
++#include <linux/regulator/driver.h> | |
++#include <linux/regulator/machine.h> | |
++#include <linux/regulator/of_regulator.h> | |
++#include <linux/of_gpio.h> | |
++#include <linux/of.h> | |
++#include <linux/slab.h> | |
++ | |
++/* Register definitions */ | |
++#define BQ2419X_INPUT_SRC_REG 0x00 | |
++#define BQ2419X_PWR_ON_REG 0x01 | |
++#define BQ2419X_CHRG_CTRL_REG 0x02 | |
++#define BQ2419X_CHRG_TERM_REG 0x03 | |
++#define BQ2419X_VOLT_CTRL_REG 0x04 | |
++#define BQ2419X_TIME_CTRL_REG 0x05 | |
++#define BQ2419X_THERM_REG 0x06 | |
++#define BQ2419X_MISC_OPER_REG 0x07 | |
++#define BQ2419X_SYS_STAT_REG 0x08 | |
++#define BQ2419X_FAULT_REG 0x09 | |
++#define BQ2419X_REVISION_REG 0x0a | |
++#define BQ2419X_MAX_REGS (BQ2419X_REVISION_REG + 1) | |
++ | |
++/* REG00 INPUT_SRC_REG */ | |
++#define BQ2419X_INPUT_SRC_EN_HIZ_MASK BIT(7) | |
++#define BQ2419X_INPUT_SRC_VINDPM_MASK 0x78 | |
++#define BQ2419X_INPUT_SRC_VINDPM_SHIFT 3 | |
++#define BQ2419X_INPUT_SRC_IINLIM_MASK 0x7 | |
++ | |
++/* REG01 PWR_ON_REG */ | |
++#define BQ2419X_PWR_ON_OTG_MASK BIT(5) | |
++#define BQ2419X_PWR_ON_OTG_ENABLE BIT(5) | |
++#define BQ2419X_PWR_ON_CHARGER_MASK BIT(4) | |
++#define BQ2419X_PWR_ON_CHARGER_ENABLE BIT(4) | |
++ | |
++/* REG0A REVISION_REG */ | |
++#define BQ24190_IC_VER 0x40 | |
++#define BQ24192_IC_VER 0x28 | |
++#define BQ24192i_IC_VER 0x18 | |
++ | |
++/* REG05 TIME_CTRL_REG */ | |
++#define BQ2419X_TIME_CTRL_WD_MASK 0x30 | |
++#define BQ2419X_TIME_CTRL_WD_DISABLE 0x00 | |
++#define BQ2419X_TIME_CTRL_WD_40ms 0x10 | |
++#define BQ2419X_TIME_CTRL_WD_80ms 0x20 | |
++#define BQ2419X_TIME_CTRL_WD_160ms 0x30 | |
++#define BQ2419X_TIME_CTRL_EN_SFT_TIMER_MASK BIT(3) | |
++ | |
++/* REG08 SYS_STAT_REG */ | |
++#define BQ2419x_SYS_STAT_CHRG_STATE_MASK 0x30 | |
++#define BQ2419x_SYS_STAT_CHRG_STATE_NOTCHARGING 0x00 | |
++#define BQ2419x_SYS_STAT_CHRG_STATE_PRE_CHARGE 0x10 | |
++#define BQ2419x_SYS_STAT_CHRG_STATE_POST_CHARGE 0x20 | |
++#define BQ2419x_SYS_STAT_CHRG_STATE_CHARGE_DONE 0x30 | |
++ | |
++/* REG09 BQ2419X_FAULT_REG */ | |
++#define BQ2419x_FAULT_WATCHDOG_FAULT BIT(7) | |
++#define BQ2419x_FAULT_BOOST_FAULT BIT(6) | |
++#define BQ2419x_FAULT_CHRG_FAULT_MASK 0x30 | |
++#define BQ2419x_FAULT_CHRG_NORMAL 0x00 | |
++#define BQ2419x_FAULT_CHRG_INPUT 0x10 | |
++#define BQ2419x_FAULT_CHRG_THERMAL 0x20 | |
++#define BQ2419x_FAULT_CHRG_SAFTY 0x30 | |
++#define BQ2419x_FAULT_NTC_FAULT 0x07 | |
++ | |
++/* Input current limit */ | |
++static const unsigned int bq2419x_charging_current[] = { | |
++ 100, 150, 500, 900, 1200, 1500, 2000, 3000, | |
++}; | |
++ | |
++enum regulator_id { | |
++ BQ2419X_REGULATOR_VBUS, | |
++ BQ2419X_REGULATOR_CHARGER, | |
++}; | |
++ | |
++struct bq2419x_chip { | |
++ struct device *dev; | |
++ struct regmap *regmap; | |
++ int irq; | |
++ | |
++ struct mutex mutex; | |
++ int otg_iusb_gpio; | |
++ int fast_charge_current_limit; | |
++ int max_in_voltage_limit; | |
++ int wdt_timeout; | |
++ int wdt_refresh_timeout; | |
++ struct delayed_work bq_wdt_work; | |
++ | |
++ struct regulator_dev *chg_rdev; | |
++ struct regulator_dev *vbus_rdev; | |
++}; | |
++ | |
++static int bq2419x_set_charging_current(struct regulator_dev *rdev, | |
++ int min_uA, int max_uA); | |
++ | |
++static struct regulator_ops bq2419x_vbus_reg_ops = { | |
++ .enable = regulator_enable_regmap, | |
++ .disable = regulator_disable_regmap, | |
++ .is_enabled = regulator_is_enabled_regmap, | |
++}; | |
++ | |
++static struct regulator_ops bq2419x_charger_regulator_ops = { | |
++ .set_current_limit = bq2419x_set_charging_current, | |
++}; | |
++ | |
++static struct regulator_desc bq2419x_reg_desc[] = { | |
++ { | |
++ .name = "bq2419x-vbus", | |
++ .owner = THIS_MODULE, | |
++ .type = REGULATOR_VOLTAGE, | |
++ .ops = &bq2419x_vbus_reg_ops, | |
++ .enable_mask = BQ2419X_PWR_ON_OTG_MASK, | |
++ .enable_reg = BQ2419X_PWR_ON_REG, | |
++ .enable_time = 500000, | |
++ }, { | |
++ .name = "bq2419x-charger", | |
++ .owner = THIS_MODULE, | |
++ .type = REGULATOR_CURRENT, | |
++ .ops = &bq2419x_charger_regulator_ops, | |
++ }, | |
++}; | |
++ | |
++static struct of_regulator_match bq2419x_matches[] = { | |
++ { .name = "vbus", }, | |
++ { .name = "charger", }, | |
++}; | |
++ | |
++static int bq2419x_parse_dt_reg_data(struct bq2419x_chip *bq2419x) | |
++{ | |
++ struct device_node *np = of_node_get(bq2419x->dev->of_node); | |
++ struct device_node *regulators; | |
++ int ret; | |
++ u32 prop; | |
++ | |
++ regulators = of_find_node_by_name(np, "regulators"); | |
++ if (!regulators) { | |
++ dev_err(bq2419x->dev, "regulator node not found\n"); | |
++ return -ENODEV; | |
++ } | |
++ | |
++ ret = of_regulator_match(bq2419x->dev, regulators, bq2419x_matches, | |
++ ARRAY_SIZE(bq2419x_matches)); | |
++ of_node_put(regulators); | |
++ if (ret < 0) { | |
++ dev_err(bq2419x->dev, | |
++ "Parsing of regulator init data failed %d\n", ret); | |
++ return ret; | |
++ } | |
++ | |
++ ret = of_property_read_u32(np, "ti,watchdog-timeout", &prop); | |
++ if (!ret) | |
++ bq2419x->wdt_timeout = prop; | |
++ | |
++ ret = of_property_read_u32(np, "ti,maximum-in-voltage-limit", &prop); | |
++ if (!ret) | |
++ bq2419x->max_in_voltage_limit = prop; | |
++ | |
++ ret = of_property_read_u32(np, "ti,fast-charge-current-limit", &prop); | |
++ if (!ret) | |
++ bq2419x->fast_charge_current_limit = prop; | |
++ | |
++ bq2419x->otg_iusb_gpio = of_get_named_gpio(np, "otg-iusb-gpio", 0); | |
++ if ((bq2419x->otg_iusb_gpio == -ENODEV) || | |
++ (bq2419x->otg_iusb_gpio == -EPROBE_DEFER)) | |
++ return -EPROBE_DEFER; | |
++ | |
++ return 0; | |
++} | |
++ | |
++static int bq2419x_clear_hi_z(struct bq2419x_chip *bq2419x) | |
++{ | |
++ int ret; | |
++ | |
++ ret = regmap_update_bits(bq2419x->regmap, BQ2419X_INPUT_SRC_REG, | |
++ BQ2419X_INPUT_SRC_EN_HIZ_MASK, 0); | |
++ if (ret < 0) { | |
++ dev_err(bq2419x->dev, "INPUT_SRC_REG update failed %d\n", ret); | |
++ return ret; | |
++ } | |
++ return ret; | |
++} | |
++ | |
++static int bq2419x_configure_charging_current(struct bq2419x_chip *bq2419x, | |
++ int in_current) | |
++{ | |
++ int ret; | |
++ int i; | |
++ | |
++ bq2419x_clear_hi_z(bq2419x); | |
++ for (i = 0; i < ARRAY_SIZE(bq2419x_charging_current) - 1; ++i) { | |
++ if (in_current <= bq2419x_charging_current[i]) | |
++ break; | |
++ } | |
++ ret = regmap_update_bits(bq2419x->regmap, BQ2419X_INPUT_SRC_REG, | |
++ BQ2419X_INPUT_SRC_IINLIM_MASK, i); | |
++ if (ret < 0) | |
++ dev_err(bq2419x->dev, "INPUT_SRC_REG update failed %d\n", ret); | |
++ return ret; | |
++} | |
++ | |
++static int bq2419x_set_charging_enable(struct bq2419x_chip *bq2419x, | |
++ bool enable) | |
++{ | |
++ int ret; | |
++ int val = 0; | |
++ | |
++ if (enable) | |
++ val = BQ2419X_PWR_ON_CHARGER_ENABLE; | |
++ | |
++ ret = regmap_update_bits(bq2419x->regmap, BQ2419X_PWR_ON_REG, | |
++ BQ2419X_PWR_ON_CHARGER_MASK, val); | |
++ if (ret < 0) { | |
++ dev_err(bq2419x->dev, "PWR_ON_REG update failed %d\n", ret); | |
++ return ret; | |
++ } | |
++ return ret; | |
++} | |
++ | |
++static int bq2419x_charger_init_configure(struct bq2419x_chip *bq2419x) | |
++{ | |
++ int ret; | |
++ int fast_charging_current; | |
++ int in_voltage_limit; | |
++ | |
++ /* Configure fast charging current */ | |
++ fast_charging_current = bq2419x->fast_charge_current_limit; | |
++ if (fast_charging_current < 512) | |
++ fast_charging_current = 512; | |
++ fast_charging_current = (fast_charging_current - 512) / 64; | |
++ ret = regmap_write(bq2419x->regmap, BQ2419X_CHRG_CTRL_REG, | |
++ fast_charging_current << 2); | |
++ if (ret < 0) { | |
++ dev_err(bq2419x->dev, "CHRG_CTRL_REG write failed %d\n", ret); | |
++ return ret; | |
++ } | |
++ | |
++ /* Configure input voltage limit */ | |
++ in_voltage_limit = bq2419x->max_in_voltage_limit; | |
++ if (in_voltage_limit < 3880) | |
++ in_voltage_limit = 3880; | |
++ in_voltage_limit -= 3880; | |
++ in_voltage_limit = (in_voltage_limit/80) << | |
++ BQ2419X_INPUT_SRC_VINDPM_SHIFT; | |
++ ret = regmap_update_bits(bq2419x->regmap, BQ2419X_INPUT_SRC_REG, | |
++ BQ2419X_INPUT_SRC_VINDPM_MASK, in_voltage_limit); | |
++ if (ret < 0) { | |
++ dev_err(bq2419x->dev, "INPUT_SRC_REG update failed %d\n", ret); | |
++ return ret; | |
++ } | |
++ | |
++ ret = bq2419x_clear_hi_z(bq2419x); | |
++ if (ret < 0) { | |
++ dev_err(bq2419x->dev, "Clearing HiZ failed %d\n", ret); | |
++ return ret; | |
++ } | |
++ | |
++ if (bq2419x_matches[BQ2419X_REGULATOR_CHARGER].init_data) { | |
++ ret = bq2419x_set_charging_enable(bq2419x, true); | |
++ if (ret < 0) { | |
++ dev_err(bq2419x->dev, "Charger enable failed %d\n", | |
++ ret); | |
++ return ret; | |
++ } | |
++ } | |
++ return ret; | |
++} | |
++ | |
++static int bq2419x_set_charging_current(struct regulator_dev *rdev, | |
++ int min_uA, int max_uA) | |
++{ | |
++ struct bq2419x_chip *bq2419x = rdev_get_drvdata(rdev); | |
++ int ret = 0; | |
++ int val; | |
++ int in_current_limit = max_uA/1000; | |
++ | |
++ ret = regmap_read(bq2419x->regmap, BQ2419X_SYS_STAT_REG, &val); | |
++ if (ret < 0) { | |
++ dev_err(bq2419x->dev, "SYS_STAT_REG read failed %d\n", ret); | |
++ return ret; | |
++ } | |
++ | |
++ if (max_uA == 0 && val != 0) | |
++ return ret; | |
++ | |
++ ret = bq2419x_configure_charging_current(bq2419x, in_current_limit); | |
++ if (ret < 0) { | |
++ dev_err(bq2419x->dev, "Charger enable failed %d\n", ret); | |
++ return ret; | |
++ } | |
++ | |
++ ret = bq2419x_set_charging_enable(bq2419x, true); | |
++ if (ret < 0) { | |
++ dev_err(bq2419x->dev, "Charger enable failed %d\n", ret); | |
++ return ret; | |
++ } | |
++ | |
++ ret = bq2419x_clear_hi_z(bq2419x); | |
++ if (ret < 0) { | |
++ dev_err(bq2419x->dev, "Clearing HiZ failed %d\n", ret); | |
++ return ret; | |
++ } | |
++ return ret; | |
++} | |
++ | |
++static int bq2419x_reset_wdt(struct bq2419x_chip *bq2419x) | |
++{ | |
++ int ret = 0; | |
++ unsigned int reg01; | |
++ | |
++ mutex_lock(&bq2419x->mutex); | |
++ | |
++ ret = bq2419x_clear_hi_z(bq2419x); | |
++ if (ret < 0) { | |
++ dev_err(bq2419x->dev, "Clearing HiZ failed %d\n", ret); | |
++ return ret; | |
++ } | |
++ | |
++ ret = regmap_read(bq2419x->regmap, BQ2419X_PWR_ON_REG, ®01); | |
++ if (ret < 0) { | |
++ dev_err(bq2419x->dev, "PWR_ON_REG read failed %d\n", ret); | |
++ goto scrub; | |
++ } | |
++ | |
++ reg01 |= BIT(6); | |
++ | |
++ /* Write two times to make sure reset WDT as suggested by Vendor*/ | |
++ ret = regmap_write(bq2419x->regmap, BQ2419X_PWR_ON_REG, reg01); | |
++ if (ret < 0) { | |
++ dev_err(bq2419x->dev, "PWR_ON_REG write failed %d\n", ret); | |
++ goto scrub; | |
++ } | |
++ ret = regmap_write(bq2419x->regmap, BQ2419X_PWR_ON_REG, reg01); | |
++ if (ret < 0) { | |
++ dev_err(bq2419x->dev, "PWR_ON_REG write failed %d\n", ret); | |
++ goto scrub; | |
++ } | |
++ | |
++scrub: | |
++ mutex_unlock(&bq2419x->mutex); | |
++ return ret; | |
++} | |
++ | |
++static int bq2419x_fault_clear_sts(struct bq2419x_chip *bq2419x) | |
++{ | |
++ int ret; | |
++ unsigned int reg09; | |
++ | |
++ /* Read two times for clearing the FAULT REG */ | |
++ ret = regmap_read(bq2419x->regmap, BQ2419X_FAULT_REG, ®09); | |
++ if (ret < 0) { | |
++ dev_err(bq2419x->dev, "FAULT_REG read failed %d\n", ret); | |
++ return ret; | |
++ } | |
++ | |
++ ret = regmap_read(bq2419x->regmap, BQ2419X_FAULT_REG, ®09); | |
++ if (ret < 0) | |
++ dev_err(bq2419x->dev, "FAULT_REG read failed %d\n", ret); | |
++ | |
++ return ret; | |
++} | |
++ | |
++static int bq2419x_watchdog_init(struct bq2419x_chip *bq2419x, int timeout) | |
++{ | |
++ int ret, val; | |
++ unsigned int reg05; | |
++ | |
++ if (!timeout) { | |
++ ret = regmap_update_bits(bq2419x->regmap, BQ2419X_TIME_CTRL_REG, | |
++ BQ2419X_TIME_CTRL_WD_MASK, 0); | |
++ if (ret < 0) | |
++ dev_err(bq2419x->dev, | |
++ "TIME_CTRL_REG read failed %d\n", ret); | |
++ return ret; | |
++ } | |
++ | |
++ if (timeout <= 60) { | |
++ val = BQ2419X_TIME_CTRL_WD_40ms; | |
++ bq2419x->wdt_refresh_timeout = 25; | |
++ } else if (timeout <= 120) { | |
++ val = BQ2419X_TIME_CTRL_WD_80ms; | |
++ bq2419x->wdt_refresh_timeout = 50; | |
++ } else { | |
++ val = BQ2419X_TIME_CTRL_WD_160ms; | |
++ bq2419x->wdt_refresh_timeout = 125; | |
++ } | |
++ | |
++ ret = regmap_read(bq2419x->regmap, BQ2419X_TIME_CTRL_REG, ®05); | |
++ if (ret < 0) { | |
++ dev_err(bq2419x->dev, "TIME_CTRL_REG read failed %d\n", ret); | |
++ return ret; | |
++ } | |
++ | |
++ if ((reg05 & BQ2419X_TIME_CTRL_WD_MASK) != val) { | |
++ ret = regmap_update_bits(bq2419x->regmap, BQ2419X_TIME_CTRL_REG, | |
++ BQ2419X_TIME_CTRL_WD_MASK, val); | |
++ if (ret < 0) { | |
++ dev_err(bq2419x->dev, | |
++ "TIME_CTRL_REG read failed %d\n", ret); | |
++ return ret; | |
++ } | |
++ } | |
++ | |
++ ret = bq2419x_reset_wdt(bq2419x); | |
++ if (ret < 0) | |
++ dev_err(bq2419x->dev, "bq2419x_reset_wdt failed %d\n", ret); | |
++ | |
++ return ret; | |
++} | |
++ | |
++static void bq2419x_reset_wdt_work(struct work_struct *work) | |
++{ | |
++ struct bq2419x_chip *bq2419x; | |
++ int ret; | |
++ | |
++ bq2419x = container_of(work, struct bq2419x_chip, bq_wdt_work.work); | |
++ ret = bq2419x_reset_wdt(bq2419x); | |
++ if (ret < 0) | |
++ dev_err(bq2419x->dev, "bq2419x_reset_wdt failed %d\n", ret); | |
++ schedule_delayed_work(&bq2419x->bq_wdt_work, | |
++ msecs_to_jiffies(bq2419x->wdt_refresh_timeout * 1000)); | |
++} | |
++ | |
++static int bq2419x_reset_safety_timer(struct bq2419x_chip *bq2419x) | |
++{ | |
++ int ret; | |
++ | |
++ ret = regmap_update_bits(bq2419x->regmap, BQ2419X_TIME_CTRL_REG, | |
++ BQ2419X_TIME_CTRL_EN_SFT_TIMER_MASK, 0); | |
++ if (ret < 0) { | |
++ dev_err(bq2419x->dev, | |
++ "TIME_CTRL_REG update failed %d\n", ret); | |
++ return ret; | |
++ } | |
++ | |
++ ret = regmap_update_bits(bq2419x->regmap, BQ2419X_TIME_CTRL_REG, | |
++ BQ2419X_TIME_CTRL_EN_SFT_TIMER_MASK, | |
++ BQ2419X_TIME_CTRL_EN_SFT_TIMER_MASK); | |
++ if (ret < 0) | |
++ dev_err(bq2419x->dev, | |
++ "TIME_CTRL_REG update failed %d\n", ret); | |
++ return ret; | |
++} | |
++ | |
++static irqreturn_t bq2419x_irq(int irq, void *data) | |
++{ | |
++ struct bq2419x_chip *bq2419x = data; | |
++ int ret; | |
++ unsigned int val; | |
++ int check_chg_state = 0; | |
++ | |
++ ret = regmap_read(bq2419x->regmap, BQ2419X_FAULT_REG, &val); | |
++ if (ret < 0) { | |
++ dev_err(bq2419x->dev, "FAULT_REG read failed %d\n", ret); | |
++ return ret; | |
++ } | |
++ | |
++ if (val & BQ2419x_FAULT_WATCHDOG_FAULT) { | |
++ dev_err(bq2419x->dev, | |
++ "Charging Fault: Watchdog Timer Expired\n"); | |
++ | |
++ ret = bq2419x_watchdog_init(bq2419x, bq2419x->wdt_timeout); | |
++ if (ret < 0) { | |
++ dev_err(bq2419x->dev, "BQWDT init failed %d\n", ret); | |
++ return ret; | |
++ } | |
++ | |
++ ret = bq2419x_charger_init_configure(bq2419x); | |
++ if (ret < 0) { | |
++ dev_err(bq2419x->dev, "Charger init failed %d\n", ret); | |
++ return ret; | |
++ } | |
++ } | |
++ | |
++ if (val & BQ2419x_FAULT_BOOST_FAULT) | |
++ dev_err(bq2419x->dev, "Charging Fault: VBUS Overloaded\n"); | |
++ | |
++ switch (val & BQ2419x_FAULT_CHRG_FAULT_MASK) { | |
++ case BQ2419x_FAULT_CHRG_INPUT: | |
++ dev_err(bq2419x->dev, | |
++ "Charging Fault: VBUS OVP or VBAT<VBUS<3.8V\n"); | |
++ break; | |
++ case BQ2419x_FAULT_CHRG_THERMAL: | |
++ dev_err(bq2419x->dev, "Charging Fault: Thermal shutdown\n"); | |
++ check_chg_state = 1; | |
++ break; | |
++ case BQ2419x_FAULT_CHRG_SAFTY: | |
++ dev_err(bq2419x->dev, | |
++ "Charging Fault: Safety timer expiration\n"); | |
++ ret = bq2419x_reset_safety_timer(bq2419x); | |
++ if (ret < 0) { | |
++ dev_err(bq2419x->dev, "Reset safety timer failed %d\n", | |
++ ret); | |
++ return ret; | |
++ } | |
++ break; | |
++ default: | |
++ break; | |
++ } | |
++ | |
++ if (val & BQ2419x_FAULT_NTC_FAULT) | |
++ dev_err(bq2419x->dev, "Charging Fault: NTC fault %d\n", | |
++ val & BQ2419x_FAULT_NTC_FAULT); | |
++ | |
++ ret = bq2419x_fault_clear_sts(bq2419x); | |
++ if (ret < 0) { | |
++ dev_err(bq2419x->dev, "fault clear status failed %d\n", ret); | |
++ return ret; | |
++ } | |
++ | |
++ ret = regmap_read(bq2419x->regmap, BQ2419X_SYS_STAT_REG, &val); | |
++ if (ret < 0) { | |
++ dev_err(bq2419x->dev, "SYS_STAT_REG read failed %d\n", ret); | |
++ return ret; | |
++ } | |
++ | |
++ if ((val & BQ2419x_SYS_STAT_CHRG_STATE_MASK) == | |
++ BQ2419x_SYS_STAT_CHRG_STATE_CHARGE_DONE) | |
++ dev_info(bq2419x->dev, "Charging completed\n"); | |
++ | |
++ return IRQ_HANDLED; | |
++} | |
++ | |
++static int bq2419x_init_charger_regulator(struct bq2419x_chip *bq2419x) | |
++{ | |
++ int ret = 0; | |
++ struct regulator_config rconfig = { }; | |
++ | |
++ rconfig.dev = bq2419x->dev; | |
++ rconfig.of_node = bq2419x->dev->of_node; | |
++ rconfig.init_data = | |
++ bq2419x_matches[BQ2419X_REGULATOR_CHARGER].init_data; | |
++ rconfig.driver_data = bq2419x; | |
++ bq2419x->chg_rdev = regulator_register( | |
++ &bq2419x_reg_desc[BQ2419X_REGULATOR_CHARGER], | |
++ &rconfig); | |
++ if (IS_ERR(bq2419x->chg_rdev)) { | |
++ ret = PTR_ERR(bq2419x->chg_rdev); | |
++ dev_err(bq2419x->dev, "charger regulator register failed %d\n", | |
++ ret); | |
++ } | |
++ return ret; | |
++} | |
++ | |
++static int bq2419x_init_vbus_regulator(struct bq2419x_chip *bq2419x) | |
++{ | |
++ int ret = 0; | |
++ struct regulator_config rconfig = { }; | |
++ | |
++ if (gpio_is_valid(bq2419x->otg_iusb_gpio)) { | |
++ ret = devm_gpio_request_one(bq2419x->dev, | |
++ bq2419x->otg_iusb_gpio, | |
++ GPIOF_OUT_INIT_HIGH, | |
++ dev_name(bq2419x->dev)); | |
++ if (ret < 0) { | |
++ dev_err(bq2419x->dev, "gpio request failed %d\n", ret); | |
++ return ret; | |
++ } | |
++ } | |
++ | |
++ /* Register the regulators */ | |
++ rconfig.dev = bq2419x->dev; | |
++ rconfig.of_node = bq2419x->dev->of_node; | |
++ rconfig.init_data = bq2419x_matches[BQ2419X_REGULATOR_VBUS].init_data; | |
++ rconfig.driver_data = bq2419x; | |
++ bq2419x->vbus_rdev = regulator_register( | |
++ &bq2419x_reg_desc[BQ2419X_REGULATOR_VBUS], | |
++ &rconfig); | |
++ if (IS_ERR(bq2419x->vbus_rdev)) { | |
++ ret = PTR_ERR(bq2419x->vbus_rdev); | |
++ dev_err(bq2419x->dev, "VBUS regulator register failed %d\n", | |
++ ret); | |
++ return ret; | |
++ } | |
++ return ret; | |
++} | |
++ | |
++static int bq2419x_show_chip_version(struct bq2419x_chip *bq2419x) | |
++{ | |
++ int ret; | |
++ unsigned int val; | |
++ | |
++ ret = regmap_read(bq2419x->regmap, BQ2419X_REVISION_REG, &val); | |
++ if (ret < 0) { | |
++ dev_err(bq2419x->dev, "REVISION_REG read failed %d\n", ret); | |
++ return ret; | |
++ } | |
++ | |
++ if ((val & BQ24190_IC_VER) == BQ24190_IC_VER) | |
++ dev_info(bq2419x->dev, "chip type BQ24190 detected\n"); | |
++ else if ((val & BQ24192_IC_VER) == BQ24192_IC_VER) | |
++ dev_info(bq2419x->dev, "chip type BQ2419X/3 detected\n"); | |
++ else if ((val & BQ24192i_IC_VER) == BQ24192i_IC_VER) | |
++ dev_info(bq2419x->dev, "chip type BQ2419Xi detected\n"); | |
++ return 0; | |
++} | |
++ | |
++ | |
++static const struct regmap_config bq2419x_regmap_config = { | |
++ .reg_bits = 8, | |
++ .val_bits = 8, | |
++ .max_register = BQ2419X_MAX_REGS, | |
++}; | |
++ | |
++static int bq2419x_probe(struct i2c_client *client, | |
++ const struct i2c_device_id *id) | |
++{ | |
++ struct bq2419x_chip *bq2419x; | |
++ int ret = 0; | |
++ | |
++ if (!client->dev.of_node) { | |
++ dev_err(&client->dev, "Driver only supported from DT\n"); | |
++ return -ENODEV; | |
++ } | |
++ | |
++ | |
++ bq2419x = devm_kzalloc(&client->dev, sizeof(*bq2419x), GFP_KERNEL); | |
++ if (!bq2419x) { | |
++ dev_err(&client->dev, "Memory allocation failed\n"); | |
++ return -ENOMEM; | |
++ } | |
++ | |
++ bq2419x->dev = &client->dev; | |
++ bq2419x->irq = client->irq; | |
++ | |
++ ret = bq2419x_parse_dt_reg_data(bq2419x); | |
++ if (ret < 0) { | |
++ dev_err(&client->dev, "DT parsing failed %d\n", ret); | |
++ return ret; | |
++ } | |
++ | |
++ bq2419x->regmap = devm_regmap_init_i2c(client, &bq2419x_regmap_config); | |
++ if (IS_ERR(bq2419x->regmap)) { | |
++ ret = PTR_ERR(bq2419x->regmap); | |
++ dev_err(&client->dev, "regmap init failed %d\n", ret); | |
++ return ret; | |
++ } | |
++ | |
++ | |
++ i2c_set_clientdata(client, bq2419x); | |
++ mutex_init(&bq2419x->mutex); | |
++ | |
++ ret = bq2419x_show_chip_version(bq2419x); | |
++ if (ret < 0) { | |
++ dev_err(&client->dev, "version read failed %d\n", ret); | |
++ goto scrub_mutex; | |
++ } | |
++ | |
++ ret = bq2419x_charger_init_configure(bq2419x); | |
++ if (ret < 0) { | |
++ dev_err(bq2419x->dev, "Charger init failed %d\n", ret); | |
++ goto scrub_mutex; | |
++ } | |
++ | |
++ ret = bq2419x_watchdog_init(bq2419x, bq2419x->wdt_timeout); | |
++ if (ret < 0) { | |
++ dev_err(bq2419x->dev, "BQWDT init failed %d\n", ret); | |
++ goto scrub_mutex; | |
++ } | |
++ | |
++ ret = bq2419x_init_vbus_regulator(bq2419x); | |
++ if (ret < 0) { | |
++ dev_err(&client->dev, "VBUS regualtor init failed %d\n", ret); | |
++ goto scrub_mutex; | |
++ } | |
++ | |
++ ret = bq2419x_init_charger_regulator(bq2419x); | |
++ if (ret < 0) { | |
++ dev_err(&client->dev, "Charger regualtor init failed %d\n", | |
++ ret); | |
++ goto scrub_vbus_reg; | |
++ } | |
++ | |
++ ret = bq2419x_fault_clear_sts(bq2419x); | |
++ if (ret < 0) { | |
++ dev_err(bq2419x->dev, "fault clear status failed %d\n", ret); | |
++ goto scrub_chg_reg; | |
++ } | |
++ | |
++ if (bq2419x->wdt_timeout) { | |
++ INIT_DELAYED_WORK(&bq2419x->bq_wdt_work, | |
++ bq2419x_reset_wdt_work); | |
++ schedule_delayed_work(&bq2419x->bq_wdt_work, | |
++ msecs_to_jiffies(bq2419x->wdt_refresh_timeout * 1000)); | |
++ } | |
++ | |
++ ret = devm_request_threaded_irq(bq2419x->dev, bq2419x->irq, NULL, | |
++ bq2419x_irq, IRQF_ONESHOT | IRQF_TRIGGER_FALLING, | |
++ dev_name(bq2419x->dev), bq2419x); | |
++ if (ret < 0) { | |
++ dev_err(bq2419x->dev, "request IRQ %d failed %d\n", | |
++ bq2419x->irq, ret); | |
++ goto scrub_wq; | |
++ } | |
++ | |
++ return 0; | |
++ | |
++scrub_wq: | |
++ flush_work(&bq2419x->bq_wdt_work.work); | |
++scrub_chg_reg: | |
++ regulator_unregister(bq2419x->chg_rdev); | |
++scrub_vbus_reg: | |
++ regulator_unregister(bq2419x->vbus_rdev); | |
++scrub_mutex: | |
++ mutex_destroy(&bq2419x->mutex); | |
++ return ret; | |
++} | |
++ | |
++static int bq2419x_remove(struct i2c_client *client) | |
++{ | |
++ struct bq2419x_chip *bq2419x = i2c_get_clientdata(client); | |
++ | |
++ flush_work(&bq2419x->bq_wdt_work.work); | |
++ regulator_unregister(bq2419x->vbus_rdev); | |
++ regulator_unregister(bq2419x->chg_rdev); | |
++ mutex_destroy(&bq2419x->mutex); | |
++ return 0; | |
++} | |
++ | |
++static const struct of_device_id bq2419x_of_match[] = { | |
++ { .compatible = "ti,bq2419x",}, | |
++ {}, | |
++}; | |
++MODULE_DEVICE_TABLE(of, tps51632_of_match); | |
++ | |
++static const struct i2c_device_id bq2419x_id[] = { | |
++ {.name = "bq2419x",}, | |
++ {}, | |
++}; | |
++MODULE_DEVICE_TABLE(i2c, bq2419x_id); | |
++ | |
++static struct i2c_driver bq2419x_i2c_driver = { | |
++ .driver = { | |
++ .name = "bq2419x", | |
++ .owner = THIS_MODULE, | |
++ .of_match_table = of_match_ptr(bq2419x_of_match), | |
++ }, | |
++ .probe = bq2419x_probe, | |
++ .remove = bq2419x_remove, | |
++ .id_table = bq2419x_id, | |
++}; | |
++ | |
++static int __init bq2419x_module_init(void) | |
++{ | |
++ return i2c_add_driver(&bq2419x_i2c_driver); | |
++} | |
++subsys_initcall(bq2419x_module_init); | |
++ | |
++static void __exit bq2419x_cleanup(void) | |
++{ | |
++ i2c_del_driver(&bq2419x_i2c_driver); | |
++} | |
++module_exit(bq2419x_cleanup); | |
++ | |
++MODULE_DESCRIPTION("BQ24190/BQ24192/BQ24192i/BQ24193 battery charger driver"); | |
++MODULE_AUTHOR("Laxman Dewangan <[email protected]>"); | |
++MODULE_LICENSE("GPL v2"); | |
+diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c | |
+index bbe4f8e6e8d7492be10cc54cfe2f37e8001f2db6..0e127e6c260db5fb5036689d9be69415a4d6c7ed 100644 | |
+--- a/drivers/usb/phy/phy-tegra-usb.c | |
++++ b/drivers/usb/phy/phy-tegra-usb.c | |
+@@ -157,6 +157,11 @@ | |
+ #define USB_USBMODE_HOST (3 << 0) | |
+ #define USB_USBMODE_DEVICE (2 << 0) | |
+ | |
++#define USB_PHY_WAKEUP 0x408 | |
++#define USB_ID_INT_EN (1<<0) | |
++#define USB_ID_CHG_DET (1<<1) | |
++#define USB_ID_STS (1<<2) | |
++ | |
+ static DEFINE_SPINLOCK(utmip_pad_lock); | |
+ static int utmip_pad_count; | |
+ | |
+@@ -244,6 +249,22 @@ static void set_phcd(struct tegra_usb_phy *phy, bool enable) | |
+ } | |
+ } | |
+ | |
++static void tegra_usb_update_vbus(struct tegra_usb_phy *tegra_phy) { | |
++ if (IS_ERR(tegra_phy->vbus)) | |
++ return; | |
++ | |
++ if (tegra_phy->otg_id && tegra_phy->otg_vbus_enabled) { | |
++ dev_notice(tegra_phy->u_phy.dev, "switching vbus to device mode\n"); | |
++ tegra_phy->otg_vbus_enabled = false; | |
++ regulator_disable(tegra_phy->vbus); | |
++ } else if (!tegra_phy->otg_id && !tegra_phy->otg_vbus_enabled) { | |
++ dev_notice(tegra_phy->u_phy.dev, "switching vbus to host mode\n"); | |
++ if (regulator_enable(tegra_phy->vbus)) | |
++ dev_err(tegra_phy->u_phy.dev, "enabling vbus failed\n"); | |
++ tegra_phy->otg_vbus_enabled = true; | |
++ } | |
++} | |
++ | |
+ static int utmip_pad_open(struct tegra_usb_phy *phy) | |
+ { | |
+ phy->pad_clk = devm_clk_get(phy->u_phy.dev, "utmi-pads"); | |
+@@ -516,6 +537,13 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) | |
+ if (!phy->is_legacy_phy) | |
+ set_pts(phy, 0); | |
+ | |
++ if (phy->mode == USB_DR_MODE_OTG) { | |
++ val = readl(base + USB_PHY_WAKEUP); | |
++ val |= USB_ID_INT_EN; | |
++ writel(val, base + USB_PHY_WAKEUP); | |
++ udelay(1); | |
++ } | |
++ | |
+ return 0; | |
+ } | |
+ | |
+@@ -787,12 +815,16 @@ static int tegra_usb_phy_init(struct tegra_usb_phy *phy) | |
+ } | |
+ | |
+ if (!IS_ERR(phy->vbus)) { | |
+- err = regulator_enable(phy->vbus); | |
+- if (err) { | |
+- dev_err(phy->u_phy.dev, | |
+- "failed to enable usb vbus regulator: %d\n", | |
+- err); | |
+- goto fail; | |
++ if (phy->mode == USB_DR_MODE_HOST) { | |
++ err = regulator_enable(phy->vbus); | |
++ if (err) { | |
++ dev_err(phy->u_phy.dev, | |
++ "failed to enable usb vbus regulator: %d\n", | |
++ err); | |
++ goto fail; | |
++ } | |
++ } else if (phy->mode == USB_DR_MODE_OTG) { | |
++ tegra_usb_update_vbus(phy); | |
+ } | |
+ } | |
+ | |
+@@ -859,13 +891,54 @@ static int read_utmi_param(struct platform_device *pdev, const char *param, | |
+ return err; | |
+ } | |
+ | |
++static irqreturn_t otg_irq(int irq, void *data) | |
++{ | |
++ | |
++ struct tegra_usb_phy *tegra_phy = data; | |
++ int val; | |
++ | |
++ val = readl(tegra_phy->regs + USB_PHY_WAKEUP); | |
++ if (val & USB_ID_INT_EN) { | |
++ writel(val, tegra_phy->regs + USB_PHY_WAKEUP); | |
++ if (val & USB_ID_CHG_DET) { | |
++ tegra_phy->otg_id = val & USB_ID_STS; | |
++ schedule_work(&tegra_phy->otg_work); | |
++ } | |
++ } | |
++ | |
++ return IRQ_HANDLED; | |
++} | |
++ | |
++static void otg_irq_work(struct work_struct *work) { | |
++ struct tegra_usb_phy *tegra_phy = container_of(work, struct tegra_usb_phy, | |
++ otg_work); | |
++ | |
++ tegra_usb_update_vbus(tegra_phy); | |
++} | |
++ | |
+ static int utmi_phy_probe(struct tegra_usb_phy *tegra_phy, | |
+ struct platform_device *pdev) | |
+ { | |
+ struct resource *res; | |
+ int err; | |
++ int irq; | |
+ struct tegra_utmip_config *config; | |
+ | |
++ if (tegra_phy->mode == USB_DR_MODE_OTG) { | |
++ tegra_phy->otg_vbus_enabled = false; | |
++ tegra_phy->otg_id = 4; | |
++ | |
++ irq = platform_get_irq(pdev, 0); | |
++ err = devm_request_threaded_irq(&pdev->dev, irq, otg_irq, NULL, | |
++ IRQF_SHARED, | |
++ "tegra-usb-otg", tegra_phy); | |
++ if (err) { | |
++ dev_err(&pdev->dev, "OTG irq request failed: %d\n", err); | |
++ } | |
++ | |
++ INIT_WORK(&tegra_phy->otg_work, otg_irq_work); | |
++ } | |
++ | |
+ tegra_phy->is_ulpi_phy = false; | |
+ | |
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | |
+@@ -1010,6 +1083,16 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) | |
+ tegra_phy->is_legacy_phy = | |
+ of_property_read_bool(np, "nvidia,has-legacy-mode"); | |
+ | |
++ if (of_find_property(np, "dr_mode", NULL)) | |
++ tegra_phy->mode = of_usb_get_dr_mode(np); | |
++ else | |
++ tegra_phy->mode = USB_DR_MODE_HOST; | |
++ | |
++ if (tegra_phy->mode == USB_DR_MODE_UNKNOWN) { | |
++ dev_err(&pdev->dev, "dr_mode is invalid\n"); | |
++ return -EINVAL; | |
++ } | |
++ | |
+ phy_type = of_usb_get_phy_mode(np); | |
+ switch (phy_type) { | |
+ case USBPHY_INTERFACE_MODE_UTMI: | |
+@@ -1036,16 +1119,6 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) | |
+ return -EINVAL; | |
+ } | |
+ | |
+- if (of_find_property(np, "dr_mode", NULL)) | |
+- tegra_phy->mode = of_usb_get_dr_mode(np); | |
+- else | |
+- tegra_phy->mode = USB_DR_MODE_HOST; | |
+- | |
+- if (tegra_phy->mode == USB_DR_MODE_UNKNOWN) { | |
+- dev_err(&pdev->dev, "dr_mode is invalid\n"); | |
+- return -EINVAL; | |
+- } | |
+- | |
+ /* On some boards, the VBUS regulator doesn't need to be controlled */ | |
+ if (of_find_property(np, "vbus-supply", NULL)) { | |
+ tegra_phy->vbus = devm_regulator_get(&pdev->dev, "vbus"); | |
+diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h | |
+index 944f33f8ba38d2072b2762306a9de0ae49c74ef2..efa1b552adc5c2ac6612fbc41dd8dc307486973c 100644 | |
+--- a/include/drm/drm_mipi_dsi.h | |
++++ b/include/drm/drm_mipi_dsi.h | |
+@@ -94,6 +94,8 @@ void mipi_dsi_host_unregister(struct mipi_dsi_host *host); | |
+ #define MIPI_DSI_MODE_VSYNC_FLUSH BIT(8) | |
+ /* disable EoT packets in HS mode */ | |
+ #define MIPI_DSI_MODE_EOT_PACKET BIT(9) | |
++/* device supports non-continuous clock behavior (DSI spec 5.6.1) */ | |
++#define MIPI_DSI_CLOCK_NON_CONTINUOUS BIT(10) | |
+ | |
+ enum mipi_dsi_pixel_format { | |
+ MIPI_DSI_FMT_RGB888, | |
+diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h | |
+index 1de16c324ec88698d3b9bfc1d7242d915ca506a8..44b85f7d42bbcd65dddad1aba690d64388223cf8 100644 | |
+--- a/include/linux/usb/tegra_usb_phy.h | |
++++ b/include/linux/usb/tegra_usb_phy.h | |
+@@ -75,6 +75,9 @@ struct tegra_usb_phy { | |
+ bool is_legacy_phy; | |
+ bool is_ulpi_phy; | |
+ int reset_gpio; | |
++ int otg_id; | |
++ bool otg_vbus_enabled; | |
++ struct work_struct otg_work; | |
+ }; | |
+ | |
+ void tegra_usb_phy_preresume(struct usb_phy *phy); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment