求大神指导,AT91SAM9G45的PWM驱动,整了一天了,还没有找到问题的关键

头文件:

#ifndef AT91_PWM_H
#define AT91_PWM_H

#define PWMC_BASE 0xfffb8000

/****************  pwm模式寄存器偏移0x00  *****************/
#define PWM_MR_OFF              0x00000000    ///< PWM Mode Register offset.
#define PWM_MR     (*((volatile unsigned long *)(PWMC_BASE + PWM_MR_OFF))) ///< PWM Mode Register.
#define PWM_MR_DIVA_MASK        0x000000FF    ///< PWM Mode Divide factor A Mask.
#define PWM_MR_DIVA_SHIFT       0             ///< PWM Mode Divide factor A LSB.
#define PWM_MR_DIVB_MASK        0x00FF0000    ///< PWM Mode Divide factor B Mask.
#define PWM_MR_DIVB_SHIFT       16            ///< PWM Mode Divide factor B LSB.

#define PWM_MR_PREA_MASK        0x00000F00    ///< PWM Mode prescaler A Mask.
#define PWM_MR_PREA_SHIFT       8             ///< PWM Mode prescaler A LSB.
#define PWM_MR_PREB_MASK        0x0F000000    ///< PWM Mode prescaler B Mask.
#define PWM_MR_PREB_SHIFT       24            ///< PWM Mode prescaler B LSB.

#define PWM_MR_PRE_MCK          0             ///< PWM Mode prescaler set to MCK.
#define PWM_MR_PRE_MCK_DIV2     1             ///< PWM Mode prescaler set to MCK/2.
#define PWM_MR_PRE_MCK_DIV4     2             ///< PWM Mode prescaler set to MCK/4.
#define PWM_MR_PRE_MCK_DIV8     3             ///< PWM Mode prescaler set to MCK/8.
#define PWM_MR_PRE_MCK_DIV16    4             ///< PWM Mode prescaler set to MCK/16.
#define PWM_MR_PRE_MCK_DIV32    5             ///< PWM Mode prescaler set to MCK/32.
#define PWM_MR_PRE_MCK_DIV64    6             ///< PWM Mode prescaler set to MCK/64.
#define PWM_MR_PRE_MCK_DIV128   7             ///< PWM Mode prescaler set to MCK/128.
#define PWM_MR_PRE_MCK_DIV256   8             ///< PWM Mode prescaler set to MCK/256.
#define PWM_MR_PRE_MCK_DIV512   9             ///< PWM Mode prescaler set to MCK/512.
#define PWM_MR_PRE_MCK_DIV1024  10            ///< PWM Mode prescaler set to MCK/1024.

#define PWM_CHID_MASK           0x0000000F
#define PWM_CHID0               0
#define PWM_CHID1               1
#define PWM_CHID2               2
#define PWM_CHID3               3

/***********************  pwm使能寄存器偏移0x04  *****************/
#define PWM_ENA_OFF             0x00000004    ///< PWM Enable Register offset.
#define PWM_ENA     (*((volatile unsigned long *)(PWMC_BASE + PWM_ENA_OFF))) ///< PWM Enable Register.


/***********************  pwm去使能寄存器0x08  *****************/
#define PWM_DIS_OFF             0x00000008    ///< PWM Disable Register offset.
#define PWM_DIS     (*((volatile unsigned long *)(PWMC_BASE + PWM_DIS_OFF))) ///< PWM Disable Register.

/*********************  pwm状态寄存器0x0C  *****************/
#define PWM_SR_OFF              0x0000000C    ///< PWM Status Register offset.
#define PWM_SR      (*((volatile unsigned long *)(PWMC_BASE + PWM_SR_OFF)))  ///< PWM Status Register.

/**********************  pwm中断使能寄存器0x10 *****************/
#define PWM_IER_OFF             0x00000010    ///< PWM Interrupt Enable Register offset.
#define PWM_IER     (*((volatile unsigned long *)(PWMC_BASE + PWM_IER_OFF))) ///< PWM Interrupt Enable Register.

