diff options
51 files changed, 914 insertions, 189 deletions
diff --git a/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt b/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt index 4c676fa66e62..ff8fb76166a3 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt @@ -34,7 +34,7 @@ Optional properties: It is a four tuple consisting of min x, min y, max x and max y values. - goodix,i2c-pull-up : To specify pull up is required. - - goodix,no-force-update : To specify force update is allowed. + - goodix,force-update : To specify force update is allowed. - goodix,enable-power-off : Power off touchscreen during suspend. - goodix,button-map : Button map of key codes. The number of key codes depend on panel. diff --git a/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi index a1d80075abe0..3681f3d34b0c 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi @@ -85,14 +85,15 @@ asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, <&loopback>, <&compress>, <&hostless>, <&afe>, <&lsm>, <&routing>, <&cpe>, <&compr>, - <&pcm_noirq>; + <&pcm_noirq>, <&cpe3>; asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", "msm-pcm-dsp.2", "msm-voip-dsp", "msm-pcm-voice", "msm-pcm-loopback", "msm-compress-dsp", "msm-pcm-hostless", "msm-pcm-afe", "msm-lsm-client", "msm-pcm-routing", "msm-cpe-lsm", - "msm-compr-dsp", "msm-pcm-dsp-noirq"; + "msm-compr-dsp", "msm-pcm-dsp-noirq", + "msm-cpe-lsm.3"; asoc-cpu = <&dai_hdmi>, <&dai_dp>, <&dai_mi2s0>, <&dai_mi2s1>, <&dai_mi2s2>, <&dai_mi2s3>, @@ -244,6 +245,12 @@ cpe: qcom,msm-cpe-lsm { compatible = "qcom,msm-cpe-lsm"; + qcom,msm-cpe-lsm-id = <1>; + }; + + cpe3: qcom,msm-cpe-lsm@3 { + compatible = "qcom,msm-cpe-lsm"; + qcom,msm-cpe-lsm-id = <3>; }; qcom,wcd-dsp-mgr { diff --git a/arch/arm/boot/dts/qcom/msmcobalt-blsp.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-blsp.dtsi index 929a079c64c3..a660ea06795e 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-blsp.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-blsp.dtsi @@ -736,8 +736,10 @@ clocks = <&clock_gcc clk_gcc_blsp1_uart3_apps_clk>, <&clock_gcc clk_gcc_blsp1_ahb_clk>; pinctrl-names = "sleep", "default"; - pinctrl-0 = <&blsp1_uart3_sleep>; - pinctrl-1 = <&blsp1_uart3_active>; + pinctrl-0 = <&blsp1_uart3_tx_sleep>, <&blsp1_uart3_rxcts_sleep>, + <&blsp1_uart3_rfr_sleep>; + pinctrl-1 = <&blsp1_uart3_tx_active>, + <&blsp1_uart3_rxcts_active>, <&blsp1_uart3_rfr_active>; qcom,msm-bus,name = "buart3"; qcom,msm-bus,num-cases = <2>; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-pinctrl.dtsi index 3975bc5d16f5..e5fd988dccce 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-pinctrl.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-pinctrl.dtsi @@ -1223,29 +1223,83 @@ }; }; - blsp1_uart3_active: blsp1_uart3_active { - mux { - pins = "gpio45", "gpio46", "gpio47", "gpio48"; - function = "blsp_uart3_a"; + blsp1_uart3: blsp1_uart3 { + blsp1_uart3_tx_active: blsp1_uart3_tx_active { + mux { + pins = "gpio45"; + function = "blsp_uart3_a"; + }; + + config { + pins = "gpio45"; + drive-strength = <2>; + bias-disable; + }; }; - config { - pins = "gpio45", "gpio46", "gpio47", "gpio48"; - drive-strength = <2>; - bias-disable; + blsp1_uart3_tx_sleep: blsp1_uart3_tx_sleep { + mux { + pins = "gpio45"; + function = "gpio"; + }; + + config { + pins = "gpio45"; + drive-strength = <2>; + bias-pull-up; + }; }; - }; - blsp1_uart3_sleep: blsp1_uart3_sleep { - mux { - pins = "gpio45", "gpio46", "gpio47", "gpio48"; - function = "gpio"; + blsp1_uart3_rxcts_active: blsp1_uart3_rxcts_active { + mux { + pins = "gpio46", "gpio47"; + function = "blsp_uart3_a"; + }; + + config { + pins = "gpio46", "gpio47"; + drive-strength = <2>; + bias-disable; + }; }; - config { - pins = "gpio45", "gpio46", "gpio47", "gpio48"; - drive-strength = <2>; - bias-pull-up; + blsp1_uart3_rxcts_sleep: blsp1_uart3_rxcts_sleep { + mux { + pins = "gpio46", "gpio47"; + function = "gpio"; + }; + + config { + pins = "gpio46", "gpio47"; + drive-strength = <2>; + bias-no-pull; + }; + }; + + blsp1_uart3_rfr_active: blsp1_uart3_rfr_active { + mux { + pins = "gpio48"; + function = "blsp_uart3_a"; + }; + + config { + pins = "gpio48"; + drive-strength = <2>; + bias-disable; + }; + }; + + blsp1_uart3_rfr_sleep: blsp1_uart3_rfr_sleep { + mux { + pins = "gpio48"; + function = "gpio"; + }; + + config { + pins = "gpio48"; + drive-strength = <2>; + bias-no-pull; + }; }; }; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-v2.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-v2.dtsi index 81e2203a5e61..cde74aa2866d 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-v2.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-v2.dtsi @@ -326,18 +326,18 @@ 1900800000>; qcom,cpr-ro-scaling-factor = - <4001 4019 3747 3758 3564 3480 2336 - 2247 3442 3147 2136 4156 4028 3030 - 3727 3198>, - <4001 4019 3747 3758 3564 3480 2336 - 2247 3442 3147 2136 4156 4028 3030 - 3727 3198>, - <3704 3601 3465 3567 3356 3473 2686 - 2773 3049 2932 2235 3816 3800 3097 - 2966 2808>, - <2974 3092 3288 3329 2905 3096 3119 - 3225 2865 3140 2892 3592 3408 3576 - 1559 1392>; + <2595 2794 2577 2762 2471 2674 2199 + 2553 3189 3255 3192 2962 3054 2982 + 2042 2945>, + <2595 2794 2577 2762 2471 2674 2199 + 2553 3189 3255 3192 2962 3054 2982 + 2042 2945>, + <2391 2550 2483 2638 2382 2564 2259 + 2555 2766 3041 2988 2935 2873 2688 + 2013 2784>, + <2066 2153 2300 2434 2220 2386 2288 + 2465 2028 2511 2487 2734 2554 2117 + 1892 2377>; qcom,cpr-open-loop-voltage-fuse-adjustment = /* Speed bin 0 */ @@ -487,18 +487,18 @@ 2112000000 2208000000>; qcom,cpr-ro-scaling-factor = - <4001 4019 3747 3758 3564 3480 2336 - 2247 3442 3147 2136 4156 4028 3030 - 3727 3190>, - <4001 4019 3747 3758 3564 3480 2336 - 2247 3442 3147 2136 4156 4028 3030 - 3727 3198>, - <3704 3601 3465 3567 3356 3473 2686 - 2773 3049 2932 2235 3816 3800 3097 - 2966 2808>, - <2974 3092 3288 3329 2905 3096 3119 - 3225 2865 3140 2892 3592 3408 3576 - 1559 1392>; + <2857 3057 2828 2952 2699 2798 2446 + 2631 2629 2578 2244 3344 3289 3137 + 3164 2655>, + <2857 3057 2828 2952 2699 2798 2446 + 2631 2629 2578 2244 3344 3289 3137 + 3164 2655>, + <2603 2755 2676 2777 2573 2685 2465 + 2610 2312 2423 2243 3104 3022 3036 + 2740 2303>, + <1901 2016 2096 2228 2034 2161 2077 + 2188 1565 1870 1925 2235 2205 2413 + 1762 1478>; qcom,cpr-open-loop-voltage-fuse-adjustment = /* Speed bin 0 */ @@ -556,6 +556,7 @@ &gfx_cpr { compatible = "qcom,cpr4-msmcobalt-v2-mmss-regulator"; + qcom,cpr-aging-ref-voltage = <1024000>; }; &gfx_vreg { @@ -606,29 +607,50 @@ 0 0 1627 0 1578 1353 0 0>; qcom,cpr-ro-scaling-factor = - < 0 0 0 0 3005 3111 0 0 - 0 0 3487 0 3280 1896 1874 0>, - < 0 0 0 0 3005 3111 0 0 - 0 0 3487 0 3280 1896 1874 0>, - < 0 0 0 0 3005 3111 0 0 - 0 0 3487 0 3280 1896 1874 0>, - < 0 0 0 0 3005 3111 0 0 - 0 0 3487 0 3280 1896 1874 0>, - < 0 0 0 0 3005 3111 0 0 - 0 0 3487 0 3280 1896 1874 0>, - < 0 0 0 0 3005 3111 0 0 - 0 0 3487 0 3280 1896 1874 0>, - < 0 0 0 0 3005 3111 0 0 - 0 0 3487 0 3280 1896 1874 0>, - < 0 0 0 0 3005 3111 0 0 - 0 0 3487 0 3280 1896 1874 0>; + < 0 0 0 0 2377 2571 0 0 + 0 0 2168 0 2209 1849 1997 0>, + < 0 0 0 0 2377 2571 0 0 + 0 0 2168 0 2209 1849 1997 0>, + < 0 0 0 0 2377 2571 0 0 + 0 0 2168 0 2209 1849 1997 0>, + < 0 0 0 0 2377 2571 0 0 + 0 0 2168 0 2209 1849 1997 0>, + < 0 0 0 0 2377 2571 0 0 + 0 0 2168 0 2209 1849 1997 0>, + < 0 0 0 0 2377 2571 0 0 + 0 0 2168 0 2209 1849 1997 0>, + < 0 0 0 0 2377 2571 0 0 + 0 0 2168 0 2209 1849 1997 0>, + < 0 0 0 0 2377 2571 0 0 + 0 0 2168 0 2209 1849 1997 0>; qcom,cpr-open-loop-voltage-fuse-adjustment = - < 100000 0 0 0>; + < 100000 0 0 0>, + < 100000 0 0 0>, + < 85000 (-15000) (-15000) (-15000)>, + < 85000 (-15000) (-15000) (-15000)>, + < 85000 (-15000) (-15000) (-15000)>, + < 85000 (-15000) (-15000) (-15000)>, + < 85000 (-15000) (-15000) (-15000)>, + < 85000 (-15000) (-15000) (-15000)>; qcom,cpr-closed-loop-voltage-adjustment = < 96000 18000 4000 0 - 0 13000 9000 0>; + 0 13000 9000 0>, + < 96000 18000 4000 0 + 0 13000 9000 0>, + < 81000 3000 (-11000) (-15000) + (-15000) (-2000) (-6000) (-15000)>, + < 81000 3000 (-11000) (-15000) + (-15000) (-2000) (-6000) (-15000)>, + < 81000 3000 (-11000) (-15000) + (-15000) (-2000) (-6000) (-15000)>, + < 81000 3000 (-11000) (-15000) + (-15000) (-2000) (-6000) (-15000)>, + < 81000 3000 (-11000) (-15000) + (-15000) (-2000) (-6000) (-15000)>, + < 81000 3000 (-11000) (-15000) + (-15000) (-2000) (-6000) (-15000)>; qcom,cpr-floor-to-ceiling-max-range = <50000 50000 50000 50000 50000 50000 70000 70000>; @@ -642,7 +664,7 @@ qcom,cpr-aging-max-voltage-adjustment = <15000>; qcom,cpr-aging-ref-corner = <8>; qcom,cpr-aging-ro-scaling-factor = <2950>; - qcom,allow-aging-voltage-adjustment = <0>; + qcom,allow-aging-voltage-adjustment = <0 0 1 1 1 1 1 1>; }; &qusb_phy0 { diff --git a/arch/arm64/configs/msmcortex-perf_defconfig b/arch/arm64/configs/msmcortex-perf_defconfig index 5d2f29b053c4..0bda100dfb5a 100644 --- a/arch/arm64/configs/msmcortex-perf_defconfig +++ b/arch/arm64/configs/msmcortex-perf_defconfig @@ -321,6 +321,7 @@ CONFIG_QPNP_SMB2=y CONFIG_SMB138X_CHARGER=y CONFIG_QPNP_QNOVO=y CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_CPU_THERMAL=y CONFIG_LIMITS_MONITOR=y CONFIG_LIMITS_LITE_HW=y CONFIG_THERMAL_MONITOR=y diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig index 741f2e5bc8f6..3568fe4ed29f 100644 --- a/arch/arm64/configs/msmcortex_defconfig +++ b/arch/arm64/configs/msmcortex_defconfig @@ -324,6 +324,7 @@ CONFIG_QPNP_SMB2=y CONFIG_SMB138X_CHARGER=y CONFIG_QPNP_QNOVO=y CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_CPU_THERMAL=y CONFIG_LIMITS_MONITOR=y CONFIG_LIMITS_LITE_HW=y CONFIG_THERMAL_MONITOR=y diff --git a/drivers/devfreq/governor_bw_vbif.c b/drivers/devfreq/governor_bw_vbif.c index da1eefb8c94e..33e144b653d0 100644 --- a/drivers/devfreq/governor_bw_vbif.c +++ b/drivers/devfreq/governor_bw_vbif.c @@ -78,15 +78,13 @@ static int devfreq_vbif_ev_handler(struct devfreq *devfreq, case DEVFREQ_GOV_START: mutex_lock(&df_lock); df = devfreq; - if (df->profile->get_dev_status) - ret = df->profile->get_dev_status(df->dev.parent, - &stat); + if (df->profile->get_dev_status && + !df->profile->get_dev_status(df->dev.parent, &stat) && + stat.private_data) + dev_ab = stat.private_data; else - ret = 0; - if (ret || !stat.private_data) pr_warn("Device doesn't take AB votes!\n"); - else - dev_ab = stat.private_data; + mutex_unlock(&df_lock); ret = devfreq_vbif_update_bw(0, 0); diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c index 306465ededf9..766b052ade1d 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.c +++ b/drivers/hwtracing/coresight/coresight-tmc.c @@ -1143,6 +1143,12 @@ static int tmc_read_prepare(struct tmc_drvdata *drvdata) goto err; } + if (drvdata->config_type == TMC_CONFIG_TYPE_ETR && + drvdata->vaddr == NULL) { + ret = -ENOMEM; + goto err; + } + if (!drvdata->enable) goto out; diff --git a/drivers/input/misc/ots_pat9125/pat9125_linux_driver.c b/drivers/input/misc/ots_pat9125/pat9125_linux_driver.c index ca5a9ec2f7f9..fa5e4cca129d 100644 --- a/drivers/input/misc/ots_pat9125/pat9125_linux_driver.c +++ b/drivers/input/misc/ots_pat9125/pat9125_linux_driver.c @@ -31,6 +31,10 @@ struct pixart_pat9125_data { struct pinctrl_state *pinctrl_state_release; }; +/* Declaration of suspend and resume functions */ +static int pat9125_suspend(struct device *dev); +static int pat9125_resume(struct device *dev); + static int pat9125_i2c_write(struct i2c_client *client, u8 reg, u8 *data, int len) { @@ -146,6 +150,27 @@ static irqreturn_t pat9125_irq(int irq, void *dev_data) return IRQ_HANDLED; } +static ssize_t pat9125_suspend_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct pixart_pat9125_data *data = + (struct pixart_pat9125_data *) dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int mode; + + if (kstrtoint(buf, 10, &mode)) { + dev_err(dev, "failed to read input for sysfs\n"); + return -EINVAL; + } + + if (mode == 1) + pat9125_suspend(&client->dev); + else if (mode == 0) + pat9125_resume(&client->dev); + + return count; +} + static ssize_t pat9125_test_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -191,11 +216,15 @@ static ssize_t pat9125_test_show(struct device *dev, { return 0; } + +static DEVICE_ATTR(suspend, S_IRUGO | S_IWUSR | S_IWGRP, + NULL, pat9125_suspend_store); static DEVICE_ATTR(test, S_IRUGO | S_IWUSR | S_IWGRP, pat9125_test_show, pat9125_test_store); static struct attribute *pat9125_attr_list[] = { &dev_attr_test.attr, + &dev_attr_suspend.attr, NULL, }; diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.c b/drivers/input/touchscreen/gt9xx/gt9xx.c index a9d7666a6d6f..3b19a45922c4 100644 --- a/drivers/input/touchscreen/gt9xx/gt9xx.c +++ b/drivers/input/touchscreen/gt9xx/gt9xx.c @@ -115,6 +115,8 @@ struct i2c_client *i2c_connect_client; #define GTP_DEBUGFS_DIR "ts_debug" #define GTP_DEBUGFS_FILE_SUSPEND "suspend" +#define GTP_DEBUGFS_FILE_DATA "data" +#define GTP_DEBUGFS_FILE_ADDR "addr" /******************************************************* Function: @@ -1521,12 +1523,108 @@ static ssize_t gtp_fw_name_store(struct device *dev, return size; } +static ssize_t gtp_fw_upgrade_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct goodix_ts_data *ts = dev_get_drvdata(dev); + + return snprintf(buf, 2, "%d\n", ts->fw_loading); +} + +static ssize_t gtp_fw_upgrade_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct goodix_ts_data *ts = dev_get_drvdata(dev); + unsigned int val; + int ret; + + if (size > 2) + return -EINVAL; + + ret = kstrtouint(buf, 10, &val); + if (ret) + return ret; + + if (ts->gtp_is_suspend) { + dev_err(&ts->client->dev, + "Can't start fw upgrade. Device is in suspend state"); + return -EBUSY; + } + + mutex_lock(&ts->input_dev->mutex); + if (!ts->fw_loading && val) { + disable_irq(ts->client->irq); + ts->fw_loading = true; + if (config_enabled(CONFIG_GT9XX_TOUCHPANEL_UPDATE)) { + ret = gup_update_proc(NULL); + if (ret == FAIL) + dev_err(&ts->client->dev, + "Fail to update GTP firmware\n"); + } + ts->fw_loading = false; + enable_irq(ts->client->irq); + } + mutex_unlock(&ts->input_dev->mutex); + + return size; +} + +static ssize_t gtp_force_fw_upgrade_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct goodix_ts_data *ts = dev_get_drvdata(dev); + unsigned int val; + int ret; + + if (size > 2) + return -EINVAL; + + ret = kstrtouint(buf, 10, &val); + if (ret) + return ret; + + if (ts->gtp_is_suspend) { + dev_err(&ts->client->dev, + "Can't start fw upgrade. Device is in suspend state."); + return -EBUSY; + } + + mutex_lock(&ts->input_dev->mutex); + if (!ts->fw_loading && val) { + disable_irq(ts->client->irq); + ts->fw_loading = true; + ts->force_update = true; + if (config_enabled(CONFIG_GT9XX_TOUCHPANEL_UPDATE)) { + ret = gup_update_proc(NULL); + if (ret == FAIL) + dev_err(&ts->client->dev, + "Fail to force update GTP firmware.\n"); + } + ts->force_update = false; + ts->fw_loading = false; + enable_irq(ts->client->irq); + } + mutex_unlock(&ts->input_dev->mutex); + + return size; +} + static DEVICE_ATTR(fw_name, (S_IRUGO | S_IWUSR | S_IWGRP), gtp_fw_name_show, gtp_fw_name_store); +static DEVICE_ATTR(fw_upgrade, (S_IRUGO | S_IWUSR | S_IWGRP), + gtp_fw_upgrade_show, + gtp_fw_upgrade_store); +static DEVICE_ATTR(force_fw_upgrade, (S_IRUGO | S_IWUSR | S_IWGRP), + gtp_fw_upgrade_show, + gtp_force_fw_upgrade_store); static struct attribute *gtp_attrs[] = { &dev_attr_fw_name.attr, + &dev_attr_fw_upgrade.attr, + &dev_attr_force_fw_upgrade.attr, NULL }; @@ -1534,6 +1632,84 @@ static const struct attribute_group gtp_attr_grp = { .attrs = gtp_attrs, }; +static int gtp_debug_addr_is_valid(u16 addr) +{ + if (addr < GTP_VALID_ADDR_START || addr > GTP_VALID_ADDR_END) { + pr_err("GTP reg address is invalid: 0x%x\n", addr); + return false; + } + + return true; +} + +static int gtp_debug_data_set(void *_data, u64 val) +{ + struct goodix_ts_data *ts = _data; + + mutex_lock(&ts->input_dev->mutex); + if (gtp_debug_addr_is_valid(ts->addr)) + dev_err(&ts->client->dev, + "Writing to GTP registers not supported\n"); + mutex_unlock(&ts->input_dev->mutex); + + return 0; +} + +static int gtp_debug_data_get(void *_data, u64 *val) +{ + struct goodix_ts_data *ts = _data; + int ret; + u8 buf[3] = {0}; + + mutex_lock(&ts->input_dev->mutex); + buf[0] = ts->addr >> 8; + buf[1] = ts->addr & 0x00ff; + + if (gtp_debug_addr_is_valid(ts->addr)) { + ret = gtp_i2c_read(ts->client, buf, 3); + if (ret < 0) + dev_err(&ts->client->dev, + "GTP read register 0x%x failed (%d)\n", + ts->addr, ret); + else + *val = buf[2]; + } + mutex_unlock(&ts->input_dev->mutex); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(debug_data_fops, gtp_debug_data_get, + gtp_debug_data_set, "%llx\n"); + +static int gtp_debug_addr_set(void *_data, u64 val) +{ + struct goodix_ts_data *ts = _data; + + if (gtp_debug_addr_is_valid(val)) { + mutex_lock(&ts->input_dev->mutex); + ts->addr = val; + mutex_unlock(&ts->input_dev->mutex); + } + + return 0; +} + +static int gtp_debug_addr_get(void *_data, u64 *val) +{ + struct goodix_ts_data *ts = _data; + + mutex_lock(&ts->input_dev->mutex); + if (gtp_debug_addr_is_valid(ts->addr)) + *val = ts->addr; + mutex_unlock(&ts->input_dev->mutex); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(debug_addr_fops, gtp_debug_addr_get, + gtp_debug_addr_set, "%llx\n"); + static int gtp_debug_suspend_set(void *_data, u64 val) { struct goodix_ts_data *ts = _data; @@ -1567,7 +1743,7 @@ static int gtp_debugfs_init(struct goodix_ts_data *data) data->debug_base = debugfs_create_dir(GTP_DEBUGFS_DIR, NULL); if (IS_ERR_OR_NULL(data->debug_base)) { - pr_err("Failed to create debugfs dir\n"); + dev_err(&data->client->dev, "Failed to create debugfs dir\n"); return -EINVAL; } @@ -1576,7 +1752,27 @@ static int gtp_debugfs_init(struct goodix_ts_data *data) data->debug_base, data, &debug_suspend_fops)))) { - pr_err("Failed to create suspend file\n"); + dev_err(&data->client->dev, "Failed to create suspend file\n"); + debugfs_remove_recursive(data->debug_base); + return -EINVAL; + } + + if ((IS_ERR_OR_NULL(debugfs_create_file(GTP_DEBUGFS_FILE_DATA, + S_IWUSR | S_IWGRP | S_IRUSR | S_IRGRP, + data->debug_base, + data, + &debug_data_fops)))) { + dev_err(&data->client->dev, "Failed to create data file\n"); + debugfs_remove_recursive(data->debug_base); + return -EINVAL; + } + + if ((IS_ERR_OR_NULL(debugfs_create_file(GTP_DEBUGFS_FILE_ADDR, + S_IWUSR | S_IWGRP | S_IRUSR | S_IRGRP, + data->debug_base, + data, + &debug_addr_fops)))) { + dev_err(&data->client->dev, "Failed to create addr file\n"); debugfs_remove_recursive(data->debug_base); return -EINVAL; } @@ -1645,8 +1841,8 @@ static int goodix_parse_dt(struct device *dev, pdata->i2c_pull_up = of_property_read_bool(np, "goodix,i2c-pull-up"); - pdata->no_force_update = of_property_read_bool(np, - "goodix,no-force-update"); + pdata->force_update = of_property_read_bool(np, + "goodix,force-update"); pdata->enable_power_off = of_property_read_bool(np, "goodix,enable-power-off"); @@ -1761,9 +1957,7 @@ static int goodix_ts_probe(struct i2c_client *client, return -EINVAL; } -#if GTP_ESD_PROTECT i2c_connect_client = client; -#endif if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { dev_err(&client->dev, "GTP I2C not supported\n"); @@ -1811,22 +2005,24 @@ static int goodix_ts_probe(struct i2c_client *client, goto exit_power_off; } + if (pdata->force_update) + ts->force_update = true; + if (pdata->fw_name) strlcpy(ts->fw_name, pdata->fw_name, strlen(pdata->fw_name) + 1); -#ifdef CONFIG_GT9XX_TOUCHPANEL_UPDATE - ret = gup_init_update_proc(ts); - if (ret < 0) { - dev_err(&client->dev, - "GTP Create firmware update thread error.\n"); - goto exit_power_off; + if (config_enabled(CONFIG_GT9XX_TOUCHPANEL_UPDATE)) { + ret = gup_init_update_proc(ts); + if (ret < 0) { + dev_err(&client->dev, + "GTP Create firmware update thread error\n"); + goto exit_power_off; + } } -#endif - ret = gtp_init_panel(ts); if (ret < 0) { - dev_err(&client->dev, "GTP init panel failed.\n"); + dev_err(&client->dev, "GTP init panel failed\n"); ts->abs_x_max = GTP_MAX_WIDTH; ts->abs_y_max = GTP_MAX_HEIGHT; ts->int_trigger_type = GTP_INT_TRIGGER; @@ -1834,7 +2030,7 @@ static int goodix_ts_probe(struct i2c_client *client, ret = gtp_request_input_dev(ts); if (ret) { - dev_err(&client->dev, "GTP request input dev failed.\n"); + dev_err(&client->dev, "GTP request input dev failed\n"); goto exit_free_inputdev; } input_set_drvdata(ts->input_dev, ts); @@ -2017,6 +2213,14 @@ static int goodix_ts_suspend(struct device *dev) } mutex_lock(&ts->lock); + + if (ts->fw_loading) { + dev_info(&ts->client->dev, + "Fw upgrade in progress, can't go to suspend."); + mutex_unlock(&ts->lock); + return 0; + } + #if GTP_ESD_PROTECT gtp_esd_switch(ts->client, SWITCH_OFF); #endif diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.h b/drivers/input/touchscreen/gt9xx/gt9xx.h index 38487eea7b10..779a0ddd93f8 100644 --- a/drivers/input/touchscreen/gt9xx/gt9xx.h +++ b/drivers/input/touchscreen/gt9xx/gt9xx.h @@ -53,7 +53,7 @@ struct goodix_ts_platform_data { u32 panel_miny; u32 panel_maxx; u32 panel_maxy; - bool no_force_update; + bool force_update; bool i2c_pull_up; bool enable_power_off; size_t config_data_len[GOODIX_MAX_CFG_GROUP]; @@ -74,6 +74,7 @@ struct goodix_ts_data { s32 use_irq; u16 abs_x_max; u16 abs_y_max; + u16 addr; u8 max_touch_num; u8 int_trigger_type; u8 green_wake_mode; @@ -88,6 +89,8 @@ struct goodix_ts_data { u8 fw_error; bool power_on; struct mutex lock; + bool fw_loading; + bool force_update; struct regulator *avdd; struct regulator *vdd; struct regulator *vcc_i2c; @@ -172,6 +175,8 @@ extern u16 total_len; /* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */ #define GTP_I2C_ADDRESS_HIGH 0x14 #define GTP_I2C_ADDRESS_LOW 0x5D +#define GTP_VALID_ADDR_START 0x8040 +#define GTP_VALID_ADDR_END 0x8177 /* GTP CM_HEAD RW flags */ #define GTP_RW_READ 0 @@ -210,11 +215,9 @@ s32 init_wr_node(struct i2c_client *client); void uninit_wr_node(void); #endif -#ifdef CONFIG_GT9XX_TOUCHPANEL_UPDATE -extern u8 gup_init_update_proc(struct goodix_ts_data *ts); +u8 gup_init_update_proc(struct goodix_ts_data *ts); s32 gup_enter_update_mode(struct i2c_client *client); void gup_leave_update_mode(struct i2c_client *client); s32 gup_update_proc(void *dir); extern struct i2c_client *i2c_connect_client; -#endif #endif /* _GOODIX_GT9XX_H_ */ diff --git a/drivers/input/touchscreen/gt9xx/gt9xx_update.c b/drivers/input/touchscreen/gt9xx/gt9xx_update.c index 4660b27d156c..a91256c576e3 100644 --- a/drivers/input/touchscreen/gt9xx/gt9xx_update.c +++ b/drivers/input/touchscreen/gt9xx/gt9xx_update.c @@ -1408,10 +1408,15 @@ s32 gup_update_proc(void *dir) goto file_fail; } - ret = gup_enter_update_judge(ts->client, &fw_head); - if (ret == FAIL) { - pr_err("Check *.bin file fail"); - goto file_fail; + if (ts->force_update) { + dev_dbg(&ts->client->dev, "Enter force update."); + } else { + ret = gup_enter_update_judge(ts->client, &fw_head); + if (ret == FAIL) { + dev_err(&ts->client->dev, + "Check *.bin file fail."); + goto file_fail; + } } ts->enter_update = 1; diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index afa519aa8203..fda10abae58a 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1870,6 +1870,10 @@ free_irqs: arm_smmu_free_context_idx(smmu, cfg->cbndx); smmu_domain->smmu = NULL; + cfg->cbndx = INVALID_CBNDX; + cfg->irptndx = INVALID_IRPTNDX; + cfg->asid = INVALID_ASID; + cfg->vmid = INVALID_VMID; } static struct iommu_domain *arm_smmu_domain_alloc(unsigned type) @@ -2938,7 +2942,7 @@ static struct iommu_group *arm_smmu_device_group(struct device *dev) */ group = generic_device_group(dev); - if (IS_ERR(group)) + if (IS_ERR_OR_NULL(group)) return group; if (dev_is_pci(dev)) diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c index 98b29cc3a9e3..9e68af87b86c 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c @@ -1747,7 +1747,7 @@ static int msm_vfe40_axi_halt(struct vfe_device *vfe_dev, msm_camera_io_w(0xFEFFFEFF, vfe_dev->vfe_base + 0x34); msm_camera_io_w(0x1, vfe_dev->vfe_base + 0x24); - msm_isp_get_timestamp(&ts); + msm_isp_get_timestamp(&ts, vfe_dev); /* if any stream is waiting for update, signal complete */ for (i = VFE_PIX_0; i <= VFE_RAW_2; i++) { msm_isp_axi_stream_update(vfe_dev, i, &ts); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c index 0e14e0957a2a..fb4f7a1dcc92 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp44.c @@ -1377,7 +1377,7 @@ static int msm_vfe44_axi_halt(struct vfe_device *vfe_dev, msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x2C0); } - msm_isp_get_timestamp(&ts); + msm_isp_get_timestamp(&ts, vfe_dev); for (i = VFE_PIX_0; i <= VFE_RAW_2; i++) { /* if any stream is waiting for update, signal complete */ msm_isp_axi_stream_update(vfe_dev, i, &ts); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c index 5237b84e9477..d45b6ff0a7d0 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp46.c @@ -1464,7 +1464,7 @@ static int msm_vfe46_axi_halt(struct vfe_device *vfe_dev, msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x374); } - msm_isp_get_timestamp(&ts); + msm_isp_get_timestamp(&ts, vfe_dev); for (i = VFE_PIX_0; i <= VFE_RAW_2; i++) { msm_isp_axi_stream_update(vfe_dev, i, &ts); msm_isp_axi_stream_update(vfe_dev, i, &ts); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c index df7e2a88e7ca..6d1ad8ef6804 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c @@ -1798,7 +1798,7 @@ int msm_vfe47_axi_halt(struct vfe_device *vfe_dev, msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x400); } - msm_isp_get_timestamp(&ts); + msm_isp_get_timestamp(&ts, vfe_dev); for (i = VFE_PIX_0; i <= VFE_RAW_2; i++) { /* if any stream is waiting for update, signal fake completes */ msm_isp_axi_stream_update(vfe_dev, i, &ts); 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 7488f371545b..fbc2fee5a51d 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 @@ -1060,7 +1060,7 @@ void msm_isp_start_avtimer(void) avcs_core_disable_power_collapse(1); } -static inline void msm_isp_get_avtimer_ts( +void msm_isp_get_avtimer_ts( struct msm_isp_timestamp *time_stamp) { int rc = 0; @@ -1088,7 +1088,7 @@ void msm_isp_start_avtimer(void) pr_err("AV Timer is not supported\n"); } -static inline void msm_isp_get_avtimer_ts( +void msm_isp_get_avtimer_ts( struct msm_isp_timestamp *time_stamp) { pr_err_ratelimited("%s: Error: AVTimer driver not available\n", @@ -2282,7 +2282,7 @@ int msm_isp_axi_reset(struct vfe_device *vfe_dev, update_vfes[vfe_dev->pdev->id] = vfe_dev; } - msm_isp_get_timestamp(×tamp); + msm_isp_get_timestamp(×tamp, vfe_dev); for (k = 0; k < MAX_VFE; k++) { vfe_dev = update_vfes[k]; @@ -2700,8 +2700,8 @@ static int __msm_isp_check_stream_state(struct msm_vfe_axi_stream *stream_info, } -static void __msm_isp_stop_axi_streams(struct msm_vfe_axi_stream **streams, - int num_streams, int cmd_type) +static void __msm_isp_stop_axi_streams(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream **streams, int num_streams, int cmd_type) { int i; struct msm_vfe_axi_shared_data *axi_data; @@ -2712,11 +2712,10 @@ static void __msm_isp_stop_axi_streams(struct msm_vfe_axi_stream **streams, unsigned long flags; uint32_t intf; int rc; - struct vfe_device *vfe_dev; struct vfe_device *update_vfes[MAX_VFE] = {0, 0}; int k; - msm_isp_get_timestamp(×tamp); + msm_isp_get_timestamp(×tamp, vfe_dev); for (i = 0; i < num_streams; i++) { stream_info = streams[i]; @@ -2881,7 +2880,7 @@ static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev_ioctl, if (stream_cfg_cmd->num_streams > MAX_NUM_STREAM) return -EINVAL; - msm_isp_get_timestamp(×tamp); + msm_isp_get_timestamp(×tamp, vfe_dev_ioctl); for (i = 0; i < stream_cfg_cmd->num_streams; i++) { if (stream_cfg_cmd->stream_handle[i] == 0) @@ -3005,7 +3004,7 @@ static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev_ioctl, return 0; error: - __msm_isp_stop_axi_streams(streams, num_streams, + __msm_isp_stop_axi_streams(vfe_dev_ioctl, streams, num_streams, STOP_STREAM); return rc; @@ -3043,7 +3042,7 @@ static int msm_isp_stop_axi_stream(struct vfe_device *vfe_dev_ioctl, } streams[num_streams++] = stream_info; } - __msm_isp_stop_axi_streams(streams, num_streams, + __msm_isp_stop_axi_streams(vfe_dev_ioctl, streams, num_streams, stream_cfg_cmd->cmd); return rc; @@ -3172,7 +3171,7 @@ static int msm_isp_return_empty_buffer(struct vfe_device *vfe_dev, return rc; } - msm_isp_get_timestamp(×tamp); + msm_isp_get_timestamp(×tamp, vfe_dev); buf->buf_debug.put_state[buf->buf_debug.put_state_last] = MSM_ISP_BUFFER_STATE_DROP_REG; buf->buf_debug.put_state_last ^= 1; @@ -3576,7 +3575,7 @@ int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg) stream_info = msm_isp_get_stream_common_data(vfe_dev, HANDLE_TO_IDX(update_info->stream_handle)); stream_info->buf_divert = 0; - msm_isp_get_timestamp(×tamp); + msm_isp_get_timestamp(×tamp, vfe_dev); frame_id = vfe_dev->axi_data.src_info[ SRC_TO_INTF(stream_info->stream_src)].frame_id; /* set ping pong address to scratch before flush */ diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h index 84720f3d8625..9c642370b1a1 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.h @@ -27,6 +27,7 @@ void msm_isp_reset_framedrop(struct vfe_device *vfe_dev, struct msm_vfe_axi_stream *stream_info); int msm_isp_request_axi_stream(struct vfe_device *vfe_dev, void *arg); +void msm_isp_get_avtimer_ts(struct msm_isp_timestamp *time_stamp); int msm_isp_cfg_axi_stream(struct vfe_device *vfe_dev, void *arg); int msm_isp_release_axi_stream(struct vfe_device *vfe_dev, void *arg); int msm_isp_update_axi_stream(struct vfe_device *vfe_dev, void *arg); 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 afa498f80928..f1103183c326 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 @@ -852,7 +852,7 @@ int msm_isp_stats_reset(struct vfe_device *vfe_dev) unsigned long flags; int k; - msm_isp_get_timestamp(×tamp); + msm_isp_get_timestamp(×tamp, vfe_dev); if (vfe_dev->is_split) { for (i = 0; i < MAX_VFE; i++) @@ -1077,7 +1077,7 @@ static int msm_isp_start_stats_stream(struct vfe_device *vfe_dev_ioctl, uint32_t num_active_streams[MAX_VFE] = {0, 0}; struct vfe_device *vfe_dev; - msm_isp_get_timestamp(×tamp); + msm_isp_get_timestamp(×tamp, vfe_dev_ioctl); num_stats_comp_mask = vfe_dev_ioctl->hw_info->stats_hw_info->num_stats_comp_mask; @@ -1164,7 +1164,7 @@ static int msm_isp_stop_stats_stream(struct vfe_device *vfe_dev, struct msm_vfe_stats_stream *streams[MSM_ISP_STATS_MAX]; unsigned long flags; - msm_isp_get_timestamp(×tamp); + msm_isp_get_timestamp(×tamp, vfe_dev); num_stats_comp_mask = vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask; 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 71c907f2b381..b0789ce4a71c 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 @@ -198,13 +198,21 @@ uint32_t msm_isp_get_framedrop_period( return 1; } -void msm_isp_get_timestamp(struct msm_isp_timestamp *time_stamp) +void msm_isp_get_timestamp(struct msm_isp_timestamp *time_stamp, + struct vfe_device *vfe_dev) { struct timespec ts; - get_monotonic_boottime(&ts); - time_stamp->buf_time.tv_sec = ts.tv_sec; - time_stamp->buf_time.tv_usec = ts.tv_nsec/1000; do_gettimeofday(&(time_stamp->event_time)); + if (vfe_dev->vt_enable) { + msm_isp_get_avtimer_ts(time_stamp); + time_stamp->buf_time.tv_sec = time_stamp->vt_time.tv_sec; + time_stamp->buf_time.tv_usec = time_stamp->vt_time.tv_usec; + } else { + get_monotonic_boottime(&ts); + time_stamp->buf_time.tv_sec = ts.tv_sec; + time_stamp->buf_time.tv_usec = ts.tv_nsec/1000; + } + } static inline u32 msm_isp_evt_mask_to_isp_event(u32 evt_mask) @@ -1820,7 +1828,8 @@ static void msm_isp_enqueue_tasklet_cmd(struct vfe_device *vfe_dev, } queue_cmd->vfeInterruptStatus0 = irq_status0; queue_cmd->vfeInterruptStatus1 = irq_status1; - msm_isp_get_timestamp(&queue_cmd->ts); + msm_isp_get_timestamp(&queue_cmd->ts, vfe_dev); + queue_cmd->cmd_used = 1; vfe_dev->taskletq_idx = (vfe_dev->taskletq_idx + 1) % MSM_VFE_TASKLETQ_SIZE; diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h index 16e3198f35b7..f4280581a730 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.h @@ -70,5 +70,6 @@ void msm_isp_fetch_engine_done_notify(struct vfe_device *vfe_dev, struct msm_vfe_fetch_engine_info *fetch_engine_info); void msm_isp_print_fourcc_error(const char *origin, uint32_t fourcc_format); void msm_isp_flush_tasklet(struct vfe_device *vfe_dev); -void msm_isp_get_timestamp(struct msm_isp_timestamp *time_stamp); +void msm_isp_get_timestamp(struct msm_isp_timestamp *time_stamp, + struct vfe_device *vfe_dev); #endif /* __MSM_ISP_UTIL_H__ */ diff --git a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c index bf3973888573..a700f836061c 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c +++ b/drivers/media/platform/msm/camera_v2/sensor/actuator/msm_actuator.c @@ -1559,11 +1559,13 @@ static long msm_actuator_subdev_ioctl(struct v4l2_subdev *sd, pr_err("a_ctrl->i2c_client.i2c_func_tbl NULL\n"); return -EINVAL; } + mutex_lock(a_ctrl->actuator_mutex); rc = msm_actuator_power_down(a_ctrl); if (rc < 0) { pr_err("%s:%d Actuator Power down failed\n", __func__, __LINE__); } + mutex_unlock(a_ctrl->actuator_mutex); return msm_actuator_close(sd, NULL); default: return -ENOIOCTLCMD; diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_1_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_1_hwreg.h index bba0b2bc9cdb..07d522cb01bb 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_1_hwreg.h +++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/msm_csiphy_5_0_1_hwreg.h @@ -105,11 +105,11 @@ struct csiphy_settings_t csiphy_combo_mode_v5_0_1 = { { {0x818, 0x1}, {0x81c, 0x2}, - {0x004, 0x08}, - {0x704, 0x08}, - {0x204, 0x08}, - {0x404, 0x08}, - {0x604, 0x08}, + {0x004, 0x0C}, + {0x704, 0x0C}, + {0x204, 0x0C}, + {0x404, 0x0C}, + {0x604, 0x0C}, {0x02c, 0x1}, {0x22c, 0x1}, {0x42c, 0x1}, diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c index a4ee5041bfff..1a40aa1c78bd 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c +++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_cci_i2c.c @@ -69,6 +69,12 @@ int32_t msm_camera_cci_i2c_read_seq(struct msm_camera_i2c_client *client, || num_byte == 0) return rc; + if (num_byte > I2C_REG_DATA_MAX) { + S_I2C_DBG("%s: Error num_byte:0x%x exceeds max:0x%x\n", + __func__, num_byte, I2C_REG_DATA_MAX); + return rc; + } + buf = kzalloc(num_byte, GFP_KERNEL); if (!buf) { pr_err("%s:%d no memory\n", __func__, __LINE__); diff --git a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c index 7a0fb97061d5..62c5cf8c91d9 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c +++ b/drivers/media/platform/msm/camera_v2/sensor/io/msm_camera_qup_i2c.c @@ -73,7 +73,7 @@ int32_t msm_camera_qup_i2c_read(struct msm_camera_i2c_client *client, enum msm_camera_i2c_data_type data_type) { int32_t rc = -EFAULT; - unsigned char buf[client->addr_type+data_type]; + unsigned char *buf = NULL; if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR && client->addr_type != MSM_CAMERA_I2C_WORD_ADDR) @@ -81,6 +81,17 @@ int32_t msm_camera_qup_i2c_read(struct msm_camera_i2c_client *client, && data_type != MSM_CAMERA_I2C_WORD_DATA)) return rc; + if (client->addr_type > UINT_MAX - data_type) { + S_I2C_DBG("%s: integer overflow prevented\n", __func__); + return rc; + } + + buf = kzalloc(client->addr_type+data_type, GFP_KERNEL); + if (!buf) { + S_I2C_DBG("%s:%d no memory\n", __func__, __LINE__); + return -ENOMEM; + } + if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) { buf[0] = addr; } else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) { @@ -90,6 +101,8 @@ int32_t msm_camera_qup_i2c_read(struct msm_camera_i2c_client *client, rc = msm_camera_qup_i2c_rxdata(client, buf, data_type); if (rc < 0) { S_I2C_DBG("%s fail\n", __func__); + kfree(buf); + buf = NULL; return rc; } @@ -99,6 +112,8 @@ int32_t msm_camera_qup_i2c_read(struct msm_camera_i2c_client *client, *data = buf[0] << 8 | buf[1]; S_I2C_DBG("%s addr = 0x%x data: 0x%x\n", __func__, addr, *data); + kfree(buf); + buf = NULL; return rc; } @@ -106,7 +121,7 @@ int32_t msm_camera_qup_i2c_read_seq(struct msm_camera_i2c_client *client, uint32_t addr, uint8_t *data, uint32_t num_byte) { int32_t rc = -EFAULT; - unsigned char buf[client->addr_type+num_byte]; + unsigned char *buf = NULL; int i; if ((client->addr_type != MSM_CAMERA_I2C_BYTE_ADDR @@ -114,6 +129,22 @@ int32_t msm_camera_qup_i2c_read_seq(struct msm_camera_i2c_client *client, || num_byte == 0) return rc; + if (num_byte > I2C_REG_DATA_MAX) { + S_I2C_DBG("%s: Error num_byte:0x%x exceeds max:0x%x\n", + __func__, num_byte, I2C_REG_DATA_MAX); + return rc; + } + if (client->addr_type > UINT_MAX - num_byte) { + S_I2C_DBG("%s: integer overflow prevented\n", __func__); + return rc; + } + + buf = kzalloc(client->addr_type+num_byte, GFP_KERNEL); + if (!buf) { + S_I2C_DBG("%s:%d no memory\n", __func__, __LINE__); + return -ENOMEM; + } + if (client->addr_type == MSM_CAMERA_I2C_BYTE_ADDR) { buf[0] = addr; } else if (client->addr_type == MSM_CAMERA_I2C_WORD_ADDR) { @@ -123,6 +154,8 @@ int32_t msm_camera_qup_i2c_read_seq(struct msm_camera_i2c_client *client, rc = msm_camera_qup_i2c_rxdata(client, buf, num_byte); if (rc < 0) { S_I2C_DBG("%s fail\n", __func__); + kfree(buf); + buf = NULL; return rc; } @@ -132,6 +165,8 @@ int32_t msm_camera_qup_i2c_read_seq(struct msm_camera_i2c_client *client, S_I2C_DBG("Byte %d: 0x%x\n", i, buf[i]); S_I2C_DBG("Data: 0x%x\n", data[i]); } + kfree(buf); + buf = NULL; return rc; } diff --git a/drivers/media/platform/msm/vidc/msm_smem.c b/drivers/media/platform/msm/vidc/msm_smem.c index bb2715654f45..90047a608984 100644 --- a/drivers/media/platform/msm/vidc/msm_smem.c +++ b/drivers/media/platform/msm/vidc/msm_smem.c @@ -475,7 +475,7 @@ bool msm_smem_compare_buffers(void *clt, int fd, void *priv) } handle = ion_import_dma_buf(client->clnt, fd); ret = handle == priv; - handle ? ion_free(client->clnt, handle) : 0; + (!IS_ERR_OR_NULL(handle)) ? ion_free(client->clnt, handle) : 0; return ret; } diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index 8332c7f4db43..c87b6fc585c7 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -4263,7 +4263,7 @@ static inline int __suspend(struct venus_hfi_device *device) return 0; } - dprintk(VIDC_DBG, "Entering power collapse\n"); + dprintk(VIDC_PROF, "Entering power collapse\n"); if (device->res->pm_qos_latency_us && pm_qos_request_active(&device->qos)) @@ -4276,7 +4276,7 @@ static inline int __suspend(struct venus_hfi_device *device) } __venus_power_off(device, true); - dprintk(VIDC_INFO, "Venus power collapsed\n"); + dprintk(VIDC_PROF, "Venus power collapsed\n"); return rc; err_tzbsp_suspend: @@ -4298,7 +4298,7 @@ static inline int __resume(struct venus_hfi_device *device) return -EINVAL; } - dprintk(VIDC_DBG, "Resuming from power collapse\n"); + dprintk(VIDC_PROF, "Resuming from power collapse\n"); rc = __venus_power_on(device); if (rc) { dprintk(VIDC_ERR, "Failed to power on venus\n"); @@ -4334,7 +4334,7 @@ static inline int __resume(struct venus_hfi_device *device) pm_qos_add_request(&device->qos, PM_QOS_CPU_DMA_LATENCY, device->res->pm_qos_latency_us); } - dprintk(VIDC_INFO, "Resumed from power collapse\n"); + dprintk(VIDC_PROF, "Resumed from power collapse\n"); exit: device->skip_pc_count = 0; return rc; diff --git a/drivers/mfd/wcd934x-regmap.c b/drivers/mfd/wcd934x-regmap.c index e07350a1e2ce..3ed3d125f430 100644 --- a/drivers/mfd/wcd934x-regmap.c +++ b/drivers/mfd/wcd934x-regmap.c @@ -1904,6 +1904,9 @@ static bool wcd934x_is_volatile_register(struct device *dev, unsigned int reg) (reg <= WCD934X_CDC_ANC1_FB_GAIN_CTL)) return true; + if ((reg >= WCD934X_CODEC_CPR_WR_DATA_0) && + (reg <= WCD934X_CODEC_CPR_RD_DATA_3)) + return true; /* * Need to mark volatile for registers that are writable but diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index bd2132d77360..df3901093006 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -108,6 +108,11 @@ static void gsi_handle_ch_ctrl(int ee) GSIDBG("ch %x\n", ch); for (i = 0; i < 32; i++) { if ((1 << i) & ch) { + if (i >= gsi_ctx->max_ch || i >= GSI_CHAN_MAX) { + GSIERR("invalid channel %d\n", i); + break; + } + ctx = &gsi_ctx->chan[i]; val = gsi_readl(gsi_ctx->base + GSI_EE_n_GSI_CH_k_CNTXT_0_OFFS(i, ee)); @@ -116,6 +121,7 @@ static void gsi_handle_ch_ctrl(int ee) GSI_EE_n_GSI_CH_k_CNTXT_0_CHSTATE_SHFT; GSIDBG("ch %u state updated to %u\n", i, ctx->state); complete(&ctx->compl); + gsi_ctx->ch_dbg[i].cmd_completed++; } } @@ -135,6 +141,11 @@ static void gsi_handle_ev_ctrl(int ee) GSIDBG("ev %x\n", ch); for (i = 0; i < 32; i++) { if ((1 << i) & ch) { + if (i >= gsi_ctx->max_ev || i >= GSI_EVT_RING_MAX) { + GSIERR("invalid event %d\n", i); + break; + } + ctx = &gsi_ctx->evtr[i]; val = gsi_readl(gsi_ctx->base + GSI_EE_n_EV_CH_k_CNTXT_0_OFFS(i, ee)); @@ -1605,6 +1616,7 @@ int gsi_alloc_channel(struct gsi_chan_props *props, unsigned long dev_hdl, ctx->props = *props; mutex_lock(&gsi_ctx->mlock); + gsi_ctx->ch_dbg[props->ch_id].ch_allocate++; val = (((props->ch_id << GSI_EE_n_GSI_CH_CMD_CHID_SHFT) & GSI_EE_n_GSI_CH_CMD_CHID_BMSK) | ((op << GSI_EE_n_GSI_CH_CMD_OPCODE_SHFT) & @@ -1775,6 +1787,7 @@ int gsi_start_channel(unsigned long chan_hdl) mutex_lock(&gsi_ctx->mlock); init_completion(&ctx->compl); + gsi_ctx->ch_dbg[chan_hdl].ch_start++; val = (((chan_hdl << GSI_EE_n_GSI_CH_CMD_CHID_SHFT) & GSI_EE_n_GSI_CH_CMD_CHID_BMSK) | ((op << GSI_EE_n_GSI_CH_CMD_OPCODE_SHFT) & @@ -1832,6 +1845,7 @@ int gsi_stop_channel(unsigned long chan_hdl) mutex_lock(&gsi_ctx->mlock); init_completion(&ctx->compl); + gsi_ctx->ch_dbg[chan_hdl].ch_stop++; val = (((chan_hdl << GSI_EE_n_GSI_CH_CMD_CHID_SHFT) & GSI_EE_n_GSI_CH_CMD_CHID_BMSK) | ((op << GSI_EE_n_GSI_CH_CMD_OPCODE_SHFT) & @@ -1900,6 +1914,7 @@ int gsi_stop_db_channel(unsigned long chan_hdl) mutex_lock(&gsi_ctx->mlock); init_completion(&ctx->compl); + gsi_ctx->ch_dbg[chan_hdl].ch_db_stop++; val = (((chan_hdl << GSI_EE_n_GSI_CH_CMD_CHID_SHFT) & GSI_EE_n_GSI_CH_CMD_CHID_BMSK) | ((op << GSI_EE_n_GSI_CH_CMD_OPCODE_SHFT) & @@ -1964,6 +1979,7 @@ int gsi_reset_channel(unsigned long chan_hdl) reset: init_completion(&ctx->compl); + gsi_ctx->ch_dbg[chan_hdl].ch_reset++; val = (((chan_hdl << GSI_EE_n_GSI_CH_CMD_CHID_SHFT) & GSI_EE_n_GSI_CH_CMD_CHID_BMSK) | ((op << GSI_EE_n_GSI_CH_CMD_OPCODE_SHFT) & @@ -2030,6 +2046,7 @@ int gsi_dealloc_channel(unsigned long chan_hdl) mutex_lock(&gsi_ctx->mlock); init_completion(&ctx->compl); + gsi_ctx->ch_dbg[chan_hdl].ch_de_alloc++; val = (((chan_hdl << GSI_EE_n_GSI_CH_CMD_CHID_SHFT) & GSI_EE_n_GSI_CH_CMD_CHID_BMSK) | ((op << GSI_EE_n_GSI_CH_CMD_OPCODE_SHFT) & diff --git a/drivers/platform/msm/gsi/gsi.h b/drivers/platform/msm/gsi/gsi.h index 0b94ed2d3a92..750ae2b329d3 100644 --- a/drivers/platform/msm/gsi/gsi.h +++ b/drivers/platform/msm/gsi/gsi.h @@ -125,12 +125,23 @@ struct gsi_ee_scratch { uint32_t word1; }; +struct ch_debug_stats { + unsigned long ch_allocate; + unsigned long ch_start; + unsigned long ch_stop; + unsigned long ch_reset; + unsigned long ch_de_alloc; + unsigned long ch_db_stop; + unsigned long cmd_completed; +}; + struct gsi_ctx { void __iomem *base; struct device *dev; struct gsi_per_props per; bool per_registered; struct gsi_chan_ctx chan[GSI_CHAN_MAX]; + struct ch_debug_stats ch_dbg[GSI_CHAN_MAX]; struct gsi_evt_ctx evtr[GSI_EVT_RING_MAX]; struct mutex mlock; spinlock_t slock; diff --git a/drivers/power/qcom-charger/fg-core.h b/drivers/power/qcom-charger/fg-core.h index adc640c7afe1..a703b208f6e4 100644 --- a/drivers/power/qcom-charger/fg-core.h +++ b/drivers/power/qcom-charger/fg-core.h @@ -118,7 +118,14 @@ enum { DELTA_SOC_IRQ_WA = BIT(0), }; -/* SRAM parameters */ +/* + * List of FG_SRAM parameters. Please add a parameter only if it is an entry + * that will be used either to configure an entity (e.g. termination current) + * which might need some encoding (or) it is an entry that will be read from + * SRAM and decoded (e.g. CC_SOC_SW) for SW to use at various places. For + * generic read/writes to SRAM registers, please use fg_sram_read/write APIs + * directly without adding an entry here. + */ enum fg_sram_param_id { FG_SRAM_BATT_SOC = 0, FG_SRAM_VOLTAGE_PRED, diff --git a/drivers/power/qcom-charger/qpnp-fg-gen3.c b/drivers/power/qcom-charger/qpnp-fg-gen3.c index c0a19ae115d0..4ee94b990382 100644 --- a/drivers/power/qcom-charger/qpnp-fg-gen3.c +++ b/drivers/power/qcom-charger/qpnp-fg-gen3.c @@ -64,6 +64,8 @@ #define PROFILE_LOAD_OFFSET 0 #define NOM_CAP_WORD 58 #define NOM_CAP_OFFSET 0 +#define ACT_BATT_CAP_BKUP_WORD 74 +#define ACT_BATT_CAP_BKUP_OFFSET 0 #define CYCLE_COUNT_WORD 75 #define CYCLE_COUNT_OFFSET 0 #define PROFILE_INTEGRITY_WORD 79 @@ -156,8 +158,8 @@ static struct fg_sram_param pmicobalt_v1_sram_params[] = { fg_decode_cc_soc), PARAM(CC_SOC_SW, CC_SOC_SW_WORD, CC_SOC_SW_OFFSET, 4, 1, 1, 0, NULL, fg_decode_cc_soc), - PARAM(ACT_BATT_CAP, ACT_BATT_CAP_WORD, ACT_BATT_CAP_OFFSET, 2, 1, 1, 0, - NULL, fg_decode_default), + PARAM(ACT_BATT_CAP, ACT_BATT_CAP_BKUP_WORD, ACT_BATT_CAP_BKUP_OFFSET, 2, + 1, 1, 0, NULL, fg_decode_default), /* Entries below here are configurable during initialization */ PARAM(CUTOFF_VOLT, CUTOFF_VOLT_WORD, CUTOFF_VOLT_OFFSET, 2, 1000000, 244141, 0, fg_encode_voltage, NULL), @@ -208,8 +210,8 @@ static struct fg_sram_param pmicobalt_v2_sram_params[] = { fg_decode_cc_soc), PARAM(CC_SOC_SW, CC_SOC_SW_WORD, CC_SOC_SW_OFFSET, 4, 1, 1, 0, NULL, fg_decode_cc_soc), - PARAM(ACT_BATT_CAP, ACT_BATT_CAP_WORD, ACT_BATT_CAP_OFFSET, 2, 1, 1, 0, - NULL, fg_decode_default), + PARAM(ACT_BATT_CAP, ACT_BATT_CAP_BKUP_WORD, ACT_BATT_CAP_BKUP_OFFSET, 2, + 1, 1, 0, NULL, fg_decode_default), /* Entries below here are configurable during initialization */ PARAM(CUTOFF_VOLT, CUTOFF_VOLT_WORD, CUTOFF_VOLT_OFFSET, 2, 1000000, 244141, 0, fg_encode_voltage, NULL), @@ -504,8 +506,7 @@ static int fg_get_cc_soc_sw(struct fg_chip *chip, int *val) #define BATT_TEMP_DENR 1 static int fg_get_battery_temp(struct fg_chip *chip, int *val) { - int rc = 0; - u16 temp = 0; + int rc = 0, temp; u8 buf[2]; rc = fg_read(chip, BATT_INFO_BATT_TEMP_LSB(chip), buf, 2); @@ -887,10 +888,20 @@ static int fg_save_learned_cap_to_sram(struct fg_chip *chip) return -EPERM; cc_mah = div64_s64(chip->cl.learned_cc_uah, 1000); + /* Write to a backup register to use across reboot */ rc = fg_sram_write(chip, chip->sp[FG_SRAM_ACT_BATT_CAP].addr_word, chip->sp[FG_SRAM_ACT_BATT_CAP].addr_byte, (u8 *)&cc_mah, chip->sp[FG_SRAM_ACT_BATT_CAP].len, FG_IMA_DEFAULT); if (rc < 0) { + pr_err("Error in writing act_batt_cap_bkup, rc=%d\n", rc); + return rc; + } + + /* Write to actual capacity register for coulomb counter operation */ + rc = fg_sram_write(chip, ACT_BATT_CAP_WORD, ACT_BATT_CAP_OFFSET, + (u8 *)&cc_mah, chip->sp[FG_SRAM_ACT_BATT_CAP].len, + FG_IMA_DEFAULT); + if (rc < 0) { pr_err("Error in writing act_batt_cap, rc=%d\n", rc); return rc; } @@ -913,10 +924,11 @@ static int fg_load_learned_cap_from_sram(struct fg_chip *chip) } chip->cl.learned_cc_uah = act_cap_mah * 1000; - if (chip->cl.learned_cc_uah == 0) - chip->cl.learned_cc_uah = chip->cl.nom_cap_uah; if (chip->cl.learned_cc_uah != chip->cl.nom_cap_uah) { + if (chip->cl.learned_cc_uah == 0) + chip->cl.learned_cc_uah = chip->cl.nom_cap_uah; + delta_cc_uah = abs(chip->cl.learned_cc_uah - chip->cl.nom_cap_uah); pct_nom_cap_uah = div64_s64((int64_t)chip->cl.nom_cap_uah * @@ -927,16 +939,14 @@ static int fg_load_learned_cap_from_sram(struct fg_chip *chip) * the nominal capacity. */ if (chip->cl.nom_cap_uah && delta_cc_uah > pct_nom_cap_uah) { - fg_dbg(chip, FG_CAP_LEARN, "learned_cc_uah: %lld is higher than expected\n", - chip->cl.learned_cc_uah); - fg_dbg(chip, FG_CAP_LEARN, "Capping it to nominal:%lld\n", - chip->cl.nom_cap_uah); + fg_dbg(chip, FG_CAP_LEARN, "learned_cc_uah: %lld is higher than expected, capping it to nominal: %lld\n", + chip->cl.learned_cc_uah, chip->cl.nom_cap_uah); chip->cl.learned_cc_uah = chip->cl.nom_cap_uah; - rc = fg_save_learned_cap_to_sram(chip); - if (rc < 0) - pr_err("Error in saving learned_cc_uah, rc=%d\n", - rc); } + + rc = fg_save_learned_cap_to_sram(chip); + if (rc < 0) + pr_err("Error in saving learned_cc_uah, rc=%d\n", rc); } fg_dbg(chip, FG_CAP_LEARN, "learned_cc_uah:%lld nom_cap_uah: %lld\n", @@ -1663,7 +1673,7 @@ static void fg_notify_charger(struct fg_chip *chip) return; } - prop.intval = chip->bp.fastchg_curr_ma; + prop.intval = chip->bp.fastchg_curr_ma * 1000; rc = power_supply_set_property(chip->batt_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &prop); if (rc < 0) { diff --git a/drivers/power/qcom-charger/smb-lib.c b/drivers/power/qcom-charger/smb-lib.c index 5785e42e0140..de4391024970 100644 --- a/drivers/power/qcom-charger/smb-lib.c +++ b/drivers/power/qcom-charger/smb-lib.c @@ -1199,6 +1199,7 @@ int smblib_get_prop_batt_charge_type(struct smb_charger *chg, int smblib_get_prop_batt_health(struct smb_charger *chg, union power_supply_propval *val) { + union power_supply_propval pval; int rc; u8 stat; @@ -1212,9 +1213,19 @@ int smblib_get_prop_batt_health(struct smb_charger *chg, stat); if (stat & CHARGER_ERROR_STATUS_BAT_OV_BIT) { - smblib_err(chg, "battery over-voltage\n"); - val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; - goto done; + rc = smblib_get_prop_batt_voltage_now(chg, &pval); + if (!rc) { + /* + * If Vbatt is within 40mV above Vfloat, then don't + * treat it as overvoltage. + */ + if (pval.intval >= + get_effective_result(chg->fv_votable) + 40000) { + val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; + smblib_err(chg, "battery over-voltage\n"); + goto done; + } + } } if (stat & BAT_TEMP_STATUS_TOO_COLD_BIT) diff --git a/drivers/power/qcom-charger/smb1351-charger.c b/drivers/power/qcom-charger/smb1351-charger.c index 0f18844b9afa..79fbe33acf5d 100644 --- a/drivers/power/qcom-charger/smb1351-charger.c +++ b/drivers/power/qcom-charger/smb1351-charger.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015 The Linux Foundation. All rights reserved. +/* Copyright (c) 2016 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 @@ -1872,6 +1872,12 @@ static void smb1351_chg_adc_notification(enum qpnp_tm_state state, void *ctx) } } + if (!cur) { + pr_debug("Couldn't choose batt state, adc state=%d and temp=%d\n", + state, temp); + return; + } + if (cur->batt_present) chip->battery_missing = false; else diff --git a/drivers/soc/qcom/glink_spi_xprt.c b/drivers/soc/qcom/glink_spi_xprt.c index 66caa6ecaad2..47c66c892736 100644 --- a/drivers/soc/qcom/glink_spi_xprt.c +++ b/drivers/soc/qcom/glink_spi_xprt.c @@ -875,21 +875,20 @@ static void __rx_worker(struct edge_info *einfo) int rcu_id; rcu_id = srcu_read_lock(&einfo->use_ref); + if (einfo->in_ssr) { + srcu_read_unlock(&einfo->use_ref, rcu_id); + return; + } + if (unlikely(!einfo->rx_fifo_start)) { rx_avail = glink_spi_xprt_read_avail(einfo); if (!rx_avail) { srcu_read_unlock(&einfo->use_ref, rcu_id); return; } - einfo->in_ssr = false; einfo->xprt_if.glink_core_if_ptr->link_up(&einfo->xprt_if); } - if (einfo->in_ssr) { - srcu_read_unlock(&einfo->use_ref, rcu_id); - return; - } - glink_spi_xprt_set_poll_mode(einfo); while (inactive_cycles < MAX_INACTIVE_CYCLES) { if (einfo->tx_resume_needed && @@ -1818,9 +1817,16 @@ static int glink_wdsp_cmpnt_event_handler(struct device *dev, spi_dev = to_spi_device(sdev); einfo->spi_dev = spi_dev; break; + case WDSP_EVENT_POST_BOOTUP: + einfo->in_ssr = false; + synchronize_srcu(&einfo->use_ref); + /* No break here to trigger fake rx_worker */ case WDSP_EVENT_IPC1_INTR: queue_kthread_work(&einfo->kworker, &einfo->kwork); break; + case WDSP_EVENT_PRE_SHUTDOWN: + ssr(&einfo->xprt_if); + break; default: pr_debug("%s: unhandled event %d", __func__, event); break; @@ -2040,7 +2046,6 @@ static int glink_spi_probe(struct platform_device *pdev) init_xprt_cfg(einfo, subsys_name); init_xprt_if(einfo); - einfo->in_ssr = true; einfo->fifo_size = DEFAULT_FIFO_SIZE; init_kthread_work(&einfo->kwork, rx_worker); init_kthread_worker(&einfo->kworker); diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 2d3d96fe80e1..5e7f5c8bd2a1 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -2414,6 +2414,7 @@ static int icnss_call_driver_probe(struct icnss_priv *priv) out: icnss_hw_power_off(priv); + penv->ops = NULL; return ret; } @@ -2516,6 +2517,7 @@ static int icnss_driver_event_register_driver(void *data) power_off: icnss_hw_power_off(penv); + penv->ops = NULL; out: return ret; } diff --git a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c index dfd6b448a65f..e8969a5e533b 100644 --- a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c +++ b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c @@ -324,6 +324,7 @@ struct apr_svc_ch_dev *apr_tal_open(uint32_t clnt, uint32_t dest, uint32_t dl, pr_err("%s: glink_open failed %s\n", __func__, svc_names[dest][clnt]); apr_ch->handle = NULL; + rc = -EINVAL; goto unlock; } diff --git a/drivers/soc/qcom/watchdog_v2.c b/drivers/soc/qcom/watchdog_v2.c index 8f58eaa537b1..470ecfdd9f5e 100644 --- a/drivers/soc/qcom/watchdog_v2.c +++ b/drivers/soc/qcom/watchdog_v2.c @@ -701,7 +701,7 @@ static void init_watchdog_data(struct msm_watchdog_data *wdog_dd) wdog_dd->user_pet_complete = true; wdog_dd->user_pet_enabled = false; wake_up_process(wdog_dd->watchdog_task); - init_timer(&wdog_dd->pet_timer); + init_timer_deferrable(&wdog_dd->pet_timer); wdog_dd->pet_timer.data = (unsigned long)wdog_dd; wdog_dd->pet_timer.function = pet_task_wakeup; wdog_dd->pet_timer.expires = jiffies + delay_time; diff --git a/drivers/soc/qcom/wcd-dsp-glink.c b/drivers/soc/qcom/wcd-dsp-glink.c index 92cdadef715d..97d922fa5724 100644 --- a/drivers/soc/qcom/wcd-dsp-glink.c +++ b/drivers/soc/qcom/wcd-dsp-glink.c @@ -216,9 +216,9 @@ static bool wdsp_glink_notify_rx_intent_req(void *handle, const void *priv, mutex_lock(&ch->mutex); rc = glink_queue_rx_intent(ch->handle, ch, req_size); - if (IS_ERR_VALUE(ret)) { - dev_err(wpriv->dev, "%s: Failed to queue rx intent\n", - __func__); + if (IS_ERR_VALUE(rc)) { + dev_err(wpriv->dev, "%s: Failed to queue rx intent, rc = %d\n", + __func__, rc); mutex_unlock(&ch->mutex); goto done; } @@ -659,10 +659,13 @@ static ssize_t wdsp_glink_read(struct file *file, char __user *buf, count = WDSP_MAX_READ_SIZE; } /* - * This is unblocked only from glink rx notification callback - * or from flush API. + * Complete signal has given from glink rx notification callback + * or from flush API. Also use interruptible wait_for_completion API + * to allow the system to go in suspend. */ - wait_for_completion(&wpriv->rsp_complete); + ret = wait_for_completion_interruptible(&wpriv->rsp_complete); + if (ret) + goto done; mutex_lock(&wpriv->rsp_mutex); if (wpriv->rsp_cnt) { diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index 6ceac4f2d4b2..560c5c72daeb 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -103,6 +103,7 @@ struct cpufreq_cooling_device { int dyn_power_table_entries; struct device *cpu_dev; get_static_t plat_get_static_power; + struct cpu_cooling_ops *plat_ops; }; static DEFINE_IDR(cpufreq_idr); static DEFINE_MUTEX(cooling_cpufreq_lock); @@ -504,8 +505,13 @@ static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev, unsigned long *state) { struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; + unsigned int cpu = cpumask_any(&cpufreq_device->allowed_cpus); - *state = cpufreq_device->cpufreq_state; + if (cpufreq_device->plat_ops + && cpufreq_device->plat_ops->get_cur_state) + cpufreq_device->plat_ops->get_cur_state(cpu, state); + else + *state = cpufreq_device->cpufreq_state; return 0; } @@ -539,7 +545,17 @@ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev, cpufreq_device->cpufreq_state = state; cpufreq_device->clipped_freq = clip_freq; - cpufreq_update_policy(cpu); + /* Check if the device has a platform mitigation function that + * can handle the CPU freq mitigation, if not, notify cpufreq + * framework. + */ + if (cpufreq_device->plat_ops) { + if (cpufreq_device->plat_ops->ceil_limit) + cpufreq_device->plat_ops->ceil_limit(cpu, + clip_freq); + } else { + cpufreq_update_policy(cpu); + } return 0; } @@ -773,6 +789,9 @@ static unsigned int find_next_max(struct cpufreq_frequency_table *table, * @capacitance: dynamic power coefficient for these cpus * @plat_static_func: function to calculate the static power consumed by these * cpus (optional) + * @plat_mitig_func: function that does the mitigation by changing the + * frequencies (Optional). By default, cpufreq framweork will + * be notified of the new limits. * * This interface function registers the cpufreq cooling device with the name * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq @@ -785,7 +804,8 @@ static unsigned int find_next_max(struct cpufreq_frequency_table *table, static struct thermal_cooling_device * __cpufreq_cooling_register(struct device_node *np, const struct cpumask *clip_cpus, u32 capacitance, - get_static_t plat_static_func) + get_static_t plat_static_func, + struct cpu_cooling_ops *plat_ops) { struct thermal_cooling_device *cool_dev; struct cpufreq_cooling_device *cpufreq_dev; @@ -851,6 +871,8 @@ __cpufreq_cooling_register(struct device_node *np, } } + cpufreq_dev->plat_ops = plat_ops; + ret = get_idr(&cpufreq_idr, &cpufreq_dev->id); if (ret) { cool_dev = ERR_PTR(ret); @@ -924,7 +946,7 @@ free_cdev: struct thermal_cooling_device * cpufreq_cooling_register(const struct cpumask *clip_cpus) { - return __cpufreq_cooling_register(NULL, clip_cpus, 0, NULL); + return __cpufreq_cooling_register(NULL, clip_cpus, 0, NULL, NULL); } EXPORT_SYMBOL_GPL(cpufreq_cooling_register); @@ -948,7 +970,7 @@ of_cpufreq_cooling_register(struct device_node *np, if (!np) return ERR_PTR(-EINVAL); - return __cpufreq_cooling_register(np, clip_cpus, 0, NULL); + return __cpufreq_cooling_register(np, clip_cpus, 0, NULL, NULL); } EXPORT_SYMBOL_GPL(of_cpufreq_cooling_register); @@ -978,11 +1000,31 @@ cpufreq_power_cooling_register(const struct cpumask *clip_cpus, u32 capacitance, get_static_t plat_static_func) { return __cpufreq_cooling_register(NULL, clip_cpus, capacitance, - plat_static_func); + plat_static_func, NULL); } EXPORT_SYMBOL(cpufreq_power_cooling_register); /** + * cpufreq_platform_cooling_register() - create cpufreq cooling device with + * additional platform specific mitigation function. + * + * @clip_cpus: cpumask of cpus where the frequency constraints will happen + * @plat_ops: the platform mitigation functions that will be called insted of + * cpufreq, if provided. + * + * Return: a valid struct thermal_cooling_device pointer on success, + * on failure, it returns a corresponding ERR_PTR(). + */ +struct thermal_cooling_device * +cpufreq_platform_cooling_register(const struct cpumask *clip_cpus, + struct cpu_cooling_ops *plat_ops) +{ + return __cpufreq_cooling_register(NULL, clip_cpus, 0, NULL, + plat_ops); +} +EXPORT_SYMBOL(cpufreq_platform_cooling_register); + +/** * of_cpufreq_power_cooling_register() - create cpufreq cooling device with power extensions * @np: a valid struct device_node to the cooling device device tree node * @clip_cpus: cpumask of cpus where the frequency constraints will happen @@ -1015,7 +1057,7 @@ of_cpufreq_power_cooling_register(struct device_node *np, return ERR_PTR(-EINVAL); return __cpufreq_cooling_register(np, clip_cpus, capacitance, - plat_static_func); + plat_static_func, NULL); } EXPORT_SYMBOL(of_cpufreq_power_cooling_register); diff --git a/drivers/thermal/msm_lmh_dcvs.c b/drivers/thermal/msm_lmh_dcvs.c index fbe76eaa3867..3758e39a1c02 100644 --- a/drivers/thermal/msm_lmh_dcvs.c +++ b/drivers/thermal/msm_lmh_dcvs.c @@ -24,6 +24,7 @@ #include <linux/interrupt.h> #include <linux/timer.h> #include <linux/pm_opp.h> +#include <linux/cpu_cooling.h> #include <asm/smp_plat.h> #include <asm/cacheflush.h> @@ -40,6 +41,7 @@ #define MSM_LIMITS_NODE_DCVS 0x44435653 #define MSM_LIMITS_SUB_FN_THERMAL 0x54484D4C +#define MSM_LIMITS_SUB_FN_GENERAL 0x47454E00 #define MSM_LIMITS_ALGO_MODE_ENABLE 0x454E424C @@ -49,6 +51,8 @@ #define MSM_LIMITS_CLUSTER_0 0x6370302D #define MSM_LIMITS_CLUSTER_1 0x6370312D +#define MSM_LIMITS_DOMAIN_MAX 0x444D4158 + #define MSM_LIMITS_HIGH_THRESHOLD_VAL 95000 #define MSM_LIMITS_ARM_THRESHOLD_VAL 65000 #define MSM_LIMITS_POLLING_DELAY_MS 10 @@ -77,8 +81,12 @@ struct msm_lmh_dcvs_hw { cpumask_t core_map; struct timer_list poll_timer; uint32_t max_freq; + uint32_t hw_freq_limit; + struct list_head list; }; +LIST_HEAD(lmh_dcvs_hw_list); + static void msm_lmh_dcvs_get_max_freq(uint32_t cpu, uint32_t *max_freq) { unsigned long freq_ceil = UINT_MAX; @@ -99,12 +107,29 @@ static void msm_lmh_dcvs_get_max_freq(uint32_t cpu, uint32_t *max_freq) static uint32_t msm_lmh_mitigation_notify(struct msm_lmh_dcvs_hw *hw) { uint32_t max_limit = 0, val = 0; + struct device *cpu_dev = NULL; + unsigned long freq_val; val = readl_relaxed(hw->osm_hw_reg); dcvsh_get_frequency(val, max_limit); + cpu_dev = get_cpu_device(cpumask_first(&hw->core_map)); + if (!cpu_dev) { + pr_err("Error in get CPU%d device\n", + cpumask_first(&hw->core_map)); + goto notify_exit; + } + + freq_val = max_limit; + rcu_read_lock(); + dev_pm_opp_find_freq_floor(cpu_dev, &freq_val); + rcu_read_unlock(); + max_limit = freq_val; + sched_update_cpu_freq_min_max(&hw->core_map, 0, max_limit); trace_lmh_dcvs_freq(cpumask_first(&hw->core_map), max_limit); +notify_exit: + hw->hw_freq_limit = max_limit; return max_limit; } @@ -250,6 +275,45 @@ static int trip_notify(enum thermal_trip_type type, int temp, void *data) return 0; } +static struct msm_lmh_dcvs_hw *get_dcvsh_hw_from_cpu(int cpu) +{ + struct msm_lmh_dcvs_hw *hw; + + list_for_each_entry(hw, &lmh_dcvs_hw_list, list) { + if (cpumask_test_cpu(cpu, &hw->core_map)) + return hw; + } + + return NULL; +} + +static int lmh_set_max_limit(int cpu, u32 freq) +{ + struct msm_lmh_dcvs_hw *hw = get_dcvsh_hw_from_cpu(cpu); + + if (!hw) + return -EINVAL; + + return msm_lmh_dcvs_write(hw->affinity, MSM_LIMITS_SUB_FN_GENERAL, + MSM_LIMITS_DOMAIN_MAX, freq); +} + +static int lmh_get_cur_limit(int cpu, unsigned long *freq) +{ + struct msm_lmh_dcvs_hw *hw = get_dcvsh_hw_from_cpu(cpu); + + if (!hw) + return -EINVAL; + *freq = hw->hw_freq_limit; + + return 0; +} + +static struct cpu_cooling_ops cd_ops = { + .get_cur_state = lmh_get_cur_limit, + .ceil_limit = lmh_set_max_limit, +}; + static int msm_lmh_dcvs_probe(struct platform_device *pdev) { int ret; @@ -257,6 +321,7 @@ static int msm_lmh_dcvs_probe(struct platform_device *pdev) struct msm_lmh_dcvs_hw *hw; char sensor_name[] = "limits_sensor-00"; struct thermal_zone_device *tzdev; + struct thermal_cooling_device *cdev; struct device_node *dn = pdev->dev.of_node; struct device_node *cpu_node, *lmh_node; uint32_t id, max_freq, request_reg, clear_reg; @@ -331,6 +396,10 @@ static int msm_lmh_dcvs_probe(struct platform_device *pdev) if (IS_ERR_OR_NULL(tzdev)) return PTR_ERR(tzdev); + /* Setup cooling devices to request mitigation states */ + cdev = cpufreq_platform_cooling_register(&hw->core_map, &cd_ops); + if (IS_ERR_OR_NULL(cdev)) + return PTR_ERR(cdev); /* * Driver defaults to for low and hi thresholds. * Since we make a check for hi > lo value, set the hi threshold @@ -356,7 +425,7 @@ static int msm_lmh_dcvs_probe(struct platform_device *pdev) return ret; } - hw->max_freq = max_freq; + hw->hw_freq_limit = hw->max_freq = max_freq; switch (affinity) { case 0: @@ -399,6 +468,9 @@ static int msm_lmh_dcvs_probe(struct platform_device *pdev) return ret; } + INIT_LIST_HEAD(&hw->list); + list_add(&hw->list, &lmh_dcvs_hw_list); + return ret; } diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c index ec9288791667..f0d5c96ac2e0 100644 --- a/drivers/tty/serial/msm_serial_hs.c +++ b/drivers/tty/serial/msm_serial_hs.c @@ -1596,6 +1596,16 @@ static void flip_insert_work(struct work_struct *work) struct tty_struct *tty = msm_uport->uport.state->port.tty; spin_lock_irqsave(&msm_uport->uport.lock, flags); + if (!tty || msm_uport->rx.flush == FLUSH_SHUTDOWN) { + dev_err(msm_uport->uport.dev, + "%s:Invalid driver state flush %d\n", + __func__, msm_uport->rx.flush); + MSM_HS_ERR("%s:Invalid driver state flush %d\n", + __func__, msm_uport->rx.flush); + spin_unlock_irqrestore(&msm_uport->uport.lock, flags); + return; + } + if (msm_uport->rx.buffer_pending == NONE_PENDING) { MSM_HS_ERR("Error: No buffer pending in %s", __func__); spin_unlock_irqrestore(&msm_uport->uport.lock, flags); @@ -1668,6 +1678,16 @@ static void msm_serial_hs_rx_work(struct kthread_work *work) spin_lock_irqsave(&uport->lock, flags); + if (!tty || rx->flush == FLUSH_SHUTDOWN) { + dev_err(uport->dev, "%s:Invalid driver state flush %d\n", + __func__, rx->flush); + MSM_HS_ERR("%s:Invalid driver state flush %d\n", + __func__, rx->flush); + spin_unlock_irqrestore(&uport->lock, flags); + msm_hs_resource_unvote(msm_uport); + return; + } + /* * Process all pending descs or if nothing is * queued - called from termios @@ -3664,12 +3684,12 @@ static void msm_hs_shutdown(struct uart_port *uport) if (msm_uport->rx.flush != FLUSH_SHUTDOWN) { /* disable and disconnect rx */ - msm_hs_disconnect_rx(uport); ret = wait_event_timeout(msm_uport->rx.wait, - msm_uport->rx.flush == FLUSH_SHUTDOWN, 500); + !msm_uport->rx.pending_flag, 500); if (!ret) MSM_HS_WARN("%s(): rx disconnect not complete", __func__); + msm_hs_disconnect_rx(uport); } cancel_delayed_work_sync(&msm_uport->rx.flip_insert_work); diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index a72c874f19a5..2bc70d1cf6fa 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -538,7 +538,7 @@ static void phy_msg_received(struct usbpd *pd, enum pd_msg_type type, } if (len < 2) { - usbpd_err(&pd->dev, "invalid message received, len=%ld\n", len); + usbpd_err(&pd->dev, "invalid message received, len=%zd\n", len); return; } @@ -547,7 +547,7 @@ static void phy_msg_received(struct usbpd *pd, enum pd_msg_type type, len -= sizeof(u16); if (len % 4 != 0) { - usbpd_err(&pd->dev, "len=%ld not multiple of 4\n", len); + usbpd_err(&pd->dev, "len=%zd not multiple of 4\n", len); return; } @@ -566,7 +566,7 @@ static void phy_msg_received(struct usbpd *pd, enum pd_msg_type type, /* check header's count field to see if it matches len */ if (PD_MSG_HDR_COUNT(header) != (len / 4)) { - usbpd_err(&pd->dev, "header count (%d) mismatch, len=%ld\n", + usbpd_err(&pd->dev, "header count (%d) mismatch, len=%zd\n", PD_MSG_HDR_COUNT(header), len); return; } diff --git a/drivers/usb/pd/qpnp-pdphy.c b/drivers/usb/pd/qpnp-pdphy.c index 5b5e6210a1bb..0b9b60c3ca45 100644 --- a/drivers/usb/pd/qpnp-pdphy.c +++ b/drivers/usb/pd/qpnp-pdphy.c @@ -23,6 +23,8 @@ #include <linux/of_irq.h> #include <linux/debugfs.h> #include <linux/seq_file.h> +#include <linux/sched.h> +#include <linux/wait.h> #include "usbpd.h" #define USB_PDPHY_MAX_DATA_OBJ_LEN 28 diff --git a/include/linux/cpu_cooling.h b/include/linux/cpu_cooling.h index c156f5082758..e221494fb7a0 100644 --- a/include/linux/cpu_cooling.h +++ b/include/linux/cpu_cooling.h @@ -31,6 +31,11 @@ typedef int (*get_static_t)(cpumask_t *cpumask, int interval, unsigned long voltage, u32 *power); +struct cpu_cooling_ops { + int (*ceil_limit)(int, u32); + int (*get_cur_state)(int, unsigned long *); +}; + #ifdef CONFIG_CPU_THERMAL /** * cpufreq_cooling_register - function to create cpufreq cooling device. @@ -43,6 +48,10 @@ struct thermal_cooling_device * cpufreq_power_cooling_register(const struct cpumask *clip_cpus, u32 capacitance, get_static_t plat_static_func); +struct thermal_cooling_device * +cpufreq_platform_cooling_register(const struct cpumask *clip_cpus, + struct cpu_cooling_ops *ops); + /** * of_cpufreq_cooling_register - create cpufreq cooling device based on DT. * @np: a valid struct device_node to the cooling device device tree node. @@ -112,6 +121,13 @@ of_cpufreq_power_cooling_register(struct device_node *np, return NULL; } +static inline struct thermal_cooling_device * +cpufreq_platform_cooling_register(const struct cpumask *clip_cpus, + struct cpu_cooling_ops *ops) +{ + return NULL; +} + static inline void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) { diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 53f7b50b7541..c07d844c576e 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -2273,6 +2273,14 @@ void sched_exit(struct task_struct *p) kfree(p->ravg.curr_window_cpu); kfree(p->ravg.prev_window_cpu); + /* + * update_task_ravg() can be called for exiting tasks. While the + * function itself ensures correct behavior, the corresponding + * trace event requires that these pointers be NULL. + */ + p->ravg.curr_window_cpu = NULL; + p->ravg.prev_window_cpu = NULL; + enqueue_task(rq, p, 0); clear_ed_task(p, rq); task_rq_unlock(rq, p, &flags); diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index b2d4e08a55cc..ed984496aec1 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -10265,14 +10265,14 @@ static int tasha_codec_ec_buf_mux_enable(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_POST_PMU: snd_soc_write(codec, WCD9335_CPE_SS_EC_BUF_INT_PERIOD, 0x3B); - snd_soc_update_bits(codec, WCD9335_CPE_SS_CFG, 0x68, 0x28); + snd_soc_update_bits(codec, WCD9335_CPE_SS_CFG, 0x08, 0x08); snd_soc_update_bits(codec, WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0, 0x08, 0x08); break; case SND_SOC_DAPM_POST_PMD: snd_soc_update_bits(codec, WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0, 0x08, 0x00); - snd_soc_update_bits(codec, WCD9335_CPE_SS_CFG, 0x68, 0x40); + snd_soc_update_bits(codec, WCD9335_CPE_SS_CFG, 0x08, 0x00); snd_soc_write(codec, WCD9335_CPE_SS_EC_BUF_INT_PERIOD, 0x00); break; } diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c index a526e1afdd28..b8dcd264b5d2 100644 --- a/sound/soc/codecs/wcd934x/wcd934x.c +++ b/sound/soc/codecs/wcd934x/wcd934x.c @@ -260,6 +260,11 @@ static const struct intr_data wcd934x_intr_table[] = { {WCD934X_IRQ_VBAT_RESTORE, false}, }; +struct tavil_cpr_reg_defaults { + int wr_data; + int wr_addr; +}; + struct interp_sample_rate { int sample_rate; int rate_val; @@ -8035,6 +8040,25 @@ static const struct tavil_reg_mask_val tavil_codec_reg_init_1_1_val[] = { {WCD934X_HPH_NEW_INT_RDAC_HD2_CTL_R, 0xFF, 0x84}, }; +static const struct tavil_cpr_reg_defaults cpr_defaults[] = { + { 0x00000820, 0x00000094 }, + { 0x00000fC0, 0x00000048 }, + { 0x0000f000, 0x00000044 }, + { 0x0000bb80, 0xC0000178 }, + { 0x00000000, 0x00000160 }, + { 0x10854522, 0x00000060 }, + { 0x10854509, 0x00000064 }, + { 0x108544dd, 0x00000068 }, + { 0x108544ad, 0x0000006C }, + { 0x0000077E, 0x00000070 }, + { 0x000007da, 0x00000074 }, + { 0x00000000, 0x00000078 }, + { 0x00000000, 0x0000007C }, + { 0x00042029, 0x00000080 }, + { 0x4002002A, 0x00000090 }, + { 0x4002002B, 0x00000090 }, +}; + static const struct tavil_reg_mask_val tavil_codec_reg_init_common_val[] = { {WCD934X_CDC_CLSH_K2_MSB, 0x0F, 0x00}, {WCD934X_CDC_CLSH_K2_LSB, 0xFF, 0x60}, @@ -8094,6 +8118,33 @@ static void tavil_update_reg_defaults(struct tavil_priv *tavil) tavil_codec_reg_defaults[i].val); } +static void tavil_update_cpr_defaults(struct tavil_priv *tavil) +{ + int i; + struct wcd9xxx *wcd9xxx; + + wcd9xxx = tavil->wcd9xxx; + if (!TAVIL_IS_1_1(wcd9xxx)) + return; + + __tavil_cdc_mclk_enable(tavil, true); + + regmap_write(wcd9xxx->regmap, WCD934X_CODEC_CPR_SVS2_MIN_CX_VDD, 0x2C); + regmap_update_bits(wcd9xxx->regmap, WCD934X_CODEC_RPM_CLK_GATE, + 0x10, 0x00); + + for (i = 0; i < ARRAY_SIZE(cpr_defaults); i++) { + regmap_bulk_write(wcd9xxx->regmap, + WCD934X_CODEC_CPR_WR_DATA_0, + (u8 *)&cpr_defaults[i].wr_data, 4); + regmap_bulk_write(wcd9xxx->regmap, + WCD934X_CODEC_CPR_WR_ADDR_0, + (u8 *)&cpr_defaults[i].wr_addr, 4); + } + + __tavil_cdc_mclk_enable(tavil, false); +} + static void tavil_slim_interface_init_reg(struct snd_soc_codec *codec) { int i; @@ -9335,6 +9386,7 @@ static int tavil_probe(struct platform_device *pdev) tavil_update_reg_defaults(tavil); __tavil_enable_efuse_sensing(tavil); ___tavil_get_codec_fine_version(tavil); + tavil_update_cpr_defaults(tavil); /* Register with soc framework */ ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tavil, diff --git a/sound/soc/msm/msmcobalt.c b/sound/soc/msm/msmcobalt.c index 524f737360d8..c82e0ad13db3 100644 --- a/sound/soc/msm/msmcobalt.c +++ b/sound/soc/msm/msmcobalt.c @@ -512,10 +512,10 @@ static struct wcd_mbhc_config wcd_mbhc_cfg = { }; static struct snd_soc_dapm_route wcd_audio_paths[] = { - {"MIC BIAS1", NULL, "MCLK"}, - {"MIC BIAS2", NULL, "MCLK"}, - {"MIC BIAS3", NULL, "MCLK"}, - {"MIC BIAS4", NULL, "MCLK"}, + {"MIC BIAS1", NULL, "MCLK TX"}, + {"MIC BIAS2", NULL, "MCLK TX"}, + {"MIC BIAS3", NULL, "MCLK TX"}, + {"MIC BIAS4", NULL, "MCLK TX"}, }; static struct afe_clk_set mi2s_clk[MI2S_MAX] = { @@ -2463,6 +2463,37 @@ static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, return ret; } +static int msm_snd_enable_codec_ext_tx_clk(struct snd_soc_codec *codec, + int enable, bool dapm) +{ + int ret = 0; + + if (!strcmp(dev_name(codec->dev), "tasha_codec")) + ret = tasha_cdc_mclk_tx_enable(codec, enable, dapm); + else { + dev_err(codec->dev, "%s: unknown codec to enable ext clk\n", + __func__); + ret = -EINVAL; + } + return ret; +} + +static int msm_mclk_tx_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + pr_debug("%s: event = %d\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + return msm_snd_enable_codec_ext_tx_clk(codec, 1, true); + case SND_SOC_DAPM_POST_PMD: + return msm_snd_enable_codec_ext_tx_clk(codec, 0, true); + } + return 0; +} + static int msm_mclk_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -2485,6 +2516,9 @@ static const struct snd_soc_dapm_widget msm_dapm_widgets[] = { msm_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MCLK TX", SND_SOC_NOPM, 0, 0, + msm_mclk_tx_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SPK("Lineout_1 amp", NULL), SND_SOC_DAPM_SPK("Lineout_3 amp", NULL), SND_SOC_DAPM_SPK("Lineout_2 amp", NULL), @@ -4632,6 +4666,20 @@ static struct snd_soc_dai_link msm_tasha_fe_dai_links[] = { .codec_dai_name = "snd-soc-dummy-dai", .codec_name = "snd-soc-dummy", }, + /* CPE LSM EC PP direct dai-link */ + { + .name = "CPE Listen service ECPP", + .stream_name = "CPE Listen Audio Service ECPP", + .cpu_dai_name = "CPE_LSM_NOHOST", + .platform_name = "msm-cpe-lsm.3", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "tasha_cpe", + .codec_name = "tasha_codec", + }, }; static struct snd_soc_dai_link msm_tavil_fe_dai_links[] = { |
