码迷,mamicode.com
首页 > 系统相关 > 详细

linux设备驱动 spi详解3-控制器驱动

时间:2020-05-30 21:38:21      阅读:85      评论:0      收藏:0      [点我收藏+]

标签:ted   under   c中   clock   val   entry   int   mod   returns   

整个SPI驱动架构可以分为协议驱动、通用接口层和控制器驱动三大部分。其中,控制器驱动负责最底层的数据收发工作,为了完成数据的收发工作,控制器驱动需要完成以下这些功能:

(1)申请必要的硬件资源,例如中断,DMA通道,DMA内存缓冲区等等;

(2)配置SPI控制器的工作模式和参数,使之可以和相应的设备进行正确的数据交换工作;

(3)向通用接口层提供接口,使得上层的协议驱动可以通过通用接口层访问控制器驱动;

(4)配合通用接口层,完成数据消息队列的排队和处理,直到消息队列变空为止。

1 控制器设备platform_device

1.1 定义platform_device

SPI控制器遵循linux的设备模型框架,所以,一个SPI控制器在代码中对应一个挂在platfrom bus下面的一个device设备。所以在板级的代码中为SPI控制器定义一个platform_device结构即可。下面以Samsung的SOC芯片:S32440,做为例子,看看如何定义这个platform_device。以下的代码来自:arch\arm\mach-s3c24xx\mach-mini2440.c中:

因为会有多个platfrom device,所以定义为数组:

 1 static struct platform_device *mini2440_devices[] __initdata = {
 2     &s3c_device_ohci,
 3     &s3c_device_wdt,
 4     &s3c_device_i2c0,
 5     &s3c_device_rtc,
 6     &s3c_device_usbgadget,
 7     &mini2440_device_eth,
 8     &mini2440_led1,
 9     &mini2440_led2,
10     &mini2440_led3,
11     &mini2440_led4,
12     &mini2440_button_device,
13     &s3c_device_nand,
14     &s3c_device_sdi,
15     &s3c_device_iis,
16     &uda1340_codec,
17     &mini2440_audio,
18 };

 

上面数组中没有添加spi的platfrom,需要自己定义并添加。如下:

 1 struct platform_device s3c2440_device_spi0 = {
 2     .name        = "s3c6410-spi",
 3     .id        = 0,
 4     .num_resources    = ARRAY_SIZE(s3c64xx_spi0_resource),
 5     .resource    = s3c2440_spi0_resource,
 6     .dev = {
 7         .dma_mask        = &samsung_device_dma_mask,
 8         .coherent_dma_mask    = DMA_BIT_MASK(32),
 9     },
10 };

 

1 static struct resource s3c2440_spi0_resource[] = {
2     [0] = DEFINE_RES_MEM(S3C_PA_SPI0, SZ_256),
3     [1] = DEFINE_RES_DMA(DMACH_SPI0_TX),
4     [2] = DEFINE_RES_DMA(DMACH_SPI0_RX),
5     [3] = DEFINE_RES_IRQ(IRQ_SPI0),
6 };

 

然后还要定义s3c2440_spi0_resource.

最终在kernel初始化的是回去调用

 1 static void __init mini2440_init(void)
 2 {
 3     struct mini2440_features_t features = { 0 };
 4     int i;
 5 
 6     printk(KERN_INFO "MINI2440: Option string mini2440=%s\n",
 7             mini2440_features_str);
 8 
 9     /* Parse the feature string */
10     mini2440_parse_features(&features, mini2440_features_str);
11 
12     /* turn LCD on */
13     s3c_gpio_cfgpin(S3C2410_GPC(0), S3C2410_GPC0_LEND);
14 
15     /* Turn the backlight early on */
16     WARN_ON(gpio_request_one(S3C2410_GPG(4), GPIOF_OUT_INIT_HIGH, NULL));
17     gpio_free(S3C2410_GPG(4));
18 
19     /* remove pullup on optional PWM backlight -- unused on 3.5 and 7"s */
20     gpio_request_one(S3C2410_GPB(1), GPIOF_IN, NULL);
21     s3c_gpio_setpull(S3C2410_GPB(1), S3C_GPIO_PULL_UP);
22     gpio_free(S3C2410_GPB(1));
23 
24     /* mark the key as input, without pullups (there is one on the board) */
25     for (i = 0; i < ARRAY_SIZE(mini2440_buttons); i++) {
26         s3c_gpio_setpull(mini2440_buttons[i].gpio, S3C_GPIO_PULL_UP);
27         s3c_gpio_cfgpin(mini2440_buttons[i].gpio, S3C2410_GPIO_INPUT);
28     }
29     if (features.lcd_index != -1) {
30         int li;
31 
32         mini2440_fb_info.displays =
33             &mini2440_lcd_cfg[features.lcd_index];
34 
35         printk(KERN_INFO "MINI2440: LCD");
36         for (li = 0; li < ARRAY_SIZE(mini2440_lcd_cfg); li++)
37             if (li == features.lcd_index)
38                 printk(" [%d:%dx%d]", li,
39                     mini2440_lcd_cfg[li].width,
40                     mini2440_lcd_cfg[li].height);
41             else
42                 printk(" %d:%dx%d", li,
43                     mini2440_lcd_cfg[li].width,
44                     mini2440_lcd_cfg[li].height);
45         printk("\n");
46         s3c24xx_fb_set_platdata(&mini2440_fb_info);
47     }
48 
49     s3c24xx_udc_set_platdata(&mini2440_udc_cfg);
50     s3c24xx_mci_set_platdata(&mini2440_mmc_cfg);
51     s3c_nand_set_platdata(&mini2440_nand_info);
52     s3c_i2c0_set_platdata(NULL);
53 
54     i2c_register_board_info(0, mini2440_i2c_devs,
55                 ARRAY_SIZE(mini2440_i2c_devs));
56 
57     platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));
58 
59     if (features.count)    /* the optional features */
60         platform_add_devices(features.optional, features.count);
61 
62 }

 

2 spi的platform_driver

既然spi控制器是挂在platform下的device,有platform_device,肯定也要有platform_driver

定义位于:/drivers/spi/spi-s3c24xx.c

1 static struct platform_driver s3c24xx_spi_driver = {
2     .probe        = s3c24xx_spi_probe,
3     .remove        = s3c24xx_spi_remove,
4     .driver        = {
5         .name    = "s3c2410-spi",
6         .owner    = THIS_MODULE,
7         .pm    = S3C24XX_SPI_PMOPS,
8     },
9 };

 

然后注册spi platform_driver 

module_platform_driver(s3c24xx_spi_driver);

 

宏展开后:

定义为于:include\linux\Platform_device.h

#define module_platform_driver(__platform_driver) \
    module_driver(__platform_driver, platform_driver_register,             platform_driver_unregister)

 

最终展开为驱动的入口和出口:

#define module_driver(__driver, __register, __unregister, ...) static int __init __driver##_init(void) {     return __register(&(__driver) , ##__VA_ARGS__); } module_init(__driver##_init); static void __exit __driver##_exit(void) {     __unregister(&(__driver) , ##__VA_ARGS__); } module_exit(__driver##_exit);

 

3 platform_device和platform_driver的匹配

当platform_device或者platform_driver添加到platform_bus的时候会调用platform_match()去匹配。

static int platform_match(struct device *dev, struct device_driver *drv)
{
....
}

 

匹配成功就会调用probe函数s3c24xx_spi_probe() :

除了完成必要的硬件资源初始化工作以外,最重要的工作就是通过spi_bitbang_start()完成了对控制器的注册工作。

  1 static int s3c24xx_spi_probe(struct platform_device *pdev)
  2 {
  3     struct s3c2410_spi_info *pdata;
  4     struct s3c24xx_spi *hw;
  5     struct spi_master *master;
  6     struct resource *res;
  7     int err = 0;
  8 
  9     master = spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi));
 10     if (master == NULL) {
 11         dev_err(&pdev->dev, "No memory for spi_master\n");
 12         err = -ENOMEM;
 13         goto err_nomem;
 14     }
 15 
 16     hw = spi_master_get_devdata(master);
 17     memset(hw, 0, sizeof(struct s3c24xx_spi));
 18 
 19     hw->master = spi_master_get(master);
 20     hw->pdata = pdata = pdev->dev.platform_data;
 21     hw->dev = &pdev->dev;
 22 
 23     if (pdata == NULL) {
 24         dev_err(&pdev->dev, "No platform data supplied\n");
 25         err = -ENOENT;
 26         goto err_no_pdata;
 27     }
 28 
 29     platform_set_drvdata(pdev, hw);
 30     init_completion(&hw->done);
 31 
 32     /* initialise fiq handler */
 33 
 34     s3c24xx_spi_initfiq(hw);
 35 
 36     /* setup the master state. */
 37 
 38     /* the spi->mode bits understood by this driver: */
 39     master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
 40 
 41     master->num_chipselect = hw->pdata->num_cs;
 42     master->bus_num = pdata->bus_num;
 43 
 44     /* setup the state for the bitbang driver */
 45 
 46     hw->bitbang.master         = hw->master;
 47     hw->bitbang.setup_transfer = s3c24xx_spi_setupxfer;
 48     hw->bitbang.chipselect     = s3c24xx_spi_chipsel;
 49     hw->bitbang.txrx_bufs      = s3c24xx_spi_txrx;
 50 
 51     hw->master->setup  = s3c24xx_spi_setup;
 52     hw->master->cleanup = s3c24xx_spi_cleanup;
 53 
 54     dev_dbg(hw->dev, "bitbang at %p\n", &hw->bitbang);
 55 
 56     /* find and map our resources */
 57 
 58     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 59     if (res == NULL) {
 60         dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
 61         err = -ENOENT;
 62         goto err_no_iores;
 63     }
 64 
 65     hw->ioarea = request_mem_region(res->start, resource_size(res),
 66                     pdev->name);
 67 
 68     if (hw->ioarea == NULL) {
 69         dev_err(&pdev->dev, "Cannot reserve region\n");
 70         err = -ENXIO;
 71         goto err_no_iores;
 72     }
 73 
 74     hw->regs = ioremap(res->start, resource_size(res));
 75     if (hw->regs == NULL) {
 76         dev_err(&pdev->dev, "Cannot map IO\n");
 77         err = -ENXIO;
 78         goto err_no_iomap;
 79     }
 80 
 81     hw->irq = platform_get_irq(pdev, 0);
 82     if (hw->irq < 0) {
 83         dev_err(&pdev->dev, "No IRQ specified\n");
 84         err = -ENOENT;
 85         goto err_no_irq;
 86     }
 87 
 88     err = request_irq(hw->irq, s3c24xx_spi_irq, 0, pdev->name, hw);
 89     if (err) {
 90         dev_err(&pdev->dev, "Cannot claim IRQ\n");
 91         goto err_no_irq;
 92     }
 93 
 94     hw->clk = clk_get(&pdev->dev, "spi");
 95     if (IS_ERR(hw->clk)) {
 96         dev_err(&pdev->dev, "No clock for device\n");
 97         err = PTR_ERR(hw->clk);
 98         goto err_no_clk;
 99     }
100 
101     /* setup any gpio we can */
102 
103     if (!pdata->set_cs) {
104         if (pdata->pin_cs < 0) {
105             dev_err(&pdev->dev, "No chipselect pin\n");
106             err = -EINVAL;
107             goto err_register;
108         }
109 
110         err = gpio_request(pdata->pin_cs, dev_name(&pdev->dev));
111         if (err) {
112             dev_err(&pdev->dev, "Failed to get gpio for cs\n");
113             goto err_register;
114         }
115 
116         hw->set_cs = s3c24xx_spi_gpiocs;
117         gpio_direction_output(pdata->pin_cs, 1);
118     } else
119         hw->set_cs = pdata->set_cs;
120 
121     s3c24xx_spi_initialsetup(hw);
122 
123     /* register our spi controller */
124 
125     err = spi_bitbang_start(&hw->bitbang);//注册spi控制器,即spi_master
126     if (err) {
127         dev_err(&pdev->dev, "Failed to register SPI master\n");
128         goto err_register;
129     }
130 
131     return 0;
132 
133  err_register:
134     if (hw->set_cs == s3c24xx_spi_gpiocs)
135         gpio_free(pdata->pin_cs);
136 
137     clk_disable(hw->clk);
138     clk_put(hw->clk);
139 
140  err_no_clk:
141     free_irq(hw->irq, hw);
142 
143  err_no_irq:
144     iounmap(hw->regs);
145 
146  err_no_iomap:
147     release_resource(hw->ioarea);
148     kfree(hw->ioarea);
149 
150  err_no_iores:
151  err_no_pdata:
152     spi_master_put(hw->master);
153 
154  err_nomem:
155     return err;
156 }

 