/**********************  pwm中断去使能寄存器0x14  *****************/
#define PWM_IDR_OFF             0x00000014    ///< PWM Interrupt Disable Register offset.
#define PWM_IDR     (*((volatile unsigned long *)(PWMC_BASE + PWM_IDR_OFF))) ///< PWM Interrupt Disable Register.


/**********************  pwm中断掩码寄存器0x18  *****************/
#define PWM_IMR_OFF             0x00000018    ///< PWM Interrupt Mask Register offset.
#define PWM_IMR     (*((volatile unsigned long *)(PWMC_BASE + PWM_IMR_OFF))) ///< PWM Interrupt Mask Register.

/**********************  pwm中断状态寄存器0x1c  *****************/
#define PWM_ISR_OFF             0x0000001C    ///< PWM Interrupt Status Register offset.
#define PWM_ISR     (*((volatile unsigned long *)(PWMC_BASE + PWM_ISR_OFF))) ///< PWM Interrupt Status Register.

/**********************  pwm通道模式寄存器 0x200+ch_num*0x20+0x00  *****************/
#define PWM_CH0_OFF             0x00000200    ///< PWM Channel 0 registers offset.
#define PWM_CH1_OFF             0x00000220    ///< PWM Channel 1 registers offset.
#define PWM_CH2_OFF             0x00000240    ///< PWM Channel 2 registers offset.
#define PWM_CH3_OFF             0x00000260    ///< PWM Channel 3 registers offset.

#define PWM_CMR_OFF             0x00000000    ///< PWM Channel Mode Register offset.
#define PWM_CMR0    (*((volatile unsigned long *)(PWMC_BASE + PWM_CMR_OFF + PWM_CH0_OFF))) ///< PWM Channel 0 Mode Register.
#define PWM_CMR1    (*((volatile unsigned long *)(PWMC_BASE + PWM_CMR_OFF + PWM_CH1_OFF))) ///< PWM Channel 1 Mode Register.
#define PWM_CMR2    (*((volatile unsigned long *)(PWMC_BASE + PWM_CMR_OFF + PWM_CH2_OFF))) ///< PWM Channel 2 Mode Register.
#define PWM_CMR3    (*((volatile unsigned long *)(PWMC_BASE + PWM_CMR_OFF + PWM_CH3_OFF))) ///< PWM Channel 3 Mode Register.



#define PWM_CPRE_MCK_MASK       0x0000000F    ///< PWM Mode prescaler mask.
#define PWM_CPRE_MCK            0             ///< PWM Mode prescaler set to MCK.
#define PWM_CPRE_MCK_DIV2       1             ///< PWM Mode prescaler set to MCK/2.
#define PWM_CPRE_MCK_DIV4       2             ///< PWM Mode prescaler set to MCK/4.
#define PWM_CPRE_MCK_DIV8       3             ///< PWM Mode prescaler set to MCK/8.
#define PWM_CPRE_MCK_DIV16      4             ///< PWM Mode prescaler set to MCK/16.
#define PWM_CPRE_MCK_DIV32      5             ///< PWM Mode prescaler set to MCK/32.
#define PWM_CPRE_MCK_DIV64      6             ///< PWM Mode prescaler set to MCK/64.
#define PWM_CPRE_MCK_DIV128     7             ///< PWM Mode prescaler set to MCK/128.
#define PWM_CPRE_MCK_DIV256     8             ///< PWM Mode prescaler set to MCK/256.
#define PWM_CPRE_MCK_DIV512     9             ///< PWM Mode prescaler set to MCK/512.
#define PWM_CPRE_MCK_DIV1024    10            ///< PWM Mode prescaler set to MCK/1024.
#define PWM_CPRE_CLKA           11            ///< PWM Mode prescaler set to CLKA.
#define PWM_CPRE_CLKB           12            ///< PWM Mode prescaler set to CLKB.
#define PWM_CALG                8             ///< PWM Mode channel alignment.
#define PWM_CPOL                9             ///< PWM Mode channel polarity.
#define PWM_CPD                 10            ///< PWM Mode channel update period.


