Skip to content

Instantly share code, notes, and snippets.

@webgeek1234
Created October 7, 2014 04:45
Show Gist options
  • Save webgeek1234/8eea739d16f03dfa715b to your computer and use it in GitHub Desktop.
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])
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 <ldewangan@nvidia.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation 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, &reg01);
++ 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, &reg09);
++ if (ret < 0) {
++ dev_err(bq2419x->dev, "FAULT_REG read failed %d\n", ret);
++ return ret;
++ }
++
++ ret = regmap_read(bq2419x->regmap, BQ2419X_FAULT_REG, &reg09);
++ 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, &reg05);
++ 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 <ldewangan@nvidia.com>");
++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