s3c6410的RTC在linux中的驱动(3)

发布者:科技小巨人最新更新时间:2022-06-09 来源: eefocus关键字:s3c6410  RTC  linux  驱动 手机看文章 扫描二维码
随时随地手机看文章

上一篇说到了s3c_rtc_probe函数,但由于太长,而没有说完,这一篇接着上一篇的说。


说完了这个函数就可以回到s3c_rtc_probe函数接着说了,下篇再聊。还记的这句话吗?现在接着聊:

 pr_debug("s3c2410_rtc: RTCCON=%02xn",

readb(s3c_rtc_base + S3C2410_RTCCON));调试信息



s3c_rtc_setfreq(&pdev->dev, 1);RTC设置频率函数,周期公式为:


Then the period of interrupt is as follows:

Period = (n+1)/32768 second (n= tick counter value)


则频率freq=32768/(n+1)


其中n为TICNT寄存器,看下图:

static int s3c_rtc_setfreq(struct device *dev, int freq)

{

spin_lock_irq(&s3c_rtc_pie_lock);


s3c_rtc_set_freq_regs(s3c_rtc_base, freq, s3c_rtc_freq);


void s3c_rtc_set_freq_regs(void __iomem *base, uint freq, uint s3c_freq)这个参数没用到

{

unsigned int tmp;



        tmp = readw(base + S3C2410_RTCCON) & (S3C_RTCCON_TICEN | S3C2410_RTCCON_RTCEN );

        writew(tmp, base + S3C2410_RTCCON);

        s3c_freq = freq;

        tmp = (32768 / freq)-1;

        writel(tmp, base + S3C2410_TICNT);看上面的图,就是那个寄存器。

}




spin_unlock_irq(&s3c_rtc_pie_lock);

return 0;

}

在此回到s3c_rtc_probe函数中。


device_init_wakeup(&pdev->dev, 1);

/* register RTC and exit */

rtc =rtc_device_register("s3c", &pdev->dev, &s3c_rtcops,THIS_MODULE);

RTC必须要注册到内核中才能使用,这个是在RTC驱动模型中说过的这个函数的作用,如果不清楚,可以回过去查看。现在具体看下这个函数的源码:


/**

 * rtc_device_register - register w/ RTC class

 * @dev: the device to register

 *

 * rtc_device_unregister() must be called when the class device is no

 * longer needed.

 *

 * Returns the pointer to the new struct class device.这个函数的返回值是个struct rtc_device结构的指针。

 */当看到一个新函数,如果不明白,就可以先看它的注释。

struct rtc_device *rtc_device_register(const char *name, struct device *dev,

const struct rtc_class_ops *ops,

struct module *owner)