#define PWM_CDTY_OFF            0x00000004    ///< PWM Channel Duty Cycle Register offset.
#define PWM_CDTY0   (*((volatile unsigned long *)(PWMC_BASE + PWM_CDTY_OFF + PWM_CH0_OFF))) ///< PWM Channel 0 Duty Cycle Register.
#define PWM_CDTY1   (*((volatile unsigned long *)(PWMC_BASE + PWM_CDTY_OFF + PWM_CH1_OFF))) ///< PWM Channel 1 Duty Cycle Register.
#define PWM_CDTY2   (*((volatile unsigned long *)(PWMC_BASE + PWM_CDTY_OFF + PWM_CH2_OFF))) ///< PWM Channel 2 Duty Cycle Register.
#define PWM_CDTY3   (*((volatile unsigned long *)(PWMC_BASE + PWM_CDTY_OFF + PWM_CH3_OFF))) ///< PWM Channel 3 Duty Cycle Register.

#define PWM_CPRD_OFF            0x00000008    ///< PWM Channel Period Register offset.
#define PWM_CPRD0   (*((volatile unsigned long *)(PWMC_BASE + PWM_CPRD_OFF + PWM_CH0_OFF))) ///< PWM Channel 0 Period Register.
#define PWM_CPRD1   (*((volatile unsigned long *)(PWMC_BASE + PWM_CPRD_OFF + PWM_CH1_OFF))) ///< PWM Channel 1 Period Register.
#define PWM_CPRD2   (*((volatile unsigned long *)(PWMC_BASE + PWM_CPRD_OFF + PWM_CH2_OFF))) ///< PWM Channel 2 Period Register.
#define PWM_CPRD3   (*((volatile unsigned long *)(PWMC_BASE + PWM_CPRD_OFF + PWM_CH3_OFF))) ///< PWM Channel 3 Period Register.

#define PWM_CCNT_OFF            0x0000000C    ///< PWM Channel Counter Register offset.
#define PWM_CCNT0   (*((volatile unsigned long *)(PWMC_BASE + PWM_CCNT_OFF + PWM_CH0_OFF))) ///< PWM Channel 0 Counter Register.00204
#define PWM_CCNT1   (*((volatile unsigned long *)(PWMC_BASE + PWM_CCNT_OFF + PWM_CH1_OFF))) ///< PWM Channel 1 Counter Register.
#define PWM_CCNT2   (*((volatile unsigned long *)(PWMC_BASE + PWM_CCNT_OFF + PWM_CH2_OFF))) ///< PWM Channel 2 Counter Register.
#define PWM_CCNT3   (*((volatile unsigned long *)(PWMC_BASE + PWM_CCNT_OFF + PWM_CH3_OFF))) ///< PWM Channel 3 Counter Register.

#define PWM_CUPD_OFF            0x00000010    ///< PWM Channel Update Register offset.
#define PWM_CUPD0   (*((volatile unsigned long *)(PWMC_BASE + PWM_CUPD_OFF + PWM_CH0_OFF))) ///< PWM Channel 0 Update Register.
#define PWM_CUPD1   (*((volatile unsigned long *)(PWMC_BASE + PWM_CUPD_OFF + PWM_CH1_OFF))) ///< PWM Channel 1 Update Register.
#define PWM_CUPD2   (*((volatile unsigned long *)(PWMC_BASE + PWM_CUPD_OFF + PWM_CH2_OFF))) ///< PWM Channel 2 Update Register.
#define PWM_CUPD3   (*((volatile unsigned long *)(PWMC_BASE + PWM_CUPD_OFF + PWM_CH3_OFF))) ///< PWM Channel 3 Update Register.

extern void PWMC_ConfigureChannel( 
    unsigned char channel, 
    unsigned int prescaler, 
    unsigned int alignment, 
    unsigned int polarity); 
 
extern void PWMC_ConfigureClocks 
    (unsigned int clka, 
     unsigned int clkb, 
     unsigned int mck); 
 
void PWMC_SetPeriod(unsigned char channel, unsigned short period); 
void PWMC_SetDutyCycle(unsigned char channel, unsigned short duty); 
void PWMC_EnableChannel(unsigned char channel); 
void PWMC_DisableChannel(unsigned char channel); 
void PWMC_EnableChannelIt(unsigned char channel); 
void PWMC_DisableChannelIt(unsigned char channel); 
unsigned short FindClockConfiguration(unsigned int frequency, unsigned int mck);

