Linux的平台总线

前言:

        介绍之前的三问:

什么是平台总线?为什么要使用平台总线?如何使用平台总线?

1、总线:

        但凡有总线,就一定有信息的传输。USB总线  IIC总线  SPI总线等 用于设备间信息的传输,并且在设备间有物理连线的。属于物理总线。

        平台总线也是总线的一种,但它是Linux内核虚拟出来的,抽象出来的总线,实际上不存在样的总线。

2、为什么要使用总线:

        首先说一下总线的优点:减少重复代码,提高程序的移植性,设备挂载在平台总线上,方便管理。

        设备树与平台总线类似都可将设备与驱动分离,虽然设备树可以代替平台总线来描述硬件设备,但它们的角色和作用是不同的。设备树主要用于描述硬件设备的层次结构、寄存器配置和中断信息等,以便驱动程序能够正确地与硬件设备进行通信。而平台总线则提供了一种物理接口和通信协议,使得不同的硬件设备能够在同一个系统中进行互联和通信。学习平台总线还是有必要的。

3、如何使用平台总线:

        a,编写两个C源文件(driver.c和device.c)

 device.c中写的是硬件资源,包括寄存器的地址,中断号,时钟等等。

driver.c中写的是驱动相同的部分,包括申请设备号,创建设备节点等等。

        b,将driver.c和device.c注册到平台总线中

        c,使用平台总线将driver.c和device.c联系在一起---设置匹配的字符串

一、编写平台总线部分内容介绍:

1、首先是硬件描述相关的结构体:--------device.c

硬件设备资源的结构体可以调用这样的结构体
	struct platform_device {
					const char	* name;   
					//暗号--用于匹配的名字-----并且在我们加载完device.c后它会在sys/bus/.....生成此名字的文件
					int	id;		//设备id,通常是-1(表示只有一个实例),它是用于,当有两个相同name的设备进行变化的
					struct device	dev;//父类,总线match时,实际match的是dev,所有设备共性的部分
					u32		num_resources;//资源的数量
					struct resource	* resource;//硬件资源
					
					const struct platform_device_id	*id_entry;
					char *driver_override; /* Driver name to force a match */ //强制匹配的驱动程序名称

					/* MFD cell pointer */ //多功能设备 单元指针
					struct mfd_cell *mfd_cell;

					/* arch specific additions */ //arch中特定的附加物
					struct pdev_archdata	archdata;
				};

   2、描述硬件资源的结构体 ------一般用来表示两种资源,地址资源和中断资源--------device.c

struct resource {
					resource_size_t start; //如果是地址资源---资源的开始地址;如果是中断资源---中断通道号
					resource_size_t end;//如果是地址资源---资源的最后一个字节的地址;如果是中断资源---中断通道号
					const char *name;//资源的名字
					unsigned long flags;//资源的种类 IORESOURCE_MEM(地址资源)IORESOURCE_IRQ(中断资源)
				};

3、linux内核中,描述驱动部分的结构体----------driver.c

	3>linux内核中,描述驱动部分的结构体----------driver.c
	struct platform_driver {
	    int (*probe)(struct platform_device *);
		//当device.c和driver.c匹配成功,就会执行probe中的内容----//也就是模块加载函数总的内容
		int (*remove)(struct platform_device *);
		//当卸载device.c和driver.c中任意一个后执行的内容-----//也就是模块卸载函数中的内容
		void (*shutdown)(struct platform_device *);
		//当设备收到shutdown命令的时候执行的函数
		int (*suspend)(struct platform_device *, pm_message_t state);
		//当设备收到suspend命令的时候执行的函数---休眠
		int (*resume)(struct platform_device *);
		//当设备收到resume命令的时候执行的函数---唤醒
		struct device_driver driver; //父类 
	    const struct platform_device_id *id_table;//与device.c中的名字相匹配----暗号 
		bool prevent_deferred_probe;//设置为私有
	};

4、注销注册函数:

device.c:
int platform_device_register(struct platform_device *pdev)//注册到平台总线中
void platform_device_unregister(struct platform_device *pdev) //从平台总线注销
drivers.c:
int platform_driver_register(struct platform_driver *drv)//注册到平台总线中
void platform_driver_unregister(struct platform_driver *drv) //从平台总线注销
二、平台总线的编写步骤:

建立:drv_device.c文件,drv_driver.c和一个makefile文件

1.1基本框架:

#include "linux/init.h"
#include "linux/module.h"
#include "linux/platform_device.h"
#include "stm32mp157xxx.h"
#include "platform_data_special.h"
#include "linux/init.h"
#include "linux/module.h"
#include "linux/platform_device.h"
#include "stm32mp157xxx.h"
#include "platform_data_special.h"

struct resource	 resource_1={//用于存放资源
	
};
//自定义资源地址
struct Platform_data_spex pdata={
	
};


void led_close(struct device *dev)
{
	
}


struct platform_device pdev[]={	
	
	
};
static int __init led_device_init(void)
{

	//加载驱动时候注册平台

	
		platform_device_unregister(&pdev[i-1]);//在平台总线中移除一个硬件设备
	
		return ret;
}

void __exit led_device_exit(void)
{
	int i;
	printk("-----------------%s------------------\n",__FUNCTION__);
	
		platform_device_unregister(&pdev[i]);//平台总线中移除一个硬件设备

	
}

module_init(led_device_init);
module_exit(led_device_exit);
MODULE_LICENSE("GPL");



driver.c的文件编写。

#include "linux/init.h"
#include "linux/module.h"
#include "linux/platform_device.h"
#include "linux/mod_devicetable.h"
#include "linux/slab.h"
#include "platform_data_special.h"
#include "linux/fs.h"
#include "linux/device.h"
#include "asm/io.h"
#include "stm32mp157xxx.h"
#include "linux/uaccess.h"
//先自定义一个结构体用于驱动,必要信息
struct stm32mp157axxx{
	unsigned int major;//表示动态申请主设备号
	struct class *cls;//类
	struct device *dev;//设备节点


};

const struct file_operations fops={//设备相关的接口

};
int led_probe(struct platform_device *pdev){}//创建平台总线调用的函数

const struct platform_device_id led_id_table[]={}//匹配存放的字符串

int led_remove(struct platform_device *pdev){}//卸载调用函数
创建平台总线的结构体
struct platform_driver pdrv={
    .probe 			= led_probe,//在驱动driver.c和device.c匹配成功后,会调用这个函数
	.remove			= led_remove,//卸载时候调用
	.driver			={
		.name =  "led_drv",
			
	},
	.id_table	= led_id_table,
}
int __init drv_driver_init(void)
{
	int ret=0;
	printk("-----------------%s------------------\n",__FUNCTION__);
    注册
	return ret;
}
void __exit drv_driver_exit(void)
{
	printk("-----------------%s------------------\n",__FUNCTION__);
        卸载
}
module_init(drv_driver_init);
module_exit(drv_driver_exit);
MODULE_LICENSE("GPL");	

说实话上面的这些我自己看了都头疼,不知道写了写啥,不会总结,算了直接拿最简单的led灯的驱动来说话。后续自己看起来也好受点。

三、以驱动stm32mp157的 led灯为示例:

1、首先看了一下开发板灯的信息。

灯在原理图中的位置,有两处。

主板的灯

 扩展板的灯

2、所以我们需要开的灯在GPIOZ,GPIOE,GPIOF上。所以找手册上

直接在数据手册上搜GPIOZ所以知道我们需要开的总线是AHB5和AHB4

3、且由上面查找知道GPIOZ,GPIOE,GPIOF的地址是0x54004000,0x50006000,0x50007000

4、我们点灯需要操作的寄存器是:MODE寄存器,pin_x号引脚,PZ7所以.MODER_SET =0x1<<14(.MODER_SET 下面的头文件会定于,自己编写定义的)

5、输出ODR寄存器:

6、在编写之前需要将寄存器的结构体编写出来,方便后续操作寄存器设置灯的状态。

7开灯需要用到的寄存器有两个GPIO和RCC的寄存器。

所以编写一个STM32MP157XXX.h的头文件方便调用,可以查看手册找到具体的内容介绍

#ifndef __STM32MP157XXX__
#define __STM32MP157XXX__

#define GPIOZ_Base 0x54004000
#define GPIOE_Base 0x50006000
#define GPIOF_Base 0x50007000


#define RCC_Base 0x50000000


#define __IO  volatile 
#define uint32_t  unsigned int 
#define uint16_t  unsigned short

typedef struct
{
  __IO uint32_t MODER;    /*!< GPIO port mode register,               Address offset: 0x00      */
  __IO uint32_t OTYPER;   /*!< GPIO port output type register,        Address offset: 0x04      */
  __IO uint32_t OSPEEDR;  /*!< GPIO port output speed register,       Address offset: 0x08      */
  __IO uint32_t PUPDR;    /*!< GPIO port pull-up/pull-down register,  Address offset: 0x0C      */
  __IO uint32_t IDR;      /*!< GPIO port input data register,         Address offset: 0x10      */
  __IO uint32_t ODR;      /*!< GPIO port output data register,        Address offset: 0x14      */
  __IO uint16_t BSRRL;    /*!< GPIO port bit set/reset low register,  Address offset: 0x18      */
  __IO uint16_t BSRRH;    /*!< GPIO port bit set/reset high register, Address offset: 0x1A      */
  __IO uint32_t LCKR;     /*!< GPIO port configuration lock register, Address offset: 0x1C      */
  __IO uint32_t AFR[2];   /*!< GPIO alternate function registers,     Address offset: 0x20-0x24 */
  __IO uint32_t BRR;      /*!< GPIO port bit reset register,          Address offset: 0x28 */
  __IO uint32_t BUF[1];   /*!< NO register,                           Address offset: 0x2C */
  __IO uint32_t SECCFGR;  /*!< GPIO secure configuration register,    Address offset: 0x30 */                      	
} GPIO_TypeDef;

typedef struct {
	__IO unsigned int TZCR;     	// 0x000
	__IO unsigned int res1[2]; 		// 0x004-0x008
	__IO unsigned int OCENSETR;     // 0x00C
	__IO unsigned int OCENCLRR;  	// 0x010
	__IO unsigned int res2[1]; 		// 0x014
	__IO unsigned int HSICFGR; 		// 0x018
	__IO unsigned int CSICFGR; 		// 0x01C
	__IO unsigned int MPCKSELR; 	// 0x020
	__IO unsigned int ASSCKSELR; 	// 0x024
	__IO unsigned int PCK12SELR; 	// 0x028
	__IO unsigned int MPCKDIVR; 	// 0x02C
	__IO unsigned int AXIDIVR; 		// 0x030
	__IO unsigned int res3[2];
	__IO unsigned int APB4DIVR; 	// 0x03C
	__IO unsigned int APB5DIVR; 	// 0x040
	__IO unsigned int RTCDIVR; 		// 0x044
	__IO unsigned int MSSCKSELR;    // 0x048
	__IO unsigned int res4[13];
	__IO unsigned int PLL1CR; 		// 0x080
	__IO unsigned int PLL1CFGR1; 	// 0x084
	__IO unsigned int PLL1CFGR2; 	// 0x088
	__IO unsigned int PLL1FRACR; 	// 0x08C
	__IO unsigned int PLL1CSGR;     // 0x090
	__IO unsigned int PLL2CR; 		// 0x094
	__IO unsigned int PLL2CFGR1; 	// 0x098
	__IO unsigned int PLL2CFGR2; 	// 0x09C
	__IO unsigned int PLL2FRACR;    // 0x0A0
	__IO unsigned int PLL2CSGR;     // 0x0A4
	__IO unsigned int res5[6];
	__IO unsigned int I2C46CKSELR;  // 0x0C0
	__IO unsigned int SPI6CKSELR;   // 0x0C4
	__IO unsigned int UART1CKSELR;  // 0x0C8
	__IO unsigned int RNG1CKSELR;   // 0x0CC
	__IO unsigned int CPERCKSELR;   // 0x0D0
	__IO unsigned int STGENCKSELR;  // 0x0D4
	__IO unsigned int DDRITFCR; 	// 0x0D8
	__IO unsigned int res6[9];
	__IO unsigned int MP_BOOTCR;  	// 0x100
	__IO unsigned int MP_SREQSETR;  // 0x104
	__IO unsigned int MP_SREQCLRR;  // 0x108
	__IO unsigned int MP_GCR;  		// 0x10C
	__IO unsigned int MP_APRSTCR; 	// 0x110
	__IO unsigned int MP_APRSTSR;   // 0x114
	__IO unsigned int res7[10];
	__IO unsigned int BDCR; 		// 0x140
	__IO unsigned int RDLSICR;  	// 0x144
	__IO unsigned int res8[14];
	__IO unsigned int APB4RSTSETR; 	// 0x180
	__IO unsigned int APB4RSTCLRR; 	// 0x184
	__IO unsigned int APB5RSTSETR;  // 0x188
	__IO unsigned int APB5RSTCLRR;  // 0x18C
	__IO unsigned int AHB5RSTSETR;  // 0x190
	__IO unsigned int AHB5RSTCLRR;  // 0x194
	__IO unsigned int AHB6RSTSETR;  // 0x198
	__IO unsigned int AHB6RSTCLRR;  // 0x19C
	__IO unsigned int TZAHB6RSTSELR;// 0x1A0
	__IO unsigned int TZAHB6RSTCLRR;// 0x1A4
	__IO unsigned int res9[22];
	__IO unsigned int MP_APB4ENSETR;// 0x200
	__IO unsigned int MP_APB4ENCLRR;// 0x204
	__IO unsigned int MP_APB5ENSETR;// 0x208
	__IO unsigned int MP_APB5ENCLRR;// 0x20C
	__IO unsigned int MP_AHB5ENSETR;// 0x210
	__IO unsigned int MP_AHB5ENCLRR;// 0x214
	__IO unsigned int MP_AHB6ENSETR;// 0x218
	__IO unsigned int MP_AHB6ENCLRR;// 0x21C
	__IO unsigned int MP_TZAHB6ENSELR;// 0x220
	__IO unsigned int MP_TZAHB6ENCLRR;// 0x224
	__IO unsigned int res10[22];
	__IO unsigned int MC_APB4ENSETR; // 0x280
	__IO unsigned int MC_APB4ENCLRR; // 0x284
	__IO unsigned int MC_APB5ENSETR; // 0x288
	__IO unsigned int MC_APB5ENCLRR; // 0x28C
	__IO unsigned int MC_AHB5ENSETR; // 0x290
	__IO unsigned int MC_AHB5ENCLRR; // 0x294
	__IO unsigned int MC_AHB6ENSETR; // 0x298
	__IO unsigned int MC_AHB6ENCLRR; // 0x29C
	__IO unsigned int res11[24];
	__IO unsigned int MP_APB4LPENSETR; // 0x300
	__IO unsigned int MP_APB4LPENCLRR; // 0x304
	__IO unsigned int MP_APB5LPENSETR; // 0x308
	__IO unsigned int MP_APB5LPENCLRR; // 0x30C
	__IO unsigned int MP_AHB5LPENSETR; // 0x310
	__IO unsigned int MP_AHB5LPENCLRR; // 0x314
	__IO unsigned int MP_AHB6LPENSETR; // 0x318
	__IO unsigned int MP_AHB6LPENCLRR; // 0x31C
	__IO unsigned int MP_TZAHB6LPENSETR; // 0x320
	__IO unsigned int MP_TZAHB6LPENCLRR; // 0x324
	__IO unsigned int res12[22];
	__IO unsigned int MC_APB4LPENSETR; // 0x380
	__IO unsigned int MC_APB4LPENCLRR; // 0x384
	__IO unsigned int MC_APB5LPENSETR; // 0x388
	__IO unsigned int MC_APB5LPENCLRR; // 0x38C
	__IO unsigned int MC_AHB5LPENSETR; // 0x390
	__IO unsigned int MC_AHB5LPENCLRR; // 0x394
	__IO unsigned int MC_AHB6LPENSETR; // 0x398
	__IO unsigned int MC_AHB6LPENCLRR; // 0x39C
	__IO unsigned int res13[24];
	__IO unsigned int BR_RSTSCLRR; 		// 0x400
	__IO unsigned int MP_GRSTCSETR; 	// 0x404
	__IO unsigned int MP_RSTSR; 		// 0x408
	__IO unsigned int MP_IWDGFZSETR; 	// 0x40C
	__IO unsigned int MP_IWDGFZCLRR;  	// 0x410
	__IO unsigned int MP_CIER; 			// 0x414
	__IO unsigned int MP_CIFR; 			// 0x418
	__IO unsigned int PWRLPDLYCR; 		// 0x41C
	__IO unsigned int MP_RSTSS; 		// 0x420
	__IO unsigned int res14[247];
	__IO unsigned int MCO1CFGR; 		// 0x800
	__IO unsigned int MCO2CFGR; 		// 0x804
	__IO unsigned int OCRDYR; 			// 0x808
	__IO unsigned int DBGCFGR; 			// 0x80C
	__IO unsigned int res15[4];
	__IO unsigned int RCK3SELR; 		// 0x820
	__IO unsigned int RCK4SELR; 		// 0x824
	__IO unsigned int TIMG1PRER;  		// 0x828
	__IO unsigned int TIMG2PRER; 		// 0x82C
	__IO unsigned int MCUDIVR; 			// 0x830
	__IO unsigned int APB1DIVR; 		// 0x834
	__IO unsigned int APB2DIVR; 		// 0x838
	__IO unsigned int APB3DIVR; 		// 0x83C
	__IO unsigned int res16[16];
	__IO unsigned int PLL3CR;   		// 0x880
	__IO unsigned int PLL3CFGR1; 		// 0x884
	__IO unsigned int PLL3CFGR2; 		// 0x888
	__IO unsigned int PLL3FRACR; 		// 0x88C
	__IO unsigned int PLL3CSGR; 		// 0x890
	__IO unsigned int PLL4CR; 			// 0x894
	__IO unsigned int PLL4CFGR1; 		// 0x898
	__IO unsigned int PLL4CFGR2; 		// 0x89C
	__IO unsigned int PLL4FRACR; 		// 0x8A0
	__IO unsigned int PLL4CSGR; 		// 0x8A4
	__IO unsigned int res17[6];
	__IO unsigned int I2C12CKSELR; 		// 0x8C0
	__IO unsigned int I2C35CKSELR;  	// 0x8C4
	__IO unsigned int SAI1CKSELR; 		// 0x8C8
	__IO unsigned int SAI2CKSELR; 		// 0x8CC
	__IO unsigned int SAI3CKSELR; 		// 0x8D0
	__IO unsigned int SAI4CKSELR; 		// 0x8D4
	__IO unsigned int SPI2S1CKSELR; 	// 0x8D8
	__IO unsigned int SPI2S23CKSELR; 	// 0x8DC
	__IO unsigned int SPI45CKSELR; 		// 0x8E0
	__IO unsigned int UART6CKSELR; 		// 0x8E4
	__IO unsigned int UART24CKSELR; 	// 0x8E8
	__IO unsigned int UART35CKSELR; 	// 0x8EC
	__IO unsigned int UART78CKSELR; 	// 0x8F0
	__IO unsigned int SDMMC12CKSELR; 	// 0x8F4
	__IO unsigned int SDMMC3CKSELR; 	// 0x8F8
	__IO unsigned int ETHCKSELR; 		// 0x8FC
	__IO unsigned int QSPICKSELR; 		// 0x900
	__IO unsigned int FMCCKSELR; 		// 0x904
	__IO unsigned int res18[1];
	__IO unsigned int FDCANCKSELR; 		// 0x90C
	__IO unsigned int res19[1];
	__IO unsigned int SPDIFCKSELR; 		// 0x914
	__IO unsigned int CECCKSELR; 		// 0x918
	__IO unsigned int USBCKSELR; 		// 0x91C
	__IO unsigned int RNG2CKSELR;  		// 0x920
	__IO unsigned int DSICKSELR; 		// 0x924
	__IO unsigned int ADCCKSELR; 		// 0x928
	__IO unsigned int LPTIM45CKSELR; 	// 0x92C
	__IO unsigned int LPTIM23CKSELR;    // 0x930
	__IO unsigned int LPTIM1CKSELR; 	// 0x934
	__IO unsigned int res20[18];
	__IO unsigned int APB1RSTSETR; 		// 0x980
	__IO unsigned int APB1RSTCLRR; 		// 0x984
	__IO unsigned int APB2RSTSETR; 		// 0x988
	__IO unsigned int APB2RSTCLRR; 		// 0x98C
	__IO unsigned int APB3RSTSETR; 		// 0x990
	__IO unsigned int APB3RSTCLRR; 		// 0x994
	__IO unsigned int AHB2RSTSETR; 		// 0x998
	__IO unsigned int AHB2RSTCLRR;  	// 0x99C
	__IO unsigned int AHB3RSTSETR; 		// 0x9A0
	__IO unsigned int AHB3RSTCLRR; 		// 0x9A4
	__IO unsigned int AHB4RSTSETR; 		// 0x9A8
	__IO unsigned int AHB4RSTCLRR; 		// 0x9AC
	__IO unsigned int res21[20];
	__IO unsigned int MP_APB1ENSETR; 	// 0xA00
	__IO unsigned int MP_APB1ENCLRR; 	// 0xA04
	__IO unsigned int MP_APB2ENSETR; 	// 0xA08
	__IO unsigned int MP_APB2ENCLRR;  	// 0xA0C
	__IO unsigned int MP_APB3ENSETR; 	// 0xA10
	__IO unsigned int MP_APB3ENCLRR; 	// 0xA14
	__IO unsigned int MP_AHB2ENSETR; 	// 0xA18
	__IO unsigned int MP_AHB2ENCLRR; 	// 0xA1C
	__IO unsigned int MP_AHB3ENSETR; 	// 0xA20
	__IO unsigned int MP_AHB3ENCLRR; 	// 0xA24
	__IO unsigned int MP_AHB4ENSETR; 	// 0xA28
	__IO unsigned int MP_AHB4ENCLRR; 	// 0xA2C
	__IO unsigned int res22[2];
	__IO unsigned int MP_MLAHBENSETR; 	// 0xA38
	__IO unsigned int MP_MLAHBENCLRR; 	// 0xA3C
	__IO unsigned int res23[16];
	__IO unsigned int MC_APB1ENSETR; 	// 0xA80
	__IO unsigned int MC_APB1ENCLRR; 	// 0xA84
	__IO unsigned int MC_APB2ENSETR; 	// 0xA88
	__IO unsigned int MC_APB2ENCLRR; 	// 0xA8C
	__IO unsigned int MC_APB3ENSETR; 	// 0xA90
	__IO unsigned int MC_APB3ENCLRR; 	// 0xA94
	__IO unsigned int MC_AHB2ENSETR; 	// 0xA98
	__IO unsigned int MC_AHB2ENCLRR; 	// 0xA9C
	__IO unsigned int MC_AHB3ENSETR; 	// 0xAA0
	__IO unsigned int MC_AHB3ENCLRR; 	// 0xAA4
	__IO unsigned int MC_AHB4ENSETR; 	// 0xAA8
	__IO unsigned int MC_AHB4ENCLRR; 	// 0xAAC
	__IO unsigned int MC_AXIMENSETR; 	// 0xAB0
	__IO unsigned int MC_AXIMENCLRR; 	// 0xAB4
	__IO unsigned int MC_MLAHBENSETR; 	// 0xAB8
	__IO unsigned int MC_MLAHBENCLRR; 	// 0xABC
	__IO unsigned int res24[16];
	__IO unsigned int MP_APB1LPENSETR; 	// 0xB00
	__IO unsigned int MP_APB1LPENCLRR; 	// 0xB04
	__IO unsigned int MP_APB2LPENSETR;  // 0xB08
	__IO unsigned int MP_APB2LPENCLRR; 	// 0xB0C
	__IO unsigned int MP_APB3LPENSETR; 	// 0xB10
	__IO unsigned int MP_APB3LPENCLRR;  // 0xB14
	__IO unsigned int MP_AHB2LPENSETR;  // 0xB18
	__IO unsigned int MP_AHB2LPENCLRR;  // 0xB1C
	__IO unsigned int MP_AHB3LPENSETR;  // 0xB20
	__IO unsigned int MP_AHB3LPENCLRR;  // 0xB24
	__IO unsigned int MP_AHB4LPENSETR;  // 0xB28
	__IO unsigned int MP_AHB4LPENCLRR;  // 0xB2C
	__IO unsigned int MP_AXIMLPENSETR;  // 0xB30
	__IO unsigned int MP_AXIMLPENCLRR;  // 0xB34
	__IO unsigned int MP_MLAHBLPENSETR; // 0xB38
	__IO unsigned int MP_MLAHBLPENCLRR; // 0xB3C
	__IO unsigned int res25[16];
	__IO unsigned int MC_APB1LPENSETR;  // 0xB80
	__IO unsigned int MC_APB1LPENCLRR; 	// 0xB84
	__IO unsigned int MC_APB2LPENSETR;  // 0xB88
	__IO unsigned int MC_APB2LPENCLRR;  // 0xB8C
	__IO unsigned int MC_APB3LPENSETR;  // 0xB90
	__IO unsigned int MC_APB3LPENCLRR;  // 0xB94
	__IO unsigned int MC_AHB2LPENSETR;  // 0xB98
	__IO unsigned int MC_AHB2LPENCLRR;  // 0xB9C
	__IO unsigned int MC_AHB3LPENSETR;  // 0xBA0
	__IO unsigned int MC_AHB3LPENCLRR;  // 0xBA4
	__IO unsigned int MC_AHB4LPENSETR;  // 0xBA8
	__IO unsigned int MC_AHB4LPENCLRR;  // 0xBAC
	__IO unsigned int MC_AXIMLPENSETR;  // 0xBB0
	__IO unsigned int MC_AXIMLPENCLRR;  // 0xBB4
	__IO unsigned int MC_MLAHBLPENSETR; // 0xBB8
	__IO unsigned int MC_MLAHBLPENCLRR; // 0xBBC
	__IO unsigned int res26[16];
	__IO unsigned int MC_RSTSCLRR;  	// 0xC00
	__IO unsigned int res27[4];
	__IO unsigned int MC_CIER;  		// 0xC14
	__IO unsigned int MC_CIFR; 			// 0xC18
	__IO unsigned int res28[246];
	__IO unsigned int VERR; 			// 0xFF4
	__IO unsigned int IDR; 				// 0xFF8
	__IO unsigned int SIDR; 			// 0xFFC
}RCC_TypeDef;


