]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'rtc/rtc-next'
authorStephen Rothwell <sfr@canb.auug.org.au>
Thu, 11 Feb 2016 04:07:23 +0000 (15:07 +1100)
committerStephen Rothwell <sfr@canb.auug.org.au>
Thu, 11 Feb 2016 04:07:23 +0000 (15:07 +1100)
Documentation/devicetree/bindings/rtc/epson,rx6110.txt [new file with mode: 0644]
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-ds1305.c
drivers/rtc/rtc-ds1307.c
drivers/rtc/rtc-pcf2123.c
drivers/rtc/rtc-rx6110.c [new file with mode: 0644]
drivers/rtc/rtc-rx8025.c

diff --git a/Documentation/devicetree/bindings/rtc/epson,rx6110.txt b/Documentation/devicetree/bindings/rtc/epson,rx6110.txt
new file mode 100644 (file)
index 0000000..3dc313e
--- /dev/null
@@ -0,0 +1,39 @@
+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;
+       };
index ef456d3cf2655ac466f7671915d0b8e579492a50..2cf87f7244fd7f0d81319baacb45ef582e0d1e8c 100644 (file)
@@ -212,6 +212,15 @@ config RTC_DRV_DS1307
          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
@@ -734,6 +743,15 @@ config RTC_DRV_RX4581
          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
@@ -1350,10 +1368,11 @@ config RTC_DRV_SUN4V
 
 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"
@@ -1593,7 +1612,7 @@ config RTC_DRV_MOXART
 
 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
index ed4519efa3caf01d5ce331cdddb1db6dd4e0b431..c8a21479deea253d7b636cef5bd221ba4f966593 100644 (file)
@@ -127,6 +127,7 @@ obj-$(CONFIG_RTC_DRV_RS5C372)       += rtc-rs5c372.o
 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
index f39691eea7360272f6c7449a2d25202e6c4106b3..8e41c4613e5135cbd4db573586f85ef60678447e 100644 (file)
@@ -532,7 +532,7 @@ ds1305_nvram_read(struct file *filp, struct kobject *kobj,
        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);
@@ -554,7 +554,7 @@ ds1305_nvram_write(struct file *filp, struct kobject *kobj,
        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);
index cf685f67b391669df4f51d8b50c746e839bd396e..2462d5a53a535bac17517d9103b5df3f105dd3e0 100644 (file)
@@ -19,6 +19,8 @@
 #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
@@ -842,6 +844,90 @@ out:
        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)
 {
@@ -851,6 +937,7 @@ static int ds1307_probe(struct i2c_client *client,
        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;
@@ -898,6 +985,20 @@ static int ds1307_probe(struct i2c_client *client,
                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:
@@ -916,11 +1017,13 @@ static int ds1307_probe(struct i2c_client *client,
                        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);
@@ -1135,6 +1238,14 @@ read_rtc:
                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,
@@ -1182,6 +1293,8 @@ read_rtc:
                }
        }
 
+       ds1307_hwmon_register(ds1307);
+
        return 0;
 
 exit:
index ea8a31c91641d46a7a5b44a2225a98e03c4317a3..d9a44ad1239b8b8486f3ac498a34bff2d5419cc8 100644 (file)
@@ -48,6 +48,7 @@
 
 #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;
 
@@ -84,12 +128,44 @@ static inline void pcf2123_delay_trec(void)
        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, &reg, 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;
 
@@ -99,19 +175,16 @@ static ssize_t pcf2123_show(struct device *dev, struct device_attribute *attr,
        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;
 
@@ -127,27 +200,25 @@ static ssize_t pcf2123_store(struct device *dev, struct device_attribute *attr,
        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);
@@ -170,7 +241,6 @@ static int pcf2123_rtc_read_time(struct device *dev, struct rtc_time *tm)
 
 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;
 
@@ -181,15 +251,12 @@ static int pcf2123_rtc_set_time(struct device *dev, struct rtc_time *tm)
                        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);
@@ -198,18 +265,48 @@ static int pcf2123_rtc_set_time(struct device *dev, struct rtc_time *tm)
        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;
 }
@@ -222,8 +319,8 @@ static const struct rtc_class_ops pcf2123_rtc_ops = {
 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),
@@ -232,56 +329,19 @@ static int pcf2123_probe(struct spi_device *spi)
                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);
diff --git a/drivers/rtc/rtc-rx6110.c b/drivers/rtc/rtc-rx6110.c
new file mode 100644 (file)
index 0000000..bbad00b
--- /dev/null
@@ -0,0 +1,402 @@
+/*
+ * 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, &regmap_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");
index 85df3b4c2521c420e54bf56d38c811bb9f503fe9..d89c65ec88119aac7be186bc78892215ed6084bd 100644 (file)
@@ -65,7 +65,6 @@
 
 static const struct i2c_device_id rx8025_id[] = {
        { "rx8025", 0 },
-       { "rv8803", 1 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, rx8025_id);