平台总线(实操)---实现(多个)LED灯的资源传递

一、业务需求和分析

业务需求:利用平台总线的方式实现多个LED灯的开和关(PZ5、6、7和PE8、10和PF10)

业务分析:

        1、只有一个driver.c和一个device.c (不要写多个device.c)

        2、将driver.c封装成一个通用的led控制文件,也就是就算一百个灯,driver.c也不需要修改,只要在device.c中增加相应的GPIO资源。

二、 编程实现步骤

device.c中的修改:

        1、首先,我们这里有六个设备,led0到led5,有六个灯,就需要提供六个灯的寄存器地址资源和描述设备的其他资源
        a:将前面的传递寄存器资源的数组(struct resource led_resource[]),定义成一个二维数组,二维数值中的每一个一维数组都表示一个设备的寄存器地址资源。

struct resource led_resource[][2]={//具体的地址资源或者中断资源
	[0]={//PZ5
		[0]={//RCC的地址资源
				.start  = RCC_Base,
				.end    = RCC_Base+sizeof(RCC_TypeDef)-1,
				.name   = "rcc",
				.flags  = IORESOURCE_MEM,
			},

	   [1]={//GPIO的地址资源
				.start  = GPIOZ_Base,
				.end    = GPIOZ_Base+sizeof(GPIO_TypeDef)-1,
				.name   = "gpioz",
				.flags  = IORESOURCE_MEM,
			},
	},
	[1]={//PZ6
		[0]={//RCC的地址资源
				.start  = RCC_Base,
				.end    = RCC_Base+sizeof(RCC_TypeDef)-1,
				.name   = "rcc",
				.flags  = IORESOURCE_MEM,
			},

	   [1]={//GPIO的地址资源
				.start  = GPIOZ_Base,
				.end    = GPIOZ_Base+sizeof(GPIO_TypeDef)-1,
				.name   = "gpioz",
				.flags  = IORESOURCE_MEM,
			},
	},
	[2]={//PZ7
		[0]={//RCC的地址资源
				.start  = RCC_Base,
				.end    = RCC_Base+sizeof(RCC_TypeDef)-1,
				.name   = "rcc",
				.flags  = IORESOURCE_MEM,
			},

	   [1]={//GPIO的地址资源
				.start  = GPIOZ_Base,
				.end    = GPIOZ_Base+sizeof(GPIO_TypeDef)-1,
				.name   = "gpioz",
				.flags  = IORESOURCE_MEM,
			},
	},
	[3]={//PE8
		[0]={//RCC的地址资源
				.start  = RCC_Base,
				.end    = RCC_Base+sizeof(RCC_TypeDef)-1,
				.name   = "rcc",
				.flags  = IORESOURCE_MEM,
			},

	   [1]={//GPIO的地址资源
				.start  = GPIOE_Base,
				.end    = GPIOE_Base+sizeof(GPIO_TypeDef)-1,
				.name   = "gpioe",
				.flags  = IORESOURCE_MEM,
			},
	},
	[4]={//PE10
		[0]={//RCC的地址资源
				.start  = RCC_Base,
				.end    = RCC_Base+sizeof(RCC_TypeDef)-1,
				.name   = "rcc",
				.flags  = IORESOURCE_MEM,
			},

	   [1]={//GPIO的地址资源
				.start  = GPIOE_Base,
				.end    = GPIOE_Base+sizeof(GPIO_TypeDef)-1,
				.name   = "gpioe",
				.flags  = IORESOURCE_MEM,
			},
	},
	[5]={//PF10
		[0]={//RCC的地址资源
				.start  = RCC_Base,
				.end    = RCC_Base+sizeof(RCC_TypeDef)-1,
				.name   = "rcc",
				.flags  = IORESOURCE_MEM,
			},

	   [1]={//GPIO的地址资源
				.start  = GPIOF_Base,
				.end    = GPIOF_Base+sizeof(GPIO_TypeDef)-1,
				.name   = "gpiof",
				.flags  = IORESOURCE_MEM,
			},
	},
};

        b:将前面的传递其他描述设备资源的变量(struct Platform_data_spex led_special)定义成一个一维数组,一维数值中的每一个元素都表示一个设备的其他描述设备的资源。 

struct Platform_data_spex special_data[]={
	[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,
	},
};

         2、前面是描述设备的资源,接下来,需要用结构体来描述这两个设备,因为有两个设备,自然也需要两个struct platform_device结构体,同样的我们可以定义一个这个类型的结构体数组来描述这两个资源,一个元素,描述一个资源

struct platform_device pdev[]={//描述这个硬件设备的信息
	[0]={
		.name  = "stm32mp157xxx_led0",//匹配的名字,这个硬件设备和谁去匹配
		.id    = -1,//一般为-1
		.dev   = {//自定义资源在这个里面定义,暂时我还没用
			.release  = drv_led_release,//在卸载时会报错,所以需要实现
			.platform_data = &special_data[0],//将定义好的资源传给driver.c
		},
		.num_resources  = sizeof(led_resource[0])/sizeof(led_resource[0][0]),//有多少个struct resource这个类型的结构体数据,用总的数据长度/一个数据的长度
		.resource       = led_resource[0],//要传递的资源的首地址
	},
	[1]={
		.name  = "stm32mp157xxx_led1",//匹配的名字,这个硬件设备和谁去匹配
		.id    = -1,//一般为-1
		.dev   = {//自定义资源在这个里面定义,暂时我还没用
			.release  = drv_led_release,//在卸载时会报错,所以需要实现
			.platform_data = &special_data[1],//将定义好的资源传给driver.c
		},
		.num_resources  = sizeof(led_resource[1])/sizeof(led_resource[1][0]),//有多少个struct resource这个类型的结构体数据,用总的数据长度/一个数据的长度
		.resource       = led_resource[1],//要传递的资源的首地址
	},
	[2]={
		.name  = "stm32mp157xxx_led2",//匹配的名字,这个硬件设备和谁去匹配
		.id    = -1,//一般为-1
		.dev   = {//自定义资源在这个里面定义,暂时我还没用
			.release  = drv_led_release,//在卸载时会报错,所以需要实现
			.platform_data = &special_data[2],//将定义好的资源传给driver.c
		},
		.num_resources  = sizeof(led_resource[2])/sizeof(led_resource[2][0]),//有多少个struct resource这个类型的结构体数据,用总的数据长度/一个数据的长度
		.resource       = led_resource[2],//要传递的资源的首地址
	},
	[3]={
		.name  = "stm32mp157xxx_led3",//匹配的名字,这个硬件设备和谁去匹配
		.id    = -1,//一般为-1
		.dev   = {//自定义资源在这个里面定义,暂时我还没用
			.release  = drv_led_release,//在卸载时会报错,所以需要实现
			.platform_data = &special_data[3],//将定义好的资源传给driver.c
		},
		.num_resources  = sizeof(led_resource[3])/sizeof(led_resource[3][0]),//有多少个struct resource这个类型的结构体数据,用总的数据长度/一个数据的长度
		.resource       = led_resource[3],//要传递的资源的首地址
	},
	[4]={
		.name  = "stm32mp157xxx_led4",//匹配的名字,这个硬件设备和谁去匹配
		.id    = -1,//一般为-1
		.dev   = {//自定义资源在这个里面定义,暂时我还没用
			.release  = drv_led_release,//在卸载时会报错,所以需要实现
			.platform_data = &special_data[4],//将定义好的资源传给driver.c
		},
		.num_resources  = sizeof(led_resource[4])/sizeof(led_resource[4][0]),//有多少个struct resource这个类型的结构体数据,用总的数据长度/一个数据的长度
		.resource       = led_resource[4],//要传递的资源的首地址
	},
	[5]={
		.name  = "stm32mp157xxx_led5",//匹配的名字,这个硬件设备和谁去匹配
		.id    = -1,//一般为-1
		.dev   = {//自定义资源在这个里面定义,暂时我还没用
			.release  = drv_led_release,//在卸载时会报错,所以需要实现
			.platform_data = &special_data[5],//将定义好的资源传给driver.c
		},
		.num_resources  = sizeof(led_resource[5])/sizeof(led_resource[5][0]),//有多少个struct resource这个类型的结构体数据,用总的数据长度/一个数据的长度
		.resource       = led_resource[5],//要传递的资源的首地址
	},
};

