平台总线(三)

平台总线:用于平台升级的
三星: 
s3c2410  --------------- s3c6410 ----------- s5pv210
gpio控制器            gpio控制器 gpio控制器
 uart 
 i2c
 spi

控制逻辑方法相同:1,配置gpio寄存器
    2.读写数据

地址会不同


三元素:
总线: 开机的时候就已经创建了,不需要我们创建
struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};


device对象:
struct platform_device {//是一个名字,描述设备属性
const char * name; //用于匹配
int id;
struct device dev; //继承父类
u32 num_resources;
struct resource * resource; // 描述设备的资源---地址和中断
};


struct resource {
resource_size_t start; //起始位置
resource_size_t end; //结束位置
const char *name; //自定义
unsigned long flags;//区分是地址还是中断资源:IORESOURCE_IRQ, IORESOURCE_MEM
}


driver对象
struct platform_driver {
int (*probe)(struct platform_device *);//表示匹配成功之后被调用
int (*remove)(struct platform_device *);
struct device_driver driver;//继承父类
const struct platform_device_id *id_table;//用于匹配
};


pdrv中获取资源:
/**
* 参数1: pdev
* 参数2: 获取的是中断资源还是内存资源 
* 参数3: 同种资源中第几个
*/
struct resource * platform_get_resource(struct platform_device * dev,unsigned int type,unsigned int num)


在probe方法中:
1,申请主设备号  register_chrdev_region (与内核相关)
2,注册字符设备驱动 cdev_alloc  cdev_init  cdev_add (与内核相关)
3,利用udev/mdev机制创建设备文件(节点) class_create, device_create (与内核相关)
4,实现操作硬件方法  xxx_open,xxx_read,xxxx_write...(与硬件相关)
5,硬件初始化
最重要的:

获取到资源,利用资源进行硬件初始化

/* led_test.c */
#include 
#include 
#include 
#include 

int main(void)
{
	int fd;
	int on;
	fd = open("/dev/led0", O_RDWR);

	while (1) {
		on = 1;
		write(fd,&on, 4);
		sleep(1);
	
		on = 0;
		write(fd,&on, 4);
		sleep(1);
	}
	
	close(fd);

	return 0;
}

/* plat_led_dev.c */
#include 
#include 
#include 

#define GPC0CON 0xE0200060
#define GPC_SIZE 24

//用于演示,没有实际设备对应
#define GPA0CON 0xE0200000
#define GPA_SIZE 24

struct resource led_res[] = {

	/*实际所用到的*/
	[0] = {
		.start = GPC0CON,
		.end = GPC0CON + GPC_SIZE - 1,
		.flags = IORESOURCE_MEM,
	},

	/*假如有其他的资源,比如有中断*/
	[1] = {
		.start = 888,
		.end = 1212,
		.flags = IORESOURCE_IRQ,
	},
	
	[2] = {
		.start = GPA0CON,
		.end = GPA0CON + GPC_SIZE - 1,
		.flags = IORESOURCE_MEM,
	},
};

struct platform_device led_pdev = {
	.name = "s5pv210_led",
	.id = -1,
	.num_resources = ARRAY_SIZE(led_res),
	.resource = led_res,
};

static int __init plat_led_dev_init(void)
{
	/*注册一个平台设备*/ 	
	printk("------*_^%s--------\n",__FUNCTION__);

    return platform_device_register(&led_pdev);
}

static void __exit plat_led_dev_exit(void)
{
	/*注销平台设备*/
	platform_device_unregister(&led_pdev);
    printk("------*_^%s--------\n",__FUNCTION__);
}

module_init(plat_led_dev_init);
module_exit(plat_led_dev_exit);
		
MODULE_LICENSE("GPL");

/* plat_led_drv.c */
#include 
#include 
#include 
#include 
#include 

#include 
#include 

/*设计一个对象,表示一个全局的设备对象*/
struct samsung_led{
	int dev_major;
	struct class *cls;
	struct device *dev;
	struct resource *res;
	void *reg_addr; //虚拟地址
};

struct samsung_led * led_dev;

int led_pdrv_open(struct inode *inode, struct file *filp)
{
	printk("-------^_*  %s-----------\n", __FUNCTION__);
	return 0;
}

