平台总线:用于平台升级的
三星:
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,硬件初始化
最重要的:
三星:
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 <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
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 <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#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 <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <asm/io.h>
/*设计一个对象,表示一个全局的设备对象*/
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