问题背景
在开发项目中,换了一个spi安全芯片,发现不能进行通信,查看spi信号波形,时钟,发送数据,片选都是正常的,但没有回复数据。安全芯片技术正常通过查看CS片选波形信号,提出CS片选信号不能在每个字节数据传输完成后拉高,需要整个数据传输完成后才能拉高。查看之前的spi驱动,是安全芯片模块厂商提供的,说明spi驱动有改动过,没有使用IMX8QXP的LPSPI驱动。
不连续传输模式
通过测量波形信号,可以看出每个字节数据完成后CS(绿色)有拉高的动作,黄色为时钟信号。
连续传输模式
可以看出,数据发送完成后CS片选(绿色)才会拉高。
手册说明
为何会有这两种传输模式呢?IMX8QXP手册中有Transmit Command Register的描述:
但设置CONT为1时,使能连续传输模式,这样CS片选就会一直asserted。为0时,CS片选会在每个字节后面拉高。
内核代码
内核中,spi默认开启dma传输,所以这里不会设置temp |= TCR_CONT。
static void fsl_lpspi_set_cmd(struct fsl_lpspi_data *fsl_lpspi)
{
u32 temp = 0;
if (!fsl_lpspi->is_slave) {
temp |= fsl_lpspi->config.bpw - 1;
temp |= fsl_lpspi->config.prescale << 27;
temp |= (fsl_lpspi->config.mode & 0x3) << 30;
temp |= (fsl_lpspi->config.chip_select & 0x3) << 24;
/*
* Set TCR_CONT will keep SS asserted after current transfer.
* For the first transfer, clear TCR_CONTC to assert SS.
* For subsequent transfer, set TCR_CONTC to keep SS asserted.
*/
if (!fsl_lpspi->usedma) {
temp |= TCR_CONT;
if (fsl_lpspi->is_first_byte)
temp &= ~TCR_CONTC;
else
temp |= TCR_CONTC;
}
} else {
temp |= fsl_lpspi->config.bpw - 1;
temp |= (fsl_lpspi->config.mode & 0x3) << 30;
}
writel(temp, fsl_lpspi->base + IMX7ULP_TCR);
dev_dbg(fsl_lpspi->dev, "TCR=0x%x\n", temp);
}
关闭SPI DMA
dts中有描述dma信息:
lpspi2: lpspi@5a020000 {
compatible = "fsl,imx7ulp-spi";
reg = <0x0 0x5a020000 0x0 0x10000>;
interrupts = <GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH>;
interrupt-parent = <&gic>;
clocks = <&clk IMX8QXP_SPI2_CLK>,
<&clk IMX8QXP_SPI2_IPG_CLK>;
clock-names = "per", "ipg";
assigned-clocks = <&clk IMX8QXP_SPI2_CLK>;
assigned-clock-rates = <20000000>;
power-domains = <&pd_dma_lpspi2>;
dma-names = "tx","rx";
dmas = <&edma2 5 0 0>, <&edma2 4 0 1>;
status = "disabled";
};
&lpspi2 {
#address-cells = <1>;
#size-cells = <0>;
fsl,spi-num-chipselects = <1>;
cs-gpios = <&gpio1 0 GPIO_ACTIVE_LOW>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_lpspi2>;
assigned-clock-rates = <128000000>;
status = "okay";
spidev2:spidev@0 {
compatible = "rohm,dh2228fv";
spi-max-frequency = <50000000>;
reg = <0>;
};
};
把dts中的dma信息删除掉编译不会报错,但启动报错:
[ 1.028078] fsl_lpspi 5a020000.lpspi: failed to enable clock
[ 1.033817] fsl_lpspi: probe of 5a020000.lpspi failed with error -22
暂不知道怎么关闭DMA,取巧的办法是在fsl_lpspi_can_dma函数返回false:
static bool fsl_lpspi_can_dma(struct spi_controller *controller,
struct spi_device *spi,
struct spi_transfer *transfer)
{
unsigned int bytes_per_word;
return false;
if (!controller->dma_rx)
return false;
bytes_per_word = fsl_lpspi_bytes_per_word(transfer->bits_per_word);
if (bytes_per_word != 1 && bytes_per_word != 2 && bytes_per_word != 4)
return false;
return true;
}
这样关闭SPI DMA方式,转而使用SPI连续传输模式。接着安全芯片就能进行愉快的通信了。