SPI 구동 의 서브 시스템 구조 및 중요 데이터 구조

개인 적 으로 리 눅 스 에서 SPI 는 '무시' 되 는 역할 을 해 왔 다. 시장 에서 대부분의 판 자 는 판 급 파일 에 SPI 에 관 한 코드 (예 를 들 어 mini 2440) 가 없 었 고 대부분 구동 을 설명 하 는 책 도 리 눅 스 에서 SPI 에 관 한 내용 (예 를 들 어 송 보 화의 리 눅 스 장치 구동 개발 에 관 한 상세 한 설명) 을 다 루 는 전문 적 인 장 이 없 었 다.I2C 에 비해 SPI 는 중시 되 지 않 는 '녀석' 인 데, 왜?나 도 잘 몰라.프로젝트 는 UT4412BV 01 에 SPI 를 이식 해 야 하기 때문에 인터넷 에 있 는 거의 모든 SPI 관련 자 료 를 조회 할 수 있 습 니 다. 모두 S3C 2440 과 S3C 6410 의 SPI 구동 분석 이 고 EXYNOS 4412 는 한 마디 도 언급 하지 않 았 습 니 다. 그러나 그들 은 서로 통 하 는 것 이 라 고 곰 곰 이 생각해 서 나중에 찾 아 보기 편 하도록 연 구 했 습 니 다.
1. SPI 서브 시스템 구조 상세 설명
SPI 버스 에는 두 가지 장치 가 있 습 니 다. 하 나 는 주 제어 단 입 니 다. 보통 SOC 시스템 의 키 모듈 로 나타 납 니 다. 예 를 들 어 많은 내장 형 MPU 에는 SPI 모듈 이 자주 포함 되 어 있 습 니 다.하 나 는 SPI 인터페이스의 Flash, 센서 등 제어 단 이다.주 제어 단 은 SPI 버스 의 제어 자 입 니 다. SPI 프로 토 콜 을 사용 하여 SPI 버스 의 세 션 을 주동 적 으로 시작 하고 제어 단 은 SPI 주 제어 단의 명령 을 수 동적 으로 받 아들 여 해당 하 는 응답 을 합 니 다.
그림 이 아직 다 그 려 지지 않 았 는데, 나중에 보충 하고, 보충 한 후에 분석 을 좀 써 라, 하하...
2. 중요 데이터 구조
(1)spi_master
struct spi_master 는 SPI 메 인 컨트롤 러 를 설명 하 는 데 사 용 됩 니 다. 우 리 는 일반적으로 spi 컨트롤 러 구동 을 직접 작성 할 필요 가 없습니다.
/** 
 *    master    SPI  ,     SPI     ,
 *         SPI  ,master->bus_num         。 
 */
struct spi_master {
	struct device	dev;

	struct list_head list;

	/** 
	 *     ,    。
	 *             board_list         boardinfo       spi_board_info  bus_num    ,
	 * (  boardinfo      spi_board_info   ,   spi_board_info      SPI( )     )
	 *           spi_board_info   SPI( )           ,      spi_new_device     spi_device。
	 */
	s16			bus_num;

	/*         。              .       0,        */
	u16			num_chipselect;

	/* some SPI controllers pose alignment requirements on DMAable
	 * buffers; let protocol drivers know about these requirements.
	 */
	u16			dma_alignment;

	/* spi_device.mode flags understood by this controller driver */
	u16			mode_bits;

	/* other constraints relevant to this driver */
	u16			flags;
#define SPI_MASTER_HALF_DUPLEX	BIT(0)		/* can't do full duplex */
#define SPI_MASTER_NO_RX	BIT(1)		/* can't do buffer read */
#define SPI_MASTER_NO_TX	BIT(2)		/* can't do buffer write */

	/* lock and mutex for SPI bus locking */
	spinlock_t		bus_lock_spinlock;
	struct mutex		bus_lock_mutex;

	/* flag indicating that the SPI bus is locked for exclusive use */
	bool			bus_lock_flag;

	int			(*setup)(struct spi_device *spi); //  spi        

	/**
	 *           。       ,            ,
	 *         (        )  spi_message  complete  ,         。
	 */
	int			(*transfer)(struct spi_device *spi, struct spi_message *mesg);

	/*cleanup    spidev_release      ,spidev_release    spidev release  */
	void			(*cleanup)(struct spi_device *spi);
};

