Commit 556d994a authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'rtc-4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux

Pull RTC updates from Alexandre Belloni:
 "RTC subsystem update:
   - Add OF device ID table for i2c drivers

  New RTC driver:
   - Motorola CPCAP PMIC RTC

  RTC driver updates:
   - cmos: fix IRQ selection
   - ds1307: Add ST m41t0 support
   - ds1374: fix watchdog configuration
   - sh: Add rza series support"

* tag 'rtc-4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (33 commits)
  rtc: gemini: add return value validation
  rtc: snvs: fix an incorrect check of return value
  rtc: ds1374: wdt: Fix stop/start ioctl always returning -EINVAL
  rtc: ds1374: wdt: Fix issue with timeout scaling from secs to wdt ticks
  rtc: sh: mark PM functions as unused
  rtc: hid-sensor-time: remove some dead code
  rtc: m41t80: Add proper compatible for rv4162
  rtc: ds1307: Add m41t0 to OF device ID table
  rtc: ds1307: support m41t0 variant
  rtc: cpcap: fix improper use of IRQ_NONE for request_threaded_irq
  rtc: cmos: Do not assume irq 8 for rtc when there are no legacy irqs
  x86: i8259: export legacy_pic symbol
  dt-bindings: rtc: document the rtc-sh bindings
  rtc: sh: add support for rza series
  rtc: cpcap: kfreeing devm allocated memory
  rtc: wm8350: Remove unused to_wm8350_from_rtc_dev
  rtc: cpcap: new rtc driver
  dt-bindings: Add vendor prefix for Motorola
  rtc: omap: mark PM methods as __maybe_unused
  rtc: omap: remove incorrect __exit markups
  ...