#define trace_DEBUG                     0 
#define trace_INFO                      1 
#define trace_WARNING                   2 
#define trace_ERROR                     3 
#define trace_FATAL                     4 
#define trace_LEVEL                     0 

#define trace_CONFIGURE(mode, baudrate, mck) { \
        const Pin pinsDbgu[] = {PINS_DBGU}; \
        PIO_Configure(pinsDbgu, PIO_LISTSIZE(pinsDbgu)); \
        DBGU_Configure(mode, baudrate, mck); \
    } 

#define trace_LOG(level, ...) { \
        if (level >= trace_LEVEL) { \
            printk(__VA_ARGS__); \
        } \
    } 


#define ASSERT(condition, ...)  { \
        if (!(condition)) { \
            printk(__VA_ARGS__); \
            while (1); \
        } \
    } 
	
#define SANITY_ERROR            "Sanity check failed at %s:%d\n\r" 
#define SANITY_CHECK(condition) ASSERT(condition, SANITY_ERROR, __FILE__, __LINE__) 


typedef struct {
	int pwm_freq;		//frequency in Hz
	int pwm_duty;		//duty cycle in percent. ex. 50 is 50% 
	int pwm_pulse;		//1 for PWM positive pulse, 0 for negative pulse
} at91_pwm_arg;


#endif /* AT91_PWM_H */

相关函数文件:

#include "at91_pwm.h"  


/// PWM frequency in Hz.   
#define PWM_FREQUENCY               20   
   
/// Maximum duty cycle value.   
#define MAX_DUTY_CYCLE              50   
#define MIN_DUTY_CYCLE              0   
   
#define BOARD_MCK               (102400000) //100 MHz  

#define at91_pwm_read(reg)                  __raw_readl(reg)   
#define at91_pwm_write(reg, val)            __raw_writel((val), reg)
//------------------------------------------------------------------------------   
/// Finds a prescaler/divisor couple to generate the desired frequency from   
/// MCK.   
/// Returns the value to enter in PWMC_MR or 0 if the configuration cannot be   
/// met.   
/// \param frequency  Desired frequency in Hz.   
/// \param mck  Master clock frequency in Hz.   
//------------------------------------------------------------------------------ 
unsigned short FindClockConfiguration(unsigned int frequency, unsigned int mck)   
{   
    unsigned int divisors[11] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};   
    unsigned char divisor = 0;   
    unsigned int prescaler;   
   
    //if (frequency < mck)
	if (frequency < mck)
	{
		printk("frequency set error!\n");
		return 0;
	}
   
    // Find prescaler and divisor values   
    prescaler = (mck / divisors[divisor]) / frequency;   
    while ((prescaler > 255) && (divisor < 11))
	{   
        divisor++;   
        prescaler = (mck / divisors[divisor]) / frequency;   
    }   
   
    // Return result   
    if (divisor < 11) 
	{   
        printk(trace_DEBUG, "-D- Found divisor=%d and prescaler=%d for freq=%dHz\n\r",divisors[divisor], prescaler, frequency);   
        return prescaler | (divisor << 8); 
    }   
    else 
	{   
        return 0;   
    }   
}   
//------------------------------------------------------------------------------   
//         Global functions   
//------------------------------------------------------------------------------   
   