spi 컨트롤 러 의 구동 은 kernel 3.0.15 / arch / arm / mach - exynos / mach - smdk4x 12. c 에서 플랫폼 장 치 를 설명 하고 등록 한 다음 kernel 3.0.15 / driver / spi 아래 플랫폼 구동 을 구축 합 니 다.spi_master 등록 과정 에서 kernel 3.0.15 / arch / arm / mach - exynos / mach - smdk4x 12. c 에서 spi 를 호출 합 니 다.register_board_info 등 록 된 정 보 는 본 버스 번호 와 같은 모든 정보 에 spi 를 만 듭 니 다.device。리 눅 스 커 널 의 구동 모델 에 따라 같은 버스 에 등 록 된 구동 과 장치 가 일치 합 니 다.spi_bus_type 버스 가 일치 하 는 근 거 는 이름 입 니 다. 이렇게 자신 이 작성 한 spidriver 와 spidevice 동명 일 때 spidriver 의 probe 방법 이 사 용 됩 니 다. spidriver 는 자신 과 일치 하 는 spi 를 볼 수 있 습 니 다.장치 입 니 다.
(2)spi_device
struct spi_device 는 장치 에서 SPI 를 설명 하 는 데 사 용 됩 니 다.
/**
 *         SPI  ,           。
 *   :SPI         ,    SOC  SPI     master  ,
 *        slave  。
 */
struct spi_device {
	struct device		dev;
	struct spi_master	*master; //        
	u32			max_speed_hz; //spi    
	u8			chip_select; //   ,              
	u8			mode; // bit     ,       /    
#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 */
	u8			bits_per_word; //        
	int			irq; //       
	void			*controller_state;
	void			*controller_data;
	char			modalias[SPI_NAME_SIZE]; //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
	 *  - drop chipselect after each word
	 *  - chipselect delays
	 *  - ...
	 */
};

(3)spi_driver
struct spi_driver 는 SPI 가 장치 에서 구동 되 는 것 을 설명 하 는 데 사 용 됩 니 다.구동 핵심 은 driver. name 과 spi 에 따라board_info 의 modalias 가 일치 합 니 다. modalias 와 name 이 같 으 면 바 인 딩 드라이버 와 kernel 3.0.5 / arch / arm / mach - exynos / mach - smdk4x 12. c 에서 spi 를 호출 합 니 다.register_board_info 등 록 된 정보 에 대응 하 는 spi장치 장치.그것들의 형식 과 struct platformdriver 는 일치 합 니 다.
struct spi_driver {
	const struct spi_device_id *id_table; //        ,               
	int			(*probe)(struct spi_device *spi); // spi_device             .                     
	int			(*remove)(struct spi_device *spi); //  spi_device spi_driver   ,  probe     
	void			(*shutdown)(struct spi_device *spi); //            ,  
	int			(*suspend)(struct spi_device *spi, pm_message_t mesg); //            ,  
	int			(*resume)(struct spi_device *spi); //            ,  
	struct device_driver	 driver;
};
(4)
spi_transfer
struct spi_transfer 는 완전한 데이터 전송 에 대한 설명 입 니 다.각 spitransfer 는 항상 같은 길이 의 비트 수 를 읽 고 기록 하지만 빈 포인터 로 읽 거나 쓸 수 있 습 니 다. spi 입 니 다.transfer 와 spi메시지 가 분 배 된 메모 리 는 메시지 처리 기간 에 완전 하 게 보장 되 어야 합 니 다.
struct spi_transfer {
	/* it's ok if tx_buf == rx_buf (right?)
	 * for MicroWire, one buffer must be null
	 * buffers must work with dma_*map_single() calls, unless
	 *   spi_message.is_dma_mapped reports a pre-existing mapping
	 */
	const void	*tx_buf; //        (   dma_safe),   NULL
	void		*rx_buf; //        (   dma_safe),   NULL
	unsigned	len; //tx tr   (   ),        ,       ,       

	dma_addr_t	tx_dma; //  spi_message.is_dma_mapped  ,   tx dma  
	dma_addr_t	rx_dma; //  spi_message.is_dma_mapped  ,   rx dma  

	unsigned	cs_change:1; //           ,    transfer              setup    
	u8		bits_per_word; //        ,   0,     
	u16		delay_usecs; //                ,                   
	u32		speed_hz; //    ,   0,     

	struct list_head transfer_list; //           
};

(5)spi_message
struct spi_message 는 여러 spitransfer 패키지.소식 을 전 할 때 spitransfer 자신의 transfer 를 통 해list 필드 spimessage 의 transfers 링크 머리 에 있 습 니 다.spi_message 원자 실행 spitransfer 가 표시 하 는 일련의 배열 전송 요청이 전송 대기 열 은 원자 입 니 다. 이 메시지 가 완성 되 기 전에 다른 메시지 가 버스 를 차지 하지 않 는 다 는 것 을 의미 합 니 다.메시지 의 실행 은 항상 FIFO 의 순서에 따라 밑 에 spi 를 제출 합 니 다.message 의 코드 는 메모리 공간 을 관리 해 야 합 니 다.초기 화 되 지 않 은 메모 리 는 0 을 사용 하여 초기 화 해 야 합 니 다.위 spitransfer 와 spi메시지 가 분 배 된 메모 리 는 메시지 처리 기간 에 완전 하 게 보장 되 어야 합 니 다.
struct spi_message {
	struct list_head	transfers; //         ,             

	struct spi_device	*spi; //       

	unsigned		is_dma_mapped:1; //    ,      dma cpu    

	/* REVISIT:  we might want a flag affecting the behavior of the
	 * last transfer ... allowing things like "read 16 bit length L"
	 * immediately followed by "read L bytes".  Basically imposing
	 * a specific message scheduling algorithm.
	 *
	 * Some controller drivers (message-at-a-time queue processing)
	 * could provide that as their default scheduling algorithm.  But
	 * others (with multi-message pipelines) could need a flag to
	 * tell them about such special cases.
	 */

	/* completion is reported through a callback */
	void			(*complete)(void *context); //            
	void			*context; //       
	unsigned		actual_length; //         
	int			status; //     ,    0,          

	/* for optional use by whatever driver currently owns the
	 * spi_message ...  between calls to spi_async and then later
	 * complete(), that's the spi_master controller driver.
	 */
	struct list_head	queue;
	void			*state;
};

(6) 두 가지 중요 한 판 급 구조
두 개의 판 급 구조, 그 중 spiboard_info spi 초기 화 에 사용device,s3c64xx_spi_info spi 초기 화 에 사용master。이 두 판 급 의 구 조 는 이식 할 때 kernel 3.0.15 / arch / arm / mach - exynos / mach - smdk4x 12. c 에서 초기 화 되 어야 합 니 다.
spi_board_info(kernel3.0.15/linux/include/spi/spi.h)
/*       SPI   (spi_device)   ,         ,                 SPI     spi_device */
struct spi_board_info {
	/* the device name and module name are coupled, like platform_bus;
	 * "modalias" is normally the driver name.
	 *
	 * platform_data goes to spi_device.dev.platform_data,
	 * controller_data goes to spi_device.controller_data,
	 * irq is copied too
	 */
	char		modalias[SPI_NAME_SIZE]; //spi   ,    spi_device      .    spi_device SPI  spi_bus_type          
	const void	*platform_data; //    
	void		*controller_data;
	int		irq; //   

	/* slower signaling on noisy or low voltage boards */
	u32		max_speed_hz; //SPI         


	/* bus_num is board specific and matches the bus_num of some
	 * spi_master that will probably be registered later.
	 *
	 * chip_select reflects how this chip is wired to that master;
	 * it's less than num_chipselect.
	 */
	u16		bus_num; // SPI( )          ,       spi_master   bus_num  .  spi_master       
	u16		chip_select; //   . SPI( )     SPI            

	/* mode becomes spi_device.mode, and is essential for chips
	 * where the default of SPI_CS_HIGH = 0 is wrong.
	 */
	u8		mode; //  spi_device    

	/* ... may need additional spi_device chip config data here.
	 * avoid stuff protocol drivers can set; but include stuff
	 * needed to behave without being bound to a driver:
	 *  - quirks like clock rate mattering when not selected
	 */
};
s3c64xx_spi_info(kernel3.0.15/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h)
struct s3c64xx_spi_info {
	int src_clk_nr;
	char *src_clk_name;
	bool clk_from_cmu;

	int num_cs; //       

	int (*cfg_gpio)(struct platform_device *pdev);

	/* Following two fields are for future compatibility */
	int fifo_lvl_mask;
	int rx_lvl_offset;
	int high_speed;
	int tx_st_done;
};

boardinfo 는 spi 를 관리 하 는 데 쓰 인 다board_info 의 구조, spiboard_info 판 급 파일 에서 spiregister_board_info (struct spi board info const * info, unsigned n) 는 board info 에 의 해 관리 되 고 board 에 걸 립 니 다.리스트 링크 에.
boardinfo(kernel3.0.15/drivers/spi/spi.c)
struct boardinfo {
	struct list_head	list; //      board_list 
	struct spi_board_info	board_info; //     spi_board_info
};
spi_register_board_info(kernel3.0.15/drivers/spi/spi.c)
int __init
spi_register_board_info(struct spi_board_info const *info, unsigned n)
{
	struct boardinfo *bi;
	int i;

	bi = kzalloc(n * sizeof(*bi), GFP_KERNEL);
	if (!bi)
		return -ENOMEM;

	for (i = 0; i < n; i++, bi++, info++) {
		struct spi_master *master;

		memcpy(&bi->board_info, info, sizeof(*info));
		mutex_lock(&board_lock);
		list_add_tail(&bi->list, &board_list);
		list_for_each_entry(master, &spi_master_list, list)
			spi_match_master_to_boardinfo(master, &bi->board_info);
		mutex_unlock(&board_lock);
	}

	return 0;
}

좋은 웹페이지 즐겨찾기