diff --git a/README.md b/README.md
index 2c72ea7..a7583d2 100644
--- a/README.md
+++ b/README.md
@@ -32,4 +32,4 @@ See the [blog post](https://blog.porucha.net/2024/pico-sdr/) for more informatio
 
 4. Open `grc/PicoSDR-WBFM.grc` in GNU Radio Companion, adjust carrier frequency to match your favorite FM radio station and press `F6`.
 
-5. Alternatively [gqrx](https://www.gqrx.dk/) works fine with `rtl_tcp` input mode. Maximum sample rate seem to be 400 ksps, above that the samples are dropped.
+5. Alternatively [gqrx](https://www.gqrx.dk/) works fine with `rtl_tcp` input mode. Maximum sample rate seem to be 400 ksps, above that the samples are dropped. Make sure to adjust LNA gain to +30 dB. It's not accurate, but it does control bias strength which in turn does affect analog gain.
diff --git a/grc/PicoSDR-WBFM.grc b/grc/PicoSDR-WBFM.grc
index 9ade9bd..7f2a5c0 100644
--- a/grc/PicoSDR-WBFM.grc
+++ b/grc/PicoSDR-WBFM.grc
@@ -374,7 +374,7 @@ blocks:
     freq7: 100e6
     freq8: 100e6
     freq9: 100e6
-    gain0: '0'
+    gain0: '30'
     gain1: '10'
     gain10: '10'
     gain11: '10'
diff --git a/grc/PicoSDR.grc b/grc/PicoSDR.grc
index 70ffba7..9a9fca4 100644
--- a/grc/PicoSDR.grc
+++ b/grc/PicoSDR.grc
@@ -401,7 +401,7 @@ blocks:
     freq7: 100e6
     freq8: 100e6
     freq9: 100e6
-    gain0: '0'
+    gain0: '30'
     gain1: '10'
     gain10: '10'
     gain11: '10'
diff --git a/src/main.c b/src/main.c
index 1b86402..95380b9 100644
--- a/src/main.c
+++ b/src/main.c
@@ -48,7 +48,6 @@ static_assert(RX_STRIDE * 4 < RX_WORDS, "RX_STRIDE * 4 < RX_WORDS");
 static uint32_t rx_cos[RX_WORDS] __attribute__((__aligned__(1 << RX_BITS_DEPTH)));
 static uint32_t rx_sin[RX_WORDS] __attribute__((__aligned__(1 << RX_BITS_DEPTH)));
 
-#define INIT_GAIN 120
 #define INIT_SAMPLE_RATE 100000
 #define INIT_FREQ 94600000
 
@@ -56,7 +55,6 @@ static uint32_t rx_sin[RX_WORDS] __attribute__((__aligned__(1 << RX_BITS_DEPTH))
 static int gains[NUM_GAINS] = { 0,   9,	  14,  27,  37,	 77,  87,  125, 144, 157,
 				166, 197, 207, 229, 254, 280, 297, 328, 338, 364,
 				372, 386, 402, 421, 434, 439, 445, 480, 496 };
-static int gain = INIT_GAIN;
 static int sample_rate = INIT_SAMPLE_RATE;
 
 #define SIN_PHASE (0u)
@@ -91,6 +89,17 @@ inline static uint32_t rnd_next()
 	return rnd;
 }
 
+static void bias_set_gain(int gain)
+{
+	if (gain > 9)
+		gain = 9;
+	else if (gain < 0)
+		gain = 0;
+
+	pio1->sm[0].execctrl = (pio1->sm[0].execctrl & ~PIO_SM0_EXECCTRL_WRAP_BOTTOM_BITS) |
+			       ((19 - gain) << PIO_SM0_EXECCTRL_WRAP_BOTTOM_LSB);
+}
+
 static void bias_init(int in_pin, int out_pin)
 {
 	gpio_disable_pulls(in_pin);
@@ -103,8 +112,7 @@ static void bias_init(int in_pin, int out_pin)
 	gpio_set_slew_rate(out_pin, GPIO_SLEW_RATE_SLOW);
 
 	const uint16_t insn[] = {
-		pio_encode_mov_not(pio_pins, pio_pins) | pio_encode_sideset(1, 1),
-
+		pio_encode_in(pio_pins, 1),
 		pio_encode_in(pio_pins, 1),
 		pio_encode_in(pio_pins, 1),
 		pio_encode_in(pio_pins, 1),
@@ -118,6 +126,7 @@ static void bias_init(int in_pin, int out_pin)
 		pio_encode_mov(pio_isr, pio_null),
 
 		pio_encode_jmp_x_dec(11),
+		pio_encode_mov_not(pio_pins, pio_pins) | pio_encode_sideset(1, 1),
 	};
 
 	pio_program_t prog = {
@@ -552,7 +561,7 @@ static void rf_rx(void)
 			int64_t I = sI;
 			int64_t Q = sQ;
 
-			I *= gain;
+			I *= 127;
 			I -= (max_amplitude * 181) / 256;
 			I /= max_amplitude;
 
@@ -563,7 +572,7 @@ static void rf_rx(void)
 
 			*blockptr++ = (uint8_t)I + 128;
 
-			Q *= gain;
+			Q *= 127;
 			Q -= (max_amplitude * 181) / 256;
 			Q /= max_amplitude;
 
@@ -599,12 +608,10 @@ static void run_command(uint8_t cmd, uint32_t arg)
 		rx_lo_init(arg - sample_rate, true);
 	} else if (0x04 == cmd) {
 		/* Set the tuner gain level */
-		gain = INIT_GAIN * powf(10.0f, 0.005f * arg);
+		bias_set_gain((arg + 14) / 30);
 	} else if (0x0d == cmd) {
 		/* Set tuner gain by the tuner's gain index */
-		if (arg < NUM_GAINS) {
-			gain = INIT_GAIN * powf(10.0f, 0.005f * gains[arg]);
-		}
+		bias_set_gain((gains[arg] + 14) / 30);
 	}
 }