Commit 9ae4ae30 authored by Stephen Rothwell's avatar Stephen Rothwell

Merge remote-tracking branch 'rtc/rtc-next'

parents 5148d660 c8c97a4f
...@@ -49,6 +49,7 @@ isil,isl1208 Intersil ISL1208 Low Power RTC with Battery Backed SRAM ...@@ -49,6 +49,7 @@ isil,isl1208 Intersil ISL1208 Low Power RTC with Battery Backed SRAM
isil,isl1218 Intersil ISL1218 Low Power RTC with Battery Backed SRAM isil,isl1218 Intersil ISL1218 Low Power RTC with Battery Backed SRAM
isil,isl12022 Intersil ISL12022 Real-time Clock isil,isl12022 Intersil ISL12022 Real-time Clock
microcrystal,rv3029 Real Time Clock Module with I2C-Bus microcrystal,rv3029 Real Time Clock Module with I2C-Bus
microcrystal,rv8523 Real Time Clock
nxp,pcf2127 Real-time clock nxp,pcf2127 Real-time clock
nxp,pcf2129 Real-time clock nxp,pcf2129 Real-time clock
nxp,pcf8523 Real-time Clock nxp,pcf8523 Real-time Clock
...@@ -62,3 +63,4 @@ ricoh,rs5c372b I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC ...@@ -62,3 +63,4 @@ ricoh,rs5c372b I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
ricoh,rv5c386 I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC ricoh,rv5c386 I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
ricoh,rv5c387a I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC ricoh,rv5c387a I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
sii,s35390a 2-wire CMOS real-time clock sii,s35390a 2-wire CMOS real-time clock
whwave,sd3078 I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
...@@ -431,6 +431,7 @@ vot Vision Optical Technology Co., Ltd. ...@@ -431,6 +431,7 @@ vot Vision Optical Technology Co., Ltd.
wd Western Digital Corp. wd Western Digital Corp.
wetek WeTek Electronics, limited. wetek WeTek Electronics, limited.
wexler Wexler wexler Wexler
whwave Shenzhen whwave Electronics, Inc.
wi2wi Wi2Wi, Inc. wi2wi Wi2Wi, Inc.
winbond Winbond Electronics corp. winbond Winbond Electronics corp.
winstar Winstar Display Corp. winstar Winstar Display Corp.
......
...@@ -16531,6 +16531,12 @@ L: linux-gpio@vger.kernel.org ...@@ -16531,6 +16531,12 @@ L: linux-gpio@vger.kernel.org
S: Maintained S: Maintained
F: drivers/gpio/gpio-wcove.c F: drivers/gpio/gpio-wcove.c
WHWAVE RTC DRIVER
M: Dianlong Li <long17.cool@163.com>
L: linux-rtc@vger.kernel.org
S: Maintained
F: drivers/rtc/rtc-sd3078.c
WIIMOTE HID DRIVER WIIMOTE HID DRIVER
M: David Herrmann <dh.herrmann@googlemail.com> M: David Herrmann <dh.herrmann@googlemail.com>
L: linux-input@vger.kernel.org L: linux-input@vger.kernel.org
......
...@@ -646,6 +646,15 @@ config RTC_DRV_S5M ...@@ -646,6 +646,15 @@ config RTC_DRV_S5M
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called rtc-s5m. will be called rtc-s5m.
config RTC_DRV_SD3078
tristate "ZXW Crystal SD3078"
help
If you say yes here you get support for the ZXW Crystal
SD3078 RTC chips.
This driver can also be built as a module. If so, the module
will be called rtc-sd3078
endif # I2C endif # I2C
comment "SPI RTC drivers" comment "SPI RTC drivers"
......
...@@ -149,6 +149,7 @@ obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o ...@@ -149,6 +149,7 @@ obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o
obj-$(CONFIG_RTC_DRV_S5M) += rtc-s5m.o obj-$(CONFIG_RTC_DRV_S5M) += rtc-s5m.o
obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o
obj-$(CONFIG_RTC_DRV_SC27XX) += rtc-sc27xx.o obj-$(CONFIG_RTC_DRV_SC27XX) += rtc-sc27xx.o
obj-$(CONFIG_RTC_DRV_SD3078) += rtc-sd3078.o
obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o
obj-$(CONFIG_RTC_DRV_SIRFSOC) += rtc-sirfsoc.o obj-$(CONFIG_RTC_DRV_SIRFSOC) += rtc-sirfsoc.o
obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o
......
...@@ -100,7 +100,7 @@ int rtc_valid_tm(struct rtc_time *tm) ...@@ -100,7 +100,7 @@ int rtc_valid_tm(struct rtc_time *tm)
if (tm->tm_year < 70 if (tm->tm_year < 70
|| ((unsigned)tm->tm_mon) >= 12 || ((unsigned)tm->tm_mon) >= 12
|| tm->tm_mday < 1 || tm->tm_mday < 1
|| tm->tm_mday > rtc_month_days(tm->tm_mon, tm->tm_year + 1900) || tm->tm_mday > rtc_month_days(tm->tm_mon, ((unsigned)tm->tm_year + 1900))
|| ((unsigned)tm->tm_hour) >= 24 || ((unsigned)tm->tm_hour) >= 24
|| ((unsigned)tm->tm_min) >= 60 || ((unsigned)tm->tm_min) >= 60
|| ((unsigned)tm->tm_sec) >= 60) || ((unsigned)tm->tm_sec) >= 60)
...@@ -116,8 +116,8 @@ EXPORT_SYMBOL(rtc_valid_tm); ...@@ -116,8 +116,8 @@ EXPORT_SYMBOL(rtc_valid_tm);
*/ */
time64_t rtc_tm_to_time64(struct rtc_time *tm) time64_t rtc_tm_to_time64(struct rtc_time *tm)
{ {
return mktime64(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, return mktime64(((unsigned)tm->tm_year + 1900), tm->tm_mon + 1,
tm->tm_hour, tm->tm_min, tm->tm_sec); tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
} }
EXPORT_SYMBOL(rtc_tm_to_time64); EXPORT_SYMBOL(rtc_tm_to_time64);
......
...@@ -161,6 +161,7 @@ isl1208_i2c_get_atr(struct i2c_client *client) ...@@ -161,6 +161,7 @@ isl1208_i2c_get_atr(struct i2c_client *client)
return atr; return atr;
} }
/* returns adjustment value + 100 */
static int static int
isl1208_i2c_get_dtr(struct i2c_client *client) isl1208_i2c_get_dtr(struct i2c_client *client)
{ {
...@@ -171,7 +172,7 @@ isl1208_i2c_get_dtr(struct i2c_client *client) ...@@ -171,7 +172,7 @@ isl1208_i2c_get_dtr(struct i2c_client *client)
/* dtr encodes adjustments of {-60,-40,-20,0,20,40,60} ppm */ /* dtr encodes adjustments of {-60,-40,-20,0,20,40,60} ppm */
dtr = ((dtr & 0x3) * 20) * (dtr & (1 << 2) ? -1 : 1); dtr = ((dtr & 0x3) * 20) * (dtr & (1 << 2) ? -1 : 1);
return dtr; return dtr + 100;
} }
static int static int
...@@ -248,8 +249,8 @@ isl1208_rtc_proc(struct device *dev, struct seq_file *seq) ...@@ -248,8 +249,8 @@ isl1208_rtc_proc(struct device *dev, struct seq_file *seq)
(sr & ISL1208_REG_SR_RTCF) ? "bad" : "okay"); (sr & ISL1208_REG_SR_RTCF) ? "bad" : "okay");
dtr = isl1208_i2c_get_dtr(client); dtr = isl1208_i2c_get_dtr(client);
if (dtr >= 0 - 1) if (dtr >= 0)
seq_printf(seq, "digital_trim\t: %d ppm\n", dtr); seq_printf(seq, "digital_trim\t: %d ppm\n", dtr - 100);
atr = isl1208_i2c_get_atr(client); atr = isl1208_i2c_get_atr(client);
if (atr >= 0) if (atr >= 0)
...@@ -637,7 +638,7 @@ isl1208_sysfs_show_dtrim(struct device *dev, ...@@ -637,7 +638,7 @@ isl1208_sysfs_show_dtrim(struct device *dev,
if (dtr < 0) if (dtr < 0)
return dtr; return dtr;
return sprintf(buf, "%d ppm\n", dtr); return sprintf(buf, "%d ppm\n", dtr - 100);
} }
static DEVICE_ATTR(dtrim, S_IRUGO, isl1208_sysfs_show_dtrim, NULL); static DEVICE_ATTR(dtrim, S_IRUGO, isl1208_sysfs_show_dtrim, NULL);
......
...@@ -374,6 +374,7 @@ MODULE_DEVICE_TABLE(i2c, pcf8523_id); ...@@ -374,6 +374,7 @@ MODULE_DEVICE_TABLE(i2c, pcf8523_id);
#ifdef CONFIG_OF #ifdef CONFIG_OF
static const struct of_device_id pcf8523_of_match[] = { static const struct of_device_id pcf8523_of_match[] = {
{ .compatible = "nxp,pcf8523" }, { .compatible = "nxp,pcf8523" },
{ .compatible = "microcrystal,rv8523" },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, pcf8523_of_match); MODULE_DEVICE_TABLE(of, pcf8523_of_match);
......
// SPDX-License-Identifier: GPL-2.0
/*
* Real Time Clock (RTC) Driver for sd3078
* Copyright (C) 2018 Zoro Li
*/
#include <linux/bcd.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/rtc.h>
#include <linux/slab.h>
#define SD3078_REG_SC 0x00
#define SD3078_REG_MN 0x01
#define SD3078_REG_HR 0x02
#define SD3078_REG_DW 0x03
#define SD3078_REG_DM 0x04
#define SD3078_REG_MO 0x05
#define SD3078_REG_YR 0x06
#define SD3078_REG_CTRL1 0x0f
#define SD3078_REG_CTRL2 0x10
#define SD3078_REG_CTRL3 0x11
#define KEY_WRITE1 0x80
#define KEY_WRITE2 0x04
#define KEY_WRITE3 0x80
#define NUM_TIME_REGS (SD3078_REG_YR - SD3078_REG_SC + 1)
/*
* The sd3078 has write protection
* and we can choose whether or not to use it.
* Write protection is turned off by default.
*/
#define WRITE_PROTECT_EN 0
struct sd3078 {
struct rtc_device *rtc;
struct regmap *regmap;
};
/*
* In order to prevent arbitrary modification of the time register,
* when modification of the register,
* the "write" bit needs to be written in a certain order.
* 1. set WRITE1 bit
* 2. set WRITE2 bit
* 3. set WRITE3 bit
*/
static void sd3078_enable_reg_write(struct sd3078 *sd3078)
{
regmap_update_bits(sd3078->regmap, SD3078_REG_CTRL2,
KEY_WRITE1, KEY_WRITE1);
regmap_update_bits(sd3078->regmap, SD3078_REG_CTRL1,
KEY_WRITE2, KEY_WRITE2);
regmap_update_bits(sd3078->regmap, SD3078_REG_CTRL1,
KEY_WRITE3, KEY_WRITE3);
}
#if WRITE_PROTECT_EN
/*
* In order to prevent arbitrary modification of the time register,
* we should disable the write function.
* when disable write,
* the "write" bit needs to be clear in a certain order.
* 1. clear WRITE2 bit
* 2. clear WRITE3 bit
* 3. clear WRITE1 bit
*/
static void sd3078_disable_reg_write(struct sd3078 *sd3078)
{
regmap_update_bits(sd3078->regmap, SD3078_REG_CTRL1,
KEY_WRITE2, 0);
regmap_update_bits(sd3078->regmap, SD3078_REG_CTRL1,
KEY_WRITE3, 0);
regmap_update_bits(sd3078->regmap, SD3078_REG_CTRL2,
KEY_WRITE1, 0);
}
#endif
static int sd3078_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
unsigned char hour;
unsigned char rtc_data[NUM_TIME_REGS] = {0};
struct i2c_client *client = to_i2c_client(dev);
struct sd3078 *sd3078 = i2c_get_clientdata(client);
int ret;
ret = regmap_bulk_read(sd3078->regmap, SD3078_REG_SC, rtc_data,
NUM_TIME_REGS);
if (ret < 0) {
dev_err(dev, "reading from RTC failed with err:%d\n", ret);
return ret;
}
tm->tm_sec = bcd2bin(rtc_data[SD3078_REG_SC] & 0x7F);
tm->tm_min = bcd2bin(rtc_data[SD3078_REG_MN] & 0x7F);
/*
* The sd3078 supports 12/24 hour mode.
* When getting time,
* we need to convert the 12 hour mode to the 24 hour mode.
*/
hour = rtc_data[SD3078_REG_HR];
if (hour & 0x80) /* 24H MODE */
tm->tm_hour = bcd2bin(rtc_data[SD3078_REG_HR] & 0x3F);
else if (hour & 0x20) /* 12H MODE PM */
tm->tm_hour = bcd2bin(rtc_data[SD3078_REG_HR] & 0x1F) + 12;
else /* 12H MODE AM */
tm->tm_hour = bcd2bin(rtc_data[SD3078_REG_HR] & 0x1F);
tm->tm_mday = bcd2bin(rtc_data[SD3078_REG_DM] & 0x3F);
tm->tm_wday = rtc_data[SD3078_REG_DW] & 0x07;
tm->tm_mon = bcd2bin(rtc_data[SD3078_REG_MO] & 0x1F) - 1;
tm->tm_year = bcd2bin(rtc_data[SD3078_REG_YR]) + 100;
return 0;
}
static int sd3078_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
unsigned char rtc_data[NUM_TIME_REGS];
struct i2c_client *client = to_i2c_client(dev);
struct sd3078 *sd3078 = i2c_get_clientdata(client);
int ret;
rtc_data[SD3078_REG_SC] = bin2bcd(tm->tm_sec);
rtc_data[SD3078_REG_MN] = bin2bcd(tm->tm_min);
rtc_data[SD3078_REG_HR] = bin2bcd(tm->tm_hour) | 0x80;
rtc_data[SD3078_REG_DM] = bin2bcd(tm->tm_mday);
rtc_data[SD3078_REG_DW] = tm->tm_wday & 0x07;
rtc_data[SD3078_REG_MO] = bin2bcd(tm->tm_mon) + 1;
rtc_data[SD3078_REG_YR] = bin2bcd(tm->tm_year - 100);
#if WRITE_PROTECT_EN
sd3078_enable_reg_write(sd3078);
#endif
ret = regmap_bulk_write(sd3078->regmap, SD3078_REG_SC, rtc_data,
NUM_TIME_REGS);
if (ret < 0) {
dev_err(dev, "writing to RTC failed with err:%d\n", ret);
return ret;
}
#if WRITE_PROTECT_EN
sd3078_disable_reg_write(sd3078);
#endif
return 0;
}
static const struct rtc_class_ops sd3078_rtc_ops = {
.read_time = sd3078_rtc_read_time,
.set_time = sd3078_rtc_set_time,
};
static const struct regmap_config regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0x11,
};
static int sd3078_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
struct sd3078 *sd3078;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV;
sd3078 = devm_kzalloc(&client->dev, sizeof(*sd3078), GFP_KERNEL);
if (!sd3078)
return -ENOMEM;
sd3078->regmap = devm_regmap_init_i2c(client, &regmap_config);
if (IS_ERR(sd3078->regmap)) {
dev_err(&client->dev, "regmap allocation failed\n");
return PTR_ERR(sd3078->regmap);
}
i2c_set_clientdata(client, sd3078);
sd3078->rtc = devm_rtc_allocate_device(&client->dev);
if (IS_ERR(sd3078->rtc))
return PTR_ERR(sd3078->rtc);
sd3078->rtc->ops = &sd3078_rtc_ops;
sd3078->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
sd3078->rtc->range_max = RTC_TIMESTAMP_END_2099;
ret = rtc_register_device(sd3078->rtc);
if (ret) {
dev_err(&client->dev, "failed to register rtc device\n");
return ret;
}
sd3078_enable_reg_write(sd3078);
return 0;
}
static const struct i2c_device_id sd3078_id[] = {
{"sd3078", 0},
{ }
};
MODULE_DEVICE_TABLE(i2c, sd3078_id);
static const struct of_device_id rtc_dt_match[] = {
{ .compatible = "whwave,sd3078" },
{},
};
MODULE_DEVICE_TABLE(of, rtc_dt_match);
struct i2c_driver sd3078_driver = {
.driver = {
.name = "sd3078",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(rtc_dt_match),
},
.probe = sd3078_probe,
.id_table = sd3078_id,
};
module_i2c_driver(sd3078_driver);
MODULE_AUTHOR("Dianlong Li <long17.cool@163.com>");
MODULE_DESCRIPTION("SD3078 RTC driver");
MODULE_LICENSE("GPL v2");
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment