4412 4路pwm输出

一、4412 xpwmTOUT1

这是4412的GPD0_1路,itop中被使用为LCD的背光电路的pwm功能。因此如果使用教程中的代码,同样操作GPD0_1是行不通的。

会出现错误,所以需要解除在内核中的占用

修改arch/arm/mach-exynos/mach-itop4412.c,找到并注释

    samsung_bl_set(&smdk4x12_bl_gpio_info, &smdk4x12_bl_data);

在内核中取消相关的模块编译,(不确定)

Device Driver>>Graphics support>>Backlight & LCD device support(取消)

然后在平台文件中增加注册设备:

    &s3c_device_timer[1],

然后是测试代码:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/fb.h>
#include <linux/backlight.h>
#include <linux/err.h>
#include <linux/pwm.h>
#include <linux/slab.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <mach/gpio.h>
#include <plat/gpio-cfg.h>
#include <linux/ioctl.h>
#include <asm-generic/uaccess.h>

#define DEVICE_NAME "my_pwm3_dev"
#define DRIVER_NAME "my_pwm3_drv"

#define PWM_MAGIC 'p'
#define PWM_MAX_NR 3

#define PWM_IOCTL_STOP      _IO(PWM_MAGIC, 0)
#define PWM_IOCTL_SET_FREQ  _IO(PWM_MAGIC, 1)
#define PWM_IOCTL_SET_DUTY  _IO(PWM_MAGIC, 2)

#define NS_IN_1HZ                               (1000000000UL)

#define BUZZER_PWM_ID                   0
#define PWM1_ID                                 1
#define PWM2_ID                 2
#define PWM3_ID                 3


#define BUZZER_PMW_GPIO EXYNOS4_GPD0(0)
#define PWM1_GPIO               EXYNOS4_GPD0(1)
#define PWM2_GPIO       EXYNOS4_GPD0(2)
#define PWM3_GPIO       EXYNOS4_GPD0(3)

static struct pwm_device *pwm4buzzer;
static struct semaphore lock;
static int period_ns = 1000;
static unsigned long freq = 50;
static unsigned long duty = 2;

static void pwm_set_freq(void)
{
    //配置周期
    period_ns = NS_IN_1HZ / freq;
    //配置占空比
        if(duty < 1)
                duty = 1;
    pwm_disable(pwm4buzzer);
    pwm_config(pwm4buzzer, period_ns / duty, period_ns);
    pwm_enable(pwm4buzzer);
    //配置相应的GPIO,蜂鸣器IO配置成PWM输出模式
    s3c_gpio_cfgpin(PWM3_GPIO, S3C_GPIO_SFN(2));
}

static void pwm_stop(void)
{
    s3c_gpio_cfgpin(PWM3_GPIO, S3C_GPIO_OUTPUT);

    pwm_config(pwm4buzzer, 0, NS_IN_1HZ / 100);
    pwm_disable(pwm4buzzer);
}

static int ops_pwm_open(struct inode *inode, struct file *file)
{
    if(!down_trylock(&lock))
        return 0;
    else
        return -EBUSY;
}

static int ops_pwm_close(struct inode *inode, struct file *file)
{
    up(&lock);
    return 0;
}

static long ops_pwm_ioctl(struct file *filep, unsigned int cmd,
                unsigned long arg)
{
    if(_IOC_TYPE(cmd)!=PWM_MAGIC) return -EINVAL;
    if(_IOC_NR(cmd) > PWM_MAX_NR) return -EINVAL;

    switch(cmd) {
    case PWM_IOCTL_SET_FREQ:
        if(arg == 0)
            return -EINVAL;
        get_user(freq, (unsigned long __user *)arg);
        printk(KERN_EMERG "freq is %ld
", freq);
        pwm_set_freq();
        break;
    case PWM_IOCTL_STOP:
        pwm_stop();
                break;
        case PWM_IOCTL_SET_DUTY:
        get_user(duty, (unsigned long __user *)arg);
        printk(KERN_EMERG "duty is %ld
", duty);
        pwm_set_freq();
                break;
    default:
        pwm_stop();
        break;
    }
    return 0;
}

static struct file_operations pwm_ops = {
    .owner = THIS_MODULE,
    .open  = ops_pwm_open,
    .release = ops_pwm_close,
    .unlocked_ioctl = ops_pwm_ioctl,
};

static struct miscdevice pwm_misc_dev = {
    .minor = MISC_DYNAMIC_MINOR,
    .name  = DEVICE_NAME,
    .fops  = &pwm_ops,
};

static int __init iTop4412_pwm_dev_init(void)
{
    int ret;
    gpio_free(PWM3_GPIO);

    ret = gpio_request(PWM3_GPIO, DEVICE_NAME);
    if(ret) {
                printk(KERN_EMERG "request GPIO %d for pwm failed
", PWM3_GPIO);
                return ret;
    }

        gpio_set_value(PWM3_GPIO, 0);
        s3c_gpio_cfgpin(PWM3_GPIO, S3C_GPIO_OUTPUT);

        pwm4buzzer = pwm_request(PWM3_ID, DEVICE_NAME);
        if (IS_ERR(pwm4buzzer)) {
                printk(KERN_EMERG "request pwm %d for %s failed
", PWM3_ID, DEVICE_NAME);
                return -ENODEV;
        }
    pwm_stop();

    sema_init(&lock, 1);
    ret = misc_register(&pwm_misc_dev);
        if(ret < 0) {
                gpio_free(BUZZER_PMW_GPIO);
                pwm_free(pwm4buzzer);
                misc_deregister(&pwm_misc_dev);
        }

    printk(KERN_EMERG "	initialized
");

    return ret;
}

static void __exit iTop4412_pwm_dev_exit(void)
{
    gpio_free(BUZZER_PMW_GPIO);
        pwm_free(pwm4buzzer);
    misc_deregister(&pwm_misc_dev);

    printk(KERN_EMERG "	exit
");
    return;
}

module_init(iTop4412_pwm_dev_init);
module_exit(iTop4412_pwm_dev_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Chen Tuo");
MODULE_DESCRIPTION("Exynos4 PWM Driver");
my_pwm3.c

然后是应用程序:

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

#define PWM2_NAME "/dev/my_pwm3_dev"

#define PWM_MAGIC 'p'
#define PWM_MAX_NR 3

#define PWM_IOCTL_STOP      _IO(PWM_MAGIC, 0)
#define PWM_IOCTL_SET_FREQ  _IO(PWM_MAGIC, 1)
#define PWM_IOCTL_SET_DUTY  _IO(PWM_MAGIC, 2)

int fd = -1;

void open_pwm1(void);
void close_pwm1(void);
void set_pwm_freq(int freq);
void set_pwm_duty(int duty);
void stop_pwm(void);

void open_pwm1(void)
{
    fd = open(PWM2_NAME, O_RDWR);
    if(fd < 0) {
        perror("open pwm1 device");
        exit(1);
    }

//    atexit(close_pwm1);
}

void close_pwm1(void)
{
    if(fd >= 0) {
        ioctl(fd, PWM_IOCTL_STOP);
        close(fd);
        fd = -1;
    }
}

void set_pwm_freq(int freq)
{
    int ret = ioctl(fd, PWM_IOCTL_SET_FREQ, &freq);
    if(ret < 0) {
        perror("set the frequency of the buzzer");
        exit(1);
    }
}

void set_pwm_duty(int duty)
{
    int ret = ioctl(fd, PWM_IOCTL_SET_DUTY, &duty);
    if(ret < 0) {
        perror("set the duty of the pwm");
        exit(1);
    }
}

void stop_pwm(void)
{
    int ret = ioctl(fd, PWM_IOCTL_STOP);
    if(ret < 0) {
        perror("Stop the buzzer");
        exit(1);
    }
}

int main(int argc, char *argv[])
{
    int freq = 1000;

    open_pwm1();
    stop_pwm();
    if(argc < 3) {
        printf("usage:%s [cmd] [arg]
", argv[0]);
        printf("	stop:%s [0] [0] 
",argv[0]);
        printf("	set freq:%s [1] [arg]
", argv[0]);
        printf("	set duty:%s [2] [arg]
", argv[0]);
    }
        switch(atoi(argv[1]))
        {
        case 2:
                set_pwm_duty(atoi(argv[2]));
        break;
        case 1:
                set_pwm_freq(atoi(argv[2]));
                break;
    case 0:
        default:
                stop_pwm();
                return -1;
        }

        return 0;
}
my_pwm3_app.c

最后是Makefile:

TARGET_NAME = my_pwm3
#TARGET_NAME = example_pwm
APP1_NAME = my_pwm3_app
#APP2_NAME = open_atomic_int_two
obj-m += $(TARGET_NAME).o

KDIR := /home/topeet/chen/kernel-3.0/iTop4412_Kernel_3.0

PWD ?= $(shell pwd)

all:app1
        make -C $(KDIR) M=$(PWD) modules
app1:
        arm-none-linux-gnueabi-gcc $(APP1_NAME).c -o $(APP1_NAME) -static
#app2:
#       arm-none-linux-gnueabi-gcc $(APP2_NAME).c -o $(APP2_NAME) -static

clean:
        rm -rf *.o *.ko *.mod.c *.symvers *.order 
        .$(TARGET_NAME)* $(APP1_NAME) $(APP2_NAME)
Makefile

二、4412 I2C_SDA7和I2C_SCL7

注释平台文件中的代码:

//  s3c_i2c7_set_platdata(NULL);
//  i2c_register_board_info(7, i2c_devs7, ARRAY_SIZE(i2c_devs7));

和这个

//  &s3c_device_i2c7,

然后make menuconfig

>>Device Drivers>>Input device support>>Touchscreens【】取消选择

三、尝试编写控制PWM波形的驱动和应用程序

my_pwm3.c(驱动)

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/fb.h>
#include <linux/backlight.h>
#include <linux/err.h>
#include <linux/pwm.h>
#include <linux/slab.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <mach/gpio.h>
#include <plat/gpio-cfg.h>
#include <linux/ioctl.h>
#include <asm-generic/uaccess.h>

#define DEVICE_NAME "my_pwm3_dev"
#define DRIVER_NAME "my_pwm3_drv"

#define PWM_MAGIC 'p'
#define PWM_MAX_NR 3

#define PWM_IOCTL_STOP      _IO(PWM_MAGIC, 0)
#define PWM_IOCTL_SET_FREQ  _IO(PWM_MAGIC, 1)
#define PWM_IOCTL_SET_DUTY  _IO(PWM_MAGIC, 2)

#define NS_IN_1HZ                (1000000000UL)

#define BUZZER_PWM_ID            0
#define PWM1_ID                    1
#define PWM2_ID                 2
#define PWM3_ID                 3


#define BUZZER_PMW_GPIO EXYNOS4_GPD0(0)
#define PWM1_GPIO         EXYNOS4_GPD0(1)
#define PWM2_GPIO       EXYNOS4_GPD0(2)
#define PWM3_GPIO       EXYNOS4_GPD0(3)

static struct pwm_device *pwm4buzzer;
static struct semaphore lock;
static int period_ns = 1000;
static unsigned long freq = 50;
static unsigned long duty = 2;

static void pwm_set_freq(void)
{
    //配置周期
    period_ns = NS_IN_1HZ / freq;
    //配置占空比
    if(duty < 2)
        duty = 2;
    pwm_disable(pwm4buzzer);
    pwm_config(pwm4buzzer, period_ns / duty, period_ns);
    pwm_enable(pwm4buzzer);
    //配置相应的GPIO,蜂鸣器IO配置成PWM输出模式
    s3c_gpio_cfgpin(PWM3_GPIO, S3C_GPIO_SFN(2));
}

static void pwm_stop(void)
{
    s3c_gpio_cfgpin(PWM3_GPIO, S3C_GPIO_OUTPUT);

    pwm_config(pwm4buzzer, 0, NS_IN_1HZ / 100);
    pwm_disable(pwm4buzzer);
}

static int ops_pwm_open(struct inode *inode, struct file *file)
{
    if(!down_trylock(&lock))
        return 0;
    else
        return -EBUSY;
}

static int ops_pwm_close(struct inode *inode, struct file *file)
{
    up(&lock);
    return 0;
}

static long ops_pwm_ioctl(struct file *filep, unsigned int cmd,
        unsigned long arg)
{
    if(_IOC_TYPE(cmd)!=PWM_MAGIC) return -EINVAL;
    if(_IOC_NR(cmd) > PWM_MAX_NR) return -EINVAL;

    switch(cmd) {
    case PWM_IOCTL_SET_FREQ:
        if(arg == 0)
            return -EINVAL;
        get_user(freq, (unsigned long __user *)arg);
        printk(KERN_EMERG "freq is %ld
", freq);
        pwm_set_freq();
        break;
    case PWM_IOCTL_STOP:
        pwm_stop();
        break;
    case PWM_IOCTL_SET_DUTY:
        get_user(duty, (unsigned long __user *)arg);
        printk(KERN_EMERG "duty is %ld
", duty);
        pwm_set_freq();
        break;
    default:
        pwm_stop();
        break;
    }
    return 0;
}

static struct file_operations pwm_ops = {
    .owner = THIS_MODULE,
    .open  = ops_pwm_open,
    .release = ops_pwm_close,
    .unlocked_ioctl = ops_pwm_ioctl,
};

static struct miscdevice pwm_misc_dev = {
    .minor = MISC_DYNAMIC_MINOR,
    .name  = DEVICE_NAME,
    .fops  = &pwm_ops,
};

static int __init iTop4412_pwm_dev_init(void)
{
    int ret;
    gpio_free(PWM3_GPIO);

    ret = gpio_request(PWM3_GPIO, DEVICE_NAME);
    if(ret) {
        printk(KERN_EMERG "request GPIO %d for pwm failed
", PWM3_GPIO);
        return ret;
    }

    gpio_set_value(PWM3_GPIO, 0);
    s3c_gpio_cfgpin(PWM3_GPIO, S3C_GPIO_OUTPUT);

    pwm4buzzer = pwm_request(PWM3_ID, DEVICE_NAME);
    if (IS_ERR(pwm4buzzer)) {
        printk(KERN_EMERG "request pwm %d for %s failed
", PWM3_ID, DEVICE_NAME);
        return -ENODEV;
    }
    pwm_stop();

    sema_init(&lock, 1);
    ret = misc_register(&pwm_misc_dev);
    if(ret < 0) {
        gpio_free(BUZZER_PMW_GPIO);
        pwm_free(pwm4buzzer);
        misc_deregister(&pwm_misc_dev);
    }

    printk(KERN_EMERG "	initialized
");

    return ret;
}

static void __exit iTop4412_pwm_dev_exit(void)
{
    gpio_free(BUZZER_PMW_GPIO);
    pwm_free(pwm4buzzer);
    misc_deregister(&pwm_misc_dev);
    
    printk(KERN_EMERG "	exit
");
    return;
}

module_init(iTop4412_pwm_dev_init);
module_exit(iTop4412_pwm_dev_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Chen Tuo");
MODULE_DESCRIPTION("Exynos4 PWM Driver");
my_pwm3.c

my_pwm3_app.c

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

#define PWM2_NAME "/dev/my_pwm3_dev"

#define PWM_MAGIC 'p'
#define PWM_MAX_NR 3

#define PWM_IOCTL_STOP      _IO(PWM_MAGIC, 0)
#define PWM_IOCTL_SET_FREQ  _IO(PWM_MAGIC, 1)
#define PWM_IOCTL_SET_DUTY  _IO(PWM_MAGIC, 2)

int fd = -1;

void open_pwm1(void);
void close_pwm1(void);
void set_pwm_freq(int freq);
void set_pwm_duty(int duty);
void stop_pwm(void);

void open_pwm1(void)
{
    fd = open(PWM2_NAME, O_RDWR);
    if(fd < 0) {
        perror("open pwm1 device");
        exit(1);
    }

//    atexit(close_pwm1);
}

void close_pwm1(void)
{
    if(fd >= 0) {
        ioctl(fd, PWM_IOCTL_STOP);
        close(fd);
        fd = -1;
    }
}

void set_pwm_freq(int freq)
{
    int ret = ioctl(fd, PWM_IOCTL_SET_FREQ, &freq);
    if(ret < 0) {
        perror("set the frequency of the buzzer");
        exit(1);
    }
}

void set_pwm_duty(int duty)
{
    int ret = ioctl(fd, PWM_IOCTL_SET_DUTY, &duty);
    if(ret < 0) {
        perror("set the duty of the pwm");
        exit(1);
    }
}

void stop_pwm(void)
{
    int ret = ioctl(fd, PWM_IOCTL_STOP);
    if(ret < 0) {
        perror("Stop the buzzer");
        exit(1);
    }
}

int main(int argc, char *argv[])
{
    int freq = 1000;

    open_pwm1();
    stop_pwm();
    if(argc < 3) {
        printf("usage:%s [cmd] [arg]
", argv[0]);
        printf("	stop:%s [0] [0] 
",argv[0]);
        printf("	set freq:%s [1] [arg]
", argv[0]);
        printf("	set duty:%s [2] [arg]
", argv[0]);
    }
    switch(atoi(argv[1]))
    {
    case 2:
        set_pwm_duty(atoi(argv[2]));
        break;
    case 1:
        set_pwm_freq(atoi(argv[2]));
        break;
    case 0:
    default:
        stop_pwm();
        return -1;
    }

    return 0;
}
my_pwm3_app.c

Makefile

TARGET_NAME = my_pwm3
#TARGET_NAME = example_pwm
APP1_NAME = my_pwm3_app
#APP2_NAME = open_atomic_int_two
obj-m += $(TARGET_NAME).o

KDIR := /home/topeet/chen/kernel-3.0/iTop4412_Kernel_3.0

PWD ?= $(shell pwd)

all:app1
        make -C $(KDIR) M=$(PWD) modules
app1:
        arm-none-linux-gnueabi-gcc $(APP1_NAME).c -o $(APP1_NAME) -static
#app2:
#       arm-none-linux-gnueabi-gcc $(APP2_NAME).c -o $(APP2_NAME) -static

clean:
        rm -rf *.o *.ko *.mod.c *.symvers *.order 
        .$(TARGET_NAME)* $(APP1_NAME) $(APP2_NAME)
Makfile

总结:内核接收ioctl的信息时需要使用特定的函数进行保护,防止被乱七八糟的传入数据。

原文地址:https://www.cnblogs.com/ch122633/p/9602679.html