{


先看出传入的参数中的const struct rtc_class_ops结构指针,实参为:


static const struct rtc_class_ops s3c_rtcops = {

.open = s3c_rtc_open,

.release  = s3c_rtc_release,

.ioctl  = s3c_rtc_ioctl,

.read_time  = s3c_rtc_gettime,

.set_time  = s3c_rtc_settime,

.read_alarm  = s3c_rtc_getalarm,

.set_alarm  = s3c_rtc_setalarm,

.irq_set_freq  = s3c_rtc_setfreq,

.irq_set_state= s3c_rtc_setpie,

.proc        = s3c_rtc_proc,

};在Rtc-s3c.c (linux2.6.28driversrtc)文件中定义,这样RTC设备模型就和具体的RTC设备联系起来了。

struct rtc_device *rtc;

int id, err;


if (idr_pre_get(&rtc_idr, GFP_KERNEL) == 0) {

err = -ENOMEM;

goto exit;

}分配一个ID号,用来把一个数字与一个指针联系起来


mutex_lock(&idr_lock);

err = idr_get_new(&rtc_idr, NULL, &id);得到一个ID号,不太懂。

mutex_unlock(&idr_lock);

if (err < 0)

goto exit;

id = id & MAX_ID_MASK;



rtc = kzalloc(sizeof(struct rtc_device), GFP_KERNEL);

if (rtc == NULL) {

err = -ENOMEM;

goto exit_idr;

}分配一个RTC设备结构体struct rtc_device



rtc->id = id;

rtc->ops = ops;

rtc->owner = owner;

rtc->max_user_freq = 64;

rtc->dev.parent = dev;

rtc->dev.class = rtc_class;

rtc->dev.release = rtc_device_release;

初始化struct rtc_device结构体,用户可以设置的最大频率为64,下面是struct rtc_device结构体的原型:


structrtc_device

{

struct device dev;

struct module *owner;



int id;

char name[RTC_DEVICE_NAME_SIZE];



const struct rtc_class_ops *ops;

struct mutex ops_lock;

struct cdev char_dev;

unsigned long flags;


 unsigned long irq_data;

spinlock_t irq_lock;

wait_queue_head_t irq_queue;

struct fasync_struct *async_queue;



struct rtc_task *irq_task;

spinlock_t irq_task_lock;

int irq_freq;

int max_user_freq;

#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL

struct work_struct uie_task;

struct timer_list uie_timer;

/* Those fields are protected by rtc->irq_lock */

unsigned int oldsecs;

unsigned int irq_active:1;

unsigned int stop_uie_polling:1;

unsigned int uie_task_active:1;

unsigned int uie_timer_active:1;

#endif

};


mutex_init(&rtc->ops_lock);

spin_lock_init(&rtc->irq_lock);

spin_lock_init(&rtc->irq_task_lock);

init_waitqueue_head(&rtc->irq_queue);

strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE);

snprintf(rtc->dev.bus_id, BUS_ID_SIZE, "rtc%d", id);



rtc_dev_prepare(rtc);


/* insertion/removal hooks */

void rtc_dev_prepare(struct rtc_device *rtc)

{

if (!rtc_devt)

return;


if (rtc->id >= RTC_DEV_MAX) {

pr_debug("%s: too many RTC devicesn", rtc->name);

return;

}



rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id);



#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL

INIT_WORK(&rtc->uie_task, rtc_uie_task);

setup_timer(&rtc->uie_timer, rtc_uie_timer, (unsigned long)rtc);

#endif



cdev_init(&rtc->char_dev, &rtc_dev_fops);看到这个函数应该很熟悉,这个是字符设备驱动中常用的函数,可是你有没有觉得少了点什么?设备号在什么时候申请的?而且没有cdev_add函数?


现在回答第一个问题——设备号在什么时候申请的?


大家还记得在第一篇中的/drivers/rtc/class.c这个文件吗?


有如下代码:


subsys_initcall(rtc_init);


static int __init rtc_init(void)

{

rtc_class = class_create(THIS_MODULE, "rtc");

if (IS_ERR(rtc_class)) {

printk(KERN_ERR "%s: couldn't create classn", __FILE__);

return PTR_ERR(rtc_class);

}

rtc_class->suspend = rtc_suspend;

rtc_class->resume = rtc_resume;

rtc_dev_init();重点来了。请关注:


void __init rtc_dev_init(void)

{

int err;



err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc");

if (err < 0)

printk(KERN_ERR "%s: failed to allocate char dev regionn",

__FILE__);

}看到了吗?设备号在这里申请的。

rtc_sysfs_init(rtc_class);

return 0;

}


接着回答第二个问题——而且没有cdev_add函数?这个在下面的某个函数中,会有答案。先揭露一点就在下面这个函数中rtc_dev_add_device。


其中函数实参为,在/drivers/rtc/rtc-dev.c文件中定义。


static const struct file_operations rtc_dev_fops = {

.owner  = THIS_MODULE,

.llseek  = no_llseek,

.read = rtc_dev_read,

.poll = rtc_dev_poll,

.unlocked_ioctl= rtc_dev_ioctl,

.open = rtc_dev_open,

.release  = rtc_dev_release,

.fasync  = rtc_dev_fasync,

};

rtc->char_dev.owner = rtc->owner;

}

rtc_dev_prepare终于完了,现在回到rtc_device_register函数中。美好的时光总是短暂的,又到了一篇结束的时刻,就像灰太狼先生说的那样:“我还会回来的!”下篇见。


