#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // #include #include #include #include #include #include "gpt_capture.h" #define MAX_NUM 2 struct gpt_device{ dev_t devid; int major; int minor; struct cdev cdev; struct class *class; struct device *device; }; struct gpt_data{ struct device *dev; struct clk *ipg_clk; struct clk *per_clk; unsigned int irq; unsigned int gpio_pin; unsigned long irq_flag; void __iomem *base; unsigned char index; uint32_t cnt[MAX_NUM]; uint8_t capture_flag; wait_queue_head_t r_wait; irqreturn_t (*irq_handler)(int,void*); }; static struct gpt_device *gptdev; static struct gpt_data *gpt; static int set_cap_mode(struct gpt_data *dev,unsigned int ch); static void gpt_disable(struct gpt_data *dev); static void gpt_enable(struct gpt_data *dev); static void gpt_irq_enable(struct gpt_data *dev,unsigned int ch); static void gpt_irq_disable(struct gpt_data *dev,unsigned int ch); static unsigned int gpt_poll(struct file *filp,poll_table *wait); static int gpt_read(struct gpt_data *dev,uint32_t *buf); static int gpt_open(struct inode *inode, struct file *filp) { filp->private_data = gpt; return 0; } static int gpt_release(struct inode *inode, struct file *filp) { // struct gpt_data *dev=(struct gpt_data*)filp->private_data; return 0; } static int gpt_read(struct gpt_data *dev,uint32_t *buf) { uint32_t val,fz; int ret; if(dev->cnt[CNT_NEXT]cnt[CNT_PREVIOUS]){ val=dev->cnt[CNT_NEXT]+0xffffffff-dev->cnt[CNT_PREVIOUS]; }else{ val=dev->cnt[CNT_NEXT]-dev->cnt[CNT_PREVIOUS]; } fz=3000000/val; ret=copy_to_user(buf,&fz,sizeof(uint32_t)); if(ret){ dev_err(dev->dev,"gpt read error!\r\n"); } return ret; } static long gpt_ioctl (struct file *filp, unsigned int cmd, unsigned long arg) { struct gpt_data *dev=(struct gpt_data*)filp->private_data; uint32_t state; unsigned long flag; switch (cmd) { case TIME_MODE: /* code */ break; case CAP_CH1_MODE: local_irq_save(flag); set_cap_mode(dev,1); local_irq_restore(flag); state=__raw_readl(gpt->base + MXC_TCTL); if(state){ dev_crit(dev->dev,"MXC_TCTL is 0x%x\r\n",state); } state=__raw_readl(gpt->base + V2_IR); if(state){ dev_crit(dev->dev,"V2_IR is 0x%x\r\n",state); } break; case CAP_CH2_MODE: set_cap_mode(dev,2); break; case COM_OUT1_MODE: break; case COM_OUT2_MODE: break; case COM_OUT3_MODE: break; case GPT_ENABLE: gpt_enable(dev); state=__raw_readl(gpt->base + MXC_TCTL); if(state){ dev_crit(dev->dev,"MXC_TCTL is 0x%x\r\n",state); } break; case GPT_DISABLE: gpt_disable(dev); break; case GPT_READ: gpt_read(dev,(uint32_t*)arg); break; default: break; } return 0; } static unsigned int gpt_poll(struct file *filp,poll_table *wait) { unsigned int mask=0; struct gpt_data *dev=(struct gpt_data *)filp->private_data; poll_wait(filp,&dev->r_wait,wait); if(dev->capture_flag){ dev->capture_flag=0; mask=POLLIN | POLLRDNORM; } return mask; } static struct file_operations gpt_ops={ .owner=THIS_MODULE, .open=gpt_open, .release=gpt_release, .unlocked_ioctl=gpt_ioctl, .poll=gpt_poll, }; static void gpt_disable(struct gpt_data *dev) { uint32_t ctl_val; ctl_val=__raw_readl(dev->base+MXC_TCTL); ctl_val&=~(MXC_TCTL_TEN); __raw_writel(ctl_val,dev->base+MXC_TCTL); } static void gpt_enable(struct gpt_data *dev) { uint32_t ctl_val; ctl_val=__raw_readl(dev->base+MXC_TCTL); ctl_val|=MXC_TCTL_TEN; __raw_writel(ctl_val,dev->base+MXC_TCTL); } static void gpt_irq_enable(struct gpt_data *dev,unsigned int ch) { if(ch==1) __raw_writel(V2_IR_IM1EN | V2_IR_ROVEN, dev->base + V2_IR); else if(ch==2) __raw_writel(V2_IR_IM2EN | V2_IR_ROVEN, dev->base + V2_IR); } static void gpt_irq_disable(struct gpt_data *dev,unsigned int ch) { if(ch==1) __raw_writel(0, dev->base + V2_IR); else if(ch==2) __raw_writel(0, dev->base + V2_IR); } static int set_cap_mode(struct gpt_data *dev,unsigned int ch) { uint32_t ctl_val; gpt_disable(dev); ctl_val=__raw_readl(dev->base+MXC_TCTL); if(ch==1) ctl_val|=V2_TCTL_IM1_RISING; else if(ch==2) ctl_val|=V2_TCTL_IM2_RISING; __raw_writel(ctl_val,dev->base+MXC_TCTL); gpt_irq_enable(dev,ch); // gpt_enable(dev); return 0; } static irqreturn_t gpt_isr(int irq, void *dev_id) { struct gpt_data *dev=(struct gpt_data *)dev_id; uint32_t state_val,cnt_val; printk("gpt isr cap rising happen!\r\n"); state_val=__raw_readl(dev->base+V2_SR); if(state_val & V2_SR_IM1){ __raw_writel(V2_SR_IM1,dev->base+V2_SR); cnt_val=__raw_readl(dev->base+V2_ICR1); }else if(state_val & V2_SR_IM2){ __raw_writel(V2_SR_IM2,dev->base+V2_SR); cnt_val=__raw_readl(dev->base+V2_ICR2); }else if(state_val & V2_SR_ROV){ __raw_writel(V2_SR_ROV,dev->base+V2_SR); return IRQ_HANDLED; }else{ return IRQ_HANDLED; } if(dev->index==CNT_PREVIOUS){ dev->cnt[CNT_PREVIOUS]=cnt_val; dev->index+=1; }else if(dev->index==CNT_NEXT){ gpt_disable(dev); dev->cnt[CNT_NEXT]=cnt_val; dev->index=CNT_PREVIOUS; dev->capture_flag=1; wake_up(&dev->r_wait); } return IRQ_HANDLED; } static int chrdev_register(struct gpt_device *dev) { int ret; dev->major=0; if(dev->major){ dev->devid=MKDEV(dev->major,0); ret=register_chrdev_region(dev->devid,DEV_CNT,DEV_NAME); if(ret<0){ goto fail_devid; } }else{ ret=alloc_chrdev_region(&dev->devid,0,DEV_CNT,DEV_NAME); if(ret<0){ goto fail_devid; } dev->major=MAJOR(dev->devid); dev->minor=MINOR(dev->devid); printk("capture major = %d,minor = %d\r\n",dev->major,dev->minor); } dev->cdev.owner=THIS_MODULE; cdev_init(&dev->cdev,&gpt_ops); ret=cdev_add(&dev->cdev,dev->devid,DEV_CNT); if(ret){ goto fail_cdev; } dev->class=class_create(THIS_MODULE,DEV_NAME); if (IS_ERR(dev->class)) { ret=PTR_ERR(dev->class); goto fail_class; } dev->device=device_create(dev->class,NULL,dev->devid,NULL,DEV_NAME); if (IS_ERR(dev->device)) { ret=PTR_ERR(dev->device); goto fail_device; } return 0; fail_device: class_destroy(dev->class); fail_class: cdev_del(&dev->cdev); fail_cdev: unregister_chrdev_region(dev->devid,DEV_CNT); fail_devid: return -1; } static int gpt_probe(struct platform_device *pdev) { int ret,err; uint32_t state,tctl_val=0; struct resource *res; gptdev=devm_kzalloc(&pdev->dev,sizeof(*gptdev),GFP_KERNEL); gpt=devm_kzalloc(&pdev->dev,sizeof(*gpt),GFP_KERNEL); if(!gpt){ dev_err(&pdev->dev,"malloc init failed!\r\n"); return ENOMEM; } gpt->dev=&pdev->dev; gpt->irq_flag=IRQF_TRIGGER_RISING; gpt->irq_handler=gpt_isr; gpt->index=0; memset(gpt->cnt,0,MAX_NUM); init_waitqueue_head(&gpt->r_wait); ret=chrdev_register(gptdev); if(ret){ printk("gpt_device register failed!\r\n"); } res=platform_get_resource(pdev,IORESOURCE_MEM,0); if (!res) { dev_err(&pdev->dev, "Couldn't get regs memory\n"); err = -ENODEV; goto exit; } dev_crit(&pdev->dev,"res start is 0x%x\r\n",res->start); gpt->base=devm_ioremap_resource(&pdev->dev,res); if (IS_ERR(gpt->base)) { dev_err(&pdev->dev, "Couldn't ioremap regs\n"); err = -ENODEV; goto exit; } dev_crit(&pdev->dev,"gpt->base is %p\r\n",gpt->base); gpt->ipg_clk=devm_clk_get(&pdev->dev,"ipg"); if (IS_ERR(gpt->ipg_clk)) { dev_err(&pdev->dev, "can't get gpt clock\n"); return PTR_ERR(gpt->ipg_clk); } ret=clk_prepare_enable(gpt->ipg_clk); if (ret) { dev_err(&pdev->dev, "can't enable gpt clock\n"); return ret; } gpt->per_clk=devm_clk_get(&pdev->dev,"per"); if (IS_ERR(gpt->per_clk)) { dev_err(&pdev->dev, "can't get gpt clock\n"); return PTR_ERR(gpt->per_clk); } ret=clk_prepare_enable(gpt->per_clk); if (ret) { dev_err(&pdev->dev, "can't enable gpt clock\n"); return ret; } gpt->irq=platform_get_irq(pdev,0); if (gpt->irq<0) { dev_err(&pdev->dev, "can't get irq number\n"); return gpt->irq; } ret=devm_request_irq(&pdev->dev,gpt->irq,gpt->irq_handler,0,pdev->name,gpt); if (ret) { dev_err(&pdev->dev, "can't claim irq %d\n", gpt->irq); goto exit; } gpt->gpio_pin=of_get_named_gpio(pdev->dev.of_node,"capture-gpios",0); if (!gpio_is_valid(gpt->gpio_pin)) { dev_err(&pdev->dev, "invalid GPIO pin\n"); ret = -EINVAL; goto exit; } ret=devm_gpio_request_one(&pdev->dev,gpt->gpio_pin,GPIOF_DIR_IN,pdev->name); if (ret) { dev_err(&pdev->dev, "failed to request GPIO pin\n"); goto exit; } /* * Initialise to a known state (all timers off, and timing reset) */ __raw_writel(V2_TCTL_SWR,gpt->base + MXC_TCTL); while(__raw_readl(gpt->base + MXC_TCTL) & V2_TCTL_SWR); __raw_writel(0, gpt->base + MXC_TCTL); __raw_writel(0, gpt->base + MXC_TPRER); /* see datasheet note */ dev_info(&pdev->dev,"gpt ipgclk is %ldHZ\r\n",clk_get_rate(gpt->ipg_clk)); dev_info(&pdev->dev,"gpt perclk is %ldHZ\r\n",clk_get_rate(gpt->per_clk)); tctl_val = V2_TCTL_CLK_IPG | V2_TCTL_ENMOD |V2_TCTL_WAITEN | V2_TCTL_STOPEN; __raw_writel((clk_get_rate(gpt->ipg_clk)/1000000)<base + MXC_TPRER); //66分频 __raw_writel(tctl_val, gpt->base + MXC_TCTL); __raw_writel(0,gpt->base + V2_SR); platform_set_drvdata(pdev,gptdev); dev_info(&pdev->dev, "initialized\n"); return 0; exit: if (err) dev_err(&pdev->dev, "Exiting (unsuccessfully) gpt_probe()\n"); return err; } static int gpt_remove(struct platform_device *pdev) { struct gpt_device *dev=platform_get_drvdata(pdev); cdev_del(&dev->cdev); unregister_chrdev_region(dev->devid,DEV_CNT); device_destroy(dev->class,dev->devid); class_destroy(dev->class); return 0; } static const struct of_device_id of_gpt_match[] = { {.compatible = "ainuode,gpt2"}, {/*Sentinel*/}, }; static struct platform_driver gpt_driver = { .probe = gpt_probe, .remove = gpt_remove, .driver = { .name = "gpt", .of_match_table = of_gpt_match, }, }; static int __init mxc_timer_init_dt(void) { platform_driver_register(&gpt_driver); return 0; } static void __exit mxc_timer_exit_dt(void) { platform_driver_unregister(&gpt_driver); } module_init(mxc_timer_init_dt); module_exit(mxc_timer_exit_dt); MODULE_LICENSE("GPL"); MODULE_AUTHOR("heshao");