mirror of https://github.com/OpenIPC/firmware.git
191 lines
5.2 KiB
Diff
191 lines
5.2 KiB
Diff
diff -drupN a/drivers/rtc/rtc-bm8563.c b/drivers/rtc/rtc-bm8563.c
|
|
--- a/drivers/rtc/rtc-bm8563.c 1970-01-01 03:00:00.000000000 +0300
|
|
+++ b/drivers/rtc/rtc-bm8563.c 2022-06-09 05:02:33.000000000 +0300
|
|
@@ -0,0 +1,186 @@
|
|
+//驱动代码
|
|
+/*
|
|
+* An rtc/i2c driver for the BM8563
|
|
+*
|
|
+* Based on rtc-bm8563.c
|
|
+*
|
|
+* 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/module.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/dma-mapping.h>
|
|
+#include <linux/clk.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/of_gpio.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/input.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/delay.h>
|
|
+#include <linux/irq.h>
|
|
+#include <linux/interrupt.h>
|
|
+#include <linux/slab.h>
|
|
+#include <asm/unaligned.h>
|
|
+#include <asm/io.h>
|
|
+#include <linux/timer.h>
|
|
+#include <linux/rtc.h>
|
|
+#include <linux/i2c.h>
|
|
+#include <linux/rtc.h>
|
|
+#include <linux/bcd.h>
|
|
+
|
|
+/* Registers */
|
|
+#define REG_CTRL_1 0x00
|
|
+#define REG_CTRL_2 0x01
|
|
+#define REG_WATCH_SEC 0x02
|
|
+#define REG_WATCH_MIN 0x03
|
|
+#define REG_WATCH_HOUR 0x04
|
|
+#define REG_WATCH_DATE 0x05
|
|
+#define REG_WATCH_DAY 0x06
|
|
+#define REG_WATCH_MON 0x07
|
|
+#define REG_WATCH_YEAR 0x08
|
|
+#define RTC_I2C_NUM 1
|
|
+#define RTC_ADDR 0x51
|
|
+
|
|
+#define I2C_WRITE 0
|
|
+#define I2C_READ 1
|
|
+
|
|
+static struct i2c_board_info bm8563_info = {
|
|
+ I2C_BOARD_INFO("bm8563", RTC_ADDR),
|
|
+};
|
|
+
|
|
+static struct i2c_client *bm8563_client;
|
|
+
|
|
+static int bm8563_get_time(struct device *dev, struct rtc_time *tm)
|
|
+{
|
|
+ struct i2c_client *client = to_i2c_client(dev);
|
|
+
|
|
+ unsigned char addr = REG_WATCH_SEC;
|
|
+ unsigned char buf[7] = {0};
|
|
+
|
|
+ struct i2c_msg msgs[2] = {
|
|
+ [0] = {
|
|
+ .addr = client->addr,
|
|
+ .flags = I2C_WRITE,
|
|
+ .len = 1,
|
|
+ .buf = &addr,
|
|
+ }, /* setup read addr */
|
|
+ [1] = {
|
|
+ .addr = client->addr,
|
|
+ .flags = I2C_READ,
|
|
+ .len = 7,
|
|
+ .buf = buf,
|
|
+ }, /* read time/date */
|
|
+ };
|
|
+
|
|
+ /* read time/date registers */
|
|
+ if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
|
|
+ dev_err(&client->dev, "%s: read error\n", __func__);
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ //printk("kernel get time\n");
|
|
+ tm->tm_sec = bcd2bin(buf[0]&0x7f) ;
|
|
+ tm->tm_min = bcd2bin(buf[1]);
|
|
+ tm->tm_hour = bcd2bin(buf[2]);
|
|
+ tm->tm_mday = bcd2bin(buf[3]);
|
|
+ tm->tm_wday = bcd2bin(buf[4]);
|
|
+ tm->tm_mon = bcd2bin(buf[5])-1;
|
|
+ tm->tm_year = bcd2bin(buf[6]) + 100;
|
|
+ if((tm->tm_sec == 0) && (tm->tm_min == 0) && (tm->tm_hour == 0) )
|
|
+ rtc_time_to_tm(0, tm);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int bm8563_set_time(struct device *dev, struct rtc_time *tm)
|
|
+{
|
|
+ struct i2c_client *client = to_i2c_client(dev);
|
|
+ unsigned char buf[8] = {0};
|
|
+ unsigned char data[2] = {0};
|
|
+
|
|
+ struct i2c_msg msg[2] = {
|
|
+ [0] = {
|
|
+ .addr = client->addr,
|
|
+ .flags = I2C_WRITE,
|
|
+ .len = 8,
|
|
+ .buf = buf,
|
|
+ }, /* setup rtc time */
|
|
+ [1] = {
|
|
+ .addr = client->addr,
|
|
+ .flags = I2C_READ,
|
|
+ .len = 1,
|
|
+ .buf = data,
|
|
+ }, /* read time/date */
|
|
+ };
|
|
+
|
|
+ //printk("kernel set time\n");
|
|
+ buf[0] = REG_WATCH_SEC;
|
|
+ buf[1] = bin2bcd(tm->tm_sec);
|
|
+ buf[2] = bin2bcd(tm->tm_min);
|
|
+ buf[3] = bin2bcd(tm->tm_hour);
|
|
+ buf[4] = bin2bcd(tm->tm_mday);
|
|
+ buf[5] = bin2bcd(tm->tm_wday);
|
|
+ buf[6] = bin2bcd(tm->tm_mon)+1;
|
|
+ buf[7] = bin2bcd(tm->tm_year % 100);
|
|
+
|
|
+ /* write time/date registers */
|
|
+ if ((i2c_transfer(client->adapter, msg, 2)) != 1) {
|
|
+ dev_err(&client->dev, "%s: write error\n", __func__);
|
|
+ return -EIO;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct rtc_class_ops bm8563_rtc_ops = {
|
|
+ .read_time = bm8563_get_time,
|
|
+ .set_time = bm8563_set_time,
|
|
+};
|
|
+
|
|
+static int bm8563_dev_init(void)
|
|
+{
|
|
+ struct rtc_device *rtc;
|
|
+ struct i2c_adapter *i2c_adap;
|
|
+ struct i2c_client *client;
|
|
+ unsigned char buf[2];
|
|
+ struct i2c_msg msg = {
|
|
+ RTC_ADDR, I2C_WRITE, 2, buf, /* write time/date */
|
|
+ };
|
|
+
|
|
+ i2c_adap = i2c_get_adapter(RTC_I2C_NUM);
|
|
+ bm8563_client = i2c_new_device(i2c_adap, &bm8563_info);
|
|
+ i2c_put_adapter(i2c_adap);
|
|
+ client = bm8563_client;
|
|
+
|
|
+
|
|
+ buf[0] = REG_CTRL_1;
|
|
+ buf[1] = 0;
|
|
+ if ((i2c_transfer(client->adapter, &msg, 1)) != 1) {
|
|
+ dev_err(&client->dev, "%s: write error\n", __func__);
|
|
+ return -EIO;
|
|
+ }
|
|
+ rtc = rtc_device_register("bm8563", &client->dev,
|
|
+ &bm8563_rtc_ops, THIS_MODULE);
|
|
+ if (IS_ERR(rtc))
|
|
+ return PTR_ERR(rtc);
|
|
+
|
|
+ i2c_set_clientdata(client, rtc);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+static void bm8563_dev_exit(void)
|
|
+{
|
|
+ struct rtc_device *rtc = i2c_get_clientdata(bm8563_client);
|
|
+
|
|
+ if (rtc)
|
|
+ rtc_device_unregister(rtc);
|
|
+ i2c_unregister_device(bm8563_client);
|
|
+}
|
|
+module_init(bm8563_dev_init);
|
|
+module_exit(bm8563_dev_exit);
|
|
+
|
|
+MODULE_AUTHOR("damon.jszhang@ingenic.com");
|
|
+MODULE_DESCRIPTION("rtc driver");
|
|
+MODULE_LICENSE("GPL");
|