rk3399下pwm驱动

现在记录一下rk3399下pwm的驱动编写,下面是内核pwm的API,从开源论坛复制(瑞芯微的开源论坛里面的Wiki教程)

(1)、在要使用 PWM 控制的设备驱动文件中包含以下头文件:

#include <linux/pwm.h>
该头文件主要包含 PWM 的函数接口。

(2)、申请 PWM使用

struct pwm_device *pwm_request(int pwm_id, const char *label);
函数申请 PWM。 例如:

struct pwm_device * pwm1 = NULL;pwm0 = pwm_request(1, “firefly-pwm”);
(3)、配置 PWM使用

int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns);
配置 PWM 的占空比, 例如:

pwm_config(pwm0, 500000, 1000000);
(4)、使能PWM 函数

int pwm_enable(struct pwm_device *pwm);
用于使能 PWM,例如:

pwm_enable(pwm0);
(5)控制 PWM 输出主要使用以下接口函数:

struct pwm_device *pwm_request(int pwm_id, const char *label);
功能:用于申请 pwm
void pwm_free(struct pwm_device *pwm);
功能:用于释放所申请的 pwm
int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns);
功能:用于配置 pwm 的占空比
int pwm_enable(struct pwm_device *pwm);
功能:使能 pwm
void pwm_disable(struct pwm_device *pwm);
功能:禁止 pwm

编写该驱动程序的几个流程:

1.在设备树下添加相应内容,内容如下:

pwm_demo{
                status = "okay";
                compatible = "pwm_test";
                buzzer-gpio = <&gpio4 18 GPIO_ACTIVE_LOW>;
        };

经测试,gpio一项完全可以不要,compatible为匹配条件,另外在/kernel/arch/arm64/boot/dts/rockchip目录下使用grep "pwm" * -nR命令,搜索结果如下:(关键的内容)

Binary file g3399-development-board.dtb matches
g3399-development-board.dts:234:&pwm3 {
g3399-development-board.dts:237:	compatible = "rockchip,remotectl-pwm";
g3399-development-board.dts:238:	remote_pwm_id = <3>;
rk3399.dtsi:1234:	pwm0: pwm@ff420000 {
rk3399.dtsi:1235:		compatible = "rockchip,rk3399-pwm", "rockchip,rk3288-pwm";
rk3399.dtsi:1237:		#pwm-cells = <3>;
rk3399.dtsi:1239:		pinctrl-0 = <&pwm0_pin>;
rk3399.dtsi:1241:		clock-names = "pwm";
rk3399.dtsi:1245:	pwm1: pwm@ff420010 {
rk3399.dtsi:1246:		compatible = "rockchip,rk3399-pwm", "rockchip,rk3288-pwm";
rk3399.dtsi:1248:		#pwm-cells = <3>;
rk3399.dtsi:1250:		pinctrl-0 = <&pwm1_pin>;
rk3399.dtsi:1252:		clock-names = "pwm";
rk3399.dtsi:1256:	pwm2: pwm@ff420020 {
rk3399.dtsi:1257:		compatible = "rockchip,rk3399-pwm", "rockchip,rk3288-pwm";
rk3399.dtsi:1259:		#pwm-cells = <3>;
rk3399.dtsi:1261:		pinctrl-0 = <&pwm2_pin>;
rk3399.dtsi:1263:		clock-names = "pwm";
rk3399.dtsi:1267:	pwm3: pwm@ff420030 {
rk3399.dtsi:1268:		compatible = "rockchip,rk3399-pwm", "rockchip,rk3288-pwm";
rk3399.dtsi:1270:		#pwm-cells = <3>;
rk3399.dtsi:1272:		pinctrl-0 = <&pwm3a_pin>;
rk3399.dtsi:1274:		clock-names = "pwm";
rk3399.dtsi:1790:	vop1_pwm: voppwm@ff8f01a0 {
rk3399.dtsi:1791:		compatible = "rockchip,vop-pwm";
rk3399.dtsi:1793:		#pwm-cells = <3>;
rk3399.dtsi:1795:		pinctrl-0 = <&vop1_pwm_pin>;
rk3399.dtsi:1797:		clock-names = "pwm";
rk3399.dtsi:1859:	vop0_pwm: voppwm@ff9001a0 {
rk3399.dtsi:1860:		compatible = "rockchip,vop-pwm";
rk3399.dtsi:1862:		#pwm-cells = <3>;
rk3399.dtsi:1864:		pinctrl-0 = <&vop0_pwm_pin>;
rk3399.dtsi:1866:		clock-names = "pwm";
rk3399.dtsi:2673:		pwm0 {
rk3399.dtsi:2674:			pwm0_pin: pwm0-pin {
rk3399.dtsi:2679:			vop0_pwm_pin: vop0-pwm-pin {
rk3399.dtsi:2685:		pwm1 {
rk3399.dtsi:2686:			pwm1_pin: pwm1-pin {
rk3399.dtsi:2691:			vop1_pwm_pin: vop1-pwm-pin {
rk3399.dtsi:2697:		pwm2 {
rk3399.dtsi:2698:			pwm2_pin: pwm2-pin {
rk3399.dtsi:2704:		pwm3a {
rk3399.dtsi:2705:			pwm3a_pin: pwm3a-pin {
rk3399.dtsi:2711:		pwm3b {
rk3399.dtsi:2712:			pwm3b_pin: pwm3b-pin {

然后打开rk3399.dtsi,内容如下:(sudo vim rk3399.dtsi)然后搜索,在终端输入 :/pwm

pwm0: pwm@ff420000 {
                compatible = "rockchip,rk3399-pwm", "rockchip,rk3288-pwm";
                reg = <0x0 0xff420000 0x0 0x10>;
                #pwm-cells = <3>;
                pinctrl-names = "default";
                pinctrl-0 = <&pwm0_pin>;
                clocks = <&pmucru PCLK_RKPWM_PMU>;
                clock-names = "pwm";
                status = "disabled";
        };

        pwm1: pwm@ff420010 {
                compatible = "rockchip,rk3399-pwm", "rockchip,rk3288-pwm";
                reg = <0x0 0xff420010 0x0 0x10>;
                #pwm-cells = <3>;
                pinctrl-names = "default";
                pinctrl-0 = <&pwm1_pin>;
                clocks = <&pmucru PCLK_RKPWM_PMU>;
                clock-names = "pwm";
                status = "disabled";
        };
.......................
此处省略n行代码

可以看到:status = "disabled";

这里我使用的pwm1 所以pwm1下面的status = "disabled";改为status = "okay";

现在是添加自己的内容了,我在该目录下的g3399-baseboard.dtsi文件中添加如下内容:

pwm_demo{
                status = "okay";
                compatible = "pwm_test";
                buzzer-gpio = <&gpio4 18 GPIO_ACTIVE_LOW>;
        };

现在第一步就结束了

2.编写设备驱动及Makefile:

#include<linux/pwm.h>
#include <linux/moduleparam.h>
#include <linux/stat.h>

#include <linux/kernel.h>
#include <linux/gpio.h>

#include <linux/init.h>
#include <linux/module.h> 
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_platform.h>


#include <linux/version.h>

#include <linux/init.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#define GPIO_LOW 0
#define GPIO_HIGH 1
struct pwm_device *pwm = NULL;
int major;
int gpio;
static struct class *cls;
static ulong arg1;
static int arg2=0;
module_param(arg1,ulong,S_IRUSR);
module_param(arg2,int,S_IRUSR);
static int pwm_open(struct inode *inode, struct file *file)
{
	printk(KERN_EMERG "%s-%d: enter\n",__FUNCTION__,__LINE__);
	
	return 0;	
}
static struct file_operations pwm_fops = {
    .owner  =   THIS_MODULE,   
    .open   =   pwm_open,        
};
static int pwm_probe(struct platform_device *pdev)
{
	int ret;
	enum of_gpio_flags flag;
	struct device_node *led_node = pdev->dev.of_node;
	
	major = register_chrdev(0, "pwm_test", &pwm_fops);
	cls = class_create(THIS_MODULE, "pwm_test");
	device_create(cls, NULL, MKDEV(major, 0), NULL, "pwm_buzzer"); 
	
	gpio = of_get_named_gpio_flags(led_node,"buzzer-gpio", 0,&flag);
	if (!gpio_is_valid(gpio)){
		printk(KERN_INFO "hello: invalid gpio : %d\n",gpio);
		return -1;
	} 
    ret = gpio_request(gpio, "buzzer");
	if (ret) {
		gpio_free(gpio);
		return -EIO;
	}

	gpio_direction_output(gpio, GPIO_HIGH);
	
	gpio_set_value(gpio,arg2);
	pwm = pwm_request(1,"pwm");
	if(IS_ERR(pwm)){
		dev_err(&pdev->dev,"unable to request pwm\n");
		printk("pwm err %ld\n",PTR_ERR(pwm));
	}
	pwm_config(pwm,arg1,100000);
	pwm_enable(pwm);
	printk(KERN_INFO "pwm sucess\n");
	return 0;
}

static struct of_device_id pwm_of_match[] = {
        { .compatible = "pwm_test"},
        {}
};
static int pwm_remove(struct platform_device *pdev)
{
	gpio_free(gpio);
	device_destroy(cls, MKDEV(major, 0));
	class_destroy(cls);
	unregister_chrdev(major, "pwm_test");
	pwm_free(pwm);
	return 0;
}
static struct platform_driver pwm_driver={
        .driver = {
                .name           ="pwm",
                .owner          =THIS_MODULE,
                .of_match_table = pwm_of_match,
        },
        .probe  = pwm_probe,
        .remove = pwm_remove,
};
static int __init pwm_init(void)
{
    printk(KERN_INFO "Enter %s\n", __FUNCTION__);
    return platform_driver_register(&pwm_driver);
    return 0;
}
static void __exit pwm_exit(void)
{
	platform_driver_unregister(&pwm_driver);
    printk(KERN_INFO "Exit pwm_driver\n");
}
module_init(pwm_init);
module_exit(pwm_exit);
MODULE_LICENSE("GPL");
#!/bin/bash

obj-m += pwm.o

KDIR := /rk3399/source/g3399-v7-1-2-20180529/kernel


PWD ?= $(shell pwd)
all:
        make -C $(KDIR) M=$(PWD) modules

clean:
        rm -rf *.o *.ko

到此,结束。

使用ls /dev 命令可以看到自己生成的设备结点,另附上本驱动加载命令: insmod pwm.ko arg1=80000 arg2=0

猜你喜欢

转载自blog.csdn.net/qq_33166886/article/details/83820839