ext qmsi: Update to QMSI 1.2 release
Update the QMSI drop we maintain in Zephyr, and fix the build where needed: - QM_USB_BASE is renamed to QM_USB_0_BASE; - parameter int_en from qm_uart cfg struct was removed; - driver's folder now has a new structure, fix makefiles accordingly; - QM_WDT_MODE and related renamed to QM_WDT_CR_RMOD; - QM_SCSS_AON renamed to QM_AONC. Change-Id: Iffe9c66b7a3f2fe64418326e20ff0894149b3044 Signed-off-by: Jesus Sanchez-Palencia <jesus.sanchez-palencia@intel.com>
This commit is contained in:
parent
d5a252cc35
commit
7c0fc99c79
|
@ -25,7 +25,7 @@
|
|||
|
||||
static int aon_counter_qmsi_start(struct device *dev)
|
||||
{
|
||||
if (qm_aonc_enable(QM_SCSS_AON_0)) {
|
||||
if (qm_aonc_enable(QM_AONC_0)) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ static int aon_counter_qmsi_start(struct device *dev)
|
|||
|
||||
static int aon_counter_qmsi_stop(struct device *dev)
|
||||
{
|
||||
qm_aonc_disable(QM_SCSS_AON_0);
|
||||
qm_aonc_disable(QM_AONC_0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ static uint32_t aon_counter_qmsi_read(void)
|
|||
{
|
||||
uint32_t value;
|
||||
|
||||
qm_aonc_get_value(QM_SCSS_AON_0, &value);
|
||||
qm_aonc_get_value(QM_AONC_0, &value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ static int aon_timer_qmsi_start(struct device *dev)
|
|||
qmsi_cfg.callback_data = NULL;
|
||||
|
||||
aon_critical_region_start(dev);
|
||||
if (qm_aonpt_set_config(QM_SCSS_AON_0, &qmsi_cfg)) {
|
||||
if (qm_aonpt_set_config(QM_AONC_0, &qmsi_cfg)) {
|
||||
result = -EIO;
|
||||
}
|
||||
aon_critical_region_end(dev);
|
||||
|
@ -118,7 +118,7 @@ static int aon_timer_qmsi_stop(struct device *dev)
|
|||
qmsi_cfg.callback_data = NULL;
|
||||
|
||||
aon_critical_region_start(dev);
|
||||
qm_aonpt_set_config(QM_SCSS_AON_0, &qmsi_cfg);
|
||||
qm_aonpt_set_config(QM_AONC_0, &qmsi_cfg);
|
||||
aon_critical_region_end(dev);
|
||||
|
||||
return 0;
|
||||
|
@ -128,7 +128,7 @@ static uint32_t aon_timer_qmsi_read(void)
|
|||
{
|
||||
uint32_t value;
|
||||
|
||||
qm_aonpt_get_value(QM_SCSS_AON_0, &value);
|
||||
qm_aonpt_get_value(QM_AONC_0, &value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ static int aon_timer_qmsi_set_alarm(struct device *dev,
|
|||
int result = 0;
|
||||
|
||||
/* Check if timer has been started */
|
||||
if (QM_SCSS_AON[QM_SCSS_AON_0].aonpt_cfg == 0) {
|
||||
if (QM_AONC[QM_AONC_0].aonpt_cfg == 0) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
|
@ -153,7 +153,7 @@ static int aon_timer_qmsi_set_alarm(struct device *dev,
|
|||
qmsi_cfg.callback_data = user_data;
|
||||
|
||||
aon_critical_region_start(dev);
|
||||
if (qm_aonpt_set_config(QM_SCSS_AON_0, &qmsi_cfg)) {
|
||||
if (qm_aonpt_set_config(QM_AONC_0, &qmsi_cfg)) {
|
||||
user_cb = NULL;
|
||||
result = -EIO;
|
||||
}
|
||||
|
|
|
@ -487,7 +487,6 @@ static int uart_qmsi_line_ctrl_set(struct device *dev, uint32_t ctrl, uint32_t v
|
|||
cfg.baud_divisor = QM_UART_CFG_BAUD_DL_PACK(DIVISOR_HIGH(val),
|
||||
DIVISOR_LOW(val), 0);
|
||||
cfg.hw_fc = QM_UART[instance]->mcr & QM_UART_MCR_AFCE;
|
||||
cfg.int_en = false;
|
||||
qm_uart_set_config(instance, &cfg);
|
||||
break;
|
||||
default:
|
||||
|
@ -544,7 +543,6 @@ static int uart_qmsi_init(struct device *dev)
|
|||
cfg.line_control = QM_UART_LC_8N1;
|
||||
cfg.baud_divisor = config->baud_divisor;
|
||||
cfg.hw_fc = config->hw_fc;
|
||||
cfg.int_en = false;
|
||||
|
||||
clk_periph_enable(config->clock_gate);
|
||||
|
||||
|
|
|
@ -205,7 +205,7 @@ struct usb_dw_reg {
|
|||
#define USB_DW_PLL_TIMEOUT_US 100
|
||||
|
||||
#if defined(CONFIG_SOC_QUARK_SE_C1000)
|
||||
#define USB_DW_BASE QM_USB_BASE
|
||||
#define USB_DW_BASE QM_USB_0_BASE
|
||||
#define USB_DW_IRQ QM_IRQ_USB_0
|
||||
#else
|
||||
#error "Unsupported board"
|
||||
|
|
|
@ -85,8 +85,8 @@ static void (*user_cb)(struct device *dev);
|
|||
static void get_config(struct device *dev, struct wdt_config *cfg)
|
||||
{
|
||||
cfg->timeout = QM_WDT[QM_WDT_0].wdt_torr;
|
||||
cfg->mode = ((QM_WDT[QM_WDT_0].wdt_cr & QM_WDT_MODE) >>
|
||||
QM_WDT_MODE_OFFSET);
|
||||
cfg->mode = ((QM_WDT[QM_WDT_0].wdt_cr & QM_WDT_CR_RMOD) >>
|
||||
QM_WDT_CR_RMOD_OFFSET);
|
||||
cfg->interrupt_fn = user_cb;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,31 +1,29 @@
|
|||
subdir-ccflags-$(CONFIG_QMSI_BUILTIN) +=-DISR_HANDLED
|
||||
subdir-ccflags-$(CONFIG_QMSI_BUILTIN) +=-DENABLE_EXTERNAL_ISR_HANDLING
|
||||
|
||||
obj-$(CONFIG_QMSI_BUILTIN) += drivers/clk.o drivers/qm_flash.o
|
||||
obj-$(CONFIG_QMSI_BUILTIN) += drivers/flash/qm_flash.o
|
||||
ifeq ($(CONFIG_ARC),y)
|
||||
obj-$(CONFIG_QMSI_BUILTIN) += drivers/sensor/ss_clk.o
|
||||
obj-$(CONFIG_QMSI_BUILTIN) += drivers/sensor/ss_power_states.o
|
||||
obj-$(CONFIG_QMSI_BUILTIN) += drivers/clk/ss_clk.o
|
||||
obj-$(CONFIG_QMSI_BUILTIN) += soc/quark_se/drivers/ss_power_states.o
|
||||
endif
|
||||
obj-$(CONFIG_QMSI_BUILTIN) += soc/$(patsubst %_ss,%,$(SOC_SERIES))/drivers/power_states.o
|
||||
obj-$(CONFIG_QMSI_BUILTIN) += soc/$(patsubst %_ss,%,$(SOC_SERIES))/drivers/clk.o
|
||||
ifeq ($(CONFIG_SOC_QUARK_SE_C1000),y)
|
||||
obj-$(CONFIG_QMSI_BUILTIN) += soc/$(SOC_SERIES)/drivers/vreg.o
|
||||
endif
|
||||
ifeq ($(CONFIG_SOC_QUARK_D2000),y)
|
||||
obj-$(CONFIG_QMSI_BUILTIN) += soc/$(SOC_SERIES)/drivers/rar.o
|
||||
endif
|
||||
obj-$(CONFIG_RTC_QMSI) += drivers/qm_rtc.o
|
||||
obj-$(CONFIG_WDT_QMSI) += drivers/qm_wdt.o
|
||||
obj-$(CONFIG_I2C_QMSI) += drivers/qm_i2c.o drivers/qm_dma.o
|
||||
obj-$(CONFIG_PWM_QMSI) += drivers/qm_pwm.o
|
||||
obj-$(CONFIG_AIO_COMPARATOR_QMSI) += drivers/qm_comparator.o
|
||||
obj-$(CONFIG_AON_COUNTER_QMSI) += drivers/qm_aon_counters.o
|
||||
obj-$(CONFIG_GPIO_QMSI) += drivers/qm_gpio.o
|
||||
obj-$(CONFIG_ADC_QMSI) += drivers/qm_adc.o
|
||||
obj-$(CONFIG_UART_QMSI) += drivers/qm_uart.o
|
||||
obj-$(CONFIG_DMA_QMSI) += drivers/qm_dma.o
|
||||
obj-$(CONFIG_SPI_QMSI) += drivers/qm_spi.o
|
||||
obj-$(CONFIG_SOC_FLASH_QMSI) += drivers/qm_flash.o
|
||||
obj-$(CONFIG_PINMUX_DEV_QMSI) += drivers/qm_pinmux.o
|
||||
obj-$(CONFIG_SPI_QMSI_SS) += drivers/sensor/qm_ss_spi.o
|
||||
obj-$(CONFIG_GPIO_QMSI_SS) += drivers/sensor/qm_ss_gpio.o
|
||||
obj-$(CONFIG_I2C_QMSI_SS) += drivers/sensor/qm_ss_i2c.o
|
||||
obj-$(CONFIG_ADC_QMSI_SS) += drivers/sensor/qm_ss_adc.o
|
||||
obj-$(CONFIG_RTC_QMSI) += drivers/rtc/qm_rtc.o
|
||||
obj-$(CONFIG_WDT_QMSI) += drivers/wdt/qm_wdt.o
|
||||
obj-$(CONFIG_I2C_QMSI) += drivers/i2c/qm_i2c.o drivers/dma/qm_dma.o
|
||||
obj-$(CONFIG_PWM_QMSI) += drivers/pwm/qm_pwm.o
|
||||
obj-$(CONFIG_AIO_COMPARATOR_QMSI) += drivers/comparator/qm_comparator.o
|
||||
obj-$(CONFIG_AON_COUNTER_QMSI) += drivers/aon_counters/qm_aon_counters.o
|
||||
obj-$(CONFIG_GPIO_QMSI) += drivers/gpio/qm_gpio.o
|
||||
obj-$(CONFIG_ADC_QMSI) += drivers/adc/qm_adc.o
|
||||
obj-$(CONFIG_UART_QMSI) += drivers/uart/qm_uart.o
|
||||
obj-$(CONFIG_DMA_QMSI) += drivers/dma/qm_dma.o
|
||||
obj-$(CONFIG_SPI_QMSI) += drivers/spi/qm_spi.o
|
||||
obj-$(CONFIG_SOC_FLASH_QMSI) += drivers/flash/qm_flash.o
|
||||
obj-$(CONFIG_PINMUX_DEV_QMSI) += drivers/pinmux/qm_pinmux.o
|
||||
obj-$(CONFIG_SPI_QMSI_SS) += drivers/spi/qm_ss_spi.o
|
||||
obj-$(CONFIG_GPIO_QMSI_SS) += drivers/gpio/qm_ss_gpio.o
|
||||
obj-$(CONFIG_I2C_QMSI_SS) += drivers/i2c/qm_ss_i2c.o
|
||||
obj-$(CONFIG_ADC_QMSI_SS) += drivers/adc/qm_ss_adc.o
|
||||
|
|
|
@ -8,7 +8,7 @@ Microcontroller products. It currently supports the following SoCs:
|
|||
- Intel® Quark™ D2000 Microcontroller
|
||||
- Intel® Quark™ SE Microcontroller
|
||||
|
||||
The current version supported in Zephyr is QMSI 1.1.0. See:
|
||||
The current version supported in Zephyr is QMSI 1.2.0. See:
|
||||
|
||||
https://github.com/quark-mcu/qmsi/releases
|
||||
|
||||
|
|
|
@ -206,7 +206,7 @@ static void qm_ss_adc_isr_cal_handler(const qm_ss_adc_t adc)
|
|||
{
|
||||
/* Clear the calibration request reg. */
|
||||
QM_SS_REG_AUX_NAND(QM_SS_CREG_BASE + QM_SS_IO_CREG_MST0_CTRL,
|
||||
QM_SS_ADC_CAL_REQ);
|
||||
QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_REQ);
|
||||
|
||||
/* Call the user callback if it is set. */
|
||||
if (cal_callback[adc]) {
|
||||
|
@ -401,14 +401,15 @@ int qm_ss_adc_set_mode(const qm_ss_adc_t adc, const qm_ss_adc_mode_t mode)
|
|||
|
||||
/* Issue mode change command and wait for it to complete. */
|
||||
creg = __builtin_arc_lr(QM_SS_CREG_BASE + QM_SS_IO_CREG_MST0_CTRL);
|
||||
creg &= ~((QM_SS_ADC_DELAY_MASK << QM_SS_ADC_DELAY_OFFSET) |
|
||||
QM_SS_ADC_PWR_MODE_MASK);
|
||||
creg |= ((delay << QM_SS_ADC_DELAY_OFFSET) | mode);
|
||||
creg &= ~((QM_SS_IO_CREG_MST0_CTRL_ADC_DELAY_MASK
|
||||
<< QM_SS_IO_CREG_MST0_CTRL_ADC_DELAY_OFFSET) |
|
||||
QM_SS_IO_CREG_MST0_CTRL_ADC_PWR_MODE_MASK);
|
||||
creg |= ((delay << QM_SS_IO_CREG_MST0_CTRL_ADC_DELAY_OFFSET) | mode);
|
||||
__builtin_arc_sr(creg, QM_SS_CREG_BASE + QM_SS_IO_CREG_MST0_CTRL);
|
||||
|
||||
/* Wait for the mode change to complete. */
|
||||
while (!(__builtin_arc_lr(QM_SS_CREG_BASE + QM_SS_IO_CREG_SLV0_OBSR) &
|
||||
QM_SS_ADC_PWR_MODE_STS)) {
|
||||
QM_SS_IO_CREG_SLV0_OBSR_ADC_PWR_MODE_STS)) {
|
||||
}
|
||||
|
||||
/* Restore the state of the mode change interrupt mask if necessary. */
|
||||
|
@ -444,9 +445,10 @@ int qm_ss_adc_irq_set_mode(const qm_ss_adc_t adc, const qm_ss_adc_mode_t mode,
|
|||
|
||||
/* Issue mode change command and wait for it to complete. */
|
||||
creg = __builtin_arc_lr(QM_SS_CREG_BASE + QM_SS_IO_CREG_MST0_CTRL);
|
||||
creg &= ~((QM_SS_ADC_DELAY_MASK << QM_SS_ADC_DELAY_OFFSET) |
|
||||
QM_SS_ADC_PWR_MODE_MASK);
|
||||
creg |= ((delay << QM_SS_ADC_DELAY_OFFSET) | mode);
|
||||
creg &= ~((QM_SS_IO_CREG_MST0_CTRL_ADC_DELAY_MASK
|
||||
<< QM_SS_IO_CREG_MST0_CTRL_ADC_DELAY_OFFSET) |
|
||||
QM_SS_IO_CREG_MST0_CTRL_ADC_PWR_MODE_MASK);
|
||||
creg |= ((delay << QM_SS_IO_CREG_MST0_CTRL_ADC_DELAY_OFFSET) | mode);
|
||||
__builtin_arc_sr(creg, QM_SS_CREG_BASE + QM_SS_IO_CREG_MST0_CTRL);
|
||||
|
||||
return 0;
|
||||
|
@ -467,21 +469,23 @@ int qm_ss_adc_calibrate(const qm_ss_adc_t adc __attribute__((unused)))
|
|||
|
||||
/* Issue the start calibrate command. */
|
||||
creg = __builtin_arc_lr(QM_SS_CREG_BASE + QM_SS_IO_CREG_MST0_CTRL);
|
||||
creg &= ~(QM_SS_ADC_CAL_CMD_MASK | QM_SS_ADC_CAL_REQ);
|
||||
creg |= ((QM_SS_ADC_CMD_START_CAL << QM_SS_ADC_CAL_CMD_OFFSET) |
|
||||
QM_SS_ADC_CAL_REQ);
|
||||
creg &= ~(QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_CMD_MASK |
|
||||
QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_REQ);
|
||||
creg |= ((QM_SS_ADC_CMD_START_CAL
|
||||
<< QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_CMD_OFFSET) |
|
||||
QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_REQ);
|
||||
__builtin_arc_sr(creg, QM_SS_CREG_BASE + QM_SS_IO_CREG_MST0_CTRL);
|
||||
|
||||
/* Wait for the calibrate command to complete. */
|
||||
while (!(__builtin_arc_lr(QM_SS_CREG_BASE + QM_SS_IO_CREG_SLV0_OBSR) &
|
||||
QM_SS_ADC_CAL_ACK)) {
|
||||
QM_SS_IO_CREG_SLV0_OBSR_ADC_CAL_ACK)) {
|
||||
}
|
||||
|
||||
/* Clear the calibration request reg and wait for it to complete. */
|
||||
QM_SS_REG_AUX_NAND(QM_SS_CREG_BASE + QM_SS_IO_CREG_MST0_CTRL,
|
||||
QM_SS_ADC_CAL_REQ);
|
||||
QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_REQ);
|
||||
while (__builtin_arc_lr(QM_SS_CREG_BASE + QM_SS_IO_CREG_SLV0_OBSR) &
|
||||
QM_SS_ADC_CAL_ACK) {
|
||||
QM_SS_IO_CREG_SLV0_OBSR_ADC_CAL_ACK) {
|
||||
}
|
||||
|
||||
/* Disable the ADC. */
|
||||
|
@ -512,9 +516,11 @@ int qm_ss_adc_irq_calibrate(const qm_ss_adc_t adc,
|
|||
|
||||
/* Issue the start calibrate command. */
|
||||
creg = __builtin_arc_lr(QM_SS_CREG_BASE + QM_SS_IO_CREG_MST0_CTRL);
|
||||
creg &= ~(QM_SS_ADC_CAL_CMD_MASK | QM_SS_ADC_CAL_REQ);
|
||||
creg |= ((QM_SS_ADC_CMD_START_CAL << QM_SS_ADC_CAL_CMD_OFFSET) |
|
||||
QM_SS_ADC_CAL_REQ);
|
||||
creg &= ~(QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_CMD_MASK |
|
||||
QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_REQ);
|
||||
creg |= ((QM_SS_ADC_CMD_START_CAL
|
||||
<< QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_CMD_OFFSET) |
|
||||
QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_REQ);
|
||||
__builtin_arc_sr(creg, QM_SS_CREG_BASE + QM_SS_IO_CREG_MST0_CTRL);
|
||||
|
||||
return 0;
|
||||
|
@ -526,7 +532,7 @@ int qm_ss_adc_set_calibration(const qm_ss_adc_t adc __attribute__((unused)),
|
|||
uint32_t creg, intstat;
|
||||
|
||||
QM_CHECK(adc < QM_SS_ADC_NUM, -EINVAL);
|
||||
QM_CHECK(cal_data <= QM_SS_ADC_CAL_MAX, -EINVAL);
|
||||
QM_CHECK(cal_data <= QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_VAL_MAX, -EINVAL);
|
||||
|
||||
/* Save the state of the calibration interrupt mask. */
|
||||
intstat = QM_SCSS_INT->int_adc_calib_mask & QM_INT_ADC_CALIB_MASK;
|
||||
|
@ -535,23 +541,25 @@ int qm_ss_adc_set_calibration(const qm_ss_adc_t adc __attribute__((unused)),
|
|||
|
||||
/* Issue the load calibrate command. */
|
||||
creg = __builtin_arc_lr(QM_SS_CREG_BASE + QM_SS_IO_CREG_MST0_CTRL);
|
||||
creg &= ~(QM_SS_ADC_CAL_VAL_SET_MASK | QM_SS_ADC_CAL_CMD_MASK |
|
||||
QM_SS_ADC_CAL_REQ);
|
||||
creg |= ((cal_data << QM_SS_ADC_CAL_VAL_SET_OFFSET) |
|
||||
(QM_SS_ADC_CMD_LOAD_CAL << QM_SS_ADC_CAL_CMD_OFFSET) |
|
||||
QM_SS_ADC_CAL_REQ);
|
||||
creg &= ~(QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_VAL_MASK |
|
||||
QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_CMD_MASK |
|
||||
QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_REQ);
|
||||
creg |= ((cal_data << QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_VAL_OFFSET) |
|
||||
(QM_SS_ADC_CMD_LOAD_CAL
|
||||
<< QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_CMD_OFFSET) |
|
||||
QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_REQ);
|
||||
__builtin_arc_sr(creg, QM_SS_CREG_BASE + QM_SS_IO_CREG_MST0_CTRL);
|
||||
|
||||
/* Wait for the calibrate command to complete. */
|
||||
while (!(__builtin_arc_lr(QM_SS_CREG_BASE + QM_SS_IO_CREG_SLV0_OBSR) &
|
||||
QM_SS_ADC_CAL_ACK)) {
|
||||
QM_SS_IO_CREG_SLV0_OBSR_ADC_CAL_ACK)) {
|
||||
}
|
||||
|
||||
/* Clear the calibration request reg and wait for it to complete. */
|
||||
QM_SS_REG_AUX_NAND(QM_SS_CREG_BASE + QM_SS_IO_CREG_MST0_CTRL,
|
||||
QM_SS_ADC_CAL_REQ);
|
||||
QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_REQ);
|
||||
while (__builtin_arc_lr(QM_SS_CREG_BASE + QM_SS_IO_CREG_SLV0_OBSR) &
|
||||
QM_SS_ADC_CAL_ACK) {
|
||||
QM_SS_IO_CREG_SLV0_OBSR_ADC_CAL_ACK) {
|
||||
}
|
||||
|
||||
/* Restore the state of the calibration interrupt mask if necessary. */
|
||||
|
@ -569,8 +577,8 @@ int qm_ss_adc_get_calibration(const qm_ss_adc_t adc __attribute__((unused)),
|
|||
QM_CHECK(NULL != cal, -EINVAL);
|
||||
|
||||
*cal = ((__builtin_arc_lr(QM_SS_CREG_BASE + QM_SS_IO_CREG_SLV0_OBSR) &
|
||||
QM_SS_ADC_CAL_VAL_GET_MASK) >>
|
||||
QM_SS_ADC_CAL_VAL_GET_OFFSET);
|
||||
QM_SS_IO_CREG_SLV0_OBSR_ADC_CAL_VAL_MASK) >>
|
||||
QM_SS_IO_CREG_SLV0_OBSR_ADC_CAL_VAL_OFFSET);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -32,7 +32,7 @@
|
|||
static void (*callback)(void *) = NULL;
|
||||
static void *callback_data;
|
||||
|
||||
static void pt_reset(const qm_scss_aon_t aonc)
|
||||
static void pt_reset(const qm_aonc_t aonc)
|
||||
{
|
||||
static bool first_run = true;
|
||||
uint32_t aonc_cfg;
|
||||
|
@ -45,16 +45,16 @@ static void pt_reset(const qm_scss_aon_t aonc)
|
|||
first_run = false;
|
||||
|
||||
/* Ensure the AON counter is enabled */
|
||||
aonc_cfg = QM_SCSS_AON[aonc].aonc_cfg;
|
||||
QM_SCSS_AON[aonc].aonc_cfg = BIT(0);
|
||||
aonc_cfg = QM_AONC[aonc].aonc_cfg;
|
||||
QM_AONC[aonc].aonc_cfg = BIT(0);
|
||||
|
||||
while (0 == QM_SCSS_AON[aonc].aonc_cnt) {
|
||||
while (0 == QM_AONC[aonc].aonc_cnt) {
|
||||
}
|
||||
|
||||
QM_SCSS_AON[aonc].aonc_cfg = aonc_cfg;
|
||||
QM_AONC[aonc].aonc_cfg = aonc_cfg;
|
||||
}
|
||||
|
||||
QM_SCSS_AON[aonc].aonpt_ctrl |= BIT(1);
|
||||
QM_AONC[aonc].aonpt_ctrl |= BIT(1);
|
||||
}
|
||||
|
||||
QM_ISR_DECLARE(qm_aonpt_isr_0)
|
||||
|
@ -62,46 +62,44 @@ QM_ISR_DECLARE(qm_aonpt_isr_0)
|
|||
if (callback) {
|
||||
(*callback)(callback_data);
|
||||
}
|
||||
|
||||
QM_SCSS_AON[0].aonpt_ctrl |= BIT(0); /* Clear pending interrupts */
|
||||
QM_AONC[0].aonpt_ctrl |= BIT(0); /* Clear pending interrupts */
|
||||
QM_ISR_EOI(QM_IRQ_AONPT_0_VECTOR);
|
||||
}
|
||||
|
||||
int qm_aonc_enable(const qm_scss_aon_t aonc)
|
||||
int qm_aonc_enable(const qm_aonc_t aonc)
|
||||
{
|
||||
QM_CHECK(aonc < QM_SCSS_AON_NUM, -EINVAL);
|
||||
QM_CHECK(aonc < QM_AONC_NUM, -EINVAL);
|
||||
|
||||
QM_SCSS_AON[aonc].aonc_cfg = 0x1;
|
||||
QM_AONC[aonc].aonc_cfg = 0x1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qm_aonc_disable(const qm_scss_aon_t aonc)
|
||||
int qm_aonc_disable(const qm_aonc_t aonc)
|
||||
{
|
||||
QM_CHECK(aonc < QM_SCSS_AON_NUM, -EINVAL);
|
||||
QM_CHECK(aonc < QM_AONC_NUM, -EINVAL);
|
||||
|
||||
QM_SCSS_AON[aonc].aonc_cfg = 0x0;
|
||||
QM_AONC[aonc].aonc_cfg = 0x0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qm_aonc_get_value(const qm_scss_aon_t aonc, uint32_t *const val)
|
||||
int qm_aonc_get_value(const qm_aonc_t aonc, uint32_t *const val)
|
||||
{
|
||||
QM_CHECK(aonc < QM_SCSS_AON_NUM, -EINVAL);
|
||||
QM_CHECK(aonc < QM_AONC_NUM, -EINVAL);
|
||||
QM_CHECK(val != NULL, -EINVAL);
|
||||
|
||||
*val = QM_SCSS_AON[aonc].aonc_cnt;
|
||||
*val = QM_AONC[aonc].aonc_cnt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qm_aonpt_set_config(const qm_scss_aon_t aonc,
|
||||
int qm_aonpt_set_config(const qm_aonc_t aonc,
|
||||
const qm_aonpt_config_t *const cfg)
|
||||
{
|
||||
QM_CHECK(aonc < QM_SCSS_AON_NUM, -EINVAL);
|
||||
QM_CHECK(aonc < QM_AONC_NUM, -EINVAL);
|
||||
QM_CHECK(cfg != NULL, -EINVAL);
|
||||
|
||||
QM_SCSS_AON[aonc].aonpt_ctrl |= BIT(0); /* Clear pending interrupts */
|
||||
QM_SCSS_AON[aonc].aonpt_cfg = cfg->count;
|
||||
QM_AONC[aonc].aonpt_cfg = cfg->count;
|
||||
if (cfg->int_en) {
|
||||
callback = cfg->callback;
|
||||
callback_data = cfg->callback_data;
|
||||
|
@ -113,36 +111,46 @@ int qm_aonpt_set_config(const qm_scss_aon_t aonc,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int qm_aonpt_get_value(const qm_scss_aon_t aonc, uint32_t *const val)
|
||||
int qm_aonpt_get_value(const qm_aonc_t aonc, uint32_t *const val)
|
||||
{
|
||||
QM_CHECK(aonc < QM_SCSS_AON_NUM, -EINVAL);
|
||||
QM_CHECK(aonc < QM_AONC_NUM, -EINVAL);
|
||||
QM_CHECK(val != NULL, -EINVAL);
|
||||
|
||||
*val = QM_SCSS_AON[aonc].aonpt_cnt;
|
||||
*val = QM_AONC[aonc].aonpt_cnt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qm_aonpt_get_status(const qm_scss_aon_t aonc, bool *const status)
|
||||
int qm_aonpt_get_status(const qm_aonc_t aonc, qm_aonpt_status_t *const status)
|
||||
{
|
||||
QM_CHECK(aonc < QM_SCSS_AON_NUM, -EINVAL);
|
||||
QM_CHECK(aonc < QM_AONC_NUM, -EINVAL);
|
||||
QM_CHECK(status != NULL, -EINVAL);
|
||||
|
||||
*status = QM_SCSS_AON[aonc].aonpt_stat & BIT(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qm_aonpt_clear(const qm_scss_aon_t aonc)
|
||||
{
|
||||
QM_CHECK(aonc < QM_SCSS_AON_NUM, -EINVAL);
|
||||
|
||||
QM_SCSS_AON[aonc].aonpt_ctrl |= BIT(0);
|
||||
#if (HAS_AONPT_BUSY_BIT)
|
||||
if (QM_AON_COUNTER[aonc]->aonpt_stat & BIT(1)) {
|
||||
*status = QM_AONPT_BUSY;
|
||||
} else
|
||||
#endif
|
||||
if (QM_AONC[aonc].aonpt_stat & BIT(0)) {
|
||||
*status = QM_AONPT_EXPIRED;
|
||||
} else {
|
||||
*status = QM_AONPT_READY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qm_aonpt_reset(const qm_scss_aon_t aonc)
|
||||
int qm_aonpt_clear(const qm_aonc_t aonc)
|
||||
{
|
||||
QM_CHECK(aonc < QM_SCSS_AON_NUM, -EINVAL);
|
||||
QM_CHECK(aonc < QM_AONC_NUM, -EINVAL);
|
||||
|
||||
QM_AONC[aonc].aonpt_ctrl |= BIT(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qm_aonpt_reset(const qm_aonc_t aonc)
|
||||
{
|
||||
QM_CHECK(aonc < QM_AONC_NUM, -EINVAL);
|
||||
|
||||
pt_reset(aonc);
|
||||
|
|
@ -38,6 +38,10 @@
|
|||
#define STANDARD_TIMEOUT_MICROSECOND (1000)
|
||||
#define ONE_MICROSECOND (1)
|
||||
|
||||
/* Temporary LLP values while waiting for linked list initialization . */
|
||||
#define LLP_LL_TO_BE_SET_MULTI_LL BIT(2)
|
||||
#define LLP_LL_TO_BE_SET_MULTI_LL_CIRCULAR BIT(3)
|
||||
|
||||
/* Set specific register bits */
|
||||
#define UPDATE_REG_BITS(reg, value, offset, mask) \
|
||||
{ \
|
||||
|
@ -49,13 +53,6 @@
|
|||
/* Mask for all supported channels */
|
||||
#define CHANNEL_MASK_ALL (BIT(QM_DMA_CHANNEL_NUM) - 1)
|
||||
|
||||
/*
|
||||
* DMA Transfer Type
|
||||
*/
|
||||
typedef enum {
|
||||
QM_DMA_TYPE_SINGLE = 0x0, /**< Single block mode. */
|
||||
} dma_transfer_type_t;
|
||||
|
||||
/*
|
||||
* DMA address increment type.
|
||||
*/
|
||||
|
@ -75,6 +72,25 @@ typedef struct dma_cfg_prv_t {
|
|||
/* DMA channel transfer callback */
|
||||
void (*client_callback)(void *callback_context, uint32_t len,
|
||||
int error_code);
|
||||
|
||||
/* Pointer to latest configured LLI (multiblock linked list). */
|
||||
qm_dma_linked_list_item_t *lli_tail;
|
||||
|
||||
/*
|
||||
* Number of contiguous blocks per buffer (multiblock mode). This is
|
||||
* needed to calculate the total transfer length which is communicated
|
||||
* to the client with the complete callback. In linked list mode, where
|
||||
* more than one buffer (scatter/gather) are used, this is also used to
|
||||
* count single block transfer callbacks so that we know when to invoke
|
||||
* the client callback corresponding to a whole transfered buffer.
|
||||
*/
|
||||
uint16_t num_blocks_per_buffer;
|
||||
|
||||
/*
|
||||
* Number of blocks from buffer that need to be transfered (multiblock
|
||||
* mode), decremented on each single block transfer callback.
|
||||
*/
|
||||
uint16_t num_blocks_remaining;
|
||||
} dma_cfg_prv_t;
|
||||
|
||||
/*
|
||||
|
@ -82,21 +98,34 @@ typedef struct dma_cfg_prv_t {
|
|||
* returned. The value returned is defined in bytes.
|
||||
*/
|
||||
static __inline__ uint32_t
|
||||
get_transfer_length(const qm_dma_t dma, const qm_dma_channel_id_t channel_id)
|
||||
get_transfer_length(const qm_dma_t dma, const qm_dma_channel_id_t channel_id,
|
||||
const dma_cfg_prv_t *prv_cfg)
|
||||
{
|
||||
uint32_t transfer_length;
|
||||
uint32_t source_transfer_width;
|
||||
volatile qm_dma_chan_reg_t *chan_reg =
|
||||
&QM_DMA[dma]->chan_reg[channel_id];
|
||||
uint32_t transfer_length;
|
||||
uint32_t ctrl_low;
|
||||
uint32_t ctrl_high;
|
||||
|
||||
QM_ASSERT(prv_cfg != NULL);
|
||||
if (NULL == prv_cfg->lli_tail) {
|
||||
/* Single block or contiguous multiblock. */
|
||||
volatile qm_dma_chan_reg_t *chan_reg =
|
||||
&QM_DMA[dma]->chan_reg[channel_id];
|
||||
ctrl_low = chan_reg->ctrl_low;
|
||||
ctrl_high = chan_reg->ctrl_high;
|
||||
} else {
|
||||
/* Linked list multiblock. */
|
||||
ctrl_low = prv_cfg->lli_tail->ctrl_low;
|
||||
ctrl_high = prv_cfg->lli_tail->ctrl_high;
|
||||
}
|
||||
|
||||
/* Read the source transfer width register value. */
|
||||
source_transfer_width =
|
||||
((chan_reg->ctrl_low & QM_DMA_CTL_L_SRC_TR_WIDTH_MASK) >>
|
||||
QM_DMA_CTL_L_SRC_TR_WIDTH_OFFSET);
|
||||
source_transfer_width = ((ctrl_low & QM_DMA_CTL_L_SRC_TR_WIDTH_MASK) >>
|
||||
QM_DMA_CTL_L_SRC_TR_WIDTH_OFFSET);
|
||||
|
||||
/* Read the length from the block_ts field. The units of this field
|
||||
* are dependent on the source transfer width. */
|
||||
transfer_length = ((chan_reg->ctrl_high & QM_DMA_CTL_H_BLOCK_TS_MASK) >>
|
||||
transfer_length = ((ctrl_high & QM_DMA_CTL_H_BLOCK_TS_MASK) >>
|
||||
QM_DMA_CTL_H_BLOCK_TS_OFFSET);
|
||||
|
||||
/* To convert this to bytes the transfer length can be shifted using
|
||||
|
@ -207,20 +236,79 @@ dma_interrupt_enable(const qm_dma_t dma, const qm_dma_channel_id_t channel_id)
|
|||
|
||||
static __inline__ int
|
||||
dma_set_transfer_type(const qm_dma_t dma, const qm_dma_channel_id_t channel_id,
|
||||
const dma_transfer_type_t transfer_type)
|
||||
const qm_dma_transfer_type_t transfer_type,
|
||||
const qm_dma_channel_direction_t channel_direction)
|
||||
{
|
||||
volatile qm_dma_chan_reg_t *chan_reg =
|
||||
&QM_DMA[dma]->chan_reg[channel_id];
|
||||
|
||||
/*
|
||||
* Valid for single block and contiguous multiblock, will be later
|
||||
* updated if using linked list multiblock.
|
||||
*/
|
||||
chan_reg->llp_low = 0x0;
|
||||
|
||||
/* Currently only single block is supported */
|
||||
switch (transfer_type) {
|
||||
case QM_DMA_TYPE_SINGLE:
|
||||
chan_reg->llp_low = 0x0;
|
||||
chan_reg->ctrl_low &= ~QM_DMA_CTL_L_LLP_SRC_EN_MASK;
|
||||
chan_reg->ctrl_low &= ~QM_DMA_CTL_L_LLP_DST_EN_MASK;
|
||||
chan_reg->cfg_low &= ~QM_DMA_CFG_L_RELOAD_SRC_MASK;
|
||||
chan_reg->cfg_low &= ~QM_DMA_CFG_L_RELOAD_DST_MASK;
|
||||
break;
|
||||
|
||||
case QM_DMA_TYPE_MULTI_CONT:
|
||||
if (QM_DMA_MEMORY_TO_MEMORY == channel_direction) {
|
||||
/*
|
||||
* The DMA core cannot handle memory to memory
|
||||
* multiblock contiguous transactions.
|
||||
*/
|
||||
return -EINVAL;
|
||||
} else if (QM_DMA_PERIPHERAL_TO_MEMORY == channel_direction) {
|
||||
/* Reload source. */
|
||||
chan_reg->cfg_low |= QM_DMA_CFG_L_RELOAD_SRC_MASK;
|
||||
chan_reg->cfg_low &= ~QM_DMA_CFG_L_RELOAD_DST_MASK;
|
||||
} else {
|
||||
/* Reload destination. */
|
||||
chan_reg->cfg_low |= QM_DMA_CFG_L_RELOAD_DST_MASK;
|
||||
chan_reg->cfg_low &= ~QM_DMA_CFG_L_RELOAD_SRC_MASK;
|
||||
}
|
||||
|
||||
/* Disable block chaining. */
|
||||
chan_reg->ctrl_low &= ~QM_DMA_CTL_L_LLP_SRC_EN_MASK;
|
||||
chan_reg->ctrl_low &= ~QM_DMA_CTL_L_LLP_DST_EN_MASK;
|
||||
break;
|
||||
|
||||
case QM_DMA_TYPE_MULTI_LL_CIRCULAR:
|
||||
chan_reg->llp_low |= LLP_LL_TO_BE_SET_MULTI_LL_CIRCULAR;
|
||||
case QM_DMA_TYPE_MULTI_LL:
|
||||
chan_reg->llp_low |= LLP_LL_TO_BE_SET_MULTI_LL;
|
||||
|
||||
/* Destination status update disable. */
|
||||
chan_reg->cfg_high &= ~QM_DMA_CFG_H_DS_UPD_EN_MASK;
|
||||
|
||||
/* Source status update disable. */
|
||||
chan_reg->cfg_high &= ~QM_DMA_CFG_H_SS_UPD_EN_MASK;
|
||||
|
||||
/* Enable linked lists for source if necessary. */
|
||||
if (QM_DMA_PERIPHERAL_TO_MEMORY == channel_direction) {
|
||||
chan_reg->ctrl_low &= ~QM_DMA_CTL_L_LLP_SRC_EN_MASK;
|
||||
chan_reg->cfg_low |= QM_DMA_CFG_L_RELOAD_SRC_MASK;
|
||||
} else {
|
||||
chan_reg->ctrl_low |= QM_DMA_CTL_L_LLP_SRC_EN_MASK;
|
||||
chan_reg->cfg_low &= ~QM_DMA_CFG_L_RELOAD_SRC_MASK;
|
||||
}
|
||||
|
||||
/* Enable linked lists for destination if necessary. */
|
||||
if (QM_DMA_MEMORY_TO_PERIPHERAL == channel_direction) {
|
||||
chan_reg->ctrl_low &= ~QM_DMA_CTL_L_LLP_DST_EN_MASK;
|
||||
chan_reg->cfg_low |= QM_DMA_CFG_L_RELOAD_DST_MASK;
|
||||
} else {
|
||||
chan_reg->ctrl_low |= QM_DMA_CTL_L_LLP_DST_EN_MASK;
|
||||
chan_reg->cfg_low &= ~QM_DMA_CFG_L_RELOAD_DST_MASK;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
|
@ -38,31 +38,88 @@ dma_cfg_prv_t dma_channel_config[QM_DMA_NUM][QM_DMA_CHANNEL_NUM] = {{{0}}};
|
|||
|
||||
/*
|
||||
* Transfer interrupt handler.
|
||||
* - Single block: TFR triggers an user callback invocation
|
||||
* - Multiblock (contiguous): TFR triggers an user callback invocation, block
|
||||
* interrupts are silent
|
||||
* - Multiblock (linked list): Last block interrupt on each buffer triggers an
|
||||
* user callback invocation, TFR is silent
|
||||
*/
|
||||
static void qm_dma_isr_handler(const qm_dma_t dma,
|
||||
const qm_dma_channel_id_t channel_id)
|
||||
{
|
||||
uint32_t transfer_length;
|
||||
dma_cfg_prv_t *chan_cfg;
|
||||
dma_cfg_prv_t *prv_cfg = &dma_channel_config[dma][channel_id];
|
||||
volatile qm_dma_int_reg_t *int_reg = &QM_DMA[dma]->int_reg;
|
||||
volatile qm_dma_chan_reg_t *chan_reg =
|
||||
&QM_DMA[dma]->chan_reg[channel_id];
|
||||
uint32_t transfer_length =
|
||||
get_transfer_length(dma, channel_id, prv_cfg);
|
||||
|
||||
QM_ASSERT(int_reg->status_int_low & QM_DMA_INT_STATUS_TFR);
|
||||
QM_ASSERT(int_reg->status_tfr_low & BIT(channel_id));
|
||||
QM_ASSERT(int_reg->status_int_low &
|
||||
(QM_DMA_INT_STATUS_TFR | QM_DMA_INT_STATUS_BLOCK));
|
||||
|
||||
/* Clear interrupt */
|
||||
int_reg->clear_tfr_low = BIT(channel_id);
|
||||
if (0 != prv_cfg->num_blocks_per_buffer) {
|
||||
/* Multiblock transfer. */
|
||||
transfer_length *= prv_cfg->num_blocks_per_buffer;
|
||||
}
|
||||
|
||||
/* Mask interrupts for this channel */
|
||||
int_reg->mask_tfr_low = BIT(channel_id) << 8;
|
||||
int_reg->mask_err_low = BIT(channel_id) << 8;
|
||||
if (int_reg->status_int_low & QM_DMA_INT_STATUS_TFR) {
|
||||
QM_ASSERT(int_reg->status_tfr_low & BIT(channel_id));
|
||||
/* Transfer completed, clear interrupt */
|
||||
int_reg->clear_tfr_low = BIT(channel_id);
|
||||
|
||||
/* Call the callback if registered and pass the
|
||||
* transfer length */
|
||||
chan_cfg = &dma_channel_config[dma][channel_id];
|
||||
if (chan_cfg->client_callback) {
|
||||
transfer_length = get_transfer_length(dma, channel_id);
|
||||
chan_cfg->client_callback(chan_cfg->callback_context,
|
||||
transfer_length, 0);
|
||||
/* Mask interrupts for this channel */
|
||||
int_reg->mask_tfr_low = BIT(channel_id) << 8;
|
||||
int_reg->mask_err_low = BIT(channel_id) << 8;
|
||||
|
||||
/*
|
||||
* Call the callback if registered and pass the transfer length.
|
||||
*/
|
||||
if (prv_cfg->client_callback && NULL == prv_cfg->lli_tail) {
|
||||
/* Single block or contiguous multiblock. */
|
||||
prv_cfg->client_callback(prv_cfg->callback_context,
|
||||
transfer_length, 0);
|
||||
}
|
||||
} else {
|
||||
/* Block interrupts are only unmasked in multiblock mode. */
|
||||
QM_ASSERT(int_reg->status_block_low & BIT(channel_id));
|
||||
|
||||
/* Block completed, clear interrupt. */
|
||||
int_reg->clear_block_low = BIT(channel_id);
|
||||
|
||||
prv_cfg->num_blocks_remaining--;
|
||||
|
||||
if (NULL != prv_cfg->lli_tail &&
|
||||
0 == prv_cfg->num_blocks_remaining) {
|
||||
/*
|
||||
* Linked list mode, invoke callback if this is last
|
||||
* block of buffer.
|
||||
*/
|
||||
if (prv_cfg->client_callback) {
|
||||
prv_cfg->client_callback(
|
||||
prv_cfg->callback_context, transfer_length,
|
||||
0);
|
||||
}
|
||||
|
||||
/* Buffer done, set for next buffer. */
|
||||
prv_cfg->num_blocks_remaining =
|
||||
prv_cfg->num_blocks_per_buffer;
|
||||
|
||||
} else if (NULL == prv_cfg->lli_tail) {
|
||||
QM_ASSERT(prv_cfg->num_blocks_remaining <
|
||||
prv_cfg->num_blocks_per_buffer);
|
||||
if (1 == prv_cfg->num_blocks_remaining) {
|
||||
/*
|
||||
* Contiguous mode. We have just processed the
|
||||
* next to last block, clear CFG.RELOAD so
|
||||
* that the next block is the last one to be
|
||||
* transfered.
|
||||
*/
|
||||
chan_reg->cfg_low &=
|
||||
~QM_DMA_CFG_L_RELOAD_SRC_MASK;
|
||||
chan_reg->cfg_low &=
|
||||
~QM_DMA_CFG_L_RELOAD_DST_MASK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -223,8 +280,9 @@ int qm_dma_channel_set_config(const qm_dma_t dma,
|
|||
int return_code;
|
||||
|
||||
/* Set the transfer type. Only one currently supported */
|
||||
return_code =
|
||||
dma_set_transfer_type(dma, channel_id, QM_DMA_TYPE_SINGLE);
|
||||
return_code = dma_set_transfer_type(dma, channel_id,
|
||||
channel_config->transfer_type,
|
||||
channel_config->channel_direction);
|
||||
if (return_code) {
|
||||
return return_code;
|
||||
}
|
||||
|
@ -286,6 +344,12 @@ int qm_dma_channel_set_config(const qm_dma_t dma,
|
|||
/* Save the callback provided by DMA client */
|
||||
chan_cfg->client_callback = channel_config->client_callback;
|
||||
|
||||
/* Multiblock linked list not configured. */
|
||||
chan_cfg->lli_tail = NULL;
|
||||
|
||||
/* Multiblock number of blocks per buffer (LL and contiguous modes). */
|
||||
chan_cfg->num_blocks_per_buffer = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -315,6 +379,182 @@ int qm_dma_transfer_set_config(const qm_dma_t dma,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Populate a linked list. */
|
||||
static qm_dma_linked_list_item_t *
|
||||
dma_linked_list_init(const qm_dma_multi_transfer_t *multi_transfer,
|
||||
uint32_t ctrl_low, uint32_t tail_pointing_lli)
|
||||
{
|
||||
uint32_t source_address = (uint32_t)multi_transfer->source_address;
|
||||
uint32_t destination_address =
|
||||
(uint32_t)multi_transfer->destination_address;
|
||||
/*
|
||||
* Extracted source/destination increment type, used to calculate
|
||||
* address increment between consecutive blocks.
|
||||
*/
|
||||
qm_dma_address_increment_t source_address_inc_type =
|
||||
(ctrl_low & QM_DMA_CTL_L_SINC_MASK) >> QM_DMA_CTL_L_SINC_OFFSET;
|
||||
qm_dma_address_increment_t destination_address_inc_type =
|
||||
(ctrl_low & QM_DMA_CTL_L_DINC_MASK) >> QM_DMA_CTL_L_DINC_OFFSET;
|
||||
QM_ASSERT(source_address_inc_type == QM_DMA_ADDRESS_INCREMENT ||
|
||||
source_address_inc_type == QM_DMA_ADDRESS_NO_CHANGE);
|
||||
QM_ASSERT(destination_address_inc_type == QM_DMA_ADDRESS_INCREMENT ||
|
||||
destination_address_inc_type == QM_DMA_ADDRESS_NO_CHANGE);
|
||||
/* Source/destination address increment between consecutive blocks. */
|
||||
uint32_t source_inc =
|
||||
(source_address_inc_type == QM_DMA_ADDRESS_INCREMENT)
|
||||
? multi_transfer->block_size
|
||||
: 0;
|
||||
uint32_t destination_inc =
|
||||
(destination_address_inc_type == QM_DMA_ADDRESS_INCREMENT)
|
||||
? multi_transfer->block_size
|
||||
: 0;
|
||||
/* Linked list node iteration variable. */
|
||||
qm_dma_linked_list_item_t *lli = multi_transfer->linked_list_first;
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < multi_transfer->num_blocks; i++) {
|
||||
lli->source_address = source_address;
|
||||
lli->destination_address = destination_address;
|
||||
lli->ctrl_low = ctrl_low;
|
||||
lli->ctrl_high = multi_transfer->block_size;
|
||||
if (i < (uint32_t)(multi_transfer->num_blocks - 1)) {
|
||||
lli->linked_list_address =
|
||||
(uint32_t)(qm_dma_linked_list_item_t *)(lli + 1);
|
||||
lli++;
|
||||
source_address += source_inc;
|
||||
destination_address += destination_inc;
|
||||
} else {
|
||||
/* Last node. */
|
||||
lli->linked_list_address = tail_pointing_lli;
|
||||
}
|
||||
}
|
||||
|
||||
/* Last node of the populated linked list. */
|
||||
return lli;
|
||||
}
|
||||
|
||||
int qm_dma_multi_transfer_set_config(
|
||||
const qm_dma_t dma, const qm_dma_channel_id_t channel_id,
|
||||
qm_dma_multi_transfer_t *const multi_transfer_config)
|
||||
{
|
||||
QM_CHECK(dma < QM_DMA_NUM, -EINVAL);
|
||||
QM_CHECK(channel_id < QM_DMA_CHANNEL_NUM, -EINVAL);
|
||||
QM_CHECK(multi_transfer_config != NULL, -EINVAL);
|
||||
QM_CHECK(multi_transfer_config->source_address != NULL, -EINVAL);
|
||||
QM_CHECK(multi_transfer_config->destination_address != NULL, -EINVAL);
|
||||
QM_CHECK(multi_transfer_config->block_size >= QM_DMA_CTL_H_BLOCK_TS_MIN,
|
||||
-EINVAL);
|
||||
QM_CHECK(multi_transfer_config->block_size <= QM_DMA_CTL_H_BLOCK_TS_MAX,
|
||||
-EINVAL);
|
||||
QM_CHECK(multi_transfer_config->num_blocks > 0, -EINVAL);
|
||||
|
||||
dma_cfg_prv_t *prv_cfg = &dma_channel_config[dma][channel_id];
|
||||
/*
|
||||
* Node to which last node points to, 0 on linear linked lists or first
|
||||
* node on circular linked lists.
|
||||
*/
|
||||
uint32_t tail_pointing_lli;
|
||||
|
||||
if (NULL == prv_cfg->lli_tail) {
|
||||
/* First call to this function after DMA channel config. */
|
||||
volatile qm_dma_chan_reg_t *chan_reg =
|
||||
&QM_DMA[dma]->chan_reg[channel_id];
|
||||
|
||||
if (0 == chan_reg->llp_low) {
|
||||
/* Contiguous multiblock transfer. */
|
||||
dma_set_source_address(
|
||||
dma, channel_id,
|
||||
(uint32_t)multi_transfer_config->source_address);
|
||||
dma_set_destination_address(
|
||||
dma, channel_id, (uint32_t)multi_transfer_config
|
||||
->destination_address);
|
||||
dma_set_block_size(dma, channel_id,
|
||||
multi_transfer_config->block_size);
|
||||
|
||||
} else if (multi_transfer_config->linked_list_first != NULL &&
|
||||
((uint32_t)multi_transfer_config->linked_list_first &
|
||||
0x3) == 0) {
|
||||
/*
|
||||
* Linked list multiblock tranfer (uninitialized). User
|
||||
* allocated linked list memory needs to be 4-byte
|
||||
* alligned.
|
||||
*/
|
||||
QM_ASSERT((uint32_t)chan_reg->llp_low &
|
||||
LLP_LL_TO_BE_SET_MULTI_LL);
|
||||
QM_ASSERT(0 == ((uint32_t)chan_reg->llp_low &
|
||||
~(LLP_LL_TO_BE_SET_MULTI_LL |
|
||||
LLP_LL_TO_BE_SET_MULTI_LL_CIRCULAR)));
|
||||
/*
|
||||
* With circular operation, the last LLI node should
|
||||
* point to the first one (this node).
|
||||
*/
|
||||
tail_pointing_lli =
|
||||
(chan_reg->llp_low &
|
||||
LLP_LL_TO_BE_SET_MULTI_LL_CIRCULAR)
|
||||
? (uint32_t)
|
||||
multi_transfer_config->linked_list_first
|
||||
: 0;
|
||||
|
||||
/* Initialize LLIs using CTL drom DMA register (plus
|
||||
* INT_EN bit). */
|
||||
prv_cfg->lli_tail = dma_linked_list_init(
|
||||
multi_transfer_config,
|
||||
chan_reg->ctrl_low | QM_DMA_CTL_L_INT_EN_MASK,
|
||||
tail_pointing_lli);
|
||||
|
||||
/* Point DMA LLP register to this LLI. */
|
||||
chan_reg->llp_low =
|
||||
(uint32_t)multi_transfer_config->linked_list_first;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize block counting internal variables, needed in ISR
|
||||
* to manage client callback invocations.
|
||||
*/
|
||||
prv_cfg->num_blocks_per_buffer =
|
||||
multi_transfer_config->num_blocks;
|
||||
prv_cfg->num_blocks_remaining =
|
||||
multi_transfer_config->num_blocks;
|
||||
|
||||
} else {
|
||||
/*
|
||||
* Linked list multiblock transfer (additional appended LLIs).
|
||||
* The number of blocks needs to match the number of blocks on
|
||||
* previous calls to this function (we only allow scatter/gather
|
||||
* buffers of same size).
|
||||
*/
|
||||
if (prv_cfg->num_blocks_per_buffer !=
|
||||
multi_transfer_config->num_blocks) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reference to NULL (linear LL) or the first LLI node (circular
|
||||
* LL), extracted from previously configured linked list.
|
||||
*/
|
||||
tail_pointing_lli = prv_cfg->lli_tail->linked_list_address;
|
||||
|
||||
/* Point last previously configured linked list to this node. */
|
||||
prv_cfg->lli_tail->linked_list_address =
|
||||
(uint32_t)multi_transfer_config->linked_list_first;
|
||||
|
||||
/*
|
||||
* Initialize LLI using CTL from last previously configured LLI,
|
||||
* returning a pointer to the new tail node.
|
||||
*/
|
||||
prv_cfg->lli_tail = dma_linked_list_init(
|
||||
multi_transfer_config, prv_cfg->lli_tail->ctrl_low,
|
||||
tail_pointing_lli);
|
||||
|
||||
QM_ASSERT(prv_cfg->lli_tail->linked_list_address ==
|
||||
tail_pointing_lli);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qm_dma_transfer_start(const qm_dma_t dma,
|
||||
const qm_dma_channel_id_t channel_id)
|
||||
{
|
||||
|
@ -322,11 +562,18 @@ int qm_dma_transfer_start(const qm_dma_t dma,
|
|||
QM_CHECK(channel_id < QM_DMA_CHANNEL_NUM, -EINVAL);
|
||||
|
||||
volatile qm_dma_int_reg_t *int_reg = &QM_DMA[dma]->int_reg;
|
||||
dma_cfg_prv_t *prv_cfg = &dma_channel_config[dma][channel_id];
|
||||
|
||||
/* Unmask Interrupts */
|
||||
int_reg->mask_tfr_low = ((BIT(channel_id) << 8) | BIT(channel_id));
|
||||
int_reg->mask_err_low = ((BIT(channel_id) << 8) | BIT(channel_id));
|
||||
|
||||
if (prv_cfg->num_blocks_per_buffer != 0) {
|
||||
/* Block interrupts are only unmasked in multiblock mode. */
|
||||
int_reg->mask_block_low =
|
||||
((BIT(channel_id) << 8) | BIT(channel_id));
|
||||
}
|
||||
|
||||
/* Enable interrupts and the channel */
|
||||
dma_interrupt_enable(dma, channel_id);
|
||||
dma_channel_enable(dma, channel_id);
|
||||
|
@ -340,9 +587,7 @@ int qm_dma_transfer_terminate(const qm_dma_t dma,
|
|||
QM_CHECK(dma < QM_DMA_NUM, -EINVAL);
|
||||
QM_CHECK(channel_id < QM_DMA_CHANNEL_NUM, -EINVAL);
|
||||
|
||||
dma_cfg_prv_t *chan_cfg;
|
||||
int return_code;
|
||||
uint32_t transfer_length;
|
||||
volatile qm_dma_int_reg_t *int_reg = &QM_DMA[dma]->int_reg;
|
||||
|
||||
/* Disable interrupts for the channel */
|
||||
|
@ -350,6 +595,7 @@ int qm_dma_transfer_terminate(const qm_dma_t dma,
|
|||
|
||||
/* Mask Interrupts */
|
||||
int_reg->mask_tfr_low = (BIT(channel_id) << 8);
|
||||
int_reg->mask_block_low = (BIT(channel_id) << 8);
|
||||
int_reg->mask_err_low = (BIT(channel_id) << 8);
|
||||
|
||||
/* The channel is disabled and the transfer complete callback is
|
||||
|
@ -357,11 +603,17 @@ int qm_dma_transfer_terminate(const qm_dma_t dma,
|
|||
* transferred before the transfer was stopped. */
|
||||
return_code = dma_channel_disable(dma, channel_id);
|
||||
if (!return_code) {
|
||||
chan_cfg = &dma_channel_config[dma][channel_id];
|
||||
if (chan_cfg->client_callback) {
|
||||
transfer_length = get_transfer_length(dma, channel_id);
|
||||
chan_cfg->client_callback(chan_cfg->callback_context,
|
||||
transfer_length, 0);
|
||||
dma_cfg_prv_t *prv_cfg = &dma_channel_config[dma][channel_id];
|
||||
if (prv_cfg->client_callback) {
|
||||
uint32_t transfer_length =
|
||||
get_transfer_length(dma, channel_id, prv_cfg);
|
||||
if (0 != prv_cfg->num_blocks_per_buffer) {
|
||||
/* Multiblock transfer. */
|
||||
transfer_length *=
|
||||
prv_cfg->num_blocks_per_buffer;
|
||||
}
|
||||
prv_cfg->client_callback(prv_cfg->callback_context,
|
||||
transfer_length, 0);
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -108,7 +108,7 @@ static void qm_ss_i2c_isr_handler(const qm_ss_i2c_t i2c)
|
|||
__builtin_arc_sr(QM_SS_I2C_INTR_MASK_ALL,
|
||||
controller + QM_SS_I2C_INTR_MASK);
|
||||
|
||||
rc = (status & QM_I2C_TX_ABRT_USER_ABRT) ? -ECANCELED : -EIO;
|
||||
rc = (status & QM_SS_I2C_TX_ABRT_USER_ABRT) ? -ECANCELED : -EIO;
|
||||
|
||||
controller_disable(i2c);
|
||||
if (i2c_transfer[i2c]->callback) {
|
||||
|
@ -137,8 +137,8 @@ static void qm_ss_i2c_isr_handler(const qm_ss_i2c_t i2c)
|
|||
*/
|
||||
QM_SS_REG_AUX_NAND(
|
||||
(controller + QM_SS_I2C_INTR_MASK),
|
||||
(QM_SS_I2C_INTR_MASK_RX_FULL |
|
||||
QM_SS_I2C_INTR_MASK_TX_EMPTY));
|
||||
QM_SS_I2C_INTR_MASK_RX_FULL |
|
||||
QM_SS_I2C_INTR_MASK_TX_EMPTY);
|
||||
|
||||
if (i2c_transfer[i2c]->stop) {
|
||||
controller_disable(i2c);
|
||||
|
@ -147,7 +147,7 @@ static void qm_ss_i2c_isr_handler(const qm_ss_i2c_t i2c)
|
|||
if (i2c_transfer[i2c]->callback) {
|
||||
i2c_transfer[i2c]->callback(
|
||||
i2c_transfer[i2c]->callback_data, 0,
|
||||
QM_I2C_IDLE, i2c_read_pos[i2c]);
|
||||
QM_SS_I2C_IDLE, i2c_read_pos[i2c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -191,7 +191,7 @@ static void qm_ss_i2c_isr_handler(const qm_ss_i2c_t i2c)
|
|||
if (i2c_transfer[i2c]->callback) {
|
||||
i2c_transfer[i2c]->callback(
|
||||
i2c_transfer[i2c]->callback_data, 0,
|
||||
QM_I2C_IDLE, i2c_write_pos[i2c]);
|
||||
QM_SS_I2C_IDLE, i2c_write_pos[i2c]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -442,7 +442,7 @@ int qm_ss_i2c_get_status(const qm_ss_i2c_t i2c,
|
|||
/* check if slave or master are active */
|
||||
if (__builtin_arc_lr(controller + QM_SS_I2C_STATUS) &
|
||||
QM_SS_I2C_STATUS_BUSY_MASK) {
|
||||
*status |= QM_I2C_BUSY;
|
||||
*status |= QM_SS_I2C_BUSY;
|
||||
}
|
||||
|
||||
/* check for abort status */
|
|
@ -36,22 +36,49 @@
|
|||
/**
|
||||
* Always-on Counters.
|
||||
*
|
||||
* @note The always on counters are in the 32kHz clock domain. Some register
|
||||
* operations take a minimum of a 32kHz clock cycle to complete.
|
||||
*
|
||||
* @defgroup groupAONC Always-on Counters
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Always-on Periodic Timer configuration type.
|
||||
* Always on counter status.
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* Default Timer Status
|
||||
*/
|
||||
QM_AONPT_READY = 0,
|
||||
/**
|
||||
* Timer expired. Status must be cleared with qm_aonpt_clear().
|
||||
*/
|
||||
QM_AONPT_EXPIRED,
|
||||
#if (HAS_AONPT_BUSY_BIT)
|
||||
/**
|
||||
* Timer is busy. Status after an alarm clear or timer reset has
|
||||
* been initiated. Status must change back to ready before any further
|
||||
* timer configuration to prevent timer lockup.
|
||||
* This is due to the always on counter being in the 32kHz clock
|
||||
* domain.
|
||||
*/
|
||||
QM_AONPT_BUSY,
|
||||
#endif
|
||||
} qm_aonpt_status_t;
|
||||
|
||||
/**
|
||||
* QM Always-on Periodic Timer configuration type.
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t count; /**< Time to count down from in clock cycles.*/
|
||||
bool int_en; /**< Enable/disable the interrupts. */
|
||||
|
||||
/**
|
||||
* User callback.
|
||||
*
|
||||
* @param[in] data User defined data.
|
||||
*/
|
||||
* User callback.
|
||||
*
|
||||
* @param[in] data User defined data.
|
||||
*/
|
||||
void (*callback)(void *data);
|
||||
void *callback_data; /**< Callback data. */
|
||||
} qm_aonpt_config_t;
|
||||
|
@ -65,7 +92,7 @@ typedef struct {
|
|||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_aonc_enable(const qm_scss_aon_t aonc);
|
||||
int qm_aonc_enable(const qm_aonc_t aonc);
|
||||
|
||||
/**
|
||||
* Disable the Always-on Counter.
|
||||
|
@ -76,7 +103,7 @@ int qm_aonc_enable(const qm_scss_aon_t aonc);
|
|||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_aonc_disable(const qm_scss_aon_t aonc);
|
||||
int qm_aonc_disable(const qm_aonc_t aonc);
|
||||
|
||||
/**
|
||||
* Get the current value of the Always-on Counter.
|
||||
|
@ -91,7 +118,7 @@ int qm_aonc_disable(const qm_scss_aon_t aonc);
|
|||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_aonc_get_value(const qm_scss_aon_t aonc, uint32_t *const val);
|
||||
int qm_aonc_get_value(const qm_aonc_t aonc, uint32_t *const val);
|
||||
|
||||
/**
|
||||
* Set the Always-on Periodic Timer configuration.
|
||||
|
@ -109,7 +136,7 @@ int qm_aonc_get_value(const qm_scss_aon_t aonc, uint32_t *const val);
|
|||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_aonpt_set_config(const qm_scss_aon_t aonc,
|
||||
int qm_aonpt_set_config(const qm_aonc_t aonc,
|
||||
const qm_aonpt_config_t *const cfg);
|
||||
|
||||
/**
|
||||
|
@ -128,13 +155,10 @@ int qm_aonpt_set_config(const qm_scss_aon_t aonc,
|
|||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_aonpt_get_value(const qm_scss_aon_t aonc, uint32_t *const val);
|
||||
int qm_aonpt_get_value(const qm_aonc_t aonc, uint32_t *const val);
|
||||
|
||||
/**
|
||||
* Get the current status of the Always-on Periodic Timer.
|
||||
*
|
||||
* Returns true if the timer has expired. This will continue to return true
|
||||
* until it is cleared with qm_aonpt_clear().
|
||||
* Get the current status of an Always-on Periodic Timer.
|
||||
*
|
||||
* @param[in] aonc Always-on counter to read.
|
||||
* @param[out] status Status of the Always-on Periodic Timer.
|
||||
|
@ -144,7 +168,7 @@ int qm_aonpt_get_value(const qm_scss_aon_t aonc, uint32_t *const val);
|
|||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_aonpt_get_status(const qm_scss_aon_t aonc, bool *const status);
|
||||
int qm_aonpt_get_status(const qm_aonc_t aonc, qm_aonpt_status_t *const status);
|
||||
|
||||
/**
|
||||
* Clear the status of the Always-on Periodic Timer.
|
||||
|
@ -158,7 +182,7 @@ int qm_aonpt_get_status(const qm_scss_aon_t aonc, bool *const status);
|
|||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_aonpt_clear(const qm_scss_aon_t aonc);
|
||||
int qm_aonpt_clear(const qm_aonc_t aonc);
|
||||
|
||||
/**
|
||||
* Reset the Always-on Periodic Timer back to the configured value.
|
||||
|
@ -169,9 +193,10 @@ int qm_aonpt_clear(const qm_scss_aon_t aonc);
|
|||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_aonpt_reset(const qm_scss_aon_t aonc);
|
||||
int qm_aonpt_reset(const qm_aonc_t aonc);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* __QM_AON_COUNTERS_H__ */
|
||||
|
|
|
@ -50,6 +50,10 @@ typedef struct {
|
|||
uint32_t reference; /**< Reference voltage, 1b: VREF; 0b: AR_PIN. */
|
||||
uint32_t polarity; /**< 0b: input>ref; 1b: input<ref */
|
||||
uint32_t power; /**< 1b: Normal mode; 0b:Power-down/Shutdown mode */
|
||||
#if HAS_COMPARATOR_VREF2
|
||||
/**< 0b: VREF_1; 1b: VREF_2; When reference is external */
|
||||
uint32_t ar_pad;
|
||||
#endif /* HAS_COMPARATOR_VREF2 */
|
||||
|
||||
/**
|
||||
* Transfer callback.
|
||||
|
|
|
@ -85,6 +85,17 @@ typedef enum {
|
|||
QM_DMA_PERIPHERAL_TO_MEMORY = 0x2 /**< Peripheral to memory transfer. */
|
||||
} qm_dma_channel_direction_t;
|
||||
|
||||
/*
|
||||
* DMA Transfer Type
|
||||
*/
|
||||
typedef enum {
|
||||
QM_DMA_TYPE_SINGLE, /**< Single block mode. */
|
||||
QM_DMA_TYPE_MULTI_CONT, /**< Contiguous multiblock mode. */
|
||||
QM_DMA_TYPE_MULTI_LL, /**< Link list multiblock mode. */
|
||||
QM_DMA_TYPE_MULTI_LL_CIRCULAR /**< Link list multiblock mode with cyclic
|
||||
operation. */
|
||||
} qm_dma_transfer_type_t;
|
||||
|
||||
/**
|
||||
* DMA channel configuration structure
|
||||
*/
|
||||
|
@ -110,6 +121,9 @@ typedef struct {
|
|||
/** DMA destination burst length */
|
||||
qm_dma_burst_length_t destination_burst_length;
|
||||
|
||||
/** DMA transfer type */
|
||||
qm_dma_transfer_type_t transfer_type;
|
||||
|
||||
/**
|
||||
* Client callback for DMA transfer ISR
|
||||
*
|
||||
|
@ -124,8 +138,22 @@ typedef struct {
|
|||
void *callback_context;
|
||||
} qm_dma_channel_config_t;
|
||||
|
||||
/*
|
||||
* Multiblock linked list node structure. The client does not need to know the
|
||||
* internals of this struct but only its size, so that the correct memory for
|
||||
* the linked list can be allocated (one node per DMA transfer block).
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t source_address; /**< Block source address. */
|
||||
uint32_t destination_address; /**< Block destination address. */
|
||||
uint32_t linked_list_address; /**< Pointer to next LLI. */
|
||||
uint32_t ctrl_low; /**< Bottom half Ctrl register. */
|
||||
uint32_t ctrl_high; /**< Top half Ctrl register. */
|
||||
/**< Destination/source status writebacks are disabled. */
|
||||
} qm_dma_linked_list_item_t;
|
||||
|
||||
/**
|
||||
* DMA transfer configuration structure
|
||||
* DMA single block transfer configuration structure
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t block_size; /**< DMA block size, Min = 1, Max = 4095. */
|
||||
|
@ -134,6 +162,20 @@ typedef struct {
|
|||
|
||||
} qm_dma_transfer_t;
|
||||
|
||||
/**
|
||||
* DMA multiblock transfer configuration structure
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t *source_address; /**< First block source address. */
|
||||
uint32_t *destination_address; /**< First block destination address. */
|
||||
uint16_t block_size; /**< DMA block size, Min = 1, Max = 4095. */
|
||||
uint16_t
|
||||
num_blocks; /**< Number of contiguous blocks to be transfered. */
|
||||
qm_dma_linked_list_item_t *linked_list_first; /**< First block LLI
|
||||
descriptor or NULL
|
||||
(contiguous mode) */
|
||||
} qm_dma_multi_transfer_t;
|
||||
|
||||
/**
|
||||
* Initialise the DMA controller.
|
||||
*
|
||||
|
@ -156,10 +198,10 @@ int qm_dma_init(const qm_dma_t dma);
|
|||
* Setup a DMA channel configuration.
|
||||
*
|
||||
* Configures the channel source width, burst size, channel direction,
|
||||
* handshaking interface and registers the client callback and callback
|
||||
* context. qm_dma_init() must first be called before configuring
|
||||
* a channel. This function only needs to be called once unless
|
||||
* a channel is being repurposed.
|
||||
* handshaking interface, transfer type and registers the client callback and
|
||||
* callback context. qm_dma_init() must first be called before configuring a
|
||||
* channel. This function only needs to be called once unless a channel is being
|
||||
* repurposed or its transfer type is changed.
|
||||
*
|
||||
* @param[in] dma DMA instance.
|
||||
* @param[in] channel_id The channel to start.
|
||||
|
@ -175,7 +217,7 @@ int qm_dma_channel_set_config(const qm_dma_t dma,
|
|||
qm_dma_channel_config_t *const channel_config);
|
||||
|
||||
/**
|
||||
* Setup a DMA channel transfer.
|
||||
* Setup a DMA single block transfer.
|
||||
*
|
||||
* Configure the source address,destination addresses and block size.
|
||||
* qm_dma_channel_set_config() must first be called before
|
||||
|
@ -197,6 +239,50 @@ int qm_dma_transfer_set_config(const qm_dma_t dma,
|
|||
const qm_dma_channel_id_t channel_id,
|
||||
qm_dma_transfer_t *const transfer_config);
|
||||
|
||||
/**
|
||||
* Setup a DMA multiblock transfer.
|
||||
*
|
||||
* If the DMA channel has been configured for contiguous multiblock transfers,
|
||||
* this function sets the source address, destination address, block size and
|
||||
* number of block parameters needed to perform a continguous multiblock
|
||||
* transfer. The linked_list_first parameter in the transfer struct is ignored.
|
||||
*
|
||||
* If the DMA channel has been configured for linked-list multiblock transfers,
|
||||
* this function populates a linked list in the client memory area pointed at
|
||||
* by the linked_list_first parameter in the transfer struct, using the provided
|
||||
* parameters source address, destination address, block size and number of
|
||||
* blocks (equal to the number of LLIs). This function may be called repeteadly
|
||||
* in order to add different client buffers for transmission/reception that are
|
||||
* not contiguous in memory (scatter-gather) in a buffer chain fashion. When
|
||||
* calling qm_dma_transfer_start, the DMA core sees a single linked list built
|
||||
* using consecutive calls to this function. Furthermore, if the transfer type
|
||||
* is linked-list cyclic, the linked_list_address parameter of the last LLI
|
||||
* points at the first LLI. The client needs to allocate enough memory starting
|
||||
* at linked_list_first for the whole set of LLIs to fit, i.e. (num_blocks *
|
||||
* sizeof(qm_dma_linked_list_item_t)).
|
||||
*
|
||||
* The DMA driver manages the block interrupts so that only when the last block
|
||||
* of a buffer has been transfered, the client callback is invoked. Note that
|
||||
* in linked-list mode, each buffer transfer results on a client callback, and
|
||||
* all buffers need to contain the same number of blocks.
|
||||
*
|
||||
* qm_dma_multi_transfer_set_config() must be called before starting every
|
||||
* transfer, even if the addresses, block size and other configuration
|
||||
* information remain unchanged.
|
||||
*
|
||||
* @param[in] dma DMA instance.
|
||||
* @param[in] channel_id The channel to start.
|
||||
* @param[in] multi_transfer_config The transfer DMA configuration as defined by
|
||||
* the dma client. This must not be NULL.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_dma_multi_transfer_set_config(
|
||||
const qm_dma_t dma, const qm_dma_channel_id_t channel_id,
|
||||
qm_dma_multi_transfer_t *const multi_transfer_config);
|
||||
|
||||
/**
|
||||
* Start a DMA transfer.
|
||||
*
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include "qm_common.h"
|
||||
#include "qm_soc_regs.h"
|
||||
|
||||
/**
|
||||
* Flash controller.
|
||||
*
|
||||
|
@ -39,46 +40,6 @@
|
|||
* @{
|
||||
*/
|
||||
|
||||
/* Flash mask to clear timing. */
|
||||
#define QM_FLASH_TMG_DEF_MASK (0xFFFFFC00)
|
||||
/* Flash mask to clear micro seconds. */
|
||||
#define QM_FLASH_MICRO_SEC_COUNT_MASK (0x3F)
|
||||
/* Flash mask to clear wait state. */
|
||||
#define QM_FLASH_WAIT_STATE_MASK (0x3C0)
|
||||
/* Flash wait state offset bit. */
|
||||
#define QM_FLASH_WAIT_STATE_OFFSET (6)
|
||||
/* Flash write disable offset bit. */
|
||||
#define QM_FLASH_WRITE_DISABLE_OFFSET (4)
|
||||
/* Flash write disable value. */
|
||||
#define QM_FLASH_WRITE_DISABLE_VAL BIT(4)
|
||||
|
||||
/* Flash page size in dwords. */
|
||||
#define QM_FLASH_PAGE_SIZE_DWORDS (0x200)
|
||||
/* Flash page size in bytes. */
|
||||
#define QM_FLASH_PAGE_SIZE_BYTES (0x800)
|
||||
/* Flash page size in bits. */
|
||||
#define QM_FLASH_PAGE_SIZE_BITS (11)
|
||||
|
||||
/* Flash page erase request. */
|
||||
#define ER_REQ BIT(1)
|
||||
/* Flash page erase done. */
|
||||
#define ER_DONE (1)
|
||||
/* Flash page write request. */
|
||||
#define WR_REQ (1)
|
||||
/* Flash page write done. */
|
||||
#define WR_DONE BIT(1)
|
||||
|
||||
/* Flash write address offset. */
|
||||
#define WR_ADDR_OFFSET (2)
|
||||
/* Flash perform mass erase includes OTP region. */
|
||||
#define MASS_ERASE_INFO BIT(6)
|
||||
/* Flash perform mass erase. */
|
||||
#define MASS_ERASE BIT(7)
|
||||
|
||||
#define QM_FLASH_ADDRESS_MASK (0x7FF)
|
||||
/* Increment by 4 bytes each time, but there is an offset of 2, so 0x10. */
|
||||
#define QM_FLASH_ADDR_INC (0x10)
|
||||
|
||||
/**
|
||||
* Flash region enum.
|
||||
*/
|
||||
|
@ -95,8 +56,8 @@ typedef enum {
|
|||
* Flash write disable / enable enum.
|
||||
*/
|
||||
typedef enum {
|
||||
QM_FLASH_WRITE_ENABLE, /**< Flash write enable. */
|
||||
QM_FLASH_WRITE_DISABLE /**< Flash write disable. */
|
||||
QM_FLASH_WRITE_ENABLE = 0, /**< Flash write enable. */
|
||||
QM_FLASH_WRITE_DISABLE /**< Flash write disable. */
|
||||
} qm_flash_disable_t;
|
||||
|
||||
/**
|
||||
|
@ -104,7 +65,12 @@ typedef enum {
|
|||
*/
|
||||
typedef struct {
|
||||
uint8_t wait_states; /**< Read wait state. */
|
||||
uint8_t us_count; /**< Number of clocks in a microsecond. */
|
||||
|
||||
/**
|
||||
* Number of clocks in a microsecond. Needed for program/erase
|
||||
* operations.
|
||||
*/
|
||||
uint8_t us_count;
|
||||
qm_flash_disable_t write_disable; /**< Write disable. */
|
||||
} qm_flash_config_t;
|
||||
|
||||
|
@ -113,7 +79,7 @@ typedef struct {
|
|||
*
|
||||
* The configuration includes timing and behavioral settings.
|
||||
*
|
||||
* Note: when switching SoC to a higher frequency, flash controllers must be
|
||||
* @note: when switching SoC to a higher frequency, flash controllers must be
|
||||
* reconfigured to reflect settings associated with higher frequency BEFORE SoC
|
||||
* frequency is changed. On the other hand, when switching SoC to a lower
|
||||
* frequency, flash controller must be reconfigured only 6 NOP instructions
|
||||
|
@ -133,9 +99,7 @@ int qm_flash_set_config(const qm_flash_t flash,
|
|||
/**
|
||||
* Write 4 bytes of data to Flash.
|
||||
*
|
||||
* Brownout check is performed before initiating the write.
|
||||
*
|
||||
* Note: this function performs a write operation only; page erase may be
|
||||
* @note: this function performs a write operation only; page erase may be
|
||||
* needed if the page is already programmed.
|
||||
*
|
||||
* @param[in] flash Flash controller index.
|
||||
|
@ -153,10 +117,9 @@ int qm_flash_word_write(const qm_flash_t flash, const qm_flash_region_t region,
|
|||
/**
|
||||
* Write multiple of 4 bytes of data to Flash.
|
||||
*
|
||||
* Brownout check is performed before initiating the write. The page is erased,
|
||||
* and then written to.
|
||||
* The page is erased, and then written to.
|
||||
*
|
||||
* NOTE: Since this operation may take some time to complete, the caller is
|
||||
* @note: Since this operation may take some time to complete, the caller is
|
||||
* responsible for ensuring that the watchdog timer does not elapse in the
|
||||
* meantime (e.g., by restarting it before calling this function).
|
||||
*
|
||||
|
@ -177,12 +140,11 @@ int qm_flash_page_update(const qm_flash_t flash, const qm_flash_region_t reg,
|
|||
const uint32_t *const data, uint32_t len);
|
||||
|
||||
/**
|
||||
* Write a 2KB flash page.
|
||||
* Write a flash page.
|
||||
*
|
||||
* Brownout check is performed before initiating the write. The page is erased,
|
||||
* and then written to.
|
||||
* The page is erased, and then written to.
|
||||
*
|
||||
* NOTE: Since this operation may take some time to complete, the caller is
|
||||
* @note: Since this operation may take some time to complete, the caller is
|
||||
* responsible for ensuring that the watchdog timer does not elapse in the
|
||||
* meantime (e.g., by restarting it before calling this function).
|
||||
*
|
||||
|
@ -202,8 +164,6 @@ int qm_flash_page_write(const qm_flash_t flash, const qm_flash_region_t region,
|
|||
/**
|
||||
* Erase one page of Flash.
|
||||
*
|
||||
* Brownout check is performed before initiating the write.
|
||||
*
|
||||
* @param[in] flash Flash controller index.
|
||||
* @param[in] region Flash region to address.
|
||||
* @param[in] page_num Page within the Flash controller to erase.
|
||||
|
@ -219,12 +179,11 @@ int qm_flash_page_erase(const qm_flash_t flash, const qm_flash_region_t region,
|
|||
/**
|
||||
* Perform mass erase.
|
||||
*
|
||||
* Perform mass erase on the specified flash controller. Brownout check is
|
||||
* performed before initiating the erase. The mass erase may include the ROM
|
||||
* region, if present and unlocked. Note: it is not possible to mass-erase the
|
||||
* ROM portion separately.
|
||||
* Perform mass erase on the specified flash controller. The mass erase may
|
||||
* include the ROM region, if present and unlocked. Note: it is not possible
|
||||
* to mass-erase the ROM portion separately.
|
||||
*
|
||||
* NOTE: Since this operation may take some time to complete, the caller is
|
||||
* @note: Since this operation may take some time to complete, the caller is
|
||||
* responsible for ensuring that the watchdog timer does not elapse in the
|
||||
* meantime (e.g., by restarting it before calling this function).
|
||||
*
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
* GPIO pin states.
|
||||
*/
|
||||
typedef enum {
|
||||
QM_GPIO_LOW, /**< GPIO low state. */
|
||||
QM_GPIO_LOW = 0, /**< GPIO low state. */
|
||||
QM_GPIO_HIGH, /**< GPIO high state. */
|
||||
QM_GPIO_STATE_NUM /**< Number of GPIO states. */
|
||||
} qm_gpio_state_t;
|
||||
|
@ -122,8 +122,8 @@ int qm_gpio_set_pin(const qm_gpio_t gpio, const uint8_t pin);
|
|||
*
|
||||
* @param[in] gpio GPIO port index.
|
||||
* @param[in] pin Pin of GPIO port to clear.
|
||||
* @return int 0 on success, error code otherwise.
|
||||
*
|
||||
* @return int 0 on success, error code otherwise.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
|
|
|
@ -67,16 +67,16 @@ typedef enum {
|
|||
* QM I2C master / slave mode type.
|
||||
*/
|
||||
typedef enum {
|
||||
QM_I2C_MASTER, /**< Master mode. */
|
||||
QM_I2C_SLAVE /**< Slave mode. */
|
||||
QM_I2C_MASTER = 0, /**< Master mode. */
|
||||
QM_I2C_SLAVE /**< Slave mode. */
|
||||
} qm_i2c_mode_t;
|
||||
|
||||
/**
|
||||
* QM I2C Speed Type.
|
||||
* QM I2C speed type.
|
||||
*/
|
||||
typedef enum {
|
||||
QM_I2C_SPEED_STD = 1, /**< Standard mode (100 Kbps). */
|
||||
QM_I2C_SPEED_FAST = 2, /**< Fast mode (400 Kbps). */
|
||||
QM_I2C_SPEED_FAST = 2, /**< Fast mode (400 Kbps). */
|
||||
QM_I2C_SPEED_FAST_PLUS = 3 /**< Fast plus mode (1 Mbps). */
|
||||
} qm_i2c_speed_t;
|
||||
|
||||
|
@ -87,34 +87,55 @@ typedef enum {
|
|||
QM_I2C_IDLE = 0, /**< Controller idle. */
|
||||
QM_I2C_TX_ABRT_7B_ADDR_NOACK = BIT(0), /**< 7-bit address noack. */
|
||||
QM_I2C_TX_ABRT_10ADDR1_NOACK = BIT(1), /**< 10-bit address noack. */
|
||||
QM_I2C_TX_ABRT_10ADDR2_NOACK = BIT(2), /**< 10-bit second address
|
||||
byte address noack. */
|
||||
QM_I2C_TX_ABRT_TXDATA_NOACK = BIT(3), /**< Tx data noack. */
|
||||
QM_I2C_TX_ABRT_GCALL_NOACK = BIT(4), /**< General call noack. */
|
||||
QM_I2C_TX_ABRT_GCALL_READ = BIT(5), /**< Read after general call. */
|
||||
QM_I2C_TX_ABRT_HS_ACKDET = BIT(6), /**< High Speed master ID ACK. */
|
||||
QM_I2C_TX_ABRT_SBYTE_ACKDET = BIT(7), /**< Start ACK. */
|
||||
QM_I2C_TX_ABRT_HS_NORSTRT = BIT(8), /**< High Speed with restart
|
||||
disabled. */
|
||||
QM_I2C_TX_ABRT_10B_RD_NORSTRT = BIT(10), /**< 10-bit address read and
|
||||
restart disabled. */
|
||||
QM_I2C_TX_ABRT_MASTER_DIS = BIT(11), /**< Master disabled. */
|
||||
QM_I2C_TX_ARB_LOST = BIT(12), /**< Master lost arbitration. */
|
||||
|
||||
/** 10-bit second address byte address noack. */
|
||||
QM_I2C_TX_ABRT_10ADDR2_NOACK = BIT(2),
|
||||
QM_I2C_TX_ABRT_TXDATA_NOACK = BIT(3), /**< Tx data noack. */
|
||||
QM_I2C_TX_ABRT_GCALL_NOACK = BIT(4), /**< General call noack. */
|
||||
QM_I2C_TX_ABRT_GCALL_READ = BIT(5), /**< Read after general call. */
|
||||
QM_I2C_TX_ABRT_HS_ACKDET = BIT(6), /**< High Speed master ID ACK. */
|
||||
QM_I2C_TX_ABRT_SBYTE_ACKDET = BIT(7), /**< Start ACK. */
|
||||
|
||||
/** High Speed with restart disabled. */
|
||||
QM_I2C_TX_ABRT_HS_NORSTRT = BIT(8),
|
||||
|
||||
/** 10-bit address read and restart disabled. */
|
||||
QM_I2C_TX_ABRT_10B_RD_NORSTRT = BIT(10),
|
||||
QM_I2C_TX_ABRT_MASTER_DIS = BIT(11), /**< Master disabled. */
|
||||
QM_I2C_TX_ARB_LOST = BIT(12), /**< Master lost arbitration. */
|
||||
QM_I2C_TX_ABRT_SLVFLUSH_TXFIFO = BIT(13), /**< Slave flush tx FIFO. */
|
||||
QM_I2C_TX_ABRT_SLV_ARBLOST = BIT(14), /**< Slave lost bus. */
|
||||
QM_I2C_TX_ABRT_SLVRD_INTX = BIT(15), /**< Slave read completion. */
|
||||
QM_I2C_TX_ABRT_USER_ABRT = BIT(16), /**< User abort. */
|
||||
QM_I2C_BUSY = BIT(17) /**< Controller busy. */
|
||||
QM_I2C_BUSY = BIT(17), /**< Controller busy. */
|
||||
QM_I2C_TX_ABORT = BIT(18), /**< Tx abort. */
|
||||
QM_I2C_TX_OVER = BIT(19), /**< Tx overflow. */
|
||||
QM_I2C_RX_OVER = BIT(20), /**< Rx overflow. */
|
||||
QM_I2C_RX_UNDER = BIT(21) /**< Rx underflow. */
|
||||
} qm_i2c_status_t;
|
||||
|
||||
/**
|
||||
* QM I2C slave stop detect behaviour
|
||||
*/
|
||||
typedef enum {
|
||||
/** Interrupt regardless of whether this slave is addressed or not. */
|
||||
QM_I2C_SLAVE_INTERRUPT_ALWAYS = 0x0,
|
||||
|
||||
/** Only interrupt if this slave is being addressed. */
|
||||
QM_I2C_SLAVE_INTERRUPT_WHEN_ADDRESSED = 0x1
|
||||
} qm_i2c_slave_stop_t;
|
||||
|
||||
/**
|
||||
* I2C configuration type.
|
||||
*/
|
||||
typedef struct {
|
||||
qm_i2c_speed_t speed; /**< Standard, Fast Mode. */
|
||||
qm_i2c_addr_t address_mode; /**< 7 or 10 bit addressing. */
|
||||
qm_i2c_speed_t speed; /**< Standard, fast or fast plus mode. */
|
||||
qm_i2c_addr_t address_mode; /**< 7 bit or 10 bit addressing. */
|
||||
qm_i2c_mode_t mode; /**< Master or slave mode. */
|
||||
uint16_t slave_addr; /**< I2C address when in slave mode. */
|
||||
|
||||
/** Slave stop detect behaviour */
|
||||
qm_i2c_slave_stop_t stop_detect_behaviour;
|
||||
} qm_i2c_config_t;
|
||||
|
||||
/**
|
||||
|
@ -122,7 +143,7 @@ typedef struct {
|
|||
* Master mode:
|
||||
* - If tx len is 0: perform receive-only transaction.
|
||||
* - If rx len is 0: perform transmit-only transaction.
|
||||
* - Both tx and Rx len not 0: perform a transmit-then-receive
|
||||
* - Both tx and rx len not 0: perform a transmit-then-receive
|
||||
* combined transaction.
|
||||
* Slave mode:
|
||||
* - If read or write exceed the buffer, then wrap around.
|
||||
|
@ -133,9 +154,22 @@ typedef struct {
|
|||
uint8_t *rx; /**< Read data. */
|
||||
uint32_t rx_len; /**< Read buffer length. */
|
||||
bool stop; /**< Generate master STOP. */
|
||||
|
||||
/**
|
||||
* Transfer callback.
|
||||
*
|
||||
* Called after all data is transmitted/received or if the driver
|
||||
* detects an error during the I2C transfer.
|
||||
*
|
||||
* @param[in] data User defined data.
|
||||
* @param[in] rc 0 on success.
|
||||
* Negative @ref errno for possible error codes.
|
||||
* @param[in] status I2C status.
|
||||
* @param[in] len Length of the transfer if successful, 0 otherwise.
|
||||
*/
|
||||
void (*callback)(void *data, int rc, qm_i2c_status_t status,
|
||||
uint32_t len); /**< Callback. */
|
||||
void *callback_data; /**< Callback identifier. */
|
||||
uint32_t len);
|
||||
void *callback_data; /**< User callback data. */
|
||||
} qm_i2c_transfer_t;
|
||||
|
||||
/**
|
||||
|
@ -155,6 +189,7 @@ int qm_i2c_set_config(const qm_i2c_t i2c, const qm_i2c_config_t *const cfg);
|
|||
*
|
||||
* Fine tune I2C clock speed. This will set the SCL low count
|
||||
* and the SCL hi count cycles. To achieve any required speed.
|
||||
*
|
||||
* @param[in] i2c I2C index.
|
||||
* @param[in] speed Bus speed (Standard or Fast. Fast includes Fast+ mode).
|
||||
* @param[in] lo_cnt SCL low count.
|
||||
|
@ -168,10 +203,13 @@ int qm_i2c_set_speed(const qm_i2c_t i2c, const qm_i2c_speed_t speed,
|
|||
const uint16_t lo_cnt, const uint16_t hi_cnt);
|
||||
|
||||
/**
|
||||
* Retrieve I2C status.
|
||||
* Retrieve I2C bus status.
|
||||
*
|
||||
* @param[in] i2c Which I2C to read the status of.
|
||||
* @param[out] status Get i2c status. This must not be NULL.
|
||||
* @param[out] status Current I2C status. This must not be NULL.
|
||||
*
|
||||
* The user may call this function before performing an I2C transfer in order to
|
||||
* guarantee that the I2C interface is available.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
|
@ -187,9 +225,9 @@ int qm_i2c_get_status(const qm_i2c_t i2c, qm_i2c_status_t *const status);
|
|||
* @param[in] i2c Which I2C to write to.
|
||||
* @param[in] slave_addr Address of slave to write to.
|
||||
* @param[in] data Pre-allocated buffer of data to write. This must not be NULL.
|
||||
* @param[in] len length of data to write.
|
||||
* @param[in] len Length of data to write.
|
||||
* @param[in] stop Generate a STOP condition at the end of tx.
|
||||
* @param[out] status Get i2c status.
|
||||
* @param[out] status Get I2C status.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
|
@ -208,9 +246,9 @@ int qm_i2c_master_write(const qm_i2c_t i2c, const uint16_t slave_addr,
|
|||
* @param[in] slave_addr Address of slave device to read from.
|
||||
* @param[out] data Pre-allocated buffer to populate with data. This must not be
|
||||
* NULL.
|
||||
* @param[in] len length of data to read from slave.
|
||||
* @param[in] stop Generate a STOP condition at the end of tx.
|
||||
* @param[out] status Get i2c status.
|
||||
* @param[in] len Length of data to read from slave.
|
||||
* @param[in] stop Generate a STOP condition at the end of rx.
|
||||
* @param[out] status Get I2C status.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
|
@ -241,6 +279,24 @@ int qm_i2c_master_irq_transfer(const qm_i2c_t i2c,
|
|||
const qm_i2c_transfer_t *const xfer,
|
||||
const uint16_t slave_addr);
|
||||
|
||||
/**
|
||||
* Interrupt based slave transfer on I2C.
|
||||
*
|
||||
* Perform an interrupt based slave transfer on the I2C bus. The function will
|
||||
* replenish/empty TX/RX FIFOs on I2C empty/full interrupts.
|
||||
*
|
||||
* @param[in] i2c Which I2C to transfer from.
|
||||
* @param[in] xfer Transfer structure includes write / read buffers, length,
|
||||
* user callback function and the callback context. This must
|
||||
* not be NULL.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_i2c_slave_irq_transfer(const qm_i2c_t i2c,
|
||||
const qm_i2c_transfer_t *const xfer);
|
||||
|
||||
/**
|
||||
* Terminate I2C IRQ transfer.
|
||||
*
|
||||
|
@ -248,7 +304,7 @@ int qm_i2c_master_irq_transfer(const qm_i2c_t i2c,
|
|||
* This will cause the user callback to be called with status
|
||||
* QM_I2C_TX_ABRT_USER_ABRT.
|
||||
*
|
||||
* @param[in] i2c I2C register block pointer.
|
||||
* @param[in] i2c I2C controller identifier.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
|
@ -289,12 +345,12 @@ int qm_i2c_dma_channel_config(const qm_i2c_t i2c,
|
|||
const qm_dma_channel_direction_t direction);
|
||||
|
||||
/**
|
||||
* Perform a DMA-based transfer on the I2C bus.
|
||||
* Perform a DMA based master transfer on the I2C bus.
|
||||
*
|
||||
* Perform a DMA-based transfer on the I2C bus. If the transfer is TX only, it
|
||||
* will enable DMA operation for the controller and start the transfer.
|
||||
* Perform a DMA based master transfer on the I2C bus. If the transfer is TX
|
||||
* only, it will enable DMA operation for the controller and start the transfer.
|
||||
*
|
||||
* If it's an RX only transfer, it will require 2 channels, one for writting the
|
||||
* If it's an RX only transfer, it will require 2 channels, one for writing the
|
||||
* READ commands and another one for reading the bytes from the bus. Both DMA
|
||||
* operations will start in parallel.
|
||||
*
|
||||
|
@ -307,9 +363,9 @@ int qm_i2c_dma_channel_config(const qm_i2c_t i2c,
|
|||
*
|
||||
* @param[in] i2c I2C controller identifier.
|
||||
* @param[in] xfer Structure containing pre-allocated write and read data
|
||||
* buffers and callback functions. This pointer must be kept valid until the
|
||||
* transfer is complete.
|
||||
* @param[in] slave_addr Slave address.
|
||||
* buffers and callback functions. This must not be NULL
|
||||
* and must be kept valid until the transfer is complete.
|
||||
* @param[in] slave_addr Address of slave to transfer data with.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
|
@ -319,6 +375,24 @@ int qm_i2c_master_dma_transfer(const qm_i2c_t i2c,
|
|||
qm_i2c_transfer_t *const xfer,
|
||||
const uint16_t slave_addr);
|
||||
|
||||
/**
|
||||
* Perform a DMA based slave transfer on the I2C bus.
|
||||
*
|
||||
* Note that qm_i2c_dma_channel_config() must first be called in order to
|
||||
* configure all DMA channels needed for a transfer.
|
||||
*
|
||||
* @param[in] i2c I2C controller identifier.
|
||||
* @param[in] xfer Structure containing pre-allocated write and read data
|
||||
* buffers and callback functions. This pointer must be kept
|
||||
* valid until the transfer is complete.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_i2c_slave_dma_transfer(const qm_i2c_t i2c,
|
||||
const qm_i2c_transfer_t *const xfer);
|
||||
|
||||
/**
|
||||
* Terminate any DMA transfer going on on the controller.
|
||||
*
|
||||
|
|
349
ext/hal/qmsi/drivers/include/qm_i2s.h
Normal file
349
ext/hal/qmsi/drivers/include/qm_i2s.h
Normal file
|
@ -0,0 +1,349 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Intel Corporation
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL CORPORATION OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __QM_I2S_H__
|
||||
#define __QM_I2S_H__
|
||||
|
||||
#include "qm_common.h"
|
||||
#include "qm_soc_regs.h"
|
||||
#include "qm_dma.h"
|
||||
|
||||
/**
|
||||
* I2S.
|
||||
*
|
||||
* @defgroup groupI2S I2S
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* I2S master/slave configuration.
|
||||
*/
|
||||
typedef enum {
|
||||
QM_I2S_MASTER = 0, /**< Master configuration selection */
|
||||
QM_I2S_SLAVE /**< Slave configuration selection */
|
||||
} qm_i2s_master_slave_t;
|
||||
|
||||
/**
|
||||
* I2S Audio stream identifiers.
|
||||
*/
|
||||
typedef enum {
|
||||
QM_I2S_AUDIO_STREAM_TRANSMIT = 0, /**< Playback audio stream */
|
||||
QM_I2S_AUDIO_STREAM_RECEIVE /**< Capture audio stream */
|
||||
} qm_i2s_audio_stream_t;
|
||||
|
||||
/**
|
||||
* I2S audio formats.
|
||||
*/
|
||||
typedef enum {
|
||||
QM_I2S_AUDIO_FORMAT_I2S_MODE = 0, /**< I2S Mode audio format */
|
||||
QM_I2S_AUDIO_FORMAT_RIGHT_J, /**< Right justified audio format */
|
||||
QM_I2S_AUDIO_FORMAT_LEFT_J, /**< Left justified audio format */
|
||||
QM_I2S_AUDIO_FORMAT_DSP_MODE /**< DSP mode audio format */
|
||||
} qm_i2s_audio_format_t;
|
||||
|
||||
/**
|
||||
* I2S Audio sample resolution. Resolution ranges between 12 bits and 32 bits.
|
||||
*/
|
||||
typedef enum {
|
||||
/** 12 bits audio sample resolution */
|
||||
QM_I2S_12_BIT_SAMPLE_RESOLUTION = 12,
|
||||
/** 13 bits audio sample resolution */
|
||||
QM_I2S_13_BIT_SAMPLE_RESOLUTION = 13,
|
||||
/** 14 bits audio sample resolution */
|
||||
QM_I2S_14_BIT_SAMPLE_RESOLUTION = 14,
|
||||
/** 15 bits audio sample resolution */
|
||||
QM_I2S_15_BIT_SAMPLE_RESOLUTION = 15,
|
||||
/** 16 bits audio sample resolution */
|
||||
QM_I2S_16_BIT_SAMPLE_RESOLUTION = 16,
|
||||
/** 17 bits audio sample resolution */
|
||||
QM_I2S_17_BIT_SAMPLE_RESOLUTION = 17,
|
||||
/** 18 bits audio sample resolution */
|
||||
QM_I2S_18_BIT_SAMPLE_RESOLUTION = 18,
|
||||
/** 19 bits audio sample resolution */
|
||||
QM_I2S_19_BIT_SAMPLE_RESOLUTION = 19,
|
||||
/** 20 bits audio sample resolution */
|
||||
QM_I2S_20_BIT_SAMPLE_RESOLUTION = 20,
|
||||
/** 21 bits audio sample resolution */
|
||||
QM_I2S_21_BIT_SAMPLE_RESOLUTION = 21,
|
||||
/** 22 bits audio sample resolution */
|
||||
QM_I2S_22_BIT_SAMPLE_RESOLUTION = 22,
|
||||
/** 23 bits audio sample resolution */
|
||||
QM_I2S_23_BIT_SAMPLE_RESOLUTION = 23,
|
||||
/** 24 bits audio sample resolution */
|
||||
QM_I2S_24_BIT_SAMPLE_RESOLUTION = 24,
|
||||
/** 25 bits audio sample resolution */
|
||||
QM_I2S_25_BIT_SAMPLE_RESOLUTION = 25,
|
||||
/** 26 bits audio sample resolution */
|
||||
QM_I2S_26_BIT_SAMPLE_RESOLUTION = 26,
|
||||
/** 27 bits audio sample resolution */
|
||||
QM_I2S_27_BIT_SAMPLE_RESOLUTION = 27,
|
||||
/** 28 bits audio sample resolution */
|
||||
QM_I2S_28_BIT_SAMPLE_RESOLUTION = 28,
|
||||
/** 29 bits audio sample resolution */
|
||||
QM_I2S_29_BIT_SAMPLE_RESOLUTION = 29,
|
||||
/** 30 bits audio sample resolution */
|
||||
QM_I2S_30_BIT_SAMPLE_RESOLUTION = 30,
|
||||
/** 31 bits audio sample resolution */
|
||||
QM_I2S_31_BIT_SAMPLE_RESOLUTION = 31,
|
||||
/** 32 bits audio sample resolution */
|
||||
QM_I2S_32_BIT_SAMPLE_RESOLUTION = 32
|
||||
} qm_i2s_sample_resolution_t;
|
||||
|
||||
/**
|
||||
* I2S Audio rates available.
|
||||
*/
|
||||
typedef enum {
|
||||
QM_I2S_RATE_4000KHZ = 0, /**< 4kHz audio rate */
|
||||
QM_I2S_RATE_8000KHZ, /**< 8kHz audio rate */
|
||||
QM_I2S_RATE_11025KHZ, /**< 11.025kHz audio rate */
|
||||
QM_I2S_RATE_16000KHZ, /**< 16kHz audio rate */
|
||||
QM_I2S_RATE_22050KHZ, /**< 22.05kHz audio rate */
|
||||
QM_I2S_RATE_32000KHZ, /**< 32kHz audio rate */
|
||||
QM_I2S_RATE_44100KHZ, /**< 44.1kHz audio rate */
|
||||
QM_I2S_RATE_48000KHZ, /**< 48kHz audio rate */
|
||||
} qm_i2s_audio_rate_t;
|
||||
|
||||
/**
|
||||
* I2S Audio buffer termination.
|
||||
*/
|
||||
typedef enum {
|
||||
/** Used for single audio playback/recording. */
|
||||
QM_I2S_TERMINATED_BUFFER = 0,
|
||||
QM_I2S_RING_BUFFER /**< Used for continuous audio playback/recording. */
|
||||
} qm_i2s_buffer_mode_t;
|
||||
|
||||
/**
|
||||
* I2S Reference Clock Source Select
|
||||
*/
|
||||
typedef enum {
|
||||
QM_I2S_INT_CLK = 0, /**< Use internal clock. */
|
||||
QM_I2S_MCLK, /**< Take in clock from external source. */
|
||||
} qm_i2s_clk_src_t;
|
||||
|
||||
/**
|
||||
* I2S status type.
|
||||
*/
|
||||
typedef enum {
|
||||
/** Indicates that a FIFO overflow error was detected. */
|
||||
QM_I2S_FIFO_OVERFLOW = BIT(0),
|
||||
/** Indicates that a FIFO underrun error was detected. */
|
||||
QM_I2S_FIFO_UNDERRUN = BIT(1),
|
||||
/** Indicates TX FIFO full interrupt occurred */
|
||||
QM_I2S_TX_FIFO_FULL = BIT(2),
|
||||
/** Indicates TX FIFO almost full interrupt occurred */
|
||||
QM_I2S_TX_FIFO_ALMOST_FULL = BIT(3),
|
||||
/** Indicates TX FIFO almost empty interrupt occurred */
|
||||
QM_I2S_TX_FIFO_ALMOST_EMPTY = BIT(4),
|
||||
/** Indicates TX FIFO empty interrupt occurred */
|
||||
QM_I2S_TX_FIFO_EMPTY = BIT(5),
|
||||
/** Indicates RX FIFO full interrupt occurred */
|
||||
QM_I2S_RX_FIFO_FULL = BIT(6),
|
||||
/** Indicates RX FIFO almost full interrupt occurred */
|
||||
QM_I2S_RX_FIFO_ALMOST_FULL = BIT(7),
|
||||
/** Indicates RX FIFO almost empty interrupt occurred */
|
||||
QM_I2S_RX_FIFO_ALMOST_EMPTY = BIT(8),
|
||||
/** Indicates RX FIFO empty interrupt occurred */
|
||||
QM_I2S_RX_FIFO_EMPTY = BIT(9),
|
||||
/** Indicates that a DMA error was detected */
|
||||
QM_I2S_DMA_ERROR = BIT(10),
|
||||
/** Indicates that DMA operation was completed */
|
||||
QM_I2S_DMA_COMPLETE = BIT(11),
|
||||
} qm_i2s_status_t;
|
||||
|
||||
/**
|
||||
* Ring buffer link definition.
|
||||
*/
|
||||
typedef struct qm_i2s_buffer_link {
|
||||
uint32_t *buff; /**< Pointer to the buffer base address. */
|
||||
/** Pointer to the head of the DMA link list for the buffer link. */
|
||||
qm_dma_lli_item_t *dma_link_head;
|
||||
/** Link list item's pointer to the next link. */
|
||||
struct qm_i2s_buffer_link *next;
|
||||
} qm_i2s_buffer_link_t;
|
||||
|
||||
/**
|
||||
* I2S controller configuration.
|
||||
* Driver instantiates one of these with given parameters for each I2S
|
||||
* channel configured using the "qm_i2s_set_channel_config" function.
|
||||
*/
|
||||
typedef struct {
|
||||
qm_dma_channel_id_t dma_channel; /**< DMA controller Channel ID */
|
||||
qm_i2s_audio_stream_t audio_stream; /**< I2S audio stream identifier */
|
||||
/** I2S audio format configuration */
|
||||
qm_i2s_audio_format_t audio_format;
|
||||
/** I2S Master or Slave configuration */
|
||||
qm_i2s_master_slave_t master_slave;
|
||||
/** Sampling resolution */
|
||||
qm_i2s_sample_resolution_t sample_resolution;
|
||||
qm_i2s_audio_rate_t audio_rate; /**< Audio rate */
|
||||
/** Terminated link list or ring buffer configuration */
|
||||
qm_i2s_buffer_mode_t audio_buff_cfg;
|
||||
/**
|
||||
* DMA block size configuration:
|
||||
* The source and destination transfer width is 32-bits for I2S.
|
||||
* Min = 1, Max = see DMA configuration
|
||||
*/
|
||||
uint32_t block_size;
|
||||
uint32_t num_dma_links; /**< Total number of DMA links. */
|
||||
qm_dma_lli_item_t *dma_link; /**< Pointer to the DMA link list */
|
||||
/** Number of buffer links in the ring buffer. */
|
||||
uint32_t num_buffer_links;
|
||||
qm_i2s_buffer_link_t *buffer_link; /**< Ring buffer head pointer. */
|
||||
/** Number of DMA links per audio buffer. */
|
||||
uint32_t num_dma_link_per_buffer;
|
||||
uint32_t buffer_len; /**< Length of a buffer in the ring buffer. */
|
||||
uint32_t afull_thresh; /**< TX/RX almost full threshold. */
|
||||
uint32_t aempty_thresh; /**< TX/RX almost empty threshold. */
|
||||
|
||||
/**
|
||||
* Transfer callback.
|
||||
*
|
||||
* @param[in] data Callback user data
|
||||
* @param[in] i2s_status I2S status
|
||||
*/
|
||||
void (*callback)(void *data, qm_i2s_status_t i2s_status);
|
||||
void *callback_data; /**< Callback user data. */
|
||||
} qm_i2s_channel_cfg_data_t;
|
||||
|
||||
/**
|
||||
* I2S Clock Configuration
|
||||
*/
|
||||
typedef struct {
|
||||
/** Select Internal NCO or external reference clock for I2S block */
|
||||
qm_i2s_clk_src_t i2s_clock_sel;
|
||||
/**
|
||||
* Used by the driver when configuring I2S reference clock from
|
||||
* the NCO.
|
||||
*/
|
||||
uint32_t i2s_clk_freq;
|
||||
/** Enable MCLK output. */
|
||||
bool i2s_mclk_output_en;
|
||||
/**
|
||||
* MCLK output is generated from the Internal
|
||||
* NCO output, normally \@24.576Mhz, using a divisor.
|
||||
* Valid divisor range is 0 to 4095.
|
||||
* E.g. with a 48kHz data rate, and NCO =
|
||||
* 24.576Mhz, then required MCLK = 256 * data rate = 12.288MHz
|
||||
* MCLK divisor = 2 (24.576Mhz/2 = 12.288MHz)
|
||||
*/
|
||||
uint32_t i2s_mclk_divisor;
|
||||
/**
|
||||
* Informs the driver of frequency of external clock
|
||||
* when it is enabled.
|
||||
*/
|
||||
uint32_t i2s_ext_clk_freq;
|
||||
} qm_i2s_clock_cfg_data_t;
|
||||
|
||||
/**
|
||||
* Function to configure specified I2S controller stream
|
||||
* Configuration parameters must be valid or an error is returned - see return
|
||||
* values below.
|
||||
*
|
||||
* @param [in] i2s I2S controller identifier
|
||||
* @param [in] audio_stream I2S audio_stream identifier
|
||||
* @param [in] config Pointer to configuration structure
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_i2s_dma_channel_config(const qm_i2s_t i2s,
|
||||
const qm_i2s_audio_stream_t audio_stream,
|
||||
const qm_i2s_channel_cfg_data_t *const config);
|
||||
|
||||
/**
|
||||
* Function to place I2S controller into a disabled state.
|
||||
* This function assumes that there is no pending transaction on the I2S
|
||||
* interface in question.
|
||||
* It is the responsibility of the calling application to do so.
|
||||
*
|
||||
* @param [in] i2s I2S controller identifier
|
||||
* @param [in] audio_stream I2S audio_stream identifier
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_i2s_channel_disable(const qm_i2s_t i2s,
|
||||
const qm_i2s_audio_stream_t audio_stream);
|
||||
|
||||
/**
|
||||
* Function to configure and enable I2S clocks
|
||||
* Configuration parameters must be valid or an error is returned - see return
|
||||
* values below.
|
||||
*
|
||||
* @param [in] i2s I2S controller identifier
|
||||
* @param [in] i2s_clk_cfg I2S Clock configuration
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_i2s_set_clock_config(const qm_i2s_t i2s,
|
||||
const qm_i2s_clock_cfg_data_t *const i2s_clk_cfg);
|
||||
|
||||
/**
|
||||
* Function to transmit a block of data to the specified I2S channel.
|
||||
*
|
||||
* @param [in] i2s I2S controller identifier
|
||||
* @param [in] audio_stream I2S audio_stream identifier
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_i2s_dma_transfer(const qm_i2s_t i2s,
|
||||
const qm_i2s_audio_stream_t audio_stream);
|
||||
|
||||
/**
|
||||
* Terminate the current DMA transfer on the given I2S peripheral channel.
|
||||
*
|
||||
* Terminate the current DMA transfer on the I2S channel.
|
||||
* This will cause the relevant callbacks to be invoked.
|
||||
*
|
||||
* In the case the user is doing a continuous transfer using a circular linked
|
||||
* list, it might be useful to fine control at which point in the linked list
|
||||
* that we stop the transfer. To do this, set the relevant linked list item's
|
||||
* "next" item to NULL.
|
||||
*
|
||||
* @param [in] i2s I2S controller identifier
|
||||
* @param [in] config Pointer to configuration structure
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_i2s_dma_transfer_terminate(const qm_i2s_t i2s,
|
||||
qm_i2s_channel_cfg_data_t *const config);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* __QM_I2S_H__ */
|
|
@ -57,15 +57,41 @@
|
|||
typedef void (*qm_isr_t)(struct interrupt_frame *frame);
|
||||
|
||||
/**
|
||||
* Enable interrupt delivery for the SoC.
|
||||
* Unconditionally enable interrupt delivery on the CPU.
|
||||
*/
|
||||
void qm_irq_enable(void);
|
||||
|
||||
/**
|
||||
* Disable interrupt delivery for the SoC.
|
||||
* Unconditionally disable interrupt delivery on the CPU.
|
||||
*/
|
||||
void qm_irq_disable(void);
|
||||
|
||||
/**
|
||||
* Save interrupt state and disable all interrupts on the CPU.
|
||||
*
|
||||
* This routine disables interrupts. It can be called from either interrupt or
|
||||
* non-interrupt context. This routine returns an architecture-dependent
|
||||
* lock-out key representing the "interrupt disable state" prior to the call;
|
||||
* this key can be passed to qm_irq_unlock() to re-enable interrupts.
|
||||
*
|
||||
* This function can be called recursively: it will return a key to return the
|
||||
* state of interrupt locking to the previous level.
|
||||
*
|
||||
* @return An architecture-dependent lock-out key representing the "interrupt
|
||||
* disable state" prior to the call.
|
||||
*
|
||||
*/
|
||||
unsigned int qm_irq_lock(void);
|
||||
|
||||
/**
|
||||
*
|
||||
* Restore previous interrupt state on the CPU saved via qm_irq_lock().
|
||||
*
|
||||
* @param[in] key architecture-dependent lock-out key returned by a previous
|
||||
* invocation of qm_irq_lock().
|
||||
*/
|
||||
void qm_irq_unlock(unsigned int key);
|
||||
|
||||
/**
|
||||
* Unmask a given interrupt line.
|
||||
*
|
||||
|
|
|
@ -314,6 +314,15 @@ QM_ISR_DECLARE(qm_uart_1_isr);
|
|||
*/
|
||||
QM_ISR_DECLARE(qm_wdt_isr_0);
|
||||
|
||||
/**
|
||||
* ISR for USB 0 interrupt.
|
||||
*
|
||||
* This function needs to be registered with
|
||||
* @code qm_irq_request(QM_IRQ_USB_0, qm_usb_0_isr_0);
|
||||
* @endcode if IRQ based transfers are used.
|
||||
*/
|
||||
QM_ISR_DECLARE(qm_usb_0_isr_0);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
|
|
@ -42,19 +42,24 @@
|
|||
*/
|
||||
|
||||
/**
|
||||
* Mailbox status. Those values are tied to HW bit setting and made up of
|
||||
* the bit 0 and bit 1 of the mailbox channel status register.
|
||||
* Mailbox channel status return codes
|
||||
*/
|
||||
typedef enum {
|
||||
/**< No interrupt pending nor any data to consume. */
|
||||
/** No interrupt pending nor any data to consume. */
|
||||
QM_MBOX_CH_IDLE = 0,
|
||||
QM_MBOX_CH_DATA = BIT(0), /**< Message has not been consumed. */
|
||||
QM_MBOX_CH_INT = BIT(1), /**< Channel interrupt pending. */
|
||||
QM_MBOX_CH_STATUS_MASK = BIT(1) | BIT(0) /**< Status mask. */
|
||||
/** Receiver has serviced the interrupt and data
|
||||
* has not been consumed. */
|
||||
QM_MBOX_CH_INT_ACK_DATA_PEND,
|
||||
/** Receiver in polling mode and data has not been consumed. */
|
||||
QM_MBOX_CH_POLLING_DATA_PEND,
|
||||
/** Receiver hasn't serviced the interrupt and data
|
||||
* has not been consumed.
|
||||
*/
|
||||
QM_MBOX_CH_INT_NACK_DATA_PEND,
|
||||
} qm_mbox_ch_status_t;
|
||||
|
||||
/**
|
||||
* Mailbox channel.
|
||||
* Mailbox channel identifiers
|
||||
*/
|
||||
typedef enum {
|
||||
QM_MBOX_CH_0 = 0, /**< Channel 0. */
|
||||
|
@ -69,49 +74,97 @@ typedef enum {
|
|||
} qm_mbox_ch_t;
|
||||
|
||||
/**
|
||||
* mailbox message pay-load index values.
|
||||
* Mailbox message payload index values.
|
||||
*/
|
||||
typedef enum {
|
||||
QM_MBOX_PAYLOAD_0 = 0, /**< Payload index value 0. */
|
||||
QM_MBOX_PAYLOAD_1, /**< Payload index value 1. */
|
||||
QM_MBOX_PAYLOAD_2, /**< Payload index value 2. */
|
||||
QM_MBOX_PAYLOAD_3, /**< Payload index value 3. */
|
||||
QM_MBOX_PAYLOAD_NUM, /**< Numbers of payloads. */
|
||||
QM_MBOX_PAYLOAD_NUM, /**< Number of payloads. */
|
||||
} qm_mbox_payload_t;
|
||||
|
||||
/**
|
||||
* Definition of the mailbox direction of operation
|
||||
* The direction of communication for each channel is configurable by the user.
|
||||
* The list below describes the possible communication directions for each
|
||||
* channel.
|
||||
*/
|
||||
typedef enum {
|
||||
QM_MBOX_TO_LMT = 0, /**< Lakemont core as destination */
|
||||
QM_MBOX_TO_SS, /**< Sensor Sub-System core as destination */
|
||||
QM_MBOX_UNUSED
|
||||
} qm_mbox_destination_t;
|
||||
|
||||
/**
|
||||
* Definition of the mailbox mode of operation, interrupt mode or polling mode.
|
||||
*/
|
||||
typedef enum {
|
||||
/** Mailbox channel operates in interrupt mode. */
|
||||
QM_MBOX_INTERRUPT_MODE = 0,
|
||||
/** Mailbox channel operates in polling mode. */
|
||||
QM_MBOX_POLLING_MODE
|
||||
} qm_mbox_mode_t;
|
||||
|
||||
/**
|
||||
* Definition of the mailbox message.
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t ctrl; /**< Mailbox control element. */
|
||||
uint32_t data[QM_MBOX_PAYLOAD_NUM]; /**< Mailbox data buffer. */
|
||||
/** Control word - bits 30 to 0 used as data/message id,
|
||||
* bit 31 triggers channel interrupt when set by the driver.
|
||||
*/
|
||||
uint32_t ctrl;
|
||||
/** Mailbox data buffer. */
|
||||
uint32_t data[QM_MBOX_PAYLOAD_NUM];
|
||||
} qm_mbox_msg_t;
|
||||
|
||||
/**
|
||||
* Definition of the mailbox callback function prototype.
|
||||
*
|
||||
* @param[in] data The callback user data.
|
||||
*/
|
||||
typedef void (*qm_mbox_callback_t)(void *data);
|
||||
|
||||
/**
|
||||
* Mailbox Configuration Structure
|
||||
*/
|
||||
typedef struct {
|
||||
/**< Mailbox Destination */
|
||||
qm_mbox_destination_t dest;
|
||||
/**< Mode of operation */
|
||||
qm_mbox_mode_t mode;
|
||||
|
||||
/**<
|
||||
* Message callback.
|
||||
*
|
||||
* Called after a message is received on the channel and the channel
|
||||
* is configured in interrupt mode.
|
||||
*
|
||||
* @note NULL for a write Mailbox.
|
||||
*
|
||||
* @param[in] data User defined data.
|
||||
*/
|
||||
qm_mbox_callback_t callback;
|
||||
/**< Callback function data to return via the callback function. */
|
||||
void *callback_data;
|
||||
} qm_mbox_config_t;
|
||||
|
||||
/**
|
||||
* Set the mailbox channel configuration.
|
||||
*
|
||||
* Configure a IRQ callback, enables or disables IRQ for the chosen mailbox
|
||||
* channel.
|
||||
* The function registers the interrupt vector to the mailbox ISR handler
|
||||
* when at least one mailbox channel is enabled, configured in interrupt mode
|
||||
* and the ISR is not handled by the application.
|
||||
*
|
||||
* @param[in] mbox_ch Mailbox to enable.
|
||||
* @param[in] mpr_cb Callback function to call on read mailbox, NULL for a
|
||||
* write to Mailbox).
|
||||
* @param[in] cb_data Callback function data to return via the callback.
|
||||
* function. This must not be NULL.
|
||||
* @param[in] irq_en Flag to enable/disable IRQ for this channel.
|
||||
* @param[in] mbox_ch Mailbox channel identifier.
|
||||
* @param[in] config Mailbox configuration.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_mbox_ch_set_config(const qm_mbox_ch_t mbox_ch, qm_mbox_callback_t mpr_cb,
|
||||
void *cb_data, const bool irq_en);
|
||||
int qm_mbox_ch_set_config(const qm_mbox_ch_t mbox_ch,
|
||||
const qm_mbox_config_t *const config);
|
||||
|
||||
/**
|
||||
* Write to a specified mailbox channel.
|
||||
|
@ -137,7 +190,7 @@ int qm_mbox_ch_write(const qm_mbox_ch_t mbox_ch,
|
|||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
*/
|
||||
int qm_mbox_ch_read(const qm_mbox_ch_t mbox_ch, qm_mbox_msg_t *const msg);
|
||||
|
||||
/**
|
||||
|
@ -153,18 +206,9 @@ int qm_mbox_ch_read(const qm_mbox_ch_t mbox_ch, qm_mbox_msg_t *const msg);
|
|||
int qm_mbox_ch_get_status(const qm_mbox_ch_t mbox_ch,
|
||||
qm_mbox_ch_status_t *const status);
|
||||
|
||||
/**
|
||||
* Acknowledge the data arrival.
|
||||
* @param[in] mbox_ch: Mailbox identifier to retrieve the status from.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_mbox_ch_data_ack(const qm_mbox_ch_t mbox_ch);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* HAS_MAILBOX */
|
||||
#endif /* __QM_MAILBOX_H__ */
|
||||
|
|
|
@ -39,38 +39,42 @@
|
|||
* @defgroup groupPWM PWM / Timer
|
||||
* @{
|
||||
*/
|
||||
#define PWM_START (1)
|
||||
|
||||
#define QM_PWM_CONF_MODE_MASK (10)
|
||||
#define QM_PWM_CONF_INT_EN_MASK (4)
|
||||
|
||||
/**
|
||||
* PWM operating mode type.
|
||||
* QM PWM mode type.
|
||||
*/
|
||||
typedef enum {
|
||||
QM_PWM_MODE_TIMER_FREE_RUNNING = 0, /**< Timer: free runnig mode. */
|
||||
QM_PWM_MODE_TIMER_COUNT = 2, /**< Timer: Counter mode. */
|
||||
QM_PWM_MODE_PWM = 10 /**< Pwm mode. */
|
||||
/**< Timer: Free running mode. */
|
||||
QM_PWM_MODE_TIMER_FREE_RUNNING = QM_PWM_MODE_TIMER_FREE_RUNNING_VALUE,
|
||||
/**< Timer: Counter mode. */
|
||||
QM_PWM_MODE_TIMER_COUNT = QM_PWM_MODE_TIMER_COUNT_VALUE,
|
||||
/**< PWM mode. */
|
||||
QM_PWM_MODE_PWM = QM_PWM_MODE_PWM_VALUE
|
||||
} qm_pwm_mode_t;
|
||||
|
||||
/**
|
||||
* PWM / Timer configuration type.
|
||||
* QM PWM / Timer configuration type.
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t
|
||||
lo_count; /**< Number of cycles the PWM output is driven low. In
|
||||
timer mode, this is the timer load count. Must be
|
||||
> 0. */
|
||||
uint32_t hi_count; /**< Number of cycles the PWM output is driven high.
|
||||
Not applicable in timer mode. Must be > 0.*/
|
||||
/**
|
||||
* Number of cycles the PWM output is driven low.
|
||||
* In timer mode, this is the timer load count. Must be > 0.
|
||||
*/
|
||||
uint32_t lo_count;
|
||||
/**
|
||||
* Number of cycles the PWM output is driven high.
|
||||
* Not applicable in timer mode. Must be > 0.
|
||||
*/
|
||||
uint32_t hi_count;
|
||||
bool mask_interrupt; /**< Mask interrupt. */
|
||||
qm_pwm_mode_t mode; /**< Pwm mode. */
|
||||
/**
|
||||
* User callback.
|
||||
*
|
||||
* @param[in] data The callback user data.
|
||||
* @param[in] int_status The timer status.
|
||||
*/
|
||||
|
||||
/**
|
||||
* User callback.
|
||||
*
|
||||
* @param[in] data The callback user data.
|
||||
* @param[in] int_status The timer status.
|
||||
*/
|
||||
void (*callback)(void *data, uint32_t int_status);
|
||||
void *callback_data; /**< Callback user data. */
|
||||
} qm_pwm_config_t;
|
||||
|
@ -93,7 +97,7 @@ typedef struct {
|
|||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
* */
|
||||
*/
|
||||
int qm_pwm_set_config(const qm_pwm_t pwm, const qm_pwm_id_t id,
|
||||
const qm_pwm_config_t *const cfg);
|
||||
|
||||
|
@ -114,7 +118,7 @@ int qm_pwm_set_config(const qm_pwm_t pwm, const qm_pwm_id_t id,
|
|||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
* */
|
||||
*/
|
||||
int qm_pwm_set(const qm_pwm_t pwm, const qm_pwm_id_t id,
|
||||
const uint32_t lo_count, const uint32_t hi_count);
|
||||
|
||||
|
@ -131,7 +135,7 @@ int qm_pwm_set(const qm_pwm_t pwm, const qm_pwm_id_t id,
|
|||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
* */
|
||||
*/
|
||||
int qm_pwm_get(const qm_pwm_t pwm, const qm_pwm_id_t id,
|
||||
uint32_t *const lo_count, uint32_t *const hi_count);
|
||||
|
||||
|
@ -144,7 +148,7 @@ int qm_pwm_get(const qm_pwm_t pwm, const qm_pwm_id_t id,
|
|||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
* */
|
||||
*/
|
||||
int qm_pwm_start(const qm_pwm_t pwm, const qm_pwm_id_t id);
|
||||
|
||||
/**
|
||||
|
@ -156,10 +160,11 @@ int qm_pwm_start(const qm_pwm_t pwm, const qm_pwm_id_t id);
|
|||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
* */
|
||||
*/
|
||||
int qm_pwm_stop(const qm_pwm_t pwm, const qm_pwm_id_t id);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* __QM_PWM_H__ */
|
||||
|
|
|
@ -35,31 +35,45 @@
|
|||
#include "clk.h"
|
||||
|
||||
/**
|
||||
* Real Time clock.
|
||||
* Real Time Clock.
|
||||
*
|
||||
* @defgroup groupRTC RTC
|
||||
* @{
|
||||
*
|
||||
* @warning The RTC clock resides in a different clock domain
|
||||
* to the system clock.
|
||||
* It takes 3-4 RTC ticks for a system clock write to propagate
|
||||
* to the RTC domain.
|
||||
* If an entry to sleep is initiated without waiting for a
|
||||
* transaction to complete the SOC will not wake from sleep.
|
||||
*/
|
||||
|
||||
#define QM_RTC_DIVIDER CLK_RTC_DIV_1
|
||||
|
||||
#define QM_RTC_CCR_INTERRUPT_ENABLE BIT(0)
|
||||
#define QM_RTC_CCR_INTERRUPT_MASK BIT(1)
|
||||
#define QM_RTC_CCR_ENABLE BIT(2)
|
||||
|
||||
#define QM_RTC_ALARM_SECOND (32768 / BIT(QM_RTC_DIVIDER))
|
||||
#define QM_RTC_ALARM_MINUTE (QM_RTC_ALARM_SECOND * 60)
|
||||
#define QM_RTC_ALARM_HOUR (QM_RTC_ALARM_MINUTE * 60)
|
||||
#define QM_RTC_ALARM_DAY (QM_RTC_ALARM_HOUR * 24)
|
||||
/**
|
||||
* RTC clock ticks to Real-time helpers
|
||||
*
|
||||
* The _prescale value is given in clk_rtc_div_t.
|
||||
*/
|
||||
#define QM_RTC_ALARM_SECOND(_prescale) (32768 / BIT(_prescale))
|
||||
#define QM_RTC_ALARM_MINUTE(_prescale) (QM_RTC_ALARM_SECOND(_prescale) * 60)
|
||||
#define QM_RTC_ALARM_HOUR(_prescale) (QM_RTC_ALARM_MINUTE(_prescale) * 60)
|
||||
#define QM_RTC_ALARM_DAY(_prescale) (QM_RTC_ALARM_HOUR(_prescale) * 24)
|
||||
|
||||
/**
|
||||
* RTC configuration type.
|
||||
* QM RTC configuration type.
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t init_val; /**< Initial value in RTC clocks. */
|
||||
bool alarm_en; /**< Alarm enable. */
|
||||
uint32_t alarm_val; /**< Alarm value in RTC clocks. */
|
||||
|
||||
/**
|
||||
* RTC Clock prescaler.
|
||||
*
|
||||
* Used to divide the clock frequency of the RTC.
|
||||
*
|
||||
*/
|
||||
clk_rtc_div_t prescaler;
|
||||
|
||||
/**
|
||||
* User callback.
|
||||
*
|
||||
|
@ -76,13 +90,6 @@ typedef struct {
|
|||
* an alarm is required. If the alarm is enabled, register an ISR with the user
|
||||
* defined callback function.
|
||||
*
|
||||
* The RTC clock resides in a different clock domain
|
||||
* to the system clock.
|
||||
* It takes 3-4 RTC ticks for a system clock write to propagate
|
||||
* to the RTC domain.
|
||||
* If an entry to sleep is initiated without waiting for the
|
||||
* transaction to complete the SOC will not wake from sleep.
|
||||
*
|
||||
* @param[in] rtc RTC index.
|
||||
* @param[in] cfg New RTC configuration. This must not be NULL.
|
||||
*
|
||||
|
@ -114,6 +121,25 @@ int qm_rtc_set_config(const qm_rtc_t rtc, const qm_rtc_config_t *const cfg);
|
|||
*/
|
||||
int qm_rtc_set_alarm(const qm_rtc_t rtc, const uint32_t alarm_val);
|
||||
|
||||
/**
|
||||
* Read the RTC register value.
|
||||
*
|
||||
* @param[in] rtc RTC index.
|
||||
* @param[out] value Location to store RTC value. This must not be NULL.
|
||||
*
|
||||
* The RTC clock resides in a different clock domain
|
||||
* to the system clock.
|
||||
* It takes 3-4 RTC ticks for a system clock write to propagate
|
||||
* to the RTC domain.
|
||||
* If an entry to sleep is initiated without waiting for the
|
||||
* transaction to complete the SOC will not wake from sleep.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_rtc_read(const qm_rtc_t rtc, uint32_t *const value);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
|
|
@ -120,13 +120,109 @@ typedef enum {
|
|||
QM_SPI_RX_OVERFLOW /**< RX transfer has overflown. */
|
||||
} qm_spi_status_t;
|
||||
|
||||
/**
|
||||
* QM SPI Frame Format
|
||||
*/
|
||||
typedef enum {
|
||||
/**< Standard SPI mode */
|
||||
QM_SPI_FRAME_FORMAT_STANDARD = 0x0,
|
||||
#if HAS_QSPI
|
||||
/**< Quad SPI mode */
|
||||
QM_SPI_FRAME_FORMAT_QUAD = 0x2
|
||||
#endif /* HAS_QSPI */
|
||||
} qm_spi_frame_format_t;
|
||||
|
||||
#if HAS_QSPI
|
||||
/**
|
||||
* QM QSPI number of wait cycles
|
||||
*/
|
||||
typedef enum {
|
||||
QM_SPI_QUAD_0_WAIT_CYCLES = 0x0, /**< No wait cycles */
|
||||
QM_SPI_QUAD_1_WAIT_CYCLES = 0x1, /**< 1 wait cycle */
|
||||
QM_SPI_QUAD_2_WAIT_CYCLES = 0x2, /**< 2 wait cycles */
|
||||
QM_SPI_QUAD_3_WAIT_CYCLES = 0x3, /**< 3 wait cycles */
|
||||
QM_SPI_QUAD_4_WAIT_CYCLES = 0x4, /**< 4 wait cycles */
|
||||
QM_SPI_QUAD_5_WAIT_CYCLES = 0x5, /**< 5 wait cycles */
|
||||
QM_SPI_QUAD_6_WAIT_CYCLES = 0x6, /**< 6 wait cycles */
|
||||
QM_SPI_QUAD_7_WAIT_CYCLES = 0x7, /**< 7 wait cycles */
|
||||
QM_SPI_QUAD_8_WAIT_CYCLES = 0x8, /**< 8 wait cycles */
|
||||
QM_SPI_QUAD_9_WAIT_CYCLES = 0x9, /**< 9 wait cycles */
|
||||
QM_SPI_QUAD_10_WAIT_CYCLES = 0xA, /**< 10 wait cycles */
|
||||
QM_SPI_QUAD_11_WAIT_CYCLES = 0xB, /**< 11 wait cycles */
|
||||
QM_SPI_QUAD_12_WAIT_CYCLES = 0xC, /**< 12 wait cycles */
|
||||
QM_SPI_QUAD_13_WAIT_CYCLES = 0xD, /**< 13 wait cycles */
|
||||
QM_SPI_QUAD_14_WAIT_CYCLES = 0xE, /**< 14 wait cycles */
|
||||
QM_SPI_QUAD_15_WAIT_CYCLES = 0xF, /**< 15 wait cycles */
|
||||
} qm_spi_quad_wait_cycles_t;
|
||||
|
||||
/**
|
||||
* QM QSPI Instruction length
|
||||
*/
|
||||
typedef enum {
|
||||
QM_SPI_QUAD_INST_LENGTH_0_BITS = 0x0, /**< No instruction */
|
||||
QM_SPI_QUAD_INST_LENGTH_4_BITS = 0x1, /**< 4 bit instruction */
|
||||
QM_SPI_QUAD_INST_LENGTH_8_BITS = 0x2, /**< 8 bit instruction */
|
||||
QM_SPI_QUAD_INST_LENGTH_16_BITS = 0x3 /**< 16 bit instruction */
|
||||
} qm_spi_quad_inst_length_t;
|
||||
|
||||
/**
|
||||
* QM QSPI Address length
|
||||
*/
|
||||
typedef enum {
|
||||
QM_SPI_QUAD_ADDR_LENGTH_0_BITS = 0x0, /**< No address */
|
||||
QM_SPI_QUAD_ADDR_LENGTH_4_BITS = 0x1, /**< 4 bit address */
|
||||
QM_SPI_QUAD_ADDR_LENGTH_8_BITS = 0x2, /**< 8 bit address */
|
||||
QM_SPI_QUAD_ADDR_LENGTH_12_BITS = 0x3, /**< 12 bit address */
|
||||
QM_SPI_QUAD_ADDR_LENGTH_16_BITS = 0x4, /**< 16 bit address */
|
||||
QM_SPI_QUAD_ADDR_LENGTH_20_BITS = 0x5, /**< 20 bit address */
|
||||
QM_SPI_QUAD_ADDR_LENGTH_24_BITS = 0x6, /**< 24 bit address */
|
||||
QM_SPI_QUAD_ADDR_LENGTH_28_BITS = 0x7, /**< 28 bit address */
|
||||
QM_SPI_QUAD_ADDR_LENGTH_32_BITS = 0x8, /**< 32 bit address */
|
||||
QM_SPI_QUAD_ADDR_LENGTH_36_BITS = 0x9, /**< 36 bit address */
|
||||
QM_SPI_QUAD_ADDR_LENGTH_40_BITS = 0xA, /**< 40 bit address */
|
||||
QM_SPI_QUAD_ADDR_LENGTH_44_BITS = 0xB, /**< 44 bit address */
|
||||
QM_SPI_QUAD_ADDR_LENGTH_48_BITS = 0xC, /**< 48 bit address */
|
||||
QM_SPI_QUAD_ADDR_LENGTH_52_BITS = 0xD, /**< 52 bit address */
|
||||
QM_SPI_QUAD_ADDR_LENGTH_56_BITS = 0xE, /**< 56 bit address */
|
||||
QM_SPI_QUAD_ADDR_LENGTH_60_BITS = 0xF /**< 60 bit address */
|
||||
} qm_spi_quad_addr_length_t;
|
||||
|
||||
/**
|
||||
* QM QSPI Transfer type
|
||||
*/
|
||||
typedef enum {
|
||||
/**< Both instruction and address sent in standard SPI mode */
|
||||
QM_SPI_QUAD_INST_STD_ADDR_STD = 0x0,
|
||||
/**
|
||||
* Instruction sent in standard SPI mode
|
||||
* and address sent in Quad SPI mode
|
||||
*/
|
||||
QM_SPI_QUAD_INST_STD_ADDR_QUAD = 0x1,
|
||||
/**< Both instruction and address sent in Quad SPI mode */
|
||||
QM_SPI_QUAD_INST_QUAD_ADDR_QUAD = 0x2
|
||||
} qm_spi_quad_transfer_type_t;
|
||||
|
||||
/**
|
||||
* QM QSPI Transfer Configuration
|
||||
*/
|
||||
typedef struct {
|
||||
qm_spi_quad_wait_cycles_t
|
||||
wait_cycles; /**< Wait cycles for QSPI reads */
|
||||
qm_spi_quad_inst_length_t inst_length; /**< Instruction length */
|
||||
qm_spi_quad_addr_length_t addr_length; /**< Address length */
|
||||
qm_spi_quad_transfer_type_t trans_type; /**< QSPI Transfer type */
|
||||
} qm_spi_quad_config_t;
|
||||
|
||||
#endif /* HAS_QSPI */
|
||||
|
||||
/**
|
||||
* SPI configuration type.
|
||||
*/
|
||||
typedef struct {
|
||||
qm_spi_frame_size_t frame_size; /**< Frame Size. */
|
||||
qm_spi_tmode_t transfer_mode; /**< Transfer mode (enum). */
|
||||
qm_spi_bmode_t bus_mode; /**< Bus mode (enum). */
|
||||
qm_spi_frame_size_t frame_size; /**< Frame Size. */
|
||||
qm_spi_tmode_t transfer_mode; /**< Transfer mode (enum). */
|
||||
qm_spi_bmode_t bus_mode; /**< Bus mode (enum). */
|
||||
qm_spi_frame_format_t frame_format; /* Data frame format for TX/RX */
|
||||
|
||||
/**
|
||||
* SCK = SPI_clock/clk_divider.
|
||||
|
@ -137,13 +233,22 @@ typedef struct {
|
|||
} qm_spi_config_t;
|
||||
|
||||
/**
|
||||
* SPI IRQ transfer type.
|
||||
* SPI aynchronous transfer type.
|
||||
*
|
||||
* If the frame size is 8 bits or less, 1 byte is needed per data frame. If the
|
||||
* frame size is 9-16 bits, 2 bytes are needed per data frame and frames of more
|
||||
* than 16 bits require 4 bytes. In each case, the least significant bits are
|
||||
* sent while the extra bits are discarded. The most significant bits of the
|
||||
* frame are sent first.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t *tx; /**< Write data. */
|
||||
uint8_t *rx; /**< Read data. */
|
||||
uint16_t tx_len; /**< Write data Length. */
|
||||
uint16_t rx_len; /**< Read buffer length. */
|
||||
void *tx; /**< Write data. */
|
||||
void *rx; /**< Read data. */
|
||||
uint16_t tx_len; /**< Number of data frames to write. */
|
||||
uint16_t rx_len; /**< Number of data frames to read. */
|
||||
#if HAS_QSPI
|
||||
qm_spi_quad_config_t qspi_cfg; /**< QSPI transfer parameters */
|
||||
#endif /* HAS_QSPI */
|
||||
|
||||
/**
|
||||
* Transfer callback.
|
||||
|
@ -164,20 +269,29 @@ typedef struct {
|
|||
} qm_spi_async_transfer_t;
|
||||
|
||||
/**
|
||||
* SPI transfer type.
|
||||
* SPI synchronous transfer type.
|
||||
*
|
||||
* If the frame size is 8 bits or less, 1 byte is needed per data frame. If the
|
||||
* frame size is 9-16 bits, 2 bytes are needed per data frame and frames of more
|
||||
* than 16 bits require 4 bytes. In each case, the least significant bits are
|
||||
* sent while the extra bits are discarded. The most significant bits of the
|
||||
* frame are sent first.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t *tx; /**< Write Data. */
|
||||
uint8_t *rx; /**< Read Data. */
|
||||
uint16_t tx_len; /**< Write Data Length. */
|
||||
uint16_t rx_len; /**< Receive Data Length. */
|
||||
void *tx; /**< Write data. */
|
||||
void *rx; /**< Read data. */
|
||||
uint16_t tx_len; /**< Number of data frames to write. */
|
||||
uint16_t rx_len; /**< Number of data frames to read. */
|
||||
#if HAS_QSPI
|
||||
qm_spi_quad_config_t qspi_cfg; /* QSPI transfer parameters */
|
||||
#endif /* HAS_QSPI */
|
||||
} qm_spi_transfer_t;
|
||||
|
||||
/**
|
||||
* Set SPI configuration.
|
||||
*
|
||||
* Change the configuration of a SPI module.
|
||||
* This includes transfer mode, bus mode and clock divider.
|
||||
* This includes transfer mode, bus mode, clock divider and data frame size.
|
||||
*
|
||||
* @param[in] spi Which SPI module to configure.
|
||||
* @param[in] cfg New configuration for SPI. This must not be NULL.
|
||||
|
@ -203,11 +317,15 @@ int qm_spi_slave_select(const qm_spi_t spi, const qm_spi_slave_select_t ss);
|
|||
/**
|
||||
* Get SPI bus status.
|
||||
*
|
||||
* Retrieve SPI bus status. Return QM_SPI_BUSY if transmitting data or data Tx
|
||||
* FIFO not empty.
|
||||
* Retrieve SPI bus status. Return QM_SPI_BUSY if transmitting data or SPI TX
|
||||
* FIFO not empty; QM_SPI_IDLE is available for transfer; QM_SPI_RX_OVERFLOW if
|
||||
* an RX overflow has occurred.
|
||||
*
|
||||
* The user may call this function before performing an SPI transfer in order to
|
||||
* guarantee that the SPI interface is available.
|
||||
*
|
||||
* @param[in] spi Which SPI to read the status of.
|
||||
* @param[out] status Get spi status. This must not be null.
|
||||
* @param[out] status Current SPI status. This must not be null.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
|
@ -286,6 +404,14 @@ int qm_spi_irq_transfer(const qm_spi_t spi,
|
|||
* interface parameters. The user will likely only call this function once for
|
||||
* the lifetime of an application unless the channel needs to be repurposed.
|
||||
*
|
||||
* This function configures the DMA source transfer width according to the
|
||||
* currently set SPI frame size. Therefore, whenever the SPI frame is updated
|
||||
* (using qm_spi_set_config) this function needs to be called again as the
|
||||
* previous source transfer width configuration is no longer valid. Note that if
|
||||
* the current frame size lies between 17 and 24 bits, this function fails
|
||||
* (returning -EINVAL) as the DMA core cannot handle 3-byte source width
|
||||
* transfers with buffers containing 1 padding byte between consecutive frames.
|
||||
*
|
||||
* Note that qm_dma_init() must first be called before configuring a channel.
|
||||
*
|
||||
* @param[in] spi SPI controller identifier.
|
||||
|
@ -308,11 +434,9 @@ int qm_spi_dma_channel_config(
|
|||
* Perform a DMA-based transfer on the SPI bus.
|
||||
*
|
||||
* If transfer mode is full duplex (QM_SPI_TMOD_TX_RX), then tx_len and
|
||||
* rx_len must be equal and neither of both callbacks can be NULL.
|
||||
* Similarly, for transmit-only transfers (QM_SPI_TMOD_TX) rx_len must be 0
|
||||
* and tx_callback cannot be NULL, while for receive-only transfers
|
||||
* (QM_SPI_TMOD_RX) tx_len must be 0 and rx_callback cannot be NULL.
|
||||
* Transfer length is limited to 4KB.
|
||||
* rx_len must be equal. Similarly, for transmit-only transfers (QM_SPI_TMOD_TX)
|
||||
* rx_len must be 0 while for receive-only transfers (QM_SPI_TMOD_RX) tx_len
|
||||
* must be 0. Transfer length is limited to 4KB.
|
||||
*
|
||||
* For starting a transfer, this controller demands at least one slave
|
||||
* select line (SS) to be enabled. Thus, a call to qm_spi_slave_select()
|
||||
|
@ -325,7 +449,8 @@ int qm_spi_dma_channel_config(
|
|||
*
|
||||
* @param[in] spi SPI controller identifier.
|
||||
* @param[in] xfer Structure containing pre-allocated write and read data
|
||||
* buffers and callback functions. This must not be NULL.
|
||||
* buffers and callback functions. This must not be NULL and
|
||||
* must be kept valid until the transfer is complete.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
|
@ -362,6 +487,45 @@ int qm_spi_irq_transfer_terminate(const qm_spi_t spi);
|
|||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_spi_dma_transfer_terminate(const qm_spi_t spi);
|
||||
|
||||
#if HAS_QSPI
|
||||
/**
|
||||
* Configure a QSPI enabled controller for use in XIP mode.
|
||||
* Execute-In-Place (XIP) mode allows the processor to access
|
||||
* external flash memory, via QSPI interface, as if it were
|
||||
* memory-mapped.
|
||||
* While in XIP mode, standard SPI register interface will be disabled.
|
||||
* The user needs to call qm_spi_exit_xip_mode to resume normal SPI operation.
|
||||
*
|
||||
* @note 'inst_length' member of qm_spi_quad_config_t parameter is not
|
||||
* needed for this function as XIP transfers do not require an
|
||||
* instruction phase.
|
||||
*
|
||||
* @param[in] spi SPI controller identifier
|
||||
* @param[in] wait_cycles No of wait cycles for QSPI transfer
|
||||
* @param[in] addr_length Length of address for QSPI transfers
|
||||
* @param[in] trans_type QSPI transfer type
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_spi_enter_xip_mode(const qm_spi_t spi,
|
||||
const qm_spi_quad_config_t qspi_cfg);
|
||||
|
||||
/**
|
||||
* Clear xip_mode flag and allow for normal operation
|
||||
* of the SPI controller.
|
||||
*
|
||||
* @param[in] spi SPI controller identifier
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_spi_exit_xip_mode(const qm_spi_t spi);
|
||||
#endif /* HAS_QSPI */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
|
|
@ -44,13 +44,13 @@
|
|||
* GPIO SS pin states.
|
||||
*/
|
||||
typedef enum {
|
||||
QM_SS_GPIO_LOW, /**< Pin level high. */
|
||||
QM_SS_GPIO_HIGH, /**< Pin level low. */
|
||||
QM_SS_GPIO_STATE_NUM
|
||||
QM_SS_GPIO_LOW = 0, /**< Pin level high. */
|
||||
QM_SS_GPIO_HIGH, /**< Pin level low. */
|
||||
QM_SS_GPIO_STATE_NUM /**< Number of states. */
|
||||
} qm_ss_gpio_state_t;
|
||||
|
||||
/**
|
||||
* GPIO port configuration type.
|
||||
* SS GPIO port configuration type.
|
||||
*
|
||||
* Each bit in the registers control a GPIO pin.
|
||||
*/
|
||||
|
@ -61,6 +61,10 @@ typedef struct {
|
|||
uint32_t int_polarity; /**< Interrupt polarity, 0b: low, 1b: high. */
|
||||
uint32_t int_debounce; /**< Debounce on/off. */
|
||||
|
||||
#if HAS_SS_GPIO_INTERRUPT_BOTHEDGE
|
||||
uint32_t int_bothedge; /**< Interrupt on rising and falling edges */
|
||||
#endif
|
||||
|
||||
/**
|
||||
* User callback.
|
||||
*
|
|
@ -65,45 +65,62 @@ typedef enum {
|
|||
} qm_ss_i2c_addr_t;
|
||||
|
||||
/**
|
||||
* QM SS I2C Speed Type.
|
||||
* QM SS I2C speed type.
|
||||
*/
|
||||
typedef enum {
|
||||
QM_SS_I2C_SPEED_STD = 1, /**< Standard mode (100 Kbps). */
|
||||
QM_SS_I2C_SPEED_FAST = 2 /**< Fast mode (400 Kbps). */
|
||||
QM_SS_I2C_SPEED_STD = 1, /**< Standard mode (100 Kbps). */
|
||||
QM_SS_I2C_SPEED_FAST = 2, /**< Fast mode (400 Kbps). */
|
||||
#if HAS_SS_I2C_FAST_PLUS_SPEED
|
||||
QM_SS_I2C_SPEED_FAST_PLUS = 3 /**< Fast plus mode (1 Mbps). */
|
||||
#endif /* HAS_SS_I2C_FAST_PLUS_SPEED */
|
||||
} qm_ss_i2c_speed_t;
|
||||
|
||||
/**
|
||||
* QM SS I2C status type.
|
||||
*/
|
||||
typedef enum {
|
||||
QM_I2C_IDLE = 0, /**< Controller idle. */
|
||||
QM_I2C_TX_ABRT_7B_ADDR_NOACK = BIT(0), /**< 7-bit address noack. */
|
||||
QM_I2C_TX_ABRT_TXDATA_NOACK = BIT(3), /**< Tx data noack. */
|
||||
QM_I2C_TX_ABRT_SBYTE_ACKDET = BIT(7), /**< Start ACK. */
|
||||
QM_I2C_TX_ABRT_MASTER_DIS = BIT(11), /**< Master disabled. */
|
||||
QM_I2C_TX_ARB_LOST = BIT(12), /**< Master lost arbitration. */
|
||||
QM_I2C_TX_ABRT_SLVFLUSH_TXFIFO = BIT(13), /**< Slave flush tx FIFO. */
|
||||
QM_I2C_TX_ABRT_SLV_ARBLOST = BIT(14), /**< Slave lost bus. */
|
||||
QM_I2C_TX_ABRT_SLVRD_INTX = BIT(15), /**< Slave read completion. */
|
||||
QM_I2C_TX_ABRT_USER_ABRT = BIT(16), /**< User abort. */
|
||||
QM_I2C_BUSY = BIT(17) /**< Controller busy. */
|
||||
QM_SS_I2C_IDLE = 0, /**< Controller idle. */
|
||||
QM_SS_I2C_TX_ABRT_7B_ADDR_NOACK = BIT(0), /**< 7-bit address noack. */
|
||||
QM_SS_I2C_TX_ABRT_10ADDR1_NOACK = BIT(1), /**< 10-bit address noack. */
|
||||
QM_SS_I2C_TX_ABRT_10ADDR2_NOACK = BIT(2), /**< 10-bit address noack. */
|
||||
QM_SS_I2C_TX_ABRT_TXDATA_NOACK = BIT(3), /**< Tx data noack. */
|
||||
QM_SS_I2C_TX_ABRT_GCALL_NOACK = BIT(4), /**< General call noack. */
|
||||
|
||||
/**< General call configured as read. */
|
||||
QM_SS_I2C_TX_ABRT_GCALL_READ = BIT(5),
|
||||
QM_SS_I2C_TX_ABRT_SBYTE_ACKDET = BIT(7), /**< Start ACK. */
|
||||
QM_SS_I2C_TX_ABRT_NORSTRT = BIT(9), /**< Restart disabled. */
|
||||
QM_SS_I2C_TX_ABRT_10B_RD_NORSTRT = BIT(10), /**< Restart disabled. */
|
||||
QM_SS_I2C_TX_ABRT_MASTER_DIS = BIT(11), /**< Master disabled. */
|
||||
QM_SS_I2C_TX_ARB_LOST = BIT(12), /**< Master lost arbitration. */
|
||||
|
||||
/**< Slave flush tx FIFO. */
|
||||
QM_SS_I2C_TX_ABRT_SLVFLUSH_TXFIFO = BIT(13),
|
||||
QM_SS_I2C_TX_ABRT_SLV_ARBLOST = BIT(14), /**< Slave lost bus. */
|
||||
QM_SS_I2C_TX_ABRT_SLVRD_INTX = BIT(15), /**< Slave read completion. */
|
||||
QM_SS_I2C_TX_ABRT_USER_ABRT = BIT(16), /**< User abort. */
|
||||
QM_SS_I2C_BUSY = BIT(17), /**< Controller busy. */
|
||||
QM_SS_I2C_TX_ABORT = BIT(18), /**< Tx abort. */
|
||||
QM_SS_I2C_TX_OVER = BIT(19), /**< Tx overflow. */
|
||||
QM_SS_I2C_RX_OVER = BIT(20), /**< Rx overflow. */
|
||||
QM_SS_I2C_RX_UNDER = BIT(21) /**< Rx underflow. */
|
||||
} qm_ss_i2c_status_t;
|
||||
|
||||
/**
|
||||
* QM SS I2C configuration type.
|
||||
*/
|
||||
typedef struct {
|
||||
qm_ss_i2c_speed_t speed; /**< Standard, Fast Mode. */
|
||||
qm_ss_i2c_speed_t speed; /**< Standard, fast or fast plus mode. */
|
||||
qm_ss_i2c_addr_t address_mode; /**< 7 or 10 bit addressing. */
|
||||
} qm_ss_i2c_config_t;
|
||||
|
||||
/**
|
||||
* QM SS I2C transfer type.
|
||||
* - if tx len is 0: perform receive-only transaction.
|
||||
* - if rx len is 0: perform transmit-only transaction.
|
||||
* - if tx_len is 0: perform receive-only transaction.
|
||||
* - if rx_len is 0: perform transmit-only transaction.
|
||||
* - both tx and rx len not 0: perform a transmit-then-receive
|
||||
* combined transaction.
|
||||
*/
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t *tx; /**< Write data. */
|
||||
uint32_t tx_len; /**< Write data length. */
|
||||
|
@ -116,9 +133,9 @@ typedef struct {
|
|||
*
|
||||
* @param[in] data User defined data.
|
||||
* @param[in] rc 0 on success.
|
||||
* Negative @ref errno for possible error codes.
|
||||
* Negative @ref errno for possible error codes.
|
||||
* @param[in] status I2C status.
|
||||
* @param[in] len Length of the transfer if succesfull, 0 otherwise.
|
||||
* @param[in] len Length of the transfer if successful, 0 otherwise.
|
||||
*/
|
||||
void (*callback)(void *data, int rc, qm_ss_i2c_status_t status,
|
||||
uint32_t len);
|
||||
|
@ -146,7 +163,7 @@ int qm_ss_i2c_set_config(const qm_ss_i2c_t i2c,
|
|||
* to achieve any required speed.
|
||||
*
|
||||
* @param[in] i2c I2C index.
|
||||
* @param[in] speed Bus speed (Standard or Fast.Fast includes Fast + mode).
|
||||
* @param[in] speed Bus speed (Standard or Fast. Fast includes Fast+ mode).
|
||||
* @param[in] lo_cnt SCL low count.
|
||||
* @param[in] hi_cnt SCL high count.
|
||||
*
|
||||
|
@ -161,7 +178,7 @@ int qm_ss_i2c_set_speed(const qm_ss_i2c_t i2c, const qm_ss_i2c_speed_t speed,
|
|||
* Retrieve SS I2C status.
|
||||
*
|
||||
* @param[in] i2c Which I2C to read the status of.
|
||||
* @param[out] status Get i2c status. This must not be NULL.
|
||||
* @param[out] status Get I2C status. This must not be NULL.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
|
@ -180,9 +197,9 @@ int qm_ss_i2c_get_status(const qm_ss_i2c_t i2c,
|
|||
* @param[in] slave_addr Address of slave to write to.
|
||||
* @param[in] data Pre-allocated buffer of data to write.
|
||||
* This must not be NULL.
|
||||
* @param[in] len length of data to write.
|
||||
* @param[in] len Length of data to write.
|
||||
* @param[in] stop Generate a STOP condition at the end of tx.
|
||||
* @param[out] status Get i2c status.
|
||||
* @param[out] status Get I2C status.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
|
@ -201,9 +218,9 @@ int qm_ss_i2c_master_write(const qm_ss_i2c_t i2c, const uint16_t slave_addr,
|
|||
* @param[in] slave_addr Address of slave device to read from.
|
||||
* @param[out] data Pre-allocated buffer to populate with data.
|
||||
* This must not be NULL.
|
||||
* @param[in] len length of data to read from slave.
|
||||
* @param[in] stop Generate a STOP condition at the end of tx.
|
||||
* @param[out] status Get i2c status.
|
||||
* @param[in] len Length of data to read from slave.
|
||||
* @param[in] stop Generate a STOP condition at the end of rx.
|
||||
* @param[out] status Get I2C status.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
|
@ -239,7 +256,7 @@ int qm_ss_i2c_master_irq_transfer(const qm_ss_i2c_t i2c,
|
|||
*
|
||||
* Terminate the current IRQ transfer on the SS I2C bus.
|
||||
* This will cause the user callback to be called with status
|
||||
* QM_I2C_TX_ABRT_USER_ABRT.
|
||||
* QM_SS_I2C_TX_ABRT_USER_ABRT.
|
||||
*
|
||||
* @param[in] i2c I2C register block pointer.
|
||||
*
|
|
@ -32,7 +32,9 @@
|
|||
|
||||
#include "qm_common.h"
|
||||
#include "qm_sensor_regs.h"
|
||||
|
||||
#if HAS_SS_DMA
|
||||
#include "qm_ss_dma.h"
|
||||
#endif
|
||||
/**
|
||||
* SPI peripheral driver for Sensor Subsystem.
|
||||
*
|
||||
|
@ -41,7 +43,7 @@
|
|||
*/
|
||||
|
||||
/**
|
||||
* QM SPI frame size type.
|
||||
* QM Sensor SPI frame size type
|
||||
*/
|
||||
typedef enum {
|
||||
QM_SS_SPI_FRAME_SIZE_4_BIT = 3, /**< 4 bit frame. */
|
||||
|
@ -56,7 +58,25 @@ typedef enum {
|
|||
QM_SS_SPI_FRAME_SIZE_13_BIT, /**< 13 bit frame. */
|
||||
QM_SS_SPI_FRAME_SIZE_14_BIT, /**< 14 bit frame. */
|
||||
QM_SS_SPI_FRAME_SIZE_15_BIT, /**< 15 bit frame. */
|
||||
QM_SS_SPI_FRAME_SIZE_16_BIT /**< 16 bit frame. */
|
||||
QM_SS_SPI_FRAME_SIZE_16_BIT, /**< 16 bit frame. */
|
||||
#if HAS_SS_SPI_32BIT
|
||||
QM_SS_SPI_FRAME_SIZE_17_BIT, /**< 17 bit frame. */
|
||||
QM_SS_SPI_FRAME_SIZE_18_BIT, /**< 18 bit frame. */
|
||||
QM_SS_SPI_FRAME_SIZE_19_BIT, /**< 19 bit frame. */
|
||||
QM_SS_SPI_FRAME_SIZE_20_BIT, /**< 20 bit frame. */
|
||||
QM_SS_SPI_FRAME_SIZE_21_BIT, /**< 21 bit frame. */
|
||||
QM_SS_SPI_FRAME_SIZE_22_BIT, /**< 22 bit frame. */
|
||||
QM_SS_SPI_FRAME_SIZE_23_BIT, /**< 23 bit frame. */
|
||||
QM_SS_SPI_FRAME_SIZE_24_BIT, /**< 24 bit frame. */
|
||||
QM_SS_SPI_FRAME_SIZE_25_BIT, /**< 25 bit frame. */
|
||||
QM_SS_SPI_FRAME_SIZE_26_BIT, /**< 26 bit frame. */
|
||||
QM_SS_SPI_FRAME_SIZE_27_BIT, /**< 27 bit frame. */
|
||||
QM_SS_SPI_FRAME_SIZE_28_BIT, /**< 28 bit frame. */
|
||||
QM_SS_SPI_FRAME_SIZE_29_BIT, /**< 29 bit frame. */
|
||||
QM_SS_SPI_FRAME_SIZE_30_BIT, /**< 30 bit frame. */
|
||||
QM_SS_SPI_FRAME_SIZE_31_BIT, /**< 31 bit frame. */
|
||||
QM_SS_SPI_FRAME_SIZE_32_BIT /**< 32 bit frame. */
|
||||
#endif /* HAS_SS_SPI_32BIT */
|
||||
} qm_ss_spi_frame_size_t;
|
||||
|
||||
/**
|
||||
|
@ -98,64 +118,71 @@ typedef enum {
|
|||
} qm_ss_spi_tmode_t;
|
||||
|
||||
/**
|
||||
* SPI bus mode type.
|
||||
* SPI Bus Mode Type
|
||||
*/
|
||||
typedef enum {
|
||||
QM_SS_SPI_BMODE_0, /**< Clock Polarity = 0, Clock Phase = 0. */
|
||||
QM_SS_SPI_BMODE_1, /**< Clock Polarity = 0, Clock Phase = 1. */
|
||||
QM_SS_SPI_BMODE_2, /**< Clock Polarity = 1, Clock Phase = 0. */
|
||||
QM_SS_SPI_BMODE_3 /**< Clock Polarity = 1, Clock Phase = 1. */
|
||||
QM_SS_SPI_BMODE_0 = 0, /**< Clock Polarity = 0, Clock Phase = 0. */
|
||||
QM_SS_SPI_BMODE_1, /**< Clock Polarity = 0, Clock Phase = 1. */
|
||||
QM_SS_SPI_BMODE_2, /**< Clock Polarity = 1, Clock Phase = 0. */
|
||||
QM_SS_SPI_BMODE_3 /**< Clock Polarity = 1, Clock Phase = 1. */
|
||||
} qm_ss_spi_bmode_t;
|
||||
|
||||
/**
|
||||
* SPI slave select type.
|
||||
* SPI Slave select type.
|
||||
*
|
||||
* Slave selects can combined by logical OR if multiple slaves are selected
|
||||
* during one transfer. Setting only QM_SS_SPI_SS_DISABLED prevents the
|
||||
* controller from starting the transfer.
|
||||
* Slave selects can be combined by logical OR.
|
||||
*/
|
||||
typedef enum {
|
||||
QM_SS_SPI_SS_DISABLED = 0, /**< Slave select disable. */
|
||||
QM_SS_SPI_SS_0 = BIT(0), /**< Slave select 0. */
|
||||
QM_SS_SPI_SS_1 = BIT(1), /**< Slave select 1. */
|
||||
QM_SS_SPI_SS_2 = BIT(2), /**< Slave select 2. */
|
||||
QM_SS_SPI_SS_3 = BIT(3), /**< Slave select 3. */
|
||||
QM_SS_SPI_SS_3 = BIT(3) /**< Slave select 3. */
|
||||
} qm_ss_spi_slave_select_t;
|
||||
|
||||
/**
|
||||
* SPI status.
|
||||
* SPI status
|
||||
*/
|
||||
typedef enum {
|
||||
QM_SS_SPI_IDLE, /**< SPI device is not in use. */
|
||||
QM_SS_SPI_BUSY, /**< SPI device is busy. */
|
||||
QM_SS_SPI_RX_OVERFLOW /**< RX transfer has overflown. */
|
||||
QM_SS_SPI_IDLE, /**< SPI device is not in use. */
|
||||
QM_SS_SPI_BUSY, /**< SPI device is busy. */
|
||||
QM_SS_SPI_RX_OVERFLOW, /**< RX transfer has overflown. */
|
||||
#if HAS_SS_SPI_VERBOSE_ERROR
|
||||
QM_SS_SPI_TX_OVERFLOW, /**< TX transfer has overflown. */
|
||||
QM_SS_SPI_RX_UNDERFLOW /**< RX transfer has underflown. */
|
||||
#endif /* HAS_SS_SPI_VERBOSE_ERROR */
|
||||
} qm_ss_spi_status_t;
|
||||
|
||||
/**
|
||||
* SPI configuration type.
|
||||
*/
|
||||
* SPI configuration type.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
qm_ss_spi_frame_size_t frame_size; /**< Frame Size. */
|
||||
qm_ss_spi_tmode_t transfer_mode; /**< Transfer mode (enum). */
|
||||
qm_ss_spi_bmode_t bus_mode; /**< Bus mode (enum). */
|
||||
qm_ss_spi_frame_size_t frame_size; /**< Frame Size */
|
||||
qm_ss_spi_tmode_t transfer_mode; /**< Transfer mode (enum) */
|
||||
qm_ss_spi_bmode_t bus_mode; /**< Bus mode (enum) */
|
||||
|
||||
/**
|
||||
* Clock divider.
|
||||
*
|
||||
* The clock divider sets the SPI speed on the interface.
|
||||
* SCK = SPI_clock/clk_divider.
|
||||
* A value of 0 will disable SCK. The LSB of this value is ignored.
|
||||
*/
|
||||
uint16_t clk_divider;
|
||||
} qm_ss_spi_config_t;
|
||||
|
||||
/**
|
||||
* SPI IRQ transfer type.
|
||||
* SPI asynchronous transfer type.
|
||||
*
|
||||
* If the frame size is 8 bits or less, 1 byte is needed per data frame. If the
|
||||
* frame size is 9-16 bits, 2 bytes are needed per data frame and frames of more
|
||||
* than 16 bits require 4 bytes. In each case, the least significant bits are
|
||||
* sent while the extra bits are discarded. The most significant bits of the
|
||||
* frame are sent first.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t *tx; /**< Write data buffer pointer. */
|
||||
uint16_t tx_len; /**< Write data length. */
|
||||
uint8_t *rx; /**< Read data buffer pointer. */
|
||||
uint16_t rx_len; /**< Read buffer length. */
|
||||
void *tx; /**< Write data. */
|
||||
void *rx; /**< Read data. */
|
||||
uint16_t tx_len; /**< Number of data frames to write. */
|
||||
uint16_t rx_len; /**< Number of data frames to read. */
|
||||
|
||||
/**
|
||||
* Transfer callback.
|
||||
|
@ -171,29 +198,35 @@ typedef struct {
|
|||
*/
|
||||
void (*callback)(void *data, int error, qm_ss_spi_status_t status,
|
||||
uint16_t len);
|
||||
void *callback_data; /**< Callback user data. */
|
||||
void *callback_data; /**< Callback user data */
|
||||
} qm_ss_spi_async_transfer_t;
|
||||
|
||||
/**
|
||||
* SPI transfer type.
|
||||
* SPI synchronous transfer type.
|
||||
*
|
||||
* If the frame size is 8 bits or less, 1 byte is needed per data frame. If the
|
||||
* frame size is 9-16 bits, 2 bytes are needed per data frame and frames of more
|
||||
* than 16 bits require 4 bytes. In each case, the least significant bits are
|
||||
* sent while the extra bits are discarded. The most significant bits of the
|
||||
* frame are sent first.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t *tx; /**< Write data buffer pointer. */
|
||||
uint16_t tx_len; /**< Write data length. */
|
||||
uint8_t *rx; /**< Read data buffer pointer. */
|
||||
uint16_t rx_len; /**< Read buffer length. */
|
||||
void *tx; /**< Write data. */
|
||||
void *rx; /**< Read data. */
|
||||
uint16_t tx_len; /**< Number of data frames to write. */
|
||||
uint16_t rx_len; /**< Number of data frames to read. */
|
||||
} qm_ss_spi_transfer_t;
|
||||
|
||||
/**
|
||||
* Set SPI configuration.
|
||||
*
|
||||
* Change the configuration of a SPI module.
|
||||
* This includes transfer mode, bus mode and clock divider.
|
||||
* This includes transfer mode, bus mode, clock divider and data frame size.
|
||||
*
|
||||
* This operation is permitted only when the SPI module is disabled.
|
||||
*
|
||||
* @param[in] spi SPI module identifier.
|
||||
* @param[in] cfg New configuration for SPI. This must not be NULL.
|
||||
* @param [in] spi SPI module identifier.
|
||||
* @param [in] cfg New configuration for SPI. This must not be NULL.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
|
@ -260,7 +293,7 @@ int qm_ss_spi_transfer(const qm_ss_spi_t spi,
|
|||
qm_ss_spi_status_t *const status);
|
||||
|
||||
/**
|
||||
* Initiate a interrupt based SPI transfer.
|
||||
* Initiate an interrupt based SPI transfer.
|
||||
*
|
||||
* Perform an interrupt based SPI transfer. If transfer mode is full duplex
|
||||
* (QM_SS_SPI_TMOD_TX_RX), then tx_len and rx_len must be equal. Similarly, for
|
||||
|
@ -280,6 +313,58 @@ int qm_ss_spi_transfer(const qm_ss_spi_t spi,
|
|||
int qm_ss_spi_irq_transfer(const qm_ss_spi_t spi,
|
||||
const qm_ss_spi_async_transfer_t *const xfer);
|
||||
|
||||
#if HAS_SS_DMA
|
||||
/**
|
||||
* Configure a DMA channel with a specific transfer direction.
|
||||
*
|
||||
* The user is responsible for managing the allocation of the pool of DMA
|
||||
* channels provided by each DMA core to the different peripheral drivers
|
||||
* that require them.
|
||||
*
|
||||
* Note that a SPI controller cannot use different DMA cores to manage
|
||||
* transfers in different directions.
|
||||
*
|
||||
* This function configures DMA channel parameters that are unlikely to change
|
||||
* between transfers, like transaction width, burst size, and handshake
|
||||
* interface parameters. The user will likely only call this function once for
|
||||
* the lifetime of an application unless the channel needs to be repurposed.
|
||||
*
|
||||
* Note that qm_dma_init() must first be called before configuring a channel.
|
||||
*
|
||||
* @param[in] spi SPI controller identifier.
|
||||
* @param[in] dma_channel_direction DMA channel direction, either
|
||||
* QM_DMA_MEMORY_TO_PERIPHERAL (TX transfer) or QM_DMA_PERIPHERAL_TO_MEMORY
|
||||
* (RX transfer).
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
/* TODO - DR AP[2756] Revisit when DMA is added the sensor SPI QMSI 1.1 */
|
||||
int qm_ss_spi_dma_channel_config(
|
||||
const qm_ss_spi_t spi,
|
||||
const qm_ss_dma_destination_target_type_t dma_channel_direction);
|
||||
|
||||
/**
|
||||
* Perform a DMA based transfer on the SPI bus. The function will
|
||||
* replenish/empty TX/RX FIFOs on DMA empty/full interrupts.
|
||||
*
|
||||
* @brief DMA based transfer on SPI.
|
||||
*
|
||||
* @param [in] spi SPI controller id
|
||||
* @param [in] xfer Transfer structure includes write / read data
|
||||
* and length; write, read and error callback
|
||||
* functions and a callback identifier.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes
|
||||
*/
|
||||
/* TODO - DR AP[2756] Revisit when DMA is added the sensor SPI QMSI 1.1 */
|
||||
int qm_ss_spi_dma_transfer(const qm_ss_spi_t spi,
|
||||
const qm_ss_spi_async_transfer_t *const xfer);
|
||||
#endif /* HAS_SS_QMSI_DMA */
|
||||
|
||||
/**
|
||||
* Terminate SPI IRQ transfer.
|
||||
*
|
||||
|
@ -295,7 +380,26 @@ int qm_ss_spi_irq_transfer(const qm_ss_spi_t spi,
|
|||
*/
|
||||
int qm_ss_spi_transfer_terminate(const qm_ss_spi_t spi);
|
||||
|
||||
#if HAS_SS_QMSI_DMA
|
||||
/**
|
||||
* Terminate SPI DMA transfer.
|
||||
*
|
||||
* Terminate the current DMA SPI transfer.
|
||||
* This function will trigger complete callbacks even
|
||||
* if the transfer is not completed.
|
||||
*
|
||||
* @param[in] spi SPI module identifier.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
/* TODO - DR AP[2756] Revisit when DMA is added the sensor SPI QMSI 1.1 */
|
||||
int qm_ss_spi_dma_transfer_terminate(const qm_ss_spi_t spi);
|
||||
#endif /* HAS_SS_QMSI_DMA */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* __QM_SS_SPI_H__ */
|
|
@ -41,100 +41,6 @@
|
|||
* @{
|
||||
*/
|
||||
|
||||
/* Divisor Latch Access Bit. */
|
||||
#define QM_UART_LCR_DLAB BIT(7)
|
||||
/* Auto Flow Control Enable Bit. */
|
||||
#define QM_UART_MCR_AFCE BIT(5)
|
||||
/* Request to Send Bit. */
|
||||
#define QM_UART_MCR_RTS BIT(1)
|
||||
|
||||
/* FIFO Enable Bit. */
|
||||
#define QM_UART_FCR_FIFOE BIT(0)
|
||||
/* Reset Receive FIFO. */
|
||||
#define QM_UART_FCR_RFIFOR BIT(1)
|
||||
/* Reset Transmit FIFO. */
|
||||
#define QM_UART_FCR_XFIFOR BIT(2)
|
||||
/* FIFO half RX, half TX Threshold. */
|
||||
#define QM_UART_FCR_DEFAULT_TX_RX_THRESHOLD (0xB0)
|
||||
/* FIFO 1 byte RX, half TX Threshold. */
|
||||
#define QM_UART_FCR_TX_1_2_RX_0_THRESHOLD (0x30)
|
||||
/* FIFO half RX, empty TX Threshold. */
|
||||
#define QM_UART_FCR_TX_0_RX_1_2_THRESHOLD (0x80)
|
||||
|
||||
/* Transmit Holding Register Empty. */
|
||||
#define QM_UART_IIR_THR_EMPTY (0x02)
|
||||
/* Received Data Available. */
|
||||
#define QM_UART_IIR_RECV_DATA_AVAIL (0x04)
|
||||
/* Receiver Line Status. */
|
||||
#define QM_UART_IIR_RECV_LINE_STATUS (0x06)
|
||||
/* Character Timeout. */
|
||||
#define QM_UART_IIR_CHAR_TIMEOUT (0x0C)
|
||||
/* Interrupt ID Mask. */
|
||||
#define QM_UART_IIR_IID_MASK (0x0F)
|
||||
|
||||
/* Data Ready Bit. */
|
||||
#define QM_UART_LSR_DR BIT(0)
|
||||
/* Overflow Error Bit. */
|
||||
#define QM_UART_LSR_OE BIT(1)
|
||||
/* Parity Error Bit. */
|
||||
#define QM_UART_LSR_PE BIT(2)
|
||||
/* Framing Error Bit. */
|
||||
#define QM_UART_LSR_FE BIT(3)
|
||||
/* Break Interrupt Bit. */
|
||||
#define QM_UART_LSR_BI BIT(4)
|
||||
/* Transmit Holding Register Empty Bit. */
|
||||
#define QM_UART_LSR_THRE BIT(5)
|
||||
/* Transmitter Empty Bit. */
|
||||
#define QM_UART_LSR_TEMT BIT(6)
|
||||
/* Receiver FIFO Error Bit. */
|
||||
#define QM_UART_LSR_RFE BIT(7)
|
||||
|
||||
/* Enable Received Data Available Interrupt. */
|
||||
#define QM_UART_IER_ERBFI BIT(0)
|
||||
/* Enable Transmit Holding Register Empty Interrupt. */
|
||||
#define QM_UART_IER_ETBEI BIT(1)
|
||||
/* Enable Receiver Line Status Interrupt. */
|
||||
#define QM_UART_IER_ELSI BIT(2)
|
||||
/* Programmable THRE Interrupt Mode. */
|
||||
#define QM_UART_IER_PTIME BIT(7)
|
||||
|
||||
/* Line Status Errors. */
|
||||
#define QM_UART_LSR_ERROR_BITS \
|
||||
(QM_UART_LSR_OE | QM_UART_LSR_PE | QM_UART_LSR_FE | QM_UART_LSR_BI)
|
||||
|
||||
/* FIFO Depth. */
|
||||
#define QM_UART_FIFO_DEPTH (16)
|
||||
/* FIFO Half Depth. */
|
||||
#define QM_UART_FIFO_HALF_DEPTH (QM_UART_FIFO_DEPTH / 2)
|
||||
|
||||
/* Divisor Latch High Offset. */
|
||||
#define QM_UART_CFG_BAUD_DLH_OFFS 16
|
||||
/* Divisor Latch Low Offset. */
|
||||
#define QM_UART_CFG_BAUD_DLL_OFFS 8
|
||||
/* Divisor Latch Fraction Offset. */
|
||||
#define QM_UART_CFG_BAUD_DLF_OFFS 0
|
||||
/* Divisor Latch High Mask. */
|
||||
#define QM_UART_CFG_BAUD_DLH_MASK (0xFF << QM_UART_CFG_BAUD_DLH_OFFS)
|
||||
/* Divisor Latch Low Mask. */
|
||||
#define QM_UART_CFG_BAUD_DLL_MASK (0xFF << QM_UART_CFG_BAUD_DLL_OFFS)
|
||||
/* Divisor Latch Fraction Mask. */
|
||||
#define QM_UART_CFG_BAUD_DLF_MASK (0xFF << QM_UART_CFG_BAUD_DLF_OFFS)
|
||||
|
||||
/* Divisor Latch Packing Helper. */
|
||||
#define QM_UART_CFG_BAUD_DL_PACK(dlh, dll, dlf) \
|
||||
(dlh << QM_UART_CFG_BAUD_DLH_OFFS | dll << QM_UART_CFG_BAUD_DLL_OFFS | \
|
||||
dlf << QM_UART_CFG_BAUD_DLF_OFFS)
|
||||
|
||||
/* Divisor Latch High Unpacking Helper. */
|
||||
#define QM_UART_CFG_BAUD_DLH_UNPACK(packed) \
|
||||
((packed & QM_UART_CFG_BAUD_DLH_MASK) >> QM_UART_CFG_BAUD_DLH_OFFS)
|
||||
/* Divisor Latch Low Unpacking Helper. */
|
||||
#define QM_UART_CFG_BAUD_DLL_UNPACK(packed) \
|
||||
((packed & QM_UART_CFG_BAUD_DLL_MASK) >> QM_UART_CFG_BAUD_DLL_OFFS)
|
||||
/* Divisor Latch Fraction Unpacking Helper. */
|
||||
#define QM_UART_CFG_BAUD_DLF_UNPACK(packed) \
|
||||
((packed & QM_UART_CFG_BAUD_DLF_MASK) >> QM_UART_CFG_BAUD_DLF_OFFS)
|
||||
|
||||
/**
|
||||
* UART Line control.
|
||||
*/
|
||||
|
@ -165,6 +71,30 @@ typedef enum {
|
|||
QM_UART_LC_8O2 = 0x0f /**< 8 data bits, odd parity, 2 stop bits. */
|
||||
} qm_uart_lc_t;
|
||||
|
||||
#if HAS_ADVANCED_UART_CONFIGURATION
|
||||
/**
|
||||
* UART Transmit Water Mark
|
||||
* Empty trigger level in the transmit FIFO.
|
||||
*/
|
||||
typedef enum {
|
||||
QM_UART_TX_WM_EMPTY = 0, /* FIFO empty */
|
||||
QM_UART_TX_WM_TWOCHAR, /* 2 characters in the FIFO */
|
||||
QM_UART_TX_WM_QUARTER, /* FIFO 1/4 full */
|
||||
QM_UART_TX_WM_HALF, /* FIFO 1/2 full */
|
||||
} qm_uart_tx_water_mark_t;
|
||||
|
||||
/**
|
||||
* UART Receive Water Mark
|
||||
* Trigger level in the receiver FIFO.
|
||||
*/
|
||||
typedef enum {
|
||||
QM_UART_RX_WM_ONEBYTE = 0, /* 1 character in the FIFO */
|
||||
QM_UART_RX_WM_QUARTER, /* FIFO 1/4 full */
|
||||
QM_UART_RX_WM_HALF, /* FIFO 1/2 full */
|
||||
QM_UART_RX_WM_TWOLESS, /* FIFO 2 less than full */
|
||||
} qm_uart_rx_water_mark_t;
|
||||
#endif /* HAS_ADVANCED_UART_CONFIGURATION */
|
||||
|
||||
/**
|
||||
* UART Status type.
|
||||
*/
|
||||
|
@ -181,13 +111,16 @@ typedef enum {
|
|||
} qm_uart_status_t;
|
||||
|
||||
/**
|
||||
* UART configuration type.
|
||||
* UART configuration structure type
|
||||
*/
|
||||
typedef struct {
|
||||
qm_uart_lc_t line_control; /**< Line control (enum). */
|
||||
uint32_t baud_divisor; /**< Baud Divisor. */
|
||||
bool hw_fc; /**< Hardware Automatic Flow Control. */
|
||||
bool int_en; /**< Interrupt enable. */
|
||||
#if HAS_ADVANCED_UART_CONFIGURATION
|
||||
qm_uart_tx_water_mark_t tx_water_mark; /* UART Tx FIFO Water Mark */
|
||||
qm_uart_rx_water_mark_t rx_water_mark; /* UART Rx FIFO Water Mark */
|
||||
#endif /* HAS_ADVANCED_UART_CONFIGURATION */
|
||||
} qm_uart_config_t;
|
||||
|
||||
/**
|
||||
|
@ -230,11 +163,14 @@ int qm_uart_set_config(const qm_uart_t uart, const qm_uart_config_t *const cfg);
|
|||
* Get UART bus status.
|
||||
*
|
||||
* Retrieve UART interface status. Return QM_UART_BUSY if transmitting
|
||||
* data; QM_UART_IDLE if available for transfer QM_UART_TX_ERROR if an
|
||||
* data; QM_UART_IDLE if available for transfer; QM_UART_TX_ERROR if an
|
||||
* error has occurred in transmission.
|
||||
*
|
||||
* The user may call this function before performing an UART transfer in order
|
||||
* to guarantee that the UART interface is available.
|
||||
|
||||
* @param[in] uart Which UART to read the status of.
|
||||
* @param[out] status UART specific status. This must not be NULL.
|
||||
* @param[out] status Current UART status. This must not be NULL.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
|
@ -248,7 +184,7 @@ int qm_uart_get_status(const qm_uart_t uart, qm_uart_status_t *const status);
|
|||
* Perform a single character write on the UART interface.
|
||||
* This is a blocking synchronous call.
|
||||
*
|
||||
* @param[in] uart UART index.
|
||||
* @param[in] uart UART identifer.
|
||||
* @param[in] data Data to write to UART.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
|
@ -263,7 +199,7 @@ int qm_uart_write(const qm_uart_t uart, const uint8_t data);
|
|||
* Perform a single character read from the UART interface.
|
||||
* This is a blocking synchronous call.
|
||||
*
|
||||
* @param[in] uart UART index.
|
||||
* @param[in] uart UART identifer.
|
||||
* @param[out] data Data to read from UART. This must not be NULL.
|
||||
* @param[out] status UART specific status.
|
||||
*
|
||||
|
@ -280,7 +216,7 @@ int qm_uart_read(const qm_uart_t uart, uint8_t *const data,
|
|||
* Perform a single character write on the UART interface.
|
||||
* This is a non-blocking synchronous call.
|
||||
*
|
||||
* @param[in] uart UART index.
|
||||
* @param[in] uart UART identifier.
|
||||
* @param[in] data Data to write to UART.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
|
@ -295,7 +231,7 @@ int qm_uart_write_non_block(const qm_uart_t uart, const uint8_t data);
|
|||
* Perform a single character read from the UART interface.
|
||||
* This is a non-blocking synchronous call.
|
||||
*
|
||||
* @param[in] uart UART index.
|
||||
* @param[in] uart UART identifer.
|
||||
* @param[out] data Character read. This must not be NULL.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
|
@ -311,7 +247,7 @@ int qm_uart_read_non_block(const qm_uart_t uart, uint8_t *const data);
|
|||
* synchronous call. The function will block until all data has
|
||||
* been transferred.
|
||||
*
|
||||
* @param[in] uart UART index.
|
||||
* @param[in] uart UART controller identifier
|
||||
* @param[in] data Data to write to UART. This must not be NULL.
|
||||
* @param[in] len Length of data to write to UART.
|
||||
*
|
||||
|
@ -320,7 +256,7 @@ int qm_uart_read_non_block(const qm_uart_t uart, uint8_t *const data);
|
|||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_uart_write_buffer(const qm_uart_t uart, const uint8_t *const data,
|
||||
uint32_t len);
|
||||
const uint32_t len);
|
||||
|
||||
/**
|
||||
* Interrupt based TX on UART.
|
||||
|
@ -328,7 +264,7 @@ int qm_uart_write_buffer(const qm_uart_t uart, const uint8_t *const data,
|
|||
* Perform an interrupt based TX transfer on the UART bus. The function
|
||||
* will replenish the TX FIFOs on UART empty interrupts.
|
||||
*
|
||||
* @param[in] uart UART index.
|
||||
* @param[in] uart UART identifier.
|
||||
* @param[in] xfer Structure containing pre-allocated
|
||||
* write buffer and callback functions.
|
||||
* The structure must not be NULL and must be kept valid until
|
||||
|
@ -347,7 +283,7 @@ int qm_uart_irq_write(const qm_uart_t uart,
|
|||
* Perform an interrupt based RX transfer on the UART bus. The function
|
||||
* will read back the RX FIFOs on UART empty interrupts.
|
||||
*
|
||||
* @param[in] uart UART index.
|
||||
* @param[in] uart UART identifier.
|
||||
* @param[in] xfer Structure containing pre-allocated read
|
||||
* buffer and callback functions.
|
||||
* The structure must not be NULL and must be kept valid until
|
||||
|
@ -366,7 +302,7 @@ int qm_uart_irq_read(const qm_uart_t uart,
|
|||
* Terminate the current IRQ TX transfer on the UART bus.
|
||||
* This will cause the relevant callbacks to be called.
|
||||
*
|
||||
* @param[in] uart UART index.
|
||||
* @param[in] uart UART identifier.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
|
@ -380,7 +316,7 @@ int qm_uart_irq_write_terminate(const qm_uart_t uart);
|
|||
* Terminate the current IRQ RX transfer on the UART bus.
|
||||
* This will cause the relevant callbacks to be called.
|
||||
*
|
||||
* @param[in] uart UART index.
|
||||
* @param[in] uart UART identifier.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
|
@ -402,7 +338,7 @@ int qm_uart_irq_read_terminate(const qm_uart_t uart);
|
|||
*
|
||||
* Note that qm_dma_init() must first be called before configuring a channel.
|
||||
*
|
||||
* @param[in] uart UART index.
|
||||
* @param[in] uart UART identifier.
|
||||
* @param[in] dma_ctrl_id DMA controller identifier.
|
||||
* @param[in] dma_channel_id DMA channel identifier.
|
||||
* @param[in] dma_channel_direction DMA channel direction, either
|
||||
|
@ -430,11 +366,10 @@ int qm_uart_dma_channel_config(
|
|||
* in addition to the DMA interrupts, the ISR of the corresponding UART must be
|
||||
* registered before using this function.
|
||||
*
|
||||
* @param[in] uart UART index.
|
||||
* @param[in] uart UART identifer.
|
||||
* @param[in] xfer Structure containing a pre-allocated write buffer
|
||||
* and callback functions.
|
||||
* This must not be NULL.
|
||||
* Callback pointer must not be NULL.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
|
@ -451,11 +386,10 @@ int qm_uart_dma_write(const qm_uart_t uart,
|
|||
* QM_DMA_PERIPHERAL_TO_MEMORY to be used on this UART, calling
|
||||
* qm_uart_dma_channel_config(). The transfer length is limited to 4KB.
|
||||
*
|
||||
* @param[in] uart UART index.
|
||||
* @param[in] uart UART identifer.
|
||||
* @param[in] xfer Structure containing a pre-allocated read buffer
|
||||
* and callback functions.
|
||||
* This must not be NULL.
|
||||
* Callback pointer must not be NULL.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
|
@ -469,7 +403,7 @@ int qm_uart_dma_read(const qm_uart_t uart,
|
|||
*
|
||||
* This will cause the relevant callbacks to be called.
|
||||
*
|
||||
* @param[in] uart UART index.
|
||||
* @param[in] uart UART identifer.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
|
@ -482,7 +416,7 @@ int qm_uart_dma_write_terminate(const qm_uart_t uart);
|
|||
*
|
||||
* This will cause the relevant callbacks to be called.
|
||||
*
|
||||
* @param[in] uart UART index.
|
||||
* @param[in] uart UART identifer.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
|
|
338
ext/hal/qmsi/drivers/include/qm_usb.h
Normal file
338
ext/hal/qmsi/drivers/include/qm_usb.h
Normal file
|
@ -0,0 +1,338 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Intel Corporation
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL CORPORATION OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __QM_USB_H__
|
||||
#define __QM_USB_H__
|
||||
|
||||
#include "qm_common.h"
|
||||
#include "qm_soc_regs.h"
|
||||
|
||||
/**
|
||||
* USB peripheral driver for Quark Microcontrollers.
|
||||
*
|
||||
* @defgroup groupUSB USB
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* USB Driver Status Codes.
|
||||
*/
|
||||
typedef enum {
|
||||
QM_USB_RESET, /**< USB reset. */
|
||||
QM_USB_CONNECTED, /**< USB connection ready and enumeration done. */
|
||||
QM_USB_CONFIGURED, /**< USB configuration completed. */
|
||||
QM_USB_DISCONNECTED, /**< USB connection lost. */
|
||||
QM_USB_SUSPEND, /**< USB connection suspended by the HOST. */
|
||||
QM_USB_RESUME, /**< USB connection resumed by the HOST. */
|
||||
} qm_usb_status_t;
|
||||
|
||||
/**
|
||||
* USB Endpoint Callback Status Codes.
|
||||
*/
|
||||
typedef enum {
|
||||
QM_USB_EP_SETUP, /**< SETUP received. */
|
||||
QM_USB_EP_DATA_OUT, /**< Out transaction on this EP. */
|
||||
QM_USB_EP_DATA_IN /**< In transaction on this EP. */
|
||||
} qm_usb_ep_status_t;
|
||||
|
||||
/**
|
||||
* USB Endpoint type.
|
||||
*/
|
||||
typedef enum {
|
||||
QM_USB_EP_CONTROL = 0, /**< Control endpoint. */
|
||||
QM_USB_EP_BULK = 2, /**< Bulk type endpoint. */
|
||||
QM_USB_EP_INTERRUPT = 3 /**< Interrupt type endpoint. */
|
||||
} qm_usb_ep_type_t;
|
||||
|
||||
/**
|
||||
* USB Endpoint Configuration.
|
||||
*/
|
||||
typedef struct {
|
||||
qm_usb_ep_type_t type; /**< Endpoint type. */
|
||||
uint16_t max_packet_size; /**< Endpoint max packet size. */
|
||||
|
||||
qm_usb_ep_idx_t ep;
|
||||
|
||||
/**
|
||||
* Callback for the USB Endpoint status.
|
||||
*
|
||||
* Called for notifying of data received and available to application
|
||||
* on this endpoint.
|
||||
*
|
||||
* @param[in] data The callback user data.
|
||||
* @param[in] error 0 on success.
|
||||
* Negative @ref errno for possible error codes.
|
||||
* @param[in] ep Endpoint index.
|
||||
* @param[in] status USB Endpoint status.
|
||||
*/
|
||||
void (*callback)(void *data, int error, qm_usb_ep_idx_t ep,
|
||||
qm_usb_ep_status_t status);
|
||||
void *callback_data; /**< Callback user data. */
|
||||
} qm_usb_ep_config_t;
|
||||
|
||||
/**
|
||||
* Callback function signature for the device status.
|
||||
*
|
||||
* @param[in] data The callback user data.
|
||||
* @param[in] error 0 on success.
|
||||
* Negative @ref errno for possible error codes.
|
||||
* @param[in] status USB Controller Driver status.
|
||||
*/
|
||||
typedef void (*qm_usb_status_callback_t)(void *data, int error,
|
||||
qm_usb_status_t status);
|
||||
|
||||
/**
|
||||
* Attach the USB device.
|
||||
*
|
||||
* Upon success, the USB PLL is enabled, and the USB device is now capable
|
||||
* of transmitting and receiving on the USB bus and of generating interrupts.
|
||||
*
|
||||
* @param[in] usb Which USB module to perform action.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_usb_attach(const qm_usb_t usb);
|
||||
|
||||
/**
|
||||
* Detach the USB device.
|
||||
*
|
||||
* Upon success, the USB hardware PLL is powered down and USB communication
|
||||
* is disabled.
|
||||
*
|
||||
* @param[in] usb Which USB module to perform action.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_usb_detach(const qm_usb_t usb);
|
||||
|
||||
/**
|
||||
* Reset the USB device controller back to it's initial state.
|
||||
*
|
||||
* Performs the Core Soft Reset from the USB controller.
|
||||
* This means that all internal state machines are reset to the IDLE state,
|
||||
* all FIFOs are flushed and all ongoing transactions are terminated.
|
||||
*
|
||||
* @note This function does NOT disable the USB clock PLL.
|
||||
*
|
||||
* @param[in] usb Which USB module to perform action.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_usb_reset(const qm_usb_t usb);
|
||||
|
||||
/**
|
||||
* Set USB device address.
|
||||
*
|
||||
* @param[in] usb Which USB module to perform action.
|
||||
* @param[in] addr USB Device Address.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_usb_set_address(const qm_usb_t usb, const uint8_t addr);
|
||||
|
||||
/**
|
||||
* Set USB device controller status callback.
|
||||
*
|
||||
* @param[in] usb Which USB module to perform action.
|
||||
* @param[in] cb USB Device Status callback.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_usb_set_status_callback(const qm_usb_t usb,
|
||||
const qm_usb_status_callback_t cb);
|
||||
|
||||
/**
|
||||
* Configure endpoint.
|
||||
*
|
||||
* @param[in] usb Which USB module to perform action.
|
||||
* @param[in] cfg Endpoint configuration.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_usb_ep_set_config(const qm_usb_t usb,
|
||||
const qm_usb_ep_config_t *const cfg);
|
||||
|
||||
/**
|
||||
* Set / Clear stall condition for the selected endpoint.
|
||||
*
|
||||
* @param[in] usb Which USB module to perform action.
|
||||
* @param[in] ep Endpoint index corresponding to the one listed in the
|
||||
* device configuration table.
|
||||
* @param[in] is_stalled Endpoint stall state to be set.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_usb_ep_set_stall_state(const qm_usb_t usb, const qm_usb_ep_idx_t ep,
|
||||
const bool is_stalled);
|
||||
|
||||
/**
|
||||
* Check stall condition for the selected endpoint.
|
||||
*
|
||||
* @param[in] usb Which USB module to perform action.
|
||||
* @param[in] ep Endpoint index corresponding to the one listed in the
|
||||
* device configuration table.
|
||||
* @param[out] stalled Endpoint stall state. Must not be NULL.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_usb_ep_is_stalled(const qm_usb_t usb, const qm_usb_ep_idx_t ep,
|
||||
bool *const stalled);
|
||||
|
||||
/**
|
||||
* Halt the selected endpoint.
|
||||
*
|
||||
* @param[in] usb Which USB module to perform action.
|
||||
* @param[in] ep Endpoint index corresponding to the one listed in the
|
||||
* device configuration table.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_usb_ep_halt(const qm_usb_t usb, const qm_usb_ep_idx_t ep);
|
||||
|
||||
/**
|
||||
* Enable the selected endpoint.
|
||||
*
|
||||
* @param[in] usb Which USB module to perform action.
|
||||
* @param[in] ep Endpoint index corresponding to the one listed in the
|
||||
* device configuration table.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_usb_ep_enable(const qm_usb_t usb, const qm_usb_ep_idx_t ep);
|
||||
|
||||
/**
|
||||
* Disable the selected endpoint.
|
||||
*
|
||||
* @param[in] usb Which USB module to perform action.
|
||||
* @param[in] ep Endpoint index corresponding to the one listed in the
|
||||
* device configuration table.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_usb_ep_disable(const qm_usb_t usb, const qm_usb_ep_idx_t ep);
|
||||
|
||||
/**
|
||||
* Flush the selected IN endpoint TX FIFO.
|
||||
*
|
||||
* RX FIFO is global and cannot be flushed per endpoint. Thus, this function
|
||||
* only applies to endpoints of direction IN.
|
||||
*
|
||||
* @param[in] usb Which USB module to perform action.
|
||||
* @param[in] ep Endpoint index corresponding to the one listed in the
|
||||
* device configuration table. Must be of IN direction.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_usb_ep_flush(const qm_usb_t usb, const qm_usb_ep_idx_t ep);
|
||||
|
||||
/**
|
||||
* Write data to the specified IN endpoint.
|
||||
*
|
||||
* @param[in] usb Which USB module to perform action.
|
||||
* @param[in] ep Endpoint index corresponding to the one listed in the
|
||||
* device configuration table. Must be of IN direction.
|
||||
* @param[in] data Pointer to data to write.
|
||||
* @param[in] len Length of data requested to write. This may be zero for
|
||||
* a zero length status packet.
|
||||
* @param[out] ret_bytes Bytes scheduled for transmission. This value may be
|
||||
* NULL if the application expects all bytes to be
|
||||
* written.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_usb_ep_write(const qm_usb_t usb, const qm_usb_ep_idx_t ep,
|
||||
const uint8_t *const data, const uint32_t len,
|
||||
uint32_t *const ret_bytes);
|
||||
|
||||
/**
|
||||
* Read data from OUT endpoint.
|
||||
*
|
||||
* This function is called by the Endpoint handler function, after an OUT
|
||||
* interrupt has been received for that EP.
|
||||
*
|
||||
* @param[in] usb Which USB module to perform action.
|
||||
* @param[in] ep Endpoint index corresponding to the one listed in the
|
||||
* device configuration table. Must be of OUT direction.
|
||||
* @param[in] data Pointer to data to read to. Must not be null.
|
||||
* @param[in] max_len Length of data requested to be read.
|
||||
* @param[out] read_bytes Number of bytes read.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_usb_ep_read(const qm_usb_t usb, const qm_usb_ep_idx_t ep,
|
||||
uint8_t *const data, const uint32_t max_len,
|
||||
uint32_t *const read_bytes);
|
||||
|
||||
/**
|
||||
* Check how many bytes are available on OUT endpoint.
|
||||
*
|
||||
* @param[in] usb Which USB module to perform action.
|
||||
* @param[in] ep Endpoint index corresponding to the one listed in the
|
||||
* device configuration table. Must be of OUT direction.
|
||||
* @param[out] read_bytes Number of bytes read. Must not be null.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int qm_usb_ep_get_bytes_read(const qm_usb_t usb, const qm_usb_ep_idx_t ep,
|
||||
uint32_t *const read_bytes);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
#endif /* __QM_USB_H__ */
|
|
@ -40,15 +40,6 @@
|
|||
* @{
|
||||
*/
|
||||
|
||||
/* Watchdog enable. */
|
||||
#define QM_WDT_ENABLE (BIT(0))
|
||||
/* Watchdog mode. */
|
||||
#define QM_WDT_MODE (BIT(1))
|
||||
/* Watchdog mode offset. */
|
||||
#define QM_WDT_MODE_OFFSET (1)
|
||||
/* Watchdog Timeout Mask. */
|
||||
#define QM_WDT_TIMEOUT_MASK (0xF)
|
||||
|
||||
/**
|
||||
* WDT Mode type.
|
||||
*/
|
||||
|
@ -57,8 +48,7 @@ typedef enum {
|
|||
*
|
||||
* The watchdog will request a SoC Warm Reset on a timeout.
|
||||
*/
|
||||
QM_WDT_MODE_RESET,
|
||||
|
||||
QM_WDT_MODE_RESET = 0,
|
||||
/** Watchdog Interrupt Reset Response Mode.
|
||||
*
|
||||
* The watchdog will generate an interrupt on first timeout.
|
||||
|
@ -68,35 +58,32 @@ typedef enum {
|
|||
QM_WDT_MODE_INTERRUPT_RESET
|
||||
} qm_wdt_mode_t;
|
||||
|
||||
/**
|
||||
* WDT clock cycles for timeout type. This value is a power of 2.
|
||||
*/
|
||||
typedef enum {
|
||||
QM_WDT_2_POW_16_CYCLES, /**< 16 clock cycles timeout. */
|
||||
QM_WDT_2_POW_17_CYCLES, /**< 17 clock cycles timeout. */
|
||||
QM_WDT_2_POW_18_CYCLES, /**< 18 clock cycles timeout. */
|
||||
QM_WDT_2_POW_19_CYCLES, /**< 19 clock cycles timeout. */
|
||||
QM_WDT_2_POW_20_CYCLES, /**< 20 clock cycles timeout. */
|
||||
QM_WDT_2_POW_21_CYCLES, /**< 21 clock cycles timeout. */
|
||||
QM_WDT_2_POW_22_CYCLES, /**< 22 clock cycles timeout. */
|
||||
QM_WDT_2_POW_23_CYCLES, /**< 23 clock cycles timeout. */
|
||||
QM_WDT_2_POW_24_CYCLES, /**< 24 clock cycles timeout. */
|
||||
QM_WDT_2_POW_25_CYCLES, /**< 25 clock cycles timeout. */
|
||||
QM_WDT_2_POW_26_CYCLES, /**< 26 clock cycles timeout. */
|
||||
QM_WDT_2_POW_27_CYCLES, /**< 27 clock cycles timeout. */
|
||||
QM_WDT_2_POW_28_CYCLES, /**< 28 clock cycles timeout. */
|
||||
QM_WDT_2_POW_29_CYCLES, /**< 29 clock cycles timeout. */
|
||||
QM_WDT_2_POW_30_CYCLES, /**< 30 clock cycles timeout. */
|
||||
QM_WDT_2_POW_31_CYCLES, /**< 31 clock cycles timeout. */
|
||||
QM_WDT_2_POW_CYCLES_NUM
|
||||
} qm_wdt_clock_timeout_cycles_t;
|
||||
|
||||
/**
|
||||
* QM WDT configuration type.
|
||||
*/
|
||||
typedef struct {
|
||||
qm_wdt_clock_timeout_cycles_t timeout; /**< Timeout in cycles. */
|
||||
qm_wdt_mode_t mode; /**< Watchdog response mode. */
|
||||
/**
|
||||
* Index for the WDT timeout table.
|
||||
* For each instantiation of WDT there are multiple timeout
|
||||
* values pre-programmed in hardware.
|
||||
* Reference the SoC datasheet or register file for the table
|
||||
* associated to the WDT being configured.
|
||||
*/
|
||||
uint32_t timeout;
|
||||
qm_wdt_mode_t mode; /**< Watchdog response mode. */
|
||||
#if (HAS_WDT_PAUSE)
|
||||
/**
|
||||
* Pause enable in LMT power state C2 and C2 Plus.
|
||||
*
|
||||
* When equal to 1, the WDT is paused when LMT enters the C2
|
||||
* state. When equal to 0, the WDT is not paused when LMT
|
||||
* enters the C2 state.
|
||||
*
|
||||
* This field applies only to Watchdogs on AON power island.
|
||||
*
|
||||
*/
|
||||
bool pause_en;
|
||||
#endif /* HAS_WDT_PAUSE */
|
||||
|
||||
/**
|
||||
* User callback.
|
||||
|
|
|
@ -56,6 +56,11 @@ static void ss_register_irq(unsigned int vector);
|
|||
#define SCSS_INT_MASK BIT(0) /* Lakemont interrupt masking */
|
||||
#endif
|
||||
|
||||
/* x86 CPU FLAGS.IF register field (Interrupt enable Flag, bit 9), indicating
|
||||
* whether or not CPU interrupts are enabled.
|
||||
*/
|
||||
#define X86_FLAGS_IF BIT(9)
|
||||
|
||||
void qm_irq_disable(void)
|
||||
{
|
||||
#if (QM_SENSOR)
|
||||
|
@ -74,6 +79,68 @@ void qm_irq_enable(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
#if (QM_SENSOR)
|
||||
unsigned int qm_irq_lock(void)
|
||||
{
|
||||
unsigned int key = 0;
|
||||
|
||||
/*
|
||||
* Store the ARC STATUS32 register fields relating to interrupts into
|
||||
* the variable `key' and disable interrupt delivery to the core.
|
||||
*/
|
||||
__asm__ __volatile__("clri %0" : "=r"(key));
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
void qm_irq_unlock(unsigned int key)
|
||||
{
|
||||
/*
|
||||
* Restore the ARC STATUS32 register fields relating to interrupts based
|
||||
* on the variable `key' populated by qm_irq_lock().
|
||||
*/
|
||||
__asm__ __volatile__("seti %0" : : "ir"(key));
|
||||
}
|
||||
|
||||
#else /* x86 */
|
||||
|
||||
unsigned int qm_irq_lock(void)
|
||||
{
|
||||
unsigned int key = 0;
|
||||
|
||||
/*
|
||||
* Store the CPU FLAGS register into the variable `key' and disable
|
||||
* interrupt delivery to the core.
|
||||
*/
|
||||
__asm__ __volatile__("pushfl;\n\t"
|
||||
"cli;\n\t"
|
||||
"popl %0;\n\t"
|
||||
: "=g"(key)
|
||||
:
|
||||
: "memory");
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
void qm_irq_unlock(unsigned int key)
|
||||
{
|
||||
/*
|
||||
* `key' holds the CPU FLAGS register content at the time when
|
||||
* qm_irq_lock() was called.
|
||||
*/
|
||||
if (!(key & X86_FLAGS_IF)) {
|
||||
/*
|
||||
* Interrupts were disabled when qm_irq_lock() was invoked:
|
||||
* do not re-enable interrupts.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
/* Enable interrupts */
|
||||
__asm__ __volatile__("sti;\n\t" : :);
|
||||
}
|
||||
#endif /* QM_SENSOR */
|
||||
|
||||
void qm_irq_mask(uint32_t irq)
|
||||
{
|
||||
#if (HAS_APIC)
|
||||
|
@ -121,7 +188,6 @@ void _qm_irq_setup(uint32_t irq, uint16_t register_offset)
|
|||
/* Route peripheral interrupt to Lakemont/Sensor Subsystem */
|
||||
scss_intmask = (uint32_t *)SCSS_LMT_INT_MASK_BASE + register_offset;
|
||||
|
||||
#if (QUARK_SE || QUARK_D2000 || QM_SENSOR)
|
||||
/* On Quark D2000 and Quark SE the register for the analog comparator
|
||||
* host mask has a different bit field than the other host mask
|
||||
* registers. */
|
||||
|
@ -130,13 +196,20 @@ void _qm_irq_setup(uint32_t irq, uint16_t register_offset)
|
|||
#if !defined(QUARK_D2000)
|
||||
} else if (QM_IRQ_MBOX_MASK_OFFSET == register_offset) {
|
||||
/* Masking MAILBOX irq id done inside mbox driver */
|
||||
#endif
|
||||
/*
|
||||
* DMA error mask uses 1 bit per DMA channel rather than the
|
||||
* generic host mask.
|
||||
*/
|
||||
} else if (QM_IRQ_DMA_ERR_MASK_OFFSET == register_offset) {
|
||||
#if (QM_SENSOR)
|
||||
*scss_intmask &= ~QM_INT_DMA_ERR_SS_MASK;
|
||||
#else
|
||||
*scss_intmask &= ~QM_INT_DMA_ERR_HOST_MASK;
|
||||
#endif
|
||||
} else {
|
||||
*scss_intmask &= ~SCSS_INT_MASK;
|
||||
}
|
||||
#else
|
||||
*scss_intmask &= ~SCSS_INT_MASK;
|
||||
#endif
|
||||
|
||||
#if (HAS_APIC)
|
||||
ioapic_unmask_irq(irq);
|
287
ext/hal/qmsi/drivers/mailbox/qm_mailbox.c
Normal file
287
ext/hal/qmsi/drivers/mailbox/qm_mailbox.c
Normal file
|
@ -0,0 +1,287 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Intel Corporation
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL CORPORATION OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "qm_common.h"
|
||||
#include "qm_mailbox.h"
|
||||
#include "qm_interrupt.h"
|
||||
|
||||
/**
|
||||
* The Active core can be either Lakemont or the Sensor Sub-System.
|
||||
* The active core depends on a compilation flag indicating which
|
||||
* core is being used.
|
||||
*
|
||||
* Core specific mailbox #defines are grouped here to prevent
|
||||
* duplication below.
|
||||
*/
|
||||
#if (HAS_MAILBOX_LAKEMONT_DEST)
|
||||
#ifdef QM_LAKEMONT
|
||||
#define ACTIVE_CORE_DEST QM_MBOX_TO_LMT
|
||||
#define MBOX_INT_MASK QM_MBOX_LMT_INT_MASK
|
||||
#define MBOX_INT_LOCK_MASK(N) QM_MBOX_LMT_INT_LOCK_MASK(N)
|
||||
#define MBOX_INT_LOCK_HALT_MASK(N) QM_MBOX_LMT_INT_LOCK_HALT_MASK(N)
|
||||
#define MBOX_ENABLE_INT_MASK(N) QM_MBOX_ENABLE_LMT_INT_MASK(N)
|
||||
#define MBOX_DISABLE_INT_MASK(N) QM_MBOX_DISABLE_LMT_INT_MASK(N)
|
||||
#endif /* QM_LAKEMONT */
|
||||
#endif /* HAS_MAILBOX_LAKEMONT_DEST */
|
||||
|
||||
#if (HAS_MAILBOX_SENSOR_SUB_SYSTEM_DEST)
|
||||
#ifdef QM_SENSOR
|
||||
#define ACTIVE_CORE_DEST QM_MBOX_TO_SS
|
||||
#define MBOX_INT_MASK QM_MBOX_SS_INT_MASK
|
||||
#define MBOX_INT_LOCK_MASK(N) QM_MBOX_SS_INT_LOCK_HALT_MASK(N)
|
||||
#define MBOX_INT_LOCK_HALT_MASK(N) QM_MBOX_SS_INT_LOCK_MASK(N)
|
||||
#define MBOX_ENABLE_INT_MASK(N) QM_MBOX_ENABLE_SS_INT_MASK(N)
|
||||
#define MBOX_DISABLE_INT_MASK(N) QM_MBOX_DISABLE_SS_INT_MASK(N)
|
||||
#endif /* QM_SENSOR */
|
||||
#endif /* HAS_MAILBOX_SENSOR_SUB_SYSTEM_DEST */
|
||||
|
||||
/**
|
||||
* Private data structure maintained by the driver
|
||||
*/
|
||||
typedef struct {
|
||||
/** Destination of the mailbox channel. */
|
||||
qm_mbox_destination_t dest;
|
||||
/** Defines if the mailbox channel operates in interrupt
|
||||
* mode or polling mode. */
|
||||
qm_mbox_mode_t mode;
|
||||
/** Callback function registered with the application. */
|
||||
qm_mbox_callback_t callback;
|
||||
/** Callback function data return via the callback function. */
|
||||
void *callback_data;
|
||||
} qm_mailbox_info_t;
|
||||
|
||||
/* Mailbox channels private data structures */
|
||||
static qm_mailbox_info_t mailbox_devs[QM_MBOX_CH_NUM];
|
||||
|
||||
QM_ISR_DECLARE(qm_mbox_isr)
|
||||
{
|
||||
qm_mailbox_t *const mbox_reg = (qm_mailbox_t *)QM_MAILBOX;
|
||||
uint8_t i = 0;
|
||||
uint8_t mask;
|
||||
uint16_t chall_sts = QM_MAILBOX->mbox_chall_sts;
|
||||
|
||||
mask = MBOX_INT_MASK;
|
||||
|
||||
for (i = 0; chall_sts; i++, chall_sts >>= 2) {
|
||||
if ((chall_sts & QM_MBOX_CH_STS_CTRL_INT) == 0) {
|
||||
continue;
|
||||
}
|
||||
if (mask & BIT(i)) {
|
||||
continue;
|
||||
}
|
||||
if (mbox_reg[i].ch_sts & QM_MBOX_CH_STS_CTRL_INT) {
|
||||
if (NULL != mailbox_devs[i].callback) {
|
||||
/* Callback */
|
||||
mailbox_devs[i].callback(
|
||||
mailbox_devs[i].callback_data);
|
||||
}
|
||||
/* Clear the interrupt */
|
||||
mbox_reg[i].ch_sts = QM_MBOX_CH_STS_CTRL_INT;
|
||||
}
|
||||
}
|
||||
|
||||
QM_ISR_EOI(QM_IRQ_MBOX_VECTOR);
|
||||
}
|
||||
|
||||
int qm_mbox_ch_set_config(const qm_mbox_ch_t mbox_ch,
|
||||
const qm_mbox_config_t *const config)
|
||||
{
|
||||
|
||||
QM_CHECK((QM_MBOX_CH_0 <= mbox_ch) && (mbox_ch < QM_MBOX_CH_NUM),
|
||||
-EINVAL);
|
||||
qm_mailbox_info_t *device = &mailbox_devs[mbox_ch];
|
||||
|
||||
/* Block interrupts while configuring MBOX */
|
||||
qm_irq_mask(QM_IRQ_MBOX);
|
||||
|
||||
/* Store the device destination */
|
||||
device->dest = config->dest;
|
||||
|
||||
/* Check if we are enabling or disabling the channel. */
|
||||
if (QM_MBOX_UNUSED != config->dest) {
|
||||
|
||||
if (QM_MBOX_INTERRUPT_MODE == config->mode) {
|
||||
QM_CHECK(NULL != config->callback, -EINVAL);
|
||||
|
||||
/* Register callback function */
|
||||
device->callback = config->callback;
|
||||
/* Register callback function data */
|
||||
device->callback_data = config->callback_data;
|
||||
/* Update the mode of operation for the mailbox channel.
|
||||
*/
|
||||
device->mode = QM_MBOX_INTERRUPT_MODE;
|
||||
|
||||
/* Enable the mailbox interrupt if the lock is not set.
|
||||
*/
|
||||
if (!(MBOX_INT_LOCK_MASK(mbox_ch))) {
|
||||
/* Note: Routing is done now, cannot be done in
|
||||
* irq_request! */
|
||||
MBOX_ENABLE_INT_MASK(mbox_ch);
|
||||
}
|
||||
} else {
|
||||
device->mode = QM_MBOX_POLLING_MODE;
|
||||
/* Disable the mailbox interrupt if the lock is not set.
|
||||
*/
|
||||
if (!(MBOX_INT_LOCK_MASK(mbox_ch))) {
|
||||
/* Note: Routing is done now, cannot be done in
|
||||
* irq_request! */
|
||||
MBOX_DISABLE_INT_MASK(mbox_ch);
|
||||
}
|
||||
device->callback = NULL;
|
||||
device->callback_data = 0;
|
||||
}
|
||||
} else {
|
||||
/* Disable the mailbox interrupt if the lock is not set. */
|
||||
if (!(MBOX_INT_LOCK_MASK(mbox_ch))) {
|
||||
/* Note: Routing is done now, cannot be done in
|
||||
* irq_request! */
|
||||
MBOX_DISABLE_INT_MASK(mbox_ch);
|
||||
}
|
||||
|
||||
/* Set the mailbox channel to its default configuration. */
|
||||
device->mode = QM_MBOX_INTERRUPT_MODE;
|
||||
device->callback = NULL;
|
||||
device->callback_data = 0;
|
||||
}
|
||||
|
||||
/* UnBlock MBOX interrupts. */
|
||||
qm_irq_unmask(QM_IRQ_MBOX);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qm_mbox_ch_write(const qm_mbox_ch_t mbox_ch, const qm_mbox_msg_t *const msg)
|
||||
{
|
||||
QM_CHECK((QM_MBOX_CH_0 <= mbox_ch) && (mbox_ch < QM_MBOX_CH_NUM),
|
||||
-EINVAL);
|
||||
QM_CHECK(NULL != msg, -EINVAL);
|
||||
qm_mailbox_t *const mbox_reg = (qm_mailbox_t *)QM_MAILBOX + mbox_ch;
|
||||
|
||||
uint32_t status = 0;
|
||||
|
||||
status = QM_MAILBOX->mbox[mbox_ch].ch_sts;
|
||||
|
||||
/* Check if the previous message has been consumed. */
|
||||
if (false == (status & (QM_MBOX_CH_STS_CTRL_INT | QM_MBOX_CH_STS))) {
|
||||
/* Write the payload data to the mailbox channel. */
|
||||
mbox_reg->ch_data[0] = msg->data[QM_MBOX_PAYLOAD_0];
|
||||
mbox_reg->ch_data[1] = msg->data[QM_MBOX_PAYLOAD_1];
|
||||
mbox_reg->ch_data[2] = msg->data[QM_MBOX_PAYLOAD_2];
|
||||
mbox_reg->ch_data[3] = msg->data[QM_MBOX_PAYLOAD_3];
|
||||
/* Write the control word and trigger the channel interrupt. */
|
||||
mbox_reg->ch_ctrl = msg->ctrl | QM_MBOX_CH_CTRL_INT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Previous message has not been consumed. */
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
int qm_mbox_ch_read(const qm_mbox_ch_t mbox_ch, qm_mbox_msg_t *const msg)
|
||||
{
|
||||
QM_CHECK((QM_MBOX_CH_0 <= mbox_ch) && (mbox_ch < QM_MBOX_CH_NUM),
|
||||
-EINVAL);
|
||||
QM_CHECK(NULL != msg, -EINVAL);
|
||||
|
||||
int rc = 0;
|
||||
uint32_t status = 0;
|
||||
|
||||
qm_mailbox_t *mbox_reg = &QM_MAILBOX->mbox[mbox_ch];
|
||||
qm_mailbox_info_t *device = &mailbox_devs[mbox_ch];
|
||||
|
||||
if (ACTIVE_CORE_DEST == device->dest) {
|
||||
status = mbox_reg->ch_sts;
|
||||
|
||||
/* If there is data pending consume it */
|
||||
if (status & QM_MBOX_CH_STS) {
|
||||
/* Read data from the mailbox channel and clear bit 31
|
||||
* of the control word. */
|
||||
msg->ctrl = mbox_reg->ch_ctrl & (~QM_MBOX_CH_CTRL_INT);
|
||||
msg->data[0] = mbox_reg->ch_data[0];
|
||||
msg->data[1] = mbox_reg->ch_data[1];
|
||||
msg->data[2] = mbox_reg->ch_data[2];
|
||||
msg->data[3] = mbox_reg->ch_data[3];
|
||||
|
||||
if (QM_MBOX_POLLING_MODE == device->mode) {
|
||||
/* In polling mode the interrupt status still
|
||||
* needs to be cleared since we are not using
|
||||
* the ISR. Note we write 1 to clear the bit.
|
||||
*/
|
||||
mbox_reg->ch_sts = QM_MBOX_CH_STS_CTRL_INT;
|
||||
}
|
||||
|
||||
/* Clear data status bit. This indicates to others that
|
||||
* the mailbox data has been consumed and a new message
|
||||
* can be sent on the channel */
|
||||
mbox_reg->ch_sts = QM_MBOX_CH_STS;
|
||||
} else {
|
||||
/* there is no pending data in the mailbox */
|
||||
rc = -EIO;
|
||||
}
|
||||
} else {
|
||||
/* Active destination has not been configured to consume data
|
||||
* from this channel */
|
||||
rc = -EINVAL;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int qm_mbox_ch_get_status(const qm_mbox_ch_t mbox_ch,
|
||||
qm_mbox_ch_status_t *const status)
|
||||
{
|
||||
QM_CHECK((QM_MBOX_CH_0 <= mbox_ch) && (mbox_ch < QM_MBOX_CH_NUM),
|
||||
-EINVAL);
|
||||
QM_CHECK(NULL != status, -EINVAL);
|
||||
|
||||
uint32_t mbox_status = QM_MAILBOX->mbox[mbox_ch].ch_sts;
|
||||
qm_mbox_ch_status_t rc = QM_MBOX_CH_IDLE;
|
||||
|
||||
/* Check if the mailbox is in polling mode or not */
|
||||
if (QM_MBOX_POLLING_MODE == mailbox_devs[mbox_ch].mode) {
|
||||
/* Polling Mode
|
||||
* Check if there is pending data to be consumed
|
||||
*/
|
||||
if (QM_MBOX_CH_STS & mbox_status) {
|
||||
rc = QM_MBOX_CH_POLLING_DATA_PEND;
|
||||
}
|
||||
} else {
|
||||
/* Interrupt Mode
|
||||
* Check if there is a pending interrupt & data,
|
||||
* otherwise check if there is pending data to be consumed
|
||||
*/
|
||||
if (QM_MBOX_STATUS_MASK == mbox_status) {
|
||||
rc = QM_MBOX_CH_INT_NACK_DATA_PEND;
|
||||
} else if (QM_MBOX_CH_STS == mbox_status) {
|
||||
rc = QM_MBOX_CH_INT_ACK_DATA_PEND;
|
||||
}
|
||||
}
|
||||
|
||||
*status = rc;
|
||||
return 0;
|
||||
}
|
|
@ -58,7 +58,8 @@ int qm_mpr_set_config(const qm_mpr_id_t id, const qm_mpr_config_t *const cfg)
|
|||
/* MPR Upper bound 16:10 */
|
||||
((cfg->up_bound & ADDRESS_MASK_7_BIT) << QM_MPR_UP_BOUND_OFFSET)
|
||||
/* MPR Lower bound 6:0 */
|
||||
| cfg->low_bound;
|
||||
|
|
||||
cfg->low_bound;
|
||||
|
||||
/* enable/lock */
|
||||
QM_MPR->mpr_cfg[id] |= (cfg->en_lock_mask << QM_MPR_EN_LOCK_OFFSET);
|
|
@ -1,191 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Intel Corporation
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL CORPORATION OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "qm_common.h"
|
||||
#include "qm_mailbox.h"
|
||||
#include "qm_interrupt.h"
|
||||
|
||||
/* Register offsets from a base register for a particular mailbox channel. */
|
||||
#define QM_MBOX_CTRL_OFFSET (0x00)
|
||||
#define QM_MBOX_DATA0_OFFSET (0x04)
|
||||
#define QM_MBOX_DATA1_OFFSET (0x08)
|
||||
#define QM_MBOX_DATA2_OFFSET (0x0C)
|
||||
#define QM_MBOX_DATA3_OFFSET (0x10)
|
||||
#define QM_MBOX_STATUS_OFFSET (0x14)
|
||||
|
||||
#define QM_MBOX_SS_MASK_OFFSET (0x8)
|
||||
|
||||
/* Private data structure maintained by the driver */
|
||||
typedef struct qm_mailbox_info_t {
|
||||
/*!< Callback function registered with the application. */
|
||||
qm_mbox_callback_t mpr_cb;
|
||||
/*!< Callback function data return via the callback function. */
|
||||
void *cb_data;
|
||||
} qm_mailbox_info_t;
|
||||
|
||||
/* Mailbox channels private data structures */
|
||||
static qm_mailbox_info_t mailbox_devs[QM_MBOX_CH_NUM];
|
||||
|
||||
QM_ISR_DECLARE(qm_mbox_isr)
|
||||
{
|
||||
qm_mailbox_t *const mbox_reg = (qm_mailbox_t *)QM_SCSS_MAILBOX;
|
||||
uint8_t i = 0;
|
||||
uint8_t mask;
|
||||
uint16_t chall_sts = QM_SCSS_MAILBOX->mbox_chall_sts;
|
||||
|
||||
/*
|
||||
* Interrupt masking register is has a bit assigned per MBOX channel.
|
||||
* QM_SCSS_INT 0-7 bits are MBOX interrupt gates to APIC, 8-15 are
|
||||
* gating interrupts to Sensors PIC.
|
||||
*/
|
||||
#if (QM_SENSOR)
|
||||
mask = 0xff & (QM_SCSS_INT->int_mailbox_mask >> QM_MBOX_SS_MASK_OFFSET);
|
||||
#else
|
||||
mask = 0xff & QM_SCSS_INT->int_mailbox_mask;
|
||||
#endif
|
||||
|
||||
for (i = 0; chall_sts; i++, chall_sts >>= 2) {
|
||||
if ((chall_sts & QM_MBOX_CH_INT) == 0) {
|
||||
continue;
|
||||
}
|
||||
if (mask & BIT(i)) {
|
||||
continue;
|
||||
}
|
||||
if (mbox_reg[i].ch_sts & QM_MBOX_CH_INT) {
|
||||
if (NULL != mailbox_devs[i].mpr_cb) {
|
||||
/* Callback */
|
||||
mailbox_devs[i].mpr_cb(mailbox_devs[i].cb_data);
|
||||
}
|
||||
/* Clear the interrupt */
|
||||
mbox_reg[i].ch_sts = QM_MBOX_CH_INT;
|
||||
}
|
||||
}
|
||||
|
||||
QM_ISR_EOI(QM_IRQ_MBOX_VECTOR);
|
||||
}
|
||||
|
||||
int qm_mbox_ch_set_config(const qm_mbox_ch_t mbox_ch, qm_mbox_callback_t mpr_cb,
|
||||
void *cb_data, const bool irq_en)
|
||||
{
|
||||
uint32_t mask;
|
||||
|
||||
QM_CHECK(mbox_ch < QM_MBOX_CH_NUM, -EINVAL);
|
||||
|
||||
/* Block interrupts while configuring MBOX */
|
||||
qm_irq_mask(QM_IRQ_MBOX);
|
||||
|
||||
#if (QM_SENSOR)
|
||||
/* MBOX Interrupt Routing gate to SS core. */
|
||||
mask = BIT((mbox_ch + QM_MBOX_SS_MASK_OFFSET));
|
||||
#else
|
||||
/* MBOX Interrupt Routing gate to LMT core. */
|
||||
mask = BIT(mbox_ch);
|
||||
#endif
|
||||
|
||||
/* Register callback function */
|
||||
mailbox_devs[mbox_ch].mpr_cb = mpr_cb;
|
||||
mailbox_devs[mbox_ch].cb_data = cb_data;
|
||||
|
||||
if (irq_en == true) {
|
||||
/* Note: Routing is done now, cannot be done in irq_request! */
|
||||
QM_SCSS_INT->int_mailbox_mask &= ~mask;
|
||||
/* Clear the interrupt */
|
||||
((qm_mailbox_t *)QM_SCSS_MAILBOX + mbox_ch)->ch_sts =
|
||||
QM_MBOX_CH_INT;
|
||||
} else {
|
||||
/* Note: Routing is done now, cannot be done in irq_request! */
|
||||
QM_SCSS_INT->int_mailbox_mask |= mask;
|
||||
}
|
||||
|
||||
/* UnBlock MBOX interrupts. */
|
||||
qm_irq_unmask(QM_IRQ_MBOX);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qm_mbox_ch_write(const qm_mbox_ch_t mbox_ch,
|
||||
const qm_mbox_msg_t *const data)
|
||||
{
|
||||
qm_mailbox_t *const mbox_reg =
|
||||
(qm_mailbox_t *)QM_SCSS_MAILBOX + mbox_ch;
|
||||
|
||||
/* Check if the previous message has been consumed. */
|
||||
if (!(mbox_reg->ch_ctrl & QM_MBOX_TRIGGER_CH_INT)) {
|
||||
/* Write the payload data to the mailbox channel. */
|
||||
mbox_reg->ch_data[0] = data->data[QM_MBOX_PAYLOAD_0];
|
||||
mbox_reg->ch_data[1] = data->data[QM_MBOX_PAYLOAD_1];
|
||||
mbox_reg->ch_data[2] = data->data[QM_MBOX_PAYLOAD_2];
|
||||
mbox_reg->ch_data[3] = data->data[QM_MBOX_PAYLOAD_3];
|
||||
/* Write the control word and trigger the channel interrupt. */
|
||||
mbox_reg->ch_ctrl = data->ctrl | QM_MBOX_TRIGGER_CH_INT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Previous message has not been consumed. */
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
int qm_mbox_ch_read(const qm_mbox_ch_t mbox_ch, qm_mbox_msg_t *const data)
|
||||
{
|
||||
qm_mailbox_t *const mbox_reg =
|
||||
(qm_mailbox_t *)QM_SCSS_MAILBOX + mbox_ch;
|
||||
|
||||
/* Read data from the mailbox channel and clear bit 31 of the
|
||||
* control word. */
|
||||
data->ctrl = mbox_reg->ch_ctrl & ~QM_MBOX_TRIGGER_CH_INT;
|
||||
data->data[QM_MBOX_PAYLOAD_0] = mbox_reg->ch_data[0];
|
||||
data->data[QM_MBOX_PAYLOAD_1] = mbox_reg->ch_data[1];
|
||||
data->data[QM_MBOX_PAYLOAD_2] = mbox_reg->ch_data[2];
|
||||
data->data[QM_MBOX_PAYLOAD_3] = mbox_reg->ch_data[3];
|
||||
|
||||
/* Check if the message has arrived. */
|
||||
if (mbox_reg->ch_sts & QM_MBOX_CH_DATA) {
|
||||
/* Clear data status bit */
|
||||
mbox_reg->ch_sts = QM_MBOX_CH_DATA;
|
||||
return 0;
|
||||
}
|
||||
/* there is no new data in mailbox */
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
int qm_mbox_ch_get_status(const qm_mbox_ch_t mbox_ch,
|
||||
qm_mbox_ch_status_t *const status)
|
||||
{
|
||||
QM_CHECK(mbox_ch < QM_MBOX_CH_NUM, -EINVAL);
|
||||
qm_mailbox_t *const mbox_reg =
|
||||
(qm_mailbox_t *)QM_SCSS_MAILBOX + mbox_ch;
|
||||
*status = mbox_reg->ch_sts & QM_MBOX_CH_STATUS_MASK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qm_mbox_ch_data_ack(const qm_mbox_ch_t mbox_ch)
|
||||
{
|
||||
QM_CHECK(mbox_ch < QM_MBOX_CH_NUM, -EINVAL);
|
||||
((qm_mailbox_t *)QM_SCSS_MAILBOX + mbox_ch)->ch_sts = QM_MBOX_CH_DATA;
|
||||
return 0;
|
||||
}
|
|
@ -28,6 +28,7 @@
|
|||
*/
|
||||
|
||||
#include "qm_rtc.h"
|
||||
#include "clk.h"
|
||||
|
||||
static void (*callback[QM_RTC_NUM])(void *data);
|
||||
static void *callback_data[QM_RTC_NUM];
|
||||
|
@ -79,7 +80,7 @@ int qm_rtc_set_config(const qm_rtc_t rtc, const qm_rtc_config_t *const cfg)
|
|||
QM_CHECK(cfg != NULL, -EINVAL);
|
||||
|
||||
/* set rtc divider */
|
||||
clk_rtc_set_div(QM_RTC_DIVIDER);
|
||||
clk_rtc_set_div(cfg->prescaler);
|
||||
|
||||
QM_RTC[rtc].rtc_clr = cfg->init_val;
|
||||
|
|
@ -276,7 +276,9 @@ int qm_spi_set_config(const qm_spi_t spi, const qm_spi_config_t *cfg)
|
|||
QM_CHECK(spi < QM_SPI_NUM, -EINVAL);
|
||||
QM_CHECK(cfg, -EINVAL);
|
||||
|
||||
QM_ASSERT(QM_SPI[spi]->ssienr == 0);
|
||||
if (0 != QM_SPI[spi]->ssienr) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
qm_spi_reg_t *const controller = QM_SPI[spi];
|
||||
|
||||
|
@ -305,7 +307,9 @@ int qm_spi_slave_select(const qm_spi_t spi, const qm_spi_slave_select_t ss)
|
|||
QM_CHECK(spi < QM_SPI_NUM, -EINVAL);
|
||||
|
||||
/* Check if the device reports as busy. */
|
||||
QM_ASSERT(!(QM_SPI[spi]->sr & QM_SPI_SR_BUSY));
|
||||
if (QM_SPI[spi]->sr & QM_SPI_SR_BUSY) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
QM_SPI[spi]->ser = ss;
|
||||
|
||||
|
@ -601,6 +605,7 @@ int qm_spi_dma_channel_config(
|
|||
dma_chan_cfg.handshake_polarity = QM_DMA_HANDSHAKE_POLARITY_HIGH;
|
||||
dma_chan_cfg.channel_direction = dma_channel_direction;
|
||||
dma_chan_cfg.client_callback = spi_dma_callback;
|
||||
dma_chan_cfg.transfer_type = QM_DMA_TYPE_SINGLE;
|
||||
|
||||
/* Every data transfer performed by the DMA core corresponds to an SPI
|
||||
* data frame, the SPI uses the number of bits determined by a previous
|
||||
|
@ -722,7 +727,9 @@ int qm_spi_dma_transfer(const qm_spi_t spi,
|
|||
int ret;
|
||||
qm_dma_transfer_t dma_trans = {0};
|
||||
qm_spi_reg_t *const controller = QM_SPI[spi];
|
||||
QM_ASSERT(0 == controller->ssienr);
|
||||
if (0 != controller->ssienr) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* Mask interrupts. */
|
||||
controller->imr = QM_SPI_IMR_MASK_ALL;
|
|
@ -88,9 +88,10 @@ int qm_ss_spi_set_config(const qm_ss_spi_t spi,
|
|||
QM_CHECK(spi < QM_SS_SPI_NUM, -EINVAL);
|
||||
QM_CHECK(cfg, -EINVAL);
|
||||
/* Configuration can be changed only when SPI is disabled */
|
||||
/* NOTE: check if QM_ASSERT is the right thing to do here */
|
||||
QM_ASSERT((__builtin_arc_lr(base[spi] + QM_SS_SPI_SPIEN) &
|
||||
QM_SS_SPI_SPIEN_EN) == 0);
|
||||
if (0 != (__builtin_arc_lr(base[spi] + QM_SS_SPI_SPIEN) &
|
||||
QM_SS_SPI_SPIEN_EN)) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
uint32_t ctrl = __builtin_arc_lr(QM_SS_SPI_0_BASE + QM_SS_SPI_CTRL);
|
||||
ctrl &= QM_SS_SPI_CTRL_CLK_ENA;
|
||||
|
@ -110,9 +111,9 @@ int qm_ss_spi_slave_select(const qm_ss_spi_t spi,
|
|||
QM_CHECK(spi < QM_SS_SPI_NUM, -EINVAL);
|
||||
|
||||
/* Check if the device reports as busy. */
|
||||
/* NOTE: check if QM_ASSERT is the right thing to do here */
|
||||
QM_ASSERT(
|
||||
!(__builtin_arc_lr(base[spi] + QM_SS_SPI_SR) & QM_SS_SPI_SR_BUSY));
|
||||
if (__builtin_arc_lr(base[spi] + QM_SS_SPI_SR) & QM_SS_SPI_SR_BUSY) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
uint32_t spien = __builtin_arc_lr(base[spi] + QM_SS_SPI_SPIEN);
|
||||
spien &= ~QM_SS_SPI_SPIEN_SER_MASK;
|
|
@ -243,6 +243,7 @@ int qm_uart_set_config(const qm_uart_t uart, const qm_uart_config_t *cfg)
|
|||
QM_CHECK(cfg != NULL, -EINVAL);
|
||||
|
||||
qm_uart_reg_t *const regs = QM_UART[uart];
|
||||
volatile uint32_t unused_lsr __attribute__((unused));
|
||||
|
||||
/* Clear DLAB by unsetting line parameters */
|
||||
regs->lcr = 0;
|
||||
|
@ -268,6 +269,9 @@ int qm_uart_set_config(const qm_uart_t uart, const qm_uart_config_t *cfg)
|
|||
QM_UART_FCR_DEFAULT_TX_RX_THRESHOLD);
|
||||
regs->ier_dlh |= QM_UART_IER_PTIME;
|
||||
|
||||
/* Clear LSR */
|
||||
unused_lsr = regs->lsr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -568,6 +572,7 @@ int qm_uart_dma_channel_config(
|
|||
dma_chan_cfg.source_burst_length = QM_DMA_BURST_TRANS_LENGTH_8;
|
||||
dma_chan_cfg.destination_burst_length = QM_DMA_BURST_TRANS_LENGTH_8;
|
||||
dma_chan_cfg.client_callback = uart_dma_callback;
|
||||
dma_chan_cfg.transfer_type = QM_DMA_TYPE_SINGLE;
|
||||
|
||||
switch (dma_channel_direction) {
|
||||
case QM_DMA_MEMORY_TO_PERIPHERAL:
|
877
ext/hal/qmsi/drivers/usb/qm_usb.c
Normal file
877
ext/hal/qmsi/drivers/usb/qm_usb.c
Normal file
|
@ -0,0 +1,877 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Intel Corporation
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL CORPORATION OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "qm_usb.h"
|
||||
#include "clk.h"
|
||||
#include <string.h>
|
||||
|
||||
/** USB registers masks */
|
||||
#define QM_USB_GRSTCTL_AHB_IDLE BIT(31)
|
||||
#define QM_USB_GRSTCTL_TX_FNUM_OFFSET (6)
|
||||
#define QM_USB_GRSTCTL_TX_FFLSH BIT(5)
|
||||
#define QM_USB_GRSTCTL_C_SFT_RST BIT(0)
|
||||
#define QM_USB_GAHBCFG_DMA_EN BIT(5)
|
||||
#define QM_USB_GAHBCFG_GLB_INTR_MASK BIT(0)
|
||||
#define QM_USB_DCTL_SFT_DISCON BIT(1)
|
||||
#define QM_USB_GINTSTS_WK_UP_INT BIT(31)
|
||||
#define QM_USB_GINTSTS_OEP_INT BIT(19)
|
||||
#define QM_USB_GINTSTS_IEP_INT BIT(18)
|
||||
#define QM_USB_GINTSTS_ENUM_DONE BIT(13)
|
||||
#define QM_USB_GINTSTS_USB_RST BIT(12)
|
||||
#define QM_USB_GINTSTS_USB_SUSP BIT(11)
|
||||
#define QM_USB_GINTSTS_RX_FLVL BIT(4)
|
||||
#define QM_USB_GINTSTS_OTG_INT BIT(2)
|
||||
#define QM_USB_DCFG_DEV_SPD_LS (0x2)
|
||||
#define QM_USB_DCFG_DEV_SPD_FS (0x3)
|
||||
#define QM_USB_DCFG_DEV_ADDR_MASK (0x7F << 4)
|
||||
#define QM_USB_DCFG_DEV_ADDR_OFFSET (4)
|
||||
#define QM_USB_DAINT_IN_EP_INT(ep) (1 << (ep))
|
||||
#define QM_USB_DAINT_OUT_EP_INT(ep) (0x10000 << (ep))
|
||||
#define QM_USB_DEPCTL_EP_ENA BIT(31)
|
||||
#define QM_USB_DEPCTL_EP_DIS BIT(30)
|
||||
#define QM_USB_DEPCTL_SETDOPID BIT(28)
|
||||
#define QM_USB_DEPCTL_SNAK BIT(27)
|
||||
#define QM_USB_DEPCTL_CNAK BIT(26)
|
||||
#define QM_USB_DEPCTL_STALL BIT(21)
|
||||
#define QM_USB_DEPCTL_EP_TYPE_MASK (0x3 << 18)
|
||||
#define QM_USB_DEPCTL_EP_TYPE_OFFSET (18)
|
||||
#define QM_USB_DEPCTL_EP_TYPE_CONTROL (0)
|
||||
#define QM_USB_DEPCTL_EP_TYPE_ISO (0x1)
|
||||
#define QM_USB_DEPCTL_EP_TYPE_BULK (0x2)
|
||||
#define QM_USB_DEPCTL_EP_TYPE_INTERRUPT (0x3)
|
||||
#define QM_USB_DEPCTL_USB_ACT_EP BIT(15)
|
||||
#define QM_USB_DEPCTL0_MSP_MASK (0x3)
|
||||
#define QM_USB_DEPCTL0_MSP_8 (0x3)
|
||||
#define QM_USB_DEPCTL0_MSP_16 (0x2)
|
||||
#define QM_USB_DEPCTL0_MSP_32 (0x1)
|
||||
#define QM_USB_DEPCTL0_MSP_64 (0)
|
||||
#define QM_USB_DEPCTLn_MSP_MASK (0x3FF)
|
||||
#define QM_USB_DEPCTL_MSP_OFFSET (0)
|
||||
#define QM_USB_DOEPTSIZ_SUP_CNT_MASK (0x3 << 29)
|
||||
#define QM_USB_DOEPTSIZ_SUP_CNT_OFFSET (29)
|
||||
#define QM_USB_DOEPTSIZ0_PKT_CNT_MASK (0x1 << 19)
|
||||
#define QM_USB_DOEPTSIZn_PKT_CNT_MASK (0x3FF << 19)
|
||||
#define QM_USB_DIEPTSIZ0_PKT_CNT_MASK (0x3 << 19)
|
||||
#define QM_USB_DIEPTSIZn_PKT_CNT_MASK (0x3FF << 19)
|
||||
#define QM_USB_DEPTSIZ_PKT_CNT_OFFSET (19)
|
||||
#define QM_USB_DEPTSIZ0_XFER_SIZE_MASK (0x7F)
|
||||
#define QM_USB_DEPTSIZn_XFER_SIZE_MASK (0x7FFFF)
|
||||
#define QM_USB_DEPTSIZ_XFER_SIZE_OFFSET (0)
|
||||
#define QM_USB_DIEPINT_XFER_COMPL BIT(0)
|
||||
#define QM_USB_DIEPINT_TX_FEMP BIT(7)
|
||||
#define QM_USB_DIEPINT_XFER_COMPL BIT(0)
|
||||
#define QM_USB_DOEPINT_SET_UP BIT(3)
|
||||
#define QM_USB_DOEPINT_XFER_COMPL BIT(0)
|
||||
#define QM_USB_DSTS_ENUM_SPD_MASK (0x3)
|
||||
#define QM_USB_DSTS_ENUM_SPD_OFFSET (1)
|
||||
#define QM_USB_DSTS_ENUM_LS (2)
|
||||
#define QM_USB_DSTS_ENUM_FS (3)
|
||||
#define QM_USB_GRXSTSR_EP_NUM_MASK (0xF << 0)
|
||||
#define QM_USB_GRXSTSR_PKT_STS_MASK (0xF << 17)
|
||||
#define QM_USB_GRXSTSR_PKT_STS_OFFSET (17)
|
||||
#define QM_USB_GRXSTSR_PKT_CNT_MASK (0x7FF << 4)
|
||||
#define QM_USB_GRXSTSR_PKT_CNT_OFFSET (4)
|
||||
#define QM_USB_GRXSTSR_PKT_STS_OUT_DATA (2)
|
||||
#define QM_USB_GRXSTSR_PKT_STS_OUT_DATA_DONE (3)
|
||||
#define QM_USB_GRXSTSR_PKT_STS_SETUP_DONE (4)
|
||||
#define QM_USB_GRXSTSR_PKT_STS_SETUP (6)
|
||||
#define QM_USB_DTXFSTS_TXF_SPC_AVAIL_MASK (0xFFFF)
|
||||
|
||||
#define QM_USB_CORE_RST_TIMEOUT_US (10000)
|
||||
#define QM_USB_PLL_TIMEOUT_US (100)
|
||||
|
||||
/** Check if an Endpoint is of direction IN. */
|
||||
#define IS_IN_EP(ep) (ep < QM_USB_IN_EP_NUM)
|
||||
|
||||
/** Number of SETUP back-to-back packets */
|
||||
#define QM_USB_SUP_CNT (1)
|
||||
|
||||
#if (UNIT_TEST)
|
||||
#define QM_USB_EP_FIFO(ep) (ep)
|
||||
#else
|
||||
#define QM_USB_EP_FIFO(ep) (*(uint32_t *)(QM_USB_0_BASE + 0x1000 * (ep + 1)))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Endpoint instance data.
|
||||
*/
|
||||
typedef struct {
|
||||
bool enabled;
|
||||
uint32_t data_len;
|
||||
const qm_usb_ep_config_t *ep_config;
|
||||
} usb_ep_priv_t;
|
||||
|
||||
/*
|
||||
* USB controller instance data.
|
||||
*/
|
||||
typedef struct {
|
||||
qm_usb_status_callback_t status_callback;
|
||||
usb_ep_priv_t ep_ctrl[QM_USB_IN_EP_NUM + QM_USB_OUT_EP_NUM];
|
||||
bool attached;
|
||||
void *user_data;
|
||||
} usb_priv_t;
|
||||
|
||||
static usb_priv_t usb_ctrl[QM_USB_NUM];
|
||||
|
||||
/* This helper is only used by QM_CHECKs, thus on Debug mode. */
|
||||
#if DEBUG || UNIT_TEST
|
||||
static bool usb_dc_ep_is_valid(const qm_usb_ep_idx_t ep)
|
||||
{
|
||||
return (ep < QM_USB_IN_EP_NUM + QM_USB_OUT_EP_NUM);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int usb_dc_reset(const qm_usb_t usb)
|
||||
{
|
||||
uint32_t cnt = 0;
|
||||
|
||||
/* Wait for AHB master idle state. */
|
||||
while (!(QM_USB[usb].grstctl & QM_USB_GRSTCTL_AHB_IDLE)) {
|
||||
clk_sys_udelay(1);
|
||||
if (++cnt > QM_USB_CORE_RST_TIMEOUT_US) {
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
/* Core Soft Reset */
|
||||
cnt = 0;
|
||||
QM_USB[usb].grstctl |= QM_USB_GRSTCTL_C_SFT_RST;
|
||||
do {
|
||||
if (++cnt > QM_USB_CORE_RST_TIMEOUT_US) {
|
||||
return -EIO;
|
||||
}
|
||||
clk_sys_udelay(1);
|
||||
} while (QM_USB[usb].grstctl & QM_USB_GRSTCTL_C_SFT_RST);
|
||||
|
||||
/* Wait for 3 PHY Clocks */
|
||||
clk_sys_udelay(100);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void usb_dc_prep_rx(const qm_usb_t usb, const qm_usb_ep_idx_t ep,
|
||||
uint8_t setup)
|
||||
{
|
||||
/* We know this is an OUT EP always. */
|
||||
const uint8_t ep_idx = ep - QM_USB_IN_EP_NUM;
|
||||
const uint16_t ep_mps =
|
||||
usb_ctrl[usb].ep_ctrl[ep].ep_config->max_packet_size;
|
||||
|
||||
/* Set max RX size to EP mps so we get an interrupt
|
||||
* each time a packet is received
|
||||
*/
|
||||
|
||||
QM_USB[usb].out_ep_reg[ep_idx].doeptsiz =
|
||||
(QM_USB_SUP_CNT << QM_USB_DOEPTSIZ_SUP_CNT_OFFSET) |
|
||||
(1 << QM_USB_DEPTSIZ_PKT_CNT_OFFSET) | ep_mps;
|
||||
|
||||
/* Clear NAK and enable ep */
|
||||
if (!setup) {
|
||||
QM_USB[usb].out_ep_reg[ep_idx].doepctl |= QM_USB_DEPCTL_CNAK;
|
||||
}
|
||||
QM_USB[usb].out_ep_reg[ep_idx].doepctl |= QM_USB_DEPCTL_EP_ENA;
|
||||
}
|
||||
|
||||
static int usb_dc_tx(const qm_usb_t usb, uint8_t ep, const uint8_t *const data,
|
||||
uint32_t data_len)
|
||||
{
|
||||
uint32_t max_xfer_size, max_pkt_cnt, pkt_cnt, avail_space;
|
||||
const uint16_t ep_mps =
|
||||
usb_ctrl[usb].ep_ctrl[ep].ep_config->max_packet_size;
|
||||
uint32_t i;
|
||||
|
||||
/* Check if FIFO space available */
|
||||
avail_space = QM_USB[usb].in_ep_reg[ep].dtxfsts &
|
||||
QM_USB_DTXFSTS_TXF_SPC_AVAIL_MASK;
|
||||
avail_space *= 4;
|
||||
if (!avail_space) {
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
if (data_len > avail_space)
|
||||
data_len = avail_space;
|
||||
|
||||
if (data_len != 0) {
|
||||
/* Get max packet size and packet count for ep */
|
||||
if (ep == QM_USB_IN_EP_0) {
|
||||
max_pkt_cnt = QM_USB_DIEPTSIZ0_PKT_CNT_MASK >>
|
||||
QM_USB_DEPTSIZ_PKT_CNT_OFFSET;
|
||||
max_xfer_size = QM_USB_DEPTSIZ0_XFER_SIZE_MASK >>
|
||||
QM_USB_DEPTSIZ_XFER_SIZE_OFFSET;
|
||||
} else {
|
||||
max_pkt_cnt = QM_USB_DIEPTSIZn_PKT_CNT_MASK >>
|
||||
QM_USB_DEPTSIZ_PKT_CNT_OFFSET;
|
||||
max_xfer_size = QM_USB_DEPTSIZn_XFER_SIZE_MASK >>
|
||||
QM_USB_DEPTSIZ_XFER_SIZE_OFFSET;
|
||||
}
|
||||
|
||||
/* Check if transfer len is too big */
|
||||
if (data_len > max_xfer_size) {
|
||||
data_len = max_xfer_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* Program the transfer size and packet count as follows:
|
||||
*
|
||||
* transfer size = N * ep_maxpacket + short_packet
|
||||
* pktcnt = N + (short_packet exist ? 1 : 0)
|
||||
*/
|
||||
pkt_cnt = (data_len + ep_mps - 1) / ep_mps;
|
||||
|
||||
if (pkt_cnt > max_pkt_cnt) {
|
||||
pkt_cnt = max_pkt_cnt;
|
||||
data_len = pkt_cnt * ep_mps;
|
||||
}
|
||||
} else {
|
||||
/* Zero length packet */
|
||||
pkt_cnt = 1;
|
||||
}
|
||||
|
||||
/* Set number of packets and transfer size */
|
||||
QM_USB[usb].in_ep_reg[ep].dieptsiz =
|
||||
(pkt_cnt << QM_USB_DEPTSIZ_PKT_CNT_OFFSET) | data_len;
|
||||
|
||||
/* Clear NAK and enable ep */
|
||||
QM_USB[usb].in_ep_reg[ep].diepctl |= QM_USB_DEPCTL_CNAK;
|
||||
QM_USB[usb].in_ep_reg[ep].diepctl |= QM_USB_DEPCTL_EP_ENA;
|
||||
|
||||
/* Write data to FIFO */
|
||||
for (i = 0; i < data_len; i += 4)
|
||||
QM_USB_EP_FIFO(ep) = *(uint32_t *)(data + i);
|
||||
|
||||
return data_len;
|
||||
}
|
||||
|
||||
static void usb_dc_handle_reset(const qm_usb_t usb)
|
||||
{
|
||||
if (usb_ctrl[usb].status_callback) {
|
||||
usb_ctrl[usb].status_callback(usb_ctrl[usb].user_data, 0,
|
||||
QM_USB_RESET);
|
||||
}
|
||||
|
||||
/* Set device address to zero after reset */
|
||||
QM_USB[usb].dcfg &= ~QM_USB_DCFG_DEV_ADDR_MASK;
|
||||
|
||||
/* enable global EP interrupts */
|
||||
QM_USB[usb].doepmsk = 0;
|
||||
QM_USB[usb].gintmsk |= QM_USB_GINTSTS_RX_FLVL;
|
||||
QM_USB[usb].diepmsk |= QM_USB_DIEPINT_XFER_COMPL;
|
||||
}
|
||||
|
||||
static void usb_dc_handle_enum_done(const qm_usb_t usb)
|
||||
{
|
||||
if (usb_ctrl[usb].status_callback) {
|
||||
usb_ctrl[usb].status_callback(usb_ctrl[usb].user_data, 0,
|
||||
QM_USB_CONNECTED);
|
||||
}
|
||||
}
|
||||
|
||||
static __inline__ void handle_rx_fifo(const qm_usb_t usb)
|
||||
{
|
||||
const uint32_t grxstsp = QM_USB[usb].grxstsp;
|
||||
|
||||
const uint8_t ep_idx =
|
||||
(grxstsp & QM_USB_GRXSTSR_EP_NUM_MASK) + QM_USB_IN_EP_NUM;
|
||||
const uint32_t status = (grxstsp & QM_USB_GRXSTSR_PKT_STS_MASK) >>
|
||||
QM_USB_GRXSTSR_PKT_STS_OFFSET;
|
||||
const uint32_t xfer_size = (grxstsp & QM_USB_GRXSTSR_PKT_CNT_MASK) >>
|
||||
QM_USB_GRXSTSR_PKT_CNT_OFFSET;
|
||||
const qm_usb_ep_config_t *const ep_cfg =
|
||||
usb_ctrl[usb].ep_ctrl[ep_idx].ep_config;
|
||||
|
||||
void (*ep_cb)(void *data, int error, qm_usb_ep_idx_t ep,
|
||||
qm_usb_ep_status_t cb_status) = ep_cfg->callback;
|
||||
|
||||
usb_ctrl[usb].ep_ctrl[ep_idx].data_len = xfer_size;
|
||||
|
||||
if (ep_cb) {
|
||||
const qm_usb_status_t usb_status =
|
||||
(status == QM_USB_GRXSTSR_PKT_STS_SETUP)
|
||||
? QM_USB_EP_SETUP
|
||||
: QM_USB_EP_DATA_OUT;
|
||||
|
||||
ep_cb(ep_cfg->callback_data, 0, ep_idx, usb_status);
|
||||
}
|
||||
}
|
||||
|
||||
static __inline__ void handle_in_ep_intr(const qm_usb_t usb)
|
||||
{
|
||||
uint32_t ep_intr_sts;
|
||||
uint8_t ep_idx;
|
||||
void (*ep_cb)(void *data, int error, qm_usb_ep_idx_t ep,
|
||||
qm_usb_ep_status_t cb_status);
|
||||
|
||||
for (ep_idx = 0; ep_idx < QM_USB_IN_EP_NUM; ep_idx++) {
|
||||
if (QM_USB[usb].daint & QM_USB_DAINT_IN_EP_INT(ep_idx)) {
|
||||
/* Read IN EP interrupt status. */
|
||||
ep_intr_sts = QM_USB[usb].in_ep_reg[ep_idx].diepint &
|
||||
QM_USB[usb].diepmsk;
|
||||
|
||||
/* Clear IN EP interrupts. */
|
||||
QM_USB[usb].in_ep_reg[ep_idx].diepint = ep_intr_sts;
|
||||
|
||||
ep_cb =
|
||||
usb_ctrl[usb].ep_ctrl[ep_idx].ep_config->callback;
|
||||
|
||||
if (ep_intr_sts & QM_USB_DIEPINT_XFER_COMPL && ep_cb) {
|
||||
ep_cb(usb_ctrl[usb]
|
||||
.ep_ctrl[ep_idx]
|
||||
.ep_config->callback_data,
|
||||
0, ep_idx, QM_USB_EP_DATA_IN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear interrupt. */
|
||||
QM_USB[usb].gintsts = QM_USB_GINTSTS_IEP_INT;
|
||||
}
|
||||
|
||||
static __inline__ void handle_out_ep_intr(const qm_usb_t usb)
|
||||
{
|
||||
uint32_t ep_intr_sts;
|
||||
uint8_t ep_idx;
|
||||
|
||||
/* No OUT interrupt expected in FIFO mode, just clear
|
||||
* interrupts. */
|
||||
for (ep_idx = 0; ep_idx < QM_USB_OUT_EP_NUM; ep_idx++) {
|
||||
if (QM_USB[usb].daint & QM_USB_DAINT_OUT_EP_INT(ep_idx)) {
|
||||
/* Read OUT EP interrupt status. */
|
||||
ep_intr_sts = QM_USB[usb].out_ep_reg[ep_idx].doepint &
|
||||
QM_USB[usb].doepmsk;
|
||||
|
||||
/* Clear OUT EP interrupts. */
|
||||
QM_USB[usb].out_ep_reg[ep_idx].doepint = ep_intr_sts;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear interrupt. */
|
||||
QM_USB[usb].gintsts = QM_USB_GINTSTS_OEP_INT;
|
||||
}
|
||||
|
||||
/* USB ISR handler */
|
||||
static void usb_dc_isr_handler(const qm_usb_t usb)
|
||||
{
|
||||
uint32_t int_status;
|
||||
|
||||
/* Read interrupt status */
|
||||
while ((int_status = (QM_USB[usb].gintsts & QM_USB[usb].gintmsk))) {
|
||||
|
||||
if (int_status & QM_USB_GINTSTS_USB_RST) {
|
||||
/* Clear interrupt. */
|
||||
QM_USB[usb].gintsts = QM_USB_GINTSTS_USB_RST;
|
||||
|
||||
/* Reset detected */
|
||||
usb_dc_handle_reset(usb);
|
||||
}
|
||||
|
||||
if (int_status & QM_USB_GINTSTS_ENUM_DONE) {
|
||||
/* Clear interrupt. */
|
||||
QM_USB[usb].gintsts = QM_USB_GINTSTS_ENUM_DONE;
|
||||
|
||||
/* Enumeration done detected */
|
||||
usb_dc_handle_enum_done(usb);
|
||||
}
|
||||
|
||||
if (int_status & QM_USB_GINTSTS_USB_SUSP) {
|
||||
/* Clear interrupt. */
|
||||
QM_USB[usb].gintsts = QM_USB_GINTSTS_USB_SUSP;
|
||||
|
||||
if (usb_ctrl[usb].status_callback) {
|
||||
usb_ctrl[usb].status_callback(
|
||||
usb_ctrl[usb].user_data, 0, QM_USB_SUSPEND);
|
||||
}
|
||||
}
|
||||
|
||||
if (int_status & QM_USB_GINTSTS_WK_UP_INT) {
|
||||
/* Clear interrupt. */
|
||||
QM_USB[usb].gintsts = QM_USB_GINTSTS_WK_UP_INT;
|
||||
|
||||
if (usb_ctrl[usb].status_callback) {
|
||||
usb_ctrl[usb].status_callback(
|
||||
usb_ctrl[usb].user_data, 0, QM_USB_RESUME);
|
||||
}
|
||||
}
|
||||
|
||||
if (int_status & QM_USB_GINTSTS_RX_FLVL) {
|
||||
/* Packet in RX FIFO. */
|
||||
handle_rx_fifo(usb);
|
||||
}
|
||||
|
||||
if (int_status & QM_USB_GINTSTS_IEP_INT) {
|
||||
/* IN EP interrupt. */
|
||||
handle_in_ep_intr(usb);
|
||||
}
|
||||
|
||||
if (int_status & QM_USB_GINTSTS_OEP_INT) {
|
||||
/* OUT EP interrupt. */
|
||||
handle_out_ep_intr(usb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QM_ISR_DECLARE(qm_usb_0_isr_0)
|
||||
{
|
||||
usb_dc_isr_handler(QM_USB_0);
|
||||
QM_ISR_EOI(QM_IRQ_USB_0_VECTOR);
|
||||
}
|
||||
|
||||
int qm_usb_attach(const qm_usb_t usb)
|
||||
{
|
||||
QM_CHECK(usb < QM_USB_NUM, -EINVAL);
|
||||
|
||||
uint8_t ep;
|
||||
|
||||
if (usb_ctrl[usb].attached) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
clk_sys_usb_enable();
|
||||
|
||||
const int ret = usb_dc_reset(usb);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Set device speed to FS */
|
||||
QM_USB[usb].dcfg |= QM_USB_DCFG_DEV_SPD_FS;
|
||||
|
||||
/* No FIFO setup needed, the default values are used. */
|
||||
/* Set NAK for all OUT EPs. */
|
||||
for (ep = 0; ep < QM_USB_OUT_EP_NUM; ep++) {
|
||||
QM_USB[usb].out_ep_reg[ep].doepctl = QM_USB_DEPCTL_SNAK;
|
||||
}
|
||||
|
||||
/* Enable global interrupts. */
|
||||
QM_USB[usb].gintmsk =
|
||||
QM_USB_GINTSTS_OEP_INT | QM_USB_GINTSTS_IEP_INT |
|
||||
QM_USB_GINTSTS_ENUM_DONE | QM_USB_GINTSTS_USB_RST |
|
||||
QM_USB_GINTSTS_WK_UP_INT | QM_USB_GINTSTS_USB_SUSP;
|
||||
|
||||
/* Enable global interrupt. */
|
||||
QM_USB[usb].gahbcfg |= QM_USB_GAHBCFG_GLB_INTR_MASK;
|
||||
|
||||
/* Disable soft disconnect. */
|
||||
QM_USB[usb].dctl &= ~QM_USB_DCTL_SFT_DISCON;
|
||||
|
||||
usb_ctrl[usb].attached = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qm_usb_detach(const qm_usb_t usb)
|
||||
{
|
||||
QM_CHECK(usb < QM_USB_NUM, -EINVAL);
|
||||
|
||||
if (!usb_ctrl[usb].attached) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
clk_sys_usb_disable();
|
||||
|
||||
/* Enable soft disconnect. */
|
||||
QM_USB[usb].dctl |= QM_USB_DCTL_SFT_DISCON;
|
||||
|
||||
usb_ctrl[usb].attached = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qm_usb_reset(const qm_usb_t usb)
|
||||
{
|
||||
QM_CHECK(usb < QM_USB_NUM, -EINVAL);
|
||||
return usb_dc_reset(usb);
|
||||
}
|
||||
|
||||
int qm_usb_set_address(const qm_usb_t usb, const uint8_t addr)
|
||||
{
|
||||
QM_CHECK(usb < QM_USB_NUM, -EINVAL);
|
||||
QM_CHECK(addr <
|
||||
(QM_USB_DCFG_DEV_ADDR_MASK >> QM_USB_DCFG_DEV_ADDR_OFFSET),
|
||||
-EINVAL);
|
||||
|
||||
QM_USB[usb].dcfg &= ~QM_USB_DCFG_DEV_ADDR_MASK;
|
||||
QM_USB[usb].dcfg |= addr << QM_USB_DCFG_DEV_ADDR_OFFSET;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qm_usb_ep_set_config(const qm_usb_t usb,
|
||||
const qm_usb_ep_config_t *const ep_cfg)
|
||||
{
|
||||
QM_CHECK(usb < QM_USB_NUM, -EINVAL);
|
||||
QM_CHECK(usb_ctrl[usb].attached, -EINVAL);
|
||||
QM_CHECK(ep_cfg, -EINVAL);
|
||||
QM_CHECK(usb_dc_ep_is_valid(ep_cfg->ep), -EINVAL);
|
||||
|
||||
volatile uint32_t *p_depctl;
|
||||
const uint8_t ep_idx = ep_cfg->ep < QM_USB_IN_EP_NUM
|
||||
? ep_cfg->ep
|
||||
: ep_cfg->ep - QM_USB_IN_EP_NUM;
|
||||
|
||||
if (!IS_IN_EP(ep_cfg->ep)) {
|
||||
p_depctl = &QM_USB[usb].out_ep_reg[ep_idx].doepctl;
|
||||
} else {
|
||||
p_depctl = &QM_USB[usb].in_ep_reg[ep_idx].diepctl;
|
||||
}
|
||||
|
||||
usb_ctrl[usb].ep_ctrl[ep_cfg->ep].ep_config = ep_cfg;
|
||||
|
||||
if (!ep_idx) {
|
||||
/* Set max packet size for EP0 */
|
||||
*p_depctl &= ~QM_USB_DEPCTL0_MSP_MASK;
|
||||
switch (ep_cfg->max_packet_size) {
|
||||
case 8:
|
||||
*p_depctl |= QM_USB_DEPCTL0_MSP_8
|
||||
<< QM_USB_DEPCTL_MSP_OFFSET;
|
||||
break;
|
||||
case 16:
|
||||
*p_depctl |= QM_USB_DEPCTL0_MSP_16
|
||||
<< QM_USB_DEPCTL_MSP_OFFSET;
|
||||
break;
|
||||
case 32:
|
||||
*p_depctl |= QM_USB_DEPCTL0_MSP_32
|
||||
<< QM_USB_DEPCTL_MSP_OFFSET;
|
||||
break;
|
||||
case 64:
|
||||
*p_depctl |= QM_USB_DEPCTL0_MSP_64
|
||||
<< QM_USB_DEPCTL_MSP_OFFSET;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
/* No need to set EP0 type */
|
||||
} else {
|
||||
/* Set max packet size for EP */
|
||||
if (ep_cfg->max_packet_size >
|
||||
(QM_USB_DEPCTLn_MSP_MASK >> QM_USB_DEPCTL_MSP_OFFSET))
|
||||
return -EINVAL;
|
||||
|
||||
*p_depctl &= ~QM_USB_DEPCTLn_MSP_MASK;
|
||||
*p_depctl |= ep_cfg->max_packet_size
|
||||
<< QM_USB_DEPCTL_MSP_OFFSET;
|
||||
|
||||
/* Set endpoint type */
|
||||
*p_depctl &= ~QM_USB_DEPCTL_EP_TYPE_MASK;
|
||||
switch (ep_cfg->type) {
|
||||
case QM_USB_EP_CONTROL:
|
||||
*p_depctl |= QM_USB_DEPCTL_EP_TYPE_CONTROL
|
||||
<< QM_USB_DEPCTL_EP_TYPE_OFFSET;
|
||||
break;
|
||||
case QM_USB_EP_BULK:
|
||||
*p_depctl |= QM_USB_DEPCTL_EP_TYPE_BULK
|
||||
<< QM_USB_DEPCTL_EP_TYPE_OFFSET;
|
||||
break;
|
||||
case QM_USB_EP_INTERRUPT:
|
||||
*p_depctl |= QM_USB_DEPCTL_EP_TYPE_INTERRUPT
|
||||
<< QM_USB_DEPCTL_EP_TYPE_OFFSET;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* sets the Endpoint Data PID to DATA0 */
|
||||
*p_depctl |= QM_USB_DEPCTL_SETDOPID;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qm_usb_ep_set_stall_state(const qm_usb_t usb, const qm_usb_ep_idx_t ep,
|
||||
const bool is_stalled)
|
||||
{
|
||||
QM_CHECK(usb < QM_USB_NUM, -EINVAL);
|
||||
QM_CHECK(usb_ctrl[usb].attached, -EINVAL);
|
||||
QM_CHECK(usb_dc_ep_is_valid(ep), -EINVAL);
|
||||
|
||||
const uint8_t ep_idx = IS_IN_EP(ep) ? ep : ep - QM_USB_IN_EP_NUM;
|
||||
|
||||
if (!is_stalled && !ep_idx) {
|
||||
/* Not possible to clear stall for EP0 */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (IS_IN_EP(ep)) {
|
||||
uint32_t reg = QM_USB[usb].in_ep_reg[ep_idx].diepctl;
|
||||
reg ^= (-is_stalled ^ reg) & QM_USB_DEPCTL_STALL;
|
||||
QM_USB[usb].in_ep_reg[ep_idx].diepctl = reg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t reg = QM_USB[usb].out_ep_reg[ep_idx].doepctl;
|
||||
reg ^= (-is_stalled ^ reg) & QM_USB_DEPCTL_STALL;
|
||||
QM_USB[usb].out_ep_reg[ep_idx].doepctl = reg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qm_usb_ep_halt(const qm_usb_t usb, const qm_usb_ep_idx_t ep)
|
||||
{
|
||||
QM_CHECK(usb < QM_USB_NUM, -EINVAL);
|
||||
QM_CHECK(usb_ctrl[usb].attached, -EINVAL);
|
||||
QM_CHECK(usb_dc_ep_is_valid(ep), -EINVAL);
|
||||
|
||||
const uint8_t ep_idx = IS_IN_EP(ep) ? ep : ep - QM_USB_IN_EP_NUM;
|
||||
volatile uint32_t *p_depctl;
|
||||
|
||||
/* Cannot disable EP0, just set stall */
|
||||
if (!ep_idx) {
|
||||
return qm_usb_ep_set_stall_state(usb, ep, true);
|
||||
}
|
||||
|
||||
if (!IS_IN_EP(ep)) {
|
||||
p_depctl = &QM_USB[usb].out_ep_reg[ep_idx].doepctl;
|
||||
} else {
|
||||
p_depctl = &QM_USB[usb].in_ep_reg[ep_idx].diepctl;
|
||||
}
|
||||
|
||||
/* Set STALL and disable endpoint if enabled */
|
||||
*p_depctl |= QM_USB_DEPCTL_STALL;
|
||||
if (*p_depctl & QM_USB_DEPCTL_EP_ENA) {
|
||||
*p_depctl |= QM_USB_DEPCTL_EP_DIS;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qm_usb_ep_is_stalled(const qm_usb_t usb, const qm_usb_ep_idx_t ep,
|
||||
bool *stalled)
|
||||
{
|
||||
QM_CHECK(usb < QM_USB_NUM, -EINVAL);
|
||||
QM_CHECK(usb_ctrl[usb].attached, -EINVAL);
|
||||
QM_CHECK(usb_dc_ep_is_valid(ep), -EINVAL);
|
||||
QM_CHECK(stalled, -EINVAL);
|
||||
|
||||
volatile uint32_t *p_depctl;
|
||||
|
||||
if (IS_IN_EP(ep)) {
|
||||
p_depctl = &QM_USB[usb].in_ep_reg[ep].diepctl;
|
||||
} else {
|
||||
const uint8_t ep_idx = ep - QM_USB_IN_EP_NUM;
|
||||
p_depctl = &QM_USB[usb].out_ep_reg[ep_idx].doepctl;
|
||||
}
|
||||
|
||||
*stalled = !!(*p_depctl & QM_USB_DEPCTL_STALL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qm_usb_ep_enable(const qm_usb_t usb, const qm_usb_ep_idx_t ep)
|
||||
{
|
||||
QM_CHECK(usb < QM_USB_NUM, -EINVAL);
|
||||
QM_CHECK(usb_ctrl[usb].attached, -EINVAL);
|
||||
QM_CHECK(usb_dc_ep_is_valid(ep), -EINVAL);
|
||||
|
||||
usb_ctrl[usb].ep_ctrl[ep].enabled = true;
|
||||
|
||||
if (IS_IN_EP(ep)) {
|
||||
/* Enable EP interrupts. */
|
||||
QM_USB[usb].daintmsk |= QM_USB_DAINT_IN_EP_INT(ep);
|
||||
|
||||
/* Activate EP. */
|
||||
QM_USB[usb].in_ep_reg[ep].diepctl |= QM_USB_DEPCTL_USB_ACT_EP;
|
||||
} else {
|
||||
const uint8_t ep_idx = ep - QM_USB_IN_EP_NUM;
|
||||
|
||||
/* Enable EP interrupts. */
|
||||
QM_USB[usb].daintmsk |= QM_USB_DAINT_OUT_EP_INT(ep_idx);
|
||||
|
||||
/* Activate EP. */
|
||||
QM_USB[usb].out_ep_reg[ep_idx].doepctl |=
|
||||
QM_USB_DEPCTL_USB_ACT_EP;
|
||||
|
||||
/* Prepare EP for rx. */
|
||||
usb_dc_prep_rx(usb, ep, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qm_usb_ep_disable(const qm_usb_t usb, const qm_usb_ep_idx_t ep)
|
||||
{
|
||||
QM_CHECK(usb < QM_USB_NUM, -EINVAL);
|
||||
QM_CHECK(usb_dc_ep_is_valid(ep), -EINVAL);
|
||||
|
||||
/* Disable EP intr then de-activate, disable and set NAK. */
|
||||
if (!IS_IN_EP(ep)) {
|
||||
const uint8_t ep_idx = ep - QM_USB_IN_EP_NUM;
|
||||
|
||||
QM_USB[usb].daintmsk &= ~QM_USB_DAINT_OUT_EP_INT(ep_idx);
|
||||
QM_USB[usb].doepmsk &= ~QM_USB_DOEPINT_SET_UP;
|
||||
QM_USB[usb].out_ep_reg[ep_idx].doepctl &=
|
||||
~(QM_USB_DEPCTL_USB_ACT_EP | QM_USB_DEPCTL_EP_ENA |
|
||||
QM_USB_DEPCTL_SNAK);
|
||||
} else {
|
||||
QM_USB[usb].daintmsk &= ~QM_USB_DAINT_IN_EP_INT(ep);
|
||||
QM_USB[usb].diepmsk &= ~QM_USB_DIEPINT_XFER_COMPL;
|
||||
QM_USB[usb].gintmsk &= ~QM_USB_GINTSTS_RX_FLVL;
|
||||
QM_USB[usb].in_ep_reg[ep].diepctl &=
|
||||
~(QM_USB_DEPCTL_USB_ACT_EP | QM_USB_DEPCTL_EP_ENA |
|
||||
QM_USB_DEPCTL_SNAK);
|
||||
}
|
||||
|
||||
usb_ctrl[usb].ep_ctrl[ep].enabled = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qm_usb_ep_flush(const qm_usb_t usb, const qm_usb_ep_idx_t ep)
|
||||
{
|
||||
QM_CHECK(usb < QM_USB_NUM, -EINVAL);
|
||||
QM_CHECK(usb_ctrl[usb].attached, -EINVAL);
|
||||
QM_CHECK(usb_dc_ep_is_valid(ep), -EINVAL);
|
||||
/*
|
||||
* RX FIFO is global and cannot be flushed per EP, but it can
|
||||
* be through bit 4 from GRSTCTL. For now we don't flush it
|
||||
* here since both FIFOs are always flushed during the Core
|
||||
* Soft Reset done at usb_dc_reset(), which is called on both
|
||||
* qm_usb_attach() and qm_usb_reset().
|
||||
*/
|
||||
QM_CHECK(IS_IN_EP(ep), -EINVAL);
|
||||
|
||||
/* Each IN endpoint has dedicated Tx FIFO. */
|
||||
QM_USB[usb].grstctl |= ep << QM_USB_GRSTCTL_TX_FNUM_OFFSET;
|
||||
QM_USB[usb].grstctl |= QM_USB_GRSTCTL_TX_FFLSH;
|
||||
|
||||
uint32_t cnt = 0;
|
||||
do {
|
||||
if (++cnt > QM_USB_CORE_RST_TIMEOUT_US) {
|
||||
return -EIO;
|
||||
}
|
||||
clk_sys_udelay(1);
|
||||
} while (QM_USB[usb].grstctl & QM_USB_GRSTCTL_TX_FFLSH);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qm_usb_ep_write(const qm_usb_t usb, const qm_usb_ep_idx_t ep,
|
||||
const uint8_t *const data, const uint32_t data_len,
|
||||
uint32_t *const ret_bytes)
|
||||
{
|
||||
QM_CHECK(usb < QM_USB_NUM, -EINVAL);
|
||||
QM_CHECK(usb_ctrl[usb].attached, -EINVAL);
|
||||
QM_CHECK(usb_dc_ep_is_valid(ep), -EINVAL);
|
||||
QM_CHECK(IS_IN_EP(ep), -EINVAL);
|
||||
|
||||
/* Check if IN EP is enabled */
|
||||
if (!usb_ctrl[usb].ep_ctrl[ep].enabled) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
const int ret = usb_dc_tx(usb, ep, data, data_len);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret_bytes) {
|
||||
*ret_bytes = ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qm_usb_ep_read(const qm_usb_t usb, const qm_usb_ep_idx_t ep,
|
||||
uint8_t *const data, const uint32_t max_data_len,
|
||||
uint32_t *const read_bytes)
|
||||
{
|
||||
QM_CHECK(usb < QM_USB_NUM, -EINVAL);
|
||||
QM_CHECK(usb_ctrl[usb].attached, -EINVAL);
|
||||
QM_CHECK(usb_dc_ep_is_valid(ep), -EINVAL);
|
||||
QM_CHECK(!IS_IN_EP(ep), -EINVAL);
|
||||
QM_CHECK(data, -EINVAL);
|
||||
|
||||
uint32_t i, j, data_len, bytes_to_copy;
|
||||
|
||||
/* Check if OUT EP enabled */
|
||||
if (!usb_ctrl[usb].ep_ctrl[ep].enabled) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
data_len = usb_ctrl[usb].ep_ctrl[ep].data_len;
|
||||
|
||||
if (data_len > max_data_len) {
|
||||
bytes_to_copy = max_data_len;
|
||||
} else {
|
||||
bytes_to_copy = data_len;
|
||||
}
|
||||
|
||||
const uint8_t ep_idx = ep - QM_USB_IN_EP_NUM;
|
||||
/* Data in the FIFOs is always stored per 32-bit words. */
|
||||
for (i = 0; i < (bytes_to_copy & ~0x3); i += 4) {
|
||||
*(uint32_t *)(data + i) = QM_USB_EP_FIFO(ep_idx);
|
||||
}
|
||||
if (bytes_to_copy & 0x3) {
|
||||
/* Not multiple of 4. */
|
||||
uint32_t last_dw = QM_USB_EP_FIFO(ep_idx);
|
||||
|
||||
for (j = 0; j < (bytes_to_copy & 0x3); j++) {
|
||||
*(data + i + j) = (last_dw >> (8 * j)) & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
usb_ctrl[usb].ep_ctrl[ep].data_len -= bytes_to_copy;
|
||||
|
||||
if (read_bytes) {
|
||||
*read_bytes = bytes_to_copy;
|
||||
}
|
||||
|
||||
/* Prepare ep for rx if all the data frames were read. */
|
||||
if (!usb_ctrl[usb].ep_ctrl[ep].data_len) {
|
||||
usb_dc_prep_rx(usb, ep, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qm_usb_set_status_callback(const qm_usb_t usb,
|
||||
const qm_usb_status_callback_t cb)
|
||||
{
|
||||
QM_CHECK(usb < QM_USB_NUM, -EINVAL);
|
||||
|
||||
usb_ctrl[usb].status_callback = cb;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qm_usb_ep_get_bytes_read(const qm_usb_t usb, const qm_usb_ep_idx_t ep,
|
||||
uint32_t *const read_bytes)
|
||||
{
|
||||
QM_CHECK(usb < QM_USB_NUM, -EINVAL);
|
||||
QM_CHECK(usb_ctrl[usb].attached, -EINVAL);
|
||||
QM_CHECK(usb_dc_ep_is_valid(ep), -EINVAL);
|
||||
QM_CHECK(!IS_IN_EP(ep), -EINVAL);
|
||||
QM_CHECK(read_bytes, -EINVAL);
|
||||
|
||||
/* Check if OUT EP enabled. */
|
||||
if (!usb_ctrl[usb].ep_ctrl[ep].enabled) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*read_bytes = usb_ctrl[usb].ep_ctrl[ep].data_len;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -28,6 +28,7 @@
|
|||
*/
|
||||
|
||||
#include "qm_wdt.h"
|
||||
#include "clk.h"
|
||||
#include "soc_watch.h"
|
||||
|
||||
#define QM_WDT_RELOAD_VALUE (0x76)
|
||||
|
@ -47,20 +48,9 @@ int qm_wdt_start(const qm_wdt_t wdt)
|
|||
{
|
||||
QM_CHECK(wdt < QM_WDT_NUM, -EINVAL);
|
||||
|
||||
QM_WDT[wdt].wdt_cr |= QM_WDT_ENABLE;
|
||||
QM_WDT[wdt].wdt_cr |= QM_WDT_CR_WDT_ENABLE;
|
||||
|
||||
#if (QUARK_SE)
|
||||
/* Enable the peripheral clock. */
|
||||
QM_SCSS_CCU->ccu_periph_clk_gate_ctl |= BIT(1);
|
||||
|
||||
#elif(QUARK_D2000)
|
||||
QM_SCSS_CCU->ccu_periph_clk_gate_ctl |= BIT(10);
|
||||
|
||||
#else
|
||||
#error("Unsupported / unspecified processor detected.");
|
||||
#endif
|
||||
SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER,
|
||||
SOCW_REG_CCU_PERIPH_CLK_GATE_CTL);
|
||||
clk_periph_enable(CLK_PERIPH_WDT_REGISTER | CLK_PERIPH_CLK);
|
||||
|
||||
QM_SCSS_PERIPHERAL->periph_cfg0 |= BIT(1);
|
||||
|
||||
|
@ -71,15 +61,23 @@ int qm_wdt_set_config(const qm_wdt_t wdt, const qm_wdt_config_t *const cfg)
|
|||
{
|
||||
QM_CHECK(wdt < QM_WDT_NUM, -EINVAL);
|
||||
QM_CHECK(cfg != NULL, -EINVAL);
|
||||
QM_CHECK(cfg->timeout <= QM_WDT_TORR_TOP_MASK, -EINVAL);
|
||||
|
||||
if (cfg->mode == QM_WDT_MODE_INTERRUPT_RESET) {
|
||||
callback[wdt] = cfg->callback;
|
||||
callback_data[wdt] = cfg->callback_data;
|
||||
}
|
||||
|
||||
QM_WDT[wdt].wdt_cr &= ~QM_WDT_MODE;
|
||||
QM_WDT[wdt].wdt_cr |= cfg->mode << QM_WDT_MODE_OFFSET;
|
||||
QM_WDT[wdt].wdt_cr &= ~QM_WDT_CR_RMOD;
|
||||
QM_WDT[wdt].wdt_cr |= cfg->mode << QM_WDT_CR_RMOD_OFFSET;
|
||||
|
||||
/*
|
||||
* Timeout range register. Select the timeout from the pre-defined
|
||||
* tables. These tables can be found in the SoC databook or register
|
||||
* file.
|
||||
*/
|
||||
QM_WDT[wdt].wdt_torr = cfg->timeout;
|
||||
|
||||
/* kick the WDT to load the Timeout Period(TOP) value */
|
||||
qm_wdt_reload(wdt);
|
||||
|
|
@ -55,9 +55,6 @@ struct interrupt_frame;
|
|||
|
||||
#define REG_VAL(addr) (*((volatile uint32_t *)addr))
|
||||
|
||||
/* QM_ASSERT is not currently available for Zephyr. */
|
||||
#define ASSERT_EXCLUDE (ZEPHYR_OS)
|
||||
|
||||
/**
|
||||
* In our reference implementation, by default DEBUG enables QM_PUTS and
|
||||
* QM_ASSERT but not QM_PRINTF.
|
||||
|
@ -65,10 +62,8 @@ struct interrupt_frame;
|
|||
*/
|
||||
|
||||
#if (DEBUG)
|
||||
#if !ASSERT_EXCLUDE
|
||||
#ifndef ASSERT_ENABLE
|
||||
#define ASSERT_ENABLE (1)
|
||||
#endif
|
||||
#endif /* ASSERT_EXCLUDE */
|
||||
#ifndef PUTS_ENABLE
|
||||
#define PUTS_ENABLE (1)
|
||||
|
@ -96,6 +91,10 @@ struct interrupt_frame;
|
|||
#define QM_CHECK_ASSERT_SAVE_ERROR (0)
|
||||
#endif
|
||||
|
||||
#ifdef ITA_NO_ASSERT
|
||||
#undef ASSERT_ENABLE
|
||||
#endif
|
||||
|
||||
#endif /* DEBUG */
|
||||
|
||||
/*
|
||||
|
@ -229,14 +228,14 @@ int pico_printf(const char *format, ...);
|
|||
void handler(__attribute__( \
|
||||
(unused)) struct interrupt_frame *__interrupt_frame__)
|
||||
#else /* !UNIT_TEST */
|
||||
#if (QM_SENSOR) && !(ISR_HANDLED)
|
||||
#if (QM_SENSOR) && !(ENABLE_EXTERNAL_ISR_HANDLING)
|
||||
/*
|
||||
* Sensor Subsystem 'interrupt' attribute.
|
||||
*/
|
||||
#define QM_ISR_DECLARE(handler) \
|
||||
__attribute__((interrupt("ilink"))) void handler(__attribute__( \
|
||||
(unused)) struct interrupt_frame *__interrupt_frame__)
|
||||
#elif(ISR_HANDLED)
|
||||
#elif(ENABLE_EXTERNAL_ISR_HANDLING)
|
||||
/*
|
||||
* Allow users to define their own ISR management. This includes optimisations
|
||||
* and clearing EOI registers.
|
||||
|
|
|
@ -30,21 +30,12 @@
|
|||
#include "clk.h"
|
||||
#include "flash_layout.h"
|
||||
#include "qm_flash.h"
|
||||
#if (!QM_SENSOR) || (UNIT_TEST)
|
||||
#include <x86intrin.h>
|
||||
#endif
|
||||
|
||||
#include "soc_watch.h"
|
||||
|
||||
#if (QM_SENSOR) && (!UNIT_TEST)
|
||||
/* Timestamp counter for Sensor Subsystem is 32bit. */
|
||||
#define get_ticks() __builtin_arc_lr(QM_SS_TSC_BASE + QM_SS_TIMER_COUNT)
|
||||
#elif(QM_SENSOR) && (UNIT_TEST)
|
||||
#define get_ticks() _rdtsc() % ((uint32_t)-1)
|
||||
#else
|
||||
/* 64bit Timestamp counter */
|
||||
#define get_ticks() _rdtsc()
|
||||
#endif
|
||||
|
||||
/* NOTE: Currently user space data / bss section overwrites the ROM data / bss
|
||||
* sections, so anything that is set in the ROM will be obliterated once we jump
|
||||
|
@ -283,7 +274,6 @@ int clk_trim_apply(const uint32_t value)
|
|||
|
||||
int clk_adc_set_div(const uint16_t div)
|
||||
{
|
||||
#if (QUARK_D2000)
|
||||
/*
|
||||
* The driver adds 1 to the value, so to avoid confusion for the user,
|
||||
* subtract 1 from the input value.
|
||||
|
@ -294,10 +284,6 @@ int clk_adc_set_div(const uint16_t div)
|
|||
reg &= CLK_ADC_DIV_DEF_MASK;
|
||||
reg |= ((div - 1) << QM_CCU_ADC_CLK_DIV_OFFSET);
|
||||
QM_SCSS_CCU->ccu_periph_clk_div_ctl0 = reg;
|
||||
#else
|
||||
/* TODO this function should only be made available on D2000 */
|
||||
(void)div;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -306,7 +292,6 @@ int clk_periph_set_div(const clk_periph_div_t div)
|
|||
{
|
||||
QM_CHECK(div <= CLK_PERIPH_DIV_8, -EINVAL);
|
||||
|
||||
#if (QUARK_D2000)
|
||||
uint32_t reg =
|
||||
QM_SCSS_CCU->ccu_periph_clk_div_ctl0 & CLK_PERIPH_DIV_DEF_MASK;
|
||||
reg |= (div << QM_CCU_PERIPH_PCLK_DIV_OFFSET);
|
||||
|
@ -314,13 +299,6 @@ int clk_periph_set_div(const clk_periph_div_t div)
|
|||
/* CLK Div en bit must be written from 0 -> 1 to apply new value */
|
||||
QM_SCSS_CCU->ccu_periph_clk_div_ctl0 |= QM_CCU_PERIPH_PCLK_DIV_EN;
|
||||
|
||||
#elif(QUARK_SE)
|
||||
QM_SCSS_CCU->ccu_periph_clk_div_ctl0 =
|
||||
(div << QM_CCU_PERIPH_PCLK_DIV_OFFSET);
|
||||
/* CLK Div en bit must be written from 0 -> 1 to apply new value */
|
||||
QM_SCSS_CCU->ccu_periph_clk_div_ctl0 |= QM_CCU_PERIPH_PCLK_DIV_EN;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -396,11 +374,7 @@ uint32_t clk_sys_get_ticks_per_us(void)
|
|||
void clk_sys_udelay(uint32_t microseconds)
|
||||
{
|
||||
uint32_t timeout = ticks_per_us * microseconds;
|
||||
#if (QM_SENSOR)
|
||||
uint32_t tsc_start;
|
||||
#else
|
||||
unsigned long long tsc_start;
|
||||
#endif
|
||||
tsc_start = get_ticks();
|
||||
/* We need to wait until timeout system clock ticks has occurred. */
|
||||
while (get_ticks() - tsc_start < timeout) {
|
|
@ -33,14 +33,21 @@
|
|||
#include "qm_isr.h"
|
||||
#include "qm_adc.h"
|
||||
#include "qm_flash.h"
|
||||
|
||||
#include "rar.h"
|
||||
#include "soc_watch.h"
|
||||
|
||||
void power_cpu_halt(void)
|
||||
{
|
||||
SOC_WATCH_LOG_EVENT(SOCW_EVENT_HALT, 0);
|
||||
__asm__ __volatile__("hlt");
|
||||
/*
|
||||
* STI sets the IF flag. After the IF flag is set,
|
||||
* the core begins responding to external,
|
||||
* maskable interrupts after the next instruction is executed.
|
||||
* When this function is called with interrupts disabled,
|
||||
* this guarantees that an interrupt is caught only
|
||||
* after the processor has transitioned into HLT.
|
||||
*/
|
||||
__asm__ __volatile__("sti\n\t"
|
||||
"hlt\n\t");
|
||||
}
|
||||
|
||||
static void clear_all_pending_interrupts(void)
|
||||
|
@ -67,6 +74,7 @@ void power_soc_sleep(void)
|
|||
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();
|
||||
|
@ -169,6 +177,7 @@ void power_soc_sleep(void)
|
|||
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;
|
||||
}
|
||||
|
||||
void power_soc_deep_sleep(const power_wake_event_t wake_event)
|
||||
|
@ -274,14 +283,14 @@ void power_soc_deep_sleep(const power_wake_event_t wake_event)
|
|||
(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__("nop");
|
||||
__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__("nop");
|
||||
__asm__ __volatile__("nop");
|
||||
|
||||
/* Set the RAR to retention mode. */
|
||||
rar_set_mode(RAR_RETENTION);
|
||||
|
@ -323,14 +332,14 @@ void power_soc_deep_sleep(const power_wake_event_t wake_event)
|
|||
(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__("nop");
|
||||
__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__("nop");
|
||||
__asm__ __volatile__("nop");
|
||||
|
||||
/* SCSS.AON_VR.ROK_BUF_VREG_MASK = 0; */
|
||||
QM_SCSS_PMU->aon_vr =
|
||||
|
@ -338,7 +347,11 @@ void power_soc_deep_sleep(const power_wake_event_t wake_event)
|
|||
(QM_SCSS_PMU->aon_vr & ~QM_AON_VR_ROK_BUF_VREG_MASK));
|
||||
|
||||
/* Wait >= 1 usec, at 256 kHz this is 1 cycle. */
|
||||
__asm__("nop");
|
||||
__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;
|
||||
|
@ -388,3 +401,31 @@ void power_soc_deep_sleep(const power_wake_event_t wake_event)
|
|||
QM_SCSS_CCU->wake_mask = SET_ALL_BITS;
|
||||
QM_SCSS_GP->gps1 &= ~QM_SCSS_GP_POWER_STATE_DEEP_SLEEP;
|
||||
}
|
||||
|
||||
int rar_set_mode(const rar_state_t mode)
|
||||
{
|
||||
QM_CHECK(mode <= RAR_RETENTION, -EINVAL);
|
||||
volatile uint32_t i = 32;
|
||||
volatile uint32_t reg;
|
||||
|
||||
switch (mode) {
|
||||
case RAR_RETENTION:
|
||||
QM_SCSS_PMU->aon_vr |=
|
||||
(QM_AON_VR_PASS_CODE | QM_AON_VR_ROK_BUF_VREG_MASK);
|
||||
QM_SCSS_PMU->aon_vr |=
|
||||
(QM_AON_VR_PASS_CODE | QM_AON_VR_VREG_SEL);
|
||||
break;
|
||||
|
||||
case RAR_NORMAL:
|
||||
reg = QM_SCSS_PMU->aon_vr & ~QM_AON_VR_VREG_SEL;
|
||||
QM_SCSS_PMU->aon_vr = QM_AON_VR_PASS_CODE | reg;
|
||||
/* Wait for >= 2usec, at most 64 clock cycles. */
|
||||
while (i--) {
|
||||
__asm__ __volatile__("nop");
|
||||
}
|
||||
reg = QM_SCSS_PMU->aon_vr & ~QM_AON_VR_ROK_BUF_VREG_MASK;
|
||||
QM_SCSS_PMU->aon_vr = QM_AON_VR_PASS_CODE | reg;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -32,9 +32,6 @@
|
|||
|
||||
#include "qm_common.h"
|
||||
#include "qm_soc_regs.h"
|
||||
#if (QM_SENSOR)
|
||||
#include "qm_sensor_regs.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Clock Management.
|
||||
|
@ -62,16 +59,14 @@
|
|||
* System clock divider type.
|
||||
*/
|
||||
typedef enum {
|
||||
CLK_SYS_DIV_1, /**< Clock Divider = 1. */
|
||||
CLK_SYS_DIV_2, /**< Clock Divider = 2. */
|
||||
CLK_SYS_DIV_4, /**< Clock Divider = 4. */
|
||||
CLK_SYS_DIV_8, /**< Clock Divider = 8. */
|
||||
#if (QUARK_D2000)
|
||||
CLK_SYS_DIV_1, /**< Clock Divider = 1. */
|
||||
CLK_SYS_DIV_2, /**< Clock Divider = 2. */
|
||||
CLK_SYS_DIV_4, /**< Clock Divider = 4. */
|
||||
CLK_SYS_DIV_8, /**< Clock Divider = 8. */
|
||||
CLK_SYS_DIV_16, /**< Clock Divider = 16. */
|
||||
CLK_SYS_DIV_32, /**< Clock Divider = 32. */
|
||||
CLK_SYS_DIV_64, /**< Clock Divider = 64. */
|
||||
CLK_SYS_DIV_128, /**< Clock Divider = 128. */
|
||||
#endif
|
||||
CLK_SYS_DIV_NUM
|
||||
} clk_sys_div_t;
|
||||
|
||||
|
@ -79,12 +74,12 @@ typedef enum {
|
|||
* System clock mode type.
|
||||
*/
|
||||
typedef enum {
|
||||
CLK_SYS_HYB_OSC_32MHZ, /**< 32MHz Hybrid Oscillator Clock. */
|
||||
CLK_SYS_HYB_OSC_16MHZ, /**< 16MHz Hybrid Oscillator Clock. */
|
||||
CLK_SYS_HYB_OSC_8MHZ, /**< 8MHz Hybrid Oscillator Clock. */
|
||||
CLK_SYS_HYB_OSC_4MHZ, /**< 4MHz Hybrid Oscillator Clock. */
|
||||
CLK_SYS_RTC_OSC, /**< Real Time Clock. */
|
||||
CLK_SYS_CRYSTAL_OSC /**< Crystal Oscillator Clock. */
|
||||
CLK_SYS_HYB_OSC_32MHZ = 0, /**< 32MHz Hybrid Oscillator Clock. */
|
||||
CLK_SYS_HYB_OSC_16MHZ = 1, /**< 16MHz Hybrid Oscillator Clock. */
|
||||
CLK_SYS_HYB_OSC_8MHZ = 2, /**< 8MHz Hybrid Oscillator Clock. */
|
||||
CLK_SYS_HYB_OSC_4MHZ = 3, /**< 4MHz Hybrid Oscillator Clock. */
|
||||
CLK_SYS_RTC_OSC = 4, /**< Real Time Clock. */
|
||||
CLK_SYS_CRYSTAL_OSC = 5 /**< Crystal Oscillator Clock. */
|
||||
} clk_sys_mode_t;
|
||||
|
||||
/**
|
||||
|
@ -190,7 +185,6 @@ int clk_trim_apply(const uint32_t value);
|
|||
*
|
||||
* Change ADC clock divider value. The new divider value is set to N, where N is
|
||||
* the value set by the function and is between 1 and 1024.
|
||||
* This function is only available on D2000.
|
||||
*
|
||||
* @param[in] div Divider value for the ADC clock.
|
||||
*
|
||||
|
@ -300,6 +294,7 @@ uint32_t clk_sys_get_ticks_per_us(void);
|
|||
* @param[in] microseconds Minimum number of micro seconds to delay for.
|
||||
*/
|
||||
void clk_sys_udelay(uint32_t microseconds);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
|
@ -52,6 +52,9 @@ typedef enum {
|
|||
* Put CPU in halt state.
|
||||
*
|
||||
* Halts the CPU until next interrupt or reset.
|
||||
*
|
||||
* This function can be called with interrupts disabled.
|
||||
* Interrupts will be enabled before triggering the transition.
|
||||
*/
|
||||
void power_cpu_halt(void);
|
||||
|
||||
|
@ -91,7 +94,37 @@ void power_soc_sleep();
|
|||
void power_soc_deep_sleep(const power_wake_event_t wake_event);
|
||||
|
||||
/**
|
||||
* @}
|
||||
* Retention alternator regulator for Quark D2000.
|
||||
*
|
||||
* @defgroup groupRAR Quark(TM) D2000 Retention Alternator Regulator (RAR).
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* RAR modes type.
|
||||
*/
|
||||
typedef enum {
|
||||
RAR_NORMAL, /**< Normal mode = 50 mA. */
|
||||
RAR_RETENTION /**< Retention mode = 300 uA. */
|
||||
} rar_state_t;
|
||||
|
||||
/**
|
||||
* Change operating mode of RAR.
|
||||
*
|
||||
* Normal mode is able to source up to 50 mA.
|
||||
* Retention mode is able to source up to 300 uA.
|
||||
* Care must be taken when entering into retention mode
|
||||
* to ensure the overall system draw is less than 300 uA.
|
||||
*
|
||||
* @param[in] mode Operating mode of the RAR.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int rar_set_mode(const rar_state_t mode);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
#endif /* __POWER_STATES_H__ */
|
||||
|
|
|
@ -40,7 +40,6 @@
|
|||
*/
|
||||
|
||||
#define QUARK_D2000 (1)
|
||||
#define HAS_RAR (1)
|
||||
#define HAS_MVIC (1)
|
||||
|
||||
/**
|
||||
|
@ -280,6 +279,7 @@ qm_scss_int_reg_t test_scss_int;
|
|||
#endif
|
||||
|
||||
#define QM_INT_TIMER_HOST_HALT_MASK BIT(0)
|
||||
#define QM_INT_DMA_ERR_HOST_MASK (0x00000003)
|
||||
#define QM_INT_SRAM_CONTROLLER_HOST_HALT_MASK BIT(16)
|
||||
#define QM_INT_SRAM_CONTROLLER_HOST_MASK BIT(0)
|
||||
#define QM_INT_FLASH_CONTROLLER_HOST_HALT_MASK BIT(16)
|
||||
|
@ -317,13 +317,11 @@ qm_scss_pmu_reg_t test_scss_pmu;
|
|||
|
||||
#define QM_P_STS_HALT_INTERRUPT_REDIRECTION BIT(26)
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Always-on controllers.
|
||||
* @{
|
||||
/*
|
||||
* Rename ROK_BUF_VREG register bit to ROK_BUF_VREG_STATUS to avoid confusion
|
||||
* and preprocessor issues with ROK_BUF_VREG_MASK register bit.
|
||||
*/
|
||||
|
||||
#define QM_AON_VR_ROK_BUF_VREG_STATUS BIT(15)
|
||||
#define QM_AON_VR_ROK_BUF_VREG_MASK BIT(9)
|
||||
#define QM_AON_VR_VREG_SEL BIT(8)
|
||||
#define QM_AON_VR_PASS_CODE (0x9DC4 << 16)
|
||||
|
@ -332,10 +330,17 @@ qm_scss_pmu_reg_t test_scss_pmu;
|
|||
#define QM_AON_VR_VSEL_1V8 (0x10)
|
||||
#define QM_AON_VR_VSTRB BIT(5)
|
||||
|
||||
/** Number of SCSS Always-on controllers. */
|
||||
typedef enum { QM_SCSS_AON_0 = 0, QM_SCSS_AON_NUM } qm_scss_aon_t;
|
||||
/** @} */
|
||||
|
||||
/** Always-on Controller register map. */
|
||||
/**
|
||||
* @name Always-on Counters.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Number of Always-on counter controllers. */
|
||||
typedef enum { QM_AONC_0 = 0, QM_AONC_NUM } qm_aonc_t;
|
||||
|
||||
/** Always-on Counter Controller register map. */
|
||||
typedef struct {
|
||||
QM_RW uint32_t aonc_cnt; /**< Always-on counter register. */
|
||||
QM_RW uint32_t aonc_cfg; /**< Always-on counter enable. */
|
||||
|
@ -345,15 +350,15 @@ typedef struct {
|
|||
QM_RW uint32_t aonpt_ctrl; /**< Always-on periodic timer control. */
|
||||
QM_RW uint32_t
|
||||
aonpt_cfg; /**< Always-on periodic timer configuration register. */
|
||||
} qm_scss_aon_reg_t;
|
||||
} qm_aonc_reg_t;
|
||||
|
||||
#if (UNIT_TEST)
|
||||
qm_scss_aon_reg_t test_scss_aon;
|
||||
#define QM_SCSS_AON ((qm_scss_aon_reg_t *)(&test_scss_aon))
|
||||
qm_aonc_reg_t test_aonc;
|
||||
#define QM_AONC ((qm_aonc_reg_t *)(&test_aonc))
|
||||
|
||||
#else
|
||||
#define QM_SCSS_AON_BASE (0xB0800700)
|
||||
#define QM_SCSS_AON ((qm_scss_aon_reg_t *)QM_SCSS_AON_BASE)
|
||||
#define QM_AONC_BASE (0xB0800700)
|
||||
#define QM_AONC ((qm_aonc_reg_t *)QM_AONC_BASE)
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
@ -552,11 +557,12 @@ typedef struct {
|
|||
typedef struct {
|
||||
qm_pwm_channel_t timer[QM_PWM_ID_NUM]; /**< 2 Timers. */
|
||||
QM_RW uint32_t reserved[30];
|
||||
QM_RW uint32_t timersintstatus; /**< Timers Interrupt Status */
|
||||
QM_RW uint32_t timerseoi; /**< Timers End Of Interrupt */
|
||||
QM_RW uint32_t timersrawintstatus; /**< Timers Raw Interrupt Status */
|
||||
QM_RW uint32_t timerscompversion; /**< Timers Component Version */
|
||||
QM_RW uint32_t timer_loadcount2[4]; /**< Timer Load Count 2 */
|
||||
QM_RW uint32_t timersintstatus; /**< Timers Interrupt Status */
|
||||
QM_RW uint32_t timerseoi; /**< Timers End Of Interrupt */
|
||||
QM_RW uint32_t timersrawintstatus; /**< Timers Raw Interrupt Status */
|
||||
QM_RW uint32_t timerscompversion; /**< Timers Component Version */
|
||||
QM_RW uint32_t
|
||||
timer_loadcount2[QM_PWM_ID_NUM]; /**< Timer Load Count 2 */
|
||||
} qm_pwm_reg_t;
|
||||
|
||||
#if (UNIT_TEST)
|
||||
|
@ -570,7 +576,38 @@ qm_pwm_reg_t test_pwm_t;
|
|||
#define QM_PWM ((qm_pwm_reg_t *)QM_PWM_BASE)
|
||||
#endif
|
||||
|
||||
#define QM_PWM_INTERRUPT_MASK_OFFSET (2)
|
||||
#define PWM_START (1)
|
||||
|
||||
#define QM_PWM_CONF_MODE_MASK (0xA)
|
||||
#define QM_PWM_CONF_INT_EN_MASK (0x4)
|
||||
|
||||
#define QM_PWM_INTERRUPT_MASK_OFFSET (0x2)
|
||||
|
||||
/**
|
||||
* Timer N Control (TimerNControlReg)
|
||||
*
|
||||
* 31:4 RO reserved
|
||||
* 3 RW Timer PWM
|
||||
* 1 - PWM Mode
|
||||
* 0 - Timer Mode
|
||||
* 2 RW Timer Interrupt Mask, set to 1b to mask interrupt.
|
||||
* 1 RW Timer Mode
|
||||
* 1 - user-defined count mode
|
||||
* 0 - free-running mode
|
||||
* 0 RW Timer Enable
|
||||
* 0 - Disable PWM/Timer
|
||||
* 1 - Enable PWM/Timer
|
||||
*/
|
||||
|
||||
#define QM_PWM_TIMERNCONTROLREG_TIMER_ENABLE (BIT(0))
|
||||
#define QM_PWM_TIMERNCONTROLREG_TIMER_MODE (BIT(1))
|
||||
#define QM_PWM_TIMERNCONTROLREG_TIMER_INTERRUPT_MASK (BIT(2))
|
||||
#define QM_PWM_TIMERNCONTROLREG_TIMER_PWM (BIT(3))
|
||||
|
||||
#define QM_PWM_MODE_TIMER_FREE_RUNNING_VALUE (0)
|
||||
#define QM_PWM_MODE_TIMER_COUNT_VALUE (QM_PWM_TIMERNCONTROLREG_TIMER_MODE)
|
||||
#define QM_PWM_MODE_PWM_VALUE \
|
||||
(QM_PWM_TIMERNCONTROLREG_TIMER_PWM | QM_PWM_TIMERNCONTROLREG_TIMER_MODE)
|
||||
|
||||
/** @} */
|
||||
|
||||
|
@ -612,6 +649,40 @@ qm_wdt_reg_t test_wdt;
|
|||
#define QM_WDT ((qm_wdt_reg_t *)QM_WDT_BASE)
|
||||
#endif
|
||||
|
||||
/* Watchdog enable. */
|
||||
#define QM_WDT_CR_WDT_ENABLE (BIT(0))
|
||||
/* Watchdog mode. */
|
||||
#define QM_WDT_CR_RMOD (BIT(1))
|
||||
/* Watchdog mode offset. */
|
||||
#define QM_WDT_CR_RMOD_OFFSET (1)
|
||||
/* Watchdog Timeout Mask. */
|
||||
#define QM_WDT_TORR_TOP_MASK (0xF)
|
||||
|
||||
/**
|
||||
* WDT timeout table (in clock cycles):
|
||||
* Each table entry corresponds with the value loaded
|
||||
* into the WDT at the time of a WDT reload for the
|
||||
* corresponding timeout range register value.
|
||||
*
|
||||
* TORR | Timeout (Clock Cycles)
|
||||
* 0. | 2^16 (65536)
|
||||
* 1. | 2^17 (131072)
|
||||
* 2. | 2^18 (262144)
|
||||
* 3. | 2^19 (524288)
|
||||
* 4. | 2^20 (1048576)
|
||||
* 5. | 2^21 (2097152)
|
||||
* 6. | 2^22 (4194304)
|
||||
* 7. | 2^23 (8388608)
|
||||
* 8. | 2^24 (16777216)
|
||||
* 9. | 2^25 (33554432)
|
||||
* 10. | 2^26 (67108864)
|
||||
* 11. | 2^27 (134217728)
|
||||
* 12. | 2^28 (268435456)
|
||||
* 13. | 2^29 (536870912)
|
||||
* 14. | 2^30 (1073741824)
|
||||
* 15. | 2^31 (2147483648)
|
||||
*/
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -619,6 +690,104 @@ qm_wdt_reg_t test_wdt;
|
|||
* @{
|
||||
*/
|
||||
|
||||
/* Break character Bit. */
|
||||
#define QM_UART_LCR_BREAK BIT(6)
|
||||
/* Divisor Latch Access Bit. */
|
||||
#define QM_UART_LCR_DLAB BIT(7)
|
||||
|
||||
/* Request to Send Bit. */
|
||||
#define QM_UART_MCR_RTS BIT(1)
|
||||
/* Loopback Enable Bit. */
|
||||
#define QM_UART_MCR_LOOPBACK BIT(4)
|
||||
/* Auto Flow Control Enable Bit. */
|
||||
#define QM_UART_MCR_AFCE BIT(5)
|
||||
|
||||
/* FIFO Enable Bit. */
|
||||
#define QM_UART_FCR_FIFOE BIT(0)
|
||||
/* Reset Receive FIFO. */
|
||||
#define QM_UART_FCR_RFIFOR BIT(1)
|
||||
/* Reset Transmit FIFO. */
|
||||
#define QM_UART_FCR_XFIFOR BIT(2)
|
||||
|
||||
/* Default FIFO RX & TX Thresholds, half full for both. */
|
||||
#define QM_UART_FCR_DEFAULT_TX_RX_THRESHOLD (0xB0)
|
||||
/* Change TX Threshold to empty, keep RX Threshold to default. */
|
||||
#define QM_UART_FCR_TX_0_RX_1_2_THRESHOLD (0x80)
|
||||
|
||||
/* Transmit Holding Register Empty. */
|
||||
#define QM_UART_IIR_THR_EMPTY (0x02)
|
||||
/* Received Data Available. */
|
||||
#define QM_UART_IIR_RECV_DATA_AVAIL (0x04)
|
||||
/* Receiver Line Status. */
|
||||
#define QM_UART_IIR_RECV_LINE_STATUS (0x06)
|
||||
/* Character Timeout. */
|
||||
#define QM_UART_IIR_CHAR_TIMEOUT (0x0C)
|
||||
/* Interrupt ID Mask. */
|
||||
#define QM_UART_IIR_IID_MASK (0x0F)
|
||||
|
||||
/* Data Ready Bit. */
|
||||
#define QM_UART_LSR_DR BIT(0)
|
||||
/* Overflow Error Bit. */
|
||||
#define QM_UART_LSR_OE BIT(1)
|
||||
/* Parity Error Bit. */
|
||||
#define QM_UART_LSR_PE BIT(2)
|
||||
/* Framing Error Bit. */
|
||||
#define QM_UART_LSR_FE BIT(3)
|
||||
/* Break Interrupt Bit. */
|
||||
#define QM_UART_LSR_BI BIT(4)
|
||||
/* Transmit Holding Register Empty Bit. */
|
||||
#define QM_UART_LSR_THRE BIT(5)
|
||||
/* Transmitter Empty Bit. */
|
||||
#define QM_UART_LSR_TEMT BIT(6)
|
||||
/* Receiver FIFO Error Bit. */
|
||||
#define QM_UART_LSR_RFE BIT(7)
|
||||
|
||||
/* Enable Received Data Available Interrupt. */
|
||||
#define QM_UART_IER_ERBFI BIT(0)
|
||||
/* Enable Transmit Holding Register Empty Interrupt. */
|
||||
#define QM_UART_IER_ETBEI BIT(1)
|
||||
/* Enable Receiver Line Status Interrupt. */
|
||||
#define QM_UART_IER_ELSI BIT(2)
|
||||
/* Programmable THRE Interrupt Mode. */
|
||||
#define QM_UART_IER_PTIME BIT(7)
|
||||
|
||||
/* Line Status Errors. */
|
||||
#define QM_UART_LSR_ERROR_BITS \
|
||||
(QM_UART_LSR_OE | QM_UART_LSR_PE | QM_UART_LSR_FE | QM_UART_LSR_BI)
|
||||
|
||||
/* FIFO Depth. */
|
||||
#define QM_UART_FIFO_DEPTH (16)
|
||||
/* FIFO Half Depth. */
|
||||
#define QM_UART_FIFO_HALF_DEPTH (QM_UART_FIFO_DEPTH / 2)
|
||||
|
||||
/* Divisor Latch High Offset. */
|
||||
#define QM_UART_CFG_BAUD_DLH_OFFS 16
|
||||
/* Divisor Latch Low Offset. */
|
||||
#define QM_UART_CFG_BAUD_DLL_OFFS 8
|
||||
/* Divisor Latch Fraction Offset. */
|
||||
#define QM_UART_CFG_BAUD_DLF_OFFS 0
|
||||
/* Divisor Latch High Mask. */
|
||||
#define QM_UART_CFG_BAUD_DLH_MASK (0xFF << QM_UART_CFG_BAUD_DLH_OFFS)
|
||||
/* Divisor Latch Low Mask. */
|
||||
#define QM_UART_CFG_BAUD_DLL_MASK (0xFF << QM_UART_CFG_BAUD_DLL_OFFS)
|
||||
/* Divisor Latch Fraction Mask. */
|
||||
#define QM_UART_CFG_BAUD_DLF_MASK (0xFF << QM_UART_CFG_BAUD_DLF_OFFS)
|
||||
|
||||
/* Divisor Latch Packing Helper. */
|
||||
#define QM_UART_CFG_BAUD_DL_PACK(dlh, dll, dlf) \
|
||||
(dlh << QM_UART_CFG_BAUD_DLH_OFFS | dll << QM_UART_CFG_BAUD_DLL_OFFS | \
|
||||
dlf << QM_UART_CFG_BAUD_DLF_OFFS)
|
||||
|
||||
/* Divisor Latch High Unpacking Helper. */
|
||||
#define QM_UART_CFG_BAUD_DLH_UNPACK(packed) \
|
||||
((packed & QM_UART_CFG_BAUD_DLH_MASK) >> QM_UART_CFG_BAUD_DLH_OFFS)
|
||||
/* Divisor Latch Low Unpacking Helper. */
|
||||
#define QM_UART_CFG_BAUD_DLL_UNPACK(packed) \
|
||||
((packed & QM_UART_CFG_BAUD_DLL_MASK) >> QM_UART_CFG_BAUD_DLL_OFFS)
|
||||
/* Divisor Latch Fraction Unpacking Helper. */
|
||||
#define QM_UART_CFG_BAUD_DLF_UNPACK(packed) \
|
||||
((packed & QM_UART_CFG_BAUD_DLF_MASK) >> QM_UART_CFG_BAUD_DLF_OFFS)
|
||||
|
||||
/** Number of UART controllers. */
|
||||
typedef enum { QM_UART_0 = 0, QM_UART_1, QM_UART_NUM } qm_uart_t;
|
||||
|
||||
|
@ -671,8 +840,8 @@ extern qm_uart_reg_t *qm_uart[QM_UART_NUM];
|
|||
* @{
|
||||
*/
|
||||
|
||||
/** Number of SPI controllers. */
|
||||
typedef enum { QM_SPI_MST_0 = 0, QM_SPI_SLV_0 = 1, QM_SPI_NUM } qm_spi_t;
|
||||
/** Number of SPI controllers (only master driver available). */
|
||||
typedef enum { QM_SPI_MST_0 = 0, QM_SPI_NUM } qm_spi_t;
|
||||
|
||||
/** SPI register map. */
|
||||
typedef struct {
|
||||
|
@ -792,6 +961,10 @@ typedef struct {
|
|||
QM_RW uint32_t rtc_comp_version; /**< End of Interrupt Register. */
|
||||
} qm_rtc_reg_t;
|
||||
|
||||
#define QM_RTC_CCR_INTERRUPT_ENABLE BIT(0)
|
||||
#define QM_RTC_CCR_INTERRUPT_MASK BIT(1)
|
||||
#define QM_RTC_CCR_ENABLE BIT(2)
|
||||
|
||||
#if (UNIT_TEST)
|
||||
qm_rtc_reg_t test_rtc;
|
||||
#define QM_RTC ((qm_rtc_reg_t *)(&test_rtc))
|
||||
|
@ -1131,6 +1304,46 @@ extern qm_flash_reg_t *qm_flash[QM_FLASH_NUM];
|
|||
#define QM_FLASH_CLK_SLOW BIT(14)
|
||||
#define QM_FLASH_LVE_MODE BIT(5)
|
||||
|
||||
/* Flash mask to clear timing. */
|
||||
#define QM_FLASH_TMG_DEF_MASK (0xFFFFFC00)
|
||||
/* Flash mask to clear micro seconds. */
|
||||
#define QM_FLASH_MICRO_SEC_COUNT_MASK (0x3F)
|
||||
/* Flash mask to clear wait state. */
|
||||
#define QM_FLASH_WAIT_STATE_MASK (0x3C0)
|
||||
/* Flash wait state offset bit. */
|
||||
#define QM_FLASH_WAIT_STATE_OFFSET (6)
|
||||
/* Flash write disable offset bit. */
|
||||
#define QM_FLASH_WRITE_DISABLE_OFFSET (4)
|
||||
/* Flash write disable value. */
|
||||
#define QM_FLASH_WRITE_DISABLE_VAL BIT(4)
|
||||
|
||||
/* Flash page erase request. */
|
||||
#define ER_REQ BIT(1)
|
||||
/* Flash page erase done. */
|
||||
#define ER_DONE (1)
|
||||
/* Flash page write request. */
|
||||
#define WR_REQ (1)
|
||||
/* Flash page write done. */
|
||||
#define WR_DONE BIT(1)
|
||||
|
||||
/* Flash write address offset. */
|
||||
#define WR_ADDR_OFFSET (2)
|
||||
/* Flash perform mass erase includes OTP region. */
|
||||
#define MASS_ERASE_INFO BIT(6)
|
||||
/* Flash perform mass erase. */
|
||||
#define MASS_ERASE BIT(7)
|
||||
|
||||
#define QM_FLASH_ADDRESS_MASK (0x7FF)
|
||||
/* Increment by 4 bytes each time, but there is an offset of 2, so 0x10. */
|
||||
#define QM_FLASH_ADDR_INC (0x10)
|
||||
|
||||
/* Flash page size in dwords. */
|
||||
#define QM_FLASH_PAGE_SIZE_DWORDS (0x200)
|
||||
/* Flash page size in bytes. */
|
||||
#define QM_FLASH_PAGE_SIZE_BYTES (0x800)
|
||||
/* Flash page size in bits. */
|
||||
#define QM_FLASH_PAGE_SIZE_BITS (11)
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -1286,7 +1499,7 @@ qm_mvic_reg_t test_mvic;
|
|||
#define QM_INT_CONTROLLER QM_MVIC
|
||||
/* Signal the interrupt controller that the interrupt was handled. The vector
|
||||
* argument is ignored. */
|
||||
#if defined(ISR_HANDLED)
|
||||
#if defined(ENABLE_EXTERNAL_ISR_HANDLING)
|
||||
#define QM_ISR_EOI(vector)
|
||||
#else
|
||||
#define QM_ISR_EOI(vector) (QM_INT_CONTROLLER->eoi.reg = 0)
|
||||
|
@ -1403,6 +1616,10 @@ typedef struct {
|
|||
#define QM_DMA_CFG_L_SRC_HS_POL_MASK BIT(QM_DMA_CFG_L_SRC_HS_POL_OFFSET)
|
||||
#define QM_DMA_CFG_L_RELOAD_SRC_MASK BIT(30)
|
||||
#define QM_DMA_CFG_L_RELOAD_DST_MASK BIT(31)
|
||||
#define QM_DMA_CFG_H_DS_UPD_EN_OFFSET (5)
|
||||
#define QM_DMA_CFG_H_DS_UPD_EN_MASK BIT(QM_DMA_CFG_H_DS_UPD_EN_OFFSET)
|
||||
#define QM_DMA_CFG_H_SS_UPD_EN_OFFSET (6)
|
||||
#define QM_DMA_CFG_H_SS_UPD_EN_MASK BIT(QM_DMA_CFG_H_SS_UPD_EN_OFFSET)
|
||||
#define QM_DMA_CFG_H_SRC_PER_OFFSET (7)
|
||||
#define QM_DMA_CFG_H_SRC_PER_MASK (0xf << QM_DMA_CFG_H_SRC_PER_OFFSET)
|
||||
#define QM_DMA_CFG_H_DEST_PER_OFFSET (11)
|
||||
|
@ -1456,6 +1673,7 @@ typedef struct {
|
|||
|
||||
/* DMA interrupt status register bits. */
|
||||
#define QM_DMA_INT_STATUS_TFR BIT(0)
|
||||
#define QM_DMA_INT_STATUS_BLOCK BIT(1)
|
||||
#define QM_DMA_INT_STATUS_ERR BIT(4)
|
||||
|
||||
/** DMA miscellaneous register map. */
|
||||
|
|
431
ext/hal/qmsi/soc/quark_se/drivers/clk.c
Normal file
431
ext/hal/qmsi/soc/quark_se/drivers/clk.c
Normal file
|
@ -0,0 +1,431 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Intel Corporation
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL CORPORATION OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "clk.h"
|
||||
#include "flash_layout.h"
|
||||
#include "qm_flash.h"
|
||||
#if (!QM_SENSOR) || (UNIT_TEST)
|
||||
#include <x86intrin.h>
|
||||
#endif
|
||||
|
||||
#include "soc_watch.h"
|
||||
|
||||
#if (QM_SENSOR) && (!UNIT_TEST)
|
||||
/* Timestamp counter for Sensor Subsystem is 32bit. */
|
||||
#define get_ticks() __builtin_arc_lr(QM_SS_TSC_BASE + QM_SS_TIMER_COUNT)
|
||||
#elif(QM_SENSOR) && (UNIT_TEST)
|
||||
#define get_ticks() _rdtsc() % ((uint32_t)-1)
|
||||
#else
|
||||
/* 64bit Timestamp counter */
|
||||
#define get_ticks() _rdtsc()
|
||||
#endif
|
||||
|
||||
/* NOTE: Currently user space data / bss section overwrites the ROM data / bss
|
||||
* sections, so anything that is set in the ROM will be obliterated once we jump
|
||||
* into the user app.
|
||||
*/
|
||||
static uint32_t ticks_per_us = SYS_TICKS_PER_US_32MHZ;
|
||||
|
||||
/* Set up flash timings according to the target sysclk frequency.
|
||||
*
|
||||
* By POR prefetcher is disabled.
|
||||
* Drivers do not expect the pre-fetcher to be enabled,
|
||||
* therefore this function does assume the prefetcher is always turned off.
|
||||
*/
|
||||
static void apply_flash_timings(uint32_t sys_ticks_per_us)
|
||||
{
|
||||
uint32_t flash;
|
||||
|
||||
for (flash = QM_FLASH_0; flash < QM_FLASH_NUM; flash++) {
|
||||
if (sys_ticks_per_us <= SYS_TICKS_PER_US_4MHZ) {
|
||||
/*
|
||||
* QM_FLASH_CLK_SLOW enables 0 wait states
|
||||
* for flash accesses.
|
||||
*/
|
||||
QM_FLASH[flash]->tmg_ctrl |= QM_FLASH_CLK_SLOW;
|
||||
QM_FLASH[flash]->tmg_ctrl &= ~QM_FLASH_WAIT_STATE_MASK;
|
||||
} else if (sys_ticks_per_us <= SYS_TICKS_PER_US_16MHZ) {
|
||||
QM_FLASH[flash]->tmg_ctrl &= ~QM_FLASH_CLK_SLOW;
|
||||
/*
|
||||
* READ_WAIT_STATE_L has an integrated +1 which
|
||||
* results as 1 wait state for 8MHz and 16MHz.
|
||||
*/
|
||||
QM_FLASH[flash]->tmg_ctrl &= ~QM_FLASH_WAIT_STATE_MASK;
|
||||
} else {
|
||||
QM_FLASH[flash]->tmg_ctrl &= ~QM_FLASH_CLK_SLOW;
|
||||
/*
|
||||
* READ_WAIT_STATE_L has an integrated +1 which
|
||||
* results as 2 wait states for 32MHz.
|
||||
*/
|
||||
QM_FLASH[flash]->tmg_ctrl =
|
||||
(QM_FLASH[flash]->tmg_ctrl &
|
||||
~QM_FLASH_WAIT_STATE_MASK) |
|
||||
(1 << QM_FLASH_WAIT_STATE_OFFSET);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute the system clock ticks per microsecond and get the shadowed trim code
|
||||
* from the Data Region of Flash.
|
||||
*/
|
||||
static void clk_sys_compute_new_frequency(clk_sys_mode_t mode,
|
||||
clk_sys_div_t div,
|
||||
uint32_t *sys_ticks_per_us,
|
||||
uint16_t *trim)
|
||||
{
|
||||
switch (mode) {
|
||||
case CLK_SYS_HYB_OSC_32MHZ:
|
||||
*sys_ticks_per_us = SYS_TICKS_PER_US_32MHZ / BIT(div);
|
||||
*trim = QM_FLASH_DATA_TRIM_CODE->osc_trim_32mhz;
|
||||
break;
|
||||
|
||||
case CLK_SYS_HYB_OSC_16MHZ:
|
||||
*sys_ticks_per_us = SYS_TICKS_PER_US_16MHZ / BIT(div);
|
||||
*trim = QM_FLASH_DATA_TRIM_CODE->osc_trim_16mhz;
|
||||
break;
|
||||
|
||||
case CLK_SYS_HYB_OSC_8MHZ:
|
||||
*sys_ticks_per_us = SYS_TICKS_PER_US_8MHZ / BIT(div);
|
||||
*trim = QM_FLASH_DATA_TRIM_CODE->osc_trim_8mhz;
|
||||
break;
|
||||
|
||||
case CLK_SYS_HYB_OSC_4MHZ:
|
||||
*sys_ticks_per_us = SYS_TICKS_PER_US_4MHZ / BIT(div);
|
||||
*trim = QM_FLASH_DATA_TRIM_CODE->osc_trim_4mhz;
|
||||
break;
|
||||
|
||||
case CLK_SYS_RTC_OSC:
|
||||
*sys_ticks_per_us = 1;
|
||||
break;
|
||||
|
||||
case CLK_SYS_CRYSTAL_OSC:
|
||||
*sys_ticks_per_us = SYS_TICKS_PER_US_XTAL / BIT(div);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int clk_sys_set_mode(const clk_sys_mode_t mode, const clk_sys_div_t div)
|
||||
{
|
||||
QM_CHECK(div < CLK_SYS_DIV_NUM, -EINVAL);
|
||||
QM_CHECK(mode <= CLK_SYS_CRYSTAL_OSC, -EINVAL);
|
||||
uint16_t trim = 0;
|
||||
|
||||
/* Store system ticks per us */
|
||||
uint32_t sys_ticks_per_us = 1;
|
||||
|
||||
/*
|
||||
* Get current settings, clear the clock divisor bits, and clock divider
|
||||
* enable bit.
|
||||
*/
|
||||
uint32_t ccu_sys_clk_ctl =
|
||||
QM_SCSS_CCU->ccu_sys_clk_ctl & CLK_SYS_CLK_DIV_DEF_MASK;
|
||||
|
||||
/* Compute new frequency parameters. */
|
||||
clk_sys_compute_new_frequency(mode, div, &sys_ticks_per_us, &trim);
|
||||
|
||||
/*
|
||||
* Changing sysclk frequency requires flash settings (mainly
|
||||
* wait states) to be realigned so as to avoid timing violations.
|
||||
* During clock switching, we change flash timings to the
|
||||
* most conservative settings (supporting up to 32MHz).
|
||||
*/
|
||||
apply_flash_timings(SYS_TICKS_PER_US_32MHZ);
|
||||
|
||||
/*
|
||||
* Steps:
|
||||
* 1. Enable the new oscillator and wait for it to stabilise.
|
||||
* 2. Switch to the new oscillator
|
||||
* Note on registers:
|
||||
* - QM_OSC0_MODE_SEL:
|
||||
* - asserted: it switches to external crystal oscillator
|
||||
* - not asserted: it switches to silicon oscillator
|
||||
* - QM_CCU_SYS_CLK_SEL:
|
||||
* - asserted: it switches to hybrid (silicon or external)
|
||||
* oscillator
|
||||
* - not asserted: it switches to RTC oscillator
|
||||
* 3. Hybrid oscillator only: apply sysclk divisor
|
||||
* 4. Disable mutually exclusive clock sources. For internal silicon
|
||||
* oscillator is disables the external crystal oscillator and vice
|
||||
* versa.
|
||||
*/
|
||||
switch (mode) {
|
||||
case CLK_SYS_HYB_OSC_32MHZ:
|
||||
case CLK_SYS_HYB_OSC_16MHZ:
|
||||
case CLK_SYS_HYB_OSC_8MHZ:
|
||||
case CLK_SYS_HYB_OSC_4MHZ:
|
||||
/*
|
||||
* Apply trim code for the selected mode if this has been
|
||||
* written in the soc_data section.
|
||||
* This is performed in rom on the first boot for each
|
||||
* available frequency.
|
||||
* If not present, something went wrong and trim code
|
||||
* will not be applied.
|
||||
*/
|
||||
if ((trim & QM_FLASH_TRIM_PRESENT_MASK) ==
|
||||
QM_FLASH_TRIM_PRESENT) {
|
||||
clk_trim_apply(trim);
|
||||
}
|
||||
/* Select the silicon oscillator frequency */
|
||||
QM_SCSS_CCU->osc0_cfg1 &= ~OSC0_CFG1_SI_FREQ_SEL_MASK;
|
||||
QM_SCSS_CCU->osc0_cfg1 |= (mode << OSC0_CFG1_SI_FREQ_SEL_OFFS);
|
||||
/* Enable the silicon oscillator */
|
||||
QM_SCSS_CCU->osc0_cfg1 |= QM_OSC0_EN_SI_OSC;
|
||||
/* Wait for the oscillator to lock */
|
||||
while (!(QM_SCSS_CCU->osc0_stat1 & QM_OSC0_LOCK_SI)) {
|
||||
};
|
||||
/* Switch to silicon oscillator mode */
|
||||
QM_SCSS_CCU->osc0_cfg1 &= ~QM_OSC0_MODE_SEL;
|
||||
/* Set the system clock divider */
|
||||
QM_SCSS_CCU->ccu_sys_clk_ctl =
|
||||
ccu_sys_clk_ctl | QM_CCU_SYS_CLK_SEL |
|
||||
(div << QM_CCU_SYS_CLK_DIV_OFFSET);
|
||||
/* Disable the crystal oscillator */
|
||||
QM_SCSS_CCU->osc0_cfg1 &= ~QM_OSC0_EN_CRYSTAL;
|
||||
break;
|
||||
|
||||
case CLK_SYS_RTC_OSC:
|
||||
/* The RTC oscillator is on by hardware default */
|
||||
ccu_sys_clk_ctl |=
|
||||
(QM_CCU_RTC_CLK_EN | (div << QM_CCU_SYS_CLK_DIV_OFFSET));
|
||||
|
||||
QM_SCSS_CCU->ccu_sys_clk_ctl =
|
||||
(ccu_sys_clk_ctl & ~(QM_CCU_SYS_CLK_SEL));
|
||||
break;
|
||||
|
||||
case CLK_SYS_CRYSTAL_OSC:
|
||||
QM_SCSS_CCU->osc0_cfg1 |= QM_OSC0_EN_CRYSTAL;
|
||||
sys_ticks_per_us = SYS_TICKS_PER_US_XTAL / BIT(div);
|
||||
while (!(QM_SCSS_CCU->osc0_stat1 & QM_OSC0_LOCK_XTAL)) {
|
||||
};
|
||||
QM_SCSS_CCU->osc0_cfg1 |= QM_OSC0_MODE_SEL;
|
||||
QM_SCSS_CCU->ccu_sys_clk_ctl =
|
||||
ccu_sys_clk_ctl | QM_CCU_SYS_CLK_SEL |
|
||||
(div << QM_CCU_SYS_CLK_DIV_OFFSET);
|
||||
QM_SCSS_CCU->osc0_cfg1 &= ~QM_OSC0_EN_SI_OSC;
|
||||
break;
|
||||
}
|
||||
|
||||
QM_SCSS_CCU->ccu_sys_clk_ctl |= QM_CCU_SYS_CLK_DIV_EN;
|
||||
ticks_per_us = (sys_ticks_per_us > 0 ? sys_ticks_per_us : 1);
|
||||
|
||||
/*
|
||||
* Apply flash timings for the new clock settings.
|
||||
*/
|
||||
apply_flash_timings(sys_ticks_per_us);
|
||||
|
||||
/* Log any clock changes. */
|
||||
SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_OSC0_CFG1);
|
||||
SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER, SOCW_REG_CCU_SYS_CLK_CTL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clk_trim_read(uint32_t *const value)
|
||||
{
|
||||
QM_CHECK(NULL != value, -EINVAL);
|
||||
|
||||
*value = (QM_SCSS_CCU->osc0_cfg1 & OSC0_CFG1_FTRIMOTP_MASK) >>
|
||||
OSC0_CFG1_FTRIMOTP_OFFS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clk_trim_apply(const uint32_t value)
|
||||
{
|
||||
/* Enable trim mode */
|
||||
QM_SCSS_CCU->osc0_cfg0 |= BIT(1);
|
||||
|
||||
/* Apply trim code */
|
||||
QM_SCSS_CCU->osc0_cfg1 &= ~OSC0_CFG1_FTRIMOTP_MASK;
|
||||
QM_SCSS_CCU->osc0_cfg1 |=
|
||||
(value << OSC0_CFG1_FTRIMOTP_OFFS) & OSC0_CFG1_FTRIMOTP_MASK;
|
||||
|
||||
/*
|
||||
* Recommended wait time after setting up the trim code
|
||||
* is 200us. Minimum wait time is 100us.
|
||||
* The delay is running from of the silicon oscillator
|
||||
* which is been trimmed. This induces a lack of precision
|
||||
* in the delay.
|
||||
*/
|
||||
clk_sys_udelay(200);
|
||||
|
||||
/* Disable trim mode */
|
||||
QM_SCSS_CCU->osc0_cfg0 &= ~BIT(1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clk_periph_set_div(const clk_periph_div_t div)
|
||||
{
|
||||
QM_CHECK(div <= CLK_PERIPH_DIV_8, -EINVAL);
|
||||
|
||||
QM_SCSS_CCU->ccu_periph_clk_div_ctl0 =
|
||||
(div << QM_CCU_PERIPH_PCLK_DIV_OFFSET);
|
||||
/* CLK Div en bit must be written from 0 -> 1 to apply new value */
|
||||
QM_SCSS_CCU->ccu_periph_clk_div_ctl0 |= QM_CCU_PERIPH_PCLK_DIV_EN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clk_gpio_db_set_div(const clk_gpio_db_div_t div)
|
||||
{
|
||||
QM_CHECK(div <= CLK_GPIO_DB_DIV_128, -EINVAL);
|
||||
|
||||
uint32_t reg =
|
||||
QM_SCSS_CCU->ccu_gpio_db_clk_ctl & CLK_GPIO_DB_DIV_DEF_MASK;
|
||||
reg |= (div << QM_CCU_GPIO_DB_DIV_OFFSET);
|
||||
QM_SCSS_CCU->ccu_gpio_db_clk_ctl = reg;
|
||||
/* CLK Div en bit must be written from 0 -> 1 to apply new value */
|
||||
QM_SCSS_CCU->ccu_gpio_db_clk_ctl |= QM_CCU_GPIO_DB_CLK_DIV_EN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clk_ext_set_div(const clk_ext_div_t div)
|
||||
{
|
||||
QM_CHECK(div <= CLK_EXT_DIV_8, -EINVAL);
|
||||
|
||||
uint32_t reg = QM_SCSS_CCU->ccu_ext_clock_ctl & CLK_EXTERN_DIV_DEF_MASK;
|
||||
reg |= (div << QM_CCU_EXTERN_DIV_OFFSET);
|
||||
QM_SCSS_CCU->ccu_ext_clock_ctl = reg;
|
||||
/* CLK Div en bit must be written from 0 -> 1 to apply new value */
|
||||
QM_SCSS_CCU->ccu_ext_clock_ctl |= QM_CCU_EXT_CLK_DIV_EN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clk_rtc_set_div(const clk_rtc_div_t div)
|
||||
{
|
||||
QM_CHECK(div <= CLK_RTC_DIV_32768, -EINVAL);
|
||||
|
||||
uint32_t reg = QM_SCSS_CCU->ccu_sys_clk_ctl & CLK_RTC_DIV_DEF_MASK;
|
||||
reg |= (div << QM_CCU_RTC_CLK_DIV_OFFSET);
|
||||
QM_SCSS_CCU->ccu_sys_clk_ctl = reg;
|
||||
/* CLK Div en bit must be written from 0 -> 1 to apply new value */
|
||||
QM_SCSS_CCU->ccu_sys_clk_ctl |= QM_CCU_RTC_CLK_DIV_EN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clk_periph_enable(const clk_periph_t clocks)
|
||||
{
|
||||
QM_CHECK(clocks <= CLK_PERIPH_ALL, -EINVAL);
|
||||
|
||||
QM_SCSS_CCU->ccu_periph_clk_gate_ctl |= clocks;
|
||||
|
||||
SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER,
|
||||
SOCW_REG_CCU_PERIPH_CLK_GATE_CTL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clk_periph_disable(const clk_periph_t clocks)
|
||||
{
|
||||
QM_CHECK(clocks <= CLK_PERIPH_ALL, -EINVAL);
|
||||
|
||||
QM_SCSS_CCU->ccu_periph_clk_gate_ctl &= ~clocks;
|
||||
|
||||
SOC_WATCH_LOG_EVENT(SOCW_EVENT_REGISTER,
|
||||
SOCW_REG_CCU_PERIPH_CLK_GATE_CTL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t clk_sys_get_ticks_per_us(void)
|
||||
{
|
||||
return ticks_per_us;
|
||||
}
|
||||
|
||||
void clk_sys_udelay(uint32_t microseconds)
|
||||
{
|
||||
uint32_t timeout = ticks_per_us * microseconds;
|
||||
#if (QM_SENSOR)
|
||||
uint32_t tsc_start;
|
||||
#else
|
||||
unsigned long long tsc_start;
|
||||
#endif
|
||||
tsc_start = get_ticks();
|
||||
/* We need to wait until timeout system clock ticks has occurred. */
|
||||
while (get_ticks() - tsc_start < timeout) {
|
||||
}
|
||||
}
|
||||
|
||||
int clk_sys_usb_enable(void)
|
||||
{
|
||||
/*
|
||||
* Section 7.2.7 from Quark SE datasheet describes the USB
|
||||
* Clock setup.
|
||||
*/
|
||||
clk_sys_set_mode(CLK_SYS_CRYSTAL_OSC, CLK_SYS_DIV_1);
|
||||
|
||||
/* Enable the USB Clock. */
|
||||
QM_SCSS_CCU->ccu_mlayer_ahb_ctl |= QM_CCU_USB_CLK_EN;
|
||||
|
||||
/* Set up the PLL. */
|
||||
QM_USB_PLL_CFG0 = QM_USB_PLL_CFG0_DEFAULT | QM_USB_PLL_PDLD;
|
||||
|
||||
/* Let's have at most 50ms timeout for the PLL lock. */
|
||||
int timeout = 5;
|
||||
|
||||
/* Wait for the PLL lock. */
|
||||
while (!(QM_USB_PLL_CFG0 & QM_USB_PLL_LOCK) && timeout) {
|
||||
clk_sys_udelay(10000); /* delay for 10ms. */
|
||||
timeout--;
|
||||
}
|
||||
|
||||
if (!timeout) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clk_sys_usb_disable(void)
|
||||
{
|
||||
/* Disable the USB Clock. */
|
||||
QM_SCSS_CCU->ccu_mlayer_ahb_ctl &= ~QM_CCU_USB_CLK_EN;
|
||||
|
||||
/* Disable the PLL. */
|
||||
QM_USB_PLL_CFG0 &= ~QM_USB_PLL_PDLD;
|
||||
|
||||
/* Let's have at most 50ms timeout for the PLL lock. */
|
||||
int timeout = 5;
|
||||
|
||||
/* Wait for the PLL to unlock. */
|
||||
while ((QM_USB_PLL_CFG0 & QM_USB_PLL_LOCK) && timeout) {
|
||||
clk_sys_udelay(10000); /* delay for 10ms. */
|
||||
timeout--;
|
||||
}
|
||||
|
||||
if (!timeout) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -86,7 +86,16 @@ void power_soc_deep_sleep()
|
|||
void power_cpu_c1()
|
||||
{
|
||||
SOC_WATCH_LOG_EVENT(SOCW_EVENT_HALT, 0);
|
||||
__asm__ __volatile__("hlt");
|
||||
/*
|
||||
* STI sets the IF flag. After the IF flag is set,
|
||||
* the core begins responding to external,
|
||||
* maskable interrupts after the next instruction is executed.
|
||||
* When this function is called with interrupts disabled,
|
||||
* this guarantees that an interrupt is caught only
|
||||
* after the processor has transitioned into HLT.
|
||||
*/
|
||||
__asm__ __volatile__("sti\n\t"
|
||||
"hlt\n\t");
|
||||
}
|
||||
|
||||
void power_cpu_c2()
|
||||
|
|
|
@ -27,34 +27,32 @@
|
|||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "rar.h"
|
||||
#include "ss_init.h"
|
||||
|
||||
#if (HAS_RAR)
|
||||
int rar_set_mode(const rar_state_t mode)
|
||||
{
|
||||
QM_CHECK(mode <= RAR_RETENTION, -EINVAL);
|
||||
volatile uint32_t i = 32;
|
||||
volatile uint32_t reg;
|
||||
/* Sensor Subsystem application's pointer to the entry point (Flash0) */
|
||||
#define SS_APP_PTR_ADDR (0x40000000)
|
||||
|
||||
switch (mode) {
|
||||
case RAR_RETENTION:
|
||||
QM_SCSS_PMU->aon_vr |=
|
||||
(QM_AON_VR_PASS_CODE | QM_AON_VR_ROK_BUF_VREG_MASK);
|
||||
QM_SCSS_PMU->aon_vr |=
|
||||
(QM_AON_VR_PASS_CODE | QM_AON_VR_VREG_SEL);
|
||||
break;
|
||||
|
||||
case RAR_NORMAL:
|
||||
reg = QM_SCSS_PMU->aon_vr & ~QM_AON_VR_VREG_SEL;
|
||||
QM_SCSS_PMU->aon_vr = QM_AON_VR_PASS_CODE | reg;
|
||||
/* Wait for >= 2usec, at most 64 clock cycles. */
|
||||
while (i--) {
|
||||
__asm__ __volatile__("nop");
|
||||
}
|
||||
reg = QM_SCSS_PMU->aon_vr & ~QM_AON_VR_ROK_BUF_VREG_MASK;
|
||||
QM_SCSS_PMU->aon_vr = QM_AON_VR_PASS_CODE | reg;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#if (UNIT_TEST)
|
||||
uint32_t __sensor_reset_vector[1];
|
||||
#else
|
||||
extern uint32_t __sensor_reset_vector[];
|
||||
#endif
|
||||
|
||||
void sensor_activation(void)
|
||||
{
|
||||
/* Write the ARC reset vector.
|
||||
*
|
||||
* The ARC reset vector is in SRAM. The first 4 bytes of the Sensor
|
||||
* Subsystem Flash partition point to the application entry point
|
||||
* (pointer located at SS_APP_PTR_ADDR).
|
||||
* Write the pointer to the application entry point into the reset
|
||||
* vector.
|
||||
*/
|
||||
volatile uint32_t *ss_reset_vector = __sensor_reset_vector;
|
||||
volatile uint32_t *sensor_startup = (uint32_t *)SS_APP_PTR_ADDR;
|
||||
|
||||
*ss_reset_vector = *sensor_startup;
|
||||
|
||||
/* Request ARC Run */
|
||||
QM_SCSS_SS->ss_cfg |= QM_SS_CFG_ARC_RUN_REQ_A;
|
||||
}
|
322
ext/hal/qmsi/soc/quark_se/include/clk.h
Normal file
322
ext/hal/qmsi/soc/quark_se/include/clk.h
Normal file
|
@ -0,0 +1,322 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Intel Corporation
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL CORPORATION OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __CLK_H__
|
||||
#define __CLK_H__
|
||||
|
||||
#include "qm_common.h"
|
||||
#include "qm_soc_regs.h"
|
||||
#if (QM_SENSOR)
|
||||
#include "qm_sensor_regs.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Clock Management.
|
||||
*
|
||||
* @defgroup groupCLK Clock Management
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*
|
||||
* When using an external crystal, this value must be set to the number of
|
||||
* system ticks per micro second. The expected value is 32 ticks for a 32MHz
|
||||
* crystal.
|
||||
*/
|
||||
#define SYS_TICKS_PER_US_XTAL (32)
|
||||
/* System ticks per microseconds for a 32MHz oscillator. */
|
||||
#define SYS_TICKS_PER_US_32MHZ (32)
|
||||
/* System ticks per microseconds for a 16MHz oscillator. */
|
||||
#define SYS_TICKS_PER_US_16MHZ (16)
|
||||
/* System ticks per microseconds for a 8MHz oscillator. */
|
||||
#define SYS_TICKS_PER_US_8MHZ (8)
|
||||
/* System ticks per microseconds for a 4MHz oscillator. */
|
||||
#define SYS_TICKS_PER_US_4MHZ (4)
|
||||
|
||||
/**
|
||||
* System clock divider type.
|
||||
*/
|
||||
typedef enum {
|
||||
CLK_SYS_DIV_1, /**< Clock Divider = 1. */
|
||||
CLK_SYS_DIV_2, /**< Clock Divider = 2. */
|
||||
CLK_SYS_DIV_4, /**< Clock Divider = 4. */
|
||||
CLK_SYS_DIV_8, /**< Clock Divider = 8. */
|
||||
CLK_SYS_DIV_NUM
|
||||
} clk_sys_div_t;
|
||||
|
||||
/**
|
||||
* System clock mode type.
|
||||
*/
|
||||
typedef enum {
|
||||
CLK_SYS_HYB_OSC_32MHZ = 0, /**< 32MHz Hybrid Oscillator Clock. */
|
||||
CLK_SYS_HYB_OSC_16MHZ = 1, /**< 16MHz Hybrid Oscillator Clock. */
|
||||
CLK_SYS_HYB_OSC_8MHZ = 2, /**< 8MHz Hybrid Oscillator Clock. */
|
||||
CLK_SYS_HYB_OSC_4MHZ = 3, /**< 4MHz Hybrid Oscillator Clock. */
|
||||
CLK_SYS_RTC_OSC = 4, /**< Real Time Clock. */
|
||||
CLK_SYS_CRYSTAL_OSC = 5 /**< Crystal Oscillator Clock. */
|
||||
} clk_sys_mode_t;
|
||||
|
||||
/**
|
||||
* Peripheral clock divider type.
|
||||
*/
|
||||
typedef enum {
|
||||
CLK_PERIPH_DIV_1, /**< Peripheral Clock Divider = 1. */
|
||||
CLK_PERIPH_DIV_2, /**< Peripheral Clock Divider = 2. */
|
||||
CLK_PERIPH_DIV_4, /**< Peripheral Clock Divider = 4. */
|
||||
CLK_PERIPH_DIV_8 /**< Peripheral Clock Divider = 8. */
|
||||
} clk_periph_div_t;
|
||||
|
||||
/**
|
||||
* GPIO clock debounce divider type.
|
||||
*/
|
||||
typedef enum {
|
||||
CLK_GPIO_DB_DIV_1, /**< GPIO Clock Debounce Divider = 1. */
|
||||
CLK_GPIO_DB_DIV_2, /**< GPIO Clock Debounce Divider = 2. */
|
||||
CLK_GPIO_DB_DIV_4, /**< GPIO Clock Debounce Divider = 4. */
|
||||
CLK_GPIO_DB_DIV_8, /**< GPIO Clock Debounce Divider = 8. */
|
||||
CLK_GPIO_DB_DIV_16, /**< GPIO Clock Debounce Divider = 16. */
|
||||
CLK_GPIO_DB_DIV_32, /**< GPIO Clock Debounce Divider = 32. */
|
||||
CLK_GPIO_DB_DIV_64, /**< GPIO Clock Debounce Divider = 64. */
|
||||
CLK_GPIO_DB_DIV_128 /**< GPIO Clock Debounce Divider = 128. */
|
||||
} clk_gpio_db_div_t;
|
||||
|
||||
/**
|
||||
* External crystal clock divider type.
|
||||
*/
|
||||
typedef enum {
|
||||
CLK_EXT_DIV_1, /**< External Crystal Clock Divider = 1. */
|
||||
CLK_EXT_DIV_2, /**< External Crystal Clock Divider = 2. */
|
||||
CLK_EXT_DIV_4, /**< External Crystal Clock Divider = 4. */
|
||||
CLK_EXT_DIV_8 /**< External Crystal Clock Divider = 8. */
|
||||
} clk_ext_div_t;
|
||||
|
||||
/**
|
||||
* RTC clock divider type.
|
||||
*/
|
||||
typedef enum {
|
||||
CLK_RTC_DIV_1, /**< Real Time Clock Divider = 1. */
|
||||
CLK_RTC_DIV_2, /**< Real Time Clock Divider = 2. */
|
||||
CLK_RTC_DIV_4, /**< Real Time Clock Divider = 4. */
|
||||
CLK_RTC_DIV_8, /**< Real Time Clock Divider = 8. */
|
||||
CLK_RTC_DIV_16, /**< Real Time Clock Divider = 16. */
|
||||
CLK_RTC_DIV_32, /**< Real Time Clock Divider = 32. */
|
||||
CLK_RTC_DIV_64, /**< Real Time Clock Divider = 64. */
|
||||
CLK_RTC_DIV_128, /**< Real Time Clock Divider = 128. */
|
||||
CLK_RTC_DIV_256, /**< Real Time Clock Divider = 256. */
|
||||
CLK_RTC_DIV_512, /**< Real Time Clock Divider = 512. */
|
||||
CLK_RTC_DIV_1024, /**< Real Time Clock Divider = 1024. */
|
||||
CLK_RTC_DIV_2048, /**< Real Time Clock Divider = 2048. */
|
||||
CLK_RTC_DIV_4096, /**< Real Time Clock Divider = 4096. */
|
||||
CLK_RTC_DIV_8192, /**< Real Time Clock Divider = 8192. */
|
||||
CLK_RTC_DIV_16384, /**< Real Time Clock Divider = 16384. */
|
||||
CLK_RTC_DIV_32768 /**< Real Time Clock Divider = 32768. */
|
||||
} clk_rtc_div_t;
|
||||
|
||||
/**
|
||||
* Set clock mode and divisor.
|
||||
*
|
||||
* Change the operating mode and clock divisor of the system
|
||||
* clock source. Changing this clock speed affects all
|
||||
* peripherals.
|
||||
* This applies the correct trim code if available.
|
||||
*
|
||||
* If trim code is not available, it is not computed
|
||||
* and previous trim code is not modified.
|
||||
*
|
||||
* @param[in] mode System clock source operating mode.
|
||||
* @param[in] div System clock divisor.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int clk_sys_set_mode(const clk_sys_mode_t mode, const clk_sys_div_t div);
|
||||
|
||||
/**
|
||||
* Read the silicon oscillator trim code for the current frequency.
|
||||
*
|
||||
* @param[out] value Pointer to store the trim code.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int clk_trim_read(uint32_t *const value);
|
||||
|
||||
/**
|
||||
* Apply silicon oscillator trim code.
|
||||
*
|
||||
* @param[in] value Trim code to apply.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int clk_trim_apply(const uint32_t value);
|
||||
|
||||
/**
|
||||
* Change divider value of peripheral clock.
|
||||
*
|
||||
* Change Peripheral clock divider value.
|
||||
* The maximum divisor is /8.
|
||||
* Refer to the list of supported peripherals for your SoC.
|
||||
*
|
||||
* @param[in] div Divider value for the peripheral clock.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int clk_periph_set_div(const clk_periph_div_t div);
|
||||
|
||||
/**
|
||||
* Change divider value of GPIO debounce clock.
|
||||
*
|
||||
* Change GPIO debounce clock divider value.
|
||||
* The maximum divisor is /128.
|
||||
*
|
||||
* @param[in] div Divider value for the GPIO debounce clock.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int clk_gpio_db_set_div(const clk_gpio_db_div_t div);
|
||||
|
||||
/**
|
||||
* Change divider value of external clock.
|
||||
*
|
||||
* Change External clock divider value.
|
||||
* The maximum divisor is /8.
|
||||
*
|
||||
* @param[in] div Divider value for the external clock.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int clk_ext_set_div(const clk_ext_div_t div);
|
||||
|
||||
/**
|
||||
* Change divider value of RTC.
|
||||
*
|
||||
* Change RTC divider value.
|
||||
* The maximum divisor is /32768.
|
||||
*
|
||||
* @param[in] div Divider value for the RTC.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int clk_rtc_set_div(const clk_rtc_div_t div);
|
||||
|
||||
/**
|
||||
* Enable clocks for peripherals / registers.
|
||||
*
|
||||
* @param[in] clocks Which peripheral and register clocks to enable.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int clk_periph_enable(const clk_periph_t clocks);
|
||||
|
||||
/**
|
||||
* Disable clocks for peripherals / registers.
|
||||
*
|
||||
* @param[in] clocks Which peripheral and register clocks to disable.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int clk_periph_disable(const clk_periph_t clocks);
|
||||
|
||||
/**
|
||||
* Get number of system ticks per micro second.
|
||||
*
|
||||
* @return uint32_t Number of system ticks per micro second.
|
||||
*/
|
||||
uint32_t clk_sys_get_ticks_per_us(void);
|
||||
|
||||
/**
|
||||
* Idle loop the processor for at least the value given in microseconds.
|
||||
*
|
||||
* This function will wait until at least the given number of microseconds has
|
||||
* elapsed since calling this function.
|
||||
*
|
||||
* Note:
|
||||
* It is dependent on the system clock speed.
|
||||
* The delay parameter does not include, calling the function, returning
|
||||
* from it, calculation setup and while loops.
|
||||
*
|
||||
* @param[in] microseconds Minimum number of micro seconds to delay for.
|
||||
*/
|
||||
void clk_sys_udelay(uint32_t microseconds);
|
||||
|
||||
/**
|
||||
* Enable the USB Clock mode.
|
||||
*
|
||||
* For Quark SE, this function will set the system clock to CLK_SYS_CRYSTAL_OSC
|
||||
* mode with CLK_SYS_DIV_1 divisor. It then will enable the USB Clock and PLL,
|
||||
* blocking execution until the USB PLL lock is ready.
|
||||
*
|
||||
* Note:
|
||||
* Application must retain the original system clock mode / divisor in case it
|
||||
* will need to restore it after disabling the usb clock.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int clk_sys_usb_enable(void);
|
||||
|
||||
/**
|
||||
* Disable the USB Clock mode.
|
||||
*
|
||||
* This function will disable the USB Clock and PLL.
|
||||
* The system clock will remain as CLK_SYS_CRYSTAL_OSC mode and CLK_SYS_DIV_1
|
||||
* divider.
|
||||
*
|
||||
* Note:
|
||||
* If the application must restore the original system clock mode / divisor
|
||||
* it must explictly call clk_sys_set_mode() restoring the previous config.
|
||||
* This can only be done after the USB clock mode is disabled.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int clk_sys_usb_disable(void);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* __CLK_H__ */
|
|
@ -36,6 +36,13 @@
|
|||
/**
|
||||
* SoC Power mode control for Quark SE Microcontrollers.
|
||||
*
|
||||
* Available SoC states are:
|
||||
* - Low Power Sensing Standby (LPSS)
|
||||
* - Sleep
|
||||
*
|
||||
* LPSS can only be enabled from the Sensor core,
|
||||
* refer to @ref ss_power_soc_lpss_enable for further details.
|
||||
*
|
||||
* @defgroup groupSoCPower Quark SE SoC Power states
|
||||
* @{
|
||||
*/
|
||||
|
@ -98,6 +105,9 @@ void power_soc_deep_sleep(void);
|
|||
* Processor Clock is gated in this state.<BR>
|
||||
* Nothing is turned off in this state.
|
||||
*
|
||||
* This function can be called with interrupts disabled.
|
||||
* Interrupts will be enabled before triggering the transition.
|
||||
*
|
||||
* A wake event causes the Host to transition to C0.<BR>
|
||||
* A wake event is a host interrupt.
|
||||
*/
|
||||
|
|
|
@ -85,7 +85,7 @@ uint32_t test_sensor_aux[QM_SS_AUX_REGS_SIZE];
|
|||
(__builtin_arc_sr(__builtin_arc_lr(reg) | (mask), reg))
|
||||
/* Bitwise NAND operation macro for registers in the auxiliary memory space. */
|
||||
#define QM_SS_REG_AUX_NAND(reg, mask) \
|
||||
(__builtin_arc_sr(__builtin_arc_lr(reg) & (~mask), reg))
|
||||
(__builtin_arc_sr(__builtin_arc_lr(reg) & (~(mask)), reg))
|
||||
|
||||
/* Sensor Subsystem status32 register. */
|
||||
#define QM_SS_AUX_STATUS32 (0xA)
|
||||
|
@ -192,7 +192,7 @@ typedef enum {
|
|||
#define QM_SS_I2C_CON_RESTART_EN BIT(7)
|
||||
#define QM_SS_I2C_CON_TAR_SAR_OFFSET (9)
|
||||
#define QM_SS_I2C_CON_TAR_SAR_MASK (0x7FE00)
|
||||
#define QM_SS_I2C_CON_TAR_SAR_10_BIT_MASK (0xFF)
|
||||
#define QM_SS_I2C_CON_TAR_SAR_10_BIT_MASK (0x3FF)
|
||||
#define QM_SS_I2C_CON_SPKLEN_OFFSET (22)
|
||||
#define QM_SS_I2C_CON_SPKLEN_MASK (0x3FC00000)
|
||||
#define QM_SS_I2C_CON_CLK_ENA BIT(31)
|
||||
|
@ -335,28 +335,27 @@ typedef enum {
|
|||
QM_SS_IO_CREG_SLV1_OBSR = 0x180 /**< Slave control register. */
|
||||
} qm_ss_creg_reg_t;
|
||||
|
||||
#define QM_SS_ADC_CAL_MAX (0x7F)
|
||||
/* MST0_CTRL fields */
|
||||
#define QM_SS_ADC_PWR_MODE_OFFSET (1)
|
||||
#define QM_SS_ADC_PWR_MODE_MASK (0x7)
|
||||
#define QM_SS_ADC_DELAY_OFFSET (3)
|
||||
#define QM_SS_ADC_DELAY_MASK (0xFFF8)
|
||||
#define QM_SS_ADC_CAL_REQ BIT(16)
|
||||
#define QM_SS_ADC_CAL_CMD_OFFSET (17)
|
||||
#define QM_SS_ADC_CAL_CMD_MASK (0xE0000)
|
||||
#define QM_SS_ADC_CAL_VAL_SET_OFFSET (20)
|
||||
#define QM_SS_ADC_CAL_VAL_SET_MASK (0x7F00000)
|
||||
|
||||
#define QM_SS_IO_CREG_MST0_CTRL_ADC_CLK_GATE BIT(31)
|
||||
#define QM_SS_IO_CREG_MST0_CTRL_I2C1_CLK_GATE BIT(30)
|
||||
#define QM_SS_IO_CREG_MST0_CTRL_I2C0_CLK_GATE BIT(29)
|
||||
#define QM_SS_IO_CREG_MST0_CTRL_SPI0_CLK_GATE BIT(28)
|
||||
#define QM_SS_IO_CREG_MST0_CTRL_ADC_PWR_MODE_OFFSET (1)
|
||||
#define QM_SS_IO_CREG_MST0_CTRL_ADC_PWR_MODE_MASK (0x7)
|
||||
#define QM_SS_IO_CREG_MST0_CTRL_ADC_DELAY_OFFSET (3)
|
||||
#define QM_SS_IO_CREG_MST0_CTRL_ADC_DELAY_MASK (0xFFF8)
|
||||
#define QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_REQ BIT(16)
|
||||
#define QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_CMD_OFFSET (17)
|
||||
#define QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_CMD_MASK (0xE0000)
|
||||
#define QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_VAL_OFFSET (20)
|
||||
#define QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_VAL_MASK (0x7F00000)
|
||||
#define QM_SS_IO_CREG_MST0_CTRL_ADC_CAL_VAL_MAX (0x7F)
|
||||
#define QM_SS_IO_CREG_MST0_CTRL_SPI1_CLK_GATE BIT(27)
|
||||
#define QM_SS_IO_CREG_MST0_CTRL_SPI0_CLK_GATE BIT(28)
|
||||
#define QM_SS_IO_CREG_MST0_CTRL_I2C0_CLK_GATE BIT(29)
|
||||
#define QM_SS_IO_CREG_MST0_CTRL_I2C1_CLK_GATE BIT(30)
|
||||
#define QM_SS_IO_CREG_MST0_CTRL_ADC_CLK_GATE BIT(31)
|
||||
/* SLV0_OBSR fields */
|
||||
#define QM_SS_ADC_CAL_VAL_GET_OFFSET (5)
|
||||
#define QM_SS_ADC_CAL_VAL_GET_MASK (0xFE0)
|
||||
#define QM_SS_ADC_CAL_ACK BIT(4)
|
||||
#define QM_SS_ADC_PWR_MODE_STS BIT(3)
|
||||
#define QM_SS_IO_CREG_SLV0_OBSR_ADC_CAL_VAL_OFFSET (5)
|
||||
#define QM_SS_IO_CREG_SLV0_OBSR_ADC_CAL_VAL_MASK (0xFE0)
|
||||
#define QM_SS_IO_CREG_SLV0_OBSR_ADC_CAL_ACK BIT(4)
|
||||
#define QM_SS_IO_CREG_SLV0_OBSR_ADC_PWR_MODE_STS BIT(3)
|
||||
|
||||
#define SS_CLK_PERIPH_ALL_IN_CREG \
|
||||
(SS_CLK_PERIPH_ADC | SS_CLK_PERIPH_I2C_1 | SS_CLK_PERIPH_I2C_0 | \
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#define HAS_4_TIMERS (1)
|
||||
#define HAS_AON_GPIO (1)
|
||||
#define HAS_MAILBOX (1)
|
||||
#define HAS_USB (1)
|
||||
|
||||
#if !defined(QM_SENSOR)
|
||||
#define HAS_APIC (1)
|
||||
|
@ -286,7 +287,7 @@ qm_lapic_reg_t test_lapic;
|
|||
* into IOAPIC. To trigger this manually we must write the vector number being
|
||||
* serviced into the IOAPIC EOI register.
|
||||
*/
|
||||
#if defined(ISR_HANDLED) || defined(QM_SENSOR)
|
||||
#if defined(ENABLE_EXTERNAL_ISR_HANDLING) || defined(QM_SENSOR)
|
||||
#define QM_ISR_EOI(vector)
|
||||
#else
|
||||
#define QM_ISR_EOI(vector) \
|
||||
|
@ -407,6 +408,8 @@ qm_scss_int_reg_t test_scss_int;
|
|||
#define QM_SCSS_INT ((qm_scss_int_reg_t *)QM_SCSS_INT_BASE)
|
||||
#endif
|
||||
|
||||
#define QM_INT_DMA_ERR_HOST_MASK (0x000000FF)
|
||||
#define QM_INT_DMA_ERR_SS_MASK (0x0000FF00)
|
||||
#define QM_INT_SRAM_CONTROLLER_HOST_HALT_MASK BIT(16)
|
||||
#define QM_INT_SRAM_CONTROLLER_HOST_MASK BIT(0)
|
||||
#define QM_INT_SRAM_CONTROLLER_SS_HALT_MASK BIT(24)
|
||||
|
@ -462,12 +465,12 @@ qm_scss_pmu_reg_t test_scss_pmu;
|
|||
#define QM_P_STS_HALT_INTERRUPT_REDIRECTION BIT(26)
|
||||
#define QM_P_STS_ARC_HALT BIT(14)
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Sensor Subsystem
|
||||
* @{
|
||||
*/
|
||||
#define QM_AON_VR_VSEL_MASK (0xFFE0)
|
||||
#define QM_AON_VR_VSEL_1V2 (0x8)
|
||||
#define QM_AON_VR_VSEL_1V35 (0xB)
|
||||
#define QM_AON_VR_VSEL_1V8 (0x10)
|
||||
#define QM_AON_VR_EN BIT(7)
|
||||
#define QM_AON_VR_VSTRB BIT(5)
|
||||
|
||||
#define QM_SCSS_SLP_CFG_LPMODE_EN BIT(8)
|
||||
#define QM_SCSS_SLP_CFG_RTC_DIS BIT(7)
|
||||
|
@ -482,6 +485,13 @@ qm_scss_pmu_reg_t test_scss_pmu;
|
|||
#define QM_SCSS_VR_EN BIT(7)
|
||||
#define QM_SCSS_VR_VREG_SEL BIT(6)
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Sensor Subsystem
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Sensor Subsystem register map. */
|
||||
typedef struct {
|
||||
QM_RW uint32_t ss_cfg; /**< Sensor Subsystem Configuration */
|
||||
|
@ -502,21 +512,14 @@ qm_scss_ss_reg_t test_scss_ss;
|
|||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Always-on controllers.
|
||||
* @name Always-on Counters.
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define QM_AON_VR_VSEL_MASK (0xFFE0)
|
||||
#define QM_AON_VR_VSEL_1V2 (0x8)
|
||||
#define QM_AON_VR_VSEL_1V35 (0xB)
|
||||
#define QM_AON_VR_VSEL_1V8 (0x10)
|
||||
#define QM_AON_VR_EN BIT(7)
|
||||
#define QM_AON_VR_VSTRB BIT(5)
|
||||
/** Number of Always-on counter controllers. */
|
||||
typedef enum { QM_AONC_0 = 0, QM_AONC_NUM } qm_aonc_t;
|
||||
|
||||
/** Number of SCSS Always-on controllers. */
|
||||
typedef enum { QM_SCSS_AON_0 = 0, QM_SCSS_AON_NUM } qm_scss_aon_t;
|
||||
|
||||
/** Always-on Controller register map. */
|
||||
/** Always-on Counter Controller register map. */
|
||||
typedef struct {
|
||||
QM_RW uint32_t aonc_cnt; /**< Always-on counter register. */
|
||||
QM_RW uint32_t aonc_cfg; /**< Always-on counter enable. */
|
||||
|
@ -526,15 +529,15 @@ typedef struct {
|
|||
QM_RW uint32_t aonpt_ctrl; /**< Always-on periodic timer control. */
|
||||
QM_RW uint32_t
|
||||
aonpt_cfg; /**< Always-on periodic timer configuration register. */
|
||||
} qm_scss_aon_reg_t;
|
||||
} qm_aonc_reg_t;
|
||||
|
||||
#if (UNIT_TEST)
|
||||
qm_scss_aon_reg_t test_scss_aon;
|
||||
#define QM_SCSS_AON ((qm_scss_aon_reg_t *)(&test_scss_aon))
|
||||
qm_aonc_reg_t test_aonc;
|
||||
#define QM_AONC ((qm_aonc_reg_t *)(&test_aonc))
|
||||
|
||||
#else
|
||||
#define QM_SCSS_AON_BASE (0xB0800700)
|
||||
#define QM_SCSS_AON ((qm_scss_aon_reg_t *)QM_SCSS_AON_BASE)
|
||||
#define QM_AONC_BASE (0xB0800700)
|
||||
#define QM_AONC ((qm_aonc_reg_t *)QM_AONC_BASE)
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
@ -625,7 +628,136 @@ qm_scss_info_reg_t test_scss_info;
|
|||
* @{
|
||||
*/
|
||||
|
||||
#define QM_MBOX_TRIGGER_CH_INT BIT(31)
|
||||
#define HAS_MAILBOX (1)
|
||||
#define NUM_MAILBOXES (8)
|
||||
|
||||
#define HAS_MAILBOX_LAKEMONT_DEST (1)
|
||||
#define HAS_MAILBOX_SENSOR_SUB_SYSTEM_DEST (1)
|
||||
|
||||
/**
|
||||
* Mailbox MBOX_CH_CTRL_N Mailbox Channel Control Word Register
|
||||
*
|
||||
* 31 RW/1S/V MBOX_CH_CTRL_INT Mailbox Channel Control Word interrupt
|
||||
* 30:0 RW MBOX_CH_CTRL Mailbox Channel Control Word
|
||||
*/
|
||||
#define QM_MBOX_CH_CTRL_INT BIT(31)
|
||||
#define QM_MBOX_CH_CTRL_MASK (0x7FFFFFFF)
|
||||
#define QM_MBOX_CH_CTRL_SHIFT (0)
|
||||
|
||||
/*
|
||||
* Mailbox Channel Status MBOX_CH_STS_N
|
||||
*
|
||||
* 31:2 RO reserved
|
||||
* 1 RW/1C/V MBOX_CH_STS_CTRL_INT Mailbox Channel Interrupt Status
|
||||
* - Bit set when message sent, indicates pending interrupt
|
||||
* - Bit set when a mailbox channel interrupt is pending..
|
||||
* - Bit cleared by writing 1
|
||||
* - Bit should be cleared by the receivers isr
|
||||
* 0 RW/1C/V MBOX_CH_STS Mailbox Channel Status
|
||||
* - Bit set when message sent, indicates pending data
|
||||
* - Bit cleared by writing 1
|
||||
* - Bit should be cleared by the receiver after
|
||||
* consuming the message.
|
||||
*/
|
||||
#define QM_MBOX_CH_STS_CTRL_INT BIT(1)
|
||||
#define QM_MBOX_CH_STS BIT(0)
|
||||
|
||||
#define QM_MBOX_STATUS_MASK (QM_MBOX_CH_STS | QM_MBOX_CH_STS_CTRL_INT)
|
||||
|
||||
/**
|
||||
* Mailbox MBOX_CHALL_STS Channel Status Bits Register
|
||||
*
|
||||
* 31:16 RO reserved
|
||||
* 15:0 RO/V MBOX_CHALL_STS Channel Status Bits
|
||||
*/
|
||||
#define QM_MBOX_CHALL_STS(N) BIT((N * 2))
|
||||
#define QM_MBOX_CHALL_INT_STS(N) BIT((N * 2) + 1)
|
||||
|
||||
/**
|
||||
* Mailbox interrupt routing mask register INT_MAILBOX_MASK
|
||||
*
|
||||
* There is only 1 Mailbox interrupt mask register.
|
||||
* The register contains masks for all 8 mailbox channels.
|
||||
*
|
||||
* Note that the Mailbox interrupt mask register does not follow
|
||||
* the same layout as most other interrupt mask registers in the SCSS.
|
||||
*
|
||||
* Mask bit positions for INT_MAILBOX_MASK are listed here:
|
||||
*
|
||||
* 31:24 RW/P/L INT_MAILBOX_SS_HALT_MASK Mailbox SS Halt interrupt mask
|
||||
* 23:16 RW/P/L INT_MAILBOX_HOST_HALT_MASK Mailbox Host Halt interrupt mask
|
||||
* 15:8 RW/P/L INT_MAILBOX_SS_MASK Mailbox SS interrupt mask
|
||||
* 7:0 RW/P/L INT_MAILBOX_HOST_MASK Mailbox Host interrupt mask
|
||||
*/
|
||||
#define QM_MBOX_SS_HALT_MASK_OFFSET (24)
|
||||
#define QM_MBOX_SS_HALT_MASK_MASK (0xFF000000)
|
||||
#define QM_MBOX_HOST_HALT_MASK_OFFSET (16)
|
||||
#define QM_MBOX_HOST_HALT_MASK_MASK (0x00FF0000)
|
||||
#define QM_MBOX_SS_MASK_OFFSET (8)
|
||||
#define QM_MBOX_SS_MASK_MASK (0x0000FF00)
|
||||
#define QM_MBOX_HOST_MASK_OFFSET (0)
|
||||
#define QM_MBOX_HOST_MASK_MASK (0x000000FF)
|
||||
|
||||
/**
|
||||
* Mailbox Interrupt Mask enable/disable definitions
|
||||
*
|
||||
* \#defines use the channel number to determine the register and bit shift to
|
||||
* use.
|
||||
* The interrupt destination adds an offset to the bit shift.
|
||||
*/
|
||||
#define QM_MBOX_ENABLE_LMT_INT_MASK(N) \
|
||||
QM_SCSS_INT->int_mailbox_mask &= ~(BIT(N + QM_MBOX_HOST_MASK_OFFSET))
|
||||
#define QM_MBOX_DISABLE_LMT_INT_MASK(N) \
|
||||
QM_SCSS_INT->int_mailbox_mask |= (BIT(N + QM_MBOX_HOST_MASK_OFFSET))
|
||||
#define QM_MBOX_ENABLE_SS_INT_MASK(N) \
|
||||
QM_SCSS_INT->int_mailbox_mask &= ~(BIT(N + QM_MBOX_SS_MASK_OFFSET))
|
||||
#define QM_MBOX_DISABLE_SS_INT_MASK(N) \
|
||||
QM_SCSS_INT->int_mailbox_mask |= (BIT(N + QM_MBOX_SS_MASK_OFFSET))
|
||||
|
||||
/**
|
||||
* Mailbox Interrupt Halt Mask enable/disable definitions
|
||||
*
|
||||
* \#defines use the channel number to determine the register and bit shift to
|
||||
* use.
|
||||
* The interrupt destination adds an offset to the bit shift,
|
||||
* see above for the bit position layout
|
||||
*/
|
||||
#define QM_MBOX_ENABLE_LMT_INT_HALT_MASK(N) \
|
||||
QM_SCSS_INT->int_mailbox_mask &= \
|
||||
~(BIT(N + QM_MBOX_HOST_HALT_MASK_OFFSET))
|
||||
#define QM_MBOX_DISABLE_LMT_INT_HALT_MASK(N) \
|
||||
QM_SCSS_INT->int_mailbox_mask |= \
|
||||
(BIT(N + QM_MBOX_HOST_HALT_MASK_OFFSET))
|
||||
#define QM_MBOX_ENABLE_SS_INT_HALT_MASK(N) \
|
||||
QM_SCSS_INT->int_mailbox_mask &= ~(BIT(N + QM_MBOX_SS_HALT_MASK_OFFSET))
|
||||
#define QM_MBOX_DISABLE_SS_INT_HALT_MASK(N) \
|
||||
QM_SCSS_INT->int_mailbox_mask |= (BIT(N + QM_MBOX_SS_HALT_MASK_OFFSET))
|
||||
|
||||
/**
|
||||
* Mailbox interrupt mask definitions to return the current mask values
|
||||
*/
|
||||
#define QM_MBOX_SS_INT_HALT_MASK \
|
||||
((QM_MBOX_SS_HALT_MASK_MASK & QM_SCSS_INT->int_mailbox_mask) >> \
|
||||
QM_MBOX_SS_HALT_MASK_OFFSET)
|
||||
#define QM_MBOX_LMT_INT_HALT_MASK \
|
||||
((QM_MBOX_HOST_HALT_MASK_MASK & QM_SCSS_INT->int_mailbox_mask) >> \
|
||||
QM_MBOX_SS_HALT_MASK_OFFSET)
|
||||
#define QM_MBOX_SS_INT_MASK \
|
||||
((QM_MBOX_SS_MASK_MASK & QM_SCSS_INT->int_mailbox_mask) >> \
|
||||
QM_MBOX_SS_MASK_OFFSET)
|
||||
#define QM_MBOX_LMT_INT_MASK \
|
||||
(QM_MBOX_HOST_MASK_MASK & QM_SCSS_INT->int_mailbox_mask)
|
||||
|
||||
/**
|
||||
* Mailbox interrupt macros to determine if the specified mailbox interrupt mask
|
||||
* has been locked.
|
||||
*/
|
||||
#define QM_MBOX_SS_INT_LOCK_HALT_MASK(N) \
|
||||
(QM_SCSS_INT->lock_int_mask_reg & BIT(3))
|
||||
#define QM_MBOX_LMT_INT_LOCK_HALT_MASK(N) \
|
||||
(QM_SCSS_INT->lock_int_mask_reg & BIT(2))
|
||||
#define QM_MBOX_SS_INT_LOCK_MASK(N) (QM_SCSS_INT->lock_int_mask_reg & BIT(1))
|
||||
#define QM_MBOX_LMT_INT_LOCK_MASK(N) (QM_SCSS_INT->lock_int_mask_reg & BIT(0))
|
||||
|
||||
/** Mailbox register structure. */
|
||||
typedef struct {
|
||||
|
@ -636,31 +768,21 @@ typedef struct {
|
|||
|
||||
/** Mailbox register map. */
|
||||
typedef struct {
|
||||
qm_mailbox_t mbox[8]; /**< 8 Mailboxes */
|
||||
QM_RW uint32_t mbox_chall_sts; /**< All channel status */
|
||||
} qm_scss_mailbox_reg_t;
|
||||
qm_mailbox_t mbox[NUM_MAILBOXES]; /**< 8 Mailboxes */
|
||||
QM_RW uint32_t mbox_chall_sts; /**< All channel status */
|
||||
} qm_mailbox_reg_t;
|
||||
|
||||
#if (UNIT_TEST)
|
||||
qm_scss_mailbox_reg_t test_scss_mailbox;
|
||||
#define QM_SCSS_MAILBOX ((qm_scss_mailbox_reg_t *)(&test_scss_mailbox))
|
||||
qm_mailbox_reg_t test_mailbox;
|
||||
#define QM_MAILBOX ((qm_mailbox_reg_t *)(&test_mailbox))
|
||||
|
||||
#else
|
||||
#define QM_SCSS_MAILBOX_BASE (0xB0800A00)
|
||||
#define QM_SCSS_MAILBOX ((qm_scss_mailbox_reg_t *)QM_SCSS_MAILBOX_BASE)
|
||||
#define QM_MAILBOX_BASE (0xB0800A00)
|
||||
#define QM_MAILBOX ((qm_mailbox_reg_t *)QM_MAILBOX_BASE)
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name USB
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** USB register base address. */
|
||||
#define QM_USB_BASE (0xB0500000)
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name IRQs and Interrupts
|
||||
* @{
|
||||
|
@ -824,11 +946,12 @@ typedef struct {
|
|||
typedef struct {
|
||||
qm_pwm_channel_t timer[QM_PWM_ID_NUM]; /**< 4 Timers */
|
||||
QM_RW uint32_t reserved[20];
|
||||
QM_RW uint32_t timersintstatus; /**< Timers Interrupt Status */
|
||||
QM_RW uint32_t timerseoi; /**< Timers End Of Interrupt */
|
||||
QM_RW uint32_t timersrawintstatus; /**< Timers Raw Interrupt Status */
|
||||
QM_RW uint32_t timerscompversion; /**< Timers Component Version */
|
||||
QM_RW uint32_t timer_loadcount2[4]; /**< Timer Load Count 2 */
|
||||
QM_RW uint32_t timersintstatus; /**< Timers Interrupt Status */
|
||||
QM_RW uint32_t timerseoi; /**< Timers End Of Interrupt */
|
||||
QM_RW uint32_t timersrawintstatus; /**< Timers Raw Interrupt Status */
|
||||
QM_RW uint32_t timerscompversion; /**< Timers Component Version */
|
||||
QM_RW uint32_t
|
||||
timer_loadcount2[QM_PWM_ID_NUM]; /**< Timer Load Count 2 */
|
||||
} qm_pwm_reg_t;
|
||||
|
||||
#if (UNIT_TEST)
|
||||
|
@ -842,7 +965,38 @@ qm_pwm_reg_t test_pwm_t;
|
|||
#define QM_PWM ((qm_pwm_reg_t *)QM_PWM_BASE)
|
||||
#endif
|
||||
|
||||
#define QM_PWM_INTERRUPT_MASK_OFFSET (2)
|
||||
#define PWM_START (1)
|
||||
|
||||
#define QM_PWM_CONF_MODE_MASK (0xA)
|
||||
#define QM_PWM_CONF_INT_EN_MASK (0x4)
|
||||
|
||||
#define QM_PWM_INTERRUPT_MASK_OFFSET (0x2)
|
||||
|
||||
/**
|
||||
* Timer N Control (TimerNControlReg)
|
||||
*
|
||||
* 31:4 RO reserved
|
||||
* 3 RW Timer PWM
|
||||
* 1 - PWM Mode
|
||||
* 0 - Timer Mode
|
||||
* 2 RW Timer Interrupt Mask, set to 1b to mask interrupt.
|
||||
* 1 RW Timer Mode
|
||||
* 1 - user-defined count mode
|
||||
* 0 - free-running mode
|
||||
* 0 RW Timer Enable
|
||||
* 0 - Disable PWM/Timer
|
||||
* 1 - Enable PWM/Timer
|
||||
*/
|
||||
|
||||
#define QM_PWM_TIMERNCONTROLREG_TIMER_ENABLE (BIT(0))
|
||||
#define QM_PWM_TIMERNCONTROLREG_TIMER_MODE (BIT(1))
|
||||
#define QM_PWM_TIMERNCONTROLREG_TIMER_INTERRUPT_MASK (BIT(2))
|
||||
#define QM_PWM_TIMERNCONTROLREG_TIMER_PWM (BIT(3))
|
||||
|
||||
#define QM_PWM_MODE_TIMER_FREE_RUNNING_VALUE (0)
|
||||
#define QM_PWM_MODE_TIMER_COUNT_VALUE (QM_PWM_TIMERNCONTROLREG_TIMER_MODE)
|
||||
#define QM_PWM_MODE_PWM_VALUE \
|
||||
(QM_PWM_TIMERNCONTROLREG_TIMER_PWM | QM_PWM_TIMERNCONTROLREG_TIMER_MODE)
|
||||
|
||||
/** @} */
|
||||
|
||||
|
@ -884,6 +1038,40 @@ qm_wdt_reg_t test_wdt;
|
|||
#define QM_WDT ((qm_wdt_reg_t *)QM_WDT_BASE)
|
||||
#endif
|
||||
|
||||
/* Watchdog enable. */
|
||||
#define QM_WDT_CR_WDT_ENABLE (BIT(0))
|
||||
/* Watchdog mode. */
|
||||
#define QM_WDT_CR_RMOD (BIT(1))
|
||||
/* Watchdog mode offset. */
|
||||
#define QM_WDT_CR_RMOD_OFFSET (1)
|
||||
/* Watchdog Timeout Mask. */
|
||||
#define QM_WDT_TORR_TOP_MASK (0xF)
|
||||
|
||||
/**
|
||||
* WDT timeout table (in clock cycles):
|
||||
* Each table entry corresponds with the value loaded
|
||||
* into the WDT at the time of a WDT reload for the
|
||||
* corresponding timeout range register value.
|
||||
*
|
||||
* TORR | Timeout (Clock Cycles)
|
||||
* 0. | 2^16 (65536)
|
||||
* 1. | 2^17 (131072)
|
||||
* 2. | 2^18 (262144)
|
||||
* 3. | 2^19 (524288)
|
||||
* 4. | 2^20 (1048576)
|
||||
* 5. | 2^21 (2097152)
|
||||
* 6. | 2^22 (4194304)
|
||||
* 7. | 2^23 (8388608)
|
||||
* 8. | 2^24 (16777216)
|
||||
* 9. | 2^25 (33554432)
|
||||
* 10. | 2^26 (67108864)
|
||||
* 11. | 2^27 (134217728)
|
||||
* 12. | 2^28 (268435456)
|
||||
* 13. | 2^29 (536870912)
|
||||
* 14. | 2^30 (1073741824)
|
||||
* 15. | 2^31 (2147483648)
|
||||
*/
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -891,6 +1079,104 @@ qm_wdt_reg_t test_wdt;
|
|||
* @{
|
||||
*/
|
||||
|
||||
/* Break character Bit. */
|
||||
#define QM_UART_LCR_BREAK BIT(6)
|
||||
/* Divisor Latch Access Bit. */
|
||||
#define QM_UART_LCR_DLAB BIT(7)
|
||||
|
||||
/* Request to Send Bit. */
|
||||
#define QM_UART_MCR_RTS BIT(1)
|
||||
/* Loopback Enable Bit. */
|
||||
#define QM_UART_MCR_LOOPBACK BIT(4)
|
||||
/* Auto Flow Control Enable Bit. */
|
||||
#define QM_UART_MCR_AFCE BIT(5)
|
||||
|
||||
/* FIFO Enable Bit. */
|
||||
#define QM_UART_FCR_FIFOE BIT(0)
|
||||
/* Reset Receive FIFO. */
|
||||
#define QM_UART_FCR_RFIFOR BIT(1)
|
||||
/* Reset Transmit FIFO. */
|
||||
#define QM_UART_FCR_XFIFOR BIT(2)
|
||||
|
||||
/* Default FIFO RX & TX Thresholds, half full for both. */
|
||||
#define QM_UART_FCR_DEFAULT_TX_RX_THRESHOLD (0xB0)
|
||||
/* Change TX Threshold to empty, keep RX Threshold to default. */
|
||||
#define QM_UART_FCR_TX_0_RX_1_2_THRESHOLD (0x80)
|
||||
|
||||
/* Transmit Holding Register Empty. */
|
||||
#define QM_UART_IIR_THR_EMPTY (0x02)
|
||||
/* Received Data Available. */
|
||||
#define QM_UART_IIR_RECV_DATA_AVAIL (0x04)
|
||||
/* Receiver Line Status. */
|
||||
#define QM_UART_IIR_RECV_LINE_STATUS (0x06)
|
||||
/* Character Timeout. */
|
||||
#define QM_UART_IIR_CHAR_TIMEOUT (0x0C)
|
||||
/* Interrupt ID Mask. */
|
||||
#define QM_UART_IIR_IID_MASK (0x0F)
|
||||
|
||||
/* Data Ready Bit. */
|
||||
#define QM_UART_LSR_DR BIT(0)
|
||||
/* Overflow Error Bit. */
|
||||
#define QM_UART_LSR_OE BIT(1)
|
||||
/* Parity Error Bit. */
|
||||
#define QM_UART_LSR_PE BIT(2)
|
||||
/* Framing Error Bit. */
|
||||
#define QM_UART_LSR_FE BIT(3)
|
||||
/* Break Interrupt Bit. */
|
||||
#define QM_UART_LSR_BI BIT(4)
|
||||
/* Transmit Holding Register Empty Bit. */
|
||||
#define QM_UART_LSR_THRE BIT(5)
|
||||
/* Transmitter Empty Bit. */
|
||||
#define QM_UART_LSR_TEMT BIT(6)
|
||||
/* Receiver FIFO Error Bit. */
|
||||
#define QM_UART_LSR_RFE BIT(7)
|
||||
|
||||
/* Enable Received Data Available Interrupt. */
|
||||
#define QM_UART_IER_ERBFI BIT(0)
|
||||
/* Enable Transmit Holding Register Empty Interrupt. */
|
||||
#define QM_UART_IER_ETBEI BIT(1)
|
||||
/* Enable Receiver Line Status Interrupt. */
|
||||
#define QM_UART_IER_ELSI BIT(2)
|
||||
/* Programmable THRE Interrupt Mode. */
|
||||
#define QM_UART_IER_PTIME BIT(7)
|
||||
|
||||
/* Line Status Errors. */
|
||||
#define QM_UART_LSR_ERROR_BITS \
|
||||
(QM_UART_LSR_OE | QM_UART_LSR_PE | QM_UART_LSR_FE | QM_UART_LSR_BI)
|
||||
|
||||
/* FIFO Depth. */
|
||||
#define QM_UART_FIFO_DEPTH (16)
|
||||
/* FIFO Half Depth. */
|
||||
#define QM_UART_FIFO_HALF_DEPTH (QM_UART_FIFO_DEPTH / 2)
|
||||
|
||||
/* Divisor Latch High Offset. */
|
||||
#define QM_UART_CFG_BAUD_DLH_OFFS 16
|
||||
/* Divisor Latch Low Offset. */
|
||||
#define QM_UART_CFG_BAUD_DLL_OFFS 8
|
||||
/* Divisor Latch Fraction Offset. */
|
||||
#define QM_UART_CFG_BAUD_DLF_OFFS 0
|
||||
/* Divisor Latch High Mask. */
|
||||
#define QM_UART_CFG_BAUD_DLH_MASK (0xFF << QM_UART_CFG_BAUD_DLH_OFFS)
|
||||
/* Divisor Latch Low Mask. */
|
||||
#define QM_UART_CFG_BAUD_DLL_MASK (0xFF << QM_UART_CFG_BAUD_DLL_OFFS)
|
||||
/* Divisor Latch Fraction Mask. */
|
||||
#define QM_UART_CFG_BAUD_DLF_MASK (0xFF << QM_UART_CFG_BAUD_DLF_OFFS)
|
||||
|
||||
/* Divisor Latch Packing Helper. */
|
||||
#define QM_UART_CFG_BAUD_DL_PACK(dlh, dll, dlf) \
|
||||
(dlh << QM_UART_CFG_BAUD_DLH_OFFS | dll << QM_UART_CFG_BAUD_DLL_OFFS | \
|
||||
dlf << QM_UART_CFG_BAUD_DLF_OFFS)
|
||||
|
||||
/* Divisor Latch High Unpacking Helper. */
|
||||
#define QM_UART_CFG_BAUD_DLH_UNPACK(packed) \
|
||||
((packed & QM_UART_CFG_BAUD_DLH_MASK) >> QM_UART_CFG_BAUD_DLH_OFFS)
|
||||
/* Divisor Latch Low Unpacking Helper. */
|
||||
#define QM_UART_CFG_BAUD_DLL_UNPACK(packed) \
|
||||
((packed & QM_UART_CFG_BAUD_DLL_MASK) >> QM_UART_CFG_BAUD_DLL_OFFS)
|
||||
/* Divisor Latch Fraction Unpacking Helper. */
|
||||
#define QM_UART_CFG_BAUD_DLF_UNPACK(packed) \
|
||||
((packed & QM_UART_CFG_BAUD_DLF_MASK) >> QM_UART_CFG_BAUD_DLF_OFFS)
|
||||
|
||||
/** Number of UART controllers. */
|
||||
typedef enum { QM_UART_0 = 0, QM_UART_1, QM_UART_NUM } qm_uart_t;
|
||||
|
||||
|
@ -935,13 +1221,8 @@ extern qm_uart_reg_t *qm_uart[QM_UART_NUM];
|
|||
* @{
|
||||
*/
|
||||
|
||||
/** Number of SPI controllers. */
|
||||
typedef enum {
|
||||
QM_SPI_MST_0 = 0,
|
||||
QM_SPI_MST_1,
|
||||
QM_SPI_SLV_0,
|
||||
QM_SPI_NUM
|
||||
} qm_spi_t;
|
||||
/** Number of SPI controllers (only master driver available). */
|
||||
typedef enum { QM_SPI_MST_0 = 0, QM_SPI_MST_1, QM_SPI_NUM } qm_spi_t;
|
||||
|
||||
/** SPI register map. */
|
||||
typedef struct {
|
||||
|
@ -1059,6 +1340,10 @@ typedef struct {
|
|||
QM_RW uint32_t rtc_comp_version; /**< End of Interrupt Register */
|
||||
} qm_rtc_reg_t;
|
||||
|
||||
#define QM_RTC_CCR_INTERRUPT_ENABLE BIT(0)
|
||||
#define QM_RTC_CCR_INTERRUPT_MASK BIT(1)
|
||||
#define QM_RTC_CCR_ENABLE BIT(2)
|
||||
|
||||
#if (UNIT_TEST)
|
||||
qm_rtc_reg_t test_rtc;
|
||||
#define QM_RTC ((qm_rtc_reg_t *)(&test_rtc))
|
||||
|
@ -1272,19 +1557,17 @@ typedef enum { QM_FLASH_0 = 0, QM_FLASH_1, QM_FLASH_NUM } qm_flash_t;
|
|||
|
||||
/** Flash register map. */
|
||||
typedef struct {
|
||||
QM_RW uint32_t tmg_ctrl; /**< TMG_CTRL */
|
||||
QM_RW uint32_t rom_wr_ctrl; /**< ROM_WR_CTRL */
|
||||
QM_RW uint32_t rom_wr_data; /**< ROM_WR_DATA */
|
||||
QM_RW uint32_t flash_wr_ctrl; /**< FLASH_WR_CTRL */
|
||||
QM_RW uint32_t flash_wr_data; /**< FLASH_WR_DATA */
|
||||
QM_RW uint32_t flash_stts; /**< FLASH_STTS */
|
||||
QM_RW uint32_t ctrl; /**< CTRL */
|
||||
QM_RW uint32_t fpr_rd_cfg[4]; /**< 4 FPR_RD_CFG registers */
|
||||
QM_RW uint32_t tmg_ctrl; /**< TMG_CTRL. */
|
||||
QM_RW uint32_t rom_wr_ctrl; /**< ROM_WR_CTRL. */
|
||||
QM_RW uint32_t rom_wr_data; /**< ROM_WR_DATA. */
|
||||
QM_RW uint32_t flash_wr_ctrl; /**< FLASH_WR_CTRL. */
|
||||
QM_RW uint32_t flash_wr_data; /**< FLASH_WR_DATA. */
|
||||
QM_RW uint32_t flash_stts; /**< FLASH_STTS. */
|
||||
QM_RW uint32_t ctrl; /**< CTRL. */
|
||||
QM_RW uint32_t fpr_rd_cfg[4]; /**< 4 FPR_RD_CFG registers. */
|
||||
QM_RW uint32_t
|
||||
mpr_wr_cfg; /**< Flash Write Protection Control Register */
|
||||
QM_RW uint32_t mpr_vsts; /**< Protection Status Register */
|
||||
QM_RW uint32_t mpr_vdata; /**< MPR Violation Data Value Register */
|
||||
QM_RW uint32_t padding[0x3FFF2]; /* (0x100000 - 0x38) / 4 */
|
||||
mpr_wr_cfg; /**< Flash Write Protection Control Register. */
|
||||
QM_RW uint32_t mpr_vsts; /**< Protection Status Register. */
|
||||
} qm_flash_reg_t;
|
||||
|
||||
#if (UNIT_TEST)
|
||||
|
@ -1329,6 +1612,46 @@ extern qm_flash_reg_t *qm_flash[QM_FLASH_NUM];
|
|||
#define QM_FLASH_CLK_SLOW BIT(14)
|
||||
#define QM_FLASH_LVE_MODE BIT(5)
|
||||
|
||||
/* Flash mask to clear timing. */
|
||||
#define QM_FLASH_TMG_DEF_MASK (0xFFFFFC00)
|
||||
/* Flash mask to clear micro seconds. */
|
||||
#define QM_FLASH_MICRO_SEC_COUNT_MASK (0x3F)
|
||||
/* Flash mask to clear wait state. */
|
||||
#define QM_FLASH_WAIT_STATE_MASK (0x3C0)
|
||||
/* Flash wait state offset bit. */
|
||||
#define QM_FLASH_WAIT_STATE_OFFSET (6)
|
||||
/* Flash write disable offset bit. */
|
||||
#define QM_FLASH_WRITE_DISABLE_OFFSET (4)
|
||||
/* Flash write disable value. */
|
||||
#define QM_FLASH_WRITE_DISABLE_VAL BIT(4)
|
||||
|
||||
/* Flash page erase request. */
|
||||
#define ER_REQ BIT(1)
|
||||
/* Flash page erase done. */
|
||||
#define ER_DONE (1)
|
||||
/* Flash page write request. */
|
||||
#define WR_REQ (1)
|
||||
/* Flash page write done. */
|
||||
#define WR_DONE BIT(1)
|
||||
|
||||
/* Flash write address offset. */
|
||||
#define WR_ADDR_OFFSET (2)
|
||||
/* Flash perform mass erase includes OTP region. */
|
||||
#define MASS_ERASE_INFO BIT(6)
|
||||
/* Flash perform mass erase. */
|
||||
#define MASS_ERASE BIT(7)
|
||||
|
||||
#define QM_FLASH_ADDRESS_MASK (0x7FF)
|
||||
/* Increment by 4 bytes each time, but there is an offset of 2, so 0x10. */
|
||||
#define QM_FLASH_ADDR_INC (0x10)
|
||||
|
||||
/* Flash page size in dwords. */
|
||||
#define QM_FLASH_PAGE_SIZE_DWORDS (0x200)
|
||||
/* Flash page size in bytes. */
|
||||
#define QM_FLASH_PAGE_SIZE_BYTES (0x800)
|
||||
/* Flash page size in bits. */
|
||||
#define QM_FLASH_PAGE_SIZE_BITS (11)
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -1522,6 +1845,10 @@ typedef struct {
|
|||
#define QM_DMA_CFG_L_SRC_HS_POL_MASK BIT(QM_DMA_CFG_L_SRC_HS_POL_OFFSET)
|
||||
#define QM_DMA_CFG_L_RELOAD_SRC_MASK BIT(30)
|
||||
#define QM_DMA_CFG_L_RELOAD_DST_MASK BIT(31)
|
||||
#define QM_DMA_CFG_H_DS_UPD_EN_OFFSET (5)
|
||||
#define QM_DMA_CFG_H_DS_UPD_EN_MASK BIT(QM_DMA_CFG_H_DS_UPD_EN_OFFSET)
|
||||
#define QM_DMA_CFG_H_SS_UPD_EN_OFFSET (6)
|
||||
#define QM_DMA_CFG_H_SS_UPD_EN_MASK BIT(QM_DMA_CFG_H_SS_UPD_EN_OFFSET)
|
||||
#define QM_DMA_CFG_H_SRC_PER_OFFSET (7)
|
||||
#define QM_DMA_CFG_H_SRC_PER_MASK (0xf << QM_DMA_CFG_H_SRC_PER_OFFSET)
|
||||
#define QM_DMA_CFG_H_DEST_PER_OFFSET (11)
|
||||
|
@ -1575,6 +1902,7 @@ typedef struct {
|
|||
|
||||
/* DMA interrupt status register bits. */
|
||||
#define QM_DMA_INT_STATUS_TFR BIT(0)
|
||||
#define QM_DMA_INT_STATUS_BLOCK BIT(1)
|
||||
#define QM_DMA_INT_STATUS_ERR BIT(4)
|
||||
|
||||
/** DMA miscellaneous register map. */
|
||||
|
@ -1620,16 +1948,125 @@ extern qm_dma_reg_t *qm_dma[QM_DMA_NUM];
|
|||
* @{
|
||||
*/
|
||||
|
||||
/* USB PLL enable bit*/
|
||||
#define QM_USB_PLL_PDLD BIT(0)
|
||||
/* USB PLL has locked when this bit is 1*/
|
||||
#define QM_USB_PLL_LOCK BIT(14)
|
||||
/* Default values to setup the USB PLL*/
|
||||
#define QM_USB_PLL_CFG0_DEFAULT (0x00001904)
|
||||
/* USB PLL register*/
|
||||
#define QM_USB_PLL_CFG0 (REG_VAL(0xB0800014))
|
||||
#define QM_USB_EP_DIR_IN_MASK (0x80)
|
||||
#define QM_USB_IN_EP_NUM (6)
|
||||
#define QM_USB_OUT_EP_NUM (4)
|
||||
#define QM_USB_MAX_PACKET_SIZE (64)
|
||||
|
||||
/* USB clock enable bit*/
|
||||
/** Number of USB controllers. */
|
||||
typedef enum { QM_USB_0 = 0, QM_USB_NUM } qm_usb_t;
|
||||
|
||||
typedef enum {
|
||||
QM_USB_IN_EP_0 = 0,
|
||||
QM_USB_IN_EP_1 = 1,
|
||||
QM_USB_IN_EP_2 = 2,
|
||||
QM_USB_IN_EP_3 = 3,
|
||||
QM_USB_IN_EP_4 = 4,
|
||||
QM_USB_IN_EP_5 = 5,
|
||||
QM_USB_OUT_EP_0 = 6,
|
||||
QM_USB_OUT_EP_1 = 7,
|
||||
QM_USB_OUT_EP_2 = 8,
|
||||
QM_USB_OUT_EP_3 = 9
|
||||
} qm_usb_ep_idx_t;
|
||||
|
||||
/** USB register map. */
|
||||
|
||||
/** IN Endpoint Registers. */
|
||||
typedef struct {
|
||||
QM_RW uint32_t diepctl;
|
||||
QM_R uint32_t reserved;
|
||||
QM_RW uint32_t diepint;
|
||||
QM_R uint32_t reserved1;
|
||||
QM_RW uint32_t dieptsiz;
|
||||
QM_RW uint32_t diepdma;
|
||||
QM_RW uint32_t dtxfsts;
|
||||
QM_R uint32_t reserved2;
|
||||
} qm_usb_in_ep_reg_t;
|
||||
|
||||
/** OUT Endpoint Registers. */
|
||||
typedef struct {
|
||||
QM_RW uint32_t doepctl;
|
||||
QM_R uint32_t reserved;
|
||||
QM_RW uint32_t doepint;
|
||||
QM_R uint32_t reserved1;
|
||||
QM_RW uint32_t doeptsiz;
|
||||
QM_RW uint32_t doepdma;
|
||||
QM_R uint32_t reserved2[2];
|
||||
} qm_usb_out_ep_reg_t;
|
||||
|
||||
/**
|
||||
* USB Register block type.
|
||||
*/
|
||||
typedef struct {
|
||||
QM_RW uint32_t gotgctl; /**< OTG Control. */
|
||||
QM_RW uint32_t gotgint; /**< OTG Interrupt. */
|
||||
QM_RW uint32_t gahbcfg; /**< AHB Configuration. */
|
||||
QM_RW uint32_t gusbcfg; /**< USB Configuration. */
|
||||
QM_RW uint32_t grstctl; /**< Reset Register. */
|
||||
QM_RW uint32_t gintsts; /**< Interrupt Status. */
|
||||
QM_RW uint32_t gintmsk; /**< Interrupt Mask. */
|
||||
QM_R uint32_t grxstsr; /**< Receive Status Read/Pop. */
|
||||
QM_R uint32_t grxstsp; /**< Receive Status Read/Pop. */
|
||||
QM_R uint32_t grxfsiz; /**< Receive FIFO Size. */
|
||||
QM_R uint32_t gnptxfsiz; /**< Non-periodic Transmit FIFO Size. */
|
||||
QM_R uint32_t reserved[5];
|
||||
QM_R uint32_t gsnpsid; /**< Synopsys ID. */
|
||||
QM_R uint32_t ghwcfg1; /**< HW config - Endpoint direction. */
|
||||
QM_R uint32_t ghwcfg2; /**< HW config 2. */
|
||||
QM_R uint32_t ghwcfg3; /**< HW config 3. */
|
||||
QM_R uint32_t ghwcfg4; /**< HW config 4. */
|
||||
QM_RW uint32_t gdfifocfg; /**< Global DFIFO Configuration. */
|
||||
QM_R uint32_t reserved1[43];
|
||||
QM_RW uint32_t dieptxf1;
|
||||
QM_RW uint32_t dieptxf2;
|
||||
QM_RW uint32_t dieptxf3;
|
||||
QM_RW uint32_t dieptxf4;
|
||||
QM_RW uint32_t dieptxf5;
|
||||
QM_R uint32_t reserved2[442];
|
||||
QM_RW uint32_t dcfg; /**< Device config. */
|
||||
QM_RW uint32_t dctl; /**< Device control. */
|
||||
QM_RW uint32_t dsts; /**< Device Status. */
|
||||
QM_R uint32_t reserved3;
|
||||
QM_RW uint32_t diepmsk; /**< IN EP Common Interrupt Mask. */
|
||||
QM_RW uint32_t doepmsk; /**< OUT EP Common Interrupt Mask. */
|
||||
QM_R uint32_t daint; /**< Device Interrupt Register. */
|
||||
QM_RW uint32_t daintmsk; /**< Device Interrupt Mask Register. */
|
||||
QM_R uint32_t reserved4[2];
|
||||
QM_RW uint32_t dvbusdis; /**< VBUS discharge time register. */
|
||||
QM_RW uint32_t dvbuspulse; /**< Device VBUS discharge time. */
|
||||
QM_RW uint32_t dthrctl; /**< Device Threshold Ctrl. */
|
||||
QM_RW uint32_t diepempmsk; /**< IN EP FIFO Empty Intr Mask. */
|
||||
QM_R uint32_t reserved5[50];
|
||||
qm_usb_in_ep_reg_t in_ep_reg[QM_USB_IN_EP_NUM];
|
||||
QM_R uint32_t reserved6[80];
|
||||
qm_usb_out_ep_reg_t out_ep_reg[QM_USB_OUT_EP_NUM];
|
||||
} qm_usb_reg_t;
|
||||
|
||||
#if (UNIT_TEST)
|
||||
qm_usb_reg_t test_usb;
|
||||
#define QM_USB ((qm_usb_reg_t *)(&test_usb))
|
||||
#else
|
||||
#define QM_USB_0_BASE (0xB0500000)
|
||||
/* USB controller base address */
|
||||
#define QM_USB ((qm_usb_reg_t *)QM_USB_0_BASE)
|
||||
#endif
|
||||
|
||||
/* USB PLL enable bit */
|
||||
#define QM_USB_PLL_PDLD BIT(0)
|
||||
/* USB PLL has locked when this bit is 1 */
|
||||
#define QM_USB_PLL_LOCK BIT(14)
|
||||
/* Default values to setup the USB PLL */
|
||||
#define QM_USB_PLL_CFG0_DEFAULT (0x00001904)
|
||||
|
||||
/* USB PLL register */
|
||||
#if (UNIT_TEST)
|
||||
uint32_t test_usb_pll;
|
||||
#define QM_USB_PLL_CFG0 (test_usb_pll)
|
||||
#else
|
||||
#define QM_USB_PLL_CFG0 (REG_VAL(0xB0800014))
|
||||
#endif
|
||||
|
||||
/* USB clock enable bit */
|
||||
#define QM_CCU_USB_CLK_EN BIT(1)
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -27,46 +27,32 @@
|
|||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __RAR_H__
|
||||
#define __RAR_H__
|
||||
#ifndef __SS_INIT_H__
|
||||
#define __SS_INIT_H__
|
||||
|
||||
#include "qm_common.h"
|
||||
#include "qm_soc_regs.h"
|
||||
|
||||
#if (HAS_RAR)
|
||||
/**
|
||||
* Retention alternator regulator for Quark D2000.
|
||||
* Sensor Subsystem initialisation.
|
||||
*
|
||||
* @defgroup groupRAR RAR
|
||||
* @defgroup groupSSINIT Quark SE Sensor Subsystem Initialisation
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* RAR modes type.
|
||||
* Initialise the sensor subsystem.
|
||||
*
|
||||
* Set the ARC reset vector with the sensor subsystem application entry point
|
||||
* address. Then, instruct the ARC to start running.
|
||||
* Note: This function is only intended to be called from the Lakemont core.
|
||||
*
|
||||
* @return void.
|
||||
*/
|
||||
typedef enum {
|
||||
RAR_NORMAL, /**< Normal mode = 50 mA. */
|
||||
RAR_RETENTION /**< Retention mode = 300 uA. */
|
||||
} rar_state_t;
|
||||
|
||||
/**
|
||||
* Change operating mode of RAR.
|
||||
*
|
||||
* Normal mode is able to source up to 50 mA.
|
||||
* Retention mode is able to source up to 300 uA.
|
||||
* Care must be taken when entering into retention mode
|
||||
* to ensure the overall system draw is less than 300 uA.
|
||||
*
|
||||
* @param[in] mode Operating mode of the RAR.
|
||||
*
|
||||
* @return Standard errno return type for QMSI.
|
||||
* @retval 0 on success.
|
||||
* @retval Negative @ref errno for possible error codes.
|
||||
*/
|
||||
int rar_set_mode(const rar_state_t mode);
|
||||
void sensor_activation(void);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
#endif /* HAS_RAR */
|
||||
#endif /* __RAR_H__ */
|
||||
|
||||
#endif /* __SS_INIT_H__ */
|
Loading…
Reference in a new issue