Merge "spi_qsd: Initialize wait queue"
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index c4b4707..afbae5e 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -293,6 +293,15 @@
- qcom,panel-roi-alignment: Specifies the panel ROI alignment restrictions on its
left, top, width, height alignments and minimum width and
height values
+- qcom,dynamic-mode-switch-enabled: Boolean used to mention whether panel supports
+ dynamic switching from video mode to command mode
+ and vice versa.
+- qcom,video-to-cmd-mode-switch-commands: List of commands that need to be sent
+ to panel in order to switch from video mode to command mode dynamically.
+ Refer to "qcom,mdss-dsi-on-command" section for adding commands.
+- qcom,cmd-to-video-mode-switch-commands: List of commands that need to be sent
+ to panel in order to switch from command mode to video mode dynamically.
+ Refer to "qcom,mdss-dsi-on-command" section for adding commands.
Note, if a given optional qcom,* binding is not present, then the driver will configure
the default values specified.
@@ -399,5 +408,9 @@
qcom,mdss-tear-check-rd-ptr-trigger-intr = <1281>;
qcom,mdss-tear-check-frame-rate = <6000>;
qcom,panel-roi-alignment = <4 4 2 2 20 20>;
+ qcom,dynamic-mode-switch-enabled;
+ qcom,video-to-cmd-mode-switch-commands = [15 01 00 00 00 00 02 C2 0B
+ 15 01 00 00 00 00 02 C2 08];
+ qcom,cmd-to-video-mode-switch-commands = [15 01 00 00 00 00 02 C2 03];
};
};
diff --git a/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
index 9a18a31..bab1735 100644
--- a/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
+++ b/arch/arm/boot/dts/dsi-panel-nt35590-720p-video.dtsi
@@ -511,6 +511,10 @@
05 01 00 00 78 00 02 10 00];
qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+ qcom,dynamic-mode-switch-enabled;
+ qcom,video-to-cmd-mode-switch-commands = [15 01 00 00 14 00 02 C2 0B
+ 15 01 00 00 00 00 02 C2 08];
+ qcom,cmd-to-video-mode-switch-commands = [15 01 00 00 00 00 02 C2 03];
qcom,mdss-dsi-h-sync-pulse = <1>;
qcom,mdss-dsi-traffic-mode = "burst_mode";
qcom,mdss-dsi-bllp-eof-power-mode;
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index d243b78..ad029ee 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -470,14 +470,25 @@
qcom,clock-a7@f9011050 {
compatible = "qcom,clock-a7-8226";
- reg = <0xf9011050 0x8>;
- reg-names = "rcg-base";
+ reg = <0xf9011050 0x8>,
+ <0xfc4b80b8 0x8>;
+ reg-names = "rcg-base", "efuse";
clock-names = "clk-4", "clk-5";
qcom,speed0-bin-v0 =
< 0 0>,
< 384000000 1>,
< 787200000 2>,
<1190400000 3>;
+ qcom,speed1-bin-v0 =
+ < 0 0>,
+ < 384000000 1>,
+ < 787200000 2>,
+ <1094400000 3>;
+ qcom,speed1-bin-v2 =
+ < 0 0>,
+ < 384000000 1>,
+ < 787200000 2>,
+ <1094400000 3>;
cpu-vdd-supply = <&apc_vreg_corner>;
};
@@ -500,6 +511,7 @@
< 600000 1525 >,
< 787200 1525 >,
< 998400 2540 >,
+ < 1094400 2540 >,
< 1190400 2540 >;
};
diff --git a/arch/arm/boot/dts/msm8974-v1.dtsi b/arch/arm/boot/dts/msm8974-v1.dtsi
index 6146454..6b3e945 100644
--- a/arch/arm/boot/dts/msm8974-v1.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1.dtsi
@@ -41,6 +41,7 @@
compatible = "qcom,android-usb";
reg = <0xfc42b0c8 0xc8>;
qcom,android-usb-swfi-latency = <1>;
+ qcom,android-usb-uicc-nluns = /bits/ 8 <1>;
};
qcom,msm-imem@fc42b000 {
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index fd4221f..91844c3 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -41,6 +41,7 @@
compatible = "qcom,android-usb";
reg = <0xfe8050c8 0xc8>;
qcom,android-usb-swfi-latency = <1>;
+ qcom,android-usb-uicc-nluns = /bits/ 8 <1>;
};
qcom,msm-imem@fe805000 {
diff --git a/arch/arm/boot/dts/msm8974pro-ac-pm8941-mtp.dts b/arch/arm/boot/dts/msm8974pro-ac-pm8941-mtp.dts
index a25b8ca..692a405 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-pm8941-mtp.dts
+++ b/arch/arm/boot/dts/msm8974pro-ac-pm8941-mtp.dts
@@ -30,3 +30,29 @@
status = "ok";
qcom,usb2-enable-uicc;
};
+
+&soc {
+ i2c@f9928000 { /* BLSP1 QUP6 */
+ nfc-nci@e {
+ compatible = "qcom,nfc-nci";
+ reg = <0x0e>;
+ qcom,irq-gpio = <&msmgpio 57 0x00>;
+ qcom,dis-gpio = <&msmgpio 13 0x00>;
+ qcom,clk-src = "BBCLK2";
+ interrupt-parent = <&msmgpio>;
+ interrupts = <57 0>;
+ qcom,clk-gpio = <&pm8941_gpios 32 0>;
+ };
+ };
+};
+
+&pm8941_gpios {
+ gpio@df00 {
+ /* NFC clk request */
+ qcom,mode = <0>; /* QPNP_PIN_MODE_DIG_IN */
+ qcom,pull = <5>; /* QPNP_PIN_PULL_NO */
+ qcom,vin-sel = <2>; /* QPNP_PIN_VIN2 */
+ qcom,src-sel = <2>; /* QPNP_PIN_SEL_FUNC_1 */
+ qcom,master-en = <1>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974pro.dtsi b/arch/arm/boot/dts/msm8974pro.dtsi
index 3e00a46..7a08ca6 100644
--- a/arch/arm/boot/dts/msm8974pro.dtsi
+++ b/arch/arm/boot/dts/msm8974pro.dtsi
@@ -27,6 +27,7 @@
compatible = "qcom,android-usb";
reg = <0xfe8050c8 0xc8>;
qcom,android-usb-swfi-latency = <1>;
+ qcom,android-usb-uicc-nluns = /bits/ 8 <1>;
};
qcom,msm-imem@fe805000 {
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 414a4df..913d798 100755
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -396,6 +396,7 @@
CONFIG_USB_EHCI_MSM=y
CONFIG_USB_EHCI_MSM_HSIC=y
CONFIG_USB_ACM=y
+CONFIG_USB_MON=y
CONFIG_USB_CCID_BRIDGE=y
CONFIG_USB_STORAGE=y
CONFIG_USB_STORAGE_DATAFAB=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 3b2f2b5..d588fc6 100755
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -420,6 +420,7 @@
CONFIG_USB_EHCI_MSM=y
CONFIG_USB_EHCI_MSM_HSIC=y
CONFIG_USB_ACM=y
+CONFIG_USB_MON=y
CONFIG_USB_CCID_BRIDGE=y
CONFIG_USB_STORAGE=y
CONFIG_USB_STORAGE_DATAFAB=y
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index e9c749a..482981c 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -559,6 +559,7 @@
F_APCS_PLL( 768000000, 40, 0x0, 0x1, 0x0, 0x0, 0x0),
F_APCS_PLL( 787200000, 41, 0x0, 0x1, 0x0, 0x0, 0x0),
F_APCS_PLL( 998400000, 52, 0x0, 0x1, 0x0, 0x0, 0x0),
+ F_APCS_PLL(1094400000, 57, 0x0, 0x1, 0x0, 0x0, 0x0),
F_APCS_PLL(1190400000, 62, 0x0, 0x1, 0x0, 0x0, 0x0),
PLL_F_END
};
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
index 8cb3cf3..fc57bd6 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
@@ -1808,12 +1808,12 @@
static void bke_switch(
void __iomem *baddr, uint32_t mas_index, bool req, int mode)
{
- uint32_t reg_val, val;
+ uint32_t reg_val, val, cur_val;
val = req << M_BKE_EN_EN_SHFT;
- reg_val = readl_relaxed(M_BKE_EN_ADDR(baddr, mas_index)) &
- M_BKE_EN_RMSK;
- if (val == reg_val)
+ reg_val = readl_relaxed(M_BKE_EN_ADDR(baddr, mas_index));
+ cur_val = reg_val & M_BKE_EN_RMSK;
+ if (val == cur_val)
return;
if (!req && mode == BIMC_QOS_MODE_FIXED)
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index 4845f11..d1e35ec 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -2111,6 +2111,75 @@
return 0;
};
+static int qcedev_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct qcedev_control *podev;
+ int ret;
+ podev = platform_get_drvdata(pdev);
+
+ if (!podev || !podev->platform_support.bus_scale_table)
+ return 0;
+
+ mutex_lock(&qcedev_sent_bw_req);
+ if (podev->high_bw_req_count) {
+ ret = msm_bus_scale_client_update_request(
+ podev->bus_scale_handle, 0);
+ if (ret) {
+ pr_err("%s Unable to set to low bandwidth\n",
+ __func__);
+ goto suspend_exit;
+ }
+ ret = qce_disable_clk(podev->qce);
+ if (ret) {
+ pr_err("%s Unable disable clk\n", __func__);
+ ret = msm_bus_scale_client_update_request(
+ podev->bus_scale_handle, 1);
+ if (ret)
+ pr_err("%s Unable to set to high bandwidth\n",
+ __func__);
+ goto suspend_exit;
+ }
+ }
+
+suspend_exit:
+ mutex_unlock(&qcedev_sent_bw_req);
+ return 0;
+}
+
+static int qcedev_resume(struct platform_device *pdev)
+{
+ struct qcedev_control *podev;
+ int ret;
+ podev = platform_get_drvdata(pdev);
+
+ if (!podev || !podev->platform_support.bus_scale_table)
+ return 0;
+
+ mutex_lock(&qcedev_sent_bw_req);
+ if (podev->high_bw_req_count) {
+ ret = qce_enable_clk(podev->qce);
+ if (ret) {
+ pr_err("%s Unable enable clk\n", __func__);
+ goto resume_exit;
+ }
+ ret = msm_bus_scale_client_update_request(
+ podev->bus_scale_handle, 1);
+ if (ret) {
+ pr_err("%s Unable to set to high bandwidth\n",
+ __func__);
+ ret = qce_disable_clk(podev->qce);
+ if (ret)
+ pr_err("%s Unable enable clk\n",
+ __func__);
+ goto resume_exit;
+ }
+ }
+
+resume_exit:
+ mutex_unlock(&qcedev_sent_bw_req);
+ return 0;
+}
+
static struct of_device_id qcedev_match[] = {
{ .compatible = "qcom,qcedev",
},
@@ -2120,6 +2189,8 @@
static struct platform_driver qcedev_plat_driver = {
.probe = qcedev_probe,
.remove = qcedev_remove,
+ .suspend = qcedev_suspend,
+ .resume = qcedev_resume,
.driver = {
.name = "qce",
.owner = THIS_MODULE,
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index d163317..4fbbda4 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -3444,13 +3444,17 @@
struct adreno_busy_data busy_data;
memset(stats, 0, sizeof(*stats));
+
/*
- * Get the busy cycles counted since the counter was last reset.
* If we're not currently active, there shouldn't have been
* any cycles since the last time this function was called.
*/
- if (device->state == KGSL_STATE_ACTIVE)
- adreno_dev->gpudev->busy_cycles(adreno_dev, &busy_data);
+
+ if (device->state != KGSL_STATE_ACTIVE)
+ return;
+
+ /* Get the busy cycles counted since the counter was last reset */
+ adreno_dev->gpudev->busy_cycles(adreno_dev, &busy_data);
stats->busy_time = adreno_ticks_to_us(busy_data.gpu_busy,
kgsl_pwrctrl_active_freq(pwr));
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index d3a848a..1c219f2 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -1284,8 +1284,6 @@
unsigned long in_phyaddr, out_phyaddr0, out_phyaddr1;
uint16_t num_stripes = 0;
struct msm_buf_mngr_info buff_mgr_info, dup_buff_mgr_info;
- struct msm_cpp_frame_info_t *u_frame_info =
- (struct msm_cpp_frame_info_t *)ioctl_ptr->ioctl_ptr;
int32_t status = 0;
uint8_t fw_version_1_2_x = 0;
int in_fd;
@@ -1441,7 +1439,7 @@
ioctl_ptr->trans_code = rc;
status = rc;
- rc = (copy_to_user((void __user *)u_frame_info->status, &status,
+ rc = (copy_to_user((void __user *)new_frame->status, &status,
sizeof(int32_t)) ? -EFAULT : 0);
if (rc) {
ERR_COPY_FROM_USER();
@@ -1457,12 +1455,12 @@
ERROR2:
kfree(cpp_frame_msg);
ERROR1:
- kfree(new_frame);
ioctl_ptr->trans_code = rc;
status = rc;
- if (copy_to_user((void __user *)u_frame_info->status, &status,
+ if (copy_to_user((void __user *)new_frame->status, &status,
sizeof(int32_t)))
pr_err("error cannot copy error\n");
+ kfree(new_frame);
return rc;
}
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index c638415..aaed0e9 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -543,6 +543,35 @@
{}
};
+static int msm_vidc_pm_suspend(struct device *pdev)
+{
+ struct msm_vidc_core *core;
+
+ if (!pdev) {
+ dprintk(VIDC_ERR, "%s invalid device\n", __func__);
+ return -EINVAL;
+ }
+
+ core = (struct msm_vidc_core *)pdev->platform_data;
+ if (!core) {
+ dprintk(VIDC_ERR, "%s invalid core\n", __func__);
+ return -EINVAL;
+ }
+ dprintk(VIDC_INFO, "%s\n", __func__);
+
+ return msm_vidc_suspend(core->id);
+}
+
+static int msm_vidc_pm_resume(struct device *dev)
+{
+ dprintk(VIDC_INFO, "%s\n", __func__);
+ return 0;
+}
+
+static const struct dev_pm_ops msm_vidc_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(msm_vidc_pm_suspend, msm_vidc_pm_resume)
+};
+
MODULE_DEVICE_TABLE(of, msm_vidc_dt_match);
static struct platform_driver msm_vidc_driver = {
@@ -552,6 +581,7 @@
.name = "msm_vidc_v4l2",
.owner = THIS_MODULE,
.of_match_table = msm_vidc_dt_match,
+ .pm = &msm_vidc_pm_ops,
},
};
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index f84a806..bff86a6 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -22,7 +22,7 @@
#define MSM_VDEC_DVC_NAME "msm_vdec_8974"
#define MIN_NUM_OUTPUT_BUFFERS 4
#define MAX_NUM_OUTPUT_BUFFERS VIDEO_MAX_FRAME
-#define DEFAULT_VIDEO_CONCEAL_COLOR_BLACK 0x8080
+#define DEFAULT_VIDEO_CONCEAL_COLOR_BLACK 0x8010
#define TZ_DYNAMIC_BUFFER_FEATURE_ID 12
#define TZ_FEATURE_VERSION(major, minor, patch) \
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index cfc2eb8..c5d038f 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -1404,3 +1404,8 @@
return 0;
}
+
+int msm_vidc_suspend(int core_id)
+{
+ return msm_comm_suspend(core_id);
+}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 9f0dac4..84b0780 100755
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -2112,6 +2112,33 @@
return rc;
}
+int msm_comm_suspend(int core_id)
+{
+ struct hfi_device *hdev;
+ struct msm_vidc_core *core;
+ int rc = 0;
+
+ core = get_vidc_core(core_id);
+ if (!core) {
+ dprintk(VIDC_ERR,
+ "%s: Failed to find core for core_id = %d\n",
+ __func__, core_id);
+ return -EINVAL;
+ }
+
+ hdev = (struct hfi_device *)core->device;
+ if (!hdev) {
+ dprintk(VIDC_ERR, "%s Invalid device handle\n", __func__);
+ return -EINVAL;
+ }
+
+ rc = call_hfi_op(hdev, suspend, hdev->hfi_device_data);
+ if (rc)
+ dprintk(VIDC_WARN, "Failed to suspend\n");
+
+ return rc;
+}
+
static int get_flipped_state(int present_state,
int desired_state)
{
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h
index da71424..f4e2cd5 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h
@@ -40,6 +40,7 @@
int msm_comm_release_persist_buffers(struct msm_vidc_inst *inst);
int msm_comm_release_output_buffers(struct msm_vidc_inst *inst);
int msm_comm_force_cleanup(struct msm_vidc_inst *inst);
+int msm_comm_suspend(int core_id);
enum hal_extradata_id msm_comm_get_hal_extradata_index(
enum v4l2_mpeg_vidc_extradata index);
int msm_comm_get_domain_partition(struct msm_vidc_inst *inst, u32 flags,
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
index 486d740..52bbe12 100755
--- a/drivers/media/platform/msm/vidc/q6_hfi.c
+++ b/drivers/media/platform/msm/vidc/q6_hfi.c
@@ -1033,6 +1033,11 @@
dprintk(VIDC_ERR, "Invalid Params");
return -EINVAL;
}
+ if (ptype == HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER) {
+ dprintk(VIDC_WARN, "Smoothstreaming is not supported\n");
+ return -ENOTSUPP;
+ }
+
dev = session->device;
dprintk(VIDC_DBG, "in set_prop,with prop id: 0x%x", ptype);
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 448fe3b..a46dc95 100755
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -3518,6 +3518,25 @@
return rc;
}
+static int venus_hfi_suspend(void *dev)
+{
+ int rc = 0;
+ struct venus_hfi_device *device = (struct venus_hfi_device *) dev;
+
+ if (!device) {
+ dprintk(VIDC_ERR, "%s invalid device\n", __func__);
+ return -EINVAL;
+ }
+ dprintk(VIDC_INFO, "%s\n", __func__);
+
+ if (device->power_enabled) {
+ venus_hfi_try_clk_gating(device);
+ rc = flush_delayed_work(&venus_hfi_pm_work);
+ dprintk(VIDC_INFO, "%s flush delayed work %d\n", __func__, rc);
+ }
+ return 0;
+}
+
static int venus_hfi_load_fw(void *dev)
{
int rc = 0;
@@ -3910,6 +3929,7 @@
hdev->get_stride_scanline = venus_hfi_get_stride_scanline;
hdev->get_core_capabilities = venus_hfi_get_core_capabilities;
hdev->power_enable = venus_hfi_power_enable;
+ hdev->suspend = venus_hfi_suspend;
}
int venus_hfi_initialize(struct hfi_device *hdev, u32 device_id,
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 38c5bdb..8484bb2 100755
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -1171,6 +1171,7 @@
int (*session_clean)(void *sess);
int (*get_core_capabilities)(void);
int (*power_enable)(void *dev);
+ int (*suspend)(void *dev);
};
typedef void (*hfi_cmd_response_callback) (enum command_response cmd,
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 0c70746..97de664 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -30,6 +30,7 @@
#include <linux/blkdev.h>
#include <linux/mutex.h>
#include <linux/scatterlist.h>
+#include <linux/bitops.h>
#include <linux/string_helpers.h>
#include <linux/delay.h>
#include <linux/capability.h>
@@ -2469,7 +2470,7 @@
areq = mmc_start_req(card->host, areq, (int *) &status);
if (!areq) {
if (status == MMC_BLK_NEW_REQUEST)
- mq->flags |= MMC_QUEUE_NEW_REQUEST;
+ set_bit(MMC_QUEUE_NEW_REQUEST, &mq->flags);
return 0;
}
@@ -2490,7 +2491,7 @@
mmc_blk_reinsert_req(areq);
}
- mq->flags |= MMC_QUEUE_URGENT_REQUEST;
+ set_bit(MMC_QUEUE_URGENT_REQUEST, &mq->flags);
ret = 0;
break;
case MMC_BLK_URGENT_DONE:
@@ -2649,6 +2650,7 @@
struct mmc_card *card = md->queue.card;
struct mmc_host *host = card->host;
unsigned long flags;
+ unsigned int cmd_flags = req ? req->cmd_flags : 0;
if (req && !mq->mqrq_prev->req) {
mmc_rpm_hold(host, &card->dev);
@@ -2674,23 +2676,23 @@
mmc_blk_write_packing_control(mq, req);
- mq->flags &= ~MMC_QUEUE_NEW_REQUEST;
- mq->flags &= ~MMC_QUEUE_URGENT_REQUEST;
- if (req && req->cmd_flags & REQ_SANITIZE) {
+ clear_bit(MMC_QUEUE_NEW_REQUEST, &mq->flags);
+ clear_bit(MMC_QUEUE_URGENT_REQUEST, &mq->flags);
+ if (cmd_flags & REQ_SANITIZE) {
/* complete ongoing async transfer before issuing sanitize */
if (card->host && card->host->areq)
mmc_blk_issue_rw_rq(mq, NULL);
ret = mmc_blk_issue_sanitize_rq(mq, req);
- } else if (req && req->cmd_flags & REQ_DISCARD) {
+ } else if (cmd_flags & REQ_DISCARD) {
/* complete ongoing async transfer before issuing discard */
if (card->host->areq)
mmc_blk_issue_rw_rq(mq, NULL);
- if (req->cmd_flags & REQ_SECURE &&
+ if (cmd_flags & REQ_SECURE &&
!(card->quirks & MMC_QUIRK_SEC_ERASE_TRIM_BROKEN))
ret = mmc_blk_issue_secdiscard_rq(mq, req);
else
ret = mmc_blk_issue_discard_rq(mq, req);
- } else if (req && req->cmd_flags & REQ_FLUSH) {
+ } else if (cmd_flags & REQ_FLUSH) {
/* complete ongoing async transfer before issuing flush */
if (card->host->areq)
mmc_blk_issue_rw_rq(mq, NULL);
@@ -2711,10 +2713,9 @@
* - urgent notification in progress and current request is not urgent
* (all existing requests completed or reinserted to the block layer)
*/
- if ((!req && !(mq->flags & MMC_QUEUE_NEW_REQUEST)) ||
- ((mq->flags & MMC_QUEUE_URGENT_REQUEST) &&
- !(mq->mqrq_cur->req->cmd_flags &
- MMC_REQ_NOREINSERT_MASK))) {
+ if ((!req && !(test_bit(MMC_QUEUE_NEW_REQUEST, &mq->flags))) ||
+ ((test_bit(MMC_QUEUE_URGENT_REQUEST, &mq->flags)) &&
+ !(cmd_flags & MMC_REQ_NOREINSERT_MASK))) {
if (mmc_card_need_bkops(card))
mmc_start_bkops(card, false);
/* release host only when there are no more requests */
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index fa3dcdc..cceb8d9 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -15,6 +15,7 @@
#include <linux/freezer.h>
#include <linux/kthread.h>
#include <linux/scatterlist.h>
+#include <linux/bitops.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@@ -75,12 +76,12 @@
if (req || mq->mqrq_prev->req) {
set_current_state(TASK_RUNNING);
mq->issue_fn(mq, req);
- if (mq->flags & MMC_QUEUE_NEW_REQUEST) {
+ if (test_bit(MMC_QUEUE_NEW_REQUEST, &mq->flags)) {
continue; /* fetch again */
- } else if ((mq->flags & MMC_QUEUE_URGENT_REQUEST) &&
- (mq->mqrq_cur->req &&
- !(mq->mqrq_cur->req->cmd_flags &
- MMC_REQ_NOREINSERT_MASK))) {
+ } else if (test_bit(MMC_QUEUE_URGENT_REQUEST,
+ &mq->flags) && (mq->mqrq_cur->req &&
+ !(mq->mqrq_cur->req->cmd_flags &
+ MMC_REQ_NOREINSERT_MASK))) {
/*
* clean current request when urgent request
* processing in progress and current request is
@@ -474,9 +475,7 @@
unsigned long flags;
int rc = 0;
- if (!(mq->flags & MMC_QUEUE_SUSPENDED)) {
- mq->flags |= MMC_QUEUE_SUSPENDED;
-
+ if (!(test_and_set_bit(MMC_QUEUE_SUSPENDED, &mq->flags))) {
spin_lock_irqsave(q->queue_lock, flags);
blk_stop_queue(q);
spin_unlock_irqrestore(q->queue_lock, flags);
@@ -487,7 +486,7 @@
* Failed to take the lock so better to abort the
* suspend because mmcqd thread is processing requests.
*/
- mq->flags &= ~MMC_QUEUE_SUSPENDED;
+ clear_bit(MMC_QUEUE_SUSPENDED, &mq->flags);
spin_lock_irqsave(q->queue_lock, flags);
blk_start_queue(q);
spin_unlock_irqrestore(q->queue_lock, flags);
@@ -509,8 +508,7 @@
struct request_queue *q = mq->queue;
unsigned long flags;
- if (mq->flags & MMC_QUEUE_SUSPENDED) {
- mq->flags &= ~MMC_QUEUE_SUSPENDED;
+ if (test_and_clear_bit(MMC_QUEUE_SUSPENDED, &mq->flags)) {
up(&mq->thread_sem);
diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
index d1fe01c..0ed7f36 100644
--- a/drivers/mmc/card/queue.h
+++ b/drivers/mmc/card/queue.h
@@ -38,10 +38,10 @@
struct mmc_card *card;
struct task_struct *thread;
struct semaphore thread_sem;
- unsigned int flags;
-#define MMC_QUEUE_SUSPENDED (1 << 0)
-#define MMC_QUEUE_NEW_REQUEST (1 << 1)
-#define MMC_QUEUE_URGENT_REQUEST (1 << 2)
+ unsigned long flags;
+#define MMC_QUEUE_SUSPENDED 0
+#define MMC_QUEUE_NEW_REQUEST 1
+#define MMC_QUEUE_URGENT_REQUEST 2
int (*issue_fn)(struct mmc_queue *, struct request *);
void *data;
diff --git a/drivers/nfc/nfc-nci.c b/drivers/nfc/nfc-nci.c
index 018c3a6..a9c093b 100644
--- a/drivers/nfc/nfc-nci.c
+++ b/drivers/nfc/nfc-nci.c
@@ -56,10 +56,11 @@
#define MAX_QCA_REG (116)
/* will timeout in approx. 100ms as 10us steps */
#define NFC_RF_CLK_FREQ (19200000)
-#define NTF_TIMEOUT (10000)
+#define NTF_TIMEOUT (10)
#define CORE_RESET_RSP_GID (0x60)
#define CORE_RESET_OID (0x00)
#define CORE_RST_NTF_LENGTH (0x02)
+#define WAKE_TIMEOUT (10)
static void clk_req_update(struct work_struct *work);
@@ -334,11 +335,11 @@
/* Read the header */
ret = i2c_master_recv(qca199x_dev->client, len, PAYLOAD_HEADER_LENGTH);
/*
- We ignore all packets of length PAYLOAD_HEADER_LENGTH
- or less (i.e <=3). In this case return a total length
- of ZERO. So ALL PACKETS MUST HAVE A PAYLOAD.
- If ret < 0 then this is an error code.
- */
+ * We ignore all packets of length PAYLOAD_HEADER_LENGTH
+ * or less (i.e <=3). In this case return a total length
+ * of ZERO. So ALL PACKETS MUST HAVE A PAYLOAD.
+ * If ret < 0 then this is an error code.
+ */
if (ret != PAYLOAD_HEADER_LENGTH) {
if (ret < 0)
total = ret;
@@ -362,6 +363,8 @@
goto err;
}
+ dev_dbg(&qca199x_dev->client->dev, "%s : NfcNciRx %x %x %x\n",
+ __func__, tmp[0], tmp[1], tmp[2]);
if (total > 0) {
if ((total > count) || copy_to_user(buf, tmp, total)) {
dev_err(&qca199x_dev->client->dev,
@@ -377,14 +380,14 @@
}
/*
- Local routine to read from nfcc buffer. This is called to clear any
- pending receive messages in the nfcc's read buffer, which may be there
- following a POR. In this way, the upper layers (Device Transport) will
- associate the next rsp/ntf nci message with the next nci command to the
- nfcc. Otherwise, the DT may interpret a ntf from the nfcc as being from
- the nci core reset command when in fact it was already present in the
- nfcc read buffer following a POR.
-*/
+ * Local routine to read from nfcc buffer. This is called to clear any
+ * pending receive messages in the nfcc's read buffer, which may be there
+ * following a POR. In this way, the upper layers (Device Transport) will
+ * associate the next rsp/ntf nci message with the next nci command to the
+ * nfcc. Otherwise, the DT may interpret a ntf from the nfcc as being from
+ * the nci core reset command when in fact it was already present in the
+ * nfcc read buffer following a POR.
+ */
int nfcc_read_buff_svc(struct qca199x_dev *qca199x_dev)
{
@@ -416,6 +419,8 @@
PAYLOAD_HEADER_LENGTH));
total = ret;
}
+ dev_dbg(&qca199x_dev->client->dev, "%s : NfcNciRx %x %x %x\n",
+ __func__, tmp[0], tmp[1], tmp[2]);
leave:
mutex_unlock(&qca199x_dev->read_mutex);
return total;
@@ -440,11 +445,11 @@
return -EFAULT;
}
/*
- A catch for when the DT is sending the initial NCI write
- following a hardware POR. In this case we should clear any
- pending messages in nfcc buffer and open the interrupt gate
- for new messages coming from the nfcc.
- */
+ * A catch for when the DT is sending the initial NCI write
+ * following a hardware POR. In this case we should clear any
+ * pending messages in nfcc buffer and open the interrupt gate
+ * for new messages coming from the nfcc.
+ */
if ((qca199x_dev->sent_first_nci_write == false) &&
(qca199x_dev->irq_enabled == false)) {
/* check rsp/ntf from nfcc read-side buffer */
@@ -500,7 +505,8 @@
(tmp[3] == 0x08) && (tmp[4] == 0x00)) {
region2_sent = true;
}
-
+ dev_dbg(&qca199x_dev->client->dev, "%s : NfcNciTx %x %x %x\n",
+ __func__, tmp[0], tmp[1], tmp[2]);
return ret;
}
@@ -594,47 +600,39 @@
r = qca199x_clock_select(qca199x_dev);
if (r < 0)
goto err_req;
+ dev_dbg(&qca199x_dev->client->dev, "gpio_set_value disable: %s: info: %p\n",
+ __func__, qca199x_dev);
gpio_set_value(qca199x_dev->dis_gpio, 0);
- r = gpio_direction_output(qca199x_dev->dis_gpio, 1);
- if (r) {
- dev_err(&qca199x_dev->client->dev,
- "unable to set direction for gpio [%d]\n",
- qca199x_dev->dis_gpio);
- goto err_req;
- }
- gpio_set_value(qca199x_dev->dis_gpio, 0);
- msleep(20);
+ usleep(1000);
} else if (arg == 1) {
/*
- We are attempting a hardware reset so let us disable
- interrupts to avoid spurious notifications to upper
- layers.
- */
+ * We are attempting a hardware reset so let us disable
+ * interrupts to avoid spurious notifications to upper
+ * layers.
+ */
qca199x_disable_irq(qca199x_dev);
/* Deselection of clock */
r = qca199x_clock_deselect(qca199x_dev);
if (r < 0)
goto err_req;
/*
- Also, set flag for initial NCI write following reset as
- may wish to do some house keeping. Ensure no pending
- messages in NFCC buffers which may be wrongly
- construed as response to initial message
- */
+ * Also, set flag for initial NCI write following resetas
+ * may wish to do some house keeping. Ensure no pending
+ * messages in NFCC buffers which may be wrongly
+ * construed as response to initial message
+ */
qca199x_dev->sent_first_nci_write = false;
- gpio_set_value(qca199x_dev->dis_gpio, 0);
- r = gpio_direction_output(qca199x_dev->dis_gpio, 1);
- if (r) {
- dev_err(&qca199x_dev->client->dev,
- "unable to set direction for gpio [%d]\n",
- qca199x_dev->dis_gpio);
- goto err_req;
- }
+ dev_dbg(&qca199x_dev->client->dev, "gpio_set_value enable: %s: info: %p\n",
+ __func__, qca199x_dev);
gpio_set_value(qca199x_dev->dis_gpio, 1);
usleep(1000);
} else if (arg == 2) {
mutex_lock(&qca199x_dev->read_mutex);
+ dev_dbg(&qca199x_dev->client->dev, "before nfcc_initialise: %s: info: %p\n",
+ __func__, qca199x_dev);
r = nfcc_initialise(qca199x_dev->client, 0xE);
+ dev_dbg(&qca199x_dev->client->dev, "after nfcc_initialise: %s: info: %p\n",
+ __func__, qca199x_dev);
/* Also reset first NCI write */
qca199x_dev->sent_first_nci_write = false;
mutex_unlock(&qca199x_dev->read_mutex);
@@ -648,6 +646,8 @@
} else if (arg == 4) {
mutex_lock(&qca199x_dev->read_mutex);
nfcc_wake(NFCC_WAKE, filp);
+ dev_dbg(&qca199x_dev->client->dev, "nfcc wake: %s: info: %p\n",
+ __func__, qca199x_dev);
mutex_unlock(&qca199x_dev->read_mutex);
} else if (arg == 5) {
nfcc_wake(NFCC_SLEEP, filp);
@@ -726,9 +726,11 @@
unsigned long arg)
{
int r = 0;
+ int time_taken = 0;
unsigned short slave_addr = 0xE;
unsigned short curr_addr;
unsigned char raw_nci_wake[] = {0x10, 0x0F};
+ unsigned char raw_nci_read;
unsigned char raw_chip_version_addr = 0x00;
unsigned char raw_chip_rev_id_addr = 0x9C;
unsigned char raw_chip_version = 0xFF;
@@ -746,39 +748,75 @@
qca199x_dev->client->addr = slave_addr;
r = nfc_i2c_write(qca199x_dev->client, &raw_nci_wake[0],
sizeof(raw_nci_wake));
- r = sizeof(raw_nci_wake);
- if (r != sizeof(raw_nci_wake))
- goto invalid_wake_up;
- qca199x_dev->state = NFCC_STATE_NORMAL_WAKE;
- /* sleep to ensure the NFCC has time to wake up */
- usleep(100);
+ if (r != sizeof(raw_nci_wake))
+ dev_err(&qca199x_dev->client->dev,
+ "nfc_ioctl_nfcc_version : failed to send wake command\n");
+
+ /*
+ * After placing the NFCC to sleep by a PROP
+ * SLEEP NCI msg (2F 03) and we need to wake
+ * it back up to obtain some information (by
+ * setting the wake bit).We need to determine
+ * when it has in actual fact woken before we
+ * can read the required data. We do that by
+ * reading back & testing if that wake bit has
+ * been cleared.
+ */
+ do {
+ r = i2c_master_recv(qca199x_dev->client, &raw_nci_read,
+ sizeof(raw_nci_read));
+ if ((raw_nci_read & NCI_WAKE) != 0)
+ usleep(1000);
+
+ time_taken++;
+ } while ((r == 1) && (raw_nci_read & NCI_WAKE)
+ && (time_taken < WAKE_TIMEOUT));
+
+ if (time_taken < WAKE_TIMEOUT)
+ qca199x_dev->state = NFCC_STATE_NORMAL_WAKE;
+ else
+ dev_err(&qca199x_dev->client->dev,
+ "nfc_ioctl_nfcc_version : TIMED OUT to get WAKEUP bit\n");
+
+
+ if (r != 1) {
+ /*
+ * r < 0 indicates an error, maybe chip isn't
+ * up yet.What should we do??? r = 0 indicates
+ * nothing read, maybe chip isn't up yet. (should
+ * not happen) r > 1 indicates too many bytes read,
+ * maybe ?(should not happen)
+ */
+ dev_err(&qca199x_dev->client->dev,
+ "nfc_ioctl_nfcc_version : i2c error %d\n", r);
+ }
+
if (arg == 0) {
r = nfc_i2c_write(qca199x_dev->client,
&raw_chip_version_addr, 1);
- if (r < 0)
- goto invalid_wr;
- usleep(10);
- r = i2c_master_recv(qca199x_dev->client, &raw_chip_version, 1);
- /* Restore original NFCC slave I2C address */
- qca199x_dev->client->addr = curr_addr;
} else if (arg == 1) {
r = nfc_i2c_write(qca199x_dev->client,
&raw_chip_rev_id_addr, 1);
- if (r < 0)
- goto invalid_wr;
- usleep(20);
- r = i2c_master_recv(qca199x_dev->client, &raw_chip_version, 1);
+ } else {
/* Restore original NFCC slave I2C address */
qca199x_dev->client->addr = curr_addr;
+ return -EINVAL;
}
- return raw_chip_version;
-invalid_wake_up:
- raw_chip_version = 0xFE;
-invalid_wr:
- raw_chip_version = 0xFF;
- dev_err(&qca199x_dev->client->dev,
- "\nNFCC_INVALID_CHIP_VERSION = %d\n", raw_chip_version);
+
+ if (r < 0) {
+ /* Restore original NFCC slave I2C address */
+ qca199x_dev->client->addr = curr_addr;
+ dev_err(&qca199x_dev->client->dev,
+ "NFCC_INVALID_CHIP_VERSION : i2c write fail\n");
+ return -EIO;
+ }
+
+ usleep(10);
+ r = i2c_master_recv(qca199x_dev->client, &raw_chip_version, 1);
+
+ /* Restore original NFCC slave I2C address */
+ qca199x_dev->client->addr = curr_addr;
return raw_chip_version;
}
@@ -1042,11 +1080,11 @@
client->addr = NCI_I2C_SLAVE;
/*
- Start with small delay and then we will poll until we
- get a core reset notification - This is time for chip
- & NFCC controller to come-up.
- */
- usleep(1000); /* 1 ms */
+ * Start with small delay and then we will poll until we
+ * get a core reset notification - This is time for chip
+ * & NFCC controller to come-up.
+ */
+ usleep(15000); /* 15 ms */
do {
ret = i2c_master_recv(client, rsp, 5);
@@ -1055,9 +1093,13 @@
(rsp[1] == CORE_RESET_OID) &&
(rsp[2] == CORE_RST_NTF_LENGTH))
|| time_taken == NTF_TIMEOUT) {
+ dev_dbg(&client->dev,
+ "NFC core reset recevd: %s: info: %p\n",
+ __func__, client);
core_reset_completed = true;
+ } else {
+ usleep(2000); /* 2ms sleep before retry */
}
- usleep(10); /* 10us sleep before retry */
time_taken++;
} while (!core_reset_completed);
r = 0;
@@ -1415,9 +1457,10 @@
}
logging_level = 0;
- /* request irq. The irq is set whenever the chip has data available
- * for reading. It is cleared when all data has been read.
- */
+ /*
+ * request irq. The irq is set whenever the chip has data available
+ * for reading. It is cleared when all data has been read.
+ */
device_mode.handle_flavour = UNSOLICITED_MODE;
/* NFC_INT IRQ */
qca199x_dev->irq_enabled = true;
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 94d48e6..7963ed4 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -2465,11 +2465,6 @@
int rc;
u8 chgr_sts, bat_if_sts;
- if ((qpnp_chg_is_usb_chg_plugged_in(chip) ||
- qpnp_chg_is_dc_chg_plugged_in(chip)) && chip->chg_done) {
- return POWER_SUPPLY_STATUS_FULL;
- }
-
rc = qpnp_chg_read(chip, &chgr_sts, INT_RT_STS(chip->chgr_base), 1);
if (rc) {
pr_err("failed to read interrupt sts %d\n", rc);
@@ -2487,10 +2482,14 @@
if (chgr_sts & FAST_CHG_ON_IRQ && bat_if_sts & BAT_FET_ON_IRQ)
return POWER_SUPPLY_STATUS_CHARGING;
- /* report full if state of charge is 100 and a charger is connected */
+ /*
+ * Report full if state of charge is 100 or chg_done is true
+ * when a charger is connected and boost is disabled
+ */
if ((qpnp_chg_is_usb_chg_plugged_in(chip) ||
- qpnp_chg_is_dc_chg_plugged_in(chip))
- && get_batt_capacity(chip) == 100) {
+ qpnp_chg_is_dc_chg_plugged_in(chip)) &&
+ (chip->chg_done || get_batt_capacity(chip) == 100)
+ && qpnp_chg_is_boost_en_set(chip) == 0) {
return POWER_SUPPLY_STATUS_FULL;
}
@@ -3242,10 +3241,10 @@
qpnp_chg_regulator_boost_enable(struct regulator_dev *rdev)
{
struct qpnp_chg_chip *chip = rdev_get_drvdata(rdev);
+ int usb_present = qpnp_chg_is_usb_chg_plugged_in(chip);
int rc;
- if (qpnp_chg_is_usb_chg_plugged_in(chip) &&
- (chip->flags & BOOST_FLASH_WA)) {
+ if (usb_present && (chip->flags & BOOST_FLASH_WA)) {
if (ext_ovp_isns_present && chip->ext_ovp_ic_gpio_enabled) {
pr_debug("EXT OVP IC ISNS disabled\n");
@@ -3273,10 +3272,24 @@
}
}
- return qpnp_chg_masked_write(chip,
+ rc = qpnp_chg_masked_write(chip,
chip->boost_base + BOOST_ENABLE_CONTROL,
BOOST_PWR_EN,
BOOST_PWR_EN, 1);
+ if (rc) {
+ pr_err("failed to enable boost rc = %d\n", rc);
+ return rc;
+ }
+ /*
+ * update battery status when charger is connected and state is full
+ */
+ if (usb_present && (chip->chg_done
+ || (get_batt_capacity(chip) == 100)
+ || (get_prop_batt_status(chip) ==
+ POWER_SUPPLY_STATUS_FULL)))
+ power_supply_changed(&chip->batt_psy);
+
+ return rc;
}
/* Boost regulator operations */
@@ -3369,6 +3382,20 @@
qpnp_chg_usb_suspend_enable(chip, 0);
}
+ /*
+ * When a charger is connected,if state of charge is not full
+ * resumeing charging else update battery status
+ */
+ if (qpnp_chg_is_usb_chg_plugged_in(chip)) {
+ if (get_batt_capacity(chip) < 100 || !chip->chg_done) {
+ chip->chg_done = false;
+ chip->resuming_charging = true;
+ qpnp_chg_set_appropriate_vbatdet(chip);
+ } else if (chip->chg_done) {
+ power_supply_changed(&chip->batt_psy);
+ }
+ }
+
if (ext_ovp_isns_present && chip->ext_ovp_ic_gpio_enabled) {
pr_debug("EXT OVP IC ISNS enable\n");
gpio_direction_output(chip->ext_ovp_isns_gpio, 1);
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 8eb5573..54c46c8 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -1998,8 +1998,11 @@
if (tty->ops->flush_chars)
tty->ops->flush_chars(tty);
} else {
+
while (nr > 0) {
+ mutex_lock(&tty->output_lock);
c = tty->ops->write(tty, b, nr);
+ mutex_unlock(&tty->output_lock);
if (c < 0) {
retval = c;
goto break_out;
diff --git a/drivers/usb/class/ccid_bridge.c b/drivers/usb/class/ccid_bridge.c
index a914902..7d2f1c3 100644
--- a/drivers/usb/class/ccid_bridge.c
+++ b/drivers/usb/class/ccid_bridge.c
@@ -21,6 +21,8 @@
#include <linux/usb.h>
#include <linux/wait.h>
#include <linux/cdev.h>
+#include <linux/ktime.h>
+#include <linux/debugfs.h>
#include <linux/usb/ccid_bridge.h>
@@ -71,6 +73,14 @@
struct cdev cdev;
struct class *class;
struct device *device;
+
+ struct dentry *dbg_root;
+ unsigned n_write;
+ unsigned n_read;
+ unsigned n_write_timeout;
+ unsigned n_read_timeout;
+ unsigned long write_max_time;
+ unsigned long read_max_time;
};
static struct ccid_bridge *__ccid_bridge_dev;
@@ -260,6 +270,7 @@
struct ccid_bridge *ccid = fp->private_data;
int ret;
char *kbuf;
+ ktime_t start_t, delta_t;
pr_debug("called with %d", count);
@@ -270,6 +281,9 @@
mutex_lock(&ccid->write_mutex);
+ ccid->n_write++;
+ start_t = ktime_get();
+
if (!count || count > CCID_BRIDGE_MSG_SZ) {
pr_err("invalid count");
ret = -EINVAL;
@@ -311,12 +325,20 @@
msecs_to_jiffies(ccid_bulk_msg_timeout));
if (!ret || ret == -ERESTARTSYS) { /* timedout or interrupted */
usb_kill_urb(ccid->writeurb);
- if (!ret)
+ if (!ret) {
+ ccid->n_write_timeout++;
ret = -ETIMEDOUT;
+ }
} else {
ret = ccid->write_result;
}
+ if (ret >= 0) {
+ delta_t = ktime_sub(ktime_get(), start_t);
+ if (ktime_to_ms(delta_t) > ccid->write_max_time)
+ ccid->write_max_time = ktime_to_ms(delta_t);
+ }
+
pr_debug("returning %d", ret);
put_pm:
@@ -336,6 +358,7 @@
struct ccid_bridge *ccid = fp->private_data;
int ret;
char *kbuf;
+ ktime_t start_t, delta_t;
pr_debug("called with %d", count);
if (!ccid->intf) {
@@ -345,6 +368,9 @@
mutex_lock(&ccid->read_mutex);
+ ccid->n_read++;
+ start_t = ktime_get();
+
if (!count || count > CCID_BRIDGE_MSG_SZ) {
pr_err("invalid count");
ret = -EINVAL;
@@ -376,22 +402,26 @@
goto free_kbuf;
}
-
ret = wait_event_interruptible_timeout(ccid->read_wq,
ccid->read_result != 0,
msecs_to_jiffies(ccid_bulk_msg_timeout));
if (!ret || ret == -ERESTARTSYS) { /* timedout or interrupted */
usb_kill_urb(ccid->readurb);
- if (!ret)
+ if (!ret) {
+ ccid->n_read_timeout++;
ret = -ETIMEDOUT;
+ }
} else {
ret = ccid->read_result;
}
-
if (ret > 0) {
if (copy_to_user(ubuf, kbuf, ret))
ret = -EFAULT;
+
+ delta_t = ktime_sub(ktime_get(), start_t);
+ if (ktime_to_ms(delta_t) > ccid->read_max_time)
+ ccid->read_max_time = ktime_to_ms(delta_t);
}
usb_autopm_put_interface(ccid->intf);
@@ -537,12 +567,30 @@
return ret;
}
+static void ccid_bridge_reset_stats(struct ccid_bridge *ccid)
+{
+ ccid->n_write = 0;
+ ccid->n_read = 0;
+ ccid->n_write_timeout = 0;
+ ccid->n_read_timeout = 0;
+ ccid->write_max_time = 0;
+ ccid->read_max_time = 0;
+}
+
static int ccid_bridge_release(struct inode *ip, struct file *fp)
{
struct ccid_bridge *ccid = fp->private_data;
pr_debug("called");
+ mutex_lock(&ccid->open_mutex);
+ if (ccid->intf == NULL) {
+ ccid->opened = false;
+ mutex_unlock(&ccid->open_mutex);
+ goto done;
+ }
+ mutex_unlock(&ccid->open_mutex);
+
usb_kill_urb(ccid->writeurb);
usb_kill_urb(ccid->readurb);
if (ccid->int_pipe)
@@ -554,6 +602,8 @@
mutex_lock(&ccid->open_mutex);
ccid->opened = false;
mutex_unlock(&ccid->open_mutex);
+done:
+ ccid_bridge_reset_stats(ccid);
return 0;
}
@@ -783,6 +833,80 @@
.supports_autosuspend = 1,
};
+static int ccid_bridge_stats_show(struct seq_file *s, void *unused)
+{
+ struct ccid_bridge *ccid = s->private;
+
+ seq_printf(s, "ccid_bridge: %s\n",
+ ccid->intf ? "connected" : "disconnected");
+ seq_printf(s, "ccid_bridge: %s\n",
+ ccid->opened ? "opened" : "closed");
+
+ seq_printf(s, "total writes: %u\n", ccid->n_write);
+ seq_printf(s, "total reads: %u\n", ccid->n_write);
+
+ seq_printf(s, "write/read timeout val: %u\n", ccid_bulk_msg_timeout);
+
+ seq_printf(s, "write_timeout: %u\n", ccid->n_write_timeout);
+ seq_printf(s, "read_timeout: %u\n", ccid->n_read_timeout);
+
+ seq_printf(s, "write_max_time (msec): %lu\n", ccid->write_max_time);
+ seq_printf(s, "read_max_time: (msec): %lu\n", ccid->read_max_time);
+
+ return 0;
+}
+
+static int ccid_bridge_stats_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ccid_bridge_stats_show, inode->i_private);
+}
+
+static ssize_t ccid_bridge_stats_write(struct file *file,
+ const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct seq_file *s = file->private_data;
+ struct ccid_bridge *ccid = s->private;
+
+ ccid_bridge_reset_stats(ccid);
+ return count;
+}
+
+const struct file_operations ccid_bridge_stats_ops = {
+ .open = ccid_bridge_stats_open,
+ .read = seq_read,
+ .write = ccid_bridge_stats_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int ccid_bridge_debugfs_init(struct ccid_bridge *ccid)
+{
+ struct dentry *dir;
+ int ret = 0;
+
+ dir = debugfs_create_dir("ccid_bridge", NULL);
+
+ if (!dir || IS_ERR(dir)) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ ccid->dbg_root = dir;
+
+ dir = debugfs_create_file("stats", 0644, ccid->dbg_root, ccid,
+ &ccid_bridge_stats_ops);
+
+ if (!dir) {
+ debugfs_remove_recursive(ccid->dbg_root);
+ ccid->dbg_root = NULL;
+ ret = -ENODEV;
+ }
+
+out:
+ return ret;
+}
+
static int __init ccid_bridge_init(void)
{
int ret;
@@ -840,6 +964,8 @@
goto del_cdev;
}
+ ccid_bridge_debugfs_init(ccid);
+
pr_info("success");
return 0;
@@ -868,6 +994,8 @@
struct ccid_bridge *ccid = __ccid_bridge_dev;
pr_debug("called");
+
+ debugfs_remove_recursive(ccid->dbg_root);
device_destroy(ccid->class, ccid->chrdev);
cdev_del(&ccid->cdev);
class_destroy(ccid->class);
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 4be032a..0f86879 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2113,6 +2113,8 @@
break;
} while (1);
+ dwc->gadget.xfer_isr_count++;
+
if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
list_empty(&dep->req_queued)) {
if (list_empty(&dep->request_list))
@@ -2276,6 +2278,7 @@
dwc->gadget_driver->disconnect(&dwc->gadget);
spin_lock(&dwc->lock);
}
+ dwc->gadget.xfer_isr_count = 0;
}
static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum)
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 30a678b..ad0e464 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -2295,6 +2295,7 @@
udc->configured = 0;
spin_unlock_irqrestore(udc->lock, flags);
+ gadget->xfer_isr_count = 0;
gadget->b_hnp_enable = 0;
gadget->a_hnp_support = 0;
gadget->host_request = 0;
@@ -3688,6 +3689,7 @@
isr_statistics.uei++;
if (USBi_UI & intr) {
isr_statistics.ui++;
+ udc->gadget.xfer_isr_count++;
isr_tr_complete_handler(udc);
}
if (USBi_SLI & intr) {
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index 05292f9..669fca9 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -235,15 +235,6 @@
sdev->use_rpm_auto = 1;
sdev->autosuspend_delay = us->sdev_autosuspend_delay;
}
-
- /*
- * This quirk enables sending consecutive TEST_UNIT_READY
- * commands in WRITE(10) command processing context. Increase
- * the timeout to 60 seconds.
- */
- if (us->fflags & US_FL_TUR_AFTER_WRITE)
- blk_queue_rq_timeout(sdev->request_queue, (60 * HZ));
-
} else {
/* Non-disk-type devices don't need to blacklist any pages
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index a710d9f..c70109e 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -859,42 +859,6 @@
srb->result = DID_ERROR << 16;
last_sector_hacks(us, srb);
-
- /*
- * TMC UICC cards expect 5 TEST_UNIT_READY commands after
- * writing some data. The card performs the flash related
- * house keeping operations after receiving these commands.
- * Send 5 TEST_UNIT_READY commands for every 8 WRITE_10
- * commands.
- */
- if (unlikely((us->fflags & US_FL_TUR_AFTER_WRITE) &&
- srb->cmnd[0] == WRITE_10)) {
- int i;
- int temp_result;
- struct scsi_eh_save ses;
- unsigned char cmd[] = {
- TEST_UNIT_READY, 0, 0, 0, 0, 0,
- };
-
- us->tur_count[srb->device->lun]++;
-
- if (++us->tur_count[srb->device->lun] == 8) {
-
- us->tur_count[srb->device->lun] = 0;
-
- scsi_eh_prep_cmnd(srb, &ses, cmd, 6, 0);
- for (i = 0; i < 5; i++) {
- temp_result = us->transport(us->srb, us);
- if (temp_result != USB_STOR_TRANSPORT_GOOD) {
- US_DEBUGP("TUR failed %d %d\n",
- i, temp_result);
- break;
- }
- }
- scsi_eh_restore_cmnd(srb, &ses);
- }
- }
-
return;
/* Error and abort processing: try to resynchronize with the device
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 901f6fb..856ad92 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -2018,12 +2018,6 @@
"Digital MP3 Audio Player",
USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ),
-/* Reported by Pavankumar Kondeti <pkondeti@codeaurora.org> */
-UNUSUAL_DEV(0x0925, 0x9011, 0x0100, 0x0100,
- "TMC",
- "USB DISK",
- USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_TUR_AFTER_WRITE),
-
/* Control/Bulk transport for all SubClass values */
USUAL_DEV(USB_SC_RBC, USB_PR_CB, USB_US_TYPE_STOR),
USUAL_DEV(USB_SC_8020, USB_PR_CB, USB_US_TYPE_STOR),
diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
index b079984..db75080 100644
--- a/drivers/usb/storage/usb.h
+++ b/drivers/usb/storage/usb.h
@@ -162,8 +162,6 @@
int use_last_sector_hacks;
int last_sector_retries;
int sdev_autosuspend_delay;
- /* consecutive TEST_UNIT_READY commands during write */
- int tur_count[16];
};
/* Convert between us_data and the corresponding Scsi_Host */
diff --git a/drivers/video/msm/mdss/dsi_host_v2.c b/drivers/video/msm/mdss/dsi_host_v2.c
index 99e1c21..454fd15 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.c
+++ b/drivers/video/msm/mdss/dsi_host_v2.c
@@ -578,15 +578,20 @@
pr_debug("msm_dsi_op_mode_config\n");
dsi_ctrl = MIPI_INP(ctrl_base + DSI_CTRL);
- /*If Video enabled, Keep Video and Cmd mode ON */
-
- dsi_ctrl &= ~0x06;
-
- if (mode == DSI_VIDEO_MODE)
- dsi_ctrl |= 0x02;
+ if (dsi_ctrl & DSI_VIDEO_MODE_EN)
+ dsi_ctrl &= ~(DSI_CMD_MODE_EN|DSI_EN);
else
- dsi_ctrl |= 0x04;
+ dsi_ctrl &= ~(DSI_CMD_MODE_EN|DSI_VIDEO_MODE_EN|DSI_EN);
+
+ if (mode == DSI_VIDEO_MODE) {
+ dsi_ctrl |= (DSI_VIDEO_MODE_EN|DSI_EN);
+ } else { /* command mode */
+ dsi_ctrl |= (DSI_CMD_MODE_EN|DSI_EN);
+ /*For Video mode panel, keep Video and Cmd mode ON */
+ if (pdata->panel_info.type == MIPI_VIDEO_PANEL)
+ dsi_ctrl |= DSI_VIDEO_MODE_EN;
+ }
pr_debug("%s: dsi_ctrl=%x\n", __func__, dsi_ctrl);
@@ -1070,13 +1075,15 @@
mutex_lock(&ctrl_pdata->mutex);
- ret = msm_dss_enable_vreg(
- ctrl_pdata->power_data.vreg_config,
- ctrl_pdata->power_data.num_vreg, 1);
- if (ret) {
- pr_err("%s: DSI power on failed\n", __func__);
- mutex_unlock(&ctrl_pdata->mutex);
- return ret;
+ if (!pdata->panel_info.dynamic_switch_pending) {
+ ret = msm_dss_enable_vreg(
+ ctrl_pdata->power_data.vreg_config,
+ ctrl_pdata->power_data.num_vreg, 1);
+ if (ret) {
+ pr_err("%s: DSI power on failed\n", __func__);
+ mutex_unlock(&ctrl_pdata->mutex);
+ return ret;
+ }
}
msm_dsi_ahb_ctrl(1);
@@ -1194,11 +1201,13 @@
msm_dsi_phy_off(dsi_host_private->dsi_base);
msm_dsi_ahb_ctrl(0);
- ret = msm_dss_enable_vreg(
- ctrl_pdata->power_data.vreg_config,
- ctrl_pdata->power_data.num_vreg, 0);
- if (ret) {
- pr_err("%s: Panel power off failed\n", __func__);
+ if (!pdata->panel_info.dynamic_switch_pending) {
+ ret = msm_dss_enable_vreg(
+ ctrl_pdata->power_data.vreg_config,
+ ctrl_pdata->power_data.num_vreg, 0);
+ if (ret) {
+ pr_err("%s: Panel power off failed\n", __func__);
+ }
}
dsi_host_private->clk_count = 0;
dsi_host_private->dsi_on = 0;
diff --git a/drivers/video/msm/mdss/dsi_host_v2.h b/drivers/video/msm/mdss/dsi_host_v2.h
index 0f3ea8d..991a769 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.h
+++ b/drivers/video/msm/mdss/dsi_host_v2.h
@@ -171,4 +171,8 @@
#define DSI_DSIPHY_BIST_CTRL4 0x049C
#define DSI_DSIPHY_BIST_CTRL5 0x04A0
+#define DSI_EN BIT(0)
+#define DSI_VIDEO_MODE_EN BIT(1)
+#define DSI_CMD_MODE_EN BIT(2)
+
#endif /* DSI_HOST_V2_H */
diff --git a/drivers/video/msm/mdss/dsi_v2.c b/drivers/video/msm/mdss/dsi_v2.c
index bc76fd0..4fc3909 100644
--- a/drivers/video/msm/mdss/dsi_v2.c
+++ b/drivers/video/msm/mdss/dsi_v2.c
@@ -52,6 +52,37 @@
return rc;
}
+static int dsi_update_pconfig(struct mdss_panel_data *pdata,
+ int mode)
+{
+ int ret = 0;
+ struct mdss_panel_info *pinfo = &pdata->panel_info;
+ struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+ if (!pdata)
+ return -ENODEV;
+ ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+ panel_data);
+
+ if (mode == DSI_CMD_MODE) {
+ pinfo->mipi.mode = DSI_CMD_MODE;
+ pinfo->type = MIPI_CMD_PANEL;
+ pinfo->mipi.vsync_enable = 1;
+ pinfo->mipi.hw_vsync_mode = 1;
+ } else {
+ pinfo->mipi.mode = DSI_VIDEO_MODE;
+ pinfo->type = MIPI_VIDEO_PANEL;
+ pinfo->mipi.vsync_enable = 0;
+ pinfo->mipi.hw_vsync_mode = 0;
+ }
+
+ ctrl_pdata->panel_mode = pinfo->mipi.mode;
+ mdss_panel_get_dst_fmt(pinfo->bpp, pinfo->mipi.mode,
+ pinfo->mipi.pixel_packing, &(pinfo->mipi.dst_format));
+ pinfo->cont_splash_enabled = 0;
+
+ return ret;
+}
+
static int dsi_panel_handler(struct mdss_panel_data *pdata, int enable)
{
int rc = 0;
@@ -64,19 +95,47 @@
panel_data);
if (enable) {
- dsi_ctrl_gpio_request(ctrl_pdata);
- mdss_dsi_panel_reset(pdata, 1);
+ if (!pdata->panel_info.dynamic_switch_pending) {
+ if (pdata->panel_info.type == MIPI_CMD_PANEL)
+ dsi_ctrl_gpio_request(ctrl_pdata);
+ mdss_dsi_panel_reset(pdata, 1);
+ }
pdata->panel_info.panel_power_on = 1;
- rc = ctrl_pdata->on(pdata);
- if (rc)
- pr_err("dsi_panel_handler panel on failed %d\n", rc);
+ if (!pdata->panel_info.dynamic_switch_pending) {
+ rc = ctrl_pdata->on(pdata);
+ if (rc)
+ pr_err("%s: panel on failed!\n", __func__);
+ }
+ if (pdata->panel_info.type == MIPI_CMD_PANEL &&
+ pdata->panel_info.dynamic_switch_pending) {
+ dsi_ctrl_gpio_request(ctrl_pdata);
+ mdss_dsi_set_tear_on(ctrl_pdata);
+ }
} else {
+ msm_dsi_sw_reset();
if (dsi_intf.op_mode_config)
dsi_intf.op_mode_config(DSI_CMD_MODE, pdata);
- rc = ctrl_pdata->off(pdata);
+ if (pdata->panel_info.dynamic_switch_pending) {
+ pr_info("%s: switching to %s mode\n", __func__,
+ (pdata->panel_info.mipi.mode ? "video" : "command"));
+ if (pdata->panel_info.type == MIPI_CMD_PANEL) {
+ ctrl_pdata->switch_mode(pdata, DSI_VIDEO_MODE);
+ dsi_ctrl_gpio_free(ctrl_pdata);
+ } else if (pdata->panel_info.type == MIPI_VIDEO_PANEL) {
+ ctrl_pdata->switch_mode(pdata, DSI_CMD_MODE);
+ dsi_ctrl_gpio_request(ctrl_pdata);
+ mdss_dsi_set_tear_off(ctrl_pdata);
+ dsi_ctrl_gpio_free(ctrl_pdata);
+ }
+ }
+ if (!pdata->panel_info.dynamic_switch_pending)
+ rc = ctrl_pdata->off(pdata);
pdata->panel_info.panel_power_on = 0;
- mdss_dsi_panel_reset(pdata, 0);
- dsi_ctrl_gpio_free(ctrl_pdata);
+ if (!pdata->panel_info.dynamic_switch_pending) {
+ if (pdata->panel_info.type == MIPI_CMD_PANEL)
+ dsi_ctrl_gpio_free(ctrl_pdata);
+ mdss_dsi_panel_reset(pdata, 0);
+ }
}
return rc;
}
@@ -138,6 +197,9 @@
case MDSS_EVENT_PANEL_CLK_CTRL:
rc = dsi_clk_ctrl(pdata, (int)arg);
break;
+ case MDSS_EVENT_DSI_DYNAMIC_SWITCH:
+ rc = dsi_update_pconfig(pdata, (int)(unsigned long) arg);
+ break;
default:
pr_debug("%s: unhandled event=%d\n", __func__, event);
break;
@@ -158,7 +220,8 @@
__func__, __LINE__);
ctrl_pdata->disp_te_gpio = -1;
- if (ctrl_pdata->panel_data.panel_info.mipi.mode == DSI_CMD_MODE) {
+ if (ctrl_pdata->panel_data.panel_info.mipi.mode == DSI_CMD_MODE ||
+ ctrl_pdata->panel_data.panel_info.mipi.dynamic_switch_enabled) {
ctrl_pdata->disp_te_gpio = of_get_named_gpio(np,
"qcom,platform-te-gpio", 0);
if (!gpio_is_valid(ctrl_pdata->disp_te_gpio))
@@ -233,7 +296,7 @@
if (!dev || !mp) {
pr_err("%s: invalid input\n", __func__);
rc = -EINVAL;
- goto error;
+ return rc;
}
np = dev->of_node;
diff --git a/drivers/video/msm/mdss/dsi_v2.h b/drivers/video/msm/mdss/dsi_v2.h
index b8c91da..1474570 100644
--- a/drivers/video/msm/mdss/dsi_v2.h
+++ b/drivers/video/msm/mdss/dsi_v2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -56,4 +56,5 @@
int mdp3_panel_get_boot_cfg(void);
+void msm_dsi_sw_reset(void);
#endif /* DSI_V2_H */
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index 37134b4..d4d913f 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -2373,7 +2373,7 @@
if (!mdp3_res || !mdp3_res->pan_cfg.init_done)
rc = -EPROBE_DEFER;
- if (mdp3_res->pan_cfg.lk_cfg)
+ else if (mdp3_res->pan_cfg.lk_cfg)
rc = 1;
else
rc = 0;
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index 8acb9b0..cd0af6d 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -49,7 +49,7 @@
if (!count)
return;
- while (count--) {
+ while (count-- && (bufq->pop_idx >= 0)) {
struct mdp3_img_data *data = &bufq->img_data[bufq->pop_idx];
bufq->pop_idx = (bufq->pop_idx + 1) % MDP3_MAX_BUF_QUEUE;
mdp3_put_img(data, MDP3_CLIENT_DMA_P);
@@ -672,16 +672,16 @@
mdp3_histogram_stop(mdp3_session, MDP_BLOCK_DMA_P);
- rc = mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf);
- if (rc)
- pr_debug("fail to stop the MDP3 dma\n");
-
-
if (panel->event_handler)
rc = panel->event_handler(panel, MDSS_EVENT_PANEL_OFF, NULL);
if (rc)
pr_err("fail to turn off the panel\n");
+ rc = mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf);
+ if (rc)
+ pr_debug("fail to stop the MDP3 dma\n");
+ msleep(20);
+
mdp3_irq_deregister();
pr_debug("mdp3_ctrl_off stop clock\n");
@@ -708,10 +708,12 @@
mdp3_session->in_splash_screen = 0;
off_error:
mdp3_session->status = 0;
- mdp3_bufq_deinit(&mdp3_session->bufq_out);
- if (mdp3_session->overlay.id != MSMFB_NEW_REQUEST) {
- mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
- mdp3_bufq_deinit(&mdp3_session->bufq_in);
+ if (!panel->panel_info.dynamic_switch_pending) {
+ mdp3_bufq_deinit(&mdp3_session->bufq_out);
+ if (mdp3_session->overlay.id != MSMFB_NEW_REQUEST) {
+ mdp3_session->overlay.id = MSMFB_NEW_REQUEST;
+ mdp3_bufq_deinit(&mdp3_session->bufq_in);
+ }
}
mutex_unlock(&mdp3_session->lock);
return 0;
@@ -984,7 +986,7 @@
{
struct mdp3_session_data *mdp3_session;
struct mdp3_img_data *data;
- struct mdss_panel_info *panel_info = mfd->panel_info;
+ struct mdss_panel_info *panel_info;
int rc = 0;
bool reset_done = false;
struct mdss_panel_data *panel;
@@ -992,6 +994,7 @@
if (!mfd || !mfd->mdp.private1)
return -EINVAL;
+ panel_info = mfd->panel_info;
mdp3_session = mfd->mdp.private1;
if (!mdp3_session || !mdp3_session->dma)
return -EINVAL;
@@ -1048,7 +1051,8 @@
if (mdp3_bufq_count(&mdp3_session->bufq_out) > 1) {
mdp3_release_splash_memory(mfd);
data = mdp3_bufq_pop(&mdp3_session->bufq_out);
- mdp3_put_img(data, MDP3_CLIENT_DMA_P);
+ if (data)
+ mdp3_put_img(data, MDP3_CLIENT_DMA_P);
}
if (mdp3_session->first_commit) {
@@ -1074,13 +1078,14 @@
struct mdp3_session_data *mdp3_session;
u32 offset;
int bpp;
- struct mdss_panel_info *panel_info = mfd->panel_info;
+ struct mdss_panel_info *panel_info;
int rc;
pr_debug("mdp3_ctrl_pan_display\n");
if (!mfd || !mfd->mdp.private1)
return;
+ panel_info = mfd->panel_info;
mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1;
if (!mdp3_session || !mdp3_session->dma)
return;
@@ -1775,6 +1780,48 @@
return rc;
}
+static int mdp3_update_panel_info(struct msm_fb_data_type *mfd, int mode)
+{
+ int ret = 0;
+ struct mdp3_session_data *mdp3_session;
+ struct mdss_panel_data *panel;
+ u32 intf_type = 0;
+
+ if (!mfd || !mfd->mdp.private1)
+ return -EINVAL;
+
+ mdp3_session = mfd->mdp.private1;
+ panel = mdp3_session->panel;
+
+ if (!panel->event_handler)
+ return 0;
+ ret = panel->event_handler(panel, MDSS_EVENT_DSI_DYNAMIC_SWITCH,
+ (void *)(unsigned long)mode);
+ if (ret)
+ pr_err("Dynamic switch to %s mode failed!\n",
+ mode ? "command" : "video");
+ if (mode == 1)
+ mfd->panel.type = MIPI_CMD_PANEL;
+ else
+ mfd->panel.type = MIPI_VIDEO_PANEL;
+
+ if (mfd->panel.type != MIPI_VIDEO_PANEL)
+ mdp3_session->wait_for_dma_done = mdp3_wait_for_dma_done;
+
+ intf_type = mdp3_ctrl_get_intf_type(mfd);
+ mdp3_session->intf->cfg.type = intf_type;
+ mdp3_session->intf->available = 1;
+ mdp3_session->intf->in_use = 1;
+ mdp3_res->intf[intf_type].in_use = 1;
+
+ mdp3_intf_init(mdp3_session->intf);
+
+ mdp3_session->dma->output_config.out_sel = intf_type;
+ mdp3_session->status = mdp3_session->intf->active;
+
+ return 0;
+}
+
int mdp3_ctrl_init(struct msm_fb_data_type *mfd)
{
struct device *dev = mfd->fbi->dev;
@@ -1797,6 +1844,7 @@
mdp3_interface->ioctl_handler = mdp3_ctrl_ioctl_handler;
mdp3_interface->kickoff_fnc = mdp3_ctrl_display_commit_kickoff;
mdp3_interface->lut_update = mdp3_ctrl_lut_update;
+ mdp3_interface->configure_panel = mdp3_update_panel_info;
mdp3_session = kmalloc(sizeof(struct mdp3_session_data), GFP_KERNEL);
if (!mdp3_session) {
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index 8fa04cd..99fd195 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -62,6 +62,9 @@
panel_data);
pr_debug("%s: enable=%d\n", __func__, enable);
+ if (pdata->panel_info.dynamic_switch_pending)
+ return 0;
+
if (enable) {
ret = msm_dss_enable_vreg(
ctrl_pdata->power_data.vreg_config,
@@ -128,7 +131,7 @@
if (!dev || !mp) {
pr_err("%s: invalid input\n", __func__);
rc = -EINVAL;
- goto error;
+ return rc;
}
of_node = dev->of_node;
@@ -594,6 +597,31 @@
return ret;
}
+static int mdss_dsi_update_panel_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata,
+ int mode)
+{
+ int ret = 0;
+ struct mdss_panel_info *pinfo = &(ctrl_pdata->panel_data.panel_info);
+
+ if (mode == DSI_CMD_MODE) {
+ pinfo->mipi.mode = DSI_CMD_MODE;
+ pinfo->type = MIPI_CMD_PANEL;
+ pinfo->mipi.vsync_enable = 1;
+ pinfo->mipi.hw_vsync_mode = 1;
+ } else { /*video mode*/
+ pinfo->mipi.mode = DSI_VIDEO_MODE;
+ pinfo->type = MIPI_VIDEO_PANEL;
+ pinfo->mipi.vsync_enable = 0;
+ pinfo->mipi.hw_vsync_mode = 0;
+ }
+
+ ctrl_pdata->panel_mode = pinfo->mipi.mode;
+ mdss_panel_get_dst_fmt(pinfo->bpp, pinfo->mipi.mode,
+ pinfo->mipi.pixel_packing, &(pinfo->mipi.dst_format));
+ pinfo->cont_splash_enabled = 0;
+
+ return ret;
+}
static int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl,
int enable)
{
@@ -727,11 +755,13 @@
mipi = &pdata->panel_info.mipi;
if (!(ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT)) {
- ret = ctrl_pdata->on(pdata);
- if (ret) {
- pr_err("%s: unable to initialize the panel\n",
+ if (!pdata->panel_info.dynamic_switch_pending) {
+ ret = ctrl_pdata->on(pdata);
+ if (ret) {
+ pr_err("%s: unable to initialize the panel\n",
__func__);
- return ret;
+ return ret;
+ }
}
ctrl_pdata->ctrl_state |= CTRL_STATE_PANEL_INIT;
}
@@ -784,6 +814,17 @@
mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata);
+ if (pdata->panel_info.dynamic_switch_pending) {
+ pr_info("%s: switching to %s mode\n", __func__,
+ (pdata->panel_info.mipi.mode ? "video" : "command"));
+ if (pdata->panel_info.type == MIPI_CMD_PANEL) {
+ ctrl_pdata->switch_mode(pdata, DSI_VIDEO_MODE);
+ } else if (pdata->panel_info.type == MIPI_VIDEO_PANEL) {
+ ctrl_pdata->switch_mode(pdata, DSI_CMD_MODE);
+ mdss_dsi_set_tear_off(ctrl_pdata);
+ }
+ }
+
if (pdata->panel_info.type == MIPI_CMD_PANEL) {
if (mipi->vsync_enable && mipi->hw_vsync_mode
&& gpio_is_valid(ctrl_pdata->disp_te_gpio)) {
@@ -792,10 +833,12 @@
}
if (ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT) {
- ret = ctrl_pdata->off(pdata);
- if (ret) {
- pr_err("%s: Panel OFF failed\n", __func__);
- return ret;
+ if (!pdata->panel_info.dynamic_switch_pending) {
+ ret = ctrl_pdata->off(pdata);
+ if (ret) {
+ pr_err("%s: Panel OFF failed\n", __func__);
+ return ret;
+ }
}
ctrl_pdata->ctrl_state &= ~CTRL_STATE_PANEL_INIT;
}
@@ -1037,6 +1080,9 @@
case MDSS_EVENT_REGISTER_RECOVERY_HANDLER:
rc = mdss_dsi_register_recovery_handler(ctrl_pdata,
(struct mdss_panel_recovery *)arg);
+ case MDSS_EVENT_DSI_DYNAMIC_SWITCH:
+ rc = mdss_dsi_update_panel_config(ctrl_pdata,
+ (int)(unsigned long) arg);
break;
default:
pr_debug("%s: unhandled event=%d\n", __func__, event);
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index 5ab06e0..609b7ce 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -243,6 +243,7 @@
int (*partial_update_fnc) (struct mdss_panel_data *pdata);
int (*check_status) (struct mdss_dsi_ctrl_pdata *pdata);
int (*cmdlist_commit)(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
+ void (*switch_mode) (struct mdss_panel_data *pdata, int mode);
struct mdss_panel_data panel_data;
unsigned char *ctrl_base;
struct dss_io_data ctrl_io;
@@ -286,6 +287,9 @@
struct dsi_panel_cmds on_cmds;
struct dsi_panel_cmds off_cmds;
+ struct dsi_panel_cmds video2cmd;
+ struct dsi_panel_cmds cmd2video;
+
struct dcs_cmd_list cmdlist;
struct completion dma_comp;
struct completion mdp_comp;
@@ -364,6 +368,8 @@
int mdss_dsi_panel_init(struct device_node *node,
struct mdss_dsi_ctrl_pdata *ctrl_pdata,
bool cmd_cfg_cont_splash);
+int mdss_panel_get_dst_fmt(u32 bpp, char mipi_mode, u32 pixel_packing,
+ char *dst_format);
int mdss_dsi_register_recovery_handler(struct mdss_dsi_ctrl_pdata *ctrl,
struct mdss_panel_recovery *recovery);
diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index d8cd22e..d8a713e 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -1534,9 +1534,11 @@
(struct mdss_dsi_ctrl_pdata *)ptr;
struct mdss_dsi_ctrl_pdata *mctrl = NULL;
- if (!ctrl->ctrl_base)
+ if (!ctrl->ctrl_base) {
pr_err("%s:%d DSI base adr no Initialized",
- __func__, __LINE__);
+ __func__, __LINE__);
+ return IRQ_HANDLED;
+ }
isr = MIPI_INP(ctrl->ctrl_base + 0x0110);/* DSI_INTR_CTRL */
MIPI_OUTP(ctrl->ctrl_base + 0x0110, isr);
diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c
index 0e1cd66..4fa995f 100644
--- a/drivers/video/msm/mdss/mdss_dsi_panel.c
+++ b/drivers/video/msm/mdss/mdss_dsi_panel.c
@@ -317,6 +317,36 @@
return rc;
}
+static void mdss_dsi_panel_switch_mode(struct mdss_panel_data *pdata,
+ int mode)
+{
+ struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
+ struct mipi_panel_info *mipi;
+ struct dsi_panel_cmds *pcmds;
+
+ if (pdata == NULL) {
+ pr_err("%s: Invalid input data\n", __func__);
+ return;
+ }
+
+ mipi = &pdata->panel_info.mipi;
+
+ if (!mipi->dynamic_switch_enabled)
+ return;
+
+ ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
+ panel_data);
+
+ if (mode == DSI_CMD_MODE)
+ pcmds = &ctrl_pdata->video2cmd;
+ else
+ pcmds = &ctrl_pdata->cmd2video;
+
+ mdss_dsi_panel_cmds_send(ctrl_pdata, pcmds);
+
+ return;
+}
+
static void mdss_dsi_panel_bl_ctrl(struct mdss_panel_data *pdata,
u32 bl_level)
{
@@ -524,11 +554,16 @@
len -= dchdr->dlen;
}
- data = of_get_property(np, link_key, NULL);
- if (data && !strcmp(data, "dsi_hs_mode"))
- pcmds->link_state = DSI_HS_MODE;
- else
- pcmds->link_state = DSI_LP_MODE;
+ /*Set default link state to LP Mode*/
+ pcmds->link_state = DSI_LP_MODE;
+
+ if (link_key) {
+ data = of_get_property(np, link_key, NULL);
+ if (data && !strcmp(data, "dsi_hs_mode"))
+ pcmds->link_state = DSI_HS_MODE;
+ else
+ pcmds->link_state = DSI_LP_MODE;
+ }
pr_debug("%s: dcs_cmd=%x len=%d, cmd_cnt=%d link_state=%d\n", __func__,
pcmds->buf[0], pcmds->blen, pcmds->cmd_cnt, pcmds->link_state);
@@ -541,7 +576,7 @@
}
-static int mdss_panel_dt_get_dst_fmt(u32 bpp, char mipi_mode, u32 pixel_packing,
+int mdss_panel_get_dst_fmt(u32 bpp, char mipi_mode, u32 pixel_packing,
char *dst_format)
{
int rc = 0;
@@ -788,6 +823,25 @@
pr_info("%s: ulps feature %s", __func__,
(pinfo->ulps_feature_enabled ? "enabled" : "disabled"));
+ pinfo->mipi.dynamic_switch_enabled = of_property_read_bool(np,
+ "qcom,dynamic-mode-switch-enabled");
+
+ if (pinfo->mipi.dynamic_switch_enabled) {
+ mdss_dsi_parse_dcs_cmds(np, &ctrl->video2cmd,
+ "qcom,video-to-cmd-mode-switch-commands", NULL);
+
+ mdss_dsi_parse_dcs_cmds(np, &ctrl->cmd2video,
+ "qcom,cmd-to-video-mode-switch-commands", NULL);
+
+ if (!ctrl->video2cmd.cmd_cnt || !ctrl->cmd2video.cmd_cnt) {
+ pr_warn("No commands specified for dynamic switch\n");
+ pinfo->mipi.dynamic_switch_enabled = 0;
+ }
+ }
+
+ pr_info("%s: dynamic switch feature enabled: %d", __func__,
+ pinfo->mipi.dynamic_switch_enabled);
+
return 0;
}
@@ -845,9 +899,11 @@
tmp = 0;
data = of_get_property(np, "qcom,mdss-dsi-pixel-packing", NULL);
if (data && !strcmp(data, "loose"))
- tmp = 1;
- rc = mdss_panel_dt_get_dst_fmt(pinfo->bpp,
- pinfo->mipi.mode, tmp,
+ pinfo->mipi.pixel_packing = 1;
+ else
+ pinfo->mipi.pixel_packing = 0;
+ rc = mdss_panel_get_dst_fmt(pinfo->bpp,
+ pinfo->mipi.mode, pinfo->mipi.pixel_packing,
&(pinfo->mipi.dst_format));
if (rc) {
pr_debug("%s: problem determining dst format. Set Default\n",
@@ -868,13 +924,14 @@
else if (!strcmp(pdest, "display_2"))
pinfo->pdest = DISPLAY_2;
else {
- pr_debug("%s: pdest not specified. Set Default\n",
- __func__);
+ pr_debug("%s: incorrect pdest. Set Default\n",
+ __func__);
pinfo->pdest = DISPLAY_1;
}
} else {
- pr_err("%s: pdest not specified\n", __func__);
- return -EINVAL;
+ pr_debug("%s: pdest not specified. Set Default\n",
+ __func__);
+ pinfo->pdest = DISPLAY_1;
}
rc = of_property_read_u32(np, "qcom,mdss-dsi-h-front-porch", &tmp);
pinfo->lcdc.h_front_porch = (!rc ? tmp : 6);
@@ -1119,9 +1176,13 @@
pr_info("%s: Continuous splash %s", __func__,
pinfo->cont_splash_enabled ? "enabled" : "disabled");
+ pinfo->dynamic_switch_pending = false;
+ pinfo->is_lpm_mode = false;
+
ctrl_pdata->on = mdss_dsi_panel_on;
ctrl_pdata->off = mdss_dsi_panel_off;
ctrl_pdata->panel_data.set_backlight = mdss_dsi_panel_bl_ctrl;
+ ctrl_pdata->switch_mode = mdss_dsi_panel_switch_mode;
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index a66f4b6..84ee426 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -96,6 +96,7 @@
static int mdss_fb_pan_idle(struct msm_fb_data_type *mfd);
static int mdss_fb_send_panel_event(struct msm_fb_data_type *mfd,
int event, void *arg);
+static void mdss_fb_set_mdp_sync_pt_threshold(struct msm_fb_data_type *mfd);
void mdss_fb_no_update_notify_timer_cb(unsigned long data)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data;
@@ -393,6 +394,91 @@
return ret;
}
+/*
+ * mdss_fb_lpm_enable() - Function to Control LowPowerMode
+ * @mfd: Framebuffer data structure for display
+ * @mode: Enabled/Disable LowPowerMode
+ * 1: Enter into LowPowerMode
+ * 0: Exit from LowPowerMode
+ *
+ * This Function dynamically switches to and from LowPowerMode
+ * based on the argument @mode.
+ */
+static int mdss_fb_lpm_enable(struct msm_fb_data_type *mfd, int mode)
+{
+ int ret = 0;
+ u32 bl_lvl = 0;
+ struct mdss_panel_info *pinfo = NULL;
+ struct mdss_panel_data *pdata;
+
+ if (!mfd || !mfd->panel_info)
+ return -EINVAL;
+
+ pinfo = mfd->panel_info;
+
+ if (!pinfo->mipi.dynamic_switch_enabled) {
+ pr_warn("Panel does not support dynamic switch!\n");
+ return 0;
+ }
+
+ if (mode == pinfo->mipi.mode) {
+ pr_debug("Already in requested mode!\n");
+ return 0;
+ }
+
+ pdata = dev_get_platdata(&mfd->pdev->dev);
+
+ pr_debug("Enter mode: %d\n", mode);
+ pdata->panel_info.dynamic_switch_pending = true;
+
+ mutex_lock(&mfd->bl_lock);
+ bl_lvl = mfd->bl_level;
+ mdss_fb_set_backlight(mfd, 0);
+ mutex_unlock(&mfd->bl_lock);
+
+ lock_fb_info(mfd->fbi);
+ ret = mdss_fb_blank_sub(FB_BLANK_POWERDOWN, mfd->fbi,
+ mfd->op_enable);
+ if (ret) {
+ pr_err("can't turn off display!\n");
+ unlock_fb_info(mfd->fbi);
+ return ret;
+ }
+
+ mfd->op_enable = false;
+
+ ret = mfd->mdp.configure_panel(mfd, mode);
+ mdss_fb_set_mdp_sync_pt_threshold(mfd);
+
+ mfd->op_enable = true;
+
+ ret = mdss_fb_blank_sub(FB_BLANK_UNBLANK, mfd->fbi,
+ mfd->op_enable);
+ if (ret) {
+ pr_err("can't turn on display!\n");
+ unlock_fb_info(mfd->fbi);
+ return ret;
+ }
+ unlock_fb_info(mfd->fbi);
+
+ mutex_lock(&mfd->bl_lock);
+ mfd->bl_updated = true;
+ mdss_fb_set_backlight(mfd, bl_lvl);
+ mutex_unlock(&mfd->bl_lock);
+
+ pdata->panel_info.dynamic_switch_pending = false;
+ pdata->panel_info.is_lpm_mode = mode ? 1 : 0;
+
+ if (ret) {
+ pr_err("can't turn on display!\n");
+ return ret;
+ }
+
+ pr_debug("Exit mode: %d\n", mode);
+
+ return 0;
+}
+
static DEVICE_ATTR(msm_fb_type, S_IRUGO, mdss_fb_get_type, NULL);
static DEVICE_ATTR(msm_fb_split, S_IRUGO, mdss_fb_get_split, NULL);
static DEVICE_ATTR(show_blank_event, S_IRUGO, mdss_mdp_show_blank_event, NULL);
@@ -539,6 +625,21 @@
__mdss_fb_sync_buf_done_callback;
}
+ mdss_fb_set_mdp_sync_pt_threshold(mfd);
+
+ if (mfd->mdp.splash_init_fnc)
+ mfd->mdp.splash_init_fnc(mfd);
+
+ INIT_DELAYED_WORK(&mfd->idle_notify_work, __mdss_fb_idle_notify_work);
+
+ return rc;
+}
+
+static void mdss_fb_set_mdp_sync_pt_threshold(struct msm_fb_data_type *mfd)
+{
+ if (!mfd)
+ return;
+
switch (mfd->panel.type) {
case WRITEBACK_PANEL:
mfd->mdp_sync_pt_data.threshold = 1;
@@ -553,28 +654,20 @@
mfd->mdp_sync_pt_data.retire_threshold = 0;
break;
}
-
- if (mfd->mdp.splash_init_fnc)
- mfd->mdp.splash_init_fnc(mfd);
-
- INIT_DELAYED_WORK(&mfd->idle_notify_work, __mdss_fb_idle_notify_work);
-
- return rc;
}
-
static int mdss_fb_remove(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
+ if (!mfd)
+ return -ENODEV;
+
mdss_fb_remove_sysfs(mfd);
pm_runtime_disable(mfd->fbi->dev);
- if (!mfd)
- return -ENODEV;
-
if (mfd->key != MFD_KEY)
return -EINVAL;
@@ -933,6 +1026,7 @@
static int mdss_fb_blank(int blank_mode, struct fb_info *info)
{
+ struct mdss_panel_data *pdata;
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
mdss_fb_pan_idle(mfd);
@@ -943,6 +1037,18 @@
mfd->suspend.panel_power_on = false;
return 0;
}
+ pr_debug("mode: %d\n", blank_mode);
+
+ pdata = dev_get_platdata(&mfd->pdev->dev);
+
+ if (pdata->panel_info.is_lpm_mode &&
+ blank_mode == FB_BLANK_UNBLANK) {
+ pr_debug("panel is in lpm mode\n");
+ mfd->mdp.configure_panel(mfd, 0);
+ mdss_fb_set_mdp_sync_pt_threshold(mfd);
+ pdata->panel_info.is_lpm_mode = false;
+ }
+
return mdss_fb_blank_sub(blank_mode, info, mfd->op_enable);
}
@@ -2377,6 +2483,7 @@
int ret = -ENOSYS;
struct mdp_buf_sync buf_sync;
struct msm_sync_pt_data *sync_pt_data = NULL;
+ unsigned int dsi_mode = 0;
if (!info || !info->par)
return -EINVAL;
@@ -2443,6 +2550,16 @@
ret = mdss_fb_display_commit(info, argp);
break;
+ case MSMFB_LPM_ENABLE:
+ ret = copy_from_user(&dsi_mode, argp, sizeof(dsi_mode));
+ if (ret) {
+ pr_err("%s: MSMFB_LPM_ENABLE ioctl failed\n", __func__);
+ goto exit;
+ }
+
+ ret = mdss_fb_lpm_enable(mfd, dsi_mode);
+ break;
+
default:
if (mfd->mdp.ioctl_handler)
ret = mfd->mdp.ioctl_handler(mfd, cmd, argp);
@@ -2536,7 +2653,8 @@
pr_info("adding framebuffer device %s\n", dev_name(&pdev->dev));
fb_pdev = of_platform_device_create(node, NULL,
&mdss_pdev->dev);
- fb_pdev->dev.platform_data = pdata;
+ if (fb_pdev)
+ fb_pdev->dev.platform_data = pdata;
}
if (master_panel && mdp_instance->panel_register_done)
@@ -2565,7 +2683,7 @@
struct fb_info *info;
struct msm_fb_data_type *mfd;
- if (fb_num > MAX_FBI_LIST)
+ if (fb_num >= MAX_FBI_LIST)
return -EINVAL;
info = fbi_list[fb_num];
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index ce0a7f9..5ab3d41 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -129,6 +129,7 @@
struct msm_sync_pt_data *(*get_sync_fnc)(struct msm_fb_data_type *mfd,
const struct mdp_buf_sync *buf_sync);
void (*check_dsi_status)(struct work_struct *work, uint32_t interval);
+ int (*configure_panel)(struct msm_fb_data_type *mfd, int mode);
void *private1;
};
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 2141659..837b276 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -1995,6 +1995,8 @@
mixer = mdss_mdp_mixer_get(mdp5_data->ctl, MDSS_MDP_MIXER_MUX_DEFAULT);
off = MDSS_MDP_REG_LM_OFFSET(mixer->num);
+ if (!mixer)
+ return -ENODEV;
if ((img->width > MDSS_MDP_CURSOR_WIDTH) ||
(img->height > MDSS_MDP_CURSOR_HEIGHT) ||
@@ -3049,6 +3051,27 @@
return 0;
}
+static int mdss_mdp_update_panel_info(struct msm_fb_data_type *mfd, int mode)
+{
+ int ret = 0;
+ struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
+ struct mdss_mdp_ctl *ctl = mdp5_data->ctl;
+
+ ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_DSI_DYNAMIC_SWITCH,
+ (void *)(unsigned long)mode);
+ if (ret)
+ pr_err("Dynamic switch to %s mode failed!\n",
+ mode ? "command" : "video");
+ /*
+ * Destroy current ctrl sturcture as this is
+ * going to be re-initialized with the requested mode.
+ */
+ mdss_mdp_ctl_destroy(mdp5_data->ctl);
+ mdp5_data->ctl = NULL;
+
+ return 0;
+}
+
int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
{
struct device *dev = mfd->fbi->dev;
@@ -3067,6 +3090,7 @@
mdp5_interface->kickoff_fnc = mdss_mdp_overlay_kickoff;
mdp5_interface->get_sync_fnc = mdss_mdp_rotator_sync_pt_get;
mdp5_interface->splash_init_fnc = mdss_mdp_splash_init;
+ mdp5_interface->configure_panel = mdss_mdp_update_panel_info;
mdp5_data = kmalloc(sizeof(struct mdss_overlay_private), GFP_KERNEL);
if (!mdp5_data) {
@@ -3117,7 +3141,10 @@
pr_err("Error dfps sysfs creation ret=%d\n", rc);
goto init_fail;
}
- } else if (mfd->panel_info->type == MIPI_CMD_PANEL) {
+ }
+
+ if (mfd->panel_info->mipi.dynamic_switch_enabled ||
+ mfd->panel_info->type == MIPI_CMD_PANEL) {
rc = __vsync_retire_setup(mfd);
if (IS_ERR_VALUE(rc)) {
pr_err("unable to create vsync timeline\n");
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
index 70544c0..ccd60a6 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pipe.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -276,7 +276,7 @@
if (pipe->mixer && pipe->mixer->rotator_mode) {
rot_mode = 1;
- } else if (ps.num_planes == 1) {
+ } else if (pipe->mixer && (ps.num_planes == 1)) {
ps.ystride[0] = MAX_BPP *
max(pipe->mixer->width, width);
} else if (mdata->has_decimation) {
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 7159a0a..ebda2ee 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -1174,15 +1174,17 @@
struct pp_hist_col_info *hist_info;
char __iomem *ctl_base;
- if (!pipe && pipe->pp_res.hist.col_en) {
- done_bit = 3 << (pipe->num * 4);
- hist_info = &pipe->pp_res.hist;
- ctl_base = pipe->base +
- MDSS_MDP_REG_VIG_HIST_CTL_BASE;
- pp_histogram_disable(hist_info, done_bit, ctl_base);
+ if (pipe) {
+ if (pipe->pp_res.hist.col_en) {
+ done_bit = 3 << (pipe->num * 4);
+ hist_info = &pipe->pp_res.hist;
+ ctl_base = pipe->base +
+ MDSS_MDP_REG_VIG_HIST_CTL_BASE;
+ pp_histogram_disable(hist_info, done_bit, ctl_base);
+ }
+ memset(&pipe->pp_cfg, 0, sizeof(struct mdp_overlay_pp_params));
+ memset(&pipe->pp_res, 0, sizeof(struct mdss_pipe_pp_res));
}
- memset(&pipe->pp_cfg, 0, sizeof(struct mdp_overlay_pp_params));
- memset(&pipe->pp_res, 0, sizeof(struct mdss_pipe_pp_res));
}
int mdss_mdp_pipe_sspp_setup(struct mdss_mdp_pipe *pipe, u32 *op)
@@ -1251,10 +1253,10 @@
struct pp_sts_type *pp_sts;
struct mdss_mdp_ctl *ctl;
char __iomem *addr;
- dspp_num = mixer->num;
if (!mixer || !mixer->ctl)
return -EINVAL;
+ dspp_num = mixer->num;
ctl = mixer->ctl;
/* no corresponding dspp */
@@ -1815,7 +1817,7 @@
}
}
}
- if (mdata) {
+ if (mdata && mdata->vig_pipes) {
vig = mdata->vig_pipes;
for (i = 0; i < mdata->nvig_pipes; i++) {
mutex_init(&vig[i].pp_res.hist.hist_mutex);
@@ -1844,6 +1846,7 @@
mutex_unlock(&mdss_pp_mutex);
return ret;
}
+
void mdss_mdp_pp_term(struct device *dev)
{
struct mdss_data_type *mdata = mdss_mdp_get_mdata();
@@ -3763,8 +3766,7 @@
hist_info = &pipe->pp_res.hist;
}
/* Histogram Done Interrupt */
- if (hist_info && (isr_blk & 0x1) &&
- (hist_info->col_en)) {
+ if (hist_info && (isr_blk & 0x1) && (hist_info->col_en)) {
spin_lock(&hist_info->hist_lock);
hist_info->col_state = HIST_READY;
spin_unlock(&hist_info->hist_lock);
@@ -3774,8 +3776,7 @@
}
}
/* Histogram Reset Done Interrupt */
- if ((isr_blk & 0x2) &&
- (hist_info->col_en)) {
+ if (hist_info && (isr_blk & 0x2) && (hist_info->col_en)) {
spin_lock(&hist_info->hist_lock);
hist_info->col_state = HIST_IDLE;
spin_unlock(&hist_info->hist_lock);
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index 9336582..01745fd 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -498,24 +498,28 @@
data->srcp_file = NULL;
} else if (!IS_ERR_OR_NULL(data->srcp_ihdl)) {
pr_debug("ion hdl=%p buf=0x%x\n", data->srcp_ihdl, data->addr);
-
- if (is_mdss_iommu_attached()) {
- int domain;
- if (data->flags & MDP_SECURE_OVERLAY_SESSION)
- domain = MDSS_IOMMU_DOMAIN_SECURE;
- else
- domain = MDSS_IOMMU_DOMAIN_UNSECURE;
- ion_unmap_iommu(iclient, data->srcp_ihdl,
+ if (!iclient) {
+ pr_err("invalid ion client\n");
+ return -ENOMEM;
+ } else {
+ if (is_mdss_iommu_attached()) {
+ int domain;
+ if (data->flags & MDP_SECURE_OVERLAY_SESSION)
+ domain = MDSS_IOMMU_DOMAIN_SECURE;
+ else
+ domain = MDSS_IOMMU_DOMAIN_UNSECURE;
+ ion_unmap_iommu(iclient, data->srcp_ihdl,
mdss_get_iommu_domain(domain), 0);
- if (domain == MDSS_IOMMU_DOMAIN_SECURE) {
- msm_ion_unsecure_buffer(iclient,
- data->srcp_ihdl);
+ if (domain == MDSS_IOMMU_DOMAIN_SECURE) {
+ msm_ion_unsecure_buffer(iclient,
+ data->srcp_ihdl);
+ }
}
+ ion_free(iclient, data->srcp_ihdl);
+ data->srcp_ihdl = NULL;
}
- ion_free(iclient, data->srcp_ihdl);
- data->srcp_ihdl = NULL;
} else {
return -ENOMEM;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp_wb.c b/drivers/video/msm/mdss/mdss_mdp_wb.c
index 6086e28..3b30b2b 100644
--- a/drivers/video/msm/mdss/mdss_mdp_wb.c
+++ b/drivers/video/msm/mdss/mdss_mdp_wb.c
@@ -343,12 +343,12 @@
static int mdss_mdp_wb_register_node(struct mdss_mdp_wb *wb,
struct mdss_mdp_wb_data *node)
{
- node->state = REGISTERED;
- list_add_tail(&node->registered_entry, &wb->register_queue);
if (!node) {
pr_err("Invalid wb node\n");
return -EINVAL;
}
+ node->state = REGISTERED;
+ list_add_tail(&node->registered_entry, &wb->register_queue);
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index c43cdd3..084cba4 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -132,6 +132,10 @@
* event arguments can have one of these values:
* - 0: Disable ULPS mode
* - 1: Enable ULPS mode
+ * @MDSS_EVENT_DSI_DYNAMIC_SWITCH: Event to update the dsi driver structures
+ * based on the dsi mode passed as argument.
+ * - 0: update to video mode
+ * - 1: update to command mode
*/
enum mdss_intf_events {
MDSS_EVENT_RESET = 1,
@@ -152,6 +156,7 @@
MDSS_EVENT_ENABLE_PARTIAL_UPDATE,
MDSS_EVENT_DSI_ULPS_CTRL,
MDSS_EVENT_REGISTER_RECOVERY_HANDLER,
+ MDSS_EVENT_DSI_DYNAMIC_SWITCH,
};
struct lcd_panel_info {
@@ -222,6 +227,9 @@
char stream; /* 0 or 1 */
char mdp_trigger;
char dma_trigger;
+ /*Dynamic Switch Support*/
+ bool dynamic_switch_enabled;
+ u32 pixel_packing;
u32 dsi_pclk_rate;
/* The packet-size should not bet changed */
char no_max_pkt_size;
@@ -337,6 +345,9 @@
u32 panel_power_on;
uint32_t panel_dead;
+ bool dynamic_switch_pending;
+ bool is_lpm_mode;
+
struct mdss_mdp_pp_tear_check te;
struct lcd_panel_info lcdc;
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index 34e383e..671fb50 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -64,7 +64,8 @@
goto mdss_dsi_clk_err;
}
- if (ctrl_pdata->panel_data.panel_info.type == MIPI_CMD_PANEL) {
+ if ((ctrl_pdata->panel_data.panel_info.type == MIPI_CMD_PANEL) ||
+ ctrl_pdata->panel_data.panel_info.mipi.dynamic_switch_enabled) {
ctrl_pdata->mmss_misc_ahb_clk = clk_get(dev, "core_mmss_clk");
if (IS_ERR(ctrl_pdata->mmss_misc_ahb_clk)) {
rc = PTR_ERR(ctrl_pdata->mmss_misc_ahb_clk);
@@ -216,7 +217,7 @@
}
/* find the mnd settings from mnd_table entry */
- for (; mnd_entry != mnd_table + ARRAY_SIZE(mnd_table); ++mnd_entry) {
+ for (; mnd_entry < mnd_table + ARRAY_SIZE(mnd_table); ++mnd_entry) {
if (((mnd_entry->lanes) == lanes) &&
((mnd_entry->bpp) == bpp))
break;
diff --git a/fs/proc/consoles.c b/fs/proc/consoles.c
index b701eaa..51942d5 100644
--- a/fs/proc/consoles.c
+++ b/fs/proc/consoles.c
@@ -29,7 +29,6 @@
char flags[ARRAY_SIZE(con_flags) + 1];
struct console *con = v;
unsigned int a;
- int len;
dev_t dev = 0;
if (con->device) {
@@ -47,11 +46,10 @@
con_flags[a].name : ' ';
flags[a] = 0;
- seq_printf(m, "%s%d%n", con->name, con->index, &len);
- len = 21 - len;
- if (len < 1)
- len = 1;
- seq_printf(m, "%*c%c%c%c (%s)", len, ' ', con->read ? 'R' : '-',
+ seq_setwidth(m, 21 - 1);
+ seq_printf(m, "%s%d", con->name, con->index);
+ seq_pad(m, ' ');
+ seq_printf(m, "%c%c%c (%s)", con->read ? 'R' : '-',
con->write ? 'W' : '-', con->unblank ? 'U' : '-',
flags);
if (dev)
diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c
index b1822dd..501ae3a 100644
--- a/fs/proc/nommu.c
+++ b/fs/proc/nommu.c
@@ -39,7 +39,7 @@
unsigned long ino = 0;
struct file *file;
dev_t dev = 0;
- int flags, len;
+ int flags;
flags = region->vm_flags;
file = region->vm_file;
@@ -50,8 +50,9 @@
ino = inode->i_ino;
}
+ seq_setwidth(m, 25 + sizeof(void *) * 6 - 1);
seq_printf(m,
- "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n",
+ "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu ",
region->vm_start,
region->vm_end,
flags & VM_READ ? 'r' : '-',
@@ -59,13 +60,10 @@
flags & VM_EXEC ? 'x' : '-',
flags & VM_MAYSHARE ? flags & VM_SHARED ? 'S' : 's' : 'p',
((loff_t)region->vm_pgoff) << PAGE_SHIFT,
- MAJOR(dev), MINOR(dev), ino, &len);
+ MAJOR(dev), MINOR(dev), ino);
if (file) {
- len = 25 + sizeof(void *) * 6 - len;
- if (len < 1)
- len = 1;
- seq_printf(m, "%*c", len, ' ');
+ seq_pad(m, ' ');
seq_path(m, &file->f_path, "");
}
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 1030a71..2fb663a 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -82,14 +82,6 @@
return mm->total_vm;
}
-static void pad_len_spaces(struct seq_file *m, int len)
-{
- len = 25 + sizeof(void*) * 6 - len;
- if (len < 1)
- len = 1;
- seq_printf(m, "%*c", len, ' ');
-}
-
static void vma_stop(struct proc_maps_private *priv, struct vm_area_struct *vma)
{
if (vma && vma != priv->tail_vma) {
@@ -221,7 +213,6 @@
unsigned long long pgoff = 0;
unsigned long start, end;
dev_t dev = 0;
- int len;
const char *name = NULL;
if (file) {
@@ -239,7 +230,8 @@
if (stack_guard_page_end(vma, end))
end -= PAGE_SIZE;
- seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n",
+ seq_setwidth(m, 25 + sizeof(void *) * 6 - 1);
+ seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu ",
start,
end,
flags & VM_READ ? 'r' : '-',
@@ -247,14 +239,14 @@
flags & VM_EXEC ? 'x' : '-',
flags & VM_MAYSHARE ? 's' : 'p',
pgoff,
- MAJOR(dev), MINOR(dev), ino, &len);
+ MAJOR(dev), MINOR(dev), ino);
/*
* Print the dentry name for named mappings, and a
* special [heap] marker for the heap:
*/
if (file) {
- pad_len_spaces(m, len);
+ seq_pad(m, ' ');
seq_path(m, &file->f_path, "\n");
goto done;
}
@@ -286,7 +278,7 @@
name = "[stack]";
} else {
/* Thread stack in /proc/PID/maps */
- pad_len_spaces(m, len);
+ seq_pad(m, ' ');
seq_printf(m, "[stack:%d]", tid);
}
}
@@ -294,7 +286,7 @@
done:
if (name) {
- pad_len_spaces(m, len);
+ seq_pad(m, ' ');
seq_puts(m, name);
}
seq_putc(m, '\n');
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c
index 74fe164..1d2b545 100644
--- a/fs/proc/task_nommu.c
+++ b/fs/proc/task_nommu.c
@@ -123,14 +123,6 @@
return size;
}
-static void pad_len_spaces(struct seq_file *m, int len)
-{
- len = 25 + sizeof(void*) * 6 - len;
- if (len < 1)
- len = 1;
- seq_printf(m, "%*c", len, ' ');
-}
-
/*
* display a single VMA to a sequenced file
*/
@@ -142,7 +134,7 @@
unsigned long ino = 0;
struct file *file;
dev_t dev = 0;
- int flags, len;
+ int flags;
unsigned long long pgoff = 0;
flags = vma->vm_flags;
@@ -155,8 +147,9 @@
pgoff = (loff_t)vma->vm_pgoff << PAGE_SHIFT;
}
+ seq_setwidth(m, 25 + sizeof(void *) * 6 - 1);
seq_printf(m,
- "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n",
+ "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu ",
vma->vm_start,
vma->vm_end,
flags & VM_READ ? 'r' : '-',
@@ -164,16 +157,16 @@
flags & VM_EXEC ? 'x' : '-',
flags & VM_MAYSHARE ? flags & VM_SHARED ? 'S' : 's' : 'p',
pgoff,
- MAJOR(dev), MINOR(dev), ino, &len);
+ MAJOR(dev), MINOR(dev), ino);
if (file) {
- pad_len_spaces(m, len);
+ seq_pad(m, ' ');
seq_path(m, &file->f_path, "");
} else if (mm) {
pid_t tid = vm_is_stack(priv->task, vma, is_pid);
if (tid != 0) {
- pad_len_spaces(m, len);
+ seq_pad(m, ' ');
/*
* Thread stack in /proc/PID/task/TID/maps or
* the main process stack.
diff --git a/fs/seq_file.c b/fs/seq_file.c
index 0cbd049..74717b4 100644
--- a/fs/seq_file.c
+++ b/fs/seq_file.c
@@ -732,6 +732,21 @@
}
EXPORT_SYMBOL(seq_write);
+/**
+ * seq_pad - write padding spaces to buffer
+ * @m: seq_file identifying the buffer to which data should be written
+ * @c: the byte to append after padding if non-zero
+ */
+void seq_pad(struct seq_file *m, char c)
+{
+ int size = m->pad_until - m->count;
+ if (size > 0)
+ seq_printf(m, "%*s", size, "");
+ if (c)
+ seq_putc(m, c);
+}
+EXPORT_SYMBOL(seq_pad);
+
struct list_head *seq_list_start(struct list_head *head, loff_t pos)
{
struct list_head *lh;
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index fd2cc6c..b295fcc 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -81,6 +81,7 @@
#define MSMFB_ASYNC_BLIT _IOW(MSMFB_IOCTL_MAGIC, 168, unsigned int)
#define MSMFB_OVERLAY_PREPARE _IOWR(MSMFB_IOCTL_MAGIC, 169, \
struct mdp_overlay_list)
+#define MSMFB_LPM_ENABLE _IOWR(MSMFB_IOCTL_MAGIC, 170, unsigned int)
#define FB_TYPE_3D_PANEL 0x10101010
#define MDP_IMGTYPE2_START 0x10000
#define MSMFB_DRIVER_VERSION 0xF9E8D701
diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h
index fc61854..e156ce1 100644
--- a/include/linux/seq_file.h
+++ b/include/linux/seq_file.h
@@ -19,6 +19,7 @@
size_t size;
size_t from;
size_t count;
+ size_t pad_until;
loff_t index;
loff_t read_pos;
u64 version;
@@ -75,6 +76,20 @@
}
}
+/**
+ * seq_setwidth - set padding width
+ * @m: the seq_file handle
+ * @size: the max number of bytes to pad.
+ *
+ * Call seq_setwidth() for setting max width, then call seq_printf() etc. and
+ * finally call seq_pad() to pad the remaining bytes.
+ */
+static inline void seq_setwidth(struct seq_file *m, size_t size)
+{
+ m->pad_until = m->count + size;
+}
+void seq_pad(struct seq_file *m, char c);
+
char *mangle_path(char *s, const char *p, const char *esc);
int seq_open(struct file *, const struct seq_operations *);
ssize_t seq_read(struct file *, char __user *, size_t, loff_t *);
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 3844f41..1a94910 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -509,6 +509,7 @@
* @usb_core_id: Identifies the usb core controlled by this usb_gadget.
* Used in case of more then one core operates concurrently.
* @streaming_enabled: Enable streaming mode with usb core.
+ * @xfer_isr_count: UI (transfer complete) interrupts count
*
* Gadgets have a mostly-portable "gadget driver" implementing device
* functions, handling all usb configurations and interfaces. Gadget
@@ -548,6 +549,7 @@
u8 usb_core_id;
bool l1_supported;
bool streaming_enabled;
+ u32 xfer_isr_count;
};
static inline void set_gadget_data(struct usb_gadget *gadget, void *data)
diff --git a/include/linux/usb_usual.h b/include/linux/usb_usual.h
index ff30988..17df360 100644
--- a/include/linux/usb_usual.h
+++ b/include/linux/usb_usual.h
@@ -64,9 +64,7 @@
US_FLAG(NO_READ_CAPACITY_16, 0x00080000) \
/* cannot handle READ_CAPACITY_16 */ \
US_FLAG(INITIAL_READ10, 0x00100000) \
- /* Initial READ(10) (and others) must be retried */ \
- US_FLAG(TUR_AFTER_WRITE, 0x00200000) \
- /* 5 TEST_UNIT_READY after 8 WRITE(10) */ \
+ /* Initial READ(10) (and others) must be retried */
#define US_FLAG(name, value) US_FL_##name = value ,
enum { US_DO_ALL_FLAGS };
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
index bbde6ef..e48c7da 100644
--- a/include/media/msm_vidc.h
+++ b/include/media/msm_vidc.h
@@ -55,6 +55,7 @@
void *msm_vidc_open(int core_id, int session_type);
int msm_vidc_close(void *instance);
+int msm_vidc_suspend(int core_id);
int msm_vidc_querycap(void *instance, struct v4l2_capability *cap);
int msm_vidc_enum_fmt(void *instance, struct v4l2_fmtdesc *f);
int msm_vidc_s_fmt(void *instance, struct v4l2_format *f);
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 2db91f9..745a600 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -648,10 +648,12 @@
void set_cpu_online(unsigned int cpu, bool online)
{
- if (online)
+ if (online) {
cpumask_set_cpu(cpu, to_cpumask(cpu_online_bits));
- else
+ cpumask_set_cpu(cpu, to_cpumask(cpu_active_bits));
+ } else {
cpumask_clear_cpu(cpu, to_cpumask(cpu_online_bits));
+ }
}
void set_cpu_active(unsigned int cpu, bool active)
diff --git a/kernel/futex.c b/kernel/futex.c
index e2b0fb9..9536918 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -1256,6 +1256,13 @@
if (requeue_pi) {
/*
+ * Requeue PI only works on two distinct uaddrs. This
+ * check is only valid for private futexes. See below.
+ */
+ if (uaddr1 == uaddr2)
+ return -EINVAL;
+
+ /*
* requeue_pi requires a pi_state, try to allocate it now
* without any locks in case it fails.
*/
@@ -1293,6 +1300,15 @@
if (unlikely(ret != 0))
goto out_put_key1;
+ /*
+ * The check above which compares uaddrs is not sufficient for
+ * shared futexes. We need to compare the keys:
+ */
+ if (requeue_pi && match_futex(&key1, &key2)) {
+ ret = -EINVAL;
+ goto out_put_keys;
+ }
+
hb1 = hash_futex(&key1);
hb2 = hash_futex(&key2);
@@ -2308,6 +2324,15 @@
if (ret)
goto out_key2;
+ /*
+ * The check above which compares uaddrs is not sufficient for
+ * shared futexes. We need to compare the keys:
+ */
+ if (match_futex(&q.key, &key2)) {
+ ret = -EINVAL;
+ goto out_put_keys;
+ }
+
/* Queue the futex_q, drop the hb lock, wait for wakeup. */
futex_wait_queue_me(hb, &q, to);
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index d9e1f1d..faeb4b7 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -5507,7 +5507,6 @@
unsigned long action, void *hcpu)
{
switch (action & ~CPU_TASKS_FROZEN) {
- case CPU_STARTING:
case CPU_DOWN_FAILED:
set_cpu_active((long)hcpu, true);
return NOTIFY_OK;
@@ -6919,9 +6918,6 @@
hotcpu_notifier(cpuset_cpu_active, CPU_PRI_CPUSET_ACTIVE);
hotcpu_notifier(cpuset_cpu_inactive, CPU_PRI_CPUSET_INACTIVE);
- /* RT runtime code needs to handle some hotplug events */
- hotcpu_notifier(update_runtime, 0);
-
init_hrtick();
/* Move init over to a non-isolated CPU */
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index 3d4b1e2..e32ab1d 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -691,15 +691,6 @@
}
}
-static void disable_runtime(struct rq *rq)
-{
- unsigned long flags;
-
- raw_spin_lock_irqsave(&rq->lock, flags);
- __disable_runtime(rq);
- raw_spin_unlock_irqrestore(&rq->lock, flags);
-}
-
static void __enable_runtime(struct rq *rq)
{
rt_rq_iter_t iter;
@@ -724,37 +715,6 @@
}
}
-static void enable_runtime(struct rq *rq)
-{
- unsigned long flags;
-
- raw_spin_lock_irqsave(&rq->lock, flags);
- __enable_runtime(rq);
- raw_spin_unlock_irqrestore(&rq->lock, flags);
-}
-
-int update_runtime(struct notifier_block *nfb, unsigned long action, void *hcpu)
-{
- int cpu = (int)(long)hcpu;
-
- switch (action) {
- case CPU_DOWN_PREPARE:
- case CPU_DOWN_PREPARE_FROZEN:
- disable_runtime(cpu_rq(cpu));
- return NOTIFY_OK;
-
- case CPU_DOWN_FAILED:
- case CPU_DOWN_FAILED_FROZEN:
- case CPU_ONLINE:
- case CPU_ONLINE_FROZEN:
- enable_runtime(cpu_rq(cpu));
- return NOTIFY_OK;
-
- default:
- return NOTIFY_DONE;
- }
-}
-
static int balance_runtime(struct rt_rq *rt_rq)
{
int more = 0;
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 34fe64f..73ae84a 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -878,7 +878,6 @@
extern void sched_init_granularity(void);
extern void update_max_interval(void);
extern void update_group_power(struct sched_domain *sd, int cpu);
-extern int update_runtime(struct notifier_block *nfb, unsigned long action, void *hcpu);
extern void init_sched_rt_class(void);
extern void init_sched_fair_class(void);
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 08b5ae7..0b3c622 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -1287,18 +1287,16 @@
break;
case FORMAT_TYPE_NRCHARS: {
- u8 qualifier = spec.qualifier;
+ /*
+ * Since %n poses a greater security risk than
+ * utility, ignore %n and skip its argument.
+ */
+ void *skip_arg;
- if (qualifier == 'l') {
- long *ip = va_arg(args, long *);
- *ip = (str - buf);
- } else if (_tolower(qualifier) == 'z') {
- size_t *ip = va_arg(args, size_t *);
- *ip = (str - buf);
- } else {
- int *ip = va_arg(args, int *);
- *ip = (str - buf);
- }
+ WARN_ONCE(1, "Please remove ignored %%n in '%s'\n",
+ old_fmt);
+
+ skip_arg = va_arg(args, void *);
break;
}
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 6d6d7d2..452fa86 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -691,11 +691,13 @@
static int ethtool_get_wol(struct net_device *dev, char __user *useraddr)
{
- struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
+ struct ethtool_wolinfo wol;
if (!dev->ethtool_ops->get_wol)
return -EOPNOTSUPP;
+ memset(&wol, 0, sizeof(struct ethtool_wolinfo));
+ wol.cmd = ETHTOOL_GWOL;
dev->ethtool_ops->get_wol(dev, &wol);
if (copy_to_user(useraddr, &wol, sizeof(wol)))
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index cada6a7..348df4d 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -2550,16 +2550,17 @@
list_for_each_entry_rcu(fa, &li->falh, fa_list) {
const struct fib_info *fi = fa->fa_info;
unsigned int flags = fib_flag_trans(fa->fa_type, mask, fi);
- int len;
if (fa->fa_type == RTN_BROADCAST
|| fa->fa_type == RTN_MULTICAST)
continue;
+ seq_setwidth(seq, 127);
+
if (fi)
seq_printf(seq,
"%s\t%08X\t%08X\t%04X\t%d\t%u\t"
- "%d\t%08X\t%d\t%u\t%u%n",
+ "%d\t%08X\t%d\t%u\t%u",
fi->fib_dev ? fi->fib_dev->name : "*",
prefix,
fi->fib_nh->nh_gw, flags, 0, 0,
@@ -2568,15 +2569,15 @@
(fi->fib_advmss ?
fi->fib_advmss + 40 : 0),
fi->fib_window,
- fi->fib_rtt >> 3, &len);
+ fi->fib_rtt >> 3);
else
seq_printf(seq,
"*\t%08X\t%08X\t%04X\t%d\t%u\t"
- "%d\t%08X\t%d\t%u\t%u%n",
+ "%d\t%08X\t%d\t%u\t%u",
prefix, 0, flags, 0, 0, 0,
- mask, 0, 0, 0, &len);
+ mask, 0, 0, 0);
- seq_printf(seq, "%*s\n", 127 - len, "");
+ seq_pad(seq, '\n');
}
}
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index 87f05b2..5f2ee64 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -248,26 +248,33 @@
struct net *net = sock_net(sk);
gid_t group = current_egid();
gid_t range[2];
- struct group_info *group_info = get_current_groups();
- int i, j, count = group_info->ngroups;
+ struct group_info *group_info;
+ int i, j, count ;
+ int ret = 0;
inet_get_ping_group_range_net(net, range, range+1);
if (range[0] <= group && group <= range[1])
return 0;
+ group_info = get_current_groups();
+ count = group_info->ngroups;
for (i = 0; i < group_info->nblocks; i++) {
int cp_count = min_t(int, NGROUPS_PER_BLOCK, count);
for (j = 0; j < cp_count; j++) {
group = group_info->blocks[i][j];
if (range[0] <= group && group <= range[1])
- return 0;
+ goto out_release_group;
}
count -= cp_count;
}
- return -EACCES;
+ ret = -EACCES;
+
+out_release_group:
+ put_group_info(group_info);
+ return ret;
}
EXPORT_SYMBOL_GPL(ping_init_sock);
@@ -1071,7 +1078,7 @@
}
static void ping_format_sock(struct sock *sp, struct seq_file *f,
- int bucket, int *len)
+ int bucket)
{
struct inet_sock *inet = inet_sk(sp);
__be32 dest = inet->inet_daddr;
@@ -1080,29 +1087,28 @@
__u16 srcp = ntohs(inet->inet_sport);
seq_printf(f, "%5d: %08X:%04X %08X:%04X"
- " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %pK %d%n",
+ " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %pK %d",
bucket, src, srcp, dest, destp, sp->sk_state,
sk_wmem_alloc_get(sp),
sk_rmem_alloc_get(sp),
0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp),
atomic_read(&sp->sk_refcnt), sp,
- atomic_read(&sp->sk_drops), len);
+ atomic_read(&sp->sk_drops));
}
static int ping_seq_show(struct seq_file *seq, void *v)
{
+ seq_setwidth(seq, 127);
if (v == SEQ_START_TOKEN)
- seq_printf(seq, "%-127s\n",
- " sl local_address rem_address st tx_queue "
+ seq_puts(seq, " sl local_address rem_address st tx_queue "
"rx_queue tr tm->when retrnsmt uid timeout "
"inode ref pointer drops");
else {
struct ping_iter_state *state = seq->private;
- int len;
- ping_format_sock(v, seq, state->bucket, &len);
- seq_printf(seq, "%*s\n", 127 - len, "");
+ ping_format_sock(v, seq, state->bucket);
}
+ seq_pad(seq, '\n');
return 0;
}
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 0cb86ce..54225b1 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -2398,13 +2398,13 @@
EXPORT_SYMBOL(tcp_proc_unregister);
static void get_openreq4(const struct sock *sk, const struct request_sock *req,
- struct seq_file *f, int i, int uid, int *len)
+ struct seq_file *f, int i, int uid)
{
const struct inet_request_sock *ireq = inet_rsk(req);
int ttd = req->expires - jiffies;
seq_printf(f, "%4d: %08X:%04X %08X:%04X"
- " %02X %08X:%08X %02X:%08lX %08X %5d %8d %u %d %pK%n",
+ " %02X %08X:%08X %02X:%08lX %08X %5d %8d %u %d %pK",
i,
ireq->loc_addr,
ntohs(inet_sk(sk)->inet_sport),
@@ -2419,11 +2419,10 @@
0, /* non standard timer */
0, /* open_requests have no inode */
atomic_read(&sk->sk_refcnt),
- req,
- len);
+ req);
}
-static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len)
+static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i)
{
int timer_active;
unsigned long timer_expires;
@@ -2459,7 +2458,7 @@
rx_queue = max_t(int, tp->rcv_nxt - tp->copied_seq, 0);
seq_printf(f, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX "
- "%08X %5d %8d %lu %d %pK %lu %lu %u %u %d%n",
+ "%08X %5d %8d %lu %d %pK %lu %lu %u %u %d",
i, src, srcp, dest, destp, sk->sk_state,
tp->write_seq - tp->snd_una,
rx_queue,
@@ -2474,12 +2473,12 @@
jiffies_to_clock_t(icsk->icsk_ack.ato),
(icsk->icsk_ack.quick << 1) | icsk->icsk_ack.pingpong,
tp->snd_cwnd,
- tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh,
- len);
+ tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh);
+
}
static void get_timewait4_sock(const struct inet_timewait_sock *tw,
- struct seq_file *f, int i, int *len)
+ struct seq_file *f, int i)
{
__be32 dest, src;
__u16 destp, srcp;
@@ -2494,10 +2493,10 @@
srcp = ntohs(tw->tw_sport);
seq_printf(f, "%4d: %08X:%04X %08X:%04X"
- " %02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK%n",
+ " %02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK",
i, src, srcp, dest, destp, tw->tw_substate, 0, 0,
3, jiffies_to_clock_t(ttd), 0, 0, 0, 0,
- atomic_read(&tw->tw_refcnt), tw, len);
+ atomic_read(&tw->tw_refcnt), tw);
}
#define TMPSZ 150
@@ -2505,11 +2504,10 @@
static int tcp4_seq_show(struct seq_file *seq, void *v)
{
struct tcp_iter_state *st;
- int len;
+ seq_setwidth(seq, TMPSZ - 1);
if (v == SEQ_START_TOKEN) {
- seq_printf(seq, "%-*s\n", TMPSZ - 1,
- " sl local_address rem_address st tx_queue "
+ seq_puts(seq, " sl local_address rem_address st tx_queue "
"rx_queue tr tm->when retrnsmt uid timeout "
"inode");
goto out;
@@ -2519,17 +2517,17 @@
switch (st->state) {
case TCP_SEQ_STATE_LISTENING:
case TCP_SEQ_STATE_ESTABLISHED:
- get_tcp4_sock(v, seq, st->num, &len);
+ get_tcp4_sock(v, seq, st->num);
break;
case TCP_SEQ_STATE_OPENREQ:
- get_openreq4(st->syn_wait_sk, v, seq, st->num, st->uid, &len);
+ get_openreq4(st->syn_wait_sk, v, seq, st->num, st->uid);
break;
case TCP_SEQ_STATE_TIME_WAIT:
- get_timewait4_sock(v, seq, st->num, &len);
+ get_timewait4_sock(v, seq, st->num);
break;
}
- seq_printf(seq, "%*s\n", TMPSZ - 1 - len, "");
out:
+ seq_pad(seq, '\n');
return 0;
}
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index fe14105..7c9e1ab 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -2080,7 +2080,7 @@
/* ------------------------------------------------------------------------ */
static void udp4_format_sock(struct sock *sp, struct seq_file *f,
- int bucket, int *len)
+ int bucket)
{
struct inet_sock *inet = inet_sk(sp);
__be32 dest = inet->inet_daddr;
@@ -2089,29 +2089,28 @@
__u16 srcp = ntohs(inet->inet_sport);
seq_printf(f, "%5d: %08X:%04X %08X:%04X"
- " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %pK %d%n",
+ " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %pK %d",
bucket, src, srcp, dest, destp, sp->sk_state,
sk_wmem_alloc_get(sp),
sk_rmem_alloc_get(sp),
0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp),
atomic_read(&sp->sk_refcnt), sp,
- atomic_read(&sp->sk_drops), len);
+ atomic_read(&sp->sk_drops));
}
int udp4_seq_show(struct seq_file *seq, void *v)
{
+ seq_setwidth(seq, 127);
if (v == SEQ_START_TOKEN)
- seq_printf(seq, "%-127s\n",
- " sl local_address rem_address st tx_queue "
+ seq_puts(seq, " sl local_address rem_address st tx_queue "
"rx_queue tr tm->when retrnsmt uid timeout "
"inode ref pointer drops");
else {
struct udp_iter_state *state = seq->private;
- int len;
- udp4_format_sock(v, seq, state->bucket, &len);
- seq_printf(seq, "%*s\n", 127 - len, "");
+ udp4_format_sock(v, seq, state->bucket);
}
+ seq_pad(seq, '\n');
return 0;
}
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index d85cf09..562f6b7 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1542,12 +1542,12 @@
if (input)
nlk_sk(sk)->netlink_rcv = input;
- if (netlink_insert(sk, net, 0))
- goto out_sock_release;
-
nlk = nlk_sk(sk);
nlk->flags |= NETLINK_KERNEL_SOCKET;
+ if (netlink_insert(sk, net, 0))
+ goto out_sock_release;
+
netlink_table_grab();
if (!nl_table[unit].registered) {
nl_table[unit].groups = groups;
diff --git a/net/phonet/socket.c b/net/phonet/socket.c
index 4c7eff3..0e3c6ec 100644
--- a/net/phonet/socket.c
+++ b/net/phonet/socket.c
@@ -598,25 +598,24 @@
static int pn_sock_seq_show(struct seq_file *seq, void *v)
{
- int len;
-
+ seq_setwidth(seq, 127);
if (v == SEQ_START_TOKEN)
- seq_printf(seq, "%s%n", "pt loc rem rs st tx_queue rx_queue "
- " uid inode ref pointer drops", &len);
+ seq_puts(seq, "pt loc rem rs st tx_queue rx_queue "
+ " uid inode ref pointer drops");
else {
struct sock *sk = v;
struct pn_sock *pn = pn_sk(sk);
seq_printf(seq, "%2d %04X:%04X:%02X %02X %08X:%08X %5d %lu "
- "%d %pK %d%n",
+ "%d %pK %d",
sk->sk_protocol, pn->sobject, pn->dobject,
pn->resource, sk->sk_state,
sk_wmem_alloc_get(sk), sk_rmem_alloc_get(sk),
sock_i_uid(sk), sock_i_ino(sk),
atomic_read(&sk->sk_refcnt), sk,
- atomic_read(&sk->sk_drops), &len);
+ atomic_read(&sk->sk_drops));
}
- seq_printf(seq, "%*s\n", 127 - len, "");
+ seq_pad(seq, '\n');
return 0;
}
@@ -787,19 +786,19 @@
static int pn_res_seq_show(struct seq_file *seq, void *v)
{
- int len;
-
+ seq_setwidth(seq, 63);
if (v == SEQ_START_TOKEN)
- seq_printf(seq, "%s%n", "rs uid inode", &len);
+ seq_puts(seq, "rs uid inode");
else {
struct sock **psk = v;
struct sock *sk = *psk;
- seq_printf(seq, "%02X %5d %lu%n",
- (int) (psk - pnres.sk), sock_i_uid(sk),
- sock_i_ino(sk), &len);
+ seq_printf(seq, "%02X %5d %lu",
+ (int) (psk - pnres.sk),
+ from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)),
+ sock_i_ino(sk));
}
- seq_printf(seq, "%*s\n", 63 - len, "");
+ seq_pad(seq, '\n');
return 0;
}
diff --git a/net/sctp/objcnt.c b/net/sctp/objcnt.c
index 8ef8e7d..d1e259c 100644
--- a/net/sctp/objcnt.c
+++ b/net/sctp/objcnt.c
@@ -85,12 +85,13 @@
*/
static int sctp_objcnt_seq_show(struct seq_file *seq, void *v)
{
- int i, len;
+ int i;
i = (int)*(loff_t *)v;
- seq_printf(seq, "%s: %d%n", sctp_dbg_objcnt[i].label,
- atomic_read(sctp_dbg_objcnt[i].counter), &len);
- seq_printf(seq, "%*s\n", 127 - len, "");
+ seq_setwidth(seq, 127);
+ seq_printf(seq, "%s: %d", sctp_dbg_objcnt[i].label,
+ atomic_read(sctp_dbg_objcnt[i].counter));
+ seq_pad(seq, '\n');
return 0;
}
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index 9bd1652..a49866c 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -845,9 +845,9 @@
if (mbhc->micbias_enable && mbhc->micbias_enable_cb) {
pr_debug("%s: Disabling micbias\n", __func__);
+ mbhc->micbias_enable = false;
mbhc->micbias_enable_cb(mbhc->codec, false,
mbhc->mbhc_cfg->micbias);
- mbhc->micbias_enable = false;
}
mbhc->zl = mbhc->zr = 0;
pr_debug("%s: Reporting removal %d(%x)\n", __func__,
@@ -872,9 +872,9 @@
if (mbhc->micbias_enable && mbhc->micbias_enable_cb &&
mbhc->hph_status == SND_JACK_HEADSET) {
pr_debug("%s: Disabling micbias\n", __func__);
+ mbhc->micbias_enable = false;
mbhc->micbias_enable_cb(mbhc->codec, false,
mbhc->mbhc_cfg->micbias);
- mbhc->micbias_enable = false;
}
pr_debug("%s: Reporting removal (%x)\n",