linux2.6.27下做DS1302驱动的问题

发布于 2022-09-18 18:26:47 字数 260 浏览 18 评论 0

小弟用的内核版本是2.6.27,处理器AT91RM9200。在内核目录linux-2.6.27/drivers/char,找到ds1302.c文件。大致看了源码,但是不知道如何去修改,请大侠指导。
PA6   <------->   RST
PA22  <------->   CLK
PA23  <------->   I/O

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

南冥有猫 2022-09-25 18:26:47

附上ds1302.c的代码。

/*!***************************************************************************
*!
*! FILE NAME  : ds1302.c
*!
*! DESCRIPTION: Implements an interface for the DS1302 RTC
*!
*! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init, get_rtc_status
*!
*! ---------------------------------------------------------------------------
*!
*! (C) Copyright 1999, 2000, 2001  Axis Communications AB, LUND, SWEDEN
*!
*!***************************************************************************/

#include <linux/fs.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/bcd.h>
#include <linux/smp_lock.h>
#include <linux/uaccess.h>
#include <linux/io.h>

#include <asm/system.h>
#include <asm/rtc.h>
#if defined(CONFIG_M32R)
#include <asm/m32r.h>
#endif

#define RTC_MAJOR_NR 121 /* local major, change later */

static const char ds1302_name[] = "ds1302";

/* Send 8 bits. */
static void
out_byte_rtc(unsigned int reg_addr, unsigned char x)
{
    //RST H

    outw(0x0001,(unsigned long)PLD_RTCRSTODT);
    //write data

    outw(((x<<8)|(reg_addr&0xff)),(unsigned long)PLD_RTCWRDATA);
    //WE

    outw(0x0002,(unsigned long)PLD_RTCCR);
    //wait

    while(inw((unsigned long)PLD_RTCCR));

    //RST L

    outw(0x0000,(unsigned long)PLD_RTCRSTODT);

}

static unsigned char
in_byte_rtc(unsigned int reg_addr)
{
    unsigned char retval;

    //RST H

    outw(0x0001,(unsigned long)PLD_RTCRSTODT);
    //write data

    outw((reg_addr&0xff),(unsigned long)PLD_RTCRDDATA);
    //RE

    outw(0x0001,(unsigned long)PLD_RTCCR);
    //wait

    while(inw((unsigned long)PLD_RTCCR));

    //read data

    retval=(inw((unsigned long)PLD_RTCRDDATA) & 0xff00)>>8;

    //RST L

    outw(0x0000,(unsigned long)PLD_RTCRSTODT);

    return retval;
}

/* Enable writing. */

static void
ds1302_wenable(void)
{
    out_byte_rtc(0x8e,0x00);
}

/* Disable writing. */

static void
ds1302_wdisable(void)
{
    out_byte_rtc(0x8e,0x80);
}

/* Read a byte from the selected register in the DS1302. */

unsigned char
ds1302_readreg(int reg)
{
    unsigned char x;

    x=in_byte_rtc((0x81 | (reg << 1))); /* read register */

    return x;
}

/* Write a byte to the selected register. */

void
ds1302_writereg(int reg, unsigned char val)
{
    ds1302_wenable();
    out_byte_rtc((0x80 | (reg << 1)),val);
    ds1302_wdisable();
}

void
get_rtc_time(struct rtc_time *rtc_tm)
{
    unsigned long flags;

    local_irq_save(flags);

    rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);
    rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);
    rtc_tm->tm_hour = CMOS_READ(RTC_HOURS);
    rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
    rtc_tm->tm_mon = CMOS_READ(RTC_MONTH);
    rtc_tm->tm_year = CMOS_READ(RTC_YEAR);

    local_irq_restore(flags);

    BCD_TO_BIN(rtc_tm->tm_sec);
    BCD_TO_BIN(rtc_tm->tm_min);
    BCD_TO_BIN(rtc_tm->tm_hour);
    BCD_TO_BIN(rtc_tm->tm_mday);
    BCD_TO_BIN(rtc_tm->tm_mon);
    BCD_TO_BIN(rtc_tm->tm_year);

    /*
     * Account for differences between how the RTC uses the values
     * and how they are defined in a struct rtc_time;
     */

    if (rtc_tm->tm_year <= 69)
        rtc_tm->tm_year += 100;

    rtc_tm->tm_mon--;
}

