二十一、spi驱动框架及驱动代码分析

一、spi驱动框架简介

 

  • spi核心层

    提供spi控制器驱动和设备驱动的注册方法、注销方法、spi通信硬件无关接口

  • spi主机驱动

    主要包含spi硬件体系结构中适配器(spi控制器)的控制,用于产生spi读写时序。

  • spi设备驱动

   通过spi主机驱动与CPU交换数据。

 

 二、驱动源码分析

1、spidev.c

(1)初始化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
static int __init spidev_init(void)
{
    int status;
 
    /* Claim our 256 reserved device numbers.  Then register a class
     * that will key udev/mdev to add/remove /dev nodes.  Last, register
     * the driver which manages those device numbers.
     */
    BUILD_BUG_ON(N_SPI_MINORS > 256);
    status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops);  //注册字符设备
    if (status < 0)
        return status;
 
    spidev_class = class_create(THIS_MODULE, "spidev");  //创建设备类
    if (IS_ERR(spidev_class)) {
        unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
        return PTR_ERR(spidev_class);
    }
 
    status = spi_register_driver(&spidev_spi_driver);  //注册spi驱动
    if (status < 0) {
        class_destroy(spidev_class);
        unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
    }
    return status;
}
(2)spi驱动定义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
static struct spi_driver spidev_spi_driver = {
    .driver = {
        .name =     "spidev",
        .of_match_table = of_match_ptr(spidev_dt_ids),
        .acpi_match_table = ACPI_PTR(spidev_acpi_ids),
    },
    .probe =    spidev_probe,
    .remove =   spidev_remove,
 
    /* NOTE:  suspend/resume methods are not necessary here.
     * We don't do anything except pass the requests to/from
     * the underlying controller.  The refrigerator handles
     * most issues; the controller driver handles the rest.
     */
};
(3)spidev_probe  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
static int spidev_probe(struct spi_device *spi)
{
    struct spidev_data  *spidev;
    int         status;
    unsigned long       minor;
 
    /*
     * spidev should never be referenced in DT without a specific
     * compatible string, it is a Linux implementation thing
     * rather than a description of the hardware.
     */
    WARN(spi->dev.of_node &&
         of_device_is_compatible(spi->dev.of_node, "spidev"),
         "%pOF: buggy DT: spidev listed directly in DT\n", spi->dev.of_node);
 
    spidev_probe_acpi(spi);
 
    /* Allocate driver data */
    spidev = kzalloc(sizeof(*spidev), GFP_KERNEL);
    if (!spidev)
        return -ENOMEM;
 
    /* Initialize the driver data */
    spidev->spi = spi;
    spin_lock_init(&spidev->spi_lock);
    mutex_init(&spidev->buf_lock);
 
    INIT_LIST_HEAD(&spidev->device_entry);
 
    /* If we can allocate a minor number, hook up this device.
     * Reusing minors is fine so long as udev or mdev is working.
     */
    mutex_lock(&device_list_lock);
    minor = find_first_zero_bit(minors, N_SPI_MINORS);
    if (minor < N_SPI_MINORS) {  //次设备号小于32
        struct device *dev;
 
        spidev->devt = MKDEV(SPIDEV_MAJOR, minor);          //创建spi设备
        dev = device_create(spidev_class, &spi->dev, spidev->devt,
                    spidev, "spidev%d.%d",
                    spi->master->bus_num, spi->chip_select);
        status = PTR_ERR_OR_ZERO(dev);
    } else {
        dev_dbg(&spi->dev, "no minor number available!\n");
        status = -ENODEV;
    }
    if (status == 0) {
        set_bit(minor, minors);
        list_add(&spidev->device_entry, &device_list);
    }
    mutex_unlock(&device_list_lock);
 
    spidev->speed_hz = spi->max_speed_hz;   //设置最大速率
 
    if (status == 0)
        spi_set_drvdata(spi, spidev);  //设置设备驱动数据
    else
        kfree(spidev);
 
    return status;
}
(4)spidev_remove
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
static int spidev_remove(struct spi_device *spi)
{
    struct spidev_data  *spidev = spi_get_drvdata(spi);
 
    /* prevent new opens */
    mutex_lock(&device_list_lock);
    /* make sure ops on existing fds can abort cleanly */
    spin_lock_irq(&spidev->spi_lock);
    spidev->spi = NULL;
    spin_unlock_irq(&spidev->spi_lock);
 
    list_del(&spidev->device_entry);
    device_destroy(spidev_class, spidev->devt);
    clear_bit(MINOR(spidev->devt), minors);
    if (spidev->users == 0)
        kfree(spidev);
    mutex_unlock(&device_list_lock);
 
    return 0;
}
(5)spi设备文件操作集合
1
2
3
4
5
6
7
8
9
10
11
12
13
14
static const struct file_operations spidev_fops = {
    .owner =    THIS_MODULE,
    /* REVISIT switch to aio primitives, so that userspace
     * gets more complete API coverage.  It'll simplify things
     * too, except for the locking.
     */
    .write =    spidev_write,
    .read =     spidev_read,
    .unlocked_ioctl = spidev_ioctl,
    .compat_ioctl = spidev_compat_ioctl,
    .open =     spidev_open,
    .release =  spidev_release,
    .llseek =   no_llseek,
};
(6)读操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/* Read-only message with current device setup */
static ssize_t
spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
    struct spidev_data  *spidev;
    ssize_t         status = 0;
 
    /* chipselect only toggles at start or end of operation */
    if (count > bufsiz)
        return -EMSGSIZE;
 
    spidev = filp->private_data;
 
    mutex_lock(&spidev->buf_lock);
    status = spidev_sync_read(spidev, count);
    if (status > 0) {
        unsigned long   missing;
 
        missing = copy_to_user(buf, spidev->rx_buffer, status);
        if (missing == status)
            status = -EFAULT;
        else
            status = status - missing;
    }
    mutex_unlock(&spidev->buf_lock);
 
    return status;
} 
1
spidev_sync_read:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
static inline ssize_t
spidev_sync_read(struct spidev_data *spidev, size_t len)
{
    struct spi_transfer t = {
            .rx_buf     = spidev->rx_buffer,
            .len        = len,
            .speed_hz   = spidev->speed_hz,
        };
    struct spi_message  m;
 
    spi_message_init(&m);
    spi_message_add_tail(&t, &m);
    return spidev_sync(spidev, &m);
}
(7)写操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/* Write-only message with current device setup */
static ssize_t
spidev_write(struct file *filp, const char __user *buf,
        size_t count, loff_t *f_pos)
{
    struct spidev_data  *spidev;
    ssize_t         status = 0;
    unsigned long       missing;
 
    /* chipselect only toggles at start or end of operation */
    if (count > bufsiz)
        return -EMSGSIZE;
 
    spidev = filp->private_data;
 
    mutex_lock(&spidev->buf_lock);
    missing = copy_from_user(spidev->tx_buffer, buf, count);
    if (missing == 0)
        status = spidev_sync_write(spidev, count);
    else
        status = -EFAULT;
    mutex_unlock(&spidev->buf_lock);
 
    return status;
}
1
spidev_sync_write:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
static inline ssize_t
spidev_sync_write(struct spidev_data *spidev, size_t len)
{
    struct spi_transfer t = {
            .tx_buf     = spidev->tx_buffer,
            .len        = len,
            .speed_hz   = spidev->speed_hz,
        };
    struct spi_message  m;
 
    spi_message_init(&m);
    spi_message_add_tail(&t, &m);
    return spidev_sync(spidev, &m);
}
(8)spidev_ioctl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
static long
spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
    int         retval = 0;
    struct spidev_data  *spidev;
    struct spi_device   *spi;
    u32         tmp;
    unsigned        n_ioc;
    struct spi_ioc_transfer *ioc;
 
    /* Check type and command number */
    if (_IOC_TYPE(cmd) != SPI_IOC_MAGIC)
        return -ENOTTY;
 
    /* guard against device removal before, or while,
     * we issue this ioctl.
     */
    spidev = filp->private_data;
    spin_lock_irq(&spidev->spi_lock);
    spi = spi_dev_get(spidev->spi);
    spin_unlock_irq(&spidev->spi_lock);
 
    if (spi == NULL)
        return -ESHUTDOWN;
 
    /* use the buffer lock here for triple duty:
     *  - prevent I/O (from us) so calling spi_setup() is safe;
     *  - prevent concurrent SPI_IOC_WR_* from morphing
     *    data fields while SPI_IOC_RD_* reads them;
     *  - SPI_IOC_MESSAGE needs the buffer locked "normally".
     */
    mutex_lock(&spidev->buf_lock);
 
    switch (cmd) {
    /* read requests */读取spi的属性
    case SPI_IOC_RD_MODE:   //读取spi mode
        retval = put_user(spi->mode & SPI_MODE_MASK,
                    (__u8 __user *)arg);
        break;
    case SPI_IOC_RD_MODE32:
        retval = put_user(spi->mode & SPI_MODE_MASK,
                    (__u32 __user *)arg);
        break;
    case SPI_IOC_RD_LSB_FIRST:  //读取spi是低位优先还是高位优先
        retval = put_user((spi->mode & SPI_LSB_FIRST) ?  1 : 0,
                    (__u8 __user *)arg);
        break;
    case SPI_IOC_RD_BITS_PER_WORD:   //读取每个字 的bit位数
        retval = put_user(spi->bits_per_word, (__u8 __user *)arg);
        break;
    case SPI_IOC_RD_MAX_SPEED_HZ:  //最大速率
        retval = put_user(spidev->speed_hz, (__u32 __user *)arg);
        break;
 
    /* write requests */  这是对应的写,用于设置spi属性
    case SPI_IOC_WR_MODE:
    case SPI_IOC_WR_MODE32:
        if (cmd == SPI_IOC_WR_MODE)
            retval = get_user(tmp, (u8 __user *)arg);
        else
            retval = get_user(tmp, (u32 __user *)arg);
        if (retval == 0) {
            struct spi_controller *ctlr = spi->controller;
            u32 save = spi->mode;
 
            if (tmp & ~SPI_MODE_MASK) {
                retval = -EINVAL;
                break;
            }
 
            if (ctlr->use_gpio_descriptors && ctlr->cs_gpiods &&
                ctlr->cs_gpiods[spi->chip_select])
                tmp |= SPI_CS_HIGH;
 
            tmp |= spi->mode & ~SPI_MODE_MASK;
            spi->mode = (u16)tmp;
            retval = spi_setup(spi);
            if (retval < 0)
                spi->mode = save;
            else
                dev_dbg(&spi->dev, "spi mode %x\n", tmp);
        }
        break;
    case SPI_IOC_WR_LSB_FIRST:
        retval = get_user(tmp, (__u8 __user *)arg);
        if (retval == 0) {
            u32 save = spi->mode;
 
            if (tmp)
                spi->mode |= SPI_LSB_FIRST;
            else
                spi->mode &= ~SPI_LSB_FIRST;
            retval = spi_setup(spi);
            if (retval < 0)
                spi->mode = save;
            else
                dev_dbg(&spi->dev, "%csb first\n",
                        tmp ? 'l' : 'm');
        }
        break;
    case SPI_IOC_WR_BITS_PER_WORD:
        retval = get_user(tmp, (__u8 __user *)arg);
        if (retval == 0) {
            u8  save = spi->bits_per_word;
 
            spi->bits_per_word = tmp;
            retval = spi_setup(spi);
            if (retval < 0)
                spi->bits_per_word = save;
            else
                dev_dbg(&spi->dev, "%d bits per word\n", tmp);
        }
        break;
    case SPI_IOC_WR_MAX_SPEED_HZ:
        retval = get_user(tmp, (__u32 __user *)arg);
        if (retval == 0) {
            u32 save = spi->max_speed_hz;
 
            spi->max_speed_hz = tmp;
            retval = spi_setup(spi);
            if (retval >= 0)
                spidev->speed_hz = tmp;
            else
                dev_dbg(&spi->dev, "%d Hz (max)\n", tmp);
            spi->max_speed_hz = save;
        }
        break;
 
    default:
        /* segmented and/or full-duplex I/O request */
        /* Check message and copy into scratch area */
        ioc = spidev_get_ioc_message(cmd,
                (struct spi_ioc_transfer __user *)arg, &n_ioc);
        if (IS_ERR(ioc)) {
            retval = PTR_ERR(ioc);
            break;
        }
        if (!ioc)
            break/* n_ioc is also 0 */
 
        /* translate to spi_message, execute */
        retval = spidev_message(spidev, ioc, n_ioc);
        kfree(ioc);
        break;
    }
 
    mutex_unlock(&spidev->buf_lock);
    spi_dev_put(spi);
    return retval;
}

  

2、spi平台驱动程序分析:spi_sun6i.c

(1)平台驱动定义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
static const struct dev_pm_ops sun6i_spi_pm_ops = {
    .runtime_resume     = sun6i_spi_runtime_resume,
    .runtime_suspend    = sun6i_spi_runtime_suspend,
};
 
static struct platform_driver sun6i_spi_driver = {
    .probe  = sun6i_spi_probe,
    .remove = sun6i_spi_remove,
    .driver = {
        .name       = "sun6i-spi",
        .of_match_table = sun6i_spi_match,
        .pm     = &sun6i_spi_pm_ops,
    },
}
(2)sun6i_spi_probe
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
static int sun6i_spi_probe(struct platform_device *pdev)
{
    struct spi_master *master;
    struct sun6i_spi *sspi;
    int ret = 0, irq;
 
    master = spi_alloc_master(&pdev->dev, sizeof(struct sun6i_spi));
    if (!master) {
        dev_err(&pdev->dev, "Unable to allocate SPI Master\n");
        return -ENOMEM;
    }
 
    platform_set_drvdata(pdev, master);
    sspi = spi_master_get_devdata(master);
         //获取平台设备的io资源
    sspi->base_addr = devm_platform_ioremap_resource(pdev, 0);
    if (IS_ERR(sspi->base_addr)) {
        ret = PTR_ERR(sspi->base_addr);
        goto err_free_master;
    }
       //获取irq资源
    irq = platform_get_irq(pdev, 0);
    if (irq < 0) {
        ret = -ENXIO;
        goto err_free_master;
    }
        //申请中断
    ret = devm_request_irq(&pdev->dev, irq, sun6i_spi_handler,
                   0, "sun6i-spi", sspi);
    if (ret) {
        dev_err(&pdev->dev, "Cannot request IRQ\n");
        goto err_free_master;
    }
 
    sspi->master = master;
    sspi->fifo_depth = (unsigned long)of_device_get_match_data(&pdev->dev);
    //spi主机的初始化
    master->max_speed_hz = 100 * 1000 * 1000;   //spi主机最大速率 100Mhz
    master->min_speed_hz = 3 * 1000;       //spi主机最小速率3000hz 
    master->set_cs = sun6i_spi_set_cs;          //设置片选引脚信号
    master->transfer_one = sun6i_spi_transfer_one;  //发送一个spi消息
    master->num_chipselect = 4;     //有4个片选信号
    master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;   //spi模式
    master->bits_per_word_mask = SPI_BPW_MASK(8);  //发送一个字8个字节
    master->dev.of_node = pdev->dev.of_node;     //设备节点
    master->auto_runtime_pm = true;
    master->max_transfer_size = sun6i_spi_max_transfer_size;  //最多发送的字节个数  0xffffff-1
 
    sspi->hclk = devm_clk_get(&pdev->dev, "ahb");    //获取AHB总线的clk
    if (IS_ERR(sspi->hclk)) {
        dev_err(&pdev->dev, "Unable to acquire AHB clock\n");
        ret = PTR_ERR(sspi->hclk);
        goto err_free_master;
    }
 
    sspi->mclk = devm_clk_get(&pdev->dev, "mod");   //获取模块clock
    if (IS_ERR(sspi->mclk)) {
        dev_err(&pdev->dev, "Unable to acquire module clock\n");
        ret = PTR_ERR(sspi->mclk);
        goto err_free_master;
    }
 
    init_completion(&sspi->done);
//获取复位控制器
    sspi->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
    if (IS_ERR(sspi->rstc)) {
        dev_err(&pdev->dev, "Couldn't get reset controller\n");
        ret = PTR_ERR(sspi->rstc);
        goto err_free_master;
    }
 
    /*
     * This wake-up/shutdown pattern is to be able to have the
     * device woken up, even if runtime_pm is disabled
     */           //恢复spi设备
    ret = sun6i_spi_runtime_resume(&pdev->dev);
    if (ret) {
        dev_err(&pdev->dev, "Couldn't resume the device\n");
        goto err_free_master;
    }
 
    pm_runtime_set_active(&pdev->dev);
    pm_runtime_enable(&pdev->dev);
    pm_runtime_idle(&pdev->dev);
       //注册spi主机
    ret = devm_spi_register_master(&pdev->dev, master);
    if (ret) {
        dev_err(&pdev->dev, "cannot register SPI master\n");
        goto err_pm_disable;
    }
 
    return 0;
 
err_pm_disable:
    pm_runtime_disable(&pdev->dev);
    sun6i_spi_runtime_suspend(&pdev->dev);
err_free_master:
    spi_master_put(master);
    return ret;
} 

 

  • sun6i_spi_remove
