[Feature][T108][task-view-1466][codec] Add codec/PA power hibernation wake up

Only Configure: No
Affected branch:
Affected module: codec
Is it affected on IC: only ASR GSW_V1453
Self-test: yes
Doc Update: no

Change-Id: Iac36f8601f2f1cddbd26946f614a6ef22a576c45
diff --git a/marvell/linux/drivers/mfd/es8311.c b/marvell/linux/drivers/mfd/es8311.c
index e350684..d28a655 100755
--- a/marvell/linux/drivers/mfd/es8311.c
+++ b/marvell/linux/drivers/mfd/es8311.c
@@ -128,6 +128,9 @@
 //#define ES8311_DEBUG
 //#define ES8311_DEBUG_CLOSE
 
+#define CONFIG_CODEC_VDDD_EN 1
+static int gpio_codec_vddd_en = -1;
+
 #define es8311_reg_NUM 0xFF
 /* base functions */
 
@@ -3077,6 +3080,24 @@
         return 0;
     }
 
+#ifdef CONFIG_CODEC_VDDD_EN
+    /* Get CODEC_VDDD_EN GPIO from device tree */
+    gpio_codec_vddd_en = of_get_gpio(g_es8311_node, 0);
+    printk(KERN_INFO"es8311_probe: gpio_codec_vddd_en=%d\n", gpio_codec_vddd_en);
+
+    /* CODEC_VDDD_EN GPIO control from device tree */
+    if (gpio_codec_vddd_en >= 0) {
+        if (gpio_request(gpio_codec_vddd_en, "codec_vddd_en") == 0) {
+            gpio_direction_output(gpio_codec_vddd_en, 1);
+            printk(KERN_EMERG "0624 GPIO%d CODEC_VDDD_EN set to high (from DTS)\n", gpio_codec_vddd_en);
+        } else {
+            printk(KERN_EMERG "GPIO%d request failed\n", gpio_codec_vddd_en);
+        }
+    } else {
+        printk(KERN_EMERG "CODEC_VDDD_EN GPIO not configured in device tree\n");
+    }
+#endif
+
     es8311_dump_debugfs_init(NULL);
 
    // es8311_audio_debugfs_init(NULL);
@@ -3194,6 +3215,13 @@
     /* Power off for ASR1901 kestrel */
     audio_set_codec_vdd(0);
 
+#ifdef CONFIG_CODEC_VDDD_EN
+    if (gpio_is_valid(gpio_codec_vddd_en)) {
+        gpio_free(gpio_codec_vddd_en);
+        printk(KERN_INFO "es8311: Released gpio_codec_vddd_en\n");
+    }
+#endif
+
 #ifdef HEADSET_DETECTION
     gpio_free(gpio_CODEC_IRQ);
     free_irq(irq_codec, g_es8311_client);
@@ -3219,10 +3247,54 @@
     return;
 }
 
+static int es8311_i2c_suspend(struct device *dev)
+{
+    printk(KERN_INFO "es8311: Entering suspend\n");
+
+#ifdef CONFIG_CODEC_VDDD_EN
+    if (gpio_is_valid(gpio_codec_vddd_en)) {
+        gpio_direction_output(gpio_codec_vddd_en, 0);
+        printk(KERN_INFO "es8311: codec_vddd_en set to input (low) for suspend\n");
+    }
+#endif
+
+    audio_set_codec_vdd(0);
+
+    return 0;
+}
+
+static int es8311_i2c_resume(struct device *dev)
+{
+    int ret = 0;
+    struct i2c_client *client = to_i2c_client(dev);
+
+    printk(KERN_INFO "es8311: Exiting suspend\n");
+
+#ifdef CONFIG_CODEC_VDDD_EN
+    if (gpio_is_valid(gpio_codec_vddd_en)) {
+        ret = gpio_direction_output(gpio_codec_vddd_en, 1);
+        if (ret) {
+            printk(KERN_ERR "es8311: Failed to set gpio_codec_vddd_en to output high: %d\n", ret);
+        } else {
+            printk(KERN_INFO "es8311: codec_vddd_en set to output high for resume\n");
+        }
+    }
+#endif
+
+    audio_set_codec_vdd(1);
+
+    return ret;
+}
+
+static const struct dev_pm_ops es8311_dev_pm_ops = {
+    SET_SYSTEM_SLEEP_PM_OPS(es8311_i2c_suspend, es8311_i2c_resume)
+};
+
 static struct i2c_driver es8311_driver = {
     .driver = {
         .name = "es8311",
         .of_match_table	= of_match_ptr(es8311_dt_ids),
+        .pm = &es8311_dev_pm_ops,
     },
     .probe = es8311_probe,
     .remove = es8311_remove,