staging: gasket: apex: restore thermal control registers

After host suspend/resume operation device is power cycled and
loses all custom register settings.
All settings are restored on first device open except thermal
monitoring related settings.

Signed-off-by: Leonid Lobachev <leonidl@google.com>
Change-Id: I3a7c69efd919da0992c585874d7fe906a7768ee7
diff --git a/drivers/staging/gasket/apex_driver.c b/drivers/staging/gasket/apex_driver.c
index 144da27..c0d9d00 100644
--- a/drivers/staging/gasket/apex_driver.c
+++ b/drivers/staging/gasket/apex_driver.c
@@ -73,6 +73,10 @@ struct apex_dev {
 	struct delayed_work check_temperature_work;
 	u32 adc_trip_points[3];
 	atomic_t temp_poll_interval;
+	u32 hw_temp_warn1_adc;
+	u32 hw_temp_warn2_adc;
+	bool hw_temp_warn1_en;
+	bool hw_temp_warn2_en;
 };
 
 /* Enumeration of the supported sysfs entries. */
@@ -685,26 +689,20 @@ static ssize_t sysfs_show(struct device *device, struct device_attribute *attr,
 		ret = scnprintf(buf, PAGE_SIZE, "%i\n", adc_to_millic(value));
 		break;
 	case ATTR_TEMP_WARN1:
-		value = gasket_dev_read_32(gasket_dev, APEX_BAR_INDEX,
-					   APEX_BAR2_REG_OMC0_D4);
-		value = (value >> 16) & ((1 << 10) - 1);
-		ret = scnprintf(buf, PAGE_SIZE, "%i\n", adc_to_millic(value));
+		ret = scnprintf(buf, PAGE_SIZE, "%i\n",
+				adc_to_millic(apex_dev->hw_temp_warn1_adc));
 		break;
 	case ATTR_TEMP_WARN2:
-		value = gasket_dev_read_32(gasket_dev, APEX_BAR_INDEX,
-					   APEX_BAR2_REG_OMC0_D8);
-		value = (value >> 16) & ((1 << 10) - 1);
-		ret = scnprintf(buf, PAGE_SIZE, "%i\n", adc_to_millic(value));
+		ret = scnprintf(buf, PAGE_SIZE, "%i\n",
+				adc_to_millic(apex_dev->hw_temp_warn2_adc));
 		break;
 	case ATTR_TEMP_WARN1_EN:
-		value = gasket_dev_read_32(gasket_dev, APEX_BAR_INDEX,
-					   APEX_BAR2_REG_OMC0_D4);
-		ret = scnprintf(buf, PAGE_SIZE, "%i\n", value >> 31);
+		ret = scnprintf(buf, PAGE_SIZE, "%i\n",
+				apex_dev->hw_temp_warn1_en);
 		break;
 	case ATTR_TEMP_WARN2_EN:
-		value = gasket_dev_read_32(gasket_dev, APEX_BAR_INDEX,
-					   APEX_BAR2_REG_OMC0_D8);
-		ret = scnprintf(buf, PAGE_SIZE, "%i\n", value >> 31);
+		ret = scnprintf(buf, PAGE_SIZE, "%i\n",
+				apex_dev->hw_temp_warn2_en);
 		break;
 	case ATTR_TEMP_TRIP0:
 		ret = scnprintf(buf, PAGE_SIZE, "%i\n",
@@ -774,24 +772,28 @@ static ssize_t sysfs_store(struct device *device, struct device_attribute *attr,
 		gasket_read_modify_write_32(gasket_dev, APEX_BAR_INDEX,
 					    APEX_BAR2_REG_OMC0_D4, value, 10,
 					    16);
+		apex_dev->hw_temp_warn1_adc = value;
 		break;
 	case ATTR_TEMP_WARN2:
 		value = millic_to_adc(value);
 		gasket_read_modify_write_32(gasket_dev, APEX_BAR_INDEX,
 					    APEX_BAR2_REG_OMC0_D8, value, 10,
 					    16);
+		apex_dev->hw_temp_warn2_adc = value;
 		break;
 	case ATTR_TEMP_WARN1_EN:
 		value = value > 0 ? 1 : 0;
 		gasket_read_modify_write_32(gasket_dev, APEX_BAR_INDEX,
 					    APEX_BAR2_REG_OMC0_D4, value, 1,
 					    31);
+		apex_dev->hw_temp_warn1_en = !!value;
 		break;
 	case ATTR_TEMP_WARN2_EN:
 		value = value > 0 ? 1 : 0;
 		gasket_read_modify_write_32(gasket_dev, APEX_BAR_INDEX,
 					    APEX_BAR2_REG_OMC0_D8, value, 1,
 					    31);
+		apex_dev->hw_temp_warn2_en = !!value;
 		break;
 	case ATTR_TEMP_TRIP0:
 		value = millic_to_adc(value);
@@ -860,6 +862,7 @@ static struct gasket_sysfs_attribute apex_sysfs_attrs[] = {
 	GASKET_END_OF_ATTR_ARRAY
 };
 
+/* Stores kernel module parameters to device specific data buffer */
 static void apply_module_params(struct apex_dev *apex_dev) {
 	kernel_param_lock(THIS_MODULE);
 
@@ -879,23 +882,47 @@ static void apply_module_params(struct apex_dev *apex_dev) {
 	apex_dev->adc_trip_points[2] = millic_to_adc(trip_point2_temp);
 	atomic_set(&apex_dev->temp_poll_interval, temp_poll_interval);
 
+	apex_dev->hw_temp_warn1_adc = millic_to_adc(hw_temp_warn1);
+	apex_dev->hw_temp_warn2_adc = millic_to_adc(hw_temp_warn2);
+	apex_dev->hw_temp_warn1_en = hw_temp_warn1_en;
+	apex_dev->hw_temp_warn2_en = hw_temp_warn2_en;
+
+	kernel_param_unlock(THIS_MODULE);
+}
+
+/* Applies hw temp warning settings to device */
+static void program_hw_temp_warnings(struct apex_dev *apex_dev) {
 	gasket_read_modify_write_32(apex_dev->gasket_dev_ptr, APEX_BAR_INDEX,
 				    APEX_BAR2_REG_OMC0_D4,
-				    millic_to_adc(hw_temp_warn1), 10, 16);
+				    apex_dev->hw_temp_warn1_adc, 10, 16);
 	gasket_read_modify_write_32(apex_dev->gasket_dev_ptr, APEX_BAR_INDEX,
 				    APEX_BAR2_REG_OMC0_D8,
-				    millic_to_adc(hw_temp_warn2), 10, 16);
-	if (hw_temp_warn1_en)
+				    apex_dev->hw_temp_warn2_adc, 10, 16);
+	if (apex_dev->hw_temp_warn1_en)
 		gasket_read_modify_write_32(apex_dev->gasket_dev_ptr,
 					    APEX_BAR_INDEX,
 					    APEX_BAR2_REG_OMC0_D4, 1, 1, 31);
 
-	if (hw_temp_warn2_en)
+	if (apex_dev->hw_temp_warn2_en)
 		gasket_read_modify_write_32(apex_dev->gasket_dev_ptr,
 					    APEX_BAR_INDEX,
 					    APEX_BAR2_REG_OMC0_D8, 1, 1, 31);
+}
 
-	kernel_param_unlock(THIS_MODULE);
+static void enable_thermal_sensing(struct gasket_dev *gasket_dev) {
+	// Enable thermal sensor clocks
+	gasket_read_modify_write_32(gasket_dev, APEX_BAR_INDEX,
+				    APEX_BAR2_REG_OMC0_D0, 0x1, 1, 7);
+
+	// Enable thermal sensor (ENAD ENVR ENBG)
+	gasket_read_modify_write_32(gasket_dev, APEX_BAR_INDEX,
+				    APEX_BAR2_REG_OMC0_D8, 0x7, 3, 0);
+
+	// Enable OMC thermal sensor controller
+	// This bit should be asserted 100 us after ENAD ENVR ENBG
+	schedule_timeout(usecs_to_jiffies(100));
+	gasket_read_modify_write_32(gasket_dev, APEX_BAR_INDEX,
+				    APEX_BAR2_REG_OMC0_DC, 0x1, 1, 0);
 }
 
 static void check_temperature_work_handler(struct work_struct *work) {
@@ -1002,6 +1029,7 @@ static int apex_pci_probe(struct pci_dev *pci_dev,
 			  check_temperature_work_handler);
 	apex_dev->gasket_dev_ptr = gasket_dev;
 	apply_module_params(apex_dev);
+	program_hw_temp_warnings(apex_dev);
 	pci_set_drvdata(pci_dev, apex_dev);
 	apex_reset(gasket_dev);
 
@@ -1027,19 +1055,7 @@ static int apex_pci_probe(struct pci_dev *pci_dev,
 		goto remove_device;
 	}
 
-	// Enable thermal sensor clocks
-	gasket_read_modify_write_32(gasket_dev, APEX_BAR_INDEX,
-				    APEX_BAR2_REG_OMC0_D0, 0x1, 1, 7);
-
-	// Enable thermal sensor (ENAD ENVR ENBG)
-	gasket_read_modify_write_32(gasket_dev, APEX_BAR_INDEX,
-				    APEX_BAR2_REG_OMC0_D8, 0x7, 3, 0);
-
-	// Enable OMC thermal sensor controller
-	// This bit should be asserted 100 us after ENAD ENVR ENBG
-	schedule_timeout(usecs_to_jiffies(100));
-	gasket_read_modify_write_32(gasket_dev, APEX_BAR_INDEX,
-				    APEX_BAR2_REG_OMC0_DC, 0x1, 1, 0);
+	enable_thermal_sensing(gasket_dev);
 
 	ret = gasket_sysfs_create_entries(gasket_dev->dev_info.device,
 					  apex_sysfs_attrs);
@@ -1090,6 +1106,28 @@ static void apex_pci_remove(struct pci_dev *pci_dev)
 	pci_disable_device(pci_dev);
 }
 
+static int apex_pci_resume(struct pci_dev *pci_dev)
+{
+	struct apex_dev *apex_dev = pci_get_drvdata(pci_dev);
+	struct gasket_dev *gasket_dev;
+
+	if (!apex_dev) {
+		dev_err_once(&pci_dev->dev, "NULL apex_dev\n");
+		return -ENODEV;
+	}
+	gasket_dev = apex_dev->gasket_dev_ptr;
+
+	apex_reset(gasket_dev);
+	program_hw_temp_warnings(apex_dev);
+	enable_thermal_sensing(gasket_dev);
+
+	/* Place device in low power mode until opened */
+	if (allow_power_save)
+		apex_enter_reset(gasket_dev);
+
+	return 0;
+}
+
 static struct gasket_driver_desc apex_desc = {
 	.name = "apex",
 	.driver_version = APEX_DRIVER_VERSION,
@@ -1136,6 +1174,9 @@ static struct pci_driver apex_pci_driver = {
 	.name = "apex",
 	.probe = apex_pci_probe,
 	.remove = apex_pci_remove,
+#ifdef CONFIG_PM_SLEEP
+	.resume = apex_pci_resume,
+#endif
 	.id_table = apex_pci_ids,
 };