/* Private Functions */ static void spi_disable(const qm_ss_spi_t spi) { /* Disable SPI device */ QM_SS_REG_AUX_NAND(base[spi] + QM_SS_SPI_SPIEN, QM_SS_SPI_SPIEN_EN); /* MASK all interrupts. */ __builtin_arc_sr(0, base[spi] + QM_SS_SPI_INTR_MASK); /* Clear all interrupts */ __builtin_arc_sr(QM_SS_SPI_INTR_ALL, base[spi] + QM_SS_SPI_CLR_INTR); }
static uint32_t switch_rtc_to_level(void) { uint32_t prev_trigger; /* The sensor cannot be woken up with an edge triggered * interrupt from the RTC and the AON Counter. * Switch to Level triggered interrupts and restore * the setting when waking up. */ __builtin_arc_sr(QM_IRQ_RTC_0_INT_VECTOR, QM_SS_AUX_IRQ_SELECT); prev_trigger = __builtin_arc_lr(QM_SS_AUX_IRQ_TRIGGER); __builtin_arc_sr(QM_SS_IRQ_LEVEL_SENSITIVE, QM_SS_AUX_IRQ_TRIGGER); return prev_trigger; }
int qm_ss_spi_irq_transfer(const qm_ss_spi_t spi, const qm_ss_spi_async_transfer_t *const xfer) { QM_CHECK(spi < QM_SS_SPI_NUM, -EINVAL); QM_CHECK(xfer, -EINVAL); /* Load and save initial control register */ uint32_t ctrl = __builtin_arc_lr(base[spi] + QM_SS_SPI_CTRL); uint8_t tmode = (uint8_t)((ctrl & QM_SS_SPI_CTRL_TMOD_MASK) >> QM_SS_SPI_CTRL_TMOD_OFFS); uint8_t bytes = BYTES_PER_FRAME(ctrl); QM_CHECK(tmode == QM_SS_SPI_TMOD_TX_RX ? (xfer->tx_len == xfer->rx_len) : 1, -EINVAL); spi_async_transfer[spi] = xfer; tx_c[spi] = xfer->tx_len; rx_c[spi] = xfer->rx_len; /* Set NDF (Number of Data Frames) in RX or EEPROM Read mode. (-1) */ if (tmode == QM_SS_SPI_TMOD_RX || tmode == QM_SS_SPI_TMOD_EEPROM_READ) { ctrl &= ~QM_SS_SPI_CTRL_NDF_MASK; ctrl |= ((xfer->rx_len - 1) << QM_SS_SPI_CTRL_NDF_OFFS) & QM_SS_SPI_CTRL_NDF_MASK; __builtin_arc_sr(ctrl, base[spi] + QM_SS_SPI_CTRL); } uint32_t ftlr = (((FIFO_RX_W_MARK < xfer->rx_len ? FIFO_RX_W_MARK : xfer->rx_len) - 1) << QM_SS_SPI_FTLR_RFT_OFFS) & QM_SS_SPI_FTLR_RFT_MASK; __builtin_arc_sr(ftlr, base[spi] + QM_SS_SPI_FTLR); /* Unmask all interrupts */ __builtin_arc_sr(QM_SS_SPI_INTR_ALL, base[spi] + QM_SS_SPI_INTR_MASK); /* Enable SPI device */ QM_SS_REG_AUX_OR(base[spi] + QM_SS_SPI_SPIEN, QM_SS_SPI_SPIEN_EN); /* RX only transfers need a dummy frame byte to be sent. */ if (tmode == QM_SS_SPI_TMOD_RX) { fifo_write(spi, (uint8_t *)&dummy_frame, bytes); } return 0; }
static void ss_gpio_interrupt_example(void) { uint32_t i; QM_PUTS("Starting: SS GPIO interrupt"); /* Enable clock to interrupt controller. */ __builtin_arc_sr(BIT(31) + BIT(0), QM_SS_GPIO_0_BASE + QM_SS_GPIO_LS_SYNC); /* Set SS GPIO pin 2 as OUTPUT. */ __builtin_arc_sr(BIT(2), QM_SS_GPIO_0_BASE + QM_SS_GPIO_SWPORTA_DDR); /* Register the SS GPIO interrupt. */ QM_IR_UNMASK_INTERRUPTS(QM_INTERRUPT_ROUTER->ss_gpio_0_int_mask); qm_ss_irq_request(QM_SS_IRQ_GPIO_0_INT, ss_gpio_interrupt_isr); /* Set the bit 3 to rising edge-sensitive. */ __builtin_arc_sr(BIT(3), QM_SS_GPIO_0_BASE + QM_SS_GPIO_INTTYPE_LEVEL); /* Unmask SS GPIO pin 3 interrupt only. */ __builtin_arc_sr(~BIT(3), QM_SS_GPIO_0_BASE + QM_SS_GPIO_INTMASK); /* Clear SS GPIO interrupt requests. */ __builtin_arc_sr(BIT(3), QM_SS_GPIO_0_BASE + QM_SS_GPIO_PORTA_EOI); /* Enable SS GPIO interrupt. */ __builtin_arc_sr(BIT(3), QM_SS_GPIO_0_BASE + QM_SS_GPIO_INTEN); for (i = 0; i < NUM_LOOPS; i++) { /* * Toggle the SS GPIO 2, will trigger the interrupt on SS * GPIO 3. */ clk_sys_udelay(DELAY); __builtin_arc_sr(BIT(2), QM_SS_GPIO_0_BASE + QM_SS_GPIO_SWPORTA_DR); QM_GPIO[0]->gpio_swporta_dr |= BIT(LED_BIT); clk_sys_udelay(DELAY); __builtin_arc_sr(0, QM_SS_GPIO_0_BASE + QM_SS_GPIO_SWPORTA_DR); QM_GPIO[0]->gpio_swporta_dr &= ~BIT(LED_BIT); } /* Unmask all SS GPIO interrupts. */ __builtin_arc_sr(0xff, QM_SS_GPIO_0_BASE + QM_SS_GPIO_INTMASK); if (counter == NUM_LOOPS) { QM_PUTS("Success"); } else { QM_PUTS("Error: Check are pins 14 and 16 on J14 connector " "short connected?"); } QM_PUTS("Finished: SS GPIO interrupt"); }
static __inline__ void fifo_read(const qm_ss_spi_t spi, void *data, uint8_t size) { __builtin_arc_sr(QM_SS_SPI_DR_R_MASK, base[spi] + QM_SS_SPI_DR); if (size == 1) { *(uint8_t *)data = __builtin_arc_lr(base[spi] + QM_SS_SPI_DR); } else { *(uint16_t *)data = __builtin_arc_lr(base[spi] + QM_SS_SPI_DR); } }
/* Public Functions */ int qm_ss_spi_set_config(const qm_ss_spi_t spi, const qm_ss_spi_config_t *const cfg) { 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); uint32_t ctrl = __builtin_arc_lr(QM_SS_SPI_0_BASE + QM_SS_SPI_CTRL); ctrl &= QM_SS_SPI_CTRL_CLK_ENA; ctrl |= cfg->frame_size << QM_SS_SPI_CTRL_DFS_OFFS; ctrl |= cfg->transfer_mode << QM_SS_SPI_CTRL_TMOD_OFFS; ctrl |= cfg->bus_mode << QM_SS_SPI_CTRL_BMOD_OFFS; __builtin_arc_sr(ctrl, base[spi] + QM_SS_SPI_CTRL); __builtin_arc_sr(cfg->clk_divider, base[spi] + QM_SS_SPI_TIMING); return 0; }
int qm_ss_spi_irq_transfer(const qm_ss_spi_t spi, const qm_ss_spi_async_transfer_t *const xfer) { QM_CHECK(spi < QM_SS_SPI_NUM, -EINVAL); QM_CHECK(xfer, -EINVAL); /* Load and save initial control register */ uint32_t ctrl = __builtin_arc_lr(base[spi] + QM_SS_SPI_CTRL); uint8_t tmode = (uint8_t)((ctrl & QM_SS_SPI_CTRL_TMOD_MASK) >> QM_SS_SPI_CTRL_TMOD_OFFS); QM_CHECK(tmode == QM_SS_SPI_TMOD_TX_RX ? (xfer->tx_len == xfer->rx_len) : 1, -EINVAL); transfer[spi] = xfer; tx_c[spi] = xfer->tx_len; rx_c[spi] = xfer->rx_len; tx_p[spi] = xfer->tx; rx_p[spi] = xfer->rx; /* RX only transfers need a dummy frame byte to be sent. */ if (tmode == QM_SS_SPI_TMOD_RX) { tx_p[spi] = (uint8_t *)&dummy_frame; tx_c[spi] = 1; } uint32_t ftlr = (((FIFO_RX_W_MARK < xfer->rx_len ? FIFO_RX_W_MARK : xfer->rx_len) - 1) << QM_SS_SPI_FTLR_RFT_OFFS) & QM_SS_SPI_FTLR_RFT_MASK; __builtin_arc_sr(ftlr, base[spi] + QM_SS_SPI_FTLR); /* Unmask all interrupts */ __builtin_arc_sr(QM_SS_SPI_INTR_ALL, base[spi] + QM_SS_SPI_INTR_MASK); /* Enable SPI device */ QM_SS_REG_AUX_OR(base[spi] + QM_SS_SPI_SPIEN, QM_SS_SPI_SPIEN_EN); return 0; }
static __inline__ void fifo_write(const qm_ss_spi_t spi, void *data, uint8_t size) { uint32_t dr; if (size == 1) { dr = *(uint8_t *)data; } else { dr = *(uint16_t *)data; } dr |= QM_SS_SPI_DR_W_MASK; __builtin_arc_sr(dr, base[spi] + QM_SS_SPI_DR); }
int qm_ss_spi_slave_select(const qm_ss_spi_t spi, const qm_ss_spi_slave_select_t ss) { 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)); uint32_t spien = __builtin_arc_lr(base[spi] + QM_SS_SPI_SPIEN); spien &= ~QM_SS_SPI_SPIEN_SER_MASK; spien |= (ss << QM_SS_SPI_SPIEN_SER_OFFS); __builtin_arc_sr(spien, base[spi] + QM_SS_SPI_SPIEN); return 0; }
static void ss_sw_triggered_interrupt_example(void) { uint32_t i; QM_PUTS("Starting: SW triggered interrupt"); qm_irq_request(QM_IRQ_I2C_1_INT, sw_interrupt_isr); QM_GPIO[0]->gpio_swporta_ddr |= BIT(LED_BIT); for (i = 0; i < NUM_LOOPS; i++) { QM_GPIO[0]->gpio_swporta_dr |= BIT(LED_BIT); clk_sys_udelay(DELAY); QM_GPIO[0]->gpio_swporta_dr &= ~BIT(LED_BIT); clk_sys_udelay(DELAY); /* SW mainpulated interrupt trigger, triggers I2C_1. */ __builtin_arc_sr(QM_IRQ_I2C_1_INT_VECTOR, QM_SS_AUX_IRQ_HINT); } if (counter == NUM_LOOPS) { QM_PUTS("Success"); } else { QM_PUTS("Error: SW interrupt didn't fire correctly"); } QM_PUTS("Finished: SW triggered interrupt"); }
int qm_ss_spi_transfer(const qm_ss_spi_t spi, const qm_ss_spi_transfer_t *const xfer, qm_ss_spi_status_t *const status) { QM_CHECK(spi < QM_SS_SPI_NUM, -EINVAL); QM_CHECK(xfer, -EINVAL); uint32_t ctrl = __builtin_arc_lr(base[spi] + QM_SS_SPI_CTRL); uint8_t tmode = (uint8_t)((ctrl & QM_SS_SPI_CTRL_TMOD_MASK) >> QM_SS_SPI_CTRL_TMOD_OFFS); QM_CHECK(tmode == QM_SS_SPI_TMOD_TX_RX ? (xfer->tx_len == xfer->rx_len) : 1, -EINVAL); QM_CHECK(tmode == QM_SS_SPI_TMOD_TX ? (xfer->rx_len == 0) : 1, -EINVAL); QM_CHECK(tmode == QM_SS_SPI_TMOD_EEPROM_READ ? (xfer->rx_len > 0) : 1, -EINVAL); QM_CHECK(tmode == QM_SS_SPI_TMOD_RX ? (xfer->rx_len > 0) : 1, -EINVAL); QM_CHECK(tmode == QM_SS_SPI_TMOD_RX ? (xfer->tx_len == 0) : 1, -EINVAL); uint32_t tx_cnt = xfer->tx_len; uint32_t rx_cnt = xfer->rx_len; uint8_t *rx_buffer = xfer->rx; uint8_t *tx_buffer = xfer->tx; int ret = 0; /* Disable all SPI interrupts */ __builtin_arc_sr(0, base[spi] + QM_SS_SPI_INTR_MASK); /* Set NDF (Number of Data Frames) in RX or EEPROM Read mode. (-1) */ if (tmode == QM_SS_SPI_TMOD_RX || tmode == QM_SS_SPI_TMOD_EEPROM_READ) { ctrl &= ~QM_SS_SPI_CTRL_NDF_MASK; ctrl |= ((xfer->rx_len - 1) << QM_SS_SPI_CTRL_NDF_OFFS) & QM_SS_SPI_CTRL_NDF_MASK; __builtin_arc_sr(ctrl, base[spi] + QM_SS_SPI_CTRL); } /* RX only transfers need a dummy frame to be sent. */ if (tmode == QM_SS_SPI_TMOD_RX) { tx_buffer = (uint8_t *)&dummy_frame; tx_cnt = 1; } /* Calculate number of bytes per frame (1 or 2)*/ uint8_t bytes = BYTES_PER_FRAME(ctrl); /* Enable SPI device */ QM_SS_REG_AUX_OR(base[spi] + QM_SS_SPI_SPIEN, QM_SS_SPI_SPIEN_EN); while (tx_cnt || rx_cnt) { uint32_t sr = __builtin_arc_lr(base[spi] + QM_SS_SPI_SR); /* Break and report error if RX FIFO has overflown */ if (__builtin_arc_lr(base[spi] + QM_SS_SPI_INTR_STAT) & QM_SS_SPI_INTR_RXOI) { ret = -EIO; if (status) { *status |= QM_SS_SPI_RX_OVERFLOW; } break; } /* Copy data to buffer as long RX-FIFO is not empty */ if (sr & QM_SS_SPI_SR_RFNE && rx_cnt) { fifo_read(spi, rx_buffer, bytes); rx_buffer += bytes; rx_cnt--; } /* Copy data from buffer as long TX-FIFO is not full. */ if (sr & QM_SS_SPI_SR_TFNF && tx_cnt) { fifo_write(spi, tx_buffer, bytes); tx_buffer += bytes; tx_cnt--; } } /* Wait for last byte transfered */ while (__builtin_arc_lr(base[spi] + QM_SS_SPI_SR) & QM_SS_SPI_SR_BUSY) ; spi_disable(spi); return ret; }
static void restore_rtc_trigger(uint32_t trigger) { /* Restore the RTC interrupt trigger when waking up. */ __builtin_arc_sr(QM_IRQ_RTC_0_INT_VECTOR, QM_SS_AUX_IRQ_SELECT); __builtin_arc_sr(trigger, QM_SS_AUX_IRQ_TRIGGER); }