Revert "Merge "Revert "ASoC: wcd9310: Fix headset detect..."" into msm-3.0"

This reverts commit 7646faf1a40035956809b4e6c54eb66fc0acc24e, reversing
changes made to 98b77c0f2f46ae9182169051c74c990ea80e5c5d.

Change-Id: Id088ae9d36c3a0084ae49468ad0ff26c3c8fb135
Signed-off-by: Joonwoo Park <joonwoop@codeaurora.org>
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index e636bb7..a2b8797 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -208,7 +208,8 @@
 };
 
 enum tabla_mbhc_plug_type {
-	PLUG_TYPE_NONE = 0,
+	PLUG_TYPE_INVALID = -1,
+	PLUG_TYPE_NONE,
 	PLUG_TYPE_HEADSET,
 	PLUG_TYPE_HEADPHONE,
 	PLUG_TYPE_HIGH_HPH,
@@ -308,11 +309,6 @@
 	 */
 	struct mutex codec_resource_lock;
 
-	/* Used to override the rule "invalid headset
-	 * when microphone voltage is too high"
-	 */
-	bool mbhc_inval_hs_range_override;
-
 #ifdef CONFIG_DEBUG_FS
 	struct dentry *debugfs_poke;
 	struct dentry *debugfs_mbhc;
@@ -2408,14 +2404,17 @@
 					 int vddio_switch, bool restartpolling,
 					 bool checkpolling)
 {
-	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
 	int cfilt_k_val;
+	bool override;
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
 
 	if (vddio_switch && !tabla->mbhc_micbias_switched &&
 	    (!checkpolling || tabla->mbhc_polling_active)) {
 		if (restartpolling)
 			tabla_codec_pause_hs_polling(codec);
-		tabla_turn_onoff_override(codec, true);
+		override = snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x04;
+		if (!override)
+			tabla_turn_onoff_override(codec, true);
 		/* Adjust threshold if Mic Bias voltage changes */
 		if (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
 			cfilt_k_val = tabla_find_k_value(
@@ -2440,7 +2439,8 @@
 				    0x80, 0x80);
 		snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
 				    0x10, 0x00);
-		tabla_turn_onoff_override(codec, false);
+		if (!override)
+			tabla_turn_onoff_override(codec, false);
 		if (restartpolling)
 			tabla_codec_start_hs_polling(codec);
 
@@ -5807,7 +5807,7 @@
 }
 
 static bool tabla_is_invalid_insertion_range(struct snd_soc_codec *codec,
-					     s32 mic_volt)
+					     s32 mic_volt, bool highhph)
 {
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
 	bool invalid = false;
@@ -5817,7 +5817,7 @@
 	 * needs to be considered as invalid
 	 */
 	v_hs_max = tabla_get_current_v_hs_max(tabla);
-	if (!tabla->mbhc_inval_hs_range_override && (mic_volt > v_hs_max))
+	if (!highhph && (mic_volt > v_hs_max))
 		invalid = true;
 	else if (mic_volt < tabla->mbhc_data.v_inval_ins_high &&
 		 (mic_volt > tabla->mbhc_data.v_inval_ins_low))
@@ -5838,40 +5838,6 @@
 	return false;
 }
 
-static bool tabla_codec_is_invalid_plug(struct snd_soc_codec *codec,
-					s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT],
-					enum tabla_mbhc_plug_type
-					    plug_type[MBHC_NUM_DCE_PLUG_DETECT])
-{
-	int i;
-	bool r = false;
-	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
-	struct tabla_mbhc_plug_type_cfg *plug_type_ptr =
-		TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
-	s16 v_hs_max = tabla_get_current_v_hs_max(tabla);
-
-	for (i = 0 ; i < MBHC_NUM_DCE_PLUG_DETECT && !r; i++) {
-		if (mic_mv[i] < plug_type_ptr->v_no_mic)
-			plug_type[i] = PLUG_TYPE_HEADPHONE;
-		else if (mic_mv[i] < v_hs_max)
-			plug_type[i] = PLUG_TYPE_HEADSET;
-		else if (mic_mv[i] > v_hs_max)
-			plug_type[i] = PLUG_TYPE_HIGH_HPH;
-
-		r = tabla_is_invalid_insertion_range(codec, mic_mv[i]);
-		if (!r && i > 0) {
-			if (plug_type[i-1] != plug_type[i])
-				r = true;
-			else
-				r = tabla_is_inval_insert_delta(codec,
-						  mic_mv[i], mic_mv[i - 1],
-						  TABLA_MBHC_FAKE_INS_DELTA_MV);
-		}
-	}
-
-	return r;
-}
-
 /* called under codec_resource_lock acquisition */
 void tabla_find_plug_and_report(struct snd_soc_codec *codec,
 				enum tabla_mbhc_plug_type plug_type)
@@ -5934,15 +5900,127 @@
 		tabla->mbhc_cfg.gpio_level_insert);
 }
 
+/* called under codec_resource_lock acquisition */
+static void tabla_codec_hphr_gnd_switch(struct snd_soc_codec *codec, bool on)
+{
+	snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01, on);
+	if (on)
+		usleep_range(5000, 5000);
+}
+
+/* called under codec_resource_lock acquisition and mbhc override = 1 */
+static enum tabla_mbhc_plug_type
+tabla_codec_get_plug_type(struct snd_soc_codec *codec, bool highhph)
+{
+	int i;
+	bool gndswitch, vddioswitch;
+	int scaled;
+	struct tabla_mbhc_plug_type_cfg *plug_type_ptr;
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+	const bool vddio = (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV);
+	int num_det = (MBHC_NUM_DCE_PLUG_DETECT + vddio);
+	enum tabla_mbhc_plug_type plug_type[num_det];
+	s16 mb_v[num_det];
+	s32 mic_mv[num_det];
+	bool inval = false;
+
+	/* make sure override is on */
+	WARN_ON(!(snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x04));
+
+	/* performs DCEs for N times
+	 * 1st: check if voltage is in invalid range
+	 * 2nd - N-2nd: check voltage range and delta
+	 * N-1st: check voltage range, delta with HPHR GND switch
+	 * Nth: check voltage range with VDDIO switch if micbias V != vddio V*/
+	for (i = 0; i < num_det && !inval; i++) {
+		gndswitch = (i == (num_det - 1 - vddio));
+		vddioswitch = (vddio && (i == num_det - 1));
+		if (i == 0) {
+			mb_v[i] = tabla_codec_setup_hs_polling(codec);
+			mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
+			inval = tabla_is_invalid_insertion_range(codec,
+								 mic_mv[i],
+								 highhph);
+			scaled = mic_mv[i];
+		} else if (vddioswitch) {
+			__tabla_codec_switch_micbias(tabla->codec, 1, false,
+						     false);
+			mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
+			mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
+			scaled = tabla_scale_v_micb_vddio(tabla, mic_mv[i],
+							  false);
+			inval = (tabla_is_invalid_insertion_range(codec,
+								  mic_mv[i],
+								  highhph) ||
+				 tabla_is_inval_insert_delta(codec, scaled,
+					  mic_mv[i - 1],
+					  TABLA_MBHC_FAKE_INS_DELTA_SCALED_MV));
+			__tabla_codec_switch_micbias(tabla->codec, 0, false,
+						     false);
+		} else {
+			if (gndswitch)
+				tabla_codec_hphr_gnd_switch(codec, true);
+			mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
+			mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
+			inval = (tabla_is_invalid_insertion_range(codec,
+								  mic_mv[i],
+								  highhph) ||
+				 tabla_is_inval_insert_delta(codec, mic_mv[i],
+					  mic_mv[i - 1],
+					  TABLA_MBHC_FAKE_INS_DELTA_SCALED_MV));
+			if (gndswitch)
+				tabla_codec_hphr_gnd_switch(codec, false);
+			scaled = mic_mv[i];
+		}
+		pr_debug("%s: DCE #%d, %04x, V %d, scaled V %d, GND %d, "
+			 "invalid %d\n", __func__,
+			 i + 1, mb_v[i] & 0xffff, mic_mv[i], scaled, gndswitch,
+			 inval);
+	}
+
+	plug_type_ptr =
+	    TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
+	plug_type[0] = PLUG_TYPE_INVALID;
+	for (i = 0; !inval && i < num_det; i++) {
+		/*
+		 * If we are here, means none of the all
+		 * measurements are fake, continue plug type detection.
+		 * If all three measurements do not produce same
+		 * plug type, restart insertion detection
+		 */
+		if (mic_mv[i] < plug_type_ptr->v_no_mic) {
+			plug_type[i] = PLUG_TYPE_HEADPHONE;
+			pr_debug("%s: Detect attempt %d, detected Headphone\n",
+				 __func__, i);
+		} else if (highhph && (mic_mv[i] > plug_type_ptr->v_hs_max)) {
+			plug_type[i] = PLUG_TYPE_HIGH_HPH;
+			pr_debug("%s: Detect attempt %d, detected High "
+				 "Headphone\n", __func__, i);
+		} else {
+			plug_type[i] = PLUG_TYPE_HEADSET;
+			pr_debug("%s: Detect attempt %d, detected Headset\n",
+				 __func__, i);
+		}
+
+		if (i > 0 && (plug_type[i - 1] != plug_type[i])) {
+			pr_err("%s: Detect attempt %d and %d are not same",
+			       __func__, i - 1, i);
+			plug_type[0] = PLUG_TYPE_INVALID;
+			inval = true;
+			break;
+		}
+	}
+
+	return plug_type[0];
+}
+
 static void tabla_hs_correct_gpio_plug(struct work_struct *work)
 {
 	struct tabla_priv *tabla;
 	struct snd_soc_codec *codec;
-	int retry = 0, i;
+	int retry = 0;
 	bool correction = false;
-	s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
-	short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
-	enum tabla_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
+	enum tabla_mbhc_plug_type plug_type;
 	unsigned long timeout;
 
 	tabla = container_of(work, struct tabla_priv, hs_correct_plug_work);
@@ -5979,24 +6057,17 @@
 
 		/* can race with removal interrupt */
 		TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
-		for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
-			mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
-			mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
-			pr_debug("%s : DCE run %d, mic_mv = %d(%x)\n",
-				 __func__, retry, mic_mv[i], mb_v[i]);
-		}
+		plug_type = tabla_codec_get_plug_type(codec, true);
 		TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
 
