1、查看电路原理图,确定spi对应的引脚GPIO口
2、根据RK-SPI手册添加dts节点并检查对应的GPIO口设置是否有问题,是否被占用
3、检查到有引脚(GPIO3_A2、GPIO3_B0)与spi的引脚占用,注释掉,不然编译后的系统可能会启动失败,或者驱动功能有问题
4、修改完后,将对应的驱动加载进内核,对应的文件如下:
5、查看生成的spi节点,ls -l | grep spi,会出现类似spi32766.0的设备节点,如果没有,请看下内核报错信息
6、通过应用层调用spi设备节点,发现SPI的时钟引脚没有信号产生,检查dts文档也没有引脚占用,因此需要排查io口的复用情况; 通过在rock_set_mux()函数中加入dump_stack()函数打印该函数的调用情况,因为所有RK的GPIO口复用都会调用该函数;其次通过“io -4 寄存器地址”来查看CLK引脚有无被其它驱动占用
7、上面的步骤做完后,发现时钟引脚被该驱动占用,关闭它之后,时钟就有信号了
8、如果根据项目需要自己去更改时钟频率,可以在spi-rockchip.c文件中rockchip_spi_config函数进行修改,修改函数中的clk_set_rate()来修改频率,spi_set_clk修改时钟的分频系数
static void rockchip_spi_config(struct rockchip_spi *rs)
{
u32 div = 0;
u32 dmacr = 0;
int rsd = 0;
u32 cr0 = (CR0_BHT_8BIT << CR0_BHT_OFFSET)
| (CR0_SSD_ONE << CR0_SSD_OFFSET)
| (CR0_EM_BIG << CR0_EM_OFFSET);
cr0 |= (rs->n_bytes << CR0_DFS_OFFSET);
cr0 |= ((rs->mode & 0x3) << CR0_SCPH_OFFSET);
if (rs->mode & SPI_LSB_FIRST)
cr0 |= (1 << CR0_FBM_OFFSET);/* First Bit Mode */
cr0 |= (rs->tmode << CR0_XFM_OFFSET);
cr0 |= (rs->type << CR0_FRF_OFFSET);
if (rs->use_dma) {
if (rs->tx)
dmacr |= TF_DMA_EN;
if (rs->rx)
dmacr |= RF_DMA_EN;
}
if (WARN_ON(rs->speed > MAX_SCLK_OUT))
rs->speed = MAX_SCLK_OUT;
/* the minimum divisor is 2 */
if (rs->max_freq < 2 * rs->speed) {
clk_set_rate(rs->spiclk, 2 * rs->speed); //设置时钟频率
rs->max_freq = clk_get_rate(rs->spiclk);
}
/* div doesn't support odd number */
div = DIV_ROUND_UP(rs->max_freq, rs->speed);
div = (div + 1) & 0xfffe;
/*
* If speed is larger than IO_DRIVER_4MA_MAX_SCLK_OUT,
* set higher driver strength.
*/
if (rs->high_speed_state) {
if (rs->speed > IO_DRIVER_4MA_MAX_SCLK_OUT)
pinctrl_select_state(rs->dev->pins->p,
rs->high_speed_state);
else
pinctrl_select_state(rs->dev->pins->p,
rs->dev->pins->default_state);
}
/* Rx sample delay is expressed in parent clock cycles (max 3) */
rsd = DIV_ROUND_CLOSEST(rs->rsd_nsecs * (rs->max_freq >> 8),
1000000000 >> 8);
if (!rsd && rs->rsd_nsecs) {
pr_warn_once("rockchip-spi: %u Hz are too slow to express %u ns delay\n",
rs->max_freq, rs->rsd_nsecs);
} else if (rsd > 3) {
rsd = 3;
pr_warn_once("rockchip-spi: %u Hz are too fast to express %u ns delay, clamping at %u ns\n",
rs->max_freq, rs->rsd_nsecs,
rsd * 1000000000U / rs->max_freq);
}
cr0 |= rsd << CR0_RSD_OFFSET;
/* write_relaxed()往寄存器写入值 */
writel_relaxed(cr0, rs->regs + ROCKCHIP_SPI_CTRLR0);
if (rs->n_bytes == 1)
writel_relaxed(rs->len - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);
else if (rs->n_bytes == 2)
writel_relaxed((rs->len / 2) - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);
else
writel_relaxed((rs->len * 2) - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);
writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_TXFTLR);
writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR);
writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_DMATDLR);
writel_relaxed(rockchip_spi_calc_burst_size(rs->len / rs->n_bytes) - 1,
rs->regs + ROCKCHIP_SPI_DMARDLR);
writel_relaxed(dmacr, rs->regs + ROCKCHIP_SPI_DMACR);
spi_set_clk(rs, div); //设置分频系数
dev_dbg(rs->dev, "cr0 0x%x, div %d\n", cr0, div);
}
9、如果想通过GPIO模拟的方式来控制对应的GPIO管脚,也可以在dts中关闭对应引脚的spi模式并复用为GPIO口后,通过gpio模拟的方式达到自己需要的功能;