parents 291b38a7 332e0d13
Motorola CPCAP PMIC RTC
-----------------------
This module is part of the CPCAP. For more details about the whole
chip see Documentation/devicetree/bindings/mfd/motorola-cpcap.txt.
Requires node properties:
- compatible: should contain "motorola,cpcap-rtc"
- interrupts: An interrupt specifier for alarm and 1 Hz irq
Example:
&cpcap {
cpcap_rtc: rtc {
compatible = "motorola,cpcap-rtc";
interrupts = <39 IRQ_TYPE_NONE>, <26 IRQ_TYPE_NONE>;
};
};
* Real Time Clock for Renesas SH and ARM SoCs
Required properties:
- compatible: Should be "renesas,r7s72100-rtc" and "renesas,sh-rtc" as a
fallback.
- reg: physical base address and length of memory mapped region.
- interrupts: 3 interrupts for alarm, period, and carry.
- interrupt-names: The interrupts should be labeled as "alarm", "period", and
"carry".
- clocks: The functional clock source for the RTC controller must be listed
first (if exists). Additionally, potential clock counting sources are to be
listed.
- clock-names: The functional clock must be labeled as "fck". Other clocks
may be named in accordance to the SoC hardware manuals.
Example:
rtc: rtc@fcff1000 {
compatible = "renesas,r7s72100-rtc", "renesas,sh-rtc";
reg = <0xfcff1000 0x2e>;
interrupts = <GIC_SPI 276 IRQ_TYPE_EDGE_RISING
GIC_SPI 277 IRQ_TYPE_EDGE_RISING
GIC_SPI 278 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "alarm", "period", "carry";
clocks = <&mstp6_clks R7S72100_CLK_RTC>, <&rtc_x1_clk>,
<&rtc_x3_clk>, <&extal_clk>;
clock-names = "fck", "rtc_x1", "rtc_x3", "extal";
};
...@@ -160,6 +160,7 @@ sii,s35390a 2-wire CMOS real-time clock ...@@ -160,6 +160,7 @@ sii,s35390a 2-wire CMOS real-time clock
silabs,si7020 Relative Humidity and Temperature Sensors silabs,si7020 Relative Humidity and Temperature Sensors
skyworks,sky81452 Skyworks SKY81452: Six-Channel White LED Driver with Touch Panel Bias Supply skyworks,sky81452 Skyworks SKY81452: Six-Channel White LED Driver with Touch Panel Bias Supply
st,24c256 i2c serial eeprom (24cxx) st,24c256 i2c serial eeprom (24cxx)
st,m41t0 Serial real-time clock (RTC)
st,m41t00 Serial real-time clock (RTC) st,m41t00 Serial real-time clock (RTC)
st,m41t62 Serial real-time clock (RTC) with alarm st,m41t62 Serial real-time clock (RTC) with alarm
st,m41t80 M41T80 - SERIAL ACCESS RTC WITH ALARMS st,m41t80 M41T80 - SERIAL ACCESS RTC WITH ALARMS
......
...@@ -197,6 +197,7 @@ minix MINIX Technology Ltd. ...@@ -197,6 +197,7 @@ minix MINIX Technology Ltd.
miramems MiraMEMS Sensing Technology Co., Ltd. miramems MiraMEMS Sensing Technology Co., Ltd.
mitsubishi Mitsubishi Electric Corporation mitsubishi Mitsubishi Electric Corporation
mosaixtech Mosaix Technologies, Inc. mosaixtech Mosaix Technologies, Inc.
motorola Motorola, Inc.
moxa Moxa moxa Moxa
mpl MPL AG mpl MPL AG
mqmaker mqmaker Inc. mqmaker mqmaker Inc.
......
...@@ -418,6 +418,7 @@ struct legacy_pic default_legacy_pic = { ...@@ -418,6 +418,7 @@ struct legacy_pic default_legacy_pic = {
}; };
struct legacy_pic *legacy_pic = &default_legacy_pic; struct legacy_pic *legacy_pic = &default_legacy_pic;
EXPORT_SYMBOL(legacy_pic);
static int __init i8259A_init_ops(void) static int __init i8259A_init_ops(void)
{ {
......
...@@ -1303,10 +1303,10 @@ config RTC_DRV_SA1100 ...@@ -1303,10 +1303,10 @@ config RTC_DRV_SA1100
config RTC_DRV_SH config RTC_DRV_SH
tristate "SuperH On-Chip RTC" tristate "SuperH On-Chip RTC"
depends on SUPERH && HAVE_CLK depends on SUPERH || ARCH_RENESAS
help help
Say Y here to enable support for the on-chip RTC found in Say Y here to enable support for the on-chip RTC found in
most SuperH processors. most SuperH processors. This RTC is also found in RZ/A SoCs.
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called rtc-sh. module will be called rtc-sh.
...@@ -1731,6 +1731,13 @@ config RTC_DRV_STM32 ...@@ -1731,6 +1731,13 @@ config RTC_DRV_STM32
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-stm32". will be called "rtc-stm32".
config RTC_DRV_CPCAP
depends on MFD_CPCAP
tristate "Motorola CPCAP RTC"
help
Say y here for CPCAP rtc found on some Motorola phones
and tablets such as Droid 4.
comment "HID Sensor RTC drivers" comment "HID Sensor RTC drivers"
config RTC_DRV_HID_SENSOR_TIME config RTC_DRV_HID_SENSOR_TIME
......
...@@ -40,6 +40,7 @@ obj-$(CONFIG_RTC_DRV_BQ32K) += rtc-bq32k.o ...@@ -40,6 +40,7 @@ obj-$(CONFIG_RTC_DRV_BQ32K) += rtc-bq32k.o
obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o
obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o
obj-$(CONFIG_RTC_DRV_COH901331) += rtc-coh901331.o obj-$(CONFIG_RTC_DRV_COH901331) += rtc-coh901331.o
obj-$(CONFIG_RTC_DRV_CPCAP) += rtc-cpcap.o
obj-$(CONFIG_RTC_DRV_DA9052) += rtc-da9052.o obj-$(CONFIG_RTC_DRV_DA9052) += rtc-da9052.o
obj-$(CONFIG_RTC_DRV_DA9055) += rtc-da9055.o obj-$(CONFIG_RTC_DRV_DA9055) += rtc-da9055.o
obj-$(CONFIG_RTC_DRV_DA9063) += rtc-da9063.o obj-$(CONFIG_RTC_DRV_DA9063) += rtc-da9063.o
......
...@@ -310,9 +310,16 @@ static const struct i2c_device_id bq32k_id[] = { ...@@ -310,9 +310,16 @@ static const struct i2c_device_id bq32k_id[] = {
}; };
MODULE_DEVICE_TABLE(i2c, bq32k_id); MODULE_DEVICE_TABLE(i2c, bq32k_id);
static const struct of_device_id bq32k_of_match[] = {
{ .compatible = "ti,bq32000" },
{ }
};
MODULE_DEVICE_TABLE(of, bq32k_of_match);
static struct i2c_driver bq32k_driver = { static struct i2c_driver bq32k_driver = {
.driver = { .driver = {
.name = "bq32k", .name = "bq32k",
.of_match_table = of_match_ptr(bq32k_of_match),
}, },
.probe = bq32k_probe, .probe = bq32k_probe,
.remove = bq32k_remove, .remove = bq32k_remove,
......
...@@ -41,6 +41,9 @@ ...@@ -41,6 +41,9 @@
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#ifdef CONFIG_X86
#include <asm/i8259.h>
#endif
/* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */ /* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */
#include <linux/mc146818rtc.h> #include <linux/mc146818rtc.h>
...@@ -1193,17 +1196,23 @@ static int cmos_pnp_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) ...@@ -1193,17 +1196,23 @@ static int cmos_pnp_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
{ {
cmos_wake_setup(&pnp->dev); cmos_wake_setup(&pnp->dev);
if (pnp_port_start(pnp, 0) == 0x70 && !pnp_irq_valid(pnp, 0)) if (pnp_port_start(pnp, 0) == 0x70 && !pnp_irq_valid(pnp, 0)) {
unsigned int irq = 0;
#ifdef CONFIG_X86
/* Some machines contain a PNP entry for the RTC, but /* Some machines contain a PNP entry for the RTC, but
* don't define the IRQ. It should always be safe to * don't define the IRQ. It should always be safe to
* hardcode it in these cases * hardcode it on systems with a legacy PIC.
*/ */
if (nr_legacy_irqs())
irq = 8;
#endif
return cmos_do_probe(&pnp->dev, return cmos_do_probe(&pnp->dev,
pnp_get_resource(pnp, IORESOURCE_IO, 0), 8); pnp_get_resource(pnp, IORESOURCE_IO, 0), irq);
else } else {
return cmos_do_probe(&pnp->dev, return cmos_do_probe(&pnp->dev,
pnp_get_resource(pnp, IORESOURCE_IO, 0), pnp_get_resource(pnp, IORESOURCE_IO, 0),
pnp_irq(pnp, 0)); pnp_irq(pnp, 0));
}
} }
static void cmos_pnp_remove(struct pnp_dev *pnp) static void cmos_pnp_remove(struct pnp_dev *pnp)
......
/*
* Motorola CPCAP PMIC RTC driver
*
* Based on cpcap-regulator.c from Motorola Linux kernel tree
* Copyright (C) 2009 Motorola, Inc.
*
* Rewritten for mainline kernel
* - use DT
* - use regmap
* - use standard interrupt framework
* - use managed device resources
* - remove custom "secure clock daemon" helpers
*
* Copyright (C) 2017 Sebastian Reichel <sre@kernel.org>
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
#include <linux/err.h>
#include <linux/regmap.h>
#include <linux/mfd/motorola-cpcap.h>
#include <linux/slab.h>
#include <linux/sched.h>
#define SECS_PER_DAY 86400
#define DAY_MASK 0x7FFF
#define TOD1_MASK 0x00FF
#define TOD2_MASK 0x01FF
struct cpcap_time {
int day;
int tod1;
int tod2;
};
struct cpcap_rtc {
struct regmap *regmap;
struct rtc_device *rtc_dev;
u16 vendor;
int alarm_irq;
bool alarm_enabled;
int update_irq;
bool update_enabled;
};
static void cpcap2rtc_time(struct rtc_time *rtc, struct cpcap_time *cpcap)
{
unsigned long int tod;
unsigned long int time;
tod = (cpcap->tod1 & TOD1_MASK) | ((cpcap->tod2 & TOD2_MASK) << 8);
time = tod + ((cpcap->day & DAY_MASK) * SECS_PER_DAY);
rtc_time_to_tm(time, rtc);
}
static void rtc2cpcap_time(struct cpcap_time *cpcap, struct rtc_time *rtc)
{
unsigned long time;
rtc_tm_to_time(rtc, &time);
cpcap->day = time / SECS_PER_DAY;
time %= SECS_PER_DAY;
cpcap->tod2 = (time >> 8) & TOD2_MASK;
cpcap->tod1 = time & TOD1_MASK;
}
static int cpcap_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
struct cpcap_rtc *rtc = dev_get_drvdata(dev);
if (rtc->alarm_enabled == enabled)
return 0;
if (enabled)
enable_irq(rtc->alarm_irq);
else
disable_irq(rtc->alarm_irq);
rtc->alarm_enabled = !!enabled;
return 0;
}
static int cpcap_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct cpcap_rtc *rtc;
struct cpcap_time cpcap_tm;
int temp_tod2;
int ret;
rtc = dev_get_drvdata(dev);
ret = regmap_read(rtc->regmap, CPCAP_REG_TOD2, &temp_tod2);
ret |= regmap_read(rtc->regmap, CPCAP_REG_DAY, &cpcap_tm.day);
ret |= regmap_read(rtc->regmap, CPCAP_REG_TOD1, &cpcap_tm.tod1);
ret |= regmap_read(rtc->regmap, CPCAP_REG_TOD2, &cpcap_tm.tod2);
if (temp_tod2 > cpcap_tm.tod2)
ret |= regmap_read(rtc->regmap, CPCAP_REG_DAY, &cpcap_tm.day);
if (ret) {
dev_err(dev, "Failed to read time\n");
return -EIO;
}
cpcap2rtc_time(tm, &cpcap_tm);
return rtc_valid_tm(tm);
}
static int cpcap_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct cpcap_rtc *rtc;
struct cpcap_time cpcap_tm;
int ret = 0;
rtc = dev_get_drvdata(dev);
rtc2cpcap_time(&cpcap_tm, tm);
if (rtc->alarm_enabled)
disable_irq(rtc->alarm_irq);
if (rtc->update_enabled)
disable_irq(rtc->update_irq);
if (rtc->vendor == CPCAP_VENDOR_ST) {
/* The TOD1 and TOD2 registers MUST be written in this order
* for the change to properly set.
*/
ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD1,
TOD1_MASK, cpcap_tm.tod1);
ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD2,
TOD2_MASK, cpcap_tm.tod2);
ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_DAY,
DAY_MASK, cpcap_tm.day);
} else {
/* Clearing the upper lower 8 bits of the TOD guarantees that
* the upper half of TOD (TOD2) will not increment for 0xFF RTC
* ticks (255 seconds). During this time we can safely write
* to DAY, TOD2, then TOD1 (in that order) and expect RTC to be
* synchronized to the exact time requested upon the final write
* to TOD1.
*/
ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD1,
TOD1_MASK, 0);
ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_DAY,
DAY_MASK, cpcap_tm.day);
ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD2,
TOD2_MASK, cpcap_tm.tod2);
ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TOD1,
TOD1_MASK, cpcap_tm.tod1);
}
if (rtc->update_enabled)
enable_irq(rtc->update_irq);
if (rtc->alarm_enabled)
enable_irq(rtc->alarm_irq);
return ret;
}
static int cpcap_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct cpcap_rtc *rtc;
struct cpcap_time cpcap_tm;
int ret;
rtc = dev_get_drvdata(dev);
alrm->enabled = rtc->alarm_enabled;
ret = regmap_read(rtc->regmap, CPCAP_REG_DAYA, &cpcap_tm.day);
ret |= regmap_read(rtc->regmap, CPCAP_REG_TODA2, &cpcap_tm.tod2);
ret |= regmap_read(rtc->regmap, CPCAP_REG_TODA1, &cpcap_tm.tod1);
if (ret) {
dev_err(dev, "Failed to read time\n");
return -EIO;
}
cpcap2rtc_time(&alrm->time, &cpcap_tm);
return rtc_valid_tm(&alrm->time);
}
static int cpcap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct cpcap_rtc *rtc;
struct cpcap_time cpcap_tm;
int ret;
rtc = dev_get_drvdata(dev);
rtc2cpcap_time(&cpcap_tm, &alrm->time);
if (rtc->alarm_enabled)
disable_irq(rtc->alarm_irq);
ret = regmap_update_bits(rtc->regmap, CPCAP_REG_DAYA, DAY_MASK,
cpcap_tm.day);
ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TODA2, TOD2_MASK,
cpcap_tm.tod2);
ret |= regmap_update_bits(rtc->regmap, CPCAP_REG_TODA1, TOD1_MASK,
cpcap_tm.tod1);
if (!ret) {
enable_irq(rtc->alarm_irq);
rtc->alarm_enabled = true;
}
return ret;
}
static const struct rtc_class_ops cpcap_rtc_ops = {
.read_time = cpcap_rtc_read_time,
.set_time = cpcap_rtc_set_time,
.read_alarm = cpcap_rtc_read_alarm,
.set_alarm = cpcap_rtc_set_alarm,
.alarm_irq_enable = cpcap_rtc_alarm_irq_enable,
};
static irqreturn_t cpcap_rtc_alarm_irq(int irq, void *data)
{
struct cpcap_rtc *rtc = data;
rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF);
return IRQ_HANDLED;
}
static irqreturn_t cpcap_rtc_update_irq(int irq, void *data)
{
struct cpcap_rtc *rtc = data;
rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF);
return IRQ_HANDLED;
}
static int cpcap_rtc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct cpcap_rtc *rtc;
int err;
rtc = devm_kzalloc(dev, sizeof(*rtc), GFP_KERNEL);
if (!rtc)
return -ENOMEM;
rtc->regmap = dev_get_regmap(dev->parent, NULL);
if (!rtc->regmap)
return -ENODEV;
platform_set_drvdata(pdev, rtc);
rtc->rtc_dev = devm_rtc_device_register(dev, "cpcap_rtc",
&cpcap_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc->rtc_dev))
return PTR_ERR(rtc->rtc_dev);
err = cpcap_get_vendor(dev, rtc->regmap, &rtc->vendor);
if (err)
return err;
rtc->alarm_irq = platform_get_irq(pdev, 0);
err = devm_request_threaded_irq(dev, rtc->alarm_irq, NULL,
cpcap_rtc_alarm_irq, IRQF_TRIGGER_NONE,
"rtc_alarm", rtc);
if (err) {
dev_err(dev, "Could not request alarm irq: %d\n", err);
return err;
}
disable_irq(rtc->alarm_irq);
/* Stock Android uses the 1 Hz interrupt for "secure clock daemon",
* which is not supported by the mainline kernel. The mainline kernel
* does not use the irq at the moment, but we explicitly request and
* disable it, so that its masked and does not wake up the processor
* every second.
*/
rtc->update_irq = platform_get_irq(pdev, 1);
err = devm_request_threaded_irq(dev, rtc->update_irq, NULL,
cpcap_rtc_update_irq, IRQF_TRIGGER_NONE,
"rtc_1hz", rtc);
if (err) {
dev_err(dev, "Could not request update irq: %d\n", err);
return err;
}
disable_irq(rtc->update_irq);
err = device_init_wakeup(dev, 1);
if (err) {
dev_err(dev, "wakeup initialization failed (%d)\n", err);
/* ignore error and continue without wakeup support */
}
return 0;
}
static const struct of_device_id cpcap_rtc_of_match[] = {
{ .compatible = "motorola,cpcap-rtc", },
{},
};
MODULE_DEVICE_TABLE(of, cpcap_rtc_of_match);
static struct platform_driver cpcap_rtc_driver = {
.probe = cpcap_rtc_probe,
.driver = {
.name = "cpcap-rtc",
.of_match_table = cpcap_rtc_of_match,
},
};
module_platform_driver(cpcap_rtc_driver);
MODULE_ALIAS("platform:cpcap-rtc");
MODULE_DESCRIPTION("CPCAP RTC driver");
MODULE_AUTHOR("Sebastian Reichel <sre@kernel.org>");
MODULE_LICENSE("GPL");
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h>
#include <linux/rtc/ds1307.h> #include <linux/rtc/ds1307.h>
#include <linux/rtc.h> #include <linux/rtc.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -38,6 +39,7 @@ enum ds_type { ...@@ -38,6 +39,7 @@ enum ds_type {
ds_1340, ds_1340,
ds_1388, ds_1388,
ds_3231, ds_3231,
m41t0,
m41t00, m41t00,
mcp794xx, mcp794xx,
rx_8025, rx_8025,
...@@ -52,6 +54,7 @@ enum ds_type { ...@@ -52,6 +54,7 @@ enum ds_type {
# define DS1340_BIT_nEOSC 0x80 # define DS1340_BIT_nEOSC 0x80
# define MCP794XX_BIT_ST 0x80 # define MCP794XX_BIT_ST 0x80
#define DS1307_REG_MIN 0x01 /* 00-59 */ #define DS1307_REG_MIN 0x01 /* 00-59 */
# define M41T0_BIT_OF 0x80
#define DS1307_REG_HOUR 0x02 /* 00-23, or 1-12{am,pm} */ #define DS1307_REG_HOUR 0x02 /* 00-23, or 1-12{am,pm} */
# define DS1307_BIT_12HR 0x40 /* in REG_HOUR */ # define DS1307_BIT_12HR 0x40 /* in REG_HOUR */
# define DS1307_BIT_PM 0x20 /* in REG_HOUR */ # define DS1307_BIT_PM 0x20 /* in REG_HOUR */
...@@ -182,6 +185,7 @@ static const struct i2c_device_id ds1307_id[] = { ...@@ -182,6 +185,7 @@ static const struct i2c_device_id ds1307_id[] = {
{ "ds1388", ds_1388 }, { "ds1388", ds_1388 },
{ "ds1340", ds_1340 }, { "ds1340", ds_1340 },
{ "ds3231", ds_3231 }, { "ds3231", ds_3231 },
{ "m41t0", m41t0 },
{ "m41t00", m41t00 }, { "m41t00", m41t00 },
{ "mcp7940x", mcp794xx }, { "mcp7940x", mcp794xx },
{ "mcp7941x", mcp794xx }, { "mcp7941x", mcp794xx },
...@@ -192,6 +196,69 @@ static const struct i2c_device_id ds1307_id[] = { ...@@ -192,6 +196,69 @@ static const struct i2c_device_id ds1307_id[] = {
}; };
MODULE_DEVICE_TABLE(i2c, ds1307_id); MODULE_DEVICE_TABLE(i2c, ds1307_id);
#ifdef CONFIG_OF
static const struct of_device_id ds1307_of_match[] = {
{
.compatible = "dallas,ds1307",
.data = (void *)ds_1307
},
{
.compatible = "dallas,ds1337",
.data = (void *)ds_1337
},
{
.compatible = "dallas,ds1338",
.data = (void *)ds_1338
},
{
.compatible = "dallas,ds1339",
.data = (void *)ds_1339
},
{
.compatible = "dallas,ds1388",
.data = (void *)ds_1388
},
{
.compatible = "dallas,ds1340",
.data = (void *)ds_1340
},
{
.compatible = "maxim,ds3231",
.data = (void *)ds_3231
},
{
.compatible = "st,m41t0",
.data = (void *)m41t00
},
{
.compatible = "st,m41t00",
.data = (void *)m41t00
},
{
.compatible = "microchip,mcp7940x",
.data = (void *)mcp794xx
},
{
.compatible = "microchip,mcp7941x",
.data = (void *)mcp794xx
},
{
.compatible = "pericom,pt7c4338",
.data = (void *)ds_1307
},
{
.compatible = "epson,rx8025",
.data = (void *)rx_8025
},
{
.compatible = "isil,isl12057",
.data = (void *)ds_1337
},
{ }
};
MODULE_DEVICE_TABLE(of, ds1307_of_match);
#endif
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
static const struct acpi_device_id ds1307_acpi_ids[] = { static const struct acpi_device_id ds1307_acpi_ids[] = {
{ .id = "DS1307", .driver_data = ds_1307 }, { .id = "DS1307", .driver_data = ds_1307 },
...@@ -201,6 +268,7 @@ static const struct acpi_device_id ds1307_acpi_ids[] = { ...@@ -201,6 +268,7 @@ static const struct acpi_device_id ds1307_acpi_ids[] = {
{ .id = "DS1388", .driver_data = ds_1388 }, { .id = "DS1388", .driver_data = ds_1388 },
{ .id = "DS1340", .driver_data = ds_1340 }, { .id = "DS1340", .driver_data = ds_1340 },
{ .id = "DS3231", .driver_data = ds_3231 }, { .id = "DS3231", .driver_data = ds_3231 },
{ .id = "M41T0", .driver_data = m41t0 },
{ .id = "M41T00", .driver_data = m41t00 }, { .id = "M41T00", .driver_data = m41t00 },
{ .id = "MCP7940X", .driver_data = mcp794xx }, { .id = "MCP7940X", .driver_data = mcp794xx },
{ .id = "MCP7941X", .driver_data = mcp794xx }, { .id = "MCP7941X", .driver_data = mcp794xx },
...@@ -396,6 +464,13 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t) ...@@ -396,6 +464,13 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t)
dev_dbg(dev, "%s: %7ph\n", "read", ds1307->regs); dev_dbg(dev, "%s: %7ph\n", "read", ds1307->regs);
/* if oscillator fail bit is set, no data can be trusted */
if (ds1307->type == m41t0 &&
ds1307->regs[DS1307_REG_MIN] & M41T0_BIT_OF) {
dev_warn_once(dev, "oscillator failed, set time!\n");
return -EINVAL;
}
t->tm_sec = bcd2bin(ds1307->regs[DS1307_REG_SECS] & 0x7f); t->tm_sec = bcd2bin(ds1307->regs[DS1307_REG_SECS] & 0x7f);
t->tm_min = bcd2bin(ds1307->regs[DS1307_REG_MIN] & 0x7f); t->tm_min = bcd2bin(ds1307->regs[DS1307_REG_MIN] & 0x7f);
tmp = ds1307->regs[DS1307_REG_HOUR] & 0x3f; tmp = ds1307->regs[DS1307_REG_HOUR] & 0x3f;
...@@ -1318,7 +1393,12 @@ static int ds1307_probe(struct i2c_client *client, ...@@ -1318,7 +1393,12 @@ static int ds1307_probe(struct i2c_client *client,
i2c_set_clientdata(client, ds1307); i2c_set_clientdata(client, ds1307);
ds1307->client = client; ds1307->client = client;
if (id) {
if (client->dev.of_node) {
ds1307->type = (enum ds_type)
of_device_get_match_data(&client->dev);
chip = &chips[ds1307->type];
} else if (id) {
chip = &chips[id->driver_data]; chip = &chips[id->driver_data];
ds1307->type = id->driver_data; ds1307->type = id->driver_data;
} else { } else {
...@@ -1513,6 +1593,7 @@ static int ds1307_probe(struct i2c_client *client, ...@@ -1513,6 +1593,7 @@ static int ds1307_probe(struct i2c_client *client,
tmp = ds1307->regs[DS1307_REG_SECS]; tmp = ds1307->regs[DS1307_REG_SECS];
switch (ds1307->type) { switch (ds1307->type) {
case ds_1307: case ds_1307:
case m41t0:
case m41t00: case m41t00:
/* clock halted? turn it on, so clock can tick. */ /* clock halted? turn it on, so clock can tick. */
if (tmp & DS1307_BIT_CH) { if (tmp & DS1307_BIT_CH) {
...@@ -1577,6 +1658,7 @@ static int ds1307_probe(struct i2c_client *client, ...@@ -1577,6 +1658,7 @@ static int ds1307_probe(struct i2c_client *client,
tmp = ds1307->regs[DS1307_REG_HOUR]; tmp = ds1307->regs[DS1307_REG_HOUR];
switch (ds1307->type) { switch (ds1307->type) {
case ds_1340: case ds_1340:
case m41t0:
case m41t00: case m41t00:
/* /*
* NOTE: ignores century bits; fix before deploying * NOTE: ignores century bits; fix before deploying
...@@ -1711,6 +1793,7 @@ static int ds1307_remove(struct i2c_client *client) ...@@ -1711,6 +1793,7 @@ static int ds1307_remove(struct i2c_client *client)
static struct i2c_driver ds1307_driver = { static struct i2c_driver ds1307_driver = {
.driver = { .driver = {
.name = "rtc-ds1307", .name = "rtc-ds1307",
.of_match_table = of_match_ptr(ds1307_of_match),
.acpi_match_table = ACPI_PTR(ds1307_acpi_ids), .acpi_match_table = ACPI_PTR(ds1307_acpi_ids),
}, },
.probe = ds1307_probe, .probe = ds1307_probe,
......
...@@ -525,6 +525,10 @@ static long ds1374_wdt_ioctl(struct file *file, unsigned int cmd, ...@@ -525,6 +525,10 @@ static long ds1374_wdt_ioctl(struct file *file, unsigned int cmd,
if (get_user(new_margin, (int __user *)arg)) if (get_user(new_margin, (int __user *)arg))
return -EFAULT; return -EFAULT;
/* the hardware's tick rate is 4096 Hz, so
* the counter value needs to be scaled accordingly
*/
new_margin <<= 12;
if (new_margin < 1 || new_margin > 16777216) if (new_margin < 1 || new_margin > 16777216)
return -EINVAL; return -EINVAL;
...@@ -533,7 +537,8 @@ static long ds1374_wdt_ioctl(struct file *file, unsigned int cmd, ...@@ -533,7 +537,8 @@ static long ds1374_wdt_ioctl(struct file *file, unsigned int cmd,
ds1374_wdt_ping(); ds1374_wdt_ping();
/* fallthrough */ /* fallthrough */
case WDIOC_GETTIMEOUT: case WDIOC_GETTIMEOUT:
return put_user(wdt_margin, (int __user *)arg); /* when returning ... inverse is true */
return put_user((wdt_margin >> 12), (int __user *)arg);
case WDIOC_SETOPTIONS: case WDIOC_SETOPTIONS:
if (copy_from_user(&options, (int __user *)arg, sizeof(int))) if (copy_from_user(&options, (int __user *)arg, sizeof(int)))
return -EFAULT; return -EFAULT;
...@@ -541,14 +546,15 @@ static long ds1374_wdt_ioctl(struct file *file, unsigned int cmd, ...@@ -541,14 +546,15 @@ static long ds1374_wdt_ioctl(struct file *file, unsigned int cmd,
if (options & WDIOS_DISABLECARD) { if (options & WDIOS_DISABLECARD) {
pr_info("disable watchdog\n"); pr_info("disable watchdog\n");
ds1374_wdt_disable(); ds1374_wdt_disable();
return 0;
} }
if (options & WDIOS_ENABLECARD) { if (options & WDIOS_ENABLECARD) {
pr_info("enable watchdog\n"); pr_info("enable watchdog\n");
ds1374_wdt_settimeout(wdt_margin); ds1374_wdt_settimeout(wdt_margin);
ds1374_wdt_ping(); ds1374_wdt_ping();
return 0;
} }
return -EINVAL; return -EINVAL;
} }
return -ENOTTY; return -ENOTTY;
...@@ -704,6 +710,7 @@ static SIMPLE_DEV_PM_OPS(ds1374_pm, ds1374_suspend, ds1374_resume); ...@@ -704,6 +710,7 @@ static SIMPLE_DEV_PM_OPS(ds1374_pm, ds1374_suspend, ds1374_resume);
static struct i2c_driver ds1374_driver = { static struct i2c_driver ds1374_driver = {
.driver = { .driver = {
.name = "rtc-ds1374", .name = "rtc-ds1374",
.of_match_table = of_match_ptr(ds1374_of_match),
.pm = &ds1374_pm, .pm = &ds1374_pm,
}, },
.probe = ds1374_probe, .probe = ds1374_probe,
......
...@@ -196,9 +196,16 @@ static struct i2c_device_id ds1672_id[] = { ...@@ -196,9 +196,16 @@ static struct i2c_device_id ds1672_id[] = {
}; };
MODULE_DEVICE_TABLE(i2c, ds1672_id); MODULE_DEVICE_TABLE(i2c, ds1672_id);
static const struct of_device_id ds1672_of_match[] = {
{ .compatible = "dallas,ds1672" },
{ }
};
MODULE_DEVICE_TABLE(of, ds1672_of_match);
static struct i2c_driver ds1672_driver = { static struct i2c_driver ds1672_driver = {
.driver = { .driver = {
.name = "rtc-ds1672", .name = "rtc-ds1672",
.of_match_table = of_match_ptr(ds1672_of_match),
}, },
.probe = &ds1672_probe, .probe = &ds1672_probe,
.id_table = ds1672_id, .id_table = ds1672_id,
......
...@@ -442,9 +442,16 @@ static const struct i2c_device_id ds3232_id[] = { ...@@ -442,9 +442,16 @@ static const struct i2c_device_id ds3232_id[] = {
}; };
MODULE_DEVICE_TABLE(i2c, ds3232_id); MODULE_DEVICE_TABLE(i2c, ds3232_id);
static const struct of_device_id ds3232_of_match[] = {
{ .compatible = "dallas,ds3232" },
{ }
};
MODULE_DEVICE_TABLE(of, ds3232_of_match);
static struct i2c_driver ds3232_driver = { static struct i2c_driver ds3232_driver = {
.driver = { .driver = {
.name = "rtc-ds3232", .name = "rtc-ds3232",
.of_match_table = of_match_ptr(ds3232_of_match),
.pm = &ds3232_pm_ops, .pm = &ds3232_pm_ops,
}, },
.probe = ds3232_i2c_probe, .probe = ds3232_i2c_probe,
......
...@@ -139,6 +139,8 @@ static int gemini_rtc_probe(struct platform_device *pdev) ...@@ -139,6 +139,8 @@ static int gemini_rtc_probe(struct platform_device *pdev)
rtc->rtc_base = devm_ioremap(dev, res->start, rtc->rtc_base = devm_ioremap(dev, res->start,
resource_size(res)); resource_size(res));
if (!rtc->rtc_base)
return -ENOMEM;
ret = devm_request_irq(dev, rtc->rtc_irq, gemini_rtc_interrupt, ret = devm_request_irq(dev, rtc->rtc_irq, gemini_rtc_interrupt,
IRQF_SHARED, pdev->name, dev); IRQF_SHARED, pdev->name, dev);
......
...@@ -291,9 +291,9 @@ static int hid_time_probe(struct platform_device *pdev) ...@@ -291,9 +291,9 @@ static int hid_time_probe(struct platform_device *pdev)
"hid-sensor-time", &hid_time_rtc_ops, "hid-sensor-time", &hid_time_rtc_ops,
THIS_MODULE); THIS_MODULE);
if (IS_ERR_OR_NULL(time_state->rtc)) { if (IS_ERR(time_state->rtc)) {
hid_device_io_stop(hsdev->hdev); hid_device_io_stop(hsdev->hdev);
ret = time_state->rtc ? PTR_ERR(time_state->rtc) : -ENODEV; ret = PTR_ERR(time_state->rtc);
time_state->rtc = NULL; time_state->rtc = NULL;
dev_err(&pdev->dev, "rtc device register failed!\n"); dev_err(&pdev->dev, "rtc device register failed!\n");
goto err_rtc; goto err_rtc;
......
...@@ -687,9 +687,17 @@ static const struct i2c_device_id isl1208_id[] = { ...@@ -687,9 +687,17 @@ static const struct i2c_device_id isl1208_id[] = {
}; };
MODULE_DEVICE_TABLE(i2c, isl1208_id); MODULE_DEVICE_TABLE(i2c, isl1208_id);
static const struct of_device_id isl1208_of_match[] = {
{ .compatible = "isil,isl1208" },
{ .compatible = "isil,isl1218" },
{ }
};
MODULE_DEVICE_TABLE(of, isl1208_of_match);
static struct i2c_driver isl1208_driver = { static struct i2c_driver isl1208_driver = {
.driver = { .driver = {
.name = "rtc-isl1208", .name = "rtc-isl1208",
.of_match_table = of_match_ptr(isl1208_of_match),
}, },
.probe = isl1208_probe, .probe = isl1208_probe,
.remove = isl1208_remove, .remove = isl1208_remove,
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h>
#include <linux/rtc.h> #include <linux/rtc.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mutex.h> #include <linux/mutex.h>
...@@ -86,8 +87,66 @@ static const struct i2c_device_id m41t80_id[] = { ...@@ -86,8 +87,66 @@ static const struct i2c_device_id m41t80_id[] = {
}; };
MODULE_DEVICE_TABLE(i2c, m41t80_id); MODULE_DEVICE_TABLE(i2c, m41t80_id);
static const struct of_device_id m41t80_of_match[] = {
{
.compatible = "st,m41t62",
.data = (void *)(M41T80_FEATURE_SQ | M41T80_FEATURE_SQ_ALT)
},
{
.compatible = "st,m41t65",
.data = (void *)(M41T80_FEATURE_HT | M41T80_FEATURE_WD)
},
{
.compatible = "st,m41t80",
.data = (void *)(M41T80_FEATURE_SQ)
},
{
.compatible = "st,m41t81",
.data = (void *)(M41T80_FEATURE_HT | M41T80_FEATURE_SQ)
},
{
.compatible = "st,m41t81s",
.data = (void *)(M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ)
},
{
.compatible = "st,m41t82",
.data = (void *)(M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ)
},
{
.compatible = "st,m41t83",
.data = (void *)(M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ)
},
{
.compatible = "st,m41t84",
.data = (void *)(M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ)
},
{
.compatible = "st,m41t85",
.data = (void *)(M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ)
},
{
.compatible = "st,m41t87",
.data = (void *)(M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ)
},
{
.compatible = "microcrystal,rv4162",
.data = (void *)(M41T80_FEATURE_SQ | M41T80_FEATURE_WD | M41T80_FEATURE_SQ_ALT)
},
/* DT compatibility only, do not use compatibles below: */
{
.compatible = "st,rv4162",
.data = (void *)(M41T80_FEATURE_SQ | M41T80_FEATURE_WD | M41T80_FEATURE_SQ_ALT)
},
{
.compatible = "rv4162",
.data = (void *)(M41T80_FEATURE_SQ | M41T80_FEATURE_WD | M41T80_FEATURE_SQ_ALT)
},
{ }
};
MODULE_DEVICE_TABLE(of, m41t80_of_match);
struct m41t80_data { struct m41t80_data {
u8 features; unsigned long features;
struct rtc_device *rtc; struct rtc_device *rtc;
}; };
...@@ -786,6 +845,10 @@ static int m41t80_probe(struct i2c_client *client, ...@@ -786,6 +845,10 @@ static int m41t80_probe(struct i2c_client *client,
if (!m41t80_data) if (!m41t80_data)
return -ENOMEM; return -ENOMEM;
if (client->dev.of_node)
m41t80_data->features = (unsigned long)
of_device_get_match_data(&client->dev);
else
m41t80_data->features = id->driver_data; m41t80_data->features = id->driver_data;
i2c_set_clientdata(client, m41t80_data); i2c_set_clientdata(client, m41t80_data);
...@@ -894,6 +957,7 @@ static int m41t80_remove(struct i2c_client *client) ...@@ -894,6 +957,7 @@ static int m41t80_remove(struct i2c_client *client)
static struct i2c_driver m41t80_driver = { static struct i2c_driver m41t80_driver = {
.driver = { .driver = {
.name = "rtc-m41t80", .name = "rtc-m41t80",
.of_match_table = of_match_ptr(m41t80_of_match),
.pm = &m41t80_pm, .pm = &m41t80_pm,
}, },
.probe = m41t80_probe, .probe = m41t80_probe,
......
...@@ -844,7 +844,7 @@ static int omap_rtc_probe(struct platform_device *pdev) ...@@ -844,7 +844,7 @@ static int omap_rtc_probe(struct platform_device *pdev)
return ret; return ret;
} }
static int __exit omap_rtc_remove(struct platform_device *pdev) static int omap_rtc_remove(struct platform_device *pdev)
{ {
struct omap_rtc *rtc = platform_get_drvdata(pdev); struct omap_rtc *rtc = platform_get_drvdata(pdev);
u8 reg; u8 reg;
...@@ -882,8 +882,7 @@ static int __exit omap_rtc_remove(struct platform_device *pdev) ...@@ -882,8 +882,7 @@ static int __exit omap_rtc_remove(struct platform_device *pdev)
return 0; return 0;
} }
#ifdef CONFIG_PM_SLEEP static int __maybe_unused omap_rtc_suspend(struct device *dev)
static int omap_rtc_suspend(struct device *dev)
{ {
struct omap_rtc *rtc = dev_get_drvdata(dev); struct omap_rtc *rtc = dev_get_drvdata(dev);
...@@ -906,7 +905,7 @@ static int omap_rtc_suspend(struct device *dev) ...@@ -906,7 +905,7 @@ static int omap_rtc_suspend(struct device *dev)
return 0; return 0;
} }
static int omap_rtc_resume(struct device *dev) static int __maybe_unused omap_rtc_resume(struct device *dev)
{ {
struct omap_rtc *rtc = dev_get_drvdata(dev); struct omap_rtc *rtc = dev_get_drvdata(dev);
...@@ -921,10 +920,8 @@ static int omap_rtc_resume(struct device *dev) ...@@ -921,10 +920,8 @@ static int omap_rtc_resume(struct device *dev)
return 0; return 0;
} }
#endif
#ifdef CONFIG_PM static int __maybe_unused omap_rtc_runtime_suspend(struct device *dev)
static int omap_rtc_runtime_suspend(struct device *dev)
{ {
struct omap_rtc *rtc = dev_get_drvdata(dev); struct omap_rtc *rtc = dev_get_drvdata(dev);
...@@ -934,16 +931,9 @@ static int omap_rtc_runtime_suspend(struct device *dev) ...@@ -934,16 +931,9 @@ static int omap_rtc_runtime_suspend(struct device *dev)
return 0; return 0;
} }
static int omap_rtc_runtime_resume(struct device *dev)
{
return 0;
}
#endif
static const struct dev_pm_ops omap_rtc_pm_ops = { static const struct dev_pm_ops omap_rtc_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(omap_rtc_suspend, omap_rtc_resume) SET_SYSTEM_SLEEP_PM_OPS(omap_rtc_suspend, omap_rtc_resume)
SET_RUNTIME_PM_OPS(omap_rtc_runtime_suspend, SET_RUNTIME_PM_OPS(omap_rtc_runtime_suspend, NULL, NULL)
omap_rtc_runtime_resume, NULL)
}; };
static void omap_rtc_shutdown(struct platform_device *pdev) static void omap_rtc_shutdown(struct platform_device *pdev)
...@@ -964,7 +954,7 @@ static void omap_rtc_shutdown(struct platform_device *pdev) ...@@ -964,7 +954,7 @@ static void omap_rtc_shutdown(struct platform_device *pdev)
static struct platform_driver omap_rtc_driver = { static struct platform_driver omap_rtc_driver = {
.probe = omap_rtc_probe, .probe = omap_rtc_probe,
.remove = __exit_p(omap_rtc_remove), .remove = omap_rtc_remove,
.shutdown = omap_rtc_shutdown, .shutdown = omap_rtc_shutdown,
.driver = { .driver = {
.name = "omap_rtc", .name = "omap_rtc",
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/bcd.h> #include <linux/bcd.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h>
/* /*
* Ricoh has a family of I2C based RTCs, which differ only slightly from * Ricoh has a family of I2C based RTCs, which differ only slightly from
...@@ -83,6 +84,35 @@ static const struct i2c_device_id rs5c372_id[] = { ...@@ -83,6 +84,35 @@ static const struct i2c_device_id rs5c372_id[] = {
}; };
MODULE_DEVICE_TABLE(i2c, rs5c372_id); MODULE_DEVICE_TABLE(i2c, rs5c372_id);
static const struct of_device_id rs5c372_of_match[] = {
{
.compatible = "ricoh,r2025sd",
.data = (void *)rtc_r2025sd
},
{
.compatible = "ricoh,r2221tl",
.data = (void *)rtc_r2221tl
},
{
.compatible = "ricoh,rs5c372a",
.data = (void *)rtc_rs5c372a
},
{
.compatible = "ricoh,rs5c372b",
.data = (void *)rtc_rs5c372b
},
{
.compatible = "ricoh,rv5c386",
.data = (void *)rtc_rv5c386
},
{
.compatible = "ricoh,rv5c387a",
.data = (void *)rtc_rv5c387a
},
{ }
};
MODULE_DEVICE_TABLE(of, rs5c372_of_match);
/* REVISIT: this assumes that: /* REVISIT: this assumes that:
* - we're in the 21st century, so it's safe to ignore the century * - we're in the 21st century, so it's safe to ignore the century
* bit for rv5c38[67] (REG_MONTH bit 7); * bit for rv5c38[67] (REG_MONTH bit 7);
...@@ -581,6 +611,10 @@ static int rs5c372_probe(struct i2c_client *client, ...@@ -581,6 +611,10 @@ static int rs5c372_probe(struct i2c_client *client,
rs5c372->client = client; rs5c372->client = client;
i2c_set_clientdata(client, rs5c372); i2c_set_clientdata(client, rs5c372);
if (client->dev.of_node)
rs5c372->type = (enum rtc_type)
of_device_get_match_data(&client->dev);
else
rs5c372->type = id->driver_data; rs5c372->type = id->driver_data;
/* we read registers 0x0f then 0x00-0x0f; skip the first one */ /* we read registers 0x0f then 0x00-0x0f; skip the first one */
...@@ -673,6 +707,7 @@ static int rs5c372_remove(struct i2c_client *client) ...@@ -673,6 +707,7 @@ static int rs5c372_remove(struct i2c_client *client)
static struct i2c_driver rs5c372_driver = { static struct i2c_driver rs5c372_driver = {
.driver = { .driver = {
.name = "rtc-rs5c372", .name = "rtc-rs5c372",
.of_match_table = of_match_ptr(rs5c372_of_match),
}, },
.probe = rs5c372_probe, .probe = rs5c372_probe,
.remove = rs5c372_remove, .remove = rs5c372_remove,
......
...@@ -875,9 +875,18 @@ static struct i2c_device_id rv3029_id[] = { ...@@ -875,9 +875,18 @@ static struct i2c_device_id rv3029_id[] = {
}; };
MODULE_DEVICE_TABLE(i2c, rv3029_id); MODULE_DEVICE_TABLE(i2c, rv3029_id);
static const struct of_device_id rv3029_of_match[] = {
{ .compatible = "rv3029" },
{ .compatible = "rv3029c2" },
{ .compatible = "mc,rv3029c2" },
{ }
};
MODULE_DEVICE_TABLE(of, rv3029_of_match);
static struct i2c_driver rv3029_driver = { static struct i2c_driver rv3029_driver = {
.driver = { .driver = {
.name = "rtc-rv3029c2", .name = "rtc-rv3029c2",
.of_match_table = of_match_ptr(rv3029_of_match),
}, },
.probe = rv3029_i2c_probe, .probe = rv3029_i2c_probe,
.id_table = rv3029_id, .id_table = rv3029_id,
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h>
#include <linux/rtc.h> #include <linux/rtc.h>
#define RV8803_I2C_TRY_COUNT 4 #define RV8803_I2C_TRY_COUNT 4
...@@ -556,6 +557,10 @@ static int rv8803_probe(struct i2c_client *client, ...@@ -556,6 +557,10 @@ static int rv8803_probe(struct i2c_client *client,
mutex_init(&rv8803->flags_lock); mutex_init(&rv8803->flags_lock);
rv8803->client = client; rv8803->client = client;
if (client->dev.of_node)
rv8803->type = (enum rv8803_type)
of_device_get_match_data(&client->dev);
else
rv8803->type = id->driver_data; rv8803->type = id->driver_data;
i2c_set_clientdata(client, rv8803); i2c_set_clientdata(client, rv8803);
...@@ -627,9 +632,23 @@ static const struct i2c_device_id rv8803_id[] = { ...@@ -627,9 +632,23 @@ static const struct i2c_device_id rv8803_id[] = {
}; };
MODULE_DEVICE_TABLE(i2c, rv8803_id); MODULE_DEVICE_TABLE(i2c, rv8803_id);
static const struct of_device_id rv8803_of_match[] = {
{
.compatible = "microcrystal,rv8803",
.data = (void *)rx_8900
},
{
.compatible = "epson,rx8900",
.data = (void *)rx_8900
},
{ }
};
MODULE_DEVICE_TABLE(of, rv8803_of_match);
static struct i2c_driver rv8803_driver = { static struct i2c_driver rv8803_driver = {
.driver = { .driver = {
.name = "rtc-rv8803", .name = "rtc-rv8803",
.of_match_table = of_match_ptr(rv8803_of_match),
}, },
.probe = rv8803_probe, .probe = rv8803_probe,
.remove = rv8803_remove, .remove = rv8803_remove,
......
...@@ -59,6 +59,12 @@ static const struct i2c_device_id rx8010_id[] = { ...@@ -59,6 +59,12 @@ static const struct i2c_device_id rx8010_id[] = {
}; };
MODULE_DEVICE_TABLE(i2c, rx8010_id); MODULE_DEVICE_TABLE(i2c, rx8010_id);
static const struct of_device_id rx8010_of_match[] = {
{ .compatible = "epson,rx8010" },
{ }
};
MODULE_DEVICE_TABLE(of, rx8010_of_match);
struct rx8010_data { struct rx8010_data {
struct i2c_client *client; struct i2c_client *client;
struct rtc_device *rtc; struct rtc_device *rtc;
...@@ -487,6 +493,7 @@ static int rx8010_probe(struct i2c_client *client, ...@@ -487,6 +493,7 @@ static int rx8010_probe(struct i2c_client *client,
static struct i2c_driver rx8010_driver = { static struct i2c_driver rx8010_driver = {
.driver = { .driver = {
.name = "rtc-rx8010", .name = "rtc-rx8010",
.of_match_table = of_match_ptr(rx8010_of_match),
}, },
.probe = rx8010_probe, .probe = rx8010_probe,
.id_table = rx8010_id, .id_table = rx8010_id,
......
...@@ -308,9 +308,16 @@ static const struct i2c_device_id rx8581_id[] = { ...@@ -308,9 +308,16 @@ static const struct i2c_device_id rx8581_id[] = {
}; };
MODULE_DEVICE_TABLE(i2c, rx8581_id); MODULE_DEVICE_TABLE(i2c, rx8581_id);
static const struct of_device_id rx8581_of_match[] = {
{ .compatible = "epson,rx8581" },
{ }
};
MODULE_DEVICE_TABLE(of, rx8581_of_match);
static struct i2c_driver rx8581_driver = { static struct i2c_driver rx8581_driver = {
.driver = { .driver = {
.name = "rtc-rx8581", .name = "rtc-rx8581",
.of_match_table = of_match_ptr(rx8581_of_match),
}, },
.probe = rx8581_probe, .probe = rx8581_probe,
.id_table = rx8581_id, .id_table = rx8581_id,
......
...@@ -58,6 +58,13 @@ static const struct i2c_device_id s35390a_id[] = { ...@@ -58,6 +58,13 @@ static const struct i2c_device_id s35390a_id[] = {
}; };
MODULE_DEVICE_TABLE(i2c, s35390a_id); MODULE_DEVICE_TABLE(i2c, s35390a_id);
static const struct of_device_id s35390a_of_match[] = {
{ .compatible = "s35390a" },
{ .compatible = "sii,s35390a" },
{ }
};
MODULE_DEVICE_TABLE(of, s35390a_of_match);
struct s35390a { struct s35390a {
struct i2c_client *client[8]; struct i2c_client *client[8];
struct rtc_device *rtc; struct rtc_device *rtc;
...@@ -502,6 +509,7 @@ static int s35390a_remove(struct i2c_client *client) ...@@ -502,6 +509,7 @@ static int s35390a_remove(struct i2c_client *client)
static struct i2c_driver s35390a_driver = { static struct i2c_driver s35390a_driver = {
.driver = { .driver = {
.name = "rtc-s35390a", .name = "rtc-s35390a",
.of_match_table = of_match_ptr(s35390a_of_match),
}, },
.probe = s35390a_probe, .probe = s35390a_probe,
.remove = s35390a_remove, .remove = s35390a_remove,
......
...@@ -27,7 +27,15 @@ ...@@ -27,7 +27,15 @@
#include <linux/log2.h> #include <linux/log2.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/slab.h> #include <linux/slab.h>
#ifdef CONFIG_SUPERH
#include <asm/rtc.h> #include <asm/rtc.h>
#else
/* Default values for RZ/A RTC */
#define rtc_reg_size sizeof(u16)
#define RTC_BIT_INVERTED 0 /* no chip bugs */
#define RTC_CAP_4_DIGIT_YEAR (1 << 0)
#define RTC_DEF_CAPABILITIES RTC_CAP_4_DIGIT_YEAR
#endif
#define DRV_NAME "sh-rtc" #define DRV_NAME "sh-rtc"
...@@ -570,6 +578,8 @@ static int __init sh_rtc_probe(struct platform_device *pdev) ...@@ -570,6 +578,8 @@ static int __init sh_rtc_probe(struct platform_device *pdev)
rtc->alarm_irq = platform_get_irq(pdev, 2); rtc->alarm_irq = platform_get_irq(pdev, 2);
res = platform_get_resource(pdev, IORESOURCE_IO, 0); res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (!res)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (unlikely(res == NULL)) { if (unlikely(res == NULL)) {
dev_err(&pdev->dev, "No IO resource\n"); dev_err(&pdev->dev, "No IO resource\n");
return -ENOENT; return -ENOENT;
...@@ -587,12 +597,15 @@ static int __init sh_rtc_probe(struct platform_device *pdev) ...@@ -587,12 +597,15 @@ static int __init sh_rtc_probe(struct platform_device *pdev)
if (unlikely(!rtc->regbase)) if (unlikely(!rtc->regbase))
return -EINVAL; return -EINVAL;
if (!pdev->dev.of_node) {
clk_id = pdev->id; clk_id = pdev->id;
/* With a single device, the clock id is still "rtc0" */ /* With a single device, the clock id is still "rtc0" */
if (clk_id < 0) if (clk_id < 0)
clk_id = 0; clk_id = 0;
snprintf(clk_name, sizeof(clk_name), "rtc%d", clk_id); snprintf(clk_name, sizeof(clk_name), "rtc%d", clk_id);
} else
snprintf(clk_name, sizeof(clk_name), "fck");
rtc->clk = devm_clk_get(&pdev->dev, clk_name); rtc->clk = devm_clk_get(&pdev->dev, clk_name);
if (IS_ERR(rtc->clk)) { if (IS_ERR(rtc->clk)) {
...@@ -608,6 +621,8 @@ static int __init sh_rtc_probe(struct platform_device *pdev) ...@@ -608,6 +621,8 @@ static int __init sh_rtc_probe(struct platform_device *pdev)
clk_enable(rtc->clk); clk_enable(rtc->clk);
rtc->capabilities = RTC_DEF_CAPABILITIES; rtc->capabilities = RTC_DEF_CAPABILITIES;
#ifdef CONFIG_SUPERH
if (dev_get_platdata(&pdev->dev)) { if (dev_get_platdata(&pdev->dev)) {
struct sh_rtc_platform_info *pinfo = struct sh_rtc_platform_info *pinfo =
dev_get_platdata(&pdev->dev); dev_get_platdata(&pdev->dev);
...@@ -618,6 +633,7 @@ static int __init sh_rtc_probe(struct platform_device *pdev) ...@@ -618,6 +633,7 @@ static int __init sh_rtc_probe(struct platform_device *pdev)
*/ */
rtc->capabilities |= pinfo->capabilities; rtc->capabilities |= pinfo->capabilities;
} }
#endif
if (rtc->carry_irq <= 0) { if (rtc->carry_irq <= 0) {
/* register shared periodic/carry/alarm irq */ /* register shared periodic/carry/alarm irq */
...@@ -718,8 +734,7 @@ static void sh_rtc_set_irq_wake(struct device *dev, int enabled) ...@@ -718,8 +734,7 @@ static void sh_rtc_set_irq_wake(struct device *dev, int enabled)
} }
} }
#ifdef CONFIG_PM_SLEEP static int __maybe_unused sh_rtc_suspend(struct device *dev)
static int sh_rtc_suspend(struct device *dev)
{ {
if (device_may_wakeup(dev)) if (device_may_wakeup(dev))
sh_rtc_set_irq_wake(dev, 1); sh_rtc_set_irq_wake(dev, 1);
...@@ -727,21 +742,27 @@ static int sh_rtc_suspend(struct device *dev) ...@@ -727,21 +742,27 @@ static int sh_rtc_suspend(struct device *dev)
return 0; return 0;
} }
static int sh_rtc_resume(struct device *dev) static int __maybe_unused sh_rtc_resume(struct device *dev)
{ {
if (device_may_wakeup(dev)) if (device_may_wakeup(dev))
sh_rtc_set_irq_wake(dev, 0); sh_rtc_set_irq_wake(dev, 0);
return 0; return 0;
} }
#endif
static SIMPLE_DEV_PM_OPS(sh_rtc_pm_ops, sh_rtc_suspend, sh_rtc_resume); static SIMPLE_DEV_PM_OPS(sh_rtc_pm_ops, sh_rtc_suspend, sh_rtc_resume);
static const struct of_device_id sh_rtc_of_match[] = {
{ .compatible = "renesas,sh-rtc", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sh_rtc_of_match);
static struct platform_driver sh_rtc_platform_driver = { static struct platform_driver sh_rtc_platform_driver = {
.driver = { .driver = {
.name = DRV_NAME, .name = DRV_NAME,
.pm = &sh_rtc_pm_ops, .pm = &sh_rtc_pm_ops,
.of_match_table = sh_rtc_of_match,
}, },
.remove = __exit_p(sh_rtc_remove), .remove = __exit_p(sh_rtc_remove),
}; };
......
...@@ -258,7 +258,7 @@ static int snvs_rtc_probe(struct platform_device *pdev) ...@@ -258,7 +258,7 @@ static int snvs_rtc_probe(struct platform_device *pdev)
of_property_read_u32(pdev->dev.of_node, "offset", &data->offset); of_property_read_u32(pdev->dev.of_node, "offset", &data->offset);
} }
if (!data->regmap) { if (IS_ERR(data->regmap)) {
dev_err(&pdev->dev, "Can't find snvs syscon\n"); dev_err(&pdev->dev, "Can't find snvs syscon\n");
return -ENODEV; return -ENODEV;
} }
......
...@@ -30,8 +30,6 @@ ...@@ -30,8 +30,6 @@
#define WM8350_SET_TIME_RETRIES 5 #define WM8350_SET_TIME_RETRIES 5
#define WM8350_GET_TIME_RETRIES 5 #define WM8350_GET_TIME_RETRIES 5
#define to_wm8350_from_rtc_dev(d) container_of(d, struct wm8350, rtc.pdev.dev)
/* /*
* Read current time and date in RTC * Read current time and date in RTC
*/ */
......
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