#define pr_fmt(fmt) …
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/rtc.h>
#include <linux/bcd.h>
#include <linux/workqueue.h>
#include <linux/slab.h>
#include <linux/pm.h>
#ifdef CONFIG_RTC_DRV_DS1374_WDT
#include <linux/fs.h>
#include <linux/ioctl.h>
#include <linux/miscdevice.h>
#include <linux/reboot.h>
#include <linux/watchdog.h>
#endif
#define DS1374_REG_TOD0 …
#define DS1374_REG_TOD1 …
#define DS1374_REG_TOD2 …
#define DS1374_REG_TOD3 …
#define DS1374_REG_WDALM0 …
#define DS1374_REG_WDALM1 …
#define DS1374_REG_WDALM2 …
#define DS1374_REG_CR …
#define DS1374_REG_CR_AIE …
#define DS1374_REG_CR_WDSTR …
#define DS1374_REG_CR_WDALM …
#define DS1374_REG_CR_WACE …
#define DS1374_REG_SR …
#define DS1374_REG_SR_OSF …
#define DS1374_REG_SR_AF …
#define DS1374_REG_TCR …
static const struct i2c_device_id ds1374_id[] = …;
MODULE_DEVICE_TABLE(i2c, ds1374_id);
#ifdef CONFIG_OF
static const struct of_device_id ds1374_of_match[] = …;
MODULE_DEVICE_TABLE(of, ds1374_of_match);
#endif
struct ds1374 { … };
static struct i2c_driver ds1374_driver;
static int ds1374_read_rtc(struct i2c_client *client, u32 *time,
int reg, int nbytes)
{ … }
static int ds1374_write_rtc(struct i2c_client *client, u32 time,
int reg, int nbytes)
{ … }
static int ds1374_check_rtc_status(struct i2c_client *client)
{ … }
static int ds1374_read_time(struct device *dev, struct rtc_time *time)
{ … }
static int ds1374_set_time(struct device *dev, struct rtc_time *time)
{ … }
#ifndef CONFIG_RTC_DRV_DS1374_WDT
static int ds1374_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
struct i2c_client *client = to_i2c_client(dev);
struct ds1374 *ds1374 = i2c_get_clientdata(client);
u32 now, cur_alarm;
int cr, sr;
int ret = 0;
if (client->irq <= 0)
return -EINVAL;
mutex_lock(&ds1374->mutex);
cr = ret = i2c_smbus_read_byte_data(client, DS1374_REG_CR);
if (ret < 0)
goto out;
sr = ret = i2c_smbus_read_byte_data(client, DS1374_REG_SR);
if (ret < 0)
goto out;
ret = ds1374_read_rtc(client, &now, DS1374_REG_TOD0, 4);
if (ret)
goto out;
ret = ds1374_read_rtc(client, &cur_alarm, DS1374_REG_WDALM0, 3);
if (ret)
goto out;
rtc_time64_to_tm(now + cur_alarm, &alarm->time);
alarm->enabled = !!(cr & DS1374_REG_CR_WACE);
alarm->pending = !!(sr & DS1374_REG_SR_AF);
out:
mutex_unlock(&ds1374->mutex);
return ret;
}
static int ds1374_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
struct i2c_client *client = to_i2c_client(dev);
struct ds1374 *ds1374 = i2c_get_clientdata(client);
struct rtc_time now;
unsigned long new_alarm, itime;
int cr;
int ret = 0;
if (client->irq <= 0)
return -EINVAL;
ret = ds1374_read_time(dev, &now);
if (ret < 0)
return ret;
new_alarm = rtc_tm_to_time64(&alarm->time);
itime = rtc_tm_to_time64(&now);
if (time_before_eq(new_alarm, itime))
new_alarm = 1;
else
new_alarm -= itime;
mutex_lock(&ds1374->mutex);
ret = cr = i2c_smbus_read_byte_data(client, DS1374_REG_CR);
if (ret < 0)
goto out;
cr &= ~DS1374_REG_CR_WACE;
ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, cr);
if (ret < 0)
goto out;
ret = ds1374_write_rtc(client, new_alarm, DS1374_REG_WDALM0, 3);
if (ret)
goto out;
if (alarm->enabled) {
cr |= DS1374_REG_CR_WACE | DS1374_REG_CR_AIE;
cr &= ~DS1374_REG_CR_WDALM;
ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, cr);
}
out:
mutex_unlock(&ds1374->mutex);
return ret;
}
#endif
static irqreturn_t ds1374_irq(int irq, void *dev_id)
{ … }
static void ds1374_work(struct work_struct *work)
{ … }
#ifndef CONFIG_RTC_DRV_DS1374_WDT
static int ds1374_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
struct i2c_client *client = to_i2c_client(dev);
struct ds1374 *ds1374 = i2c_get_clientdata(client);
int ret;
mutex_lock(&ds1374->mutex);
ret = i2c_smbus_read_byte_data(client, DS1374_REG_CR);
if (ret < 0)
goto out;
if (enabled) {
ret |= DS1374_REG_CR_WACE | DS1374_REG_CR_AIE;
ret &= ~DS1374_REG_CR_WDALM;
} else {
ret &= ~DS1374_REG_CR_WACE;
}
ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, ret);
out:
mutex_unlock(&ds1374->mutex);
return ret;
}
#endif
static const struct rtc_class_ops ds1374_rtc_ops = …;
#ifdef CONFIG_RTC_DRV_DS1374_WDT
#define TIMER_MARGIN_DEFAULT …
#define TIMER_MARGIN_MIN …
#define TIMER_MARGIN_MAX …
static int wdt_margin;
module_param(wdt_margin, int, 0);
MODULE_PARM_DESC(…) …;
static bool nowayout = … WATCHDOG_NOWAYOUT;
module_param(nowayout, bool, 0);
MODULE_PARM_DESC(…) …;
static const struct watchdog_info ds1374_wdt_info = …;
static int ds1374_wdt_settimeout(struct watchdog_device *wdt, unsigned int timeout)
{ … }
static int ds1374_wdt_start(struct watchdog_device *wdt)
{ … }
static int ds1374_wdt_stop(struct watchdog_device *wdt)
{ … }
static const struct watchdog_ops ds1374_wdt_ops = …;
#endif
static int ds1374_probe(struct i2c_client *client)
{ … }
static void ds1374_remove(struct i2c_client *client)
{ … }
#ifdef CONFIG_PM_SLEEP
static int ds1374_suspend(struct device *dev)
{ … }
static int ds1374_resume(struct device *dev)
{ … }
#endif
static SIMPLE_DEV_PM_OPS(ds1374_pm, ds1374_suspend, ds1374_resume);
static struct i2c_driver ds1374_driver = …;
module_i2c_driver(…) …;
MODULE_AUTHOR(…) …;
MODULE_DESCRIPTION(…) …;
MODULE_LICENSE(…) …;