目录
mtk_spi_slave_prepare_message函数
源码路径
drivers/spi/spi-slave-mt27xx.c
设备树
spis0: spis0@11014000 {
compatible = "mediatek,mt6765-spi-slave","mediatek,mt8512-spi-slave";
reg = <0 0x11014000 0 0x100>;
interrupts = <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&infracfg_ao_clk CLK_IFRAO_RG_FSPIS_CK>,
<&infracfg_ao_clk CLK_IFRAO_SPIS_HCLK_66M>;
clock-names = "spi", "axi";
assigned-clocks = <&topckgen_clk CLK_TOP_SPIS_SEL>;
assigned-clock-parents = <&topckgen_clk CLK_TOP_UNIVPLL_D6>;
status = "disabled";
};
SPI slave控制器驱动
static const struct of_device_id mtk_spi_slave_of_match[] = {
{ .compatible = "mediatek,mt2712-spi-slave",
.data = (void *)&mt2712_compat,},
{ .compatible = "mediatek,mt8512-spi-slave", //和设备树中的compatible同名,然后执行probe函数
.data = (void *)&mt8512_compat,},
{}
};
static struct platform_driver mtk_spi_slave_driver = {
.driver = {
.name = "mtk-spi-slave",
.pm = &mtk_spi_slave_pm,
.of_match_table = mtk_spi_slave_of_match,
},
.probe = mtk_spi_slave_probe,
.remove = mtk_spi_slave_remove,
};
module_platform_driver(mtk_spi_slave_driver);
mtk_spi_slave_probe函数
static int mtk_spi_slave_probe(struct platform_device *pdev)
{
struct spi_controller *ctlr;
struct mtk_spi_slave *mdata;
struct resource *res;
int irq, ret;
const struct of_device_id *of_id;
//申请ctlr地址空间,同时申请mdata的地址空间,mdata的地址在ctlr之后
ctlr = spi_alloc_slave(&pdev->dev, sizeof(*mdata));
......
ctlr->auto_runtime_pm = true;
ctlr->dev.of_node = pdev->dev.of_node;//设备树节点保存到ctlr中
ctlr->mode_bits = SPI_CPOL | SPI_CPHA;//模式位初始化
ctlr->mode_bits |= SPI_LSB_FIRST;
ctlr->flags = SPI_MASTER_MUST_RX;
//回调函数初始化,后续spi读写时,在spi框架中会用到
ctlr->prepare_message = mtk_spi_slave_prepare_message;
ctlr->transfer_one = mtk_spi_slave_transfer_one;
ctlr->setup = mtk_spi_slave_setup;
ctlr->slave_abort = mtk_slave_abort;
//of_id 指向mtk_spi_slave_of_match
of_id = of_match_node(mtk_spi_slave_of_match, pdev->dev.of_node);
......
mdata = spi_controller_get_devdata(ctlr); //获取mdata地址,,mdata的地址在ctlr之后
mdata->dev_comp = of_id->data;//mdata->dev_comp指向mt8512_compat
if (mdata->dev_comp->must_rx)
ctlr->flags = SPI_MASTER_MUST_RX;
platform_set_drvdata(pdev, ctlr);
init_completion(&mdata->xfer_done);//完成量初始化
//获取资源,为后续获取寄存器基地址使用
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
......
mdata->dev = &pdev->dev;
//获取spis0的寄存器基地址,然后做地址映射
mdata->base = devm_ioremap_resource(&pdev->dev, res);
......
irq = platform_get_irq(pdev, 0); //获取spis0的中断号
......
//注册中断
ret = devm_request_irq(&pdev->dev, irq, mtk_spi_slave_interrupt,
IRQF_TRIGGER_NONE, dev_name(&pdev->dev), ctlr);
.......
mdata->spi_clk = devm_clk_get(&pdev->dev, "spi");
......
//使能spi时钟
ret = clk_prepare_enable(mdata->spi_clk);
......
if (mdata->dev_comp->need_axi_clk) {
mdata->axi_clk = devm_clk_get(&pdev->dev, "axi");
......
//使能axi时钟
ret = clk_prepare_enable(mdata->axi_clk);
......
}
pm_runtime_enable(&pdev->dev);
//spi控制器注册
ret = devm_spi_register_controller(&pdev->dev, ctlr);
......
if (mdata->dev_comp->need_axi_clk)
clk_disable_unprepare(mdata->axi_clk);
clk_disable_unprepare(mdata->spi_clk);
return 0;
}
mtk_spi_slave_prepare_message函数
spi读写前的准备动作
static int mtk_spi_slave_prepare_message(struct spi_controller *ctlr,
struct spi_message *msg)
{
struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr);
struct spi_device *spi = msg->spi;
bool cpha, cpol;
u32 reg_val;
cpha = spi->mode & SPI_CPHA ? 1 : 0;
cpol = spi->mode & SPI_CPOL ? 1 : 0;
//读取寄存器的值,接着修改
reg_val = readl(mdata->base + SPIS_CFG_REG);
if (cpha)
reg_val |= SPIS_CPHA;
else
reg_val &= ~SPIS_CPHA;
if (cpol)
reg_val |= SPIS_CPOL;
else
reg_val &= ~SPIS_CPOL;
if (spi->mode & SPI_LSB_FIRST)
reg_val &= ~(SPIS_TXMSBF | SPIS_RXMSBF);
else
reg_val |= SPIS_TXMSBF | SPIS_RXMSBF;
reg_val &= ~SPIS_TX_ENDIAN;
reg_val &= ~SPIS_RX_ENDIAN;
writel(reg_val, mdata->base + SPIS_CFG_REG);//将修改后的值写入寄存器
return 0;
}
mtk_spi_slave_transfer_one函数
static int mtk_spi_slave_fifo_transfer(struct spi_controller *ctlr,
struct spi_device *spi,
struct spi_transfer *xfer)
{
struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr);
int reg_val, cnt, remainder, ret;
writel(SPIS_SOFT_RST, mdata->base + SPIS_SOFT_RST_REG);//spi复位
reg_val = readl(mdata->base + SPIS_CFG_REG);
if (xfer->rx_buf)
reg_val |= SPIS_RX_EN;
if (xfer->tx_buf)
reg_val |= SPIS_TX_EN;
writel(reg_val, mdata->base + SPIS_CFG_REG);//spi使能
cnt = xfer->len / 4;
if (xfer->tx_buf)
iowrite32_rep(mdata->base + SPIS_TX_DATA_REG,//spi发送前面4的倍数长度的字节
xfer->tx_buf, cnt);
remainder = xfer->len % 4;
if (xfer->tx_buf && remainder > 0) {
reg_val = 0;
memcpy(®_val, xfer->tx_buf + cnt * 4, remainder);
writel(reg_val, mdata->base + SPIS_TX_DATA_REG);//spi发送最后几个字节
}
ret = mtk_spi_slave_wait_for_completion(mdata);//阻塞,等待发送完成,中断里面使用complete解除阻塞
if (ret) {
mtk_spi_slave_disable_xfer(mdata);
writel(SPIS_SOFT_RST, mdata->base + SPIS_SOFT_RST_REG);
}
return ret;
}
static int mtk_spi_slave_dma_transfer(struct spi_controller *ctlr,
struct spi_device *spi,
struct spi_transfer *xfer)
{
struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr);
struct device *dev = mdata->dev;
int reg_val, ret;
writel(SPIS_SOFT_RST, mdata->base + SPIS_SOFT_RST_REG);//spi复位
reg_val = readl(mdata->base + SPIS_CFG_REG);
if (xfer->tx_buf)
reg_val |= SPIS_TX_EN;
if (xfer->rx_buf)
reg_val |= SPIS_RX_EN;
writel(reg_val, mdata->base + SPIS_CFG_REG);//spi使能
/*省略了DMA的配置 */
......
ret = mtk_spi_slave_wait_for_completion(mdata);//阻塞,等待发送完成,中断里面使用complete解除阻塞
if (ret)
goto unmap_rxdma;
return 0;
......
}
static int mtk_spi_slave_transfer_one(struct spi_controller *ctlr,
struct spi_device *spi,
struct spi_transfer *xfer)
{
struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr);
reinit_completion(&mdata->xfer_done);
mdata->slave_aborted = false;
mdata->cur_transfer = xfer;
//spi发送超过128字节,使用DMA传输,否则使用FIFO传输
if (xfer->len > mdata->dev_comp->max_fifo_size)
return mtk_spi_slave_dma_transfer(ctlr, spi, xfer);
else
return mtk_spi_slave_fifo_transfer(ctlr, spi, xfer);
}
mtk_spi_slave_interrupt中断处理函数
static irqreturn_t mtk_spi_slave_interrupt(int irq, void *dev_id)
{
struct spi_controller *ctlr = dev_id;
struct mtk_spi_slave *mdata = spi_controller_get_devdata(ctlr);
struct spi_transfer *trans = mdata->cur_transfer;
u32 int_status, reg_val, cnt, remainder;
int_status = readl(mdata->base + SPIS_IRQ_ST_REG);//读取中断状态
writel(int_status, mdata->base + SPIS_IRQ_CLR_REG);//清除中断状态
if (!trans)
return IRQ_NONE;
//发送完成
if ((int_status & DMA_DONE_ST) &&
((int_status & DATA_DONE_ST) ||
(int_status & RSTA_DONE_ST))) {
writel(SPIS_SOFT_RST, mdata->base + SPIS_SOFT_RST_REG);
......
}
//接收完成
if ((!(int_status & DMA_DONE_ST)) &&
((int_status & DATA_DONE_ST) ||
(int_status & RSTA_DONE_ST))) {
cnt = trans->len / 4;
//接收数据
if (trans->rx_buf)
ioread32_rep(mdata->base + SPIS_RX_DATA_REG,
trans->rx_buf, cnt);
remainder = trans->len % 4;
if (trans->rx_buf && remainder > 0) {
reg_val = readl(mdata->base + SPIS_RX_DATA_REG);
memcpy(trans->rx_buf + (cnt * 4),
®_val, remainder);
}
mtk_spi_slave_disable_xfer(mdata);
}
......
mdata->cur_transfer = NULL;
complete(&mdata->xfer_done);//完成量complete,解除mtk_spi_slave_wait_for_completion阻塞
return IRQ_HANDLED;
}