1. 硬件
    BL5372 RTC
    https://www.belling.com.cn/product_info.html?id=65
  2. 驱动
/** An I2C driver for Beilin BL5372 RTC*/#include <linux/i2c.h>
#include <linux/bcd.h>
#include <linux/rtc.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/of.h>#define DEG 0#define DRV_VERSION "0.0.1"#define TIME24 1
#define RS5C_ADDR(R)        (((R) << 4) | 0)
#define RS5C372_REG_SECS    0
#define RS5C372_REG_MINS    1
#define RS5C372_REG_HOURS   2
#define RS5C372_REG_WDAY    3
#define RS5C372_REG_DAY     4
#define RS5C372_REG_MONTH   5
#define RS5C372_REG_YEAR    6
#define RS5C372_REG_TRIM    7
#define RS5C_REG_ALARM_A_MIN    8           /* or ALARM_W */
#define RS5C_REG_ALARM_A_HOURS  9
#define RS5C_REG_ALARM_A_WDAY   10#define RS5C_REG_ALARM_B_MIN  11          /* or ALARM_D */
#define RS5C_REG_ALARM_B_HOURS  12
#define RS5C_REG_ALARM_B_WDAY   13          /* (ALARM_B only) */
#define RS5C_REG_CTRL1      14
#define RS5C_REG_CTRL2      15
#define DEVICE_ADDR        0x32 //0x5d#if 0
//11 ---> 0x11
static unsigned char bin2bcd(unsigned  val)
{return ((val / 10) << 4) + val % 10;
}
//0x11---> 11
static unsigned bcd2bin(unsigned char val)
{return (val & 0x0f) + (val >> 4) * 10;
}
#endifstatic unsigned rs5c_reg2hr(unsigned reg)
{#if TIME24return bcd2bin(reg & 0x3f);
#elseunsigned   hour;hour = bcd2bin(reg & 0x1f);if (hour == 12)hour = 0;if (reg & 0x20)hour += 12;return hour;
#endif
}static unsigned rs5c_hr2reg(unsigned hour)
{#if TIME24return bin2bcd(hour);#elseif (hour > 12)return 0x20 | bin2bcd(hour - 12);if (hour == 12)return 0x20 | bin2bcd(12);if (hour == 0)return bin2bcd(12);return bin2bcd(hour);
#endif
}//-----------------------------------------------
static struct i2c_driver bl5372_driver;struct bl5372 {struct rtc_device *rtc;struct device *dev;int irq;/*unsigned char sec;unsigned char min;unsigned char hour;unsigned char week;unsigned char day;unsigned char month;unsigned int year;*/
};static int i2c_write_bytes(struct i2c_client *client, uint8_t *data, uint16_t len)
{struct i2c_msg msg;int ret=-1;msg.flags = !I2C_M_RD;msg.addr = client->addr;msg.len = len;msg.buf = data;ret=i2c_transfer(client->adapter, &msg,1);return ret;
}static int bl5372_get_datetime(struct i2c_client *client, struct rtc_time *tm)
{struct bl5372 *bl5372 = i2c_get_clientdata(client);unsigned char buf[7] = { RS5C_ADDR(RS5C372_REG_SECS) };struct i2c_msg msgs[] = {{/* setup read ptr */.addr = client->addr,.flags = 0,/* write */.len = 1,.buf = buf},{/* read the sec,min,hour,week,day,month,year */.addr = client->addr,.flags = I2C_M_RD,/* read */.len = 7,.buf = buf},};//int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)//@num: Number of messages to be executed.//这里有两个消息, msgs[]的大小/* read registers */if ((i2c_transfer(client->adapter, msgs, 2)) != 2) {dev_err(&client->dev, "%s: read error\n", __func__);return -EIO;}tm->tm_sec = bcd2bin(buf[0] & 0x7f);tm->tm_min = bcd2bin(buf[1] & 0x7f);tm->tm_hour = rs5c_reg2hr(buf[2]);tm->tm_mday = bcd2bin(buf[4] & 0x7f);;tm->tm_wday = bcd2bin(buf[3] & 0x7f);tm->tm_mon = rs5c_reg2hr(buf[5])-1;tm->tm_year = bcd2bin(buf[6] & 0x7f)+100;//------------------------------------buf[0]= RS5C_ADDR(RS5C_REG_CTRL2);struct i2c_msg msgs2[] = {{/* setup read  */.addr = client->addr,.len = 1,.buf = buf},{/* read is_24hour */.addr = client->addr,.flags = I2C_M_RD,.len = 1,.buf = buf},};/* read registers */if ((i2c_transfer(client->adapter, msgs2, 2)) != 2) {dev_err(&client->dev, "%s: read error\n", __func__);return -EIO;}if(buf[0]&0x20){tm->tm_hour= (tm->tm_hour<24)? (tm->tm_hour):(24-tm->tm_hour);}else{tm->tm_hour=(tm->tm_hour<24-8)? (tm->tm_hour+8):(tm->tm_hour+8-24);}/* the clock can give out invalid datetime, but we cannot return* -EINVAL otherwise hwclock will refuse to set the time on bootup.*/if (rtc_valid_tm(tm) < 0)dev_err(&client->dev, "retrieved date/time is not valid.\n");return 0;
}static int bl5372_set_datetime(struct i2c_client *client, struct rtc_time *tm)
{struct bl5372 *bl5372 = i2c_get_clientdata(client);int i, err;unsigned char buf[7];//------------------------------------buf[0]= RS5C_ADDR(RS5C_REG_CTRL2);struct i2c_msg msgs2[] = {{/* setup read  */.addr = client->addr,.len = 1,.buf = buf},{/* read is_24hour */.addr = client->addr,.flags = I2C_M_RD,.len = 1,.buf = buf},};/* read registers */if ((i2c_transfer(client->adapter, msgs2, 2)) != 2) {dev_err(&client->dev, "%s: read error\n", __func__);return -EIO;}if((buf[0]&0x20)== 0){buf[0] |= (1<<5); err = i2c_master_send(client, buf, 1);}
//------------------------/* hours, minutes and seconds */buf[0] = bin2bcd(tm->tm_sec);buf[1] = bin2bcd(tm->tm_min);buf[2] = rs5c_hr2reg(tm->tm_hour);buf[3] = bin2bcd(tm->tm_wday & 0x07); //week 0~6buf[4] = bin2bcd(tm->tm_mday);buf[5] = bin2bcd(tm->tm_mon)+1;// 0~11tm->tm_year -= 100;buf[6] = bin2bcd(tm->tm_year % 100);// start at 1900  2018=>118err = i2c_smbus_write_byte_data(client, RS5C_ADDR(RS5C372_REG_SECS),   buf[0]);i2c_smbus_write_byte_data(client, RS5C_ADDR(RS5C372_REG_MINS) ,  buf[1]);i2c_smbus_write_byte_data(client, RS5C_ADDR(RS5C372_REG_HOURS) , buf[2]);i2c_smbus_write_byte_data(client, RS5C_ADDR(RS5C372_REG_WDAY) ,  buf[3]);i2c_smbus_write_byte_data(client, RS5C_ADDR(RS5C372_REG_DAY) ,   buf[4]);i2c_smbus_write_byte_data(client, RS5C_ADDR(RS5C372_REG_MONTH) , buf[5]);i2c_smbus_write_byte_data(client, RS5C_ADDR(RS5C372_REG_YEAR) ,  buf[6]);return 0;
}#ifdef CONFIG_RTC_INTF_DEV
static int bl5372_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
{struct bl5372 *bl5372 = i2c_get_clientdata(to_i2c_client(dev));struct rtc_time tm;switch (cmd) {case RTC_RD_TIME://bl5372_get_datetime(to_i2c_client(dev), &tm);return 0;case RTC_SET_TIME:if (copy_from_user(&tm, arg, sizeof(tm)))return -EFAULT;bl5372_set_datetime(to_i2c_client(dev), &tm);return 0;default:return -ENOIOCTLCMD;}}
#else
#define bl5372_rtc_ioctl NULL
#endifstatic int bl5372_rtc_read_time(struct device *dev, struct rtc_time *tm)
{return bl5372_get_datetime(to_i2c_client(dev), tm);
}static int bl5372_rtc_set_time(struct device *dev, struct rtc_time *tm)
{return bl5372_set_datetime(to_i2c_client(dev), tm);
}static int bl5372_rtc_getalarm(struct device *dev, struct rtc_wkalrm *wkalrm)
{struct bl5372 *bl5372 = i2c_get_clientdata(to_i2c_client(dev));return 0;
}static int bl5372_rtc_setalarm(struct device *dev, struct rtc_wkalrm *wkalrm)
{struct bl5372 *bl5372 = i2c_get_clientdata(to_i2c_client(dev));return 0;
}static int bl5372_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
{//struct bl5372 *bl5372 = dev_get_drvdata(dev);struct bl5372 *bl5372 = i2c_get_clientdata(to_i2c_client(dev));return 0;
}static const struct rtc_class_ops bl5372_rtc_ops = {.ioctl        = bl5372_rtc_ioctl,.read_time  = bl5372_rtc_read_time,.set_time   = bl5372_rtc_set_time,.read_alarm             = bl5372_rtc_getalarm,.set_alarm              = bl5372_rtc_setalarm,.alarm_irq_enable       = bl5372_rtc_alarm_irq_enable
};static int bl5372_probe(struct i2c_client *client,const struct i2c_device_id *id)
{struct bl5372 *bl5372;if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)){return -ENODEV;}bl5372 = devm_kzalloc(&client->dev, sizeof(struct bl5372),GFP_KERNEL);if (!bl5372){return -ENOMEM;}device_init_wakeup(&client->dev, 1);i2c_set_clientdata(client, bl5372);bl5372->rtc = devm_rtc_device_register(&client->dev,bl5372_driver.driver.name,&bl5372_rtc_ops, THIS_MODULE);if (IS_ERR(bl5372->rtc)){return PTR_ERR(bl5372->rtc);}return 0;
}static int bl5372_remove(struct i2c_client *client)
{return 0;
}static const struct i2c_device_id bl5372_id[] = {{ "bl5372", 0 },{ }
};
MODULE_DEVICE_TABLE(i2c, bl5372_id);#ifdef CONFIG_OF
static const struct of_device_id bl5372_of_match[] = {{ .compatible = "beilin,bl5372" },{}
};
MODULE_DEVICE_TABLE(of, bl5372_of_match);
#endifstatic struct i2c_driver bl5372_driver = {.driver        = {.name   = "rtc-bl5372",.owner    = THIS_MODULE,.of_match_table = of_match_ptr(bl5372_of_match),},.probe        = bl5372_probe,.remove     = bl5372_remove,.id_table  = bl5372_id,
};module_i2c_driver(bl5372_driver);MODULE_AUTHOR("Zhengweiqing <1548889230@qq.com>");
MODULE_DESCRIPTION("Beilin BL5372 RTC driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);

BL5372 RTC linux驱动相关推荐

  1. Linux驱动修炼之道-RTC子系统框架与源码分析【转】

    转自:http://helloyesyes.iteye.com/blog/1072433 努力成为linux kernel hacker的人李万鹏原创作品,为梦而战.转载请标明出处 http://bl ...

  2. 【正点原子MP157连载】第四十三章 外置RTC芯片PCF8563实验-摘自【正点原子】STM32MP1嵌入式Linux驱动开发指南V1.7

    1)实验平台:正点原子STM32MP157开发板 2)购买链接:https://item.taobao.com/item.htm?&id=629270721801 3)全套实验源码+手册+视频 ...

  3. 【正点原子Linux连载】第六十章 Linux RTC驱动实验 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0

    1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...

  4. linux 实时时钟(RTC)驱动【转】

    本文转载自:http://blog.csdn.net/yaozhenguo2006/article/details/6820218 这个是linux内核文档关于rtc实时时钟部分的说明,此文档主要描述 ...

  5. Linux驱动开发必看详解神秘内核(完全转载)

    Linux驱动开发必看详解神秘内核 完全转载-链接:http://blog.chinaunix.net/uid-21356596-id-1827434.html IT168 技术文档]在开始步入Lin ...

  6. 2022 年了,重新理解一波设备驱动 | Linux 驱动

    哈喽,我是老吴. 非常怀念写文章的感觉. 昨晚复习了一些 Linux 驱动的基础知识,给大家分享一下吧. 先说结论: 多年来,我接触到的 Linux 驱动教程大多都是从 0 编写,这样对初学者而言最大 ...

  7. linux驱动工程面试必问知识点

    linux内核原理面试必问(由易到难) 简单型 1:linux中内核空间及用户空间的区别?用户空间与内核通信方式有哪些? 2:linux中内存划分及如何使用?虚拟地址及物理地址的概念及彼此之间的转化, ...

  8. 【正点原子MP157连载】第二十三章 Linux设备树-摘自【正点原子】STM32MP1嵌入式Linux驱动开发指南V1.7

    1)实验平台:正点原子STM32MP157开发板 2)购买链接:https://item.taobao.com/item.htm?&id=629270721801 3)全套实验源码+手册+视频 ...

  9. i.MX283开发板第一个Linux驱动-LED驱动

    字符设备驱动开发 字符设备是 Linux 驱动中最基本的一类设备驱动,字符设备就是一个一个字节,按照字节流进行读写操作的设备,读写数据是分先后顺序的.比如我们最常见的点灯.按键.IIC.SPI,LCD ...

