android rtc驱动问题

colwer 2015-12-25 11:43:01
1. android4.4, i2c接口外部rtc驱动。写驱动的时候,发现发rtc注册到i2c device下面时(rtc = devm_rtc_device_register(&client->dev, em3027_driver.driver.name, &em3027_rtc_ops, THIS_MODULE);),android系统里面设置时间时,
驱动会提示找不到rtc设备;
只有注册到paltform_dev下面时,android系统设置时间时才会找到rtc设备(priv->rtc = rtc_device_register("aml_rtc", &pdev->dev, &aml_rtc_ops, THIS_MODULE);).

android系统设置时间时,会调用 到kernel中的drivers/staging/android/alarm-dev.c

static int alarm_set_rtc(struct timespec *ts)
{
struct rtc_time new_rtc_tm;
struct rtc_device *rtc_dev;
unsigned long flags;
int rv = 0;

rtc_time_to_tm(ts->tv_sec, &new_rtc_tm);
rtc_dev = alarmtimer_get_rtcdev(); //rtc注册到i2c device中时,这里就找获取不到rtc_dev

rv = do_settimeofday(ts);

if (rv < 0)
return rv;

if (rtc_dev)
{
printk("#### [kernel] %s %s %d ####\n", __FILE__, __FUNCTION__, __LINE__);
rv = rtc_set_time(rtc_dev, &new_rtc_tm);
}

spin_lock_irqsave(&alarm_slock, flags);
alarm_pending |= ANDROID_ALARM_TIME_CHANGE_MASK;
wake_up(&alarm_wait_queue);
spin_unlock_irqrestore(&alarm_slock, flags);

return rv;
}


2. i2c的rtc驱动 :rtc注册到&client->dev时,android系统里面设置时间时找不到rtc设备。

/*
* An rtc/i2c driver for the EM Microelectronic EM3027
* Copyright 2011 CompuLab, Ltd.
*
* Author: Mike Rapoport <mike@compulab.co.il>
*
* Based on rtc-ds1672.c by Alessandro Zummo <a.zummo@towertech.it>
*
* 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.
*/

#include <linux/i2c.h>
#include <linux/rtc.h>
#include <linux/bcd.h>
#include <linux/module.h>

/* Registers */
#define EM3027_REG_ON_OFF_CTRL 0x00
#define EM3027_REG_IRQ_CTRL 0x01
#define EM3027_REG_IRQ_FLAGS 0x02
#define EM3027_REG_STATUS 0x03
#define EM3027_REG_RST_CTRL 0x04

#define EM3027_REG_WATCH_SEC 0x08
#define EM3027_REG_WATCH_MIN 0x09
#define EM3027_REG_WATCH_HOUR 0x0a
#define EM3027_REG_WATCH_DATE 0x0b
#define EM3027_REG_WATCH_DAY 0x0c
#define EM3027_REG_WATCH_MON 0x0d
#define EM3027_REG_WATCH_YEAR 0x0e

#define EM3027_REG_ALARM_SEC 0x10
#define EM3027_REG_ALARM_MIN 0x11
#define EM3027_REG_ALARM_HOUR 0x12
#define EM3027_REG_ALARM_DATE 0x13
#define EM3027_REG_ALARM_DAY 0x14
#define EM3027_REG_ALARM_MON 0x15
#define EM3027_REG_ALARM_YEAR 0x16

static struct i2c_driver em3027_driver;

static int em3027_get_time(struct device *dev, struct rtc_time *tm)
{
return 0;
}

static int em3027_set_time(struct device *dev, struct rtc_time *tm)
{
return 0;
}

static const struct rtc_class_ops em3027_rtc_ops = {
.read_time = em3027_get_time,
.set_time = em3027_set_time,
};

//em3027_probe中, rtc注册到&client->dev时,android系统里面设置时间时找不到rtc设备。
static int em3027_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct rtc_device *rtc;

if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV;

rtc = devm_rtc_device_register(&client->dev, em3027_driver.driver.name, &em3027_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);

i2c_set_clientdata(client, rtc);

return 0;
}

static int em3027_remove(struct i2c_client *client)
{
return 0;
}

static struct i2c_device_id em3027_id[] = {
{ "i2c-rtc", 0 },
{ }
};

static struct i2c_driver em3027_driver = {
.driver = {
.name = "aml-rtc-em3027",
},
.probe = &em3027_probe,
.remove = &em3027_remove,
.id_table = em3027_id,
};

module_i2c_driver(em3027_driver);

MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
MODULE_DESCRIPTION("EM Microelectronic EM3027 RTC driver");
MODULE_LICENSE("GPL");



3. 如果是注册到platform device下面, 操作rtc时,又获取不到i2c_client。请问如何去获取i2c_client?

/*
* this driver is written for the internal rtc for M1
*/

#include<linux/module.h>
#include<linux/platform_device.h>
#include<linux/rtc.h>
#include<linux/slab.h>
#include<asm/delay.h>
#include<mach/am_regs.h>
#if MESON_CPU_TYPE >= MESON_CPU_TYPE_MESON6
#include <plat/io.h>
#endif

#include <linux/of.h>

struct aml_rtc_priv{
struct rtc_device *rtc;
unsigned long base_addr;
struct timer_list timer;
struct work_struct work;
struct workqueue_struct *rtc_work_queue;
};

typedef struct alarm_data_s {
int level;
unsigned alarm_sec; //in s
} alarm_data_t;

//这里的to_i2c_client找不到dev
static int aml_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
return pt7c4337_get_datetime(to_i2c_client(dev), tm);
}