//------------------------------------------------------------------------------   
/// Configures PWM a channel with the given parameters.   
/// The PWM controller must have been clocked in the PMC prior to calling this   
/// function.   
/// \param channel  Channel number.   
/// \param prescaler  Channel prescaler.   
/// \param alignment  Channel alignment.   
/// \param polarity  Channel polarity.   
//------------------------------------------------------------------------------   
void PWMC_ConfigureChannel(   
    unsigned char channel,   
    unsigned int prescaler,   
    unsigned int alignment,   
    unsigned int polarity)   
{   
#if 0
    SANITY_CHECK(prescaler < PWM_CPRE_CLKB);   
    SANITY_CHECK((alignment & ~(1 << PWM_CALG)) == 0);   
    SANITY_CHECK((polarity & ~(1<<PWM_CPOL)) == 0);   
 #endif
	
	//if (prescaler > PWM_CPRE_CLKB)
	if (prescaler > PWM_CPRE_CLKB)
	{
		printk("PWMC_ConfigureChannel: prescaler > AT91C_PWMC_CPRE_MCKB\n");   
        return;
	}
	if (alignment & ~(1 << PWM_CALG))
	{
        printk("PWMC_ConfigureChannel: (alignment & ~AT91C_PWMC_CALG) != 0\n");   
        return;   
	}
	if (polarity & ~(1<<PWM_CPOL))
	{
        printk("PWMC_ConfigureChannel: (polarity & ~AT91C_PWMC_CPOL) != 0\n");   
        return;   
	}
    // Disable channel   
    //PWM_DIS |= (1 << channel);
	at91_pwm_write(PWM_DIS, (1 << channel));
   
    // Configure channel   
    //PWM_CMR0 = prescaler | alignment | polarity;  
	at91_pwm_write(PWM_CMR0, prescaler | alignment | polarity); 
}   
   
//------------------------------------------------------------------------------   
/// Configures PWM clocks A & B to run at the given frequencies. This function   
/// finds the best MCK divisor and prescaler values automatically.   
/// \param clka  Desired clock A frequency (0 if not used).   
/// \param clkb  Desired clock B frequency (0 if not used).   
/// \param mck  Master clock frequency.   
//------------------------------------------------------------------------------   
void PWMC_ConfigureClocks(unsigned int clka, unsigned int clkb, unsigned int mck)   
{   
    unsigned int mode = 0;   
    unsigned int result;   
   
#if 0	
    // Clock A   
    if (clka != 0) 
	{   
        result = FindClockConfiguration(clka, mck);   
        ASSERT(result != 0, "-F- Could not generated the desired PWM frequency (%dHz)\n\r", clka);   
        mode |= result;   
    }   
   
    // Clock B   
    if (clkb != 0) 
	{   
        result = FindClockConfiguration(clkb, mck);   
        ASSERT(result != 0, "-F- Could not generated the desired PWM frequency (%dHz)\n\r", clkb);   
        mode |= (result << 16);   
    }   
    // Configure clocks   
    trace_LOG(trace_DEBUG, "-D- Setting PWMC_MR = 0x%08X\n\r", mode);   
    //PWM_MR = mode;   
#endif 	

	mode = 0xA2; //CLKA = BOARD_MCK/1024/2 = 50K Hz 
	// Configure clocks   
	printk("-D- Setting PWMC_MR = 0x%08X\n\r", mode);  
	at91_pwm_write(PWM_MR, mode); 
}   
   
//------------------------------------------------------------------------------   
/// Sets the period value used by a PWM channel. This function writes directly   
/// to the CPRD register if the channel is disabled; otherwise, it uses the   
/// update register CUPD.   
/// \param channel  Channel number.   
/// \param period  Period value.   
//------------------------------------------------------------------------------   
void PWMC_SetPeriod(unsigned char channel, unsigned short period)   
{   
	int ret;
	
	ret = at91_pwm_read(PWM_SR);
    // If channel is disabled, write to CPRD   
    if ((ret & (1 << channel)) == 0) 
	{      
        //PWM_CPRD0 = period;  
		at91_pwm_write(PWM_CPRD0, period);
    }   
    // Otherwise use update register   
    else 
	{   
        //PWM_CMR0 |= (1 << PWM_CPD);   
        //PWM_CUPD0 = period; 
		ret = at91_pwm_read(PWM_CMR0);   
        ret |= PWM_CPD;   
        at91_pwm_write(PWM_CMR0, ret);   
        at91_pwm_write(PWM_CUPD0, period);	
    }   
}   
   