1
2
3
4
5
6
7
static int sun6i_spi_remove(struct platform_device *pdev)
{
     //强制挂机
    pm_runtime_force_suspend(&pdev->dev);
 
    return 0;
} 

 

  • sun6i_spi_match
1
2
3
4
5
static const struct of_device_id sun6i_spi_match[] = {
    { .compatible = "allwinner,sun6i-a31-spi", .data = (void *)SUN6I_FIFO_DEPTH },
    { .compatible = "allwinner,sun8i-h3-spi",  .data = (void *)SUN8I_FIFO_DEPTH },
    {}
};
(3)spi_device结构体
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
//spi.h
struct spi_device {
    struct device       dev;      //spi设备
    struct spi_controller   *controller;    //spi控制器
    struct spi_controller   *master;    /* compatibility layer */ spi的 复制,为了向后兼容
    u32         max_speed_hz; 
    u8          chip_select;    //Chipselect, distinguishing chips
    u8          bits_per_word;  //定义每个字的bits位数,由spi协议决定
    bool            rt;  //使pump线程实时优先
    u32         mode;   //spi模式
#define SPI_CPHA    0x01            /* clock phase */
#define SPI_CPOL    0x02            /* clock polarity */
#define SPI_MODE_0  (0|0)           /* (original MicroWire) */
#define SPI_MODE_1  (0|SPI_CPHA)
#define SPI_MODE_2  (SPI_CPOL|0)
#define SPI_MODE_3  (SPI_CPOL|SPI_CPHA)
#define SPI_CS_HIGH 0x04            /* chipselect active high? */
#define SPI_LSB_FIRST   0x08            /* per-word bits-on-wire */
#define SPI_3WIRE   0x10            /* SI/SO signals shared */
#define SPI_LOOP    0x20            /* loopback mode */
#define SPI_NO_CS   0x40            /* 1 dev/bus, no chipselect */
#define SPI_READY   0x80            /* slave pulls low to pause */
#define SPI_TX_DUAL 0x100           /* transmit with 2 wires */
#define SPI_TX_QUAD 0x200           /* transmit with 4 wires */
#define SPI_RX_DUAL 0x400           /* receive with 2 wires */
#define SPI_RX_QUAD 0x800           /* receive with 4 wires */
#define SPI_CS_WORD 0x1000          /* toggle cs after each word */
#define SPI_TX_OCTAL    0x2000          /* transmit with 8 wires */
#define SPI_RX_OCTAL    0x4000          /* receive with 8 wires */
#define SPI_3WIRE_HIZ   0x8000          /* high impedance turnaround */
    int         irq;    //中断号
    void            *controller_state;   //控制器的实时状态
    void            *controller_data;
    char            modalias[SPI_NAME_SIZE];  //驱动别名
    const char      *driver_override;
    int         cs_gpio;    /* LEGACY: chip select gpio */
    struct gpio_desc    *cs_gpiod;  /* chip select gpio desc */
    uint8_t         word_delay_usecs; //每个字数据之间的微秒延时
 
