驱动demo

PWM驱动

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
//#include <linux/uaccess.h>
//#include <linux/slab.h> 
#include <linux/pwm.h>


#define PWM_CMD_WRITE		0x01
#define PWM_CMD_READ		0x03
#define PWM_CMD_CLOSE		0x05

#define PWM_PERIOD			100000
#define PWM_MAX_NUM			12

typedef unsigned int		UINT32;
typedef struct hiPWM_DATA_S
{
	UINT32 pwm_chn;
	UINT32 clk_div;
//	UINT32 reload;
   	UINT32  ui_prd;                              ///< Base period, how many PWM clock per period, 2 ~ 255
	UINT32  ui_rise;                             ///< Rising at which clock
	UINT32  ui_fall;                             ///< Falling at which clock	
	UINT32  ui_on_cycle;                   ///< Output cycle, 0 ~ 65535	
	UINT32  ui_inv;    
} PWM_DATA_S;


static int s_pwm_id_list[PWM_MAX_NUM];
static struct pwm_device *s_pwm_dev_list[PWM_MAX_NUM]; 

static int
PWM_Open(struct inode *inode, struct file *filp)
{
	return 0;
}

static int
PWM_Close(struct inode *inode, struct file *filp)
{
	return 0;
}

void PWM_DRV_Write(unsigned long channel, unsigned long base_period, unsigned long rising, unsigned long falling, unsigned long clk_div, unsigned long inv, unsigned long cycle)
{
	int pwm_id = 0;
	static struct pwm_device *pwm_dev; 
	struct pwm_state state;
	
	pwm_id = (int)channel;
	
	if ((pwm_id >= 1) && (pwm_id <= PWM_MAX_NUM) && (-1 == s_pwm_id_list[pwm_id - 1]))
	{
		pwm_dev = pwm_request(pwm_id, "pwm");
		if (IS_ERR(pwm_dev)) 
		{
			printk("申请PWM通道%d失败\n", pwm_id);
			return;
		}
		s_pwm_dev_list[pwm_id - 1] = pwm_dev;
		s_pwm_id_list[pwm_id - 1] = 1;
	}
	else
	{
		pwm_dev = s_pwm_dev_list[pwm_id - 1];
	}
	
	memset(&state, 0, sizeof(state));
	state.period = PWM_PERIOD; //set pwm parameter
	state.duty_cycle = 90000;
	state.polarity = PWM_POLARITY_NORMAL;

	state.enabled = 0;
	pwm_apply_state(pwm_dev, &state); //disable firstly

	if (falling)
	{
		state.enabled = 1;
		pwm_apply_state(pwm_dev, &state); //apply setting
	}
	else
	{
		state.enabled = 0;
		pwm_apply_state(pwm_dev, &state); //apply setting
	}
}

void PWM_DRV_Exit(void)
{
	int i = 0;
	for(i = 0; i < PWM_MAX_NUM;++i)
	{
		if (-1 == s_pwm_id_list[i])
			continue;
		
		pwm_disable(s_pwm_dev_list[i]);
		pwm_free(s_pwm_dev_list[i]);
		s_pwm_id_list[i] = -1;
	}
}

static long
PWM_Ioctl(struct file *filp, unsigned int req, unsigned long arg)
{
	switch (req) 
	{
		case PWM_CMD_WRITE: 
		{
			PWM_DATA_S st_pwm;
			if(copy_from_user(&st_pwm, (PWM_DATA_S __user *)arg, sizeof(PWM_DATA_S)))
			{
				return -EFAULT;
			}
			PWM_DRV_Write(st_pwm.pwm_chn,st_pwm.ui_prd,st_pwm.ui_rise,st_pwm.ui_fall,st_pwm.clk_div,st_pwm.ui_inv,st_pwm.ui_on_cycle);
			break;
		}
		case PWM_CMD_READ: 
		{	
			break;
		}
		case PWM_CMD_CLOSE:
		{
			PWM_DATA_S st_pwm;
			int pwm_id = 0;
			pwm_id = (int)st_pwm.pwm_chn;
			if(copy_from_user(&st_pwm, (PWM_DATA_S __user *)arg, sizeof(PWM_DATA_S)))
			{
				return -EFAULT;
			}	
			if ((pwm_id >= 1) && (pwm_id <= PWM_MAX_NUM) && (1 == s_pwm_id_list[pwm_id - 1]))
			{
				pwm_disable(s_pwm_dev_list[pwm_id - 1]);
				pwm_free(s_pwm_dev_list[pwm_id - 1]);
				s_pwm_id_list[pwm_id - 1] = -1;
		
				s_pwm_id_list[pwm_id - 1] = -1;
			}
			
			break;
		}
		default:
		{
			return -1;
		}
	}
	return 0;
}


