Esempio n. 1
0
static void adc_qmsi_enable(struct device *dev)
{
	struct adc_info *info = dev->driver_data;

	adc_lock(info);
	qm_adc_set_mode(QM_ADC_0, QM_ADC_MODE_NORM_NO_CAL);
	adc_unlock(info);
}
Esempio n. 2
0
static void adc_qmsi_disable(struct device *dev)
{
	struct adc_info *info = dev->driver_data;

	adc_lock(info);
	/* Go to deep sleep */
	qm_adc_set_mode(QM_ADC_0, QM_ADC_MODE_DEEP_PWR_DOWN);
	adc_unlock(info);
}
Esempio n. 3
0
File: main.c Progetto: CurieBSP/qmsi
int main(void)
{
#if (QUARK_D2000)
	int i;
	qm_adc_config_t cfg;
	qm_adc_xfer_t xfer;
	qm_adc_channel_t channels[] = {QM_ADC_CH_8, QM_ADC_CH_9};
	uint32_t samples_polled[NUM_SAMPLES_POLLED] = {0};
	uint32_t samples_interrupt[NUM_SAMPLES_INTERRUPT] = {0};

	QM_PUTS("\nADC example app start");

	/* Enable the ADC and set the clock divisor */
	clk_periph_enable(CLK_PERIPH_CLK | CLK_PERIPH_ADC |
			  CLK_PERIPH_ADC_REGISTER);
	clk_adc_set_div(100); /* ADC clock is 320KHz @ 32MHz */

	/* Set up pinmux */
	qm_pmux_select(QM_PIN_ID_8, QM_PMUX_FN_1);
	qm_pmux_select(QM_PIN_ID_9, QM_PMUX_FN_1);
	qm_pmux_input_en(QM_PIN_ID_8, true);
	qm_pmux_input_en(QM_PIN_ID_9, true);

	/* Set the mode and calibrate */
	qm_adc_set_mode(QM_ADC_0, QM_ADC_MODE_NORM_CAL);
	qm_adc_calibrate(QM_ADC_0);

	/* Set up config */
	cfg.window = 20; /* Clock cycles between the start of each sample */
	cfg.resolution = QM_ADC_RES_12_BITS;
	qm_adc_set_config(QM_ADC_0, &cfg);

	/*******************************
	 * ADC polled mode example
	 ******************************/
	QM_PUTS("ADC polled mode");

	/* Set up xfer */
	xfer.ch = channels;
	xfer.ch_len = NUM_CHANNELS;
	xfer.samples = samples_polled;
	xfer.samples_len = NUM_SAMPLES_POLLED;

	/* Run the conversion */
	if (qm_adc_convert(QM_ADC_0, &xfer)) {
		QM_PUTS("ERROR: qm_adc_convert failed");
		return 1;
	}

	/* Print the values of the samples */
	for (i = 0; i < NUM_SAMPLES_POLLED; i++) {
		QM_PRINTF("%d:%x ", i, (unsigned int)samples_polled[i]);
	}

	/*******************************
	 * ADC interrupt mode example
	 ******************************/
	QM_PUTS("\nADC interrupt mode");

	qm_irq_request(QM_IRQ_ADC_0, qm_adc_0_isr);

	/* Set up xfer */
	xfer.ch = channels;
	xfer.ch_len = NUM_CHANNELS;
	xfer.samples = samples_interrupt;
	xfer.samples_len = NUM_SAMPLES_INTERRUPT;
	xfer.complete_callback = complete_callback;
	xfer.error_callback = error_callback;

	if (qm_adc_irq_convert(QM_ADC_0, &xfer)) {
		QM_PUTS("ERROR: qm_adc_irq_convert failed");
		return 1;
	}

	/* Wait for the callback */
	while (false == complete)
		;

	for (i = 0; i < NUM_SAMPLES_INTERRUPT; i++) {
		QM_PRINTF("%d:%x ", i, (unsigned int)samples_interrupt[i]);
	}

	QM_PUTS("\nADC example app complete");

#endif /* QUARK_D2000 */
	return 0;
}
Esempio n. 4
0
void power_soc_sleep(void)
{
	/* Variables to save register values. */
	uint32_t ac_power_save;
	uint32_t clk_gate_save = QM_SCSS_CCU->ccu_periph_clk_gate_ctl;
	uint32_t sys_clk_ctl_save = QM_SCSS_CCU->ccu_sys_clk_ctl;
	uint32_t osc0_cfg_save = QM_SCSS_CCU->osc0_cfg1;
	uint32_t adc_mode_save = QM_ADC->adc_op_mode;
	uint32_t flash_tmg_save = QM_FLASH[QM_FLASH_0]->tmg_ctrl;
	uint32_t lp_clk_save = QM_SCSS_CCU->ccu_lp_clk_ctl;

	/* Clear any pending interrupts. */
	clear_all_pending_interrupts();

	qm_adc_set_mode(QM_ADC_0, QM_ADC_MODE_PWR_DOWN);

	/* Turn off high power comparators. */
	ac_power_save = QM_SCSS_CMP->cmp_pwr;
	QM_SCSS_CMP->cmp_pwr &= QM_AC_HP_COMPARATORS_MASK;

	/*
	 * Program WAKE_MASK.WAKE_MASK[31:0],
	 * CCU_LP_CLK_CTL.WAKE_PROBE_MODE_MASK registers identical to Interrupt
	 * Mask registers.
	 */
	QM_SCSS_CCU->ccu_lp_clk_ctl &= ~QM_WAKE_PROBE_MODE_MASK;
	/* Enable all wake sources as interrupts. */
	QM_SCSS_CCU->wake_mask = 0;

	/*
	 * Ensure that powering down of oscillators is delayed by hardware until
	 * core  executes HALT instruction.
	 */
	/* HYB_OSC_PD_LATCH_EN = 0, RTC_OSC_PD_LATCH_EN=0 */
	QM_SCSS_CCU->ccu_lp_clk_ctl &=
	    ~(QM_HYB_OSC_PD_LATCH_EN | QM_RTC_OSC_PD_LATCH_EN);

	/* Ensure that at exit, hardware will switch system clock to Hybrid
	 * oscillator clock so as to minimize exit latency by running at higher
	 * frequency than RTC clock.
	 */
	/* CCU_LP_CLK_CTL.CCU_EXIT_TO_HYBOSC */
	QM_SCSS_CCU->ccu_lp_clk_ctl |=
	    QM_CCU_EXIT_TO_HYBOSC | QM_CCU_MEM_HALT_EN | QM_CCU_CPU_HALT_EN;
	SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_CCU_LP_CLK_CTL);

	/*
	 * Only the following peripherals can be used as a wakeup source:
	 *  - GPIO Interrupts
	 *  - AON timers
	 *  - RTC
	 *  - low power comparators
	 */
	clk_periph_disable(
	    CLK_PERIPH_I2C_M0 | CLK_PERIPH_SPI_S | CLK_PERIPH_SPI_M0 |
	    CLK_PERIPH_GPIO_DB | CLK_PERIPH_WDT_REGISTER |
	    CLK_PERIPH_PWM_REGISTER | CLK_PERIPH_GPIO_REGISTER |
	    CLK_PERIPH_SPI_M0_REGISTER | CLK_PERIPH_SPI_S_REGISTER |
	    CLK_PERIPH_UARTA_REGISTER | CLK_PERIPH_UARTB_REGISTER |
	    CLK_PERIPH_I2C_M0_REGISTER);

	/* Set system clock source to hyb osc, 4 MHz, scaled to 512 kHz. */
	clk_sys_set_mode(CLK_SYS_HYB_OSC_4MHZ, CLK_SYS_DIV_8);

	/* Set the RAR to retention mode. */
	rar_set_mode(RAR_RETENTION);

	/*
	 * If wake source is any of AON Timer, RTC, GPIO interrupt, program
	 * CCU_SYS_CLK_CTL.CCU_SYS_CLK_SEL to RTC Oscillator.
	 */
	/* Enter SoC sleep mode. */
	power_cpu_halt();

	/* From here on, restore the SoC to an active state. */
	/* Set the RAR to normal mode. */
	rar_set_mode(RAR_NORMAL);

	/*
	 * Since we are running below 4MHz, 0 wait states are configured.
	 * If the previous frequency was > 4MHz, 0 wait states will
	 * violate the flash timings.
	 * In the worst case scenario, when switching back to 32MHz,
	 * 2 wait states will be restored.
	 * This setting will be too conservative until the frequency has been
	 * restored.
	 */
	QM_FLASH[QM_FLASH_0]->tmg_ctrl = flash_tmg_save;

	/* Restore all previous values. */
	QM_SCSS_CCU->ccu_sys_clk_ctl = sys_clk_ctl_save;
	/* Re-apply clock divider values. DIV_EN must go 0 -> 1. */
	QM_SCSS_CCU->ccu_sys_clk_ctl &=
	    ~(QM_CCU_SYS_CLK_DIV_EN | QM_CCU_RTC_CLK_DIV_EN);
	QM_SCSS_CCU->ccu_sys_clk_ctl |=
	    QM_CCU_SYS_CLK_DIV_EN | QM_CCU_RTC_CLK_DIV_EN;

	SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_CCU_SYS_CLK_CTL);

	/* Wait for the XTAL or SI oscillator to stabilise. */
	while (!(QM_SCSS_CCU->osc0_stat1 &
		 (QM_OSC0_LOCK_SI | QM_OSC0_LOCK_XTAL))) {
	};

	/* Restore original clocking, ADC, analog comparator states. */
	QM_SCSS_CCU->osc0_cfg1 = osc0_cfg_save;
	QM_SCSS_CCU->ccu_periph_clk_gate_ctl = clk_gate_save;
	SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_OSC0_CFG1);
	SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER,
			    SOCW_REG_CCU_PERIPH_CLK_GATE_CTL);
	QM_SCSS_CMP->cmp_pwr = ac_power_save;
	QM_ADC->adc_op_mode = adc_mode_save;
	QM_SCSS_CCU->ccu_lp_clk_ctl = lp_clk_save;
}
Esempio n. 5
0
void power_soc_deep_sleep(const power_wake_event_t wake_event)
{
	/* Variables to save register values. */
	uint32_t ac_power_save;
	uint32_t clk_gate_save = QM_SCSS_CCU->ccu_periph_clk_gate_ctl;
	uint32_t sys_clk_ctl_save = QM_SCSS_CCU->ccu_sys_clk_ctl;
	uint32_t osc0_cfg_save = QM_SCSS_CCU->osc0_cfg1;
	uint32_t osc1_cfg_save = QM_SCSS_CCU->osc1_cfg0;
	uint32_t adc_mode_save = QM_ADC->adc_op_mode;
	uint32_t aon_vr_save = QM_SCSS_PMU->aon_vr;
	uint32_t flash_tmg_save = QM_FLASH[QM_FLASH_0]->tmg_ctrl;
	uint32_t ext_clock_save;
	uint32_t lp_clk_save, pmux_slew_save;

	pmux_slew_save = QM_SCSS_PMUX->pmux_slew[0];
	ext_clock_save = QM_SCSS_CCU->ccu_ext_clock_ctl;
	lp_clk_save = QM_SCSS_CCU->ccu_lp_clk_ctl;

	/* Clear any pending interrupts. */
	clear_all_pending_interrupts();

	/*
	 * Clear the wake mask bits. Default behaviour is to wake from GPIO /
	 * comparator.
	 */
	switch (wake_event) {
	case POWER_WAKE_FROM_RTC:
		QM_SCSS_CCU->wake_mask =
		    SET_ALL_BITS & ~QM_CCU_WAKE_MASK_RTC_BIT;
		break;
	case POWER_WAKE_FROM_GPIO_COMP:
	default:
		QM_SCSS_CCU->wake_mask = SET_ALL_BITS &
					 ~(QM_CCU_WAKE_MASK_COMPARATOR_BIT |
					   QM_CCU_WAKE_MASK_GPIO_BIT);
		break;
	}

	QM_SCSS_GP->gps1 |= QM_SCSS_GP_POWER_STATE_DEEP_SLEEP;

	qm_adc_set_mode(QM_ADC_0, QM_ADC_MODE_DEEP_PWR_DOWN);

	/* Turn off high power comparators. */
	ac_power_save = QM_SCSS_CMP->cmp_pwr;
	QM_SCSS_CMP->cmp_pwr &= QM_AC_HP_COMPARATORS_MASK;

	/* Disable all peripheral clocks. */
	clk_periph_disable(CLK_PERIPH_REGISTER);

	/* Disable external clocks. */
	QM_SCSS_CCU->ccu_ext_clock_ctl = 0;
	SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_CCU_EXT_CLK_CTL);

	/* Set slew rate of all pins to 12mA. */
	QM_SCSS_PMUX->pmux_slew[0] = 0;
	SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_PMUX_SLEW);

	if (wake_event != POWER_WAKE_FROM_RTC) {
		/* Disable RTC. */
		QM_SCSS_CCU->osc1_cfg0 &= ~QM_OSC1_PD;

		/* Set system clock source to
		 * Silicon Oscillator 4 MHz, scaled down to 32 kHz. */
		clk_sys_set_mode(CLK_SYS_HYB_OSC_4MHZ, CLK_SYS_DIV_128);
	}

	/* Power down the oscillator after the halt instruction is executed. */
	QM_SCSS_CCU->ccu_lp_clk_ctl &= ~QM_HYB_OSC_PD_LATCH_EN;
	/*
	 * Enable memory halt and CPU halt. When exiting sleep mode, use hybrid
	 * oscillator.
	 */
	QM_SCSS_CCU->ccu_lp_clk_ctl |=
	    QM_CCU_EXIT_TO_HYBOSC | QM_CCU_MEM_HALT_EN | QM_CCU_CPU_HALT_EN;
	SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_CCU_LP_CLK_CTL);

	/* Power down hybrid oscillator. */
	QM_SCSS_CCU->osc0_cfg1 |= QM_OSC0_PD;

	/* Disable gpio debounce clocking. */
	QM_SCSS_CCU->ccu_gpio_db_clk_ctl &= ~QM_CCU_GPIO_DB_CLK_EN;
	/* Set retention voltage to 1.35V. */
	/* SCSS.OSC0_CFG0.OSC0_HYB_SET_REG1.OSC0_CFG0[0]  = 1; */
	QM_SCSS_CCU->osc0_cfg0 |= QM_SI_OSC_1V2_MODE;

	/* Enable low voltage mode for flash controller. */
	/* FlashCtrl.CTRL.LVE_MODE = 1; */
	QM_FLASH[QM_FLASH_0]->ctrl |= QM_FLASH_LVE_MODE;

	/* Select 1.35V for voltage regulator. */
	/* SCSS.AON_VR.VSEL = 0xB; */
	QM_SCSS_PMU->aon_vr =
	    (QM_AON_VR_PASS_CODE | (aon_vr_save & QM_AON_VR_VSEL_MASK) |
	     QM_AON_VR_VSEL_1V35);
	/* SCSS.AON_VR.ROK_BUF_VREG_MASK = 1; */
	QM_SCSS_PMU->aon_vr = (QM_AON_VR_PASS_CODE | QM_SCSS_PMU->aon_vr |
			       QM_AON_VR_ROK_BUF_VREG_MASK);

	/* SCSS.AON_VR.VSEL_STROBE = 1;  */
	QM_SCSS_PMU->aon_vr =
	    (QM_AON_VR_PASS_CODE | QM_SCSS_PMU->aon_vr | QM_AON_VR_VSTRB);

	/* Wait >= 1 usec, at 256 kHz this is 1 cycle. */
	__asm__ __volatile__("nop");

	/* SCSS.AON_VR.VSEL_STROBE = 0; */
	QM_SCSS_PMU->aon_vr =
	    (QM_AON_VR_PASS_CODE | (QM_SCSS_PMU->aon_vr & ~QM_AON_VR_VSTRB));

	/* Wait >= 2 usec, at 256 kHz this is 1 cycle. */
	__asm__ __volatile__("nop");

	/* Set the RAR to retention mode. */
	rar_set_mode(RAR_RETENTION);

	if (wake_event == POWER_WAKE_FROM_RTC) {
		/* Start running on the rtc clock */
		clk_sys_set_mode(CLK_SYS_RTC_OSC, CLK_SYS_DIV_1);
	}

	/* Disable all peripheral clocks. */
	clk_periph_disable(CLK_PERIPH_REGISTER | CLK_PERIPH_CLK);

	/* Enter SoC deep sleep mode. */
	power_cpu_halt();

	/* We are now exiting from deep sleep mode. */
	/* Set the RAR to normal mode. */
	rar_set_mode(RAR_NORMAL);

	/*
	 * Since we are running below 4MHz, 0 wait states are configured.
	 * If the previous frequency was > 4MHz, 0 wait states will
	 * violate the flash timings.
	 * In the worst case scenario, when switching back to 32MHz,
	 * 2 wait states will be restored.
	 * This setting will be too conservative until the frequency has been
	 * restored.
	 */
	QM_FLASH[QM_FLASH_0]->tmg_ctrl = flash_tmg_save;

	/* Restore operating voltage to 1.8V. */
	/* SCSS.AON_VR.VSEL = 0x10; */
	QM_SCSS_PMU->aon_vr =
	    (QM_AON_VR_PASS_CODE | (QM_SCSS_PMU->aon_vr & QM_AON_VR_VSEL_MASK) |
	     QM_AON_VR_VSEL_1V8 | QM_AON_VR_ROK_BUF_VREG_MASK);

	/* SCSS.AON_VR.VSEL_STROBE = 1;  */
	QM_SCSS_PMU->aon_vr =
	    (QM_AON_VR_PASS_CODE | QM_SCSS_PMU->aon_vr | QM_AON_VR_VSTRB);

	/* Wait >= 1 usec, at 256 kHz this is 1 cycle. */
	__asm__ __volatile__("nop");

	/* SCSS.AON_VR.VSEL_STROBE = 0; */
	QM_SCSS_PMU->aon_vr =
	    (QM_AON_VR_PASS_CODE | (QM_SCSS_PMU->aon_vr & ~QM_AON_VR_VSTRB));

	/* Wait >= 2 usec, at 256 kHz this is 1 cycle. */
	__asm__ __volatile__("nop");

	/* SCSS.AON_VR.ROK_BUF_VREG_MASK = 0;  */
	QM_SCSS_PMU->aon_vr =
	    (QM_AON_VR_PASS_CODE |
	     (QM_SCSS_PMU->aon_vr & ~QM_AON_VR_ROK_BUF_VREG_MASK));

	/* Wait >= 1 usec, at 256 kHz this is 1 cycle. */
	__asm__ __volatile__("nop");

	/* Wait for voltage regulator to attain 1.8V regulation. */
	while (!(QM_SCSS_PMU->aon_vr & QM_AON_VR_ROK_BUF_VREG_STATUS)) {
	}

	/* SCSS.OSC0_CFG0.OSC0_HYB_SET_REG1.OSC0_CFG0[0]  = 0; */
	QM_SCSS_CCU->osc0_cfg0 &= ~QM_SI_OSC_1V2_MODE;

	/* FlashCtrl.CTRL.LVE_MODE = 0; */
	QM_FLASH[QM_FLASH_0]->ctrl &= ~QM_FLASH_LVE_MODE;

	/* Restore all previous values. */
	QM_SCSS_CCU->ccu_sys_clk_ctl = sys_clk_ctl_save;
	/* Re-apply clock divider values. DIV_EN must go 0 -> 1. */
	QM_SCSS_CCU->ccu_sys_clk_ctl &=
	    ~(QM_CCU_SYS_CLK_DIV_EN | QM_CCU_RTC_CLK_DIV_EN);
	QM_SCSS_CCU->ccu_sys_clk_ctl |=
	    QM_CCU_SYS_CLK_DIV_EN | QM_CCU_RTC_CLK_DIV_EN;

	/* Wait for the XTAL or SI oscillator to stabilise. */
	while (!(QM_SCSS_CCU->osc0_stat1 &
		 (QM_OSC0_LOCK_SI | QM_OSC0_LOCK_XTAL))) {
	};
	SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_CCU_SYS_CLK_CTL);

	/* Re-enable clocks. */
	clk_periph_enable(CLK_PERIPH_REGISTER);

	/* Re-enable gpio debounce clocking. */
	QM_SCSS_CCU->ccu_gpio_db_clk_ctl |= QM_CCU_GPIO_DB_CLK_EN;

	/* Restore original clocking, ADC, analog comparator states. */
	QM_SCSS_CCU->osc0_cfg1 = osc0_cfg_save;
	QM_SCSS_CCU->ccu_periph_clk_gate_ctl = clk_gate_save;
	QM_SCSS_CCU->osc1_cfg0 = osc1_cfg_save;

	SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_OSC0_CFG1);
	SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER,
			    SOCW_REG_CCU_PERIPH_CLK_GATE_CTL);
	QM_SCSS_CMP->cmp_pwr = ac_power_save;
	QM_ADC->adc_op_mode = adc_mode_save;

	QM_SCSS_PMUX->pmux_slew[0] = pmux_slew_save;
	QM_SCSS_CCU->ccu_ext_clock_ctl = ext_clock_save;
	QM_SCSS_CCU->ccu_lp_clk_ctl = lp_clk_save;

	SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_PMUX_SLEW);
	SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_CCU_LP_CLK_CTL);
	SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_CCU_EXT_CLK_CTL);

	QM_SCSS_CCU->wake_mask = SET_ALL_BITS;
	QM_SCSS_GP->gps1 &= ~QM_SCSS_GP_POWER_STATE_DEEP_SLEEP;
}