    /* the statistics */
    struct spi_statistics   statistics;  //spi传输的统计信息,包括传输的数据信息
 
    /*
     * likely need more hooks for more protocol options affecting how
     * the controller talks to each chip, like:
     *  - memory packing (12 bit samples into low bits, others zeroed)
     *  - priority
     *  - chipselect delays
     *  - ...
     */
}; 

2、spi.c

(1)spi_init
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//spi.c
static int __init spi_init(void)
{
    int status;
 
    buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
    if (!buf) {
        status = -ENOMEM;
        goto err0;
    }
 
    status = bus_register(&spi_bus_type);   //总线注册,注册后,可以在/sys/bus目录下看到注册的总线
    if (status < 0)
        goto err1;
      //注册spi主机类
    status = class_register(&spi_master_class);  //
    if (status < 0)
        goto err2;
        //注册从机类
    if (IS_ENABLED(CONFIG_SPI_SLAVE)) {
        status = class_register(&spi_slave_class);
        if (status < 0)
            goto err3;
    }
 
    if (IS_ENABLED(CONFIG_OF_DYNAMIC))
        WARN_ON(of_reconfig_notifier_register(&spi_of_notifier));
    if (IS_ENABLED(CONFIG_ACPI))
        WARN_ON(acpi_reconfig_notifier_register(&spi_acpi_notifier));
 
    return 0;
 
err3:
    class_unregister(&spi_master_class);
err2:
    bus_unregister(&spi_bus_type);
err1:
    kfree(buf);
    buf = NULL;
err0:
    return status;
}
(2)spi_bus_type定义:
1
2
3
4
5
6
struct bus_type spi_bus_type = {
    .name       = "spi",    //总线名
    .dev_groups = spi_dev_groups,  //设备组
    .match      = spi_match_device,   //spi匹配
    .uevent     = spi_uevent, 
}; 
  • spi_match_device :spi设备和驱动的匹配方式, 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
