SPI驱动之主控制器驱动程序

嵌入式微处理器访问SPI设备有两种方式:使用GPIO模拟SPI接口的工作时序或者使用SPI控制器。使用GPIO模拟SPI接口的工作时序是非常容易实现的,但是会导致大量的时间耗费在模拟SPI接口的时序上,访问效率比较低,容易成为系统瓶颈。这里主要分析使用SPI控制器的情况。

在内核的drivers/spi/目录下有两个spi主控制器驱动程序:spi_s3c24xx.c和spi_s3c24xx_gpio.c其中spi_s3c24xx.c是基于s3c24xx下相应的spi接口的驱动程序,spi_s3c24xx_gpio.c运行用户指定3个gpio口分别充当spi_clk、spi_mosi和spi_miso接口,模拟标准的spi总线。UT4412BV01开发板预留了两路的spi接口(spi0和spi1),对于UT4412BV01开发板而言,使用的是spi_s3c64xx.c,也就是硬件SPI,不是软件SPI。注:下面是基于硬件SPI的spi1分析。

1. 定义platform device

kernel3.0.15/arch/arm/mach-exynos/dev-spi.c

static struct resource exynos_spi1_resource[] = {
	[0] = {
		.start = EXYNOS_PA_SPI1,
		.end   = EXYNOS_PA_SPI1 + 0x100 - 1,
		.flags = IORESOURCE_MEM,
	},
	[1] = {
		.start = DMACH_SPI1_TX,
		.end   = DMACH_SPI1_TX,
		.flags = IORESOURCE_DMA,
	},
	[2] = {
		.start = DMACH_SPI1_RX,
		.end   = DMACH_SPI1_RX,
		.flags = IORESOURCE_DMA,
	},
	[3] = {
		.start = IRQ_SPI1,
		.end   = IRQ_SPI1,
		.flags = IORESOURCE_IRQ,
	},
};

static struct s3c64xx_spi_info exynos_spi1_pdata = {
	.cfg_gpio = exynos_spi_cfg_gpio,
	.fifo_lvl_mask = 0x7f,
	.rx_lvl_offset = 15,
	.high_speed = 1,
	.clk_from_cmu = true,
	.tx_st_done = 25,
};

struct platform_device exynos_device_spi1 = {
	.name		  = "s3c64xx-spi",
	.id		  = 1,
	.num_resources	  = ARRAY_SIZE(exynos_spi1_resource),
	.resource	  = exynos_spi1_resource,
	.dev = {
		.dma_mask		= &spi_dmamask,
		.coherent_dma_mask	= DMA_BIT_MASK(32),
		.platform_data = &exynos_spi1_pdata,
	},
};
exynos4412总共定义了三个spi控制器平台设备,实际上UT4412BV01开发板只预留了两个spi控制器(spi0和spi1)。platform设备给出了spi1接口的寄存器地址资源及IRQ资源。 注意其设备名为s3c64xx-spi

2. 定义platform driver

kernel3.0.15/drivers/spi/spi_s3c64xx.c

static struct platform_driver s3c64xx_spi_driver = {
	.driver = {
		.name	= "s3c64xx-spi",
		.owner = THIS_MODULE,
	},
	.remove = s3c64xx_spi_remove,
	.suspend = s3c64xx_spi_suspend,
	.resume = s3c64xx_spi_resume,
};
MODULE_ALIAS("platform:s3c64xx-spi");

static int __init s3c64xx_spi_init(void)
{
	//设备不可热插拔,所以使用该函数,而不是platform_driver_register
	return platform_driver_probe(&s3c64xx_spi_driver, s3c64xx_spi_probe);
}
subsys_initcall(s3c64xx_spi_init);

static void __exit s3c64xx_spi_exit(void)
{
	platform_driver_unregister(&s3c64xx_spi_driver);
}
module_exit(s3c64xx_spi_exit);

MODULE_AUTHOR("Jaswinder Singh <jassi.brar@samsung.com>");
MODULE_DESCRIPTION("S3C64XX SPI Controller Driver");
MODULE_LICENSE("GPL");
调用了platform_driver_probe注册platform驱动,注册完成以后将会调用platform的s3c64xx_spi_probe函数。 注意:platform驱动的name和platform device的name是相同的

3. s3c64xx_spi_probe函数

kernel3.0.15/drivers/spi/spi_s3c64xx.c

当exynos_device_spi1中的name与s3c64xx_spi_driver中的name相同时,也就是是设备名字跟驱动名字可以匹配,s3c64xx_spi_probe驱动探测函数被调用,该函数代码如下所示:

static int __init s3c64xx_spi_probe(struct platform_device *pdev)
{
	struct resource	*mem_res, *dmatx_res, *dmarx_res;
	struct s3c64xx_spi_driver_data *sdd;
	struct s3c64xx_spi_info *sci;
	struct spi_master *master;
	int ret;

	if (pdev->id < 0) { //pdev->id = 1
		dev_err(&pdev->dev,
				"Invalid platform device id-%d\n", pdev->id);
		return -ENODEV;
	}

	if (pdev->dev.platform_data == NULL) { //pdev->dev.platform_data = &exynos_spi1_pdata
		dev_err(&pdev->dev, "platform_data missing!\n");
		return -ENODEV;
	}

	sci = pdev->dev
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值