summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/regulator/qpnp-oledb-regulator.txt6
-rw-r--r--Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt4
-rw-r--r--arch/arm/boot/dts/qcom/msm-pm660l.dtsi1
-rw-r--r--arch/arm/boot/dts/qcom/msm8998.dtsi1
-rw-r--r--arch/arm/boot/dts/qcom/sdm630.dtsi1
-rw-r--r--arch/arm/boot/dts/qcom/sdm660.dtsi1
-rw-r--r--arch/arm64/configs/msmcortex_mediabox_defconfig1
-rw-r--r--drivers/clk/qcom/clk-cpu-osm.c2
-rw-r--r--drivers/clk/qcom/gcc-sdm660.c4
-rw-r--r--drivers/crypto/msm/qcedev.c51
-rw-r--r--drivers/leds/leds-qpnp-flash-v2.c20
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c53
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c5
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c3
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c2
-rw-r--r--drivers/net/wireless/ath/wil6210/pcie_bus.c16
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h9
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c11
-rw-r--r--drivers/pci/host/pci-msm.c36
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa.c10
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_i.h8
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_utils.c78
-rw-r--r--drivers/power/supply/qcom/battery.c51
-rw-r--r--drivers/power/supply/qcom/qpnp-qnovo.c37
-rw-r--r--drivers/power/supply/qcom/qpnp-smb2.c18
-rw-r--r--drivers/power/supply/qcom/smb-lib.c792
-rw-r--r--drivers/power/supply/qcom/smb-lib.h18
-rw-r--r--drivers/regulator/qpnp-oledb-regulator.c16
-rw-r--r--drivers/soc/qcom/qpnp-haptic.c92
-rw-r--r--drivers/soc/qcom/spcom.c2
-rw-r--r--drivers/spmi/spmi-pmic-arb.c13
-rw-r--r--drivers/staging/android/lowmemorykiller.c34
-rw-r--r--drivers/usb/phy/phy-msm-ssusb-qmp.c15
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_cdm.c13
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_intf_video.c15
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c4
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_overlay.c12
-rw-r--r--fs/ext4/inline.c14
-rw-r--r--fs/ext4/inode.c54
-rw-r--r--fs/ext4/readpage.c47
-rw-r--r--fs/f2fs/data.c41
-rw-r--r--fs/f2fs/inline.c18
-rw-r--r--fs/mpage.c36
-rw-r--r--include/linux/shrinker.h1
-rw-r--r--include/trace/events/android_fs.h65
-rw-r--r--include/trace/events/android_fs_template.h57
-rw-r--r--mm/vmscan.c54
-rw-r--r--sound/soc/msm/msm8998.c22
-rw-r--r--sound/soc/msm/qdsp6v2/q6afe.c2
49 files changed, 1284 insertions, 582 deletions
diff --git a/Documentation/devicetree/bindings/regulator/qpnp-oledb-regulator.txt b/Documentation/devicetree/bindings/regulator/qpnp-oledb-regulator.txt
index 38f599ba5321..efff6c79a9c0 100644
--- a/Documentation/devicetree/bindings/regulator/qpnp-oledb-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/qpnp-oledb-regulator.txt
@@ -14,6 +14,11 @@ Required Node Structure
Value type: <string>
Definition: should be "qcom,qpnp-oledb-regulator".
+- qcom,pmic-revid
+ Usage: required
+ Value type: <phandle>
+ Definition: Used to identify the PMIC subtype.
+
- reg
Usage: required
Value type: <prop-encoded-array>
@@ -224,6 +229,7 @@ pm660a_oledb: qpnp-oledb@e000 {
compatible = "qcom,qpnp-oledb-regulator";
#address-cells = <1>;
#size-cells = <1>;
+ qcom,pmic-revid = <&pm660l_revid>;
reg = <0xe000 0x100>;
label = "oledb";
diff --git a/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt
index bef919334574..633abd2b8d08 100644
--- a/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt
+++ b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.txt
@@ -42,6 +42,9 @@ Required properties:
cell 4: interrupt flags indicating level-sense information, as defined in
dt-bindings/interrupt-controller/irq.h
+Optional properties:
+- qcom,reserved-chan : Reserved channel for debug purpose
+
Example V1 PMIC-Arbiter:
spmi {
@@ -56,6 +59,7 @@ Example V1 PMIC-Arbiter:
qcom,ee = <0>;
qcom,channel = <0>;
+ qcom,reserved-chan = <511>;
#address-cells = <2>;
#size-cells = <0>;
diff --git a/arch/arm/boot/dts/qcom/msm-pm660l.dtsi b/arch/arm/boot/dts/qcom/msm-pm660l.dtsi
index fdc04b9726b4..236565af6af2 100644
--- a/arch/arm/boot/dts/qcom/msm-pm660l.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-pm660l.dtsi
@@ -415,6 +415,7 @@
compatible = "qcom,qpnp-oledb-regulator";
#address-cells = <1>;
#size-cells = <1>;
+ qcom,pmic-revid = <&pm660l_revid>;
reg = <0xe000 0x100>;
label = "oledb";
diff --git a/arch/arm/boot/dts/qcom/msm8998.dtsi b/arch/arm/boot/dts/qcom/msm8998.dtsi
index 85142c6c755e..9b5092cf7f14 100644
--- a/arch/arm/boot/dts/qcom/msm8998.dtsi
+++ b/arch/arm/boot/dts/qcom/msm8998.dtsi
@@ -441,6 +441,7 @@
interrupts = <GIC_SPI 326 IRQ_TYPE_NONE>;
qcom,ee = <0>;
qcom,channel = <0>;
+ qcom,reserved-chan = <511>;
#address-cells = <2>;
#size-cells = <0>;
interrupt-controller;
diff --git a/arch/arm/boot/dts/qcom/sdm630.dtsi b/arch/arm/boot/dts/qcom/sdm630.dtsi
index 0011e1d75321..24a935ffebec 100644
--- a/arch/arm/boot/dts/qcom/sdm630.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm630.dtsi
@@ -1988,6 +1988,7 @@
interrupts = <GIC_SPI 326 IRQ_TYPE_NONE>;
qcom,ee = <0>;
qcom,channel = <0>;
+ qcom,reserved-chan = <511>;
#address-cells = <2>;
#size-cells = <0>;
interrupt-controller;
diff --git a/arch/arm/boot/dts/qcom/sdm660.dtsi b/arch/arm/boot/dts/qcom/sdm660.dtsi
index be200f8dd531..2e576a51677f 100644
--- a/arch/arm/boot/dts/qcom/sdm660.dtsi
+++ b/arch/arm/boot/dts/qcom/sdm660.dtsi
@@ -466,6 +466,7 @@
interrupts = <GIC_SPI 326 IRQ_TYPE_NONE>;
qcom,ee = <0>;
qcom,channel = <0>;
+ qcom,reserved-chan = <511>;
#address-cells = <2>;
#size-cells = <0>;
interrupt-controller;
diff --git a/arch/arm64/configs/msmcortex_mediabox_defconfig b/arch/arm64/configs/msmcortex_mediabox_defconfig
index 29a511d3eec5..3322f8fa11fc 100644
--- a/arch/arm64/configs/msmcortex_mediabox_defconfig
+++ b/arch/arm64/configs/msmcortex_mediabox_defconfig
@@ -194,6 +194,7 @@ CONFIG_L2TP_V3=y
CONFIG_L2TP_IP=y
CONFIG_L2TP_ETH=y
CONFIG_BRIDGE=y
+CONFIG_VLAN_8021Q=y
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_HTB=y
CONFIG_NET_SCH_PRIO=y
diff --git a/drivers/clk/qcom/clk-cpu-osm.c b/drivers/clk/qcom/clk-cpu-osm.c
index f82ddc3b008b..d3914ab5f47c 100644
--- a/drivers/clk/qcom/clk-cpu-osm.c
+++ b/drivers/clk/qcom/clk-cpu-osm.c
@@ -772,7 +772,7 @@ static const char * const gcc_parent_names_1[] = {
};
static struct freq_tbl ftbl_osm_clk_src[] = {
- F(200000000, LMH_LITE_CLK_SRC, 3, 0, 0),
+ F(200000000, LMH_LITE_CLK_SRC, 1.5, 0, 0),
{ }
};
diff --git a/drivers/clk/qcom/gcc-sdm660.c b/drivers/clk/qcom/gcc-sdm660.c
index b55310e091af..b10f9ca9fe1a 100644
--- a/drivers/clk/qcom/gcc-sdm660.c
+++ b/drivers/clk/qcom/gcc-sdm660.c
@@ -732,6 +732,7 @@ static struct clk_rcg2 gp3_clk_src = {
};
static const struct freq_tbl ftbl_hmss_gpll0_clk_src[] = {
+ F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0),
F(600000000, P_GPLL0_OUT_MAIN, 1, 0, 0),
{ }
};
@@ -2755,6 +2756,9 @@ static int gcc_660_probe(struct platform_device *pdev)
/* Keep bimc gfx clock port on all the time */
clk_prepare_enable(gcc_bimc_gfx_clk.clkr.hw.clk);
+ /* Set the HMSS_GPLL0_SRC for 300MHz to CPU subsystem */
+ clk_set_rate(hmss_gpll0_clk_src.clkr.hw.clk, 300000000);
+
dev_info(&pdev->dev, "Registered GCC clocks\n");
return ret;
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index 7459401979fe..d04ca6f28f90 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -56,6 +56,7 @@ static uint8_t _std_init_vector_sha256_uint8[] = {
static DEFINE_MUTEX(send_cmd_lock);
static DEFINE_MUTEX(qcedev_sent_bw_req);
+static DEFINE_MUTEX(hash_access_lock);
static void qcedev_ce_high_bw_req(struct qcedev_control *podev,
bool high_bw_req)
@@ -1648,12 +1649,18 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
(void __user *)arg,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
- if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev))
+ mutex_lock(&hash_access_lock);
+ if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev)) {
+ mutex_unlock(&hash_access_lock);
return -EINVAL;
+ }
qcedev_areq.op_type = QCEDEV_CRYPTO_OPER_SHA;
err = qcedev_hash_init(&qcedev_areq, handle, &sg_src);
- if (err)
+ if (err) {
+ mutex_unlock(&hash_access_lock);
return err;
+ }
+ mutex_unlock(&hash_access_lock);
if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
@@ -1671,32 +1678,42 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
(void __user *)arg,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
- if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev))
+ mutex_lock(&hash_access_lock);
+ if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev)) {
+ mutex_unlock(&hash_access_lock);
return -EINVAL;
+ }
qcedev_areq.op_type = QCEDEV_CRYPTO_OPER_SHA;
if (qcedev_areq.sha_op_req.alg == QCEDEV_ALG_AES_CMAC) {
err = qcedev_hash_cmac(&qcedev_areq, handle, &sg_src);
- if (err)
+ if (err) {
+ mutex_unlock(&hash_access_lock);
return err;
+ }
} else {
if (handle->sha_ctxt.init_done == false) {
pr_err("%s Init was not called\n", __func__);
+ mutex_unlock(&hash_access_lock);
return -EINVAL;
}
err = qcedev_hash_update(&qcedev_areq, handle, &sg_src);
- if (err)
+ if (err) {
+ mutex_unlock(&hash_access_lock);
return err;
+ }
}
if (handle->sha_ctxt.diglen > QCEDEV_MAX_SHA_DIGEST) {
pr_err("Invalid sha_ctxt.diglen %d\n",
handle->sha_ctxt.diglen);
+ mutex_unlock(&hash_access_lock);
return -EINVAL;
}
memcpy(&qcedev_areq.sha_op_req.digest[0],
&handle->sha_ctxt.digest[0],
handle->sha_ctxt.diglen);
+ mutex_unlock(&hash_access_lock);
if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
@@ -1713,16 +1730,22 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
(void __user *)arg,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
- if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev))
+ mutex_lock(&hash_access_lock);
+ if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev)) {
+ mutex_unlock(&hash_access_lock);
return -EINVAL;
+ }
qcedev_areq.op_type = QCEDEV_CRYPTO_OPER_SHA;
err = qcedev_hash_final(&qcedev_areq, handle);
- if (err)
+ if (err) {
+ mutex_unlock(&hash_access_lock);
return err;
+ }
qcedev_areq.sha_op_req.diglen = handle->sha_ctxt.diglen;
memcpy(&qcedev_areq.sha_op_req.digest[0],
&handle->sha_ctxt.digest[0],
handle->sha_ctxt.diglen);
+ mutex_unlock(&hash_access_lock);
if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
@@ -1737,20 +1760,28 @@ long qcedev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
(void __user *)arg,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
- if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev))
+ mutex_lock(&hash_access_lock);
+ if (qcedev_check_sha_params(&qcedev_areq.sha_op_req, podev)) {
+ mutex_unlock(&hash_access_lock);
return -EINVAL;
+ }
qcedev_areq.op_type = QCEDEV_CRYPTO_OPER_SHA;
qcedev_hash_init(&qcedev_areq, handle, &sg_src);
err = qcedev_hash_update(&qcedev_areq, handle, &sg_src);
- if (err)
+ if (err) {
+ mutex_unlock(&hash_access_lock);
return err;
+ }
err = qcedev_hash_final(&qcedev_areq, handle);
- if (err)
+ if (err) {
+ mutex_unlock(&hash_access_lock);
return err;
+ }
qcedev_areq.sha_op_req.diglen = handle->sha_ctxt.diglen;
memcpy(&qcedev_areq.sha_op_req.digest[0],
&handle->sha_ctxt.digest[0],
handle->sha_ctxt.diglen);
+ mutex_unlock(&hash_access_lock);
if (copy_to_user((void __user *)arg, &qcedev_areq.sha_op_req,
sizeof(struct qcedev_sha_op_req)))
return -EFAULT;
diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c
index 4c28e0922c84..de5c61418d07 100644
--- a/drivers/leds/leds-qpnp-flash-v2.c
+++ b/drivers/leds/leds-qpnp-flash-v2.c
@@ -152,7 +152,6 @@
#define FLASH_LED_MOD_ENABLE BIT(7)
#define FLASH_LED_DISABLE 0x00
#define FLASH_LED_SAFETY_TMR_DISABLED 0x13
-#define FLASH_LED_MIN_CURRENT_MA 25
#define FLASH_LED_MAX_TOTAL_CURRENT_MA 3750
/* notifier call chain for flash-led irqs */
@@ -879,11 +878,12 @@ static int qpnp_flash_led_get_max_avail_current(struct qpnp_flash_led *led)
static void qpnp_flash_led_node_set(struct flash_node_data *fnode, int value)
{
int prgm_current_ma = value;
+ int min_ma = fnode->ires_ua / 1000;
if (value <= 0)
prgm_current_ma = 0;
- else if (value < FLASH_LED_MIN_CURRENT_MA)
- prgm_current_ma = FLASH_LED_MIN_CURRENT_MA;
+ else if (value < min_ma)
+ prgm_current_ma = min_ma;
prgm_current_ma = min(prgm_current_ma, fnode->max_current);
fnode->current_ma = prgm_current_ma;
@@ -1335,7 +1335,7 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
struct flash_node_data *fnode, struct device_node *node)
{
const char *temp_string;
- int rc;
+ int rc, min_ma;
u32 val;
bool strobe_sel = 0, edge_trigger = 0, active_high = 0;
@@ -1391,10 +1391,11 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
return rc;
}
+ min_ma = fnode->ires_ua / 1000;
rc = of_property_read_u32(node, "qcom,max-current", &val);
if (!rc) {
- if (val < FLASH_LED_MIN_CURRENT_MA)
- val = FLASH_LED_MIN_CURRENT_MA;
+ if (val < min_ma)
+ val = min_ma;
fnode->max_current = val;
fnode->cdev.max_brightness = val;
} else {
@@ -1404,11 +1405,10 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
rc = of_property_read_u32(node, "qcom,current-ma", &val);
if (!rc) {
- if (val < FLASH_LED_MIN_CURRENT_MA ||
- val > fnode->max_current)
+ if (val < min_ma || val > fnode->max_current)
pr_warn("Invalid operational current specified, capping it\n");
- if (val < FLASH_LED_MIN_CURRENT_MA)
- val = FLASH_LED_MIN_CURRENT_MA;
+ if (val < min_ma)
+ val = min_ma;
if (val > fnode->max_current)
val = fnode->max_current;
fnode->current_ma = val;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index dce474e40470..5f1c9c2f9436 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -773,6 +773,40 @@ void msm_isp_check_for_output_error(struct vfe_device *vfe_dev,
}
}
+static int msm_isp_check_sync_time(struct msm_vfe_src_info *src_info,
+ struct msm_isp_timestamp *ts,
+ struct master_slave_resource_info *ms_res)
+{
+ int i;
+ struct msm_vfe_src_info *master_src_info = NULL;
+ uint32_t master_time = 0, current_time;
+
+ if (!ms_res->src_sof_mask)
+ return 0;
+
+ for (i = 0; i < MAX_VFE * VFE_SRC_MAX; i++) {
+ if (ms_res->src_info[i] == NULL)
+ continue;
+ if (src_info == ms_res->src_info[i] ||
+ ms_res->src_info[i]->active == 0)
+ continue;
+ if (ms_res->src_sof_mask &
+ (1 << ms_res->src_info[i]->dual_hw_ms_info.index)) {
+ master_src_info = ms_res->src_info[i];
+ break;
+ }
+ }
+ if (!master_src_info)
+ return 0;
+ master_time = master_src_info->
+ dual_hw_ms_info.sof_info.mono_timestamp_ms;
+ current_time = ts->buf_time.tv_sec * 1000 +
+ ts->buf_time.tv_usec / 1000;
+ if ((current_time - master_time) > ms_res->sof_delta_threshold)
+ return 1;
+ return 0;
+}
+
static void msm_isp_sync_dual_cam_frame_id(
struct vfe_device *vfe_dev,
struct master_slave_resource_info *ms_res,
@@ -787,11 +821,24 @@ static void msm_isp_sync_dual_cam_frame_id(
if (src_info->dual_hw_ms_info.sync_state ==
ms_res->dual_sync_mode) {
- (frame_src == VFE_PIX_0) ? src_info->frame_id +=
+ if (msm_isp_check_sync_time(src_info, ts, ms_res) == 0) {
+ (frame_src == VFE_PIX_0) ? src_info->frame_id +=
vfe_dev->axi_data.src_info[frame_src].
sof_counter_step :
src_info->frame_id++;
- return;
+ return;
+ }
+ ms_res->src_sof_mask = 0;
+ ms_res->active_src_mask = 0;
+ for (i = 0; i < MAX_VFE * VFE_SRC_MAX; i++) {
+ if (ms_res->src_info[i] == NULL)
+ continue;
+ if (ms_res->src_info[i]->active == 0)
+ continue;
+ ms_res->src_info[i]->dual_hw_ms_info.
+ sync_state =
+ MSM_ISP_DUAL_CAM_ASYNC;
+ }
}
WARN_ON(ms_res->dual_sync_mode == MSM_ISP_DUAL_CAM_ASYNC);
@@ -948,8 +995,6 @@ static void msm_isp_update_pd_stats_idx(struct vfe_device *vfe_dev,
uint32_t pingpong_status = 0, pingpong_bit = 0;
struct msm_isp_buffer *done_buf = NULL;
int vfe_idx = -1;
- /* initialize pd_buf_idx with an invalid index 0xF */
- vfe_dev->pd_buf_idx = 0xF;
if (frame_src < VFE_RAW_0 || frame_src > VFE_RAW_2)
return;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
index f2cf4d477b3f..f92c67150215 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c
@@ -228,9 +228,10 @@ static int32_t msm_isp_stats_buf_divert(struct vfe_device *vfe_dev,
done_buf->buf_idx;
stats_event->pd_stats_idx = 0xF;
- if (stream_info->stats_type == MSM_ISP_STATS_BF)
+ if (stream_info->stats_type == MSM_ISP_STATS_BF) {
stats_event->pd_stats_idx = vfe_dev->pd_buf_idx;
-
+ vfe_dev->pd_buf_idx = 0xF;
+ }
if (comp_stats_type_mask == NULL) {
stats_event->stats_mask =
1 << stream_info->stats_type;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index e7be914ca267..2a9bb6e8e505 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -2315,6 +2315,9 @@ int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
vfe_dev->reg_update_requested = 0;
/* Register page fault handler */
vfe_dev->buf_mgr->pagefault_debug_disable = 0;
+ /* initialize pd_buf_idx with an invalid index 0xF */
+ vfe_dev->pd_buf_idx = 0xF;
+
cam_smmu_reg_client_page_fault_handler(
vfe_dev->buf_mgr->iommu_hdl,
msm_vfe_iommu_fault_handler, vfe_dev);
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 476521b77008..37898146f01d 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -1414,6 +1414,8 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);
wil_set_recovery_state(wil, fw_recovery_idle);
+ set_bit(wil_status_resetting, wil->status);
+
mutex_lock(&wil->mutex);
wmi_pcp_stop(wil);
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index d472e13fb9d9..2a515e848820 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -26,6 +26,10 @@ static bool use_msi = true;
module_param(use_msi, bool, 0444);
MODULE_PARM_DESC(use_msi, " Use MSI interrupt, default - true");
+static bool ftm_mode;
+module_param(ftm_mode, bool, 0444);
+MODULE_PARM_DESC(ftm_mode, " Set factory test mode, default - false");
+
#ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP
static int wil6210_pm_notify(struct notifier_block *notify_block,
@@ -36,13 +40,15 @@ static int wil6210_pm_notify(struct notifier_block *notify_block,
static
void wil_set_capabilities(struct wil6210_priv *wil)
{
+ const char *wil_fw_name;
u32 jtag_id = wil_r(wil, RGF_USER_JTAG_DEV_ID);
u8 chip_revision = (wil_r(wil, RGF_USER_REVISION_ID) &
RGF_USER_REVISION_ID_MASK);
bitmap_zero(wil->hw_capabilities, hw_capability_last);
bitmap_zero(wil->fw_capabilities, WMI_FW_CAPABILITY_MAX);
- wil->wil_fw_name = WIL_FW_NAME_DEFAULT;
+ wil->wil_fw_name = ftm_mode ? WIL_FW_NAME_FTM_DEFAULT :
+ WIL_FW_NAME_DEFAULT;
wil->chip_revision = chip_revision;
switch (jtag_id) {
@@ -51,9 +57,11 @@ void wil_set_capabilities(struct wil6210_priv *wil)
case REVISION_ID_SPARROW_D0:
wil->hw_name = "Sparrow D0";
wil->hw_version = HW_VER_SPARROW_D0;
- if (wil_fw_verify_file_exists(wil,
- WIL_FW_NAME_SPARROW_PLUS))
- wil->wil_fw_name = WIL_FW_NAME_SPARROW_PLUS;
+ wil_fw_name = ftm_mode ? WIL_FW_NAME_FTM_SPARROW_PLUS :
+ WIL_FW_NAME_SPARROW_PLUS;
+
+ if (wil_fw_verify_file_exists(wil, wil_fw_name))
+ wil->wil_fw_name = wil_fw_name;
break;
case REVISION_ID_SPARROW_B0:
wil->hw_name = "Sparrow B0";
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 9d3e7a4f911e..0529d10a8268 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -37,8 +37,13 @@ extern bool debug_fw;
extern bool disable_ap_sme;
#define WIL_NAME "wil6210"
-#define WIL_FW_NAME_DEFAULT "wil6210.fw" /* code Sparrow B0 */
-#define WIL_FW_NAME_SPARROW_PLUS "wil6210_sparrow_plus.fw" /* code Sparrow D0 */
+
+#define WIL_FW_NAME_DEFAULT "wil6210.fw"
+#define WIL_FW_NAME_FTM_DEFAULT "wil6210_ftm.fw"
+
+#define WIL_FW_NAME_SPARROW_PLUS "wil6210_sparrow_plus.fw"
+#define WIL_FW_NAME_FTM_SPARROW_PLUS "wil6210_sparrow_plus_ftm.fw"
+
#define WIL_BOARD_FILE_NAME "wil6210.brd" /* board & radio parameters */
#define WIL_DEFAULT_BUS_REQUEST_KBPS 128000 /* ~1Gbps */
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 83ef6eb57e53..41afbdc34c18 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -518,16 +518,16 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
assoc_resp_ielen = 0;
}
- mutex_lock(&wil->mutex);
if (test_bit(wil_status_resetting, wil->status) ||
!test_bit(wil_status_fwready, wil->status)) {
wil_err(wil, "status_resetting, cancel connect event, CID %d\n",
evt->cid);
- mutex_unlock(&wil->mutex);
/* no need for cleanup, wil_reset will do that */
return;
}
+ mutex_lock(&wil->mutex);
+
if ((wdev->iftype == NL80211_IFTYPE_STATION) ||
(wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
if (!test_bit(wil_status_fwconnecting, wil->status)) {
@@ -631,6 +631,13 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
wil->sinfo_gen++;
+ if (test_bit(wil_status_resetting, wil->status) ||
+ !test_bit(wil_status_fwready, wil->status)) {
+ wil_err(wil, "status_resetting, cancel disconnect event\n");
+ /* no need for cleanup, wil_reset will do that */
+ return;
+ }
+
mutex_lock(&wil->mutex);
wil6210_disconnect(wil, evt->bssid, reason_code, true);
mutex_unlock(&wil->mutex);
diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c
index 9dc678ce4a48..f364882943e1 100644
--- a/drivers/pci/host/pci-msm.c
+++ b/drivers/pci/host/pci-msm.c
@@ -5811,9 +5811,10 @@ static int msm_pcie_map_qgic_addr(struct msm_pcie_dev_t *dev,
struct msi_msg *msg)
{
struct iommu_domain *domain = iommu_get_domain_for_dev(&pdev->dev);
- int ret, bypass_en = 0;
+ struct iommu_domain_geometry geometry;
+ int ret, fastmap_en = 0, bypass_en = 0;
dma_addr_t iova;
- phys_addr_t pcie_base_addr, gicm_db_offset;
+ phys_addr_t gicm_db_offset;
msg->address_hi = 0;
msg->address_lo = dev->msi_gicm_addr;
@@ -5835,16 +5836,25 @@ static int msm_pcie_map_qgic_addr(struct msm_pcie_dev_t *dev,
if (bypass_en)
return 0;
- gicm_db_offset = dev->msi_gicm_addr -
- rounddown(dev->msi_gicm_addr, PAGE_SIZE);
- /*
- * Use PCIe DBI address as the IOVA since client cannot
- * use this address for their IOMMU mapping. This will
- * prevent any conflicts between PCIe host and
- * client's mapping.
- */
- pcie_base_addr = dev->res[MSM_PCIE_RES_DM_CORE].resource->start;
- iova = rounddown(pcie_base_addr, PAGE_SIZE);
+ iommu_domain_get_attr(domain, DOMAIN_ATTR_FAST, &fastmap_en);
+ if (fastmap_en) {
+ iommu_domain_get_attr(domain, DOMAIN_ATTR_GEOMETRY, &geometry);
+ iova = geometry.aperture_start;
+ PCIE_DBG(dev,
+ "PCIe: RC%d: Use client's IOVA 0x%llx to map QGIC MSI address\n",
+ dev->rc_idx, iova);
+ } else {
+ phys_addr_t pcie_base_addr;
+
+ /*
+ * Use PCIe DBI address as the IOVA since client cannot
+ * use this address for their IOMMU mapping. This will
+ * prevent any conflicts between PCIe host and
+ * client's mapping.
+ */
+ pcie_base_addr = dev->res[MSM_PCIE_RES_DM_CORE].resource->start;
+ iova = rounddown(pcie_base_addr, PAGE_SIZE);
+ }
ret = iommu_map(domain, iova, rounddown(dev->msi_gicm_addr, PAGE_SIZE),
PAGE_SIZE, IOMMU_READ | IOMMU_WRITE);
@@ -5855,6 +5865,8 @@ static int msm_pcie_map_qgic_addr(struct msm_pcie_dev_t *dev,
return -ENOMEM;
}
+ gicm_db_offset = dev->msi_gicm_addr -
+ rounddown(dev->msi_gicm_addr, PAGE_SIZE);
msg->address_lo = iova + gicm_db_offset;
return 0;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index ddff50834f03..7aaddbbdabaf 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -4036,6 +4036,7 @@ fail_register_device:
unregister_chrdev_region(ipa3_ctx->dev_num, 1);
if (ipa3_ctx->pipe_mem_pool)
gen_pool_destroy(ipa3_ctx->pipe_mem_pool);
+ ipa3_free_dma_task_for_gsi();
ipa3_destroy_flt_tbl_idrs();
idr_destroy(&ipa3_ctx->ipa_idr);
kmem_cache_destroy(ipa3_ctx->rx_pkt_wrapper_cache);
@@ -4551,6 +4552,13 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p,
goto fail_dma_pool;
}
+ /* allocate memory for DMA_TASK workaround */
+ result = ipa3_allocate_dma_task_for_gsi();
+ if (result) {
+ IPAERR("failed to allocate dma task\n");
+ goto fail_dma_task;
+ }
+
/* init the various list heads */
INIT_LIST_HEAD(&ipa3_ctx->hdr_tbl.head_hdr_entry_list);
for (i = 0; i < IPA_HDR_BIN_MAX; i++) {
@@ -4723,6 +4731,8 @@ fail_cdev_add:
fail_device_create:
unregister_chrdev_region(ipa3_ctx->dev_num, 1);
fail_alloc_chrdev_region:
+ ipa3_free_dma_task_for_gsi();
+fail_dma_task:
if (ipa3_ctx->pipe_mem_pool)
gen_pool_destroy(ipa3_ctx->pipe_mem_pool);
ipa3_destroy_flt_tbl_idrs();
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index 0cf77bbde496..ac7ef6a21952 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -1027,6 +1027,11 @@ struct ipa_tz_unlock_reg_info {
u32 size;
};
+struct ipa_dma_task_info {
+ struct ipa_mem_buffer mem;
+ struct ipahal_imm_cmd_pyld *cmd_pyld;
+};
+
/**
* struct ipa3_context - IPA context
* @class: pointer to the struct class
@@ -1246,6 +1251,7 @@ struct ipa3_context {
struct ipa3_smp2p_info smp2p_info;
u32 ipa_tz_unlock_reg_num;
struct ipa_tz_unlock_reg_info *ipa_tz_unlock_reg;
+ struct ipa_dma_task_info dma_task_info;
};
/**
@@ -2053,4 +2059,6 @@ int ipa3_get_ntn_stats(struct Ipa3HwStatsNTNInfoData_t *stats);
struct dentry *ipa_debugfs_get_root(void);
bool ipa3_is_msm_device(void);
struct device *ipa3_get_pdev(void);
+int ipa3_allocate_dma_task_for_gsi(void);
+void ipa3_free_dma_task_for_gsi(void);
#endif /* _IPA3_I_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index 14735787cb9c..f4a7319ca290 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -3483,6 +3483,51 @@ void ipa3_suspend_apps_pipes(bool suspend)
}
}
+int ipa3_allocate_dma_task_for_gsi(void)
+{
+ struct ipahal_imm_cmd_dma_task_32b_addr cmd = { 0 };
+
+ IPADBG("Allocate mem\n");
+ ipa3_ctx->dma_task_info.mem.size = IPA_GSI_CHANNEL_STOP_PKT_SIZE;
+ ipa3_ctx->dma_task_info.mem.base = dma_alloc_coherent(ipa3_ctx->pdev,
+ ipa3_ctx->dma_task_info.mem.size,
+ &ipa3_ctx->dma_task_info.mem.phys_base,
+ GFP_KERNEL);
+ if (!ipa3_ctx->dma_task_info.mem.base) {
+ IPAERR("no mem\n");
+ return -EFAULT;
+ }
+
+ cmd.flsh = 1;
+ cmd.size1 = ipa3_ctx->dma_task_info.mem.size;
+ cmd.addr1 = ipa3_ctx->dma_task_info.mem.phys_base;
+ cmd.packet_size = ipa3_ctx->dma_task_info.mem.size;
+ ipa3_ctx->dma_task_info.cmd_pyld = ipahal_construct_imm_cmd(
+ IPA_IMM_CMD_DMA_TASK_32B_ADDR, &cmd, false);
+ if (!ipa3_ctx->dma_task_info.cmd_pyld) {
+ IPAERR("failed to construct dma_task_32b_addr cmd\n");
+ dma_free_coherent(ipa3_ctx->pdev,
+ ipa3_ctx->dma_task_info.mem.size,
+ ipa3_ctx->dma_task_info.mem.base,
+ ipa3_ctx->dma_task_info.mem.phys_base);
+ memset(&ipa3_ctx->dma_task_info, 0,
+ sizeof(ipa3_ctx->dma_task_info));
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+void ipa3_free_dma_task_for_gsi(void)
+{
+ dma_free_coherent(ipa3_ctx->pdev,
+ ipa3_ctx->dma_task_info.mem.size,
+ ipa3_ctx->dma_task_info.mem.base,
+ ipa3_ctx->dma_task_info.mem.phys_base);
+ ipahal_destroy_imm_cmd(ipa3_ctx->dma_task_info.cmd_pyld);
+ memset(&ipa3_ctx->dma_task_info, 0, sizeof(ipa3_ctx->dma_task_info));
+}
+
/**
* ipa3_inject_dma_task_for_gsi()- Send DMA_TASK to IPA for GSI stop channel
*
@@ -3491,41 +3536,12 @@ void ipa3_suspend_apps_pipes(bool suspend)
*/
int ipa3_inject_dma_task_for_gsi(void)
{
- static struct ipa_mem_buffer mem = {0};
- struct ipahal_imm_cmd_dma_task_32b_addr cmd = {0};
- static struct ipahal_imm_cmd_pyld *cmd_pyld;
struct ipa3_desc desc = {0};
- /* allocate the memory only for the very first time */
- if (!mem.base) {
- IPADBG("Allocate mem\n");
- mem.size = IPA_GSI_CHANNEL_STOP_PKT_SIZE;
- mem.base = dma_alloc_coherent(ipa3_ctx->pdev,
- mem.size,
- &mem.phys_base,
- GFP_KERNEL);
- if (!mem.base) {
- IPAERR("no mem\n");
- return -EFAULT;
- }
- }
- if (!cmd_pyld) {
- cmd.flsh = 1;
- cmd.size1 = mem.size;
- cmd.addr1 = mem.phys_base;
- cmd.packet_size = mem.size;
- cmd_pyld = ipahal_construct_imm_cmd(
- IPA_IMM_CMD_DMA_TASK_32B_ADDR, &cmd, false);
- if (!cmd_pyld) {
- IPAERR("failed to construct dma_task_32b_addr cmd\n");
- return -EFAULT;
- }
- }
-
desc.opcode = ipahal_imm_cmd_get_opcode_param(
IPA_IMM_CMD_DMA_TASK_32B_ADDR, 1);
- desc.pyld = cmd_pyld->data;
- desc.len = cmd_pyld->len;
+ desc.pyld = ipa3_ctx->dma_task_info.cmd_pyld->data;
+ desc.len = ipa3_ctx->dma_task_info.cmd_pyld->len;
desc.type = IPA_IMM_CMD_DESC;
IPADBG("sending 1B packet to IPA\n");
diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c
index 67f9d4fafeb8..539e757d3e99 100644
--- a/drivers/power/supply/qcom/battery.c
+++ b/drivers/power/supply/qcom/battery.c
@@ -434,23 +434,28 @@ static int pl_fcc_vote_callback(struct votable *votable, void *data,
return rc;
}
- split_fcc(chip, total_fcc_ua, &master_fcc_ua, &slave_fcc_ua);
- pval.intval = slave_fcc_ua;
- rc = power_supply_set_property(chip->pl_psy,
- POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval);
- if (rc < 0) {
- pr_err("Couldn't set parallel fcc, rc=%d\n", rc);
- return rc;
- }
+ if (chip->pl_mode != POWER_SUPPLY_PL_NONE) {
+ split_fcc(chip, total_fcc_ua, &master_fcc_ua, &slave_fcc_ua);
+
+ pval.intval = slave_fcc_ua;
+ rc = power_supply_set_property(chip->pl_psy,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+ &pval);
+ if (rc < 0) {
+ pr_err("Couldn't set parallel fcc, rc=%d\n", rc);
+ return rc;
+ }
- chip->slave_fcc_ua = slave_fcc_ua;
+ chip->slave_fcc_ua = slave_fcc_ua;
- pval.intval = master_fcc_ua;
- rc = power_supply_set_property(chip->main_psy,
- POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval);
- if (rc < 0) {
- pr_err("Could not set main fcc, rc=%d\n", rc);
- return rc;
+ pval.intval = master_fcc_ua;
+ rc = power_supply_set_property(chip->main_psy,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+ &pval);
+ if (rc < 0) {
+ pr_err("Could not set main fcc, rc=%d\n", rc);
+ return rc;
+ }
}
pl_dbg(chip, PR_PARALLEL, "master_fcc=%d slave_fcc=%d distribution=(%d/%d)\n",
@@ -685,9 +690,6 @@ static bool is_main_available(struct pl_data *chip)
chip->main_psy = power_supply_get_by_name("main");
- if (chip->main_psy)
- rerun_election(chip->usb_icl_votable);
-
return !!chip->main_psy;
}
@@ -866,7 +868,18 @@ static void status_change_work(struct work_struct *work)
struct pl_data *chip = container_of(work,
struct pl_data, status_change_work);
- if (!is_main_available(chip))
+ if (!chip->main_psy && is_main_available(chip)) {
+ /*
+ * re-run election for FCC/FV/ICL once main_psy
+ * is available to ensure all votes are reflected
+ * on hardware
+ */
+ rerun_election(chip->usb_icl_votable);
+ rerun_election(chip->fcc_votable);
+ rerun_election(chip->fv_votable);
+ }
+
+ if (!chip->main_psy)
return;
if (!is_batt_available(chip))
diff --git a/drivers/power/supply/qcom/qpnp-qnovo.c b/drivers/power/supply/qcom/qpnp-qnovo.c
index c74dc8989821..eb97eb0ff2ac 100644
--- a/drivers/power/supply/qcom/qpnp-qnovo.c
+++ b/drivers/power/supply/qcom/qpnp-qnovo.c
@@ -89,7 +89,16 @@
#define QNOVO_STRM_CTRL 0xA8
#define QNOVO_IADC_OFFSET_OVR_VAL 0xA9
#define QNOVO_IADC_OFFSET_OVR 0xAA
+
#define QNOVO_DISABLE_CHARGING 0xAB
+#define ERR_SWITCHER_DISABLED BIT(7)
+#define ERR_JEITA_SOFT_CONDITION BIT(6)
+#define ERR_BAT_OV BIT(5)
+#define ERR_CV_MODE BIT(4)
+#define ERR_BATTERY_MISSING BIT(3)
+#define ERR_SAFETY_TIMER_EXPIRED BIT(2)
+#define ERR_CHARGING_DISABLED BIT(1)
+#define ERR_JEITA_HARD_CONDITION BIT(0)
#define QNOVO_TR_IADC_OFFSET_0 0xF1
#define QNOVO_TR_IADC_OFFSET_1 0xF2
@@ -1107,24 +1116,28 @@ static int qnovo_update_status(struct qnovo *chip)
{
u8 val = 0;
int rc;
- bool charging;
+ bool ok_to_qnovo;
bool changed = false;
rc = qnovo_read(chip, QNOVO_ERROR_STS2, &val, 1);
if (rc < 0) {
pr_err("Couldn't read error sts rc = %d\n", rc);
- charging = false;
+ ok_to_qnovo = false;
} else {
- charging = !(val & QNOVO_ERROR_CHARGING_DISABLED);
+ /*
+ * For CV mode keep qnovo enabled, userspace is expected to
+ * disable it after few runs
+ */
+ ok_to_qnovo = (val == ERR_CV_MODE || val == 0) ? true : false;
}
- if (chip->ok_to_qnovo ^ charging) {
+ if (chip->ok_to_qnovo ^ ok_to_qnovo) {
- vote(chip->disable_votable, OK_TO_QNOVO_VOTER, !charging, 0);
- if (!charging)
+ vote(chip->disable_votable, OK_TO_QNOVO_VOTER, !ok_to_qnovo, 0);
+ if (!ok_to_qnovo)
vote(chip->disable_votable, USER_VOTER, true, 0);
- chip->ok_to_qnovo = charging;
+ chip->ok_to_qnovo = ok_to_qnovo;
changed = true;
}
@@ -1247,6 +1260,16 @@ static int qnovo_hw_init(struct qnovo *chip)
chip->v_gain_mega = 1000000000 + (s64)(s8)vadc_gain * GAIN_LSB_FACTOR;
chip->v_gain_mega = div_s64(chip->v_gain_mega, 1000);
+ /* allow charger error conditions to disable qnovo, CV mode excluded */
+ val = ERR_SWITCHER_DISABLED | ERR_JEITA_SOFT_CONDITION | ERR_BAT_OV |
+ ERR_BATTERY_MISSING | ERR_SAFETY_TIMER_EXPIRED |
+ ERR_CHARGING_DISABLED | ERR_JEITA_HARD_CONDITION;
+ rc = qnovo_write(chip, QNOVO_DISABLE_CHARGING, &val, 1);
+ if (rc < 0) {
+ pr_err("Couldn't write QNOVO_DISABLE_CHARGING rc = %d\n", rc);
+ return rc;
+ }
+
return 0;
}
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index c7d6937bcc49..8855a1c74e0b 100644
--- a/drivers/power/supply/qcom/qpnp-smb2.c
+++ b/drivers/power/supply/qcom/qpnp-smb2.c
@@ -540,6 +540,12 @@ static int smb2_usb_set_prop(struct power_supply *psy,
struct smb_charger *chg = &chip->chg;
int rc = 0;
+ mutex_lock(&chg->lock);
+ if (!chg->typec_present) {
+ rc = -EINVAL;
+ goto unlock;
+ }
+
switch (psp) {
case POWER_SUPPLY_PROP_VOLTAGE_MIN:
rc = smblib_set_prop_usb_voltage_min(chg, val);
@@ -578,6 +584,8 @@ static int smb2_usb_set_prop(struct power_supply *psy,
break;
}
+unlock:
+ mutex_unlock(&chg->lock);
return rc;
}
@@ -1350,10 +1358,12 @@ static int smb2_configure_typec(struct smb_charger *chg)
return rc;
}
- /* disable try.SINK mode */
- rc = smblib_masked_write(chg, TYPE_C_CFG_3_REG, EN_TRYSINK_MODE_BIT, 0);
+ /* disable try.SINK mode and legacy cable IRQs */
+ rc = smblib_masked_write(chg, TYPE_C_CFG_3_REG, EN_TRYSINK_MODE_BIT |
+ TYPEC_NONCOMPLIANT_LEGACY_CABLE_INT_EN_BIT |
+ TYPEC_LEGACY_CABLE_INT_EN_BIT, 0);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't set TRYSINK_MODE rc=%d\n", rc);
+ dev_err(chg->dev, "Couldn't set Type-C config rc=%d\n", rc);
return rc;
}
@@ -1509,6 +1519,8 @@ static int smb2_init_hw(struct smb2 *chip)
DEFAULT_VOTER, true, chip->dt.dc_icl_ua);
vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER,
true, 0);
+ vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
+ true, 0);
vote(chg->hvdcp_disable_votable_indirect, DEFAULT_VOTER,
chip->dt.hvdcp_disable, 0);
vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER,
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index 128b778c73ce..1e417e8aa22d 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -543,30 +543,6 @@ static void smblib_rerun_apsd(struct smb_charger *chg)
smblib_err(chg, "Couldn't re-run APSD rc=%d\n", rc);
}
-static int try_rerun_apsd_for_hvdcp(struct smb_charger *chg)
-{
- const struct apsd_result *apsd_result;
-
- /*
- * PD_INACTIVE_VOTER on hvdcp_disable_votable indicates whether
- * apsd rerun was tried earlier
- */
- if (get_client_vote(chg->hvdcp_disable_votable_indirect,
- PD_INACTIVE_VOTER)) {
- vote(chg->hvdcp_disable_votable_indirect,
- PD_INACTIVE_VOTER, false, 0);
- /* ensure hvdcp is enabled */
- if (!get_effective_result(
- chg->hvdcp_disable_votable_indirect)) {
- apsd_result = smblib_get_apsd_result(chg);
- if (apsd_result->bit & (QC_2P0_BIT | QC_3P0_BIT)) {
- smblib_rerun_apsd(chg);
- }
- }
- }
- return 0;
-}
-
static const struct apsd_result *smblib_update_usb_type(struct smb_charger *chg)
{
const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
@@ -1023,6 +999,7 @@ static int smblib_hvdcp_enable_vote_callback(struct votable *votable,
struct smb_charger *chg = data;
int rc;
u8 val = HVDCP_AUTH_ALG_EN_CFG_BIT | HVDCP_EN_BIT;
+ u8 stat;
/* vote to enable/disable HW autonomous INOV */
vote(chg->hvdcp_hw_inov_dis_votable, client, !hvdcp_enable, 0);
@@ -1044,6 +1021,16 @@ static int smblib_hvdcp_enable_vote_callback(struct votable *votable,
return rc;
}
+ rc = smblib_read(chg, APSD_STATUS_REG, &stat);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read APSD status rc=%d\n", rc);
+ return rc;
+ }
+
+ /* re-run APSD if HVDCP was detected */
+ if (stat & QC_CHARGER_BIT)
+ smblib_rerun_apsd(chg);
+
return 0;
}
@@ -1137,6 +1124,22 @@ static int smblib_usb_irq_enable_vote_callback(struct votable *votable,
return 0;
}
+static int smblib_typec_irq_disable_vote_callback(struct votable *votable,
+ void *data, int disable, const char *client)
+{
+ struct smb_charger *chg = data;
+
+ if (!chg->irq_info[TYPE_C_CHANGE_IRQ].irq)
+ return 0;
+
+ if (disable)
+ disable_irq_nosync(chg->irq_info[TYPE_C_CHANGE_IRQ].irq);
+ else
+ enable_irq(chg->irq_info[TYPE_C_CHANGE_IRQ].irq);
+
+ return 0;
+}
+
/*******************
* VCONN REGULATOR *
* *****************/
@@ -1145,7 +1148,7 @@ static int smblib_usb_irq_enable_vote_callback(struct votable *votable,
static int _smblib_vconn_regulator_enable(struct regulator_dev *rdev)
{
struct smb_charger *chg = rdev_get_drvdata(rdev);
- u8 otg_stat, stat4;
+ u8 otg_stat, val;
int rc = 0, i;
if (!chg->external_vconn) {
@@ -1176,17 +1179,12 @@ static int _smblib_vconn_regulator_enable(struct regulator_dev *rdev)
* VCONN_EN_ORIENTATION is overloaded with overriding the CC pin used
* for Vconn, and it should be set with reverse polarity of CC_OUT.
*/
- rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat4);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
- return rc;
- }
-
smblib_dbg(chg, PR_OTG, "enabling VCONN\n");
- stat4 = stat4 & CC_ORIENTATION_BIT ? 0 : VCONN_EN_ORIENTATION_BIT;
+ val = chg->typec_status[3] &
+ CC_ORIENTATION_BIT ? 0 : VCONN_EN_ORIENTATION_BIT;
rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
VCONN_EN_VALUE_BIT | VCONN_EN_ORIENTATION_BIT,
- VCONN_EN_VALUE_BIT | stat4);
+ VCONN_EN_VALUE_BIT | val);
if (rc < 0) {
smblib_err(chg, "Couldn't enable vconn setting rc=%d\n", rc);
return rc;
@@ -2149,23 +2147,13 @@ int smblib_get_prop_charger_temp_max(struct smb_charger *chg,
int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg,
union power_supply_propval *val)
{
- int rc = 0;
- u8 stat;
-
- rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
- return rc;
- }
- smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n",
- stat);
-
- if (stat & CC_ATTACHED_BIT)
- val->intval = (bool)(stat & CC_ORIENTATION_BIT) + 1;
+ if (chg->typec_status[3] & CC_ATTACHED_BIT)
+ val->intval =
+ (bool)(chg->typec_status[3] & CC_ORIENTATION_BIT) + 1;
else
val->intval = 0;
- return rc;
+ return 0;
}
static const char * const smblib_typec_mode_name[] = {
@@ -2183,17 +2171,7 @@ static const char * const smblib_typec_mode_name[] = {
static int smblib_get_prop_ufp_mode(struct smb_charger *chg)
{
- int rc;
- u8 stat;
-
- rc = smblib_read(chg, TYPE_C_STATUS_1_REG, &stat);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_STATUS_1 rc=%d\n", rc);
- return POWER_SUPPLY_TYPEC_NONE;
- }
- smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_1 = 0x%02x\n", stat);
-
- switch (stat) {
+ switch (chg->typec_status[0]) {
case 0:
return POWER_SUPPLY_TYPEC_NONE;
case UFP_TYPEC_RDSTD_BIT:
@@ -2211,17 +2189,7 @@ static int smblib_get_prop_ufp_mode(struct smb_charger *chg)
static int smblib_get_prop_dfp_mode(struct smb_charger *chg)
{
- int rc;
- u8 stat;
-
- rc = smblib_read(chg, TYPE_C_STATUS_2_REG, &stat);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_STATUS_2 rc=%d\n", rc);
- return POWER_SUPPLY_TYPEC_NONE;
- }
- smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_2 = 0x%02x\n", stat);
-
- switch (stat & DFP_TYPEC_MASK) {
+ switch (chg->typec_status[1] & DFP_TYPEC_MASK) {
case DFP_RA_RA_BIT:
return POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER;
case DFP_RD_RD_BIT:
@@ -2242,28 +2210,17 @@ static int smblib_get_prop_dfp_mode(struct smb_charger *chg)
int smblib_get_prop_typec_mode(struct smb_charger *chg,
union power_supply_propval *val)
{
- int rc;
- u8 stat;
-
- rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
+ if (!(chg->typec_status[3] & TYPEC_DEBOUNCE_DONE_STATUS_BIT)) {
val->intval = POWER_SUPPLY_TYPEC_NONE;
- return rc;
- }
- smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n", stat);
-
- if (!(stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT)) {
- val->intval = POWER_SUPPLY_TYPEC_NONE;
- return rc;
+ return 0;
}
- if (stat & UFP_DFP_MODE_STATUS_BIT)
+ if (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT)
val->intval = smblib_get_prop_dfp_mode(chg);
else
val->intval = smblib_get_prop_ufp_mode(chg);
- return rc;
+ return 0;
}
int smblib_get_prop_typec_power_role(struct smb_charger *chg,
@@ -2355,16 +2312,7 @@ int smblib_get_prop_input_voltage_settled(struct smb_charger *chg,
int smblib_get_prop_pd_in_hard_reset(struct smb_charger *chg,
union power_supply_propval *val)
{
- int rc;
- u8 ctrl;
-
- rc = smblib_read(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, &ctrl);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG rc=%d\n",
- rc);
- return rc;
- }
- val->intval = ctrl & EXIT_SNK_BASED_ON_CC_BIT;
+ val->intval = chg->pd_hard_reset;
return 0;
}
@@ -2560,53 +2508,60 @@ int smblib_set_prop_pd_active(struct smb_charger *chg,
const union power_supply_propval *val)
{
int rc;
- u8 stat = 0;
- bool cc_debounced;
- bool orientation;
- bool pd_active = val->intval;
+ bool orientation, cc_debounced, sink_attached, hvdcp;
+ u8 stat;
- if (!get_effective_result(chg->pd_allowed_votable)) {
- smblib_err(chg, "PD is not allowed\n");
+ if (!get_effective_result(chg->pd_allowed_votable))
return -EINVAL;
- }
-
- vote(chg->apsd_disable_votable, PD_VOTER, pd_active, 0);
- vote(chg->pd_allowed_votable, PD_VOTER, pd_active, 0);
- vote(chg->usb_irq_enable_votable, PD_VOTER, pd_active, 0);
- /*
- * VCONN_EN_ORIENTATION_BIT controls whether to use CC1 or CC2 line
- * when TYPEC_SPARE_CFG_BIT (CC pin selection s/w override) is set
- * or when VCONN_EN_VALUE_BIT is set.
- */
- rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
+ rc = smblib_read(chg, APSD_STATUS_REG, &stat);
if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
+ smblib_err(chg, "Couldn't read APSD status rc=%d\n", rc);
return rc;
}
- if (pd_active) {
- orientation = stat & CC_ORIENTATION_BIT;
+ cc_debounced = (bool)
+ (chg->typec_status[3] & TYPEC_DEBOUNCE_DONE_STATUS_BIT);
+ sink_attached = (bool)
+ (chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT);
+ hvdcp = stat & QC_CHARGER_BIT;
+
+ chg->pd_active = val->intval;
+ if (chg->pd_active) {
+ vote(chg->apsd_disable_votable, PD_VOTER, true, 0);
+ vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
+ vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
+
+ /*
+ * VCONN_EN_ORIENTATION_BIT controls whether to use CC1 or CC2
+ * line when TYPEC_SPARE_CFG_BIT (CC pin selection s/w override)
+ * is set or when VCONN_EN_VALUE_BIT is set.
+ */
+ orientation = chg->typec_status[3] & CC_ORIENTATION_BIT;
rc = smblib_masked_write(chg,
TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
VCONN_EN_ORIENTATION_BIT,
orientation ? 0 : VCONN_EN_ORIENTATION_BIT);
- if (rc < 0) {
+ if (rc < 0)
smblib_err(chg,
"Couldn't enable vconn on CC line rc=%d\n", rc);
- return rc;
- }
+
+ /* SW controlled CC_OUT */
+ rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
+ TYPEC_SPARE_CFG_BIT, TYPEC_SPARE_CFG_BIT);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't enable SW cc_out rc=%d\n",
+ rc);
+
/*
* Enforce 500mA for PD until the real vote comes in later.
* It is guaranteed that pd_active is set prior to
* pd_current_max
*/
rc = vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA);
- if (rc < 0) {
+ if (rc < 0)
smblib_err(chg, "Couldn't vote for USB ICL rc=%d\n",
- rc);
- return rc;
- }
+ rc);
/* since PD was found the cable must be non-legacy */
vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
@@ -2614,36 +2569,40 @@ int smblib_set_prop_pd_active(struct smb_charger *chg,
/* clear USB ICL vote for DCP_VOTER */
rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
if (rc < 0)
- smblib_err(chg,
- "Couldn't un-vote DCP from USB ICL rc=%d\n",
- rc);
+ smblib_err(chg, "Couldn't un-vote DCP from USB ICL rc=%d\n",
+ rc);
/* remove USB_PSY_VOTER */
rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
- if (rc < 0) {
+ if (rc < 0)
smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc);
- return rc;
- }
- }
+ } else {
+ vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
+ vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
+ vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
+ vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER,
+ false, 0);
- /* CC pin selection s/w override in PD session; h/w otherwise. */
- rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
- TYPEC_SPARE_CFG_BIT,
- pd_active ? TYPEC_SPARE_CFG_BIT : 0);
- if (rc < 0) {
- smblib_err(chg, "Couldn't change cc_out ctrl to %s rc=%d\n",
- pd_active ? "SW" : "HW", rc);
- return rc;
- }
+ /* HW controlled CC_OUT */
+ rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
+ TYPEC_SPARE_CFG_BIT, 0);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n",
+ rc);
- cc_debounced = (bool)(stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT);
- if (!pd_active && cc_debounced)
- try_rerun_apsd_for_hvdcp(chg);
+ /*
+ * This WA should only run for HVDCP. Non-legacy SDP/CDP could
+ * draw more, but this WA will remove Rd causing VBUS to drop,
+ * and data could be interrupted. Non-legacy DCP could also draw
+ * more, but it may impact compliance.
+ */
+ if (!chg->typec_legacy_valid && cc_debounced &&
+ !sink_attached && hvdcp)
+ schedule_work(&chg->legacy_detection_work);
+ }
- chg->pd_active = pd_active;
smblib_update_usb_type(chg);
power_supply_changed(chg->usb_psy);
-
return rc;
}
@@ -2746,88 +2705,70 @@ static struct reg_info cc2_detach_settings[] = {
static int smblib_cc2_sink_removal_enter(struct smb_charger *chg)
{
- int rc = 0;
- union power_supply_propval cc2_val = {0, };
+ int rc, ccout, ufp_mode;
+ u8 stat;
if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
- return rc;
+ return 0;
- if (chg->cc2_sink_detach_flag != CC2_SINK_NONE)
- return rc;
+ if (chg->cc2_detach_wa_active)
+ return 0;
- rc = smblib_get_prop_typec_cc_orientation(chg, &cc2_val);
+ rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
if (rc < 0) {
- smblib_err(chg, "Couldn't get cc orientation rc=%d\n", rc);
+ smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
return rc;
}
- if (cc2_val.intval == 1)
- return rc;
+ ccout = (stat & CC_ATTACHED_BIT) ?
+ (!!(stat & CC_ORIENTATION_BIT) + 1) : 0;
+ ufp_mode = (stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT) ?
+ !(stat & UFP_DFP_MODE_STATUS_BIT) : 0;
- rc = smblib_get_prop_typec_mode(chg, &cc2_val);
- if (rc < 0) {
- smblib_err(chg, "Couldn't get prop typec mode rc=%d\n", rc);
- return rc;
- }
+ if (ccout != 2)
+ return 0;
- switch (cc2_val.intval) {
- case POWER_SUPPLY_TYPEC_SOURCE_DEFAULT:
- smblib_reg_block_update(chg, cc2_detach_settings);
- chg->cc2_sink_detach_flag = CC2_SINK_STD;
- schedule_work(&chg->rdstd_cc2_detach_work);
- break;
- case POWER_SUPPLY_TYPEC_SOURCE_MEDIUM:
- case POWER_SUPPLY_TYPEC_SOURCE_HIGH:
- chg->cc2_sink_detach_flag = CC2_SINK_MEDIUM_HIGH;
- break;
- default:
- break;
- }
+ if (!ufp_mode)
+ return 0;
+ chg->cc2_detach_wa_active = true;
+ /* The CC2 removal WA will cause a type-c-change IRQ storm */
+ smblib_reg_block_update(chg, cc2_detach_settings);
+ schedule_work(&chg->rdstd_cc2_detach_work);
return rc;
}
static int smblib_cc2_sink_removal_exit(struct smb_charger *chg)
{
- int rc = 0;
-
if ((chg->wa_flags & TYPEC_CC2_REMOVAL_WA_BIT) == 0)
- return rc;
-
- if (chg->cc2_sink_detach_flag == CC2_SINK_STD) {
- cancel_work_sync(&chg->rdstd_cc2_detach_work);
- smblib_reg_block_restore(chg, cc2_detach_settings);
- }
+ return 0;
- chg->cc2_sink_detach_flag = CC2_SINK_NONE;
+ if (!chg->cc2_detach_wa_active)
+ return 0;
- return rc;
+ chg->cc2_detach_wa_active = false;
+ cancel_work_sync(&chg->rdstd_cc2_detach_work);
+ smblib_reg_block_restore(chg, cc2_detach_settings);
+ return 0;
}
int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg,
const union power_supply_propval *val)
{
- int rc;
+ int rc = 0;
- rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
- EXIT_SNK_BASED_ON_CC_BIT,
- (val->intval) ? EXIT_SNK_BASED_ON_CC_BIT : 0);
- if (rc < 0) {
- smblib_err(chg, "Could not set EXIT_SNK_BASED_ON_CC rc=%d\n",
- rc);
+ if (chg->pd_hard_reset == val->intval)
return rc;
- }
- vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER, val->intval, 0);
-
- if (val->intval)
- rc = smblib_cc2_sink_removal_enter(chg);
- else
- rc = smblib_cc2_sink_removal_exit(chg);
+ chg->pd_hard_reset = val->intval;
+ rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
+ EXIT_SNK_BASED_ON_CC_BIT,
+ (chg->pd_hard_reset) ? EXIT_SNK_BASED_ON_CC_BIT : 0);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't set EXIT_SNK_BASED_ON_CC rc=%d\n",
+ rc);
- if (rc < 0) {
- smblib_err(chg, "Could not detect cc2 removal rc=%d\n", rc);
- return rc;
- }
+ vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER,
+ chg->pd_hard_reset, 0);
return rc;
}
@@ -3134,25 +3075,43 @@ irqreturn_t smblib_handle_usbin_uv(int irq, void *data)
return IRQ_HANDLED;
}
+static void smblib_micro_usb_plugin(struct smb_charger *chg, bool vbus_rising)
+{
+ if (vbus_rising) {
+ /* use the typec flag even though its not typec */
+ chg->typec_present = 1;
+ } else {
+ chg->typec_present = 0;
+ smblib_update_usb_type(chg);
+ extcon_set_cable_state_(chg->extcon, EXTCON_USB, false);
+ smblib_uusb_removal(chg);
+ }
+}
+
+static void smblib_typec_usb_plugin(struct smb_charger *chg, bool vbus_rising)
+{
+ if (vbus_rising)
+ smblib_cc2_sink_removal_exit(chg);
+ else
+ smblib_cc2_sink_removal_enter(chg);
+}
+
#define PL_DELAY_MS 30000
-irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
+void smblib_usb_plugin_locked(struct smb_charger *chg)
{
- struct smb_irq_data *irq_data = data;
- struct smb_charger *chg = irq_data->parent_data;
int rc;
u8 stat;
bool vbus_rising;
rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
if (rc < 0) {
- dev_err(chg->dev, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
- return IRQ_HANDLED;
+ smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
+ return;
}
vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);
- smblib_set_opt_freq_buck(chg,
- vbus_rising ? chg->chg_freq.freq_5V :
- chg->chg_freq.freq_removal);
+ smblib_set_opt_freq_buck(chg, vbus_rising ? chg->chg_freq.freq_5V :
+ chg->chg_freq.freq_removal);
/* fetch the DPDM regulator */
if (!chg->dpdm_reg && of_get_property(chg->dev->of_node,
@@ -3189,17 +3148,26 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
smblib_err(chg, "Couldn't disable dpdm regulator rc=%d\n",
rc);
}
-
- if (chg->micro_usb_mode) {
- smblib_update_usb_type(chg);
- extcon_set_cable_state_(chg->extcon, EXTCON_USB, false);
- smblib_uusb_removal(chg);
- }
}
+ if (chg->micro_usb_mode)
+ smblib_micro_usb_plugin(chg, vbus_rising);
+ else
+ smblib_typec_usb_plugin(chg, vbus_rising);
+
power_supply_changed(chg->usb_psy);
- smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s %s\n",
- irq_data->name, vbus_rising ? "attached" : "detached");
+ smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
+ vbus_rising ? "attached" : "detached");
+}
+
+irqreturn_t smblib_handle_usb_plugin(int irq, void *data)
+{
+ struct smb_irq_data *irq_data = data;
+ struct smb_charger *chg = irq_data->parent_data;
+
+ mutex_lock(&chg->lock);
+ smblib_usb_plugin_locked(chg);
+ mutex_unlock(&chg->lock);
return IRQ_HANDLED;
}
@@ -3368,9 +3336,6 @@ static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg,
if (rising) {
vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
false, 0);
- if (get_effective_result(chg->pd_disallowed_votable_indirect))
- /* could be a legacy cable, try doing hvdcp */
- try_rerun_apsd_for_hvdcp(chg);
/* enable HDC and ICL irq for QC2/3 charger */
if (qc_charger)
@@ -3405,6 +3370,10 @@ static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg,
static void smblib_force_legacy_icl(struct smb_charger *chg, int pst)
{
+ /* while PD is active it should have complete ICL control */
+ if (chg->pd_active)
+ return;
+
switch (pst) {
case POWER_SUPPLY_TYPE_USB:
/*
@@ -3444,7 +3413,7 @@ static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
apsd_result = smblib_update_usb_type(chg);
- if (!chg->pd_active)
+ if (!chg->typec_legacy_valid)
smblib_force_legacy_icl(chg, apsd_result->pst);
switch (apsd_result->bit) {
@@ -3530,73 +3499,6 @@ irqreturn_t smblib_handle_usb_source_change(int irq, void *data)
return IRQ_HANDLED;
}
-static void typec_source_removal(struct smb_charger *chg)
-{
- int rc;
-
- /* reset legacy unknown vote */
- vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
-
- /* reset both usbin current and voltage votes */
- vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
- vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
-
- cancel_delayed_work_sync(&chg->hvdcp_detect_work);
-
- if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
- /* re-enable AUTH_IRQ_EN_CFG_BIT */
- rc = smblib_masked_write(chg,
- USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
- AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
- if (rc < 0)
- smblib_err(chg,
- "Couldn't enable QC auth setting rc=%d\n", rc);
- }
-
- /* reconfigure allowed voltage for HVDCP */
- rc = smblib_set_adapter_allowance(chg,
- USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
- if (rc < 0)
- smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
- rc);
-
- chg->voltage_min_uv = MICRO_5V;
- chg->voltage_max_uv = MICRO_5V;
-
- /* clear USB ICL vote for PD_VOTER */
- rc = vote(chg->usb_icl_votable, PD_VOTER, false, 0);
- if (rc < 0)
- smblib_err(chg, "Couldn't un-vote PD from USB ICL rc=%d\n", rc);
-
- /* clear USB ICL vote for USB_PSY_VOTER */
- rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
- if (rc < 0)
- smblib_err(chg,
- "Couldn't un-vote USB_PSY from USB ICL rc=%d\n", rc);
-
- /* clear USB ICL vote for DCP_VOTER */
- rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
- if (rc < 0)
- smblib_err(chg,
- "Couldn't un-vote DCP from USB ICL rc=%d\n", rc);
-
-}
-
-static void typec_source_insertion(struct smb_charger *chg)
-{
- /*
- * at any time we want LEGACY_UNKNOWN, PD, or USB_PSY to be voting for
- * ICL, so vote LEGACY_UNKNOWN here if none of the above three have
- * casted their votes
- */
- if (!is_client_vote_enabled(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER)
- && !is_client_vote_enabled(chg->usb_icl_votable, PD_VOTER)
- && !is_client_vote_enabled(chg->usb_icl_votable, USB_PSY_VOTER))
- vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000);
-
- smblib_set_opt_freq_buck(chg, chg->chg_freq.freq_5V);
-}
-
static void typec_sink_insertion(struct smb_charger *chg)
{
/* when a sink is inserted we should not wait on hvdcp timeout to
@@ -3617,30 +3519,50 @@ static void smblib_handle_typec_removal(struct smb_charger *chg)
{
int rc;
+ chg->cc2_detach_wa_active = false;
+
+ /* reset APSD voters */
+ vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER, false, 0);
+ vote(chg->apsd_disable_votable, PD_VOTER, false, 0);
+
cancel_delayed_work_sync(&chg->pl_enable_work);
- vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
- vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
+ cancel_delayed_work_sync(&chg->hvdcp_detect_work);
+ /* reset input current limit voters */
+ vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000);
+ vote(chg->usb_icl_votable, PD_VOTER, false, 0);
+ vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
+ vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
+ vote(chg->usb_icl_votable, PL_USBIN_USBIN_VOTER, false, 0);
+
+ /* reset hvdcp voters */
+ vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, true, 0);
+ vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER, true, 0);
+
+ /* reset power delivery voters */
+ vote(chg->pd_allowed_votable, PD_VOTER, false, 0);
vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0);
vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER, true, 0);
+
+ /* reset usb irq voters */
vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
vote(chg->usb_irq_enable_votable, QC_VOTER, false, 0);
- /* reset votes from vbus_cc_short */
- vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
- true, 0);
- vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER,
- true, 0);
- /*
- * cable could be removed during hard reset, remove its vote to
- * disable apsd
- */
- vote(chg->apsd_disable_votable, PD_HARD_RESET_VOTER, false, 0);
+ /* reset parallel voters */
+ vote(chg->pl_disable_votable, PL_DELAY_VOTER, true, 0);
+ vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
+ vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
+ vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
chg->vconn_attempts = 0;
chg->otg_attempts = 0;
chg->pulse_cnt = 0;
chg->usb_icl_delta_ua = 0;
+ chg->voltage_min_uv = MICRO_5V;
+ chg->voltage_max_uv = MICRO_5V;
+ chg->pd_active = 0;
+ chg->pd_hard_reset = 0;
+ chg->typec_legacy_valid = false;
/* enable APSD CC trigger for next insertion */
rc = smblib_masked_write(chg, TYPE_C_CFG_REG,
@@ -3648,15 +3570,48 @@ static void smblib_handle_typec_removal(struct smb_charger *chg)
if (rc < 0)
smblib_err(chg, "Couldn't enable APSD_START_ON_CC rc=%d\n", rc);
- smblib_update_usb_type(chg);
- typec_source_removal(chg);
+ if (chg->wa_flags & QC_AUTH_INTERRUPT_WA_BIT) {
+ /* re-enable AUTH_IRQ_EN_CFG_BIT */
+ rc = smblib_masked_write(chg,
+ USBIN_SOURCE_CHANGE_INTRPT_ENB_REG,
+ AUTH_IRQ_EN_CFG_BIT, AUTH_IRQ_EN_CFG_BIT);
+ if (rc < 0)
+ smblib_err(chg,
+ "Couldn't enable QC auth setting rc=%d\n", rc);
+ }
+
+ /* reconfigure allowed voltage for HVDCP */
+ rc = smblib_set_adapter_allowance(chg,
+ USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
+ rc);
+
+ /* enable DRP */
+ rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
+ TYPEC_POWER_ROLE_CMD_MASK, 0);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't enable DRP rc=%d\n", rc);
+
+ /* HW controlled CC_OUT */
+ rc = smblib_masked_write(chg, TAPER_TIMER_SEL_CFG_REG,
+ TYPEC_SPARE_CFG_BIT, 0);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n", rc);
+
+ /* restore crude sensor */
+ rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0xA5);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't restore crude sensor rc=%d\n", rc);
+
typec_sink_removal(chg);
+ smblib_update_usb_type(chg);
}
static void smblib_handle_typec_insertion(struct smb_charger *chg,
- bool sink_attached, bool legacy_cable)
+ bool sink_attached)
{
- int rp, rc;
+ int rc;
vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, false, 0);
@@ -3666,59 +3621,36 @@ static void smblib_handle_typec_insertion(struct smb_charger *chg,
smblib_err(chg, "Couldn't disable APSD_START_ON_CC rc=%d\n",
rc);
- if (sink_attached) {
- typec_source_removal(chg);
+ if (sink_attached)
typec_sink_insertion(chg);
- } else {
+ else
typec_sink_removal(chg);
- typec_source_insertion(chg);
- }
-
- rp = smblib_get_prop_ufp_mode(chg);
- if (rp == POWER_SUPPLY_TYPEC_SOURCE_HIGH
- || rp == POWER_SUPPLY_TYPEC_NON_COMPLIANT) {
- smblib_dbg(chg, PR_MISC, "VBUS & CC could be shorted; keeping HVDCP disabled\n");
- vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
- true, 0);
- } else {
- vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
- false, 0);
- }
}
static void smblib_handle_typec_debounce_done(struct smb_charger *chg,
- bool rising, bool sink_attached, bool legacy_cable)
+ bool rising, bool sink_attached)
{
int rc;
union power_supply_propval pval = {0, };
- if (rising)
- smblib_handle_typec_insertion(chg, sink_attached, legacy_cable);
- else
- smblib_handle_typec_removal(chg);
+ if (rising) {
+ if (!chg->typec_present) {
+ chg->typec_present = true;
+ smblib_dbg(chg, PR_MISC, "TypeC insertion\n");
+ smblib_handle_typec_insertion(chg, sink_attached);
+ }
+ } else {
+ if (chg->typec_present) {
+ chg->typec_present = false;
+ smblib_dbg(chg, PR_MISC, "TypeC removal\n");
+ smblib_handle_typec_removal(chg);
+ }
+ }
rc = smblib_get_prop_typec_mode(chg, &pval);
if (rc < 0)
smblib_err(chg, "Couldn't get prop typec mode rc=%d\n", rc);
- /*
- * HW BUG - after cable is removed, medium or high rd reading
- * falls to std. Use it for signal of typec cc detachment in
- * software WA.
- */
- if (chg->cc2_sink_detach_flag == CC2_SINK_MEDIUM_HIGH
- && pval.intval == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) {
-
- chg->cc2_sink_detach_flag = CC2_SINK_WA_DONE;
-
- rc = smblib_masked_write(chg,
- TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
- EXIT_SNK_BASED_ON_CC_BIT, 0);
- if (rc < 0)
- smblib_err(chg, "Couldn't get prop typec mode rc=%d\n",
- rc);
- }
-
smblib_dbg(chg, PR_INTERRUPT, "IRQ: debounce-done %s; Type-C %s detected\n",
rising ? "rising" : "falling",
smblib_typec_mode_name[pval.intval]);
@@ -3744,50 +3676,54 @@ irqreturn_t smblib_handle_usb_typec_change_for_uusb(struct smb_charger *chg)
return IRQ_HANDLED;
}
-irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
+static void smblib_usb_typec_change(struct smb_charger *chg)
{
- struct smb_irq_data *irq_data = data;
- struct smb_charger *chg = irq_data->parent_data;
int rc;
- u8 stat4, stat5;
- bool debounce_done, sink_attached, legacy_cable;
-
- if (chg->micro_usb_mode)
- return smblib_handle_usb_typec_change_for_uusb(chg);
+ bool debounce_done, sink_attached;
- /* WA - not when PD hard_reset WIP on cc2 in sink mode */
- if (chg->cc2_sink_detach_flag == CC2_SINK_STD)
- return IRQ_HANDLED;
-
- rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat4);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
- return IRQ_HANDLED;
- }
-
- rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
+ rc = smblib_multibyte_read(chg, TYPE_C_STATUS_1_REG,
+ chg->typec_status, 5);
if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_STATUS_5 rc=%d\n", rc);
- return IRQ_HANDLED;
+ smblib_err(chg, "Couldn't cache USB Type-C status rc=%d\n", rc);
+ return;
}
- debounce_done = (bool)(stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT);
- sink_attached = (bool)(stat4 & UFP_DFP_MODE_STATUS_BIT);
- legacy_cable = (bool)(stat5 & TYPEC_LEGACY_CABLE_STATUS_BIT);
+ debounce_done =
+ (bool)(chg->typec_status[3] & TYPEC_DEBOUNCE_DONE_STATUS_BIT);
+ sink_attached =
+ (bool)(chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT);
- smblib_handle_typec_debounce_done(chg,
- debounce_done, sink_attached, legacy_cable);
+ smblib_handle_typec_debounce_done(chg, debounce_done, sink_attached);
- if (stat4 & TYPEC_VBUS_ERROR_STATUS_BIT)
- smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s vbus-error\n",
- irq_data->name);
+ if (chg->typec_status[3] & TYPEC_VBUS_ERROR_STATUS_BIT)
+ smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n");
- if (stat4 & TYPEC_VCONN_OVERCURR_STATUS_BIT)
+ if (chg->typec_status[3] & TYPEC_VCONN_OVERCURR_STATUS_BIT)
schedule_work(&chg->vconn_oc_work);
power_supply_changed(chg->usb_psy);
- smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_4 = 0x%02x\n", stat4);
- smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATUS_5 = 0x%02x\n", stat5);
+}
+
+irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
+{
+ struct smb_irq_data *irq_data = data;
+ struct smb_charger *chg = irq_data->parent_data;
+
+ if (chg->micro_usb_mode) {
+ smblib_handle_usb_typec_change_for_uusb(chg);
+ return IRQ_HANDLED;
+ }
+
+ if (chg->cc2_detach_wa_active || chg->typec_en_dis_active) {
+ smblib_dbg(chg, PR_INTERRUPT, "Ignoring since %s active\n",
+ chg->cc2_detach_wa_active ?
+ "cc2_detach_wa" : "typec_en_dis");
+ return IRQ_HANDLED;
+ }
+
+ mutex_lock(&chg->lock);
+ smblib_usb_typec_change(chg);
+ mutex_unlock(&chg->lock);
return IRQ_HANDLED;
}
@@ -3815,7 +3751,7 @@ irqreturn_t smblib_handle_switcher_power_ok(int irq, void *data)
{
struct smb_irq_data *irq_data = data;
struct smb_charger *chg = irq_data->parent_data;
- int rc;
+ int rc, usb_icl;
u8 stat;
if (!(chg->wa_flags & BOOST_BACK_WA))
@@ -3827,8 +3763,9 @@ irqreturn_t smblib_handle_switcher_power_ok(int irq, void *data)
return IRQ_HANDLED;
}
- if ((stat & USE_USBIN_BIT) &&
- get_effective_result(chg->usb_icl_votable) < USBIN_25MA)
+ /* skip suspending input if its already suspended by some other voter */
+ usb_icl = get_effective_result(chg->usb_icl_votable);
+ if ((stat & USE_USBIN_BIT) && usb_icl >= 0 && usb_icl < USBIN_25MA)
return IRQ_HANDLED;
if (stat & USE_DCIN_BIT)
@@ -3866,12 +3803,7 @@ static void smblib_hvdcp_detect_work(struct work_struct *work)
vote(chg->pd_disallowed_votable_indirect, HVDCP_TIMEOUT_VOTER,
false, 0);
- if (get_effective_result(chg->pd_disallowed_votable_indirect))
- /* pd is still disabled, try hvdcp */
- try_rerun_apsd_for_hvdcp(chg);
- else
- /* notify pd now that pd is allowed */
- power_supply_changed(chg->usb_psy);
+ power_supply_changed(chg->usb_psy);
}
static void bms_update_work(struct work_struct *work)
@@ -3912,11 +3844,13 @@ static void clear_hdc_work(struct work_struct *work)
static void rdstd_cc2_detach_work(struct work_struct *work)
{
int rc;
- u8 stat;
- struct smb_irq_data irq_data = {NULL, "cc2-removal-workaround"};
+ u8 stat4, stat5;
struct smb_charger *chg = container_of(work, struct smb_charger,
rdstd_cc2_detach_work);
+ if (!chg->cc2_detach_wa_active)
+ return;
+
/*
* WA steps -
* 1. Enable both UFP and DFP, wait for 10ms.
@@ -3924,7 +3858,7 @@ static void rdstd_cc2_detach_work(struct work_struct *work)
* 3. Removal detected if both TYPEC_DEBOUNCE_DONE_STATUS
* and TIMER_STAGE bits are gone, otherwise repeat all by
* work rescheduling.
- * Note, work will be cancelled when pd_hard_reset is 0.
+ * Note, work will be cancelled when USB_PLUGIN rises.
*/
rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
@@ -3947,30 +3881,35 @@ static void rdstd_cc2_detach_work(struct work_struct *work)
usleep_range(30000, 31000);
- rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
+ rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat4);
if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
- rc);
+ smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
return;
}
- if (stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT)
- goto rerun;
- rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat);
+ rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat5);
if (rc < 0) {
smblib_err(chg,
"Couldn't read TYPE_C_STATUS_5_REG rc=%d\n", rc);
return;
}
- if (stat & TIMER_STAGE_2_BIT)
+
+ if ((stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT)
+ || (stat5 & TIMER_STAGE_2_BIT)) {
+ smblib_dbg(chg, PR_MISC, "rerunning DD=%d TS2BIT=%d\n",
+ (int)(stat4 & TYPEC_DEBOUNCE_DONE_STATUS_BIT),
+ (int)(stat5 & TIMER_STAGE_2_BIT));
goto rerun;
+ }
- /* Bingo, cc2 removal detected */
+ smblib_dbg(chg, PR_MISC, "Bingo CC2 Removal detected\n");
+ chg->cc2_detach_wa_active = false;
+ rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
+ EXIT_SNK_BASED_ON_CC_BIT, 0);
smblib_reg_block_restore(chg, cc2_detach_settings);
- chg->cc2_sink_detach_flag = CC2_SINK_WA_DONE;
- irq_data.parent_data = chg;
- smblib_handle_usb_typec_change(0, &irq_data);
-
+ mutex_lock(&chg->lock);
+ smblib_usb_typec_change(chg);
+ mutex_unlock(&chg->lock);
return;
rerun:
@@ -4193,6 +4132,56 @@ static void smblib_pl_enable_work(struct work_struct *work)
vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
}
+static void smblib_legacy_detection_work(struct work_struct *work)
+{
+ struct smb_charger *chg = container_of(work, struct smb_charger,
+ legacy_detection_work);
+ int rc;
+ u8 stat;
+ bool legacy, rp_high;
+
+ mutex_lock(&chg->lock);
+ chg->typec_en_dis_active = 1;
+ smblib_dbg(chg, PR_MISC, "running legacy unknown workaround\n");
+ rc = smblib_masked_write(chg,
+ TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
+ TYPEC_DISABLE_CMD_BIT,
+ TYPEC_DISABLE_CMD_BIT);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't disable type-c rc=%d\n", rc);
+
+ /* wait for the adapter to turn off VBUS */
+ msleep(500);
+
+ rc = smblib_masked_write(chg,
+ TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG,
+ TYPEC_DISABLE_CMD_BIT, 0);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't enable type-c rc=%d\n", rc);
+
+ /* wait for type-c detection to complete */
+ msleep(100);
+
+ rc = smblib_read(chg, TYPE_C_STATUS_5_REG, &stat);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read typec stat5 rc = %d\n", rc);
+ goto unlock;
+ }
+
+ chg->typec_legacy_valid = true;
+ vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0);
+ legacy = stat & TYPEC_LEGACY_CABLE_STATUS_BIT;
+ rp_high = smblib_get_prop_ufp_mode(chg) ==
+ POWER_SUPPLY_TYPEC_SOURCE_HIGH;
+ if (!legacy || !rp_high)
+ vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER,
+ false, 0);
+
+unlock:
+ chg->typec_en_dis_active = 0;
+ mutex_unlock(&chg->lock);
+}
+
static int smblib_create_votables(struct smb_charger *chg)
{
int rc = 0;
@@ -4325,6 +4314,15 @@ static int smblib_create_votables(struct smb_charger *chg)
return rc;
}
+ chg->typec_irq_disable_votable = create_votable("TYPEC_IRQ_DISABLE",
+ VOTE_SET_ANY,
+ smblib_typec_irq_disable_vote_callback,
+ chg);
+ if (IS_ERR(chg->typec_irq_disable_votable)) {
+ rc = PTR_ERR(chg->typec_irq_disable_votable);
+ return rc;
+ }
+
return rc;
}
@@ -4350,6 +4348,8 @@ static void smblib_destroy_votables(struct smb_charger *chg)
destroy_votable(chg->apsd_disable_votable);
if (chg->hvdcp_hw_inov_dis_votable)
destroy_votable(chg->hvdcp_hw_inov_dis_votable);
+ if (chg->typec_irq_disable_votable)
+ destroy_votable(chg->typec_irq_disable_votable);
}
static void smblib_iio_deinit(struct smb_charger *chg)
@@ -4370,6 +4370,7 @@ int smblib_init(struct smb_charger *chg)
{
int rc = 0;
+ mutex_init(&chg->lock);
mutex_init(&chg->write_lock);
mutex_init(&chg->otg_oc_lock);
INIT_WORK(&chg->bms_update_work, bms_update_work);
@@ -4382,6 +4383,7 @@ int smblib_init(struct smb_charger *chg)
INIT_DELAYED_WORK(&chg->otg_ss_done_work, smblib_otg_ss_done_work);
INIT_DELAYED_WORK(&chg->icl_change_work, smblib_icl_change_work);
INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work);
+ INIT_WORK(&chg->legacy_detection_work, smblib_legacy_detection_work);
chg->fake_capacity = -EINVAL;
switch (chg->mode) {
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index 4b277c4282cf..b0d84f014b0d 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -61,6 +61,7 @@ enum print_reason {
#define SW_QC3_VOTER "SW_QC3_VOTER"
#define AICL_RERUN_VOTER "AICL_RERUN_VOTER"
#define LEGACY_UNKNOWN_VOTER "LEGACY_UNKNOWN_VOTER"
+#define CC2_WA_VOTER "CC2_WA_VOTER"
#define VCONN_MAX_ATTEMPTS 3
#define OTG_MAX_ATTEMPTS 3
@@ -71,13 +72,6 @@ enum smb_mode {
NUM_MODES,
};
-enum cc2_sink_type {
- CC2_SINK_NONE = 0,
- CC2_SINK_STD,
- CC2_SINK_MEDIUM_HIGH,
- CC2_SINK_WA_DONE,
-};
-
enum {
QC_CHARGER_DETECTION_WA_BIT = BIT(0),
BOOST_BACK_WA = BIT(1),
@@ -236,6 +230,7 @@ struct smb_charger {
int smb_version;
/* locks */
+ struct mutex lock;
struct mutex write_lock;
struct mutex ps_change_lock;
struct mutex otg_oc_lock;
@@ -276,6 +271,7 @@ struct smb_charger {
struct votable *apsd_disable_votable;
struct votable *hvdcp_hw_inov_dis_votable;
struct votable *usb_irq_enable_votable;
+ struct votable *typec_irq_disable_votable;
/* work */
struct work_struct bms_update_work;
@@ -289,6 +285,7 @@ struct smb_charger {
struct delayed_work otg_ss_done_work;
struct delayed_work icl_change_work;
struct delayed_work pl_enable_work;
+ struct work_struct legacy_detection_work;
/* cached status */
int voltage_min_uv;
@@ -313,10 +310,15 @@ struct smb_charger {
int default_icl_ua;
int otg_cl_ua;
bool uusb_apsd_rerun_done;
+ bool pd_hard_reset;
+ bool typec_present;
+ u8 typec_status[5];
+ bool typec_legacy_valid;
/* workaround flag */
u32 wa_flags;
- enum cc2_sink_type cc2_sink_detach_flag;
+ bool cc2_detach_wa_active;
+ bool typec_en_dis_active;
int boost_current_ua;
int temp_speed_reading_count;
diff --git a/drivers/regulator/qpnp-oledb-regulator.c b/drivers/regulator/qpnp-oledb-regulator.c
index c012f373e80e..fa14445f9d26 100644
--- a/drivers/regulator/qpnp-oledb-regulator.c
+++ b/drivers/regulator/qpnp-oledb-regulator.c
@@ -27,6 +27,7 @@
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/qpnp-labibb-regulator.h>
#include <linux/qpnp/qpnp-pbs.h>
+#include <linux/qpnp/qpnp-revid.h>
#define QPNP_OLEDB_REGULATOR_DRIVER_NAME "qcom,qpnp-oledb-regulator"
#define OLEDB_VOUT_STEP_MV 100
@@ -162,6 +163,7 @@ struct qpnp_oledb {
struct notifier_block oledb_nb;
struct mutex bus_lock;
struct device_node *pbs_dev_node;
+ struct pmic_revid_data *pmic_rev_id;
u32 base;
u8 mod_enable;
@@ -1085,8 +1087,22 @@ static int qpnp_oledb_parse_fast_precharge(struct qpnp_oledb *oledb)
static int qpnp_oledb_parse_dt(struct qpnp_oledb *oledb)
{
int rc = 0;
+ struct device_node *revid_dev_node;
struct device_node *of_node = oledb->dev->of_node;
+ revid_dev_node = of_parse_phandle(oledb->dev->of_node,
+ "qcom,pmic-revid", 0);
+ if (!revid_dev_node) {
+ pr_err("Missing qcom,pmic-revid property - driver failed\n");
+ return -EINVAL;
+ }
+
+ oledb->pmic_rev_id = get_revid_data(revid_dev_node);
+ if (IS_ERR(oledb->pmic_rev_id)) {
+ pr_debug("Unable to get revid data\n");
+ return -EPROBE_DEFER;
+ }
+
oledb->swire_control =
of_property_read_bool(of_node, "qcom,swire-control");
diff --git a/drivers/soc/qcom/qpnp-haptic.c b/drivers/soc/qcom/qpnp-haptic.c
index c86eebcd390f..70cf11359e97 100644
--- a/drivers/soc/qcom/qpnp-haptic.c
+++ b/drivers/soc/qcom/qpnp-haptic.c
@@ -138,7 +138,7 @@
#define QPNP_HAP_WAV_SAMP_MAX 0x7E
#define QPNP_HAP_BRAKE_PAT_LEN 4
#define QPNP_HAP_PLAY_EN 0x80
-#define QPNP_HAP_EN 0x80
+#define QPNP_HAP_EN_BIT BIT(7)
#define QPNP_HAP_BRAKE_MASK BIT(0)
#define QPNP_HAP_AUTO_RES_MASK BIT(7)
#define AUTO_RES_ENABLE BIT(7)
@@ -305,7 +305,6 @@ struct qpnp_pwm_info {
* @ wave_samp - array of wave samples
* @ shadow_wave_samp - shadow array of wave samples
* @ brake_pat - pattern for active breaking
- * @ reg_en_ctl - enable control register
* @ reg_play - play register
* @ lra_res_cal_period - period for resonance calibration
* @ sc_duration - counter to determine the duration of short circuit condition
@@ -358,6 +357,7 @@ struct qpnp_hap {
u32 sc_irq;
u32 status_flags;
u16 base;
+ u16 last_rate_cfg;
u16 drive_period_code_max_limit;
u16 drive_period_code_min_limit;
u16 lra_res_cal_period;
@@ -368,7 +368,6 @@ struct qpnp_hap {
u8 wave_samp[QPNP_HAP_WAV_SAMP_LEN];
u8 shadow_wave_samp[QPNP_HAP_WAV_SAMP_LEN];
u8 brake_pat[QPNP_HAP_BRAKE_PAT_LEN];
- u8 reg_en_ctl;
u8 reg_play;
u8 sc_duration;
u8 ext_pwm_dtest_line;
@@ -391,6 +390,18 @@ struct qpnp_hap {
static struct qpnp_hap *ghap;
/* helper to read a pmic register */
+static int qpnp_hap_read_mult_reg(struct qpnp_hap *hap, u16 addr, u8 *val,
+ int len)
+{
+ int rc;
+
+ rc = regmap_bulk_read(hap->regmap, addr, val, len);
+ if (rc < 0)
+ pr_err("Error reading address: %X - ret %X\n", addr, rc);
+
+ return rc;
+}
+
static int qpnp_hap_read_reg(struct qpnp_hap *hap, u16 addr, u8 *val)
{
int rc;
@@ -399,11 +410,28 @@ static int qpnp_hap_read_reg(struct qpnp_hap *hap, u16 addr, u8 *val)
rc = regmap_read(hap->regmap, addr, &tmp);
if (rc < 0)
pr_err("Error reading address: %X - ret %X\n", addr, rc);
- *val = (u8)tmp;
+ else
+ *val = (u8)tmp;
+
return rc;
}
/* helper to write a pmic register */
+static int qpnp_hap_write_mult_reg(struct qpnp_hap *hap, u16 addr, u8 *val,
+ int len)
+{
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&hap->bus_lock, flags);
+ rc = regmap_bulk_write(hap->regmap, addr, val, len);
+ if (rc < 0)
+ pr_err("Error writing address: %X - ret %X\n", addr, rc);
+
+ spin_unlock_irqrestore(&hap->bus_lock, flags);
+ return rc;
+}
+
static int qpnp_hap_write_reg(struct qpnp_hap *hap, u16 addr, u8 val)
{
unsigned long flags;
@@ -480,15 +508,12 @@ static void qpnp_handle_sc_irq(struct work_struct *work)
}
}
-static int qpnp_hap_mod_enable(struct qpnp_hap *hap, int on)
+static int qpnp_hap_mod_enable(struct qpnp_hap *hap, bool on)
{
u8 val;
int rc, i;
- val = hap->reg_en_ctl;
- if (on) {
- val |= QPNP_HAP_EN;
- } else {
+ if (!on) {
for (i = 0; i < QPNP_HAP_MAX_RETRIES; i++) {
/* wait for 4 cycles of play rate */
unsigned long sleep_time =
@@ -511,16 +536,13 @@ static int qpnp_hap_mod_enable(struct qpnp_hap *hap, int on)
if (i >= QPNP_HAP_MAX_RETRIES)
pr_debug("Haptics Busy. Force disable\n");
-
- val &= ~QPNP_HAP_EN;
}
+ val = on ? QPNP_HAP_EN_BIT : 0;
rc = qpnp_hap_write_reg(hap, QPNP_HAP_EN_CTL_REG(hap->base), val);
if (rc < 0)
return rc;
- hap->reg_en_ctl = val;
-
return 0;
}
@@ -1517,20 +1539,23 @@ static int qpnp_hap_auto_res_enable(struct qpnp_hap *hap, int enable)
static void update_lra_frequency(struct qpnp_hap *hap)
{
- u8 lra_auto_res_lo = 0, lra_auto_res_hi = 0, val;
+ u8 lra_auto_res[2], val;
u32 play_rate_code;
+ u16 rate_cfg;
int rc;
- qpnp_hap_read_reg(hap, QPNP_HAP_LRA_AUTO_RES_LO(hap->base),
- &lra_auto_res_lo);
- qpnp_hap_read_reg(hap, QPNP_HAP_LRA_AUTO_RES_HI(hap->base),
- &lra_auto_res_hi);
+ rc = qpnp_hap_read_mult_reg(hap, QPNP_HAP_LRA_AUTO_RES_LO(hap->base),
+ lra_auto_res, 2);
+ if (rc < 0) {
+ pr_err("Error in reading LRA_AUTO_RES_LO/HI, rc=%d\n", rc);
+ return;
+ }
play_rate_code =
- (lra_auto_res_hi & 0xF0) << 4 | (lra_auto_res_lo & 0xFF);
+ (lra_auto_res[1] & 0xF0) << 4 | (lra_auto_res[0] & 0xFF);
pr_debug("lra_auto_res_lo = 0x%x lra_auto_res_hi = 0x%x play_rate_code = 0x%x\n",
- lra_auto_res_lo, lra_auto_res_hi, play_rate_code);
+ lra_auto_res[0], lra_auto_res[1], play_rate_code);
rc = qpnp_hap_read_reg(hap, QPNP_HAP_STATUS(hap->base), &val);
if (rc < 0)
@@ -1559,12 +1584,21 @@ static void update_lra_frequency(struct qpnp_hap *hap)
return;
}
- qpnp_hap_write_reg(hap, QPNP_HAP_RATE_CFG1_REG(hap->base),
- lra_auto_res_lo);
+ lra_auto_res[1] >>= 4;
+ rate_cfg = lra_auto_res[1] << 8 | lra_auto_res[0];
+ if (hap->last_rate_cfg == rate_cfg) {
+ pr_debug("Same rate_cfg, skip updating\n");
+ return;
+ }
- lra_auto_res_hi = lra_auto_res_hi >> 4;
- qpnp_hap_write_reg(hap, QPNP_HAP_RATE_CFG2_REG(hap->base),
- lra_auto_res_hi);
+ rc = qpnp_hap_write_mult_reg(hap, QPNP_HAP_RATE_CFG1_REG(hap->base),
+ lra_auto_res, 2);
+ if (rc < 0) {
+ pr_err("Error in writing to RATE_CFG1/2, rc=%d\n", rc);
+ } else {
+ pr_debug("Update RATE_CFG with [0x%x]\n", rate_cfg);
+ hap->last_rate_cfg = rate_cfg;
+ }
}
static enum hrtimer_restart detect_auto_res_error(struct hrtimer *timer)
@@ -1983,6 +2017,8 @@ static int qpnp_hap_config(struct qpnp_hap *hap)
if (rc)
return rc;
+ hap->last_rate_cfg = hap->init_drive_period_code;
+
if (hap->act_type == QPNP_HAP_LRA &&
hap->perform_lra_auto_resonance_search)
calculate_lra_code(hap);
@@ -2019,12 +2055,6 @@ static int qpnp_hap_config(struct qpnp_hap *hap)
return rc;
}
- /* Cache enable control register */
- rc = qpnp_hap_read_reg(hap, QPNP_HAP_EN_CTL_REG(hap->base), &val);
- if (rc < 0)
- return rc;
- hap->reg_en_ctl = val;
-
/* Cache play register */
rc = qpnp_hap_read_reg(hap, QPNP_HAP_PLAY_REG(hap->base), &val);
if (rc < 0)
diff --git a/drivers/soc/qcom/spcom.c b/drivers/soc/qcom/spcom.c
index 0c44d76bc7c7..f7b9c3f85a30 100644
--- a/drivers/soc/qcom/spcom.c
+++ b/drivers/soc/qcom/spcom.c
@@ -898,12 +898,12 @@ static int spcom_rx(struct spcom_channel *ch,
goto exit_err;
}
+copy_buf:
if (!ch->glink_rx_buf) {
pr_err("invalid glink_rx_buf.\n");
goto exit_err;
}
-copy_buf:
/* Copy from glink buffer to spcom buffer */
size = min_t(int, ch->actual_rx_size, size);
memcpy(buf, ch->glink_rx_buf, size);
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index a5bfeab596ac..d1802bcba0fb 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -166,6 +166,7 @@ struct spmi_pmic_arb {
u16 max_apid;
u16 max_periph;
u32 *mapping_table;
+ int reserved_chan;
DECLARE_BITMAP(mapping_table_valid, PMIC_ARB_MAX_PERIPHS);
struct irq_domain *domain;
struct spmi_controller *spmic;
@@ -861,6 +862,10 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid)
* ppid_to_apid is an in-memory invert of that table.
*/
for (apid = pa->last_apid; apid < pa->max_periph; apid++) {
+ /* Do not keep the reserved channel in the mapping table */
+ if (pa->reserved_chan >= 0 && apid == pa->reserved_chan)
+ continue;
+
regval = readl_relaxed(pa->cnfg +
SPMI_OWNERSHIP_TABLE_REG(apid));
pa->apid_data[apid].irq_owner
@@ -920,6 +925,10 @@ static int pmic_arb_read_apid_map_v5(struct spmi_pmic_arb *pa)
* receive interrupts from the PPID.
*/
for (apid = 0; apid < pa->max_periph; apid++) {
+ /* Do not keep the reserved channel in the mapping table */
+ if (pa->reserved_chan >= 0 && apid == pa->reserved_chan)
+ continue;
+
offset = pa->ver_ops->channel_map_offset(apid);
if (offset >= pa->core_size)
break;
@@ -1340,6 +1349,10 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
pa->ee = ee;
+ pa->reserved_chan = -EINVAL;
+ of_property_read_u32(pdev->dev.of_node, "qcom,reserved-chan",
+ &pa->reserved_chan);
+
pa->mapping_table = devm_kcalloc(&ctrl->dev, PMIC_ARB_MAX_PERIPHS - 1,
sizeof(*pa->mapping_table), GFP_KERNEL);
if (!pa->mapping_table) {
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index bec687853c5d..205af6627b80 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -217,6 +217,22 @@ static int test_task_flag(struct task_struct *p, int flag)
return 0;
}
+static int test_task_state(struct task_struct *p, int state)
+{
+ struct task_struct *t;
+
+ for_each_thread(p, t) {
+ task_lock(t);
+ if (t->state & state) {
+ task_unlock(t);
+ return 1;
+ }
+ task_unlock(t);
+ }
+
+ return 0;
+}
+
static DEFINE_MUTEX(scan_mutex);
int can_use_cma_pages(gfp_t gfp_mask)
@@ -404,7 +420,7 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
int other_free;
int other_file;
- if (mutex_lock_interruptible(&scan_mutex) < 0)
+ if (!mutex_trylock(&scan_mutex))
return 0;
other_free = global_page_state(NR_FREE_PAGES);
@@ -462,8 +478,6 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
if (time_before_eq(jiffies, lowmem_deathpending_timeout)) {
if (test_task_flag(tsk, TIF_MEMDIE)) {
rcu_read_unlock();
- /* give the system time to free up the memory */
- msleep_interruptible(20);
mutex_unlock(&scan_mutex);
return 0;
}
@@ -497,6 +511,17 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
}
if (selected) {
long cache_size, cache_limit, free;
+
+ if (test_task_flag(selected, TIF_MEMDIE) &&
+ (test_task_state(selected, TASK_UNINTERRUPTIBLE))) {
+ lowmem_print(2, "'%s' (%d) is already killed\n",
+ selected->comm,
+ selected->pid);
+ rcu_read_unlock();
+ mutex_unlock(&scan_mutex);
+ return 0;
+ }
+
task_lock(selected);
send_sig(SIGKILL, selected, 0);
/*
@@ -565,7 +590,8 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
static struct shrinker lowmem_shrinker = {
.scan_objects = lowmem_scan,
.count_objects = lowmem_count,
- .seeks = DEFAULT_SEEKS * 16
+ .seeks = DEFAULT_SEEKS * 16,
+ .flags = SHRINKER_LMK
};
static int __init lowmem_init(void)
diff --git a/drivers/usb/phy/phy-msm-ssusb-qmp.c b/drivers/usb/phy/phy-msm-ssusb-qmp.c
index aa11cf2f7417..6ba742076baa 100644
--- a/drivers/usb/phy/phy-msm-ssusb-qmp.c
+++ b/drivers/usb/phy/phy-msm-ssusb-qmp.c
@@ -222,11 +222,6 @@ static int msm_ssusb_qmp_ldo_enable(struct msm_ssphy_qmp *phy, int on)
"enable phy->fpc_redrive_ldo failed\n");
return rc;
}
-
- dev_dbg(phy->phy.dev,
- "fpc redrive ldo: min_vol:%duV max_vol:%duV\n",
- phy->redrive_voltage_levels[VOLTAGE_LEVEL_MIN],
- phy->redrive_voltage_levels[VOLTAGE_LEVEL_MAX]);
}
rc = msm_ldo_enable(phy, phy->vdd, phy->vdd_levels,
@@ -236,11 +231,6 @@ static int msm_ssusb_qmp_ldo_enable(struct msm_ssphy_qmp *phy, int on)
goto disable_fpc_redrive;
}
- dev_dbg(phy->phy.dev,
- "vdd ldo: min_vol:%duV max_vol:%duV\n",
- phy->vdd_levels[VOLTAGE_LEVEL_MIN],
- phy->vdd_levels[VOLTAGE_LEVEL_MAX]);
-
rc = msm_ldo_enable(phy, phy->core_ldo, phy->core_voltage_levels,
USB_SSPHY_HPM_LOAD);
if (rc < 0) {
@@ -248,11 +238,6 @@ static int msm_ssusb_qmp_ldo_enable(struct msm_ssphy_qmp *phy, int on)
goto disable_vdd;
}
- dev_dbg(phy->phy.dev,
- "core ldo: min_vol:%duV max_vol:%duV\n",
- phy->core_voltage_levels[VOLTAGE_LEVEL_MIN],
- phy->core_voltage_levels[VOLTAGE_LEVEL_MAX]);
-
return 0;
disable_regulators:
diff --git a/drivers/video/fbdev/msm/mdss_mdp_cdm.c b/drivers/video/fbdev/msm/mdss_mdp_cdm.c
index f1d1bdd301e3..10928e6bceaa 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_cdm.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_cdm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2017, 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
@@ -377,6 +377,17 @@ int mdss_mdp_cdm_destroy(struct mdss_mdp_cdm *cdm)
return -EINVAL;
}
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
+ mutex_lock(&cdm->lock);
+ /* Disable HDMI packer */
+ writel_relaxed(0x0, cdm->base + MDSS_MDP_REG_CDM_HDMI_PACK_OP_MODE);
+
+ /* Put CDM in bypass */
+ writel_relaxed(0x0, cdm->mdata->mdp_base + MDSS_MDP_MDP_OUT_CTL_0);
+
+ mutex_unlock(&cdm->lock);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
+
kref_put(&cdm->kref, mdss_mdp_cdm_free);
return rc;
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
index ea55203afc51..fe258d85b667 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
@@ -1071,6 +1071,13 @@ static int mdss_mdp_video_stop(struct mdss_mdp_ctl *ctl, int panel_power_state)
{
int intfs_num, ret = 0;
+ if (ctl->cdm) {
+ if (!mdss_mdp_cdm_destroy(ctl->cdm))
+ mdss_mdp_ctl_write(ctl,
+ MDSS_MDP_REG_CTL_FLUSH, BIT(26));
+ ctl->cdm = NULL;
+ }
+
intfs_num = ctl->intf_num - MDSS_MDP_INTF0;
ret = mdss_mdp_video_intfs_stop(ctl, ctl->panel_data, intfs_num);
if (IS_ERR_VALUE(ret)) {
@@ -1083,10 +1090,6 @@ static int mdss_mdp_video_stop(struct mdss_mdp_ctl *ctl, int panel_power_state)
mdss_mdp_ctl_reset(ctl, false);
ctl->intf_ctx[MASTER_CTX] = NULL;
- if (ctl->cdm) {
- mdss_mdp_cdm_destroy(ctl->cdm);
- ctl->cdm = NULL;
- }
return 0;
}
@@ -1806,7 +1809,9 @@ int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl,
mdss_mdp_video_timegen_flush(ctl, sctx);
/* wait for 1 VSYNC for the pipe to be unstaged */
- msleep(20);
+ mdss_mdp_video_wait4comp(ctl, NULL);
+ if (sctl)
+ mdss_mdp_video_wait4comp(sctl, NULL);
ret = mdss_mdp_ctl_intf_event(ctl,
MDSS_EVENT_CONT_SPLASH_FINISH, NULL,
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c b/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c
index 87ed56028edd..9b63499e64b0 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_writeback.c
@@ -792,7 +792,9 @@ static int mdss_mdp_writeback_stop(struct mdss_mdp_ctl *ctl,
}
if (ctl->cdm) {
- mdss_mdp_cdm_destroy(ctl->cdm);
+ if (!mdss_mdp_cdm_destroy(ctl->cdm))
+ mdss_mdp_ctl_write(ctl,
+ MDSS_MDP_REG_CTL_FLUSH, BIT(26));
ctl->cdm = NULL;
}
return 0;
diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
index 8eb12d764be3..c800bbe4963c 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
@@ -2601,6 +2601,18 @@ int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd,
mdss_mdp_splash_cleanup(mfd, true);
/*
+ * Wait for pingpong done only during resume for
+ * command mode panels. Ensure that one commit is
+ * sent before kickoff completes so that backlight
+ * update happens after it.
+ */
+ if (mdss_fb_is_power_off(mfd) &&
+ mfd->panel_info->type == MIPI_CMD_PANEL) {
+ pr_debug("wait for pp done after resume for cmd mode\n");
+ mdss_mdp_display_wait4pingpong(ctl, true);
+ }
+
+ /*
* Configure Timing Engine, if new fps was set.
* We need to do this after the wait for vsync
* to guarantee that mdp flush bit and dsi flush
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
index cb3d6f6419cd..db81acb686c0 100644
--- a/fs/ext4/inline.c
+++ b/fs/ext4/inline.c
@@ -18,6 +18,7 @@
#include "ext4.h"
#include "xattr.h"
#include "truncate.h"
+#include <trace/events/android_fs.h>
#define EXT4_XATTR_SYSTEM_DATA "data"
#define EXT4_MIN_INLINE_DATA_SIZE ((sizeof(__le32) * EXT4_N_BLOCKS))
@@ -502,6 +503,17 @@ int ext4_readpage_inline(struct inode *inode, struct page *page)
return -EAGAIN;
}
+ if (trace_android_fs_dataread_start_enabled()) {
+ char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
+
+ path = android_fstrace_get_pathname(pathbuf,
+ MAX_TRACE_PATHBUF_LEN,
+ inode);
+ trace_android_fs_dataread_start(inode, page_offset(page),
+ PAGE_SIZE, current->pid,
+ path, current->comm);
+ }
+
/*
* Current inline data can only exist in the 1st page,
* So for all the other pages, just set them uptodate.
@@ -513,6 +525,8 @@ int ext4_readpage_inline(struct inode *inode, struct page *page)
SetPageUptodate(page);
}
+ trace_android_fs_dataread_end(inode, page_offset(page), PAGE_SIZE);
+
up_read(&EXT4_I(inode)->xattr_sem);
unlock_page(page);
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 99fa2fca52b1..72b384931f66 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -45,6 +45,7 @@
#include "ext4_ice.h"
#include <trace/events/ext4.h>
+#include <trace/events/android_fs.h>
#define MPAGE_DA_EXTENT_TAIL 0x01
@@ -1018,6 +1019,16 @@ static int ext4_write_begin(struct file *file, struct address_space *mapping,
pgoff_t index;
unsigned from, to;
+ if (trace_android_fs_datawrite_start_enabled()) {
+ char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
+
+ path = android_fstrace_get_pathname(pathbuf,
+ MAX_TRACE_PATHBUF_LEN,
+ inode);
+ trace_android_fs_datawrite_start(inode, pos, len,
+ current->pid, path,
+ current->comm);
+ }
trace_ext4_write_begin(inode, pos, len, flags);
/*
* Reserve one block more for addition to orphan list in case
@@ -1154,6 +1165,7 @@ static int ext4_write_end(struct file *file,
int ret = 0, ret2;
int i_size_changed = 0;
+ trace_android_fs_datawrite_end(inode, pos, len);
trace_ext4_write_end(inode, pos, len, copied);
if (ext4_test_inode_state(inode, EXT4_STATE_ORDERED_MODE)) {
ret = ext4_jbd2_file_inode(handle, inode);
@@ -1267,6 +1279,7 @@ static int ext4_journalled_write_end(struct file *file,
unsigned from, to;
int size_changed = 0;
+ trace_android_fs_datawrite_end(inode, pos, len);
trace_ext4_journalled_write_end(inode, pos, len, copied);
from = pos & (PAGE_CACHE_SIZE - 1);
to = from + len;
@@ -2742,6 +2755,16 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping,
len, flags, pagep, fsdata);
}
*fsdata = (void *)0;
+ if (trace_android_fs_datawrite_start_enabled()) {
+ char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
+
+ path = android_fstrace_get_pathname(pathbuf,
+ MAX_TRACE_PATHBUF_LEN,
+ inode);
+ trace_android_fs_datawrite_start(inode, pos, len,
+ current->pid,
+ path, current->comm);
+ }
trace_ext4_da_write_begin(inode, pos, len, flags);
if (ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) {
@@ -2860,6 +2883,7 @@ static int ext4_da_write_end(struct file *file,
return ext4_write_end(file, mapping, pos,
len, copied, page, fsdata);
+ trace_android_fs_datawrite_end(inode, pos, len);
trace_ext4_da_write_end(inode, pos, len, copied);
start = pos & (PAGE_CACHE_SIZE - 1);
end = start + copied - 1;
@@ -3352,12 +3376,42 @@ static ssize_t ext4_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
if (ext4_has_inline_data(inode))
return 0;
+ if (trace_android_fs_dataread_start_enabled() &&
+ (iov_iter_rw(iter) == READ)) {
+ char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
+
+ path = android_fstrace_get_pathname(pathbuf,
+ MAX_TRACE_PATHBUF_LEN,
+ inode);
+ trace_android_fs_dataread_start(inode, offset, count,
+ current->pid, path,
+ current->comm);
+ }
+ if (trace_android_fs_datawrite_start_enabled() &&
+ (iov_iter_rw(iter) == WRITE)) {
+ char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
+
+ path = android_fstrace_get_pathname(pathbuf,
+ MAX_TRACE_PATHBUF_LEN,
+ inode);
+ trace_android_fs_datawrite_start(inode, offset, count,
+ current->pid, path,
+ current->comm);
+ }
trace_ext4_direct_IO_enter(inode, offset, count, iov_iter_rw(iter));
if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
ret = ext4_ext_direct_IO(iocb, iter, offset);
else
ret = ext4_ind_direct_IO(iocb, iter, offset);
trace_ext4_direct_IO_exit(inode, offset, count, iov_iter_rw(iter), ret);
+
+ if (trace_android_fs_dataread_start_enabled() &&
+ (iov_iter_rw(iter) == READ))
+ trace_android_fs_dataread_end(inode, offset, count);
+ if (trace_android_fs_datawrite_start_enabled() &&
+ (iov_iter_rw(iter) == WRITE))
+ trace_android_fs_datawrite_end(inode, offset, count);
+
return ret;
}
diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c
index 71a08a294529..99f1bd8c7f05 100644
--- a/fs/ext4/readpage.c
+++ b/fs/ext4/readpage.c
@@ -46,6 +46,7 @@
#include "ext4.h"
#include "ext4_ice.h"
+#include <trace/events/android_fs.h>
/*
* Call ext4_decrypt on every single page, reusing the encryption
@@ -92,6 +93,17 @@ static inline bool ext4_bio_encrypted(struct bio *bio)
#endif
}
+static void
+ext4_trace_read_completion(struct bio *bio)
+{
+ struct page *first_page = bio->bi_io_vec[0].bv_page;
+
+ if (first_page != NULL)
+ trace_android_fs_dataread_end(first_page->mapping->host,
+ page_offset(first_page),
+ bio->bi_iter.bi_size);
+}
+
/*
* I/O completion handler for multipage BIOs.
*
@@ -109,6 +121,9 @@ static void mpage_end_io(struct bio *bio)
struct bio_vec *bv;
int i;
+ if (trace_android_fs_dataread_start_enabled())
+ ext4_trace_read_completion(bio);
+
if (ext4_bio_encrypted(bio)) {
struct ext4_crypto_ctx *ctx = bio->bi_private;
@@ -136,6 +151,30 @@ static void mpage_end_io(struct bio *bio)
bio_put(bio);
}
+static void
+ext4_submit_bio_read(struct bio *bio)
+{
+ if (trace_android_fs_dataread_start_enabled()) {
+ struct page *first_page = bio->bi_io_vec[0].bv_page;
+
+ if (first_page != NULL) {
+ char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
+
+ path = android_fstrace_get_pathname(pathbuf,
+ MAX_TRACE_PATHBUF_LEN,
+ first_page->mapping->host);
+ trace_android_fs_dataread_start(
+ first_page->mapping->host,
+ page_offset(first_page),
+ bio->bi_iter.bi_size,
+ current->pid,
+ path,
+ current->comm);
+ }
+ }
+ submit_bio(READ, bio);
+}
+
int ext4_mpage_readpages(struct address_space *mapping,
struct list_head *pages, struct page *page,
unsigned nr_pages)
@@ -277,7 +316,7 @@ int ext4_mpage_readpages(struct address_space *mapping,
*/
if (bio && (last_block_in_bio != blocks[0] - 1)) {
submit_and_realloc:
- submit_bio(READ, bio);
+ ext4_submit_bio_read(bio);
bio = NULL;
}
if (bio == NULL) {
@@ -309,14 +348,14 @@ int ext4_mpage_readpages(struct address_space *mapping,
if (((map.m_flags & EXT4_MAP_BOUNDARY) &&
(relative_block == map.m_len)) ||
(first_hole != blocks_per_page)) {
- submit_bio(READ, bio);
+ ext4_submit_bio_read(bio);
bio = NULL;
} else
last_block_in_bio = blocks[blocks_per_page - 1];
goto next_page;
confused:
if (bio) {
- submit_bio(READ, bio);
+ ext4_submit_bio_read(bio);
bio = NULL;
}
if (!PageUptodate(page))
@@ -329,6 +368,6 @@ int ext4_mpage_readpages(struct address_space *mapping,
}
BUG_ON(pages && !list_empty(pages));
if (bio)
- submit_bio(READ, bio);
+ ext4_submit_bio_read(bio);
return 0;
}
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index f53826ec30f3..4fb5709256fd 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -26,6 +26,7 @@
#include "segment.h"
#include "trace.h"
#include <trace/events/f2fs.h>
+#include <trace/events/android_fs.h>
static void f2fs_read_end_io(struct bio *bio)
{
@@ -1405,6 +1406,16 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
struct dnode_of_data dn;
int err = 0;
+ if (trace_android_fs_datawrite_start_enabled()) {
+ char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
+
+ path = android_fstrace_get_pathname(pathbuf,
+ MAX_TRACE_PATHBUF_LEN,
+ inode);
+ trace_android_fs_datawrite_start(inode, pos, len,
+ current->pid, path,
+ current->comm);
+ }
trace_f2fs_write_begin(inode, pos, len, flags);
f2fs_balance_fs(sbi);
@@ -1533,6 +1544,7 @@ static int f2fs_write_end(struct file *file,
{
struct inode *inode = page->mapping->host;
+ trace_android_fs_datawrite_end(inode, pos, len);
trace_f2fs_write_end(inode, pos, len, copied);
set_page_dirty(page);
@@ -1586,6 +1598,28 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
trace_f2fs_direct_IO_enter(inode, offset, count, iov_iter_rw(iter));
+ if (trace_android_fs_dataread_start_enabled() &&
+ (iov_iter_rw(iter) == READ)) {
+ char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
+
+ path = android_fstrace_get_pathname(pathbuf,
+ MAX_TRACE_PATHBUF_LEN,
+ inode);
+ trace_android_fs_dataread_start(inode, offset,
+ count, current->pid, path,
+ current->comm);
+ }
+ if (trace_android_fs_datawrite_start_enabled() &&
+ (iov_iter_rw(iter) == WRITE)) {
+ char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
+
+ path = android_fstrace_get_pathname(pathbuf,
+ MAX_TRACE_PATHBUF_LEN,
+ inode);
+ trace_android_fs_datawrite_start(inode, offset, count,
+ current->pid, path,
+ current->comm);
+ }
if (iov_iter_rw(iter) == WRITE) {
__allocate_data_blocks(inode, offset, count);
if (unlikely(f2fs_cp_error(F2FS_I_SB(inode)))) {
@@ -1599,6 +1633,13 @@ out:
if (err < 0 && iov_iter_rw(iter) == WRITE)
f2fs_write_failed(mapping, offset + count);
+ if (trace_android_fs_dataread_start_enabled() &&
+ (iov_iter_rw(iter) == READ))
+ trace_android_fs_dataread_end(inode, offset, count);
+ if (trace_android_fs_datawrite_start_enabled() &&
+ (iov_iter_rw(iter) == WRITE))
+ trace_android_fs_datawrite_end(inode, offset, count);
+
trace_f2fs_direct_IO_exit(inode, offset, count, iov_iter_rw(iter), err);
return err;
diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c
index bda7126466c0..dbb2cc4df603 100644
--- a/fs/f2fs/inline.c
+++ b/fs/f2fs/inline.c
@@ -13,6 +13,7 @@
#include "f2fs.h"
#include "node.h"
+#include <trace/events/android_fs.h>
bool f2fs_may_inline_data(struct inode *inode)
{
@@ -84,14 +85,29 @@ int f2fs_read_inline_data(struct inode *inode, struct page *page)
{
struct page *ipage;
+ if (trace_android_fs_dataread_start_enabled()) {
+ char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
+
+ path = android_fstrace_get_pathname(pathbuf,
+ MAX_TRACE_PATHBUF_LEN,
+ inode);
+ trace_android_fs_dataread_start(inode, page_offset(page),
+ PAGE_SIZE, current->pid,
+ path, current->comm);
+ }
+
ipage = get_node_page(F2FS_I_SB(inode), inode->i_ino);
if (IS_ERR(ipage)) {
+ trace_android_fs_dataread_end(inode, page_offset(page),
+ PAGE_SIZE);
unlock_page(page);
return PTR_ERR(ipage);
}
if (!f2fs_has_inline_data(inode)) {
f2fs_put_page(ipage, 1);
+ trace_android_fs_dataread_end(inode, page_offset(page),
+ PAGE_SIZE);
return -EAGAIN;
}
@@ -102,6 +118,8 @@ int f2fs_read_inline_data(struct inode *inode, struct page *page)
SetPageUptodate(page);
f2fs_put_page(ipage, 1);
+ trace_android_fs_dataread_end(inode, page_offset(page),
+ PAGE_SIZE);
unlock_page(page);
return 0;
}
diff --git a/fs/mpage.c b/fs/mpage.c
index 1480d3a18037..0fd48fdcc1b1 100644
--- a/fs/mpage.c
+++ b/fs/mpage.c
@@ -30,6 +30,14 @@
#include <linux/cleancache.h>
#include "internal.h"
+#define CREATE_TRACE_POINTS
+#include <trace/events/android_fs.h>
+
+EXPORT_TRACEPOINT_SYMBOL(android_fs_datawrite_start);
+EXPORT_TRACEPOINT_SYMBOL(android_fs_datawrite_end);
+EXPORT_TRACEPOINT_SYMBOL(android_fs_dataread_start);
+EXPORT_TRACEPOINT_SYMBOL(android_fs_dataread_end);
+
/*
* I/O completion handler for multipage BIOs.
*
@@ -47,6 +55,16 @@ static void mpage_end_io(struct bio *bio)
struct bio_vec *bv;
int i;
+ if (trace_android_fs_dataread_end_enabled() &&
+ (bio_data_dir(bio) == READ)) {
+ struct page *first_page = bio->bi_io_vec[0].bv_page;
+
+ if (first_page != NULL)
+ trace_android_fs_dataread_end(first_page->mapping->host,
+ page_offset(first_page),
+ bio->bi_iter.bi_size);
+ }
+
bio_for_each_segment_all(bv, bio, i) {
struct page *page = bv->bv_page;
page_endio(page, bio_data_dir(bio), bio->bi_error);
@@ -57,6 +75,24 @@ static void mpage_end_io(struct bio *bio)
static struct bio *mpage_bio_submit(int rw, struct bio *bio)
{
+ if (trace_android_fs_dataread_start_enabled() && (rw == READ)) {
+ struct page *first_page = bio->bi_io_vec[0].bv_page;
+
+ if (first_page != NULL) {
+ char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
+
+ path = android_fstrace_get_pathname(pathbuf,
+ MAX_TRACE_PATHBUF_LEN,
+ first_page->mapping->host);
+ trace_android_fs_dataread_start(
+ first_page->mapping->host,
+ page_offset(first_page),
+ bio->bi_iter.bi_size,
+ current->pid,
+ path,
+ current->comm);
+ }
+ }
bio->bi_end_io = mpage_end_io;
guard_bio_eod(rw, bio);
submit_bio(rw, bio);
diff --git a/include/linux/shrinker.h b/include/linux/shrinker.h
index 4fcacd915d45..e77f648f9662 100644
--- a/include/linux/shrinker.h
+++ b/include/linux/shrinker.h
@@ -66,6 +66,7 @@ struct shrinker {
/* Flags */
#define SHRINKER_NUMA_AWARE (1 << 0)
#define SHRINKER_MEMCG_AWARE (1 << 1)
+#define SHRINKER_LMK (1 << 2)
extern int register_shrinker(struct shrinker *);
extern void unregister_shrinker(struct shrinker *);
diff --git a/include/trace/events/android_fs.h b/include/trace/events/android_fs.h
new file mode 100644
index 000000000000..49509533d3fa
--- /dev/null
+++ b/include/trace/events/android_fs.h
@@ -0,0 +1,65 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM android_fs
+
+#if !defined(_TRACE_ANDROID_FS_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_ANDROID_FS_H
+
+#include <linux/tracepoint.h>
+#include <trace/events/android_fs_template.h>
+
+DEFINE_EVENT(android_fs_data_start_template, android_fs_dataread_start,
+ TP_PROTO(struct inode *inode, loff_t offset, int bytes,
+ pid_t pid, char *pathname, char *command),
+ TP_ARGS(inode, offset, bytes, pid, pathname, command));
+
+DEFINE_EVENT(android_fs_data_end_template, android_fs_dataread_end,
+ TP_PROTO(struct inode *inode, loff_t offset, int bytes),
+ TP_ARGS(inode, offset, bytes));
+
+DEFINE_EVENT(android_fs_data_start_template, android_fs_datawrite_start,
+ TP_PROTO(struct inode *inode, loff_t offset, int bytes,
+ pid_t pid, char *pathname, char *command),
+ TP_ARGS(inode, offset, bytes, pid, pathname, command));
+
+DEFINE_EVENT(android_fs_data_end_template, android_fs_datawrite_end,
+ TP_PROTO(struct inode *inode, loff_t offset, int bytes),
+ TP_ARGS(inode, offset, bytes));
+
+#endif /* _TRACE_ANDROID_FS_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
+
+#ifndef ANDROID_FSTRACE_GET_PATHNAME
+#define ANDROID_FSTRACE_GET_PATHNAME
+
+/* Sizes an on-stack array, so careful if sizing this up ! */
+#define MAX_TRACE_PATHBUF_LEN 256
+
+static inline char *
+android_fstrace_get_pathname(char *buf, int buflen, struct inode *inode)
+{
+ char *path;
+ struct dentry *d;
+
+ /*
+ * d_obtain_alias() will either iput() if it locates an existing
+ * dentry or transfer the reference to the new dentry created.
+ * So get an extra reference here.
+ */
+ ihold(inode);
+ d = d_obtain_alias(inode);
+ if (likely(!IS_ERR(d))) {
+ path = dentry_path_raw(d, buf, buflen);
+ if (unlikely(IS_ERR(path))) {
+ strcpy(buf, "ERROR");
+ path = buf;
+ }
+ dput(d);
+ } else {
+ strcpy(buf, "ERROR");
+ path = buf;
+ }
+ return path;
+}
+#endif
diff --git a/include/trace/events/android_fs_template.h b/include/trace/events/android_fs_template.h
new file mode 100644
index 000000000000..4e61ffe7a814
--- /dev/null
+++ b/include/trace/events/android_fs_template.h
@@ -0,0 +1,57 @@
+#if !defined(_TRACE_ANDROID_FS_TEMPLATE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_ANDROID_FS_TEMPLATE_H
+
+#include <linux/tracepoint.h>
+
+DECLARE_EVENT_CLASS(android_fs_data_start_template,
+ TP_PROTO(struct inode *inode, loff_t offset, int bytes,
+ pid_t pid, char *pathname, char *command),
+ TP_ARGS(inode, offset, bytes, pid, pathname, command),
+ TP_STRUCT__entry(
+ __string(pathbuf, pathname);
+ __field(loff_t, offset);
+ __field(int, bytes);
+ __field(loff_t, i_size);
+ __string(cmdline, command);
+ __field(pid_t, pid);
+ __field(ino_t, ino);
+ ),
+ TP_fast_assign(
+ {
+ __assign_str(pathbuf, pathname);
+ __entry->offset = offset;
+ __entry->bytes = bytes;
+ __entry->i_size = i_size_read(inode);
+ __assign_str(cmdline, command);
+ __entry->pid = pid;
+ __entry->ino = inode->i_ino;
+ }
+ ),
+ TP_printk("entry_name %s, offset %llu, bytes %d, cmdline %s,"
+ " pid %d, i_size %llu, ino %lu",
+ __get_str(pathbuf), __entry->offset, __entry->bytes,
+ __get_str(cmdline), __entry->pid, __entry->i_size,
+ (unsigned long) __entry->ino)
+);
+
+DECLARE_EVENT_CLASS(android_fs_data_end_template,
+ TP_PROTO(struct inode *inode, loff_t offset, int bytes),
+ TP_ARGS(inode, offset, bytes),
+ TP_STRUCT__entry(
+ __field(ino_t, ino);
+ __field(loff_t, offset);
+ __field(int, bytes);
+ ),
+ TP_fast_assign(
+ {
+ __entry->ino = inode->i_ino;
+ __entry->offset = offset;
+ __entry->bytes = bytes;
+ }
+ ),
+ TP_printk("ino %lu, offset %llu, bytes %d",
+ (unsigned long) __entry->ino,
+ __entry->offset, __entry->bytes)
+);
+
+#endif /* _TRACE_ANDROID_FS_TEMPLATE_H */
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 5e9e74955bd1..94fecacf0ddc 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -399,6 +399,35 @@ static unsigned long do_shrink_slab(struct shrink_control *shrinkctl,
return freed;
}
+static void shrink_slab_lmk(gfp_t gfp_mask, int nid,
+ struct mem_cgroup *memcg,
+ unsigned long nr_scanned,
+ unsigned long nr_eligible)
+{
+ struct shrinker *shrinker;
+
+ if (nr_scanned == 0)
+ nr_scanned = SWAP_CLUSTER_MAX;
+
+ if (!down_read_trylock(&shrinker_rwsem))
+ goto out;
+
+ list_for_each_entry(shrinker, &shrinker_list, list) {
+ struct shrink_control sc = {
+ .gfp_mask = gfp_mask,
+ };
+
+ if (!(shrinker->flags & SHRINKER_LMK))
+ continue;
+
+ do_shrink_slab(&sc, shrinker, nr_scanned, nr_eligible);
+ }
+
+ up_read(&shrinker_rwsem);
+out:
+ cond_resched();
+}
+
/**
* shrink_slab - shrink slab caches
* @gfp_mask: allocation context
@@ -460,6 +489,9 @@ static unsigned long shrink_slab(gfp_t gfp_mask, int nid,
.memcg = memcg,
};
+ if (shrinker->flags & SHRINKER_LMK)
+ continue;
+
if (memcg && !(shrinker->flags & SHRINKER_MEMCG_AWARE))
continue;
@@ -2626,6 +2658,7 @@ static bool shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
gfp_t orig_mask;
enum zone_type requested_highidx = gfp_zone(sc->gfp_mask);
bool reclaimable = false;
+ unsigned long lru_pages = 0;
/*
* If the number of buffer_heads in the machine exceeds the maximum
@@ -2653,6 +2686,7 @@ static bool shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
* to global LRU.
*/
if (global_reclaim(sc)) {
+ lru_pages += zone_reclaimable_pages(zone);
if (!cpuset_zone_allowed(zone,
GFP_KERNEL | __GFP_HARDWALL))
continue;
@@ -2703,6 +2737,9 @@ static bool shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
reclaimable = true;
}
+ if (global_reclaim(sc))
+ shrink_slab_lmk(sc->gfp_mask, 0, NULL,
+ sc->nr_scanned, lru_pages);
/*
* Restore to original mask to avoid the impact on the caller if we
* promoted it to __GFP_HIGHMEM.
@@ -3181,7 +3218,8 @@ static bool prepare_kswapd_sleep(pg_data_t *pgdat, int order, long remaining,
*/
static bool kswapd_shrink_zone(struct zone *zone,
int classzone_idx,
- struct scan_control *sc)
+ struct scan_control *sc,
+ unsigned long lru_pages)
{
unsigned long balance_gap;
bool lowmem_pressure;
@@ -3208,6 +3246,8 @@ static bool kswapd_shrink_zone(struct zone *zone,
return true;
shrink_zone(zone, sc, zone_idx(zone) == classzone_idx);
+ shrink_slab_lmk(sc->gfp_mask, zone_to_nid(zone), NULL,
+ sc->nr_scanned, lru_pages);
clear_bit(ZONE_WRITEBACK, &zone->flags);
@@ -3265,6 +3305,7 @@ static int balance_pgdat(pg_data_t *pgdat, int order, int classzone_idx)
do {
bool raise_priority = true;
+ unsigned long lru_pages = 0;
sc.nr_reclaimed = 0;
@@ -3322,6 +3363,15 @@ static int balance_pgdat(pg_data_t *pgdat, int order, int classzone_idx)
if (sc.priority < DEF_PRIORITY - 2)
sc.may_writepage = 1;
+ for (i = 0; i <= end_zone; i++) {
+ struct zone *zone = pgdat->node_zones + i;
+
+ if (!populated_zone(zone))
+ continue;
+
+ lru_pages += zone_reclaimable_pages(zone);
+ }
+
/*
* Now scan the zone in the dma->highmem direction, stopping
* at the last zone which needs scanning.
@@ -3358,7 +3408,7 @@ static int balance_pgdat(pg_data_t *pgdat, int order, int classzone_idx)
* that that high watermark would be met at 100%
* efficiency.
*/
- if (kswapd_shrink_zone(zone, end_zone, &sc))
+ if (kswapd_shrink_zone(zone, end_zone, &sc, lru_pages))
raise_priority = false;
}
diff --git a/sound/soc/msm/msm8998.c b/sound/soc/msm/msm8998.c
index 0f09c68ab344..f6a5d1344568 100644
--- a/sound/soc/msm/msm8998.c
+++ b/sound/soc/msm/msm8998.c
@@ -4203,6 +4203,13 @@ static int msm_set_pinctrl(struct msm_pinctrl_info *pinctrl_info,
ret = -EINVAL;
goto err;
}
+
+ if (pinctrl_info->pinctrl == NULL) {
+ pr_err("%s: pinctrl_info->pinctrl is NULL\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
curr_state = pinctrl_info->curr_state;
pinctrl_info->curr_state = new_state;
pr_debug("%s: curr_state = %s new_state = %s\n", __func__,
@@ -4471,6 +4478,7 @@ static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream)
struct snd_soc_card *card = rtd->card;
struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
+ int ret_pinctrl = 0;
dev_dbg(rtd->card->dev,
"%s: substream = %s stream = %d, dai name %s, dai ID %d\n",
@@ -4485,11 +4493,10 @@ static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream)
goto done;
}
if (index == QUAT_MI2S) {
- ret = msm_set_pinctrl(pinctrl_info, STATE_MI2S_ACTIVE);
- if (ret) {
+ ret_pinctrl = msm_set_pinctrl(pinctrl_info, STATE_MI2S_ACTIVE);
+ if (ret_pinctrl) {
pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
- __func__, ret);
- goto done;
+ __func__, ret_pinctrl);
}
}
@@ -4548,6 +4555,7 @@ static void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
struct snd_soc_card *card = rtd->card;
struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
+ int ret_pinctrl = 0;
pr_debug("%s(): substream = %s stream = %d\n", __func__,
substream->name, substream->stream);
@@ -4568,10 +4576,10 @@ static void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
mutex_unlock(&mi2s_intf_conf[index].lock);
if (index == QUAT_MI2S) {
- ret = msm_set_pinctrl(pinctrl_info, STATE_DISABLE);
- if (ret)
+ ret_pinctrl = msm_set_pinctrl(pinctrl_info, STATE_DISABLE);
+ if (ret_pinctrl)
pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
- __func__, ret);
+ __func__, ret_pinctrl);
}
}
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 6616edcd3347..f0a78dc8aee8 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -5193,7 +5193,7 @@ static int afe_sidetone(u16 tx_port_id, u16 rx_port_id, bool enable)
AFE_API_VERSION_LOOPBACK_CONFIG;
cmd_sidetone.cfg_data.dst_port_id = rx_port_id;
cmd_sidetone.cfg_data.routing_mode = LB_MODE_SIDETONE;
- cmd_sidetone.cfg_data.enable = ((enable == 1) ? sidetone_enable : 0);
+ cmd_sidetone.cfg_data.enable = enable;
pr_debug("%s rx(0x%x) tx(0x%x) enable(%d) mid(0x%x) gain(%d) sidetone_enable(%d)\n",
__func__, rx_port_id, tx_port_id,