平台总线第一天③

app代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>

int main(void)
{
	int fd;
	int on;

	fd = open("/dev/led_plat",O_RDWR);
	if(fd < 0)
	{
		perror("open");
		exit(1);
	}
		on = 1;
		write(fd, &on,sizeof(on));
		sleep(1);
		on = 0;
		write(fd, &on,sizeof(on));
		sleep(1);

	close(fd);
	return 0;
}

驱动层代码:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <asm/uaccess.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/fs.h>
#include "led_info.h"

struct s5pv210_led_dev{
	int major;
	struct class * clz;
	struct device * dev;
    void * reg_base;
	struct led_platdata *pdata;
};

unsigned int reg_val;

struct s5pv210_led_dev * led_dev;

int led_pdrv_open(struct inode *node, struct file *filp)
{
	int conf_reg_clear;
	int conf_reg_data;
	int shift;
	printk("--------------%s---------------\n",__FUNCTION__);
	conf_reg_clear = led_dev->pdata->conf_reg_clear;
	conf_reg_data = led_dev->pdata->conf_reg_data;
	shift = led_dev->pdata->shift;
		
	reg_val = __raw_readl(led_dev->reg_base);
	reg_val &= ~(conf_reg_clear << shift *4);
	reg_val |= conf_reg_data << shift *4;
	__raw_writel(reg_val,led_dev->reg_base);
	return 0;
}

ssize_t led_pdrv_write(struct file *filp, const char __user *buff, size_t count, loff_t * offset)
{
	int ret, value;
	ret = copy_from_user(&value,buff,count);
	if(ret > 0)
	{
		printk("copy_from_user error!\n");
		return -EFAULT;
	}
	if(value)
	{
		reg_val = readl(led_dev->reg_base + 4);
		reg_val |= 0x3 << 3;
		writel(reg_val, led_dev->reg_base + 4);
	}
	else
	{
		reg_val = readl(led_dev->reg_base + 4);
		reg_val &= ~(0x3 << 3);
		writel(reg_val, led_dev->reg_base + 4);
	}
	return 0;
}

int led_pdrv_release(struct inode *node, struct file *filp)
{
    writel(readl(led_dev->reg_base + 4) & ~(0x3 <<3),led_dev->reg_base + 4);
	return 0;
}


const struct file_operations fops = {
	.open = led_pdrv_open,
	.write = led_pdrv_write,
	.release = led_pdrv_release,
};

int led_pdrv_probe(struct platform_device *pdev)
{
	struct resource * addr_res1, *addr_res2;
	struct resource * irq_res;
	int irqno,ret;
 	printk("---------------%s------------------\n",__FUNCTION__);
    //1.实例化全局对象
	led_dev = kzalloc(sizeof(struct s5pv210_led_dev),GFP_KERNEL);
	if(IS_ERR(led_dev))
	{
		printk("kzalloc error!\n");
		return -ENOMEM;
	}
    //2.申请设备号
    led_dev->major = register_chrdev(0,"led_pdrv",&fops);
	if(led_dev->major < 0)
	{
		printk("register_chrdev error!\n");
		ret = led_dev->major;
		goto err_kfree;
	}
	//3.创建类
	led_dev->clz = class_create(THIS_MODULE,"led_class");
	if(IS_ERR(led_dev->clz))
	{
		printk("class_create error!\n");
		ret = PTR_ERR(led_dev->clz);
		goto err_unregister;
	}
	//4.创建设备节点
	led_dev->dev = device_create(led_dev->clz,NULL,MKDEV(led_dev->major,0),NULL,"led_plat");
	if(IS_ERR(led_dev->dev))
	{
		printk("device_create error!\n");
		ret = PTR_ERR(led_dev->dev);
		goto err_class;
	}
    //参数1:pdev对象
    //参数2:资源的类型
    //参数3:资源的编号,同一种类型,从0开始编号
	addr_res1 = platform_get_resource(pdev,IORESOURCE_MEM,0);
	printk("addr_res1: start = 0x%x\n",addr_res1->start);

	addr_res2 = platform_get_resource(pdev,IORESOURCE_MEM,1);
	printk("addr_res2: start = 0x%x\n",addr_res2->start);

    //方法一
	irq_res = platform_get_resource(pdev,IORESOURCE_IRQ,0);
	printk("irq_res: start = %d\n",irq_res->start);
	printk("irq_res: end = %d\n",irq_res->end);
	//方法二
	irqno = platform_get_irq(pdev,0);
	printk("irqno = %d\n",irqno);

	led_dev->pdata = pdev->dev.platform_data;       //设备层数据传递到驱动层

	//5.硬件初始化
	led_dev->reg_base = ioremap(addr_res1->start,resource_size(addr_res1));

    /*
        计算地址大小
        static inline resource_size_t resource_size(const struct resource *res)
        {
        	return res->end - res->start + 1;
        }
    */
	if(IS_ERR(led_dev->reg_base))
	{
		printk("ioremap error!\n");
        ret = PTR_ERR(led_dev->reg_base);
		goto err_device;
	}
	return 0;
	err_device:
		device_destroy(led_dev->clz,MKDEV(led_dev->major,0));
	err_class:
		class_destroy(led_dev->clz);
	err_unregister:
		unregister_chrdev(led_dev->major,"led_pdrv");
	err_kfree:
		kfree(led_dev);
	return ret;
}

int led_pdrv_remove(struct platform_device *pdev)
{
	printk("---------------%s------------------\n",__FUNCTION__);
	iounmap(led_dev->reg_base);
	device_destroy(led_dev->clz,MKDEV(led_dev->major,0));
	class_destroy(led_dev->clz);
	unregister_chrdev(led_dev->major,"led_pdrv");
	kfree(led_dev);
	return 0;
}

const struct platform_device_id led_id_table[] = {
	{"s5pv210_led", 0x1122},
	{"s3c2410_led", 0x1234},
	{"s3c6410_led", 0x2233},
};

struct platform_driver led_pdrv = {
 	.probe = led_pdrv_probe,
	.remove = led_pdrv_remove,
	.driver = {
		.name = "samsung led_drv",//自定义,但是一定要有,没有id_table则用这个名字和pdev匹配,--- ls /sys/bus/platform/drivers/下创建同名目录
	},
	.id_table = led_id_table,
};


static int __init led_pdrv_init(void)
{
	printk("--------------%s--------------\n",__FUNCTION__);
	return platform_driver_register(&led_pdrv);
}

static void __exit led_pdrv_exit(void)
{
	printk("--------------%s--------------\n",__FUNCTION__);
	platform_driver_unregister(&led_pdrv);

}
module_init(led_pdrv_init);
module_exit(led_pdrv_exit);
MODULE_LICENSE("GPL");

设备层代码:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include "led_info.h"

#define LED_GPC0_CONF 0xe0200060
#define LED_GPC0_SIZE 8

//定义一个平台自定义数据
struct led_platdata led_pdata = {
	.name = "gpc0_3/4",
	.shift = 3,
	.conf_reg_clear = 0xff,
	.conf_reg_data = 0x11,
	.data_reg = 0x3,
};
struct resource led_resource[] = {
	[0] = {
		.start = LED_GPC0_CONF,
		.end = LED_GPC0_CONF + LED_GPC0_SIZE - 1,
		.flags = IORESOURCE_MEM,
	},
	
	//以下是演示代码
	[1] = {
		.start = 0x1122,
		.end = 0x1122,
		.flags = IORESOURCE_IRQ,
	},
	[2] = {
		.start = 0xe0200160,
		.end = 0xe0200160 + 8 - 1, //end地址的计算
		.flags = IORESOURCE_MEM,
	},
};

//可以不用实现5,但是一定要有,因为卸载的时候会调用
void led_pdev_release(struct device *dev)
{
	printk("--------------%s--------------\n",__FUNCTION__);
}


struct platform_device led_pdev = {
	.name = "s5pv210_led",
	.id = -1,
	.dev = {
		.release = led_pdev_release,
		.platform_data = &led_pdata, //platform_data为void*类型的变量(这样就可以将数据在匹配成功时传递给驱动层probe方法使用)
	},
	.num_resources = ARRAY_SIZE(led_resource),
	.resource = led_resource,

};
static int __init led_pdev_init(void)
{
	printk("--------------%s--------------\n",__FUNCTION__);
	return platform_device_register(&led_pdev);
}

static void __exit led_pdev_exit(void)
{
	printk("--------------%s--------------\n",__FUNCTION__);
	platform_device_unregister(&led_pdev);

}
module_init(led_pdev_init);
module_exit(led_pdev_exit);
MODULE_LICENSE("GPL");

数据结构fifo.h:

#ifndef __LED_INFO_H__
#define __LED_INFO_H__

//设计一个平台自定义数据类型
struct led_platdata{
  char * name;
  int shift;//移位数,3
  int conf_reg_clear;//配置寄存器的清空
  int conf_reg_data; //配置寄存器的值
  int data_reg;//数据寄存器的值

};
#endif
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值