Chinaunix首页 | 论坛 | 博客
  • 博客访问: 524411
  • 博文数量: 87
  • 博客积分: 4086
  • 博客等级: 上校
  • 技术积分: 900
  • 用 户 组: 普通用户
  • 注册时间: 2007-12-23 15:55
文章分类

全部博文(87)

文章存档

2012年(3)

2010年(13)

2009年(7)

2008年(64)

我的朋友

分类: LINUX

2008-06-04 17:44:03

这几天闲来无事,自己写了一个数码管的驱动。想想以前总是改别人的驱动,现在自己也写一个,体会一下写驱动的过程。
 
虽然驱动很小,却花了我将近半天的时间。主要是在时钟上面耽搁了。
 
先把源代码贴上来,大家可以讨论。
 
 

#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/clk.h>
#include <asm-arm/plat-s3c24xx/regs-spi.h>
#include <asm-arm/arch-s3c2410/regs-gpio.h>
#include <asm/io.h>
#include <asm/arch/map.h>
#include <asm-arm/plat-s3c24xx/clock.h>
#include <asm/arch/regs-clock.h>

#define DEVICE_NAME "s3c2410-spi"
static char tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x8e};
static int opencount=0;
static void __iomem *spi_base;
static struct clk *spi_clock; //就是这个地方,浪费了我好多时间


static inline void spi_send(unsigned char val)
{
 unsigned long flags;
 local_irq_save(flags);
 clk_enable(spi_clock); //就是这个地方,浪费了我好多时间

 while((readb(spi_base+S3C2410_SPSTA)&0x01) != 0x01);
 writeb(val, spi_base+S3C2410_SPTDAT);
 s3c2410_gpio_setpin(S3C2410_GPH1, 0);
 udelay(10);
 s3c2410_gpio_setpin(S3C2410_GPH1, 1);
 
 local_irq_restore(flags);
}
static ssize_t s3c2410_hc595_write(struct file *file, const char *buffer,
                                   size_t count,loff_t * ppos)
{
     char sendbuffer[4];
     char num=0;
     int tensdigit=0;
 int singledigit=0;
    if( copy_from_user(sendbuffer, buffer, count))
     {
         kfree( sendbuffer );
         printk(" return -EFAULT;\n");
         return -EFAULT;
     }
      singledigit=(sendbuffer[0])%10;
      tensdigit=(int)(sendbuffer[0]/10);
        
        num=tab[singledigit];
        spi_send(num);
        udelay(100);
        num=tab[tensdigit];
        spi_send(num);
        udelay(100);
    return 0;
}
static int s3c2410_hc595_open(struct inode *inode, struct file *file)
{
 if(opencount==1)
  return -EBUSY;
 opencount++;
 s3c2410_gpio_setpin(S3C2410_GPH1, 0);
 
 printk("device open\n");
 return 0;
}
static int s3c2410_hc595_release(struct inode *inode, struct file *filp)
{
 opencount--;
 s3c2410_gpio_setpin(S3C2410_GPH1, 1);
 printk("device release\n");
 return 0;
}

 
static struct file_operations s3c2410_595_fops = {
 .owner = THIS_MODULE,
 .write = s3c2410_hc595_write,
 .open = s3c2410_hc595_open,
 .release = s3c2410_hc595_release,
};
static int s3c2410_tube_probe(struct platform_device *pdev)
{
 unsigned long base;
 unsigned char value;
 int ret;
 s3c2410_gpio_cfgpin(S3C2410_GPE11, S3C2410_GPE11_SPIMISO0);
 s3c2410_gpio_pullup(S3C2410_GPE11, 0);
 s3c2410_gpio_cfgpin(S3C2410_GPE12, S3C2410_GPE12_SPIMOSI0);
 s3c2410_gpio_pullup(S3C2410_GPE12, 0);
 s3c2410_gpio_cfgpin(S3C2410_GPE13, S3C2410_GPE13_SPICLK0);
 s3c2410_gpio_pullup(S3C2410_GPE13, 1);
 
 base = pdev->resource[0].start;
 
        if (!request_mem_region(base, 0x20, DEVICE_NAME)) {
                ret = -EBUSY;
  printk("---------------failed-----------------\n");
                return ret;
        }
 
 spi_base = ioremap(base, 0x40); //就是这个地方,浪费了我好多时间

 spi_clock = clk_get(&pdev->dev, "spi");
 if (spi_clock == NULL) {
   printk(KERN_INFO "failed to find clock source\n");
   return -ENOENT;
 }
 
 clk_enable(spi_clock); //就是这个地方,浪费了我好多时间

 

 value = (0<<5)|(1<<4)|(1<<3)|(0<<2)|(0<<1);
 writeb(value, spi_base+S3C2410_SPCON);
 value = 33;
 writeb(value, spi_base+S3C2410_SPPRE);
 value = 2;
 writeb(value, spi_base+S3C2410_SPPIN);
 s3c2410_gpio_cfgpin(S3C2410_GPH1, S3C2410_GPH1_OUTP);
 s3c2410_gpio_pullup(S3C2410_GPH1, 1);
 ret = register_chrdev(0, DEVICE_NAME, &s3c2410_595_fops);
 if(!ret)
   printk("--------------failed-----------------\n");
 printk("74HC595 initialized for tubes!\n");
 return 0;
}
static struct platform_driver s3c2410_tube = {
 .probe = s3c2410_tube_probe,
 .driver = {
  .name = "s3c2410-spi",
  .owner = THIS_MODULE,
 },
};
int __init s3c2410tube_init(void)
{
 return platform_driver_register(&s3c2410_tube);
}
void __exit s3c2410tube_exit(void)
{
 platform_driver_unregister(&s3c2410_tube);
}
module_init(s3c2410tube_init);
module_exit(s3c2410tube_exit);
MODULE_AUTHOR("yanqiang-liu@163.com");
MODULE_DESCRIPTION("Tube driver for the s3c2410");
MODULE_LICENSE("GPL");

 

需要注意的地方在源文件中都标注了,希望大家不要犯类似的错误,浪费时间。
 
那几个相关的函数就是处理clkcon寄存器的,大家看看datasheet就明白了。
 
我的邮箱:yanqiang-liu@163.com 现在正做arm9上的linux开发。欢迎大家讨论。
阅读(1804) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-03-12 15:12:16

作者您好: 做为一个嵌入式技术的初学者,有幸拜读了您的驱动程序。感觉很好,从中学到了不少东西。 我现在也在做一个驱动程序,功能就是,利用数码管显示最大到4位 的数,内核是最新的2.6.33.开发板是S3C2410. 因为初步涉猎此技术,能力有现,希望得到您的建议,给我一点建议!我将非长感谢。