[嵌入式Linux驅動]S5PV210的步進電機Linux驅動程式
阿新 • • 發佈:2019-01-03
#include <asm/io.h> #include <asm/uaccess.h> #include <linux/fs.h> #include <linux/delay.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/mutex.h> #include <linux/platform_device.h> #include <linux/miscdevice.h> #define DEBUG 1 #define SINGLE_MODULE 1 #define READING_WAIT_TIME 300 #define MAGIC_WORD 'P' #define STEPPER_MOTOR_DOWN_A_STEP _IO(MAGIC_WORD,11) #define STEPPER_MOTOR_UP_A_STEP _IO(MAGIC_WORD,21) #define GPH0_4_SET_LOWLEVEL(tmp) do{ \ tmp =ioread32(GPH0_BASE+1); \ tmp &= ~(0x1<<4); \ iowrite32(tmp,GPH0_BASE+1); \ }while(0) #define GPH0_4_SET_HIGHLEVEL(tmp) do{ \ tmp =ioread32(GPH0_BASE+1); \ tmp |= (0x1<<4); \ iowrite32(tmp,GPH0_BASE+1); \ }while(0) #define GPH1_1_SET_LOWLEVEL(tmp) do{ \ tmp =ioread32(GPH1_BASE+1); \ tmp &= ~(0x1<<1); \ iowrite32(tmp,GPH1_BASE+1); \ }while(0) #define GPH1_1_SET_HIGHLEVEL(tmp) do{ \ tmp =ioread32(GPH1_BASE+1); \ tmp |= (0x1<<1); \ iowrite32(tmp,GPH1_BASE+1); \ }while(0) #define GPH0_3_SET_LOWLEVEL(tmp) do{ \ tmp =ioread32(GPH0_BASE+1); \ tmp &= ~(0x1<<3); \ iowrite32(tmp,GPH0_BASE+1); \ }while(0) #define GPH0_3_SET_HIGHLEVEL(tmp) do{ \ tmp =ioread32(GPH0_BASE+1); \ tmp |= (0x1<<3); \ iowrite32(tmp,GPH0_BASE+1); \ }while(0) #define GPH0_5_SET_LOWLEVEL(tmp) do{ \ tmp =ioread32(GPH0_BASE+1); \ tmp &= ~(0x1<<5); \ iowrite32(tmp,GPH0_BASE+1); \ }while(0) #define GPH0_5_SET_HIGHLEVEL(tmp) do{ \ tmp =ioread32(GPH0_BASE+1); \ tmp |= (0x1<<5); \ iowrite32(tmp,GPH0_BASE+1); \ }while(0) #define OP_1(tmp) do{ \ GPH0_4_SET_HIGHLEVEL(tmp); \ mdelay(plat_data_p->pulse_period); \ GPH0_4_SET_LOWLEVEL(tmp); \ }while(0) #define OP_2(tmp) do{ \ GPH1_1_SET_HIGHLEVEL(tmp); \ mdelay(plat_data_p->pulse_period); \ GPH1_1_SET_LOWLEVEL(tmp); \ }while(0) #define OP_3(tmp) do{ \ GPH0_3_SET_HIGHLEVEL(tmp); \ mdelay(plat_data_p->pulse_period); \ GPH0_3_SET_LOWLEVEL(tmp); \ }while(0) #define OP_4(tmp) do{ \ GPH0_5_SET_HIGHLEVEL(tmp); \ mdelay(plat_data_p->pulse_period); \ GPH0_5_SET_LOWLEVEL(tmp); \ }while(0) struct StepperMotor_Plat_Data{ unsigned short step_long; unsigned short one_round; unsigned short pulse_period; unsigned short max_position; unsigned short current_position; unsigned short min_position; }; static struct StepperMotor_Plat_Data * plat_data_p; struct resource * platform_resource; static volatile unsigned long * GPH_BASE; //Must caculate the offset carefully!!! #define GPH0_BASE (GPH_BASE + 0) #define GPH1_BASE (GPH_BASE + 8) /*** file_operation_function declare ****/ int Stepper_Motor_driver_open (struct inode * inode_p, struct file *file_p); long Stepper_Motor_driver_ioctl (struct file *file_p, unsigned int cmd, unsigned long arg); int Stepper_Motor_driver_close (struct inode *inode_p, struct file *file_p); ssize_t Stepper_Motor_driver_read (struct file *file_p, char __user *buff, size_t size, loff_t *offset); static int __devexit Stepper_Motor_driver_remove(struct platform_device * pdev); static int __devinit Stepper_Motor_dirver_probe(struct platform_device * pdev); /*** Mutex ***/ struct mutex Stepper_Motor_mutex; /*** Struct declare ****/ static struct platform_driver Stepper_Motor_driver={ .probe=Stepper_Motor_dirver_probe, .remove = Stepper_Motor_driver_remove, .driver = { .name = "stepper_motor_drv", .owner = THIS_MODULE, }, }; static struct file_operations Stepper_Motor_fop={ .open=Stepper_Motor_driver_open, .unlocked_ioctl=Stepper_Motor_driver_ioctl, .release=Stepper_Motor_driver_close, .read=Stepper_Motor_driver_read, }; static struct miscdevice Stepper_Motor_miscdev = { .minor = MISC_DYNAMIC_MINOR, //dynamic .name = "smarthome_steppermotor_control", .fops = &Stepper_Motor_fop, }; /*** file_operation_function implement ****/ int Stepper_Motor_driver_open (struct inode * inode_p, struct file *file_p) { printk("entering %s\n",__FUNCTION__); unsigned int tmp; /*nLED_1=EINT4/GPH0_4*/ //GPH0CON[4] [19:16] = 0001 tmp =ioread32(GPH0_BASE+0); tmp &= ~(0xf<<16); tmp |= (0x1<<16); iowrite32(tmp,GPH0_BASE+0); GPH0_4_SET_LOWLEVEL(tmp); /*nLED_4=EINT9/GPH1_1*/ //GPH1CON[1] [7:4]=0001 tmp =ioread32(GPH1_BASE+0); tmp &= ~(0xf<<4); tmp |= (0x1<<4); iowrite32(tmp,GPH1_BASE+0); GPH1_1_SET_LOWLEVEL(tmp); /*nLED_3=EINT3/GPH0_3*/ //GPH0CON[3] [15:12] = 0001 tmp =ioread32(GPH0_BASE+0); tmp &= ~(0xf<<12); tmp |= (0x1<<12); iowrite32(tmp,GPH0_BASE+0); GPH0_3_SET_LOWLEVEL(tmp); /*nLED_4=EINT5/GPH0_5*/ //GPH0CON[5] [23:20]=0001 tmp =ioread32(GPH0_BASE+0); tmp &= ~(0xf<<20); tmp |= (0x1<<20); iowrite32(tmp,GPH0_BASE+0); GPH0_5_SET_LOWLEVEL(tmp); plat_data_p->current_position=0; printk("%s: gpio init finished!!!\n",__FUNCTION__); return 0; } ssize_t Stepper_Motor_driver_read (struct file * file_p,char __user * buff, size_t size,loff_t *offset) { printk("entering %s\n",__FUNCTION__); unsigned char i; i=0; while(copy_to_user(buff,(void *)plat_data_p,sizeof(*plat_data_p))){ msleep(READING_WAIT_TIME); if(i++ >= 2){ printk("%s: copy_to_user failed!!!\n",__FUNCTION__); return -EBUSY; } } return 0; } long Stepper_Motor_driver_ioctl (struct file *file_p, unsigned int cmd, unsigned long arg) { /* Locked */ mutex_lock(&Stepper_Motor_mutex); printk("entering %s\n",__FUNCTION__); unsigned int tmp; int i; if(_IOC_TYPE(cmd) != MAGIC_WORD) return -EINVAL; switch(cmd){ case STEPPER_MOTOR_DOWN_A_STEP: if(plat_data_p->current_position < plat_data_p->max_position){ for(i=0;i<plat_data_p->one_round;i++){ OP_1(tmp); OP_2(tmp); OP_3(tmp); OP_4(tmp); } plat_data_p->current_position++; #if DEBUG printk("Kernel Debug: plat_data_p->current_position is %d\n", plat_data_p->current_position); #endif } break; case STEPPER_MOTOR_UP_A_STEP: if(plat_data_p->current_position > plat_data_p->min_position){ for(i=0;i<plat_data_p->one_round;i++){ OP_4(tmp); OP_3(tmp); OP_2(tmp); OP_1(tmp); } plat_data_p->current_position--; #if DEBUG printk("Kernel Debug: plat_data_p->current_position is %d\n", plat_data_p->current_position); #endif } break; default: printk("%s: invalid command !!!\n",__FUNCTION__); break; } /* Unlocked */ mutex_unlock(&Stepper_Motor_mutex); return 0; } int Stepper_Motor_driver_close (struct inode *inode_p, struct file *file_p) { printk("entering %s\n",__FUNCTION__); unsigned int tmp; GPH0_4_SET_LOWLEVEL(tmp); GPH1_1_SET_LOWLEVEL(tmp); GPH0_3_SET_LOWLEVEL(tmp); GPH0_5_SET_LOWLEVEL(tmp); return 0; } /*** driver_operation ****/ static int __devinit Stepper_Motor_dirver_probe(struct platform_device * pdev) { printk("entering %s\n",__FUNCTION__); struct resource * pcheck; plat_data_p=(struct StepperMotor_Plat_Data *)(pdev->dev.platform_data); platform_resource=platform_get_resource(pdev,IORESOURCE_MEM,0); if(NULL == platform_resource){ printk("%s: platform_get_resource failed!\n",__FUNCTION__); goto err1; } #if SINGLE_MODULE pcheck=request_mem_region(platform_resource->start, platform_resource->end - platform_resource->start + 1, platform_resource->name); if(NULL==pcheck){ printk("%s: request_mem_region failed!\n",__FUNCTION__); goto err1; //return device busy! } #endif GPH_BASE=(unsigned long *)ioremap(platform_resource->start, platform_resource->end - platform_resource->start + 1); #if DEBUG printk("%s: GPH_BASE is %p \n",__FUNCTION__,GPH_BASE); printk("%s: GPH0_BASE is %p \n",__FUNCTION__,GPH0_BASE); printk("%s: GPH1_BASE is %p \n",__FUNCTION__,GPH1_BASE); #endif if( misc_register(&Stepper_Motor_miscdev) ){ printk("%s: misc_register failed!\n",__FUNCTION__); goto err2; } /* initing the mutex */ mutex_init(&Stepper_Motor_mutex); return 0; err2: iounmap(GPH_BASE); #if SINGLE_MODULE release_mem_region(platform_resource->start, platform_resource->end - platform_resource->start + 1); #endif err1: return -EBUSY; } static int __devexit Stepper_Motor_driver_remove(struct platform_device * pdev) { printk("entering %s\n",__FUNCTION__); mutex_destroy(&Stepper_Motor_mutex); iounmap(GPH_BASE); #if SINGLE_MODULE release_mem_region(platform_resource->start, platform_resource->end - platform_resource->start + 1); #endif if( misc_deregister(&Stepper_Motor_miscdev) ){ printk("%s:misc_deregister failed!\n",__FUNCTION__); return -EPERM; } return 0; } static int __init Stepper_Motor_driver_init(void) { printk("entering %s\n",__FUNCTION__); if( platform_driver_register(& Stepper_Motor_driver) ){ printk("%s: driver_register failed!\n",__FUNCTION__); return -EBUSY; } return 0; } static void __exit Stepper_Motor_driver_exit(void) { printk("entering %s\n",__FUNCTION__); platform_driver_unregister(& Stepper_Motor_driver); } module_init(Stepper_Motor_driver_init); module_exit(Stepper_Motor_driver_exit); MODULE_AUTHOR("kinyanderson"); MODULE_DESCRIPTION("Stepper_Motor_driver,use for controlling the Stepper motor"); MODULE_LICENSE("GPL");