Merge android-msm-bluecross-4.9-pi-dr1 into -pi-qpr1
Change-Id: Ic7e616a620bdefd72ca69233e3008f9607a998b8
Signed-off-by: Petri Gynther <pgynther@google.com>
diff --git a/arch/arm64/boot/dts/google/sdm845-b1c1-battery.dtsi b/arch/arm64/boot/dts/google/sdm845-b1c1-battery.dtsi
index 714e791..a4ff13a 100644
--- a/arch/arm64/boot/dts/google/sdm845-b1c1-battery.dtsi
+++ b/arch/arm64/boot/dts/google/sdm845-b1c1-battery.dtsi
@@ -108,6 +108,7 @@
google_overheat_mitigation: google,overheat_mitigation {
compatible = "google,overheat_mitigation";
google,port-overheat-work-interval = <1000>;
+ google,accessory-monitoring-period = <150>;
/* Must maintain < 1/15 duty cycle */
google,polling-freq = <3>;
};
diff --git a/arch/arm64/boot/dts/google/sdm845-b1c1-thermal.dtsi b/arch/arm64/boot/dts/google/sdm845-b1c1-thermal.dtsi
index b35cad4..568bdd4 100644
--- a/arch/arm64/boot/dts/google/sdm845-b1c1-thermal.dtsi
+++ b/arch/arm64/boot/dts/google/sdm845-b1c1-thermal.dtsi
@@ -149,15 +149,27 @@
};
};
+&low_vbat {
+ temperature = <3200>;
+ hysteresis = <100>;
+ type = "passive";
+};
+
+&low_soc {
+ temperature = <10>;
+ hysteresis = <0>;
+ type = "passive";
+};
+
+&ibat_high {
+ temperature = <5000>;
+ hysteresis = <200>;
+ type = "passive";
+};
+
&thermal_zones {
vbat {
- trips {
- low_vbat {
- temperature = <3200>;
- hysteresis = <100>;
- type = "passive";
- };
- };
+ polling-delay-passive = <100>;
cooling-maps {
vbat_cpu4 {
trip = <&low_vbat>;
@@ -182,19 +194,12 @@
mnh_thermal {
trip = <&low_vbat>;
cooling-device =
- <&mnh_thermal 0 0>;
+ <&mnh_thermal 3 3>;
};
};
};
soc {
polling-delay-passive = <0>;
- trips {
- low_soc {
- temperature = <10>;
- hysteresis = <0>;
- type = "passive";
- };
- };
cooling-maps {
soc_cpu4 {
trip = <&low_soc>;
@@ -216,21 +221,10 @@
cooling-device =
<&CPU7 18 18>;
};
- mnh_thermal {
- trip = <&low_soc>;
- cooling-device =
- <&mnh_thermal 0 0>;
- };
};
};
ibat-high {
- trips {
- ibat_high {
- temperature = <5000>;
- hysteresis = <200>;
- type = "passive";
- };
- };
+ polling-delay-passive = <100>;
cooling-maps {
ibat_cpu4 {
trip = <&ibat_high>;
@@ -252,11 +246,6 @@
cooling-device =
<&CPU7 18 18>;
};
- mnh_thermal {
- trip = <&ibat_high>;
- cooling-device =
- <&mnh_thermal 0 0>;
- };
};
};
diff --git a/drivers/iio/adc/qcom-rradc.c b/drivers/iio/adc/qcom-rradc.c
index 03b0d92..313aa0c 100644
--- a/drivers/iio/adc/qcom-rradc.c
+++ b/drivers/iio/adc/qcom-rradc.c
@@ -62,7 +62,7 @@
#define FG_ADC_RR_AUX_THERM_CTRL 0x80
#define FG_ADC_RR_AUX_THERM_TRIGGER 0x81
#define FG_ADC_RR_AUX_THERM_EVERY_CYCLE_MASK 0x80
-#define FG_ADC_RR_AUX_THERM_EVERY_CYCLE BIT(7)
+#define FG_ADC_RR_AUX_THERM_EVERY_CYCLE BIT(7)
#define FG_ADC_RR_AUX_THERM_STS 0x82
#define FG_ADC_RR_AUX_THERM_CFG 0x83
#define FG_ADC_RR_AUX_THERM_LSB 0x84
@@ -226,11 +226,6 @@
RR_ADC_MAX
};
-struct rradc_cache {
- u16 value;
- struct timespec ts;
-};
-
struct rradc_chip {
struct device *dev;
struct mutex lock;
@@ -243,7 +238,6 @@
struct pmic_revid_data *pmic_fab_id;
int volt;
struct power_supply *usb_trig;
- struct rradc_cache usbin_v;
};
struct rradc_channels {
@@ -903,31 +897,6 @@
return ret;
}
-static void rradc_update_cache(struct rradc_cache *cache, u16 value)
-{
- cache->value = value;
- getboottime(&cache->ts);
-}
-
-static int rradc_check_cache(struct rradc_cache *cache, u16 *value)
-{
- struct timespec ts, diff;
- s64 delay;
-
- if (cache->ts.tv_sec == 0 && cache->ts.tv_nsec == 0)
- return -ENODATA;
-
- getboottime(&ts);
- diff = timespec_sub(ts, cache->ts);
- delay = timespec_to_ns(&diff);
- if (delay < NSEC_PER_SEC*2) {
- *value = cache->value;
- return 0;
- }
-
- return -ENODATA;
-}
-
static int rradc_do_conversion(struct rradc_chip *chip,
struct rradc_chan_prop *prop, u16 *data)
{
@@ -948,14 +917,11 @@
break;
case RR_ADC_USBIN_V:
/* Don't waste time reporting V BUS on boot */
- if (ktime_get_seconds() <= 3) {
+ if (ktime_get_seconds() <= 10) {
rc = -EAGAIN;
goto fail;
}
- if (rradc_check_cache(&chip->usbin_v, data) == 0) {
- rc = 0;
- goto fail;
- }
+
/* Force conversion every cycle */
rc = rradc_masked_write(chip, FG_ADC_RR_USB_IN_V_TRIGGER,
FG_ADC_RR_USB_IN_V_EVERY_CYCLE_MASK,
@@ -1052,10 +1018,6 @@
} else {
*data = (buf[1] << 8) | buf[0];
}
-
- if (prop->channel == RR_ADC_USBIN_V)
- rradc_update_cache(&chip->usbin_v, *data);
-
fail:
mutex_unlock(&chip->lock);
@@ -1228,9 +1190,6 @@
indio_dev->channels = chip->iio_chans;
indio_dev->num_channels = chip->nchannels;
- chip->usbin_v.ts.tv_sec = 0;
- chip->usbin_v.ts.tv_nsec = 0;
-
chip->usb_trig = power_supply_get_by_name("usb");
if (!chip->usb_trig)
pr_debug("Error obtaining usb power supply\n");
diff --git a/drivers/input/touchscreen/sec_ts/sec_ts.c b/drivers/input/touchscreen/sec_ts/sec_ts.c
index b4faa07..2f76de3 100644
--- a/drivers/input/touchscreen/sec_ts/sec_ts.c
+++ b/drivers/input/touchscreen/sec_ts/sec_ts.c
@@ -2796,6 +2796,8 @@
ts->power_status = SEC_TS_STATE_SUSPEND;
+ sec_ts_pinctrl_configure(ts, false);
+
sec_set_switch_gpio(ts, SEC_SWITCH_GPIO_VALUE_SLPI_MASTER);
#ifdef CONFIG_TOUCHSCREEN_TBN
@@ -2823,6 +2825,8 @@
sec_set_switch_gpio(ts, SEC_SWITCH_GPIO_VALUE_AP_MASTER);
+ sec_ts_pinctrl_configure(ts, true);
+
if (ts->power_status == SEC_TS_STATE_POWER_ON) {
input_err(true, &ts->client->dev, "%s: already resumed.\n",
__func__);
diff --git a/drivers/misc/google-easel-comm-dma.c b/drivers/misc/google-easel-comm-dma.c
index 242a1a7..35d81e2 100644
--- a/drivers/misc/google-easel-comm-dma.c
+++ b/drivers/misc/google-easel-comm-dma.c
@@ -493,7 +493,8 @@
static int easelcomm_client_handle_dma_request(
struct easelcomm_service *service,
struct easelcomm_message_metadata *msg_metadata,
- enum easelcomm_dma_direction dma_dir)
+ enum easelcomm_dma_direction dma_dir,
+ int timeout_ms)
{
int ret, ret2;
@@ -508,9 +509,18 @@
return 0;
/* Wait for server to return the DMA request info */
- ret = wait_for_completion_interruptible(
- &msg_metadata->dma_xfer.xfer_ready);
- if (ret || msg_metadata->dma_xfer.aborting)
+ ret = wait_for_completion_interruptible_timeout(
+ &msg_metadata->dma_xfer.xfer_ready,
+ msecs_to_jiffies(timeout_ms));
+ if (ret == -ERESTARTSYS) {
+ dev_info(easelcomm_miscdev.this_device,
+ "Wait for DMA_XFER from server interrupted\n");
+ goto abort;
+ } else if (ret == 0) {
+ dev_err(easelcomm_miscdev.this_device,
+ "Wait for DMA_XFER from server timed out\n");
+ goto abort;
+ } else if (msg_metadata->dma_xfer.aborting)
goto abort;
/*
@@ -566,9 +576,10 @@
int ret = 0;
dev_dbg(easelcomm_miscdev.this_device,
- "RECVDMA msg %u:r%llu buf_type=%d buf_size=%u dma_buf_fd=%d dma_buf_off=%u dma_buf_width=%u dma_buf_stride=%u\n",
+ "RECVDMA msg %u:r%llu buf_type=%d buf_size=%u timeout_ms=%d dma_buf_fd=%d dma_buf_off=%u dma_buf_width=%u dma_buf_stride=%u\n",
service->service_id, buf_desc->message_id,
buf_desc->buf_type, buf_desc->buf_size,
+ buf_desc->wait.timeout_ms,
buf_desc->dma_buf_fd,
buf_desc->dma_buf_off,
buf_desc->dma_buf_width,
@@ -631,7 +642,8 @@
if (easelcomm_is_client())
ret = easelcomm_client_handle_dma_request(
- service, msg_metadata, dma_dir);
+ service, msg_metadata, dma_dir,
+ buf_desc->wait.timeout_ms);
else
ret = easelcomm_server_handle_dma_request(
service, msg_metadata, dma_dir);
@@ -659,9 +671,10 @@
int ret = 0;
dev_dbg(easelcomm_miscdev.this_device,
- "SENDDMA msg %u:l%llu buf_type=%d buf_size=%u dma_buf_fd=%d dma_buf_off=%u dma_buf_width=%u dma_buf_stride=%u\n",
+ "SENDDMA msg %u:l%llu buf_type=%d buf_size=%u timeout_ms=%d dma_buf_fd=%d dma_buf_off=%u dma_buf_width=%u dma_buf_stride=%u\n",
service->service_id, buf_desc->message_id,
buf_desc->buf_type, buf_desc->buf_size,
+ buf_desc->wait.timeout_ms,
buf_desc->dma_buf_fd, buf_desc->dma_buf_off,
buf_desc->dma_buf_width, buf_desc->dma_buf_stride);
@@ -717,7 +730,8 @@
if (msg_metadata->msg->desc.dma_buf_size) {
if (easelcomm_is_client())
ret = easelcomm_client_handle_dma_request(
- service, msg_metadata, dma_dir);
+ service, msg_metadata, dma_dir,
+ buf_desc->wait.timeout_ms);
else
ret = easelcomm_server_handle_dma_request(
service, msg_metadata, dma_dir);
diff --git a/drivers/misc/google-easel-comm.c b/drivers/misc/google-easel-comm.c
index ff639e8..44b103f 100644
--- a/drivers/misc/google-easel-comm.c
+++ b/drivers/misc/google-easel-comm.c
@@ -1932,6 +1932,7 @@
kbuf_desc.buf = compat_ptr(compat_kbuf_desc.buf);
kbuf_desc.buf_size = compat_kbuf_desc.buf_size;
kbuf_desc.buf_type = compat_kbuf_desc.buf_type;
+ kbuf_desc.wait.timeout_ms = -1;
kbuf_desc.dma_buf_fd = compat_kbuf_desc.dma_buf_fd;
kbuf_desc.dma_buf_off = compat_kbuf_desc.dma_buf_off;
kbuf_desc.dma_buf_width = compat_kbuf_desc.dma_buf_width;
@@ -1971,6 +1972,7 @@
kbuf_desc.buf = compat_ptr(compat_kbuf_desc_legacy.buf);
kbuf_desc.buf_size = compat_kbuf_desc_legacy.buf_size;
kbuf_desc.buf_type = compat_kbuf_desc_legacy.buf_type;
+ kbuf_desc.wait.timeout_ms = -1;
kbuf_desc.dma_buf_fd = compat_kbuf_desc_legacy.dma_buf_fd;
kbuf_desc.dma_buf_width = compat_kbuf_desc_legacy.buf_size;
kbuf_desc.dma_buf_stride = compat_kbuf_desc_legacy.buf_size;
@@ -1988,6 +1990,7 @@
kbuf_desc.buf = kbuf_desc_legacy.buf;
kbuf_desc.buf_size = kbuf_desc_legacy.buf_size;
kbuf_desc.buf_type = kbuf_desc_legacy.buf_type;
+ kbuf_desc.wait.timeout_ms = kbuf_desc_legacy.wait.timeout_ms;
kbuf_desc.dma_buf_fd = kbuf_desc_legacy.dma_buf_fd;
kbuf_desc.dma_buf_width = kbuf_desc_legacy.buf_size;
kbuf_desc.dma_buf_stride = kbuf_desc_legacy.buf_size;
diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c
index 5ba8de3..b87b06c 100644
--- a/drivers/power/reset/msm-poweroff.c
+++ b/drivers/power/reset/msm-poweroff.c
@@ -349,7 +349,11 @@
if (in_panic) {
qpnp_pon_set_restart_reason(PON_RESTART_REASON_PANIC);
} else if (cmd != NULL) {
- if (!strncmp(cmd, "bootloader", 10)) {
+ if (!strncmp(cmd, "packout", strlen("packout"))) {
+ qpnp_pon_set_restart_reason(
+ PON_RESTART_REASON_OEM_PACKOUT);
+ __raw_writel(0x77665500, restart_reason);
+ } else if (!strncmp(cmd, "bootloader", 10)) {
qpnp_pon_set_restart_reason(
PON_RESTART_REASON_BOOTLOADER);
__raw_writel(0x77665500, restart_reason);
diff --git a/drivers/power/supply/max1720x_battery.c b/drivers/power/supply/max1720x_battery.c
index 7ad5001..0f69a5b 100644
--- a/drivers/power/supply/max1720x_battery.c
+++ b/drivers/power/supply/max1720x_battery.c
@@ -28,6 +28,12 @@
#include <linux/slab.h>
#include <linux/time.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/fs.h> /* register_chrdev, unregister_chrdev */
+#include <linux/module.h>
+#include <linux/seq_file.h> /* seq_read, seq_lseek, single_release */
+
#ifdef CONFIG_DEBUG_FS
#include <linux/debugfs.h>
#endif
@@ -40,8 +46,7 @@
#define MAX1720X_DELAY_INIT_MS 1000
#define FULLCAPNOM_STABILIZE_CYCLES 5
-/* workaround for b/111835845 */
-#define MAXFG_HISTORY_PAGE_ENT_COUNT (PAGE_SIZE / (16*5 + 1))
+#define HISTORY_DEVICENAME "maxfg_history"
enum max1720x_register {
/* ModelGauge m5 Register */
@@ -290,6 +295,14 @@
int prev_soc;
};
+
+struct max1720x_history {
+ loff_t history_index;
+ int history_count;
+ bool *page_status;
+ u16 *history;
+};
+
struct max1720x_chip {
struct device *dev;
struct regmap *regmap;
@@ -302,6 +315,15 @@
struct device_node *batt_node;
struct iio_channel *iio_ch;
struct max1720x_cyc_ctr_data cyc_ctr;
+
+ /* history */
+ struct mutex history_lock;
+ int hcmajor;
+ struct cdev hcdev;
+ struct class *hcclass;
+ bool history_available;
+ bool history_added;
+
u16 RSense;
u16 RConfig;
bool init_complete;
@@ -544,13 +566,6 @@
kfree(write_status);
kfree(valid_status);
- /* workaround for b/111835845 */
- if (valid_history_entry_count > MAXFG_HISTORY_PAGE_ENT_COUNT) {
- dev_info(chip->dev, " support only one page (%d available)\n",
- valid_history_entry_count);
- valid_history_entry_count = MAXFG_HISTORY_PAGE_ENT_COUNT;
- }
-
return valid_history_entry_count;
}
@@ -576,105 +591,68 @@
}
}
-static ssize_t max1720x_history_count_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static int format_battery_history_entry(char *temp, int size, u16 *line)
{
+ int length = 0, i;
- struct power_supply *psy;
- struct max1720x_chip *chip;
- int length, ret;
- bool *page_status;
-
- psy = container_of(dev, struct power_supply, dev);
- chip = power_supply_get_drvdata(psy);
-
- page_status = kcalloc(MAX1720X_N_OF_HISTORY_PAGES,
- sizeof(bool), GFP_KERNEL);
- if (!page_status)
- return -ENOMEM;
-
- ret = get_battery_history_status(chip, page_status);
- if (ret < 0) {
- kfree(page_status);
- return ret;
+ for (i = 0; i < MAX1720X_HISTORY_PAGE_SIZE; i++) {
+ length += scnprintf(temp + length,
+ size - length, "%04x ",
+ line[i]);
}
- length = scnprintf(buf, PAGE_SIZE, "%i\n", ret);
- kfree(page_status);
+ if (length > 0)
+ temp[--length] = 0;
return length;
}
-static const DEVICE_ATTR(history_count, 0444,
- max1720x_history_count_show, NULL);
-
-static ssize_t max1720x_history_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+/* @return number of valid entries */
+static int max1720x_history_read(struct max1720x_chip *chip,
+ struct max1720x_history *hi)
{
- struct power_supply *psy;
- struct max1720x_chip *chip;
- int i;
- int length = 0;
- bool *page_status = NULL;
- int history_index, history_count;
- u16 *history;
+ memset(hi, 0, sizeof(*hi));
- psy = container_of(dev, struct power_supply, dev);
- chip = power_supply_get_drvdata(psy);
-
- /*
- * Total history size can be up to 6.7KB, which is greater than
- * PAGE_SIZE, which is 4K. Complete history may need to be queried
- * in two calls (only one supported now)
- */
- page_status = kcalloc(MAX1720X_N_OF_HISTORY_PAGES,
+ hi->page_status = kcalloc(MAX1720X_N_OF_HISTORY_PAGES,
sizeof(bool), GFP_KERNEL);
- if (!page_status)
+ if (!hi->page_status)
return -ENOMEM;
- history_count = get_battery_history_status(chip, page_status);
- if (history_count <= 0) {
- kfree(page_status);
- if (!history_count)
- dev_info(chip->dev,
- "No battery history has been recorded\n");
- return history_count;
- }
+ mutex_lock(&chip->history_lock);
- history = kmalloc_array(MAX1720X_N_OF_HISTORY_PAGES *
- MAX1720X_HISTORY_PAGE_SIZE,
- sizeof(u16), GFP_KERNEL);
- if (!history) {
- kfree(page_status);
- return -ENOMEM;
- }
+ hi->history_count = get_battery_history_status(chip, hi->page_status);
+ if (hi->history_count < 0) {
+ goto error_exit;
+ } else if (hi->history_count != 0) {
+ const int size = hi->history_count * MAX1720X_HISTORY_PAGE_SIZE;
- get_battery_history(chip, page_status, history);
-
- /*
- * The 81 in the next line is arrived with 16*5: one history log
- * is 16 of u16. We print each u16 to 4 chars and we leave one space
- * between the hex data in the buffer. And lastly we need a new line
- * for every history log. (16x4 + 16x1 + 1) = 81.
- */
- for (history_index = 0; (history_index < history_count)
- && (length < (PAGE_SIZE - 81)); history_index++) {
- for (i = 0; i < MAX1720X_HISTORY_PAGE_SIZE; i++) {
- length += scnprintf(buf + length,
- PAGE_SIZE - length, "%04x ",
- history[history_index *
- MAX1720X_HISTORY_PAGE_SIZE + i]);
+ hi->history = kmalloc_array(size, sizeof(u16), GFP_KERNEL);
+ if (!hi->history) {
+ hi->history_count = -ENOMEM;
+ goto error_exit;
}
- length += scnprintf(buf + length, PAGE_SIZE - length, "\n");
+
+ get_battery_history(chip, hi->page_status, hi->history);
}
- kfree(history);
- kfree(page_status);
+ mutex_unlock(&chip->history_lock);
+ return hi->history_count;
- return length;
+error_exit:
+ mutex_unlock(&chip->history_lock);
+ kfree(hi->page_status);
+ hi->page_status = NULL;
+ return hi->history_count;
+
}
-static const DEVICE_ATTR(history, 0444, max1720x_history_show, NULL);
+static void max1720x_history_free(struct max1720x_history *hi)
+{
+ kfree(hi->page_status);
+ kfree(hi->history);
+
+ hi->history = NULL;
+ hi->page_status = NULL;
+}
static enum power_supply_property max1720x_battery_props[] = {
POWER_SUPPLY_PROP_STATUS,
@@ -1842,6 +1820,146 @@
.num_properties = ARRAY_SIZE(max1720x_battery_props),
};
+
+static void *ct_seq_start(struct seq_file *s, loff_t *pos)
+{
+ struct max1720x_history *hi =
+ (struct max1720x_history *)s->private;
+
+ if (*pos >= hi->history_count)
+ return NULL;
+ hi->history_index = *pos;
+
+ return &hi->history_index;
+}
+
+static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+ loff_t *spos = (loff_t *)v;
+ struct max1720x_history *hi =
+ (struct max1720x_history *)s->private;
+
+ *pos = ++*spos;
+ if (*pos >= hi->history_count)
+ return NULL;
+
+ return spos;
+}
+
+static void ct_seq_stop(struct seq_file *s, void *v)
+{
+ /* iterator in hi, no need to free */
+}
+
+static int ct_seq_show(struct seq_file *s, void *v)
+{
+ char temp[96];
+ loff_t *spos = (loff_t *)v;
+ struct max1720x_history *hi =
+ (struct max1720x_history *)s->private;
+ const size_t offset = *spos * MAX1720X_HISTORY_PAGE_SIZE;
+
+ format_battery_history_entry(temp, sizeof(temp), &hi->history[offset]);
+ seq_printf(s, "%s\n", temp);
+
+ return 0;
+}
+
+static const struct seq_operations ct_seq_ops = {
+ .start = ct_seq_start,
+ .next = ct_seq_next,
+ .stop = ct_seq_stop,
+ .show = ct_seq_show
+};
+
+static int history_dev_open(struct inode *inode, struct file *file)
+{
+ struct max1720x_chip *chip =
+ container_of(inode->i_cdev, struct max1720x_chip, hcdev);
+ struct max1720x_history *hi;
+ int history_count;
+
+ hi = __seq_open_private(file, &ct_seq_ops, sizeof(*hi));
+ if (!hi)
+ return -ENOMEM;
+
+ history_count = max1720x_history_read(chip, hi);
+ if (history_count < 0) {
+ return history_count;
+ } else if (history_count == 0) {
+ dev_info(chip->dev,
+ "No battery history has been recorded\n");
+ }
+
+ return 0;
+}
+
+static int history_dev_release(struct inode *inode, struct file *file)
+{
+ struct max1720x_history *hi =
+ ((struct seq_file *)file->private_data)->private;
+
+ if (hi) {
+ max1720x_history_free(hi);
+ seq_release_private(inode, file);
+ }
+
+ return 0;
+}
+
+static const struct file_operations hdev_fops = {
+ .open = history_dev_open,
+ .owner = THIS_MODULE,
+ .read = seq_read,
+ .release = history_dev_release,
+};
+
+static void max1720x_cleanup_history(struct max1720x_chip *chip)
+{
+ if (chip->history_added)
+ cdev_del(&chip->hcdev);
+ if (chip->history_available)
+ device_destroy(chip->hcclass, chip->hcmajor);
+ if (chip->hcclass)
+ class_destroy(chip->hcclass);
+ if (chip->hcmajor != -1)
+ unregister_chrdev_region(chip->hcmajor, 1);
+}
+
+static int max1720x_init_history(struct max1720x_chip *chip)
+{
+ struct device *hcdev;
+
+ mutex_init(&chip->history_lock);
+
+ chip->hcmajor = -1;
+
+ /* cat /proc/devices */
+ if (alloc_chrdev_region(&chip->hcmajor, 0, 1, HISTORY_DEVICENAME) < 0)
+ goto no_history;
+ /* ls /sys/class */
+ chip->hcclass = class_create(THIS_MODULE, HISTORY_DEVICENAME);
+ if (chip->hcclass == NULL)
+ goto no_history;
+ /* ls /dev/ */
+ hcdev = device_create(chip->hcclass, NULL, chip->hcmajor, NULL,
+ HISTORY_DEVICENAME);
+ if (hcdev == NULL)
+ goto no_history;
+
+ chip->history_available = true;
+ cdev_init(&chip->hcdev, &hdev_fops);
+ if (cdev_add(&chip->hcdev, chip->hcmajor, 1) == -1)
+ goto no_history;
+
+ chip->history_added = true;
+ return 0;
+
+no_history:
+ max1720x_cleanup_history(chip);
+ return -ENODEV;
+}
+
static void max1720x_init_work(struct work_struct *work)
{
struct max1720x_chip *chip = container_of(work, struct max1720x_chip,
@@ -1853,6 +1971,8 @@
msecs_to_jiffies(MAX1720X_DELAY_INIT_MS));
return;
}
+
+ (void)max1720x_init_history(chip);
}
static int max1720x_probe(struct i2c_client *client,
@@ -1919,18 +2039,6 @@
goto irq_unregister;
}
- ret = device_create_file(&chip->psy->dev, &dev_attr_history_count);
- if (ret) {
- dev_err(dev, "Failed to create history_count attribute\n");
- goto psy_unregister;
- }
-
- ret = device_create_file(&chip->psy->dev, &dev_attr_history);
- if (ret) {
- dev_err(dev, "Failed to create history attribute\n");
- goto psy_unregister;
- }
-
ret = device_create_file(&chip->psy->dev, &dev_attr_cycle_counts_bins);
if (ret) {
dev_err(dev, "Failed to create cycle_counts_bins attribute\n");
@@ -1966,6 +2074,7 @@
{
struct max1720x_chip *chip = i2c_get_clientdata(client);
+ max1720x_cleanup_history(chip);
cancel_delayed_work(&chip->init_work);
iio_channel_release(chip->iio_ch);
if (chip->primary->irq)
diff --git a/drivers/power/supply/overheat_mitigation.c b/drivers/power/supply/overheat_mitigation.c
index da68d8d..8cbbc42 100644
--- a/drivers/power/supply/overheat_mitigation.c
+++ b/drivers/power/supply/overheat_mitigation.c
@@ -45,6 +45,7 @@
struct wakeup_source overheat_ws;
bool usb_connected;
+ bool accessory_connected;
bool usb_replug;
bool overheat_mitigation;
bool overheat_work_running;
@@ -53,6 +54,8 @@
int clear_temp;
int overheat_work_delay_ms;
int polling_freq;
+ int monitor_accessory_s;
+ time_t accessory_connect_time;
int check_status;
};
@@ -117,6 +120,15 @@
return ret;
}
+ ret = of_property_read_u32(node, "google,accessory-monitoring-period",
+ &ovh_info->monitor_accessory_s);
+ if (ret < 0) {
+ dev_err(ovh_info->dev,
+ "cannot read accessory-monitoring-period, ret=%d\n",
+ ret);
+ ovh_info->monitor_accessory_s = 5;
+ }
+
return 0;
}
@@ -177,13 +189,25 @@
return ret;
}
+static inline time_t get_seconds_since_boot(void)
+{
+ struct timespec boot;
+
+ getboottime(&boot);
+ return get_seconds() - boot.tv_sec;
+}
+
/*
- * Updated usb_connected and usb_replug status in overheat_info struct
+ * Update usb_connected, accessory_connected, and usb_replug status in
+ * overheat_info struct.
*/
static int update_usb_status(struct overheat_info *ovh_info)
{
int ret;
- bool prev_state = ovh_info->usb_connected;
+ bool prev_state = ovh_info->usb_connected ||
+ ovh_info->accessory_connected;
+ bool prev_accessory_state = ovh_info->accessory_connected;
+ bool curr_state;
int *check_status = &ovh_info->check_status;
if (ovh_info->overheat_mitigation) {
@@ -208,6 +232,16 @@
return ret;
ovh_info->usb_connected = ret;
+ ret = PSY_GET_PROP(ovh_info->usb_psy, POWER_SUPPLY_PROP_TYPEC_MODE);
+ if (ret < 0)
+ return ret;
+ ovh_info->accessory_connected = (ret == POWER_SUPPLY_TYPEC_SINK) ||
+ (ret == POWER_SUPPLY_TYPEC_SINK_POWERED_CABLE);
+
+ if (!prev_accessory_state && ovh_info->accessory_connected)
+ ovh_info->accessory_connect_time = get_seconds_since_boot();
+ curr_state = ovh_info->usb_connected || ovh_info->accessory_connected;
+
if (ovh_info->overheat_mitigation) {
ret = vote(ovh_info->disable_power_role_switch,
USB_OVERHEAT_MITIGATION_VOTER, true, 0);
@@ -219,14 +253,13 @@
}
}
- if (ovh_info->usb_connected != prev_state)
+ if (curr_state != prev_state)
dev_info(ovh_info->dev,
"USB is %sconnected",
- ovh_info->usb_connected ? "" : "dis");
+ curr_state ? "" : "dis");
// USB should be disconnected for two cycles before replug is acked
- if(ovh_info->overheat_mitigation && !ovh_info->usb_connected &&
- !prev_state)
+ if (ovh_info->overheat_mitigation && !curr_state && !prev_state)
ovh_info->usb_replug = true;
return 0;
@@ -267,6 +300,24 @@
return NOTIFY_OK;
}
+static bool should_check_accessory(struct overheat_info *ovh_info)
+{
+ time_t connected;
+ bool ret;
+
+ if (!ovh_info->accessory_connected)
+ return false;
+
+ connected =
+ get_seconds_since_boot() - ovh_info->accessory_connect_time;
+ ret = (connected < ovh_info->monitor_accessory_s);
+ if (!ret)
+ dev_info(ovh_info->dev,
+ "Stop monitoring: %d sec since USB accessory connected",
+ (int) connected);
+ return ret;
+}
+
static void port_overheat_work(struct work_struct *work)
{
struct overheat_info *ovh_info =
@@ -304,7 +355,8 @@
goto rerun;
}
- if (ovh_info->overheat_mitigation || ovh_info->usb_connected)
+ if (ovh_info->overheat_mitigation || ovh_info->usb_connected ||
+ should_check_accessory(ovh_info))
goto rerun;
// Do not run again, USB port isn't overheated or connected to something
ovh_info->overheat_work_running = false;
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index 9f99a54..8318603 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -338,6 +338,7 @@
POWER_SUPPLY_ATTR(enable_jeita_detection),
POWER_SUPPLY_ATTR(otg_fastroleswap),
POWER_SUPPLY_ATTR(charge_disable),
+ POWER_SUPPLY_ATTR(in_explicit_contract),
/* Local extensions of type int64_t */
POWER_SUPPLY_ATTR(charge_counter_ext),
/* Properties of type `const char *' */
diff --git a/drivers/power/supply/qcom/p9221_charger.c b/drivers/power/supply/qcom/p9221_charger.c
index 49d3937..944f9d9 100644
--- a/drivers/power/supply/qcom/p9221_charger.c
+++ b/drivers/power/supply/qcom/p9221_charger.c
@@ -36,6 +36,11 @@
#define P9221R5_ILIM_MAX_UA (1600 * 1000)
#define P9221R5_OVER_CHECK_NUM 3
+#define OVC_LIMIT 1
+#define OVC_THRESHOLD 1400000
+#define OVC_BACKOFF_LIMIT 900000
+#define OVC_BACKOFF_AMOUNT 100000
+
static const u32 p9221_ov_set_lut[] = {
17000000, 20000000, 15000000, 13000000,
11000000, 11000000, 11000000, 11000000};
@@ -733,7 +738,6 @@
struct p9221_prop_reg_map_entry p9221_prop_reg_map[] = {
/* property register g, s */
{POWER_SUPPLY_PROP_CURRENT_NOW, P9221_RX_IOUT_REG, 1, 0},
- {POWER_SUPPLY_PROP_CURRENT_MAX, P9221_ILIM_SET_REG, 1, 1},
{POWER_SUPPLY_PROP_VOLTAGE_NOW, P9221_VOUT_ADC_REG, 1, 0},
{POWER_SUPPLY_PROP_VOLTAGE_MAX, P9221_VOUT_SET_REG, 1, 1},
{POWER_SUPPLY_PROP_TEMP, P9221_DIE_TEMP_ADC_REG, 1, 0},
@@ -743,7 +747,6 @@
struct p9221_prop_reg_map_entry p9221_prop_reg_map_r5[] = {
/* property register g, s */
{POWER_SUPPLY_PROP_CURRENT_NOW, P9221R5_IOUT_REG, 1, 0},
- {POWER_SUPPLY_PROP_CURRENT_MAX, P9221R5_ILIM_SET_REG, 1, 1},
{POWER_SUPPLY_PROP_VOLTAGE_NOW, P9221R5_VOUT_REG, 1, 0},
{POWER_SUPPLY_PROP_VOLTAGE_MAX, P9221R5_VOUT_SET_REG, 1, 1},
{POWER_SUPPLY_PROP_TEMP, P9221R5_DIE_TEMP_ADC_REG, 1, 0},
@@ -836,10 +839,35 @@
sysfs_notify(&charger->dev->kobj, NULL, "rxdone");
}
-static void p9221_set_offline(struct p9221_charger_data *charger)
+/*
+ * Put the default ICL back to BPP, reset OCP voter
+ * @pre charger && charger->dc_icl_votable && charger->client->dev
+ */
+static void p9221_vote_defaults(struct p9221_charger_data *charger)
{
int ret;
+ if (!charger->dc_icl_votable) {
+ dev_err(&charger->client->dev,
+ "Could not vote DC_ICL - no votable\n");
+ return;
+ }
+
+ ret = vote(charger->dc_icl_votable, P9221_WLC_VOTER, true,
+ P9221_DC_ICL_BPP_UA);
+ if (ret)
+ dev_err(&charger->client->dev,
+ "Could not vote DC_ICL %d\n", ret);
+
+ ret = vote(charger->dc_icl_votable, P9221_OCP_VOTER, true,
+ P9221_DC_ICL_EPP_UA);
+ if (ret)
+ dev_err(&charger->client->dev,
+ "Could not reset OCP DC_ICL voter %d\n", ret);
+}
+
+static void p9221_set_offline(struct p9221_charger_data *charger)
+{
dev_info(&charger->client->dev, "Set offline\n");
charger->online = false;
@@ -851,14 +879,7 @@
cancel_delayed_work(&charger->dcin_work);
del_timer(&charger->vrect_timer);
- /* Put the default ICL back to BPP */
- if (charger->dc_icl_votable) {
- ret = vote(charger->dc_icl_votable, P9221_WLC_VOTER, true,
- P9221_DC_ICL_BPP_UA);
- if (ret)
- dev_err(&charger->client->dev,
- "Could not vote DC_ICL %d\n", ret);
- }
+ p9221_vote_defaults(charger);
}
static void p9221_tx_work(struct work_struct *work)
@@ -965,6 +986,16 @@
else
val->intval = 0;
break;
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ if (!charger->dc_icl_votable)
+ return -EAGAIN;
+
+ ret = get_effective_result(charger->dc_icl_votable);
+ if (ret < 0)
+ break;
+
+ val->intval = ret;
+ break;
default:
ret = p9221_get_property_reg(charger, prop, val);
break;
@@ -995,7 +1026,18 @@
"Could send csp: %d\n", ret);
}
break;
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ if (val->intval < 0) {
+ ret = -EINVAL;
+ break;
+ }
+ if (!charger->dc_icl_votable)
+ return -EAGAIN;
+
+ ret = vote(charger->dc_icl_votable, P9221_USER_VOTER, true,
+ val->intval);
+ break;
default:
ret = p9221_set_property_reg(charger, prop, val);
break;
@@ -1853,6 +1895,19 @@
"Failed to send EOP %d: %d\n", reason, ret);
}
+static void print_current_samples(struct p9221_charger_data *charger,
+ u32 *iout_val, int count)
+{
+ int i;
+ char temp[P9221R5_OVER_CHECK_NUM * 9 + 1] = { 0 };
+
+ for (i = 0; i < count ; i++)
+ scnprintf(temp + i * 9, sizeof(temp) - i * 9,
+ "%08x ", iout_val[i]);
+
+ dev_info(&charger->client->dev, "OVER IOUT_SAMPLES: %s\n", temp);
+}
+
/*
* Number of times to poll the status to see if the current limit condition
* was transient or not.
@@ -1863,6 +1918,8 @@
u8 reason = 0;
int i;
int ret;
+ int ovc_count = 0;
+ u32 iout_val[P9221R5_OVER_CHECK_NUM] = { 0 };
dev_err(&charger->client->dev, "Received OVER INT: %02x\n", irq_src);
@@ -1879,7 +1936,26 @@
if ((irq_src & P9221R5_STAT_UV) && !(irq_src & P9221R5_STAT_OVC))
return;
- /* Overcurrent, poll to absorb any transients */
+ /* Overcurrent, reduce ICL and poll to absorb any transients */
+
+ if (charger->dc_icl_votable) {
+ int icl;
+
+ icl = get_effective_result_locked(charger->dc_icl_votable);
+ if (icl < 0) {
+ dev_err(&charger->client->dev,
+ "Failed to read ICL (%d)\n", icl);
+ } else if (icl > OVC_BACKOFF_LIMIT) {
+ icl -= OVC_BACKOFF_AMOUNT;
+
+ ret = vote(charger->dc_icl_votable,
+ P9221_OCP_VOTER, true,
+ icl);
+ dev_err(&charger->client->dev,
+ "Reduced ICL to %d (%d)\n", icl, ret);
+ }
+ }
+
reason = P9221_EOP_OVER_CURRENT;
for (i = 0; i < P9221R5_OVER_CHECK_NUM; i++) {
ret = p9221_clear_interrupts(charger,
@@ -1888,6 +1964,16 @@
if (ret)
continue;
+ ret = p9221_reg_read_cooked(charger, P9221R5_IOUT_REG,
+ &iout_val[i]);
+ if (ret) {
+ dev_err(&charger->client->dev,
+ "Failed to read IOUT[%d]: %d\n", i, ret);
+ continue;
+ } else if (iout_val[i] > OVC_THRESHOLD) {
+ ovc_count++;
+ }
+
ret = p9221_reg_read_16(charger, P9221_STATUS_REG, &irq_src);
if (ret) {
dev_err(&charger->client->dev,
@@ -1896,15 +1982,26 @@
}
if ((irq_src & P9221R5_STAT_OVC) == 0) {
+ print_current_samples(charger, iout_val, i + 1);
dev_info(&charger->client->dev,
"OVER condition %04x cleared after %d tries\n",
irq_src, i);
return;
}
+
dev_err(&charger->client->dev,
"OVER status is still %04x, retry\n", irq_src);
}
+ if (ovc_count < OVC_LIMIT) {
+ print_current_samples(charger, iout_val,
+ P9221R5_OVER_CHECK_NUM);
+ dev_info(&charger->client->dev,
+ "ovc_threshold=%d, ovc_count=%d, ovc_limit=%d\n",
+ OVC_THRESHOLD, ovc_count, OVC_LIMIT);
+ return;
+ }
+
send_eop:
dev_err(&charger->client->dev,
"OVER is %04x, sending EOP %d\n", irq_src, reason);
@@ -2237,6 +2334,14 @@
return PTR_ERR(charger->wc_psy);
}
+ /*
+ * Find the DC_ICL votable, we use this to limit the current that
+ * is taken from the wireless charger.
+ */
+ charger->dc_icl_votable = find_votable("DC_ICL");
+ if (!charger->dc_icl_votable)
+ dev_warn(&charger->client->dev, "Could not find DC_ICL votable\n");
+
/* Test to see if the charger is online */
ret = p9221_reg_read_16(charger, P9221_CHIP_ID_REG, &chip_id);
if (ret == 0 && chip_id == P9221_CHIP_ID) {
@@ -2244,19 +2349,8 @@
/* set charger->online=true, will ignore first VRECTON IRQ */
p9221_set_online(charger);
} else {
- /* disconnected, vote for BPP */
- charger->dc_icl_votable = find_votable("DC_ICL");
- if (!charger->dc_icl_votable) {
- ret = -ENODEV;
- } else {
- ret = vote(charger->dc_icl_votable,
- P9221_WLC_VOTER, true,
- P9221_DC_ICL_BPP_UA);
- }
- if (ret)
- dev_err(&charger->client->dev,
- "Could not vote for default DC_ICL votable=%d %d\n",
- charger->dc_icl_votable != 0, ret);
+ /* disconnected, (likely err!=0) vote for BPP */
+ p9221_vote_defaults(charger);
}
ret = devm_request_threaded_irq(
@@ -2268,7 +2362,11 @@
return ret;
}
device_init_wakeup(charger->dev, true);
- /* NOTE: will get a VRECTON when booting on a pad */
+
+ /*
+ * We will receive a VRECTON after enabling IRQ if the device is
+ * if the device is already in-field when the driver is probed.
+ */
enable_irq_wake(charger->pdata->irq_int);
if (gpio_is_valid(charger->pdata->irq_det_gpio)) {
diff --git a/drivers/power/supply/qcom/p9221_charger.h b/drivers/power/supply/qcom/p9221_charger.h
index fe24807..514560c 100644
--- a/drivers/power/supply/qcom/p9221_charger.h
+++ b/drivers/power/supply/qcom/p9221_charger.h
@@ -16,6 +16,8 @@
#define __P9221_CHARGER_H__
#define P9221_WLC_VOTER "WLC_VOTER"
+#define P9221_USER_VOTER "WLC_USER_VOTER"
+#define P9221_OCP_VOTER "OCP_VOTER"
#define P9221_DC_ICL_BPP_UA 700000
#define P9221_DC_ICL_EPP_UA 1100000
#define P9221_EPP_THRESHOLD_UV 7000000
diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index 5eef7d6..a90f3b07 100644
--- a/drivers/power/supply/qcom/qpnp-smb2.c
+++ b/drivers/power/supply/qcom/qpnp-smb2.c
@@ -404,6 +404,7 @@
POWER_SUPPLY_PROP_CONNECTOR_TYPE,
POWER_SUPPLY_PROP_OTG_FASTROLESWAP,
POWER_SUPPLY_PROP_MOISTURE_DETECTED,
+ POWER_SUPPLY_PROP_PD_IN_EXPLICIT_CONTRACT,
};
static int smb2_usb_get_prop(struct power_supply *psy,
@@ -415,6 +416,9 @@
int rc = 0;
switch (psp) {
+ case POWER_SUPPLY_PROP_PD_IN_EXPLICIT_CONTRACT:
+ val->intval = chg->in_explicit_contract;
+ break;
case POWER_SUPPLY_PROP_PRESENT:
if (chip->bad_part)
val->intval = 1;
@@ -564,17 +568,25 @@
case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE:
rc = smblib_set_prop_typec_power_role(chg, val);
break;
+ case POWER_SUPPLY_PROP_PD_IN_EXPLICIT_CONTRACT:
+ chg->in_explicit_contract = val->intval;
+ power_supply_changed(chg->usb_psy);
+ break;
default:
rc = -EINVAL;
break;
}
-
goto unlock;
}
switch (psp) {
+ case POWER_SUPPLY_PROP_PD_IN_EXPLICIT_CONTRACT:
+ chg->in_explicit_contract = val->intval;
+ power_supply_changed(chg->usb_psy);
+ break;
case POWER_SUPPLY_PROP_PD_CURRENT_MAX:
rc = smblib_set_prop_pd_current_max(chg, val);
+ power_supply_changed(chg->usb_psy);
break;
case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE:
rc = smblib_set_prop_typec_power_role(chg, val);
diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c
index 3c72829..505490b 100644
--- a/drivers/power/supply/qcom/smb-lib.c
+++ b/drivers/power/supply/qcom/smb-lib.c
@@ -3445,7 +3445,7 @@
bool non_compliant;
u8 stat5;
- if (chg->pd_active) {
+ if (chg->in_explicit_contract) {
*total_current_ua =
get_client_vote_locked(chg->usb_icl_votable, PD_VOTER);
return rc;
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index efa476c1..314a10a 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -360,6 +360,7 @@
bool otg_present;
bool is_audio_adapter;
bool hvdcp_disable;
+ u8 in_explicit_contract;
/* workaround flag */
u32 wa_flags;
diff --git a/drivers/usb/pd/pd_engine.c b/drivers/usb/pd/pd_engine.c
index 2ce347e..c0c87cb 100644
--- a/drivers/usb/pd/pd_engine.c
+++ b/drivers/usb/pd/pd_engine.c
@@ -116,6 +116,7 @@
bool apsd_done;
bool wireless_online;
+ bool in_explicit_contract;
};
/*
@@ -1428,6 +1429,37 @@
return ret;
}
+static int tcpm_in_pd_contract(struct tcpc_dev *dev,
+ bool status)
+{
+ union power_supply_propval val = {0};
+ struct usbpd *pd = container_of(dev, struct usbpd, tcpc_dev);
+ int ret = 0;
+
+ mutex_lock(&pd->lock);
+
+ if (status == pd->in_explicit_contract)
+ goto unlock;
+
+ /* Attempt once */
+ val.intval = status ? 1 : 0;
+ pd_engine_log(pd, "pd contract %d", status ? 1 : 0);
+ ret = power_supply_set_property(pd->usb_psy,
+ POWER_SUPPLY_PROP_PD_IN_EXPLICIT_CONTRACT,
+ &val);
+ if (ret < 0) {
+ pd_engine_log(pd,
+ "unable to set pd contract to %d, ret=%d",
+ status ? 1 : 0, ret);
+ } else {
+ pd->in_explicit_contract = status;
+ }
+
+unlock:
+ mutex_unlock(&pd->lock);
+ return ret;
+}
+
static int tcpm_set_suspend_supported(struct tcpc_dev *dev,
bool suspend_supported)
{
@@ -1971,6 +2003,7 @@
pd_tcpc_dev->set_in_hard_reset = set_in_hard_reset;
pd_tcpc_dev->log_rtc = log_rtc;
pd_tcpc_dev->set_suspend_supported = tcpm_set_suspend_supported;
+ pd_tcpc_dev->in_pd_contract = tcpm_in_pd_contract;
pd_tcpc_dev->mux = NULL;
return 0;
}
diff --git a/drivers/usb/typec/tcpm.c b/drivers/usb/typec/tcpm.c
index 622ed63..c73c1b2 100644
--- a/drivers/usb/typec/tcpm.c
+++ b/drivers/usb/typec/tcpm.c
@@ -2173,12 +2173,21 @@
memset(modep, 0, sizeof(*modep));
}
+static void update_pd_contract_status(struct tcpm_port *port,
+ bool in_explicit_contract)
+{
+ if (port->tcpc->in_pd_contract)
+ port->tcpc->in_pd_contract(port->tcpc, in_explicit_contract);
+}
+
+
static void tcpm_reset_port(struct tcpm_port *port)
{
tcpm_unregister_altmodes(port);
tcpm_typec_disconnect(port);
port->attached = false;
tcpm_set_pd_capable(port, false);
+ update_pd_contract_status(port, false);
port->usb_comm_capable = false;
/*
@@ -2472,6 +2481,7 @@
/* port->hard_reset_count = 0; */
port->caps_count = 0;
tcpm_set_pd_capable(port, true);
+ update_pd_contract_status(port, false);
tcpm_set_state_cond(port, hard_reset_state(port),
PD_T_SEND_SOURCE_CAP);
}
@@ -2518,6 +2528,9 @@
== TYPEC_CC_RP_DEF)
tcpm_set_cc(port, TYPEC_CC_RP_1_5);
tcpm_check_send_discover(port);
+ update_pd_contract_status(port, port->pd_capable
+ ? true : false);
+
/*
* 6.3.5
* Sending ping messages is not necessary if
@@ -2691,6 +2704,8 @@
break;
case SNK_NEGOTIATE_CAPABILITIES:
tcpm_set_pd_capable(port, true);
+ update_pd_contract_status(port, false);
+
port->usb_comm_capable = port->source_caps[0] &
PDO_FIXED_USB_COMM;
/* Notify TCPC of usb_comm_capable. */
@@ -2730,6 +2745,8 @@
tcpm_swap_complete(port, 0);
tcpm_typec_connect(port);
tcpm_check_send_discover(port);
+ update_pd_contract_status(port, port->pd_capable
+ ? true : false);
break;
/* Accessory states */
@@ -2754,6 +2771,7 @@
break;
case HARD_RESET_START:
tcpm_port_in_hard_reset(port, true);
+ update_pd_contract_status(port, false);
port->hard_reset_count++;
port->tcpc->set_pd_rx(port->tcpc, false);
tcpm_unregister_altmodes(port);
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index f2cba44..d7d0188 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -606,9 +606,6 @@
ctx->bio = bio;
ctx->enabled_steps = post_read_steps;
bio->bi_private = ctx;
-
- /* wait the page to be moved by cleaning */
- f2fs_wait_on_block_writeback(sbi, blkaddr);
}
return bio;
@@ -626,6 +623,9 @@
if (f2fs_may_encrypt_bio(inode, NULL))
fscrypt_set_ice_dun(inode, bio, PG_DUN(inode, page));
+ /* wait for GCed page writeback via META_MAPPING */
+ f2fs_wait_on_block_writeback(inode, blkaddr);
+
if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) {
bio_put(bio);
return -EFAULT;
@@ -1587,6 +1587,12 @@
fscrypt_set_ice_dun(inode, bio, dun);
}
+ /*
+ * If the page is under writeback, we need to wait for
+ * its completion to see the correct decrypted data.
+ */
+ f2fs_wait_on_block_writeback(inode, block_nr);
+
if (bio_add_page(bio, page, blocksize, 0) < blocksize)
goto submit_and_realloc;
@@ -1653,7 +1659,7 @@
return 0;
/* wait for GCed page writeback via META_MAPPING */
- f2fs_wait_on_block_writeback(fio->sbi, fio->old_blkaddr);
+ f2fs_wait_on_block_writeback(inode, fio->old_blkaddr);
retry_encrypt:
if (fscrypt_using_hardware_encryption(inode))
@@ -2382,10 +2388,6 @@
f2fs_wait_on_page_writeback(page, DATA, false);
- /* wait for GCed page writeback via META_MAPPING */
- if (f2fs_post_read_required(inode))
- f2fs_wait_on_block_writeback(sbi, blkaddr);
-
if (len == PAGE_SIZE || PageUptodate(page))
return 0;
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index dc89bae06..702aa18 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -2839,7 +2839,7 @@
struct f2fs_io_info *fio, bool add_list);
void f2fs_wait_on_page_writeback(struct page *page,
enum page_type type, bool ordered);
-void f2fs_wait_on_block_writeback(struct f2fs_sb_info *sbi, block_t blkaddr);
+void f2fs_wait_on_block_writeback(struct inode *inode, block_t blkaddr);
void write_data_summaries(struct f2fs_sb_info *sbi, block_t start_blk);
void write_node_summaries(struct f2fs_sb_info *sbi, block_t start_blk);
int lookup_journal_in_cursum(struct f2fs_journal *journal, int type,
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 5a39adf..e62fb40 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -113,8 +113,7 @@
f2fs_wait_on_page_writeback(page, DATA, false);
/* wait for GCed page writeback via META_MAPPING */
- if (f2fs_post_read_required(inode))
- f2fs_wait_on_block_writeback(sbi, dn.data_blkaddr);
+ f2fs_wait_on_block_writeback(inode, dn.data_blkaddr);
out_sem:
up_read(&F2FS_I(inode)->i_mmap_sem);
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index 4fa2efa..5062c02 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -2946,10 +2946,14 @@
}
}
-void f2fs_wait_on_block_writeback(struct f2fs_sb_info *sbi, block_t blkaddr)
+void f2fs_wait_on_block_writeback(struct inode *inode, block_t blkaddr)
{
+ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
struct page *cpage;
+ if (!f2fs_post_read_required(inode))
+ return;
+
if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR)
return;
diff --git a/fs/sdcardfs/file.c b/fs/sdcardfs/file.c
index 1461254..271c4c4 100644
--- a/fs/sdcardfs/file.c
+++ b/fs/sdcardfs/file.c
@@ -118,7 +118,11 @@
goto out;
/* save current_cred and override it */
- OVERRIDE_CRED(sbi, saved_cred, SDCARDFS_I(file_inode(file)));
+ saved_cred = override_fsids(sbi, SDCARDFS_I(file_inode(file))->data);
+ if (!saved_cred) {
+ err = -ENOMEM;
+ goto out;
+ }
if (lower_file->f_op->unlocked_ioctl)
err = lower_file->f_op->unlocked_ioctl(lower_file, cmd, arg);
@@ -127,7 +131,7 @@
if (!err)
sdcardfs_copy_and_fix_attrs(file_inode(file),
file_inode(lower_file));
- REVERT_CRED(saved_cred);
+ revert_fsids(saved_cred);
out:
return err;
}
@@ -149,12 +153,16 @@
goto out;
/* save current_cred and override it */
- OVERRIDE_CRED(sbi, saved_cred, SDCARDFS_I(file_inode(file)));
+ saved_cred = override_fsids(sbi, SDCARDFS_I(file_inode(file))->data);
+ if (!saved_cred) {
+ err = -ENOMEM;
+ goto out;
+ }
if (lower_file->f_op->compat_ioctl)
err = lower_file->f_op->compat_ioctl(lower_file, cmd, arg);
- REVERT_CRED(saved_cred);
+ revert_fsids(saved_cred);
out:
return err;
}
@@ -241,7 +249,11 @@
}
/* save current_cred and override it */
- OVERRIDE_CRED(sbi, saved_cred, SDCARDFS_I(inode));
+ saved_cred = override_fsids(sbi, SDCARDFS_I(inode)->data);
+ if (!saved_cred) {
+ err = -ENOMEM;
+ goto out_err;
+ }
file->private_data =
kzalloc(sizeof(struct sdcardfs_file_info), GFP_KERNEL);
@@ -271,7 +283,7 @@
sdcardfs_copy_and_fix_attrs(inode, sdcardfs_lower_inode(inode));
out_revert_cred:
- REVERT_CRED(saved_cred);
+ revert_fsids(saved_cred);
out_err:
dput(parent);
return err;
diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c
index fafc09c4..de34561 100644
--- a/fs/sdcardfs/inode.c
+++ b/fs/sdcardfs/inode.c
@@ -22,7 +22,6 @@
#include <linux/fs_struct.h>
#include <linux/ratelimit.h>
-/* Do not directly use this function. Use OVERRIDE_CRED() instead. */
const struct cred *override_fsids(struct sdcardfs_sb_info *sbi,
struct sdcardfs_inode_data *data)
{
@@ -50,7 +49,6 @@
return old_cred;
}
-/* Do not directly use this function, use REVERT_CRED() instead. */
void revert_fsids(const struct cred *old_cred)
{
const struct cred *cur_cred;
@@ -78,7 +76,10 @@
}
/* save current_cred and override it */
- OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir));
+ saved_cred = override_fsids(SDCARDFS_SB(dir->i_sb),
+ SDCARDFS_I(dir)->data);
+ if (!saved_cred)
+ return -ENOMEM;
sdcardfs_get_lower_path(dentry, &lower_path);
lower_dentry = lower_path.dentry;
@@ -95,8 +96,11 @@
err = -ENOMEM;
goto out_unlock;
}
+ copied_fs->umask = 0;
+ task_lock(current);
current->fs = copied_fs;
- current->fs->umask = 0;
+ task_unlock(current);
+
err = vfs_create2(lower_dentry_mnt, d_inode(lower_parent_dentry), lower_dentry, mode, want_excl);
if (err)
goto out;
@@ -110,58 +114,18 @@
fixup_lower_ownership(dentry, dentry->d_name.name);
out:
+ task_lock(current);
current->fs = saved_fs;
+ task_unlock(current);
free_fs_struct(copied_fs);
out_unlock:
unlock_dir(lower_parent_dentry);
sdcardfs_put_lower_path(dentry, &lower_path);
- REVERT_CRED(saved_cred);
+ revert_fsids(saved_cred);
out_eacces:
return err;
}
-#if 0
-static int sdcardfs_link(struct dentry *old_dentry, struct inode *dir,
- struct dentry *new_dentry)
-{
- struct dentry *lower_old_dentry;
- struct dentry *lower_new_dentry;
- struct dentry *lower_dir_dentry;
- u64 file_size_save;
- int err;
- struct path lower_old_path, lower_new_path;
-
- OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb));
-
- file_size_save = i_size_read(d_inode(old_dentry));
- sdcardfs_get_lower_path(old_dentry, &lower_old_path);
- sdcardfs_get_lower_path(new_dentry, &lower_new_path);
- lower_old_dentry = lower_old_path.dentry;
- lower_new_dentry = lower_new_path.dentry;
- lower_dir_dentry = lock_parent(lower_new_dentry);
-
- err = vfs_link(lower_old_dentry, d_inode(lower_dir_dentry),
- lower_new_dentry, NULL);
- if (err || !d_inode(lower_new_dentry))
- goto out;
-
- err = sdcardfs_interpose(new_dentry, dir->i_sb, &lower_new_path);
- if (err)
- goto out;
- fsstack_copy_attr_times(dir, d_inode(lower_new_dentry));
- fsstack_copy_inode_size(dir, d_inode(lower_new_dentry));
- set_nlink(d_inode(old_dentry),
- sdcardfs_lower_inode(d_inode(old_dentry))->i_nlink);
- i_size_write(d_inode(new_dentry), file_size_save);
-out:
- unlock_dir(lower_dir_dentry);
- sdcardfs_put_lower_path(old_dentry, &lower_old_path);
- sdcardfs_put_lower_path(new_dentry, &lower_new_path);
- REVERT_CRED();
- return err;
-}
-#endif
-
static int sdcardfs_unlink(struct inode *dir, struct dentry *dentry)
{
int err;
@@ -178,7 +142,10 @@
}
/* save current_cred and override it */
- OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir));
+ saved_cred = override_fsids(SDCARDFS_SB(dir->i_sb),
+ SDCARDFS_I(dir)->data);
+ if (!saved_cred)
+ return -ENOMEM;
sdcardfs_get_lower_path(dentry, &lower_path);
lower_dentry = lower_path.dentry;
@@ -209,43 +176,11 @@
unlock_dir(lower_dir_dentry);
dput(lower_dentry);
sdcardfs_put_lower_path(dentry, &lower_path);
- REVERT_CRED(saved_cred);
+ revert_fsids(saved_cred);
out_eacces:
return err;
}
-#if 0
-static int sdcardfs_symlink(struct inode *dir, struct dentry *dentry,
- const char *symname)
-{
- int err;
- struct dentry *lower_dentry;
- struct dentry *lower_parent_dentry = NULL;
- struct path lower_path;
-
- OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb));
-
- sdcardfs_get_lower_path(dentry, &lower_path);
- lower_dentry = lower_path.dentry;
- lower_parent_dentry = lock_parent(lower_dentry);
-
- err = vfs_symlink(d_inode(lower_parent_dentry), lower_dentry, symname);
- if (err)
- goto out;
- err = sdcardfs_interpose(dentry, dir->i_sb, &lower_path);
- if (err)
- goto out;
- fsstack_copy_attr_times(dir, sdcardfs_lower_inode(dir));
- fsstack_copy_inode_size(dir, d_inode(lower_parent_dentry));
-
-out:
- unlock_dir(lower_parent_dentry);
- sdcardfs_put_lower_path(dentry, &lower_path);
- REVERT_CRED();
- return err;
-}
-#endif
-
static int touch(char *abs_path, mode_t mode)
{
struct file *filp = filp_open(abs_path, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, mode);
@@ -286,7 +221,10 @@
}
/* save current_cred and override it */
- OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir));
+ saved_cred = override_fsids(SDCARDFS_SB(dir->i_sb),
+ SDCARDFS_I(dir)->data);
+ if (!saved_cred)
+ return -ENOMEM;
/* check disk space */
if (!check_min_free_space(dentry, 0, 1)) {
@@ -312,8 +250,11 @@
unlock_dir(lower_parent_dentry);
goto out_unlock;
}
+ copied_fs->umask = 0;
+ task_lock(current);
current->fs = copied_fs;
- current->fs->umask = 0;
+ task_unlock(current);
+
err = vfs_mkdir2(lower_mnt, d_inode(lower_parent_dentry), lower_dentry, mode);
if (err) {
@@ -362,23 +303,34 @@
if (make_nomedia_in_obb ||
((pd->perm == PERM_ANDROID)
&& (qstr_case_eq(&dentry->d_name, &q_data)))) {
- REVERT_CRED(saved_cred);
- OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(d_inode(dentry)));
+ revert_fsids(saved_cred);
+ saved_cred = override_fsids(sbi,
+ SDCARDFS_I(d_inode(dentry))->data);
+ if (!saved_cred) {
+ pr_err("sdcardfs: failed to set up .nomedia in %s: %d\n",
+ lower_path.dentry->d_name.name,
+ -ENOMEM);
+ goto out;
+ }
set_fs_pwd(current->fs, &lower_path);
touch_err = touch(".nomedia", 0664);
if (touch_err) {
pr_err("sdcardfs: failed to create .nomedia in %s: %d\n",
- lower_path.dentry->d_name.name, touch_err);
+ lower_path.dentry->d_name.name,
+ touch_err);
goto out;
}
}
out:
+ task_lock(current);
current->fs = saved_fs;
+ task_unlock(current);
+
free_fs_struct(copied_fs);
out_unlock:
sdcardfs_put_lower_path(dentry, &lower_path);
out_revert:
- REVERT_CRED(saved_cred);
+ revert_fsids(saved_cred);
out_eacces:
return err;
}
@@ -398,7 +350,10 @@
}
/* save current_cred and override it */
- OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir));
+ saved_cred = override_fsids(SDCARDFS_SB(dir->i_sb),
+ SDCARDFS_I(dir)->data);
+ if (!saved_cred)
+ return -ENOMEM;
/* sdcardfs_get_real_lower(): in case of remove an user's obb dentry
* the dentry on the original path should be deleted.
@@ -423,44 +378,11 @@
out:
unlock_dir(lower_dir_dentry);
sdcardfs_put_real_lower(dentry, &lower_path);
- REVERT_CRED(saved_cred);
+ revert_fsids(saved_cred);
out_eacces:
return err;
}
-#if 0
-static int sdcardfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
- dev_t dev)
-{
- int err;
- struct dentry *lower_dentry;
- struct dentry *lower_parent_dentry = NULL;
- struct path lower_path;
-
- OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb));
-
- sdcardfs_get_lower_path(dentry, &lower_path);
- lower_dentry = lower_path.dentry;
- lower_parent_dentry = lock_parent(lower_dentry);
-
- err = vfs_mknod(d_inode(lower_parent_dentry), lower_dentry, mode, dev);
- if (err)
- goto out;
-
- err = sdcardfs_interpose(dentry, dir->i_sb, &lower_path);
- if (err)
- goto out;
- fsstack_copy_attr_times(dir, sdcardfs_lower_inode(dir));
- fsstack_copy_inode_size(dir, d_inode(lower_parent_dentry));
-
-out:
- unlock_dir(lower_parent_dentry);
- sdcardfs_put_lower_path(dentry, &lower_path);
- REVERT_CRED();
- return err;
-}
-#endif
-
/*
* The locking rules in sdcardfs_rename are complex. We could use a simpler
* superblock-level name-space lock for renames and copy-ups.
@@ -489,7 +411,10 @@
}
/* save current_cred and override it */
- OVERRIDE_CRED(SDCARDFS_SB(old_dir->i_sb), saved_cred, SDCARDFS_I(new_dir));
+ saved_cred = override_fsids(SDCARDFS_SB(old_dir->i_sb),
+ SDCARDFS_I(new_dir)->data);
+ if (!saved_cred)
+ return -ENOMEM;
sdcardfs_get_real_lower(old_dentry, &lower_old_path);
sdcardfs_get_lower_path(new_dentry, &lower_new_path);
@@ -536,7 +461,7 @@
dput(lower_new_dir_dentry);
sdcardfs_put_real_lower(old_dentry, &lower_old_path);
sdcardfs_put_lower_path(new_dentry, &lower_new_path);
- REVERT_CRED(saved_cred);
+ revert_fsids(saved_cred);
out_eacces:
return err;
}
@@ -655,33 +580,7 @@
if (IS_POSIXACL(inode))
pr_warn("%s: This may be undefined behavior...\n", __func__);
err = generic_permission(&tmp, mask);
- /* XXX
- * Original sdcardfs code calls inode_permission(lower_inode,.. )
- * for checking inode permission. But doing such things here seems
- * duplicated work, because the functions called after this func,
- * such as vfs_create, vfs_unlink, vfs_rename, and etc,
- * does exactly same thing, i.e., they calls inode_permission().
- * So we just let they do the things.
- * If there are any security hole, just uncomment following if block.
- */
-#if 0
- if (!err) {
- /*
- * Permission check on lower_inode(=EXT4).
- * we check it with AID_MEDIA_RW permission
- */
- struct inode *lower_inode;
-
- OVERRIDE_CRED(SDCARDFS_SB(inode->sb));
-
- lower_inode = sdcardfs_lower_inode(inode);
- err = inode_permission(lower_inode, mask);
-
- REVERT_CRED();
- }
-#endif
return err;
-
}
static int sdcardfs_setattr_wrn(struct dentry *dentry, struct iattr *ia)
@@ -759,7 +658,10 @@
goto out_err;
/* save current_cred and override it */
- OVERRIDE_CRED(SDCARDFS_SB(dentry->d_sb), saved_cred, SDCARDFS_I(inode));
+ saved_cred = override_fsids(SDCARDFS_SB(dentry->d_sb),
+ SDCARDFS_I(inode)->data);
+ if (!saved_cred)
+ return -ENOMEM;
sdcardfs_get_lower_path(dentry, &lower_path);
lower_dentry = lower_path.dentry;
@@ -818,7 +720,7 @@
out:
sdcardfs_put_lower_path(dentry, &lower_path);
- REVERT_CRED(saved_cred);
+ revert_fsids(saved_cred);
out_err:
return err;
}
@@ -901,13 +803,6 @@
.setattr = sdcardfs_setattr_wrn,
.setattr2 = sdcardfs_setattr,
.getattr = sdcardfs_getattr,
- /* XXX Following operations are implemented,
- * but FUSE(sdcard) or FAT does not support them
- * These methods are *NOT* perfectly tested.
- .symlink = sdcardfs_symlink,
- .link = sdcardfs_link,
- .mknod = sdcardfs_mknod,
- */
};
const struct inode_operations sdcardfs_main_iops = {
diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c
index 8a4b054..a6e6615 100644
--- a/fs/sdcardfs/lookup.c
+++ b/fs/sdcardfs/lookup.c
@@ -437,7 +437,12 @@
}
/* save current_cred and override it */
- OVERRIDE_CRED_PTR(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir));
+ saved_cred = override_fsids(SDCARDFS_SB(dir->i_sb),
+ SDCARDFS_I(dir)->data);
+ if (!saved_cred) {
+ ret = ERR_PTR(-ENOMEM);
+ goto out_err;
+ }
sdcardfs_get_lower_path(parent, &lower_parent_path);
@@ -468,7 +473,7 @@
out:
sdcardfs_put_lower_path(parent, &lower_parent_path);
- REVERT_CRED(saved_cred);
+ revert_fsids(saved_cred);
out_err:
dput(parent);
return ret;
diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h
index 826afb5..ec2290a 100644
--- a/fs/sdcardfs/sdcardfs.h
+++ b/fs/sdcardfs/sdcardfs.h
@@ -88,31 +88,6 @@
(x)->i_mode = ((x)->i_mode & S_IFMT) | 0775;\
} while (0)
-/* OVERRIDE_CRED() and REVERT_CRED()
- * OVERRIDE_CRED()
- * backup original task->cred
- * and modifies task->cred->fsuid/fsgid to specified value.
- * REVERT_CRED()
- * restore original task->cred->fsuid/fsgid.
- * These two macro should be used in pair, and OVERRIDE_CRED() should be
- * placed at the beginning of a function, right after variable declaration.
- */
-#define OVERRIDE_CRED(sdcardfs_sbi, saved_cred, info) \
- do { \
- saved_cred = override_fsids(sdcardfs_sbi, info->data); \
- if (!saved_cred) \
- return -ENOMEM; \
- } while (0)
-
-#define OVERRIDE_CRED_PTR(sdcardfs_sbi, saved_cred, info) \
- do { \
- saved_cred = override_fsids(sdcardfs_sbi, info->data); \
- if (!saved_cred) \
- return ERR_PTR(-ENOMEM); \
- } while (0)
-
-#define REVERT_CRED(saved_cred) revert_fsids(saved_cred)
-
/* Android 5.0 support */
/* Permission mode for a specific node. Controls how file permissions
diff --git a/include/linux/input/qpnp-power-on.h b/include/linux/input/qpnp-power-on.h
index ab5de0a..ce3f0c7 100644
--- a/include/linux/input/qpnp-power-on.h
+++ b/include/linux/input/qpnp-power-on.h
@@ -65,6 +65,7 @@
/* 32 ~ 63 for OEMs/ODMs secific features */
PON_RESTART_REASON_OEM_MIN = 0x20,
+ PON_RESTART_REASON_OEM_PACKOUT = 0x21,
PON_RESTART_REASON_OEM_MAX = 0x3f,
};
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 329a5b5..30f8f08 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -295,6 +295,7 @@
POWER_SUPPLY_PROP_ENABLE_JEITA_DETECTION,
POWER_SUPPLY_PROP_OTG_FASTROLESWAP,
POWER_SUPPLY_PROP_CHARGE_DISABLE,
+ POWER_SUPPLY_PROP_PD_IN_EXPLICIT_CONTRACT,
/* Local extensions of type int64_t */
POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT,
/* Properties of type `const char *' */
diff --git a/include/linux/usb/tcpm.h b/include/linux/usb/tcpm.h
index c95b4c2..ae00429 100644
--- a/include/linux/usb/tcpm.h
+++ b/include/linux/usb/tcpm.h
@@ -157,6 +157,8 @@
* detected.
* @set_in_hard_reset:
* Optional; Called to notify that hard reset is in progress.
+ * @in_pd_contract:
+ * Optional; Called to notify is when pd contract is established.
* @mux: Pointer to multiplexer data
*/
struct tcpc_dev {
@@ -189,6 +191,7 @@
void (*log_rtc)(struct tcpc_dev *dev);
int (*set_suspend_supported)(struct tcpc_dev *dev,
bool suspend_supported);
+ int (*in_pd_contract)(struct tcpc_dev *dev, bool status);
struct tcpc_mux_dev *mux;
};
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 427e33d..5659b40 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -1511,8 +1511,20 @@
ts->tv_nsec = 0;
}
-/* Flag for if timekeeping_resume() has injected sleeptime */
-static bool sleeptime_injected;
+/*
+ * Flag reflecting whether timekeeping_resume() has injected sleeptime.
+ *
+ * The flag starts of false and is only set when a suspend reaches
+ * timekeeping_suspend(), timekeeping_resume() sets it to false when the
+ * timekeeper clocksource is not stopping across suspend and has been
+ * used to update sleep time. If the timekeeper clocksource has stopped
+ * then the flag stays true and is used by the RTC resume code to decide
+ * whether sleeptime must be injected and if so the flag gets false then.
+ *
+ * If a suspend fails before reaching timekeeping_resume() then the flag
+ * stays false and prevents erroneous sleeptime injection.
+ */
+static bool suspend_timing_needed;
/* Flag for if there is a persistent clock on this platform */
static bool persistent_clock_exists;
@@ -1611,7 +1623,7 @@
*/
bool timekeeping_rtc_skipresume(void)
{
- return sleeptime_injected;
+ return !suspend_timing_needed;
}
/**
@@ -1647,6 +1659,8 @@
raw_spin_lock_irqsave(&timekeeper_lock, flags);
write_seqcount_begin(&tk_core.seq);
+ suspend_timing_needed = false;
+
timekeeping_forward_now(tk);
__timekeeping_inject_sleeptime(tk, delta);
@@ -1671,8 +1685,8 @@
unsigned long flags;
struct timespec64 ts_new, ts_delta;
cycle_t cycle_now, cycle_delta;
+ bool inject_sleeptime = false;
- sleeptime_injected = false;
read_persistent_clock64(&ts_new);
clockevents_resume();
@@ -1718,14 +1732,16 @@
nsec += ((u64) cycle_delta * mult) >> shift;
ts_delta = ns_to_timespec64(nsec);
- sleeptime_injected = true;
+ inject_sleeptime = true;
} else if (timespec64_compare(&ts_new, &timekeeping_suspend_time) > 0) {
ts_delta = timespec64_sub(ts_new, timekeeping_suspend_time);
- sleeptime_injected = true;
+ inject_sleeptime = true;
}
- if (sleeptime_injected)
+ if (inject_sleeptime) {
+ suspend_timing_needed = false;
__timekeeping_inject_sleeptime(tk, &ts_delta);
+ }
/* Re-base the last cycle value */
tk->tkr_mono.cycle_last = cycle_now;
@@ -1760,6 +1776,8 @@
if (timekeeping_suspend_time.tv_sec || timekeeping_suspend_time.tv_nsec)
persistent_clock_exists = true;
+ suspend_timing_needed = true;
+
raw_spin_lock_irqsave(&timekeeper_lock, flags);
write_seqcount_begin(&tk_core.seq);
timekeeping_forward_now(tk);