#endif //__STM32MP157XXX__

5、这里编写一份我们自己需要用到的平台总线自定义资源的头文件

#ifndef __PLATFORM_DATA_SPECIAL__
#define __PLATFORM_DATA_SPECIAL__

struct Platform_data_spex{
	char *name;  // 设备�?
	unsigned int minum;// 次设备号
	unsigned int MODER_SET;
	unsigned int MODER_RESET;

	unsigned int OTYPER_SET;
	unsigned int OTYPER_RESET;

	unsigned int OSPEEDR_SET;
	unsigned int OSPEEDR_RESET;

	unsigned int PUPDR_SET;
	unsigned int PUPDR_RESET;

	unsigned int IDR_SET;
	unsigned int IDR_RESET;

	unsigned int ODR_SET;
	unsigned int ODR_RESET;

	unsigned int BSRRL_SET;
	unsigned int BSRRL_RESET;

	unsigned int BSRRH_SET;
	unsigned int BSRRH_RESET;

	unsigned int LCKR_SET;
	unsigned int LCKR_RESET;

	unsigned int BRR_SET;
	unsigned int BRR_RESET;

	unsigned int SECCFGR_SET;
	unsigned int SECCFGR_RESET;

	unsigned int RCC_MP_REGISTER; //操作寄存器的哪一个位