static struct file_operations drv_fops = {
	.owner		= THIS_MODULE,
	.open		= PWM_Open,
	.release	= PWM_Close,
	.unlocked_ioctl = PWM_Ioctl,
};

static struct miscdevice misc_dev = {
	.minor	= MISC_DYNAMIC_MINOR,
	.name	= "pwm",
	.fops	= &drv_fops,
};

static int __init my_init(void)
{
	int ret;
	int i;
	
	for (i = 0; i < PWM_MAX_NUM; ++i)
	{
		s_pwm_id_list[i] = -1;
	}
	
	ret = misc_register(&misc_dev);
	if (ret < 0)
	{
		printk("drv init\n");
		return -1;
	}
	
	printk("pwm(build time:%s_%s) load successfully\n", __DATE__, __TIME__ );
	
	return 0;
}

static void __exit my_exit(void)
{
	PWM_DRV_Exit();
	
	misc_deregister (&misc_dev);
	
	printk("pwm(build time:%s_%s) exit successfully\n", __DATE__, __TIME__ );
	return;
}

module_init(my_init);
module_exit(my_exit);
MODULE_AUTHOR("SHJ");
MODULE_LICENSE("GPL");

test

#include "stdio.h"
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <unistd.h>


typedef unsigned int           UINT32;
typedef struct hiPWM_DATA_S
{
	UINT32 pwm_chn;
	UINT32 clk_div;
//	UINT32 reload;
   	UINT32  ui_prd;                              ///< Base period, how many PWM clock per period, 2 ~ 255
	UINT32  ui_rise;                             ///< Rising at which clock
	UINT32  ui_fall;                             ///< Falling at which clock	
	UINT32  ui_on_cycle;                   ///< Output cycle, 0 ~ 65535	
	UINT32  ui_inv;    
} PWM_DATA_S;

#define PWM_CMD_WRITE      0x01
#define PWM_CMD_READ       0x03
#define PWM_CMD_CLOSE 	   0x05


int main(int argc,char* argv[])
{
	static int s_pwm_fd = 0;
	PWM_DATA_S st_pwm_data;
	
	
	st_pwm_data.pwm_chn = 4;
	st_pwm_data.ui_prd = 0;
	st_pwm_data.ui_rise = 0;
	st_pwm_data.ui_fall = 0;
	st_pwm_data.clk_div = 0;
	st_pwm_data.ui_inv = 0;
	st_pwm_data.ui_on_cycle = 0;
	
	s_pwm_fd = open("/dev/pwm",O_RDWR);
	if(s_pwm_fd<=0)
	{
		printf("open failure!\n");
		return -1;
	}
	
	for (int i = 0; i < 30; ++i)
	{
		printf("red open\n");
		st_pwm_data.pwm_chn = 4;
		st_pwm_data.ui_fall = 1;
		int s32_ret = ioctl(s_pwm_fd, PWM_CMD_WRITE, &st_pwm_data); 
		if(s32_ret < 0)
		{
			printf("PWM_CMD_WRITE failure\n");
		}
		
		usleep(1000 * 50);
		
		printf("red close\n");
		st_pwm_data.pwm_chn = 4;
		st_pwm_data.ui_fall = 0;
		s32_ret = ioctl(s_pwm_fd, PWM_CMD_WRITE, &st_pwm_data); 
		if(s32_ret < 0)
		{
			printf("PWM_CMD_WRITE failure\n");
		}
		
		usleep(1000 * 50);
		
		printf("blue open\n");
		st_pwm_data.pwm_chn = 5;
		st_pwm_data.ui_fall = 1;
		s32_ret = ioctl(s_pwm_fd, PWM_CMD_WRITE, &st_pwm_data); 
		if(s32_ret < 0)
		{
			printf("PWM_CMD_WRITE failure\n");
		}
		
		usleep(1000 * 50);
		
		printf("blue close\n");
		st_pwm_data.ui_fall = 0;
		s32_ret = ioctl(s_pwm_fd, PWM_CMD_WRITE, &st_pwm_data); 
		if(s32_ret < 0)
		{
			printf("PWM_CMD_CLOSE failure\n");
		}
		
		usleep(1000 * 50);
		printf("-------------------------------------\n");
		
	}
	
	
	return 0;
}

Makefile

# 专用于编译.ko的Makefile
# 需要找到当前运行内核对应的根Makefile
KERNEL := /home/work/sourcecode/kernel/


obj-m := pwm.o
myko := pwm.ko

all:
	make -C $(KERNEL) M=`pwd` modules
install:
	adb remount
	adb push $(myko) /system/lib/modules/
clean:
	make -C $(KERNEL) M=`pwd` clean


GPIO驱动

#ifndef __GPIO_H__
#define __GPIO_H__

#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */





#define DRV_NAME "gpio"
#define DRV_VERS "c01b01"


typedef struct
{
	unsigned char name[32];
	unsigned char version[32];
	unsigned char build_time[64];
}drv_ver_info_st;

typedef enum
{
	out = 0,
	input,
}direction_e;

typedef struct
{
	unsigned int 	gpio_id;			/*gpio id*/
	unsigned char 	direction;			/*配置gpio引脚的方向 0:输出;1:输入*/
	unsigned char	input_valu;			/*读取gpio的输入值*/
	unsigned char	output_valu;		/*配置gpio的输出值*/
	unsigned char	gpio_name[32];		/*gpio的名字*/
}gpio_attr_st;


#define IOC_MAGIC 'g'

//driver version info
#define GPIO_GET_DRV_INFO		_IOR(IOC_MAGIC,0x00, drv_ver_info_st)

#define GPIO_REQUEST			_IOW(IOC_MAGIC,0x01,gpio_attr_st)
#define GPIO_FERR				_IOW(IOC_MAGIC,0x02,gpio_attr_st)

#define GPIO_DIRECTION_SET		_IOW(IOC_MAGIC,0x03,gpio_attr_st)
#define GPIO_DIRECTION_GET		_IOR(IOC_MAGIC,0x04,gpio_attr_st)

#define GPIO_VALU_SET			_IOW(IOC_MAGIC,0x05,gpio_attr_st)
#define GPIO_VALU_GET			_IOR(IOC_MAGIC,0x06,gpio_attr_st)



#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */

#endif	/* __GPIO_H__ */



#include <asm/uaccess.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/fcntl.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/spi/spi.h>
#include <linux/proc_fs.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/time.h>
#include <linux/gpio.h>

#if 0
int gpio_request(unsigned gpio, const char *label);
void gpio_free(unsigned gpio);
int gpio_direction_input(unsigned gpio);
int gpio_direction_output(unsigned gpio, int value);
int gpio_get_value(unsigned int gpio);
void gpio_set_value(unsigned int gpio, int value);
int gpio_to_irq(unsigned int gpio);
#endif

#include "gpio.h"


static DEFINE_MUTEX(gpio_lock);


static int set_direction(gpio_attr_st *p_gpio_attr_info)
{
	int ret = -1;
	if(p_gpio_attr_info->direction == 1)
	{
		ret = gpio_direction_input(p_gpio_attr_info->gpio_id);
	}
	else
	{
		ret = gpio_direction_output(p_gpio_attr_info->gpio_id, p_gpio_attr_info->output_valu);
	}
	return ret;
}

static long fops_ioctl(struct file *file,unsigned int cmd, unsigned long __user arg)
{
	int ret = 0;

	mutex_lock(&gpio_lock);
	//if(!mutex_trylock(&gpio_lock))
	//{
	//	printk("\n============ gpio_ioctl busy =========\n");
	//	return -EBUSY;
	//}
	
	switch(cmd)
	{
		case GPIO_GET_DRV_INFO:
		{
			char str_tmp[24] = {0};
			if(copy_to_user(((drv_ver_info_st __user *)arg)->name, DRV_NAME, sizeof(DRV_NAME)))
				goto exit;
			if(copy_to_user(((drv_ver_info_st __user *)arg)->version, DRV_VERS, sizeof(DRV_VERS)))
				goto exit;
			sprintf( str_tmp, "%s-%s", __DATE__, __TIME__ );
			if(copy_to_user(((drv_ver_info_st __user *)arg)->build_time, str_tmp, sizeof(str_tmp)))
				goto exit;
			break;
		}
		case GPIO_REQUEST:
		{
			gpio_attr_st gpio_attr_info;
			if( copy_from_user(&(gpio_attr_info), (gpio_attr_st __user *)arg, sizeof(gpio_attr_st)))
			{
				goto exit;
			}
			ret = gpio_request(gpio_attr_info.gpio_id, gpio_attr_info.gpio_name);
			if(ret != 0)
			{
				goto exit;
			}
			break;
		}
		case GPIO_FERR:
		{
			gpio_attr_st gpio_attr_info;
			if( copy_from_user(&(gpio_attr_info), (gpio_attr_st __user *)arg, sizeof(gpio_attr_st)))
			{
				goto exit;
			}
			gpio_free(gpio_attr_info.gpio_id);
			break;
		}
		case GPIO_DIRECTION_SET:
		{
			gpio_attr_st gpio_attr_info;
			if( copy_from_user(&(gpio_attr_info), (gpio_attr_st __user *)arg, sizeof(gpio_attr_st)))
			{
				return -EFAULT;
			}
			ret = set_direction(&gpio_attr_info);
			
			break;
		}
		case GPIO_DIRECTION_GET:
		{
			gpio_attr_st gpio_attr_info;

			goto exit;//不支持
			
			if( copy_from_user(&(gpio_attr_info), (gpio_attr_st __user *)arg, sizeof(gpio_attr_st)))
			{
				goto exit;
			}
			//ret = gpiod_get_direction(gpio_attr_info.gpio_id);
			if(copy_to_user((gpio_attr_st __user *)arg, &gpio_attr_info, sizeof(gpio_attr_info)))
			{
				goto exit;
			}
			break;
		}
		case GPIO_VALU_SET:
		{
			gpio_attr_st gpio_attr_info;
			if( copy_from_user(&(gpio_attr_info), (gpio_attr_st __user *)arg, sizeof(gpio_attr_st)))
			{
				goto exit;
			}
			
			ret = set_direction(&gpio_attr_info);
			//printk(" gpio_attr_info.gpio_id = %d , gpio_attr_info.output_valu = %d \n",gpio_attr_info.gpio_id, gpio_attr_info.output_valu);
			gpio_set_value(gpio_attr_info.gpio_id, gpio_attr_info.output_valu);
			
			break;
		}
		case GPIO_VALU_GET:
		{
			gpio_attr_st gpio_attr_info;
			if( copy_from_user(&(gpio_attr_info), (gpio_attr_st __user *)arg, sizeof(gpio_attr_st)))
			{
				goto exit;
			}
			
			ret = set_direction(&gpio_attr_info);
			
			gpio_attr_info.input_valu = gpio_get_value(gpio_attr_info.gpio_id);

			if(copy_to_user((gpio_attr_st __user *)arg, &gpio_attr_info, sizeof(gpio_attr_info)))
			{
				goto exit;
			}
			
			break;
		}
		default:
		{
			printk("unkonw cmd:0x%x\n", cmd );
			goto exit;
		}
	}

	mutex_unlock(&gpio_lock);
	return ret;
	
exit:
	
	mutex_unlock(&gpio_lock);
	
	return -EFAULT;
}




int fops_open(struct inode* inode, struct file* file)
{
	//pwm_base_clk_update();
	return 0 ;
}

int  fops_close(struct inode* inode, struct file* file)
{
	return 0;
}


static const struct file_operations drv_fops = {
	.owner=THIS_MODULE,
	.open=fops_open,
	.release=fops_close,
	.unlocked_ioctl=fops_ioctl,
};

static struct miscdevice misc_dev = {
	.minor = MISC_DYNAMIC_MINOR,
	.name = "gpio",
	.fops = &drv_fops,
};

static int __init mod_init(void)
{
	int ret;

	ret = misc_register(&misc_dev);
	if (ret < 0)
	{
		printk("drv init\n");
		return -1;
	}
	printk("gpio.ko(ver:%s, build time:%s_%s) load successfully\n", DRV_VERS, __DATE__, __TIME__ );
	return 0;
}

static void __exit mod_exit(void)
{
/*把以前fclose里面的zoom/focus stop挪到此处,因为测试程序会多次open, close此驱动,改到此处后,将不再影响到lv8044的寄存器值。Jimmy Feb17th2016*/
	printk("gpio(ver:%s, build time:%s_%s) exit successfully\n", DRV_VERS, __DATE__, __TIME__ );	

	misc_deregister(&misc_dev);
	
	printk("gpio(ver:%s, build time:%s_%s) exit successfully\n", DRV_VERS, __DATE__, __TIME__ );
	return;
}


module_init(mod_init);
module_exit(mod_exit);

MODULE_DESCRIPTION("gpio driver");
MODULE_LICENSE("GPL");
//MODULE_AUTHOR("gpio");

test

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <pthread.h>

#include "gpio.h"