最新文章

  1. ubuntu VMware
  2. 窗体和控件使用中的注意事项有哪些?
  3. P4310-绝世好题【位运算,dp】
  4. 汇编语言(三)之判断数值是否大于42H并统计个数
  5. 晨风机器人怎么买奴隶_潮牌复刻和正品该怎么抉择???带你了解了解
  6. fwrite函数的一般调用形式是什么?
  7. python3.x中pip升级报错
  8. android游戏开发框架libgdx环境搭建
  9. 《长城保护总体规划》出台 为长城保护提供遵循依据
  10. Steam提示steam需要在线更新 + steam needs to be online to update最全解决方法
  11. html 视频在线播放,HTML 视频(Video)播放
  12. html打印预览空白,win7系统下使用IE浏览器预览打印页面时显示页面空白
  13. 软件著作权源代码文档word操作技巧
  14. pt100铂电阻低温温度传感器的特点
  15. spring核心技术之Resource资源理解
  16. python终端小游戏_我用Python玩小游戏“跳一跳”,瞬间称霸了朋友圈!
  17. Component xxx does not have a method xxx to handle event xxx
  18. 首届华为开发者大赛沙龙牵手大连-与开发者共话赛事
  19. JavaScript 动态表格操作
  20. 植入大脑电极,晚期渐冻症患者通过神经信号交流!匹配准确率80%,有效时间仅1/3...

热门文章

  1. STM8S105S4T6C和STM8S105C6T6对比
  2. inteli211网卡linux驱动,intel(R)I211网卡刷I210简易教程
  3. dwz 表单提交 html,dwz 文件上传表单提交 分析
  4. 在Mac OS X苹果lion系统上制作USB启动盘
  5. 如何选择拨号服务器!
  6. 微信支付交易查询案例
  7. 300000000元!短融网获C轮融资,CEO王坤透露了几点信息
  8. vue修改网站名称和图标
  9. 2、安装VisualStudio、Unity3D、下载MRTK
  10. linux运行dock打包的镜像,Docke镜像和仓库基础命令