int gpio_dw_initialize(struct device *port) { struct gpio_dw_config *config = port->config->config_info; uint32_t base_addr; if (!gpio_dw_setup(port)) { return -EPERM; } base_addr = config->base_addr; #ifdef CONFIG_SOC_QUARK_SE_SS /* Need to enable clock for GPIO controller */ dw_set_bit(base_addr, INT_CLOCK_SYNC, CLK_ENA_POS, 1); #endif /* CONFIG_SOC_QUARK_SE_SS */ /* interrupts in sync with system clock */ dw_set_bit(base_addr, INT_CLOCK_SYNC, LS_SYNC_POS, 1); _gpio_dw_clock_config(port); /* mask and disable interrupts */ dw_write(base_addr, INTMASK, ~(0)); dw_write(base_addr, INTEN, 0); dw_write(base_addr, PORTA_EOI, ~(0)); port->driver_api = &api_funcs; config->config_func(port); return 0; }
static void dw_dma_isr(void *arg) { struct device *dev = (struct device *)arg; const struct dw_dma_dev_cfg *const dev_cfg = DEV_CFG(dev); struct dw_dma_dev_data *const dev_data = DEV_DATA(dev); struct dma_chan_data *chan_data; u32_t status_tfr = 0; u32_t status_block = 0; u32_t status_err = 0; u32_t status_intr; u32_t channel; status_intr = dw_read(dev_cfg->base, DW_INTR_STATUS); if (!status_intr) { SYS_LOG_ERR("status_intr = %d", status_intr); } /* get the source of our IRQ. */ status_block = dw_read(dev_cfg->base, DW_STATUS_BLOCK); status_tfr = dw_read(dev_cfg->base, DW_STATUS_TFR); /* TODO: handle errors, just clear them atm */ status_err = dw_read(dev_cfg->base, DW_STATUS_ERR); if (status_err) { SYS_LOG_ERR("status_err = %d\n", status_err); dw_write(dev_cfg->base, DW_CLEAR_ERR, status_err); } /* clear interrupts */ dw_write(dev_cfg->base, DW_CLEAR_BLOCK, status_block); dw_write(dev_cfg->base, DW_CLEAR_TFR, status_tfr); /* Dispatch ISRs for channels depending upon the bit set */ while (status_block) { channel = find_lsb_set(status_block) - 1; status_block &= ~(1 << channel); chan_data = &dev_data->chan[channel]; if (chan_data->dma_blkcallback) { /* Ensure the linked list (chan_data->lli) is * freed in the user callback function once * all the blocks are transferred. */ chan_data->dma_blkcallback(dev, channel, 0); } } while (status_tfr) { channel = find_lsb_set(status_tfr) - 1; status_tfr &= ~(1 << channel); chan_data = &dev_data->chan[channel]; k_free(chan_data->lli); chan_data->lli = NULL; if (chan_data->dma_tfrcallback) { chan_data->dma_tfrcallback(dev, channel, 0); } } }
static int dw_dma_transfer_stop(struct device *dev, u32_t channel) { const struct dw_dma_dev_cfg *const dev_cfg = DEV_CFG(dev); if (channel >= DW_MAX_CHAN) { return -EINVAL; } /* mask block, transfer and error interrupts for channel */ dw_write(dev_cfg->base, DW_MASK_TFR, INT_MASK(channel)); dw_write(dev_cfg->base, DW_MASK_BLOCK, INT_MASK(channel)); dw_write(dev_cfg->base, DW_MASK_ERR, INT_MASK(channel)); /* disable the channel */ dw_write(dev_cfg->base, DW_DMA_CHAN_EN, CHAN_DISABLE(channel)); return 0; }
static inline int gpio_dw_write(struct device *port, int access_op, uint32_t pin, uint32_t value) { struct gpio_dw_config *config = port->config->config_info; uint32_t base_addr = config->base_addr; if (GPIO_ACCESS_BY_PIN == access_op) { dw_set_bit(base_addr, SWPORTA_DR, pin, value); } else { dw_write(base_addr, SWPORTA_DR, value); } return 0; }
static inline int gpio_dw_enable_callback(struct device *port, int access_op, uint32_t pin) { struct gpio_dw_config *config = port->config->config_info; struct gpio_dw_runtime *context = port->driver_data; uint32_t base_addr = config->base_addr; if (GPIO_ACCESS_BY_PIN == access_op) { context->enabled_callbacks |= BIT(pin); } else { context->port_callback = 1; } dw_write(base_addr, PORTA_EOI, BIT(pin)); dw_set_bit(base_addr, INTMASK, pin, 0); return 0; }
void gpio_dw_isr(void *arg) { struct device *port = (struct device *)arg; struct gpio_dw_runtime *context = port->driver_data; struct gpio_dw_config *config = port->config->config_info; uint32_t base_addr = config->base_addr; uint32_t enabled_int, int_status, bit; int_status = dw_read(base_addr, INTSTATUS); #ifdef CONFIG_SHARED_IRQ /* If using with shared IRQ, this function will be called * by the shared IRQ driver. So check here if the interrupt * is coming from the GPIO controller (or somewhere else). */ if (!int_status) { return; } #endif dw_write(base_addr, PORTA_EOI, int_status); if (!context->callback) { return; } if (context->port_callback) { context->callback(port, int_status); return; } if (context->enabled_callbacks) { enabled_int = int_status & context->enabled_callbacks; for (bit = 0; bit < config->bits; bit++) { if (enabled_int & BIT(bit)) { context->callback(port, bit); } } } }
static void dw_dma_setup(struct device *dev) { const struct dw_dma_dev_cfg *const dev_cfg = DEV_CFG(dev); struct dw_dma_dev_data *const dev_data = DEV_DATA(dev); struct dw_drv_plat_data *dp = dev_data->channel_data; int i; /* we cannot config DMAC if DMAC has been already enabled by host */ if (dw_read(dev_cfg->base, DW_DMA_CFG) != 0) { dw_write(dev_cfg->base, DW_DMA_CFG, 0x0); } /* now check that it's 0 */ for (i = DW_DMA_CFG_TRIES; i > 0; i--) { if (dw_read(dev_cfg->base, DW_DMA_CFG) == 0) { goto found; } } SYS_LOG_ERR("DW_DMA_CFG is non-zero\n"); return; found: for (i = 0; i < DW_MAX_CHAN; i++) { dw_read(dev_cfg->base, DW_DMA_CHAN_EN); } /* enable the DMA controller */ dw_write(dev_cfg->base, DW_DMA_CFG, 1); /* mask all interrupts for all 8 channels */ dw_write(dev_cfg->base, DW_MASK_TFR, INT_MASK_ALL); dw_write(dev_cfg->base, DW_MASK_BLOCK, INT_MASK_ALL); dw_write(dev_cfg->base, DW_MASK_SRC_TRAN, INT_MASK_ALL); dw_write(dev_cfg->base, DW_MASK_DST_TRAN, INT_MASK_ALL); dw_write(dev_cfg->base, DW_MASK_ERR, INT_MASK_ALL); /* set channel priorities */ for (i = 0; i < DW_MAX_CHAN; i++) { dw_write(dev_cfg->base, DW_CTRL_HIGH(i), DW_CFG_CLASS(dp->chan[i].class)); } }
static void dw_reloc( dw_sectnum sect, dw_reloc_type reloc_type, ... ) /********************************************************************/ { va_list args; dw_targ_addr targ_data; dw_targ_seg seg_data; uint_32 u32_data; dw_sectnum sect_no; SYMPTR sym; va_start( args, reloc_type ); switch( reloc_type ) { case DW_W_LABEL: case DW_W_DEFAULT_FUNCTION: case DW_W_ARANGE_ADDR: case DW_W_LOW_PC: u32_data = 0; // NOTE: assumes little-endian byte order dw_write( sect, &u32_data, TARGET_NEAR_POINTER ); break; case DW_W_HIGH_PC: u32_data = 1; // NOTE: assumes little-endian byte order dw_write( sect, &u32_data, TARGET_NEAR_POINTER ); break; case DW_W_UNIT_SIZE: u32_data = 1; dw_write( sect, &u32_data, sizeof( u32_data ) ); break; case DW_W_STATIC: sym = va_arg( args, SYMPTR ); targ_data = 0; dw_write( sect, &targ_data, sizeof( targ_data ) ); break; case DW_W_SEGMENT: sym = va_arg( args, SYMPTR ); seg_data = SymSegId( sym ); dw_write( sect, &seg_data, sizeof( seg_data ) ); break; case DW_W_SECTION_POS: sect_no = va_arg( args, dw_sectnum ); u32_data = dw_tell( sect_no ); dw_write( sect, &u32_data, sizeof( u32_data ) ); break; default: break; } va_end( args ); }
static int dw_dma_transfer_start(struct device *dev, u32_t channel) { const struct dw_dma_dev_cfg *const dev_cfg = DEV_CFG(dev); struct dw_dma_dev_data *const dev_data = DEV_DATA(dev); struct dma_chan_data *chan_data; if (channel >= DW_MAX_CHAN) { return -EINVAL; } chan_data = &dev_data->chan[channel]; if (chan_data->dma_tfrcallback) { dw_write(dev_cfg->base, DW_MASK_TFR, INT_UNMASK(channel)); } if (chan_data->dma_blkcallback) { dw_write(dev_cfg->base, DW_MASK_BLOCK, INT_UNMASK(channel)); } dw_write(dev_cfg->base, DW_MASK_ERR, INT_UNMASK(channel)); /* write interrupt clear registers for the channel * ClearTfr, ClearBlock, ClearSrcTran, ClearDstTran, ClearErr */ dw_write(dev_cfg->base, DW_CLEAR_TFR, 0x1 << channel); dw_write(dev_cfg->base, DW_CLEAR_BLOCK, 0x1 << channel); dw_write(dev_cfg->base, DW_CLEAR_SRC_TRAN, 0x1 << channel); dw_write(dev_cfg->base, DW_CLEAR_DST_TRAN, 0x1 << channel); dw_write(dev_cfg->base, DW_CLEAR_ERR, 0x1 << channel); if (chan_data->lli->llp) { /* LLP mode - only write LLP pointer */ dw_write(dev_cfg->base, DW_LLP(channel), (u32_t)chan_data->lli); } else { /* single transfer, must set zero */ dw_write(dev_cfg->base, DW_LLP(channel), 0); } /* channel needs started from scratch, so write SARn, DARn */ dw_write(dev_cfg->base, DW_SAR(channel), chan_data->lli->sar); dw_write(dev_cfg->base, DW_DAR(channel), chan_data->lli->dar); /* program CTLn */ dw_write(dev_cfg->base, DW_CTRL_LOW(channel), chan_data->lli->ctrl_lo); dw_write(dev_cfg->base, DW_CTRL_HIGH(channel), chan_data->lli->ctrl_hi); /* write channel config */ dw_write(dev_cfg->base, DW_CFG_LOW(channel), chan_data->cfg_lo); dw_write(dev_cfg->base, DW_CFG_HIGH(channel), chan_data->cfg_hi); /* enable the channel */ dw_write(dev_cfg->base, DW_DMA_CHAN_EN, CHAN_ENABLE(channel)); return 0; }