	unsigned int RCC_OFFSET;
};


#endif //__PLATFORM_DATA_SPECIAL__
四、开始编写设备与驱动文件
1、device设备文件,具体看注释

Linux源码部分解析:

#include "linux/init.h"
#include "linux/module.h"
struct resource	 led_resource[][2]={//地址资源
	[0]={//PZ 5
		[0]={//GPIO
			.start  =GPIOZ_Base,//起始地址
			.end    =GPIOZ_Base+sizeof(GPIO_TypeDef)-1,//结束地址
			.name   ="gpioz",//资源名字
			.flags  =IORESOURCE_MEM,//资源类型,地址资源	
			},
		[1]={//RCC资源
				.start  =RCC_Base,//RCC基地址
				.end    =RCC_Base+sizeof(RCC_TypeDef)-1,//RCC结束地址
				.name   ="rcc",
				.flags  =IORESOURCE_MEM,//地址资源
			},
		},
	[1]={//PZ 6
		[0]={//GPIO
			.start  =GPIOZ_Base,
			.end    =GPIOZ_Base+sizeof(GPIO_TypeDef)-1,
			.name   ="gpioz",
			.flags  =IORESOURCE_MEM,	
			},
		[1]={//RCC��Դ
				.start  =RCC_Base,
				.end    =RCC_Base+sizeof(RCC_TypeDef)-1,
				.name   ="rcc",
				.flags  =IORESOURCE_MEM,
			},
		},
	[2]={//PZ 7
		[0]={//GPIO
			.start  =GPIOZ_Base,
			.end    =GPIOZ_Base+sizeof(GPIO_TypeDef)-1,
			.name   ="gpioz",
			.flags  =IORESOURCE_MEM,	
			},
		[1]={//RCC��Դ
				.start  =RCC_Base,
				.end    =RCC_Base+sizeof(RCC_TypeDef)-1,
				.name   ="rcc",
				.flags  =IORESOURCE_MEM,
			},
		},
	[3]={//PE8
		[0]={//GPIO
			.start  =GPIOE_Base,
			.end    =GPIOE_Base+sizeof(GPIO_TypeDef)-1,
			.name   ="gpioe",
			.flags  =IORESOURCE_MEM,	
			},
		[1]={//RCC��Դ
				.start  =RCC_Base,
				.end    =RCC_Base+sizeof(RCC_TypeDef)-1,
				.name   ="rcc",
				.flags  =IORESOURCE_MEM,
			},
		},
	[4]={//PE10
		[0]={//GPIO
			.start  =GPIOE_Base,
			.end    =GPIOE_Base+sizeof(GPIO_TypeDef)-1,
			.name   ="gpioe",
			.flags  =IORESOURCE_MEM,	
			},
		[1]={//RCC��Դ
				.start  =RCC_Base,
				.end    =RCC_Base+sizeof(RCC_TypeDef)-1,
				.name   ="rcc",
				.flags  =IORESOURCE_MEM,
			},
		},
	[5]={//PF10
		[0]={//GPIO
			.start  =GPIOF_Base,
			.end    =GPIOF_Base+sizeof(GPIO_TypeDef)-1,
			.name   ="gpiof",
			.flags  =IORESOURCE_MEM,	
			},
		[1]={//RCC��Դ
				.start  =RCC_Base,
				.end    =RCC_Base+sizeof(RCC_TypeDef)-1,
				.name   ="rcc",
				.flags  =IORESOURCE_MEM,
			},
		},
};

struct Platform_data_spex led_special[]={//自定义资源
	[0]={//pz5
		.name  ="drv_led0",//设备名字名字
		.minum =0,//次设备号,此处我们用次设备号用于排序
		.MODER_SET =0x1<<10,//位移操作,之前分析寄存器的时候有所要用哪些
		.MODER_RESET =0x3<<10,
	    .ODR_SET   =0x1<<5,
		.ODR_RESET =0x1<<5,
	    .RCC_MP_REGISTER=0,
		.RCC_OFFSET = 0x210/4,//偏移量,寄存器大小
		},
	[1]={//PZ6
		.name  ="drv_led1",
		.minum =1,
		.MODER_SET =0x1<<12,
		.MODER_RESET =0x3<<12,
	    .ODR_SET   =0x1<<6,
		.ODR_RESET =0x1<<6,
	    .RCC_MP_REGISTER=0,
		.RCC_OFFSET = 0x210/4,	
		},
	[2]={//PZ7
		.name  ="drv_led2",
		.minum =2,
		.MODER_SET =0x1<<14,
		.MODER_RESET =0x3<<14,
	    .ODR_SET   =0x1<<7,
		.ODR_RESET =0x1<<7,
	    .RCC_MP_REGISTER=0,
		.RCC_OFFSET = 0x210/4,	
		},
	[3]={//PE8
		.name  ="drv_led3",
		.minum =3,
		.MODER_SET =0x1<<16,
		.MODER_RESET =0x3<<16,
	    .ODR_SET   =0x1<<8,
		.ODR_RESET =0x1<<8,
	    .RCC_MP_REGISTER=4,
		.RCC_OFFSET = 0xA28/4,	
		},
	[4]={//PE10
		.name  ="drv_led4",
		.minum =4,
		.MODER_SET =0x1<<20,
		.MODER_RESET =0x3<<20,
	    .ODR_SET   =0x1<<10,
		.ODR_RESET =0x1<<10,
	    .RCC_MP_REGISTER=4,
		.RCC_OFFSET = 0xA28/4,	
		},
	[5]={//PF10
		.name  ="drv_led5",
		.minum =5,
		.MODER_SET =0x1<<20,
		.MODER_RESET =0x3<<20,
	    .ODR_SET   =0x1<<10,
		.ODR_RESET =0x1<<10,
	    .RCC_MP_REGISTER=5,
		.RCC_OFFSET = 0xA28/4,	
		},
};

void led_close(struct device *dev)
{
	//必须要调用的,卸载时候会调用
}
struct platform_device pdev[]={	//注册的结构体
	[0]={
		.name 		= "stm32mp157_led0",//匹配的名字
		.id			= -1,	//id号一般为-1
		.dev 		={//设备号结构体
		.release = led_close,	//卸载时调用
		.platform_data =&led_special[0],//获取的自定义资源
		},
		.num_resources =sizeof(led_resource[0])/sizeof(led_resource[0][0]),//资源个数
		.resource	   = led_resource[0],//资源
	},
	[1]={
		.name 		= "stm32mp157_led1",
		.id			= -1,
		.dev 		={
		.release = led_close,	
		.platform_data =&led_special[1],
		},
		.num_resources =sizeof(led_resource[1])/sizeof(led_resource[1][0]),
		.resource	   = led_resource[1],
	},
	[2]={
		.name 		= "stm32mp157_led2",
		.id			= -1,	
		.dev 		={
		.release = led_close,	
		.platform_data =&led_special[2],
		},
		.num_resources =sizeof(led_resource[2])/sizeof(led_resource[2][0]),
		.resource	   = led_resource[2],
	},
	[3]={
		.name 		= "stm32mp157_led3",
		.id			= -1,	
		.dev 		={
		.release = led_close,	
		.platform_data =&led_special[3],
		},
		.num_resources =sizeof(led_resource[3])/sizeof(led_resource[3][0]),
		.resource	   = led_resource[3],
	},
	[4]={
		.name 		= "stm32mp157_led4",
		.id			= -1,	
		.dev 		={
		.release = led_close,	
		.platform_data =&led_special[4],
		},
		.num_resources =sizeof(led_resource[4])/sizeof(led_resource[4][0]),
		.resource	   = led_resource[4],
	},
	[5]={
		.name 		= "stm32mp157_led5",
		.id			= -1,	
		.dev 		={
		.release = led_close,
		.platform_data =&led_special[5],
		},
		.num_resources =sizeof(led_resource[5])/sizeof(led_resource[5][0]),
		.resource	   = led_resource[5],
	},
	
};
static int __init led_device_init(void)//入口函数
{
	int ret =0;//判断返回值
	int i;//循环注册的变量
	for(i=0;i<ARRAY_SIZE(pdev);i++){//ARRAY_SIZES是一个宏用于求数据的大小,pdev是资源获取的机构体
 		ret =platform_device_register(&pdev[i]);//注册的个数
		if(ret<0){//注册失败
			printk("dev_led_init:platform_device_register is error\n");
				goto platform_device_register_err;//跳转到下面错误的操作
		}
	}
		return ret;
	platform_device_register_err://存在错误删除上述操作,退出
		for(;i>0;i--){
			platform_device_unregister(&pdev[i-1]);
		}		
		return ret;
}

void __exit led_device_exit(void)
{
	int i;
	printk("-----------------%s------------------\n",__FUNCTION__);
	for(i=0;i<ARRAY_SIZE(pdev);i++){
		platform_device_unregister(&pdev[i]);//卸载时注销
	}
	
}

module_init(led_device_init);//申明
module_exit(led_device_exit);
MODULE_LICENSE("GPL");//协议
2、drive设备文件,具体看注释
#include "linux/init.h"
#include "linux/module.h"
#include "linux/platform_device.h"
#include "linux/mod_devicetable.h"
#include "linux/slab.h"
#include "platform_data_special.h"
#include "linux/fs.h"
#include "linux/device.h"
#include "asm/io.h"
#include "stm32mp157xxx.h"
#include "linux/uaccess.h"
//注册设备号等基本信息结构体
struct stm32mp157axxx{
	unsigned int major;//设备号号
	struct class *cls;//类,创建需要用到节点类
	struct device *dev;//设备节点
	
	struct resource *led_resource[2];//LED的地址资源
	struct Platform_data_spex *led_special;//自定义资源
	unsigned int  *rcc;//RCC标识
	GPIO_TypeDef *gpio;//GPIO标识
};
struct stm32mp157axxx **led_drvs;//2级指针全局变量用于存放各类驱动的一级指针
int led_open(struct inode *inode, struct file *filp)//开灯函数,在入口函数后调用
{
	int ret = 0;
	struct stm32mp157axxx *led_drv;
	unsigned int minor;//次设备号,用于排序
	printk("-------------%s-----------------\n",__FUNCTION__);	
	minor = iminor(inode);//获取节点次设备号函数,Linux驱动的函数,可以直接使用
	led_drv = led_drvs[minor];//以次设备号做下表放在全局变量中
	if(!(*(led_drv->rcc+led_drv->led_special->RCC_OFFSET)&(1<<led_drv->led_special->RCC_MP_REGISTER))){ //判断时钟是否已经开启,有些时钟是启动时候已经开启了,所以需要判断
		*(led_drv->rcc+led_drv->led_special->RCC_OFFSET) |=(1<<led_drv->led_special->RCC_MP_REGISTER);//未开启,直接开启,上面有概述时钟
	}
	led_drv->gpio->MODER     &=~(led_drv->led_special->MODER_RESET);//模式先清理0再置1
	led_drv->gpio->MODER     |=led_drv->led_special->MODER_SET;
	// 设置ODR寄存器关灯
	led_drv->gpio->ODR      &=~(led_drv->led_special->ODR_RESET);
	return ret;	
}
int led_close(struct inode *inode, struct file *filp)
{
    //卸载时会自动调用
	int ret=0;
	printk("-------------%s-----------------\n",__FUNCTION__);	
	return ret;

}
//write写入函数,写入设备信息
ssize_t led_write(struct file *filp, const char __user *buf, size_t size, loff_t *flag)
{
	int ret=0;
	int on;
	struct stm32mp157axxx *led_drv;
	unsigned int minor;
	printk("-------------%s-----------------\n",__FUNCTION__);	
	minor=iminor(filp->f_inode);//获取节点信息
	led_drv =led_drvs[minor];
	ret=copy_from_user(&on,buf,size);//接受引用层信息,应用层和内核是无法直传递信息的需要此函数转换一下
	if(ret<0){//判断转换是否成功
		printk("drv_led_write: copy_from_user is error\n");
		return ret;
	}
	if(1==on){//判断应用层输入的值是多少,1开灯,0关灯
		led_drv->gpio->ODR      |=(led_drv->led_special->ODR_SET);	
	}else{
		led_drv->gpio->ODR      &=~(led_drv->led_special->ODR_RESET);
	}
	
	return ret;
}
const struct file_operations fops={//接口函数结构体
	.open	= led_open,//调用内核的接口函数,重新写入
	.release= led_close,
	.write	= led_write,
};



int led_probe(struct platform_device *pdev)
{
	int ret=0;
	struct stm32mp157axxx *led_drv;
	printk("-------------%s-----------------\n",__FUNCTION__);
	led_drv=kzalloc(sizeof(struct stm32mp157axxx),GFP_KERNEL);//开辟空间设备结构体存储空间
	if(IS_ERR(led_drv)){//判断开辟空间是否成功,IS_ERR函数,内核自带的,需要与PTR函数配合
		ret=PTR_ERR(led_drv);
		printk("led_probe: led_drv  kzalloc is error\n");
		return ret;
	}
	//led_drv->led_resource[],
	led_drv->led_resource[0]=platform_get_resource(pdev,IORESOURCE_MEM, 0);//获取地址资源,后面的0和1表示获取同类型资源的序号,IORESOURCE_MEM表示地址资源
	led_drv->led_resource[1]=platform_get_resource(pdev,IORESOURCE_MEM, 1);
	led_drv->led_special =pdev->dev.platform_data;//获取自定义资源
    
	led_drv->major = register_chrdev(0, led_drv->led_special->name, &fops);//注册设备号,0表示自动注册。
	if(led_drv->major<0){//注册设备号失败
		printk("drv_led_init: led_drv register_chrdev is error\n");
		ret =led_drv->major;
		goto register_chrdev_err;
	}	

	led_drv->cls = class_create(THIS_MODULE,led_drv->led_special->name);//创建节点类
	if(IS_ERR(led_drv->cls)){//判断节点类是否创建成功

		printk("drv_led_init: led_drv class_create is error\n");
		ret=PTR_ERR(led_drv->cls);
		goto class_create_err;//创建失败跳转到释放设备号处
	}	
	// 创建设备节点
	led_drv->dev=device_create(led_drv->cls,NULL,MKDEV(led_drv->major, led_drv->led_special->minum),NULL,led_drv->led_special
->name);
	//判断节点创建是否成功
	if(IS_ERR(led_drv->dev)){
		printk("drv_led_init: led_drv->dev device_create is error\n");
		ret=PTR_ERR(led_drv->dev);	
		goto device_create_err;//释放节点类
	}	
    //将虚拟空间映射到STM32MP157的RCC实际地址
	led_drv->rcc=ioremap(led_drv->led_resource[1]->start,led_drv->led_resource[1]->end - led_drv->led_resource[1]->start+1);
	if(IS_ERR(led_drv->rcc)){
		printk("drv_led_init: drv_led->rcc ioremap is error\n");
		ret=PTR_ERR(led_drv->rcc);//释放设备节点
		goto rcc_ioremap_err;
	}
     //将虚拟空间映射到STM32MP157的GPIO实际地址		
	led_drv->gpio=ioremap(led_drv->led_resource[0]->start,led_drv->led_resource[0]->end - led_drv->led_resource[0]->start+1);
	if(IS_ERR(led_drv->gpio)){
		printk("drv_led_init: led_drv->gpio ioremap is error\n");
		ret=PTR_ERR(led_drv->gpio);
		goto gpio_ioremap_err;
	}	
		led_drvs[led_drv->led_special->minum]=led_drv;
	
	return ret;
	gpio_ioremap_err:
		iounmap(led_drv->rcc);
	rcc_ioremap_err:
		device_destroy(led_drv->cls,MKDEV(led_drv->major, led_drv->led_special->minum));
	device_create_err:
		class_destroy(led_drv->cls);
	class_create_err:
		unregister_chrdev(led_drv->major,led_drv->led_special->name);
	register_chrdev_err:
		kfree(led_drv);
		return ret;

	
}
int led_remove(struct platform_device *pdev)//卸载时候自动调用需要将之前创建的空间之类的,设备号之类的东西全部释放掉,映射的东西也要接触映射
{
	int ret =0;
	struct stm32mp157axxx *led_drv;
	struct Platform_data_spex *led_special;//获取的自定义空间
	led_special=pdev->dev.platform_data;
	led_drv=led_drvs[led_special->minum];
	iounmap(led_drv->gpio);//解除映射GPIO
	iounmap(led_drv->rcc);
	device_destroy(led_drv->cls,MKDEV(led_drv->major, led_drv->led_special->minum));
	class_destroy(led_drv->cls);
	unregister_chrdev(led_drv->major,led_drv->led_special->name);
	kfree(led_drv);
	return ret;
}
const struct platform_device_id led_id_table[]={//字符设备匹配的名字

	{"stm32mp157_led0"},
	{"stm32mp157_led1"},
	{"stm32mp157_led2"},
	{"stm32mp157_led3"},
	{"stm32mp157_led4"},
	{"stm32mp157_led5"},
};

struct platform_driver pdrv={
	.probe 			= led_probe,//注册账号会自动调用的
	.remove			= led_remove,//卸载时候自动调用的函数
	.driver			={
		.name =  "led_drv",//设备的名字
			
	},
	.id_table	= led_id_table,//匹配的名字
};

static int __init led_driver_init(void)//入口函数
{
	int ret =0;
	printk("-----------------%s------------------\n",__FUNCTION__);
	led_drvs=kzalloc(sizeof(struct stm32mp157axxx *)*10, GFP_KERNEL);//注册
	if(IS_ERR(led_drvs)){
		ret=PTR_ERR(led_drvs);
		printk("led_driver_init:kzalloc is error\n");
		return ret;
	}
		 platform_driver_register(&pdrv);
	return ret;
}
void __exit led_driver_exit(void)
{
	printk("-----------------%s------------------\n",__FUNCTION__);
	
	platform_driver_unregister(&pdrv);//卸载
	kfree(led_drvs);
}
module_init(led_driver_init);//声明
module_exit(led_driver_exit);
MODULE_LICENSE("GPL");	//协议





3.简单写一下应用层的代码:
#include "stdio.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>

int main(void)
{
	int fd0,fd1,fd2,fd3,fd4,fd5;
	int on;
	int i;	
	fd0=open("/dev/drv_led0",O_RDWR);
	if(fd0<0){
		perror("open");
		exit(1);
	}
	fd1=open("/dev/drv_led1",O_RDWR);
	if(fd1<0){
		perror("open");
		exit(1);
	}
	fd2=open("/dev/drv_led2",O_RDWR);
	if(fd2<0){
		perror("open");
		exit(1);
	}
	fd3=open("/dev/drv_led3",O_RDWR);
	if(fd3<0){
		perror("open");
		exit(1);
	}
	fd4=open("/dev/drv_led4",O_RDWR);
	if(fd4<0){
		perror("open");
		exit(1);
	}
	fd5=open("/dev/drv_led5",O_RDWR);
	if(fd5<0){
		perror("open");
		exit(1);
	}
	while(1){
		printf("please input a data:");
		scanf("%d",&on);
		write(fd0,&on,sizeof(on));
		write(fd1,&on,sizeof(on));
		write(fd2,&on,sizeof(on));
		write(fd3,&on,sizeof(on));
		write(fd4,&on,sizeof(on));
		write(fd5,&on,sizeof(on));		
	}
	close(fd0);
	close(fd1);
	close(fd2);
	close(fd3);
	close(fd4);
	close(fd5);
	return 0;
}

五测试:

makefile函数:

#编译的地址
Kernel_Dir = /home/pm/fs-mp157/kernel/linux-stm32mp-5.4.31-r0/linux-5.4.31
#当前代码地址用PWD获取
Cue_Dir = ${shell pwd}

Myapp   = app_test
all :
	make -C $(Kernel_Dir) M=$(Cue_Dir) modules
	$(CC)  $(Myapp).c  -o $(Myapp)
clean:
	make -C $(Kernel_Dir) M=$(Cue_Dir) clean
	rm $(Myapp)
install://将编译的.ko文件放到Linux开发板中
	cp ./*.ko  $(Myapp) /opt/rootfs/drv_module 
	
obj-m =led_device.o
obj-m +=led_drivers.o

make的时候出现这个莫慌,是交叉编译器没有导入的原因,不是makefile写错了。

输入:source /opt/st/stm32mp1/3.1-openstlinux-5.4-dunfell-mp1-20-06-24/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi再内核文件目录下就ok了

你看这不就解决了吗。

 测试加载一下:

加载结果:

实验结果:

看这不就点亮了了嘛,简简单单,加油咯。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值