RTC for 4.7
Subsystem wide cleanups: - Use IS_ENABLED() instead of checking for built-in or module - remove useless DRV_VERSION - remove CLK_IS_ROOT - remove UIE signaling Drivers: - ds1302: rewritten to be a proper SPI device driver - m41t80: huge cleanup, alarm, wakelarm ans oscialltor failure detection support - rv3029: switch to regmap to handle rv3049, alarm support, fixes - zynqmp: enable switching to battery power, fixes - small fixes for at91sam9, da9053, ds1307, ds1685, ds3232, r2025, sa1100, snvs, stmp3xxx, tps6586x -----BEGIN PGP SIGNATURE----- iQIcBAABCgAGBQJXQHoaAAoJENiigzvaE+LCqKkP/1EmY0R7yTLf0eL/gdbIeEqi ji39pqtmhZ9T2KIN3vk2LyrPRY4FUNVehK8MYb8GrBV3LxQR1QqCZTTNH60j5w2h mRdWNU7LvbKQTuhGGe68K/Re87V+hbUsgY56/YXqW3IzSzs0ROmDYYw2nYVNoT/T TFWA3lzlWbYNIPIVl8COU9OzWp/ejGyVSqaFrZmTeAyAco/BSMdA8z1zVtLF8O56 KbCUAfssROZ+CiChzKwFUKHFj6f+qTzIg9SaEOsA+EsJJPexJdoV277ugzBdxBFf f9IDHOj6xaRrKeKKz2QLjS6cd0pnxoLaN3fL5nxoiqyj+nXKSD4DfiHIvhGcqdS/ i8di0TAeHnTDOMZ48/LHQ1qCLduPhkEXeiI1BieVx5Nl05PhEysnWbC0wYF8JrJs 9lm3Q9KI9eIcL/M2NGeO7pXYKQRuYZyZYvc5Qci0s3APJNC7wTp5Ee/9tUADLziM z7IfkRkPcQUHltCtKYgV3rTh1QCjY0/cGZuAzMLfNVXF4i79YuHokIRO0fDELumo JtzIIpk/Ume4yV5X/t6Xci+RBIBJwt0S4IbF9got0rAgPVDYu6yhd/szNPQsAFJU 0ORf5XE9yDQbnXx/hjlTm3EALt5UqRmIS6McQ4MvU9meregl9+K5+27eBOkVsnSJ ZnI0++4IvqlZ8XpprEIH =iiOS -----END PGP SIGNATURE----- Merge tag 'rtc-4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux Pull RTC updates from Alexandre Belloni: "Subsystem wide cleanups: - Use IS_ENABLED() instead of checking for built-in or module - remove useless DRV_VERSION - remove CLK_IS_ROOT - remove UIE signaling Drivers: - ds1302: rewritten to be a proper SPI device driver - m41t80: huge cleanup, alarm, wakelarm ans oscialltor failure detection support - rv3029: switch to regmap to handle rv3049, alarm support, fixes - zynqmp: enable switching to battery power, fixes - small fixes for at91sam9, da9053, ds1307, ds1685, ds3232, r2025, sa1100, snvs, stmp3xxx, tps6586x" * tag 'rtc-4.7' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (40 commits) rtc: tps6586x: rename so module can be autoloaded rtc: rv3029: hide unused i2c device table rtc: rs5c372: r2025: fix check for 'oscillator halted' condition rtc: rv3029: add alarm IRQ rtc: rv3029: fix set_time function rtc: rv3029: fix alarm support rtc: rv3029: Remove some checks and warnings rtc: rv3029: Add support of RV3049 rtc: rv3029: convert to use regmap rtc: rv3029: remove 'i2c' in functions names rtc: stmp3xxx: print message on error rtc: Use IS_ENABLED() instead of checking for built-in or module rtc: ds3232: fix call trace when rtc->ops_lock is used as NULL rtc: snvs: return error in case enable_irq_wake fails rtc: zynqmp: Update seconds time programming logic rtc: sa1100: DT spelling s/interrupt-name/interrupt-names/ rtc: mc13xxx: remove UIE signaling rtc: mxc: remove UIE signaling rtc: ds1307: Remove CLK_IS_ROOT rtc: hym8563: Remove CLK_IS_ROOT ...
This commit is contained in:
Коммит
63d222b9d2
|
@ -0,0 +1,46 @@
|
|||
* Maxim/Dallas Semiconductor DS-1302 RTC
|
||||
|
||||
Simple device which could be used to store date/time between reboots.
|
||||
|
||||
The device uses the standard MicroWire half-duplex transfer timing.
|
||||
Master output is set on low clock and sensed by the RTC on the rising
|
||||
edge. Master input is set by the RTC on the trailing edge and is sensed
|
||||
by the master on low clock.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : Should be "maxim,ds1302"
|
||||
|
||||
Required SPI properties:
|
||||
|
||||
- reg : Should be address of the device chip select within
|
||||
the controller.
|
||||
|
||||
- spi-max-frequency : DS-1302 has 500 kHz if powered at 2.2V,
|
||||
and 2MHz if powered at 5V.
|
||||
|
||||
- spi-3wire : The device has a shared signal IN/OUT line.
|
||||
|
||||
- spi-lsb-first : DS-1302 requires least significant bit first
|
||||
transfers.
|
||||
|
||||
- spi-cs-high: DS-1302 has active high chip select line. This is
|
||||
required unless inverted in hardware.
|
||||
|
||||
Example:
|
||||
|
||||
spi@901c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "icpdas,lp8841-spi-rtc";
|
||||
reg = <0x901c 0x1>;
|
||||
|
||||
rtc@0 {
|
||||
compatible = "maxim,ds1302";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <500000>;
|
||||
spi-3wire;
|
||||
spi-lsb-first;
|
||||
spi-cs-high;
|
||||
};
|
||||
};
|
|
@ -13,5 +13,5 @@ Example:
|
|||
compatible = "mrvl,mmp-rtc";
|
||||
reg = <0xd4010000 0x1000>;
|
||||
interrupts = <5>, <6>;
|
||||
interrupt-name = "rtc 1Hz", "rtc alarm";
|
||||
interrupt-names = "rtc 1Hz", "rtc alarm";
|
||||
};
|
||||
|
|
|
@ -573,24 +573,6 @@ config RTC_DRV_EM3027
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-em3027.
|
||||
|
||||
config RTC_DRV_RV3029C2
|
||||
tristate "Micro Crystal RV3029"
|
||||
help
|
||||
If you say yes here you get support for the Micro Crystal
|
||||
RV3029 RTC chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-rv3029c2.
|
||||
|
||||
config RTC_DRV_RV3029_HWMON
|
||||
bool "HWMON support for RV3029"
|
||||
depends on RTC_DRV_RV3029C2 && HWMON
|
||||
depends on !(RTC_DRV_RV3029C2=y && HWMON=m)
|
||||
default y
|
||||
help
|
||||
Say Y here if you want to expose temperature sensor data on
|
||||
rtc-rv3029.
|
||||
|
||||
config RTC_DRV_RV8803
|
||||
tristate "Micro Crystal RV8803"
|
||||
help
|
||||
|
@ -634,6 +616,15 @@ config RTC_DRV_M41T94
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-m41t94.
|
||||
|
||||
config RTC_DRV_DS1302
|
||||
tristate "Dallas/Maxim DS1302"
|
||||
depends on SPI
|
||||
help
|
||||
If you say yes here you get support for the Dallas DS1302 RTC chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-ds1302.
|
||||
|
||||
config RTC_DRV_DS1305
|
||||
tristate "Dallas/Maxim DS1305/DS1306"
|
||||
help
|
||||
|
@ -777,6 +768,25 @@ config RTC_DRV_PCF2127
|
|||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-pcf2127.
|
||||
|
||||
config RTC_DRV_RV3029C2
|
||||
tristate "Micro Crystal RV3029/3049"
|
||||
depends on RTC_I2C_AND_SPI
|
||||
help
|
||||
If you say yes here you get support for the Micro Crystal
|
||||
RV3029 and RV3049 RTC chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-rv3029c2.
|
||||
|
||||
config RTC_DRV_RV3029_HWMON
|
||||
bool "HWMON support for RV3029/3049"
|
||||
depends on RTC_DRV_RV3029C2 && HWMON
|
||||
depends on !(RTC_DRV_RV3029C2=y && HWMON=m)
|
||||
default y
|
||||
help
|
||||
Say Y here if you want to expose temperature sensor data on
|
||||
rtc-rv3029.
|
||||
|
||||
comment "Platform RTC drivers"
|
||||
|
||||
# this 'CMOS' RTC driver is arch dependent because <asm-generic/rtc.h>
|
||||
|
@ -834,12 +844,6 @@ config RTC_DRV_DS1286
|
|||
help
|
||||
If you say yes here you get support for the Dallas DS1286 RTC chips.
|
||||
|
||||
config RTC_DRV_DS1302
|
||||
tristate "Dallas DS1302"
|
||||
depends on SH_SECUREEDGE5410
|
||||
help
|
||||
If you say yes here you get support for the Dallas DS1302 RTC chips.
|
||||
|
||||
config RTC_DRV_DS1511
|
||||
tristate "Dallas DS1511"
|
||||
depends on HAS_IOMEM
|
||||
|
|
|
@ -268,7 +268,7 @@ static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
|||
static int at91_rtc_proc(struct device *dev, struct seq_file *seq)
|
||||
{
|
||||
struct sam9_rtc *rtc = dev_get_drvdata(dev);
|
||||
u32 mr = mr = rtt_readl(rtc, MR);
|
||||
u32 mr = rtt_readl(rtc, MR);
|
||||
|
||||
seq_printf(seq, "update_IRQ\t: %s\n",
|
||||
(mr & AT91_RTT_RTTINCIEN) ? "yes" : "no");
|
||||
|
|
|
@ -401,7 +401,7 @@ static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE)
|
||||
#if IS_ENABLED(CONFIG_RTC_INTF_PROC)
|
||||
|
||||
static int cmos_procfs(struct device *dev, struct seq_file *seq)
|
||||
{
|
||||
|
|
|
@ -302,6 +302,13 @@ static int da9052_rtc_probe(struct platform_device *pdev)
|
|||
if (ret != 0)
|
||||
rtc_err(rtc, "Failed to disable TICKS: %d\n", ret);
|
||||
|
||||
device_init_wakeup(&pdev->dev, true);
|
||||
rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
|
||||
&da9052_rtc_ops, THIS_MODULE);
|
||||
|
||||
if (IS_ERR(rtc->rtc))
|
||||
return PTR_ERR(rtc->rtc);
|
||||
|
||||
ret = da9052_request_irq(rtc->da9052, DA9052_IRQ_ALARM, "ALM",
|
||||
da9052_rtc_irq, rtc);
|
||||
if (ret != 0) {
|
||||
|
@ -309,11 +316,7 @@ static int da9052_rtc_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
device_init_wakeup(&pdev->dev, true);
|
||||
|
||||
rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
|
||||
&da9052_rtc_ops, THIS_MODULE);
|
||||
return PTR_ERR_OR_ZERO(rtc->rtc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver da9052_rtc_driver = {
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
#include <linux/bcd.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define DRV_VERSION "0.2"
|
||||
|
||||
struct ds1216_regs {
|
||||
u8 tsec;
|
||||
u8 sec;
|
||||
|
@ -176,5 +174,4 @@ module_platform_driver_probe(ds1216_rtc_platform_driver, ds1216_rtc_probe);
|
|||
MODULE_AUTHOR("Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
|
||||
MODULE_DESCRIPTION("DS1216 RTC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
MODULE_ALIAS("platform:rtc-ds1216");
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define DRV_VERSION "1.0"
|
||||
|
||||
struct ds1286_priv {
|
||||
struct rtc_device *rtc;
|
||||
u32 __iomem *rtcregs;
|
||||
|
@ -363,5 +361,4 @@ module_platform_driver(ds1286_platform_driver);
|
|||
MODULE_AUTHOR("Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
|
||||
MODULE_DESCRIPTION("DS1286 RTC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
MODULE_ALIAS("platform:rtc-ds1286");
|
||||
|
|
|
@ -9,16 +9,16 @@
|
|||
* this archive for more details.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#define DRV_NAME "rtc-ds1302"
|
||||
#define DRV_VERSION "0.1.1"
|
||||
|
||||
#define RTC_CMD_READ 0x81 /* Read command */
|
||||
#define RTC_CMD_WRITE 0x80 /* Write command */
|
||||
|
@ -28,6 +28,8 @@
|
|||
|
||||
#define RTC_ADDR_RAM0 0x20 /* Address of RAM0 */
|
||||
#define RTC_ADDR_TCR 0x08 /* Address of trickle charge register */
|
||||
#define RTC_CLCK_BURST 0x1F /* Address of clock burst */
|
||||
#define RTC_CLCK_LEN 0x08 /* Size of clock burst */
|
||||
#define RTC_ADDR_CTRL 0x07 /* Address of control register */
|
||||
#define RTC_ADDR_YEAR 0x06 /* Address of year register */
|
||||
#define RTC_ADDR_DAY 0x05 /* Address of day of week register */
|
||||
|
@ -37,219 +39,181 @@
|
|||
#define RTC_ADDR_MIN 0x01 /* Address of minute register */
|
||||
#define RTC_ADDR_SEC 0x00 /* Address of second register */
|
||||
|
||||
#ifdef CONFIG_SH_SECUREEDGE5410
|
||||
#include <asm/rtc.h>
|
||||
#include <mach/secureedge5410.h>
|
||||
|
||||
#define RTC_RESET 0x1000
|
||||
#define RTC_IODATA 0x0800
|
||||
#define RTC_SCLK 0x0400
|
||||
|
||||
#define set_dp(x) SECUREEDGE_WRITE_IOPORT(x, 0x1c00)
|
||||
#define get_dp() SECUREEDGE_READ_IOPORT()
|
||||
#define ds1302_set_tx()
|
||||
#define ds1302_set_rx()
|
||||
|
||||
static inline int ds1302_hw_init(void)
|
||||
static int ds1302_rtc_set_time(struct device *dev, struct rtc_time *time)
|
||||
{
|
||||
return 0;
|
||||
struct spi_device *spi = dev_get_drvdata(dev);
|
||||
u8 buf[1 + RTC_CLCK_LEN];
|
||||
u8 *bp = buf;
|
||||
int status;
|
||||
|
||||
/* Enable writing */
|
||||
bp = buf;
|
||||
*bp++ = RTC_ADDR_CTRL << 1 | RTC_CMD_WRITE;
|
||||
*bp++ = RTC_CMD_WRITE_ENABLE;
|
||||
|
||||
status = spi_write_then_read(spi, buf, 2,
|
||||
NULL, 0);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
/* Write registers starting at the first time/date address. */
|
||||
bp = buf;
|
||||
*bp++ = RTC_CLCK_BURST << 1 | RTC_CMD_WRITE;
|
||||
|
||||
*bp++ = bin2bcd(time->tm_sec);
|
||||
*bp++ = bin2bcd(time->tm_min);
|
||||
*bp++ = bin2bcd(time->tm_hour);
|
||||
*bp++ = bin2bcd(time->tm_mday);
|
||||
*bp++ = bin2bcd(time->tm_mon + 1);
|
||||
*bp++ = time->tm_wday + 1;
|
||||
*bp++ = bin2bcd(time->tm_year % 100);
|
||||
*bp++ = RTC_CMD_WRITE_DISABLE;
|
||||
|
||||
/* use write-then-read since dma from stack is nonportable */
|
||||
return spi_write_then_read(spi, buf, sizeof(buf),
|
||||
NULL, 0);
|
||||
}
|
||||
|
||||
static inline void ds1302_reset(void)
|
||||
static int ds1302_rtc_get_time(struct device *dev, struct rtc_time *time)
|
||||
{
|
||||
set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
|
||||
}
|
||||
struct spi_device *spi = dev_get_drvdata(dev);
|
||||
u8 addr = RTC_CLCK_BURST << 1 | RTC_CMD_READ;
|
||||
u8 buf[RTC_CLCK_LEN - 1];
|
||||
int status;
|
||||
|
||||
static inline void ds1302_clock(void)
|
||||
{
|
||||
set_dp(get_dp() | RTC_SCLK); /* clock high */
|
||||
set_dp(get_dp() & ~RTC_SCLK); /* clock low */
|
||||
}
|
||||
/* Use write-then-read to get all the date/time registers
|
||||
* since dma from stack is nonportable
|
||||
*/
|
||||
status = spi_write_then_read(spi, &addr, sizeof(addr),
|
||||
buf, sizeof(buf));
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
static inline void ds1302_start(void)
|
||||
{
|
||||
set_dp(get_dp() | RTC_RESET);
|
||||
}
|
||||
/* Decode the registers */
|
||||
time->tm_sec = bcd2bin(buf[RTC_ADDR_SEC]);
|
||||
time->tm_min = bcd2bin(buf[RTC_ADDR_MIN]);
|
||||
time->tm_hour = bcd2bin(buf[RTC_ADDR_HOUR]);
|
||||
time->tm_wday = buf[RTC_ADDR_DAY] - 1;
|
||||
time->tm_mday = bcd2bin(buf[RTC_ADDR_DATE]);
|
||||
time->tm_mon = bcd2bin(buf[RTC_ADDR_MON]) - 1;
|
||||
time->tm_year = bcd2bin(buf[RTC_ADDR_YEAR]) + 100;
|
||||
|
||||
static inline void ds1302_stop(void)
|
||||
{
|
||||
set_dp(get_dp() & ~RTC_RESET);
|
||||
}
|
||||
|
||||
static inline void ds1302_txbit(int bit)
|
||||
{
|
||||
set_dp((get_dp() & ~RTC_IODATA) | (bit ? RTC_IODATA : 0));
|
||||
}
|
||||
|
||||
static inline int ds1302_rxbit(void)
|
||||
{
|
||||
return !!(get_dp() & RTC_IODATA);
|
||||
}
|
||||
|
||||
#else
|
||||
#error "Add support for your platform"
|
||||
#endif
|
||||
|
||||
static void ds1302_sendbits(unsigned int val)
|
||||
{
|
||||
int i;
|
||||
|
||||
ds1302_set_tx();
|
||||
|
||||
for (i = 8; (i); i--, val >>= 1) {
|
||||
ds1302_txbit(val & 0x1);
|
||||
ds1302_clock();
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int ds1302_recvbits(void)
|
||||
{
|
||||
unsigned int val;
|
||||
int i;
|
||||
|
||||
ds1302_set_rx();
|
||||
|
||||
for (i = 0, val = 0; (i < 8); i++) {
|
||||
val |= (ds1302_rxbit() << i);
|
||||
ds1302_clock();
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static unsigned int ds1302_readbyte(unsigned int addr)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
ds1302_reset();
|
||||
|
||||
ds1302_start();
|
||||
ds1302_sendbits(((addr & 0x3f) << 1) | RTC_CMD_READ);
|
||||
val = ds1302_recvbits();
|
||||
ds1302_stop();
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void ds1302_writebyte(unsigned int addr, unsigned int val)
|
||||
{
|
||||
ds1302_reset();
|
||||
|
||||
ds1302_start();
|
||||
ds1302_sendbits(((addr & 0x3f) << 1) | RTC_CMD_WRITE);
|
||||
ds1302_sendbits(val);
|
||||
ds1302_stop();
|
||||
}
|
||||
|
||||
static int ds1302_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
tm->tm_sec = bcd2bin(ds1302_readbyte(RTC_ADDR_SEC));
|
||||
tm->tm_min = bcd2bin(ds1302_readbyte(RTC_ADDR_MIN));
|
||||
tm->tm_hour = bcd2bin(ds1302_readbyte(RTC_ADDR_HOUR));
|
||||
tm->tm_wday = bcd2bin(ds1302_readbyte(RTC_ADDR_DAY));
|
||||
tm->tm_mday = bcd2bin(ds1302_readbyte(RTC_ADDR_DATE));
|
||||
tm->tm_mon = bcd2bin(ds1302_readbyte(RTC_ADDR_MON)) - 1;
|
||||
tm->tm_year = bcd2bin(ds1302_readbyte(RTC_ADDR_YEAR));
|
||||
|
||||
if (tm->tm_year < 70)
|
||||
tm->tm_year += 100;
|
||||
|
||||
dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
|
||||
"mday=%d, mon=%d, year=%d, wday=%d\n",
|
||||
__func__,
|
||||
tm->tm_sec, tm->tm_min, tm->tm_hour,
|
||||
tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_wday);
|
||||
|
||||
return rtc_valid_tm(tm);
|
||||
}
|
||||
|
||||
static int ds1302_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
ds1302_writebyte(RTC_ADDR_CTRL, RTC_CMD_WRITE_ENABLE);
|
||||
/* Stop RTC */
|
||||
ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) | 0x80);
|
||||
|
||||
ds1302_writebyte(RTC_ADDR_SEC, bin2bcd(tm->tm_sec));
|
||||
ds1302_writebyte(RTC_ADDR_MIN, bin2bcd(tm->tm_min));
|
||||
ds1302_writebyte(RTC_ADDR_HOUR, bin2bcd(tm->tm_hour));
|
||||
ds1302_writebyte(RTC_ADDR_DAY, bin2bcd(tm->tm_wday));
|
||||
ds1302_writebyte(RTC_ADDR_DATE, bin2bcd(tm->tm_mday));
|
||||
ds1302_writebyte(RTC_ADDR_MON, bin2bcd(tm->tm_mon + 1));
|
||||
ds1302_writebyte(RTC_ADDR_YEAR, bin2bcd(tm->tm_year % 100));
|
||||
|
||||
/* Start RTC */
|
||||
ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) & ~0x80);
|
||||
|
||||
ds1302_writebyte(RTC_ADDR_CTRL, RTC_CMD_WRITE_DISABLE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ds1302_rtc_ioctl(struct device *dev, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
switch (cmd) {
|
||||
#ifdef RTC_SET_CHARGE
|
||||
case RTC_SET_CHARGE:
|
||||
{
|
||||
int tcs_val;
|
||||
|
||||
if (copy_from_user(&tcs_val, (int __user *)arg, sizeof(int)))
|
||||
return -EFAULT;
|
||||
|
||||
ds1302_writebyte(RTC_ADDR_TCR, (0xa0 | tcs_val * 0xf));
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return -ENOIOCTLCMD;
|
||||
/* Time may not be set */
|
||||
return rtc_valid_tm(time);
|
||||
}
|
||||
|
||||
static struct rtc_class_ops ds1302_rtc_ops = {
|
||||
.read_time = ds1302_rtc_read_time,
|
||||
.read_time = ds1302_rtc_get_time,
|
||||
.set_time = ds1302_rtc_set_time,
|
||||
.ioctl = ds1302_rtc_ioctl,
|
||||
};
|
||||
|
||||
static int __init ds1302_rtc_probe(struct platform_device *pdev)
|
||||
static int ds1302_probe(struct spi_device *spi)
|
||||
{
|
||||
struct rtc_device *rtc;
|
||||
struct rtc_device *rtc;
|
||||
u8 addr;
|
||||
u8 buf[4];
|
||||
u8 *bp = buf;
|
||||
int status;
|
||||
|
||||
if (ds1302_hw_init()) {
|
||||
dev_err(&pdev->dev, "Failed to init communication channel");
|
||||
/* Sanity check board setup data. This may be hooked up
|
||||
* in 3wire mode, but we don't care. Note that unless
|
||||
* there's an inverter in place, this needs SPI_CS_HIGH!
|
||||
*/
|
||||
if (spi->bits_per_word && (spi->bits_per_word != 8)) {
|
||||
dev_err(&spi->dev, "bad word length\n");
|
||||
return -EINVAL;
|
||||
} else if (spi->max_speed_hz > 2000000) {
|
||||
dev_err(&spi->dev, "speed is too high\n");
|
||||
return -EINVAL;
|
||||
} else if (spi->mode & SPI_CPHA) {
|
||||
dev_err(&spi->dev, "bad mode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Reset */
|
||||
ds1302_reset();
|
||||
|
||||
/* Write a magic value to the DS1302 RAM, and see if it sticks. */
|
||||
ds1302_writebyte(RTC_ADDR_RAM0, 0x42);
|
||||
if (ds1302_readbyte(RTC_ADDR_RAM0) != 0x42) {
|
||||
dev_err(&pdev->dev, "Failed to probe");
|
||||
return -ENODEV;
|
||||
addr = RTC_ADDR_CTRL << 1 | RTC_CMD_READ;
|
||||
status = spi_write_then_read(spi, &addr, sizeof(addr), buf, 1);
|
||||
if (status < 0) {
|
||||
dev_err(&spi->dev, "control register read error %d\n",
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
|
||||
rtc = devm_rtc_device_register(&pdev->dev, "ds1302",
|
||||
&ds1302_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(rtc))
|
||||
return PTR_ERR(rtc);
|
||||
if ((buf[0] & ~RTC_CMD_WRITE_DISABLE) != 0) {
|
||||
status = spi_write_then_read(spi, &addr, sizeof(addr), buf, 1);
|
||||
if (status < 0) {
|
||||
dev_err(&spi->dev, "control register read error %d\n",
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, rtc);
|
||||
if ((buf[0] & ~RTC_CMD_WRITE_DISABLE) != 0) {
|
||||
dev_err(&spi->dev, "junk in control register\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
if (buf[0] == 0) {
|
||||
bp = buf;
|
||||
*bp++ = RTC_ADDR_CTRL << 1 | RTC_CMD_WRITE;
|
||||
*bp++ = RTC_CMD_WRITE_DISABLE;
|
||||
|
||||
status = spi_write_then_read(spi, buf, 2, NULL, 0);
|
||||
if (status < 0) {
|
||||
dev_err(&spi->dev, "control register write error %d\n",
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
|
||||
addr = RTC_ADDR_CTRL << 1 | RTC_CMD_READ;
|
||||
status = spi_write_then_read(spi, &addr, sizeof(addr), buf, 1);
|
||||
if (status < 0) {
|
||||
dev_err(&spi->dev,
|
||||
"error %d reading control register\n",
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (buf[0] != RTC_CMD_WRITE_DISABLE) {
|
||||
dev_err(&spi->dev, "failed to detect chip\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
spi_set_drvdata(spi, spi);
|
||||
|
||||
rtc = devm_rtc_device_register(&spi->dev, "ds1302",
|
||||
&ds1302_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(rtc)) {
|
||||
status = PTR_ERR(rtc);
|
||||
dev_err(&spi->dev, "error %d registering rtc\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ds1302_platform_driver = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
},
|
||||
static int ds1302_remove(struct spi_device *spi)
|
||||
{
|
||||
spi_set_drvdata(spi, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id ds1302_dt_ids[] = {
|
||||
{ .compatible = "maxim,ds1302", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ds1302_dt_ids);
|
||||
#endif
|
||||
|
||||
static struct spi_driver ds1302_driver = {
|
||||
.driver.name = "rtc-ds1302",
|
||||
.driver.of_match_table = of_match_ptr(ds1302_dt_ids),
|
||||
.probe = ds1302_probe,
|
||||
.remove = ds1302_remove,
|
||||
};
|
||||
|
||||
module_platform_driver_probe(ds1302_platform_driver, ds1302_rtc_probe);
|
||||
module_spi_driver(ds1302_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Dallas DS1302 RTC driver");
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
MODULE_AUTHOR("Paul Mundt, David McCullough");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -275,9 +275,13 @@ static s32 ds1307_native_smbus_write_block_data(const struct i2c_client *client,
|
|||
{
|
||||
u8 suboffset = 0;
|
||||
|
||||
if (length <= I2C_SMBUS_BLOCK_MAX)
|
||||
return i2c_smbus_write_i2c_block_data(client,
|
||||
if (length <= I2C_SMBUS_BLOCK_MAX) {
|
||||
s32 retval = i2c_smbus_write_i2c_block_data(client,
|
||||
command, length, values);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
return length;
|
||||
}
|
||||
|
||||
while (suboffset < length) {
|
||||
s32 retval = i2c_smbus_write_i2c_block_data(client,
|
||||
|
@ -538,12 +542,8 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t)
|
|||
buf[5] = 0;
|
||||
buf[6] = 0;
|
||||
|
||||
/* optionally enable ALARM1 */
|
||||
/* disable alarms */
|
||||
buf[7] = control & ~(DS1337_BIT_A1IE | DS1337_BIT_A2IE);
|
||||
if (t->enabled) {
|
||||
dev_dbg(dev, "alarm IRQ armed\n");
|
||||
buf[7] |= DS1337_BIT_A1IE; /* only ALARM1 is used */
|
||||
}
|
||||
buf[8] = status & ~(DS1337_BIT_A1I | DS1337_BIT_A2I);
|
||||
|
||||
ret = ds1307->write_block_data(client,
|
||||
|
@ -553,6 +553,13 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* optionally enable ALARM1 */
|
||||
if (t->enabled) {
|
||||
dev_dbg(dev, "alarm IRQ armed\n");
|
||||
buf[7] |= DS1337_BIT_A1IE; /* only ALARM1 is used */
|
||||
i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, buf[7]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1144,12 +1151,10 @@ static struct clk_init_data ds3231_clks_init[] = {
|
|||
[DS3231_CLK_SQW] = {
|
||||
.name = "ds3231_clk_sqw",
|
||||
.ops = &ds3231_clk_sqw_ops,
|
||||
.flags = CLK_IS_ROOT,
|
||||
},
|
||||
[DS3231_CLK_32KHZ] = {
|
||||
.name = "ds3231_clk_32khz",
|
||||
.ops = &ds3231_clk_32khz_ops,
|
||||
.flags = CLK_IS_ROOT,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include <linux/pm_wakeirq.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define DS1343_DRV_VERSION "01.00"
|
||||
#define DALLAS_MAXIM_DS1343 0
|
||||
#define DALLAS_MAXIM_DS1344 1
|
||||
|
||||
|
@ -747,4 +746,3 @@ MODULE_DESCRIPTION("DS1343 RTC SPI Driver");
|
|||
MODULE_AUTHOR("Raghavendra Chandra Ganiga <ravi23ganiga@gmail.com>,"
|
||||
"Ankur Srivastava <sankurece@gmail.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_VERSION(DS1343_DRV_VERSION);
|
||||
|
|
|
@ -25,8 +25,6 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#define DRV_VERSION "0.6"
|
||||
|
||||
enum ds1511reg {
|
||||
DS1511_SEC = 0x0,
|
||||
DS1511_MIN = 0x1,
|
||||
|
@ -537,4 +535,3 @@ module_platform_driver(ds1511_rtc_driver);
|
|||
MODULE_AUTHOR("Andrew Sharp <andy.sharp@lsi.com>");
|
||||
MODULE_DESCRIPTION("Dallas DS1511 RTC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#define DRV_VERSION "0.3"
|
||||
|
||||
#define RTC_REG_SIZE 0x2000
|
||||
#define RTC_OFFSET 0x1ff0
|
||||
|
||||
|
@ -359,4 +357,3 @@ module_platform_driver(ds1553_rtc_driver);
|
|||
MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
|
||||
MODULE_DESCRIPTION("Dallas DS1553 RTC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
|
|
|
@ -13,8 +13,6 @@
|
|||
#include <linux/rtc.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#define DRV_VERSION "0.4"
|
||||
|
||||
/* Registers */
|
||||
|
||||
#define DS1672_REG_CNT_BASE 0
|
||||
|
@ -165,8 +163,6 @@ static int ds1672_probe(struct i2c_client *client,
|
|||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
|
||||
return -ENODEV;
|
||||
|
||||
dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
|
||||
|
||||
rtc = devm_rtc_device_register(&client->dev, ds1672_driver.driver.name,
|
||||
&ds1672_rtc_ops, THIS_MODULE);
|
||||
|
||||
|
@ -213,4 +209,3 @@ module_i2c_driver(ds1672_driver);
|
|||
MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
|
||||
MODULE_DESCRIPTION("Dallas/Maxim DS1672 timekeeper driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
|
|
|
@ -32,8 +32,6 @@
|
|||
#include <linux/proc_fs.h>
|
||||
#endif
|
||||
|
||||
#define DRV_VERSION "0.42.0"
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
/* Standard read/write functions if platform does not provide overrides */
|
||||
|
@ -2213,6 +2211,7 @@ ds1685_rtc_poweroff(struct platform_device *pdev)
|
|||
(ctrl4a | RTC_CTRL_4A_PAB));
|
||||
|
||||
/* Spin ... we do not switch back to bank0. */
|
||||
while(1);
|
||||
unreachable();
|
||||
}
|
||||
}
|
||||
|
@ -2224,5 +2223,4 @@ MODULE_AUTHOR("Joshua Kinard <kumba@gentoo.org>");
|
|||
MODULE_AUTHOR("Matthias Fuchs <matthias.fuchs@esd-electronics.com>");
|
||||
MODULE_DESCRIPTION("Dallas/Maxim DS1685/DS1687-series RTC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
MODULE_ALIAS("platform:rtc-ds1685");
|
||||
|
|
|
@ -24,8 +24,6 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#define DRV_VERSION "0.4"
|
||||
|
||||
#define RTC_SIZE 8
|
||||
|
||||
#define RTC_CONTROL 0
|
||||
|
@ -239,5 +237,4 @@ module_platform_driver(ds1742_rtc_driver);
|
|||
MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
|
||||
MODULE_DESCRIPTION("Dallas DS1742 RTC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
MODULE_ALIAS("platform:rtc-ds1742");
|
||||
|
|
|
@ -369,6 +369,11 @@ static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ds3232->rtc = devm_rtc_device_register(dev, name, &ds3232_rtc_ops,
|
||||
THIS_MODULE);
|
||||
if (IS_ERR(ds3232->rtc))
|
||||
return PTR_ERR(ds3232->rtc);
|
||||
|
||||
if (ds3232->irq > 0) {
|
||||
ret = devm_request_threaded_irq(dev, ds3232->irq, NULL,
|
||||
ds3232_irq,
|
||||
|
@ -380,10 +385,8 @@ static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq,
|
|||
} else
|
||||
device_init_wakeup(dev, 1);
|
||||
}
|
||||
ds3232->rtc = devm_rtc_device_register(dev, name, &ds3232_rtc_ops,
|
||||
THIS_MODULE);
|
||||
|
||||
return PTR_ERR_OR_ZERO(ds3232->rtc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
|
|
@ -28,8 +28,6 @@
|
|||
#define EP93XX_RTC_SWCOMP_INT_MASK 0x0000ffff
|
||||
#define EP93XX_RTC_SWCOMP_INT_SHIFT 0
|
||||
|
||||
#define DRV_VERSION "0.3"
|
||||
|
||||
/*
|
||||
* struct device dev.platform_data is used to store our private data
|
||||
* because struct rtc_device does not have a variable to hold it.
|
||||
|
@ -184,5 +182,4 @@ module_platform_driver(ep93xx_rtc_driver);
|
|||
MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
|
||||
MODULE_DESCRIPTION("EP93XX RTC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
MODULE_ALIAS("platform:ep93xx-rtc");
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#include <linux/module.h>
|
||||
|
||||
#define DRV_NAME "rtc-gemini"
|
||||
#define DRV_VERSION "0.2"
|
||||
|
||||
MODULE_AUTHOR("Hans Ulli Kroll <ulli.kroll@googlemail.com>");
|
||||
MODULE_DESCRIPTION("RTC driver for Gemini SoC");
|
||||
|
|
|
@ -413,7 +413,7 @@ static struct clk *hym8563_clkout_register_clk(struct hym8563 *hym8563)
|
|||
|
||||
init.name = "hym8563-clkout";
|
||||
init.ops = &hym8563_clkout_ops;
|
||||
init.flags = CLK_IS_ROOT;
|
||||
init.flags = 0;
|
||||
init.parent_names = NULL;
|
||||
init.num_parents = 0;
|
||||
hym8563->clkout_hw.init = &init;
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#define DRV_VERSION "0.1"
|
||||
|
||||
/* ISL register offsets */
|
||||
#define ISL12022_REG_SC 0x00
|
||||
#define ISL12022_REG_MN 0x01
|
||||
|
@ -258,8 +256,6 @@ static int isl12022_probe(struct i2c_client *client,
|
|||
if (!isl12022)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_dbg(&client->dev, "chip found, driver version " DRV_VERSION "\n");
|
||||
|
||||
i2c_set_clientdata(client, isl12022);
|
||||
|
||||
isl12022->rtc = devm_rtc_device_register(&client->dev,
|
||||
|
@ -299,4 +295,3 @@ module_i2c_driver(isl12022_driver);
|
|||
MODULE_AUTHOR("roman.fietze@telemotive.de");
|
||||
MODULE_DESCRIPTION("ISL 12022 RTC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
|
|
|
@ -15,8 +15,6 @@
|
|||
#include <linux/bcd.h>
|
||||
#include <linux/rtc.h>
|
||||
|
||||
#define DRV_VERSION "0.3"
|
||||
|
||||
/* Register map */
|
||||
/* rtc section */
|
||||
#define ISL1208_REG_SC 0x00
|
||||
|
@ -632,9 +630,6 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
if (isl1208_i2c_validate_client(client) < 0)
|
||||
return -ENODEV;
|
||||
|
||||
dev_info(&client->dev,
|
||||
"chip found, driver version " DRV_VERSION "\n");
|
||||
|
||||
if (client->irq > 0) {
|
||||
rc = devm_request_threaded_irq(&client->dev, client->irq, NULL,
|
||||
isl1208_rtc_interrupt,
|
||||
|
@ -706,4 +701,3 @@ module_i2c_driver(isl1208_driver);
|
|||
MODULE_AUTHOR("Herbert Valerio Riedel <hvr@gnu.org>");
|
||||
MODULE_DESCRIPTION("Intersil ISL1208 RTC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
|
|
|
@ -32,41 +32,42 @@
|
|||
#include <linux/watchdog.h>
|
||||
#endif
|
||||
|
||||
#define M41T80_REG_SSEC 0
|
||||
#define M41T80_REG_SEC 1
|
||||
#define M41T80_REG_MIN 2
|
||||
#define M41T80_REG_HOUR 3
|
||||
#define M41T80_REG_WDAY 4
|
||||
#define M41T80_REG_DAY 5
|
||||
#define M41T80_REG_MON 6
|
||||
#define M41T80_REG_YEAR 7
|
||||
#define M41T80_REG_ALARM_MON 0xa
|
||||
#define M41T80_REG_ALARM_DAY 0xb
|
||||
#define M41T80_REG_ALARM_HOUR 0xc
|
||||
#define M41T80_REG_ALARM_MIN 0xd
|
||||
#define M41T80_REG_ALARM_SEC 0xe
|
||||
#define M41T80_REG_FLAGS 0xf
|
||||
#define M41T80_REG_SQW 0x13
|
||||
#define M41T80_REG_SSEC 0x00
|
||||
#define M41T80_REG_SEC 0x01
|
||||
#define M41T80_REG_MIN 0x02
|
||||
#define M41T80_REG_HOUR 0x03
|
||||
#define M41T80_REG_WDAY 0x04
|
||||
#define M41T80_REG_DAY 0x05
|
||||
#define M41T80_REG_MON 0x06
|
||||
#define M41T80_REG_YEAR 0x07
|
||||
#define M41T80_REG_ALARM_MON 0x0a
|
||||
#define M41T80_REG_ALARM_DAY 0x0b
|
||||
#define M41T80_REG_ALARM_HOUR 0x0c
|
||||
#define M41T80_REG_ALARM_MIN 0x0d
|
||||
#define M41T80_REG_ALARM_SEC 0x0e
|
||||
#define M41T80_REG_FLAGS 0x0f
|
||||
#define M41T80_REG_SQW 0x13
|
||||
|
||||
#define M41T80_DATETIME_REG_SIZE (M41T80_REG_YEAR + 1)
|
||||
#define M41T80_ALARM_REG_SIZE \
|
||||
(M41T80_REG_ALARM_SEC + 1 - M41T80_REG_ALARM_MON)
|
||||
|
||||
#define M41T80_SEC_ST (1 << 7) /* ST: Stop Bit */
|
||||
#define M41T80_ALMON_AFE (1 << 7) /* AFE: AF Enable Bit */
|
||||
#define M41T80_ALMON_SQWE (1 << 6) /* SQWE: SQW Enable Bit */
|
||||
#define M41T80_ALHOUR_HT (1 << 6) /* HT: Halt Update Bit */
|
||||
#define M41T80_FLAGS_AF (1 << 6) /* AF: Alarm Flag Bit */
|
||||
#define M41T80_FLAGS_BATT_LOW (1 << 4) /* BL: Battery Low Bit */
|
||||
#define M41T80_WATCHDOG_RB2 (1 << 7) /* RB: Watchdog resolution */
|
||||
#define M41T80_WATCHDOG_RB1 (1 << 1) /* RB: Watchdog resolution */
|
||||
#define M41T80_WATCHDOG_RB0 (1 << 0) /* RB: Watchdog resolution */
|
||||
#define M41T80_SEC_ST BIT(7) /* ST: Stop Bit */
|
||||
#define M41T80_ALMON_AFE BIT(7) /* AFE: AF Enable Bit */
|
||||
#define M41T80_ALMON_SQWE BIT(6) /* SQWE: SQW Enable Bit */
|
||||
#define M41T80_ALHOUR_HT BIT(6) /* HT: Halt Update Bit */
|
||||
#define M41T80_FLAGS_OF BIT(2) /* OF: Oscillator Failure Bit */
|
||||
#define M41T80_FLAGS_AF BIT(6) /* AF: Alarm Flag Bit */
|
||||
#define M41T80_FLAGS_BATT_LOW BIT(4) /* BL: Battery Low Bit */
|
||||
#define M41T80_WATCHDOG_RB2 BIT(7) /* RB: Watchdog resolution */
|
||||
#define M41T80_WATCHDOG_RB1 BIT(1) /* RB: Watchdog resolution */
|
||||
#define M41T80_WATCHDOG_RB0 BIT(0) /* RB: Watchdog resolution */
|
||||
|
||||
#define M41T80_FEATURE_HT (1 << 0) /* Halt feature */
|
||||
#define M41T80_FEATURE_BL (1 << 1) /* Battery low indicator */
|
||||
#define M41T80_FEATURE_SQ (1 << 2) /* Squarewave feature */
|
||||
#define M41T80_FEATURE_WD (1 << 3) /* Extra watchdog resolution */
|
||||
#define M41T80_FEATURE_SQ_ALT (1 << 4) /* RSx bits are in reg 4 */
|
||||
#define M41T80_FEATURE_HT BIT(0) /* Halt feature */
|
||||
#define M41T80_FEATURE_BL BIT(1) /* Battery low indicator */
|
||||
#define M41T80_FEATURE_SQ BIT(2) /* Squarewave feature */
|
||||
#define M41T80_FEATURE_WD BIT(3) /* Extra watchdog resolution */
|
||||
#define M41T80_FEATURE_SQ_ALT BIT(4) /* RSx bits are in reg 4 */
|
||||
|
||||
static DEFINE_MUTEX(m41t80_rtc_mutex);
|
||||
static const struct i2c_device_id m41t80_id[] = {
|
||||
|
@ -90,27 +91,65 @@ struct m41t80_data {
|
|||
struct rtc_device *rtc;
|
||||
};
|
||||
|
||||
static irqreturn_t m41t80_handle_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct i2c_client *client = dev_id;
|
||||
struct m41t80_data *m41t80 = i2c_get_clientdata(client);
|
||||
struct mutex *lock = &m41t80->rtc->ops_lock;
|
||||
unsigned long events = 0;
|
||||
int flags, flags_afe;
|
||||
|
||||
mutex_lock(lock);
|
||||
|
||||
flags_afe = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
|
||||
if (flags_afe < 0) {
|
||||
mutex_unlock(lock);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
flags = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
|
||||
if (flags <= 0) {
|
||||
mutex_unlock(lock);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
if (flags & M41T80_FLAGS_AF) {
|
||||
flags &= ~M41T80_FLAGS_AF;
|
||||
flags_afe &= ~M41T80_ALMON_AFE;
|
||||
events |= RTC_AF;
|
||||
}
|
||||
|
||||
if (events) {
|
||||
rtc_update_irq(m41t80->rtc, 1, events);
|
||||
i2c_smbus_write_byte_data(client, M41T80_REG_FLAGS, flags);
|
||||
i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
|
||||
flags_afe);
|
||||
}
|
||||
|
||||
mutex_unlock(lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int m41t80_get_datetime(struct i2c_client *client,
|
||||
struct rtc_time *tm)
|
||||
{
|
||||
u8 buf[M41T80_DATETIME_REG_SIZE], dt_addr[1] = { M41T80_REG_SEC };
|
||||
struct i2c_msg msgs[] = {
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = 0,
|
||||
.len = 1,
|
||||
.buf = dt_addr,
|
||||
},
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = I2C_M_RD,
|
||||
.len = M41T80_DATETIME_REG_SIZE - M41T80_REG_SEC,
|
||||
.buf = buf + M41T80_REG_SEC,
|
||||
},
|
||||
};
|
||||
unsigned char buf[8];
|
||||
int err, flags;
|
||||
|
||||
if (i2c_transfer(client->adapter, msgs, 2) < 0) {
|
||||
dev_err(&client->dev, "read error\n");
|
||||
flags = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
|
||||
if (flags < 0)
|
||||
return flags;
|
||||
|
||||
if (flags & M41T80_FLAGS_OF) {
|
||||
dev_err(&client->dev, "Oscillator failure, data is invalid.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = i2c_smbus_read_i2c_block_data(client, M41T80_REG_SSEC,
|
||||
sizeof(buf), buf);
|
||||
if (err < 0) {
|
||||
dev_err(&client->dev, "Unable to read date\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
@ -129,70 +168,42 @@ static int m41t80_get_datetime(struct i2c_client *client,
|
|||
/* Sets the given date and time to the real time clock. */
|
||||
static int m41t80_set_datetime(struct i2c_client *client, struct rtc_time *tm)
|
||||
{
|
||||
u8 wbuf[1 + M41T80_DATETIME_REG_SIZE];
|
||||
u8 *buf = &wbuf[1];
|
||||
u8 dt_addr[1] = { M41T80_REG_SEC };
|
||||
struct i2c_msg msgs_in[] = {
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = 0,
|
||||
.len = 1,
|
||||
.buf = dt_addr,
|
||||
},
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = I2C_M_RD,
|
||||
.len = M41T80_DATETIME_REG_SIZE - M41T80_REG_SEC,
|
||||
.buf = buf + M41T80_REG_SEC,
|
||||
},
|
||||
};
|
||||
struct i2c_msg msgs[] = {
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = 0,
|
||||
.len = 1 + M41T80_DATETIME_REG_SIZE,
|
||||
.buf = wbuf,
|
||||
},
|
||||
};
|
||||
unsigned char buf[8];
|
||||
int err, flags;
|
||||
|
||||
/* Read current reg values into buf[1..7] */
|
||||
if (i2c_transfer(client->adapter, msgs_in, 2) < 0) {
|
||||
dev_err(&client->dev, "read error\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
wbuf[0] = 0; /* offset into rtc's regs */
|
||||
/* Merge time-data and register flags into buf[0..7] */
|
||||
buf[M41T80_REG_SSEC] = 0;
|
||||
buf[M41T80_REG_SEC] =
|
||||
bin2bcd(tm->tm_sec) | (buf[M41T80_REG_SEC] & ~0x7f);
|
||||
buf[M41T80_REG_MIN] =
|
||||
bin2bcd(tm->tm_min) | (buf[M41T80_REG_MIN] & ~0x7f);
|
||||
buf[M41T80_REG_HOUR] =
|
||||
bin2bcd(tm->tm_hour) | (buf[M41T80_REG_HOUR] & ~0x3f);
|
||||
buf[M41T80_REG_WDAY] =
|
||||
(tm->tm_wday & 0x07) | (buf[M41T80_REG_WDAY] & ~0x07);
|
||||
buf[M41T80_REG_DAY] =
|
||||
bin2bcd(tm->tm_mday) | (buf[M41T80_REG_DAY] & ~0x3f);
|
||||
buf[M41T80_REG_MON] =
|
||||
bin2bcd(tm->tm_mon + 1) | (buf[M41T80_REG_MON] & ~0x1f);
|
||||
|
||||
/* assume 20YY not 19YY */
|
||||
if (tm->tm_year < 100 || tm->tm_year > 199) {
|
||||
dev_err(&client->dev, "Year must be between 2000 and 2099. It's %d.\n",
|
||||
tm->tm_year + 1900);
|
||||
if (tm->tm_year < 100 || tm->tm_year > 199)
|
||||
return -EINVAL;
|
||||
}
|
||||
buf[M41T80_REG_YEAR] = bin2bcd(tm->tm_year % 100);
|
||||
|
||||
if (i2c_transfer(client->adapter, msgs, 1) != 1) {
|
||||
dev_err(&client->dev, "write error\n");
|
||||
buf[M41T80_REG_SSEC] = 0;
|
||||
buf[M41T80_REG_SEC] = bin2bcd(tm->tm_sec);
|
||||
buf[M41T80_REG_MIN] = bin2bcd(tm->tm_min);
|
||||
buf[M41T80_REG_HOUR] = bin2bcd(tm->tm_hour);
|
||||
buf[M41T80_REG_DAY] = bin2bcd(tm->tm_mday);
|
||||
buf[M41T80_REG_MON] = bin2bcd(tm->tm_mon + 1);
|
||||
buf[M41T80_REG_YEAR] = bin2bcd(tm->tm_year - 100);
|
||||
buf[M41T80_REG_WDAY] = tm->tm_wday;
|
||||
|
||||
err = i2c_smbus_write_i2c_block_data(client, M41T80_REG_SSEC,
|
||||
sizeof(buf), buf);
|
||||
if (err < 0) {
|
||||
dev_err(&client->dev, "Unable to write to date registers\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Clear the OF bit of Flags Register */
|
||||
flags = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
|
||||
if (flags < 0)
|
||||
return flags;
|
||||
|
||||
if (i2c_smbus_write_byte_data(client, M41T80_REG_FLAGS,
|
||||
flags & ~M41T80_FLAGS_OF)) {
|
||||
dev_err(&client->dev, "Unable to write flags register\n");
|
||||
return -EIO;
|
||||
}
|
||||
return 0;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE)
|
||||
static int m41t80_rtc_proc(struct device *dev, struct seq_file *seq)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
|
@ -206,9 +217,6 @@ static int m41t80_rtc_proc(struct device *dev, struct seq_file *seq)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define m41t80_rtc_proc NULL
|
||||
#endif
|
||||
|
||||
static int m41t80_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
|
@ -220,19 +228,117 @@ static int m41t80_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
|||
return m41t80_set_datetime(to_i2c_client(dev), tm);
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX - m41t80 alarm functionality is reported broken.
|
||||
* until it is fixed, don't register alarm functions.
|
||||
*/
|
||||
static int m41t80_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
int flags, retval;
|
||||
|
||||
flags = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
|
||||
if (flags < 0)
|
||||
return flags;
|
||||
|
||||
if (enabled)
|
||||
flags |= M41T80_ALMON_AFE;
|
||||
else
|
||||
flags &= ~M41T80_ALMON_AFE;
|
||||
|
||||
retval = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, flags);
|
||||
if (retval < 0) {
|
||||
dev_info(dev, "Unable to enable alarm IRQ %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int m41t80_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
u8 alarmvals[5];
|
||||
int ret, err;
|
||||
|
||||
alarmvals[0] = bin2bcd(alrm->time.tm_mon + 1);
|
||||
alarmvals[1] = bin2bcd(alrm->time.tm_mday);
|
||||
alarmvals[2] = bin2bcd(alrm->time.tm_hour);
|
||||
alarmvals[3] = bin2bcd(alrm->time.tm_min);
|
||||
alarmvals[4] = bin2bcd(alrm->time.tm_sec);
|
||||
|
||||
/* Clear AF and AFE flags */
|
||||
ret = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
err = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
|
||||
ret & ~(M41T80_ALMON_AFE));
|
||||
if (err < 0) {
|
||||
dev_err(dev, "Unable to clear AFE bit\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
ret = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
err = i2c_smbus_write_byte_data(client, M41T80_REG_FLAGS,
|
||||
ret & ~(M41T80_FLAGS_AF));
|
||||
if (err < 0) {
|
||||
dev_err(dev, "Unable to clear AF bit\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Write the alarm */
|
||||
err = i2c_smbus_write_i2c_block_data(client, M41T80_REG_ALARM_MON,
|
||||
5, alarmvals);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Enable the alarm interrupt */
|
||||
if (alrm->enabled) {
|
||||
alarmvals[0] |= M41T80_ALMON_AFE;
|
||||
err = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
|
||||
alarmvals[0]);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int m41t80_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
u8 alarmvals[5];
|
||||
int flags, ret;
|
||||
|
||||
ret = i2c_smbus_read_i2c_block_data(client, M41T80_REG_ALARM_MON,
|
||||
5, alarmvals);
|
||||
if (ret != 5)
|
||||
return ret < 0 ? ret : -EIO;
|
||||
|
||||
flags = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
|
||||
if (flags < 0)
|
||||
return flags;
|
||||
|
||||
alrm->time.tm_sec = bcd2bin(alarmvals[4] & 0x7f);
|
||||
alrm->time.tm_min = bcd2bin(alarmvals[3] & 0x7f);
|
||||
alrm->time.tm_hour = bcd2bin(alarmvals[2] & 0x3f);
|
||||
alrm->time.tm_wday = -1;
|
||||
alrm->time.tm_mday = bcd2bin(alarmvals[1] & 0x3f);
|
||||
alrm->time.tm_mon = bcd2bin(alarmvals[0] & 0x3f);
|
||||
alrm->time.tm_year = -1;
|
||||
|
||||
alrm->enabled = !!(alarmvals[0] & M41T80_ALMON_AFE);
|
||||
alrm->pending = (flags & M41T80_FLAGS_AF) && alrm->enabled;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct rtc_class_ops m41t80_rtc_ops = {
|
||||
.read_time = m41t80_rtc_read_time,
|
||||
.set_time = m41t80_rtc_set_time,
|
||||
.proc = m41t80_rtc_proc,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_RTC_INTF_SYSFS) || defined(CONFIG_RTC_INTF_SYSFS_MODULE)
|
||||
static ssize_t m41t80_sysfs_show_flags(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
static ssize_t flags_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
int val;
|
||||
|
@ -242,10 +348,10 @@ static ssize_t m41t80_sysfs_show_flags(struct device *dev,
|
|||
return val;
|
||||
return sprintf(buf, "%#x\n", val);
|
||||
}
|
||||
static DEVICE_ATTR(flags, S_IRUGO, m41t80_sysfs_show_flags, NULL);
|
||||
static DEVICE_ATTR_RO(flags);
|
||||
|
||||
static ssize_t m41t80_sysfs_show_sqwfreq(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
static ssize_t sqwfreq_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct m41t80_data *clientdata = i2c_get_clientdata(client);
|
||||
|
@ -272,14 +378,19 @@ static ssize_t m41t80_sysfs_show_sqwfreq(struct device *dev,
|
|||
}
|
||||
return sprintf(buf, "%d\n", val);
|
||||
}
|
||||
static ssize_t m41t80_sysfs_set_sqwfreq(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
|
||||
static ssize_t sqwfreq_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct m41t80_data *clientdata = i2c_get_clientdata(client);
|
||||
int almon, sqw, reg_sqw, rc;
|
||||
int val = simple_strtoul(buf, NULL, 0);
|
||||
unsigned long val;
|
||||
|
||||
rc = kstrtoul(buf, 0, &val);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
if (!(clientdata->features & M41T80_FEATURE_SQ))
|
||||
return -EINVAL;
|
||||
|
@ -308,7 +419,7 @@ static ssize_t m41t80_sysfs_set_sqwfreq(struct device *dev,
|
|||
sqw = (sqw & 0x0f) | (val << 4);
|
||||
|
||||
rc = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
|
||||
almon & ~M41T80_ALMON_SQWE);
|
||||
almon & ~M41T80_ALMON_SQWE);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
|
@ -318,35 +429,24 @@ static ssize_t m41t80_sysfs_set_sqwfreq(struct device *dev,
|
|||
return rc;
|
||||
|
||||
rc = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
|
||||
almon | M41T80_ALMON_SQWE);
|
||||
if (rc <0)
|
||||
almon | M41T80_ALMON_SQWE);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR(sqwfreq, S_IRUGO | S_IWUSR,
|
||||
m41t80_sysfs_show_sqwfreq, m41t80_sysfs_set_sqwfreq);
|
||||
static DEVICE_ATTR_RW(sqwfreq);
|
||||
|
||||
static struct attribute *attrs[] = {
|
||||
&dev_attr_flags.attr,
|
||||
&dev_attr_sqwfreq.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group attr_group = {
|
||||
.attrs = attrs,
|
||||
};
|
||||
|
||||
static int m41t80_sysfs_register(struct device *dev)
|
||||
{
|
||||
return sysfs_create_group(&dev->kobj, &attr_group);
|
||||
}
|
||||
#else
|
||||
static int m41t80_sysfs_register(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_RTC_DRV_M41T80_WDT
|
||||
/*
|
||||
*****************************************************************************
|
||||
|
@ -394,7 +494,7 @@ static void wdt_ping(void)
|
|||
/*
|
||||
* WDS = 1 (0x80), mulitplier = WD_TIMO, resolution = 1s (0x02)
|
||||
*/
|
||||
i2c_data[1] = wdt_margin<<2 | 0x82;
|
||||
i2c_data[1] = wdt_margin << 2 | 0x82;
|
||||
|
||||
/*
|
||||
* M41T65 has three bits for watchdog resolution. Don't set bit 7, as
|
||||
|
@ -636,49 +736,76 @@ static struct notifier_block wdt_notifier = {
|
|||
*
|
||||
*****************************************************************************
|
||||
*/
|
||||
|
||||
static void m41t80_remove_sysfs_group(void *_dev)
|
||||
{
|
||||
struct device *dev = _dev;
|
||||
|
||||
sysfs_remove_group(&dev->kobj, &attr_group);
|
||||
}
|
||||
|
||||
static int m41t80_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
|
||||
int rc = 0;
|
||||
struct rtc_device *rtc = NULL;
|
||||
struct rtc_time tm;
|
||||
struct m41t80_data *clientdata = NULL;
|
||||
struct m41t80_data *m41t80_data = NULL;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C
|
||||
| I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK |
|
||||
I2C_FUNC_SMBUS_BYTE_DATA)) {
|
||||
dev_err(&adapter->dev, "doesn't support I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_I2C_BLOCK\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
clientdata = devm_kzalloc(&client->dev, sizeof(*clientdata),
|
||||
GFP_KERNEL);
|
||||
if (!clientdata)
|
||||
m41t80_data = devm_kzalloc(&client->dev, sizeof(*m41t80_data),
|
||||
GFP_KERNEL);
|
||||
if (!m41t80_data)
|
||||
return -ENOMEM;
|
||||
|
||||
clientdata->features = id->driver_data;
|
||||
i2c_set_clientdata(client, clientdata);
|
||||
m41t80_data->features = id->driver_data;
|
||||
i2c_set_clientdata(client, m41t80_data);
|
||||
|
||||
if (client->irq > 0) {
|
||||
rc = devm_request_threaded_irq(&client->dev, client->irq,
|
||||
NULL, m41t80_handle_irq,
|
||||
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
|
||||
"m41t80", client);
|
||||
if (rc) {
|
||||
dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n");
|
||||
client->irq = 0;
|
||||
} else {
|
||||
m41t80_rtc_ops.read_alarm = m41t80_read_alarm;
|
||||
m41t80_rtc_ops.set_alarm = m41t80_set_alarm;
|
||||
m41t80_rtc_ops.alarm_irq_enable = m41t80_alarm_irq_enable;
|
||||
/* Enable the wakealarm */
|
||||
device_init_wakeup(&client->dev, true);
|
||||
}
|
||||
}
|
||||
|
||||
rtc = devm_rtc_device_register(&client->dev, client->name,
|
||||
&m41t80_rtc_ops, THIS_MODULE);
|
||||
&m41t80_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(rtc))
|
||||
return PTR_ERR(rtc);
|
||||
|
||||
clientdata->rtc = rtc;
|
||||
m41t80_data->rtc = rtc;
|
||||
|
||||
/* Make sure HT (Halt Update) bit is cleared */
|
||||
rc = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_HOUR);
|
||||
|
||||
if (rc >= 0 && rc & M41T80_ALHOUR_HT) {
|
||||
if (clientdata->features & M41T80_FEATURE_HT) {
|
||||
if (m41t80_data->features & M41T80_FEATURE_HT) {
|
||||
m41t80_get_datetime(client, &tm);
|
||||
dev_info(&client->dev, "HT bit was set!\n");
|
||||
dev_info(&client->dev,
|
||||
"Power Down at "
|
||||
"%04i-%02i-%02i %02i:%02i:%02i\n",
|
||||
"Power Down at %04i-%02i-%02i %02i:%02i:%02i\n",
|
||||
tm.tm_year + 1900,
|
||||
tm.tm_mon + 1, tm.tm_mday, tm.tm_hour,
|
||||
tm.tm_min, tm.tm_sec);
|
||||
}
|
||||
rc = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_HOUR,
|
||||
rc & ~M41T80_ALHOUR_HT);
|
||||
rc & ~M41T80_ALHOUR_HT);
|
||||
}
|
||||
|
||||
if (rc < 0) {
|
||||
|
@ -691,18 +818,30 @@ static int m41t80_probe(struct i2c_client *client,
|
|||
|
||||
if (rc >= 0 && rc & M41T80_SEC_ST)
|
||||
rc = i2c_smbus_write_byte_data(client, M41T80_REG_SEC,
|
||||
rc & ~M41T80_SEC_ST);
|
||||
rc & ~M41T80_SEC_ST);
|
||||
if (rc < 0) {
|
||||
dev_err(&client->dev, "Can't clear ST bit\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = m41t80_sysfs_register(&client->dev);
|
||||
if (rc)
|
||||
/* Export sysfs entries */
|
||||
rc = sysfs_create_group(&(&client->dev)->kobj, &attr_group);
|
||||
if (rc) {
|
||||
dev_err(&client->dev, "Failed to create sysfs group: %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = devm_add_action(&client->dev, m41t80_remove_sysfs_group,
|
||||
&client->dev);
|
||||
if (rc) {
|
||||
m41t80_remove_sysfs_group(&client->dev);
|
||||
dev_err(&client->dev,
|
||||
"Failed to add sysfs cleanup action: %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_RTC_DRV_M41T80_WDT
|
||||
if (clientdata->features & M41T80_FEATURE_HT) {
|
||||
if (m41t80_data->features & M41T80_FEATURE_HT) {
|
||||
save_client = client;
|
||||
rc = misc_register(&wdt_dev);
|
||||
if (rc)
|
||||
|
|
|
@ -22,8 +22,6 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#define DRV_VERSION "1.0"
|
||||
|
||||
struct m48t35_rtc {
|
||||
u8 pad[0x7ff8]; /* starts at 0x7ff8 */
|
||||
u8 control;
|
||||
|
@ -190,5 +188,4 @@ module_platform_driver(m48t35_platform_driver);
|
|||
MODULE_AUTHOR("Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
|
||||
MODULE_DESCRIPTION("M48T35 RTC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
MODULE_ALIAS("platform:rtc-m48t35");
|
||||
|
|
|
@ -39,9 +39,6 @@
|
|||
#define M48T86_REG_B_SET (1 << 7)
|
||||
#define M48T86_REG_D_VRT (1 << 7)
|
||||
|
||||
#define DRV_VERSION "0.1"
|
||||
|
||||
|
||||
static int m48t86_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
unsigned char reg;
|
||||
|
@ -178,5 +175,4 @@ module_platform_driver(m48t86_rtc_platform_driver);
|
|||
MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
|
||||
MODULE_DESCRIPTION("M48T86 RTC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
MODULE_ALIAS("platform:rtc-m48t86");
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
#include <linux/rtc.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#define DRV_VERSION "0.2"
|
||||
|
||||
/*
|
||||
* register indices
|
||||
*/
|
||||
|
@ -218,8 +216,6 @@ max6900_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
|
||||
return -ENODEV;
|
||||
|
||||
dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
|
||||
|
||||
rtc = devm_rtc_device_register(&client->dev, max6900_driver.driver.name,
|
||||
&max6900_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(rtc))
|
||||
|
@ -249,4 +245,3 @@ module_i2c_driver(max6900_driver);
|
|||
MODULE_DESCRIPTION("Maxim MAX6900 RTC driver");
|
||||
MODULE_AUTHOR("Dale Farnsworth <dale@farnsworth.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
|
|
|
@ -250,18 +250,6 @@ static irqreturn_t mc13xxx_rtc_alarm_handler(int irq, void *dev)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t mc13xxx_rtc_update_handler(int irq, void *dev)
|
||||
{
|
||||
struct mc13xxx_rtc *priv = dev;
|
||||
struct mc13xxx *mc13xxx = priv->mc13xxx;
|
||||
|
||||
rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_UF);
|
||||
|
||||
mc13xxx_irq_ack(mc13xxx, irq);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops mc13xxx_rtc_ops = {
|
||||
.read_time = mc13xxx_rtc_read_time,
|
||||
.set_mmss64 = mc13xxx_rtc_set_mmss,
|
||||
|
@ -307,11 +295,6 @@ static int __init mc13xxx_rtc_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto err_irq_request;
|
||||
|
||||
ret = mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_1HZ,
|
||||
mc13xxx_rtc_update_handler, DRIVER_NAME, priv);
|
||||
if (ret)
|
||||
goto err_irq_request;
|
||||
|
||||
ret = mc13xxx_irq_request_nounmask(mc13xxx, MC13XXX_IRQ_TODA,
|
||||
mc13xxx_rtc_alarm_handler, DRIVER_NAME, priv);
|
||||
if (ret)
|
||||
|
@ -326,7 +309,6 @@ static int __init mc13xxx_rtc_probe(struct platform_device *pdev)
|
|||
|
||||
err_irq_request:
|
||||
mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_TODA, priv);
|
||||
mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_1HZ, priv);
|
||||
mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_RTCRST, priv);
|
||||
|
||||
mc13xxx_unlock(mc13xxx);
|
||||
|
@ -341,7 +323,6 @@ static int mc13xxx_rtc_remove(struct platform_device *pdev)
|
|||
mc13xxx_lock(priv->mc13xxx);
|
||||
|
||||
mc13xxx_irq_free(priv->mc13xxx, MC13XXX_IRQ_TODA, priv);
|
||||
mc13xxx_irq_free(priv->mc13xxx, MC13XXX_IRQ_1HZ, priv);
|
||||
mc13xxx_irq_free(priv->mc13xxx, MC13XXX_IRQ_RTCRST, priv);
|
||||
|
||||
mc13xxx_unlock(priv->mc13xxx);
|
||||
|
|
|
@ -266,7 +266,7 @@ static int mrst_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
|||
}
|
||||
|
||||
|
||||
#if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE)
|
||||
#if IS_ENABLED(CONFIG_RTC_INTF_PROC)
|
||||
|
||||
static int mrst_procfs(struct device *dev, struct seq_file *seq)
|
||||
{
|
||||
|
|
|
@ -240,9 +240,6 @@ static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
|
|||
mxc_rtc_irq_enable(&pdev->dev, RTC_ALM_BIT, 0);
|
||||
}
|
||||
|
||||
if (status & RTC_1HZ_BIT)
|
||||
events |= (RTC_UF | RTC_IRQF);
|
||||
|
||||
if (status & PIT_ALL_ON)
|
||||
events |= (RTC_PF | RTC_IRQF);
|
||||
|
||||
|
|
|
@ -46,8 +46,6 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
#define DRV_VERSION "0.6"
|
||||
|
||||
/* REGISTERS */
|
||||
#define PCF2123_REG_CTRL1 (0x00) /* Control Register 1 */
|
||||
#define PCF2123_REG_CTRL2 (0x01) /* Control Register 2 */
|
||||
|
@ -395,7 +393,6 @@ static int pcf2123_probe(struct spi_device *spi)
|
|||
}
|
||||
}
|
||||
|
||||
dev_info(&spi->dev, "chip found, driver version " DRV_VERSION "\n");
|
||||
dev_info(&spi->dev, "spiclk %u KHz.\n",
|
||||
(spi->max_speed_hz + 500) / 1000);
|
||||
|
||||
|
@ -474,4 +471,3 @@ module_spi_driver(pcf2123_driver);
|
|||
MODULE_AUTHOR("Chris Verges <chrisv@cyberswitching.com>");
|
||||
MODULE_DESCRIPTION("NXP PCF2123 RTC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
|
|
|
@ -23,8 +23,6 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#define DRV_VERSION "0.4.4"
|
||||
|
||||
#define PCF8563_REG_ST1 0x00 /* status */
|
||||
#define PCF8563_REG_ST2 0x01
|
||||
#define PCF8563_BIT_AIE (1 << 1)
|
||||
|
@ -535,7 +533,7 @@ static struct clk *pcf8563_clkout_register_clk(struct pcf8563 *pcf8563)
|
|||
|
||||
init.name = "pcf8563-clkout";
|
||||
init.ops = &pcf8563_clkout_ops;
|
||||
init.flags = CLK_IS_ROOT;
|
||||
init.flags = 0;
|
||||
init.parent_names = NULL;
|
||||
init.num_parents = 0;
|
||||
pcf8563->clkout_hw.init = &init;
|
||||
|
@ -580,8 +578,6 @@ static int pcf8563_probe(struct i2c_client *client,
|
|||
if (!pcf8563)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
|
||||
|
||||
i2c_set_clientdata(client, pcf8563);
|
||||
pcf8563->client = client;
|
||||
device_set_wakeup_capable(&client->dev, 1);
|
||||
|
@ -662,4 +658,3 @@ module_i2c_driver(pcf8563_driver);
|
|||
MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
|
||||
MODULE_DESCRIPTION("Philips PCF8563/Epson RTC8564 RTC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
|
|
|
@ -50,7 +50,6 @@
|
|||
#include <linux/io.h>
|
||||
|
||||
#define DRV_NAME "rs5c313"
|
||||
#define DRV_VERSION "1.13"
|
||||
|
||||
#ifdef CONFIG_SH_LANDISK
|
||||
/*****************************************************/
|
||||
|
@ -407,7 +406,6 @@ static void __exit rs5c313_rtc_exit(void)
|
|||
module_init(rs5c313_rtc_init);
|
||||
module_exit(rs5c313_rtc_exit);
|
||||
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
MODULE_AUTHOR("kogiidena , Nobuhiro Iwamatsu <iwamatsu@nigauri.org>");
|
||||
MODULE_DESCRIPTION("Ricoh RS5C313 RTC device driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -25,8 +25,6 @@
|
|||
#include <linux/spi/spi.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#define DRV_VERSION "0.2"
|
||||
|
||||
#define RS5C348_REG_SECS 0
|
||||
#define RS5C348_REG_MINS 1
|
||||
#define RS5C348_REG_HOURS 2
|
||||
|
@ -171,7 +169,6 @@ static int rs5c348_probe(struct spi_device *spi)
|
|||
goto kfree_exit;
|
||||
}
|
||||
|
||||
dev_info(&spi->dev, "chip found, driver version " DRV_VERSION "\n");
|
||||
dev_info(&spi->dev, "spiclk %u KHz.\n",
|
||||
(spi->max_speed_hz + 500) / 1000);
|
||||
|
||||
|
@ -230,5 +227,4 @@ module_spi_driver(rs5c348_driver);
|
|||
MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
|
||||
MODULE_DESCRIPTION("Ricoh RS5C348 RTC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
MODULE_ALIAS("spi:rtc-rs5c348");
|
||||
|
|
|
@ -16,9 +16,6 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#define DRV_VERSION "0.6"
|
||||
|
||||
|
||||
/*
|
||||
* Ricoh has a family of I2C based RTCs, which differ only slightly from
|
||||
* each other. Differences center on pinout (e.g. how many interrupts,
|
||||
|
@ -240,11 +237,11 @@ static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE)
|
||||
#if IS_ENABLED(CONFIG_RTC_INTF_PROC)
|
||||
#define NEED_TRIM
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_RTC_INTF_SYSFS) || defined(CONFIG_RTC_INTF_SYSFS_MODULE)
|
||||
#if IS_ENABLED(CONFIG_RTC_INTF_SYSFS)
|
||||
#define NEED_TRIM
|
||||
#endif
|
||||
|
||||
|
@ -412,7 +409,7 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE)
|
||||
#if IS_ENABLED(CONFIG_RTC_INTF_PROC)
|
||||
|
||||
static int rs5c372_rtc_proc(struct device *dev, struct seq_file *seq)
|
||||
{
|
||||
|
@ -441,7 +438,7 @@ static const struct rtc_class_ops rs5c372_rtc_ops = {
|
|||
.alarm_irq_enable = rs5c_rtc_alarm_irq_enable,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_RTC_INTF_SYSFS) || defined(CONFIG_RTC_INTF_SYSFS_MODULE)
|
||||
#if IS_ENABLED(CONFIG_RTC_INTF_SYSFS)
|
||||
|
||||
static ssize_t rs5c372_sysfs_show_trim(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
|
@ -509,9 +506,9 @@ static int rs5c_oscillator_setup(struct rs5c372 *rs5c372)
|
|||
int addr, i, ret = 0;
|
||||
|
||||
if (rs5c372->type == rtc_r2025sd) {
|
||||
if (!(rs5c372->regs[RS5C_REG_CTRL2] & R2025_CTRL2_XST))
|
||||
if (rs5c372->regs[RS5C_REG_CTRL2] & R2025_CTRL2_XST)
|
||||
return ret;
|
||||
rs5c372->regs[RS5C_REG_CTRL2] &= ~R2025_CTRL2_XST;
|
||||
rs5c372->regs[RS5C_REG_CTRL2] |= R2025_CTRL2_XST;
|
||||
} else {
|
||||
if (!(rs5c372->regs[RS5C_REG_CTRL2] & RS5C_CTRL2_XSTP))
|
||||
return ret;
|
||||
|
@ -640,7 +637,7 @@ static int rs5c372_probe(struct i2c_client *client,
|
|||
if (rs5c372_get_datetime(client, &tm) < 0)
|
||||
dev_warn(&client->dev, "clock needs to be set\n");
|
||||
|
||||
dev_info(&client->dev, "%s found, %s, driver version " DRV_VERSION "\n",
|
||||
dev_info(&client->dev, "%s found, %s\n",
|
||||
({ char *s; switch (rs5c372->type) {
|
||||
case rtc_r2025sd: s = "r2025sd"; break;
|
||||
case rtc_r2221tl: s = "r2221tl"; break;
|
||||
|
@ -696,4 +693,3 @@ MODULE_AUTHOR(
|
|||
"Paul Mundt <lethal@linux-sh.org>");
|
||||
MODULE_DESCRIPTION("Ricoh RS5C372 RTC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Micro Crystal RV-3029 rtc class driver
|
||||
* Micro Crystal RV-3029 / RV-3049 rtc class driver
|
||||
*
|
||||
* Author: Gregory Hermant <gregory.hermant@calao-systems.com>
|
||||
* Michael Buesch <m@bues.ch>
|
||||
|
@ -14,13 +14,14 @@
|
|||
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
|
||||
#include <linux/regmap.h>
|
||||
|
||||
/* Register map */
|
||||
/* control section */
|
||||
|
@ -75,6 +76,7 @@
|
|||
#define RV3029_A_DW 0x14
|
||||
#define RV3029_A_MO 0x15
|
||||
#define RV3029_A_YR 0x16
|
||||
#define RV3029_A_AE_X BIT(7)
|
||||
#define RV3029_ALARM_SECTION_LEN 0x07
|
||||
|
||||
/* timer section */
|
||||
|
@ -116,85 +118,84 @@
|
|||
#define RV3029_USR2_RAM_PAGE 0x3C
|
||||
#define RV3029_USR2_SECTION_LEN 0x04
|
||||
|
||||
static int
|
||||
rv3029_i2c_read_regs(struct i2c_client *client, u8 reg, u8 *buf,
|
||||
unsigned len)
|
||||
struct rv3029_data {
|
||||
struct device *dev;
|
||||
struct rtc_device *rtc;
|
||||
struct regmap *regmap;
|
||||
int irq;
|
||||
};
|
||||
|
||||
static int rv3029_read_regs(struct device *dev, u8 reg, u8 *buf,
|
||||
unsigned int len)
|
||||
{
|
||||
int ret;
|
||||
struct rv3029_data *rv3029 = dev_get_drvdata(dev);
|
||||
|
||||
if ((reg > RV3029_USR1_RAM_PAGE + 7) ||
|
||||
(reg + len > RV3029_USR1_RAM_PAGE + 8))
|
||||
(reg + len > RV3029_USR1_RAM_PAGE + 8))
|
||||
return -EINVAL;
|
||||
|
||||
ret = i2c_smbus_read_i2c_block_data(client, reg, len, buf);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret < len)
|
||||
return -EIO;
|
||||
return 0;
|
||||
return regmap_bulk_read(rv3029->regmap, reg, buf, len);
|
||||
}
|
||||
|
||||
static int
|
||||
rv3029_i2c_write_regs(struct i2c_client *client, u8 reg, u8 const buf[],
|
||||
unsigned len)
|
||||
static int rv3029_write_regs(struct device *dev, u8 reg, u8 const buf[],
|
||||
unsigned int len)
|
||||
{
|
||||
struct rv3029_data *rv3029 = dev_get_drvdata(dev);
|
||||
|
||||
if ((reg > RV3029_USR1_RAM_PAGE + 7) ||
|
||||
(reg + len > RV3029_USR1_RAM_PAGE + 8))
|
||||
(reg + len > RV3029_USR1_RAM_PAGE + 8))
|
||||
return -EINVAL;
|
||||
|
||||
return i2c_smbus_write_i2c_block_data(client, reg, len, buf);
|
||||
return regmap_bulk_write(rv3029->regmap, reg, buf, len);
|
||||
}
|
||||
|
||||
static int
|
||||
rv3029_i2c_update_bits(struct i2c_client *client, u8 reg, u8 mask, u8 set)
|
||||
static int rv3029_update_bits(struct device *dev, u8 reg, u8 mask, u8 set)
|
||||
{
|
||||
u8 buf;
|
||||
int ret;
|
||||
|
||||
ret = rv3029_i2c_read_regs(client, reg, &buf, 1);
|
||||
ret = rv3029_read_regs(dev, reg, &buf, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
buf &= ~mask;
|
||||
buf |= set & mask;
|
||||
ret = rv3029_i2c_write_regs(client, reg, &buf, 1);
|
||||
ret = rv3029_write_regs(dev, reg, &buf, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rv3029_i2c_get_sr(struct i2c_client *client, u8 *buf)
|
||||
static int rv3029_get_sr(struct device *dev, u8 *buf)
|
||||
{
|
||||
int ret = rv3029_i2c_read_regs(client, RV3029_STATUS, buf, 1);
|
||||
int ret = rv3029_read_regs(dev, RV3029_STATUS, buf, 1);
|
||||
|
||||
if (ret < 0)
|
||||
return -EIO;
|
||||
dev_dbg(&client->dev, "status = 0x%.2x (%d)\n", buf[0], buf[0]);
|
||||
dev_dbg(dev, "status = 0x%.2x (%d)\n", buf[0], buf[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rv3029_i2c_set_sr(struct i2c_client *client, u8 val)
|
||||
static int rv3029_set_sr(struct device *dev, u8 val)
|
||||
{
|
||||
u8 buf[1];
|
||||
int sr;
|
||||
|
||||
buf[0] = val;
|
||||
sr = rv3029_i2c_write_regs(client, RV3029_STATUS, buf, 1);
|
||||
dev_dbg(&client->dev, "status = 0x%.2x (%d)\n", buf[0], buf[0]);
|
||||
sr = rv3029_write_regs(dev, RV3029_STATUS, buf, 1);
|
||||
dev_dbg(dev, "status = 0x%.2x (%d)\n", buf[0], buf[0]);
|
||||
if (sr < 0)
|
||||
return -EIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rv3029_eeprom_busywait(struct i2c_client *client)
|
||||
static int rv3029_eeprom_busywait(struct device *dev)
|
||||
{
|
||||
int i, ret;
|
||||
u8 sr;
|
||||
|
||||
for (i = 100; i > 0; i--) {
|
||||
ret = rv3029_i2c_get_sr(client, &sr);
|
||||
ret = rv3029_get_sr(dev, &sr);
|
||||
if (ret < 0)
|
||||
break;
|
||||
if (!(sr & RV3029_STATUS_EEBUSY))
|
||||
|
@ -202,28 +203,28 @@ static int rv3029_eeprom_busywait(struct i2c_client *client)
|
|||
usleep_range(1000, 10000);
|
||||
}
|
||||
if (i <= 0) {
|
||||
dev_err(&client->dev, "EEPROM busy wait timeout.\n");
|
||||
dev_err(dev, "EEPROM busy wait timeout.\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rv3029_eeprom_exit(struct i2c_client *client)
|
||||
static int rv3029_eeprom_exit(struct device *dev)
|
||||
{
|
||||
/* Re-enable eeprom refresh */
|
||||
return rv3029_i2c_update_bits(client, RV3029_ONOFF_CTRL,
|
||||
RV3029_ONOFF_CTRL_EERE,
|
||||
RV3029_ONOFF_CTRL_EERE);
|
||||
return rv3029_update_bits(dev, RV3029_ONOFF_CTRL,
|
||||
RV3029_ONOFF_CTRL_EERE,
|
||||
RV3029_ONOFF_CTRL_EERE);
|
||||
}
|
||||
|
||||
static int rv3029_eeprom_enter(struct i2c_client *client)
|
||||
static int rv3029_eeprom_enter(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
u8 sr;
|
||||
|
||||
/* Check whether we are in the allowed voltage range. */
|
||||
ret = rv3029_i2c_get_sr(client, &sr);
|
||||
ret = rv3029_get_sr(dev, &sr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (sr & (RV3029_STATUS_VLOW1 | RV3029_STATUS_VLOW2)) {
|
||||
|
@ -232,129 +233,168 @@ static int rv3029_eeprom_enter(struct i2c_client *client)
|
|||
*/
|
||||
sr &= ~RV3029_STATUS_VLOW1;
|
||||
sr &= ~RV3029_STATUS_VLOW2;
|
||||
ret = rv3029_i2c_set_sr(client, sr);
|
||||
ret = rv3029_set_sr(dev, sr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
usleep_range(1000, 10000);
|
||||
ret = rv3029_i2c_get_sr(client, &sr);
|
||||
ret = rv3029_get_sr(dev, &sr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (sr & (RV3029_STATUS_VLOW1 | RV3029_STATUS_VLOW2)) {
|
||||
dev_err(&client->dev,
|
||||
dev_err(dev,
|
||||
"Supply voltage is too low to safely access the EEPROM.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
/* Disable eeprom refresh. */
|
||||
ret = rv3029_i2c_update_bits(client, RV3029_ONOFF_CTRL,
|
||||
RV3029_ONOFF_CTRL_EERE, 0);
|
||||
ret = rv3029_update_bits(dev, RV3029_ONOFF_CTRL, RV3029_ONOFF_CTRL_EERE,
|
||||
0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Wait for any previous eeprom accesses to finish. */
|
||||
ret = rv3029_eeprom_busywait(client);
|
||||
ret = rv3029_eeprom_busywait(dev);
|
||||
if (ret < 0)
|
||||
rv3029_eeprom_exit(client);
|
||||
rv3029_eeprom_exit(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rv3029_eeprom_read(struct i2c_client *client, u8 reg,
|
||||
static int rv3029_eeprom_read(struct device *dev, u8 reg,
|
||||
u8 buf[], size_t len)
|
||||
{
|
||||
int ret, err;
|
||||
|
||||
err = rv3029_eeprom_enter(client);
|
||||
err = rv3029_eeprom_enter(dev);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
ret = rv3029_i2c_read_regs(client, reg, buf, len);
|
||||
ret = rv3029_read_regs(dev, reg, buf, len);
|
||||
|
||||
err = rv3029_eeprom_exit(client);
|
||||
err = rv3029_eeprom_exit(dev);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rv3029_eeprom_write(struct i2c_client *client, u8 reg,
|
||||
static int rv3029_eeprom_write(struct device *dev, u8 reg,
|
||||
u8 const buf[], size_t len)
|
||||
{
|
||||
int ret, err;
|
||||
size_t i;
|
||||
u8 tmp;
|
||||
|
||||
err = rv3029_eeprom_enter(client);
|
||||
err = rv3029_eeprom_enter(dev);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
for (i = 0; i < len; i++, reg++) {
|
||||
ret = rv3029_i2c_read_regs(client, reg, &tmp, 1);
|
||||
ret = rv3029_read_regs(dev, reg, &tmp, 1);
|
||||
if (ret < 0)
|
||||
break;
|
||||
if (tmp != buf[i]) {
|
||||
ret = rv3029_i2c_write_regs(client, reg, &buf[i], 1);
|
||||
ret = rv3029_write_regs(dev, reg, &buf[i], 1);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
ret = rv3029_eeprom_busywait(client);
|
||||
ret = rv3029_eeprom_busywait(dev);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
err = rv3029_eeprom_exit(client);
|
||||
err = rv3029_eeprom_exit(dev);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rv3029_eeprom_update_bits(struct i2c_client *client,
|
||||
static int rv3029_eeprom_update_bits(struct device *dev,
|
||||
u8 reg, u8 mask, u8 set)
|
||||
{
|
||||
u8 buf;
|
||||
int ret;
|
||||
|
||||
ret = rv3029_eeprom_read(client, reg, &buf, 1);
|
||||
ret = rv3029_eeprom_read(dev, reg, &buf, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
buf &= ~mask;
|
||||
buf |= set & mask;
|
||||
ret = rv3029_eeprom_write(client, reg, &buf, 1);
|
||||
ret = rv3029_eeprom_write(dev, reg, &buf, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rv3029_i2c_read_time(struct i2c_client *client, struct rtc_time *tm)
|
||||
static irqreturn_t rv3029_handle_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct device *dev = dev_id;
|
||||
struct rv3029_data *rv3029 = dev_get_drvdata(dev);
|
||||
struct mutex *lock = &rv3029->rtc->ops_lock;
|
||||
unsigned long events = 0;
|
||||
u8 flags, controls;
|
||||
int ret;
|
||||
|
||||
mutex_lock(lock);
|
||||
|
||||
ret = rv3029_read_regs(dev, RV3029_IRQ_CTRL, &controls, 1);
|
||||
if (ret) {
|
||||
dev_warn(dev, "Read IRQ Control Register error %d\n", ret);
|
||||
mutex_unlock(lock);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
ret = rv3029_read_regs(dev, RV3029_IRQ_FLAGS, &flags, 1);
|
||||
if (ret) {
|
||||
dev_warn(dev, "Read IRQ Flags Register error %d\n", ret);
|
||||
mutex_unlock(lock);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
if (flags & RV3029_IRQ_FLAGS_AF) {
|
||||
flags &= ~RV3029_IRQ_FLAGS_AF;
|
||||
controls &= ~RV3029_IRQ_CTRL_AIE;
|
||||
events |= RTC_AF;
|
||||
}
|
||||
|
||||
if (events) {
|
||||
rtc_update_irq(rv3029->rtc, 1, events);
|
||||
rv3029_write_regs(dev, RV3029_IRQ_FLAGS, &flags, 1);
|
||||
rv3029_write_regs(dev, RV3029_IRQ_CTRL, &controls, 1);
|
||||
}
|
||||
mutex_unlock(lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int rv3029_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
u8 buf[1];
|
||||
int ret;
|
||||
u8 regs[RV3029_WATCH_SECTION_LEN] = { 0, };
|
||||
|
||||
ret = rv3029_i2c_get_sr(client, buf);
|
||||
ret = rv3029_get_sr(dev, buf);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "%s: reading SR failed\n", __func__);
|
||||
dev_err(dev, "%s: reading SR failed\n", __func__);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ret = rv3029_i2c_read_regs(client, RV3029_W_SEC, regs,
|
||||
RV3029_WATCH_SECTION_LEN);
|
||||
ret = rv3029_read_regs(dev, RV3029_W_SEC, regs,
|
||||
RV3029_WATCH_SECTION_LEN);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "%s: reading RTC section failed\n",
|
||||
__func__);
|
||||
dev_err(dev, "%s: reading RTC section failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
tm->tm_sec = bcd2bin(regs[RV3029_W_SEC-RV3029_W_SEC]);
|
||||
tm->tm_min = bcd2bin(regs[RV3029_W_MINUTES-RV3029_W_SEC]);
|
||||
tm->tm_sec = bcd2bin(regs[RV3029_W_SEC - RV3029_W_SEC]);
|
||||
tm->tm_min = bcd2bin(regs[RV3029_W_MINUTES - RV3029_W_SEC]);
|
||||
|
||||
/* HR field has a more complex interpretation */
|
||||
{
|
||||
const u8 _hr = regs[RV3029_W_HOURS-RV3029_W_SEC];
|
||||
const u8 _hr = regs[RV3029_W_HOURS - RV3029_W_SEC];
|
||||
|
||||
if (_hr & RV3029_REG_HR_12_24) {
|
||||
/* 12h format */
|
||||
|
@ -365,77 +405,86 @@ rv3029_i2c_read_time(struct i2c_client *client, struct rtc_time *tm)
|
|||
tm->tm_hour = bcd2bin(_hr & 0x3f);
|
||||
}
|
||||
|
||||
tm->tm_mday = bcd2bin(regs[RV3029_W_DATE-RV3029_W_SEC]);
|
||||
tm->tm_mon = bcd2bin(regs[RV3029_W_MONTHS-RV3029_W_SEC]) - 1;
|
||||
tm->tm_year = bcd2bin(regs[RV3029_W_YEARS-RV3029_W_SEC]) + 100;
|
||||
tm->tm_wday = bcd2bin(regs[RV3029_W_DAYS-RV3029_W_SEC]) - 1;
|
||||
tm->tm_mday = bcd2bin(regs[RV3029_W_DATE - RV3029_W_SEC]);
|
||||
tm->tm_mon = bcd2bin(regs[RV3029_W_MONTHS - RV3029_W_SEC]) - 1;
|
||||
tm->tm_year = bcd2bin(regs[RV3029_W_YEARS - RV3029_W_SEC]) + 100;
|
||||
tm->tm_wday = bcd2bin(regs[RV3029_W_DAYS - RV3029_W_SEC]) - 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rv3029_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
return rv3029_i2c_read_time(to_i2c_client(dev), tm);
|
||||
}
|
||||
|
||||
static int
|
||||
rv3029_i2c_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm)
|
||||
static int rv3029_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
{
|
||||
struct rtc_time *const tm = &alarm->time;
|
||||
int ret;
|
||||
u8 regs[8];
|
||||
u8 regs[8], controls, flags;
|
||||
|
||||
ret = rv3029_i2c_get_sr(client, regs);
|
||||
ret = rv3029_get_sr(dev, regs);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "%s: reading SR failed\n", __func__);
|
||||
dev_err(dev, "%s: reading SR failed\n", __func__);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ret = rv3029_i2c_read_regs(client, RV3029_A_SC, regs,
|
||||
RV3029_ALARM_SECTION_LEN);
|
||||
ret = rv3029_read_regs(dev, RV3029_A_SC, regs,
|
||||
RV3029_ALARM_SECTION_LEN);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "%s: reading alarm section failed\n",
|
||||
__func__);
|
||||
dev_err(dev, "%s: reading alarm section failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
tm->tm_sec = bcd2bin(regs[RV3029_A_SC-RV3029_A_SC] & 0x7f);
|
||||
tm->tm_min = bcd2bin(regs[RV3029_A_MN-RV3029_A_SC] & 0x7f);
|
||||
tm->tm_hour = bcd2bin(regs[RV3029_A_HR-RV3029_A_SC] & 0x3f);
|
||||
tm->tm_mday = bcd2bin(regs[RV3029_A_DT-RV3029_A_SC] & 0x3f);
|
||||
tm->tm_mon = bcd2bin(regs[RV3029_A_MO-RV3029_A_SC] & 0x1f) - 1;
|
||||
tm->tm_year = bcd2bin(regs[RV3029_A_YR-RV3029_A_SC] & 0x7f) + 100;
|
||||
tm->tm_wday = bcd2bin(regs[RV3029_A_DW-RV3029_A_SC] & 0x07) - 1;
|
||||
ret = rv3029_read_regs(dev, RV3029_IRQ_CTRL, &controls, 1);
|
||||
if (ret) {
|
||||
dev_err(dev, "Read IRQ Control Register error %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = rv3029_read_regs(dev, RV3029_IRQ_FLAGS, &flags, 1);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Read IRQ Flags Register error %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
tm->tm_sec = bcd2bin(regs[RV3029_A_SC - RV3029_A_SC] & 0x7f);
|
||||
tm->tm_min = bcd2bin(regs[RV3029_A_MN - RV3029_A_SC] & 0x7f);
|
||||
tm->tm_hour = bcd2bin(regs[RV3029_A_HR - RV3029_A_SC] & 0x3f);
|
||||
tm->tm_mday = bcd2bin(regs[RV3029_A_DT - RV3029_A_SC] & 0x3f);
|
||||
tm->tm_mon = bcd2bin(regs[RV3029_A_MO - RV3029_A_SC] & 0x1f) - 1;
|
||||
tm->tm_year = bcd2bin(regs[RV3029_A_YR - RV3029_A_SC] & 0x7f) + 100;
|
||||
tm->tm_wday = bcd2bin(regs[RV3029_A_DW - RV3029_A_SC] & 0x07) - 1;
|
||||
|
||||
alarm->enabled = !!(controls & RV3029_IRQ_CTRL_AIE);
|
||||
alarm->pending = (flags & RV3029_IRQ_FLAGS_AF) && alarm->enabled;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rv3029_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
{
|
||||
return rv3029_i2c_read_alarm(to_i2c_client(dev), alarm);
|
||||
}
|
||||
|
||||
static int rv3029_rtc_i2c_alarm_set_irq(struct i2c_client *client,
|
||||
int enable)
|
||||
static int rv3029_alarm_irq_enable(struct device *dev, unsigned int enable)
|
||||
{
|
||||
int ret;
|
||||
u8 controls;
|
||||
|
||||
ret = rv3029_read_regs(dev, RV3029_IRQ_CTRL, &controls, 1);
|
||||
if (ret < 0) {
|
||||
dev_warn(dev, "Read IRQ Control Register error %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* enable/disable AIE irq */
|
||||
ret = rv3029_i2c_update_bits(client, RV3029_IRQ_CTRL,
|
||||
RV3029_IRQ_CTRL_AIE,
|
||||
(enable ? RV3029_IRQ_CTRL_AIE : 0));
|
||||
if (enable)
|
||||
controls |= RV3029_IRQ_CTRL_AIE;
|
||||
else
|
||||
controls &= ~RV3029_IRQ_CTRL_AIE;
|
||||
|
||||
ret = rv3029_write_regs(dev, RV3029_IRQ_CTRL, &controls, 1);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "can't update INT reg\n");
|
||||
dev_err(dev, "can't update INT reg\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rv3029_rtc_i2c_set_alarm(struct i2c_client *client,
|
||||
struct rtc_wkalrm *alarm)
|
||||
static int rv3029_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
{
|
||||
struct rtc_time *const tm = &alarm->time;
|
||||
int ret;
|
||||
|
@ -449,57 +498,48 @@ static int rv3029_rtc_i2c_set_alarm(struct i2c_client *client,
|
|||
if (tm->tm_year < 100)
|
||||
return -EINVAL;
|
||||
|
||||
ret = rv3029_i2c_get_sr(client, regs);
|
||||
ret = rv3029_get_sr(dev, regs);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "%s: reading SR failed\n", __func__);
|
||||
dev_err(dev, "%s: reading SR failed\n", __func__);
|
||||
return -EIO;
|
||||
}
|
||||
regs[RV3029_A_SC-RV3029_A_SC] = bin2bcd(tm->tm_sec & 0x7f);
|
||||
regs[RV3029_A_MN-RV3029_A_SC] = bin2bcd(tm->tm_min & 0x7f);
|
||||
regs[RV3029_A_HR-RV3029_A_SC] = bin2bcd(tm->tm_hour & 0x3f);
|
||||
regs[RV3029_A_DT-RV3029_A_SC] = bin2bcd(tm->tm_mday & 0x3f);
|
||||
regs[RV3029_A_MO-RV3029_A_SC] = bin2bcd((tm->tm_mon & 0x1f) - 1);
|
||||
regs[RV3029_A_DW-RV3029_A_SC] = bin2bcd((tm->tm_wday & 7) - 1);
|
||||
regs[RV3029_A_YR-RV3029_A_SC] = bin2bcd((tm->tm_year & 0x7f) - 100);
|
||||
|
||||
ret = rv3029_i2c_write_regs(client, RV3029_A_SC, regs,
|
||||
RV3029_ALARM_SECTION_LEN);
|
||||
/* Activate all the alarms with AE_x bit */
|
||||
regs[RV3029_A_SC - RV3029_A_SC] = bin2bcd(tm->tm_sec) | RV3029_A_AE_X;
|
||||
regs[RV3029_A_MN - RV3029_A_SC] = bin2bcd(tm->tm_min) | RV3029_A_AE_X;
|
||||
regs[RV3029_A_HR - RV3029_A_SC] = (bin2bcd(tm->tm_hour) & 0x3f)
|
||||
| RV3029_A_AE_X;
|
||||
regs[RV3029_A_DT - RV3029_A_SC] = (bin2bcd(tm->tm_mday) & 0x3f)
|
||||
| RV3029_A_AE_X;
|
||||
regs[RV3029_A_MO - RV3029_A_SC] = (bin2bcd(tm->tm_mon + 1) & 0x1f)
|
||||
| RV3029_A_AE_X;
|
||||
regs[RV3029_A_DW - RV3029_A_SC] = (bin2bcd(tm->tm_wday + 1) & 0x7)
|
||||
| RV3029_A_AE_X;
|
||||
regs[RV3029_A_YR - RV3029_A_SC] = (bin2bcd(tm->tm_year - 100))
|
||||
| RV3029_A_AE_X;
|
||||
|
||||
/* Write the alarm */
|
||||
ret = rv3029_write_regs(dev, RV3029_A_SC, regs,
|
||||
RV3029_ALARM_SECTION_LEN);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (alarm->enabled) {
|
||||
/* clear AF flag */
|
||||
ret = rv3029_i2c_update_bits(client, RV3029_IRQ_FLAGS,
|
||||
RV3029_IRQ_FLAGS_AF, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "can't clear alarm flag\n");
|
||||
return ret;
|
||||
}
|
||||
/* enable AIE irq */
|
||||
ret = rv3029_rtc_i2c_alarm_set_irq(client, 1);
|
||||
ret = rv3029_alarm_irq_enable(dev, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dev_dbg(&client->dev, "alarm IRQ armed\n");
|
||||
} else {
|
||||
/* disable AIE irq */
|
||||
ret = rv3029_rtc_i2c_alarm_set_irq(client, 0);
|
||||
ret = rv3029_alarm_irq_enable(dev, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dev_dbg(&client->dev, "alarm IRQ disabled\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rv3029_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
{
|
||||
return rv3029_rtc_i2c_set_alarm(to_i2c_client(dev), alarm);
|
||||
}
|
||||
|
||||
static int
|
||||
rv3029_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm)
|
||||
static int rv3029_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
u8 regs[8];
|
||||
int ret;
|
||||
|
@ -512,39 +552,34 @@ rv3029_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm)
|
|||
if (tm->tm_year < 100)
|
||||
return -EINVAL;
|
||||
|
||||
regs[RV3029_W_SEC-RV3029_W_SEC] = bin2bcd(tm->tm_sec);
|
||||
regs[RV3029_W_MINUTES-RV3029_W_SEC] = bin2bcd(tm->tm_min);
|
||||
regs[RV3029_W_HOURS-RV3029_W_SEC] = bin2bcd(tm->tm_hour);
|
||||
regs[RV3029_W_DATE-RV3029_W_SEC] = bin2bcd(tm->tm_mday);
|
||||
regs[RV3029_W_MONTHS-RV3029_W_SEC] = bin2bcd(tm->tm_mon+1);
|
||||
regs[RV3029_W_DAYS-RV3029_W_SEC] = bin2bcd((tm->tm_wday & 7)+1);
|
||||
regs[RV3029_W_YEARS-RV3029_W_SEC] = bin2bcd(tm->tm_year - 100);
|
||||
regs[RV3029_W_SEC - RV3029_W_SEC] = bin2bcd(tm->tm_sec);
|
||||
regs[RV3029_W_MINUTES - RV3029_W_SEC] = bin2bcd(tm->tm_min);
|
||||
regs[RV3029_W_HOURS - RV3029_W_SEC] = bin2bcd(tm->tm_hour);
|
||||
regs[RV3029_W_DATE - RV3029_W_SEC] = bin2bcd(tm->tm_mday);
|
||||
regs[RV3029_W_MONTHS - RV3029_W_SEC] = bin2bcd(tm->tm_mon + 1);
|
||||
regs[RV3029_W_DAYS - RV3029_W_SEC] = bin2bcd(tm->tm_wday + 1) & 0x7;
|
||||
regs[RV3029_W_YEARS - RV3029_W_SEC] = bin2bcd(tm->tm_year - 100);
|
||||
|
||||
ret = rv3029_i2c_write_regs(client, RV3029_W_SEC, regs,
|
||||
RV3029_WATCH_SECTION_LEN);
|
||||
ret = rv3029_write_regs(dev, RV3029_W_SEC, regs,
|
||||
RV3029_WATCH_SECTION_LEN);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = rv3029_i2c_get_sr(client, regs);
|
||||
ret = rv3029_get_sr(dev, regs);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "%s: reading SR failed\n", __func__);
|
||||
dev_err(dev, "%s: reading SR failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
/* clear PON bit */
|
||||
ret = rv3029_i2c_set_sr(client, (regs[0] & ~RV3029_STATUS_PON));
|
||||
ret = rv3029_set_sr(dev, (regs[0] & ~RV3029_STATUS_PON));
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "%s: reading SR failed\n", __func__);
|
||||
dev_err(dev, "%s: reading SR failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rv3029_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
return rv3029_i2c_set_time(to_i2c_client(dev), tm);
|
||||
}
|
||||
|
||||
static const struct rv3029_trickle_tab_elem {
|
||||
u32 r; /* resistance in ohms */
|
||||
u8 conf; /* trickle config bits */
|
||||
|
@ -602,9 +637,9 @@ static const struct rv3029_trickle_tab_elem {
|
|||
},
|
||||
};
|
||||
|
||||
static void rv3029_trickle_config(struct i2c_client *client)
|
||||
static void rv3029_trickle_config(struct device *dev)
|
||||
{
|
||||
struct device_node *of_node = client->dev.of_node;
|
||||
struct device_node *of_node = dev->of_node;
|
||||
const struct rv3029_trickle_tab_elem *elem;
|
||||
int i, err;
|
||||
u32 ohms;
|
||||
|
@ -626,27 +661,25 @@ static void rv3029_trickle_config(struct i2c_client *client)
|
|||
break;
|
||||
}
|
||||
trickle_set_bits = elem->conf;
|
||||
dev_info(&client->dev,
|
||||
dev_info(dev,
|
||||
"Trickle charger enabled at %d ohms resistance.\n",
|
||||
elem->r);
|
||||
}
|
||||
err = rv3029_eeprom_update_bits(client, RV3029_CONTROL_E2P_EECTRL,
|
||||
err = rv3029_eeprom_update_bits(dev, RV3029_CONTROL_E2P_EECTRL,
|
||||
RV3029_TRICKLE_MASK,
|
||||
trickle_set_bits);
|
||||
if (err < 0) {
|
||||
dev_err(&client->dev,
|
||||
"Failed to update trickle charger config\n");
|
||||
}
|
||||
if (err < 0)
|
||||
dev_err(dev, "Failed to update trickle charger config\n");
|
||||
}
|
||||
|
||||
#ifdef CONFIG_RTC_DRV_RV3029_HWMON
|
||||
|
||||
static int rv3029_read_temp(struct i2c_client *client, int *temp_mC)
|
||||
static int rv3029_read_temp(struct device *dev, int *temp_mC)
|
||||
{
|
||||
int ret;
|
||||
u8 temp;
|
||||
|
||||
ret = rv3029_i2c_read_regs(client, RV3029_TEMP_PAGE, &temp, 1);
|
||||
ret = rv3029_read_regs(dev, RV3029_TEMP_PAGE, &temp, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -659,10 +692,9 @@ static ssize_t rv3029_hwmon_show_temp(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct i2c_client *client = dev_get_drvdata(dev);
|
||||
int ret, temp_mC;
|
||||
|
||||
ret = rv3029_read_temp(client, &temp_mC);
|
||||
ret = rv3029_read_temp(dev, &temp_mC);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -674,7 +706,6 @@ static ssize_t rv3029_hwmon_set_update_interval(struct device *dev,
|
|||
const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct i2c_client *client = dev_get_drvdata(dev);
|
||||
unsigned long interval_ms;
|
||||
int ret;
|
||||
u8 th_set_bits = 0;
|
||||
|
@ -688,7 +719,7 @@ static ssize_t rv3029_hwmon_set_update_interval(struct device *dev,
|
|||
if (interval_ms >= 16000)
|
||||
th_set_bits |= RV3029_EECTRL_THP;
|
||||
}
|
||||
ret = rv3029_eeprom_update_bits(client, RV3029_CONTROL_E2P_EECTRL,
|
||||
ret = rv3029_eeprom_update_bits(dev, RV3029_CONTROL_E2P_EECTRL,
|
||||
RV3029_EECTRL_THE | RV3029_EECTRL_THP,
|
||||
th_set_bits);
|
||||
if (ret < 0)
|
||||
|
@ -701,11 +732,10 @@ static ssize_t rv3029_hwmon_show_update_interval(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct i2c_client *client = dev_get_drvdata(dev);
|
||||
int ret, interval_ms;
|
||||
u8 eectrl;
|
||||
|
||||
ret = rv3029_eeprom_read(client, RV3029_CONTROL_E2P_EECTRL,
|
||||
ret = rv3029_eeprom_read(dev, RV3029_CONTROL_E2P_EECTRL,
|
||||
&eectrl, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -735,34 +765,109 @@ static struct attribute *rv3029_hwmon_attrs[] = {
|
|||
};
|
||||
ATTRIBUTE_GROUPS(rv3029_hwmon);
|
||||
|
||||
static void rv3029_hwmon_register(struct i2c_client *client)
|
||||
static void rv3029_hwmon_register(struct device *dev, const char *name)
|
||||
{
|
||||
struct rv3029_data *rv3029 = dev_get_drvdata(dev);
|
||||
struct device *hwmon_dev;
|
||||
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(
|
||||
&client->dev, client->name, client, rv3029_hwmon_groups);
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(dev, name, rv3029,
|
||||
rv3029_hwmon_groups);
|
||||
if (IS_ERR(hwmon_dev)) {
|
||||
dev_warn(&client->dev,
|
||||
"unable to register hwmon device %ld\n",
|
||||
PTR_ERR(hwmon_dev));
|
||||
dev_warn(dev, "unable to register hwmon device %ld\n",
|
||||
PTR_ERR(hwmon_dev));
|
||||
}
|
||||
}
|
||||
|
||||
#else /* CONFIG_RTC_DRV_RV3029_HWMON */
|
||||
|
||||
static void rv3029_hwmon_register(struct i2c_client *client)
|
||||
static void rv3029_hwmon_register(struct device *dev, const char *name)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_RTC_DRV_RV3029_HWMON */
|
||||
|
||||
static const struct rtc_class_ops rv3029_rtc_ops = {
|
||||
.read_time = rv3029_rtc_read_time,
|
||||
.set_time = rv3029_rtc_set_time,
|
||||
.read_alarm = rv3029_rtc_read_alarm,
|
||||
.set_alarm = rv3029_rtc_set_alarm,
|
||||
static struct rtc_class_ops rv3029_rtc_ops = {
|
||||
.read_time = rv3029_read_time,
|
||||
.set_time = rv3029_set_time,
|
||||
};
|
||||
|
||||
static int rv3029_probe(struct device *dev, struct regmap *regmap, int irq,
|
||||
const char *name)
|
||||
{
|
||||
struct rv3029_data *rv3029;
|
||||
int rc = 0;
|
||||
u8 buf[1];
|
||||
|
||||
rv3029 = devm_kzalloc(dev, sizeof(*rv3029), GFP_KERNEL);
|
||||
if (!rv3029)
|
||||
return -ENOMEM;
|
||||
|
||||
rv3029->regmap = regmap;
|
||||
rv3029->irq = irq;
|
||||
rv3029->dev = dev;
|
||||
dev_set_drvdata(dev, rv3029);
|
||||
|
||||
rc = rv3029_get_sr(dev, buf);
|
||||
if (rc < 0) {
|
||||
dev_err(dev, "reading status failed\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
rv3029_trickle_config(dev);
|
||||
rv3029_hwmon_register(dev, name);
|
||||
|
||||
rv3029->rtc = devm_rtc_device_register(dev, name, &rv3029_rtc_ops,
|
||||
THIS_MODULE);
|
||||
if (IS_ERR(rv3029->rtc)) {
|
||||
dev_err(dev, "unable to register the class device\n");
|
||||
return PTR_ERR(rv3029->rtc);
|
||||
}
|
||||
|
||||
if (rv3029->irq > 0) {
|
||||
rc = devm_request_threaded_irq(dev, rv3029->irq,
|
||||
NULL, rv3029_handle_irq,
|
||||
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
|
||||
"rv3029", dev);
|
||||
if (rc) {
|
||||
dev_warn(dev, "unable to request IRQ, alarms disabled\n");
|
||||
rv3029->irq = 0;
|
||||
} else {
|
||||
rv3029_rtc_ops.read_alarm = rv3029_read_alarm;
|
||||
rv3029_rtc_ops.set_alarm = rv3029_set_alarm;
|
||||
rv3029_rtc_ops.alarm_irq_enable = rv3029_alarm_irq_enable;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C)
|
||||
|
||||
static int rv3029_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct regmap *regmap;
|
||||
static const struct regmap_config config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
};
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK |
|
||||
I2C_FUNC_SMBUS_BYTE)) {
|
||||
dev_err(&client->dev, "Adapter does not support SMBUS_I2C_BLOCK or SMBUS_I2C_BYTE\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
regmap = devm_regmap_init_i2c(client, &config);
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(&client->dev, "%s: regmap allocation failed: %ld\n",
|
||||
__func__, PTR_ERR(regmap));
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
return rv3029_probe(&client->dev, regmap, client->irq, client->name);
|
||||
}
|
||||
|
||||
static struct i2c_device_id rv3029_id[] = {
|
||||
{ "rv3029", 0 },
|
||||
{ "rv3029c2", 0 },
|
||||
|
@ -770,47 +875,116 @@ static struct i2c_device_id rv3029_id[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(i2c, rv3029_id);
|
||||
|
||||
static int rv3029_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct rtc_device *rtc;
|
||||
int rc = 0;
|
||||
u8 buf[1];
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_EMUL))
|
||||
return -ENODEV;
|
||||
|
||||
rc = rv3029_i2c_get_sr(client, buf);
|
||||
if (rc < 0) {
|
||||
dev_err(&client->dev, "reading status failed\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
rv3029_trickle_config(client);
|
||||
rv3029_hwmon_register(client);
|
||||
|
||||
rtc = devm_rtc_device_register(&client->dev, client->name,
|
||||
&rv3029_rtc_ops, THIS_MODULE);
|
||||
|
||||
if (IS_ERR(rtc))
|
||||
return PTR_ERR(rtc);
|
||||
|
||||
i2c_set_clientdata(client, rtc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct i2c_driver rv3029_driver = {
|
||||
.driver = {
|
||||
.name = "rtc-rv3029c2",
|
||||
},
|
||||
.probe = rv3029_probe,
|
||||
.probe = rv3029_i2c_probe,
|
||||
.id_table = rv3029_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(rv3029_driver);
|
||||
static int rv3029_register_driver(void)
|
||||
{
|
||||
return i2c_add_driver(&rv3029_driver);
|
||||
}
|
||||
|
||||
static void rv3029_unregister_driver(void)
|
||||
{
|
||||
i2c_del_driver(&rv3029_driver);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int rv3029_register_driver(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rv3029_unregister_driver(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_SPI_MASTER)
|
||||
|
||||
static int rv3049_probe(struct spi_device *spi)
|
||||
{
|
||||
static const struct regmap_config config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
};
|
||||
struct regmap *regmap;
|
||||
|
||||
regmap = devm_regmap_init_spi(spi, &config);
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(&spi->dev, "%s: regmap allocation failed: %ld\n",
|
||||
__func__, PTR_ERR(regmap));
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
return rv3029_probe(&spi->dev, regmap, spi->irq, "rv3049");
|
||||
}
|
||||
|
||||
static struct spi_driver rv3049_driver = {
|
||||
.driver = {
|
||||
.name = "rv3049",
|
||||
},
|
||||
.probe = rv3049_probe,
|
||||
};
|
||||
|
||||
static int rv3049_register_driver(void)
|
||||
{
|
||||
return spi_register_driver(&rv3049_driver);
|
||||
}
|
||||
|
||||
static void rv3049_unregister_driver(void)
|
||||
{
|
||||
spi_unregister_driver(&rv3049_driver);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int rv3049_register_driver(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rv3049_unregister_driver(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int __init rv30x9_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = rv3029_register_driver();
|
||||
if (ret) {
|
||||
pr_err("Failed to register rv3029 driver: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = rv3049_register_driver();
|
||||
if (ret) {
|
||||
pr_err("Failed to register rv3049 driver: %d\n", ret);
|
||||
rv3029_unregister_driver();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
module_init(rv30x9_init)
|
||||
|
||||
static void __exit rv30x9_exit(void)
|
||||
{
|
||||
rv3049_unregister_driver();
|
||||
rv3029_unregister_driver();
|
||||
}
|
||||
module_exit(rv30x9_exit)
|
||||
|
||||
MODULE_AUTHOR("Gregory Hermant <gregory.hermant@calao-systems.com>");
|
||||
MODULE_AUTHOR("Michael Buesch <m@bues.ch>");
|
||||
MODULE_DESCRIPTION("Micro Crystal RV3029 RTC driver");
|
||||
MODULE_DESCRIPTION("Micro Crystal RV3029/RV3049 RTC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("spi:rv3049");
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
#include <linux/rtc.h>
|
||||
#include <linux/log2.h>
|
||||
|
||||
#define DRV_VERSION "0.1"
|
||||
|
||||
#define RX8581_REG_SC 0x00 /* Second in BCD */
|
||||
#define RX8581_REG_MN 0x01 /* Minute in BCD */
|
||||
#define RX8581_REG_HR 0x02 /* Hour in BCD */
|
||||
|
@ -292,8 +290,6 @@ static int rx8581_probe(struct i2c_client *client,
|
|||
rx8581->write_block_data = rx8581_write_block_data;
|
||||
}
|
||||
|
||||
dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
|
||||
|
||||
rx8581->rtc = devm_rtc_device_register(&client->dev,
|
||||
rx8581_driver.driver.name, &rx8581_rtc_ops, THIS_MODULE);
|
||||
|
||||
|
@ -325,4 +321,3 @@ module_i2c_driver(rx8581_driver);
|
|||
MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com>");
|
||||
MODULE_DESCRIPTION("Epson RX-8581 RTC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
#include <asm/rtc.h>
|
||||
|
||||
#define DRV_NAME "sh-rtc"
|
||||
#define DRV_VERSION "0.2.3"
|
||||
|
||||
#define RTC_REG(r) ((r) * rtc_reg_size)
|
||||
|
||||
|
@ -790,7 +789,6 @@ static struct platform_driver sh_rtc_platform_driver = {
|
|||
module_platform_driver_probe(sh_rtc_platform_driver, sh_rtc_probe);
|
||||
|
||||
MODULE_DESCRIPTION("SuperH on-chip RTC driver");
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, "
|
||||
"Jamie Lenehan <lenehan@twibble.org>, "
|
||||
"Angelo Castello <angelo.castello@st.com>");
|
||||
|
|
|
@ -322,7 +322,7 @@ static int snvs_rtc_suspend(struct device *dev)
|
|||
struct snvs_rtc_data *data = dev_get_drvdata(dev);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
enable_irq_wake(data->irq);
|
||||
return enable_irq_wake(data->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -23,8 +23,6 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#define DRV_VERSION "0.1"
|
||||
|
||||
#define RTC_REG_SIZE 0x20000
|
||||
#define RTC_OFFSET 0x1fff0
|
||||
|
||||
|
@ -366,4 +364,3 @@ module_platform_driver(stk17ta8_rtc_driver);
|
|||
MODULE_AUTHOR("Thomas Hommel <thomas.hommel@ge.com>");
|
||||
MODULE_DESCRIPTION("Simtek STK17TA8 RTC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
|
|
|
@ -107,14 +107,19 @@ static struct stmp3xxx_wdt_pdata wdt_pdata = {
|
|||
|
||||
static void stmp3xxx_wdt_register(struct platform_device *rtc_pdev)
|
||||
{
|
||||
int rc = -1;
|
||||
struct platform_device *wdt_pdev =
|
||||
platform_device_alloc("stmp3xxx_rtc_wdt", rtc_pdev->id);
|
||||
|
||||
if (wdt_pdev) {
|
||||
wdt_pdev->dev.parent = &rtc_pdev->dev;
|
||||
wdt_pdev->dev.platform_data = &wdt_pdata;
|
||||
platform_device_add(wdt_pdev);
|
||||
rc = platform_device_add(wdt_pdev);
|
||||
}
|
||||
|
||||
if (rc)
|
||||
dev_err(&rtc_pdev->dev,
|
||||
"failed to register stmp3xxx_rtc_wdt\n");
|
||||
}
|
||||
#else
|
||||
static void stmp3xxx_wdt_register(struct platform_device *rtc_pdev)
|
||||
|
|
|
@ -344,7 +344,7 @@ static struct platform_driver tps6586x_rtc_driver = {
|
|||
};
|
||||
module_platform_driver(tps6586x_rtc_driver);
|
||||
|
||||
MODULE_ALIAS("platform:rtc-tps6586x");
|
||||
MODULE_ALIAS("platform:tps6586x-rtc");
|
||||
MODULE_DESCRIPTION("TI TPS6586x RTC driver");
|
||||
MODULE_AUTHOR("Laxman dewangan <ldewangan@nvidia.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -24,8 +24,6 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#define DRV_VERSION "1.0.8"
|
||||
|
||||
/* offsets into CCR area */
|
||||
|
||||
#define CCR_SEC 0
|
||||
|
@ -634,8 +632,6 @@ static int x1205_probe(struct i2c_client *client,
|
|||
if (x1205_validate_client(client) < 0)
|
||||
return -ENODEV;
|
||||
|
||||
dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
|
||||
|
||||
rtc = devm_rtc_device_register(&client->dev, x1205_driver.driver.name,
|
||||
&x1205_rtc_ops, THIS_MODULE);
|
||||
|
||||
|
@ -693,4 +689,3 @@ MODULE_AUTHOR(
|
|||
"Alessandro Zummo <a.zummo@towertech.it>");
|
||||
MODULE_DESCRIPTION("Xicor/Intersil X1205 RTC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#define RTC_INT_SEC BIT(0)
|
||||
#define RTC_INT_ALRM BIT(1)
|
||||
#define RTC_OSC_EN BIT(24)
|
||||
#define RTC_BATT_EN BIT(31)
|
||||
|
||||
#define RTC_CALIB_DEF 0x198233
|
||||
#define RTC_CALIB_MASK 0x1FFFFF
|
||||
|
@ -55,6 +56,7 @@ struct xlnx_rtc_dev {
|
|||
void __iomem *reg_base;
|
||||
int alarm_irq;
|
||||
int sec_irq;
|
||||
int calibval;
|
||||
};
|
||||
|
||||
static int xlnx_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
|
@ -62,21 +64,63 @@ static int xlnx_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
|||
struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
|
||||
unsigned long new_time;
|
||||
|
||||
new_time = rtc_tm_to_time64(tm);
|
||||
/*
|
||||
* The value written will be updated after 1 sec into the
|
||||
* seconds read register, so we need to program time +1 sec
|
||||
* to get the correct time on read.
|
||||
*/
|
||||
new_time = rtc_tm_to_time64(tm) + 1;
|
||||
|
||||
if (new_time > RTC_SEC_MAX_VAL)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Writing into calibration register will clear the Tick Counter and
|
||||
* force the next second to be signaled exactly in 1 second period
|
||||
*/
|
||||
xrtcdev->calibval &= RTC_CALIB_MASK;
|
||||
writel(xrtcdev->calibval, (xrtcdev->reg_base + RTC_CALIB_WR));
|
||||
|
||||
writel(new_time, xrtcdev->reg_base + RTC_SET_TM_WR);
|
||||
|
||||
/*
|
||||
* Clear the rtc interrupt status register after setting the
|
||||
* time. During a read_time function, the code should read the
|
||||
* RTC_INT_STATUS register and if bit 0 is still 0, it means
|
||||
* that one second has not elapsed yet since RTC was set and
|
||||
* the current time should be read from SET_TIME_READ register;
|
||||
* otherwise, CURRENT_TIME register is read to report the time
|
||||
*/
|
||||
writel(RTC_INT_SEC, xrtcdev->reg_base + RTC_INT_STS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xlnx_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
u32 status;
|
||||
unsigned long read_time;
|
||||
struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
|
||||
|
||||
rtc_time64_to_tm(readl(xrtcdev->reg_base + RTC_CUR_TM), tm);
|
||||
status = readl(xrtcdev->reg_base + RTC_INT_STS);
|
||||
|
||||
if (status & RTC_INT_SEC) {
|
||||
/*
|
||||
* RTC has updated the CURRENT_TIME with the time written into
|
||||
* SET_TIME_WRITE register.
|
||||
*/
|
||||
rtc_time64_to_tm(readl(xrtcdev->reg_base + RTC_CUR_TM), tm);
|
||||
} else {
|
||||
/*
|
||||
* Time written in SET_TIME_WRITE has not yet updated into
|
||||
* the seconds read register, so read the time from the
|
||||
* SET_TIME_WRITE instead of CURRENT_TIME register.
|
||||
* Since we add +1 sec while writing, we need to -1 sec while
|
||||
* reading.
|
||||
*/
|
||||
read_time = readl(xrtcdev->reg_base + RTC_SET_TM_RD) - 1;
|
||||
rtc_time64_to_tm(read_time, tm);
|
||||
}
|
||||
|
||||
return rtc_valid_tm(tm);
|
||||
}
|
||||
|
@ -120,16 +164,23 @@ static int xlnx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void xlnx_init_rtc(struct xlnx_rtc_dev *xrtcdev, u32 calibval)
|
||||
static void xlnx_init_rtc(struct xlnx_rtc_dev *xrtcdev)
|
||||
{
|
||||
u32 rtc_ctrl;
|
||||
|
||||
/* Enable RTC switch to battery when VCC_PSAUX is not available */
|
||||
rtc_ctrl = readl(xrtcdev->reg_base + RTC_CTRL);
|
||||
rtc_ctrl |= RTC_BATT_EN;
|
||||
writel(rtc_ctrl, xrtcdev->reg_base + RTC_CTRL);
|
||||
|
||||
/*
|
||||
* Based on crystal freq of 33.330 KHz
|
||||
* set the seconds counter and enable, set fractions counter
|
||||
* to default value suggested as per design spec
|
||||
* to correct RTC delay in frequency over period of time.
|
||||
*/
|
||||
calibval &= RTC_CALIB_MASK;
|
||||
writel(calibval, (xrtcdev->reg_base + RTC_CALIB_WR));
|
||||
xrtcdev->calibval &= RTC_CALIB_MASK;
|
||||
writel(xrtcdev->calibval, (xrtcdev->reg_base + RTC_CALIB_WR));
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops xlnx_rtc_ops = {
|
||||
|
@ -150,11 +201,9 @@ static irqreturn_t xlnx_rtc_interrupt(int irq, void *id)
|
|||
if (!(status & (RTC_INT_SEC | RTC_INT_ALRM)))
|
||||
return IRQ_NONE;
|
||||
|
||||
/* Clear interrupt */
|
||||
writel(status, xrtcdev->reg_base + RTC_INT_STS);
|
||||
/* Clear RTC_INT_ALRM interrupt only */
|
||||
writel(RTC_INT_ALRM, xrtcdev->reg_base + RTC_INT_STS);
|
||||
|
||||
if (status & RTC_INT_SEC)
|
||||
rtc_update_irq(xrtcdev->rtc, 1, RTC_IRQF | RTC_UF);
|
||||
if (status & RTC_INT_ALRM)
|
||||
rtc_update_irq(xrtcdev->rtc, 1, RTC_IRQF | RTC_AF);
|
||||
|
||||
|
@ -166,7 +215,6 @@ static int xlnx_rtc_probe(struct platform_device *pdev)
|
|||
struct xlnx_rtc_dev *xrtcdev;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
unsigned int calibvalue;
|
||||
|
||||
xrtcdev = devm_kzalloc(&pdev->dev, sizeof(*xrtcdev), GFP_KERNEL);
|
||||
if (!xrtcdev)
|
||||
|
@ -207,11 +255,11 @@ static int xlnx_rtc_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
ret = of_property_read_u32(pdev->dev.of_node, "calibration",
|
||||
&calibvalue);
|
||||
&xrtcdev->calibval);
|
||||
if (ret)
|
||||
calibvalue = RTC_CALIB_DEF;
|
||||
xrtcdev->calibval = RTC_CALIB_DEF;
|
||||
|
||||
xlnx_init_rtc(xrtcdev, calibvalue);
|
||||
xlnx_init_rtc(xrtcdev);
|
||||
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче