brintos

brintos / linux-shallow public Read only

0
0
Text · 14.1 KiB · c2359eb Raw
585 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * RTC client/driver for the Maxim/Dallas DS1374 Real-Time Clock over I2C4 *5 * Based on code by Randy Vinson <rvinson@mvista.com>,6 * which was based on the m41t00.c by Mark Greer <mgreer@mvista.com>.7 *8 * Copyright (C) 2014 Rose Technology9 * Copyright (C) 2006-2007 Freescale Semiconductor10 * Copyright (c) 2005 MontaVista Software, Inc.11 */12/*13 * It would be more efficient to use i2c msgs/i2c_transfer directly but, as14 * recommended in .../Documentation/i2c/writing-clients.rst section15 * "Sending and receiving", using SMBus level communication is preferred.16 */17 18#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt19 20#include <linux/kernel.h>21#include <linux/module.h>22#include <linux/interrupt.h>23#include <linux/i2c.h>24#include <linux/rtc.h>25#include <linux/bcd.h>26#include <linux/workqueue.h>27#include <linux/slab.h>28#include <linux/pm.h>29#ifdef CONFIG_RTC_DRV_DS1374_WDT30#include <linux/fs.h>31#include <linux/ioctl.h>32#include <linux/miscdevice.h>33#include <linux/reboot.h>34#include <linux/watchdog.h>35#endif36 37#define DS1374_REG_TOD0		0x00 /* Time of Day */38#define DS1374_REG_TOD1		0x0139#define DS1374_REG_TOD2		0x0240#define DS1374_REG_TOD3		0x0341#define DS1374_REG_WDALM0	0x04 /* Watchdog/Alarm */42#define DS1374_REG_WDALM1	0x0543#define DS1374_REG_WDALM2	0x0644#define DS1374_REG_CR		0x07 /* Control */45#define DS1374_REG_CR_AIE	0x01 /* Alarm Int. Enable */46#define DS1374_REG_CR_WDSTR	0x08 /* 1=INT, 0=RST */47#define DS1374_REG_CR_WDALM	0x20 /* 1=Watchdog, 0=Alarm */48#define DS1374_REG_CR_WACE	0x40 /* WD/Alarm counter enable */49#define DS1374_REG_SR		0x08 /* Status */50#define DS1374_REG_SR_OSF	0x80 /* Oscillator Stop Flag */51#define DS1374_REG_SR_AF	0x01 /* Alarm Flag */52#define DS1374_REG_TCR		0x09 /* Trickle Charge */53 54static const struct i2c_device_id ds1374_id[] = {55	{ "ds1374" },56	{ }57};58MODULE_DEVICE_TABLE(i2c, ds1374_id);59 60#ifdef CONFIG_OF61static const struct of_device_id ds1374_of_match[] = {62	{ .compatible = "dallas,ds1374" },63	{ }64};65MODULE_DEVICE_TABLE(of, ds1374_of_match);66#endif67 68struct ds1374 {69	struct i2c_client *client;70	struct rtc_device *rtc;71	struct work_struct work;72#ifdef CONFIG_RTC_DRV_DS1374_WDT73	struct watchdog_device wdt;74#endif75	/* The mutex protects alarm operations, and prevents a race76	 * between the enable_irq() in the workqueue and the free_irq()77	 * in the remove function.78	 */79	struct mutex mutex;80	int exiting;81};82 83static struct i2c_driver ds1374_driver;84 85static int ds1374_read_rtc(struct i2c_client *client, u32 *time,86			   int reg, int nbytes)87{88	u8 buf[4];89	int ret;90	int i;91 92	if (WARN_ON(nbytes > 4))93		return -EINVAL;94 95	ret = i2c_smbus_read_i2c_block_data(client, reg, nbytes, buf);96 97	if (ret < 0)98		return ret;99	if (ret < nbytes)100		return -EIO;101 102	for (i = nbytes - 1, *time = 0; i >= 0; i--)103		*time = (*time << 8) | buf[i];104 105	return 0;106}107 108static int ds1374_write_rtc(struct i2c_client *client, u32 time,109			    int reg, int nbytes)110{111	u8 buf[4];112	int i;113 114	if (nbytes > 4) {115		WARN_ON(1);116		return -EINVAL;117	}118 119	for (i = 0; i < nbytes; i++) {120		buf[i] = time & 0xff;121		time >>= 8;122	}123 124	return i2c_smbus_write_i2c_block_data(client, reg, nbytes, buf);125}126 127static int ds1374_check_rtc_status(struct i2c_client *client)128{129	int ret = 0;130	int control, stat;131 132	stat = i2c_smbus_read_byte_data(client, DS1374_REG_SR);133	if (stat < 0)134		return stat;135 136	if (stat & DS1374_REG_SR_OSF)137		dev_warn(&client->dev,138			 "oscillator discontinuity flagged, time unreliable\n");139 140	stat &= ~(DS1374_REG_SR_OSF | DS1374_REG_SR_AF);141 142	ret = i2c_smbus_write_byte_data(client, DS1374_REG_SR, stat);143	if (ret < 0)144		return ret;145 146	/* If the alarm is pending, clear it before requesting147	 * the interrupt, so an interrupt event isn't reported148	 * before everything is initialized.149	 */150 151	control = i2c_smbus_read_byte_data(client, DS1374_REG_CR);152	if (control < 0)153		return control;154 155	control &= ~(DS1374_REG_CR_WACE | DS1374_REG_CR_AIE);156	return i2c_smbus_write_byte_data(client, DS1374_REG_CR, control);157}158 159static int ds1374_read_time(struct device *dev, struct rtc_time *time)160{161	struct i2c_client *client = to_i2c_client(dev);162	u32 itime;163	int ret;164 165	ret = ds1374_read_rtc(client, &itime, DS1374_REG_TOD0, 4);166	if (!ret)167		rtc_time64_to_tm(itime, time);168 169	return ret;170}171 172static int ds1374_set_time(struct device *dev, struct rtc_time *time)173{174	struct i2c_client *client = to_i2c_client(dev);175	unsigned long itime = rtc_tm_to_time64(time);176 177	return ds1374_write_rtc(client, itime, DS1374_REG_TOD0, 4);178}179 180#ifndef CONFIG_RTC_DRV_DS1374_WDT181/* The ds1374 has a decrementer for an alarm, rather than a comparator.182 * If the time of day is changed, then the alarm will need to be183 * reset.184 */185static int ds1374_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)186{187	struct i2c_client *client = to_i2c_client(dev);188	struct ds1374 *ds1374 = i2c_get_clientdata(client);189	u32 now, cur_alarm;190	int cr, sr;191	int ret = 0;192 193	if (client->irq <= 0)194		return -EINVAL;195 196	mutex_lock(&ds1374->mutex);197 198	cr = ret = i2c_smbus_read_byte_data(client, DS1374_REG_CR);199	if (ret < 0)200		goto out;201 202	sr = ret = i2c_smbus_read_byte_data(client, DS1374_REG_SR);203	if (ret < 0)204		goto out;205 206	ret = ds1374_read_rtc(client, &now, DS1374_REG_TOD0, 4);207	if (ret)208		goto out;209 210	ret = ds1374_read_rtc(client, &cur_alarm, DS1374_REG_WDALM0, 3);211	if (ret)212		goto out;213 214	rtc_time64_to_tm(now + cur_alarm, &alarm->time);215	alarm->enabled = !!(cr & DS1374_REG_CR_WACE);216	alarm->pending = !!(sr & DS1374_REG_SR_AF);217 218out:219	mutex_unlock(&ds1374->mutex);220	return ret;221}222 223static int ds1374_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)224{225	struct i2c_client *client = to_i2c_client(dev);226	struct ds1374 *ds1374 = i2c_get_clientdata(client);227	struct rtc_time now;228	unsigned long new_alarm, itime;229	int cr;230	int ret = 0;231 232	if (client->irq <= 0)233		return -EINVAL;234 235	ret = ds1374_read_time(dev, &now);236	if (ret < 0)237		return ret;238 239	new_alarm = rtc_tm_to_time64(&alarm->time);240	itime = rtc_tm_to_time64(&now);241 242	/* This can happen due to races, in addition to dates that are243	 * truly in the past.  To avoid requiring the caller to check for244	 * races, dates in the past are assumed to be in the recent past245	 * (i.e. not something that we'd rather the caller know about via246	 * an error), and the alarm is set to go off as soon as possible.247	 */248	if (time_before_eq(new_alarm, itime))249		new_alarm = 1;250	else251		new_alarm -= itime;252 253	mutex_lock(&ds1374->mutex);254 255	ret = cr = i2c_smbus_read_byte_data(client, DS1374_REG_CR);256	if (ret < 0)257		goto out;258 259	/* Disable any existing alarm before setting the new one260	 * (or lack thereof). */261	cr &= ~DS1374_REG_CR_WACE;262 263	ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, cr);264	if (ret < 0)265		goto out;266 267	ret = ds1374_write_rtc(client, new_alarm, DS1374_REG_WDALM0, 3);268	if (ret)269		goto out;270 271	if (alarm->enabled) {272		cr |= DS1374_REG_CR_WACE | DS1374_REG_CR_AIE;273		cr &= ~DS1374_REG_CR_WDALM;274 275		ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, cr);276	}277 278out:279	mutex_unlock(&ds1374->mutex);280	return ret;281}282#endif283 284static irqreturn_t ds1374_irq(int irq, void *dev_id)285{286	struct i2c_client *client = dev_id;287	struct ds1374 *ds1374 = i2c_get_clientdata(client);288 289	disable_irq_nosync(irq);290	schedule_work(&ds1374->work);291	return IRQ_HANDLED;292}293 294static void ds1374_work(struct work_struct *work)295{296	struct ds1374 *ds1374 = container_of(work, struct ds1374, work);297	struct i2c_client *client = ds1374->client;298	int stat, control;299 300	mutex_lock(&ds1374->mutex);301 302	stat = i2c_smbus_read_byte_data(client, DS1374_REG_SR);303	if (stat < 0)304		goto unlock;305 306	if (stat & DS1374_REG_SR_AF) {307		stat &= ~DS1374_REG_SR_AF;308		i2c_smbus_write_byte_data(client, DS1374_REG_SR, stat);309 310		control = i2c_smbus_read_byte_data(client, DS1374_REG_CR);311		if (control < 0)312			goto out;313 314		control &= ~(DS1374_REG_CR_WACE | DS1374_REG_CR_AIE);315		i2c_smbus_write_byte_data(client, DS1374_REG_CR, control);316 317		rtc_update_irq(ds1374->rtc, 1, RTC_AF | RTC_IRQF);318	}319 320out:321	if (!ds1374->exiting)322		enable_irq(client->irq);323unlock:324	mutex_unlock(&ds1374->mutex);325}326 327#ifndef CONFIG_RTC_DRV_DS1374_WDT328static int ds1374_alarm_irq_enable(struct device *dev, unsigned int enabled)329{330	struct i2c_client *client = to_i2c_client(dev);331	struct ds1374 *ds1374 = i2c_get_clientdata(client);332	int ret;333 334	mutex_lock(&ds1374->mutex);335 336	ret = i2c_smbus_read_byte_data(client, DS1374_REG_CR);337	if (ret < 0)338		goto out;339 340	if (enabled) {341		ret |= DS1374_REG_CR_WACE | DS1374_REG_CR_AIE;342		ret &= ~DS1374_REG_CR_WDALM;343	} else {344		ret &= ~DS1374_REG_CR_WACE;345	}346	ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, ret);347 348out:349	mutex_unlock(&ds1374->mutex);350	return ret;351}352#endif353 354static const struct rtc_class_ops ds1374_rtc_ops = {355	.read_time = ds1374_read_time,356	.set_time = ds1374_set_time,357#ifndef CONFIG_RTC_DRV_DS1374_WDT358	.read_alarm = ds1374_read_alarm,359	.set_alarm = ds1374_set_alarm,360	.alarm_irq_enable = ds1374_alarm_irq_enable,361#endif362};363 364#ifdef CONFIG_RTC_DRV_DS1374_WDT365/*366 *****************************************************************************367 *368 * Watchdog Driver369 *370 *****************************************************************************371 */372/* Default margin */373#define TIMER_MARGIN_DEFAULT	32374#define TIMER_MARGIN_MIN	1375#define TIMER_MARGIN_MAX	4095 /* 24-bit value */376 377static int wdt_margin;378module_param(wdt_margin, int, 0);379MODULE_PARM_DESC(wdt_margin, "Watchdog timeout in seconds (default 32s)");380 381static bool nowayout = WATCHDOG_NOWAYOUT;382module_param(nowayout, bool, 0);383MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default ="384		__MODULE_STRING(WATCHDOG_NOWAYOUT)")");385 386static const struct watchdog_info ds1374_wdt_info = {387	.identity       = "DS1374 Watchdog",388	.options        = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |389						WDIOF_MAGICCLOSE,390};391 392static int ds1374_wdt_settimeout(struct watchdog_device *wdt, unsigned int timeout)393{394	struct ds1374 *ds1374 = watchdog_get_drvdata(wdt);395	struct i2c_client *client = ds1374->client;396	int ret, cr;397 398	wdt->timeout = timeout;399 400	cr = i2c_smbus_read_byte_data(client, DS1374_REG_CR);401	if (cr < 0)402		return cr;403 404	/* Disable any existing watchdog/alarm before setting the new one */405	cr &= ~DS1374_REG_CR_WACE;406 407	ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, cr);408	if (ret < 0)409		return ret;410 411	/* Set new watchdog time */412	timeout = timeout * 4096;413	ret = ds1374_write_rtc(client, timeout, DS1374_REG_WDALM0, 3);414	if (ret)415		return ret;416 417	/* Enable watchdog timer */418	cr |= DS1374_REG_CR_WACE | DS1374_REG_CR_WDALM;419	cr &= ~DS1374_REG_CR_WDSTR;/* for RST PIN */420	cr &= ~DS1374_REG_CR_AIE;421 422	ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, cr);423	if (ret < 0)424		return ret;425 426	return 0;427}428 429/*430 * Reload the watchdog timer.  (ie, pat the watchdog)431 */432static int ds1374_wdt_start(struct watchdog_device *wdt)433{434	struct ds1374 *ds1374 = watchdog_get_drvdata(wdt);435	u32 val;436 437	return ds1374_read_rtc(ds1374->client, &val, DS1374_REG_WDALM0, 3);438}439 440static int ds1374_wdt_stop(struct watchdog_device *wdt)441{442	struct ds1374 *ds1374 = watchdog_get_drvdata(wdt);443	struct i2c_client *client = ds1374->client;444	int cr;445 446	cr = i2c_smbus_read_byte_data(client, DS1374_REG_CR);447	if (cr < 0)448		return cr;449 450	/* Disable watchdog timer */451	cr &= ~DS1374_REG_CR_WACE;452 453	return i2c_smbus_write_byte_data(client, DS1374_REG_CR, cr);454}455 456static const struct watchdog_ops ds1374_wdt_ops = {457	.owner          = THIS_MODULE,458	.start          = ds1374_wdt_start,459	.stop           = ds1374_wdt_stop,460	.set_timeout    = ds1374_wdt_settimeout,461};462#endif /*CONFIG_RTC_DRV_DS1374_WDT*/463/*464 *****************************************************************************465 *466 *	Driver Interface467 *468 *****************************************************************************469 */470static int ds1374_probe(struct i2c_client *client)471{472	struct ds1374 *ds1374;473	int ret;474 475	ds1374 = devm_kzalloc(&client->dev, sizeof(struct ds1374), GFP_KERNEL);476	if (!ds1374)477		return -ENOMEM;478 479	ds1374->rtc = devm_rtc_allocate_device(&client->dev);480	if (IS_ERR(ds1374->rtc))481		return PTR_ERR(ds1374->rtc);482 483	ds1374->client = client;484	i2c_set_clientdata(client, ds1374);485 486	INIT_WORK(&ds1374->work, ds1374_work);487	mutex_init(&ds1374->mutex);488 489	ret = ds1374_check_rtc_status(client);490	if (ret)491		return ret;492 493	if (client->irq > 0) {494		ret = devm_request_irq(&client->dev, client->irq, ds1374_irq, 0,495					"ds1374", client);496		if (ret) {497			dev_err(&client->dev, "unable to request IRQ\n");498			return ret;499		}500 501		device_set_wakeup_capable(&client->dev, 1);502	}503 504	ds1374->rtc->ops = &ds1374_rtc_ops;505	ds1374->rtc->range_max = U32_MAX;506 507	ret = devm_rtc_register_device(ds1374->rtc);508	if (ret)509		return ret;510 511#ifdef CONFIG_RTC_DRV_DS1374_WDT512	ds1374->wdt.info = &ds1374_wdt_info;513	ds1374->wdt.ops = &ds1374_wdt_ops;514	ds1374->wdt.timeout = TIMER_MARGIN_DEFAULT;515	ds1374->wdt.min_timeout = TIMER_MARGIN_MIN;516	ds1374->wdt.max_timeout = TIMER_MARGIN_MAX;517 518	watchdog_init_timeout(&ds1374->wdt, wdt_margin, &client->dev);519	watchdog_set_nowayout(&ds1374->wdt, nowayout);520	watchdog_stop_on_reboot(&ds1374->wdt);521	watchdog_stop_on_unregister(&ds1374->wdt);522	watchdog_set_drvdata(&ds1374->wdt, ds1374);523	ds1374_wdt_settimeout(&ds1374->wdt, ds1374->wdt.timeout);524 525	ret = devm_watchdog_register_device(&client->dev, &ds1374->wdt);526	if (ret)527		return ret;528#endif529 530	return 0;531}532 533static void ds1374_remove(struct i2c_client *client)534{535	struct ds1374 *ds1374 = i2c_get_clientdata(client);536 537	if (client->irq > 0) {538		mutex_lock(&ds1374->mutex);539		ds1374->exiting = 1;540		mutex_unlock(&ds1374->mutex);541 542		devm_free_irq(&client->dev, client->irq, client);543		cancel_work_sync(&ds1374->work);544	}545}546 547#ifdef CONFIG_PM_SLEEP548static int ds1374_suspend(struct device *dev)549{550	struct i2c_client *client = to_i2c_client(dev);551 552	if (client->irq > 0 && device_may_wakeup(&client->dev))553		enable_irq_wake(client->irq);554	return 0;555}556 557static int ds1374_resume(struct device *dev)558{559	struct i2c_client *client = to_i2c_client(dev);560 561	if (client->irq > 0 && device_may_wakeup(&client->dev))562		disable_irq_wake(client->irq);563	return 0;564}565#endif566 567static SIMPLE_DEV_PM_OPS(ds1374_pm, ds1374_suspend, ds1374_resume);568 569static struct i2c_driver ds1374_driver = {570	.driver = {571		.name = "rtc-ds1374",572		.of_match_table = of_match_ptr(ds1374_of_match),573		.pm = &ds1374_pm,574	},575	.probe = ds1374_probe,576	.remove = ds1374_remove,577	.id_table = ds1374_id,578};579 580module_i2c_driver(ds1374_driver);581 582MODULE_AUTHOR("Scott Wood <scottwood@freescale.com>");583MODULE_DESCRIPTION("Maxim/Dallas DS1374 RTC Driver");584MODULE_LICENSE("GPL");585