欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

linux设备树之pwm

程序员文章站 2024-01-23 15:07:28
...

linux设备树之pwm驱动层

#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);

linux设备树之pwm应用层

#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;
}



相关标签: linux 设备树