Chinaunix首页 | 论坛 | 博客
  • 博客访问: 713952
  • 博文数量: 104
  • 博客积分: 4320
  • 博客等级: 上校
  • 技术积分: 1948
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-30 14:42
文章分类

全部博文(104)

文章存档

2012年(4)

2011年(65)

2010年(35)

分类:

2011-11-01 13:40:24

原文地址:基于ARM2440-watchdog驱动 作者:chenmeng56

一、本文总体结构
   1.看门狗硬件结构及原理
   2.“平台设备”与“字符设备”和“misc设备”关系及特点
   3.平台设备框架学习及具体设备建立分析
   4.看门狗驱动分析及源代码
   5.调试
   6.参考文献

1.看门狗硬件结构及原理
  看门狗分为硬件和软件,2440内部集成一个硬件看门狗(一个定时器电路,可以作为一般TIMER),定时器输出链接到RESET,实现复位功能。当定时器计数值=0时,产生复位信号。
  对看门的设置和操作是对其3个寄存器:
 WTCON Watchdog timer control register 地址:0x53000000
WTCON Bit Description Initial State
Prescaler value 【15:8】 分为128 64等,需要设置
#define s3c2440_wdt_precaler(x) (x<<8)
#define s3c2440_wdt_precaler256 0xff
 
Interrupt generation [2] Enable or disable bit of the interrupt.
0 = Disable
1 = Enable
看门狗开启应该是先使能【2】为1,再开启【0】为1
#define S3C2440_WTCON_RSTEN   (0x01)
#define S3C2410_WTCON_ENABLE  (1<<5)
Reset enable/disable [0]
Enable or disable bit of Watchdog timer output for reset
signal.
1: Assert reset signal of the S3C2440A at watchdog timeout
0: Disable the reset function of the watchdog timer.
时钟选择:
Clock select [4:3] Determine the clock division factor.
00: 16 01 : 32
10: 64 11 : 128
#define S3C2410_WTCON_DIV16   (0<<3)
#define S3C2410_WTCON_DIV32   (1<<3)
#define S3C2410_WTCON_DIV64   (2<<3)
#define S3C2410_WTCON_DIV128  (3<<3)
所以一个看门狗的开启可以是下面:
#define rWTCON (*(volatile unsigned int  *)0x53000000)
void s3c2440_wdt_start(void)
{
  rWTCON=S3C2410_WTCON_DIV128  |   S3C2410_WTCON_ENABLE  | s3c2440_wdt_precaler(s3c2440_wdt_precaler256 );
 rWTDAT=0X8000;是默认值
 rWTCON |=S3C2440_WTCON_RSTEN;  
}
看门狗还必须定时”喂狗“就是设置rWTCNT=0X8000;
但是在linux驱动中只能使用虚拟地址.
注:此部分参考ARM2440手册

2.“平台设备”与“字符设备”和“misc设备”关系及特点
 平台设备是linux系统提供的一种附加手段,他实现物理、逻辑设备,和linux内核交互信息,只是设备的属性;
 字符设备是面向上层用户空间,他对VFS提供接口是其本质;
misc设备是linux把一些字符设备放在一起;(为什么还不太清楚)
总的来说,他们各自相配合完成设备驱动。
平台设备:
     分为驱动和设备
 
驱动是把设备注册到内核
设备是对其资源的抽象

3.平台设备框架学习及具体设备建立分析
在arch/arm/mach-s3c2440/devs.c对系统中所有设备的定义
  static struct resource s3c_wdt_resource[] = {
 [0] = {
  .start = S3C24XX_PA_WATCHDOG,
  .end   = S3C24XX_PA_WATCHDOG + S3C24XX_SZ_WATCHDOG - 1,
  .flags = IORESOURCE_MEM,
 },
 [1] = {
  .start = IRQ_WDT,
  .end   = IRQ_WDT,
  .flags = IORESOURCE_IRQ,
 }
};
struct platform_device s3c_device_wdt = {
 .name    = "s3c2440-wdt",
 .id    = -1,
 .num_resources   = ARRAY_SIZE(s3c_wdt_resource),
 .resource   = s3c_wdt_resource,
};
在/arch/arm/mach-2440.c
 
static struct platform_device *smdk2440_devices[] __initdata = {
 &s3c_device_usb,
 &s3c_device_lcd,
 &s3c_device_wdt,
 &s3c_device_i2c,
 &s3c_device_iis,
 &s3c_device_adc,
 &s3c_device_eth,
 &s3c_device_camif,
 &s3c_device_sdi,
 &s3c_device_buttons,
 &s3c_device_rtc,
 &s3c_device_ts,
};
这个是对系统所有设备的数据链,需要用下面的函数加入到系统,以至于我们可以在驱动中使用资源了。
void __init smdk_machine_init(void)
{
 /* Configure the LEDs (even if we have no LED support)*/
 s3c2410_gpio_cfgpin(S3C2410_GPF4, S3C2410_GPF4_OUTP);
 s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP);
 s3c2410_gpio_cfgpin(S3C2410_GPF6, S3C2410_GPF6_OUTP);
 s3c2410_gpio_cfgpin(S3C2410_GPF7, S3C2410_GPF7_OUTP);
 s3c2410_gpio_setpin(S3C2410_GPF4, 1);
 s3c2410_gpio_setpin(S3C2410_GPF5, 1);
 s3c2410_gpio_setpin(S3C2410_GPF6, 1);
 s3c2410_gpio_setpin(S3C2410_GPF7, 1);
 s3c_device_nand.dev.platform_data = &smdk_nand_info;
 platform_add_devices(smdk_devs, ARRAY_SIZE(smdk_devs));
 s3c2410_pm_init();
}


4.看门狗驱动分析及源代码
 初始化函数
static struct platform_driver s3c2410wdt_driver = {
 .probe  = s3c2410wdt_probe,
 .remove  = s3c2410wdt_remove,
 .shutdown = s3c2410wdt_shutdown,
 //.suspend = s3c2410wdt_suspend,
 //.resume  = s3c2410wdt_resume,
 .driver  = {
  .owner = THIS_MODULE,
  .name = "s3c2410-wdt",
 },
};
static int __init watchdog_init(void)
{
 printk(banner);
 return platform_driver_register(&s3c2410wdt_driver);
}
他会调用s3c2410wdt_probe
static int s3c2410wdt_probe(struct platform_device *pdev)
{
 struct resource *res;
 int started = 0;
 int ret;
 int size;
  /* get the memory region for the watchdog timer */
 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);这里和我们上面的资源联系
 if (res == NULL) {
  printk(KERN_INFO PFX "failed to get memory region resouce\n");
  return -ENOENT;
 }
 size = (res->end-res->start)+1;
 wdt_mem = request_mem_region(res->start, size, pdev->name);
 if (wdt_mem == NULL) {
  printk(KERN_INFO PFX "failed to get memory region\n");
  return -ENOENT;
 }
 wdt_base = ioremap(res->start, size);内存-虚拟地址的转换
 if (wdt_base == 0) {
  printk(KERN_INFO PFX "failed to ioremap() region\n");
  return -EINVAL;
 }
 DBG("probe: mapped wdt_base=%p\n", wdt_base);
 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 if (res == NULL) {
  printk(KERN_INFO PFX "failed to get irq resource\n");
  return -ENOENT;
 }
 ret = request_irq(res->start, s3c2410wdt_irq, 0, pdev->name, pdev);
 if (ret != 0) {
  printk(KERN_INFO PFX "failed to install irq (%d)\n", ret);
  return ret;
 }
 wdt_clock = clk_get(&pdev->dev, "watchdog");
 if (wdt_clock == NULL) {
  printk(KERN_INFO PFX "failed to find watchdog clock source\n");
  return -ENOENT;
 }
 clk_enable(wdt_clock);
 /* see if we can actually set the requested timer margin, and if
  * not, try the default value */
 if (s3c2410wdt_set_heartbeat(tmr_margin)) {
  started = s3c2410wdt_set_heartbeat(CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);
  if (started == 0) {
   printk(KERN_INFO PFX "tmr_margin value out of range, default %d used\n",
          CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);
  } else {
   printk(KERN_INFO PFX "default timer value is out of range, cannot start\n");
  }
 }
 ret = misc_register(&s3c2410wdt_miscdev);
 if (ret) {
  printk (KERN_ERR PFX "cannot register miscdev on minor=%d (%d)\n",
   WATCHDOG_MINOR, ret);
  return ret;
 }
 if (tmr_atboot && started == 0) {
  printk(KERN_INFO PFX "Starting Watchdog Timer\n");
  s3c2410wdt_start();
 } else if (!tmr_atboot) {
  /* if we're not enabling the watchdog, then ensure it is
   * disabled if it has been left running from the bootloader
   * or other source
s3c2410wdt_stop();
 }
 return 0;
}
明天继续
 
 
 
阅读(1926) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~