4 注册spi控制器

 1 int spi_bitbang_start(struct spi_bitbang *bitbang)
 2 {
 3     struct spi_master *master = bitbang->master;
 4     int status;
 5 
 6     if (!master || !bitbang->chipselect)
 7         return -EINVAL;
 8 
 9     INIT_WORK(&bitbang->work, bitbang_work);
10     spin_lock_init(&bitbang->lock);
11     INIT_LIST_HEAD(&bitbang->queue);
12 
13     if (!master->mode_bits)
14         master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags;
15 
16     if (!master->transfer)
17         master->transfer = spi_bitbang_transfer;
18     if (!bitbang->txrx_bufs) {
19         bitbang->use_dma = 0;
20         bitbang->txrx_bufs = spi_bitbang_bufs;
21         if (!master->setup) {
22             if (!bitbang->setup_transfer)
23                 bitbang->setup_transfer =
24                      spi_bitbang_setup_transfer;
25             master->setup = spi_bitbang_setup;
26             master->cleanup = spi_bitbang_cleanup;
27         }
28     } else if (!master->setup)
29         return -EINVAL;
30     if (master->transfer == spi_bitbang_transfer &&
31             !bitbang->setup_transfer)
32         return -EINVAL;
33 
34     /* this task is the only thing to touch the SPI bits */
35     bitbang->busy = 0;
36     bitbang->workqueue = create_singlethread_workqueue(
37             dev_name(master->dev.parent));
38     if (bitbang->workqueue == NULL) {
39         status = -EBUSY;
40         goto err1;
41     }
42 
43     /* driver may get busy before register() returns, especially
44      * if someone registered boardinfo for devices
45      */
46     status = spi_register_master(master);//注册spi控制器
47     if (status < 0)
48         goto err2;
49 
50     return status;
51 
52 err2:
53     destroy_workqueue(bitbang->workqueue);
54 err1:
55     return status;
56 }

 

4.2  spi_register_master

 1 int spi_register_master(struct spi_master *master)
 2 {
 3     static atomic_t        dyn_bus_id = ATOMIC_INIT((1<<15) - 1);
 4     struct device        *dev = master->dev.parent;
 5     struct boardinfo    *bi;
 6     int            status = -ENODEV;
 7     int            dynamic = 0;
 8 
 9     if (!dev)
10         return -ENODEV;
11 
12     status = of_spi_register_master(master);
13     if (status)
14         return status;
15 
16     /* even if it‘s just one always-selected device, there must
17      * be at least one chipselect
18      */
19     if (master->num_chipselect == 0)
20         return -EINVAL;
21 
22     if ((master->bus_num < 0) && master->dev.of_node)
23         master->bus_num = of_alias_get_id(master->dev.of_node, "spi");
24 
25     /* convention:  dynamically assigned bus IDs count down from the max */
26     if (master->bus_num < 0) {
27         /* FIXME switch to an IDR based scheme, something like
28          * I2C now uses, so we can‘t run out of "dynamic" IDs
29          */
30         master->bus_num = atomic_dec_return(&dyn_bus_id);
31         dynamic = 1;
32     }
33 
34     spin_lock_init(&master->bus_lock_spinlock);
35     mutex_init(&master->bus_lock_mutex);
36     master->bus_lock_flag = 0;
37 
38     /* register the device, then userspace will see it.
39      * registration fails if the bus ID is in use.
40      */
41     dev_set_name(&master->dev, "spi%u", master->bus_num);
42     status = device_add(&master->dev);
43     if (status < 0)
44         goto done;
45     dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev),
46             dynamic ? " (dynamic)" : "");
47 
48     /* If we‘re using a queued driver, start the queue */
49     if (master->transfer)
50         dev_info(dev, "master is unqueued, this is deprecated\n");
51     else {
52         status = spi_master_initialize_queue(master);
53         if (status) {
54             device_unregister(&master->dev);
55             goto done;
56         }
57     }
58 
59     mutex_lock(&board_lock);
60     list_add_tail(&master->list, &spi_master_list);
61     list_for_each_entry(bi, &board_list, list)
62         spi_match_master_to_boardinfo(master, &bi->board_info);
63     mutex_unlock(&board_lock);
64 
65     /* Register devices from the device tree and ACPI */
66     of_register_spi_devices(master);
67     acpi_register_spi_devices(master);
68 done:
69     return status;
70 }

 