static int spi_match_device(struct device *dev, struct device_driver *drv)
{
    const struct spi_device *spi = to_spi_device(dev);
    const struct spi_driver *sdrv = to_spi_driver(drv);
       //通过spi设备名和驱动名进行匹配
    /* Check override first, and if set, only use the named driver */
    if (spi->driver_override)
        return strcmp(spi->driver_override, drv->name) == 0;
 
    /* Attempt an OF style match */
    if (of_driver_match_device(dev, drv))  //设备树中compatiable属性和驱动名进行匹配
        return 1;
 
    /* Then try ACPI */
    if (acpi_driver_match_device(dev, drv))  //acpi匹配 
        return 1;
 
    if (sdrv->id_table)
        return !!spi_match_id(sdrv->id_table, spi);  //通过驱动别名来进行匹配
 
    return strcmp(spi->modalias, drv->name) == 0;
}
  • spi_uevent
1
2
3
4
5
6
7
8
9
10
11
static int spi_uevent(struct device *dev, struct kobj_uevent_env *env)
{
    const struct spi_device     *spi = to_spi_device(dev);
    int rc;
 
    rc = acpi_device_uevent_modalias(dev, env);
    if (rc != -ENODEV)
        return rc;
 
    return add_uevent_var(env, "MODALIAS=%s%s", SPI_MODULE_PREFIX, spi->modalias);
}
(3)spi_master_class定义:
1
2
3
4
5
6
static struct class spi_master_class = {
    .name       = "spi_master",
    .owner      = THIS_MODULE,
    .dev_release    = spi_controller_release,
    .dev_groups = spi_master_groups,
};
(4)spi驱动注册
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
 * __spi_register_driver - register a SPI driver
 * @owner: owner module of the driver to register
 * @sdrv: the driver to register
 * Context: can sleep
 *
 * Return: zero on success, else a negative error code.
 */
int __spi_register_driver(struct module *owner, struct spi_driver *sdrv)
{
    sdrv->driver.owner = owner;
    sdrv->driver.bus = &spi_bus_type;
    sdrv->driver.probe = spi_drv_probe;
    sdrv->driver.remove = spi_drv_remove;
    if (sdrv->shutdown)
        sdrv->driver.shutdown = spi_drv_shutdown;
    return driver_register(&sdrv->driver);
}
EXPORT_SYMBOL_GPL(__spi_register_driver); 

  

  • spi_drv_probe
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
static int spi_drv_probe(struct device *dev)
{
    const struct spi_driver     *sdrv = to_spi_driver(dev->driver);
    struct spi_device       *spi = to_spi_device(dev);
    int ret;
 
    ret = of_clk_set_defaults(dev->of_node, false);   //获取设备树中的clock属性,并设置clock
    if (ret)
        return ret;
 
    if (dev->of_node) {
        spi->irq = of_irq_get(dev->of_node, 0);   //获取spi终端
        if (spi->irq == -EPROBE_DEFER)
            return -EPROBE_DEFER;
        if (spi->irq < 0)
            spi->irq = 0;
    }
 
    ret = dev_pm_domain_attach(dev, true);  //将spi设备加进PM域,用于节省电源能耗
    if (ret)
        return ret;
 
    if (sdrv->probe) {
        ret = sdrv->probe(spi);
        if (ret)
            dev_pm_domain_detach(dev, true);
    }
 
    return ret;
} 

Linux PM domain概述和使用流程

  • spi_remove
1
2
3
4
5
6
7
8
9
10
11
static int spi_drv_remove(struct device *dev)
{
    const struct spi_driver     *sdrv = to_spi_driver(dev->driver);
    int ret = 0;
 
    if (sdrv->remove)
        ret = sdrv->remove(to_spi_device(dev));
    dev_pm_domain_detach(dev, true);  //spi驱动移除后,要将spi设备从pm域中去掉
 
    return ret;
}

 

  

 

posted @   轻轻的吻  阅读(1681)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示