ssize_t led_pdrv_write(struct file *filp, const char __user *buf, size_t count, loff_t *fpos)
{
	int value;
	int ret;
	
	ret  = copy_from_user(&value, buf, count);
	if (ret > 0) {
		printk("copy_from_user error\n");
		return -EFAULT;
	}

	if (value) {
		//点灯
		__raw_writel(__raw_readl(led_dev->reg_addr + 4) | (0x3<<3), led_dev->reg_addr + 4);
		
	}else{
		__raw_writel(__raw_readl(led_dev->reg_addr + 4) & ~(0x3<<3), led_dev->reg_addr + 4);
	}

	return count;
}

int led_pdrv_close(struct inode *inode, struct file *filp)
{
	printk("-------^_*  %s-----------\n", __FUNCTION__);
	return 0;
}

struct file_operations led_fops = {
	.open = led_pdrv_open,
	.write = led_pdrv_write,
	.release = led_pdrv_close,
};

int led_pdrv_probe(struct platform_device *pdev)
{
	/*需要向应用空间提供接口
	1,申请设备号
	2,创建文件
	*/
	printk("-------^_*  %s-----------\n", __FUNCTION__);

	/*申请空间*/
	led_dev = kzalloc(sizeof(struct samsung_led), GFP_KERNEL); 

	/*动态申请设备*/
	led_dev->dev_major = register_chrdev(0, "led_drv", &led_fops);

	/*创建设备类*/
	led_dev->cls = class_create(THIS_MODULE, "led_cls");

	/*创建字符设备*/
	led_dev->dev = device_create(led_dev->cls,NULL, MKDEV(led_dev->dev_major, 0), NULL, "led%d", 0);
	led_dev->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

	//可以进行映射
	led_dev->reg_addr = ioremap(led_dev->res->start, resource_size(led_dev->res));

	//获取中断
	int irqno = platform_get_irq(pdev, 0);
	printk("irqno  = %d\n", irqno );

	// 配置gpio为输出
	unsigned int temp = __raw_readl(led_dev->reg_addr);
	temp &= ~(0xff<<12);
	temp |= (0x11<<12);
	__raw_writel(temp,led_dev->reg_addr);

	return 0;
}

int led_pdrv_remove(struct platform_device *pdev)
{
	iounmap(led_dev->reg_addr);
	device_destroy(led_dev->cls,MKDEV(led_dev->dev_major, 0));
	class_destroy(led_dev->cls);
	unregister_chrdev(led_dev->dev_major,"led_drv");
	kfree(led_dev);
	
	return 0;
}

/*用于匹配*/		
const struct platform_device_id led_id_table[] = {
	{"s3c2410_led", 1111},
	{"s3c6410_led", 2222},
	{"s5pv210_led", 3333},
};

struct platform_driver led_drv = {
	.probe = led_pdrv_probe,
	.remove = led_pdrv_remove,
	.driver = {
		.name = "s5pv210_led"	// 随便写,用于匹配,/sys/bus/platform/drivers/samsung_led_drv
	},
	.id_table = led_id_table,//优先匹配列表中的名字,如果没有列表,就匹配父类中name

};

static int __init plat_led_drv_init(void)
{
	/*注册一个平台驱动*/ 	
	printk("------*_^%s--------\n",__FUNCTION__);

    return platform_driver_register(&led_drv);
}

static void __exit plat_led_drv_exit(void)
{
	/*注销平台驱动*/
	platform_driver_unregister(&led_drv);

	printk("------*_^%s--------\n",__FUNCTION__);
}

module_init(plat_led_drv_init);
module_exit(plat_led_drv_exit);
		
MODULE_LICENSE("GPL");

# Makefile
ROOTFS_DIR = /opt/filesystem
MODULE_NAME = plat_led_dev
MODULE_NAME2 = plat_led_drv

APP_NAME = led_test
CROSS_COMPILE = arm-cortex_a8-linux-gnueabi-
CC = $(CROSS_COMPILE)gcc

ifeq ($(KERNELRELEASE), )
KERNEL_DIR = /home/linux-3.0.8
CUR_DIR = $(shell pwd)
all :	
	make -C $(KERNEL_DIR) M=$(CUR_DIR) modules
	$(CC) $(APP_NAME).c -o $(APP_NAME)
clean :	
	make -C $(KERNEL_DIR) M=$(CUR_DIR) clean
	rm -rf $(APP_NAME)
	
install:	
	cp -raf *.ko  $(APP_NAME) $(ROOTFS_DIR)/drv_module
else

obj-m = $(MODULE_NAME).o
obj-m += $(MODULE_NAME2).o

endif


你可能感兴趣的:(Linux高级驱动)