static unsigned char days_in_mo[] =
    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

/* ioctl that supports RTC_RD_TIME and RTC_SET_TIME (read and set time/date). */

static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    unsigned long flags;

    switch(cmd) {
        case RTC_RD_TIME:    /* read the time/date from RTC    */
        {
            struct rtc_time rtc_tm;

            memset(&rtc_tm, 0, sizeof (struct rtc_time));
            lock_kernel();
            get_rtc_time(&rtc_tm);
            unlock_kernel();
            if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time)))
                return -EFAULT;
            return 0;
        }

        case RTC_SET_TIME:    /* set the RTC */
        {
            struct rtc_time rtc_tm;
            unsigned char mon, day, hrs, min, sec, leap_yr;
            unsigned int yrs;

            if (!capable(CAP_SYS_TIME))
                return -EPERM;

            if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time)))
                return -EFAULT;

            yrs = rtc_tm.tm_year + 1900;
            mon = rtc_tm.tm_mon + 1;   /* tm_mon starts at zero */
            day = rtc_tm.tm_mday;
            hrs = rtc_tm.tm_hour;
            min = rtc_tm.tm_min;
            sec = rtc_tm.tm_sec;

            if ((yrs < 1970) || (yrs > 2069))
                return -EINVAL;

            leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));

            if ((mon > 12) || (day == 0))
                return -EINVAL;

            if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
                return -EINVAL;

            if ((hrs >= 24) || (min >= 60) || (sec >= 60))
                return -EINVAL;

            if (yrs >= 2000)
                yrs -= 2000;    /* RTC (0, 1, ... 69) */
            else
                yrs -= 1900;    /* RTC (70, 71, ... 99) */

            BIN_TO_BCD(sec);
            BIN_TO_BCD(min);
            BIN_TO_BCD(hrs);
            BIN_TO_BCD(day);
            BIN_TO_BCD(mon);
            BIN_TO_BCD(yrs);

            lock_kernel();
            local_irq_save(flags);
            CMOS_WRITE(yrs, RTC_YEAR);
            CMOS_WRITE(mon, RTC_MONTH);
            CMOS_WRITE(day, RTC_DAY_OF_MONTH);
            CMOS_WRITE(hrs, RTC_HOURS);
            CMOS_WRITE(min, RTC_MINUTES);
            CMOS_WRITE(sec, RTC_SECONDS);
            local_irq_restore(flags);
            unlock_kernel();

            /* Notice that at this point, the RTC is updated but
             * the kernel is still running with the old time.
             * You need to set that separately with settimeofday
             * or adjtimex.
             */

            return 0;
        }

        case RTC_SET_CHARGE: /* set the RTC TRICKLE CHARGE register */
        {
            int tcs_val;

            if (!capable(CAP_SYS_TIME))
                return -EPERM;

            if(copy_from_user(&tcs_val, (int*)arg, sizeof(int)))
                return -EFAULT;

            lock_kernel();
            tcs_val = RTC_TCR_PATTERN | (tcs_val & 0x0F);
            ds1302_writereg(RTC_TRICKLECHARGER, tcs_val);
            unlock_kernel();
            return 0;
        }
        default:
            return -EINVAL;
    }
}

int
get_rtc_status(char *buf)
{
    char *p;
    struct rtc_time tm;

    p = buf;

    get_rtc_time(&tm);

    /*
     * There is no way to tell if the luser has the RTC set for local
     * time or for Universal Standard Time (GMT). Probably local though.
     */

    p += sprintf(p,
        "rtc_time\t: %02d:%02d:%02d\n"
        "rtc_date\t: %04d-%02d-%02d\n",
        tm.tm_hour, tm.tm_min, tm.tm_sec,
        tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);

    return  p - buf;
}

/* The various file operations we support. */

static const struct file_operations rtc_fops = {
    .owner        = THIS_MODULE,
    .unlocked_ioctl    = rtc_ioctl,
};

/* Probe for the chip by writing something to its RAM and try reading it back. */

#define MAGIC_PATTERN 0x42

static int __init
ds1302_probe(void)
{
    int retval, res, baur;

    baur=(boot_cpu_data.bus_clock/(2*1000*1000));

    printk("%s: Set PLD_RTCBAUR = %d\n", ds1302_name,baur);

    outw(0x0000,(unsigned long)PLD_RTCCR);
    outw(0x0000,(unsigned long)PLD_RTCRSTODT);
    outw(baur,(unsigned long)PLD_RTCBAUR);

    /* Try to talk to timekeeper. */

    ds1302_wenable();
    /* write RAM byte 0 */
    /* write something magic */
    out_byte_rtc(0xc0,MAGIC_PATTERN);

    /* read RAM byte 0 */
    if((res = in_byte_rtc(0xc1)) == MAGIC_PATTERN) {
        char buf[100];
        ds1302_wdisable();
        printk("%s: RTC found.\n", ds1302_name);
        get_rtc_status(buf);
        printk(buf);
        retval = 1;
    } else {
        printk("%s: RTC not found.\n", ds1302_name);
        retval = 0;
    }

    return retval;
}

/* Just probe for the RTC and register the device to handle the ioctl needed. */

int __init
ds1302_init(void)
{
    if (!ds1302_probe()) {
        return -1;
      }
    return 0;
}

static int __init ds1302_register(void)
{
    ds1302_init();
    if (register_chrdev(RTC_MAJOR_NR, ds1302_name, &rtc_fops)) {
        printk(KERN_INFO "%s: unable to get major %d for rtc\n",
               ds1302_name, RTC_MAJOR_NR);
        return -1;
    }
    return 0;
}

module_init(ds1302_register);

静谧 2022-09-25 18:26:47

你先把你要做什么,以及这段代码是如何工作的搞清楚再说吧

未央 2022-09-25 18:26:47

谢谢楼主

橙味迷妹 2022-09-25 18:26:47

原帖由 zhj1011 于 2009-4-7 17:00 发表
谢谢楼主

You are楼主

何以心动 2022-09-25 18:26:47

原帖由 dreamice 于 2009/4/7 19:27 发表

You are楼主

BZ先生, 不要这么惊讶

伤痕我心 2022-09-25 18:26:47

LZ, 内核里有了驱动, 你还要做什么呢? 你没有详述你的需要和问题.

回首观望 2022-09-25 18:26:47

是这样的 2.6内核下面 有两个ds1302的驱动 一个位于drivers/char/ds1302.c 一个是drivers/rtc/rtc-ds1302.c
看了char下的Kconfig和rtc/Kconfig
drivers/char/ds1302.c 依赖于 M32R && (PLAT_M32700UT || PLAT_OPSPUT)
drivers/rtc/rtc-ds1302.c依赖于 depends on SH_SECUREEDGE5410
这两个驱动都不是针对ARM体系结构的。
我现在是要做一个AT91RM9200上的DS1302驱动 通过三个GPIO管脚实现通信
我现在修改char/ds1302.c代码 编译通过后 加载到内核后 出错
移植这个非ARM体系结构的去到ARM体系结构下 需要修改哪些东西呢? 只是一些管脚的具体定义就OK了吗? 谢谢

江湖正好 2022-09-25 18:26:47

好像不止三个口啊,并口? arch/cris/arch-v10/drivers 下面有个 ds1302 的好像才是模拟的

[ 本帖最后由 star316 于 2009-4-8 11:37 编辑 ]

习惯成性 2022-09-25 18:26:47

手头没有2.6.27.   看了一下2.6.28的ds1302.c,  我认为你要先确认RTC的地址正确, 几个函数都是针对地址/寄存器的操作.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文