//------------------------------------------------------------------------------   
/// Sets the duty cycle used by a PWM channel. This function writes directly to   
/// the CDTY register if the channel is disabled; otherwise it uses the   
/// update register CUPD.   
/// Note that the duty cycle must always be inferior or equal to the channel   
/// period.   
/// \param channel  Channel number.   
/// \param duty  Duty cycle value.   
//------------------------------------------------------------------------------   
void PWMC_SetDutyCycle(unsigned char channel, unsigned short duty)   
{   
    //SANITY_CHECK(duty <= PWM_CPRD0);
	int ret;
	
	ret = at91_pwm_read(PWM_CPRD0);
	if (duty > ret)
	{
		printk("SANITY_CHECK(duty[%x] = AT91C_BASE_PWMC->PWMC_CH[%d].PWMC_CPRDR[%x])\n", duty, channel, ret);   
        return;
	}
	
    //ASSERT(duty > 0, "-F- Duty cycle value 0 is not permitted on SAM7S chips.\n\r");   
	
		
    //ASSERT((duty > 1) || (PWM_CMR0 & (1 << PWM_CALG)), "-F- Duty cycle value 1 is not permitted in left-aligned mode on SAM7S chips.\n\r");   

   
    // If channel is disabled, write to CDTY 
	ret = at91_pwm_read(PWM_SR);
    if ((ret & (1 << channel)) == 0) 
	{   
        //PWM_CDTY0 = duty;  
		at91_pwm_write(PWM_CDTY0, duty);
    }   
    // Otherwise use update register   
    else 
	{   
        //PWM_CMR0 &= ~(1 << PWM_CPD);   
        //PWM_CUPD0 = duty; 
		ret = at91_pwm_read(PWM_CMR0);
		ret &= ~(1 << PWM_CPD);
		at91_pwm_write(PWM_CMR0, ret);
		at91_pwm_write(PWM_CUPD0, duty);
    }   
}   
   
//------------------------------------------------------------------------------   
/// Enables the given PWM channel. This does NOT enable the corresponding pin;   
/// this must be done in the user code.   
/// \param channel  Channel number.   
//------------------------------------------------------------------------------   
void PWMC_EnableChannel(unsigned char channel)   
{   
    //PWM_ENA |= 1 << channel;  
	at91_pwm_write(PWM_ENA, (1 << channel));
}   
   
//------------------------------------------------------------------------------   
/// Disables the given PWM channel.   
/// \param channel  Channel number.   
//------------------------------------------------------------------------------   
void PWMC_DisableChannel(unsigned char channel)   
{   
    //PWM_DIS |= 1 << channel; 
	at91_pwm_write(PWM_DIS, (1 << channel));	
}   
   
//------------------------------------------------------------------------------   
/// Enables the period interrupt for the given PWM channel.   
/// \param channel  Channel number.   
//------------------------------------------------------------------------------   
void PWMC_EnableChannelIt(unsigned char channel)   
{   
    //PWM_IER |= 1 << channel; 
	at91_pwm_write(PWM_IER, (1 << channel));
}   
   
//------------------------------------------------------------------------------   
/// Disables the period interrupt for the given PWM channel.   
/// \param channel  Channel number.   
//------------------------------------------------------------------------------   
void PWMC_DisableChannelIt(unsigned char channel)   
{   
    PWM_IDR |= 1 << channel;
	at91_pwm_write(PWM_IDR, (1 << channel));	
}   

pwm驱动文件;

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>		           /* everything... */
#include <linux/cdev.h>                /* cdev...*/
#include <linux/gpio.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include "at91_pwm.h"
#include "at91_pwm.c"
#include <mach/at91_pmc.h>

#define DEVICE_NAME "mypwm"

static int led_major = 0;
static int led_minor = 0;
struct cdev *led_device;


void PWMC_EnablePMC(void)   
{   
    at91_sys_write(AT91_PMC_PCER, (1 < AT91SAM9G45_ID_PWMC));   
}  

static int pwm_configure(int channel, at91_pwm_arg *config)   
{   
    int prescaler, period, duty;   
   
    if (config->pwm_freq  < 2 || config->pwm_freq > 100000) {   
        printk("PWM Frequency should be: 1Hz  freq  100KHz\n");   
        config->pwm_freq = 2;   
    }   
       
    prescaler = PWM_CPRE_MCK_DIV1024;   
    period = (BOARD_MCK/1024)/(config->pwm_freq); //100KHz   
   
    if (config->pwm_duty == 0)
	{   
        config->pwm_duty = 50;   
    }   
    //duty = at91_pwm.pwm_arg[channel].pwm_duty = (period * config->pwm_duty) / 100;   
	duty = (period * config->pwm_duty) / 100; 
	
    PWMC_ConfigureChannel(channel, prescaler, 0, 0);   
    PWMC_SetPeriod(channel, period);   
    PWMC_SetDutyCycle(channel, duty);   
       
    return 0;   
}  

   
static int pwm_start(int channel)   
{   
    PWMC_EnableChannelIt(channel);   
    PWMC_EnableChannel(channel);   
   
    return 0;   
}   
   
static int pwm_stop(int channel)   
{   
    PWMC_DisableChannelIt(channel);   
    PWMC_DisableChannel(channel);   
   
    return 0;   
}   
   
static int pwm_open(struct inode *inode,struct file *filp)  
{   
#if 0
    int minor = MINOR(inode->i_rdev);   
    
//  printk("pwm_open %d\n", minor);   
   
    if (minor >= PWM_MAX) {   
        return -1;   
    }   
//  printk("pwm_base%d = %x\n", minor, (unsigned int)at91_pwm.pwm_base);   
    filp->private_data = at91_pwm.pwm_base;   
#endif  
	//at91_set_B_periph(AT91_PIN_PD24, 1);	/* enable PWM0 */
	//at91_set_gpio_output(AT91_PIN_PD24, 0);	
	//at91_set_gpio_value(AT91_PIN_PD24, 1);
	
    PWMC_EnablePMC();   
    PWMC_ConfigureClocks(PWM_FREQUENCY * MAX_DUTY_CYCLE, 0, BOARD_MCK);   
   
    return 0;  
}  
  
static int pwm_ioctl( struct inode *inode, struct file *file,  
                unsigned int cmd, unsigned long arg)  
{   
    //int ch = MINOR(inode->i_rdev);
	int ch = 0;

	if (arg > 4)
	{
		return -1;
	}
#if 0   
    if (ch >= PWM_MAX) {   
        printk("pwm_ioctl ch %d, not exist!\n", ch);   
        return -1;   
    }   
//  printk("pwm_ioctl ch = %d\n", ch);   
#endif      
    
	switch (cmd) {   
    case 0:   
        pwm_start(ch);   
        break;   
    case 1:   
        pwm_stop(ch);   
        break;   
    case 2:   
        //at91_pwm.pwm_arg[ch] = *(at91_pwm_arg *)arg;   
        pwm_configure(ch, (at91_pwm_arg *)arg);   
        break;     
    default:   
        printk("pwm_ioctl cmd, Not Support!\n");   
        break;   
    }  
    return 0;  
}  

static struct file_operations pwm_fops = {  
    .open       = pwm_open,  
    .ioctl      = pwm_ioctl  
}; 


/****************************   pwm test  ***************************/
#if 0
static void PWM_Set_Freq(int arg)
{
	at91_set_gpio_output(AT91_PIN_PD15, 0);	//设置PD15为输出模式
	at91_set_gpio_value(AT91_PIN_PD15, 0);	//设置PD15输出为0,表示点亮
	at91_set_B_periph(AT91_PIN_PD24, 1);	/* enable PWM0 */

	
	PWMC_ConfigureChannel(0, 1, 2, 3);
	PWMC_ConfigureClocks(1000, 500, 10);
	PWMC_SetPeriod(0, 1);
	PWMC_SetDutyCycle(0, 50);
}

static void PWM_Stop(void)
{
	at91_set_gpio_output(AT91_PIN_PD24, 0);	
	at91_set_gpio_value(AT91_PIN_PD24, 1);

	return ;
}

		   
static int myled_open(struct inode *inode, struct file *filp)
{
	PWMC_EnableChannel(0);//这一步在测试驱动的时候总是报内存操作错误
	at91_set_B_periph(AT91_PIN_PD24, 1);/* enable PWM0 */

	return 0;
}

static int myled_release(struct inode *inode, struct file *filp)
{
	PWMC_DisableChannel(0); //这一步在测试驱动的时候总是报内存操作错误
	return 0;
}

static int myled_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
	if (arg > 4)
	{
		return -1;
	}
	
	switch (cmd)
	{
		case 0:
			if (arg == 0)
				return -1;
			PWM_Set_Freq(arg);
			break;
			//通过cmd命令控制PD15
		case 1:
			PWM_Stop();
			break;
	}
	return 0;
}

struct file_operations led_fops = 
{
	.owner =    THIS_MODULE,
	.open =     myled_open,
	.release =  myled_release,
	.ioctl = myled_ioctl,
};
#endif 

static void __exit my_led_exit(void)
{
    dev_t devno = MKDEV(led_major, led_minor);	//通过主次设备号获得设备号
	
	if (led_device)
	{
		cdev_del(led_device);	//删除设备号
		
		kfree(led_device);	//释放设备号空间
		led_device = NULL;	//设置为空, 防止再次被调用
	}
	
	unregister_chrdev_region(devno, 1);	//卸载主设备号
	

    return;
}

static int __init my_led_init(void)
{
	int result = 0;	//用来返回结果值
	dev_t dev = 0;	//设备号
	
	/***********************分配主次设备号******************/
	result = alloc_chrdev_region(&dev, led_minor, 1, DEVICE_NAME);	//自动分配主设备号
	led_major = MAJOR(dev);	//得到主设备号
	
	if (result < 0)
	{
		printk(KERN_WARNING "wfet_kb: can't get major %d\n", led_major);
		return result;
	}
	
	/*********************注册字符设备*************************/
	led_device = kmalloc(sizeof(struct cdev), GFP_KERNEL);	//字符设备的全局结构占用的内存要用kmalloc或kzalloc申请
	
	if(!led_device)
	{
		result = -ENOMEM;
		unregister_chrdev_region(dev, 1);
		return result;
	}
	memset(led_device, 0, sizeof(struct cdev));
	
	cdev_init(led_device, &pwm_fops);	//字符设备初始化
	led_device->owner = THIS_MODULE;
	
	result = cdev_add(led_device, dev, 1);	//字符设备添加
	if(result)
	{
		printk(KERN_NOTICE "Error %d adding LED device, major_%d", result, MAJOR(dev));
		kfree(led_device);	//释放空间
		unregister_chrdev_region(dev, 1);	//注销设备号
		return result;
	}

    return 0;
}


module_init(my_led_init)
module_exit(my_led_exit)

MODULE_LICENSE("GPL");

驱动测试文件:

#include <stdio.h>  
#include <sys/types.h>  
#include <sys/stat.h>  
#include <fcntl.h>  
#include <unistd.h>  
#include <string.h>  
#include <termios.h>  
#include <errno.h>  
#include <fcntl.h>  
#include <sys/ioctl.h>  
#include "at91_pwm.h"  
  
#define DEV_PWM0 "/dev/mypwm"  

int main(int argc, void *argv[])  
{  
    int fd0 = -1;     
    int i;  
    at91_pwm_arg arg;  
  
#if 1 //PWM0 Test  
    printf (" AT91 PWM0 Test ...\n");     
        fd0 = open(DEV_PWM0, O_RDWR);  
        if (fd0 == 0) {  
                printf("open pwm device error! %d\n", fd0);  
                return -1;  
        }  
   
        arg.pwm_freq = 1000;  
        arg.pwm_duty = 50;  
        arg.pwm_pulse = 1;  
        ioctl(fd0, 2, &arg);
		printf("---->2<----ioctl pwm device error! %d\n");  
   
        ioctl(fd0, 0, 1); 
		printf("---->0<----ioctl pwm device error! %d\n");		
   
        for (i=0; i<3; i++) {  
                sleep(1);  
        }  
        ioctl(fd0, 1, 0); 
		printf("---->1<----ioctl pwm device error! %d\n");
        close(fd0); 
#endif //PWM0  
}


你可能感兴趣的:(struct,cmd,File,Module,div,alignment)