驱动层 主要修改的新增3个文件夹 修改1处地方
Krenel:驱动层文件夹
Krenel/arch/arm64/boot/dts/rockchip/xxxxxx.DTSI :设备树文件夹 这里选中的是 rk3399-android.dtsi
dtsi 类似json 这种文本 是解析给 驱动层看的 可以写 也可以不写 写的话 以后维护舒服 不写也能继续下去
DTSi文件:找个你看的顺眼的文件夹内添加
PWm_demo:PWm_demo{
status = "okay";
compatible = "Pwm_demo_data";
pwm_id = <1>;
Min_preiod = <0>; //最小 周期
Max_preiod = <10000>;//最大周期
duty_Ns = <5000>;//激活时常
};
kerenel下 新建一个文件夹Pai_driver 内 然后新建三个文件
Makefile Pwm_driver.c Kconfig
Makefile:
KERNELDIR := /home/share/samba/RK3399-Android8.1/kernel/
PWD := $(shell pwd)
all:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean
obj-m := Pai_pwm_driver.o
这段代码劝你手打 复制容易出错
Kconfig
config HELLO
tristate "Hello Android Driver"
default n
help
This is the hello android driver.
Pwm_dirver.c
#include "../2/config.h"
#include <linux/pwm.h>
#define DEV_NAME "Pwm_demo"
#define DEV_COUNT 1
/*设备结构体*/
struct embededplatform_dev1{
dev_t devid; /* 设备号 */
struct embededplatform_dev dev;
struct pwm_device *pwm_device;
int dev_stats; /* 设备状态,0 ,设备未使用;>0, 设备已经被使用 */
int Pwm_id;
unsigned int Max_Duty;
unsigned int Min_Duty;
};
struct Pai_pwm_driver
{
int Pwm_id;
unsigned int Max;
unsigned int Duty;
};
//设备结构体实例
struct embededplatform_dev1 embededplatform_dev_er;
static int embeded_platform_open (struct inode *node, struct file *filp){
printk("embeded_platform_open\n");
return 0;
}
static ssize_t embeded_platform_write (struct file *filp, const char __user *buf, size_t count, loff_t *off)
{
/* unsigned int Key = 0; */
struct Pai_pwm_driver Key;
if (copy_to_user(&Key,buf,sizeof(struct Pai_pwm_driver)))
{
switch (Key.Duty)
{
case 0:
pwm_disable(embededplatform_dev_er.pwm_device);
break;
default:
pwm_config(embededplatform_dev_er.pwm_device,Key.Duty,Key.Max);
pwm_enable(embededplatform_dev_er.pwm_device);
break;
}
}
return 0;
}
ssize_t embeded_platform_read(struct file *filp, char __user *ubuf, size_t count, loff_t *ppos)
{
return 0;
}
static int embeded_platform_release (struct inode *node, struct file *filp){
printk("embeded_platform_release \n");
return 0;
}
static struct file_operations embeded_file_ops = {
.owner = THIS_MODULE,
.open = embeded_platform_open,
.write = embeded_platform_write,
.read = embeded_platform_read,
.release = embeded_platform_release,
};
static int Init_Class(void)
{
int ret = 0;
/* 申请设备号 */
ret = alloc_chrdev_region(&embededplatform_dev_er.devid, 0, DEV_COUNT, DEV_NAME);
if (ret < 0) {
printk("embededplatform_dev_er chrdev_region err!\r\n");
goto fail_devid;
}
/* 注册字符设备 */
cdev_init(&embededplatform_dev_er.dev.cdev, &embeded_file_ops);
ret = cdev_add(&embededplatform_dev_er.dev.cdev, embededplatform_dev_er.devid, DEV_COUNT);
if (ret < 0) {
goto fail_cdev;
}
/* 自动创建设备节点 */
embededplatform_dev_er.dev.class = class_create(embeded_file_ops.owner, DEV_NAME);
if (IS_ERR(embededplatform_dev_er.dev.class)) {
ret = PTR_ERR(embededplatform_dev_er.dev.class);
goto fail_class;
}
embededplatform_dev_er.dev.device = device_create(embededplatform_dev_er.dev.class, NULL,
embededplatform_dev_er.devid, NULL, DEV_NAME);
if (IS_ERR(embededplatform_dev_er.dev.device)) {
ret = PTR_ERR(embededplatform_dev_er.dev.device);
goto fail_device;
}
return 1;
fail_device:
class_destroy(embededplatform_dev_er.dev.class);
fail_class:
cdev_del(&embededplatform_dev_er.dev.cdev);
fail_cdev:
unregister_chrdev_region(embededplatform_dev_er.devid, DEV_COUNT);
fail_devid:
return ret;
}
static int Init_Pwm(struct device_node *led_node)
{
int ret = 0;
//查找 pwm_id 子字节的u32参数 如果没写dtsi 这一大段可以不写
ret = of_property_read_u32(led_node, "pwm_id", &embededplatform_dev_er.Pwm_id);
if (ret < 0)
{
printk("---pwm_id ERR %d!\n",embededplatform_dev_er.Pwm_id);
goto fail_GPIO;
}
ret = of_property_read_u32(led_node, "Min_preiod", &embededplatform_dev_er.Min_Duty);
if (ret < 0)
{
printk("---pwm_id ERR %d!\n",embededplatform_dev_er.Min_Duty);
goto fail_GPIO;
}
ret = of_property_read_u32(led_node, "Max_preiod", &embededplatform_dev_er.Max_Duty);
if (ret < 0)
{
printk("---pwm_id ERR %d!\n",embededplatform_dev_er.Max_Duty);
goto fail_GPIO;
}
printk("---Max_preiod %d!\n",embededplatform_dev_er.Max_Duty);
printk("---Min_preiod %d!\n",embededplatform_dev_er.Min_Duty);
printk(" ---pwm_id : %d !\n", embededplatform_dev_er.Pwm_id);
/* 申请 pwm使用 如果没有写dtsi 下面就需要自己写入实数了*/
embededplatform_dev_er.pwm_device = pwm_request(embededplatform_dev_er.Pwm_id,"Pwm_demo");
if(IS_ERR(embededplatform_dev_er.pwm_device)){
printk("pwm_request err %ld\n",PTR_ERR(embededplatform_dev_er.pwm_device));
goto fail_GPIO;
}
/* 配置pwm */
ret = pwm_config(embededplatform_dev_er.pwm_device,embededplatform_dev_er.Min_Duty,embededplatform_dev_er.Max_Duty);
if (ret < 0)
{
printk("pwm_config err %ld\n",PTR_ERR(embededplatform_dev_er.pwm_device));
goto Del_Pwm;
}
/* 停止使能pwm */
pwm_disable(embededplatform_dev_er.pwm_device);
return 1;
Del_Pwm:
pwm_free(embededplatform_dev_er.pwm_device);
fail_GPIO:
class_destroy(embededplatform_dev_er.dev.class);
cdev_del(&embededplatform_dev_er.dev.cdev);
unregister_chrdev_region(embededplatform_dev_er.devid, DEV_COUNT);
return ret;
}
static int embeded_platform_probe(struct platform_device *pdev)
{
int ret = 0;
struct device_node *led_node = pdev->dev.of_node;
printk("Init ALL Config\n");
if (Init_Class() < 0)goto fail_Class; //创建字符串设备
if (Init_Pwm(led_node) < 0)goto fail_Class; // 初始化pwm io口设置
printk("--------------ALL Ok----------\n");
return 0;
fail_Class:
return ret;
}
static int embeded_platform_remove(struct platform_device *pdev)
{
printk("embeded_platform_exit\r\n");
/* 删除字符设备 */
cdev_del(&embededplatform_dev_er.dev.cdev);
/* 释放字符设号 */
unregister_chrdev_region(embededplatform_dev_er.devid, DEV_COUNT);
/* 摧毁设备 */
device_destroy(embededplatform_dev_er.dev.class, embededplatform_dev_er.devid);
/* 摧毁类 */
class_destroy(embededplatform_dev_er.dev.class);
/* 销毁 pwm */
pwm_free(embededplatform_dev_er.pwm_device);
return 0;
}
static struct of_device_id embeded_match_table[] = {
{ .compatible = "Pwm_demo_data"},
{},
};
static struct platform_driver embeded_platform_driver = {
.driver = {
.name = DEV_NAME,
.owner = THIS_MODULE,
.of_match_table = embeded_match_table,
},
.remove = embeded_platform_remove,
.probe = embeded_platform_probe,
};
static int embeded_platformdriver_init(void)
{
return platform_driver_register(&embeded_platform_driver);
}
static void embeded_platformdriver_exit(void)
{
platform_driver_unregister(&embeded_platform_driver);
}
module_init(embeded_platformdriver_init);
module_exit(embeded_platformdriver_exit);
MODULE_AUTHOR("embeded");
MODULE_DESCRIPTION("embeded platform driver");
MODULE_LICENSE("GPL");