/drivers/rtc/rtc-s3c.c
822行
static struct platform_driver s3c_rtc_driver = {
    .probe        = s3c_rtc_probe,
    .remove        = s3c_rtc_remove,
    .driver        = {
        .name    = "s3c-rtc",
        .pm    = &s3c_rtc_pm_ops,
        .of_match_table    = of_match_ptr(s3c_rtc_dt_match),
    },
};
module_platform_driver(s3c_rtc_driver);

/arch/arm/plat-samsung/devs.c
836行
static struct resource s3c_rtc_resource[] = {
    [0] = DEFINE_RES_MEM(S3C24XX_PA_RTC, SZ_256),
    [1] = DEFINE_RES_IRQ(IRQ_RTC),
    [2] = DEFINE_RES_IRQ(IRQ_TICK),
};

struct platform_device s3c_device_rtc = {
    .name        = "s3c-rtc", //修改此处 和 s3c_rtc_driver 中的 .name 相同
    .id        = -1,
    .num_resources    = ARRAY_SIZE(s3c_rtc_resource),
    .resource    = s3c_rtc_resource,
};

修改 mach-smdk2440.c 中添加设备
static struct platform_device *smdk2440_devices[] __initdata = {
    &s3c_device_ohci,
    &s3c_device_lcd,
    &s3c_device_wdt,
    &s3c_device_i2c0,
    &s3c_device_iis,
    &dm9000_device_eth,
    &s3c_device_rtc, //添加此项
};