#define LOG_INFO(fmt,args...)   ({printf("info: %s(%d) %s:",__FILE__, __LINE__, __func__);printf(fmt"\r\n" ,##args);})
#define SN_GOTO(express, go, fmt, ...) \
do \
{\
	if(!(express)) \
	{ \
		LOG_INFO(fmt, ##__VA_ARGS__); \
		goto go; \
	} \
}while(0)



	
int main(int argc ,char * argv[])
{
	int s32Ret;
	int fd = -1;
	
	fd = open("/dev/gpio",O_RDWR);
	SN_GOTO(fd >=0, _Exit_GPIO_FD, "ioctl GPIO open failed !");

	
	gpio_attr_st stGpioAttr;
	memset(&stGpioAttr, -1,sizeof(gpio_attr_st));
	
	
	LOG_INFO(" ----- argc %d\n", argc);
		
	
	int _u32GpioNum = 0;
	//READ
	if (argc == 1)
	{
		stGpioAttr.gpio_id = _u32GpioNum;
		stGpioAttr.direction = 1; //1 为读
		sprintf((char*)stGpioAttr.gpio_name,"gpio%d", _u32GpioNum);
	
		s32Ret = ioctl(fd, GPIO_REQUEST, &stGpioAttr);
		SN_GOTO(s32Ret >=0, _Exit_GPIO_FD, "ioctl GPIO_REQUEST failed!");

		s32Ret = ioctl(fd, GPIO_DIRECTION_SET, &stGpioAttr);
		SN_GOTO(s32Ret >=0, _Exit_GPIO_FD, "ioctl GPIO_DIRECTION_SET failed!");
		usleep(10*1000);
		
		s32Ret = ioctl(fd, GPIO_VALU_GET, &stGpioAttr);
		SN_GOTO(s32Ret >=0, _Exit_GPIO_FD, "ioctl GPIO_VALU_GET failed!");
		usleep(10*1000);
		
		LOG_INFO(" ----- read %d\n", stGpioAttr.input_valu);
		
		s32Ret = ioctl(fd, GPIO_FERR, &stGpioAttr);
		SN_GOTO(s32Ret >=0, _Exit_GPIO_FD, "ioctl GPIO_DIRECTION_SET failed!");
			
	}
	else
	{
		stGpioAttr.gpio_id = _u32GpioNum;
		stGpioAttr.direction = 0; //0 为写
		sprintf((char*)stGpioAttr.gpio_name,"gpio%d", _u32GpioNum);
		
		
		//stGpioAttr.output_valu = 1;
		//stGpioAttr.output_valu = atoi(argv[1]);
		
		//LOG_INFO(" ----- write %d\n", stGpioAttr.output_valu);

		s32Ret = ioctl(fd, GPIO_REQUEST, &stGpioAttr);
		SN_GOTO(s32Ret >=0, _Exit_GPIO_FD, "ioctl GPIO_REQUEST failed!");
		
		stGpioAttr.output_valu = 1;
		s32Ret = ioctl(fd, GPIO_DIRECTION_SET, &stGpioAttr);
		SN_GOTO(s32Ret >=0, _Exit_GPIO_FD, "ioctl GPIO_DIRECTION_SET failed!");
		usleep(10*1000);
		
		
		
		
		//引脚拉低
		stGpioAttr.output_valu = 0;
		s32Ret = ioctl(fd, GPIO_VALU_SET, &stGpioAttr);
		SN_GOTO(s32Ret >=0, _Exit_GPIO_FD, "ioctl GPIO_VALU_GET failed!");
		usleep(10*1000);
		
		
		
		
		
		s32Ret = ioctl(fd, GPIO_FERR, &stGpioAttr);
		SN_GOTO(s32Ret >=0, _Exit_GPIO_FD, "ioctl GPIO_DIRECTION_SET failed!");
		
	}
	
	
	
_Exit_GPIO_FD:
			
	if(fd)	
	{	
		close(fd);
		//fd = NULL;
	}
	return 0;
}





Makefile

CROSS_COMPILE = arm-buildroot-linux-uclibcgnueabihf-

ifeq (${ISVP_ENV_KERNEL_DIR}, )
	ISVP_ENV_KERNEL_DIR = ../kernel
endif

KDIR := ${ISVP_ENV_KERNEL_DIR}


all: modules gpio_test



.PHONY: modules clean

GPIO_HAL_NAME := gpio
GPIO_TEST := gpio_test
$(MODULE_NAME)-objs := gpio.o
obj-m := $(GPIO_HAL_NAME).o
#obj-m := $(GPIO_TEST).o 

modules:
	@$(MAKE) -C $(KDIR)  M=$(shell pwd) $@

gpio_test:
	$(CROSS_COMPILE)gcc -o gpio_test gpio_test.c

clean:
	@rm -rf *.o *~ .depend .*.cmd  *.mod.c .tmp_versions *.ko *.symvers modules.order
	@rm gpio_test

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值