3、因为有两个设备所以需要将两个设备都注册到平台总线中,所以需要注册两次 

// 2,入口函数----在加载,insmod的时候调用的函数
static int __init dev_led_init(void)
{
	int ret = 0,i;
	printk("-------------%s-----------------\n",__FUNCTION__);
	for(i = 0; i < ARRAY_SIZE(pdev); i++){
		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;
}

4、在出口函数中,注销设备

// 3,出口函数---在卸载这个模块,rmmod的时候调用
static void __exit dev_led_exit (void)
{
	int i;
	printk("-------------%s-----------------\n",__FUNCTION__);
	for(i=0;i<ARRAY_SIZE(pdev);i++){
		platform_device_unregister(&pdev[i]);//平台总线中移除一个硬件设备
	}
}

driver.c中的修改:

1、首先你注册多个设备和driver.c匹配,你的driver.c就应该能够兼容多个设备

const struct platform_device_id led_id_table[]={
	{"stm32mp157xxx_led0"},//这个名字必须和device.c中的platform_device中的name名字一致
	{"stm32mp157xxx_led1"},
	{"stm32mp157xxx_led2"},
	{"stm32mp157xxx_led3"},
	{"stm32mp157xxx_led4"},
	{"stm32mp157xxx_led5"},	
};

            2、这样改好了以后,可以试一下看能不能调用多次probe,每注册一次pdev会调用一次,这里六个灯就是六次 

        3、虽然能调用两次probe,但是每次调用probe都是用的drv_led这个指针,当你调用了led0的资源后,再调用led1的资源,然后你再想操作led0,你还能找到led0的资源吗?不能吧,在第二次匹配的时候,led0的资源已经被覆盖了,所以我们就要思考,怎么能把多个灯的资源全部都保存下来?
        灯的资源我们现在是用struct stm32mp157a_led *drv_led;来保存的,可不可以这样,每次获取到资源,注册完设备号设备节点,映射地址后,我将drv_led保存下来,当我要操作某个灯的时候再将它调出来。用什么保持呢?因为你每个设备资源是一个指针(struct stm32mp157a_led *drv_led),我们可不可以用一个数组将它们保存起来,并且是用一个指针数组。并且用每一个设备的次设备号作为数组下标。
        具体如何实现,步骤如下:

a、定义一个二级指针(相当于指针数组),全局的,用来保存每个设备的资源,设备号,设备文件等等 

struct stm32mp157axxx **drv_leds;

b、给这个二级指针申请空间,相当于给数组申请空间----------在入口函数中申请 

// 2,入口函数----在加载,insmod的时候调用的函数
static int __init drv_led_init(void)
{
	int ret=0;
	printk("-------------%s-----------------\n",__FUNCTION__);
	drv_leds=kzalloc(sizeof(struct stm32mp157axxx *)*10, GFP_KERNEL);
	if(IS_ERR(drv_leds)){
		ret=PTR_ERR(drv_leds);
		printk("drv_led_init:kzalloc is error\n");
		return ret;
	}
	platform_driver_register(&pdrv); //注册一个驱动到平台总线中
	return 	ret;
}

c、在出口函数中去释放空间

// 3,出口函数---在卸载这个模块,rmmod的时候调用
static void __exit drv_led_exit (void)
{
	printk("-------------%s-----------------\n",__FUNCTION__);
	platform_driver_unregister(&pdrv);//从平台总线中,移除这个驱动
	kfree(drv_leds);
}

d、利用开辟的空间去保存设备的参数----------probe函数

        1、在probe中定义一个局部的drv_led变量,以前那个全局的删除             

    struct stm32mp157axxx *drv_led;

        2、其他的不要变,在probe函数的最后,将drv_led保存在drv_leds中                   

drv_leds[drv_led->led_pdata->minum]=drv_led;

e、在卸载设备的时候,调用remove函数,卸载设备,我们要找到对应的需要卸载的设备

        1、在remove中定义一个局部的drv_led变量,             

    struct stm32mp157axxx *drv_led;

         2、根据struct platform_device *pdev中的dev中的platform_data拿到次设备号,找到次设备号。定义一个特殊资源指针,拿到特殊资源                

    //定义一个指针,用于接收这个设备所对应的自定义的数据
    struct Platform_data_spex *led_special; 
    //从pdev中拿到自定义数据,指针指向自定义数据
    led_special=pdev->dev.platform_data;

        3、将drv_leds中次设备号所对应数组下标的元素给drv_led           

    //从自定义数据中拿到次设备号,再将次设备号作为数组下标,找到对应的设备操作对象
    drv_led=drv_leds[led_special->minum];

f、在应用层调用open的时候,我们要找到对应的设备,操作 

        1、在open中定义一个局部的drv_led变量,                 

    struct stm32mp157axxx *drv_led;

        2、根据 struct file *filp找到次设备号,将drv_leds中次设备号所对应数组下标的元素给drv_led                

    unsigned int minor;
    minor=iminor(inode);
	drv_led =drv_leds[minor];

g、在应用层调用write的时候,我们要找到对应的设备,操作

        1、在write中定义一个局部的drv_led变量,                

    struct stm32mp157axxx *drv_led;

        2、根据 struct file *filp找到次设备号,将drv_leds中次设备号所对应数组下标的元素给drv_led                

    minor=iminor(filp->f_inode); //根据filp中的完整的设备号,获得次设备号
	drv_led =drv_leds[minor];    //根据次设备号,找到操作的设备对象

三、完整程序

app.c文件

#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;
	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/xyn/fs_mp157/kernel/linux-stm32mp-5.4.31-r0/linux-5.4.31
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:
	 cp ./*.ko $(Myapp) /opt/rootfs/drv_module/

obj-m =platform_led_driver.o
obj-m +=platform_led_device.o

special文件

#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__

device.c

// 1,头文件
#include "linux/init.h"
#include "linux/module.h"
#include "linux/platform_device.h"
#include "stm32mp157xxx.h"
#include "platform_data_special.h"

//这是在定义自定的资源,因为这些资源会随着硬件的变化而改变
struct Platform_data_spex special_data[]={
	[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,
	},
};

struct resource led_resource[][2]={//具体的地址资源或者中断资源
	[0]={//PZ5
		[0]={//RCC的地址资源
				.start  = RCC_Base,
				.end    = RCC_Base+sizeof(RCC_TypeDef)-1,
				.name   = "rcc",
				.flags  = IORESOURCE_MEM,
			},

	   [1]={//GPIO的地址资源
				.start  = GPIOZ_Base,
				.end    = GPIOZ_Base+sizeof(GPIO_TypeDef)-1,
				.name   = "gpioz",
				.flags  = IORESOURCE_MEM,
			},
	},
	[1]={//PZ6
		[0]={//RCC的地址资源
				.start  = RCC_Base,
				.end    = RCC_Base+sizeof(RCC_TypeDef)-1,
				.name   = "rcc",
				.flags  = IORESOURCE_MEM,
			},

	   [1]={//GPIO的地址资源
				.start  = GPIOZ_Base,
				.end    = GPIOZ_Base+sizeof(GPIO_TypeDef)-1,
				.name   = "gpioz",
				.flags  = IORESOURCE_MEM,
			},
	},
	[2]={//PZ7
		[0]={//RCC的地址资源
				.start  = RCC_Base,
				.end    = RCC_Base+sizeof(RCC_TypeDef)-1,
				.name   = "rcc",
				.flags  = IORESOURCE_MEM,
			},

	   [1]={//GPIO的地址资源
				.start  = GPIOZ_Base,
				.end    = GPIOZ_Base+sizeof(GPIO_TypeDef)-1,
				.name   = "gpioz",
				.flags  = IORESOURCE_MEM,
			},
	},
	[3]={//PE8
		[0]={//RCC的地址资源
				.start  = RCC_Base,
				.end    = RCC_Base+sizeof(RCC_TypeDef)-1,
				.name   = "rcc",
				.flags  = IORESOURCE_MEM,
			},

	   [1]={//GPIO的地址资源
				.start  = GPIOE_Base,
				.end    = GPIOE_Base+sizeof(GPIO_TypeDef)-1,
				.name   = "gpioe",
				.flags  = IORESOURCE_MEM,
			},
	},
	[4]={//PE10
		[0]={//RCC的地址资源
				.start  = RCC_Base,
				.end    = RCC_Base+sizeof(RCC_TypeDef)-1,
				.name   = "rcc",
				.flags  = IORESOURCE_MEM,
			},

	   [1]={//GPIO的地址资源
				.start  = GPIOE_Base,
				.end    = GPIOE_Base+sizeof(GPIO_TypeDef)-1,
				.name   = "gpioe",
				.flags  = IORESOURCE_MEM,
			},
	},
	[5]={//PF10
		[0]={//RCC的地址资源
				.start  = RCC_Base,
				.end    = RCC_Base+sizeof(RCC_TypeDef)-1,
				.name   = "rcc",
				.flags  = IORESOURCE_MEM,
			},

	   [1]={//GPIO的地址资源
				.start  = GPIOF_Base,
				.end    = GPIOF_Base+sizeof(GPIO_TypeDef)-1,
				.name   = "gpiof",
				.flags  = IORESOURCE_MEM,
			},
	},
};
void drv_led_release(struct device *dev)
{
	//必须实现,可以不干事,在卸载这个驱动时,会被调用,如果找不到这个函数,系统会提示错误
}
struct platform_device pdev[]={//描述这个硬件设备的信息
	[0]={
		.name  = "stm32mp157xxx_led0",//匹配的名字,这个硬件设备和谁去匹配
		.id    = -1,//一般为-1
		.dev   = {//自定义资源在这个里面定义,暂时我还没用
			.release  = drv_led_release,//在卸载时会报错,所以需要实现
			.platform_data = &special_data[0],//将定义好的资源传给driver.c
		},
		.num_resources  = sizeof(led_resource[0])/sizeof(led_resource[0][0]),//有多少个struct resource这个类型的结构体数据,用总的数据长度/一个数据的长度
		.resource       = led_resource[0],//要传递的资源的首地址
	},
	[1]={
		.name  = "stm32mp157xxx_led1",//匹配的名字,这个硬件设备和谁去匹配
		.id    = -1,//一般为-1
		.dev   = {//自定义资源在这个里面定义,暂时我还没用
			.release  = drv_led_release,//在卸载时会报错,所以需要实现
			.platform_data = &special_data[1],//将定义好的资源传给driver.c
		},
		.num_resources  = sizeof(led_resource[1])/sizeof(led_resource[1][0]),//有多少个struct resource这个类型的结构体数据,用总的数据长度/一个数据的长度
		.resource       = led_resource[1],//要传递的资源的首地址
	},
	[2]={
		.name  = "stm32mp157xxx_led2",//匹配的名字,这个硬件设备和谁去匹配
		.id    = -1,//一般为-1
		.dev   = {//自定义资源在这个里面定义,暂时我还没用
			.release  = drv_led_release,//在卸载时会报错,所以需要实现
			.platform_data = &special_data[2],//将定义好的资源传给driver.c
		},
		.num_resources  = sizeof(led_resource[2])/sizeof(led_resource[2][0]),//有多少个struct resource这个类型的结构体数据,用总的数据长度/一个数据的长度
		.resource       = led_resource[2],//要传递的资源的首地址
	},
	[3]={
		.name  = "stm32mp157xxx_led3",//匹配的名字,这个硬件设备和谁去匹配
		.id    = -1,//一般为-1
		.dev   = {//自定义资源在这个里面定义,暂时我还没用
			.release  = drv_led_release,//在卸载时会报错,所以需要实现
			.platform_data = &special_data[3],//将定义好的资源传给driver.c
		},
		.num_resources  = sizeof(led_resource[3])/sizeof(led_resource[3][0]),//有多少个struct resource这个类型的结构体数据,用总的数据长度/一个数据的长度
		.resource       = led_resource[3],//要传递的资源的首地址
	},
	[4]={
		.name  = "stm32mp157xxx_led4",//匹配的名字,这个硬件设备和谁去匹配
		.id    = -1,//一般为-1
		.dev   = {//自定义资源在这个里面定义,暂时我还没用
			.release  = drv_led_release,//在卸载时会报错,所以需要实现
			.platform_data = &special_data[4],//将定义好的资源传给driver.c
		},
		.num_resources  = sizeof(led_resource[4])/sizeof(led_resource[4][0]),//有多少个struct resource这个类型的结构体数据,用总的数据长度/一个数据的长度
		.resource       = led_resource[4],//要传递的资源的首地址
	},
	[5]={
		.name  = "stm32mp157xxx_led5",//匹配的名字,这个硬件设备和谁去匹配
		.id    = -1,//一般为-1
		.dev   = {//自定义资源在这个里面定义,暂时我还没用
			.release  = drv_led_release,//在卸载时会报错,所以需要实现
			.platform_data = &special_data[5],//将定义好的资源传给driver.c
		},
		.num_resources  = sizeof(led_resource[5])/sizeof(led_resource[5][0]),//有多少个struct resource这个类型的结构体数据,用总的数据长度/一个数据的长度
		.resource       = led_resource[5],//要传递的资源的首地址
	},
};
// 2,入口函数----在加载,insmod的时候调用的函数
static int __init dev_led_init(void)
{
	int ret = 0,i;
	printk("-------------%s-----------------\n",__FUNCTION__);
	for(i = 0; i < ARRAY_SIZE(pdev); i++){
		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;
}
// 3,出口函数---在卸载这个模块,rmmod的时候调用
static void __exit dev_led_exit (void)
{
	int i;
	printk("-------------%s-----------------\n",__FUNCTION__);
	for(i=0;i<ARRAY_SIZE(pdev);i++){
		platform_device_unregister(&pdev[i]);//平台总线中移除一个硬件设备
	}
}
// 声明
module_init(dev_led_init);//声明入口函数是哪一个函数
module_exit(dev_led_exit);//声明哪一个函数是出口函数
MODULE_LICENSE("GPL");

driver.c

// 1,头文件
#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 *devi;

	struct resource *led_resource[2];
	struct Platform_data_spex *led_pdata; 

	unsigned int  *rcc;
	GPIO_TypeDef *gpio;
};

struct stm32mp157axxx **drv_leds;

int drv_led_open(struct inode *inode, struct file *filp)
{
	int ret = 0;
	struct stm32mp157axxx *drv_led;
	unsigned int minor;
	printk("-------------%s-----------------\n",__FUNCTION__);	
	minor = iminor(inode);
	drv_led = drv_leds[minor];
	if(!(*(drv_led->rcc+drv_led->led_pdata->RCC_OFFSET)&(1<<drv_led->led_pdata->RCC_MP_REGISTER))){ //判断时钟是否是默认开启
		*(drv_led->rcc+drv_led->led_pdata->RCC_OFFSET) |=(1<<drv_led->led_pdata->RCC_MP_REGISTER);//如果时钟未开始,打开时钟
	}

	// 设置GPIOZ的第5个引脚的模式
	drv_led->gpio->MODER     &= ~(drv_led->led_pdata->MODER_RESET);
	drv_led->gpio->MODER     |= drv_led->led_pdata->MODER_SET;

	// 默认关灯
	drv_led->gpio->ODR       &= ~(drv_led->led_pdata->ODR_RESET);
	return ret;
}

int drv_led_close(struct inode *inode, struct file *filp)
{
	int ret=0;
	printk("-------------%s-----------------\n",__FUNCTION__);	
	return ret;

}
// 实现write接口
ssize_t drv_led_write(struct file *filp, const char __user *buf, size_t size, loff_t *flag)
{
	int ret = 0;
	int on;
	struct stm32mp157axxx *drv_led;
	unsigned int minor; //定义一个变量,用于接收次设备号
	printk("-------------%s-----------------\n",__FUNCTION__);	
	minor = iminor(filp->f_inode);//根据filp中的完整的设备号,获得次设备号
	drv_led = drv_leds[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){
		drv_led->gpio->ODR      |=(drv_led->led_pdata->ODR_SET);	
	}else{
		drv_led->gpio->ODR      &=~(drv_led->led_pdata->ODR_RESET);
	}
	return ret;
}

const struct file_operations fops={
	.open   =drv_led_open,
	.release=drv_led_close,
	.write  =drv_led_write,
};

int drv_led_probe(struct platform_device *pdev)
{
	int ret = 0;
	struct stm32mp157axxx *drv_led;
	printk("-------------%s-----------------\n",__FUNCTION__);
	drv_led = kzalloc(sizeof(struct stm32mp157axxx),GFP_KERNEL);
	if(IS_ERR(drv_led)){
		ret=PTR_ERR(drv_led);
		printk("drv_led_probe: drv_led  kzalloc is error\n");
		return ret;
	}
	drv_led->led_resource[0]=platform_get_resource(pdev,IORESOURCE_MEM,0);
	printk("led_resource[0]->start=0x%x,led_resource[0]->end=0x%x\n",drv_led->led_resource[0]->start,drv_led->led_resource[0]->end);
	drv_led->led_resource[1]=platform_get_resource(pdev,IORESOURCE_MEM,1);
	printk("led_resource[1]->start=0x%x,led_resource[1]->end=0x%x\n",drv_led->led_resource[1]->start,drv_led->led_resource[1]->end);

	drv_led->led_pdata =pdev->dev.platform_data;
	printk("drv_led->led_pdata->name=%s\n",drv_led->led_pdata->name);
    printk("drv_led->led_pdata->minum=%d\n",drv_led->led_pdata->minum);
	printk("drv_led->led_pdata->MODER_SET=%d\n",drv_led->led_pdata->MODER_SET);
	printk("drv_led->led_pdata->MODER_RESET=%d\n",drv_led->led_pdata->MODER_RESET);
	printk("drv_led->led_pdata->ODR_SET=%d\n",drv_led->led_pdata->ODR_SET);
	printk("drv_led->led_pdata->ODR_RESET=%d\n",drv_led->led_pdata->ODR_RESET);
	printk("drv_led->led_pdata->RCC_MP_REGISTER=%d\n",drv_led->led_pdata->RCC_MP_REGISTER);
	printk("drv_led->led_pdata->RCC_OFFSET=%d\n",drv_led->led_pdata->RCC_OFFSET);

	//1,申请设备号-----动态分配
	drv_led->major=register_chrdev(0,drv_led->led_pdata->name,&fops);
	if(drv_led->major<0){
		printk("drv_led_init: drv_led register_chrdev is error\n");
		ret =drv_led->major;
		goto register_chrdev_err;
	}	
// 2,创建设备文件
	// 1,创建类
	drv_led->cls = class_create(THIS_MODULE,drv_led->led_pdata->name);
	//判断drv_led->cls 创建类是否成功
	if(IS_ERR(drv_led->cls)){//判断drv_led->cls这个类创建是否成功,如果指向空,IS_ERR(drv_led->cls)的结果就为真
		printk("drv_led_init: drv_led class_create is error\n");
		ret=PTR_ERR(drv_led->cls);//获得错误码
		goto class_create_err;
	}	

	// 2,创建设备文件		
	drv_led->devi=device_create(drv_led->cls,NULL,MKDEV(drv_led->major, drv_led->led_pdata->minum),NULL,drv_led->led_pdata->name);
	//判断drv_led->devi 创建类是否成功
	if(IS_ERR(drv_led->devi)){//判断drv_led->devi这个类创建是否成功,如果指向空,IS_ERR(drv_led->devi)的结果就为真
		printk("drv_led_init: drv_led device_create is error\n");
		ret=PTR_ERR(drv_led->devi);//获得错误码
		goto device_create_err;
	}	

	drv_led->rcc=ioremap(drv_led->led_resource[0]->start,drv_led->led_resource[0]->end-drv_led->led_resource[0]->start+1);
	if(IS_ERR(drv_led->rcc)){
		printk("drv_led_init: drv_led->rcc ioremap is error\n");
		ret=PTR_ERR(drv_led->rcc);//获得错误码
		goto rcc_ioremap_err;
	}		
	drv_led->gpio=ioremap(drv_led->led_resource[1]->start,drv_led->led_resource[1]->end-drv_led->led_resource[1]->start+1);
	if(IS_ERR(drv_led->gpio)){
		printk("drv_led_init: drv_led->gpio ioremap is error\n");
		ret=PTR_ERR(drv_led->gpio);//获得错误码
		goto gpio_ioremap_err;
	}		
	drv_leds[drv_led->led_pdata->minum]=drv_led;
	return ret;
	gpio_ioremap_err:
		iounmap(drv_led->rcc);
	rcc_ioremap_err:
		device_destroy(drv_led->cls,MKDEV(drv_led->major, drv_led->led_pdata->minum));//删除设备文件
	device_create_err:
		class_destroy(drv_led->cls);//删除类
	class_create_err:
		unregister_chrdev(drv_led->major,drv_led->led_pdata->name);//删除设备号
	register_chrdev_err:
		kfree(drv_led);//当申请设备号失败,释放指针空间
		return ret;

}
int drv_led_remove(struct platform_device *pdev)
{
	int ret=0;
	struct stm32mp157axxx *drv_led;
	struct Platform_data_spex *led_special; //定义一个指针,用于接收这个设备所对应的自定义的数据
	printk("-------------%s-----------------\n",__FUNCTION__);
	led_special=pdev->dev.platform_data;//从pdev中拿到自定义数据,指针指向自定义数据
	drv_led=drv_leds[led_special->minum];//从自定义数据中拿到次设备号,再将次设备号作为数组下标,找到对应的设备操作对象
	iounmap(drv_led->gpio);
	iounmap(drv_led->rcc);
	device_destroy(drv_led->cls,MKDEV(drv_led->major, drv_led->led_pdata->minum));//删除设备文件
	class_destroy(drv_led->cls);//删除类
	unregister_chrdev(drv_led->major,drv_led->led_pdata->name);//删除设备号
	kfree(drv_led);
	return ret;
}
const struct platform_device_id led_id_table[]={
	{"stm32mp157xxx_led0"},//这个名字必须和device.c中的platform_device中的name名字一致
	{"stm32mp157xxx_led1"},
	{"stm32mp157xxx_led2"},
	{"stm32mp157xxx_led3"},
	{"stm32mp157xxx_led4"},
	{"stm32mp157xxx_led5"},	
};

struct platform_driver pdrv={ //具体的驱动
	.probe   =drv_led_probe,//在驱动driver.c和device.c匹配成功后,会调用这个函数
	.remove  =drv_led_remove,//在移除driver.c和device.c中的任何一个会调用的函数
	.driver  ={
		.name ="drv_led",//描述这个驱动的名字
	},
	.id_table =led_id_table,//用于和硬件设备匹配的名字数组
};

// 2,入口函数----在加载,insmod的时候调用的函数
static int __init drv_led_init(void)
{
	int ret=0;
	printk("-------------%s-----------------\n",__FUNCTION__);
	drv_leds=kzalloc(sizeof(struct stm32mp157axxx *)*10, GFP_KERNEL);
	if(IS_ERR(drv_leds)){
		ret=PTR_ERR(drv_leds);
		printk("drv_led_init:kzalloc is error\n");
		return ret;
	}
	platform_driver_register(&pdrv); //注册一个驱动到平台总线中
	return 	ret;
}

// 3,出口函数---在卸载这个模块,rmmod的时候调用
static void __exit drv_led_exit (void)
{
	printk("-------------%s-----------------\n",__FUNCTION__);
	platform_driver_unregister(&pdrv);//从平台总线中,移除这个驱动
	kfree(drv_leds);
}
// 声明
module_init(drv_led_init);//声明入口函数是哪一个函数
module_exit(drv_led_exit);//声明哪一个函数是出口函数
MODULE_LICENSE("GPL");

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__

四、程序结果

 注意!!!

1、两个资源的接收指针必须放在结构体中

struct stm32mp157a_led{
    unsigned int major;
    struct class *cls;
    struct device *dev;
    GPIO_TypeDef *GPIO;
    unsigned int  *RCC;
    struct resource *led_reg_resource[10];
    struct Platform_data_spex *led_special;
};

2、在probe中定义了struct stm32mp157a_led * drv_led;必须先分配空间再去使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值