-		if (tabla_codec_is_invalid_plug(codec, mic_mv, plug_type)) {
+		if (plug_type == PLUG_TYPE_INVALID) {
 			pr_debug("Invalid plug in attempt # %d\n", retry);
 			if (retry == NUM_ATTEMPTS_TO_REPORT &&
 			    tabla->current_plug == PLUG_TYPE_NONE) {
 				tabla_codec_report_plug(codec, 1,
 							SND_JACK_HEADPHONE);
 			}
-		} else if (!tabla_codec_is_invalid_plug(codec, mic_mv,
-							plug_type) &&
-			   plug_type[0] == PLUG_TYPE_HEADPHONE) {
+		} else if (plug_type == PLUG_TYPE_HEADPHONE) {
 			pr_debug("Good headphone detected, continue polling mic\n");
 			if (tabla->current_plug == PLUG_TYPE_NONE) {
 				tabla_codec_report_plug(codec, 1,
@@ -6006,10 +6077,10 @@
 			TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
 			/* Turn off override */
 			tabla_turn_onoff_override(codec, false);
-			tabla_find_plug_and_report(codec, plug_type[0]);
+			tabla_find_plug_and_report(codec, plug_type);
 			TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
 			pr_debug("Attempt %d found correct plug %d\n", retry,
-				 plug_type[0]);
+				 plug_type);
 			correction = true;
 			break;
 		}
@@ -6029,24 +6100,12 @@
 static void tabla_codec_decide_gpio_plug(struct snd_soc_codec *codec)
 {
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
-	short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
-	s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
-	enum tabla_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
-	int i;
+	enum tabla_mbhc_plug_type plug_type;
 
 	pr_debug("%s: enter\n", __func__);
 
 	tabla_turn_onoff_override(codec, true);
-	mb_v[0] = tabla_codec_setup_hs_polling(codec);
-	mic_mv[0] = tabla_codec_sta_dce_v(codec, 1, mb_v[0]);
-	pr_debug("%s: DCE run 1, mic_mv = %d\n", __func__, mic_mv[0]);
-
-	for (i = 1; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
-		mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
-		mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
-		pr_debug("%s: DCE run %d, mic_mv = %d\n", __func__, i + 1,
-			 mic_mv[i]);
-	}
+	plug_type = tabla_codec_get_plug_type(codec, true);
 	tabla_turn_onoff_override(codec, false);
 
 	if (tabla_hs_gpio_level_remove(tabla)) {
@@ -6055,48 +6114,26 @@
 		return;
 	}
 
-	if (tabla_codec_is_invalid_plug(codec, mic_mv, plug_type)) {
+	if (plug_type == PLUG_TYPE_INVALID) {
 		tabla_schedule_hs_detect_plug(tabla);
-	} else if (plug_type[0] == PLUG_TYPE_HEADPHONE) {
+	} else if (plug_type == PLUG_TYPE_HEADPHONE) {
 		tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
 
 		tabla_schedule_hs_detect_plug(tabla);
 	} else {
-		pr_debug("%s: Valid plug found, determine plug type\n",
-			 __func__);
-		tabla_find_plug_and_report(codec, plug_type[0]);
-	}
-}
-
-/* called under codec_resource_lock acquisition */
-static void tabla_codec_hphr_gnd_switch(struct snd_soc_codec *codec, bool on)
-{
-	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
-
-	if (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
-		snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01, on);
-		if (on)
-			usleep_range(5000, 5000);
+		pr_debug("%s: Valid plug found, determine plug type %d\n",
+			 __func__, plug_type);
+		tabla_find_plug_and_report(codec, plug_type);
 	}
 }
 
 /* called under codec_resource_lock acquisition */
 static void tabla_codec_detect_plug_type(struct snd_soc_codec *codec)
 {
-	int i;
-	bool gndswitch, vddioswitch;
-	int scaled;
+	enum tabla_mbhc_plug_type plug_type;
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
 	const struct tabla_mbhc_plug_detect_cfg *plug_det =
 	    TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->mbhc_cfg.calibration);
-	struct tabla_mbhc_plug_type_cfg *plug_type_ptr;
-	const bool vddio = (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
-			    !tabla->mbhc_micbias_switched);
-	int num_det = (MBHC_NUM_DCE_PLUG_DETECT + vddio);
-	enum tabla_mbhc_plug_type plug_type[num_det];
-	short mb_v[num_det];
-	s32 mic_mv[num_det];
-	bool inval = false;
 
 	/* Turn on the override,
 	 * tabla_codec_setup_hs_polling requires override on */
@@ -6119,84 +6156,11 @@
 		return;
 	}
 
-	/* performs DCEs for N times
-	 * 1st: check if voltage is in invalid range
-	 * 2nd - N-2nd: check voltage range and delta
-	 * N-1st: check voltage range, delta with HPHR GND switch
-	 * Nth: check voltage range with VDDIO switch if micbias V != vddio V*/
-	for (i = 0; i < num_det && !inval; i++) {
-		gndswitch = (i == (num_det - 1 - vddio));
-		vddioswitch = (vddio && (i == num_det - 1));
-		if (i == 0) {
-			mb_v[i] = tabla_codec_setup_hs_polling(codec);
-			mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
-			inval = tabla_is_invalid_insertion_range(codec,
-								 mic_mv[i]);
-			scaled = mic_mv[i];
-		} else if (vddioswitch) {
-			__tabla_codec_switch_micbias(tabla->codec, 1, false,
-						     false);
-			mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
-			mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
-			scaled = tabla_scale_v_micb_vddio(tabla, mic_mv[i],
-							  false);
-			inval = (tabla_is_invalid_insertion_range(codec,
-								  mic_mv[i]) ||
-				 tabla_is_inval_insert_delta(codec, scaled,
-					  mic_mv[i - 1],
-					  TABLA_MBHC_FAKE_INS_DELTA_SCALED_MV));
-			__tabla_codec_switch_micbias(tabla->codec, 0, false,
-						     false);
-		} else {
-			if (gndswitch)
-				tabla_codec_hphr_gnd_switch(codec, true);
-			mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
-			mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
-			inval = (tabla_is_invalid_insertion_range(codec,
-								  mic_mv[i]) ||
-				 tabla_is_inval_insert_delta(codec, mic_mv[i],
-					  mic_mv[i - 1],
-					  TABLA_MBHC_FAKE_INS_DELTA_SCALED_MV));
-			if (gndswitch)
-				tabla_codec_hphr_gnd_switch(codec, false);
-			scaled = mic_mv[i];
-		}
-		pr_debug("%s: DCE #%d, %04x, V %d, scaled V %d, GND %d, "
-			 "invalid %d\n", __func__,
-			 i + 1, mb_v[i] & 0xffff, mic_mv[i], scaled, gndswitch,
-			 inval);
-	}
+	plug_type = tabla_codec_get_plug_type(codec, tabla->mbhc_cfg.gpio ?
+						     true : false);
 	tabla_turn_onoff_override(codec, false);
 
-	plug_type_ptr =
-	    TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
-
-	for (i = 0; !inval && i < num_det; i++) {
-		/*
-		 * If we are here, means none of the all
-		 * measurements are fake, continue plug type detection.
-		 * If all three measurements do not produce same
-		 * plug type, restart insertion detection
-		 */
-		if (mic_mv[i] < plug_type_ptr->v_no_mic) {
-			plug_type[i] = PLUG_TYPE_HEADPHONE;
-			pr_debug("%s: Detect attempt %d, detected Headphone\n",
-				 __func__, i);
-		} else {
-			plug_type[i] = PLUG_TYPE_HEADSET;
-			pr_debug("%s: Detect attempt %d, detected Headset\n",
-				 __func__, i);
-		}
-
-		if (i > 0 && (plug_type[i - 1] != plug_type[i])) {
-			pr_err("%s: Detect attempt %d and %d are not same",
-			       __func__, i - 1, i);
-			inval = true;
-			break;
-		}
-	}
-
-	if (inval) {
+	if (plug_type == PLUG_TYPE_INVALID) {
 		pr_debug("%s: Invalid plug type detected\n", __func__);
 		snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
 				    0x02, 0x02);
@@ -6204,12 +6168,12 @@
 		tabla_codec_enable_hs_detect(codec, 1,
 					     MBHC_USE_MB_TRIGGER |
 					     MBHC_USE_HPHL_TRIGGER, false);
-	} else if (plug_type[0] == PLUG_TYPE_HEADPHONE) {
+	} else if (plug_type == PLUG_TYPE_HEADPHONE) {
 		pr_debug("%s: Headphone Detected\n", __func__);
 		tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
 		tabla_codec_cleanup_hs_polling(codec);
 		tabla_codec_enable_hs_detect(codec, 0, 0, false);
-	} else if (plug_type[0] == PLUG_TYPE_HEADSET) {
+	} else if (plug_type == PLUG_TYPE_HEADSET) {
 		pr_debug("%s: Headset detected\n", __func__);
 		tabla_codec_report_plug(codec, 1, SND_JACK_HEADSET);
 
@@ -6679,7 +6643,6 @@
 	tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
 	tabla_codec_calibrate_hs_polling(codec);
 	if (!tabla->mbhc_cfg.gpio) {
-		tabla->mbhc_inval_hs_range_override = false;
 		rc = tabla_codec_enable_hs_detect(codec, 1,
 						  MBHC_USE_MB_TRIGGER |
 						  MBHC_USE_HPHL_TRIGGER,
@@ -6689,7 +6652,6 @@
 			pr_err("%s: Failed to setup MBHC detection\n",
 			       __func__);
 	} else {
-		tabla->mbhc_inval_hs_range_override = true;
 		/* Enable Mic Bias pull down and HPH Switch to GND */
 		snd_soc_update_bits(codec,
 				    tabla->mbhc_bias_regs.ctl_reg, 0x01,
@@ -6747,13 +6709,11 @@
 		tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
 		tabla_codec_calibrate_hs_polling(codec);
 		if (!tabla->mbhc_cfg.gpio) {
-			tabla->mbhc_inval_hs_range_override = false;
 			rc =  tabla_codec_enable_hs_detect(codec, 1,
 							  MBHC_USE_MB_TRIGGER |
 							  MBHC_USE_HPHL_TRIGGER,
 							  false);
 		} else {
-			tabla->mbhc_inval_hs_range_override = true;
 			/* Enable Mic Bias pull down and HPH Switch to GND */
 			snd_soc_update_bits(codec,
 					    tabla->mbhc_bias_regs.ctl_reg, 0x01,