+#endif
+
+#define ADC_RING_SIZE 512
+
+static uint8_t *adc_ring;
+static uint16_t adc_head, adc_tail;
+static uint16_t adc_wake;
+
+void lpc_adc_isr(void)
+{
+ uint16_t avail;
+ uint16_t this, next;
+
+ this = adc_head;
+ next = (this + 1) & (ADC_RING_SIZE - 1);
+ if (next == adc_tail) {
+ lpc_adc.inten = 0;
+ return;
+ }
+ adc_ring[this] = lpc_adc.dr[6] >> 8;
+ adc_head = next;
+
+ /* If there are enough entries, wake up any waiters
+ */
+ avail = (next - adc_tail) & (ADC_RING_SIZE - 1);
+ if (avail >= adc_wake) {
+ adc_wake = 0;
+ ao_wakeup(&adc_wake);
+ }
+}
+
+#define AO_ADC_CLKDIV (AO_LPC_SYSCLK / 450000)
+
+static void
+ao_trng_adc_init(void)
+{
+ adc_ring = ao_usb_alloc(ADC_RING_SIZE);
+
+ lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_ADC);
+ lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_ADC_PD);
+
+ /* Enable interrupt when AO_ADC_6 is complete */
+ lpc_adc.inten = 0;
+
+ lpc_nvic_set_enable(LPC_ISR_ADC_POS);
+ lpc_nvic_set_priority(LPC_ISR_ADC_POS, AO_LPC_NVIC_CLOCK_PRIORITY);
+
+#if AO_ADC_0
+ ao_enable_analog(0, 11, 0);
+#endif
+#if AO_ADC_1
+ ao_enable_analog(0, 12, 1);
+#endif
+#if AO_ADC_2
+ ao_enable_analog(0, 13, 2);
+#endif
+#if AO_ADC_3
+ ao_enable_analog(0, 14, 3);
+#endif
+#if AO_ADC_4
+ ao_enable_analog(0, 15, 4);
+#endif
+#if AO_ADC_5
+ ao_enable_analog(0, 16, 5);
+#endif
+#if AO_ADC_6
+ ao_enable_analog(0, 22, 6);
+#endif
+#if AO_ADC_7
+ ao_enable_analog(0, 23, 7);
+#endif
+
+ lpc_adc.cr = ((1 << (LPC_ADC_CR_SEL + 6)) |
+ (AO_ADC_CLKDIV << LPC_ADC_CR_CLKDIV) |
+ (1 << LPC_ADC_CR_BURST) |
+ (LPC_ADC_CR_CLKS_9 << LPC_ADC_CR_CLKS));
+}
+
+static void
+ao_trng_adc_dump(void)
+{
+ int i;
+
+ while (((adc_head - adc_tail) & (ADC_RING_SIZE - 1)) < 16) {
+ lpc_adc.inten = (1 << (LPC_ADC_INTEN_ADINTEN + 6));
+ adc_wake = 16;
+ ao_sleep(&adc_wake);
+ }
+ printf("adc_head %d tail %d\n", adc_head, adc_tail);
+
+ for (i = 0; i < 16; i++) {
+ printf(" %4d", adc_ring[adc_tail]);
+ adc_tail = (adc_tail + 1) & (ADC_RING_SIZE - 1);
+ }
+ printf("\n");
+ lpc_adc.inten = 0;
+}
+
+static void
+ao_trng_run(void)
+{
+ uint16_t this_time;
+ flush();
+
+ while (!ao_usb_out_avail) {
+ ao_arch_block_interrupts();
+ while (((adc_head - adc_tail) & (ADC_RING_SIZE - 1)) < 64) {
+ lpc_adc.inten = (1 << (LPC_ADC_INTEN_ADINTEN + 6));
+ adc_wake = 64;
+ ao_sleep(&adc_wake);
+ }
+ ao_arch_release_interrupts();
+
+ this_time = ADC_RING_SIZE - adc_tail;
+ if (this_time > 64)
+ this_time = 64;
+ ao_usb_write(&adc_ring[adc_tail], this_time);
+ adc_tail = (adc_tail + this_time) & (ADC_RING_SIZE - 1);
+ }
+ lpc_adc.inten = 0;
+}
+
+static void
+ao_trng_speed(void)
+{
+ ao_cmd_decimal();
+
+ if (ao_cmd_lex_u32 == 0 || ao_cmd_status != ao_cmd_success) {
+ ao_cmd_status = ao_cmd_success;
+ printf ("Current spi speed %d\n", spi_speed);
+ } else {
+ spi_speed = ao_cmd_lex_u32;
+ }
+}