这是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\n", 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\n", 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\n", 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\n", 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 "\tinitialized\n"); 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 "\texit\n"); 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");