pwm

pwm_dev.c:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include "pwm.h"

struct resource pwm_dev_resource[] = {
[0]={
.start = PWM_TCFG,
.end = PWM_TCFG + S_T36 - 1,
.flags = IORESOURCE_MEM,
},
};
static void pwm_release(struct device *dev)
{

}

struct platform_device pwm_plat_dev ={
.name = "s5pc_pwm",
.id = -1,
.num_resources = ARRAY_SIZE(pwm_dev_resource),
.resource = pwm_dev_resource,
.dev = {
.release = pwm_release,
},
};


static int __init pwm_dev_init(void)
{
platform_device_register(&pwm_plat_dev);
return 0;
}

static void __exit pwm_dev_exit(void)
{
platform_device_unregister(&pwm_plat_dev);
}

module_init(pwm_dev_init);
module_exit(pwm_dev_exit);
MODULE_LICENSE("GPL");

 

 

pwm_drv.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h> //file_operations
#include <linux/device.h> //class_create device_create
#include <linux/cdev.h> //Struct cdev
#include <linux/slab.h> //kmalloc
#include <asm/io.h> //ioremap,writel,readl
#include <asm/uaccess.h> //copy_from_user
#include <asm-generic/poll.h>
#include <linux/sched.h>
#include <linux/platform_device.h>
#include "pwm.h"

#define PWM_DENO 252

struct pwm_device {
unsigned int pwm_major;
struct cdev *pwm_cdev;
struct class *pwm_class;
struct device *pwm_device;
void __iomem *pwm_base;
void __iomem *pwm_gdpcon;
dev_t devno;
};

struct pwm_device *pwm_dev = NULL;


static int pwm_open(struct inode *inode, struct file *file)
{
writel(readl(pwm_dev->pwm_gdpcon) & (~(0xf<<4)), pwm_dev->pwm_gdpcon);
writel(readl(pwm_dev->pwm_gdpcon) | ((0x2<<4)), pwm_dev->pwm_gdpcon);

writel(readl(pwm_dev->pwm_base + PWM_TCFG0) & (~(0xff<<0)), pwm_dev->pwm_base + PWM_TCFG0);
writel(readl(pwm_dev->pwm_base + PWM_TCFG0) | (249<<0), pwm_dev->pwm_base + PWM_TCFG0);

writel(readl(pwm_dev->pwm_base + PWM_TCFG1) & (~(0xf<<4)), pwm_dev->pwm_base + PWM_TCFG1);
writel(readl(pwm_dev->pwm_base + PWM_TCFG1) | (0x4<<4), pwm_dev->pwm_base + PWM_TCFG1);

return 0;
}
static ssize_t pwm_write(struct file *file, const char __user *user_buf, size_t size, loff_t *offset)
{
char buf[10];
unsigned length = size;

if(copy_from_user(buf, user_buf, length))
{
return -EINVAL;
}else{
writel(6666, pwm_dev->pwm_base + PWM_TCNTB1);
writel(3456, pwm_dev->pwm_base + PWM_TCMPB1);

writel(readl(pwm_dev->pwm_base + PWM_TCON) | (0xf<<8), pwm_dev->pwm_base + PWM_TCON);
writel(readl(pwm_dev->pwm_base + PWM_TCON) & (~(0x1<<9)), pwm_dev->pwm_base + PWM_TCON);
}
return length;
}

static int pwm_close(struct inode *inode, struct file *file)
{
writel(readl(pwm_dev->pwm_base + PWM_TCON) | (0xf<<8), pwm_dev->pwm_base + PWM_TCON);
writel(readl(pwm_dev->pwm_gdpcon) & (~(0xf<<4)), pwm_dev->pwm_gdpcon);
return 0;
}


struct file_operations pwm_fops = {
.owner = THIS_MODULE,
.open = pwm_open,
.write = pwm_write,
.release = pwm_close,
};


static int pwm_drv_probe(struct platform_device *pdev)
{
int ret;
struct resource *res;
pwm_dev = kmalloc(sizeof(struct pwm_device), GFP_KERNEL);
if(pwm_dev == NULL)
{
printk(KERN_INFO "pwm_dev kmalloc failed!\n");
ret = -EINVAL;
}

res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

if(PWM_DENO){
pwm_dev->devno = MKDEV(PWM_DENO, 0);
ret = register_chrdev_region(pwm_dev->devno, 1, "pwm_dev");
if(ret < 0){
printk(KERN_INFO "pwm_dev->devno register_chrdev_region failed!\n");
ret = -EINVAL;
goto output0;
}
}else{
ret = alloc_chrdev_region(&pwm_dev->devno, 252, 1, "pwm_dev");
if(ret < 0){
printk(KERN_INFO "pwm_dev->devno register_chrdev_region failed!\n");
ret = -EINVAL;
goto output0;
}
}


pwm_dev->pwm_base = ioremap(res->start, res->end - res->start +1);
if(pwm_dev->pwm_base == NULL)
{
printk(KERN_INFO"pwm_dev->pwm_base remap failed! \n");
ret = -EINVAL;
goto output1;
}

pwm_dev->pwm_cdev = cdev_alloc();
if(IS_ERR(&pwm_dev->pwm_cdev))
{
printk(KERN_INFO "pwm_dev->cdev alloc failed!\n");
ret = -EINVAL;
goto output2;
}
cdev_init(pwm_dev->pwm_cdev, &pwm_fops);
cdev_add(pwm_dev->pwm_cdev, pwm_dev->devno, 1);

pwm_dev->pwm_class = class_create(THIS_MODULE, "pwm_class");
if(IS_ERR(&pwm_dev->pwm_class))
{
printk(KERN_INFO"pwm_dev->pwm_class create failed!\n");
ret = -EINVAL;
goto output3;
}

pwm_dev->pwm_device = device_create(pwm_dev->pwm_class, NULL, pwm_dev->devno, NULL, "pwm");
if(IS_ERR(&pwm_dev->pwm_device))
{
printk(KERN_INFO"pwm_dev->pwm_device create failed!\n");
ret = -EINVAL;
goto output4;
}

pwm_dev->pwm_gdpcon = ioremap(PWM_GPDCON, 4);
if(!pwm_dev->pwm_gdpcon)
{
printk(KERN_INFO "tm_dev->pwm_GDPCON ioremap failed!\n");
ret = -EINVAL;
goto output5;
}
return 0;

output5:
device_destroy(pwm_dev->pwm_class, pwm_dev->devno);
output4:
class_destroy(pwm_dev->pwm_class);
output3:
cdev_del(pwm_dev->pwm_cdev);
output2:
iounmap(pwm_dev->pwm_base);
output1:
unregister_chrdev_region(pwm_dev->devno, 1);
output0:
kfree(pwm_dev);

return ret;
}

static int pwm_drv_remove(struct platform_device *pdev)
{
iounmap(pwm_dev->pwm_gdpcon);
device_destroy(pwm_dev->pwm_class, pwm_dev->devno);
class_destroy(pwm_dev->pwm_class);
cdev_del(pwm_dev->pwm_cdev);
iounmap(pwm_dev->pwm_base);
unregister_chrdev_region( pwm_dev->devno, 1);
kfree(pwm_dev);
return 0;
}


struct platform_driver plat_drv={
.probe = pwm_drv_probe,
.remove = pwm_drv_remove,
.driver = {
.owner = THIS_MODULE,
.name = "s5pc_pwm",
},
};


static int __init pwm_drv_init(void)
{
platform_driver_register(&plat_drv);
return 0;
}

static void __exit pwm_drv_exit(void)
{
platform_driver_unregister(&plat_drv);
}

module_init(pwm_drv_init);
module_exit(pwm_drv_exit);
MODULE_LICENSE("GPL");

 

 

pwm_test.c:


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>

int main(void)
{
int fd = 0;
int ret;
char buf[10];

fd = open("/dev/pwm", O_RDWR);
if(fd <= 0)
{
perror("open failed!\n");
exit(1);
}

printf("please input \"start\" or \"quit\"\n");
while(1)
{
memset(buf, 0, 10);
fgets(buf, 10, stdin);
if(strncmp(buf, "start", 5) == 0){
if(write(fd, buf, 10)!=10)
{
perror("write failed!\n");
exit(1);
}
}else{
break;
}
}

close(fd);
return 0;
}

 

 

 

makefile:

ifeq ($(KERNELRELEASE),)
KERNELDIR ?=/home/farsight/Linux_source/linux-2.6.35.5
PWD :=$(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
arm-unknown-linux-gnueabi-gcc -o pwm_test pwm_test.c
cp pwm_drv.ko pwm_dev.ko pwm_test /opt/rootfs/s5pc100_drv
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
rm -rf pwm_test *.o *~core *.ko *.mod.c .tmp_versions Module.symvers modules.order
else
obj-m :=pwm_drv.o pwm_dev.o
endif

 

pwm.h:

#ifndef __PWM_H_
#define __PWM_H_

#define PWM_GPDCON 0xE0300080
#define PWM_TCFG 0xEA000000
#define PWM_TCFG0 0x0
#define PWM_TCFG1 0x4
#define PWM_TCON 0x8
#define PWM_TCNTB1 0x18
#define PWM_TCMPB1 0x1C
#define PWM_TCNTO1 0x20
#define S_T36 0x24
#define PWM_MAJOR 251

#endif

 

posted on 2013-12-26 22:02  weat  阅读(379)  评论(0编辑  收藏  举报