err = device_register(&rtc->dev);

if (err)

goto exit_kfree;



rtc_dev_add_device(rtc);

rtc_sysfs_add_device(rtc);

rtc_proc_add_device(rtc);



dev_info(dev, "rtc core: registered %s as %sn",

rtc->name, rtc->dev.bus_id);



return rtc;



exit_kfree:

kfree(rtc);



exit_idr:

mutex_lock(&idr_lock);

idr_remove(&rtc_idr, id);

mutex_unlock(&idr_lock);



exit:

dev_err(dev, "rtc core: unable to register %s, err = %dn",

name, err);

return ERR_PTR(err);

}




if (IS_ERR(rtc)) {

dev_err(&pdev->dev, "cannot attach rtcn");

ret = PTR_ERR(rtc);

goto err_nortc;

}



rtc->max_user_freq = S3C_MAX_CNT;



/* check rtc time */

for (bcd_loop = S3C2410_RTCSEC ; bcd_loop <= S3C2410_RTCYEAR ; bcd_loop +=0x4)

{

bcd_tmp = readb(s3c_rtc_base + bcd_loop);

if(((bcd_tmp & 0xf) > 0x9) || ((bcd_tmp & 0xf0) > 0x90))

writeb(0, s3c_rtc_base + bcd_loop);

}



platform_set_drvdata(pdev, rtc);



return 0;



 err_nortc:

s3c_rtc_enable(pdev, 0);

iounmap(s3c_rtc_base);


err_nomap:

release_resource(s3c_rtc_mem);



 err_nores:

return ret;

}

关键字:s3c6410  RTC  linux  驱动 引用地址:s3c6410的RTC在linux中的驱动(3)

上一篇:GPIO驱动相关笔记
下一篇:s3c6410的RTC在linux中的驱动(4)

推荐阅读最新更新时间:2024-11-01 20:16

MAX522 DAC驱动电荷泵产生可调负偏压
电荷泵是一种利用所谓的“快速”或“泵送”电容来储能的DC-DC(变换器).它们能使输入电压升高或降低,也可以用于产生负电压。其内部的FET开关阵列以一定方式控制快速电容器的充电和放电,从而使输入电压以一定因数(0.5,2或3)倍增或降低,从而得到所需要的输出电压。这种特别的调制过程可以保证高达80%的效率,而且只需外接陶瓷电容。由于电路是开关工作的,电荷泵结构也会产生一定的输出纹波和EMI(电磁干扰 )
[模拟电子]
TI推用于电机控制的业界最小栅极驱动器和功率MOSFET解决方案
近日,德州仪器 (TI) 推出两款新型器件,有助于减小电机驱动应用的尺寸和重量。当两者结合使用时,DRV832x无刷直流(BLDC)栅极驱动器和CSD88584/99 NexFET™电源模块只需占用511 mm2的电路板空间,仅为其他同类解决方案的一半。 DRV832x BLDC栅极驱动器采用智能栅极驱动架构,省去传统架构中用于设置栅极驱动电流的24个部件,使设计人员能够轻松调整场效应晶体管(FET)开关,从而优化功耗和电磁兼容性。CSD88584Q5DC和CSD88599Q5DC电源模块利用独特的堆叠式晶片封装结构的两个FET,使功率密度提高一倍,并最大限度地减少并联FET中典型的FET电阻和寄生电感。 紧凑的18伏BLDC电机
[电源管理]
TI推用于电机控制的业界最小栅极<font color='red'>驱动</font>器和功率MOSFET解决方案
面向小型LCD背光的LED驱动电路设计技巧
彩色 LCD 显示屏 需要白色背光,以便用户在任何光照环境下都能正常地观看。这个背 光子 系统包括1个高 亮度 白光发光二极管( led )阵列、1个扩散器(diffuser)以扩散光线和1个背光 驱动 器将可用 电能 稳压为恒定电流以驱动LED。一块1到1.5英寸的显示屏可能包含2到4个LED,而一块3.5英寸显示屏则可能轻易地就包含6到10个LED。对于LED而言,其光输出与电流成正比,而且由于LED具有非常陡峭的电流-电压(I-V)曲线,流过LED的电流紧密匹配是非常重要,这样才能确保均衡背光,因为LED通常分布在LCD显示屏的一边。此外,也需要软件控制让用户调节亮度,以及针对周围光照环境作出补偿。根据流经LED电流
[电源管理]
面向小型LCD背光的LED<font color='red'>驱动</font>电路设计技巧
Tolley推出可以行走的四足软体机器人,靠气体驱动可征服各种地形
在几年前的智能机器人与系统国际会议上(IROS),哈佛研究生 chael Tolley 向我们介绍了一款依靠爆炸力进行弹跳的机器人。这款粉红色的柔软机器人有三条可以左右摇摆并负责定位的腿,不过这家伙的长相实在是太对不起观众了。现在,Tolley 在加州大学圣地亚哥分校已经有了自己的机器人实验室,该实验室的主要工作就是找到有效的制造软体机器人的方法。在的论文中(下周发表在 ICRA),Tolley 展示了可以行走的四足软体机器人。 软体机器人(搭载有)潜力巨大,它们廉价、灵活,且易于配置。不过以现在的技术水平来看,软体机器人可不好造,因为你必须手工完成一系列复杂的操作。 Dylan Drotman 与 Tolley 实
[机器人]
74hc164驱动数码管程序
#i nclude reg51.h #define uint unsigned int #define uchar unsigned char sbit DAT=P1^1; //模拟串口数据发送端 sbit CLK=P1^2;//模拟时钟控制端 uchar co de tab ={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xff};//0-9,-,全灭 (共阳字段表) void sendbyte(uchar byte) { uchar num,c; num=tab ; for(c=0;c 8;c++) { C
[单片机]
单片机驱动19264a液晶显示英文程序
19264液晶是一种比12864大一点点的单色液晶,这里我给大家介绍一下用单片机驱动他的原理 电路图 仿真图 实际效果图 #include stc89.h #include intrins.h #define uchar unsigned char #define uint unsigned int uint ee; sbit lcd_cs3=P1^0;//片选信号右 低有效 sbit lcd_cs2=P1^1;//片选信号中 低有效 sbit lcd_cs1=P1^2;//片选信号左 低有效 sbit lcd_e =P1^3;//使能信号 sbit lcd_rw =P1^4;//读写选择 sbit lcd_rs =P
[单片机]
单片机<font color='red'>驱动</font>19264a液晶显示英文程序
51单片机驱动点阵16*16上移C程序
#include reg52.h #define uchar unsigned char #define uint unsigned int #define LINE P0//定义行线IO口,即74HC154控制端 #define shudu 20//字移动的速度 sbit DATA=P1^4;//74HC595数据端 sbit CLK=P1^5;//74HC595移位脉冲端 sbit CLKR=P1^6;//74HC595数据锁存端 uchar move;//移动几位变量 uchar line;//行变量 uchar word;//字节变量 uchar ji;//字节变量 uchar code table ={ 0x00,
[单片机]
51单片机<font color='red'>驱动</font>点阵16*16上移C程序
基于S3C2410的TFT-LCD驱动电路设计
随着电子技术的迅猛发展,具有耗电少、亮度高、体积小等特点的液晶显示器被广泛应用于嵌入式系统中。S3C2410是三星公司开发的一款以ARM920T为核心的16/32位嵌入式处理器。它主要面向手持设备以及高性价比、低功耗的应用。LTS350Q1-PE1是三星电子公司生产的一款非晶硅有源矩阵TFT-LCD,它具有功耗低、亮度高和体积小等特点,目前在嵌入式设备中应用非常广泛。 基于S3C2410,采用LTS350Q1-PE1作为显示设备可以构成一个基于嵌入式平台的液晶显示系统,如图1所示,该系统可以满足大多数嵌入式手持设备的功能要求。但是,要想S3C2410的LCD控制器可以正确有效地控制TFT-LCD,需要设计两者之间的硬
[单片机]
基于S3C2410的TFT-LCD<font color='red'>驱动</font>电路设计
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved