📄 au1550_spi.c
字号:
au1550_spi_mask_ack_all(hw); hw->rx_count = hw->len; hw->tx_count = hw->len; complete(&hw->master_done); } return IRQ_HANDLED;}/* routines to handle different word sizes in pio mode */#define AU1550_SPI_RX_WORD(size, mask) \static void au1550_spi_rx_word_##size(struct au1550_spi *hw) \{ \ u32 fifoword = hw->regs->psc_spitxrx & (u32)(mask); \ au_sync(); \ if (hw->rx) { \ *(u##size *)hw->rx = (u##size)fifoword; \ hw->rx += (size) / 8; \ } \ hw->rx_count += (size) / 8; \}#define AU1550_SPI_TX_WORD(size, mask) \static void au1550_spi_tx_word_##size(struct au1550_spi *hw) \{ \ u32 fifoword = 0; \ if (hw->tx) { \ fifoword = *(u##size *)hw->tx & (u32)(mask); \ hw->tx += (size) / 8; \ } \ hw->tx_count += (size) / 8; \ if (hw->tx_count >= hw->len) \ fifoword |= PSC_SPITXRX_LC; \ hw->regs->psc_spitxrx = fifoword; \ au_sync(); \}AU1550_SPI_RX_WORD(8,0xff)AU1550_SPI_RX_WORD(16,0xffff)AU1550_SPI_RX_WORD(32,0xffffff)AU1550_SPI_TX_WORD(8,0xff)AU1550_SPI_TX_WORD(16,0xffff)AU1550_SPI_TX_WORD(32,0xffffff)static int au1550_spi_pio_txrxb(struct spi_device *spi, struct spi_transfer *t){ u32 stat, mask; struct au1550_spi *hw = spi_master_get_devdata(spi->master); hw->tx = t->tx_buf; hw->rx = t->rx_buf; hw->len = t->len; hw->tx_count = 0; hw->rx_count = 0; /* by default enable nearly all events after filling tx fifo */ mask = PSC_SPIMSK_SD; /* fill the transmit FIFO */ while (hw->tx_count < hw->len) { hw->tx_word(hw); if (hw->tx_count >= hw->len) { /* mask tx fifo request interrupt as we are done */ mask |= PSC_SPIMSK_TR; } stat = hw->regs->psc_spistat; au_sync(); if (stat & PSC_SPISTAT_TF) break; } /* enable event interrupts */ hw->regs->psc_spimsk = mask; au_sync(); /* start the transfer */ hw->regs->psc_spipcr = PSC_SPIPCR_MS; au_sync(); wait_for_completion(&hw->master_done); return hw->rx_count < hw->tx_count ? hw->rx_count : hw->tx_count;}static irqreturn_t au1550_spi_pio_irq_callback(struct au1550_spi *hw){ int busy; u32 stat, evnt; stat = hw->regs->psc_spistat; evnt = hw->regs->psc_spievent; au_sync(); if ((stat & PSC_SPISTAT_DI) == 0) { dev_err(hw->dev, "Unexpected IRQ!\n"); return IRQ_NONE; } if ((evnt & (PSC_SPIEVNT_MM | PSC_SPIEVNT_RO | PSC_SPIEVNT_RU | PSC_SPIEVNT_TO | PSC_SPIEVNT_TU | PSC_SPIEVNT_SD)) != 0) { dev_err(hw->dev, "Unexpected SPI error: event=0x%x stat=0x%x!\n", evnt, stat); /* * due to an error we consider transfer as done, * so mask all events until before next transfer start */ au1550_spi_mask_ack_all(hw); au1550_spi_reset_fifos(hw); complete(&hw->master_done); return IRQ_HANDLED; } /* * while there is something to read from rx fifo * or there is a space to write to tx fifo: */ do { busy = 0; stat = hw->regs->psc_spistat; au_sync(); if ((stat & PSC_SPISTAT_RE) == 0 && hw->rx_count < hw->len) { hw->rx_word(hw); /* ack the receive request event */ hw->regs->psc_spievent = PSC_SPIEVNT_RR; au_sync(); busy = 1; } if ((stat & PSC_SPISTAT_TF) == 0 && hw->tx_count < hw->len) { hw->tx_word(hw); /* ack the transmit request event */ hw->regs->psc_spievent = PSC_SPIEVNT_TR; au_sync(); busy = 1; } } while (busy); evnt = hw->regs->psc_spievent; au_sync(); if (hw->rx_count >= hw->len || (evnt & PSC_SPIEVNT_MD) != 0) { /* transfer completed successfully */ au1550_spi_mask_ack_all(hw); complete(&hw->master_done); } return IRQ_HANDLED;}static int au1550_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t){ struct au1550_spi *hw = spi_master_get_devdata(spi->master); return hw->txrx_bufs(spi, t);}static irqreturn_t au1550_spi_irq(int irq, void *dev, struct pt_regs *regs){ struct au1550_spi *hw = dev; return hw->irq_callback(hw);}static void au1550_spi_bits_handlers_set(struct au1550_spi *hw, int bpw){ if (bpw <= 8) { if (hw->usedma) { hw->txrx_bufs = &au1550_spi_dma_txrxb; hw->irq_callback = &au1550_spi_dma_irq_callback; } else { hw->rx_word = &au1550_spi_rx_word_8; hw->tx_word = &au1550_spi_tx_word_8; hw->txrx_bufs = &au1550_spi_pio_txrxb; hw->irq_callback = &au1550_spi_pio_irq_callback; } } else if (bpw <= 16) { hw->rx_word = &au1550_spi_rx_word_16; hw->tx_word = &au1550_spi_tx_word_16; hw->txrx_bufs = &au1550_spi_pio_txrxb; hw->irq_callback = &au1550_spi_pio_irq_callback; } else { hw->rx_word = &au1550_spi_rx_word_32; hw->tx_word = &au1550_spi_tx_word_32; hw->txrx_bufs = &au1550_spi_pio_txrxb; hw->irq_callback = &au1550_spi_pio_irq_callback; }}static void __init au1550_spi_setup_psc_as_spi(struct au1550_spi *hw){ u32 stat, cfg; /* set up the PSC for SPI mode */ hw->regs->psc_ctrl = PSC_CTRL_DISABLE; au_sync(); hw->regs->psc_sel = PSC_SEL_PS_SPIMODE; au_sync(); hw->regs->psc_spicfg = 0; au_sync(); hw->regs->psc_ctrl = PSC_CTRL_ENABLE; au_sync(); do { stat = hw->regs->psc_spistat; au_sync(); } while ((stat & PSC_SPISTAT_SR) == 0); cfg = hw->usedma ? 0 : PSC_SPICFG_DD_DISABLE; cfg |= PSC_SPICFG_SET_LEN(8); cfg |= PSC_SPICFG_RT_FIFO8 | PSC_SPICFG_TT_FIFO8; /* use minimal allowed brg and div values as initial setting: */ cfg |= PSC_SPICFG_SET_BAUD(4) | PSC_SPICFG_SET_DIV(0);#ifdef AU1550_SPI_DEBUG_LOOPBACK cfg |= PSC_SPICFG_LB;#endif hw->regs->psc_spicfg = cfg; au_sync(); au1550_spi_mask_ack_all(hw); hw->regs->psc_spicfg |= PSC_SPICFG_DE_ENABLE; au_sync(); do { stat = hw->regs->psc_spistat; au_sync(); } while ((stat & PSC_SPISTAT_DR) == 0);}static int __init au1550_spi_probe(struct platform_device *pdev){ struct au1550_spi *hw; struct spi_master *master; int err = 0; master = spi_alloc_master(&pdev->dev, sizeof(struct au1550_spi)); if (master == NULL) { dev_err(&pdev->dev, "No memory for spi_master\n"); err = -ENOMEM; goto err_nomem; } hw = spi_master_get_devdata(master); hw->master = spi_master_get(master); hw->pdata = pdev->dev.platform_data; hw->dev = &pdev->dev; if (hw->pdata == NULL) { dev_err(&pdev->dev, "No platform data supplied\n"); err = -ENOENT; goto err_no_pdata; } platform_set_drvdata(pdev, hw); init_completion(&hw->master_done); hw->bitbang.master = hw->master; hw->bitbang.setup_transfer = au1550_spi_setupxfer; hw->bitbang.chipselect = au1550_spi_chipsel; hw->bitbang.master->setup = au1550_spi_setup; hw->bitbang.txrx_bufs = au1550_spi_txrx_bufs; switch (hw->pdata->bus_num) { case 0: hw->irq = AU1550_PSC0_INT; hw->regs = (volatile psc_spi_t *)PSC0_BASE_ADDR; hw->dma_rx_id = DSCR_CMD0_PSC0_RX; hw->dma_tx_id = DSCR_CMD0_PSC0_TX; break; case 1: hw->irq = AU1550_PSC1_INT; hw->regs = (volatile psc_spi_t *)PSC1_BASE_ADDR; hw->dma_rx_id = DSCR_CMD0_PSC1_RX; hw->dma_tx_id = DSCR_CMD0_PSC1_TX; break; case 2: hw->irq = AU1550_PSC2_INT; hw->regs = (volatile psc_spi_t *)PSC2_BASE_ADDR; hw->dma_rx_id = DSCR_CMD0_PSC2_RX; hw->dma_tx_id = DSCR_CMD0_PSC2_TX; break; case 3: hw->irq = AU1550_PSC3_INT; hw->regs = (volatile psc_spi_t *)PSC3_BASE_ADDR; hw->dma_rx_id = DSCR_CMD0_PSC3_RX; hw->dma_tx_id = DSCR_CMD0_PSC3_TX; break; default: dev_err(&pdev->dev, "Wrong bus_num of SPI\n"); err = -ENOENT; goto err_no_pdata; } if (request_mem_region((unsigned long)hw->regs, sizeof(psc_spi_t), pdev->name) == NULL) { dev_err(&pdev->dev, "Cannot reserve iomem region\n"); err = -ENXIO; goto err_no_iores; } if (usedma) { if (pdev->dev.dma_mask == NULL) dev_warn(&pdev->dev, "no dma mask\n"); else hw->usedma = 1; } if (hw->usedma) { /* * create memory device with 8 bits dev_devwidth * needed for proper byte ordering to spi fifo */ int memid = au1xxx_ddma_add_device(&au1550_spi_mem_dbdev); if (!memid) { dev_err(&pdev->dev, "Cannot create dma 8 bit mem device\n"); err = -ENXIO; goto err_dma_add_dev; } hw->dma_tx_ch = au1xxx_dbdma_chan_alloc(memid, hw->dma_tx_id, NULL, (void *)hw); if (hw->dma_tx_ch == 0) { dev_err(&pdev->dev, "Cannot allocate tx dma channel\n"); err = -ENXIO; goto err_no_txdma; } au1xxx_dbdma_set_devwidth(hw->dma_tx_ch, 8); if (au1xxx_dbdma_ring_alloc(hw->dma_tx_ch, AU1550_SPI_DBDMA_DESCRIPTORS) == 0) { dev_err(&pdev->dev, "Cannot allocate tx dma descriptors\n"); err = -ENXIO; goto err_no_txdma_descr; } hw->dma_rx_ch = au1xxx_dbdma_chan_alloc(hw->dma_rx_id, memid, NULL, (void *)hw); if (hw->dma_rx_ch == 0) { dev_err(&pdev->dev, "Cannot allocate rx dma channel\n"); err = -ENXIO; goto err_no_rxdma; } au1xxx_dbdma_set_devwidth(hw->dma_rx_ch, 8); if (au1xxx_dbdma_ring_alloc(hw->dma_rx_ch, AU1550_SPI_DBDMA_DESCRIPTORS) == 0) { dev_err(&pdev->dev, "Cannot allocate rx dma descriptors\n"); err = -ENXIO; goto err_no_rxdma_descr; } err = au1550_spi_dma_rxtmp_alloc(hw, AU1550_SPI_DMA_RXTMP_MINSIZE); if (err < 0) { dev_err(&pdev->dev, "Cannot allocate initial rx dma tmp buffer\n"); goto err_dma_rxtmp_alloc; } } au1550_spi_bits_handlers_set(hw, 8); err = request_irq(hw->irq, au1550_spi_irq, 0, pdev->name, hw); if (err) { dev_err(&pdev->dev, "Cannot claim IRQ\n"); goto err_no_irq; } master->bus_num = hw->pdata->bus_num; master->num_chipselect = hw->pdata->num_chipselect; /* * precompute valid range for spi freq - from au1550 datasheet: * psc_tempclk = psc_mainclk / (2 << DIV) * spiclk = psc_tempclk / (2 * (BRG + 1)) * BRG valid range is 4..63 * DIV valid range is 0..3 * round the min and max frequencies to values that would still * produce valid brg and div */ { int min_div = (2 << 0) * (2 * (4 + 1)); int max_div = (2 << 3) * (2 * (63 + 1)); hw->freq_max = hw->pdata->mainclk_hz / min_div; hw->freq_min = hw->pdata->mainclk_hz / (max_div + 1) + 1; } au1550_spi_setup_psc_as_spi(hw); err = spi_bitbang_start(&hw->bitbang); if (err) { dev_err(&pdev->dev, "Failed to register SPI master\n"); goto err_register; } dev_info(&pdev->dev, "spi master registered: bus_num=%d num_chipselect=%d\n", master->bus_num, master->num_chipselect); return 0;err_register: free_irq(hw->irq, hw);err_no_irq: au1550_spi_dma_rxtmp_free(hw);err_dma_rxtmp_alloc:err_no_rxdma_descr: if (hw->usedma) au1xxx_dbdma_chan_free(hw->dma_rx_ch);err_no_rxdma:err_no_txdma_descr: if (hw->usedma) au1xxx_dbdma_chan_free(hw->dma_tx_ch);err_no_txdma:err_dma_add_dev: release_mem_region((unsigned long)hw->regs, sizeof(psc_spi_t));err_no_iores:err_no_pdata: spi_master_put(hw->master);err_nomem: return err;}static int __exit au1550_spi_remove(struct platform_device *pdev){ struct au1550_spi *hw = platform_get_drvdata(pdev); dev_info(&pdev->dev, "spi master remove: bus_num=%d\n", hw->master->bus_num); spi_bitbang_stop(&hw->bitbang); free_irq(hw->irq, hw); release_mem_region((unsigned long)hw->regs, sizeof(psc_spi_t)); if (hw->usedma) { au1550_spi_dma_rxtmp_free(hw); au1xxx_dbdma_chan_free(hw->dma_rx_ch); au1xxx_dbdma_chan_free(hw->dma_tx_ch); } platform_set_drvdata(pdev, NULL); spi_master_put(hw->master); return 0;}static struct platform_driver au1550_spi_drv = { .remove = __exit_p(au1550_spi_remove), .driver = { .name = "au1550-spi", .owner = THIS_MODULE, },};static int __init au1550_spi_init(void){ return platform_driver_probe(&au1550_spi_drv, au1550_spi_probe);}module_init(au1550_spi_init);static void __exit au1550_spi_exit(void){ platform_driver_unregister(&au1550_spi_drv);}module_exit(au1550_spi_exit);MODULE_DESCRIPTION("Au1550 PSC SPI Driver");MODULE_AUTHOR("Jan Nikitenko <jan.nikitenko@gmail.com>");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -