具体的寄存器配法,就去看一下手册吧 ,这种写寄存器的方式参考了一下本省自带的红外驱动,不过pwm的理论知识,以及为什么要这样配置这些寄存器,可以看一看ARM的教材,以前学习的时候写过代码,现在也是忘得很多了,想仔细了解的可以去找一下ARM相关的书。
#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>
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#define GPIO_LOW 0
#define GPIO_HIGH 1
#define PWM_REG_CNTR 0x00 /* Counter Register /
#define PWM_REG_HPR 0x04 / Period Register /
#define PWM_REG_LPR 0x08 / Duty Cycle Register /
#define PWM_REG_CTRL 0x0c / Control Register */
/REG_CTRL bits definitions/
#define PWM_ENABLE (1 << 0)
#define PWM_DISABLE (0 << 0)
/operation mode/
#define PWM_MODE_ONESHOT (0x00 << 1)
#define PWM_MODE_CONTINUMOUS (0x01 << 1)
#define PWM_MODE_CAPTURE (0x02 << 1)
int major;
int gpio;
static struct class *cls;
static struct clk *pwm_clk;
void __iomem *base;
static int pwm_open(struct inode *inode, struct file *file)
{
printk(KERN_EMERG "%s-%d: enter\n",FUNCTION,LINE);
return 0;
}
static ssize_t pwm_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
int val,ret;
ret = copy_from_user(&val, buf, count);
printk(KERN_INFO "val:%d\n",val);
if(val>100){
printk(KERN_INFO "error\n");
return -1;
}
val = 100000 - (val * 1000);
writel_relaxed(val,base + PWM_REG_LPR);
return 0;
}
static struct file_operations pwm_fops = {
.owner = THIS_MODULE,
.open = pwm_open,
.write = pwm_write,
};
static int pwm_probe(struct platform_device *pdev)
{
struct resource *r;
// struct device_node *node = pdev->dev.of_node;
int ret;
int val;
int pwm_freq_nstime;
// int pwm_id;
int pwm_freq;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) {
dev_err(&pdev->dev, "no memory resources defined\n");
return -ENODEV;
}
base = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(base))
return PTR_ERR(base);
pwm_clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(pwm_clk)) {
ret = PTR_ERR(pwm_clk);
if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev, "Can't get bus clk: %d\n", ret);
return ret;
}
ret = clk_prepare_enable(pwm_clk);
if (ret) {
dev_err(&pdev->dev, "Can't enable bus clk: %d\n", ret);
return ret;
}
// of_property_read_u32(node, "pwm_id", &pwm_id);
val = readl_relaxed(base + PWM_REG_CTRL);
val = (val & 0xFFFFFFFE) | PWM_DISABLE;
writel_relaxed(val, base + PWM_REG_CTRL);
val = readl_relaxed(base + PWM_REG_CTRL);
val = (val & 0xFFFFFFF9) | PWM_MODE_CONTINUMOUS;
writel_relaxed(val, base + PWM_REG_CTRL);
val = readl_relaxed(base + PWM_REG_CTRL);
val = (val & 0xFF008DFF) | 0x0006000;
writel_relaxed(val, base + PWM_REG_CTRL);
val = readl_relaxed(base + PWM_REG_CTRL);
val = (val & 0xFFFFFFFE) | PWM_ENABLE;
writel_relaxed(val, base + PWM_REG_CTRL);
pwm_freq = clk_get_rate(pwm_clk) / 64;
printk(KERN_INFO "pwm_freq %d\n",pwm_freq);
pwm_freq_nstime = 1000000000 / pwm_freq;
printk(KERN_INFO "pwm_freq_nstime %d\n",pwm_freq_nstime);
writel_relaxed(100000,base + PWM_REG_HPR);
writel_relaxed(80000,base + PWM_REG_LPR);
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");
printk(KERN_INFO "pwm sucess\n");
return 0;
}
static struct of_device_id pwm_of_match[] = {
{ .compatible = "pwm_1"},
{}
};
static int pwm_remove(struct platform_device *pdev)
{
int val;
device_destroy(cls, MKDEV(major, 0));
class_destroy(cls);
unregister_chrdev(major, "pwm_test");
writel_relaxed(100000,base + PWM_REG_LPR);//Duty
val = readl_relaxed(base + PWM_REG_CTRL);
val = (val & 0xFFFFFFFE) | PWM_DISABLE;
writel_relaxed(val, base + PWM_REG_CTRL);
val = readl_relaxed(base + PWM_REG_CTRL);
val = (val & 0xFFFFFFF9) | PWM_MODE_CAPTURE;
writel_relaxed(val, base + PWM_REG_CTRL);
val = readl_relaxed(base + PWM_REG_CTRL);
val = (val & 0xFF008DFF) | 0x0006000;
writel_relaxed(val, base + PWM_REG_CTRL);
val = readl_relaxed(base + PWM_REG_CTRL);
val = (val & 0xFFFFFFFE);
writel_relaxed(val, base + PWM_REG_CTRL);
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,
};
module_platform_driver(pwm_driver);
MODULE_LICENSE("GPL");
关于这个的dts配置:
&pwm1 {
status = "okay";
compatible = "pwm_1";
};
原作者:mfence