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


    一、spi驱动框架简介

     

    • spi核心层

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

    • spi主机驱动

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

    • spi设备驱动

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

     

     二、驱动源码分析

    1、spidev.c

    (1)初始化
    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驱动定义
    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  
    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
    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设备文件操作集合
    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)读操作
    /* 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;
    } 
    spidev_sync_read:
    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)写操作
    /* 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;
    }
    
    spidev_sync_write:
    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
    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)平台驱动定义
    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
    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
    static int sun6i_spi_remove(struct platform_device *pdev)
    {
         //强制挂机
    	pm_runtime_force_suspend(&pdev->dev);
    
    	return 0;
    } 

     

    • sun6i_spi_match
    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结构体
    //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
    //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定义:
    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设备和驱动的匹配方式, 
    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
    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定义:
    static struct class spi_master_class = {
    	.name		= "spi_master",
    	.owner		= THIS_MODULE,
    	.dev_release	= spi_controller_release,
    	.dev_groups	= spi_master_groups,
    };
    (4)spi驱动注册
    /**
     * __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
    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
    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;
    }
    

     

      

     

  • 相关阅读:
    Qt判断文件夹是否存在并新建文件夹
    QFileDialog的使用
    C++11 std::chrono库详解
    disconnected no supported authentication methods available(server sent: publickey)
    connect函数的第5参数Qt::ConnectionType
    在C++ 中检查一个文件是否存在的几种方法
    win10打开便签
    1024. Palindromic Number (25)
    1023. Have Fun with Numbers (20)
    1021. Deepest Root (25)
  • 原文地址:https://www.cnblogs.com/yuanqiangfei/p/15810651.html
Copyright © 2020-2023  润新知