linux设备树之pwm

9 篇文章 0 订阅

吐舌头驱动层

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



  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值