Linux驱动开发 - spi子系统(3) spi slave控制器驱动

目录

源码路径

设备树

SPI slave控制器驱动

mtk_spi_slave_probe函数

mtk_spi_slave_prepare_message函数

mtk_spi_slave_transfer_one函数

mtk_spi_slave_interrupt中断处理函数


源码路径

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(&reg_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),
			       &reg_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;
}

  • 16
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值