Merge "msm: vidc: Adds support to send frame rate to Video Hardware" into msm-3.4
diff --git a/arch/arm/boot/dts/msm8974-gpio.dtsi b/arch/arm/boot/dts/msm8974-gpio.dtsi
index 323fac4..5d93fa3 100644
--- a/arch/arm/boot/dts/msm8974-gpio.dtsi
+++ b/arch/arm/boot/dts/msm8974-gpio.dtsi
@@ -25,14 +25,26 @@
};
gpio@c200 {
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
status = "ok";
};
gpio@c300 {
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
status = "ok";
};
gpio@c400 {
+ qcom,mode = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,select = <0>;
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index c5b53d7..194717c 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -788,6 +788,37 @@
qcom,temp-hysteresis = <10>;
qcom,freq-step = <2>;
};
+
+ gpio_keys {
+ compatible = "gpio-keys";
+
+ camera_snapshot {
+ label = "camera_snapshot";
+ gpios = <&pm8941_gpios 3 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x2fe>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ camera_focus {
+ label = "camera_focus";
+ gpios = <&pm8941_gpios 4 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x210>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&pm8941_gpios 5 0x1>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ };
+ };
};
/include/ "msm-pm8x41-rpm-regulator.dtsi"
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index 518579a..1f39d3f 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -394,6 +394,7 @@
.v_cutoff = 3400,
.max_voltage_uv = MAX_VOLTAGE_MV * 1000,
.shutdown_soc_valid_limit = 20,
+ .adjust_soc_low_threshold = 25,
};
static struct pm8921_platform_data
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index 384b1cf..c16f55d 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -345,6 +345,7 @@
.v_cutoff = 3400,
.max_voltage_uv = MAX_VOLTAGE_MV * 1000,
.shutdown_soc_valid_limit = 20,
+ .adjust_soc_low_threshold = 25,
};
static struct pm8038_platform_data pm8038_platform_data __devinitdata = {
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index 98140b4..46d317b 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -426,6 +426,7 @@
.max_voltage_uv = MAX_VOLTAGE_MV * 1000,
.rconn_mohm = 18,
.shutdown_soc_valid_limit = 20,
+ .adjust_soc_low_threshold = 25,
};
#define PM8921_LC_LED_MAX_CURRENT 4 /* I = 4mA */
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 95d2f17..b5d38d5 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -1010,8 +1010,16 @@
int dpm_suspend_end(pm_message_t state)
{
int error = dpm_suspend_late(state);
+ if (error)
+ return error;
- return error ? : dpm_suspend_noirq(state);
+ error = dpm_suspend_noirq(state);
+ if (error) {
+ dpm_resume_early(state);
+ return error;
+ }
+
+ return 0;
}
EXPORT_SYMBOL_GPL(dpm_suspend_end);
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index c0a35f9..1894465 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.c
@@ -2347,37 +2347,6 @@
int retval;
radio->region = req_region;
- switch (radio->region) {
- case IRIS_REGION_US:
- radio->recv_conf.band_low_limit =
- REGION_US_EU_BAND_LOW;
- radio->recv_conf.band_high_limit =
- REGION_US_EU_BAND_HIGH;
- break;
- case IRIS_REGION_EU:
- radio->recv_conf.band_low_limit =
- REGION_US_EU_BAND_LOW;
- radio->recv_conf.band_high_limit =
- REGION_US_EU_BAND_HIGH;
- break;
- case IRIS_REGION_JAPAN:
- radio->recv_conf.band_low_limit =
- REGION_JAPAN_STANDARD_BAND_LOW;
- radio->recv_conf.band_high_limit =
- REGION_JAPAN_STANDARD_BAND_HIGH;
- break;
- case IRIS_REGION_JAPAN_WIDE:
- radio->recv_conf.band_low_limit =
- REGION_JAPAN_WIDE_BAND_LOW;
- radio->recv_conf.band_high_limit =
- REGION_JAPAN_WIDE_BAND_HIGH;
- break;
- default:
- /* The user specifies the value.
- So nothing needs to be done */
- break;
- }
-
retval = hci_set_fm_recv_conf(
&radio->recv_conf,
radio->fm_hdev);
@@ -2391,34 +2360,6 @@
int retval;
radio->region = req_region;
- switch (radio->region) {
- case IRIS_REGION_US:
- radio->trans_conf.band_low_limit =
- REGION_US_EU_BAND_LOW;
- radio->trans_conf.band_high_limit =
- REGION_US_EU_BAND_HIGH;
- break;
- case IRIS_REGION_EU:
- radio->trans_conf.band_low_limit =
- REGION_US_EU_BAND_LOW;
- radio->trans_conf.band_high_limit =
- REGION_US_EU_BAND_HIGH;
- break;
- case IRIS_REGION_JAPAN:
- radio->trans_conf.band_low_limit =
- REGION_JAPAN_STANDARD_BAND_LOW;
- radio->trans_conf.band_high_limit =
- REGION_JAPAN_STANDARD_BAND_HIGH;
- break;
- case IRIS_REGION_JAPAN_WIDE:
- radio->recv_conf.band_low_limit =
- REGION_JAPAN_WIDE_BAND_LOW;
- radio->recv_conf.band_high_limit =
- REGION_JAPAN_WIDE_BAND_HIGH;
- default:
- break;
- }
-
retval = hci_set_fm_trans_conf(
&radio->trans_conf,
radio->fm_hdev);
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 4de5752..88e0948 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -28,6 +28,7 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mutex.h>
+#include <linux/rtc.h>
#define BMS_CONTROL 0x224
#define BMS_S1_DELAY 0x225
@@ -50,6 +51,9 @@
#define TEMP_SOC_STORAGE 0x107
+#define TEMP_IAVG_STORAGE 0x105
+#define TEMP_IAVG_STORAGE_USE_MASK 0x0F
+
enum pmic_bms_interrupts {
PM8921_BMS_SBI_WRITE_OK,
PM8921_BMS_CC_THR,
@@ -126,14 +130,20 @@
int last_ocv_uv;
int pon_ocv_uv;
int last_cc_uah;
- struct timeval t;
+ unsigned long tm_sec;
int enable_fcc_learning;
int shutdown_soc;
+ int shutdown_iavg_ua;
int shutdown_soc_timer_expired;
struct delayed_work shutdown_soc_work;
struct delayed_work calculate_soc_delayed_work;
struct timespec t_soc_queried;
int shutdown_soc_valid_limit;
+ int ignore_shutdown_soc;
+ int prev_iavg_ua;
+ int prev_uuc_iavg_ma;
+ int prev_pc_unusable;
+ int adjust_soc_low_threshold;
};
/*
@@ -475,8 +485,8 @@
return div_s64(cc * CC_RESOLUTION_N, CC_RESOLUTION_D);
}
-#define CC_READING_TICKS 55
-#define SLEEP_CLK_HZ 32768
+#define CC_READING_TICKS 56
+#define SLEEP_CLK_HZ 32764
#define SECONDS_PER_HOUR 3600
/**
* ccmicrovolt_to_nvh -
@@ -1148,59 +1158,168 @@
*val = cc_uah;
}
-static int calculate_uuc_uah_at_given_current(struct pm8921_bms_chip *chip,
+static int calculate_termination_uuc(struct pm8921_bms_chip *chip,
int batt_temp, int chargecycles,
- int rbatt, int fcc_uah, int i_ma)
+ int fcc_uah, int i_ma,
+ int *ret_pc_unusable)
{
int unusable_uv, pc_unusable, uuc;
+ int i = 0;
+ int ocv_mv;
+ int batt_temp_degc = batt_temp / 10;
+ int rbatt_mohm;
+ int delta_uv;
+ int prev_delta_uv = 0;
+ int prev_rbatt_mohm = 0;
+ int prev_ocv_mv = 0;
+ int uuc_rbatt_uv;
- /* calculate unusable charge with itest */
- unusable_uv = (rbatt * i_ma) + (chip->v_cutoff * 1000);
+ for (i = 0; i <= 100; i++) {
+ ocv_mv = interpolate_ocv(chip, batt_temp_degc, i);
+ rbatt_mohm = get_rbatt(chip, i, batt_temp);
+ unusable_uv = (rbatt_mohm * i_ma) + (chip->v_cutoff * 1000);
+ delta_uv = ocv_mv * 1000 - unusable_uv;
+
+ pr_debug("soc = %d ocv = %d rbat = %d u_uv = %d delta_v = %d\n",
+ i, ocv_mv, rbatt_mohm, unusable_uv, delta_uv);
+
+ if (delta_uv > 0)
+ break;
+
+ prev_delta_uv = delta_uv;
+ prev_rbatt_mohm = rbatt_mohm;
+ prev_ocv_mv = ocv_mv;
+ }
+
+ uuc_rbatt_uv = linear_interpolate(rbatt_mohm, delta_uv,
+ prev_rbatt_mohm, prev_delta_uv,
+ 0);
+
+ unusable_uv = (uuc_rbatt_uv * i_ma) + (chip->v_cutoff * 1000);
+
pc_unusable = calculate_pc(chip, unusable_uv, batt_temp, chargecycles);
uuc = (fcc_uah * pc_unusable) / 100;
- pr_debug("For i_ma = %d, unusable_uv = %d unusable_pc = %d uuc = %d\n",
- i_ma, unusable_uv, pc_unusable, uuc);
+ pr_debug("For i_ma = %d, unusable_rbatt = %d unusable_uv = %d unusable_pc = %d uuc = %d\n",
+ i_ma, uuc_rbatt_uv, unusable_uv,
+ pc_unusable, uuc);
+ *ret_pc_unusable = pc_unusable;
return uuc;
}
-static void calculate_iavg_ua(struct pm8921_bms_chip *chip, int cc_uah,
- int *iavg_ua, int *delta_time_us)
+static int adjust_uuc(struct pm8921_bms_chip *chip, int fcc_uah,
+ int new_pc_unusable,
+ int new_uuc,
+ int batt_temp,
+ int rbatt,
+ int *iavg_ma)
{
- int delta_cc_uah;
- struct timeval now;
+ int new_unusable_mv;
+ int batt_temp_degc = batt_temp / 10;
- delta_cc_uah = cc_uah - chip->last_cc_uah;
- do_gettimeofday(&now);
- if (chip->t.tv_sec != 0) {
- *delta_time_us = (now.tv_sec - chip->t.tv_sec) * USEC_PER_SEC
- + now.tv_usec - chip->t.tv_usec;
- } else {
- /* calculation for the first time */
- *delta_time_us = 0;
+ if (chip->prev_pc_unusable == -EINVAL
+ || abs(chip->prev_pc_unusable - new_pc_unusable) <= 1) {
+ chip->prev_pc_unusable = new_pc_unusable;
+ return new_uuc;
}
- if (*delta_time_us != 0)
- *iavg_ua = div_s64((s64)delta_cc_uah * 3600 * 1000000,
- *delta_time_us);
+ /* the uuc is trying to change more than 1% restrict it */
+ if (new_pc_unusable > chip->prev_pc_unusable)
+ chip->prev_pc_unusable++;
else
- *iavg_ua = 0;
+ chip->prev_pc_unusable--;
- pr_debug("t.tv_sec = %d, now.tv_sec = %d delta_us = %d iavg_ua = %d\n",
- (int)chip->t.tv_sec, (int)now.tv_sec,
- *delta_time_us, (int)*iavg_ua);
+ new_uuc = (fcc_uah * chip->prev_pc_unusable) / 100;
+
+ /* also find update the iavg_ma accordingly */
+ new_unusable_mv = interpolate_ocv(chip, batt_temp_degc,
+ chip->prev_pc_unusable);
+ if (new_unusable_mv < chip->v_cutoff)
+ new_unusable_mv = chip->v_cutoff;
+
+ *iavg_ma = (new_unusable_mv - chip->v_cutoff) * 1000 / rbatt;
+ if (*iavg_ma == 0)
+ *iavg_ma = 1;
+ pr_debug("Restricting UUC to %d (%d%%) unusable_mv = %d iavg_ma = %d\n",
+ new_uuc, chip->prev_pc_unusable,
+ new_unusable_mv, *iavg_ma);
+
+ return new_uuc;
+}
+
+static void calculate_iavg_ua(struct pm8921_bms_chip *chip, int cc_uah,
+ int *iavg_ua, int *delta_time_s)
+{
+ int delta_cc_uah;
+ struct rtc_time tm;
+ struct rtc_device *rtc;
+ unsigned long now_tm_sec = 0;
+ int rc = 0;
+
+ /* if anything fails report the previous iavg_ua */
+ *iavg_ua = chip->prev_iavg_ua;
+
+ rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
+ if (rtc == NULL) {
+ pr_err("%s: unable to open rtc device (%s)\n",
+ __FILE__, CONFIG_RTC_HCTOSYS_DEVICE);
+ goto out;
+ }
+
+ rc = rtc_read_time(rtc, &tm);
+ if (rc) {
+ pr_err("Error reading rtc device (%s) : %d\n",
+ CONFIG_RTC_HCTOSYS_DEVICE, rc);
+ goto out;
+ }
+
+ rc = rtc_valid_tm(&tm);
+ if (rc) {
+ pr_err("Invalid RTC time (%s): %d\n",
+ CONFIG_RTC_HCTOSYS_DEVICE, rc);
+ goto out;
+ }
+ rtc_tm_to_time(&tm, &now_tm_sec);
+
+ if (chip->tm_sec == 0) {
+ *delta_time_s = 0;
+ pm8921_bms_get_battery_current(iavg_ua);
+ goto out;
+ }
+
+ *delta_time_s = (now_tm_sec - chip->tm_sec);
+
+ /* use the previous iavg if called within 15 seconds */
+ if (*delta_time_s < 15) {
+ *iavg_ua = chip->prev_iavg_ua;
+ goto out;
+ }
+
+ delta_cc_uah = cc_uah - chip->last_cc_uah;
+
+ *iavg_ua = div_s64((s64)delta_cc_uah * 3600, *delta_time_s);
+
+ pr_debug("tm_sec = %ld, now_tm_sec = %ld delta_s = %d delta_cc = %d iavg_ua = %d\n",
+ chip->tm_sec, now_tm_sec,
+ *delta_time_s, delta_cc_uah, (int)*iavg_ua);
+
+out:
+ /* remember the iavg */
+ chip->prev_iavg_ua = *iavg_ua;
+
/* remember cc_uah */
chip->last_cc_uah = cc_uah;
/* remember this time */
- chip->t = now;
+ chip->tm_sec = now_tm_sec;
}
#define IAVG_SAMPLES 16
-#define CHARGING_IAVG_MA 300
+#define CHARGING_IAVG_MA 250
+#define MIN_SECONDS_FOR_VALID_SAMPLE 20
static int calculate_unusable_charge_uah(struct pm8921_bms_chip *chip,
int rbatt, int fcc_uah, int cc_uah,
int soc_rbatt, int batt_temp, int chargecycles,
- int iavg_ua, int delta_time_us)
+ int iavg_ua, int delta_time_s)
{
int uuc_uah_iavg;
int i;
@@ -1208,32 +1327,34 @@
static int iavg_samples[IAVG_SAMPLES];
static int iavg_index;
static int iavg_num_samples;
+ static int firsttime = 1;
+ int pc_unusable;
- if (delta_time_us == 0) {
- /*
- * this means uuc is being for the first time,
- * iavg_ua will be 0 which will lead to unreasonably low uuc
- * hence use the instantenous current instead of iavg_ua
- * value for the first time
- */
- pm8921_bms_get_battery_current(&iavg_ua);
- iavg_ma = iavg_ua / 1000;
+ /*
+ * if we are called first time fill all the
+ * samples with the the shutdown_iavg_ua
+ */
+ if (firsttime && chip->shutdown_iavg_ua != 0) {
+ pr_emerg("Using shutdown_iavg_ua = %d in all samples\n",
+ chip->shutdown_iavg_ua);
+ for (i = 0; i < IAVG_SAMPLES; i++)
+ iavg_samples[i] = chip->shutdown_iavg_ua;
+
+ iavg_index = 0;
+ iavg_num_samples = IAVG_SAMPLES;
}
- /* if the time since last sample is small ignore it */
- if (delta_time_us == 0 || delta_time_us > USEC_PER_SEC) {
- /*
- * if we are charging use a nominal avg current so that we keep
- * a reasonable UUC while charging
- */
- if (iavg_ma < 0)
- iavg_ma = CHARGING_IAVG_MA;
- iavg_samples[iavg_index] = iavg_ma;
- iavg_index = (iavg_index + 1) % IAVG_SAMPLES;
- iavg_num_samples++;
- if (iavg_num_samples >= IAVG_SAMPLES)
- iavg_num_samples = IAVG_SAMPLES;
- }
+ /*
+ * if we are charging use a nominal avg current so that we keep
+ * a reasonable UUC while charging
+ */
+ if (iavg_ma < 0)
+ iavg_ma = CHARGING_IAVG_MA;
+ iavg_samples[iavg_index] = iavg_ma;
+ iavg_index = (iavg_index + 1) % IAVG_SAMPLES;
+ iavg_num_samples++;
+ if (iavg_num_samples >= IAVG_SAMPLES)
+ iavg_num_samples = IAVG_SAMPLES;
/* now that this sample is added calcualte the average */
iavg_ma = 0;
@@ -1246,11 +1367,20 @@
iavg_ma = DIV_ROUND_CLOSEST(iavg_ma, iavg_num_samples);
}
- uuc_uah_iavg = calculate_uuc_uah_at_given_current(chip,
+ uuc_uah_iavg = calculate_termination_uuc(chip,
batt_temp, chargecycles,
- rbatt, fcc_uah, iavg_ma);
+ fcc_uah, iavg_ma,
+ &pc_unusable);
pr_debug("iavg = %d uuc_iavg = %d\n", iavg_ma, uuc_uah_iavg);
+ /* restrict the uuc such that it can increase only by one percent */
+ uuc_uah_iavg = adjust_uuc(chip, fcc_uah, pc_unusable, uuc_uah_iavg,
+ batt_temp, rbatt, &iavg_ma);
+
+ /* find out what the avg current should be for this uuc */
+ chip->prev_uuc_iavg_ma = iavg_ma;
+
+ firsttime = 0;
return uuc_uah_iavg;
}
@@ -1277,7 +1407,7 @@
int *cc_uah,
int *rbatt,
int *iavg_ua,
- int *delta_time_us)
+ int *delta_time_s)
{
int soc_rbatt;
@@ -1303,12 +1433,12 @@
soc_rbatt = 0;
*rbatt = get_rbatt(chip, soc_rbatt, batt_temp);
- calculate_iavg_ua(chip, *cc_uah, iavg_ua, delta_time_us);
+ calculate_iavg_ua(chip, *cc_uah, iavg_ua, delta_time_s);
*unusable_charge_uah = calculate_unusable_charge_uah(chip, *rbatt,
*fcc_uah, *cc_uah, soc_rbatt,
batt_temp, chargecycles, *iavg_ua,
- *delta_time_us);
+ *delta_time_s);
pr_debug("UUC = %uuAh\n", *unusable_charge_uah);
}
@@ -1323,7 +1453,7 @@
int real_fcc_uah;
int rbatt;
int iavg_ua;
- int delta_time_us;
+ int delta_time_s;
calculate_soc_params(chip, raw, batt_temp, chargecycles,
&fcc_uah,
@@ -1332,7 +1462,7 @@
&cc_uah,
&rbatt,
&iavg_ua,
- &delta_time_us);
+ &delta_time_s);
real_fcc_uah = remaining_charge_uah - cc_uah;
*ret_fcc_uah = fcc_uah;
@@ -1393,6 +1523,7 @@
int soc_new = 0;
int m = 0;
int rc = 0;
+ int delta_ocv_uv_limit = 0;
rc = pm8921_bms_get_simultaneous_battery_voltage_and_current(
&ibat_ua,
@@ -1405,6 +1536,9 @@
if (ibat_ua < 0)
goto out;
+
+ delta_ocv_uv_limit = DIV_ROUND_CLOSEST(ibat_ua, 1000);
+
ocv_est_uv = vbat_uv + (ibat_ua * rbatt)/1000;
pc_est = calculate_pc(chip, ocv_est_uv, batt_temp, last_chargecycles);
soc_est = div_s64((s64)fcc_uah * pc_est - uuc_uah*100,
@@ -1422,7 +1556,8 @@
* and cause a bad user experience
*/
if (soc_est == soc
- || (is_between(45, 25, soc_est) && is_between(50, 20, soc))
+ || (is_between(45, chip->adjust_soc_low_threshold, soc_est)
+ && is_between(50, chip->adjust_soc_low_threshold - 5, soc))
|| soc >= 90)
goto out;
@@ -1457,6 +1592,18 @@
delta_ocv_uv = div_s64((soc - soc_est) * (s64)m * 1000,
n * (pc - pc_new));
+
+ if (abs(delta_ocv_uv) > delta_ocv_uv_limit) {
+ pr_debug("limiting delta ocv %d limit = %d\n", delta_ocv_uv,
+ delta_ocv_uv_limit);
+
+ if (delta_ocv_uv > 0)
+ delta_ocv_uv = delta_ocv_uv_limit;
+ else
+ delta_ocv_uv = -1 * delta_ocv_uv_limit;
+ pr_debug("new delta ocv = %d\n", delta_ocv_uv);
+ }
+
chip->last_ocv_uv -= delta_ocv_uv;
if (chip->last_ocv_uv >= chip->max_voltage_uv)
@@ -1490,48 +1637,81 @@
}
#define IGNORE_SOC_TEMP_DECIDEG 50
-static void backup_soc(struct pm8921_bms_chip *chip, int batt_temp, int soc)
+#define IAVG_STEP_SIZE_MA 50
+#define IAVG_START 600
+#define SOC_ZERO 0xFF
+static void backup_soc_and_iavg(struct pm8921_bms_chip *chip, int batt_temp,
+ int soc)
{
+ u8 temp;
+ int iavg_ma = chip->prev_uuc_iavg_ma;
+
+ if (iavg_ma > IAVG_START)
+ temp = (iavg_ma - IAVG_START) / IAVG_STEP_SIZE_MA;
+ else
+ temp = 0;
+
+ pm_bms_masked_write(chip, TEMP_IAVG_STORAGE,
+ TEMP_IAVG_STORAGE_USE_MASK, temp);
+
+ /* since only 6 bits are available for SOC, we store half the soc */
if (soc == 0)
- soc = 0xFF;
+ temp = SOC_ZERO;
+ else
+ temp = soc;
- if (batt_temp < IGNORE_SOC_TEMP_DECIDEG)
- soc = 0;
-
- pm8xxx_writeb(the_chip->dev->parent, TEMP_SOC_STORAGE, soc);
+ /* don't store soc if temperature is below 5degC */
+ if (batt_temp > IGNORE_SOC_TEMP_DECIDEG)
+ pm8xxx_writeb(the_chip->dev->parent, TEMP_SOC_STORAGE, temp);
}
-static void read_shutdown_soc(struct pm8921_bms_chip *chip)
+static void read_shutdown_soc_and_iavg(struct pm8921_bms_chip *chip)
{
int rc;
u8 temp;
- rc = pm8xxx_readb(chip->dev->parent, TEMP_SOC_STORAGE, &temp);
- if (rc)
- pr_err("failed to read addr = %d %d\n", TEMP_SOC_STORAGE, rc);
- else
- chip->shutdown_soc = temp;
+ rc = pm8xxx_readb(chip->dev->parent, TEMP_IAVG_STORAGE, &temp);
+ if (rc) {
+ pr_err("failed to read addr = %d %d assuming %d\n",
+ TEMP_IAVG_STORAGE, rc, IAVG_START);
+ chip->shutdown_iavg_ua = IAVG_START;
+ } else {
+ temp &= TEMP_IAVG_STORAGE_USE_MASK;
- pr_debug("shutdown_soc = %d\n", chip->shutdown_soc);
-}
-
-void pm8921_bms_invalidate_shutdown_soc(void)
-{
- pr_debug("Invalidating shutdown soc - the battery was removed\n");
- mutex_lock(&soc_invalidation_mutex);
- shutdown_soc_invalid = 1;
- last_soc = -EINVAL;
- if (the_chip) {
- /* reset to pon ocv undoing what the adjusting did */
- if (the_chip->pon_ocv_uv) {
- the_chip->last_ocv_uv = the_chip->pon_ocv_uv;
- pr_debug("resetting ocv to pon_ocv = %d\n",
- the_chip->pon_ocv_uv);
+ if (temp == 0) {
+ chip->shutdown_iavg_ua = IAVG_START;
+ } else {
+ chip->shutdown_iavg_ua = IAVG_START
+ + IAVG_STEP_SIZE_MA * (temp + 1);
}
}
- mutex_unlock(&soc_invalidation_mutex);
+
+ rc = pm8xxx_readb(chip->dev->parent, TEMP_SOC_STORAGE, &temp);
+ if (rc) {
+ pr_err("failed to read addr = %d %d\n", TEMP_SOC_STORAGE, rc);
+ } else {
+ chip->shutdown_soc = temp;
+
+ if (chip->shutdown_soc == 0) {
+ pr_debug("No shutdown soc available\n");
+ shutdown_soc_invalid = 1;
+ chip->shutdown_iavg_ua = 0;
+ } else if (chip->shutdown_soc == SOC_ZERO) {
+ chip->shutdown_soc = 0;
+ }
+ }
+
+ if (chip->ignore_shutdown_soc) {
+ shutdown_soc_invalid = 1;
+ chip->shutdown_soc = 0;
+ chip->shutdown_iavg_ua = 0;
+ }
+
+ pr_debug("shutdown_soc = %d shutdown_iavg = %d shutdown_soc_invalid = %d\n",
+ chip->shutdown_soc,
+ chip->shutdown_iavg_ua,
+ shutdown_soc_invalid);
}
-EXPORT_SYMBOL(pm8921_bms_invalidate_shutdown_soc);
static void find_ocv_for_soc(struct pm8921_bms_chip *chip,
int batt_temp,
@@ -1575,82 +1755,32 @@
*rc_uah = (int)rc;
}
-static void adjust_rc_and_uuc_for_shutdown_soc(
+static void adjust_rc_and_uuc_for_specific_soc(
struct pm8921_bms_chip *chip,
int batt_temp,
int chargecycles,
+ int soc,
int fcc_uah,
int uuc_uah,
int cc_uah,
- int remaining_charge_uah,
+ int rc_uah,
int rbatt,
+ int *ret_ocv,
int *ret_rc,
int *ret_uuc,
int *ret_rbatt)
{
- int new_rbatt;
int ocv_uv;
- int shutdown_soc;
- int rc_uah;
- int soc_rbatt;
- int iavg_ua, iavg_ma;
- int num_tries = 0;
-
- mutex_lock(&soc_invalidation_mutex);
- shutdown_soc = chip->shutdown_soc;
- /*
- * value of zero means the shutdown soc should not be used, the battery
- * was removed for extended period, the coincell capacitor could have
- * drained
- * shutdown_soc_invalid means the shutdown soc should not be used,
- * the battery was removed for a small period
- */
- if (shutdown_soc == 0 || shutdown_soc_invalid) {
- rc_uah = remaining_charge_uah;
- goto out;
- }
-
- /* value of 0xFF means shutdown soc was 0% */
- if (shutdown_soc == 0xFF)
- shutdown_soc = 0;
-
- pm8921_bms_get_battery_current(&iavg_ua);
- iavg_ma = iavg_ua / 1000;
- if (iavg_ma < 0)
- iavg_ma = CHARGING_IAVG_MA;
-
-recalculate_ocv:
find_ocv_for_soc(chip, batt_temp, chargecycles,
fcc_uah, uuc_uah, cc_uah,
- shutdown_soc,
+ soc,
&rc_uah, &ocv_uv);
- soc_rbatt = div_s64((rc_uah - cc_uah) * 100, fcc_uah);
- new_rbatt = get_rbatt(chip, soc_rbatt, batt_temp);
- pr_debug("for s_soc = %d rc_uah = %d ocv_uv = %d, soc_rbatt = %d rbatt = %d\n",
- shutdown_soc, rc_uah, ocv_uv, soc_rbatt, new_rbatt);
- if (abs(new_rbatt - rbatt) > 20 && num_tries < 10) {
- rbatt = new_rbatt;
- uuc_uah = calculate_uuc_uah_at_given_current(chip,
- batt_temp, chargecycles,
- new_rbatt, fcc_uah, iavg_ma);
-
- pr_debug("rbatt not settled uuc = %d for rbatt = %d iavg_ma = %d num_tries = %d\n",
- uuc_uah, rbatt, iavg_ma, num_tries);
- num_tries++;
- goto recalculate_ocv;
- }
- pr_debug("DONE for s_soc = %d rc_uah = %d ocv_uv = %d, rbatt = %d\n",
- shutdown_soc, rc_uah, ocv_uv, new_rbatt);
-
- chip->pon_ocv_uv = chip->last_ocv_uv;
- chip->last_ocv_uv = ocv_uv;
-out:
+ *ret_ocv = ocv_uv;
*ret_rbatt = rbatt;
*ret_rc = rc_uah;
*ret_uuc = uuc_uah;
- mutex_unlock(&soc_invalidation_mutex);
}
#define SOC_CATCHUP_SEC_MAX 600
@@ -1714,20 +1844,15 @@
static bool is_shutdown_soc_within_limits(struct pm8921_bms_chip *chip, int soc)
{
- int shutdown_soc;
-
- if (chip->shutdown_soc == 0 || shutdown_soc_invalid) {
+ if (shutdown_soc_invalid) {
pr_debug("NOT forcing shutdown soc = %d\n", chip->shutdown_soc);
return 0;
}
- shutdown_soc = chip->shutdown_soc;
- if (shutdown_soc == 0xFF)
- shutdown_soc = 0;
-
- if (abs(shutdown_soc - soc) > chip->shutdown_soc_valid_limit) {
- pr_debug("rejecting shutdown soc = %d, soc = %d, limit = %d\n",
- shutdown_soc, soc, chip->shutdown_soc_valid_limit);
+ if (abs(chip->shutdown_soc - soc) > chip->shutdown_soc_valid_limit) {
+ pr_debug("rejecting shutdown soc = %d, soc = %d limit = %d\n",
+ chip->shutdown_soc, soc,
+ chip->shutdown_soc_valid_limit);
shutdown_soc_invalid = 1;
return 0;
}
@@ -1749,10 +1874,13 @@
int cc_uah;
int rbatt;
int iavg_ua;
- int delta_time_us;
+ int delta_time_s;
+ int new_ocv;
int new_rc_uah;
int new_ucc_uah;
int new_rbatt;
+ int shutdown_soc;
+ static int firsttime = 1;
calculate_soc_params(chip, raw, batt_temp, chargecycles,
&fcc_uah,
@@ -1761,7 +1889,7 @@
&cc_uah,
&rbatt,
&iavg_ua,
- &delta_time_us);
+ &delta_time_s);
/* calculate remaining usable charge */
remaining_usable_charge_uah = remaining_charge_uah
@@ -1778,9 +1906,39 @@
(fcc_uah - unusable_charge_uah));
}
+ if (firsttime && soc < 0) {
+ /*
+ * first time calcualtion and the pon ocv is too low resulting
+ * in a bad soc. Adjust ocv such that we get 0 soc
+ */
+ pr_debug("soc is %d, adjusting pon ocv to make it 0\n", soc);
+ adjust_rc_and_uuc_for_specific_soc(
+ chip,
+ batt_temp, chargecycles,
+ 0,
+ fcc_uah, unusable_charge_uah,
+ cc_uah, remaining_charge_uah,
+ rbatt,
+ &new_ocv,
+ &new_rc_uah, &new_ucc_uah,
+ &new_rbatt);
+ chip->last_ocv_uv = new_ocv;
+ remaining_charge_uah = new_rc_uah;
+ unusable_charge_uah = new_ucc_uah;
+ rbatt = new_rbatt;
+
+ remaining_usable_charge_uah = remaining_charge_uah
+ - cc_uah
+ - unusable_charge_uah;
+
+ soc = DIV_ROUND_CLOSEST((remaining_usable_charge_uah * 100),
+ (fcc_uah - unusable_charge_uah));
+ pr_debug("DONE for O soc is %d, pon ocv adjusted to %duV\n",
+ soc, chip->last_ocv_uv);
+ }
+
if (soc > 100)
soc = 100;
- pr_debug("before adjusting calculated SOC = %d%%\n", soc);
if (bms_fake_battery != -EINVAL) {
pr_debug("Returning Fake SOC = %d%%\n", bms_fake_battery);
@@ -1802,33 +1960,52 @@
soc = 0;
}
- if (delta_time_us == 0 && is_shutdown_soc_within_limits(chip, soc)) {
+ mutex_lock(&soc_invalidation_mutex);
+ shutdown_soc = chip->shutdown_soc;
+
+ if (firsttime && soc != shutdown_soc
+ && is_shutdown_soc_within_limits(chip, soc)) {
/*
* soc for the first time - use shutdown soc
* to adjust pon ocv since it is a small percent away from
* the real soc
*/
- adjust_rc_and_uuc_for_shutdown_soc(
+ pr_debug("soc = %d before forcing shutdown_soc = %d\n",
+ soc, shutdown_soc);
+ adjust_rc_and_uuc_for_specific_soc(
chip,
batt_temp, chargecycles,
+ shutdown_soc,
fcc_uah, unusable_charge_uah,
cc_uah, remaining_charge_uah,
rbatt,
+ &new_ocv,
&new_rc_uah, &new_ucc_uah,
&new_rbatt);
+ chip->pon_ocv_uv = chip->last_ocv_uv;
+ chip->last_ocv_uv = new_ocv;
remaining_charge_uah = new_rc_uah;
unusable_charge_uah = new_ucc_uah;
rbatt = new_rbatt;
+ remaining_usable_charge_uah = remaining_charge_uah
+ - cc_uah
+ - unusable_charge_uah;
+
soc = DIV_ROUND_CLOSEST((remaining_usable_charge_uah * 100),
(fcc_uah - unusable_charge_uah));
+
+ pr_debug("DONE for shutdown_soc = %d soc is %d, adjusted ocv to %duV\n",
+ shutdown_soc, soc, chip->last_ocv_uv);
}
+ mutex_unlock(&soc_invalidation_mutex);
calculated_soc = adjust_soc(chip, soc, batt_temp,
rbatt, fcc_uah, unusable_charge_uah, cc_uah);
pr_debug("calculated SOC = %d\n", calculated_soc);
+ firsttime = 0;
return calculated_soc;
}
@@ -1937,22 +2114,67 @@
* force shutdown soc if it is valid and the shutdown soc show
* timer has not expired
*/
- if (chip->shutdown_soc != 0xFF)
- soc = chip->shutdown_soc;
- else
- soc = 0;
+ soc = chip->shutdown_soc;
pr_debug("Forcing SHUTDOWN_SOC = %d\n", soc);
}
last_soc = soc;
- backup_soc(chip, batt_temp, last_soc);
+ backup_soc_and_iavg(chip, batt_temp, last_soc);
pr_debug("Reported SOC = %d\n", last_soc);
chip->t_soc_queried = now;
return last_soc;
}
+void pm8921_bms_invalidate_shutdown_soc(void)
+{
+ int calculate_soc = 0;
+ struct pm8921_bms_chip *chip = the_chip;
+ int batt_temp, rc;
+ struct pm8xxx_adc_chan_result result;
+ struct pm8921_soc_params raw;
+ int soc;
+
+ pr_debug("Invalidating shutdown soc - the battery was removed\n");
+ if (shutdown_soc_invalid)
+ return;
+
+ mutex_lock(&soc_invalidation_mutex);
+ shutdown_soc_invalid = 1;
+ last_soc = -EINVAL;
+ if (the_chip) {
+ /* reset to pon ocv undoing what the adjusting did */
+ if (the_chip->pon_ocv_uv) {
+ the_chip->last_ocv_uv = the_chip->pon_ocv_uv;
+ calculate_soc = 1;
+ pr_debug("resetting ocv to pon_ocv = %d\n",
+ the_chip->pon_ocv_uv);
+ }
+ }
+ mutex_unlock(&soc_invalidation_mutex);
+ if (!calculate_soc)
+ return;
+
+ rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
+ if (rc) {
+ pr_err("error reading adc channel = %d, rc = %d\n",
+ chip->batt_temp_channel, rc);
+ return;
+ }
+ pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
+ result.measurement);
+ batt_temp = (int)result.physical;
+
+ mutex_lock(&chip->last_ocv_uv_mutex);
+ read_soc_params_raw(chip, &raw);
+
+ soc = calculate_state_of_charge(chip, &raw,
+ batt_temp, last_chargecycles);
+ mutex_unlock(&chip->last_ocv_uv_mutex);
+}
+EXPORT_SYMBOL(pm8921_bms_invalidate_shutdown_soc);
+
#define MIN_DELTA_625_UV 1000
static void calib_hkadc(struct pm8921_bms_chip *chip)
{
@@ -2099,7 +2321,7 @@
int cc_uah;
int rbatt;
int iavg_ua;
- int delta_time_us;
+ int delta_time_s;
if (!the_chip) {
pr_err("called before initialization\n");
@@ -2127,7 +2349,7 @@
&cc_uah,
&rbatt,
&iavg_ua,
- &delta_time_us);
+ &delta_time_s);
mutex_unlock(&the_chip->last_ocv_uv_mutex);
return rbatt;
@@ -2244,7 +2466,6 @@
last_real_fcc_mah = new_fcc_uah/1000;
last_real_fcc_batt_temp = batt_temp;
readjust_fcc_table();
-
}
if (is_battery_full) {
@@ -2258,7 +2479,7 @@
* forget the old cc value
*/
the_chip->last_cc_uah = 0;
- pr_debug("EOC ocv_reading = 0x%x cc = 0x%x\n",
+ pr_debug("EOC BATT_FULL ocv_reading = 0x%x cc = 0x%x\n",
the_chip->ocv_reading_at_100,
the_chip->cc_reading_at_100);
}
@@ -2891,6 +3112,13 @@
chip->start_percent = -EINVAL;
chip->end_percent = -EINVAL;
chip->shutdown_soc_valid_limit = pdata->shutdown_soc_valid_limit;
+ chip->adjust_soc_low_threshold = pdata->adjust_soc_low_threshold;
+ if (chip->adjust_soc_low_threshold >= 45)
+ chip->adjust_soc_low_threshold = 45;
+
+ chip->prev_pc_unusable = -EINVAL;
+
+ chip->ignore_shutdown_soc = pdata->ignore_shutdown_soc;
rc = set_battery_data(chip);
if (rc) {
pr_err("%s bad battery data %d\n", __func__, rc);
@@ -2935,7 +3163,7 @@
goto free_irqs;
}
- read_shutdown_soc(chip);
+ read_shutdown_soc_and_iavg(chip);
platform_set_drvdata(pdev, chip);
the_chip = chip;
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 4e15e77..6330883 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -2808,6 +2808,8 @@
static int ichg_threshold_ua = -400000;
module_param(ichg_threshold_ua, int, 0644);
+
+#define PM8921_CHG_VDDMAX_RES_MV 10
static void adjust_vdd_max_for_fastchg(struct pm8921_chg_chip *chip)
{
int ichg_meas_ua, vbat_uv;
@@ -2867,9 +2869,11 @@
return;
}
+ adj_vdd_max_mv = DIV_ROUND_UP(adj_vdd_max_mv, PM8921_CHG_VDDMAX_RES_MV)
+ * PM8921_CHG_VDDMAX_RES_MV;
+
if (adj_vdd_max_mv > (chip->max_voltage_mv + vdd_max_increase_mv))
adj_vdd_max_mv = chip->max_voltage_mv + vdd_max_increase_mv;
-
pr_debug("adjusting vdd_max_mv to %d to make "
"vbat_batt_termial_uv = %d to %d\n",
adj_vdd_max_mv, vbat_batt_terminal_uv, chip->max_voltage_mv);
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index d17125a..d1438d1 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.h
@@ -131,6 +131,8 @@
unsigned int rconn_mohm;
int enable_fcc_learning;
int shutdown_soc_valid_limit;
+ int ignore_shutdown_soc;
+ int adjust_soc_low_threshold;
};
#if defined(CONFIG_PM8921_BMS) || defined(CONFIG_PM8921_BMS_MODULE)
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 3516022..f50b915 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -837,6 +837,21 @@
.ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
},
+ /* Hostless PCM purpose */
+ {
+ .name = "SLIMBUS_0 Hostless",
+ .stream_name = "SLIMBUS_0 Hostless",
+ .cpu_dai_name = "SLIMBUS0_HOSTLESS",
+ .platform_name = "msm-pcm-hostless",
+ .dynamic = 1,
+ .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, /* dai link has playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ },
{
.name = "MSM8974 Compr",
.stream_name = "COMPR",
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index 756cb18..2e58e1b 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -586,25 +586,23 @@
sizeof(lb_cmd) - APR_HDR_SIZE);
lb_cmd.hdr.src_port = 0;
lb_cmd.hdr.dest_port = 0;
- lb_cmd.hdr.token = 0;
+ lb_cmd.hdr.token = index;
lb_cmd.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
lb_cmd.param.port_id = tx_port;
- lb_cmd.param.payload_size = (sizeof(lb_cmd) -
- sizeof(struct apr_hdr) -
- sizeof(struct afe_port_cmd_set_param_v2));
+ lb_cmd.param.payload_size = (sizeof(lb_cmd) - sizeof(struct apr_hdr) -
+ sizeof(struct afe_port_cmd_set_param_v2));
lb_cmd.param.payload_address_lsw = 0x00;
lb_cmd.param.payload_address_msw = 0x00;
lb_cmd.param.mem_map_handle = 0x00;
lb_cmd.pdata.module_id = AFE_MODULE_LOOPBACK;
lb_cmd.pdata.param_id = AFE_PARAM_ID_LOOPBACK_CONFIG;
- lb_cmd.pdata.param_size = lb_cmd.param.payload_size -
- sizeof(struct afe_port_param_data_v2);
+ lb_cmd.pdata.param_size = lb_cmd.param.payload_size -
+ sizeof(struct afe_port_param_data_v2);
lb_cmd.dst_port_id = rx_port;
lb_cmd.routing_mode = LB_MODE_DEFAULT;
lb_cmd.enable = (enable ? 1 : 0);
- lb_cmd.loopback_cfg_minor_version =
- AFE_API_VERSION_LOOPBACK_CONFIG;
+ lb_cmd.loopback_cfg_minor_version = AFE_API_VERSION_LOOPBACK_CONFIG;
atomic_set(&this_afe.state, 1);
ret = apr_send_pkt(this_afe.apr, (uint32_t *) &lb_cmd);
@@ -613,9 +611,10 @@
ret = -EINVAL;
goto done;
}
+ pr_debug("%s: waiting for this_afe.wait[%d]\n", __func__, index);
ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
pr_err("%s: wait_event timeout\n", __func__);
ret = -EINVAL;
@@ -667,26 +666,24 @@
set_param.hdr.pkt_size = sizeof(set_param);
set_param.hdr.src_port = 0;
set_param.hdr.dest_port = 0;
- set_param.hdr.token = 0;
+ set_param.hdr.token = index;
set_param.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2;
- set_param.param.port_id = port_id;
- set_param.param.payload_size =
- (sizeof(struct afe_loopback_gain_per_path_param) -
- sizeof(struct apr_hdr) -
- sizeof(struct afe_port_cmd_set_param_v2));
+ set_param.param.port_id = port_id;
+ set_param.param.payload_size =
+ (sizeof(struct afe_loopback_gain_per_path_param) -
+ sizeof(struct apr_hdr) - sizeof(struct afe_port_cmd_set_param_v2));
set_param.param.payload_address_lsw = 0;
set_param.param.payload_address_msw = 0;
set_param.param.mem_map_handle = 0;
- set_param.pdata.module_id = AFE_MODULE_LOOPBACK;
- set_param.pdata.param_id = AFE_PARAM_ID_LOOPBACK_GAIN_PER_PATH;
- set_param.pdata.param_size = (set_param.param.payload_size -
- sizeof(struct afe_port_param_data_v2));
+ set_param.pdata.module_id = AFE_MODULE_LOOPBACK;
+ set_param.pdata.param_id = AFE_PARAM_ID_LOOPBACK_GAIN_PER_PATH;
+ set_param.pdata.param_size =
+ (set_param.param.payload_size -
+ sizeof(struct afe_port_param_data_v2));
set_param.rx_port_id = port_id;
- set_param.gain = volume;
-
- set_param.hdr.token = index;
+ set_param.gain = volume;
atomic_set(&this_afe.state, 1);
ret = apr_send_pkt(this_afe.apr, (uint32_t *) &set_param);
@@ -698,8 +695,8 @@
}
ret = wait_event_timeout(this_afe.wait[index],
- (atomic_read(&this_afe.state) == 0),
- msecs_to_jiffies(TIMEOUT_MS));
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
if (ret < 0) {
pr_err("%s: wait_event timeout\n", __func__);
ret = -EINVAL;