--- /dev/null
+Epson RX6110 Real Time Clock
+============================
+
+The Epson RX6110 can be used with SPI or I2C busses. The kind of
+bus depends on the SPISEL pin and can not be configured via software.
+
+I2C mode
+--------
+
+Required properties:
+ - compatible: should be: "epson,rx6110"
+ - reg : the I2C address of the device for I2C
+
+Example:
+
+ rtc: rtc@32 {
+ compatible = "epson,rx6110"
+ reg = <0x32>;
+ };
+
+SPI mode
+--------
+
+Required properties:
+ - compatible: should be: "epson,rx6110"
+ - reg: chip select number
+ - spi-cs-high: RX6110 needs chipselect high
+ - spi-cpha: RX6110 works with SPI shifted clock phase
+ - spi-cpol: RX6110 works with SPI inverse clock polarity
+
+Example:
+
+ rtc: rtc@3 {
+ compatible = "epson,rx6110"
+ reg = <3>
+ spi-cs-high;
+ spi-cpha;
+ spi-cpol;
+ };
This driver can also be built as a module. If so, the module
will be called rtc-ds1307.
+config RTC_DRV_DS1307_HWMON
+ bool "HWMON support for rtc-ds1307"
+ depends on RTC_DRV_DS1307 && HWMON
+ depends on !(RTC_DRV_DS1307=y && HWMON=m)
+ default y
+ help
+ Say Y here if you want to expose temperature sensor data on
+ rtc-ds1307 (only DS3231)
+
config RTC_DRV_DS1374
tristate "Dallas/Maxim DS1374"
help
This driver can also be built as a module. If so the module
will be called rtc-rx4581.
+config RTC_DRV_RX6110
+ tristate "Epson RX-6110"
+ select REGMAP_SPI
+ help
+ If you say yes here you will get support for the Epson RX-6610.
+
+ This driver can also be built as a module. If so the module
+ will be called rtc-rx6110.
+
config RTC_DRV_MCP795
tristate "Microchip MCP795"
help
config RTC_DRV_SUN6I
tristate "Allwinner A31 RTC"
- depends on MACH_SUN6I || MACH_SUN8I
+ default MACH_SUN6I || MACH_SUN8I
+ depends on ARCH_SUNXI
help
- If you say Y here you will get support for the RTC found on
- Allwinner A31.
+ If you say Y here you will get support for the RTC found in
+ some Allwinner SoCs like the A31 or the A64.
config RTC_DRV_SUNXI
tristate "Allwinner sun4i/sun7i RTC"
config RTC_DRV_MT6397
tristate "Mediatek Real Time Clock driver"
- depends on MFD_MT6397 || COMPILE_TEST
+ depends on MFD_MT6397 || (COMPILE_TEST && IRQ_DOMAIN)
help
This selects the Mediatek(R) RTC driver. RTC is part of Mediatek
MT6397 PMIC. You should enable MT6397 PMIC MFD before select
obj-$(CONFIG_RTC_DRV_RV3029C2) += rtc-rv3029c2.o
obj-$(CONFIG_RTC_DRV_RV8803) += rtc-rv8803.o
obj-$(CONFIG_RTC_DRV_RX4581) += rtc-rx4581.o
+obj-$(CONFIG_RTC_DRV_RX6110) += rtc-rx6110.o
obj-$(CONFIG_RTC_DRV_RX8010) += rtc-rx8010.o
obj-$(CONFIG_RTC_DRV_RX8025) += rtc-rx8025.o
obj-$(CONFIG_RTC_DRV_RX8581) += rtc-rx8581.o
struct spi_transfer x[2];
int status;
- spi = container_of(kobj, struct spi_device, dev.kobj);
+ spi = to_spi_device(kobj_to_dev(kobj));
addr = DS1305_NVRAM + off;
msg_init(&m, x, &addr, count, NULL, buf);
struct spi_transfer x[2];
int status;
- spi = container_of(kobj, struct spi_device, dev.kobj);
+ spi = to_spi_device(kobj_to_dev(kobj));
addr = (DS1305_WRITE | DS1305_NVRAM) + off;
msg_init(&m, x, &addr, count, buf, NULL);
#include <linux/rtc.h>
#include <linux/slab.h>
#include <linux/string.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
/*
* We can't determine type by probing, but if we expect pre-Linux code
return;
}
+/*----------------------------------------------------------------------*/
+
+#ifdef CONFIG_RTC_DRV_DS1307_HWMON
+
+/*
+ * Temperature sensor support for ds3231 devices.
+ */
+
+#define DS3231_REG_TEMPERATURE 0x11
+
+/*
+ * A user-initiated temperature conversion is not started by this function,
+ * so the temperature is updated once every 64 seconds.
+ */
+static int ds3231_hwmon_read_temp(struct device *dev, s16 *mC)
+{
+ struct ds1307 *ds1307 = dev_get_drvdata(dev);
+ u8 temp_buf[2];
+ s16 temp;
+ int ret;
+
+ ret = ds1307->read_block_data(ds1307->client, DS3231_REG_TEMPERATURE,
+ sizeof(temp_buf), temp_buf);
+ if (ret < 0)
+ return ret;
+ if (ret != sizeof(temp_buf))
+ return -EIO;
+
+ /*
+ * Temperature is represented as a 10-bit code with a resolution of
+ * 0.25 degree celsius and encoded in two's complement format.
+ */
+ temp = (temp_buf[0] << 8) | temp_buf[1];
+ temp >>= 6;
+ *mC = temp * 250;
+
+ return 0;
+}
+
+static ssize_t ds3231_hwmon_show_temp(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+ s16 temp;
+
+ ret = ds3231_hwmon_read_temp(dev, &temp);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%d\n", temp);
+}
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, ds3231_hwmon_show_temp,
+ NULL, 0);
+
+static struct attribute *ds3231_hwmon_attrs[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(ds3231_hwmon);
+
+static void ds1307_hwmon_register(struct ds1307 *ds1307)
+{
+ struct device *dev;
+
+ if (ds1307->type != ds_3231)
+ return;
+
+ dev = devm_hwmon_device_register_with_groups(&ds1307->client->dev,
+ ds1307->client->name,
+ ds1307, ds3231_hwmon_groups);
+ if (IS_ERR(dev)) {
+ dev_warn(&ds1307->client->dev,
+ "unable to register hwmon device %ld\n", PTR_ERR(dev));
+ }
+}
+
+#else
+
+static void ds1307_hwmon_register(struct ds1307 *ds1307)
+{
+}
+
+#endif
+
static int ds1307_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct chip_desc *chip = &chips[id->driver_data];
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
bool want_irq = false;
+ bool ds1307_can_wakeup_device = false;
unsigned char *buf;
struct ds1307_platform_data *pdata = dev_get_platdata(&client->dev);
irq_handler_t irq_handler = ds1307_irq;
ds1307->write_block_data = ds1307_write_block_data;
}
+#ifdef CONFIG_OF
+/*
+ * For devices with no IRQ directly connected to the SoC, the RTC chip
+ * can be forced as a wakeup source by stating that explicitly in
+ * the device's .dts file using the "wakeup-source" boolean property.
+ * If the "wakeup-source" property is set, don't request an IRQ.
+ * This will guarantee the 'wakealarm' sysfs entry is available on the device,
+ * if supported by the RTC.
+ */
+ if (of_property_read_bool(client->dev.of_node, "wakeup-source")) {
+ ds1307_can_wakeup_device = true;
+ }
+#endif
+
switch (ds1307->type) {
case ds_1337:
case ds_1339:
ds1307->regs[0] &= ~DS1337_BIT_nEOSC;
/*
- * Using IRQ? Disable the square wave and both alarms.
+ * Using IRQ or defined as wakeup-source?
+ * Disable the square wave and both alarms.
* For some variants, be sure alarms can trigger when we're
* running on Vbackup (BBSQI/BBSQW)
*/
- if (ds1307->client->irq > 0 && chip->alarm) {
+ if (chip->alarm && (ds1307->client->irq > 0 ||
+ ds1307_can_wakeup_device)) {
ds1307->regs[0] |= DS1337_BIT_INTCN
| bbsqi_bitpos[ds1307->type];
ds1307->regs[0] &= ~(DS1337_BIT_A2IE | DS1337_BIT_A1IE);
return PTR_ERR(ds1307->rtc);
}
+ if (ds1307_can_wakeup_device) {
+ /* Disable request for an IRQ */
+ want_irq = false;
+ dev_info(&client->dev, "'wakeup-source' is set, request for an IRQ is disabled!\n");
+ /* We cannot support UIE mode if we do not have an IRQ line */
+ ds1307->rtc->uie_unsupported = 1;
+ }
+
if (want_irq) {
err = devm_request_threaded_irq(&client->dev,
client->irq, NULL, irq_handler,
}
}
+ ds1307_hwmon_register(ds1307);
+
return 0;
exit:
#define DRV_VERSION "0.6"
+/* REGISTERS */
#define PCF2123_REG_CTRL1 (0x00) /* Control Register 1 */
#define PCF2123_REG_CTRL2 (0x01) /* Control Register 2 */
#define PCF2123_REG_SC (0x02) /* datetime */
#define PCF2123_REG_DW (0x06)
#define PCF2123_REG_MO (0x07)
#define PCF2123_REG_YR (0x08)
+#define PCF2123_REG_ALRM_MN (0x09) /* Alarm Registers */
+#define PCF2123_REG_ALRM_HR (0x0a)
+#define PCF2123_REG_ALRM_DM (0x0b)
+#define PCF2123_REG_ALRM_DW (0x0c)
+#define PCF2123_REG_OFFSET (0x0d) /* Clock Rate Offset Register */
+#define PCF2123_REG_TMR_CLKOUT (0x0e) /* Timer Registers */
+#define PCF2123_REG_CTDWN_TMR (0x0f)
+
+/* PCF2123_REG_CTRL1 BITS */
+#define CTRL1_CLEAR (0) /* Clear */
+#define CTRL1_CORR_INT BIT(1) /* Correction irq enable */
+#define CTRL1_12_HOUR BIT(2) /* 12 hour time */
+#define CTRL1_SW_RESET (BIT(3) | BIT(4) | BIT(6)) /* Software reset */
+#define CTRL1_STOP BIT(5) /* Stop the clock */
+#define CTRL1_EXT_TEST BIT(7) /* External clock test mode */
+
+/* PCF2123_REG_CTRL2 BITS */
+#define CTRL2_TIE BIT(0) /* Countdown timer irq enable */
+#define CTRL2_AIE BIT(1) /* Alarm irq enable */
+#define CTRL2_TF BIT(2) /* Countdown timer flag */
+#define CTRL2_AF BIT(3) /* Alarm flag */
+#define CTRL2_TI_TP BIT(4) /* Irq pin generates pulse */
+#define CTRL2_MSF BIT(5) /* Minute or second irq flag */
+#define CTRL2_SI BIT(6) /* Second irq enable */
+#define CTRL2_MI BIT(7) /* Minute irq enable */
+
+/* PCF2123_REG_SC BITS */
+#define OSC_HAS_STOPPED BIT(7) /* Clock has been stopped */
+
+/* PCF2123_REG_ALRM_XX BITS */
+#define ALRM_ENABLE BIT(7) /* MN, HR, DM, or DW alarm enable */
+
+/* PCF2123_REG_TMR_CLKOUT BITS */
+#define CD_TMR_4096KHZ (0) /* 4096 KHz countdown timer */
+#define CD_TMR_64HZ (1) /* 64 Hz countdown timer */
+#define CD_TMR_1HZ (2) /* 1 Hz countdown timer */
+#define CD_TMR_60th_HZ (3) /* 60th Hz countdown timer */
+#define CD_TMR_TE BIT(3) /* Countdown timer enable */
+
+/* PCF2123_REG_OFFSET BITS */
+#define OFFSET_SIGN_BIT BIT(6) /* 2's complement sign bit */
+#define OFFSET_COARSE BIT(7) /* Coarse mode offset */
+
+/* READ/WRITE ADDRESS BITS */
+#define PCF2123_WRITE BIT(4)
+#define PCF2123_READ (BIT(4) | BIT(7))
-#define PCF2123_SUBADDR (1 << 4)
-#define PCF2123_WRITE ((0 << 7) | PCF2123_SUBADDR)
-#define PCF2123_READ ((1 << 7) | PCF2123_SUBADDR)
static struct spi_driver pcf2123_driver;
ndelay(30);
}
+static int pcf2123_read(struct device *dev, u8 reg, u8 *rxbuf, size_t size)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ int ret;
+
+ reg |= PCF2123_READ;
+ ret = spi_write_then_read(spi, ®, 1, rxbuf, size);
+ pcf2123_delay_trec();
+
+ return ret;
+}
+
+static int pcf2123_write(struct device *dev, u8 *txbuf, size_t size)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ int ret;
+
+ txbuf[0] |= PCF2123_WRITE;
+ ret = spi_write(spi, txbuf, size);
+ pcf2123_delay_trec();
+
+ return ret;
+}
+
+static int pcf2123_write_reg(struct device *dev, u8 reg, u8 val)
+{
+ u8 txbuf[2];
+
+ txbuf[0] = reg;
+ txbuf[1] = val;
+ return pcf2123_write(dev, txbuf, sizeof(txbuf));
+}
+
static ssize_t pcf2123_show(struct device *dev, struct device_attribute *attr,
char *buffer)
{
- struct spi_device *spi = to_spi_device(dev);
struct pcf2123_sysfs_reg *r;
- u8 txbuf[1], rxbuf[1];
+ u8 rxbuf[1];
unsigned long reg;
int ret;
if (ret)
return ret;
- txbuf[0] = PCF2123_READ | reg;
- ret = spi_write_then_read(spi, txbuf, 1, rxbuf, 1);
+ ret = pcf2123_read(dev, reg, rxbuf, 1);
if (ret < 0)
return -EIO;
- pcf2123_delay_trec();
+
return sprintf(buffer, "0x%x\n", rxbuf[0]);
}
static ssize_t pcf2123_store(struct device *dev, struct device_attribute *attr,
const char *buffer, size_t count) {
- struct spi_device *spi = to_spi_device(dev);
struct pcf2123_sysfs_reg *r;
- u8 txbuf[2];
unsigned long reg;
unsigned long val;
if (ret)
return ret;
- txbuf[0] = PCF2123_WRITE | reg;
- txbuf[1] = val;
- ret = spi_write(spi, txbuf, sizeof(txbuf));
+ pcf2123_write_reg(dev, reg, val);
if (ret < 0)
return -EIO;
- pcf2123_delay_trec();
return count;
}
static int pcf2123_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
- struct spi_device *spi = to_spi_device(dev);
- u8 txbuf[1], rxbuf[7];
+ u8 rxbuf[7];
int ret;
- txbuf[0] = PCF2123_READ | PCF2123_REG_SC;
- ret = spi_write_then_read(spi, txbuf, sizeof(txbuf),
- rxbuf, sizeof(rxbuf));
+ ret = pcf2123_read(dev, PCF2123_REG_SC, rxbuf, sizeof(rxbuf));
if (ret < 0)
return ret;
- pcf2123_delay_trec();
+
+ if (rxbuf[0] & OSC_HAS_STOPPED) {
+ dev_info(dev, "clock was stopped. Time is not valid\n");
+ return -EINVAL;
+ }
tm->tm_sec = bcd2bin(rxbuf[0] & 0x7F);
tm->tm_min = bcd2bin(rxbuf[1] & 0x7F);
static int pcf2123_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
- struct spi_device *spi = to_spi_device(dev);
u8 txbuf[8];
int ret;
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
/* Stop the counter first */
- txbuf[0] = PCF2123_WRITE | PCF2123_REG_CTRL1;
- txbuf[1] = 0x20;
- ret = spi_write(spi, txbuf, 2);
+ ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_STOP);
if (ret < 0)
return ret;
- pcf2123_delay_trec();
/* Set the new time */
- txbuf[0] = PCF2123_WRITE | PCF2123_REG_SC;
+ txbuf[0] = PCF2123_REG_SC;
txbuf[1] = bin2bcd(tm->tm_sec & 0x7F);
txbuf[2] = bin2bcd(tm->tm_min & 0x7F);
txbuf[3] = bin2bcd(tm->tm_hour & 0x3F);
txbuf[6] = bin2bcd((tm->tm_mon + 1) & 0x1F); /* rtc mn 1-12 */
txbuf[7] = bin2bcd(tm->tm_year < 100 ? tm->tm_year : tm->tm_year - 100);
- ret = spi_write(spi, txbuf, sizeof(txbuf));
+ ret = pcf2123_write(dev, txbuf, sizeof(txbuf));
if (ret < 0)
return ret;
- pcf2123_delay_trec();
/* Start the counter */
- txbuf[0] = PCF2123_WRITE | PCF2123_REG_CTRL1;
- txbuf[1] = 0x00;
- ret = spi_write(spi, txbuf, 2);
+ ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_CLEAR);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int pcf2123_reset(struct device *dev)
+{
+ int ret;
+ u8 rxbuf[2];
+
+ ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_SW_RESET);
+ if (ret < 0)
+ return ret;
+
+ /* Stop the counter */
+ dev_dbg(dev, "stopping RTC\n");
+ ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_STOP);
+ if (ret < 0)
+ return ret;
+
+ /* See if the counter was actually stopped */
+ dev_dbg(dev, "checking for presence of RTC\n");
+ ret = pcf2123_read(dev, PCF2123_REG_CTRL1, rxbuf, sizeof(rxbuf));
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(dev, "received data from RTC (0x%02X 0x%02X)\n",
+ rxbuf[0], rxbuf[1]);
+ if (!(rxbuf[0] & CTRL1_STOP))
+ return -ENODEV;
+
+ /* Start the counter */
+ ret = pcf2123_write_reg(dev, PCF2123_REG_CTRL1, CTRL1_CLEAR);
if (ret < 0)
return ret;
- pcf2123_delay_trec();
return 0;
}
static int pcf2123_probe(struct spi_device *spi)
{
struct rtc_device *rtc;
+ struct rtc_time tm;
struct pcf2123_plat_data *pdata;
- u8 txbuf[2], rxbuf[2];
int ret, i;
pdata = devm_kzalloc(&spi->dev, sizeof(struct pcf2123_plat_data),
return -ENOMEM;
spi->dev.platform_data = pdata;
- /* Send a software reset command */
- txbuf[0] = PCF2123_WRITE | PCF2123_REG_CTRL1;
- txbuf[1] = 0x58;
- dev_dbg(&spi->dev, "resetting RTC (0x%02X 0x%02X)\n",
- txbuf[0], txbuf[1]);
- ret = spi_write(spi, txbuf, 2 * sizeof(u8));
- if (ret < 0)
- goto kfree_exit;
- pcf2123_delay_trec();
-
- /* Stop the counter */
- txbuf[0] = PCF2123_WRITE | PCF2123_REG_CTRL1;
- txbuf[1] = 0x20;
- dev_dbg(&spi->dev, "stopping RTC (0x%02X 0x%02X)\n",
- txbuf[0], txbuf[1]);
- ret = spi_write(spi, txbuf, 2 * sizeof(u8));
- if (ret < 0)
- goto kfree_exit;
- pcf2123_delay_trec();
-
- /* See if the counter was actually stopped */
- txbuf[0] = PCF2123_READ | PCF2123_REG_CTRL1;
- dev_dbg(&spi->dev, "checking for presence of RTC (0x%02X)\n",
- txbuf[0]);
- ret = spi_write_then_read(spi, txbuf, 1 * sizeof(u8),
- rxbuf, 2 * sizeof(u8));
- dev_dbg(&spi->dev, "received data from RTC (0x%02X 0x%02X)\n",
- rxbuf[0], rxbuf[1]);
- if (ret < 0)
- goto kfree_exit;
- pcf2123_delay_trec();
-
- if (!(rxbuf[0] & 0x20)) {
- dev_err(&spi->dev, "chip not found\n");
- ret = -ENODEV;
- goto kfree_exit;
+ ret = pcf2123_rtc_read_time(&spi->dev, &tm);
+ if (ret < 0) {
+ ret = pcf2123_reset(&spi->dev);
+ if (ret < 0) {
+ dev_err(&spi->dev, "chip not found\n");
+ 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);
- /* Start the counter */
- txbuf[0] = PCF2123_WRITE | PCF2123_REG_CTRL1;
- txbuf[1] = 0x00;
- ret = spi_write(spi, txbuf, sizeof(txbuf));
- if (ret < 0)
- goto kfree_exit;
- pcf2123_delay_trec();
-
/* Finalize the initialization */
rtc = devm_rtc_device_register(&spi->dev, pcf2123_driver.driver.name,
&pcf2123_rtc_ops, THIS_MODULE);
--- /dev/null
+/*
+ * Driver for the Epson RTC module RX-6110 SA
+ *
+ * Copyright(C) 2015 Pengutronix, Steffen Trumtrar <kernel@pengutronix.de>
+ * Copyright(C) SEIKO EPSON CORPORATION 2013. All rights reserved.
+ *
+ * This driver software is distributed as is, without any warranty of any kind,
+ * either express or implied as further specified in the GNU Public License.
+ * This software may be used and distributed according to the terms of the GNU
+ * Public License, version 2 as published by the Free Software Foundation.
+ * See the file COPYING in the main directory of this archive for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/bcd.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+#include <linux/spi/spi.h>
+
+/* RX-6110 Register definitions */
+#define RX6110_REG_SEC 0x10
+#define RX6110_REG_MIN 0x11
+#define RX6110_REG_HOUR 0x12
+#define RX6110_REG_WDAY 0x13
+#define RX6110_REG_MDAY 0x14
+#define RX6110_REG_MONTH 0x15
+#define RX6110_REG_YEAR 0x16
+#define RX6110_REG_RES1 0x17
+#define RX6110_REG_ALMIN 0x18
+#define RX6110_REG_ALHOUR 0x19
+#define RX6110_REG_ALWDAY 0x1A
+#define RX6110_REG_TCOUNT0 0x1B
+#define RX6110_REG_TCOUNT1 0x1C
+#define RX6110_REG_EXT 0x1D
+#define RX6110_REG_FLAG 0x1E
+#define RX6110_REG_CTRL 0x1F
+#define RX6110_REG_USER0 0x20
+#define RX6110_REG_USER1 0x21
+#define RX6110_REG_USER2 0x22
+#define RX6110_REG_USER3 0x23
+#define RX6110_REG_USER4 0x24
+#define RX6110_REG_USER5 0x25
+#define RX6110_REG_USER6 0x26
+#define RX6110_REG_USER7 0x27
+#define RX6110_REG_USER8 0x28
+#define RX6110_REG_USER9 0x29
+#define RX6110_REG_USERA 0x2A
+#define RX6110_REG_USERB 0x2B
+#define RX6110_REG_USERC 0x2C
+#define RX6110_REG_USERD 0x2D
+#define RX6110_REG_USERE 0x2E
+#define RX6110_REG_USERF 0x2F
+#define RX6110_REG_RES2 0x30
+#define RX6110_REG_RES3 0x31
+#define RX6110_REG_IRQ 0x32
+
+#define RX6110_BIT_ALARM_EN BIT(7)
+
+/* Extension Register (1Dh) bit positions */
+#define RX6110_BIT_EXT_TSEL0 BIT(0)
+#define RX6110_BIT_EXT_TSEL1 BIT(1)
+#define RX6110_BIT_EXT_TSEL2 BIT(2)
+#define RX6110_BIT_EXT_WADA BIT(3)
+#define RX6110_BIT_EXT_TE BIT(4)
+#define RX6110_BIT_EXT_USEL BIT(5)
+#define RX6110_BIT_EXT_FSEL0 BIT(6)
+#define RX6110_BIT_EXT_FSEL1 BIT(7)
+
+/* Flag Register (1Eh) bit positions */
+#define RX6110_BIT_FLAG_VLF BIT(1)
+#define RX6110_BIT_FLAG_AF BIT(3)
+#define RX6110_BIT_FLAG_TF BIT(4)
+#define RX6110_BIT_FLAG_UF BIT(5)
+
+/* Control Register (1Fh) bit positions */
+#define RX6110_BIT_CTRL_TBKE BIT(0)
+#define RX6110_BIT_CTRL_TBKON BIT(1)
+#define RX6110_BIT_CTRL_TSTP BIT(2)
+#define RX6110_BIT_CTRL_AIE BIT(3)
+#define RX6110_BIT_CTRL_TIE BIT(4)
+#define RX6110_BIT_CTRL_UIE BIT(5)
+#define RX6110_BIT_CTRL_STOP BIT(6)
+#define RX6110_BIT_CTRL_TEST BIT(7)
+
+enum {
+ RTC_SEC = 0,
+ RTC_MIN,
+ RTC_HOUR,
+ RTC_WDAY,
+ RTC_MDAY,
+ RTC_MONTH,
+ RTC_YEAR,
+ RTC_NR_TIME
+};
+
+#define RX6110_DRIVER_NAME "rx6110"
+
+struct rx6110_data {
+ struct rtc_device *rtc;
+ struct regmap *regmap;
+};
+
+/**
+ * rx6110_rtc_tm_to_data - convert rtc_time to native time encoding
+ *
+ * @tm: holds date and time
+ * @data: holds the encoding in rx6110 native form
+ */
+static int rx6110_rtc_tm_to_data(struct rtc_time *tm, u8 *data)
+{
+ pr_debug("%s: date %ds %dm %dh %dmd %dm %dy\n", __func__,
+ tm->tm_sec, tm->tm_min, tm->tm_hour,
+ tm->tm_mday, tm->tm_mon, tm->tm_year);
+
+ /*
+ * The year in the RTC is a value between 0 and 99.
+ * Assume that this represents the current century
+ * and disregard all other values.
+ */
+ if (tm->tm_year < 100 || tm->tm_year >= 200)
+ return -EINVAL;
+
+ data[RTC_SEC] = bin2bcd(tm->tm_sec);
+ data[RTC_MIN] = bin2bcd(tm->tm_min);
+ data[RTC_HOUR] = bin2bcd(tm->tm_hour);
+ data[RTC_WDAY] = BIT(bin2bcd(tm->tm_wday));
+ data[RTC_MDAY] = bin2bcd(tm->tm_mday);
+ data[RTC_MONTH] = bin2bcd(tm->tm_mon + 1);
+ data[RTC_YEAR] = bin2bcd(tm->tm_year % 100);
+
+ return 0;
+}
+
+/**
+ * rx6110_data_to_rtc_tm - convert native time encoding to rtc_time
+ *
+ * @data: holds the encoding in rx6110 native form
+ * @tm: holds date and time
+ */
+static int rx6110_data_to_rtc_tm(u8 *data, struct rtc_time *tm)
+{
+ tm->tm_sec = bcd2bin(data[RTC_SEC] & 0x7f);
+ tm->tm_min = bcd2bin(data[RTC_MIN] & 0x7f);
+ /* only 24-hour clock */
+ tm->tm_hour = bcd2bin(data[RTC_HOUR] & 0x3f);
+ tm->tm_wday = ffs(data[RTC_WDAY] & 0x7f);
+ tm->tm_mday = bcd2bin(data[RTC_MDAY] & 0x3f);
+ tm->tm_mon = bcd2bin(data[RTC_MONTH] & 0x1f) - 1;
+ tm->tm_year = bcd2bin(data[RTC_YEAR]) + 100;
+
+ pr_debug("%s: date %ds %dm %dh %dmd %dm %dy\n", __func__,
+ tm->tm_sec, tm->tm_min, tm->tm_hour,
+ tm->tm_mday, tm->tm_mon, tm->tm_year);
+
+ /*
+ * The year in the RTC is a value between 0 and 99.
+ * Assume that this represents the current century
+ * and disregard all other values.
+ */
+ if (tm->tm_year < 100 || tm->tm_year >= 200)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * rx6110_set_time - set the current time in the rx6110 registers
+ *
+ * @dev: the rtc device in use
+ * @tm: holds date and time
+ *
+ * BUG: The HW assumes every year that is a multiple of 4 to be a leap
+ * year. Next time this is wrong is 2100, which will not be a leap year
+ *
+ * Note: If STOP is not set/cleared, the clock will start when the seconds
+ * register is written
+ *
+ */
+static int rx6110_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct rx6110_data *rx6110 = dev_get_drvdata(dev);
+ u8 data[RTC_NR_TIME];
+ int ret;
+
+ ret = rx6110_rtc_tm_to_data(tm, data);
+ if (ret < 0)
+ return ret;
+
+ /* set STOP bit before changing clock/calendar */
+ ret = regmap_update_bits(rx6110->regmap, RX6110_REG_CTRL,
+ RX6110_BIT_CTRL_STOP, RX6110_BIT_CTRL_STOP);
+ if (ret)
+ return ret;
+
+ ret = regmap_bulk_write(rx6110->regmap, RX6110_REG_SEC, data,
+ RTC_NR_TIME);
+ if (ret)
+ return ret;
+
+ /* The time in the RTC is valid. Be sure to have VLF cleared. */
+ ret = regmap_update_bits(rx6110->regmap, RX6110_REG_FLAG,
+ RX6110_BIT_FLAG_VLF, 0);
+ if (ret)
+ return ret;
+
+ /* clear STOP bit after changing clock/calendar */
+ ret = regmap_update_bits(rx6110->regmap, RX6110_REG_CTRL,
+ RX6110_BIT_CTRL_STOP, 0);
+
+ return ret;
+}
+
+/**
+ * rx6110_get_time - get the current time from the rx6110 registers
+ * @dev: the rtc device in use
+ * @tm: holds date and time
+ */
+static int rx6110_get_time(struct device *dev, struct rtc_time *tm)
+{
+ struct rx6110_data *rx6110 = dev_get_drvdata(dev);
+ u8 data[RTC_NR_TIME];
+ int flags;
+ int ret;
+
+ ret = regmap_read(rx6110->regmap, RX6110_REG_FLAG, &flags);
+ if (ret)
+ return -EINVAL;
+
+ /* check for VLF Flag (set at power-on) */
+ if ((flags & RX6110_BIT_FLAG_VLF)) {
+ dev_warn(dev, "Voltage low, data is invalid.\n");
+ return -EINVAL;
+ }
+
+ /* read registers to date */
+ ret = regmap_bulk_read(rx6110->regmap, RX6110_REG_SEC, data,
+ RTC_NR_TIME);
+ if (ret)
+ return ret;
+
+ ret = rx6110_data_to_rtc_tm(data, tm);
+ if (ret)
+ return ret;
+
+ dev_dbg(dev, "%s: date %ds %dm %dh %dmd %dm %dy\n", __func__,
+ tm->tm_sec, tm->tm_min, tm->tm_hour,
+ tm->tm_mday, tm->tm_mon, tm->tm_year);
+
+ return rtc_valid_tm(tm);
+}
+
+static const struct reg_sequence rx6110_default_regs[] = {
+ { RX6110_REG_RES1, 0xB8 },
+ { RX6110_REG_RES2, 0x00 },
+ { RX6110_REG_RES3, 0x10 },
+ { RX6110_REG_IRQ, 0x00 },
+ { RX6110_REG_ALMIN, 0x00 },
+ { RX6110_REG_ALHOUR, 0x00 },
+ { RX6110_REG_ALWDAY, 0x00 },
+};
+
+/**
+ * rx6110_init - initialize the rx6110 registers
+ *
+ * @rx6110: pointer to the rx6110 struct in use
+ *
+ */
+static int rx6110_init(struct rx6110_data *rx6110)
+{
+ struct rtc_device *rtc = rx6110->rtc;
+ int flags;
+ int ret;
+
+ ret = regmap_update_bits(rx6110->regmap, RX6110_REG_EXT,
+ RX6110_BIT_EXT_TE, 0);
+ if (ret)
+ return ret;
+
+ ret = regmap_register_patch(rx6110->regmap, rx6110_default_regs,
+ ARRAY_SIZE(rx6110_default_regs));
+ if (ret)
+ return ret;
+
+ ret = regmap_read(rx6110->regmap, RX6110_REG_FLAG, &flags);
+ if (ret)
+ return ret;
+
+ /* check for VLF Flag (set at power-on) */
+ if ((flags & RX6110_BIT_FLAG_VLF))
+ dev_warn(&rtc->dev, "Voltage low, data loss detected.\n");
+
+ /* check for Alarm Flag */
+ if (flags & RX6110_BIT_FLAG_AF)
+ dev_warn(&rtc->dev, "An alarm may have been missed.\n");
+
+ /* check for Periodic Timer Flag */
+ if (flags & RX6110_BIT_FLAG_TF)
+ dev_warn(&rtc->dev, "Periodic timer was detected\n");
+
+ /* check for Update Timer Flag */
+ if (flags & RX6110_BIT_FLAG_UF)
+ dev_warn(&rtc->dev, "Update timer was detected\n");
+
+ /* clear all flags BUT VLF */
+ ret = regmap_update_bits(rx6110->regmap, RX6110_REG_FLAG,
+ RX6110_BIT_FLAG_AF |
+ RX6110_BIT_FLAG_UF |
+ RX6110_BIT_FLAG_TF,
+ 0);
+
+ return ret;
+}
+
+static struct rtc_class_ops rx6110_rtc_ops = {
+ .read_time = rx6110_get_time,
+ .set_time = rx6110_set_time,
+};
+
+static struct regmap_config regmap_spi_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = RX6110_REG_IRQ,
+ .read_flag_mask = 0x80,
+};
+
+/**
+ * rx6110_probe - initialize rtc driver
+ * @spi: pointer to spi device
+ */
+static int rx6110_probe(struct spi_device *spi)
+{
+ struct rx6110_data *rx6110;
+ int err;
+
+ if ((spi->bits_per_word && spi->bits_per_word != 8) ||
+ (spi->max_speed_hz > 2000000) ||
+ (spi->mode != (SPI_CS_HIGH | SPI_CPOL | SPI_CPHA))) {
+ dev_warn(&spi->dev, "SPI settings: bits_per_word: %d, max_speed_hz: %d, mode: %xh\n",
+ spi->bits_per_word, spi->max_speed_hz, spi->mode);
+ dev_warn(&spi->dev, "driving device in an unsupported mode");
+ }
+
+ rx6110 = devm_kzalloc(&spi->dev, sizeof(*rx6110), GFP_KERNEL);
+ if (!rx6110)
+ return -ENOMEM;
+
+ rx6110->regmap = devm_regmap_init_spi(spi, ®map_spi_config);
+ if (IS_ERR(rx6110->regmap)) {
+ dev_err(&spi->dev, "regmap init failed for rtc rx6110\n");
+ return PTR_ERR(rx6110->regmap);
+ }
+
+ spi_set_drvdata(spi, rx6110);
+
+ rx6110->rtc = devm_rtc_device_register(&spi->dev,
+ RX6110_DRIVER_NAME,
+ &rx6110_rtc_ops, THIS_MODULE);
+
+ if (IS_ERR(rx6110->rtc))
+ return PTR_ERR(rx6110->rtc);
+
+ err = rx6110_init(rx6110);
+ if (err)
+ return err;
+
+ rx6110->rtc->max_user_freq = 1;
+
+ return 0;
+}
+
+static int rx6110_remove(struct spi_device *spi)
+{
+ return 0;
+}
+
+static const struct spi_device_id rx6110_id[] = {
+ { "rx6110", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, rx6110_id);
+
+static struct spi_driver rx6110_driver = {
+ .driver = {
+ .name = RX6110_DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = rx6110_probe,
+ .remove = rx6110_remove,
+ .id_table = rx6110_id,
+};
+
+module_spi_driver(rx6110_driver);
+
+MODULE_AUTHOR("Val Krutov <val.krutov@erd.epson.com>");
+MODULE_DESCRIPTION("RX-6110 SA RTC driver");
+MODULE_LICENSE("GPL");
static const struct i2c_device_id rx8025_id[] = {
{ "rx8025", 0 },
- { "rv8803", 1 },
{ }
};
MODULE_DEVICE_TABLE(i2c, rx8025_id);