static int aml_rtc_write_time(struct device *dev, struct rtc_time *tm)
{
return pt7c4337_set_datetime(to_i2c_client(dev), tm);
}

static const struct rtc_class_ops aml_rtc_ops ={
.read_time = aml_rtc_read_time,
.set_time = aml_rtc_write_time,
.set_alarm = aml_rtc_set_alarm,
};

static int aml_rtc_probe(struct platform_device *pdev)
{
struct aml_rtc_priv *priv;
struct device_node* aml_rtc_node = pdev->dev.of_node;
int ret;
int sec_adjust = 0;

priv = (struct aml_rtc_priv *)kzalloc(sizeof(*priv), GFP_KERNEL);

if(!priv)
return -ENOMEM;

platform_set_drvdata(pdev, priv);

/* platform setup code should have handled this; sigh */
if (!device_can_wakeup(&pdev->dev))
device_init_wakeup(&pdev->dev, 1);

priv->rtc = rtc_device_register("aml_rtc", &pdev->dev, &aml_rtc_ops, THIS_MODULE);

if(IS_ERR(priv->rtc)){
ret = PTR_ERR(priv->rtc);
goto out;
}

return 0;

out:
if(priv->rtc_work_queue)
destroy_workqueue(priv->rtc_work_queue);
kfree(priv);
return ret;
}

static const struct of_device_id meson6_rtc_dt_match[]={
{ .compatible = "amlogic,aml_rtc"},
{},
};

struct platform_driver aml_rtc_driver = {
.driver = {
.name = "aml_rtc",
.owner = THIS_MODULE,
.of_match_table=meson6_rtc_dt_match,
},
.probe = aml_rtc_probe,
};

static int __init aml_rtc_init(void)
{

return platform_driver_register(&aml_rtc_driver);
}

static void __init aml_rtc_exit(void)
{
return platform_driver_unregister(&aml_rtc_driver);
}

module_init(aml_rtc_init);
module_exit(aml_rtc_exit);

MODULE_DESCRIPTION("Amlogic internal rtc driver");
MODULE_LICENSE("GPL");

...全文
1349 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
刘大球 2016-10-25
  • 打赏
  • 举报
回复
这个方法是有效的。提醒,在驱动中set_alarm要有,否则 if (!rtc->ops->set_alarm)就也是-1了。 感谢大家
houyizi313 2016-09-12
  • 打赏
  • 举报
回复
这是因为alarmtimer.c中alarmtimer_rtc_add_device()函数中对if (!device_may_wakeup(rtc->dev.parent)) return -1;直接返回了;在你的i2c的rtc的probe驱动增加一行: device_init_wakeup(&client->dev, true); 就解决了; static int rx8010_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); struct rx8010_data *rx8010; int err, need_reset = 0; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_I2C_BLOCK)) { dev_err(&adapter->dev, "doesn't support required functionality\n"); err = -EIO; goto errout; } rx8010 = kzalloc(sizeof(*rx8010), GFP_KERNEL); if (!rx8010) { dev_err(&adapter->dev, "failed to alloc memory\n"); err = -ENOMEM; goto errout; } rx8010->client = client; i2c_set_clientdata(client, rx8010); INIT_WORK(&rx8010->work, rx8010_work); device_init_wakeup(&client->dev, true); //解决alarm_set_rtc@163 rtc_dev->name=(null) err = rx8010_init_client(client, &need_reset); if (err) goto errout_free; if (need_reset) { struct rtc_time tm; dev_info(&client->dev, "bad conditions detected, resetting date\n"); rtc_time_to_tm(0, &tm); // set to 1970/1/1 rx8010_set_time(&client->dev, &tm); } rx8010->rtc = rtc_device_register(client->name, &client->dev, &rx8010_rtc_ops, THIS_MODULE); //cat /sys/class/rtc/rtc0/name=>rx8010 //rx8010->rtc = devm_rtc_device_register(&client->dev, rx8010_driver.driver.name,&rx8010_rtc_ops, THIS_MODULE); if (IS_ERR(rx8010->rtc)) { err = PTR_ERR(rx8010->rtc); dev_err(&client->dev, "unable to register the class device\n"); goto errout_free; } if (client->irq > 0) { dev_info(&client->dev, "IRQ %d supplied\n", client->irq); err = devm_request_threaded_irq(&client->dev,client->irq, NULL, rx8010_irq, IRQF_TRIGGER_LOW | IRQF_ONESHOT,"rx8010", client); if (err) { dev_err(&client->dev, "unable to request IRQ\n"); goto errout_reg; } } rx8010->rtc->irq_freq = 1; rx8010->rtc->max_user_freq = 1; return 0; errout_reg: rtc_device_unregister(rx8010->rtc); errout_free: kfree(rx8010); errout: dev_err(&adapter->dev, "probing for rx8010 failed\n"); return err; }
houyizi313 2016-09-08
  • 打赏
  • 举报
回复
楼主怎么解决的?我也遇到了这个问题!
colwer 2015-12-25
  • 打赏
  • 举报
回复
或者,我在drivers/staging/android/alarm-dev.c中,能获取到驱动的i2c dev吗?想把rv = rtc_set_time(rtc_dev中的rtc_dev换成i2c的,该怎么写呢?

80,479

社区成员

发帖
与我相关
我的任务
社区描述
移动平台 Android
androidandroid-studioandroidx 技术论坛(原bbs)
社区管理员
  • Android
  • yechaoa
  • 失落夏天
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