linux设备树之pwm
程序员文章站
2024-01-23 15:07:28
...
驱动层
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/platform_device.h>
#include <asm/io.h>
#include <linux/fs.h>
#include <linux/of.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
/*
mybeep{
compatible = "beep";
pinctrl-0 = <&pwm0_out>;
pinctrl-names = "default";
reg = <0x139D0000 0x14>;
};
*/
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("a simple driver example!");
#define ON _IOW('P', 0, int)
#define OFF _IOW('P', 1, int)
#define XXX _IOW('P', 2, int)
typedef struct {
unsigned int TCFG0;
unsigned int TCFG1;
unsigned int TCON;
unsigned int TCNTB0;
unsigned int TCMPB0;
unsigned int TCNTO0;
unsigned int TCNTB1;
unsigned int TCMPB1;
unsigned int TCNTO1;
unsigned int TCNTB2;
unsigned int TCMPB2;
unsigned int TCNTO2;
unsigned int TCNTB3;
unsigned int TCMPB3;
unsigned int TCNTO3;
unsigned int TCNTB4;
unsigned int TCNTO4;
unsigned int TINT_CSTAT;
}pwm_t;
struct beep{
dev_t num;
int *gpioaddr;
pwm_t *pwmaddr;
struct cdev cdev_beep;
struct class *class;
struct device *device;
}xbeep;
static int beep_open(struct inode *inodep, struct file *filep)
{
printk("pwm open call \n");
return 0;
}
typedef struct{
int base;
int cont;
}ARG;
static long beep_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
{
int a, b;
ARG *p;
switch(cmd)
{
case ON:
iowrite32((ioread32(&xbeep.pwmaddr->TCON) | 1) , &xbeep.pwmaddr->TCON);
break;
case OFF:
iowrite32((ioread32(&xbeep.pwmaddr->TCON) & ~1) , &xbeep.pwmaddr->TCON);
break;
case XXX:
p = (ARG*)arg;
get_user(a, &p->base);
get_user(b, &p->cont);
iowrite32(a , &xbeep.pwmaddr->TCNTB0);
iowrite32(b , &xbeep.pwmaddr->TCMPB0);
printk("config ok\n");
break;
}
return 0;
}
static int beep_release(struct inode *inodep, struct file *filep)
{
printk("beep closed\n");
//iounmap(xbeep.gpioaddr);
iounmap(xbeep.pwmaddr);
iowrite32((ioread32(&xbeep.pwmaddr->TCON) & ~1) , &xbeep.pwmaddr->TCON);
return 0;
}
struct file_operations beep_ops = {
.owner = THIS_MODULE,
.open = beep_open,
.unlocked_ioctl = beep_ioctl,
.release = beep_release
};
struct resource *res;
int beep_probe(struct platform_device *pdev)
{
int ret = 0;
printk("beep probe !\n");
// pwm 对应的cpu引脚,从设备树节点描述中获取: pinctrl-0 = <&pwm0_out>; pinctrl-names = "default";
devm_pinctrl_get_select_default(&pdev->dev);
// pwm 控制器基地址,从设备树节点描述中获取: reg = <0x139D0000 0x14>;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
printk("baseaddr: %#x\n", res->start);
// 物理地址映射到内核空间
xbeep.pwmaddr = ioremap(res->start, res->end - res->start);
printk("beep module in\n");
//request dev num
ret = alloc_chrdev_region(&xbeep.num, 0, 1, "beep");
if(ret)
{
printk("devnum alloc fail!\n");
return ret;
}
printk("num: %d\n", MAJOR(xbeep.num) );
//init cdev ops
cdev_init(&xbeep.cdev_beep, &beep_ops);
xbeep.cdev_beep.owner = THIS_MODULE;
//register cdev into kernel
ret = cdev_add(&xbeep.cdev_beep, xbeep.num, 1);
if(ret)
{
printk("add cdev fail!\n");
goto cdev_add_out;
}
xbeep.class = class_create(THIS_MODULE, "beeps");
xbeep.device = device_create(xbeep.class, NULL, xbeep.num, NULL, "beep%d", 0);
return 0;
cdev_add_out:
unregister_chrdev_region(xbeep.num, 1);
return ret;
}
int beep_remove(struct platform_device *pdev)
{
//unregister cdev from kernel
cdev_del(&xbeep.cdev_beep);
//release dev num
unregister_chrdev_region(xbeep.num,1);
device_del(xbeep.device);
class_destroy(xbeep.class);
printk("beep module release\n");
return 0;
}
struct platform_device_id beep_ids[] = {
[0] = {
.name = "beep0"
},
[1] = {
}
};
#ifdef CONFIG_OF
struct of_device_id beep_table[] = {
{ .compatible = "beep" },
{ }
};
#endif
struct platform_driver beep_driver = {
.probe = beep_probe,
.remove = beep_remove,
// .id_table = beep_ids,
.driver = {
.name = "beep",
.of_match_table = of_match_ptr(beep_table)
}
};
MODULE_DEVICE_TABLE(platform, beep_ids);
static int beep_init(void)
{
printk("module install\n");
//add into platform bus
platform_driver_register(&beep_driver);
return 0;
}
static void beep_exit(void)
{
printk("module release\n");
//del from platform bus
platform_driver_unregister(&beep_driver);
}
module_init(beep_init);
module_exit(beep_exit);
应用层
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define ON _IOW('P', 0, int)
#define OFF _IOW('P', 1, int)
#define XXX _IOW('P', 2, int)
typedef struct{
int base;
int cont;
}ARG;
int main(int argc, char **argv)
{
int fd;
int duty = 1000;
int period = 2000;
if(2 != argc)
{
printf("Usage: %s <beep dev>\n", argv[0]);
return -1;
}
fd = open(argv[1], O_RDWR);
if(-1 == fd)
{
perror("open");
return -1;
}
while(1)
{
ioctl(fd, ON, 0);
sleep(1);
ARG arg = {period, duty};
ioctl(fd, XXX, &arg);
duty = rand()%2000;
}
close(fd);
return 0;
}