Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1712065
  • 博文数量: 143
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1462
  • 用 户 组: 普通用户
  • 注册时间: 2016-08-23 11:14
文章分类

全部博文(143)

文章存档

2022年(3)

2021年(13)

2020年(21)

2019年(8)

2018年(28)

2017年(7)

2016年(63)

我的朋友

分类: 嵌入式

2016-08-27 16:30:40

背景介绍:ICETEK OMAPL138开发板的厂商提供的kernel.sdk中,默认只初始化了1个spi控制器,并挂载1个spi外设及spi外设驱动。而我们当前的项目需要,2个spi控制器,并分别挂多个spi外设。那么,我们先尝试在现有spi1控制器上,再挂一个spi外设,本文旨在于此。(其实,关于增加spi0控制器的开发工作,由于项目决定使用TI的OMAPL138,而我查看了TI官网推荐的kernel.sdk中,默认已经初始化好了spi0控制器和spi1控制器,所以这一步,在我们项目中没做)
本文参考:http://zch7811.blog.163.com/blog/static/1770522820135423251597/http://blog.sina.com.cn/s/blog_3fb7f7270102vbtx.html 基于ICETEK OMAPL138开发板来添加spi。
操作步骤:
  第一步,添加spi驱动。
  通过如下操作,将内核自带的spidev驱动加载到内核中:
sudo make menuconfig ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-
Device Drivers  ---> 
[*] SPI support  --->
<*>   SPI controller driver for DaVinci SoC's
<*>   User mode SPI device driver support
  第二步,添加spi设备。
  首先,由于spi的pin是和gpio复用的pin,所以需要添加spi的pin mux配置:(为什么只需要修改如下3个地方,请看我的另一篇关于pinmux的文章)
  在kernel.sdk/arch/arm/mach-davinci/include/mach/mux.h的enum davinci_da850_index 中,增加DA850_SPI1_CS_1:
        /* SPI1 function */
        DA850_SPI1_CS_0,
        DA850_SPI1_CS_1,
        DA850_SPI1_CLK,
        DA850_SPI1_SOMI,
        DA850_SPI1_SIMO,
  在kernel.sdk/arch/arm/mach-davinci/da850.c的static const struct mux_config da850_pins[]中,增加MUX_CFG(DA850, SPI1_CS_1,       5,      0,      15,     1,      false):
        /* SPI1 function */
        MUX_CFG(DA850, SPI1_CS_0,       5,      4,      15,     1,      false)
        MUX_CFG(DA850, SPI1_CS_1,       5,      0,      15,     1,      false)
        MUX_CFG(DA850, SPI1_CLK,        5,      8,      15,     1,      false)
        MUX_CFG(DA850, SPI1_SOMI,       5,      16,     15,     1,      false)
        MUX_CFG(DA850, SPI1_SIMO,       5,      20,     15,     1,      false)
  在kernel.sdk/arch/arm/mach-davinci/da850.c的const short da850_spi1_pins[] __initdata中,增加DA850_SPI1_CS_1:
        DA850_SPI1_CS_0, DA850_SPI1_CS_1, DA850_SPI1_CLK, DA850_SPI1_SOMI, DA850_SPI1_SIMO,
  其次,添加spi设备:
  增加一个名称为spidev的设备
static struct spi_board_info da850_spi_board_info[] = {
        [0] = {
                .modalias = "m25p80",
                .platform_data = &spi_flash_data,
                .mode = SPI_MODE_0,
                .max_speed_hz = 30000000,       /* max sample rate at 3V */
                .bus_num = 1,
                .chip_select = 0,
        },
        [1] = {
                .modalias = "spidev",
                .mode = SPI_MODE_3,
                .max_speed_hz = 30000000,       /* max sample rate at 3V */
                .bus_num = 1,
                .chip_select = 1,
        },
};
  一般情况下,通过如上2个步骤后,spi外设和spi外设驱动就会被挂载上去了,即:在/sys/bus/spi/devices/下多出个spi1.1;在/sys/bus/spi/drivers/下多出个spidev。并且,如果spi外设和spi外设驱动匹配成功,就会注册spi字符设备,即:在/dev/下多出个spidev1.1。然而,spi外设驱动的确挂载成功了,但是spi外设挂载失败了,也没有匹配成功。查看单板启动日志中有报错,接下来我们就一步步解决报错吧。

解决问题:
  新增后,会报错:spi_davinci spi_davinci.1: cs1 >= max 1
  通过一步步加打印调试,发现在:
int spi_add_device(struct spi_device *spi)
{
...
        if (spi->chip_select >= spi->master->num_chipselect)
...
}
  很明显,由于这里的master->num_chipselect,其能力被限制为1了。而当我们在da850_spi_board_info中增加一条后,这里spi->chip_select的取值依次为0,1,相应地需要把num_chipselect增加为2,那么num_chipselect在哪儿修改呢?
  通过直接分析函数调用关系:由于spi_add_device()<-spi_new_device()<-scan_boardinfo()<-spi_register_master()<-spi_bitbang_start()<-davinci_spi_probe(),那么到此我们就找到了master->num_chipselect被赋值的地方:
static int davinci_spi_probe(struct platform_device *pdev)
{
...
master->num_chipselect = pdata->num_chipselect;
...
}
  而在davinci_spi_probe()中的master->num_chipselect的值,就是通过传入的platform_device(即da850_spi1_device)参数赋值的。那么,很明显只需要修改da850_spi1_device中的num_chipselect的能力值即可。

  接着,又会报错:spi_davinci spi_davinci.1: can't setup spi1.1, status -11
  通过继续一步步加打印调试,或直接grep -rn can't setup,发现在:
int spi_add_device(struct spi_device *spi)
{
...
        status = spi_setup(spi);
        if (status < 0) {
                dev_err(dev, "can't %s %s, status %d\n",
                                "setup", dev_name(&spi->dev), status);
                goto done;
        }
...
}
  这里直接看不出来,需要继续往下分析调用关系。
  通过加打印调试分析函数调用出错的原始出处:由于spi_add_device()->spi_setup()->davinci_spi_setup(),而函数出错就是在如下:
static int davinci_spi_setup(struct spi_device *spi)
{
...
        if (use_dma && davinci_spi->dma_channels) {
                davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select];


                if ((davinci_spi_dma->dma_rx_channel == -1)
                                || (davinci_spi_dma->dma_tx_channel == -1)) {
                        retval = davinci_spi_request_dma(spi);
                        if (retval < 0)
                        {
                                return retval;
                        }
                }
        }
...
}
  感觉好像和use_dma有很大关系,进一步分析use_dma的调用关系,use_dma是个全局静态变量:
static unsigned use_dma;
  而use_dma唯一被赋值的地方:
static int davinci_spi_probe(struct platform_device *pdev)
{
...
use_dma = pdata->use_dma;
...
}
  而在davinci_spi_probe()中的use_dma的值,就是通过传入的platform_device(即da850_spi1_device)参数赋值的,这不就和如上第一个问题的修改点不谋而合了嘛!那么和第一个问题一样,我们修改da850_spi1_device中的use_dma的能力值为0试试。果然在/sys/bus/spi/devices/下多出个spi1.1,即是我们新增的spi外设,并且,在/dev/下多出个spidev1.1,即是匹配成功后新增的spi字符设备,那么表示成功了。至于为什么这里要修改dma,我怀疑一般的spi外设不需要配置这个东西,仅spi flash外设可配值。
  至此,在/sys/bus/spi/devices/下多出个spi1.1;在/sys/bus/spi/drivers/下多出个spidev;在/dev/下多出个spidev1.1。
阅读(4399) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~