18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * rtc-ds1305.c -- driver for DS1305 and DS1306 SPI RTC chips
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2008 David Brownell
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci#include <linux/kernel.h>
88c2ecf20Sopenharmony_ci#include <linux/init.h>
98c2ecf20Sopenharmony_ci#include <linux/bcd.h>
108c2ecf20Sopenharmony_ci#include <linux/slab.h>
118c2ecf20Sopenharmony_ci#include <linux/rtc.h>
128c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/spi/spi.h>
158c2ecf20Sopenharmony_ci#include <linux/spi/ds1305.h>
168c2ecf20Sopenharmony_ci#include <linux/module.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/*
208c2ecf20Sopenharmony_ci * Registers ... mask DS1305_WRITE into register address to write,
218c2ecf20Sopenharmony_ci * otherwise you're reading it.  All non-bitmask values are BCD.
228c2ecf20Sopenharmony_ci */
238c2ecf20Sopenharmony_ci#define DS1305_WRITE		0x80
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/* RTC date/time ... the main special cases are that we:
278c2ecf20Sopenharmony_ci *  - Need fancy "hours" encoding in 12hour mode
288c2ecf20Sopenharmony_ci *  - Don't rely on the "day-of-week" field (or tm_wday)
298c2ecf20Sopenharmony_ci *  - Are a 21st-century clock (2000 <= year < 2100)
308c2ecf20Sopenharmony_ci */
318c2ecf20Sopenharmony_ci#define DS1305_RTC_LEN		7		/* bytes for RTC regs */
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#define DS1305_SEC		0x00		/* register addresses */
348c2ecf20Sopenharmony_ci#define DS1305_MIN		0x01
358c2ecf20Sopenharmony_ci#define DS1305_HOUR		0x02
368c2ecf20Sopenharmony_ci#	define DS1305_HR_12		0x40	/* set == 12 hr mode */
378c2ecf20Sopenharmony_ci#	define DS1305_HR_PM		0x20	/* set == PM (12hr mode) */
388c2ecf20Sopenharmony_ci#define DS1305_WDAY		0x03
398c2ecf20Sopenharmony_ci#define DS1305_MDAY		0x04
408c2ecf20Sopenharmony_ci#define DS1305_MON		0x05
418c2ecf20Sopenharmony_ci#define DS1305_YEAR		0x06
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci/* The two alarms have only sec/min/hour/wday fields (ALM_LEN).
458c2ecf20Sopenharmony_ci * DS1305_ALM_DISABLE disables a match field (some combos are bad).
468c2ecf20Sopenharmony_ci *
478c2ecf20Sopenharmony_ci * NOTE that since we don't use WDAY, we limit ourselves to alarms
488c2ecf20Sopenharmony_ci * only one day into the future (vs potentially up to a week).
498c2ecf20Sopenharmony_ci *
508c2ecf20Sopenharmony_ci * NOTE ALSO that while we could generate once-a-second IRQs (UIE), we
518c2ecf20Sopenharmony_ci * don't currently support them.  We'd either need to do it only when
528c2ecf20Sopenharmony_ci * no alarm is pending (not the standard model), or to use the second
538c2ecf20Sopenharmony_ci * alarm (implying that this is a DS1305 not DS1306, *and* that either
548c2ecf20Sopenharmony_ci * it's wired up a second IRQ we know, or that INTCN is set)
558c2ecf20Sopenharmony_ci */
568c2ecf20Sopenharmony_ci#define DS1305_ALM_LEN		4		/* bytes for ALM regs */
578c2ecf20Sopenharmony_ci#define DS1305_ALM_DISABLE	0x80
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci#define DS1305_ALM0(r)		(0x07 + (r))	/* register addresses */
608c2ecf20Sopenharmony_ci#define DS1305_ALM1(r)		(0x0b + (r))
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci/* three control registers */
648c2ecf20Sopenharmony_ci#define DS1305_CONTROL_LEN	3		/* bytes of control regs */
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci#define DS1305_CONTROL		0x0f		/* register addresses */
678c2ecf20Sopenharmony_ci#	define DS1305_nEOSC		0x80	/* low enables oscillator */
688c2ecf20Sopenharmony_ci#	define DS1305_WP		0x40	/* write protect */
698c2ecf20Sopenharmony_ci#	define DS1305_INTCN		0x04	/* clear == only int0 used */
708c2ecf20Sopenharmony_ci#	define DS1306_1HZ		0x04	/* enable 1Hz output */
718c2ecf20Sopenharmony_ci#	define DS1305_AEI1		0x02	/* enable ALM1 IRQ */
728c2ecf20Sopenharmony_ci#	define DS1305_AEI0		0x01	/* enable ALM0 IRQ */
738c2ecf20Sopenharmony_ci#define DS1305_STATUS		0x10
748c2ecf20Sopenharmony_ci/* status has just AEIx bits, mirrored as IRQFx */
758c2ecf20Sopenharmony_ci#define DS1305_TRICKLE		0x11
768c2ecf20Sopenharmony_ci/* trickle bits are defined in <linux/spi/ds1305.h> */
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci/* a bunch of NVRAM */
798c2ecf20Sopenharmony_ci#define DS1305_NVRAM_LEN	96		/* bytes of NVRAM */
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci#define DS1305_NVRAM		0x20		/* register addresses */
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistruct ds1305 {
858c2ecf20Sopenharmony_ci	struct spi_device	*spi;
868c2ecf20Sopenharmony_ci	struct rtc_device	*rtc;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	struct work_struct	work;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	unsigned long		flags;
918c2ecf20Sopenharmony_ci#define FLAG_EXITING	0
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	bool			hr12;
948c2ecf20Sopenharmony_ci	u8			ctrl[DS1305_CONTROL_LEN];
958c2ecf20Sopenharmony_ci};
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci/*----------------------------------------------------------------------*/
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci/*
1018c2ecf20Sopenharmony_ci * Utilities ...  tolerate 12-hour AM/PM notation in case of non-Linux
1028c2ecf20Sopenharmony_ci * software (like a bootloader) which may require it.
1038c2ecf20Sopenharmony_ci */
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_cistatic unsigned bcd2hour(u8 bcd)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	if (bcd & DS1305_HR_12) {
1088c2ecf20Sopenharmony_ci		unsigned	hour = 0;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci		bcd &= ~DS1305_HR_12;
1118c2ecf20Sopenharmony_ci		if (bcd & DS1305_HR_PM) {
1128c2ecf20Sopenharmony_ci			hour = 12;
1138c2ecf20Sopenharmony_ci			bcd &= ~DS1305_HR_PM;
1148c2ecf20Sopenharmony_ci		}
1158c2ecf20Sopenharmony_ci		hour += bcd2bin(bcd);
1168c2ecf20Sopenharmony_ci		return hour - 1;
1178c2ecf20Sopenharmony_ci	}
1188c2ecf20Sopenharmony_ci	return bcd2bin(bcd);
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistatic u8 hour2bcd(bool hr12, int hour)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	if (hr12) {
1248c2ecf20Sopenharmony_ci		hour++;
1258c2ecf20Sopenharmony_ci		if (hour <= 12)
1268c2ecf20Sopenharmony_ci			return DS1305_HR_12 | bin2bcd(hour);
1278c2ecf20Sopenharmony_ci		hour -= 12;
1288c2ecf20Sopenharmony_ci		return DS1305_HR_12 | DS1305_HR_PM | bin2bcd(hour);
1298c2ecf20Sopenharmony_ci	}
1308c2ecf20Sopenharmony_ci	return bin2bcd(hour);
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci/*----------------------------------------------------------------------*/
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci/*
1368c2ecf20Sopenharmony_ci * Interface to RTC framework
1378c2ecf20Sopenharmony_ci */
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_cistatic int ds1305_alarm_irq_enable(struct device *dev, unsigned int enabled)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	struct ds1305	*ds1305 = dev_get_drvdata(dev);
1428c2ecf20Sopenharmony_ci	u8		buf[2];
1438c2ecf20Sopenharmony_ci	long		err = -EINVAL;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	buf[0] = DS1305_WRITE | DS1305_CONTROL;
1468c2ecf20Sopenharmony_ci	buf[1] = ds1305->ctrl[0];
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	if (enabled) {
1498c2ecf20Sopenharmony_ci		if (ds1305->ctrl[0] & DS1305_AEI0)
1508c2ecf20Sopenharmony_ci			goto done;
1518c2ecf20Sopenharmony_ci		buf[1] |= DS1305_AEI0;
1528c2ecf20Sopenharmony_ci	} else {
1538c2ecf20Sopenharmony_ci		if (!(buf[1] & DS1305_AEI0))
1548c2ecf20Sopenharmony_ci			goto done;
1558c2ecf20Sopenharmony_ci		buf[1] &= ~DS1305_AEI0;
1568c2ecf20Sopenharmony_ci	}
1578c2ecf20Sopenharmony_ci	err = spi_write_then_read(ds1305->spi, buf, sizeof(buf), NULL, 0);
1588c2ecf20Sopenharmony_ci	if (err >= 0)
1598c2ecf20Sopenharmony_ci		ds1305->ctrl[0] = buf[1];
1608c2ecf20Sopenharmony_cidone:
1618c2ecf20Sopenharmony_ci	return err;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci/*
1678c2ecf20Sopenharmony_ci * Get/set of date and time is pretty normal.
1688c2ecf20Sopenharmony_ci */
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_cistatic int ds1305_get_time(struct device *dev, struct rtc_time *time)
1718c2ecf20Sopenharmony_ci{
1728c2ecf20Sopenharmony_ci	struct ds1305	*ds1305 = dev_get_drvdata(dev);
1738c2ecf20Sopenharmony_ci	u8		addr = DS1305_SEC;
1748c2ecf20Sopenharmony_ci	u8		buf[DS1305_RTC_LEN];
1758c2ecf20Sopenharmony_ci	int		status;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	/* Use write-then-read to get all the date/time registers
1788c2ecf20Sopenharmony_ci	 * since dma from stack is nonportable
1798c2ecf20Sopenharmony_ci	 */
1808c2ecf20Sopenharmony_ci	status = spi_write_then_read(ds1305->spi, &addr, sizeof(addr),
1818c2ecf20Sopenharmony_ci			buf, sizeof(buf));
1828c2ecf20Sopenharmony_ci	if (status < 0)
1838c2ecf20Sopenharmony_ci		return status;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	dev_vdbg(dev, "%s: %3ph, %4ph\n", "read", &buf[0], &buf[3]);
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	/* Decode the registers */
1888c2ecf20Sopenharmony_ci	time->tm_sec = bcd2bin(buf[DS1305_SEC]);
1898c2ecf20Sopenharmony_ci	time->tm_min = bcd2bin(buf[DS1305_MIN]);
1908c2ecf20Sopenharmony_ci	time->tm_hour = bcd2hour(buf[DS1305_HOUR]);
1918c2ecf20Sopenharmony_ci	time->tm_wday = buf[DS1305_WDAY] - 1;
1928c2ecf20Sopenharmony_ci	time->tm_mday = bcd2bin(buf[DS1305_MDAY]);
1938c2ecf20Sopenharmony_ci	time->tm_mon = bcd2bin(buf[DS1305_MON]) - 1;
1948c2ecf20Sopenharmony_ci	time->tm_year = bcd2bin(buf[DS1305_YEAR]) + 100;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	dev_vdbg(dev, "%s secs=%d, mins=%d, "
1978c2ecf20Sopenharmony_ci		"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
1988c2ecf20Sopenharmony_ci		"read", time->tm_sec, time->tm_min,
1998c2ecf20Sopenharmony_ci		time->tm_hour, time->tm_mday,
2008c2ecf20Sopenharmony_ci		time->tm_mon, time->tm_year, time->tm_wday);
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	return 0;
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_cistatic int ds1305_set_time(struct device *dev, struct rtc_time *time)
2068c2ecf20Sopenharmony_ci{
2078c2ecf20Sopenharmony_ci	struct ds1305	*ds1305 = dev_get_drvdata(dev);
2088c2ecf20Sopenharmony_ci	u8		buf[1 + DS1305_RTC_LEN];
2098c2ecf20Sopenharmony_ci	u8		*bp = buf;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	dev_vdbg(dev, "%s secs=%d, mins=%d, "
2128c2ecf20Sopenharmony_ci		"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
2138c2ecf20Sopenharmony_ci		"write", time->tm_sec, time->tm_min,
2148c2ecf20Sopenharmony_ci		time->tm_hour, time->tm_mday,
2158c2ecf20Sopenharmony_ci		time->tm_mon, time->tm_year, time->tm_wday);
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	/* Write registers starting at the first time/date address. */
2188c2ecf20Sopenharmony_ci	*bp++ = DS1305_WRITE | DS1305_SEC;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	*bp++ = bin2bcd(time->tm_sec);
2218c2ecf20Sopenharmony_ci	*bp++ = bin2bcd(time->tm_min);
2228c2ecf20Sopenharmony_ci	*bp++ = hour2bcd(ds1305->hr12, time->tm_hour);
2238c2ecf20Sopenharmony_ci	*bp++ = (time->tm_wday < 7) ? (time->tm_wday + 1) : 1;
2248c2ecf20Sopenharmony_ci	*bp++ = bin2bcd(time->tm_mday);
2258c2ecf20Sopenharmony_ci	*bp++ = bin2bcd(time->tm_mon + 1);
2268c2ecf20Sopenharmony_ci	*bp++ = bin2bcd(time->tm_year - 100);
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s: %3ph, %4ph\n", "write", &buf[1], &buf[4]);
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	/* use write-then-read since dma from stack is nonportable */
2318c2ecf20Sopenharmony_ci	return spi_write_then_read(ds1305->spi, buf, sizeof(buf),
2328c2ecf20Sopenharmony_ci			NULL, 0);
2338c2ecf20Sopenharmony_ci}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci/*
2368c2ecf20Sopenharmony_ci * Get/set of alarm is a bit funky:
2378c2ecf20Sopenharmony_ci *
2388c2ecf20Sopenharmony_ci * - First there's the inherent raciness of getting the (partitioned)
2398c2ecf20Sopenharmony_ci *   status of an alarm that could trigger while we're reading parts
2408c2ecf20Sopenharmony_ci *   of that status.
2418c2ecf20Sopenharmony_ci *
2428c2ecf20Sopenharmony_ci * - Second there's its limited range (we could increase it a bit by
2438c2ecf20Sopenharmony_ci *   relying on WDAY), which means it will easily roll over.
2448c2ecf20Sopenharmony_ci *
2458c2ecf20Sopenharmony_ci * - Third there's the choice of two alarms and alarm signals.
2468c2ecf20Sopenharmony_ci *   Here we use ALM0 and expect that nINT0 (open drain) is used;
2478c2ecf20Sopenharmony_ci *   that's the only real option for DS1306 runtime alarms, and is
2488c2ecf20Sopenharmony_ci *   natural on DS1305.
2498c2ecf20Sopenharmony_ci *
2508c2ecf20Sopenharmony_ci * - Fourth, there's also ALM1, and a second interrupt signal:
2518c2ecf20Sopenharmony_ci *     + On DS1305 ALM1 uses nINT1 (when INTCN=1) else nINT0;
2528c2ecf20Sopenharmony_ci *     + On DS1306 ALM1 only uses INT1 (an active high pulse)
2538c2ecf20Sopenharmony_ci *       and it won't work when VCC1 is active.
2548c2ecf20Sopenharmony_ci *
2558c2ecf20Sopenharmony_ci *   So to be most general, we should probably set both alarms to the
2568c2ecf20Sopenharmony_ci *   same value, letting ALM1 be the wakeup event source on DS1306
2578c2ecf20Sopenharmony_ci *   and handling several wiring options on DS1305.
2588c2ecf20Sopenharmony_ci *
2598c2ecf20Sopenharmony_ci * - Fifth, we support the polled mode (as well as possible; why not?)
2608c2ecf20Sopenharmony_ci *   even when no interrupt line is wired to an IRQ.
2618c2ecf20Sopenharmony_ci */
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci/*
2648c2ecf20Sopenharmony_ci * Context: caller holds rtc->ops_lock (to protect ds1305->ctrl)
2658c2ecf20Sopenharmony_ci */
2668c2ecf20Sopenharmony_cistatic int ds1305_get_alarm(struct device *dev, struct rtc_wkalrm *alm)
2678c2ecf20Sopenharmony_ci{
2688c2ecf20Sopenharmony_ci	struct ds1305	*ds1305 = dev_get_drvdata(dev);
2698c2ecf20Sopenharmony_ci	struct spi_device *spi = ds1305->spi;
2708c2ecf20Sopenharmony_ci	u8		addr;
2718c2ecf20Sopenharmony_ci	int		status;
2728c2ecf20Sopenharmony_ci	u8		buf[DS1305_ALM_LEN];
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	/* Refresh control register cache BEFORE reading ALM0 registers,
2758c2ecf20Sopenharmony_ci	 * since reading alarm registers acks any pending IRQ.  That
2768c2ecf20Sopenharmony_ci	 * makes returning "pending" status a bit of a lie, but that bit
2778c2ecf20Sopenharmony_ci	 * of EFI status is at best fragile anyway (given IRQ handlers).
2788c2ecf20Sopenharmony_ci	 */
2798c2ecf20Sopenharmony_ci	addr = DS1305_CONTROL;
2808c2ecf20Sopenharmony_ci	status = spi_write_then_read(spi, &addr, sizeof(addr),
2818c2ecf20Sopenharmony_ci			ds1305->ctrl, sizeof(ds1305->ctrl));
2828c2ecf20Sopenharmony_ci	if (status < 0)
2838c2ecf20Sopenharmony_ci		return status;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	alm->enabled = !!(ds1305->ctrl[0] & DS1305_AEI0);
2868c2ecf20Sopenharmony_ci	alm->pending = !!(ds1305->ctrl[1] & DS1305_AEI0);
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	/* get and check ALM0 registers */
2898c2ecf20Sopenharmony_ci	addr = DS1305_ALM0(DS1305_SEC);
2908c2ecf20Sopenharmony_ci	status = spi_write_then_read(spi, &addr, sizeof(addr),
2918c2ecf20Sopenharmony_ci			buf, sizeof(buf));
2928c2ecf20Sopenharmony_ci	if (status < 0)
2938c2ecf20Sopenharmony_ci		return status;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	dev_vdbg(dev, "%s: %02x %02x %02x %02x\n",
2968c2ecf20Sopenharmony_ci		"alm0 read", buf[DS1305_SEC], buf[DS1305_MIN],
2978c2ecf20Sopenharmony_ci		buf[DS1305_HOUR], buf[DS1305_WDAY]);
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	if ((DS1305_ALM_DISABLE & buf[DS1305_SEC])
3008c2ecf20Sopenharmony_ci			|| (DS1305_ALM_DISABLE & buf[DS1305_MIN])
3018c2ecf20Sopenharmony_ci			|| (DS1305_ALM_DISABLE & buf[DS1305_HOUR]))
3028c2ecf20Sopenharmony_ci		return -EIO;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	/* Stuff these values into alm->time and let RTC framework code
3058c2ecf20Sopenharmony_ci	 * fill in the rest ... and also handle rollover to tomorrow when
3068c2ecf20Sopenharmony_ci	 * that's needed.
3078c2ecf20Sopenharmony_ci	 */
3088c2ecf20Sopenharmony_ci	alm->time.tm_sec = bcd2bin(buf[DS1305_SEC]);
3098c2ecf20Sopenharmony_ci	alm->time.tm_min = bcd2bin(buf[DS1305_MIN]);
3108c2ecf20Sopenharmony_ci	alm->time.tm_hour = bcd2hour(buf[DS1305_HOUR]);
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	return 0;
3138c2ecf20Sopenharmony_ci}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci/*
3168c2ecf20Sopenharmony_ci * Context: caller holds rtc->ops_lock (to protect ds1305->ctrl)
3178c2ecf20Sopenharmony_ci */
3188c2ecf20Sopenharmony_cistatic int ds1305_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
3198c2ecf20Sopenharmony_ci{
3208c2ecf20Sopenharmony_ci	struct ds1305	*ds1305 = dev_get_drvdata(dev);
3218c2ecf20Sopenharmony_ci	struct spi_device *spi = ds1305->spi;
3228c2ecf20Sopenharmony_ci	unsigned long	now, later;
3238c2ecf20Sopenharmony_ci	struct rtc_time	tm;
3248c2ecf20Sopenharmony_ci	int		status;
3258c2ecf20Sopenharmony_ci	u8		buf[1 + DS1305_ALM_LEN];
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	/* convert desired alarm to time_t */
3288c2ecf20Sopenharmony_ci	later = rtc_tm_to_time64(&alm->time);
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	/* Read current time as time_t */
3318c2ecf20Sopenharmony_ci	status = ds1305_get_time(dev, &tm);
3328c2ecf20Sopenharmony_ci	if (status < 0)
3338c2ecf20Sopenharmony_ci		return status;
3348c2ecf20Sopenharmony_ci	now = rtc_tm_to_time64(&tm);
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	/* make sure alarm fires within the next 24 hours */
3378c2ecf20Sopenharmony_ci	if (later <= now)
3388c2ecf20Sopenharmony_ci		return -EINVAL;
3398c2ecf20Sopenharmony_ci	if ((later - now) > 24 * 60 * 60)
3408c2ecf20Sopenharmony_ci		return -EDOM;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	/* disable alarm if needed */
3438c2ecf20Sopenharmony_ci	if (ds1305->ctrl[0] & DS1305_AEI0) {
3448c2ecf20Sopenharmony_ci		ds1305->ctrl[0] &= ~DS1305_AEI0;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci		buf[0] = DS1305_WRITE | DS1305_CONTROL;
3478c2ecf20Sopenharmony_ci		buf[1] = ds1305->ctrl[0];
3488c2ecf20Sopenharmony_ci		status = spi_write_then_read(ds1305->spi, buf, 2, NULL, 0);
3498c2ecf20Sopenharmony_ci		if (status < 0)
3508c2ecf20Sopenharmony_ci			return status;
3518c2ecf20Sopenharmony_ci	}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	/* write alarm */
3548c2ecf20Sopenharmony_ci	buf[0] = DS1305_WRITE | DS1305_ALM0(DS1305_SEC);
3558c2ecf20Sopenharmony_ci	buf[1 + DS1305_SEC] = bin2bcd(alm->time.tm_sec);
3568c2ecf20Sopenharmony_ci	buf[1 + DS1305_MIN] = bin2bcd(alm->time.tm_min);
3578c2ecf20Sopenharmony_ci	buf[1 + DS1305_HOUR] = hour2bcd(ds1305->hr12, alm->time.tm_hour);
3588c2ecf20Sopenharmony_ci	buf[1 + DS1305_WDAY] = DS1305_ALM_DISABLE;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s: %02x %02x %02x %02x\n",
3618c2ecf20Sopenharmony_ci		"alm0 write", buf[1 + DS1305_SEC], buf[1 + DS1305_MIN],
3628c2ecf20Sopenharmony_ci		buf[1 + DS1305_HOUR], buf[1 + DS1305_WDAY]);
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	status = spi_write_then_read(spi, buf, sizeof(buf), NULL, 0);
3658c2ecf20Sopenharmony_ci	if (status < 0)
3668c2ecf20Sopenharmony_ci		return status;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	/* enable alarm if requested */
3698c2ecf20Sopenharmony_ci	if (alm->enabled) {
3708c2ecf20Sopenharmony_ci		ds1305->ctrl[0] |= DS1305_AEI0;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci		buf[0] = DS1305_WRITE | DS1305_CONTROL;
3738c2ecf20Sopenharmony_ci		buf[1] = ds1305->ctrl[0];
3748c2ecf20Sopenharmony_ci		status = spi_write_then_read(ds1305->spi, buf, 2, NULL, 0);
3758c2ecf20Sopenharmony_ci	}
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	return status;
3788c2ecf20Sopenharmony_ci}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_cistatic int ds1305_proc(struct device *dev, struct seq_file *seq)
3838c2ecf20Sopenharmony_ci{
3848c2ecf20Sopenharmony_ci	struct ds1305	*ds1305 = dev_get_drvdata(dev);
3858c2ecf20Sopenharmony_ci	char		*diodes = "no";
3868c2ecf20Sopenharmony_ci	char		*resistors = "";
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	/* ctrl[2] is treated as read-only; no locking needed */
3898c2ecf20Sopenharmony_ci	if ((ds1305->ctrl[2] & 0xf0) == DS1305_TRICKLE_MAGIC) {
3908c2ecf20Sopenharmony_ci		switch (ds1305->ctrl[2] & 0x0c) {
3918c2ecf20Sopenharmony_ci		case DS1305_TRICKLE_DS2:
3928c2ecf20Sopenharmony_ci			diodes = "2 diodes, ";
3938c2ecf20Sopenharmony_ci			break;
3948c2ecf20Sopenharmony_ci		case DS1305_TRICKLE_DS1:
3958c2ecf20Sopenharmony_ci			diodes = "1 diode, ";
3968c2ecf20Sopenharmony_ci			break;
3978c2ecf20Sopenharmony_ci		default:
3988c2ecf20Sopenharmony_ci			goto done;
3998c2ecf20Sopenharmony_ci		}
4008c2ecf20Sopenharmony_ci		switch (ds1305->ctrl[2] & 0x03) {
4018c2ecf20Sopenharmony_ci		case DS1305_TRICKLE_2K:
4028c2ecf20Sopenharmony_ci			resistors = "2k Ohm";
4038c2ecf20Sopenharmony_ci			break;
4048c2ecf20Sopenharmony_ci		case DS1305_TRICKLE_4K:
4058c2ecf20Sopenharmony_ci			resistors = "4k Ohm";
4068c2ecf20Sopenharmony_ci			break;
4078c2ecf20Sopenharmony_ci		case DS1305_TRICKLE_8K:
4088c2ecf20Sopenharmony_ci			resistors = "8k Ohm";
4098c2ecf20Sopenharmony_ci			break;
4108c2ecf20Sopenharmony_ci		default:
4118c2ecf20Sopenharmony_ci			diodes = "no";
4128c2ecf20Sopenharmony_ci			break;
4138c2ecf20Sopenharmony_ci		}
4148c2ecf20Sopenharmony_ci	}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_cidone:
4178c2ecf20Sopenharmony_ci	seq_printf(seq, "trickle_charge\t: %s%s\n", diodes, resistors);
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	return 0;
4208c2ecf20Sopenharmony_ci}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci#else
4238c2ecf20Sopenharmony_ci#define ds1305_proc	NULL
4248c2ecf20Sopenharmony_ci#endif
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_cistatic const struct rtc_class_ops ds1305_ops = {
4278c2ecf20Sopenharmony_ci	.read_time	= ds1305_get_time,
4288c2ecf20Sopenharmony_ci	.set_time	= ds1305_set_time,
4298c2ecf20Sopenharmony_ci	.read_alarm	= ds1305_get_alarm,
4308c2ecf20Sopenharmony_ci	.set_alarm	= ds1305_set_alarm,
4318c2ecf20Sopenharmony_ci	.proc		= ds1305_proc,
4328c2ecf20Sopenharmony_ci	.alarm_irq_enable = ds1305_alarm_irq_enable,
4338c2ecf20Sopenharmony_ci};
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_cistatic void ds1305_work(struct work_struct *work)
4368c2ecf20Sopenharmony_ci{
4378c2ecf20Sopenharmony_ci	struct ds1305	*ds1305 = container_of(work, struct ds1305, work);
4388c2ecf20Sopenharmony_ci	struct mutex	*lock = &ds1305->rtc->ops_lock;
4398c2ecf20Sopenharmony_ci	struct spi_device *spi = ds1305->spi;
4408c2ecf20Sopenharmony_ci	u8		buf[3];
4418c2ecf20Sopenharmony_ci	int		status;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	/* lock to protect ds1305->ctrl */
4448c2ecf20Sopenharmony_ci	mutex_lock(lock);
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	/* Disable the IRQ, and clear its status ... for now, we "know"
4478c2ecf20Sopenharmony_ci	 * that if more than one alarm is active, they're in sync.
4488c2ecf20Sopenharmony_ci	 * Note that reading ALM data registers also clears IRQ status.
4498c2ecf20Sopenharmony_ci	 */
4508c2ecf20Sopenharmony_ci	ds1305->ctrl[0] &= ~(DS1305_AEI1 | DS1305_AEI0);
4518c2ecf20Sopenharmony_ci	ds1305->ctrl[1] = 0;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	buf[0] = DS1305_WRITE | DS1305_CONTROL;
4548c2ecf20Sopenharmony_ci	buf[1] = ds1305->ctrl[0];
4558c2ecf20Sopenharmony_ci	buf[2] = 0;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	status = spi_write_then_read(spi, buf, sizeof(buf),
4588c2ecf20Sopenharmony_ci			NULL, 0);
4598c2ecf20Sopenharmony_ci	if (status < 0)
4608c2ecf20Sopenharmony_ci		dev_dbg(&spi->dev, "clear irq --> %d\n", status);
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	mutex_unlock(lock);
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	if (!test_bit(FLAG_EXITING, &ds1305->flags))
4658c2ecf20Sopenharmony_ci		enable_irq(spi->irq);
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	rtc_update_irq(ds1305->rtc, 1, RTC_AF | RTC_IRQF);
4688c2ecf20Sopenharmony_ci}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci/*
4718c2ecf20Sopenharmony_ci * This "real" IRQ handler hands off to a workqueue mostly to allow
4728c2ecf20Sopenharmony_ci * mutex locking for ds1305->ctrl ... unlike I2C, we could issue async
4738c2ecf20Sopenharmony_ci * I/O requests in IRQ context (to clear the IRQ status).
4748c2ecf20Sopenharmony_ci */
4758c2ecf20Sopenharmony_cistatic irqreturn_t ds1305_irq(int irq, void *p)
4768c2ecf20Sopenharmony_ci{
4778c2ecf20Sopenharmony_ci	struct ds1305		*ds1305 = p;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	disable_irq(irq);
4808c2ecf20Sopenharmony_ci	schedule_work(&ds1305->work);
4818c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
4828c2ecf20Sopenharmony_ci}
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci/*----------------------------------------------------------------------*/
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci/*
4878c2ecf20Sopenharmony_ci * Interface for NVRAM
4888c2ecf20Sopenharmony_ci */
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_cistatic void msg_init(struct spi_message *m, struct spi_transfer *x,
4918c2ecf20Sopenharmony_ci		u8 *addr, size_t count, char *tx, char *rx)
4928c2ecf20Sopenharmony_ci{
4938c2ecf20Sopenharmony_ci	spi_message_init(m);
4948c2ecf20Sopenharmony_ci	memset(x, 0, 2 * sizeof(*x));
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	x->tx_buf = addr;
4978c2ecf20Sopenharmony_ci	x->len = 1;
4988c2ecf20Sopenharmony_ci	spi_message_add_tail(x, m);
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	x++;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	x->tx_buf = tx;
5038c2ecf20Sopenharmony_ci	x->rx_buf = rx;
5048c2ecf20Sopenharmony_ci	x->len = count;
5058c2ecf20Sopenharmony_ci	spi_message_add_tail(x, m);
5068c2ecf20Sopenharmony_ci}
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_cistatic int ds1305_nvram_read(void *priv, unsigned int off, void *buf,
5098c2ecf20Sopenharmony_ci			     size_t count)
5108c2ecf20Sopenharmony_ci{
5118c2ecf20Sopenharmony_ci	struct ds1305		*ds1305 = priv;
5128c2ecf20Sopenharmony_ci	struct spi_device	*spi = ds1305->spi;
5138c2ecf20Sopenharmony_ci	u8			addr;
5148c2ecf20Sopenharmony_ci	struct spi_message	m;
5158c2ecf20Sopenharmony_ci	struct spi_transfer	x[2];
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	addr = DS1305_NVRAM + off;
5188c2ecf20Sopenharmony_ci	msg_init(&m, x, &addr, count, NULL, buf);
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	return spi_sync(spi, &m);
5218c2ecf20Sopenharmony_ci}
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_cistatic int ds1305_nvram_write(void *priv, unsigned int off, void *buf,
5248c2ecf20Sopenharmony_ci			      size_t count)
5258c2ecf20Sopenharmony_ci{
5268c2ecf20Sopenharmony_ci	struct ds1305		*ds1305 = priv;
5278c2ecf20Sopenharmony_ci	struct spi_device	*spi = ds1305->spi;
5288c2ecf20Sopenharmony_ci	u8			addr;
5298c2ecf20Sopenharmony_ci	struct spi_message	m;
5308c2ecf20Sopenharmony_ci	struct spi_transfer	x[2];
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	addr = (DS1305_WRITE | DS1305_NVRAM) + off;
5338c2ecf20Sopenharmony_ci	msg_init(&m, x, &addr, count, buf, NULL);
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	return spi_sync(spi, &m);
5368c2ecf20Sopenharmony_ci}
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci/*----------------------------------------------------------------------*/
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci/*
5418c2ecf20Sopenharmony_ci * Interface to SPI stack
5428c2ecf20Sopenharmony_ci */
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_cistatic int ds1305_probe(struct spi_device *spi)
5458c2ecf20Sopenharmony_ci{
5468c2ecf20Sopenharmony_ci	struct ds1305			*ds1305;
5478c2ecf20Sopenharmony_ci	int				status;
5488c2ecf20Sopenharmony_ci	u8				addr, value;
5498c2ecf20Sopenharmony_ci	struct ds1305_platform_data	*pdata = dev_get_platdata(&spi->dev);
5508c2ecf20Sopenharmony_ci	bool				write_ctrl = false;
5518c2ecf20Sopenharmony_ci	struct nvmem_config ds1305_nvmem_cfg = {
5528c2ecf20Sopenharmony_ci		.name = "ds1305_nvram",
5538c2ecf20Sopenharmony_ci		.word_size = 1,
5548c2ecf20Sopenharmony_ci		.stride = 1,
5558c2ecf20Sopenharmony_ci		.size = DS1305_NVRAM_LEN,
5568c2ecf20Sopenharmony_ci		.reg_read = ds1305_nvram_read,
5578c2ecf20Sopenharmony_ci		.reg_write = ds1305_nvram_write,
5588c2ecf20Sopenharmony_ci	};
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	/* Sanity check board setup data.  This may be hooked up
5618c2ecf20Sopenharmony_ci	 * in 3wire mode, but we don't care.  Note that unless
5628c2ecf20Sopenharmony_ci	 * there's an inverter in place, this needs SPI_CS_HIGH!
5638c2ecf20Sopenharmony_ci	 */
5648c2ecf20Sopenharmony_ci	if ((spi->bits_per_word && spi->bits_per_word != 8)
5658c2ecf20Sopenharmony_ci			|| (spi->max_speed_hz > 2000000)
5668c2ecf20Sopenharmony_ci			|| !(spi->mode & SPI_CPHA))
5678c2ecf20Sopenharmony_ci		return -EINVAL;
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	/* set up driver data */
5708c2ecf20Sopenharmony_ci	ds1305 = devm_kzalloc(&spi->dev, sizeof(*ds1305), GFP_KERNEL);
5718c2ecf20Sopenharmony_ci	if (!ds1305)
5728c2ecf20Sopenharmony_ci		return -ENOMEM;
5738c2ecf20Sopenharmony_ci	ds1305->spi = spi;
5748c2ecf20Sopenharmony_ci	spi_set_drvdata(spi, ds1305);
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	/* read and cache control registers */
5778c2ecf20Sopenharmony_ci	addr = DS1305_CONTROL;
5788c2ecf20Sopenharmony_ci	status = spi_write_then_read(spi, &addr, sizeof(addr),
5798c2ecf20Sopenharmony_ci			ds1305->ctrl, sizeof(ds1305->ctrl));
5808c2ecf20Sopenharmony_ci	if (status < 0) {
5818c2ecf20Sopenharmony_ci		dev_dbg(&spi->dev, "can't %s, %d\n",
5828c2ecf20Sopenharmony_ci				"read", status);
5838c2ecf20Sopenharmony_ci		return status;
5848c2ecf20Sopenharmony_ci	}
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	dev_dbg(&spi->dev, "ctrl %s: %3ph\n", "read", ds1305->ctrl);
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	/* Sanity check register values ... partially compensating for the
5898c2ecf20Sopenharmony_ci	 * fact that SPI has no device handshake.  A pullup on MISO would
5908c2ecf20Sopenharmony_ci	 * make these tests fail; but not all systems will have one.  If
5918c2ecf20Sopenharmony_ci	 * some register is neither 0x00 nor 0xff, a chip is likely there.
5928c2ecf20Sopenharmony_ci	 */
5938c2ecf20Sopenharmony_ci	if ((ds1305->ctrl[0] & 0x38) != 0 || (ds1305->ctrl[1] & 0xfc) != 0) {
5948c2ecf20Sopenharmony_ci		dev_dbg(&spi->dev, "RTC chip is not present\n");
5958c2ecf20Sopenharmony_ci		return -ENODEV;
5968c2ecf20Sopenharmony_ci	}
5978c2ecf20Sopenharmony_ci	if (ds1305->ctrl[2] == 0)
5988c2ecf20Sopenharmony_ci		dev_dbg(&spi->dev, "chip may not be present\n");
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	/* enable writes if needed ... if we were paranoid it would
6018c2ecf20Sopenharmony_ci	 * make sense to enable them only when absolutely necessary.
6028c2ecf20Sopenharmony_ci	 */
6038c2ecf20Sopenharmony_ci	if (ds1305->ctrl[0] & DS1305_WP) {
6048c2ecf20Sopenharmony_ci		u8		buf[2];
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci		ds1305->ctrl[0] &= ~DS1305_WP;
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci		buf[0] = DS1305_WRITE | DS1305_CONTROL;
6098c2ecf20Sopenharmony_ci		buf[1] = ds1305->ctrl[0];
6108c2ecf20Sopenharmony_ci		status = spi_write_then_read(spi, buf, sizeof(buf), NULL, 0);
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci		dev_dbg(&spi->dev, "clear WP --> %d\n", status);
6138c2ecf20Sopenharmony_ci		if (status < 0)
6148c2ecf20Sopenharmony_ci			return status;
6158c2ecf20Sopenharmony_ci	}
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	/* on DS1305, maybe start oscillator; like most low power
6188c2ecf20Sopenharmony_ci	 * oscillators, it may take a second to stabilize
6198c2ecf20Sopenharmony_ci	 */
6208c2ecf20Sopenharmony_ci	if (ds1305->ctrl[0] & DS1305_nEOSC) {
6218c2ecf20Sopenharmony_ci		ds1305->ctrl[0] &= ~DS1305_nEOSC;
6228c2ecf20Sopenharmony_ci		write_ctrl = true;
6238c2ecf20Sopenharmony_ci		dev_warn(&spi->dev, "SET TIME!\n");
6248c2ecf20Sopenharmony_ci	}
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	/* ack any pending IRQs */
6278c2ecf20Sopenharmony_ci	if (ds1305->ctrl[1]) {
6288c2ecf20Sopenharmony_ci		ds1305->ctrl[1] = 0;
6298c2ecf20Sopenharmony_ci		write_ctrl = true;
6308c2ecf20Sopenharmony_ci	}
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	/* this may need one-time (re)init */
6338c2ecf20Sopenharmony_ci	if (pdata) {
6348c2ecf20Sopenharmony_ci		/* maybe enable trickle charge */
6358c2ecf20Sopenharmony_ci		if (((ds1305->ctrl[2] & 0xf0) != DS1305_TRICKLE_MAGIC)) {
6368c2ecf20Sopenharmony_ci			ds1305->ctrl[2] = DS1305_TRICKLE_MAGIC
6378c2ecf20Sopenharmony_ci						| pdata->trickle;
6388c2ecf20Sopenharmony_ci			write_ctrl = true;
6398c2ecf20Sopenharmony_ci		}
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci		/* on DS1306, configure 1 Hz signal */
6428c2ecf20Sopenharmony_ci		if (pdata->is_ds1306) {
6438c2ecf20Sopenharmony_ci			if (pdata->en_1hz) {
6448c2ecf20Sopenharmony_ci				if (!(ds1305->ctrl[0] & DS1306_1HZ)) {
6458c2ecf20Sopenharmony_ci					ds1305->ctrl[0] |= DS1306_1HZ;
6468c2ecf20Sopenharmony_ci					write_ctrl = true;
6478c2ecf20Sopenharmony_ci				}
6488c2ecf20Sopenharmony_ci			} else {
6498c2ecf20Sopenharmony_ci				if (ds1305->ctrl[0] & DS1306_1HZ) {
6508c2ecf20Sopenharmony_ci					ds1305->ctrl[0] &= ~DS1306_1HZ;
6518c2ecf20Sopenharmony_ci					write_ctrl = true;
6528c2ecf20Sopenharmony_ci				}
6538c2ecf20Sopenharmony_ci			}
6548c2ecf20Sopenharmony_ci		}
6558c2ecf20Sopenharmony_ci	}
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	if (write_ctrl) {
6588c2ecf20Sopenharmony_ci		u8		buf[4];
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci		buf[0] = DS1305_WRITE | DS1305_CONTROL;
6618c2ecf20Sopenharmony_ci		buf[1] = ds1305->ctrl[0];
6628c2ecf20Sopenharmony_ci		buf[2] = ds1305->ctrl[1];
6638c2ecf20Sopenharmony_ci		buf[3] = ds1305->ctrl[2];
6648c2ecf20Sopenharmony_ci		status = spi_write_then_read(spi, buf, sizeof(buf), NULL, 0);
6658c2ecf20Sopenharmony_ci		if (status < 0) {
6668c2ecf20Sopenharmony_ci			dev_dbg(&spi->dev, "can't %s, %d\n",
6678c2ecf20Sopenharmony_ci					"write", status);
6688c2ecf20Sopenharmony_ci			return status;
6698c2ecf20Sopenharmony_ci		}
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci		dev_dbg(&spi->dev, "ctrl %s: %3ph\n", "write", ds1305->ctrl);
6728c2ecf20Sopenharmony_ci	}
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci	/* see if non-Linux software set up AM/PM mode */
6758c2ecf20Sopenharmony_ci	addr = DS1305_HOUR;
6768c2ecf20Sopenharmony_ci	status = spi_write_then_read(spi, &addr, sizeof(addr),
6778c2ecf20Sopenharmony_ci				&value, sizeof(value));
6788c2ecf20Sopenharmony_ci	if (status < 0) {
6798c2ecf20Sopenharmony_ci		dev_dbg(&spi->dev, "read HOUR --> %d\n", status);
6808c2ecf20Sopenharmony_ci		return status;
6818c2ecf20Sopenharmony_ci	}
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci	ds1305->hr12 = (DS1305_HR_12 & value) != 0;
6848c2ecf20Sopenharmony_ci	if (ds1305->hr12)
6858c2ecf20Sopenharmony_ci		dev_dbg(&spi->dev, "AM/PM\n");
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	/* register RTC ... from here on, ds1305->ctrl needs locking */
6888c2ecf20Sopenharmony_ci	ds1305->rtc = devm_rtc_allocate_device(&spi->dev);
6898c2ecf20Sopenharmony_ci	if (IS_ERR(ds1305->rtc))
6908c2ecf20Sopenharmony_ci		return PTR_ERR(ds1305->rtc);
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	ds1305->rtc->ops = &ds1305_ops;
6938c2ecf20Sopenharmony_ci	ds1305->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
6948c2ecf20Sopenharmony_ci	ds1305->rtc->range_max = RTC_TIMESTAMP_END_2099;
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	ds1305_nvmem_cfg.priv = ds1305;
6978c2ecf20Sopenharmony_ci	ds1305->rtc->nvram_old_abi = true;
6988c2ecf20Sopenharmony_ci	status = rtc_register_device(ds1305->rtc);
6998c2ecf20Sopenharmony_ci	if (status)
7008c2ecf20Sopenharmony_ci		return status;
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	rtc_nvmem_register(ds1305->rtc, &ds1305_nvmem_cfg);
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	/* Maybe set up alarm IRQ; be ready to handle it triggering right
7058c2ecf20Sopenharmony_ci	 * away.  NOTE that we don't share this.  The signal is active low,
7068c2ecf20Sopenharmony_ci	 * and we can't ack it before a SPI message delay.  We temporarily
7078c2ecf20Sopenharmony_ci	 * disable the IRQ until it's acked, which lets us work with more
7088c2ecf20Sopenharmony_ci	 * IRQ trigger modes (not all IRQ controllers can do falling edge).
7098c2ecf20Sopenharmony_ci	 */
7108c2ecf20Sopenharmony_ci	if (spi->irq) {
7118c2ecf20Sopenharmony_ci		INIT_WORK(&ds1305->work, ds1305_work);
7128c2ecf20Sopenharmony_ci		status = devm_request_irq(&spi->dev, spi->irq, ds1305_irq,
7138c2ecf20Sopenharmony_ci				0, dev_name(&ds1305->rtc->dev), ds1305);
7148c2ecf20Sopenharmony_ci		if (status < 0) {
7158c2ecf20Sopenharmony_ci			dev_err(&spi->dev, "request_irq %d --> %d\n",
7168c2ecf20Sopenharmony_ci					spi->irq, status);
7178c2ecf20Sopenharmony_ci		} else {
7188c2ecf20Sopenharmony_ci			device_set_wakeup_capable(&spi->dev, 1);
7198c2ecf20Sopenharmony_ci		}
7208c2ecf20Sopenharmony_ci	}
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	return 0;
7238c2ecf20Sopenharmony_ci}
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_cistatic int ds1305_remove(struct spi_device *spi)
7268c2ecf20Sopenharmony_ci{
7278c2ecf20Sopenharmony_ci	struct ds1305 *ds1305 = spi_get_drvdata(spi);
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci	/* carefully shut down irq and workqueue, if present */
7308c2ecf20Sopenharmony_ci	if (spi->irq) {
7318c2ecf20Sopenharmony_ci		set_bit(FLAG_EXITING, &ds1305->flags);
7328c2ecf20Sopenharmony_ci		devm_free_irq(&spi->dev, spi->irq, ds1305);
7338c2ecf20Sopenharmony_ci		cancel_work_sync(&ds1305->work);
7348c2ecf20Sopenharmony_ci	}
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	return 0;
7378c2ecf20Sopenharmony_ci}
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_cistatic struct spi_driver ds1305_driver = {
7408c2ecf20Sopenharmony_ci	.driver.name	= "rtc-ds1305",
7418c2ecf20Sopenharmony_ci	.probe		= ds1305_probe,
7428c2ecf20Sopenharmony_ci	.remove		= ds1305_remove,
7438c2ecf20Sopenharmony_ci	/* REVISIT add suspend/resume */
7448c2ecf20Sopenharmony_ci};
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_cimodule_spi_driver(ds1305_driver);
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("RTC driver for DS1305 and DS1306 chips");
7498c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
7508c2ecf20Sopenharmony_ciMODULE_ALIAS("spi:rtc-ds1305");
751