LTS: Merge android-4.14-stable (4.14.261) into android-msm-pixel-4.14
Merge android-4.14-stable common kernel (4.14.261) into C2F2/S5 master kernel.
Bug: 213962841
Test: Manual testing, SST, vts/vts-kernel, pts/base, pts/postsubmit-long
Signed-off-by: Lucas Wei <lucaswei@google.com>
Change-Id: I6164f22d3e4cc23d9a7b8d79c585c6cf458fdad1
diff --git a/arch/arm64/configs/floral_defconfig b/arch/arm64/configs/floral_defconfig
index ae47b44..d18a14a 100644
--- a/arch/arm64/configs/floral_defconfig
+++ b/arch/arm64/configs/floral_defconfig
@@ -493,6 +493,7 @@
CONFIG_HID_STEAM=y
CONFIG_HID_GREENASIA=y
CONFIG_GREENASIA_FF=y
+CONFIG_HID_WACOM=y
CONFIG_HID_WIIMOTE=y
CONFIG_USB_HIDDEV=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
@@ -531,8 +532,6 @@
CONFIG_TYPEC_TCPM=y
CONFIG_USB_PD_ENGINE=y
CONFIG_QPNP_USB_PDPHY=y
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
CONFIG_LEDS_QPNP_FLASH_V2=y
CONFIG_LEDS_TRIGGER_TIMER=y
CONFIG_LEDS_TRIGGER_TRANSIENT=y
diff --git a/arch/arm64/configs/sunfish_defconfig b/arch/arm64/configs/sunfish_defconfig
index 7d91361..06ed6b8 100644
--- a/arch/arm64/configs/sunfish_defconfig
+++ b/arch/arm64/configs/sunfish_defconfig
@@ -477,6 +477,7 @@
CONFIG_SONY_FF=y
CONFIG_HID_GREENASIA=y
CONFIG_GREENASIA_FF=y
+CONFIG_HID_WACOM=y
CONFIG_HID_WIIMOTE=y
CONFIG_USB_HIDDEV=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
@@ -521,8 +522,6 @@
CONFIG_TYPEC_TCPM=y
CONFIG_USB_PD_ENGINE=y
CONFIG_QPNP_USB_PDPHY=y
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
CONFIG_LEDS_QPNP_FLASH_V2=y
CONFIG_LEDS_QPNP_HAPTICS=y
CONFIG_LEDS_TRIGGER_TIMER=y
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index df601d4..a973454 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -1,4 +1,4 @@
-/* Copyright (c)2017-2020, The Linux Foundation. All rights reserved.
+/* Copyright (c)2017-2020,2021 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
@@ -388,6 +388,7 @@
{ 0x8D0, 0x23, 0 },
{ 0x980, 0x4, 0 },
{ 0xA630, 0x0, 1 },
+ { 0x1b400, 0x1fff, 1 },
};
/* IFPC & Preemption static powerup restore list */
diff --git a/drivers/media/platform/msm/ais/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/media/platform/msm/ais/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
index 1a99564..27fcef9 100644
--- a/drivers/media/platform/msm/ais/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
+++ b/drivers/media/platform/msm/ais/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019,2021 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
@@ -750,10 +750,12 @@
}
if ((packet->num_cmd_buf > 5) || !packet->num_patches ||
- !packet->num_io_configs) {
- CAM_ERR(CAM_JPEG, "wrong number of cmd/patch info: %u %u",
- packet->num_cmd_buf,
- packet->num_patches);
+ !packet->num_io_configs ||
+ (packet->num_io_configs > CAM_JPEG_IMAGE_MAX)) {
+ CAM_ERR(CAM_JPEG,
+ "wrong number of cmd/patch/io_configs info: %u %u %u",
+ packet->num_cmd_buf, packet->num_patches,
+ packet->num_io_configs);
return -EINVAL;
}
diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
index 1a99564..27fcef9 100644
--- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019,2021 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
@@ -750,10 +750,12 @@
}
if ((packet->num_cmd_buf > 5) || !packet->num_patches ||
- !packet->num_io_configs) {
- CAM_ERR(CAM_JPEG, "wrong number of cmd/patch info: %u %u",
- packet->num_cmd_buf,
- packet->num_patches);
+ !packet->num_io_configs ||
+ (packet->num_io_configs > CAM_JPEG_IMAGE_MAX)) {
+ CAM_ERR(CAM_JPEG,
+ "wrong number of cmd/patch/io_configs info: %u %u %u",
+ packet->num_cmd_buf, packet->num_patches,
+ packet->num_io_configs);
return -EINVAL;
}
diff --git a/drivers/media/platform/msm/camera_floral/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/media/platform/msm/camera_floral/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
index 9ea8e3f..ceaa1f6 100644
--- a/drivers/media/platform/msm/camera_floral/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
+++ b/drivers/media/platform/msm/camera_floral/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2019,2021 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
@@ -745,10 +745,12 @@
}
if ((packet->num_cmd_buf > 5) || !packet->num_patches ||
- !packet->num_io_configs) {
- CAM_ERR(CAM_JPEG, "wrong number of cmd/patch info: %u %u",
- packet->num_cmd_buf,
- packet->num_patches);
+ !packet->num_io_configs ||
+ (packet->num_io_configs > CAM_JPEG_IMAGE_MAX)) {
+ CAM_ERR(CAM_JPEG,
+ "wrong number of cmd/patch/io_configs info: %u %u %u",
+ packet->num_cmd_buf, packet->num_patches,
+ packet->num_io_configs);
return -EINVAL;
}
diff --git a/drivers/mfd/adnc/iaxxx-btp.c b/drivers/mfd/adnc/iaxxx-btp.c
index d331e42..f727cdf 100644
--- a/drivers/mfd/adnc/iaxxx-btp.c
+++ b/drivers/mfd/adnc/iaxxx-btp.c
@@ -150,6 +150,10 @@
* so calculate the offset and use it for first transaction
*/
addr_offset = phy_addr % IAXXX_MAC_WINDOW_SIZE;
+ if ((addr_offset >> 2) > btp_size) {
+ ret = -EINVAL;
+ goto exit;
+ }
while (words) {
/* Size of each transfer cannot exceed chunk size */
@@ -230,6 +234,10 @@
* so calculate the offset and use it for first transaction
*/
addr_offset = phy_addr % IAXXX_MAC_WINDOW_SIZE;
+ if ((addr_offset >> 2) > btp_size) {
+ ret = -EINVAL;
+ goto exit;
+ }
while (words) {
/* Size of each transfer cannot exceed chunk size */
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
index dc2e030..55281f0 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
@@ -3433,18 +3433,22 @@
list_for_each_entry(tbl, &set->head_rt_tbl_list, link) {
i = 0;
list_for_each_entry(entry, &tbl->head_rt_rule_list, link) {
- if (entry->proc_ctx) {
+ if (entry->proc_ctx && entry->proc_ctx->offset_entry) {
ofst = entry->proc_ctx->offset_entry->offset;
ofst_words =
(ofst +
ipa3_ctx->hdr_proc_ctx_tbl.start_offset)
>> 5;
- nbytes += scnprintf(msg_buff + nbytes,
- max_buff_len - nbytes,
- "tbl_idx:%d tbl_name:%s tbl_ref:%u\n",
- entry->tbl->idx, entry->tbl->name,
- entry->tbl->ref_cnt);
+ if (entry->tbl) {
+ nbytes += scnprintf(
+ msg_buff + nbytes,
+ max_buff_len - nbytes,
+ "tbl_idx:%d tbl_name:%s tbl_ref:%u\n",
+ entry->tbl->idx,
+ entry->tbl->name,
+ entry->tbl->ref_cnt);
+ }
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"rule_idx:%d dst:%d ep:%d S:%u\n",
@@ -3472,16 +3476,20 @@
entry->rule.hashable,
entry->rule.retain_hdr);
} else {
- if (entry->hdr)
+ if (entry->hdr && entry->hdr->offset_entry)
ofst = entry->hdr->offset_entry->offset;
else
ofst = 0;
- nbytes += scnprintf(msg_buff + nbytes,
- max_buff_len - nbytes,
- "tbl_idx:%d tbl_name:%s tbl_ref:%u\n",
- entry->tbl->idx, entry->tbl->name,
- entry->tbl->ref_cnt);
+ if (entry->tbl) {
+ nbytes += scnprintf(
+ msg_buff + nbytes,
+ max_buff_len - nbytes,
+ "tbl_idx:%d tbl_name:%s tbl_ref:%u\n",
+ entry->tbl->idx,
+ entry->tbl->name,
+ entry->tbl->ref_cnt);
+ }
nbytes += scnprintf(msg_buff + nbytes,
max_buff_len - nbytes,
"rule_idx:%d dst:%d ep:%d S:%u\n",
diff --git a/drivers/power/supply/google/google_battery.c b/drivers/power/supply/google/google_battery.c
index 62aba54..47ff65b 100644
--- a/drivers/power/supply/google/google_battery.c
+++ b/drivers/power/supply/google/google_battery.c
@@ -58,6 +58,11 @@
#define MSC_ERROR_UPDATE_INTERVAL 5000
#define MSC_DEFAULT_UPDATE_INTERVAL 30000
+
+/* AACR default slope is disabled by default */
+#define AACR_START_CYCLE_DEFAULT 100
+#define AACR_MAX_CYCLE_DEFAULT 0 /* disabled */
+
/* qual time is 0 minutes of charge or 0% increase in SOC */
#define DEFAULT_CHG_STATS_MIN_QUAL_TIME 0
#define DEFAULT_CHG_STATS_MIN_DELTA_SOC 0
@@ -75,10 +80,16 @@
#define HCC_WRITE_AGAIN 0xF0F0
#define HCC_DEFAULT_DELTA_CYCLE_CNT 25
-/* Interval value used when health is settings disabled when not running */
-#define CHG_DEADLINE_SETTING -1
-/* Internal value used when health is settings disabled while running */
-#define CHG_DEADLINE_SETTING_STOP -2
+enum batt_health_ui {
+ /* Internal value used when health is cleared via dialog */
+ CHG_DEADLINE_DIALOG = -3,
+ /* Internal value used when health is settings disabled while running */
+ CHG_DEADLINE_SETTING_STOP = -2,
+ /* Internal value used when health is settings disabled */
+ CHG_DEADLINE_SETTING = -1,
+ /* Internal value used when health is cleared via alarms/re-plug */
+ CHG_DEADLINE_CLEARED = 0,
+};
#undef MODULE_PARAM_PREFIX
#define MODULE_PARAM_PREFIX "androidboot."
@@ -230,6 +241,15 @@
u16 checksum; // 0x1A
};
+enum batt_aacr_state {
+ BATT_AACR_UNKNOWN = -3,
+ BATT_AACR_INVALID_CAP = -2,
+ BATT_AACR_UNDER_CYCLES = -1,
+ BATT_AACR_DISABLED = 0,
+ BATT_AACR_ENABLED = 1,
+ BATT_AACR_MAX,
+};
+
/* battery driver state */
struct batt_drv {
struct device *device;
@@ -288,7 +308,7 @@
struct batt_chg_health chg_health;
/* MSC charging */
- u32 battery_capacity;
+ u32 battery_capacity; /* in mAh */
struct gbms_chg_profile chg_profile;
union gbms_charger_state chg_state;
@@ -345,6 +365,11 @@
/* Battery pack info for Suez*/
char batt_pack_info[GBMS_MINF_LEN];
bool pack_info_ready;
+
+ /* AACR: Aged Adjusted Charging Rate */
+ enum batt_aacr_state aacr_state;
+ int aacr_cycle_grace;
+ int aacr_cycle_max;
};
static int batt_chg_tier_stats_cstr(char *buff, int size,
@@ -1134,8 +1159,7 @@
cev_stats_init(ce_data, &batt_drv->chg_profile);
batt_drv->ce_data.adapter_details.v = ad.v;
- vin = GPSY_GET_PROP(batt_drv->fg_psy,
- POWER_SUPPLY_PROP_VOLTAGE_NOW);
+ vin = GPSY_GET_PROP(batt_drv->fg_psy, POWER_SUPPLY_PROP_VOLTAGE_NOW);
ce_data->charging_stats.voltage_in = (vin < 0) ? -1 : vin / 1000;
ce_data->charging_stats.ssoc_in =
ssoc_get_capacity(&batt_drv->ssoc_state);
@@ -1421,6 +1445,8 @@
tier_idx = GBMS_STATS_AC_TI_DISABLE_SETTING;
else if (rest_deadline == CHG_DEADLINE_SETTING_STOP)
tier_idx = GBMS_STATS_AC_TI_DISABLE_SETTING_STOP;
+ else if (rest_deadline == CHG_DEADLINE_DIALOG)
+ tier_idx = GBMS_STATS_AC_TI_DISABLE_DIALOG;
else
tier_idx = GBMS_STATS_AC_TI_DISABLE_MISC;
break;
@@ -1586,7 +1612,7 @@
ce_data->adapter_details.ad_voltage * 100,
ce_data->adapter_details.ad_amperage * 100);
- logbuffer_log(log, "S: %hu,%hu, %hu,%hu %hu,%hu %ld,%ld",
+ logbuffer_log(log, "S: %hu,%hu, %hu,%hu %hu,%hu %ld,%ld, %u",
ce_data->charging_stats.ssoc_in,
ce_data->charging_stats.voltage_in,
ce_data->charging_stats.ssoc_out,
@@ -1594,7 +1620,8 @@
ce_data->charging_stats.cc_in,
ce_data->charging_stats.cc_out,
ce_data->first_update,
- ce_data->last_update);
+ ce_data->last_update,
+ ce_data->chg_profile->capacity_ma);
for (i = 0; i < GBMS_STATS_TIER_COUNT; i++) {
const int soc_next = batt_chg_stats_soc_next(ce_data, i);
@@ -1972,8 +1999,12 @@
chg_health->rest_cc_max = -1;
chg_health->rest_fv_uv = -1;
- /* keep negative deadlines (they mean USER disabled) */
- if (chg_health->rest_deadline < 0) {
+ /* Keep negative deadlines (they mean user has disabled via settings)
+ * NOTE: CHG_DEADLINE_DIALOG needs to be applied only for the current
+ * session. Therefore, it should be cleared on disconnect.
+ */
+ if (chg_health->rest_deadline < 0 &&
+ chg_health->rest_deadline != CHG_DEADLINE_DIALOG) {
chg_health->rest_state = CHG_HEALTH_USER_DISABLED;
} else {
chg_health->rest_state = CHG_HEALTH_INACTIVE;
@@ -1981,6 +2012,7 @@
}
chg_health->dry_run_deadline = 0;
+ chg_health->active_time = 0;
}
/* should not reset rl state */
@@ -2225,13 +2257,14 @@
#define HEALTH_PAUSE_DEBOUNCE 180
#define HEALTH_PAUSE_MAX_SSOC 95
+#define HEALTH_PAUSE_TIME 3
static bool msc_health_pause(struct batt_drv *batt_drv, const ktime_t ttf,
const ktime_t now,
const enum chg_health_state rest_state)
{
const struct gbms_charging_event *ce_data = &batt_drv->ce_data;
const struct gbms_ce_tier_stats *h = &ce_data->health_stats;
- const struct batt_chg_health *rest = &batt_drv->chg_health;
+ struct batt_chg_health *rest = &batt_drv->chg_health;
const ktime_t deadline = rest->rest_deadline;
const ktime_t safety_margin = (ktime_t)batt_drv->health_safety_margin;
/* Note: We only capture ACTIVE time in health stats */
@@ -2256,17 +2289,31 @@
return false;
/*
- * elap_h: running active for a while wait status and current stable
* ssoc: transfer in high soc impact charge full condition, disable
* pause behavior in high soc
*/
- if (elap_h < HEALTH_PAUSE_DEBOUNCE || ssoc > HEALTH_PAUSE_MAX_SSOC)
+ if (ssoc > HEALTH_PAUSE_MAX_SSOC)
+ return false;
+
+ /*
+ * elap_h: running active for a while wait status and current stable
+ * need to re-check before re-enter pause, so we need to minus previous
+ * health active time (rest->active_time) for next HEALTH_PAUSE_DEBOUNCE
+ */
+ if (elap_h - rest->active_time < HEALTH_PAUSE_DEBOUNCE)
+ return false;
+
+ /* prevent enter <---> leave PAUSE too many times */
+ if (rest->active_time > (HEALTH_PAUSE_TIME * HEALTH_PAUSE_DEBOUNCE))
return false;
/* check if time meets the PAUSE condition or not */
if (ttf > 0 && deadline > now + ttf + safety_margin)
return true;
+ /* record time for next pause check */
+ rest->active_time = elap_h;
+
return false;
}
@@ -2290,7 +2337,12 @@
new_deadline = chg_health->rest_deadline != deadline_s;
chg_health->rest_state = CHG_HEALTH_USER_DISABLED;
- if (chg_health->rest_deadline > 0) /* was active */
+ /* disabled with notification; assumes that the dialog exists
+ * only if there is a >0 deadline.
+ */
+ if (deadline_s == CHG_DEADLINE_DIALOG)
+ chg_health->rest_deadline = CHG_DEADLINE_DIALOG;
+ else if (chg_health->rest_deadline > 0) /* was active */
chg_health->rest_deadline = CHG_DEADLINE_SETTING_STOP;
else
chg_health->rest_deadline = CHG_DEADLINE_SETTING;
@@ -2304,8 +2356,7 @@
if (chg_health->rest_state != CHG_HEALTH_DONE)
chg_health->rest_state = CHG_HEALTH_USER_DISABLED;
- /* enabled from any previous state */
- } else {
+ } else { /* enabled from any previous state */
const time_t rest_deadline = get_boot_sec() + deadline_s;
/* ->always_on SOC overrides the deadline */
@@ -2452,13 +2503,17 @@
if (!changed)
return false;
- pr_info("MSC_HEALTH: now=%d deadline=%d aon_soc=%d ttf=%ld state=%d->%d fv_uv=%d, cc_max=%d\n",
+ pr_info("MSC_HEALTH: now=%d deadline=%d aon_soc=%d ttf=%ld state=%d->%d fv_uv=%d, cc_max=%d"
+ " safety_margin=%d active_time:%d\n",
now, rest->rest_deadline, rest->always_on_soc,
- ttf, rest->rest_state, rest_state, fv_uv, cc_max);
+ ttf, rest->rest_state, rest_state, fv_uv, cc_max,
+ batt_drv->health_safety_margin, rest->active_time);
logbuffer_log(batt_drv->ttf_stats.ttf_log,
- "MSC_HEALTH: now=%d deadline=%d aon_soc=%d ttf=%ld state=%d->%d fv_uv=%d, cc_max=%d\n",
+ "MSC_HEALTH: now=%d deadline=%d aon_soc=%d ttf=%ld state=%d->%d fv_uv=%d, cc_max=%d"
+ " safety_margin=%d active_time:%d\n",
now, rest->rest_deadline, rest->always_on_soc,
- ttf, rest->rest_state, rest_state, fv_uv, cc_max);
+ ttf, rest->rest_state, rest_state, fv_uv, cc_max,
+ batt_drv->health_safety_margin, rest->active_time);
rest->rest_state = rest_state;
memcpy(&batt_drv->ce_data.ce_health, &batt_drv->chg_health,
@@ -2517,6 +2572,101 @@
return cc_max;
}
+/* same as design when under the grace period */
+static u32 aacr_get_reference_capacity(const struct batt_drv *batt_drv,
+ int cycle_count)
+{
+ const int design_capacity = batt_drv->battery_capacity;
+ const int aacr_cycle_grace = batt_drv->aacr_cycle_grace;
+ const int aacr_cycle_max = batt_drv->aacr_cycle_max;
+ int fade10;
+
+ fade10 = gbms_aacr_fade10(&batt_drv->chg_profile, cycle_count);
+ if (fade10 >= 0) {
+ /* use interpolation between known points */
+ } else if (aacr_cycle_max && (cycle_count > aacr_cycle_grace)) {
+ /* or use slope from ->aacr_cycle_grace for 20% @
+ * ->aacr_cycle_max
+ */
+ fade10 = (200 * (cycle_count - aacr_cycle_grace)) /
+ (aacr_cycle_max - aacr_cycle_grace);
+
+ pr_debug("%s: aacr_cycle_max=%d, cycle_count=%d fade10=%d\n",
+ __func__, aacr_cycle_max, cycle_count, fade10);
+ } else {
+ fade10 = 0;
+ }
+
+ return design_capacity - (design_capacity * fade10 / 1000);
+}
+
+/* 80% of design_capacity min, design_capacity in grace, aacr or negative */
+static int aacr_get_capacity_at_cycle(const struct batt_drv *batt_drv,
+ int cycle_count)
+{
+ const int design_capacity = batt_drv->battery_capacity; /* mAh */
+ const int min_capacity = (batt_drv->battery_capacity * 80) / 100;
+ int reference_capacity, full_cap_nom, full_capacity;
+ struct power_supply *fg_psy = batt_drv->fg_psy;
+ int aacr_capacity;
+
+ /* batt_drv->cycle_count might be negative */
+ if (cycle_count <= batt_drv->aacr_cycle_grace)
+ return design_capacity;
+
+ /* peg at 80% of design when over limit (if set) */
+ if (batt_drv->aacr_cycle_max &&
+ (cycle_count >= batt_drv->aacr_cycle_max))
+ return min_capacity;
+
+ reference_capacity = aacr_get_reference_capacity(batt_drv, cycle_count);
+ if (reference_capacity <= 0)
+ return design_capacity;
+
+ /* full_cap_nom in uAh, need to scale to mAh */
+ full_cap_nom = GPSY_GET_PROP(fg_psy, POWER_SUPPLY_PROP_CHARGE_FULL);
+ if (full_cap_nom < 0)
+ return full_cap_nom;
+
+ full_capacity = min(min(full_cap_nom / 1000, design_capacity),
+ reference_capacity);
+ aacr_capacity = max(full_capacity, min_capacity);
+ aacr_capacity = (aacr_capacity / 50) * 50; /* 50mAh, ~1% capacity */
+
+ pr_debug("%s: design=%d reference=%d full_cap_nom=%d, full=%d aacr=%d\n",
+ __func__, design_capacity, reference_capacity, full_cap_nom,
+ full_capacity, aacr_capacity);
+
+ return aacr_capacity;
+}
+
+/* design_capacity when not enabled, never a negative value */
+static u32 aacr_get_capacity(struct batt_drv *batt_drv)
+{
+ int capacity = batt_drv->battery_capacity;
+
+ if (batt_drv->aacr_state == BATT_AACR_DISABLED)
+ goto exit_done;
+
+ if (batt_drv->cycle_count <= batt_drv->aacr_cycle_grace) {
+ batt_drv->aacr_state = BATT_AACR_UNDER_CYCLES;
+ } else {
+ int aacr_capacity;
+
+ aacr_capacity = aacr_get_capacity_at_cycle(batt_drv,
+ batt_drv->cycle_count);
+ if (aacr_capacity < 0) {
+ batt_drv->aacr_state = BATT_AACR_INVALID_CAP;
+ } else {
+ batt_drv->aacr_state = BATT_AACR_ENABLED;
+ capacity = aacr_capacity;
+ }
+ }
+
+exit_done:
+ return (u32)capacity;
+}
+
/* TODO: factor msc_logic_irdop from the logic about tier switch */
static int msc_logic(struct batt_drv *batt_drv)
{
@@ -2568,7 +2718,9 @@
msc_state = MSC_SEED;
- /* seed voltage only on connect, book 0 time */
+ /* seed voltage and charging table only on connect,
+ * book 0 time
+ */
if (batt_drv->vbatt_idx == -1)
vbatt_idx = gbms_msc_voltage_idx(profile, vbatt);
@@ -2783,6 +2935,18 @@
ce_data->bd_clear_trickle = true;
}
+static void google_battery_dump_profile(const struct gbms_chg_profile *profile)
+{
+ char *buff;
+
+ buff = kzalloc(GBMS_CHG_ALG_BUF, GFP_KERNEL);
+ if (buff) {
+ gbms_dump_chg_profile(buff, GBMS_CHG_ALG_BUF, profile);
+ pr_info("%s", buff);
+ kfree(buff);
+ }
+}
+
/* called holding chg_lock */
static int batt_chg_logic(struct batt_drv *batt_drv)
{
@@ -2841,7 +3005,9 @@
/* here when connected to power supply */
if (batt_drv->ssoc_state.buck_enabled <= 0) {
+ struct device_node *node = batt_drv->device->of_node;
const qnum_t ssoc_delta = ssoc_get_delta(batt_drv);
+ u32 capacity;
/*
* FIX: BatteryDefenderUI needs use a different curve because
@@ -2856,6 +3022,13 @@
if (batt_drv->res_state.estimate_filter)
batt_res_state_set(&batt_drv->res_state, true);
+ capacity = aacr_get_capacity(batt_drv);
+ if (capacity != batt_drv->chg_profile.capacity_ma) {
+ gbms_init_chg_table(&batt_drv->chg_profile, node,
+ capacity);
+ google_battery_dump_profile(&batt_drv->chg_profile);
+ }
+
batt_chg_stats_start(batt_drv);
err = GPSY_SET_PROP(batt_drv->fg_psy,
POWER_SUPPLY_PROP_BATT_CE_CTRL,
@@ -3010,8 +3183,8 @@
/* charge profile not in battery */
static int batt_init_chg_profile(struct batt_drv *batt_drv)
{
- struct device_node *node = batt_drv->device->of_node;
struct gbms_chg_profile *profile = &batt_drv->chg_profile;
+ struct device_node *node = batt_drv->device->of_node;
int ret = 0;
/* handle retry */
@@ -3021,6 +3194,7 @@
return -EINVAL;
}
+ /* this is in mAh */
ret = of_property_read_u32(node, "google,chg-battery-capacity",
&batt_drv->battery_capacity);
if (ret < 0)
@@ -3036,7 +3210,7 @@
if (batt_drv->batt_present) {
fc = GPSY_GET_PROP(fg_psy,
- POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN);
+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN);
if (fc == -EAGAIN)
return -EPROBE_DEFER;
if (fc > 0) {
@@ -3056,12 +3230,17 @@
if (ret < 0)
pr_warn("battery not present, no default capacity, zero charge table\n");
else
- pr_warn("battery not present, using default capacity:\n");
+ pr_warn("battery not present, using default capacity\n");
}
}
+ /* aacr tables enable AACR by default UNLESS explicitly disabled */
+ ret = of_property_read_bool(node, "google,aacr-disable");
+ if (!ret && profile->aacr_nb_limits)
+ batt_drv->aacr_state = BATT_AACR_ENABLED;
+
/* NOTE: with NG charger tolerance is applied from "charger" */
- gbms_init_chg_table(&batt_drv->chg_profile, batt_drv->battery_capacity);
+ gbms_init_chg_table(profile, node, aacr_get_capacity(batt_drv));
return 0;
}
@@ -3481,6 +3660,77 @@
debug_chg_health_set_stage, "%u\n");
#endif
+/* debug variable */
+static int raw_profile_cycles;
+
+static ssize_t debug_get_chg_raw_profile(struct file *filp,
+ char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct batt_drv *batt_drv = (struct batt_drv *)filp->private_data;
+ char *tmp;
+ int len;
+
+ tmp = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!tmp)
+ return -ENOMEM;
+
+ if (raw_profile_cycles) {
+ struct gbms_chg_profile profile;
+ int count;
+
+ len = gbms_init_chg_profile(&profile,
+ batt_drv->device->of_node);
+ if (len < 0)
+ goto exit_done;
+
+ /* len is the capacity */
+ len = aacr_get_capacity_at_cycle(batt_drv, raw_profile_cycles);
+ if (len <= 0) {
+ gbms_free_chg_profile(&profile);
+ goto exit_done;
+ }
+
+ count = scnprintf(tmp, PAGE_SIZE, "AACR Profile at %d cycles\n",
+ raw_profile_cycles);
+ gbms_init_chg_table(&profile, batt_drv->device->of_node, len);
+ gbms_dump_chg_profile(&tmp[count], PAGE_SIZE - count, &profile);
+ gbms_free_chg_profile(&profile);
+ } else {
+ gbms_dump_chg_profile(tmp, PAGE_SIZE, &batt_drv->chg_profile);
+ }
+
+ len = simple_read_from_buffer(buf, count, ppos, tmp, strlen(tmp));
+
+exit_done:
+ kfree(tmp);
+ return len;
+}
+
+static ssize_t debug_set_chg_raw_profile(struct file *filp,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ int ret = 0, val;
+ char buf[8];
+
+ ret = simple_write_to_buffer(buf, sizeof(buf), ppos, user_buf, count);
+ if (!ret)
+ return -EFAULT;
+
+ buf[ret] = '\0';
+ ret = kstrtoint(buf, 0, &val);
+ if (ret < 0)
+ return ret;
+
+ raw_profile_cycles = val;
+ return count;
+}
+
+BATTERY_DEBUG_ATTRIBUTE(debug_chg_raw_profile_fops,
+ debug_get_chg_raw_profile,
+ debug_set_chg_raw_profile);
+
/* ------------------------------------------------------------------------- */
static ssize_t charge_stats_actual_store(struct device *dev,
struct device_attribute *attr,
@@ -4250,6 +4500,93 @@
static DEVICE_ATTR_RW(health_safety_margin);
+static ssize_t aacr_state_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct power_supply *psy = container_of(dev, struct power_supply, dev);
+ struct batt_drv *batt_drv = power_supply_get_drvdata(psy);
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", batt_drv->aacr_state);
+}
+
+static ssize_t aacr_state_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct power_supply *psy = container_of(dev, struct power_supply, dev);
+ struct batt_drv *batt_drv = power_supply_get_drvdata(psy);
+ int state, ret = 0;
+
+ ret = kstrtoint(buf, 0, &state);
+ if (ret < 0)
+ return ret;
+
+ if ((state != BATT_AACR_DISABLED) && (state != BATT_AACR_ENABLED))
+ return -ERANGE;
+
+ if (batt_drv->aacr_state == state)
+ return count;
+
+ batt_drv->aacr_state = state;
+ return count;
+}
+
+static DEVICE_ATTR_RW(aacr_state);
+
+static ssize_t aacr_cycle_grace_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct power_supply *psy = container_of(dev, struct power_supply, dev);
+ struct batt_drv *batt_drv = power_supply_get_drvdata(psy);
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", batt_drv->aacr_cycle_grace);
+}
+
+static ssize_t aacr_cycle_grace_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct power_supply *psy = container_of(dev, struct power_supply, dev);
+ struct batt_drv *batt_drv = power_supply_get_drvdata(psy);
+ int value, ret = 0;
+
+ ret = kstrtoint(buf, 0, &value);
+ if (ret < 0)
+ return ret;
+
+ batt_drv->aacr_cycle_grace = value;
+ return count;
+}
+
+static DEVICE_ATTR_RW(aacr_cycle_grace);
+
+static ssize_t aacr_cycle_max_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct power_supply *psy = container_of(dev, struct power_supply, dev);
+ struct batt_drv *batt_drv = power_supply_get_drvdata(psy);
+
+ return scnprintf(buf, PAGE_SIZE, "%d\n", batt_drv->aacr_cycle_max);
+}
+
+static ssize_t aacr_cycle_max_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct power_supply *psy = container_of(dev, struct power_supply, dev);
+ struct batt_drv *batt_drv = power_supply_get_drvdata(psy);
+ int value, ret = 0;
+
+ ret = kstrtoint(buf, 0, &value);
+ if (ret < 0)
+ return ret;
+
+ batt_drv->aacr_cycle_max = value;
+ return count;
+}
+
+static DEVICE_ATTR_RW(aacr_cycle_max);
+
static struct attribute *batt_attrs[] = {
&dev_attr_charge_stats.attr,
&dev_attr_charge_stats_actual.attr,
@@ -4270,6 +4607,9 @@
&dev_attr_bd_trickle_reset_sec.attr,
&dev_attr_bd_clear.attr,
&dev_attr_health_safety_margin.attr,
+ &dev_attr_aacr_state.attr,
+ &dev_attr_aacr_cycle_grace.attr,
+ &dev_attr_aacr_cycle_max.attr,
NULL,
};
@@ -4322,6 +4662,10 @@
batt_drv, &debug_chg_health_rest_rate_fops);
debugfs_create_file("chg_health_stage", 0600, de,
batt_drv, &debug_chg_health_stage_fops);
+
+ /* charging table */
+ debugfs_create_file("chg_raw_profile", 0644, de,
+ batt_drv, &debug_chg_raw_profile_fops);
}
#endif
@@ -5477,6 +5821,7 @@
dump_ssoc_state(&batt_drv->ssoc_state, batt_drv->ssoc_log);
+ /* chg_profile will use cycle_count when aacr is enabled */
ret = batt_init_chg_profile(batt_drv);
if (ret == -EPROBE_DEFER)
goto retry_init_work;
@@ -5484,7 +5829,7 @@
if (ret < 0) {
pr_err("charging profile disabled, ret=%d\n", ret);
} else if (batt_drv->battery_capacity) {
- gbms_dump_chg_profile(&batt_drv->chg_profile);
+ google_battery_dump_profile(&batt_drv->chg_profile);
}
cev_stats_init(&batt_drv->ce_data, &batt_drv->chg_profile);
@@ -5727,6 +6072,12 @@
} else {
thermal_zone_device_update(batt_drv->tz_dev, THERMAL_DEVICE_UP);
}
+
+ /* AACR server side */
+ batt_drv->aacr_cycle_grace = AACR_START_CYCLE_DEFAULT;
+ batt_drv->aacr_cycle_max = AACR_MAX_CYCLE_DEFAULT;
+ batt_drv->aacr_state = BATT_AACR_DISABLED;
+
/* give time to fg driver to start */
schedule_delayed_work(&batt_drv->init_work,
msecs_to_jiffies(BATT_DELAY_INIT_MS));
diff --git a/drivers/power/supply/google/google_bms.c b/drivers/power/supply/google/google_bms.c
index 57de959..4e6fdfc 100644
--- a/drivers/power/supply/google/google_bms.c
+++ b/drivers/power/supply/google/google_bms.c
@@ -82,14 +82,23 @@
* NOTE: the call covert C rates to chanrge currents IN PLACE, ie you cannot
* call this twice.
*/
-void gbms_init_chg_table(struct gbms_chg_profile *profile, u32 capacity_ma)
+void gbms_init_chg_table(struct gbms_chg_profile *profile,
+ struct device_node *node, u32 capacity_ma)
{
u32 ccm;
- int vi, ti;
+ int vi, ti, ret;
const int fv_uv_step = profile->fv_uv_resolution;
+ u32 cccm_array_size = (profile->temp_nb_limits - 1)
+ * profile->volt_nb_limits;
profile->capacity_ma = capacity_ma;
+ ret = of_property_read_u32_array(node, "google,chg-cc-limits",
+ (u32 *)profile->cccm_limits,
+ cccm_array_size);
+ if (ret < 0)
+ pr_warn("unable to get default cccm_limits.\n");
+
/* chg-battery-capacity is in mAh, chg-cc-limits relative to 100 */
for (ti = 0; ti < profile->temp_nb_limits - 1; ti++) {
for (vi = 0; vi < profile->volt_nb_limits; vi++) {
@@ -159,6 +168,85 @@
return 0;
}
+static int gbms_read_aacr_limits(struct gbms_chg_profile *profile,
+ struct device_node *node)
+{
+ int ret = 0, cycle_nb_limits = 0, fade10_nb_limits = 0;
+
+ ret = of_property_count_elems_of_size(node,
+ "google,aacr-ref-cycles",
+ sizeof(u32));
+ if (ret < 0)
+ goto no_data;
+
+ cycle_nb_limits = ret;
+
+ ret = of_property_count_elems_of_size(node,
+ "google,aacr-ref-fade10",
+ sizeof(u32));
+ if (ret < 0)
+ goto no_data;
+
+ fade10_nb_limits = ret;
+
+ if (cycle_nb_limits != fade10_nb_limits ||
+ cycle_nb_limits > GBMS_AACR_DATA_MAX ||
+ cycle_nb_limits == 0) {
+ gbms_warn(profile,
+ "aacr not enable, cycle_nb:%d, fade10_nb:%d, max:%d",
+ cycle_nb_limits, fade10_nb_limits,
+ GBMS_AACR_DATA_MAX);
+ profile->aacr_nb_limits = 0;
+ return -ERANGE;
+ }
+
+ ret = of_property_read_u32_array(node, "google,aacr-ref-cycles",
+ (u32 *)profile->reference_cycles,
+ cycle_nb_limits);
+ if (ret < 0)
+ return ret;
+
+ ret = of_property_read_u32_array(node, "google,aacr-ref-fade10",
+ (u32 *)profile->reference_fade10,
+ fade10_nb_limits);
+ if (ret < 0)
+ return ret;
+
+ profile->aacr_nb_limits = cycle_nb_limits;
+
+ return 0;
+
+no_data:
+ profile->aacr_nb_limits = 0;
+ return ret;
+}
+
+/* return pct amount of capacity fade at cycles or negative if not enabled */
+int gbms_aacr_fade10(const struct gbms_chg_profile *profile, int cycles)
+{
+ int cycle_s = 0, fade_s = 0;
+ int idx, cycle_f, fade_f;
+
+ if (profile->aacr_nb_limits == 0 || cycles < 0)
+ return -EINVAL;
+
+ for (idx = 0; idx < profile->aacr_nb_limits; idx++)
+ if (cycles < profile->reference_cycles[idx])
+ break;
+
+ /* Interpolation */
+ cycle_f = profile->reference_cycles[idx];
+ fade_f = profile->reference_fade10[idx];
+ if (idx > 0) {
+ cycle_s = profile->reference_cycles[idx - 1];
+ fade_s = profile->reference_fade10[idx - 1];
+ }
+
+ return (cycles - cycle_s) * (fade_f - fade_s) / (cycle_f - cycle_s)
+ + fade_s;
+}
+EXPORT_SYMBOL_GPL(gbms_aacr_fade10);
+
int gbms_init_chg_profile_internal(struct gbms_chg_profile *profile,
struct device_node *node,
const char *owner_name)
@@ -172,6 +260,11 @@
if (ret < 0)
return ret;
+ /* TODO: dump the AACR table if supported */
+ ret = gbms_read_aacr_limits(profile, node);
+ if (ret == 0)
+ gbms_info(profile, "AACR: supported\n");
+
cccm_array_size = (profile->temp_nb_limits - 1)
* profile->volt_nb_limits;
mem_size = sizeof(s32) * cccm_array_size;
@@ -276,23 +369,22 @@
}
/* NOTE: I should really pass the scale */
-void gbms_dump_raw_profile(const struct gbms_chg_profile *profile, int scale)
+void gbms_dump_raw_profile(char *buff, size_t len,
+ const struct gbms_chg_profile *profile, int scale)
{
const int tscale = (scale == 1) ? 1 : 10;
- /* with scale == 1 voltage takes 7 bytes, add 7 bytes of temperature */
- char buff[GBMS_CHG_VOLT_NB_LIMITS_MAX * 9 + 7];
- int ti, vi, count, len = sizeof(buff);
+ int ti, vi, count = 0;
- gbms_info(profile, "Profile constant charge limits:\n");
- count = 0;
+ count += scnprintf(buff + count, len - count,
+ "Profile constant charge limits:\n");
+ count += scnprintf(buff + count, len - count, "|T \\ V");
for (vi = 0; vi < profile->volt_nb_limits; vi++) {
count += scnprintf(buff + count, len - count, " %4d",
profile->volt_limits[vi] / scale);
}
- gbms_info(profile, "|T \\ V%s\n", buff);
+ count += scnprintf(buff + count, len - count, "\n");
for (ti = 0; ti < profile->temp_nb_limits - 1; ti++) {
- count = 0;
count += scnprintf(buff + count, len - count, "|%2d:%2d",
profile->temp_limits[ti] / tscale,
profile->temp_limits[ti + 1] / tscale);
@@ -301,7 +393,7 @@
GBMS_CCCM_LIMITS(profile, ti, vi)
/ scale);
}
- gbms_info(profile, "%s\n", buff);
+ count += scnprintf(buff + count, len - count, "\n");
}
}
diff --git a/drivers/power/supply/google/google_bms.h b/drivers/power/supply/google/google_bms.h
index 0551395..477641f 100644
--- a/drivers/power/supply/google/google_bms.h
+++ b/drivers/power/supply/google/google_bms.h
@@ -17,6 +17,7 @@
#ifndef __GOOGLE_BMS_H_
#define __GOOGLE_BMS_H_
+#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/power_supply.h>
#include "qmath.h"
@@ -26,6 +27,8 @@
#define GBMS_CHG_TEMP_NB_LIMITS_MAX 10
#define GBMS_CHG_VOLT_NB_LIMITS_MAX 6
+#define GBMS_CHG_ALG_BUF 500
+#define GBMS_AACR_DATA_MAX 10
struct gbms_chg_profile {
const char *owner_name;
@@ -53,6 +56,11 @@
u32 fv_uv_resolution;
/* experimental */
u32 cv_otv_margin;
+
+ /* AACR feature */
+ u32 reference_cycles[GBMS_AACR_DATA_MAX];
+ u32 reference_fade10[GBMS_AACR_DATA_MAX];
+ u32 aacr_nb_limits;
};
#define WLC_BPP_THRESHOLD_UV 700000
@@ -241,6 +249,7 @@
/* tier index used to log the session */
enum gbms_stats_tier_idx_t {
+ GBMS_STATS_AC_TI_DISABLE_DIALOG = -6,
GBMS_STATS_AC_TI_DEFENDER = -5,
GBMS_STATS_AC_TI_DISABLE_SETTING_STOP = -4,
GBMS_STATS_AC_TI_DISABLE_MISC = -3,
@@ -284,6 +293,7 @@
enum chg_health_state rest_state;
int rest_cc_max;
int rest_fv_uv;
+ ktime_t active_time;
};
#define CHG_HEALTH_REST_IS_ACTIVE(rest) \
@@ -358,12 +368,15 @@
#define gbms_init_chg_profile(p, n) \
gbms_init_chg_profile_internal(p, n, KBUILD_MODNAME)
-void gbms_init_chg_table(struct gbms_chg_profile *profile, u32 capacity);
+void gbms_init_chg_table(struct gbms_chg_profile *profile,
+ struct device_node *node, u32 capacity);
void gbms_free_chg_profile(struct gbms_chg_profile *profile);
-void gbms_dump_raw_profile(const struct gbms_chg_profile *profile, int scale);
-#define gbms_dump_chg_profile(profile) gbms_dump_raw_profile(profile, 1000)
+void gbms_dump_raw_profile(char *buff, size_t len,
+ const struct gbms_chg_profile *profile, int scale);
+#define gbms_dump_chg_profile(buff, len, profile) \
+ gbms_dump_raw_profile(buff, len, profile, 1000)
/* newgen charging: charge profile */
int gbms_msc_temp_idx(const struct gbms_chg_profile *profile, int temp);
@@ -378,6 +391,9 @@
struct power_supply *chg_psy,
struct power_supply *wlc_psy);
+/* calculate aacr reference capacity */
+int gbms_aacr_fade10(const struct gbms_chg_profile *profile, int cycles);
+
/* debug/print */
const char *gbms_chg_type_s(int chg_type);
const char *gbms_chg_status_s(int chg_status);
diff --git a/drivers/power/supply/google/sm7150_bms.c b/drivers/power/supply/google/sm7150_bms.c
index 909a657..aecf04d 100644
--- a/drivers/power/supply/google/sm7150_bms.c
+++ b/drivers/power/supply/google/sm7150_bms.c
@@ -630,8 +630,6 @@
case SM7150_TAPER_CHARGE:
ret = POWER_SUPPLY_STATUS_CHARGING;
break;
- /* pause on FCC=0, JEITA, USB/DC suspend or on INPUT UV/OV */
- case SM7150_PAUSE_CHARGE:
case SM7150_INHIBIT_CHARGE:
case SM7150_TERMINATE_CHARGE:
/* flag full only at the correct voltage */
@@ -643,6 +641,8 @@
else
ret = POWER_SUPPLY_STATUS_FULL;
break;
+ /* pause on JEITA, USB/DC suspend or on INPUT UV/OV */
+ case SM7150_PAUSE_CHARGE:
/* disabled disconnect */
case SM7150_DISABLE_CHARGE:
ret = POWER_SUPPLY_STATUS_NOT_CHARGING;
diff --git a/drivers/power/supply/google/sm8150_bms.c b/drivers/power/supply/google/sm8150_bms.c
index 0652684..37ef7b0f 100644
--- a/drivers/power/supply/google/sm8150_bms.c
+++ b/drivers/power/supply/google/sm8150_bms.c
@@ -660,8 +660,6 @@
case SM8150_TAPER_CHARGE:
ret = POWER_SUPPLY_STATUS_CHARGING;
break;
- /* pause on FCC=0, JEITA, USB/DC suspend or on INPUT UV/OV */
- case SM8150_PAUSE_CHARGE:
case SM8150_INHIBIT_CHARGE:
case SM8150_TERMINATE_CHARGE:
/* flag full only at the correct voltage */
@@ -673,6 +671,8 @@
else
ret = POWER_SUPPLY_STATUS_FULL;
break;
+ /* pause on JEITA, USB/DC suspend or on INPUT UV/OV */
+ case SM8150_PAUSE_CHARGE:
/* disabled disconnect */
case SM8150_DISABLE_CHARGE:
ret = POWER_SUPPLY_STATUS_NOT_CHARGING;
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 0243779..b6bfc24 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -1802,11 +1802,13 @@
if (atomic_dec_and_test(&ffs->opened)) {
if (ffs->no_disconnect) {
ffs->state = FFS_DEACTIVATED;
+ mutex_lock(&ffs->mutex);
if (ffs->epfiles) {
ffs_epfiles_destroy(ffs->epfiles,
ffs->eps_count);
ffs->epfiles = NULL;
}
+ mutex_unlock(&ffs->mutex);
if (ffs->setup_state == FFS_SETUP_PENDING)
__ffs_ep0_stall(ffs);
} else {
@@ -1878,10 +1880,12 @@
BUG_ON(ffs->gadget);
+ mutex_lock(&ffs->mutex);
if (ffs->epfiles) {
ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count);
ffs->epfiles = NULL;
}
+ mutex_unlock(&ffs->mutex);
if (ffs->ffs_eventfd) {
eventfd_ctx_put(ffs->ffs_eventfd);
diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c
index 16dc063..d908717 100644
--- a/fs/tracefs/inode.c
+++ b/fs/tracefs/inode.c
@@ -501,8 +501,7 @@
if (unlikely(!inode))
return failed_creating(dentry);
- /* Do not set bits for OTH */
- inode->i_mode = S_IFDIR | S_IRWXU | S_IRUSR| S_IRGRP | S_IXUSR | S_IXGRP;
+ inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
inode->i_op = ops;
inode->i_fop = &simple_dir_operations;
inode->i_uid = d_inode(dentry->d_parent)->i_uid;