然后调用spi_match_master_to_boardinfo

 1 static void spi_match_master_to_boardinfo(struct spi_master *master,
 2                 struct spi_board_info *bi)
 3 {
 4     struct spi_device *dev;
 5 
 6     if (master->bus_num != bi->bus_num)
 7         return;
 8 
 9     dev = spi_new_device(master, bi);//注册spi_device
10     if (!dev)
11         dev_err(master->dev.parent, "can‘t create new device for %s\n",
12             bi->modalias);
13 }

 

调用spi_new_device 注册spi设备。详见: linux设备驱动SPI详解2-通用接口层 , 将spi_device添加到spi_bus上。

所以对于spi来说,spi_masterspi控制器是挂在platform虚拟总线上,但同时spi同时又有自己的bus。

(追寻spi_init也就是spi_bus) 

5 实现spi_master中的回调函数

事实上,SPI控制器驱动程序的主要工作,就是要实现spi_master结构中的几个回调函数,其它的工作逻辑,均由通用接口层帮我们完成,通用接口层会在适当的时机调用这几个回调函数,各个回调函数的作用如下,具体的实现例子位于:drivers\spi\Spi-s3c24xx.c

int (*setup)(struct spi_device *spi)
当协议驱动希望修改控制器的工作模式或参数时,会调用通用接口层提供的API:spi_setup(),该API函数最后会调用setup回调函数来完成设置工作。
int (*transfer)(struct spi_device *spi, struct spi_message *mesg)
目前已经可以不用我们自己实现该回调函数,初始化时直接设为NULL即可,目前的通用接口层已经实现了消息队列化,注册spi_master时,通用接口层会提供实现好的通用函数。现在只有一些老的驱动还在使用该回调方式,新的驱动应该停止使用该回调函数,而是应该使用队列化的transfer_one_message回调。需要注意的是,我们只能选择其中一种方式,设置了transfer_one_message回调,就不能设置transfer回调,反之亦然。

void (*cleanup)(struct spi_device *spi)
当一个SPI从设备(spi_device结构)被释放时,该回调函数会被调用,以便释放该从设备所占用的硬件资源。

int (*prepare_transfer_hardware)(struct spi_master *master)
int (*unprepare_transfer_hardware)(struct spi_master *master)
这两个回调函数用于在发起一个数据传送过程前和后,给控制器驱动一个机会,申请或释放某些必要的硬件资源,例如DMA资源和内存资源等等。int (*transfer_one_message)(struct spi_master *master, struct spi_message *mesg)
当通用接口层发现master的队列中有消息需要传送时,会调用该回调函数,所以该函数是真正完成一个消息传送的工作函数,当传送工作完成时,应该调用spi_finalize_current_message函数,以便通知通用接口层,发起队列中的下一个消息的传送工作。

参考博文:https://blog.csdn.net/DroidPhone/java/article/details/24353293

 

linux设备驱动 spi详解3-控制器驱动

标签:ted   under   c中   clock   val   entry   int   mod   returns   

原文地址:https://www.cnblogs.com/xinghuo123/p/12994825.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!