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