Mni2440 linux PWM 驅動代碼修改支援 頻率,占空比修改–XiaoLin.Peng

來源:互聯網
上載者:User

     作者:XiaoLin.Peng

     歡迎交流 196568501

 #include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>

#include <asm/irq.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <plat/regs-timer.h>
#include <mach/regs-irq.h>
#include <asm/mach/time.h>
#include <linux/clk.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/miscdevice.h>

#define DEVICE_NAME     "pwm"

#define PWM_IOCTL_SET_FREQ        1
#define PWM_IOCTL_STOP            0

static struct semaphore lock;

/* freq:  pclk/50/16/65536 ~ pclk/50/16
  * if pclk = 50MHz, freq is 1Hz to 62500Hz
  * human ear : 20Hz~ 20000Hz
  */
static void PWM_Set_Freq_Duty( unsigned long freq,unsigned long duty)
{
    unsigned long tcon;
    unsigned long tcnt;
    unsigned long tcfg1;
    unsigned long tcfg0;

    //for test added byXiaolin.Peng
    unsigned long TCNTB_saver = 0;
    unsigned long TCMPB_saver = 0;
    
    struct clk *clk_p;
    unsigned long pclk;

    //for test  added by Xiaolin.Peng
    printk("freq: %ld\n", freq);

    //set GPB0 as tout0, pwm output
    s3c2410_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPB0_TOUT0);

    tcon = __raw_readl(S3C2410_TCON);
    tcfg1 = __raw_readl(S3C2410_TCFG1);
    tcfg0 = __raw_readl(S3C2410_TCFG0);

    //prescaler = 50
    tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK;
    tcfg0 |= (50 - 1);

    //mux = 1/16
    tcfg1 &= ~S3C2410_TCFG1_MUX0_MASK;
    tcfg1 |= S3C2410_TCFG1_MUX0_DIV16;

    __raw_writel(tcfg1, S3C2410_TCFG1);
    __raw_writel(tcfg0, S3C2410_TCFG0);

    clk_p = clk_get(NULL, "pclk");
    pclk  = clk_get_rate(clk_p);
    tcnt  = (pclk/(tcfg0+1)/16)/freq;
    
    __raw_writel(tcnt, S3C2410_TCNTB(0));
    __raw_writel((tcnt*duty)/100, S3C2410_TCMPB(0));

    //for test add by Xiaolin.Peng
    TCNTB_saver = __raw_readl(S3C2410_TCNTB(0));
    TCMPB_saver = __raw_readl(S3C2410_TCMPB(0));
    printk("TCNTB: %ld\n", TCNTB_saver);
    printk("TCMPB: %ld\n", TCMPB_saver);    
    
    tcon &= ~0x1f;
    tcon |= 0xb;        //disable deadzone, auto-reload, inv-off, update TCNTB0&TCMPB0, start timer 0
    __raw_writel(tcon, S3C2410_TCON);
    
    tcon &= ~2;            //clear manual update bit
    __raw_writel(tcon, S3C2410_TCON);
}

static void PWM_Stop(void)
{
    s3c2410_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPIO_OUTPUT);
    s3c2410_gpio_setpin(S3C2410_GPB(0), 0);
}

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

static int s3c24xx_pwm_close(struct inode *inode, struct file *file)
{
    PWM_Stop();
    up(&lock);
    return 0;
}
//cmd =1,open pwm function. =  0, close pwm function
//pwm frquency = (arg & 0xff00)>>8,
//pwm duty = (arm & 0x00ff)
//
static int s3c24xx_pwm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
    printk("ioctl pwm: %d %ld\n", cmd, arg);
    switch (cmd) {
    case PWM_IOCTL_SET_FREQ:
        if (arg == 0)
            return -EINVAL;
        PWM_Set_Freq_Duty((arg>>8),(arg&0xff));
        break;

    case PWM_IOCTL_STOP:
        PWM_Stop();
        break;
    }

    return 0;
}

static struct file_operations dev_fops = {
    .owner   =   THIS_MODULE,
    .open    =   s3c24xx_pwm_open,
    .release =   s3c24xx_pwm_close,
    .ioctl   =   s3c24xx_pwm_ioctl,
};

static struct miscdevice misc = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = DEVICE_NAME,
    .fops = &dev_fops,
};

static int __init dev_init(void)
{
    int ret;

    init_MUTEX(&lock);//init semaphore
    ret = misc_register(&misc);

    printk (DEVICE_NAME"\tinitialized\n");

    return ret;
}

static void __exit dev_exit(void)
{
    misc_deregister(&misc);
}

module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("FriendlyARM Inc.");
MODULE_DESCRIPTION("S3C2410/S3C2440 PWM Driver");

下面是用於測試驅動的代碼:

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

int main(int argc, char **argv)
{
    int on = 1;
        unsigned long frq_duty = 0;;
    int fd;

    fprintf(stderr, "PWM APP starting...\n");

    fd = open("/dev/pwm", 0);
    if (fd < 0) {
        fprintf(stderr, "error:open device pwm failed\n    ");
        exit(1);
    }
    else {
        fprintf(stderr, "PWM devie open success\n");
    }
        frq_duty = ((200<<8)|80);
    ioctl(fd, on, frq_duty);
        while(1);
    close(fd);
    return 0;
}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.