make uImage 使用新内核 启动
错误信息
Unable to handle kernel NULL pointer dereference at virtual address 000000c0
pgd = c0004000
[000000c0] *pgd=00000000
Internal error: Oops: 5 [#1] ARM
Modules linked in:
CPU: 0 PID: 1 Comm: swapper Not tainted 4.1.36 #73
Hardware name: SMDK2440
task: c381faa0 ti: c3822000 task.ti: c3822000
PC is at s3c_rtc_probe+0x4c/0x3f0
LR is at s3c_rtc_probe+0x38/0x3f0

经过 printk 大法以后定位到 s3c_rtc_get_data() 出现空指针问题

static const struct of_device_id s3c_rtc_dt_match[];

static struct s3c_rtc_data *s3c_rtc_get_data(struct platform_device *pdev)
{
    const struct of_device_id *match;

match = of_match_node(s3c_rtc_dt_match, pdev->dev.of_node);
    return (struct s3c_rtc_data *)match->data;
}

改为
static struct s3c_rtc_data *s3c_rtc_get_data(struct platform_device *pdev)
{
    const struct of_device_id *match;
    match = of_match_node(s3c_rtc_dt_match, pdev->dev.of_node);
    if(NULL != match)
    {
        return (struct s3c_rtc_data *)match->data;
    }
    return NULL;
}

改了以后,启动不报空指针错误了。但是还是不能用rtc 。

要自己实现这么一个函数
添加一个函数声明
static struct s3c_rtc_data *get_s3c_2410_data(void);

在最下面添加实现
static struct s3c_rtc_data *get_s3c_2410_data(void)
{
    return (struct s3c_rtc_data *)&s3c2410_rtc_data;
}

rtc-s3c.c

/* drivers/rtc/rtc-s3c.c
*
* Copyright (c) 2010 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
* Copyright (c) 2004,2006 Simtec Electronics
* Ben Dooks, <ben@simtec.co.uk>
* http://armlinux.simtec.co.uk/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* S3C2410/S3C2440/S3C24XX Internal RTC Driver
*/ #include <linux/module.h>
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/rtc.h>
#include <linux/bcd.h>
#include <linux/clk.h>
#include <linux/log2.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/uaccess.h>
#include <linux/io.h> #include <asm/irq.h>
#include "rtc-s3c.h" struct s3c_rtc {
struct device *dev;
struct rtc_device *rtc; void __iomem *base;
struct clk *rtc_clk;
struct clk *rtc_src_clk;
bool clk_disabled; struct s3c_rtc_data *data; int irq_alarm;
int irq_tick; spinlock_t pie_lock;
spinlock_t alarm_clk_lock; int ticnt_save, ticnt_en_save;
bool wake_en;
}; struct s3c_rtc_data {
int max_user_freq;
bool needs_src_clk; void (*irq_handler) (struct s3c_rtc *info, int mask);
void (*set_freq) (struct s3c_rtc *info, int freq);
void (*enable_tick) (struct s3c_rtc *info, struct seq_file *seq);
void (*select_tick_clk) (struct s3c_rtc *info);
void (*save_tick_cnt) (struct s3c_rtc *info);
void (*restore_tick_cnt) (struct s3c_rtc *info);
void (*enable) (struct s3c_rtc *info);
void (*disable) (struct s3c_rtc *info);
};
static struct s3c_rtc_data *get_s3c_2410_data(void);
static void s3c_rtc_enable_clk(struct s3c_rtc *info)
{
unsigned long irq_flags; spin_lock_irqsave(&info->alarm_clk_lock, irq_flags);
if (info->clk_disabled) {
clk_enable(info->rtc_clk);
if (info->data->needs_src_clk)
clk_enable(info->rtc_src_clk);
info->clk_disabled = false;
}
spin_unlock_irqrestore(&info->alarm_clk_lock, irq_flags);
} static void s3c_rtc_disable_clk(struct s3c_rtc *info)
{
unsigned long irq_flags; spin_lock_irqsave(&info->alarm_clk_lock, irq_flags);
if (!info->clk_disabled) {
if (info->data->needs_src_clk)
clk_disable(info->rtc_src_clk);
clk_disable(info->rtc_clk);
info->clk_disabled = true;
}
spin_unlock_irqrestore(&info->alarm_clk_lock, irq_flags);
} /* IRQ Handlers */
static irqreturn_t s3c_rtc_tickirq(int irq, void *id)
{
struct s3c_rtc *info = (struct s3c_rtc *)id; if (info->data->irq_handler)
info->data->irq_handler(info, S3C2410_INTP_TIC); return IRQ_HANDLED;
} static irqreturn_t s3c_rtc_alarmirq(int irq, void *id)
{
struct s3c_rtc *info = (struct s3c_rtc *)id; if (info->data->irq_handler)
info->data->irq_handler(info, S3C2410_INTP_ALM); return IRQ_HANDLED;
} /* Update control registers */
static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
{
struct s3c_rtc *info = dev_get_drvdata(dev);
unsigned int tmp; dev_dbg(info->dev, "%s: aie=%d\n", __func__, enabled); s3c_rtc_enable_clk(info); tmp = readb(info->base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN; if (enabled)
tmp |= S3C2410_RTCALM_ALMEN; writeb(tmp, info->base + S3C2410_RTCALM); s3c_rtc_disable_clk(info); if (enabled)
s3c_rtc_enable_clk(info);
else
s3c_rtc_disable_clk(info); return ;
} /* Set RTC frequency */
static int s3c_rtc_setfreq(struct s3c_rtc *info, int freq)
{
if (!is_power_of_2(freq))
return -EINVAL; s3c_rtc_enable_clk(info);
spin_lock_irq(&info->pie_lock); if (info->data->set_freq)
info->data->set_freq(info, freq); spin_unlock_irq(&info->pie_lock);
s3c_rtc_disable_clk(info); return ;
} /* Time read/write */
static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
{
struct s3c_rtc *info = dev_get_drvdata(dev);
unsigned int have_retried = ; s3c_rtc_enable_clk(info); retry_get_time:
rtc_tm->tm_min = readb(info->base + S3C2410_RTCMIN);
rtc_tm->tm_hour = readb(info->base + S3C2410_RTCHOUR);
rtc_tm->tm_mday = readb(info->base + S3C2410_RTCDATE);
rtc_tm->tm_mon = readb(info->base + S3C2410_RTCMON);
rtc_tm->tm_year = readb(info->base + S3C2410_RTCYEAR);
rtc_tm->tm_sec = readb(info->base + S3C2410_RTCSEC); /* the only way to work out whether the system was mid-update
* when we read it is to check the second counter, and if it
* is zero, then we re-try the entire read
*/ if (rtc_tm->tm_sec == && !have_retried) {
have_retried = ;
goto retry_get_time;
} rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec);
rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min);
rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour);
rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday);
rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon);
rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year); s3c_rtc_disable_clk(info); rtc_tm->tm_year += ; dev_dbg(dev, "read time %04d.%02d.%02d %02d:%02d:%02d\n",
+ rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec); rtc_tm->tm_mon -= ; return rtc_valid_tm(rtc_tm);
} static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
{
struct s3c_rtc *info = dev_get_drvdata(dev);
int year = tm->tm_year - ; dev_dbg(dev, "set time %04d.%02d.%02d %02d:%02d:%02d\n",
+ tm->tm_year, tm->tm_mon, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec); /* we get around y2k by simply not supporting it */ if (year < || year >= ) {
dev_err(dev, "rtc only supports 100 years\n");
return -EINVAL;
} s3c_rtc_enable_clk(info); writeb(bin2bcd(tm->tm_sec), info->base + S3C2410_RTCSEC);
writeb(bin2bcd(tm->tm_min), info->base + S3C2410_RTCMIN);
writeb(bin2bcd(tm->tm_hour), info->base + S3C2410_RTCHOUR);
writeb(bin2bcd(tm->tm_mday), info->base + S3C2410_RTCDATE);
writeb(bin2bcd(tm->tm_mon + ), info->base + S3C2410_RTCMON);
writeb(bin2bcd(year), info->base + S3C2410_RTCYEAR); s3c_rtc_disable_clk(info); return ;
} static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct s3c_rtc *info = dev_get_drvdata(dev);
struct rtc_time *alm_tm = &alrm->time;
unsigned int alm_en; s3c_rtc_enable_clk(info); alm_tm->tm_sec = readb(info->base + S3C2410_ALMSEC);
alm_tm->tm_min = readb(info->base + S3C2410_ALMMIN);
alm_tm->tm_hour = readb(info->base + S3C2410_ALMHOUR);
alm_tm->tm_mon = readb(info->base + S3C2410_ALMMON);
alm_tm->tm_mday = readb(info->base + S3C2410_ALMDATE);
alm_tm->tm_year = readb(info->base + S3C2410_ALMYEAR); alm_en = readb(info->base + S3C2410_RTCALM); s3c_rtc_disable_clk(info); alrm->enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? : ; dev_dbg(dev, "read alarm %d, %04d.%02d.%02d %02d:%02d:%02d\n",
alm_en,
+ alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday,
alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec); /* decode the alarm enable field */
if (alm_en & S3C2410_RTCALM_SECEN)
alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec);
else
alm_tm->tm_sec = -; if (alm_en & S3C2410_RTCALM_MINEN)
alm_tm->tm_min = bcd2bin(alm_tm->tm_min);
else
alm_tm->tm_min = -; if (alm_en & S3C2410_RTCALM_HOUREN)
alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour);
else
alm_tm->tm_hour = -; if (alm_en & S3C2410_RTCALM_DAYEN)
alm_tm->tm_mday = bcd2bin(alm_tm->tm_mday);
else
alm_tm->tm_mday = -; if (alm_en & S3C2410_RTCALM_MONEN) {
alm_tm->tm_mon = bcd2bin(alm_tm->tm_mon);
alm_tm->tm_mon -= ;
} else {
alm_tm->tm_mon = -;
} if (alm_en & S3C2410_RTCALM_YEAREN)
alm_tm->tm_year = bcd2bin(alm_tm->tm_year);
else
alm_tm->tm_year = -; return ;
} static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct s3c_rtc *info = dev_get_drvdata(dev);
struct rtc_time *tm = &alrm->time;
unsigned int alrm_en; dev_dbg(dev, "s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n",
alrm->enabled,
+ tm->tm_year, tm->tm_mon + , tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec); s3c_rtc_enable_clk(info); alrm_en = readb(info->base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN;
writeb(0x00, info->base + S3C2410_RTCALM); if (tm->tm_sec < && tm->tm_sec >= ) {
alrm_en |= S3C2410_RTCALM_SECEN;
writeb(bin2bcd(tm->tm_sec), info->base + S3C2410_ALMSEC);
} if (tm->tm_min < && tm->tm_min >= ) {
alrm_en |= S3C2410_RTCALM_MINEN;
writeb(bin2bcd(tm->tm_min), info->base + S3C2410_ALMMIN);
} if (tm->tm_hour < && tm->tm_hour >= ) {
alrm_en |= S3C2410_RTCALM_HOUREN;
writeb(bin2bcd(tm->tm_hour), info->base + S3C2410_ALMHOUR);
} dev_dbg(dev, "setting S3C2410_RTCALM to %08x\n", alrm_en); writeb(alrm_en, info->base + S3C2410_RTCALM); s3c_rtc_disable_clk(info); s3c_rtc_setaie(dev, alrm->enabled); return ;
} static int s3c_rtc_proc(struct device *dev, struct seq_file *seq)
{
struct s3c_rtc *info = dev_get_drvdata(dev); s3c_rtc_enable_clk(info); if (info->data->enable_tick)
info->data->enable_tick(info, seq); s3c_rtc_disable_clk(info); return ;
} static const struct rtc_class_ops s3c_rtcops = {
.read_time = s3c_rtc_gettime,
.set_time = s3c_rtc_settime,
.read_alarm = s3c_rtc_getalarm,
.set_alarm = s3c_rtc_setalarm,
.proc = s3c_rtc_proc,
.alarm_irq_enable = s3c_rtc_setaie,
}; static void s3c24xx_rtc_enable(struct s3c_rtc *info)
{
unsigned int con, tmp; con = readw(info->base + S3C2410_RTCCON);
/* re-enable the device, and check it is ok */
if ((con & S3C2410_RTCCON_RTCEN) == ) {
dev_info(info->dev, "rtc disabled, re-enabling\n"); tmp = readw(info->base + S3C2410_RTCCON);
writew(tmp | S3C2410_RTCCON_RTCEN,
info->base + S3C2410_RTCCON);
} if (con & S3C2410_RTCCON_CNTSEL) {
dev_info(info->dev, "removing RTCCON_CNTSEL\n"); tmp = readw(info->base + S3C2410_RTCCON);
writew(tmp & ~S3C2410_RTCCON_CNTSEL,
info->base + S3C2410_RTCCON);
} if (con & S3C2410_RTCCON_CLKRST) {
dev_info(info->dev, "removing RTCCON_CLKRST\n"); tmp = readw(info->base + S3C2410_RTCCON);
writew(tmp & ~S3C2410_RTCCON_CLKRST,
info->base + S3C2410_RTCCON);
}
} static void s3c24xx_rtc_disable(struct s3c_rtc *info)
{
unsigned int con; con = readw(info->base + S3C2410_RTCCON);
con &= ~S3C2410_RTCCON_RTCEN;
writew(con, info->base + S3C2410_RTCCON); con = readb(info->base + S3C2410_TICNT);
con &= ~S3C2410_TICNT_ENABLE;
writeb(con, info->base + S3C2410_TICNT);
} static void s3c6410_rtc_disable(struct s3c_rtc *info)
{
unsigned int con; con = readw(info->base + S3C2410_RTCCON);
con &= ~S3C64XX_RTCCON_TICEN;
con &= ~S3C2410_RTCCON_RTCEN;
writew(con, info->base + S3C2410_RTCCON);
} static int s3c_rtc_remove(struct platform_device *pdev)
{
struct s3c_rtc *info = platform_get_drvdata(pdev); s3c_rtc_setaie(info->dev, ); clk_unprepare(info->rtc_clk);
info->rtc_clk = NULL; return ;
} static const struct of_device_id s3c_rtc_dt_match[]; static struct s3c_rtc_data *s3c_rtc_get_data(struct platform_device *pdev)
{
const struct of_device_id *match; match = of_match_node(s3c_rtc_dt_match, pdev->dev.of_node);
if(NULL != match)
{
return (struct s3c_rtc_data *)match->data;
}
return NULL;
} static int s3c_rtc_probe(struct platform_device *pdev)
{
struct s3c_rtc *info = NULL;
struct rtc_time rtc_tm;
struct resource *res;
int ret; info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM; /* find the IRQs */
info->irq_tick = platform_get_irq(pdev, );
if (info->irq_tick < ) {
dev_err(&pdev->dev, "no irq for rtc tick\n");
return info->irq_tick;
} info->dev = &pdev->dev;
//改为自己实现的函数
//info->data = s3c_rtc_get_data(pdev);
info->data = get_s3c_2410_data();
if (!info->data) {
dev_err(&pdev->dev, "failed getting s3c_rtc_data\n");
return -EINVAL;
}
spin_lock_init(&info->pie_lock);
spin_lock_init(&info->alarm_clk_lock); platform_set_drvdata(pdev, info); info->irq_alarm = platform_get_irq(pdev, );
if (info->irq_alarm < ) {
dev_err(&pdev->dev, "no irq for alarm\n");
return info->irq_alarm;
} dev_dbg(&pdev->dev, "s3c2410_rtc: tick irq %d, alarm irq %d\n",
info->irq_tick, info->irq_alarm); /* get the memory region */
res = platform_get_resource(pdev, IORESOURCE_MEM, );
info->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(info->base))
return PTR_ERR(info->base); info->rtc_clk = devm_clk_get(&pdev->dev, "rtc");
if (IS_ERR(info->rtc_clk)) {
dev_err(&pdev->dev, "failed to find rtc clock\n");
return PTR_ERR(info->rtc_clk);
}
clk_prepare_enable(info->rtc_clk); if (info->data->needs_src_clk) {
info->rtc_src_clk = devm_clk_get(&pdev->dev, "rtc_src");
if (IS_ERR(info->rtc_src_clk)) {
dev_err(&pdev->dev,
"failed to find rtc source clock\n");
return PTR_ERR(info->rtc_src_clk);
}
clk_prepare_enable(info->rtc_src_clk);
} /* check to see if everything is setup correctly */
if (info->data->enable)
info->data->enable(info); dev_dbg(&pdev->dev, "s3c2410_rtc: RTCCON=%02x\n",
readw(info->base + S3C2410_RTCCON)); device_init_wakeup(&pdev->dev, ); /* Check RTC Time */
if (s3c_rtc_gettime(&pdev->dev, &rtc_tm)) {
rtc_tm.tm_year = ;
rtc_tm.tm_mon = ;
rtc_tm.tm_mday = ;
rtc_tm.tm_hour = ;
rtc_tm.tm_min = ;
rtc_tm.tm_sec = ; s3c_rtc_settime(&pdev->dev, &rtc_tm); dev_warn(&pdev->dev, "warning: invalid RTC value so initializing it\n");
} /* register RTC and exit */
info->rtc = devm_rtc_device_register(&pdev->dev, "s3c", &s3c_rtcops,
THIS_MODULE);
if (IS_ERR(info->rtc)) {
dev_err(&pdev->dev, "cannot attach rtc\n");
ret = PTR_ERR(info->rtc);
goto err_nortc;
} ret = devm_request_irq(&pdev->dev, info->irq_alarm, s3c_rtc_alarmirq,
, "s3c2410-rtc alarm", info);
if (ret) {
dev_err(&pdev->dev, "IRQ%d error %d\n", info->irq_alarm, ret);
goto err_nortc;
} ret = devm_request_irq(&pdev->dev, info->irq_tick, s3c_rtc_tickirq,
, "s3c2410-rtc tick", info);
if (ret) {
dev_err(&pdev->dev, "IRQ%d error %d\n", info->irq_tick, ret);
goto err_nortc;
} if (info->data->select_tick_clk)
info->data->select_tick_clk(info); s3c_rtc_setfreq(info, ); s3c_rtc_disable_clk(info); return ; err_nortc:
if (info->data->disable)
info->data->disable(info); if (info->data->needs_src_clk)
clk_disable_unprepare(info->rtc_src_clk);
clk_disable_unprepare(info->rtc_clk); return ret;
} #ifdef CONFIG_PM_SLEEP static int s3c_rtc_suspend(struct device *dev)
{
struct s3c_rtc *info = dev_get_drvdata(dev); s3c_rtc_enable_clk(info); /* save TICNT for anyone using periodic interrupts */
if (info->data->save_tick_cnt)
info->data->save_tick_cnt(info); if (info->data->disable)
info->data->disable(info); if (device_may_wakeup(dev) && !info->wake_en) {
if (enable_irq_wake(info->irq_alarm) == )
info->wake_en = true;
else
dev_err(dev, "enable_irq_wake failed\n");
} return ;
} static int s3c_rtc_resume(struct device *dev)
{
struct s3c_rtc *info = dev_get_drvdata(dev); if (info->data->enable)
info->data->enable(info); if (info->data->restore_tick_cnt)
info->data->restore_tick_cnt(info); s3c_rtc_disable_clk(info); if (device_may_wakeup(dev) && info->wake_en) {
disable_irq_wake(info->irq_alarm);
info->wake_en = false;
} return ;
}
#endif
static SIMPLE_DEV_PM_OPS(s3c_rtc_pm_ops, s3c_rtc_suspend, s3c_rtc_resume); static void s3c24xx_rtc_irq(struct s3c_rtc *info, int mask)
{
rtc_update_irq(info->rtc, , RTC_AF | RTC_IRQF);
} static void s3c6410_rtc_irq(struct s3c_rtc *info, int mask)
{
rtc_update_irq(info->rtc, , RTC_AF | RTC_IRQF);
writeb(mask, info->base + S3C2410_INTP);
} static void s3c2410_rtc_setfreq(struct s3c_rtc *info, int freq)
{
unsigned int tmp = ;
int val; tmp = readb(info->base + S3C2410_TICNT);
tmp &= S3C2410_TICNT_ENABLE; val = (info->rtc->max_user_freq / freq) - ;
tmp |= val; writel(tmp, info->base + S3C2410_TICNT);
} static void s3c2416_rtc_setfreq(struct s3c_rtc *info, int freq)
{
unsigned int tmp = ;
int val; tmp = readb(info->base + S3C2410_TICNT);
tmp &= S3C2410_TICNT_ENABLE; val = (info->rtc->max_user_freq / freq) - ; tmp |= S3C2443_TICNT_PART(val);
writel(S3C2443_TICNT1_PART(val), info->base + S3C2443_TICNT1); writel(S3C2416_TICNT2_PART(val), info->base + S3C2416_TICNT2); writel(tmp, info->base + S3C2410_TICNT);
} static void s3c2443_rtc_setfreq(struct s3c_rtc *info, int freq)
{
unsigned int tmp = ;
int val; tmp = readb(info->base + S3C2410_TICNT);
tmp &= S3C2410_TICNT_ENABLE; val = (info->rtc->max_user_freq / freq) - ; tmp |= S3C2443_TICNT_PART(val);
writel(S3C2443_TICNT1_PART(val), info->base + S3C2443_TICNT1); writel(tmp, info->base + S3C2410_TICNT);
} static void s3c6410_rtc_setfreq(struct s3c_rtc *info, int freq)
{
int val; val = (info->rtc->max_user_freq / freq) - ;
writel(val, info->base + S3C2410_TICNT);
} static void s3c24xx_rtc_enable_tick(struct s3c_rtc *info, struct seq_file *seq)
{
unsigned int ticnt; ticnt = readb(info->base + S3C2410_TICNT);
ticnt &= S3C2410_TICNT_ENABLE; seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt ? "yes" : "no");
} static void s3c2416_rtc_select_tick_clk(struct s3c_rtc *info)
{
unsigned int con; con = readw(info->base + S3C2410_RTCCON);
con |= S3C2443_RTCCON_TICSEL;
writew(con, info->base + S3C2410_RTCCON);
} static void s3c6410_rtc_enable_tick(struct s3c_rtc *info, struct seq_file *seq)
{
unsigned int ticnt; ticnt = readw(info->base + S3C2410_RTCCON);
ticnt &= S3C64XX_RTCCON_TICEN; seq_printf(seq, "periodic_IRQ\t: %s\n", ticnt ? "yes" : "no");
} static void s3c24xx_rtc_save_tick_cnt(struct s3c_rtc *info)
{
info->ticnt_save = readb(info->base + S3C2410_TICNT);
} static void s3c24xx_rtc_restore_tick_cnt(struct s3c_rtc *info)
{
writeb(info->ticnt_save, info->base + S3C2410_TICNT);
} static void s3c6410_rtc_save_tick_cnt(struct s3c_rtc *info)
{
info->ticnt_en_save = readw(info->base + S3C2410_RTCCON);
info->ticnt_en_save &= S3C64XX_RTCCON_TICEN;
info->ticnt_save = readl(info->base + S3C2410_TICNT);
} static void s3c6410_rtc_restore_tick_cnt(struct s3c_rtc *info)
{
unsigned int con; writel(info->ticnt_save, info->base + S3C2410_TICNT);
if (info->ticnt_en_save) {
con = readw(info->base + S3C2410_RTCCON);
writew(con | info->ticnt_en_save,
info->base + S3C2410_RTCCON);
}
} static struct s3c_rtc_data const s3c2410_rtc_data = {
.max_user_freq = ,
.irq_handler = s3c24xx_rtc_irq,
.set_freq = s3c2410_rtc_setfreq,
.enable_tick = s3c24xx_rtc_enable_tick,
.save_tick_cnt = s3c24xx_rtc_save_tick_cnt,
.restore_tick_cnt = s3c24xx_rtc_restore_tick_cnt,
.enable = s3c24xx_rtc_enable,
.disable = s3c24xx_rtc_disable,
}; static struct s3c_rtc_data const s3c2416_rtc_data = {
.max_user_freq = ,
.irq_handler = s3c24xx_rtc_irq,
.set_freq = s3c2416_rtc_setfreq,
.enable_tick = s3c24xx_rtc_enable_tick,
.select_tick_clk = s3c2416_rtc_select_tick_clk,
.save_tick_cnt = s3c24xx_rtc_save_tick_cnt,
.restore_tick_cnt = s3c24xx_rtc_restore_tick_cnt,
.enable = s3c24xx_rtc_enable,
.disable = s3c24xx_rtc_disable,
}; static struct s3c_rtc_data const s3c2443_rtc_data = {
.max_user_freq = ,
.irq_handler = s3c24xx_rtc_irq,
.set_freq = s3c2443_rtc_setfreq,
.enable_tick = s3c24xx_rtc_enable_tick,
.select_tick_clk = s3c2416_rtc_select_tick_clk,
.save_tick_cnt = s3c24xx_rtc_save_tick_cnt,
.restore_tick_cnt = s3c24xx_rtc_restore_tick_cnt,
.enable = s3c24xx_rtc_enable,
.disable = s3c24xx_rtc_disable,
}; static struct s3c_rtc_data const s3c6410_rtc_data = {
.max_user_freq = ,
.needs_src_clk = true,
.irq_handler = s3c6410_rtc_irq,
.set_freq = s3c6410_rtc_setfreq,
.enable_tick = s3c6410_rtc_enable_tick,
.save_tick_cnt = s3c6410_rtc_save_tick_cnt,
.restore_tick_cnt = s3c6410_rtc_restore_tick_cnt,
.enable = s3c24xx_rtc_enable,
.disable = s3c6410_rtc_disable,
}; static struct s3c_rtc_data const exynos3250_rtc_data = {
.max_user_freq = ,
.needs_src_clk = true,
.irq_handler = s3c6410_rtc_irq,
.set_freq = s3c6410_rtc_setfreq,
.enable_tick = s3c6410_rtc_enable_tick,
.save_tick_cnt = s3c6410_rtc_save_tick_cnt,
.restore_tick_cnt = s3c6410_rtc_restore_tick_cnt,
.enable = s3c24xx_rtc_enable,
.disable = s3c6410_rtc_disable,
};
static struct s3c_rtc_data *get_s3c_2410_data(void)
{
return (struct s3c_rtc_data *)&s3c2410_rtc_data;
}
static const struct of_device_id s3c_rtc_dt_match[] = {
{
.compatible = "samsung,s3c2410-rtc",
.data = (void *)&s3c2410_rtc_data,
}, {
.compatible = "samsung,s3c2416-rtc",
.data = (void *)&s3c2416_rtc_data,
}, {
.compatible = "samsung,s3c2443-rtc",
.data = (void *)&s3c2443_rtc_data,
}, {
.compatible = "samsung,s3c6410-rtc",
.data = (void *)&s3c6410_rtc_data,
}, {
.compatible = "samsung,exynos3250-rtc",
.data = (void *)&exynos3250_rtc_data,
},
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, s3c_rtc_dt_match); static struct platform_driver s3c_rtc_driver = {
.probe = s3c_rtc_probe,
.remove = s3c_rtc_remove,
.driver = {
.name = "s3c-rtc",
.pm = &s3c_rtc_pm_ops,
.of_match_table = of_match_ptr(s3c_rtc_dt_match),
},
};
module_platform_driver(s3c_rtc_driver); MODULE_DESCRIPTION("Samsung S3C RTC Driver");
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:s3c2410-rtc");

linux4.1.36 2440 启用 RTC 支持的更多相关文章

  1. s3c2440 移值新内核 linux-4.1.36

    arm-linuxgcc version 4.3.2 经过试验,最高可以编译到 linux-4.1.36 ,在高的版本会有错误 ,可能是 GCC 编译器版本较低造成. 解压比较麻烦还要装一个 xz x ...

  2. linux4.1.36 解决 SPI 时钟找不到 不生成设备 device

    最初的问题是 编译内核添加了 spi 支持,配置了 board 后,加载25q64驱动不执行probe 函数. 然后发现是,spi-s3c24xx.c 中的 probe 没有执行完就退出了 没有生成 ...

  3. 检查浏览器是否已经启用Java支持功能

    <script type="text/javascript"> document.write("navigator对象的方法"+"< ...

  4. Druid.io启用SQL支持

    Druid.io的SQL功能虽然在试验阶段,但是也支持了大部分的功能,而且还可以通过 Avatica JDBC查看请求的json,有助于我们理解Druid.io的语法.Druid.io有个比较坑的是, ...

  5. 在Nginx/Openresty中启用http2支持

    转自个人博客 chinazt.cc 以下摘自http2的介绍: HTTP/2 源自 SPDY/2 SPDY 系列协议由谷歌开发,于 2009 年公开.它的设计目标是降低 50% 的页面加载时间.当下很 ...

  6. 第36讲 谈谈MySQL支持的事务隔离级别,以及悲观锁和乐观锁的原理和应用场景

    在日常开发中,尤其是业务开发,少不了利用 Java 对数据库进行基本的增删改查等数据操作,这也是 Java 工程师的必备技能之一.做好数据操作,不仅仅需要对 Java 语言相关框架的掌握,更需要对各种 ...

  7. 使用本地自签名证书为 React 项目启用 https 支持

    简介 现在是大前端的时代,我们在本地开发 React 项目非常方便.这不是本文的重点,今天要分享一个话题是,如何为这些本地的项目,添加 https 的支持.为什么要考虑这个问题呢?主要有几个原因 如果 ...

  8. tiny4412学习(三)之移植linux-4.x驱动(1)支持网卡驱动【转】

    本文转载自:http://blog.csdn.net/fengyuwuzu0519/article/details/74160686 一.思路 上一节我们通过DNW将内核.文件系统.设备树文件烧入到内 ...

  9. 【OF框架】在Visual Studio中启用Docker支持,编译生成,并在容器运行项目

    准备 本地已经安装Docker 一.添加Docker支持 第一步:查看本地Docker服务状态 第二步:项目添加Docker支持 第三步:选择Linux容器 第四步:点击启动 第五步:确认Docker ...

随机推荐

  1. SPACESNIFFER查看文件大小

  2. SpringMVC静态资源拦截的问题

    通常在web.xml中的核心控制器的DispatcherServlet中的url-pattern属性配置成类似“/”的拦截路径,但是会出现静态资源找不到的问题,比如js脚本.图片.css等无法加载,那 ...

  3. C++中字符串的表示与转换

    转换总结 1.char*转string:可以直接赋值. 2.char[]转string:可以直接赋值. 3.char*转char[]:不能直接赋值,可以循环char*字符串逐个字符赋值,也可以使用st ...

  4. stm32 flash 存储

    转载自: http://bbs.elecfans.com/jishu_388272_1_1.html 说到STM32的FLSAH,我们的第一反应是用来装程序的,实际上,STM32的片内FLASH不仅用 ...

  5. toString()和强制类型转换(String)的用法

    原来是String类型的才可以强转到String,不然会报 ClassCastException异常: 所有的引用类型都从Object类继承了toString方法.

  6. seaJs模块化开发简单入门

    随着前端技术的日益成熟,功能越来越丰富强大,规范也越来越健全,在这样的背景环境下很快便有了CommonJs.AMD.CMD等一系列规范,使前端发开趋向模块化.规范化.CMD模块化的代表之一就是国内开发 ...

  7. SQL注入攻击浅谈

    原理 SQL注入攻击指的是通过构建特殊的输入作为参数传入Web应用程序,而这些输入大都是SQL语法里的一些组合,通过执行SQL语句进而执行攻击者所要的操作,其主要原因是程序没有细致地过滤用户输入的数据 ...

  8. diary20180428

    17:05:59 今天早晨去了图书馆.学习了一把vscode.试图在河边看电脑,总有小虫不让我专心. 23:27:34 看纯黑直播打战神,有点感触. 动漫或游戏,角色觉醒,实力大增,小时候(甚至现在) ...

  9. 查看python库文档

    安装完python第三方库以后,经常需要查询其文档,其实python就自带文档查看器.可以查看所有内置库和第三方库的文档,虽然不是很详尽,但是总比没有的好. 在命令行窗口 python -m pydo ...

  10. Vizceral小白入门

    Vizceral小白入门 接到一个任务,要求将N个program可视化,能一目了然查看当前爬虫状态.记得之前做测试时,一个queue service前端可视化效果不错,经询问是用vizceral开源框 ...