13. Drive development -- spi bus

SPI
The abbreviation of English Serial Peripheral interface, as the name implies, is Serial Peripheral interface. It was first defined by Motorola on its MC68HCXX series processor. SPI interface is mainly used in EEPROM, FLASH, real-time clock, AD converter, digital signal processor and digital signal decoder. SPI is a high-speed, full duplex, synchronous communication bus, and only takes up four lines on the pins of the chip, saving the pins of the chip, and saving space and convenience for PCB layout. Because of this simple and easy-to-use feature, more and more chips now integrate this communication protocol, such as AT91RM9200


The communication principle of SPI is very simple. It works in the master-slave mode. This mode usually has one master device and one or more slave devices. It requires at least four lines, and in fact, three lines can also be used (one-way transmission). It is also common to all SPI based devices. They are SDI (data input), SDO (data output), SCK (clock), CS (chip selection).
SDO – master device data output, slave device data input corresponds to the MOSI master output slave input
SDI – master device data input, slave device data output corresponding to MISO master input slave output
SCLK - clock signal, generated by the main equipment
CS – slave enable signal, controlled by master



Write a SPI driver
1. Define and initialize drive objects

 struct spi_driver {
        struct device_driver    driver;        Inherit parent class
            const char    *name;    The name of the driver
            struct of_device_id  of_match_table[];        The table describes,What devices does the driver support
            int (*probe) (struct device *dev);        Review hardware and init    The first match between the driver and the device
            int (*remove) (struct device *dev);     De initialize hardware        Drive and equipment separation

        const struct spi_device_id *id_table;    The ancient way of matching
        int         (*probe)(struct spi_device *spi);
        int         (*remove)(struct spi_device *spi);
    };

2. Add drive objects to the bus

    int spi_register_driver(struct spi_driver * sdrv)

3. Unload drive

spi_unregister_driver(struct spi_driver * sdrv)
/*****************************************************************
*   Copyright (C) 2019 Sangfor Ltd. All rights reserved.
*   
*   File name: spi_drv.c
*   Creator: Yinfei Hu
*   Date created:
*   Function Description: spi bus
*
*****************************************************************/

#include <linux/kernel.h>
#include <linux/module.h>

struct dev_pri {
	int xxx;
};

struct of_device_id  of_match_table[] = {

		{.compatible = "xxxxdev",},
			{}		//Last entry is null
};	


/*
struct spi_device {
	struct device		dev;		Inherit parent class	
		void	*platform_data; 	Private data, used to store information specific to the hardware
		struct		 device_node	*of_node;		Device tree node pointer, which node the hardware / device comes from in the device tree
	Own properties	
}


*/

int  spi_probe(struct spi_device *spi_dev)
{
	struct  dev_pri *pri;
	struct device_node *of_node = spi_dev->dev.of_node;

	pri = kmalloc(sizeof(*pri));
	memset(pri,0,sizeof(*pri));
	spi_dev->dev.platform_data = pri;

	/*Read and write registers to complete the operation of spi dev

	int spi_write_then_read(struct spi_device * spi,
						const void * txbuf,unsigned n_tx,
									void * rxbuf,unsigned n_rx)

		Write only but not read, rxbuf is null
		Read only, do not write, txbuf is null

	*/
	int spi_write_then_read(struct spi_device * spi,const void * txbuf,unsigned n_tx,void * rxbuf,unsigned n_rx)

}

int spi_remove(struct spi_device *spi)
{
	//spi_ Reverse steps in probe
}


struct spi_driver spidrvobj = {
	.driver = {
		.name = "xx spi drv",
		.of_match_table = of_match_table,
	},
	.id_table = NULL,
	.probe = spi_probe,
	.remove = spi_remove,
};


int module_fun_init(void)
{
	spi_register_driver(&spidrvobj);

	printk("%s->%d\n",__FUNCTION__,__LINE__);
	return 0;
}

void  module_fun_exit(void)
{
	spi_unregister_driver(&spidrvobj);

	printk("%s->%d\n",__FUNCTION__,__LINE__);
}

/*    Kernel module entry module_ The parameters in init are the module entry function*/
module_init(module_fun_init);
/*    Kernel module exit module_ The parameter in exit refers to the module exit function*/
module_exit(module_fun_exit);

/*Module author information*/
MODULE_AUTHOR("YinFei.Hu <hu_yin_fei@163.com>");
/*Module information*/
MODULE_DESCRIPTION("spi_driver");
/*Tell the kernel to comply with the gpl protocol*/
MODULE_LICENSE("GPL");

Tags: Linux

Posted on Sat, 13 Jun 2020 06:04:53 -0400 by advancedfuture