免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 969 | 回复: 0
打印 上一主题 下一主题

基于ARM2440-watchdog驱动 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-02-23 18:20 |只看该作者 |倒序浏览
一、本文总体结构
   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
#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
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
所以一个看门狗的开启可以是下面:
#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;
}
明天继续




本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u1/56448/showart_1840110.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP